From: Ben Schweikert Date: Tue, 8 Sep 2009 07:55:37 +0000 (+0200) Subject: Merge branch 'master' of git://git.ipfire.org/ipfire-2.x X-Git-Url: http://git.ipfire.org/?p=people%2Fteissler%2Fipfire-2.x.git;a=commitdiff_plain;h=f47403a4c1cc198c54291ea16d4c388ff253a9ea;hp=cb4fdb52ad4be01ddb32d996710ba743f4492cdb Merge branch 'master' of git://git.ipfire.org/ipfire-2.x --- diff --git a/config/kernel/kernel.config.i586-ipfire-xen b/config/kernel/kernel.config.i586-ipfire-xen index aa3e2b42d..5ae27c2c4 100644 --- a/config/kernel/kernel.config.i586-ipfire-xen +++ b/config/kernel/kernel.config.i586-ipfire-xen @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.27.25-ipfire-xen -# Sun Aug 9 16:17:27 2009 +# Linux kernel version: 2.6.27.31 +# Mon Sep 7 10:05:41 2009 # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -252,6 +252,7 @@ CONFIG_RESOURCES_64BIT=y CONFIG_ZONE_DMA_FLAG=1 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_HIGHPTE is not set CONFIG_MTRR=y # CONFIG_X86_PAT is not set @@ -926,7 +927,6 @@ CONFIG_SONY_LAPTOP=m # CONFIG_SONYPI_COMPAT is not set CONFIG_THINKPAD_ACPI=m # CONFIG_THINKPAD_ACPI_DEBUG is not set -CONFIG_THINKPAD_ACPI_BAY=y CONFIG_THINKPAD_ACPI_VIDEO=y CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y CONFIG_INTEL_MENLOW=m @@ -2852,6 +2852,7 @@ CONFIG_XEN_SMPBOOT=y CONFIG_XEN_DEVMEM=y CONFIG_XEN_BALLOON=y CONFIG_XEN_SCRUB_PAGES=y +# CONFIG_STAGING is not set # # Firmware Drivers diff --git a/make.sh b/make.sh index 2f69a4c92..a4063a562 100755 --- a/make.sh +++ b/make.sh @@ -338,17 +338,17 @@ buildipfire() { ipfiremake pptp ipfiremake unzip ipfiremake which -# ipfiremake linux XEN=1 -# ipfiremake atl2 XEN=1 -# ipfiremake hso XEN=1 -# ipfiremake e1000e XEN=1 -# ipfiremake kqemu XEN=1 -# ipfiremake v4l-dvb XEN=1 -# ipfiremake madwifi XEN=1 -## ipfiremake alsa XEN=1 KMOD=1 -# ipfiremake openswan XEN=1 KMOD=1 -# ipfiremake mISDN XEN=1 -# ipfiremake compat-wireless XEN=1 + ipfiremake linux XEN=1 + ipfiremake atl2 XEN=1 + ipfiremake hso XEN=1 + ipfiremake e1000e XEN=1 + ipfiremake kqemu XEN=1 + ipfiremake v4l-dvb XEN=1 + ipfiremake madwifi XEN=1 +# ipfiremake alsa XEN=1 KMOD=1 + ipfiremake openswan XEN=1 KMOD=1 + ipfiremake mISDN XEN=1 + ipfiremake compat-wireless XEN=1 ipfiremake linux ipfiremake atl2 ipfiremake hso diff --git a/src/patches/suse-2.6.27.31/arch-symbols b/src/patches/suse-2.6.27.31/arch-symbols new file mode 100755 index 000000000..60c2c0061 --- /dev/null +++ b/src/patches/suse-2.6.27.31/arch-symbols @@ -0,0 +1,35 @@ +#!/bin/sh + +# Generate architecture specific patch selection symbols + +if [ "$1" = "--list" ]; then + # List all known architectures + echo i386 mips{,64} sparc{,64} ppc{,64} s390{,x} ia64 x86_64 alpha parisc + exit 0 +fi + +if [ -z "$SYMBOLS" ]; then + if [ -n "$1" ]; then + ARCH="$1" + elif [ -n "$PATCH_ARCH" ]; then + ARCH="$PATCH_ARCH" + else + ARCH="`arch`" + fi + SYMBOLS="$ARCH" + case "$ARCH" in + (i?86) SYMBOLS="$SYMBOLS IA32" ;; + (mips*) SYMBOLS="$SYMBOLS MIPS" ;; + (sparc*) SYMBOLS="$SYMBOLS SPARC" ;; + (ppc*) SYMBOLS="$SYMBOLS PPC" ;; + (s390*) SYMBOLS="$SYMBOLS S390" ;; + (ia64) ;; + (x86_64) ;; + (alpha) ;; + (parisc) ;; + (*) # not a recognized architeture! + exit + ;; + esac +fi +echo $SYMBOLS diff --git a/src/patches/suse-2.6.27.31/guards b/src/patches/suse-2.6.27.31/guards new file mode 100755 index 000000000..e93af5ca5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/guards @@ -0,0 +1,287 @@ +#!/usr/bin/perl -w + +# +# Guards: +# +# +xxx include if xxx is defined +# -xxx exclude if xxx is defined +# +!xxx include if xxx is not defined +# -!xxx exclude if xxx is not defined +# + +use FileHandle; +use Getopt::Long; +use strict; + +# Prototypes +sub files_in($$); +sub parse($$); +sub help(); + +#sub strip_ext($) { +# local ($_) = @_; +# s/\.(diff?|patch)$//; +#} + +#sub try_ext($) { +# my ($path) = @_; +# for my $p in (($path, "$path.diff", "$path.dif", "$path.patch")) { +# return $p +# if (-f $p); +# } +# return undef; +#} + +sub slashme($) { + my ($dir) = @_; + $dir =~ s#([^/])$#$&/#; # append a slash if necessary + if ($dir eq './') { + return ''; + } else { + return $dir; + } +} + +# Generate a list of files in a directory +# +sub files_in($$) { + my ($dir, $path) = @_; + my $dh = new FileHandle; + my (@files, $file); + + + opendir $dh, length("$dir$path") ? "$dir$path" : '.' + or die "$dir$path: $!\n"; + while ($file = readdir($dh)) { + next if $file =~ /^(\.|\.\.|\.#.*|CVS|.*~)$/; + if (-d "$dir$path$file") { + @files = (@files, files_in($dir, "$path$file/")); + } else { + #print "[$path$file]\n"; + push @files, "$path$file"; + } + } + closedir $dh; + return @files; +} + +# Parse a configuration file +# Callback called with ($patch, @guards) arguments +# +sub parse($$) { + my ($fh, $callback) = @_; + + my $line = ""; + + while (<$fh>) { + chomp; + s/(^|\s+)#.*//; + if (s/\\$/ /) { + $line .= $_; + next; + } + $line .= $_; + my @guards = (); + foreach my $token (split /[\s\t\n]+/, $line) { + next if $token eq ""; + if ($token =~ /^[-+]/) { + push @guards, $token; + } else { + #print "[" . join(",", @guards) . "] $token\n"; + &$callback($token, @guards); + } + } + $line = ""; + } +} + +# Command line options +# +my ($dir, $config, $default, $check, $list, $invert_match, $with_guards) = + ( '', '-', 1, 0, 0, 0, 0); +my @path; + +# Help text +# +sub help() { + print "$0 - select from a list of files guarded by conditions\n"; + print "SYNOPSIS: $0 [--prefix=dir] [--path=dir1:dir2:...]\n" . + " [--default=0|1] [--check|--list] [--invert-match]\n" . + " [--with-guards] [--config=file] symbol ...\n\n" . + " (Default values: --path='" . join(':', @path) . "', " . + "--default=$default)\n"; + exit 0; +} + +# Parse command line options +# +Getopt::Long::Configure ("bundling"); +eval { + unless (GetOptions ( + 'd|prefix=s' => \$dir, + 'c|config=s' => \$config, + 'C|check' => \$check, + 'l|list' => \$list, + 'w|with-guards' => \$with_guards, + 'p|path=s' => \@path, + 'D|default=i' => \$default, + 'v|invert-match' => \$invert_match, + 'h|help' => sub { help(); exit 0; })) { + help(); + exit 1; + } +}; +if ($@) { + print "$@"; + help(); + exit 1; +} + +@path = ('.') + unless (@path); +@path = split(/:/, join(':', @path)); + +my $fh = ($config eq '-') ? \*STDIN : new FileHandle($config) + or die "$config: $!\n"; + +$dir = slashme($dir); + +if ($check) { + # Check for duplicate files, or for files that are not referenced by + # the specification. + + my $problems = 0; + my @files; + + foreach (@path) { + @files = (@files, files_in($dir, slashme($_))); + } + my %files = map { $_ => 0 } @files; + + parse($fh, sub { + my ($patch, @guards) = @_; + if (exists $files{$patch}) { + $files{$patch}++; + } else { + print "Not found: $dir$patch\n"; + $problems++; + }}); + + $fh->close(); + + my ($file, $ref); + while (($file, $ref) = each %files) { + next if $ref == 1; + + if ($ref == 0) { + print "Unused: $file\n" if $ref == 0; + $problems++; + } + if ($ref > 1) { + print "Warning: multiple uses: $file\n" if $ref > 1; + # This is not an error if the entries are mutually exclusive... + } + } + exit $problems ? 1 : 0; + +} elsif ($list) { + parse($fh, sub { + my ($patch, @guards) = @_; + print join(' ', @guards), ' ' + if (@guards && $with_guards); + print "$dir$patch\n"; + }); +} else { + # Generate a list of patches to apply. + + my %symbols = map { $_ => 1 } @ARGV; + + parse($fh, sub { + my ($patch, @guards) = @_; + + my $selected; + if (@guards) { + # If the first guard is -xxx, the patch is included by default; + # if it is +xxx, the patch is excluded by default. + $selected = ($guards[0] =~ /^-/); + + foreach (@guards) { + /^([-+])(!?)(.*)?/ + or die "Bad guard '$_'\n"; + + # Check if the guard matches + if (($2 eq '!' && !exists $symbols{$3}) || + ($2 eq '' && ( $3 eq '' || exists $symbols{$3}))) { + # Include or exclude + $selected = ($1 eq '+'); + } + } + } else { + # If there are no guards, use the specified default result. + $selected = $default; + } + + print "$dir$patch\n" + if $selected ^ $invert_match; + }); + + $fh->close(); + + exit 0; +} + +__END__ + +=head1 NAME + +guards - select from a list of files guarded by conditions + +=head1 SYNOPSIS + +F [--prefix=F] [--path=F] [--default=<0|1>] + [--check|--list] [--invert-match] [--with-guards] [--config=] + I ... + + +=head1 DESCRIPTION + +The script reads a configuration file that may contain so-called guards, file +names, and comments, and writes those file names that satisfy all guards to +standard output. The script takes a list of symbols as its arguments. Each line +in the configuration file is processed separately. Lines may start with a +number of guards. The following guards are defined: + +=over + ++I Include the file(s) on this line if the symbol I is defined. + +-I Exclude the file(s) on this line if the symbol I is defined. + ++!I Include the file(s) on this line if the symbol I is not defined. + +-!I Exclude the file(s) on this line if the symbol I is not defined. + +- Exclude this file. Used to avoid spurious I<--check> messages. + +=back + +The guards are processed left to right. The last guard that matches determines +if the file is included. If no guard is specified, the I<--default> +setting determines if the file is included. + +If no configuration file is specified, the script reads from standard input. + +The I<--check> option is used to compare the specification file against the +file system. If files are referenced in the specification that do not exist, or +if files are not enlisted in the specification file warnings are printed. The +I<--path> option can be used to specify which directory or directories to scan. +Multiple directories are eparated by a colon (C<:>) character. The +I<--prefix> option specifies the location of the files. + +Use I<--list> to list all files independend of any rules. Use I<--invert-match> +to list only the excluded patches. Use I<--with-guards> to also include all +inclusion and exclusion rules. + +=head1 AUTHOR + +Andreas Gruenbacher , SUSE Labs diff --git a/src/patches/suse-2.6.27.31/patches.apparmor/add-security_path_permission b/src/patches/suse-2.6.27.31/patches.apparmor/add-security_path_permission new file mode 100644 index 000000000..adaaff8b3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.apparmor/add-security_path_permission @@ -0,0 +1,109 @@ +From: Jeff Mahoney +Subject: [PATCH] security: add ->path_permission + + This patch adds a security_ops->path_permission hook that is identical to + security_ops->inode_permission except that it is passed a struct path + instead of a struct inode. + + LSMs which don't implement it will have their ->inode_permission call + used instead. + +Signed-off-by: Jeff Mahoney +--- + + include/linux/security.h | 21 +++++++++++++++++++++ + security/capability.c | 6 ++++++ + security/security.c | 9 +++++++++ + 3 files changed, 36 insertions(+) + +--- a/include/linux/security.h ++++ b/include/linux/security.h +@@ -592,6 +592,20 @@ static inline void security_free_mnt_opt + * file_permission, and recheck access if anything has changed + * since inode_permission. + * ++ * Security hook for path ++ * ++ * @path_permission: ++ * Check permission before accessing a path. This hook is called by the ++ * existing Linux permission function, so a security module can use it to ++ * provide additional checking for existing Linux permission checks. ++ * Notice that this hook is called when a file is opened (as well as many ++ * other operations), whereas the file_security_ops permission hook is ++ * called when the actual read/write operations are performed. This ++ * hook is optional and if absent, inode_permission will be substituted. ++ * @path contains the path structure to check. ++ * @mask contains the permission mask. ++ * Return 0 if permission is granted. ++ + * Security hooks for task operations. + * + * @task_create: +@@ -1434,6 +1448,7 @@ struct security_operations { + struct fown_struct *fown, int sig); + int (*file_receive) (struct file *file); + int (*dentry_open) (struct file *file); ++ int (*path_permission) (struct path *path, int mask); + + int (*task_create) (unsigned long clone_flags); + int (*task_alloc_security) (struct task_struct *p); +@@ -1708,6 +1723,7 @@ int security_file_send_sigiotask(struct + struct fown_struct *fown, int sig); + int security_file_receive(struct file *file); + int security_dentry_open(struct file *file); ++int security_path_permission(struct path *path, int mask); + int security_task_create(unsigned long clone_flags); + int security_task_alloc(struct task_struct *p); + void security_task_free(struct task_struct *p); +@@ -2242,6 +2258,11 @@ static inline int security_dentry_open(s + { + return 0; + } ++ ++static inline int security_path_permission(struct path *path, int mask) ++{ ++ return 0; ++} + + static inline int security_task_create(unsigned long clone_flags) + { +--- a/security/capability.c ++++ b/security/capability.c +@@ -343,6 +343,11 @@ static int cap_dentry_open(struct file * + return 0; + } + ++static int cap_path_permission(struct path *path, int mask) ++{ ++ return security_inode_permission(path->dentry->d_inode, mask); ++} ++ + static int cap_task_create(unsigned long clone_flags) + { + return 0; +@@ -897,6 +902,7 @@ void security_fixup_ops(struct security_ + set_to_cap_if_null(ops, file_send_sigiotask); + set_to_cap_if_null(ops, file_receive); + set_to_cap_if_null(ops, dentry_open); ++ set_to_cap_if_null(ops, path_permission); + set_to_cap_if_null(ops, task_create); + set_to_cap_if_null(ops, task_alloc_security); + set_to_cap_if_null(ops, task_free_security); +--- a/security/security.c ++++ b/security/security.c +@@ -612,6 +612,15 @@ int security_dentry_open(struct file *fi + return security_ops->dentry_open(file); + } + ++int security_path_permission(struct path *path, int mask) ++{ ++ struct inode *inode = path->dentry->d_inode; ++ if (unlikely(IS_PRIVATE(inode))) ++ return 0; ++ ++ return security_ops->path_permission(path, mask); ++} ++ + int security_task_create(unsigned long clone_flags) + { + return security_ops->task_create(clone_flags); diff --git a/src/patches/suse-2.6.27.31/patches.apparmor/apparmor-path_permission b/src/patches/suse-2.6.27.31/patches.apparmor/apparmor-path_permission new file mode 100644 index 000000000..41b7ad181 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.apparmor/apparmor-path_permission @@ -0,0 +1,78 @@ +From: Jeff Mahoney +Subject: [PATCH] apparmor: convert apparmor_inode_permission to path + + patches.apparmor/add-security_path_permission added the ->path_permission + call. This patch converts apparmor_inode_permission to + apparmor_path_permission. The former is now a pass-all, which is how + it behaved in 2.6.26 if a NULL nameidata was passed. + +Signed-off-by: Jeff Mahoney +--- + security/apparmor/lsm.c | 41 +++++++++++++++++++++++++++-------------- + 1 file changed, 27 insertions(+), 14 deletions(-) + +--- a/security/apparmor/lsm.c ++++ b/security/apparmor/lsm.c +@@ -448,21 +448,9 @@ out: + return error; + } + +-static int apparmor_inode_permission(struct inode *inode, int mask, +- struct nameidata *nd) ++static int apparmor_inode_permission(struct inode *inode, int mask) + { +- int check = 0; +- +- if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)) +- return 0; +- mask = aa_mask_permissions(mask); +- if (S_ISDIR(inode->i_mode)) { +- check |= AA_CHECK_DIR; +- /* allow traverse accesses to directories */ +- mask &= ~MAY_EXEC; +- } +- return aa_permission("inode_permission", inode, nd->dentry, nd->mnt, +- mask, check); ++ return 0; + } + + static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, +@@ -656,6 +644,29 @@ static int apparmor_file_mprotect(struct + !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); + } + ++static int apparmor_path_permission(struct path *path, int mask) ++{ ++ struct inode *inode; ++ int check = 0; ++ ++ if (!path) ++ return 0; ++ ++ inode = path->dentry->d_inode; ++ ++ mask = aa_mask_permissions(mask); ++ if (S_ISDIR(inode->i_mode)) { ++ check |= AA_CHECK_DIR; ++ /* allow traverse accesses to directories */ ++ mask &= ~MAY_EXEC; ++ if (!mask) ++ return 0; ++ } ++ ++ return aa_permission("inode_permission", inode, path->dentry, ++ path->mnt, mask, check); ++} ++ + static int apparmor_task_alloc_security(struct task_struct *task) + { + return aa_clone(task); +@@ -800,6 +811,8 @@ struct security_operations apparmor_ops + .file_mprotect = apparmor_file_mprotect, + .file_lock = apparmor_file_lock, + ++ .path_permission = apparmor_path_permission, ++ + .task_alloc_security = apparmor_task_alloc_security, + .task_free_security = apparmor_task_free_security, + .task_post_setuid = cap_task_post_setuid, diff --git a/src/patches/suse-2.6.27.31/patches.apparmor/export-security_inode_permission-for-aufs b/src/patches/suse-2.6.27.31/patches.apparmor/export-security_inode_permission-for-aufs new file mode 100644 index 000000000..d7a533e55 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.apparmor/export-security_inode_permission-for-aufs @@ -0,0 +1,26 @@ +From: Jeff Mahoney +Subject: [PATCH] LSM: Export security_inode_permission for aufs +Patch-mainline: Never +References: 356902 + + In order for aufs to work with AppArmor, it needs to be able to call + security_inode_permission itself. + + This patch is a _workaround_ since the author will need to find a + mainline-compatible solution moving forward. + +Signed-off-by: Jeff Mahoney +--- + security/security.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/security/security.c ++++ b/security/security.c +@@ -412,6 +412,7 @@ int security_inode_mknod(struct inode *d + return 0; + return security_ops->inode_mknod(dir, dentry, mnt, mode, dev); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, + struct vfsmount *old_mnt, struct inode *new_dir, diff --git a/src/patches/suse-2.6.27.31/patches.arch/0000-ACPI-video-Ignore-devices-not-present.patch b/src/patches/suse-2.6.27.31/patches.arch/0000-ACPI-video-Ignore-devices-not-present.patch new file mode 100644 index 000000000..794f5e721 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0000-ACPI-video-Ignore-devices-not-present.patch @@ -0,0 +1,118 @@ +From: Thomas Renninger +Subject: ACPI: video: Ignore devices that aren't present in hardware +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit ad9ed8385ed6ec5be8da7094db911c824258ceec + + This is a reimplemention of commit + 0119509c4fbc9adcef1472817fda295334612976 + from Matthew Garrett + + This patch got removed because of a regression: ThinkPads with a + Intel graphics card and an Integrated Graphics Device BIOS implementation + stopped working. + In fact, they only worked because the ACPI device of the discrete, the + wrong one, got used (via int10). So ACPI functions were poking on the wrong + hardware used which is a sever bug. + The next patch provides support for above ThinkPads to be able to + switch brightness via the legacy thinkpad_acpi driver and automatically + detect when to use it. + + Original commit message from Matthew Garrett: + Vendors often ship machines with a choice of integrated or discrete + graphics, and use the same DSDT for both. As a result, the ACPI video + module will locate devices that may not exist on this specific platform. + Attempt to determine whether the device exists or not, and abort the + device creation if it doesn't. + + http://bugzilla.kernel.org/show_bug.cgi?id=9614 + + Signed-off-by: Thomas Renninger + Signed-off-by: Andi Kleen + +--- + drivers/acpi/glue.c | 40 ++++++++++++++++++++++++++++++++++++++++ + drivers/acpi/video.c | 7 ++++++- + include/acpi/acpi_bus.h | 2 ++ + 3 files changed, 48 insertions(+), 1 deletion(-) + +--- a/drivers/acpi/glue.c ++++ b/drivers/acpi/glue.c +@@ -140,6 +140,46 @@ struct device *acpi_get_physical_device( + + EXPORT_SYMBOL(acpi_get_physical_device); + ++/* ToDo: When a PCI bridge is found, return the PCI device behind the bridge ++ * This should work in general, but did not on a Lenovo T61 for the ++ * graphics card. But this must be fixed when the PCI device is ++ * bound and the kernel device struct is attached to the acpi device ++ * Note: A success call will increase reference count by one ++ * Do call put_device(dev) on the returned device then ++ */ ++struct device *acpi_get_physical_pci_device(acpi_handle handle) ++{ ++ struct device *dev; ++ long long device_id; ++ acpi_status status; ++ ++ status = ++ acpi_evaluate_integer(handle, "_ADR", NULL, &device_id); ++ ++ if (ACPI_FAILURE(status)) ++ return NULL; ++ ++ /* We need to attempt to determine whether the _ADR refers to a ++ PCI device or not. There's no terribly good way to do this, ++ so the best we can hope for is to assume that there'll never ++ be a device in the host bridge */ ++ if (device_id >= 0x10000) { ++ /* It looks like a PCI device. Does it exist? */ ++ dev = acpi_get_physical_device(handle); ++ } else { ++ /* It doesn't look like a PCI device. Does its parent ++ exist? */ ++ acpi_handle phandle; ++ if (acpi_get_parent(handle, &phandle)) ++ return NULL; ++ dev = acpi_get_physical_device(phandle); ++ } ++ if (!dev) ++ return NULL; ++ return dev; ++} ++EXPORT_SYMBOL(acpi_get_physical_pci_device); ++ + static int acpi_bind_one(struct device *dev, acpi_handle handle) + { + struct acpi_device *acpi_dev; +--- a/drivers/acpi/video.c ++++ b/drivers/acpi/video.c +@@ -862,11 +862,16 @@ static void acpi_video_bus_find_cap(stru + static int acpi_video_bus_check(struct acpi_video_bus *video) + { + acpi_status status = -ENOENT; +- ++ struct device *dev; + + if (!video) + return -EINVAL; + ++ dev = acpi_get_physical_pci_device(video->device->handle); ++ if (!dev) ++ return -ENODEV; ++ put_device(dev); ++ + /* Since there is no HID, CID and so on for VGA driver, we have + * to check well known required nodes. + */ +--- a/include/acpi/acpi_bus.h ++++ b/include/acpi/acpi_bus.h +@@ -373,6 +373,8 @@ struct acpi_bus_type { + int register_acpi_bus_type(struct acpi_bus_type *); + int unregister_acpi_bus_type(struct acpi_bus_type *); + struct device *acpi_get_physical_device(acpi_handle); ++struct device *acpi_get_physical_pci_device(acpi_handle); ++ + /* helper */ + acpi_handle acpi_get_child(acpi_handle, acpi_integer); + acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); diff --git a/src/patches/suse-2.6.27.31/patches.arch/0001-Check-for-ACPI-backlight-support.patch b/src/patches/suse-2.6.27.31/patches.arch/0001-Check-for-ACPI-backlight-support.patch new file mode 100644 index 000000000..520e48993 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0001-Check-for-ACPI-backlight-support.patch @@ -0,0 +1,489 @@ +From: Thomas Renninger +Subject: [PATCH] Check for ACPI backlight support otherwise use vendor ACPI drivers +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit f43d728731c691772ddc29e50d25c68a859935b5 + +If an ACPI graphics device supports backlight brightness functions (cmp. with +latest ACPI spec Appendix B), let the ACPI video driver control backlight and +switch backlight control off in vendor specific ACPI drivers (asus_acpi, +thinkpad_acpi, eeepc, fujitsu_laptop, msi_laptop, sony_laptop, acer-wmi). + +Currently it is possible to load above drivers and let both poke on the +brightness HW registers, the video and vendor specific ACPI drivers -> bad. + +This patch provides the basic support to check for BIOS capabilities before +driver loading time. Driver specific modifications are in separate follow up +patches. + +acpi_backlight=vendor/video + boot params forces video.ko or vendor specific drivers to keep its + fingers off backlight control even it would find needed functions. + The corresponding vendor specific driver be used then. + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + Documentation/kernel-parameters.txt | 13 + + drivers/acpi/Makefile | 5 + drivers/acpi/scan.c | 32 ---- + drivers/acpi/video.c | 28 ++- + drivers/acpi/video_detect.c | 268 ++++++++++++++++++++++++++++++++++++ + include/linux/acpi.h | 44 +++++ + 6 files changed, 347 insertions(+), 43 deletions(-) + create mode 100644 drivers/acpi/video_detect.c + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -200,6 +200,19 @@ and is between 256 and 4096 characters. + that require a timer override, but don't have + HPET + ++ acpi_backlight= [HW,ACPI] ++ acpi_backlight=vendor ++ acpi_backlight=video ++ If set to vendor, it enforces the use of a ++ vendor specific ACPI driver for backlight switching ++ (e.g. thinkpad_acpi, sony_acpi, etc.) instead ++ of the video.ko driver. ++ ++ acpi_display_output= [HW,ACPI] ++ acpi_display_output=vendor ++ acpi_display_output=video ++ See above. ++ + acpi.debug_layer= [HW,ACPI] + Format: + Each bit of the indicates an ACPI debug layer, +--- a/drivers/acpi/Makefile ++++ b/drivers/acpi/Makefile +@@ -46,7 +46,12 @@ obj-$(CONFIG_ACPI_BUTTON) += button.o + obj-$(CONFIG_ACPI_FAN) += fan.o + obj-$(CONFIG_ACPI_DOCK) += dock.o + obj-$(CONFIG_ACPI_BAY) += bay.o ++ + obj-$(CONFIG_ACPI_VIDEO) += video.o ++ifdef CONFIG_ACPI_VIDEO ++obj-y += video_detect.o ++endif ++ + obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o + obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o + obj-$(CONFIG_ACPI_POWER) += power.o +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -908,36 +908,6 @@ static void acpi_device_get_busid(struct + } + } + +-static int +-acpi_video_bus_match(struct acpi_device *device) +-{ +- acpi_handle h_dummy; +- +- if (!device) +- return -EINVAL; +- +- /* Since there is no HID, CID for ACPI Video drivers, we have +- * to check well known required nodes for each feature we support. +- */ +- +- /* Does this device able to support video switching ? */ +- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && +- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) +- return 0; +- +- /* Does this device able to retrieve a video ROM ? */ +- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) +- return 0; +- +- /* Does this device able to configure which video head to be POSTed ? */ +- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && +- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && +- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) +- return 0; +- +- return -ENODEV; +-} +- + /* + * acpi_bay_match - see if a device is an ejectable driver bay + * +@@ -1020,7 +990,7 @@ static void acpi_device_set_id(struct ac + will get autoloaded and the device might still match + against another driver. + */ +- if (ACPI_SUCCESS(acpi_video_bus_match(device))) ++ if (acpi_is_video_device(device)) + cid_add = ACPI_VIDEO_HID; + else if (ACPI_SUCCESS(acpi_bay_match(device))) + cid_add = ACPI_BAY_HID; +--- a/drivers/acpi/video.c ++++ b/drivers/acpi/video.c +@@ -759,7 +759,8 @@ static void acpi_video_device_find_cap(s + device->cap._DSS = 1; + } + +- max_level = acpi_video_init_brightness(device); ++ if (acpi_video_backlight_support()) ++ max_level = acpi_video_init_brightness(device); + + if (device->cap._BCL && device->cap._BCM && max_level > 0) { + int result; +@@ -805,18 +806,21 @@ static void acpi_video_device_find_cap(s + printk(KERN_ERR PREFIX "Create sysfs link\n"); + + } +- if (device->cap._DCS && device->cap._DSS){ +- static int count = 0; +- char *name; +- name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); +- if (!name) +- return; +- sprintf(name, "acpi_video%d", count++); +- device->output_dev = video_output_register(name, +- NULL, device, &acpi_output_properties); +- kfree(name); ++ ++ if (acpi_video_display_switch_support()) { ++ ++ if (device->cap._DCS && device->cap._DSS) { ++ static int count; ++ char *name; ++ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); ++ if (!name) ++ return; ++ sprintf(name, "acpi_video%d", count++); ++ device->output_dev = video_output_register(name, ++ NULL, device, &acpi_output_properties); ++ kfree(name); ++ } + } +- return; + } + + /* +--- /dev/null ++++ b/drivers/acpi/video_detect.c +@@ -0,0 +1,268 @@ ++/* ++ * Copyright (C) 2008 SuSE Linux Products GmbH ++ * Thomas Renninger ++ * ++ * May be copied or modified under the terms of the GNU General Public License ++ * ++ * video_detect.c: ++ * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c ++ * There a Linux specific (Spec does not provide a HID for video devices) is ++ * assinged ++ * ++ * After PCI devices are glued with ACPI devices ++ * acpi_get_physical_pci_device() can be called to identify ACPI graphics ++ * devices for which a real graphics card is plugged in ++ * ++ * Now acpi_video_get_capabilities() can be called to check which ++ * capabilities the graphics cards plugged in support. The check for general ++ * video capabilities will be triggered by the first caller of ++ * acpi_video_get_capabilities(NULL); which will happen when the first ++ * backlight (or display output) switching supporting driver calls: ++ * acpi_video_backlight_support(); ++ * ++ * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) ++ * are available, video.ko should be used to handle the device. ++ * ++ * Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi, ++ * sony_acpi,... can take care about backlight brightness and display output ++ * switching. ++ * ++ * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) ++ * this file will not be compiled, acpi_video_get_capabilities() and ++ * acpi_video_backlight_support() will always return 0 and vendor specific ++ * drivers always can handle backlight. ++ * ++ */ ++ ++#include ++#include ++ ++ACPI_MODULE_NAME("video"); ++#define ACPI_VIDEO_COMPONENT 0x08000000 ++#define _COMPONENT ACPI_VIDEO_COMPONENT ++ ++static long acpi_video_support; ++static bool acpi_video_caps_checked; ++ ++static acpi_status ++acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, ++ void **retyurn_value) ++{ ++ long *cap = context; ++ acpi_handle h_dummy; ++ ++ if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && ++ ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " ++ "support\n")); ++ *cap |= ACPI_VIDEO_BACKLIGHT; ++ /* We have backlight support, no need to scan further */ ++ return AE_CTRL_TERMINATE; ++ } ++ return 0; ++} ++ ++/* Returns true if the device is a video device which can be handled by ++ * video.ko. ++ * The device will get a Linux specific CID added in scan.c to ++ * identify the device as an ACPI graphics device ++ * Be aware that the graphics device may not be physically present ++ * Use acpi_video_get_capabilities() to detect general ACPI video ++ * capabilities of present cards ++ */ ++long acpi_is_video_device(struct acpi_device *device) ++{ ++ acpi_handle h_dummy; ++ long video_caps = 0; ++ ++ if (!device) ++ return 0; ++ ++ /* Does this device able to support video switching ? */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) && ++ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) ++ video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; ++ ++ /* Does this device able to retrieve a video ROM ? */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) ++ video_caps |= ACPI_VIDEO_ROM_AVAILABLE; ++ ++ /* Does this device able to configure which video head to be POSTed ? */ ++ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && ++ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && ++ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) ++ video_caps |= ACPI_VIDEO_DEVICE_POSTING; ++ ++ /* Only check for backlight functionality if one of the above hit. */ ++ if (video_caps) ++ acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle, ++ ACPI_UINT32_MAX, acpi_backlight_cap_match, ++ &video_caps, NULL); ++ ++ return video_caps; ++} ++EXPORT_SYMBOL(acpi_is_video_device); ++ ++static acpi_status ++find_video(acpi_handle handle, u32 lvl, void *context, void **rv) ++{ ++ long *cap = context; ++ struct device *dev; ++ struct acpi_device *acpi_dev; ++ ++ const struct acpi_device_id video_ids[] = { ++ {ACPI_VIDEO_HID, 0}, ++ {"", 0}, ++ }; ++ if (acpi_bus_get_device(handle, &acpi_dev)) ++ return AE_OK; ++ ++ if (!acpi_match_device_ids(acpi_dev, video_ids)) { ++ dev = acpi_get_physical_pci_device(handle); ++ if (!dev) ++ return AE_OK; ++ put_device(dev); ++ *cap |= acpi_is_video_device(acpi_dev); ++ } ++ return AE_OK; ++} ++ ++/* ++ * Returns the video capabilities of a specific ACPI graphics device ++ * ++ * if NULL is passed as argument all ACPI devices are enumerated and ++ * all graphics capabilities of physically present devices are ++ * summerized and returned. This is cached and done only once. ++ */ ++long acpi_video_get_capabilities(acpi_handle graphics_handle) ++{ ++ long caps = 0; ++ struct acpi_device *tmp_dev; ++ acpi_status status; ++ ++ if (acpi_video_caps_checked && graphics_handle == NULL) ++ return acpi_video_support; ++ ++ if (!graphics_handle) { ++ /* Only do the global walk through all graphics devices once */ ++ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ++ ACPI_UINT32_MAX, find_video, ++ &caps, NULL); ++ /* There might be boot param flags set already... */ ++ acpi_video_support |= caps; ++ acpi_video_caps_checked = 1; ++ /* Add blacklists here. Be careful to use the right *DMI* bits ++ * to still be able to override logic via boot params, e.g.: ++ * ++ * if (dmi_name_in_vendors("XY")) { ++ * acpi_video_support |= ++ * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR; ++ * acpi_video_support |= ++ * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; ++ *} ++ */ ++ } else { ++ status = acpi_bus_get_device(graphics_handle, &tmp_dev); ++ if (ACPI_FAILURE(status)) { ++ ACPI_EXCEPTION((AE_INFO, status, "Invalid device")); ++ return 0; ++ } ++ acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, ++ ACPI_UINT32_MAX, find_video, ++ &caps, NULL); ++ } ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", ++ graphics_handle ? caps : acpi_video_support, ++ graphics_handle ? "on device " : "in general", ++ graphics_handle ? acpi_device_bid(tmp_dev) : "")); ++ return caps; ++} ++EXPORT_SYMBOL(acpi_video_get_capabilities); ++ ++/* Returns true if video.ko can do backlight switching */ ++int acpi_video_backlight_support(void) ++{ ++ /* ++ * We must check whether the ACPI graphics device is physically plugged ++ * in. Therefore this must be called after binding PCI and ACPI devices ++ */ ++ if (!acpi_video_caps_checked) ++ acpi_video_get_capabilities(NULL); ++ ++ /* First check for boot param -> highest prio */ ++ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) ++ return 0; ++ else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO) ++ return 1; ++ ++ /* Then check for DMI blacklist -> second highest prio */ ++ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR) ++ return 0; ++ else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO) ++ return 1; ++ ++ /* Then go the default way */ ++ return acpi_video_support & ACPI_VIDEO_BACKLIGHT; ++} ++EXPORT_SYMBOL(acpi_video_backlight_support); ++ ++/* ++ * Returns true if video.ko can do display output switching. ++ * This does not work well/at all with binary graphics drivers ++ * which disable system io ranges and do it on their own. ++ */ ++int acpi_video_display_switch_support(void) ++{ ++ if (!acpi_video_caps_checked) ++ acpi_video_get_capabilities(NULL); ++ ++ if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR) ++ return 0; ++ else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO) ++ return 1; ++ ++ if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR) ++ return 0; ++ else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO) ++ return 1; ++ ++ return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING; ++} ++EXPORT_SYMBOL(acpi_video_display_switch_support); ++ ++/* ++ * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video ++ * To force that backlight or display output switching is processed by vendor ++ * specific acpi drivers or video.ko driver. ++ */ ++int __init acpi_backlight(char *str) ++{ ++ if (str == NULL || *str == '\0') ++ return 1; ++ else { ++ if (!strcmp("vendor", str)) ++ acpi_video_support |= ++ ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR; ++ if (!strcmp("video", str)) ++ acpi_video_support |= ++ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; ++ } ++ return 1; ++} ++__setup("acpi_backlight=", acpi_backlight); ++ ++int __init acpi_display_output(char *str) ++{ ++ if (str == NULL || *str == '\0') ++ return 1; ++ else { ++ if (!strcmp("vendor", str)) ++ acpi_video_support |= ++ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR; ++ if (!strcmp("video", str)) ++ acpi_video_support |= ++ ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO; ++ } ++ return 1; ++} ++__setup("acpi_display_output=", acpi_display_output); +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -202,6 +202,50 @@ extern bool wmi_has_guid(const char *gui + + #endif /* CONFIG_ACPI_WMI */ + ++#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 ++#define ACPI_VIDEO_DEVICE_POSTING 0x0002 ++#define ACPI_VIDEO_ROM_AVAILABLE 0x0004 ++#define ACPI_VIDEO_BACKLIGHT 0x0008 ++#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 ++#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 ++#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 ++#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 ++#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 ++#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 ++#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 ++#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 ++ ++#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) ++ ++extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle); ++extern long acpi_is_video_device(struct acpi_device *device); ++extern int acpi_video_backlight_support(void); ++extern int acpi_video_display_switch_support(void); ++ ++#else ++ ++static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle) ++{ ++ return 0; ++} ++ ++static inline long acpi_is_video_device(struct acpi_device *device) ++{ ++ return 0; ++} ++ ++static inline int acpi_video_backlight_support(void) ++{ ++ return 0; ++} ++ ++static inline int acpi_video_display_switch_support(void) ++{ ++ return 0; ++} ++ ++#endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */ ++ + extern int acpi_blacklisted(void); + #ifdef CONFIG_DMI + extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); diff --git a/src/patches/suse-2.6.27.31/patches.arch/0002-Acer-WMI-fingers-off-backlight-video.ko.patch b/src/patches/suse-2.6.27.31/patches.arch/0002-Acer-WMI-fingers-off-backlight-video.ko.patch new file mode 100644 index 000000000..b3bb88254 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0002-Acer-WMI-fingers-off-backlight-video.ko.patch @@ -0,0 +1,27 @@ +From: Thomas Renninger +Subject: [PATCH] Acer-WMI: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit 017f8ecd1cedb482392f0500ee3701b8c50a46f9 + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/acer-wmi.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/misc/acer-wmi.c ++++ b/drivers/misc/acer-wmi.c +@@ -1242,6 +1242,12 @@ static int __init acer_wmi_init(void) + + set_quirks(); + ++ if (!acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { ++ interface->capability &= ~ACER_CAP_BRIGHTNESS; ++ printk(ACER_INFO "Brightness must be controlled by " ++ "generic video driver\n"); ++ } ++ + if (platform_driver_register(&acer_platform_driver)) { + printk(ACER_ERR "Unable to register platform driver.\n"); + goto error_platform_register; diff --git a/src/patches/suse-2.6.27.31/patches.arch/0003-Asus-acpi-fingers-off-backlight.patch b/src/patches/suse-2.6.27.31/patches.arch/0003-Asus-acpi-fingers-off-backlight.patch new file mode 100644 index 000000000..b17c411e8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0003-Asus-acpi-fingers-off-backlight.patch @@ -0,0 +1,31 @@ +From: Thomas Renninger +Subject: [PATCH] asus-acpi: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit aaa47082a287d66fad32e3289e01bb9419ab18da + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/asus-laptop.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/misc/asus-laptop.c ++++ b/drivers/misc/asus-laptop.c +@@ -1208,9 +1208,13 @@ static int __init asus_laptop_init(void) + + dev = acpi_get_physical_device(hotk->device->handle); + +- result = asus_backlight_init(dev); +- if (result) +- goto fail_backlight; ++ if (!acpi_video_backlight_support()) { ++ result = asus_backlight_init(dev); ++ if (result) ++ goto fail_backlight; ++ } else ++ printk(ASUS_INFO "Brightness ignored, must be controlled by " ++ "ACPI video driver\n"); + + result = asus_led_init(dev); + if (result) diff --git a/src/patches/suse-2.6.27.31/patches.arch/0004-Compal-fingers-off-backlight.patch b/src/patches/suse-2.6.27.31/patches.arch/0004-Compal-fingers-off-backlight.patch new file mode 100644 index 000000000..b25b368d8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0004-Compal-fingers-off-backlight.patch @@ -0,0 +1,39 @@ +From: Thomas Renninger +Subject: [PATCH] compal: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit efbc58e3236022d040e1c1f177ee5971d46b034f + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/compal-laptop.c | 12 +++++++----- + 1 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/misc/compal-laptop.c b/drivers/misc/compal-laptop.c +index 344b790..11003bb 100644 +--- a/drivers/misc/compal-laptop.c ++++ b/drivers/misc/compal-laptop.c +@@ -326,12 +326,14 @@ static int __init compal_init(void) + + /* Register backlight stuff */ + +- compalbl_device = backlight_device_register("compal-laptop", NULL, NULL, +- &compalbl_ops); +- if (IS_ERR(compalbl_device)) +- return PTR_ERR(compalbl_device); ++ if (!acpi_video_backlight_support()) { ++ compalbl_device = backlight_device_register("compal-laptop", NULL, NULL, ++ &compalbl_ops); ++ if (IS_ERR(compalbl_device)) ++ return PTR_ERR(compalbl_device); + +- compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1; ++ compalbl_device->props.max_brightness = COMPAL_LCD_LEVEL_MAX-1; ++ } + + ret = platform_driver_register(&compal_driver); + if (ret) +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.arch/0005-eeepc-laptop-fingers-off.patch b/src/patches/suse-2.6.27.31/patches.arch/0005-eeepc-laptop-fingers-off.patch new file mode 100644 index 000000000..eefad60eb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0005-eeepc-laptop-fingers-off.patch @@ -0,0 +1,31 @@ +From: Thomas Renninger +Subject: [PATCH] eeepc-laptop: fingers off backlight if video.ko is serving this functionality +commit bb7e1665304cba64b1178237c966308d06b33182 + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/eeepc-laptop.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/drivers/misc/eeepc-laptop.c ++++ b/drivers/misc/eeepc-laptop.c +@@ -636,9 +636,15 @@ static int __init eeepc_laptop_init(void + return -ENODEV; + } + dev = acpi_get_physical_device(ehotk->device->handle); +- result = eeepc_backlight_init(dev); +- if (result) +- goto fail_backlight; ++ ++ if (!acpi_video_backlight_support()) { ++ result = eeepc_backlight_init(dev); ++ if (result) ++ goto fail_backlight; ++ } else ++ printk(EEEPC_INFO "Backlight controlled by ACPI video " ++ "driver\n"); ++ + result = eeepc_hwmon_init(dev); + if (result) + goto fail_hwmon; diff --git a/src/patches/suse-2.6.27.31/patches.arch/0006-fujitsu-laptop-fingers-off-backlight.patch b/src/patches/suse-2.6.27.31/patches.arch/0006-fujitsu-laptop-fingers-off-backlight.patch new file mode 100644 index 000000000..cc2e6fa9f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0006-fujitsu-laptop-fingers-off-backlight.patch @@ -0,0 +1,61 @@ +From: Thomas Renninger +Subject: [PATCH] fujitsu-laptop: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit 44cce15b053d27477980e34b1086e0c3ce642afe + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/fujitsu-laptop.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/misc/fujitsu-laptop.c ++++ b/drivers/misc/fujitsu-laptop.c +@@ -970,16 +970,16 @@ static int __init fujitsu_init(void) + + /* Register backlight stuff */ + +- fujitsu->bl_device = +- backlight_device_register("fujitsu-laptop", NULL, NULL, +- &fujitsubl_ops); +- if (IS_ERR(fujitsu->bl_device)) +- return PTR_ERR(fujitsu->bl_device); +- +- max_brightness = fujitsu->max_brightness; +- +- fujitsu->bl_device->props.max_brightness = max_brightness - 1; +- fujitsu->bl_device->props.brightness = fujitsu->brightness_level; ++ if (!acpi_video_backlight_support()) { ++ fujitsu->bl_device = ++ backlight_device_register("fujitsu-laptop", NULL, NULL, ++ &fujitsubl_ops); ++ if (IS_ERR(fujitsu->bl_device)) ++ return PTR_ERR(fujitsu->bl_device); ++ max_brightness = fujitsu->max_brightness; ++ fujitsu->bl_device->props.max_brightness = max_brightness - 1; ++ fujitsu->bl_device->props.brightness = fujitsu->brightness_level; ++ } + + ret = platform_driver_register(&fujitsupf_driver); + if (ret) +@@ -1015,7 +1015,8 @@ fail_hotkey: + + fail_backlight: + +- backlight_device_unregister(fujitsu->bl_device); ++ if (fujitsu->bl_device) ++ backlight_device_unregister(fujitsu->bl_device); + + fail_platform_device2: + +@@ -1042,7 +1043,8 @@ static void __exit fujitsu_cleanup(void) + &fujitsupf_attribute_group); + platform_device_unregister(fujitsu->pf_device); + platform_driver_unregister(&fujitsupf_driver); +- backlight_device_unregister(fujitsu->bl_device); ++ if (fujitsu->bl_device) ++ backlight_device_unregister(fujitsu->bl_device); + + acpi_bus_unregister_driver(&acpi_fujitsu_driver); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/0007-msi-laptop-fingers-off-backlight.patch b/src/patches/suse-2.6.27.31/patches.arch/0007-msi-laptop-fingers-off-backlight.patch new file mode 100644 index 000000000..acfd9ff8c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0007-msi-laptop-fingers-off-backlight.patch @@ -0,0 +1,42 @@ +From: Thomas Renninger +Subject: [PATCH] msi-laptop: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit a8c338259a436627d2427d70dc31fac67b86b9e6 + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/msi-laptop.c | 16 ++++++++++------ + 1 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c +index de898c6..759763d 100644 +--- a/drivers/misc/msi-laptop.c ++++ b/drivers/misc/msi-laptop.c +@@ -347,12 +347,16 @@ static int __init msi_init(void) + + /* Register backlight stuff */ + +- msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL, +- &msibl_ops); +- if (IS_ERR(msibl_device)) +- return PTR_ERR(msibl_device); +- +- msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; ++ if (acpi_video_backlight_support()) { ++ printk(KERN_INFO "MSI: Brightness ignored, must be controlled " ++ "by ACPI video driver\n"); ++ } else { ++ msibl_device = backlight_device_register("msi-laptop-bl", NULL, ++ NULL, &msibl_ops); ++ if (IS_ERR(msibl_device)) ++ return PTR_ERR(msibl_device); ++ msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; ++ } + + ret = platform_driver_register(&msipf_driver); + if (ret) +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.arch/0008-sony-laptop-fingers-off-backlight.patch b/src/patches/suse-2.6.27.31/patches.arch/0008-sony-laptop-fingers-off-backlight.patch new file mode 100644 index 000000000..3ba719391 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0008-sony-laptop-fingers-off-backlight.patch @@ -0,0 +1,32 @@ +From: Thomas Renninger +Subject: [PATCH] sony-laptop: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit 1d38a0697573617e7f4d184207cced6cbe8d54d5 + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/sony-laptop.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c +index 60775be..3d178ab 100644 +--- a/drivers/misc/sony-laptop.c ++++ b/drivers/misc/sony-laptop.c +@@ -1038,7 +1038,11 @@ static int sony_nc_add(struct acpi_device *device) + goto outinput; + } + +- if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { ++ if (acpi_video_backlight_support()) { ++ printk(KERN_INFO DRV_PFX "Sony: Brightness ignored, must be " ++ "controlled by ACPI video driver\n"); ++ } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", ++ &handle))) { + sony_backlight_device = backlight_device_register("sony", NULL, + NULL, + &sony_backlight_ops); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.arch/0009-thinkpad_acpi-fingers-off-backlight.patch b/src/patches/suse-2.6.27.31/patches.arch/0009-thinkpad_acpi-fingers-off-backlight.patch new file mode 100644 index 000000000..8825a5fd8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/0009-thinkpad_acpi-fingers-off-backlight.patch @@ -0,0 +1,50 @@ +From: Thomas Renninger +Subject: [PATCH] thinkpad_acpi: fingers off backlight if video.ko is serving this functionality +Patch-Mainline: queued for .28 in Len's/ak's ACPI tree + +commit bcca9a4a97b6e270793003d745d6f9439e1357a8 + +Signed-off-by: Thomas Renninger +Signed-off-by: Andi Kleen +--- + drivers/misc/thinkpad_acpi.c | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -4918,16 +4918,25 @@ static int __init brightness_init(struct + */ + b = tpacpi_check_std_acpi_brightness_support(); + if (b > 0) { +- if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { +- printk(TPACPI_NOTICE +- "Lenovo BIOS switched to ACPI backlight " +- "control mode\n"); +- } +- if (brightness_enable > 1) { +- printk(TPACPI_NOTICE +- "standard ACPI backlight interface " +- "available, not loading native one...\n"); +- return 1; ++ ++ if (acpi_video_backlight_support()) { ++ if (brightness_enable > 1) { ++ printk(TPACPI_NOTICE ++ "Standard ACPI backlight interface " ++ "available, not loading native one.\n"); ++ return 1; ++ } else if (brightness_enable == 1) { ++ printk(TPACPI_NOTICE ++ "Backlight control force, even standard " ++ "ACPI backlight interface available\n"); ++ } ++ } else { ++ if (brightness_enable > 1) { ++ printk(TPACPI_NOTICE ++ "Standard ACPI backlight interface not " ++ "available, thinkpad_acpi driver " ++ "will take over control\n"); ++ } + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-bay-remove-from-makefile b/src/patches/suse-2.6.27.31/patches.arch/acpi-bay-remove-from-makefile new file mode 100644 index 000000000..7af4962f7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-bay-remove-from-makefile @@ -0,0 +1,39 @@ +From: Jeff Mahoney +Subject: acpi: remove bay.c from makefile + + patches.fixes/acpi-bay-remove-useless-code.patch removed drivers/acpi/bay.c. + This patch removes the build infrastructure for it. + +Signed-off-by: Jeff Mahoney +--- + drivers/acpi/Kconfig | 8 -------- + drivers/acpi/Makefile | 1 - + 2 files changed, 9 deletions(-) + +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -162,14 +162,6 @@ config ACPI_DOCK + help + This driver adds support for ACPI controlled docking stations + +-config ACPI_BAY +- tristate "Removable Drive Bay (EXPERIMENTAL)" +- depends on EXPERIMENTAL +- depends on ACPI_DOCK +- help +- This driver adds support for ACPI controlled removable drive +- bays such as the IBM ultrabay or the Dell Module Bay. +- + config ACPI_PROCESSOR + tristate "Processor" + select THERMAL +--- a/drivers/acpi/Makefile ++++ b/drivers/acpi/Makefile +@@ -45,7 +45,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o + obj-$(CONFIG_ACPI_BUTTON) += button.o + obj-$(CONFIG_ACPI_FAN) += fan.o + obj-$(CONFIG_ACPI_DOCK) += dock.o +-obj-$(CONFIG_ACPI_BAY) += bay.o + + obj-$(CONFIG_ACPI_VIDEO) += video.o + ifdef CONFIG_ACPI_VIDEO diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-bay-remove-useless-code.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-bay-remove-useless-code.patch new file mode 100644 index 000000000..916322fee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-bay-remove-useless-code.patch @@ -0,0 +1,425 @@ +From: Shaohua Li +Subject: remove useless code +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +Bay driver is replaced by dock driver, remove it. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +--- linux-2.6.26.orig/drivers/acpi/bay.c 2008-07-13 23:51:29.000000000 +0200 ++++ linux-2.6.26/drivers/acpi/bay.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,411 +0,0 @@ +-/* +- * bay.c - ACPI removable drive bay driver +- * +- * Copyright (C) 2006 Kristen Carlson Accardi +- * +- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or (at +- * your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, but +- * WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License along +- * with this program; if not, write to the Free Software Foundation, Inc., +- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +- * +- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- */ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-ACPI_MODULE_NAME("bay"); +-MODULE_AUTHOR("Kristen Carlson Accardi"); +-MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver"); +-MODULE_LICENSE("GPL"); +-#define ACPI_BAY_CLASS "bay" +-#define ACPI_BAY_COMPONENT 0x10000000 +-#define _COMPONENT ACPI_BAY_COMPONENT +-#define bay_dprintk(h,s) {\ +- char prefix[80] = {'\0'};\ +- struct acpi_buffer buffer = {sizeof(prefix), prefix};\ +- acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ +- printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } +-static void bay_notify(acpi_handle handle, u32 event, void *data); +- +-static const struct acpi_device_id bay_device_ids[] = { +- {"LNXIOBAY", 0}, +- {"", 0}, +-}; +-MODULE_DEVICE_TABLE(acpi, bay_device_ids); +- +-struct bay { +- acpi_handle handle; +- char *name; +- struct list_head list; +- struct platform_device *pdev; +-}; +- +-static LIST_HEAD(drive_bays); +- +- +-/***************************************************************************** +- * Drive Bay functions * +- *****************************************************************************/ +-/** +- * is_ejectable - see if a device is ejectable +- * @handle: acpi handle of the device +- * +- * If an acpi object has a _EJ0 method, then it is ejectable +- */ +-static int is_ejectable(acpi_handle handle) +-{ +- acpi_status status; +- acpi_handle tmp; +- +- status = acpi_get_handle(handle, "_EJ0", &tmp); +- if (ACPI_FAILURE(status)) +- return 0; +- return 1; +-} +- +-/** +- * bay_present - see if the bay device is present +- * @bay: the drive bay +- * +- * execute the _STA method. +- */ +-static int bay_present(struct bay *bay) +-{ +- unsigned long long sta; +- acpi_status status; +- +- if (bay) { +- status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta); +- if (ACPI_SUCCESS(status) && sta) +- return 1; +- } +- return 0; +-} +- +-/** +- * eject_device - respond to an eject request +- * @handle - the device to eject +- * +- * Call this devices _EJ0 method. +- */ +-static void eject_device(acpi_handle handle) +-{ +- struct acpi_object_list arg_list; +- union acpi_object arg; +- +- bay_dprintk(handle, "Ejecting device"); +- +- arg_list.count = 1; +- arg_list.pointer = &arg; +- arg.type = ACPI_TYPE_INTEGER; +- arg.integer.value = 1; +- +- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", +- &arg_list, NULL))) +- pr_debug("Failed to evaluate _EJ0!\n"); +-} +- +-/* +- * show_present - read method for "present" file in sysfs +- */ +-static ssize_t show_present(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- struct bay *bay = dev_get_drvdata(dev); +- return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); +- +-} +-static DEVICE_ATTR(present, S_IRUGO, show_present, NULL); +- +-/* +- * write_eject - write method for "eject" file in sysfs +- */ +-static ssize_t write_eject(struct device *dev, struct device_attribute *attr, +- const char *buf, size_t count) +-{ +- struct bay *bay = dev_get_drvdata(dev); +- +- if (!count) +- return -EINVAL; +- +- eject_device(bay->handle); +- return count; +-} +-static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); +- +-/** +- * is_ata - see if a device is an ata device +- * @handle: acpi handle of the device +- * +- * If an acpi object has one of 4 ATA ACPI methods defined, +- * then it is an ATA device +- */ +-static int is_ata(acpi_handle handle) +-{ +- acpi_handle tmp; +- +- if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || +- (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || +- (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || +- (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) +- return 1; +- +- return 0; +-} +- +-/** +- * parent_is_ata(acpi_handle handle) +- * +- */ +-static int parent_is_ata(acpi_handle handle) +-{ +- acpi_handle phandle; +- +- if (acpi_get_parent(handle, &phandle)) +- return 0; +- +- return is_ata(phandle); +-} +- +-/** +- * is_ejectable_bay - see if a device is an ejectable drive bay +- * @handle: acpi handle of the device +- * +- * If an acpi object is ejectable and has one of the ACPI ATA +- * methods defined, then we can safely call it an ejectable +- * drive bay +- */ +-static int is_ejectable_bay(acpi_handle handle) +-{ +- if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle)) +- return 1; +- return 0; +-} +- +-#if 0 +-/** +- * eject_removable_drive - try to eject this drive +- * @dev : the device structure of the drive +- * +- * If a device is a removable drive that requires an _EJ0 method +- * to be executed in order to safely remove from the system, do +- * it. ATM - always returns success +- */ +-int eject_removable_drive(struct device *dev) +-{ +- acpi_handle handle = DEVICE_ACPI_HANDLE(dev); +- +- if (handle) { +- bay_dprintk(handle, "Got device handle"); +- if (is_ejectable_bay(handle)) +- eject_device(handle); +- } else { +- printk("No acpi handle for device\n"); +- } +- +- /* should I return an error code? */ +- return 0; +-} +-EXPORT_SYMBOL_GPL(eject_removable_drive); +-#endif /* 0 */ +- +-static int acpi_bay_add_fs(struct bay *bay) +-{ +- int ret; +- struct device *dev = &bay->pdev->dev; +- +- ret = device_create_file(dev, &dev_attr_present); +- if (ret) +- goto add_fs_err; +- ret = device_create_file(dev, &dev_attr_eject); +- if (ret) { +- device_remove_file(dev, &dev_attr_present); +- goto add_fs_err; +- } +- return 0; +- +- add_fs_err: +- bay_dprintk(bay->handle, "Error adding sysfs files\n"); +- return ret; +-} +- +-static void acpi_bay_remove_fs(struct bay *bay) +-{ +- struct device *dev = &bay->pdev->dev; +- +- /* cleanup sysfs */ +- device_remove_file(dev, &dev_attr_present); +- device_remove_file(dev, &dev_attr_eject); +-} +- +-static int bay_is_dock_device(acpi_handle handle) +-{ +- acpi_handle parent; +- +- acpi_get_parent(handle, &parent); +- +- /* if the device or it's parent is dependent on the +- * dock, then we are a dock device +- */ +- return (is_dock_device(handle) || is_dock_device(parent)); +-} +- +-static int bay_add(acpi_handle handle, int id) +-{ +- acpi_status status; +- struct bay *new_bay; +- struct platform_device *pdev; +- struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL}; +- acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer); +- +- bay_dprintk(handle, "Adding notify handler"); +- +- /* +- * Initialize bay device structure +- */ +- new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC); +- INIT_LIST_HEAD(&new_bay->list); +- new_bay->handle = handle; +- new_bay->name = (char *)nbuffer.pointer; +- +- /* initialize platform device stuff */ +- pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); +- if (IS_ERR(pdev)) { +- printk(KERN_ERR PREFIX "Error registering bay device\n"); +- goto bay_add_err; +- } +- new_bay->pdev = pdev; +- platform_set_drvdata(pdev, new_bay); +- +- /* +- * we want the bay driver to be able to send uevents +- */ +- pdev->dev.uevent_suppress = 0; +- +- /* register for events on this device */ +- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, +- bay_notify, new_bay); +- if (ACPI_FAILURE(status)) { +- printk(KERN_INFO PREFIX "Error installing bay notify handler\n"); +- platform_device_unregister(new_bay->pdev); +- goto bay_add_err; +- } +- +- if (acpi_bay_add_fs(new_bay)) { +- acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, +- bay_notify); +- platform_device_unregister(new_bay->pdev); +- goto bay_add_err; +- } +- +- /* if we are on a dock station, we should register for dock +- * notifications. +- */ +- if (bay_is_dock_device(handle)) { +- bay_dprintk(handle, "Is dependent on dock\n"); +- register_hotplug_dock_device(handle, bay_notify, new_bay); +- } +- list_add(&new_bay->list, &drive_bays); +- printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name); +- return 0; +- +-bay_add_err: +- kfree(new_bay->name); +- kfree(new_bay); +- return -ENODEV; +-} +- +-/** +- * bay_notify - act upon an acpi bay notification +- * @handle: the bay handle +- * @event: the acpi event +- * @data: our driver data struct +- * +- */ +-static void bay_notify(acpi_handle handle, u32 event, void *data) +-{ +- struct bay *bay_dev = (struct bay *)data; +- struct device *dev = &bay_dev->pdev->dev; +- char event_string[12]; +- char *envp[] = { event_string, NULL }; +- +- bay_dprintk(handle, "Bay event"); +- sprintf(event_string, "BAY_EVENT=%d", event); +- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); +-} +- +-static acpi_status +-find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) +-{ +- int *count = (int *)context; +- +- /* +- * there could be more than one ejectable bay. +- * so, just return AE_OK always so that every object +- * will be checked. +- */ +- if (is_ejectable_bay(handle)) { +- bay_dprintk(handle, "found ejectable bay"); +- if (!bay_add(handle, *count)) +- (*count)++; +- } +- return AE_OK; +-} +- +-static int __init bay_init(void) +-{ +- int bays = 0; +- +- INIT_LIST_HEAD(&drive_bays); +- +- if (acpi_disabled) +- return -ENODEV; +- +- /* look for dockable drive bays */ +- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, +- ACPI_UINT32_MAX, find_bay, &bays, NULL); +- +- if (!bays) +- return -ENODEV; +- +- return 0; +-} +- +-static void __exit bay_exit(void) +-{ +- struct bay *bay, *tmp; +- +- list_for_each_entry_safe(bay, tmp, &drive_bays, list) { +- if (is_dock_device(bay->handle)) +- unregister_hotplug_dock_device(bay->handle); +- acpi_bay_remove_fs(bay); +- acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY, +- bay_notify); +- platform_device_unregister(bay->pdev); +- kfree(bay->name); +- kfree(bay); +- } +-} +- +-postcore_initcall(bay_init); +-module_exit(bay_exit); +- diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-Fix-duplicate-notification-handler-register.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-Fix-duplicate-notification-handler-register.patch new file mode 100644 index 000000000..bd90bb732 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-Fix-duplicate-notification-handler-register.patch @@ -0,0 +1,164 @@ +From: Shaohua Li +Subject: Fix duplicate notification handler register +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +Battery driver already registers notification handler. To avoid register +notification handler again, the patch introduced a notifier chain in +global system notifier handler and use it in dock driver, so we can +avoid register notification handler. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +--- + drivers/acpi/bus.c | 15 +++++++++++++++ + drivers/acpi/dock.c | 46 ++++++++++++++++++++++++---------------------- + include/acpi/acpi_bus.h | 3 +++ + 3 files changed, 42 insertions(+), 22 deletions(-) + +--- a/drivers/acpi/bus.c ++++ b/drivers/acpi/bus.c +@@ -496,6 +496,19 @@ static int acpi_bus_check_scope(struct a + return 0; + } + ++static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); ++int register_acpi_bus_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&acpi_bus_notify_list, nb); ++} ++EXPORT_SYMBOL_GPL(register_acpi_bus_notifier); ++ ++void unregister_acpi_bus_notifier(struct notifier_block *nb) ++{ ++ blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb); ++} ++EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); ++ + /** + * acpi_bus_notify + * --------------- +@@ -506,6 +519,8 @@ static void acpi_bus_notify(acpi_handle + int result = 0; + struct acpi_device *device = NULL; + ++ blocking_notifier_call_chain(&acpi_bus_notify_list, ++ type, (void *)handle); + + if (acpi_bus_get_device(handle, &device)) + return; +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -748,6 +748,28 @@ static void dock_notify(acpi_handle hand + } + } + ++static int acpi_dock_notifier_call(struct notifier_block *this, ++ unsigned long event, void *data) ++{ ++ struct dock_station *dock_station; ++ acpi_handle handle = (acpi_handle)data; ++ ++ if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK ++ && event != ACPI_NOTIFY_EJECT_REQUEST) ++ return 0; ++ list_for_each_entry(dock_station, &dock_stations, sibiling) { ++ if (dock_station->handle == handle) { ++ dock_notify(handle, event, dock_station); ++ return 0 ; ++ } ++ } ++ return 0; ++} ++ ++static struct notifier_block dock_acpi_notifier = { ++ .notifier_call = acpi_dock_notifier_call, ++}; ++ + /** + * find_dock_devices - find devices on the dock station + * @handle: the handle of the device we are examining +@@ -859,7 +881,6 @@ static DEVICE_ATTR(uid, S_IRUGO, show_do + static int dock_add(acpi_handle handle) + { + int ret; +- acpi_status status; + struct dock_dependent_device *dd; + struct dock_station *dock_station; + struct platform_device *dock_device; +@@ -954,23 +975,10 @@ static int dock_add(acpi_handle handle) + } + add_dock_dependent_device(dock_station, dd); + +- /* register for dock events */ +- status = acpi_install_notify_handler(dock_station->handle, +- ACPI_SYSTEM_NOTIFY, +- dock_notify, dock_station); +- +- if (ACPI_FAILURE(status)) { +- printk(KERN_ERR PREFIX "Error installing notify handler\n"); +- ret = -ENODEV; +- goto dock_add_err; +- } +- + dock_station_count++; + list_add(&dock_station->sibiling, &dock_stations); + return 0; + +-dock_add_err: +- kfree(dd); + dock_add_err_unregister: + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); +@@ -988,7 +996,6 @@ dock_add_err_unregister: + static int dock_remove(struct dock_station *dock_station) + { + struct dock_dependent_device *dd, *tmp; +- acpi_status status; + struct platform_device *dock_device = dock_station->dock_device; + + if (!dock_station_count) +@@ -999,13 +1006,6 @@ static int dock_remove(struct dock_stati + list) + kfree(dd); + +- /* remove dock notify handler */ +- status = acpi_remove_notify_handler(dock_station->handle, +- ACPI_SYSTEM_NOTIFY, +- dock_notify); +- if (ACPI_FAILURE(status)) +- printk(KERN_ERR "Error removing notify handler\n"); +- + /* cleanup sysfs */ + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); +@@ -1067,6 +1067,7 @@ static int __init dock_init(void) + return 0; + } + ++ register_acpi_bus_notifier(&dock_acpi_notifier); + printk(KERN_INFO PREFIX "%s: %d docks/bays found\n", + ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); + return 0; +@@ -1076,6 +1077,7 @@ static void __exit dock_exit(void) + { + struct dock_station *dock_station; + ++ unregister_acpi_bus_notifier(&dock_acpi_notifier); + list_for_each_entry(dock_station, &dock_stations, sibiling) + dock_remove(dock_station); + } +--- a/include/acpi/acpi_bus.h ++++ b/include/acpi/acpi_bus.h +@@ -327,6 +327,9 @@ int acpi_bus_get_private_data(acpi_handl + extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); + extern int register_acpi_notifier(struct notifier_block *); + extern int unregister_acpi_notifier(struct notifier_block *); ++ ++extern int register_acpi_bus_notifier(struct notifier_block *nb); ++extern void unregister_acpi_bus_notifier(struct notifier_block *nb); + /* + * External Functions + */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-_LCK-support-for-dock.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-_LCK-support-for-dock.patch new file mode 100644 index 000000000..13a6b936d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-_LCK-support-for-dock.patch @@ -0,0 +1,57 @@ +From: Shaohua Li +Subject: add _LCK support for dock +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +support _LCK method, which is a optional method for hotplug + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c +index 78d27ce..7bdf93b 100644 +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -452,6 +452,25 @@ static inline void complete_undock(struct dock_station *ds) + ds->flags &= ~(DOCK_UNDOCKING); + } + ++static void dock_lock(struct dock_station *ds, int lock) ++{ ++ struct acpi_object_list arg_list; ++ union acpi_object arg; ++ acpi_status status; ++ ++ arg_list.count = 1; ++ arg_list.pointer = &arg; ++ arg.type = ACPI_TYPE_INTEGER; ++ arg.integer.value = !!lock; ++ status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); ++ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { ++ if (lock) ++ printk(KERN_WARNING PREFIX "Locking device failed\n"); ++ else ++ printk(KERN_WARNING PREFIX "Unlocking device failed\n"); ++ } ++} ++ + /** + * dock_in_progress - see if we are in the middle of handling a dock event + * @ds: the dock station +@@ -577,6 +596,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) + + hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + undock(ds); ++ dock_lock(ds, 0); + eject_dock(ds); + if (dock_present(ds)) { + printk(KERN_ERR PREFIX "Unable to undock!\n"); +@@ -617,6 +637,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) + hotplug_dock_devices(ds, event); + complete_dock(ds); + dock_event(ds, event, DOCK_EVENT); ++ dock_lock(ds, 1); + } + break; + case ACPI_NOTIFY_DEVICE_CHECK: diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-add-type-sysfs-file-for-dock.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-add-type-sysfs-file-for-dock.patch new file mode 100644 index 000000000..a450cb574 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-add-type-sysfs-file-for-dock.patch @@ -0,0 +1,70 @@ +From: Shaohua Li +Subject: add 'type' sysfs file for dock +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +add a sysfs file to present dock type. Suggested by Holger. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +--- + drivers/acpi/dock.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -909,6 +909,26 @@ static ssize_t show_dock_uid(struct devi + } + static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); + ++static ssize_t show_dock_type(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dock_station *dock_station = *((struct dock_station **) ++ dev->platform_data); ++ char *type; ++ ++ if (dock_station->flags & DOCK_IS_DOCK) ++ type = "dock_station"; ++ else if (dock_station->flags & DOCK_IS_ATA) ++ type = "ata_bay"; ++ else if (dock_station->flags & DOCK_IS_BAT) ++ type = "battery_bay"; ++ else ++ type = "unknown"; ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", type); ++} ++static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); ++ + /** + * dock_add - add a new dock station + * @handle: the dock station handle +@@ -997,6 +1017,9 @@ static int dock_add(acpi_handle handle) + dock_station = NULL; + return ret; + } ++ ret = device_create_file(&dock_device->dev, &dev_attr_type); ++ if (ret) ++ printk(KERN_ERR"Error %d adding sysfs file\n", ret); + + /* Find dependent devices */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, +@@ -1018,6 +1041,7 @@ static int dock_add(acpi_handle handle) + return 0; + + dock_add_err_unregister: ++ device_remove_file(&dock_device->dev, &dev_attr_type); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); +@@ -1045,6 +1069,7 @@ static int dock_remove(struct dock_stati + kfree(dd); + + /* cleanup sysfs */ ++ device_remove_file(&dock_device->dev, &dev_attr_type); + device_remove_file(&dock_device->dev, &dev_attr_docked); + device_remove_file(&dock_device->dev, &dev_attr_undock); + device_remove_file(&dock_device->dev, &dev_attr_uid); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-don-t-eval-_sta-on-every-show_docked-sysfs-read.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-don-t-eval-_sta-on-every-show_docked-sysfs-read.patch new file mode 100644 index 000000000..f1c4f9baa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-don-t-eval-_sta-on-every-show_docked-sysfs-read.patch @@ -0,0 +1,47 @@ +From 1d672ef324e78a467603ef55aa4558cac9f895ba Mon Sep 17 00:00:00 2001 +From: Holger Macht +Date: Tue, 20 Jan 2009 12:18:24 +0100 +Subject: ACPI: dock: Don't eval _STA on every show_docked sysfs read + +From: Holger Macht + +commit fc5a9f8841ee87d93376ada5d73117d4d6a373ea upstream. + +Some devices trigger a DEVICE_CHECK on every evalutation of _STA. This +can also be seen in commit 8b59560a3baf2e7c24e0fb92ea5d09eca92805db +(ACPI: dock: avoid check _STA method). If an undock is processed, the +dock driver sends a uevent and userspace might read the show_docked +property in sysfs. This causes an evaluation of _STA of the particular +device which causes the dock driver to immediately dock again. + +In any case, evaluation of _STA (show_docked) does not necessarily mean +that we are docked, so check with the internal device structure. + +http://bugzilla.kernel.org/show_bug.cgi?id=12360 + +Signed-off-by: Holger Macht +Signed-off-by: Len Brown +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/dock.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -854,8 +854,14 @@ fdd_out: + static ssize_t show_docked(struct device *dev, + struct device_attribute *attr, char *buf) + { +- return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); ++ struct acpi_device *tmp; + ++ struct dock_station *dock_station = *((struct dock_station **) ++ dev->platform_data); ++ ++ if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp))) ++ return snprintf(buf, PAGE_SIZE, "1\n"); ++ return snprintf(buf, PAGE_SIZE, "0\n"); + } + static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-eject-request-process.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-eject-request-process.patch new file mode 100644 index 000000000..e3158b82e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-eject-request-process.patch @@ -0,0 +1,30 @@ +From: Shaohua Li +Subject: fix eject request process +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +commit 2a7feab28d3fc060d320eaba192e49dad1079b7e introduces a bug. +My thinkpad actually will send an eject_request and we should follow the +eject process to finish the eject, otherwise system still thinks the bay +is present. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c +index 25d2161..78d27ce 100644 +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -575,11 +575,6 @@ static int handle_eject_request(struct dock_station *ds, u32 event) + */ + dock_event(ds, event, UNDOCK_EVENT); + +- if (!dock_present(ds)) { +- complete_undock(ds); +- return -ENODEV; +- } +- + hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + undock(ds); + eject_dock(ds); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-for-bay-in-a-dock-station.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-for-bay-in-a-dock-station.patch new file mode 100644 index 000000000..7e8244b7d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-for-bay-in-a-dock-station.patch @@ -0,0 +1,61 @@ +From: Shaohua Li +Subject: fix for bay in a dock station +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +an ATA bay can be in a dock and itself can be ejected separately. The +patch handles such eject bay. Found by Holger. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +--- + drivers/acpi/dock.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -609,6 +609,7 @@ register_hotplug_dock_device(acpi_handle + { + struct dock_dependent_device *dd; + struct dock_station *dock_station; ++ int ret = -EINVAL; + + if (!dock_station_count) + return -ENODEV; +@@ -618,16 +619,21 @@ register_hotplug_dock_device(acpi_handle + * this would include the dock station itself + */ + list_for_each_entry(dock_station, &dock_stations, sibiling) { ++ /* ++ * An ATA bay can be in a dock and itself can be ejected ++ * seperately, so there are two 'dock stations' which need the ++ * ops ++ */ + dd = find_dock_dependent_device(dock_station, handle); + if (dd) { + dd->ops = ops; + dd->context = context; + dock_add_hotplug_device(dock_station, dd); +- return 0; ++ ret = 0; + } + } + +- return -EINVAL; ++ return ret; + } + + EXPORT_SYMBOL_GPL(register_hotplug_dock_device); +@@ -1076,8 +1082,8 @@ find_dock(acpi_handle handle, u32 lvl, v + static acpi_status + find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) + { +- /* If bay is in a dock, it's already handled */ +- if (is_ejectable_bay(handle) && !is_dock_device(handle)) ++ /* If bay is a dock, it's already handled */ ++ if (is_ejectable_bay(handle) && !is_dock(handle)) + dock_add(handle); + return AE_OK; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-hotplug-race.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-hotplug-race.patch new file mode 100644 index 000000000..2a622cca0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-fix-hotplug-race.patch @@ -0,0 +1,160 @@ +From: Shaohua Li +Subject: fix hotplug race +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +hotplug notification handler and drivers' notification handler are all +running in one workqueue. Before hotplug removes an acpi device, the +device driver's notification handler is already be recorded to run just +after global notification handler. After hotplug notification handler +runs, acpica will notice a NULL notification handler and crash. This +patch runs hotplug in other workqueue and wait for all acpi notication +handlers finish. This is found in battery hotplug, but actually all +hotplug can be affected. + +Signed-off-by: Zhang Rui +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +--- + drivers/acpi/dock.c | 25 ++++++++++++++++++++++++- + drivers/acpi/osl.c | 46 +++++++++++++++++++++++++++++++++++++++++----- + include/acpi/acpiosxf.h | 3 +++ + 3 files changed, 68 insertions(+), 6 deletions(-) + +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -748,6 +748,20 @@ static void dock_notify(acpi_handle hand + } + } + ++struct dock_data { ++ acpi_handle handle; ++ unsigned long event; ++ struct dock_station *ds; ++}; ++ ++static void acpi_dock_deferred_cb(void *context) ++{ ++ struct dock_data *data = (struct dock_data *)context; ++ ++ dock_notify(data->handle, data->event, data->ds); ++ kfree(data); ++} ++ + static int acpi_dock_notifier_call(struct notifier_block *this, + unsigned long event, void *data) + { +@@ -759,7 +773,16 @@ static int acpi_dock_notifier_call(struc + return 0; + list_for_each_entry(dock_station, &dock_stations, sibiling) { + if (dock_station->handle == handle) { +- dock_notify(handle, event, dock_station); ++ struct dock_data *dock_data; ++ ++ dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); ++ if (!dock_data) ++ return 0; ++ dock_data->handle = handle; ++ dock_data->event = event; ++ dock_data->ds = dock_station; ++ acpi_os_hotplug_execute(acpi_dock_deferred_cb, ++ dock_data); + return 0 ; + } + } +--- a/drivers/acpi/osl.c ++++ b/drivers/acpi/osl.c +@@ -705,6 +705,22 @@ static void acpi_os_execute_deferred(str + return; + } + ++static void acpi_os_execute_hp_deferred(struct work_struct *work) ++{ ++ struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); ++ if (!dpc) { ++ printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); ++ return; ++ } ++ ++ acpi_os_wait_events_complete(NULL); ++ ++ dpc->function(dpc->context); ++ kfree(dpc); ++ ++ return; ++} ++ + /******************************************************************************* + * + * FUNCTION: acpi_os_execute +@@ -720,12 +736,13 @@ static void acpi_os_execute_deferred(str + * + ******************************************************************************/ + +-acpi_status acpi_os_execute(acpi_execute_type type, +- acpi_osd_exec_callback function, void *context) ++static acpi_status __acpi_os_execute(acpi_execute_type type, ++ acpi_osd_exec_callback function, void *context, int hp) + { + acpi_status status = AE_OK; + struct acpi_os_dpc *dpc; + struct workqueue_struct *queue; ++ int ret; + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Scheduling function [%p(%p)] for deferred execution.\n", + function, context)); +@@ -749,9 +766,17 @@ acpi_status acpi_os_execute(acpi_execute + dpc->function = function; + dpc->context = context; + +- INIT_WORK(&dpc->work, acpi_os_execute_deferred); +- queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq; +- if (!queue_work(queue, &dpc->work)) { ++ if (!hp) { ++ INIT_WORK(&dpc->work, acpi_os_execute_deferred); ++ queue = (type == OSL_NOTIFY_HANDLER) ? ++ kacpi_notify_wq : kacpid_wq; ++ ret = queue_work(queue, &dpc->work); ++ } else { ++ INIT_WORK(&dpc->work, acpi_os_execute_hp_deferred); ++ ret = schedule_work(&dpc->work); ++ } ++ ++ if (!ret) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Call to queue_work() failed.\n")); + status = AE_ERROR; +@@ -760,8 +785,19 @@ acpi_status acpi_os_execute(acpi_execute + return_ACPI_STATUS(status); + } + ++acpi_status acpi_os_execute(acpi_execute_type type, ++ acpi_osd_exec_callback function, void *context) ++{ ++ return __acpi_os_execute(type, function, context, 0); ++} + EXPORT_SYMBOL(acpi_os_execute); + ++acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, ++ void *context) ++{ ++ return __acpi_os_execute(0, function, context, 1); ++} ++ + void acpi_os_wait_events_complete(void *context) + { + flush_workqueue(kacpid_wq); +--- a/include/acpi/acpiosxf.h ++++ b/include/acpi/acpiosxf.h +@@ -193,6 +193,9 @@ acpi_status + acpi_os_execute(acpi_execute_type type, + acpi_osd_exec_callback function, void *context); + ++acpi_status ++acpi_os_hotplug_execute(acpi_osd_exec_callback function, void *context); ++ + void acpi_os_wait_events_complete(void *context); + + void acpi_os_sleep(acpi_integer milliseconds); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-introduce-.uevent-for-devices-in-dock.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-introduce-.uevent-for-devices-in-dock.patch new file mode 100644 index 000000000..012b83680 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-introduce-.uevent-for-devices-in-dock.patch @@ -0,0 +1,214 @@ +From: Shaohua Li +Subject: introduce .uevent for devices in dock +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +dock's uevent reported itself, not ata. It might be difficult to find an +ata device just according to a dock. This patch introduces docking ops +for each device in a dock. when docking, dock driver can send device +specific uevent. This should help dock station too (not just bay) + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c +index f19f643..ac7dfef 100644 +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -75,7 +75,7 @@ struct dock_dependent_device { + struct list_head list; + struct list_head hotplug_list; + acpi_handle handle; +- acpi_notify_handler handler; ++ struct acpi_dock_ops *ops; + void *context; + }; + +@@ -385,8 +385,8 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) + * First call driver specific hotplug functions + */ + list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { +- if (dd->handler) +- dd->handler(dd->handle, event, dd->context); ++ if (dd->ops && dd->ops->handler) ++ dd->ops->handler(dd->handle, event, dd->context); + } + + /* +@@ -409,6 +409,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num) + struct device *dev = &ds->dock_device->dev; + char event_string[13]; + char *envp[] = { event_string, NULL }; ++ struct dock_dependent_device *dd; + + if (num == UNDOCK_EVENT) + sprintf(event_string, "EVENT=undock"); +@@ -419,7 +420,14 @@ static void dock_event(struct dock_station *ds, u32 event, int num) + * Indicate that the status of the dock station has + * changed. + */ +- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); ++ if (num == DOCK_EVENT) ++ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); ++ ++ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) ++ if (dd->ops && dd->ops->uevent) ++ dd->ops->uevent(dd->handle, event, dd->context); ++ if (num != DOCK_EVENT) ++ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); + } + + /** +@@ -588,7 +596,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); + /** + * register_hotplug_dock_device - register a hotplug function + * @handle: the handle of the device +- * @handler: the acpi_notifier_handler to call after docking ++ * @ops: handlers to call after docking + * @context: device specific data + * + * If a driver would like to perform a hotplug operation after a dock +@@ -596,7 +604,7 @@ EXPORT_SYMBOL_GPL(unregister_dock_notifier); + * the dock driver after _DCK is executed. + */ + int +-register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, ++register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, + void *context) + { + struct dock_dependent_device *dd; +@@ -612,7 +620,7 @@ register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, + list_for_each_entry(dock_station, &dock_stations, sibiling) { + dd = find_dock_dependent_device(dock_station, handle); + if (dd) { +- dd->handler = handler; ++ dd->ops = ops; + dd->context = context; + dock_add_hotplug_device(dock_station, dd); + return 0; +diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c +index 97727be..c012307 100644 +--- a/drivers/ata/libata-acpi.c ++++ b/drivers/ata/libata-acpi.c +@@ -209,6 +209,46 @@ static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) + ata_acpi_handle_hotplug(ap, NULL, event); + } + ++static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, ++ u32 event) ++{ ++ struct kobject *kobj = NULL; ++ char event_string[20]; ++ char *envp[] = { event_string, NULL }; ++ ++ if (dev) { ++ if (dev->sdev) ++ kobj = &dev->sdev->sdev_gendev.kobj; ++ } else ++ kobj = &ap->dev->kobj; ++ ++ if (kobj) { ++ snprintf(event_string, 20, "BAY_EVENT=%d", event); ++ kobject_uevent_env(kobj, KOBJ_CHANGE, envp); ++ } ++} ++ ++static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) ++{ ++ ata_acpi_uevent(data, NULL, event); ++} ++ ++static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) ++{ ++ struct ata_device *dev = data; ++ ata_acpi_uevent(dev->link->ap, dev, event); ++} ++ ++static struct acpi_dock_ops ata_acpi_dev_dock_ops = { ++ .handler = ata_acpi_dev_notify_dock, ++ .uevent = ata_acpi_dev_uevent, ++}; ++ ++static struct acpi_dock_ops ata_acpi_ap_dock_ops = { ++ .handler = ata_acpi_ap_notify_dock, ++ .uevent = ata_acpi_ap_uevent, ++}; ++ + /** + * ata_acpi_associate - associate ATA host with ACPI objects + * @host: target ATA host +@@ -244,7 +284,7 @@ void ata_acpi_associate(struct ata_host *host) + if (ap->acpi_handle) { + /* we might be on a docking station */ + register_hotplug_dock_device(ap->acpi_handle, +- ata_acpi_ap_notify_dock, ap); ++ &ata_acpi_ap_dock_ops, ap); + } + + for (j = 0; j < ata_link_max_devices(&ap->link); j++) { +@@ -253,7 +293,7 @@ void ata_acpi_associate(struct ata_host *host) + if (dev->acpi_handle) { + /* we might be on a docking station */ + register_hotplug_dock_device(dev->acpi_handle, +- ata_acpi_dev_notify_dock, dev); ++ &ata_acpi_dev_dock_ops, dev); + } + } + } +diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c +index a3e4705..db54c5e 100644 +--- a/drivers/pci/hotplug/acpiphp_glue.c ++++ b/drivers/pci/hotplug/acpiphp_glue.c +@@ -169,7 +169,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, + } + + +- ++static struct acpi_dock_ops acpiphp_dock_ops = { ++ .handler = handle_hotplug_event_func, ++}; + + /* callback routine to register each ACPI PCI slot object */ + static acpi_status +@@ -285,7 +287,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) + */ + newfunc->flags &= ~FUNC_HAS_EJ0; + if (register_hotplug_dock_device(handle, +- handle_hotplug_event_func, newfunc)) ++ &acpiphp_dock_ops, newfunc)) + dbg("failed to register dock device\n"); + + /* we need to be notified when dock events happen +diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h +index e5f38e5..4f5042a 100644 +--- a/include/acpi/acpi_drivers.h ++++ b/include/acpi/acpi_drivers.h +@@ -115,12 +115,17 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type); + /*-------------------------------------------------------------------------- + Dock Station + -------------------------------------------------------------------------- */ ++struct acpi_dock_ops { ++ acpi_notify_handler handler; ++ acpi_notify_handler uevent; ++}; ++ + #if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) + extern int is_dock_device(acpi_handle handle); + extern int register_dock_notifier(struct notifier_block *nb); + extern void unregister_dock_notifier(struct notifier_block *nb); + extern int register_hotplug_dock_device(acpi_handle handle, +- acpi_notify_handler handler, ++ struct acpi_dock_ops *ops, + void *context); + extern void unregister_hotplug_dock_device(acpi_handle handle); + #else +@@ -136,7 +141,7 @@ static inline void unregister_dock_notifier(struct notifier_block *nb) + { + } + static inline int register_hotplug_dock_device(acpi_handle handle, +- acpi_notify_handler handler, ++ struct acpi_dock_ops *ops, + void *context) + { + return -ENODEV; diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch new file mode 100644 index 000000000..78c5cd07c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-dock-makeing-dock-driver-supports-bay-and-battery-hotplug.patch @@ -0,0 +1,451 @@ +From: Shaohua Li +Subject: makeing dock driver supports bay and battery hotplug +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +Making dock driver supports bay and battery hotplug. They are all +regarded as dock, and unified handled. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +--- + drivers/acpi/dock.c | 221 ++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 173 insertions(+), 48 deletions(-) + +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -48,7 +48,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (d + " before undocking"); + + static struct atomic_notifier_head dock_notifier_list; +-static struct platform_device *dock_device; + static char dock_device_name[] = "dock"; + + static const struct acpi_device_id dock_device_ids[] = { +@@ -65,7 +64,12 @@ struct dock_station { + struct mutex hp_lock; + struct list_head dependent_devices; + struct list_head hotplug_devices; ++ ++ struct list_head sibiling; ++ struct platform_device *dock_device; + }; ++static LIST_HEAD(dock_stations); ++static int dock_station_count; + + struct dock_dependent_device { + struct list_head list; +@@ -77,11 +81,12 @@ struct dock_dependent_device { + + #define DOCK_DOCKING 0x00000001 + #define DOCK_UNDOCKING 0x00000002 ++#define DOCK_IS_DOCK 0x00000010 ++#define DOCK_IS_ATA 0x00000020 ++#define DOCK_IS_BAT 0x00000040 + #define DOCK_EVENT 3 + #define UNDOCK_EVENT 2 + +-static struct dock_station *dock_station; +- + /***************************************************************************** + * Dock Dependent device functions * + *****************************************************************************/ +@@ -199,6 +204,60 @@ static int is_dock(acpi_handle handle) + return 1; + } + ++static int is_ejectable(acpi_handle handle) ++{ ++ acpi_status status; ++ acpi_handle tmp; ++ ++ status = acpi_get_handle(handle, "_EJ0", &tmp); ++ if (ACPI_FAILURE(status)) ++ return 0; ++ return 1; ++} ++ ++static int is_ata(acpi_handle handle) ++{ ++ acpi_handle tmp; ++ ++ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || ++ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || ++ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || ++ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) ++ return 1; ++ ++ return 0; ++} ++ ++static int is_battery(acpi_handle handle) ++{ ++ struct acpi_device_info *info; ++ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; ++ int ret = 1; ++ ++ if (!ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) ++ return 0; ++ info = buffer.pointer; ++ if (!(info->valid & ACPI_VALID_HID)) ++ ret = 0; ++ else ++ ret = !strcmp("PNP0C0A", info->hardware_id.value); ++ ++ kfree(buffer.pointer); ++ return ret; ++} ++ ++static int is_ejectable_bay(acpi_handle handle) ++{ ++ acpi_handle phandle; ++ if (!is_ejectable(handle)) ++ return 0; ++ if (is_battery(handle) || is_ata(handle)) ++ return 1; ++ if (!acpi_get_parent(handle, &phandle) && is_ata(phandle)) ++ return 1; ++ return 0; ++} ++ + /** + * is_dock_device - see if a device is on a dock station + * @handle: acpi handle of the device +@@ -209,11 +268,17 @@ static int is_dock(acpi_handle handle) + */ + int is_dock_device(acpi_handle handle) + { +- if (!dock_station) ++ struct dock_station *dock_station; ++ ++ if (!dock_station_count) + return 0; + +- if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) ++ if (is_dock(handle)) + return 1; ++ list_for_each_entry(dock_station, &dock_stations, sibiling) { ++ if (find_dock_dependent_device(dock_station, handle)) ++ return 1; ++ } + + return 0; + } +@@ -341,7 +406,7 @@ static void hotplug_dock_devices(struct + + static void dock_event(struct dock_station *ds, u32 event, int num) + { +- struct device *dev = &dock_device->dev; ++ struct device *dev = &ds->dock_device->dev; + char event_string[13]; + char *envp[] = { event_string, NULL }; + +@@ -414,7 +479,7 @@ static void handle_dock(struct dock_stat + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = dock; + status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); +- if (ACPI_FAILURE(status)) ++ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", + (char *)name_buffer.pointer); + kfree(buffer.pointer); +@@ -498,7 +563,7 @@ static int dock_in_progress(struct dock_ + */ + int register_dock_notifier(struct notifier_block *nb) + { +- if (!dock_station) ++ if (!dock_station_count) + return -ENODEV; + + return atomic_notifier_chain_register(&dock_notifier_list, nb); +@@ -512,7 +577,7 @@ EXPORT_SYMBOL_GPL(register_dock_notifier + */ + void unregister_dock_notifier(struct notifier_block *nb) + { +- if (!dock_station) ++ if (!dock_station_count) + return; + + atomic_notifier_chain_unregister(&dock_notifier_list, nb); +@@ -535,20 +600,23 @@ register_hotplug_dock_device(acpi_handle + void *context) + { + struct dock_dependent_device *dd; ++ struct dock_station *dock_station; + +- if (!dock_station) ++ if (!dock_station_count) + return -ENODEV; + + /* + * make sure this handle is for a device dependent on the dock, + * this would include the dock station itself + */ +- dd = find_dock_dependent_device(dock_station, handle); +- if (dd) { +- dd->handler = handler; +- dd->context = context; +- dock_add_hotplug_device(dock_station, dd); +- return 0; ++ list_for_each_entry(dock_station, &dock_stations, sibiling) { ++ dd = find_dock_dependent_device(dock_station, handle); ++ if (dd) { ++ dd->handler = handler; ++ dd->context = context; ++ dock_add_hotplug_device(dock_station, dd); ++ return 0; ++ } + } + + return -EINVAL; +@@ -563,13 +631,16 @@ EXPORT_SYMBOL_GPL(register_hotplug_dock_ + void unregister_hotplug_dock_device(acpi_handle handle) + { + struct dock_dependent_device *dd; ++ struct dock_station *dock_station; + +- if (!dock_station) ++ if (!dock_station_count) + return; + +- dd = find_dock_dependent_device(dock_station, handle); +- if (dd) +- dock_del_hotplug_device(dock_station, dd); ++ list_for_each_entry(dock_station, &dock_stations, sibiling) { ++ dd = find_dock_dependent_device(dock_station, handle); ++ if (dd) ++ dock_del_hotplug_device(dock_station, dd); ++ } + } + + EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); +@@ -620,9 +691,28 @@ static void dock_notify(acpi_handle hand + { + struct dock_station *ds = data; + struct acpi_device *tmp; ++ int surprise_removal = 0; + ++ /* ++ * According to acpi spec 3.0a, if a DEVICE_CHECK notification ++ * is sent and _DCK is present, it is assumed to mean an undock ++ * request. ++ */ ++ if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK) ++ event = ACPI_NOTIFY_EJECT_REQUEST; ++ ++ /* ++ * dock station: BUS_CHECK - docked or surprise removal ++ * DEVICE_CHECK - undocked ++ * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal ++ * ++ * To simplify event handling, dock dependent device handler always ++ * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and ++ * ACPI_NOTIFY_EJECT_REQUEST for removal ++ */ + switch (event) { + case ACPI_NOTIFY_BUS_CHECK: ++ case ACPI_NOTIFY_DEVICE_CHECK: + if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, + &tmp)) { + begin_dock(ds); +@@ -638,20 +728,17 @@ static void dock_notify(acpi_handle hand + complete_dock(ds); + dock_event(ds, event, DOCK_EVENT); + dock_lock(ds, 1); ++ break; + } +- break; +- case ACPI_NOTIFY_DEVICE_CHECK: +- /* +- * According to acpi spec 3.0a, if a DEVICE_CHECK notification +- * is sent and _DCK is present, it is assumed to mean an +- * undock request. This notify routine will only be called +- * for objects defining _DCK, so we will fall through to eject +- * request here. However, we will pass an eject request through +- * to the driver who wish to hotplug. +- */ ++ if (dock_present(ds) || dock_in_progress(ds)) ++ break; ++ /* This is a surprise removal */ ++ surprise_removal = 1; ++ event = ACPI_NOTIFY_EJECT_REQUEST; ++ /* Fall back */ + case ACPI_NOTIFY_EJECT_REQUEST: + begin_undock(ds); +- if (immediate_undock) ++ if (immediate_undock || surprise_removal) + handle_eject_request(ds, event); + else + dock_event(ds, event, UNDOCK_EVENT); +@@ -718,6 +805,8 @@ static DEVICE_ATTR(docked, S_IRUGO, show + static ssize_t show_flags(struct device *dev, + struct device_attribute *attr, char *buf) + { ++ struct dock_station *dock_station = *((struct dock_station **) ++ dev->platform_data); + return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); + + } +@@ -730,6 +819,8 @@ static ssize_t write_undock(struct devic + const char *buf, size_t count) + { + int ret; ++ struct dock_station *dock_station = *((struct dock_station **) ++ dev->platform_data); + + if (!count) + return -EINVAL; +@@ -747,6 +838,8 @@ static ssize_t show_dock_uid(struct devi + struct device_attribute *attr, char *buf) + { + unsigned long long lbuf; ++ struct dock_station *dock_station = *((struct dock_station **) ++ dev->platform_data); + acpi_status status = acpi_evaluate_integer(dock_station->handle, + "_UID", NULL, &lbuf); + if (ACPI_FAILURE(status)) +@@ -768,6 +861,8 @@ static int dock_add(acpi_handle handle) + int ret; + acpi_status status; + struct dock_dependent_device *dd; ++ struct dock_station *dock_station; ++ struct platform_device *dock_device; + + /* allocate & initialize the dock_station private data */ + dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); +@@ -777,22 +872,34 @@ static int dock_add(acpi_handle handle) + dock_station->last_dock_time = jiffies - HZ; + INIT_LIST_HEAD(&dock_station->dependent_devices); + INIT_LIST_HEAD(&dock_station->hotplug_devices); ++ INIT_LIST_HEAD(&dock_station->sibiling); + spin_lock_init(&dock_station->dd_lock); + mutex_init(&dock_station->hp_lock); + ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); + + /* initialize platform device stuff */ +- dock_device = +- platform_device_register_simple(dock_device_name, 0, NULL, 0); ++ dock_station->dock_device = ++ platform_device_register_simple(dock_device_name, ++ dock_station_count, NULL, 0); ++ dock_device = dock_station->dock_device; + if (IS_ERR(dock_device)) { + kfree(dock_station); + dock_station = NULL; + return PTR_ERR(dock_device); + } ++ platform_device_add_data(dock_device, &dock_station, ++ sizeof(struct dock_station *)); + + /* we want the dock device to send uevents */ + dock_device->dev.uevent_suppress = 0; + ++ if (is_dock(handle)) ++ dock_station->flags |= DOCK_IS_DOCK; ++ if (is_ata(handle)) ++ dock_station->flags |= DOCK_IS_ATA; ++ if (is_battery(handle)) ++ dock_station->flags |= DOCK_IS_BAT; ++ + ret = device_create_file(&dock_device->dev, &dev_attr_docked); + if (ret) { + printk("Error %d adding sysfs file\n", ret); +@@ -858,8 +965,8 @@ static int dock_add(acpi_handle handle) + goto dock_add_err; + } + +- printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION); +- ++ dock_station_count++; ++ list_add(&dock_station->sibiling, &dock_stations); + return 0; + + dock_add_err: +@@ -878,12 +985,13 @@ dock_add_err_unregister: + /** + * dock_remove - free up resources related to the dock station + */ +-static int dock_remove(void) ++static int dock_remove(struct dock_station *dock_station) + { + struct dock_dependent_device *dd, *tmp; + acpi_status status; ++ struct platform_device *dock_device = dock_station->dock_device; + +- if (!dock_station) ++ if (!dock_station_count) + return 0; + + /* remove dependent devices */ +@@ -923,41 +1031,58 @@ static int dock_remove(void) + static acpi_status + find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) + { +- int *count = context; + acpi_status status = AE_OK; + + if (is_dock(handle)) { + if (dock_add(handle) >= 0) { +- (*count)++; + status = AE_CTRL_TERMINATE; + } + } + return status; + } + +-static int __init dock_init(void) ++static acpi_status ++find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) + { +- int num = 0; +- +- dock_station = NULL; ++ /* If bay is in a dock, it's already handled */ ++ if (is_ejectable_bay(handle) && !is_dock_device(handle)) ++ dock_add(handle); ++ return AE_OK; ++} + ++static int __init dock_init(void) ++{ + if (acpi_disabled) + return 0; + + /* look for a dock station */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, +- ACPI_UINT32_MAX, find_dock, &num, NULL); ++ ACPI_UINT32_MAX, find_dock, NULL, NULL); + +- if (!num) +- printk(KERN_INFO "No dock devices found.\n"); ++ /* look for bay */ ++ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ++ ACPI_UINT32_MAX, find_bay, NULL, NULL); ++ if (!dock_station_count) { ++ printk(KERN_INFO PREFIX "No dock devices found.\n"); ++ return 0; ++ } + ++ printk(KERN_INFO PREFIX "%s: %d docks/bays found\n", ++ ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); + return 0; + } + + static void __exit dock_exit(void) + { +- dock_remove(); ++ struct dock_station *dock_station; ++ ++ list_for_each_entry(dock_station, &dock_stations, sibiling) ++ dock_remove(dock_station); + } + +-postcore_initcall(dock_init); ++/* ++ * Must be called before drivers of devices in dock, otherwise we can't know ++ * which devices are in a dock ++ */ ++subsys_initcall(dock_init); + module_exit(dock_exit); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-export-hotplug_execute b/src/patches/suse-2.6.27.31/patches.arch/acpi-export-hotplug_execute new file mode 100644 index 000000000..43b70019c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-export-hotplug_execute @@ -0,0 +1,23 @@ +From: Jeff Mahoney +Subject: acpi: export acpi_os_hotplug_execute + + The ACPI dock driver changes require acpi_os_hotplug_execute, + which wasn't exported. + + This patch exports it. + +Signed-off-by: Jeff Mahoney +--- + drivers/acpi/osl.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/acpi/osl.c ++++ b/drivers/acpi/osl.c +@@ -797,6 +797,7 @@ acpi_status acpi_os_hotplug_execute(acpi + { + return __acpi_os_execute(0, function, context, 1); + } ++EXPORT_SYMBOL(acpi_os_hotplug_execute); + + void acpi_os_wait_events_complete(void *context) + { diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi-libata-hotplug-to-align-with-dock-driver.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi-libata-hotplug-to-align-with-dock-driver.patch new file mode 100644 index 000000000..e3fd17e76 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi-libata-hotplug-to-align-with-dock-driver.patch @@ -0,0 +1,211 @@ +From: Shaohua Li +Subject: libata hotplug to align with dock driver +Patch-mainline: submitted 2008-08-28 +References: fate#304731,bnc#401740 + +dock driver can handle ata(bay) hotplug now. dock driver already handles +_EJ0 and _STA, so remove them. Also libata doesn't need register +notification handler anymore. + +Signed-off-by: Shaohua Li +Signed-off-by: Holger Macht +--- + +diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c +index 4b395b1..f19f643 100644 +--- a/drivers/acpi/dock.c ++++ b/drivers/acpi/dock.c +@@ -738,7 +738,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) + /* Fall back */ + case ACPI_NOTIFY_EJECT_REQUEST: + begin_undock(ds); +- if (immediate_undock || surprise_removal) ++ if ((immediate_undock && !(ds->flags & DOCK_IS_ATA)) ++ || surprise_removal) + handle_eject_request(ds, event); + else + dock_event(ds, event, UNDOCK_EVENT); +diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c +index 9330b79..97727be 100644 +--- a/drivers/ata/libata-acpi.c ++++ b/drivers/ata/libata-acpi.c +@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) + ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; + } + +-static void ata_acpi_eject_device(acpi_handle handle) +-{ +- struct acpi_object_list arg_list; +- union acpi_object arg; +- +- arg_list.count = 1; +- arg_list.pointer = &arg; +- arg.type = ACPI_TYPE_INTEGER; +- arg.integer.value = 1; +- +- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", +- &arg_list, NULL))) +- printk(KERN_ERR "Failed to evaluate _EJ0!\n"); +-} +- + /* @ap and @dev are the same as ata_acpi_handle_hotplug() */ + static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) + { +@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) + * @ap: ATA port ACPI event occurred + * @dev: ATA device ACPI event occurred (can be NULL) + * @event: ACPI event which occurred +- * @is_dock_event: boolean indicating whether the event was a dock one + * + * All ACPI bay / device realted events end up in this function. If + * the event is port-wide @dev is NULL. If the event is specific to a +@@ -171,115 +155,58 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) + * ACPI notify handler context. May sleep. + */ + static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, +- u32 event, int is_dock_event) ++ u32 event) + { +- char event_string[12]; +- char *envp[] = { event_string, NULL }; + struct ata_eh_info *ehi = &ap->link.eh_info; +- struct kobject *kobj = NULL; + int wait = 0; + unsigned long flags; +- acpi_handle handle, tmphandle; +- unsigned long long sta; +- acpi_status status; ++ acpi_handle handle; + +- if (dev) { +- if (dev->sdev) +- kobj = &dev->sdev->sdev_gendev.kobj; ++ if (dev) + handle = dev->acpi_handle; +- } else { +- kobj = &ap->dev->kobj; ++ else + handle = ap->acpi_handle; +- } +- +- status = acpi_get_handle(handle, "_EJ0", &tmphandle); +- if (ACPI_FAILURE(status)) +- /* This device does not support hotplug */ +- return; +- +- if (event == ACPI_NOTIFY_BUS_CHECK || +- event == ACPI_NOTIFY_DEVICE_CHECK) +- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + + spin_lock_irqsave(ap->lock, flags); +- ++ /* ++ * When dock driver calls into the routine, it will always use ++ * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and ++ * ACPI_NOTIFY_EJECT_REQUEST for remove ++ */ + switch (event) { + case ACPI_NOTIFY_BUS_CHECK: + case ACPI_NOTIFY_DEVICE_CHECK: + ata_ehi_push_desc(ehi, "ACPI event"); + +- if (ACPI_FAILURE(status)) { +- ata_port_printk(ap, KERN_ERR, +- "acpi: failed to determine bay status (0x%x)\n", +- status); +- break; +- } +- +- if (sta) { +- ata_ehi_hotplugged(ehi); +- ata_port_freeze(ap); +- } else { +- /* The device has gone - unplug it */ +- ata_acpi_detach_device(ap, dev); +- wait = 1; +- } ++ ata_ehi_hotplugged(ehi); ++ ata_port_freeze(ap); + break; + case ACPI_NOTIFY_EJECT_REQUEST: + ata_ehi_push_desc(ehi, "ACPI event"); + +- if (!is_dock_event) +- break; +- +- /* undock event - immediate unplug */ + ata_acpi_detach_device(ap, dev); + wait = 1; + break; + } + +- /* make sure kobj doesn't go away while ap->lock is released */ +- kobject_get(kobj); +- + spin_unlock_irqrestore(ap->lock, flags); + +- if (wait) { ++ if (wait) + ata_port_wait_eh(ap); +- ata_acpi_eject_device(handle); +- } +- +- if (kobj && !is_dock_event) { +- sprintf(event_string, "BAY_EVENT=%d", event); +- kobject_uevent_env(kobj, KOBJ_CHANGE, envp); +- } +- +- kobject_put(kobj); + } + + static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) + { + struct ata_device *dev = data; + +- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1); ++ ata_acpi_handle_hotplug(dev->link->ap, dev, event); + } + + static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) + { + struct ata_port *ap = data; + +- ata_acpi_handle_hotplug(ap, NULL, event, 1); +-} +- +-static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) +-{ +- struct ata_device *dev = data; +- +- ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0); +-} +- +-static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) +-{ +- struct ata_port *ap = data; +- +- ata_acpi_handle_hotplug(ap, NULL, event, 0); ++ ata_acpi_handle_hotplug(ap, NULL, event); + } + + /** +@@ -315,9 +242,6 @@ void ata_acpi_associate(struct ata_host *host) + ata_acpi_associate_ide_port(ap); + + if (ap->acpi_handle) { +- acpi_install_notify_handler(ap->acpi_handle, +- ACPI_SYSTEM_NOTIFY, +- ata_acpi_ap_notify, ap); + /* we might be on a docking station */ + register_hotplug_dock_device(ap->acpi_handle, + ata_acpi_ap_notify_dock, ap); +@@ -327,9 +251,6 @@ void ata_acpi_associate(struct ata_host *host) + struct ata_device *dev = &ap->link.device[j]; + + if (dev->acpi_handle) { +- acpi_install_notify_handler(dev->acpi_handle, +- ACPI_SYSTEM_NOTIFY, +- ata_acpi_dev_notify, dev); + /* we might be on a docking station */ + register_hotplug_dock_device(dev->acpi_handle, + ata_acpi_dev_notify_dock, dev); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_behave_uniquely_based_on_processor_declaration.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_behave_uniquely_based_on_processor_declaration.patch new file mode 100644 index 000000000..d623df979 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_behave_uniquely_based_on_processor_declaration.patch @@ -0,0 +1,206 @@ +From: Myron Stowe +Subject: ACPI: Behave uniquely based on processor declaration definition type +References: bnc#440062 +Patch-Mainline: yes +Commit-ID: b26e9286fb438eb78bcdb68b67a3dbb8bc539125 + +Signed-off-by: Thomas Renninger + +Associating a Local SAPIC with a processor object is dependent upon the +processor object's definition type. CPUs declared as "Processor" should +use the Local SAPIC's 'processor_id', and CPUs declared as "Device" +should use the 'uid'. Note that for "Processor" declarations, even if a +'_UID' child object exists, it has no bearing with respect to mapping +Local SAPICs (see section 5.2.11.13 - Local SAPIC Structure; "Advanced +Configuration and Power Interface Specification", Revision 3.0b). + +This patch changes the lsapic mapping logic to rely on the distinction of +how the processor object was declared - the mapping can't just try both +types of matches regardless of declaration type and rely on one failing +as is currently being done. + +Signed-off-by: Myron Stowe +Signed-off-by: Len Brown + +--- + drivers/acpi/processor_core.c | 78 +++++++++++++++++++++++------------------- + 1 file changed, 44 insertions(+), 34 deletions(-) + +Index: linux-2.6.27/drivers/acpi/processor_core.c +=================================================================== +--- linux-2.6.27.orig/drivers/acpi/processor_core.c ++++ linux-2.6.27/drivers/acpi/processor_core.c +@@ -410,7 +410,7 @@ static int acpi_processor_remove_fs(stru + /* Use the acpiid in MADT to map cpus in case of SMP */ + + #ifndef CONFIG_SMP +-static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;} ++static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) { return -1; } + #else + + static struct acpi_table_madt *madt; +@@ -429,27 +429,35 @@ static int map_lapic_id(struct acpi_subt + } + + static int map_lsapic_id(struct acpi_subtable_header *entry, +- u32 acpi_id, int *apic_id) ++ int device_declaration, u32 acpi_id, int *apic_id) + { + struct acpi_madt_local_sapic *lsapic = + (struct acpi_madt_local_sapic *)entry; ++ u32 tmp = (lsapic->id << 8) | lsapic->eid; ++ + /* Only check enabled APICs*/ +- if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { +- /* First check against id */ +- if (lsapic->processor_id == acpi_id) { +- *apic_id = (lsapic->id << 8) | lsapic->eid; +- return 1; +- /* Check against optional uid */ +- } else if (entry->length >= 16 && +- lsapic->uid == acpi_id) { +- *apic_id = lsapic->uid; +- return 1; +- } +- } ++ if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED)) ++ return 0; ++ ++ /* Device statement declaration type */ ++ if (device_declaration) { ++ if (entry->length < 16) ++ printk(KERN_ERR PREFIX ++ "Invalid LSAPIC with Device type processor (SAPIC ID %#x)\n", ++ tmp); ++ else if (lsapic->uid == acpi_id) ++ goto found; ++ /* Processor statement declaration type */ ++ } else if (lsapic->processor_id == acpi_id) ++ goto found; ++ + return 0; ++found: ++ *apic_id = tmp; ++ return 1; + } + +-static int map_madt_entry(u32 acpi_id) ++static int map_madt_entry(int type, u32 acpi_id) + { + unsigned long madt_end, entry; + int apic_id = -1; +@@ -470,7 +478,7 @@ static int map_madt_entry(u32 acpi_id) + if (map_lapic_id(header, acpi_id, &apic_id)) + break; + } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { +- if (map_lsapic_id(header, acpi_id, &apic_id)) ++ if (map_lsapic_id(header, type, acpi_id, &apic_id)) + break; + } + entry += header->length; +@@ -478,7 +486,7 @@ static int map_madt_entry(u32 acpi_id) + return apic_id; + } + +-static int map_mat_entry(acpi_handle handle, u32 acpi_id) ++static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id) + { + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; +@@ -501,7 +509,7 @@ static int map_mat_entry(acpi_handle han + if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { + map_lapic_id(header, acpi_id, &apic_id); + } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { +- map_lsapic_id(header, acpi_id, &apic_id); ++ map_lsapic_id(header, type, acpi_id, &apic_id); + } + + exit: +@@ -510,14 +518,14 @@ exit: + return apic_id; + } + +-static int get_cpu_id(acpi_handle handle, u32 acpi_id) ++static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) + { + int i; + int apic_id = -1; + +- apic_id = map_mat_entry(handle, acpi_id); ++ apic_id = map_mat_entry(handle, type, acpi_id); + if (apic_id == -1) +- apic_id = map_madt_entry(acpi_id); ++ apic_id = map_madt_entry(type, acpi_id); + if (apic_id == -1) + return apic_id; + +@@ -533,15 +541,16 @@ static int get_cpu_id(acpi_handle handle + Driver Interface + -------------------------------------------------------------------------- */ + +-static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid) ++static int acpi_processor_get_info(struct acpi_device *device) + { + acpi_status status = 0; + union acpi_object object = { 0 }; + struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; +- int cpu_index; ++ struct acpi_processor *pr; ++ int cpu_index, device_declaration = 0; + static int cpu0_initialized; + +- ++ pr = acpi_driver_data(device); + if (!pr) + return -EINVAL; + +@@ -562,22 +571,23 @@ static int acpi_processor_get_info(struc + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "No bus mastering arbitration control\n")); + +- /* Check if it is a Device with HID and UID */ +- if (has_uid) { ++ if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_HID)) { ++ /* ++ * Declared with "Device" statement; match _UID. ++ * Note that we don't handle string _UIDs yet. ++ */ + unsigned long long value; + status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, + NULL, &value); + if (ACPI_FAILURE(status)) { +- printk(KERN_ERR PREFIX "Evaluating processor _UID\n"); ++ printk(KERN_ERR PREFIX ++ "Evaluating processor _UID [%#x]\n", status); + return -ENODEV; + } ++ device_declaration = 1; + pr->acpi_id = value; + } else { +- /* +- * Evalute the processor object. Note that it is common on SMP to +- * have the first (boot) processor with a valid PBLK address while +- * all others have a NULL address. +- */ ++ /* Declared with "Processor" statement; match ProcessorID */ + status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Evaluating processor object\n"); +@@ -590,7 +600,7 @@ static int acpi_processor_get_info(struc + */ + pr->acpi_id = object.processor.proc_id; + } +- cpu_index = get_cpu_id(pr->handle, pr->acpi_id); ++ cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id); + + /* Handle UP system running SMP kernel, with no LAPIC in MADT */ + if (!cpu0_initialized && (cpu_index == -1) && +@@ -662,7 +672,7 @@ static int __cpuinit acpi_processor_star + + pr = acpi_driver_data(device); + +- result = acpi_processor_get_info(pr, device->flags.unique_id); ++ result = acpi_processor_get_info(device); + if (result) { + /* Processor is physically not present */ + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_disambiguate_processor_declaration_type.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_disambiguate_processor_declaration_type.patch new file mode 100644 index 000000000..9eeb2fb23 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_disambiguate_processor_declaration_type.patch @@ -0,0 +1,58 @@ +From: Myron Stowe +Subject: ACPI: Disambiguate processor declaration type +References: bnc#440062 +Patch-Mainline: yes +Commit-ID: ad93a765c1834db031b5bf1c2baf2a50d0462ca4 + +Signed-off-by: Thomas Renninger + +Declaring processors in ACPI namespace can be done using either a +"Processor" definition or a "Device" definition (see section 8.4 - +Declaring Processors; "Advanced Configuration and Power Interface +Specification", Revision 3.0b). Currently the two processor +declaration types are conflated. + +This patch disambiguates the processor declaration's definition type +enabling subsequent code to behave uniquely based explicitly on the +declaration's type. + +Signed-off-by: Myron Stowe +Signed-off-by: Len Brown + +--- + drivers/acpi/processor_core.c | 1 + + drivers/acpi/scan.c | 2 +- + include/acpi/acpi_drivers.h | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/acpi/processor_core.c ++++ b/drivers/acpi/processor_core.c +@@ -89,6 +89,7 @@ static int acpi_processor_handle_eject(s + + + static const struct acpi_device_id processor_device_ids[] = { ++ {ACPI_PROCESSOR_OBJECT_HID, 0}, + {ACPI_PROCESSOR_HID, 0}, + {"", 0}, + }; +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -1002,7 +1002,7 @@ static void acpi_device_set_id(struct ac + hid = ACPI_POWER_HID; + break; + case ACPI_BUS_TYPE_PROCESSOR: +- hid = ACPI_PROCESSOR_HID; ++ hid = ACPI_PROCESSOR_OBJECT_HID; + break; + case ACPI_BUS_TYPE_SYSTEM: + hid = ACPI_SYSTEM_HID; +--- a/include/acpi/acpi_drivers.h ++++ b/include/acpi/acpi_drivers.h +@@ -41,6 +41,7 @@ + */ + + #define ACPI_POWER_HID "LNXPOWER" ++#define ACPI_PROCESSOR_OBJECT_HID "ACPI_CPU" + #define ACPI_PROCESSOR_HID "ACPI0007" + #define ACPI_SYSTEM_HID "LNXSYSTM" + #define ACPI_THERMAL_HID "LNXTHERM" diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_ec_provide_non_interrupt_mode_boot_param.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_ec_provide_non_interrupt_mode_boot_param.patch new file mode 100644 index 000000000..db2d4d69d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_ec_provide_non_interrupt_mode_boot_param.patch @@ -0,0 +1,67 @@ +From: Alexey Starikovskiy +Subject: ACPI: EC: Don't degrade to poll mode at storm automatically. +References: bnc#446142 +Patch-Mainline: no + +Signed-off-by: Thomas Renninger + +Not all users of semi-broken EC devices want to degrade to poll mode, so +give them right to choose. + +Signed-off-by: Alexey Starikovskiy +--- + + Documentation/kernel-parameters.txt | 5 +++++ + drivers/acpi/ec.c | 15 +++++++++++++++ + 2 files changed, 20 insertions(+) + + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -706,6 +706,11 @@ and is between 256 and 4096 characters. + + eata= [HW,SCSI] + ++ ec_intr= [HW,ACPI] ACPI Embedded Controller interrupt mode ++ Format: ++ 0: polling mode ++ non-0: interrupt mode (default) ++ + edd= [EDD] + Format: {"off" | "on" | "skip[mbr]"} + +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -121,6 +121,8 @@ static struct acpi_ec { + spinlock_t curr_lock; + } *boot_ec, *first_ec; + ++int acpi_ec_intr = 1; /* Default is interrupt mode */ ++ + /* + * Some Asus system have exchanged ECDT data/command IO addresses. + */ +@@ -902,6 +904,8 @@ static int ec_install_handlers(struct ac + &acpi_ec_gpe_handler, ec); + if (ACPI_FAILURE(status)) + return -ENODEV; ++ if (!acpi_ec_intr) ++ set_bit(EC_FLAGS_NO_GPE, &ec->flags); + acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); + acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); + status = acpi_install_address_space_handler(ec->handle, +@@ -1095,3 +1099,14 @@ static void __exit acpi_ec_exit(void) + return; + } + #endif /* 0 */ ++ ++static int __init acpi_ec_set_intr_mode(char *str) ++{ ++ if (!get_option(&str, &acpi_ec_intr)) { ++ acpi_ec_intr = 0; ++ return 0; ++ } ++ return 1; ++} ++ ++__setup("ec_intr=", acpi_ec_set_intr_mode); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_processor_cleanups.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_processor_cleanups.patch new file mode 100644 index 000000000..376ce00f6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_processor_cleanups.patch @@ -0,0 +1,29 @@ +From: Myron Stowe +Subject: ACPI: 80 column adherence and spelling fix (no functional change) +References: bnc#440062 +Patch-Mainline: yes +Commit-ID: 5b53ed69158eeff115004f246193d07a083445f6 + +Signed-off-by: Thomas Renninger + +Signed-off-by: Myron Stowe +Signed-off-by: Len Brown + +diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c +index bc332fc..b57b1f0 100644 +--- a/drivers/acpi/processor_core.c ++++ b/drivers/acpi/processor_core.c +@@ -595,9 +595,10 @@ static int acpi_processor_get_info(struct acpi_device *device) + } + + /* +- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. +- * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c +- */ ++ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. ++ * >>> 'acpi_get_processor_id(acpi_id, &id)' in ++ * arch/xxx/acpi.c ++ */ + pr->acpi_id = object.processor.proc_id; + } + cpu_index = get_cpu_id(pr->handle, device_declaration, pr->acpi_id); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-ia64.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-ia64.patch new file mode 100644 index 000000000..98bba18d9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-ia64.patch @@ -0,0 +1,58 @@ +From: Kurt Garloff +Subject: Use SRAT table rev to use 8bit or 16/32bit PXM fields (ia64) +References: bnc#503038 + +In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides +32bits for these. The new fields were reserved before. +According to the ACPI spec, the OS must disregrard reserved fields. + +ia64 did handle the PXM fields almost consistently, but depending on +sgi's sn2 platform. This patch leaves the sn2 logic in, but does also +use 16/32 bits for PXM if the SRAT has rev 2 or higher. + +The patch also adds __init to the two pxm accessor functions, as they +access __initdata now and are called from an __init function only anyway. + +Note that the code only uses 16 bits for the PXM field in the processor +proximity field; the patch does not address this as 16 bits are more than +enough. + +This is patch 3/3. + +Signed-off-by: Kurt Garloff + +--- + arch/ia64/kernel/acpi.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/arch/ia64/kernel/acpi.c ++++ b/arch/ia64/kernel/acpi.c +@@ -430,22 +430,24 @@ static u32 __devinitdata pxm_flag[PXM_FL + static struct acpi_table_slit __initdata *slit_table; + cpumask_t early_cpu_possible_map = CPU_MASK_NONE; + +-static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) ++static int __init ++get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) + { + int pxm; + + pxm = pa->proximity_domain_lo; +- if (ia64_platform_is("sn2")) ++ if (ia64_platform_is("sn2") || acpi_srat_revision >= 2) + pxm += pa->proximity_domain_hi[0] << 8; + return pxm; + } + +-static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) ++static int __init ++get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) + { + int pxm; + + pxm = ma->proximity_domain; +- if (!ia64_platform_is("sn2")) ++ if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1) + pxm &= 0xff; + + return pxm; diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-store.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-store.patch new file mode 100644 index 000000000..697b1011d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-store.patch @@ -0,0 +1,51 @@ +From: Kurt Garloff +Subject: Store SRAT table revision +References: bnc#503038 + +In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides +32bits for these. The new fields were reserved before. +According to the ACPI spec, the OS must disregrard reserved fields. +In order to know whether or not, we must know what version the SRAT +table has. + +This patch stores the SRAT table revision for later consumption +by arch specific __init functions. + +This is patch 1/3. + +Signed-off-by: Kurt Garloff + +--- + drivers/acpi/numa.c | 3 +++ + include/acpi/acpi_numa.h | 1 + + 2 files changed, 4 insertions(+) + +--- a/drivers/acpi/numa.c ++++ b/drivers/acpi/numa.c +@@ -43,6 +43,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAI + static int node_to_pxm_map[MAX_NUMNODES] + = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; + ++unsigned char acpi_srat_revision __initdata; ++ + int pxm_to_node(int pxm) + { + if (pxm < 0) +@@ -225,6 +227,7 @@ static int __init acpi_parse_srat(struct + return -EINVAL; + + srat = (struct acpi_table_srat *)table; ++ acpi_srat_revision = srat->header.revision; + + return 0; + } +--- a/include/acpi/acpi_numa.h ++++ b/include/acpi/acpi_numa.h +@@ -15,6 +15,7 @@ extern int pxm_to_node(int); + extern int node_to_pxm(int); + extern void __acpi_map_pxm_to_node(int, int); + extern int acpi_map_pxm_to_node(int); ++extern unsigned char acpi_srat_revision; + + #endif /* CONFIG_ACPI_NUMA */ + #endif /* __ACP_NUMA_H */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-x86-64.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-x86-64.patch new file mode 100644 index 000000000..53430f270 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_srat-pxm-rev-x86-64.patch @@ -0,0 +1,41 @@ +From: Kurt Garloff +Subject: Use SRAT table rev to use 8bit or 32bit PXM fields (x86-64) +References: bnc#503038 + +In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides +32bits for these. The new fields were reserved before. +According to the ACPI spec, the OS must disregrard reserved fields. + +x86-64 was rather inconsistent prior to this patch; it used 8 bits +for the pxm field in cpu_affinity, but 32 bits in mem_affinity. +This patch makes it consistent: Either use 8 bits consistently (SRAT +rev 1 or lower) or 32 bits (SRAT rev 2 or higher). + +This is patch 2/3. + +Signed-off-by: Kurt Garloff + +--- + arch/x86/mm/srat_64.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/x86/mm/srat_64.c ++++ b/arch/x86/mm/srat_64.c +@@ -133,6 +133,8 @@ acpi_numa_processor_affinity_init(struct + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) + return; + pxm = pa->proximity_domain_lo; ++ if (acpi_srat_revision >= 2) ++ pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; + node = setup_node(pxm); + if (node < 0) { + printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); +@@ -243,6 +245,8 @@ acpi_numa_memory_affinity_init(struct ac + start = ma->base_address; + end = start + ma->length; + pxm = ma->proximity_domain; ++ if (acpi_srat_revision <= 1) ++ pxm &= 0xff; + node = setup_node(pxm); + if (node < 0) { + printk(KERN_ERR "SRAT: Too many proximity domains.\n"); diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_thermal_passive_blacklist.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_thermal_passive_blacklist.patch new file mode 100644 index 000000000..a07e12993 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_thermal_passive_blacklist.patch @@ -0,0 +1,104 @@ +From: Thomas Renninger +Subject: Avoid critical temp shutdowns on specific ThinkPad T4x(p) and R40 +References: https://bugzilla.novell.com/show_bug.cgi?id=333043 + +--- + drivers/acpi/thermal.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 73 insertions(+) + +--- a/drivers/acpi/thermal.c ++++ b/drivers/acpi/thermal.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1640,6 +1641,66 @@ static int acpi_thermal_get_info(struct + return 0; + } + ++static struct dmi_system_id thermal_psv_dmi_table[] = { ++ { ++ .ident = "IBM ThinkPad T41", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T41"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad T42", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T42"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad T43", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T43"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad T41p", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T41p"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad T42p", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T42p"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad T43p", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad T43p"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad R40", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad R40"), ++ }, ++ }, ++ { ++ .ident = "IBM ThinkPad R50p", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), ++ DMI_MATCH(DMI_PRODUCT_VERSION,"ThinkPad R50p"), ++ }, ++ }, ++ {}, ++}; ++ + static int acpi_thermal_add(struct acpi_device *device) + { + int result = 0; +@@ -1670,6 +1731,18 @@ static int acpi_thermal_add(struct acpi_ + if (result) + goto free_memory; + ++ if (dmi_check_system(thermal_psv_dmi_table)) { ++ if (tz->trips.passive.flags.valid && ++ tz->trips.passive.temperature > CELSIUS_TO_KELVIN(85)) { ++ printk (KERN_INFO "Adjust passive trip point from %lu" ++ " to %lu\n", ++ KELVIN_TO_CELSIUS(tz->trips.passive.temperature), ++ KELVIN_TO_CELSIUS(tz->trips.passive.temperature - 150)); ++ tz->trips.passive.temperature -= 150; ++ acpi_thermal_set_polling(tz, 5); ++ } ++ } ++ + result = acpi_thermal_add_fs(device); + if (result) + goto unregister_thermal_zone; diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_introduce_acpi_root_table_boot_param.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_introduce_acpi_root_table_boot_param.patch new file mode 100644 index 000000000..c5ab109f7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_introduce_acpi_root_table_boot_param.patch @@ -0,0 +1,96 @@ +From: Thomas Renninger +Subject: Introduce acpi_root_table=rsdt boot param and dmi list to force rsdt +Patch-mainline: not yet +References: http://bugzilla.kernel.org/show_bug.cgi?id=8246 + +This one is part of a patch series: +acpi_thinkpad_introduce_acpi_root_table_boot_param.patch +acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch +acpi_thinkpad_remove_R40e_c-state_blacklist.patch + +Blacklist R40e, R51e and T40, T40p, T41, T41p, T42, T42p, R50 and R50p +ThinkPads to use the RSDT instead of the XSDT. + +Signed-off-by: Thomas Renninger +Tested-by: Mark Doughty +CC: Yakui Zhao + +--- + Documentation/kernel-parameters.txt | 5 ++++ + drivers/acpi/tables.c | 37 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -237,6 +237,11 @@ and is between 256 and 4096 characters. + to assume that this machine's pmtimer latches its value + and always returns good values. + ++ acpi_root_table= [X86,ACPI] ++ { rsdt } ++ rsdt: Take RSDT address for fetching ++ ACPI tables (instead of XSDT) ++ + agp= [AGP] + { off | try_unsupported } + off: disable AGP support +--- a/drivers/acpi/tables.c ++++ b/drivers/acpi/tables.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #define PREFIX "ACPI: " + +@@ -282,6 +283,37 @@ static void __init check_multiple_madt(v + return; + } + ++static struct dmi_system_id __initdata acpi_rsdt_dmi_table[] = { ++ { ++ .ident = "ThinkPad ", /* R40e, broken C-states */ ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "1SET")}, ++ }, ++ { ++ .ident = "ThinkPad ", /* R50e, slow booting */ ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "1WET")}, ++ }, ++ { ++ .ident = "ThinkPad ", /* T40, T40p, T41, T41p, T42, T42p ++ R50, R50p */ ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "1RET")}, ++ }, ++ {} ++}; ++ ++static int __init acpi_force_rsdt(char *opt) ++{ ++ if (!strcmp(opt, "rsdt")) ++ acpi_gbl_force_rsdt = 1; ++ return 0; ++} ++early_param("acpi_root_table", acpi_force_rsdt); ++ + /* + * acpi_table_init() + * +@@ -295,6 +327,11 @@ int __init acpi_table_init(void) + { + acpi_status status; + ++ if (dmi_check_system(acpi_rsdt_dmi_table)) ++ acpi_gbl_force_rsdt = 1; ++ if (acpi_gbl_force_rsdt) ++ printk(KERN_INFO "Using RSDT as ACPI root table\n"); ++ + status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); + if (ACPI_FAILURE(status)) + return 1; diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch new file mode 100644 index 000000000..877ebf336 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch @@ -0,0 +1,53 @@ +From: Thomas Renninger +Subject: ACPICA: Add acpi_gbl_force_rsdt variable +Patch-mainline: not yet +References: http://bugzilla.kernel.org/show_bug.cgi?id=8246 + +This one is part of a patch series: +acpi_thinkpad_introduce_acpi_root_table_boot_param.patch +acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch +acpi_thinkpad_remove_R40e_c-state_blacklist.patch + + +Signed-off-by: Thomas Renninger +Tested-by: Mark Doughty + + +--- + drivers/acpi/tables/tbutils.c | 3 ++- + drivers/acpi/utilities/utglobal.c | 1 + + include/acpi/acglobal.h | 1 + + 3 files changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/acpi/tables/tbutils.c ++++ b/drivers/acpi/tables/tbutils.c +@@ -420,7 +420,8 @@ acpi_tb_parse_root_table(acpi_physical_a + + /* Differentiate between RSDT and XSDT root tables */ + +- if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { ++ if (rsdp->revision > 1 && rsdp->xsdt_physical_address ++ && !acpi_gbl_force_rsdt) { + /* + * Root table is an XSDT (64-bit physical addresses). We must use the + * XSDT if the revision is > 1 and the XSDT pointer is present, as per +--- a/drivers/acpi/utilities/utglobal.c ++++ b/drivers/acpi/utilities/utglobal.c +@@ -76,6 +76,7 @@ u8 acpi_gbl_method_executing = FALSE; + /* System flags */ + + u32 acpi_gbl_startup_flags = 0; ++int acpi_gbl_force_rsdt = 0; + + /* System starts uninitialized */ + +--- a/include/acpi/acglobal.h ++++ b/include/acpi/acglobal.h +@@ -246,6 +246,7 @@ ACPI_EXTERN u8 acpi_gbl_system_awake_and + + extern u8 acpi_gbl_shutdown; + extern u32 acpi_gbl_startup_flags; ++extern int acpi_gbl_force_rsdt; + extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; + extern const char *acpi_gbl_highest_dstate_names[4]; + extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_remove_R40e_c-state_blacklist.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_remove_R40e_c-state_blacklist.patch new file mode 100644 index 000000000..2dfd73522 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_thinkpad_remove_R40e_c-state_blacklist.patch @@ -0,0 +1,98 @@ +From: Thomas Renninger +Subject: Remove R40e c-state blacklist +Patch-mainline: not yet +References: http://bugzilla.kernel.org/show_bug.cgi?id=8246 + +This one is part of a patch series: +acpi_thinkpad_introduce_acpi_root_table_boot_param.patch +acpi_thinkpad_introduce_acpica_rsdt_global_variable.patch +acpi_thinkpad_remove_R40e_c-state_blacklist.patch + + +The FADT pointed to through XSDT is wrong on this (and similar) +machines. +The HW addresses to switch C-states are coming from the FADT. +When using the FADT pointed to in the RSDT the info is correct. +Previous patches blacklist this machine to use the right FADT and +C-states finally work fine. + +Signed-off-by: Thomas Renninger +Tested-by: Mark Doughty + +Remove R40e c-state blacklist + +The FADT pointed to through XSDT is wrong on this (and similar) machines. +The HW addresses to switch C-states are coming from the FADT. +When using the FADT pointed to in the RSDT the info is correct. +Previous patches blacklist this machine to use the right FADT and +C-states finally work fine. + +Signed-off-by: Thomas Renninger +Tested-by: Mark Doughty +CC: Yakui Zhao + + +--- + drivers/acpi/processor_idle.c | 51 ------------------------------------------ + 1 file changed, 51 deletions(-) + +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -127,57 +127,6 @@ static int set_max_cstate(const struct d + /* Actually this shouldn't be __cpuinitdata, would be better to fix the + callers to only run once -AK */ + static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET43WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET45WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET47WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET50WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET52WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET55WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET56WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET59WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET61WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET62WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET64WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET65WW") }, (void*)1}, +- { set_max_cstate, "IBM ThinkPad R40e", { +- DMI_MATCH(DMI_BIOS_VENDOR,"IBM"), +- DMI_MATCH(DMI_BIOS_VERSION,"1SET68WW") }, (void*)1}, +- { set_max_cstate, "Medion 41700", { +- DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), +- DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J")}, (void *)1}, + { set_max_cstate, "Clevo 5600D", { + DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), + DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")}, diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_video_thinkpad_exclude_IGD_devices.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_video_thinkpad_exclude_IGD_devices.patch new file mode 100644 index 000000000..1a051f362 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_video_thinkpad_exclude_IGD_devices.patch @@ -0,0 +1,56 @@ +From: Thomas Renninger +Subject: Do not use video backlight switching for Lenovo ThinkPads +Patch-Mainline: never + +Mainline will go the IGD driver way which is too new and untested for +SLE11. + +--- + drivers/acpi/video.c | 17 ++++++++++++++--- + drivers/acpi/video_detect.c | 2 +- + 2 files changed, 15 insertions(+), 4 deletions(-) + +--- a/drivers/acpi/video.c ++++ b/drivers/acpi/video.c +@@ -731,7 +731,7 @@ static void acpi_video_device_find_cap(s + { + acpi_handle h_dummy1; + u32 max_level = 0; +- ++ unsigned long acpi_video_support; + + memset(&device->cap, 0, sizeof(device->cap)); + +@@ -759,8 +759,19 @@ static void acpi_video_device_find_cap(s + device->cap._DSS = 1; + } + +- if (acpi_video_backlight_support()) +- max_level = acpi_video_init_brightness(device); ++ acpi_video_support = acpi_video_backlight_support(); ++ if (acpi_video_support) { ++ /* ++ * Ugly SLE11 hack to let thinkpad_acpi handle brightness on ++ * ThinkPad IGD devices ++ */ ++ if (dmi_name_in_vendors("LENOVO") && ++ (acpi_video_support & ACPI_VIDEO_IGD)) ++ brightness_switch_enabled = 0; ++ else ++ max_level = acpi_video_init_brightness(device); ++ } else ++ brightness_switch_enabled = 0; + + if (device->cap._BCL && device->cap._BCM && max_level > 0) { + int result; +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -217,7 +217,7 @@ int acpi_video_backlight_support(void) + return 1; + + /* Then go the default way */ +- return acpi_video_support & ACPI_VIDEO_BACKLIGHT; ++ return acpi_video_support & (ACPI_VIDEO_BACKLIGHT | ACPI_VIDEO_IGD); + } + EXPORT_SYMBOL(acpi_video_backlight_support); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/acpi_x2APIC_madt_enhancements.patch b/src/patches/suse-2.6.27.31/patches.arch/acpi_x2APIC_madt_enhancements.patch new file mode 100644 index 000000000..00a981b97 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/acpi_x2APIC_madt_enhancements.patch @@ -0,0 +1,134 @@ +From: Bob Moore +Subject: ACPICA: x2APIC support: changes for MADT and SRAT ACPI tables +References: fate 303948 and fate 303984 +Patch-Mainline: in 2.6.28 +Commit-ID: 1d7cc03049f7c9c5cced9208a39316c5245ef314 + +Signed-off-by: Thomas Renninger + +Support for the x2APIC. There are 2 new subtables for the MADT and +one new subtable for the SRAT. Includes disassembler and acpisrc +support. Data from the Intel 64 Architecture x2APIC Specification, +June 2008. + +Signed-off-by: Bob Moore +Signed-off-by: Lin Ming +Signed-off-by: Andi Kleen +Signed-off-by: Len Brown + +diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h +index f53faca..0c1ed38 100644 +--- a/include/acpi/acdisasm.h ++++ b/include/acpi/acdisasm.h +@@ -186,6 +186,8 @@ extern struct acpi_dmtable_info acpi_dm_table_info_madt5[]; + extern struct acpi_dmtable_info acpi_dm_table_info_madt6[]; + extern struct acpi_dmtable_info acpi_dm_table_info_madt7[]; + extern struct acpi_dmtable_info acpi_dm_table_info_madt8[]; ++extern struct acpi_dmtable_info acpi_dm_table_info_madt9[]; ++extern struct acpi_dmtable_info acpi_dm_table_info_madt10[]; + extern struct acpi_dmtable_info acpi_dm_table_info_madt_hdr[]; + extern struct acpi_dmtable_info acpi_dm_table_info_mcfg[]; + extern struct acpi_dmtable_info acpi_dm_table_info_mcfg0[]; +@@ -197,8 +199,10 @@ extern struct acpi_dmtable_info acpi_dm_table_info_slit[]; + extern struct acpi_dmtable_info acpi_dm_table_info_spcr[]; + extern struct acpi_dmtable_info acpi_dm_table_info_spmi[]; + extern struct acpi_dmtable_info acpi_dm_table_info_srat[]; ++extern struct acpi_dmtable_info acpi_dm_table_info_srat_hdr[]; + extern struct acpi_dmtable_info acpi_dm_table_info_srat0[]; + extern struct acpi_dmtable_info acpi_dm_table_info_srat1[]; ++extern struct acpi_dmtable_info acpi_dm_table_info_srat2[]; + extern struct acpi_dmtable_info acpi_dm_table_info_tcpa[]; + extern struct acpi_dmtable_info acpi_dm_table_info_wdrt[]; + +diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h +index d38f9be..63f5b4c 100644 +--- a/include/acpi/actbl1.h ++++ b/include/acpi/actbl1.h +@@ -908,7 +908,9 @@ enum acpi_madt_type { + ACPI_MADT_TYPE_IO_SAPIC = 6, + ACPI_MADT_TYPE_LOCAL_SAPIC = 7, + ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, +- ACPI_MADT_TYPE_RESERVED = 9 /* 9 and greater are reserved */ ++ ACPI_MADT_TYPE_LOCAL_X2APIC = 9, ++ ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, ++ ACPI_MADT_TYPE_RESERVED = 11 /* 11 and greater are reserved */ + }; + + /* +@@ -1009,6 +1011,26 @@ struct acpi_madt_interrupt_source { + + #define ACPI_MADT_CPEI_OVERRIDE (1) + ++/* 9: Processor Local X2_APIC (07/2008) */ ++ ++struct acpi_madt_local_x2apic { ++ struct acpi_subtable_header header; ++ u16 reserved; /* Reserved - must be zero */ ++ u32 local_apic_id; /* Processor X2_APIC ID */ ++ u32 lapic_flags; ++ u32 uid; /* Extended X2_APIC processor ID */ ++}; ++ ++/* 10: Local X2APIC NMI (07/2008) */ ++ ++struct acpi_madt_local_x2apic_nmi { ++ struct acpi_subtable_header header; ++ u16 inti_flags; ++ u32 uid; /* Processor X2_APIC ID */ ++ u8 lint; /* LINTn to which NMI is connected */ ++ u8 reserved[3]; ++}; ++ + /* + * Common flags fields for MADT subtables + */ +@@ -1150,10 +1172,15 @@ struct acpi_table_srat { + enum acpi_srat_type { + ACPI_SRAT_TYPE_CPU_AFFINITY = 0, + ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1, +- ACPI_SRAT_TYPE_RESERVED = 2 ++ ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2, ++ ACPI_SRAT_TYPE_RESERVED = 3 /* 3 and greater are reserved */ + }; + +-/* SRAT sub-tables */ ++/* ++ * SRAT Sub-tables, correspond to Type in struct acpi_subtable_header ++ */ ++ ++/* 0: Processor Local APIC/SAPIC Affinity */ + + struct acpi_srat_cpu_affinity { + struct acpi_subtable_header header; +@@ -1165,9 +1192,7 @@ struct acpi_srat_cpu_affinity { + u32 reserved; /* Reserved, must be zero */ + }; + +-/* Flags */ +- +-#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */ ++/* 1: Memory Affinity */ + + struct acpi_srat_mem_affinity { + struct acpi_subtable_header header; +@@ -1186,6 +1211,20 @@ struct acpi_srat_mem_affinity { + #define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */ + #define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */ + ++/* 2: Processor Local X2_APIC Affinity (07/2008) */ ++ ++struct acpi_srat_x2apic_cpu_affinity { ++ struct acpi_subtable_header header; ++ u16 reserved; /* Reserved, must be zero */ ++ u32 proximity_domain; ++ u32 apic_id; ++ u32 flags; ++}; ++ ++/* Flags for struct acpi_srat_cpu_affinity and struct acpi_srat_x2apic_cpu_affinity */ ++ ++#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */ ++ + /******************************************************************************* + * + * TCPA - Trusted Computing Platform Alliance table diff --git a/src/patches/suse-2.6.27.31/patches.arch/check-for-acpi-resource-conflicts-in-hwmon-drivers.patch b/src/patches/suse-2.6.27.31/patches.arch/check-for-acpi-resource-conflicts-in-hwmon-drivers.patch new file mode 100644 index 000000000..2b398303d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/check-for-acpi-resource-conflicts-in-hwmon-drivers.patch @@ -0,0 +1,335 @@ +From: Jean Delvare +Subject: Check for ACPI resource conflicts in hwmon drivers. +Patch-mainline: 2.6.24-rc3-mm1 + +I've included all Super-I/O and PCI drivers. + +I've voluntarily left out: +* Laptop specific and vendor-specific drivers: if they conflicted + on any system, this would pretty much mean that they conflict on all + systems, and we would know by now. +* Legacy ISA drivers (lm78 and w83781d): they only support chips found + on old designs were ACPI either wasn't supported or didn't deal with + thermal management. +* Drivers accessing the I/O resources indirectly (e.g. through SMBus): + the check will be added where it belongs, i.e. in the bus drivers. + +Signed-off-by: Jean Delvare +Signed-off-by: Thomas Renninger +Cc: "Mark M. Hoffman" +Cc: Len Brown +Signed-off-by: Andrew Morton +--- + + drivers/hwmon/dme1737.c | 5 +++++ + drivers/hwmon/f71805f.c | 5 +++++ + drivers/hwmon/f71882fg.c | 5 +++++ + drivers/hwmon/it87.c | 5 +++++ + drivers/hwmon/pc87360.c | 6 ++++++ + drivers/hwmon/pc87427.c | 5 +++++ + drivers/hwmon/sis5595.c | 5 +++++ + drivers/hwmon/smsc47b397.c | 5 +++++ + drivers/hwmon/smsc47m1.c | 5 +++++ + drivers/hwmon/via686a.c | 5 +++++ + drivers/hwmon/vt1211.c | 5 +++++ + drivers/hwmon/vt8231.c | 5 +++++ + drivers/hwmon/w83627ehf.c | 6 ++++++ + drivers/hwmon/w83627hf.c | 5 +++++ + 14 files changed, 72 insertions(+) + +--- a/drivers/hwmon/dme1737.c ++++ b/drivers/hwmon/dme1737.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + + /* ISA device, if found */ +@@ -2372,6 +2373,10 @@ static int __init dme1737_isa_device_add + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + if (!(pdev = platform_device_alloc("dme1737", addr))) { + printk(KERN_ERR "dme1737: Failed to allocate device.\n"); + err = -ENOMEM; +--- a/drivers/hwmon/f71805f.c ++++ b/drivers/hwmon/f71805f.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + + static unsigned short force_id; +@@ -1455,6 +1456,10 @@ static int __init f71805f_device_add(uns + } + + res.name = pdev->name; ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit_device_put; ++ + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " +--- a/drivers/hwmon/f71882fg.c ++++ b/drivers/hwmon/f71882fg.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #define DRVNAME "f71882fg" +@@ -892,6 +893,10 @@ static int __init f71882fg_device_add(un + return -ENOMEM; + + res.name = f71882fg_pdev->name; ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ return err; ++ + err = platform_device_add_resources(f71882fg_pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed\n"); +--- a/drivers/hwmon/it87.c ++++ b/drivers/hwmon/it87.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + #include + + #define DRVNAME "it87" +@@ -1535,6 +1536,10 @@ static int __init it87_device_add(unsign + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/pc87360.c ++++ b/drivers/hwmon/pc87360.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + #include + + static u8 devid; +@@ -1425,6 +1426,11 @@ static int __init pc87360_device_add(uns + continue; + res.start = extra_isa[i]; + res.end = extra_isa[i] + PC87360_EXTENT - 1; ++ ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit_device_put; ++ + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR "pc87360: Device resource[%d] " +--- a/drivers/hwmon/pc87427.c ++++ b/drivers/hwmon/pc87427.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + + static unsigned short force_id; +@@ -524,6 +525,10 @@ static int __init pc87427_device_add(uns + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/sis5595.c ++++ b/drivers/hwmon/sis5595.c +@@ -62,6 +62,7 @@ + #include + #include + #include ++#include + #include + + +@@ -727,6 +728,10 @@ static int __devinit sis5595_device_add( + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc("sis5595", address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/smsc47b397.c ++++ b/drivers/hwmon/smsc47b397.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + + static unsigned short force_id; +@@ -303,6 +304,10 @@ static int __init smsc47b397_device_add( + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/smsc47m1.c ++++ b/drivers/hwmon/smsc47m1.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + + static unsigned short force_id; +@@ -716,6 +717,10 @@ static int __init smsc47m1_device_add(un + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/via686a.c ++++ b/drivers/hwmon/via686a.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + #include + + +@@ -783,6 +784,10 @@ static int __devinit via686a_device_add( + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc("via686a", address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/vt1211.c ++++ b/drivers/hwmon/vt1211.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + + static int uch_config = -1; +@@ -1259,6 +1260,10 @@ static int __init vt1211_device_add(unsi + } + + res.name = pdev->name; ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto EXIT; ++ + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " +--- a/drivers/hwmon/vt8231.c ++++ b/drivers/hwmon/vt8231.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + + static int force_addr; +@@ -894,6 +895,10 @@ static int __devinit vt8231_device_add(u + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc("vt8231", address); + if (!pdev) { + err = -ENOMEM; +--- a/drivers/hwmon/w83627ehf.c ++++ b/drivers/hwmon/w83627ehf.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + #include + #include "lm75.h" + +@@ -1544,6 +1545,11 @@ static int __init sensors_w83627ehf_init + res.start = address + IOREGION_OFFSET; + res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; + res.flags = IORESOURCE_IO; ++ ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " +--- a/drivers/hwmon/w83627hf.c ++++ b/drivers/hwmon/w83627hf.c +@@ -50,6 +50,7 @@ + #include + #include + #include ++#include + #include + #include "lm75.h" + +@@ -1793,6 +1794,10 @@ static int __init w83627hf_device_add(un + }; + int err; + ++ err = acpi_check_resource_conflict(&res); ++ if (err) ++ goto exit; ++ + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; diff --git a/src/patches/suse-2.6.27.31/patches.arch/compat-sys-swapcontext b/src/patches/suse-2.6.27.31/patches.arch/compat-sys-swapcontext new file mode 100644 index 000000000..20129ea22 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/compat-sys-swapcontext @@ -0,0 +1,38 @@ +From: schwab@suse.de +Subject: Fix msr check in compat_sys_swapcontext +References: 441498 + +The new context may not be 16-byte aligned, so the real address of the +mcontext structure should be read from the uc_regs pointer instead of +directly using the (unaligned) uc_mcontext field. + +Signed-off-by: Andreas Schwab + +--- +--- + arch/powerpc/kernel/signal_32.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/arch/powerpc/kernel/signal_32.c ++++ b/arch/powerpc/kernel/signal_32.c +@@ -941,9 +941,17 @@ long sys_swapcontext(struct ucontext __u + #ifdef CONFIG_PPC64 + unsigned long new_msr = 0; + +- if (new_ctx && +- get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR])) +- return -EFAULT; ++ if (new_ctx) { ++ struct mcontext __user *mcp; ++ u32 cmcp; ++ ++ /* Get pointer to the real mcontext. */ ++ if (get_user(cmcp, &new_ctx->uc_regs)) ++ return -EFAULT; ++ mcp = (struct mcontext __user *)(u64)cmcp; ++ if (get_user(new_msr, &mcp->mc_gregs[PT_MSR])) ++ return -EFAULT; ++ } + /* + * Check that the context is not smaller than the original + * size (with VMX but without VSX) diff --git a/src/patches/suse-2.6.27.31/patches.arch/disable-apic-error b/src/patches/suse-2.6.27.31/patches.arch/disable-apic-error new file mode 100644 index 000000000..5d29258eb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/disable-apic-error @@ -0,0 +1,43 @@ +From: ak@suse.de +Subject: Disable APIC error printing +References: 156576 +Patch-mainline: not planned + +ATI chipsets currently do this all the time. It's probably +mostly harmless + +We keep it enabled in mainline to make sure the (hardware?) bug +is tracked down, but don't bother in the distribution kernels +with it. + +--- + arch/x86/kernel/apic_32.c | 2 ++ + arch/x86/kernel/apic_64.c | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/arch/x86/kernel/apic_32.c ++++ b/arch/x86/kernel/apic_32.c +@@ -1316,8 +1316,10 @@ void smp_error_interrupt(struct pt_regs + 6: Received illegal vector + 7: Illegal register address + */ ++#if 0 + printk(KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n", + smp_processor_id(), v , v1); ++#endif + irq_exit(); + } + +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -998,8 +998,10 @@ asmlinkage void smp_error_interrupt(void + 6: Received illegal vector + 7: Illegal register address + */ ++#if 0 + printk(KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", + smp_processor_id(), v , v1); ++#endif + irq_exit(); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-cpu_disable-fix b/src/patches/suse-2.6.27.31/patches.arch/ia64-cpu_disable-fix new file mode 100644 index 000000000..e99ae761e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-cpu_disable-fix @@ -0,0 +1,30 @@ +From: Alex Chiang +Subject: IA64: first clear CPU from online map, then fixup IRQs. +References: bnc#386714 + +Acked-by: Raymund Will + +--- + arch/ia64/kernel/smpboot.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/arch/ia64/kernel/smpboot.c ++++ b/arch/ia64/kernel/smpboot.c +@@ -741,14 +741,12 @@ int __cpu_disable(void) + return -EBUSY; + } + +- if (migrate_platform_irqs(cpu)) { +- cpu_set(cpu, cpu_online_map); +- return (-EBUSY); +- } ++ if (migrate_platform_irqs(cpu)) ++ return -EBUSY; + + remove_siblinginfo(cpu); +- fixup_irqs(); + cpu_clear(cpu, cpu_online_map); ++ fixup_irqs(); + local_flush_tlb_all(); + cpu_clear(cpu, cpu_callin_map); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-page-migration b/src/patches/suse-2.6.27.31/patches.arch/ia64-page-migration new file mode 100644 index 000000000..cf040c830 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-page-migration @@ -0,0 +1,598 @@ +From: Russ Anderson +Subject: ia64: Call migration code on correctable errors v8 +References: 415829 +Acked-by: schwab@suse.de + +Migrate data off pages with correctable memory errors. This patch is the +ia64 specific piece. It connects the CPE handler to the page migration +code. It is implemented as a kernel loadable module, similar to the mca +recovery code (mca_recovery.ko). This allows the feature to be turned off +by uninstalling the module. + + +Signed-off-by: Russ Anderson + +--- + arch/ia64/Kconfig | 9 + arch/ia64/include/asm/mca.h | 6 + arch/ia64/include/asm/page.h | 1 + arch/ia64/kernel/Makefile | 1 + arch/ia64/kernel/cpe_migrate.c | 434 +++++++++++++++++++++++++++++++++++++++++ + arch/ia64/kernel/mca.c | 37 +++ + 6 files changed, 487 insertions(+), 1 deletion(-) + +--- a/arch/ia64/include/asm/mca.h ++++ b/arch/ia64/include/asm/mca.h +@@ -137,6 +137,7 @@ extern unsigned long __per_cpu_mca[NR_CP + + extern int cpe_vector; + extern int ia64_cpe_irq; ++extern int cpe_poll_enabled; + extern void ia64_mca_init(void); + extern void ia64_mca_cpu_init(void *); + extern void ia64_os_mca_dispatch(void); +@@ -150,10 +151,15 @@ extern void ia64_slave_init_handler(void + extern void ia64_mca_cmc_vector_setup(void); + extern int ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *)); + extern void ia64_unreg_MCA_extension(void); ++extern int ia64_reg_CE_extension(int (*fn)(void *)); ++extern void ia64_unreg_CE_extension(void); + extern u64 ia64_get_rnat(u64 *); + extern void ia64_mca_printk(const char * fmt, ...) + __attribute__ ((format (printf, 1, 2))); + ++extern struct list_head badpagelist; ++extern unsigned int total_badpages; ++ + struct ia64_mca_notify_die { + struct ia64_sal_os_state *sos; + int *monarch_cpu; +--- a/arch/ia64/include/asm/page.h ++++ b/arch/ia64/include/asm/page.h +@@ -121,6 +121,7 @@ extern unsigned long max_low_pfn; + #endif + + #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) ++#define phys_to_page(kaddr) (pfn_to_page(kaddr >> PAGE_SHIFT)) + #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) + #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + +--- a/arch/ia64/Kconfig ++++ b/arch/ia64/Kconfig +@@ -470,6 +470,15 @@ config COMPAT_FOR_U64_ALIGNMENT + config IA64_MCA_RECOVERY + tristate "MCA recovery from errors other than TLB." + ++config IA64_CPE_MIGRATE ++ tristate "Migrate data off pages with correctable errors" ++ default m ++ help ++ Migrate data off pages with correctable memory errors. Selecting ++ Y will build this functionality into the kernel. Selecting M will ++ build this functionality as a kernel loadable module. Installing ++ the module will turn on the functionality. ++ + config PERFMON + bool "Performance monitor support" + help +--- /dev/null ++++ b/arch/ia64/kernel/cpe_migrate.c +@@ -0,0 +1,434 @@ ++/* ++ * File: cpe_migrate.c ++ * Purpose: Migrate data from physical pages with excessive correctable ++ * errors to new physical pages. Keep the old pages on a discard ++ * list. ++ * ++ * Copyright (C) 2008 SGI - Silicon Graphics Inc. ++ * Copyright (C) 2008 Russ Anderson ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define BADRAM_BASENAME "badram" ++#define CE_HISTORY_LENGTH 30 ++ ++struct cpe_info { ++ u64 paddr; ++ u16 node; ++}; ++static struct cpe_info cpe[CE_HISTORY_LENGTH]; ++ ++static int cpe_polling_enabled = 1; ++static int cpe_head; ++static int cpe_tail; ++static int work_scheduled; ++static int mstat_cannot_isolate; ++static int mstat_failed_to_discard; ++static int mstat_already_marked; ++static int mstat_already_on_list; ++ ++DEFINE_SPINLOCK(cpe_migrate_lock); ++ ++static void ++get_physical_address(void *buffer, u64 *paddr, u16 *node) ++{ ++ sal_log_record_header_t *rh; ++ sal_log_mem_dev_err_info_t *mdei; ++ ia64_err_rec_t *err_rec; ++ sal_log_platform_err_info_t *plat_err; ++ efi_guid_t guid; ++ ++ err_rec = buffer; ++ rh = &err_rec->sal_elog_header; ++ *paddr = 0; ++ *node = 0; ++ ++ /* ++ * Make sure it is a corrected error. ++ */ ++ if (rh->severity != sal_log_severity_corrected) ++ return; ++ ++ plat_err = (sal_log_platform_err_info_t *)&err_rec->proc_err; ++ ++ guid = plat_err->mem_dev_err.header.guid; ++ if (efi_guidcmp(guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { ++ /* ++ * Memory cpe ++ */ ++ mdei = &plat_err->mem_dev_err; ++ if (mdei->valid.oem_data) { ++ if (mdei->valid.physical_addr) ++ *paddr = mdei->physical_addr; ++ ++ if (mdei->valid.node) { ++ if (ia64_platform_is("sn2")) ++ *node = nasid_to_cnodeid(mdei->node); ++ else ++ *node = mdei->node; ++ } ++ } ++ } ++} ++ ++static struct page * ++alloc_migrate_page(struct page *ignored, unsigned long node, int **x) ++{ ++ ++ return alloc_pages_node(node, GFP_HIGHUSER_MOVABLE, 0); ++} ++ ++static int ++validate_paddr_page(u64 paddr) ++{ ++ struct page *page; ++ ++ if (!paddr) ++ return -EINVAL; ++ ++ if (!ia64_phys_addr_valid(paddr)) ++ return -EINVAL; ++ ++ if (!pfn_valid(paddr >> PAGE_SHIFT)) ++ return -EINVAL; ++ ++ page = phys_to_page(paddr); ++ if (PageMemError(page)) ++ mstat_already_marked++; ++ return 0; ++} ++ ++static int ++ia64_mca_cpe_move_page(u64 paddr, u32 node) ++{ ++ LIST_HEAD(pagelist); ++ struct page *page; ++ int ret; ++ ++ ret = validate_paddr_page(paddr); ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * convert physical address to page number ++ */ ++ page = phys_to_page(paddr); ++ ++ migrate_prep(); ++ ret = isolate_lru_page(page, &pagelist); ++ if (ret) { ++ mstat_cannot_isolate++; ++ return ret; ++ } ++ ++ SetPageMemError(page); /* Mark the page as bad */ ++ ret = migrate_pages(&pagelist, alloc_migrate_page, node); ++ if (ret == 0) { ++ total_badpages++; ++ list_add_tail(&page->lru, &badpagelist); ++ } else { ++ mstat_failed_to_discard++; ++ /* ++ * The page failed to migrate and is not on the bad page list. ++ * Clearing the error bit will allow another attempt to migrate ++ * if it gets another correctable error. ++ */ ++ ClearPageMemError(page); ++ } ++ ++ return 0; ++} ++ ++/* ++ * ia64_mca_cpe_migrate ++ * The worker that does the actual migration. It pulls a ++ * physical address off the list and calls the migration code. ++ */ ++static void ++ia64_mca_cpe_migrate(struct work_struct *unused) ++{ ++ int ret; ++ u64 paddr; ++ u16 node; ++ ++ do { ++ paddr = cpe[cpe_tail].paddr; ++ if (paddr) { ++ /* ++ * There is a valid entry that needs processing. ++ */ ++ node = cpe[cpe_tail].node; ++ ++ ret = ia64_mca_cpe_move_page(paddr, node); ++ if (ret <= 0) ++ /* ++ * Even though the return status is negative, ++ * clear the entry. If the same address has ++ * another CPE it will be re-added to the list. ++ */ ++ cpe[cpe_tail].paddr = 0; ++ ++ } ++ if (++cpe_tail >= CE_HISTORY_LENGTH) ++ cpe_tail = 0; ++ ++ } while (cpe_tail != cpe_head); ++ work_scheduled = 0; ++} ++ ++static DECLARE_WORK(cpe_enable_work, ia64_mca_cpe_migrate); ++DEFINE_SPINLOCK(cpe_list_lock); ++ ++/* ++ * cpe_setup_migrate ++ * Get the physical address out of the CPE record, add it ++ * to the list of addresses to migrate (if not already on), ++ * and schedule the back end worker task. This is called ++ * in interrupt context so cannot directly call the migration ++ * code. ++ * ++ * Inputs ++ * rec The CPE record ++ * Outputs ++ * 1 on Success, -1 on failure ++ */ ++static int ++cpe_setup_migrate(void *rec) ++{ ++ u64 paddr; ++ u16 node; ++ /* int head, tail; */ ++ int i, ret; ++ ++ if (!rec) ++ return -EINVAL; ++ ++ get_physical_address(rec, &paddr, &node); ++ ret = validate_paddr_page(paddr); ++ if (ret < 0) ++ return -EINVAL; ++ ++ if ((cpe_head != cpe_tail) || (cpe[cpe_head].paddr != 0)) ++ /* ++ * List not empty ++ */ ++ for (i = 0; i < CE_HISTORY_LENGTH; i++) { ++ if (PAGE_ALIGN(cpe[i].paddr) == PAGE_ALIGN(paddr)) { ++ mstat_already_on_list++; ++ return 1; /* already on the list */ ++ } ++ } ++ ++ if (!spin_trylock(&cpe_list_lock)) { ++ /* ++ * Someone else has the lock. To avoid spinning in interrupt ++ * handler context, bail. ++ */ ++ return 1; ++ } ++ ++ if (cpe[cpe_head].paddr == 0) { ++ cpe[cpe_head].node = node; ++ cpe[cpe_head].paddr = paddr; ++ ++ if (++cpe_head >= CE_HISTORY_LENGTH) ++ cpe_head = 0; ++ } ++ spin_unlock(&cpe_list_lock); ++ ++ if (!work_scheduled) { ++ work_scheduled = 1; ++ schedule_work(&cpe_enable_work); ++ } ++ ++ return 1; ++} ++ ++/* ++ * ============================================================================= ++ */ ++ ++/* ++ * free_one_bad_page ++ * Free one page from the list of bad pages. ++ */ ++static int ++free_one_bad_page(unsigned long paddr) ++{ ++ LIST_HEAD(pagelist); ++ struct page *page, *page2, *target; ++ ++ /* ++ * Verify page address ++ */ ++ target = phys_to_page(paddr); ++ list_for_each_entry_safe(page, page2, &badpagelist, lru) { ++ if (page != target) ++ continue; ++ ++ ClearPageMemError(page); /* Mark the page as good */ ++ total_badpages--; ++ list_move_tail(&page->lru, &pagelist); ++ putback_lru_pages(&pagelist); ++ break; ++ } ++ return 0; ++} ++ ++/* ++ * free_all_bad_pages ++ * Free all of the pages on the bad pages list. ++ */ ++static int ++free_all_bad_pages(void) ++{ ++ struct page *page, *page2; ++ ++ list_for_each_entry_safe(page, page2, &badpagelist, lru) { ++ ClearPageMemError(page); /* Mark the page as good */ ++ total_badpages--; ++ } ++ putback_lru_pages(&badpagelist); ++ return 0; ++} ++ ++#define OPT_LEN 16 ++ ++static ssize_t ++badpage_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ char optstr[OPT_LEN]; ++ unsigned long opt; ++ int len = OPT_LEN; ++ int err; ++ ++ if (count < len) ++ len = count; ++ ++ strlcpy(optstr, buf, len); ++ ++ err = strict_strtoul(optstr, 16, &opt); ++ if (err) ++ return err; ++ ++ if (opt == 0) ++ free_all_bad_pages(); ++ else ++ free_one_bad_page(opt); ++ ++ return count; ++} ++ ++/* ++ * badpage_show ++ * Display the number, size, and addresses of all the pages on the ++ * bad page list. ++ * ++ * Note that sysfs provides buf of PAGE_SIZE length. bufend tracks ++ * the remaining space in buf to avoid overflowing. ++ */ ++static ssize_t ++badpage_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++ ++{ ++ struct page *page, *page2; ++ int i = 0, cnt = 0; ++ char *bufend = buf + PAGE_SIZE; ++ ++ cnt = snprintf(buf, bufend - (buf + cnt), ++ "Memory marked bad: %d kB\n" ++ "Pages marked bad: %d\n" ++ "Unable to isolate on LRU: %d\n" ++ "Unable to migrate: %d\n" ++ "Already marked bad: %d\n" ++ "Already on list: %d\n" ++ "List of bad physical pages\n", ++ total_badpages << (PAGE_SHIFT - 10), total_badpages, ++ mstat_cannot_isolate, mstat_failed_to_discard, ++ mstat_already_marked, mstat_already_on_list ++ ); ++ ++ list_for_each_entry_safe(page, page2, &badpagelist, lru) { ++ if (bufend - (buf + cnt) < 20) ++ break; /* Avoid overflowing the buffer */ ++ cnt += snprintf(buf + cnt, bufend - (buf + cnt), ++ " 0x%011lx", page_to_phys(page)); ++ if (!(++i % 5)) ++ cnt += snprintf(buf + cnt, bufend - (buf + cnt), "\n"); ++ } ++ cnt += snprintf(buf + cnt, bufend - (buf + cnt), "\n"); ++ ++ return cnt; ++} ++ ++static struct kobj_attribute badram_attr = { ++ .attr = { ++ .name = "badram", ++ .mode = S_IWUSR | S_IRUGO, ++ }, ++ .show = badpage_show, ++ .store = badpage_store, ++}; ++ ++static int __init ++cpe_migrate_external_handler_init(void) ++{ ++ int error; ++ ++ error = sysfs_create_file(kernel_kobj, &badram_attr.attr); ++ if (error) ++ return -EINVAL; ++ ++ /* ++ * register external ce handler ++ */ ++ if (ia64_reg_CE_extension(cpe_setup_migrate)) { ++ printk(KERN_ERR "ia64_reg_CE_extension failed.\n"); ++ return -EFAULT; ++ } ++ cpe_poll_enabled = cpe_polling_enabled; ++ ++ printk(KERN_INFO "Registered badram Driver\n"); ++ return 0; ++} ++ ++static void __exit ++cpe_migrate_external_handler_exit(void) ++{ ++ /* unregister external mca handlers */ ++ ia64_unreg_CE_extension(); ++ ++ sysfs_remove_file(kernel_kobj, &badram_attr.attr); ++} ++ ++module_init(cpe_migrate_external_handler_init); ++module_exit(cpe_migrate_external_handler_exit); ++ ++module_param(cpe_polling_enabled, int, 0644); ++MODULE_PARM_DESC(cpe_polling_enabled, ++ "Enable polling with migration"); ++ ++MODULE_AUTHOR("Russ Anderson "); ++MODULE_DESCRIPTION("ia64 Corrected Error page migration driver"); ++MODULE_LICENSE("GPL"); +--- a/arch/ia64/kernel/Makefile ++++ b/arch/ia64/kernel/Makefile +@@ -27,6 +27,7 @@ obj-$(CONFIG_PERFMON) += perfmon_defaul + obj-$(CONFIG_IA64_CYCLONE) += cyclone.o + obj-$(CONFIG_CPU_FREQ) += cpufreq/ + obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o ++obj-$(CONFIG_IA64_CPE_MIGRATE) += cpe_migrate.o + obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o + obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o + obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +--- a/arch/ia64/kernel/mca.c ++++ b/arch/ia64/kernel/mca.c +@@ -68,6 +68,9 @@ + * + * 2007-04-27 Russ Anderson + * Support multiple cpus going through OS_MCA in the same event. ++ * ++ * 2008-04-22 Russ Anderson ++ * Migrate data off pages with correctable memory errors. + */ + #include + #include +@@ -163,7 +166,14 @@ static int cmc_polling_enabled = 1; + * but encounters problems retrieving CPE logs. This should only be + * necessary for debugging. + */ +-static int cpe_poll_enabled = 1; ++int cpe_poll_enabled = 1; ++EXPORT_SYMBOL(cpe_poll_enabled); ++ ++unsigned int total_badpages; ++EXPORT_SYMBOL(total_badpages); ++ ++LIST_HEAD(badpagelist); ++EXPORT_SYMBOL(badpagelist); + + extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); + +@@ -523,6 +533,28 @@ int mca_recover_range(unsigned long addr + } + EXPORT_SYMBOL_GPL(mca_recover_range); + ++/* Function pointer to Corrected Error memory migration driver */ ++int (*ia64_mca_ce_extension)(void *); ++ ++int ++ia64_reg_CE_extension(int (*fn)(void *)) ++{ ++ if (ia64_mca_ce_extension) ++ return 1; ++ ++ ia64_mca_ce_extension = fn; ++ return 0; ++} ++EXPORT_SYMBOL(ia64_reg_CE_extension); ++ ++void ++ia64_unreg_CE_extension(void) ++{ ++ if (ia64_mca_ce_extension) ++ ia64_mca_ce_extension = NULL; ++} ++EXPORT_SYMBOL(ia64_unreg_CE_extension); ++ + #ifdef CONFIG_ACPI + + int cpe_vector = -1; +@@ -534,6 +566,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, v + static unsigned long cpe_history[CPE_HISTORY_LENGTH]; + static int index; + static DEFINE_SPINLOCK(cpe_history_lock); ++ int recover; + + IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n", + __func__, cpe_irq, smp_processor_id()); +@@ -580,6 +613,8 @@ ia64_mca_cpe_int_handler (int cpe_irq, v + out: + /* Get the CPE error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); ++ recover = (ia64_mca_ce_extension && ia64_mca_ce_extension( ++ IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_CPE))); + + return IRQ_HANDLED; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-page-migration.fix b/src/patches/suse-2.6.27.31/patches.arch/ia64-page-migration.fix new file mode 100644 index 000000000..b7515e740 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-page-migration.fix @@ -0,0 +1,161 @@ +From: Russ Anderson +Subject: ia64: cpe_migrate.ko causes deadlock. +References: bnc#464676 + +schedule_on_each_cpu() deadlocks when called from an event thread. +Change cpe_migrate to use a kthread to avoid the problem. + +Signed-off-by: Russ Anderson +Acked-by: Raymund Will + +--- + arch/ia64/kernel/cpe_migrate.c | 72 +++++++++++++++++++++++++++++++---------- + 1 file changed, 56 insertions(+), 16 deletions(-) + +Index: linux/arch/ia64/kernel/cpe_migrate.c +=================================================================== +--- linux.orig/arch/ia64/kernel/cpe_migrate.c 2009-01-09 11:37:47.130269369 -0600 ++++ linux/arch/ia64/kernel/cpe_migrate.c 2009-01-09 11:44:43.658280930 -0600 +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -40,12 +41,15 @@ static struct cpe_info cpe[CE_HISTORY_LE + static int cpe_polling_enabled = 1; + static int cpe_head; + static int cpe_tail; +-static int work_scheduled; + static int mstat_cannot_isolate; + static int mstat_failed_to_discard; + static int mstat_already_marked; + static int mstat_already_on_list; + ++/* IRQ handler notifies this wait queue on receipt of an IRQ */ ++DECLARE_WAIT_QUEUE_HEAD(cpe_activate_IRQ_wq); ++static DECLARE_COMPLETION(kthread_cpe_migrated_exited); ++int cpe_active; + DEFINE_SPINLOCK(cpe_migrate_lock); + + static void +@@ -159,12 +163,12 @@ ia64_mca_cpe_move_page(u64 paddr, u32 no + } + + /* +- * ia64_mca_cpe_migrate +- * The worker that does the actual migration. It pulls a +- * physical address off the list and calls the migration code. ++ * cpe_process_queue ++ * Pulls the physical address off the list and calls the migration code. ++ * Will process all the addresses on the list. + */ +-static void +-ia64_mca_cpe_migrate(struct work_struct *unused) ++void ++cpe_process_queue(void) + { + int ret; + u64 paddr; +@@ -192,10 +196,36 @@ ia64_mca_cpe_migrate(struct work_struct + cpe_tail = 0; + + } while (cpe_tail != cpe_head); +- work_scheduled = 0; ++ return; ++} ++ ++inline int ++cpe_list_empty(void) ++{ ++ return (cpe_head == cpe_tail) && (!cpe[cpe_head].paddr); ++} ++ ++/* ++ * kthread_cpe_migrate ++ * kthread_cpe_migrate is created at module load time and lives ++ * until the module is removed. When not active, it will sleep. ++ */ ++static int ++kthread_cpe_migrate(void *ignore) ++{ ++ while (cpe_active) { ++ /* ++ * wait for work ++ */ ++ (void)wait_event_interruptible(cpe_activate_IRQ_wq, ++ (!cpe_list_empty() || ++ !cpe_active)); ++ cpe_process_queue(); /* process work */ ++ } ++ complete(&kthread_cpe_migrated_exited); ++ return 0; + } + +-static DECLARE_WORK(cpe_enable_work, ia64_mca_cpe_migrate); + DEFINE_SPINLOCK(cpe_list_lock); + + /* +@@ -227,10 +257,7 @@ cpe_setup_migrate(void *rec) + if (ret < 0) + return -EINVAL; + +- if ((cpe_head != cpe_tail) || (cpe[cpe_head].paddr != 0)) +- /* +- * List not empty +- */ ++ if (!cpe_list_empty()) + for (i = 0; i < CE_HISTORY_LENGTH; i++) { + if (PAGE_ALIGN(cpe[i].paddr) == PAGE_ALIGN(paddr)) { + mstat_already_on_list++; +@@ -255,10 +282,7 @@ cpe_setup_migrate(void *rec) + } + spin_unlock(&cpe_list_lock); + +- if (!work_scheduled) { +- work_scheduled = 1; +- schedule_work(&cpe_enable_work); +- } ++ wake_up_interruptible(&cpe_activate_IRQ_wq); + + return 1; + } +@@ -395,12 +419,23 @@ static int __init + cpe_migrate_external_handler_init(void) + { + int error; ++ struct task_struct *kthread; + + error = sysfs_create_file(kernel_kobj, &badram_attr.attr); + if (error) + return -EINVAL; + + /* ++ * set up the kthread ++ */ ++ cpe_active = 1; ++ kthread = kthread_run(kthread_cpe_migrate, NULL, "cpe_migrate"); ++ if (IS_ERR(kthread)) { ++ complete(&kthread_cpe_migrated_exited); ++ return -EFAULT; ++ } ++ ++ /* + * register external ce handler + */ + if (ia64_reg_CE_extension(cpe_setup_migrate)) { +@@ -418,6 +453,11 @@ cpe_migrate_external_handler_exit(void) + { + /* unregister external mca handlers */ + ia64_unreg_CE_extension(); ++ ++ /* Stop kthread */ ++ cpe_active = 0; /* tell kthread_cpe_migrate to exit */ ++ wake_up_interruptible(&cpe_activate_IRQ_wq); ++ wait_for_completion(&kthread_cpe_migrated_exited); + + sysfs_remove_file(kernel_kobj, &badram_attr.attr); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-rwlocks-enable-interrupts b/src/patches/suse-2.6.27.31/patches.arch/ia64-rwlocks-enable-interrupts new file mode 100644 index 000000000..1c4385aec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-rwlocks-enable-interrupts @@ -0,0 +1,112 @@ +From: Petr Tesarik +Subject: [ia64] re-enable interrupts when waiting for a rwlock +References: bnc#387784 +Mainline: no + +Re-enable interrupts for _read_lock_irqsave() and _write_lock_irqsave() +while waiting for the lock if interrupts were enabled in the caller. + +Signed-off-by: Petr Tesarik + +--- + arch/ia64/include/asm/spinlock.h | 49 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 43 insertions(+), 6 deletions(-) + +--- linux-2.6.26.orig/arch/ia64/include/asm/spinlock.h 2008-09-26 13:02:50.000000000 +0200 ++++ linux-2.6.26/arch/ia64/include/asm/spinlock.h 2008-09-26 15:54:11.000000000 +0200 +@@ -120,6 +120,35 @@ do { \ + #define __raw_read_can_lock(rw) (*(volatile int *)(rw) >= 0) + #define __raw_write_can_lock(rw) (*(volatile int *)(rw) == 0) + ++#ifdef ASM_SUPPORTED ++#define __raw_read_lock_flags(rw, flags) \ ++do { \ ++ __asm__ __volatile__ ( \ ++ "tbit.nz p6,p0 = %1,%2\n" \ ++ "br.few 3f\n" \ ++ "1:\n" \ ++ "fetchadd4.rel r2 = [%0],-1;;\n" \ ++ "(p6) ssm psr.i\n" \ ++ "2:\n" \ ++ "hint @pause\n" \ ++ "ld4 r2 = [%0];;\n" \ ++ "cmp4.lt p7,p0 = r2,r0\n" \ ++ "(p7) br.cond.spnt.few 2b\n" \ ++ "(p6) rsm psr.i;;\n" \ ++ "3:\n" \ ++ "fetchadd4.acq r2 = [%0],1;;\n" \ ++ "cmp4.lt p7,p0 = r2,r0\n" \ ++ "(p7) br.cond.spnt.few 1b\n" \ ++ :: "r"(rw), "r"(flags), "i"(IA64_PSR_I_BIT) \ ++ : "p6", "p7", "r2", "memory"); \ ++} while(0) ++ ++#define __raw_read_lock(lock) __raw_read_lock_flags(lock, 0) ++ ++#else /* !ASM_SUPPORTED */ ++ ++#define __raw_read_lock_flags(rw, flags) __raw_read_lock(rw) ++ + #define __raw_read_lock(rw) \ + do { \ + raw_rwlock_t *__read_lock_ptr = (rw); \ +@@ -131,6 +160,8 @@ do { \ + } \ + } while (0) + ++#endif /* !ASM_SUPPORTED */ ++ + #define __raw_read_unlock(rw) \ + do { \ + raw_rwlock_t *__read_lock_ptr = (rw); \ +@@ -138,21 +169,28 @@ do { \ + } while (0) + + #ifdef ASM_SUPPORTED +-#define __raw_write_lock(rw) \ ++#define __raw_write_lock_flags(rw, flags) \ + do { \ + __asm__ __volatile__ ( \ + "mov ar.ccv = r0\n" \ ++ "tbit.nz p6,p0 = %1,%2\n" \ + "dep r29 = -1, r0, 31, 1;;\n" \ + "1:\n" \ ++ "(p6) ssm psr.i\n" \ ++ "2:\n" \ + "ld4 r2 = [%0];;\n" \ + "cmp4.eq p0,p7 = r0,r2\n" \ +- "(p7) br.cond.spnt.few 1b \n" \ ++ "(p7) br.cond.spnt.few 2b \n" \ ++ "(p6) rsm psr.i;;\n" \ + "cmpxchg4.acq r2 = [%0], r29, ar.ccv;;\n" \ + "cmp4.eq p0,p7 = r0, r2\n" \ + "(p7) br.cond.spnt.few 1b;;\n" \ +- :: "r"(rw) : "ar.ccv", "p7", "r2", "r29", "memory"); \ ++ :: "r"(rw), "r"(flags), "i"(IA64_PSR_I_BIT) \ ++ : "ar.ccv", "p6", "p7", "r2", "r29", "memory"); \ + } while(0) + ++#define __raw_write_lock(rw) __raw_write_lock_flags(rw, 0) ++ + #define __raw_write_trylock(rw) \ + ({ \ + register long result; \ +@@ -174,6 +212,8 @@ static inline void __raw_write_unlock(ra + + #else /* !ASM_SUPPORTED */ + ++#define __raw_write_lock_flags(l, flags) __raw_write_lock(l) ++ + #define __raw_write_lock(l) \ + ({ \ + __u64 ia64_val, ia64_set_val = ia64_dep_mi(-1, 0, 31, 1); \ +@@ -213,9 +253,6 @@ static inline int __raw_read_trylock(raw + return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word; + } + +-#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) +-#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) +- + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-smp_flush_tlb_mm-IPI-fix b/src/patches/suse-2.6.27.31/patches.arch/ia64-smp_flush_tlb_mm-IPI-fix new file mode 100644 index 000000000..e1f42bb55 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-smp_flush_tlb_mm-IPI-fix @@ -0,0 +1,49 @@ +From: Dimitri Sivanich +Date: Wed, 15 Apr 2009 15:56:25 +0000 (-0500) +Subject: ia64: smp_flush_tlb_mm() should only send IPI's to cpus in cpu_vm_mask +Patch-mainline: 2.6.30-rc3 +Git-commit: edb91dc01a216e84b78721b71a06db1e0db141b7 +References: bnc#497807 + +[IA64] smp_flush_tlb_mm() should only send IPI's to cpus in cpu_vm_mask + +Having flush_tlb_mm->smp_flush_tlb_mm() send an IPI to every cpu +on the system is occasionally triggering spin_lock contention in +generic_smp_call_function_interrupt(). + +Follow x86 arch's lead and only sends IPIs to the cpus in mm->cpu_vm_mask. + +Experiments with this change have shown significant improvement in this +contention issue. + +Signed-off-by: Dimitri Sivanich +Signed-off-by: Tony Luck +Acked-by: Jeff Mahoney +--- + + arch/ia64/kernel/smp.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/arch/ia64/kernel/smp.c ++++ b/arch/ia64/kernel/smp.c +@@ -300,15 +300,12 @@ smp_flush_tlb_mm (struct mm_struct *mm) + return; + } + ++ smp_call_function_mask(mm->cpu_vm_mask, ++ (void (*)(void *))local_finish_flush_tlb_mm, mm, 1); ++ local_irq_disable(); ++ local_finish_flush_tlb_mm(mm); ++ local_irq_enable(); + preempt_enable(); +- /* +- * We could optimize this further by using mm->cpu_vm_mask to track which CPUs +- * have been running in the address space. It's not clear that this is worth the +- * trouble though: to avoid races, we have to raise the IPI on the target CPU +- * anyhow, and once a CPU is interrupted, the cost of local_flush_tlb_all() is +- * rather trivial. +- */ +- on_each_cpu((void (*)(void *))local_finish_flush_tlb_mm, mm, 1); + } + + void arch_send_call_function_single_ipi(int cpu) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-BTE_MAX_XFER b/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-BTE_MAX_XFER new file mode 100644 index 000000000..83aedf1fe --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-BTE_MAX_XFER @@ -0,0 +1,64 @@ +Date: Wed, 4 Feb 2009 10:47:37 -0600 +From: Robin Holt +Subject: bte_copy of BTE_MAX_XFER trips BUG_ON -V2 +References: bnc#472894 + +BTE_MAX_XFER is wrong. It is one greater than the number of cache +lines the BTE is actually able to transfer. If you request a transfer +of exactly BTE_MAX_XFER size, you trip a very cryptic BUG_ON() which +should certainly be made more clear. + +This patch fixes that constant and also cleans up the BUG_ON()s in +arch/ia64/sn/kernel/bte.c to test one condition per line. + +Signed-off-by: Robin Holt +Acked-by: Raymund Will + +--- + +Changes since -V1: + Base the BTE_LEN_MASK upon a 1UL instead of 1 for correctness. + + + arch/ia64/include/asm/sn/bte.h | 4 ++-- + arch/ia64/sn/kernel/bte.c | 7 ++++--- + 2 files changed, 6 insertions(+), 5 deletions(-) + +Index: bte_fixup/arch/ia64/include/asm/sn/bte.h +=================================================================== +--- bte_fixup.orig/arch/ia64/include/asm/sn/bte.h 2009-02-04 10:37:29.594750841 -0600 ++++ bte_fixup/arch/ia64/include/asm/sn/bte.h 2009-02-04 10:40:32.495791608 -0600 +@@ -38,8 +38,8 @@ + + /* BTE status register only supports 16 bits for length field */ + #define BTE_LEN_BITS (16) +-#define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1) +-#define BTE_MAX_XFER ((1 << BTE_LEN_BITS) * L1_CACHE_BYTES) ++#define BTE_LEN_MASK ((1UL << BTE_LEN_BITS) - 1) ++#define BTE_MAX_XFER (BTE_LEN_MASK << L1_CACHE_SHIFT) + + + /* Define hardware */ +Index: bte_fixup/arch/ia64/sn/kernel/bte.c +=================================================================== +--- bte_fixup.orig/arch/ia64/sn/kernel/bte.c 2009-02-04 10:37:30.026753839 -0600 ++++ bte_fixup/arch/ia64/sn/kernel/bte.c 2009-02-04 10:40:11.711701203 -0600 +@@ -97,9 +97,10 @@ bte_result_t bte_copy(u64 src, u64 dest, + return BTE_SUCCESS; + } + +- BUG_ON((len & L1_CACHE_MASK) || +- (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)); +- BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT))); ++ BUG_ON(len & L1_CACHE_MASK); ++ BUG_ON(src & L1_CACHE_MASK); ++ BUG_ON(dest & L1_CACHE_MASK); ++ BUG_ON(len > BTE_MAX_XFER); + + /* + * Start with interface corresponding to cpu number +-- +To unsubscribe from this list: send the line "unsubscribe linux-ia64" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-fix-pci-attribute-propagation-bug.patch b/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-fix-pci-attribute-propagation-bug.patch new file mode 100644 index 000000000..fe211d09c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-fix-pci-attribute-propagation-bug.patch @@ -0,0 +1,72 @@ +From: Jeremy Higdon +Subject: ia64: sn: fix pci attribute propagation bug +Patch-mainline: 2.6.29 +References: bnc#480591 + +Customer backups were no longer able to complete within 24 hours after +upgrading from SLES10 SP1 to SLES10 SP2. Further investigation demonstrated +tape streaming bandwidth reduced when the scsi controller is operating at PCI +66 mhz. Operating both ports simultaneously caused the reduced bandwidth to +reduce in half to each tape drive. If the controller is operating at PCI-X +100mhz, there is no reduction in the tape performance. + +Performance degradation is noticeable with a single tape drive writing highly +compressible data and the controller operating in PCI-66. This only affects +PCI mode, not PCIx. + +kotd SP2 baseline: 4194304000 bytes (4.2 GB) copied, 70.7747 seconds, 59.3 MB/s +kotd SP1 baseline: 4194304000 bytes (4.2 GB) copied, 26.7403 seconds, 157 MB/s + +The culprit patch is: + patches.fixes/fix-ia64-sn-msi-support + +The patch is a backport of the following upstream patch: + + http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=83821d3f558dc651e555d62182ed0c95651f41a6 + +The fact that the patch is sn2 specific, and that the problem shows up only in +PCI mode, would easily explain how the performance regression managed to go +unnoticed for this long. + +The problem is that DMA attributes are not getting set on 64bit DMA addresses +on our PIC ASIC based PCI busses (i.e. O350 and O3000 systems). This only +affects devices running in PCI mode, not PCIx mode. The result is anything +from poor performance to data corruption -- so this is a mustfix type problem. + +This is a _regression_ in SLES10SP2 introduced _accidentally_ by the patch + patches.fixes/fix-ia64-sn-msi-support +That implemented MSI support on IA64 SN2 systems. + +The broken code is located in the changes to the pcibr_dmatrans_direct64() +routine in arch/ia64/sn/pci/pcibr/pcibr_dma.c. + +The bug is also present in upstream code which means that SLES11 too suffers +from the same problem: git commit that introduced the bug is +83821d3f558dc651e555d62182ed0c95651f41a6 + +This patch resolves the problem. + +Signed-off-by: Greg Kroah-Hartman + + +--- + arch/ia64/sn/pci/pcibr/pcibr_dma.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c ++++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c +@@ -135,11 +135,10 @@ pcibr_dmatrans_direct64(struct pcidev_in + if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) + pci_addr = IS_PIC_SOFT(pcibus_info) ? + PHYS_TO_DMA(paddr) : +- PHYS_TO_TIODMA(paddr) | dma_attributes; ++ PHYS_TO_TIODMA(paddr); + else +- pci_addr = IS_PIC_SOFT(pcibus_info) ? +- paddr : +- paddr | dma_attributes; ++ pci_addr = paddr; ++ pci_addr |= dma_attributes; + + /* Handle Bus mode */ + if (IS_PCIX(pcibus_info)) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-specific-version-of-dma_get_required_mask b/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-specific-version-of-dma_get_required_mask new file mode 100644 index 000000000..f329edaa5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ia64-sn-specific-version-of-dma_get_required_mask @@ -0,0 +1,192 @@ +From: John Keller +Date: Mon, 24 Nov 2008 22:47:17 +0000 (-0600) +Subject: [IA64] SN specific version of dma_get_required_mask() +Patch-mainline: 2.6.29-rc2 +Git-commit: 175add1981e53d22caba8f42d5f924a4de507b6c +References: bnc#529369 + +[IA64] SN specific version of dma_get_required_mask() + +Create a platform specific version of dma_get_required_mask() +for ia64 SN Altix. All SN Altix platforms support 64 bit DMA +addressing regardless of the size of system memory. +Create an ia64 machvec for dma_get_required_mask, with the +SN version unconditionally returning DMA_64BIT_MASK. + +Signed-off-by: John Keller +Signed-off-by: Tony Luck +Acked-by: Jeff Mahoney +--- + Documentation/DMA-API.txt | 9 ++++----- + arch/ia64/include/asm/dma-mapping.h | 2 ++ + arch/ia64/include/asm/machvec.h | 7 +++++++ + arch/ia64/include/asm/machvec_init.h | 1 + + arch/ia64/include/asm/machvec_sn2.h | 2 ++ + arch/ia64/pci/pci.c | 27 +++++++++++++++++++++++++++ + arch/ia64/sn/pci/pci_dma.c | 6 ++++++ + 7 files changed, 49 insertions(+), 5 deletions(-) + +--- a/Documentation/DMA-API.txt ++++ b/Documentation/DMA-API.txt +@@ -170,16 +170,15 @@ Returns: 0 if successful and a negative + u64 + dma_get_required_mask(struct device *dev) + +-After setting the mask with dma_set_mask(), this API returns the +-actual mask (within that already set) that the platform actually +-requires to operate efficiently. Usually this means the returned mask ++This API returns the mask that the platform requires to ++operate efficiently. Usually this means the returned mask + is the minimum required to cover all of memory. Examining the + required mask gives drivers with variable descriptor sizes the + opportunity to use smaller descriptors as necessary. + + Requesting the required mask does not alter the current mask. If you +-wish to take advantage of it, you should issue another dma_set_mask() +-call to lower the mask again. ++wish to take advantage of it, you should issue a dma_set_mask() ++call to set the mask to the value returned. + + + Part Id - Streaming DMA mappings +--- a/arch/ia64/include/asm/dma-mapping.h ++++ b/arch/ia64/include/asm/dma-mapping.h +@@ -8,6 +8,8 @@ + #include + #include + ++#define ARCH_HAS_DMA_GET_REQUIRED_MASK ++ + #define dma_alloc_coherent platform_dma_alloc_coherent + /* coherent mem. is cheap */ + static inline void * +--- a/arch/ia64/include/asm/machvec.h ++++ b/arch/ia64/include/asm/machvec.h +@@ -61,6 +61,7 @@ typedef dma_addr_t ia64_mv_dma_map_singl + typedef void ia64_mv_dma_unmap_single_attrs (struct device *, dma_addr_t, size_t, int, struct dma_attrs *); + typedef int ia64_mv_dma_map_sg_attrs (struct device *, struct scatterlist *, int, int, struct dma_attrs *); + typedef void ia64_mv_dma_unmap_sg_attrs (struct device *, struct scatterlist *, int, int, struct dma_attrs *); ++typedef u64 ia64_mv_dma_get_required_mask (struct device *); + + /* + * WARNING: The legacy I/O space is _architected_. Platforms are +@@ -154,6 +155,7 @@ extern void machvec_tlb_migrate_finish ( + # define platform_dma_sync_sg_for_device ia64_mv.dma_sync_sg_for_device + # define platform_dma_mapping_error ia64_mv.dma_mapping_error + # define platform_dma_supported ia64_mv.dma_supported ++# define platform_dma_get_required_mask ia64_mv.dma_get_required_mask + # define platform_irq_to_vector ia64_mv.irq_to_vector + # define platform_local_vector_to_irq ia64_mv.local_vector_to_irq + # define platform_pci_get_legacy_mem ia64_mv.pci_get_legacy_mem +@@ -208,6 +210,7 @@ struct ia64_machine_vector { + ia64_mv_dma_sync_sg_for_device *dma_sync_sg_for_device; + ia64_mv_dma_mapping_error *dma_mapping_error; + ia64_mv_dma_supported *dma_supported; ++ ia64_mv_dma_get_required_mask *dma_get_required_mask; + ia64_mv_irq_to_vector *irq_to_vector; + ia64_mv_local_vector_to_irq *local_vector_to_irq; + ia64_mv_pci_get_legacy_mem_t *pci_get_legacy_mem; +@@ -258,6 +261,7 @@ struct ia64_machine_vector { + platform_dma_sync_sg_for_device, \ + platform_dma_mapping_error, \ + platform_dma_supported, \ ++ platform_dma_get_required_mask, \ + platform_irq_to_vector, \ + platform_local_vector_to_irq, \ + platform_pci_get_legacy_mem, \ +@@ -382,6 +386,9 @@ extern ia64_mv_dma_supported swiotlb_dm + #ifndef platform_dma_supported + # define platform_dma_supported swiotlb_dma_supported + #endif ++#ifndef platform_dma_get_required_mask ++# define platform_dma_get_required_mask ia64_dma_get_required_mask ++#endif + #ifndef platform_irq_to_vector + # define platform_irq_to_vector __ia64_irq_to_vector + #endif +--- a/arch/ia64/include/asm/machvec_init.h ++++ b/arch/ia64/include/asm/machvec_init.h +@@ -2,6 +2,7 @@ + + extern ia64_mv_send_ipi_t ia64_send_ipi; + extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge; ++extern ia64_mv_dma_get_required_mask ia64_dma_get_required_mask; + extern ia64_mv_irq_to_vector __ia64_irq_to_vector; + extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq; + extern ia64_mv_pci_get_legacy_mem_t ia64_pci_get_legacy_mem; +--- a/arch/ia64/include/asm/machvec_sn2.h ++++ b/arch/ia64/include/asm/machvec_sn2.h +@@ -67,6 +67,7 @@ extern ia64_mv_dma_sync_single_for_devic + extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; + extern ia64_mv_dma_mapping_error sn_dma_mapping_error; + extern ia64_mv_dma_supported sn_dma_supported; ++extern ia64_mv_dma_get_required_mask sn_dma_get_required_mask; + extern ia64_mv_migrate_t sn_migrate; + extern ia64_mv_kernel_launch_event_t sn_kernel_launch_event; + extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq; +@@ -123,6 +124,7 @@ extern ia64_mv_pci_fixup_bus_t sn_pci_f + #define platform_dma_sync_sg_for_device sn_dma_sync_sg_for_device + #define platform_dma_mapping_error sn_dma_mapping_error + #define platform_dma_supported sn_dma_supported ++#define platform_dma_get_required_mask sn_dma_get_required_mask + #define platform_migrate sn_migrate + #define platform_kernel_launch_event sn_kernel_launch_event + #ifdef CONFIG_PCI_MSI +--- a/arch/ia64/pci/pci.c ++++ b/arch/ia64/pci/pci.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -743,6 +744,32 @@ static void __init set_pci_cacheline_siz + pci_cache_line_size = (1 << cci.pcci_line_size) / 4; + } + ++u64 ia64_dma_get_required_mask(struct device *dev) ++{ ++ u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); ++ u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); ++ u64 mask; ++ ++ if (!high_totalram) { ++ /* convert to mask just covering totalram */ ++ low_totalram = (1 << (fls(low_totalram) - 1)); ++ low_totalram += low_totalram - 1; ++ mask = low_totalram; ++ } else { ++ high_totalram = (1 << (fls(high_totalram) - 1)); ++ high_totalram += high_totalram - 1; ++ mask = (((u64)high_totalram) << 32) + 0xffffffff; ++ } ++ return mask; ++} ++EXPORT_SYMBOL_GPL(ia64_dma_get_required_mask); ++ ++u64 dma_get_required_mask(struct device *dev) ++{ ++ return platform_dma_get_required_mask(dev); ++} ++EXPORT_SYMBOL_GPL(dma_get_required_mask); ++ + static int __init pcibios_init(void) + { + set_pci_cacheline_size(); +--- a/arch/ia64/sn/pci/pci_dma.c ++++ b/arch/ia64/sn/pci/pci_dma.c +@@ -356,6 +356,12 @@ int sn_dma_mapping_error(struct device * + } + EXPORT_SYMBOL(sn_dma_mapping_error); + ++u64 sn_dma_get_required_mask(struct device *dev) ++{ ++ return DMA_64BIT_MASK; ++} ++EXPORT_SYMBOL_GPL(sn_dma_get_required_mask); ++ + char *sn_pci_get_legacy_mem(struct pci_bus *bus) + { + if (!SN_PCIBUS_BUSSOFT(bus)) diff --git a/src/patches/suse-2.6.27.31/patches.arch/mm-avoid-bad-page-on-lru b/src/patches/suse-2.6.27.31/patches.arch/mm-avoid-bad-page-on-lru new file mode 100644 index 000000000..6cbad12a4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/mm-avoid-bad-page-on-lru @@ -0,0 +1,150 @@ +From: Russ Anderson +Subject: mm: Avoid putting a bad page back on the LRU v8 +References: 415829 +Acked-by: schwab@suse.de + +Prevent a page with a physical memory error from being placed back +on the LRU. A new page flag (PG_memerror) is added if +CONFIG_PAGEFLAGS_EXTENDED is defined. + +Version 8 change: Removed hot path check for pages with memory +errors on the free list. + +Signed-off-by: Russ Anderson +Reviewed-by: Christoph Lameter + +--- + include/linux/page-flags.h | 15 ++++++++++++++- + mm/migrate.c | 36 +++++++++++++++++++++++++++++++++++- + 2 files changed, 49 insertions(+), 2 deletions(-) + +Index: linux/mm/migrate.c +=================================================================== +--- linux.orig/mm/migrate.c 2008-07-29 13:18:23.000000000 -0500 ++++ linux/mm/migrate.c 2008-07-29 13:21:03.000000000 -0500 +@@ -65,6 +65,7 @@ int isolate_lru_page(struct page *page, + } + return ret; + } ++EXPORT_SYMBOL(isolate_lru_page); + + /* + * migrate_prep() needs to be called before we start compiling a list of pages +@@ -82,6 +83,7 @@ int migrate_prep(void) + + return 0; + } ++EXPORT_SYMBOL(migrate_prep); + + static inline void move_to_lru(struct page *page) + { +@@ -116,6 +118,7 @@ int putback_lru_pages(struct list_head * + } + return count; + } ++EXPORT_SYMBOL(putback_lru_pages); + + /* + * Restore a potential migration pte to a working pte entry +@@ -741,7 +744,26 @@ unlock: + * restored. + */ + list_del(&page->lru); +- move_to_lru(page); ++ if (PageMemError(page)) { ++ if (rc == 0) ++ /* ++ * A page with a memory error that has ++ * been migrated will not be moved to ++ * the LRU. ++ */ ++ goto move_newpage; ++ else ++ /* ++ * The page failed to migrate and will not ++ * be added to the bad page list. Clearing ++ * the error bit will allow another attempt ++ * to migrate if it gets another correctable ++ * error. ++ */ ++ ClearPageMemError(page); ++ } ++ ++ move_to_lru(page); + } + + move_newpage: +@@ -813,6 +835,17 @@ int migrate_pages(struct list_head *from + } + } + } ++ ++ if (rc != 0) ++ list_for_each_entry_safe(page, page2, from, lru) ++ if (PageMemError(page)) ++ /* ++ * The page failed to migrate. Clearing ++ * the error bit will allow another attempt ++ * to migrate if it gets another correctable ++ * error. ++ */ ++ ClearPageMemError(page); + rc = 0; + out: + if (!swapwrite) +@@ -825,6 +858,7 @@ out: + + return nr_failed + retry; + } ++EXPORT_SYMBOL(migrate_pages); + + #ifdef CONFIG_NUMA + /* +Index: linux/include/linux/page-flags.h +=================================================================== +--- linux.orig/include/linux/page-flags.h 2008-07-29 13:18:23.000000000 -0500 ++++ linux/include/linux/page-flags.h 2008-07-29 13:21:03.000000000 -0500 +@@ -84,6 +84,7 @@ enum pageflags { + PG_private, /* If pagecache, has fs-private data */ + PG_writeback, /* Page is under writeback */ + #ifdef CONFIG_PAGEFLAGS_EXTENDED ++ PG_memerror, /* Page has a physical memory error */ + PG_head, /* A head page */ + PG_tail, /* A tail page */ + #else +@@ -147,15 +148,21 @@ static inline int TestSetPage##uname(str + static inline int TestClearPage##uname(struct page *page) \ + { return test_and_clear_bit(PG_##lname, &page->flags); } + ++#define PAGEFLAGMASK(uname, lname) \ ++static inline int PAGEMASK_##uname(void) \ ++ { return (1 << PG_##lname); } + + #define PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \ +- SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname) ++ SETPAGEFLAG(uname, lname) CLEARPAGEFLAG(uname, lname) \ ++ PAGEFLAGMASK(uname, lname) + + #define __PAGEFLAG(uname, lname) TESTPAGEFLAG(uname, lname) \ + __SETPAGEFLAG(uname, lname) __CLEARPAGEFLAG(uname, lname) + + #define PAGEFLAG_FALSE(uname) \ + static inline int Page##uname(struct page *page) \ ++ { return 0; } \ ++static inline int PAGEMASK_##uname(void) \ + { return 0; } + + #define TESTSCFLAG(uname, lname) \ +@@ -325,6 +332,12 @@ static inline void __ClearPageTail(struc + } + + #endif /* !PAGEFLAGS_EXTENDED */ ++ ++#ifdef CONFIG_PAGEFLAGS_EXTENDED ++PAGEFLAG(MemError, memerror) ++#else ++PAGEFLAG_FALSE(MemError) ++#endif + + #define PAGE_FLAGS (1 << PG_lru | 1 << PG_private | 1 << PG_locked | \ + 1 << PG_buddy | 1 << PG_writeback | \ diff --git a/src/patches/suse-2.6.27.31/patches.arch/powerpc-pseries-cmo-unused-page-hinting.patch b/src/patches/suse-2.6.27.31/patches.arch/powerpc-pseries-cmo-unused-page-hinting.patch new file mode 100644 index 000000000..6385eba5f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/powerpc-pseries-cmo-unused-page-hinting.patch @@ -0,0 +1,119 @@ +From 14f966e79445015cd89d0fa0ceb6b33702e951b6 Mon Sep 17 00:00:00 2001 +From: Robert Jennings +Date: Wed, 15 Apr 2009 05:55:32 +0000 +Subject: powerpc/pseries: CMO unused page hinting +Patch-mainline: 2.6.31 +References: bnc#495091 + +From: Robert Jennings + +commit 14f966e79445015cd89d0fa0ceb6b33702e951b6 upstream. + +Adds support for the "unused" page hint which can be used in shared +memory partitions to flag pages not in use, which will then be stolen +before active pages by the hypervisor when memory needs to be moved to +LPARs in need of additional memory. Failure to mark pages as 'unused' +makes the LPAR slower to give up unused memory to other partitions. + +This adds the kernel parameter 'cmo_free_hint' to disable this +functionality. + +Signed-off-by: Brian King +Signed-off-by: Robert Jennings +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/kernel-parameters.txt | 7 ++++ + arch/powerpc/include/asm/page.h | 5 +++ + arch/powerpc/platforms/pseries/lpar.c | 52 ++++++++++++++++++++++++++++++++++ + 3 files changed, 64 insertions(+) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -458,6 +458,13 @@ and is between 256 and 4096 characters. + Also note the kernel might malfunction if you disable + some critical bits. + ++ cmo_free_hint= [PPC] Format: { yes | no } ++ Specify whether pages are marked as being inactive ++ when they are freed. This is used in CMO environments ++ to determine OS memory pressure for page stealing by ++ a hypervisor. ++ Default: yes ++ + code_bytes [IA32/X86_64] How many bytes of object code to print + in an oops report. + Range: 0 - 8192 +--- a/arch/powerpc/include/asm/page.h ++++ b/arch/powerpc/include/asm/page.h +@@ -215,6 +215,11 @@ extern void copy_user_page(void *to, voi + struct page *p); + extern int page_is_ram(unsigned long pfn); + ++#ifdef CONFIG_PPC_SMLPAR ++void arch_free_page(struct page *page, int order); ++#define HAVE_ARCH_FREE_PAGE ++#endif ++ + struct vm_area_struct; + + typedef struct page *pgtable_t; +--- a/arch/powerpc/platforms/pseries/lpar.c ++++ b/arch/powerpc/platforms/pseries/lpar.c +@@ -609,3 +609,55 @@ void __init hpte_init_lpar(void) + ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; + ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; + } ++ ++#ifdef CONFIG_PPC_SMLPAR ++#define CMO_FREE_HINT_DEFAULT 1 ++static int cmo_free_hint_flag = CMO_FREE_HINT_DEFAULT; ++ ++static int __init cmo_free_hint(char *str) ++{ ++ char *parm; ++ parm = strstrip(str); ++ ++ if (strcasecmp(parm, "no") == 0 || strcasecmp(parm, "off") == 0) { ++ printk(KERN_INFO "cmo_free_hint: CMO free page hinting is not active.\n"); ++ cmo_free_hint_flag = 0; ++ return 1; ++ } ++ ++ cmo_free_hint_flag = 1; ++ printk(KERN_INFO "cmo_free_hint: CMO free page hinting is active.\n"); ++ ++ if (strcasecmp(parm, "yes") == 0 || strcasecmp(parm, "on") == 0) ++ return 1; ++ ++ return 0; ++} ++ ++__setup("cmo_free_hint=", cmo_free_hint); ++ ++static void pSeries_set_page_state(struct page *page, int order, ++ unsigned long state) ++{ ++ int i, j; ++ unsigned long cmo_page_sz, addr; ++ ++ cmo_page_sz = cmo_get_page_size(); ++ addr = __pa((unsigned long)page_address(page)); ++ ++ for (i = 0; i < (1 << order); i++, addr += PAGE_SIZE) { ++ for (j = 0; j < PAGE_SIZE; j += cmo_page_sz) ++ plpar_hcall_norets(H_PAGE_INIT, state, addr + j, 0); ++ } ++} ++ ++void arch_free_page(struct page *page, int order) ++{ ++ if (!cmo_free_hint_flag || !firmware_has_feature(FW_FEATURE_CMO)) ++ return; ++ ++ pSeries_set_page_state(page, order, H_PAGE_SET_UNUSED); ++} ++EXPORT_SYMBOL(arch_free_page); ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-altivec-VSX-ctxswitch b/src/patches/suse-2.6.27.31/patches.arch/ppc-altivec-VSX-ctxswitch new file mode 100644 index 000000000..982c098ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-altivec-VSX-ctxswitch @@ -0,0 +1,68 @@ +From: Michael Neuling +Subject: change giveup_fpu/altivec to disable VSX for current +Patch-mainline: 2.6.30 +References: bnc#492324 + +[PATCH] powerpc: change giveup_fpu/altivec to disable VSX for current + +When we call giveup_fpu, we need to need to turn off VSX in current. +If we don't, on return to current it may execute a VSX instruction +(before the next FP), and not have it's register state refreshed +correctly from the thread_struct. Ditto for altivec. + +This caused a bug where an unaligned lfs or stfs (which calls +giveup_fpu so it can use the FPRs) to return to userspace with FP off +but VSX on. Then if a VSX instruction is executed, before another FP +instruction, it will proceed without another exception and hence have +the incorrect register state for VSX registers 0-31. + + lfs unaligned <- alignment exception turns FP off but leaves VSX on + + VSX instruction <- no exception since VSX on, hence we get the + wrong VSX register values for VSX registers 0-31 + (overlapping the FPRs) + +Signed-off-by: Michael Neuling +Acked-by: duwe@suse.de + +--- + arch/powerpc/kernel/fpu.S | 5 +++++ + arch/powerpc/kernel/misc_64.S | 8 ++++++++ + 2 files changed, 13 insertions(+) + +Index: clone3/arch/powerpc/kernel/fpu.S +=================================================================== +--- clone3.orig/arch/powerpc/kernel/fpu.S ++++ clone3/arch/powerpc/kernel/fpu.S +@@ -145,6 +145,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) + beq 1f + PPC_LL r4,_MSR-STACK_FRAME_OVERHEAD(r5) + li r3,MSR_FP|MSR_FE0|MSR_FE1 ++#ifdef CONFIG_VSX ++BEGIN_FTR_SECTION ++ oris r3,r3,MSR_VSX@h ++END_FTR_SECTION_IFSET(CPU_FTR_VSX) ++#endif + andc r4,r4,r3 /* disable FP for previous task */ + PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5) + 1: +Index: clone3/arch/powerpc/kernel/misc_64.S +=================================================================== +--- clone3.orig/arch/powerpc/kernel/misc_64.S ++++ clone3/arch/powerpc/kernel/misc_64.S +@@ -493,7 +493,15 @@ _GLOBAL(giveup_altivec) + stvx vr0,r4,r3 + beq 1f + ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) ++#ifdef CONFIG_VSX ++BEGIN_FTR_SECTION ++ lis r3,(MSR_VEC|MSR_VSX)@h ++FTR_SECTION_ELSE ++ lis r3,MSR_VEC@h ++ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX) ++#else + lis r3,MSR_VEC@h ++#endif + andc r4,r4,r3 /* disable FP for previous task */ + std r4,_MSR-STACK_FRAME_OVERHEAD(r5) + 1: diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-cell-gdb-watchpoints.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-cell-gdb-watchpoints.patch new file mode 100644 index 000000000..ff511ffe9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-cell-gdb-watchpoints.patch @@ -0,0 +1,50 @@ +Subject: Fix GDB watchpoints on Cell +From: Arnd Bergmann +References: 456405 - LTC50396 + +An earlier patch from Jens Osterkamp attempted to fix GDB +watchpoints by enabling the DABRX register at boot time. +Unfortunately, this did not work on SMP setups, where +secondary CPUs were still using the power-on DABRX value. + +This introduces the same change for secondary CPUs on cell +as well. + +Reported-by: Ulrich Weigand +Tested-by: Ulrich Weigand +Signed-off-by: Arnd Bergmann +Signed-off-by: Paul Mackerras +Signed-off-by: Olaf Hering + +--- + arch/powerpc/platforms/cell/smp.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/platforms/cell/smp.c ++++ b/arch/powerpc/platforms/cell/smp.c +@@ -129,10 +129,15 @@ static int __init smp_iic_probe(void) + return cpus_weight(cpu_possible_map); + } + +-static void __devinit smp_iic_setup_cpu(int cpu) ++static void __devinit smp_cell_setup_cpu(int cpu) + { + if (cpu != boot_cpuid) + iic_setup_cpu(); ++ ++ /* ++ * change default DABRX to allow user watchpoints ++ */ ++ mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER); + } + + static DEFINE_SPINLOCK(timebase_lock); +@@ -192,7 +197,7 @@ static struct smp_ops_t bpa_iic_smp_ops + .message_pass = smp_iic_message_pass, + .probe = smp_iic_probe, + .kick_cpu = smp_cell_kick_cpu, +- .setup_cpu = smp_iic_setup_cpu, ++ .setup_cpu = smp_cell_setup_cpu, + .cpu_bootable = smp_cell_cpu_bootable, + }; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-clock_gettime-nanoseconds.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-clock_gettime-nanoseconds.patch new file mode 100644 index 000000000..37425133e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-clock_gettime-nanoseconds.patch @@ -0,0 +1,513 @@ +From: Tony Breeds +Subject: [PATCH] powerpc: Improve resolution of VDSO clock_gettime +References: 439908 - LTC49499 + +Currently the clock_gettime implementation in the VDSO produces a +result with microsecond resolution for the cases that are handled +without a system call, i.e. CLOCK_REALTIME and CLOCK_MONOTONIC. The +nanoseconds field of the result is obtained by computing a +microseconds value and multiplying by 1000. + +This changes the code in the VDSO to do the computation for +clock_gettime with nanosecond resolution. That means that the +resolution of the result will ultimately depend on the timebase +frequency. + +Because the timestamp in the VDSO datapage (stamp_xsec, the real time +corresponding to the timebase count in tb_orig_stamp) is in units of +2^-20 seconds, it doesn't have sufficient resolution for computing a +result with nanosecond resolution. Therefore this adds a copy of +xtime to the VDSO datapage and updates it in update_gtod() along with +the other time-related fields. + +Signed-off-by: Paul Mackerras +Signed-off-by: Tony Breeds +Signed-off-by: Olaf Hering +--- + arch/powerpc/include/asm/vdso_datapage.h | 3 + arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/time.c | 1 + arch/powerpc/kernel/vdso32/gettimeofday.S | 196 ++++++++++++++++++------------ + arch/powerpc/kernel/vdso64/gettimeofday.S | 143 +++++++++++---------- + 5 files changed, 205 insertions(+), 139 deletions(-) + +--- a/arch/powerpc/include/asm/vdso_datapage.h ++++ b/arch/powerpc/include/asm/vdso_datapage.h +@@ -39,6 +39,7 @@ + #ifndef __ASSEMBLY__ + + #include ++#include + + #define SYSCALL_MAP_SIZE ((__NR_syscalls + 31) / 32) + +@@ -83,6 +84,7 @@ struct vdso_data { + __u32 icache_log_block_size; /* L1 i-cache log block size */ + __s32 wtom_clock_sec; /* Wall to monotonic clock */ + __s32 wtom_clock_nsec; ++ struct timespec stamp_xtime; /* xtime value for tb_orig_stamp */ + __u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */ + __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ + }; +@@ -102,6 +104,7 @@ struct vdso_data { + __u32 tz_dsttime; /* Type of dst correction 0x5C */ + __s32 wtom_clock_sec; /* Wall to monotonic clock */ + __s32 wtom_clock_nsec; ++ struct timespec stamp_xtime; /* xtime value for tb_orig_stamp */ + __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ + __u32 dcache_block_size; /* L1 d-cache block size */ + __u32 icache_block_size; /* L1 i-cache block size */ +--- a/arch/powerpc/kernel/asm-offsets.c ++++ b/arch/powerpc/kernel/asm-offsets.c +@@ -304,6 +304,7 @@ int main(void) + DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32)); + DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec)); + DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); ++ DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime)); + DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size)); + DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size)); + DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size)); +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -456,6 +456,7 @@ static inline void update_gtod(u64 new_t + vdso_data->tb_to_xs = new_tb_to_xs; + vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; + vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; ++ vdso_data->stamp_xtime = xtime; + smp_wmb(); + ++(vdso_data->tb_update_count); + } +--- a/arch/powerpc/kernel/vdso32/gettimeofday.S ++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S +@@ -16,6 +16,13 @@ + #include + #include + ++/* Offset for the low 32-bit part of a field of long type */ ++#ifdef CONFIG_PPC64 ++#define LOPART 4 ++#else ++#define LOPART 0 ++#endif ++ + .text + /* + * Exact prototype of gettimeofday +@@ -90,101 +97,53 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) + + mflr r12 /* r12 saves lr */ + .cfi_register lr,r12 +- mr r10,r3 /* r10 saves id */ + mr r11,r4 /* r11 saves tp */ + bl __get_datapage@local /* get data page */ + mr r9,r3 /* datapage ptr in r9 */ +- beq cr1,50f /* if monotonic -> jump there */ +- +- /* +- * CLOCK_REALTIME +- */ +- +- bl __do_get_xsec@local /* get xsec from tb & kernel */ +- bne- 98f /* out of line -> do syscall */ +- +- /* seconds are xsec >> 20 */ +- rlwinm r5,r4,12,20,31 +- rlwimi r5,r3,12,0,19 +- stw r5,TSPC32_TV_SEC(r11) + +- /* get remaining xsec and convert to nsec. we scale +- * up remaining xsec by 12 bits and get the top 32 bits +- * of the multiplication, then we multiply by 1000 +- */ +- rlwinm r5,r4,12,0,19 +- lis r6,1000000@h +- ori r6,r6,1000000@l +- mulhwu r5,r5,r6 +- mulli r5,r5,1000 +- stw r5,TSPC32_TV_NSEC(r11) +- mtlr r12 +- crclr cr0*4+so +- li r3,0 +- blr ++50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ ++ bne cr1,80f /* not monotonic -> all done */ + + /* + * CLOCK_MONOTONIC + */ + +-50: bl __do_get_xsec@local /* get xsec from tb & kernel */ +- bne- 98f /* out of line -> do syscall */ +- +- /* seconds are xsec >> 20 */ +- rlwinm r6,r4,12,20,31 +- rlwimi r6,r3,12,0,19 +- +- /* get remaining xsec and convert to nsec. we scale +- * up remaining xsec by 12 bits and get the top 32 bits +- * of the multiplication, then we multiply by 1000 +- */ +- rlwinm r7,r4,12,0,19 +- lis r5,1000000@h +- ori r5,r5,1000000@l +- mulhwu r7,r7,r5 +- mulli r7,r7,1000 +- + /* now we must fixup using wall to monotonic. We need to snapshot + * that value and do the counter trick again. Fortunately, we still + * have the counter value in r8 that was returned by __do_get_xsec. +- * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5 +- * can be used ++ * At this point, r3,r4 contain our sec/nsec values, r5 and r6 ++ * can be used, r7 contains NSEC_PER_SEC. + */ + +- lwz r3,WTOM_CLOCK_SEC(r9) +- lwz r4,WTOM_CLOCK_NSEC(r9) ++ lwz r5,WTOM_CLOCK_SEC(r9) ++ lwz r6,WTOM_CLOCK_NSEC(r9) + +- /* We now have our result in r3,r4. We create a fake dependency +- * on that result and re-check the counter ++ /* We now have our offset in r5,r6. We create a fake dependency ++ * on that value and re-check the counter + */ +- or r5,r4,r3 +- xor r0,r5,r5 ++ or r0,r6,r5 ++ xor r0,r0,r0 + add r9,r9,r0 +-#ifdef CONFIG_PPC64 +- lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9) +-#else +- lwz r0,(CFG_TB_UPDATE_COUNT)(r9) +-#endif ++ lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) + cmpl cr0,r8,r0 /* check if updated */ + bne- 50b + +- /* Calculate and store result. Note that this mimmics the C code, ++ /* Calculate and store result. Note that this mimics the C code, + * which may cause funny results if nsec goes negative... is that + * possible at all ? + */ +- add r3,r3,r6 +- add r4,r4,r7 +- lis r5,NSEC_PER_SEC@h +- ori r5,r5,NSEC_PER_SEC@l +- cmpl cr0,r4,r5 +- cmpli cr1,r4,0 ++ add r3,r3,r5 ++ add r4,r4,r6 ++ cmpw cr0,r4,r7 ++ cmpwi cr1,r4,0 + blt 1f +- subf r4,r5,r4 ++ subf r4,r7,r4 + addi r3,r3,1 +-1: bge cr1,1f ++1: bge cr1,80f + addi r3,r3,-1 +- add r4,r4,r5 +-1: stw r3,TSPC32_TV_SEC(r11) ++ add r4,r4,r7 ++ ++80: stw r3,TSPC32_TV_SEC(r11) + stw r4,TSPC32_TV_NSEC(r11) + + mtlr r12 +@@ -195,10 +154,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) + /* + * syscall fallback + */ +-98: +- mtlr r12 +- mr r3,r10 +- mr r4,r11 + 99: + li r0,__NR_clock_gettime + sc +@@ -322,3 +277,98 @@ __do_get_xsec: + */ + 3: blr + .cfi_endproc ++ ++/* ++ * This is the core of clock_gettime(), it returns the current ++ * time in seconds and nanoseconds in r3 and r4. ++ * It expects the datapage ptr in r9 and doesn't clobber it. ++ * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7. ++ * On return, r8 contains the counter value that can be reused. ++ * This clobbers cr0 but not any other cr field. ++ */ ++__do_get_tspec: ++ .cfi_startproc ++ /* Check for update count & load values. We use the low ++ * order 32 bits of the update count ++ */ ++1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) ++ andi. r0,r8,1 /* pending update ? loop */ ++ bne- 1b ++ xor r0,r8,r8 /* create dependency */ ++ add r9,r9,r0 ++ ++ /* Load orig stamp (offset to TB) */ ++ lwz r5,CFG_TB_ORIG_STAMP(r9) ++ lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) ++ ++ /* Get a stable TB value */ ++2: mftbu r3 ++ mftbl r4 ++ mftbu r0 ++ cmpl cr0,r3,r0 ++ bne- 2b ++ ++ /* Subtract tb orig stamp and shift left 12 bits. ++ */ ++ subfc r7,r6,r4 ++ subfe r0,r5,r3 ++ slwi r0,r0,12 ++ rlwimi. r0,r7,12,20,31 ++ slwi r7,r7,12 ++ ++ /* Load scale factor & do multiplication */ ++ lwz r5,CFG_TB_TO_XS(r9) /* load values */ ++ lwz r6,(CFG_TB_TO_XS+4)(r9) ++ mulhwu r3,r7,r6 ++ mullw r10,r7,r5 ++ mulhwu r4,r7,r5 ++ addc r10,r3,r10 ++ li r3,0 ++ ++ beq+ 4f /* skip high part computation if 0 */ ++ mulhwu r3,r0,r5 ++ mullw r7,r0,r5 ++ mulhwu r5,r0,r6 ++ mullw r6,r0,r6 ++ adde r4,r4,r7 ++ addze r3,r3 ++ addc r4,r4,r5 ++ addze r3,r3 ++ addc r10,r10,r6 ++ ++4: addze r4,r4 /* add in carry */ ++ lis r7,NSEC_PER_SEC@h ++ ori r7,r7,NSEC_PER_SEC@l ++ mulhwu r4,r4,r7 /* convert to nanoseconds */ ++ ++ /* At this point, we have seconds & nanoseconds since the xtime ++ * stamp in r3+CA and r4. Load & add the xtime stamp. ++ */ ++#ifdef CONFIG_PPC64 ++ lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9) ++ lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9) ++#else ++ lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9) ++ lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9) ++#endif ++ add r4,r4,r6 ++ adde r3,r3,r5 ++ ++ /* We now have our result in r3,r4. We create a fake dependency ++ * on that result and re-check the counter ++ */ ++ or r6,r4,r3 ++ xor r0,r6,r6 ++ add r9,r9,r0 ++ lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) ++ cmpl cr0,r8,r0 /* check if updated */ ++ bne- 1b ++ ++ /* check for nanosecond overflow and adjust if necessary */ ++ cmpw r4,r7 ++ bltlr /* all done if no overflow */ ++ subf r4,r7,r4 /* adjust if overflow */ ++ addi r3,r3,1 ++ ++ blr ++ .cfi_endproc +--- a/arch/powerpc/kernel/vdso64/gettimeofday.S ++++ b/arch/powerpc/kernel/vdso64/gettimeofday.S +@@ -75,90 +75,49 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) + + mflr r12 /* r12 saves lr */ + .cfi_register lr,r12 +- mr r10,r3 /* r10 saves id */ + mr r11,r4 /* r11 saves tp */ + bl V_LOCAL_FUNC(__get_datapage) /* get data page */ +- beq cr1,50f /* if monotonic -> jump there */ +- +- /* +- * CLOCK_REALTIME +- */ +- +- bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ +- +- lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ +- ori r7,r7,16960 +- rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ +- rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ +- std r5,TSPC64_TV_SEC(r11) /* store sec in tv */ +- subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ +- mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / +- * XSEC_PER_SEC +- */ +- rldicl r0,r0,44,20 +- mulli r0,r0,1000 /* nsec = usec * 1000 */ +- std r0,TSPC64_TV_NSEC(r11) /* store nsec in tp */ +- +- mtlr r12 +- crclr cr0*4+so +- li r3,0 +- blr ++50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */ ++ bne cr1,80f /* if not monotonic, all done */ + + /* + * CLOCK_MONOTONIC + */ + +-50: bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ +- +- lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ +- ori r7,r7,16960 +- rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ +- rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ +- subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ +- mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / +- * XSEC_PER_SEC +- */ +- rldicl r6,r0,44,20 +- mulli r6,r6,1000 /* nsec = usec * 1000 */ +- + /* now we must fixup using wall to monotonic. We need to snapshot + * that value and do the counter trick again. Fortunately, we still +- * have the counter value in r8 that was returned by __do_get_xsec. +- * At this point, r5,r6 contain our sec/nsec values. +- * can be used ++ * have the counter value in r8 that was returned by __do_get_tspec. ++ * At this point, r4,r5 contain our sec/nsec values. + */ + +- lwa r4,WTOM_CLOCK_SEC(r3) +- lwa r7,WTOM_CLOCK_NSEC(r3) ++ lwa r6,WTOM_CLOCK_SEC(r3) ++ lwa r9,WTOM_CLOCK_NSEC(r3) + +- /* We now have our result in r4,r7. We create a fake dependency ++ /* We now have our result in r6,r9. We create a fake dependency + * on that result and re-check the counter + */ +- or r9,r4,r7 +- xor r0,r9,r9 ++ or r0,r6,r9 ++ xor r0,r0,r0 + add r3,r3,r0 + ld r0,CFG_TB_UPDATE_COUNT(r3) + cmpld cr0,r0,r8 /* check if updated */ + bne- 50b + +- /* Calculate and store result. Note that this mimmics the C code, +- * which may cause funny results if nsec goes negative... is that +- * possible at all ? +- */ +- add r4,r4,r5 +- add r7,r7,r6 +- lis r9,NSEC_PER_SEC@h +- ori r9,r9,NSEC_PER_SEC@l +- cmpl cr0,r7,r9 +- cmpli cr1,r7,0 ++ /* Add wall->monotonic offset and check for overflow or underflow. ++ */ ++ add r4,r4,r6 ++ add r5,r5,r9 ++ cmpd cr0,r5,r7 ++ cmpdi cr1,r5,0 + blt 1f +- subf r7,r9,r7 ++ subf r5,r7,r5 + addi r4,r4,1 +-1: bge cr1,1f ++1: bge cr1,80f + addi r4,r4,-1 +- add r7,r7,r9 +-1: std r4,TSPC64_TV_SEC(r11) +- std r7,TSPC64_TV_NSEC(r11) ++ add r5,r5,r7 ++ ++80: std r4,TSPC64_TV_SEC(r11) ++ std r5,TSPC64_TV_NSEC(r11) + + mtlr r12 + crclr cr0*4+so +@@ -168,10 +127,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) + /* + * syscall fallback + */ +-98: +- mtlr r12 +- mr r3,r10 +- mr r4,r11 + 99: + li r0,__NR_clock_gettime + sc +@@ -253,3 +208,59 @@ V_FUNCTION_BEGIN(__do_get_xsec) + blr + .cfi_endproc + V_FUNCTION_END(__do_get_xsec) ++ ++/* ++ * This is the core of clock_gettime(), it returns the current ++ * time in seconds and nanoseconds in r4 and r5. ++ * It expects the datapage ptr in r3 and doesn't clobber it. ++ * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7. ++ * On return, r8 contains the counter value that can be reused. ++ * This clobbers cr0 but not any other cr field. ++ */ ++V_FUNCTION_BEGIN(__do_get_tspec) ++ .cfi_startproc ++ /* check for update count & load values */ ++1: ld r8,CFG_TB_UPDATE_COUNT(r3) ++ andi. r0,r8,1 /* pending update ? loop */ ++ bne- 1b ++ xor r0,r8,r8 /* create dependency */ ++ add r3,r3,r0 ++ ++ /* Get TB & offset it. We use the MFTB macro which will generate ++ * workaround code for Cell. ++ */ ++ MFTB(r7) ++ ld r9,CFG_TB_ORIG_STAMP(r3) ++ subf r7,r9,r7 ++ ++ /* Scale result */ ++ ld r5,CFG_TB_TO_XS(r3) ++ sldi r7,r7,12 /* compute time since stamp_xtime */ ++ mulhdu r6,r7,r5 /* in units of 2^-32 seconds */ ++ ++ /* Add stamp since epoch */ ++ ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3) ++ ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3) ++ or r0,r4,r5 ++ or r0,r0,r6 ++ xor r0,r0,r0 ++ add r3,r3,r0 ++ ld r0,CFG_TB_UPDATE_COUNT(r3) ++ cmpld r0,r8 /* check if updated */ ++ bne- 1b /* reload if so */ ++ ++ /* convert to seconds & nanoseconds and add to stamp */ ++ lis r7,NSEC_PER_SEC@h ++ ori r7,r7,NSEC_PER_SEC@l ++ mulhwu r0,r6,r7 /* compute nanoseconds and */ ++ srdi r6,r6,32 /* seconds since stamp_xtime */ ++ clrldi r0,r0,32 ++ add r5,r5,r0 /* add nanoseconds together */ ++ cmpd r5,r7 /* overflow? */ ++ add r4,r4,r6 ++ bltlr /* all done if no overflow */ ++ subf r5,r7,r5 /* if overflow, adjust */ ++ addi r4,r4,1 ++ blr ++ .cfi_endproc ++V_FUNCTION_END(__do_get_tspec) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-bestcomm-ata-dma.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-bestcomm-ata-dma.patch new file mode 100644 index 000000000..65b00456a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-bestcomm-ata-dma.patch @@ -0,0 +1,755 @@ +Subject: Efika ATA DMA +From: Matt Sealey +References: 445856 + +Enables UDMA operation for ATA disks on Efika, meaning faster (up to +~33MB/s, from ~1.2MB/s) access and lower (5-10% from 40-80%) CPU usage. + +Signed-off-by: Olaf Hering + +--- + arch/powerpc/sysdev/bestcomm/ata.c | 3 + arch/powerpc/sysdev/bestcomm/ata.h | 2 + arch/powerpc/sysdev/bestcomm/bestcomm.c | 7 + arch/powerpc/sysdev/bestcomm/bestcomm.h | 33 +- + arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | 20 + + drivers/ata/pata_mpc52xx.c | 440 +++++++++++++++++++++++++-- + 6 files changed, 473 insertions(+), 32 deletions(-) + +--- a/arch/powerpc/sysdev/bestcomm/ata.c ++++ b/arch/powerpc/sysdev/bestcomm/ata.c +@@ -61,6 +61,9 @@ bcom_ata_init(int queue_len, int maxbufs + struct bcom_ata_var *var; + struct bcom_ata_inc *inc; + ++ /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ ++ bcom_disable_prefetch(); ++ + tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); + if (!tsk) + return NULL; +--- a/arch/powerpc/sysdev/bestcomm/ata.h ++++ b/arch/powerpc/sysdev/bestcomm/ata.h +@@ -16,8 +16,8 @@ + + struct bcom_ata_bd { + u32 status; +- u32 dst_pa; + u32 src_pa; ++ u32 dst_pa; + }; + + extern struct bcom_task * +--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c ++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c +@@ -279,7 +279,6 @@ bcom_engine_init(void) + int task; + phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; + unsigned int tdt_size, ctx_size, var_size, fdt_size; +- u16 regval; + + /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ + tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); +@@ -331,10 +330,8 @@ bcom_engine_init(void) + out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); + + /* Disable COMM Bus Prefetch on the original 5200; it's broken */ +- if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) { +- regval = in_be16(&bcom_eng->regs->PtdCntrl); +- out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); +- } ++ if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) ++ bcom_disable_prefetch(); + + /* Init lock */ + spin_lock_init(&bcom_eng->lock); +--- a/arch/powerpc/sysdev/bestcomm/bestcomm.h ++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h +@@ -140,15 +140,29 @@ bcom_queue_full(struct bcom_task *tsk) + } + + /** ++ * bcom_get_bd - Get a BD from the queue ++ * @tsk: The BestComm task structure ++ * index: Index of the BD to fetch ++ */ ++static inline struct bcom_bd ++*bcom_get_bd(struct bcom_task *tsk, unsigned int index) ++{ ++ return tsk->bd + index * tsk->bd_size; ++} ++ ++/** + * bcom_buffer_done - Checks if a BestComm + * @tsk: The BestComm task structure + */ + static inline int + bcom_buffer_done(struct bcom_task *tsk) + { ++ struct bcom_bd *bd; + if (bcom_queue_empty(tsk)) + return 0; +- return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); ++ ++ bd = bcom_get_bd(tsk, tsk->outdex); ++ return !(bd->status & BCOM_BD_READY); + } + + /** +@@ -160,16 +174,21 @@ bcom_buffer_done(struct bcom_task *tsk) + static inline struct bcom_bd * + bcom_prepare_next_buffer(struct bcom_task *tsk) + { +- tsk->bd[tsk->index].status = 0; /* cleanup last status */ +- return &tsk->bd[tsk->index]; ++ struct bcom_bd *bd; ++ ++ bd = bcom_get_bd(tsk, tsk->index); ++ bd->status = 0; /* cleanup last status */ ++ return bd; + } + + static inline void + bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) + { ++ struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index); ++ + tsk->cookie[tsk->index] = cookie; + mb(); /* ensure the bd is really up-to-date */ +- tsk->bd[tsk->index].status |= BCOM_BD_READY; ++ bd->status |= BCOM_BD_READY; + tsk->index = _bcom_next_index(tsk); + if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) + bcom_enable(tsk); +@@ -179,10 +198,12 @@ static inline void * + bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) + { + void *cookie = tsk->cookie[tsk->outdex]; ++ struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex); ++ + if (p_status) +- *p_status = tsk->bd[tsk->outdex].status; ++ *p_status = bd->status; + if (p_bd) +- *p_bd = &tsk->bd[tsk->outdex]; ++ *p_bd = bd; + tsk->outdex = _bcom_next_outdex(tsk); + return cookie; + } +--- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h ++++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h +@@ -198,8 +198,8 @@ struct bcom_task_header { + #define BCOM_IPR_SCTMR_1 2 + #define BCOM_IPR_FEC_RX 6 + #define BCOM_IPR_FEC_TX 5 +-#define BCOM_IPR_ATA_RX 4 +-#define BCOM_IPR_ATA_TX 3 ++#define BCOM_IPR_ATA_RX 7 ++#define BCOM_IPR_ATA_TX 7 + #define BCOM_IPR_SCPCI_RX 2 + #define BCOM_IPR_SCPCI_TX 2 + #define BCOM_IPR_PSC3_RX 2 +@@ -241,6 +241,22 @@ extern void bcom_set_initiator(int task, + + #define TASK_ENABLE 0x8000 + ++/** ++ * bcom_disable_prefetch - Hook to disable bus prefetching ++ * ++ * ATA DMA and the original MPC5200 need this due to silicon bugs. At the ++ * moment disabling prefetch is a one-way street. There is no mechanism ++ * in place to turn prefetch back on after it has been disabled. There is ++ * no reason it couldn't be done, it would just be more complex to implement. ++ */ ++static inline void bcom_disable_prefetch(void) ++{ ++ u16 regval; ++ ++ regval = in_be16(&bcom_eng->regs->PtdCntrl); ++ out_be16(&bcom_eng->regs->PtdCntrl, regval | 1); ++}; ++ + static inline void + bcom_enable_task(int task) + { +--- a/drivers/ata/pata_mpc52xx.c ++++ b/drivers/ata/pata_mpc52xx.c +@@ -6,6 +6,9 @@ + * Copyright (C) 2006 Sylvain Munaut + * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt + * ++ * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby), ++ * Domen Puncer and Tim Yamin. ++ * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. +@@ -18,27 +21,46 @@ + #include + #include + ++#include + #include + #include + #include + ++#include ++#include ++#include + + #define DRV_NAME "mpc52xx_ata" + #define DRV_VERSION "0.1.2" + +- + /* Private structures used by the driver */ + struct mpc52xx_ata_timings { + u32 pio1; + u32 pio2; ++ u32 mdma1; ++ u32 mdma2; ++ u32 udma1; ++ u32 udma2; ++ u32 udma3; ++ u32 udma4; ++ u32 udma5; ++ int using_udma; + }; + + struct mpc52xx_ata_priv { + unsigned int ipb_period; + struct mpc52xx_ata __iomem * ata_regs; ++ phys_addr_t ata_regs_pa; + int ata_irq; + struct mpc52xx_ata_timings timings[2]; + int csel; ++ ++ /* DMA */ ++ struct bcom_task *dmatsk; ++ const struct udmaspec *udmaspec; ++ const struct mdmaspec *mdmaspec; ++ int mpc52xx_ata_dma_last_write; ++ int waiting_for_dma; + }; + + +@@ -53,6 +75,107 @@ static const int ataspec_ta[5] = { 35 + + #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) + ++/* ======================================================================== */ ++ ++/* ATAPI-4 MDMA specs (in clocks) */ ++struct mdmaspec { ++ u32 t0M; ++ u32 td; ++ u32 th; ++ u32 tj; ++ u32 tkw; ++ u32 tm; ++ u32 tn; ++}; ++ ++static const struct mdmaspec mdmaspec66[3] = { ++ { .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 }, ++ { .t0M = 10, .td = 6, .th = 1, .tj = 1, .tkw = 4, .tm = 2, .tn = 1 }, ++ { .t0M = 8, .td = 5, .th = 1, .tj = 1, .tkw = 2, .tm = 2, .tn = 1 }, ++}; ++ ++static const struct mdmaspec mdmaspec132[3] = { ++ { .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 }, ++ { .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7, .tm = 4, .tn = 1 }, ++ { .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4, .tm = 4, .tn = 1 }, ++}; ++ ++/* ATAPI-4 UDMA specs (in clocks) */ ++struct udmaspec { ++ u32 tcyc; ++ u32 t2cyc; ++ u32 tds; ++ u32 tdh; ++ u32 tdvs; ++ u32 tdvh; ++ u32 tfs; ++ u32 tli; ++ u32 tmli; ++ u32 taz; ++ u32 tzah; ++ u32 tenv; ++ u32 tsr; ++ u32 trfs; ++ u32 trp; ++ u32 tack; ++ u32 tss; ++}; ++ ++static const struct udmaspec udmaspec66[6] = { ++ { .tcyc = 8, .t2cyc = 16, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, ++ .tfs = 16, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 3, .trfs = 5, .trp = 11, .tack = 2, .tss = 4, ++ }, ++ { .tcyc = 5, .t2cyc = 11, .tds = 1, .tdh = 1, .tdvs = 4, .tdvh = 1, ++ .tfs = 14, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 2, .trfs = 5, .trp = 9, .tack = 2, .tss = 4, ++ }, ++ { .tcyc = 4, .t2cyc = 8, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, ++ .tfs = 12, .tli = 10, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, ++ }, ++ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 2, .tdvh = 1, ++ .tfs = 9, .tli = 7, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, ++ }, ++ { .tcyc = 2, .t2cyc = 4, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, ++ .tfs = 8, .tli = 8, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 2, .trfs = 4, .trp = 7, .tack = 2, .tss = 4, ++ }, ++ { .tcyc = 2, .t2cyc = 2, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, ++ .tfs = 6, .tli = 5, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 2, .trfs = 4, .trp = 6, .tack = 2, .tss = 4, ++ }, ++}; ++ ++static const struct udmaspec udmaspec132[6] = { ++ { .tcyc = 15, .t2cyc = 31, .tds = 2, .tdh = 1, .tdvs = 10, .tdvh = 1, ++ .tfs = 30, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, ++ .tsr = 7, .trfs = 10, .trp = 22, .tack = 3, .tss = 7, ++ }, ++ { .tcyc = 10, .t2cyc = 21, .tds = 2, .tdh = 1, .tdvs = 7, .tdvh = 1, ++ .tfs = 27, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, ++ .tsr = 4, .trfs = 10, .trp = 17, .tack = 3, .tss = 7, ++ }, ++ { .tcyc = 6, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 5, .tdvh = 1, ++ .tfs = 23, .tli = 20, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, ++ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, ++ }, ++ { .tcyc = 7, .t2cyc = 12, .tds = 1, .tdh = 1, .tdvs = 3, .tdvh = 1, ++ .tfs = 15, .tli = 13, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, ++ .tsr = 3, .trfs = 8, .trp = 14, .tack = 3, .tss = 7, ++ }, ++ { .tcyc = 2, .t2cyc = 5, .tds = 0, .tdh = 0, .tdvs = 1, .tdvh = 1, ++ .tfs = 16, .tli = 14, .tmli = 2, .taz = 1, .tzah = 2, .tenv = 2, ++ .tsr = 2, .trfs = 7, .trp = 13, .tack = 2, .tss = 6, ++ }, ++ { .tcyc = 3, .t2cyc = 6, .tds = 1, .tdh = 1, .tdvs = 1, .tdvh = 1, ++ .tfs = 12, .tli = 10, .tmli = 3, .taz = 2, .tzah = 3, .tenv = 3, ++ .tsr = 3, .trfs = 7, .trp = 12, .tack = 3, .tss = 7, ++ }, ++}; ++ ++/* ======================================================================== */ + + /* Bit definitions inside the registers */ + #define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */ +@@ -66,6 +189,7 @@ static const int ataspec_ta[5] = { 35 + #define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */ + + #define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */ ++#define MPC52xx_ATA_FIFOSTAT_ERROR 0x40 /* FIFO Error */ + + #define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */ + #define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */ +@@ -75,6 +199,8 @@ static const int ataspec_ta[5] = { 35 + #define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */ + #define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */ + ++#define MAX_DMA_BUFFERS 128 ++#define MAX_DMA_BUFFER_SIZE 0x20000u + + /* Structure of the hardware registers */ + struct mpc52xx_ata { +@@ -140,7 +266,6 @@ struct mpc52xx_ata { + + + /* MPC52xx low level hw control */ +- + static int + mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) + { +@@ -165,6 +290,42 @@ mpc52xx_ata_compute_pio_timings(struct m + return 0; + } + ++static int ++mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev, ++ int speed) ++{ ++ struct mpc52xx_ata_timings *t = &priv->timings[dev]; ++ const struct mdmaspec *s = &priv->mdmaspec[speed]; ++ ++ if (speed < 0 || speed > 2) ++ return -EINVAL; ++ ++ t->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm); ++ t->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8); ++ t->using_udma = 0; ++ ++ return 0; ++} ++ ++static int ++mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed) ++{ ++ struct mpc52xx_ata_timings *t = &priv->timings[dev]; ++ const struct udmaspec *s = &priv->udmaspec[speed]; ++ ++ if (speed < 0 || speed > 2) ++ return -EINVAL; ++ ++ t->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | s->tdh; ++ t->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | s->tli; ++ t->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | s->tsr; ++ t->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | s->tack; ++ t->udma5 = (s->tzah << 24); ++ t->using_udma = 1; ++ ++ return 0; ++} ++ + static void + mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) + { +@@ -173,14 +334,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx + + out_be32(®s->pio1, timing->pio1); + out_be32(®s->pio2, timing->pio2); +- out_be32(®s->mdma1, 0); +- out_be32(®s->mdma2, 0); +- out_be32(®s->udma1, 0); +- out_be32(®s->udma2, 0); +- out_be32(®s->udma3, 0); +- out_be32(®s->udma4, 0); +- out_be32(®s->udma5, 0); +- ++ out_be32(®s->mdma1, timing->mdma1); ++ out_be32(®s->mdma2, timing->mdma2); ++ out_be32(®s->udma1, timing->udma1); ++ out_be32(®s->udma2, timing->udma2); ++ out_be32(®s->udma3, timing->udma3); ++ out_be32(®s->udma4, timing->udma4); ++ out_be32(®s->udma5, timing->udma5); + priv->csel = device; + } + +@@ -244,6 +404,31 @@ mpc52xx_ata_set_piomode(struct ata_port + + mpc52xx_ata_apply_timings(priv, adev->devno); + } ++ ++static void ++mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev) ++{ ++ struct mpc52xx_ata_priv *priv = ap->host->private_data; ++ int rv; ++ ++ if (adev->dma_mode >= XFER_UDMA_0) { ++ int dma = adev->dma_mode - XFER_UDMA_0; ++ rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma); ++ } else { ++ int dma = adev->dma_mode - XFER_MW_DMA_0; ++ rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma); ++ } ++ ++ if (rv) { ++ dev_alert(ap->dev, ++ "Trying to select invalid DMA mode %d\n", ++ adev->dma_mode); ++ return; ++ } ++ ++ mpc52xx_ata_apply_timings(priv, adev->devno); ++} ++ + static void + mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) + { +@@ -255,6 +440,172 @@ mpc52xx_ata_dev_select(struct ata_port * + ata_sff_dev_select(ap,device); + } + ++static int ++mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc) ++{ ++ struct ata_port *ap = qc->ap; ++ struct mpc52xx_ata_priv *priv = ap->host->private_data; ++ struct bcom_ata_bd *bd; ++ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si; ++ struct scatterlist *sg; ++ int count = 0; ++ ++ if (read) ++ bcom_ata_rx_prepare(priv->dmatsk); ++ else ++ bcom_ata_tx_prepare(priv->dmatsk); ++ ++ for_each_sg(qc->sg, sg, qc->n_elem, si) { ++ dma_addr_t cur_addr = sg_dma_address(sg); ++ u32 cur_len = sg_dma_len(sg); ++ ++ while (cur_len) { ++ unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE); ++ bd = (struct bcom_ata_bd *) ++ bcom_prepare_next_buffer(priv->dmatsk); ++ ++ if (read) { ++ bd->status = tc; ++ bd->src_pa = (__force u32) priv->ata_regs_pa + ++ offsetof(struct mpc52xx_ata, fifo_data); ++ bd->dst_pa = (__force u32) cur_addr; ++ } else { ++ bd->status = tc; ++ bd->src_pa = (__force u32) cur_addr; ++ bd->dst_pa = (__force u32) priv->ata_regs_pa + ++ offsetof(struct mpc52xx_ata, fifo_data); ++ } ++ ++ bcom_submit_next_buffer(priv->dmatsk, NULL); ++ ++ cur_addr += tc; ++ cur_len -= tc; ++ count++; ++ ++ if (count > MAX_DMA_BUFFERS) { ++ dev_alert(ap->dev, "dma table" ++ "too small\n"); ++ goto use_pio_instead; ++ } ++ } ++ } ++ return 1; ++ ++ use_pio_instead: ++ bcom_ata_reset_bd(priv->dmatsk); ++ return 0; ++} ++ ++static void ++mpc52xx_bmdma_setup(struct ata_queued_cmd *qc) ++{ ++ struct ata_port *ap = qc->ap; ++ struct mpc52xx_ata_priv *priv = ap->host->private_data; ++ struct mpc52xx_ata __iomem *regs = priv->ata_regs; ++ ++ unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE); ++ u8 dma_mode; ++ ++ if (!mpc52xx_ata_build_dmatable(qc)) ++ dev_alert(ap->dev, "%s: %i, return 1?\n", ++ __func__, __LINE__); ++ ++ /* Check FIFO is OK... */ ++ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) ++ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", ++ __func__, in_8(&priv->ata_regs->fifo_status)); ++ ++ if (read) { ++ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ | ++ MPC52xx_ATA_DMAMODE_FE; ++ ++ /* Setup FIFO if direction changed */ ++ if (priv->mpc52xx_ata_dma_last_write != 0) { ++ priv->mpc52xx_ata_dma_last_write = 0; ++ ++ /* Configure FIFO with granularity to 7 */ ++ out_8(®s->fifo_control, 7); ++ out_be16(®s->fifo_alarm, 128); ++ ++ /* Set FIFO Reset bit (FR) */ ++ out_8(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR); ++ } ++ } else { ++ dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE; ++ ++ /* Setup FIFO if direction changed */ ++ if (priv->mpc52xx_ata_dma_last_write != 1) { ++ priv->mpc52xx_ata_dma_last_write = 1; ++ ++ /* Configure FIFO with granularity to 4 */ ++ out_8(®s->fifo_control, 4); ++ out_be16(®s->fifo_alarm, 128); ++ } ++ } ++ ++ if (priv->timings[qc->dev->devno].using_udma) ++ dma_mode |= MPC52xx_ATA_DMAMODE_UDMA; ++ ++ out_8(®s->dma_mode, dma_mode); ++ priv->waiting_for_dma = ATA_DMA_ACTIVE; ++ ++ ata_wait_idle(ap); ++ ap->ops->sff_exec_command(ap, &qc->tf); ++} ++ ++static void ++mpc52xx_bmdma_start(struct ata_queued_cmd *qc) ++{ ++ struct ata_port *ap = qc->ap; ++ struct mpc52xx_ata_priv *priv = ap->host->private_data; ++ ++ bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum); ++ bcom_enable(priv->dmatsk); ++} ++ ++static void ++mpc52xx_bmdma_stop(struct ata_queued_cmd *qc) ++{ ++ struct ata_port *ap = qc->ap; ++ struct mpc52xx_ata_priv *priv = ap->host->private_data; ++ ++ bcom_disable(priv->dmatsk); ++ bcom_ata_reset_bd(priv->dmatsk); ++ priv->waiting_for_dma = 0; ++ ++ /* Check FIFO is OK... */ ++ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) ++ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", ++ __func__, in_8(&priv->ata_regs->fifo_status)); ++} ++ ++static u8 ++mpc52xx_bmdma_status(struct ata_port *ap) ++{ ++ struct mpc52xx_ata_priv *priv = ap->host->private_data; ++ ++ /* Check FIFO is OK... */ ++ if (in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) { ++ dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n", ++ __func__, in_8(&priv->ata_regs->fifo_status)); ++ return priv->waiting_for_dma | ATA_DMA_ERR; ++ } ++ ++ return priv->waiting_for_dma; ++} ++ ++static irqreturn_t ++mpc52xx_ata_task_irq(int irq, void *vpriv) ++{ ++ struct mpc52xx_ata_priv *priv = vpriv; ++ while (bcom_buffer_done(priv->dmatsk)) ++ bcom_retrieve_buffer(priv->dmatsk, NULL, NULL); ++ ++ priv->waiting_for_dma |= ATA_DMA_INTR; ++ ++ return IRQ_HANDLED; ++} ++ + static struct scsi_host_template mpc52xx_ata_sht = { + ATA_PIO_SHT(DRV_NAME), + }; +@@ -262,14 +613,18 @@ static struct scsi_host_template mpc52xx + static struct ata_port_operations mpc52xx_ata_port_ops = { + .inherits = &ata_sff_port_ops, + .sff_dev_select = mpc52xx_ata_dev_select, +- .cable_detect = ata_cable_40wire, + .set_piomode = mpc52xx_ata_set_piomode, +- .post_internal_cmd = ATA_OP_NULL, ++ .set_dmamode = mpc52xx_ata_set_dmamode, ++ .bmdma_setup = mpc52xx_bmdma_setup, ++ .bmdma_start = mpc52xx_bmdma_start, ++ .bmdma_stop = mpc52xx_bmdma_stop, ++ .bmdma_status = mpc52xx_bmdma_status, ++ .qc_prep = ata_noop_qc_prep, + }; + + static int __devinit + mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, +- unsigned long raw_ata_regs) ++ unsigned long raw_ata_regs, int mwdma_mask, int udma_mask) + { + struct ata_host *host; + struct ata_port *ap; +@@ -281,9 +636,9 @@ mpc52xx_ata_init_one(struct device *dev, + + ap = host->ports[0]; + ap->flags |= ATA_FLAG_SLAVE_POSS; +- ap->pio_mask = 0x1f; /* Up to PIO4 */ +- ap->mwdma_mask = 0x00; /* No MWDMA */ +- ap->udma_mask = 0x00; /* No UDMA */ ++ ap->pio_mask = ATA_PIO4; ++ ap->mwdma_mask = mwdma_mask; ++ ap->udma_mask = udma_mask; + ap->ops = &mpc52xx_ata_port_ops; + host->private_data = priv; + +@@ -333,7 +688,10 @@ mpc52xx_ata_probe(struct of_device *op, + int ata_irq; + struct mpc52xx_ata __iomem *ata_regs; + struct mpc52xx_ata_priv *priv; +- int rv; ++ int rv, ret, task_irq; ++ int mwdma_mask = 0, udma_mask = 0; ++ const __be32 *prop; ++ int proplen; + + /* Get ipb frequency */ + ipb_freq = mpc52xx_find_ipb_freq(op->node); +@@ -351,6 +709,27 @@ mpc52xx_ata_probe(struct of_device *op, + return rv; + } + ++ /* ++ * By default, all DMA modes are disabled for the MPC5200. Some ++ * boards don't have the required signals routed to make DMA work. ++ * Also, the MPC5200B has a silicon bug that causes data corruption ++ * with UDMA if it is used at the same time as the LocalPlus bus. ++ * ++ * Instead of trying to guess what modes are usable, check the ++ * ATA device tree node to find out what DMA modes work on the board. ++ * UDMA/MWDMA modes can also be forced by adding "libata.force=" ++ * to the kernel boot parameters. ++ * ++ * The MPC5200 ATA controller supports MWDMA modes 0, 1 and 2 and ++ * UDMA modes 0, 1 and 2. ++ */ ++ prop = of_get_property(op->node, "mwdma-mode", &proplen); ++ if ((prop) && (proplen >= 4)) ++ mwdma_mask = 0x7 & ((1 << (*prop + 1)) - 1); ++ prop = of_get_property(op->node, "udma-mode", &proplen); ++ if ((prop) && (proplen >= 4)) ++ udma_mask = 0x7 & ((1 << (*prop + 1)) - 1); ++ + ata_irq = irq_of_parse_and_map(op->node, 0); + if (ata_irq == NO_IRQ) { + printk(KERN_ERR DRV_NAME ": " +@@ -389,8 +768,32 @@ mpc52xx_ata_probe(struct of_device *op, + + priv->ipb_period = 1000000000 / (ipb_freq / 1000); + priv->ata_regs = ata_regs; ++ priv->ata_regs_pa = res_mem.start; + priv->ata_irq = ata_irq; + priv->csel = -1; ++ priv->mpc52xx_ata_dma_last_write = -1; ++ ++ if (ipb_freq/1000000 == 66) { ++ priv->mdmaspec = mdmaspec66; ++ priv->udmaspec = udmaspec66; ++ } else { ++ priv->mdmaspec = mdmaspec132; ++ priv->udmaspec = udmaspec132; ++ } ++ ++ priv->dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE); ++ if (!priv->dmatsk) { ++ dev_err(&op->dev, "bestcomm initialization failed\n"); ++ rv = -ENOMEM; ++ goto err; ++ } ++ ++ task_irq = bcom_get_task_irq(priv->dmatsk); ++ ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED, ++ "ATA task", priv); ++ if (ret) ++ dev_alert(&op->dev, "request_irq failed with: " ++ "%i\n", ret); + + /* Init the hw */ + rv = mpc52xx_ata_hw_init(priv); +@@ -400,7 +803,8 @@ mpc52xx_ata_probe(struct of_device *op, + } + + /* Register ourselves to libata */ +- rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); ++ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start, ++ mwdma_mask, udma_mask); + if (rv) { + printk(KERN_ERR DRV_NAME ": " + "Error while registering to ATA layer\n"); diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-mpc52xx-ac97.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-mpc52xx-ac97.patch new file mode 100644 index 000000000..dc16454df --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-mpc52xx-ac97.patch @@ -0,0 +1,892 @@ +From: Juergen Beisert +Subject: RFC: MPC5200 PSC AC97 driver + +if someone is interested: Here the full patch to get sound support for +MPC5200b and a current 2.6.25 kernel. + +Acked-by: Olaf Hering + +--- + arch/powerpc/include/asm/mpc52xx_psc.h | 4 + arch/powerpc/kernel/prom_init.c | 3 + sound/ppc/Kconfig | 15 + sound/ppc/Makefile | 2 + sound/ppc/mpc52xx_ac97.c | 807 +++++++++++++++++++++++++++++++++ + 5 files changed, 831 insertions(+) + +--- a/arch/powerpc/include/asm/mpc52xx_psc.h ++++ b/arch/powerpc/include/asm/mpc52xx_psc.h +@@ -28,6 +28,10 @@ + #define MPC52xx_PSC_MAXNUM 6 + + /* Programmable Serial Controller (PSC) status register bits */ ++#define MPC52xx_PSC_SR_UNEX_RX 0x0001 ++#define MPC52xx_PSC_SR_DATA_VAL 0x0002 ++#define MPC52xx_PSC_SR_DATA_OVR 0x0004 ++#define MPC52xx_PSC_SR_CMDSEND 0x0008 + #define MPC52xx_PSC_SR_CDE 0x0080 + #define MPC52xx_PSC_SR_RXRDY 0x0100 + #define MPC52xx_PSC_SR_RXFULL 0x0200 +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -2189,6 +2189,7 @@ static void __init fixup_device_tree_efi + + static void __init fixup_device_tree_efika(void) + { ++ int sound_cell[1] = { 1 }; + int sound_irq[3] = { 2, 2, 0 }; + int bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0, + 3,4,0, 3,5,0, 3,6,0, 3,7,0, +@@ -2244,6 +2245,8 @@ static void __init fixup_device_tree_efi + prom_printf("Adding sound interrupts property\n"); + prom_setprop(node, "/builtin/sound", "interrupts", + sound_irq, sizeof(sound_irq)); ++ prom_setprop(node, "/builtin/sound", "cell-index", ++ sound_cell, sizeof(sound_cell)); + } + } + +--- a/sound/ppc/Kconfig ++++ b/sound/ppc/Kconfig +@@ -48,4 +48,19 @@ config SND_PS3_DEFAULT_START_DELAY + depends on SND_PS3 + default "2000" + ++ ++# ALSA ppc drivers ++ ++menu "ALSA PPC devices" ++ depends on SND!=n && PPC ++ ++config SND_PPC_MPC52xx_AC97 ++ tristate "Freescale MPC52xx AC97 interface support" ++ depends on SND && PPC_MPC52xx ++ select SND_AC97_CODEC ++ help ++ Say Y or M if you want to support any AC97 codec attached to ++ the Freescqle MPC52xx AC97 interface. ++endmenu ++ + endif # SND_PPC +--- a/sound/ppc/Makefile ++++ b/sound/ppc/Makefile +@@ -4,7 +4,9 @@ + # + + snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o ++snd-mpc52xx-ac97-objs := mpc52xx_ac97.o + + # Toplevel Module Dependency + obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o + obj-$(CONFIG_SND_PS3) += snd_ps3.o ++obj-$(CONFIG_SND_PPC_MPC52xx_AC97) += snd-mpc52xx-ac97.o +--- /dev/null ++++ b/sound/ppc/mpc52xx_ac97.c +@@ -0,0 +1,807 @@ ++/* ++ * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface ++ * ++ * ++ * Copyright (C) 2006 Sylvain Munaut ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++#define DRV_NAME "mpc52xx-psc-ac97" ++ ++ ++/* ======================================================================== */ ++/* Structs / Defines */ ++/* ======================================================================== */ ++ ++/* Private structure */ ++struct mpc52xx_ac97_priv { ++ struct device *dev; ++ resource_size_t mem_start; ++ resource_size_t mem_len; ++ int irq; ++ struct mpc52xx_psc __iomem *psc; ++ struct mpc52xx_psc_fifo __iomem *fifo; ++ ++ struct bcom_task *tsk_tx; ++ spinlock_t dma_lock; ++ ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ struct snd_ac97 *ac97; ++ ++ struct snd_pcm_substream *substream_playback; ++ ++ int period_byte_size; ++ u32 period_start, period_end, period_next_p; ++}; ++ ++/* Register bit definition (AC97 mode specific) */ ++#define PSC_AC97_SLOT_BIT(n) (1<<(12-n)) ++#define PSC_AC97_SLOTS_XMIT_SHIFT 16 ++#define PSC_AC97_SLOTS_RECV_SHIFT 0 ++ ++/* Bestcomm options */ ++#define AC97_TX_NUM_BD 32 ++#define AC97_RX_NUM_BD 32 ++ ++static int mpc52xx_ac97_tx_fill(struct mpc52xx_ac97_priv *priv) ++{ ++ struct snd_pcm_runtime *rt; ++ ++ u32 dma_data_ptr; ++ ++ rt = priv->substream_playback->runtime; ++ ++ dma_data_ptr = virt_to_phys(rt->dma_area); ++ ++ priv->period_byte_size = frames_to_bytes(rt, rt->period_size); ++ priv->period_start = dma_data_ptr; ++ priv->period_end = dma_data_ptr + priv->period_byte_size * rt->periods; ++ priv->period_next_p = dma_data_ptr; ++ ++ spin_lock(&priv->dma_lock); ++ while (!bcom_queue_full(priv->tsk_tx)) { ++ struct bcom_gen_bd *bd; ++ ++ /* Submit a new one */ ++ bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx); ++ bd->status = priv->period_byte_size; ++ bd->buf_pa = priv->period_next_p; ++ bcom_submit_next_buffer(priv->tsk_tx, NULL); ++ ++ /* Next pointer */ ++ priv->period_next_p += priv->period_byte_size; ++ if (priv->period_next_p >= priv->period_end) ++ priv->period_next_p = priv->period_start; ++ } ++ spin_unlock(&priv->dma_lock); ++ ++ return 0; ++} ++ ++ ++/* ======================================================================== */ ++/* ISR routine */ ++/* ======================================================================== */ ++ ++static irqreturn_t mpc52xx_ac97_tx_irq(int irq, void *dev_id) ++{ ++ struct mpc52xx_ac97_priv *priv = dev_id; ++ struct snd_pcm_runtime *rt; ++ struct bcom_gen_bd *bd; ++ ++ rt = priv->substream_playback->runtime; ++ ++ if (!bcom_buffer_done(priv->tsk_tx)) { ++ dev_dbg(priv->dev, "tx mismatch? Check correct output PSC\n"); ++ bcom_disable(priv->tsk_tx); ++ } ++ ++ spin_lock(&priv->dma_lock); ++ while (bcom_buffer_done(priv->tsk_tx)) { ++ /* Get the buffer back */ ++ bcom_retrieve_buffer(priv->tsk_tx, NULL, NULL); ++ ++ /* Submit a new one */ ++ bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx); ++ bd->status = priv->period_byte_size; ++ bd->buf_pa = priv->period_next_p; ++ bcom_submit_next_buffer(priv->tsk_tx, NULL); ++ bcom_enable(priv->tsk_tx); ++ ++ /* Next pointer */ ++ priv->period_next_p += priv->period_byte_size; ++ if (priv->period_next_p >= priv->period_end) ++ priv->period_next_p = priv->period_start; ++ } ++ spin_unlock(&priv->dma_lock); ++ ++ snd_pcm_period_elapsed(priv->substream_playback); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static irqreturn_t mpc52xx_ac97_irq(int irq, void *dev_id) ++{ ++ struct mpc52xx_ac97_priv *priv = dev_id; ++ ++ static int icnt = 0; ++ ++#if 1 ++ /* Anti Crash during dev ;) */ ++ if ((icnt++) > 5000) ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0); ++#endif ++ ++ /* Print statuts */ ++ dev_dbg(priv->dev, "isr: %04x", in_be16(&priv->psc->mpc52xx_psc_imr)); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT); ++ ++ return IRQ_HANDLED; ++} ++ ++/* ======================================================================== */ ++/* PCM interface */ ++/* ======================================================================== */ ++ ++/* HW desc */ ++ ++static struct snd_pcm_hardware mpc52xx_ac97_hw = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID, ++ .formats = SNDRV_PCM_FMTBIT_S32_BE, ++ .rates = SNDRV_PCM_RATE_8000_48000, ++ .rate_min = 8000, ++ .rate_max = 48000, ++ .channels_min = 1, ++ .channels_max = 2, /* Support for more ? */ ++ .buffer_bytes_max = 1024*1024, ++ .period_bytes_min = 512, ++ .period_bytes_max = 16*1024, ++ .periods_min = 8, ++ .periods_max = 1024, ++ .fifo_size = 512, ++}; ++ ++ ++/* Playback */ ++ ++static int mpc52xx_ac97_playback_open(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_playback_open(%p)\n", substream); ++ ++ substream->runtime->hw = mpc52xx_ac97_hw; ++ ++ priv->substream_playback = substream; ++ ++ return 0; /* FIXME */ ++} ++ ++static int mpc52xx_ac97_playback_close(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ dev_dbg(priv->dev, "mpc52xx_ac97_playback_close(%p)\n", substream); ++ priv->substream_playback = NULL; ++ return 0; /* FIXME */ ++} ++ ++static int mpc52xx_ac97_playback_prepare(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_playback_prepare(%p)\n", substream); ++ ++ /* FIXME, need a spinlock to protect access */ ++ if (substream->runtime->channels == 1) ++ out_be32(&priv->psc->ac97_slots, 0x01000000); ++ else ++ out_be32(&priv->psc->ac97_slots, 0x03000000); ++ ++ snd_ac97_set_rate(priv->ac97, AC97_PCM_FRONT_DAC_RATE, ++ substream->runtime->rate); ++ ++ return 0; /* FIXME */ ++} ++ ++ ++/* Capture */ ++ ++static int mpc52xx_ac97_capture_open(struct snd_pcm_substream *substream) ++{ ++/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */ ++ return 0; /* FIXME */ ++} ++ ++static int mpc52xx_ac97_capture_close(struct snd_pcm_substream *substream) ++{ ++/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */ ++ return 0; /* FIXME */ ++} ++ ++static int ++mpc52xx_ac97_capture_prepare(struct snd_pcm_substream *substream) ++{ ++/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */ ++ return 0; /* FIXME */ ++} ++ ++ ++/* Common */ ++ ++static int mpc52xx_ac97_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ int rv; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_hw_params(%p)\n", substream); ++ ++ rv = snd_pcm_lib_malloc_pages(substream, ++ params_buffer_bytes(params)); ++ if (rv < 0) { ++ printk(KERN_ERR "hw params failes\n"); /* FIXME */ ++ return rv; ++ } ++ ++ dev_dbg(priv->dev, "%d %d %d\n", params_buffer_bytes(params), ++ params_period_bytes(params), params_periods(params)); ++ ++ return 0; ++} ++ ++static int mpc52xx_ac97_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_hw_free(%p)\n", substream); ++ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static int mpc52xx_ac97_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ int rv = 0; ++ ++ dev_dbg(priv->dev, "mpc52xx_ac97_trigger(%p,%d)\n", substream, cmd); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ /* Enable TX taks */ ++ bcom_gen_bd_tx_reset(priv->tsk_tx); ++ mpc52xx_ac97_tx_fill(priv); ++ bcom_enable(priv->tsk_tx); ++/* ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0800); // 0x0100 ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100 ++*/ ++ /* FIXME: Shouldn't we check for overrun too ? */ ++ /* also, shouldn't we just activate TX here ? */ ++ ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ /* Disable TX task */ ++ bcom_disable(priv->tsk_tx); ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); // 0x0100 ++ ++ break; ++ ++ default: ++ rv = -EINVAL; ++ } ++ ++ /* FIXME */ ++ return rv; ++} ++ ++static snd_pcm_uframes_t mpc52xx_ac97_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; ++ u32 count; ++ ++ count = priv->tsk_tx->bd[priv->tsk_tx->outdex].data[0] - priv->period_start; ++ ++ return bytes_to_frames(runtime, count); ++} ++ ++ ++/* Ops */ ++ ++static struct snd_pcm_ops mpc52xx_ac97_playback_ops = { ++ .open = mpc52xx_ac97_playback_open, ++ .close = mpc52xx_ac97_playback_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = mpc52xx_ac97_hw_params, ++ .hw_free = mpc52xx_ac97_hw_free, ++ .prepare = mpc52xx_ac97_playback_prepare, ++ .trigger = mpc52xx_ac97_trigger, ++ .pointer = mpc52xx_ac97_pointer, ++}; ++ ++static struct snd_pcm_ops mpc52xx_ac97_capture_ops = { ++ .open = mpc52xx_ac97_capture_open, ++ .close = mpc52xx_ac97_capture_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = mpc52xx_ac97_hw_params, ++ .hw_free = mpc52xx_ac97_hw_free, ++ .prepare = mpc52xx_ac97_capture_prepare, ++ .trigger = mpc52xx_ac97_trigger, ++ .pointer = mpc52xx_ac97_pointer, ++}; ++ ++ ++/* ======================================================================== */ ++/* AC97 Bus interface */ ++/* ======================================================================== */ ++ ++static unsigned short mpc52xx_ac97_bus_read(struct snd_ac97 *ac97, ++ unsigned short reg) ++{ ++ struct mpc52xx_ac97_priv *priv = ac97->private_data; ++ int timeout; ++ unsigned int val; ++ ++ /* Wait for it to be ready */ ++ timeout = 1000; ++ while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) & ++ MPC52xx_PSC_SR_CMDSEND) ) ++ udelay(10); ++ ++ if (!timeout) { ++ printk(KERN_ERR DRV_NAME ": timeout on ac97 bus (rdy)\n"); ++ return 0xffff; ++ } ++ ++ /* Do the read */ ++ out_be32(&priv->psc->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24)); ++ ++ /* Wait for the answer */ ++ timeout = 1000; ++ while ((--timeout) && !(in_be16(&priv->psc->mpc52xx_psc_status) & ++ MPC52xx_PSC_SR_DATA_VAL) ) ++ udelay(10); ++ ++ if (!timeout) { ++ printk(KERN_ERR DRV_NAME ": timeout on ac97 read (val)\n"); ++ return 0xffff; ++ } ++ ++ /* Get the data */ ++ val = in_be32(&priv->psc->ac97_data); ++ if ( ((val>>24) & 0x7f) != reg ) { ++ printk(KERN_ERR DRV_NAME ": reg echo error on ac97 read\n"); ++ return 0xffff; ++ } ++ val = (val >> 8) & 0xffff; ++ ++ return (unsigned short) val; ++} ++ ++static void mpc52xx_ac97_bus_write(struct snd_ac97 *ac97, ++ unsigned short reg, unsigned short val) ++{ ++ struct mpc52xx_ac97_priv *priv = ac97->private_data; ++ int timeout; ++ ++ /* Wait for it to be ready */ ++ timeout = 1000; ++ while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) & ++ MPC52xx_PSC_SR_CMDSEND) ) ++ udelay(10); ++ ++ if (!timeout) { ++ printk(KERN_ERR DRV_NAME ": timeout on ac97 write\n"); ++ return; ++ } ++ ++ /* Write data */ ++ out_be32(&priv->psc->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8)); ++} ++ ++static void mpc52xx_ac97_bus_reset(struct snd_ac97 *ac97) ++{ ++ struct mpc52xx_ac97_priv *priv = ac97->private_data; ++ ++ dev_dbg(priv->dev, "ac97 codec reset\n"); ++ ++ /* Do a cold reset */ ++ /* ++ * Note: This could interfere with some external AC97 mixers, as it ++ * could switch them into test mode, when SYNC or SDATA_OUT are not ++ * low while RES is low! ++ */ ++ out_8(&priv->psc->op1, 0x02); ++ udelay(10); ++ out_8(&priv->psc->op0, 0x02); ++ udelay(50); ++ ++ /* PSC recover from cold reset (cfr user manual, not sure if useful) */ ++ out_be32(&priv->psc->sicr, in_be32(&priv->psc->sicr)); ++} ++ ++ ++static struct snd_ac97_bus_ops mpc52xx_ac97_bus_ops = { ++ .read = mpc52xx_ac97_bus_read, ++ .write = mpc52xx_ac97_bus_write, ++ .reset = mpc52xx_ac97_bus_reset, ++}; ++ ++ ++/* ======================================================================== */ ++/* Sound driver setup */ ++/* ======================================================================== */ ++ ++static int mpc52xx_ac97_setup_pcm(struct mpc52xx_ac97_priv *priv) ++{ ++ int rv; ++ ++ rv = snd_pcm_new(priv->card, DRV_NAME "-pcm", 0, 1, 1, &priv->pcm); ++ if (rv) { ++ dev_dbg(priv->dev, "%s: snd_pcm_new failed\n", DRV_NAME); ++ return rv; ++ } ++ ++ rv = snd_pcm_lib_preallocate_pages_for_all(priv->pcm, ++ SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), ++ 128*1024, 128*1024); ++ if (rv) { ++ dev_dbg(priv->dev, ++ "%s: snd_pcm_lib_preallocate_pages_for_all failed\n", ++ DRV_NAME); ++ return rv; ++ } ++ ++ snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_PLAYBACK, ++ &mpc52xx_ac97_playback_ops); ++ snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_CAPTURE, ++ &mpc52xx_ac97_capture_ops); ++ ++ priv->pcm->private_data = priv; ++ priv->pcm->info_flags = 0; ++ ++ strcpy(priv->pcm->name, "Freescale MPC52xx PSC-AC97 PCM"); ++ ++ return 0; ++} ++ ++static int mpc52xx_ac97_setup_mixer(struct mpc52xx_ac97_priv *priv) ++{ ++ struct snd_ac97_bus *ac97_bus; ++ struct snd_ac97_template ac97_template; ++ int rv; ++ ++ rv = snd_ac97_bus(priv->card, 0, &mpc52xx_ac97_bus_ops, NULL, &ac97_bus); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": snd_ac97_bus failed\n"); ++ return rv; ++ } ++ ++ memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); ++ ac97_template.private_data = priv; ++ ++ rv = snd_ac97_mixer(ac97_bus, &ac97_template, &priv->ac97); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": snd_ac97_mixer failed\n"); ++ return rv; ++ } ++ ++ return 0; ++} ++ ++static int mpc52xx_ac97_hwinit(struct mpc52xx_ac97_priv *priv) ++{ ++ /* Reset everything first by safety */ ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_RX); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_TX); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT); ++ ++ /* Do a cold reset of codec */ ++ /* ++ * Note: This could interfere with some external AC97 mixers, as it ++ * could switch them into test mode, when SYNC or SDATA_OUT are not ++ * low while RES is low! ++ */ ++ out_8(&priv->psc->op1, 0x02); ++ udelay(10); ++ out_8(&priv->psc->op0, 0x02); ++ udelay(50); ++ ++ /* Configure AC97 enhanced mode */ ++ out_be32(&priv->psc->sicr, 0x03010000); ++ ++ /* No slots active */ ++ out_be32(&priv->psc->ac97_slots, 0x00000000); ++ ++ /* No IRQ */ ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); ++ ++ /* FIFO levels */ ++ out_8(&priv->fifo->rfcntl, 0x07); ++ out_8(&priv->fifo->tfcntl, 0x07); ++ out_be16(&priv->fifo->rfalarm, 0x80); ++ out_be16(&priv->fifo->tfalarm, 0x80); ++ ++ /* Go */ ++ out_8(&priv->psc->command,MPC52xx_PSC_TX_ENABLE); ++ out_8(&priv->psc->command,MPC52xx_PSC_RX_ENABLE); ++ ++ return 0; ++} ++ ++static int mpc52xx_ac97_hwshutdown(struct mpc52xx_ac97_priv *priv) ++{ ++ /* No IRQ */ ++ out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); ++ ++ /* Disable TB & RX */ ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_RX); ++ out_8(&priv->psc->command,MPC52xx_PSC_RST_TX); ++ ++ /* FIXME : Reset or put codec in low power ? */ ++ ++ return 0; ++} ++ ++/* ======================================================================== */ ++/* OF Platform Driver */ ++/* ======================================================================== */ ++ ++static int __devinit ++mpc52xx_ac97_probe(struct of_device *op, const struct of_device_id *match) ++{ ++ struct device_node *dn = op->node; ++ struct mpc52xx_ac97_priv *priv; ++ struct snd_card *card; ++ struct resource res; ++ int tx_initiator; ++ int rv; ++ const unsigned int *devno; ++ ++ dev_dbg(&op->dev, "probing MPC52xx PSC AC97 driver\n"); ++ ++ /* Get card structure */ ++ rv = -ENOMEM; ++ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, ++ THIS_MODULE, sizeof(struct mpc52xx_ac97_priv)); ++ if (!card) ++ goto err_early; ++ ++ priv = card->private_data; ++ ++ /* Init our private structure */ ++ priv->card = card; ++ priv->dev = &op->dev; ++ ++ /* Get resources (mem,irq,...) */ ++ rv = of_address_to_resource(dn, 0, &res); ++ if (rv) ++ goto err_early; ++ ++ priv->mem_start = res.start; ++ priv->mem_len = res.end - res.start + 1; ++ ++ if (!request_mem_region(priv->mem_start, priv->mem_len, DRV_NAME)) { ++ dev_err(&op->dev, "%s: request_mem_region failed\n", DRV_NAME); ++ rv = -EBUSY; ++ goto err_early; ++ } ++ ++ priv->psc = ioremap(priv->mem_start, priv->mem_len); ++ if (!priv->psc) { ++ dev_err(&op->dev, "%s: ioremap failed\n", DRV_NAME); ++ rv = -ENOMEM; ++ goto err_iomap; ++ } ++ /* the fifo starts right after psc ends */ ++ priv->fifo = (struct mpc52xx_psc_fifo*)&priv->psc[1]; /* FIXME */ ++ ++ priv->irq = irq_of_parse_and_map(dn, 0); ++ if (priv->irq == NO_IRQ) { ++ dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", ++ DRV_NAME); ++ rv = -EBUSY; ++ goto err_irqmap; ++ } ++ ++ /* Setup Bestcomm tasks */ ++ spin_lock_init(&priv->dma_lock); ++ ++ /* ++ * PSC1 or PSC2 can be configured for AC97 usage. Select the right ++ * channel, to let the BCOMM unit does its job correctly. ++ */ ++ devno = of_get_property(dn, "cell-index", NULL); ++ switch (*devno) { ++ case 0: /* PSC1 */ ++ tx_initiator = 14; ++ break; ++ case 1: /* PSC2 */ ++ tx_initiator = 12; ++ break; ++ default: ++ dev_dbg(priv->dev, "Unknown PSC unit for AC97 usage!\n"); ++ rv = -ENODEV; ++ goto err_irq; ++ } ++ ++ priv->tsk_tx = bcom_gen_bd_tx_init(AC97_TX_NUM_BD, ++ priv->mem_start + sizeof(struct mpc52xx_psc) + ++ offsetof(struct mpc52xx_psc_fifo, tfdata), ++ tx_initiator, ++ 2); /* ipr : FIXME */ ++ if (!priv->tsk_tx) { ++ dev_err(&op->dev, "%s: bcom_gen_bd_tx_init failed\n", ++ DRV_NAME); ++ rv = -ENOMEM; ++ goto err_bcomm; ++ } ++ ++ /* Low level HW Init */ ++ mpc52xx_ac97_hwinit(priv); ++ ++ /* Request IRQ now that we're 'stable' */ ++ rv = request_irq(priv->irq, mpc52xx_ac97_irq, 0, DRV_NAME, priv); ++ if (rv < 0) { ++ dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME); ++ goto err_irqreq; ++ } ++ ++ rv = request_irq(bcom_get_task_irq(priv->tsk_tx), ++ mpc52xx_ac97_tx_irq, 0, DRV_NAME "_tx", priv); ++ if (rv < 0) { ++ dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME); ++ goto err_txirqreq; ++ } ++ ++ /* Prepare sound stuff */ ++ rv = mpc52xx_ac97_setup_mixer(priv); ++ if (rv) ++ goto err_late; ++ ++ rv = mpc52xx_ac97_setup_pcm(priv); ++ if (rv) ++ goto err_late; ++ ++ /* Finally register the card */ ++ snprintf(card->shortname, sizeof(card->shortname), DRV_NAME); ++ snprintf(card->longname, sizeof(card->longname), ++ "Freescale MPC52xx PSC-AC97 (%s)", card->mixername); ++ ++ rv = snd_card_register(card); ++ if (rv) { ++ dev_err(&op->dev, "%s: snd_card_register failed\n", DRV_NAME); ++ goto err_late; ++ } ++ ++ dev_set_drvdata(&op->dev, priv); ++ ++ return 0; ++ ++err_late: ++ free_irq(bcom_get_task_irq(priv->tsk_tx), priv); ++err_txirqreq: ++ free_irq(priv->irq, priv); ++err_irqreq: ++ bcom_gen_bd_tx_release(priv->tsk_tx); ++err_bcomm: ++ mpc52xx_ac97_hwshutdown(priv); ++err_irq: ++ irq_dispose_mapping(priv->irq); ++err_irqmap: ++ iounmap(priv->psc); ++err_iomap: ++ release_mem_region(priv->mem_start, priv->mem_len); ++err_early: ++ if (card) ++ snd_card_free(card); ++ return rv; ++} ++ ++static int mpc52xx_ac97_remove(struct of_device *op) ++{ ++ struct mpc52xx_ac97_priv *priv; ++ ++ dev_dbg(&op->dev, "removing MPC52xx PSC AC97 driver\n"); ++ ++ priv = dev_get_drvdata(&op->dev); ++ if (priv) { ++ /* Sound subsys shutdown */ ++ snd_card_free(priv->card); ++ ++ /* Low level HW shutdown */ ++ mpc52xx_ac97_hwshutdown(priv); ++ ++ /* Release bestcomm tasks */ ++ free_irq(bcom_get_task_irq(priv->tsk_tx), priv); ++ bcom_gen_bd_tx_release(priv->tsk_tx); ++ ++ /* Release resources */ ++ iounmap(priv->psc); ++ free_irq(priv->irq, priv); ++ irq_dispose_mapping(priv->irq); ++ release_mem_region(priv->mem_start, priv->mem_len); ++ } ++ ++ dev_set_drvdata(&op->dev, NULL); ++ ++ return 0; ++} ++ ++ ++static struct of_device_id mpc52xx_ac97_of_match[] = { ++ { ++ .type = "sound", ++ .compatible = "mpc5200b-psc-ac97", /* B only for now */ ++ }, { } ++}; ++MODULE_DEVICE_TABLE(of, mpc52xx_ac97_of_match); ++static struct of_platform_driver mpc52xx_ac97_of_driver = { ++ .owner = THIS_MODULE, ++ .name = DRV_NAME, ++ .match_table = mpc52xx_ac97_of_match, ++ .probe = mpc52xx_ac97_probe, ++ .remove = mpc52xx_ac97_remove, ++ .driver = { ++ .name = DRV_NAME, ++ }, ++}; ++ ++/* ======================================================================== */ ++/* Module */ ++/* ======================================================================== */ ++ ++static int __init mpc52xx_ac97_init(void) ++{ ++ int rv; ++ ++ printk(KERN_INFO "Sound: MPC52xx PSC AC97 driver\n"); ++ ++ rv = of_register_platform_driver(&mpc52xx_ac97_of_driver); ++ if (rv) { ++ printk(KERN_ERR DRV_NAME ": " ++ "of_register_platform_driver failed (%i)\n", rv); ++ return rv; ++ } ++ ++ return 0; ++} ++ ++static void __exit mpc52xx_ac97_exit(void) ++{ ++ of_unregister_platform_driver(&mpc52xx_ac97_of_driver); ++} ++ ++module_init(mpc52xx_ac97_init); ++module_exit(mpc52xx_ac97_exit); ++ ++MODULE_AUTHOR("Sylvain Munaut "); ++MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver"); ++MODULE_LICENSE("GPL"); ++ diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-psc-console-autodetection.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-psc-console-autodetection.patch new file mode 100644 index 000000000..a14b718f4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-efika-psc-console-autodetection.patch @@ -0,0 +1,83 @@ +Subject: [PATCH] autodetect serial console on efika +From: Olaf Hering + +Efika boards have to be booted with console=ttyPSC0 unless there is a +graphics card plugged in. Detect if the firmware stdout is the serial +connector. + +--- + arch/powerpc/platforms/52xx/efika.c | 50 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +--- a/arch/powerpc/platforms/52xx/efika.c ++++ b/arch/powerpc/platforms/52xx/efika.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -211,12 +212,61 @@ static int __init efika_probe(void) + return 1; + } + ++/* ++ * Per default, input/output-device points to the keyboard/screen ++ * If no card is installed, the built-in serial port is used as a fallback. ++ * But unfortunately, the firmware does not connect /chosen/{stdin,stdout} ++ * the the built-in serial node. Instead, a /failsafe node is created. ++ * More advanced hardware configurations cant be detected, ++ * boot with console=xyz123 to point the kernel to the correct device ++ */ ++static void __init efika_init_early(void) ++{ ++#ifdef CONFIG_SERIAL_MPC52xx ++ struct device_node *stdout_node; ++ const char *property; ++ ++ if (strstr(cmd_line, "console=")) ++ return; ++ /* find the boot console from /chosen/stdout */ ++ if (!of_chosen) ++ return; ++ property = of_get_property(of_chosen, "linux,stdout-path", NULL); ++ if (!property) ++ return; ++ stdout_node = of_find_node_by_path(property); ++ if (!stdout_node) ++ return; ++ property = of_get_property(stdout_node, "device_type", NULL); ++ if (property && strcmp(property, "serial") == 0) { ++ /* ++ * The 9pin connector is either /failsafe or /builtin/serial. ++ * The optional graphics card has also type 'serial' in VGA mode. ++ */ ++ property = of_get_property(stdout_node, "name", NULL); ++ if (property) { ++ if (strcmp(property, "failsafe") == 0) ++ add_preferred_console("ttyPSC", 0, NULL); ++ else { ++ if (strcmp(property, "serial") == 0) { ++ property = of_get_property(stdout_node, "model", NULL); ++ if (property && strcmp(property, "mpc5200-serial") == 0) ++ add_preferred_console("ttyPSC", 0, NULL); ++ } ++ } ++ } ++ } ++ of_node_put(stdout_node); ++#endif ++} ++ + define_machine(efika) + { + .name = EFIKA_PLATFORM_NAME, + .probe = efika_probe, + .setup_arch = efika_setup_arch, + .init = mpc52xx_declare_of_platform_devices, ++ .init_early = efika_init_early, + .show_cpuinfo = efika_show_cpuinfo, + .init_IRQ = mpc52xx_init_irq, + .get_irq = mpc52xx_get_irq, diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-fix-ppc-insn-emulation_mr.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-fix-ppc-insn-emulation_mr.patch new file mode 100644 index 000000000..6acb05a3e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-fix-ppc-insn-emulation_mr.patch @@ -0,0 +1,25 @@ +Subject: Don't emulate mr. instructions +From: Ananth N Mavinakayanahalli +References: 459387 - LTC49903 + +Currently emulate_step() emulates mr. instructions without updating cr0 +and this can be disastrous. Don't emulate mr. + +Signed-off-by: Ananth N Mavinakayanahalli +Signed-off-by: Olaf Hering + +--- + arch/powerpc/lib/sstep.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/powerpc/lib/sstep.c ++++ b/arch/powerpc/lib/sstep.c +@@ -172,6 +172,8 @@ int __kprobes emulate_step(struct pt_reg + } + break; + case 0x378: /* orx */ ++ if (instr & 1) ++ break; + rs = (instr >> 21) & 0x1f; + rb = (instr >> 11) & 0x1f; + if (rs == rb) { /* mr */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-ipic-suspend-without-83xx-fix b/src/patches/suse-2.6.27.31/patches.arch/ppc-ipic-suspend-without-83xx-fix new file mode 100644 index 000000000..6df27772c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-ipic-suspend-without-83xx-fix @@ -0,0 +1,33 @@ +From: Takashi Iwai +Subject: [PATCH] Fix build_error without CONFIG_PPC_83xx +Patch-mainline: +References: + +fsl_deep_sleep() is defined only with CONFIG_PPC_83xx although +CONFIG_IPIC is set for CONFIG_PPC_MPC512x, too. + +Signed-off-by: Takashi Iwai + +--- +--- + arch/powerpc/sysdev/ipic.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/powerpc/sysdev/ipic.c ++++ b/arch/powerpc/sysdev/ipic.c +@@ -920,6 +920,7 @@ static int ipic_suspend(struct sys_devic + ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR); + ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR); + ++#ifdef CONFIG_PPC_83xx + if (fsl_deep_sleep()) { + /* In deep sleep, make sure there can be no + * pending interrupts, as this can cause +@@ -930,6 +931,7 @@ static int ipic_suspend(struct sys_devic + ipic_write(ipic->regs, IPIC_SEMSR, 0); + ipic_write(ipic->regs, IPIC_SERMR, 0); + } ++#endif + + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-memoryless-nodes.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-memoryless-nodes.patch new file mode 100644 index 000000000..be528756c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-memoryless-nodes.patch @@ -0,0 +1,213 @@ +Subject: fix booting with memoryless nodes +From: haveblue@us.ibm.com +References: 443280 - LTC49675 + +I've reproduced this on 2.6.27.7. I'm pretty sure it is caused by this +patch: + +http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=8f64e1f2d1e09267ac926e15090fd505c1c0cbcb + +The problem is that Jon took a loop which was (in psuedocode): + + for_each_node(nid) + NODE_DATA(nid) = careful_alloc(nid); + setup_bootmem(nid); + reserve_node_bootmem(nid); + +and broke it up into: + + for_each_node(nid) + NODE_DATA(nid) = careful_alloc(nid); + setup_bootmem(nid); + for_each_node(nid) + reserve_node_bootmem(nid); + +The issue comes in when the 'careful_alloc()' is called on a node with +no memory. It falls back to using bootmem from a previously-initialized +node. But, bootmem has not yet been reserved when Jon's patch is +applied. It gives back bogus memory (0xc000000000000000) and pukes +later in boot. + +The following patch collapses the loop back together. It also breaks +the mark_reserved_regions_for_nid() code out into a function and adds +some comments. I think a huge part of introducing this bug is because +for loop was too long and hard to read. + +The actual bug fix here is the: + ++ if (end_pfn <= node->node_start_pfn || ++ start_pfn >= node_end_pfn) ++ continue; + +Signed-off-by: Olaf Hering + +--- + arch/powerpc/mm/numa.c | 130 ++++++++++++++++++++++++++++++------------------- + 1 file changed, 82 insertions(+), 48 deletions(-) + +--- a/arch/powerpc/mm/numa.c ++++ b/arch/powerpc/mm/numa.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -867,10 +868,75 @@ static struct notifier_block __cpuinitda + .priority = 1 /* Must run before sched domains notifier. */ + }; + ++static void mark_reserved_regions_for_nid(int nid) ++{ ++ struct pglist_data *node = NODE_DATA(nid); ++ int i; ++ ++ dbg("mark_reserved_regions_for_nid(%d) NODE_DATA: %p\n", nid, node); ++ for (i = 0; i < lmb.reserved.cnt; i++) { ++ unsigned long physbase = lmb.reserved.region[i].base; ++ unsigned long size = lmb.reserved.region[i].size; ++ unsigned long start_pfn = physbase >> PAGE_SHIFT; ++ unsigned long end_pfn = PFN_UP(physbase + size); ++ struct node_active_region node_ar; ++ unsigned long node_end_pfn = node->node_start_pfn + ++ node->node_spanned_pages; ++ ++ /* ++ * Check to make sure that this lmb.reserved area is ++ * within the bounds of the node that we care about. ++ * Checking the nid of the start and end points is not ++ * sufficient because the reserved area could span the ++ * entire node. ++ */ ++ if (end_pfn <= node->node_start_pfn || ++ start_pfn >= node_end_pfn) ++ continue; ++ ++ get_node_active_region(start_pfn, &node_ar); ++ while (start_pfn < end_pfn && ++ node_ar.start_pfn < node_ar.end_pfn) { ++ unsigned long reserve_size = size; ++ /* ++ * if reserved region extends past active region ++ * then trim size to active region ++ */ ++ if (end_pfn > node_ar.end_pfn) ++ reserve_size = (node_ar.end_pfn << PAGE_SHIFT) ++ - physbase; ++ /* ++ * Only worry about *this* node, others may not ++ * yet have valid NODE_DATA(). ++ */ ++ if (node_ar.nid == nid) ++ reserve_bootmem_node(NODE_DATA(node_ar.nid), ++ physbase, reserve_size, ++ BOOTMEM_DEFAULT); ++ /* ++ * if reserved region is contained in the active region ++ * then done. ++ */ ++ if (end_pfn <= node_ar.end_pfn) ++ break; ++ ++ /* ++ * reserved region extends past the active region ++ * get next active region that contains this ++ * reserved region ++ */ ++ start_pfn = node_ar.end_pfn; ++ physbase = start_pfn << PAGE_SHIFT; ++ size = size - reserve_size; ++ get_node_active_region(start_pfn, &node_ar); ++ } ++ } ++} ++ ++ + void __init do_init_bootmem(void) + { + int nid; +- unsigned int i; + + min_low_pfn = 0; + max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT; +@@ -890,9 +956,16 @@ void __init do_init_bootmem(void) + unsigned long bootmem_paddr; + unsigned long bootmap_pages; + ++ dbg("node %d is online\n", nid); + get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); + +- /* Allocate the node structure node local if possible */ ++ /* ++ * Allocate the node structure node local if possible ++ * ++ * Be careful moving this around, as it relies on all ++ * previous nodes' bootmem to be initialized and have ++ * all reserved areas marked. ++ */ + NODE_DATA(nid) = careful_allocation(nid, + sizeof(struct pglist_data), + SMP_CACHE_BYTES, end_pfn); +@@ -924,53 +997,14 @@ void __init do_init_bootmem(void) + start_pfn, end_pfn); + + free_bootmem_with_active_regions(nid, end_pfn); +- } +- +- /* Mark reserved regions */ +- for (i = 0; i < lmb.reserved.cnt; i++) { +- unsigned long physbase = lmb.reserved.region[i].base; +- unsigned long size = lmb.reserved.region[i].size; +- unsigned long start_pfn = physbase >> PAGE_SHIFT; +- unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT); +- struct node_active_region node_ar; +- +- get_node_active_region(start_pfn, &node_ar); +- while (start_pfn < end_pfn && +- node_ar.start_pfn < node_ar.end_pfn) { +- unsigned long reserve_size = size; +- /* +- * if reserved region extends past active region +- * then trim size to active region +- */ +- if (end_pfn > node_ar.end_pfn) +- reserve_size = (node_ar.end_pfn << PAGE_SHIFT) +- - (start_pfn << PAGE_SHIFT); +- dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, +- reserve_size, node_ar.nid); +- reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase, +- reserve_size, BOOTMEM_DEFAULT); +- /* +- * if reserved region is contained in the active region +- * then done. +- */ +- if (end_pfn <= node_ar.end_pfn) +- break; +- +- /* +- * reserved region extends past the active region +- * get next active region that contains this +- * reserved region +- */ +- start_pfn = node_ar.end_pfn; +- physbase = start_pfn << PAGE_SHIFT; +- size = size - reserve_size; +- get_node_active_region(start_pfn, &node_ar); +- } +- +- } +- +- for_each_online_node(nid) ++ /* ++ * Be very careful about moving this around. Future ++ * calls to careful_allocation() depend on this getting ++ * done correctly. ++ */ ++ mark_reserved_regions_for_nid(nid); + sparse_memory_present_with_active_regions(nid); ++ } + } + + void __init paging_init(void) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-of-irq-map.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-of-irq-map.patch new file mode 100644 index 000000000..e7d1755f8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-of-irq-map.patch @@ -0,0 +1,30 @@ +Subject: fix IRQ assignment if interrupts property is missing +From: Adhemerval Zanella Neto +References: 446610 - LTC50006 + +This patch fix the IRQ assign. +If the code can not get "interrupts" property from PCI OF node, +it falls back to standard OF parsing. + +Signed-off-by: Olaf Hering + +--- + arch/powerpc/kernel/prom_parse.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/kernel/prom_parse.c ++++ b/arch/powerpc/kernel/prom_parse.c +@@ -250,8 +250,11 @@ int of_irq_map_pci(struct pci_dev *pdev, + * parsing + */ + dn = pci_device_to_OF_node(pdev); +- if (dn) +- return of_irq_map_one(dn, 0, out_irq); ++ if (dn) { ++ rc = of_irq_map_one(dn, 0, out_irq); ++ if (!rc) ++ return rc; ++ } + + /* Ok, we don't, time to have fun. Let's start by building up an + * interrupt spec. we assume #interrupt-cells is 1, which is standard diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-oprofile-spu-mutex-locking.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-oprofile-spu-mutex-locking.patch new file mode 100644 index 000000000..b4ebaeaa4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-oprofile-spu-mutex-locking.patch @@ -0,0 +1,513 @@ +Subject: [PATCH] powerpc/oprofile: Fix mutex locking for cell spu-oprofile +From: Carl Love +References: 422501 - LTC47617 + +The issue is the SPU code is not holding the kernel mutex lock while +adding samples to the kernel buffer. + +This patch creates per SPU buffers to hold the data. Data +is added to the buffers from in interrupt context. The data +is periodically pushed to the kernel buffer via a new Oprofile +function oprofile_put_buff(). The oprofile_put_buff() function +is called via a work queue enabling the funtion to acquire the +mutex lock. + +The existing user controls for adjusting the per CPU buffer +size is used to control the size of the per SPU buffers. +Similarly, overflows of the SPU buffers are reported by +incrementing the per CPU buffer stats. This eliminates the +need to have architecture specific controls for the per SPU +buffers which is not acceptable to the OProfile user tool +maintainer. + +The export of the oprofile add_event_entry() is removed as it +is no longer needed given this patch. + +Note, this patch has not addressed the issue of indexing arrays +by the spu number. This still needs to be fixed as the spu +numbering is not guarenteed to be 0 to max_num_spus-1. + +Signed-off-by: Carl Love +Signed-off-by: Maynard Johnson +Signed-off-by: Arnd Bergmann +Acked-by: Acked-by: Robert Richter +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Olaf Hering + +--- + arch/powerpc/oprofile/cell/pr_util.h | 13 + + arch/powerpc/oprofile/cell/spu_profiler.c | 4 + arch/powerpc/oprofile/cell/spu_task_sync.c | 236 +++++++++++++++++++++++++---- + drivers/oprofile/buffer_sync.c | 24 ++ + drivers/oprofile/cpu_buffer.c | 15 + + drivers/oprofile/event_buffer.h | 7 + include/linux/oprofile.h | 16 + + 7 files changed, 279 insertions(+), 36 deletions(-) + +--- a/arch/powerpc/oprofile/cell/pr_util.h ++++ b/arch/powerpc/oprofile/cell/pr_util.h +@@ -24,6 +24,11 @@ + #define SKIP_GENERIC_SYNC 0 + #define SYNC_START_ERROR -1 + #define DO_GENERIC_SYNC 1 ++#define SPUS_PER_NODE 8 ++#define DEFAULT_TIMER_EXPIRE (HZ / 10) ++ ++extern struct delayed_work spu_work; ++extern int spu_prof_running; + + struct spu_overlay_info { /* map of sections within an SPU overlay */ + unsigned int vma; /* SPU virtual memory address from elf */ +@@ -62,6 +67,14 @@ struct vma_to_fileoffset_map { /* map of + + }; + ++struct spu_buffer { ++ int last_guard_val; ++ int ctx_sw_seen; ++ unsigned long *buff; ++ unsigned int head, tail; ++}; ++ ++ + /* The three functions below are for maintaining and accessing + * the vma-to-fileoffset map. + */ +--- a/arch/powerpc/oprofile/cell/spu_profiler.c ++++ b/arch/powerpc/oprofile/cell/spu_profiler.c +@@ -24,12 +24,11 @@ + + static u32 *samples; + +-static int spu_prof_running; ++int spu_prof_running; + static unsigned int profiling_interval; + + #define NUM_SPU_BITS_TRBUF 16 + #define SPUS_PER_TB_ENTRY 4 +-#define SPUS_PER_NODE 8 + + #define SPU_PC_MASK 0xFFFF + +@@ -209,6 +208,7 @@ int start_spu_profiling(unsigned int cyc + + spu_prof_running = 1; + hrtimer_start(&timer, kt, HRTIMER_MODE_REL); ++ schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE); + + return 0; + } +--- a/arch/powerpc/oprofile/cell/spu_task_sync.c ++++ b/arch/powerpc/oprofile/cell/spu_task_sync.c +@@ -35,7 +35,102 @@ static DEFINE_SPINLOCK(buffer_lock); + static DEFINE_SPINLOCK(cache_lock); + static int num_spu_nodes; + int spu_prof_num_nodes; +-int last_guard_val[MAX_NUMNODES * 8]; ++ ++struct spu_buffer spu_buff[MAX_NUMNODES * SPUS_PER_NODE]; ++struct delayed_work spu_work; ++static unsigned max_spu_buff; ++ ++static void spu_buff_add(unsigned long int value, int spu) ++{ ++ /* spu buff is a circular buffer. Add entries to the ++ * head. Head is the index to store the next value. ++ * The buffer is full when there is one available entry ++ * in the queue, i.e. head and tail can't be equal. ++ * That way we can tell the difference between the ++ * buffer being full versus empty. ++ * ++ * ASSUPTION: the buffer_lock is held when this function ++ * is called to lock the buffer, head and tail. ++ */ ++ int full = 1; ++ ++ if (spu_buff[spu].head >= spu_buff[spu].tail) { ++ if ((spu_buff[spu].head - spu_buff[spu].tail) ++ < (max_spu_buff - 1)) ++ full = 0; ++ ++ } else if (spu_buff[spu].tail > spu_buff[spu].head) { ++ if ((spu_buff[spu].tail - spu_buff[spu].head) ++ > 1) ++ full = 0; ++ } ++ ++ if (!full) { ++ spu_buff[spu].buff[spu_buff[spu].head] = value; ++ spu_buff[spu].head++; ++ ++ if (spu_buff[spu].head >= max_spu_buff) ++ spu_buff[spu].head = 0; ++ } else { ++ /* From the user's perspective make the SPU buffer ++ * size management/overflow look like we are using ++ * per cpu buffers. The user uses the same ++ * per cpu parameter to adjust the SPU buffer size. ++ * Increment the sample_lost_overflow to inform ++ * the user the buffer size needs to be increased. ++ */ ++ oprofile_cpu_buffer_inc_smpl_lost(); ++ } ++} ++ ++/* This function copies the per SPU buffers to the ++ * OProfile kernel buffer. ++ */ ++void sync_spu_buff(void) ++{ ++ int spu; ++ unsigned long flags; ++ int curr_head; ++ ++ for (spu = 0; spu < num_spu_nodes; spu++) { ++ /* In case there was an issue and the buffer didn't ++ * get created skip it. ++ */ ++ if (spu_buff[spu].buff == NULL) ++ continue; ++ ++ /* Hold the lock to make sure the head/tail ++ * doesn't change while spu_buff_add() is ++ * deciding if the buffer is full or not. ++ * Being a little paranoid. ++ */ ++ spin_lock_irqsave(&buffer_lock, flags); ++ curr_head = spu_buff[spu].head; ++ spin_unlock_irqrestore(&buffer_lock, flags); ++ ++ /* Transfer the current contents to the kernel buffer. ++ * data can still be added to the head of the buffer. ++ */ ++ oprofile_put_buff(spu_buff[spu].buff, ++ spu_buff[spu].tail, ++ curr_head, max_spu_buff); ++ ++ spin_lock_irqsave(&buffer_lock, flags); ++ spu_buff[spu].tail = curr_head; ++ spin_unlock_irqrestore(&buffer_lock, flags); ++ } ++ ++} ++ ++static void wq_sync_spu_buff(struct work_struct *work) ++{ ++ /* move data from spu buffers to kernel buffer */ ++ sync_spu_buff(); ++ ++ /* only reschedule if profiling is not done */ ++ if (spu_prof_running) ++ schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE); ++} + + /* Container for caching information about an active SPU task. */ + struct cached_info { +@@ -305,14 +400,21 @@ static int process_context_switch(struct + + /* Record context info in event buffer */ + spin_lock_irqsave(&buffer_lock, flags); +- add_event_entry(ESCAPE_CODE); +- add_event_entry(SPU_CTX_SWITCH_CODE); +- add_event_entry(spu->number); +- add_event_entry(spu->pid); +- add_event_entry(spu->tgid); +- add_event_entry(app_dcookie); +- add_event_entry(spu_cookie); +- add_event_entry(offset); ++ spu_buff_add(ESCAPE_CODE, spu->number); ++ spu_buff_add(SPU_CTX_SWITCH_CODE, spu->number); ++ spu_buff_add(spu->number, spu->number); ++ spu_buff_add(spu->pid, spu->number); ++ spu_buff_add(spu->tgid, spu->number); ++ spu_buff_add(app_dcookie, spu->number); ++ spu_buff_add(spu_cookie, spu->number); ++ spu_buff_add(offset, spu->number); ++ ++ /* Set flag to indicate SPU PC data can now be written out. If ++ * the SPU program counter data is seen before an SPU context ++ * record is seen, the postprocessing will fail. ++ */ ++ spu_buff[spu->number].ctx_sw_seen = 1; ++ + spin_unlock_irqrestore(&buffer_lock, flags); + smp_wmb(); /* insure spu event buffer updates are written */ + /* don't want entries intermingled... */ +@@ -360,6 +462,47 @@ static int number_of_online_nodes(void) + return nodes; + } + ++static int oprofile_spu_buff_create(void) ++{ ++ int spu; ++ ++ max_spu_buff = oprofile_get_cpu_buffer_size(); ++ ++ for (spu = 0; spu < num_spu_nodes; spu++) { ++ /* create circular buffers to store the data in. ++ * use locks to manage accessing the buffers ++ */ ++ spu_buff[spu].head = 0; ++ spu_buff[spu].tail = 0; ++ ++ /* ++ * Create a buffer for each SPU. Can't reliably ++ * create a single buffer for all spus due to not ++ * enough contiguous kernel memory. ++ */ ++ ++ spu_buff[spu].buff = kzalloc((max_spu_buff ++ * sizeof(unsigned long)), ++ GFP_KERNEL); ++ ++ if (!spu_buff[spu].buff) { ++ printk(KERN_ERR "SPU_PROF: " ++ "%s, line %d: oprofile_spu_buff_create " ++ "failed to allocate spu buffer %d.\n", ++ __func__, __LINE__, spu); ++ ++ /* release the spu buffers that have been allocated */ ++ while (spu >= 0) { ++ kfree(spu_buff[spu].buff); ++ spu_buff[spu].buff = 0; ++ spu--; ++ } ++ return -ENOMEM; ++ } ++ } ++ return 0; ++} ++ + /* The main purpose of this function is to synchronize + * OProfile with SPUFS by registering to be notified of + * SPU task switches. +@@ -372,20 +515,35 @@ static int number_of_online_nodes(void) + */ + int spu_sync_start(void) + { +- int k; ++ int spu; + int ret = SKIP_GENERIC_SYNC; + int register_ret; + unsigned long flags = 0; + + spu_prof_num_nodes = number_of_online_nodes(); + num_spu_nodes = spu_prof_num_nodes * 8; ++ INIT_DELAYED_WORK(&spu_work, wq_sync_spu_buff); ++ ++ /* create buffer for storing the SPU data to put in ++ * the kernel buffer. ++ */ ++ ret = oprofile_spu_buff_create(); ++ if (ret) ++ goto out; + + spin_lock_irqsave(&buffer_lock, flags); +- add_event_entry(ESCAPE_CODE); +- add_event_entry(SPU_PROFILING_CODE); +- add_event_entry(num_spu_nodes); ++ for (spu = 0; spu < num_spu_nodes; spu++) { ++ spu_buff_add(ESCAPE_CODE, spu); ++ spu_buff_add(SPU_PROFILING_CODE, spu); ++ spu_buff_add(num_spu_nodes, spu); ++ } + spin_unlock_irqrestore(&buffer_lock, flags); + ++ for (spu = 0; spu < num_spu_nodes; spu++) { ++ spu_buff[spu].ctx_sw_seen = 0; ++ spu_buff[spu].last_guard_val = 0; ++ } ++ + /* Register for SPU events */ + register_ret = spu_switch_event_register(&spu_active); + if (register_ret) { +@@ -393,8 +551,6 @@ int spu_sync_start(void) + goto out; + } + +- for (k = 0; k < (MAX_NUMNODES * 8); k++) +- last_guard_val[k] = 0; + pr_debug("spu_sync_start -- running.\n"); + out: + return ret; +@@ -446,13 +602,20 @@ void spu_sync_buffer(int spu_num, unsign + * use. We need to discard samples taken during the time + * period which an overlay occurs (i.e., guard value changes). + */ +- if (grd_val && grd_val != last_guard_val[spu_num]) { +- last_guard_val[spu_num] = grd_val; ++ if (grd_val && grd_val != spu_buff[spu_num].last_guard_val) { ++ spu_buff[spu_num].last_guard_val = grd_val; + /* Drop the rest of the samples. */ + break; + } + +- add_event_entry(file_offset | spu_num_shifted); ++ /* We must ensure that the SPU context switch has been written ++ * out before samples for the SPU. Otherwise, the SPU context ++ * information is not available and the postprocessing of the ++ * SPU PC will fail with no available anonymous map information. ++ */ ++ if (spu_buff[spu_num].ctx_sw_seen) ++ spu_buff_add((file_offset | spu_num_shifted), ++ spu_num); + } + spin_unlock(&buffer_lock); + out: +@@ -463,20 +626,41 @@ out: + int spu_sync_stop(void) + { + unsigned long flags = 0; +- int ret = spu_switch_event_unregister(&spu_active); +- if (ret) { ++ int ret; ++ int k; ++ ++ ret = spu_switch_event_unregister(&spu_active); ++ ++ if (ret) + printk(KERN_ERR "SPU_PROF: " +- "%s, line %d: spu_switch_event_unregister returned %d\n", +- __func__, __LINE__, ret); +- goto out; +- } ++ "%s, line %d: spu_switch_event_unregister " \ ++ "returned %d\n", ++ __func__, __LINE__, ret); ++ ++ /* flush any remaining data in the per SPU buffers */ ++ sync_spu_buff(); + + spin_lock_irqsave(&cache_lock, flags); + ret = release_cached_info(RELEASE_ALL); + spin_unlock_irqrestore(&cache_lock, flags); +-out: ++ ++ /* remove scheduled work queue item rather then waiting ++ * for every queued entry to execute. Then flush pending ++ * system wide buffer to event buffer. ++ */ ++ cancel_delayed_work(&spu_work); ++ ++ for (k = 0; k < num_spu_nodes; k++) { ++ spu_buff[k].ctx_sw_seen = 0; ++ ++ /* ++ * spu_sys_buff will be null if there was a problem ++ * allocating the buffer. Only delete if it exists. ++ */ ++ kfree(spu_buff[k].buff); ++ spu_buff[k].buff = 0; ++ } + pr_debug("spu_sync_stop -- done.\n"); + return ret; + } + +- +--- a/drivers/oprofile/buffer_sync.c ++++ b/drivers/oprofile/buffer_sync.c +@@ -551,3 +551,27 @@ void sync_buffer(int cpu) + + mutex_unlock(&buffer_mutex); + } ++ ++/* The function can be used to add a buffer worth of data directly to ++ * the kernel buffer. The buffer is assumed to be a circular buffer. ++ * Take the entries from index start and end at index end, wrapping ++ * at max_entries. ++ */ ++void oprofile_put_buff(unsigned long *buf, unsigned int start, ++ unsigned int stop, unsigned int max) ++{ ++ int i; ++ ++ i = start; ++ ++ mutex_lock(&buffer_mutex); ++ while (i != stop) { ++ add_event_entry(buf[i++]); ++ ++ if (i >= max) ++ i = 0; ++ } ++ ++ mutex_unlock(&buffer_mutex); ++} ++ +--- a/drivers/oprofile/cpu_buffer.c ++++ b/drivers/oprofile/cpu_buffer.c +@@ -37,13 +37,26 @@ static int work_enabled; + void free_cpu_buffers(void) + { + int i; +- ++ + for_each_online_cpu(i) { + vfree(per_cpu(cpu_buffer, i).buffer); + per_cpu(cpu_buffer, i).buffer = NULL; + } + } + ++unsigned long oprofile_get_cpu_buffer_size(void) ++{ ++ return fs_cpu_buffer_size; ++} ++ ++void oprofile_cpu_buffer_inc_smpl_lost(void) ++{ ++ struct oprofile_cpu_buffer *cpu_buf ++ = &__get_cpu_var(cpu_buffer); ++ ++ cpu_buf->sample_lost_overflow++; ++} ++ + int alloc_cpu_buffers(void) + { + int i; +--- a/drivers/oprofile/event_buffer.h ++++ b/drivers/oprofile/event_buffer.h +@@ -17,6 +17,13 @@ int alloc_event_buffer(void); + + void free_event_buffer(void); + ++/** ++ * Add data to the event buffer. ++ * The data passed is free-form, but typically consists of ++ * file offsets, dcookies, context information, and ESCAPE codes. ++ */ ++void add_event_entry(unsigned long data); ++ + /* wake up the process sleeping on the event file */ + void wake_up_buffer_waiter(void); + +--- a/include/linux/oprofile.h ++++ b/include/linux/oprofile.h +@@ -84,13 +84,6 @@ int oprofile_arch_init(struct oprofile_o + void oprofile_arch_exit(void); + + /** +- * Add data to the event buffer. +- * The data passed is free-form, but typically consists of +- * file offsets, dcookies, context information, and ESCAPE codes. +- */ +-void add_event_entry(unsigned long data); +- +-/** + * Add a sample. This may be called from any context. Pass + * smp_processor_id() as cpu. + */ +@@ -160,5 +153,14 @@ int oprofilefs_ulong_from_user(unsigned + + /** lock for read/write safety */ + extern spinlock_t oprofilefs_lock; ++ ++/** ++ * Add the contents of a circular buffer to the event buffer. ++ */ ++void oprofile_put_buff(unsigned long *buf, unsigned int start, ++ unsigned int stop, unsigned int max); ++ ++unsigned long oprofile_get_cpu_buffer_size(void); ++void oprofile_cpu_buffer_inc_smpl_lost(void); + + #endif /* OPROFILE_H */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-oprofile-spu.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-oprofile-spu.patch new file mode 100644 index 000000000..3aea19e39 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-oprofile-spu.patch @@ -0,0 +1,64 @@ +Subject: Incorrect local array size in activate spu profiling function +From: Carl Love +References: 439553 - LTC48925 + +Updated the patch to address comments by Michael Ellerman. +Specifically, changed upper limit in for loop to +ARRAY_SIZE() macro and added a check to make sure the +number of events specified by the user, which is used as +the max for indexing various arrays, is no bigger then the +declared size of the arrays. + +The size of the pm_signal_local array should be equal to the +number of SPUs being configured in the array. Currently, the +array is of size 4 (NR_PHYS_CTRS) but being indexed by a for +loop from 0 to 7 (NUM_SPUS_PER_NODE). + +Signed-off-by: Carl Love +Signed-off-by: Olaf Hering + +--- + arch/powerpc/oprofile/op_model_cell.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +--- a/arch/powerpc/oprofile/op_model_cell.c ++++ b/arch/powerpc/oprofile/op_model_cell.c +@@ -582,6 +582,13 @@ static int cell_reg_setup(struct op_coun + + num_counters = num_ctrs; + ++ if (unlikely(num_ctrs > NR_PHYS_CTRS)) { ++ printk(KERN_ERR ++ "%s: Oprofile, number of specified events " \ ++ "exceeds number of physical counters\n", ++ __func__); ++ return -EIO; ++ } + pm_regs.group_control = 0; + pm_regs.debug_bus_control = 0; + +@@ -830,13 +837,13 @@ static int calculate_lfsr(int n) + static int pm_rtas_activate_spu_profiling(u32 node) + { + int ret, i; +- struct pm_signal pm_signal_local[NR_PHYS_CTRS]; ++ struct pm_signal pm_signal_local[NUM_SPUS_PER_NODE]; + + /* + * Set up the rtas call to configure the debug bus to + * route the SPU PCs. Setup the pm_signal for each SPU + */ +- for (i = 0; i < NUM_SPUS_PER_NODE; i++) { ++ for (i = 0; i < ARRAY_SIZE(pm_signal_local); i++) { + pm_signal_local[i].cpu = node; + pm_signal_local[i].signal_group = 41; + /* spu i on word (i/2) */ +@@ -848,7 +855,7 @@ static int pm_rtas_activate_spu_profilin + + ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE, + PASSTHRU_ENABLE, pm_signal_local, +- (NUM_SPUS_PER_NODE ++ (ARRAY_SIZE(pm_signal_local) + * sizeof(struct pm_signal))); + + if (unlikely(ret)) { diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-optimize-sync.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-optimize-sync.patch new file mode 100644 index 000000000..fa436d01e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-optimize-sync.patch @@ -0,0 +1,240 @@ +Subject: Optimise smp_{r,w}mb and mutex +From: Nick Piggin +References: 471222 - LTC51356 + + powerpc: Optimise smp_wmb + + Change 2d1b2027626d5151fff8ef7c06ca8e7876a1a510 ("powerpc: Fixup + lwsync at runtime") removed __SUBARCH_HAS_LWSYNC, causing smp_wmb to + revert back to eieio for all CPUs. This restores the behaviour + intorduced in 74f0609526afddd88bef40b651da24f3167b10b2 ("powerpc: + Optimise smp_wmb on 64-bit processors"). + + powerpc: Optimise smp_rmb + + After commit 598056d5af8fef1dbe8f96f5c2b641a528184e5a ("[POWERPC] Fix + rmb to order cacheable vs. noncacheable"), rmb() becomes a sync + instruction, which is needed to order cacheable vs noncacheable loads. + However smp_rmb() is #defined to rmb(), and smp_rmb() can be an + lwsync. + + This restores smp_rmb() performance by using lwsync there and updates + the comments. + + powerpc: Optimise mutex + + This implements an optimised mutex fastpath for powerpc, making use of + acquire and release barrier semantics. This takes the mutex + lock+unlock benchmark from 203 to 173 cycles on a G5. + + Signed-off-by: Nick Piggin + Signed-off-by: Paul Mackerras +Signed-off-by: Olaf Hering + +--- + arch/powerpc/include/asm/mutex.h | 135 ++++++++++++++++++++++++++++++++++++-- + arch/powerpc/include/asm/synch.h | 4 + + arch/powerpc/include/asm/system.h | 24 +++--- + 3 files changed, 147 insertions(+), 16 deletions(-) + +--- a/arch/powerpc/include/asm/mutex.h ++++ b/arch/powerpc/include/asm/mutex.h +@@ -1,9 +1,134 @@ + /* +- * Pull in the generic implementation for the mutex fastpath. ++ * Optimised mutex implementation of include/asm-generic/mutex-dec.h algorithm ++ */ ++#ifndef _ASM_POWERPC_MUTEX_H ++#define _ASM_POWERPC_MUTEX_H ++ ++static inline int __mutex_cmpxchg_lock(atomic_t *v, int old, int new) ++{ ++ int t; ++ ++ __asm__ __volatile__ ( ++"1: lwarx %0,0,%1 # mutex trylock\n\ ++ cmpw 0,%0,%2\n\ ++ bne- 2f\n" ++ PPC405_ERR77(0,%1) ++" stwcx. %3,0,%1\n\ ++ bne- 1b" ++ ISYNC_ON_SMP ++ "\n\ ++2:" ++ : "=&r" (t) ++ : "r" (&v->counter), "r" (old), "r" (new) ++ : "cc", "memory"); ++ ++ return t; ++} ++ ++static inline int __mutex_dec_return_lock(atomic_t *v) ++{ ++ int t; ++ ++ __asm__ __volatile__( ++"1: lwarx %0,0,%1 # mutex lock\n\ ++ addic %0,%0,-1\n" ++ PPC405_ERR77(0,%1) ++" stwcx. %0,0,%1\n\ ++ bne- 1b" ++ ISYNC_ON_SMP ++ : "=&r" (t) ++ : "r" (&v->counter) ++ : "cc", "memory"); ++ ++ return t; ++} ++ ++static inline int __mutex_inc_return_unlock(atomic_t *v) ++{ ++ int t; ++ ++ __asm__ __volatile__( ++ LWSYNC_ON_SMP ++"1: lwarx %0,0,%1 # mutex unlock\n\ ++ addic %0,%0,1\n" ++ PPC405_ERR77(0,%1) ++" stwcx. %0,0,%1 \n\ ++ bne- 1b" ++ : "=&r" (t) ++ : "r" (&v->counter) ++ : "cc", "memory"); ++ ++ return t; ++} ++ ++/** ++ * __mutex_fastpath_lock - try to take the lock by moving the count ++ * from 1 to a 0 value ++ * @count: pointer of type atomic_t ++ * @fail_fn: function to call if the original value was not 1 ++ * ++ * Change the count from 1 to a value lower than 1, and call if ++ * it wasn't 1 originally. This function MUST leave the value lower than ++ * 1 even when the "1" assertion wasn't true. ++ */ ++static inline void ++__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) ++{ ++ if (unlikely(__mutex_dec_return_lock(count) < 0)) ++ fail_fn(count); ++} ++ ++/** ++ * __mutex_fastpath_lock_retval - try to take the lock by moving the count ++ * from 1 to a 0 value ++ * @count: pointer of type atomic_t ++ * @fail_fn: function to call if the original value was not 1 ++ * ++ * Change the count from 1 to a value lower than 1, and call if ++ * it wasn't 1 originally. This function returns 0 if the fastpath succeeds, ++ * or anything the slow path function returns. ++ */ ++static inline int ++__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) ++{ ++ if (unlikely(__mutex_dec_return_lock(count) < 0)) ++ return fail_fn(count); ++ return 0; ++} ++ ++/** ++ * __mutex_fastpath_unlock - try to promote the count from 0 to 1 ++ * @count: pointer of type atomic_t ++ * @fail_fn: function to call if the original value was not 0 ++ * ++ * Try to promote the count from 0 to 1. If it wasn't 0, call . ++ * In the failure case, this function is allowed to either set the value to ++ * 1, or to set it to a value lower than 1. ++ */ ++static inline void ++__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) ++{ ++ if (unlikely(__mutex_inc_return_unlock(count) <= 0)) ++ fail_fn(count); ++} ++ ++#define __mutex_slowpath_needs_to_unlock() 1 ++ ++/** ++ * __mutex_fastpath_trylock - try to acquire the mutex, without waiting ++ * ++ * @count: pointer of type atomic_t ++ * @fail_fn: fallback function + * +- * TODO: implement optimized primitives instead, or leave the generic +- * implementation in place, or pick the atomic_xchg() based generic +- * implementation. (see asm-generic/mutex-xchg.h for details) ++ * Change the count from 1 to 0, and return 1 (success), or if the count ++ * was not 1, then return 0 (failure). + */ ++static inline int ++__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) ++{ ++ if (likely(__mutex_cmpxchg_lock(count, 1, 0) == 1)) ++ return 1; ++ return 0; ++} + +-#include ++#endif +--- a/arch/powerpc/include/asm/synch.h ++++ b/arch/powerpc/include/asm/synch.h +@@ -5,6 +5,10 @@ + #include + #include + ++#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) ++#define __SUBARCH_HAS_LWSYNC ++#endif ++ + #ifndef __ASSEMBLY__ + extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; + extern void do_lwsync_fixups(unsigned long value, void *fixup_start, +--- a/arch/powerpc/include/asm/system.h ++++ b/arch/powerpc/include/asm/system.h +@@ -23,15 +23,17 @@ + * read_barrier_depends() prevents data-dependent loads being reordered + * across this point (nop on PPC). + * +- * We have to use the sync instructions for mb(), since lwsync doesn't +- * order loads with respect to previous stores. Lwsync is fine for +- * rmb(), though. Note that rmb() actually uses a sync on 32-bit +- * architectures. ++ * *mb() variants without smp_ prefix must order all types of memory ++ * operations with one another. sync is the only instruction sufficient ++ * to do this. + * +- * For wmb(), we use sync since wmb is used in drivers to order +- * stores to system memory with respect to writes to the device. +- * However, smp_wmb() can be a lighter-weight lwsync or eieio barrier +- * on SMP since it is only used to order updates to system memory. ++ * For the smp_ barriers, ordering is for cacheable memory operations ++ * only. We have to use the sync instruction for smp_mb(), since lwsync ++ * doesn't order loads with respect to previous stores. Lwsync can be ++ * used for smp_rmb() and smp_wmb(). ++ * ++ * However, on CPUs that don't support lwsync, lwsync actually maps to a ++ * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio. + */ + #define mb() __asm__ __volatile__ ("sync" : : : "memory") + #define rmb() __asm__ __volatile__ ("sync" : : : "memory") +@@ -45,14 +47,14 @@ + #ifdef CONFIG_SMP + + #ifdef __SUBARCH_HAS_LWSYNC +-# define SMPWMB lwsync ++# define SMPWMB LWSYNC + #else + # define SMPWMB eieio + #endif + + #define smp_mb() mb() +-#define smp_rmb() rmb() +-#define smp_wmb() __asm__ __volatile__ (__stringify(SMPWMB) : : :"memory") ++#define smp_rmb() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory") ++#define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory") + #define smp_read_barrier_depends() read_barrier_depends() + #else + #define smp_mb() barrier() diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pcibios_allocate_bus_resources.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pcibios_allocate_bus_resources.patch new file mode 100644 index 000000000..de7b50d7b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pcibios_allocate_bus_resources.patch @@ -0,0 +1,178 @@ +Subject: Fix DLPAR +From: Benjamin Herrenschmidt +References: 439491 + +Signed-off-by: Olaf Hering +--- + arch/powerpc/include/asm/pci.h | 2 + arch/powerpc/kernel/pci-common.c | 110 ++++++++++++++--------------- + arch/powerpc/platforms/pseries/pci_dlpar.c | 2 + 3 files changed, 59 insertions(+), 55 deletions(-) + +--- a/arch/powerpc/include/asm/pci.h ++++ b/arch/powerpc/include/asm/pci.h +@@ -196,6 +196,8 @@ extern void pcibios_setup_new_device(str + + extern void pcibios_claim_one_bus(struct pci_bus *b); + ++extern void pcibios_allocate_bus_resources(struct pci_bus *bus); ++ + extern void pcibios_resource_survey(void); + + extern struct pci_controller *init_phb_dynamic(struct device_node *dn); +--- a/arch/powerpc/kernel/pci-common.c ++++ b/arch/powerpc/kernel/pci-common.c +@@ -986,69 +986,66 @@ static int __init reparent_resources(str + * as well. + */ + +-static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) ++void pcibios_allocate_bus_resources(struct pci_bus *bus) + { +- struct pci_bus *bus; ++ struct pci_bus *b; + int i; + struct resource *res, *pr; + +- /* Depth-First Search on bus tree */ +- list_for_each_entry(bus, bus_list, node) { +- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { +- if ((res = bus->resource[i]) == NULL || !res->flags +- || res->start > res->end) +- continue; +- if (bus->parent == NULL) +- pr = (res->flags & IORESOURCE_IO) ? +- &ioport_resource : &iomem_resource; +- else { +- /* Don't bother with non-root busses when +- * re-assigning all resources. We clear the +- * resource flags as if they were colliding +- * and as such ensure proper re-allocation +- * later. ++ for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { ++ if ((res = bus->resource[i]) == NULL || !res->flags ++ || res->start > res->end) ++ continue; ++ if (bus->parent == NULL) ++ pr = (res->flags & IORESOURCE_IO) ? ++ &ioport_resource : &iomem_resource; ++ else { ++ /* Don't bother with non-root busses when ++ * re-assigning all resources. We clear the ++ * resource flags as if they were colliding ++ * and as such ensure proper re-allocation ++ * later. ++ */ ++ if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC) ++ goto clear_resource; ++ pr = pci_find_parent_resource(bus->self, res); ++ if (pr == res) { ++ /* this happens when the generic PCI ++ * code (wrongly) decides that this ++ * bridge is transparent -- paulus + */ +- if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC) +- goto clear_resource; +- pr = pci_find_parent_resource(bus->self, res); +- if (pr == res) { +- /* this happens when the generic PCI +- * code (wrongly) decides that this +- * bridge is transparent -- paulus +- */ +- continue; +- } ++ continue; + } ++ } + +- DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " +- "[0x%x], parent %p (%s)\n", +- bus->self ? pci_name(bus->self) : "PHB", +- bus->number, i, +- (unsigned long long)res->start, +- (unsigned long long)res->end, +- (unsigned int)res->flags, +- pr, (pr && pr->name) ? pr->name : "nil"); +- +- if (pr && !(pr->flags & IORESOURCE_UNSET)) { +- if (request_resource(pr, res) == 0) +- continue; +- /* +- * Must be a conflict with an existing entry. +- * Move that entry (or entries) under the +- * bridge resource and try again. +- */ +- if (reparent_resources(pr, res) == 0) +- continue; +- } +- printk(KERN_WARNING +- "PCI: Cannot allocate resource region " +- "%d of PCI bridge %d, will remap\n", +- i, bus->number); +-clear_resource: +- res->flags = 0; ++ DBG("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx " ++ "[0x%x], parent %p (%s)\n", ++ bus->self ? pci_name(bus->self) : "PHB", ++ bus->number, i, ++ (unsigned long long)res->start, ++ (unsigned long long)res->end, ++ (unsigned int)res->flags, ++ pr, (pr && pr->name) ? pr->name : "nil"); ++ ++ if (pr && !(pr->flags & IORESOURCE_UNSET)) { ++ if (request_resource(pr, res) == 0) ++ continue; ++ /* ++ * Must be a conflict with an existing entry. ++ * Move that entry (or entries) under the ++ * bridge resource and try again. ++ */ ++ if (reparent_resources(pr, res) == 0) ++ continue; + } +- pcibios_allocate_bus_resources(&bus->children); ++ printk(KERN_WARNING "PCI: Cannot allocate resource region " ++ "%d of PCI bridge %d, will remap\n", i, bus->number); ++clear_resource: ++ res->flags = 0; + } ++ ++ list_for_each_entry(b, &bus->children, node) ++ pcibios_allocate_bus_resources(b); + } + + static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) +@@ -1119,10 +1116,13 @@ static void __init pcibios_allocate_reso + + void __init pcibios_resource_survey(void) + { ++ struct pci_bus *b; ++ + /* Allocate and assign resources. If we re-assign everything, then + * we skip the allocate phase + */ +- pcibios_allocate_bus_resources(&pci_root_buses); ++ list_for_each_entry(b, &pci_root_buses, node) ++ pcibios_allocate_bus_resources(b); + + if (!(ppc_pci_flags & PPC_PCI_REASSIGN_ALL_RSRC)) { + pcibios_allocate_resources(0); +--- a/arch/powerpc/platforms/pseries/pci_dlpar.c ++++ b/arch/powerpc/platforms/pseries/pci_dlpar.c +@@ -189,6 +189,7 @@ struct pci_controller * __devinit init_p + { + struct pci_controller *phb; + int primary; ++ struct pci_bus *b; + + primary = list_empty(&hose_list); + phb = pcibios_alloc_controller(dn); +@@ -203,6 +204,7 @@ struct pci_controller * __devinit init_p + eeh_add_device_tree_early(dn); + + scan_phb(phb); ++ pcibios_allocate_bus_resources(phb->bus); + pcibios_fixup_new_pci_devices(phb->bus); + pci_bus_add_devices(phb->bus); + eeh_add_device_tree_late(phb->bus); diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pegasos-console-autodetection.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pegasos-console-autodetection.patch new file mode 100644 index 000000000..a0f0ea738 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pegasos-console-autodetection.patch @@ -0,0 +1,19 @@ +From: olh@suse.de +Subject: force speed to fix autodetection on pegasos2 +Patch-mainline: never + +--- + arch/powerpc/platforms/chrp/setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/platforms/chrp/setup.c ++++ b/arch/powerpc/platforms/chrp/setup.c +@@ -295,7 +295,7 @@ static void chrp_init_early(void) + if (!property) + goto out_put; + if (!strcmp(property, "failsafe") || !strcmp(property, "serial")) +- add_preferred_console("ttyS", 0, NULL); ++ add_preferred_console("ttyS", 0, "115200"); + out_put: + of_node_put(node); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-powerpc-debug-pci-hotplug.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-powerpc-debug-pci-hotplug.patch new file mode 100644 index 000000000..bbc05332a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-powerpc-debug-pci-hotplug.patch @@ -0,0 +1,834 @@ +Subject: Fix DLPAR +From: Benjamin Herrenschmidt +References: 439491 + +Signed-off-by: Olaf Hering +--- + arch/powerpc/include/asm/pci-bridge.h | 4 + arch/powerpc/include/asm/pci.h | 10 + + arch/powerpc/kernel/pci-common.c | 124 ++++++++++++---------- + arch/powerpc/kernel/pci_32.c | 6 - + arch/powerpc/kernel/pci_64.c | 27 +++- + arch/powerpc/kernel/rtas_pci.c | 48 -------- + arch/powerpc/platforms/pseries/eeh.c | 44 ++++--- + arch/powerpc/platforms/pseries/pci_dlpar.c | 163 +++++++++++++++-------------- + drivers/pci/hotplug/rpadlpar_core.c | 49 +++++--- + drivers/pci/hotplug/rpaphp_slot.c | 4 + 10 files changed, 245 insertions(+), 234 deletions(-) + +--- a/arch/powerpc/include/asm/pci-bridge.h ++++ b/arch/powerpc/include/asm/pci-bridge.h +@@ -234,9 +234,7 @@ extern void pcibios_remove_pci_devices(s + + /** Discover new pci devices under this bus, and add them */ + extern void pcibios_add_pci_devices(struct pci_bus *bus); +-extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus); +- +-extern int pcibios_remove_root_bus(struct pci_controller *phb); ++extern void pcibios_finish_adding_new_bus(struct pci_bus *bus); + + static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus) + { +--- a/arch/powerpc/include/asm/pci.h ++++ b/arch/powerpc/include/asm/pci.h +@@ -201,6 +201,7 @@ extern void pcibios_allocate_bus_resourc + extern void pcibios_resource_survey(void); + + extern struct pci_controller *init_phb_dynamic(struct device_node *dn); ++extern int remove_phb_dynamic(struct pci_controller *phb); + + extern struct pci_dev *of_create_pci_dev(struct device_node *node, + struct pci_bus *bus, int devfn); +@@ -208,7 +209,8 @@ extern struct pci_dev *of_create_pci_dev + extern void of_scan_pci_bridge(struct device_node *node, + struct pci_dev *dev); + +-extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); ++extern void of_scan_bus(struct device_node *node, struct pci_bus *bus, ++ int rescan_existing); + + extern int pci_read_irq_line(struct pci_dev *dev); + +@@ -223,8 +225,10 @@ extern void pci_resource_to_user(const s + const struct resource *rsrc, + resource_size_t *start, resource_size_t *end); + +-extern void pcibios_do_bus_setup(struct pci_bus *bus); +-extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus); ++extern void pcibios_do_bus_setup_self(struct pci_bus *bus); ++extern void pcibios_do_bus_setup_devices(struct pci_bus *bus); ++extern void pcibios_fixup_bus_self(struct pci_bus *bus); ++extern void pcibios_fixup_bus_devices(struct pci_bus *bus); + + #endif /* __KERNEL__ */ + #endif /* __ASM_POWERPC_PCI_H */ +--- a/arch/powerpc/kernel/pci_32.c ++++ b/arch/powerpc/kernel/pci_32.c +@@ -418,7 +418,7 @@ static int __init pcibios_init(void) + + subsys_initcall(pcibios_init); + +-void __devinit pcibios_do_bus_setup(struct pci_bus *bus) ++void __devinit pcibios_do_bus_setup_self(struct pci_bus *bus) + { + struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + unsigned long io_offset; +@@ -459,6 +459,10 @@ void __devinit pcibios_do_bus_setup(stru + } + } + ++void __devinit pcibios_do_bus_setup_devices(struct pci_bus *bus) ++{ ++} ++ + /* the next one is stolen from the alpha port... */ + void __init + pcibios_update_irq(struct pci_dev *dev, int irq) +--- a/arch/powerpc/kernel/pci_64.c ++++ b/arch/powerpc/kernel/pci_64.c +@@ -225,14 +225,16 @@ struct pci_dev *of_create_pci_dev(struct + EXPORT_SYMBOL(of_create_pci_dev); + + void __devinit of_scan_bus(struct device_node *node, +- struct pci_bus *bus) ++ struct pci_bus *bus, ++ int rescan_existing) + { + struct device_node *child; + const u32 *reg; + int reglen, devfn; + struct pci_dev *dev; + +- DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); ++ DBG("of_scan_bus(%s) %s bus no %d... \n", node->full_name, ++ rescan_existing ? "existing" : "new", bus->number); + + /* Scan direct children */ + for_each_child_of_node(node, child) { +@@ -249,8 +251,12 @@ void __devinit of_scan_bus(struct device + DBG(" dev header type: %x\n", dev->hdr_type); + } + +- /* Ally all fixups */ +- pcibios_fixup_of_probed_bus(bus); ++ /* Apply all fixups necessary. We don't fixup the bus "self" ++ * for an existing bridge that is being rescanned ++ */ ++ if (!rescan_existing) ++ pcibios_fixup_bus_self(bus); ++ pcibios_fixup_bus_devices(bus); + + /* Now scan child busses */ + list_for_each_entry(dev, &bus->devices, bus_list) { +@@ -346,7 +352,7 @@ void __devinit of_scan_pci_bridge(struct + DBG(" probe mode: %d\n", mode); + + if (mode == PCI_PROBE_DEVTREE) +- of_scan_bus(node, bus); ++ of_scan_bus(node, bus, 0); + else if (mode == PCI_PROBE_NORMAL) + pci_scan_child_bus(bus); + } +@@ -396,7 +402,7 @@ void __devinit scan_phb(struct pci_contr + DBG(" probe mode: %d\n", mode); + if (mode == PCI_PROBE_DEVTREE) { + bus->subordinate = hose->last_busno; +- of_scan_bus(node, bus); ++ of_scan_bus(node, bus, 0); + } + + if (mode == PCI_PROBE_NORMAL) +@@ -568,12 +574,15 @@ void __devinit pcibios_setup_new_device( + } + EXPORT_SYMBOL(pcibios_setup_new_device); + +-void __devinit pcibios_do_bus_setup(struct pci_bus *bus) ++void __devinit pcibios_do_bus_setup_self(struct pci_bus *bus) + { +- struct pci_dev *dev; +- + if (ppc_md.pci_dma_bus_setup) + ppc_md.pci_dma_bus_setup(bus); ++} ++ ++void __devinit pcibios_do_bus_setup_devices(struct pci_bus *bus) ++{ ++ struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) + pcibios_setup_new_device(dev); +--- a/arch/powerpc/kernel/pci-common.c ++++ b/arch/powerpc/kernel/pci-common.c +@@ -789,63 +789,78 @@ static void __devinit pcibios_fixup_reso + } + DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); + +-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) ++void __devinit pcibios_fixup_bus_self(struct pci_bus *bus) + { + struct pci_controller *hose = pci_bus_to_host(bus); + struct pci_dev *dev = bus->self; ++ struct resource *res; ++ int i; + +- pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB"); ++ pr_debug("PCI: Fixup bus resources %d (%s)\n", ++ bus->number, dev ? pci_name(dev) : "PHB"); + + /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for + * now differently between 32 and 64 bits. + */ +- if (dev != NULL) { +- struct resource *res; +- int i; +- +- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { +- if ((res = bus->resource[i]) == NULL) +- continue; +- if (!res->flags) +- continue; +- if (i >= 3 && bus->self->transparent) +- continue; +- /* On PowerMac, Apple leaves bridge windows open over +- * an inaccessible region of memory space (0...fffff) +- * which is somewhat bogus, but that's what they think +- * means disabled... +- * +- * We clear those to force them to be reallocated later +- * +- * We detect such regions by the fact that the base is +- * equal to the pci_mem_offset of the host bridge and +- * their size is smaller than 1M. +- */ +- if (res->flags & IORESOURCE_MEM && +- res->start == hose->pci_mem_offset && +- res->end < 0x100000) { +- printk(KERN_INFO +- "PCI: Closing bogus Apple Firmware" +- " region %d on bus 0x%02x\n", +- i, bus->number); +- res->flags = 0; +- continue; +- } ++ if (dev == NULL) ++ goto host_bridge; + +- pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", +- pci_name(dev), i, +- (unsigned long long)res->start,\ +- (unsigned long long)res->end, +- (unsigned int)res->flags); ++ for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { ++ if ((res = bus->resource[i]) == NULL) ++ continue; ++ if (!res->flags) ++ continue; ++ if (i >= 3 && bus->self->transparent) ++ continue; + +- fixup_resource(res, dev); ++ /* On PowerMac, Apple leaves bridge windows open over ++ * an inaccessible region of memory space (0...fffff) ++ * which is somewhat bogus, but that's what they think ++ * means disabled... ++ * ++ * We clear those to force them to be reallocated later ++ * ++ * We detect such regions by the fact that the base is ++ * equal to the pci_mem_offset of the host bridge and ++ * their size is smaller than 1M. ++ */ ++ if (res->flags & IORESOURCE_MEM && ++ res->start == hose->pci_mem_offset && ++ res->end < 0x100000) { ++ printk(KERN_INFO ++ "PCI: Closing bogus Apple Firmware" ++ " region %d on bus 0x%02x\n", ++ i, bus->number); ++ res->flags = 0; ++ continue; + } ++ ++ pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", ++ pci_name(dev), i, ++ (unsigned long long)res->start,\ ++ (unsigned long long)res->end, ++ (unsigned int)res->flags); ++ ++ fixup_resource(res, dev); + } + ++host_bridge: ++ ++ /* Additional setup that is different between 32 and 64 bits for now */ ++ pcibios_do_bus_setup_self(bus); ++} ++ ++void __devinit pcibios_fixup_bus_devices(struct pci_bus *bus) ++{ ++ struct pci_dev *dev = bus->self; ++ ++ pr_debug("PCI: Fixup bus devices %d (%s)\n", ++ bus->number, dev ? pci_name(dev) : "PHB"); ++ + /* Additional setup that is different between 32 and 64 bits for now */ +- pcibios_do_bus_setup(bus); ++ pcibios_do_bus_setup_devices(bus); + +- /* Platform specific bus fixups */ ++ /* Platform specific bus fixups (XXX Get rid of these !) */ + if (ppc_md.pcibios_fixup_bus) + ppc_md.pcibios_fixup_bus(bus); + +@@ -864,19 +879,11 @@ void __devinit pcibios_fixup_bus(struct + */ + if (bus->self != NULL) + pci_read_bridge_bases(bus); +- __pcibios_fixup_bus(bus); ++ pcibios_fixup_bus_self(bus); ++ pcibios_fixup_bus_devices(bus); + } + EXPORT_SYMBOL(pcibios_fixup_bus); + +-/* When building a bus from the OF tree rather than probing, we need a +- * slightly different version of the fixup which doesn't read the +- * bridge bases using config space accesses +- */ +-void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus) +-{ +- __pcibios_fixup_bus(bus); +-} +- + static int skip_isa_ioresource_align(struct pci_dev *dev) + { + if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) && +@@ -992,9 +999,12 @@ void pcibios_allocate_bus_resources(stru + int i; + struct resource *res, *pr; + ++ DBG("PCI: Allocating bus resources for %04x:%02x...\n", ++ pci_domain_nr(bus), bus->number); ++ + for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { + if ((res = bus->resource[i]) == NULL || !res->flags +- || res->start > res->end) ++ || res->start > res->end || res->parent) + continue; + if (bus->parent == NULL) + pr = (res->flags & IORESOURCE_IO) ? +@@ -1047,6 +1057,7 @@ clear_resource: + list_for_each_entry(b, &bus->children, node) + pcibios_allocate_bus_resources(b); + } ++EXPORT_SYMBOL_GPL(pcibios_allocate_bus_resources); + + static inline void __devinit alloc_resource(struct pci_dev *dev, int idx) + { +@@ -1157,6 +1168,13 @@ void __devinit pcibios_claim_one_bus(str + + if (r->parent || !r->start || !r->flags) + continue; ++ ++ DBG("PCI: Claiming %s: Resource %d: %016llx..%016llx [%x]\n", ++ pci_name(dev), i, ++ (unsigned long long)r->start, ++ (unsigned long long)r->end, ++ (unsigned int)r->flags); ++ + pci_claim_resource(dev, i); + } + } +--- a/arch/powerpc/kernel/rtas_pci.c ++++ b/arch/powerpc/kernel/rtas_pci.c +@@ -301,51 +301,3 @@ void __init find_and_init_phbs(void) + #endif /* CONFIG_PPC32 */ + } + } +- +-/* RPA-specific bits for removing PHBs */ +-int pcibios_remove_root_bus(struct pci_controller *phb) +-{ +- struct pci_bus *b = phb->bus; +- struct resource *res; +- int rc, i; +- +- res = b->resource[0]; +- if (!res->flags) { +- printk(KERN_ERR "%s: no IO resource for PHB %s\n", __func__, +- b->name); +- return 1; +- } +- +- rc = pcibios_unmap_io_space(b); +- if (rc) { +- printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", +- __func__, b->name); +- return 1; +- } +- +- if (release_resource(res)) { +- printk(KERN_ERR "%s: failed to release IO on bus %s\n", +- __func__, b->name); +- return 1; +- } +- +- for (i = 1; i < 3; ++i) { +- res = b->resource[i]; +- if (!res->flags && i == 0) { +- printk(KERN_ERR "%s: no MEM resource for PHB %s\n", +- __func__, b->name); +- return 1; +- } +- if (res->flags && release_resource(res)) { +- printk(KERN_ERR +- "%s: failed to release IO %d on bus %s\n", +- __func__, i, b->name); +- return 1; +- } +- } +- +- pcibios_free_controller(phb); +- +- return 0; +-} +-EXPORT_SYMBOL(pcibios_remove_root_bus); +--- a/arch/powerpc/platforms/pseries/eeh.c ++++ b/arch/powerpc/platforms/pseries/eeh.c +@@ -21,6 +21,8 @@ + * Please address comments and feedback to Linas Vepstas + */ + ++#undef DEBUG ++ + #include + #include + #include +@@ -488,10 +490,8 @@ int eeh_dn_check_failure(struct device_n + if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || + pdn->eeh_mode & EEH_MODE_NOCHECK) { + ignored_check++; +-#ifdef DEBUG +- printk ("EEH:ignored check (%x) for %s %s\n", +- pdn->eeh_mode, pci_name (dev), dn->full_name); +-#endif ++ pr_debug("EEH: Ignored check (%x) for %s %s\n", ++ pdn->eeh_mode, pci_name (dev), dn->full_name); + return 0; + } + +@@ -1014,10 +1014,9 @@ static void *early_enable_eeh(struct dev + eeh_subsystem_enabled = 1; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; + +-#ifdef DEBUG +- printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", +- dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); +-#endif ++ pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", ++ dn->full_name, pdn->eeh_config_addr, ++ pdn->eeh_pe_config_addr); + } else { + + /* This device doesn't support EEH, but it may have an +@@ -1161,13 +1160,17 @@ static void eeh_add_device_late(struct p + if (!dev || !eeh_subsystem_enabled) + return; + +-#ifdef DEBUG +- printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); +-#endif ++ pr_debug("EEH: Adding device %s\n", pci_name(dev)); + +- pci_dev_get (dev); + dn = pci_device_to_OF_node(dev); + pdn = PCI_DN(dn); ++ if (pdn->pcidev == dev) { ++ pr_debug("EEH: Already referenced !\n"); ++ return; ++ } ++ WARN_ON(pdn->pcidev); ++ ++ pci_dev_get (dev); + pdn->pcidev = dev; + + pci_addr_cache_insert_device(dev); +@@ -1206,17 +1209,18 @@ static void eeh_remove_device(struct pci + return; + + /* Unregister the device with the EEH/PCI address search system */ +-#ifdef DEBUG +- printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); +-#endif +- pci_addr_cache_remove_device(dev); +- eeh_sysfs_remove_device(dev); ++ pr_debug("EEH: Removing device %s\n", pci_name(dev)); + + dn = pci_device_to_OF_node(dev); +- if (PCI_DN(dn)->pcidev) { +- PCI_DN(dn)->pcidev = NULL; +- pci_dev_put (dev); ++ if (PCI_DN(dn)->pcidev == NULL) { ++ pr_debug("EEH: Not referenced !\n"); ++ return; + } ++ PCI_DN(dn)->pcidev = NULL; ++ pci_dev_put (dev); ++ ++ pci_addr_cache_remove_device(dev); ++ eeh_sysfs_remove_device(dev); + } + + void eeh_remove_bus_device(struct pci_dev *dev) +--- a/arch/powerpc/platforms/pseries/pci_dlpar.c ++++ b/arch/powerpc/platforms/pseries/pci_dlpar.c +@@ -25,6 +25,8 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++#undef DEBUG ++ + #include + #include + #include +@@ -69,73 +71,41 @@ EXPORT_SYMBOL_GPL(pcibios_find_pci_bus); + * Remove all of the PCI devices under this bus both from the + * linux pci device tree, and from the powerpc EEH address cache. + */ +-void +-pcibios_remove_pci_devices(struct pci_bus *bus) ++void pcibios_remove_pci_devices(struct pci_bus *bus) + { + struct pci_dev *dev, *tmp; ++ struct pci_bus *child_bus; + ++ /* First go down child busses */ ++ list_for_each_entry(child_bus, &bus->children, node) ++ pcibios_remove_pci_devices(child_bus); ++ ++ pr_debug("PCI: Removing devices on bus %04x:%02x\n", ++ pci_domain_nr(bus), bus->number); + list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { ++ pr_debug(" * Removing %s...\n", pci_name(dev)); + eeh_remove_bus_device(dev); + pci_remove_bus_device(dev); + } + } + EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); + +-/* Must be called before pci_bus_add_devices */ +-void +-pcibios_fixup_new_pci_devices(struct pci_bus *bus) +-{ +- struct pci_dev *dev; +- +- list_for_each_entry(dev, &bus->devices, bus_list) { +- /* Skip already-added devices */ +- if (!dev->is_added) { +- int i; +- +- /* Fill device archdata and setup iommu table */ +- pcibios_setup_new_device(dev); +- +- pci_read_irq_line(dev); +- for (i = 0; i < PCI_NUM_RESOURCES; i++) { +- struct resource *r = &dev->resource[i]; +- +- if (r->parent || !r->start || !r->flags) +- continue; +- pci_claim_resource(dev, i); +- } +- } +- } +-} +-EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices); +- +-static int +-pcibios_pci_config_bridge(struct pci_dev *dev) ++void pcibios_finish_adding_new_bus(struct pci_bus *bus) + { +- u8 sec_busno; +- struct pci_bus *child_bus; +- +- /* Get busno of downstream bus */ +- pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno); ++ pr_debug("PCI: Finishing adding hotplug bus %04x:%02x\n", ++ pci_domain_nr(bus), bus->number); + +- /* Add to children of PCI bridge dev->bus */ +- child_bus = pci_add_new_bus(dev->bus, dev, sec_busno); +- if (!child_bus) { +- printk (KERN_ERR "%s: could not add second bus\n", __func__); +- return -EIO; +- } +- sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number); +- +- pci_scan_child_bus(child_bus); ++ /* Allocate bus and devices resources */ ++ pcibios_allocate_bus_resources(bus); ++ pcibios_claim_one_bus(bus); + +- /* Fixup new pci devices */ +- pcibios_fixup_new_pci_devices(child_bus); ++ /* Add new devices to global lists. Register in proc, sysfs. */ ++ pci_bus_add_devices(bus); + +- /* Make the discovered devices available */ +- pci_bus_add_devices(child_bus); +- +- eeh_add_device_tree_late(child_bus); +- return 0; ++ /* Fixup EEH */ ++ eeh_add_device_tree_late(bus); + } ++EXPORT_SYMBOL_GPL(pcibios_finish_adding_new_bus); + + /** + * pcibios_add_pci_devices - adds new pci devices to bus +@@ -147,10 +117,9 @@ pcibios_pci_config_bridge(struct pci_dev + * is how this routine differs from other, similar pcibios + * routines.) + */ +-void +-pcibios_add_pci_devices(struct pci_bus * bus) ++void pcibios_add_pci_devices(struct pci_bus * bus) + { +- int slotno, num, mode; ++ int slotno, num, mode, pass, max; + struct pci_dev *dev; + struct device_node *dn = pci_bus_to_OF_node(bus); + +@@ -162,25 +131,24 @@ pcibios_add_pci_devices(struct pci_bus * + + if (mode == PCI_PROBE_DEVTREE) { + /* use ofdt-based probe */ +- of_scan_bus(dn, bus); +- if (!list_empty(&bus->devices)) { +- pcibios_fixup_new_pci_devices(bus); +- pci_bus_add_devices(bus); +- eeh_add_device_tree_late(bus); +- } ++ of_scan_bus(dn, bus, 1); ++ if (!list_empty(&bus->devices)) ++ pcibios_finish_adding_new_bus(bus); + } else if (mode == PCI_PROBE_NORMAL) { + /* use legacy probe */ + slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); + num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); +- if (num) { +- pcibios_fixup_new_pci_devices(bus); +- pci_bus_add_devices(bus); +- eeh_add_device_tree_late(bus); ++ if (!num) ++ return; ++ pcibios_fixup_bus_devices(bus); ++ max = bus->secondary; ++ for (pass=0; pass < 2; pass++) ++ list_for_each_entry(dev, &bus->devices, bus_list) { ++ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || ++ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) ++ max = pci_scan_bridge(bus, dev, max, pass); + } +- +- list_for_each_entry(dev, &bus->devices, bus_list) +- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) +- pcibios_pci_config_bridge(dev); ++ pcibios_finish_adding_new_bus(bus); + } + } + EXPORT_SYMBOL_GPL(pcibios_add_pci_devices); +@@ -189,7 +157,8 @@ struct pci_controller * __devinit init_p + { + struct pci_controller *phb; + int primary; +- struct pci_bus *b; ++ ++ pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name); + + primary = list_empty(&hose_list); + phb = pcibios_alloc_controller(dn); +@@ -204,11 +173,57 @@ struct pci_controller * __devinit init_p + eeh_add_device_tree_early(dn); + + scan_phb(phb); +- pcibios_allocate_bus_resources(phb->bus); +- pcibios_fixup_new_pci_devices(phb->bus); +- pci_bus_add_devices(phb->bus); +- eeh_add_device_tree_late(phb->bus); ++ pcibios_finish_adding_new_bus(phb->bus); + + return phb; + } + EXPORT_SYMBOL_GPL(init_phb_dynamic); ++ ++ ++ ++ ++/* RPA-specific bits for removing PHBs */ ++int remove_phb_dynamic(struct pci_controller *phb) ++{ ++ struct pci_bus *b = phb->bus; ++ struct resource *res; ++ int rc, i; ++ ++ pr_debug("PCI: Removing PHB %04x:%02x... \n", pci_domain_nr(b), b->number); ++ ++ /* We -know- there aren't any child devices anymore at this stage ++ * and thus, we can safely unmap the IO space as it's not in use ++ */ ++ res = &phb->io_resource; ++ if (res->flags & IORESOURCE_IO) { ++ rc = pcibios_unmap_io_space(b); ++ if (rc) { ++ printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", ++ __func__, b->name); ++ return 1; ++ } ++ } ++ ++ /* Unregister the bridge device from sysfs and remove the PCI bus */ ++ device_unregister(b->bridge); ++ phb->bus = NULL; ++ pci_remove_bus(b); ++ ++ /* Now release the IO resource */ ++ if (res->flags & IORESOURCE_IO) ++ release_resource(res); ++ ++ /* Release memory resources */ ++ for (i = 0; i < 3; ++i) { ++ res = &phb->mem_resources[i]; ++ if (!(res->flags & IORESOURCE_MEM)) ++ continue; ++ release_resource(res); ++ } ++ ++ /* Free pci_controller data structure */ ++ pcibios_free_controller(phb); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(remove_phb_dynamic); +--- a/drivers/pci/hotplug/rpadlpar_core.c ++++ b/drivers/pci/hotplug/rpadlpar_core.c +@@ -14,6 +14,8 @@ + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ ++#undef DEBUG ++ + #include + #include + #include +@@ -155,16 +157,15 @@ static void dlpar_pci_add_bus(struct dev + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + of_scan_pci_bridge(dn, dev); + +- pcibios_fixup_new_pci_devices(dev->subordinate); +- +- /* Claim new bus resources */ +- pcibios_claim_one_bus(dev->bus); +- + /* Map IO space for child bus, which may or may not succeed */ + pcibios_map_io_space(dev->subordinate); + +- /* Add new devices to global lists. Register in proc, sysfs. */ +- pci_bus_add_devices(phb->bus); ++ /* Finish adding it : resource allocation, adding devices, etc... ++ * Note that we need to perform the finish pass on the -parent- ++ * bus of the EADS bridge so the bridge device itself gets ++ * properly added ++ */ ++ pcibios_finish_adding_new_bus(phb->bus); + } + + static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) +@@ -206,22 +207,19 @@ static int dlpar_add_pci_slot(char *drc_ + static int dlpar_remove_root_bus(struct pci_controller *phb) + { + struct pci_bus *phb_bus; +- int rc; + + phb_bus = phb->bus; ++ pr_debug("PCI: -> removing root bus %04x:%02x\n", ++ pci_domain_nr(phb_bus), phb_bus->number); ++ ++ /* We cannot to remove a root bus that has children */ + if (!(list_empty(&phb_bus->children) && + list_empty(&phb_bus->devices))) { ++ pr_debug("PCI: PHB removal failed, bus not empty !\n"); + return -EBUSY; + } + +- rc = pcibios_remove_root_bus(phb); +- if (rc) +- return -EIO; +- +- device_unregister(phb_bus->bridge); +- pci_remove_bus(phb_bus); +- +- return 0; ++ return remove_phb_dynamic(phb); + } + + static int dlpar_remove_phb(char *drc_name, struct device_node *dn) +@@ -233,6 +231,8 @@ static int dlpar_remove_phb(char *drc_na + if (!pcibios_find_pci_bus(dn)) + return -EINVAL; + ++ pr_debug("PCI: Removing PHB %s...\n", dn->full_name); ++ + /* If pci slot is hotplugable, use hotplug to remove it */ + slot = find_php_slot(dn); + if (slot) { +@@ -378,25 +378,36 @@ int dlpar_remove_pci_slot(char *drc_name + if (!bus) + return -EINVAL; + +- /* If pci slot is hotplugable, use hotplug to remove it */ ++ pr_debug("PCI: Removing PCI slot below EADS bridge %s\n", ++ bus->self ? pci_name(bus->self) : ""); ++ ++ /* If pci slot is hotplugable, remove hotplug data structures */ + slot = find_php_slot(dn); + if (slot) { ++ pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n", ++ pci_domain_nr(bus), bus->number); + if (rpaphp_deregister_slot(slot)) { + printk(KERN_ERR + "%s: unable to remove hotplug slot %s\n", + __func__, drc_name); + return -EIO; + } +- } else +- pcibios_remove_pci_devices(bus); ++ } ++ ++ /* Remove all devices below slot */ ++ pcibios_remove_pci_devices(bus); + ++ /* Unmap PCI IO space */ + if (pcibios_unmap_io_space(bus)) { + printk(KERN_ERR "%s: failed to unmap bus range\n", + __func__); + return -ERANGE; + } + ++ /* Remove the EADS bridge device itself */ + BUG_ON(!bus->self); ++ pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); ++ eeh_remove_bus_device(bus->self); + pci_remove_bus_device(bus->self); + return 0; + } +--- a/drivers/pci/hotplug/rpaphp_slot.c ++++ b/drivers/pci/hotplug/rpaphp_slot.c +@@ -145,9 +145,5 @@ int rpaphp_register_slot(struct slot *sl + list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head); + info("Slot [%s] registered\n", slot->name); + return 0; +- +-sysfs_fail: +- pci_hp_deregister(php_slot); +- return retval; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-powerpc-fix-pci-unmap-io.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-powerpc-fix-pci-unmap-io.patch new file mode 100644 index 000000000..115ef1b9b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-powerpc-fix-pci-unmap-io.patch @@ -0,0 +1,28 @@ +Subject: powerpc/pci: Fix unmapping of IO space on 64-bit +From: Benjamin Herrenschmidt +References: 439491 + +A typo/thinko made us pass the wrong argument to __flush_hash_table_range +when unplugging bridges, thus not flushing all the translations for +the IO space on unplug. + +This causes the hypervisor to refuse unplugging slots. + +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Olaf Hering + +--- + arch/powerpc/kernel/pci_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/kernel/pci_64.c ++++ b/arch/powerpc/kernel/pci_64.c +@@ -455,7 +455,7 @@ int pcibios_unmap_io_space(struct pci_bu + pci_name(bus->self)); + + __flush_hash_table_range(&init_mm, res->start + _IO_BASE, +- res->end - res->start + 1); ++ res->end + _IO_BASE + 1); + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-prom-nodisplay.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-prom-nodisplay.patch new file mode 100644 index 000000000..21aeeaf65 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-prom-nodisplay.patch @@ -0,0 +1,86 @@ +From: unknown@suse.de +Subject: some crazy ppc patch + +add prom=nodisplay +avoid crash in firmware on IBM B50 when OF stdout is on serial. + + 0 > boot scsi/sd@4:1,yaboot | +yaboot starting: loaded at 00200000 00222530 (0/0/00c1a078; sp: 00efffd0) +brokenfirmware did not claim executable memory, fixed it myself +Config file 'yaboot.cnf' read, 213 bytes + +Welcome to yaboot version 10.1.22-r945.SuSE +booted from '/pci@80000000/scsi@10/sd@4:1,yaboot' +Enter "help" to get some basic usage information +boot: +* linux +boot: linux 3 +Please wait, loading kernel... +Allocated 00600000 bytes for executable @ 02000000 + Elf32 kernel loaded... +Loading ramdisk... +ramdisk loaded 0030e057 @ 04100000 +OF stdout device is: /pci@80000000/isa@b/serial@i3f8 +command line: root=/dev/system/root xmon=on sysrq=1 quiet panic=12 3 +memory layout at init: + memory_limit : 00000000 (16 MB aligned) + alloc_bottom : 0440f000 + alloc_top : 30000000 + alloc_top_hi : 40000000 + rmo_top : 30000000 + ram_top : 40000000 +Looking for displays +found display : /pci@80000000/display@16, opening ... +Unexpected Firmware Error: +DEFAULT CATCH!, code=fff00300 at %SRR0: 00c18ccc %SRR1: 00003030 + ok + 0 > reset-all + + +--- + arch/powerpc/kernel/prom_init.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/kernel/prom_init.c ++++ b/arch/powerpc/kernel/prom_init.c +@@ -172,6 +172,7 @@ static unsigned long __initdata dt_strin + + static unsigned long __initdata prom_initrd_start, prom_initrd_end; + ++static int __initdata prom_no_display; + #ifdef CONFIG_PPC64 + static int __initdata prom_iommu_force_on; + static int __initdata prom_iommu_off; +@@ -555,9 +556,7 @@ unsigned long prom_memparse(const char * + static void __init early_cmdline_parse(void) + { + struct prom_t *_prom = &RELOC(prom); +-#ifdef CONFIG_PPC64 + const char *opt; +-#endif + char *p; + int l = 0; + +@@ -572,6 +571,14 @@ static void __init early_cmdline_parse(v + #endif /* CONFIG_CMDLINE */ + prom_printf("command line: %s\n", RELOC(prom_cmd_line)); + ++ opt = strstr(RELOC(prom_cmd_line), RELOC("prom=")); ++ if (opt) { ++ opt += 5; ++ while (*opt && *opt == ' ') ++ opt++; ++ if (!strncmp(opt, RELOC("nodisplay"), 9)) ++ RELOC(prom_no_display) = 1; ++ } + #ifdef CONFIG_PPC64 + opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); + if (opt) { +@@ -2400,6 +2407,7 @@ unsigned long __init prom_init(unsigned + /* + * Initialize display devices + */ ++ if (RELOC(prom_no_display) == 0) + prom_check_displays(); + + #ifdef CONFIG_PPC64 diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-passthrough-support-for-non-audio-streams.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-passthrough-support-for-non-audio-streams.patch new file mode 100644 index 000000000..5d82907ab --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-passthrough-support-for-non-audio-streams.patch @@ -0,0 +1,83 @@ +Subject: ps3: Add passthru support for non-audio streams +From: Takashi Iwai tiwai@suse.de Mon Oct 20 08:05:10 2008 +0200 +Date: Mon Oct 20 08:05:15 2008 +0200: +Git: 64931a4be03dbc49bd50d10d211592cf98b523bb + +Add support for the channel status bit setting so that non-PCM +data stream can be sent (i.e. pass-through) via SPDIF/HDMI. + +Signed-off-by: Masakazu Mokuno +Acked-by: Geert Uytterhoeven +Signed-off-by: Takashi Iwai +Signed-off-by: Stefan Assmann + +diff --git a/arch/powerpc/include/asm/ps3av.h b/arch/powerpc/include/asm/ps3av.h +index d30bde2..5aa22cf 100644 +--- a/arch/powerpc/include/asm/ps3av.h ++++ b/arch/powerpc/include/asm/ps3av.h +@@ -678,6 +678,8 @@ struct ps3av_pkt_avb_param { + u8 buf[PS3AV_PKT_AVB_PARAM_MAX_BUF_SIZE]; + }; + ++/* channel status */ ++extern u8 ps3av_mode_cs_info[]; + + /** command status **/ + #define PS3AV_STATUS_SUCCESS 0x0000 /* success */ +diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c +index 7f880c2..11eb503 100644 +--- a/drivers/ps3/ps3av_cmd.c ++++ b/drivers/ps3/ps3av_cmd.c +@@ -660,9 +660,10 @@ u32 ps3av_cmd_set_av_audio_param(void *p, u32 port, + } + + /* default cs val */ +-static const u8 ps3av_mode_cs_info[] = { ++u8 ps3av_mode_cs_info[] = { + 0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00 + }; ++EXPORT_SYMBOL_GPL(ps3av_mode_cs_info); + + #define CS_44 0x00 + #define CS_48 0x02 +@@ -677,7 +678,7 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport, + u32 ch, u32 fs, u32 word_bits, u32 format, + u32 source) + { +- int spdif_through, spdif_bitstream; ++ int spdif_through; + int i; + + if (!(ch | fs | format | word_bits | source)) { +@@ -687,7 +688,6 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport, + format = PS3AV_CMD_AUDIO_FORMAT_PCM; + source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; + } +- spdif_through = spdif_bitstream = 0; /* XXX not supported */ + + /* audio mode */ + memset(audio, 0, sizeof(*audio)); +@@ -777,16 +777,17 @@ void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport, + break; + } + ++ /* non-audio bit */ ++ spdif_through = audio->audio_cs_info[0] & 0x02; ++ + /* pass through setting */ + if (spdif_through && + (avport == PS3AV_CMD_AVPORT_SPDIF_0 || +- avport == PS3AV_CMD_AVPORT_SPDIF_1)) { ++ avport == PS3AV_CMD_AVPORT_SPDIF_1 || ++ avport == PS3AV_CMD_AVPORT_HDMI_0 || ++ avport == PS3AV_CMD_AVPORT_HDMI_1)) { + audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16; +- audio->audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF; +- if (spdif_bitstream) { +- audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM; +- audio->audio_cs_info[0] |= CS_BIT; +- } ++ audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM; + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-ps3av-audio-mute-analog.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-ps3av-audio-mute-analog.patch new file mode 100644 index 000000000..713b55e24 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-ps3av-audio-mute-analog.patch @@ -0,0 +1,51 @@ +Subject: ps3: Add ps3av_audio_mute_analog() +From: Masakazu Mokuno mokuno@sm.sony.co.jp Mon Oct 20 08:03:33 2008 +0200 +Date: Mon Oct 20 08:04:59 2008 +0200: +Git: 756ba83ee370fbf62643777e7ba4a4f05932f6fb + +Add support for muting the analog output so that it does not +play noises while non-PCM data is played. + +Signed-off-by: Masakazu Mokuno +Signed-off-by: Takashi Iwai +Signed-off-by: Stefan Assmann + +diff --git a/arch/powerpc/include/asm/ps3av.h b/arch/powerpc/include/asm/ps3av.h +index fda9871..d30bde2 100644 +--- a/arch/powerpc/include/asm/ps3av.h ++++ b/arch/powerpc/include/asm/ps3av.h +@@ -735,6 +735,7 @@ extern int ps3av_get_mode(void); + extern int ps3av_video_mode2res(u32, u32 *, u32 *); + extern int ps3av_video_mute(int); + extern int ps3av_audio_mute(int); ++extern int ps3av_audio_mute_analog(int); + extern int ps3av_dev_open(void); + extern int ps3av_dev_close(void); + extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), +diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c +index 6f2f90e..06848b2 100644 +--- a/drivers/ps3/ps3av.c ++++ b/drivers/ps3/ps3av.c +@@ -915,6 +915,22 @@ int ps3av_video_mute(int mute) + + EXPORT_SYMBOL_GPL(ps3av_video_mute); + ++/* mute analog output only */ ++int ps3av_audio_mute_analog(int mute) ++{ ++ int i, res; ++ ++ for (i = 0; i < ps3av->av_hw_conf.num_of_avmulti; i++) { ++ res = ps3av_cmd_av_audio_mute(1, ++ &ps3av->av_port[i + ps3av->av_hw_conf.num_of_hdmi], ++ mute); ++ if (res < 0) ++ return -1; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ps3av_audio_mute_analog); ++ + int ps3av_audio_mute(int mute) + { + return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-support-for-SPDIF-HDMI-passthrough.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-support-for-SPDIF-HDMI-passthrough.patch new file mode 100644 index 000000000..3fd58a4b4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-add-support-for-SPDIF-HDMI-passthrough.patch @@ -0,0 +1,166 @@ +Subject: ALSA: ps3: Add support for SPDIF/HDMI passthru +From: Takashi Iwai tiwai@suse.de Mon Oct 20 08:06:39 2008 +0200 +Date: Mon Oct 20 08:06:39 2008 +0200: +Git: 1ee2a322b058f6399dc900603f9ebb392037ff77 + +Add support for SPDIF/HDMI pass-through support of PS3 audio driver. + +Signed-off-by: Masakazu Mokuno +Signed-off-by: Takashi Iwai +Signed-off-by: Stefan Assmann + +diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c +index 20d0e32..8f9e385 100644 +--- a/sound/ppc/snd_ps3.c ++++ b/sound/ppc/snd_ps3.c +@@ -666,6 +666,7 @@ static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card) + card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16; + card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM; + card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL; ++ memcpy(card->avs.avs_cs_info, ps3av_mode_cs_info, 8); + + ret = snd_ps3_change_avsetting(card); + +@@ -685,6 +686,7 @@ static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) + { + struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); + struct snd_ps3_avsetting_info avs; ++ int ret; + + avs = card->avs; + +@@ -729,19 +731,92 @@ static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream) + return 1; + } + +- if ((card->avs.avs_audio_width != avs.avs_audio_width) || +- (card->avs.avs_audio_rate != avs.avs_audio_rate)) { +- card->avs = avs; +- snd_ps3_change_avsetting(card); ++ memcpy(avs.avs_cs_info, ps3av_mode_cs_info, 8); + ++ if (memcmp(&card->avs, &avs, sizeof(avs))) { + pr_debug("%s: after freq=%d width=%d\n", __func__, + card->avs.avs_audio_rate, card->avs.avs_audio_width); + +- return 0; ++ card->avs = avs; ++ snd_ps3_change_avsetting(card); ++ ret = 0; + } else ++ ret = 1; ++ ++ /* check CS non-audio bit and mute accordingly */ ++ if (avs.avs_cs_info[0] & 0x02) ++ ps3av_audio_mute_analog(1); /* mute if non-audio */ ++ else ++ ps3av_audio_mute_analog(0); ++ ++ return ret; ++} ++ ++/* ++ * SPDIF status bits controls ++ */ ++static int snd_ps3_spdif_mask_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; ++ uinfo->count = 1; ++ return 0; ++} ++ ++/* FIXME: ps3av_set_audio_mode() assumes only consumer mode */ ++static int snd_ps3_spdif_cmask_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ memset(ucontrol->value.iec958.status, 0xff, 8); ++ return 0; ++} ++ ++static int snd_ps3_spdif_pmask_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ return 0; ++} ++ ++static int snd_ps3_spdif_default_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ memcpy(ucontrol->value.iec958.status, ps3av_mode_cs_info, 8); ++ return 0; ++} ++ ++static int snd_ps3_spdif_default_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ if (memcmp(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8)) { ++ memcpy(ps3av_mode_cs_info, ucontrol->value.iec958.status, 8); + return 1; ++ } ++ return 0; + } + ++static struct snd_kcontrol_new spdif_ctls[] = { ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ, ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), ++ .info = snd_ps3_spdif_mask_info, ++ .get = snd_ps3_spdif_cmask_get, ++ }, ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ, ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), ++ .info = snd_ps3_spdif_mask_info, ++ .get = snd_ps3_spdif_pmask_get, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), ++ .info = snd_ps3_spdif_mask_info, ++ .get = snd_ps3_spdif_default_get, ++ .put = snd_ps3_spdif_default_put, ++ }, ++}; + + + static int snd_ps3_map_mmio(void) +@@ -842,7 +917,7 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start) + + static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) + { +- int ret; ++ int i, ret; + u64 lpar_addr, lpar_size; + + BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)); +@@ -903,6 +978,15 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev) + strcpy(the_card.card->driver, "PS3"); + strcpy(the_card.card->shortname, "PS3"); + strcpy(the_card.card->longname, "PS3 sound"); ++ ++ /* create control elements */ ++ for (i = 0; i < ARRAY_SIZE(spdif_ctls); i++) { ++ ret = snd_ctl_add(the_card.card, ++ snd_ctl_new1(&spdif_ctls[i], &the_card)); ++ if (ret < 0) ++ goto clean_card; ++ } ++ + /* create PCM devices instance */ + /* NOTE:this driver works assuming pcm:substream = 1:1 */ + ret = snd_pcm_new(the_card.card, +diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h +index 4b7e6fb..326fb29 100644 +--- a/sound/ppc/snd_ps3.h ++++ b/sound/ppc/snd_ps3.h +@@ -51,6 +51,7 @@ struct snd_ps3_avsetting_info { + uint32_t avs_audio_width; + uint32_t avs_audio_format; /* fixed */ + uint32_t avs_audio_source; /* fixed */ ++ unsigned char avs_cs_info[8]; + }; + /* + * PS3 audio 'card' instance diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-introduce-ps3_gpu_mutex.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-introduce-ps3_gpu_mutex.patch new file mode 100644 index 000000000..ff58b39f5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-introduce-ps3_gpu_mutex.patch @@ -0,0 +1,164 @@ +From: Geert Uytterhoeven +Subject: Introduce ps3_gpu_mutex + +Introduce ps3_gpu_mutex to synchronizes GPU-related operations, like: + - invoking the L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT command using the + lv1_gpu_context_attribute() hypervisor call, + - handling the PS3AV_CID_AVB_PARAM packet in the PS3 A/V Settings driver. + +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Stefan Assmann +--- + arch/powerpc/include/asm/ps3.h | 3 +++ + arch/powerpc/include/asm/ps3av.h | 3 --- + arch/powerpc/platforms/ps3/setup.c | 4 ++++ + drivers/ps3/ps3av.c | 20 -------------------- + drivers/ps3/ps3av_cmd.c | 4 ++-- + drivers/video/ps3fb.c | 17 +++++------------ + 6 files changed, 14 insertions(+), 37 deletions(-) + +--- a/arch/powerpc/include/asm/ps3.h ++++ b/arch/powerpc/include/asm/ps3.h +@@ -516,4 +516,7 @@ void ps3_sync_irq(int node); + u32 ps3_get_hw_thread_id(int cpu); + u64 ps3_get_spe_id(void *arg); + ++/* mutex synchronizing GPU accesses and video mode changes */ ++extern struct mutex ps3_gpu_mutex; ++ + #endif +--- a/arch/powerpc/include/asm/ps3av.h ++++ b/arch/powerpc/include/asm/ps3av.h +@@ -740,8 +740,5 @@ extern int ps3av_audio_mute(int); + extern int ps3av_audio_mute_analog(int); + extern int ps3av_dev_open(void); + extern int ps3av_dev_close(void); +-extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), +- void *flip_data); +-extern void ps3av_flip_ctl(int on); + + #endif /* _ASM_POWERPC_PS3AV_H_ */ +--- a/arch/powerpc/platforms/ps3/setup.c ++++ b/arch/powerpc/platforms/ps3/setup.c +@@ -42,6 +42,10 @@ + #define DBG pr_debug + #endif + ++/* mutex synchronizing GPU accesses and video mode changes */ ++DEFINE_MUTEX(ps3_gpu_mutex); ++EXPORT_SYMBOL_GPL(ps3_gpu_mutex); ++ + #if !defined(CONFIG_SMP) + static void smp_send_stop(void) {} + #endif +--- a/drivers/ps3/ps3av.c ++++ b/drivers/ps3/ps3av.c +@@ -59,8 +59,6 @@ static struct ps3av { + struct ps3av_reply_hdr reply_hdr; + u8 raw[PS3AV_BUF_SIZE]; + } recv_buf; +- void (*flip_ctl)(int on, void *data); +- void *flip_data; + } *ps3av; + + /* color space */ +@@ -939,24 +937,6 @@ int ps3av_audio_mute(int mute) + + EXPORT_SYMBOL_GPL(ps3av_audio_mute); + +-void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data), +- void *flip_data) +-{ +- mutex_lock(&ps3av->mutex); +- ps3av->flip_ctl = flip_ctl; +- ps3av->flip_data = flip_data; +- mutex_unlock(&ps3av->mutex); +-} +-EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl); +- +-void ps3av_flip_ctl(int on) +-{ +- mutex_lock(&ps3av->mutex); +- if (ps3av->flip_ctl) +- ps3av->flip_ctl(on, ps3av->flip_data); +- mutex_unlock(&ps3av->mutex); +-} +- + static int ps3av_probe(struct ps3_system_bus_device *dev) + { + int res; +--- a/drivers/ps3/ps3av_cmd.c ++++ b/drivers/ps3/ps3av_cmd.c +@@ -864,7 +864,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt + { + int res; + +- ps3av_flip_ctl(0); /* flip off */ ++ mutex_lock(&ps3_gpu_mutex); + + /* avb packet */ + res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb), +@@ -878,7 +878,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt + res); + + out: +- ps3av_flip_ctl(1); /* flip on */ ++ mutex_unlock(&ps3_gpu_mutex); + return res; + } + +--- a/drivers/video/ps3fb.c ++++ b/drivers/video/ps3fb.c +@@ -460,12 +460,16 @@ static void ps3fb_sync_image(struct devi + line_length |= (u64)src_line_length << 32; + + src_offset += GPU_FB_START; ++ ++ mutex_lock(&ps3_gpu_mutex); + status = lv1_gpu_context_attribute(ps3fb.context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, + dst_offset, GPU_IOIF + src_offset, + L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | + (width << 16) | height, + line_length); ++ mutex_unlock(&ps3_gpu_mutex); ++ + if (status) + dev_err(dev, + "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", +@@ -784,15 +788,6 @@ static int ps3fb_wait_for_vsync(u32 crtc + return 0; + } + +-static void ps3fb_flip_ctl(int on, void *data) +-{ +- struct ps3fb_priv *priv = data; +- if (on) +- atomic_dec_if_positive(&priv->ext_flip); +- else +- atomic_inc(&priv->ext_flip); +-} +- + + /* + * ioctl +@@ -1228,7 +1223,6 @@ static int __devinit ps3fb_probe(struct + } + + ps3fb.task = task; +- ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); + + return 0; + +@@ -1258,10 +1252,9 @@ static int ps3fb_shutdown(struct ps3_sys + + dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); + +- ps3fb_flip_ctl(0, &ps3fb); /* flip off */ ++ atomic_inc(&ps3fb.ext_flip); /* flip off */ + ps3fb.dinfo->irq.mask = 0; + +- ps3av_register_flip_ctl(NULL, NULL); + if (ps3fb.task) { + struct task_struct *task = ps3fb.task; + ps3fb.task = NULL; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-ps3vram-mtd.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-ps3vram-mtd.patch new file mode 100644 index 000000000..9ed54be72 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-ps3-ps3vram-mtd.patch @@ -0,0 +1,912 @@ +From: Jim Paris +Subject: Add ps3vram driver, which exposes unused video RAM on the PS3 as a MTD + +Add ps3vram driver, which exposes unused video RAM on the PS3 as a MTD +device suitable for storage or swap. Fast data transfer is achieved +using a local cache in system RAM and DMA transfers via the GPU. + +Signed-off-by: Vivien Chappelier +CC: Geert Uytterhoeven +CC: Geoff Levand +Signed-off-by: Jim Paris +Signed-off-by: Stefan Assmann +--- +This version has been updated to work with PS3 firmware 2.50, and +to use ps3_gpu_mutex. + +Please consider for 2.6.29. + + MAINTAINERS | 6 + arch/powerpc/include/asm/ps3.h | 1 + arch/powerpc/platforms/ps3/device-init.c | 37 + + drivers/mtd/devices/Kconfig | 7 + drivers/mtd/devices/Makefile | 1 + MAINTAINERS | 6 + arch/powerpc/include/asm/ps3.h | 1 + arch/powerpc/platforms/ps3/device-init.c | 37 + + drivers/mtd/devices/Kconfig | 7 + drivers/mtd/devices/Makefile | 1 + drivers/mtd/devices/ps3vram.c | 776 +++++++++++++++++++++++++++++++ + 6 files changed, 828 insertions(+) + create mode 100644 drivers/mtd/devices/ps3vram.c + +--- a/arch/powerpc/include/asm/ps3.h ++++ b/arch/powerpc/include/asm/ps3.h +@@ -340,6 +340,7 @@ enum ps3_system_bus_device_type { + enum ps3_match_sub_id { + /* for PS3_MATCH_ID_GRAPHICS */ + PS3_MATCH_SUB_ID_FB = 1, ++ PS3_MATCH_SUB_ID_RAMDISK = 2, + }; + + /** +--- a/arch/powerpc/platforms/ps3/device-init.c ++++ b/arch/powerpc/platforms/ps3/device-init.c +@@ -499,6 +499,41 @@ static int __init ps3_register_graphics_ + return result; + } + ++static int __init ps3_register_ramdisk_device(void) ++{ ++ int result; ++ struct layout { ++ struct ps3_system_bus_device dev; ++ } *p; ++ ++ pr_debug(" -> %s:%d\n", __func__, __LINE__); ++ ++ p = kzalloc(sizeof(struct layout), GFP_KERNEL); ++ ++ if (!p) ++ return -ENOMEM; ++ ++ p->dev.match_id = PS3_MATCH_ID_GRAPHICS; ++ p->dev.match_sub_id = PS3_MATCH_SUB_ID_RAMDISK; ++ p->dev.dev_type = PS3_DEVICE_TYPE_IOC0; ++ ++ result = ps3_system_bus_device_register(&p->dev); ++ ++ if (result) { ++ pr_debug("%s:%d ps3_system_bus_device_register failed\n", ++ __func__, __LINE__); ++ goto fail_device_register; ++ } ++ ++ pr_debug(" <- %s:%d\n", __func__, __LINE__); ++ return 0; ++ ++fail_device_register: ++ kfree(p); ++ pr_debug(" <- %s:%d failed\n", __func__, __LINE__); ++ return result; ++} ++ + /** + * ps3_setup_dynamic_device - Setup a dynamic device from the repository + */ +@@ -927,6 +962,8 @@ static int __init ps3_register_devices(v + + ps3_register_lpm_devices(); + ++ ps3_register_ramdisk_device(); ++ + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; + } +--- a/drivers/mtd/devices/Kconfig ++++ b/drivers/mtd/devices/Kconfig +@@ -99,6 +99,13 @@ config MTD_PHRAM + doesn't have access to, memory beyond the mem=xxx limit, nvram, + memory on the video card, etc... + ++config MTD_PS3VRAM ++ tristate "PS3 video RAM" ++ depends on FB_PS3 ++ help ++ This driver allows you to use excess PS3 video RAM as volatile ++ storage or system swap. ++ + config MTD_LART + tristate "28F160xx flash driver for LART" + depends on SA1100_LART +--- a/drivers/mtd/devices/Makefile ++++ b/drivers/mtd/devices/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_LART) += lart.o + obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o + obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o + obj-$(CONFIG_MTD_M25P80) += m25p80.o ++obj-$(CONFIG_MTD_PS3VRAM) += ps3vram.o +--- /dev/null ++++ b/drivers/mtd/devices/ps3vram.c +@@ -0,0 +1,776 @@ ++/** ++ * ps3vram - Use extra PS3 video ram as MTD block device. ++ * ++ * Copyright (c) 2007-2008 Jim Paris ++ * Added support RSX DMA Vivien Chappelier ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define DEVICE_NAME "ps3vram" ++ ++#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MB aligned) */ ++#define XDR_IOIF 0x0c000000 ++ ++#define FIFO_BASE XDR_IOIF ++#define FIFO_SIZE (64 * 1024) ++ ++#define DMA_PAGE_SIZE (4 * 1024) ++ ++#define CACHE_PAGE_SIZE (256 * 1024) ++#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE) ++ ++#define CACHE_OFFSET CACHE_PAGE_SIZE ++#define FIFO_OFFSET 0 ++ ++#define CTRL_PUT 0x10 ++#define CTRL_GET 0x11 ++#define CTRL_TOP 0x15 ++ ++#define UPLOAD_SUBCH 1 ++#define DOWNLOAD_SUBCH 2 ++ ++#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c ++#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 ++ ++#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 ++ ++struct mtd_info ps3vram_mtd; ++ ++#define CACHE_PAGE_PRESENT 1 ++#define CACHE_PAGE_DIRTY 2 ++ ++#define dbg(fmt, args...) \ ++ pr_debug("%s:%d " fmt "\n", __func__, __LINE__, ## args) ++ ++struct ps3vram_tag { ++ unsigned int address; ++ unsigned int flags; ++}; ++ ++struct ps3vram_cache { ++ unsigned int page_count; ++ unsigned int page_size; ++ struct ps3vram_tag *tags; ++}; ++ ++struct ps3vram_priv { ++ uint64_t memory_handle; ++ uint64_t context_handle; ++ uint8_t *base; ++ uint32_t *ctrl; ++ uint32_t *reports; ++ uint8_t *xdr_buf; ++ ++ uint32_t *fifo_base; ++ uint32_t *fifo_ptr; ++ ++ struct ps3vram_cache cache; ++ ++ /* Used to serialize cache/DMA operations */ ++ struct mutex lock; ++}; ++ ++#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */ ++#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */ ++#define DMA_NOTIFIER_SIZE 0x40 ++ ++#define NUM_NOTIFIERS 16 ++ ++#define NOTIFIER 7 /* notifier used for completion report */ ++ ++/* A trailing '-' means to subtract off ps3fb_videomemory.size */ ++char *size = "256M-"; ++module_param(size, charp, 0); ++MODULE_PARM_DESC(size, "memory size"); ++ ++static inline uint32_t *ps3vram_get_notifier(uint32_t *reports, int notifier) ++{ ++ return (void *) reports + ++ DMA_NOTIFIER_OFFSET_BASE + ++ DMA_NOTIFIER_SIZE * notifier; ++} ++ ++static void ps3vram_notifier_reset(struct mtd_info *mtd) ++{ ++ int i; ++ struct ps3vram_priv *priv = mtd->priv; ++ uint32_t *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); ++ for (i = 0; i < 4; i++) ++ notify[i] = 0xffffffff; ++} ++ ++static int ps3vram_notifier_wait(struct mtd_info *mtd, int timeout_ms) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ uint32_t *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); ++ ++ timeout_ms *= 1000; ++ ++ do { ++ if (notify[3] == 0) ++ return 0; ++ ++ if (timeout_ms) ++ udelay(1); ++ } while (timeout_ms--); ++ ++ return -1; ++} ++ ++static void ps3vram_dump_ring(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ uint32_t *fifo; ++ ++ pr_info("PUT = %08x GET = %08x\n", priv->ctrl[CTRL_PUT], ++ priv->ctrl[CTRL_GET]); ++ for (fifo = priv->fifo_base; fifo < priv->fifo_ptr; fifo++) ++ pr_info("%p: %08x\n", fifo, *fifo); ++} ++ ++static void ps3vram_dump_reports(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ int i; ++ ++ for (i = 0; i < NUM_NOTIFIERS; i++) { ++ uint32_t *n = ps3vram_get_notifier(priv->reports, i); ++ pr_info("%p: %08x\n", n, *n); ++ } ++} ++ ++static void ps3vram_init_ring(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; ++ priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; ++} ++ ++static int ps3vram_wait_ring(struct mtd_info *mtd, int timeout) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ /* wait until setup commands are processed */ ++ timeout *= 1000; ++ while (--timeout) { ++ if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET]) ++ break; ++ udelay(1); ++ } ++ if (timeout == 0) { ++ pr_err("FIFO timeout (%08x/%08x/%08x)\n", priv->ctrl[CTRL_PUT], ++ priv->ctrl[CTRL_GET], priv->ctrl[CTRL_TOP]); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static inline void ps3vram_out_ring(struct ps3vram_priv *priv, uint32_t data) ++{ ++ *(priv->fifo_ptr)++ = data; ++} ++ ++static inline void ps3vram_begin_ring(struct ps3vram_priv *priv, uint32_t chan, ++ uint32_t tag, uint32_t size) ++{ ++ ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag); ++} ++ ++static void ps3vram_rewind_ring(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ u64 status; ++ ++ ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); ++ ++ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; ++ ++ /* asking the HV for a blit will kick the fifo */ ++ status = lv1_gpu_context_attribute(priv->context_handle, ++ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, ++ 0, 0, 0, 0); ++ if (status) ++ pr_err("ps3vram: lv1_gpu_context_attribute FB_BLIT failed\n"); ++ ++ priv->fifo_ptr = priv->fifo_base; ++} ++ ++static void ps3vram_fire_ring(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ u64 status; ++ ++ mutex_lock(&ps3_gpu_mutex); ++ ++ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET + ++ (priv->fifo_ptr - priv->fifo_base) * sizeof(uint32_t); ++ ++ /* asking the HV for a blit will kick the fifo */ ++ status = lv1_gpu_context_attribute(priv->context_handle, ++ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, ++ 0, 0, 0, 0); ++ if (status) ++ pr_err("ps3vram: lv1_gpu_context_attribute FB_BLIT failed\n"); ++ ++ if ((priv->fifo_ptr - priv->fifo_base) * sizeof(uint32_t) > ++ FIFO_SIZE - 1024) { ++ dbg("fifo full, rewinding"); ++ ps3vram_wait_ring(mtd, 200); ++ ps3vram_rewind_ring(mtd); ++ } ++ ++ mutex_unlock(&ps3_gpu_mutex); ++} ++ ++static void ps3vram_bind(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); ++ ps3vram_out_ring(priv, 0x31337303); ++ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3); ++ ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); ++ ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ ++ ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ ++ ++ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1); ++ ps3vram_out_ring(priv, 0x3137c0de); ++ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3); ++ ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); ++ ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ ++ ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ ++ ++ ps3vram_fire_ring(mtd); ++} ++ ++static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset, ++ unsigned int dst_offset, int len, int count) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ ps3vram_begin_ring(priv, UPLOAD_SUBCH, ++ NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); ++ ps3vram_out_ring(priv, XDR_IOIF + src_offset); ++ ps3vram_out_ring(priv, dst_offset); ++ ps3vram_out_ring(priv, len); ++ ps3vram_out_ring(priv, len); ++ ps3vram_out_ring(priv, len); ++ ps3vram_out_ring(priv, count); ++ ps3vram_out_ring(priv, (1 << 8) | 1); ++ ps3vram_out_ring(priv, 0); ++ ++ ps3vram_notifier_reset(mtd); ++ ps3vram_begin_ring(priv, UPLOAD_SUBCH, ++ NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); ++ ps3vram_out_ring(priv, 0); ++ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1); ++ ps3vram_out_ring(priv, 0); ++ ps3vram_fire_ring(mtd); ++ if (ps3vram_notifier_wait(mtd, 200) < 0) { ++ pr_err("notifier timeout\n"); ++ ps3vram_dump_ring(mtd); ++ ps3vram_dump_reports(mtd); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset, ++ unsigned int dst_offset, int len, int count) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, ++ NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); ++ ps3vram_out_ring(priv, src_offset); ++ ps3vram_out_ring(priv, XDR_IOIF + dst_offset); ++ ps3vram_out_ring(priv, len); ++ ps3vram_out_ring(priv, len); ++ ps3vram_out_ring(priv, len); ++ ps3vram_out_ring(priv, count); ++ ps3vram_out_ring(priv, (1 << 8) | 1); ++ ps3vram_out_ring(priv, 0); ++ ++ ps3vram_notifier_reset(mtd); ++ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, ++ NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); ++ ps3vram_out_ring(priv, 0); ++ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1); ++ ps3vram_out_ring(priv, 0); ++ ps3vram_fire_ring(mtd); ++ if (ps3vram_notifier_wait(mtd, 200) < 0) { ++ pr_err("notifier timeout\n"); ++ ps3vram_dump_ring(mtd); ++ ps3vram_dump_reports(mtd); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void ps3vram_cache_evict(struct mtd_info *mtd, int entry) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ struct ps3vram_cache *cache = &priv->cache; ++ ++ if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) { ++ dbg("flushing %d : 0x%08x", entry, cache->tags[entry].address); ++ if (ps3vram_upload(mtd, ++ CACHE_OFFSET + entry * cache->page_size, ++ cache->tags[entry].address, ++ DMA_PAGE_SIZE, ++ cache->page_size / DMA_PAGE_SIZE) < 0) { ++ pr_err("failed to upload from 0x%x to 0x%x size 0x%x\n", ++ entry * cache->page_size, ++ cache->tags[entry].address, ++ cache->page_size); ++ } ++ cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY; ++ } ++} ++ ++static void ps3vram_cache_load(struct mtd_info *mtd, int entry, ++ unsigned int address) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ struct ps3vram_cache *cache = &priv->cache; ++ ++ dbg("fetching %d : 0x%08x", entry, address); ++ if (ps3vram_download(mtd, ++ address, ++ CACHE_OFFSET + entry * cache->page_size, ++ DMA_PAGE_SIZE, ++ cache->page_size / DMA_PAGE_SIZE) < 0) { ++ pr_err("failed to download from 0x%x to 0x%x size 0x%x\n", ++ address, ++ entry * cache->page_size, ++ cache->page_size); ++ } ++ ++ cache->tags[entry].address = address; ++ cache->tags[entry].flags |= CACHE_PAGE_PRESENT; ++} ++ ++ ++static void ps3vram_cache_flush(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ struct ps3vram_cache *cache = &priv->cache; ++ int i; ++ ++ dbg("FLUSH"); ++ for (i = 0; i < cache->page_count; i++) { ++ ps3vram_cache_evict(mtd, i); ++ cache->tags[i].flags = 0; ++ } ++} ++ ++static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ struct ps3vram_cache *cache = &priv->cache; ++ unsigned int base; ++ unsigned int offset; ++ int i; ++ static int counter; ++ ++ offset = (unsigned int) (address & (cache->page_size - 1)); ++ base = (unsigned int) (address - offset); ++ ++ /* fully associative check */ ++ for (i = 0; i < cache->page_count; i++) { ++ if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) && ++ cache->tags[i].address == base) { ++ dbg("found entry %d : 0x%08x", ++ i, cache->tags[i].address); ++ return i; ++ } ++ } ++ ++ /* choose a random entry */ ++ i = (jiffies + (counter++)) % cache->page_count; ++ dbg("using cache entry %d", i); ++ ++ ps3vram_cache_evict(mtd, i); ++ ps3vram_cache_load(mtd, i, base); ++ ++ return i; ++} ++ ++static int ps3vram_cache_init(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ pr_info("creating cache: %d entries, %d bytes pages\n", ++ CACHE_PAGE_COUNT, CACHE_PAGE_SIZE); ++ ++ priv->cache.page_count = CACHE_PAGE_COUNT; ++ priv->cache.page_size = CACHE_PAGE_SIZE; ++ priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) * ++ CACHE_PAGE_COUNT, GFP_KERNEL); ++ if (priv->cache.tags == NULL) { ++ pr_err("could not allocate cache tags\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void ps3vram_cache_cleanup(struct mtd_info *mtd) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ ps3vram_cache_flush(mtd); ++ kfree(priv->cache.tags); ++} ++ ++static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ ++ if (instr->addr + instr->len > mtd->size) ++ return -EINVAL; ++ ++ mutex_lock(&priv->lock); ++ ++ ps3vram_cache_flush(mtd); ++ ++ /* Set bytes to 0xFF */ ++ memset(priv->base + instr->addr, 0xFF, instr->len); ++ ++ mutex_unlock(&priv->lock); ++ ++ instr->state = MTD_ERASE_DONE; ++ mtd_erase_callback(instr); ++ ++ return 0; ++} ++ ++ ++static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t *retlen, u_char *buf) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ unsigned int cached, count; ++ ++ dbg("from = 0x%08x len = 0x%zx", (unsigned int) from, len); ++ ++ if (from >= mtd->size) ++ return -EINVAL; ++ ++ if (len > mtd->size - from) ++ len = mtd->size - from; ++ ++ /* Copy from vram to buf */ ++ count = len; ++ while (count) { ++ unsigned int offset, avail; ++ unsigned int entry; ++ ++ offset = (unsigned int) (from & (priv->cache.page_size - 1)); ++ avail = priv->cache.page_size - offset; ++ ++ mutex_lock(&priv->lock); ++ ++ entry = ps3vram_cache_match(mtd, from); ++ cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; ++ ++ dbg("from=%08x cached=%08x offset=%08x avail=%08x count=%08x", ++ (unsigned)from, cached, offset, avail, count); ++ ++ if (avail > count) ++ avail = count; ++ memcpy(buf, priv->xdr_buf + cached, avail); ++ ++ mutex_unlock(&priv->lock); ++ ++ buf += avail; ++ count -= avail; ++ from += avail; ++ } ++ ++ *retlen = len; ++ return 0; ++} ++ ++static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const u_char *buf) ++{ ++ struct ps3vram_priv *priv = mtd->priv; ++ unsigned int cached, count; ++ ++ if (to >= mtd->size) ++ return -EINVAL; ++ ++ if (len > mtd->size - to) ++ len = mtd->size - to; ++ ++ /* Copy from buf to vram */ ++ count = len; ++ while (count) { ++ unsigned int offset, avail; ++ unsigned int entry; ++ ++ offset = (unsigned int) (to & (priv->cache.page_size - 1)); ++ avail = priv->cache.page_size - offset; ++ ++ mutex_lock(&priv->lock); ++ ++ entry = ps3vram_cache_match(mtd, to); ++ cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; ++ ++ dbg("to=%08x cached=%08x offset=%08x avail=%08x count=%08x", ++ (unsigned) to, cached, offset, avail, count); ++ ++ if (avail > count) ++ avail = count; ++ memcpy(priv->xdr_buf + cached, buf, avail); ++ ++ priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; ++ ++ mutex_unlock(&priv->lock); ++ ++ buf += avail; ++ count -= avail; ++ to += avail; ++ } ++ ++ *retlen = len; ++ return 0; ++} ++ ++static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) ++{ ++ struct ps3vram_priv *priv; ++ uint64_t status; ++ uint64_t ddr_lpar, ctrl_lpar, info_lpar, reports_lpar; ++ int64_t ddr_size; ++ uint64_t reports_size; ++ int ret = -ENOMEM; ++ char *rest; ++ ++ ret = -EIO; ++ ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL); ++ if (!ps3vram_mtd.priv) ++ goto out; ++ priv = ps3vram_mtd.priv; ++ ++ mutex_init(&priv->lock); ++ ++ /* Allocate XDR buffer (1MB aligned) */ ++ priv->xdr_buf = (uint8_t *) __get_free_pages(GFP_KERNEL, ++ get_order(XDR_BUF_SIZE)); ++ if (priv->xdr_buf == NULL) { ++ pr_err("ps3vram: could not allocate XDR buffer\n"); ++ ret = -ENOMEM; ++ goto out_free_priv; ++ } ++ ++ /* Put FIFO at begginning of XDR buffer */ ++ priv->fifo_base = (uint32_t *) (priv->xdr_buf + FIFO_OFFSET); ++ priv->fifo_ptr = priv->fifo_base; ++ ++ /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */ ++ if (ps3_open_hv_device(dev)) { ++ pr_err("ps3vram: ps3_open_hv_device failed\n"); ++ ret = -EAGAIN; ++ goto out_close_gpu; ++ } ++ ++ /* Request memory */ ++ status = -1; ++ ddr_size = memparse(size, &rest); ++ if (*rest == '-') ++ ddr_size -= ps3fb_videomemory.size; ++ ddr_size = ALIGN(ddr_size, 1024*1024); ++ if (ddr_size <= 0) { ++ printk(KERN_ERR "ps3vram: specified size is too small\n"); ++ ret = -EINVAL; ++ goto out_close_gpu; ++ } ++ ++ while (ddr_size > 0) { ++ status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, ++ &priv->memory_handle, ++ &ddr_lpar); ++ if (status == 0) ++ break; ++ ddr_size -= 1024*1024; ++ } ++ if (status != 0 || ddr_size <= 0) { ++ pr_err("ps3vram: lv1_gpu_memory_allocate failed\n"); ++ ret = -ENOMEM; ++ goto out_free_xdr_buf; ++ } ++ pr_info("ps3vram: allocated %u MiB of DDR memory\n", ++ (unsigned int) (ddr_size / 1024 / 1024)); ++ ++ /* Request context */ ++ status = lv1_gpu_context_allocate(priv->memory_handle, ++ 0, ++ &priv->context_handle, ++ &ctrl_lpar, ++ &info_lpar, ++ &reports_lpar, ++ &reports_size); ++ if (status) { ++ pr_err("ps3vram: lv1_gpu_context_allocate failed\n"); ++ ret = -ENOMEM; ++ goto out_free_memory; ++ } ++ ++ /* Map XDR buffer to RSX */ ++ status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, ++ ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), ++ XDR_BUF_SIZE, 0); ++ if (status) { ++ pr_err("ps3vram: lv1_gpu_context_iomap failed\n"); ++ ret = -ENOMEM; ++ goto out_free_context; ++ } ++ ++ priv->base = ioremap(ddr_lpar, ddr_size); ++ if (!priv->base) { ++ pr_err("ps3vram: ioremap failed\n"); ++ ret = -ENOMEM; ++ goto out_free_context; ++ } ++ ++ priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); ++ if (!priv->ctrl) { ++ pr_err("ps3vram: ioremap failed\n"); ++ ret = -ENOMEM; ++ goto out_unmap_vram; ++ } ++ ++ priv->reports = ioremap(reports_lpar, reports_size); ++ if (!priv->reports) { ++ pr_err("ps3vram: ioremap failed\n"); ++ ret = -ENOMEM; ++ goto out_unmap_ctrl; ++ } ++ ++ mutex_lock(&ps3_gpu_mutex); ++ ps3vram_init_ring(&ps3vram_mtd); ++ mutex_unlock(&ps3_gpu_mutex); ++ ++ ps3vram_mtd.name = "ps3vram"; ++ ps3vram_mtd.size = ddr_size; ++ ps3vram_mtd.flags = MTD_CAP_RAM; ++ ps3vram_mtd.erase = ps3vram_erase; ++ ps3vram_mtd.point = NULL; ++ ps3vram_mtd.unpoint = NULL; ++ ps3vram_mtd.read = ps3vram_read; ++ ps3vram_mtd.write = ps3vram_write; ++ ps3vram_mtd.owner = THIS_MODULE; ++ ps3vram_mtd.type = MTD_RAM; ++ ps3vram_mtd.erasesize = CACHE_PAGE_SIZE; ++ ps3vram_mtd.writesize = 1; ++ ++ ps3vram_bind(&ps3vram_mtd); ++ ++ mutex_lock(&ps3_gpu_mutex); ++ ret = ps3vram_wait_ring(&ps3vram_mtd, 100); ++ mutex_unlock(&ps3_gpu_mutex); ++ if (ret < 0) { ++ pr_err("failed to initialize channels\n"); ++ ret = -ETIMEDOUT; ++ goto out_unmap_reports; ++ } ++ ++ ps3vram_cache_init(&ps3vram_mtd); ++ ++ if (add_mtd_device(&ps3vram_mtd)) { ++ pr_err("ps3vram: failed to register device\n"); ++ ret = -EAGAIN; ++ goto out_cache_cleanup; ++ } ++ ++ pr_info("ps3vram mtd device registered, %lu bytes\n", ddr_size); ++ return 0; ++ ++out_cache_cleanup: ++ ps3vram_cache_cleanup(&ps3vram_mtd); ++out_unmap_reports: ++ iounmap(priv->reports); ++out_unmap_ctrl: ++ iounmap(priv->ctrl); ++out_unmap_vram: ++ iounmap(priv->base); ++out_free_context: ++ lv1_gpu_context_free(priv->context_handle); ++out_free_memory: ++ lv1_gpu_memory_free(priv->memory_handle); ++out_close_gpu: ++ ps3_close_hv_device(dev); ++out_free_xdr_buf: ++ free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); ++out_free_priv: ++ kfree(ps3vram_mtd.priv); ++ ps3vram_mtd.priv = NULL; ++out: ++ return ret; ++} ++ ++static int ps3vram_shutdown(struct ps3_system_bus_device *dev) ++{ ++ struct ps3vram_priv *priv; ++ ++ priv = ps3vram_mtd.priv; ++ ++ del_mtd_device(&ps3vram_mtd); ++ ps3vram_cache_cleanup(&ps3vram_mtd); ++ iounmap(priv->reports); ++ iounmap(priv->ctrl); ++ iounmap(priv->base); ++ lv1_gpu_context_free(priv->context_handle); ++ lv1_gpu_memory_free(priv->memory_handle); ++ ps3_close_hv_device(dev); ++ free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); ++ kfree(priv); ++ return 0; ++} ++ ++static struct ps3_system_bus_driver ps3vram_driver = { ++ .match_id = PS3_MATCH_ID_GRAPHICS, ++ .match_sub_id = PS3_MATCH_SUB_ID_RAMDISK, ++ .core.name = DEVICE_NAME, ++ .core.owner = THIS_MODULE, ++ .probe = ps3vram_probe, ++ .remove = ps3vram_shutdown, ++ .shutdown = ps3vram_shutdown, ++}; ++ ++static int __init ps3vram_init(void) ++{ ++ return ps3_system_bus_driver_register(&ps3vram_driver); ++} ++ ++static void __exit ps3vram_exit(void) ++{ ++ ps3_system_bus_driver_unregister(&ps3vram_driver); ++} ++ ++module_init(ps3vram_init); ++module_exit(ps3vram_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jim Paris "); ++MODULE_DESCRIPTION("MTD driver for PS3 video RAM"); +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3353,6 +3353,12 @@ L: linuxppc-dev@ozlabs.org + L: cbe-oss-dev@ozlabs.org + S: Supported + ++PS3VRAM DRIVER ++P: Jim Paris ++M: jim@jtan.com ++L: cbe-oss-dev@ozlabs.org ++S: Maintained ++ + PVRUSB2 VIDEO4LINUX DRIVER + P: Mike Isely + M: isely@pobox.com diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-bsr-4k.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-bsr-4k.patch new file mode 100644 index 000000000..711448c83 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-bsr-4k.patch @@ -0,0 +1,57 @@ +Subject: Unable to Use Small BSR register on Power LPAR +From: Sonny Rao +References: 443673 - LTC49749 + +Fix the BSR driver to allow small BSR devices on a 64k page kernel. +Previously the driver would reject the mmap since the size was smaller +than PAGESIZE. This patch adds a check for this case and uses remap_4k_pfn(). + +Also, take out code to set vm_flags, as the remap_pfn functions will +do this for us. + +Signed-off-by: Sonny Rao +Signed-off-by: Olaf Hering + +--- + drivers/char/bsr.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +--- a/drivers/char/bsr.c ++++ b/drivers/char/bsr.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + /* +@@ -115,15 +116,22 @@ static int bsr_mmap(struct file *filp, s + { + unsigned long size = vma->vm_end - vma->vm_start; + struct bsr_dev *dev = filp->private_data; ++ int ret; + +- if (size > dev->bsr_len || (size & (PAGE_SIZE-1))) +- return -EINVAL; +- +- vma->vm_flags |= (VM_IO | VM_DONTEXPAND); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + +- if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT, +- size, vma->vm_page_prot)) ++ /* check for the case of a small BSR device and map one 4k page for it*/ ++ if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE) ++ ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12, ++ vma->vm_page_prot); ++ else if (size <= dev->bsr_len) ++ ret = io_remap_pfn_range(vma, vma->vm_start, ++ dev->bsr_addr >> PAGE_SHIFT, ++ size, vma->vm_page_prot); ++ else ++ return -EINVAL; ++ ++ if (ret) + return -EAGAIN; + + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-bsr-multinode.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-bsr-multinode.patch new file mode 100644 index 000000000..5ff8031fc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-bsr-multinode.patch @@ -0,0 +1,206 @@ +Subject: Add support for multiple BSR nodes in the device tree. +From: Sonny Rao +References: 443665 - LTC49817 + +Previously, the BSR driver only supported a single OF node describing +a BSR. Apparently when an LPAR is set to use "all system resources" +the BSR appears as a single node, but when it is handed out in pieces, +each 8 byte piece gets its own node. So, keep a list of bsr devices +instead of the array and include all nodes. + +Also, be more inclusive of what BSR devices we accept by only checking +compatibility and not the device name property (which might change in +the future versions of BSR). + +Signed-off-by: Sonny Rao +Signed-off-by: Olaf Hering + +--- + drivers/char/bsr.c | 84 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 55 insertions(+), 29 deletions(-) + +--- a/drivers/char/bsr.c ++++ b/drivers/char/bsr.c +@@ -61,6 +61,8 @@ struct bsr_dev { + unsigned bsr_num; /* bsr id number for its type */ + int bsr_minor; + ++ struct list_head bsr_list; ++ + dev_t bsr_dev; + struct cdev bsr_cdev; + struct device *bsr_device; +@@ -68,8 +70,8 @@ struct bsr_dev { + + }; + +-static unsigned num_bsr_devs; +-static struct bsr_dev *bsr_devs; ++static unsigned total_bsr_devs; ++static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs); + static struct class *bsr_class; + static int bsr_major; + +@@ -154,24 +156,25 @@ const static struct file_operations bsr_ + + static void bsr_cleanup_devs(void) + { +- int i; +- for (i=0 ; i < num_bsr_devs; i++) { +- struct bsr_dev *cur = bsr_devs + i; ++ struct bsr_dev *cur, *n; ++ ++ list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) { + if (cur->bsr_device) { + cdev_del(&cur->bsr_cdev); + device_del(cur->bsr_device); + } ++ list_del(&cur->bsr_list); ++ kfree(cur); + } +- +- kfree(bsr_devs); + } + +-static int bsr_create_devs(struct device_node *bn) ++static int bsr_add_node(struct device_node *bn) + { +- int bsr_stride_len, bsr_bytes_len; ++ int bsr_stride_len, bsr_bytes_len, num_bsr_devs; + const u32 *bsr_stride; + const u32 *bsr_bytes; + unsigned i; ++ int ret = -ENODEV; + + bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len); + bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len); +@@ -179,35 +182,36 @@ static int bsr_create_devs(struct device + if (!bsr_stride || !bsr_bytes || + (bsr_stride_len != bsr_bytes_len)) { + printk(KERN_ERR "bsr of-node has missing/incorrect property\n"); +- return -ENODEV; ++ return ret; + } + + num_bsr_devs = bsr_bytes_len / sizeof(u32); + +- /* only a warning, its informational since we'll fail and exit */ +- WARN_ON(num_bsr_devs > BSR_MAX_DEVS); +- +- bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL); +- if (!bsr_devs) +- return -ENOMEM; +- + for (i = 0 ; i < num_bsr_devs; i++) { +- struct bsr_dev *cur = bsr_devs + i; ++ struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev), ++ GFP_KERNEL); + struct resource res; + int result; + ++ if (!cur) { ++ printk(KERN_ERR "Unable to alloc bsr dev\n"); ++ ret = -ENOMEM; ++ goto out_err; ++ } ++ + result = of_address_to_resource(bn, i, &res); + if (result < 0) { +- printk(KERN_ERR "bsr of-node has invalid reg property\n"); +- goto out_err; ++ printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n"); ++ kfree(cur); ++ continue; + } + +- cur->bsr_minor = i; ++ cur->bsr_minor = i + total_bsr_devs; + cur->bsr_addr = res.start; + cur->bsr_len = res.end - res.start + 1; + cur->bsr_bytes = bsr_bytes[i]; + cur->bsr_stride = bsr_stride[i]; +- cur->bsr_dev = MKDEV(bsr_major, i); ++ cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); + + switch(cur->bsr_bytes) { + case 8: +@@ -228,14 +232,15 @@ static int bsr_create_devs(struct device + } + + cur->bsr_num = bsr_types[cur->bsr_type]; +- bsr_types[cur->bsr_type] = cur->bsr_num + 1; + snprintf(cur->bsr_name, 32, "bsr%d_%d", + cur->bsr_bytes, cur->bsr_num); + + cdev_init(&cur->bsr_cdev, &bsr_fops); + result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1); +- if (result) ++ if (result) { ++ kfree(cur); + goto out_err; ++ } + + cur->bsr_device = device_create_drvdata(bsr_class, NULL, + cur->bsr_dev, +@@ -244,16 +249,37 @@ static int bsr_create_devs(struct device + printk(KERN_ERR "device_create failed for %s\n", + cur->bsr_name); + cdev_del(&cur->bsr_cdev); ++ kfree(cur); + goto out_err; + } ++ ++ bsr_types[cur->bsr_type] = cur->bsr_num + 1; ++ list_add_tail(&cur->bsr_list, &bsr_devs); + } + ++ total_bsr_devs += num_bsr_devs; ++ + return 0; + + out_err: + + bsr_cleanup_devs(); +- return -ENODEV; ++ return ret; ++} ++ ++static int bsr_create_devs(struct device_node *bn) ++{ ++ int ret; ++ ++ while (bn) { ++ ret = bsr_add_node(bn); ++ if (ret) { ++ of_node_put(bn); ++ return ret; ++ } ++ bn = of_find_compatible_node(bn, NULL, "ibm,bsr"); ++ } ++ return 0; + } + + static int __init bsr_init(void) +@@ -263,7 +289,7 @@ static int __init bsr_init(void) + int ret = -ENODEV; + int result; + +- np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr"); ++ np = of_find_compatible_node(NULL, NULL, "ibm,bsr"); + if (!np) + goto out_err; + +@@ -281,10 +307,10 @@ static int __init bsr_init(void) + goto out_err_2; + } + +- if ((ret = bsr_create_devs(np)) < 0) ++ if ((ret = bsr_create_devs(np)) < 0) { ++ np = NULL; + goto out_err_3; +- +- of_node_put(np); ++ } + + return 0; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-cmm-pagecounter.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-cmm-pagecounter.patch new file mode 100644 index 000000000..998a06c79 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-cmm-pagecounter.patch @@ -0,0 +1,73 @@ +Subject: powerpc: Update page in counter for CMM +From: Brian King +References: 445540 - LTC49942 + +A new field has been added to the VPA as a method for +the client OS to communicate to firmware the number of +page ins it is performing when running collaborative +memory overcommit. The hypervisor will use this information +to better determine if a partition is experiencing memory +pressure and needs more memory allocated to it. + +Signed-off-by: Brian King +Signed-off-by: Robert Jennings +Signed-off-by: Olaf Hering + +--- + + arch/powerpc/include/asm/lppaca.h | 3 ++- + arch/powerpc/kernel/paca.c | 1 + + arch/powerpc/mm/fault.c | 12 ++++++++++-- + 3 files changed, 13 insertions(+), 3 deletions(-) + +--- a/arch/powerpc/include/asm/lppaca.h ++++ b/arch/powerpc/include/asm/lppaca.h +@@ -133,7 +133,8 @@ struct lppaca { + //============================================================================= + // CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data + //============================================================================= +- u8 pmc_save_area[256]; // PMC interrupt Area x00-xFF ++ u32 page_ins; // CMO Hint - # page ins by OS x00-x04 ++ u8 pmc_save_area[252]; // PMC interrupt Area x04-xFF + } __attribute__((__aligned__(0x400))); + + extern struct lppaca lppaca[]; +--- a/arch/powerpc/kernel/paca.c ++++ b/arch/powerpc/kernel/paca.c +@@ -36,6 +36,7 @@ struct lppaca lppaca[] = { + .end_of_quantum = 0xfffffffffffffffful, + .slb_count = 64, + .vmxregs_in_use = 0, ++ .page_ins = 0, + }, + }; + +--- a/arch/powerpc/mm/fault.c ++++ b/arch/powerpc/mm/fault.c +@@ -30,6 +30,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -318,9 +319,16 @@ good_area: + goto do_sigbus; + BUG(); + } +- if (ret & VM_FAULT_MAJOR) ++ if (ret & VM_FAULT_MAJOR) { + current->maj_flt++; +- else ++#ifdef CONFIG_PPC_SMLPAR ++ if (firmware_has_feature(FW_FEATURE_CMO)) { ++ preempt_disable(); ++ get_lppaca()->page_ins += (1 << PAGE_FACTOR); ++ preempt_enable(); ++ } ++#endif ++ } else + current->min_flt++; + up_read(&mm->mmap_sem); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-cpu-migrate.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-cpu-migrate.patch new file mode 100644 index 000000000..e1c0de5ba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-cpu-migrate.patch @@ -0,0 +1,60 @@ +Subject: Update default_server during migrate_irqs_away +From: Milton Miller +References: 460566 - LTC50723 + +Currently, every time we determine which irq server to use, we check if +default_server, which is the id of the bootcpu, is still online. But +default_server is a hardware cpu, not the logical cpu id needed to index +cpu_online_map. + +Since the default server can only go offline during a cpu hotplug event, +explicitly check the default server and choose the new one when we move +irqs away from the cpu being offlined. + +This has the added benefit of only needing the boot_cpuid to be updated +and not relying on the cpu being marked offline during migrate_irqs_away. + +Also, since xics_update_irq_servers only reads device tree information, we +can call it before xics_init_host in xics_init_IRQ and then default_server +will always be valid when we can reach get_irq_server via the host ops. + +Signed-off-by: Milton Miller +Signed-off-by: Benjamin Herrenschmidt +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/pseries/xics.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/arch/powerpc/platforms/pseries/xics.c ++++ b/arch/powerpc/platforms/pseries/xics.c +@@ -208,9 +208,6 @@ static int get_irq_server(unsigned int v + cpumask_t cpumask = irq_desc[virq].affinity; + cpumask_t tmp = CPU_MASK_NONE; + +- if (! cpu_isset(default_server, cpu_online_map)) +- xics_update_irq_servers(); +- + if (!distribute_irqs) + return default_server; + +@@ -659,8 +656,8 @@ void __init xics_init_IRQ(void) + if (found == 0) + return; + +- xics_init_host(); + xics_update_irq_servers(); ++ xics_init_host(); + + if (firmware_has_feature(FW_FEATURE_LPAR)) + ppc_md.get_irq = xics_get_irq_lpar; +@@ -753,6 +750,10 @@ void xics_migrate_irqs_away(void) + int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); + unsigned int irq, virq; + ++ /* If we used to be the default server, move to the new "boot_cpuid" */ ++ if (hw_cpu == default_server) ++ xics_update_irq_servers(); ++ + /* Reject any interrupt that was queued to us... */ + xics_set_cpu_priority(0); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-migration_hang_fix.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-migration_hang_fix.patch new file mode 100644 index 000000000..7a02348ca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries-migration_hang_fix.patch @@ -0,0 +1,69 @@ +Subject: Fix partition migration hang under load +From: Brian King +References: 470563 - LTC51153 + +While testing partition migration with heavy CPU load using +shared processors, it was observed that sometimes the migration +would never complete and would appear to hang. Currently, the +migration code assumes that if H_SUCCESS is returned from the H_JOIN +then the migration is complete and the processor is waking up on +the target system. If there was an outstanding PROD to the processor +when the H_JOIN is called, however, it will return H_SUCCESS on the source +system, causing the migration to hang, or in some scenarios cause +the kernel to crash on the complete call waking the caller +of rtas_percpu_suspend_me. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + arch/powerpc/kernel/rtas.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/kernel/rtas.c ++++ b/arch/powerpc/kernel/rtas.c +@@ -46,6 +46,7 @@ EXPORT_SYMBOL(rtas); + + struct rtas_suspend_me_data { + atomic_t working; /* number of cpus accessing this struct */ ++ atomic_t done; + int token; /* ibm,suspend-me */ + int error; + struct completion *complete; /* wait on this until working == 0 */ +@@ -663,7 +664,7 @@ static int ibm_suspend_me_token = RTAS_U + #ifdef CONFIG_PPC_PSERIES + static void rtas_percpu_suspend_me(void *info) + { +- long rc; ++ long rc = H_SUCCESS; + unsigned long msr_save; + int cpu; + struct rtas_suspend_me_data *data = +@@ -675,7 +676,8 @@ static void rtas_percpu_suspend_me(void + msr_save = mfmsr(); + mtmsr(msr_save & ~(MSR_EE)); + +- rc = plpar_hcall_norets(H_JOIN); ++ while (rc == H_SUCCESS && !atomic_read(&data->done)) ++ rc = plpar_hcall_norets(H_JOIN); + + mtmsr(msr_save); + +@@ -698,6 +700,9 @@ static void rtas_percpu_suspend_me(void + smp_processor_id(), rc); + data->error = rc; + } ++ ++ atomic_set(&data->done, 1); ++ + /* This cpu did the suspend or got an error; in either case, + * we need to prod all other other cpus out of join state. + * Extra prods are harmless. +@@ -740,6 +745,7 @@ static int rtas_ibm_suspend_me(struct rt + } + + atomic_set(&data.working, 0); ++ atomic_set(&data.done, 0); + data.token = rtas_token("ibm,suspend-me"); + data.error = 0; + data.complete = &done; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries_pfn-mem-rm.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries_pfn-mem-rm.patch new file mode 100644 index 000000000..5ffe36fe2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries_pfn-mem-rm.patch @@ -0,0 +1,46 @@ +Subject: Bug 435181 - DMEM add caused kernel opps after ehca rejected request +From: olh@suse.de +References: 435181 + +--- + arch/powerpc/platforms/pseries/hotplug-memory.c | 12 ++++++++++++ + mm/memory_hotplug.c | 4 ++-- + 2 files changed, 14 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/platforms/pseries/hotplug-memory.c ++++ b/arch/powerpc/platforms/pseries/hotplug-memory.c +@@ -22,6 +22,18 @@ static int pseries_remove_lmb(unsigned l + int ret; + + start_pfn = base >> PAGE_SHIFT; ++ ++ if (!pfn_valid(start_pfn)) { ++ /* ++ * Failing hotplug memory add will end up calling ++ * remove device node to clean up. Since its already ++ * added to lmbs, we need to remove it and pretend ++ * success. ++ */ ++ lmb_remove(base, lmb_size); ++ return 0; ++ } ++ + zone = page_zone(pfn_to_page(start_pfn)); + + /* +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -323,11 +323,11 @@ int __remove_pages(struct zone *zone, un + BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK); + BUG_ON(nr_pages % PAGES_PER_SECTION); + +- release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE); +- + sections_to_remove = nr_pages / PAGES_PER_SECTION; + for (i = 0; i < sections_to_remove; i++) { + unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION; ++ release_mem_region(pfn << PAGE_SHIFT, ++ PAGES_PER_SECTION << PAGE_SHIFT); + ret = __remove_section(zone, __pfn_to_section(pfn)); + if (ret) + break; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries_remove_lmb-PAGE_SHIFTT.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries_remove_lmb-PAGE_SHIFTT.patch new file mode 100644 index 000000000..1d20fd09b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-pseries_remove_lmb-PAGE_SHIFTT.patch @@ -0,0 +1,32 @@ +Subject: Bug 431380 – UPT-LTE: mem dlpar remove generates oops(.pseries_remove_lmb+0x28/0xb8) +From: Nathan Fontenot +References: 431380 - LTC48430 + + +Testing hotplug memory remove has revealed that we can oops in +pseries_lmb_remove(). The incorrect shift causes a NULL pointer +dereference in the page_zone() inline routine. + +I have only been able to reproduce the oops on kernels with large pages +enabled. + +Tested on Power5 and Power6 with and without large pages enabled. + + +Signed-off-by: Olaf Hering + +--- + arch/powerpc/platforms/pseries/hotplug-memory.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/platforms/pseries/hotplug-memory.c ++++ b/arch/powerpc/platforms/pseries/hotplug-memory.c +@@ -21,7 +21,7 @@ static int pseries_remove_lmb(unsigned l + struct zone *zone; + int ret; + +- start_pfn = base >> PFN_SECTION_SHIFT; ++ start_pfn = base >> PAGE_SHIFT; + zone = page_zone(pfn_to_page(start_pfn)); + + /* diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-select b/src/patches/suse-2.6.27.31/patches.arch/ppc-select new file mode 100644 index 000000000..9e6f043eb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-select @@ -0,0 +1,17 @@ +From: Paul Mackerras +Subject: Fix wrong error code from ppc32 select syscall +Acked-by: schwab@suse.de + +See . + +--- linux-2.6.27/arch/powerpc/include/asm/systbl.h.~1~ 2008-11-10 23:10:37.000000000 +0100 ++++ linux-2.6.27/arch/powerpc/include/asm/systbl.h 2008-11-11 11:39:06.000000000 +0100 +@@ -145,7 +145,7 @@ SYSCALL_SPU(setfsuid) + SYSCALL_SPU(setfsgid) + SYSCALL_SPU(llseek) + COMPAT_SYS_SPU(getdents) +-SYSX_SPU(sys_select,ppc32_select,ppc_select) ++SYSX_SPU(sys_select,ppc32_select,sys_select) + SYSCALL_SPU(flock) + SYSCALL_SPU(msync) + COMPAT_SYS_SPU(readv) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-01-use-inc_nlink.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-01-use-inc_nlink.patch new file mode 100644 index 000000000..2bf96e659 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-01-use-inc_nlink.patch @@ -0,0 +1,36 @@ +Subject: use inc_nlink +From: Jeremy Kerr +References: 447133 - LTC50070 + +Style change: use inc_nlink instead of incrementing i_nlink directly + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/inode.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/powerpc/platforms/cell/spufs/inode.c ++++ b/arch/powerpc/platforms/cell/spufs/inode.c +@@ -298,8 +298,8 @@ spufs_mkdir(struct inode *dir, struct de + + d_instantiate(dentry, inode); + dget(dentry); +- dir->i_nlink++; +- dentry->d_inode->i_nlink++; ++ inc_nlink(dir); ++ inc_nlink(dentry->d_inode); + goto out; + + out_free_ctx: +@@ -540,8 +540,8 @@ spufs_mkgang(struct inode *dir, struct d + inode->i_fop = &simple_dir_operations; + + d_instantiate(dentry, inode); +- dir->i_nlink++; +- dentry->d_inode->i_nlink++; ++ inc_nlink(dir); ++ inc_nlink(dentry->d_inode); + return ret; + + out_iput: diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-03-sputrace-Only-enable-logging-on-open.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-03-sputrace-Only-enable-logging-on-open.patch new file mode 100644 index 000000000..abb460d69 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-03-sputrace-Only-enable-logging-on-open.patch @@ -0,0 +1,83 @@ +Subject: Only enable logging on open(), prevent multiple openers +From: Jeremy Kerr +References: 447133 - LTC50070 + +Currently, sputrace will start logging to the event buffer before the +log buffer has been open()ed. This results in a heap of "lost samples" +warnings if the sputrace file hasn't yet been opened. + +Since the buffer is reset on open() anyway, there's no need to enable +logging when no-one has opened the log. + +Because open clears the log, make it return EBUSY for mutliple open +calls. + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/sputrace.c | 32 ++++++++++++++++++++++++--- + 1 file changed, 29 insertions(+), 3 deletions(-) + +--- a/arch/powerpc/platforms/cell/spufs/sputrace.c ++++ b/arch/powerpc/platforms/cell/spufs/sputrace.c +@@ -40,6 +40,7 @@ static DECLARE_WAIT_QUEUE_HEAD(sputrace_ + static ktime_t sputrace_start; + static unsigned long sputrace_head, sputrace_tail; + static struct sputrace *sputrace_log; ++static int sputrace_logging; + + static int sputrace_used(void) + { +@@ -109,24 +110,49 @@ static ssize_t sputrace_read(struct file + + static int sputrace_open(struct inode *inode, struct file *file) + { ++ int rc; ++ + spin_lock(&sputrace_lock); ++ if (sputrace_logging) { ++ rc = -EBUSY; ++ goto out; ++ } ++ ++ sputrace_logging = 1; + sputrace_head = sputrace_tail = 0; + sputrace_start = ktime_get(); ++ rc = 0; ++ ++out: + spin_unlock(&sputrace_lock); ++ return rc; ++} + ++static int sputrace_release(struct inode *inode, struct file *file) ++{ ++ spin_lock(&sputrace_lock); ++ sputrace_logging = 0; ++ spin_unlock(&sputrace_lock); + return 0; + } + + static const struct file_operations sputrace_fops = { +- .owner = THIS_MODULE, +- .open = sputrace_open, +- .read = sputrace_read, ++ .owner = THIS_MODULE, ++ .open = sputrace_open, ++ .read = sputrace_read, ++ .release = sputrace_release, + }; + + static void sputrace_log_item(const char *name, struct spu_context *ctx, + struct spu *spu) + { + spin_lock(&sputrace_lock); ++ ++ if (!sputrace_logging) { ++ spin_unlock(&sputrace_lock); ++ return; ++ } ++ + if (sputrace_avail() > 1) { + struct sputrace *t = sputrace_log + sputrace_head; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-04-sputrace-Don-t-block-until-the-read.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-04-sputrace-Don-t-block-until-the-read.patch new file mode 100644 index 000000000..c2ec818a5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-04-sputrace-Don-t-block-until-the-read.patch @@ -0,0 +1,32 @@ +Subject: Don't block until the read buffer is full +From: Jeremy Kerr +References: 447133 - LTC50070 + +Currently, read() on the sputrace buffer will only return data when +the user buffer is exhausted. This may mean that we never see the +end of the event log, unless we read() with exactly the right-sized +buffer. + +This change makes sputrace_read not block if we have data ready to +return. + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/sputrace.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/powerpc/platforms/cell/spufs/sputrace.c ++++ b/arch/powerpc/platforms/cell/spufs/sputrace.c +@@ -80,6 +80,11 @@ static ssize_t sputrace_read(struct file + char tbuf[128]; + int width; + ++ /* If we have data ready to return, don't block waiting ++ * for more */ ++ if (cnt > 0 && sputrace_used() == 0) ++ break; ++ + error = wait_event_interruptible(sputrace_wait, + sputrace_used() > 0); + if (error) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-05-Use-state_mutex-for-switch_log-lockin.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-05-Use-state_mutex-for-switch_log-lockin.patch new file mode 100644 index 000000000..0be692235 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-05-Use-state_mutex-for-switch_log-lockin.patch @@ -0,0 +1,264 @@ +Subject: Use state_mutex for switch_log locking, and prevent multiple openers +From: Jeremy Kerr +References: 447133 - LTC50070 + +Currently, we use ctx->mapping_lock and ctx->switch_log->lock for the +context switch log. The mapping lock only prevents concurrent open()s, +so we require the switch_lock->lock for reads. + +Since writes to the switch log buffer occur on context switches, we're +better off synchronising with the state_mutex, which is held during a +switch. Since we're serialised througout the buffer reads and writes, +we can use the state mutex to protect open and release too, and +can now kfree() the log buffer on release. This allows us to perform +the switch log notify without taking any extra locks. + +Because the buffer is only present while the file is open, we can use +it to prevent multiple simultaneous openers. + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/file.c | 133 ++++++++++++++++++------------ + arch/powerpc/platforms/cell/spufs/run.c | 3 + arch/powerpc/platforms/cell/spufs/spufs.h | 1 + 3 files changed, 81 insertions(+), 56 deletions(-) + +--- a/arch/powerpc/platforms/cell/spufs/file.c ++++ b/arch/powerpc/platforms/cell/spufs/file.c +@@ -2429,38 +2429,48 @@ static inline int spufs_switch_log_avail + static int spufs_switch_log_open(struct inode *inode, struct file *file) + { + struct spu_context *ctx = SPUFS_I(inode)->i_ctx; ++ int rc; ++ ++ rc = spu_acquire(ctx); ++ if (rc) ++ return rc; + +- /* +- * We (ab-)use the mapping_lock here because it serves the similar +- * purpose for synchronizing open/close elsewhere. Maybe it should +- * be renamed eventually. +- */ +- mutex_lock(&ctx->mapping_lock); + if (ctx->switch_log) { +- spin_lock(&ctx->switch_log->lock); +- ctx->switch_log->head = 0; +- ctx->switch_log->tail = 0; +- spin_unlock(&ctx->switch_log->lock); +- } else { +- /* +- * We allocate the switch log data structures on first open. +- * They will never be free because we assume a context will +- * be traced until it goes away. +- */ +- ctx->switch_log = kzalloc(sizeof(struct switch_log) + +- SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry), +- GFP_KERNEL); +- if (!ctx->switch_log) +- goto out; +- spin_lock_init(&ctx->switch_log->lock); +- init_waitqueue_head(&ctx->switch_log->wait); ++ rc = -EBUSY; ++ goto out; ++ } ++ ++ ctx->switch_log = kzalloc(sizeof(struct switch_log) + ++ SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry), ++ GFP_KERNEL); ++ ++ if (!ctx->switch_log) { ++ rc = -ENOMEM; ++ goto out; + } +- mutex_unlock(&ctx->mapping_lock); ++ ++ init_waitqueue_head(&ctx->switch_log->wait); ++ rc = 0; ++ ++out: ++ spu_release(ctx); ++ return rc; ++} ++ ++static int spufs_switch_log_release(struct inode *inode, struct file *file) ++{ ++ struct spu_context *ctx = SPUFS_I(inode)->i_ctx; ++ int rc; ++ ++ rc = spu_acquire(ctx); ++ if (rc) ++ return rc; ++ ++ kfree(ctx->switch_log); ++ ctx->switch_log = NULL; ++ spu_release(ctx); + + return 0; +- out: +- mutex_unlock(&ctx->mapping_lock); +- return -ENOMEM; + } + + static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) +@@ -2488,42 +2498,46 @@ static ssize_t spufs_switch_log_read(str + if (!buf || len < 0) + return -EINVAL; + ++ error = spu_acquire(ctx); ++ if (error) ++ return error; ++ + while (cnt < len) { + char tbuf[128]; + int width; + + if (file->f_flags & O_NONBLOCK) { +- if (spufs_switch_log_used(ctx) <= 0) +- return cnt ? cnt : -EAGAIN; ++ if (spufs_switch_log_used(ctx) == 0) { ++ error = -EAGAIN; ++ break; ++ } + } else { +- /* Wait for data in buffer */ +- error = wait_event_interruptible(ctx->switch_log->wait, ++ /* spufs_wait will drop the mutex and re-acquire, ++ * but since we're in read(), the file cannot be ++ * _released (and so ctx->switch_log is stable). ++ */ ++ error = spufs_wait(ctx->switch_log->wait, + spufs_switch_log_used(ctx) > 0); ++ ++ /* On error, spufs_wait returns without the ++ * state mutex held */ + if (error) +- break; ++ return error; + } + +- spin_lock(&ctx->switch_log->lock); +- if (ctx->switch_log->head == ctx->switch_log->tail) { +- /* multiple readers race? */ +- spin_unlock(&ctx->switch_log->lock); ++ /* We may have had entries read from underneath us while we ++ * dropped the mutex in spufs_wait, so re-check */ ++ if (ctx->switch_log->head == ctx->switch_log->tail) + continue; +- } + + width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); +- if (width < len) { ++ if (width < len) + ctx->switch_log->tail = + (ctx->switch_log->tail + 1) % + SWITCH_LOG_BUFSIZE; +- } +- +- spin_unlock(&ctx->switch_log->lock); +- +- /* +- * If the record is greater than space available return +- * partial buffer (so far) +- */ +- if (width >= len) ++ else ++ /* If the record is greater than space available return ++ * partial buffer (so far) */ + break; + + error = copy_to_user(buf + cnt, tbuf, width); +@@ -2532,6 +2546,8 @@ static ssize_t spufs_switch_log_read(str + cnt += width; + } + ++ spu_release(ctx); ++ + return cnt == 0 ? error : cnt; + } + +@@ -2540,29 +2556,41 @@ static unsigned int spufs_switch_log_pol + struct inode *inode = file->f_path.dentry->d_inode; + struct spu_context *ctx = SPUFS_I(inode)->i_ctx; + unsigned int mask = 0; ++ int rc; + + poll_wait(file, &ctx->switch_log->wait, wait); + ++ rc = spu_acquire(ctx); ++ if (rc) ++ return rc; ++ + if (spufs_switch_log_used(ctx) > 0) + mask |= POLLIN; + ++ spu_release(ctx); ++ + return mask; + } + + static const struct file_operations spufs_switch_log_fops = { +- .owner = THIS_MODULE, +- .open = spufs_switch_log_open, +- .read = spufs_switch_log_read, +- .poll = spufs_switch_log_poll, ++ .owner = THIS_MODULE, ++ .open = spufs_switch_log_open, ++ .read = spufs_switch_log_read, ++ .poll = spufs_switch_log_poll, ++ .release = spufs_switch_log_release, + }; + ++/** ++ * Log a context switch event to a switch log reader. ++ * ++ * Must be called with ctx->state_mutex held. ++ */ + void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, + u32 type, u32 val) + { + if (!ctx->switch_log) + return; + +- spin_lock(&ctx->switch_log->lock); + if (spufs_switch_log_avail(ctx) > 1) { + struct switch_log_entry *p; + +@@ -2576,7 +2604,6 @@ void spu_switch_log_notify(struct spu *s + ctx->switch_log->head = + (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; + } +- spin_unlock(&ctx->switch_log->lock); + + wake_up(&ctx->switch_log->wait); + } +--- a/arch/powerpc/platforms/cell/spufs/run.c ++++ b/arch/powerpc/platforms/cell/spufs/run.c +@@ -249,6 +249,7 @@ static int spu_run_fini(struct spu_conte + + spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); + clear_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags); ++ spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, *status); + spu_release(ctx); + + if (signal_pending(current)) +@@ -417,8 +418,6 @@ long spufs_run_spu(struct spu_context *c + ret = spu_run_fini(ctx, npc, &status); + spu_yield(ctx); + +- spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, status); +- + if ((status & SPU_STATUS_STOPPED_BY_STOP) && + (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) + ctx->stats.libassist++; +--- a/arch/powerpc/platforms/cell/spufs/spufs.h ++++ b/arch/powerpc/platforms/cell/spufs/spufs.h +@@ -65,7 +65,6 @@ enum { + }; + + struct switch_log { +- spinlock_t lock; + wait_queue_head_t wait; + unsigned long head; + unsigned long tail; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-06-Don-t-require-full-buffer-in-switch_l.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-06-Don-t-require-full-buffer-in-switch_l.patch new file mode 100644 index 000000000..b65d8d461 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-06-Don-t-require-full-buffer-in-switch_l.patch @@ -0,0 +1,78 @@ +Subject: Don't require full buffer in switch_log read +From: Jeremy Kerr +References: 447133 - LTC50070 + +Currently, read() on the sputrace log will block until the read buffer +is full. This makes it difficult to retrieve the end of the buffer, as +the user will need to read with the right-sized buffer. + +In a similar method as 91553a1b5e0df006a3573a88d98ee7cd48a3818a, this +change makes the switch_log return if there has already been data +read. + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/file.c | 46 ++++++++++++++++++------------- + 1 file changed, 27 insertions(+), 19 deletions(-) + +--- a/arch/powerpc/platforms/cell/spufs/file.c ++++ b/arch/powerpc/platforms/cell/spufs/file.c +@@ -2506,30 +2506,38 @@ static ssize_t spufs_switch_log_read(str + char tbuf[128]; + int width; + +- if (file->f_flags & O_NONBLOCK) { +- if (spufs_switch_log_used(ctx) == 0) { ++ if (spufs_switch_log_used(ctx) == 0) { ++ if (cnt > 0) { ++ /* If there's data ready to go, we can ++ * just return straight away */ ++ break; ++ ++ } else if (file->f_flags & O_NONBLOCK) { + error = -EAGAIN; + break; ++ ++ } else { ++ /* spufs_wait will drop the mutex and ++ * re-acquire, but since we're in read(), the ++ * file cannot be _released (and so ++ * ctx->switch_log is stable). ++ */ ++ error = spufs_wait(ctx->switch_log->wait, ++ spufs_switch_log_used(ctx) > 0); ++ ++ /* On error, spufs_wait returns without the ++ * state mutex held */ ++ if (error) ++ return error; ++ ++ /* We may have had entries read from underneath ++ * us while we dropped the mutex in spufs_wait, ++ * so re-check */ ++ if (spufs_switch_log_used(ctx) == 0) ++ continue; + } +- } else { +- /* spufs_wait will drop the mutex and re-acquire, +- * but since we're in read(), the file cannot be +- * _released (and so ctx->switch_log is stable). +- */ +- error = spufs_wait(ctx->switch_log->wait, +- spufs_switch_log_used(ctx) > 0); +- +- /* On error, spufs_wait returns without the +- * state mutex held */ +- if (error) +- return error; + } + +- /* We may have had entries read from underneath us while we +- * dropped the mutex in spufs_wait, so re-check */ +- if (ctx->switch_log->head == ctx->switch_log->tail) +- continue; +- + width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); + if (width < len) + ctx->switch_log->tail = diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-07-Don-t-spu_acquire_saved-unnecessarily.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-07-Don-t-spu_acquire_saved-unnecessarily.patch new file mode 100644 index 000000000..597aeb86b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-07-Don-t-spu_acquire_saved-unnecessarily.patch @@ -0,0 +1,32 @@ +Subject: Don't spu_acquire_saved unnecessarily in regs read +From: Jeremy Kerr +References: 447133 - LTC50070 + +With most file readers (eg cat, dd), reading a context's regs file will +result in two reads: the first to read the data, and the second to +return EOF. Because each read performs a spu_acquire_saved, we end up +descheduling and re-scheduling the context twice. + +This change does a simple check to see if we'd return EOF before +calling spu_acquire_saved(), saving the extra schedule operation. + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/file.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/powerpc/platforms/cell/spufs/file.c ++++ b/arch/powerpc/platforms/cell/spufs/file.c +@@ -551,6 +551,11 @@ spufs_regs_read(struct file *file, char + int ret; + struct spu_context *ctx = file->private_data; + ++ /* pre-check for file position: if we'd return EOF, there's no point ++ * causing a deschedule */ ++ if (*pos >= sizeof(ctx->csa.lscsa->gprs)) ++ return 0; ++ + ret = spu_acquire_saved(ctx); + if (ret) + return ret; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-08-Use-kmalloc-rather-than-kzalloc-for-s.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-08-Use-kmalloc-rather-than-kzalloc-for-s.patch new file mode 100644 index 000000000..184bf3d1a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-08-Use-kmalloc-rather-than-kzalloc-for-s.patch @@ -0,0 +1,31 @@ +Subject: Use kmalloc rather than kzalloc for switch log buffer +From: Jeremy Kerr +References: 447133 - LTC50070 + +No need to zero the entire buffer, just the head and tail indices. + +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/file.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/powerpc/platforms/cell/spufs/file.c ++++ b/arch/powerpc/platforms/cell/spufs/file.c +@@ -2445,7 +2445,7 @@ static int spufs_switch_log_open(struct + goto out; + } + +- ctx->switch_log = kzalloc(sizeof(struct switch_log) + ++ ctx->switch_log = kmalloc(sizeof(struct switch_log) + + SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry), + GFP_KERNEL); + +@@ -2454,6 +2454,7 @@ static int spufs_switch_log_open(struct + goto out; + } + ++ ctx->switch_log->head = ctx->switch_log->tail = 0; + init_waitqueue_head(&ctx->switch_log->wait); + rc = 0; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-09-Improve-search-of-node-for-contexts-w.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-09-Improve-search-of-node-for-contexts-w.patch new file mode 100644 index 000000000..1a403b475 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-09-Improve-search-of-node-for-contexts-w.patch @@ -0,0 +1,52 @@ +Subject: Improve search of node for contexts with SPU affinity +From: Andre Detsch +References: 447133 - LTC50070 + +This patch improves redability of the code responsible for trying to find +a node with enough SPUs not committed to other affinity gangs. + +An additional check is also added, to avoid taking into account gangs that +have no SPU affinity. + +Signed-off-by: Andre Detsch +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/sched.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/arch/powerpc/platforms/cell/spufs/sched.c ++++ b/arch/powerpc/platforms/cell/spufs/sched.c +@@ -312,6 +312,15 @@ static struct spu *aff_ref_location(stru + */ + node = cpu_to_node(raw_smp_processor_id()); + for (n = 0; n < MAX_NUMNODES; n++, node++) { ++ /* ++ * "available_spus" counts how many spus are not potentially ++ * going to be used by other affinity gangs whose reference ++ * context is already in place. Although this code seeks to ++ * avoid having affinity gangs with a summed amount of ++ * contexts bigger than the amount of spus in the node, ++ * this may happen sporadically. In this case, available_spus ++ * becomes negative, which is harmless. ++ */ + int available_spus; + + node = (node < MAX_NUMNODES) ? node : 0; +@@ -321,12 +330,10 @@ static struct spu *aff_ref_location(stru + available_spus = 0; + mutex_lock(&cbe_spu_info[node].list_mutex); + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { +- if (spu->ctx && spu->ctx->gang +- && spu->ctx->aff_offset == 0) +- available_spus -= +- (spu->ctx->gang->contexts - 1); +- else +- available_spus++; ++ if (spu->ctx && spu->ctx->gang && !spu->ctx->aff_offset ++ && spu->ctx->gang->aff_ref_spu) ++ available_spus -= spu->ctx->gang->contexts; ++ available_spus++; + } + if (available_spus < ctx->gang->contexts) { + mutex_unlock(&cbe_spu_info[node].list_mutex); diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-10-Explain-conditional-decrement-of-aff_.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-10-Explain-conditional-decrement-of-aff_.patch new file mode 100644 index 000000000..c8a589dc1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-spufs-10-Explain-conditional-decrement-of-aff_.patch @@ -0,0 +1,28 @@ +Subject: Explain conditional decrement of aff_sched_count +From: Andre Detsch +References: 447133 - LTC50070 + +This patch adds a comment to clarify why atomic_dec_if_positive is being used +to decrement gang's aff_sched_count on SPU context unbind. + +Signed-off-by: Andre Detsch +Signed-off-by: Jeremy Kerr +Signed-off-by: Olaf Hering +--- + arch/powerpc/platforms/cell/spufs/sched.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/arch/powerpc/platforms/cell/spufs/sched.c ++++ b/arch/powerpc/platforms/cell/spufs/sched.c +@@ -444,6 +444,11 @@ static void spu_unbind_context(struct sp + atomic_dec(&cbe_spu_info[spu->node].reserved_spus); + + if (ctx->gang) ++ /* ++ * If ctx->gang->aff_sched_count is positive, SPU affinity is ++ * being considered in this gang. Using atomic_dec_if_positive ++ * allow us to skip an explicit check for affinity in this gang ++ */ + atomic_dec_if_positive(&ctx->gang->aff_sched_count); + + spu_switch_notify(spu, NULL); diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-syscall-xer.so.1.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-syscall-xer.so.1.patch new file mode 100644 index 000000000..8b6f331de --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-syscall-xer.so.1.patch @@ -0,0 +1,48 @@ +Subject: Fix system calls on Cell entered with XER.SO=1 +From: Paul Mackerras +References: 456406 - LTC50395 + + +It turns out that on Cell, on a kernel with CONFIG_VIRT_CPU_ACCOUNTING=y, +if a program sets the SO (summary overflow) bit in the XER and +then does a system call, the SO bit in CR0 will be set on return +regardless of whether the system call detected an error. Since CR0.SO +is used as the error indication from the system call, this means that +all system calls appear to fail. + +The reason is that the workaround for the timebase bug on Cell uses a +compare instruction. With CONFIG_VIRT_CPU_ACCOUNTING = y, the +ACCOUNT_CPU_USER_ENTRY macro reads the timebase, so we end up doing a +compare instruction, which copies XER.SO to CR0.SO. Since we were +doing this in the system call entry patch after clearing CR0.SO but +before saving the CR, this meant that the saved CR image had CR0.SO +set if XER.SO was set on entry. + +This fixes it by moving the clearing of CR0.SO to after the +ACCOUNT_CPU_USER_ENTRY call in the system call entry path. + +Signed-off-by: Paul Mackerras +Acked-by: Arnd Bergmann +Acked-by: Benjamin Herrenschmidt +Signed-off-by: Olaf Hering + +--- + arch/powerpc/kernel/entry_64.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/kernel/entry_64.S ++++ b/arch/powerpc/kernel/entry_64.S +@@ -57,12 +57,12 @@ system_call_common: + beq- 1f + ld r1,PACAKSAVE(r13) + 1: std r10,0(r1) +- crclr so + std r11,_NIP(r1) + std r12,_MSR(r1) + std r0,GPR0(r1) + std r10,GPR1(r1) + ACCOUNT_CPU_USER_ENTRY(r10, r11) ++ crclr so + std r2,GPR2(r1) + std r3,GPR3(r1) + std r4,GPR4(r1) diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-valid-hugepage-size-hugetlb_get_unmapped_area.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-valid-hugepage-size-hugetlb_get_unmapped_area.patch new file mode 100644 index 000000000..8a7995595 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-valid-hugepage-size-hugetlb_get_unmapped_area.patch @@ -0,0 +1,61 @@ +Subject: Check for valid hugepage size in hugetlb_get_unmapped_area +From: Brian King +References: 456433 - LTC50170 + +It looks like most of the hugetlb code is doing the correct thing if +hugepages are not supported, but the mmap code is not. If we get into +the mmap code when hugepages are not supported, such as in an LPAR +which is running Active Memory Sharing, we can oops the kernel. This +patch fixes the oops being seen in this path. + +ops: Kernel access of bad area, sig: 11 [#1] +SMP NR_CPUS=1024 NUMA pSeries +Modules linked in: nfs(N) lockd(N) nfs_acl(N) sunrpc(N) ipv6(N) fuse(N) loop(N) +dm_mod(N) sg(N) ibmveth(N) sd_mod(N) crc_t10dif(N) ibmvscsic(N) +scsi_transport_srp(N) scsi_tgt(N) scsi_mod(N) +Supported: No +NIP: c000000000038d60 LR: c00000000003945c CTR: c0000000000393f0 +REGS: c000000077e7b830 TRAP: 0300 Tainted: G +(2.6.27.5-bz50170-2-ppc64) +MSR: 8000000000009032 CR: 44000448 XER: 20000001 +DAR: c000002000af90a8, DSISR: 0000000040000000 +TASK = c00000007c1b8600[4019] 'hugemmap01' THREAD: c000000077e78000 CPU: 6 +GPR00: 0000001fffffffe0 c000000077e7bab0 c0000000009a4e78 0000000000000000 +GPR04: 0000000000010000 0000000000000001 00000000ffffffff 0000000000000001 +GPR08: 0000000000000000 c000000000af90c8 0000000000000001 0000000000000000 +GPR12: 000000000000003f c000000000a73880 0000000000000000 0000000000000000 +GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000010000 +GPR20: 0000000000000000 0000000000000003 0000000000010000 0000000000000001 +GPR24: 0000000000000003 0000000000000000 0000000000000001 ffffffffffffffb5 +GPR28: c000000077ca2e80 0000000000000000 c00000000092af78 0000000000010000 +NIP [c000000000038d60] .slice_get_unmapped_area+0x6c/0x4e0 +LR [c00000000003945c] .hugetlb_get_unmapped_area+0x6c/0x80 +Call Trace: +[c000000077e7bbc0] [c00000000003945c] .hugetlb_get_unmapped_area+0x6c/0x80 +[c000000077e7bc30] [c000000000107e30] .get_unmapped_area+0x64/0xd8 +[c000000077e7bcb0] [c00000000010b140] .do_mmap_pgoff+0x140/0x420 +[c000000077e7bd80] [c00000000000bf5c] .sys_mmap+0xc4/0x140 +[c000000077e7be30] [c0000000000086b4] syscall_exit+0x0/0x40 +Instruction dump: +fac1ffb0 fae1ffb8 fb01ffc0 fb21ffc8 fb41ffd0 fb61ffd8 fb81ffe0 fbc1fff0 +fbe1fff8 f821fef1 f8c10158 f8e10160 <7d49002e> f9010168 e92d01b0 eb4902b0 + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering + +--- + arch/powerpc/mm/hugetlbpage.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/powerpc/mm/hugetlbpage.c ++++ b/arch/powerpc/mm/hugetlbpage.c +@@ -500,6 +500,9 @@ unsigned long hugetlb_get_unmapped_area( + { + struct hstate *hstate = hstate_file(file); + int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate)); ++ ++ if (!mmu_huge_psizes[mmu_psize]) ++ return -EINVAL; + return slice_get_unmapped_area(addr, len, flags, mmu_psize, 1, 0); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-vio-modalias.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-vio-modalias.patch new file mode 100644 index 000000000..a9649f587 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-vio-modalias.patch @@ -0,0 +1,35 @@ +From: Olaf Hering +Subject: [PATCH] poweroc: vio modalias + +Acked-by: Olaf Hering +--- + arch/powerpc/kernel/vio.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/arch/powerpc/kernel/vio.c ++++ b/arch/powerpc/kernel/vio.c +@@ -1315,9 +1315,24 @@ static ssize_t devspec_show(struct devic + return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); + } + ++static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct device_node *of_node = dev->archdata.of_node; ++ const char *compat; ++ int i = 0; ++ ++ if (of_node) { ++ compat = of_get_property(of_node, "compatible", &i); ++ i = sprintf (buf, "vio:T%sS%s\n", of_node->type, compat); ++ } ++ return i; ++} ++ + static struct device_attribute vio_dev_attrs[] = { + __ATTR_RO(name), + __ATTR_RO(devspec), ++ __ATTR_RO(modalias), + __ATTR_NULL + }; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc-xics-EOI-unmapped-irqs.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc-xics-EOI-unmapped-irqs.patch new file mode 100644 index 000000000..b014428d6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc-xics-EOI-unmapped-irqs.patch @@ -0,0 +1,111 @@ +From: Milton Miller +Subject: powerpc/xics: EOI unmapped irqs after disabling them +Date: Fri Oct 10 01:56:23 2008 +0000 +X-Git-Tag: v2.6.28-rc1~569^2~27 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8767e9badca7cdf0adc2564d7524092d47ababf3 +Patch-mainline: v2.6.28-rc1 +References: bnc#459065 + +When reciving an irq vector that does not have a linux mapping, the kernel +prints a message and calls RTAS to disable the irq source. Previously +the kernel did not EOI the interrupt, causing the source to think it is +still being processed by software. While this does add an additional +layer of protection against interrupt storms had RTAS failed to disable +the source, it also prevents the interrupt from working when a driver +later enables it. (We could alternatively send an EOI on startup, but +that strategy would likely fail on an emulated xics.) + +All interrupts should be disabled when the kernel starts, but this can +be observed if a driver does not shutdown an interrupt in its reboot +hook before starting a new kernel with kexec. + +Michael reports this can be reproduced trivially by banging the keyboard +while kexec'ing on a P5 LPAR: even though the hvc_console driver request's +the console irq later in boot, the console is non-functional because +we're receiving no console interrupts. + +Reported-By: Michael Ellerman +Signed-off-by: Milton Miller +Signed-off-by: Benjamin Herrenschmidt +Acked-by: Petr Tesarik + +--- + arch/powerpc/platforms/pseries/xics.c | 53 ++++++++++++++++++++++++++-------- + 1 file changed, 41 insertions(+), 12 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/arch/powerpc/platforms/pseries/xics.c 2009-04-16 10:33:47.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/arch/powerpc/platforms/pseries/xics.c 2009-04-16 10:52:29.000000000 +0200 +@@ -335,32 +335,61 @@ static void xics_eoi_lpar(unsigned int v + lpar_xirr_info_set((0xff << 24) | irq); + } + +-static inline unsigned int xics_remap_irq(unsigned int vec) ++static inline unsigned int xics_xirr_vector(unsigned int xirr) + { +- unsigned int irq; ++ /* ++ * The top byte is the old cppr, to be restored on EOI. ++ * The remaining 24 bits are the vector. ++ */ ++ return xirr & 0x00ffffff; ++} + +- vec &= 0x00ffffff; ++static void xics_mask_unknown_vec(unsigned int vec) ++{ ++ printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); ++ xics_mask_real_irq(vec); ++} ++ ++static unsigned int xics_get_irq_direct(void) ++{ ++ unsigned int xirr = direct_xirr_info_get(); ++ unsigned int vec = xics_xirr_vector(xirr); ++ unsigned int irq; + + if (vec == XICS_IRQ_SPURIOUS) + return NO_IRQ; ++ + irq = irq_radix_revmap(xics_host, vec); + if (likely(irq != NO_IRQ)) + return irq; + +- printk(KERN_ERR "Interrupt %u (real) is invalid," +- " disabling it.\n", vec); +- xics_mask_real_irq(vec); +- return NO_IRQ; +-} ++ /* We don't have a linux mapping, so have rtas mask it. */ ++ xics_mask_unknown_vec(vec); + +-static unsigned int xics_get_irq_direct(void) +-{ +- return xics_remap_irq(direct_xirr_info_get()); ++ /* We might learn about it later, so EOI it */ ++ direct_xirr_info_set(xirr); ++ return NO_IRQ; + } + + static unsigned int xics_get_irq_lpar(void) + { +- return xics_remap_irq(lpar_xirr_info_get()); ++ unsigned int xirr = lpar_xirr_info_get(); ++ unsigned int vec = xics_xirr_vector(xirr); ++ unsigned int irq; ++ ++ if (vec == XICS_IRQ_SPURIOUS) ++ return NO_IRQ; ++ ++ irq = irq_radix_revmap(xics_host, vec); ++ if (likely(irq != NO_IRQ)) ++ return irq; ++ ++ /* We don't have a linux mapping, so have RTAS mask it. */ ++ xics_mask_unknown_vec(vec); ++ ++ /* We might learn about it later, so EOI it */ ++ lpar_xirr_info_set(xirr); ++ return NO_IRQ; + } + + #ifdef CONFIG_SMP diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc32-fix-ptrace-compat-wrapper-for-fpu-register-access b/src/patches/suse-2.6.27.31/patches.arch/ppc32-fix-ptrace-compat-wrapper-for-fpu-register-access new file mode 100644 index 000000000..d21aa70e4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc32-fix-ptrace-compat-wrapper-for-fpu-register-access @@ -0,0 +1,63 @@ +From: Michael Neuling +Subject: powerpc: Fix ptrace compat wrapper for FPU register access +Patch-mainline: 2.6.30-rc4 +Git-commit: bc826666e4252f78d2b144af3b7d699ff5efce0a +References: bnc#496027 + +powerpc: Fix ptrace compat wrapper for FPU register access + +The ptrace compat wrapper mishandles access to the fpu registers. The +PTRACE_PEEKUSR and PTRACE_POKEUSR requests miscalculate the index into +the fpr array due to the broken FPINDEX macro. The +PPC_PTRACE_PEEKUSR_3264 request needs to use the same formula that the +native ptrace interface uses when operating on the register number (as +opposed to the 4-byte offset). The PPC_PTRACE_POKEUSR_3264 request +didn't take TS_FPRWIDTH into account. + +Signed-off-by: Andreas Schwab +Signed-off-by: Michael Neuling +Signed-off-by: Paul Mackerras +Acked-by: Jeff Mahoney +--- + arch/powerpc/kernel/ptrace32.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/arch/powerpc/kernel/ptrace32.c ++++ b/arch/powerpc/kernel/ptrace32.c +@@ -70,7 +70,8 @@ static long compat_ptrace_old(struct tas + /* Macros to workout the correct index for the FPR in the thread struct */ + #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1) + #define FPRHALF(i) (((i) - PT_FPR0) & 1) +-#define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) + FPRHALF(i) ++#define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i) ++#define FPRINDEX_3264(i) (TS_FPRWIDTH * ((i) - PT_FPR0)) + + static int compat_ptrace_getsiginfo(struct task_struct *child, compat_siginfo_t __user *data) + { +@@ -192,8 +193,9 @@ long compat_arch_ptrace(struct task_stru + CHECK_FULL_REGS(child->thread.regs); + if (numReg >= PT_FPR0) { + flush_fp_to_thread(child); +- tmp = ((unsigned long int *)child->thread.fpr) +- [FPRINDEX(numReg)]; ++ /* get 64 bit FPR */ ++ tmp = ((u64 *)child->thread.fpr) ++ [FPRINDEX_3264(numReg)]; + } else { /* register within PT_REGS struct */ + tmp = ptrace_get_reg(child, numReg); + } +@@ -286,8 +288,13 @@ long compat_arch_ptrace(struct task_stru + freg = (freg & 0xfffffffful) | (data << 32); + ret = ptrace_put_reg(child, numReg, freg); + } else { ++ u64 *tmp; + flush_fp_to_thread(child); +- ((unsigned int *)child->thread.regs)[index] = data; ++ /* get 64 bit FPR ... */ ++ tmp = &(((u64 *)child->thread.fpr) ++ [FPRINDEX_3264(numReg)]); ++ /* ... write the 32 bit part we want */ ++ ((u32 *)tmp)[index % 2] = data; + ret = 0; + } + break; diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc64-eeh-msix-irq b/src/patches/suse-2.6.27.31/patches.arch/ppc64-eeh-msix-irq new file mode 100644 index 000000000..0436ab890 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc64-eeh-msix-irq @@ -0,0 +1,145 @@ +From: Mike Mason +Date: Tue, 10 Feb 2009 11:12:21 +0000 (+0000) +Subject: powerpc/eeh: Only disable/enable LSI interrupts in EEH +Patch-mainline: 2.6.30-rc1 +Git-commit: 8535ef05a6904429ce72671c3035dbf05e6d5edf +References: bnc#509497 + +powerpc/eeh: Only disable/enable LSI interrupts in EEH + +The EEH code disables and enables interrupts during the +device recovery process. This is unnecessary for MSI +and MSI-X interrupts because they are effectively disabled +by the DMA Stopped state when an EEH error occurs. The +current code is also incorrect for MSI-X interrupts. It +doesn't take into account that MSI-X interrupts are tracked +in a different way than LSI/MSI interrupts. This patch +ensures only LSI interrupts are disabled/enabled. + +Signed-off-by: Mike Mason +Acked-by: Linas Vepstas +Signed-off-by: Benjamin Herrenschmidt +Acked-by: Jeff Mahoney +--- + + arch/powerpc/platforms/pseries/eeh_driver.c | 68 ++++++++++++++++++---------- + 1 file changed, 45 insertions(+), 23 deletions(-) + +--- a/arch/powerpc/platforms/pseries/eeh_driver.c ++++ b/arch/powerpc/platforms/pseries/eeh_driver.c +@@ -79,6 +79,40 @@ static int irq_in_use(unsigned int irq) + return rc; + } + ++/** ++ * eeh_disable_irq - disable interrupt for the recovering device ++ */ ++static void eeh_disable_irq(struct pci_dev *dev) ++{ ++ struct device_node *dn = pci_device_to_OF_node(dev); ++ ++ /* Don't disable MSI and MSI-X interrupts. They are ++ * effectively disabled by the DMA Stopped state ++ * when an EEH error occurs. ++ */ ++ if (dev->msi_enabled || dev->msix_enabled) ++ return; ++ ++ if (!irq_in_use(dev->irq)) ++ return; ++ ++ PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; ++ disable_irq_nosync(dev->irq); ++} ++ ++/** ++ * eeh_enable_irq - enable interrupt for the recovering device ++ */ ++static void eeh_enable_irq(struct pci_dev *dev) ++{ ++ struct device_node *dn = pci_device_to_OF_node(dev); ++ ++ if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { ++ PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; ++ enable_irq(dev->irq); ++ } ++} ++ + /* ------------------------------------------------------- */ + /** + * eeh_report_error - report pci error to each device driver +@@ -98,11 +132,8 @@ static void eeh_report_error(struct pci_ + if (!driver) + return; + +- if (irq_in_use (dev->irq)) { +- struct device_node *dn = pci_device_to_OF_node(dev); +- PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; +- disable_irq_nosync(dev->irq); +- } ++ eeh_disable_irq(dev); ++ + if (!driver->err_handler || + !driver->err_handler->error_detected) + return; +@@ -147,17 +178,14 @@ static void eeh_report_reset(struct pci_ + { + enum pci_ers_result rc, *res = userdata; + struct pci_driver *driver = dev->driver; +- struct device_node *dn = pci_device_to_OF_node(dev); + + if (!driver) + return; + + dev->error_state = pci_channel_io_normal; + +- if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { +- PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; +- enable_irq(dev->irq); +- } ++ eeh_enable_irq(dev); ++ + if (!driver->err_handler || + !driver->err_handler->slot_reset) + return; +@@ -176,17 +204,14 @@ static void eeh_report_reset(struct pci_ + static void eeh_report_resume(struct pci_dev *dev, void *userdata) + { + struct pci_driver *driver = dev->driver; +- struct device_node *dn = pci_device_to_OF_node(dev); + + dev->error_state = pci_channel_io_normal; + + if (!driver) + return; + +- if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { +- PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; +- enable_irq(dev->irq); +- } ++ eeh_enable_irq(dev); ++ + if (!driver->err_handler || + !driver->err_handler->resume) + return; +@@ -210,15 +235,12 @@ static void eeh_report_failure(struct pc + if (!driver) + return; + +- if (irq_in_use (dev->irq)) { +- struct device_node *dn = pci_device_to_OF_node(dev); +- PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; +- disable_irq_nosync(dev->irq); +- } +- if (!driver->err_handler) +- return; +- if (!driver->err_handler->error_detected) ++ eeh_disable_irq(dev); ++ ++ if (!driver->err_handler || ++ !driver->err_handler->error_detected) + return; ++ + driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc64-reduce-hashtable-size-for-64k-pages.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc64-reduce-hashtable-size-for-64k-pages.patch new file mode 100644 index 000000000..bbb5b8891 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc64-reduce-hashtable-size-for-64k-pages.patch @@ -0,0 +1,46 @@ +From: Anton Blanchard +Subject: powerpc/mm: Reduce hashtable size when using 64kB pages +Date: Fri Feb 13 11:57:30 2009 +0000 +References: bnc#501160 +Patch-upstream: yes +Git: 13870b657578bcce167978ee93dc02bf54e3beb0 + + powerpc/mm: Reduce hashtable size when using 64kB pages + + At the moment we size the hashtable based on 4kB pages / 2, even on a + 64kB kernel. This results in a hashtable that is much larger than it + needs to be. + + Grab the real page size and size the hashtable based on that + + Note: This only has effect on non hypervisor machines. + + Signed-off-by: Anton Blanchard + Signed-off-by: Benjamin Herrenschmidt +Acked-by: Nick Piggin + +--- + arch/powerpc/mm/hash_utils_64.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/mm/hash_utils_64.c ++++ b/arch/powerpc/mm/hash_utils_64.c +@@ -514,7 +514,7 @@ static int __init htab_dt_scan_pftsize(u + + static unsigned long __init htab_get_table_size(void) + { +- unsigned long mem_size, rnd_mem_size, pteg_count; ++ unsigned long mem_size, rnd_mem_size, pteg_count, psize; + + /* If hash size isn't already provided by the platform, we try to + * retrieve it from the device-tree. If it's not there neither, we +@@ -532,7 +532,8 @@ static unsigned long __init htab_get_tab + rnd_mem_size <<= 1; + + /* # pages / 2 */ +- pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); ++ psize = mmu_psize_defs[mmu_virtual_psize].shift; ++ pteg_count = max(rnd_mem_size >> (psize + 1), 1UL << 11); + + return pteg_count << 7; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/ppc64-xmon-dmesg-printing.patch b/src/patches/suse-2.6.27.31/patches.arch/ppc64-xmon-dmesg-printing.patch new file mode 100644 index 000000000..5217414e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/ppc64-xmon-dmesg-printing.patch @@ -0,0 +1,130 @@ +Subject: [PATCH] add syslog printing to xmon debugger. +From: Linas Vepstas + + +This patch 'dmesg'/printk log buffer printing to xmon. I find this +useful because crashes are almost always preceeded by interesting +printk's. This patch is simple & straightforward, except for one +possibly controversial aspect: it embeds a small snippet in +kernel/printk.c to return the location of the syslog. This is +needed because kallsyms and even CONFIG_KALLSYMS_ALL is not enough +to reveal the location of log_buf. This code is about 90% +cut-n-paste of earlier code from Keith Owens. + +Signed-off-by: Olaf Hering + + arch/powerpc/xmon/xmon.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ + kernel/printk.c | 15 ++++++++++++ + 2 files changed, 72 insertions(+) + +--- a/arch/powerpc/xmon/xmon.c ++++ b/arch/powerpc/xmon/xmon.c +@@ -136,6 +136,7 @@ static struct bpt *in_breakpoint_table(u + static int do_step(struct pt_regs *); + static void bpt_cmds(void); + static void cacheflush(void); ++static void xmon_show_dmesg(void); + static int cpu_cmd(void); + static void csum(void); + static void bootcmds(void); +@@ -194,6 +195,7 @@ Commands:\n\ + #endif + "\ + C checksum\n\ ++ D show dmesg (printk) buffer\n\ + d dump bytes\n\ + di dump instructions\n\ + df dump float values\n\ +@@ -808,6 +810,9 @@ cmds(struct pt_regs *excp) + case 'd': + dump(); + break; ++ case 'D': ++ xmon_show_dmesg(); ++ break; + case 'l': + symbol_lookup(); + break; +@@ -2522,6 +2527,58 @@ static void xmon_print_symbol(unsigned l + printf("%s", after); + } + ++extern void debugger_syslog_data(char *syslog_data[4]); ++#define SYSLOG_WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; \ ++ else if (p >= syslog_data[1]) p = syslog_data[0]; ++ ++static void xmon_show_dmesg(void) ++{ ++ char *syslog_data[4], *start, *end, c; ++ int logsize; ++ ++ /* syslog_data[0,1] physical start, end+1. ++ * syslog_data[2,3] logical start, end+1. ++ */ ++ debugger_syslog_data(syslog_data); ++ if (syslog_data[2] == syslog_data[3]) ++ return; ++ logsize = syslog_data[1] - syslog_data[0]; ++ start = syslog_data[0] + (syslog_data[2] - syslog_data[0]) % logsize; ++ end = syslog_data[0] + (syslog_data[3] - syslog_data[0]) % logsize; ++ ++ /* Do a line at a time (max 200 chars) to reduce overhead */ ++ c = '\0'; ++ while(1) { ++ char *p; ++ int chars = 0; ++ if (!*start) { ++ while (!*start) { ++ ++start; ++ SYSLOG_WRAP(start); ++ if (start == end) ++ break; ++ } ++ if (start == end) ++ break; ++ } ++ p = start; ++ while (*start && chars < 200) { ++ c = *start; ++ ++chars; ++ ++start; ++ SYSLOG_WRAP(start); ++ if (start == end || c == '\n') ++ break; ++ } ++ if (chars) ++ printf("%.*s", chars, p); ++ if (start == end) ++ break; ++ } ++ if (c != '\n') ++ printf("\n"); ++} ++ + #ifdef CONFIG_PPC64 + static void dump_slb(void) + { +--- a/kernel/printk.c ++++ b/kernel/printk.c +@@ -426,6 +426,21 @@ asmlinkage long sys_syslog(int type, cha + return do_syslog(type, buf, len); + } + ++#ifdef CONFIG_DEBUG_KERNEL ++/* Its very handy to be able to view the syslog buffer during debug. ++ * But do_syslog() uses locks so it cannot be used during debugging. ++ * Instead, provide the start and end of the physical and logical logs. ++ * This is equivalent to do_syslog(3). ++ */ ++void debugger_syslog_data(char *syslog_data[4]) ++{ ++ syslog_data[0] = log_buf; ++ syslog_data[1] = log_buf + log_buf_len; ++ syslog_data[2] = log_buf + log_end - (logged_chars < log_buf_len ? logged_chars : log_buf_len); ++ syslog_data[3] = log_buf + log_end; ++} ++#endif /* CONFIG_DEBUG_KERNEL */ ++ + /* + * Call the console drivers on a range of log_buf + */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/pseries-set-error_state-correctly-in-eeh_report_reset b/src/patches/suse-2.6.27.31/patches.arch/pseries-set-error_state-correctly-in-eeh_report_reset new file mode 100644 index 000000000..e4e58652e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/pseries-set-error_state-correctly-in-eeh_report_reset @@ -0,0 +1,98 @@ +From: Mike Mason +Date: Fri, 10 Apr 2009 08:57:03 +0000 (+0000) +Subject: powerpc/pseries: Set error_state to pci_channel_io_normal in eeh_report_reset() +Patch-mainline: 2.6.30 +Git-commit: c58dc575f3c8bdc69fb868ec51e1c80ee7cae5e7 +References: bnc#509407 + +powerpc/pseries: Set error_state to pci_channel_io_normal in eeh_report_reset() + +While adding native EEH support to Emulex and Qlogic drivers, it was +discovered that dev->error_state was set to pci_io_channel_normal too +late in the recovery process. These drivers rely on error_state to +determine if they can access the device in their slot_reset callback, +thus error_state needs to be set to pci_io_channel_normal in +eeh_report_reset(). Below is a detailed explanation (courtesy of Richard +Lary) as to why this is necessary. + +Background: +PCI MMIO or DMA accesses to a frozen slot generate additional EEH +errors. If the number of additional EEH errors exceeds EEH_MAX_FAILS the +adapter will be shutdown. To avoid triggering excessive EEH errors and +an undesirable adapter shutdown, some drivers use the +pci_channel_offline(dev) wrapper function to return a Boolean value +based on the value of pci_dev->error_state to determine if PCI MMIO or +DMA accesses are safe. If the wrapper returns TRUE, drivers must not +make PCI MMIO or DMA access to their hardware. + +The pci_dev structure member error_state reflects one of three values, +1) pci_channel_io_normal, 2) pci_channel_io_frozen, 3) +pci_channel_io_perm_failure. Function pci_channel_offline(dev) returns +TRUE if error_state is pci_channel_io_frozen or pci_channel_io_perm_failure. + +The EEH driver sets pci_dev->error_state to pci_channel_io_frozen at the +point where the PCI slot is frozen. Currently, the EEH driver restores +dev->error_state to pci_channel_io_normal in eeh_report_resume() before +calling the driver's resume callback. However, when the EEH driver calls +the driver's slot_reset callback() from eeh_report_reset(), it +incorrectly indicates the error state is still pci_channel_io_frozen. + +Waiting until eeh_report_resume() to restore dev->error_state to +pci_channel_io_normal is too late for Emulex and QLogic FC drivers and +any other drivers which are designed to use common code paths in these +two cases: i) those called after the driver's slot_reset callback() and +ii) those called after the PCI slot is frozen but before the driver's +slot_reset callback is called. Case i) all driver paths executed to +reinitialize the hardware after a reset and case ii) all code paths +executed by driver kernel threads that run asynchronous to the main +driver thread, such as interrupt handlers and worker threads to process +driver work queues. + +Emulex and QLogic FC drivers are designed with common code paths which +require that pci_channel_offline(dev) reflect the true state of the +hardware. The state transitions that the hardware takes from Normal +Operations to Slot Frozen to Reset to Normal Operations are documented +in the Power Architecture™ Platform Requirements+ (PAPR+) in Table 75. +PE State Control. + +PAPR defines the following 3 states: + +0 -- Not reset, Not EEH stopped, MMIO load/store allowed, DMA allowed + (Normal Operations) +1 -- Reset, Not EEH stopped, MMIO load/store disabled, DMA disabled +2 -- Not reset, EEH stopped, MMIO load/store disabled, DMA disabled + (Slot Frozen) + +An EEH error places the slot in state 2 (Frozen) and the adapter driver +is notified that an EEH error was detected. If the adapter driver +returns PCI_ERS_RESULT_NEED_RESET, the EEH driver calls +eeh_reset_device() to place the slot into state 1 (Reset) and +eeh_reset_device completes by placing the slot into State 0 (Normal +Operations). Upon return from eeh_reset_device(), the EEH driver calls +eeh_report_reset, which then calls the adapter's slot_reset callback. At +the time the adapter's slot_reset callback is called, the true state of +the hardware is Normal Operations and should be accurately reflected by +setting dev->error_state to pci_channel_io_normal. + +The current implementation of EEH driver does not do so and requires +this change to correct this deficiency. + +Signed-off-by: Mike Mason +Acked-by: Linas Vepstas +Signed-off-by: Paul Mackerras +Acked-by: Jeff Mahoney +--- + arch/powerpc/platforms/pseries/eeh_driver.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/powerpc/platforms/pseries/eeh_driver.c ++++ b/arch/powerpc/platforms/pseries/eeh_driver.c +@@ -152,6 +152,8 @@ static void eeh_report_reset(struct pci_ + if (!driver) + return; + ++ dev->error_state = pci_channel_io_normal; ++ + if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { + PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; + enable_irq(dev->irq); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-02-dcss-64-v2.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-02-dcss-64-v2.patch new file mode 100644 index 000000000..e4d06651c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-02-dcss-64-v2.patch @@ -0,0 +1,1211 @@ +From: Gerald Schaefer +Subject: dcssblk (new function): Add support for >2G DCSS and stacked + contiguous DCSS support. +References: bnc#417246 + +Description: The DCSS block device driver is modified to add >2G DCSS support + and allow a DCSS block device to map to a set of contiguous DCSSs. + The extmem code is also modified to use new Diagnose x'64' subcodes + for >2G DCSSs. + +Acked-by: John Jolly + +--- + + arch/s390/mm/extmem.c | 251 +++++++++++++++++--- + drivers/s390/block/dcssblk.c | 516 ++++++++++++++++++++++++++++++++----------- + 2 files changed, 597 insertions(+), 170 deletions(-) + +Index: linux-sles11/arch/s390/mm/extmem.c +=================================================================== +--- linux-sles11.orig/arch/s390/mm/extmem.c ++++ linux-sles11/arch/s390/mm/extmem.c +@@ -43,20 +43,40 @@ + #define DCSS_FINDSEG 0x0c + #define DCSS_LOADNOLY 0x10 + #define DCSS_SEGEXT 0x18 ++#define DCSS_LOADSHRX 0x20 ++#define DCSS_LOADNSRX 0x24 ++#define DCSS_FINDSEGX 0x2c ++#define DCSS_SEGEXTX 0x38 + #define DCSS_FINDSEGA 0x0c + + struct qrange { +- unsigned int start; // 3byte start address, 1 byte type +- unsigned int end; // 3byte end address, 1 byte reserved ++ unsigned long start; /* last byte type */ ++ unsigned long end; /* last byte reserved */ + }; + + struct qout64 { ++ unsigned long segstart; ++ unsigned long segend; ++ int segcnt; ++ int segrcnt; ++ struct qrange range[6]; ++}; ++ ++#ifdef CONFIG_64BIT ++struct qrange_old { ++ unsigned int start; /* last byte type */ ++ unsigned int end; /* last byte reserved */ ++}; ++ ++/* output area format for the Diag x'64' old subcode x'18' */ ++struct qout64_old { + int segstart; + int segend; + int segcnt; + int segrcnt; +- struct qrange range[6]; ++ struct qrange_old range[6]; + }; ++#endif + + struct qin64 { + char qopcode; +@@ -86,6 +106,55 @@ static DEFINE_MUTEX(dcss_lock); + static LIST_HEAD(dcss_list); + static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", + "EW/EN-MIXED" }; ++static int loadshr_scode, loadnsr_scode, findseg_scode; ++static int segext_scode, purgeseg_scode; ++static int scode_set; ++ ++/* set correct Diag x'64' subcodes. */ ++static int ++dcss_set_subcodes(void) ++{ ++#ifdef CONFIG_64BIT ++ char *name = kmalloc(8 * sizeof(char), GFP_DMA); ++ unsigned long rx, ry; ++ int rc; ++ ++ if (name == NULL) ++ return -ENOMEM; ++ ++ rx = (unsigned long) name; ++ ry = DCSS_FINDSEGX; ++ ++ strcpy(name, "dummy"); ++ asm volatile( ++ " diag %0,%1,0x64\n" ++ "0: ipm %2\n" ++ " srl %2,28\n" ++ " j 2f\n" ++ "1: la %2,3\n" ++ "2:\n" ++ EX_TABLE(0b, 1b) ++ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); ++ ++ kfree(name); ++ /* Diag x'64' new subcodes are supported, set to new subcodes */ ++ if (rc != 3) { ++ loadshr_scode = DCSS_LOADSHRX; ++ loadnsr_scode = DCSS_LOADNSRX; ++ purgeseg_scode = DCSS_PURGESEG; ++ findseg_scode = DCSS_FINDSEGX; ++ segext_scode = DCSS_SEGEXTX; ++ return 0; ++ } ++#endif ++ /* Diag x'64' new subcodes are not supported, set to old subcodes */ ++ loadshr_scode = DCSS_LOADNOLY; ++ loadnsr_scode = DCSS_LOADNSR; ++ purgeseg_scode = DCSS_PURGESEG; ++ findseg_scode = DCSS_FINDSEG; ++ segext_scode = DCSS_SEGEXT; ++ return 0; ++} + + /* + * Create the 8 bytes, ebcdic VM segment name from +@@ -135,25 +204,45 @@ segment_by_name (char *name) + * Perform a function on a dcss segment. + */ + static inline int +-dcss_diag (__u8 func, void *parameter, ++dcss_diag(int *func, void *parameter, + unsigned long *ret1, unsigned long *ret2) + { + unsigned long rx, ry; + int rc; + ++ if (scode_set == 0) { ++ rc = dcss_set_subcodes(); ++ if (rc < 0) ++ return rc; ++ scode_set = 1; ++ } + rx = (unsigned long) parameter; +- ry = (unsigned long) func; +- asm volatile( ++ ry = (unsigned long) *func; ++ + #ifdef CONFIG_64BIT +- " sam31\n" +- " diag %0,%1,0x64\n" +- " sam64\n" ++ /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */ ++ if (*func > DCSS_SEGEXT) ++ asm volatile( ++ " diag %0,%1,0x64\n" ++ " ipm %2\n" ++ " srl %2,28\n" ++ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); ++ /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */ ++ else ++ asm volatile( ++ " sam31\n" ++ " diag %0,%1,0x64\n" ++ " sam64\n" ++ " ipm %2\n" ++ " srl %2,28\n" ++ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); + #else ++ asm volatile( + " diag %0,%1,0x64\n" +-#endif + " ipm %2\n" + " srl %2,28\n" + : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); ++#endif + *ret1 = rx; + *ret2 = ry; + return rc; +@@ -190,14 +279,45 @@ query_segment_type (struct dcss_segment + qin->qoutlen = sizeof(struct qout64); + memcpy (qin->qname, seg->dcss_name, 8); + +- diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc); ++ diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc); + ++ if (diag_cc < 0) { ++ rc = diag_cc; ++ goto out_free; ++ } + if (diag_cc > 1) { + PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc); + rc = dcss_diag_translate_rc (vmrc); + goto out_free; + } + ++#ifdef CONFIG_64BIT ++ /* Only old format of output area of Diagnose x'64' is supported, ++ copy data for the new format. */ ++ if (segext_scode == DCSS_SEGEXT) { ++ struct qout64_old *qout_old; ++ qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA); ++ if (qout_old == NULL) { ++ rc = -ENOMEM; ++ goto out_free; ++ } ++ memcpy(qout_old, qout, sizeof(struct qout64_old)); ++ qout->segstart = (unsigned long) qout_old->segstart; ++ qout->segend = (unsigned long) qout_old->segend; ++ qout->segcnt = qout_old->segcnt; ++ qout->segrcnt = qout_old->segrcnt; ++ ++ if (qout->segcnt > 6) ++ qout->segrcnt = 6; ++ for (i = 0; i < qout->segrcnt; i++) { ++ qout->range[i].start = ++ (unsigned long) qout_old->range[i].start; ++ qout->range[i].end = ++ (unsigned long) qout_old->range[i].end; ++ } ++ kfree(qout_old); ++ } ++#endif + if (qout->segcnt > 6) { + rc = -ENOTSUPP; + goto out_free; +@@ -269,6 +389,30 @@ segment_type (char* name) + } + + /* ++ * check if segment collides with other segments that are currently loaded ++ * returns 1 if this is the case, 0 if no collision was found ++ */ ++static int ++segment_overlaps_others (struct dcss_segment *seg) ++{ ++ struct list_head *l; ++ struct dcss_segment *tmp; ++ ++ BUG_ON(!mutex_is_locked(&dcss_lock)); ++ list_for_each(l, &dcss_list) { ++ tmp = list_entry(l, struct dcss_segment, list); ++ if ((tmp->start_addr >> 20) > (seg->end >> 20)) ++ continue; ++ if ((tmp->end >> 20) < (seg->start_addr >> 20)) ++ continue; ++ if (seg == tmp) ++ continue; ++ return 1; ++ } ++ return 0; ++} ++ ++/* + * real segment loading function, called from segment_load + */ + static int +@@ -276,7 +420,8 @@ __segment_load (char *name, int do_nonsh + { + struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment), + GFP_DMA); +- int dcss_command, rc, diag_cc; ++ int rc, diag_cc; ++ unsigned long start_addr, end_addr, dummy; + + if (seg == NULL) { + rc = -ENOMEM; +@@ -287,6 +432,13 @@ __segment_load (char *name, int do_nonsh + if (rc < 0) + goto out_free; + ++ if (loadshr_scode == DCSS_LOADSHRX) { ++ if (segment_overlaps_others(seg)) { ++ rc = -EBUSY; ++ goto out_free; ++ } ++ } ++ + rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1); + + if (rc) +@@ -316,20 +468,28 @@ __segment_load (char *name, int do_nonsh + } + + if (do_nonshared) +- dcss_command = DCSS_LOADNSR; ++ diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, ++ &start_addr, &end_addr); + else +- dcss_command = DCSS_LOADNOLY; +- +- diag_cc = dcss_diag(dcss_command, seg->dcss_name, +- &seg->start_addr, &seg->end); ++ diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, ++ &start_addr, &end_addr); ++ if (diag_cc < 0) { ++ dcss_diag(&purgeseg_scode, seg->dcss_name, ++ &dummy, &dummy); ++ rc = diag_cc; ++ goto out_resource; ++ } + if (diag_cc > 1) { + PRINT_WARN ("segment_load: could not load segment %s - " +- "diag returned error (%ld)\n",name,seg->end); +- rc = dcss_diag_translate_rc (seg->end); +- dcss_diag(DCSS_PURGESEG, seg->dcss_name, +- &seg->start_addr, &seg->end); ++ "diag returned error (%ld)\n", ++ name, end_addr); ++ rc = dcss_diag_translate_rc(end_addr); ++ dcss_diag(&purgeseg_scode, seg->dcss_name, ++ &dummy, &dummy); + goto out_resource; + } ++ seg->start_addr = start_addr; ++ seg->end = end_addr; + seg->do_nonshared = do_nonshared; + atomic_set(&seg->ref_count, 1); + list_add(&seg->list, &dcss_list); +@@ -423,8 +583,8 @@ int + segment_modify_shared (char *name, int do_nonshared) + { + struct dcss_segment *seg; +- unsigned long dummy; +- int dcss_command, rc, diag_cc; ++ unsigned long start_addr, end_addr, dummy; ++ int rc, diag_cc; + + mutex_lock(&dcss_lock); + seg = segment_by_name (name); +@@ -445,38 +605,51 @@ segment_modify_shared (char *name, int d + goto out_unlock; + } + release_resource(seg->res); +- if (do_nonshared) { +- dcss_command = DCSS_LOADNSR; ++ if (do_nonshared) + seg->res->flags &= ~IORESOURCE_READONLY; +- } else { +- dcss_command = DCSS_LOADNOLY; ++ else + if (seg->vm_segtype == SEG_TYPE_SR || + seg->vm_segtype == SEG_TYPE_ER) + seg->res->flags |= IORESOURCE_READONLY; +- } ++ + if (request_resource(&iomem_resource, seg->res)) { + PRINT_WARN("segment_modify_shared: could not reload segment %s" + " - overlapping resources\n", name); + rc = -EBUSY; + kfree(seg->res); +- goto out_del; ++ goto out_del_mem; ++ } ++ ++ dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); ++ if (do_nonshared) ++ diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, ++ &start_addr, &end_addr); ++ else ++ diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, ++ &start_addr, &end_addr); ++ if (diag_cc < 0) { ++ rc = diag_cc; ++ goto out_del_res; + } +- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); +- diag_cc = dcss_diag(dcss_command, seg->dcss_name, +- &seg->start_addr, &seg->end); + if (diag_cc > 1) { + PRINT_WARN ("segment_modify_shared: could not reload segment %s" +- " - diag returned error (%ld)\n",name,seg->end); +- rc = dcss_diag_translate_rc (seg->end); +- goto out_del; ++ " - diag returned error (%ld)\n", ++ name, end_addr); ++ rc = dcss_diag_translate_rc(end_addr); ++ goto out_del_res; + } ++ seg->start_addr = start_addr; ++ seg->end = end_addr; + seg->do_nonshared = do_nonshared; + rc = 0; + goto out_unlock; +- out_del: ++ out_del_res: ++ release_resource(seg->res); ++ kfree(seg->res); ++ out_del_mem: + vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); + list_del(&seg->list); +- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); ++ dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); + kfree(seg); + out_unlock: + mutex_unlock(&dcss_lock); +@@ -510,7 +683,7 @@ segment_unload(char *name) + kfree(seg->res); + vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); + list_del(&seg->list); +- dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); ++ dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); + kfree(seg); + out_unlock: + mutex_unlock(&dcss_lock); +@@ -545,7 +718,7 @@ segment_save(char *name) + endpfn = (seg->end) >> PAGE_SHIFT; + sprintf(cmd1, "DEFSEG %s", name); + for (i=0; isegcnt; i++) { +- sprintf(cmd1+strlen(cmd1), " %X-%X %s", ++ sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", + seg->range[i].start >> PAGE_SHIFT, + seg->range[i].end >> PAGE_SHIFT, + segtype_string[seg->range[i].start & 0xff]); +Index: linux-sles11/drivers/s390/block/dcssblk.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dcssblk.c ++++ linux-sles11/drivers/s390/block/dcssblk.c +@@ -31,7 +31,6 @@ + #define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) + #define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) + +- + static int dcssblk_open(struct inode *inode, struct file *filp); + static int dcssblk_release(struct inode *inode, struct file *filp); + static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +@@ -48,6 +47,30 @@ static struct block_device_operations dc + .direct_access = dcssblk_direct_access, + }; + ++struct dcssblk_dev_info { ++ struct list_head lh; ++ struct device dev; ++ char segment_name[BUS_ID_SIZE]; ++ atomic_t use_count; ++ struct gendisk *gd; ++ unsigned long start; ++ unsigned long end; ++ int segment_type; ++ unsigned char save_pending; ++ unsigned char is_shared; ++ struct request_queue *dcssblk_queue; ++ int num_of_segments; ++ struct list_head seg_list; ++}; ++ ++struct segment_info { ++ struct list_head lh; ++ char segment_name[BUS_ID_SIZE]; ++ unsigned long start; ++ unsigned long end; ++ int segment_type; ++}; ++ + static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf, + size_t count); + static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, +@@ -58,30 +81,20 @@ static ssize_t dcssblk_save_show(struct + static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, + size_t count); + static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); ++static ssize_t dcssblk_seglist_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf); + + static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); + static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); +-static DEVICE_ATTR(save, S_IWUSR | S_IRUGO, dcssblk_save_show, ++static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show, + dcssblk_save_store); +-static DEVICE_ATTR(shared, S_IWUSR | S_IRUGO, dcssblk_shared_show, ++static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show, + dcssblk_shared_store); ++static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL); + + static struct device *dcssblk_root_dev; + +-struct dcssblk_dev_info { +- struct list_head lh; +- struct device dev; +- char segment_name[BUS_ID_SIZE]; +- atomic_t use_count; +- struct gendisk *gd; +- unsigned long start; +- unsigned long end; +- int segment_type; +- unsigned char save_pending; +- unsigned char is_shared; +- struct request_queue *dcssblk_queue; +-}; +- + static LIST_HEAD(dcssblk_devices); + static struct rw_semaphore dcssblk_devices_sem; + +@@ -91,8 +104,15 @@ static struct rw_semaphore dcssblk_devic + static void + dcssblk_release_segment(struct device *dev) + { +- PRINT_DEBUG("segment release fn called for %s\n", dev->bus_id); +- kfree(container_of(dev, struct dcssblk_dev_info, dev)); ++ struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry, *temp; ++ ++ dev_info = container_of(dev, struct dcssblk_dev_info, dev); ++ list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) { ++ list_del(&entry->lh); ++ kfree(entry); ++ } ++ kfree(dev_info); + module_put(THIS_MODULE); + } + +@@ -142,6 +162,169 @@ dcssblk_get_device_by_name(char *name) + return NULL; + } + ++/* ++ * get the struct segment_info from seg_list ++ * for the given name. ++ * down_read(&dcssblk_devices_sem) must be held. ++ */ ++static struct segment_info * ++dcssblk_get_segment_by_name(char *name) ++{ ++ struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry; ++ ++ list_for_each_entry(dev_info, &dcssblk_devices, lh) { ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ if (!strcmp(name, entry->segment_name)) ++ return entry; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * get the highest address of the multi-segment block. ++ */ ++static unsigned long ++dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info) ++{ ++ unsigned long highest_addr; ++ struct segment_info *entry; ++ ++ highest_addr = 0; ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ if (highest_addr < entry->end) ++ highest_addr = entry->end; ++ } ++ return highest_addr; ++} ++ ++/* ++ * get the lowest address of the multi-segment block. ++ */ ++static unsigned long ++dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info) ++{ ++ int set_first; ++ unsigned long lowest_addr; ++ struct segment_info *entry; ++ ++ set_first = 0; ++ lowest_addr = 0; ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ if (set_first == 0) { ++ lowest_addr = entry->start; ++ set_first = 1; ++ } else { ++ if (lowest_addr > entry->start) ++ lowest_addr = entry->start; ++ } ++ } ++ return lowest_addr; ++} ++ ++/* ++ * Check continuity of segments. ++ */ ++static int ++dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) ++{ ++ int i, j, rc; ++ struct segment_info *sort_list, *entry, temp; ++ ++ if (dev_info->num_of_segments <= 1) ++ return 0; ++ ++ sort_list = kzalloc( ++ sizeof(struct segment_info) * dev_info->num_of_segments, ++ GFP_KERNEL); ++ if (sort_list == NULL) ++ return -ENOMEM; ++ i = 0; ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ memcpy(&sort_list[i], entry, sizeof(struct segment_info)); ++ i++; ++ } ++ ++ /* sort segments */ ++ for (i = 0; i < dev_info->num_of_segments; i++) ++ for (j = 0; j < dev_info->num_of_segments; j++) ++ if (sort_list[j].start > sort_list[i].start) { ++ memcpy(&temp, &sort_list[i], ++ sizeof(struct segment_info)); ++ memcpy(&sort_list[i], &sort_list[j], ++ sizeof(struct segment_info)); ++ memcpy(&sort_list[j], &temp, ++ sizeof(struct segment_info)); ++ } ++ ++ /* check continuity */ ++ for (i = 0; i < dev_info->num_of_segments - 1; i++) { ++ if ((sort_list[i].end + 1) != sort_list[i+1].start) { ++ PRINT_ERR("Segment %s is not contiguous with " ++ "segment %s\n", ++ sort_list[i].segment_name, ++ sort_list[i+1].segment_name); ++ rc = -EINVAL; ++ goto out; ++ } ++ /* EN and EW are allowed in a block device */ ++ if (sort_list[i].segment_type != sort_list[i+1].segment_type) { ++ if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) || ++ (sort_list[i].segment_type == SEG_TYPE_ER) || ++ !(sort_list[i+1].segment_type & ++ SEGMENT_EXCLUSIVE) || ++ (sort_list[i+1].segment_type == SEG_TYPE_ER)) { ++ PRINT_ERR("Segment %s has different type from " ++ "segment %s\n", ++ sort_list[i].segment_name, ++ sort_list[i+1].segment_name); ++ rc = -EINVAL; ++ goto out; ++ } ++ } ++ } ++ rc = 0; ++out: ++ kfree(sort_list); ++ return rc; ++} ++ ++/* ++ * Load a segment ++ */ ++static int ++dcssblk_load_segment(char *name, struct segment_info **seg_info) ++{ ++ int rc; ++ ++ /* already loaded? */ ++ down_read(&dcssblk_devices_sem); ++ *seg_info = dcssblk_get_segment_by_name(name); ++ up_read(&dcssblk_devices_sem); ++ if (*seg_info != NULL) ++ return -EEXIST; ++ ++ /* get a struct segment_info */ ++ *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL); ++ if (*seg_info == NULL) ++ return -ENOMEM; ++ ++ strcpy((*seg_info)->segment_name, name); ++ ++ /* load the segment */ ++ rc = segment_load(name, SEGMENT_SHARED, ++ &(*seg_info)->start, &(*seg_info)->end); ++ if (rc < 0) { ++ segment_warning(rc, (*seg_info)->segment_name); ++ kfree(*seg_info); ++ } else { ++ INIT_LIST_HEAD(&(*seg_info)->lh); ++ (*seg_info)->segment_type = rc; ++ } ++ return rc; ++} ++ + static void dcssblk_unregister_callback(struct device *dev) + { + device_unregister(dev); +@@ -165,6 +348,7 @@ static ssize_t + dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) + { + struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry, *temp; + int rc; + + if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) +@@ -172,46 +356,46 @@ dcssblk_shared_store(struct device *dev, + down_write(&dcssblk_devices_sem); + dev_info = container_of(dev, struct dcssblk_dev_info, dev); + if (atomic_read(&dev_info->use_count)) { +- PRINT_ERR("share: segment %s is busy!\n", +- dev_info->segment_name); + rc = -EBUSY; + goto out; + } + if (inbuf[0] == '1') { +- // reload segment in shared mode +- rc = segment_modify_shared(dev_info->segment_name, +- SEGMENT_SHARED); +- if (rc < 0) { +- BUG_ON(rc == -EINVAL); +- if (rc != -EAGAIN) +- goto removeseg; +- } else { +- dev_info->is_shared = 1; +- switch (dev_info->segment_type) { +- case SEG_TYPE_SR: +- case SEG_TYPE_ER: +- case SEG_TYPE_SC: +- set_disk_ro(dev_info->gd,1); ++ /* reload segments in shared mode */ ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ rc = segment_modify_shared(entry->segment_name, ++ SEGMENT_SHARED); ++ if (rc < 0) { ++ BUG_ON(rc == -EINVAL); ++ if (rc != -EAGAIN) ++ goto removeseg; + } + } ++ dev_info->is_shared = 1; ++ switch (dev_info->segment_type) { ++ case SEG_TYPE_SR: ++ case SEG_TYPE_ER: ++ case SEG_TYPE_SC: ++ set_disk_ro(dev_info->gd, 1); ++ } + } else if (inbuf[0] == '0') { +- // reload segment in exclusive mode ++ /* reload segments in exclusive mode */ + if (dev_info->segment_type == SEG_TYPE_SC) { + PRINT_ERR("Segment type SC (%s) cannot be loaded in " +- "non-shared mode\n", dev_info->segment_name); ++ "non-shared mode\n", dev_info->segment_name); + rc = -EINVAL; + goto out; + } +- rc = segment_modify_shared(dev_info->segment_name, +- SEGMENT_EXCLUSIVE); +- if (rc < 0) { +- BUG_ON(rc == -EINVAL); +- if (rc != -EAGAIN) +- goto removeseg; +- } else { +- dev_info->is_shared = 0; +- set_disk_ro(dev_info->gd, 0); ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ rc = segment_modify_shared(entry->segment_name, ++ SEGMENT_EXCLUSIVE); ++ if (rc < 0) { ++ BUG_ON(rc == -EINVAL); ++ if (rc != -EAGAIN) ++ goto removeseg; ++ } + } ++ dev_info->is_shared = 0; ++ set_disk_ro(dev_info->gd, 0); + } else { + rc = -EINVAL; + goto out; +@@ -220,8 +404,14 @@ dcssblk_shared_store(struct device *dev, + goto out; + + removeseg: +- PRINT_ERR("Could not reload segment %s, removing it now!\n", +- dev_info->segment_name); ++ PRINT_ERR("Could not reload segment(s) of the device %s, removing " ++ "segment(s) now!\n", ++ dev_info->segment_name); ++ temp = entry; ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ if (entry != temp) ++ segment_unload(entry->segment_name); ++ } + list_del(&dev_info->lh); + + del_gendisk(dev_info->gd); +@@ -254,6 +444,7 @@ static ssize_t + dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count) + { + struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry; + + if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) + return -EINVAL; +@@ -263,14 +454,16 @@ dcssblk_save_store(struct device *dev, s + if (inbuf[0] == '1') { + if (atomic_read(&dev_info->use_count) == 0) { + // device is idle => we save immediately +- PRINT_INFO("Saving segment %s\n", ++ PRINT_INFO("Saving segment(s) of the device %s\n", + dev_info->segment_name); +- segment_save(dev_info->segment_name); ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ segment_save(entry->segment_name); ++ } + } else { + // device is busy => we save it when it becomes + // idle in dcssblk_release +- PRINT_INFO("Segment %s is currently busy, it will " +- "be saved when it becomes idle...\n", ++ PRINT_INFO("Device %s is currently busy, segment(s) " ++ "will be saved when it becomes idle...\n", + dev_info->segment_name); + dev_info->save_pending = 1; + } +@@ -279,7 +472,8 @@ dcssblk_save_store(struct device *dev, s + // device is busy & the user wants to undo his save + // request + dev_info->save_pending = 0; +- PRINT_INFO("Pending save for segment %s deactivated\n", ++ PRINT_INFO("Pending save for segment(s) of the device " ++ "%s deactivated\n", + dev_info->segment_name); + } + } else { +@@ -291,66 +485,123 @@ dcssblk_save_store(struct device *dev, s + } + + /* ++ * device attribute for showing all segments in a device ++ */ ++static ssize_t ++dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ int i; ++ ++ struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry; ++ ++ down_read(&dcssblk_devices_sem); ++ dev_info = container_of(dev, struct dcssblk_dev_info, dev); ++ i = 0; ++ buf[0] = '\0'; ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ strcpy(&buf[i], entry->segment_name); ++ i += strlen(entry->segment_name); ++ buf[i] = '\n'; ++ i++; ++ } ++ up_read(&dcssblk_devices_sem); ++ return i; ++} ++ ++/* + * device attribute for adding devices + */ + static ssize_t + dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + { +- int rc, i; ++ int rc, i, j, num_of_segments; + struct dcssblk_dev_info *dev_info; ++ struct segment_info *seg_info, *temp; + char *local_buf; + unsigned long seg_byte_size; + + dev_info = NULL; ++ seg_info = NULL; + if (dev != dcssblk_root_dev) { + rc = -EINVAL; + goto out_nobuf; + } ++ if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) { ++ rc = -ENAMETOOLONG; ++ goto out_nobuf; ++ } ++ + local_buf = kmalloc(count + 1, GFP_KERNEL); + if (local_buf == NULL) { + rc = -ENOMEM; + goto out_nobuf; + } ++ + /* + * parse input + */ ++ num_of_segments = 0; + for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) { +- local_buf[i] = toupper(buf[i]); ++ for (j = i; (buf[j] != ':') && ++ (buf[j] != '\0') && ++ (buf[j] != '\n') && ++ j < count; j++) { ++ local_buf[j-i] = toupper(buf[j]); ++ } ++ local_buf[j-i] = '\0'; ++ if (((j - i) == 0) || ((j - i) > 8)) { ++ rc = -ENAMETOOLONG; ++ goto seg_list_del; ++ } ++ ++ rc = dcssblk_load_segment(local_buf, &seg_info); ++ if (rc < 0) ++ goto seg_list_del; ++ /* ++ * get a struct dcssblk_dev_info ++ */ ++ if (num_of_segments == 0) { ++ dev_info = kzalloc(sizeof(struct dcssblk_dev_info), ++ GFP_KERNEL); ++ if (dev_info == NULL) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ strcpy(dev_info->segment_name, local_buf); ++ dev_info->segment_type = seg_info->segment_type; ++ INIT_LIST_HEAD(&dev_info->seg_list); ++ } ++ list_add_tail(&seg_info->lh, &dev_info->seg_list); ++ num_of_segments++; ++ i = j; ++ ++ if ((buf[j] == '\0') || (buf[j] == '\n')) ++ break; + } +- local_buf[i] = '\0'; +- if ((i == 0) || (i > 8)) { ++ ++ /* no trailing colon at the end of the input */ ++ if ((i > 0) && (buf[i-1] == ':')) { + rc = -ENAMETOOLONG; +- goto out; +- } +- /* +- * already loaded? +- */ +- down_read(&dcssblk_devices_sem); +- dev_info = dcssblk_get_device_by_name(local_buf); +- up_read(&dcssblk_devices_sem); +- if (dev_info != NULL) { +- PRINT_WARN("Segment %s already loaded!\n", local_buf); +- rc = -EEXIST; +- goto out; +- } +- /* +- * get a struct dcssblk_dev_info +- */ +- dev_info = kzalloc(sizeof(struct dcssblk_dev_info), GFP_KERNEL); +- if (dev_info == NULL) { +- rc = -ENOMEM; +- goto out; ++ goto seg_list_del; + } ++ strlcpy(local_buf, buf, i + 1); ++ dev_info->num_of_segments = num_of_segments; ++ rc = dcssblk_is_continuous(dev_info); ++ if (rc < 0) ++ goto seg_list_del; + +- strcpy(dev_info->segment_name, local_buf); +- strlcpy(dev_info->dev.bus_id, local_buf, BUS_ID_SIZE); ++ dev_info->start = dcssblk_find_lowest_addr(dev_info); ++ dev_info->end = dcssblk_find_highest_addr(dev_info); ++ ++ strlcpy(dev_info->dev.bus_id, dev_info->segment_name, BUS_ID_SIZE); + dev_info->dev.release = dcssblk_release_segment; + INIT_LIST_HEAD(&dev_info->lh); +- + dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); + if (dev_info->gd == NULL) { + rc = -ENOMEM; +- goto free_dev_info; ++ goto seg_list_del; + } + dev_info->gd->major = dcssblk_major; + dev_info->gd->fops = &dcssblk_devops; +@@ -360,59 +611,43 @@ dcssblk_add_store(struct device *dev, st + dev_info->gd->driverfs_dev = &dev_info->dev; + blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); + blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); +- /* +- * load the segment +- */ +- rc = segment_load(local_buf, SEGMENT_SHARED, +- &dev_info->start, &dev_info->end); +- if (rc < 0) { +- segment_warning(rc, dev_info->segment_name); +- goto dealloc_gendisk; +- } ++ + seg_byte_size = (dev_info->end - dev_info->start + 1); + set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors +- PRINT_INFO("Loaded segment %s, size = %lu Byte, " ++ PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, " + "capacity = %lu (512 Byte) sectors\n", local_buf, + seg_byte_size, seg_byte_size >> 9); + +- dev_info->segment_type = rc; + dev_info->save_pending = 0; + dev_info->is_shared = 1; + dev_info->dev.parent = dcssblk_root_dev; + + /* +- * get minor, add to list ++ *get minor, add to list + */ + down_write(&dcssblk_devices_sem); +- if (dcssblk_get_device_by_name(local_buf)) { +- up_write(&dcssblk_devices_sem); ++ if (dcssblk_get_segment_by_name(local_buf)) { + rc = -EEXIST; +- goto unload_seg; ++ goto release_gd; + } + rc = dcssblk_assign_free_minor(dev_info); +- if (rc) { +- up_write(&dcssblk_devices_sem); +- PRINT_ERR("No free minor number available! " +- "Unloading segment...\n"); +- goto unload_seg; +- } ++ if (rc) ++ goto release_gd; + sprintf(dev_info->gd->disk_name, "dcssblk%d", + dev_info->gd->first_minor); + list_add_tail(&dev_info->lh, &dcssblk_devices); + + if (!try_module_get(THIS_MODULE)) { + rc = -ENODEV; +- goto list_del; ++ goto dev_list_del; + } + /* + * register the device + */ + rc = device_register(&dev_info->dev); + if (rc) { +- PRINT_ERR("Segment %s could not be registered RC=%d\n", +- local_buf, rc); + module_put(THIS_MODULE); +- goto list_del; ++ goto dev_list_del; + } + get_device(&dev_info->dev); + rc = device_create_file(&dev_info->dev, &dev_attr_shared); +@@ -421,6 +656,9 @@ dcssblk_add_store(struct device *dev, st + rc = device_create_file(&dev_info->dev, &dev_attr_save); + if (rc) + goto unregister_dev; ++ rc = device_create_file(&dev_info->dev, &dev_attr_seglist); ++ if (rc) ++ goto unregister_dev; + + add_disk(dev_info->gd); + +@@ -434,7 +672,6 @@ dcssblk_add_store(struct device *dev, st + set_disk_ro(dev_info->gd,0); + break; + } +- PRINT_DEBUG("Segment %s loaded successfully\n", local_buf); + up_write(&dcssblk_devices_sem); + rc = count; + goto out; +@@ -445,20 +682,27 @@ unregister_dev: + dev_info->gd->queue = NULL; + put_disk(dev_info->gd); + device_unregister(&dev_info->dev); +- segment_unload(dev_info->segment_name); ++ list_for_each_entry(seg_info, &dev_info->seg_list, lh) { ++ segment_unload(seg_info->segment_name); ++ } + put_device(&dev_info->dev); + up_write(&dcssblk_devices_sem); + goto out; +-list_del: ++dev_list_del: + list_del(&dev_info->lh); +- up_write(&dcssblk_devices_sem); +-unload_seg: +- segment_unload(local_buf); +-dealloc_gendisk: ++release_gd: + blk_cleanup_queue(dev_info->dcssblk_queue); + dev_info->gd->queue = NULL; + put_disk(dev_info->gd); +-free_dev_info: ++ up_write(&dcssblk_devices_sem); ++seg_list_del: ++ if (dev_info == NULL) ++ goto out; ++ list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) { ++ list_del(&seg_info->lh); ++ segment_unload(seg_info->segment_name); ++ kfree(seg_info); ++ } + kfree(dev_info); + out: + kfree(local_buf); +@@ -473,6 +717,7 @@ static ssize_t + dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) + { + struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry; + int rc, i; + char *local_buf; + +@@ -499,26 +744,28 @@ dcssblk_remove_store(struct device *dev, + dev_info = dcssblk_get_device_by_name(local_buf); + if (dev_info == NULL) { + up_write(&dcssblk_devices_sem); +- PRINT_WARN("Segment %s is not loaded!\n", local_buf); ++ PRINT_WARN("Device %s is not loaded!\n", local_buf); + rc = -ENODEV; + goto out_buf; + } + if (atomic_read(&dev_info->use_count) != 0) { + up_write(&dcssblk_devices_sem); +- PRINT_WARN("Segment %s is in use!\n", local_buf); ++ PRINT_WARN("Device %s is in use!\n", local_buf); + rc = -EBUSY; + goto out_buf; + } +- list_del(&dev_info->lh); + ++ list_del(&dev_info->lh); + del_gendisk(dev_info->gd); + blk_cleanup_queue(dev_info->dcssblk_queue); + dev_info->gd->queue = NULL; + put_disk(dev_info->gd); + device_unregister(&dev_info->dev); +- segment_unload(dev_info->segment_name); +- PRINT_DEBUG("Segment %s unloaded successfully\n", +- dev_info->segment_name); ++ ++ /* unload all related segments */ ++ list_for_each_entry(entry, &dev_info->seg_list, lh) ++ segment_unload(entry->segment_name); ++ + put_device(&dev_info->dev); + up_write(&dcssblk_devices_sem); + +@@ -550,6 +797,7 @@ static int + dcssblk_release(struct inode *inode, struct file *filp) + { + struct dcssblk_dev_info *dev_info; ++ struct segment_info *entry; + int rc; + + dev_info = inode->i_bdev->bd_disk->private_data; +@@ -560,9 +808,11 @@ dcssblk_release(struct inode *inode, str + down_write(&dcssblk_devices_sem); + if (atomic_dec_and_test(&dev_info->use_count) + && (dev_info->save_pending)) { +- PRINT_INFO("Segment %s became idle and is being saved now\n", ++ PRINT_INFO("Device %s became idle and is being saved now\n", + dev_info->segment_name); +- segment_save(dev_info->segment_name); ++ list_for_each_entry(entry, &dev_info->seg_list, lh) { ++ segment_save(entry->segment_name); ++ } + dev_info->save_pending = 0; + } + up_write(&dcssblk_devices_sem); +@@ -602,7 +852,8 @@ dcssblk_make_request(struct request_queu + case SEG_TYPE_SC: + /* cannot write to these segments */ + if (bio_data_dir(bio) == WRITE) { +- PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id); ++ PRINT_WARN("rejecting write to ro device %s\n", ++ dev_info->dev.bus_id); + goto fail; + } + } +@@ -657,7 +908,7 @@ static void + dcssblk_check_params(void) + { + int rc, i, j, k; +- char buf[9]; ++ char buf[DCSSBLK_PARM_LEN + 1]; + struct dcssblk_dev_info *dev_info; + + for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0'); +@@ -665,15 +916,16 @@ dcssblk_check_params(void) + for (j = i; (dcssblk_segments[j] != ',') && + (dcssblk_segments[j] != '\0') && + (dcssblk_segments[j] != '(') && +- (j - i) < 8; j++) ++ (j < DCSSBLK_PARM_LEN); j++) + { + buf[j-i] = dcssblk_segments[j]; + } + buf[j-i] = '\0'; + rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i); + if ((rc >= 0) && (dcssblk_segments[j] == '(')) { +- for (k = 0; buf[k] != '\0'; k++) ++ for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++) + buf[k] = toupper(buf[k]); ++ buf[k] = '\0'; + if (!strncmp(&dcssblk_segments[j], "(local)", 7)) { + down_read(&dcssblk_devices_sem); + dev_info = dcssblk_get_device_by_name(buf); +@@ -740,10 +992,12 @@ module_exit(dcssblk_exit); + + module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444); + MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, " +- "comma-separated list, each name max. 8 chars.\n" +- "Adding \"(local)\" to segment name equals echoing 0 to " +- "/sys/devices/dcssblk//shared after loading " +- "the segment - \n" +- "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\""); ++ "comma-separated list, names in each set separated " ++ "by commas are separated by colons, each set contains " ++ "names of contiguous segments and each name max. 8 chars.\n" ++ "Adding \"(local)\" to the end of each set equals echoing 0 " ++ "to /sys/devices/dcssblk//shared after loading " ++ "the contiguous segments - \n" ++ "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\""); + + MODULE_LICENSE("GPL"); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-1.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-1.patch new file mode 100644 index 000000000..5e9d3d0cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-1.patch @@ -0,0 +1,128 @@ +From: Gerald Schaefer +Subject: (kernel):FCP - Performance Data colletion & analysis +References: bnc#417243 + +This header file is of interest for user space programming, i.e. +for tools that process blktrace data. + +We would like to use it for a tool on-top of blktrace which processes +data provided by blktrace. For this purpose, it would be helpful +if the blktrace API would make it to /usr/include/linux. + +The git tree for the blktrace tools comes with its own copy of this header +file. I didn't manage to replace that copy with the file generated +by the patch below yet. A few more cleanups would be needed. +For example, the blktrace ioctl numbers, which are currently defined in +usr/include/fs.h, might need to be moved. Should be feasible, though. + + +Signed-off-by: Sven Schuetz +Signed-off-by: Martin Peschke + +Acked-by: John Jolly + +--- + include/linux/Kbuild | 1 + include/linux/blktrace_api.h | 58 +++++++++++++++++++++++-------------------- + 2 files changed, 33 insertions(+), 26 deletions(-) + +--- a/include/linux/blktrace_api.h ++++ b/include/linux/blktrace_api.h +@@ -1,8 +1,10 @@ + #ifndef BLKTRACE_H + #define BLKTRACE_H + ++#ifdef __KERNEL__ + #include + #include ++#endif + + /* + * Trace categories +@@ -89,17 +91,17 @@ enum blktrace_notify { + * The trace itself + */ + struct blk_io_trace { +- u32 magic; /* MAGIC << 8 | version */ +- u32 sequence; /* event number */ +- u64 time; /* in microseconds */ +- u64 sector; /* disk offset */ +- u32 bytes; /* transfer length */ +- u32 action; /* what happened */ +- u32 pid; /* who did it */ +- u32 device; /* device number */ +- u32 cpu; /* on what cpu did it happen */ +- u16 error; /* completion error */ +- u16 pdu_len; /* length of data after this trace */ ++ __u32 magic; /* MAGIC << 8 | version */ ++ __u32 sequence; /* event number */ ++ __u64 time; /* in microseconds */ ++ __u64 sector; /* disk offset */ ++ __u32 bytes; /* transfer length */ ++ __u32 action; /* what happened */ ++ __u32 pid; /* who did it */ ++ __u32 device; /* device number */ ++ __u32 cpu; /* on what cpu did it happen */ ++ __u16 error; /* completion error */ ++ __u16 pdu_len; /* length of data after this trace */ + }; + + /* +@@ -117,6 +119,25 @@ enum { + Blktrace_stopped, + }; + ++/* ++ * User setup structure passed with BLKTRACESTART ++ */ ++struct blk_user_trace_setup { ++#ifdef __KERNEL__ ++ char name[BDEVNAME_SIZE]; /* output */ ++#else ++ char name[32]; /* output */ ++#endif ++ __u16 act_mask; /* input */ ++ __u32 buf_size; /* input */ ++ __u32 buf_nr; /* input */ ++ __u64 start_lba; ++ __u64 end_lba; ++ __u32 pid; ++}; ++ ++#ifdef __KERNEL__ ++#if defined(CONFIG_BLK_DEV_IO_TRACE) + struct blk_trace { + int trace_state; + struct rchan *rchan; +@@ -133,21 +154,6 @@ struct blk_trace { + atomic_t dropped; + }; + +-/* +- * User setup structure passed with BLKTRACESTART +- */ +-struct blk_user_trace_setup { +- char name[BDEVNAME_SIZE]; /* output */ +- u16 act_mask; /* input */ +- u32 buf_size; /* input */ +- u32 buf_nr; /* input */ +- u64 start_lba; +- u64 end_lba; +- u32 pid; +-}; +- +-#ifdef __KERNEL__ +-#if defined(CONFIG_BLK_DEV_IO_TRACE) + extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *); + extern void blk_trace_shutdown(struct request_queue *); + extern void __blk_add_trace(struct blk_trace *, sector_t, int, int, u32, int, int, void *); +--- a/include/linux/Kbuild ++++ b/include/linux/Kbuild +@@ -181,6 +181,7 @@ unifdef-y += audit.h + unifdef-y += auto_fs.h + unifdef-y += auxvec.h + unifdef-y += binfmts.h ++unifdef-y += blktrace_api.h + unifdef-y += capability.h + unifdef-y += capi.h + unifdef-y += cciss_ioctl.h diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-2.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-2.patch new file mode 100644 index 000000000..5fd456544 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-2.patch @@ -0,0 +1,85 @@ +From: Gerald Schaefer +Subject: (kernel):FCP - Performance Data colletion & analysis +References: bnc#417243 + +This patch adds the new api call blk_add_driver_data() to blktrace. +It allows to trace device driver-specific binary data. + +Signed-off-by: Stefan Raspl +Signed-off-by: Martin Peschke + +Acked-by: John Jolly + +--- + include/linux/blktrace_api.h | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +--- a/include/linux/blktrace_api.h ++++ b/include/linux/blktrace_api.h +@@ -23,6 +23,7 @@ enum blktrace_cat { + BLK_TC_NOTIFY = 1 << 10, /* special message */ + BLK_TC_AHEAD = 1 << 11, /* readahead */ + BLK_TC_META = 1 << 12, /* metadata */ ++ BLK_TC_DRV_DATA = 1 << 13, /* binary per-driver data */ + + BLK_TC_END = 1 << 15, /* only 16-bits, reminder */ + }; +@@ -49,6 +50,7 @@ enum blktrace_act { + __BLK_TA_SPLIT, /* bio was split */ + __BLK_TA_BOUNCE, /* bio was bounced */ + __BLK_TA_REMAP, /* bio was remapped */ ++ __BLK_TA_DRV_DATA, /* driver-specific binary data */ + }; + + /* +@@ -79,6 +81,7 @@ enum blktrace_notify { + #define BLK_TA_SPLIT (__BLK_TA_SPLIT) + #define BLK_TA_BOUNCE (__BLK_TA_BOUNCE) + #define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE)) ++#define BLK_TA_DRV_DATA (__BLK_TA_DRV_DATA | BLK_TC_ACT(BLK_TC_DRV_DATA)) + + #define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY)) + #define BLK_TN_TIMESTAMP (__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY)) +@@ -313,6 +316,34 @@ static inline void blk_add_trace_remap(s + __blk_add_trace(bt, from, bio->bi_size, bio->bi_rw, BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); + } + ++/** ++ * blk_add_driver_data - Add binary message with driver-specific data ++ * @q: queue the io is for ++ * @rq: io request ++ * @data: driver-specific data ++ * @len: length of driver-specific data ++ * ++ * Description: ++ * Some drivers might want to write driver-specific data per request. ++ * ++ **/ ++static inline void blk_add_driver_data(struct request_queue *q, ++ struct request *rq, ++ void *data, size_t len) ++{ ++ struct blk_trace *bt = q->blk_trace; ++ ++ if (likely(!bt)) ++ return; ++ ++ if (blk_pc_request(rq)) ++ __blk_add_trace(bt, 0, rq->data_len, 0, BLK_TA_DRV_DATA, ++ rq->errors, len, data); ++ else ++ __blk_add_trace(bt, rq->hard_sector, rq->hard_nr_sectors << 9, ++ 0, BLK_TA_DRV_DATA, rq->errors, len, data); ++} ++ + extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev, + char __user *arg); + extern int blk_trace_startstop(struct request_queue *q, int start); +@@ -326,6 +357,7 @@ extern int blk_trace_remove(struct reque + #define blk_add_trace_generic(q, rq, rw, what) do { } while (0) + #define blk_add_trace_pdu_int(q, what, bio, pdu) do { } while (0) + #define blk_add_trace_remap(q, bio, dev, f, t) do {} while (0) ++#define blk_add_driver_data(q, rq, data, len) do {} while (0) + #define do_blk_trace_setup(q, name, dev, buts) (-ENOTTY) + #define blk_trace_setup(q, name, dev, arg) (-ENOTTY) + #define blk_trace_startstop(q, start) (-ENOTTY) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-3-v2.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-3-v2.patch new file mode 100644 index 000000000..5a4314ddf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-3-v2.patch @@ -0,0 +1,125 @@ +From: Gerald Schaefer +Subject: (kernel):FCP - Performance Data colletion & analysis +References: bnc#417243 + +This patch writes the channel and fabric latencies in nanoseconds per +request via blktrace for later analysis. The utilization of the inbound +and outbound adapter queue is also reported. + +Signed-off-by: Stefan Raspl +Signed-off-by: Martin Peschke +Signed-off-by: Christof Schmitt + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_def.h | 2 ++ + drivers/s390/scsi/zfcp_fsf.c | 34 ++++++++++++++++++++++++++++++++++ + drivers/s390/scsi/zfcp_fsf.h | 12 ++++++++++++ + drivers/s390/scsi/zfcp_qdio.c | 1 + + 4 files changed, 49 insertions(+) + +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -6,6 +6,7 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#include + #include "zfcp_ext.h" + + static void zfcp_fsf_request_timeout_handler(unsigned long data) +@@ -834,6 +835,7 @@ static int zfcp_fsf_req_send(struct zfcp + list_add_tail(&req->list, &adapter->req_list[idx]); + spin_unlock(&adapter->req_list_lock); + ++ req->qdio_outb_usage = atomic_read(&req_q->count); + req->issued = get_clock(); + if (zfcp_qdio_send(req)) { + /* Queues are down..... */ +@@ -2036,6 +2038,36 @@ static void zfcp_fsf_req_latency(struct + spin_unlock_irqrestore(&unit->latencies.lock, flags); + } + ++#ifdef CONFIG_BLK_DEV_IO_TRACE ++static void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) ++{ ++ struct fsf_qual_latency_info *lat_inf; ++ struct scsi_cmnd *scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; ++ struct request *req = scsi_cmnd->request; ++ struct zfcp_blk_drv_data trace; ++ int ticks = fsf_req->adapter->timer_ticks; ++ ++ trace.flags = 0; ++ trace.magic = ZFCP_BLK_DRV_DATA_MAGIC; ++ if (fsf_req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) { ++ trace.flags |= ZFCP_BLK_LAT_VALID; ++ lat_inf = &fsf_req->qtcb->prefix.prot_status_qual.latency_info; ++ trace.channel_lat = lat_inf->channel_lat * ticks; ++ trace.fabric_lat = lat_inf->fabric_lat * ticks; ++ } ++ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) ++ trace.flags |= ZFCP_BLK_REQ_ERROR; ++ trace.inb_usage = fsf_req->qdio_inb_usage; ++ trace.outb_usage = fsf_req->qdio_outb_usage; ++ ++ blk_add_driver_data(req->q, req, &trace, sizeof(trace)); ++} ++#else ++static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) ++{ ++} ++#endif ++ + static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) + { + struct scsi_cmnd *scpnt = req->data; +@@ -2068,6 +2100,8 @@ static void zfcp_fsf_send_fcp_command_ta + if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) + zfcp_fsf_req_latency(req); + ++ zfcp_fsf_trace_latency(req); ++ + if (unlikely(fcp_rsp_iu->validity.bits.fcp_rsp_len_valid)) { + if (fcp_rsp_info[3] == RSP_CODE_GOOD) + set_host_byte(scpnt, DID_OK); +--- a/drivers/s390/scsi/zfcp_def.h ++++ b/drivers/s390/scsi/zfcp_def.h +@@ -638,6 +638,8 @@ struct zfcp_fsf_req { + unsigned long long issued; /* request sent time (STCK) */ + struct zfcp_unit *unit; + void (*handler)(struct zfcp_fsf_req *); ++ u16 qdio_outb_usage;/* usage of outbound queue */ ++ u16 qdio_inb_usage; /* usage of inbound queue */ + }; + + /* driver data */ +--- a/drivers/s390/scsi/zfcp_qdio.c ++++ b/drivers/s390/scsi/zfcp_qdio.c +@@ -115,6 +115,7 @@ static void zfcp_qdio_reqid_check(struct + spin_unlock_irqrestore(&adapter->req_list_lock, flags); + + fsf_req->sbal_response = sbal_idx; ++ fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count); + zfcp_fsf_req_complete(fsf_req); + } + +--- a/drivers/s390/scsi/zfcp_fsf.h ++++ b/drivers/s390/scsi/zfcp_fsf.h +@@ -514,4 +514,16 @@ struct fsf_qtcb { + u8 log[FSF_QTCB_LOG_SIZE]; + } __attribute__ ((packed)); + ++struct zfcp_blk_drv_data { ++#define ZFCP_BLK_DRV_DATA_MAGIC 0x1 ++ u32 magic; ++#define ZFCP_BLK_LAT_VALID 0x1 ++#define ZFCP_BLK_REQ_ERROR 0x2 ++ u16 flags; ++ u8 inb_usage; ++ u8 outb_usage; ++ u64 channel_lat; ++ u64 fabric_lat; ++} __attribute__ ((packed)); ++ + #endif /* FSF_H */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-4-v2.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-4-v2.patch new file mode 100644 index 000000000..2e4778412 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-04-fcpperf-4-v2.patch @@ -0,0 +1,158 @@ +From: Gerald Schaefer +Subject: zfcp: add queue_full sysfs attribute +References: bnc#417243 + +From: Stefan Raspl + +Adds a new sysfs attribute queue_full for adapters that records the number +of incidents where a requests could not be submitted due to insufficient +free space on the request queue. + +Signed-off-by: Stefan Raspl +Signed-off-by: Martin Peschke +Signed-off-by: Christof Schmitt + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_def.h | 1 + + drivers/s390/scsi/zfcp_fsf.c | 24 +++++++++++++++++------- + drivers/s390/scsi/zfcp_qdio.c | 1 + + drivers/s390/scsi/zfcp_sysfs.c | 13 +++++++++++++ + 4 files changed, 32 insertions(+), 7 deletions(-) + +--- a/drivers/s390/scsi/zfcp_def.h ++++ b/drivers/s390/scsi/zfcp_def.h +@@ -568,6 +568,7 @@ struct zfcp_adapter { + struct fsf_qtcb_bottom_port *stats_reset_data; + unsigned long stats_reset; + struct work_struct scan_work; ++ atomic_t qdio_outb_full; /* queue full incidents */ + }; + + struct zfcp_port { +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -718,6 +718,14 @@ static int zfcp_fsf_sbal_check(struct zf + return 0; + } + ++static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) ++{ ++ unsigned int count = atomic_read(&adapter->req_q.count); ++ if (!count) ++ atomic_inc(&adapter->qdio_outb_full); ++ return count > 0; ++} ++ + static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) + { + long ret; +@@ -728,6 +736,8 @@ static int zfcp_fsf_req_sbal_get(struct + zfcp_fsf_sbal_check(req_q), 5 * HZ); + if (ret > 0) + return 0; ++ if (!ret) ++ atomic_inc(&adapter->qdio_outb_full); + + spin_lock_bh(&req_q->lock); + return -EIO; +@@ -986,7 +996,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_ + struct zfcp_fsf_req *req = NULL; + + spin_lock(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, + req_flags, adapter->pool.fsf_req_abort); +@@ -1221,7 +1231,7 @@ int zfcp_fsf_send_els(struct zfcp_send_e + return -EBUSY; + + spin_lock(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, + ZFCP_REQ_AUTO_CLEANUP, NULL); +@@ -1266,7 +1276,7 @@ int zfcp_fsf_exchange_config_data(struct + int retval = -EIO; + + spin_lock_bh(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, + FSF_QTCB_EXCHANGE_CONFIG_DATA, +@@ -1362,7 +1372,7 @@ int zfcp_fsf_exchange_port_data(struct z + return -EOPNOTSUPP; + + spin_lock_bh(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + ZFCP_REQ_AUTO_CLEANUP, +@@ -1408,7 +1418,7 @@ int zfcp_fsf_exchange_port_data_sync(str + return -EOPNOTSUPP; + + spin_lock_bh(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, +@@ -2258,7 +2268,7 @@ int zfcp_fsf_send_fcp_command_task(struc + return -EBUSY; + + spin_lock(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); +@@ -2381,7 +2391,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + return NULL; + + spin_lock(&adapter->req_q.lock); +- if (!atomic_read(&adapter->req_q.count)) ++ if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); +--- a/drivers/s390/scsi/zfcp_qdio.c ++++ b/drivers/s390/scsi/zfcp_qdio.c +@@ -283,6 +283,7 @@ static int zfcp_qdio_fill_sbals(struct z + addr += length, remaining -= length) { + sbale = zfcp_qdio_sbale_next(fsf_req, sbtype); + if (!sbale) { ++ atomic_inc(&fsf_req->adapter->qdio_outb_full); + zfcp_qdio_undo_sbals(fsf_req); + return -EINVAL; + } +--- a/drivers/s390/scsi/zfcp_sysfs.c ++++ b/drivers/s390/scsi/zfcp_sysfs.c +@@ -487,10 +487,23 @@ ZFCP_SHOST_ATTR(megabytes, "%llu %llu\n" + ZFCP_SHOST_ATTR(seconds_active, "%llu\n", + (unsigned long long) stat_info.seconds_act); + ++static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *scsi_host = class_to_shost(dev); ++ struct zfcp_adapter *adapter = ++ (struct zfcp_adapter *) scsi_host->hostdata[0]; ++ ++ return sprintf(buf, "%d\n", atomic_read(&adapter->qdio_outb_full)); ++} ++static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL); ++ + struct device_attribute *zfcp_sysfs_shost_attrs[] = { + &dev_attr_utilization, + &dev_attr_requests, + &dev_attr_megabytes, + &dev_attr_seconds_active, ++ &dev_attr_queue_full, + NULL + }; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-05-kmsg-v3.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-05-kmsg-v3.patch new file mode 100644 index 000000000..074ec8f32 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-05-kmsg-v3.patch @@ -0,0 +1,10243 @@ +From: Gerald Schaefer +Subject: Kernel message catalog infrastucture and message generation +References: bnc#417300 + +Instrument the kernel components such that a kernel message catalog as well as +related man pages can be automatically generated. + +This patch now uses pr_xyz instead of kmsg_xyz and there is no Tag anymore +inside the doc file. + +Acked-by: John Jolly +--- + Documentation/kmsg/s390/aes_s390 | 30 + + Documentation/kmsg/s390/af_iucv | 33 + + Documentation/kmsg/s390/ap | 47 ++ + Documentation/kmsg/s390/appldata | 88 +++ + Documentation/kmsg/s390/cio | 92 +++ + Documentation/kmsg/s390/claw | 666 ++++++++++++++++++++++++++++ + Documentation/kmsg/s390/cpcmd | 17 + Documentation/kmsg/s390/cpu | 69 ++ + Documentation/kmsg/s390/ctcm | 199 ++++++++ + Documentation/kmsg/s390/dcssblk | 162 +++++++ + Documentation/kmsg/s390/extmem | 290 ++++++++++++ + Documentation/kmsg/s390/hypfs | 56 ++ + Documentation/kmsg/s390/iucv | 20 + Documentation/kmsg/s390/lcs | 160 ++++++ + Documentation/kmsg/s390/monreader | 127 +++++ + Documentation/kmsg/s390/monwriter | 16 + Documentation/kmsg/s390/netiucv | 139 ++++++ + Documentation/kmsg/s390/qeth | 472 ++++++++++++++++++++ + Documentation/kmsg/s390/s390dbf | 83 +++ + Documentation/kmsg/s390/sclp_cmd | 6 + Documentation/kmsg/s390/sclp_config | 3 + Documentation/kmsg/s390/sclp_cpi | 2 + Documentation/kmsg/s390/sclp_sdias | 4 + Documentation/kmsg/s390/setup | 151 ++++++ + Documentation/kmsg/s390/time | 36 + + Documentation/kmsg/s390/vmcp | 13 + Documentation/kmsg/s390/vmlogrdr | 5 + Documentation/kmsg/s390/vmur | 34 + + Documentation/kmsg/s390/xpram | 58 ++ + Documentation/kmsg/s390/zdump | 12 + Documentation/kmsg/s390/zfcp | 830 ++++++++++++++++++++++++++++++++++++ + Makefile | 16 + arch/s390/Kconfig | 9 + arch/s390/appldata/appldata.h | 4 + arch/s390/appldata/appldata_base.c | 11 + arch/s390/appldata/appldata_os.c | 20 + arch/s390/crypto/aes_s390.c | 13 + arch/s390/hypfs/hypfs_diag.c | 9 + arch/s390/hypfs/inode.c | 13 + arch/s390/kernel/Makefile | 4 + arch/s390/kernel/cpcmd.c | 6 + arch/s390/kernel/debug.c | 36 - + arch/s390/kernel/processor.c | 97 ++++ + arch/s390/kernel/setup.c | 159 +----- + arch/s390/kernel/smp.c | 16 + arch/s390/kernel/time.c | 13 + arch/s390/kernel/topology.c | 4 + arch/s390/mm/extmem.c | 105 +--- + drivers/s390/block/dcssblk.c | 73 +-- + drivers/s390/block/xpram.c | 40 - + drivers/s390/char/monreader.c | 40 - + drivers/s390/char/monwriter.c | 4 + drivers/s390/char/sclp_cmd.c | 28 - + drivers/s390/char/sclp_config.c | 9 + drivers/s390/char/sclp_cpi_sys.c | 11 + drivers/s390/char/sclp_sdias.c | 17 + drivers/s390/char/vmcp.c | 7 + drivers/s390/char/vmlogrdr.c | 25 - + drivers/s390/char/vmur.c | 14 + drivers/s390/char/zcore.c | 13 + drivers/s390/cio/blacklist.c | 13 + drivers/s390/cio/chsc.c | 7 + drivers/s390/cio/cio.c | 4 + drivers/s390/cio/cmf.c | 7 + drivers/s390/cio/css.c | 7 + drivers/s390/crypto/ap_bus.c | 9 + drivers/s390/net/claw.c | 258 +++++------ + drivers/s390/net/ctcm_fsms.c | 45 + + drivers/s390/net/ctcm_main.c | 71 +-- + drivers/s390/net/ctcm_main.h | 6 + drivers/s390/net/ctcm_mpc.c | 14 + drivers/s390/net/ctcm_sysfs.c | 2 + drivers/s390/net/lcs.c | 91 ++- + drivers/s390/net/netiucv.c | 63 +- + drivers/s390/net/qeth_core.h | 7 + drivers/s390/net/qeth_core_main.c | 148 +++--- + drivers/s390/net/qeth_l2_main.c | 40 - + drivers/s390/net/qeth_l3_main.c | 214 ++++----- + drivers/s390/scsi/zfcp_aux.c | 10 + drivers/s390/scsi/zfcp_ccw.c | 14 + drivers/s390/scsi/zfcp_cfdc.c | 2 + drivers/s390/scsi/zfcp_dbf.c | 2 + drivers/s390/scsi/zfcp_erp.c | 53 +- + drivers/s390/scsi/zfcp_fc.c | 2 + drivers/s390/scsi/zfcp_fsf.c | 234 +++------- + drivers/s390/scsi/zfcp_qdio.c | 28 - + drivers/s390/scsi/zfcp_scsi.c | 5 + drivers/s390/scsi/zfcp_sysfs.c | 2 + include/linux/device.h | 28 - + include/linux/kernel.h | 38 + + kernel/printk.c | 45 + + net/iucv/af_iucv.c | 18 + net/iucv/iucv.c | 8 + scripts/Makefile.build | 14 + scripts/kmsg-doc | 477 ++++++++++++++++++++ + 95 files changed, 5641 insertions(+), 1081 deletions(-) + +--- /dev/null ++++ b/Documentation/kmsg/s390/aes_s390 +@@ -0,0 +1,30 @@ ++/*? ++ * Text: "Allocating AES fallback algorithm %s failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: algorithm name ++ * Description: ++ * The advanced encryption standard (AES) algorithm includes three modes with ++ * 128-bit, 192-bit, and 256-bit keys. Your hardware system only provides ++ * hardware acceleration for the 128-bit mode. The aes_s390 module failed to ++ * allocate a software fallback for the AES modes that are not supported by the ++ * hardware. A possible reason for this problem is that the aes_generic module ++ * that provides the fallback algorithms is not available. ++ * User action: ++ * Use the 128-bit mode only or ensure that the aes_generic module is available ++ * and loaded and reload the aes_s390 module. ++ */ ++ ++/*? ++ * Text: "AES hardware acceleration is only available for 128-bit keys\n" ++ * Severity: Informational ++ * Description: ++ * The advanced encryption standard (AES) algorithm includes three modes with ++ * 128-bit, 192-bit, and 256-bit keys. Your hardware system only provides ++ * hardware acceleration for the 128-bit key mode. The aes_s390 module ++ * will use the less performant software fallback algorithm for the 192-bit ++ * and 256-bit key modes. ++ * User action: ++ * None. ++ */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/af_iucv +@@ -0,0 +1,33 @@ ++/*? ++ * Text: "Application %s on z/VM guest %s exceeds message limit\n" ++ * Severity: Error ++ * Parameter: ++ * @1: application name ++ * @2: z/VM user ID ++ * Description: ++ * Messages or packets destined for the application have accumulated and ++ * reached the maximum value. The default for the message limit is 65535. ++ * You can specify a different limit as the value for MSGLIMIT within ++ * the IUCV statement of the z/VM virtual machine on which the application ++ * runs. ++ * User action: ++ * Ensure that you do not send data faster than the application retrieves ++ * them. Ensure that the message limit on the z/VM guest virtual machine ++ * on which the application runs is high enough. ++ */ ++ ++/*? ++ * Text: "The af_iucv module cannot be loaded without z/VM\n" ++ * Severity: Error ++ * Description: ++ * The AF_IUCV protocol connects socket applications running in Linux ++ * kernels on different z/VM virtual machines, or it connects a Linux ++ * application to another sockets application running in a z/VM virtual ++ * machine. On Linux instances that run in environments other than the ++ * z/VM hypervisor, the AF_IUCV protocol does not provide any useful ++ * function and the corresponding af_iucv module cannot be loaded. ++ * User action: ++ * Load the af_iucv module only on Linux instances that run as guest ++ * operating systems of the z/VM hypervisor. If the module has been ++ * compiled into the kernel, ignore this message. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/ap +@@ -0,0 +1,47 @@ ++/*? ++ * Text: "%d is not a valid cryptographic domain\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: AP domain index ++ * Description: ++ * The cryptographic domain specified for the 'domain=' module or kernel ++ * parameter must be an integer in the range 0 to 15. ++ * User action: ++ * Reload the cryptographic device driver with a correct module parameter. ++ * If the device driver has been compiled into the kernel, correct the value ++ * in the kernel parameter line and reboot Linux. ++ */ ++ ++/*? ++ * Text: "The hardware system does not support AP instructions\n" ++ * Severity: Warning ++ * Description: ++ * The ap module addresses AP adapters through AP instructions. The hardware ++ * system on which the Linux instance runs does not support AP instructions. ++ * The ap module cannot detect any AP adapters. ++ * User action: ++ * Load the ap module only if your Linux instance runs on hardware that ++ * supports AP instructions. If the ap module has been compiled into the kernel, ++ * ignore this message. ++ */ ++ ++/*? ++ * Text: "Registering adapter interrupts for AP %d failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: AP device ID ++ * Description: ++ * The hardware system supports AP adapter interrupts but failed to enable ++ * an adapter for interrupts. Possible causes for this error are: ++ * i) The AP adapter firmware does not support AP interrupts. ++ * ii) An AP adapter firmware update to a firmware level that supports AP ++ * adapter interrupts failed. ++ * iii) The AP adapter firmware has been successfully updated to a level that ++ * supports AP interrupts but the new firmware has not been activated. ++ * User action: ++ * Ensure that the firmware on your AP adapters support AP interrupts and that ++ * any firmware updates have completed successfully. If necessary, deconfigure ++ * your cryptographic adapters and reconfigure them to ensure that any firmware ++ * updates become active, then reload the ap module. If the ap module has been ++ * compiled into the kernel, reboot Linux. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/appldata +@@ -0,0 +1,88 @@ ++/*? ++ * Text: "Starting the data collection for %s failed with rc=%d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: appldata module ++ * @2: return code ++ * Description: ++ * The specified data collection module used the z/VM diagnose call ++ * DIAG 0xDC to start writing data. z/VM returned an error and the data ++ * collection could not start. If the return code is 5, your z/VM guest ++ * virtual machine is not authorized to write data records. ++ * User action: ++ * If the return code is 5, ensure that your z/VM guest virtual machine's ++ * entry in the z/VM directory includes the OPTION APPLMON statement. ++ * For other return codes see the section about DIAGNOSE Code X'DC' ++ * in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "Stopping the data collection for %s failed with rc=%d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: appldata module ++ * @2: return code ++ * Description: ++ * The specified data collection module used the z/VM diagnose call DIAG 0xDC ++ * to stop writing data. z/VM returned an error and the data collection ++ * continues. ++ * User action: ++ * See the section about DIAGNOSE Code X'DC' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "Starting a new OS data collection failed with rc=%d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: return code ++ * Description: ++ * After a CPU hotplug event, the record size for the running operating ++ * system data collection is no longer correct. The appldata_os module tried ++ * to start a new data collection with the correct record size but received ++ * an error from the z/VM diagnose call DIAG 0xDC. Any data collected with ++ * the current record size might be faulty. ++ * User action: ++ * Start a new data collection with the cappldata_os module. For information ++ * about starting data collections see "Device Drivers, Features, and ++ * Commands". For information about the return codes see the section about ++ * DIAGNOSE Code X'DC' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "Stopping a faulty OS data collection failed with rc=%d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: return code ++ * Description: ++ * After a CPU hotplug event, the record size for the running operating ++ * system data collection is no longer correct. The appldata_os module tried ++ * to stop the faulty data collection but received an error from the z/VM ++ * diagnose call DIAG 0xDC. Any data collected with the current record size ++ * might be faulty. ++ * User action: ++ * Try to restart appldata_os monitoring. For information about stopping ++ * and starting data collections see "Device Drivers, Features, and ++ * Commands". For information about the return codes see the section about ++ * DIAGNOSE Code X'DC' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "Maximum OS record size %i exceeds the maximum record size %i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: no of bytes ++ * @2: no of bytes ++ * Description: ++ * The OS record size grows with the number of CPUs and is adjusted by the ++ * appldata_os module in response to CPU hotplug events. For more than 110 ++ * CPUs the record size would exceed the maximum record size of 4024 bytes ++ * that is supported by the z/VM hypervisor. To prevent the maximum supported ++ * record size from being exceeded while data collection is in progress, ++ * you cannot load the appldata_os module on Linux instances that are ++ * configured for a maximum of more than 110 CPUs. ++ * User action: ++ * If you do not want to collect operating system data, you can ignore this ++ * message. If you want to collect operating system data, reconfigure your ++ * Linux instance to support less than 110 CPUs. ++ */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/cio +@@ -0,0 +1,92 @@ ++/*? ++ * Text: "%s is not a valid device for the cio_ignore kernel parameter\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: device bus-ID ++ * Description: ++ * The device specification for the cio_ignore kernel parameter is ++ * syntactically incorrect or specifies an unknown device. This device is not ++ * excluded from being sensed and analyzed. ++ * User action: ++ * Correct your device specification in the kernel parameter line to have the ++ * device excluded when you next reboot Linux. You can write the correct ++ * device specification to /proc/cio_ignore to add the device to the list of ++ * devices to be excluded. This does not immediately make the device ++ * inaccessible but the device is ignored if it disappears and later reappears. ++ */ ++ ++/*? ++ * Text: "0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: from subchannel set ID ++ * @2: from device number ++ * @3: to subchannel set ID ++ * @4: to device number ++ * Description: ++ * The device range specified for the cio_ignore kernel parameter is ++ * syntactically incorrect. No devices specified with this range are ++ * excluded from being sensed and analyzed. ++ * User action: ++ * Correct your range specification in the kernel parameter line to have the ++ * range of devices excluded when you next reboot Linux. You can write the ++ * correct range specification to /proc/cio_ignore to add the range of devices ++ * to the list of devices to be excluded. This does not immediately make the ++ * devices in the range inaccessible but any of these devices are ignored if ++ * they disappear and later reappear. ++ */ ++ ++/*? ++ * Text: "Processing %s for channel path %x.%02x\n" ++ * Severity: Notice ++ * Parameter: ++ * @1: configuration change ++ * @2: channel subsystem ID ++ * @3: CHPID ++ * Description: ++ * A configuration change is in progress for the given channel path. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "No CCW console was found\n" ++ * Severity: Warning ++ * Description: ++ * Linux did not find the expected CCW console and tries to use an alternative ++ * console. A possible reason why the console was not found is that the console ++ * has been specified in the cio_ignore list. ++ * User action: ++ * None, if an appropriate alternative console has been found, and you want ++ * to use this alternative console. If you want to use the CCW console, ensure ++ * that is not specified in the cio_ignore list, explicitly specify the console ++ * with the 'condev=' kernel parameter, and reboot Linux. ++ */ ++ ++/*? ++ * Text: "Channel measurement facility initialized using format %s (mode %s)\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: format ++ * @2: mode ++ * Description: ++ * The channel measurement facility has been initialized successfully. Format ++ * 'extended' should be used for z990 and later mainframe systems. Format ++ * 'basic' is intended for earlier mainframes. Mode 'autodetected' means that ++ * the format has been set automatically. Mode 'parameter' means that the ++ * format has been set according to the 'format=' kernel parameter. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "The CSS device driver initialization failed with errno=%d\n" ++ * Severity: Alert ++ * Parameter: ++ * @1: Return code ++ * Description: ++ * The channel subsystem bus could not be established. ++ * User action: ++ * See the errno man page to find out what caused the problem. ++ */ ++ /*? Text: "%s: Got subchannel machine check but no sch_event handler provided.\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/claw +@@ -0,0 +1,666 @@ ++/*? ++ * Text: "%s: add_files failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Device ++ * Description: ++ * sysfs_create_group() failed to create the ++ * /proc/... files for the new device. ++ * This could be a result of the /proc file ++ * system not being available or it could be ++ * a symptom of a more serious problem. ++ * User action: ++ * The device will not start. Re-start the device ++ * If the /proc file system is not available CLAW ++ * devices cannot be used. ++ */ ++ ++/*? ++ * Text: "%s: unsolicited interrupt for device received c-%02x d-%02x\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device address ++ * @2: Returned SubChannel Status word ++ * @3: Returned Device Status word ++ * Description: ++ * An IRQ (channel interrupt) was received for a device that ++ * was not in a state to receive data. The IRQ will be ++ * ignored. ++ * User action: ++ * This can happen as devices come on and off line. ++ * If the problem persists or the device will not ++ * activate, channel tracing or device traces may be ++ * used to diagnose the problem. ++ */ ++ ++/*? ++ * Text: "%s: Can't determine channel for interrupt\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device address ++ * Description: ++ * The interrupt device was not the READ or WRITE device ++ * for the CLAW device. The bus address of the interrupt ++ * is displayed. This should not occur and indicates a ++ * a problem in the CCW driver in the kernel. ++ * User action: ++ * If the problem persists check if an incorrect device type ++ * has been assigned to a CLAW channel. ++ */ ++ ++/*? ++ * Text: "%s: %s: wrong selection code - irq state=%d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: Current CLAW device status ++ * Description: ++ * The CLAW device is in an invalid CCW state ++ * to handle IO. The interrupt will be ignored. ++ * User action: ++ * The device may need to be restarted. If the problem ++ * persists s390dbf traces and CCW traces may be used ++ * to diagnose the problem. ++ * The CLAW status is a number from 0 to 4 indicating the device ++ * driver's view of the read or write channel state. ++ * Channel status values: ++ * 0 The channel is inactive ++ * 1 The channel is ready to start ++ * 2 RESERVED ++ * 3 The channel is started for READ ++ * 4 The channel is started for WRITE ++ */ ++ ++/*? ++ * Text: "%s: %s: channel problems during close - read: %02x - write: %02x\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: Saved CLAW Read sub channel Device Status ++ * @4: Saved CLAW Write sub channel Device Status ++ * Description: ++ * claw_release() has freed all of the storage ++ * for the device. The device state is expected to be ++ * DEVICE END and CHANNEL END and it was not. ++ * The device may not restart cleanly. ++ * User action: ++ * The device should restart after varying it ++ * on and offline. If not it, power the CLAW device off ++ * and on and retry. ++ */ ++ ++/*? ++ * Text: "%s: Device not found for IO ENODEV\n" ++ * Severity: Error ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * A Channel Command Word was executed and returned ++ * a non-zero return code (ERRNO) was returned by ++ * the Common IO Layer. ++ * User action: ++ * The ERRNO indicated was ENODEV. This indicates that the ++ * Device was offline or not operational. ++ * Check the status of the device and restart the device. ++ */ ++ ++/*? ++ * Text: "%s: Status pending... EIO \n" ++ * Severity: Error ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * The Common IO Layer returned an EIO ERRNO ++ * when a CCW was executed. ++ * A 'sub-channel check for device:' message may ++ * also be seen with the cstat and other device status. ++ * User action: ++ * The device may be in an invalid state. Check the ++ * device status and restart the device if needed. ++ */ ++ ++/*? ++ * Text: "%s: Invalid Dev State EINVAL \n" ++ * Severity: Error ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * The Common IO Layer returned an EINVAL ERRNO ++ * when a CCW was executed. ++ * A 'sub-channel check for device:' message may ++ * also be seen with the cstat and other device status. ++ * User action: ++ * The ERRNO indicated was ENODEV. This indicates that the ++ * Device was offline or not operational. ++ * Check the status of the device and restart the device. ++ */ ++ ++/*? ++ * Text: "%s: Unknown error in Do_IO %d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: ERRNO ++ * Description: ++ * The Common IO Layer returned an unexpected ERRNO ++ * when a CCW was executed. ++ * A 'sub-channel check for device:' message may ++ * also be seen with the cstat and other device status. ++ * User action: ++ * Determine the ERRNO issued and restart the device. ++ * If the problem remains a sub-channel trace may be needed. ++ */ ++ ++/*? ++ * Text: "%s: %s: Interface disconnect or Selective reset occurred (remote side)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CCW completed with the Returned Device Status word ++ * having DEV_STAT_UNIT_CHECK set. The Sense code contained 0x41 ++ * User action: ++ * The CLAW device has been reset or the CLAW device's ++ * channel card has been reset. ++ * Once the device is back in service restart the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: System reset occurred (remote side)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CCW completed with the Returned Device Status word ++ * having DEV_STAT_UNIT_CHECK set. The Sense code contained 0x40 ++ * User action: ++ * The CLAW device has been reset or the CLAW device's ++ * channel card has been reset. ++ * Once the device is back in service restart the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: Data-streaming timeout)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CCW completed with the Returned Device Status word ++ * having DEV_STAT_UNIT_CHECK set. The Sense code contained 0x24 ++ * User action: ++ * The device may be having errors or the channel is not operating ++ * properly. CCW trace may be needed to diagnose. Restart ++ * the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: Data-transfer parity error\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @1: network device name (eg. claw0) ++ * Description: ++ * The CCW completed with the Returned Device Status word ++ * having DEV_STAT_UNIT_CHECK set. The Sense code contained 0x20 ++ * User action: ++ * The device may be having errors or the channel is not operating ++ * properly. CCW trace may be needed to diagnose. Restart ++ * the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: Hardware malfunction (remote side)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CCW completed with the Returned Device Status word ++ * having DEV_STAT_UNIT_CHECK set. The Sense code contained 0x30 ++ * User action: ++ * The CLAW Device may be in error. Check the device and restart. ++ * If the problem continues CCW traces and device ++ * diagnosis will be needed. ++ */ ++ ++/*? ++ * Text: "%s: %s: read-data parity error (remote side)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CCW completed with the Returned Device Status word ++ * having DEV_STAT_UNIT_CHECK set. The Sense code contained 0x10 ++ * User action: ++ * The CLAW Device may be in error. Check the device and restart. ++ * If the problem continues CCW traces and device ++ * diagnosis will be needed. ++ */ ++ ++/*? ++ * Text: "%s: %s: %d is wrong version id. Expected %d\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: CLAW API version (must be '2') ++ * @4: 2 ++ * Description: ++ * The claw device driver received a ++ * SYSTEM_VALIDATE_REQUEST packet with a mismatched version ID ++ * claw expects all packets to be version 2. ++ * User action: ++ * The CLAW device has sent an invalid packet. Check the device ++ * and if needed trace the channel to determine the cause. ++ */ ++ ++/*? ++ * Text: "%s: %s: Host name mismatch. Received: %s expected: %s\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: The 1 to 8 character host name received ++ * @4: The 1 to 8 character host name configured ++ * Description: ++ * The HOSTNAME portion of the CLAW parameters does not match the ++ * HOSTNAME received on a control packet from the CLAW Device. ++ * The 1 to 8 character host name received is the received host name. ++ * User action: ++ * Check the claw device parameters and the CLAW device definitions. ++ * Correct the parameter so the parameters match and ++ * restart the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: WS name mismatch. Received: %s expected: %s\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @1: network device name (eg. claw0) ++ * @2: The 1 to 8 character Work Station Name received ++ * @3: The 1 to 8 character Work Station Name configured ++ * Description: ++ * The Work Station name portion of the CLAW parameters does not match the ++ * WSNAME received on a control packet from the CLAW Device. ++ * The received Work Station name is in The 1 to 8 character Work Station Name received. ++ * User action: ++ * Check the claw device parameters and the CLAW device definitions. ++ * Correct the parameter so the parameters match and ++ * restart the device. ++ */ ++ ++/*? ++ * Text: "%s: host write size is too small\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * The write buffer size received from the ++ * CLAW device is smaller than the ++ * write buffer size that the parameters the ++ * device was defined with. ++ * User action: ++ * Check the setup of the device and the ++ * claw device parameters and correct the ++ * difference. ++ */ ++ ++/*? ++ * Text: "%s: host read size is too small\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * * The read buffer size received from the ++ * CLAW device is smaller than the ++ * read buffer size in the parameters the ++ * device was defined with. ++ * User action: ++ * Check the setup of the device and the ++ * claw device parameters and correct the ++ * difference. ++ */ ++ ++/*? ++ * Text: "%s: %s: Recv Sys Validate Resp: Vers=%d,Corr=%d,RC=%d,WS name=%.8s,Host name=%.8s\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: CLAW API version (must be '2') ++ * @4: CLAW device identifier ++ * @5: Return code received from CLAW device ++ * @6: The 1 to 8 character Work Station Name received ++ * @7: The 1 to 8 character Host Name received ++ * Description: ++ * A System Validate packet was sent to the device and ++ * a response was received. The message summarizes ++ * the content of the response. ++ * User action: ++ * Check for expected values. ++ */ ++ ++/*? ++ * Text: "%s: %s: Sys Validate Resp : Host, WS name is mismatch\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * A System validate request sent to the CLAW ++ * device has been rejected due to ++ * mismatched parameters. The device will not start. ++ * User action: ++ * Check the CLAW device parameters and ensure ++ * they match the CLAW devices definitions. ++ */ ++ ++/*? ++ * Text: "%s: %s: Sys Validate Resp : Wrong version\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * A System validate request sent to the CLAW ++ * device has been rejected due to ++ * mismatched parameters. The device will not start. ++ * User action: ++ * Check the CLAW device parameters and ensure ++ * they match the CLAW devices definitions. ++ */ ++ ++/*? ++ * Text: "%s: %s: Sys Validate Resp : bad frame size\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * A System validate request sent to the CLAW ++ * device has been rejected due to ++ * mismatched parameters. The device will not start. ++ * User action: ++ * Check the CLAW device parameters and ensure ++ * they match the CLAW devices definitions. ++ */ ++ ++/*? ++ * Text: "%s: %s: Sys Validate error code=%d \n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: Return code received ++ * Description: ++ * A System validate request sent to the CLAW ++ * device has been rejected due to ++ * mismatched parameters. The device will not start. ++ * User action: ++ * Check the CLAW device parameters and ensure ++ * they match the CLAW devices definitions. ++ */ ++ ++/*? ++ * Text: "%s: %s: Conn Req error : already logical link is active \n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * A connection request has been received but the ++ * logical link is already active. ++ * User action: ++ * This can be a timing error. If the device ++ * fails to connect a restart may be needed. ++ */ ++ ++/*? ++ * Text: "%s: %s: Conn Req error : req logical link id is not 1\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The current CLAW design allows only logical link 1 ++ * A device attempted to connect with a Log Link ID ++ * other than 1. The connection will be rejected. ++ * User action: ++ * Check the device setup and restart the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: Conn Req error : req appl name does not match\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @1: network device name (eg. claw0) ++ * Description: ++ * A Connection Request was received with a mismatched ++ * WS Application name. ++ * User action: ++ * Check the device driver setup and restart the device. ++ */ ++ ++/*? ++ * Text: "%s: %s: Conn Resp error: rc=%d \n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @1: network device name (eg. claw0) ++ * @2: Return code received ++ * Description: ++ * An error was detected by the CLAW device in ++ * the Connection Request packet it processed. ++ * User action: ++ * Check the device parameters and restart. ++ */ ++ ++/*? ++ * Text: "%s: %s: Conn Resp error: req appl name does not match\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CLAW device received a Connection Request with ++ * a mismatched Application ID. The connection will ++ * not be started. ++ * User action: ++ * Check the definitions in the device and the device driver ++ * and correct errors. ++ */ ++ ++/*? ++ * Text: "%s: %s: Conn confirm: unexpected linkid=%d \n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: p_ctlbk->linkid ++ * Description: ++ * A Connection Confirmed packet was received ++ * with a different link Id than the default ++ * User action: ++ * The link will not become active. A restart ++ * is required after checking the device parameters. ++ */ ++ ++/*? ++ * Text: "%s: %s: CLAW ERROR detected\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * Description: ++ * The CLAW device detected an error condition ++ * User action: ++ * Check the logs and traces on the device. ++ * If the problem persists diagnostic traces may be ++ * needed ++ */ ++ ++/*? ++ * Text: "%s: %s: Unexpected command code=%d \n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: CLAW command code received ++ * Description: ++ * This should not occur. An undefined command code ++ * was received in a control packet from the CLAW ++ * device. ++ * User action: ++ * Restart the device. If the problem persists ++ * tracing of the connection and diagnosis of the ++ * device may be needed. ++ */ ++ ++/*? ++ * Text: "%s: %s: Invalid frame detected length is %02x\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: network device name (eg. claw0) ++ * @3: Data packet frame length value ++ * Description: ++ * Claw data packet was received with an invalid length field. ++ * the header length is shown. This can be the result of ++ * data errors or invalid packing. ++ * User action: ++ * restart the device and if the problem persists trace the ++ * device or channel interface. ++ */ ++ ++/*? ++ * Text: "%s: buffer allocate failed on receive\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * Claw data packet was received but allocate for the recevie buffer ++ * failed. this can be a low memory condition. ++ * the data packet will be dropped. ++ * User action: ++ * Restart the device if the problem persists. ++ */ ++ ++/*? ++ * Text: "%s: add channel failed with ret = %d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: ERRNO ++ * Description: ++ * add_channel() failed with return code rc. ++ * This is most likely an ENOMEM errno returned from ++ * an attempt to allocate an IRB for the CLAW ++ * channel device structure. ++ * User action: ++ * Check the return code and take action as needed. ++ * If this is caused by a low memory condition in the ++ * kernel itself several other messages and symptoms ++ * may appear. if the problem persists expert assistance ++ * in kernel diagosis may be needed. ++ */ ++ ++/*? ++ * Text: "%s: device set online READ failed with ret = %d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: ret ++ * Description: ++ * A non zero return code was the result of an attempt to ++ * set the device online. The device cannot be activated. ++ * User action: ++ * Check the device driver parameters and the system definitions. ++ */ ++ ++/*? ++ * Text: "%s: device set online WRITE failed with ret = %d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * @2: ret ++ * Description: ++ * A non zero return code was the result of an attempt to ++ * set the device online. The device cannot be activated. ++ * User action: ++ * Check the device driver parameters and the system definitions. ++ */ ++ ++/*? ++ * Text: "%s: failed creating network device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: Channel Device Address ++ * Description: ++ * Creation of a network claw device failed. ++ * no pointer to a new device was returned. ++ * User action: ++ * Check for errors in the Linux system. ++ * This can result from memory shortage or ++ * errors in setup. ++ */ ++ ++/*? ++ * Text: "debug_register failed %d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: ret ++ * Description: ++ * The claw driver failed to register with the ccw ++ * s390dbf facility. No DBF traces will be available. ++ * User action: ++ * Check the state of the dbf facility unload the ++ * the device driver and reload. ++ */ ++ ++/*? ++ * Text: "register_cu3088_discipline() failed rc=%d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: ret ++ * Description: ++ * The claw driver failed to register with the ++ * channel subsystem drivers. cu3088 driver ++ * may not be loaded or may not be operational. ++ * User action: ++ * Check the state of the cu3088 facility unload the ++ * the device driver and reload. ++ */ ++ ++/*? Text: "%s: %s: CLAW device %.8s: Received Control Packet\n" */ ++/*? Text: "%s: %s: CLAW device %.8s: System validate completed.\n" */ ++/*? Text: "%s: %s: CLAW device %.8s: Connection completed link_id=%d.\n" */ ++/*? Text: "%s: %s: remote side is not ready\n" */ ++/*? Text: "%s: %s: Unit Check with sense byte:0x%04x\n" */ ++/*? Text: "%s: %s: write connection restarting\n" */ ++/*? Text: "%s: %s: subchannel check for device: %04x - Sch Stat %02x Dev Stat %02x CPA - %04x\n" */ ++/*? Text: "%s: %s: Unit Exception occurred in write channel\n" */ ++/*? Text: "%s: %s: Resetting Event occurred:\n" */ ++/*? Text: "%s: %s: Recv Conn Confirm:Vers=%d,link_id=%d,Corr=%d,Host appl=%.8s,WS appl=%.8s\n" */ ++/*? Text: "%s: %s: Recv Conn Req: Vers=%d,link_id=%d,Corr=%d,HOST appl=%.8s,WS appl=%.8s\n" */ ++/*? Text: "%s: %s: Recv Sys Validate Request: Vers=%d,link_id=%d,Corr=%d,WS name=%.8s,Host name=%.8s\n" */ ++/*? Text: "%s: %s: Confirmed Now packing\n" */ ++/*? Text: "%s: %s: Unit Check Occured in write channel\n" */ ++/*? Text: "%s: %s: Restart is required after remote side recovers \n" */ ++/*? Text: "%s: %s: sys Validate Rsize:%d Wsize:%d\n" */ ++/*? Text: "%s: %s:readsize=%d writesize=%d readbuffer=%d writebuffer=%d read=0x%04x write=0x%04x\n" */ ++/*? Text: "%s: %s:host_name:%.8s, adapter_name :%.8s api_type: %.8s\n" */ ++/*? Text: "Driver unloaded\n" */ ++/*? Text: "Loading %s\n" */ ++/*? Text: "%s: will be removed.\n" */ ++/*? Text: "%s: add for %s\n" */ ++/*? Text: "%s: %s: shutting down \n" */ ++/*? Text: "%s: CLAW device %.8s: System validate completed.\n" */ ++/*? Text: "%s: %s: Disconnect: Vers=%d,link_id=%d,Corr=%d\n" */ ++/*? Text: "%s: %s: Revc Conn Resp: Vers=%d,link_id=%d,Corr=%d,RC=%d,Host appl=%.8s, WS appl=%.8s\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/cpcmd +@@ -0,0 +1,17 @@ ++/*? ++ * Text: "The cpcmd kernel function failed to allocate a response buffer\n" ++ * Severity: Warning ++ * Description: ++ * IPL code, console detection, and device drivers like vmcp or vmlogrdr use ++ * the cpcmd kernel function to send commands to the z/VM control program (CP). ++ * If a program that uses the cpcmd function does not allocate a contiguous ++ * response buffer below 2 GB guest real storage, cpcmd creates a bounce buffer ++ * to be used as the response buffer. Because of low memory or memory ++ * fragmentation, cpcmd could not create the bounce buffer. ++ * User action: ++ * Look for related page allocation failure messages and at the stack trace to ++ * find out which program or operation failed. Free some memory and retry the ++ * failed operation. Consider allocating more memory to your z/VM guest virtual ++ * machine. ++ */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/cpu +@@ -0,0 +1,69 @@ ++/*? ++ * Text: "Processor %d started, address %d, identification %06X\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: logical CPU number ++ * @2: CPU address ++ * @3: CPU identification number ++ * Description: ++ * The kernel detected a CPU with the given characteristics. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Processor %d stopped\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: logical CPU number ++ * Description: ++ * A logical CPU has been set offline. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "%d configured CPUs, %d standby CPUs\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: number of configured CPUs ++ * @2: number of standby CPUs ++ * Description: ++ * The kernel detected the given number of configured and standby CPUs. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "The CPU configuration topology of the machine is:" ++ * Severity: Informational ++ * Description: ++ * The first six values of the topology information represent fields Mag1 to ++ * Mag6 of system-information block (SYSIB) 15.1.2. These fields specify the ++ * maximum numbers of topology-list entries (TLE) at successive topology nesting ++ * levels. The last value represents the MNest value of SYSIB 15.1.2 which ++ * specifies the maximum possible nesting that can be configured through ++ * dynamic changes. For details see the SYSIB 15.1.2 information in the ++ * "Principles of Operation." ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "CPU %i exceeds the maximum %i and is excluded from the dump\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: CPU number ++ * @2: maximum CPU number ++ * Description: ++ * The Linux kernel is used as a system dumper but it runs on more CPUs than ++ * it has been compiled for with the CONFIG_NR_CPUS kernel configuration ++ * option. The system dump will be created but information on one or more ++ * CPUs will be missing. ++ * User action: ++ * Update the system dump kernel to a newer version that supports more ++ * CPUs or reduce the number of installed CPUs and reproduce the problem ++ * that should be analyzed. If you send the system dump that prompted this ++ * message to a support organization, be sure to communicate that the dump ++ * does not include all CPU information. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/ctcm +@@ -0,0 +1,199 @@ ++/*? ++ * Text: "%s: An I/O-error occurred on the CTCM device\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * Description: ++ * An I/O error was detected on one of the subchannels of the CTCM device. ++ * Depending on the error, the CTCM device driver might attempt an automatic ++ * recovery. ++ * User action: ++ * Check the status of the CTCM device, for example, with ifconfig. If the ++ * device is not operational, perform a manual recovery. See "Device Drivers, ++ * Features, and Commands" for details about how to recover a CTCM device. ++ */ ++ ++/*? ++ * Text: "%s: An adapter hardware operation timed out\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * Description: ++ * The CTCM device uses an adapter to physically connect to its communication ++ * peer. An operation on this adapter timed out. ++ * User action: ++ * Check the status of the CTCM device, for example, with ifconfig. If the ++ * device is not operational, perform a manual recovery. See "Device Drivers, ++ * Features, and Commands" for details about how to recover a CTCM device. ++ */ ++ ++/*? ++ * Text: "%s: An error occurred on the adapter hardware\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * Description: ++ * The CTCM device uses an adapter to physically connect to its communication ++ * peer. An operation on this adapter returned an error. ++ * User action: ++ * Check the status of the CTCM device, for example, with ifconfig. If the ++ * device is not operational, perform a manual recovery. See "Device Drivers, ++ * Features, and Commands" for details about how to recover a CTCM device. ++ */ ++ ++/*? ++ * Text: "%s: The communication peer has disconnected\n" ++ * Severity: Notice ++ * Parameter: ++ * @1: channel ID ++ * Description: ++ * The remote device has disconnected. Possible reasons are that the remote ++ * interface has been closed or that the operating system instance with the ++ * communication peer has been rebooted or shut down. ++ * User action: ++ * Check the status of the peer device. Ensure that the peer operating system ++ * instance is running and that the peer interface is operational. ++ */ ++ ++/*? ++ * Text: "%s: The remote operating system is not available\n" ++ * Severity: Notice ++ * Parameter: ++ * @1: channel ID ++ * Description: ++ * The operating system instance with the communication peer has disconnected. ++ * Possible reasons are that the operating system instance has been rebooted ++ * or shut down. ++ * User action: ++ * Ensure that the peer operating system instance is running and that the peer ++ * interface is operational. ++ */ ++ ++/*? ++ * Text: "%s: The adapter received a non-specific IRQ\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * Description: ++ * The adapter hardware used by the CTCM device received an IRQ that cannot ++ * be mapped to a particular device. This is a hardware problem. ++ * User action: ++ * Check the status of the CTCM device, for example, with ifconfig. Check if ++ * the connection to the remote device still works. If the CTCM device is not ++ * operational, set it offline and back online. If this does not resolve the ++ * problem, perform a manual recovery. See "Device Drivers, Features, and ++ * Commands" for details about how to recover a CTCM device. If this problem ++ * persists, gather Linux debug data, collect the hardware logs, and report the ++ * problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: A check occurred on the subchannel\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * Description: ++ * A check condition has been detected on the subchannel. ++ * User action: ++ * Check if the connection to the remote device still works. If the CTCM device ++ * is not operational, set it offline and back online. If this does not resolve ++ * the problem, perform a manual recovery. See "Device Drivers, Features, and ++ * Commands" for details about how to recover a CTCM device. If this problem ++ * persists, gather Linux debug data and report the problem to your support ++ * organization. ++ */ ++ ++/*? ++ * Text: "%s: The communication peer is busy\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: channel ID ++ * Description: ++ * A busy target device was reported. This might be a temporary problem. ++ * User action: ++ * If this problem persists or is reported frequently ensure that the target ++ * device is working properly. ++ */ ++ ++/*? ++ * Text: "%s: The specified target device is not valid\n" ++ * Severity: Error ++ * Parameter: ++ * @1: channel ID ++ * Description: ++ * A target device was called with a faulty device specification. This is an ++ * adapter hardware problem. ++ * User action: ++ * Gather Linux debug data, collect the hardware logs, and contact IBM support. ++ */ ++ ++/*? ++ * Text: "An I/O operation resulted in error %04x\n" ++ * Severity: Error ++ * Parameter: ++ * @1: channel ID ++ * @2: error information ++ * Description: ++ * A hardware operation ended with an error. ++ * User action: ++ * Check the status of the CTCM device, for example, with ifconfig. If the ++ * device is not operational, perform a manual recovery. See "Device Drivers, ++ * Features, and Commands" for details about how to recover a CTCM device. ++ * If this problem persists, gather Linux debug data, collect the hardware logs, ++ * and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Initialization failed with RX/TX init handshake error %s\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * @2: error information ++ * Description: ++ * A problem occurred during the initialization of the connection. If the ++ * connection can be established after an automatic recovery, a success message ++ * is issued. ++ * User action: ++ * If the problem is not resolved by the automatic recovery process, check the ++ * local and remote device. If this problem persists, gather Linux debug data ++ * and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The network backlog for %s is exceeded, package dropped\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * @2: calling function ++ * Description: ++ * There is more network traffic than can be handled by the device. The device ++ * is closed and some data has not been transmitted. The device might be ++ * recovered automatically. ++ * User action: ++ * Investigate and resolve the congestion. If necessary, set the device ++ * online to make it operational. ++ */ ++ ++/*? ++ * Text: "%s: The XID used in the MPC protocol is not valid, rc = %d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the CTCM device ++ * @2: return code ++ * Description: ++ * The exchange identification (XID) used by the CTCM device driver when ++ * in MPC mode is not valid. ++ * User action: ++ * Note the error information provided with this message and contact your ++ * support organization. ++ */ ++ ++/*? Text: "CTCM driver unloaded\n" */ ++/*? Text: "%s: %s Internal error: net_device is NULL, ch = 0x%p\n" */ ++/*? Text: "%s / register_cu3088_discipline failed, ret = %d\n" */ ++/*? Text: "%s: %s: Internal error: Can't determine channel for interrupt device %s\n" */ ++/*? Text: "CTCM driver initialized\n" */ ++/*? Text: "%s: setup OK : r/w = %s/%s, protocol : %d\n" */ ++/*? Text: "%s: Connected with remote side\n" */ ++/*? Text: "%s: Restarting device\n" */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/dcssblk +@@ -0,0 +1,162 @@ ++/*? ++ * Text: "Adjacent DCSSs %s and %s are not contiguous\n" ++ * Severity: Error ++ * Parameter: ++ * @1: name 1 ++ * @2: name 2 ++ * Description: ++ * You can only map a set of two or more DCSSs to a single DCSS device if the ++ * DCSSs in the set form a contiguous memory space. The DCSS device cannot be ++ * created because there is a memory gap between two adjacent DCSSs. ++ * User action: ++ * Ensure that you have specified all DCSSs that belong to the set. Check the ++ * definitions of the DCSSs on the z/VM hypervisor to verify that they form ++ * a contiguous memory space. ++ */ ++ ++/*? ++ * Text: "DCSS %s and DCSS %s have incompatible types\n" ++ * Severity: Error ++ * Parameter: ++ * @1: name 1 ++ * @2: name 2 ++ * Description: ++ * You can only map a set of two or more DCSSs to a single DCSS device if ++ * either all DCSSs in the set have the same type or if the set contains DCSSs ++ * of the two types EW and EN but no other type. The DCSS device cannot be ++ * created because at least two of the specified DCSSs are not compatible. ++ * User action: ++ * Check the definitions of the DCSSs on the z/VM hypervisor to verify that ++ * their types are compatible. ++ */ ++ ++/*? ++ * Text: "DCSS %s is of type SC and cannot be loaded as exclusive-writable\n" ++ * Severity: Error ++ * Parameter: ++ * @1: device name ++ * Description: ++ * You cannot load a DCSS device in exclusive-writable access mode if the DCSS ++ * devise maps to one or more DCSSs of type SC. ++ * User action: ++ * Load the DCSS in shared access mode. ++ */ ++ ++/*? ++ * Text: "DCSS device %s is removed after a failed access mode change\n" ++ * Severity: Error ++ * Parameter: ++ * @1: device name ++ * Description: ++ * To change the access mode of a DCSS device, all DCSSs that map to the device ++ * were unloaded. Reloading the DCSSs for the new access mode failed and the ++ * device is removed. ++ * User action: ++ * Look for related messages to find out why the DCSSs could not be reloaded. ++ * If necessary, add the device again. ++ */ ++ ++/*? ++ * Text: "All DCSSs that map to device %s are saved\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: device name ++ * Description: ++ * A save request has been submitted for the DCSS device. Changes to all DCSSs ++ * that map to the device are saved permanently. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Device %s is in use, its DCSSs will be saved when it becomes idle\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: device name ++ * Description: ++ * A save request for the device has been deferred until the device becomes ++ * idle. Then changes to all DCSSs that the device maps to will be saved ++ * permanently. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "A pending save request for device %s has been canceled\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: device name ++ * Description: ++ * A save request for the DCSSs that map to a DCSS device has been pending ++ * while the device was in use. This save request has been canceled. Changes to ++ * the DCSSs will not be saved permanently. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Loaded %s with total size %lu bytes and capacity %lu sectors\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: DCSS names ++ * @2: total size in bytes ++ * @3: total size in 512 byte sectors ++ * Description: ++ * The listed DCSSs have been verified as contiguous and successfully loaded. ++ * The displayed sizes are the sums of all DCSSs. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Device %s cannot be removed because it is not a known device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: device name ++ * Description: ++ * The DCSS device you are trying to remove is not known to the DCSS device ++ * driver. ++ * User action: ++ * List the entries under /sys/devices/dcssblk/ to see the names of the ++ * existing DCSS devices. ++ */ ++ ++/*? ++ * Text: "Device %s cannot be removed while it is in use\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: device name ++ * Description: ++ * You are trying to remove a device that is in use. ++ * User action: ++ * Make sure that all users of the device close the device before you try to ++ * remove it. ++ */ ++ ++/*? ++ * Text: "Device %s has become idle and is being saved now\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: device name ++ * Description: ++ * A save request for the DCSSs that map to a DCSS device has been pending ++ * while the device was in use. The device has become idle and all changes ++ * to the DCSSs are now saved permanently. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Writing to %s failed because it is a read-only device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: device name ++ * Description: ++ * The DCSS device is in shared access mode and cannot be written to. Depending ++ * on the type of the DCSSs that the device maps to, you might be able to ++ * change the access mode to exclusive-writable. ++ * User action: ++ * If the DCSSs of the device are of type SC, do not attempt to write to the ++ * device. If the DCSSs of the device are of type ER or SR, change the access ++ * mode to exclusive-writable before writing to the device. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/extmem +@@ -0,0 +1,290 @@ ++/*? ++ * Text: "Querying a DCSS type failed with rc=%ld\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: return code ++ * Description: ++ * The DCSS kernel interface used z/VM diagnose call X'64' to query the ++ * type of a DCSS. z/VM failed to determine the type and returned an error. ++ * User action: ++ * Look for related messages to find out which DCSS is affected. ++ * For details about the return codes see the section about DIAGNOSE Code ++ * X'64' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "Loading DCSS %s failed with rc=%ld\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: DCSS name ++ * @2: return code ++ * Description: ++ * The DCSS kernel interface used diagnose call X'64' to load a DCSS. z/VM ++ * failed to load the DCSS and returned an error. ++ * User action: ++ * For details about the return codes see the section about DIAGNOSE Code ++ * X'64' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "DCSS %s of range %p to %p and type %s loaded as exclusive-writable\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: DCSS name ++ * @2: starting page address ++ * @3: ending page address ++ * @4: DCSS type ++ * Description: ++ * The DCSS was loaded successfully in exclusive-writable access mode. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "DCSS %s of range %p to %p and type %s loaded in shared access mode\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: DCSS name ++ * @2: starting page address ++ * @3: ending page address ++ * @4: DCSS type ++ * Description: ++ * The DCSS was loaded successfully in shared access mode. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "DCSS %s is already in the requested access mode\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * A request to reload a DCSS with a new access mode has been rejected ++ * because the new access mode is the same as the current access mode. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "DCSS %s is in use and cannot be reloaded\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * Reloading a DCSS in a different access mode has failed because the DCSS is ++ * being used by one or more device drivers. The DCSS remains loaded with the ++ * current access mode. ++ * User action: ++ * Ensure that the DCSS is not used by any device driver then try again to ++ * load the DCSS with the new access mode. ++ */ ++ ++/*? ++ * Text: "DCSS %s overlaps with used memory resources and cannot be reloaded\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * The DCSS has been unloaded and cannot be reloaded because it overlaps with ++ * another loaded DCSS or with the memory of the z/VM guest virtual machine ++ * (guest storage). ++ * User action: ++ * Ensure that no DCSS is loaded that has overlapping memory resources ++ * with the DCSS you want to reload. If the DCSS overlaps with guest storage, ++ * use the DEF STORE CONFIG z/VM CP command to create a sufficient storage gap ++ * for the DCSS. For details, see the section about the DCSS device driver in ++ * "Device Drivers, Features, and Commands". ++ */ ++ ++/*? ++ * Text: "Reloading DCSS %s failed with rc=%ld\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: DCSS name ++ * @2: return code ++ * Description: ++ * The DCSS kernel interface used z/VM diagnose call X'64' to reload a DCSS ++ * in a different access mode. The DCSS was unloaded but z/VM failed to reload ++ * the DCSS. ++ * User action: ++ * For details about the return codes see the section about DIAGNOSE Code ++ * X'64' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "Unloading unknown DCSS %s failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * The specified DCSS cannot be unloaded. The DCSS is known to the DCSS device ++ * driver but not to the DCSS kernel interface. This problem indicates a ++ * program error in extmem.c. ++ * User action: ++ * Report this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "Saving unknown DCSS %s failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * The specified DCSS cannot be saved. The DCSS is known to the DCSS device ++ * driver but not to the DCSS kernel interface. This problem indicates a ++ * program error in extmem.c. ++ * User action: ++ * Report this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "Saving a DCSS failed with DEFSEG response code %i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: response-code ++ * Description: ++ * The DEFSEG z/VM CP command failed to permanently save changes to a DCSS. ++ * User action: ++ * Look for related messages to find the cause of this error. See also message ++ * HCPE in the DEFSEG section of the "z/VM CP Command and ++ * Utility Reference". ++ */ ++ ++/*? ++ * Text: "Saving a DCSS failed with SAVESEG response code %i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: response-code ++ * Description: ++ * The SAVESEG z/VM CP command failed to permanently save changes to a DCSS. ++ * User action: ++ * Look for related messages to find the cause of this error. See also message ++ * HCPE in the SAVESEG section of the "z/VM CP Command and ++ * Utility Reference". ++ */ ++ ++/*? ++ * Text: "DCSS %s cannot be loaded or queried\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * You cannot load or query the specified DCSS because it either is not defined ++ * in the z/VM hypervisor, or it is a class S DCSS, or it is above 2047 MB ++ * and he Linux system is a 31-bit system. ++ * User action: ++ * Use the CP command "QUERY NSS" to find out if the DCSS is a valid ++ * DCSS that can be loaded. ++ */ ++ ++/*? ++ * Text: "DCSS %s cannot be loaded or queried without z/VM\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * A DCSS is a z/VM resource. Your Linux instance is not running as a z/VM ++ * guest operating system and, therefore, cannot load DCSSs. ++ * User action: ++ * Load DCSSs only on Linux instances that run as z/VM guest operating systems. ++ */ ++ ++/*? ++ * Text: "Loading or querying DCSS %s resulted in a hardware error\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * Either the z/VM DIAGNOSE X'64' query or load call issued for the DCSS ++ * returned with an error. ++ * User action: ++ * Look for previous extmem message to find the return code from the ++ * DIAGNOSE X'64' query or load call. For details about the return codes see ++ * the section about DIAGNOSE Code X'64' in "z/VM CP Programming Services". ++ */ ++ ++/*? ++ * Text: "DCSS %s has multiple page ranges and cannot be loaded or queried\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * You can only load or query a DCSS with multiple page ranges if: ++ * - The DCSS has 6 or fewer page ranges ++ * - The page ranges form a contiguous address space ++ * - The page ranges are of type EW or EN ++ * User action: ++ * Check the definition of the DCSS to make sure that the conditions for ++ * DCSSs with multiple page ranges are met. ++ */ ++ ++/*? ++ * Text: "%s needs used memory resources and cannot be loaded or queried\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * You cannot load or query the DCSS because it overlaps with an already ++ * loaded DCSS or with the memory of the z/VM guest virtual machine ++ * (guest storage). ++ * User action: ++ * Ensure that no DCSS is loaded that has overlapping memory resources ++ * with the DCSS you want to load or query. If the DCSS overlaps with guest ++ * storage, use the DEF STORE CONFIG z/VM CP command to create a sufficient ++ * storage gap for the DCSS. For details, see the section about the DCSS ++ * device driver in "Device Drivers, Features, and Commands". ++ */ ++ ++/*? ++ * Text: "DCSS %s is already loaded in a different access mode\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * The DCSS you are trying to load has already been loaded in a different ++ * access mode. You cannot simultaneously load the DCSS in different modes. ++ * User action: ++ * Reload the DCSS in a different mode or load it with the same mode in which ++ * it has already been loaded. ++ */ ++ ++/*? ++ * Text: "There is not enough memory to load or query DCSS %s\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * The available memory is not enough to load or query the DCSS. ++ * User action: ++ * Free some memory and repeat the failed operation. ++ */ ++ ++/*? ++ * Text: "DCSS %s overlaps with used storage and cannot be loaded\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * You cannot load the DCSS because it overlaps with an already loaded DCSS ++ * or with the memory of the z/VM guest virtual machine (guest storage). ++ * User action: ++ * Ensure that no DCSS is loaded that has overlapping memory resources ++ * with the DCSS you want to load. If the DCSS overlaps with guest storage, ++ * use the DEF STORE CONFIG z/VM CP command to create a sufficient storage gap ++ * for the DCSS. For details, see the section about the DCSS device driver in ++ * "Device Drivers, Features, and Commands". ++ */ ++ ++/*? ++ * Text: "DCSS %s exceeds the kernel mapping range (%lu) and cannot be loaded\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * @2: kernel mapping range in bytes ++ * Description: ++ * You cannot load the DCSS because it exceeds the kernel mapping range limit. ++ * User action: ++ * Ensure that the DCSS range is defined below the kernel mapping range. ++ */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/hypfs +@@ -0,0 +1,56 @@ ++/*? ++ * Text: "The hardware system does not support hypfs\n" ++ * Severity: Error ++ * Description: ++ * hypfs requires DIAGNOSE Code X'204' but this diagnose code is not available ++ * on your hardware. You need more recent hardware to use hypfs. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "The hardware system does not provide all functions required by hypfs\n" ++ * Severity: Error ++ * Description: ++ * hypfs requires DIAGNOSE Code X'224' but this diagnode code is not available ++ * on your hardware. You need more recent hardware to use hypfs. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Updating the hypfs tree failed\n" ++ * Severity: Error ++ * Description: ++ * There was not enough memory available to update the hypfs tree. ++ * User action: ++ * Free some memory and try again to update the hypfs tree. Consider assigning ++ * more memory to your LPAR or z/VM guest virtual machine. ++ */ ++ ++/*? ++ * Text: "%s is not a valid mount option\n" ++ * Severity: Error ++ * Parameter: ++ * @1: mount option ++ * Description: ++ * hypfs has detected mount options that are not valid. ++ * User action: ++ * See "Device Drivers Features and Commands" for information about valid ++ * mount options for hypfs. ++ */ ++ ++/*? ++ * Text: "Initialization of hypfs failed with rc=%i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: error code ++ * Description: ++ * Initialization of hypfs failed because of resource or hardware constraints. ++ * Possible reasons for this problem are insufficient free memory or missing ++ * hardware interfaces. ++ * User action: ++ * See errno.h for information about the error codes. ++ */ ++ ++/*? Text: "Hypervisor filesystem mounted\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/iucv +@@ -0,0 +1,20 @@ ++/*? ++ * Text: "Defining an interrupt buffer on CPU %i failed with 0x%02x (%s)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: CPU number ++ * @2: hexadecimal error value ++ * @3: short error code explanation ++ * Description: ++ * Defining an interrupt buffer for external interrupts failed. Error ++ * value 0x03 indicates a problem with the z/VM directory entry of the ++ * z/VM guest virtual machine. This problem can also be caused by a ++ * program error. ++ * User action: ++ * If the error value is 0x03, examine the z/VM directory entry of your ++ * z/VM guest virtual machine. If the directory entry is correct or if the ++ * error value is not 0x03, report this problem to your support organization. ++ */ ++ ++/*? Text: "iucv_external_interrupt: out of memory\n" */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/lcs +@@ -0,0 +1,160 @@ ++/*? ++ * Text: "%s: Allocating a socket buffer to interface %s failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * @2: network interface ++ * Description: ++ * LAN channel station (LCS) devices require a socket buffer (SKB) structure ++ * for storing incoming data. The LCS device driver failed to allocate an SKB ++ * structure to the LCS device. A likely cause of this problem is memory ++ * constraints. ++ * User action: ++ * Free some memory and repeat the failed operation. ++ */ ++ ++/*? ++ * Text: "%s: Shutting down the LCS device failed\n " ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * Description: ++ * A request to shut down a LAN channel station (LCS) device resulted in an ++ * error. The error is logged in the LCS trace at trace level 4. ++ * User action: ++ * Try again to shut down the device. If the error persists, see the LCS trace ++ * to find out what causes the error. ++ */ ++ ++/*? ++ * Text: "%s: Detecting a network adapter for LCS devices failed with rc=%d (0x%x)\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: lcs_detect return code in decimal notation ++ * @2: lcs_detect return code in hexadecimal notation ++ * Description: ++ * The LCS device driver could not initialize a network adapter. ++ * User action: ++ * Note the return codes from the error message and contact IBM support. ++ */ ++ ++/*? ++ * Text: "%s: A recovery process has been started for the LCS device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * Description: ++ * The LAN channel station (LCS) device is shut down and restarted. The recovery ++ * process might have been initiated by a user or started automatically as a ++ * response to a device problem. ++ * User action: ++ * Wait until a message indicates the completion of the recovery process. ++ */ ++ ++/*? ++ * Text: "%s: An I/O-error occurred on the LCS device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * Description: ++ * The LAN channel station (LCS) device reported a problem that can be recovered ++ * by the LCS device driver. Repeated occurrences of this problem indicate a ++ * malfunctioning device. ++ * User action: ++ * If this problem occurs frequently, initiate a recovery process for the ++ * device, for example, by writing '1' to the 'recover' sysfs attribute of the ++ * device. ++ */ ++ ++/*? ++ * Text: "%s: A command timed out on the LCS device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * Description: ++ * The LAN channel station (LCS) device reported a problem that can be recovered ++ * by the LCS device driver. Repeated occurrences of this problem indicate a ++ * malfunctioning device. ++ * User action: ++ * If this problem occurs frequently, initiate a recovery process for the ++ * device, for example, by writing '1' to the 'recover' sysfs attribute of the ++ * device. ++ */ ++ ++/*? ++ * Text: "%s: An error occurred on the LCS device, rc=%ld\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * @2: return code ++ * Description: ++ * The LAN channel station (LCS) device reported a problem that can be recovered ++ * by the LCS device driver. Repeated occurrences of this problem indicate a ++ * malfunctioning device. ++ * User action: ++ * If this problem occurs frequently, initiate a recovery process for the ++ * device, for example, by writing '1' to the 'recover' sysfs attribute of the ++ * device. ++ */ ++ ++/*? ++ * Text: "%s: The LCS device stopped because of an error, dstat=0x%X, cstat=0x%X \n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * @2: device status ++ * @3: subchannel status ++ * Description: ++ * The LAN channel station (LCS) device reported an error. The LCS device driver ++ * might start a device recovery process. ++ * User action: ++ * If the device driver does not start a recovery process, initiate a recovery ++ * process, for example, by writing '1' to the 'recover' sysfs attribute of the ++ * device. If the problem persists, note the status information provided with ++ * the message and contact IBM support. ++ */ ++ ++/*? ++ * Text: "%s: Starting an LCS device resulted in an error, rc=%d!\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * @2: ccw_device_start return code in decimal notation ++ * Description: ++ * The LAN channel station (LCS) device driver failed to initialize an LCS ++ * device. The device is not operational. ++ * User action: ++ * Initiate a recovery process, for example, by writing '1' to the 'recover' ++ * sysfs attribute of the device. If the problem persists, contact IBM support. ++ */ ++ ++/*? ++ * Text: "%s: Sending data from the LCS device to the LAN failed with rc=%d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the LCS device ++ * @2: ccw_device_resume return code in decimal notation ++ * Description: ++ * The LAN channel station (LCS) device driver could not send data to the LAN ++ * using the LCS device. This might be a temporary problem. Operations continue ++ * on the LCS device. ++ * User action: ++ * If this problem occurs frequently, initiate a recovery process, for example, ++ * by writing '1' to the 'recover' sysfs attribute of the device. If the ++ * problem persists, contact IBM support. ++ */ ++ ++/*? Text: "Query IPAssist failed. Assuming unsupported!\n" */ ++/*? Text: "Stoplan for %s initiated by LGW.\n" */ ++/*? Text: "Not enough memory to add new multicast entry!\n" */ ++/*? Text: "Not enough memory for debug facility.\n" */ ++/*? Text: "Adding multicast address failed. Table possibly full!\n" */ ++/*? Text: "Error in opening device!\n" */ ++/*? Text: "LCS device %s %s IPv6 support\n" */ ++/*? Text: "Device %s successfully recovered!\n" */ ++/*? Text: "LCS device %s %s Multicast support\n" */ ++/*? Text: " Initialization failed\n" */ ++/*? Text: "Loading %s\n" */ ++/*? Text: "Initialization failed\n" */ ++/*? Text: "Terminating lcs module.\n" */ ++/*? Text: "Device %s could not be recovered!\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/monreader +@@ -0,0 +1,127 @@ ++/*? ++ * Text: "Reading monitor data failed with rc=%i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: return code ++ * Description: ++ * The z/VM *MONITOR record device driver failed to read monitor data ++ * because the IUCV REPLY function failed. The read function against ++ * the monitor record device returns EIO. All monitor data that has been read ++ * since the last read with 0 size is incorrect. ++ * User action: ++ * Disregard all monitor data that has been read since the last read with ++ * 0 size. If the device driver has been compiled as a separate module, unload ++ * and reload the monreader module. If the device driver has been compiled ++ * into the kernel, reboot Linux. For more information about possible causes ++ * of the error see the IUCV section in "z/VM CP Programming Services" and ++ * the *MONITOR section in "z/VM Performance". ++ */ ++ ++/*? ++ * Text: "z/VM *MONITOR system service disconnected with rc=%i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: IPUSER SEVER return code ++ * Description: ++ * The z/VM *MONITOR record device driver receives monitor records through ++ * an IUCV connection to the z/VM *MONITOR system service. This connection ++ * has been severed and the read function of the z/VM *MONITOR device driver ++ * returns EIO. All data received since the last read with 0 size is incorrect. ++ * User action: ++ * Disregard all monitor data read since the last read with 0 size. Close and ++ * reopen the monitor record device. For information about the IPUSER SEVER ++ * return codes see "z/VM Performance". ++ */ ++ ++/*? ++ * Text: "The read queue for monitor data is full\n" ++ * Severity: Warning ++ * Description: ++ * The read function of the z/VM *MONITOR device driver returns EOVERFLOW ++ * because not enough monitor data has been read since the monitor device ++ * has been opened. Monitor data already read are valid and subsequent reads ++ * return valid data but some intermediate data might be missing. ++ * User action: ++ * Be aware that monitor data might be missing. Assure that you regularly ++ * read monitor data after opening the monitor record device. ++ */ ++ ++/*? ++ * Text: "Connecting to the z/VM *MONITOR system service failed with rc=%i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: IUCV CONNECT return code ++ * Description: ++ * The z/VM *MONITOR record device driver receives monitor records through ++ * an IUCV connection to the z/VM *MONITOR system service. This connection ++ * could not be established when the monitor record device was opened. If ++ * the return code is 15, your z/VM guest virtual machine is not authorized ++ * to connect to the *MONITOR system service. ++ * User action: ++ * If the return code is 15, ensure that the IUCV *MONITOR statement is ++ * included in the z/VM directory entry for your z/VM guest virtual machine. ++ * For other IUCV CONNECT return codes see the IUCV section in "CP Programming ++ * Services" and the *MONITOR section in "z/VM Performance". ++ */ ++ ++/*? ++ * Text: "Disconnecting the z/VM *MONITOR system service failed with rc=%i\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: IUCV SEVER return code ++ * Description: ++ * The z/VM *MONITOR record device driver receives monitor data through an ++ * IUCV connection to the z/VM *MONITOR system service. This connection ++ * could not be closed when the monitor record device was closed. You might ++ * not be able to resume monitoring. ++ * User action: ++ * No immediate action is necessary. If you cannot open the monitor record ++ * device in the future, reboot Linux. For information about the IUCV SEVER ++ * return codes see the IUCV section in "CP Programming Services" and the ++ * *MONITOR section in "z/VM Performance". ++ */ ++ ++/*? ++ * Text: "The z/VM *MONITOR record device driver cannot be loaded without z/VM\n" ++ * Severity: Error ++ * Description: ++ * The z/VM *MONITOR record device driver uses z/VM system services to provide ++ * monitor data about z/VM guest operating systems to applications on Linux. ++ * On Linux instances that run in environments other than the z/VM hypervisor, ++ * the z/VM *MONITOR record device driver does not provide any useful ++ * function and the corresponding monreader module cannot be loaded. ++ * User action: ++ * Load the z/VM *MONITOR record device driver only on Linux instances that run ++ * as guest operating systems of the z/VM hypervisor. If the z/VM *MONITOR ++ * record device driver has been compiled into the kernel, ignore this message. ++ */ ++ ++/*? ++ * Text: "The z/VM *MONITOR record device driver failed to register with IUCV\n" ++ * Severity: Error ++ * Description: ++ * The z/VM *MONITOR record device driver receives monitor data through an IUCV ++ * connection and needs to register with the IUCV device driver. This ++ * registration failed and the z/VM *MONITOR record device driver was not ++ * loaded. A possible cause of this problem is insufficient memory. ++ * User action: ++ * Free some memory and try again to load the module. If the z/VM *MONITOR ++ * record device driver has been compiled into the kernel, you might have to ++ * configure more memory and reboot Linux. If you do not want to read monitor ++ * data, ignore this message. ++ */ ++ ++/*? ++ * Text: "The specified *MONITOR DCSS %s does not have the required type SC\n" ++ * Severity: Error ++ * Parameter: ++ * @1: DCSS name ++ * Description: ++ * The DCSS that was specified with the monreader.mondcss kernel parameter or ++ * with the mondcss module parameter cannot be a *MONITOR DCSS because it is ++ * not of type SC. ++ * User action: ++ * Confirm that you are using the name of the DCSS that has been configured as ++ * the *MONITOR DCSS on the z/VM hypervisor. If the default name, MONDCSS, is ++ * used, omit the monreader.mondcss or mondcss parameter. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/monwriter +@@ -0,0 +1,16 @@ ++/*? ++ * Text: "Writing monitor data failed with rc=%i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: return code ++ * Description: ++ * The monitor stream application device driver used the z/VM diagnose call ++ * DIAG X'DC' to start writing monitor data. z/VM returned an error and the ++ * monitor data cannot be written. If the return code is 5, your z/VM guest ++ * virtual machine is not authorized to write monitor data. ++ * User action: ++ * If the return code is 5, ensure that your z/VM guest virtual machine's ++ * entry in the z/VM directory includes the OPTION APPLMON statement. ++ * For other return codes see the section about DIAGNOSE Code X'DC' ++ * in "z/VM CP Programming Services". ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/netiucv +@@ -0,0 +1,139 @@ ++/*? ++ * Text: "%s: The peer interface of the IUCV device has closed the connection\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * Description: ++ * The peer interface on the remote z/VM guest virtual machine has closed the ++ * connection. Do not expect further packets on this interface. Any packets ++ * you send to this interface will be dropped. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "%s: The IUCV device failed to connect to z/VM guest %s\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: z/VM user ID ++ * Description: ++ * The connection cannot be established because the z/VM guest virtual ++ * machine with the peer interface is not running. ++ * User action: ++ * Ensure that the z/VM guest virtual machine with the peer interface is ++ * running; then try again to establish the connection. ++ */ ++ ++/*? ++ * Text: "%s: The IUCV device failed to connect to the peer on z/VM guest %s\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: z/VM user ID ++ * Description: ++ * The connection cannot be established because the z/VM guest virtual machine ++ * with the peer interface is not configured for IUCV connections. ++ * User action: ++ * Configure the z/VM guest virtual machine with the peer interface for IUCV ++ * connections; then try again to establish the connection. ++ */ ++ ++/*? ++ * Text: "%s: Connecting the IUCV device would exceed the maximum number of IUCV connections\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * Description: ++ * The connection cannot be established because the maximum number of IUCV ++ * connections has been reached on the local z/VM guest virtual machine. ++ * User action: ++ * Close some of the established IUCV connections on the local z/VM guest ++ * virtual machine; then try again to establish the connection. ++ */ ++ ++/*? ++ * Text: "%s: z/VM guest %s has too many IUCV connections to connect with the IUCV device\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: remote z/VM user ID ++ * Description: ++ * Connecting to the remote z/VM guest virtual machine failed because the ++ * maximum number of IUCV connections for the remote z/VM guest virtual ++ * machine has been reached. ++ * User action: ++ * Close some of the established IUCV connections on the remote z/VM guest ++ * virtual machine; then try again to establish the connection. ++ */ ++ ++/*? ++ * Text: "%s: The IUCV device cannot connect to a z/VM guest with no IUCV authorization\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * Description: ++ * Because the remote z/VM guest virtual machine is not authorized for IUCV ++ * connections, the connection cannot be established. ++ * User action: ++ * Add the statements 'IUCV ALLOW' and 'IUCV ANY' to the z/VM directory ++ * entry of the remote z/VM guest virtual machine; then try again to ++ * establish the connection. See "z/VM CP Planning and Administration" ++ * for details about the IUCV statements. ++ */ ++ ++/*? ++ * Text: "%s: Connecting the IUCV device failed with error %d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: error code ++ * Description: ++ * The connection cannot be established because of an IUCV CONNECT error. ++ * User action: ++ * Report this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The IUCV device has been connected successfully to %s\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: remote z/VM user ID ++ * Description: ++ * The connection has been established and the interface is ready to ++ * transmit communication packages. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "%s: The IUCV interface to %s has been established successfully\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: remote z/VM user ID ++ * Description: ++ * The IUCV interface to the remote z/VM guest virtual machine has been ++ * established and can be activated with "ifconfig up" or an equivalent ++ * command. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "%s: The IUCV device is connected to %s and cannot be removed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the IUCV device ++ * @2: remote z/VM user ID ++ * Description: ++ * Removing a connection failed because the interface is active with a peer ++ * interface on a remote z/VM guest virtual machine. ++ * User action: ++ * Deactivate the interface with "ifconfig down" or an equivalent command; ++ * then try again to remove the interface. ++ */ ++ ++/*? Text: "driver unloaded\n" */ ++/*? Text: "driver initialized\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/qeth +@@ -0,0 +1,472 @@ ++/*? ++ * Text: "%s: The LAN is offline\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * A start LAN command was sent by the qeth device driver but the physical or ++ * virtual adapter has not started the LAN. The LAN might take a few seconds ++ * to become available. ++ * User action: ++ * Check the status of the qeth device, for example, with the lsqeth command. ++ * If the device does not become operational within a few seconds, initiate a ++ * recovery process, for example, by writing '1' to the 'recover' sysfs ++ * attribute of the device. ++ */ ++ ++/*? ++ * Text: "%s: The user canceled setting the qeth device offline\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * A user initiated setting the device offline but subsequently canceled the ++ * operation, for example, with CTRL+C. ++ * User action: ++ * Check the status of the qeth device, for example, with the lsqeth command. ++ * If necessary, repeat the operation to set the device offline. ++ */ ++ ++/*? ++ * Text: "%s: A recovery process has been started for the device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * A recovery process was started either by the qeth device driver or through ++ * a user command. ++ * User action: ++ * Wait until a message indicates the completion of the recovery process. ++ */ ++ ++/*? ++ * Text: "%s: The qeth device driver failed to recover an error on the device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * The qeth device driver performed an automatic recovery operation to recover ++ * an error on a qeth device. The recovery operation failed. ++ * User action: ++ * Try the following actions in the given order: i) Check the status of the ++ * qeth device, for example, with the lsqeth command. ii) Initiate a recovery ++ * process by writing '1' to the 'recover' sysfs attribute of the device. ++ * iii) Ungroup and regroup the subchannel triplet of the device. vi) Reboot ++ * Linux. v) If the problem persists, gather Linux debug data and report the ++ * problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The link for interface %s on CHPID 0x%X failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * @3: CHPID ++ * Description: ++ * A network link failed. A possible reason for this error is that a physical ++ * network cable has been disconnected. ++ * User action: ++ * Ensure that the network cable on the adapter hardware is connected properly. ++ * If the connection is to a guest LAN, ensure that the device is still coupled ++ * to the guest LAN. ++ */ ++ ++/*? ++ * Text: "%s: The link for %s on CHPID 0x%X has been restored\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * @3: CHPID ++ * Description: ++ * A failed network link has been re-established. A device recovery is in ++ * progress. ++ * User action: ++ * Wait until a message indicates the completion of the recovery process. ++ */ ++ ++/*? ++ * Text: "%s: A hardware operation timed out on the device\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * A hardware operation timed out on the qeth device. ++ * User action: ++ * Check the status of the qeth device, for example, with the lsqeth command. ++ * If the device is not operational, initiate a recovery process, for example, ++ * by writing '1' to the 'recover' sysfs attribute of the device. ++ */ ++ ++/*? ++ * Text: "%s: The adapter hardware is of an unknown type\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * The qeth device driver does not recognize the adapter hardware. The cause ++ * of this problem could be a hardware error or a Linux level that does not ++ * support your adapter hardware. ++ * User action: ++ * i) Investigate if your adapter hardware is supported by your Linux level. ++ * Consider using hardware that is supported by your Linux level or upgrading ++ * to a Linux level that supports your hardware. ii) Install the latest ++ * firmware on your adapter hardware. iii) If the problem persists and is not ++ * caused by a version mismatch, contact IBM support. ++ */ ++ ++/*? ++ * Text: "%s: The adapter is used exclusively by another host\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * The qeth adapter is exclusively used by another host. ++ * User action: ++ * Use another qeth adapter or configure this one not exclusively to a ++ * particular host. ++ */ ++ ++/*? ++ * Text: "%s: QDIO reported an error, rc=%i\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: return code ++ * Description: ++ * The QDIO subsystem reported an error. ++ * User action: ++ * Check for related QDIO errors. Check the status of the qeth device, for ++ * example, with the lsqeth command. If the device is not operational, initiate ++ * a recovery process, for example, by writing '1' to the 'recover' sysfs ++ * attribute of the device. ++ */ ++ ++/*? ++ * Text: "%s: There is no kernel module to support discipline %d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: discipline ++ * Description: ++ * The qeth device driver or a user command requested a kernel module for a ++ * particular qeth discipline. Either the discipline is not supported by the ++ * qeth device driver or the requested module is not available to your Linux ++ * system. ++ * User action: ++ * Check if the requested discipline module has been compiled into the kernel ++ * or is present in /lib/modules//kernel/drivers/s390/net. ++ */ ++ ++/*? ++ * Text: "Initializing the qeth device driver failed\n" ++ * Severity: Error ++ * Parameter: ++ * Description: ++ * The base module of the qeth device driver could not be initialized. ++ * User action: ++ * See errno.h to determine the reason for the error. ++ * i) Reboot Linux. ii) If the problem persists, gather Linux debug data and ++ * report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Registering IP address %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: IP address ++ * Description: ++ * An IP address could not be registered with the network adapter. ++ * User action: ++ * Check if another operating system instance has already registered the ++ * IP address with the same network adapter or at the same logical IP subnet. ++ */ ++ ++/*? ++ * Text: "%s: Reading the adapter MAC address failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * The qeth device driver could not read the MAC address from the network ++ * adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting ARP processing support for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not start ARP support on the network adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting IP fragmentation support for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not start IP fragmentation support on the ++ * network adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting proxy ARP support for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not start proxy ARP support on the network ++ * adapter. ++ * User action: ++ * None if you do not require proxy ARP support. If you need proxy ARP, ++ * ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting VLAN support for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not start VLAN support on the network adapter. ++ * User action: ++ * None if you do not require VLAN support. If you need VLAN support, ++ * ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting multicast support for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not start multicast support on the network ++ * adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Activating IPv6 support for %s failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not activate IPv6 support on the network ++ * adapter. ++ * User action: ++ * None if you do not require IPv6 communication. If you need IPv6 support, ++ * ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Enabling the passthrough mode for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not enable the passthrough mode on the ++ * network adapter. The passthrough mode is required for all network traffic ++ * other than IPv4. In particular, the passthrough mode is required for IPv6 ++ * traffic. ++ * User action: ++ * None if all you want to support is IPv4 communication. If you want to support ++ * IPv6 or other network traffic apart from IPv4, ungroup and regroup the ++ * subchannel triplet of the device. If this does not resolve the problem, ++ * reboot Linux. If the problem persists, gather Linux debug data and report ++ * the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Enabling broadcast filtering for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not enable broadcast filtering on the network ++ * adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Setting up broadcast filtering for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not set up broadcast filtering on the network ++ * adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Setting up broadcast echo filtering for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not set up broadcast echo filtering on the ++ * network adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting HW checksumming for %s failed, using SW checksumming\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The network adapter supports hardware checksumming for incoming IP packages ++ * but the qeth device driver could not start hardware checksumming on the ++ * adapter. The qeth device driver continues to use software checksumming for ++ * incoming IP packages. ++ * User action: ++ * None if you do not require hardware checksumming for incoming network ++ * traffic. If you want to enable hardware checksumming, ungroup and regroup ++ * the subchannel triplet of the device. If this does not resolve the problem, ++ * reboot Linux. If the problem persists, gather Linux debug data and report ++ * the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Enabling HW checksumming for %s failed, using SW checksumming\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The network adapter supports hardware checksumming for incoming IP packages ++ * but the qeth device driver could not enable hardware checksumming on the ++ * adapter. The qeth device driver continues to use software checksumming for ++ * incoming IP packages. ++ * User action: ++ * None if you do not require hardware checksumming for incoming network ++ * traffic. If you want to enable hardware checksumming, ungroup and regroup ++ * the subchannel triplet of the device. If this does not resolve the problem, ++ * reboot Linux. If the problem persists, gather Linux debug data and report ++ * the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Starting outbound TCP segmentation offload for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The network adapter supports TCP segmentation offload, but the qeth device ++ * driver could not start this support on the adapter. ++ * User action: ++ * None if you do not require TCP segmentation offload. If you want to ++ * enable TCP segmentation offload, ungroup and regroup the subchannel triplet ++ * of the device. If this does not resolve the problem, reboot Linux. If the ++ * problem persists, gather Linux debug data and report the problem to your ++ * support organization. ++ */ ++ ++/*? ++ * Text: "%s: The network adapter failed to generate a unique ID\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * Description: ++ * In IBM mainframe environments, network interfaces are not identified by ++ * a specific MAC address. Therefore, the network adapters provide the network ++ * interfaces with unique IDs to be used in their IPv6 link local addresses. ++ * Without such a unique ID, duplicate addresses might be assigned in other ++ * LPARs. ++ * User action: ++ * Install the latest firmware on the adapter hardware. Manually, configure ++ * an IPv6 link local address for this device. ++ */ ++ ++/*? ++ * Text: "There is no IPv6 support for the layer 3 discipline\n" ++ * Severity: Warning ++ * Description: ++ * If you want to use IPv6 with the layer 3 discipline, you need a Linux kernel ++ * with IPv6 support. Because your Linux kernel has not been compiled with ++ * IPv6 support, you cannot use IPv6 with the layer 3 discipline, even if your ++ * adapter supports IPv6. ++ * User action: ++ * Use a Linux kernel that has been complied to include IPv6 support if you ++ * want to use IPv6 with layer 3 qeth devices. ++ */ ++ ++/*? Text: "core functions removed\n" */ ++/*? Text: "%s: Device is a%s card%s%s%s\nwith link type %s.\n" */ ++/*? Text: "%s: Device is a%s card%s%s%s\nwith link type %s (no portname needed by interface).\n" */ ++/*? Text: "%s: Device is a%s card%s%s%s\nwith link type %s (portname: %s)\n" */ ++/*? Text: "%s: issue_next_read failed: no iob available!\n" */ ++/*? Text: "%s: Priority Queueing not supported\n" */ ++/*? Text: "%s: sense data available. cstat 0x%X dstat 0x%X\n" */ ++/*? Text: "loading core functions\n" */ ++/*? Text: "%s: MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x successfully registered on device %s\n" */ ++/*? Text: "%s: Device successfully recovered!\n" */ ++/*? Text: "register layer 2 discipline\n" */ ++/*? Text: "unregister layer 2 discipline\n" */ ++/*? Text: "%s: Hardware IP fragmentation not supported on %s\n" */ ++/*? Text: "%s: IPv6 not supported on %s\n" */ ++/*? Text: "%s: VLAN not supported on %s\n" */ ++/*? Text: "%s: Inbound source address not supported on %s\n" */ ++/*? Text: "%s: IPV6 enabled\n" */ ++/*? Text: "%s: ARP processing not supported on %s!\n" */ ++/*? Text: "%s: Hardware IP fragmentation enabled \n" */ ++/*? Text: "%s: set adapter parameters not supported.\n" */ ++/*? Text: "%s: VLAN enabled\n" */ ++/*? Text: "register layer 3 discipline\n" */ ++/*? Text: "%s: Outbound TSO enabled\n" */ ++/*? Text: "%s: Broadcast not supported on %s\n" */ ++/*? Text: "%s: Outbound TSO not supported on %s\n" */ ++/*? Text: "%s: Inbound HW Checksumming not supported on %s,\ncontinuing using Inbound SW Checksumming\n" */ ++/*? Text: "%s: Using no checksumming on %s.\n" */ ++/*? Text: "%s: Broadcast enabled\n" */ ++/*? Text: "%s: Multicast not supported on %s\n" */ ++/*? Text: "%s: Using SW checksumming on %s.\n" */ ++/*? Text: "%s: HW Checksumming (inbound) enabled\n" */ ++/*? Text: "unregister layer 3 discipline\n" */ ++/*? Text: "%s: Multicast enabled\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/s390dbf +@@ -0,0 +1,83 @@ ++/*? ++ * Text: "Root becomes the owner of all s390dbf files in sysfs\n" ++ * Severity: Warning ++ * Description: ++ * The S/390 debug feature you are using only supports uid/gid = 0. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Registering debug feature %s failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: feature name ++ * Description: ++ * The initialization of an S/390 debug feature failed. A likely cause of this ++ * problem is memory constraints. The system keeps running, but the debug ++ * data for this feature will not be available in sysfs. ++ * User action: ++ * Consider assigning more memory to your LPAR or z/VM guest virtual machine. ++ */ ++ ++/*? ++ * Text: "Registering view %s/%s would exceed the maximum number of views %i\n" ++ * Severity: Error ++ * Parameter: ++ * @1: feature name ++ * @2: view name ++ * @3: maximum ++ * Description: ++ * The maximum number of allowed debug feature views has been reached. The ++ * view has not been registered. The system keeps running but the new view ++ * will not be available in sysfs. This is a program error. ++ * User action: ++ * Report this problem to your support partner. ++ */ ++ ++/*? ++ * Text: "%s is not a valid level for a debug feature\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: level ++ * Description: ++ * Setting a new level for a debug feature by using the 'level' sysfs attribute ++ * failed. Valid levels are the minus sign (-) and the integers in the ++ * range 0 to 6. The minus sign switches off the feature. The numbers switch ++ * the feature on, where higher numbers produce more debug output. ++ * User action: ++ * Write a valid value to the 'level' sysfs attribute. ++ */ ++ ++/*? ++ * Text: "Flushing debug data failed because %c is not a valid area\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: debug area number ++ * Description: ++ * Flushing a debug area by using the 'flush' sysfs attribute failed. Valid ++ * values are the minus sign (-) for flushing all areas, or the number of the ++ * respective area for flushing a single area. ++ * User action: ++ * Write a valid area number or the minus sign (-) to the 'flush' sysfs ++ * attribute. ++ */ ++ ++/*? ++ * Text: "Allocating memory for %i pages failed\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: number of pages ++ * Description: ++ * Setting the debug feature size by using the 'page' sysfs attribute failed. ++ * Linux did not have enough memory for expanding the debug feature to the ++ * requested size. ++ * User action: ++ * Use a smaller number of pages for the debug feature or allocate more ++ * memory to your LPAR or z/VM guest virtual machine. ++ */ ++ ++/*? Text: "%s: set new size (%i pages)\n" */ ++/*? Text: "%s: switched off\n" */ ++/*? Text: "%s: level %i is out of range (%i - %i)\n" */ ++/*? Text: "Registering view %s/%s failed due to out of memory\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/sclp_cmd +@@ -0,0 +1,6 @@ ++/*? Text: "sync request failed (cmd=0x%08x, status=0x%02x)\n" */ ++/*? Text: "readcpuinfo failed (response=0x%04x)\n" */ ++/*? Text: "configure cpu failed (cmd=0x%08x, response=0x%04x)\n" */ ++/*? Text: "configure channel-path failed (cmd=0x%08x, response=0x%04x)\n" */ ++/*? Text: "read channel-path info failed (response=0x%04x)\n" */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/sclp_config +@@ -0,0 +1,3 @@ ++/*? Text: "cpu capability changed.\n" */ ++/*? Text: "no configuration management.\n" */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/sclp_cpi +@@ -0,0 +1,2 @@ ++/*? Text: "request failed (status=0x%02x)\n" */ ++/*? Text: "request failed with response code 0x%x\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/sclp_sdias +@@ -0,0 +1,4 @@ ++/*? Text: "sclp_send failed for get_nr_blocks\n" */ ++/*? Text: "SCLP error: %x\n" */ ++/*? Text: "sclp_send failed: %x\n" */ ++/*? Text: "Error from SCLP while copying hsa. Event status = %x\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/setup +@@ -0,0 +1,151 @@ ++/*? ++ * Text: "Execute protection active, mvcos available\n" ++ * Severity: Informational ++ * Description: ++ * The kernel parameter 'noexec' has been specified. The kernel will ++ * honor the execute bit of mappings and will use the mvcos instruction ++ * to copy between the user and kernel address space. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Execute protection active, mvcos not available\n" ++ * Severity: Informational ++ * Description: ++ * The kernel parameter 'noexec' has been specified. The kernel will ++ * honor the execute bit of mappings. The mvcos instruction is not ++ * available and the kernel will use the slower page table walk method ++ * to copy between the user and kernel address space. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Address spaces switched, mvcos available\n" ++ * Severity: Informational ++ * Description: ++ * The kernel parameter 'switch_amode' has been specified. The kernel ++ * will use the primary address space for user space processes and the ++ * home address space for the kernel. The mvcos instruction is used to ++ * copy between the user and kernel address space. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Address spaces switched, mvcos not available\n" ++ * Severity: Informational ++ * Description: ++ * The kernel parameter 'switch_amode' has been specified. The kernel ++ * will use the primary address space for user space processes and the ++ * home address space for the kernel. The mvcos instruction is not ++ * available and the kernel will use the slower page table walk method ++ * to copy between the user and kernel address space. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "initrd extends beyond end of memory (0x%08lx > 0x%08lx) disabling initrd\n" ++ * Severity: Error ++ * Parameter: ++ * @1: start address of the initial RAM disk ++ * @2: memory end address ++ * Description: ++ * The load address and the size of the initial RAM disk result in an end ++ * address of the initial RAM disk that is beyond the end of the system ++ * memory. ++ * User action: ++ * Lower the load address of the initial RAM disk, reduce the size of the ++ * initial RAM disk, or increase the size if the system memory to make the ++ * initial RAM disk fit into the memory. ++ */ ++ ++/*? ++ * Text: "Moving initrd (0x%08lx -> 0x%08lx, size: %ld)\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: old start address of the initial RAM disk ++ * @2: new start address of the initial RAM disk ++ * @3: size of the initial RAM disk ++ * Description: ++ * The location of the initial RAM disk conflicted with the boot memory bitmap. ++ * To resolve the conflict the initial RAM disk has been moved to a new ++ * location. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Linux is running as a z/VM guest operating system in 31-bit mode\n" ++ * Severity: Informational ++ * Description: ++ * The 31-bit Linux kernel detected that it is running as a guest operating ++ * system of the z/VM hypervisor. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Linux is running natively in 31-bit mode\n" ++ * Severity: Informational ++ * Description: ++ * The 31-bit Linux kernel detected that it is running on an IBM mainframe, ++ * either as the sole operating system in an LPAR or as the sole operating ++ * system on the entire mainframe. The Linux kernel is not running as a ++ * guest operating system of the z/VM hypervisor. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "The hardware system has IEEE compatible floating point units\n" ++ * Severity: Informational ++ * Description: ++ * The Linux kernel detected that it is running on a hardware system with ++ * CPUs that have IEEE compatible floating point units. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "The hardware system has no IEEE compatible floating point units\n" ++ * Severity: Informational ++ * Description: ++ * The Linux kernel detected that it is running on a hardware system with ++ * CPUs that do not have IEEE compatible floating point units. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Linux is running as a z/VM guest operating system in 64-bit mode\n" ++ * Severity: Informational ++ * Description: ++ * The 64-bit Linux kernel detected that it is running as a guest operating ++ * system of the z/VM hypervisor. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Linux is running natively in 64-bit mode\n" ++ * Severity: Informational ++ * Description: ++ * The 64-bit Linux kernel detected that it is running on an IBM mainframe, ++ * either as the sole operating system in an LPAR or as the sole operating ++ * system on the entire mainframe. The Linux kernel is not running as a ++ * guest operating system of the z/VM hypervisor. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "Linux is running under KVM in 64-bit mode\n" ++ * Severity: Informational ++ * Description: ++ * The 64-bit kernel detected that it is running under the KVM hypervisor. ++ * User action: ++ * None. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/time +@@ -0,0 +1,36 @@ ++/*? ++ * Text: "The ETR interface has adjusted the clock by %li microseconds\n" ++ * Severity: Notice ++ * Parameter: ++ * @1: number of microseconds ++ * Description: ++ * The external time reference (ETR) interface has synchronized the system ++ * clock with the external reference and set it to a new value. The time ++ * difference between the old and new clock value has been passed to the ++ * network time protocol (NTP) as a single shot adjustment. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "The real or virtual hardware system does not provide an ETR interface\n" ++ * Severity: Warning ++ * Description: ++ * The 'etr=' parameter has been passed on the kernel parameter line for ++ * a Linux instance that does not have access to the external time reference ++ * (ETR) facility. ++ * User action: ++ * To avoid this warning remove the 'etr=' kernel parameter. ++ */ ++ ++/*? ++ * Text: "The real or virtual hardware system does not provide an STP interface\n" ++ * Severity: Warning ++ * Description: ++ * The 'stp=' parameter has been passed on the kernel parameter line for ++ * a Linux instance that does not have access to the server time protocol ++ * (STP) facility. ++ * User action: ++ * To avoid this warning remove the 'stp=' kernel parameter. ++ */ ++ +--- /dev/null ++++ b/Documentation/kmsg/s390/vmcp +@@ -0,0 +1,13 @@ ++/*? ++ * Text: "The z/VM CP interface device driver cannot be loaded without z/VM\n" ++ * Severity: Warning ++ * Description: ++ * With the z/VM CP interface you can issue z/VM CP commands from a Linux ++ * terminal session. On Linux instances that run in environments other than ++ * the z/VM hypervisor, the z/VM CP interface does not provide any useful ++ * function and the corresponding vmcp device driver cannot be loaded. ++ * User action: ++ * Load the vmcp device driver only on Linux instances that run as guest ++ * operating systems of the z/VM hypervisor. If the device driver has been ++ * compiled into the kernel, ignore this message. ++ */ +--- /dev/null ++++ b/Documentation/kmsg/s390/vmlogrdr +@@ -0,0 +1,5 @@ ++/*? Text: "vmlogrdr: failed to start recording automatically\n" */ ++/*? Text: "vmlogrdr: connection severed with reason %i\n" */ ++/*? Text: "vmlogrdr: iucv connection to %s failed with rc %i \n" */ ++/*? Text: "vmlogrdr: failed to stop recording automatically\n" */ ++/*? Text: "not running under VM, driver not loaded.\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/vmur +@@ -0,0 +1,34 @@ ++/*? ++ * Text: "The %s cannot be loaded without z/VM\n" ++ * Severity: Error ++ * Parameter: ++ * @1: z/VM virtual unit record device driver ++ * Description: ++ * The z/VM virtual unit record device driver provides Linux with access to ++ * z/VM virtual unit record devices like punch card readers, card punches, and ++ * line printers. On Linux instances that run in environments other than the ++ * z/VM hypervisor, the device driver does not provide any useful function and ++ * the corresponding vmur module cannot be loaded. ++ * User action: ++ * Load the vmur module only on Linux instances that run as guest operating ++ * systems of the z/VM hypervisor. If the z/VM virtual unit record device ++ * has been compiled into the kernel, ignore this message. ++ */ ++ ++/*? ++ * Text: "Kernel function alloc_chrdev_region failed with error code %d\n" ++ * Severity: Error ++ * Parameter: ++ * @1: error code according to errno definitions ++ * Description: ++ * The z/VM virtual unit record device driver (vmur) needs to register a range ++ * of character device minor numbers from 0x0000 to 0xffff. ++ * This registration failed, probably because of memory constraints. ++ * User action: ++ * Free some memory and reload the vmur module. If the z/VM virtual unit ++ * record device driver has been compiled into the kernel reboot Linux. ++ * Consider assigning more memory to your LPAR or z/VM guest virtual machine. ++ */ ++ ++/*? Text: "%s loaded.\n" */ ++/*? Text: "%s unloaded.\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/xpram +@@ -0,0 +1,58 @@ ++/*? ++ * Text: "%d is not a valid number of XPRAM devices\n" ++ * Severity: Error ++ * Parameter: ++ * @1: number of partitions ++ * Description: ++ * The number of XPRAM partitions specified for the 'devs' module parameter ++ * or with the 'xpram.parts' kernel parameter must be an integer in the ++ * range 1 to 32. The XPRAM device driver created a maximum of 32 partitions ++ * that are probably not configured as intended. ++ * User action: ++ * If the XPRAM device driver has been compiled as a separate module, ++ * unload the module and load it again with a correct value for the ++ * 'devs' module parameter. If the XPRAM device driver has been compiled ++ * into the kernel, correct the 'xpram.parts' parameter in the kernel ++ * command line and restart Linux. ++ */ ++ ++/*? ++ * Text: "Not enough expanded memory available\n" ++ * Severity: Error ++ * Description: ++ * The amount of expanded memory required to set up your XPRAM partitions ++ * depends on the 'sizes' parameter specified for the xpram module or on ++ * the specifications for the 'xpram.parts' parameter if the XPRAM device ++ * driver has been compiled into the kernel. Your ++ * current specification exceed the amount of available expanded memory. ++ * Your XPRAM partitions are probably not configured as intended. ++ * User action: ++ * If the XPRAM device driver has been compiled as a separate module, ++ * unload the xpram module and load it again with an appropriate value ++ * for the 'sizes' module parameter. If the XPRAM device driver has been ++ * compiled into the kernel, adjust the 'xpram.parts' parameter in the ++ * kernel command line and restart Linux. If you need more than the ++ * available expanded memory, increase the expanded memory allocation for ++ * your virtual hardware or LPAR. ++ */ ++ ++/*? ++ * Text: "No expanded memory available\n" ++ * Severity: Error ++ * Description: ++ * The XPRAM device driver has been loaded in a Linux instance that runs ++ * in an LPAR or virtual hardware without expanded memory. ++ * are created. ++ * User action: ++ * Allocate expanded memory for your LPAR or virtual hardware or do not ++ * load the xpram module. You can ignore this message, if you do not want ++ * to create XPRAM partitions. ++ */ ++ ++/*? Text: " number of devices (partitions): %d \n" */ ++/*? Text: " size of partition %d: %u kB\n" */ ++/*? Text: " size of partition %d to be set automatically\n" */ ++/*? Text: " memory needed (for sized partitions): %lu kB\n" */ ++/*? Text: " partitions to be sized automatically: %d\n" */ ++/*? Text: " automatically determined partition size: %lu kB\n" */ ++/*? Text: " %u pages expanded memory found (%lu KB).\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/zdump +@@ -0,0 +1,12 @@ ++/*? ++ * Text: "The 32-bit dump tool cannot be used for a 64-bit system\n" ++ * Severity: Alert ++ * Description: ++ * The dump process ends without creating a system dump. ++ * User action: ++ * Use a 64-bit dump tool to obtain a system dump for 64-bit Linux instance. ++ */ ++ ++/*? Text: "DETECTED 'S390 (32 bit) OS'\n" */ ++/*? Text: "0x%x is an unknown architecture.\n" */ ++/*? Text: "DETECTED 'S390X (64 bit) OS'\n" */ +--- /dev/null ++++ b/Documentation/kmsg/s390/zfcp +@@ -0,0 +1,830 @@ ++/*? ++ * Text: "%s is not a valid SCSI device\n" ++ * Severity: Error ++ * Parameter: ++ * @1: device specification ++ * Description: ++ * The specification for an initial SCSI device provided with the 'zfcp.device' ++ * kernel parameter or with the 'device' module parameter is syntactically ++ * incorrect. The specified SCSI device could not be attached to the Linux ++ * system. ++ * User action: ++ * Correct the value for the 'zfcp.device' or 'device' parameter and reboot ++ * Linux. See "Device Drivers, Features, and Commands" for information about ++ * the syntax. ++ */ ++ ++/*? ++ * Text: "Registering the misc device zfcp_cfdc failed\n" ++ * Severity: Error ++ * Description: ++ * The zfcp device driver failed to register the device that provides access to ++ * the adapter access control file (ACL tables). The device driver ++ * initialization failed. A possible cause for this problem is memory ++ * constraints. ++ * User action: ++ * Free some memory and try again to load the zfcp device driver. If the zfcp ++ * device driver has been compiled into the kernel, reboot Linux. Consider ++ * assigning more memory to your LPAR or z/VM guest virtual machine. If the ++ * problem persists, contact your support organization. ++ */ ++ ++/*? ++ * Text: "The zfcp device driver could not register with the common I/O layer\n" ++ * Severity: Error ++ * Description: ++ * The device driver initialization failed. A possible cause of this problem is ++ * memory constraints. ++ * User action: ++ * Free some memory and try again to load the zfcp device driver. If the zfcp ++ * device driver has been compiled into the kernel, reboot Linux. Consider ++ * assigning more memory to your LPAR or z/VM guest virtual machine. If the ++ * problem persists, contact your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Setting up data structures for the FCP adapter failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The zfcp device driver could not allocate data structures for an FCP adapter. ++ * A possible reason for this problem is memory constraints. ++ * User action: ++ * Set the FCP adapter offline or detach it from the Linux system, free some ++ * memory and set the FCP adapter online again or attach it again. If this ++ * problem persists, gather Linux debug data, collect the FCP adapter ++ * hardware logs, and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The FCP device is operational again\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * An FCP device has been unavailable because it had been detached from the ++ * Linux system or because the corresponding CHPID was offline. The FCP device ++ * is now available again and the zfcp device driver resumes all operations to ++ * the FCP device. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "%s: The CHPID for the FCP device is offline\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The CHPID for an FCP device has been set offline, either logically in Linux ++ * or on the hardware. ++ * User action: ++ * Find out which CHPID corresponds to the FCP device, for example, with the ++ * lscss command. Check if the CHPID has been set logically offline in sysfs. ++ * Write 'on' to the CHPID's status attribute to set it online. If the CHPID is ++ * online in sysfs, find out if it has been varied offline through a hardware ++ * management interface, for example the service element (SE). ++ */ ++ ++/*? ++ * Text: "%s: The FCP device has been detached\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * An FCP device is no longer available to Linux. ++ * User action: ++ * Ensure that the FCP adapter is operational and attached to the LPAR or z/VM ++ * virtual machine. ++ */ ++ ++/*? ++ * Text: "%s: Registering the FCP device with the SCSI stack failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter could not be registered with the Linux SCSI ++ * stack. A possible reason for this problem is memory constraints. ++ * User action: ++ * Set the FCP adapter offline or detach it from the Linux system, free some ++ * memory and set the FCP adapter online again or attach it again. If this ++ * problem persists, gather Linux debug data, collect the FCP adapter ++ * hardware logs, and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: ERP cannot recover an error on the FCP device\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * An error occurred on an FCP device. The error recovery procedure (ERP) ++ * could not resolve the error. The FCP device driver cannot use the FCP device. ++ * User action: ++ * Check for previous error messages for the same FCP device to find the ++ * cause of the problem. ++ */ ++ ++/*? ++ * Text: "%s: Creating an ERP thread for the FCP device failed.\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The zfcp device driver could not set up error recovery procedure (ERP) ++ * processing for the FCP device. The FCP device is not available for use ++ * in Linux. ++ * User action: ++ * Free some memory and try again to load the zfcp device driver. If the zfcp ++ * device driver has been compiled into the kernel, reboot Linux. Consider ++ * assigning more memory to your LPAR or z/VM guest virtual machine. If the ++ * problem persists, contact your support organization. ++ */ ++ ++/*? ++ * Text: "%s: ERP failed for unit 0x%016Lx on port 0x%016Lx\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * An error occurred on the SCSI device at the specified LUN. The error recovery ++ * procedure (ERP) could not resolve the error. The SCSI device is not ++ * available. ++ * User action: ++ * Verify that the LUN is correct. Check the fibre channel fabric for errors ++ * related to the specified WWPN and LUN, the storage server, and Linux. ++ */ ++ ++/*? ++ * Text: "%s: ERP failed for remote port 0x%016Lx\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: WWPN ++ * Description: ++ * An error occurred on a remote port. The error recovery procedure (ERP) ++ * could not resolve the error. The port is not available. ++ * User action: ++ * Verify that the WWPN is correct and check the fibre channel fabric for ++ * errors related to the WWPN. ++ */ ++ ++/*? ++ * Text: "%s: Attaching the name server port to the FCP device failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The zfcp device driver could not attach the name server port of the fibre ++ * channel fabric to an FCP device. A possible cause of this problem is ++ * memory constraints. ++ * User action: ++ * Set the FCP device offline, free some memory, then set the FCP device online ++ * again. If this does not resolve the problem, reboot Linux and try again to ++ * set the FCP device online. ++ */ ++ ++/*? ++ * Text: "%s: Registering unit 0x%016Lx on port 0x%016Lx failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * The Linux kernel could not allocate enough memory to register the SCSI ++ * device at the indicated LUN with the SCSI stack. The SCSI device is not ++ * available. ++ * User action: ++ * Free some memory then detach the LUN and attach it again. ++ */ ++ ++/*? ++ * Text: "%s: Registering port 0x%016Lx failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: WWPN ++ * Description: ++ * The Linux kernel could not allocate enough memory to register the ++ * remote port with the indicated WWPN with the SCSI stack. The remote ++ * port is not available. ++ * User action: ++ * Free some memory and trigger the rescan for ports. ++ */ ++ ++/*? ++ * Text: "%s: A QDIO problem occurred\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * QDIO reported a problem to the zfcp device driver. The zfcp device driver ++ * tries to recover this problem. ++ * User action: ++ * Check for related error messages. If this problem occurs frequently, gather ++ * Linux debug data and contact your support organization. ++ */ ++ ++/*? ++ * Text: "%s: A QDIO protocol error occurred, operations continue\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The zfcp device driver detected a missing flag in a QDIO queue. The device ++ * driver tries to keep the FCP device operational. ++ * User action: ++ * Check for related error messages. If this problem occurs frequently, gather ++ * Linux debug data, collect the FCP adapter hardware logs, and report the ++ * problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Setting up the QDIO connection to the FCP adapter failed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The zfcp device driver failed to establish a QDIO connection with the FCP ++ * adapter. ++ * User action: ++ * Set the FCP adapter offline or detach it from the Linux system, free some ++ * memory and set the FCP adapter online again or attach it again. If this ++ * problem persists, gather Linux debug data, collect the FCP adapter ++ * hardware logs, and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The FCP adapter reported a problem that cannot be recovered\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter has a problem that cannot be recovered by the zfcp device ++ * driver. The zfcp device driver stopped using the FCP device. ++ * User action: ++ * Gather Linux debug data, collect the FCP adapter hardware logs, and report ++ * this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: There is a wrap plug instead of a fibre channel cable\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter is not physically connected to the fibre channel fabric. ++ * User action: ++ * Remove the wrap plug from the FCP adapter and connect the adapter with the ++ * fibre channel fabric. ++ */ ++ ++/*? ++ * Text: "%s: Access denied to unit 0x%016Lx on port 0x%016Lx\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * The Linux system is not allowed to access the SCSI device at the indicated ++ * LUN. ++ * User action: ++ * Update the access control table of the FCP device to grant the Linux ++ * system access to the LUN or remove the LUN from the Linux system. ++ */ ++ ++/*? ++ * Text: "%s: FCP device not operational because of an unsupported FC class\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter hardware does not support the fibre channel service class ++ * requested by the zfcp device driver. This problem indicates a program error ++ * in the zfcp device driver. ++ * User action: ++ * Gather Linux debug data, collect the FCP adapter hardware logs, and report ++ * this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: 0x%Lx is an ambiguous request identifier\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: request ID ++ * Description: ++ * The FCP adapter reported that it received the same request ID twice. This is ++ * an error. The zfcp device driver stopped using the FCP device. ++ * User action: ++ * Gather Linux debug data, collect the FCP adapter hardware logs, and report ++ * this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: QTCB version 0x%x not supported by FCP adapter (0x%x to 0x%x)\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: requested version ++ * @3: lowest supported version ++ * @4: highest supported version ++ * Description: ++ * See message text. ++ * The queue transfer control block (QTCB) version requested by the zfcp device ++ * driver is not supported by the FCP adapter hardware. ++ * User action: ++ * If the requested version is higher than the highest version supported by the ++ * hardware, install more recent firmware on the FCP adapter. If the requested ++ * version is lower then the lowest version supported by the hardware, upgrade ++ * to a Linux level with a more recent zfcp device driver. ++ */ ++ ++/*? ++ * Text: "%s: The FCP adapter could not log in to the fibre channel fabric\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The fibre channel switch rejected the login request from the FCP adapter. ++ * User action: ++ * Check the fibre channel fabric or switch logs for possible errors. ++ */ ++ ++/*? ++ * Text: "%s: The FCP device is suspended because of a firmware update\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP device is not available while a firmware update is in progress. This ++ * problem is temporary. The FCP device will resume operations when the ++ * firmware update is completed. ++ * User action: ++ * Wait 10 seconds and try the operation again. ++ */ ++ ++/*? ++ * Text: "%s: All NPIV ports on the FCP adapter have been assigned\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The number of N_Port ID Virtualization (NPIV) ports that can be assigned ++ * on an FCP adapter is limited. Once assigned, NPIV ports are not released ++ * automatically but have to be released explicitly through the support ++ * element (SE). ++ * User action: ++ * Identify NPIV ports that have been assigned but are no longer in use and ++ * release them from the SE. ++ */ ++ ++/*? ++ * Text: "%s: The link between the FCP adapter and the FC fabric is down\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter is not usable. Specific error information is not available. ++ * User action: ++ * Check the cabling and the fibre channel fabric configuration. If this ++ * problem persists, gather Linux debug data, collect the FCP adapter ++ * hardware logs, and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Access denied to port 0x%016Lx\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: WWPN ++ * Description: ++ * The Linux system is not allowed to access the remote port with the specified ++ * WWPN. ++ * User action: ++ * Update the access control table of the FCP device to grant the Linux ++ * system access to the WWPN or remove the WWPN from the Linux system. ++ */ ++ ++/*? ++ * Text: "%s: The QTCB type is not supported by the FCP adapter\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The queue transfer control block (QTCB) type requested by the zfcp device ++ * driver is not supported by the FCP adapter hardware. ++ * User action: ++ * Install the latest firmware on your FCP adapter hardware. If this does not ++ * resolve the problem, upgrade to a Linux level with a more recent zfcp device ++ * driver. If the problem persists, contact your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The error threshold for checksum statistics has been exceeded\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter has reported a large number of bit errors. This might ++ * indicate a problem with the physical components of the fibre channel fabric. ++ * Details about the errors have been written to the HBA trace for the FCP ++ * adapter. ++ * User action: ++ * Check for problems in the fibre channel fabric and ensure that all cables ++ * are properly plugged. ++ */ ++ ++/*? ++ * Text: "%s: The local link has been restored\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * A problem with the connection between the FCP adapter and the adjacent node ++ * on the fibre channel fabric has been resolved. The FCP adapter is now ++ * available again. ++ * User action: ++ * None. ++ */ ++ ++/*? ++ * Text: "%s: Access denied according to ACT rule type %s, rule %d\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: access rule type ++ * @3: access rule ++ * Description: ++ * A rule in the access control table (ACT) for the FCP device denies access ++ * to a remote port or a LUN. ++ * User action: ++ * Examine the access control tables for the FCP device to see if the ++ * specified rule is correct. ++ */ ++ ++/*? ++ * Text: "%s: The mode table on the FCP adapter has been damaged\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * This is an FCP adapter hardware problem. ++ * User action: ++ * Report this problem with FCP hardware logs to IBM support. ++ */ ++ ++/*? ++ * Text: "%s: The adjacent fibre channel node does not support FCP\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The fibre channel switch or storage system that is connected to the FCP ++ * channel does not support the fibre channel protocol (FCP). The zfcp ++ * device driver stopped using the FCP device. ++ * User action: ++ * Check the adjacent fibre channel node. ++ */ ++ ++/*? ++ * Text: "%s: The FCP adapter does not recognize the command 0x%x\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: command ++ * Description: ++ * A command code that was sent from the zfcp device driver to the FCP adapter ++ * is not valid. The zfcp device driver stopped using the FCP device. ++ * User action: ++ * Gather Linux debug data, collect the FCP adapter hardware logs, and report ++ * this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: There is no light signal from the local fibre channel cable\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * There is no signal on the fibre channel cable that connects the FCP adapter ++ * to the fibre channel fabric. ++ * User action: ++ * Ensure that the cable is in place and connected properly to the FCP adapter ++ * and to the adjacent fibre channel switch or storage system. ++ */ ++ ++/*? ++ * Text: "%s: The WWPN assignment file on the FCP adapter has been damaged\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * This is an FCP adapter hardware problem. ++ * User action: ++ * Report this problem with FCP hardware logs to IBM support. ++ */ ++ ++/*? ++ * Text: "%s: The FCP device detected a WWPN that is duplicate or not valid\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * This condition indicates an error in the FCP adapter hardware or in the z/VM ++ * hypervisor. ++ * User action: ++ * Gather Linux debug data, collect the FCP adapter hardware logs, and report ++ * this problem to IBM support. ++ */ ++ ++/*? ++ * Text: "%s: The fibre channel fabric does not support NPIV\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP adapter requires N_Port ID Virtualization (NPIV) from the adjacent ++ * fibre channel node. Either the FCP adapter is connected to a fibre channel ++ * switch that does not support NPIV or the FCP adapter tries to use NPIV in a ++ * point-to-point setup. The connection is not operational. ++ * User action: ++ * Verify that NPIV is correctly used for this connection. Check the FCP adapter ++ * configuration and the fibre channel switch configuration. If necessary, ++ * update the fibre channel switch firmware. ++ */ ++ ++/*? ++ * Text: "%s: The FCP adapter cannot support more NPIV ports\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * N_Port ID Virtualization (NPIV) ports consume physical resources on the FCP ++ * adapter. The FCP adapter resources are exhausted. The connection is not ++ * operational. ++ * User action: ++ * Analyze the number of available NPIV ports and which operating system ++ * instances use them. If necessary, reconfigure your setup to move some ++ * NPIV ports to an FCP adapter with free resources. ++ */ ++ ++/*? ++ * Text: "%s: The adjacent switch cannot support more NPIV ports\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * N_Port ID Virtualization (NPIV) ports consume physical resources. The ++ * resources of the fibre channel switch that is connected to the FCP adapter ++ * are exhausted. The connection is not operational. ++ * User action: ++ * Analyze the number of available NPIV ports on the adjacent fibre channel ++ * switch and how they are used. If necessary, reconfigure your fibre channel ++ * fabric to accommodate the required NPIV ports. ++ */ ++ ++/*? ++ * Text: "%s: 0x%x is not a valid transfer protocol status\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: status information ++ * Description: ++ * The transfer protocol status information reported by the FCP adapter is not ++ * a valid status for the zfcp device driver. The zfcp device driver stopped ++ * using the FCP device. ++ * User action: ++ * Gather Linux debug data, collect the FCP adapter hardware logs, and report ++ * this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Unknown or unsupported arbitrated loop fibre channel topology detected\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The FCP device is connected to a fibre channel arbitrated loop or the FCP adapter ++ * reported an unknown fibre channel topology. The zfcp device driver supports ++ * point-to-point connections and switched fibre channel fabrics but not arbitrated ++ * loop topologies. The FCP device cannot be used. ++ * User action: ++ * Check the fibre channel setup and ensure that only supported topologies are ++ * connected to the FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: FCP adapter maximum QTCB size (%d bytes) is too small\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: maximum supported size ++ * @3: requested QTCB size ++ * Description: ++ * The queue transfer control block (QTCB) size requested by the zfcp ++ * device driver is not supported by the FCP adapter hardware. ++ * User action: ++ * Update the firmware on your FCP adapter hardware to the latest ++ * available level and update the Linux kernel to the latest supported ++ * level. If the problem persists, contact your support organization. ++ */ ++ ++/*? ++ * Text: "%s: The FCP adapter only supports newer control block versions\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The protocol supported by the FCP adapter is not compatible with the zfcp ++ * device driver. ++ * User action: ++ * Upgrade your Linux kernel to a level that includes a zfcp device driver ++ * with support for the control block version required by your FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: The FCP adapter only supports older control block versions\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The protocol supported by the FCP adapter is not compatible with the zfcp ++ * device driver. ++ * User action: ++ * Install the latest firmware on your FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: Not enough FCP adapter resources to open remote port 0x%016Lx\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: WWPN ++ * Description: ++ * Each port that is opened consumes physical resources of the FCP adapter to ++ * which it is attached. These resources are exhausted and the specified port ++ * cannot be opened. ++ * User action: ++ * Reduce the total number of remote ports that are attached to the ++ * FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: Remote port 0x%016Lx could not be opened\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: WWPN ++ * Description: ++ * The FCP adapter rejected a request to open the specified port. No retry ++ * is possible. ++ * User action: ++ * Verify the setup and try removing and adding the port again. If this ++ * problem persists, gather Linux debug data, collect the FCP adapter ++ * hardware logs, and report the problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: LUN 0x%Lx on port 0x%Lx is already in use by CSS%d, MIF Image ID %x\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: remote port WWPN ++ * @4: channel subsystem ID ++ * @5: MIF Image ID of the LPAR ++ * Description: ++ * The SCSI device at the indicated LUN is already in use by another system. ++ * Only one system at a time can use the SCSI device. ++ * User action: ++ * Ensure that the other system stops using the device before trying to use it. ++ */ ++ ++/*? ++ * Text: "%s: No handle is available for LUN 0x%016Lx on port 0x%016Lx\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * The FCP adapter can only open a limited number of SCSI devices. This limit ++ * has been reached and the SCSI device at the indicated LUN cannot be opened. ++ * User action: ++ * Check all SCSI devices opened through the FCP adapter and close some of them. ++ */ ++ ++/*? ++ * Text: "%s: SCSI device at LUN 0x%016Lx on port 0x%016Lx opened read-only\n" ++ * Severity: Informational ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * The access control tables in the FCP adapter allow read-only access for the ++ * LUN. Write access is not permitted for your Linux instance. The SCSI ++ * device has been opened successfully in read-only access mode. ++ * User action: ++ * None if read-only access is sufficient. If you require write access, change ++ * the access control tables in the FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: Exclusive read-only access not supported (unit 0x%016Lx, port 0x%016Lx)\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * The access configuration specified in the access control tables of the FCP ++ * adapter is not valid. The SCSI device at the indicated LUN cannot be ++ * accessed. ++ * User action: ++ * Change the access control tables in the FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: Shared read-write access not supported (unit 0x%016Lx, port 0x%016Lx\n)" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * The access configuration specified in the access control tables of the FCP ++ * adapter is not valid. The SCSI device at the indicated LUN cannot be ++ * accessed. ++ * User action: ++ * Change the access control tables in the FCP adapter. ++ */ ++ ++/*? ++ * Text: "%s: Incorrect direction %d, unit 0x%016Lx on port 0x%016Lx closed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: value in direction field ++ * @3: LUN ++ * @4: WWPN ++ * Description: ++ * The direction field in a SCSI request contains an incorrect value. The zfcp ++ * device driver closed down the SCSI device at the indicated LUN. ++ * User action: ++ * Gather Linux debug data and report this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Incorrect CDB length %d, unit 0x%016Lx on port 0x%016Lx closed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: value in length field ++ * @3: LUN ++ * @4: WWPN ++ * Description: ++ * The control-data-block (CDB) length field in a SCSI request is not valid or ++ * too large for the FCP adapter. The zfcp device driver closed down the SCSI ++ * device at the indicated LUN. ++ * User action: ++ * Gather Linux debug data and report this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Oversize data package, unit 0x%016Lx on port 0x%016Lx closed\n" ++ * Severity: Error ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: LUN ++ * @3: WWPN ++ * Description: ++ * A SCSI request with too much data has been sent to the SCSI device at the ++ * indicated LUN. The FCP adapter cannot handle data packets of this size and ++ * the SCSI device driver closed down the SCSI device. ++ * User action: ++ * Gather Linux debug data and report this problem to your support organization. ++ */ ++ ++/*? ++ * Text: "%s: Opening WKA port 0x%x failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * @2: destination ID of the WKA port ++ * Description: ++ * The FCP adapter rejected a request to open the specified ++ * well-known address (WKA) port. No retry is possible. ++ * User action: ++ * Verify the setup and check if the maximum number of remote ports ++ * used through this adapter is below the maximum allowed. If the ++ * problem persists, gather Linux debug data, collect the FCP adapter ++ * hardware logs, and report the problem to your support organization. ++ */ +--- a/Makefile ++++ b/Makefile +@@ -63,6 +63,20 @@ ifndef KBUILD_CHECKSRC + KBUILD_CHECKSRC = 0 + endif + ++# Call message checker as part of the C compilation ++# ++# Use 'make D=1' to enable checking ++# Use 'make D=2' to create the message catalog ++ ++ifdef D ++ ifeq ("$(origin D)", "command line") ++ KBUILD_KMSG_CHECK = $(D) ++ endif ++endif ++ifndef KBUILD_KMSG_CHECK ++ KBUILD_KMSG_CHECK = 0 ++endif ++ + # Use make M=dir to specify directory of external module to build + # Old syntax make ... SUBDIRS=$PWD is still supported + # Setting the environment variable KBUILD_EXTMOD take precedence +@@ -321,6 +335,7 @@ PERL = perl + CHECK = sparse + + CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) ++KMSG_CHECK = $(srctree)/scripts/kmsg-doc + MODFLAGS = -DMODULE + CFLAGS_MODULE = $(MODFLAGS) + AFLAGS_MODULE = $(MODFLAGS) +@@ -361,6 +376,7 @@ export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODU + export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS + export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE + export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE ++export KBUILD_KMSG_CHECK KMSG_CHECK + + # When compiling out-of-tree modules, put MODVERDIR in the module + # tree rather than in the kernel tree. The kernel tree might +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -572,6 +572,15 @@ bool "s390 guest support (EXPERIMENTAL)" + select VIRTIO_CONSOLE + help + Select this option if you want to run the kernel under s390 linux ++ ++config KMSG_IDS ++ bool "Kernel message numbers" ++ default y ++ help ++ Select this option if you want to include a message number to the ++ prefix for kernel messages issued by the s390 architecture and ++ driver code. See "Documentation/s390/kmsg.txt" for more details. ++ + endmenu + + source "net/Kconfig" +--- a/arch/s390/appldata/appldata.h ++++ b/arch/s390/appldata/appldata.h +@@ -26,10 +26,6 @@ + #define CTL_APPLDATA_NET_SUM 2125 + #define CTL_APPLDATA_PROC 2126 + +-#define P_INFO(x...) printk(KERN_INFO MY_PRINT_NAME " info: " x) +-#define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x) +-#define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x) +- + struct appldata_ops { + struct list_head list; + struct ctl_table_header *sysctl_header; +--- a/arch/s390/appldata/appldata_base.c ++++ b/arch/s390/appldata/appldata_base.c +@@ -10,6 +10,8 @@ + * Author: Gerald Schaefer + */ + ++#define KMSG_COMPONENT "appldata" ++ + #include + #include + #include +@@ -32,7 +34,6 @@ + #include "appldata.h" + + +-#define MY_PRINT_NAME "appldata" /* for debug messages, etc. */ + #define APPLDATA_CPU_INTERVAL 10000 /* default (CPU) time for + sampling interval in + milliseconds */ +@@ -390,8 +391,8 @@ appldata_generic_handler(ctl_table *ctl, + (unsigned long) ops->data, ops->size, + ops->mod_lvl); + if (rc != 0) { +- P_ERROR("START DIAG 0xDC for %s failed, " +- "return code: %d\n", ops->name, rc); ++ pr_err("Starting the data collection for %s " ++ "failed with rc=%d\n", ops->name, rc); + module_put(ops->owner); + } else + ops->active = 1; +@@ -401,8 +402,8 @@ appldata_generic_handler(ctl_table *ctl, + (unsigned long) ops->data, ops->size, + ops->mod_lvl); + if (rc != 0) +- P_ERROR("STOP DIAG 0xDC for %s failed, " +- "return code: %d\n", ops->name, rc); ++ pr_err("Stopping the data collection for %s " ++ "failed with rc=%d\n", ops->name, rc); + module_put(ops->owner); + } + spin_unlock(&appldata_ops_lock); +--- a/arch/s390/appldata/appldata_os.c ++++ b/arch/s390/appldata/appldata_os.c +@@ -9,6 +9,8 @@ + * Author: Gerald Schaefer + */ + ++#define KMSG_COMPONENT "appldata" ++ + #include + #include + #include +@@ -22,7 +24,6 @@ + #include "appldata.h" + + +-#define MY_PRINT_NAME "appldata_os" /* for debug messages, etc. */ + #define LOAD_INT(x) ((x) >> FSHIFT) + #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + +@@ -143,21 +144,16 @@ static void appldata_get_os_data(void *d + (unsigned long) ops.data, new_size, + ops.mod_lvl); + if (rc != 0) +- P_ERROR("os: START NEW DIAG 0xDC failed, " +- "return code: %d, new size = %i\n", rc, +- new_size); ++ pr_err("Starting a new OS data collection " ++ "failed with rc=%d\n", rc); + + rc = appldata_diag(APPLDATA_RECORD_OS_ID, + APPLDATA_STOP_REC, + (unsigned long) ops.data, ops.size, + ops.mod_lvl); + if (rc != 0) +- P_ERROR("os: STOP OLD DIAG 0xDC failed, " +- "return code: %d, old size = %i\n", rc, +- ops.size); +- else +- P_INFO("os: old record size = %i stopped\n", +- ops.size); ++ pr_err("Stopping a faulty OS data " ++ "collection failed with rc=%d\n", rc); + } + ops.size = new_size; + } +@@ -178,8 +174,8 @@ static int __init appldata_os_init(void) + max_size = sizeof(struct appldata_os_data) + + (NR_CPUS * sizeof(struct appldata_os_per_cpu)); + if (max_size > APPLDATA_MAX_REC_SIZE) { +- P_ERROR("Max. size of OS record = %i, bigger than maximum " +- "record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE); ++ pr_err("Maximum OS record size %i exceeds the maximum " ++ "record size %i\n", max_size, APPLDATA_MAX_REC_SIZE); + rc = -ENOMEM; + goto out; + } +--- a/arch/s390/crypto/aes_s390.c ++++ b/arch/s390/crypto/aes_s390.c +@@ -17,6 +17,8 @@ + * + */ + ++#define KMSG_COMPONENT "aes_s390" ++ + #include + #include + #include +@@ -169,7 +171,8 @@ static int fallback_init_cip(struct cryp + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(sctx->fallback.cip)) { +- printk(KERN_ERR "Error allocating fallback algo %s\n", name); ++ pr_err("Allocating AES fallback algorithm %s failed\n", ++ name); + return PTR_ERR(sctx->fallback.blk); + } + +@@ -349,7 +352,8 @@ static int fallback_init_blk(struct cryp + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(sctx->fallback.blk)) { +- printk(KERN_ERR "Error allocating fallback algo %s\n", name); ++ pr_err("Allocating AES fallback algorithm %s failed\n", ++ name); + return PTR_ERR(sctx->fallback.blk); + } + +@@ -515,9 +519,8 @@ static int __init aes_s390_init(void) + + /* z9 109 and z9 BC/EC only support 128 bit key length */ + if (keylen_flag == AES_KEYLEN_128) +- printk(KERN_INFO +- "aes_s390: hardware acceleration only available for " +- "128 bit keys\n"); ++ pr_info("AES hardware acceleration is only available for" ++ " 128-bit keys\n"); + + ret = crypto_register_alg(&aes_alg); + if (ret) +--- a/arch/s390/hypfs/hypfs_diag.c ++++ b/arch/s390/hypfs/hypfs_diag.c +@@ -3,10 +3,12 @@ + * Hypervisor filesystem for Linux on s390. Diag 204 and 224 + * implementation. + * +- * Copyright (C) IBM Corp. 2006 ++ * Copyright IBM Corp. 2006, 2008 + * Author(s): Michael Holzheu + */ + ++#define KMSG_COMPONENT "hypfs" ++ + #include + #include + #include +@@ -527,13 +529,14 @@ __init int hypfs_diag_init(void) + int rc; + + if (diag204_probe()) { +- printk(KERN_ERR "hypfs: diag 204 not working."); ++ pr_err("The hardware system does not support hypfs\n"); + return -ENODATA; + } + rc = diag224_get_name_table(); + if (rc) { + diag204_free_buffer(); +- printk(KERN_ERR "hypfs: could not get name table.\n"); ++ pr_err("The hardware system does not provide all " ++ "functions required by hypfs\n"); + } + return rc; + } +--- a/arch/s390/hypfs/inode.c ++++ b/arch/s390/hypfs/inode.c +@@ -2,10 +2,12 @@ + * arch/s390/hypfs/inode.c + * Hypervisor filesystem for Linux on s390. + * +- * Copyright (C) IBM Corp. 2006 ++ * Copyright IBM Corp. 2006, 2008 + * Author(s): Michael Holzheu + */ + ++#define KMSG_COMPONENT "hypfs" ++ + #include + #include + #include +@@ -200,7 +202,7 @@ static ssize_t hypfs_aio_write(struct ki + else + rc = hypfs_diag_create_files(sb, sb->s_root); + if (rc) { +- printk(KERN_ERR "hypfs: Update failed\n"); ++ pr_err("Updating the hypfs tree failed\n"); + hypfs_delete_tree(sb->s_root); + goto out; + } +@@ -252,8 +254,7 @@ static int hypfs_parse_options(char *opt + break; + case opt_err: + default: +- printk(KERN_ERR "hypfs: Unrecognized mount option " +- "\"%s\" or missing value\n", str); ++ pr_err("%s is not a valid mount option\n", str); + return -EINVAL; + } + } +@@ -317,7 +318,7 @@ static int hypfs_fill_super(struct super + } + hypfs_update_update(sb); + sb->s_root = root_dentry; +- printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n"); ++ pr_info("Hypervisor filesystem mounted\n"); + return 0; + + err_tree: +@@ -513,7 +514,7 @@ fail_sysfs: + if (!MACHINE_IS_VM) + hypfs_diag_exit(); + fail_diag: +- printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); ++ pr_err("Initialization of hypfs failed with rc=%i\n", rc); + return rc; + } + +--- a/arch/s390/kernel/Makefile ++++ b/arch/s390/kernel/Makefile +@@ -12,8 +12,8 @@ CFLAGS_smp.o := -Wno-nonnull + # + CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' + +-obj-y := bitmap.o traps.o time.o process.o base.o early.o \ +- setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ ++obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \ ++ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ + s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o + + obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) +--- a/arch/s390/kernel/cpcmd.c ++++ b/arch/s390/kernel/cpcmd.c +@@ -7,6 +7,8 @@ + * Christian Borntraeger (cborntra@de.ibm.com), + */ + ++#define KMSG_COMPONENT "cpcmd" ++ + #include + #include + #include +@@ -104,8 +106,8 @@ int cpcmd(const char *cmd, char *respons + (((unsigned long)response + rlen) >> 31)) { + lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); + if (!lowbuf) { +- printk(KERN_WARNING +- "cpcmd: could not allocate response buffer\n"); ++ pr_warning("The cpcmd kernel function failed to " ++ "allocate a response buffer\n"); + return -ENOMEM; + } + spin_lock_irqsave(&cpcmd_lock, flags); +--- a/arch/s390/kernel/debug.c ++++ b/arch/s390/kernel/debug.c +@@ -10,6 +10,8 @@ + * Bugreports to: + */ + ++#define KMSG_COMPONENT "s390dbf" ++ + #include + #include + #include +@@ -693,8 +695,8 @@ debug_info_t *debug_register_mode(const + /* Since debugfs currently does not support uid/gid other than root, */ + /* we do not allow gid/uid != 0 until we get support for that. */ + if ((uid != 0) || (gid != 0)) +- printk(KERN_WARNING "debug: Warning - Currently only uid/gid " +- "= 0 are supported. Using root as owner now!"); ++ pr_warning("Root becomes the owner of all s390dbf files " ++ "in sysfs\n"); + if (!initialized) + BUG(); + mutex_lock(&debug_mutex); +@@ -709,7 +711,7 @@ debug_info_t *debug_register_mode(const + debug_register_view(rc, &debug_pages_view); + out: + if (!rc){ +- printk(KERN_ERR "debug: debug_register failed for %s\n",name); ++ pr_err("Registering debug feature %s failed\n", name); + } + mutex_unlock(&debug_mutex); + return rc; +@@ -763,8 +765,8 @@ debug_set_size(debug_info_t* id, int nr_ + if(pages_per_area > 0){ + new_areas = debug_areas_alloc(pages_per_area, nr_areas); + if(!new_areas) { +- printk(KERN_WARNING "debug: could not allocate memory "\ +- "for pagenumber: %i\n",pages_per_area); ++ pr_info("Allocating memory for %i pages failed\n", ++ pages_per_area); + rc = -ENOMEM; + goto out; + } +@@ -780,8 +782,7 @@ debug_set_size(debug_info_t* id, int nr_ + memset(id->active_entries,0,sizeof(int)*id->nr_areas); + memset(id->active_pages, 0, sizeof(int)*id->nr_areas); + spin_unlock_irqrestore(&id->lock,flags); +- printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\ +- ,id->name, pages_per_area); ++ pr_info("%s: set new size (%i pages)\n" ,id->name, pages_per_area); + out: + return rc; + } +@@ -800,10 +801,9 @@ debug_set_level(debug_info_t* id, int ne + spin_lock_irqsave(&id->lock,flags); + if(new_level == DEBUG_OFF_LEVEL){ + id->level = DEBUG_OFF_LEVEL; +- printk(KERN_INFO "debug: %s: switched off\n",id->name); ++ pr_info("%s: switched off\n",id->name); + } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { +- printk(KERN_INFO +- "debug: %s: level %i is out of range (%i - %i)\n", ++ pr_info("%s: level %i is out of range (%i - %i)\n", + id->name, new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; +@@ -1108,8 +1108,8 @@ debug_register_view(debug_info_t * id, s + pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry, + id , &debug_file_ops); + if (!pde){ +- printk(KERN_WARNING "debug: debugfs_create_file() failed!"\ +- " Cannot register view %s/%s\n", id->name,view->name); ++ pr_err("Registering view %s/%s failed due to out of " ++ "memory\n", id->name,view->name); + rc = -1; + goto out; + } +@@ -1119,10 +1119,8 @@ debug_register_view(debug_info_t * id, s + break; + } + if (i == DEBUG_MAX_VIEWS) { +- printk(KERN_WARNING "debug: cannot register view %s/%s\n", +- id->name,view->name); +- printk(KERN_WARNING +- "debug: maximum number of views reached (%i)!\n", i); ++ pr_err("Registering view %s/%s would exceed the maximum " ++ "number of views %i\n", id->name, view->name, i); + debugfs_remove(pde); + rc = -1; + } else { +@@ -1303,7 +1301,8 @@ debug_input_level_fn(debug_info_t * id, + new_level = debug_get_uint(str); + } + if(new_level < 0) { +- printk(KERN_INFO "debug: level `%s` is not valid\n", str); ++ pr_warning("%s is not a valid level for a debug " ++ "feature\n", str); + rc = -EINVAL; + } else { + debug_set_level(id, new_level); +@@ -1380,7 +1379,8 @@ debug_input_flush_fn(debug_info_t * id, + goto out; + } + +- printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]); ++ pr_info("Flushing debug data failed because %c is not a valid " ++ "area\n", input_buf[0]); + + out: + *offset += user_len; +--- /dev/null ++++ b/arch/s390/kernel/processor.c +@@ -0,0 +1,97 @@ ++/* ++ * arch/s390/kernel/processor.c ++ * ++ * Copyright IBM Corp. 2008 ++ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) ++ */ ++ ++#define KMSG_COMPONENT "cpu" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) ++{ ++ pr_info("Processor %d started, address %d, identification %06X\n", ++ cpuinfo->cpu_nr, cpuinfo->cpu_addr, cpuinfo->cpu_id.ident); ++} ++ ++/* ++ * show_cpuinfo - Get information on one CPU for use by procfs. ++ */ ++ ++static int show_cpuinfo(struct seq_file *m, void *v) ++{ ++ static const char *hwcap_str[8] = { ++ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", ++ "edat" ++ }; ++ struct cpuinfo_S390 *cpuinfo; ++ unsigned long n = (unsigned long) v - 1; ++ int i; ++ ++ s390_adjust_jiffies(); ++ preempt_disable(); ++ if (!n) { ++ seq_printf(m, "vendor_id : IBM/S390\n" ++ "# processors : %i\n" ++ "bogomips per cpu: %lu.%02lu\n", ++ num_online_cpus(), loops_per_jiffy/(500000/HZ), ++ (loops_per_jiffy/(5000/HZ))%100); ++ seq_puts(m, "features\t: "); ++ for (i = 0; i < 8; i++) ++ if (hwcap_str[i] && (elf_hwcap & (1UL << i))) ++ seq_printf(m, "%s ", hwcap_str[i]); ++ seq_puts(m, "\n"); ++ } ++ ++ if (cpu_online(n)) { ++#ifdef CONFIG_SMP ++ if (smp_processor_id() == n) ++ cpuinfo = &S390_lowcore.cpu_data; ++ else ++ cpuinfo = &lowcore_ptr[n]->cpu_data; ++#else ++ cpuinfo = &S390_lowcore.cpu_data; ++#endif ++ seq_printf(m, "processor %li: " ++ "version = %02X, " ++ "identification = %06X, " ++ "machine = %04X\n", ++ n, cpuinfo->cpu_id.version, ++ cpuinfo->cpu_id.ident, ++ cpuinfo->cpu_id.machine); ++ } ++ preempt_enable(); ++ return 0; ++} ++ ++static void *c_start(struct seq_file *m, loff_t *pos) ++{ ++ return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; ++} ++ ++static void *c_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return c_start(m, pos); ++} ++ ++static void c_stop(struct seq_file *m, void *v) ++{ ++} ++ ++const struct seq_operations cpuinfo_op = { ++ .start = c_start, ++ .next = c_next, ++ .stop = c_stop, ++ .show = show_cpuinfo, ++}; ++ +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -14,6 +14,8 @@ + * This file handles the architecture-dependent parts of initialization + */ + ++#define KMSG_COMPONENT "setup" ++ + #include + #include + #include +@@ -32,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -291,8 +292,8 @@ unsigned int switch_amode = 0; + #endif + EXPORT_SYMBOL_GPL(switch_amode); + +-static void set_amode_and_uaccess(unsigned long user_amode, +- unsigned long user32_amode) ++static int set_amode_and_uaccess(unsigned long user_amode, ++ unsigned long user32_amode) + { + psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | +@@ -309,11 +310,11 @@ static void set_amode_and_uaccess(unsign + PSW_MASK_MCHECK | PSW_DEFAULT_KEY; + + if (MACHINE_HAS_MVCOS) { +- printk("mvcos available.\n"); + memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); ++ return 1; + } else { +- printk("mvcos not available.\n"); + memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); ++ return 0; + } + } + +@@ -328,9 +329,10 @@ static int __init early_parse_switch_amo + early_param("switch_amode", early_parse_switch_amode); + + #else /* CONFIG_S390_SWITCH_AMODE */ +-static inline void set_amode_and_uaccess(unsigned long user_amode, +- unsigned long user32_amode) ++static inline int set_amode_and_uaccess(unsigned long user_amode, ++ unsigned long user32_amode) + { ++ return 0; + } + #endif /* CONFIG_S390_SWITCH_AMODE */ + +@@ -355,11 +357,20 @@ early_param("noexec", early_parse_noexec + static void setup_addressing_mode(void) + { + if (s390_noexec) { +- printk("S390 execute protection active, "); +- set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY); ++ if (set_amode_and_uaccess(PSW_ASC_SECONDARY, ++ PSW32_ASC_SECONDARY)) ++ pr_info("Execute protection active, " ++ "mvcos available\n"); ++ else ++ pr_info("Execute protection active, " ++ "mvcos not available\n"); + } else if (switch_amode) { +- printk("S390 address spaces switched, "); +- set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); ++ if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY)) ++ pr_info("Address spaces switched, " ++ "mvcos available\n"); ++ else ++ pr_info("Address spaces switched, " ++ "mvcos not available\n"); + } + #ifdef CONFIG_TRACE_IRQFLAGS + sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; +@@ -572,15 +583,15 @@ setup_memory(void) + start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE; + + if (start + INITRD_SIZE > memory_end) { +- printk("initrd extends beyond end of memory " +- "(0x%08lx > 0x%08lx)\n" ++ pr_err("initrd extends beyond end of " ++ "memory (0x%08lx > 0x%08lx) " + "disabling initrd\n", + start + INITRD_SIZE, memory_end); + INITRD_START = INITRD_SIZE = 0; + } else { +- printk("Moving initrd (0x%08lx -> 0x%08lx, " +- "size: %ld)\n", +- INITRD_START, start, INITRD_SIZE); ++ pr_info("Moving initrd (0x%08lx -> " ++ "0x%08lx, size: %ld)\n", ++ INITRD_START, start, INITRD_SIZE); + memmove((void *) start, (void *) INITRD_START, + INITRD_SIZE); + INITRD_START = start; +@@ -642,8 +653,9 @@ setup_memory(void) + initrd_start = INITRD_START; + initrd_end = initrd_start + INITRD_SIZE; + } else { +- printk("initrd extends beyond end of memory " +- "(0x%08lx > 0x%08lx)\ndisabling initrd\n", ++ pr_err("initrd extends beyond end of " ++ "memory (0x%08lx > 0x%08lx) " ++ "disabling initrd\n", + initrd_start + INITRD_SIZE, memory_end); + initrd_start = initrd_end = 0; + } +@@ -756,21 +768,27 @@ setup_arch(char **cmdline_p) + * print what head.S has found out about the machine + */ + #ifndef CONFIG_64BIT +- printk((MACHINE_IS_VM) ? +- "We are running under VM (31 bit mode)\n" : +- "We are running native (31 bit mode)\n"); +- printk((MACHINE_HAS_IEEE) ? +- "This machine has an IEEE fpu\n" : +- "This machine has no IEEE fpu\n"); ++ if (MACHINE_IS_VM) ++ pr_info("Linux is running as a z/VM " ++ "guest operating system in 31-bit mode\n"); ++ else ++ pr_info("Linux is running natively in 31-bit mode\n"); ++ if (MACHINE_HAS_IEEE) ++ pr_info("The hardware system has IEEE compatible " ++ "floating point units\n"); ++ else ++ pr_info("The hardware system has no IEEE compatible " ++ "floating point units\n"); + #else /* CONFIG_64BIT */ + if (MACHINE_IS_VM) +- printk("We are running under VM (64 bit mode)\n"); ++ pr_info("Linux is running as a z/VM " ++ "guest operating system in 64-bit mode\n"); + else if (MACHINE_IS_KVM) { +- printk("We are running under KVM (64 bit mode)\n"); ++ pr_info("Linux is running under KVM in 64-bit mode\n"); + add_preferred_console("hvc", 0, NULL); + s390_virtio_console_init(); + } else +- printk("We are running native (64 bit mode)\n"); ++ pr_info("Linux is running natively in 64-bit mode\n"); + #endif /* CONFIG_64BIT */ + + /* Have one command line that is parsed and saved in /proc/cmdline */ +@@ -818,90 +836,3 @@ setup_arch(char **cmdline_p) + /* Setup zfcpdump support */ + setup_zfcpdump(console_devno); + } +- +-void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) +-{ +- printk(KERN_INFO "cpu %d " +-#ifdef CONFIG_SMP +- "phys_idx=%d " +-#endif +- "vers=%02X ident=%06X machine=%04X unused=%04X\n", +- cpuinfo->cpu_nr, +-#ifdef CONFIG_SMP +- cpuinfo->cpu_addr, +-#endif +- cpuinfo->cpu_id.version, +- cpuinfo->cpu_id.ident, +- cpuinfo->cpu_id.machine, +- cpuinfo->cpu_id.unused); +-} +- +-/* +- * show_cpuinfo - Get information on one CPU for use by procfs. +- */ +- +-static int show_cpuinfo(struct seq_file *m, void *v) +-{ +- static const char *hwcap_str[8] = { +- "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", +- "edat" +- }; +- struct cpuinfo_S390 *cpuinfo; +- unsigned long n = (unsigned long) v - 1; +- int i; +- +- s390_adjust_jiffies(); +- preempt_disable(); +- if (!n) { +- seq_printf(m, "vendor_id : IBM/S390\n" +- "# processors : %i\n" +- "bogomips per cpu: %lu.%02lu\n", +- num_online_cpus(), loops_per_jiffy/(500000/HZ), +- (loops_per_jiffy/(5000/HZ))%100); +- seq_puts(m, "features\t: "); +- for (i = 0; i < 8; i++) +- if (hwcap_str[i] && (elf_hwcap & (1UL << i))) +- seq_printf(m, "%s ", hwcap_str[i]); +- seq_puts(m, "\n"); +- } +- +- if (cpu_online(n)) { +-#ifdef CONFIG_SMP +- if (smp_processor_id() == n) +- cpuinfo = &S390_lowcore.cpu_data; +- else +- cpuinfo = &lowcore_ptr[n]->cpu_data; +-#else +- cpuinfo = &S390_lowcore.cpu_data; +-#endif +- seq_printf(m, "processor %li: " +- "version = %02X, " +- "identification = %06X, " +- "machine = %04X\n", +- n, cpuinfo->cpu_id.version, +- cpuinfo->cpu_id.ident, +- cpuinfo->cpu_id.machine); +- } +- preempt_enable(); +- return 0; +-} +- +-static void *c_start(struct seq_file *m, loff_t *pos) +-{ +- return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL; +-} +-static void *c_next(struct seq_file *m, void *v, loff_t *pos) +-{ +- ++*pos; +- return c_start(m, pos); +-} +-static void c_stop(struct seq_file *m, void *v) +-{ +-} +-const struct seq_operations cpuinfo_op = { +- .start = c_start, +- .next = c_next, +- .stop = c_stop, +- .show = show_cpuinfo, +-}; +- +--- a/arch/s390/kernel/smp.c ++++ b/arch/s390/kernel/smp.c +@@ -20,6 +20,8 @@ + * cpu_number_map in other architectures. + */ + ++#define KMSG_COMPONENT "cpu" ++ + #include + #include + #include +@@ -388,8 +390,8 @@ static void __init smp_get_save_area(uns + if (ipl_info.type != IPL_TYPE_FCP_DUMP) + return; + if (cpu >= NR_CPUS) { +- printk(KERN_WARNING "Registers for cpu %i not saved since dump " +- "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS); ++ pr_warning("CPU %i exceeds the maximum %i and is excluded from " ++ "the dump\n", cpu, NR_CPUS - 1); + return; + } + zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL); +@@ -562,7 +564,7 @@ static void __init smp_detect_cpus(void) + } + out: + kfree(info); +- printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus); ++ pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus); + get_online_cpus(); + __smp_rescan_cpus(); + put_online_cpus(); +@@ -688,12 +690,8 @@ int __cpuinit __cpu_up(unsigned int cpu) + + ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]), + cpu, sigp_set_prefix); +- if (ccode) { +- printk("sigp_set_prefix failed for cpu %d " +- "with condition code %d\n", +- (int) cpu, (int) ccode); ++ if (ccode) + return -EIO; +- } + + idle = current_set[cpu]; + cpu_lowcore = lowcore_ptr[cpu]; +@@ -776,7 +774,7 @@ void __cpu_die(unsigned int cpu) + while (!smp_cpu_not_running(cpu)) + cpu_relax(); + smp_free_lowcore(cpu); +- printk(KERN_INFO "Processor %d spun down\n", cpu); ++ pr_info("Processor %d stopped\n", cpu); + } + + void cpu_die(void) +--- a/arch/s390/kernel/time.c ++++ b/arch/s390/kernel/time.c +@@ -12,6 +12,8 @@ + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + */ + ++#define KMSG_COMPONENT "time" ++ + #include + #include + #include +@@ -291,8 +293,8 @@ static unsigned long long adjust_time(un + } + jiffies_timer_cc += delta; + if (adjust.offset != 0) { +- printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", +- adjust.offset); ++ pr_notice("The ETR interface has adjusted the clock " ++ "by %li microseconds\n", adjust.offset); + adjust.modes = ADJ_OFFSET_SINGLESHOT; + do_adjtimex(&adjust); + } +@@ -443,8 +445,8 @@ static void etr_reset(void) + etr_tolec = get_clock(); + set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); + } else if (etr_port0_online || etr_port1_online) { +- printk(KERN_WARNING "Running on non ETR capable " +- "machine, only local mode available.\n"); ++ pr_warning("The real or virtual hardware system does " ++ "not provide an ETR interface\n"); + etr_port0_online = etr_port1_online = 0; + } + } +@@ -1359,7 +1361,8 @@ static void __init stp_reset(void) + if (rc == 1) + set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); + else if (stp_online) { +- printk(KERN_WARNING "Running on non STP capable machine.\n"); ++ pr_warning("The real or virtual hardware system does " ++ "not provide an STP interface\n"); + free_bootmem((unsigned long) stp_page, PAGE_SIZE); + stp_page = NULL; + stp_online = 0; +--- a/arch/s390/kernel/topology.c ++++ b/arch/s390/kernel/topology.c +@@ -3,6 +3,8 @@ + * Author(s): Heiko Carstens + */ + ++#define KMSG_COMPONENT "cpu" ++ + #include + #include + #include +@@ -311,7 +313,7 @@ void __init s390_init_cpu_topology(void) + for (i = 0; i < info->mnest - 2; i++) + nr_cores *= info->mag[NR_MAG - 3 - i]; + +- printk(KERN_INFO "CPU topology:"); ++ pr_info("The CPU configuration topology of the machine is:"); + for (i = 0; i < NR_MAG; i++) + printk(" %d", info->mag[i]); + printk(" / %d\n", info->mnest); +--- a/arch/s390/mm/extmem.c ++++ b/arch/s390/mm/extmem.c +@@ -7,6 +7,8 @@ + * (C) IBM Corporation 2002-2004 + */ + ++#define KMSG_COMPONENT "extmem" ++ + #include + #include + #include +@@ -24,19 +26,6 @@ + #include + #include + +-#define DCSS_DEBUG /* Debug messages on/off */ +- +-#define DCSS_NAME "extmem" +-#ifdef DCSS_DEBUG +-#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSS_NAME " debug:" x) +-#else +-#define PRINT_DEBUG(x...) do {} while (0) +-#endif +-#define PRINT_INFO(x...) printk(KERN_INFO DCSS_NAME " info:" x) +-#define PRINT_WARN(x...) printk(KERN_WARNING DCSS_NAME " warning:" x) +-#define PRINT_ERR(x...) printk(KERN_ERR DCSS_NAME " error:" x) +- +- + #define DCSS_LOADSHR 0x00 + #define DCSS_LOADNSR 0x04 + #define DCSS_PURGESEG 0x08 +@@ -286,7 +275,7 @@ query_segment_type (struct dcss_segment + goto out_free; + } + if (diag_cc > 1) { +- PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc); ++ pr_warning("Querying a DCSS type failed with rc=%ld\n", vmrc); + rc = dcss_diag_translate_rc (vmrc); + goto out_free; + } +@@ -368,7 +357,6 @@ query_segment_type (struct dcss_segment + * -EIO : could not perform query diagnose + * -ENOENT : no such segment + * -ENOTSUPP: multi-part segment cannot be used with linux +- * -ENOSPC : segment cannot be used (overlaps with storage) + * -ENOMEM : out of memory + * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h + */ +@@ -480,9 +468,8 @@ __segment_load (char *name, int do_nonsh + goto out_resource; + } + if (diag_cc > 1) { +- PRINT_WARN ("segment_load: could not load segment %s - " +- "diag returned error (%ld)\n", +- name, end_addr); ++ pr_warning("Loading DCSS %s failed with rc=%ld\n", name, ++ end_addr); + rc = dcss_diag_translate_rc(end_addr); + dcss_diag(&purgeseg_scode, seg->dcss_name, + &dummy, &dummy); +@@ -496,15 +483,13 @@ __segment_load (char *name, int do_nonsh + *addr = seg->start_addr; + *end = seg->end; + if (do_nonshared) +- PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " +- "type %s in non-shared mode\n", name, +- (void*)seg->start_addr, (void*)seg->end, +- segtype_string[seg->vm_segtype]); ++ pr_info("DCSS %s of range %p to %p and type %s loaded as " ++ "exclusive-writable\n", name, (void*) seg->start_addr, ++ (void*) seg->end, segtype_string[seg->vm_segtype]); + else { +- PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " +- "type %s in shared mode\n", name, +- (void*)seg->start_addr, (void*)seg->end, +- segtype_string[seg->vm_segtype]); ++ pr_info("DCSS %s of range %p to %p and type %s loaded in " ++ "shared access mode\n", name, (void*) seg->start_addr, ++ (void*) seg->end, segtype_string[seg->vm_segtype]); + } + goto out; + out_resource: +@@ -593,14 +578,14 @@ segment_modify_shared (char *name, int d + goto out_unlock; + } + if (do_nonshared == seg->do_nonshared) { +- PRINT_INFO ("segment_modify_shared: not reloading segment %s" +- " - already in requested mode\n",name); ++ pr_info("DCSS %s is already in the requested access " ++ "mode\n", name); + rc = 0; + goto out_unlock; + } + if (atomic_read (&seg->ref_count) != 1) { +- PRINT_WARN ("segment_modify_shared: not reloading segment %s - " +- "segment is in use by other driver(s)\n",name); ++ pr_warning("DCSS %s is in use and cannot be reloaded\n", ++ name); + rc = -EAGAIN; + goto out_unlock; + } +@@ -613,8 +598,8 @@ segment_modify_shared (char *name, int d + seg->res->flags |= IORESOURCE_READONLY; + + if (request_resource(&iomem_resource, seg->res)) { +- PRINT_WARN("segment_modify_shared: could not reload segment %s" +- " - overlapping resources\n", name); ++ pr_warning("DCSS %s overlaps with used memory resources " ++ "and cannot be reloaded\n", name); + rc = -EBUSY; + kfree(seg->res); + goto out_del_mem; +@@ -632,9 +617,8 @@ segment_modify_shared (char *name, int d + goto out_del_res; + } + if (diag_cc > 1) { +- PRINT_WARN ("segment_modify_shared: could not reload segment %s" +- " - diag returned error (%ld)\n", +- name, end_addr); ++ pr_warning("Reloading DCSS %s failed with rc=%ld\n", name, ++ end_addr); + rc = dcss_diag_translate_rc(end_addr); + goto out_del_res; + } +@@ -673,8 +657,7 @@ segment_unload(char *name) + mutex_lock(&dcss_lock); + seg = segment_by_name (name); + if (seg == NULL) { +- PRINT_ERR ("could not find segment %s in segment_unload, " +- "please report to linux390@de.ibm.com\n",name); ++ pr_err("Unloading unknown DCSS %s failed\n", name); + goto out_unlock; + } + if (atomic_dec_return(&seg->ref_count) != 0) +@@ -709,8 +692,7 @@ segment_save(char *name) + seg = segment_by_name (name); + + if (seg == NULL) { +- PRINT_ERR("could not find segment %s in segment_save, please " +- "report to linux390@de.ibm.com\n", name); ++ pr_err("Saving unknown DCSS %s failed\n", name); + goto out; + } + +@@ -727,14 +709,14 @@ segment_save(char *name) + response = 0; + cpcmd(cmd1, NULL, 0, &response); + if (response) { +- PRINT_ERR("segment_save: DEFSEG failed with response code %i\n", +- response); ++ pr_err("Saving a DCSS failed with DEFSEG response code " ++ "%i\n", response); + goto out; + } + cpcmd(cmd2, NULL, 0, &response); + if (response) { +- PRINT_ERR("segment_save: SAVESEG failed with response code %i\n", +- response); ++ pr_err("Saving a DCSS failed with SAVESEG response code " ++ "%i\n", response); + goto out; + } + out: +@@ -749,44 +731,41 @@ void segment_warning(int rc, char *seg_n + { + switch (rc) { + case -ENOENT: +- PRINT_WARN("cannot load/query segment %s, " +- "does not exist\n", seg_name); ++ pr_err("DCSS %s cannot be loaded or queried\n", seg_name); + break; + case -ENOSYS: +- PRINT_WARN("cannot load/query segment %s, " +- "not running on VM\n", seg_name); ++ pr_err("DCSS %s cannot be loaded or queried without " ++ "z/VM\n", seg_name); + break; + case -EIO: +- PRINT_WARN("cannot load/query segment %s, " +- "hardware error\n", seg_name); ++ pr_err("Loading or querying DCSS %s resulted in a " ++ "hardware error\n", seg_name); + break; + case -ENOTSUPP: +- PRINT_WARN("cannot load/query segment %s, " +- "is a multi-part segment\n", seg_name); ++ pr_err("DCSS %s has multiple page ranges and cannot be " ++ "loaded or queried\n", seg_name); + break; + case -ENOSPC: +- PRINT_WARN("cannot load/query segment %s, " +- "overlaps with storage\n", seg_name); ++ pr_err("DCSS %s overlaps with used storage and cannot " ++ "be loaded\n", seg_name); + break; + case -EBUSY: +- PRINT_WARN("cannot load/query segment %s, " +- "overlaps with already loaded dcss\n", seg_name); ++ pr_err("%s needs used memory resources and cannot be " ++ "loaded or queried\n", seg_name); + break; + case -EPERM: +- PRINT_WARN("cannot load/query segment %s, " +- "already loaded in incompatible mode\n", seg_name); ++ pr_err("DCSS %s is already loaded in a different access " ++ "mode\n", seg_name); + break; + case -ENOMEM: +- PRINT_WARN("cannot load/query segment %s, " +- "out of memory\n", seg_name); ++ pr_err("There is not enough memory to load or query " ++ "DCSS %s\n", seg_name); + break; + case -ERANGE: +- PRINT_WARN("cannot load/query segment %s, " +- "exceeds kernel mapping range\n", seg_name); ++ pr_err("DCSS %s exceeds the kernel mapping range (%lu) " ++ "and cannot be loaded\n", seg_name, VMEM_MAX_PHYS); + break; + default: +- PRINT_WARN("cannot load/query segment %s, " +- "return value %i\n", seg_name, rc); + break; + } + } +--- a/drivers/s390/block/dcssblk.c ++++ b/drivers/s390/block/dcssblk.c +@@ -4,6 +4,8 @@ + * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer + */ + ++#define KMSG_COMPONENT "dcssblk" ++ + #include + #include + #include +@@ -17,20 +19,10 @@ + #include + #include + +-//#define DCSSBLK_DEBUG /* Debug messages on/off */ + #define DCSSBLK_NAME "dcssblk" + #define DCSSBLK_MINORS_PER_DISK 1 + #define DCSSBLK_PARM_LEN 400 + +-#ifdef DCSSBLK_DEBUG +-#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x) +-#else +-#define PRINT_DEBUG(x...) do {} while (0) +-#endif +-#define PRINT_INFO(x...) printk(KERN_INFO DCSSBLK_NAME " info: " x) +-#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) +-#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) +- + static int dcssblk_open(struct inode *inode, struct file *filp); + static int dcssblk_release(struct inode *inode, struct file *filp); + static int dcssblk_make_request(struct request_queue *q, struct bio *bio); +@@ -261,10 +253,9 @@ dcssblk_is_continuous(struct dcssblk_dev + /* check continuity */ + for (i = 0; i < dev_info->num_of_segments - 1; i++) { + if ((sort_list[i].end + 1) != sort_list[i+1].start) { +- PRINT_ERR("Segment %s is not contiguous with " +- "segment %s\n", +- sort_list[i].segment_name, +- sort_list[i+1].segment_name); ++ pr_err("Adjacent DCSSs %s and %s are not " ++ "contiguous\n", sort_list[i].segment_name, ++ sort_list[i+1].segment_name); + rc = -EINVAL; + goto out; + } +@@ -275,10 +266,10 @@ dcssblk_is_continuous(struct dcssblk_dev + !(sort_list[i+1].segment_type & + SEGMENT_EXCLUSIVE) || + (sort_list[i+1].segment_type == SEG_TYPE_ER)) { +- PRINT_ERR("Segment %s has different type from " +- "segment %s\n", +- sort_list[i].segment_name, +- sort_list[i+1].segment_name); ++ pr_err("DCSS %s and DCSS %s have " ++ "incompatible types\n", ++ sort_list[i].segment_name, ++ sort_list[i+1].segment_name); + rc = -EINVAL; + goto out; + } +@@ -380,8 +371,9 @@ dcssblk_shared_store(struct device *dev, + } else if (inbuf[0] == '0') { + /* reload segments in exclusive mode */ + if (dev_info->segment_type == SEG_TYPE_SC) { +- PRINT_ERR("Segment type SC (%s) cannot be loaded in " +- "non-shared mode\n", dev_info->segment_name); ++ pr_err("DCSS %s is of type SC and cannot be " ++ "loaded as exclusive-writable\n", ++ dev_info->segment_name); + rc = -EINVAL; + goto out; + } +@@ -404,9 +396,8 @@ dcssblk_shared_store(struct device *dev, + goto out; + + removeseg: +- PRINT_ERR("Could not reload segment(s) of the device %s, removing " +- "segment(s) now!\n", +- dev_info->segment_name); ++ pr_err("DCSS device %s is removed after a failed access mode " ++ "change\n", dev_info->segment_name); + temp = entry; + list_for_each_entry(entry, &dev_info->seg_list, lh) { + if (entry != temp) +@@ -454,17 +445,17 @@ dcssblk_save_store(struct device *dev, s + if (inbuf[0] == '1') { + if (atomic_read(&dev_info->use_count) == 0) { + // device is idle => we save immediately +- PRINT_INFO("Saving segment(s) of the device %s\n", +- dev_info->segment_name); ++ pr_info("All DCSSs that map to device %s are " ++ "saved\n", dev_info->segment_name); + list_for_each_entry(entry, &dev_info->seg_list, lh) { + segment_save(entry->segment_name); + } + } else { + // device is busy => we save it when it becomes + // idle in dcssblk_release +- PRINT_INFO("Device %s is currently busy, segment(s) " +- "will be saved when it becomes idle...\n", +- dev_info->segment_name); ++ pr_info("Device %s is in use, its DCSSs will be " ++ "saved when it becomes idle\n", ++ dev_info->segment_name); + dev_info->save_pending = 1; + } + } else if (inbuf[0] == '0') { +@@ -472,9 +463,9 @@ dcssblk_save_store(struct device *dev, s + // device is busy & the user wants to undo his save + // request + dev_info->save_pending = 0; +- PRINT_INFO("Pending save for segment(s) of the device " +- "%s deactivated\n", +- dev_info->segment_name); ++ pr_info("A pending save request for device %s " ++ "has been canceled\n", ++ dev_info->segment_name); + } + } else { + up_write(&dcssblk_devices_sem); +@@ -614,9 +605,8 @@ dcssblk_add_store(struct device *dev, st + + seg_byte_size = (dev_info->end - dev_info->start + 1); + set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors +- PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, " +- "capacity = %lu (512 Byte) sectors\n", local_buf, +- seg_byte_size, seg_byte_size >> 9); ++ pr_info("Loaded %s with total size %lu bytes and capacity %lu " ++ "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9); + + dev_info->save_pending = 0; + dev_info->is_shared = 1; +@@ -744,13 +734,15 @@ dcssblk_remove_store(struct device *dev, + dev_info = dcssblk_get_device_by_name(local_buf); + if (dev_info == NULL) { + up_write(&dcssblk_devices_sem); +- PRINT_WARN("Device %s is not loaded!\n", local_buf); ++ pr_warning("Device %s cannot be removed because it is not a " ++ "known device\n", local_buf); + rc = -ENODEV; + goto out_buf; + } + if (atomic_read(&dev_info->use_count) != 0) { + up_write(&dcssblk_devices_sem); +- PRINT_WARN("Device %s is in use!\n", local_buf); ++ pr_warning("Device %s cannot be removed while it is in " ++ "use\n", local_buf); + rc = -EBUSY; + goto out_buf; + } +@@ -808,8 +800,8 @@ dcssblk_release(struct inode *inode, str + down_write(&dcssblk_devices_sem); + if (atomic_dec_and_test(&dev_info->use_count) + && (dev_info->save_pending)) { +- PRINT_INFO("Device %s became idle and is being saved now\n", +- dev_info->segment_name); ++ pr_info("Device %s has become idle and is being saved " ++ "now\n", dev_info->segment_name); + list_for_each_entry(entry, &dev_info->seg_list, lh) { + segment_save(entry->segment_name); + } +@@ -852,8 +844,9 @@ dcssblk_make_request(struct request_queu + case SEG_TYPE_SC: + /* cannot write to these segments */ + if (bio_data_dir(bio) == WRITE) { +- PRINT_WARN("rejecting write to ro device %s\n", +- dev_info->dev.bus_id); ++ pr_warning("Writing to %s failed because it " ++ "is a read-only device\n", ++ dev_name(&dev_info->dev)); + goto fail; + } + } +--- a/drivers/s390/block/xpram.c ++++ b/drivers/s390/block/xpram.c +@@ -25,6 +25,8 @@ + * generic hard disk support to replace ad-hoc partitioning + */ + ++#define KMSG_COMPONENT "xpram" ++ + #include + #include + #include /* isdigit, isxdigit */ +@@ -42,12 +44,6 @@ + #define XPRAM_DEVS 1 /* one partition */ + #define XPRAM_MAX_DEVS 32 /* maximal number of devices (partitions) */ + +-#define PRINT_DEBUG(x...) printk(KERN_DEBUG XPRAM_NAME " debug:" x) +-#define PRINT_INFO(x...) printk(KERN_INFO XPRAM_NAME " info:" x) +-#define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) +-#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) +- +- + typedef struct { + unsigned int size; /* size of xpram segment in pages */ + unsigned int offset; /* start page of xpram segment */ +@@ -263,7 +259,7 @@ static int __init xpram_setup_sizes(unsi + + /* Check number of devices. */ + if (devs <= 0 || devs > XPRAM_MAX_DEVS) { +- PRINT_ERR("invalid number %d of devices\n",devs); ++ pr_err("%d is not a valid number of XPRAM devices\n",devs); + return -EINVAL; + } + xpram_devs = devs; +@@ -294,22 +290,22 @@ static int __init xpram_setup_sizes(unsi + mem_auto_no++; + } + +- PRINT_INFO(" number of devices (partitions): %d \n", xpram_devs); ++ pr_info(" number of devices (partitions): %d \n", xpram_devs); + for (i = 0; i < xpram_devs; i++) { + if (xpram_sizes[i]) +- PRINT_INFO(" size of partition %d: %u kB\n", +- i, xpram_sizes[i]); ++ pr_info(" size of partition %d: %u kB\n", ++ i, xpram_sizes[i]); + else +- PRINT_INFO(" size of partition %d to be set " +- "automatically\n",i); ++ pr_info(" size of partition %d to be set " ++ "automatically\n",i); + } +- PRINT_DEBUG(" memory needed (for sized partitions): %lu kB\n", +- mem_needed); +- PRINT_DEBUG(" partitions to be sized automatically: %d\n", +- mem_auto_no); ++ pr_info(" memory needed (for sized partitions): %lu kB\n", ++ mem_needed); ++ pr_info(" partitions to be sized automatically: %d\n", ++ mem_auto_no); + + if (mem_needed > pages * 4) { +- PRINT_ERR("Not enough expanded memory available\n"); ++ pr_err("Not enough expanded memory available\n"); + return -EINVAL; + } + +@@ -321,8 +317,8 @@ static int __init xpram_setup_sizes(unsi + */ + if (mem_auto_no) { + mem_auto = ((pages - mem_needed / 4) / mem_auto_no) * 4; +- PRINT_INFO(" automatically determined " +- "partition size: %lu kB\n", mem_auto); ++ pr_info(" automatically determined " ++ "partition size: %lu kB\n", mem_auto); + for (i = 0; i < xpram_devs; i++) + if (xpram_sizes[i] == 0) + xpram_sizes[i] = mem_auto; +@@ -412,12 +408,12 @@ static int __init xpram_init(void) + + /* Find out size of expanded memory. */ + if (xpram_present() != 0) { +- PRINT_WARN("No expanded memory available\n"); ++ pr_err("No expanded memory available\n"); + return -ENODEV; + } + xpram_pages = xpram_highest_page_index() + 1; +- PRINT_INFO(" %u pages expanded memory found (%lu KB).\n", +- xpram_pages, (unsigned long) xpram_pages*4); ++ pr_info(" %u pages expanded memory found (%lu KB).\n", ++ xpram_pages, (unsigned long) xpram_pages*4); + rc = xpram_setup_sizes(xpram_pages); + if (rc) + return rc; +--- a/drivers/s390/char/monreader.c ++++ b/drivers/s390/char/monreader.c +@@ -7,6 +7,8 @@ + * Author: Gerald Schaefer + */ + ++#define KMSG_COMPONENT "monreader" ++ + #include + #include + #include +@@ -24,19 +26,6 @@ + #include + #include + +-//#define MON_DEBUG /* Debug messages on/off */ +- +-#define MON_NAME "monreader" +- +-#define P_INFO(x...) printk(KERN_INFO MON_NAME " info: " x) +-#define P_ERROR(x...) printk(KERN_ERR MON_NAME " error: " x) +-#define P_WARNING(x...) printk(KERN_WARNING MON_NAME " warning: " x) +- +-#ifdef MON_DEBUG +-#define P_DEBUG(x...) printk(KERN_DEBUG MON_NAME " debug: " x) +-#else +-#define P_DEBUG(x...) do {} while (0) +-#endif + + #define MON_COLLECT_SAMPLE 0x80 + #define MON_COLLECT_EVENT 0x40 +@@ -172,7 +161,7 @@ static int mon_send_reply(struct mon_msg + } else + monmsg->replied_msglim = 1; + if (rc) { +- P_ERROR("read, IUCV reply failed with rc = %i\n\n", rc); ++ pr_err("Reading monitor data failed with rc=%i\n", rc); + return -EIO; + } + return 0; +@@ -251,7 +240,8 @@ static void mon_iucv_path_severed(struct + { + struct mon_private *monpriv = path->private; + +- P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); ++ pr_err("z/VM *MONITOR system service disconnected with rc=%i\n", ++ ipuser[0]); + iucv_path_sever(path, NULL); + atomic_set(&monpriv->iucv_severed, 1); + wake_up(&mon_conn_wait_queue); +@@ -266,8 +256,7 @@ static void mon_iucv_message_pending(str + memcpy(&monpriv->msg_array[monpriv->write_index]->msg, + msg, sizeof(*msg)); + if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { +- P_WARNING("IUCV message pending, message limit (%i) reached\n", +- MON_MSGLIM); ++ pr_warning("The read queue for monitor data is full\n"); + monpriv->msg_array[monpriv->write_index]->msglim_reached = 1; + } + monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM; +@@ -311,8 +300,8 @@ static int mon_open(struct inode *inode, + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); + if (rc) { +- P_ERROR("iucv connection to *MONITOR failed with " +- "IPUSER SEVER code = %i\n", rc); ++ pr_err("Connecting to the z/VM *MONITOR system service " ++ "failed with rc=%i\n", rc); + rc = -EIO; + goto out_path; + } +@@ -353,7 +342,8 @@ static int mon_close(struct inode *inode + */ + rc = iucv_path_sever(monpriv->path, user_data_sever); + if (rc) +- P_ERROR("close, iucv_sever failed with rc = %i\n", rc); ++ pr_warning("Disconnecting the z/VM *MONITOR system service " ++ "failed with rc=%i\n", rc); + + atomic_set(&monpriv->iucv_severed, 0); + atomic_set(&monpriv->iucv_connected, 0); +@@ -469,7 +459,8 @@ static int __init mon_init(void) + int rc; + + if (!MACHINE_IS_VM) { +- P_ERROR("not running under z/VM, driver not loaded\n"); ++ pr_err("The z/VM *MONITOR record device driver cannot be " ++ "loaded without z/VM\n"); + return -ENODEV; + } + +@@ -478,7 +469,8 @@ static int __init mon_init(void) + */ + rc = iucv_register(&monreader_iucv_handler, 1); + if (rc) { +- P_ERROR("failed to register with iucv driver\n"); ++ pr_err("The z/VM *MONITOR record device driver failed to " ++ "register with IUCV\n"); + return rc; + } + +@@ -488,8 +480,8 @@ static int __init mon_init(void) + goto out_iucv; + } + if (rc != SEG_TYPE_SC) { +- P_ERROR("segment %s has unsupported type, should be SC\n", +- mon_dcss_name); ++ pr_err("The specified *MONITOR DCSS %s does not have the " ++ "required type SC\n", mon_dcss_name); + rc = -EINVAL; + goto out_iucv; + } +--- a/drivers/s390/char/monwriter.c ++++ b/drivers/s390/char/monwriter.c +@@ -8,6 +8,8 @@ + * Author(s): Melissa Howland + */ + ++#define KMSG_COMPONENT "monwriter" ++ + #include + #include + #include +@@ -64,9 +66,9 @@ static int monwrite_diag(struct monwrite + rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen); + if (rc <= 0) + return rc; ++ pr_err("Writing monitor data failed with rc=%i\n", rc); + if (rc == 5) + return -EPERM; +- printk("DIAG X'DC' error with return code: %i\n", rc); + return -EINVAL; + } + +--- a/drivers/s390/char/sclp_cmd.c ++++ b/drivers/s390/char/sclp_cmd.c +@@ -6,6 +6,8 @@ + * Peter Oberparleiter + */ + ++#define KMSG_COMPONENT "sclp_cmd" ++ + #include + #include + #include +@@ -16,9 +18,8 @@ + #include + #include + #include +-#include "sclp.h" + +-#define TAG "sclp_cmd: " ++#include "sclp.h" + + #define SCLP_CMDW_READ_SCP_INFO 0x00020001 + #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 +@@ -169,8 +170,8 @@ static int do_sync_request(sclp_cmdw_t c + + /* Check response. */ + if (request->status != SCLP_REQ_DONE) { +- printk(KERN_WARNING TAG "sync request failed " +- "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status); ++ pr_warning("sync request failed (cmd=0x%08x, " ++ "status=0x%02x)\n", cmd, request->status); + rc = -EIO; + } + out: +@@ -224,8 +225,8 @@ int sclp_get_cpu_info(struct sclp_cpu_in + if (rc) + goto out; + if (sccb->header.response_code != 0x0010) { +- printk(KERN_WARNING TAG "readcpuinfo failed " +- "(response=0x%04x)\n", sccb->header.response_code); ++ pr_warning("readcpuinfo failed (response=0x%04x)\n", ++ sccb->header.response_code); + rc = -EIO; + goto out; + } +@@ -262,8 +263,9 @@ static int do_cpu_configure(sclp_cmdw_t + case 0x0120: + break; + default: +- printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, " +- "response=0x%04x)\n", cmd, sccb->header.response_code); ++ pr_warning("configure cpu failed (cmd=0x%08x, " ++ "response=0x%04x)\n", cmd, ++ sccb->header.response_code); + rc = -EIO; + break; + } +@@ -623,9 +625,9 @@ static int do_chp_configure(sclp_cmdw_t + case 0x0450: + break; + default: +- printk(KERN_WARNING TAG "configure channel-path failed " +- "(cmd=0x%08x, response=0x%04x)\n", cmd, +- sccb->header.response_code); ++ pr_warning("configure channel-path failed " ++ "(cmd=0x%08x, response=0x%04x)\n", cmd, ++ sccb->header.response_code); + rc = -EIO; + break; + } +@@ -692,8 +694,8 @@ int sclp_chp_read_info(struct sclp_chp_i + if (rc) + goto out; + if (sccb->header.response_code != 0x0010) { +- printk(KERN_WARNING TAG "read channel-path info failed " +- "(response=0x%04x)\n", sccb->header.response_code); ++ pr_warning("read channel-path info failed " ++ "(response=0x%04x)\n", sccb->header.response_code); + rc = -EIO; + goto out; + } +--- a/drivers/s390/char/sclp_config.c ++++ b/drivers/s390/char/sclp_config.c +@@ -5,15 +5,16 @@ + * Author(s): Heiko Carstens + */ + ++#define KMSG_COMPONENT "sclp_config" ++ + #include + #include + #include + #include + #include + #include +-#include "sclp.h" + +-#define TAG "sclp_config: " ++#include "sclp.h" + + struct conf_mgm_data { + u8 reserved; +@@ -31,7 +32,7 @@ static void sclp_cpu_capability_notify(s + int cpu; + struct sys_device *sysdev; + +- printk(KERN_WARNING TAG "cpu capability changed.\n"); ++ pr_warning("cpu capability changed.\n"); + get_online_cpus(); + for_each_online_cpu(cpu) { + sysdev = get_cpu_sysdev(cpu); +@@ -78,7 +79,7 @@ static int __init sclp_conf_init(void) + return rc; + + if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { +- printk(KERN_WARNING TAG "no configuration management.\n"); ++ pr_warning("no configuration management.\n"); + sclp_unregister(&sclp_conf_register); + rc = -ENOSYS; + } +--- a/drivers/s390/char/sclp_cpi_sys.c ++++ b/drivers/s390/char/sclp_cpi_sys.c +@@ -7,6 +7,8 @@ + * Michael Ernst + */ + ++#define KMSG_COMPONENT "sclp_cpi" ++ + #include + #include + #include +@@ -20,6 +22,7 @@ + #include + #include + #include ++ + #include "sclp.h" + #include "sclp_rw.h" + #include "sclp_cpi_sys.h" +@@ -150,16 +153,16 @@ static int cpi_req(void) + wait_for_completion(&completion); + + if (req->status != SCLP_REQ_DONE) { +- printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n", +- req->status); ++ pr_warning("request failed (status=0x%02x)\n", ++ req->status); + rc = -EIO; + goto out_free_req; + } + + response = ((struct cpi_sccb *) req->sccb)->header.response_code; + if (response != 0x0020) { +- printk(KERN_WARNING "cpi: failed with " +- "response code 0x%x\n", response); ++ pr_warning("request failed with response code 0x%x\n", ++ response); + rc = -EIO; + } + +--- a/drivers/s390/char/sclp_sdias.c ++++ b/drivers/s390/char/sclp_sdias.c +@@ -5,15 +5,17 @@ + * Author(s): Michael Holzheu + */ + ++#define KMSG_COMPONENT "sclp_sdias" ++ + #include + #include + #include + #include ++ + #include "sclp.h" + #include "sclp_rw.h" + + #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) +-#define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x ) + + #define SDIAS_RETRIES 300 + #define SDIAS_SLEEP_TICKS 50 +@@ -131,7 +133,7 @@ int sclp_sdias_blk_count(void) + + rc = sdias_sclp_send(&request); + if (rc) { +- ERROR_MSG("sclp_send failed for get_nr_blocks\n"); ++ pr_err("sclp_send failed for get_nr_blocks\n"); + goto out; + } + if (sccb.hdr.response_code != 0x0020) { +@@ -145,7 +147,8 @@ int sclp_sdias_blk_count(void) + rc = sccb.evbuf.blk_cnt; + break; + default: +- ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status); ++ pr_err("SCLP error: %x\n", ++ sccb.evbuf.event_status); + rc = -EIO; + goto out; + } +@@ -201,7 +204,7 @@ int sclp_sdias_copy(void *dest, int star + + rc = sdias_sclp_send(&request); + if (rc) { +- ERROR_MSG("sclp_send failed: %x\n", rc); ++ pr_err("sclp_send failed: %x\n", rc); + goto out; + } + if (sccb.hdr.response_code != 0x0020) { +@@ -219,9 +222,9 @@ int sclp_sdias_copy(void *dest, int star + case EVSTATE_NO_DATA: + TRACE("no data\n"); + default: +- ERROR_MSG("Error from SCLP while copying hsa. " +- "Event status = %x\n", +- sccb.evbuf.event_status); ++ pr_err("Error from SCLP while copying hsa. " ++ "Event status = %x\n", ++ sccb.evbuf.event_status); + rc = -EIO; + } + out: +--- a/drivers/s390/char/vmcp.c ++++ b/drivers/s390/char/vmcp.c +@@ -11,6 +11,8 @@ + * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS + */ + ++#define KMSG_COMPONENT "vmcp" ++ + #include + #include + #include +@@ -26,8 +28,6 @@ MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Christian Borntraeger "); + MODULE_DESCRIPTION("z/VM CP interface"); + +-#define PRINTK_HEADER "vmcp: " +- + static debug_info_t *vmcp_debug; + + static int vmcp_open(struct inode *inode, struct file *file) +@@ -193,7 +193,8 @@ static int __init vmcp_init(void) + int ret; + + if (!MACHINE_IS_VM) { +- PRINT_WARN("z/VM CP interface is only available under z/VM\n"); ++ pr_warning("The z/VM CP interface device driver cannot be " ++ "loaded without z/VM\n"); + return -ENODEV; + } + +--- a/drivers/s390/char/vmlogrdr.c ++++ b/drivers/s390/char/vmlogrdr.c +@@ -10,6 +10,9 @@ + * Stefan Weinhuber + * + */ ++ ++#define KMSG_COMPONENT "vmlogrdr" ++ + #include + #include + #include +@@ -28,8 +31,6 @@ + #include + #include + +- +- + MODULE_AUTHOR + ("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n" + " Stefan Weinhuber (wein@de.ibm.com)"); +@@ -174,8 +175,7 @@ static void vmlogrdr_iucv_path_severed(s + struct vmlogrdr_priv_t * logptr = path->private; + u8 reason = (u8) ipuser[8]; + +- printk (KERN_ERR "vmlogrdr: connection severed with" +- " reason %i\n", reason); ++ pr_err("vmlogrdr: connection severed with reason %i\n", reason); + + iucv_path_sever(path, NULL); + kfree(path); +@@ -333,8 +333,8 @@ static int vmlogrdr_open (struct inode * + if (logptr->autorecording) { + ret = vmlogrdr_recording(logptr,1,logptr->autopurge); + if (ret) +- printk (KERN_WARNING "vmlogrdr: failed to start " +- "recording automatically\n"); ++ pr_warning("vmlogrdr: failed to start " ++ "recording automatically\n"); + } + + /* create connection to the system service */ +@@ -345,9 +345,9 @@ static int vmlogrdr_open (struct inode * + logptr->system_service, NULL, NULL, + logptr); + if (connect_rc) { +- printk (KERN_ERR "vmlogrdr: iucv connection to %s " +- "failed with rc %i \n", logptr->system_service, +- connect_rc); ++ pr_err("vmlogrdr: iucv connection to %s " ++ "failed with rc %i \n", ++ logptr->system_service, connect_rc); + goto out_path; + } + +@@ -388,8 +388,8 @@ static int vmlogrdr_release (struct inod + if (logptr->autorecording) { + ret = vmlogrdr_recording(logptr,0,logptr->autopurge); + if (ret) +- printk (KERN_WARNING "vmlogrdr: failed to stop " +- "recording automatically\n"); ++ pr_warning("vmlogrdr: failed to stop " ++ "recording automatically\n"); + } + logptr->dev_in_use = 0; + +@@ -824,8 +824,7 @@ static int __init vmlogrdr_init(void) + dev_t dev; + + if (! MACHINE_IS_VM) { +- printk (KERN_ERR "vmlogrdr: not running under VM, " +- "driver not loaded.\n"); ++ pr_err("not running under VM, driver not loaded.\n"); + return -ENODEV; + } + +--- a/drivers/s390/char/vmur.c ++++ b/drivers/s390/char/vmur.c +@@ -8,6 +8,8 @@ + * Frank Munzert + */ + ++#define KMSG_COMPONENT "vmur" ++ + #include + #include + +@@ -40,8 +42,6 @@ MODULE_AUTHOR("IBM Corporation"); + MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver"); + MODULE_LICENSE("GPL"); + +-#define PRINTK_HEADER "vmur: " +- + static dev_t ur_first_dev_maj_min; + static struct class *vmur_class; + static struct debug_info *vmur_dbf; +@@ -988,7 +988,8 @@ static int __init ur_init(void) + dev_t dev; + + if (!MACHINE_IS_VM) { +- PRINT_ERR("%s is only available under z/VM.\n", ur_banner); ++ pr_err("The %s cannot be loaded without z/VM\n", ++ ur_banner); + return -ENODEV; + } + +@@ -1007,7 +1008,8 @@ static int __init ur_init(void) + + rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur"); + if (rc) { +- PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc); ++ pr_err("Kernel function alloc_chrdev_region failed with " ++ "error code %d\n", rc); + goto fail_unregister_driver; + } + ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0); +@@ -1017,7 +1019,7 @@ static int __init ur_init(void) + rc = PTR_ERR(vmur_class); + goto fail_unregister_region; + } +- PRINT_INFO("%s loaded.\n", ur_banner); ++ pr_info("%s loaded.\n", ur_banner); + return 0; + + fail_unregister_region: +@@ -1035,7 +1037,7 @@ static void __exit ur_exit(void) + unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); + ccw_driver_unregister(&ur_driver); + debug_unregister(vmur_dbf); +- PRINT_INFO("%s unloaded.\n", ur_banner); ++ pr_info("%s unloaded.\n", ur_banner); + } + + module_init(ur_init); +--- a/drivers/s390/char/zcore.c ++++ b/drivers/s390/char/zcore.c +@@ -9,6 +9,8 @@ + * Author(s): Michael Holzheu + */ + ++#define KMSG_COMPONENT "zdump" ++ + #include + #include + #include +@@ -24,8 +26,6 @@ + #include "sclp.h" + + #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) +-#define MSG(x...) printk( KERN_ALERT x ) +-#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x ) + + #define TO_USER 0 + #define TO_KERNEL 1 +@@ -563,19 +563,19 @@ static int __init sys_info_init(enum arc + + switch (arch) { + case ARCH_S390X: +- MSG("DETECTED 'S390X (64 bit) OS'\n"); ++ pr_alert("DETECTED 'S390X (64 bit) OS'\n"); + sys_info.sa_base = SAVE_AREA_BASE_S390X; + sys_info.sa_size = sizeof(struct save_area_s390x); + set_s390x_lc_mask(&sys_info.lc_mask); + break; + case ARCH_S390: +- MSG("DETECTED 'S390 (32 bit) OS'\n"); ++ pr_alert("DETECTED 'S390 (32 bit) OS'\n"); + sys_info.sa_base = SAVE_AREA_BASE_S390; + sys_info.sa_size = sizeof(struct save_area_s390); + set_s390_lc_mask(&sys_info.lc_mask); + break; + default: +- ERROR_MSG("unknown architecture 0x%x.\n",arch); ++ pr_alert("0x%x is an unknown architecture.\n",arch); + return -EINVAL; + } + sys_info.arch = arch; +@@ -674,7 +674,8 @@ static int __init zcore_init(void) + + #ifndef __s390x__ + if (arch == ARCH_S390X) { +- ERROR_MSG("32 bit dumper can't dump 64 bit system!\n"); ++ pr_alert("The 32-bit dump tool cannot be used for a " ++ "64-bit system\n"); + rc = -EINVAL; + goto fail; + } +--- a/drivers/s390/cio/blacklist.c ++++ b/drivers/s390/cio/blacklist.c +@@ -9,6 +9,8 @@ + * Arnd Bergmann (arndb@de.ibm.com) + */ + ++#define KMSG_COMPONENT "cio" ++ + #include + #include + #include +@@ -49,9 +51,10 @@ static int blacklist_range(range_action + { + if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { + if (msgtrigger) +- printk(KERN_WARNING "cio: Invalid cio_ignore range " +- "0.%x.%04x-0.%x.%04x\n", from_ssid, from, +- to_ssid, to); ++ pr_warning("0.%x.%04x to 0.%x.%04x is not a valid " ++ "range for cio_ignore\n", from_ssid, from, ++ to_ssid, to); ++ + return 1; + } + +@@ -139,8 +142,8 @@ static int parse_busid(char *str, unsign + rc = 0; + out: + if (rc && msgtrigger) +- printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n", +- str); ++ pr_warning("%s is not a valid device for the cio_ignore " ++ "kernel parameter\n", str); + + return rc; + } +--- a/drivers/s390/cio/chsc.c ++++ b/drivers/s390/cio/chsc.c +@@ -8,6 +8,8 @@ + * Arnd Bergmann (arndb@de.ibm.com) + */ + ++#define KMSG_COMPONENT "cio" ++ + #include + #include + #include +@@ -333,6 +335,7 @@ static void chsc_process_sei_chp_config( + struct chp_config_data *data; + struct chp_id chpid; + int num; ++ char *events[3] = {"configure", "deconfigure", "cancel deconfigure"}; + + CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n"); + if (sei_area->rs != 0) +@@ -343,8 +346,8 @@ static void chsc_process_sei_chp_config( + if (!chp_test_bit(data->map, num)) + continue; + chpid.id = num; +- printk(KERN_WARNING "cio: processing configure event %d for " +- "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id); ++ pr_notice("Processing %s for channel path %x.%02x\n", ++ events[data->op], chpid.cssid, chpid.id); + switch (data->op) { + case 0: + chp_cfg_schedule(chpid, 1); +--- a/drivers/s390/cio/cio.c ++++ b/drivers/s390/cio/cio.c +@@ -9,6 +9,8 @@ + * Martin Schwidefsky (schwidefsky@de.ibm.com) + */ + ++#define KMSG_COMPONENT "cio" ++ + #include + #include + #include +@@ -773,7 +775,7 @@ cio_probe_console(void) + sch_no = cio_get_console_sch_no(); + if (sch_no == -1) { + console_subchannel_in_use = 0; +- printk(KERN_WARNING "cio: No ccw console found!\n"); ++ pr_warning("No CCW console was found\n"); + return ERR_PTR(-ENODEV); + } + memset(&console_subchannel, 0, sizeof(struct subchannel)); +--- a/drivers/s390/cio/cmf.c ++++ b/drivers/s390/cio/cmf.c +@@ -25,6 +25,8 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++#define KMSG_COMPONENT "cio" ++ + #include + #include + #include +@@ -1359,9 +1361,8 @@ static int __init init_cmf(void) + default: + return 1; + } +- +- printk(KERN_INFO "cio: Channel measurement facility using %s " +- "format (%s)\n", format_string, detect_string); ++ pr_info("Channel measurement facility initialized using format " ++ "%s (mode %s)\n", format_string, detect_string); + return 0; + } + +--- a/drivers/s390/cio/css.c ++++ b/drivers/s390/cio/css.c +@@ -6,6 +6,9 @@ + * Author(s): Arnd Bergmann (arndb@de.ibm.com) + * Cornelia Huck (cornelia.huck@de.ibm.com) + */ ++ ++#define KMSG_COMPONENT "cio" ++ + #include + #include + #include +@@ -844,8 +847,8 @@ out: + s390_unregister_crw_handler(CRW_RSC_CSS); + chsc_free_sei_area(); + kfree(slow_subchannel_set); +- printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", +- ret); ++ pr_alert("The CSS device driver initialization failed with " ++ "errno=%d\n", ret); + return ret; + } + +--- a/drivers/s390/crypto/ap_bus.c ++++ b/drivers/s390/crypto/ap_bus.c +@@ -23,6 +23,8 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++#define KMSG_COMPONENT "ap" ++ + #include + #include + #include +@@ -1337,12 +1339,13 @@ int __init ap_module_init(void) + int rc, i; + + if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) { +- printk(KERN_WARNING "Invalid param: domain = %d. " +- " Not loading.\n", ap_domain_index); ++ pr_warning("%d is not a valid cryptographic domain\n", ++ ap_domain_index); + return -EINVAL; + } + if (ap_instructions_available() != 0) { +- printk(KERN_WARNING "AP instructions not installed.\n"); ++ pr_warning("The hardware system does not support " ++ "AP instructions\n"); + return -ENODEV; + } + register_reset_call(&ap_reset_call); +--- a/drivers/s390/net/claw.c ++++ b/drivers/s390/net/claw.c +@@ -60,6 +60,9 @@ + * 1.25 Added Packing support + * 1.5 + */ ++ ++#define KMSG_COMPONENT "claw" ++ + #include + #include + #include +@@ -94,7 +97,7 @@ + CLAW uses the s390dbf file system see claw_trace and claw_setup + */ + +- ++static char version[] __initdata = "CLAW driver"; + static char debug_buffer[255]; + /** + * Debug Facility Stuff +@@ -298,8 +301,7 @@ claw_probe(struct ccwgroup_device *cgdev + if (rc) { + probe_error(cgdev); + put_device(&cgdev->dev); +- printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n", +- cgdev->cdev[0]->dev.bus_id,__func__,__LINE__); ++ dev_warn(&cgdev->dev, "add_files failed\n"); + CLAW_DBF_TEXT_(2, setup, "probex%d", rc); + return rc; + } +@@ -496,7 +498,8 @@ claw_open(struct net_device *dev) + ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || + (((privptr->channel[READ].flag | + privptr->channel[WRITE].flag) & CLAW_TIMER) != 0x00)) { +- printk(KERN_INFO "%s: remote side is not ready\n", dev->name); ++ dev_info(&privptr->channel[READ].cdev->dev, ++ "%s: remote side is not ready\n", dev->name); + CLAW_DBF_TEXT(2, trace, "notrdy"); + + for ( i = 0; i < 2; i++) { +@@ -582,10 +585,9 @@ claw_irq_handler(struct ccw_device *cdev + CLAW_DBF_TEXT(4, trace, "clawirq"); + /* Bypass all 'unsolicited interrupts' */ + if (!cdev->dev.driver_data) { +- printk(KERN_WARNING "claw: unsolicited interrupt for device:" +- "%s received c-%02x d-%02x\n", +- cdev->dev.bus_id, irb->scsw.cmd.cstat, +- irb->scsw.cmd.dstat); ++ dev_warn(&cdev->dev, "unsolicited interrupt for device " ++ "received c-%02x d-%02x\n", ++ irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); + CLAW_DBF_TEXT(2, trace, "badirq"); + return; + } +@@ -597,8 +599,8 @@ claw_irq_handler(struct ccw_device *cdev + else if (privptr->channel[WRITE].cdev == cdev) + p_ch = &privptr->channel[WRITE]; + else { +- printk(KERN_WARNING "claw: Can't determine channel for " +- "interrupt, device %s\n", cdev->dev.bus_id); ++ dev_warn(&cdev->dev, "Can't determine channel for " ++ "interrupt\n"); + CLAW_DBF_TEXT(2, trace, "badchan"); + return; + } +@@ -612,7 +614,8 @@ claw_irq_handler(struct ccw_device *cdev + + /* Check for good subchannel return code, otherwise info message */ + if (irb->scsw.cmd.cstat && !(irb->scsw.cmd.cstat & SCHN_STAT_PCI)) { +- printk(KERN_INFO "%s: subchannel check for device: %04x -" ++ dev_info(&cdev->dev, ++ "%s: subchannel check for device: %04x -" + " Sch Stat %02x Dev Stat %02x CPA - %04x\n", + dev->name, p_ch->devno, + irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, +@@ -651,7 +654,7 @@ claw_irq_handler(struct ccw_device *cdev + wake_up(&p_ch->wait); /* wake claw_open (READ)*/ + } else if (p_ch->flag == CLAW_WRITE) { + p_ch->claw_state = CLAW_START_WRITE; +- /* send SYSTEM_VALIDATE */ ++ /* send SYSTEM_VALIDATE */ + claw_strt_read(dev, LOCK_NO); + claw_send_control(dev, + SYSTEM_VALIDATE_REQUEST, +@@ -659,10 +662,9 @@ claw_irq_handler(struct ccw_device *cdev + p_env->host_name, + p_env->adapter_name); + } else { +- printk(KERN_WARNING "claw: unsolicited " +- "interrupt for device:" +- "%s received c-%02x d-%02x\n", +- cdev->dev.bus_id, ++ dev_warn(&cdev->dev, "unsolicited " ++ "interrupt for device " ++ "received c-%02x d-%02x\n", + irb->scsw.cmd.cstat, + irb->scsw.cmd.dstat); + return; +@@ -677,8 +679,8 @@ claw_irq_handler(struct ccw_device *cdev + (p_ch->irb->ecw[0] & 0x40) == 0x40 || + (p_ch->irb->ecw[0]) == 0) { + privptr->stats.rx_errors++; +- printk(KERN_INFO "%s: Restart is " +- "required after remote " ++ dev_info(&cdev->dev, ++ "%s: Restart is required after remote " + "side recovers \n", + dev->name); + } +@@ -713,11 +715,13 @@ claw_irq_handler(struct ccw_device *cdev + return; + case CLAW_START_WRITE: + if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { +- printk(KERN_INFO "%s: Unit Check Occured in " ++ dev_info(&cdev->dev, ++ "%s: Unit Check Occured in " + "write channel\n", dev->name); + clear_bit(0, (void *)&p_ch->IO_active); + if (p_ch->irb->ecw[0] & 0x80) { +- printk(KERN_INFO "%s: Resetting Event " ++ dev_info(&cdev->dev, ++ "%s: Resetting Event " + "occurred:\n", dev->name); + init_timer(&p_ch->timer); + p_ch->timer.function = +@@ -725,7 +729,8 @@ claw_irq_handler(struct ccw_device *cdev + p_ch->timer.data = (unsigned long)p_ch; + p_ch->timer.expires = jiffies + 10*HZ; + add_timer(&p_ch->timer); +- printk(KERN_INFO "%s: write connection " ++ dev_info(&cdev->dev, ++ "%s: write connection " + "restarting\n", dev->name); + } + CLAW_DBF_TEXT(4, trace, "rstrtwrt"); +@@ -733,9 +738,10 @@ claw_irq_handler(struct ccw_device *cdev + } + if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { + clear_bit(0, (void *)&p_ch->IO_active); +- printk(KERN_INFO "%s: Unit Exception " +- "Occured in write channel\n", +- dev->name); ++ dev_info(&cdev->dev, ++ "%s: Unit Exception " ++ "occurred in write channel\n", ++ dev->name); + } + if (!((p_ch->irb->scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND) || +@@ -757,7 +763,8 @@ claw_irq_handler(struct ccw_device *cdev + CLAW_DBF_TEXT(4, trace, "StWtExit"); + return; + default: +- printk(KERN_WARNING "%s: wrong selection code - irq " ++ dev_warn(&cdev->dev, ++ "%s: wrong selection code - irq " + "state=%d\n", dev->name, p_ch->claw_state); + CLAW_DBF_TEXT(2, trace, "badIRQ"); + return; +@@ -910,7 +917,8 @@ claw_release(struct net_device *dev) + if (((privptr->channel[READ].last_dstat | + privptr->channel[WRITE].last_dstat) & + ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { +- printk(KERN_WARNING "%s: channel problems during close - " ++ dev_warn(&privptr->channel[READ].cdev->dev, ++ "%s: channel problems during close - " + "read: %02x - write: %02x\n", + dev->name, + privptr->channel[READ].last_dstat, +@@ -1135,20 +1143,19 @@ ccw_check_return_code(struct ccw_device + case -EBUSY: /* BUSY is a transient state no action needed */ + break; + case -ENODEV: +- printk(KERN_EMERG "%s: Missing device called " +- "for IO ENODEV\n", cdev->dev.bus_id); ++ dev_err(&cdev->dev, "Device not found " ++ "for IO ENODEV\n"); + break; + case -EIO: +- printk(KERN_EMERG "%s: Status pending... EIO \n", +- cdev->dev.bus_id); ++ dev_err(&cdev->dev, "Status pending... EIO \n"); + break; + case -EINVAL: +- printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n", +- cdev->dev.bus_id); ++ dev_err(&cdev->dev, ++ "Invalid Dev State EINVAL \n"); + break; + default: +- printk(KERN_EMERG "%s: Unknown error in " +- "Do_IO %d\n",cdev->dev.bus_id, return_code); ++ dev_err(&cdev->dev, "Unknown error in " ++ "Do_IO %d\n", return_code); + } + } + CLAW_DBF_TEXT(4, trace, "ccwret"); +@@ -1162,39 +1169,40 @@ static void + ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) + { + struct net_device *ndev = p_ch->ndev; ++ struct device *dev = &p_ch->cdev->dev; + + CLAW_DBF_TEXT(4, trace, "unitchek"); +- printk(KERN_INFO "%s: Unit Check with sense byte:0x%04x\n", +- ndev->name, sense); ++ dev_info(dev, "%s: Unit Check with sense byte:0x%04x\n", ++ ndev->name, sense); + + if (sense & 0x40) { + if (sense & 0x01) { +- printk(KERN_WARNING "%s: Interface disconnect or " ++ dev_warn(dev, "%s: Interface disconnect or " + "Selective reset " + "occurred (remote side)\n", ndev->name); + } + else { +- printk(KERN_WARNING "%s: System reset occured" ++ dev_warn(dev, "%s: System reset occurred" + " (remote side)\n", ndev->name); + } + } + else if (sense & 0x20) { + if (sense & 0x04) { +- printk(KERN_WARNING "%s: Data-streaming " ++ dev_warn(dev, "%s: Data-streaming " + "timeout)\n", ndev->name); + } + else { +- printk(KERN_WARNING "%s: Data-transfer parity" ++ dev_warn(dev, "%s: Data-transfer parity" + " error\n", ndev->name); + } + } + else if (sense & 0x10) { + if (sense & 0x20) { +- printk(KERN_WARNING "%s: Hardware malfunction " ++ dev_warn(dev, "%s: Hardware malfunction " + "(remote side)\n", ndev->name); + } + else { +- printk(KERN_WARNING "%s: read-data parity error " ++ dev_warn(dev, "%s: read-data parity error " + "(remote side)\n", ndev->name); + } + } +@@ -2002,7 +2010,7 @@ claw_process_control( struct net_device + tdev = &privptr->channel[READ].cdev->dev; + memcpy( &temp_host_name, p_env->host_name, 8); + memcpy( &temp_ws_name, p_env->adapter_name , 8); +- printk(KERN_INFO "%s: CLAW device %.8s: " ++ dev_info(tdev, "%s: CLAW device %.8s: " + "Received Control Packet\n", + dev->name, temp_ws_name); + if (privptr->release_pend==1) { +@@ -2021,30 +2029,28 @@ claw_process_control( struct net_device + if (p_ctlbk->version != CLAW_VERSION_ID) { + claw_snd_sys_validate_rsp(dev, p_ctlbk, + CLAW_RC_WRONG_VERSION); +- printk("%s: %d is wrong version id. " +- "Expected %d\n", +- dev->name, p_ctlbk->version, +- CLAW_VERSION_ID); ++ dev_info(tdev, "%s: %d is wrong version id. " ++ "Expected %d\n", dev->name, p_ctlbk->version, ++ CLAW_VERSION_ID); + } + p_sysval = (struct sysval *)&(p_ctlbk->data); +- printk("%s: Recv Sys Validate Request: " +- "Vers=%d,link_id=%d,Corr=%d,WS name=%." +- "8s,Host name=%.8s\n", +- dev->name, p_ctlbk->version, +- p_ctlbk->linkid, +- p_ctlbk->correlator, +- p_sysval->WS_name, +- p_sysval->host_name); ++ dev_info(tdev, "%s: Recv Sys Validate Request: " ++ "Vers=%d,link_id=%d,Corr=%d,WS name=%.8s," ++ "Host name=%.8s\n", ++ dev->name, p_ctlbk->version, ++ p_ctlbk->linkid, ++ p_ctlbk->correlator, ++ p_sysval->WS_name, ++ p_sysval->host_name); + if (memcmp(temp_host_name, p_sysval->host_name, 8)) { + claw_snd_sys_validate_rsp(dev, p_ctlbk, + CLAW_RC_NAME_MISMATCH); + CLAW_DBF_TEXT(2, setup, "HSTBAD"); + CLAW_DBF_TEXT_(2, setup, "%s", p_sysval->host_name); + CLAW_DBF_TEXT_(2, setup, "%s", temp_host_name); +- printk(KERN_INFO "%s: Host name mismatch\n", +- dev->name); +- printk(KERN_INFO "%s: Received :%s: " +- "expected :%s: \n", ++ dev_info(tdev, ++ "%s: Host name mismatch. Received: %s " ++ "expected: %s\n", + dev->name, + p_sysval->host_name, + temp_host_name); +@@ -2055,35 +2061,36 @@ claw_process_control( struct net_device + CLAW_DBF_TEXT(2, setup, "WSNBAD"); + CLAW_DBF_TEXT_(2, setup, "%s", p_sysval->WS_name); + CLAW_DBF_TEXT_(2, setup, "%s", temp_ws_name); +- printk(KERN_INFO "%s: WS name mismatch\n", +- dev->name); +- printk(KERN_INFO "%s: Received :%s: " +- "expected :%s: \n", +- dev->name, +- p_sysval->WS_name, +- temp_ws_name); ++ dev_info(tdev, "%s: WS name mismatch." ++ " Received: %s expected: %s\n", ++ dev->name, ++ p_sysval->WS_name, ++ temp_ws_name); + } + if ((p_sysval->write_frame_size < p_env->write_size) && + (p_env->packing == 0)) { + claw_snd_sys_validate_rsp(dev, p_ctlbk, + CLAW_RC_HOST_RCV_TOO_SMALL); +- printk(KERN_INFO "%s: host write size is too " +- "small\n", dev->name); ++ dev_info(tdev, ++ "host write size is too small\n"); + CLAW_DBF_TEXT(2, setup, "wrtszbad"); + } + if ((p_sysval->read_frame_size < p_env->read_size) && + (p_env->packing == 0)) { + claw_snd_sys_validate_rsp(dev, p_ctlbk, + CLAW_RC_HOST_RCV_TOO_SMALL); +- printk(KERN_INFO "%s: host read size is too " +- "small\n", dev->name); ++ dev_info(tdev, ++ "host read size is too small\n"); + CLAW_DBF_TEXT(2, setup, "rdsizbad"); + } + claw_snd_sys_validate_rsp(dev, p_ctlbk, 0); +- printk(KERN_INFO "%s: CLAW device %.8s: System validate " +- "completed.\n", dev->name, temp_ws_name); +- printk("%s: sys Validate Rsize:%d Wsize:%d\n", dev->name, +- p_sysval->read_frame_size, p_sysval->write_frame_size); ++ dev_info(tdev, ++ "CLAW device %.8s: System validate" ++ " completed.\n", temp_ws_name); ++ dev_info(tdev, ++ "%s: sys Validate Rsize:%d Wsize:%d\n", ++ dev->name, p_sysval->read_frame_size, ++ p_sysval->write_frame_size); + privptr->system_validate_comp = 1; + if (strncmp(p_env->api_type, WS_APPL_NAME_PACKED, 6) == 0) + p_env->packing = PACKING_ASK; +@@ -2091,8 +2098,9 @@ claw_process_control( struct net_device + break; + case SYSTEM_VALIDATE_RESPONSE: + p_sysval = (struct sysval *)&(p_ctlbk->data); +- printk("%s: Recv Sys Validate Resp: Vers=%d,Corr=%d,RC=%d," +- "WS name=%.8s,Host name=%.8s\n", ++ dev_info(tdev, ++ "%s: Recv Sys Validate Resp: Vers=%d,Corr=%d," ++ "RC=%d,WS name=%.8s,Host name=%.8s\n", + dev->name, + p_ctlbk->version, + p_ctlbk->correlator, +@@ -2101,32 +2109,31 @@ claw_process_control( struct net_device + p_sysval->host_name); + switch (p_ctlbk->rc) { + case 0: +- printk(KERN_INFO "%s: CLAW device " +- "%.8s: System validate " +- "completed.\n", +- dev->name, temp_ws_name); ++ dev_info(tdev, "%s: CLAW device " ++ "%.8s: System validate completed.\n", ++ dev->name, temp_ws_name); + if (privptr->system_validate_comp == 0) + claw_strt_conn_req(dev); + privptr->system_validate_comp = 1; + break; + case CLAW_RC_NAME_MISMATCH: +- printk(KERN_INFO "%s: Sys Validate " ++ dev_info(tdev, "%s: Sys Validate " + "Resp : Host, WS name is " + "mismatch\n", +- dev->name); ++ dev->name); + break; + case CLAW_RC_WRONG_VERSION: +- printk(KERN_INFO "%s: Sys Validate " ++ dev_info(tdev, "%s: Sys Validate " + "Resp : Wrong version\n", + dev->name); + break; + case CLAW_RC_HOST_RCV_TOO_SMALL: +- printk(KERN_INFO "%s: Sys Validate " ++ dev_info(tdev, "%s: Sys Validate " + "Resp : bad frame size\n", + dev->name); + break; + default: +- printk(KERN_INFO "%s: Sys Validate " ++ dev_info(tdev, "%s: Sys Validate " + "error code=%d \n", + dev->name, p_ctlbk->rc); + break; +@@ -2135,7 +2142,7 @@ claw_process_control( struct net_device + + case CONNECTION_REQUEST: + p_connect = (struct conncmd *)&(p_ctlbk->data); +- printk(KERN_INFO "%s: Recv Conn Req: Vers=%d,link_id=%d," ++ dev_info(tdev, "%s: Recv Conn Req: Vers=%d,link_id=%d," + "Corr=%d,HOST appl=%.8s,WS appl=%.8s\n", + dev->name, + p_ctlbk->version, +@@ -2145,20 +2152,20 @@ claw_process_control( struct net_device + p_connect->WS_name); + if (privptr->active_link_ID != 0) { + claw_snd_disc(dev, p_ctlbk); +- printk(KERN_INFO "%s: Conn Req error : " ++ dev_info(tdev, "%s: Conn Req error : " + "already logical link is active \n", + dev->name); + } + if (p_ctlbk->linkid != 1) { + claw_snd_disc(dev, p_ctlbk); +- printk(KERN_INFO "%s: Conn Req error : " ++ dev_info(tdev, "%s: Conn Req error : " + "req logical link id is not 1\n", + dev->name); + } + rc = find_link(dev, p_connect->host_name, p_connect->WS_name); + if (rc != 0) { + claw_snd_disc(dev, p_ctlbk); +- printk(KERN_INFO "%s: Conn Resp error: " ++ dev_info(tdev, "%s: Conn Req error : " + "req appl name does not match\n", + dev->name); + } +@@ -2171,7 +2178,7 @@ claw_process_control( struct net_device + p_env->packing = PACK_SEND; + claw_snd_conn_req(dev, 0); + } +- printk(KERN_INFO "%s: CLAW device %.8s: Connection " ++ dev_info(tdev, "%s: CLAW device %.8s: Connection " + "completed link_id=%d.\n", + dev->name, temp_ws_name, + p_ctlbk->linkid); +@@ -2181,7 +2188,7 @@ claw_process_control( struct net_device + break; + case CONNECTION_RESPONSE: + p_connect = (struct conncmd *)&(p_ctlbk->data); +- printk(KERN_INFO "%s: Revc Conn Resp: Vers=%d,link_id=%d," ++ dev_info(tdev, "%s: Revc Conn Resp: Vers=%d,link_id=%d," + "Corr=%d,RC=%d,Host appl=%.8s, WS appl=%.8s\n", + dev->name, + p_ctlbk->version, +@@ -2192,7 +2199,7 @@ claw_process_control( struct net_device + p_connect->WS_name); + + if (p_ctlbk->rc != 0) { +- printk(KERN_INFO "%s: Conn Resp error: rc=%d \n", ++ dev_info(tdev, "%s: Conn Resp error: rc=%d \n", + dev->name, p_ctlbk->rc); + return 1; + } +@@ -2200,7 +2207,7 @@ claw_process_control( struct net_device + p_connect->host_name, p_connect->WS_name); + if (rc != 0) { + claw_snd_disc(dev, p_ctlbk); +- printk(KERN_INFO "%s: Conn Resp error: " ++ dev_info(tdev, "%s: Conn Resp error: " + "req appl name does not match\n", + dev->name); + } +@@ -2209,7 +2216,8 @@ claw_process_control( struct net_device + break; + case CONNECTION_CONFIRM: + p_connect = (struct conncmd *)&(p_ctlbk->data); +- printk(KERN_INFO "%s: Recv Conn Confirm:Vers=%d,link_id=%d," ++ dev_info(tdev, ++ "%s: Recv Conn Confirm:Vers=%d,link_id=%d," + "Corr=%d,Host appl=%.8s,WS appl=%.8s\n", + dev->name, + p_ctlbk->version, +@@ -2220,21 +2228,21 @@ claw_process_control( struct net_device + if (p_ctlbk->linkid == -(privptr->active_link_ID)) { + privptr->active_link_ID = p_ctlbk->linkid; + if (p_env->packing > PACKING_ASK) { +- printk(KERN_INFO "%s: Confirmed Now packing\n", +- dev->name); ++ dev_info(tdev, ++ "%s: Confirmed Now packing\n", dev->name); + p_env->packing = DO_PACKED; + } + p_ch = &privptr->channel[WRITE]; + wake_up(&p_ch->wait); + } else { +- printk(KERN_INFO "%s: Conn confirm: " ++ dev_info(tdev, "%s: Conn confirm: " + "unexpected linkid=%d \n", + dev->name, p_ctlbk->linkid); + claw_snd_disc(dev, p_ctlbk); + } + break; + case DISCONNECT: +- printk(KERN_INFO "%s: Disconnect: " ++ dev_info(tdev, "%s: Disconnect: " + "Vers=%d,link_id=%d,Corr=%d\n", + dev->name, p_ctlbk->version, + p_ctlbk->linkid, p_ctlbk->correlator); +@@ -2246,11 +2254,11 @@ claw_process_control( struct net_device + privptr->active_link_ID = 0; + break; + case CLAW_ERROR: +- printk(KERN_INFO "%s: CLAW ERROR detected\n", ++ dev_info(tdev, "%s: CLAW ERROR detected\n", + dev->name); + break; + default: +- printk(KERN_INFO "%s: Unexpected command code=%d \n", ++ dev_info(tdev, "%s: Unexpected command code=%d \n", + dev->name, p_ctlbk->command); + break; + } +@@ -2510,7 +2518,8 @@ unpack_read(struct net_device *dev ) + mtc_this_frm=1; + if (p_this_ccw->header.length!= + privptr->p_env->read_size ) { +- printk(KERN_INFO " %s: Invalid frame detected " ++ dev_info(p_dev, ++ "%s: Invalid frame detected " + "length is %02x\n" , + dev->name, p_this_ccw->header.length); + } +@@ -2594,8 +2603,8 @@ unpack_next: + } + else { + privptr->stats.rx_dropped++; +- printk(KERN_WARNING "%s: %s() low on memory\n", +- dev->name,__func__); ++ dev_warn(p_dev, ++ "buffer allocate failed on receive\n"); + } + privptr->mtc_offset=0; + privptr->mtc_logical_link=-1; +@@ -2879,7 +2888,8 @@ claw_new_device(struct ccwgroup_device * + int ret; + struct ccw_dev_id dev_id; + +- printk(KERN_INFO "claw: add for %s\n",cgdev->cdev[READ]->dev.bus_id); ++ dev_info(&cgdev->dev, "add for %s\n", ++ dev_name(&cgdev->cdev[READ]->dev)); + CLAW_DBF_TEXT(2, setup, "new_dev"); + privptr = cgdev->dev.driver_data; + cgdev->cdev[READ]->dev.driver_data = privptr; +@@ -2895,27 +2905,28 @@ claw_new_device(struct ccwgroup_device * + if (ret == 0) + ret = add_channel(cgdev->cdev[1],1,privptr); + if (ret != 0) { +- printk(KERN_WARNING +- "add channel failed with ret = %d\n", ret); ++ dev_warn(&cgdev->dev, "add channel failed " ++ "with ret = %d\n", ret); + goto out; + } + ret = ccw_device_set_online(cgdev->cdev[READ]); + if (ret != 0) { +- printk(KERN_WARNING +- "claw: ccw_device_set_online %s READ failed " +- "with ret = %d\n",cgdev->cdev[READ]->dev.bus_id,ret); ++ dev_warn(&cgdev->dev, ++ "device set online READ failed " ++ "with ret = %d\n", ret); + goto out; + } + ret = ccw_device_set_online(cgdev->cdev[WRITE]); + if (ret != 0) { +- printk(KERN_WARNING +- "claw: ccw_device_set_online %s WRITE failed " +- "with ret = %d\n",cgdev->cdev[WRITE]->dev.bus_id, ret); ++ dev_warn(&cgdev->dev, ++ "device set online WRITE failed " ++ "with ret = %d\n", ret); + goto out; + } + dev = alloc_netdev(0,"claw%d",claw_init_netdevice); + if (!dev) { +- printk(KERN_WARNING "%s:alloc_netdev failed\n",__func__); ++ dev_warn(&cgdev->dev, ++ "failed creating network device\n"); + goto out; + } + dev->ml_priv = privptr; +@@ -2943,13 +2954,13 @@ claw_new_device(struct ccwgroup_device * + privptr->channel[WRITE].ndev = dev; + privptr->p_env->ndev = dev; + +- printk(KERN_INFO "%s:readsize=%d writesize=%d " ++ dev_info(&cgdev->dev, "%s:readsize=%d writesize=%d " + "readbuffer=%d writebuffer=%d read=0x%04x write=0x%04x\n", + dev->name, p_env->read_size, + p_env->write_size, p_env->read_buffers, + p_env->write_buffers, p_env->devno[READ], + p_env->devno[WRITE]); +- printk(KERN_INFO "%s:host_name:%.8s, adapter_name " ++ dev_info(&cgdev->dev, "%s:host_name:%.8s, adapter_name " + ":%.8s api_type: %.8s\n", + dev->name, p_env->host_name, + p_env->adapter_name , p_env->api_type); +@@ -2993,8 +3004,8 @@ claw_shutdown_device(struct ccwgroup_dev + ndev = priv->channel[READ].ndev; + if (ndev) { + /* Close the device */ +- printk(KERN_INFO +- "%s: shuting down \n",ndev->name); ++ dev_info(&cgdev->dev, "%s: shutting down \n", ++ ndev->name); + if (ndev->flags & IFF_RUNNING) + ret = claw_release(ndev); + ndev->flags &=~IFF_RUNNING; +@@ -3019,8 +3030,7 @@ claw_remove_device(struct ccwgroup_devic + CLAW_DBF_TEXT_(2, setup, "%s", cgdev->dev.bus_id); + priv = cgdev->dev.driver_data; + BUG_ON(!priv); +- printk(KERN_INFO "claw: %s() called %s will be removed.\n", +- __func__,cgdev->cdev[0]->dev.bus_id); ++ dev_info(&cgdev->dev, " will be removed.\n"); + if (cgdev->state == CCWGROUP_ONLINE) + claw_shutdown_device(cgdev); + claw_remove_files(&cgdev->dev); +@@ -3285,7 +3295,7 @@ claw_cleanup(void) + { + unregister_cu3088_discipline(&claw_group_driver); + claw_unregister_debug_facility(); +- printk(KERN_INFO "claw: Driver unloaded\n"); ++ pr_info("Driver unloaded\n"); + + } + +@@ -3299,12 +3309,11 @@ static int __init + claw_init(void) + { + int ret = 0; +- printk(KERN_INFO "claw: starting driver\n"); + ++ pr_info("Loading %s\n", version); + ret = claw_register_debug_facility(); + if (ret) { +- printk(KERN_WARNING "claw: %s() debug_register failed %d\n", +- __func__,ret); ++ pr_warning("debug_register failed %d\n", ret); + return ret; + } + CLAW_DBF_TEXT(2, setup, "init_mod"); +@@ -3312,8 +3321,7 @@ claw_init(void) + if (ret) { + CLAW_DBF_TEXT(2, setup, "init_bad"); + claw_unregister_debug_facility(); +- printk(KERN_WARNING "claw; %s() cu3088 register failed %d\n", +- __func__,ret); ++ pr_warning("register_cu3088_discipline() failed rc=%d\n", ret); + } + return ret; + } +--- a/drivers/s390/net/ctcm_fsms.c ++++ b/drivers/s390/net/ctcm_fsms.c +@@ -13,6 +13,8 @@ + #undef DEBUGDATA + #undef DEBUGCCW + ++#define KMSG_COMPONENT "ctcm" ++ + #include + #include + #include +@@ -190,21 +192,22 @@ static void ctcmpc_chx_send_sweep(fsm_in + void ctcm_ccw_check_rc(struct channel *ch, int rc, char *msg) + { + CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, +- "%s(%s): %s: %04x\n", +- CTCM_FUNTAIL, ch->id, msg, rc); ++ "%s(%s): %s: %04x\n", ++ CTCM_FUNTAIL, ch->id, msg, rc); + switch (rc) { + case -EBUSY: +- ctcm_pr_warn("%s (%s): Busy !\n", ch->id, msg); ++ pr_info("%s: The communication peer is busy\n", ++ ch->id); + fsm_event(ch->fsm, CTC_EVENT_IO_EBUSY, ch); + break; + case -ENODEV: +- ctcm_pr_emerg("%s (%s): Invalid device called for IO\n", +- ch->id, msg); ++ pr_err("%s: The specified target device is not valid\n", ++ ch->id); + fsm_event(ch->fsm, CTC_EVENT_IO_ENODEV, ch); + break; + default: +- ctcm_pr_emerg("%s (%s): Unknown error in do_IO %04x\n", +- ch->id, msg, rc); ++ pr_err("An I/O operation resulted in error %04x\n", ++ rc); + fsm_event(ch->fsm, CTC_EVENT_IO_UNKNOWN, ch); + } + } +@@ -886,8 +889,15 @@ static void ctcm_chx_rxiniterr(fsm_insta + fsm_newstate(fi, CTC_STATE_RXERR); + fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev); + } +- } else +- ctcm_pr_warn("%s: Error during RX init handshake\n", dev->name); ++ } else { ++ CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, ++ "%s(%s): %s in %s", CTCM_FUNTAIL, ch->id, ++ ctc_ch_event_names[event], fsm_getstate_str(fi)); ++ ++ dev_warn(&dev->dev, ++ "Initialization failed with RX/TX init handshake " ++ "error %s\n", ctc_ch_event_names[event]); ++ } + } + + /** +@@ -969,7 +979,9 @@ static void ctcm_chx_txiniterr(fsm_insta + "%s(%s): %s in %s", CTCM_FUNTAIL, ch->id, + ctc_ch_event_names[event], fsm_getstate_str(fi)); + +- ctcm_pr_warn("%s: Error during TX init handshake\n", dev->name); ++ dev_warn(&dev->dev, ++ "Initialization failed with RX/TX init handshake " ++ "error %s\n", ctc_ch_event_names[event]); + } + } + +@@ -2101,14 +2113,11 @@ static void dev_action_restart(fsm_insta + CTCMY_DBF_DEV_NAME(TRACE, dev, ""); + + if (IS_MPC(priv)) { +- ctcm_pr_info("ctcm: %s Restarting Device and " +- "MPC Group in 5 seconds\n", +- dev->name); + restart_timer = CTCM_TIME_1_SEC; + } else { +- ctcm_pr_info("%s: Restarting\n", dev->name); + restart_timer = CTCM_TIME_5_SEC; + } ++ dev_info(&dev->dev, "Restarting device\n"); + + dev_action_stop(fi, event, arg); + fsm_event(priv->fsm, DEV_EVENT_STOP, dev); +@@ -2150,16 +2159,16 @@ static void dev_action_chup(fsm_instance + case DEV_STATE_STARTWAIT_RX: + if (event == DEV_EVENT_RXUP) { + fsm_newstate(fi, DEV_STATE_RUNNING); +- ctcm_pr_info("%s: connected with remote side\n", +- dev->name); ++ dev_info(&dev->dev, ++ "Connected with remote side\n"); + ctcm_clear_busy(dev); + } + break; + case DEV_STATE_STARTWAIT_TX: + if (event == DEV_EVENT_TXUP) { + fsm_newstate(fi, DEV_STATE_RUNNING); +- ctcm_pr_info("%s: connected with remote side\n", +- dev->name); ++ dev_info(&dev->dev, ++ "Connected with remote side\n"); + ctcm_clear_busy(dev); + } + break; +--- a/drivers/s390/net/ctcm_main.c ++++ b/drivers/s390/net/ctcm_main.c +@@ -21,6 +21,8 @@ + #undef DEBUGDATA + #undef DEBUGCCW + ++#define KMSG_COMPONENT "ctcm" ++ + #include + #include + #include +@@ -281,14 +283,16 @@ static long ctcm_check_irb_error(struct + + switch (PTR_ERR(irb)) { + case -EIO: +- ctcm_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id); ++ dev_err(&cdev->dev, ++ "An I/O-error occurred on the CTCM device\n"); + break; + case -ETIMEDOUT: +- ctcm_pr_warn("timeout on device %s\n", cdev->dev.bus_id); ++ dev_err(&cdev->dev, ++ "An adapter hardware operation timed out\n"); + break; + default: +- ctcm_pr_warn("unknown error %ld on device %s\n", +- PTR_ERR(irb), cdev->dev.bus_id); ++ dev_err(&cdev->dev, ++ "An error occurred on the adapter hardware\n"); + } + return PTR_ERR(irb); + } +@@ -309,15 +313,17 @@ static inline void ccw_unit_check(struct + if (sense & SNS0_INTERVENTION_REQ) { + if (sense & 0x01) { + if (ch->sense_rc != 0x01) { +- ctcm_pr_debug("%s: Interface disc. or Sel. " +- "reset (remote)\n", ch->id); ++ pr_notice( ++ "%s: The communication peer has " ++ "disconnected\n", ch->id); + ch->sense_rc = 0x01; + } + fsm_event(ch->fsm, CTC_EVENT_UC_RCRESET, ch); + } else { + if (ch->sense_rc != SNS0_INTERVENTION_REQ) { +- ctcm_pr_debug("%s: System reset (remote)\n", +- ch->id); ++ pr_notice( ++ "%s: The remote operating system is " ++ "not available\n", ch->id); + ch->sense_rc = SNS0_INTERVENTION_REQ; + } + fsm_event(ch->fsm, CTC_EVENT_UC_RSRESET, ch); +@@ -1194,8 +1200,11 @@ static void ctcm_irq_handler(struct ccw_ + + /* Check for unsolicited interrupts. */ + if (cgdev == NULL) { +- ctcm_pr_warn("ctcm: Got unsolicited irq: c-%02x d-%02x\n", +- cstat, dstat); ++ CTCM_DBF_TEXT_(TRACE, CTC_DBF_ERROR, ++ "%s(%s) unsolicited irq: c-%02x d-%02x\n", ++ CTCM_FUNTAIL, dev_name(&cdev->dev), cstat, dstat); ++ dev_warn(&cdev->dev, ++ "The adapter received a non-specific IRQ\n"); + return; + } + +@@ -1207,31 +1216,34 @@ static void ctcm_irq_handler(struct ccw_ + else if (priv->channel[WRITE]->cdev == cdev) + ch = priv->channel[WRITE]; + else { +- ctcm_pr_err("ctcm: Can't determine channel for interrupt, " +- "device %s\n", cdev->dev.bus_id); ++ dev_err(&cdev->dev, ++ "%s: Internal error: Can't determine channel for " ++ "interrupt device %s\n", ++ __func__, dev_name(&cdev->dev)); ++ /* Explain: inconsistent internal structures */ + return; + } + + dev = ch->netdev; + if (dev == NULL) { +- ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n", +- __func__, cdev->dev.bus_id, ch); ++ dev_err(&cdev->dev, ++ "%s Internal error: net_device is NULL, ch = 0x%p\n", ++ __func__, ch); ++ /* Explain: inconsistent internal structures */ + return; + } + +- CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, +- "%s(%s): int. for %s: cstat=%02x dstat=%02x", +- CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat); +- + /* Copy interruption response block. */ + memcpy(ch->irb, irb, sizeof(struct irb)); + ++ /* Issue error message and return on subchannel error code */ + if (irb->scsw.cmd.cstat) { +- /* Check for good subchannel return code, otherwise error message */ + fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch); +- ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n", +- dev->name, ch->id, irb->scsw.cmd.cstat, +- irb->scsw.cmd.dstat); ++ CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN, ++ "%s(%s): sub-ch check %s: cs=%02x ds=%02x", ++ CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat); ++ dev_warn(&cdev->dev, ++ "A check occurred on the subchannel\n"); + return; + } + +@@ -1239,7 +1251,7 @@ static void ctcm_irq_handler(struct ccw_ + if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if ((irb->ecw[0] & ch->sense_rc) == 0) + /* print it only once */ +- CTCM_DBF_TEXT_(TRACE, CTC_DBF_INFO, ++ CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN, + "%s(%s): sense=%02x, ds=%02x", + CTCM_FUNTAIL, ch->id, irb->ecw[0], dstat); + ccw_unit_check(ch, irb->ecw[0]); +@@ -1574,6 +1586,11 @@ static int ctcm_new_device(struct ccwgro + + strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); + ++ dev_info(&dev->dev, ++ "setup OK : r/w = %s/%s, protocol : %d\n", ++ priv->channel[READ]->id, ++ priv->channel[WRITE]->id, priv->protocol); ++ + CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, + "setup(%s) OK : r/w = %s/%s, protocol : %d", dev->name, + priv->channel[READ]->id, +@@ -1687,7 +1704,7 @@ static void __exit ctcm_exit(void) + { + unregister_cu3088_discipline(&ctcm_group_driver); + ctcm_unregister_dbf_views(); +- ctcm_pr_info("CTCM driver unloaded\n"); ++ pr_info("CTCM driver unloaded\n"); + } + + /* +@@ -1695,7 +1712,7 @@ static void __exit ctcm_exit(void) + */ + static void print_banner(void) + { +- printk(KERN_INFO "CTCM driver initialized\n"); ++ pr_info("CTCM driver initialized\n"); + } + + /** +@@ -1717,8 +1734,8 @@ static int __init ctcm_init(void) + ret = register_cu3088_discipline(&ctcm_group_driver); + if (ret) { + ctcm_unregister_dbf_views(); +- ctcm_pr_crit("ctcm_init failed with register_cu3088_discipline " +- "(rc = %d)\n", ret); ++ pr_err("%s / register_cu3088_discipline failed, ret = %d\n", ++ __func__, ret); + return ret; + } + print_banner(); +--- a/drivers/s390/net/ctcm_main.h ++++ b/drivers/s390/net/ctcm_main.h +@@ -41,12 +41,6 @@ + #define LOG_FLAG_NOMEM 8 + + #define ctcm_pr_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) +-#define ctcm_pr_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) +-#define ctcm_pr_notice(fmt, arg...) printk(KERN_NOTICE fmt, ##arg) +-#define ctcm_pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg) +-#define ctcm_pr_emerg(fmt, arg...) printk(KERN_EMERG fmt, ##arg) +-#define ctcm_pr_err(fmt, arg...) printk(KERN_ERR fmt, ##arg) +-#define ctcm_pr_crit(fmt, arg...) printk(KERN_CRIT fmt, ##arg) + + #define CTCM_PR_DEBUG(fmt, arg...) \ + do { \ +--- a/drivers/s390/net/ctcm_mpc.c ++++ b/drivers/s390/net/ctcm_mpc.c +@@ -19,6 +19,8 @@ + #undef DEBUGDATA + #undef DEBUGCCW + ++#define KMSG_COMPONENT "ctcm" ++ + #include + #include + #include +@@ -386,7 +388,7 @@ int ctc_mpc_alloc_channel(int port_num, + if (grp->allocchan_callback_retries < 4) { + if (grp->allochanfunc) + grp->allochanfunc(grp->port_num, +- grp->group_max_buflen); ++ grp->group_max_buflen); + } else { + /* there are problems...bail out */ + /* there may be a state mismatch so restart */ +@@ -1232,8 +1234,9 @@ done: + + dev_kfree_skb_any(pskb); + if (sendrc == NET_RX_DROP) { +- printk(KERN_WARNING "%s %s() NETWORK BACKLOG EXCEEDED" +- " - PACKET DROPPED\n", dev->name, __func__); ++ dev_warn(&dev->dev, ++ "The network backlog for %s is exceeded, " ++ "package dropped\n", __func__); + fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); + } + +@@ -1670,10 +1673,11 @@ static int mpc_validate_xid(struct mpcg_ + CTCM_FUNTAIL, ch->id); + } + } +- + done: + if (rc) { +- ctcm_pr_info("ctcmpc : %s() failed\n", __FUNCTION__); ++ dev_warn(&dev->dev, ++ "The XID used in the MPC protocol is not valid, " ++ "rc = %d\n", rc); + priv->xid->xid2_flag2 = 0x40; + grp->saved_xid2->xid2_flag2 = 0x40; + } +--- a/drivers/s390/net/ctcm_sysfs.c ++++ b/drivers/s390/net/ctcm_sysfs.c +@@ -10,6 +10,8 @@ + #undef DEBUGDATA + #undef DEBUGCCW + ++#define KMSG_COMPONENT "ctcm" ++ + #include + #include "ctcm_main.h" + +--- a/drivers/s390/net/lcs.c ++++ b/drivers/s390/net/lcs.c +@@ -26,6 +26,8 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++#define KMSG_COMPONENT "lcs" ++ + #include + #include + #include +@@ -54,8 +56,6 @@ + #error Cannot compile lcs.c without some net devices switched on. + #endif + +-#define PRINTK_HEADER " lcs: " +- + /** + * initialization string for output + */ +@@ -96,7 +96,7 @@ lcs_register_debug_facility(void) + lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8); + lcs_dbf_trace = debug_register("lcs_trace", 4, 1, 8); + if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { +- PRINT_ERR("Not enough memory for debug facility.\n"); ++ pr_err("Not enough memory for debug facility.\n"); + lcs_unregister_debug_facility(); + return -ENOMEM; + } +@@ -502,7 +502,9 @@ lcs_start_channel(struct lcs_channel *ch + spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + if (rc) { + LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id); +- PRINT_ERR("Error in starting channel, rc=%d!\n", rc); ++ dev_err(&channel->ccwdev->dev, ++ "Starting an LCS device resulted in an error," ++ " rc=%d!\n", rc); + } + return rc; + } +@@ -636,7 +638,9 @@ __lcs_resume_channel(struct lcs_channel + rc = ccw_device_resume(channel->ccwdev); + if (rc) { + LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id); +- PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); ++ dev_warn(&channel->ccwdev->dev, ++ "Sending data from the LCS device to the LAN failed" ++ " with rc=%d\n",rc); + } else + channel->state = LCS_CH_STATE_RUNNING; + return rc; +@@ -1082,7 +1086,7 @@ lcs_check_multicast_support(struct lcs_c + cmd->cmd.lcs_qipassist.num_ip_pairs = 1; + rc = lcs_send_lancmd(card, buffer, __lcs_check_multicast_cb); + if (rc != 0) { +- PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n"); ++ pr_err("Query IPAssist failed. Assuming unsupported!\n"); + return -EOPNOTSUPP; + } + if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) +@@ -1115,8 +1119,8 @@ list_modified: + rc = lcs_send_setipm(card, ipm); + spin_lock_irqsave(&card->ipm_lock, flags); + if (rc) { +- PRINT_INFO("Adding multicast address failed. " +- "Table possibly full!\n"); ++ pr_info("Adding multicast address failed." ++ " Table possibly full!\n"); + /* store ipm in failed list -> will be added + * to ipm_list again, so a retry will be done + * during the next call of this function */ +@@ -1227,8 +1231,8 @@ lcs_set_mc_addresses(struct lcs_card *ca + ipm = (struct lcs_ipm_list *) + kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); + if (ipm == NULL) { +- PRINT_INFO("Not enough memory to add " +- "new multicast entry!\n"); ++ pr_info("Not enough memory to add" ++ " new multicast entry!\n"); + break; + } + memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); +@@ -1302,18 +1306,21 @@ lcs_check_irb_error(struct ccw_device *c + + switch (PTR_ERR(irb)) { + case -EIO: +- PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id); ++ dev_warn(&cdev->dev, ++ "An I/O-error occurred on the LCS device\n"); + LCS_DBF_TEXT(2, trace, "ckirberr"); + LCS_DBF_TEXT_(2, trace, " rc%d", -EIO); + break; + case -ETIMEDOUT: +- PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); ++ dev_warn(&cdev->dev, ++ "A command timed out on the LCS device\n"); + LCS_DBF_TEXT(2, trace, "ckirberr"); + LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT); + break; + default: +- PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), +- cdev->dev.bus_id); ++ dev_warn(&cdev->dev, ++ "An error occurred on the LCS device, rc=%ld\n", ++ PTR_ERR(irb)); + LCS_DBF_TEXT(2, trace, "ckirberr"); + LCS_DBF_TEXT(2, trace, " rc???"); + } +@@ -1399,8 +1406,10 @@ lcs_irq(struct ccw_device *cdev, unsigne + /* Check for channel and device errors presented */ + rc = lcs_get_problem(cdev, irb); + if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) { +- PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", +- cdev->dev.bus_id, dstat, cstat); ++ dev_warn(&cdev->dev, ++ "The LCS device stopped because of an error," ++ " dstat=0x%X, cstat=0x%X \n", ++ dstat, cstat); + if (rc) { + channel->state = LCS_CH_STATE_ERROR; + } +@@ -1757,8 +1766,8 @@ lcs_get_control(struct lcs_card *card, s + lcs_schedule_recovery(card); + break; + case LCS_CMD_STOPLAN: +- PRINT_WARN("Stoplan for %s initiated by LGW.\n", +- card->dev->name); ++ pr_warning("Stoplan for %s initiated by LGW.\n", ++ card->dev->name); + if (card->dev) + netif_carrier_off(card->dev); + break; +@@ -1786,7 +1795,8 @@ lcs_get_skb(struct lcs_card *card, char + + skb = dev_alloc_skb(skb_len); + if (skb == NULL) { +- PRINT_ERR("LCS: alloc_skb failed for device=%s\n", ++ dev_err(&card->dev->dev, ++ " Allocating a socket buffer to interface %s failed\n", + card->dev->name); + card->stats.rx_dropped++; + return; +@@ -1882,7 +1892,8 @@ lcs_stop_device(struct net_device *dev) + (card->write.state != LCS_CH_STATE_RUNNING)); + rc = lcs_stopcard(card); + if (rc) +- PRINT_ERR("Try it again!\n "); ++ dev_err(&card->dev->dev, ++ " Shutting down the LCS device failed\n "); + return rc; + } + +@@ -1901,7 +1912,7 @@ lcs_open_device(struct net_device *dev) + /* initialize statistics */ + rc = lcs_detect(card); + if (rc) { +- PRINT_ERR("LCS:Error in opening device!\n"); ++ pr_err("Error in opening device!\n"); + + } else { + dev->flags |= IFF_UP; +@@ -2109,8 +2120,9 @@ lcs_new_device(struct ccwgroup_device *c + rc = lcs_detect(card); + if (rc) { + LCS_DBF_TEXT(2, setup, "dtctfail"); +- PRINT_WARN("Detection of LCS card failed with return code " +- "%d (0x%x)\n", rc, rc); ++ dev_warn(&card->dev->dev, ++ "Detecting a network adapter for LCS devices" ++ " failed with rc=%d (0x%x)\n", rc, rc); + lcs_stopcard(card); + goto out; + } +@@ -2140,7 +2152,7 @@ lcs_new_device(struct ccwgroup_device *c + #endif + default: + LCS_DBF_TEXT(3, setup, "errinit"); +- PRINT_ERR("LCS: Initialization failed\n"); ++ pr_err(" Initialization failed\n"); + goto out; + } + if (!dev) +@@ -2172,13 +2184,13 @@ netdev_out: + goto out; + + /* Print out supported assists: IPv6 */ +- PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, +- (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? +- "with" : "without"); ++ pr_info("LCS device %s %s IPv6 support\n", card->dev->name, ++ (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? ++ "with" : "without"); + /* Print out supported assist: Multicast */ +- PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, +- (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? +- "with" : "without"); ++ pr_info("LCS device %s %s Multicast support\n", card->dev->name, ++ (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? ++ "with" : "without"); + return 0; + out: + +@@ -2244,15 +2256,16 @@ lcs_recovery(void *ptr) + return 0; + LCS_DBF_TEXT(4, trace, "recover2"); + gdev = card->gdev; +- PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id); ++ dev_warn(&gdev->dev, ++ "A recovery process has been started for the LCS device\n"); + rc = __lcs_shutdown_device(gdev, 1); + rc = lcs_new_device(gdev); + if (!rc) +- PRINT_INFO("Device %s successfully recovered!\n", +- card->dev->name); ++ pr_info("Device %s successfully recovered!\n", ++ card->dev->name); + else +- PRINT_INFO("Device %s could not be recovered!\n", +- card->dev->name); ++ pr_info("Device %s could not be recovered!\n", ++ card->dev->name); + lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD); + return 0; + } +@@ -2304,17 +2317,17 @@ __init lcs_init_module(void) + { + int rc; + +- PRINT_INFO("Loading %s\n",version); ++ pr_info("Loading %s\n", version); + rc = lcs_register_debug_facility(); + LCS_DBF_TEXT(0, setup, "lcsinit"); + if (rc) { +- PRINT_ERR("Initialization failed\n"); ++ pr_err("Initialization failed\n"); + return rc; + } + + rc = register_cu3088_discipline(&lcs_group_driver); + if (rc) { +- PRINT_ERR("Initialization failed\n"); ++ pr_err("Initialization failed\n"); + return rc; + } + return 0; +@@ -2327,7 +2340,7 @@ __init lcs_init_module(void) + static void + __exit lcs_cleanup_module(void) + { +- PRINT_INFO("Terminating lcs module.\n"); ++ pr_info("Terminating lcs module.\n"); + LCS_DBF_TEXT(0, trace, "cleanup"); + unregister_cu3088_discipline(&lcs_group_driver); + lcs_unregister_debug_facility(); +--- a/drivers/s390/net/netiucv.c ++++ b/drivers/s390/net/netiucv.c +@@ -31,6 +31,8 @@ + * + */ + ++#define KMSG_COMPONENT "netiucv" ++ + #undef DEBUG + + #include +@@ -846,7 +848,8 @@ static void conn_action_connsever(fsm_in + + fsm_deltimer(&conn->timer); + iucv_path_sever(conn->path, NULL); +- PRINT_INFO("%s: Remote dropped connection\n", netdev->name); ++ dev_info(privptr->dev, "The peer interface of the IUCV device" ++ " has closed the connection\n"); + IUCV_DBF_TEXT(data, 2, + "conn_action_connsever: Remote dropped connection\n"); + fsm_newstate(fi, CONN_STATE_STARTWAIT); +@@ -856,13 +859,15 @@ static void conn_action_connsever(fsm_in + static void conn_action_start(fsm_instance *fi, int event, void *arg) + { + struct iucv_connection *conn = arg; ++ struct net_device *netdev = conn->netdev; ++ struct netiucv_priv *privptr = netdev_priv(netdev); + int rc; + + IUCV_DBF_TEXT(trace, 3, __func__); + + fsm_newstate(fi, CONN_STATE_STARTWAIT); + IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n", +- conn->netdev->name, conn->userid); ++ netdev->name, conn->userid); + + /* + * We must set the state before calling iucv_connect because the +@@ -876,41 +881,45 @@ static void conn_action_start(fsm_instan + NULL, iucvMagic, conn); + switch (rc) { + case 0: +- conn->netdev->tx_queue_len = conn->path->msglim; ++ netdev->tx_queue_len = conn->path->msglim; + fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, + CONN_EVENT_TIMER, conn); + return; + case 11: +- PRINT_INFO("%s: User %s is currently not available.\n", +- conn->netdev->name, +- netiucv_printname(conn->userid)); ++ dev_warn(privptr->dev, ++ "The IUCV device failed to connect to z/VM guest %s\n", ++ netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 12: +- PRINT_INFO("%s: User %s is currently not ready.\n", +- conn->netdev->name, +- netiucv_printname(conn->userid)); ++ dev_warn(privptr->dev, ++ "The IUCV device failed to connect to the peer on z/VM" ++ " guest %s\n", netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 13: +- PRINT_WARN("%s: Too many IUCV connections.\n", +- conn->netdev->name); ++ dev_err(privptr->dev, ++ "Connecting the IUCV device would exceed the maximum" ++ " number of IUCV connections\n"); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 14: +- PRINT_WARN("%s: User %s has too many IUCV connections.\n", +- conn->netdev->name, +- netiucv_printname(conn->userid)); ++ dev_err(privptr->dev, ++ "z/VM guest %s has too many IUCV connections" ++ " to connect with the IUCV device\n", ++ netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 15: +- PRINT_WARN("%s: No IUCV authorization in CP directory.\n", +- conn->netdev->name); ++ dev_err(privptr->dev, ++ "The IUCV device cannot connect to a z/VM guest with no" ++ " IUCV authorization\n"); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + default: +- PRINT_WARN("%s: iucv_connect returned error %d\n", +- conn->netdev->name, rc); ++ dev_err(privptr->dev, ++ "Connecting the IUCV device failed with error %d\n", ++ rc); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + } +@@ -1059,8 +1068,9 @@ dev_action_connup(fsm_instance *fi, int + switch (fsm_getstate(fi)) { + case DEV_STATE_STARTWAIT: + fsm_newstate(fi, DEV_STATE_RUNNING); +- PRINT_INFO("%s: connected with remote side %s\n", +- dev->name, privptr->conn->userid); ++ dev_info(privptr->dev, ++ "The IUCV device has been connected" ++ " successfully to %s\n", privptr->conn->userid); + IUCV_DBF_TEXT(setup, 3, + "connection is up and running\n"); + break; +@@ -1982,6 +1992,8 @@ static ssize_t conn_write(struct device_ + if (rc) + goto out_unreg; + ++ dev_info(priv->dev, "The IUCV interface to %s has been" ++ " established successfully\n", netiucv_printname(username)); + + return count; + +@@ -2027,10 +2039,9 @@ static ssize_t remove_write (struct devi + continue; + read_unlock_bh(&iucv_connection_rwlock); + if (ndev->flags & (IFF_UP | IFF_RUNNING)) { +- PRINT_WARN("netiucv: net device %s active with peer " +- "%s\n", ndev->name, priv->conn->userid); +- PRINT_WARN("netiucv: %s cannot be removed\n", +- ndev->name); ++ dev_warn(dev, "The IUCV device is connected" ++ " to %s and cannot be removed\n", ++ priv->conn->userid); + IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); + return -EPERM; + } +@@ -2062,7 +2073,7 @@ static struct attribute_group *netiucv_d + + static void netiucv_banner(void) + { +- PRINT_INFO("NETIUCV driver initialized\n"); ++ pr_info("driver initialized\n"); + } + + static void __exit netiucv_exit(void) +@@ -2088,7 +2099,7 @@ static void __exit netiucv_exit(void) + iucv_unregister(&netiucv_handler, 1); + iucv_unregister_dbf_views(); + +- PRINT_INFO("NETIUCV driver unloaded\n"); ++ pr_info("driver unloaded\n"); + return; + } + +--- a/drivers/s390/net/qeth_core.h ++++ b/drivers/s390/net/qeth_core.h +@@ -34,8 +34,6 @@ + + #include "qeth_core_mpc.h" + +-#define KMSG_COMPONENT "qeth" +- + /** + * Debug Facility stuff + */ +@@ -74,11 +72,6 @@ struct qeth_dbf_info { + #define QETH_DBF_TEXT_(name, level, text...) \ + qeth_dbf_longtext(QETH_DBF_##name, level, text) + +-/** +- * some more debug stuff +- */ +-#define PRINTK_HEADER "qeth: " +- + #define SENSE_COMMAND_REJECT_BYTE 0 + #define SENSE_COMMAND_REJECT_FLAG 0x80 + #define SENSE_RESETTING_EVENT_BYTE 1 +--- a/drivers/s390/net/qeth_core_main.c ++++ b/drivers/s390/net/qeth_core_main.c +@@ -8,6 +8,8 @@ + * Frank Blaschka + */ + ++#define KMSG_COMPONENT "qeth" ++ + #include + #include + #include +@@ -319,7 +321,10 @@ static int qeth_issue_next_read(struct q + return -EIO; + iob = qeth_get_buffer(&card->read); + if (!iob) { +- PRINT_WARN("issue_next_read failed: no iob available!\n"); ++ dev_warn(&card->gdev->dev, "The qeth device driver " ++ "failed to recover an error on the device\n"); ++ QETH_DBF_MESSAGE(2, "%s issue_next_read failed: no iob " ++ "available\n", dev_name(&card->gdev->dev)); + return -ENOMEM; + } + qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE); +@@ -327,7 +332,8 @@ static int qeth_issue_next_read(struct q + rc = ccw_device_start(card->read.ccwdev, &card->read.ccw, + (addr_t) iob, 0, 0); + if (rc) { +- PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc); ++ QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! " ++ "rc=%i\n", dev_name(&card->gdev->dev), rc); + atomic_set(&card->read.irq_pending, 0); + qeth_schedule_recovery(card); + wake_up(&card->wait_q); +@@ -393,10 +399,9 @@ static struct qeth_ipa_cmd *qeth_check_i + } else { + switch (cmd->hdr.command) { + case IPA_CMD_STOPLAN: +- PRINT_WARN("Link failure on %s (CHPID 0x%X) - " +- "there is a network problem or " +- "someone pulled the cable or " +- "disabled the port.\n", ++ dev_warn(&card->gdev->dev, ++ "The link for interface %s on CHPID" ++ " 0x%X failed\n", + QETH_CARD_IFNAME(card), + card->info.chpid); + card->lan_online = 0; +@@ -404,9 +409,9 @@ static struct qeth_ipa_cmd *qeth_check_i + netif_carrier_off(card->dev); + return NULL; + case IPA_CMD_STARTLAN: +- PRINT_INFO("Link reestablished on %s " +- "(CHPID 0x%X). Scheduling " +- "IP address reset.\n", ++ dev_info(&card->gdev->dev, ++ "The link for %s on CHPID 0x%X has" ++ " been restored\n", + QETH_CARD_IFNAME(card), + card->info.chpid); + netif_carrier_on(card->dev); +@@ -458,7 +463,7 @@ static int qeth_check_idx_response(unsig + + QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN); + if ((buffer[2] & 0xc0) == 0xc0) { +- PRINT_WARN("received an IDX TERMINATE " ++ QETH_DBF_MESSAGE(2, "received an IDX TERMINATE " + "with cause code 0x%02x%s\n", + buffer[4], + ((buffer[4] == 0x22) ? +@@ -744,8 +749,10 @@ static int qeth_get_problem(struct ccw_d + SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | + SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) { + QETH_DBF_TEXT(TRACE, 2, "CGENCHK"); +- PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ", +- cdev->dev.bus_id, dstat, cstat); ++ dev_warn(&cdev->dev, "The qeth device driver " ++ "failed to recover an error on the device\n"); ++ QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x ", ++ dev_name(&cdev->dev), dstat, cstat); + print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET, + 16, 1, irb, 64, 1); + return 1; +@@ -784,12 +791,14 @@ static long __qeth_check_irb_error(struc + + switch (PTR_ERR(irb)) { + case -EIO: +- PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id); ++ QETH_DBF_MESSAGE(2, "%s i/o-error on device\n", ++ dev_name(&cdev->dev)); + QETH_DBF_TEXT(TRACE, 2, "ckirberr"); + QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO); + break; + case -ETIMEDOUT: +- PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); ++ dev_warn(&cdev->dev, "A hardware operation timed out" ++ " on the device\n"); + QETH_DBF_TEXT(TRACE, 2, "ckirberr"); + QETH_DBF_TEXT_(TRACE, 2, " rc%d", -ETIMEDOUT); + if (intparm == QETH_RCD_PARM) { +@@ -802,8 +811,8 @@ static long __qeth_check_irb_error(struc + } + break; + default: +- PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), +- cdev->dev.bus_id); ++ QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n", ++ dev_name(&cdev->dev), PTR_ERR(irb)); + QETH_DBF_TEXT(TRACE, 2, "ckirberr"); + QETH_DBF_TEXT(TRACE, 2, " rc???"); + } +@@ -869,10 +878,12 @@ static void qeth_irq(struct ccw_device * + (dstat & DEV_STAT_UNIT_CHECK) || + (cstat)) { + if (irb->esw.esw0.erw.cons) { +- /* TODO: we should make this s390dbf */ +- PRINT_WARN("sense data available on channel %s.\n", +- CHANNEL_ID(channel)); +- PRINT_WARN(" cstat 0x%X\n dstat 0x%X\n", cstat, dstat); ++ dev_warn(&channel->ccwdev->dev, ++ "The qeth device driver failed to recover " ++ "an error on the device\n"); ++ QETH_DBF_MESSAGE(2, "%s sense data available. cstat " ++ "0x%X dstat 0x%X\n", ++ dev_name(&channel->ccwdev->dev), cstat, dstat); + print_hex_dump(KERN_WARNING, "qeth: irb ", + DUMP_PREFIX_OFFSET, 16, 1, irb, 32, 1); + print_hex_dump(KERN_WARNING, "qeth: sense data ", +@@ -1174,8 +1185,8 @@ static int qeth_determine_card_type(stru + card->qdio.no_out_queues = known_devices[i][8]; + card->info.is_multicast_different = known_devices[i][9]; + if (qeth_is_1920_device(card)) { +- PRINT_INFO("Priority Queueing not able " +- "due to hardware limitations!\n"); ++ dev_info(&card->gdev->dev, ++ "Priority Queueing not supported\n"); + card->qdio.no_out_queues = 1; + card->qdio.default_out_queue = 0; + } +@@ -1184,7 +1195,8 @@ static int qeth_determine_card_type(stru + i++; + } + card->info.type = QETH_CARD_TYPE_UNKNOWN; +- PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card)); ++ dev_err(&card->gdev->dev, "The adapter hardware is of an " ++ "unknown type\n"); + return -ENOENT; + } + +@@ -1367,8 +1379,8 @@ static int qeth_get_unitaddr(struct qeth + QETH_DBF_TEXT(SETUP, 2, "getunit"); + rc = qeth_read_conf_data(card, (void **) &prcd, &length); + if (rc) { +- PRINT_ERR("qeth_read_conf_data for device %s returned %i\n", +- CARD_DDEV_ID(card), rc); ++ QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", ++ dev_name(&card->gdev->dev), rc); + return rc; + } + card->info.chpid = prcd[30]; +@@ -1518,7 +1530,10 @@ static int qeth_idx_activate_channel(str + if (rc == -ERESTARTSYS) + return rc; + if (channel->state != CH_STATE_ACTIVATING) { +- PRINT_WARN("IDX activate timed out!\n"); ++ dev_warn(&channel->ccwdev->dev, "The qeth device driver" ++ " failed to recover an error on the device\n"); ++ QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n", ++ dev_name(&channel->ccwdev->dev)); + QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); + qeth_clear_cmd_buffers(channel); + return -ETIME; +@@ -1551,20 +1566,21 @@ static void qeth_idx_write_cb(struct qet + + if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { + if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) +- PRINT_ERR("IDX_ACTIVATE on write channel device %s: " +- "adapter exclusively used by another host\n", +- CARD_WDEV_ID(card)); ++ dev_err(&card->write.ccwdev->dev, ++ "The adapter is used exclusively by another " ++ "host\n"); + else +- PRINT_ERR("IDX_ACTIVATE on write channel device %s: " +- "negative reply\n", CARD_WDEV_ID(card)); ++ QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel:" ++ " negative reply\n", ++ dev_name(&card->write.ccwdev->dev)); + goto out; + } + memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); + if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) { +- PRINT_WARN("IDX_ACTIVATE on write channel device %s: " +- "function level mismatch " +- "(sent: 0x%x, received: 0x%x)\n", +- CARD_WDEV_ID(card), card->info.func_level, temp); ++ QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel: " ++ "function level mismatch (sent: 0x%x, received: " ++ "0x%x)\n", dev_name(&card->write.ccwdev->dev), ++ card->info.func_level, temp); + goto out; + } + channel->state = CH_STATE_UP; +@@ -1590,12 +1606,13 @@ static void qeth_idx_read_cb(struct qeth + + if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { + if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) +- PRINT_ERR("IDX_ACTIVATE on read channel device %s: " +- "adapter exclusively used by another host\n", +- CARD_RDEV_ID(card)); ++ dev_err(&card->write.ccwdev->dev, ++ "The adapter is used exclusively by another " ++ "host\n"); + else +- PRINT_ERR("IDX_ACTIVATE on read channel device %s: " +- "negative reply\n", CARD_RDEV_ID(card)); ++ QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:" ++ " negative reply\n", ++ dev_name(&card->read.ccwdev->dev)); + goto out; + } + +@@ -1609,9 +1626,10 @@ static void qeth_idx_read_cb(struct qeth + + memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); + if (temp != qeth_peer_func_level(card->info.func_level)) { +- PRINT_WARN("IDX_ACTIVATE on read channel device %s: function " +- "level mismatch (sent: 0x%x, received: 0x%x)\n", +- CARD_RDEV_ID(card), card->info.func_level, temp); ++ QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel: function " ++ "level mismatch (sent: 0x%x, received: 0x%x)\n", ++ dev_name(&card->read.ccwdev->dev), ++ card->info.func_level, temp); + goto out; + } + memcpy(&card->token.issuer_rm_r, +@@ -1685,8 +1703,9 @@ int qeth_send_control_data(struct qeth_c + (addr_t) iob, 0, 0); + spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); + if (rc) { +- PRINT_WARN("qeth_send_control_data: " +- "ccw_device_start rc = %i\n", rc); ++ QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: " ++ "ccw_device_start rc = %i\n", ++ dev_name(&card->write.ccwdev->dev), rc); + QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); + spin_lock_irqsave(&card->lock, flags); + list_del_init(&reply->list); +@@ -2169,11 +2188,8 @@ static void qeth_print_status_with_portn + dbf_text[i] = + (char) _ebcasc[(__u8) dbf_text[i]]; + dbf_text[8] = 0; +- PRINT_INFO("Device %s/%s/%s is a%s card%s%s%s\n" ++ dev_info(&card->gdev->dev, "Device is a%s card%s%s%s\n" + "with link type %s (portname: %s)\n", +- CARD_RDEV_ID(card), +- CARD_WDEV_ID(card), +- CARD_DDEV_ID(card), + qeth_get_cardname(card), + (card->info.mcl_level[0]) ? " (level: " : "", + (card->info.mcl_level[0]) ? card->info.mcl_level : "", +@@ -2186,23 +2202,17 @@ static void qeth_print_status_with_portn + static void qeth_print_status_no_portname(struct qeth_card *card) + { + if (card->info.portname[0]) +- PRINT_INFO("Device %s/%s/%s is a%s " ++ dev_info(&card->gdev->dev, "Device is a%s " + "card%s%s%s\nwith link type %s " + "(no portname needed by interface).\n", +- CARD_RDEV_ID(card), +- CARD_WDEV_ID(card), +- CARD_DDEV_ID(card), + qeth_get_cardname(card), + (card->info.mcl_level[0]) ? " (level: " : "", + (card->info.mcl_level[0]) ? card->info.mcl_level : "", + (card->info.mcl_level[0]) ? ")" : "", + qeth_get_cardname_short(card)); + else +- PRINT_INFO("Device %s/%s/%s is a%s " ++ dev_info(&card->gdev->dev, "Device is a%s " + "card%s%s%s\nwith link type %s.\n", +- CARD_RDEV_ID(card), +- CARD_WDEV_ID(card), +- CARD_DDEV_ID(card), + qeth_get_cardname(card), + (card->info.mcl_level[0]) ? " (level: " : "", + (card->info.mcl_level[0]) ? card->info.mcl_level : "", +@@ -2629,9 +2639,8 @@ void qeth_queue_input_buffer(struct qeth + qeth_get_micros() - + card->perf_stats.inbound_do_qdio_start_time; + if (rc) { +- PRINT_WARN("qeth_queue_input_buffer's do_QDIO " +- "return %i (device %s).\n", +- rc, CARD_DDEV_ID(card)); ++ dev_warn(&card->gdev->dev, ++ "QDIO reported an error, rc=%i\n", rc); + QETH_DBF_TEXT(TRACE, 2, "qinberr"); + QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card)); + } +@@ -3764,7 +3773,8 @@ int qeth_core_hardsetup_card(struct qeth + atomic_set(&card->force_alloc_skb, 0); + retry: + if (retries < 3) { +- PRINT_WARN("Retrying to do IDX activates.\n"); ++ QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n", ++ dev_name(&card->gdev->dev)); + ccw_device_set_offline(CARD_DDEV(card)); + ccw_device_set_offline(CARD_WDEV(card)); + ccw_device_set_offline(CARD_RDEV(card)); +@@ -3832,7 +3842,10 @@ retry: + } + return 0; + out: +- PRINT_ERR("Initialization in hardsetup failed! rc=%d\n", rc); ++ dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " ++ "an error on the device\n"); ++ QETH_DBF_MESSAGE(2, "%s Initialization in hardsetup failed! rc=%d\n", ++ dev_name(&card->gdev->dev), rc); + return rc; + } + EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card); +@@ -4052,8 +4065,8 @@ int qeth_core_load_discipline(struct qet + break; + } + if (!card->discipline.ccwgdriver) { +- PRINT_ERR("Support for discipline %d not present\n", +- discipline); ++ dev_err(&card->gdev->dev, "There is no kernel module to " ++ "support discipline %d\n", discipline); + rc = -EINVAL; + } + return rc; +@@ -4445,7 +4458,7 @@ static int __init qeth_core_init(void) + { + int rc; + +- PRINT_INFO("loading core functions\n"); ++ pr_info("loading core functions\n"); + INIT_LIST_HEAD(&qeth_core_card_list.list); + rwlock_init(&qeth_core_card_list.rwlock); + +@@ -4485,9 +4498,10 @@ driver_err: + ccwgroup_err: + ccw_driver_unregister(&qeth_ccw_driver); + ccw_err: ++ QETH_DBF_MESSAGE(2, "Initialization failed with code %d\n", rc); + qeth_unregister_dbf_views(); + out_err: +- PRINT_ERR("Initialization failed with code %d\n", rc); ++ pr_err("Initializing the qeth device driver failed\n"); + return rc; + } + +@@ -4500,7 +4514,7 @@ static void __exit qeth_core_exit(void) + ccw_driver_unregister(&qeth_ccw_driver); + kmem_cache_destroy(qeth_core_header_cache); + qeth_unregister_dbf_views(); +- PRINT_INFO("core functions removed\n"); ++ pr_info("core functions removed\n"); + } + + module_init(qeth_core_init); +--- a/drivers/s390/net/qeth_l2_main.c ++++ b/drivers/s390/net/qeth_l2_main.c +@@ -8,6 +8,8 @@ + * Frank Blaschka + */ + ++#define KMSG_COMPONENT "qeth" ++ + #include + #include + #include +@@ -501,12 +503,13 @@ static int qeth_l2_send_setmac_cb(struct + card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; + memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, + OSA_ADDR_LEN); +- PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " +- "successfully registered on device %s\n", +- card->dev->dev_addr[0], card->dev->dev_addr[1], +- card->dev->dev_addr[2], card->dev->dev_addr[3], +- card->dev->dev_addr[4], card->dev->dev_addr[5], +- card->dev->name); ++ dev_info(&card->gdev->dev, ++ "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " ++ "successfully registered on device %s\n", ++ card->dev->dev_addr[0], card->dev->dev_addr[1], ++ card->dev->dev_addr[2], card->dev->dev_addr[3], ++ card->dev->dev_addr[4], card->dev->dev_addr[5], ++ card->dev->name); + } + return 0; + } +@@ -976,8 +979,6 @@ static int __qeth_l2_set_online(struct c + + qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); + if (qeth_wait_for_threads(card, ~QETH_RECOVER_THREAD)) { +- PRINT_WARN("set_online of card %s interrupted by user!\n", +- CARD_BUS_ID(card)); + return -ERESTARTSYS; + } + +@@ -1020,9 +1021,8 @@ static int __qeth_l2_set_online(struct c + if (rc) { + QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); + if (rc == 0xe080) { +- PRINT_WARN("LAN on card %s if offline! " +- "Waiting for STARTLAN from card.\n", +- CARD_BUS_ID(card)); ++ dev_warn(&card->gdev->dev, ++ "The LAN is offline\n"); + card->lan_online = 0; + } + return rc; +@@ -1092,8 +1092,6 @@ static int __qeth_l2_set_offline(struct + netif_carrier_off(card->dev); + recover_flag = card->state; + if (qeth_l2_stop_card(card, recovery_mode) == -ERESTARTSYS) { +- PRINT_WARN("Stopping card %s interrupted by user!\n", +- CARD_BUS_ID(card)); + return -ERESTARTSYS; + } + rc = ccw_device_set_offline(CARD_DDEV(card)); +@@ -1126,8 +1124,8 @@ static int qeth_l2_recover(void *ptr) + if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) + return 0; + QETH_DBF_TEXT(TRACE, 2, "recover2"); +- PRINT_WARN("Recovery of device %s started ...\n", +- CARD_BUS_ID(card)); ++ dev_warn(&card->gdev->dev, ++ "A recovery process has been started for the device\n"); + card->use_hard_stop = 1; + __qeth_l2_set_offline(card->gdev, 1); + rc = __qeth_l2_set_online(card->gdev, 1); +@@ -1135,23 +1133,23 @@ static int qeth_l2_recover(void *ptr) + qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); + qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); + if (!rc) +- PRINT_INFO("Device %s successfully recovered!\n", +- CARD_BUS_ID(card)); ++ dev_info(&card->gdev->dev, ++ "Device successfully recovered!\n"); + else +- PRINT_INFO("Device %s could not be recovered!\n", +- CARD_BUS_ID(card)); ++ dev_warn(&card->gdev->dev, "The qeth device driver " ++ "failed to recover an error on the device\n"); + return 0; + } + + static int __init qeth_l2_init(void) + { +- PRINT_INFO("register layer 2 discipline\n"); ++ pr_info("register layer 2 discipline\n"); + return 0; + } + + static void __exit qeth_l2_exit(void) + { +- PRINT_INFO("unregister layer 2 discipline\n"); ++ pr_info("unregister layer 2 discipline\n"); + } + + static void qeth_l2_shutdown(struct ccwgroup_device *gdev) +--- a/drivers/s390/net/qeth_l3_main.c ++++ b/drivers/s390/net/qeth_l3_main.c +@@ -8,6 +8,8 @@ + * Frank Blaschka + */ + ++#define KMSG_COMPONENT "qeth" ++ + #include + #include + #include +@@ -917,8 +919,8 @@ static int qeth_l3_register_addr_entry(s + if (rc) { + QETH_DBF_TEXT(TRACE, 2, "FAILED"); + qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf); +- PRINT_WARN("Could not register IP address %s (rc=0x%x/%d)\n", +- buf, rc, rc); ++ dev_warn(&card->gdev->dev, ++ "Registering IP address %s failed\n", buf); + } + return rc; + } +@@ -1029,24 +1031,22 @@ static int qeth_l3_setadapter_parms(stru + QETH_DBF_TEXT(SETUP, 2, "setadprm"); + + if (!qeth_is_supported(card, IPA_SETADAPTERPARMS)) { +- PRINT_WARN("set adapter parameters not supported " +- "on device %s.\n", +- CARD_BUS_ID(card)); ++ dev_info(&card->gdev->dev, ++ "set adapter parameters not supported.\n"); + QETH_DBF_TEXT(SETUP, 2, " notsupp"); + return 0; + } + rc = qeth_query_setadapterparms(card); + if (rc) { +- PRINT_WARN("couldn't set adapter parameters on device %s: " +- "x%x\n", CARD_BUS_ID(card), rc); ++ QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: " ++ "0x%x\n", card->gdev->dev.bus_id, rc); + return rc; + } + if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) { + rc = qeth_setadpparms_change_macaddr(card); + if (rc) +- PRINT_WARN("couldn't get MAC address on " +- "device %s: x%x\n", +- CARD_BUS_ID(card), rc); ++ dev_warn(&card->gdev->dev, "Reading the adapter MAC" ++ " address failed\n", rc); + } + + if ((card->info.link_type == QETH_LINK_TYPE_HSTR) || +@@ -1160,16 +1160,17 @@ static int qeth_l3_start_ipa_arp_process + QETH_DBF_TEXT(TRACE, 3, "ipaarp"); + + if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { +- PRINT_WARN("ARP processing not supported " +- "on %s!\n", QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "ARP processing not supported on %s!\n", ++ QETH_CARD_IFNAME(card)); + return 0; + } + rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING, + IPA_CMD_ASS_START, 0); + if (rc) { +- PRINT_WARN("Could not start ARP processing " +- "assist on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Starting ARP processing support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + } + return rc; + } +@@ -1181,19 +1182,21 @@ static int qeth_l3_start_ipa_ip_fragment + QETH_DBF_TEXT(TRACE, 3, "ipaipfrg"); + + if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { +- PRINT_INFO("Hardware IP fragmentation not supported on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Hardware IP fragmentation not supported on %s\n", ++ QETH_CARD_IFNAME(card)); + return -EOPNOTSUPP; + } + + rc = qeth_l3_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, + IPA_CMD_ASS_START, 0); + if (rc) { +- PRINT_WARN("Could not start Hardware IP fragmentation " +- "assist on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Starting IP fragmentation support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + } else +- PRINT_INFO("Hardware IP fragmentation enabled \n"); ++ dev_info(&card->gdev->dev, ++ "Hardware IP fragmentation enabled \n"); + return rc; + } + +@@ -1207,17 +1210,18 @@ static int qeth_l3_start_ipa_source_mac( + return -EOPNOTSUPP; + + if (!qeth_is_supported(card, IPA_SOURCE_MAC)) { +- PRINT_INFO("Inbound source address not " +- "supported on %s\n", QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Inbound source address not supported on %s\n", ++ QETH_CARD_IFNAME(card)); + return -EOPNOTSUPP; + } + + rc = qeth_l3_send_simple_setassparms(card, IPA_SOURCE_MAC, + IPA_CMD_ASS_START, 0); + if (rc) +- PRINT_WARN("Could not start inbound source " +- "assist on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Starting proxy ARP support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + +@@ -1228,19 +1232,19 @@ static int qeth_l3_start_ipa_vlan(struct + QETH_DBF_TEXT(TRACE, 3, "strtvlan"); + + if (!qeth_is_supported(card, IPA_FULL_VLAN)) { +- PRINT_WARN("VLAN not supported on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "VLAN not supported on %s\n", QETH_CARD_IFNAME(card)); + return -EOPNOTSUPP; + } + + rc = qeth_l3_send_simple_setassparms(card, IPA_VLAN_PRIO, + IPA_CMD_ASS_START, 0); + if (rc) { +- PRINT_WARN("Could not start vlan " +- "assist on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Starting VLAN support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + } else { +- PRINT_INFO("VLAN enabled \n"); ++ dev_info(&card->gdev->dev, "VLAN enabled\n"); + } + return rc; + } +@@ -1252,19 +1256,20 @@ static int qeth_l3_start_ipa_multicast(s + QETH_DBF_TEXT(TRACE, 3, "stmcast"); + + if (!qeth_is_supported(card, IPA_MULTICASTING)) { +- PRINT_WARN("Multicast not supported on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Multicast not supported on %s\n", ++ QETH_CARD_IFNAME(card)); + return -EOPNOTSUPP; + } + + rc = qeth_l3_send_simple_setassparms(card, IPA_MULTICASTING, + IPA_CMD_ASS_START, 0); + if (rc) { +- PRINT_WARN("Could not start multicast " +- "assist on %s: rc=%i\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Starting multicast support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + } else { +- PRINT_INFO("Multicast enabled\n"); ++ dev_info(&card->gdev->dev, "Multicast enabled\n"); + card->dev->flags |= IFF_MULTICAST; + } + return rc; +@@ -1315,36 +1320,37 @@ static int qeth_l3_softsetup_ipv6(struct + + rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6); + if (rc) { +- PRINT_ERR("IPv6 query ipassist failed on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_warn(&card->gdev->dev, ++ "Activating IPv6 support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + rc = qeth_l3_send_simple_setassparms(card, IPA_IPV6, + IPA_CMD_ASS_START, 3); + if (rc) { +- PRINT_WARN("IPv6 start assist (version 4) failed " +- "on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Activating IPv6 support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_IPV6, + IPA_CMD_ASS_START); + if (rc) { +- PRINT_WARN("IPV6 start assist (version 6) failed " +- "on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Activating IPv6 support for %s failed\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_PASSTHRU, + IPA_CMD_ASS_START); + if (rc) { +- PRINT_WARN("Could not enable passthrough " +- "on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Enabling the passthrough mode for %s failed\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + out: +- PRINT_INFO("IPV6 enabled \n"); ++ dev_info(&card->gdev->dev, "IPV6 enabled\n"); + return 0; + } + #endif +@@ -1356,8 +1362,8 @@ static int qeth_l3_start_ipa_ipv6(struct + QETH_DBF_TEXT(TRACE, 3, "strtipv6"); + + if (!qeth_is_supported(card, IPA_IPV6)) { +- PRINT_WARN("IPv6 not supported on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card)); + return 0; + } + #ifdef CONFIG_QETH_IPV6 +@@ -1373,34 +1379,35 @@ static int qeth_l3_start_ipa_broadcast(s + QETH_DBF_TEXT(TRACE, 3, "stbrdcst"); + card->info.broadcast_capable = 0; + if (!qeth_is_supported(card, IPA_FILTERING)) { +- PRINT_WARN("Broadcast not supported on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Broadcast not supported on %s\n", ++ QETH_CARD_IFNAME(card)); + rc = -EOPNOTSUPP; + goto out; + } + rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, + IPA_CMD_ASS_START, 0); + if (rc) { +- PRINT_WARN("Could not enable broadcasting filtering " +- "on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, "Enabling broadcast filtering for " ++ "%s failed\n", QETH_CARD_IFNAME(card)); + goto out; + } + + rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, + IPA_CMD_ASS_CONFIGURE, 1); + if (rc) { +- PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, ++ "Setting up broadcast filtering for %s failed\n", ++ QETH_CARD_IFNAME(card)); + goto out; + } + card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO; +- PRINT_INFO("Broadcast enabled \n"); ++ dev_info(&card->gdev->dev, "Broadcast enabled\n"); + rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, + IPA_CMD_ASS_ENABLE, 1); + if (rc) { +- PRINT_WARN("Could not set up broadcast echo filtering on " +- "%s: 0x%x\n", QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, "Setting up broadcast echo " ++ "filtering for %s failed\n", QETH_CARD_IFNAME(card)); + goto out; + } + card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO; +@@ -1419,18 +1426,18 @@ static int qeth_l3_send_checksum_command + rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, + IPA_CMD_ASS_START, 0); + if (rc) { +- PRINT_WARN("Starting Inbound HW Checksumming failed on %s: " +- "0x%x,\ncontinuing using Inbound SW Checksumming\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, "Starting HW checksumming for %s " ++ "failed, using SW checksumming\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, + IPA_CMD_ASS_ENABLE, + card->info.csum_mask); + if (rc) { +- PRINT_WARN("Enabling Inbound HW Checksumming failed on %s: " +- "0x%x,\ncontinuing using Inbound SW Checksumming\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s " ++ "failed, using SW checksumming\n", ++ QETH_CARD_IFNAME(card)); + return rc; + } + return 0; +@@ -1443,26 +1450,30 @@ static int qeth_l3_start_ipa_checksum(st + QETH_DBF_TEXT(TRACE, 3, "strtcsum"); + + if (card->options.checksum_type == NO_CHECKSUMMING) { +- PRINT_WARN("Using no checksumming on %s.\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Using no checksumming on %s.\n", ++ QETH_CARD_IFNAME(card)); + return 0; + } + if (card->options.checksum_type == SW_CHECKSUMMING) { +- PRINT_WARN("Using SW checksumming on %s.\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Using SW checksumming on %s.\n", ++ QETH_CARD_IFNAME(card)); + return 0; + } + if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { +- PRINT_WARN("Inbound HW Checksumming not " +- "supported on %s,\ncontinuing " +- "using Inbound SW Checksumming\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Inbound HW Checksumming not " ++ "supported on %s,\ncontinuing " ++ "using Inbound SW Checksumming\n", ++ QETH_CARD_IFNAME(card)); + card->options.checksum_type = SW_CHECKSUMMING; + return 0; + } + rc = qeth_l3_send_checksum_command(card); + if (!rc) +- PRINT_INFO("HW Checksumming (inbound) enabled \n"); ++ dev_info(&card->gdev->dev, ++ "HW Checksumming (inbound) enabled\n"); + + return rc; + } +@@ -1474,18 +1485,20 @@ static int qeth_l3_start_ipa_tso(struct + QETH_DBF_TEXT(TRACE, 3, "sttso"); + + if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) { +- PRINT_WARN("Outbound TSO not supported on %s\n", +- QETH_CARD_IFNAME(card)); ++ dev_info(&card->gdev->dev, ++ "Outbound TSO not supported on %s\n", ++ QETH_CARD_IFNAME(card)); + rc = -EOPNOTSUPP; + } else { + rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_TSO, + IPA_CMD_ASS_START, 0); + if (rc) +- PRINT_WARN("Could not start outbound TSO " +- "assist on %s: rc=%i\n", +- QETH_CARD_IFNAME(card), rc); ++ dev_warn(&card->gdev->dev, "Starting outbound TCP " ++ "segmentation offload for %s failed\n", ++ QETH_CARD_IFNAME(card)); + else +- PRINT_INFO("Outbound TSO enabled\n"); ++ dev_info(&card->gdev->dev, ++ "Outbound TSO enabled\n"); + } + if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) { + card->options.large_send = QETH_LARGE_SEND_NO; +@@ -1578,12 +1591,8 @@ static int qeth_l3_get_unique_id_cb(stru + else { + card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED | + UNIQUE_ID_NOT_BY_CARD; +- PRINT_WARN("couldn't get a unique id from the card on device " +- "%s (result=x%x), using default id. ipv6 " +- "autoconfig on other lpars may lead to duplicate " +- "ip addresses. please use manually " +- "configured ones.\n", +- CARD_BUS_ID(card), cmd->hdr.return_code); ++ dev_warn(&card->gdev->dev, "The network adapter failed to " ++ "generate a unique ID\n"); + } + return 0; + } +@@ -3052,8 +3061,6 @@ static int __qeth_l3_set_online(struct c + + qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); + if (qeth_wait_for_threads(card, ~QETH_RECOVER_THREAD)) { +- PRINT_WARN("set_online of card %s interrupted by user!\n", +- CARD_BUS_ID(card)); + return -ERESTARTSYS; + } + +@@ -3095,9 +3102,8 @@ static int __qeth_l3_set_online(struct c + if (rc) { + QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); + if (rc == 0xe080) { +- PRINT_WARN("LAN on card %s if offline! " +- "Waiting for STARTLAN from card.\n", +- CARD_BUS_ID(card)); ++ dev_warn(&card->gdev->dev, ++ "The LAN is offline\n"); + card->lan_online = 0; + } + return rc; +@@ -3173,8 +3179,6 @@ static int __qeth_l3_set_offline(struct + netif_carrier_off(card->dev); + recover_flag = card->state; + if (qeth_l3_stop_card(card, recovery_mode) == -ERESTARTSYS) { +- PRINT_WARN("Stopping card %s interrupted by user!\n", +- CARD_BUS_ID(card)); + return -ERESTARTSYS; + } + rc = ccw_device_set_offline(CARD_DDEV(card)); +@@ -3207,8 +3211,8 @@ static int qeth_l3_recover(void *ptr) + if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) + return 0; + QETH_DBF_TEXT(TRACE, 2, "recover2"); +- PRINT_WARN("Recovery of device %s started ...\n", +- CARD_BUS_ID(card)); ++ dev_warn(&card->gdev->dev, ++ "A recovery process has been started for the device\n"); + card->use_hard_stop = 1; + __qeth_l3_set_offline(card->gdev, 1); + rc = __qeth_l3_set_online(card->gdev, 1); +@@ -3216,11 +3220,11 @@ static int qeth_l3_recover(void *ptr) + qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); + qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); + if (!rc) +- PRINT_INFO("Device %s successfully recovered!\n", +- CARD_BUS_ID(card)); ++ dev_info(&card->gdev->dev, ++ "Device successfully recovered!\n"); + else +- PRINT_INFO("Device %s could not be recovered!\n", +- CARD_BUS_ID(card)); ++ dev_warn(&card->gdev->dev, "The qeth device driver " ++ "failed to recover an error on the device\n"); + return 0; + } + +@@ -3353,7 +3357,7 @@ static int qeth_l3_register_notifiers(vo + return rc; + } + #else +- PRINT_WARN("layer 3 discipline no IPv6 support\n"); ++ pr_warning("There is no IPv6 support for the layer 3 discipline\n"); + #endif + return 0; + } +@@ -3372,7 +3376,7 @@ static int __init qeth_l3_init(void) + { + int rc = 0; + +- PRINT_INFO("register layer 3 discipline\n"); ++ pr_info("register layer 3 discipline\n"); + rc = qeth_l3_register_notifiers(); + return rc; + } +@@ -3380,7 +3384,7 @@ static int __init qeth_l3_init(void) + static void __exit qeth_l3_exit(void) + { + qeth_l3_unregister_notifiers(); +- PRINT_INFO("unregister layer 3 discipline\n"); ++ pr_info("unregister layer 3 discipline\n"); + } + + module_init(qeth_l3_init); +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -25,6 +25,8 @@ + * Sven Schuetz + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include + #include "zfcp_ext.h" + +@@ -100,8 +102,7 @@ static int __init zfcp_device_setup(char + + err_out: + kfree(str); +- pr_err("zfcp: Parse error for device parameter string %s, " +- "device not attached.\n", devstr); ++ pr_err("%s is not a valid SCSI device\n", devstr); + return 0; + } + +@@ -193,13 +194,14 @@ static int __init zfcp_module_init(void) + + retval = misc_register(&zfcp_cfdc_misc); + if (retval) { +- pr_err("zfcp: registration of misc device zfcp_cfdc failed\n"); ++ pr_err("Registering the misc device zfcp_cfdc failed\n"); + goto out_misc; + } + + retval = zfcp_ccw_register(); + if (retval) { +- pr_err("zfcp: Registration with common I/O layer failed.\n"); ++ pr_err("The zfcp device driver could not register with " ++ "the common I/O layer\n"); + goto out_ccw_register; + } + +--- a/drivers/s390/scsi/zfcp_ccw.c ++++ b/drivers/s390/scsi/zfcp_ccw.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include "zfcp_ext.h" + + /** +@@ -25,7 +27,8 @@ static int zfcp_ccw_probe(struct ccw_dev + down(&zfcp_data.config_sema); + if (zfcp_adapter_enqueue(ccw_device)) { + dev_err(&ccw_device->dev, +- "Setup of data structures failed.\n"); ++ "Setting up data structures for the " ++ "FCP adapter failed\n"); + retval = -EINVAL; + } + up(&zfcp_data.config_sema); +@@ -156,15 +159,18 @@ static int zfcp_ccw_notify(struct ccw_de + + switch (event) { + case CIO_GONE: +- dev_warn(&adapter->ccw_device->dev, "device gone\n"); ++ dev_warn(&adapter->ccw_device->dev, ++ "The FCP device has been detached\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 87, NULL); + break; + case CIO_NO_PATH: +- dev_warn(&adapter->ccw_device->dev, "no path\n"); ++ dev_warn(&adapter->ccw_device->dev, ++ "The CHPID for the FCP device is offline\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 88, NULL); + break; + case CIO_OPER: +- dev_info(&adapter->ccw_device->dev, "operational again\n"); ++ dev_info(&adapter->ccw_device->dev, ++ "The FCP device is operational again\n"); + zfcp_erp_modify_adapter_status(adapter, 11, NULL, + ZFCP_STATUS_COMMON_RUNNING, + ZFCP_SET); +--- a/drivers/s390/scsi/zfcp_cfdc.c ++++ b/drivers/s390/scsi/zfcp_cfdc.c +@@ -7,6 +7,8 @@ + * Copyright IBM Corporation 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include + #include + #include +--- a/drivers/s390/scsi/zfcp_dbf.c ++++ b/drivers/s390/scsi/zfcp_dbf.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include + #include + #include "zfcp_ext.h" +--- a/drivers/s390/scsi/zfcp_erp.c ++++ b/drivers/s390/scsi/zfcp_erp.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include "zfcp_ext.h" + + #define ZFCP_MAX_ERPS 3 +@@ -901,11 +903,6 @@ static int zfcp_erp_open_ptp_port(struct + struct zfcp_port *port = act->port; + + if (port->wwpn != adapter->peer_wwpn) { +- dev_err(&adapter->ccw_device->dev, +- "Failed to open port 0x%016Lx, " +- "Peer WWPN 0x%016Lx does not " +- "match.\n", port->wwpn, +- adapter->peer_wwpn); + zfcp_erp_port_failed(port, 25, NULL); + return ZFCP_ERP_FAILED; + } +@@ -1065,8 +1062,14 @@ static int zfcp_erp_strategy_check_unit( + break; + case ZFCP_ERP_FAILED : + atomic_inc(&unit->erp_counter); +- if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) ++ if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { ++ dev_err(&unit->port->adapter->ccw_device->dev, ++ "ERP failed for unit 0x%016Lx on " ++ "port 0x%016Lx\n", ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_unit_failed(unit, 21, NULL); ++ } + break; + } + +@@ -1091,8 +1094,12 @@ static int zfcp_erp_strategy_check_port( + result = ZFCP_ERP_EXIT; + } + atomic_inc(&port->erp_counter); +- if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) ++ if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { ++ dev_err(&port->adapter->ccw_device->dev, ++ "ERP failed for remote port 0x%016Lx\n", ++ (unsigned long long)port->wwpn); + zfcp_erp_port_failed(port, 22, NULL); ++ } + break; + } + +@@ -1114,8 +1121,12 @@ static int zfcp_erp_strategy_check_adapt + + case ZFCP_ERP_FAILED : + atomic_inc(&adapter->erp_counter); +- if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) ++ if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { ++ dev_err(&adapter->ccw_device->dev, ++ "ERP cannot recover an error " ++ "on the FCP device\n"); + zfcp_erp_adapter_failed(adapter, 23, NULL); ++ } + break; + } + +@@ -1263,9 +1274,9 @@ static void zfcp_erp_schedule_work(struc + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + dev_err(&unit->port->adapter->ccw_device->dev, +- "Out of resources. Could not register unit " +- "0x%016Lx on port 0x%016Lx with SCSI stack.\n", +- unit->fcp_lun, unit->port->wwpn); ++ "Registering unit 0x%016Lx on port 0x%016Lx failed\n", ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + return; + } + +@@ -1286,8 +1297,8 @@ static void zfcp_erp_rport_register(stru + port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); + if (!port->rport) { + dev_err(&port->adapter->ccw_device->dev, +- "Failed registration of rport " +- "0x%016Lx.\n", port->wwpn); ++ "Registering port 0x%016Lx failed\n", ++ (unsigned long long)port->wwpn); + return; + } + +@@ -1484,7 +1495,7 @@ int zfcp_erp_thread_setup(struct zfcp_ad + retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); + if (retval < 0) { + dev_err(&adapter->ccw_device->dev, +- "Creation of ERP thread failed.\n"); ++ "Creating an ERP thread for the FCP device failed.\n"); + return retval; + } + wait_event(adapter->erp_thread_wqh, +@@ -1526,7 +1537,6 @@ void zfcp_erp_adapter_failed(struct zfcp + { + zfcp_erp_modify_adapter_status(adapter, id, ref, + ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); +- dev_err(&adapter->ccw_device->dev, "Adapter ERP failed.\n"); + } + + /** +@@ -1539,15 +1549,6 @@ void zfcp_erp_port_failed(struct zfcp_po + { + zfcp_erp_modify_port_status(port, id, ref, + ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); +- +- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) +- dev_err(&port->adapter->ccw_device->dev, +- "Port ERP failed for WKA port d_id=0x%06x.\n", +- port->d_id); +- else +- dev_err(&port->adapter->ccw_device->dev, +- "Port ERP failed for port wwpn=0x%016Lx.\n", +- port->wwpn); + } + + /** +@@ -1560,10 +1561,6 @@ void zfcp_erp_unit_failed(struct zfcp_un + { + zfcp_erp_modify_unit_status(unit, id, ref, + ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); +- +- dev_err(&unit->port->adapter->ccw_device->dev, +- "Unit ERP failed for unit 0x%016Lx on port 0x%016Lx.\n", +- unit->fcp_lun, unit->port->wwpn); + } + + /** +--- a/drivers/s390/scsi/zfcp_fc.c ++++ b/drivers/s390/scsi/zfcp_fc.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include "zfcp_ext.h" + + struct ct_iu_gpn_ft_req { +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include + #include "zfcp_ext.h" + +@@ -51,19 +53,16 @@ static u32 fsf_qtcb_type[] = { + [FSF_QTCB_UPLOAD_CONTROL_FILE] = FSF_SUPPORT_COMMAND + }; + +-static const char *zfcp_act_subtable_type[] = { +- "unknown", "OS", "WWPN", "DID", "LUN" +-}; +- + static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) + { + u16 subtable = table >> 16; + u16 rule = table & 0xffff; ++ const char *act_type[] = { "unknown", "OS", "WWPN", "DID", "LUN" }; + +- if (subtable && subtable < ARRAY_SIZE(zfcp_act_subtable_type)) ++ if (subtable && subtable < ARRAY_SIZE(act_type)) + dev_warn(&adapter->ccw_device->dev, +- "Access denied in subtable %s, rule %d.\n", +- zfcp_act_subtable_type[subtable], rule); ++ "Access denied according to ACT rule type %s, " ++ "rule %d\n", act_type[subtable], rule); + } + + static void zfcp_fsf_access_denied_port(struct zfcp_fsf_req *req, +@@ -71,7 +70,7 @@ static void zfcp_fsf_access_denied_port( + { + struct fsf_qtcb_header *header = &req->qtcb->header; + dev_warn(&req->adapter->ccw_device->dev, +- "Access denied, cannot send command to port 0x%016Lx.\n", ++ "Access denied to port 0x%016Lx\n", + port->wwpn); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); +@@ -84,7 +83,7 @@ static void zfcp_fsf_access_denied_unit( + { + struct fsf_qtcb_header *header = &req->qtcb->header; + dev_warn(&req->adapter->ccw_device->dev, +- "Access denied for unit 0x%016Lx on port 0x%016Lx.\n", ++ "Access denied to unit 0x%016Lx on port 0x%016Lx\n", + unit->fcp_lun, unit->port->wwpn); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); +@@ -94,9 +93,8 @@ static void zfcp_fsf_access_denied_unit( + + static void zfcp_fsf_class_not_supp(struct zfcp_fsf_req *req) + { +- dev_err(&req->adapter->ccw_device->dev, +- "Required FC class not supported by adapter, " +- "shutting down adapter.\n"); ++ dev_err(&req->adapter->ccw_device->dev, "FCP device not " ++ "operational because of an unsupported FC class\n"); + zfcp_erp_adapter_shutdown(req->adapter, 0, 123, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + } +@@ -172,42 +170,6 @@ static void zfcp_fsf_status_read_port_cl + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + } + +-static void zfcp_fsf_bit_error_threshold(struct zfcp_fsf_req *req) +-{ +- struct zfcp_adapter *adapter = req->adapter; +- struct fsf_status_read_buffer *sr_buf = req->data; +- struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; +- +- dev_warn(&adapter->ccw_device->dev, +- "Warning: bit error threshold data " +- "received for the adapter: " +- "link failures = %i, loss of sync errors = %i, " +- "loss of signal errors = %i, " +- "primitive sequence errors = %i, " +- "invalid transmission word errors = %i, " +- "CRC errors = %i).\n", +- err->link_failure_error_count, +- err->loss_of_sync_error_count, +- err->loss_of_signal_error_count, +- err->primitive_sequence_error_count, +- err->invalid_transmission_word_error_count, +- err->crc_error_count); +- dev_warn(&adapter->ccw_device->dev, +- "Additional bit error threshold data of the adapter: " +- "primitive sequence event time-outs = %i, " +- "elastic buffer overrun errors = %i, " +- "advertised receive buffer-to-buffer credit = %i, " +- "current receice buffer-to-buffer credit = %i, " +- "advertised transmit buffer-to-buffer credit = %i, " +- "current transmit buffer-to-buffer credit = %i).\n", +- err->primitive_sequence_event_timeout_count, +- err->elastic_buffer_overrun_error_count, +- err->advertised_receive_b2b_credit, +- err->current_receive_b2b_credit, +- err->advertised_transmit_b2b_credit, +- err->current_transmit_b2b_credit); +-} +- + static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, u8 id, + struct fsf_link_down_info *link_down) + { +@@ -224,62 +186,66 @@ static void zfcp_fsf_link_down_info_eval + switch (link_down->error_code) { + case FSF_PSQ_LINK_NO_LIGHT: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: no light detected.\n"); ++ "There is no light signal from the local " ++ "fibre channel cable\n"); + break; + case FSF_PSQ_LINK_WRAP_PLUG: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: wrap plug detected.\n"); ++ "There is a wrap plug instead of a fibre " ++ "channel cable\n"); + break; + case FSF_PSQ_LINK_NO_FCP: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "adjacent node on link does not support FCP.\n"); ++ "The adjacent fibre channel node does not " ++ "support FCP\n"); + break; + case FSF_PSQ_LINK_FIRMWARE_UPDATE: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "firmware update in progress.\n"); ++ "The FCP device is suspended because of a " ++ "firmware update\n"); + break; + case FSF_PSQ_LINK_INVALID_WWPN: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "duplicate or invalid WWPN detected.\n"); ++ "The FCP device detected a WWPN that is " ++ "duplicate or not valid\n"); + break; + case FSF_PSQ_LINK_NO_NPIV_SUPPORT: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "no support for NPIV by Fabric.\n"); ++ "The fibre channel fabric does not support NPIV\n"); + break; + case FSF_PSQ_LINK_NO_FCP_RESOURCES: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "out of resource in FCP daughtercard.\n"); ++ "The FCP adapter cannot support more NPIV ports\n"); + break; + case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "out of resource in Fabric.\n"); ++ "The adjacent switch cannot support " ++ "more NPIV ports\n"); + break; + case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link is down: " +- "unable to login to Fabric.\n"); ++ "The FCP adapter could not log in to the " ++ "fibre channel fabric\n"); + break; + case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: + dev_warn(&req->adapter->ccw_device->dev, +- "WWPN assignment file corrupted on adapter.\n"); ++ "The WWPN assignment file on the FCP adapter " ++ "has been damaged\n"); + break; + case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: + dev_warn(&req->adapter->ccw_device->dev, +- "Mode table corrupted on adapter.\n"); ++ "The mode table on the FCP adapter " ++ "has been damaged\n"); + break; + case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: + dev_warn(&req->adapter->ccw_device->dev, +- "No WWPN for assignment table on adapter.\n"); ++ "All NPIV ports on the FCP adapter have " ++ "been assigned\n"); + break; + default: + dev_warn(&req->adapter->ccw_device->dev, +- "The local link to adapter is down.\n"); ++ "The link between the FCP adapter and " ++ "the FC fabric is down\n"); + } + out: + zfcp_erp_adapter_failed(adapter, id, req); +@@ -287,27 +253,18 @@ out: + + static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) + { +- struct zfcp_adapter *adapter = req->adapter; + struct fsf_status_read_buffer *sr_buf = req->data; + struct fsf_link_down_info *ldi = + (struct fsf_link_down_info *) &sr_buf->payload; + + switch (sr_buf->status_subtype) { + case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: +- dev_warn(&adapter->ccw_device->dev, +- "Physical link is down.\n"); + zfcp_fsf_link_down_info_eval(req, 38, ldi); + break; + case FSF_STATUS_READ_SUB_FDISC_FAILED: +- dev_warn(&adapter->ccw_device->dev, +- "Local link is down " +- "due to failed FDISC login.\n"); + zfcp_fsf_link_down_info_eval(req, 39, ldi); + break; + case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: +- dev_warn(&adapter->ccw_device->dev, +- "Local link is down " +- "due to firmware update on adapter.\n"); + zfcp_fsf_link_down_info_eval(req, 40, NULL); + }; + } +@@ -336,14 +293,16 @@ static void zfcp_fsf_status_read_handler + case FSF_STATUS_READ_SENSE_DATA_AVAIL: + break; + case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: +- zfcp_fsf_bit_error_threshold(req); ++ dev_warn(&adapter->ccw_device->dev, ++ "The error threshold for checksum statistics " ++ "has been exceeded\n"); + break; + case FSF_STATUS_READ_LINK_DOWN: + zfcp_fsf_status_read_link_down(req); + break; + case FSF_STATUS_READ_LINK_UP: + dev_info(&adapter->ccw_device->dev, +- "Local link was replugged.\n"); ++ "The local link has been restored\n"); + /* All ports should be marked as ready to run again */ + zfcp_erp_modify_adapter_status(adapter, 30, NULL, + ZFCP_STATUS_COMMON_RUNNING, +@@ -387,8 +346,8 @@ static void zfcp_fsf_fsfstatus_qual_eval + break; + case FSF_SQ_NO_RECOM: + dev_err(&req->adapter->ccw_device->dev, +- "No recommendation could be given for a " +- "problem on the adapter.\n"); ++ "The FCP adapter reported a problem " ++ "that cannot be recovered\n"); + zfcp_erp_adapter_shutdown(req->adapter, 0, 121, req); + break; + } +@@ -404,8 +363,7 @@ static void zfcp_fsf_fsfstatus_eval(stru + switch (req->qtcb->header.fsf_status) { + case FSF_UNKNOWN_COMMAND: + dev_err(&req->adapter->ccw_device->dev, +- "Command issued by the device driver (0x%x) is " +- "not known by the adapter.\n", ++ "The FCP adapter does not recognize the command 0x%x\n", + req->qtcb->header.fsf_command); + zfcp_erp_adapter_shutdown(req->adapter, 0, 120, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; +@@ -436,11 +394,9 @@ static void zfcp_fsf_protstatus_eval(str + return; + case FSF_PROT_QTCB_VERSION_ERROR: + dev_err(&adapter->ccw_device->dev, +- "The QTCB version requested by zfcp (0x%x) is not " +- "supported by the FCP adapter (lowest supported " +- "0x%x, highest supported 0x%x).\n", +- FSF_QTCB_CURRENT_VERSION, psq->word[0], +- psq->word[1]); ++ "QTCB version 0x%x not supported by FCP adapter " ++ "(0x%x to 0x%x)\n", FSF_QTCB_CURRENT_VERSION, ++ psq->word[0], psq->word[1]); + zfcp_erp_adapter_shutdown(adapter, 0, 117, req); + break; + case FSF_PROT_ERROR_STATE: +@@ -450,8 +406,7 @@ static void zfcp_fsf_protstatus_eval(str + break; + case FSF_PROT_UNSUPP_QTCB_TYPE: + dev_err(&adapter->ccw_device->dev, +- "Packet header type used by the device driver is " +- "incompatible with that used on the adapter.\n"); ++ "The QTCB type is not supported by the FCP adapter\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 118, req); + break; + case FSF_PROT_HOST_CONNECTION_INITIALIZING: +@@ -460,7 +415,7 @@ static void zfcp_fsf_protstatus_eval(str + break; + case FSF_PROT_DUPLICATE_REQUEST_ID: + dev_err(&adapter->ccw_device->dev, +- "The request identifier 0x%Lx is ambiguous.\n", ++ "0x%Lx is an ambiguous request identifier\n", + (unsigned long long)qtcb->bottom.support.req_handle); + zfcp_erp_adapter_shutdown(adapter, 0, 78, req); + break; +@@ -480,9 +435,7 @@ static void zfcp_fsf_protstatus_eval(str + break; + default: + dev_err(&adapter->ccw_device->dev, +- "Transfer protocol status information" +- "provided by the adapter (0x%x) " +- "is not compatible with the device driver.\n", ++ "0x%x is not a valid transfer protocol status\n", + qtcb->prefix.prot_status); + zfcp_erp_adapter_shutdown(adapter, 0, 119, req); + } +@@ -560,33 +513,17 @@ static int zfcp_fsf_exchange_config_eval + adapter->peer_wwpn = bottom->plogi_payload.wwpn; + adapter->peer_wwnn = bottom->plogi_payload.wwnn; + fc_host_port_type(shost) = FC_PORTTYPE_PTP; +- if (req->erp_action) +- dev_info(&adapter->ccw_device->dev, +- "Point-to-Point fibrechannel " +- "configuration detected.\n"); + break; + case FSF_TOPO_FABRIC: + fc_host_port_type(shost) = FC_PORTTYPE_NPORT; +- if (req->erp_action) +- dev_info(&adapter->ccw_device->dev, +- "Switched fabric fibrechannel " +- "network detected.\n"); + break; + case FSF_TOPO_AL: + fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; +- dev_err(&adapter->ccw_device->dev, +- "Unsupported arbitrated loop fibrechannel " +- "topology detected, shutting down " +- "adapter.\n"); +- zfcp_erp_adapter_shutdown(adapter, 0, 127, req); +- return -EIO; + default: +- fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; + dev_err(&adapter->ccw_device->dev, +- "The fibrechannel topology reported by the" +- " adapter is not known by the zfcp driver," +- " shutting down adapter.\n"); +- zfcp_erp_adapter_shutdown(adapter, 0, 128, req); ++ "Unknown or unsupported arbitrated loop " ++ "fibre channel topology detected\n"); ++ zfcp_erp_adapter_shutdown(adapter, 0, 127, req); + return -EIO; + } + +@@ -617,11 +554,9 @@ static void zfcp_fsf_exchange_config_dat + + if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { + dev_err(&adapter->ccw_device->dev, +- "Maximum QTCB size (%d bytes) allowed by " +- "the adapter is lower than the minimum " +- "required by the driver (%ld bytes).\n", +- bottom->max_qtcb_size, +- sizeof(struct fsf_qtcb)); ++ "FCP adapter maximum QTCB size (%d bytes) " ++ "is too small\n", ++ bottom->max_qtcb_size); + zfcp_erp_adapter_shutdown(adapter, 0, 129, req); + return; + } +@@ -657,15 +592,15 @@ static void zfcp_fsf_exchange_config_dat + + if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) { + dev_err(&adapter->ccw_device->dev, +- "The adapter only supports newer control block " +- "versions, try updated device driver.\n"); ++ "The FCP adapter only supports newer " ++ "control block versions\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 125, req); + return; + } + if (FSF_QTCB_CURRENT_VERSION > bottom->high_qtcb_version) { + dev_err(&adapter->ccw_device->dev, +- "The adapter only supports older control block " +- "versions, consider a microcode upgrade.\n"); ++ "The FCP adapter only supports older " ++ "control block versions\n"); + zfcp_erp_adapter_shutdown(adapter, 0, 126, req); + } + } +@@ -1465,8 +1400,8 @@ static void zfcp_fsf_open_port_handler(s + break; + case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: + dev_warn(&req->adapter->ccw_device->dev, +- "The adapter is out of resources. The remote port " +- "0x%016Lx could not be opened, disabling it.\n", ++ "Not enough FCP adapter resources to open " ++ "remote port 0x%016Lx\n", + port->wwpn); + zfcp_erp_port_failed(port, 31, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; +@@ -1479,8 +1414,8 @@ static void zfcp_fsf_open_port_handler(s + break; + case FSF_SQ_NO_RETRY_POSSIBLE: + dev_warn(&req->adapter->ccw_device->dev, +- "The remote port 0x%016Lx could not be " +- "opened. Disabling it.\n", port->wwpn); ++ "Remote port 0x%016Lx could not be opened\n", ++ port->wwpn); + zfcp_erp_port_failed(port, 32, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; +@@ -1786,14 +1721,12 @@ static void zfcp_fsf_open_unit_handler(s + case FSF_LUN_SHARING_VIOLATION: + if (header->fsf_status_qual.word[0]) + dev_warn(&adapter->ccw_device->dev, +- "FCP-LUN 0x%Lx at the remote port " +- "with WWPN 0x%Lx " +- "connected to the adapter " +- "is already in use in LPAR%d, CSS%d.\n", ++ "LUN 0x%Lx on port 0x%Lx is already in " ++ "use by CSS%d, MIF Image ID %x\n", + unit->fcp_lun, + unit->port->wwpn, +- queue_designator->hla, +- queue_designator->cssid); ++ queue_designator->cssid, ++ queue_designator->hla); + else + zfcp_act_eval_err(adapter, + header->fsf_status_qual.word[2]); +@@ -1804,8 +1737,8 @@ static void zfcp_fsf_open_unit_handler(s + break; + case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED: + dev_warn(&adapter->ccw_device->dev, +- "The adapter ran out of resources. There is no " +- "handle available for unit 0x%016Lx on port 0x%016Lx.", ++ "No handle is available for LUN " ++ "0x%016Lx on port 0x%016Lx\n", + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_unit_failed(unit, 34, req); + /* fall through */ +@@ -1843,25 +1776,25 @@ static void zfcp_fsf_open_unit_handler(s + atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, + &unit->status); + dev_info(&adapter->ccw_device->dev, +- "Read-only access for unit 0x%016Lx " +- "on port 0x%016Lx.\n", ++ "SCSI device at LUN 0x%016Lx on port " ++ "0x%016Lx opened read-only\n", + unit->fcp_lun, unit->port->wwpn); + } + + if (exclusive && !readwrite) { + dev_err(&adapter->ccw_device->dev, +- "Exclusive access of read-only unit " +- "0x%016Lx on port 0x%016Lx not " +- "supported, disabling unit.\n", ++ "Exclusive read-only access not " ++ "supported (unit 0x%016Lx, " ++ "port 0x%016Lx)\n", + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_unit_failed(unit, 35, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0, 80, req); + } else if (!exclusive && readwrite) { + dev_err(&adapter->ccw_device->dev, +- "Shared access of read-write unit " +- "0x%016Lx on port 0x%016Lx not " +- "supported, disabling unit.\n", ++ "Shared read-write access not " ++ "supported (unit 0x%016Lx, port " ++ "0x%016Lx\n)", + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_unit_failed(unit, 36, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; +@@ -2200,9 +2133,8 @@ static void zfcp_fsf_send_fcp_command_ha + break; + case FSF_DIRECTION_INDICATOR_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, +- "Invalid data direction (%d) given for unit " +- "0x%016Lx on port 0x%016Lx, shutting down " +- "adapter.\n", ++ "Incorrect direction %d, unit 0x%016Lx on port " ++ "0x%016Lx closed\n", + req->qtcb->bottom.io.data_direction, + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req); +@@ -2210,9 +2142,8 @@ static void zfcp_fsf_send_fcp_command_ha + break; + case FSF_CMND_LENGTH_NOT_VALID: + dev_err(&req->adapter->ccw_device->dev, +- "An invalid control-data-block length field (%d) " +- "was found in a command for unit 0x%016Lx on port " +- "0x%016Lx. Shutting down adapter.\n", ++ "Incorrect CDB length %d, unit 0x%016Lx on " ++ "port 0x%016Lx closed\n", + req->qtcb->bottom.io.fcp_cmnd_length, + unit->fcp_lun, unit->port->wwpn); + zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req); +@@ -2340,10 +2271,9 @@ int zfcp_fsf_send_fcp_command_task(struc + retval = -EIO; + else { + dev_err(&adapter->ccw_device->dev, +- "SCSI request too large. " +- "Shutting down unit 0x%016Lx on port " +- "0x%016Lx.\n", unit->fcp_lun, +- unit->port->wwpn); ++ "Oversize data package, unit 0x%016Lx " ++ "on port 0x%016Lx closed\n", ++ unit->fcp_lun, unit->port->wwpn); + zfcp_erp_unit_shutdown(unit, 0, 131, req); + retval = -EINVAL; + } +--- a/drivers/s390/scsi/zfcp_qdio.c ++++ b/drivers/s390/scsi/zfcp_qdio.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include "zfcp_ext.h" + + /* FIXME(tune): free space should be one max. SBAL chain plus what? */ +@@ -57,7 +59,7 @@ void zfcp_qdio_free(struct zfcp_adapter + + static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, u8 id) + { +- dev_warn(&adapter->ccw_device->dev, "QDIO problem occurred.\n"); ++ dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); + + zfcp_erp_adapter_reopen(adapter, + ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | +@@ -175,8 +177,8 @@ static void zfcp_qdio_int_resp(struct cc + + if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY))) + dev_warn(&adapter->ccw_device->dev, +- "Protocol violation by adapter. " +- "Continuing operations.\n"); ++ "A QDIO protocol error occurred, " ++ "operations continue\n"); + } + + /* +@@ -458,17 +460,11 @@ int zfcp_qdio_open(struct zfcp_adapter * + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) + return -EIO; + +- if (qdio_establish(&adapter->qdio_init_data)) { +- dev_err(&adapter->ccw_device->dev, +- "Establish of QDIO queues failed.\n"); +- return -EIO; +- } ++ if (qdio_establish(&adapter->qdio_init_data)) ++ goto failed_establish; + +- if (qdio_activate(adapter->ccw_device)) { +- dev_err(&adapter->ccw_device->dev, +- "Activate of QDIO queues failed.\n"); ++ if (qdio_activate(adapter->ccw_device)) + goto failed_qdio; +- } + + for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { + sbale = &(adapter->resp_q.sbal[cc]->element[0]); +@@ -478,11 +474,8 @@ int zfcp_qdio_open(struct zfcp_adapter * + } + + if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0, +- QDIO_MAX_BUFFERS_PER_Q)) { +- dev_err(&adapter->ccw_device->dev, +- "Init of QDIO response queue failed.\n"); ++ QDIO_MAX_BUFFERS_PER_Q)) + goto failed_qdio; +- } + + /* set index of first avalable SBALS / number of available SBALS */ + adapter->req_q.first = 0; +@@ -493,5 +486,8 @@ int zfcp_qdio_open(struct zfcp_adapter * + + failed_qdio: + qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); ++failed_establish: ++ dev_err(&adapter->ccw_device->dev, ++ "Setting up the QDIO connection to the FCP adapter failed\n"); + return -EIO; + } +--- a/drivers/s390/scsi/zfcp_scsi.c ++++ b/drivers/s390/scsi/zfcp_scsi.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2002, 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include "zfcp_ext.h" + #include + +@@ -294,7 +296,8 @@ int zfcp_adapter_scsi_register(struct zf + sizeof (struct zfcp_adapter *)); + if (!adapter->scsi_host) { + dev_err(&adapter->ccw_device->dev, +- "registration with SCSI stack failed."); ++ "Registering the FCP device with the " ++ "SCSI stack failed\n"); + return -EIO; + } + +--- a/drivers/s390/scsi/zfcp_sysfs.c ++++ b/drivers/s390/scsi/zfcp_sysfs.c +@@ -6,6 +6,8 @@ + * Copyright IBM Corporation 2008 + */ + ++#define KMSG_COMPONENT "zfcp" ++ + #include "zfcp_ext.h" + + #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -524,20 +524,34 @@ extern const char *dev_driver_string(con + printk(level "%s %s: " format , dev_driver_string(dev) , \ + dev_name(dev) , ## arg) + ++/* dev_printk_hash for message documentation */ ++#if defined(__KMSG_CHECKER) && defined(KMSG_COMPONENT) ++/* generate magic string for scripts/kmsg-doc to parse */ ++#define dev_printk_hash(level, dev, format, arg...) \ ++ __KMSG_DEV(level _FMT_ format _ARGS_ dev, ## arg _END_) ++#elif defined(CONFIG_KMSG_IDS) && defined(KMSG_COMPONENT) ++int printk_dev_hash(const char *, const char *, const char *, ...); ++#define dev_printk_hash(level, dev, format, arg...) \ ++ printk_dev_hash(level "%s.%06x: ", dev_driver_string(dev), \ ++ "%s: " format, dev_name(dev), ## arg) ++#else /* !defined(CONFIG_KMSG_IDS) */ ++#define dev_printk_hash dev_printk ++#endif ++ + #define dev_emerg(dev, format, arg...) \ +- dev_printk(KERN_EMERG , dev , format , ## arg) ++ dev_printk_hash(KERN_EMERG , dev , format , ## arg) + #define dev_alert(dev, format, arg...) \ +- dev_printk(KERN_ALERT , dev , format , ## arg) ++ dev_printk_hash(KERN_ALERT , dev , format , ## arg) + #define dev_crit(dev, format, arg...) \ +- dev_printk(KERN_CRIT , dev , format , ## arg) ++ dev_printk_hash(KERN_CRIT , dev , format , ## arg) + #define dev_err(dev, format, arg...) \ +- dev_printk(KERN_ERR , dev , format , ## arg) ++ dev_printk_hash(KERN_ERR , dev , format , ## arg) + #define dev_warn(dev, format, arg...) \ +- dev_printk(KERN_WARNING , dev , format , ## arg) ++ dev_printk_hash(KERN_WARNING , dev , format , ## arg) + #define dev_notice(dev, format, arg...) \ +- dev_printk(KERN_NOTICE , dev , format , ## arg) ++ dev_printk_hash(KERN_NOTICE , dev , format , ## arg) + #define dev_info(dev, format, arg...) \ +- dev_printk(KERN_INFO , dev , format , ## arg) ++ dev_printk_hash(KERN_INFO , dev , format , ## arg) + + #ifdef DEBUG + #define dev_dbg(dev, format, arg...) \ +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -296,28 +296,48 @@ static inline char *pack_hex_byte(char * + return buf; + } + ++#ifdef KMSG_COMPONENT ++#define pr_printk(level, format, ...) \ ++ printk(level KMSG_COMPONENT ": " format, ##__VA_ARGS__) ++#else ++#define pr_printk(level, format, ...) \ ++ printk(level ": " format, ##__VA_ARGS__) ++#endif ++ ++#if defined(__KMSG_CHECKER) && defined(KMSG_COMPONENT) ++/* generate magic string for scripts/kmsg-doc to parse */ ++#define pr_printk_hash(level, format, ...) \ ++ __KMSG_PRINT(level _FMT_ format _ARGS_ ##__VA_ARGS__ _END_) ++#elif defined(CONFIG_KMSG_IDS) && defined(KMSG_COMPONENT) ++int printk_hash(const char *, const char *, ...); ++#define pr_printk_hash(level, format, ...) \ ++ printk_hash(level KMSG_COMPONENT ".%06x" ": ", format, ##__VA_ARGS__) ++#else /* !defined(CONFIG_KMSG_IDS) */ ++#define pr_printk_hash pr_printk ++#endif ++ + #define pr_emerg(fmt, arg...) \ +- printk(KERN_EMERG fmt, ##arg) ++ pr_printk_hash(KERN_EMERG, fmt, ##arg) + #define pr_alert(fmt, arg...) \ +- printk(KERN_ALERT fmt, ##arg) ++ pr_printk_hash(KERN_ALERT, fmt, ##arg) + #define pr_crit(fmt, arg...) \ +- printk(KERN_CRIT fmt, ##arg) ++ pr_printk_hash(KERN_CRIT, fmt, ##arg) + #define pr_err(fmt, arg...) \ +- printk(KERN_ERR fmt, ##arg) ++ pr_printk_hash(KERN_ERR, fmt, ##arg) + #define pr_warning(fmt, arg...) \ +- printk(KERN_WARNING fmt, ##arg) ++ pr_printk_hash(KERN_WARNING, fmt, ##arg) + #define pr_notice(fmt, arg...) \ +- printk(KERN_NOTICE fmt, ##arg) ++ pr_printk_hash(KERN_NOTICE, fmt, ##arg) + #define pr_info(fmt, arg...) \ +- printk(KERN_INFO fmt, ##arg) ++ pr_printk_hash(KERN_INFO, fmt, ##arg) + + #ifdef DEBUG + /* If you are writing a driver, please use dev_dbg instead */ + #define pr_debug(fmt, arg...) \ +- printk(KERN_DEBUG fmt, ##arg) ++ pr_printk(KERN_DEBUG, fmt, ##arg) + #else + #define pr_debug(fmt, arg...) \ +- ({ if (0) printk(KERN_DEBUG fmt, ##arg); 0; }) ++ ({ if (0) pr_printk(KERN_DEBUG, fmt, ##arg); 0; }) + #endif + + /* +--- a/kernel/printk.c ++++ b/kernel/printk.c +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + #include + +@@ -1353,3 +1355,46 @@ bool printk_timed_ratelimit(unsigned lon + } + EXPORT_SYMBOL(printk_timed_ratelimit); + #endif ++ ++#if defined CONFIG_PRINTK && defined CONFIG_KMSG_IDS ++ ++/** ++ * printk_hash - print a kernel message include a hash over the message ++ * @prefix: message prefix including the ".%06x" for the hash ++ * @fmt: format string ++ */ ++asmlinkage int printk_hash(const char *prefix, const char *fmt, ...) ++{ ++ va_list args; ++ int r; ++ ++ r = printk(prefix, jhash(fmt, strlen(fmt), 0) & 0xffffff); ++ va_start(args, fmt); ++ r += vprintk(fmt, args); ++ va_end(args); ++ ++ return r; ++} ++EXPORT_SYMBOL(printk_hash); ++ ++/** ++ * printk_dev_hash - print a kernel message include a hash over the message ++ * @prefix: message prefix including the ".%06x" for the hash ++ * @dev: device this printk is all about ++ * @fmt: format string ++ */ ++asmlinkage int printk_dev_hash(const char *prefix, const char *driver_name, ++ const char *fmt, ...) ++{ ++ va_list args; ++ int r; ++ ++ r = printk(prefix, driver_name, jhash(fmt, strlen(fmt), 0) & 0xffffff); ++ va_start(args, fmt); ++ r += vprintk(fmt, args); ++ va_end(args); ++ ++ return r; ++} ++EXPORT_SYMBOL(printk_dev_hash); ++#endif +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -8,6 +8,8 @@ + * Author(s): Jennifer Hunt + */ + ++#define KMSG_COMPONENT "af_iucv" ++ + #include + #include + #include +@@ -616,6 +618,8 @@ static int iucv_sock_sendmsg(struct kioc + struct iucv_sock *iucv = iucv_sk(sk); + struct sk_buff *skb; + struct iucv_message txmsg; ++ char user_id[9]; ++ char appl_id[9]; + int err; + + err = sock_error(sk); +@@ -651,8 +655,15 @@ static int iucv_sock_sendmsg(struct kioc + err = iucv_message_send(iucv->path, &txmsg, 0, 0, + (void *) skb->data, skb->len); + if (err) { +- if (err == 3) +- printk(KERN_ERR "AF_IUCV msg limit exceeded\n"); ++ if (err == 3) { ++ user_id[8] = 0; ++ memcpy(user_id, iucv->dst_user_id, 8); ++ appl_id[8] = 0; ++ memcpy(appl_id, iucv->dst_name, 8); ++ pr_err("Application %s on z/VM guest %s" ++ " exceeds message limit\n", ++ user_id, appl_id); ++ } + skb_unlink(skb, &iucv->send_skb_q); + err = -EPIPE; + goto fail; +@@ -1190,7 +1201,8 @@ static int __init afiucv_init(void) + int err; + + if (!MACHINE_IS_VM) { +- printk(KERN_ERR "AF_IUCV connection needs VM as base\n"); ++ pr_err("The af_iucv module cannot be loaded" ++ " without z/VM\n"); + err = -EPROTONOSUPPORT; + goto out; + } +--- a/net/iucv/iucv.c ++++ b/net/iucv/iucv.c +@@ -30,6 +30,8 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + ++#define KMSG_COMPONENT "iucv" ++ + #include + #include + #include +@@ -424,8 +426,8 @@ static void iucv_declare_cpu(void *data) + err = "Paging or storage error"; + break; + } +- printk(KERN_WARNING "iucv_register: iucv_declare_buffer " +- "on cpu %i returned error 0x%02x (%s)\n", cpu, rc, err); ++ pr_warning("Defining an interrupt buffer on CPU %i" ++ " failed with 0x%02x (%s)\n", cpu, rc, err); + return; + } + +@@ -1572,7 +1574,7 @@ static void iucv_external_interrupt(u16 + BUG_ON(p->iptype < 0x01 || p->iptype > 0x09); + work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC); + if (!work) { +- printk(KERN_WARNING "iucv_external_interrupt: out of memory\n"); ++ pr_warning("iucv_external_interrupt: out of memory\n"); + return; + } + memcpy(&work->data, p, sizeof(work->data)); +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -223,12 +223,14 @@ endef + # Built-in and composite module parts + $(obj)/%.o: $(src)/%.c FORCE + $(call cmd,force_checksrc) ++ $(call cmd,force_check_kmsg) + $(call if_changed_rule,cc_o_c) + + # Single-part modules are special since we need to mark them in $(MODVERDIR) + + $(single-used-m): $(obj)/%.o: $(src)/%.c FORCE + $(call cmd,force_checksrc) ++ $(call cmd,force_check_kmsg) + $(call if_changed_rule,cc_o_c) + @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod) + +@@ -351,6 +353,18 @@ $(multi-used-m) : %.o: $(multi-objs-m) F + + targets += $(multi-used-y) $(multi-used-m) + ++# kmsg check tool ++ifneq ($(KBUILD_KMSG_CHECK),0) ++ ifeq ($(KBUILD_KMSG_CHECK),2) ++ kmsg_cmd := print ++ quiet_cmd_force_check_kmsg = KMSG_PRINT $< ++ $(shell [ -d $(objtree)/man ] || mkdir -p $(objtree)/man) ++ else ++ kmsg_cmd := check ++ quiet_cmd_force_check_kmsg = KMSG_CHECK $< ++ endif ++ cmd_force_check_kmsg = $(KMSG_CHECK) $(kmsg_cmd) $(CC) $(c_flags) $< ; ++endif + + # Descending + # --------------------------------------------------------------------------- +--- /dev/null ++++ b/scripts/kmsg-doc +@@ -0,0 +1,477 @@ ++#!/usr/bin/perl -w ++# ++# kmsg kernel messages check and print tool. ++# ++# To check the source code for missing messages the script is called ++# with check, the name compiler and the compile parameters ++# kmsg-doc check $(CC) $(c_flags) $< ++# To create man pages for the messages the script is called with ++# kmsg-doc print $(CC) $(c_flags) $< ++# ++# Copyright IBM Corp. 2008 ++# Author(s): Martin Schwidefsky ++# Michael Holzheu ++# ++ ++use Cwd; ++use Switch; ++ ++my $errors = 0; ++my $warnings = 0; ++my $srctree = ""; ++my $objtree = ""; ++my $kmsg_count = 0; ++ ++sub remove_quotes($) ++{ ++ my ($string) = @_; ++ my $inside = 0; ++ my $slash = 0; ++ my $result = ""; ++ ++ foreach my $str (split(/([\\"])/, $string)) { ++ if ($inside && ($str ne "\"" || $slash)) { ++ $result .= $str; ++ } ++ # Check for backslash before quote ++ if ($str eq "\"") { ++ if (!$slash) { ++ $inside = !$inside; ++ } ++ $slash = 0; ++ } elsif ($str eq "\\") { ++ $slash = !$slash; ++ } elsif ($str ne "") { ++ $slash = 0; ++ } ++ } ++ return $result; ++} ++ ++sub string_to_bytes($) ++{ ++ my ($string) = @_; ++ my %is_escape = ('"', 0x22, '\'', 0x27, 'n', 0x0a, 'r', 0x0d, 'b', 0x08, ++ 't', 0x09, 'f', 0x0c, 'a', 0x07, 'v', 0x0b, '?', 0x3f); ++ my (@ar, $slash, $len); ++ ++ # scan string, interpret backslash escapes and write bytes to @ar ++ $len = 0; ++ foreach my $ch (split(//, $string)) { ++ if ($ch eq '\\') { ++ $slash = !$slash; ++ if (!$slash) { ++ $ar[$len] = ord('\\'); ++ $len++; ++ } ++ } elsif ($slash && defined $is_escape{$ch}) { ++ # C99 backslash escapes: \\ \" \' \n \r \b \t \f \a \v \? ++ $ar[$len] = $is_escape{$ch}; ++ $len++; ++ $slash = 0; ++ } elsif ($slash) { ++ # FIXME: C99 backslash escapes \nnn \xhh ++ die("Unknown backslash escape in message $string."); ++ } else { ++ # normal character ++ $ar[$len] = ord($ch); ++ $len++; ++ } ++ } ++ return @ar; ++} ++ ++sub calc_jhash($) ++{ ++ my ($string) = @_; ++ my @ar; ++ my ($a, $b, $c, $i, $length, $len); ++ ++ @ar = string_to_bytes($string); ++ $length = @ar; ++ # add dummy elements to @ar to avoid if then else hell ++ push @ar, (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); ++ $a = 0x9e3779b9; ++ $b = 0x9e3779b9; ++ $c = 0; ++ $i = 0; ++ for ($len = $length + 12; $len >= 12; $len -= 12) { ++ if ($len < 24) { ++ # add length for last round ++ $c += $length; ++ } ++ $a += $ar[$i] + ($ar[$i+1]<<8) + ($ar[$i+2]<<16) + ($ar[$i+3]<<24); ++ $b += $ar[$i+4] + ($ar[$i+5]<<8) + ($ar[$i+6]<<16) + ($ar[$i+7]<<24); ++ if ($len >= 24) { ++ $c += $ar[$i+8] + ($ar[$i+9]<<8) + ($ar[$i+10]<<16) + ($ar[$i+11]<<24); ++ } else { ++ $c += ($ar[$i+8]<<8) + ($ar[$i+9]<<16) + ($ar[$i+10]<<24); ++ } ++ $a &= 0xffffffff; $b &= 0xffffffff; $c &= 0xffffffff; ++ $a -= $b; $a -= $c; $a ^= ($c >> 13); $a &= 0xffffffff; ++ $b -= $c; $b -= $a; $b ^= ($a << 8); $b &= 0xffffffff; ++ $c -= $a; $c -= $b; $c ^= ($b >> 13); $c &= 0xffffffff; ++ $a -= $b; $a -= $c; $a ^= ($c >> 12); $a &= 0xffffffff; ++ $b -= $c; $b -= $a; $b ^= ($a << 16); $b &= 0xffffffff; ++ $c -= $a; $c -= $b; $c ^= ($b >> 5); $c &= 0xffffffff; ++ $a -= $b; $a -= $c; $a ^= ($c >> 3); $a &= 0xffffffff; ++ $b -= $c; $b -= $a; $b ^= ($a << 10); $b &= 0xffffffff; ++ $c -= $a; $c -= $b; $c ^= ($b >> 15); $c &= 0xffffffff; ++ $i += 12; ++ } ++ return $c; ++} ++ ++sub add_kmsg_desc($$$$$$) ++{ ++ my ($component, $text, $sev, $argv, $desc, $user) = @_; ++ my ($hash, $tag); ++ ++ $text = remove_quotes($text); ++ $hash = substr(sprintf("%08x", calc_jhash($text)), 2, 6); ++ $tag = $component . "." . $hash; ++ ++ if ($kmsg_desc{$tag}) { ++ if ($text ne $kmsg_desc{$tag}->{'TEXT'}) { ++ warn "Duplicate message with tag $tag\n"; ++ warn " --- $kmsg_desc{$tag}->{'TEXT'}\n"; ++ warn " +++ $text\n"; ++ } else { ++ warn "Duplicate message description for \"$text\"\n"; ++ } ++ $errors++; ++ return; ++ } ++ $kmsg_desc{$tag}->{'TEXT'} = $text; ++ $kmsg_desc{$tag}->{'SEV'} = $sev; ++ $kmsg_desc{$tag}->{'ARGV'} = $argv; ++ $kmsg_desc{$tag}->{'DESC'} = $desc; ++ $kmsg_desc{$tag}->{'USER'} = $user; ++} ++ ++sub add_kmsg_print($$$$) ++{ ++ my ($component, $sev, $text, $argv) = @_; ++ my ($hash, $tag, $count, $parm); ++ ++ $text = remove_quotes($text); ++ $hash = substr(sprintf("%08x", calc_jhash($text)), 2, 6); ++ $tag = $component . "." . $hash; ++ ++ # Pretty print severity ++ $sev =~ s/"<0>"/Emerg/; ++ $sev =~ s/"<1>"/Alert/; ++ $sev =~ s/"<2>"/Critical/; ++ $sev =~ s/"<3>"/Error/; ++ $sev =~ s/"<4>"/Warning/; ++ $sev =~ s/"<5>"/Notice/; ++ $sev =~ s/"<6>"/Informational/; ++ $sev =~ s/"<7>"/Debug/; ++ $kmsg_print{$kmsg_count}->{'TAG'} = $tag; ++ $kmsg_print{$kmsg_count}->{'TEXT'} = $text; ++ $kmsg_print{$kmsg_count}->{'SEV'} = $sev; ++ $kmsg_print{$kmsg_count}->{'ARGV'} = $argv; ++ $kmsg_count += 1; ++} ++ ++sub process_source_file($$) ++{ ++ my ($component, $file) = @_; ++ my $state; ++ my ($text, $sev, $argv, $desc, $user); ++ ++ if (!open(FD, "$file")) { ++ return ""; ++ } ++ ++ $state = 0; ++ while () { ++ chomp; ++ # kmsg message component: #define KMSG_COMPONENT "" ++ if (/^#define\s+KMSG_COMPONENT\s+\"(.*)\"[^\"]*$/o) { ++ $component = $1; ++ } ++ if ($state == 0) { ++ # single line kmsg for undocumented messages, format: ++ # /*? Text: "" */ ++ if (/^\s*\/\*\?\s*Text:\s*(\".*\")\s*\*\/\s*$/o) { ++ add_kmsg_desc($component, $1, "", "", "", ""); ++ } ++ # kmsg message start: '/*?' ++ if (/^\s*\/\*\?\s*$/o) { ++ $state = 1; ++ ($text, $sev, $argv, $desc, $user) = ( "", "", "", "", "" ); ++ } ++ } elsif ($state == 1) { ++ # kmsg message end: ' */' ++ if (/^\s*\*\/\s*/o) { ++ add_kmsg_desc($component, $text, $sev, $argv, $desc, $user); ++ $state = 0; ++ } ++ # kmsg message text: ' * Text: ""' ++ elsif (/^\s*\*\s*Text:\s*(\".*\")\s*$/o) { ++ $text = $1; ++ } ++ # kmsg message severity: ' * Severity: ' ++ elsif (/^\s*\*\s*Severity:\s*(\S*)\s*$/o) { ++ $sev = $1; ++ } ++ # kmsg message parameter: ' * Parameter: ' ++ elsif (/^\s*\*\s*Parameter:\s*(\S*)\s*$/o) { ++ if (!defined($1)) { ++ $argv = ""; ++ } else { ++ $argv = $1; ++ } ++ $state = 2; ++ } ++ # kmsg message description start: ' * Description:' ++ elsif (/^\s*\*\s*Description:\s*(\S*)\s*$/o) { ++ if (!defined($1)) { ++ $desc = ""; ++ } else { ++ $desc = $1; ++ } ++ $state = 3; ++ } ++ # kmsg has unrecognizable lines ++ else { ++ warn "Warning(${file}:$.): Cannot understand $_"; ++ $warnings++; ++ $state = 0; ++ } ++ } elsif ($state == 2) { ++ # kmsg message end: ' */' ++ if (/^\s*\*\//o) { ++ warn "Warning(${file}:$.): Missing description, skipping message"; ++ $warnings++; ++ $state = 0; ++ } ++ # kmsg message description start: ' * Description:' ++ elsif (/^\s*\*\s*Description:\s*$/o) { ++ $desc = $1; ++ $state = 3; ++ } ++ # kmsg message parameter line: ' * ' ++ elsif (/^\s*\*(.*)$/o) { ++ $argv .= "\n" . $1; ++ } else { ++ warn "Warning(${file}:$.): Cannot understand $_"; ++ $warnings++; ++ $state = 0; ++ } ++ } elsif ($state == 3) { ++ # kmsg message end: ' */' ++ if (/^\s*\*\/\s*/o) { ++ add_kmsg_desc($component, $text, $sev, $argv, $desc, $user); ++ $state = 0; ++ } ++ # kmsg message description start: ' * User action:' ++ elsif (/^\s*\*\s*User action:\s*$/o) { ++ $user = $1; ++ $state = 4; ++ } ++ # kmsg message description line: ' * ' ++ elsif (/^\s*\*\s*(.*)$/o) { ++ $desc .= "\n" . $1; ++ } else { ++ warn "Warning(${file}:$.): Cannot understand $_"; ++ $warnings++; ++ $state = 0; ++ } ++ } elsif ($state == 4) { ++ # kmsg message end: ' */' ++ if (/^\s*\*\/\s*/o) { ++ add_kmsg_desc($component, $text, $sev, $argv, $desc, $user); ++ $state = 0; ++ } ++ # kmsg message user action line: ' * ' ++ elsif (/^\s*\*\s*(.*)$/o) { ++ $user .= "\n" . $1; ++ } else { ++ warn "Warning(${file}:$.): Cannot understand $_"; ++ $warnings++; ++ $state = 0; ++ } ++ } ++ } ++ return $component; ++} ++ ++sub process_cpp_file($$$$) ++{ ++ my ($cc, $options, $file, $component) = @_; ++ ++ open(FD, "$cc $gcc_options|") or die ("Preprocessing failed."); ++ ++ while () { ++ chomp; ++ if (/.*__KMSG_PRINT\(\s*(\S*)\s*_FMT_(.*)_ARGS_\s*(.*)?_END_\s*\)/o) { ++ if ($component ne "") { ++ add_kmsg_print($component, $1, $2, $3); ++ } else { ++ warn "Error(${file}:$.): kmsg without component\n"; ++ $errors++; ++ } ++ } elsif (/.*__KMSG_DEV\(\s*(\S*)\s*_FMT_(.*)_ARGS_\s*(.*)?_END_\s*\)/o) { ++ if ($component ne "") { ++ add_kmsg_print($component, $1, "\"%s: \"" . $2, $3); ++ } else { ++ warn "Error(${file}:$.): kmsg without component\n"; ++ $errors++; ++ } ++ } ++ } ++} ++ ++sub check_messages($) ++{ ++ my $component = "@_"; ++ my $failed = 0; ++ ++ for ($i = 0; $i < $kmsg_count; $i++) { ++ $tag = $kmsg_print{$i}->{'TAG'}; ++ if (!defined($kmsg_desc{$tag})) { ++ add_kmsg_desc($component, ++ "\"" . $kmsg_print{$i}->{'TEXT'} . "\"", ++ $kmsg_print{$i}->{'SEV'}, ++ $kmsg_print{$i}->{'ARGV'}, ++ "Please insert description here", ++ "What is the user supposed to do"); ++ $kmsg_desc{$tag}->{'CHECK'} = 1; ++ $failed = 1; ++ warn "$component: Missing description for: $kmsg_desc{$tag}\n"; ++ $errors++; ++ next; ++ } ++ if ($kmsg_desc{$tag}->{'SEV'} ne "" && ++ $kmsg_desc{$tag}->{'SEV'} ne $kmsg_print{$i}->{'SEV'}) { ++ warn "Message severity mismatch for \"$kmsg_print{$i}->{'TEXT'}\"\n"; ++ warn " --- $kmsg_desc{$tag}->{'SEV'}\n"; ++ warn " +++ $kmsg_print{$i}->{'SEV'}\n"; ++ } ++ } ++ return $failed; ++} ++ ++sub print_templates() ++{ ++ print "Templates for missing messages:\n"; ++ foreach $tag ( sort { $kmsg_desc{$a} <=> $kmsg_desc{$b} } keys %kmsg_desc ) { ++ if (!defined($kmsg_desc{$tag}->{'CHECK'})) { ++ next; ++ } ++ print "/*?\n"; ++ print " * Text: \"$kmsg_desc{$tag}->{'TEXT'}\"\n"; ++ print " * Severity: $kmsg_desc{$tag}->{'SEV'}\n"; ++ $argv = $kmsg_desc{$tag}->{'ARGV'}; ++ if ($argv ne "") { ++ print " * Parameter:\n"; ++ @parms = split(/\s*,\s*/,$kmsg_desc{$tag}->{'ARGV'}); ++ $count = 0; ++ foreach $parm (@parms) { ++ $count += 1; ++ if (!($parm eq "")) { ++ print " * \@$count: $parm\n"; ++ } ++ } ++ } ++ print " * Description:\n"; ++ print " * $kmsg_desc{$tag}->{'DESC'}\n"; ++ print " * User action:\n"; ++ print " * $kmsg_desc{$tag}->{'USER'}\n"; ++ print " */\n\n"; ++ } ++} ++ ++sub write_man_pages() ++{ ++ my ($i, $file); ++ ++ for ($i = 0; $i < $kmsg_count; $i++) { ++ $tag = $kmsg_print{$i}->{'TAG'}; ++ if (!defined($kmsg_desc{$tag}) || ++ defined($kmsg_desc{$tag}->{'CHECK'}) || ++ $kmsg_desc{$tag}->{'DESC'} eq "") { ++ next; ++ } ++ $file = $objtree . "man/" . $tag . ".9"; ++ if (!open(WR, ">$file")) { ++ warn "Error: Cannot open file $file\n"; ++ $errors++; ++ return; ++ } ++ print WR ".TH \"$tag\" 9 \"Linux Messages\" LINUX\n"; ++ print WR ".SH Message\n"; ++ print WR $tag . ": " . $kmsg_desc{$tag}->{'TEXT'} . "\n"; ++ print WR ".SH Severity\n"; ++ print WR "$kmsg_desc{$tag}->{'SEV'}\n"; ++ $argv = $kmsg_desc{$tag}->{'ARGV'}; ++ if ($argv ne "") { ++ print WR ".SH Parameters\n"; ++ @parms = split(/\s*\n\s*/,$kmsg_desc{$tag}->{'ARGV'}); ++ foreach $parm (@parms) { ++ $parm =~ s/^\s*(.*)\s*$/$1/; ++ if (!($parm eq "")) { ++ print WR "$parm\n\n"; ++ } ++ } ++ } ++ print WR ".SH Description"; ++ print WR "$kmsg_desc{$tag}->{'DESC'}\n"; ++ $user = $kmsg_desc{$tag}->{'USER'}; ++ if ($user ne "") { ++ print WR ".SH User action"; ++ print WR "$user\n"; ++ } ++ } ++} ++ ++if (defined($ENV{'srctree'})) { ++ $srctree = "$ENV{'srctree'}" . "/"; ++} else { ++ $srctree = getcwd; ++} ++ ++if (defined($ENV{'objtree'})) { ++ $objtree = "$ENV{'objtree'}" . "/"; ++} else { ++ $objtree = getcwd; ++} ++ ++if (defined($ENV{'SRCARCH'})) { ++ $srcarch = "$ENV{'SRCARCH'}" . "/"; ++} else { ++ print "kmsg-doc called without a valid \$SRCARCH\n"; ++ exit 1; ++} ++ ++$option = shift; ++ ++$cc = shift; ++$gcc_options = "-E -D __KMSG_CHECKER "; ++foreach $tmp (@ARGV) { ++ $tmp =~ s/\(/\\\(/; ++ $tmp =~ s/\)/\\\)/; ++ $gcc_options .= " $tmp"; ++ $filename = $tmp; ++} ++ ++$component = process_source_file("", $filename); ++if ($component ne "") { ++ process_source_file($component, $srctree . "Documentation/kmsg/" . ++ $srcarch . $component); ++ process_source_file($component, $srctree . "Documentation/kmsg/" . ++ $component); ++} ++ ++process_cpp_file($cc, $gcc_options, $filename, $component); ++if ($option eq "check") { ++ if (check_messages($component)) { ++ print_templates(); ++ } ++} elsif ($option eq "print") { ++ write_man_pages(); ++} ++ ++exit($errors); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-01-06-zfcp-cleanup-v2.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-01-06-zfcp-cleanup-v2.patch new file mode 100644 index 000000000..5ca23e576 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-01-06-zfcp-cleanup-v2.patch @@ -0,0 +1,3242 @@ +From: Gerald Schaefer +Subject: FCP - code cleanup stage 2 +References: bnc#417550 + +Stage 2 of the code cleanup covers functional aspects of zFCP driver + - state machine for adapter, port and unit + - layering violation issues regarding request processing + - modify exchange-port, + - config data to not use recovery semaphore + - kernel thread API adaption + - remove forced port recovery when port recovery is already running + - lock consolidation (config lock vs. other locks) + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 142 +++-------------- + drivers/s390/scsi/zfcp_ccw.c | 33 +++- + drivers/s390/scsi/zfcp_dbf.c | 73 +++++++-- + drivers/s390/scsi/zfcp_dbf.h | 1 + drivers/s390/scsi/zfcp_def.h | 178 +++++---------------- + drivers/s390/scsi/zfcp_erp.c | 178 ++++++--------------- + drivers/s390/scsi/zfcp_ext.h | 27 +-- + drivers/s390/scsi/zfcp_fc.c | 227 +++++++++++++++++++--------- + drivers/s390/scsi/zfcp_fsf.c | 332 ++++++++++++++++++++++++++++------------- + drivers/s390/scsi/zfcp_fsf.h | 75 --------- + drivers/s390/scsi/zfcp_qdio.c | 40 ++-- + drivers/s390/scsi/zfcp_scsi.c | 25 --- + drivers/s390/scsi/zfcp_sysfs.c | 47 ++--- + 13 files changed, 654 insertions(+), 724 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -90,11 +90,13 @@ static int __init zfcp_device_setup(char + strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); + + token = strsep(&str, ","); +- if (!token || strict_strtoull(token, 0, &zfcp_data.init_wwpn)) ++ if (!token || strict_strtoull(token, 0, ++ (unsigned long long *) &zfcp_data.init_wwpn)) + goto err_out; + + token = strsep(&str, ","); +- if (!token || strict_strtoull(token, 0, &zfcp_data.init_fcp_lun)) ++ if (!token || strict_strtoull(token, 0, ++ (unsigned long long *) &zfcp_data.init_fcp_lun)) + goto err_out; + + kfree(str); +@@ -106,19 +108,6 @@ static int __init zfcp_device_setup(char + return 0; + } + +-static struct zfcp_adapter *zfcp_get_adapter_by_busid(char *bus_id) +-{ +- struct zfcp_adapter *adapter; +- +- list_for_each_entry(adapter, &zfcp_data.adapter_list_head, list) +- if ((strncmp(bus_id, adapter->ccw_device->dev.bus_id, +- BUS_ID_SIZE) == 0) && +- !(atomic_read(&adapter->status) & +- ZFCP_STATUS_COMMON_REMOVE)) +- return adapter; +- return NULL; +-} +- + static void __init zfcp_init_device_configure(void) + { + struct zfcp_adapter *adapter; +@@ -142,7 +131,12 @@ static void __init zfcp_init_device_conf + goto out_unit; + up(&zfcp_data.config_sema); + ccw_device_set_online(adapter->ccw_device); ++ + zfcp_erp_wait(adapter); ++ wait_event(adapter->erp_done_wqh, ++ !(atomic_read(&unit->status) & ++ ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)); ++ + down(&zfcp_data.config_sema); + zfcp_unit_put(unit); + out_unit: +@@ -181,9 +175,9 @@ static int __init zfcp_module_init(void) + if (!zfcp_data.gid_pn_cache) + goto out_gid_cache; + +- INIT_LIST_HEAD(&zfcp_data.adapter_list_head); +- INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh); ++ zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq"); + ++ INIT_LIST_HEAD(&zfcp_data.adapter_list_head); + sema_init(&zfcp_data.config_sema, 1); + rwlock_init(&zfcp_data.config_lock); + +@@ -233,8 +227,7 @@ module_init(zfcp_module_init); + * + * Returns: pointer to zfcp_unit or NULL + */ +-struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, +- fcp_lun_t fcp_lun) ++struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) + { + struct zfcp_unit *unit; + +@@ -253,7 +246,7 @@ struct zfcp_unit *zfcp_get_unit_by_lun(s + * Returns: pointer to zfcp_port or NULL + */ + struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, +- wwn_t wwpn) ++ u64 wwpn) + { + struct zfcp_port *port; + +@@ -278,7 +271,7 @@ static void zfcp_sysfs_unit_release(stru + * + * Sets up some unit internal structures and creates sysfs entry. + */ +-struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) ++struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) + { + struct zfcp_unit *unit; + +@@ -292,7 +285,8 @@ struct zfcp_unit *zfcp_unit_enqueue(stru + unit->port = port; + unit->fcp_lun = fcp_lun; + +- snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", fcp_lun); ++ snprintf(unit->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", ++ (unsigned long long) fcp_lun); + unit->sysfs_device.parent = &port->sysfs_device; + unit->sysfs_device.release = zfcp_sysfs_unit_release; + dev_set_drvdata(&unit->sysfs_device, unit); +@@ -325,7 +319,6 @@ struct zfcp_unit *zfcp_unit_enqueue(stru + } + + zfcp_unit_get(unit); +- unit->scsi_lun = scsilun_to_int((struct scsi_lun *)&unit->fcp_lun); + + write_lock_irq(&zfcp_data.config_lock); + list_add_tail(&unit->list, &port->unit_list_head); +@@ -334,7 +327,6 @@ struct zfcp_unit *zfcp_unit_enqueue(stru + + write_unlock_irq(&zfcp_data.config_lock); + +- port->units++; + zfcp_port_get(port); + + return unit; +@@ -353,11 +345,10 @@ err_out_free: + */ + void zfcp_unit_dequeue(struct zfcp_unit *unit) + { +- zfcp_unit_wait(unit); ++ wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); + write_lock_irq(&zfcp_data.config_lock); + list_del(&unit->list); + write_unlock_irq(&zfcp_data.config_lock); +- unit->port->units--; + zfcp_port_put(unit->port); + sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); + device_unregister(&unit->sysfs_device); +@@ -418,11 +409,6 @@ static void zfcp_free_low_mem_buffers(st + mempool_destroy(adapter->pool.data_gid_pn); + } + +-static void zfcp_dummy_release(struct device *dev) +-{ +- return; +-} +- + /** + * zfcp_status_read_refill - refill the long running status_read_requests + * @adapter: ptr to struct zfcp_adapter for which the buffers should be refilled +@@ -452,19 +438,6 @@ static void _zfcp_status_read_scheduler( + stat_work)); + } + +-static int zfcp_nameserver_enqueue(struct zfcp_adapter *adapter) +-{ +- struct zfcp_port *port; +- +- port = zfcp_port_enqueue(adapter, 0, ZFCP_STATUS_PORT_WKA, +- ZFCP_DID_DIRECTORY_SERVICE); +- if (IS_ERR(port)) +- return PTR_ERR(port); +- zfcp_port_put(port); +- +- return 0; +-} +- + /** + * zfcp_adapter_enqueue - enqueue a new adapter to the list + * @ccw_device: pointer to the struct cc_device +@@ -510,7 +483,6 @@ int zfcp_adapter_enqueue(struct ccw_devi + init_waitqueue_head(&adapter->erp_done_wqh); + + INIT_LIST_HEAD(&adapter->port_list_head); +- INIT_LIST_HEAD(&adapter->port_remove_lh); + INIT_LIST_HEAD(&adapter->erp_ready_head); + INIT_LIST_HEAD(&adapter->erp_running_head); + +@@ -520,7 +492,7 @@ int zfcp_adapter_enqueue(struct ccw_devi + spin_lock_init(&adapter->san_dbf_lock); + spin_lock_init(&adapter->scsi_dbf_lock); + spin_lock_init(&adapter->rec_dbf_lock); +- spin_lock_init(&adapter->req_q.lock); ++ spin_lock_init(&adapter->req_q_lock); + + rwlock_init(&adapter->erp_lock); + rwlock_init(&adapter->abort_lock); +@@ -539,28 +511,15 @@ int zfcp_adapter_enqueue(struct ccw_devi + &zfcp_sysfs_adapter_attrs)) + goto sysfs_failed; + +- adapter->generic_services.parent = &adapter->ccw_device->dev; +- adapter->generic_services.release = zfcp_dummy_release; +- snprintf(adapter->generic_services.bus_id, BUS_ID_SIZE, +- "generic_services"); +- +- if (device_register(&adapter->generic_services)) +- goto generic_services_failed; +- + write_lock_irq(&zfcp_data.config_lock); + atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); + list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); + write_unlock_irq(&zfcp_data.config_lock); + +- zfcp_data.adapters++; +- +- zfcp_nameserver_enqueue(adapter); ++ zfcp_fc_nameserver_init(adapter); + + return 0; + +-generic_services_failed: +- sysfs_remove_group(&ccw_device->dev.kobj, +- &zfcp_sysfs_adapter_attrs); + sysfs_failed: + zfcp_adapter_debug_unregister(adapter); + debug_register_failed: +@@ -587,7 +546,6 @@ void zfcp_adapter_dequeue(struct zfcp_ad + cancel_work_sync(&adapter->scan_work); + cancel_work_sync(&adapter->stat_work); + zfcp_adapter_scsi_unregister(adapter); +- device_unregister(&adapter->generic_services); + sysfs_remove_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs); + dev_set_drvdata(&adapter->ccw_device->dev, NULL); +@@ -605,9 +563,6 @@ void zfcp_adapter_dequeue(struct zfcp_ad + list_del(&adapter->list); + write_unlock_irq(&zfcp_data.config_lock); + +- /* decrease number of adapters in list */ +- zfcp_data.adapters--; +- + zfcp_qdio_free(adapter); + + zfcp_free_low_mem_buffers(adapter); +@@ -635,21 +590,19 @@ static void zfcp_sysfs_port_release(stru + * d_id is used to enqueue ports with a well known address like the Directory + * Service for nameserver lookup. + */ +-struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, ++struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, + u32 status, u32 d_id) + { + struct zfcp_port *port; + int retval; +- char *bus_id; + + port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + init_waitqueue_head(&port->remove_wq); +- + INIT_LIST_HEAD(&port->unit_list_head); +- INIT_LIST_HEAD(&port->unit_remove_lh); ++ INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); + + port->adapter = adapter; + port->d_id = d_id; +@@ -659,34 +612,9 @@ struct zfcp_port *zfcp_port_enqueue(stru + atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); + atomic_set(&port->refcount, 0); + +- if (status & ZFCP_STATUS_PORT_WKA) { +- switch (d_id) { +- case ZFCP_DID_DIRECTORY_SERVICE: +- bus_id = "directory"; +- break; +- case ZFCP_DID_MANAGEMENT_SERVICE: +- bus_id = "management"; +- break; +- case ZFCP_DID_KEY_DISTRIBUTION_SERVICE: +- bus_id = "key_distribution"; +- break; +- case ZFCP_DID_ALIAS_SERVICE: +- bus_id = "alias"; +- break; +- case ZFCP_DID_TIME_SERVICE: +- bus_id = "time"; +- break; +- default: +- kfree(port); +- return ERR_PTR(-EINVAL); +- } +- snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "%s", bus_id); +- port->sysfs_device.parent = &adapter->generic_services; +- } else { +- snprintf(port->sysfs_device.bus_id, +- BUS_ID_SIZE, "0x%016llx", wwpn); +- port->sysfs_device.parent = &adapter->ccw_device->dev; +- } ++ snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", ++ (unsigned long long) wwpn); ++ port->sysfs_device.parent = &adapter->ccw_device->dev; + + port->sysfs_device.release = zfcp_sysfs_port_release; + dev_set_drvdata(&port->sysfs_device, port); +@@ -702,12 +630,8 @@ struct zfcp_port *zfcp_port_enqueue(stru + if (device_register(&port->sysfs_device)) + goto err_out_free; + +- if (status & ZFCP_STATUS_PORT_WKA) +- retval = sysfs_create_group(&port->sysfs_device.kobj, +- &zfcp_sysfs_ns_port_attrs); +- else +- retval = sysfs_create_group(&port->sysfs_device.kobj, +- &zfcp_sysfs_port_attrs); ++ retval = sysfs_create_group(&port->sysfs_device.kobj, ++ &zfcp_sysfs_port_attrs); + + if (retval) { + device_unregister(&port->sysfs_device); +@@ -720,10 +644,6 @@ struct zfcp_port *zfcp_port_enqueue(stru + list_add_tail(&port->list, &adapter->port_list_head); + atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); +- if (d_id == ZFCP_DID_DIRECTORY_SERVICE) +- if (!adapter->nameserver_port) +- adapter->nameserver_port = port; +- adapter->ports++; + + write_unlock_irq(&zfcp_data.config_lock); + +@@ -742,21 +662,15 @@ err_out: + */ + void zfcp_port_dequeue(struct zfcp_port *port) + { +- zfcp_port_wait(port); ++ wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); + write_lock_irq(&zfcp_data.config_lock); + list_del(&port->list); +- port->adapter->ports--; + write_unlock_irq(&zfcp_data.config_lock); + if (port->rport) + fc_remote_port_delete(port->rport); + port->rport = NULL; + zfcp_adapter_put(port->adapter); +- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA) +- sysfs_remove_group(&port->sysfs_device.kobj, +- &zfcp_sysfs_ns_port_attrs); +- else +- sysfs_remove_group(&port->sysfs_device.kobj, +- &zfcp_sysfs_port_attrs); ++ sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); + device_unregister(&port->sysfs_device); + } + +--- a/drivers/s390/scsi/zfcp_ccw.c ++++ b/drivers/s390/scsi/zfcp_ccw.c +@@ -49,6 +49,8 @@ static void zfcp_ccw_remove(struct ccw_d + struct zfcp_adapter *adapter; + struct zfcp_port *port, *p; + struct zfcp_unit *unit, *u; ++ LIST_HEAD(unit_remove_lh); ++ LIST_HEAD(port_remove_lh); + + ccw_device_set_offline(ccw_device); + down(&zfcp_data.config_sema); +@@ -57,26 +59,26 @@ static void zfcp_ccw_remove(struct ccw_d + write_lock_irq(&zfcp_data.config_lock); + list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { + list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { +- list_move(&unit->list, &port->unit_remove_lh); ++ list_move(&unit->list, &unit_remove_lh); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, + &unit->status); + } +- list_move(&port->list, &adapter->port_remove_lh); ++ list_move(&port->list, &port_remove_lh); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); + } + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); + write_unlock_irq(&zfcp_data.config_lock); + +- list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) { +- list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) { +- if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED, +- &unit->status)) ++ list_for_each_entry_safe(port, p, &port_remove_lh, list) { ++ list_for_each_entry_safe(unit, u, &unit_remove_lh, list) { ++ if (atomic_read(&unit->status) & ++ ZFCP_STATUS_UNIT_REGISTERED) + scsi_remove_device(unit->device); + zfcp_unit_dequeue(unit); + } + zfcp_port_dequeue(port); + } +- zfcp_adapter_wait(adapter); ++ wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); + zfcp_adapter_dequeue(adapter); + + up(&zfcp_data.config_sema); +@@ -226,3 +228,20 @@ int __init zfcp_ccw_register(void) + { + return ccw_driver_register(&zfcp_ccw_driver); + } ++ ++/** ++ * zfcp_get_adapter_by_busid - find zfcp_adapter struct ++ * @busid: bus id string of zfcp adapter to find ++ */ ++struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid) ++{ ++ struct ccw_device *ccw_device; ++ struct zfcp_adapter *adapter = NULL; ++ ++ ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); ++ if (ccw_device) { ++ adapter = dev_get_drvdata(&ccw_device->dev); ++ put_device(&ccw_device->dev); ++ } ++ return adapter; ++} +--- a/drivers/s390/scsi/zfcp_dbf.c ++++ b/drivers/s390/scsi/zfcp_dbf.c +@@ -320,6 +320,26 @@ void zfcp_hba_dbf_event_qdio(struct zfcp + spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); + } + ++/** ++ * zfcp_hba_dbf_event_berr - trace event for bit error threshold ++ * @adapter: adapter affected by this QDIO related event ++ * @req: fsf request ++ */ ++void zfcp_hba_dbf_event_berr(struct zfcp_adapter *adapter, ++ struct zfcp_fsf_req *req) ++{ ++ struct zfcp_hba_dbf_record *r = &adapter->hba_dbf_buf; ++ struct fsf_status_read_buffer *sr_buf = req->data; ++ struct fsf_bit_error_payload *err = &sr_buf->payload.bit_error; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->hba_dbf_lock, flags); ++ memset(r, 0, sizeof(*r)); ++ strncpy(r->tag, "berr", ZFCP_DBF_TAG_SIZE); ++ memcpy(&r->u.berr, err, sizeof(struct fsf_bit_error_payload)); ++ debug_event(adapter->hba_dbf, 0, r, sizeof(*r)); ++ spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); ++} + static void zfcp_hba_dbf_view_response(char **p, + struct zfcp_hba_dbf_record_response *r) + { +@@ -401,6 +421,30 @@ static void zfcp_hba_dbf_view_qdio(char + zfcp_dbf_out(p, "sbal_count", "0x%02x", r->sbal_count); + } + ++static void zfcp_hba_dbf_view_berr(char **p, struct fsf_bit_error_payload *r) ++{ ++ zfcp_dbf_out(p, "link_failures", "%d", r->link_failure_error_count); ++ zfcp_dbf_out(p, "loss_of_sync_err", "%d", r->loss_of_sync_error_count); ++ zfcp_dbf_out(p, "loss_of_sig_err", "%d", r->loss_of_signal_error_count); ++ zfcp_dbf_out(p, "prim_seq_err", "%d", ++ r->primitive_sequence_error_count); ++ zfcp_dbf_out(p, "inval_trans_word_err", "%d", ++ r->invalid_transmission_word_error_count); ++ zfcp_dbf_out(p, "CRC_errors", "%d", r->crc_error_count); ++ zfcp_dbf_out(p, "prim_seq_event_to", "%d", ++ r->primitive_sequence_event_timeout_count); ++ zfcp_dbf_out(p, "elast_buf_overrun_err", "%d", ++ r->elastic_buffer_overrun_error_count); ++ zfcp_dbf_out(p, "adv_rec_buf2buf_cred", "%d", ++ r->advertised_receive_b2b_credit); ++ zfcp_dbf_out(p, "curr_rec_buf2buf_cred", "%d", ++ r->current_receive_b2b_credit); ++ zfcp_dbf_out(p, "adv_trans_buf2buf_cred", "%d", ++ r->advertised_transmit_b2b_credit); ++ zfcp_dbf_out(p, "curr_trans_buf2buf_cred", "%d", ++ r->current_transmit_b2b_credit); ++} ++ + static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view, + char *out_buf, const char *in_buf) + { +@@ -420,6 +464,8 @@ static int zfcp_hba_dbf_view_format(debu + zfcp_hba_dbf_view_status(&p, &r->u.status); + else if (strncmp(r->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0) + zfcp_hba_dbf_view_qdio(&p, &r->u.qdio); ++ else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0) ++ zfcp_hba_dbf_view_berr(&p, &r->u.berr); + + p += sprintf(p, "\n"); + return p - out_buf; +@@ -521,14 +567,14 @@ static const char *zfcp_rec_dbf_ids[] = + [75] = "physical port recovery escalation after failed port " + "recovery", + [76] = "port recovery escalation after failed unit recovery", +- [77] = "recovery opening nameserver port", ++ [77] = "", + [78] = "duplicate request id", + [79] = "link down", + [80] = "exclusive read-only unit access unsupported", + [81] = "shared read-write unit access unsupported", + [82] = "incoming rscn", + [83] = "incoming wwpn", +- [84] = "", ++ [84] = "wka port handle not valid close port", + [85] = "online", + [86] = "offline", + [87] = "ccw device gone", +@@ -831,9 +877,9 @@ void zfcp_rec_dbf_event_action(u8 id2, s + void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) + { + struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; +- struct zfcp_port *port = ct->port; +- struct zfcp_adapter *adapter = port->adapter; +- struct ct_hdr *hdr = zfcp_sg_to_address(ct->req); ++ struct zfcp_wka_port *wka_port = ct->wka_port; ++ struct zfcp_adapter *adapter = wka_port->adapter; ++ struct ct_hdr *hdr = sg_virt(ct->req); + struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; + struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req; + unsigned long flags; +@@ -844,7 +890,7 @@ void zfcp_san_dbf_event_ct_request(struc + r->fsf_reqid = (unsigned long)fsf_req; + r->fsf_seqno = fsf_req->seq_no; + r->s_id = fc_host_port_id(adapter->scsi_host); +- r->d_id = port->d_id; ++ r->d_id = wka_port->d_id; + oct->cmd_req_code = hdr->cmd_rsp_code; + oct->revision = hdr->revision; + oct->gs_type = hdr->gs_type; +@@ -865,9 +911,9 @@ void zfcp_san_dbf_event_ct_request(struc + void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) + { + struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; +- struct zfcp_port *port = ct->port; +- struct zfcp_adapter *adapter = port->adapter; +- struct ct_hdr *hdr = zfcp_sg_to_address(ct->resp); ++ struct zfcp_wka_port *wka_port = ct->wka_port; ++ struct zfcp_adapter *adapter = wka_port->adapter; ++ struct ct_hdr *hdr = sg_virt(ct->resp); + struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; + struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp; + unsigned long flags; +@@ -877,7 +923,7 @@ void zfcp_san_dbf_event_ct_response(stru + strncpy(r->tag, "rctc", ZFCP_DBF_TAG_SIZE); + r->fsf_reqid = (unsigned long)fsf_req; + r->fsf_seqno = fsf_req->seq_no; +- r->s_id = port->d_id; ++ r->s_id = wka_port->d_id; + r->d_id = fc_host_port_id(adapter->scsi_host); + rct->cmd_rsp_code = hdr->cmd_rsp_code; + rct->revision = hdr->revision; +@@ -924,8 +970,8 @@ void zfcp_san_dbf_event_els_request(stru + + zfcp_san_dbf_event_els("oels", 2, fsf_req, + fc_host_port_id(els->adapter->scsi_host), +- els->d_id, *(u8 *) zfcp_sg_to_address(els->req), +- zfcp_sg_to_address(els->req), els->req->length); ++ els->d_id, *(u8 *) sg_virt(els->req), ++ sg_virt(els->req), els->req->length); + } + + /** +@@ -938,8 +984,7 @@ void zfcp_san_dbf_event_els_response(str + + zfcp_san_dbf_event_els("rels", 2, fsf_req, els->d_id, + fc_host_port_id(els->adapter->scsi_host), +- *(u8 *)zfcp_sg_to_address(els->req), +- zfcp_sg_to_address(els->resp), ++ *(u8 *)sg_virt(els->req), sg_virt(els->resp), + els->resp->length); + } + +--- a/drivers/s390/scsi/zfcp_dbf.h ++++ b/drivers/s390/scsi/zfcp_dbf.h +@@ -151,6 +151,7 @@ struct zfcp_hba_dbf_record { + struct zfcp_hba_dbf_record_response response; + struct zfcp_hba_dbf_record_status status; + struct zfcp_hba_dbf_record_qdio qdio; ++ struct fsf_bit_error_payload berr; + } u; + } __attribute__ ((packed)); + +--- a/drivers/s390/scsi/zfcp_def.h ++++ b/drivers/s390/scsi/zfcp_def.h +@@ -39,29 +39,6 @@ + + /********************* GENERAL DEFINES *********************************/ + +-/** +- * zfcp_sg_to_address - determine kernel address from struct scatterlist +- * @list: struct scatterlist +- * Return: kernel address +- */ +-static inline void * +-zfcp_sg_to_address(struct scatterlist *list) +-{ +- return sg_virt(list); +-} +- +-/** +- * zfcp_address_to_sg - set up struct scatterlist from kernel address +- * @address: kernel address +- * @list: struct scatterlist +- * @size: buffer size +- */ +-static inline void +-zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) +-{ +- sg_set_buf(list, address, size); +-} +- + #define REQUEST_LIST_SIZE 128 + + /********************* SCSI SPECIFIC DEFINES *********************************/ +@@ -101,11 +78,6 @@ zfcp_address_to_sg(void *address, struct + + /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ + +-typedef unsigned long long wwn_t; +-typedef unsigned long long fcp_lun_t; +-/* data length field may be at variable position in FCP-2 FCP_CMND IU */ +-typedef unsigned int fcp_dl_t; +- + /* timeout for name-server lookup (in seconds) */ + #define ZFCP_NS_GID_PN_TIMEOUT 10 + +@@ -129,7 +101,7 @@ typedef unsigned int fcp_dl_t; + + /* FCP(-2) FCP_CMND IU */ + struct fcp_cmnd_iu { +- fcp_lun_t fcp_lun; /* FCP logical unit number */ ++ u64 fcp_lun; /* FCP logical unit number */ + u8 crn; /* command reference number */ + u8 reserved0:5; /* reserved */ + u8 task_attribute:3; /* task attribute */ +@@ -204,7 +176,7 @@ struct fcp_rscn_element { + struct fcp_logo { + u32 command; + u32 nport_did; +- wwn_t nport_wwpn; ++ u64 nport_wwpn; + } __attribute__((packed)); + + /* +@@ -218,13 +190,6 @@ struct fcp_logo { + #define ZFCP_LS_RSCN 0x61 + #define ZFCP_LS_RNID 0x78 + +-struct zfcp_ls_rjt_par { +- u8 action; +- u8 reason_code; +- u8 reason_expl; +- u8 vendor_unique; +-} __attribute__ ((packed)); +- + struct zfcp_ls_adisc { + u8 code; + u8 field[3]; +@@ -234,20 +199,6 @@ struct zfcp_ls_adisc { + u32 nport_id; + } __attribute__ ((packed)); + +-struct zfcp_ls_adisc_acc { +- u8 code; +- u8 field[3]; +- u32 hard_nport_id; +- u64 wwpn; +- u64 wwnn; +- u32 nport_id; +-} __attribute__ ((packed)); +- +-struct zfcp_rc_entry { +- u8 code; +- const char *description; +-}; +- + /* + * FC-GS-2 stuff + */ +@@ -281,9 +232,7 @@ struct zfcp_rc_entry { + #define ZFCP_STATUS_COMMON_RUNNING 0x40000000 + #define ZFCP_STATUS_COMMON_ERP_FAILED 0x20000000 + #define ZFCP_STATUS_COMMON_UNBLOCKED 0x10000000 +-#define ZFCP_STATUS_COMMON_OPENING 0x08000000 + #define ZFCP_STATUS_COMMON_OPEN 0x04000000 +-#define ZFCP_STATUS_COMMON_CLOSING 0x02000000 + #define ZFCP_STATUS_COMMON_ERP_INUSE 0x01000000 + #define ZFCP_STATUS_COMMON_ACCESS_DENIED 0x00800000 + #define ZFCP_STATUS_COMMON_ACCESS_BOXED 0x00400000 +@@ -291,16 +240,15 @@ struct zfcp_rc_entry { + + /* adapter status */ + #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 +-#define ZFCP_STATUS_ADAPTER_REGISTERED 0x00000004 + #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 + #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 + #define ZFCP_STATUS_ADAPTER_ERP_THREAD_UP 0x00000020 + #define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080 + #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 + #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 +-#define ZFCP_STATUS_ADAPTER_XPORT_OK 0x00000800 + + /* FC-PH/FC-GS well-known address identifiers for generic services */ ++#define ZFCP_DID_WKA 0xFFFFF0 + #define ZFCP_DID_MANAGEMENT_SERVICE 0xFFFFFA + #define ZFCP_DID_TIME_SERVICE 0xFFFFFB + #define ZFCP_DID_DIRECTORY_SERVICE 0xFFFFFC +@@ -312,29 +260,27 @@ struct zfcp_rc_entry { + #define ZFCP_STATUS_PORT_DID_DID 0x00000002 + #define ZFCP_STATUS_PORT_PHYS_CLOSING 0x00000004 + #define ZFCP_STATUS_PORT_NO_WWPN 0x00000008 +-#define ZFCP_STATUS_PORT_NO_SCSI_ID 0x00000010 + #define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020 + +-/* for ports with well known addresses */ +-#define ZFCP_STATUS_PORT_WKA \ +- (ZFCP_STATUS_PORT_NO_WWPN | \ +- ZFCP_STATUS_PORT_NO_SCSI_ID) ++/* well known address (WKA) port status*/ ++enum zfcp_wka_status { ++ ZFCP_WKA_PORT_OFFLINE, ++ ZFCP_WKA_PORT_CLOSING, ++ ZFCP_WKA_PORT_OPENING, ++ ZFCP_WKA_PORT_ONLINE, ++}; + + /* logical unit status */ +-#define ZFCP_STATUS_UNIT_TEMPORARY 0x00000002 + #define ZFCP_STATUS_UNIT_SHARED 0x00000004 + #define ZFCP_STATUS_UNIT_READONLY 0x00000008 + #define ZFCP_STATUS_UNIT_REGISTERED 0x00000010 + #define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020 + + /* FSF request status (this does not have a common part) */ +-#define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000 +-#define ZFCP_STATUS_FSFREQ_POOL 0x00000001 + #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 + #define ZFCP_STATUS_FSFREQ_COMPLETED 0x00000004 + #define ZFCP_STATUS_FSFREQ_ERROR 0x00000008 + #define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010 +-#define ZFCP_STATUS_FSFREQ_ABORTING 0x00000020 + #define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040 + #define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080 + #define ZFCP_STATUS_FSFREQ_ABORTED 0x00000100 +@@ -379,7 +325,7 @@ struct ct_hdr { + * a port name is required */ + struct ct_iu_gid_pn_req { + struct ct_hdr header; +- wwn_t wwpn; ++ u64 wwpn; + } __attribute__ ((packed)); + + /* FS_ACC IU and data unit for GID_PN nameserver request */ +@@ -388,11 +334,9 @@ struct ct_iu_gid_pn_resp { + u32 d_id; + } __attribute__ ((packed)); + +-typedef void (*zfcp_send_ct_handler_t)(unsigned long); +- + /** + * struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct +- * @port: port where the request is sent to ++ * @wka_port: port where the request is sent to + * @req: scatter-gather list for request + * @resp: scatter-gather list for response + * @req_count: number of elements in request scatter-gather list +@@ -404,12 +348,12 @@ typedef void (*zfcp_send_ct_handler_t)(u + * @status: used to pass error status to calling function + */ + struct zfcp_send_ct { +- struct zfcp_port *port; ++ struct zfcp_wka_port *wka_port; + struct scatterlist *req; + struct scatterlist *resp; + unsigned int req_count; + unsigned int resp_count; +- zfcp_send_ct_handler_t handler; ++ void (*handler)(unsigned long); + unsigned long handler_data; + int timeout; + struct completion *completion; +@@ -426,8 +370,6 @@ struct zfcp_gid_pn_data { + struct zfcp_port *port; + }; + +-typedef void (*zfcp_send_els_handler_t)(unsigned long); +- + /** + * struct zfcp_send_els - used to pass parameters to function zfcp_fsf_send_els + * @adapter: adapter where request is sent from +@@ -451,22 +393,28 @@ struct zfcp_send_els { + struct scatterlist *resp; + unsigned int req_count; + unsigned int resp_count; +- zfcp_send_els_handler_t handler; ++ void (*handler)(unsigned long); + unsigned long handler_data; + struct completion *completion; + int ls_code; + int status; + }; + ++struct zfcp_wka_port { ++ struct zfcp_adapter *adapter; ++ wait_queue_head_t completion_wq; ++ enum zfcp_wka_status status; ++ atomic_t refcount; ++ u32 d_id; ++ u32 handle; ++ struct mutex mutex; ++ struct delayed_work work; ++}; ++ + struct zfcp_qdio_queue { +- struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ +- u8 first; /* index of next free bfr +- in queue (free_count>0) */ +- atomic_t count; /* number of free buffers +- in queue */ +- spinlock_t lock; /* lock for operations on queue */ +- int pci_batch; /* SBALs since PCI indication +- was last set */ ++ struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; ++ u8 first; /* index of next free bfr in queue */ ++ atomic_t count; /* number of free buffers in queue */ + }; + + struct zfcp_erp_action { +@@ -475,7 +423,7 @@ struct zfcp_erp_action { + struct zfcp_adapter *adapter; /* device which should be recovered */ + struct zfcp_port *port; + struct zfcp_unit *unit; +- volatile u32 status; /* recovery status */ ++ u32 status; /* recovery status */ + u32 step; /* active step of this erp action */ + struct zfcp_fsf_req *fsf_req; /* fsf request currently pending + for this action */ +@@ -506,8 +454,8 @@ struct zfcp_adapter { + atomic_t refcount; /* reference count */ + wait_queue_head_t remove_wq; /* can be used to wait for + refcount drop to zero */ +- wwn_t peer_wwnn; /* P2P peer WWNN */ +- wwn_t peer_wwpn; /* P2P peer WWPN */ ++ u64 peer_wwnn; /* P2P peer WWNN */ ++ u64 peer_wwpn; /* P2P peer WWPN */ + u32 peer_d_id; /* P2P peer D_ID */ + struct ccw_device *ccw_device; /* S/390 ccw device */ + u32 hydra_version; /* Hydra version */ +@@ -518,13 +466,13 @@ struct zfcp_adapter { + u16 timer_ticks; /* time int for a tick */ + struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ + struct list_head port_list_head; /* remote port list */ +- struct list_head port_remove_lh; /* head of ports to be +- removed */ +- u32 ports; /* number of remote ports */ + unsigned long req_no; /* unique FSF req number */ + struct list_head *req_list; /* list of pending reqs */ + spinlock_t req_list_lock; /* request list lock */ + struct zfcp_qdio_queue req_q; /* request queue */ ++ spinlock_t req_q_lock; /* for operations on queue */ ++ int req_q_pci_batch; /* SBALs since PCI indication ++ was last set */ + u32 fsf_req_seq_no; /* FSF cmnd seq number */ + wait_queue_head_t request_wq; /* can be used to wait for + more avaliable SBALs */ +@@ -548,7 +496,7 @@ struct zfcp_adapter { + actions */ + u32 erp_low_mem_count; /* nr of erp actions waiting + for memory */ +- struct zfcp_port *nameserver_port; /* adapter's nameserver */ ++ struct zfcp_wka_port nsp; /* adapter's nameserver */ + debug_info_t *rec_dbf; + debug_info_t *hba_dbf; + debug_info_t *san_dbf; /* debug feature areas */ +@@ -563,7 +511,6 @@ struct zfcp_adapter { + struct zfcp_scsi_dbf_record scsi_dbf_buf; + struct zfcp_adapter_mempool pool; /* Adapter memory pools */ + struct qdio_initialize qdio_init_data; /* for qdio_establish */ +- struct device generic_services; /* directory for WKA ports */ + struct fc_host_statistics *fc_stats; + struct fsf_qtcb_bottom_port *stats_reset_data; + unsigned long stats_reset; +@@ -580,18 +527,16 @@ struct zfcp_port { + refcount drop to zero */ + struct zfcp_adapter *adapter; /* adapter used to access port */ + struct list_head unit_list_head; /* head of logical unit list */ +- struct list_head unit_remove_lh; /* head of luns to be removed +- list */ +- u32 units; /* # of logical units in list */ + atomic_t status; /* status of this remote port */ +- wwn_t wwnn; /* WWNN if known */ +- wwn_t wwpn; /* WWPN */ ++ u64 wwnn; /* WWNN if known */ ++ u64 wwpn; /* WWPN */ + u32 d_id; /* D_ID */ + u32 handle; /* handle assigned by FSF */ + struct zfcp_erp_action erp_action; /* pending error recovery */ + atomic_t erp_counter; + u32 maxframe_size; + u32 supported_classes; ++ struct work_struct gid_pn_work; + }; + + struct zfcp_unit { +@@ -602,8 +547,7 @@ struct zfcp_unit { + refcount drop to zero */ + struct zfcp_port *port; /* remote port of unit */ + atomic_t status; /* status of this logical unit */ +- unsigned int scsi_lun; /* own SCSI LUN */ +- fcp_lun_t fcp_lun; /* own FCP_LUN */ ++ u64 fcp_lun; /* own FCP_LUN */ + u32 handle; /* handle assigned by FSF */ + struct scsi_device *device; /* scsi device struct pointer */ + struct zfcp_erp_action erp_action; /* pending error recovery */ +@@ -626,7 +570,7 @@ struct zfcp_fsf_req { + u8 sbal_response; /* SBAL used in interrupt */ + wait_queue_head_t completion_wq; /* can be used by a routine + to wait for completion */ +- volatile u32 status; /* status of this request */ ++ u32 status; /* status of this request */ + u32 fsf_command; /* FSF Command copy */ + struct fsf_qtcb *qtcb; /* address of associated QTCB */ + u32 seq_no; /* Sequence number of request */ +@@ -647,11 +591,7 @@ struct zfcp_fsf_req { + struct zfcp_data { + struct scsi_host_template scsi_host_template; + struct scsi_transport_template *scsi_transport_template; +- atomic_t status; /* Module status flags */ + struct list_head adapter_list_head; /* head of adapter list */ +- struct list_head adapter_remove_lh; /* head of adapters to be +- removed */ +- u32 adapters; /* # of adapters in list */ + rwlock_t config_lock; /* serialises changes + to adapter/port/unit + lists */ +@@ -659,11 +599,12 @@ struct zfcp_data { + changes */ + atomic_t loglevel; /* current loglevel */ + char init_busid[BUS_ID_SIZE]; +- wwn_t init_wwpn; +- fcp_lun_t init_fcp_lun; +- struct kmem_cache *fsf_req_qtcb_cache; +- struct kmem_cache *sr_buffer_cache; +- struct kmem_cache *gid_pn_cache; ++ u64 init_wwpn; ++ u64 init_fcp_lun; ++ struct kmem_cache *fsf_req_qtcb_cache; ++ struct kmem_cache *sr_buffer_cache; ++ struct kmem_cache *gid_pn_cache; ++ struct workqueue_struct *work_queue; + }; + + /* struct used by memory pools for fsf_requests */ +@@ -680,14 +621,7 @@ struct zfcp_fsf_req_qtcb { + #define ZFCP_SET 0x00000100 + #define ZFCP_CLEAR 0x00000200 + +-#ifndef atomic_test_mask +-#define atomic_test_mask(mask, target) \ +- ((atomic_read(target) & mask) == mask) +-#endif +- + #define zfcp_get_busid_by_adapter(adapter) (adapter->ccw_device->dev.bus_id) +-#define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter)) +-#define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) + + /* + * Helper functions for request ID management. +@@ -748,12 +682,6 @@ zfcp_unit_put(struct zfcp_unit *unit) + } + + static inline void +-zfcp_unit_wait(struct zfcp_unit *unit) +-{ +- wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); +-} +- +-static inline void + zfcp_port_get(struct zfcp_port *port) + { + atomic_inc(&port->refcount); +@@ -767,12 +695,6 @@ zfcp_port_put(struct zfcp_port *port) + } + + static inline void +-zfcp_port_wait(struct zfcp_port *port) +-{ +- wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); +-} +- +-static inline void + zfcp_adapter_get(struct zfcp_adapter *adapter) + { + atomic_inc(&adapter->refcount); +@@ -785,10 +707,4 @@ zfcp_adapter_put(struct zfcp_adapter *ad + wake_up(&adapter->remove_wq); + } + +-static inline void +-zfcp_adapter_wait(struct zfcp_adapter *adapter) +-{ +- wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); +-} +- + #endif /* ZFCP_DEF_H */ +--- a/drivers/s390/scsi/zfcp_erp.c ++++ b/drivers/s390/scsi/zfcp_erp.c +@@ -25,7 +25,6 @@ enum zfcp_erp_steps { + ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001, + ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010, + ZFCP_ERP_STEP_PORT_CLOSING = 0x0100, +- ZFCP_ERP_STEP_NAMESERVER_OPEN = 0x0200, + ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, + ZFCP_ERP_STEP_PORT_OPENING = 0x0800, + ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, +@@ -534,8 +533,7 @@ static void _zfcp_erp_port_reopen_all(st + struct zfcp_port *port; + + list_for_each_entry(port, &adapter->port_list_head, list) +- if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_WKA)) +- _zfcp_erp_port_reopen(port, clear, id, ref); ++ _zfcp_erp_port_reopen(port, clear, id, ref); + } + + static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id, +@@ -671,8 +669,6 @@ static int zfcp_erp_adapter_strategy_ope + int ret; + struct zfcp_adapter *adapter = act->adapter; + +- atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); +- + write_lock_irq(&adapter->erp_lock); + zfcp_erp_action_to_running(act); + write_unlock_irq(&adapter->erp_lock); +@@ -743,8 +739,7 @@ static int zfcp_erp_adapter_strategy_gen + ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); + failed_qdio: + atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | +- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | +- ZFCP_STATUS_ADAPTER_XPORT_OK, ++ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &act->adapter->status); + return retval; + } +@@ -753,15 +748,11 @@ static int zfcp_erp_adapter_strategy(str + { + int retval; + +- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); + zfcp_erp_adapter_strategy_generic(act, 1); /* close */ +- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &act->adapter->status); + if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) + return ZFCP_ERP_EXIT; + +- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); + retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */ +- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &act->adapter->status); + + if (retval == ZFCP_ERP_FAILED) + ssleep(8); +@@ -785,10 +776,7 @@ static int zfcp_erp_port_forced_strategy + + static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) + { +- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | +- ZFCP_STATUS_COMMON_CLOSING | +- ZFCP_STATUS_COMMON_ACCESS_DENIED | +- ZFCP_STATUS_PORT_DID_DID | ++ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_PORT_PHYS_CLOSING | + ZFCP_STATUS_PORT_INVALID_WWPN, + &port->status); +@@ -841,62 +829,6 @@ static int zfcp_erp_port_strategy_open_p + return ZFCP_ERP_CONTINUES; + } + +-static void zfcp_erp_port_strategy_open_ns_wake(struct zfcp_erp_action *ns_act) +-{ +- unsigned long flags; +- struct zfcp_adapter *adapter = ns_act->adapter; +- struct zfcp_erp_action *act, *tmp; +- int status; +- +- read_lock_irqsave(&adapter->erp_lock, flags); +- list_for_each_entry_safe(act, tmp, &adapter->erp_running_head, list) { +- if (act->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { +- status = atomic_read(&adapter->nameserver_port->status); +- if (status & ZFCP_STATUS_COMMON_ERP_FAILED) +- zfcp_erp_port_failed(act->port, 27, NULL); +- zfcp_erp_action_ready(act); +- } +- } +- read_unlock_irqrestore(&adapter->erp_lock, flags); +-} +- +-static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *act) +-{ +- int retval; +- +- switch (act->step) { +- case ZFCP_ERP_STEP_UNINITIALIZED: +- case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: +- case ZFCP_ERP_STEP_PORT_CLOSING: +- return zfcp_erp_port_strategy_open_port(act); +- +- case ZFCP_ERP_STEP_PORT_OPENING: +- if (atomic_read(&act->port->status) & ZFCP_STATUS_COMMON_OPEN) +- retval = ZFCP_ERP_SUCCEEDED; +- else +- retval = ZFCP_ERP_FAILED; +- /* this is needed anyway */ +- zfcp_erp_port_strategy_open_ns_wake(act); +- return retval; +- +- default: +- return ZFCP_ERP_FAILED; +- } +-} +- +-static int zfcp_erp_port_strategy_open_lookup(struct zfcp_erp_action *act) +-{ +- int retval; +- +- retval = zfcp_fc_ns_gid_pn_request(act); +- if (retval == -ENOMEM) +- return ZFCP_ERP_NOMEM; +- act->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; +- if (retval) +- return ZFCP_ERP_FAILED; +- return ZFCP_ERP_CONTINUES; +-} +- + static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) + { + struct zfcp_adapter *adapter = act->adapter; +@@ -911,11 +843,25 @@ static int zfcp_erp_open_ptp_port(struct + return zfcp_erp_port_strategy_open_port(act); + } + ++void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) ++{ ++ int retval; ++ struct zfcp_port *port = container_of(work, struct zfcp_port, ++ gid_pn_work); ++ ++ retval = zfcp_fc_ns_gid_pn(&port->erp_action); ++ if (retval == -ENOMEM) ++ zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); ++ port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; ++ if (retval) ++ zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); ++ ++} ++ + static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) + { + struct zfcp_adapter *adapter = act->adapter; + struct zfcp_port *port = act->port; +- struct zfcp_port *ns_port = adapter->nameserver_port; + int p_status = atomic_read(&port->status); + + switch (act->step) { +@@ -924,28 +870,10 @@ static int zfcp_erp_port_strategy_open_c + case ZFCP_ERP_STEP_PORT_CLOSING: + if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) + return zfcp_erp_open_ptp_port(act); +- if (!ns_port) { +- dev_err(&adapter->ccw_device->dev, +- "Nameserver port unavailable.\n"); +- return ZFCP_ERP_FAILED; +- } +- if (!(atomic_read(&ns_port->status) & +- ZFCP_STATUS_COMMON_UNBLOCKED)) { +- /* nameserver port may live again */ +- atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, +- &ns_port->status); +- if (zfcp_erp_port_reopen(ns_port, 0, 77, act) >= 0) { +- act->step = ZFCP_ERP_STEP_NAMESERVER_OPEN; +- return ZFCP_ERP_CONTINUES; +- } +- return ZFCP_ERP_FAILED; ++ if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { ++ queue_work(zfcp_data.work_queue, &port->gid_pn_work); ++ return ZFCP_ERP_CONTINUES; + } +- /* else nameserver port is already open, fall through */ +- case ZFCP_ERP_STEP_NAMESERVER_OPEN: +- if (!(atomic_read(&ns_port->status) & ZFCP_STATUS_COMMON_OPEN)) +- return ZFCP_ERP_FAILED; +- return zfcp_erp_port_strategy_open_lookup(act); +- + case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: + if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { + if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { +@@ -958,25 +886,26 @@ static int zfcp_erp_port_strategy_open_c + + case ZFCP_ERP_STEP_PORT_OPENING: + /* D_ID might have changed during open */ +- if ((p_status & ZFCP_STATUS_COMMON_OPEN) && +- (p_status & ZFCP_STATUS_PORT_DID_DID)) +- return ZFCP_ERP_SUCCEEDED; ++ if (p_status & ZFCP_STATUS_COMMON_OPEN) { ++ if (p_status & ZFCP_STATUS_PORT_DID_DID) ++ return ZFCP_ERP_SUCCEEDED; ++ else { ++ act->step = ZFCP_ERP_STEP_PORT_CLOSING; ++ return ZFCP_ERP_CONTINUES; ++ } + /* fall through otherwise */ ++ } + } + return ZFCP_ERP_FAILED; + } + +-static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *act) +-{ +- if (atomic_read(&act->port->status) & (ZFCP_STATUS_PORT_WKA)) +- return zfcp_erp_port_strategy_open_nameserver(act); +- return zfcp_erp_port_strategy_open_common(act); +-} +- + static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) + { + struct zfcp_port *port = erp_action->port; + ++ if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) ++ goto close_init_done; ++ + switch (erp_action->step) { + case ZFCP_ERP_STEP_UNINITIALIZED: + zfcp_erp_port_strategy_clearstati(port); +@@ -989,19 +918,17 @@ static int zfcp_erp_port_strategy(struct + return ZFCP_ERP_FAILED; + break; + } ++ ++close_init_done: + if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) + return ZFCP_ERP_EXIT; +- else +- return zfcp_erp_port_strategy_open(erp_action); + +- return ZFCP_ERP_FAILED; ++ return zfcp_erp_port_strategy_open_common(erp_action); + } + + static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) + { +- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | +- ZFCP_STATUS_COMMON_CLOSING | +- ZFCP_STATUS_COMMON_ACCESS_DENIED | ++ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_UNIT_SHARED | + ZFCP_STATUS_UNIT_READONLY, + &unit->status); +@@ -1261,9 +1188,10 @@ static void zfcp_erp_scsi_scan(struct wo + struct zfcp_unit *unit = p->unit; + struct fc_rport *rport = unit->port->rport; + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, +- unit->scsi_lun, 0); ++ scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0); + atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + zfcp_unit_put(unit); ++ wake_up(&unit->port->adapter->erp_done_wqh); + kfree(p); + } + +@@ -1284,7 +1212,7 @@ static void zfcp_erp_schedule_work(struc + atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + INIT_WORK(&p->work, zfcp_erp_scsi_scan); + p->unit = unit; +- schedule_work(&p->work); ++ queue_work(zfcp_data.work_queue, &p->work); + } + + static void zfcp_erp_rport_register(struct zfcp_port *port) +@@ -1310,12 +1238,12 @@ static void zfcp_erp_rport_register(stru + static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) + { + struct zfcp_port *port; +- list_for_each_entry(port, &adapter->port_list_head, list) +- if (port->rport && !(atomic_read(&port->status) & +- ZFCP_STATUS_PORT_WKA)) { +- fc_remote_port_delete(port->rport); +- port->rport = NULL; +- } ++ list_for_each_entry(port, &adapter->port_list_head, list) { ++ if (!port->rport) ++ continue; ++ fc_remote_port_delete(port->rport); ++ port->rport = NULL; ++ } + } + + static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) +@@ -1470,9 +1398,9 @@ static int zfcp_erp_thread(void *data) + zfcp_erp_wakeup(adapter); + } + +- zfcp_rec_dbf_event_thread(4, adapter); ++ zfcp_rec_dbf_event_thread_lock(4, adapter); + down_interruptible(&adapter->erp_ready_sem); +- zfcp_rec_dbf_event_thread(5, adapter); ++ zfcp_rec_dbf_event_thread_lock(5, adapter); + } + + atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); +@@ -1517,7 +1445,7 @@ void zfcp_erp_thread_kill(struct zfcp_ad + { + atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); + up(&adapter->erp_ready_sem); +- zfcp_rec_dbf_event_thread_lock(2, adapter); ++ zfcp_rec_dbf_event_thread_lock(3, adapter); + + wait_event(adapter->erp_thread_wqh, + !(atomic_read(&adapter->status) & +@@ -1751,9 +1679,8 @@ static void zfcp_erp_port_access_changed + + if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_COMMON_ACCESS_BOXED))) { +- if (!(status & ZFCP_STATUS_PORT_WKA)) +- list_for_each_entry(unit, &port->unit_list_head, list) +- zfcp_erp_unit_access_changed(unit, id, ref); ++ list_for_each_entry(unit, &port->unit_list_head, list) ++ zfcp_erp_unit_access_changed(unit, id, ref); + return; + } + +@@ -1776,10 +1703,7 @@ void zfcp_erp_adapter_access_changed(str + return; + + read_lock_irqsave(&zfcp_data.config_lock, flags); +- if (adapter->nameserver_port) +- zfcp_erp_port_access_changed(adapter->nameserver_port, id, ref); + list_for_each_entry(port, &adapter->port_list_head, list) +- if (port != adapter->nameserver_port) +- zfcp_erp_port_access_changed(port, id, ref); ++ zfcp_erp_port_access_changed(port, id, ref); + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + } +--- a/drivers/s390/scsi/zfcp_ext.h ++++ b/drivers/s390/scsi/zfcp_ext.h +@@ -12,16 +12,14 @@ + #include "zfcp_def.h" + + /* zfcp_aux.c */ +-extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, +- fcp_lun_t); +-extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, +- wwn_t); ++extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); ++extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); + extern int zfcp_adapter_enqueue(struct ccw_device *); + extern void zfcp_adapter_dequeue(struct zfcp_adapter *); +-extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32, ++extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, + u32); + extern void zfcp_port_dequeue(struct zfcp_port *); +-extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t); ++extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); + extern void zfcp_unit_dequeue(struct zfcp_unit *); + extern int zfcp_reqlist_isempty(struct zfcp_adapter *); + extern void zfcp_sg_free_table(struct scatterlist *, int); +@@ -29,6 +27,7 @@ extern int zfcp_sg_setup_table(struct sc + + /* zfcp_ccw.c */ + extern int zfcp_ccw_register(void); ++extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); + + /* zfcp_cfdc.c */ + extern struct miscdevice zfcp_cfdc_misc; +@@ -50,6 +49,8 @@ extern void zfcp_hba_dbf_event_fsf_unsol + struct fsf_status_read_buffer *); + extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, unsigned int, int, + int); ++extern void zfcp_hba_dbf_event_berr(struct zfcp_adapter *, ++ struct zfcp_fsf_req *); + extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); + extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); + extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); +@@ -91,17 +92,21 @@ extern void zfcp_erp_port_access_denied( + extern void zfcp_erp_unit_access_denied(struct zfcp_unit *, u8, void *); + extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, u8, void *); + extern void zfcp_erp_timeout_handler(unsigned long); ++extern void zfcp_erp_port_strategy_open_lookup(struct work_struct *); + + /* zfcp_fc.c */ + extern int zfcp_scan_ports(struct zfcp_adapter *); + extern void _zfcp_scan_ports_later(struct work_struct *); + extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); +-extern int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *); ++extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); + extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); + extern void zfcp_test_link(struct zfcp_port *); ++extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); + + /* zfcp_fsf.c */ + extern int zfcp_fsf_open_port(struct zfcp_erp_action *); ++extern int zfcp_fsf_open_wka_port(struct zfcp_wka_port *); ++extern int zfcp_fsf_close_wka_port(struct zfcp_wka_port *); + extern int zfcp_fsf_close_port(struct zfcp_erp_action *); + extern int zfcp_fsf_close_physical_port(struct zfcp_erp_action *); + extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); +@@ -135,10 +140,8 @@ extern struct zfcp_fsf_req *zfcp_fsf_abo + extern int zfcp_qdio_allocate(struct zfcp_adapter *); + extern void zfcp_qdio_free(struct zfcp_adapter *); + extern int zfcp_qdio_send(struct zfcp_fsf_req *); +-extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req( +- struct zfcp_fsf_req *); +-extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_curr( +- struct zfcp_fsf_req *); ++extern struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *); ++extern struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *); + extern int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *, unsigned long, + struct scatterlist *, int); + extern int zfcp_qdio_open(struct zfcp_adapter *); +@@ -148,14 +151,12 @@ extern void zfcp_qdio_close(struct zfcp_ + extern struct zfcp_data zfcp_data; + extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); + extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); +-extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); + extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); + extern struct fc_function_template zfcp_transport_functions; + + /* zfcp_sysfs.c */ + extern struct attribute_group zfcp_sysfs_unit_attrs; + extern struct attribute_group zfcp_sysfs_adapter_attrs; +-extern struct attribute_group zfcp_sysfs_ns_port_attrs; + extern struct attribute_group zfcp_sysfs_port_attrs; + extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; + extern struct device_attribute *zfcp_sysfs_shost_attrs[]; +--- a/drivers/s390/scsi/zfcp_fc.c ++++ b/drivers/s390/scsi/zfcp_fc.c +@@ -41,6 +41,84 @@ struct zfcp_gpn_ft { + struct scatterlist sg_resp[ZFCP_GPN_FT_BUFFERS]; + }; + ++struct zfcp_fc_ns_handler_data { ++ struct completion done; ++ void (*handler)(unsigned long); ++ unsigned long handler_data; ++}; ++ ++static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) ++{ ++ if (mutex_lock_interruptible(&wka_port->mutex)) ++ return -ERESTARTSYS; ++ ++ if (wka_port->status != ZFCP_WKA_PORT_ONLINE) { ++ wka_port->status = ZFCP_WKA_PORT_OPENING; ++ if (zfcp_fsf_open_wka_port(wka_port)) ++ wka_port->status = ZFCP_WKA_PORT_OFFLINE; ++ } ++ ++ mutex_unlock(&wka_port->mutex); ++ ++ wait_event_timeout( ++ wka_port->completion_wq, ++ wka_port->status == ZFCP_WKA_PORT_ONLINE || ++ wka_port->status == ZFCP_WKA_PORT_OFFLINE, ++ HZ >> 1); ++ ++ if (wka_port->status == ZFCP_WKA_PORT_ONLINE) { ++ atomic_inc(&wka_port->refcount); ++ return 0; ++ } ++ return -EIO; ++} ++ ++static void zfcp_wka_port_offline(struct work_struct *work) ++{ ++ struct delayed_work *dw = container_of(work, struct delayed_work, work); ++ struct zfcp_wka_port *wka_port = ++ container_of(dw, struct zfcp_wka_port, work); ++ ++ wait_event(wka_port->completion_wq, ++ atomic_read(&wka_port->refcount) == 0); ++ ++ mutex_lock(&wka_port->mutex); ++ if ((atomic_read(&wka_port->refcount) != 0) || ++ (wka_port->status != ZFCP_WKA_PORT_ONLINE)) ++ goto out; ++ ++ wka_port->status = ZFCP_WKA_PORT_CLOSING; ++ if (zfcp_fsf_close_wka_port(wka_port)) { ++ wka_port->status = ZFCP_WKA_PORT_OFFLINE; ++ wake_up(&wka_port->completion_wq); ++ } ++out: ++ mutex_unlock(&wka_port->mutex); ++} ++ ++static void zfcp_wka_port_put(struct zfcp_wka_port *wka_port) ++{ ++ if (atomic_dec_return(&wka_port->refcount) != 0) ++ return; ++ /* wait 10 miliseconds, other reqs might pop in */ ++ schedule_delayed_work(&wka_port->work, HZ / 100); ++} ++ ++void zfcp_fc_nameserver_init(struct zfcp_adapter *adapter) ++{ ++ struct zfcp_wka_port *wka_port = &adapter->nsp; ++ ++ init_waitqueue_head(&wka_port->completion_wq); ++ ++ wka_port->adapter = adapter; ++ wka_port->d_id = ZFCP_DID_DIRECTORY_SERVICE; ++ ++ wka_port->status = ZFCP_WKA_PORT_OFFLINE; ++ atomic_set(&wka_port->refcount, 0); ++ mutex_init(&wka_port->mutex); ++ INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline); ++} ++ + static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, + struct fcp_rscn_element *elem) + { +@@ -49,10 +127,8 @@ static void _zfcp_fc_incoming_rscn(struc + + read_lock_irqsave(&zfcp_data.config_lock, flags); + list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { +- if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) +- continue; + /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ +- if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) ++ if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID)) + /* Try to connect to unused ports anyway. */ + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, +@@ -104,7 +180,7 @@ static void zfcp_fc_incoming_rscn(struct + schedule_work(&fsf_req->adapter->scan_work); + } + +-static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, wwn_t wwpn) ++static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn) + { + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_port *port; +@@ -159,7 +235,18 @@ void zfcp_fc_incoming_els(struct zfcp_fs + zfcp_fc_incoming_rscn(fsf_req); + } + +-static void zfcp_ns_gid_pn_handler(unsigned long data) ++static void zfcp_fc_ns_handler(unsigned long data) ++{ ++ struct zfcp_fc_ns_handler_data *compl_rec = ++ (struct zfcp_fc_ns_handler_data *) data; ++ ++ if (compl_rec->handler) ++ compl_rec->handler(compl_rec->handler_data); ++ ++ complete(&compl_rec->done); ++} ++ ++static void zfcp_fc_ns_gid_pn_eval(unsigned long data) + { + struct zfcp_gid_pn_data *gid_pn = (struct zfcp_gid_pn_data *) data; + struct zfcp_send_ct *ct = &gid_pn->ct; +@@ -168,43 +255,31 @@ static void zfcp_ns_gid_pn_handler(unsig + struct zfcp_port *port = gid_pn->port; + + if (ct->status) +- goto out; ++ return; + if (ct_iu_resp->header.cmd_rsp_code != ZFCP_CT_ACCEPT) { + atomic_set_mask(ZFCP_STATUS_PORT_INVALID_WWPN, &port->status); +- goto out; ++ return; + } + /* paranoia */ + if (ct_iu_req->wwpn != port->wwpn) +- goto out; ++ return; + /* looks like a valid d_id */ + port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; + atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); +-out: +- mempool_free(gid_pn, port->adapter->pool.data_gid_pn); + } + +-/** +- * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request +- * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed +- * return: -ENOMEM on error, 0 otherwise +- */ +-int zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action) ++int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, ++ struct zfcp_gid_pn_data *gid_pn) + { +- int ret; +- struct zfcp_gid_pn_data *gid_pn; + struct zfcp_adapter *adapter = erp_action->adapter; +- +- gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); +- if (!gid_pn) +- return -ENOMEM; +- +- memset(gid_pn, 0, sizeof(*gid_pn)); ++ struct zfcp_fc_ns_handler_data compl_rec; ++ int ret; + + /* setup parameters for send generic command */ + gid_pn->port = erp_action->port; +- gid_pn->ct.port = adapter->nameserver_port; +- gid_pn->ct.handler = zfcp_ns_gid_pn_handler; +- gid_pn->ct.handler_data = (unsigned long) gid_pn; ++ gid_pn->ct.wka_port = &adapter->nsp; ++ gid_pn->ct.handler = zfcp_fc_ns_handler; ++ gid_pn->ct.handler_data = (unsigned long) &compl_rec; + gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; + gid_pn->ct.req = &gid_pn->req; + gid_pn->ct.resp = &gid_pn->resp; +@@ -224,10 +299,42 @@ int zfcp_fc_ns_gid_pn_request(struct zfc + gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; + gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; + ++ init_completion(&compl_rec.done); ++ compl_rec.handler = zfcp_fc_ns_gid_pn_eval; ++ compl_rec.handler_data = (unsigned long) gid_pn; + ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp, + erp_action); ++ if (!ret) ++ wait_for_completion(&compl_rec.done); ++ return ret; ++} ++ ++/** ++ * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request ++ * @erp_action: pointer to zfcp_erp_action where GID_PN request is needed ++ * return: -ENOMEM on error, 0 otherwise ++ */ ++int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *erp_action) ++{ ++ int ret; ++ struct zfcp_gid_pn_data *gid_pn; ++ struct zfcp_adapter *adapter = erp_action->adapter; ++ ++ gid_pn = mempool_alloc(adapter->pool.data_gid_pn, GFP_ATOMIC); ++ if (!gid_pn) ++ return -ENOMEM; ++ ++ memset(gid_pn, 0, sizeof(*gid_pn)); ++ ++ ret = zfcp_wka_port_get(&adapter->nsp); + if (ret) +- mempool_free(gid_pn, adapter->pool.data_gid_pn); ++ goto out; ++ ++ ret = zfcp_fc_ns_gid_pn_request(erp_action, gid_pn); ++ ++ zfcp_wka_port_put(&adapter->nsp); ++out: ++ mempool_free(gid_pn, adapter->pool.data_gid_pn); + return ret; + } + +@@ -257,14 +364,14 @@ struct zfcp_els_adisc { + struct scatterlist req; + struct scatterlist resp; + struct zfcp_ls_adisc ls_adisc; +- struct zfcp_ls_adisc_acc ls_adisc_acc; ++ struct zfcp_ls_adisc ls_adisc_acc; + }; + + static void zfcp_fc_adisc_handler(unsigned long data) + { + struct zfcp_els_adisc *adisc = (struct zfcp_els_adisc *) data; + struct zfcp_port *port = adisc->els.port; +- struct zfcp_ls_adisc_acc *ls_adisc = &adisc->ls_adisc_acc; ++ struct zfcp_ls_adisc *ls_adisc = &adisc->ls_adisc_acc; + + if (adisc->els.status) { + /* request rejected or timed out */ +@@ -297,7 +404,7 @@ static int zfcp_fc_adisc(struct zfcp_por + sg_init_one(adisc->els.req, &adisc->ls_adisc, + sizeof(struct zfcp_ls_adisc)); + sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, +- sizeof(struct zfcp_ls_adisc_acc)); ++ sizeof(struct zfcp_ls_adisc)); + + adisc->els.req_count = 1; + adisc->els.resp_count = 1; +@@ -340,30 +447,6 @@ void zfcp_test_link(struct zfcp_port *po + zfcp_erp_port_forced_reopen(port, 0, 65, NULL); + } + +-static int zfcp_scan_get_nameserver(struct zfcp_adapter *adapter) +-{ +- int ret; +- +- if (!adapter->nameserver_port) +- return -EINTR; +- +- if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, +- &adapter->nameserver_port->status)) { +- ret = zfcp_erp_port_reopen(adapter->nameserver_port, 0, 148, +- NULL); +- if (ret) +- return ret; +- zfcp_erp_wait(adapter); +- } +- return !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, +- &adapter->nameserver_port->status); +-} +- +-static void zfcp_gpn_ft_handler(unsigned long _done) +-{ +- complete((struct completion *)_done); +-} +- + static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) + { + struct scatterlist *sg = &gpn_ft->sg_req; +@@ -405,7 +488,7 @@ static int zfcp_scan_issue_gpn_ft(struct + { + struct zfcp_send_ct *ct = &gpn_ft->ct; + struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); +- struct completion done; ++ struct zfcp_fc_ns_handler_data compl_rec; + int ret; + + /* prepare CT IU for GPN_FT */ +@@ -422,19 +505,20 @@ static int zfcp_scan_issue_gpn_ft(struct + req->fc4_type = ZFCP_CT_SCSI_FCP; + + /* prepare zfcp_send_ct */ +- ct->port = adapter->nameserver_port; +- ct->handler = zfcp_gpn_ft_handler; +- ct->handler_data = (unsigned long)&done; ++ ct->wka_port = &adapter->nsp; ++ ct->handler = zfcp_fc_ns_handler; ++ ct->handler_data = (unsigned long)&compl_rec; + ct->timeout = 10; + ct->req = &gpn_ft->sg_req; + ct->resp = gpn_ft->sg_resp; + ct->req_count = 1; + ct->resp_count = ZFCP_GPN_FT_BUFFERS; + +- init_completion(&done); ++ init_completion(&compl_rec.done); ++ compl_rec.handler = NULL; + ret = zfcp_fsf_send_ct(ct, NULL, NULL); + if (!ret) +- wait_for_completion(&done); ++ wait_for_completion(&compl_rec.done); + return ret; + } + +@@ -444,9 +528,8 @@ static void zfcp_validate_port(struct zf + + atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); + +- if (port == adapter->nameserver_port) +- return; +- if ((port->supported_classes != 0) || (port->units != 0)) { ++ if ((port->supported_classes != 0) || ++ !list_empty(&port->unit_list_head)) { + zfcp_port_put(port); + return; + } +@@ -462,7 +545,7 @@ static int zfcp_scan_eval_gpn_ft(struct + struct scatterlist *sg = gpn_ft->sg_resp; + struct ct_hdr *hdr = sg_virt(sg); + struct gpn_ft_resp_acc *acc = sg_virt(sg); +- struct zfcp_adapter *adapter = ct->port->adapter; ++ struct zfcp_adapter *adapter = ct->wka_port->adapter; + struct zfcp_port *port, *tmp; + u32 d_id; + int ret = 0, x, last = 0; +@@ -492,6 +575,9 @@ static int zfcp_scan_eval_gpn_ft(struct + d_id = acc->port_id[0] << 16 | acc->port_id[1] << 8 | + acc->port_id[2]; + ++ /* don't attach ports with a well known address */ ++ if ((d_id & ZFCP_DID_WKA) == ZFCP_DID_WKA) ++ continue; + /* skip the adapter's port and known remote ports */ + if (acc->wwpn == fc_host_port_name(adapter->scsi_host)) + continue; +@@ -530,13 +616,15 @@ int zfcp_scan_ports(struct zfcp_adapter + if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) + return 0; + +- ret = zfcp_scan_get_nameserver(adapter); ++ ret = zfcp_wka_port_get(&adapter->nsp); + if (ret) + return ret; + + gpn_ft = zfcp_alloc_sg_env(); +- if (!gpn_ft) +- return -ENOMEM; ++ if (!gpn_ft) { ++ ret = -ENOMEM; ++ goto out; ++ } + + for (i = 0; i < 3; i++) { + ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); +@@ -549,7 +637,8 @@ int zfcp_scan_ports(struct zfcp_adapter + } + } + zfcp_free_sg_env(gpn_ft); +- ++out: ++ zfcp_wka_port_put(&adapter->nsp); + return ret; + } + +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -71,7 +71,7 @@ static void zfcp_fsf_access_denied_port( + struct fsf_qtcb_header *header = &req->qtcb->header; + dev_warn(&req->adapter->ccw_device->dev, + "Access denied to port 0x%016Lx\n", +- port->wwpn); ++ (unsigned long long)port->wwpn); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); + zfcp_erp_port_access_denied(port, 55, req); +@@ -84,7 +84,8 @@ static void zfcp_fsf_access_denied_unit( + struct fsf_qtcb_header *header = &req->qtcb->header; + dev_warn(&req->adapter->ccw_device->dev, + "Access denied to unit 0x%016Lx on port 0x%016Lx\n", +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[0]); + zfcp_act_eval_err(req->adapter, header->fsf_status_qual.halfword[1]); + zfcp_erp_unit_access_denied(unit, 59, req); +@@ -296,6 +297,7 @@ static void zfcp_fsf_status_read_handler + dev_warn(&adapter->ccw_device->dev, + "The error threshold for checksum statistics " + "has been exceeded\n"); ++ zfcp_hba_dbf_event_berr(adapter, req); + break; + case FSF_STATUS_READ_LINK_DOWN: + zfcp_fsf_status_read_link_down(req); +@@ -330,7 +332,7 @@ static void zfcp_fsf_status_read_handler + zfcp_fsf_req_free(req); + + atomic_inc(&adapter->stat_miss); +- schedule_work(&adapter->stat_work); ++ queue_work(zfcp_data.work_queue, &adapter->stat_work); + } + + static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) +@@ -624,7 +626,6 @@ static void zfcp_fsf_exchange_port_evalu + + static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) + { +- struct zfcp_adapter *adapter = req->adapter; + struct fsf_qtcb *qtcb = req->qtcb; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) +@@ -633,23 +634,23 @@ static void zfcp_fsf_exchange_port_data_ + switch (qtcb->header.fsf_status) { + case FSF_GOOD: + zfcp_fsf_exchange_port_evaluate(req); +- atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + break; + case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + zfcp_fsf_exchange_port_evaluate(req); +- atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + zfcp_fsf_link_down_info_eval(req, 43, + &qtcb->header.fsf_status_qual.link_down_info); + break; + } + } + +-static int zfcp_fsf_sbal_check(struct zfcp_qdio_queue *queue) ++static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter) + { +- spin_lock_bh(&queue->lock); +- if (atomic_read(&queue->count)) ++ struct zfcp_qdio_queue *req_q = &adapter->req_q; ++ ++ spin_lock_bh(&adapter->req_q_lock); ++ if (atomic_read(&req_q->count)) + return 1; +- spin_unlock_bh(&queue->lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return 0; + } + +@@ -664,17 +665,16 @@ static int zfcp_fsf_sbal_available(struc + static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) + { + long ret; +- struct zfcp_qdio_queue *req_q = &adapter->req_q; + +- spin_unlock_bh(&req_q->lock); ++ spin_unlock_bh(&adapter->req_q_lock); + ret = wait_event_interruptible_timeout(adapter->request_wq, +- zfcp_fsf_sbal_check(req_q), 5 * HZ); ++ zfcp_fsf_sbal_check(adapter), 5 * HZ); + if (ret > 0) + return 0; + if (!ret) + atomic_inc(&adapter->qdio_outb_full); + +- spin_lock_bh(&req_q->lock); ++ spin_lock_bh(&adapter->req_q_lock); + return -EIO; + } + +@@ -711,7 +711,7 @@ static struct zfcp_fsf_req *zfcp_fsf_req + u32 fsf_cmd, int req_flags, + mempool_t *pool) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + + struct zfcp_fsf_req *req; + struct zfcp_qdio_queue *req_q = &adapter->req_q; +@@ -814,10 +814,10 @@ int zfcp_fsf_status_read(struct zfcp_ada + { + struct zfcp_fsf_req *req; + struct fsf_status_read_buffer *sr_buf; +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -857,7 +857,7 @@ failed_buf: + zfcp_fsf_req_free(req); + zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -927,10 +927,10 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_ + struct zfcp_unit *unit, + int req_flags) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + +- spin_lock(&adapter->req_q.lock); ++ spin_lock(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, +@@ -960,7 +960,7 @@ out_error_free: + zfcp_fsf_req_free(req); + req = NULL; + out: +- spin_unlock(&adapter->req_q.lock); ++ spin_unlock(&adapter->req_q_lock); + return req; + } + +@@ -968,7 +968,6 @@ static void zfcp_fsf_send_ct_handler(str + { + struct zfcp_adapter *adapter = req->adapter; + struct zfcp_send_ct *send_ct = req->data; +- struct zfcp_port *port = send_ct->port; + struct fsf_qtcb_header *header = &req->qtcb->header; + + send_ct->status = -EINVAL; +@@ -987,17 +986,14 @@ static void zfcp_fsf_send_ct_handler(str + case FSF_ADAPTER_STATUS_AVAILABLE: + switch (header->fsf_status_qual.word[0]){ + case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: +- zfcp_test_link(port); + case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + } + break; + case FSF_ACCESS_DENIED: +- zfcp_fsf_access_denied_port(req, port); + break; + case FSF_PORT_BOXED: +- zfcp_erp_port_boxed(port, 49, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR | + ZFCP_STATUS_FSFREQ_RETRY; + break; +@@ -1048,12 +1044,12 @@ static int zfcp_fsf_setup_sbals(struct z + int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, + struct zfcp_erp_action *erp_action) + { +- struct zfcp_port *port = ct->port; +- struct zfcp_adapter *adapter = port->adapter; ++ struct zfcp_wka_port *wka_port = ct->wka_port; ++ struct zfcp_adapter *adapter = wka_port->adapter; + struct zfcp_fsf_req *req; + int ret = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -1070,7 +1066,7 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct + goto failed_send; + + req->handler = zfcp_fsf_send_ct_handler; +- req->qtcb->header.port_handle = port->handle; ++ req->qtcb->header.port_handle = wka_port->handle; + req->qtcb->bottom.support.service_class = FSF_CLASS_3; + req->qtcb->bottom.support.timeout = ct->timeout; + req->data = ct; +@@ -1095,7 +1091,7 @@ failed_send: + if (erp_action) + erp_action->fsf_req = NULL; + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return ret; + } + +@@ -1165,7 +1161,7 @@ int zfcp_fsf_send_els(struct zfcp_send_e + ZFCP_STATUS_COMMON_UNBLOCKED))) + return -EBUSY; + +- spin_lock(&adapter->req_q.lock); ++ spin_lock(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, +@@ -1175,8 +1171,8 @@ int zfcp_fsf_send_els(struct zfcp_send_e + goto out; + } + +- ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, +- FSF_MAX_SBALS_PER_ELS_REQ); ++ ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2); ++ + if (ret) + goto failed_send; + +@@ -1199,18 +1195,18 @@ int zfcp_fsf_send_els(struct zfcp_send_e + failed_send: + zfcp_fsf_req_free(req); + out: +- spin_unlock(&adapter->req_q.lock); ++ spin_unlock(&adapter->req_q_lock); + return ret; + } + + int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req; + struct zfcp_adapter *adapter = erp_action->adapter; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, +@@ -1242,18 +1238,18 @@ int zfcp_fsf_exchange_config_data(struct + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + + int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_config *data) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -1281,7 +1277,7 @@ int zfcp_fsf_exchange_config_data_sync(s + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + if (!retval) + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); +@@ -1298,7 +1294,7 @@ out: + */ + int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req; + struct zfcp_adapter *adapter = erp_action->adapter; + int retval = -EIO; +@@ -1306,7 +1302,7 @@ int zfcp_fsf_exchange_port_data(struct z + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) + return -EOPNOTSUPP; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, +@@ -1332,7 +1328,7 @@ int zfcp_fsf_exchange_port_data(struct z + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -1345,14 +1341,14 @@ out: + int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, + struct fsf_qtcb_bottom_port *data) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + int retval = -EIO; + + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) + return -EOPNOTSUPP; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + +@@ -1374,7 +1370,7 @@ int zfcp_fsf_exchange_port_data_sync(str + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + if (!retval) + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); +@@ -1390,7 +1386,7 @@ static void zfcp_fsf_open_port_handler(s + struct fsf_plogi *plogi; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) +- goto skip_fsfstatus; ++ return; + + switch (header->fsf_status) { + case FSF_PORT_ALREADY_OPEN: +@@ -1402,7 +1398,7 @@ static void zfcp_fsf_open_port_handler(s + dev_warn(&req->adapter->ccw_device->dev, + "Not enough FCP adapter resources to open " + "remote port 0x%016Lx\n", +- port->wwpn); ++ (unsigned long long)port->wwpn); + zfcp_erp_port_failed(port, 31, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; +@@ -1415,7 +1411,7 @@ static void zfcp_fsf_open_port_handler(s + case FSF_SQ_NO_RETRY_POSSIBLE: + dev_warn(&req->adapter->ccw_device->dev, + "Remote port 0x%016Lx could not be opened\n", +- port->wwpn); ++ (unsigned long long)port->wwpn); + zfcp_erp_port_failed(port, 32, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; +@@ -1443,9 +1439,6 @@ static void zfcp_fsf_open_port_handler(s + * another GID_PN straight after a port has been opened. + * Alternately, an ADISC/PDISC ELS should suffice, as well. + */ +- if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) +- break; +- + plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; + if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { + if (plogi->serv_param.wwpn != port->wwpn) +@@ -1461,9 +1454,6 @@ static void zfcp_fsf_open_port_handler(s + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; + } +- +-skip_fsfstatus: +- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &port->status); + } + + /** +@@ -1473,12 +1463,12 @@ skip_fsfstatus: + */ + int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -1500,7 +1490,6 @@ int zfcp_fsf_open_port(struct zfcp_erp_a + req->data = erp_action->port; + req->erp_action = erp_action; + erp_action->fsf_req = req; +- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); + + zfcp_fsf_start_erp_timer(req); + retval = zfcp_fsf_req_send(req); +@@ -1509,7 +1498,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_a + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -1518,7 +1507,7 @@ static void zfcp_fsf_close_port_handler( + struct zfcp_port *port = req->data; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) +- goto skip_fsfstatus; ++ return; + + switch (req->qtcb->header.fsf_status) { + case FSF_PORT_HANDLE_NOT_VALID: +@@ -1533,9 +1522,6 @@ static void zfcp_fsf_close_port_handler( + ZFCP_CLEAR); + break; + } +- +-skip_fsfstatus: +- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &port->status); + } + + /** +@@ -1545,12 +1531,12 @@ skip_fsfstatus: + */ + int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -1571,7 +1557,6 @@ int zfcp_fsf_close_port(struct zfcp_erp_ + req->erp_action = erp_action; + req->qtcb->header.port_handle = erp_action->port->handle; + erp_action->fsf_req = req; +- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); + + zfcp_fsf_start_erp_timer(req); + retval = zfcp_fsf_req_send(req); +@@ -1580,7 +1565,131 @@ int zfcp_fsf_close_port(struct zfcp_erp_ + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); ++ return retval; ++} ++ ++static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) ++{ ++ struct zfcp_wka_port *wka_port = req->data; ++ struct fsf_qtcb_header *header = &req->qtcb->header; ++ ++ if (req->status & ZFCP_STATUS_FSFREQ_ERROR) { ++ wka_port->status = ZFCP_WKA_PORT_OFFLINE; ++ goto out; ++ } ++ ++ switch (header->fsf_status) { ++ case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: ++ dev_warn(&req->adapter->ccw_device->dev, ++ "Opening WKA port 0x%x failed\n", wka_port->d_id); ++ case FSF_ADAPTER_STATUS_AVAILABLE: ++ req->status |= ZFCP_STATUS_FSFREQ_ERROR; ++ case FSF_ACCESS_DENIED: ++ wka_port->status = ZFCP_WKA_PORT_OFFLINE; ++ break; ++ case FSF_PORT_ALREADY_OPEN: ++ case FSF_GOOD: ++ wka_port->handle = header->port_handle; ++ wka_port->status = ZFCP_WKA_PORT_ONLINE; ++ } ++out: ++ wake_up(&wka_port->completion_wq); ++} ++ ++/** ++ * zfcp_fsf_open_wka_port - create and send open wka-port request ++ * @wka_port: pointer to struct zfcp_wka_port ++ * Returns: 0 on success, error otherwise ++ */ ++int zfcp_fsf_open_wka_port(struct zfcp_wka_port *wka_port) ++{ ++ struct qdio_buffer_element *sbale; ++ struct zfcp_adapter *adapter = wka_port->adapter; ++ struct zfcp_fsf_req *req; ++ int retval = -EIO; ++ ++ spin_lock_bh(&adapter->req_q_lock); ++ if (zfcp_fsf_req_sbal_get(adapter)) ++ goto out; ++ ++ req = zfcp_fsf_req_create(adapter, ++ FSF_QTCB_OPEN_PORT_WITH_DID, ++ ZFCP_REQ_AUTO_CLEANUP, ++ adapter->pool.fsf_req_erp); ++ if (unlikely(IS_ERR(req))) { ++ retval = PTR_ERR(req); ++ goto out; ++ } ++ ++ sbale = zfcp_qdio_sbale_req(req); ++ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; ++ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; ++ ++ req->handler = zfcp_fsf_open_wka_port_handler; ++ req->qtcb->bottom.support.d_id = wka_port->d_id; ++ req->data = wka_port; ++ ++ zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ++ retval = zfcp_fsf_req_send(req); ++ if (retval) ++ zfcp_fsf_req_free(req); ++out: ++ spin_unlock_bh(&adapter->req_q_lock); ++ return retval; ++} ++ ++static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) ++{ ++ struct zfcp_wka_port *wka_port = req->data; ++ ++ if (req->qtcb->header.fsf_status == FSF_PORT_HANDLE_NOT_VALID) { ++ req->status |= ZFCP_STATUS_FSFREQ_ERROR; ++ zfcp_erp_adapter_reopen(wka_port->adapter, 0, 84, req); ++ } ++ ++ wka_port->status = ZFCP_WKA_PORT_OFFLINE; ++ wake_up(&wka_port->completion_wq); ++} ++ ++/** ++ * zfcp_fsf_close_wka_port - create and send close wka port request ++ * @erp_action: pointer to struct zfcp_erp_action ++ * Returns: 0 on success, error otherwise ++ */ ++int zfcp_fsf_close_wka_port(struct zfcp_wka_port *wka_port) ++{ ++ struct qdio_buffer_element *sbale; ++ struct zfcp_adapter *adapter = wka_port->adapter; ++ struct zfcp_fsf_req *req; ++ int retval = -EIO; ++ ++ spin_lock_bh(&adapter->req_q_lock); ++ if (zfcp_fsf_req_sbal_get(adapter)) ++ goto out; ++ ++ req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_PORT, ++ ZFCP_REQ_AUTO_CLEANUP, ++ adapter->pool.fsf_req_erp); ++ if (unlikely(IS_ERR(req))) { ++ retval = PTR_ERR(req); ++ goto out; ++ } ++ ++ sbale = zfcp_qdio_sbale_req(req); ++ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; ++ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; ++ ++ req->handler = zfcp_fsf_close_wka_port_handler; ++ req->data = wka_port; ++ req->qtcb->header.port_handle = wka_port->handle; ++ ++ zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); ++ retval = zfcp_fsf_req_send(req); ++ if (retval) ++ zfcp_fsf_req_free(req); ++out: ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -1642,12 +1751,12 @@ skip_fsfstatus: + */ + int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -1678,7 +1787,7 @@ int zfcp_fsf_close_physical_port(struct + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -1693,7 +1802,7 @@ static void zfcp_fsf_open_unit_handler(s + int exclusive, readwrite; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) +- goto skip_fsfstatus; ++ return; + + atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_COMMON_ACCESS_BOXED | +@@ -1723,8 +1832,8 @@ static void zfcp_fsf_open_unit_handler(s + dev_warn(&adapter->ccw_device->dev, + "LUN 0x%Lx on port 0x%Lx is already in " + "use by CSS%d, MIF Image ID %x\n", +- unit->fcp_lun, +- unit->port->wwpn, ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn, + queue_designator->cssid, + queue_designator->hla); + else +@@ -1739,7 +1848,8 @@ static void zfcp_fsf_open_unit_handler(s + dev_warn(&adapter->ccw_device->dev, + "No handle is available for LUN " + "0x%016Lx on port 0x%016Lx\n", +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_unit_failed(unit, 34, req); + /* fall through */ + case FSF_INVALID_COMMAND_OPTION: +@@ -1778,7 +1888,8 @@ static void zfcp_fsf_open_unit_handler(s + dev_info(&adapter->ccw_device->dev, + "SCSI device at LUN 0x%016Lx on port " + "0x%016Lx opened read-only\n", +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + } + + if (exclusive && !readwrite) { +@@ -1786,7 +1897,8 @@ static void zfcp_fsf_open_unit_handler(s + "Exclusive read-only access not " + "supported (unit 0x%016Lx, " + "port 0x%016Lx)\n", +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_unit_failed(unit, 35, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0, 80, req); +@@ -1795,7 +1907,8 @@ static void zfcp_fsf_open_unit_handler(s + "Shared read-write access not " + "supported (unit 0x%016Lx, port " + "0x%016Lx\n)", +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_unit_failed(unit, 36, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + zfcp_erp_unit_shutdown(unit, 0, 81, req); +@@ -1803,9 +1916,6 @@ static void zfcp_fsf_open_unit_handler(s + } + break; + } +- +-skip_fsfstatus: +- atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, &unit->status); + } + + /** +@@ -1815,12 +1925,12 @@ skip_fsfstatus: + */ + int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -1846,8 +1956,6 @@ int zfcp_fsf_open_unit(struct zfcp_erp_a + if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) + req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING; + +- atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); +- + zfcp_fsf_start_erp_timer(req); + retval = zfcp_fsf_req_send(req); + if (retval) { +@@ -1855,7 +1963,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_a + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -1864,7 +1972,7 @@ static void zfcp_fsf_close_unit_handler( + struct zfcp_unit *unit = req->data; + + if (req->status & ZFCP_STATUS_FSFREQ_ERROR) +- goto skip_fsfstatus; ++ return; + + switch (req->qtcb->header.fsf_status) { + case FSF_PORT_HANDLE_NOT_VALID: +@@ -1894,8 +2002,6 @@ static void zfcp_fsf_close_unit_handler( + atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); + break; + } +-skip_fsfstatus: +- atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, &unit->status); + } + + /** +@@ -1905,12 +2011,12 @@ skip_fsfstatus: + */ + int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_adapter *adapter = erp_action->adapter; + struct zfcp_fsf_req *req; + int retval = -EIO; + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_CLOSE_LUN, +@@ -1931,7 +2037,6 @@ int zfcp_fsf_close_unit(struct zfcp_erp_ + req->data = erp_action->unit; + req->erp_action = erp_action; + erp_action->fsf_req = req; +- atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); + + zfcp_fsf_start_erp_timer(req); + retval = zfcp_fsf_req_send(req); +@@ -1940,7 +2045,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_ + erp_action->fsf_req = NULL; + } + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -2136,7 +2241,8 @@ static void zfcp_fsf_send_fcp_command_ha + "Incorrect direction %d, unit 0x%016Lx on port " + "0x%016Lx closed\n", + req->qtcb->bottom.io.data_direction, +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 133, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; +@@ -2145,7 +2251,8 @@ static void zfcp_fsf_send_fcp_command_ha + "Incorrect CDB length %d, unit 0x%016Lx on " + "port 0x%016Lx closed\n", + req->qtcb->bottom.io.fcp_cmnd_length, +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_adapter_shutdown(unit->port->adapter, 0, 134, req); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; +@@ -2176,6 +2283,20 @@ skip_fsfstatus: + } + } + ++static void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, u32 fcp_dl) ++{ ++ u32 *fcp_dl_ptr; ++ ++ /* ++ * fcp_dl_addr = start address of fcp_cmnd structure + ++ * size of fixed part + size of dynamically sized add_dcp_cdb field ++ * SEE FCP-2 documentation ++ */ ++ fcp_dl_ptr = (u32 *) ((unsigned char *) &fcp_cmd[1] + ++ (fcp_cmd->add_fcp_cdb_length << 2)); ++ *fcp_dl_ptr = fcp_dl; ++} ++ + /** + * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) + * @adapter: adapter where scsi command is issued +@@ -2198,7 +2319,7 @@ int zfcp_fsf_send_fcp_command_task(struc + ZFCP_STATUS_COMMON_UNBLOCKED))) + return -EBUSY; + +- spin_lock(&adapter->req_q.lock); ++ spin_lock(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, +@@ -2261,7 +2382,7 @@ int zfcp_fsf_send_fcp_command_task(struc + memcpy(fcp_cmnd_iu->fcp_cdb, scsi_cmnd->cmnd, scsi_cmnd->cmd_len); + + req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + +- fcp_cmnd_iu->add_fcp_cdb_length + sizeof(fcp_dl_t); ++ fcp_cmnd_iu->add_fcp_cdb_length + sizeof(u32); + + real_bytes = zfcp_qdio_sbals_from_sg(req, sbtype, + scsi_sglist(scsi_cmnd), +@@ -2273,7 +2394,8 @@ int zfcp_fsf_send_fcp_command_task(struc + dev_err(&adapter->ccw_device->dev, + "Oversize data package, unit 0x%016Lx " + "on port 0x%016Lx closed\n", +- unit->fcp_lun, unit->port->wwpn); ++ (unsigned long long)unit->fcp_lun, ++ (unsigned long long)unit->port->wwpn); + zfcp_erp_unit_shutdown(unit, 0, 131, req); + retval = -EINVAL; + } +@@ -2296,7 +2418,7 @@ failed_scsi_cmnd: + zfcp_fsf_req_free(req); + scsi_cmnd->host_scribble = NULL; + out: +- spin_unlock(&adapter->req_q.lock); ++ spin_unlock(&adapter->req_q_lock); + return retval; + } + +@@ -2312,7 +2434,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + struct zfcp_unit *unit, + u8 tm_flags, int req_flags) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + struct fcp_cmnd_iu *fcp_cmnd_iu; + +@@ -2320,7 +2442,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + ZFCP_STATUS_COMMON_UNBLOCKED))) + return NULL; + +- spin_lock(&adapter->req_q.lock); ++ spin_lock(&adapter->req_q_lock); + if (!zfcp_fsf_sbal_available(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, +@@ -2336,7 +2458,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; + req->qtcb->bottom.io.service_class = FSF_CLASS_3; + req->qtcb->bottom.io.fcp_cmnd_length = sizeof(struct fcp_cmnd_iu) + +- sizeof(fcp_dl_t); ++ sizeof(u32); + + sbale = zfcp_qdio_sbale_req(req); + sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE; +@@ -2353,7 +2475,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + zfcp_fsf_req_free(req); + req = NULL; + out: +- spin_unlock(&adapter->req_q.lock); ++ spin_unlock(&adapter->req_q_lock); + return req; + } + +@@ -2372,7 +2494,7 @@ static void zfcp_fsf_control_file_handle + struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, + struct zfcp_fsf_cfdc *fsf_cfdc) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + struct fsf_qtcb_bottom_support *bottom; + int direction, retval = -EIO, bytes; +@@ -2391,7 +2513,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_fi + return ERR_PTR(-EINVAL); + } + +- spin_lock_bh(&adapter->req_q.lock); ++ spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + +@@ -2421,7 +2543,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_fi + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); + out: +- spin_unlock_bh(&adapter->req_q.lock); ++ spin_unlock_bh(&adapter->req_q_lock); + + if (!retval) { + wait_event(req->completion_wq, +--- a/drivers/s390/scsi/zfcp_fsf.h ++++ b/drivers/s390/scsi/zfcp_fsf.h +@@ -71,13 +71,6 @@ + #define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED 0x00000041 + #define FSF_ELS_COMMAND_REJECTED 0x00000050 + #define FSF_GENERIC_COMMAND_REJECTED 0x00000051 +-#define FSF_OPERATION_PARTIALLY_SUCCESSFUL 0x00000052 +-#define FSF_AUTHORIZATION_FAILURE 0x00000053 +-#define FSF_CFDC_ERROR_DETECTED 0x00000054 +-#define FSF_CONTROL_FILE_UPDATE_ERROR 0x00000055 +-#define FSF_CONTROL_FILE_TOO_LARGE 0x00000056 +-#define FSF_ACCESS_CONFLICT_DETECTED 0x00000057 +-#define FSF_CONFLICTS_OVERRULED 0x00000058 + #define FSF_PORT_BOXED 0x00000059 + #define FSF_LUN_BOXED 0x0000005A + #define FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE 0x0000005B +@@ -85,9 +78,7 @@ + #define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061 + #define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062 + #define FSF_SBAL_MISMATCH 0x00000063 +-#define FSF_OPEN_PORT_WITHOUT_PRLI 0x00000064 + #define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD +-#define FSF_FCP_RSP_AVAILABLE 0x000000AF + #define FSF_UNKNOWN_COMMAND 0x000000E2 + #define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3 + #define FSF_INVALID_COMMAND_OPTION 0x000000E5 +@@ -102,20 +93,9 @@ + #define FSF_SQ_RETRY_IF_POSSIBLE 0x02 + #define FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED 0x03 + #define FSF_SQ_INVOKE_LINK_TEST_PROCEDURE 0x04 +-#define FSF_SQ_ULP_PROGRAMMING_ERROR 0x05 + #define FSF_SQ_COMMAND_ABORTED 0x06 + #define FSF_SQ_NO_RETRY_POSSIBLE 0x07 + +-/* FSF status qualifier for CFDC commands */ +-#define FSF_SQ_CFDC_HARDENED_ON_SE 0x00000000 +-#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE 0x00000001 +-#define FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2 0x00000002 +-/* CFDC subtable codes */ +-#define FSF_SQ_CFDC_SUBTABLE_OS 0x0001 +-#define FSF_SQ_CFDC_SUBTABLE_PORT_WWPN 0x0002 +-#define FSF_SQ_CFDC_SUBTABLE_PORT_DID 0x0003 +-#define FSF_SQ_CFDC_SUBTABLE_LUN 0x0004 +- + /* FSF status qualifier (most significant 4 bytes), local link down */ + #define FSF_PSQ_LINK_NO_LIGHT 0x00000004 + #define FSF_PSQ_LINK_WRAP_PLUG 0x00000008 +@@ -145,7 +125,6 @@ + #define FSF_STATUS_READ_LINK_UP 0x00000006 + #define FSF_STATUS_READ_NOTIFICATION_LOST 0x00000009 + #define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A +-#define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B + #define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C + + /* status subtypes in status read buffer */ +@@ -159,20 +138,9 @@ + + /* status subtypes for unsolicited status notification lost */ + #define FSF_STATUS_READ_SUB_INCOMING_ELS 0x00000001 +-#define FSF_STATUS_READ_SUB_SENSE_DATA 0x00000002 +-#define FSF_STATUS_READ_SUB_LINK_STATUS 0x00000004 +-#define FSF_STATUS_READ_SUB_PORT_CLOSED 0x00000008 +-#define FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD 0x00000010 + #define FSF_STATUS_READ_SUB_ACT_UPDATED 0x00000020 +-#define FSF_STATUS_READ_SUB_ACT_HARDENED 0x00000040 +-#define FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT 0x00000080 +- +-/* status subtypes for CFDC */ +-#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002 +-#define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F + + /* topologie that is detected by the adapter */ +-#define FSF_TOPO_ERROR 0x00000000 + #define FSF_TOPO_P2P 0x00000001 + #define FSF_TOPO_FABRIC 0x00000002 + #define FSF_TOPO_AL 0x00000003 +@@ -180,17 +148,13 @@ + /* data direction for FCP commands */ + #define FSF_DATADIR_WRITE 0x00000001 + #define FSF_DATADIR_READ 0x00000002 +-#define FSF_DATADIR_READ_WRITE 0x00000003 + #define FSF_DATADIR_CMND 0x00000004 + + /* fc service class */ +-#define FSF_CLASS_1 0x00000001 +-#define FSF_CLASS_2 0x00000002 + #define FSF_CLASS_3 0x00000003 + + /* SBAL chaining */ + #define FSF_MAX_SBALS_PER_REQ 36 +-#define FSF_MAX_SBALS_PER_ELS_REQ 2 + + /* logging space behind QTCB */ + #define FSF_QTCB_LOG_SIZE 1024 +@@ -200,50 +164,16 @@ + #define FSF_FEATURE_LUN_SHARING 0x00000004 + #define FSF_FEATURE_NOTIFICATION_LOST 0x00000008 + #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 +-#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 + #define FSF_FEATURE_UPDATE_ALERT 0x00000100 + #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 + + /* host connection features */ + #define FSF_FEATURE_NPIV_MODE 0x00000001 +-#define FSF_FEATURE_VM_ASSIGNED_WWPN 0x00000002 + + /* option */ + #define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001 +-#define FSF_OPEN_LUN_REPLICATE_SENSE 0x00000002 +- +-/* adapter types */ +-#define FSF_ADAPTER_TYPE_FICON 0x00000001 +-#define FSF_ADAPTER_TYPE_FICON_EXPRESS 0x00000002 +- +-/* port types */ +-#define FSF_HBA_PORTTYPE_UNKNOWN 0x00000001 +-#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003 +-#define FSF_HBA_PORTTYPE_NPORT 0x00000005 +-#define FSF_HBA_PORTTYPE_PTP 0x00000021 +-/* following are not defined and used by FSF Spec +- but are additionally defined by FC-HBA */ +-#define FSF_HBA_PORTTYPE_OTHER 0x00000002 +-#define FSF_HBA_PORTTYPE_NOTPRESENT 0x00000003 +-#define FSF_HBA_PORTTYPE_NLPORT 0x00000006 +-#define FSF_HBA_PORTTYPE_FLPORT 0x00000007 +-#define FSF_HBA_PORTTYPE_FPORT 0x00000008 +-#define FSF_HBA_PORTTYPE_LPORT 0x00000020 +- +-/* port states */ +-#define FSF_HBA_PORTSTATE_UNKNOWN 0x00000001 +-#define FSF_HBA_PORTSTATE_ONLINE 0x00000002 +-#define FSF_HBA_PORTSTATE_OFFLINE 0x00000003 +-#define FSF_HBA_PORTSTATE_LINKDOWN 0x00000006 +-#define FSF_HBA_PORTSTATE_ERROR 0x00000007 +- +-/* IO states of adapter */ +-#define FSF_IOSTAT_NPORT_RJT 0x00000004 +-#define FSF_IOSTAT_FABRIC_RJT 0x00000005 +-#define FSF_IOSTAT_LS_RJT 0x00000009 + + /* open LUN access flags*/ +-#define FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED 0x01000000 + #define FSF_UNIT_ACCESS_EXCLUSIVE 0x02000000 + #define FSF_UNIT_ACCESS_OUTBOUND_TRANSFER 0x10000000 + +@@ -265,11 +195,6 @@ struct fsf_queue_designator { + u32 res1; + } __attribute__ ((packed)); + +-struct fsf_port_closed_payload { +- struct fsf_queue_designator queue_designator; +- u32 port_handle; +-} __attribute__ ((packed)); +- + struct fsf_bit_error_payload { + u32 res1; + u32 link_failure_error_count; +--- a/drivers/s390/scsi/zfcp_qdio.c ++++ b/drivers/s390/scsi/zfcp_qdio.c +@@ -30,7 +30,7 @@ static int zfcp_qdio_buffers_enqueue(str + return 0; + } + +-static volatile struct qdio_buffer_element * ++static struct qdio_buffer_element * + zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) + { + return &q->sbal[sbal_idx]->element[sbale_idx]; +@@ -148,7 +148,7 @@ static void zfcp_qdio_int_resp(struct cc + { + struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm; + struct zfcp_qdio_queue *queue = &adapter->resp_q; +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + int sbal_idx, sbale_idx, sbal_no; + + if (unlikely(qdio_err)) { +@@ -193,8 +193,7 @@ static void zfcp_qdio_int_resp(struct cc + * @fsf_req: pointer to struct fsf_req + * Returns: pointer to qdio_buffer_element (SBALE) structure + */ +-volatile struct qdio_buffer_element * +-zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) ++struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req) + { + return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0); + } +@@ -204,8 +203,7 @@ zfcp_qdio_sbale_req(struct zfcp_fsf_req + * @fsf_req: pointer to struct fsf_req + * Returns: pointer to qdio_buffer_element (SBALE) structure + */ +-volatile struct qdio_buffer_element * +-zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) ++struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req) + { + return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, + req->sbale_curr); +@@ -219,10 +217,10 @@ static void zfcp_qdio_sbal_limit(struct + % QDIO_MAX_BUFFERS_PER_Q; + } + +-static volatile struct qdio_buffer_element * ++static struct qdio_buffer_element * + zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + + /* set last entry flag in current SBALE of current SBAL */ + sbale = zfcp_qdio_sbale_curr(fsf_req); +@@ -253,7 +251,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req + return sbale; + } + +-static volatile struct qdio_buffer_element * ++static struct qdio_buffer_element * + zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) + { + if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) +@@ -276,7 +274,7 @@ static int zfcp_qdio_fill_sbals(struct z + unsigned int sbtype, void *start_addr, + unsigned int total_length) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + unsigned long remaining, length; + void *addr; + +@@ -311,7 +309,7 @@ static int zfcp_qdio_fill_sbals(struct z + int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, + struct scatterlist *sg, int max_sbals) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + int retval, bytes = 0; + + /* figure out last allowed SBAL */ +@@ -348,10 +346,10 @@ int zfcp_qdio_send(struct zfcp_fsf_req * + int first = fsf_req->sbal_first; + int count = fsf_req->sbal_number; + int retval, pci, pci_batch; +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + + /* acknowledgements for transferred buffers */ +- pci_batch = req_q->pci_batch + count; ++ pci_batch = adapter->req_q_pci_batch + count; + if (unlikely(pci_batch >= ZFCP_QDIO_PCI_INTERVAL)) { + pci_batch %= ZFCP_QDIO_PCI_INTERVAL; + pci = first + count - (pci_batch + 1); +@@ -371,7 +369,7 @@ int zfcp_qdio_send(struct zfcp_fsf_req * + atomic_sub(count, &req_q->count); + req_q->first += count; + req_q->first %= QDIO_MAX_BUFFERS_PER_Q; +- req_q->pci_batch = pci_batch; ++ adapter->req_q_pci_batch = pci_batch; + return 0; + } + +@@ -422,14 +420,14 @@ void zfcp_qdio_close(struct zfcp_adapter + struct zfcp_qdio_queue *req_q; + int first, count; + +- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) ++ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) + return; + + /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ + req_q = &adapter->req_q; +- spin_lock_bh(&req_q->lock); ++ spin_lock_bh(&adapter->req_q_lock); + atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); +- spin_unlock_bh(&req_q->lock); ++ spin_unlock_bh(&adapter->req_q_lock); + + qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); + +@@ -442,7 +440,7 @@ void zfcp_qdio_close(struct zfcp_adapter + } + req_q->first = 0; + atomic_set(&req_q->count, 0); +- req_q->pci_batch = 0; ++ adapter->req_q_pci_batch = 0; + adapter->resp_q.first = 0; + atomic_set(&adapter->resp_q.count, 0); + } +@@ -454,10 +452,10 @@ void zfcp_qdio_close(struct zfcp_adapter + */ + int zfcp_qdio_open(struct zfcp_adapter *adapter) + { +- volatile struct qdio_buffer_element *sbale; ++ struct qdio_buffer_element *sbale; + int cc; + +- if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) ++ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) + return -EIO; + + if (qdio_establish(&adapter->qdio_init_data)) +@@ -480,7 +478,7 @@ int zfcp_qdio_open(struct zfcp_adapter * + /* set index of first avalable SBALS / number of available SBALS */ + adapter->req_q.first = 0; + atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q); +- adapter->req_q.pci_batch = 0; ++ adapter->req_q_pci_batch = 0; + + return 0; + +--- a/drivers/s390/scsi/zfcp_scsi.c ++++ b/drivers/s390/scsi/zfcp_scsi.c +@@ -23,20 +23,6 @@ char *zfcp_get_fcp_sns_info_ptr(struct f + return fcp_sns_info_ptr; + } + +-void zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) +-{ +- fcp_dl_t *fcp_dl_ptr; +- +- /* +- * fcp_dl_addr = start address of fcp_cmnd structure + +- * size of fixed part + size of dynamically sized add_dcp_cdb field +- * SEE FCP-2 documentation +- */ +- fcp_dl_ptr = (fcp_dl_t *) ((unsigned char *) &fcp_cmd[1] + +- (fcp_cmd->add_fcp_cdb_length << 2)); +- *fcp_dl_ptr = fcp_dl; +-} +- + static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) + { + struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; +@@ -121,13 +107,17 @@ static struct zfcp_unit *zfcp_unit_looku + { + struct zfcp_port *port; + struct zfcp_unit *unit; ++ int scsi_lun; + + list_for_each_entry(port, &adapter->port_list_head, list) { + if (!port->rport || (id != port->rport->scsi_target_id)) + continue; +- list_for_each_entry(unit, &port->unit_list_head, list) +- if (lun == unit->scsi_lun) ++ list_for_each_entry(unit, &port->unit_list_head, list) { ++ scsi_lun = scsilun_to_int( ++ (struct scsi_lun *)&unit->fcp_lun); ++ if (lun == scsi_lun) + return unit; ++ } + } + + return NULL; +@@ -185,7 +175,6 @@ static int zfcp_scsi_eh_abort_handler(st + return retval; + } + fsf_req->data = NULL; +- fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; + + /* don't access old fsf_req after releasing the abort_lock */ + write_unlock_irqrestore(&adapter->abort_lock, flags); +@@ -315,7 +304,6 @@ int zfcp_adapter_scsi_register(struct zf + scsi_host_put(adapter->scsi_host); + return -EIO; + } +- atomic_set_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); + + return 0; + } +@@ -339,7 +327,6 @@ void zfcp_adapter_scsi_unregister(struct + scsi_remove_host(shost); + scsi_host_put(shost); + adapter->scsi_host = NULL; +- atomic_clear_mask(ZFCP_STATUS_ADAPTER_REGISTERED, &adapter->status); + + return; + } +--- a/drivers/s390/scsi/zfcp_sysfs.c ++++ b/drivers/s390/scsi/zfcp_sysfs.c +@@ -28,9 +28,9 @@ static ZFCP_DEV_ATTR(_feat, _name, S_IRU + ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, status, "0x%08x\n", + atomic_read(&adapter->status)); + ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwnn, "0x%016llx\n", +- adapter->peer_wwnn); ++ (unsigned long long) adapter->peer_wwnn); + ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_wwpn, "0x%016llx\n", +- adapter->peer_wwpn); ++ (unsigned long long) adapter->peer_wwpn); + ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, peer_d_id, "0x%06x\n", + adapter->peer_d_id); + ZFCP_DEFINE_ATTR(zfcp_adapter, adapter, card_version, "0x%04x\n", +@@ -137,8 +137,9 @@ static ssize_t zfcp_sysfs_port_remove_st + { + struct zfcp_adapter *adapter = dev_get_drvdata(dev); + struct zfcp_port *port; +- wwn_t wwpn; ++ u64 wwpn; + int retval = 0; ++ LIST_HEAD(port_remove_lh); + + down(&zfcp_data.config_sema); + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { +@@ -146,7 +147,7 @@ static ssize_t zfcp_sysfs_port_remove_st + goto out; + } + +- if (strict_strtoull(buf, 0, &wwpn)) { ++ if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn)) { + retval = -EINVAL; + goto out; + } +@@ -156,7 +157,7 @@ static ssize_t zfcp_sysfs_port_remove_st + if (port && (atomic_read(&port->refcount) == 0)) { + zfcp_port_get(port); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); +- list_move(&port->list, &adapter->port_remove_lh); ++ list_move(&port->list, &port_remove_lh); + } else + port = NULL; + write_unlock_irq(&zfcp_data.config_lock); +@@ -202,7 +203,7 @@ static ssize_t zfcp_sysfs_unit_add_store + { + struct zfcp_port *port = dev_get_drvdata(dev); + struct zfcp_unit *unit; +- fcp_lun_t fcp_lun; ++ u64 fcp_lun; + int retval = -EINVAL; + + down(&zfcp_data.config_sema); +@@ -211,7 +212,7 @@ static ssize_t zfcp_sysfs_unit_add_store + goto out; + } + +- if (strict_strtoull(buf, 0, &fcp_lun)) ++ if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) + goto out; + + unit = zfcp_unit_enqueue(port, fcp_lun); +@@ -235,8 +236,9 @@ static ssize_t zfcp_sysfs_unit_remove_st + { + struct zfcp_port *port = dev_get_drvdata(dev); + struct zfcp_unit *unit; +- fcp_lun_t fcp_lun; ++ u64 fcp_lun; + int retval = 0; ++ LIST_HEAD(unit_remove_lh); + + down(&zfcp_data.config_sema); + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { +@@ -244,7 +246,7 @@ static ssize_t zfcp_sysfs_unit_remove_st + goto out; + } + +- if (strict_strtoull(buf, 0, &fcp_lun)) { ++ if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) { + retval = -EINVAL; + goto out; + } +@@ -254,7 +256,7 @@ static ssize_t zfcp_sysfs_unit_remove_st + if (unit && (atomic_read(&unit->refcount) == 0)) { + zfcp_unit_get(unit); + atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); +- list_move(&unit->list, &port->unit_remove_lh); ++ list_move(&unit->list, &unit_remove_lh); + } else + unit = NULL; + +@@ -275,22 +277,7 @@ out: + } + static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); + +-static struct attribute *zfcp_port_ns_attrs[] = { +- &dev_attr_port_failed.attr, +- &dev_attr_port_in_recovery.attr, +- &dev_attr_port_status.attr, +- &dev_attr_port_access_denied.attr, +- NULL +-}; +- +-/** +- * zfcp_sysfs_ns_port_attrs - sysfs attributes for nameserver +- */ +-struct attribute_group zfcp_sysfs_ns_port_attrs = { +- .attrs = zfcp_port_ns_attrs, +-}; +- +-static struct attribute *zfcp_port_no_ns_attrs[] = { ++static struct attribute *zfcp_port_attrs[] = { + &dev_attr_unit_add.attr, + &dev_attr_unit_remove.attr, + &dev_attr_port_failed.attr, +@@ -304,7 +291,7 @@ static struct attribute *zfcp_port_no_ns + * zfcp_sysfs_port_attrs - sysfs attributes for all other ports + */ + struct attribute_group zfcp_sysfs_port_attrs = { +- .attrs = zfcp_port_no_ns_attrs, ++ .attrs = zfcp_port_attrs, + }; + + static struct attribute *zfcp_unit_attrs[] = { +@@ -397,8 +384,10 @@ static DEVICE_ATTR(_name, S_IRUGO, zfcp_ + + ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", + unit->port->adapter->ccw_device->dev.bus_id); +-ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", unit->port->wwpn); +-ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", unit->fcp_lun); ++ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n", ++ (unsigned long long) unit->port->wwpn); ++ZFCP_DEFINE_SCSI_ATTR(fcp_lun, "0x%016llx\n", ++ (unsigned long long) unit->fcp_lun); + + struct device_attribute *zfcp_sysfs_sdev_attrs[] = { + &dev_attr_fcp_lun, diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-01-xpram.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-01-xpram.patch new file mode 100644 index 000000000..2fa613afc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-01-xpram.patch @@ -0,0 +1,116 @@ +From: Gerald Schaefer +Subject: xpram: per device block request queues +References: bnc#434333,LTC#49030 + +Symptom: With recent kernels removing xpram module fails to clean up all + sysfs files. The next time the xpram module is loaded you'll get + warnings: + + WARNING: at fs/sysfs/dir.c:463 sysfs_add_one+0x5e/0x64() + sysfs: duplicate filename '35:0' can not be created + Modules linked in: xpram(+) [last unloaded: xpram] + + Followed by the usual WARN_ON output, followed by an error message + from kobject_add_internal, followed by a badness in genhd. +Problem: The xpram driver uses a single block device queue for all of its + devices so far. +Solution: Allocating a block queue per device fixes this. + +Acked-by: John Jolly +--- + + drivers/s390/block/xpram.c | 37 +++++++++++++++---------------------- + 1 file changed, 15 insertions(+), 22 deletions(-) + +--- a/drivers/s390/block/xpram.c ++++ b/drivers/s390/block/xpram.c +@@ -52,6 +52,7 @@ typedef struct { + static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; + static unsigned int xpram_sizes[XPRAM_MAX_DEVS]; + static struct gendisk *xpram_disks[XPRAM_MAX_DEVS]; ++static struct request_queue *xpram_queues[XPRAM_MAX_DEVS]; + static unsigned int xpram_pages; + static int xpram_devs; + +@@ -326,18 +327,22 @@ static int __init xpram_setup_sizes(unsi + return 0; + } + +-static struct request_queue *xpram_queue; +- + static int __init xpram_setup_blkdev(void) + { + unsigned long offset; + int i, rc = -ENOMEM; + + for (i = 0; i < xpram_devs; i++) { +- struct gendisk *disk = alloc_disk(1); +- if (!disk) ++ xpram_disks[i] = alloc_disk(1); ++ if (!xpram_disks[i]) ++ goto out; ++ xpram_queues[i] = blk_alloc_queue(GFP_KERNEL); ++ if (!xpram_queues[i]) { ++ put_disk(xpram_disks[i]); + goto out; +- xpram_disks[i] = disk; ++ } ++ blk_queue_make_request(xpram_queues[i], xpram_make_request); ++ blk_queue_hardsect_size(xpram_queues[i], 4096); + } + + /* +@@ -348,18 +353,6 @@ static int __init xpram_setup_blkdev(voi + goto out; + + /* +- * Assign the other needed values: make request function, sizes and +- * hardsect size. All the minor devices feature the same value. +- */ +- xpram_queue = blk_alloc_queue(GFP_KERNEL); +- if (!xpram_queue) { +- rc = -ENOMEM; +- goto out_unreg; +- } +- blk_queue_make_request(xpram_queue, xpram_make_request); +- blk_queue_hardsect_size(xpram_queue, 4096); +- +- /* + * Setup device structures. + */ + offset = 0; +@@ -373,18 +366,18 @@ static int __init xpram_setup_blkdev(voi + disk->first_minor = i; + disk->fops = &xpram_devops; + disk->private_data = &xpram_devices[i]; +- disk->queue = xpram_queue; ++ disk->queue = xpram_queues[i]; + sprintf(disk->disk_name, "slram%d", i); + set_capacity(disk, xpram_sizes[i] << 1); + add_disk(disk); + } + + return 0; +-out_unreg: +- unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); + out: +- while (i--) ++ while (i--) { ++ blk_cleanup_queue(xpram_queues[i]); + put_disk(xpram_disks[i]); ++ } + return rc; + } + +@@ -396,10 +389,10 @@ static void __exit xpram_exit(void) + int i; + for (i = 0; i < xpram_devs; i++) { + del_gendisk(xpram_disks[i]); ++ blk_cleanup_queue(xpram_queues[i]); + put_disk(xpram_disks[i]); + } + unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); +- blk_cleanup_queue(xpram_queue); + } + + static int __init xpram_init(void) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-03-zfcp.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-03-zfcp.patch new file mode 100644 index 000000000..327cda972 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-03-zfcp.patch @@ -0,0 +1,87 @@ +From: Gerald Schaefer +Subject: Fix zfcp problems that have been found +References: bnc#434333 + +Symptom: lock dependency warnings and flaws found during code review +Problem: various small zfcp problems +Solution: fix zfcp problems + - SCSI command times out on "deleted scsi device" + - fix memory leak for status_read requests + - locking for req_list + - fix error path for failed request send + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fsf.c | 23 ++++++++++------------- + drivers/s390/scsi/zfcp_scsi.c | 12 ++++-------- + 2 files changed, 14 insertions(+), 21 deletions(-) + +--- a/drivers/s390/scsi/zfcp_scsi.c 2008-10-15 16:39:08.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_scsi.c 2008-10-15 16:39:08.000000000 +0200 +@@ -26,14 +26,10 @@ char *zfcp_get_fcp_sns_info_ptr(struct f + static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) + { + struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; +- WARN_ON(!unit); +- if (unit) { +- atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); +- sdpnt->hostdata = NULL; +- unit->device = NULL; +- zfcp_erp_unit_failed(unit, 12, NULL); +- zfcp_unit_put(unit); +- } ++ atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); ++ unit->device = NULL; ++ zfcp_erp_unit_failed(unit, 12, NULL); ++ zfcp_unit_put(unit); + } + + static int zfcp_scsi_slave_configure(struct scsi_device *sdp) +--- a/drivers/s390/scsi/zfcp_fsf.c 2008-10-15 16:39:08.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2008-10-15 16:40:11.000000000 +0200 +@@ -685,6 +685,7 @@ static struct zfcp_fsf_req *zfcp_fsf_all + if (!req) + return NULL; + memset(req, 0, sizeof(*req)); ++ req->pool = pool; + return req; + } + +@@ -771,28 +772,24 @@ static struct zfcp_fsf_req *zfcp_fsf_req + static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) + { + struct zfcp_adapter *adapter = req->adapter; +- struct zfcp_qdio_queue *req_q = &adapter->req_q; ++ unsigned long flags; + int idx; + + /* put allocated FSF request into hash table */ +- spin_lock(&adapter->req_list_lock); ++ spin_lock_irqsave(&adapter->req_list_lock, flags); + idx = zfcp_reqlist_hash(req->req_id); + list_add_tail(&req->list, &adapter->req_list[idx]); +- spin_unlock(&adapter->req_list_lock); ++ spin_unlock_irqrestore(&adapter->req_list_lock, flags); + +- req->qdio_outb_usage = atomic_read(&req_q->count); ++ req->qdio_outb_usage = atomic_read(&adapter->req_q.count); + req->issued = get_clock(); + if (zfcp_qdio_send(req)) { +- /* Queues are down..... */ + del_timer(&req->timer); +- spin_lock(&adapter->req_list_lock); +- zfcp_reqlist_remove(adapter, req); +- spin_unlock(&adapter->req_list_lock); +- /* undo changes in request queue made for this request */ +- atomic_add(req->sbal_number, &req_q->count); +- req_q->first -= req->sbal_number; +- req_q->first += QDIO_MAX_BUFFERS_PER_Q; +- req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ ++ spin_lock_irqsave(&adapter->req_list_lock, flags); ++ /* lookup request again, list might have changed */ ++ if (zfcp_reqlist_find_safe(adapter, req)) ++ zfcp_reqlist_remove(adapter, req); ++ spin_unlock_irqrestore(&adapter->req_list_lock, flags); + zfcp_erp_adapter_reopen(adapter, 0, 116, req); + return -EIO; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-04-qeth-mac.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-04-qeth-mac.patch new file mode 100644 index 000000000..06523fafd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-04-qeth-mac.patch @@ -0,0 +1,31 @@ +From: Gerald Schaefer +Subject: qeth: use firmware MAC-address for layer2 hsi-devices +References: bnc#434333 + +Symptom: Real HiperSocket devices in layer2 show random MAC-address. +Problem: Usability +Solution: Use firmware MAC-address + +Signed-off-by: Ursula Braun +Signed-off-by: Frank Blaschka + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_l2_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -562,7 +562,8 @@ static int qeth_l2_request_initial_mac(s + "device %s: x%x\n", CARD_BUS_ID(card), rc); + } + +- if (card->info.guestlan) { ++ if ((card->info.type == QETH_CARD_TYPE_IQD) || ++ (card->info.guestlan)) { + rc = qeth_setadpparms_change_macaddr(card); + if (rc) { + QETH_DBF_MESSAGE(2, "couldn't get MAC address on " diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-05-qeth-recovery.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-05-qeth-recovery.patch new file mode 100644 index 000000000..5a10b3f75 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-05-qeth-recovery.patch @@ -0,0 +1,133 @@ +From: Gerald Schaefer +Subject: qeth: qeth recovery fails +References: bnc#434333 + +Symptom: Device is not functional after a recovery +Problem: The handling of the IFF flags changed in 2.6.27 code +Solution: Do not touch IFF_UP flag during qeth recovery, but invoke + dev_close() in case of failing recovery. + Cancel outstanding control commands in case of Data Checks or + Channel Checks. + Do not invoke qeth_l2_del_all_mc() in case of a hard stop to speed + up removal of qeth devices. + +Signed-off-by: Ursula Braun +Signed-off-by: Frank Blaschka + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_core_main.c | 4 +++- + drivers/s390/net/qeth_l2_main.c | 11 +++++++---- + drivers/s390/net/qeth_l3_main.c | 8 +++++--- + 3 files changed, 15 insertions(+), 8 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -767,7 +767,7 @@ static int qeth_get_problem(struct ccw_d + if (sense[SENSE_COMMAND_REJECT_BYTE] & + SENSE_COMMAND_REJECT_FLAG) { + QETH_DBF_TEXT(TRACE, 2, "CMDREJi"); +- return 0; ++ return 1; + } + if ((sense[2] == 0xaf) && (sense[3] == 0xfe)) { + QETH_DBF_TEXT(TRACE, 2, "AFFE"); +@@ -895,6 +895,7 @@ static void qeth_irq(struct ccw_device * + } + rc = qeth_get_problem(cdev, irb); + if (rc) { ++ qeth_clear_ipacmd_list(card); + qeth_schedule_recovery(card); + goto out; + } +@@ -4160,6 +4161,7 @@ static void qeth_core_remove_device(stru + unsigned long flags; + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + ++ QETH_DBF_TEXT(SETUP, 2, "removedv"); + if (card->discipline.ccwgdriver) { + card->discipline.ccwgdriver->remove(gdev); + qeth_core_free_discipline(card); +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -397,7 +397,8 @@ static int qeth_l2_stop_card(struct qeth + } + if (card->state == CARD_STATE_SOFTSETUP) { + qeth_l2_process_vlans(card, 1); +- qeth_l2_del_all_mc(card); ++ if (!card->use_hard_stop) ++ qeth_l2_del_all_mc(card); + qeth_clear_ipacmd_list(card); + card->state = CARD_STATE_HARDSETUP; + } +@@ -829,7 +830,6 @@ static int qeth_l2_open(struct net_devic + } + card->data.state = CH_STATE_UP; + card->state = CARD_STATE_UP; +- card->dev->flags |= IFF_UP; + netif_start_queue(dev); + + if (!card->lan_online && netif_carrier_ok(dev)) +@@ -844,7 +844,6 @@ static int qeth_l2_stop(struct net_devic + + QETH_DBF_TEXT(TRACE, 4, "qethstop"); + netif_tx_disable(dev); +- card->dev->flags &= ~IFF_UP; + if (card->state == CARD_STATE_UP) + card->state = CARD_STATE_SOFTSETUP; + return 0; +@@ -1136,9 +1135,13 @@ static int qeth_l2_recover(void *ptr) + if (!rc) + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); +- else ++ else { ++ rtnl_lock(); ++ dev_close(card->dev); ++ rtnl_unlock(); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); ++ } + return 0; + } + +Index: linux-sles11/drivers/s390/net/qeth_l3_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l3_main.c ++++ linux-sles11/drivers/s390/net/qeth_l3_main.c +@@ -2804,7 +2804,6 @@ static int qeth_l3_open(struct net_devic + return -ENODEV; + card->data.state = CH_STATE_UP; + card->state = CARD_STATE_UP; +- card->dev->flags |= IFF_UP; + netif_start_queue(dev); + + if (!card->lan_online && netif_carrier_ok(dev)) +@@ -2818,7 +2817,6 @@ static int qeth_l3_stop(struct net_devic + + QETH_DBF_TEXT(TRACE, 4, "qethstop"); + netif_tx_disable(dev); +- card->dev->flags &= ~IFF_UP; + if (card->state == CARD_STATE_UP) + card->state = CARD_STATE_SOFTSETUP; + return 0; +@@ -3222,9 +3220,13 @@ static int qeth_l3_recover(void *ptr) + if (!rc) + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); +- else ++ else { ++ rtnl_lock(); ++ dev_close(card->dev); ++ rtnl_unlock(); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); ++ } + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-06-qeth-offset.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-06-qeth-offset.patch new file mode 100644 index 000000000..f79f96be4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-06-qeth-offset.patch @@ -0,0 +1,38 @@ +From: Gerald Schaefer +Subject: qeth: fix offset error in non prealloc header path +References: bnc#434333,LTC#48840 + +Symptom: bad or no VSWITCH/guest lan network traffic +Problem: Offset error in the non prealloc header path +Solution: For the non preallocated qeth header code path we should not + change the header length. + +Signed-off-by: Frank Blaschka + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_core_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -3034,7 +3034,7 @@ static inline void __qeth_fill_buffer(st + struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, + int offset) + { +- int length = skb->len - offset; ++ int length = skb->len; + int length_here; + int element; + char *data; +@@ -3046,6 +3046,7 @@ static inline void __qeth_fill_buffer(st + + if (offset >= 0) { + data = skb->data + offset; ++ length -= offset; + first_lap = 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-07-qeth-ipv6check.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-07-qeth-ipv6check.patch new file mode 100644 index 000000000..73377f5ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-07-qeth-ipv6check.patch @@ -0,0 +1,42 @@ +From: Gerald Schaefer +Subject: qeth: remove unnecessary support ckeck in sysfs route6 +References: bnc#434333 + +Symptom: route6 attribute can not be set in initial device condition +Problem: Usability +Solution: Remove this check improves usability because you do not have to + set the device online to initially set ipv6 routing option. + +Signed-off-by: Frank Blaschka + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_l3_sys.c | 7 ------- + 1 file changed, 7 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_l3_sys.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l3_sys.c ++++ linux-sles11/drivers/s390/net/qeth_l3_sys.c +@@ -121,9 +121,6 @@ static ssize_t qeth_l3_dev_route6_show(s + if (!card) + return -EINVAL; + +- if (!qeth_is_supported(card, IPA_IPV6)) +- return sprintf(buf, "%s\n", "n/a"); +- + return qeth_l3_dev_route_show(card, &card->options.route6, buf); + } + +@@ -135,10 +132,6 @@ static ssize_t qeth_l3_dev_route6_store( + if (!card) + return -EINVAL; + +- if (!qeth_is_supported(card, IPA_IPV6)) { +- return -EOPNOTSUPP; +- } +- + return qeth_l3_dev_route_store(card, &card->options.route6, + QETH_PROT_IPV6, buf, count); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-08-qeth-panic.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-08-qeth-panic.patch new file mode 100644 index 000000000..92a2ae85b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-08-qeth-panic.patch @@ -0,0 +1,43 @@ +From: Gerald Schaefer +Subject: qeth: avoid skb_under_panic for malformatted inbound data +References: bnc#434333 + +Symptom: kernel dump +Problem: malformatted inbound packets due to hardware problems +Solution: make the qeth driver more robust in case of malformatted inbound + packets due to hardware problems, an additional check for + OSN-card-type is added for OSN-type packets. + +Signed-off-by: Ursula Braun + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_l2_main.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -453,12 +453,15 @@ static void qeth_l2_process_inbound_buff + netif_rx(skb); + break; + case QETH_HEADER_TYPE_OSN: +- skb_push(skb, sizeof(struct qeth_hdr)); +- skb_copy_to_linear_data(skb, hdr, ++ if (card->info.type == QETH_CARD_TYPE_OSN) { ++ skb_push(skb, sizeof(struct qeth_hdr)); ++ skb_copy_to_linear_data(skb, hdr, + sizeof(struct qeth_hdr)); +- len = skb->len; +- card->osn_info.data_cb(skb); +- break; ++ len = skb->len; ++ card->osn_info.data_cb(skb); ++ break; ++ } ++ /* else unknown */ + default: + dev_kfree_skb_any(skb); + QETH_DBF_TEXT(TRACE, 3, "inbunkno"); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-09-tape-lock.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-09-tape-lock.patch new file mode 100644 index 000000000..57f41979f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-09-tape-lock.patch @@ -0,0 +1,87 @@ +From: Gerald Schaefer +Subject: tape device driver: improve locking +References: bnc#434333 + +Symptom: 1. message "Badness at include/linux/blkdev.h" + 2. lockdep message "INFO: inconsistent lock state" +Problem: 1. Tape block device driver does not hold request queue lock + when completing request via __blk_end_request. + 2. During open() processing tape device driver receives + interrupt while holding the tape device lock. +Solution: 1. Use blk_end_request rather than __blk_end_request + 2. Use spin_lock_irq to disable interrupts rather than spin_lock. + +Acked-by: John Jolly +--- + drivers/s390/char/tape_block.c | 6 ++++-- + drivers/s390/char/tape_core.c | 8 ++++---- + 2 files changed, 8 insertions(+), 6 deletions(-) + +Index: temp_orig/drivers/s390/char/tape_block.c +=================================================================== +--- temp_orig.orig/drivers/s390/char/tape_block.c ++++ temp_orig/drivers/s390/char/tape_block.c +@@ -76,7 +76,7 @@ tapeblock_trigger_requeue(struct tape_de + static void + tapeblock_end_request(struct request *req, int error) + { +- if (__blk_end_request(req, error, blk_rq_bytes(req))) ++ if (blk_end_request(req, error, blk_rq_bytes(req))) + BUG(); + } + +@@ -166,7 +166,7 @@ tapeblock_requeue(struct work_struct *wo + nr_queued++; + spin_unlock(get_ccwdev_lock(device->cdev)); + +- spin_lock(&device->blk_data.request_queue_lock); ++ spin_lock_irq(&device->blk_data.request_queue_lock); + while ( + !blk_queue_plugged(queue) && + elv_next_request(queue) && +@@ -176,7 +176,9 @@ tapeblock_requeue(struct work_struct *wo + if (rq_data_dir(req) == WRITE) { + DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); + blkdev_dequeue_request(req); ++ spin_unlock_irq(&device->blk_data.request_queue_lock); + tapeblock_end_request(req, -EIO); ++ spin_lock_irq(&device->blk_data.request_queue_lock); + continue; + } + blkdev_dequeue_request(req); +Index: temp_orig/drivers/s390/char/tape_core.c +=================================================================== +--- temp_orig.orig/drivers/s390/char/tape_core.c ++++ temp_orig/drivers/s390/char/tape_core.c +@@ -1199,7 +1199,7 @@ tape_open(struct tape_device *device) + { + int rc; + +- spin_lock(get_ccwdev_lock(device->cdev)); ++ spin_lock_irq(get_ccwdev_lock(device->cdev)); + if (device->tape_state == TS_NOT_OPER) { + DBF_EVENT(6, "TAPE:nodev\n"); + rc = -ENODEV; +@@ -1217,7 +1217,7 @@ tape_open(struct tape_device *device) + tape_state_set(device, TS_IN_USE); + rc = 0; + } +- spin_unlock(get_ccwdev_lock(device->cdev)); ++ spin_unlock_irq(get_ccwdev_lock(device->cdev)); + return rc; + } + +@@ -1227,11 +1227,11 @@ tape_open(struct tape_device *device) + int + tape_release(struct tape_device *device) + { +- spin_lock(get_ccwdev_lock(device->cdev)); ++ spin_lock_irq(get_ccwdev_lock(device->cdev)); + if (device->tape_state == TS_IN_USE) + tape_state_set(device, TS_UNUSED); + module_put(device->discipline->owner); +- spin_unlock(get_ccwdev_lock(device->cdev)); ++ spin_unlock_irq(get_ccwdev_lock(device->cdev)); + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-02-10-zfcp-scan-online.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-02-10-zfcp-scan-online.patch new file mode 100644 index 000000000..b1a9d8fa6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-02-10-zfcp-scan-online.patch @@ -0,0 +1,29 @@ +From: Gerald Schaefer +Subject: wait for port scan when setting FCP device online +References: bnc#434333 + +Description: wait for port scan when setting FCP device online +Symptom: running chccwdev -e xxxx; echo ... > unit_add in a script + does not work +Problem: The port scan in zfcp runs asynchronously to set_online +Solution: Wait for the port scan to complete in the zfcp set_online + packets due to hardware problems, an additional check for + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_ccw.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_ccw.c 2008-10-17 18:26:54.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_ccw.c 2008-10-17 18:31:42.000000000 +0200 +@@ -118,7 +118,9 @@ static int zfcp_ccw_set_online(struct cc + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 85, + NULL); + zfcp_erp_wait(adapter); +- goto out; ++ up(&zfcp_data.config_sema); ++ flush_work(&adapter->scan_work); ++ return 0; + + out_scsi_register: + zfcp_erp_thread_kill(adapter); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-01-stp-init.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-01-stp-init.patch new file mode 100644 index 000000000..83b48881a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-01-stp-init.patch @@ -0,0 +1,26 @@ +From: Gerald Schaefer +Subject: kernel: Fix initialization of stp. +References: bnc#440610 + +Symptom: The stp support cannot be activated. +Problem: The return code of chsc_sstpc changed from 1 for success to + 0 for success. The stp_reset function still tests for 1 and + does not set the indication that stp support is available. +Solution: Check for the correct return code of chsc_sstpc. + +Acked-by: John Jolly +--- + arch/s390/kernel/time.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/s390/kernel/time.c ++++ b/arch/s390/kernel/time.c +@@ -1358,7 +1358,7 @@ static void __init stp_reset(void) + + stp_page = alloc_bootmem_pages(PAGE_SIZE); + rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); +- if (rc == 1) ++ if (rc == 0) + set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); + else if (stp_online) { + pr_warning("The real or virtual hardware system does " diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-02-setup_memory.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-02-setup_memory.patch new file mode 100644 index 000000000..13ac3a470 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-02-setup_memory.patch @@ -0,0 +1,36 @@ +From: Gerald Schaefer +Subject: kernel: Fix range for add_active_range() in setup_memory() +References: bnc#440610 + +Symptom: BUG_ON in move_freepages(), when the kernelcore parameter is + specified and the last memory chunk is set offline. +Problem: add_active_range() expects start_pfn + size as end_pfn value, + i.e. not the pfn of the last page frame but the one behind that. + We used the pfn of the last page frame so far. +Solution: Use start_pfn + size as end_pfn value. + +Acked-by: John Jolly +--- + arch/s390/kernel/setup.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-sles11/arch/s390/kernel/setup.c +=================================================================== +--- linux-sles11.orig/arch/s390/kernel/setup.c ++++ linux-sles11/arch/s390/kernel/setup.c +@@ -615,13 +615,13 @@ setup_memory(void) + if (memory_chunk[i].type != CHUNK_READ_WRITE) + continue; + start_chunk = PFN_DOWN(memory_chunk[i].addr); +- end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1; ++ end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size); + end_chunk = min(end_chunk, end_pfn); + if (start_chunk >= end_chunk) + continue; + add_active_range(0, start_chunk, end_chunk); + pfn = max(start_chunk, start_pfn); +- for (; pfn <= end_chunk; pfn++) ++ for (; pfn < end_chunk; pfn++) + page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-03-dasd_unsolicited_interrupt.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-03-dasd_unsolicited_interrupt.patch new file mode 100644 index 000000000..f6fc4f8b3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-03-dasd_unsolicited_interrupt.patch @@ -0,0 +1,52 @@ +From: Gerald Schaefer +Subject: dasd: fix message flood for unsolicited interrupts +References: bnc#440610 + +Symptom: The message log is flooded with messages for unsolicited + interrupts and missing sense data. +Problem: CIO generates fake IRBs which are falsly interpreted as + unsolicited interrupts. +Solution: ignore fake IRBs + +Acked-by: John Jolly +--- + drivers/s390/block/dasd_eckd.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +Index: linux-sles11/drivers/s390/block/dasd_eckd.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd_eckd.c ++++ linux-sles11/drivers/s390/block/dasd_eckd.c +@@ -1501,12 +1501,27 @@ static void dasd_eckd_handle_unsolicited + return; + } + +- /* just report other unsolicited interrupts */ +- DEV_MESSAGE(KERN_DEBUG, device, "%s", +- "unsolicited interrupt received"); +- device->discipline->dump_sense(device, NULL, irb); +- dasd_schedule_device_bh(device); ++ if ((irb->scsw.cmd.cc == 1) && ++ (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && ++ (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) && ++ (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) { ++ /* fake irb do nothing, they are handled elsewhere */ ++ dasd_schedule_device_bh(device); ++ return; ++ } + ++ if (!(irb->esw.esw0.erw.cons)) { ++ /* just report other unsolicited interrupts */ ++ DEV_MESSAGE(KERN_ERR, device, "%s", ++ "unsolicited interrupt received"); ++ } else { ++ DEV_MESSAGE(KERN_ERR, device, "%s", ++ "unsolicited interrupt received " ++ "(sense available)"); ++ device->discipline->dump_sense(device, NULL, irb); ++ } ++ ++ dasd_schedule_device_bh(device); + return; + }; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-04-qdio_multicast_performance.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-04-qdio_multicast_performance.patch new file mode 100644 index 000000000..296b1da18 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-04-qdio_multicast_performance.patch @@ -0,0 +1,52 @@ +From: Gerald Schaefer +Subject: dasd: fix message flood for unsolicited interrupts +References: bnc#440610 + +Symptom: The message log is flooded with messages for unsolicited + interrupts and missing sense data. +Problem: CIO generates fake IRBs which are falsly interpreted as + unsolicited interrupts. +Solution: Ignore fake IRBs in unsolicited interupt handler. + +Acked-by: John Jolly +--- + drivers/s390/cio/qdio.h | 8 ++++++++ + drivers/s390/cio/qdio_main.c | 6 ++++++ + 2 files changed, 14 insertions(+) + +Index: linux-sles11/drivers/s390/cio/qdio.h +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio.h ++++ linux-sles11/drivers/s390/cio/qdio.h +@@ -16,6 +16,14 @@ + #define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */ + #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ + ++/* ++ * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait ++ * till next initiative to give transmitted skbs back to the stack is too long. ++ * Therefore polling is started in case of multicast queue is filled more ++ * than 50 percent. ++ */ ++#define QDIO_IQDIO_POLL_LVL 65 /* HS multicast queue */ ++ + enum qdio_irq_states { + QDIO_IRQ_STATE_INACTIVE, + QDIO_IRQ_STATE_ESTABLISHED, +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -851,6 +851,12 @@ static void __qdio_outbound_processing(s + if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) + return; + ++ if ((queue_type(q) == QDIO_IQDIO_QFMT) && ++ (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) { ++ tasklet_schedule(&q->tasklet); ++ return; ++ } ++ + if (q->u.out.pci_out_enabled) + return; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-05-dasd-block-uevent.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-05-dasd-block-uevent.patch new file mode 100644 index 000000000..5ff053fc5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-05-dasd-block-uevent.patch @@ -0,0 +1,83 @@ +From: Gerald Schaefer +Subject: dasd: DASD uevents are not sent correctly +References: bnc#440610,LTC#49429 + +Symptom: by-id device links are not created +Problem: On SLES10 there was an extra patch that would send + uevents for a DASD block device when it reached the + online state. This code was never upstream and is now + missing from SLES11. +Solution: Send change events when device reaches or leaves online + state. + +Acked-by: John Jolly +--- + drivers/s390/block/dasd.c | 33 ++++++++++++++++++++++++++++++--- + 1 file changed, 30 insertions(+), 3 deletions(-) + +Index: linux-sles11/drivers/s390/block/dasd.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd.c ++++ linux-sles11/drivers/s390/block/dasd.c +@@ -335,7 +335,9 @@ static int dasd_state_unfmt_to_basic(str + static int + dasd_state_ready_to_online(struct dasd_device * device) + { +- int rc; ++ int rc, i; ++ struct gendisk *disk; ++ struct hd_struct *p; + + if (device->discipline->ready_to_online) { + rc = device->discipline->ready_to_online(device); +@@ -343,8 +345,19 @@ dasd_state_ready_to_online(struct dasd_d + return rc; + } + device->state = DASD_STATE_ONLINE; +- if (device->block) ++ if (device->block) { + dasd_schedule_block_bh(device->block); ++ ++ disk = device->block->bdev->bd_disk; ++ kobject_uevent(&disk->dev.kobj, KOBJ_CHANGE); ++ /* send uevents for all partitions */ ++ for (i = 1; i < disk->minors; i++) { ++ p = disk->part[i-1]; ++ if (!p || !p->nr_sects) ++ continue; ++ kobject_uevent(&p->dev.kobj, KOBJ_CHANGE); ++ } ++ } + return 0; + } + +@@ -353,7 +366,9 @@ dasd_state_ready_to_online(struct dasd_d + */ + static int dasd_state_online_to_ready(struct dasd_device *device) + { +- int rc; ++ int rc, i; ++ struct gendisk *disk; ++ struct hd_struct *p; + + if (device->discipline->online_to_ready) { + rc = device->discipline->online_to_ready(device); +@@ -361,6 +376,18 @@ static int dasd_state_online_to_ready(st + return rc; + } + device->state = DASD_STATE_READY; ++ ++ /* send uevents for all partitions */ ++ if (device->block) { ++ disk = device->block->bdev->bd_disk; ++ for (i = 1; i < disk->minors; i++) { ++ p = disk->part[i-1]; ++ if (!p || !p->nr_sects) ++ continue; ++ kobject_uevent(&p->dev.kobj, KOBJ_CHANGE); ++ } ++ kobject_uevent(&disk->dev.kobj, KOBJ_CHANGE); ++ } + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-06-zfcp-hexdump.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-06-zfcp-hexdump.patch new file mode 100644 index 000000000..02ac8b8eb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-06-zfcp-hexdump.patch @@ -0,0 +1,189 @@ +From: Gerald Schaefer +Subject: zfcp: fix hexdump data in s390dbf traces +References: bnc#440610 + +Symptom: Hexdump data in s390dbf traces is incomplete +Problem: The length of the data traced was wrong and the SAN payload + was read from a different place then it was written to. +Solution: Fix the mentioned problems, now we have complete RSCN + traces (up to 1024 bytes) + +Acked-by: John Jolly +--- + + drivers/s390/scsi/zfcp_dbf.c | 42 ++++++++++++++++-------------------------- + drivers/s390/scsi/zfcp_dbf.h | 8 ++------ + 2 files changed, 18 insertions(+), 32 deletions(-) + +diff -urpN linux-2.6/drivers/s390/scsi/zfcp_dbf.c linux-2.6-patched/drivers/s390/scsi/zfcp_dbf.c +--- linux-2.6/drivers/s390/scsi/zfcp_dbf.c 2008-11-04 09:46:57.000000000 +0100 ++++ linux-2.6-patched/drivers/s390/scsi/zfcp_dbf.c 2008-11-04 09:47:18.000000000 +0100 +@@ -32,7 +32,7 @@ static void zfcp_dbf_hexdump(debug_info_ + dump->offset = offset; + dump->size = min(from_len - offset, room); + memcpy(dump->data, from + offset, dump->size); +- debug_event(dbf, level, dump, dump->size); ++ debug_event(dbf, level, dump, dump->size + sizeof(*dump)); + } + } + +@@ -110,7 +110,7 @@ static int zfcp_dbf_view_header(debug_in + t.tv_sec, t.tv_nsec); + zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid); + } else { +- zfcp_dbf_outd(&p, NULL, dump->data, dump->size, dump->offset, ++ zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset, + dump->total_size); + if ((dump->offset + dump->size) == dump->total_size) + p += sprintf(p, "\n"); +@@ -368,6 +368,7 @@ static void zfcp_hba_dbf_view_response(c + break; + zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); + zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); ++ p += sprintf(*p, "\n"); + break; + + case FSF_QTCB_OPEN_PORT_WITH_DID: +@@ -467,7 +468,8 @@ static int zfcp_hba_dbf_view_format(debu + else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0) + zfcp_hba_dbf_view_berr(&p, &r->u.berr); + +- p += sprintf(p, "\n"); ++ if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0) ++ p += sprintf(p, "\n"); + return p - out_buf; + } + +@@ -882,6 +884,7 @@ void zfcp_san_dbf_event_ct_request(struc + struct ct_hdr *hdr = sg_virt(ct->req); + struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; + struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req; ++ int level = 3; + unsigned long flags; + + spin_lock_irqsave(&adapter->san_dbf_lock, flags); +@@ -898,9 +901,10 @@ void zfcp_san_dbf_event_ct_request(struc + oct->options = hdr->options; + oct->max_res_size = hdr->max_res_size; + oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr), +- ZFCP_DBF_CT_PAYLOAD); +- memcpy(oct->payload, (void *)hdr + sizeof(struct ct_hdr), oct->len); +- debug_event(adapter->san_dbf, 3, r, sizeof(*r)); ++ ZFCP_DBF_SAN_MAX_PAYLOAD); ++ debug_event(adapter->san_dbf, level, r, sizeof(*r)); ++ zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level, ++ (void *)hdr + sizeof(struct ct_hdr), oct->len); + spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); + } + +@@ -916,6 +920,7 @@ void zfcp_san_dbf_event_ct_response(stru + struct ct_hdr *hdr = sg_virt(ct->resp); + struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; + struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp; ++ int level = 3; + unsigned long flags; + + spin_lock_irqsave(&adapter->san_dbf_lock, flags); +@@ -931,9 +936,10 @@ void zfcp_san_dbf_event_ct_response(stru + rct->expl = hdr->reason_code_expl; + rct->vendor_unique = hdr->vendor_unique; + rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), +- ZFCP_DBF_CT_PAYLOAD); +- memcpy(rct->payload, (void *)hdr + sizeof(struct ct_hdr), rct->len); +- debug_event(adapter->san_dbf, 3, r, sizeof(*r)); ++ ZFCP_DBF_SAN_MAX_PAYLOAD); ++ debug_event(adapter->san_dbf, level, r, sizeof(*r)); ++ zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level, ++ (void *)hdr + sizeof(struct ct_hdr), rct->len); + spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); + } + +@@ -956,7 +962,7 @@ static void zfcp_san_dbf_event_els(const + rec->u.els.ls_code = ls_code; + debug_event(adapter->san_dbf, level, rec, sizeof(*rec)); + zfcp_dbf_hexdump(adapter->san_dbf, rec, sizeof(*rec), level, +- buffer, min(buflen, ZFCP_DBF_ELS_MAX_PAYLOAD)); ++ buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); + spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); + } + +@@ -1010,8 +1016,6 @@ static int zfcp_san_dbf_view_format(debu + char *out_buf, const char *in_buf) + { + struct zfcp_san_dbf_record *r = (struct zfcp_san_dbf_record *)in_buf; +- char *buffer = NULL; +- int buflen = 0, total = 0; + char *p = out_buf; + + if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) +@@ -1031,9 +1035,6 @@ static int zfcp_san_dbf_view_format(debu + zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype); + zfcp_dbf_out(&p, "options", "0x%02x", ct->options); + zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); +- total = ct->len; +- buffer = ct->payload; +- buflen = min(total, ZFCP_DBF_CT_PAYLOAD); + } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { + struct zfcp_san_dbf_record_ct_response *ct = &r->u.ct_resp; + zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code); +@@ -1041,23 +1042,12 @@ static int zfcp_san_dbf_view_format(debu + zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); + zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); + zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); +- total = ct->len; +- buffer = ct->payload; +- buflen = min(total, ZFCP_DBF_CT_PAYLOAD); + } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || + strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || + strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { + struct zfcp_san_dbf_record_els *els = &r->u.els; + zfcp_dbf_out(&p, "ls_code", "0x%02x", els->ls_code); +- total = els->len; +- buffer = els->payload; +- buflen = min(total, ZFCP_DBF_ELS_PAYLOAD); + } +- +- zfcp_dbf_outd(&p, "payload", buffer, buflen, 0, total); +- if (buflen == total) +- p += sprintf(p, "\n"); +- + return p - out_buf; + } + +diff -urpN linux-2.6/drivers/s390/scsi/zfcp_dbf.h linux-2.6-patched/drivers/s390/scsi/zfcp_dbf.h +--- linux-2.6/drivers/s390/scsi/zfcp_dbf.h 2008-11-04 09:46:30.000000000 +0100 ++++ linux-2.6-patched/drivers/s390/scsi/zfcp_dbf.h 2008-11-04 09:47:18.000000000 +0100 +@@ -163,8 +163,6 @@ struct zfcp_san_dbf_record_ct_request { + u8 options; + u16 max_res_size; + u32 len; +-#define ZFCP_DBF_CT_PAYLOAD 24 +- u8 payload[ZFCP_DBF_CT_PAYLOAD]; + } __attribute__ ((packed)); + + struct zfcp_san_dbf_record_ct_response { +@@ -174,15 +172,11 @@ struct zfcp_san_dbf_record_ct_response { + u8 expl; + u8 vendor_unique; + u32 len; +- u8 payload[ZFCP_DBF_CT_PAYLOAD]; + } __attribute__ ((packed)); + + struct zfcp_san_dbf_record_els { + u8 ls_code; + u32 len; +-#define ZFCP_DBF_ELS_PAYLOAD 32 +-#define ZFCP_DBF_ELS_MAX_PAYLOAD 1024 +- u8 payload[ZFCP_DBF_ELS_PAYLOAD]; + } __attribute__ ((packed)); + + struct zfcp_san_dbf_record { +@@ -196,6 +190,8 @@ struct zfcp_san_dbf_record { + struct zfcp_san_dbf_record_ct_response ct_resp; + struct zfcp_san_dbf_record_els els; + } u; ++#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024 ++ u8 payload[32]; + } __attribute__ ((packed)); + + struct zfcp_scsi_dbf_record { diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-07-qeth_hsi_mcl_string.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-07-qeth_hsi_mcl_string.patch new file mode 100644 index 000000000..ebf352128 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-07-qeth_hsi_mcl_string.patch @@ -0,0 +1,26 @@ +From: Gerald Schaefer +Subject: qeth: pre z9 systems return HiperSocket version string different. +References: bnc#440610,LTC#49052 + +Symptom: Device startup message shows invalid version string. +Problem: z9 changed the string format from EBCDIC to ASCII. +Solution: In case an EBCDIC HiperSocket version string is detected + the string is converted to ASCII before insertion into + message. + +Acked-by: John Jolly + +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -2239,7 +2239,8 @@ void qeth_print_status_message(struct qe + } + /* fallthrough */ + case QETH_CARD_TYPE_IQD: +- if (card->info.guestlan) { ++ if ((card->info.guestlan) || ++ (card->info.mcl_level[0] & 0x80)) { + card->info.mcl_level[0] = (char) _ebcasc[(__u8) + card->info.mcl_level[0]]; + card->info.mcl_level[1] = (char) _ebcasc[(__u8) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-08-zfcp-abort-race.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-08-zfcp-abort-race.patch new file mode 100644 index 000000000..e75b5ab5d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-08-zfcp-abort-race.patch @@ -0,0 +1,53 @@ +From: Gerald Schaefer +Subject: zfcp: eliminate race between validation and locking. +References: bnc#440610 + +Symptom: machine stalls +Problem: ptr is verified before processing is secured by lock. +Solution: assign, verify ptr after secured by lock + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fsf.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fsf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fsf.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fsf.c +@@ -2115,18 +2115,21 @@ static inline void zfcp_fsf_trace_latenc + + static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) + { +- struct scsi_cmnd *scpnt = req->data; ++ struct scsi_cmnd *scpnt; + struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) + &(req->qtcb->bottom.io.fcp_rsp); + u32 sns_len; + char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; + unsigned long flags; + +- if (unlikely(!scpnt)) +- return; +- + read_lock_irqsave(&req->adapter->abort_lock, flags); + ++ scpnt = req->data; ++ if (unlikely(!scpnt)) { ++ read_unlock_irqrestore(&req->adapter->abort_lock, flags); ++ return; ++ } ++ + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { + set_host_byte(scpnt, DID_SOFT_ERROR); + set_driver_byte(scpnt, SUGGEST_RETRY); +@@ -2181,7 +2184,8 @@ skip_fsfstatus: + zfcp_scsi_dbf_event_result("norm", 6, req->adapter, scpnt, req); + + scpnt->host_scribble = NULL; +- (scpnt->scsi_done) (scpnt); ++ if (scpnt->scsi_done) ++ (scpnt->scsi_done) (scpnt); + /* + * We must hold this lock until scsi_done has been called. + * Otherwise we may call scsi_done after abort regarding this diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-03-09-zfcp-oops-during-target-scan.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-03-09-zfcp-oops-during-target-scan.patch new file mode 100644 index 000000000..2bcb428f8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-03-09-zfcp-oops-during-target-scan.patch @@ -0,0 +1,28 @@ +From: Gerald Schaefer +Subject: zfcp: prevent SCSI target scan for vanished rport +References: bnc#440610,LTC#49373 + +Symptom: Oops unable to handle ptr dereference +Problem: A rport might be referenced eventhough it vanished +Solution: Verify that rport is still existant and online + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_erp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_erp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_erp.c ++++ linux-sles11/drivers/s390/scsi/zfcp_erp.c +@@ -1187,7 +1187,9 @@ static void zfcp_erp_scsi_scan(struct wo + container_of(work, struct zfcp_erp_add_work, work); + struct zfcp_unit *unit = p->unit; + struct fc_rport *rport = unit->port->rport; +- scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, ++ ++ if (rport && rport->port_state == FC_PORTSTATE_ONLINE) ++ scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, + scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0); + atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + zfcp_unit_put(unit); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-01-qdio_prevent_double_shutdown.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-01-qdio_prevent_double_shutdown.patch new file mode 100644 index 000000000..bb42fde4d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-01-qdio_prevent_double_shutdown.patch @@ -0,0 +1,28 @@ +From: Gerald Schaefer +Subject: qdio: prevent double qdio shutdown in case of I/O errors. +References: bnc#445100 + +Symptom: I/O errors reported using a zfcp disk. +Problem: In case of I/O errors on a qdio subchannel qdio_shutdown may be + called twice by the qdio driver and by zfcp. +Solution: Remove the superfluous shutdown from qdio and let the upper layer driver + handle the error condition. + +Acked-by: John Jolly + +--- + drivers/s390/cio/qdio_main.c | 1 - + 1 file changed, 1 deletion(-) + +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -1080,7 +1080,6 @@ void qdio_int_handler(struct ccw_device + case -EIO: + sprintf(dbf_text, "ierr%4x", irq_ptr->schid.sch_no); + QDIO_DBF_TEXT2(1, setup, dbf_text); +- qdio_int_error(cdev); + return; + case -ETIMEDOUT: + sprintf(dbf_text, "qtoh%4x", irq_ptr->schid.sch_no); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-02-qdio-osa-port-count.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-02-qdio-osa-port-count.patch new file mode 100644 index 000000000..c5c43f3bb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-02-qdio-osa-port-count.patch @@ -0,0 +1,205 @@ +From: Gerald Schaefer +Subject: qdio: fix qeth port count detection. +References: bnc#445100 + +Symptom: qeth network interface with multiple ports fails to initialize. +Problem: qeth needs to get the port count information before + qdio has allocated a page for the chsc operation. + Otherwise the number of available ports could not be detected. +Solution: Extend qdio_get_ssqd_desc() to store the data in the + specified structure. + +Acked-by: John Jolly + +--- + arch/s390/include/asm/qdio.h | 16 ++++++++-------- + drivers/s390/cio/qdio.h | 3 +++ + drivers/s390/cio/qdio_main.c | 18 +++++++++--------- + drivers/s390/cio/qdio_setup.c | 33 ++++++++++++++++++++++++--------- + drivers/s390/net/qeth_core_main.c | 15 +++++++++++---- + 5 files changed, 55 insertions(+), 30 deletions(-) + +Index: linux-sles11/arch/s390/include/asm/qdio.h +=================================================================== +--- linux-sles11.orig/arch/s390/include/asm/qdio.h ++++ linux-sles11/arch/s390/include/asm/qdio.h +@@ -367,16 +367,16 @@ struct qdio_initialize { + #define QDIO_FLAG_SYNC_OUTPUT 0x02 + #define QDIO_FLAG_PCI_OUT 0x10 + +-extern int qdio_initialize(struct qdio_initialize *init_data); +-extern int qdio_allocate(struct qdio_initialize *init_data); +-extern int qdio_establish(struct qdio_initialize *init_data); ++extern int qdio_initialize(struct qdio_initialize *); ++extern int qdio_allocate(struct qdio_initialize *); ++extern int qdio_establish(struct qdio_initialize *); + extern int qdio_activate(struct ccw_device *); + +-extern int do_QDIO(struct ccw_device*, unsigned int flags, +- int q_nr, int qidx, int count); +-extern int qdio_cleanup(struct ccw_device*, int how); +-extern int qdio_shutdown(struct ccw_device*, int how); ++extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, ++ int q_nr, int bufnr, int count); ++extern int qdio_cleanup(struct ccw_device*, int); ++extern int qdio_shutdown(struct ccw_device*, int); + extern int qdio_free(struct ccw_device *); +-extern struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev); ++extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); + + #endif /* __QDIO_H__ */ +Index: linux-sles11/drivers/s390/cio/qdio.h +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio.h ++++ linux-sles11/drivers/s390/cio/qdio.h +@@ -375,6 +375,9 @@ void qdio_int_handler(struct ccw_device + int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, + int nr_output_qs); + void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); ++int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, ++ struct subchannel_id *schid, ++ struct qdio_ssqd_desc *data); + int qdio_setup_irq(struct qdio_initialize *init_data); + void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, + struct ccw_device *cdev); +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -1126,23 +1126,23 @@ void qdio_int_handler(struct ccw_device + /** + * qdio_get_ssqd_desc - get qdio subchannel description + * @cdev: ccw device to get description for ++ * @data: where to store the ssqd + * +- * Returns a pointer to the saved qdio subchannel description, +- * or NULL for not setup qdio devices. ++ * Returns 0 or an error code. The results of the chsc are stored in the ++ * specified structure. + */ +-struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev) ++int qdio_get_ssqd_desc(struct ccw_device *cdev, ++ struct qdio_ssqd_desc *data) + { +- struct qdio_irq *irq_ptr; + char dbf_text[15]; + ++ if (!cdev || !cdev->private) ++ return -EINVAL; ++ + sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); + QDIO_DBF_TEXT0(0, setup, dbf_text); + +- irq_ptr = cdev->private->qdio_data; +- if (!irq_ptr) +- return NULL; +- +- return &irq_ptr->ssqd_desc; ++ return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); + } + EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); + +Index: linux-sles11/drivers/s390/cio/qdio_setup.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_setup.c ++++ linux-sles11/drivers/s390/cio/qdio_setup.c +@@ -243,22 +243,31 @@ no_qebsm: + QDIO_DBF_TEXT0(0, setup, "noV=V"); + } + +-static int __get_ssqd_info(struct qdio_irq *irq_ptr) ++/* ++ * If there is a qdio_irq we use the chsc_page and store the information ++ * in the qdio_irq, otherwise we copy it to the specified structure. ++ */ ++int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, ++ struct subchannel_id *schid, ++ struct qdio_ssqd_desc *data) + { + struct chsc_ssqd_area *ssqd; + int rc; + + QDIO_DBF_TEXT0(0, setup, "getssqd"); +- ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; ++ if (irq_ptr != NULL) ++ ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; ++ else ++ ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); + memset(ssqd, 0, PAGE_SIZE); + + ssqd->request = (struct chsc_header) { + .length = 0x0010, + .code = 0x0024, + }; +- ssqd->first_sch = irq_ptr->schid.sch_no; +- ssqd->last_sch = irq_ptr->schid.sch_no; +- ssqd->ssid = irq_ptr->schid.ssid; ++ ssqd->first_sch = schid->sch_no; ++ ssqd->last_sch = schid->sch_no; ++ ssqd->ssid = schid->ssid; + + if (chsc(ssqd)) + return -EIO; +@@ -268,11 +277,17 @@ static int __get_ssqd_info(struct qdio_i + + if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || + !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || +- (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) ++ (ssqd->qdio_ssqd.sch != schid->sch_no)) + return -EINVAL; + +- memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, +- sizeof(struct qdio_ssqd_desc)); ++ if (irq_ptr != NULL) ++ memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, ++ sizeof(struct qdio_ssqd_desc)); ++ else { ++ memcpy(&data, &ssqd->qdio_ssqd, ++ sizeof(struct qdio_ssqd_desc)); ++ free_page((unsigned long)ssqd); ++ } + return 0; + } + +@@ -282,7 +297,7 @@ void qdio_setup_ssqd_info(struct qdio_ir + char dbf_text[15]; + int rc; + +- rc = __get_ssqd_info(irq_ptr); ++ rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); + if (rc) { + QDIO_DBF_TEXT2(0, setup, "ssqdasig"); + sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -3767,7 +3767,7 @@ static int qeth_core_driver_group(const + + int qeth_core_hardsetup_card(struct qeth_card *card) + { +- struct qdio_ssqd_desc *qdio_ssqd; ++ struct qdio_ssqd_desc *ssqd; + int retries = 3; + int mpno = 0; + int rc; +@@ -3803,9 +3803,16 @@ retry: + return rc; + } + +- qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); +- if (qdio_ssqd) +- mpno = qdio_ssqd->pcnt; ++ ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); ++ if (!ssqd) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); ++ if (rc == 0) ++ mpno = ssqd->pcnt; ++ kfree(ssqd); ++ + if (mpno) + mpno = min(mpno - 1, QETH_MAX_PORTNO); + if (card->info.portno > mpno) { diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-03-kmsg.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-03-kmsg.patch new file mode 100644 index 000000000..78e63c7d6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-03-kmsg.patch @@ -0,0 +1,27 @@ +From: Gerald Schaefer +Subject: kmsg: do not change pr_xyz messages without KMSG_COMPONENT +References: bnc#445100 + +Symptom: Normal pr_xyz messages without KMSG_COMPONENT have an additional + ": " in the output. +Problem: The pr_printk macro if KMSG_COMPONENT is not defined has + additional text. +Solution: Remove the additional text. + +Acked-by: John Jolly + +--- + include/linux/kernel.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -301,7 +301,7 @@ static inline char *pack_hex_byte(char * + printk(level KMSG_COMPONENT ": " format, ##__VA_ARGS__) + #else + #define pr_printk(level, format, ...) \ +- printk(level ": " format, ##__VA_ARGS__) ++ printk(level format, ##__VA_ARGS__) + #endif + + #if defined(__KMSG_CHECKER) && defined(KMSG_COMPONENT) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-04-dasd_fatal_error_log_sense.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-04-dasd_fatal_error_log_sense.patch new file mode 100644 index 000000000..c4ac633bf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-04-dasd_fatal_error_log_sense.patch @@ -0,0 +1,31 @@ +From: Gerald Schaefer +Subject: dasd: log sense for fatal errors. +References: bnc#445100 + +Symptom: When a fatal error occures no sense data is printed. +Problem: During Hyper PAV work the log sense call was accidentally + removed. +Solution: Call dasd_log_sense() for fatal errors. + +Acked-by: John Jolly + +--- + drivers/s390/block/dasd.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: linux-sles11/drivers/s390/block/dasd.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd.c ++++ linux-sles11/drivers/s390/block/dasd.c +@@ -1773,6 +1773,11 @@ restart: + goto restart; + } + ++ /* log sense for fatal error */ ++ if (cqr->status == DASD_CQR_FAILED) { ++ dasd_log_sense(cqr, &cqr->irb); ++ } ++ + /* First of all call extended error reporting. */ + if (dasd_eer_enabled(base) && + cqr->status == DASD_CQR_FAILED) { diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-07-als.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-07-als.patch new file mode 100644 index 000000000..a24a700cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-07-als.patch @@ -0,0 +1,175 @@ +From: Gerald Schaefer +Subject: kernel: Add processor type march=z10 and a processor type safety check. +References: bnc#445100 + +Description: This patch adds the code generation option for IBM System z10 and + adds a check in head[31,64].S to prevent the execution of a kernel + compiled for a new processor type on an old machine. + +Acked-by: John Jolly +--- + + arch/s390/Kconfig | 8 +++++++ + arch/s390/Makefile | 1 + arch/s390/kernel/head.S | 49 ++++++++++++++++++++++++++++++++++++++++++++++ + arch/s390/kernel/head31.S | 27 ++----------------------- + arch/s390/kernel/head64.S | 23 --------------------- + 5 files changed, 61 insertions(+), 47 deletions(-) + +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -223,6 +223,14 @@ config MARCH_Z9_109 + Class (z9 BC). The kernel will be slightly faster but will not + work on older machines such as the z990, z890, z900, and z800. + ++config MARCH_Z10 ++ bool "IBM System z10" ++ help ++ Select this to enable optimizations for IBM System z10. The ++ kernel will be slightly faster but will not work on older ++ machines such as the z990, z890, z900, z800, z9-109, z9-ec ++ and z9-bc. ++ + endchoice + + config PACK_STACK +--- a/arch/s390/kernel/head31.S ++++ b/arch/s390/kernel/head31.S +@@ -10,34 +10,13 @@ + * + */ + +-# +-# startup-code at 0x10000, running in absolute addressing mode +-# this is called either by the ipl loader or directly by PSW restart +-# or linload or SALIPL +-# +- .org 0x10000 +-startup:basr %r13,0 # get base +-.LPG0: l %r13,0f-.LPG0(%r13) +- b 0(%r13) +-0: .long startup_continue +- +-# +-# params at 10400 (setup.h) +-# +- .org PARMAREA +- .long 0,0 # IPL_DEVICE +- .long 0,0 # INITRD_START +- .long 0,0 # INITRD_SIZE +- +- .org COMMAND_LINE +- .byte "root=/dev/ram0 ro" +- .byte 0 +- + .org 0x11000 + + startup_continue: + basr %r13,0 # get base +-.LPG1: mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) ++.LPG1: ++ ++ mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) + lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers + l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area + # move IPL device to lowcore +--- a/arch/s390/kernel/head64.S ++++ b/arch/s390/kernel/head64.S +@@ -10,29 +10,6 @@ + * + */ + +-# +-# startup-code at 0x10000, running in absolute addressing mode +-# this is called either by the ipl loader or directly by PSW restart +-# or linload or SALIPL +-# +- .org 0x10000 +-startup:basr %r13,0 # get base +-.LPG0: l %r13,0f-.LPG0(%r13) +- b 0(%r13) +-0: .long startup_continue +- +-# +-# params at 10400 (setup.h) +-# +- .org PARMAREA +- .quad 0 # IPL_DEVICE +- .quad 0 # INITRD_START +- .quad 0 # INITRD_SIZE +- +- .org COMMAND_LINE +- .byte "root=/dev/ram0 ro" +- .byte 0 +- + .org 0x11000 + + startup_continue: +--- a/arch/s390/kernel/head.S ++++ b/arch/s390/kernel/head.S +@@ -461,6 +461,55 @@ start: + .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 + .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff + ++# ++# startup-code at 0x10000, running in absolute addressing mode ++# this is called either by the ipl loader or directly by PSW restart ++# or linload or SALIPL ++# ++ .org 0x10000 ++startup:basr %r13,0 # get base ++.LPG0: ++ ++#ifndef CONFIG_MARCH_G5 ++ # check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10} ++ stidp __LC_CPUID # store cpuid ++ lhi %r0,(3f-2f) / 2 ++ la %r1,2f-.LPG0(%r13) ++0: clc __LC_CPUID+4(2),0(%r1) ++ jne 3f ++ lpsw 1f-.LPG0(13) # machine type not good enough, crash ++ .align 16 ++1: .long 0x000a0000,0x00000000 ++2: ++#if defined(CONFIG_MARCH_Z10) ++ .short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086, 0x2094, 0x2096 ++#elif defined(CONFIG_MARCH_Z9_109) ++ .short 0x9672, 0x2064, 0x2066, 0x2084, 0x2086 ++#elif defined(CONFIG_MARCH_Z990) ++ .short 0x9672, 0x2064, 0x2066 ++#elif defined(CONFIG_MARCH_Z900) ++ .short 0x9672 ++#endif ++3: la %r1,2(%r1) ++ brct %r0,0b ++#endif ++ ++ l %r13,0f-.LPG0(%r13) ++ b 0(%r13) ++0: .long startup_continue ++ ++# ++# params at 10400 (setup.h) ++# ++ .org PARMAREA ++ .long 0,0 # IPL_DEVICE ++ .long 0,0 # INITRD_START ++ .long 0,0 # INITRD_SIZE ++ ++ .org COMMAND_LINE ++ .byte "root=/dev/ram0 ro" ++ .byte 0 ++ + #ifdef CONFIG_64BIT + #include "head64.S" + #else +--- a/arch/s390/Makefile ++++ b/arch/s390/Makefile +@@ -34,6 +34,7 @@ cflags-$(CONFIG_MARCH_G5) += $(call cc + cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) + cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) + cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) ++cflags-$(CONFIG_MARCH_Z10) += $(call cc-option,-march=z10) + + #KBUILD_IMAGE is necessary for make rpm + KBUILD_IMAGE :=arch/s390/boot/image diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-08-cio-ungroup-race-fix.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-08-cio-ungroup-race-fix.patch new file mode 100644 index 000000000..eb79bcac0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-08-cio-ungroup-race-fix.patch @@ -0,0 +1,49 @@ +From: Gerald Schaefer +Subject: cio: ccwgroup online vs. ungroup race condition +References: bnc#445100,LTC#50092 + +Symptom: Kernel oops when a ccwgroup ungroup operation is triggered while + online operation is still in progress. +Problem: Atomicity of ungroup operation is not guaranteed because of + missing locking. +Solution: Introduce locking to ungroup operation. + +Acked-by: John Jolly + +--- + drivers/s390/cio/ccwgroup.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +Index: linux-sles11/drivers/s390/cio/ccwgroup.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/ccwgroup.c ++++ linux-sles11/drivers/s390/cio/ccwgroup.c +@@ -89,15 +89,23 @@ ccwgroup_ungroup_store(struct device *de + + gdev = to_ccwgroupdev(dev); + +- if (gdev->state != CCWGROUP_OFFLINE) +- return -EINVAL; +- ++ /* Prevent concurrent online/offline processing and ungrouping. */ ++ if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) ++ return -EAGAIN; ++ if (gdev->state != CCWGROUP_OFFLINE) { ++ rc = -EINVAL; ++ goto out; ++ } + /* Note that we cannot unregister the device from one of its + * attribute methods, so we have to use this roundabout approach. + */ + rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); +- if (rc) +- count = rc; ++out: ++ if (rc) { ++ /* Release onoff "lock" when ungrouping failed. */ ++ atomic_set(&gdev->onoff, 0); ++ return rc; ++ } + return count; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-04-09-zfcp-host-busy-count-fix.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-04-09-zfcp-host-busy-count-fix.patch new file mode 100644 index 000000000..19c206dd5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-04-09-zfcp-host-busy-count-fix.patch @@ -0,0 +1,34 @@ +From: Gerald Schaefer +Subject: zfcp: prevent double decrement on host_busy counter +References: bnc#445100 + +Symptom: SCSI host hangs +Problem: double finish triggerd for one request +Solution: respond, act according to SCSI_mid_low API + +The zfcp_scsi_queuecommand was not acting according to the standard +when respective unit was not available. In this case an -EBUSY was +returned, which is not valid in itself, and in addition scsi_done +was called. This combination is not allowed and was leading to a +double finish of the request and therefor double decrement of the +host_busy counter. + +Signed-off-by: Swen Schillig +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_scsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_scsi.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_scsi.c ++++ linux-sles11/drivers/s390/scsi/zfcp_scsi.c +@@ -90,7 +90,7 @@ static int zfcp_scsi_queuecommand(struct + ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, + ZFCP_REQ_AUTO_CLEANUP); + if (unlikely(ret == -EBUSY)) +- zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); ++ return SCSI_MLQUEUE_DEVICE_BUSY; + else if (unlikely(ret < 0)) + return SCSI_MLQUEUE_HOST_BUSY; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-01-zfcp-message-linebreak.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-01-zfcp-message-linebreak.patch new file mode 100644 index 000000000..3ee152cd0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-01-zfcp-message-linebreak.patch @@ -0,0 +1,37 @@ +From: Gerald Schaefer +Subject: zfcp: Wrong placement of linebreak in message +References: bnc#450096 + +Symptom: Closing parenthesis missing in message output. +Problem: Typo in message. +Solution: Fix message text, put the parenthesis before the + linebreak. + +Acked-by: John Jolly +--- + Documentation/kmsg/s390/zfcp | 2 +- + drivers/s390/scsi/zfcp_fsf.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/s390/scsi/zfcp_fsf.c 2008-11-26 10:51:05.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2008-11-26 10:51:06.000000000 +0100 +@@ -1903,7 +1903,7 @@ static void zfcp_fsf_open_unit_handler(s + dev_err(&adapter->ccw_device->dev, + "Shared read-write access not " + "supported (unit 0x%016Lx, port " +- "0x%016Lx\n)", ++ "0x%016Lx)\n", + (unsigned long long)unit->fcp_lun, + (unsigned long long)unit->port->wwpn); + zfcp_erp_unit_failed(unit, 36, req); +--- a/Documentation/kmsg/s390/zfcp 2008-11-26 10:12:47.000000000 +0100 ++++ b/Documentation/kmsg/s390/zfcp 2008-11-26 10:53:58.000000000 +0100 +@@ -753,7 +753,7 @@ + */ + + /*? +- * Text: "%s: Shared read-write access not supported (unit 0x%016Lx, port 0x%016Lx\n)" ++ * Text: "%s: Shared read-write access not supported (unit 0x%016Lx, port 0x%016Lx)\n" + * Severity: Error + * Parameter: + * @1: bus ID of the zfcp device diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-02-zfcp-invalid-non-null-return.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-02-zfcp-invalid-non-null-return.patch new file mode 100644 index 000000000..ee1c54433 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-02-zfcp-invalid-non-null-return.patch @@ -0,0 +1,41 @@ +From: Gerald Schaefer +Subject: zfcp: invalid return value on failing fsf_req creation +References: bnc#450096 + +Symptom: I/O stops unrecoverably +Problem: An ERR_PTR is returned where a NULL value is expected +Solution: Fix the two instances + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fsf.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fsf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fsf.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fsf.c +@@ -932,8 +932,10 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_ + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, + req_flags, adapter->pool.fsf_req_abort); +- if (IS_ERR(req)) ++ if (IS_ERR(req)) { ++ req = NULL; + goto out; ++ } + + if (unlikely(!(atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) +@@ -2448,8 +2450,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); +- if (IS_ERR(req)) ++ if (IS_ERR(req)) { ++ req = NULL; + goto out; ++ } + + req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; + req->data = unit; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-03-zfcp-wka-port.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-03-zfcp-wka-port.patch new file mode 100644 index 000000000..67f316182 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-03-zfcp-wka-port.patch @@ -0,0 +1,43 @@ +From: Gerald Schaefer +Subject: zfcp: Fix opening of wka ports +References: bnc#450096 + +Symptom: Opening the wka port twice in parallel leads to error + recovery. +Problem: Two port_open requests are sent and the second one + invalidates the existing port handle. Using the wrong + port handle later is unexpected and starts error + recovery. +Solution: Change the status check to only issue one port_open + request and do not accidentally overwrite the existing + port handle. + +Acked-by: John Jolly +--- + + drivers/s390/scsi/zfcp_fc.c | 3 ++- + drivers/s390/scsi/zfcp_fsf.c | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_fc.c 2008-11-26 15:05:49.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_fc.c 2008-11-26 15:13:11.000000000 +0100 +@@ -52,7 +52,8 @@ static int zfcp_wka_port_get(struct zfcp + if (mutex_lock_interruptible(&wka_port->mutex)) + return -ERESTARTSYS; + +- if (wka_port->status != ZFCP_WKA_PORT_ONLINE) { ++ if (wka_port->status == ZFCP_WKA_PORT_OFFLINE || ++ wka_port->status == ZFCP_WKA_PORT_CLOSING) { + wka_port->status = ZFCP_WKA_PORT_OPENING; + if (zfcp_fsf_open_wka_port(wka_port)) + wka_port->status = ZFCP_WKA_PORT_OFFLINE; +--- a/drivers/s390/scsi/zfcp_fsf.c 2008-11-26 15:05:51.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2008-11-26 15:13:11.000000000 +0100 +@@ -1588,6 +1588,7 @@ static void zfcp_fsf_open_wka_port_handl + wka_port->status = ZFCP_WKA_PORT_OFFLINE; + break; + case FSF_PORT_ALREADY_OPEN: ++ break; + case FSF_GOOD: + wka_port->handle = header->port_handle; + wka_port->status = ZFCP_WKA_PORT_ONLINE; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-04-fix_rport_status_check.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-04-fix_rport_status_check.patch new file mode 100644 index 000000000..38d972226 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-04-fix_rport_status_check.patch @@ -0,0 +1,31 @@ +From: Gerald Schaefer +Subject: zfcp: fix remote port status check +References: bnc#450096 + +Symptom: SCSI disks dropped out during FC switch error injection +Problem: For an incoming rscn it was checked by the + ZFCP_STATUS_PORT_DID_DID define to re-open a remote port + or to test the connection. Since this define was re-used + it was also necessary to replace that define. +Solution: Replaced ZFCP_STATUS_PORT_DID_DID with + ZFCP_STATUS_PORT_PHYS_OPEN. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fc.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -128,8 +128,7 @@ static void _zfcp_fc_incoming_rscn(struc + + read_lock_irqsave(&zfcp_data.config_lock, flags); + list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { +- /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ +- if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID)) ++ if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_PHYS_OPEN)) + /* Try to connect to unused ports anyway. */ + zfcp_erp_port_reopen(port, + ZFCP_STATUS_COMMON_ERP_FAILED, diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-05-stp-etr-stop-machine.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-05-stp-etr-stop-machine.patch new file mode 100644 index 000000000..7234de31f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-05-stp-etr-stop-machine.patch @@ -0,0 +1,416 @@ +From: Gerald Schaefer +Subject: stp/etr: smp_call_function races. +References: bnc#450096 + +Symptom: System hangs when setting stp/etr online. +Problem: The stp/etr code uses smp_call_function() with blocking + function on the signalled cpus. This is prone to cause + deadlocks. +Solution: Replace the smp_call_function() synchronization with one + based on stop_machine_run. + +Acked-by: John Jolly +--- + arch/s390/kernel/time.c | 210 +++++++++++++++++++++++++++++------------------- + 1 file changed, 130 insertions(+), 80 deletions(-) + +Index: linux-2.6.27/arch/s390/kernel/time.c +=================================================================== +--- linux-2.6.27.orig/arch/s390/kernel/time.c ++++ linux-2.6.27/arch/s390/kernel/time.c +@@ -22,6 +22,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -365,6 +367,15 @@ static void enable_sync_clock(void) + atomic_set_mask(0x80000000, sw_ptr); + } + ++/* Single threaded workqueue used for etr and stp sync events */ ++static struct workqueue_struct *time_sync_wq; ++ ++static void __init time_init_wq(void) ++{ ++ if (!time_sync_wq) ++ time_sync_wq = create_singlethread_workqueue("timesync"); ++} ++ + /* + * External Time Reference (ETR) code. + */ +@@ -457,17 +468,18 @@ static int __init etr_init(void) + + if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) + return 0; ++ time_init_wq(); + /* Check if this machine has the steai instruction. */ + if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) + etr_steai_available = 1; + setup_timer(&etr_timer, etr_timeout, 0UL); + if (etr_port0_online) { + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + if (etr_port1_online) { + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + return 0; + } +@@ -494,7 +506,7 @@ void etr_switch_to_local(void) + if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) + disable_sync_clock(NULL); + set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + + /* +@@ -510,7 +522,7 @@ void etr_sync_check(void) + if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) + disable_sync_clock(NULL); + set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + + /* +@@ -534,13 +546,13 @@ static void etr_timing_alert(struct etr_ + * Both ports are not up-to-date now. + */ + set_bit(ETR_EVENT_PORT_ALERT, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + + static void etr_timeout(unsigned long dummy) + { + set_bit(ETR_EVENT_UPDATE, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + + /* +@@ -647,14 +659,16 @@ static int etr_aib_follows(struct etr_ai + } + + struct clock_sync_data { ++ atomic_t cpus; + int in_sync; + unsigned long long fixup_cc; ++ int etr_port; ++ struct etr_aib *etr_aib; + }; + +-static void clock_sync_cpu_start(void *dummy) ++static void clock_sync_cpu(struct clock_sync_data *sync) + { +- struct clock_sync_data *sync = dummy; +- ++ atomic_dec(&sync->cpus); + enable_sync_clock(); + /* + * This looks like a busy wait loop but it isn't. etr_sync_cpus +@@ -680,39 +694,35 @@ static void clock_sync_cpu_start(void *d + fixup_clock_comparator(sync->fixup_cc); + } + +-static void clock_sync_cpu_end(void *dummy) +-{ +-} +- + /* + * Sync the TOD clock using the port refered to by aibp. This port + * has to be enabled and the other port has to be disabled. The + * last eacr update has to be more than 1.6 seconds in the past. + */ +-static int etr_sync_clock(struct etr_aib *aib, int port) ++static int etr_sync_clock(void *data) + { +- struct etr_aib *sync_port; +- struct clock_sync_data etr_sync; ++ static int first; + unsigned long long clock, old_clock, delay, delta; +- int follows; ++ struct clock_sync_data *etr_sync; ++ struct etr_aib *sync_port, *aib; ++ int port; + int rc; + +- /* Check if the current aib is adjacent to the sync port aib. */ +- sync_port = (port == 0) ? &etr_port0 : &etr_port1; +- follows = etr_aib_follows(sync_port, aib, port); +- memcpy(sync_port, aib, sizeof(*aib)); +- if (!follows) +- return -EAGAIN; ++ etr_sync = data; + +- /* +- * Catch all other cpus and make them wait until we have +- * successfully synced the clock. smp_call_function will +- * return after all other cpus are in etr_sync_cpu_start. +- */ +- memset(&etr_sync, 0, sizeof(etr_sync)); +- preempt_disable(); +- smp_call_function(clock_sync_cpu_start, &etr_sync, 0); +- local_irq_disable(); ++ if (xchg(&first, 1) == 1) { ++ /* Slave */ ++ clock_sync_cpu(etr_sync); ++ return 0; ++ } ++ ++ /* Wait until all other cpus entered the sync function. */ ++ while (atomic_read(&etr_sync->cpus) != 0) ++ cpu_relax(); ++ ++ port = etr_sync->etr_port; ++ aib = etr_sync->etr_aib; ++ sync_port = (port == 0) ? &etr_port0 : &etr_port1; + enable_sync_clock(); + + /* Set clock to next OTE. */ +@@ -729,16 +739,16 @@ static int etr_sync_clock(struct etr_aib + delay = (unsigned long long) + (aib->edf2.etv - sync_port->edf2.etv) << 32; + delta = adjust_time(old_clock, clock, delay); +- etr_sync.fixup_cc = delta; ++ etr_sync->fixup_cc = delta; + fixup_clock_comparator(delta); + /* Verify that the clock is properly set. */ + if (!etr_aib_follows(sync_port, aib, port)) { + /* Didn't work. */ + disable_sync_clock(NULL); +- etr_sync.in_sync = -EAGAIN; ++ etr_sync->in_sync = -EAGAIN; + rc = -EAGAIN; + } else { +- etr_sync.in_sync = 1; ++ etr_sync->in_sync = 1; + rc = 0; + } + } else { +@@ -746,12 +756,33 @@ static int etr_sync_clock(struct etr_aib + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + disable_sync_clock(NULL); +- etr_sync.in_sync = -EAGAIN; ++ etr_sync->in_sync = -EAGAIN; + rc = -EAGAIN; + } +- local_irq_enable(); +- smp_call_function(clock_sync_cpu_end, NULL, 0); +- preempt_enable(); ++ xchg(&first, 0); ++ return rc; ++} ++ ++static int etr_sync_clock_stop(struct etr_aib *aib, int port) ++{ ++ struct clock_sync_data etr_sync; ++ struct etr_aib *sync_port; ++ int follows; ++ int rc; ++ ++ /* Check if the current aib is adjacent to the sync port aib. */ ++ sync_port = (port == 0) ? &etr_port0 : &etr_port1; ++ follows = etr_aib_follows(sync_port, aib, port); ++ memcpy(sync_port, aib, sizeof(*aib)); ++ if (!follows) ++ return -EAGAIN; ++ memset(&etr_sync, 0, sizeof(etr_sync)); ++ etr_sync.etr_aib = aib; ++ etr_sync.etr_port = port; ++ get_online_cpus(); ++ atomic_set(&etr_sync.cpus, num_online_cpus() - 1); ++ rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map); ++ put_online_cpus(); + return rc; + } + +@@ -908,7 +939,7 @@ static void etr_update_eacr(struct etr_e + } + + /* +- * ETR tasklet. In this function you'll find the main logic. In ++ * ETR work. In this function you'll find the main logic. In + * particular this is the only function that calls etr_update_eacr(), + * it "controls" the etr control register. + */ +@@ -1041,7 +1072,7 @@ static void etr_work_fn(struct work_stru + etr_update_eacr(eacr); + set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + if (now < etr_tolec + (1600000 << 12) || +- etr_sync_clock(&aib, sync_port) != 0) { ++ etr_sync_clock_stop(&aib, sync_port) != 0) { + /* Sync failed. Try again in 1/2 second. */ + eacr.es = 0; + etr_update_eacr(eacr); +@@ -1130,13 +1161,13 @@ static ssize_t etr_online_store(struct s + return count; /* Nothing to do. */ + etr_port0_online = value; + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } else { + if (etr_port1_online == value) + return count; /* Nothing to do. */ + etr_port1_online = value; + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } + return count; + } +@@ -1371,8 +1402,12 @@ static void __init stp_reset(void) + + static int __init stp_init(void) + { +- if (test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online) +- schedule_work(&stp_work); ++ if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) ++ return 0; ++ time_init_wq(); ++ if (!stp_online) ++ return 0; ++ queue_work(time_sync_wq, &stp_work); + return 0; + } + +@@ -1389,7 +1424,7 @@ arch_initcall(stp_init); + static void stp_timing_alert(struct stp_irq_parm *intparm) + { + if (intparm->tsc || intparm->lac || intparm->tcpc) +- schedule_work(&stp_work); ++ queue_work(time_sync_wq, &stp_work); + } + + /* +@@ -1417,46 +1452,34 @@ void stp_island_check(void) + if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) + return; + disable_sync_clock(NULL); +- schedule_work(&stp_work); ++ queue_work(time_sync_wq, &stp_work); + } + +-/* +- * STP tasklet. Check for the STP state and take over the clock +- * synchronization if the STP clock source is usable. +- */ +-static void stp_work_fn(struct work_struct *work) ++ ++static int stp_sync_clock(void *data) + { +- struct clock_sync_data stp_sync; ++ static int first; + unsigned long long old_clock, delta; ++ struct clock_sync_data *stp_sync; + int rc; + +- if (!stp_online) { +- chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); +- return; +- } ++ stp_sync = data; + +- rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); +- if (rc) +- return; ++ if (xchg(&first, 1) == 1) { ++ /* Slave */ ++ clock_sync_cpu(stp_sync); ++ return 0; ++ } + +- rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); +- if (rc || stp_info.c == 0) +- return; ++ /* Wait until all other cpus entered the sync function. */ ++ while (atomic_read(&stp_sync->cpus) != 0) ++ cpu_relax(); + +- /* +- * Catch all other cpus and make them wait until we have +- * successfully synced the clock. smp_call_function will +- * return after all other cpus are in clock_sync_cpu_start. +- */ +- memset(&stp_sync, 0, sizeof(stp_sync)); +- preempt_disable(); +- smp_call_function(clock_sync_cpu_start, &stp_sync, 0); +- local_irq_disable(); + enable_sync_clock(); + + set_bit(CLOCK_SYNC_STP, &clock_sync_flags); + if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + + rc = 0; + if (stp_info.todoff[0] || stp_info.todoff[1] || +@@ -1475,16 +1498,43 @@ static void stp_work_fn(struct work_stru + } + if (rc) { + disable_sync_clock(NULL); +- stp_sync.in_sync = -EAGAIN; ++ stp_sync->in_sync = -EAGAIN; + clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); + if (etr_port0_online || etr_port1_online) +- schedule_work(&etr_work); ++ queue_work(time_sync_wq, &etr_work); + } else +- stp_sync.in_sync = 1; ++ stp_sync->in_sync = 1; ++ xchg(&first, 0); ++ return 0; ++} + +- local_irq_enable(); +- smp_call_function(clock_sync_cpu_end, NULL, 0); +- preempt_enable(); ++/* ++ * STP work. Check for the STP state and take over the clock ++ * synchronization if the STP clock source is usable. ++ */ ++static void stp_work_fn(struct work_struct *work) ++{ ++ struct clock_sync_data stp_sync; ++ int rc; ++ ++ if (!stp_online) { ++ chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); ++ return; ++ } ++ ++ rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); ++ if (rc) ++ return; ++ ++ rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); ++ if (rc || stp_info.c == 0) ++ return; ++ ++ memset(&stp_sync, 0, sizeof(stp_sync)); ++ get_online_cpus(); ++ atomic_set(&stp_sync.cpus, num_online_cpus() - 1); ++ stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); ++ put_online_cpus(); + } + + /* +@@ -1593,7 +1643,7 @@ static ssize_t stp_online_store(struct s + if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) + return -EOPNOTSUPP; + stp_online = value; +- schedule_work(&stp_work); ++ queue_work(time_sync_wq, &stp_work); + return count; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-06-stp-etr-mutex.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-06-stp-etr-mutex.patch new file mode 100644 index 000000000..926daf661 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-06-stp-etr-mutex.patch @@ -0,0 +1,107 @@ +From: Gerald Schaefer +Subject: stp/etr: serialize work. +References: bnc#450096 + +Symptom: Oops when setting stp online. +Problem: The stp/etr work function dispatched with schedule_work() + can be run twice on different cpus because run_workqueue + clears the WORK_STRUCT_PENDING bit before it executes the + function. +Solution: Serialize the etr and stp work functions with a mutex. + +Acked-by: John Jolly +--- + arch/s390/kernel/time.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +Index: linux-2.6.27/arch/s390/kernel/time.c +=================================================================== +--- linux-2.6.27.orig/arch/s390/kernel/time.c ++++ linux-2.6.27/arch/s390/kernel/time.c +@@ -441,6 +441,7 @@ static struct timer_list etr_timer; + + static void etr_timeout(unsigned long dummy); + static void etr_work_fn(struct work_struct *work); ++static DEFINE_MUTEX(etr_work_mutex); + static DECLARE_WORK(etr_work, etr_work_fn); + + /* +@@ -950,6 +951,9 @@ static void etr_work_fn(struct work_stru + struct etr_aib aib; + int sync_port; + ++ /* prevent multiple execution. */ ++ mutex_lock(&etr_work_mutex); ++ + /* Create working copy of etr_eacr. */ + eacr = etr_eacr; + +@@ -965,7 +969,7 @@ static void etr_work_fn(struct work_stru + del_timer_sync(&etr_timer); + etr_update_eacr(eacr); + clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); +- return; ++ goto out_unlock; + } + + /* Store aib to get the current ETR status word. */ +@@ -1052,7 +1056,7 @@ static void etr_work_fn(struct work_stru + eacr.es || sync_port < 0) { + etr_update_eacr(eacr); + etr_set_tolec_timeout(now); +- return; ++ goto out_unlock; + } + + /* +@@ -1080,6 +1084,8 @@ static void etr_work_fn(struct work_stru + etr_set_sync_timeout(); + } else + etr_set_tolec_timeout(now); ++out_unlock: ++ mutex_unlock(&etr_work_mutex); + } + + /* +@@ -1368,6 +1374,7 @@ static struct stp_sstpi stp_info; + static void *stp_page; + + static void stp_work_fn(struct work_struct *work); ++static DEFINE_MUTEX(stp_work_mutex); + static DECLARE_WORK(stp_work, stp_work_fn); + + static int __init early_parse_stp(char *p) +@@ -1517,24 +1524,30 @@ static void stp_work_fn(struct work_stru + struct clock_sync_data stp_sync; + int rc; + ++ /* prevent multiple execution. */ ++ mutex_lock(&stp_work_mutex); ++ + if (!stp_online) { + chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); +- return; ++ goto out_unlock; + } + + rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); + if (rc) +- return; ++ goto out_unlock; + + rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); + if (rc || stp_info.c == 0) +- return; ++ goto out_unlock; + + memset(&stp_sync, 0, sizeof(stp_sync)); + get_online_cpus(); + atomic_set(&stp_sync.cpus, num_online_cpus() - 1); + stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); + put_online_cpus(); ++ ++out_unlock: ++ mutex_unlock(&stp_work_mutex); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-07-generic-ipi.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-07-generic-ipi.patch new file mode 100644 index 000000000..fbe278045 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-07-generic-ipi.patch @@ -0,0 +1,259 @@ +From: Gerald Schaefer +Subject: kernel: smp_call_function races. +References: bnc#450096 + +Symptom: System hangs. +Problem: The s390 specific implementation of smp_call_function() + waits until all signalled cpus have started to execute + the function. This can cause deadlocks. +Solution: Replace the s390 speficic implementation with the generic + ipi infrastructure. + +Acked-by: John Jolly +--- + arch/s390/Kconfig | 1 + arch/s390/include/asm/sigp.h | 1 + arch/s390/include/asm/smp.h | 5 - + arch/s390/kernel/smp.c | 175 ++++--------------------------------------- + 4 files changed, 24 insertions(+), 158 deletions(-) + +--- a/arch/s390/include/asm/sigp.h ++++ b/arch/s390/include/asm/sigp.h +@@ -61,6 +61,7 @@ typedef enum + { + ec_schedule=0, + ec_call_function, ++ ec_call_function_single, + ec_bit_last + } ec_bit_sig; + +--- a/arch/s390/include/asm/smp.h ++++ b/arch/s390/include/asm/smp.h +@@ -91,8 +91,9 @@ extern int __cpu_up (unsigned int cpu); + extern struct mutex smp_cpu_state_mutex; + extern int smp_cpu_polarization[]; + +-extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), +- void *info, int wait); ++extern void arch_send_call_function_single_ipi(int cpu); ++extern void arch_send_call_function_ipi(cpumask_t mask); ++ + #endif + + #ifndef CONFIG_SMP +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -70,6 +70,7 @@ mainmenu "Linux Kernel Configuration" + + config S390 + def_bool y ++ select USE_GENERIC_SMP_HELPERS if SMP + select HAVE_SYSCALL_WRAPPERS + select HAVE_OPROFILE + select HAVE_KPROBES +--- a/arch/s390/kernel/smp.c ++++ b/arch/s390/kernel/smp.c +@@ -79,159 +79,6 @@ static DEFINE_PER_CPU(struct cpu, cpu_de + + static void smp_ext_bitcall(int, ec_bit_sig); + +-/* +- * Structure and data for __smp_call_function_map(). This is designed to +- * minimise static memory requirements. It also looks cleaner. +- */ +-static DEFINE_SPINLOCK(call_lock); +- +-struct call_data_struct { +- void (*func) (void *info); +- void *info; +- cpumask_t started; +- cpumask_t finished; +- int wait; +-}; +- +-static struct call_data_struct *call_data; +- +-/* +- * 'Call function' interrupt callback +- */ +-static void do_call_function(void) +-{ +- void (*func) (void *info) = call_data->func; +- void *info = call_data->info; +- int wait = call_data->wait; +- +- cpu_set(smp_processor_id(), call_data->started); +- (*func)(info); +- if (wait) +- cpu_set(smp_processor_id(), call_data->finished);; +-} +- +-static void __smp_call_function_map(void (*func) (void *info), void *info, +- int wait, cpumask_t map) +-{ +- struct call_data_struct data; +- int cpu, local = 0; +- +- /* +- * Can deadlock when interrupts are disabled or if in wrong context. +- */ +- WARN_ON(irqs_disabled() || in_irq()); +- +- /* +- * Check for local function call. We have to have the same call order +- * as in on_each_cpu() because of machine_restart_smp(). +- */ +- if (cpu_isset(smp_processor_id(), map)) { +- local = 1; +- cpu_clear(smp_processor_id(), map); +- } +- +- cpus_and(map, map, cpu_online_map); +- if (cpus_empty(map)) +- goto out; +- +- data.func = func; +- data.info = info; +- data.started = CPU_MASK_NONE; +- data.wait = wait; +- if (wait) +- data.finished = CPU_MASK_NONE; +- +- call_data = &data; +- +- for_each_cpu_mask(cpu, map) +- smp_ext_bitcall(cpu, ec_call_function); +- +- /* Wait for response */ +- while (!cpus_equal(map, data.started)) +- cpu_relax(); +- if (wait) +- while (!cpus_equal(map, data.finished)) +- cpu_relax(); +-out: +- if (local) { +- local_irq_disable(); +- func(info); +- local_irq_enable(); +- } +-} +- +-/* +- * smp_call_function: +- * @func: the function to run; this must be fast and non-blocking +- * @info: an arbitrary pointer to pass to the function +- * @wait: if true, wait (atomically) until function has completed on other CPUs +- * +- * Run a function on all other CPUs. +- * +- * You must not call this function with disabled interrupts, from a +- * hardware interrupt handler or from a bottom half. +- */ +-int smp_call_function(void (*func) (void *info), void *info, int wait) +-{ +- cpumask_t map; +- +- spin_lock(&call_lock); +- map = cpu_online_map; +- cpu_clear(smp_processor_id(), map); +- __smp_call_function_map(func, info, wait, map); +- spin_unlock(&call_lock); +- return 0; +-} +-EXPORT_SYMBOL(smp_call_function); +- +-/* +- * smp_call_function_single: +- * @cpu: the CPU where func should run +- * @func: the function to run; this must be fast and non-blocking +- * @info: an arbitrary pointer to pass to the function +- * @wait: if true, wait (atomically) until function has completed on other CPUs +- * +- * Run a function on one processor. +- * +- * You must not call this function with disabled interrupts, from a +- * hardware interrupt handler or from a bottom half. +- */ +-int smp_call_function_single(int cpu, void (*func) (void *info), void *info, +- int wait) +-{ +- spin_lock(&call_lock); +- __smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu)); +- spin_unlock(&call_lock); +- return 0; +-} +-EXPORT_SYMBOL(smp_call_function_single); +- +-/** +- * smp_call_function_mask(): Run a function on a set of other CPUs. +- * @mask: The set of cpus to run on. Must not include the current cpu. +- * @func: The function to run. This must be fast and non-blocking. +- * @info: An arbitrary pointer to pass to the function. +- * @wait: If true, wait (atomically) until function has completed on other CPUs. +- * +- * Returns 0 on success, else a negative status code. +- * +- * If @wait is true, then returns once @func has returned; otherwise +- * it returns just before the target cpu calls @func. +- * +- * You must not call this function with disabled interrupts or from a +- * hardware interrupt handler or from a bottom half handler. +- */ +-int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, +- int wait) +-{ +- spin_lock(&call_lock); +- cpu_clear(smp_processor_id(), mask); +- __smp_call_function_map(func, info, wait, mask); +- spin_unlock(&call_lock); +- return 0; +-} +-EXPORT_SYMBOL(smp_call_function_mask); +- + void smp_send_stop(void) + { + int cpu, rc; +@@ -273,7 +120,10 @@ static void do_ext_call_interrupt(__u16 + bits = xchg(&S390_lowcore.ext_call_fast, 0); + + if (test_bit(ec_call_function, &bits)) +- do_call_function(); ++ generic_smp_call_function_interrupt(); ++ ++ if (test_bit(ec_call_function_single, &bits)) ++ generic_smp_call_function_single_interrupt(); + } + + /* +@@ -290,6 +140,19 @@ static void smp_ext_bitcall(int cpu, ec_ + udelay(10); + } + ++void arch_send_call_function_ipi(cpumask_t mask) ++{ ++ int cpu; ++ ++ for_each_cpu_mask(cpu, mask) ++ smp_ext_bitcall(cpu, ec_call_function); ++} ++ ++void arch_send_call_function_single_ipi(int cpu) ++{ ++ smp_ext_bitcall(cpu, ec_call_function_single); ++} ++ + #ifndef CONFIG_64BIT + /* + * this function sends a 'purge tlb' signal to another CPU. +@@ -588,9 +451,9 @@ int __cpuinit start_secondary(void *cpuv + pfault_init(); + + /* Mark this cpu as online */ +- spin_lock(&call_lock); ++ ipi_call_lock(); + cpu_set(smp_processor_id(), cpu_online_map); +- spin_unlock(&call_lock); ++ ipi_call_unlock(); + /* Switch on interrupts */ + local_irq_enable(); + /* Print info about this processor */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-08-topology.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-08-topology.patch new file mode 100644 index 000000000..f08a61afc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-08-topology.patch @@ -0,0 +1,74 @@ +From: Gerald Schaefer +Subject: kernel: disable cpu topology support by default +References: bnc#450096,LTC#50392 + +Symptom: System performance may be lower than expected. +Problem: If the hardware supports the configuration-topology facility + the system cpu topology information will be passed to the + scheduler. The scheduler bases its load balancing decisions + also on the cpu topology. This may have a negative performance + impact on machines where I/O interrupts are distributed unevenly + to cpus. Those cpus which are grouped together and get more I/O + interrupts than others will tend to have a higher average load. +Solution: Disable cpu topology support by default and add a kernel parameter + which allows to switch it on. In order to switch support on + topology=on needs to be added to the kernel parameter line. + +Acked-by: John Jolly +--- + Documentation/kernel-parameters.txt | 8 ++++++++ + arch/s390/kernel/topology.c | 12 +++++++++++- + 2 files changed, 19 insertions(+), 1 deletion(-) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -2201,6 +2201,14 @@ and is between 256 and 4096 characters. + See comment before function dc390_setup() in + drivers/scsi/tmscsim.c. + ++ topology= [S390] ++ Format: {off | on} ++ Specify if the kernel should make use of the cpu ++ topology informations if the hardware supports these. ++ The scheduler will make use of these informations and ++ e.g. base its process migration decisions on it. ++ Default is off. ++ + tp720= [HW,PS2] + + trix= [HW,OSS] MediaTrix AudioTrix Pro +--- a/arch/s390/kernel/topology.c ++++ b/arch/s390/kernel/topology.c +@@ -59,6 +59,7 @@ struct core_info { + cpumask_t mask; + }; + ++static int topology_enabled; + static void topology_work_fn(struct work_struct *work); + static struct tl_info *tl_info; + static struct core_info core_info; +@@ -79,7 +80,7 @@ cpumask_t cpu_coregroup_map(unsigned int + cpumask_t mask; + + cpus_clear(mask); +- if (!machine_has_topology) ++ if (!topology_enabled || !machine_has_topology) + return cpu_present_map; + spin_lock_irqsave(&topology_lock, flags); + while (core) { +@@ -264,6 +265,15 @@ static void topology_interrupt(__u16 cod + schedule_work(&topology_work); + } + ++static int __init early_parse_topology(char *p) ++{ ++ if (strncmp(p, "on", 2)) ++ return 0; ++ topology_enabled = 1; ++ return 0; ++} ++early_param("topology", early_parse_topology); ++ + static int __init init_topology_update(void) + { + int rc; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-05-09-cleanup-of-portopen-requests.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-05-09-cleanup-of-portopen-requests.patch new file mode 100644 index 000000000..ccfaa0999 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-05-09-cleanup-of-portopen-requests.patch @@ -0,0 +1,30 @@ +From: Gerald Schaefer +Subject: zfcp: fix erp timeout cleanup for port open requests +References: bnc#450096 + +Symptom: kernel panic on manylinux idle guests +Problem: If an open port fsf request times out (in erp) the + corresponding erp_action member of the fsf + request need to set to NULL. If the port structure + will be removed later-on there will be still a + reference in the fsf request to the non existing + erp_action otherwise. +Solution: setting erp_action to NULL + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_erp.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-sles11/drivers/s390/scsi/zfcp_erp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_erp.c ++++ linux-sles11/drivers/s390/scsi/zfcp_erp.c +@@ -474,6 +474,7 @@ static void zfcp_erp_strategy_check_fsfr + ZFCP_STATUS_ERP_TIMEDOUT)) { + act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; + zfcp_rec_dbf_event_action(142, act); ++ act->fsf_req->erp_action = NULL; + } + if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) + zfcp_rec_dbf_event_action(143, act); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-01-qeth-ext-src-mac-addr.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-01-qeth-ext-src-mac-addr.patch new file mode 100644 index 000000000..2c9b28649 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-01-qeth-ext-src-mac-addr.patch @@ -0,0 +1,121 @@ +From: Gerald Schaefer +Subject: qeth: exploit source MAC address for inbound layer3 packets +References: bnc#458339 + +Symptom: tcpdump showing "FAKELL" for inbound layer3 packets +Problem: OSA-devices operating in layer3 mode offer adding of the + source MAC address to the QDIO header of inbound packets. + This support is not exploited yet. +Solution: Make use of this functionality to replace FAKELL-entries in + the ethernet header of received packets. + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_core.h | 1 - + drivers/s390/net/qeth_core_main.c | 1 - + drivers/s390/net/qeth_l3_main.c | 16 +++++++++------- + 3 files changed, 9 insertions(+), 9 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_core.h +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core.h ++++ linux-sles11/drivers/s390/net/qeth_core.h +@@ -642,7 +642,6 @@ struct qeth_card_options { + int macaddr_mode; + int fake_broadcast; + int add_hhlen; +- int fake_ll; + int layer2; + enum qeth_large_send_types large_send; + int performance_stats; +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -1071,7 +1071,6 @@ static void qeth_set_intial_options(stru + card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL; + card->options.fake_broadcast = 0; + card->options.add_hhlen = DEFAULT_ADD_HHLEN; +- card->options.fake_ll = 0; + card->options.performance_stats = 0; + card->options.rx_sg_cb = QETH_RX_SG_CB; + } +Index: linux-sles11/drivers/s390/net/qeth_l3_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l3_main.c ++++ linux-sles11/drivers/s390/net/qeth_l3_main.c +@@ -1206,12 +1206,9 @@ static int qeth_l3_start_ipa_source_mac( + + QETH_DBF_TEXT(TRACE, 3, "stsrcmac"); + +- if (!card->options.fake_ll) +- return -EOPNOTSUPP; +- + if (!qeth_is_supported(card, IPA_SOURCE_MAC)) { + dev_info(&card->gdev->dev, +- "Inbound source address not supported on %s\n", ++ "Inbound source MAC-address not supported on %s\n", + QETH_CARD_IFNAME(card)); + return -EOPNOTSUPP; + } +@@ -1920,8 +1917,13 @@ static inline __u16 qeth_l3_rebuild_skb( + memcpy(tg_addr, card->dev->dev_addr, + card->dev->addr_len); + } +- card->dev->header_ops->create(skb, card->dev, prot, tg_addr, +- "FAKELL", card->dev->addr_len); ++ if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) ++ card->dev->header_ops->create(skb, card->dev, prot, ++ tg_addr, &hdr->hdr.l3.dest_addr[2], ++ card->dev->addr_len); ++ else ++ card->dev->header_ops->create(skb, card->dev, prot, ++ tg_addr, "FAKELL", card->dev->addr_len); + } + + #ifdef CONFIG_TR +Index: linux-sles11/Documentation/kmsg/s390/qeth +=================================================================== +--- linux-sles11.orig/Documentation/kmsg/s390/qeth ++++ linux-sles11/Documentation/kmsg/s390/qeth +@@ -275,7 +275,7 @@ + + /*? + * Text: "%s: Activating IPv6 support for %s failed\n" +- * Severity: Error ++ * Severity: Warning + * Parameter: + * @1: bus ID of the qeth device + * @2: network interface name +@@ -437,6 +437,21 @@ + * want to use IPv6 with layer 3 qeth devices. + */ + ++/*? ++ * Text: "%s: Starting source MAC-address support for %s failed\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the qeth device ++ * @2: network interface name ++ * Description: ++ * The qeth device driver could not enable source MAC-address on the network ++ * adapter. ++ * User action: ++ * Ungroup and regroup the subchannel triplet of the device. If this does not ++ * resolve the problem, reboot Linux. If the problem persists, gather Linux ++ * debug data and report the problem to your support organization. ++ */ ++ + /*? Text: "core functions removed\n" */ + /*? Text: "%s: Device is a%s card%s%s%s\nwith link type %s.\n" */ + /*? Text: "%s: Device is a%s card%s%s%s\nwith link type %s (no portname needed by interface).\n" */ +@@ -452,7 +467,7 @@ + /*? Text: "%s: Hardware IP fragmentation not supported on %s\n" */ + /*? Text: "%s: IPv6 not supported on %s\n" */ + /*? Text: "%s: VLAN not supported on %s\n" */ +-/*? Text: "%s: Inbound source address not supported on %s\n" */ ++/*? Text: "%s: Inbound source MAC-address not supported on %s\n" */ + /*? Text: "%s: IPV6 enabled\n" */ + /*? Text: "%s: ARP processing not supported on %s!\n" */ + /*? Text: "%s: Hardware IP fragmentation enabled \n" */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-02-qeth-layercrash.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-02-qeth-layercrash.patch new file mode 100644 index 000000000..414020ddf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-02-qeth-layercrash.patch @@ -0,0 +1,101 @@ +From: Gerald Schaefer +Subject: qeth: avoid crash in case of layer mismatch for VSWITCH +References: bnc#458339 + +Symptom: Oops in dev_close invocation of qeth_recover +Problem: For z/VM GuestLAN or VSWITCH devices the transport + layer is configured in z/VM. The layer2 attribute of + a participating Linux device has to match the z/VM + definition. In case of a mismatch Linux currently + crashes in qeth recovery due to a reference to the + not yet existing net_device. +Solution: add a check for existence of net_device and add a + message pointing to the mismatch of layer definitions + in Linux and z/VM. + +Acked-by: John Jolly +--- + + drivers/s390/net/qeth_core_main.c | 4 ++++ + drivers/s390/net/qeth_l2_main.c | 8 +++++--- + drivers/s390/net/qeth_l3_main.c | 8 +++++--- + 3 files changed, 14 insertions(+), 6 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -571,6 +571,10 @@ static void qeth_send_control_data_cb(st + card = CARD_FROM_CDEV(channel->ccwdev); + if (qeth_check_idx_response(iob->data)) { + qeth_clear_ipacmd_list(card); ++ if (((iob->data[2] & 0xc0) == 0xc0) && iob->data[4] == 0xf6) ++ dev_err(&card->gdev->dev, ++ "The qeth device is not configured " ++ "for the OSI layer required by z/VM\n"); + qeth_schedule_recovery(card); + goto out; + } +Index: linux-sles11/drivers/s390/net/qeth_l3_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l3_main.c ++++ linux-sles11/drivers/s390/net/qeth_l3_main.c +@@ -2083,9 +2083,11 @@ static int qeth_l3_stop_card(struct qeth + if (recovery_mode) + qeth_l3_stop(card->dev); + else { +- rtnl_lock(); +- dev_close(card->dev); +- rtnl_unlock(); ++ if (card->dev) { ++ rtnl_lock(); ++ dev_close(card->dev); ++ rtnl_unlock(); ++ } + } + if (!card->use_hard_stop) { + rc = qeth_send_stoplan(card); +Index: linux-sles11/Documentation/kmsg/s390/qeth +=================================================================== +--- linux-sles11.orig/Documentation/kmsg/s390/qeth ++++ linux-sles11/Documentation/kmsg/s390/qeth +@@ -438,6 +438,20 @@ + */ + + /*? ++ * Text: "%s: The qeth device is not configured for the OSI layer required by z/VM\n" ++ * Severity: Error ++ * Description: ++ * A qeth device that connects to a virtual network on z/VM must be configured for the ++ * same Open Systems Interconnection (OSI) layer as the virtual network. An ETHERNET ++ * guest LAN or VSWITCH uses the data link layer (layer 2) while an IP guest LAN ++ * or VSWITCH uses the network layer (layer 3). ++ * User action: ++ * If you are connecting to an ETHERNET guest LAN or VSWITCH, set the layer2 sysfs ++ * attribute of the qeth device to 1. If you are connecting to an IP guest LAN or ++ * VSWITCH, set the layer2 sysfs attribute of the qeth device to 0. ++ */ ++ ++/*? + * Text: "%s: Starting source MAC-address support for %s failed\n" + * Severity: Warning + * Parameter: +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -1139,9 +1139,11 @@ static int qeth_l2_recover(void *ptr) + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); + else { +- rtnl_lock(); +- dev_close(card->dev); +- rtnl_unlock(); ++ if (card->dev) { ++ rtnl_lock(); ++ dev_close(card->dev); ++ rtnl_unlock(); ++ } + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-03-dasd_sim_sense_condition.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-03-dasd_sim_sense_condition.patch new file mode 100644 index 000000000..401967f31 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-03-dasd_sim_sense_condition.patch @@ -0,0 +1,26 @@ +From: Gerald Schaefer +Subject: Fix unsolicited SIM sense condition. +References: bnc#458339 + +Symptom: SIM reported via unsolicited interrupt are not shown. +Problem: SIMs are alway 32 bit sense data so byte 27 bit 0 has not to + be set. This was mixed up. +Solution: Negate condition for byte 27 bit 0. + +Acked-by: John Jolly + +--- + drivers/s390/block/dasd_eckd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/s390/block/dasd_eckd.c ++++ b/drivers/s390/block/dasd_eckd.c +@@ -1494,7 +1494,7 @@ static void dasd_eckd_handle_unsolicited + + + /* service information message SIM */ +- if (irb->esw.esw0.erw.cons && (irb->ecw[27] & DASD_SENSE_BIT_0) && ++ if (irb->esw.esw0.erw.cons && !(irb->ecw[27] & DASD_SENSE_BIT_0) && + ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { + dasd_3990_erp_handle_sim(device, irb->ecw); + dasd_schedule_device_bh(device); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-04-qdio_ssqd_memcpy.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-04-qdio_ssqd_memcpy.patch new file mode 100644 index 000000000..1762eba82 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-04-qdio_ssqd_memcpy.patch @@ -0,0 +1,29 @@ +From: Gerald Schaefer +Subject: qdio: fix broken memcpy +References: bnc#458339 + +Symptom: qeth fails to detect multiple ports on OSA Express 3 cards. +Problem: The memcpy that stores the detected card features is broken. + Therefore qeth reads a port count of zero and cannot detect + multiple ports. +Solution: Fix the memcpy. + +Acked-by: John Jolly + +--- + drivers/s390/cio/qdio_setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/cio/qdio_setup.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_setup.c ++++ linux-sles11/drivers/s390/cio/qdio_setup.c +@@ -284,7 +284,7 @@ int qdio_setup_get_ssqd(struct qdio_irq + memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, + sizeof(struct qdio_ssqd_desc)); + else { +- memcpy(&data, &ssqd->qdio_ssqd, ++ memcpy(data, &ssqd->qdio_ssqd, + sizeof(struct qdio_ssqd_desc)); + free_page((unsigned long)ssqd); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-05-qdio_s390dbf.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-05-qdio_s390dbf.patch new file mode 100644 index 000000000..013cf886a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-05-qdio_s390dbf.patch @@ -0,0 +1,1395 @@ +From: Gerald Schaefer +Subject: qdio: rework s390dbf usage +References: bnc#458339 + +Symptom: n/a +Problem: n/a +Solution: Add a debug view per qdio device that contains trace data. + This trace view is no longer dependent on a Kconfig option and + can be manually enabled at runtime. + Add a global error view for all qdio problems. + Enlarge the setup view in order to find data structures also in + case of many qdio devices used. + +Acked-by: John Jolly + +--- + arch/s390/Kconfig | 10 - + drivers/s390/cio/qdio.h | 3 + drivers/s390/cio/qdio_debug.c | 95 +++++------ + drivers/s390/cio/qdio_debug.h | 126 +++++++-------- + drivers/s390/cio/qdio_main.c | 320 +++++++++++----------------------------- + drivers/s390/cio/qdio_setup.c | 110 ++++--------- + drivers/s390/cio/qdio_thinint.c | 25 +-- + 7 files changed, 242 insertions(+), 447 deletions(-) + +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -352,16 +352,6 @@ config QDIO + + If unsure, say Y. + +-config QDIO_DEBUG +- bool "Extended debugging information" +- depends on QDIO +- help +- Say Y here to get extended debugging output in +- /sys/kernel/debug/s390dbf/qdio... +- Warning: this option reduces the performance of the QDIO module. +- +- If unsure, say N. +- + config CHSC_SCH + tristate "Support for CHSC subchannels" + help +--- a/drivers/s390/cio/qdio_debug.c ++++ b/drivers/s390/cio/qdio_debug.c +@@ -14,66 +14,40 @@ + #include "qdio.h" + + debug_info_t *qdio_dbf_setup; +-debug_info_t *qdio_dbf_trace; ++debug_info_t *qdio_dbf_error; + + static struct dentry *debugfs_root; + #define MAX_DEBUGFS_QUEUES 32 + static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; + static DEFINE_MUTEX(debugfs_mutex); + +-void qdio_allocate_do_dbf(struct qdio_initialize *init_data) ++void qdio_allocate_dbf(struct qdio_initialize *init_data, ++ struct qdio_irq *irq_ptr) + { +- char dbf_text[20]; ++ char text[20]; + +- sprintf(dbf_text, "qfmt:%x", init_data->q_format); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- QDIO_DBF_HEX0(0, setup, init_data->adapter_name, 8); +- sprintf(dbf_text, "qpff%4x", init_data->qib_param_field_format); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- QDIO_DBF_HEX0(0, setup, &init_data->qib_param_field, sizeof(void *)); +- QDIO_DBF_HEX0(0, setup, &init_data->input_slib_elements, sizeof(void *)); +- QDIO_DBF_HEX0(0, setup, &init_data->output_slib_elements, sizeof(void *)); +- sprintf(dbf_text, "niq:%4x", init_data->no_input_qs); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- sprintf(dbf_text, "noq:%4x", init_data->no_output_qs); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- QDIO_DBF_HEX0(0, setup, &init_data->input_handler, sizeof(void *)); +- QDIO_DBF_HEX0(0, setup, &init_data->output_handler, sizeof(void *)); +- QDIO_DBF_HEX0(0, setup, &init_data->int_parm, sizeof(long)); +- QDIO_DBF_HEX0(0, setup, &init_data->flags, sizeof(long)); +- QDIO_DBF_HEX0(0, setup, &init_data->input_sbal_addr_array, sizeof(void *)); +- QDIO_DBF_HEX0(0, setup, &init_data->output_sbal_addr_array, sizeof(void *)); +-} +- +-static void qdio_unregister_dbf_views(void) +-{ +- if (qdio_dbf_setup) +- debug_unregister(qdio_dbf_setup); +- if (qdio_dbf_trace) +- debug_unregister(qdio_dbf_trace); +-} +- +-static int qdio_register_dbf_views(void) +-{ +- qdio_dbf_setup = debug_register("qdio_setup", QDIO_DBF_SETUP_PAGES, +- QDIO_DBF_SETUP_NR_AREAS, +- QDIO_DBF_SETUP_LEN); +- if (!qdio_dbf_setup) +- goto oom; +- debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); +- debug_set_level(qdio_dbf_setup, QDIO_DBF_SETUP_LEVEL); +- +- qdio_dbf_trace = debug_register("qdio_trace", QDIO_DBF_TRACE_PAGES, +- QDIO_DBF_TRACE_NR_AREAS, +- QDIO_DBF_TRACE_LEN); +- if (!qdio_dbf_trace) +- goto oom; +- debug_register_view(qdio_dbf_trace, &debug_hex_ascii_view); +- debug_set_level(qdio_dbf_trace, QDIO_DBF_TRACE_LEVEL); +- return 0; +-oom: +- qdio_unregister_dbf_views(); +- return -ENOMEM; ++ DBF_EVENT("qfmt:%1d", init_data->q_format); ++ DBF_HEX(init_data->adapter_name, 8); ++ DBF_EVENT("qpff%4x", init_data->qib_param_field_format); ++ DBF_HEX(&init_data->qib_param_field, sizeof(void *)); ++ DBF_HEX(&init_data->input_slib_elements, sizeof(void *)); ++ DBF_HEX(&init_data->output_slib_elements, sizeof(void *)); ++ DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs, ++ init_data->no_output_qs); ++ DBF_HEX(&init_data->input_handler, sizeof(void *)); ++ DBF_HEX(&init_data->output_handler, sizeof(void *)); ++ DBF_HEX(&init_data->int_parm, sizeof(long)); ++ DBF_HEX(&init_data->flags, sizeof(long)); ++ DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); ++ DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); ++ DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); ++ ++ /* allocate trace view for the interface */ ++ snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev)); ++ irq_ptr->debug_area = debug_register(text, 2, 1, 16); ++ debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view); ++ debug_set_level(irq_ptr->debug_area, DBF_WARN); ++ DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); + } + + static int qstat_show(struct seq_file *m, void *v) +@@ -230,11 +204,24 @@ void qdio_shutdown_debug_entries(struct + int __init qdio_debug_init(void) + { + debugfs_root = debugfs_create_dir("qdio_queues", NULL); +- return qdio_register_dbf_views(); ++ ++ qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); ++ debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); ++ debug_set_level(qdio_dbf_setup, DBF_INFO); ++ DBF_EVENT("dbf created\n"); ++ ++ qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); ++ debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); ++ debug_set_level(qdio_dbf_error, DBF_INFO); ++ DBF_ERROR("dbf created\n"); ++ return 0; + } + + void qdio_debug_exit(void) + { + debugfs_remove(debugfs_root); +- qdio_unregister_dbf_views(); ++ if (qdio_dbf_setup) ++ debug_unregister(qdio_dbf_setup); ++ if (qdio_dbf_error) ++ debug_unregister(qdio_dbf_error); + } +--- a/drivers/s390/cio/qdio_debug.h ++++ b/drivers/s390/cio/qdio_debug.h +@@ -12,80 +12,72 @@ + #include + #include "qdio.h" + +-#define QDIO_DBF_HEX(ex, name, level, addr, len) \ +- do { \ +- if (ex) \ +- debug_exception(qdio_dbf_##name, level, (void *)(addr), len); \ +- else \ +- debug_event(qdio_dbf_##name, level, (void *)(addr), len); \ +- } while (0) +-#define QDIO_DBF_TEXT(ex, name, level, text) \ +- do { \ +- if (ex) \ +- debug_text_exception(qdio_dbf_##name, level, text); \ +- else \ +- debug_text_event(qdio_dbf_##name, level, text); \ +- } while (0) +- +-#define QDIO_DBF_HEX0(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 0, addr, len) +-#define QDIO_DBF_HEX1(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 1, addr, len) +-#define QDIO_DBF_HEX2(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 2, addr, len) +- +-#ifdef CONFIG_QDIO_DEBUG +-#define QDIO_DBF_HEX3(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 3, addr, len) +-#define QDIO_DBF_HEX4(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 4, addr, len) +-#define QDIO_DBF_HEX5(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 5, addr, len) +-#define QDIO_DBF_HEX6(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 6, addr, len) +-#else +-#define QDIO_DBF_HEX3(ex, name, addr, len) do {} while (0) +-#define QDIO_DBF_HEX4(ex, name, addr, len) do {} while (0) +-#define QDIO_DBF_HEX5(ex, name, addr, len) do {} while (0) +-#define QDIO_DBF_HEX6(ex, name, addr, len) do {} while (0) +-#endif /* CONFIG_QDIO_DEBUG */ +- +-#define QDIO_DBF_TEXT0(ex, name, text) QDIO_DBF_TEXT(ex, name, 0, text) +-#define QDIO_DBF_TEXT1(ex, name, text) QDIO_DBF_TEXT(ex, name, 1, text) +-#define QDIO_DBF_TEXT2(ex, name, text) QDIO_DBF_TEXT(ex, name, 2, text) +- +-#ifdef CONFIG_QDIO_DEBUG +-#define QDIO_DBF_TEXT3(ex, name, text) QDIO_DBF_TEXT(ex, name, 3, text) +-#define QDIO_DBF_TEXT4(ex, name, text) QDIO_DBF_TEXT(ex, name, 4, text) +-#define QDIO_DBF_TEXT5(ex, name, text) QDIO_DBF_TEXT(ex, name, 5, text) +-#define QDIO_DBF_TEXT6(ex, name, text) QDIO_DBF_TEXT(ex, name, 6, text) +-#else +-#define QDIO_DBF_TEXT3(ex, name, text) do {} while (0) +-#define QDIO_DBF_TEXT4(ex, name, text) do {} while (0) +-#define QDIO_DBF_TEXT5(ex, name, text) do {} while (0) +-#define QDIO_DBF_TEXT6(ex, name, text) do {} while (0) +-#endif /* CONFIG_QDIO_DEBUG */ +- +-/* s390dbf views */ +-#define QDIO_DBF_SETUP_LEN 8 +-#define QDIO_DBF_SETUP_PAGES 8 +-#define QDIO_DBF_SETUP_NR_AREAS 1 +- +-#define QDIO_DBF_TRACE_LEN 8 +-#define QDIO_DBF_TRACE_NR_AREAS 2 +- +-#ifdef CONFIG_QDIO_DEBUG +-#define QDIO_DBF_TRACE_PAGES 32 +-#define QDIO_DBF_SETUP_LEVEL 6 +-#define QDIO_DBF_TRACE_LEVEL 4 +-#else /* !CONFIG_QDIO_DEBUG */ +-#define QDIO_DBF_TRACE_PAGES 8 +-#define QDIO_DBF_SETUP_LEVEL 2 +-#define QDIO_DBF_TRACE_LEVEL 2 +-#endif /* CONFIG_QDIO_DEBUG */ ++/* that gives us 15 characters in the text event views */ ++#define QDIO_DBF_LEN 16 + + extern debug_info_t *qdio_dbf_setup; +-extern debug_info_t *qdio_dbf_trace; ++extern debug_info_t *qdio_dbf_error; ++ ++/* sort out low debug levels early to avoid wasted sprints */ ++static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) ++{ ++ return (level <= dbf_grp->level); ++} ++ ++#define DBF_ERR 3 /* error conditions */ ++#define DBF_WARN 4 /* warning conditions */ ++#define DBF_INFO 6 /* informational */ ++ ++#undef DBF_EVENT ++#undef DBF_ERROR ++#undef DBF_DEV_EVENT ++ ++#define DBF_EVENT(text...) \ ++ do { \ ++ char debug_buffer[QDIO_DBF_LEN]; \ ++ snprintf(debug_buffer, QDIO_DBF_LEN, text); \ ++ debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ ++ } while (0) ++ ++#define DBF_HEX(addr, len) \ ++ do { \ ++ debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \ ++ } while (0) ++ ++#define DBF_ERROR(text...) \ ++ do { \ ++ char debug_buffer[QDIO_DBF_LEN]; \ ++ snprintf(debug_buffer, QDIO_DBF_LEN, text); \ ++ debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ ++ } while (0) + +-void qdio_allocate_do_dbf(struct qdio_initialize *init_data); +-void debug_print_bstat(struct qdio_q *q); ++#define DBF_ERROR_HEX(addr, len) \ ++ do { \ ++ debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \ ++ } while (0) ++ ++ ++#define DBF_DEV_EVENT(level, device, text...) \ ++ do { \ ++ char debug_buffer[QDIO_DBF_LEN]; \ ++ if (qdio_dbf_passes(device->debug_area, level)) { \ ++ snprintf(debug_buffer, QDIO_DBF_LEN, text); \ ++ debug_text_event(device->debug_area, level, debug_buffer); \ ++ } \ ++ } while (0) ++ ++#define DBF_DEV_HEX(level, device, addr, len) \ ++ do { \ ++ debug_event(device->debug_area, level, (void*)(addr), len); \ ++ } while (0) ++ ++void qdio_allocate_dbf(struct qdio_initialize *init_data, ++ struct qdio_irq *irq_ptr); + void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, + struct ccw_device *cdev); + void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, + struct ccw_device *cdev); + int qdio_debug_init(void); + void qdio_debug_exit(void); ++ + #endif +--- a/drivers/s390/cio/qdio.h ++++ b/drivers/s390/cio/qdio.h +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include "chsc.h" + + #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ +@@ -297,11 +298,13 @@ struct qdio_irq { + struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ]; + struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; + ++ debug_info_t *debug_area; + struct mutex setup_mutex; + }; + + /* helper functions */ + #define queue_type(q) q->irq_ptr->qib.qfmt ++#define SCH_NO(q) (q->irq_ptr->schid.sch_no) + + #define is_thinint_irq(irq) \ + (irq->qib.qfmt == QDIO_IQDIO_QFMT || \ +--- a/drivers/s390/cio/qdio_main.c ++++ b/drivers/s390/cio/qdio_main.c +@@ -95,8 +95,6 @@ static inline int do_siga_output(unsigne + + static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) + { +- char dbf_text[15]; +- + /* all done or next buffer state different */ + if (ccq == 0 || ccq == 32) + return 0; +@@ -104,8 +102,7 @@ static inline int qdio_check_ccq(struct + if (ccq == 96 || ccq == 97) + return 1; + /* notify devices immediately */ +- sprintf(dbf_text, "%d", ccq); +- QDIO_DBF_TEXT2(1, trace, dbf_text); ++ DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); + return -EIO; + } + +@@ -126,7 +123,6 @@ static int qdio_do_eqbs(struct qdio_q *q + int tmp_count = count, tmp_start = start; + int nr = q->nr; + int rc; +- char dbf_text[15]; + + BUG_ON(!q->irq_ptr->sch_token); + +@@ -142,14 +138,13 @@ again: + if ((ccq == 96) && (count != tmp_count)) + return (count - tmp_count); + if (rc == 1) { +- QDIO_DBF_TEXT5(1, trace, "eqAGAIN"); ++ DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); + goto again; + } + + if (rc < 0) { +- QDIO_DBF_TEXT2(1, trace, "eqberr"); +- sprintf(dbf_text, "%2x,%2x,%d,%d", count, tmp_count, ccq, nr); +- QDIO_DBF_TEXT2(1, trace, dbf_text); ++ DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); ++ DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); + q->handler(q->irq_ptr->cdev, + QDIO_ERROR_ACTIVATE_CHECK_CONDITION, + 0, -1, -1, q->irq_ptr->int_parm); +@@ -176,7 +171,6 @@ static int qdio_do_sqbs(struct qdio_q *q + int tmp_count = count, tmp_start = start; + int nr = q->nr; + int rc; +- char dbf_text[15]; + + BUG_ON(!q->irq_ptr->sch_token); + +@@ -186,16 +180,12 @@ again: + ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); + rc = qdio_check_ccq(q, ccq); + if (rc == 1) { +- QDIO_DBF_TEXT5(1, trace, "sqAGAIN"); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); + goto again; + } + if (rc < 0) { +- QDIO_DBF_TEXT3(1, trace, "sqberr"); +- sprintf(dbf_text, "%2x,%2x", count, tmp_count); +- QDIO_DBF_TEXT3(1, trace, dbf_text); +- sprintf(dbf_text, "%d,%d", ccq, nr); +- QDIO_DBF_TEXT3(1, trace, dbf_text); +- ++ DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); ++ DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); + q->handler(q->irq_ptr->cdev, + QDIO_ERROR_ACTIVATE_CHECK_CONDITION, + 0, -1, -1, q->irq_ptr->int_parm); +@@ -282,14 +272,13 @@ static int qdio_siga_sync(struct qdio_q + if (!need_siga_sync(q)) + return 0; + ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:"); ++ DBF_DEV_HEX(DBF_INFO, q->irq_ptr, q, sizeof(void *)); + qdio_perf_stat_inc(&perf_stats.siga_sync); + + cc = do_siga_sync(q->irq_ptr->schid, output, input); +- if (cc) { +- QDIO_DBF_TEXT4(0, trace, "sigasync"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); +- QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); +- } ++ if (cc) ++ DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); + return cc; + } + +@@ -330,17 +319,13 @@ static int qdio_siga_output(struct qdio_ + int cc; + u32 busy_bit; + u64 start_time = 0; +- char dbf_text[15]; +- +- QDIO_DBF_TEXT5(0, trace, "sigaout"); +- QDIO_DBF_HEX5(0, trace, &q, sizeof(void *)); + ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); + qdio_perf_stat_inc(&perf_stats.siga_out); + again: + cc = qdio_do_siga_output(q, &busy_bit); + if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) { +- sprintf(dbf_text, "bb%4x%2x", q->irq_ptr->schid.sch_no, q->nr); +- QDIO_DBF_TEXT3(0, trace, dbf_text); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w bb:%2d", q->nr); + + if (!start_time) + start_time = get_usecs(); +@@ -351,7 +336,7 @@ again: + if (cc == 2 && busy_bit) + cc |= QDIO_ERROR_SIGA_BUSY; + if (cc) +- QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); ++ DBF_ERROR("%4x SIGA-W:%2d", SCH_NO(q), cc); + return cc; + } + +@@ -359,14 +344,12 @@ static inline int qdio_siga_input(struct + { + int cc; + +- QDIO_DBF_TEXT4(0, trace, "sigain"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); +- ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); + qdio_perf_stat_inc(&perf_stats.siga_in); + + cc = do_siga_input(q->irq_ptr->schid, q->mask); + if (cc) +- QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); ++ DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); + return cc; + } + +@@ -399,18 +382,12 @@ inline void qdio_stop_polling(struct qdi + + static void announce_buffer_error(struct qdio_q *q) + { +- char dbf_text[15]; +- +- if (q->is_input_q) +- QDIO_DBF_TEXT3(1, trace, "inperr"); +- else +- QDIO_DBF_TEXT3(0, trace, "outperr"); +- +- sprintf(dbf_text, "%x-%x-%x", q->first_to_check, +- q->sbal[q->first_to_check]->element[14].flags, +- q->sbal[q->first_to_check]->element[15].flags); +- QDIO_DBF_TEXT3(1, trace, dbf_text); +- QDIO_DBF_HEX2(1, trace, q->sbal[q->first_to_check], 256); ++ DBF_ERROR("%4x BUF ERROR", SCH_NO(q)); ++ DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr); ++ DBF_ERROR("FTC:%3d", q->first_to_check); ++ DBF_ERROR("F14:%2x F15:%2x", ++ q->sbal[q->first_to_check]->element[14].flags & 0xff, ++ q->sbal[q->first_to_check]->element[15].flags & 0xff); + + q->qdio_error = QDIO_ERROR_SLSB_STATE; + } +@@ -453,7 +430,7 @@ check_next: + + switch (state) { + case SLSB_P_INPUT_PRIMED: +- QDIO_DBF_TEXT5(0, trace, "inptprim"); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); + + /* + * Only ACK the first buffer. The ACK will be removed in +@@ -492,13 +469,12 @@ check_next: + case SLSB_CU_INPUT_EMPTY: + case SLSB_P_INPUT_NOT_INIT: + case SLSB_P_INPUT_ACK: +- QDIO_DBF_TEXT5(0, trace, "inpnipro"); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop"); + break; + default: + BUG(); + } + out: +- QDIO_DBF_HEX4(0, trace, &q->first_to_check, sizeof(int)); + return q->first_to_check; + } + +@@ -512,8 +488,7 @@ int qdio_inbound_q_moved(struct qdio_q * + if (!need_siga_sync(q) && !pci_out_supported(q)) + q->u.in.timestamp = get_usecs(); + +- QDIO_DBF_TEXT4(0, trace, "inhasmvd"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in moved"); + return 1; + } else + return 0; +@@ -522,9 +497,6 @@ int qdio_inbound_q_moved(struct qdio_q * + static int qdio_inbound_q_done(struct qdio_q *q) + { + unsigned char state; +-#ifdef CONFIG_QDIO_DEBUG +- char dbf_text[15]; +-#endif + + if (!atomic_read(&q->nr_buf_used)) + return 1; +@@ -549,20 +521,12 @@ static int qdio_inbound_q_done(struct qd + * has (probably) not moved (see qdio_inbound_processing). + */ + if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { +-#ifdef CONFIG_QDIO_DEBUG +- QDIO_DBF_TEXT4(0, trace, "inqisdon"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); +- sprintf(dbf_text, "pf%02x", q->first_to_check); +- QDIO_DBF_TEXT4(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", ++ q->first_to_check); + return 1; + } else { +-#ifdef CONFIG_QDIO_DEBUG +- QDIO_DBF_TEXT4(0, trace, "inqisntd"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); +- sprintf(dbf_text, "pf%02x", q->first_to_check); +- QDIO_DBF_TEXT4(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in notd:%3d", ++ q->first_to_check); + return 0; + } + } +@@ -570,9 +534,6 @@ static int qdio_inbound_q_done(struct qd + void qdio_kick_inbound_handler(struct qdio_q *q) + { + int count, start, end; +-#ifdef CONFIG_QDIO_DEBUG +- char dbf_text[15]; +-#endif + + qdio_perf_stat_inc(&perf_stats.inbound_handler); + +@@ -583,10 +544,7 @@ void qdio_kick_inbound_handler(struct qd + else + count = end + QDIO_MAX_BUFFERS_PER_Q - start; + +-#ifdef CONFIG_QDIO_DEBUG +- sprintf(dbf_text, "s=%2xc=%2x", start, count); +- QDIO_DBF_TEXT4(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); + + if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) + return; +@@ -659,7 +617,7 @@ check_next: + switch (state) { + case SLSB_P_OUTPUT_EMPTY: + /* the adapter got it */ +- QDIO_DBF_TEXT5(0, trace, "outpempt"); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %3d", q->nr, count); + + atomic_sub(count, &q->nr_buf_used); + q->first_to_check = add_buf(q->first_to_check, count); +@@ -678,7 +636,7 @@ check_next: + break; + case SLSB_CU_OUTPUT_PRIMED: + /* the adapter has not fetched the output yet */ +- QDIO_DBF_TEXT5(0, trace, "outpprim"); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr); + break; + case SLSB_P_OUTPUT_NOT_INIT: + case SLSB_P_OUTPUT_HALTED: +@@ -703,8 +661,7 @@ static inline int qdio_outbound_q_moved( + + if ((bufnr != q->last_move_ftc) || q->qdio_error) { + q->last_move_ftc = bufnr; +- QDIO_DBF_TEXT4(0, trace, "oqhasmvd"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); + return 1; + } else + return 0; +@@ -739,12 +696,8 @@ static inline int qdio_outbound_q_moved( + static void qdio_kick_outbound_q(struct qdio_q *q) + { + int rc; +-#ifdef CONFIG_QDIO_DEBUG +- char dbf_text[15]; + +- QDIO_DBF_TEXT5(0, trace, "kickoutq"); +- QDIO_DBF_HEX5(0, trace, &q, sizeof(void *)); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickoutq:%1d", q->nr); + + if (!need_siga_out(q)) + return; +@@ -753,15 +706,9 @@ static void qdio_kick_outbound_q(struct + switch (rc) { + case 0: + /* TODO: improve error handling for CC=0 case */ +-#ifdef CONFIG_QDIO_DEBUG +- if (q->u.out.timestamp) { +- QDIO_DBF_TEXT3(0, trace, "cc2reslv"); +- sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, +- q->nr, +- atomic_read(&q->u.out.busy_siga_counter)); +- QDIO_DBF_TEXT3(0, trace, dbf_text); +- } +-#endif /* CONFIG_QDIO_DEBUG */ ++ if (q->u.out.timestamp) ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "cc2 rslv:%4x", ++ atomic_read(&q->u.out.busy_siga_counter)); + /* went smooth this time, reset timestamp */ + q->u.out.timestamp = 0; + break; +@@ -778,12 +725,7 @@ static void qdio_kick_outbound_q(struct + tasklet_schedule(&q->tasklet); + break; + } +- QDIO_DBF_TEXT2(0, trace, "cc2REPRT"); +-#ifdef CONFIG_QDIO_DEBUG +- sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, q->nr, +- atomic_read(&q->u.out.busy_siga_counter)); +- QDIO_DBF_TEXT3(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); + default: + /* for plain cc=1, 2 or 3 */ + q->qdio_error = rc; +@@ -793,9 +735,6 @@ static void qdio_kick_outbound_q(struct + static void qdio_kick_outbound_handler(struct qdio_q *q) + { + int start, end, count; +-#ifdef CONFIG_QDIO_DEBUG +- char dbf_text[15]; +-#endif + + start = q->first_to_kick; + end = q->last_move_ftc; +@@ -804,13 +743,8 @@ static void qdio_kick_outbound_handler(s + else + count = end + QDIO_MAX_BUFFERS_PER_Q - start; + +-#ifdef CONFIG_QDIO_DEBUG +- QDIO_DBF_TEXT4(0, trace, "kickouth"); +- QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); +- +- sprintf(dbf_text, "s=%2xc=%2x", start, count); +- QDIO_DBF_TEXT4(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count); + + if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) + return; +@@ -905,27 +839,18 @@ void qdio_check_outbound_after_thinint(s + static inline void qdio_set_state(struct qdio_irq *irq_ptr, + enum qdio_irq_states state) + { +-#ifdef CONFIG_QDIO_DEBUG +- char dbf_text[15]; +- +- QDIO_DBF_TEXT5(0, trace, "newstate"); +- sprintf(dbf_text, "%4x%4x", irq_ptr->schid.sch_no, state); +- QDIO_DBF_TEXT5(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, irq_ptr, "newstate: %1d", state); + + irq_ptr->state = state; + mb(); + } + +-static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) ++static void qdio_irq_check_sense(struct qdio_irq *irq_ptr, struct irb *irb) + { +- char dbf_text[15]; +- + if (irb->esw.esw0.erw.cons) { +- sprintf(dbf_text, "sens%4x", schid.sch_no); +- QDIO_DBF_TEXT2(1, trace, dbf_text); +- QDIO_DBF_HEX0(0, trace, irb, 64); +- QDIO_DBF_HEX0(0, trace, irb->ecw, 64); ++ DBF_ERROR("%4x sense:", irq_ptr->schid.sch_no); ++ DBF_ERROR_HEX(irb, 64); ++ DBF_ERROR_HEX(irb->ecw, 64); + } + } + +@@ -959,14 +884,10 @@ static void qdio_handle_activate_check(s + { + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + struct qdio_q *q; +- char dbf_text[15]; + +- QDIO_DBF_TEXT2(1, trace, "ick2"); +- sprintf(dbf_text, "%s", cdev->dev.bus_id); +- QDIO_DBF_TEXT2(1, trace, dbf_text); +- QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int)); +- QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); +- QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int)); ++ DBF_ERROR("%4x ACT CHECK", irq_ptr->schid.sch_no); ++ DBF_ERROR("intp :%lx", intparm); ++ DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); + + if (irq_ptr->nr_input_qs) { + q = irq_ptr->input_qs[0]; +@@ -1019,28 +940,29 @@ static void qdio_int_error(struct ccw_de + } + + static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat, +- int dstat) ++ int dstat) + { + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + + if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { +- QDIO_DBF_TEXT2(1, setup, "eq:ckcon"); ++ DBF_ERROR("EQ:ck con"); + goto error; + } + + if (!(dstat & DEV_STAT_DEV_END)) { +- QDIO_DBF_TEXT2(1, setup, "eq:no de"); ++ DBF_ERROR("EQ:no dev"); + goto error; + } + + if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { +- QDIO_DBF_TEXT2(1, setup, "eq:badio"); ++ DBF_ERROR("EQ: bad io"); + goto error; + } + return 0; + error: +- QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int)); +- QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); ++ DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); ++ DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); ++ + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); + return 1; + } +@@ -1049,12 +971,8 @@ static void qdio_establish_handle_irq(st + int dstat) + { + struct qdio_irq *irq_ptr = cdev->private->qdio_data; +- char dbf_text[15]; +- +- sprintf(dbf_text, "qehi%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- QDIO_DBF_TEXT0(0, trace, dbf_text); + ++ DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq"); + if (!qdio_establish_check_errors(cdev, cstat, dstat)) + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); + } +@@ -1065,25 +983,21 @@ void qdio_int_handler(struct ccw_device + { + struct qdio_irq *irq_ptr = cdev->private->qdio_data; + int cstat, dstat; +- char dbf_text[15]; + + qdio_perf_stat_inc(&perf_stats.qdio_int); + + if (!intparm || !irq_ptr) { +- sprintf(dbf_text, "qihd%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT2(1, setup, dbf_text); ++ DBF_ERROR("qint:%4x", cdev->private->schid.sch_no); + return; + } + + if (IS_ERR(irb)) { + switch (PTR_ERR(irb)) { + case -EIO: +- sprintf(dbf_text, "ierr%4x", irq_ptr->schid.sch_no); +- QDIO_DBF_TEXT2(1, setup, dbf_text); ++ DBF_ERROR("%4x IO error", irq_ptr->schid.sch_no); + return; + case -ETIMEDOUT: +- sprintf(dbf_text, "qtoh%4x", irq_ptr->schid.sch_no); +- QDIO_DBF_TEXT2(1, setup, dbf_text); ++ DBF_ERROR("%4x IO timeout", irq_ptr->schid.sch_no); + qdio_int_error(cdev); + return; + default: +@@ -1091,7 +1005,7 @@ void qdio_int_handler(struct ccw_device + return; + } + } +- qdio_irq_check_sense(irq_ptr->schid, irb); ++ qdio_irq_check_sense(irq_ptr, irb); + + cstat = irb->scsw.cmd.cstat; + dstat = irb->scsw.cmd.dstat; +@@ -1134,14 +1048,11 @@ void qdio_int_handler(struct ccw_device + int qdio_get_ssqd_desc(struct ccw_device *cdev, + struct qdio_ssqd_desc *data) + { +- char dbf_text[15]; + + if (!cdev || !cdev->private) + return -EINVAL; + +- sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- ++ DBF_EVENT("get ssqd:%4x", cdev->private->schid.sch_no); + return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); + } + EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); +@@ -1156,14 +1067,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); + */ + int qdio_cleanup(struct ccw_device *cdev, int how) + { +- struct qdio_irq *irq_ptr; +- char dbf_text[15]; ++ struct qdio_irq *irq_ptr = cdev->private->qdio_data; + int rc; + +- sprintf(dbf_text, "qcln%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- +- irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) + return -ENODEV; + +@@ -1196,18 +1102,15 @@ static void qdio_shutdown_queues(struct + */ + int qdio_shutdown(struct ccw_device *cdev, int how) + { +- struct qdio_irq *irq_ptr; ++ struct qdio_irq *irq_ptr = cdev->private->qdio_data; + int rc; + unsigned long flags; +- char dbf_text[15]; +- +- sprintf(dbf_text, "qshu%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); + +- irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) + return -ENODEV; + ++ DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); ++ + mutex_lock(&irq_ptr->setup_mutex); + /* + * Subchannel was already shot down. We cannot prevent being called +@@ -1231,10 +1134,8 @@ int qdio_shutdown(struct ccw_device *cde + /* default behaviour is halt */ + rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); + if (rc) { +- sprintf(dbf_text, "sher%4x", irq_ptr->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- sprintf(dbf_text, "rc=%d", rc); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_ERROR("%4x SHUTD ERR", irq_ptr->schid.sch_no); ++ DBF_ERROR("rc:%4d", rc); + goto no_cleanup; + } + +@@ -1268,17 +1169,18 @@ EXPORT_SYMBOL_GPL(qdio_shutdown); + */ + int qdio_free(struct ccw_device *cdev) + { +- struct qdio_irq *irq_ptr; +- char dbf_text[15]; +- +- sprintf(dbf_text, "qfre%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ struct qdio_irq *irq_ptr = cdev->private->qdio_data; + +- irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) + return -ENODEV; + ++ DBF_EVENT("qfree:%4x", cdev->private->schid.sch_no); + mutex_lock(&irq_ptr->setup_mutex); ++ ++ if (irq_ptr->debug_area != NULL) { ++ debug_unregister(irq_ptr->debug_area); ++ irq_ptr->debug_area = NULL; ++ } + cdev->private->qdio_data = NULL; + mutex_unlock(&irq_ptr->setup_mutex); + +@@ -1297,10 +1199,6 @@ EXPORT_SYMBOL_GPL(qdio_free); + int qdio_initialize(struct qdio_initialize *init_data) + { + int rc; +- char dbf_text[15]; +- +- sprintf(dbf_text, "qini%4x", init_data->cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); + + rc = qdio_allocate(init_data); + if (rc) +@@ -1320,10 +1218,8 @@ EXPORT_SYMBOL_GPL(qdio_initialize); + int qdio_allocate(struct qdio_initialize *init_data) + { + struct qdio_irq *irq_ptr; +- char dbf_text[15]; + +- sprintf(dbf_text, "qalc%4x", init_data->cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("qallocate:%4x", init_data->cdev->private->schid.sch_no); + + if ((init_data->no_input_qs && !init_data->input_handler) || + (init_data->no_output_qs && !init_data->output_handler)) +@@ -1337,16 +1233,13 @@ int qdio_allocate(struct qdio_initialize + (!init_data->output_sbal_addr_array)) + return -EINVAL; + +- qdio_allocate_do_dbf(init_data); +- + /* irq_ptr must be in GFP_DMA since it contains ccw1.cda */ + irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!irq_ptr) + goto out_err; +- QDIO_DBF_TEXT0(0, setup, "irq_ptr:"); +- QDIO_DBF_HEX0(0, setup, &irq_ptr, sizeof(void *)); + + mutex_init(&irq_ptr->setup_mutex); ++ qdio_allocate_dbf(init_data, irq_ptr); + + /* + * Allocate a page for the chsc calls in qdio_establish. +@@ -1364,9 +1257,6 @@ int qdio_allocate(struct qdio_initialize + goto out_rel; + WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); + +- QDIO_DBF_TEXT0(0, setup, "qdr:"); +- QDIO_DBF_HEX0(0, setup, &irq_ptr->qdr, sizeof(void *)); +- + if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs, + init_data->no_output_qs)) + goto out_rel; +@@ -1387,14 +1277,12 @@ EXPORT_SYMBOL_GPL(qdio_allocate); + */ + int qdio_establish(struct qdio_initialize *init_data) + { +- char dbf_text[20]; + struct qdio_irq *irq_ptr; + struct ccw_device *cdev = init_data->cdev; + unsigned long saveflags; + int rc; + +- sprintf(dbf_text, "qest%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("qestablish:%4x", cdev->private->schid.sch_no); + + irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) +@@ -1424,10 +1312,8 @@ int qdio_establish(struct qdio_initializ + + rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0); + if (rc) { +- sprintf(dbf_text, "eq:io%4x", irq_ptr->schid.sch_no); +- QDIO_DBF_TEXT2(1, setup, dbf_text); +- sprintf(dbf_text, "eq:rc%4x", rc); +- QDIO_DBF_TEXT2(1, setup, dbf_text); ++ DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no); ++ DBF_ERROR("rc:%4x", rc); + } + spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); + +@@ -1448,8 +1334,7 @@ int qdio_establish(struct qdio_initializ + } + + qdio_setup_ssqd_info(irq_ptr); +- sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac); +- QDIO_DBF_TEXT2(0, setup, dbf_text); ++ DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac); + + /* qebsm is now setup if available, initialize buffer states */ + qdio_init_buf_states(irq_ptr); +@@ -1470,10 +1355,8 @@ int qdio_activate(struct ccw_device *cde + struct qdio_irq *irq_ptr; + int rc; + unsigned long saveflags; +- char dbf_text[20]; + +- sprintf(dbf_text, "qact%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("qactivate:%4x", cdev->private->schid.sch_no); + + irq_ptr = cdev->private->qdio_data; + if (!irq_ptr) +@@ -1499,10 +1382,8 @@ int qdio_activate(struct ccw_device *cde + rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ACTIVATE, + 0, DOIO_DENY_PREFETCH); + if (rc) { +- sprintf(dbf_text, "aq:io%4x", irq_ptr->schid.sch_no); +- QDIO_DBF_TEXT2(1, setup, dbf_text); +- sprintf(dbf_text, "aq:rc%4x", rc); +- QDIO_DBF_TEXT2(1, setup, dbf_text); ++ DBF_ERROR("%4x act IO ERR", irq_ptr->schid.sch_no); ++ DBF_ERROR("rc:%4x", rc); + } + spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); + +@@ -1639,7 +1520,7 @@ static void handle_outbound(struct qdio_ + if (state != SLSB_CU_OUTPUT_PRIMED) + qdio_kick_outbound_q(q); + else { +- QDIO_DBF_TEXT5(0, trace, "fast-req"); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); + qdio_perf_stat_inc(&perf_stats.fast_requeue); + } + out: +@@ -1659,12 +1540,6 @@ int do_QDIO(struct ccw_device *cdev, uns + int q_nr, int bufnr, int count) + { + struct qdio_irq *irq_ptr; +-#ifdef CONFIG_QDIO_DEBUG +- char dbf_text[20]; +- +- sprintf(dbf_text, "doQD%4x", cdev->private->schid.sch_no); +- QDIO_DBF_TEXT3(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ + + if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || + (count > QDIO_MAX_BUFFERS_PER_Q) || +@@ -1678,33 +1553,24 @@ int do_QDIO(struct ccw_device *cdev, uns + if (!irq_ptr) + return -ENODEV; + +-#ifdef CONFIG_QDIO_DEBUG + if (callflags & QDIO_FLAG_SYNC_INPUT) +- QDIO_DBF_HEX3(0, trace, &irq_ptr->input_qs[q_nr], +- sizeof(void *)); ++ DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO input"); + else +- QDIO_DBF_HEX3(0, trace, &irq_ptr->output_qs[q_nr], +- sizeof(void *)); +- +- sprintf(dbf_text, "flag%04x", callflags); +- QDIO_DBF_TEXT3(0, trace, dbf_text); +- sprintf(dbf_text, "qi%02xct%02x", bufnr, count); +- QDIO_DBF_TEXT3(0, trace, dbf_text); +-#endif /* CONFIG_QDIO_DEBUG */ ++ DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO output"); ++ DBF_DEV_EVENT(DBF_INFO, irq_ptr, "q:%1d flag:%4x", q_nr, callflags); ++ DBF_DEV_EVENT(DBF_INFO, irq_ptr, "buf:%2d cnt:%3d", bufnr, count); + + if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) + return -EBUSY; + + if (callflags & QDIO_FLAG_SYNC_INPUT) +- handle_inbound(irq_ptr->input_qs[q_nr], +- callflags, bufnr, count); ++ handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, ++ count); + else if (callflags & QDIO_FLAG_SYNC_OUTPUT) +- handle_outbound(irq_ptr->output_qs[q_nr], +- callflags, bufnr, count); +- else { +- QDIO_DBF_TEXT3(1, trace, "doQD:inv"); ++ handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, ++ count); ++ else + return -EINVAL; +- } + return 0; + } + EXPORT_SYMBOL_GPL(do_QDIO); +--- a/drivers/s390/cio/qdio_setup.c ++++ b/drivers/s390/cio/qdio_setup.c +@@ -120,14 +120,12 @@ static void setup_queues_misc(struct qdi + } + + static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, +- void **sbals_array, char *dbf_text, int i) ++ void **sbals_array, int i) + { + struct qdio_q *prev; + int j; + +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- QDIO_DBF_HEX0(0, setup, &q, sizeof(void *)); +- ++ DBF_HEX(&q, sizeof(void *)); + q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); + + /* fill in sbal */ +@@ -150,31 +148,27 @@ static void setup_storage_lists(struct q + for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) + q->sl->element[j].sbal = (unsigned long)q->sbal[j]; + +- QDIO_DBF_TEXT2(0, setup, "sl-sb-b0"); +- QDIO_DBF_HEX2(0, setup, q->sl, sizeof(void *)); +- QDIO_DBF_HEX2(0, setup, &q->slsb, sizeof(void *)); +- QDIO_DBF_HEX2(0, setup, q->sbal, sizeof(void *)); ++ DBF_EVENT("sl-slsb-sbal"); ++ DBF_HEX(q->sl, sizeof(void *)); ++ DBF_HEX(&q->slsb, sizeof(void *)); ++ DBF_HEX(q->sbal, sizeof(void *)); + } + + static void setup_queues(struct qdio_irq *irq_ptr, + struct qdio_initialize *qdio_init) + { +- char dbf_text[20]; + struct qdio_q *q; + void **input_sbal_array = qdio_init->input_sbal_addr_array; + void **output_sbal_array = qdio_init->output_sbal_addr_array; + int i; + +- sprintf(dbf_text, "qset%4x", qdio_init->cdev->private->schid.sch_no); +- QDIO_DBF_TEXT0(0, setup, dbf_text); +- + for_each_input_queue(irq_ptr, q, i) { +- sprintf(dbf_text, "in-q%4x", i); ++ DBF_EVENT("in-q:%1d", i); + setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); + + q->is_input_q = 1; + spin_lock_init(&q->u.in.lock); +- setup_storage_lists(q, irq_ptr, input_sbal_array, dbf_text, i); ++ setup_storage_lists(q, irq_ptr, input_sbal_array, i); + input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; + + if (is_thinint_irq(irq_ptr)) +@@ -186,12 +180,11 @@ static void setup_queues(struct qdio_irq + } + + for_each_output_queue(irq_ptr, q, i) { +- sprintf(dbf_text, "outq%4x", i); ++ DBF_EVENT("outq:%1d", i); + setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); + + q->is_input_q = 0; +- setup_storage_lists(q, irq_ptr, output_sbal_array, +- dbf_text, i); ++ setup_storage_lists(q, irq_ptr, output_sbal_array, i); + output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; + + tasklet_init(&q->tasklet, qdio_outbound_processing, +@@ -222,8 +215,6 @@ static void process_ac_flags(struct qdio + static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, + unsigned char qdioac, unsigned long token) + { +- char dbf_text[15]; +- + if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM)) + goto no_qebsm; + if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) || +@@ -232,15 +223,14 @@ static void check_and_setup_qebsm(struct + + irq_ptr->sch_token = token; + +- QDIO_DBF_TEXT0(0, setup, "V=V:1"); +- sprintf(dbf_text, "%8lx", irq_ptr->sch_token); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("V=V:1"); ++ DBF_EVENT("%8lx", irq_ptr->sch_token); + return; + + no_qebsm: + irq_ptr->sch_token = 0; + irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; +- QDIO_DBF_TEXT0(0, setup, "noV=V"); ++ DBF_EVENT("noV=V"); + } + + /* +@@ -254,7 +244,7 @@ int qdio_setup_get_ssqd(struct qdio_irq + struct chsc_ssqd_area *ssqd; + int rc; + +- QDIO_DBF_TEXT0(0, setup, "getssqd"); ++ DBF_EVENT("getssqd:%4x", schid->sch_no); + if (irq_ptr != NULL) + ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; + else +@@ -294,16 +284,12 @@ int qdio_setup_get_ssqd(struct qdio_irq + void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) + { + unsigned char qdioac; +- char dbf_text[15]; + int rc; + + rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); + if (rc) { +- QDIO_DBF_TEXT2(0, setup, "ssqdasig"); +- sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); +- QDIO_DBF_TEXT2(0, setup, dbf_text); +- sprintf(dbf_text, "rc:%d", rc); +- QDIO_DBF_TEXT2(0, setup, dbf_text); ++ DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); ++ DBF_ERROR("rc:%x", rc); + /* all flags set, worst case */ + qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED | + AC1_SIGA_SYNC_NEEDED; +@@ -312,9 +298,7 @@ void qdio_setup_ssqd_info(struct qdio_ir + + check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); + process_ac_flags(irq_ptr, qdioac); +- +- sprintf(dbf_text, "qdioac%2x", qdioac); +- QDIO_DBF_TEXT2(0, setup, dbf_text); ++ DBF_EVENT("qdioac:%4x", qdioac); + } + + void qdio_release_memory(struct qdio_irq *irq_ptr) +@@ -434,7 +418,7 @@ int qdio_setup_irq(struct qdio_initializ + /* get qdio commands */ + ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); + if (!ciw) { +- QDIO_DBF_TEXT2(1, setup, "no eq"); ++ DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); + rc = -EINVAL; + goto out_err; + } +@@ -442,7 +426,7 @@ int qdio_setup_irq(struct qdio_initializ + + ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); + if (!ciw) { +- QDIO_DBF_TEXT2(1, setup, "no aq"); ++ DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); + rc = -EINVAL; + goto out_err; + } +@@ -462,56 +446,38 @@ void qdio_print_subchannel_info(struct q + { + char s[80]; + +- sprintf(s, "qdio: %s ", dev_name(&cdev->dev)); +- switch (irq_ptr->qib.qfmt) { +- case QDIO_QETH_QFMT: +- sprintf(s + strlen(s), "OSA "); +- break; +- case QDIO_ZFCP_QFMT: +- sprintf(s + strlen(s), "ZFCP "); +- break; +- case QDIO_IQDIO_QFMT: +- sprintf(s + strlen(s), "HS "); +- break; +- } +- sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no); +- sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr)); +- sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0); +- sprintf(s + strlen(s), "PCI:%d ", +- (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0); +- sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd); +- sprintf(s + strlen(s), "SIGA:"); +- sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " "); +- sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " "); +- sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " "); +- sprintf(s + strlen(s), "%s", +- (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " "); +- sprintf(s + strlen(s), "%s", +- (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " "); +- sprintf(s + strlen(s), "%s", +- (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); +- sprintf(s + strlen(s), "\n"); ++ snprintf(s, 80, "qdio: %s %s on SC %x using " ++ "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n", ++ dev_name(&cdev->dev), ++ (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : ++ ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), ++ irq_ptr->schid.sch_no, ++ is_thinint_irq(irq_ptr), ++ (irq_ptr->sch_token) ? 1 : 0, ++ (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0, ++ css_general_characteristics.aif_tdd, ++ (irq_ptr->siga_flag.input) ? "R" : " ", ++ (irq_ptr->siga_flag.output) ? "W" : " ", ++ (irq_ptr->siga_flag.sync) ? "S" : " ", ++ (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ", ++ (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ", ++ (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); + printk(KERN_INFO "%s", s); + } + + int __init qdio_setup_init(void) + { +- char dbf_text[15]; +- + qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), + 256, 0, NULL); + if (!qdio_q_cache) + return -ENOMEM; + + /* Check for OSA/FCP thin interrupts (bit 67). */ +- sprintf(dbf_text, "thini%1x", +- (css_general_characteristics.aif_osa) ? 1 : 0); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("thinint:%1d", ++ (css_general_characteristics.aif_osa) ? 1 : 0); + + /* Check for QEBSM support in general (bit 58). */ +- sprintf(dbf_text, "cssQBS:%1x", +- (qebsm_possible()) ? 1 : 0); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); + return 0; + } + +--- a/drivers/s390/cio/qdio_thinint.c ++++ b/drivers/s390/cio/qdio_thinint.c +@@ -258,8 +258,6 @@ static void tiqdio_thinint_handler(void + static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) + { + struct scssc_area *scssc_area; +- char dbf_text[15]; +- void *ptr; + int rc; + + scssc_area = (struct scssc_area *)irq_ptr->chsc_page; +@@ -294,19 +292,15 @@ static int set_subchannel_ind(struct qdi + + rc = chsc_error_from_response(scssc_area->response.code); + if (rc) { +- sprintf(dbf_text, "sidR%4x", scssc_area->response.code); +- QDIO_DBF_TEXT1(0, trace, dbf_text); +- QDIO_DBF_TEXT1(0, setup, dbf_text); +- ptr = &scssc_area->response; +- QDIO_DBF_HEX2(1, setup, &ptr, QDIO_DBF_SETUP_LEN); ++ DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, ++ scssc_area->response.code); ++ DBF_ERROR_HEX(&scssc_area->response, sizeof(void *)); + return rc; + } + +- QDIO_DBF_TEXT2(0, setup, "setscind"); +- QDIO_DBF_HEX2(0, setup, &scssc_area->summary_indicator_addr, +- sizeof(unsigned long)); +- QDIO_DBF_HEX2(0, setup, &scssc_area->subchannel_indicator_addr, +- sizeof(unsigned long)); ++ DBF_EVENT("setscind"); ++ DBF_HEX(&scssc_area->summary_indicator_addr, sizeof(unsigned long)); ++ DBF_HEX(&scssc_area->subchannel_indicator_addr, sizeof(unsigned long)); + return 0; + } + +@@ -327,14 +321,11 @@ void tiqdio_free_memory(void) + + int __init tiqdio_register_thinints(void) + { +- char dbf_text[20]; +- + isc_register(QDIO_AIRQ_ISC); + tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler, + NULL, QDIO_AIRQ_ISC); + if (IS_ERR(tiqdio_alsi)) { +- sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_alsi)); +- QDIO_DBF_TEXT0(0, setup, dbf_text); ++ DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi)); + tiqdio_alsi = NULL; + isc_unregister(QDIO_AIRQ_ISC); + return -ENOMEM; +@@ -360,7 +351,7 @@ void qdio_setup_thinint(struct qdio_irq + if (!is_thinint_irq(irq_ptr)) + return; + irq_ptr->dsci = get_indicator(); +- QDIO_DBF_HEX1(0, setup, &irq_ptr->dsci, sizeof(void *)); ++ DBF_HEX(&irq_ptr->dsci, sizeof(void *)); + } + + void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-06-qdio_inbound_ack.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-06-qdio_inbound_ack.patch new file mode 100644 index 000000000..3d7f682cf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-06-qdio_inbound_ack.patch @@ -0,0 +1,499 @@ +From: Gerald Schaefer +Subject: qdio: rework inbound buffer acknowledgement +References: bnc#458339 + +Symptom: Inbound network traffic stall. +Problem: Under high load the qdio buffer that specifies the acknowledge + mode can be overwritten. +Solution: Use automatic acknowledgement of incoming buffers in QEBSM mode + to improve performance with QIOASSIST. + Move ACK for non-QEBSM mode always to the newest buffer to prevent + a race with qdio_stop_polling. + Remove the polling spinlock, the upper layer drivers return new + buffers in the same code path and could not run in parallel. + Don't flood the error log in case of no-target-buffer-empty. + In handle_inbound we check if we would overwrite an ACK'ed buffer, + if so advance the pointer to the oldest ACK'ed buffer so we don't + overwrite an empty buffer in qdio_stop_polling. + +Acked-by: John Jolly + +--- + drivers/s390/cio/qdio.h | 19 ++-- + drivers/s390/cio/qdio_debug.c | 7 + + drivers/s390/cio/qdio_main.c | 181 ++++++++++++++++++++++++++-------------- + drivers/s390/cio/qdio_perf.c | 2 + drivers/s390/cio/qdio_perf.h | 1 + drivers/s390/cio/qdio_setup.c | 1 + drivers/s390/cio/qdio_thinint.c | 2 + 7 files changed, 139 insertions(+), 74 deletions(-) + +Index: linux-sles11/drivers/s390/cio/qdio.h +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio.h ++++ linux-sles11/drivers/s390/cio/qdio.h +@@ -112,12 +112,12 @@ static inline int do_sqbs(u64 token, uns + } + + static inline int do_eqbs(u64 token, unsigned char *state, int queue, +- int *start, int *count) ++ int *start, int *count, int ack) + { + register unsigned long _ccq asm ("0") = *count; + register unsigned long _token asm ("1") = token; + unsigned long _queuestart = ((unsigned long)queue << 32) | *start; +- unsigned long _state = 0; ++ unsigned long _state = (unsigned long)ack << 63; + + asm volatile( + " .insn rrf,0xB99c0000,%1,%2,0,0" +@@ -134,7 +134,7 @@ static inline int do_eqbs(u64 token, uns + static inline int do_sqbs(u64 token, unsigned char state, int queue, + int *start, int *count) { return 0; } + static inline int do_eqbs(u64 token, unsigned char *state, int queue, +- int *start, int *count) { return 0; } ++ int *start, int *count, int ack) { return 0; } + #endif /* CONFIG_64BIT */ + + struct qdio_irq; +@@ -187,11 +187,11 @@ struct qdio_input_q { + /* input buffer acknowledgement flag */ + int polling; + ++ /* how much sbals are acknowledged with qebsm */ ++ int ack_count; ++ + /* last time of noticing incoming data */ + u64 timestamp; +- +- /* lock for clearing the acknowledgement */ +- spinlock_t lock; + }; + + struct qdio_output_q { +@@ -348,10 +348,13 @@ static inline unsigned long long get_use + ((bufnr + 1) & QDIO_MAX_BUFFERS_MASK) + #define add_buf(bufnr, inc) \ + ((bufnr + inc) & QDIO_MAX_BUFFERS_MASK) ++#define sub_buf(bufnr, dec) \ ++ ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK) + + /* prototypes for thin interrupt */ + void qdio_sync_after_thinint(struct qdio_q *q); +-int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state); ++int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state, ++ int auto_ack); + void qdio_check_outbound_after_thinint(struct qdio_q *q); + int qdio_inbound_q_moved(struct qdio_q *q); + void qdio_kick_inbound_handler(struct qdio_q *q); +@@ -385,6 +388,8 @@ int qdio_setup_irq(struct qdio_initializ + void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, + struct ccw_device *cdev); + void qdio_release_memory(struct qdio_irq *irq_ptr); ++int qdio_setup_create_sysfs(struct ccw_device *cdev); ++void qdio_setup_destroy_sysfs(struct ccw_device *cdev); + int qdio_setup_init(void); + void qdio_setup_exit(void); + +Index: linux-sles11/drivers/s390/cio/qdio_debug.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_debug.c ++++ linux-sles11/drivers/s390/cio/qdio_debug.c +@@ -59,16 +59,18 @@ static int qstat_show(struct seq_file *m + if (!q) + return 0; + +- seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci); ++ seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci); + seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); + seq_printf(m, "ftc: %d\n", q->first_to_check); + seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); + seq_printf(m, "polling: %d\n", q->u.in.polling); ++ seq_printf(m, "ack count: %d\n", q->u.in.ack_count); + seq_printf(m, "slsb buffer states:\n"); ++ seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); + + qdio_siga_sync_q(q); + for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { +- get_buf_state(q, i, &state); ++ get_buf_state(q, i, &state, 0); + switch (state) { + case SLSB_P_INPUT_NOT_INIT: + case SLSB_P_OUTPUT_NOT_INIT: +@@ -100,6 +102,7 @@ static int qstat_show(struct seq_file *m + seq_printf(m, "\n"); + } + seq_printf(m, "\n"); ++ seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); + return 0; + } + +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -112,12 +112,13 @@ static inline int qdio_check_ccq(struct + * @state: state of the extracted buffers + * @start: buffer number to start at + * @count: count of buffers to examine ++ * @auto_ack: automatically acknowledge buffers + * + * Returns the number of successfull extracted equal buffer states. + * Stops processing if a state is different from the last buffers state. + */ + static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, +- int start, int count) ++ int start, int count, int auto_ack) + { + unsigned int ccq = 0; + int tmp_count = count, tmp_start = start; +@@ -129,7 +130,8 @@ static int qdio_do_eqbs(struct qdio_q *q + if (!q->is_input_q) + nr += q->irq_ptr->nr_input_qs; + again: +- ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); ++ ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, ++ auto_ack); + rc = qdio_check_ccq(q, ccq); + + /* At least one buffer was processed, return and extract the remaining +@@ -172,6 +174,9 @@ static int qdio_do_sqbs(struct qdio_q *q + int nr = q->nr; + int rc; + ++ if (!count) ++ return 0; ++ + BUG_ON(!q->irq_ptr->sch_token); + + if (!q->is_input_q) +@@ -197,7 +202,8 @@ again: + + /* returns number of examined buffers and their common state in *state */ + static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, +- unsigned char *state, unsigned int count) ++ unsigned char *state, unsigned int count, ++ int auto_ack) + { + unsigned char __state = 0; + int i; +@@ -206,7 +212,7 @@ static inline int get_buf_states(struct + BUG_ON(count > QDIO_MAX_BUFFERS_PER_Q); + + if (is_qebsm(q)) +- return qdio_do_eqbs(q, state, bufnr, count); ++ return qdio_do_eqbs(q, state, bufnr, count, auto_ack); + + for (i = 0; i < count; i++) { + if (!__state) +@@ -220,9 +226,9 @@ static inline int get_buf_states(struct + } + + inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, +- unsigned char *state) ++ unsigned char *state, int auto_ack) + { +- return get_buf_states(q, bufnr, state, 1); ++ return get_buf_states(q, bufnr, state, 1, auto_ack); + } + + /* wrap-around safe setting of slsb states, returns number of changed buffers */ +@@ -367,29 +373,91 @@ void qdio_sync_after_thinint(struct qdio + + inline void qdio_stop_polling(struct qdio_q *q) + { +- spin_lock_bh(&q->u.in.lock); +- if (!q->u.in.polling) { +- spin_unlock_bh(&q->u.in.lock); ++ if (!q->u.in.polling) + return; +- } ++ + q->u.in.polling = 0; + qdio_perf_stat_inc(&perf_stats.debug_stop_polling); + + /* show the card that we are not polling anymore */ +- set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); +- spin_unlock_bh(&q->u.in.lock); ++ if (is_qebsm(q)) { ++ set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, ++ q->u.in.ack_count); ++ q->u.in.ack_count = 0; ++ } else ++ set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); + } + +-static void announce_buffer_error(struct qdio_q *q) ++static void announce_buffer_error(struct qdio_q *q, int count) + { ++ q->qdio_error = QDIO_ERROR_SLSB_STATE; ++ ++ /* special handling for no target buffer empty */ ++ if ((!q->is_input_q && ++ (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { ++ qdio_perf_stat_inc(&perf_stats.outbound_target_full); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d", ++ q->first_to_check); ++ return; ++ } ++ + DBF_ERROR("%4x BUF ERROR", SCH_NO(q)); + DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr); +- DBF_ERROR("FTC:%3d", q->first_to_check); ++ DBF_ERROR("FTC:%3d C:%3d", q->first_to_check, count); + DBF_ERROR("F14:%2x F15:%2x", + q->sbal[q->first_to_check]->element[14].flags & 0xff, + q->sbal[q->first_to_check]->element[15].flags & 0xff); ++} + +- q->qdio_error = QDIO_ERROR_SLSB_STATE; ++static inline void inbound_primed(struct qdio_q *q, int count) ++{ ++ int new; ++ ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); ++ ++ /* for QEBSM the ACK was already set by EQBS */ ++ if (is_qebsm(q)) { ++ if (!q->u.in.polling) { ++ q->u.in.polling = 1; ++ q->u.in.ack_count = count; ++ q->last_move_ftc = q->first_to_check; ++ return; ++ } ++ ++ /* delete the previous ACK's */ ++ set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, ++ q->u.in.ack_count); ++ q->u.in.ack_count = count; ++ q->last_move_ftc = q->first_to_check; ++ return; ++ } ++ ++ /* ++ * ACK the newest buffer. The ACK will be removed in qdio_stop_polling ++ * or by the next inbound run. ++ */ ++ new = add_buf(q->first_to_check, count - 1); ++ if (q->u.in.polling) { ++ /* reset the previous ACK but first set the new one */ ++ set_buf_state(q, new, SLSB_P_INPUT_ACK); ++ set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); ++ } ++ else { ++ q->u.in.polling = 1; ++ set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); ++ } ++ ++ q->last_move_ftc = new; ++ count--; ++ if (!count) ++ return; ++ ++ /* ++ * Need to change all PRIMED buffers to NOT_INIT, otherwise ++ * we're loosing initiative in the thinint code. ++ */ ++ set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT, ++ count); + } + + static int get_inbound_buffer_frontier(struct qdio_q *q) +@@ -398,13 +466,6 @@ static int get_inbound_buffer_frontier(s + unsigned char state; + + /* +- * If we still poll don't update last_move_ftc, keep the +- * previously ACK buffer there. +- */ +- if (!q->u.in.polling) +- q->last_move_ftc = q->first_to_check; +- +- /* + * Don't check 128 buffers, as otherwise qdio_inbound_q_moved + * would return 0. + */ +@@ -424,34 +485,13 @@ check_next: + if (q->first_to_check == stop) + goto out; + +- count = get_buf_states(q, q->first_to_check, &state, count); ++ count = get_buf_states(q, q->first_to_check, &state, count, 1); + if (!count) + goto out; + + switch (state) { + case SLSB_P_INPUT_PRIMED: +- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); +- +- /* +- * Only ACK the first buffer. The ACK will be removed in +- * qdio_stop_polling. +- */ +- if (q->u.in.polling) +- state = SLSB_P_INPUT_NOT_INIT; +- else { +- q->u.in.polling = 1; +- state = SLSB_P_INPUT_ACK; +- } +- set_buf_state(q, q->first_to_check, state); +- +- /* +- * Need to change all PRIMED buffers to NOT_INIT, otherwise +- * we're loosing initiative in the thinint code. +- */ +- if (count > 1) +- set_buf_states(q, next_buf(q->first_to_check), +- SLSB_P_INPUT_NOT_INIT, count - 1); +- ++ inbound_primed(q, count); + /* + * No siga-sync needed for non-qebsm here, as the inbound queue + * will be synced on the next siga-r, resp. +@@ -461,7 +501,7 @@ check_next: + atomic_sub(count, &q->nr_buf_used); + goto check_next; + case SLSB_P_INPUT_ERROR: +- announce_buffer_error(q); ++ announce_buffer_error(q, count); + /* process the buffer, the upper layer will take care of it */ + q->first_to_check = add_buf(q->first_to_check, count); + atomic_sub(count, &q->nr_buf_used); +@@ -507,7 +547,7 @@ static int qdio_inbound_q_done(struct qd + */ + qdio_siga_sync_q(q); + +- get_buf_state(q, q->first_to_check, &state); ++ get_buf_state(q, q->first_to_check, &state, 0); + if (state == SLSB_P_INPUT_PRIMED) + /* we got something to do */ + return 0; +@@ -610,7 +650,7 @@ check_next: + if (q->first_to_check == stop) + return q->first_to_check; + +- count = get_buf_states(q, q->first_to_check, &state, count); ++ count = get_buf_states(q, q->first_to_check, &state, count, 0); + if (!count) + return q->first_to_check; + +@@ -629,7 +669,7 @@ check_next: + break; + goto check_next; + case SLSB_P_OUTPUT_ERROR: +- announce_buffer_error(q); ++ announce_buffer_error(q, count); + /* process the buffer, the upper layer will take care of it */ + q->first_to_check = add_buf(q->first_to_check, count); + atomic_sub(count, &q->nr_buf_used); +@@ -1441,23 +1481,38 @@ static inline int buf_in_between(int buf + static void handle_inbound(struct qdio_q *q, unsigned int callflags, + int bufnr, int count) + { +- unsigned long flags; +- int used, rc; ++ int used, rc, diff; + +- /* +- * do_QDIO could run in parallel with the queue tasklet so the +- * upper-layer programm could empty the ACK'ed buffer here. +- * If that happens we must clear the polling flag, otherwise +- * qdio_stop_polling() could set the buffer to NOT_INIT after +- * it was set to EMPTY which would kill us. +- */ +- spin_lock_irqsave(&q->u.in.lock, flags); +- if (q->u.in.polling) +- if (buf_in_between(q->last_move_ftc, bufnr, count)) ++ if (!q->u.in.polling) ++ goto set; ++ ++ /* protect against stop polling setting an ACK for an emptied slsb */ ++ if (count == QDIO_MAX_BUFFERS_PER_Q) { ++ /* overwriting everything, just delete polling status */ ++ q->u.in.polling = 0; ++ q->u.in.ack_count = 0; ++ goto set; ++ } else if (buf_in_between(q->last_move_ftc, bufnr, count)) { ++ if (is_qebsm(q)) { ++ /* partial overwrite, just update last_move_ftc */ ++ diff = add_buf(bufnr, count); ++ diff = sub_buf(diff, q->last_move_ftc); ++ q->u.in.ack_count -= diff; ++ if (q->u.in.ack_count <= 0) { ++ q->u.in.polling = 0; ++ q->u.in.ack_count = 0; ++ /* TODO: must we set last_move_ftc to something meaningful? */ ++ goto set; ++ } ++ q->last_move_ftc = add_buf(q->last_move_ftc, diff); ++ } ++ else ++ /* the only ACK will be deleted, so stop polling */ + q->u.in.polling = 0; ++ } + ++set: + count = set_buf_states(q, bufnr, SLSB_CU_INPUT_EMPTY, count); +- spin_unlock_irqrestore(&q->u.in.lock, flags); + + used = atomic_add_return(count, &q->nr_buf_used) - count; + BUG_ON(used + count > QDIO_MAX_BUFFERS_PER_Q); +@@ -1516,7 +1571,7 @@ static void handle_outbound(struct qdio_ + } + + /* try to fast requeue buffers */ +- get_buf_state(q, prev_buf(bufnr), &state); ++ get_buf_state(q, prev_buf(bufnr), &state, 0); + if (state != SLSB_CU_OUTPUT_PRIMED) + qdio_kick_outbound_q(q); + else { +Index: linux-sles11/drivers/s390/cio/qdio_perf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_perf.c ++++ linux-sles11/drivers/s390/cio/qdio_perf.c +@@ -74,6 +74,8 @@ static int qdio_perf_proc_show(struct se + seq_printf(m, "\n"); + seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n", + (long)atomic_long_read(&perf_stats.fast_requeue)); ++ seq_printf(m, "Number of outbound target full condition\t: %li\n", ++ (long)atomic_long_read(&perf_stats.outbound_target_full)); + seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n", + (long)atomic_long_read(&perf_stats.debug_tl_out_timer)); + seq_printf(m, "Number of stop polling calls\t\t\t: %li\n", +Index: linux-sles11/drivers/s390/cio/qdio_perf.h +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_perf.h ++++ linux-sles11/drivers/s390/cio/qdio_perf.h +@@ -36,6 +36,7 @@ struct qdio_perf_stats { + atomic_long_t inbound_handler; + atomic_long_t outbound_handler; + atomic_long_t fast_requeue; ++ atomic_long_t outbound_target_full; + + /* for debugging */ + atomic_long_t debug_tl_out_timer; +Index: linux-sles11/drivers/s390/cio/qdio_setup.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_setup.c ++++ linux-sles11/drivers/s390/cio/qdio_setup.c +@@ -167,7 +167,6 @@ static void setup_queues(struct qdio_irq + setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); + + q->is_input_q = 1; +- spin_lock_init(&q->u.in.lock); + setup_storage_lists(q, irq_ptr, input_sbal_array, i); + input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; + +Index: linux-sles11/drivers/s390/cio/qdio_thinint.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_thinint.c ++++ linux-sles11/drivers/s390/cio/qdio_thinint.c +@@ -131,7 +131,7 @@ static inline int tiqdio_inbound_q_done( + return 1; + + qdio_siga_sync_q(q); +- get_buf_state(q, q->first_to_check, &state); ++ get_buf_state(q, q->first_to_check, &state, 0); + + if (state == SLSB_P_INPUT_PRIMED) + /* more work coming */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-06-07-cio-attach_detach.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-06-07-cio-attach_detach.patch new file mode 100644 index 000000000..3c2a81a5f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-06-07-cio-attach_detach.patch @@ -0,0 +1,324 @@ +From: Gerald Schaefer +Subject: cio: Crashes when repeatetly attaching/detaching devices. +References: bnc#458339 + +Symptom: Oops in dmesg after attaching/detaching a device, subsequent + calls to lscss hang. +Problem: Incorrect reference counting of subchannel in relation to + ccw devices, missing check for delayed registering of ccw + devices and incorrectly failing the probe function for I/O + subchannels (which leads to unbound subchannels that can't + be unregistered). +Solution: Make sure that the ccw device holds a reference of the + subchannel, that it is not registered if the subchannel is + not registered anymore, and schedule unregistering an I/O + subchannel if probing encounters an error. + +Acked-by: John Jolly +--- + drivers/s390/cio/cio.h | 1 + drivers/s390/cio/device.c | 128 ++++++++++++++++++++++++++++++++++------------ + 2 files changed, 98 insertions(+), 31 deletions(-) + +--- linux-sles11.orig/drivers/s390/cio/device.c ++++ linux-sles11/drivers/s390/cio/device.c +@@ -716,6 +716,8 @@ ccw_device_release(struct device *dev) + struct ccw_device *cdev; + + cdev = to_ccwdev(dev); ++ /* Release reference of parent subchannel. */ ++ put_device(cdev->dev.parent); + kfree(cdev->private); + kfree(cdev); + } +@@ -790,37 +792,55 @@ static void sch_attach_disconnected_devi + struct subchannel *other_sch; + int ret; + +- other_sch = to_subchannel(get_device(cdev->dev.parent)); ++ /* Get reference for new parent. */ ++ if (!get_device(&sch->dev)) ++ return; ++ other_sch = to_subchannel(cdev->dev.parent); ++ /* Note: device_move() changes cdev->dev.parent */ + ret = device_move(&cdev->dev, &sch->dev); + if (ret) { + CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " + "(ret=%d)!\n", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); +- put_device(&other_sch->dev); ++ /* Put reference for new parent. */ ++ put_device(&sch->dev); + return; + } + sch_set_cdev(other_sch, NULL); + /* No need to keep a subchannel without ccw device around. */ + css_sch_device_unregister(other_sch); +- put_device(&other_sch->dev); + sch_attach_device(sch, cdev); ++ /* Put reference for old parent. */ ++ put_device(&other_sch->dev); + } + + static void sch_attach_orphaned_device(struct subchannel *sch, + struct ccw_device *cdev) + { + int ret; ++ struct subchannel *pseudo_sch; + +- /* Try to move the ccw device to its new subchannel. */ ++ /* Get reference for new parent. */ ++ if (!get_device(&sch->dev)) ++ return; ++ pseudo_sch = to_subchannel(cdev->dev.parent); ++ /* ++ * Try to move the ccw device to its new subchannel. ++ * Note: device_move() changes cdev->dev.parent ++ */ + ret = device_move(&cdev->dev, &sch->dev); + if (ret) { + CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " + "failed (ret=%d)!\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); ++ /* Put reference for new parent. */ ++ put_device(&sch->dev); + return; + } + sch_attach_device(sch, cdev); ++ /* Put reference on pseudo subchannel. */ ++ put_device(&pseudo_sch->dev); + } + + static void sch_create_and_recog_new_device(struct subchannel *sch) +@@ -842,9 +862,11 @@ static void sch_create_and_recog_new_dev + spin_lock_irq(sch->lock); + sch_set_cdev(sch, NULL); + spin_unlock_irq(sch->lock); +- if (cdev->dev.release) +- cdev->dev.release(&cdev->dev); + css_sch_device_unregister(sch); ++ /* Put reference from io_subchannel_create_ccwdev(). */ ++ put_device(&sch->dev); ++ /* Give up initial reference. */ ++ put_device(&cdev->dev); + } + } + +@@ -866,15 +888,20 @@ void ccw_device_move_to_orphanage(struct + dev_id.devno = sch->schib.pmcw.dev; + dev_id.ssid = sch->schid.ssid; + ++ /* Increase refcount for pseudo subchannel. */ ++ get_device(&css->pseudo_subchannel->dev); + /* + * Move the orphaned ccw device to the orphanage so the replacing + * ccw device can take its place on the subchannel. ++ * Note: device_move() changes cdev->dev.parent + */ + ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); + if (ret) { + CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " + "(ret=%d)!\n", cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); ++ /* Decrease refcount for pseudo subchannel again. */ ++ put_device(&css->pseudo_subchannel->dev); + return; + } + cdev->ccwlock = css->pseudo_subchannel->lock; +@@ -886,14 +913,20 @@ void ccw_device_move_to_orphanage(struct + replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev); + if (replacing_cdev) { + sch_attach_disconnected_device(sch, replacing_cdev); ++ /* Release reference of subchannel from old cdev. */ ++ put_device(&sch->dev); + return; + } + replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); + if (replacing_cdev) { + sch_attach_orphaned_device(sch, replacing_cdev); ++ /* Release reference of subchannel from old cdev. */ ++ put_device(&sch->dev); + return; + } + sch_create_and_recog_new_device(sch); ++ /* Release reference of subchannel from old cdev. */ ++ put_device(&sch->dev); + } + + /* +@@ -911,6 +944,14 @@ io_subchannel_register(struct work_struc + priv = container_of(work, struct ccw_device_private, kick_work); + cdev = priv->cdev; + sch = to_subchannel(cdev->dev.parent); ++ /* ++ * Check if subchannel is still registered. It may have become ++ * unregistered if a machine check hit us after finishing ++ * device recognition but before the register work could be ++ * queued. ++ */ ++ if (!device_is_registered(&sch->dev)) ++ goto out_err; + css_update_ssd_info(sch); + /* + * io_subchannel_register() will also be called after device +@@ -942,22 +983,19 @@ io_subchannel_register(struct work_struc + CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno, ret); +- put_device(&cdev->dev); + spin_lock_irqsave(sch->lock, flags); + sch_set_cdev(sch, NULL); + spin_unlock_irqrestore(sch->lock, flags); +- kfree (cdev->private); +- kfree (cdev); +- put_device(&sch->dev); +- if (atomic_dec_and_test(&ccw_device_init_count)) +- wake_up(&ccw_device_init_wq); +- return; ++ /* Release initial device reference. */ ++ put_device(&cdev->dev); ++ goto out_err; + } +- put_device(&cdev->dev); + out: + cdev->private->flags.recog_done = 1; +- put_device(&sch->dev); + wake_up(&cdev->private->wait_q); ++out_err: ++ /* Release reference for workqueue processing. */ ++ put_device(&cdev->dev); + if (atomic_dec_and_test(&ccw_device_init_count)) + wake_up(&ccw_device_init_wq); + } +@@ -1068,10 +1106,15 @@ static void ccw_device_move_to_sch(struc + priv = container_of(work, struct ccw_device_private, kick_work); + sch = priv->sch; + cdev = priv->cdev; +- former_parent = ccw_device_is_orphan(cdev) ? +- NULL : to_subchannel(get_device(cdev->dev.parent)); ++ former_parent = to_subchannel(cdev->dev.parent); ++ /* Get reference for new parent. */ ++ if (!get_device(&sch->dev)) ++ return; + mutex_lock(&sch->reg_mutex); +- /* Try to move the ccw device to its new subchannel. */ ++ /* ++ * Try to move the ccw device to its new subchannel. ++ * Note: device_move() changes cdev->dev.parent ++ */ + rc = device_move(&cdev->dev, &sch->dev); + mutex_unlock(&sch->reg_mutex); + if (rc) { +@@ -1081,9 +1124,11 @@ static void ccw_device_move_to_sch(struc + cdev->private->dev_id.devno, sch->schid.ssid, + sch->schid.sch_no, rc); + css_sch_device_unregister(sch); ++ /* Put reference for new parent again. */ ++ put_device(&sch->dev); + goto out; + } +- if (former_parent) { ++ if (!sch_is_pseudo_sch(former_parent)) { + spin_lock_irq(former_parent->lock); + sch_set_cdev(former_parent, NULL); + spin_unlock_irq(former_parent->lock); +@@ -1094,8 +1139,8 @@ static void ccw_device_move_to_sch(struc + } + sch_attach_device(sch, cdev); + out: +- if (former_parent) +- put_device(&former_parent->dev); ++ /* Put reference for old parent. */ ++ put_device(&former_parent->dev); + put_device(&cdev->dev); + } + +@@ -1137,6 +1182,30 @@ static void io_subchannel_init_fields(st + sch->schib.mba = 0; + } + ++static void io_subchannel_do_unreg(struct work_struct *work) ++{ ++ struct subchannel *sch; ++ ++ sch = container_of(work, struct subchannel, work); ++ css_sch_device_unregister(sch); ++ /* Reset intparm to zeroes. */ ++ sch->schib.pmcw.intparm = 0; ++ cio_modify(sch); ++ put_device(&sch->dev); ++} ++ ++/* Schedule unregister if we have no cdev. */ ++static void io_subchannel_schedule_removal(struct subchannel *sch) ++{ ++ get_device(&sch->dev); ++ INIT_WORK(&sch->work, io_subchannel_do_unreg); ++ queue_work(slow_path_wq, &sch->work); ++} ++ ++/* ++ * Note: We always return 0 so that we bind to the device even on error. ++ * This is needed so that our remove function is called on unregister. ++ */ + static int io_subchannel_probe(struct subchannel *sch) + { + struct ccw_device *cdev; +@@ -1186,14 +1255,12 @@ static int io_subchannel_probe(struct su + rc = sysfs_create_group(&sch->dev.kobj, + &io_subchannel_attr_group); + if (rc) +- return rc; ++ goto out_schedule; + /* Allocate I/O subchannel private data. */ + sch->private = kzalloc(sizeof(struct io_subchannel_private), + GFP_KERNEL | GFP_DMA); +- if (!sch->private) { +- rc = -ENOMEM; ++ if (!sch->private) + goto out_err; +- } + cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); + if (!cdev) + cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), +@@ -1211,24 +1278,23 @@ static int io_subchannel_probe(struct su + return 0; + } + cdev = io_subchannel_create_ccwdev(sch); +- if (IS_ERR(cdev)) { +- rc = PTR_ERR(cdev); ++ if (IS_ERR(cdev)) + goto out_err; +- } + rc = io_subchannel_recog(cdev, sch); + if (rc) { + spin_lock_irqsave(sch->lock, flags); + sch_set_cdev(sch, NULL); ++ io_subchannel_recog_done(cdev); + spin_unlock_irqrestore(sch->lock, flags); +- if (cdev->dev.release) +- cdev->dev.release(&cdev->dev); +- goto out_err; + } + return 0; + out_err: + kfree(sch->private); + sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); + return rc; ++out_schedule: ++ io_subchannel_schedule_removal(sch); ++ return 0; + } + + static int +--- linux-sles11.orig/drivers/s390/cio/cio.h ++++ linux-sles11/drivers/s390/cio/cio.h +@@ -82,6 +82,7 @@ struct subchannel { + struct device dev; /* entry in device tree */ + struct css_driver *driver; + void *private; /* private per subchannel type data */ ++ struct work_struct work; + } __attribute__ ((aligned(8))); + + #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-07-04-dasd-failfast.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-07-04-dasd-failfast.patch new file mode 100644 index 000000000..1f7879bdc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-07-04-dasd-failfast.patch @@ -0,0 +1,157 @@ +From: Gerald Schaefer +Subject: dasd: Add 'failfast' device feature. +References: bnc#464466,LTC#43066 + + Symptom: md-raid1 cannot operate and manage md array, when no path is + operational. + Problem: md-raid1 does not set the FAILFAST flag, because that would + break SCSI functionality due to ambiguous meaning of the flag. + Solution: Add a new dasd feature 'failfast' which controls the dasd + driver handling of requests and can be configured per device + independently of the setting of the FAILFAST flag per request. + If the 'failfast' feature is enabled for a device, the dasd + driver will handle requests as if the request had the FAILFAST + flag set, particularly posting I/O failure, when no path is + operational to the device. + The 'failfast' feature can be configured via the new sysfs + attribute 'failfast' or via the 'dasd=' parameter, just like + any other feature. By default, the 'failfast' feature is not + set. + +Acked-by: John Jolly + +--- + arch/s390/include/asm/dasd.h | 1 + drivers/s390/block/dasd_devmap.c | 48 +++++++++++++++++++++++++++++++++++++++ + drivers/s390/block/dasd_diag.c | 3 +- + drivers/s390/block/dasd_eckd.c | 3 +- + drivers/s390/block/dasd_fba.c | 3 +- + 5 files changed, 55 insertions(+), 3 deletions(-) + +Index: linux-sles11/drivers/s390/block/dasd_devmap.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd_devmap.c ++++ linux-sles11/drivers/s390/block/dasd_devmap.c +@@ -205,6 +205,8 @@ dasd_feature_list(char *str, char **endp + features |= DASD_FEATURE_USEDIAG; + else if (len == 6 && !strncmp(str, "erplog", 6)) + features |= DASD_FEATURE_ERPLOG; ++ else if (len == 8 && !strncmp(str, "failfast", 8)) ++ features |= DASD_FEATURE_FAILFAST; + else { + MESSAGE(KERN_WARNING, + "unsupported feature: %*s, " +@@ -666,6 +668,51 @@ dasd_device_from_cdev(struct ccw_device + */ + + /* ++ * failfast controls the behaviour, if no path is available ++ */ ++static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct dasd_devmap *devmap; ++ int ff_flag; ++ ++ devmap = dasd_find_busid(dev->bus_id); ++ if (!IS_ERR(devmap)) ++ ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0; ++ else ++ ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0; ++ return snprintf(buf, PAGE_SIZE, ff_flag ? "1\n" : "0\n"); ++} ++ ++static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct dasd_devmap *devmap; ++ int val; ++ char *endp; ++ ++ devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); ++ if (IS_ERR(devmap)) ++ return PTR_ERR(devmap); ++ ++ val = simple_strtoul(buf, &endp, 0); ++ if (((endp + 1) < (buf + count)) || (val > 1)) ++ return -EINVAL; ++ ++ spin_lock(&dasd_devmap_lock); ++ if (val) ++ devmap->features |= DASD_FEATURE_FAILFAST; ++ else ++ devmap->features &= ~DASD_FEATURE_FAILFAST; ++ if (devmap->device) ++ devmap->device->features = devmap->features; ++ spin_unlock(&dasd_devmap_lock); ++ return count; ++} ++ ++static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store); ++ ++/* + * readonly controls the readonly status of a dasd + */ + static ssize_t +@@ -1019,6 +1066,7 @@ static struct attribute * dasd_attrs[] = + &dev_attr_use_diag.attr, + &dev_attr_eer_enabled.attr, + &dev_attr_erplog.attr, ++ &dev_attr_failfast.attr, + NULL, + }; + +Index: linux-sles11/drivers/s390/block/dasd_diag.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd_diag.c ++++ linux-sles11/drivers/s390/block/dasd_diag.c +@@ -544,7 +544,8 @@ static struct dasd_ccw_req *dasd_diag_bu + } + cqr->retries = DIAG_MAX_RETRIES; + cqr->buildclk = get_clock(); +- if (blk_noretry_request(req)) ++ if (blk_noretry_request(req) || ++ block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = memdev; + cqr->memdev = memdev; +Index: linux-sles11/drivers/s390/block/dasd_eckd.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd_eckd.c ++++ linux-sles11/drivers/s390/block/dasd_eckd.c +@@ -1700,7 +1700,8 @@ static struct dasd_ccw_req *dasd_eckd_bu + recid++; + } + } +- if (blk_noretry_request(req)) ++ if (blk_noretry_request(req) || ++ block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = startdev; + cqr->memdev = startdev; +Index: linux-sles11/drivers/s390/block/dasd_fba.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd_fba.c ++++ linux-sles11/drivers/s390/block/dasd_fba.c +@@ -355,7 +355,8 @@ static struct dasd_ccw_req *dasd_fba_bui + recid++; + } + } +- if (blk_noretry_request(req)) ++ if (blk_noretry_request(req) || ++ block->base->features & DASD_FEATURE_FAILFAST) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = memdev; + cqr->memdev = memdev; +Index: linux-sles11/arch/s390/include/asm/dasd.h +=================================================================== +--- linux-sles11.orig/arch/s390/include/asm/dasd.h ++++ linux-sles11/arch/s390/include/asm/dasd.h +@@ -78,6 +78,7 @@ typedef struct dasd_information2_t { + #define DASD_FEATURE_USEDIAG 0x02 + #define DASD_FEATURE_INITIAL_ONLINE 0x04 + #define DASD_FEATURE_ERPLOG 0x08 ++#define DASD_FEATURE_FAILFAST 0x10 + + #define DASD_PARTN_BITS 2 + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-08-05-af_iucv-msgpeek-fix.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-08-05-af_iucv-msgpeek-fix.patch new file mode 100644 index 000000000..da3d2c41c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-08-05-af_iucv-msgpeek-fix.patch @@ -0,0 +1,39 @@ +From: Gerald Schaefer +Subject: af_iucv: System hang if recvmsg() is used with MSG_PEEK +References: bnc#466462,LTC#51136 + +Symptom: Receiving socket data with MSG_PEEK flag set causes systen hang +Problem: If iucv_sock_recvmsg() is called with MSG_PEEK flag set, + the skb is enqueued twice. If the socket is then closed, the + pointer to the skb is also freed twice and causes a kernel oops. +Solution: Remove the skb_queue_head() call for MSG_PEEK, because the + skb_recv_datagram() function already handles MSG_PEEK (it + actually does not dequeue the skb). + +Acked-by: John Jolly +--- + net/iucv/af_iucv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -789,6 +789,8 @@ static int iucv_sock_recvmsg(struct kioc + + target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); + ++ /* receive/dequeue next skb: ++ * the function understands MSG_PEEK and, thus, does not dequeue skb */ + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) { + if (sk->sk_shutdown & RCV_SHUTDOWN) +@@ -836,9 +838,7 @@ static int iucv_sock_recvmsg(struct kioc + iucv_process_message_q(sk); + spin_unlock_bh(&iucv->message_q.lock); + } +- +- } else +- skb_queue_head(&sk->sk_receive_queue, skb); ++ } + + done: + return err ? : copied; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-08-06-personality.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-08-06-personality.patch new file mode 100644 index 000000000..8c320c7e2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-08-06-personality.patch @@ -0,0 +1,52 @@ +From: Gerald Schaefer +Subject: kernel: setting 32 bit personality doesn't work +References: bnc#466462 + +Symptom: Setting the personality from 64 bit to 32 bit and afterwards + issueing a uname system call will return that the environment + is still 64 bit. Some executables that rely on a correct 32 bit + environment don't work. +Problem: The SET_PERSONALITY macro compares the whole personality field + on each execve with PER_LINUX32. If that doesn't match personality + is set to PER_LINUX. When some higher order bits in the personality + field are set the personality is incorrectly changed from + PER_LINUX32 to PER_LINUX on execve. +Solution: Use the personality() function to mask out bits that shouldn't be + taken into account when comparing personality types. + +Acked-by: Hannes Reinecke +--- + arch/s390/include/asm/elf.h | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +Index: linux-sles11/arch/s390/include/asm/elf.h +=================================================================== +--- linux-sles11.orig/arch/s390/include/asm/elf.h ++++ linux-sles11/arch/s390/include/asm/elf.h +@@ -168,16 +168,16 @@ extern char elf_platform[]; + #ifndef __s390x__ + #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) + #else /* __s390x__ */ +-#define SET_PERSONALITY(ex, ibcs2) \ +-do { \ +- if (ibcs2) \ +- set_personality(PER_SVR4); \ +- else if (current->personality != PER_LINUX32) \ +- set_personality(PER_LINUX); \ +- if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ +- set_thread_flag(TIF_31BIT); \ +- else \ +- clear_thread_flag(TIF_31BIT); \ ++#define SET_PERSONALITY(ex, ibcs2) \ ++ do { \ ++ if (ibcs2) \ ++ set_personality(PER_SVR4); \ ++ else if (personality(current->personality) != PER_LINUX32) \ ++ set_personality(PER_LINUX); \ ++ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ ++ set_thread_flag(TIF_31BIT); \ ++ else \ ++ clear_thread_flag(TIF_31BIT); \ + } while (0) + #endif /* __s390x__ */ + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-08-07-compat_wrappers.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-08-07-compat_wrappers.patch new file mode 100644 index 000000000..2cc29edb3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-08-07-compat_wrappers.patch @@ -0,0 +1,103 @@ +From: Gerald Schaefer +Subject: kernel: Add missing wrapper functions for 31 bit compat syscalls. +References: bnc#466462,LTC#51229 + +Symptom: Some 31 bit system calls not work as expected on 64 bit Linux. + Therefore programs like e.g. 31 bit java may not work correctly. +Problem: Wrapper functions for the following compat system calls are + missing: readahead, sendfile64, tkill, tgkill and + keyctl. Due to the missing wrappers, the 31 bit system call + parameter registers are not correctly expanded to 64 bit. +Solution: Add wrapper functions that do the correct 31 bit to 64 bit + conversion. + +Acked-by: Hannes Reinecke +--- + arch/s390/kernel/compat_wrapper.S | 38 ++++++++++++++++++++++++++++++++++++++ + arch/s390/kernel/syscalls.S | 10 +++++----- + 2 files changed, 43 insertions(+), 5 deletions(-) + +Index: linux-sles11/arch/s390/kernel/compat_wrapper.S +=================================================================== +--- linux-sles11.orig/arch/s390/kernel/compat_wrapper.S ++++ linux-sles11/arch/s390/kernel/compat_wrapper.S +@@ -1769,3 +1769,41 @@ sys_dup3_wrapper: + sys_epoll_create1_wrapper: + lgfr %r2,%r2 # int + jg sys_epoll_create1 # branch to system call ++ ++ .globl sys32_readahead_wrapper ++sys32_readahead_wrapper: ++ lgfr %r2,%r2 # int ++ llgfr %r3,%r3 # u32 ++ llgfr %r4,%r4 # u32 ++ lgfr %r5,%r5 # s32 ++ jg sys32_readahead # branch to system call ++ ++ .globl sys32_sendfile64_wrapper ++sys32_sendfile64_wrapper: ++ lgfr %r2,%r2 # int ++ lgfr %r3,%r3 # int ++ llgtr %r4,%r4 # compat_loff_t * ++ lgfr %r5,%r5 # s32 ++ jg sys32_sendfile64 # branch to system call ++ ++ .globl sys_tkill_wrapper ++sys_tkill_wrapper: ++ lgfr %r2,%r2 # pid_t ++ lgfr %r3,%r3 # int ++ jg sys_tkill # branch to system call ++ ++ .globl sys_tgkill_wrapper ++sys_tgkill_wrapper: ++ lgfr %r2,%r2 # pid_t ++ lgfr %r3,%r3 # pid_t ++ lgfr %r4,%r4 # int ++ jg sys_tgkill # branch to system call ++ ++ .globl compat_sys_keyctl_wrapper ++compat_sys_keyctl_wrapper: ++ llgfr %r2,%r2 # u32 ++ llgfr %r3,%r3 # u32 ++ llgfr %r4,%r4 # u32 ++ llgfr %r5,%r5 # u32 ++ llgfr %r6,%r6 # u32 ++ jg compat_sys_keyctl # branch to system call +Index: linux-sles11/arch/s390/kernel/syscalls.S +=================================================================== +--- linux-sles11.orig/arch/s390/kernel/syscalls.S ++++ linux-sles11/arch/s390/kernel/syscalls.S +@@ -230,8 +230,8 @@ SYSCALL(sys_mincore,sys_mincore,sys32_mi + SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper) + SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper) /* 220 */ + SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper) +-SYSCALL(sys_readahead,sys_readahead,sys32_readahead) +-SYSCALL(sys_sendfile64,sys_ni_syscall,sys32_sendfile64) ++SYSCALL(sys_readahead,sys_readahead,sys32_readahead_wrapper) ++SYSCALL(sys_sendfile64,sys_ni_syscall,sys32_sendfile64_wrapper) + SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper) + SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */ + SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper) +@@ -245,11 +245,11 @@ SYSCALL(sys_removexattr,sys_removexattr, + SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper) + SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */ + SYSCALL(sys_gettid,sys_gettid,sys_gettid) +-SYSCALL(sys_tkill,sys_tkill,sys_tkill) ++SYSCALL(sys_tkill,sys_tkill,sys_tkill_wrapper) + SYSCALL(sys_futex,sys_futex,compat_sys_futex_wrapper) + SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper) + SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */ +-SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill) ++SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill_wrapper) + NI_SYSCALL /* reserved for TUX */ + SYSCALL(sys_io_setup,sys_io_setup,sys32_io_setup_wrapper) + SYSCALL(sys_io_destroy,sys_io_destroy,sys32_io_destroy_wrapper) +@@ -288,7 +288,7 @@ SYSCALL(sys_mq_getsetattr,sys_mq_getseta + SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper) + SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper) + SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper) +-SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */ ++SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl_wrapper) /* 280 */ + SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid_wrapper) + SYSCALL(sys_ioprio_set,sys_ioprio_set,sys_ioprio_set_wrapper) + SYSCALL(sys_ioprio_get,sys_ioprio_get,sys_ioprio_get_wrapper) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-08-08-add_qdio_utilization.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-08-08-add_qdio_utilization.patch new file mode 100644 index 000000000..7c79661d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-08-08-add_qdio_utilization.patch @@ -0,0 +1,97 @@ +From: Gerald Schaefer +Subject: zfcp: queue_full is lacking the entry for qdio utilization +References: bnc#466462 + +Symptom: ziomon fails with an error message indicating an outdated kernel +Problem: queue_full is missing an additional entry that gives the + qdio utilization. Without this entry, the scsi performance + dara collection feature does not work at all. +Solution: Add the missing attribute to queue_full. + +Acked-by: John Jolly + +--- + + drivers/s390/scsi/zfcp_aux.c | 1 + + drivers/s390/scsi/zfcp_def.h | 3 +++ + drivers/s390/scsi/zfcp_qdio.c | 20 ++++++++++++++++++++ + drivers/s390/scsi/zfcp_sysfs.c | 3 ++- + 4 files changed, 26 insertions(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -500,6 +500,7 @@ int zfcp_adapter_enqueue(struct ccw_devi + spin_lock_init(&adapter->scsi_dbf_lock); + spin_lock_init(&adapter->rec_dbf_lock); + spin_lock_init(&adapter->req_q_lock); ++ spin_lock_init(&adapter->qdio_stat_lock); + + rwlock_init(&adapter->erp_lock); + rwlock_init(&adapter->abort_lock); +--- a/drivers/s390/scsi/zfcp_def.h ++++ b/drivers/s390/scsi/zfcp_def.h +@@ -472,6 +472,9 @@ struct zfcp_adapter { + spinlock_t req_q_lock; /* for operations on queue */ + int req_q_pci_batch; /* SBALs since PCI indication + was last set */ ++ ktime_t req_q_time; /* time of last fill level change */ ++ u64 req_q_util; /* for accounting */ ++ spinlock_t qdio_stat_lock; + u32 fsf_req_seq_no; /* FSF cmnd seq number */ + wait_queue_head_t request_wq; /* can be used to wait for + more avaliable SBALs */ +--- a/drivers/s390/scsi/zfcp_qdio.c ++++ b/drivers/s390/scsi/zfcp_qdio.c +@@ -76,6 +76,23 @@ static void zfcp_qdio_zero_sbals(struct + } + } + ++/* this needs to be called prior to updating the queue fill level */ ++static void zfcp_qdio_account(struct zfcp_adapter *adapter) ++{ ++ ktime_t now; ++ s64 span; ++ int free, used; ++ ++ spin_lock(&adapter->qdio_stat_lock); ++ now = ktime_get(); ++ span = ktime_us_delta(now, adapter->req_q_time); ++ free = max(0, atomic_read(&adapter->req_q.count)); ++ used = QDIO_MAX_BUFFERS_PER_Q - free; ++ adapter->req_q_util += used * span; ++ adapter->req_q_time = now; ++ spin_unlock(&adapter->qdio_stat_lock); ++} ++ + static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, + int queue_no, int first, int count, + unsigned long parm) +@@ -92,6 +109,7 @@ static void zfcp_qdio_int_req(struct ccw + /* cleanup all SBALs being program-owned now */ + zfcp_qdio_zero_sbals(queue->sbal, first, count); + ++ zfcp_qdio_account(adapter); + atomic_add(count, &queue->count); + wake_up(&adapter->request_wq); + } +@@ -358,6 +376,8 @@ int zfcp_qdio_send(struct zfcp_fsf_req * + sbale->flags |= SBAL_FLAGS0_PCI; + } + ++ zfcp_qdio_account(adapter); ++ + retval = do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, first, + count); + if (unlikely(retval)) { +--- a/drivers/s390/scsi/zfcp_sysfs.c ++++ b/drivers/s390/scsi/zfcp_sysfs.c +@@ -486,7 +486,8 @@ static ssize_t zfcp_sysfs_adapter_q_full + struct zfcp_adapter *adapter = + (struct zfcp_adapter *) scsi_host->hostdata[0]; + +- return sprintf(buf, "%d\n", atomic_read(&adapter->qdio_outb_full)); ++ return sprintf(buf, "%d %llu\n", atomic_read(&adapter->qdio_outb_full), ++ (unsigned long long)adapter->req_q_util); + } + static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-08-09-switch-amode-off.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-08-09-switch-amode-off.patch new file mode 100644 index 000000000..6d89bcd62 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-08-09-switch-amode-off.patch @@ -0,0 +1,143 @@ +From: Gerald Schaefer +Subject: kernel: Fix user copy functions (pagetable walk) with KERNEL_DS. +References: bnc#466462 + +Symptom: Kernel OOPS / system hang on user program core dump on pre z9 + hardware. +Problem: Passing incorrect addresses to user copy functions is not handled + correctly when address spaces are switched and KERNEL_DS is set. +Solution: Verify addresses by handling KERNEL_DS case in the same way as + USER_DS (pagetable walk). Also disable switch_amode by default + because pagetable walk has negative performance impact. + +Acked-by: John Jolly +--- + arch/s390/kernel/setup.c | 4 ---- + arch/s390/lib/uaccess_pt.c | 32 +++++++------------------------- + arch/s390/mm/pgtable.c | 4 ++++ + 3 files changed, 11 insertions(+), 29 deletions(-) + +Index: linux-sles11/arch/s390/kernel/setup.c +=================================================================== +--- linux-sles11.orig/arch/s390/kernel/setup.c ++++ linux-sles11/arch/s390/kernel/setup.c +@@ -285,11 +285,7 @@ static int __init early_parse_mem(char * + early_param("mem", early_parse_mem); + + #ifdef CONFIG_S390_SWITCH_AMODE +-#ifdef CONFIG_PGSTE +-unsigned int switch_amode = 1; +-#else + unsigned int switch_amode = 0; +-#endif + EXPORT_SYMBOL_GPL(switch_amode); + + static int set_amode_and_uaccess(unsigned long user_amode, +Index: linux-sles11/arch/s390/mm/pgtable.c +=================================================================== +--- linux-sles11.orig/arch/s390/mm/pgtable.c ++++ linux-sles11/arch/s390/mm/pgtable.c +@@ -256,6 +256,10 @@ int s390_enable_sie(void) + struct task_struct *tsk = current; + struct mm_struct *mm, *old_mm; + ++ /* Do we have switched amode? If no, we cannot do sie */ ++ if (!switch_amode) ++ return -EINVAL; ++ + /* Do we have pgstes? if yes, we are done */ + if (tsk->mm->context.pgstes) + return 0; +Index: linux-sles11/arch/s390/lib/uaccess_pt.c +=================================================================== +--- linux-sles11.orig/arch/s390/lib/uaccess_pt.c ++++ linux-sles11/arch/s390/lib/uaccess_pt.c +@@ -43,8 +43,9 @@ static int __handle_fault(struct mm_stru + int ret = -EFAULT; + int fault; + +- if (in_atomic()) ++ if (in_atomic() || segment_eq(get_fs(), KERNEL_DS)) + return ret; ++ + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + if (unlikely(!vma)) +@@ -109,6 +110,8 @@ static size_t __user_copy_pt(unsigned lo + pte_t *pte; + void *from, *to; + ++ if (segment_eq(get_fs(), KERNEL_DS)) ++ mm = &init_mm; + done = 0; + retry: + spin_lock(&mm->page_table_lock); +@@ -182,10 +185,6 @@ size_t copy_from_user_pt(size_t n, const + { + size_t rc; + +- if (segment_eq(get_fs(), KERNEL_DS)) { +- memcpy(to, (void __kernel __force *) from, n); +- return 0; +- } + rc = __user_copy_pt((unsigned long) from, to, n, 0); + if (unlikely(rc)) + memset(to + n - rc, 0, rc); +@@ -194,10 +193,6 @@ size_t copy_from_user_pt(size_t n, const + + size_t copy_to_user_pt(size_t n, void __user *to, const void *from) + { +- if (segment_eq(get_fs(), KERNEL_DS)) { +- memcpy((void __kernel __force *) to, from, n); +- return 0; +- } + return __user_copy_pt((unsigned long) to, (void *) from, n, 1); + } + +@@ -205,10 +200,6 @@ static size_t clear_user_pt(size_t n, vo + { + long done, size, ret; + +- if (segment_eq(get_fs(), KERNEL_DS)) { +- memset((void __kernel __force *) to, 0, n); +- return 0; +- } + done = 0; + do { + if (n - done > PAGE_SIZE) +@@ -234,7 +225,7 @@ static size_t strnlen_user_pt(size_t cou + size_t len_str; + + if (segment_eq(get_fs(), KERNEL_DS)) +- return strnlen((const char __kernel __force *) src, count) + 1; ++ mm = &init_mm; + done = 0; + retry: + spin_lock(&mm->page_table_lock); +@@ -276,13 +267,6 @@ static size_t strncpy_from_user_pt(size_ + return -EFAULT; + if (n > count) + n = count; +- if (segment_eq(get_fs(), KERNEL_DS)) { +- memcpy(dst, (const char __kernel __force *) src, n); +- if (dst[n-1] == '\0') +- return n-1; +- else +- return n; +- } + if (__user_copy_pt((unsigned long) src, dst, n, 0)) + return -EFAULT; + if (dst[n-1] == '\0') +@@ -302,10 +286,8 @@ static size_t copy_in_user_pt(size_t n, + pte_t *pte_from, *pte_to; + int write_user; + +- if (segment_eq(get_fs(), KERNEL_DS)) { +- memcpy((void __force *) to, (void __force *) from, n); +- return 0; +- } ++ if (segment_eq(get_fs(), KERNEL_DS)) ++ mm = &init_mm; + done = 0; + retry: + spin_lock(&mm->page_table_lock); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-09-01-cio_disable_notoper.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-09-01-cio_disable_notoper.patch new file mode 100644 index 000000000..0d733fef0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-09-01-cio_disable_notoper.patch @@ -0,0 +1,80 @@ +From: Gerald Schaefer +Subject: cio: Properly disable not operational subchannel. +References: bnc#477666,LTC#51619 + +Symptom: Kernel BUG at drivers/s390/cio/device_fsm.c:1241! +Problem: After deferred cc=3 was received on all paths, a + device was set to not operational to prepare for + re-evaluation. An unsolicited interrupt indicating + that the device became accessible again triggered + an invalid event in the state machine (interrupt in + not operational state). +Solution: Properly disable the subchannel before setting the + device not operational. To be able to disable the + subchannel reliably, pending status needs to be + collected. + +Acked-by: John Jolly + +--- + drivers/s390/cio/cio.c | 19 +++++-------------- + drivers/s390/cio/device_fsm.c | 4 ++-- + 2 files changed, 7 insertions(+), 16 deletions(-) + +Index: linux-sles11/drivers/s390/cio/device_fsm.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/device_fsm.c ++++ linux-sles11/drivers/s390/cio/device_fsm.c +@@ -726,7 +726,7 @@ static void ccw_device_generic_notoper(s + { + struct subchannel *sch; + +- cdev->private->state = DEV_STATE_NOT_OPER; ++ ccw_device_set_notoper(cdev); + sch = to_subchannel(cdev->dev.parent); + css_schedule_eval(sch->schid); + } +@@ -1048,7 +1048,7 @@ ccw_device_offline_irq(struct ccw_device + sch = to_subchannel(cdev->dev.parent); + /* + * An interrupt in state offline means a previous disable was not +- * successful. Try again. ++ * successful - should not happen, but we try to disable again. + */ + cio_disable_subchannel(sch); + } +Index: linux-sles11/drivers/s390/cio/cio.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/cio.c ++++ linux-sles11/drivers/s390/cio/cio.c +@@ -464,25 +464,16 @@ int cio_disable_subchannel(struct subcha + if (ccode == 3) /* Not operational. */ + return -ENODEV; + +- if (scsw_actl(&sch->schib.scsw) != 0) +- /* +- * the disable function must not be called while there are +- * requests pending for completion ! +- */ +- return -EBUSY; +- + for (retry = 5, ret = 0; retry > 0; retry--) { + sch->schib.pmcw.ena = 0; + ret = cio_modify(sch); + if (ret == -ENODEV) + break; +- if (ret == -EBUSY) +- /* +- * The subchannel is busy or status pending. +- * We'll disable when the next interrupt was delivered +- * via the state machine. +- */ +- break; ++ if (ret == -EBUSY) { ++ struct irb irb; ++ if (tsch(sch->schid, &irb) != 0) ++ break; ++ } + if (ret == 0) { + stsch (sch->schid, &sch->schib); + if (!sch->schib.pmcw.ena) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-09-02-sclp-handle-empty-evbufs.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-09-02-sclp-handle-empty-evbufs.patch new file mode 100644 index 000000000..f877bf3a1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-09-02-sclp-handle-empty-evbufs.patch @@ -0,0 +1,34 @@ +From: Gerald Schaefer +Subject: sclp: handle zero-length event buffers +References: bnc#477666,LTC#51641 + +Symptom: Support Element (SE) restart may cause Linux on LPAR to hang. +Problem: During SE restart, some SE versions may under certain conditions + present a malformed Read Event Data response block to Linux which + causes an endless loop in function sclp_dispatch_evbufs. +Solution: Stop event dispatching loop when a zero-length event buffer was + recognized. + +Acked-by: John Jolly + +--- + drivers/s390/char/sclp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/char/sclp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/char/sclp.c ++++ linux-sles11/drivers/s390/char/sclp.c +@@ -280,8 +280,11 @@ sclp_dispatch_evbufs(struct sccb_header + rc = 0; + for (offset = sizeof(struct sccb_header); offset < sccb->length; + offset += evbuf->length) { +- /* Search for event handler */ + evbuf = (struct evbuf_header *) ((addr_t) sccb + offset); ++ /* Check for malformed hardware response */ ++ if (evbuf->length == 0) ++ break; ++ /* Search for event handler */ + reg = NULL; + list_for_each(l, &sclp_reg_list) { + reg = list_entry(l, struct sclp_register, list); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-09-03-sclp-mem.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-09-03-sclp-mem.patch new file mode 100644 index 000000000..1ac129a70 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-09-03-sclp-mem.patch @@ -0,0 +1,93 @@ +From: Gerald Schaefer +Subject: sclp: consider "mem=" kernel parameter for standby memory +References: bnc#477666,LTC#51741 + +Symptom: zfcpdump exits with "panic: out of memory" +Problem: Standby memory detected with the sclp interface always gets + registered with add_memory calls without considering the + limitations that the "mem=" kernel paramater imply. + zfcpdump uses "mem=32M". In case there is approximately 2GB of + standby memory present all usable memory will be used for + struct pages needed for standby memory. This in turn leads + to an early out of memory situation and a panic. +Solution: Only register standby memory that is below the address specified + with the "mem=" kernel parameter. + +Acked-by: John Jolly +--- + arch/s390/include/asm/setup.h | 2 ++ + arch/s390/kernel/setup.c | 9 +++++++-- + drivers/s390/char/sclp_cmd.c | 5 +++++ + 3 files changed, 14 insertions(+), 2 deletions(-) + +Index: linux-sles11/arch/s390/include/asm/setup.h +=================================================================== +--- linux-sles11.orig/arch/s390/include/asm/setup.h ++++ linux-sles11/arch/s390/include/asm/setup.h +@@ -43,6 +43,8 @@ struct mem_chunk { + + extern struct mem_chunk memory_chunk[]; + extern unsigned long real_memory_size; ++extern int memory_end_set; ++extern unsigned long memory_end; + + void detect_memory_layout(struct mem_chunk chunk[]); + +Index: linux-sles11/arch/s390/kernel/setup.c +=================================================================== +--- linux-sles11.orig/arch/s390/kernel/setup.c ++++ linux-sles11/arch/s390/kernel/setup.c +@@ -81,7 +81,9 @@ char elf_platform[ELF_PLATFORM_SIZE]; + + struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; + volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ +-static unsigned long __initdata memory_end; ++ ++int __initdata memory_end_set; ++unsigned long __initdata memory_end; + + /* + * This is set up by the setup-routine at boot-time +@@ -280,6 +282,7 @@ void (*pm_power_off)(void) = machine_pow + static int __init early_parse_mem(char *p) + { + memory_end = memparse(p, &p); ++ memory_end_set = 1; + return 0; + } + early_param("mem", early_parse_mem); +@@ -501,8 +504,10 @@ static void __init setup_memory_end(void + int i; + + #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) +- if (ipl_info.type == IPL_TYPE_FCP_DUMP) ++ if (ipl_info.type == IPL_TYPE_FCP_DUMP) { + memory_end = ZFCPDUMP_HSA_SIZE; ++ memory_end_set = 1; ++ } + #endif + memory_size = 0; + memory_end &= PAGE_MASK; +Index: linux-sles11/drivers/s390/char/sclp_cmd.c +=================================================================== +--- linux-sles11.orig/drivers/s390/char/sclp_cmd.c ++++ linux-sles11/drivers/s390/char/sclp_cmd.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "sclp.h" + +@@ -470,6 +471,10 @@ static void __init add_memory_merged(u16 + goto skip_add; + if (start + size > VMEM_MAX_PHYS) + size = VMEM_MAX_PHYS - start; ++ if (memory_end_set && (start >= memory_end)) ++ goto skip_add; ++ if (memory_end_set && (start + size > memory_end)) ++ size = memory_end - start; + add_memory(0, start, size); + skip_add: + first_rn = rn; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-01-airq_fix_array_boundary.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-01-airq_fix_array_boundary.patch new file mode 100644 index 000000000..985c5c4c1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-01-airq_fix_array_boundary.patch @@ -0,0 +1,30 @@ +From: Gerald Schaefer +Subject: cio: airq - fix array boundary +References: bnc#482818,LTC#51920 + +Symptom: Potential memory overwrite. +Problem: In airq array definitions use a length of MAX_ISC, which is + a valid isc number. So if drivers are using adapter + interrupts with the lowest isc memory may be overwritten. +Solution: Use array lengths of MAX_ISC+1 + +Acked-by: John Jolly +--- + drivers/s390/cio/airq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: linux-sles11/drivers/s390/cio/airq.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/airq.c 2008-10-10 00:13:53.000000000 +0200 ++++ linux-sles11/drivers/s390/cio/airq.c 2009-02-27 14:32:43.000000000 +0100 +@@ -34,8 +34,8 @@ struct airq_t { + void *drv_data; + }; + +-static union indicator_t indicators[MAX_ISC]; +-static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; ++static union indicator_t indicators[MAX_ISC+1]; ++static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS]; + + static int register_airq(struct airq_t *airq, u8 isc) + { diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-02-zfcp_wait_sbal.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-02-zfcp_wait_sbal.patch new file mode 100644 index 000000000..6f6e60732 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-02-zfcp_wait_sbal.patch @@ -0,0 +1,85 @@ +From: Gerald Schaefer +Subject: zfcp: Fix locking problem found during port offline test +References: bnc#482818,LTC#51957 + +Symptom: Error message from lock dependency checker. +Problem: Softirqs not disabled. +Solution: Always disable softirqs when acquiring queue lock. + +Acked-by: John Jolly +--- + + drivers/s390/scsi/zfcp_fsf.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fsf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fsf.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fsf.c +@@ -927,8 +927,8 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_ + struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + +- spin_lock(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ spin_lock_bh(&adapter->req_q_lock); ++ if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, + req_flags, adapter->pool.fsf_req_abort); +@@ -959,7 +959,7 @@ out_error_free: + zfcp_fsf_req_free(req); + req = NULL; + out: +- spin_unlock(&adapter->req_q_lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return req; + } + +@@ -1223,7 +1223,7 @@ int zfcp_fsf_exchange_config_data(struct + int retval = -EIO; + + spin_lock_bh(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, + FSF_QTCB_EXCHANGE_CONFIG_DATA, +@@ -1319,7 +1319,7 @@ int zfcp_fsf_exchange_port_data(struct z + return -EOPNOTSUPP; + + spin_lock_bh(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, + ZFCP_REQ_AUTO_CLEANUP, +@@ -1365,7 +1365,7 @@ int zfcp_fsf_exchange_port_data_sync(str + return -EOPNOTSUPP; + + spin_lock_bh(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, +@@ -2458,8 +2458,8 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + ZFCP_STATUS_COMMON_UNBLOCKED))) + return NULL; + +- spin_lock(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ spin_lock_bh(&adapter->req_q_lock); ++ if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); +@@ -2493,7 +2493,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + zfcp_fsf_req_free(req); + req = NULL; + out: +- spin_unlock(&adapter->req_q_lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return req; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-03-zfcp_els_thread_context.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-03-zfcp_els_thread_context.patch new file mode 100644 index 000000000..27e0e2bce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-03-zfcp_els_thread_context.patch @@ -0,0 +1,148 @@ +From: Gerald Schaefer +Subject: zfcp: Send ELS ADISC from workqueue +References: bnc#482818,LTC#51958 + +Symptom: Remote port status change not handled + with high I/O load on other ports. +Problem: The ELS ADISC command used for checking + the remote port status could not be sent + because of a full request queue. +Solution: Move issing the ELS ADISC request to + a workqueue that can wait for a slot + in the request queue to become free. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 1 + + drivers/s390/scsi/zfcp_def.h | 1 + + drivers/s390/scsi/zfcp_ext.h | 1 + + drivers/s390/scsi/zfcp_fc.c | 28 ++++++++++++++++++---------- + drivers/s390/scsi/zfcp_fsf.c | 18 ++++++------------ + 5 files changed, 27 insertions(+), 22 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -611,6 +611,7 @@ struct zfcp_port *zfcp_port_enqueue(stru + init_waitqueue_head(&port->remove_wq); + INIT_LIST_HEAD(&port->unit_list_head); + INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); ++ INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); + + port->adapter = adapter; + port->d_id = d_id; +--- a/drivers/s390/scsi/zfcp_def.h ++++ b/drivers/s390/scsi/zfcp_def.h +@@ -539,6 +539,7 @@ struct zfcp_port { + u32 maxframe_size; + u32 supported_classes; + struct work_struct gid_pn_work; ++ struct work_struct test_link_work; + }; + + struct zfcp_unit { +--- a/drivers/s390/scsi/zfcp_ext.h ++++ b/drivers/s390/scsi/zfcp_ext.h +@@ -101,6 +101,7 @@ extern void zfcp_fc_incoming_els(struct + extern int zfcp_fc_ns_gid_pn(struct zfcp_erp_action *); + extern void zfcp_fc_plogi_evaluate(struct zfcp_port *, struct fsf_plogi *); + extern void zfcp_test_link(struct zfcp_port *); ++extern void zfcp_fc_link_test_work(struct work_struct *); + extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); + + /* zfcp_fsf.c */ +--- a/drivers/s390/scsi/zfcp_fc.c ++++ b/drivers/s390/scsi/zfcp_fc.c +@@ -415,19 +415,12 @@ static int zfcp_fc_adisc(struct zfcp_por + return zfcp_fsf_send_els(&adisc->els); + } + +-/** +- * zfcp_test_link - lightweight link test procedure +- * @port: port to be tested +- * +- * Test status of a link to a remote port using the ELS command ADISC. +- * If there is a problem with the remote port, error recovery steps +- * will be triggered. +- */ +-void zfcp_test_link(struct zfcp_port *port) ++void zfcp_fc_link_test_work(struct work_struct *work) + { ++ struct zfcp_port *port = ++ container_of(work, struct zfcp_port, test_link_work); + int retval; + +- zfcp_port_get(port); + retval = zfcp_fc_adisc(port); + if (retval == 0) + return; +@@ -438,6 +431,21 @@ void zfcp_test_link(struct zfcp_port *po + zfcp_erp_port_forced_reopen(port, 0, 65, NULL); + } + ++/** ++ * zfcp_test_link - lightweight link test procedure ++ * @port: port to be tested ++ * ++ * Test status of a link to a remote port using the ELS command ADISC. ++ * If there is a problem with the remote port, error recovery steps ++ * will be triggered. ++ */ ++void zfcp_test_link(struct zfcp_port *port) ++{ ++ zfcp_port_get(port); ++ if (!queue_work(zfcp_data.work_queue, &port->test_link_work)) ++ zfcp_port_put(port); ++} ++ + static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) + { + struct scatterlist *sg = &gpn_ft->sg_req; +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -654,14 +654,6 @@ static int zfcp_fsf_sbal_check(struct zf + return 0; + } + +-static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) +-{ +- unsigned int count = atomic_read(&adapter->req_q.count); +- if (!count) +- atomic_inc(&adapter->qdio_outb_full); +- return count > 0; +-} +- + static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) + { + long ret; +@@ -1177,8 +1169,8 @@ int zfcp_fsf_send_els(struct zfcp_send_e + ZFCP_STATUS_COMMON_UNBLOCKED))) + return -EBUSY; + +- spin_lock(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ spin_lock_bh(&adapter->req_q_lock); ++ if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, + ZFCP_REQ_AUTO_CLEANUP, NULL); +@@ -1211,7 +1203,7 @@ int zfcp_fsf_send_els(struct zfcp_send_e + failed_send: + zfcp_fsf_req_free(req); + out: +- spin_unlock(&adapter->req_q_lock); ++ spin_unlock_bh(&adapter->req_q_lock); + return ret; + } + +@@ -2336,8 +2328,10 @@ int zfcp_fsf_send_fcp_command_task(struc + return -EBUSY; + + spin_lock(&adapter->req_q_lock); +- if (!zfcp_fsf_sbal_available(adapter)) ++ if (atomic_read(&adapter->req_q.count) <= 0) { ++ atomic_inc(&adapter->qdio_outb_full); + goto out; ++ } + req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, + adapter->pool.fsf_req_scsi); + if (IS_ERR(req)) { diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-04-zfcp_change_adisc_processing.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-04-zfcp_change_adisc_processing.patch new file mode 100644 index 000000000..cee757736 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-04-zfcp_change_adisc_processing.patch @@ -0,0 +1,91 @@ +From: Gerald Schaefer +Subject: zfcp: incorrect reaction on incoming RSCN. +References: bnc#482818,LTC#51960 + +Symptom: After re-establishing a remote storage port connection + the port was never re-opened. +Problem: The port re-opening was prevented by a unfortunate + status flag combination, verification. +Solution: Fix the oddities in the processing on RSCN receiption. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_dbf.c | 4 ++-- + drivers/s390/scsi/zfcp_fc.c | 18 +++++++----------- + drivers/s390/scsi/zfcp_fsf.c | 4 ---- + 3 files changed, 9 insertions(+), 17 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fsf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fsf.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fsf.c +@@ -1165,10 +1165,6 @@ int zfcp_fsf_send_els(struct zfcp_send_e + struct fsf_qtcb_bottom_support *bottom; + int ret = -EIO; + +- if (unlikely(!(atomic_read(&els->port->status) & +- ZFCP_STATUS_COMMON_UNBLOCKED))) +- return -EBUSY; +- + spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; +Index: linux-sles11/drivers/s390/scsi/zfcp_dbf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_dbf.c ++++ linux-sles11/drivers/s390/scsi/zfcp_dbf.c +@@ -553,7 +553,7 @@ static const char *zfcp_rec_dbf_ids[] = + [61] = "", + [62] = "request timeout", + [63] = "adisc link test reject or timeout", +- [64] = "adisc link test d_id changed", ++ [64] = "adisc link test d_id changed or port not open", + [65] = "adisc link test failed", + [66] = "recovery out of memory", + [67] = "adapter recovery repeated after state change", +@@ -574,7 +574,7 @@ static const char *zfcp_rec_dbf_ids[] = + [79] = "link down", + [80] = "exclusive read-only unit access unsupported", + [81] = "shared read-write unit access unsupported", +- [82] = "incoming rscn", ++ [82] = "", + [83] = "incoming wwpn", + [84] = "wka port handle not valid close port", + [85] = "online", +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -122,16 +122,10 @@ static void _zfcp_fc_incoming_rscn(struc + struct zfcp_port *port; + + read_lock_irqsave(&zfcp_data.config_lock, flags); +- list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { +- if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_PHYS_OPEN)) +- /* Try to connect to unused ports anyway. */ +- zfcp_erp_port_reopen(port, +- ZFCP_STATUS_COMMON_ERP_FAILED, +- 82, fsf_req); +- else if ((port->d_id & range) == (elem->nport_did & range)) +- /* Check connection status for connected ports */ ++ list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) ++ if ((port->d_id & range) == (elem->nport_did & range)) + zfcp_test_link(port); +- } ++ + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + } + +@@ -375,8 +369,10 @@ static void zfcp_fc_adisc_handler(unsign + if (!port->wwnn) + port->wwnn = ls_adisc->wwnn; + +- if (port->wwpn != ls_adisc->wwpn) +- zfcp_erp_port_reopen(port, 0, 64, NULL); ++ if ((port->wwpn != ls_adisc->wwpn) || ++ !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) ++ zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 64, ++ NULL); + + out: + zfcp_port_put(port); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-05-zfcp_remote_port_handling.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-05-zfcp_remote_port_handling.patch new file mode 100644 index 000000000..f7ddd0fd7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-05-zfcp_remote_port_handling.patch @@ -0,0 +1,371 @@ +From: Gerald Schaefer +Subject: zfcp: Block remote ports (rports) early +References: bnc#482818,LTC#51961 + +Symptom: On path failover, the SCSI error recovery can set + SCSI devices offline. +Problem: For path failover to work correctly, the FC rports + in the Linux kernel have to be in the state BLOCKED. + This prevents SCSI timeouts from triggering the SCSI + error recovery. +Solution: On any problem (local link, remote port or any type + of error recovery) set the FC rports to BLOCKED early. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 2 + drivers/s390/scsi/zfcp_dbf.c | 1 + drivers/s390/scsi/zfcp_def.h | 2 + drivers/s390/scsi/zfcp_erp.c | 48 ++--------------- + drivers/s390/scsi/zfcp_ext.h | 4 + + drivers/s390/scsi/zfcp_fc.c | 20 ++++++- + drivers/s390/scsi/zfcp_fsf.c | 1 + drivers/s390/scsi/zfcp_scsi.c | 117 +++++++++++++++++++++++++++++++++++++++++- + 8 files changed, 149 insertions(+), 46 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -612,10 +612,12 @@ struct zfcp_port *zfcp_port_enqueue(stru + INIT_LIST_HEAD(&port->unit_list_head); + INIT_WORK(&port->gid_pn_work, zfcp_erp_port_strategy_open_lookup); + INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); ++ INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); + + port->adapter = adapter; + port->d_id = d_id; + port->wwpn = wwpn; ++ port->rport_task = RPORT_NONE; + + /* mark port unusable as long as sysfs registration is not complete */ + atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); +--- a/drivers/s390/scsi/zfcp_dbf.c ++++ b/drivers/s390/scsi/zfcp_dbf.c +@@ -644,6 +644,7 @@ static const char *zfcp_rec_dbf_ids[] = + [149] = "port scan", + [150] = "ptp attach", + [151] = "port validation failed", ++ [152] = "term rport io", + }; + + static int zfcp_rec_dbf_view_format(debug_info_t *id, struct debug_view *view, +--- a/drivers/s390/scsi/zfcp_def.h ++++ b/drivers/s390/scsi/zfcp_def.h +@@ -540,6 +540,8 @@ struct zfcp_port { + u32 supported_classes; + struct work_struct gid_pn_work; + struct work_struct test_link_work; ++ struct work_struct rport_work; ++ enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task; + }; + + struct zfcp_unit { +--- a/drivers/s390/scsi/zfcp_erp.c ++++ b/drivers/s390/scsi/zfcp_erp.c +@@ -239,6 +239,7 @@ static int _zfcp_erp_adapter_reopen(stru + int clear_mask, u8 id, void *ref) + { + zfcp_erp_adapter_block(adapter, clear_mask); ++ zfcp_scsi_schedule_rports_block(adapter); + + /* ensure propagation of failed status to new devices */ + if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { +@@ -319,6 +320,7 @@ static void _zfcp_erp_port_forced_reopen + int clear, u8 id, void *ref) + { + zfcp_erp_port_block(port, clear); ++ zfcp_scsi_schedule_rport_block(port); + + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + return; +@@ -350,6 +352,7 @@ static int _zfcp_erp_port_reopen(struct + void *ref) + { + zfcp_erp_port_block(port, clear); ++ zfcp_scsi_schedule_rport_block(port); + + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { + /* ensure propagation of failed status to new devices */ +@@ -1218,37 +1221,6 @@ static void zfcp_erp_schedule_work(struc + queue_work(zfcp_data.work_queue, &p->work); + } + +-static void zfcp_erp_rport_register(struct zfcp_port *port) +-{ +- struct fc_rport_identifiers ids; +- ids.node_name = port->wwnn; +- ids.port_name = port->wwpn; +- ids.port_id = port->d_id; +- ids.roles = FC_RPORT_ROLE_FCP_TARGET; +- port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); +- if (!port->rport) { +- dev_err(&port->adapter->ccw_device->dev, +- "Registering port 0x%016Lx failed\n", +- (unsigned long long)port->wwpn); +- return; +- } +- +- scsi_target_unblock(&port->rport->dev); +- port->rport->maxframe_size = port->maxframe_size; +- port->rport->supported_classes = port->supported_classes; +-} +- +-static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) +-{ +- struct zfcp_port *port; +- list_for_each_entry(port, &adapter->port_list_head, list) { +- if (!port->rport) +- continue; +- fc_remote_port_delete(port->rport); +- port->rport = NULL; +- } +-} +- + static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) + { + struct zfcp_adapter *adapter = act->adapter; +@@ -1257,8 +1229,8 @@ static void zfcp_erp_action_cleanup(stru + + switch (act->action) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: +- if ((result == ZFCP_ERP_SUCCEEDED) && +- !unit->device && port->rport) { ++ flush_work(&port->rport_work); ++ if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { + atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, + &unit->status); + if (!(atomic_read(&unit->status) & +@@ -1274,18 +1246,12 @@ static void zfcp_erp_action_cleanup(stru + zfcp_port_put(port); + return; + } +- if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport) +- zfcp_erp_rport_register(port); +- if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { +- fc_remote_port_delete(port->rport); +- port->rport = NULL; +- } ++ if (result == ZFCP_ERP_SUCCEEDED) ++ zfcp_scsi_schedule_rport_register(port); + zfcp_port_put(port); + break; + + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: +- if (result != ZFCP_ERP_SUCCEEDED) +- zfcp_erp_rports_del(adapter); + zfcp_adapter_put(adapter); + break; + } +--- a/drivers/s390/scsi/zfcp_ext.h ++++ b/drivers/s390/scsi/zfcp_ext.h +@@ -154,6 +154,10 @@ extern int zfcp_adapter_scsi_register(st + extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); + extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); + extern struct fc_function_template zfcp_transport_functions; ++extern void zfcp_scsi_rport_work(struct work_struct *); ++extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); ++extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); ++extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); + + /* zfcp_sysfs.c */ + extern struct attribute_group zfcp_sysfs_unit_attrs; +--- a/drivers/s390/scsi/zfcp_fc.c ++++ b/drivers/s390/scsi/zfcp_fc.c +@@ -370,9 +370,14 @@ static void zfcp_fc_adisc_handler(unsign + port->wwnn = ls_adisc->wwnn; + + if ((port->wwpn != ls_adisc->wwpn) || +- !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) ++ !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)) { + zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, 64, + NULL); ++ goto out; ++ } ++ ++ /* port is good, unblock rport without going through erp */ ++ zfcp_scsi_schedule_rport_register(port); + + out: + zfcp_port_put(port); +@@ -417,14 +422,23 @@ void zfcp_fc_link_test_work(struct work_ + container_of(work, struct zfcp_port, test_link_work); + int retval; + ++ if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) { ++ zfcp_port_put(port); ++ return; /* port erp is running and will update rport status */ ++ } ++ ++ zfcp_port_get(port); ++ port->rport_task = RPORT_DEL; ++ zfcp_scsi_rport_work(&port->rport_work); ++ + retval = zfcp_fc_adisc(port); + if (retval == 0) + return; + + /* send of ADISC was not possible */ ++ zfcp_erp_port_forced_reopen(port, 0, 65, NULL); ++ + zfcp_port_put(port); +- if (retval != -EBUSY) +- zfcp_erp_port_forced_reopen(port, 0, 65, NULL); + } + + /** +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -180,6 +180,7 @@ static void zfcp_fsf_link_down_info_eval + return; + + atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); ++ zfcp_scsi_schedule_rports_block(adapter); + + if (!link_down) + goto out; +--- a/drivers/s390/scsi/zfcp_scsi.c ++++ b/drivers/s390/scsi/zfcp_scsi.c +@@ -57,8 +57,8 @@ static int zfcp_scsi_queuecommand(struct + { + struct zfcp_unit *unit; + struct zfcp_adapter *adapter; +- int status; +- int ret; ++ int status, scsi_result, ret; ++ struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); + + /* reset the status for this request */ + scpnt->result = 0; +@@ -80,6 +80,14 @@ static int zfcp_scsi_queuecommand(struct + return 0; + } + ++ scsi_result = fc_remote_port_chkready(rport); ++ if (unlikely(scsi_result)) { ++ scpnt->result = scsi_result; ++ zfcp_scsi_dbf_event_result("fail", 4, adapter, scpnt, NULL); ++ scpnt->scsi_done(scpnt); ++ return 0; ++ } ++ + status = atomic_read(&unit->status); + if (unlikely((status & ZFCP_STATUS_COMMON_ERP_FAILED) || + !(status & ZFCP_STATUS_COMMON_RUNNING))) { +@@ -478,6 +486,109 @@ static void zfcp_set_rport_dev_loss_tmo( + rport->dev_loss_tmo = timeout; + } + ++/** ++ * zfcp_scsi_dev_loss_tmo_callbk - Free any reference to rport ++ * @rport: The rport that is about to be deleted. ++ */ ++static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) ++{ ++ struct zfcp_port *port = rport->dd_data; ++ ++ write_lock_irq(&zfcp_data.config_lock); ++ port->rport = NULL; ++ write_unlock_irq(&zfcp_data.config_lock); ++} ++ ++/** ++ * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport ++ * @rport: The FC rport where to teminate I/O ++ * ++ * Abort all pending SCSI commands for a port by closing the ++ * port. Using a reopen for avoids a conflict with a shutdown ++ * overwriting a reopen. ++ */ ++static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) ++{ ++ struct zfcp_port *port = rport->dd_data; ++ ++ zfcp_erp_port_reopen(port, 0, 152, NULL); ++} ++ ++static void zfcp_scsi_rport_register(struct zfcp_port *port) ++{ ++ struct fc_rport_identifiers ids; ++ struct fc_rport *rport; ++ ++ ids.node_name = port->wwnn; ++ ids.port_name = port->wwpn; ++ ids.port_id = port->d_id; ++ ids.roles = FC_RPORT_ROLE_FCP_TARGET; ++ ++ rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); ++ if (!rport) { ++ dev_err(&port->adapter->ccw_device->dev, ++ "Registering port 0x%016Lx failed\n", ++ (unsigned long long)port->wwpn); ++ return; ++ } ++ ++ rport->dd_data = port; ++ rport->maxframe_size = port->maxframe_size; ++ rport->supported_classes = port->supported_classes; ++ port->rport = rport; ++} ++ ++static void zfcp_scsi_rport_block(struct zfcp_port *port) ++{ ++ if (port->rport) ++ fc_remote_port_delete(port->rport); ++} ++ ++void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) ++{ ++ zfcp_port_get(port); ++ port->rport_task = RPORT_ADD; ++ ++ if (!queue_work(zfcp_data.work_queue, &port->rport_work)) ++ zfcp_port_put(port); ++} ++ ++void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) ++{ ++ zfcp_port_get(port); ++ port->rport_task = RPORT_DEL; ++ ++ if (!queue_work(zfcp_data.work_queue, &port->rport_work)) ++ zfcp_port_put(port); ++} ++ ++void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) ++{ ++ struct zfcp_port *port; ++ ++ list_for_each_entry(port, &adapter->port_list_head, list) ++ zfcp_scsi_schedule_rport_block(port); ++} ++ ++void zfcp_scsi_rport_work(struct work_struct *work) ++{ ++ struct zfcp_port *port = container_of(work, struct zfcp_port, ++ rport_work); ++ ++ while (port->rport_task) { ++ if (port->rport_task == RPORT_ADD) { ++ port->rport_task = RPORT_NONE; ++ zfcp_scsi_rport_register(port); ++ } else { ++ port->rport_task = RPORT_NONE; ++ zfcp_scsi_rport_block(port); ++ } ++ } ++ ++ zfcp_port_put(port); ++} ++ ++ + struct fc_function_template zfcp_transport_functions = { + .show_starget_port_id = 1, + .show_starget_port_name = 1, +@@ -496,6 +607,8 @@ struct fc_function_template zfcp_transpo + .reset_fc_host_stats = zfcp_reset_fc_host_stats, + .set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo, + .get_host_port_state = zfcp_get_host_port_state, ++ .dev_loss_tmo_callbk = zfcp_scsi_dev_loss_tmo_callbk, ++ .terminate_rport_io = zfcp_scsi_terminate_rport_io, + .show_host_port_state = 1, + /* no functions registered for following dynamic attributes but + directly set by LLDD */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-06-zfcp_slave_destroy.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-06-zfcp_slave_destroy.patch new file mode 100644 index 000000000..d4c655b26 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-06-zfcp_slave_destroy.patch @@ -0,0 +1,27 @@ +From: Gerald Schaefer +Subject: zfcp: erp failed status bit will not be set +References: bnc#482818,LTC#51962 + +Problem: It will not be necessary to set the erp failed status bit + in case a scsi device is removed by the scsi mid layer. + In the case a scsi device is unavailable for a short time + (15 to 20 seconds) a FCP unit will not get on-line again. +Solution: Do not change the status bits if slave destroy is called. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_scsi.c | 1 - + 1 file changed, 1 deletion(-) + +Index: linux/drivers/s390/scsi/zfcp_scsi.c +=================================================================== +--- linux.orig/drivers/s390/scsi/zfcp_scsi.c ++++ linux/drivers/s390/scsi/zfcp_scsi.c +@@ -28,7 +28,6 @@ static void zfcp_scsi_slave_destroy(stru + struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; + atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); + unit->device = NULL; +- zfcp_erp_unit_failed(unit, 12, NULL); + zfcp_unit_put(unit); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-07-zfcp_refc_work_inflight.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-07-zfcp_refc_work_inflight.patch new file mode 100644 index 000000000..2c4b12d6b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-07-zfcp_refc_work_inflight.patch @@ -0,0 +1,59 @@ +From: Gerald Schaefer +Subject: zfcp: fix queue, scheduled work processing. +References: bnc#482818,LTC#51963 + +Symptom: A nonexisting device might get referenced by a task. +Problem: An asynchronous scheduled work might get executed + at a time the originating device is already removed. +Solution: Secure all devices by proper ref-counting and cancel + outstanding work before device-removal. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 1 + + drivers/s390/scsi/zfcp_erp.c | 10 +++++++--- + 2 files changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -553,6 +553,7 @@ void zfcp_adapter_dequeue(struct zfcp_ad + + cancel_work_sync(&adapter->scan_work); + cancel_work_sync(&adapter->stat_work); ++ cancel_delayed_work_sync(&adapter->nsp.work); + zfcp_adapter_scsi_unregister(adapter); + sysfs_remove_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs); +--- a/drivers/s390/scsi/zfcp_erp.c ++++ b/drivers/s390/scsi/zfcp_erp.c +@@ -859,7 +859,7 @@ void zfcp_erp_port_strategy_open_lookup( + port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; + if (retval) + zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); +- ++ zfcp_port_put(port); + } + + static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) +@@ -875,7 +875,10 @@ static int zfcp_erp_port_strategy_open_c + if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) + return zfcp_erp_open_ptp_port(act); + if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { +- queue_work(zfcp_data.work_queue, &port->gid_pn_work); ++ zfcp_port_get(port); ++ if (!queue_work(zfcp_data.work_queue, ++ &port->gid_pn_work)) ++ zfcp_port_put(port); + return ZFCP_ERP_CONTINUES; + } + case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: +@@ -1218,7 +1221,8 @@ static void zfcp_erp_schedule_work(struc + atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + INIT_WORK(&p->work, zfcp_erp_scsi_scan); + p->unit = unit; +- queue_work(zfcp_data.work_queue, &p->work); ++ if (!queue_work(zfcp_data.work_queue, &p->work)) ++ zfcp_unit_put(unit); + } + + static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-08-iucv-2ndparm.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-08-iucv-2ndparm.patch new file mode 100644 index 000000000..0f2d24de1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-08-iucv-2ndparm.patch @@ -0,0 +1,155 @@ +From: Gerald Schaefer +Subject: iucv: provide second per-cpu IUCV command parameter block +References: bnc#482818,LTC#52502 + +Symptom: failing connect during cpu hotplugging +Problem: Some of the IUCV commands can be invoked in interrupt + context. If they use the same per-cpu IUCV command + parameter block as another IUCV command invoked in + process context and running in parallel, the IUCV command + parameter of the not yet finished IUCV command invocation + in process context might be overwritten. +Solution: Provide a different per-cpu IUCV command parameter block + for IUCV commands that can be invoked in interrupt + context. + +Acked-by: John Jolly +--- + + net/iucv/iucv.c | 41 +++++++++++++++++++++++++++++++---------- + 1 file changed, 31 insertions(+), 10 deletions(-) + +Index: linux-sles11/net/iucv/iucv.c +=================================================================== +--- linux-sles11.orig/net/iucv/iucv.c ++++ linux-sles11/net/iucv/iucv.c +@@ -280,6 +280,7 @@ union iucv_param { + * Anchor for per-cpu IUCV command parameter block. + */ + static union iucv_param *iucv_param[NR_CPUS]; ++static union iucv_param *iucv_param_irq[NR_CPUS]; + + /** + * iucv_call_b2f0 +@@ -358,7 +359,7 @@ static void iucv_allow_cpu(void *data) + * 0x10 - Flag to allow priority message completion interrupts + * 0x08 - Flag to allow IUCV control interrupts + */ +- parm = iucv_param[cpu]; ++ parm = iucv_param_irq[cpu]; + memset(parm, 0, sizeof(union iucv_param)); + parm->set_mask.ipmask = 0xf8; + iucv_call_b2f0(IUCV_SETMASK, parm); +@@ -379,7 +380,7 @@ static void iucv_block_cpu(void *data) + union iucv_param *parm; + + /* Disable all iucv interrupts. */ +- parm = iucv_param[cpu]; ++ parm = iucv_param_irq[cpu]; + memset(parm, 0, sizeof(union iucv_param)); + iucv_call_b2f0(IUCV_SETMASK, parm); + +@@ -403,7 +404,7 @@ static void iucv_declare_cpu(void *data) + return; + + /* Declare interrupt buffer. */ +- parm = iucv_param[cpu]; ++ parm = iucv_param_irq[cpu]; + memset(parm, 0, sizeof(union iucv_param)); + parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); + rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); +@@ -460,7 +461,7 @@ static void iucv_retrieve_cpu(void *data + iucv_block_cpu(NULL); + + /* Retrieve interrupt buffer. */ +- parm = iucv_param[cpu]; ++ parm = iucv_param_irq[cpu]; + iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); + + /* Clear indication that an iucv buffer exists for this cpu. */ +@@ -574,11 +575,22 @@ static int __cpuinit iucv_cpu_notify(str + iucv_irq_data[cpu] = NULL; + return NOTIFY_BAD; + } ++ iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), ++ GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); ++ if (!iucv_param_irq[cpu]) { ++ kfree(iucv_param[cpu]); ++ iucv_param[cpu] = NULL; ++ kfree(iucv_irq_data[cpu]); ++ iucv_irq_data[cpu] = NULL; ++ return NOTIFY_BAD; ++ } + break; + case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: + case CPU_DEAD: + case CPU_DEAD_FROZEN: ++ kfree(iucv_param_irq[cpu]); ++ iucv_param_irq[cpu] = NULL; + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); +@@ -625,7 +637,7 @@ static int iucv_sever_pathid(u16 pathid, + { + union iucv_param *parm; + +- parm = iucv_param[smp_processor_id()]; ++ parm = iucv_param_irq[smp_processor_id()]; + memset(parm, 0, sizeof(union iucv_param)); + if (userdata) + memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); +@@ -918,10 +930,8 @@ int iucv_path_sever(struct iucv_path *pa + if (iucv_active_cpu != smp_processor_id()) + spin_lock_bh(&iucv_table_lock); + rc = iucv_sever_pathid(path->pathid, userdata); +- if (!rc) { +- iucv_path_table[path->pathid] = NULL; +- list_del_init(&path->list); +- } ++ iucv_path_table[path->pathid] = NULL; ++ list_del_init(&path->list); + if (iucv_active_cpu != smp_processor_id()) + spin_unlock_bh(&iucv_table_lock); + preempt_enable(); +@@ -1333,7 +1343,7 @@ static void iucv_path_severed(struct iuc + else { + iucv_sever_pathid(path->pathid, NULL); + iucv_path_table[path->pathid] = NULL; +- list_del_init(&path->list); ++ list_del(&path->list); + iucv_path_free(path); + } + } +@@ -1637,6 +1647,13 @@ static int __init iucv_init(void) + rc = -ENOMEM; + goto out_free; + } ++ iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), ++ GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); ++ if (!iucv_param_irq[cpu]) { ++ rc = -ENOMEM; ++ goto out_free; ++ } ++ + } + rc = register_hotcpu_notifier(&iucv_cpu_notifier); + if (rc) +@@ -1654,6 +1671,8 @@ out_cpu: + unregister_hotcpu_notifier(&iucv_cpu_notifier); + out_free: + for_each_possible_cpu(cpu) { ++ kfree(iucv_param_irq[cpu]); ++ iucv_param_irq[cpu] = NULL; + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); +@@ -1684,6 +1703,8 @@ static void __exit iucv_exit(void) + spin_unlock_irq(&iucv_queue_lock); + unregister_hotcpu_notifier(&iucv_cpu_notifier); + for_each_possible_cpu(cpu) { ++ kfree(iucv_param_irq[cpu]); ++ iucv_param_irq[cpu] = NULL; + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-09-dasd-fix-timer-add.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-09-dasd-fix-timer-add.patch new file mode 100644 index 000000000..159695774 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-09-dasd-fix-timer-add.patch @@ -0,0 +1,119 @@ +From: Gerald Schaefer +Subject: dasd: fix race in dasd timer handling +References: bnc#482818,LTC#52092 + +Symptom: DASD driver runs into BUG statement in add_timer +Problem: If the timer expires just after we check whether it is + still pending and before mod_timer is called, then + mod_timer will setup the timer, return zero and add_timer + will be called as well although the timer is already set. +Solution: Initialize the timer variables at device creation time + and remove all timer_pending checks from dasd functions. + del_timer and mod_timer will do all the necessary + checking themselves and mod_timer will set a timer if it + is not already pending. + +Acked-by: John Jolly +--- + drivers/s390/block/dasd.c | 46 ++++++++++++++++------------------------------ + 1 file changed, 16 insertions(+), 30 deletions(-) + +Index: linux-sles11/drivers/s390/block/dasd.c +=================================================================== +--- linux-sles11.orig/drivers/s390/block/dasd.c ++++ linux-sles11/drivers/s390/block/dasd.c +@@ -57,6 +57,8 @@ static void dasd_device_tasklet(struct d + static void dasd_block_tasklet(struct dasd_block *); + static void do_kick_device(struct work_struct *); + static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); ++static void dasd_device_timeout(unsigned long); ++static void dasd_block_timeout(unsigned long); + + /* + * SECTION: Operations on the device structure. +@@ -99,6 +101,8 @@ struct dasd_device *dasd_alloc_device(vo + (unsigned long) device); + INIT_LIST_HEAD(&device->ccw_queue); + init_timer(&device->timer); ++ device->timer.function = dasd_device_timeout; ++ device->timer.data = (unsigned long) device; + INIT_WORK(&device->kick_work, do_kick_device); + device->state = DASD_STATE_NEW; + device->target = DASD_STATE_NEW; +@@ -138,6 +142,8 @@ struct dasd_block *dasd_alloc_block(void + INIT_LIST_HEAD(&block->ccw_queue); + spin_lock_init(&block->queue_lock); + init_timer(&block->timer); ++ block->timer.function = dasd_block_timeout; ++ block->timer.data = (unsigned long) block; + + return block; + } +@@ -923,19 +929,10 @@ static void dasd_device_timeout(unsigned + */ + void dasd_device_set_timer(struct dasd_device *device, int expires) + { +- if (expires == 0) { +- if (timer_pending(&device->timer)) +- del_timer(&device->timer); +- return; +- } +- if (timer_pending(&device->timer)) { +- if (mod_timer(&device->timer, jiffies + expires)) +- return; +- } +- device->timer.function = dasd_device_timeout; +- device->timer.data = (unsigned long) device; +- device->timer.expires = jiffies + expires; +- add_timer(&device->timer); ++ if (expires == 0) ++ del_timer(&device->timer); ++ else ++ mod_timer(&device->timer, jiffies + expires); + } + + /* +@@ -943,8 +940,7 @@ void dasd_device_set_timer(struct dasd_d + */ + void dasd_device_clear_timer(struct dasd_device *device) + { +- if (timer_pending(&device->timer)) +- del_timer(&device->timer); ++ del_timer(&device->timer); + } + + static void dasd_handle_killed_request(struct ccw_device *cdev, +@@ -1594,19 +1590,10 @@ static void dasd_block_timeout(unsigned + */ + void dasd_block_set_timer(struct dasd_block *block, int expires) + { +- if (expires == 0) { +- if (timer_pending(&block->timer)) +- del_timer(&block->timer); +- return; +- } +- if (timer_pending(&block->timer)) { +- if (mod_timer(&block->timer, jiffies + expires)) +- return; +- } +- block->timer.function = dasd_block_timeout; +- block->timer.data = (unsigned long) block; +- block->timer.expires = jiffies + expires; +- add_timer(&block->timer); ++ if (expires == 0) ++ del_timer(&block->timer); ++ else ++ mod_timer(&block->timer, jiffies + expires); + } + + /* +@@ -1614,8 +1601,7 @@ void dasd_block_set_timer(struct dasd_bl + */ + void dasd_block_clear_timer(struct dasd_block *block) + { +- if (timer_pending(&block->timer)) +- del_timer(&block->timer); ++ del_timer(&block->timer); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-10-10-ccwgroup_fix_unbind.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-10-10-ccwgroup_fix_unbind.patch new file mode 100644 index 000000000..1a64b9058 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-10-10-ccwgroup_fix_unbind.patch @@ -0,0 +1,153 @@ +From: Gerald Schaefer +Subject: cio: ccwgroup - fix unbind behaviour +References: bnc#482818,LTC#52098 + +Symptom: Oops after unbinding a ccwgroup device. +Problem: There is no special callback to tell a driver to unbind + a device - the normal remove is called. In this case + the device remains partly registered in the driver core. +Solution: Use a bus notifier function to handle this special case + and call ungroup since this virtual device can not exist + without a driver. + +Acked-by: John Jolly +--- + drivers/s390/cio/ccwgroup.c | 73 +++++++++++++++++++++++++++++++++----------- + 1 file changed, 56 insertions(+), 17 deletions(-) + +Index: linux-sles11/drivers/s390/cio/ccwgroup.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/ccwgroup.c 2009-03-09 15:36:56.000000000 +0100 ++++ linux-sles11/drivers/s390/cio/ccwgroup.c 2009-03-09 15:53:56.000000000 +0100 +@@ -313,16 +313,32 @@ error: + } + EXPORT_SYMBOL(ccwgroup_create_from_string); + +-static int __init +-init_ccwgroup (void) ++static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, ++ void *data); ++ ++static struct notifier_block ccwgroup_nb = { ++ .notifier_call = ccwgroup_notifier ++}; ++ ++static int __init init_ccwgroup(void) + { +- return bus_register (&ccwgroup_bus_type); ++ int ret; ++ ++ ret = bus_register(&ccwgroup_bus_type); ++ if (ret) ++ return ret; ++ ++ ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb); ++ if (ret) ++ bus_unregister(&ccwgroup_bus_type); ++ ++ return ret; + } + +-static void __exit +-cleanup_ccwgroup (void) ++static void __exit cleanup_ccwgroup(void) + { +- bus_unregister (&ccwgroup_bus_type); ++ bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb); ++ bus_unregister(&ccwgroup_bus_type); + } + + module_init(init_ccwgroup); +@@ -390,27 +406,28 @@ ccwgroup_online_store (struct device *de + unsigned long value; + int ret; + +- gdev = to_ccwgroupdev(dev); + if (!dev->driver) +- return count; ++ return -ENODEV; ++ ++ gdev = to_ccwgroupdev(dev); ++ gdrv = to_ccwgroupdrv(dev->driver); + +- gdrv = to_ccwgroupdrv (gdev->dev.driver); + if (!try_module_get(gdrv->owner)) + return -EINVAL; + + ret = strict_strtoul(buf, 0, &value); + if (ret) + goto out; +- ret = count; ++ + if (value == 1) +- ccwgroup_set_online(gdev); ++ ret = ccwgroup_set_online(gdev); + else if (value == 0) +- ccwgroup_set_offline(gdev); ++ ret = ccwgroup_set_offline(gdev); + else + ret = -EINVAL; + out: + module_put(gdrv->owner); +- return ret; ++ return (ret == 0) ? count : ret; + } + + static ssize_t +@@ -452,13 +469,18 @@ ccwgroup_remove (struct device *dev) + struct ccwgroup_device *gdev; + struct ccwgroup_driver *gdrv; + ++ device_remove_file(dev, &dev_attr_online); ++ device_remove_file(dev, &dev_attr_ungroup); ++ ++ if (!dev->driver) ++ return 0; ++ + gdev = to_ccwgroupdev(dev); + gdrv = to_ccwgroupdrv(dev->driver); + +- device_remove_file(dev, &dev_attr_online); +- +- if (gdrv && gdrv->remove) ++ if (gdrv->remove) + gdrv->remove(gdev); ++ + return 0; + } + +@@ -467,9 +489,13 @@ static void ccwgroup_shutdown(struct dev + struct ccwgroup_device *gdev; + struct ccwgroup_driver *gdrv; + ++ if (!dev->driver) ++ return; ++ + gdev = to_ccwgroupdev(dev); + gdrv = to_ccwgroupdrv(dev->driver); +- if (gdrv && gdrv->shutdown) ++ ++ if (gdrv->shutdown) + gdrv->shutdown(gdev); + } + +@@ -482,6 +508,19 @@ static struct bus_type ccwgroup_bus_type + .shutdown = ccwgroup_shutdown, + }; + ++ ++static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, ++ void *data) ++{ ++ struct device *dev = data; ++ ++ if (action == BUS_NOTIFY_UNBIND_DRIVER) ++ device_schedule_callback(dev, ccwgroup_ungroup_callback); ++ ++ return NOTIFY_OK; ++} ++ ++ + /** + * ccwgroup_driver_register() - register a ccw group driver + * @cdriver: driver to be registered diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-01-kernel_ds_pgtable_walk.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-01-kernel_ds_pgtable_walk.patch new file mode 100644 index 000000000..0d162aaef --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-01-kernel_ds_pgtable_walk.patch @@ -0,0 +1,110 @@ +From: Gerald Schaefer +Subject: kernel: don't use pagetable walk for KERNEL_DS +References: bnc#484767,LTC#52176 + +Symptom: Access to KERNEL_DS via usercopy functions is very slow on + pre z9 hardware. +Problem: The usercopy functions do a pagetable walk even if KERNEL_DS + is set on pre z9 hardware. This was a workaroud for a common + code bug in SLES 11. +Solution: Don't use pagetable walk for KERNEL_DS as the common code bug + has been fixed in SLES 11 GMC. + +Acked-by: John Jolly +--- + arch/s390/lib/uaccess_pt.c | 32 +++++++++++++++++++++++++------- + 1 file changed, 25 insertions(+), 7 deletions(-) + +Index: linux-sles11/arch/s390/lib/uaccess_pt.c +=================================================================== +--- linux-sles11.orig/arch/s390/lib/uaccess_pt.c ++++ linux-sles11/arch/s390/lib/uaccess_pt.c +@@ -43,9 +43,8 @@ static int __handle_fault(struct mm_stru + int ret = -EFAULT; + int fault; + +- if (in_atomic() || segment_eq(get_fs(), KERNEL_DS)) ++ if (in_atomic()) + return ret; +- + down_read(&mm->mmap_sem); + vma = find_vma(mm, address); + if (unlikely(!vma)) +@@ -110,8 +109,6 @@ static size_t __user_copy_pt(unsigned lo + pte_t *pte; + void *from, *to; + +- if (segment_eq(get_fs(), KERNEL_DS)) +- mm = &init_mm; + done = 0; + retry: + spin_lock(&mm->page_table_lock); +@@ -185,6 +182,10 @@ size_t copy_from_user_pt(size_t n, const + { + size_t rc; + ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ memcpy(to, (void __kernel __force *) from, n); ++ return 0; ++ } + rc = __user_copy_pt((unsigned long) from, to, n, 0); + if (unlikely(rc)) + memset(to + n - rc, 0, rc); +@@ -193,6 +194,10 @@ size_t copy_from_user_pt(size_t n, const + + size_t copy_to_user_pt(size_t n, void __user *to, const void *from) + { ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ memcpy((void __kernel __force *) to, from, n); ++ return 0; ++ } + return __user_copy_pt((unsigned long) to, (void *) from, n, 1); + } + +@@ -200,6 +205,10 @@ static size_t clear_user_pt(size_t n, vo + { + long done, size, ret; + ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ memset((void __kernel __force *) to, 0, n); ++ return 0; ++ } + done = 0; + do { + if (n - done > PAGE_SIZE) +@@ -225,7 +234,7 @@ static size_t strnlen_user_pt(size_t cou + size_t len_str; + + if (segment_eq(get_fs(), KERNEL_DS)) +- mm = &init_mm; ++ return strnlen((const char __kernel __force *) src, count) + 1; + done = 0; + retry: + spin_lock(&mm->page_table_lock); +@@ -267,6 +276,13 @@ static size_t strncpy_from_user_pt(size_ + return -EFAULT; + if (n > count) + n = count; ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ memcpy(dst, (const char __kernel __force *) src, n); ++ if (dst[n-1] == '\0') ++ return n-1; ++ else ++ return n; ++ } + if (__user_copy_pt((unsigned long) src, dst, n, 0)) + return -EFAULT; + if (dst[n-1] == '\0') +@@ -286,8 +302,10 @@ static size_t copy_in_user_pt(size_t n, + pte_t *pte_from, *pte_to; + int write_user; + +- if (segment_eq(get_fs(), KERNEL_DS)) +- mm = &init_mm; ++ if (segment_eq(get_fs(), KERNEL_DS)) { ++ memcpy((void __force *) to, (void __force *) from, n); ++ return 0; ++ } + done = 0; + retry: + spin_lock(&mm->page_table_lock); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-02-kernel_pfn_valid_uaccess.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-02-kernel_pfn_valid_uaccess.patch new file mode 100644 index 000000000..dbcdd3446 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-02-kernel_pfn_valid_uaccess.patch @@ -0,0 +1,89 @@ +From: Gerald Schaefer +Subject: kernel: don't check for pfn_valid() in uaccess_pt.c +References: bnc#484767,LTC#52175 + +Symptom: Access to xip mappings fails (-EFAULT). +Problem: pfn_valid() actually checks for a valid struct page and + not for a valid pfn. Using xip mappings w/o struct pages, + this will result in -EFAULT returned by the (page table + walk) user copy functions, even though there is valid memory. +Solution: Those user copy functions don't need a struct page, so this + patch just removes the pfn_valid() check. + +Acked-by: John Jolly +--- + arch/s390/lib/uaccess_pt.c | 18 ------------------ + 1 file changed, 18 deletions(-) + +Index: linux-sles11/arch/s390/lib/uaccess_pt.c +=================================================================== +--- linux-sles11.orig/arch/s390/lib/uaccess_pt.c ++++ linux-sles11/arch/s390/lib/uaccess_pt.c +@@ -119,8 +119,6 @@ retry: + goto fault; + + pfn = pte_pfn(*pte); +- if (!pfn_valid(pfn)) +- goto out; + + offset = uaddr & (PAGE_SIZE - 1); + size = min(n - done, PAGE_SIZE - offset); +@@ -135,7 +133,6 @@ retry: + done += size; + uaddr += size; + } while (done < n); +-out: + spin_unlock(&mm->page_table_lock); + return n - done; + fault: +@@ -163,9 +160,6 @@ retry: + goto fault; + + pfn = pte_pfn(*pte); +- if (!pfn_valid(pfn)) +- goto out; +- + ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1)); + out: + return ret; +@@ -244,11 +238,6 @@ retry: + goto fault; + + pfn = pte_pfn(*pte); +- if (!pfn_valid(pfn)) { +- done = -1; +- goto out; +- } +- + offset = uaddr & (PAGE_SIZE-1); + addr = (char *)(pfn << PAGE_SHIFT) + offset; + len = min(count - done, PAGE_SIZE - offset); +@@ -256,7 +245,6 @@ retry: + done += len_str; + uaddr += len_str; + } while ((len_str == len) && (done < count)); +-out: + spin_unlock(&mm->page_table_lock); + return done + 1; + fault: +@@ -325,12 +313,7 @@ retry: + } + + pfn_from = pte_pfn(*pte_from); +- if (!pfn_valid(pfn_from)) +- goto out; + pfn_to = pte_pfn(*pte_to); +- if (!pfn_valid(pfn_to)) +- goto out; +- + offset_from = uaddr_from & (PAGE_SIZE-1); + offset_to = uaddr_from & (PAGE_SIZE-1); + offset_max = max(offset_from, offset_to); +@@ -342,7 +325,6 @@ retry: + uaddr_from += size; + uaddr_to += size; + } while (done < n); +-out: + spin_unlock(&mm->page_table_lock); + return n - done; + fault: diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-03-qeth_recovery_drop_mac.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-03-qeth_recovery_drop_mac.patch new file mode 100644 index 000000000..4b1313fc3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-03-qeth_recovery_drop_mac.patch @@ -0,0 +1,37 @@ +From: Gerald Schaefer +Subject: qeth: unregister MAC addresses during recovery. +References: bnc#484767,LTC#52200 + +Symptom: After thousands of recovery cycles no more MAC addresses are +registered at z/VM GuestLAN adapter. +Problem: MAC address table of GuestLAN adapter full. +Solution: Unregister MAC addresses from device (layer 2) during +recovery cycle. When the device is set online the MAC +addresses are registered again on the device. + +Acked-by: John Jolly +--- +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -388,7 +388,8 @@ static int qeth_l2_stop_card(struct qeth + dev_close(card->dev); + rtnl_unlock(); + } +- if (!card->use_hard_stop) { ++ if (!card->use_hard_stop || ++ recovery_mode) { + __u8 *mac = &card->dev->dev_addr[0]; + rc = qeth_l2_send_delmac(card, mac); + QETH_DBF_TEXT_(SETUP, 2, "Lerr%d", rc); +@@ -397,7 +398,8 @@ static int qeth_l2_stop_card(struct qeth + } + if (card->state == CARD_STATE_SOFTSETUP) { + qeth_l2_process_vlans(card, 1); +- if (!card->use_hard_stop) ++ if (!card->use_hard_stop || ++ recovery_mode) + qeth_l2_del_all_mc(card); + qeth_clear_ipacmd_list(card); + card->state = CARD_STATE_HARDSETUP; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-04-lcs_hard_sx_rc.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-04-lcs_hard_sx_rc.patch new file mode 100644 index 000000000..aac6f8df1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-04-lcs_hard_sx_rc.patch @@ -0,0 +1,33 @@ +From: Gerald Schaefer +Subject: lcs: invalid return codes from hard_start_xmit. +References: bnc#484767,LTC#52201 + +Symptom: Messages about invalid return codes in /var/log/messages. The data +transmission works ok. +Problem: LCS hard_start_xmit returns non-standard Return Codes. +Solution: Now lcs returns only either NETDEV_TX_OK or NETDEV_TX_BUSY. + +Acked-by: John Jolly +--- +Index: linux-sles11/drivers/s390/net/lcs.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/lcs.c ++++ linux-sles11/drivers/s390/net/lcs.c +@@ -1553,7 +1553,7 @@ __lcs_start_xmit(struct lcs_card *card, + if (skb == NULL) { + card->stats.tx_dropped++; + card->stats.tx_errors++; +- return -EIO; ++ return 0; + } + if (card->state != DEV_STATE_UP) { + dev_kfree_skb(skb); +@@ -1578,7 +1578,7 @@ __lcs_start_xmit(struct lcs_card *card, + card->tx_buffer = lcs_get_buffer(&card->write); + if (card->tx_buffer == NULL) { + card->stats.tx_dropped++; +- rc = -EBUSY; ++ rc = NETDEV_TX_BUSY; + goto out; + } + card->tx_buffer->callback = lcs_txbuffer_cb; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-05-qdio_error_reporting_hs.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-05-qdio_error_reporting_hs.patch new file mode 100644 index 000000000..b5dc45f3e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-05-qdio_error_reporting_hs.patch @@ -0,0 +1,350 @@ +From: Gerald Schaefer +Subject: qdio: fix hipersocket busy error handling +References: bnc#484767,LTC#52204 + +Symptom: Lower performance of hipersocket connections in case of + busy errors. +Problem: The immediate retry for a busy condition is missing and the + qeth notification about a failed send operation may indicate + a wrong buffer position since a temporary SIGA error is not + reported immediately. +Solution: Retry immediately after a busy condition and report SIGA errors + directly to qeth. + +Acked-by: John Jolly +--- + drivers/s390/cio/qdio.h | 7 - + drivers/s390/cio/qdio_main.c | 181 ++++++++++++++----------------------------- + 2 files changed, 63 insertions(+), 125 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/s390/cio/qdio.h ++++ linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio.h +@@ -14,7 +14,6 @@ + #include "chsc.h" + + #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ +-#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */ + #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ + + /* +@@ -195,12 +194,6 @@ struct qdio_input_q { + }; + + struct qdio_output_q { +- /* failed siga-w attempts*/ +- atomic_t busy_siga_counter; +- +- /* start time of busy condition */ +- u64 timestamp; +- + /* PCIs are enabled for the queue */ + int pci_out_enabled; + +Index: linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/s390/cio/qdio_main.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/s390/cio/qdio_main.c +@@ -74,7 +74,7 @@ static inline int do_siga_input(struct s + * Note: For IQDC unicast queues only the highest priority queue is processed. + */ + static inline int do_siga_output(unsigned long schid, unsigned long mask, +- u32 *bb, unsigned int fc) ++ unsigned int *bb, unsigned int fc) + { + register unsigned long __fc asm("0") = fc; + register unsigned long __schid asm("1") = schid; +@@ -278,8 +278,7 @@ static int qdio_siga_sync(struct qdio_q + if (!need_siga_sync(q)) + return 0; + +- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:"); +- DBF_DEV_HEX(DBF_INFO, q->irq_ptr, q, sizeof(void *)); ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); + qdio_perf_stat_inc(&perf_stats.siga_sync); + + cc = do_siga_sync(q->irq_ptr->schid, output, input); +@@ -306,43 +305,34 @@ static inline int qdio_siga_sync_all(str + return qdio_siga_sync(q, ~0U, ~0U); + } + +-static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit) ++static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) + { +- unsigned int fc = 0; + unsigned long schid; ++ unsigned int fc = 0; ++ u64 start_time = 0; ++ int cc; + +- if (!is_qebsm(q)) +- schid = *((u32 *)&q->irq_ptr->schid); +- else { ++ if (is_qebsm(q)) { + schid = q->irq_ptr->sch_token; + fc |= 0x80; + } +- return do_siga_output(schid, q->mask, busy_bit, fc); +-} +- +-static int qdio_siga_output(struct qdio_q *q) +-{ +- int cc; +- u32 busy_bit; +- u64 start_time = 0; ++ else ++ schid = *((u32 *)&q->irq_ptr->schid); + +- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); +- qdio_perf_stat_inc(&perf_stats.siga_out); + again: +- cc = qdio_do_siga_output(q, &busy_bit); +- if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) { +- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w bb:%2d", q->nr); ++ cc = do_siga_output(schid, q->mask, busy_bit, fc); + +- if (!start_time) ++ /* hipersocket busy condition */ ++ if (*busy_bit) { ++ WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); ++ ++ if (!start_time) { + start_time = get_usecs(); +- else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) ++ goto again; ++ } ++ if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) + goto again; + } +- +- if (cc == 2 && busy_bit) +- cc |= QDIO_ERROR_SIGA_BUSY; +- if (cc) +- DBF_ERROR("%4x SIGA-W:%2d", SCH_NO(q), cc); + return cc; + } + +@@ -390,7 +380,7 @@ inline void qdio_stop_polling(struct qdi + + static void announce_buffer_error(struct qdio_q *q, int count) + { +- q->qdio_error = QDIO_ERROR_SLSB_STATE; ++ q->qdio_error |= QDIO_ERROR_SLSB_STATE; + + /* special handling for no target buffer empty */ + if ((!q->is_input_q && +@@ -707,69 +697,34 @@ static inline int qdio_outbound_q_moved( + return 0; + } + +-/* +- * VM could present us cc=2 and busy bit set on SIGA-write +- * during reconfiguration of their Guest LAN (only in iqdio mode, +- * otherwise qdio is asynchronous and cc=2 and busy bit there will take +- * the queues down immediately). +- * +- * Therefore qdio_siga_output will try for a short time constantly, +- * if such a condition occurs. If it doesn't change, it will +- * increase the busy_siga_counter and save the timestamp, and +- * schedule the queue for later processing. qdio_outbound_processing +- * will check out the counter. If non-zero, it will call qdio_kick_outbound_q +- * as often as the value of the counter. This will attempt further SIGA +- * instructions. For each successful SIGA, the counter is +- * decreased, for failing SIGAs the counter remains the same, after +- * all. After some time of no movement, qdio_kick_outbound_q will +- * finally fail and reflect corresponding error codes to call +- * the upper layer module and have it take the queues down. +- * +- * Note that this is a change from the original HiperSockets design +- * (saying cc=2 and busy bit means take the queues down), but in +- * these days Guest LAN didn't exist... excessive cc=2 with busy bit +- * conditions will still take the queues down, but the threshold is +- * higher due to the Guest LAN environment. +- * +- * Called from outbound tasklet and do_QDIO handler. +- */ +-static void qdio_kick_outbound_q(struct qdio_q *q) ++static int qdio_kick_outbound_q(struct qdio_q *q) + { +- int rc; +- +- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickoutq:%1d", q->nr); ++ unsigned int busy_bit; ++ int cc; + + if (!need_siga_out(q)) +- return; ++ return 0; + +- rc = qdio_siga_output(q); +- switch (rc) { ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); ++ qdio_perf_stat_inc(&perf_stats.siga_out); ++ ++ cc = qdio_siga_output(q, &busy_bit); ++ switch (cc) { + case 0: +- /* TODO: improve error handling for CC=0 case */ +- if (q->u.out.timestamp) +- DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "cc2 rslv:%4x", +- atomic_read(&q->u.out.busy_siga_counter)); +- /* went smooth this time, reset timestamp */ +- q->u.out.timestamp = 0; + break; +- /* cc=2 and busy bit */ +- case (2 | QDIO_ERROR_SIGA_BUSY): +- atomic_inc(&q->u.out.busy_siga_counter); +- +- /* if the last siga was successful, save timestamp here */ +- if (!q->u.out.timestamp) +- q->u.out.timestamp = get_usecs(); +- +- /* if we're in time, don't touch qdio_error */ +- if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) { +- tasklet_schedule(&q->tasklet); +- break; +- } +- DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); +- default: +- /* for plain cc=1, 2 or 3 */ +- q->qdio_error = rc; ++ case 2: ++ if (busy_bit) { ++ DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); ++ cc |= QDIO_ERROR_SIGA_BUSY; ++ } else ++ DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); ++ break; ++ case 1: ++ case 3: ++ DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); ++ break; + } ++ return cc; + } + + static void qdio_kick_outbound_handler(struct qdio_q *q) +@@ -799,17 +754,7 @@ static void qdio_kick_outbound_handler(s + + static void __qdio_outbound_processing(struct qdio_q *q) + { +- int siga_attempts; +- + qdio_perf_stat_inc(&perf_stats.tasklet_outbound); +- +- /* see comment in qdio_kick_outbound_q */ +- siga_attempts = atomic_read(&q->u.out.busy_siga_counter); +- while (siga_attempts--) { +- atomic_dec(&q->u.out.busy_siga_counter); +- qdio_kick_outbound_q(q); +- } +- + BUG_ON(atomic_read(&q->nr_buf_used) < 0); + + if (qdio_outbound_q_moved(q)) +@@ -1478,10 +1423,10 @@ static inline int buf_in_between(int buf + * @bufnr: first buffer to process + * @count: how many buffers are emptied + */ +-static void handle_inbound(struct qdio_q *q, unsigned int callflags, +- int bufnr, int count) ++static int handle_inbound(struct qdio_q *q, unsigned int callflags, ++ int bufnr, int count) + { +- int used, rc, diff; ++ int used, diff; + + if (!q->u.in.polling) + goto set; +@@ -1519,13 +1464,11 @@ set: + + /* no need to signal as long as the adapter had free buffers */ + if (used) +- return; ++ return 0; + +- if (need_siga_in(q)) { +- rc = qdio_siga_input(q); +- if (rc) +- q->qdio_error = rc; +- } ++ if (need_siga_in(q)) ++ return qdio_siga_input(q); ++ return 0; + } + + /** +@@ -1535,11 +1478,11 @@ set: + * @bufnr: first buffer to process + * @count: how many buffers are filled + */ +-static void handle_outbound(struct qdio_q *q, unsigned int callflags, +- int bufnr, int count) ++static int handle_outbound(struct qdio_q *q, unsigned int callflags, ++ int bufnr, int count) + { + unsigned char state; +- int used; ++ int used, rc = 0; + + qdio_perf_stat_inc(&perf_stats.outbound_handler); + +@@ -1554,14 +1497,17 @@ static void handle_outbound(struct qdio_ + + if (queue_type(q) == QDIO_IQDIO_QFMT) { + if (multicast_outbound(q)) +- qdio_kick_outbound_q(q); ++ rc = qdio_kick_outbound_q(q); + else + /* + * One siga-w per buffer required for unicast + * HiperSockets. + */ +- while (count--) +- qdio_kick_outbound_q(q); ++ while (count--) { ++ rc = qdio_kick_outbound_q(q); ++ if (rc) ++ goto out; ++ } + goto out; + } + +@@ -1573,7 +1519,7 @@ static void handle_outbound(struct qdio_ + /* try to fast requeue buffers */ + get_buf_state(q, prev_buf(bufnr), &state, 0); + if (state != SLSB_CU_OUTPUT_PRIMED) +- qdio_kick_outbound_q(q); ++ rc = qdio_kick_outbound_q(q); + else { + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); + qdio_perf_stat_inc(&perf_stats.fast_requeue); +@@ -1581,6 +1527,7 @@ static void handle_outbound(struct qdio_ + out: + /* Fixme: could wait forever if called from process context */ + tasklet_schedule(&q->tasklet); ++ return rc; + } + + /** +@@ -1619,14 +1566,12 @@ int do_QDIO(struct ccw_device *cdev, uns + return -EBUSY; + + if (callflags & QDIO_FLAG_SYNC_INPUT) +- handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, +- count); ++ return handle_inbound(irq_ptr->input_qs[q_nr], ++ callflags, bufnr, count); + else if (callflags & QDIO_FLAG_SYNC_OUTPUT) +- handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, +- count); +- else +- return -EINVAL; +- return 0; ++ return handle_outbound(irq_ptr->output_qs[q_nr], ++ callflags, bufnr, count); ++ return -EINVAL; + } + EXPORT_SYMBOL_GPL(do_QDIO); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-06-qdio_tiq_list_lock.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-06-qdio_tiq_list_lock.patch new file mode 100644 index 000000000..78ab65c96 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-06-qdio_tiq_list_lock.patch @@ -0,0 +1,66 @@ +From: Gerald Schaefer +Subject: qdio: add missing tiq_list locking +References: bnc#484767,LTC#52205 + +Symptom: The system may hang if multiple qdio devices are added or + removed in parallel. +Problem: Although reading the tiq_list is done using RCU adding and + removing elements from the list must still happen locked since + multiple qdio devices may change the list in parallel otherwise. +Solution: Add a mutex to protect the tiq_list. + +Acked-by: John Jolly +--- + drivers/s390/cio/qdio_main.c | 1 + + drivers/s390/cio/qdio_thinint.c | 10 +++++++--- + 2 files changed, 8 insertions(+), 3 deletions(-) + +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -1094,6 +1094,7 @@ int qdio_shutdown(struct ccw_device *cde + if (!irq_ptr) + return -ENODEV; + ++ BUG_ON(irqs_disabled()); + DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); + + mutex_lock(&irq_ptr->setup_mutex); +Index: linux-sles11/drivers/s390/cio/qdio_thinint.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_thinint.c ++++ linux-sles11/drivers/s390/cio/qdio_thinint.c +@@ -31,6 +31,7 @@ + + /* list of thin interrupt input queues */ + static LIST_HEAD(tiq_list); ++DEFINE_MUTEX(tiq_list_lock); + + /* adapter local summary indicator */ + static unsigned char *tiqdio_alsi; +@@ -95,10 +96,10 @@ void tiqdio_add_input_queues(struct qdio + if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync) + css_qdio_omit_svs = 1; + +- for_each_input_queue(irq_ptr, q, i) { ++ mutex_lock(&tiq_list_lock); ++ for_each_input_queue(irq_ptr, q, i) + list_add_rcu(&q->entry, &tiq_list); +- synchronize_rcu(); +- } ++ mutex_unlock(&tiq_list_lock); + xchg(irq_ptr->dsci, 1); + tasklet_schedule(&tiqdio_tasklet); + } +@@ -118,7 +119,10 @@ void tiqdio_remove_input_queues(struct q + /* if establish triggered an error */ + if (!q || !q->entry.prev || !q->entry.next) + continue; ++ ++ mutex_lock(&tiq_list_lock); + list_del_rcu(&q->entry); ++ mutex_unlock(&tiq_list_lock); + synchronize_rcu(); + } + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-07-qdio_kill_tasklets.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-07-qdio_kill_tasklets.patch new file mode 100644 index 000000000..a21d92db6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-07-qdio_kill_tasklets.patch @@ -0,0 +1,159 @@ +From: Gerald Schaefer +Subject: qdio: proper kill of qdio tasklets +References: bnc#484767,LTC#52206 + +Symptom: kernel BUG at kernel/softirq.c:392! +Problem: The queue tasklets were stopped with tasklet_disable. Although + tasklet_disable prevents the tasklet from beeing executed it is + still possible that a tasklet is scheduled on a CPU at that point. + A following qdio_establish calls tasklet_init which clears the + tasklet count and the tasklet state leading to the oops. +Solution: Use tasklet_kill instead of tasklet_disbale. Since + tasklet_schedule must not be called after tasklet_kill use the + QDIO_IRQ_STATE_STOPPED to inidicate that a queue is going down + and prevent further tasklet schedules in that case. + +Acked-by: John Jolly +--- + drivers/s390/cio/qdio_main.c | 35 ++++++++++++++++++++++++----------- + drivers/s390/cio/qdio_thinint.c | 8 ++++---- + 2 files changed, 28 insertions(+), 15 deletions(-) + +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -760,21 +760,17 @@ static void __qdio_outbound_processing(s + if (qdio_outbound_q_moved(q)) + qdio_kick_outbound_handler(q); + +- if (queue_type(q) == QDIO_ZFCP_QFMT) { ++ if (queue_type(q) == QDIO_ZFCP_QFMT) + if (!pci_out_supported(q) && !qdio_outbound_q_done(q)) +- tasklet_schedule(&q->tasklet); +- return; +- } ++ goto sched; + + /* bail out for HiperSockets unicast queues */ + if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q)) + return; + + if ((queue_type(q) == QDIO_IQDIO_QFMT) && +- (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) { +- tasklet_schedule(&q->tasklet); +- return; +- } ++ (atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) ++ goto sched; + + if (q->u.out.pci_out_enabled) + return; +@@ -792,6 +788,12 @@ static void __qdio_outbound_processing(s + qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer); + } + } ++ return; ++ ++sched: ++ if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) ++ return; ++ tasklet_schedule(&q->tasklet); + } + + /* outbound tasklet */ +@@ -804,6 +806,9 @@ void qdio_outbound_processing(unsigned l + void qdio_outbound_timer(unsigned long data) + { + struct qdio_q *q = (struct qdio_q *)data; ++ ++ if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) ++ return; + tasklet_schedule(&q->tasklet); + } + +@@ -845,6 +850,9 @@ static void qdio_int_handler_pci(struct + int i; + struct qdio_q *q; + ++ if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) ++ return; ++ + qdio_perf_stat_inc(&perf_stats.pci_int); + + for_each_input_queue(irq_ptr, q, i) +@@ -1072,11 +1080,11 @@ static void qdio_shutdown_queues(struct + int i; + + for_each_input_queue(irq_ptr, q, i) +- tasklet_disable(&q->tasklet); ++ tasklet_kill(&q->tasklet); + + for_each_output_queue(irq_ptr, q, i) { +- tasklet_disable(&q->tasklet); + del_timer(&q->u.out.timer); ++ tasklet_kill(&q->tasklet); + } + } + +@@ -1107,6 +1115,12 @@ int qdio_shutdown(struct ccw_device *cde + return 0; + } + ++ /* ++ * Indicate that the device is going down. Scheduling the queue ++ * tasklets is forbidden from here on. ++ */ ++ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); ++ + tiqdio_remove_input_queues(irq_ptr); + qdio_shutdown_queues(cdev); + qdio_shutdown_debug_entries(irq_ptr, cdev); +@@ -1526,7 +1540,6 @@ static int handle_outbound(struct qdio_q + qdio_perf_stat_inc(&perf_stats.fast_requeue); + } + out: +- /* Fixme: could wait forever if called from process context */ + tasklet_schedule(&q->tasklet); + return rc; + } +Index: linux-sles11/drivers/s390/cio/qdio_thinint.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_thinint.c ++++ linux-sles11/drivers/s390/cio/qdio_thinint.c +@@ -101,7 +101,6 @@ void tiqdio_add_input_queues(struct qdio + list_add_rcu(&q->entry, &tiq_list); + mutex_unlock(&tiq_list_lock); + xchg(irq_ptr->dsci, 1); +- tasklet_schedule(&tiqdio_tasklet); + } + + /* +@@ -159,7 +158,6 @@ static void __tiqdio_inbound_processing( + */ + qdio_check_outbound_after_thinint(q); + +-again: + if (!qdio_inbound_q_moved(q)) + return; + +@@ -167,7 +165,8 @@ again: + + if (!tiqdio_inbound_q_done(q)) { + qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); +- goto again; ++ if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) ++ tasklet_schedule(&q->tasklet); + } + + qdio_stop_polling(q); +@@ -177,7 +176,8 @@ again: + */ + if (!tiqdio_inbound_q_done(q)) { + qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); +- goto again; ++ if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) ++ tasklet_schedule(&q->tasklet); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-08-qdio_free_shutdown.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-08-qdio_free_shutdown.patch new file mode 100644 index 000000000..61888b6ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-08-qdio_free_shutdown.patch @@ -0,0 +1,42 @@ +From: Gerald Schaefer +Subject: qdio: call qdio_free also if qdio_shutdown fails +References: bnc#484767,LTC#52207 + +Symptom: Warning message after qeth recovery. +Problem: qdio_cleanup is a wrapper function that should call qdio_shutdown + and qdio_free. qdio_free was not called if an error occured in + qdio_shutdown resulting in a missing free of allocated resources. +Solution: Always call qdio_free in qdio_cleanup. + +Acked-by: John Jolly +--- + drivers/s390/cio/qdio_main.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -1055,8 +1055,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); + * @cdev: associated ccw device + * @how: use halt or clear to shutdown + * +- * This function calls qdio_shutdown() for @cdev with method @how +- * and on success qdio_free() for @cdev. ++ * This function calls qdio_shutdown() for @cdev with method @how. ++ * and qdio_free(). The qdio_free() return value is ignored since ++ * !irq_ptr is already checked. + */ + int qdio_cleanup(struct ccw_device *cdev, int how) + { +@@ -1067,8 +1068,8 @@ int qdio_cleanup(struct ccw_device *cdev + return -ENODEV; + + rc = qdio_shutdown(cdev, how); +- if (rc == 0) +- rc = qdio_free(cdev); ++ ++ qdio_free(cdev); + return rc; + } + EXPORT_SYMBOL_GPL(qdio_cleanup); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-09-qdio_ack_newest_and_seperate_polling.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-09-qdio_ack_newest_and_seperate_polling.patch new file mode 100644 index 000000000..7262959bf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-09-qdio_ack_newest_and_seperate_polling.patch @@ -0,0 +1,183 @@ +From: Gerald Schaefer +Subject: qdio: move ACK to newest buffer for devices without QEBSM +References: bnc#484767,LTC#52208 + +Symptom: Lower performance of non-QEBSM qdio devices under heavy traffic +Problem: The ACKnowledgement state is set on the first SBAL so in case of + multiple PRIMED buffers the firmware has to scan all buffers. +Solution: The ACKnowledgement state is set on the newest SBAL so an + adapter interrupt surpression check needs to scan fewer SBALs. + +Acked-by: John Jolly +--- + drivers/s390/cio/qdio.h | 5 ++++- + drivers/s390/cio/qdio_debug.c | 3 ++- + drivers/s390/cio/qdio_main.c | 41 ++++++++++++++++++++--------------------- + 3 files changed, 26 insertions(+), 23 deletions(-) + +Index: linux-sles11/drivers/s390/cio/qdio.h +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio.h ++++ linux-sles11/drivers/s390/cio/qdio.h +@@ -186,6 +186,9 @@ struct qdio_input_q { + /* input buffer acknowledgement flag */ + int polling; + ++ /* first ACK'ed buffer */ ++ int ack_start; ++ + /* how much sbals are acknowledged with qebsm */ + int ack_count; + +@@ -231,7 +234,7 @@ struct qdio_q { + int first_to_check; + + /* first_to_check of the last time */ +- int last_move_ftc; ++ int last_move; + + /* beginning position for calling the program */ + int first_to_kick; +Index: linux-sles11/drivers/s390/cio/qdio_debug.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_debug.c ++++ linux-sles11/drivers/s390/cio/qdio_debug.c +@@ -62,8 +62,9 @@ static int qstat_show(struct seq_file *m + seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci); + seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); + seq_printf(m, "ftc: %d\n", q->first_to_check); +- seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); ++ seq_printf(m, "last_move: %d\n", q->last_move); + seq_printf(m, "polling: %d\n", q->u.in.polling); ++ seq_printf(m, "ack start: %d\n", q->u.in.ack_start); + seq_printf(m, "ack count: %d\n", q->u.in.ack_count); + seq_printf(m, "slsb buffer states:\n"); + seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); +Index: linux-sles11/drivers/s390/cio/qdio_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/qdio_main.c ++++ linux-sles11/drivers/s390/cio/qdio_main.c +@@ -371,11 +371,11 @@ inline void qdio_stop_polling(struct qdi + + /* show the card that we are not polling anymore */ + if (is_qebsm(q)) { +- set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, ++ set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT, + q->u.in.ack_count); + q->u.in.ack_count = 0; + } else +- set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); ++ set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); + } + + static void announce_buffer_error(struct qdio_q *q, int count) +@@ -410,15 +410,15 @@ static inline void inbound_primed(struct + if (!q->u.in.polling) { + q->u.in.polling = 1; + q->u.in.ack_count = count; +- q->last_move_ftc = q->first_to_check; ++ q->u.in.ack_start = q->first_to_check; + return; + } + + /* delete the previous ACK's */ +- set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, ++ set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT, + q->u.in.ack_count); + q->u.in.ack_count = count; +- q->last_move_ftc = q->first_to_check; ++ q->u.in.ack_start = q->first_to_check; + return; + } + +@@ -430,14 +430,13 @@ static inline void inbound_primed(struct + if (q->u.in.polling) { + /* reset the previous ACK but first set the new one */ + set_buf_state(q, new, SLSB_P_INPUT_ACK); +- set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); +- } +- else { ++ set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT); ++ } else { + q->u.in.polling = 1; +- set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); ++ set_buf_state(q, new, SLSB_P_INPUT_ACK); + } + +- q->last_move_ftc = new; ++ q->u.in.ack_start = new; + count--; + if (!count) + return; +@@ -446,7 +445,7 @@ static inline void inbound_primed(struct + * Need to change all PRIMED buffers to NOT_INIT, otherwise + * we're loosing initiative in the thinint code. + */ +- set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT, ++ set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, + count); + } + +@@ -514,7 +513,8 @@ int qdio_inbound_q_moved(struct qdio_q * + + bufnr = get_inbound_buffer_frontier(q); + +- if ((bufnr != q->last_move_ftc) || q->qdio_error) { ++ if ((bufnr != q->last_move) || q->qdio_error) { ++ q->last_move = bufnr; + if (!need_siga_sync(q) && !pci_out_supported(q)) + q->u.in.timestamp = get_usecs(); + +@@ -689,8 +689,8 @@ static inline int qdio_outbound_q_moved( + + bufnr = get_outbound_buffer_frontier(q); + +- if ((bufnr != q->last_move_ftc) || q->qdio_error) { +- q->last_move_ftc = bufnr; ++ if ((bufnr != q->last_move) || q->qdio_error) { ++ q->last_move = bufnr; + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); + return 1; + } else +@@ -732,7 +732,7 @@ static void qdio_kick_outbound_handler(s + int start, end, count; + + start = q->first_to_kick; +- end = q->last_move_ftc; ++ end = q->last_move; + if (end >= start) + count = end - start; + else +@@ -748,7 +748,7 @@ static void qdio_kick_outbound_handler(s + q->irq_ptr->int_parm); + + /* for the next time: */ +- q->first_to_kick = q->last_move_ftc; ++ q->first_to_kick = q->last_move; + q->qdio_error = 0; + } + +@@ -1453,19 +1453,18 @@ static int handle_inbound(struct qdio_q + q->u.in.polling = 0; + q->u.in.ack_count = 0; + goto set; +- } else if (buf_in_between(q->last_move_ftc, bufnr, count)) { ++ } else if (buf_in_between(q->u.in.ack_start, bufnr, count)) { + if (is_qebsm(q)) { +- /* partial overwrite, just update last_move_ftc */ ++ /* partial overwrite, just update ack_start */ + diff = add_buf(bufnr, count); +- diff = sub_buf(diff, q->last_move_ftc); ++ diff = sub_buf(diff, q->u.in.ack_start); + q->u.in.ack_count -= diff; + if (q->u.in.ack_count <= 0) { + q->u.in.polling = 0; + q->u.in.ack_count = 0; +- /* TODO: must we set last_move_ftc to something meaningful? */ + goto set; + } +- q->last_move_ftc = add_buf(q->last_move_ftc, diff); ++ q->u.in.ack_start = add_buf(q->u.in.ack_start, diff); + } + else + /* the only ACK will be deleted, so stop polling */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-10-zfcp_nameserver_state_on_adapter_offline.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-10-zfcp_nameserver_state_on_adapter_offline.patch new file mode 100644 index 000000000..b38392768 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-10-zfcp_nameserver_state_on_adapter_offline.patch @@ -0,0 +1,69 @@ +From: Gerald Schaefer +Subject: zfcp: set nameserver port to offline on adapter deactivation. +References: bnc#484767,LTC#52232 + +Symptom: Storage ports remain in offline state after adapter reactivation. +Problem: The nameserver port might be in state online when the adapter is + offlined. On adapter reactivation the nameserver port is not + re-opened due to the PORT_ONLINE status. This results in an + unsuccessful recovery. +Solution: Force the nameserver port status to offline on all adapter + offline events ensuring a nameserver port open on adapter + reactivation. + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_aux.c | 1 - + drivers/s390/scsi/zfcp_erp.c | 1 + + drivers/s390/scsi/zfcp_ext.h | 1 + + drivers/s390/scsi/zfcp_fc.c | 8 ++++++++ + 4 files changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -553,7 +553,6 @@ void zfcp_adapter_dequeue(struct zfcp_ad + + cancel_work_sync(&adapter->scan_work); + cancel_work_sync(&adapter->stat_work); +- cancel_delayed_work_sync(&adapter->nsp.work); + zfcp_adapter_scsi_unregister(adapter); + sysfs_remove_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs); +--- a/drivers/s390/scsi/zfcp_erp.c ++++ b/drivers/s390/scsi/zfcp_erp.c +@@ -738,6 +738,7 @@ static int zfcp_erp_adapter_strategy_gen + zfcp_qdio_close(adapter); + zfcp_fsf_req_dismiss_all(adapter); + adapter->fsf_req_seq_no = 0; ++ zfcp_fc_wka_port_force_offline(&adapter->nsp); + /* all ports and units are closed */ + zfcp_erp_modify_adapter_status(adapter, 24, NULL, + ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); +--- a/drivers/s390/scsi/zfcp_ext.h ++++ b/drivers/s390/scsi/zfcp_ext.h +@@ -103,6 +103,7 @@ extern void zfcp_fc_plogi_evaluate(struc + extern void zfcp_test_link(struct zfcp_port *); + extern void zfcp_fc_link_test_work(struct work_struct *); + extern void zfcp_fc_nameserver_init(struct zfcp_adapter *); ++extern void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *); + + /* zfcp_fsf.c */ + extern int zfcp_fsf_open_port(struct zfcp_erp_action *); +--- a/drivers/s390/scsi/zfcp_fc.c ++++ b/drivers/s390/scsi/zfcp_fc.c +@@ -115,6 +115,14 @@ void zfcp_fc_nameserver_init(struct zfcp + INIT_DELAYED_WORK(&wka_port->work, zfcp_wka_port_offline); + } + ++void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) ++{ ++ cancel_delayed_work_sync(&wka->work); ++ mutex_lock(&wka->mutex); ++ wka->status = ZFCP_WKA_PORT_OFFLINE; ++ mutex_unlock(&wka->mutex); ++} ++ + static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, + struct fcp_rscn_element *elem) + { diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-11-zfcp_req_free.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-11-zfcp_req_free.patch new file mode 100644 index 000000000..da7ee8490 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-11-zfcp_req_free.patch @@ -0,0 +1,88 @@ +From: Gerald Schaefer +Subject: zfcp: Don't call zfcp_fsf_req_free on NULL pointer +References: bnc#484767,LTC#52234 + +Symptom: Reading adapter statistics from user space on a full + queue might lead to the attempt of freeing memory on + a NULL pointer. +Problem: The error path for the queue full case is wrong in the code. +Solution: Only free the FSF request if it has been sucessfully allocated + before + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fsf.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/s390/scsi/zfcp_fsf.c 2009-03-16 15:34:34.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2009-03-16 16:04:01.000000000 +0100 +@@ -1256,13 +1256,13 @@ int zfcp_fsf_exchange_config_data_sync(s + + spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) +- goto out; ++ goto out_unlock; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, + 0, NULL); + if (IS_ERR(req)) { + retval = PTR_ERR(req); +- goto out; ++ goto out_unlock; + } + + sbale = zfcp_qdio_sbale_req(req); +@@ -1281,14 +1281,16 @@ int zfcp_fsf_exchange_config_data_sync(s + + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); +-out: + spin_unlock_bh(&adapter->req_q_lock); + if (!retval) + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + + zfcp_fsf_req_free(req); ++ return retval; + ++out_unlock: ++ spin_unlock_bh(&adapter->req_q_lock); + return retval; + } + +@@ -1355,13 +1357,13 @@ int zfcp_fsf_exchange_port_data_sync(str + + spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) +- goto out; ++ goto out_unlock; + + req = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA, 0, + NULL); + if (IS_ERR(req)) { + retval = PTR_ERR(req); +- goto out; ++ goto out_unlock; + } + + if (data) +@@ -1374,14 +1376,18 @@ int zfcp_fsf_exchange_port_data_sync(str + req->handler = zfcp_fsf_exchange_port_data_handler; + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); + retval = zfcp_fsf_req_send(req); +-out: + spin_unlock_bh(&adapter->req_q_lock); ++ + if (!retval) + wait_event(req->completion_wq, + req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + zfcp_fsf_req_free(req); + + return retval; ++ ++out_unlock: ++ spin_unlock_bh(&adapter->req_q_lock); ++ return retval; + } + + static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-12-zfcp_scsi_scan.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-12-zfcp_scsi_scan.patch new file mode 100644 index 000000000..5c9b2180e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-12-zfcp_scsi_scan.patch @@ -0,0 +1,159 @@ +From: Gerald Schaefer +Subject: zfcp: Move scan_target to scsi host workqueue +References: bnc#484767,LTC#52236 + +Symptom: Trying to attach a non-existing LUN blocks all state + changes in the zfcp driver. +Problem: If the storage server does not respond, the + scsi_scan_target call blocks until it reaches all + timeouts. This blocks all other tasks on the zfcp workqueue. +Solution: Run the scsi_scan_target work on the scsi host + workqueue, the same one where the scan from the SCSI + midlayer runs on. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 5 +--- + drivers/s390/scsi/zfcp_def.h | 2 - + drivers/s390/scsi/zfcp_erp.c | 49 +++--------------------------------------- + drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_scsi.c | 14 ++++++++++++ + 5 files changed, 22 insertions(+), 49 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c 2009-03-16 16:41:33.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_aux.c 2009-03-16 16:42:42.000000000 +0100 +@@ -133,9 +133,7 @@ static void __init zfcp_init_device_conf + ccw_device_set_online(adapter->ccw_device); + + zfcp_erp_wait(adapter); +- wait_event(adapter->erp_done_wqh, +- !(atomic_read(&unit->status) & +- ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)); ++ flush_work(&unit->scsi_work); + + down(&zfcp_data.config_sema); + zfcp_unit_put(unit); +@@ -288,6 +286,7 @@ struct zfcp_unit *zfcp_unit_enqueue(stru + + atomic_set(&unit->refcount, 0); + init_waitqueue_head(&unit->remove_wq); ++ INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); + + unit->port = port; + unit->fcp_lun = fcp_lun; +--- a/drivers/s390/scsi/zfcp_def.h 2009-03-16 16:41:33.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_def.h 2009-03-16 16:43:18.000000000 +0100 +@@ -273,7 +273,6 @@ enum zfcp_wka_status { + #define ZFCP_STATUS_UNIT_SHARED 0x00000004 + #define ZFCP_STATUS_UNIT_READONLY 0x00000008 + #define ZFCP_STATUS_UNIT_REGISTERED 0x00000010 +-#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020 + + /* FSF request status (this does not have a common part) */ + #define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002 +@@ -558,6 +557,7 @@ struct zfcp_unit { + struct zfcp_erp_action erp_action; /* pending error recovery */ + atomic_t erp_counter; + struct zfcp_latencies latencies; ++ struct work_struct scsi_work; + }; + + /* FSF request */ +--- a/drivers/s390/scsi/zfcp_erp.c 2009-03-16 16:41:33.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_erp.c 2009-03-16 16:44:04.000000000 +0100 +@@ -1184,48 +1184,6 @@ static void zfcp_erp_action_dequeue(stru + } + } + +-struct zfcp_erp_add_work { +- struct zfcp_unit *unit; +- struct work_struct work; +-}; +- +-static void zfcp_erp_scsi_scan(struct work_struct *work) +-{ +- struct zfcp_erp_add_work *p = +- container_of(work, struct zfcp_erp_add_work, work); +- struct zfcp_unit *unit = p->unit; +- struct fc_rport *rport = unit->port->rport; +- +- if (rport && rport->port_state == FC_PORTSTATE_ONLINE) +- scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, +- scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0); +- atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); +- zfcp_unit_put(unit); +- wake_up(&unit->port->adapter->erp_done_wqh); +- kfree(p); +-} +- +-static void zfcp_erp_schedule_work(struct zfcp_unit *unit) +-{ +- struct zfcp_erp_add_work *p; +- +- p = kzalloc(sizeof(*p), GFP_KERNEL); +- if (!p) { +- dev_err(&unit->port->adapter->ccw_device->dev, +- "Registering unit 0x%016Lx on port 0x%016Lx failed\n", +- (unsigned long long)unit->fcp_lun, +- (unsigned long long)unit->port->wwpn); +- return; +- } +- +- zfcp_unit_get(unit); +- atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); +- INIT_WORK(&p->work, zfcp_erp_scsi_scan); +- p->unit = unit; +- if (!queue_work(zfcp_data.work_queue, &p->work)) +- zfcp_unit_put(unit); +-} +- + static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) + { + struct zfcp_adapter *adapter = act->adapter; +@@ -1238,9 +1196,10 @@ static void zfcp_erp_action_cleanup(stru + if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { + atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, + &unit->status); +- if (!(atomic_read(&unit->status) & +- ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) +- zfcp_erp_schedule_work(unit); ++ zfcp_unit_get(unit); ++ if (scsi_queue_work(unit->port->adapter->scsi_host, ++ &unit->scsi_work) <= 0) ++ zfcp_unit_put(unit); + } + zfcp_unit_put(unit); + break; +--- a/drivers/s390/scsi/zfcp_scsi.c 2009-03-16 16:41:33.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_scsi.c 2009-03-16 16:42:42.000000000 +0100 +@@ -588,6 +588,20 @@ void zfcp_scsi_rport_work(struct work_st + } + + ++void zfcp_scsi_scan(struct work_struct *work) ++{ ++ struct zfcp_unit *unit = container_of(work, struct zfcp_unit, ++ scsi_work); ++ struct fc_rport *rport = unit->port->rport; ++ ++ if (rport && rport->port_state == FC_PORTSTATE_ONLINE) ++ scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, ++ scsilun_to_int((struct scsi_lun *) ++ &unit->fcp_lun), 0); ++ ++ zfcp_unit_put(unit); ++} ++ + struct fc_function_template zfcp_transport_functions = { + .show_starget_port_id = 1, + .show_starget_port_name = 1, +--- a/drivers/s390/scsi/zfcp_ext.h 2009-03-16 16:41:33.000000000 +0100 ++++ b/drivers/s390/scsi/zfcp_ext.h 2009-03-16 16:42:42.000000000 +0100 +@@ -159,6 +159,7 @@ extern void zfcp_scsi_rport_work(struct + extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); + extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); + extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); ++extern void zfcp_scsi_scan(struct work_struct *); + + /* zfcp_sysfs.c */ + extern struct attribute_group zfcp_sysfs_unit_attrs; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-13-zfcp_avoid_semaphore_race.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-13-zfcp_avoid_semaphore_race.patch new file mode 100644 index 000000000..d67636400 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-13-zfcp_avoid_semaphore_race.patch @@ -0,0 +1,56 @@ +From: Gerald Schaefer +Subject: zfcp: avoid false ERP complete task due to semaphore race. +References: bnc#484767,LTC#55250 + +Symptom: The adapter is not able to perform an initial exchange config. +Problem: The ERP thread is performing a task before it is executing the + corresponding down on the semaphore. The response handler of the + just started exchange config should wait for the completion by + performing a down on this semaphore. Since this semaphore is still + positive from the ERP enqueue the handler won't wait and therefore + the exchange config will always fail leaving the adapter in error. +Solution: Perform the down on the semaphore before starting an ERP task. + This is the logically correct order. Only walk the ERP loop + if there is a task to perform. + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_erp.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_erp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_erp.c ++++ linux-sles11/drivers/s390/scsi/zfcp_erp.c +@@ -1310,6 +1310,7 @@ static int zfcp_erp_thread(void *data) + struct list_head *next; + struct zfcp_erp_action *act; + unsigned long flags; ++ int ignore; + + daemonize("zfcperp%s", adapter->ccw_device->dev.bus_id); + /* Block all signals */ +@@ -1319,6 +1320,11 @@ static int zfcp_erp_thread(void *data) + + while (!(atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { ++ ++ zfcp_rec_dbf_event_thread_lock(4, adapter); ++ ignore = down_interruptible(&adapter->erp_ready_sem); ++ zfcp_rec_dbf_event_thread_lock(5, adapter); ++ + write_lock_irqsave(&adapter->erp_lock, flags); + next = adapter->erp_ready_head.next; + write_unlock_irqrestore(&adapter->erp_lock, flags); +@@ -1330,10 +1336,6 @@ static int zfcp_erp_thread(void *data) + if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) + zfcp_erp_wakeup(adapter); + } +- +- zfcp_rec_dbf_event_thread_lock(4, adapter); +- down_interruptible(&adapter->erp_ready_sem); +- zfcp_rec_dbf_event_thread_lock(5, adapter); + } + + atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-14-zfcp_unit_remove.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-14-zfcp_unit_remove.patch new file mode 100644 index 000000000..3c0d1cf21 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-14-zfcp_unit_remove.patch @@ -0,0 +1,48 @@ +From: Gerald Schaefer +Subject: zfcp: remove unit will fail if add unit is not finished +References: bnc#484767,LTC#48795 + +Symptom: On some hardware it can take some time to add a unit. If + some remove this unit during this process the remove will + fail. +Problem: There exists some SCSI work which needs to be finished + before removing this unit. +Solution: Wait until all SCSI work is done for that unit. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_sysfs.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_sysfs.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_sysfs.c ++++ linux-sles11/drivers/s390/scsi/zfcp_sysfs.c +@@ -253,12 +253,21 @@ static ssize_t zfcp_sysfs_unit_remove_st + + write_lock_irq(&zfcp_data.config_lock); + unit = zfcp_get_unit_by_lun(port, fcp_lun); +- if (unit && (atomic_read(&unit->refcount) == 0)) { +- zfcp_unit_get(unit); +- atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); +- list_move(&unit->list, &unit_remove_lh); +- } else +- unit = NULL; ++ if (unit) { ++ write_unlock_irq(&zfcp_data.config_lock); ++ /* wait for possible timeout during SCSI probe */ ++ flush_work(&unit->scsi_work); ++ write_lock_irq(&zfcp_data.config_lock); ++ ++ if (atomic_read(&unit->refcount) == 0) { ++ zfcp_unit_get(unit); ++ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, ++ &unit->status); ++ list_move(&unit->list, &unit_remove_lh); ++ } else { ++ unit = NULL; ++ } ++ } + + write_unlock_irq(&zfcp_data.config_lock); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-15-kernel_task_size.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-15-kernel_task_size.patch new file mode 100644 index 000000000..4ccdb787d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-15-kernel_task_size.patch @@ -0,0 +1,175 @@ +From: Gerald Schaefer +Subject: kernel: fix dynamic TASK_SIZE handling. +References: bnc#484767,LTC#52259 + +Symptom: System crash (memory overwrite) on access to /proc//pagemap. +Problem: pagemap_read() is using TASK_SIZE_OF to determine the address + range for the generic page table walker. With dynamic page table + upgrades on s390, this does not reflect the true task size, but + the maximum task size, with the maximum level of page tables. If + a process has not yet mmapped enough memory, the page tables will + not be completely upgraded and the generic page table walker will + access (and write) beyond the page tables. +Solution: Change TASK_SIZE/TASK_SIZE_OF to reflect the current size of the + address space. + +Acked-by: John Jolly +--- + arch/s390/include/asm/mman.h | 5 +++ + arch/s390/include/asm/processor.h | 5 +-- + arch/s390/mm/mmap.c | 48 +++++++++++++++++++++++++------------- + arch/s390/mm/pgtable.c | 2 + + 4 files changed, 41 insertions(+), 19 deletions(-) + +Index: linux-2.6.27/arch/s390/include/asm/mman.h +=================================================================== +--- linux-2.6.27.orig/arch/s390/include/asm/mman.h ++++ linux-2.6.27/arch/s390/include/asm/mman.h +@@ -22,4 +22,9 @@ + #define MCL_CURRENT 1 /* lock all current mappings */ + #define MCL_FUTURE 2 /* lock all future mappings */ + ++#if defined(__KERNEL__) && !defined(__ASSEMBLY__) && defined(CONFIG_64BIT) ++int s390_mmap_check(unsigned long addr, unsigned long len); ++#define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len) ++#endif ++ + #endif /* __S390_MMAN_H__ */ +Index: linux-2.6.27/arch/s390/include/asm/processor.h +=================================================================== +--- linux-2.6.27.orig/arch/s390/include/asm/processor.h ++++ linux-2.6.27/arch/s390/include/asm/processor.h +@@ -60,7 +60,7 @@ extern void print_cpu_info(struct cpuinf + extern int get_cpu_capability(unsigned int *); + + /* +- * User space process size: 2GB for 31 bit, 4TB for 64 bit. ++ * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. + */ + #ifndef __s390x__ + +@@ -69,8 +69,7 @@ extern int get_cpu_capability(unsigned i + + #else /* __s390x__ */ + +-#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk,TIF_31BIT) ? \ +- (1UL << 31) : (1UL << 53)) ++#define TASK_SIZE_OF(tsk) ((tsk)->mm->context.asce_limit) + #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ + (1UL << 30) : (1UL << 41)) + #define TASK_SIZE TASK_SIZE_OF(current) +Index: linux-2.6.27/arch/s390/mm/mmap.c +=================================================================== +--- linux-2.6.27.orig/arch/s390/mm/mmap.c ++++ linux-2.6.27/arch/s390/mm/mmap.c +@@ -35,7 +35,7 @@ + * Leave an at least ~128 MB hole. + */ + #define MIN_GAP (128*1024*1024) +-#define MAX_GAP (TASK_SIZE/6*5) ++#define MAX_GAP (STACK_TOP/6*5) + + static inline unsigned long mmap_base(void) + { +@@ -46,7 +46,7 @@ static inline unsigned long mmap_base(vo + else if (gap > MAX_GAP) + gap = MAX_GAP; + +- return TASK_SIZE - (gap & PAGE_MASK); ++ return STACK_TOP - (gap & PAGE_MASK); + } + + static inline int mmap_is_legacy(void) +@@ -89,42 +89,58 @@ EXPORT_SYMBOL_GPL(arch_pick_mmap_layout) + + #else + ++int s390_mmap_check(unsigned long addr, unsigned long len) ++{ ++ if (!test_thread_flag(TIF_31BIT) && ++ len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) ++ return crst_table_upgrade(current->mm, 1UL << 53); ++ return 0; ++} ++ + static unsigned long + s390_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) + { + struct mm_struct *mm = current->mm; ++ unsigned long area; + int rc; + +- addr = arch_get_unmapped_area(filp, addr, len, pgoff, flags); +- if (addr & ~PAGE_MASK) +- return addr; +- if (unlikely(mm->context.asce_limit < addr + len)) { +- rc = crst_table_upgrade(mm, addr + len); ++ area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); ++ if (!(area & ~PAGE_MASK)) ++ return area; ++ if (area == -ENOMEM && ++ !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) { ++ /* Upgrade the page table to 4 levels and retry. */ ++ rc = crst_table_upgrade(mm, 1UL << 53); + if (rc) + return (unsigned long) rc; ++ area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); + } +- return addr; ++ return area; + } + + static unsigned long +-s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, ++s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) + { + struct mm_struct *mm = current->mm; +- unsigned long addr = addr0; ++ unsigned long area; + int rc; + +- addr = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); +- if (addr & ~PAGE_MASK) +- return addr; +- if (unlikely(mm->context.asce_limit < addr + len)) { +- rc = crst_table_upgrade(mm, addr + len); ++ area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); ++ if (!(area & ~PAGE_MASK)) ++ return area; ++ if (area == -ENOMEM && ++ !test_thread_flag(TIF_31BIT) && TASK_SIZE < (1UL << 53)) { ++ /* Upgrade the page table to 4 levels and retry. */ ++ rc = crst_table_upgrade(mm, 1UL << 53); + if (rc) + return (unsigned long) rc; ++ area = arch_get_unmapped_area_topdown(filp, addr, len, ++ pgoff, flags); + } +- return addr; ++ return area; + } + /* + * This function, called very early during the creation of a new +Index: linux-2.6.27/arch/s390/mm/pgtable.c +=================================================================== +--- linux-2.6.27.orig/arch/s390/mm/pgtable.c ++++ linux-2.6.27/arch/s390/mm/pgtable.c +@@ -117,6 +117,7 @@ repeat: + crst_table_init(table, entry); + pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd); + mm->pgd = (pgd_t *) table; ++ mm->task_size = mm->context.asce_limit; + table = NULL; + } + spin_unlock(&mm->page_table_lock); +@@ -154,6 +155,7 @@ void crst_table_downgrade(struct mm_stru + BUG(); + } + mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN); ++ mm->task_size = mm->context.asce_limit; + crst_table_free(mm, (unsigned long *) pgd); + } + update_mm(mm, current); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-11-16-qeth_siga_error_handling.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-11-16-qeth_siga_error_handling.patch new file mode 100644 index 000000000..bea0752d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-11-16-qeth_siga_error_handling.patch @@ -0,0 +1,103 @@ +From: Gerald Schaefer +Subject: qeth: adept SIGA error handling to qdio changes +References: bnc#484767,LTC#52300 + +Symptom: A qeth recovery may be triggered on hipersocket devices + in case no buffers are available on the target. +Problem: Recovery is triggered for all non-zero return values of + do_QDIO. +Solution: Check for SIGA errors after do_QDIO and don't recover in case + of temporary problems. + +Acked-by: John Jolly +--- + drivers/s390/net/qeth_core_main.c | 55 +++++++++++--------------------------- + 1 file changed, 17 insertions(+), 38 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_core_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_main.c ++++ linux-sles11/drivers/s390/net/qeth_core_main.c +@@ -2659,40 +2659,21 @@ static int qeth_handle_send_error(struct + struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err) + { + int sbalf15 = buffer->buffer->element[15].flags & 0xff; +- int cc = qdio_err & 3; + + QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); + qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); +- switch (cc) { +- case 0: +- if (qdio_err) { +- QETH_DBF_TEXT(TRACE, 1, "lnkfail"); +- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); +- QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", +- (u16)qdio_err, (u8)sbalf15); +- return QETH_SEND_ERROR_LINK_FAILURE; +- } ++ ++ if (!qdio_err) + return QETH_SEND_ERROR_NONE; +- case 2: +- if (qdio_err & QDIO_ERROR_SIGA_BUSY) { +- QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B"); +- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); +- return QETH_SEND_ERROR_KICK_IT; +- } +- if ((sbalf15 >= 15) && (sbalf15 <= 31)) +- return QETH_SEND_ERROR_RETRY; +- return QETH_SEND_ERROR_LINK_FAILURE; +- /* look at qdio_error and sbalf 15 */ +- case 1: +- QETH_DBF_TEXT(TRACE, 1, "SIGAcc1"); +- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); +- return QETH_SEND_ERROR_LINK_FAILURE; +- case 3: +- default: +- QETH_DBF_TEXT(TRACE, 1, "SIGAcc3"); +- QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); +- return QETH_SEND_ERROR_KICK_IT; +- } ++ ++ if ((sbalf15 >= 15) && (sbalf15 <= 31)) ++ return QETH_SEND_ERROR_RETRY; ++ ++ QETH_DBF_TEXT(TRACE, 1, "lnkfail"); ++ QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); ++ QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", ++ (u16)qdio_err, (u8)sbalf15); ++ return QETH_SEND_ERROR_LINK_FAILURE; + } + + /* +@@ -2828,10 +2809,14 @@ static void qeth_flush_buffers(struct qe + qeth_get_micros() - + queue->card->perf_stats.outbound_do_qdio_start_time; + if (rc) { ++ queue->card->stats.tx_errors += count; ++ /* ignore temporary SIGA errors without busy condition */ ++ if (rc == 2) ++ return; + QETH_DBF_TEXT(TRACE, 2, "flushbuf"); + QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); + QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card)); +- queue->card->stats.tx_errors += count; ++ + /* this must not happen under normal circumstances. if it + * happens something is really wrong -> recover */ + qeth_schedule_recovery(queue->card); +@@ -2906,13 +2891,7 @@ void qeth_qdio_output_handler(struct ccw + } + for (i = first_element; i < (first_element + count); ++i) { + buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; +- /*we only handle the KICK_IT error by doing a recovery */ +- if (qeth_handle_send_error(card, buffer, qdio_error) +- == QETH_SEND_ERROR_KICK_IT){ +- netif_stop_queue(card->dev); +- qeth_schedule_recovery(card); +- return; +- } ++ qeth_handle_send_error(card, buffer, qdio_error); + qeth_clear_output_buffer(queue, buffer); + } + atomic_sub(count, &queue->used_buffers); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-01-cio-reprobe-deadlock-fix.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-01-cio-reprobe-deadlock-fix.patch new file mode 100644 index 000000000..34117026f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-01-cio-reprobe-deadlock-fix.patch @@ -0,0 +1,59 @@ +From: Gerald Schaefer +Subject: cio: incomplete device initialization on LPAR +References: bnc#487755,LTC#52366 + +Symptom: Random CCW devices are not usable after IPL. Sysfs shows + subchannel directories without links to CCW devices. This occurs + on LPARs with DASDs. +Problem: The DASD device driver triggers the subchannel reprobe function + during PAV initialization. Subchannel reprobing blocks the kslowcrw + workqueue until all outstanding device recognition requests have + finished processing. Device recognition uses kslowcrw to finish + processing which leads to a workqueue deadlock. +Solution: Move the waiting portion of subchannel reprobing to the cio + workqueue. + +Acked-by: John Jolly + +--- + drivers/s390/cio/css.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +Index: linux-sles11/drivers/s390/cio/css.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/css.c ++++ linux-sles11/drivers/s390/cio/css.c +@@ -509,6 +509,17 @@ static int reprobe_subchannel(struct sub + return ret; + } + ++static void reprobe_after_idle(struct work_struct *unused) ++{ ++ /* Make sure initial subchannel scan is done. */ ++ wait_event(ccw_device_init_wq, ++ atomic_read(&ccw_device_init_count) == 0); ++ if (need_reprobe) ++ css_schedule_reprobe(); ++} ++ ++static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle); ++ + /* Work function used to reprobe all unregistered subchannels. */ + static void reprobe_all(struct work_struct *unused) + { +@@ -516,10 +527,12 @@ static void reprobe_all(struct work_stru + + CIO_MSG_EVENT(4, "reprobe start\n"); + +- need_reprobe = 0; + /* Make sure initial subchannel scan is done. */ +- wait_event(ccw_device_init_wq, +- atomic_read(&ccw_device_init_count) == 0); ++ if (atomic_read(&ccw_device_init_count) != 0) { ++ queue_work(ccw_device_work, &reprobe_idle_work); ++ return; ++ } ++ need_reprobe = 0; + ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL); + + CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-02-zfcp_scsi_queue_erp_deadlock.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-02-zfcp_scsi_queue_erp_deadlock.patch new file mode 100644 index 000000000..859c27da8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-02-zfcp_scsi_queue_erp_deadlock.patch @@ -0,0 +1,47 @@ +From: Gerald Schaefer +Subject: zfcp: SCSI queue ERP deadlock +References: bnc#487755,LTC#52401 + +Symptom: The I/O stalls if the an error injection is triggerd on + the storage side. +Problem: The ERP is waiting for the fc tranport class to finish a + task which has triggered a task for the SCSI error handler + which in turn is waiting for the ERP to finish ->deadlock. +Solution: Don't let the ERP wait for anything and move the fulfillment + check of the scheduled task to the async running job (scsi scan) + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_erp.c | 1 - + drivers/s390/scsi/zfcp_scsi.c | 6 +++++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_erp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_erp.c ++++ linux-sles11/drivers/s390/scsi/zfcp_erp.c +@@ -1192,7 +1192,6 @@ static void zfcp_erp_action_cleanup(stru + + switch (act->action) { + case ZFCP_ERP_ACTION_REOPEN_UNIT: +- flush_work(&port->rport_work); + if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { + atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, + &unit->status); +Index: linux-sles11/drivers/s390/scsi/zfcp_scsi.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_scsi.c ++++ linux-sles11/drivers/s390/scsi/zfcp_scsi.c +@@ -592,7 +593,10 @@ void zfcp_scsi_scan(struct work_struct * + { + struct zfcp_unit *unit = container_of(work, struct zfcp_unit, + scsi_work); +- struct fc_rport *rport = unit->port->rport; ++ struct fc_rport *rport; ++ ++ flush_work(&unit->port->rport_work); ++ rport = unit->port->rport; + + if (rport && rport->port_state == FC_PORTSTATE_ONLINE) + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-03-zfcp_adjust_test_link_pre_reqs.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-03-zfcp_adjust_test_link_pre_reqs.patch new file mode 100644 index 000000000..e41336865 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-03-zfcp_adjust_test_link_pre_reqs.patch @@ -0,0 +1,32 @@ +From: Gerald Schaefer +Subject: zfcp: no port recovery after storage side error inject +References: bnc#487755,LTC#52402 + +Symptom: The remote port remains in error state even if connection + is re-established. +Problem: A wrong precondition check was performed on the port status + leading to a cancellation of the port reopen. +Solution: Remove the pre-req check because it's not required and better + handled within the ERP. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fc.c | 5 ----- + 1 file changed, 5 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -430,11 +430,6 @@ void zfcp_fc_link_test_work(struct work_ + container_of(work, struct zfcp_port, test_link_work); + int retval; + +- if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_UNBLOCKED)) { +- zfcp_port_put(port); +- return; /* port erp is running and will update rport status */ +- } +- + zfcp_port_get(port); + port->rport_task = RPORT_DEL; + zfcp_scsi_rport_work(&port->rport_work); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-04-zfcp_rport_handling_on_error_inject.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-04-zfcp_rport_handling_on_error_inject.patch new file mode 100644 index 000000000..e2b38a811 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-04-zfcp_rport_handling_on_error_inject.patch @@ -0,0 +1,29 @@ +From: Gerald Schaefer +Subject: zfcp: no port recovery after ADISC request timeout +References: bnc#487755,LTC#52565 + +Symptom: The remote port remains in error state even if we receive + a RSCN stating that the connection is re-established. +Problem: A flag is not reset which prevents the error recovery + to reopen the port. +Solution: Clear the flag in question before we trigger a ERP. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fc.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -370,7 +370,8 @@ static void zfcp_fc_adisc_handler(unsign + + if (adisc->els.status) { + /* request rejected or timed out */ +- zfcp_erp_port_forced_reopen(port, 0, 63, NULL); ++ zfcp_erp_port_forced_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, ++ 63, NULL); + goto out; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-05-cio_introduce_ccw_device_boxed_notify.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-05-cio_introduce_ccw_device_boxed_notify.patch new file mode 100644 index 000000000..a56ff6899 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-05-cio_introduce_ccw_device_boxed_notify.patch @@ -0,0 +1,219 @@ +From: Gerald Schaefer +Subject: cio: notify ccw driver for boxed devices +References: bnc#487755,LTC#52560 + +Symptom: Dasd driver keeps trying to start io on not accessible device. +Problem: Missing notification for ccw device drivers. +Solution: Add proper notification if a device goes into boxed state. + +Acked-by: John Jolly +--- + Documentation/kmsg/s390/zfcp | 15 +++++++++++++++ + arch/s390/include/asm/cio.h | 2 ++ + drivers/s390/block/dasd.c | 1 + + drivers/s390/cio/device.c | 26 +++++++++++++++++--------- + drivers/s390/cio/device.h | 1 + + drivers/s390/cio/device_fsm.c | 29 ++++++++++++++++++----------- + drivers/s390/scsi/zfcp_ccw.c | 5 +++++ + 7 files changed, 59 insertions(+), 20 deletions(-) + +--- a/Documentation/kmsg/s390/zfcp ++++ b/Documentation/kmsg/s390/zfcp +@@ -100,6 +100,21 @@ + */ + + /*? ++ * Text: "%s: The FCP device did not respond within the specified time\n" ++ * Severity: Warning ++ * Parameter: ++ * @1: bus ID of the zfcp device ++ * Description: ++ * The common I/O layer waited for a response from the FCP adapter but ++ * no response was received within the specified time limit. This might ++ * indicate a hardware problem. ++ * User action: ++ * Consult your hardware administrator. If this problem persists, ++ * gather Linux debug data, collect the FCP adapter hardware logs, and ++ * report the problem to your support organization. ++ */ ++ ++/*? + * Text: "%s: Registering the FCP device with the SCSI stack failed\n" + * Severity: Error + * Parameter: +--- a/arch/s390/include/asm/cio.h ++++ b/arch/s390/include/asm/cio.h +@@ -456,6 +456,8 @@ struct ciw { + #define CIO_OPER 0x0004 + /* Sick revalidation of device. */ + #define CIO_REVALIDATE 0x0008 ++/* Device did not respond in time. */ ++#define CIO_BOXED 0x0010 + + /** + * struct ccw_dev_id - unique identifier for ccw devices +--- a/drivers/s390/block/dasd.c ++++ b/drivers/s390/block/dasd.c +@@ -2359,6 +2359,7 @@ int dasd_generic_notify(struct ccw_devic + ret = 0; + switch (event) { + case CIO_GONE: ++ case CIO_BOXED: + case CIO_NO_PATH: + /* First of all call extended error reporting. */ + dasd_eer_write(device, NULL, DASD_EER_NOPATH); +--- a/drivers/s390/cio/device.c ++++ b/drivers/s390/cio/device.c +@@ -479,11 +479,15 @@ static int online_store_recog_and_online + } + wait_event(cdev->private->wait_q, + cdev->private->flags.recog_done); ++ if (cdev->private->state != DEV_STATE_OFFLINE) ++ /* recognition failed */ ++ return -EAGAIN; + } + if (cdev->drv && cdev->drv->set_online) + ccw_device_set_online(cdev); + return 0; + } ++ + static int online_store_handle_online(struct ccw_device *cdev, int force) + { + int ret; +@@ -497,7 +501,9 @@ static int online_store_handle_online(st + return ret; + if (cdev->id.cu_type == 0) + cdev->private->state = DEV_STATE_NOT_OPER; +- online_store_recog_and_online(cdev); ++ ret = online_store_recog_and_online(cdev); ++ if (ret) ++ return ret; + } + return 0; + } +@@ -1017,33 +1023,35 @@ static void ccw_device_call_sch_unregist + put_device(&sch->dev); + } + ++void ccw_device_schedule_sch_unregister(struct ccw_device *cdev) ++{ ++ PREPARE_WORK(&cdev->private->kick_work, ++ ccw_device_call_sch_unregister); ++ queue_work(slow_path_wq, &cdev->private->kick_work); ++} ++ + /* + * subchannel recognition done. Called from the state machine. + */ + void + io_subchannel_recog_done(struct ccw_device *cdev) + { +- struct subchannel *sch; +- + if (css_init_done == 0) { + cdev->private->flags.recog_done = 1; + return; + } + switch (cdev->private->state) { ++ case DEV_STATE_BOXED: ++ /* Device did not respond in time. */ + case DEV_STATE_NOT_OPER: + cdev->private->flags.recog_done = 1; + /* Remove device found not operational. */ + if (!get_device(&cdev->dev)) + break; +- sch = to_subchannel(cdev->dev.parent); +- PREPARE_WORK(&cdev->private->kick_work, +- ccw_device_call_sch_unregister); +- queue_work(slow_path_wq, &cdev->private->kick_work); ++ ccw_device_schedule_sch_unregister(cdev); + if (atomic_dec_and_test(&ccw_device_init_count)) + wake_up(&ccw_device_init_wq); + break; +- case DEV_STATE_BOXED: +- /* Device did not respond in time. */ + case DEV_STATE_OFFLINE: + /* + * We can't register the device in interrupt context so +--- a/drivers/s390/cio/device.h ++++ b/drivers/s390/cio/device.h +@@ -86,6 +86,7 @@ int ccw_device_is_orphan(struct ccw_devi + int ccw_device_recognition(struct ccw_device *); + int ccw_device_online(struct ccw_device *); + int ccw_device_offline(struct ccw_device *); ++void ccw_device_schedule_sch_unregister(struct ccw_device *); + + /* Function prototypes for device status and basic sense stuff. */ + void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); +--- a/drivers/s390/cio/device_fsm.c ++++ b/drivers/s390/cio/device_fsm.c +@@ -253,13 +253,12 @@ ccw_device_recog_done(struct ccw_device + old_lpm = 0; + if (sch->lpm != old_lpm) + __recover_lost_chpids(sch, old_lpm); +- if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { +- if (state == DEV_STATE_NOT_OPER) { +- cdev->private->flags.recog_done = 1; +- cdev->private->state = DEV_STATE_DISCONNECTED; +- return; +- } +- /* Boxed devices don't need extra treatment. */ ++ if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID && ++ (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) { ++ cdev->private->flags.recog_done = 1; ++ cdev->private->state = DEV_STATE_DISCONNECTED; ++ wake_up(&cdev->private->wait_q); ++ return; + } + notify = 0; + same_dev = 0; /* Keep the compiler quiet... */ +@@ -304,12 +303,17 @@ ccw_device_recog_done(struct ccw_device + " subchannel 0.%x.%04x\n", + cdev->private->dev_id.devno, + sch->schid.ssid, sch->schid.sch_no); ++ if (cdev->id.cu_type != 0) { /* device was recognized before */ ++ cdev->private->flags.recog_done = 1; ++ cdev->private->state = DEV_STATE_BOXED; ++ wake_up(&cdev->private->wait_q); ++ return; ++ } + break; + } + cdev->private->state = state; + io_subchannel_recog_done(cdev); +- if (state != DEV_STATE_NOT_OPER) +- wake_up(&cdev->private->wait_q); ++ wake_up(&cdev->private->wait_q); + } + + /* +@@ -387,10 +391,13 @@ ccw_device_done(struct ccw_device *cdev, + + cdev->private->state = state; + +- +- if (state == DEV_STATE_BOXED) ++ if (state == DEV_STATE_BOXED) { + CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n", + cdev->private->dev_id.devno, sch->schid.sch_no); ++ if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED)) ++ ccw_device_schedule_sch_unregister(cdev); ++ cdev->private->flags.donotify = 0; ++ } + + if (cdev->private->flags.donotify) { + cdev->private->flags.donotify = 0; +--- a/drivers/s390/scsi/zfcp_ccw.c ++++ b/drivers/s390/scsi/zfcp_ccw.c +@@ -181,6 +181,11 @@ static int zfcp_ccw_notify(struct ccw_de + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, + 89, NULL); + break; ++ case CIO_BOXED: ++ dev_warn(&adapter->ccw_device->dev, "The FCP device " ++ "did not respond within the specified time\n"); ++ zfcp_erp_adapter_shutdown(adapter, 0, 91, NULL); ++ break; + } + return 1; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-06-zfcp_actcli_error.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-06-zfcp_actcli_error.patch new file mode 100644 index 000000000..2af1c5122 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-06-zfcp_actcli_error.patch @@ -0,0 +1,31 @@ +From: Gerald Schaefer +Subject: zfcp: Let actcli handle control file errors +References: bnc#487755,LTC#52571 + +Symptom: actcli returns "No such device or address", although the + access control tables have been updated or could be + updated with the -F flag. +Problem: The FCP channel reports an FSF status indicating, that + the channel is in use or that the -F flag has been + used. zfcp did present the "No such device.." problem for + any error for the "control file download command" which + is wrong. +Solution: Don't report "No such device or address" from zfcp for + errors specific to the "control file download command". + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fsf.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/s390/scsi/zfcp_fsf.c 2009-04-02 16:20:24.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2009-04-02 16:23:30.000000000 +0200 +@@ -2496,8 +2496,6 @@ out: + + static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req) + { +- if (req->qtcb->header.fsf_status != FSF_GOOD) +- req->status |= ZFCP_STATUS_FSFREQ_ERROR; + } + + /** diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-07-ctcm_remove_crash.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-07-ctcm_remove_crash.patch new file mode 100644 index 000000000..e40383eef --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-07-ctcm_remove_crash.patch @@ -0,0 +1,33 @@ +From: Gerald Schaefer +Subject: ctcm: avoid crash in ctcm_remove_device +References: bnc#487755,LTC#52679 + +Symptom: crash in debugging call of ctcm_remove_device +Problem: Channels are already removed when setting a + ctcm-device offline. Thus ctcm_remove_device must + not refer to channel information. +Solution: delete channel information from the trace call in + ctcm_remove_device. + +Acked-by: John Jolly +--- + drivers/s390/net/ctcm_main.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +Index: linux-sles11/drivers/s390/net/ctcm_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/ctcm_main.c ++++ linux-sles11/drivers/s390/net/ctcm_main.c +@@ -1665,10 +1665,8 @@ static void ctcm_remove_device(struct cc + BUG_ON(priv == NULL); + + CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, +- "removing device %s, r/w = %s/%s, proto : %d", +- priv->channel[READ]->netdev->name, +- priv->channel[READ]->id, priv->channel[WRITE]->id, +- priv->protocol); ++ "removing device %p, proto : %d", ++ cgdev, priv->protocol); + + if (cgdev->state == CCWGROUP_ONLINE) + ctcm_shutdown_device(cgdev); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-08-kernel_appldata_vtimer.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-08-kernel_appldata_vtimer.patch new file mode 100644 index 000000000..e6eac18a1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-08-kernel_appldata_vtimer.patch @@ -0,0 +1,46 @@ +From: Gerald Schaefer +Subject: kernel: appldata vtimer bug with cpu hotplug +References: bnc#487755,LTC#52680 + +Symptom: Kernel BUG on SLES 11 with cpu hotplug and appldata timer enabled. + On older distributions, the appldata interval will not expire + correctly instead (interval may be longer after cpu hotplug). +Problem: The mod_virt_timer() function will add a one-shot timer for new + cpus, not an interval timer. Also, on SLES 11 there is a misplaced + BUG_ON() statement in that function. +Solution: Work around by adding a new vtimer for cpus that get online, + before modifying it. + +Acked-by: John Jolly +--- + arch/s390/appldata/appldata_base.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +Index: linux-sles11/arch/s390/appldata/appldata_base.c +=================================================================== +--- linux-sles11.orig/arch/s390/appldata/appldata_base.c ++++ linux-sles11/arch/s390/appldata/appldata_base.c +@@ -478,13 +478,22 @@ void appldata_unregister_ops(struct appl + + static void __cpuinit appldata_online_cpu(int cpu) + { ++ u64 per_cpu_interval; ++ + init_virt_timer(&per_cpu(appldata_timer, cpu)); + per_cpu(appldata_timer, cpu).function = appldata_timer_function; + per_cpu(appldata_timer, cpu).data = (unsigned long) + &appldata_work; + atomic_inc(&appldata_expire_count); + spin_lock(&appldata_timer_lock); +- __appldata_vtimer_setup(APPLDATA_MOD_TIMER); ++ if (appldata_timer_active) { ++ per_cpu_interval = (u64) (appldata_interval * 1000 / ++ num_online_cpus()) * TOD_MICRO; ++ per_cpu(appldata_timer, cpu).expires = per_cpu_interval; ++ smp_call_function_single(cpu, add_virt_timer_periodic, ++ &per_cpu(appldata_timer, cpu), 1); ++ __appldata_vtimer_setup(APPLDATA_MOD_TIMER); ++ } + spin_unlock(&appldata_timer_lock); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-09-qeth_lan_offline.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-09-qeth_lan_offline.patch new file mode 100644 index 000000000..c13402b7a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-09-qeth_lan_offline.patch @@ -0,0 +1,75 @@ +From: Gerald Schaefer +Subject: qeth: avoid crash after detach of replugged device +References: bnc#487755,LTC#52681,LTC#52353 + +Symptom: kernel panic in qeth_l3_qdio_input_handler +Problem: If a qeth device is plugged off, setting the device + online stops in state HARDSETUP and a failure is + reported to the base cio-layer causing halt/clear to + be invoked. Replugging the device again triggers a + qeth recovery without notification of the cio-layer. + If a device is ungrouped in this state, the qeth + set_offline function is not invoked, because the + corresponding ccwgroup device is not in state ONLINE. + Then incoming traffic is still handled by the qdio + layer resulting in a crash in + qeth_l_qdio_input_handler, because (part of) the + qeth data structures for this device are already + removed. +Solution: After replugging the device qeth recovery should lead + to a working net device. Thus a "LAN offline" result + when setting a qeth device online must not report a + failure to the base cio-layer. + +Acked-by: John Jolly +--- + drivers/s390/net/qeth_l2_main.c | 4 +++- + drivers/s390/net/qeth_l3_main.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -873,6 +873,7 @@ static void qeth_l2_remove_device(struct + { + struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + ++ qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + + if (cgdev->state == CCWGROUP_ONLINE) { +@@ -1029,8 +1030,9 @@ static int __qeth_l2_set_online(struct c + dev_warn(&card->gdev->dev, + "The LAN is offline\n"); + card->lan_online = 0; ++ return 0; + } +- return rc; ++ goto out_remove; + } else + card->lan_online = 1; + +Index: linux-sles11/drivers/s390/net/qeth_l3_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l3_main.c ++++ linux-sles11/drivers/s390/net/qeth_l3_main.c +@@ -3033,6 +3033,7 @@ static void qeth_l3_remove_device(struct + { + struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + ++ qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + + if (cgdev->state == CCWGROUP_ONLINE) { +@@ -3107,8 +3108,9 @@ static int __qeth_l3_set_online(struct c + dev_warn(&card->gdev->dev, + "The LAN is offline\n"); + card->lan_online = 0; ++ return 0; + } +- return rc; ++ goto out_remove; + } else + card->lan_online = 1; + qeth_set_large_send(card, card->options.large_send); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-10-kernel_appldata_mutex.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-10-kernel_appldata_mutex.patch new file mode 100644 index 000000000..21cbd3680 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-10-kernel_appldata_mutex.patch @@ -0,0 +1,146 @@ +From: Gerald Schaefer +Subject: kernel: use mutex for appldata_ops instead of spin_lock. +References: bnc#487755,LTC#52788 + +Symptom: Possible deadlock when appldata_mem is active +Problem: The appldata_ops callbacks are called with a spin_lock held. + But the appldata_mem callback then calls all_vm_events(), which + calls get_online_cpus(), which might sleep. +Solution: Use a mutex instead of a spin_lock. + +Acked-by: John Jolly +--- + arch/s390/appldata/appldata_base.c | 32 ++++++++++++++++---------------- + arch/s390/appldata/appldata_mem.c | 4 +--- + 2 files changed, 17 insertions(+), 19 deletions(-) + +Index: linux-sles11/arch/s390/appldata/appldata_base.c +=================================================================== +--- linux-sles11.orig/arch/s390/appldata/appldata_base.c ++++ linux-sles11/arch/s390/appldata/appldata_base.c +@@ -97,7 +97,7 @@ static DECLARE_WORK(appldata_work, appld + /* + * Ops list + */ +-static DEFINE_SPINLOCK(appldata_ops_lock); ++static DEFINE_MUTEX(appldata_ops_mutex); + static LIST_HEAD(appldata_ops_list); + + +@@ -128,14 +128,14 @@ static void appldata_work_fn(struct work + + i = 0; + get_online_cpus(); +- spin_lock(&appldata_ops_lock); ++ mutex_lock(&appldata_ops_mutex); + list_for_each(lh, &appldata_ops_list) { + ops = list_entry(lh, struct appldata_ops, list); + if (ops->active == 1) { + ops->callback(ops->data); + } + } +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + put_online_cpus(); + } + +@@ -337,7 +337,7 @@ appldata_generic_handler(ctl_table *ctl, + struct list_head *lh; + + found = 0; +- spin_lock(&appldata_ops_lock); ++ mutex_lock(&appldata_ops_mutex); + list_for_each(lh, &appldata_ops_list) { + tmp_ops = list_entry(lh, struct appldata_ops, list); + if (&tmp_ops->ctl_table[2] == ctl) { +@@ -345,15 +345,15 @@ appldata_generic_handler(ctl_table *ctl, + } + } + if (!found) { +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + return -ENODEV; + } + ops = ctl->data; + if (!try_module_get(ops->owner)) { // protect this function +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + return -ENODEV; + } +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + + if (!*lenp || *ppos) { + *lenp = 0; +@@ -377,11 +377,11 @@ appldata_generic_handler(ctl_table *ctl, + return -EFAULT; + } + +- spin_lock(&appldata_ops_lock); ++ mutex_lock(&appldata_ops_mutex); + if ((buf[0] == '1') && (ops->active == 0)) { + // protect work queue callback + if (!try_module_get(ops->owner)) { +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + module_put(ops->owner); + return -ENODEV; + } +@@ -406,7 +406,7 @@ appldata_generic_handler(ctl_table *ctl, + "failed with rc=%d\n", ops->name, rc); + module_put(ops->owner); + } +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + out: + *lenp = len; + *ppos += len; +@@ -432,9 +432,9 @@ int appldata_register_ops(struct appldat + if (!ops->ctl_table) + return -ENOMEM; + +- spin_lock(&appldata_ops_lock); ++ mutex_lock(&appldata_ops_mutex); + list_add(&ops->list, &appldata_ops_list); +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + + ops->ctl_table[0].procname = appldata_proc_name; + ops->ctl_table[0].maxlen = 0; +@@ -451,9 +451,9 @@ int appldata_register_ops(struct appldat + goto out; + return 0; + out: +- spin_lock(&appldata_ops_lock); ++ mutex_lock(&appldata_ops_mutex); + list_del(&ops->list); +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + kfree(ops->ctl_table); + return -ENOMEM; + } +@@ -465,9 +465,9 @@ out: + */ + void appldata_unregister_ops(struct appldata_ops *ops) + { +- spin_lock(&appldata_ops_lock); ++ mutex_lock(&appldata_ops_mutex); + list_del(&ops->list); +- spin_unlock(&appldata_ops_lock); ++ mutex_unlock(&appldata_ops_mutex); + unregister_sysctl_table(ops->sysctl_header); + kfree(ops->ctl_table); + } +Index: linux-sles11/arch/s390/appldata/appldata_mem.c +=================================================================== +--- linux-sles11.orig/arch/s390/appldata/appldata_mem.c ++++ linux-sles11/arch/s390/appldata/appldata_mem.c +@@ -78,7 +78,7 @@ static void appldata_get_mem_data(void * + { + /* + * don't put large structures on the stack, we are +- * serialized through the appldata_ops_lock and can use static ++ * serialized through the appldata_ops_mutex and can use static + */ + static struct sysinfo val; + unsigned long ev[NR_VM_EVENT_ITEMS]; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-11-zfcp_fcp_port_handling.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-11-zfcp_fcp_port_handling.patch new file mode 100644 index 000000000..75e039d6c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-11-zfcp_fcp_port_handling.patch @@ -0,0 +1,100 @@ +From: Gerald Schaefer +Subject: zfcp: Fix oops when port disappears +References: bnc#487755,LTC#52844 + +Symptom: Kernel oops when port disappears. +Problem: The zfcp_port might have been removed, while the FC + fast_io_fail timer is still running and could trigger + the terminate_rport_io callback. +Solution: Set the pointer to the zfcp_port to NULL and check + accordingly before using it. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 3 +-- + drivers/s390/scsi/zfcp_fsf.c | 4 ++++ + drivers/s390/scsi/zfcp_scsi.c | 25 +++++++++++++++++++------ + 3 files changed, 24 insertions(+), 8 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -677,8 +677,7 @@ void zfcp_port_dequeue(struct zfcp_port + list_del(&port->list); + write_unlock_irq(&zfcp_data.config_lock); + if (port->rport) +- fc_remote_port_delete(port->rport); +- port->rport = NULL; ++ port->rport->dd_data = NULL; + zfcp_adapter_put(port->adapter); + sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); + device_unregister(&port->sysfs_device); +--- a/drivers/s390/scsi/zfcp_fsf.c ++++ b/drivers/s390/scsi/zfcp_fsf.c +@@ -175,12 +175,16 @@ static void zfcp_fsf_link_down_info_eval + struct fsf_link_down_info *link_down) + { + struct zfcp_adapter *adapter = req->adapter; ++ unsigned long flags; + + if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) + return; + + atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); ++ ++ read_lock_irqsave(&zfcp_data.config_lock, flags); + zfcp_scsi_schedule_rports_block(adapter); ++ read_unlock_irqrestore(&zfcp_data.config_lock, flags); + + if (!link_down) + goto out; +--- a/drivers/s390/scsi/zfcp_scsi.c ++++ b/drivers/s390/scsi/zfcp_scsi.c +@@ -491,10 +491,12 @@ static void zfcp_set_rport_dev_loss_tmo( + */ + static void zfcp_scsi_dev_loss_tmo_callbk(struct fc_rport *rport) + { +- struct zfcp_port *port = rport->dd_data; ++ struct zfcp_port *port; + + write_lock_irq(&zfcp_data.config_lock); +- port->rport = NULL; ++ port = rport->dd_data; ++ if (port) ++ port->rport = NULL; + write_unlock_irq(&zfcp_data.config_lock); + } + +@@ -508,9 +510,18 @@ static void zfcp_scsi_dev_loss_tmo_callb + */ + static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) + { +- struct zfcp_port *port = rport->dd_data; ++ struct zfcp_port *port; + +- zfcp_erp_port_reopen(port, 0, 152, NULL); ++ write_lock_irq(&zfcp_data.config_lock); ++ port = rport->dd_data; ++ if (port) ++ zfcp_port_get(port); ++ write_unlock_irq(&zfcp_data.config_lock); ++ ++ if (port) { ++ zfcp_erp_port_reopen(port, 0, 152, NULL); ++ zfcp_port_put(port); ++ } + } + + static void zfcp_scsi_rport_register(struct zfcp_port *port) +@@ -539,8 +550,10 @@ static void zfcp_scsi_rport_register(str + + static void zfcp_scsi_rport_block(struct zfcp_port *port) + { +- if (port->rport) +- fc_remote_port_delete(port->rport); ++ struct fc_rport *rport = port->rport; ++ ++ if (rport) ++ fc_remote_port_delete(rport); + } + + void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-12-zfcp_wka_wait_refcount.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-12-zfcp_wka_wait_refcount.patch new file mode 100644 index 000000000..d491739c3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-12-zfcp_wka_wait_refcount.patch @@ -0,0 +1,34 @@ +From: Gerald Schaefer +Subject: zfcp: deadlock between scheduled task, ERP and scan_work +References: bnc#487755,LTC#52845 + +Symptom: I/O stalls due to a pending ERP action. +Problem: Under certain timing constraints a deadlock can prevent + the ERP to finish. The ERP is trying to force the wka + port offline waiting for the scheduled work to finish. + The scheduled work is waiting for the refcount to + turn zero and another task is waiting for the ERP to + finish before descrementing the refcounter. ->deadlock +Solution: Don't wait for the refcount to turn zero. If required + the wka port offline function is called again later. + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_fc.c | 3 --- + 1 file changed, 3 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -75,9 +75,6 @@ static void zfcp_wka_port_offline(struct + struct zfcp_wka_port *wka_port = + container_of(dw, struct zfcp_wka_port, work); + +- wait_event(wka_port->completion_wq, +- atomic_read(&wka_port->refcount) == 0); +- + mutex_lock(&wka_port->mutex); + if ((atomic_read(&wka_port->refcount) != 0) || + (wka_port->status != ZFCP_WKA_PORT_ONLINE)) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-13-zfcp_deadlock_port_scan_ERP.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-13-zfcp_deadlock_port_scan_ERP.patch new file mode 100644 index 000000000..07a5fb3c0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-13-zfcp_deadlock_port_scan_ERP.patch @@ -0,0 +1,49 @@ +From: Gerald Schaefer +Subject: zfcp: deadlock between scheduled task and ERP +References: bnc#487755,LTC#52846 + +Symptom: I/O stall. +Problem: Waiting for the ERP in a task running in global wq + is a bad idea especially if the ERP needs to run another + job in this wq before it can finish. ->deadlock. +Solution: Remove the necessity to wait for the ERP. + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_erp.c | 2 +- + drivers/s390/scsi/zfcp_fc.c | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_erp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_erp.c ++++ linux-sles11/drivers/s390/scsi/zfcp_erp.c +@@ -725,7 +725,6 @@ static int zfcp_erp_adapter_strategy_gen + goto failed_openfcp; + + atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status); +- schedule_work(&act->adapter->scan_work); + + return ZFCP_ERP_SUCCEEDED; + +@@ -1215,6 +1214,7 @@ static void zfcp_erp_action_cleanup(stru + break; + + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: ++ schedule_work(&adapter->scan_work); + zfcp_adapter_put(adapter); + break; + } +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -631,7 +631,6 @@ int zfcp_scan_ports(struct zfcp_adapter + max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES; + max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE; + +- zfcp_erp_wait(adapter); /* wait until adapter is finished with ERP */ + if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) + return 0; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-14-zfcp_port_reference_counting.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-14-zfcp_port_reference_counting.patch new file mode 100644 index 000000000..056c8bb77 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-14-zfcp_port_reference_counting.patch @@ -0,0 +1,44 @@ +From: Gerald Schaefer +Subject: zfcp: Fix port reference counting +References: bnc#487755,LTC#52847 + +Symptom: If this problem appears zfcp ports cannot + be de-queued since it is checked for a + zero refcount. +Problem: The port reference counting is wrong for + existing zfcp ports when e.g. an adapter + gets on-line again. +Solution: During port scanning the reference counting + for existing ports should not be changed. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fc.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -535,6 +535,9 @@ static void zfcp_validate_port(struct zf + { + struct zfcp_adapter *adapter = port->adapter; + ++ if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) ++ return; ++ + atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); + + if ((port->supported_classes != 0) || +@@ -595,10 +598,8 @@ static int zfcp_scan_eval_gpn_ft(struct + if (acc->wwpn == fc_host_port_name(adapter->scsi_host)) + continue; + port = zfcp_get_port_by_wwpn(adapter, acc->wwpn); +- if (port) { +- zfcp_port_get(port); ++ if (port) + continue; +- } + + port = zfcp_port_enqueue(adapter, acc->wwpn, + ZFCP_STATUS_PORT_DID_DID | diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-15-zfcp_abort_handler_for_completions_in_progress.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-15-zfcp_abort_handler_for_completions_in_progress.patch new file mode 100644 index 000000000..a94cba547 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-15-zfcp_abort_handler_for_completions_in_progress.patch @@ -0,0 +1,23 @@ +From: Gerald Schaefer +Subject: zfcp: Fix abort handler for FSF requests in completion +References: bnc#487755,LTC#52848 + +Symptom: Kernel panic during FC switch port offline. +Problem: When the abort handler cannot find a pending FSF + request, the request completion could just be running. +Solution: Return FAILED in such a case by the abort handler. + +Acked-by: John Jolly +Index: linux-2.6.27.21-5.1.20090327_mz08/drivers/s390/scsi/zfcp_scsi.c +=================================================================== +--- linux-2.6.27.21-5.1.20090327_mz08.orig/drivers/s390/scsi/zfcp_scsi.c ++++ linux-2.6.27.21-5.1.20090327_mz08/drivers/s390/scsi/zfcp_scsi.c +@@ -175,7 +175,7 @@ static int zfcp_scsi_eh_abort_handler(st + if (!fsf_req) { + write_unlock_irqrestore(&adapter->abort_lock, flags); + zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); +- return retval; ++ return FAILED; /* completion could be in progress */ + } + fsf_req->data = NULL; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-12-16-zfcp_reference_counting_for_cfdc_requests.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-12-16-zfcp_reference_counting_for_cfdc_requests.patch new file mode 100644 index 000000000..977472961 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-12-16-zfcp_reference_counting_for_cfdc_requests.patch @@ -0,0 +1,26 @@ +From: Gerald Schaefer +Subject: zfcp: Fix reference counting for cfdc requests +References: bnc#487755,LTC#52849 + +Symptom: Setting adapter off-line will hang. +Problem: The adapter reference count can get negative. +Solution: Increase the reference count when issuing + cfdc requests. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_cfdc.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-sles11/drivers/s390/scsi/zfcp_cfdc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_cfdc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_cfdc.c +@@ -207,6 +207,7 @@ static long zfcp_cfdc_dev_ioctl(struct f + retval = -ENXIO; + goto free_buffer; + } ++ zfcp_adapter_get(adapter); + + retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, + data_user->control_file); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-13-01-af_iucv-fix-race-msgpending.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-13-01-af_iucv-fix-race-msgpending.patch new file mode 100644 index 000000000..75d0dc986 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-13-01-af_iucv-fix-race-msgpending.patch @@ -0,0 +1,58 @@ +From: Gerald Schaefer +Subject: af_iucv: Fix race when queuing incoming iucv messages +References: bnc#499845,LTC#53033 + +Symptom: A socket application does not receive any new data even + if incoming IUCV messages are received and queued. +Problem: AF_IUCV runs into a race when queueing incoming iucv + messages and receiving the resulting backlog. + If the Linux system is under pressure (high load or + steal time), the message queue grows up, but messages + are not received and queued onto the backlog queue. + In that case, applications do not receive any data with + recvmsg() even if AF_IUCV puts incoming messages onto + the message queue. +Solution: The race can be avoided if the message queue + spinlock in the message_pending callback is + spreaded across the entire callback function. + +Acked-by: John Jolly +--- + net/iucv/af_iucv.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -1089,6 +1089,8 @@ static void iucv_callback_rx(struct iucv + if (sk->sk_shutdown & RCV_SHUTDOWN) + return; + ++ spin_lock(&iucv->message_q.lock); ++ + if (!list_empty(&iucv->message_q.list) || + !skb_queue_empty(&iucv->backlog_skb_q)) + goto save_message; +@@ -1102,11 +1104,8 @@ static void iucv_callback_rx(struct iucv + if (!skb) + goto save_message; + +- spin_lock(&iucv->message_q.lock); + iucv_process_message(sk, skb, path, msg); +- spin_unlock(&iucv->message_q.lock); +- +- return; ++ goto out_unlock; + + save_message: + save_msg = kzalloc(sizeof(struct sock_msg_q), GFP_ATOMIC | GFP_DMA); +@@ -1115,8 +1114,9 @@ save_message: + save_msg->path = path; + save_msg->msg = *msg; + +- spin_lock(&iucv->message_q.lock); + list_add_tail(&save_msg->list, &iucv->message_q.list); ++ ++out_unlock: + spin_unlock(&iucv->message_q.lock); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-13-02-zfcp_changed_port_did.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-13-02-zfcp_changed_port_did.patch new file mode 100644 index 000000000..e57b38553 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-13-02-zfcp_changed_port_did.patch @@ -0,0 +1,88 @@ +From: Gerald Schaefer +Subject: zfcp: unrecoverable port on D_ID change. +References: bnc#499845,LTC#53175 + +Symptom: Remote storage port remains offline. +Problem: If, for whatever reason, the destination ID of a + remote storage port changes, it won't become available + again. The problem is that in such a situation the + mapping between the WWPN and D_ID is breaking. Since + all communication in a SAN is done via the D_ID, the + zfcp driver is treating this "new" D_ID as an unknown + reference leading to no further action. +Solution: Trigger a port reopen in situations which could be + the result of a changed D_ID and trigger a port reopen + for all ports having no D_ID on RSCN receiption. + +Acked-by: John Jolly + +--- + drivers/s390/scsi/zfcp_dbf.c | 4 ++-- + drivers/s390/scsi/zfcp_erp.c | 10 ++++++++-- + drivers/s390/scsi/zfcp_fc.c | 7 ++++++- + 3 files changed, 16 insertions(+), 5 deletions(-) + +Index: linux-sles11/drivers/s390/scsi/zfcp_erp.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_erp.c ++++ linux-sles11/drivers/s390/scsi/zfcp_erp.c +@@ -892,7 +892,6 @@ static int zfcp_erp_port_strategy_open_c + return zfcp_erp_port_strategy_open_port(act); + + case ZFCP_ERP_STEP_PORT_OPENING: +- /* D_ID might have changed during open */ + if (p_status & ZFCP_STATUS_COMMON_OPEN) { + if (p_status & ZFCP_STATUS_PORT_DID_DID) + return ZFCP_ERP_SUCCEEDED; +@@ -900,8 +899,15 @@ static int zfcp_erp_port_strategy_open_c + act->step = ZFCP_ERP_STEP_PORT_CLOSING; + return ZFCP_ERP_CONTINUES; + } +- /* fall through otherwise */ + } ++ if ((atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID) && ++ !(p_status & ZFCP_STATUS_COMMON_NOESC)) { ++ atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID, ++ &port->status); ++ _zfcp_erp_port_reopen(port, 0, 56, NULL); ++ return ZFCP_ERP_EXIT; ++ } ++ /* fall through otherwise */ + } + return ZFCP_ERP_FAILED; + } +Index: linux-sles11/drivers/s390/scsi/zfcp_dbf.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_dbf.c ++++ linux-sles11/drivers/s390/scsi/zfcp_dbf.c +@@ -545,8 +545,8 @@ static const char *zfcp_rec_dbf_ids[] = + [53] = "port boxed fcp", + [54] = "unit boxed fcp", + [55] = "port access denied", +- [56] = "", +- [57] = "", ++ [56] = "port d_id changed", ++ [57] = "port reopen on RSCN reception", + [58] = "", + [59] = "unit access denied", + [60] = "shared unit access denied open unit", +Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c ++++ linux-sles11/drivers/s390/scsi/zfcp_fc.c +@@ -127,9 +127,14 @@ static void _zfcp_fc_incoming_rscn(struc + struct zfcp_port *port; + + read_lock_irqsave(&zfcp_data.config_lock, flags); +- list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) ++ list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { + if ((port->d_id & range) == (elem->nport_did & range)) + zfcp_test_link(port); ++ if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID)) ++ zfcp_erp_port_reopen(port, ++ ZFCP_STATUS_COMMON_ERP_FAILED, 57, ++ 0); ++ } + + read_unlock_irqrestore(&zfcp_data.config_lock, flags); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-13-03-qeth_checksum.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-13-03-qeth_checksum.patch new file mode 100644 index 000000000..823a2ca23 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-13-03-qeth_checksum.patch @@ -0,0 +1,51 @@ +From: Gerald Schaefer +Subject: qeth: improve no_checksumming handling for layer3 +References: bnc#499845,LTC#53306 + +Symptom: Messages "hw csum failure" when tcpdump is running +Problem: If sysfs-attribute checksumming is set to + "no-checksumming" for a layer3 qeth device, incoming + data is stored in skbs with incorrect setting of + skb->ip_summed. +Solution: Set skb->ip_summed to CHECKSUM_UNNECESSARY if + RX-checksumming is not required. + +Acked-by: John Jolly +--- + drivers/s390/net/qeth_l3_main.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +Index: linux-sles11/drivers/s390/net/qeth_l3_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l3_main.c ++++ linux-sles11/drivers/s390/net/qeth_l3_main.c +@@ -1939,16 +1939,22 @@ static inline __u16 qeth_l3_rebuild_skb( + hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); + } + +- skb->ip_summed = card->options.checksum_type; +- if (card->options.checksum_type == HW_CHECKSUMMING) { ++ switch (card->options.checksum_type) { ++ case SW_CHECKSUMMING: ++ skb->ip_summed = CHECKSUM_NONE; ++ break; ++ case NO_CHECKSUMMING: ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ break; ++ case HW_CHECKSUMMING: + if ((hdr->hdr.l3.ext_flags & +- (QETH_HDR_EXT_CSUM_HDR_REQ | +- QETH_HDR_EXT_CSUM_TRANSP_REQ)) == +- (QETH_HDR_EXT_CSUM_HDR_REQ | +- QETH_HDR_EXT_CSUM_TRANSP_REQ)) ++ (QETH_HDR_EXT_CSUM_HDR_REQ | ++ QETH_HDR_EXT_CSUM_TRANSP_REQ)) == ++ (QETH_HDR_EXT_CSUM_HDR_REQ | ++ QETH_HDR_EXT_CSUM_TRANSP_REQ)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else +- skb->ip_summed = SW_CHECKSUMMING; ++ skb->ip_summed = CHECKSUM_NONE; + } + + return vlan_id; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-13-04-qeth-port-isolation.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-13-04-qeth-port-isolation.patch new file mode 100644 index 000000000..a3dbed71d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-13-04-qeth-port-isolation.patch @@ -0,0 +1,84 @@ +From: Gerald Schaefer +Subject: qeth: handle error codes from z/VM VSwitch Port Isolation +References: bnc#499845,LTC#53307 + +Symptom: Message "Error in registering MAC address on device" +Problem: Usually z/VM guests are allowed to change the MAC address + of a VSWITCH device. This is no longer true, if + z/VM Virtual Switch Port Isolation is active (see + z/VM Apars VM64281 and VM64463). The corresponding + error code should be translated into a meaningful + message. +Solution: qeth driver issues message + "MAC address is not authorized" + if z/VM Virtual Switch Port Isolation forbids setting + of a locally defined virtual MAC address. + +Acked-by: John Jolly +--- + drivers/s390/net/qeth_core_mpc.c | 2 ++ + drivers/s390/net/qeth_core_mpc.h | 2 ++ + drivers/s390/net/qeth_l2_main.c | 24 ++++++++++++++++++++++++ + 3 files changed, 28 insertions(+) + +Index: linux-sles11/drivers/s390/net/qeth_core_mpc.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_mpc.c ++++ linux-sles11/drivers/s390/net/qeth_core_mpc.c +@@ -181,6 +181,8 @@ static struct ipa_rc_msg qeth_ipa_rc_msg + {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"}, + {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"}, + {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"}, ++ {IPA_RC_L2_MAC_NOT_AUTH_BY_HYP, "L2 mac not authorized by hypervisor"}, ++ {IPA_RC_L2_MAC_NOT_AUTH_BY_ADP, "L2 mac not authorized by adapter"}, + {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"}, + {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"}, + {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"}, +Index: linux-sles11/drivers/s390/net/qeth_core_mpc.h +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_core_mpc.h ++++ linux-sles11/drivers/s390/net/qeth_core_mpc.h +@@ -168,6 +168,8 @@ enum qeth_ipa_return_codes { + IPA_RC_L2_ADDR_TABLE_FULL = 0x2006, + IPA_RC_L2_DUP_LAYER3_MAC = 0x200a, + IPA_RC_L2_GMAC_NOT_FOUND = 0x200b, ++ IPA_RC_L2_MAC_NOT_AUTH_BY_HYP = 0x200c, ++ IPA_RC_L2_MAC_NOT_AUTH_BY_ADP = 0x200d, + IPA_RC_L2_MAC_NOT_FOUND = 0x2010, + IPA_RC_L2_INVALID_VLAN_ID = 0x2015, + IPA_RC_L2_DUP_VLAN_ID = 0x2016, +Index: linux-sles11/drivers/s390/net/qeth_l2_main.c +=================================================================== +--- linux-sles11.orig/drivers/s390/net/qeth_l2_main.c ++++ linux-sles11/drivers/s390/net/qeth_l2_main.c +@@ -504,6 +504,30 @@ static int qeth_l2_send_setmac_cb(struct + if (cmd->hdr.return_code) { + QETH_DBF_TEXT_(TRACE, 2, "L2er%x", cmd->hdr.return_code); + card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; ++ switch (cmd->hdr.return_code) { ++ case IPA_RC_L2_DUP_MAC: ++ case IPA_RC_L2_DUP_LAYER3_MAC: ++ dev_warn(&card->gdev->dev, ++ "MAC address " ++ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " ++ "already exists\n", ++ card->dev->dev_addr[0], card->dev->dev_addr[1], ++ card->dev->dev_addr[2], card->dev->dev_addr[3], ++ card->dev->dev_addr[4], card->dev->dev_addr[5]); ++ break; ++ case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: ++ case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: ++ dev_warn(&card->gdev->dev, ++ "MAC address " ++ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " ++ "is not authorized\n", ++ card->dev->dev_addr[0], card->dev->dev_addr[1], ++ card->dev->dev_addr[2], card->dev->dev_addr[3], ++ card->dev->dev_addr[4], card->dev->dev_addr[5]); ++ break; ++ default: ++ break; ++ } + cmd->hdr.return_code = -EIO; + } else { + card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-14-01-af_iucv-connect-free-path.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-14-01-af_iucv-connect-free-path.patch new file mode 100644 index 000000000..cd666115d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-14-01-af_iucv-connect-free-path.patch @@ -0,0 +1,38 @@ +From: Gerald Schaefer +Subject: af_iucv: avoid left over IUCV connections from failing connects +References: bnc#514644,LTC#52270 + +Symptom: extra unused IUCV connections left around +Problem: For certain types of AFIUCV socket connect failures + connection cleanup is insufficient resulting in + left over IUCV connections. +Solution: Add some cleanup-statements to avoid cluttered IUCV + connections. + +Acked-by: John Jolly +--- + net/iucv/af_iucv.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +Index: linux-sles11/net/iucv/af_iucv.c +=================================================================== +--- linux-sles11.orig/net/iucv/af_iucv.c ++++ linux-sles11/net/iucv/af_iucv.c +@@ -503,9 +503,15 @@ static int iucv_sock_connect(struct sock + } + + if (sk->sk_state == IUCV_DISCONN) { +- release_sock(sk); +- return -ECONNREFUSED; ++ err = -ECONNREFUSED; + } ++ ++ if (err) { ++ iucv_path_sever(iucv->path, NULL); ++ iucv_path_free(iucv->path); ++ iucv->path = NULL; ++ } ++ + done: + release_sock(sk); + return err; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-01-zfcp-erp-escalation.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-01-zfcp-erp-escalation.patch new file mode 100644 index 000000000..39df29a99 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-01-zfcp-erp-escalation.patch @@ -0,0 +1,113 @@ +From: Gerald Schaefer +Subject: zfcp: Fix erp escalation procedure +References: bnc#518291,LTC#54456 + +Symptom: After a failure the zfcp erp gives up. +Problem: When a zfcp erp step fails the zfcp erp might end without + setting the driver internal flags appropriately. +Solution: Fix the erp escalation procedure. If a erp action fails, + retry it until the retry counter exceeds. This ensures + that the erp continues or the failed flag is set + correctly. If for some reason another action is + necessary, this will be triggered from outside the erp, + to avoid global recoveries for single port failures. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_dbf.c | 8 ++---- + drivers/s390/scsi/zfcp_erp.c | 50 ++++++++++++++++++++----------------------- + 2 files changed, 27 insertions(+), 31 deletions(-) + +--- a/drivers/s390/scsi/zfcp_erp.c 2009-06-23 10:45:52.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_erp.c 2009-06-23 14:13:30.000000000 +0200 +@@ -549,40 +549,35 @@ static void _zfcp_erp_unit_reopen_all(st + _zfcp_erp_unit_reopen(unit, clear, id, ref); + } + +-static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) ++static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) + { +- struct zfcp_adapter *adapter = act->adapter; +- struct zfcp_port *port = act->port; +- struct zfcp_unit *unit = act->unit; +- u32 status = act->status; +- +- /* initiate follow-up actions depending on success of finished action */ + switch (act->action) { +- + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: +- if (status == ZFCP_ERP_SUCCEEDED) +- _zfcp_erp_port_reopen_all(adapter, 0, 70, NULL); +- else +- _zfcp_erp_adapter_reopen(adapter, 0, 71, NULL); ++ _zfcp_erp_adapter_reopen(act->adapter, 0, 71, NULL); + break; +- + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: +- if (status == ZFCP_ERP_SUCCEEDED) +- _zfcp_erp_port_reopen(port, 0, 72, NULL); +- else +- _zfcp_erp_adapter_reopen(adapter, 0, 73, NULL); ++ _zfcp_erp_port_forced_reopen(act->port, 0, 73, NULL); + break; +- + case ZFCP_ERP_ACTION_REOPEN_PORT: +- if (status == ZFCP_ERP_SUCCEEDED) +- _zfcp_erp_unit_reopen_all(port, 0, 74, NULL); +- else +- _zfcp_erp_port_forced_reopen(port, 0, 75, NULL); ++ _zfcp_erp_port_reopen(act->port, 0, 75, NULL); + break; +- + case ZFCP_ERP_ACTION_REOPEN_UNIT: +- if (status != ZFCP_ERP_SUCCEEDED) +- _zfcp_erp_port_reopen(unit->port, 0, 76, NULL); ++ _zfcp_erp_unit_reopen(act->unit, 0, 76, NULL); ++ break; ++ } ++} ++ ++static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) ++{ ++ switch (act->action) { ++ case ZFCP_ERP_ACTION_REOPEN_ADAPTER: ++ _zfcp_erp_port_reopen_all(act->adapter, 0, 70, NULL); ++ break; ++ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: ++ _zfcp_erp_port_reopen(act->port, 0, 72, NULL); ++ break; ++ case ZFCP_ERP_ACTION_REOPEN_PORT: ++ _zfcp_erp_unit_reopen_all(act->port, 0, 74, NULL); + break; + } + } +@@ -1297,7 +1292,10 @@ static int zfcp_erp_strategy(struct zfcp + retval = zfcp_erp_strategy_statechange(erp_action, retval); + if (retval == ZFCP_ERP_EXIT) + goto unlock; +- zfcp_erp_strategy_followup_actions(erp_action); ++ if (retval == ZFCP_ERP_SUCCEEDED) ++ zfcp_erp_strategy_followup_success(erp_action); ++ if (retval == ZFCP_ERP_FAILED) ++ zfcp_erp_strategy_followup_failed(erp_action); + + unlock: + write_unlock(&adapter->erp_lock); +--- a/drivers/s390/scsi/zfcp_dbf.c 2009-06-23 10:45:52.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_dbf.c 2009-06-23 14:20:41.000000000 +0200 +@@ -563,12 +563,10 @@ static const char *zfcp_rec_dbf_ids[] = + [71] = "adapter recovery escalation after failed adapter recovery", + [72] = "port recovery follow-up after successful physical port " + "recovery", +- [73] = "adapter recovery escalation after failed physical port " +- "recovery", ++ [73] = "physical port recovery retry after failure", + [74] = "unit recovery follow-up after successful port recovery", +- [75] = "physical port recovery escalation after failed port " +- "recovery", +- [76] = "port recovery escalation after failed unit recovery", ++ [75] = "port recovery retry after failure", ++ [76] = "unit recovery retry after failure", + [77] = "", + [78] = "duplicate request id", + [79] = "link down", diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-02-phys-port-close.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-02-phys-port-close.patch new file mode 100644 index 000000000..4b7040939 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-02-phys-port-close.patch @@ -0,0 +1,27 @@ +From: Gerald Schaefer +Subject: zfcp: Handle "forced close" correctly in the erp +References: bnc#518291,LTC#54458 + +Symptom: After a remote port problem, the zfcp erp does not + recover from the problem. +Problem: After trying the "forced close" step from the erp the + the check of the flag indicating if the port is still + open is wrong. +Solution: Fix the check of the open flag. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_erp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_erp.c 2009-06-23 14:11:53.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_erp.c 2009-06-23 14:11:57.000000000 +0200 +@@ -796,7 +796,7 @@ static int zfcp_erp_port_forced_strategy + return ZFCP_ERP_FAILED; + + case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: +- if (status & ZFCP_STATUS_PORT_PHYS_OPEN) ++ if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN)) + return ZFCP_ERP_SUCCEEDED; + } + return ZFCP_ERP_FAILED; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-03-zfcp-recover-stall.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-03-zfcp-recover-stall.patch new file mode 100644 index 000000000..112af1d8c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-03-zfcp-recover-stall.patch @@ -0,0 +1,46 @@ +From: Gerald Schaefer +Subject: zfcp: Recover from stalled outbound queue +References: bnc#518291,LTC#54460 + +Symptom: In some error scenarious, the channel can stall. To + Linux this looks like a stall in the outbound queue. + Linux has to recover this. +Problem: There is no trigger to recover the queues if the outbound + queue stalls. +Solution: When trying to issue a non-SCSI command, zfcp waits for + 5 seconds to get a free SBAL in the queue. Use this timeout + as a trigger: If after 5 seconds there is no free SBAL, + assume a stalled outbound queue and trigger recovery. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_dbf.c | 2 +- + drivers/s390/scsi/zfcp_fsf.c | 5 ++++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/s390/scsi/zfcp_fsf.c 2009-06-23 14:24:48.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2009-06-23 14:26:00.000000000 +0200 +@@ -668,8 +668,11 @@ static int zfcp_fsf_req_sbal_get(struct + zfcp_fsf_sbal_check(adapter), 5 * HZ); + if (ret > 0) + return 0; +- if (!ret) ++ if (!ret) { + atomic_inc(&adapter->qdio_outb_full); ++ /* assume hanging outbound queue, try queue recovery */ ++ zfcp_erp_adapter_reopen(adapter, 0, 77, NULL); ++ } + + spin_lock_bh(&adapter->req_q_lock); + return -EIO; +--- a/drivers/s390/scsi/zfcp_dbf.c 2009-06-23 14:20:41.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_dbf.c 2009-06-23 14:25:50.000000000 +0200 +@@ -567,7 +567,7 @@ static const char *zfcp_rec_dbf_ids[] = + [74] = "unit recovery follow-up after successful port recovery", + [75] = "port recovery retry after failure", + [76] = "unit recovery retry after failure", +- [77] = "", ++ [77] = "adapter reopen from queue stall", + [78] = "duplicate request id", + [79] = "link down", + [80] = "exclusive read-only unit access unsupported", diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-04-zfcp-unchained-sbals.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-04-zfcp-unchained-sbals.patch new file mode 100644 index 000000000..2b048c3b1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-04-zfcp-unchained-sbals.patch @@ -0,0 +1,72 @@ +From: Gerald Schaefer +Subject: zfcp: Use only single SBAL commands from recovery +References: bnc#518291,LTC#54462 + +Symptom: Issuing an ELS request might not detect a stalled + outbound queue +Problem: zfcp uses chained SBALs for ELS requests leading to the + situation that the ELS request gets one free SBAL, but + not the following ones. In this situation the ELS request + fails but does not trigger the error handling for the + stalled queue. +Solution: Use unchained SBALs where possible, especially for + commands from the erp. This guarantees that each erp + command will get the required SBAL or trigger queue + recovery. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_fsf.c | 33 +++++++++++++++++++++++++-------- + 1 file changed, 25 insertions(+), 8 deletions(-) + +--- a/drivers/s390/scsi/zfcp_fsf.c 2009-07-01 12:26:28.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2009-07-01 12:28:43.000000000 +0200 +@@ -1012,6 +1012,23 @@ skip_fsfstatus: + send_ct->handler(send_ct->handler_data); + } + ++static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale, ++ struct scatterlist *sg_req, ++ struct scatterlist *sg_resp) ++{ ++ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; ++ sbale[2].addr = sg_virt(sg_req); ++ sbale[2].length = sg_req->length; ++ sbale[3].addr = sg_virt(sg_resp); ++ sbale[3].length = sg_resp->length; ++ sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; ++} ++ ++static int zfcp_fsf_one_sbal(struct scatterlist *sg) ++{ ++ return sg_is_last(sg) && sg->length <= PAGE_SIZE; ++} ++ + static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, + struct scatterlist *sg_req, + struct scatterlist *sg_resp, +@@ -1022,16 +1039,16 @@ static int zfcp_fsf_setup_ct_els_sbals(s + int bytes; + + if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { +- if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || +- !sg_is_last(sg_req) || !sg_is_last(sg_resp)) ++ if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp)) + return -EOPNOTSUPP; + +- sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; +- sbale[2].addr = sg_virt(sg_req); +- sbale[2].length = sg_req->length; +- sbale[3].addr = sg_virt(sg_resp); +- sbale[3].length = sg_resp->length; +- sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; ++ zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); ++ return 0; ++ } ++ ++ /* use single, unchained SBAL if it can hold the request */ ++ if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) { ++ zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-05-zfcp-erp-notify.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-05-zfcp-erp-notify.patch new file mode 100644 index 000000000..b6d4800c8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-05-zfcp-erp-notify.patch @@ -0,0 +1,31 @@ +From: Gerald Schaefer +Subject: zfcp: Use correct flags when reporting status to erp +References: bnc#518291,LTC#54463 + +Symptom: The erp might not detect correctly problems from the + gid_pn nameserver requests. +Problem: The wrong status flags have been used to pass updates via + the call to zfcp_erp_notify. +Solution: Use the correct status flags when calling zfcp_erp_notify. + +Acked-by: John Jolly +--- + + drivers/s390/scsi/zfcp_erp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/s390/scsi/zfcp_erp.c 2009-07-01 11:31:02.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_erp.c 2009-07-01 12:44:45.000000000 +0200 +@@ -850,10 +850,10 @@ void zfcp_erp_port_strategy_open_lookup( + + retval = zfcp_fc_ns_gid_pn(&port->erp_action); + if (retval == -ENOMEM) +- zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); ++ zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM); + port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; + if (retval) +- zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); ++ zfcp_erp_notify(&port->erp_action, 0); + zfcp_port_put(port); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-06-zfcp-recovery-wait.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-06-zfcp-recovery-wait.patch new file mode 100644 index 000000000..b792c5e6b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-06-zfcp-recovery-wait.patch @@ -0,0 +1,369 @@ +From: Gerald Schaefer +Subject: zfcp: Improve reliability of SCSI eh handlers in zfcp +References: bnc#518291,LTC#54465 + +Symptom: During error recovery scenarious, zfcp and SCSI midlayer + run error recovery and later SCSI devices are flagged as + "offline" in the Linux kernel. +Problem: The SCSI midlayer error recovery issues various requests + to zfcp. If zfcp is recovering internally at the same + time, the SCSI midlayer requests fail immediately and the + SCSI midlayer recovery will run until hitting the final + step where SCSI devices are flagged as "offline". +Solution: Backport the commit 63caf367e1c92e0667a344d9b687c04e6ef054b5. + This commit changes the SCSI midlayer recovery callbacks + in zfcp to wait for the zfcp erp to finish before issuing any + request. If necessary retry the request three times. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_def.h | 3 - + drivers/s390/scsi/zfcp_ext.h | 11 +-- + drivers/s390/scsi/zfcp_fsf.c | 39 ++++--------- + drivers/s390/scsi/zfcp_scsi.c | 122 ++++++++++++++++++++---------------------- + 4 files changed, 77 insertions(+), 98 deletions(-) + +--- a/drivers/s390/scsi/zfcp_def.h 2009-07-01 13:39:47.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_def.h 2009-07-01 13:39:50.000000000 +0200 +@@ -621,9 +621,6 @@ struct zfcp_fsf_req_qtcb { + + /********************** ZFCP SPECIFIC DEFINES ********************************/ + +-#define ZFCP_REQ_AUTO_CLEANUP 0x00000002 +-#define ZFCP_REQ_NO_QTCB 0x00000008 +- + #define ZFCP_SET 0x00000100 + #define ZFCP_CLEAR 0x00000200 + +--- a/drivers/s390/scsi/zfcp_ext.h 2009-07-01 13:39:47.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_ext.h 2009-07-01 13:39:50.000000000 +0200 +@@ -127,16 +127,13 @@ extern int zfcp_status_read_refill(struc + extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, + struct zfcp_erp_action *); + extern int zfcp_fsf_send_els(struct zfcp_send_els *); +-extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, +- struct zfcp_unit *, +- struct scsi_cmnd *, int, int); ++extern int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *, ++ struct scsi_cmnd *); + extern void zfcp_fsf_req_complete(struct zfcp_fsf_req *); + extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); +-extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *, +- struct zfcp_unit *, u8, int); ++extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *, u8); + extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long, +- struct zfcp_adapter *, +- struct zfcp_unit *, int); ++ struct zfcp_unit *); + + /* zfcp_qdio.c */ + extern int zfcp_qdio_allocate(struct zfcp_adapter *); +--- a/drivers/s390/scsi/zfcp_fsf.c 2009-07-01 13:39:47.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2009-07-01 13:39:50.000000000 +0200 +@@ -11,6 +11,9 @@ + #include + #include "zfcp_ext.h" + ++#define ZFCP_REQ_AUTO_CLEANUP 0x00000002 ++#define ZFCP_REQ_NO_QTCB 0x00000008 ++ + static void zfcp_fsf_request_timeout_handler(unsigned long data) + { + struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; +@@ -911,27 +914,22 @@ static void zfcp_fsf_abort_fcp_command_h + /** + * zfcp_fsf_abort_fcp_command - abort running SCSI command + * @old_req_id: unsigned long +- * @adapter: pointer to struct zfcp_adapter + * @unit: pointer to struct zfcp_unit +- * @req_flags: integer specifying the request flags + * Returns: pointer to struct zfcp_fsf_req +- * +- * FIXME(design): should be watched by a timeout !!! + */ + + struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, +- struct zfcp_adapter *adapter, +- struct zfcp_unit *unit, +- int req_flags) ++ struct zfcp_unit *unit) + { + struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; ++ struct zfcp_adapter *adapter = unit->port->adapter; + + spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; + req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, +- req_flags, adapter->pool.fsf_req_abort); ++ 0, adapter->pool.fsf_req_abort); + if (IS_ERR(req)) { + req = NULL; + goto out; +@@ -2334,21 +2332,17 @@ static void zfcp_set_fcp_dl(struct fcp_c + + /** + * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) +- * @adapter: adapter where scsi command is issued + * @unit: unit where command is sent to + * @scsi_cmnd: scsi command to be sent +- * @timer: timer to be started when request is initiated +- * @req_flags: flags for fsf_request + */ +-int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, +- struct zfcp_unit *unit, +- struct scsi_cmnd *scsi_cmnd, +- int use_timer, int req_flags) ++int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, ++ struct scsi_cmnd *scsi_cmnd) + { + struct zfcp_fsf_req *req; + struct fcp_cmnd_iu *fcp_cmnd_iu; + unsigned int sbtype; + int real_bytes, retval = -EIO; ++ struct zfcp_adapter *adapter = unit->port->adapter; + + if (unlikely(!(atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) +@@ -2359,7 +2353,8 @@ int zfcp_fsf_send_fcp_command_task(struc + atomic_inc(&adapter->qdio_outb_full); + goto out; + } +- req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, ++ req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, ++ ZFCP_REQ_AUTO_CLEANUP, + adapter->pool.fsf_req_scsi); + if (IS_ERR(req)) { + retval = PTR_ERR(req); +@@ -2441,9 +2436,6 @@ int zfcp_fsf_send_fcp_command_task(struc + + zfcp_set_fcp_dl(fcp_cmnd_iu, real_bytes); + +- if (use_timer) +- zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); +- + retval = zfcp_fsf_req_send(req); + if (unlikely(retval)) + goto failed_scsi_cmnd; +@@ -2461,19 +2453,16 @@ out: + + /** + * zfcp_fsf_send_fcp_ctm - send SCSI task management command +- * @adapter: pointer to struct zfcp-adapter + * @unit: pointer to struct zfcp_unit + * @tm_flags: unsigned byte for task management flags +- * @req_flags: int request flags + * Returns: on success pointer to struct fsf_req, NULL otherwise + */ +-struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, +- struct zfcp_unit *unit, +- u8 tm_flags, int req_flags) ++struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags) + { + struct qdio_buffer_element *sbale; + struct zfcp_fsf_req *req = NULL; + struct fcp_cmnd_iu *fcp_cmnd_iu; ++ struct zfcp_adapter *adapter = unit->port->adapter; + + if (unlikely(!(atomic_read(&unit->status) & + ZFCP_STATUS_COMMON_UNBLOCKED))) +@@ -2482,7 +2471,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_c + spin_lock_bh(&adapter->req_q_lock); + if (zfcp_fsf_req_sbal_get(adapter)) + goto out; +- req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, ++ req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, 0, + adapter->pool.fsf_req_scsi); + if (IS_ERR(req)) { + req = NULL; +--- a/drivers/s390/scsi/zfcp_scsi.c 2009-07-01 13:39:47.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_scsi.c 2009-07-01 13:41:23.000000000 +0200 +@@ -94,8 +94,7 @@ static int zfcp_scsi_queuecommand(struct + return 0;; + } + +- ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, +- ZFCP_REQ_AUTO_CLEANUP); ++ ret = zfcp_fsf_send_fcp_command_task(unit, scpnt); + if (unlikely(ret == -EBUSY)) + return SCSI_MLQUEUE_DEVICE_BUSY; + else if (unlikely(ret < 0)) +@@ -153,79 +152,91 @@ out: + + static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) + { +- struct Scsi_Host *scsi_host; +- struct zfcp_adapter *adapter; +- struct zfcp_unit *unit; +- struct zfcp_fsf_req *fsf_req; ++ struct Scsi_Host *scsi_host = scpnt->device->host; ++ struct zfcp_adapter *adapter = ++ (struct zfcp_adapter *) scsi_host->hostdata[0]; ++ struct zfcp_unit *unit = scpnt->device->hostdata; ++ struct zfcp_fsf_req *old_req, *abrt_req; + unsigned long flags; + unsigned long old_req_id = (unsigned long) scpnt->host_scribble; + int retval = SUCCESS; +- +- scsi_host = scpnt->device->host; +- adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; +- unit = scpnt->device->hostdata; ++ int retry = 3; + + /* avoid race condition between late normal completion and abort */ + write_lock_irqsave(&adapter->abort_lock, flags); + +- /* Check whether corresponding fsf_req is still pending */ + spin_lock(&adapter->req_list_lock); +- fsf_req = zfcp_reqlist_find(adapter, old_req_id); ++ old_req = zfcp_reqlist_find(adapter, old_req_id); + spin_unlock(&adapter->req_list_lock); +- if (!fsf_req) { ++ if (!old_req) { + write_unlock_irqrestore(&adapter->abort_lock, flags); +- zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); +- return FAILED; /* completion could be in progress */ ++ zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, ++ old_req_id); ++ return SUCCESS; + } +- fsf_req->data = NULL; ++ old_req->data = NULL; + + /* don't access old fsf_req after releasing the abort_lock */ + write_unlock_irqrestore(&adapter->abort_lock, flags); + +- fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); +- if (!fsf_req) { +- zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, +- old_req_id); +- retval = FAILED; +- return retval; ++ while (retry--) { ++ abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit); ++ if (abrt_req) ++ break; ++ ++ zfcp_erp_wait(adapter); ++ if (!(atomic_read(&adapter->status) & ++ ZFCP_STATUS_COMMON_RUNNING)) { ++ zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, ++ old_req_id); ++ return SUCCESS; ++ } + } ++ if (!abrt_req) ++ return FAILED; + +- __wait_event(fsf_req->completion_wq, +- fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); ++ wait_event(abrt_req->completion_wq, ++ abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + +- if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { +- zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); +- } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { +- zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); +- } else { +- zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); ++ if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) ++ zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0); ++ else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) ++ zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0); ++ else { ++ zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0); + retval = FAILED; + } +- zfcp_fsf_req_free(fsf_req); +- ++ zfcp_fsf_req_free(abrt_req); + return retval; + } + +-static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, +- struct scsi_cmnd *scpnt) ++static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) + { ++ struct zfcp_unit *unit = scpnt->device->hostdata; + struct zfcp_adapter *adapter = unit->port->adapter; + struct zfcp_fsf_req *fsf_req; + int retval = SUCCESS; ++ int retry = 3; + +- /* issue task management function */ +- fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); +- if (!fsf_req) { +- zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); +- return FAILED; ++ while (retry--) { ++ fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags); ++ if (fsf_req) ++ break; ++ ++ zfcp_erp_wait(adapter); ++ if (!(atomic_read(&adapter->status) & ++ ZFCP_STATUS_COMMON_RUNNING)) { ++ zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, ++ scpnt); ++ return SUCCESS; ++ } + } ++ if (!fsf_req) ++ return FAILED; + +- __wait_event(fsf_req->completion_wq, +- fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); ++ wait_event(fsf_req->completion_wq, ++ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + +- /* +- * check completion status of task management function +- */ + if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { + zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); + retval = FAILED; +@@ -236,39 +247,24 @@ static int zfcp_task_mgmt_function(struc + zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); + + zfcp_fsf_req_free(fsf_req); +- + return retval; + } + + static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) + { +- struct zfcp_unit *unit = scpnt->device->hostdata; +- +- if (!unit) { +- WARN_ON(1); +- return SUCCESS; +- } +- return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt); ++ return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET); + } + + static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) + { +- struct zfcp_unit *unit = scpnt->device->hostdata; +- +- if (!unit) { +- WARN_ON(1); +- return SUCCESS; +- } +- return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt); ++ return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET); + } + + static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) + { +- struct zfcp_unit *unit; +- struct zfcp_adapter *adapter; ++ struct zfcp_unit *unit = scpnt->device->hostdata; ++ struct zfcp_adapter *adapter = unit->port->adapter; + +- unit = scpnt->device->hostdata; +- adapter = unit->port->adapter; + zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); + zfcp_erp_wait(adapter); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-07-zfcp-fc-rport.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-07-zfcp-fc-rport.patch new file mode 100644 index 000000000..36b28f40a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-07-zfcp-fc-rport.patch @@ -0,0 +1,42 @@ +From: Gerald Schaefer +Subject: zfcp: Don't create multiple sysfs entries for same WWPN +References: bnc#518291,LTC#54468 + +Symptom: The FC transport class creates multiple rport entries in + sysfs for the same WWPN. +Problem: The FC transport class requires that the + fc_remote_port_add and fc_remote_delete functions are + always called in this sequence. It was possible that zfcp + called fc_remote_port_add twice leading to the problem. +Solution: Make sure to only call fc_remote_port_add once before + calling fc_remote_port_delete. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_scsi.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_scsi.c 2009-06-29 14:11:50.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_scsi.c 2009-06-29 14:27:25.000000000 +0200 +@@ -525,6 +525,9 @@ static void zfcp_scsi_rport_register(str + struct fc_rport_identifiers ids; + struct fc_rport *rport; + ++ if (port->rport) ++ return; ++ + ids.node_name = port->wwnn; + ids.port_name = port->wwpn; + ids.port_id = port->d_id; +@@ -548,8 +551,10 @@ static void zfcp_scsi_rport_block(struct + { + struct fc_rport *rport = port->rport; + +- if (rport) ++ if (rport) { + fc_remote_port_delete(rport); ++ port->rport = NULL; ++ } + } + + void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-08-zfcp-fc-wka-opening.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-08-zfcp-fc-wka-opening.patch new file mode 100644 index 000000000..f97a228c8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-08-zfcp-fc-wka-opening.patch @@ -0,0 +1,52 @@ +From: Gerald Schaefer +Subject: zfcp: fix wka port processing +References: bnc#518291,LTC#54673 + +Symptom: Remote port cannot be opened. +Problem: After an "open port" request for the WKA port did not + return within half a second, the WKA port for the + directory server remains in the state OPENING, + preventing any succeeding request to open the port. +Solution: Make sure to always update the WKA port status from the + corresponding FSF handler and do not rely on the timeout + in zfcp_wka_port_get. + +Acked-by: John Jolly +--- + + drivers/s390/scsi/zfcp_fc.c | 8 +++----- + drivers/s390/scsi/zfcp_fsf.c | 4 ++-- + 2 files changed, 5 insertions(+), 7 deletions(-) + +--- a/drivers/s390/scsi/zfcp_fc.c 2009-07-13 11:07:50.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fc.c 2009-07-13 11:18:09.000000000 +0200 +@@ -56,11 +56,9 @@ static int zfcp_wka_port_get(struct zfcp + + mutex_unlock(&wka_port->mutex); + +- wait_event_timeout( +- wka_port->completion_wq, +- wka_port->status == ZFCP_WKA_PORT_ONLINE || +- wka_port->status == ZFCP_WKA_PORT_OFFLINE, +- HZ >> 1); ++ wait_event(wka_port->completion_wq, ++ wka_port->status == ZFCP_WKA_PORT_ONLINE || ++ wka_port->status == ZFCP_WKA_PORT_OFFLINE); + + if (wka_port->status == ZFCP_WKA_PORT_ONLINE) { + atomic_inc(&wka_port->refcount); +--- a/drivers/s390/scsi/zfcp_fsf.c 2009-07-13 11:07:50.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fsf.c 2009-07-13 11:18:09.000000000 +0200 +@@ -1616,10 +1616,10 @@ static void zfcp_fsf_open_wka_port_handl + case FSF_ACCESS_DENIED: + wka_port->status = ZFCP_WKA_PORT_OFFLINE; + break; +- case FSF_PORT_ALREADY_OPEN: +- break; + case FSF_GOOD: + wka_port->handle = header->port_handle; ++ /* fall through */ ++ case FSF_PORT_ALREADY_OPEN: + wka_port->status = ZFCP_WKA_PORT_ONLINE; + } + out: diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-10-zcrypt-hrtimer-scheduling.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-10-zcrypt-hrtimer-scheduling.patch new file mode 100644 index 000000000..3bc394fbc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-10-zcrypt-hrtimer-scheduling.patch @@ -0,0 +1,34 @@ +From: Gerald Schaefer +Subject: zcrypt: fix z90crypt kernel modules causes 100% cpu usage +References: bnc#518291,LTC#54925 + +Symptom: 100% cpu usage +Problem: ap_poll_timer expires permanently and is restarts +Solution: Only restart ap_poll_timer when it expires and do it in the + future. + +Acked-by: John Jolly +--- +Index: linux-sles11/drivers/s390/crypto/ap_bus.c +=================================================================== +--- linux-sles11.orig/drivers/s390/crypto/ap_bus.c ++++ linux-sles11/drivers/s390/crypto/ap_bus.c +@@ -930,10 +930,16 @@ ap_config_timeout(unsigned long ptr) + */ + static inline void ap_schedule_poll_timer(void) + { ++ ktime_t hr_time; + if (hrtimer_is_queued(&ap_poll_timer)) + return; +- hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), +- HRTIMER_MODE_ABS); ++ ++ if (ktime_to_ns(hrtimer_get_remaining(&ap_poll_timer)) <= 0) { ++ hr_time = ktime_set(0, poll_timeout); ++ hrtimer_forward_now(&ap_poll_timer, hr_time); ++ hrtimer_restart(&ap_poll_timer); ++ } ++ return; + } + + /** diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-11-cio-vary-unregister.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-11-cio-vary-unregister.patch new file mode 100644 index 000000000..3cf07f30d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-11-cio-vary-unregister.patch @@ -0,0 +1,48 @@ +From: Gerald Schaefer +Subject: cio: ccw devices are not removed when last path is varied offline +References: bnc#518291,LTC#54951 + +Symptom: When the last CHPID to an offline CCW device is varied offline, + that device remains registered even though it is no longer + accessible. +Problem: The vary command triggers an internal path verification event + which is not handled for devices in the offline state. +Solution: Install a handler for the path verification event in offline state + which will remove the device if it is no longer accessible. + +Acked-by: John Jolly +--- + drivers/s390/cio/device_fsm.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +Index: linux-sles11/drivers/s390/cio/device_fsm.c +=================================================================== +--- linux-sles11.orig/drivers/s390/cio/device_fsm.c ++++ linux-sles11/drivers/s390/cio/device_fsm.c +@@ -739,6 +739,17 @@ static void ccw_device_generic_notoper(s + } + + /* ++ * Handle path verification event in offline state. ++ */ ++static void ccw_device_offline_verify(struct ccw_device *cdev, ++ enum dev_event dev_event) ++{ ++ struct subchannel *sch = to_subchannel(cdev->dev.parent); ++ ++ css_schedule_eval(sch->schid); ++} ++ ++/* + * Handle path verification event. + */ + static void +@@ -1155,7 +1166,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES] + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, + [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, + [DEV_EVENT_TIMEOUT] = ccw_device_nop, +- [DEV_EVENT_VERIFY] = ccw_device_nop, ++ [DEV_EVENT_VERIFY] = ccw_device_offline_verify, + }, + [DEV_STATE_VERIFY] = { + [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-15-12-zfcp-wka-work.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-15-12-zfcp-wka-work.patch new file mode 100644 index 000000000..eab969090 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-15-12-zfcp-wka-work.patch @@ -0,0 +1,26 @@ +From: Gerald Schaefer +Subject: zfcp: Cancel WKA port work on adapter dequeue +References: bnc#518291,LTC#54988 + +Symptom: Oops when enabling / disabling lots of FCP subchannels + while setting the chpid off / on. +Problem: The delayed_work for the directory server wka port is + being executed after the adapter struct has been removed. +Solution: Before removing the adapter struct make sure that the + delayed_work is not running. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_aux.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -552,6 +552,7 @@ void zfcp_adapter_dequeue(struct zfcp_ad + + cancel_work_sync(&adapter->scan_work); + cancel_work_sync(&adapter->stat_work); ++ zfcp_fc_wka_port_force_offline(&adapter->nsp); + zfcp_adapter_scsi_unregister(adapter); + sysfs_remove_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_adapter_attrs); diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-16-01-zfcp-link-test.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-16-01-zfcp-link-test.patch new file mode 100644 index 000000000..fff60457c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-16-01-zfcp-link-test.patch @@ -0,0 +1,60 @@ +From: Gerald Schaefer +Subject: zfcp: Only issue one test link command per port +References: bnc#529188,LTC#55337 + +Symptom: During error recovery, the SAN trace shows a long series + of els adisc commands being issued to the same remote port. +Problem: When the FCP channel returns a series of failed commands, + a els adisc test link command is issued for each failed + command. +Solution: Introduce a flag to ensure only one els adisc is pending + at one time. This is enough to trigger follow-on actions. + +Acked-by: John Jolly +--- + drivers/s390/scsi/zfcp_def.h | 1 + + drivers/s390/scsi/zfcp_fc.c | 9 +++++++++ + 2 files changed, 10 insertions(+) + +--- a/drivers/s390/scsi/zfcp_def.h 2009-07-16 12:20:57.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_def.h 2009-07-16 12:22:20.000000000 +0200 +@@ -260,6 +260,7 @@ struct zfcp_ls_adisc { + #define ZFCP_STATUS_PORT_PHYS_CLOSING 0x00000004 + #define ZFCP_STATUS_PORT_NO_WWPN 0x00000008 + #define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020 ++#define ZFCP_STATUS_PORT_LINK_TEST 0x00000040 + + /* well known address (WKA) port status*/ + enum zfcp_wka_status { +--- a/drivers/s390/scsi/zfcp_fc.c 2009-07-16 12:20:57.000000000 +0200 ++++ b/drivers/s390/scsi/zfcp_fc.c 2009-07-16 12:23:15.000000000 +0200 +@@ -389,6 +389,7 @@ static void zfcp_fc_adisc_handler(unsign + zfcp_scsi_schedule_rport_register(port); + + out: ++ atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + zfcp_port_put(port); + kfree(adisc); + } +@@ -435,13 +436,21 @@ void zfcp_fc_link_test_work(struct work_ + port->rport_task = RPORT_DEL; + zfcp_scsi_rport_work(&port->rport_work); + ++ /* only issue one test command at one time per port */ ++ if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST) ++ goto out; ++ ++ atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); ++ + retval = zfcp_fc_adisc(port); + if (retval == 0) + return; + + /* send of ADISC was not possible */ ++ atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + zfcp_erp_port_forced_reopen(port, 0, 65, NULL); + ++out: + zfcp_port_put(port); + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-add-FREE_PTE_NR b/src/patches/suse-2.6.27.31/patches.arch/s390-add-FREE_PTE_NR new file mode 100644 index 000000000..e9f66e2f4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-add-FREE_PTE_NR @@ -0,0 +1,43 @@ +From: Jeff Mahoney +Subject: [PATCH] s390: Define FREE_PTE_NR +Patch-mainline: Never, unless FREE_PTE_NR is used in generic code + + Commit ba8a9229ab9e80278c28ad68b15053f65b2b0a7c from + Martin Schwidefsky removed the + #include from asm-s390/tlb.h when he defined the + s390-specific TLB operations. + + FREE_PTR_NR is generally an internal-only value, but our unmap_vmas-lat + patch uses it to make smarter decisions about dumping PTEs in chunks. + + This patch restores the generic value in asm-s390/tlb.h. Since it's only + used for an optimization, this should be safe. + +Signed-off-by: Jeff Mahoney + +--- + arch/s390/include/asm/tlb.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/arch/s390/include/asm/tlb.h ++++ b/arch/s390/include/asm/tlb.h +@@ -34,6 +34,19 @@ + #define TLB_NR_PTRS 508 + #endif + ++/* Lifted from asm-generic/tlb.h; Is used by patches.suse/unmap_vmas-lat */ ++/* ++ * For UP we don't need to worry about TLB flush ++ * and page free order so much.. ++ */ ++#ifdef CONFIG_SMP ++ #define FREE_PTE_NR 506 ++ #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U) ++#else ++ #define FREE_PTE_NR 1 ++ #define tlb_fast_mode(tlb) 1 ++#endif ++ + struct mmu_gather { + struct mm_struct *mm; + unsigned int fullmm; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-disable-etr-stp b/src/patches/suse-2.6.27.31/patches.arch/s390-disable-etr-stp new file mode 100644 index 000000000..561484d87 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-disable-etr-stp @@ -0,0 +1,71 @@ +From: Hannes Reinecke +Subject: Disable ETR/STP on S/390 +References: bnc#450468 + +STP/ETR support need an update to the in-kernel workqueue support +to be avoid running into a deadlock. However, this update was not +accepted for SLES11, so we should make sure to not enable ETR/STP +support by accident. + +Signed-off-by: Hannes Reinecke + +diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c +index dbce49b..f171abf 100644 +--- a/arch/s390/kernel/time.c ++++ b/arch/s390/kernel/time.c +@@ -383,20 +383,6 @@ static int etr_port0_online; + static int etr_port1_online; + static int etr_steai_available; + +-static int __init early_parse_etr(char *p) +-{ +- if (strncmp(p, "off", 3) == 0) +- etr_port0_online = etr_port1_online = 0; +- else if (strncmp(p, "port0", 5) == 0) +- etr_port0_online = 1; +- else if (strncmp(p, "port1", 5) == 0) +- etr_port1_online = 1; +- else if (strncmp(p, "on", 2) == 0) +- etr_port0_online = etr_port1_online = 1; +- return 0; +-} +-early_param("etr", early_parse_etr); +- + enum etr_event { + ETR_EVENT_PORT0_CHANGE, + ETR_EVENT_PORT1_CHANGE, +@@ -1178,7 +1164,7 @@ static ssize_t etr_online_store(struct sys_device *dev, + return count; + } + +-static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store); ++static SYSDEV_ATTR(online, 0400, etr_online_show, etr_online_store); + + static ssize_t etr_stepping_control_show(struct sys_device *dev, + struct sysdev_attribute *attr, +@@ -1377,16 +1363,6 @@ static void stp_work_fn(struct work_struct *work); + static DEFINE_MUTEX(stp_work_mutex); + static DECLARE_WORK(stp_work, stp_work_fn); + +-static int __init early_parse_stp(char *p) +-{ +- if (strncmp(p, "off", 3) == 0) +- stp_online = 0; +- else if (strncmp(p, "on", 2) == 0) +- stp_online = 1; +- return 0; +-} +-early_param("stp", early_parse_stp); +- + /* + * Reset STP attachment. + */ +@@ -1665,7 +1641,7 @@ static ssize_t stp_online_store(struct sysdev_class *class, + * stp/online but attr_online already exists in this file .. + */ + static struct sysdev_class_attribute attr_stp_online = { +- .attr = { .name = "online", .mode = 0600 }, ++ .attr = { .name = "online", .mode = 0400 }, + .show = stp_online_show, + .store = stp_online_store, + }; diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-personality-mask.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-personality-mask.patch new file mode 100644 index 000000000..0c471933d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-personality-mask.patch @@ -0,0 +1,26 @@ +Subject: [PATCH] fix s390x_newuname + +From: Martin Schwidefsky + +The uname system call for 64 bit compares current->personality without +masking the upper 16 bits. If e.g. READ_IMPLIES_EXEC is set the result +of a uname system call will always be s390x even if the process uses +the s390 personality. + +Signed-off-by: Martin Schwidefsky +Acked-by: John Jolly +--- + arch/s390/kernel/sys_s390.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/s390/kernel/sys_s390.c ++++ b/arch/s390/kernel/sys_s390.c +@@ -199,7 +199,7 @@ SYSCALL_DEFINE1(s390_newuname, struct ne + { + int ret = sys_newuname(name); + +- if (current->personality == PER_LINUX32 && !ret) { ++ if (personality(current->personality) == PER_LINUX32 && !ret) { + ret = copy_to_user(name->machine, "s390\0\0\0\0", 8); + if (ret) ret = -EFAULT; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-symmetrix-ioctl.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-symmetrix-ioctl.patch new file mode 100644 index 000000000..29f14eb5c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-symmetrix-ioctl.patch @@ -0,0 +1,180 @@ +commit ab1d848fd6a9151b02c6cbf4bddce6e24707b094 +From: Nigel Hislop +Date: Fri Oct 10 21:33:25 2008 +0200 +Subject: Add ioctl support for EMC Symmetrix Subsystem Control I/O +References: bnc#439221 + +EMC Symmetrix Subsystem Control I/O through CKD dasd requires a +specific parameter list sent to the array via a Perform Subsystem +Function CCW. The Symmetrix response is retrieved from the array +via a Read Subsystem Data CCW. + +Signed-off-by: Nigel Hislop +Signed-off-by: Hannes Reinecke +Signed-off-by: Martin Schwidefsky + +--- + arch/s390/include/asm/dasd.h | 13 +++++ + drivers/s390/block/dasd_eckd.c | 101 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 114 insertions(+) + +--- a/arch/s390/include/asm/dasd.h ++++ b/arch/s390/include/asm/dasd.h +@@ -3,6 +3,8 @@ + * Author(s)......: Holger Smolinski + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 ++ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 ++ * Author.........: Nigel Hislop + * + * This file is the interface of the DASD device driver, which is exported to user space + * any future changes wrt the API will result in a change of the APIVERSION reported +@@ -202,6 +204,16 @@ typedef struct attrib_data_t { + #define DASD_SEQ_PRESTAGE 0x4 + #define DASD_REC_ACCESS 0x5 + ++/* ++ * Perform EMC Symmetrix I/O ++ */ ++typedef struct dasd_symmio_parms { ++ unsigned char reserved[8]; /* compat with older releases */ ++ unsigned long long psf_data; /* char * cast to u64 */ ++ unsigned long long rssd_result; /* char * cast to u64 */ ++ int psf_data_len; ++ int rssd_result_len; ++} __attribute__ ((packed)) dasd_symmio_parms_t; + + /******************************************************************************** + * SECTION: Definition of IOCTLs +@@ -247,6 +259,7 @@ typedef struct attrib_data_t { + /* Set Attributes (cache operations) */ + #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) + ++#define BIODASDSYMMIO _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t) + + #endif /* DASD_H */ + +--- a/drivers/s390/block/dasd_eckd.c ++++ b/drivers/s390/block/dasd_eckd.c +@@ -6,6 +6,8 @@ + * Martin Schwidefsky + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 ++ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 ++ * Author.........: Nigel Hislop + * + */ + +@@ -2083,6 +2085,103 @@ dasd_eckd_set_attrib(struct dasd_device + return 0; + } + ++/* ++ * Issue syscall I/O to EMC Symmetrix array. ++ * CCWs are PSF and RSSD ++ */ ++static int dasd_symm_io(struct dasd_device *device, void __user *argp) ++{ ++ struct dasd_symmio_parms usrparm; ++ char *psf_data, *rssd_result; ++ struct dasd_ccw_req *cqr; ++ struct ccw1 *ccw; ++ int rc; ++ ++ /* Copy parms from caller */ ++ rc = -EFAULT; ++ if (copy_from_user(&usrparm, argp, sizeof(usrparm))) ++ goto out; ++#ifndef CONFIG_64BIT ++ /* Make sure pointers are sane even on 31 bit. */ ++ if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) { ++ rc = -EINVAL; ++ goto out; ++ } ++#endif ++ /* alloc I/O data area */ ++ psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA); ++ rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA); ++ if (!psf_data || !rssd_result) { ++ rc = -ENOMEM; ++ goto out_free; ++ } ++ ++ /* get syscall header from user space */ ++ rc = -EFAULT; ++ if (copy_from_user(psf_data, ++ (void __user *)(unsigned long) usrparm.psf_data, ++ usrparm.psf_data_len)) ++ goto out_free; ++ ++ /* sanity check on syscall header */ ++ if (psf_data[0] != 0x17 && psf_data[1] != 0xce) { ++ rc = -EINVAL; ++ goto out_free; ++ } ++ ++ /* setup CCWs for PSF + RSSD */ ++ cqr = dasd_smalloc_request("ECKD", 2 , 0, device); ++ if (IS_ERR(cqr)) { ++ DEV_MESSAGE(KERN_WARNING, device, "%s", ++ "Could not allocate initialization request"); ++ rc = PTR_ERR(cqr); ++ goto out_free; ++ } ++ ++ cqr->startdev = device; ++ cqr->memdev = device; ++ cqr->retries = 3; ++ cqr->expires = 10 * HZ; ++ cqr->buildclk = get_clock(); ++ cqr->status = DASD_CQR_FILLED; ++ ++ /* Build the ccws */ ++ ccw = cqr->cpaddr; ++ ++ /* PSF ccw */ ++ ccw->cmd_code = DASD_ECKD_CCW_PSF; ++ ccw->count = usrparm.psf_data_len; ++ ccw->flags |= CCW_FLAG_CC; ++ ccw->cda = (__u32)(addr_t) psf_data; ++ ++ ccw++; ++ ++ /* RSSD ccw */ ++ ccw->cmd_code = DASD_ECKD_CCW_RSSD; ++ ccw->count = usrparm.rssd_result_len; ++ ccw->flags = CCW_FLAG_SLI ; ++ ccw->cda = (__u32)(addr_t) rssd_result; ++ ++ rc = dasd_sleep_on(cqr); ++ if (rc) ++ goto out_sfree; ++ ++ rc = -EFAULT; ++ if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result, ++ rssd_result, usrparm.rssd_result_len)) ++ goto out_sfree; ++ rc = 0; ++ ++out_sfree: ++ dasd_sfree_request(cqr, cqr->memdev); ++out_free: ++ kfree(rssd_result); ++ kfree(psf_data); ++out: ++ DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc); ++ return rc; ++} ++ + static int + dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) + { +@@ -2101,6 +2200,8 @@ dasd_eckd_ioctl(struct dasd_block *block + return dasd_eckd_reserve(device); + case BIODASDSLCK: + return dasd_eckd_steal_lock(device); ++ case BIODASDSYMMIO: ++ return dasd_symm_io(device, argp); + default: + return -ENOIOCTLCMD; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-zfcp-synchronize-scsi-register b/src/patches/suse-2.6.27.31/patches.arch/s390-zfcp-synchronize-scsi-register new file mode 100644 index 000000000..46338b189 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/s390-zfcp-synchronize-scsi-register @@ -0,0 +1,62 @@ +From: Swen Schillig +Subject: No udev events for zfcp online / offline +References: bnc#443667 + +The following sequence: + +echo 1 > /sys/bus/ccw/devices/0.0.fc00/online +echo 0 > /sys/bus/ccw/devices/0.0.fc00/online +echo 1 > /sys/bus/ccw/devices/0.0.fc00/online + +generates udev events only for the first 'online' request. +The following 'offline' request does not remove the zfcp +adapter from the SCSI stack (directory 'hostX' in /sys/bus/ccw/devices/0.0.fc00 +is still present), and no udev events are generated. +Consequently no udev events are being generated for the following 'online' +request. +As discussed with IBM this is actually by design; the zfcp adapter +will only be removed if a 'detach' is done. Consequently we should be +register with the SCSI stack when an 'attach' is done, not when the +ccw device is set online. + +Signed-off-by: Hannes Reinecke + +--- + drivers/s390/scsi/zfcp_aux.c | 3 ++- + drivers/s390/scsi/zfcp_ccw.c | 6 ------ + 2 files changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/s390/scsi/zfcp_aux.c ++++ b/drivers/s390/scsi/zfcp_aux.c +@@ -525,7 +525,8 @@ int zfcp_adapter_enqueue(struct ccw_devi + + zfcp_fc_nameserver_init(adapter); + +- return 0; ++ if (!zfcp_adapter_scsi_register(adapter)) ++ return 0; + + sysfs_failed: + zfcp_adapter_debug_unregister(adapter); +--- a/drivers/s390/scsi/zfcp_ccw.c ++++ b/drivers/s390/scsi/zfcp_ccw.c +@@ -105,10 +105,6 @@ static int zfcp_ccw_set_online(struct cc + if (retval) + goto out; + +- retval = zfcp_adapter_scsi_register(adapter); +- if (retval) +- goto out_scsi_register; +- + /* initialize request counter */ + BUG_ON(!zfcp_reqlist_isempty(adapter)); + adapter->req_no = 0; +@@ -122,8 +118,6 @@ static int zfcp_ccw_set_online(struct cc + flush_work(&adapter->scan_work); + return 0; + +- out_scsi_register: +- zfcp_erp_thread_kill(adapter); + out: + up(&zfcp_data.config_sema); + return retval; diff --git a/src/patches/suse-2.6.27.31/patches.arch/thinkpad_acpi-hotkey-notify-fix b/src/patches/suse-2.6.27.31/patches.arch/thinkpad_acpi-hotkey-notify-fix new file mode 100644 index 000000000..ccbcc01fc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/thinkpad_acpi-hotkey-notify-fix @@ -0,0 +1,29 @@ +From: Jeff Mahoney +Subject: [PATCH] thinkpad_acpi: Fix oops with incompatible backlight interface + + Mainline commit 2dba1b5d87e08a294da5cdfa4d32908000e9b085 (trenn's patch + thinkpad_fingers_off_backlight_igd.patch added new users of + ibm_backlight_device. + + brightness_init() returns -errno on fatal errors and 1 if the interface + is incompatible. This leaves ibm_backlight_device == NULL, which causes + an oops in hotkey_notify(). + + This patch adds a check for ibm_backlight_device. + +Signed-off-by: Jeff Mahoney +--- + drivers/misc/thinkpad_acpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -2401,7 +2401,7 @@ static void hotkey_notify(struct ibm_str + case 1: + /* 0x1000-0x1FFF: key presses */ + scancode = hkey & 0xfff; +- if (tp_features.bright_igdmode) { ++ if (tp_features.bright_igdmode && ibm_backlight_device) { + /* ToDo: + * Is there an already defined key? + */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/thinkpad_fingers_off_backlight_igd.patch b/src/patches/suse-2.6.27.31/patches.arch/thinkpad_fingers_off_backlight_igd.patch new file mode 100644 index 000000000..1e6195890 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/thinkpad_fingers_off_backlight_igd.patch @@ -0,0 +1,144 @@ +From: Thomas Renninger +Subject: Serve ThinkPad IGD devices backlight functionality through thinkpad_acpi +References: fate #302883 + +In future IDG devices will be handled by the dri subsystem. +But this code is very young and complex, better workaround this in +thinkpad_acpi driver for now. + +If in a later service pack the IGD parts get backported, this patch must +be reverted. + +Signed-off-by: Thomas Renninger +--- + drivers/acpi/video_detect.c | 15 +++++++++++++++ + drivers/misc/thinkpad_acpi.c | 40 ++++++++++++++++++++++++++++++++++++---- + include/linux/acpi.h | 2 ++ + 3 files changed, 53 insertions(+), 4 deletions(-) + +--- a/drivers/acpi/video_detect.c ++++ b/drivers/acpi/video_detect.c +@@ -99,6 +99,21 @@ long acpi_is_video_device(struct acpi_de + ACPI_UINT32_MAX, acpi_backlight_cap_match, + &video_caps, NULL); + ++ /* IGD detection is not perfect. It should use the same method as done ++ * to identify an IGD device in the dri parts or video.ko ++ */ ++ ++ /* ++ * ThinkPads do need the IGD implementation, we detect ThinkPad IGD ++ * devices here and specially workaround it in thinkpad_acpi as the ++ * IGD parts are too experimental yet ++ */ ++ if (dmi_name_in_vendors("LENOVO") && ++ ACPI_SUCCESS(acpi_get_handle(device->handle, "DRDY", &h_dummy))) { ++ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IGD device\n")); ++ video_caps |= ACPI_VIDEO_IGD; ++ } ++ + return video_caps; + } + EXPORT_SYMBOL(acpi_is_video_device); +--- a/drivers/misc/thinkpad_acpi.c ++++ b/drivers/misc/thinkpad_acpi.c +@@ -240,6 +240,7 @@ static struct { + u32 light_status:1; + u32 bright_16levels:1; + u32 bright_acpimode:1; ++ u32 bright_igdmode:1; + u32 wan:1; + u32 fan_ctrl_status_undef:1; + u32 input_device_registered:1; +@@ -2359,6 +2360,9 @@ err_exit: + return (res < 0)? res : 1; + } + ++static struct backlight_device *ibm_backlight_device; ++static int brightness_update_status(struct backlight_device *bd); ++ + static void hotkey_notify(struct ibm_struct *ibm, u32 event) + { + u32 hkey; +@@ -2397,6 +2401,28 @@ static void hotkey_notify(struct ibm_str + case 1: + /* 0x1000-0x1FFF: key presses */ + scancode = hkey & 0xfff; ++ if (tp_features.bright_igdmode) { ++ /* ToDo: ++ * Is there an already defined key? ++ */ ++ if (hkey == 0x1011) { ++ if (ibm_backlight_device-> ++ props.brightness > 0) { ++ ibm_backlight_device-> ++ props.brightness--; ++ } ++ } else if (hkey == 0x1010) { ++ if (ibm_backlight_device-> ++ props.brightness < ++ ibm_backlight_device-> ++ props.max_brightness) { ++ ibm_backlight_device-> ++ props.brightness++; ++ } ++ } ++ brightness_update_status(ibm_backlight_device); ++ } ++ + if (scancode > 0 && scancode < 0x21) { + scancode--; + if (!(hotkey_source_mask & (1 << scancode))) { +@@ -4767,7 +4793,6 @@ enum { + TP_EC_BACKLIGHT_MAPSW = 0x20, + }; + +-static struct backlight_device *ibm_backlight_device; + static int brightness_mode; + static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ + +@@ -4906,7 +4931,7 @@ static struct backlight_ops ibm_backligh + static int __init brightness_init(struct ibm_init_struct *iibm) + { + int b; +- ++ long acpi_video_support; + vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); + + mutex_init(&brightness_mutex); +@@ -4918,8 +4943,9 @@ static int __init brightness_init(struct + */ + b = tpacpi_check_std_acpi_brightness_support(); + if (b > 0) { +- +- if (acpi_video_backlight_support()) { ++ acpi_video_support = acpi_video_backlight_support(); ++ if (acpi_video_support && ++ !(acpi_video_support & ACPI_VIDEO_IGD)) { + if (brightness_enable > 1) { + printk(TPACPI_NOTICE + "Standard ACPI backlight interface " +@@ -4937,6 +4963,12 @@ static int __init brightness_init(struct + "available, thinkpad_acpi driver " + "will take over control\n"); + } ++ if (acpi_video_support & ACPI_VIDEO_IGD) { ++ printk(TPACPI_NOTICE, "IGD device" ++ " detected - take over backlight" ++ " switching\n"); ++ tp_features.bright_igdmode = 1; ++ } + } + } + +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -214,6 +214,8 @@ extern bool wmi_has_guid(const char *gui + #define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 + #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 + #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 ++/* Do not use the IGD define, this is a SUSE only ThinkPad workaround hack! */ ++#define ACPI_VIDEO_IGD 0x1000 + + #if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_01_0f4896665a02b465ddca59a560983b24ec28c64b b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_01_0f4896665a02b465ddca59a560983b24ec28c64b new file mode 100644 index 000000000..31b6a2a2d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_01_0f4896665a02b465ddca59a560983b24ec28c64b @@ -0,0 +1,36 @@ +From: Suresh Siddha +Subject: dmar: fix dmar_parse_dev() devices_cnt error condition check +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 0f4896665a02b465ddca59a560983b24ec28c64b + +Signed-off-by: Thomas Renninger + +It is possible that, +instead of PCI endpoint/sub-hierarchy structures, only IO-APIC/HPET +devices may be reported under device scope structures. Fix the devices_cnt +error check, which cares about only PCI structures and removes the +dma-remapping unit structure (dmaru) when the devices_cnt is zero +and include_all flag is not set. + +Signed-off-by: Suresh Siddha +Acked-by: Yinghai Lu +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -212,7 +212,7 @@ dmar_parse_dev(struct dmar_drhd_unit *dm + include_all = 1; + } + +- if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) { ++ if (ret) { + list_del(&dmaru->list); + kfree(dmaru); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_01_of_41_e61d98d8dad0048619bb138b0ff996422ffae53b b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_01_of_41_e61d98d8dad0048619bb138b0ff996422ffae53b new file mode 100644 index 000000000..524abdd4a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_01_of_41_e61d98d8dad0048619bb138b0ff996422ffae53b @@ -0,0 +1,629 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: Intel vt-d, IOMMU code reorganization +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: e61d98d8dad0048619bb138b0ff996422ffae53b + +Signed-off-by: Thomas Renninger + +code reorganization of the generic Intel vt-d parsing related routines and linux +iommu routines specific to Intel vt-d. + +drivers/pci/dmar.c now contains the generic vt-d parsing related routines +drivers/pci/intel_iommu.c contains the iommu routines specific to vt-d + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dma_remapping.h | 155 +++++++++++++++++++++++++++++++++++++++++ + drivers/pci/dmar.c | 90 ++++++++++++++++++++++++ + drivers/pci/intel-iommu.c | 92 ++---------------------- + drivers/pci/intel-iommu.h | 163 +++----------------------------------------- + 4 files changed, 264 insertions(+), 236 deletions(-) + +--- a/drivers/pci/dmar.c ++++ b/drivers/pci/dmar.c +@@ -19,9 +19,11 @@ + * Author: Shaohua Li + * Author: Anil S Keshavamurthy + * +- * This file implements early detection/parsing of DMA Remapping Devices ++ * This file implements early detection/parsing of Remapping Devices + * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI + * tables. ++ * ++ * These routines are used by both DMA-remapping and Interrupt-remapping + */ + + #include +@@ -300,6 +302,37 @@ parse_dmar_table(void) + return ret; + } + ++int dmar_pci_device_match(struct pci_dev *devices[], int cnt, ++ struct pci_dev *dev) ++{ ++ int index; ++ ++ while (dev) { ++ for (index = 0; index < cnt; index++) ++ if (dev == devices[index]) ++ return 1; ++ ++ /* Check our parent */ ++ dev = dev->bus->self; ++ } ++ ++ return 0; ++} ++ ++struct dmar_drhd_unit * ++dmar_find_matched_drhd_unit(struct pci_dev *dev) ++{ ++ struct dmar_drhd_unit *drhd = NULL; ++ ++ list_for_each_entry(drhd, &dmar_drhd_units, list) { ++ if (drhd->include_all || dmar_pci_device_match(drhd->devices, ++ drhd->devices_cnt, dev)) ++ return drhd; ++ } ++ ++ return NULL; ++} ++ + + int __init dmar_table_init(void) + { +@@ -341,3 +374,58 @@ int __init early_dmar_detect(void) + + return (ACPI_SUCCESS(status) ? 1 : 0); + } ++ ++struct intel_iommu *alloc_iommu(struct intel_iommu *iommu, ++ struct dmar_drhd_unit *drhd) ++{ ++ int map_size; ++ u32 ver; ++ ++ iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K); ++ if (!iommu->reg) { ++ printk(KERN_ERR "IOMMU: can't map the region\n"); ++ goto error; ++ } ++ iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); ++ iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); ++ ++ /* the registers might be more than one page */ ++ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), ++ cap_max_fault_reg_offset(iommu->cap)); ++ map_size = PAGE_ALIGN_4K(map_size); ++ if (map_size > PAGE_SIZE_4K) { ++ iounmap(iommu->reg); ++ iommu->reg = ioremap(drhd->reg_base_addr, map_size); ++ if (!iommu->reg) { ++ printk(KERN_ERR "IOMMU: can't map the region\n"); ++ goto error; ++ } ++ } ++ ++ ver = readl(iommu->reg + DMAR_VER_REG); ++ pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", ++ drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), ++ iommu->cap, iommu->ecap); ++ ++ spin_lock_init(&iommu->register_lock); ++ ++ drhd->iommu = iommu; ++ return iommu; ++error: ++ kfree(iommu); ++ return NULL; ++} ++ ++void free_iommu(struct intel_iommu *iommu) ++{ ++ if (!iommu) ++ return; ++ ++#ifdef CONFIG_DMAR ++ free_dmar_iommu(iommu); ++#endif ++ ++ if (iommu->reg) ++ iounmap(iommu->reg); ++ kfree(iommu); ++} +--- /dev/null ++++ b/drivers/pci/dma_remapping.h +@@ -0,0 +1,155 @@ ++#ifndef _DMA_REMAPPING_H ++#define _DMA_REMAPPING_H ++ ++/* ++ * We need a fixed PAGE_SIZE of 4K irrespective of ++ * arch PAGE_SIZE for IOMMU page tables. ++ */ ++#define PAGE_SHIFT_4K (12) ++#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K) ++#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K) ++#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K) ++ ++#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K) ++#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK) ++#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK) ++ ++ ++/* ++ * 0: Present ++ * 1-11: Reserved ++ * 12-63: Context Ptr (12 - (haw-1)) ++ * 64-127: Reserved ++ */ ++struct root_entry { ++ u64 val; ++ u64 rsvd1; ++}; ++#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry)) ++static inline bool root_present(struct root_entry *root) ++{ ++ return (root->val & 1); ++} ++static inline void set_root_present(struct root_entry *root) ++{ ++ root->val |= 1; ++} ++static inline void set_root_value(struct root_entry *root, unsigned long value) ++{ ++ root->val |= value & PAGE_MASK_4K; ++} ++ ++struct context_entry; ++static inline struct context_entry * ++get_context_addr_from_root(struct root_entry *root) ++{ ++ return (struct context_entry *) ++ (root_present(root)?phys_to_virt( ++ root->val & PAGE_MASK_4K): ++ NULL); ++} ++ ++/* ++ * low 64 bits: ++ * 0: present ++ * 1: fault processing disable ++ * 2-3: translation type ++ * 12-63: address space root ++ * high 64 bits: ++ * 0-2: address width ++ * 3-6: aval ++ * 8-23: domain id ++ */ ++struct context_entry { ++ u64 lo; ++ u64 hi; ++}; ++#define context_present(c) ((c).lo & 1) ++#define context_fault_disable(c) (((c).lo >> 1) & 1) ++#define context_translation_type(c) (((c).lo >> 2) & 3) ++#define context_address_root(c) ((c).lo & PAGE_MASK_4K) ++#define context_address_width(c) ((c).hi & 7) ++#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1)) ++ ++#define context_set_present(c) do {(c).lo |= 1;} while (0) ++#define context_set_fault_enable(c) \ ++ do {(c).lo &= (((u64)-1) << 2) | 1;} while (0) ++#define context_set_translation_type(c, val) \ ++ do { \ ++ (c).lo &= (((u64)-1) << 4) | 3; \ ++ (c).lo |= ((val) & 3) << 2; \ ++ } while (0) ++#define CONTEXT_TT_MULTI_LEVEL 0 ++#define context_set_address_root(c, val) \ ++ do {(c).lo |= (val) & PAGE_MASK_4K;} while (0) ++#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0) ++#define context_set_domain_id(c, val) \ ++ do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0) ++#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0) ++ ++/* ++ * 0: readable ++ * 1: writable ++ * 2-6: reserved ++ * 7: super page ++ * 8-11: available ++ * 12-63: Host physcial address ++ */ ++struct dma_pte { ++ u64 val; ++}; ++#define dma_clear_pte(p) do {(p).val = 0;} while (0) ++ ++#define DMA_PTE_READ (1) ++#define DMA_PTE_WRITE (2) ++ ++#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0) ++#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0) ++#define dma_set_pte_prot(p, prot) \ ++ do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0) ++#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K) ++#define dma_set_pte_addr(p, addr) do {\ ++ (p).val |= ((addr) & PAGE_MASK_4K); } while (0) ++#define dma_pte_present(p) (((p).val & 3) != 0) ++ ++struct intel_iommu; ++ ++struct dmar_domain { ++ int id; /* domain id */ ++ struct intel_iommu *iommu; /* back pointer to owning iommu */ ++ ++ struct list_head devices; /* all devices' list */ ++ struct iova_domain iovad; /* iova's that belong to this domain */ ++ ++ struct dma_pte *pgd; /* virtual address */ ++ spinlock_t mapping_lock; /* page table lock */ ++ int gaw; /* max guest address width */ ++ ++ /* adjusted guest address width, 0 is level 2 30-bit */ ++ int agaw; ++ ++#define DOMAIN_FLAG_MULTIPLE_DEVICES 1 ++ int flags; ++}; ++ ++/* PCI domain-device relationship */ ++struct device_domain_info { ++ struct list_head link; /* link to domain siblings */ ++ struct list_head global; /* link to global list */ ++ u8 bus; /* PCI bus numer */ ++ u8 devfn; /* PCI devfn number */ ++ struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */ ++ struct dmar_domain *domain; /* pointer to domain */ ++}; ++ ++extern int init_dmars(void); ++extern void free_dmar_iommu(struct intel_iommu *iommu); ++ ++#ifndef CONFIG_DMAR_GFX_WA ++static inline void iommu_prepare_gfx_mapping(void) ++{ ++ return; ++} ++#endif /* !CONFIG_DMAR_GFX_WA */ ++ ++#endif +--- a/drivers/pci/intel-iommu.c ++++ b/drivers/pci/intel-iommu.c +@@ -992,6 +992,8 @@ static int iommu_init_domains(struct int + return -ENOMEM; + } + ++ spin_lock_init(&iommu->lock); ++ + /* + * if Caching mode is set, then invalid translations are tagged + * with domainid 0. Hence we need to pre-allocate it. +@@ -1000,62 +1002,15 @@ static int iommu_init_domains(struct int + set_bit(0, iommu->domain_ids); + return 0; + } +-static struct intel_iommu *alloc_iommu(struct intel_iommu *iommu, +- struct dmar_drhd_unit *drhd) +-{ +- int ret; +- int map_size; +- u32 ver; +- +- iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K); +- if (!iommu->reg) { +- printk(KERN_ERR "IOMMU: can't map the region\n"); +- goto error; +- } +- iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); +- iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); +- +- /* the registers might be more than one page */ +- map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), +- cap_max_fault_reg_offset(iommu->cap)); +- map_size = PAGE_ALIGN_4K(map_size); +- if (map_size > PAGE_SIZE_4K) { +- iounmap(iommu->reg); +- iommu->reg = ioremap(drhd->reg_base_addr, map_size); +- if (!iommu->reg) { +- printk(KERN_ERR "IOMMU: can't map the region\n"); +- goto error; +- } +- } + +- ver = readl(iommu->reg + DMAR_VER_REG); +- pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", +- drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), +- iommu->cap, iommu->ecap); +- ret = iommu_init_domains(iommu); +- if (ret) +- goto error_unmap; +- spin_lock_init(&iommu->lock); +- spin_lock_init(&iommu->register_lock); +- +- drhd->iommu = iommu; +- return iommu; +-error_unmap: +- iounmap(iommu->reg); +-error: +- kfree(iommu); +- return NULL; +-} + + static void domain_exit(struct dmar_domain *domain); +-static void free_iommu(struct intel_iommu *iommu) ++ ++void free_dmar_iommu(struct intel_iommu *iommu) + { + struct dmar_domain *domain; + int i; + +- if (!iommu) +- return; +- + i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap)); + for (; i < cap_ndoms(iommu->cap); ) { + domain = iommu->domains[i]; +@@ -1080,10 +1035,6 @@ static void free_iommu(struct intel_iomm + + /* free context mapping */ + free_context_table(iommu); +- +- if (iommu->reg) +- iounmap(iommu->reg); +- kfree(iommu); + } + + static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu) +@@ -1428,37 +1379,6 @@ find_domain(struct pci_dev *pdev) + return NULL; + } + +-static int dmar_pci_device_match(struct pci_dev *devices[], int cnt, +- struct pci_dev *dev) +-{ +- int index; +- +- while (dev) { +- for (index = 0; index < cnt; index++) +- if (dev == devices[index]) +- return 1; +- +- /* Check our parent */ +- dev = dev->bus->self; +- } +- +- return 0; +-} +- +-static struct dmar_drhd_unit * +-dmar_find_matched_drhd_unit(struct pci_dev *dev) +-{ +- struct dmar_drhd_unit *drhd = NULL; +- +- list_for_each_entry(drhd, &dmar_drhd_units, list) { +- if (drhd->include_all || dmar_pci_device_match(drhd->devices, +- drhd->devices_cnt, dev)) +- return drhd; +- } +- +- return NULL; +-} +- + /* domain is initialized */ + static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) + { +@@ -1765,6 +1685,10 @@ int __init init_dmars(void) + goto error; + } + ++ ret = iommu_init_domains(iommu); ++ if (ret) ++ goto error; ++ + /* + * TBD: + * we could share the same root & context tables +--- a/drivers/pci/intel-iommu.h ++++ b/drivers/pci/intel-iommu.h +@@ -27,19 +27,7 @@ + #include + #include "iova.h" + #include +- +-/* +- * We need a fixed PAGE_SIZE of 4K irrespective of +- * arch PAGE_SIZE for IOMMU page tables. +- */ +-#define PAGE_SHIFT_4K (12) +-#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K) +-#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K) +-#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K) +- +-#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K) +-#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK) +-#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK) ++#include "dma_remapping.h" + + /* + * Intel IOMMU register specification per version 1.0 public spec. +@@ -187,158 +175,31 @@ static inline void dmar_writeq(void __io + #define dma_frcd_source_id(c) (c & 0xffff) + #define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */ + +-/* +- * 0: Present +- * 1-11: Reserved +- * 12-63: Context Ptr (12 - (haw-1)) +- * 64-127: Reserved +- */ +-struct root_entry { +- u64 val; +- u64 rsvd1; +-}; +-#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry)) +-static inline bool root_present(struct root_entry *root) +-{ +- return (root->val & 1); +-} +-static inline void set_root_present(struct root_entry *root) +-{ +- root->val |= 1; +-} +-static inline void set_root_value(struct root_entry *root, unsigned long value) +-{ +- root->val |= value & PAGE_MASK_4K; +-} +- +-struct context_entry; +-static inline struct context_entry * +-get_context_addr_from_root(struct root_entry *root) +-{ +- return (struct context_entry *) +- (root_present(root)?phys_to_virt( +- root->val & PAGE_MASK_4K): +- NULL); +-} +- +-/* +- * low 64 bits: +- * 0: present +- * 1: fault processing disable +- * 2-3: translation type +- * 12-63: address space root +- * high 64 bits: +- * 0-2: address width +- * 3-6: aval +- * 8-23: domain id +- */ +-struct context_entry { +- u64 lo; +- u64 hi; +-}; +-#define context_present(c) ((c).lo & 1) +-#define context_fault_disable(c) (((c).lo >> 1) & 1) +-#define context_translation_type(c) (((c).lo >> 2) & 3) +-#define context_address_root(c) ((c).lo & PAGE_MASK_4K) +-#define context_address_width(c) ((c).hi & 7) +-#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1)) +- +-#define context_set_present(c) do {(c).lo |= 1;} while (0) +-#define context_set_fault_enable(c) \ +- do {(c).lo &= (((u64)-1) << 2) | 1;} while (0) +-#define context_set_translation_type(c, val) \ +- do { \ +- (c).lo &= (((u64)-1) << 4) | 3; \ +- (c).lo |= ((val) & 3) << 2; \ +- } while (0) +-#define CONTEXT_TT_MULTI_LEVEL 0 +-#define context_set_address_root(c, val) \ +- do {(c).lo |= (val) & PAGE_MASK_4K;} while (0) +-#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0) +-#define context_set_domain_id(c, val) \ +- do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0) +-#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0) +- +-/* +- * 0: readable +- * 1: writable +- * 2-6: reserved +- * 7: super page +- * 8-11: available +- * 12-63: Host physcial address +- */ +-struct dma_pte { +- u64 val; +-}; +-#define dma_clear_pte(p) do {(p).val = 0;} while (0) +- +-#define DMA_PTE_READ (1) +-#define DMA_PTE_WRITE (2) +- +-#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0) +-#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0) +-#define dma_set_pte_prot(p, prot) \ +- do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0) +-#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K) +-#define dma_set_pte_addr(p, addr) do {\ +- (p).val |= ((addr) & PAGE_MASK_4K); } while (0) +-#define dma_pte_present(p) (((p).val & 3) != 0) +- +-struct intel_iommu; +- +-struct dmar_domain { +- int id; /* domain id */ +- struct intel_iommu *iommu; /* back pointer to owning iommu */ +- +- struct list_head devices; /* all devices' list */ +- struct iova_domain iovad; /* iova's that belong to this domain */ +- +- struct dma_pte *pgd; /* virtual address */ +- spinlock_t mapping_lock; /* page table lock */ +- int gaw; /* max guest address width */ +- +- /* adjusted guest address width, 0 is level 2 30-bit */ +- int agaw; +- +-#define DOMAIN_FLAG_MULTIPLE_DEVICES 1 +- int flags; +-}; +- +-/* PCI domain-device relationship */ +-struct device_domain_info { +- struct list_head link; /* link to domain siblings */ +- struct list_head global; /* link to global list */ +- u8 bus; /* PCI bus numer */ +- u8 devfn; /* PCI devfn number */ +- struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */ +- struct dmar_domain *domain; /* pointer to domain */ +-}; +- +-extern int init_dmars(void); +- + struct intel_iommu { + void __iomem *reg; /* Pointer to hardware regs, virtual addr */ + u64 cap; + u64 ecap; +- unsigned long *domain_ids; /* bitmap of domains */ +- struct dmar_domain **domains; /* ptr to domains */ + int seg; + u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */ +- spinlock_t lock; /* protect context, domain ids */ + spinlock_t register_lock; /* protect register handling */ ++ ++#ifdef CONFIG_DMAR ++ unsigned long *domain_ids; /* bitmap of domains */ ++ struct dmar_domain **domains; /* ptr to domains */ ++ spinlock_t lock; /* protect context, domain ids */ + struct root_entry *root_entry; /* virtual address */ + + unsigned int irq; + unsigned char name[7]; /* Device Name */ + struct msi_msg saved_msg; + struct sys_device sysdev; ++#endif + }; + +-#ifndef CONFIG_DMAR_GFX_WA +-static inline void iommu_prepare_gfx_mapping(void) +-{ +- return; +-} +-#endif /* !CONFIG_DMAR_GFX_WA */ ++extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); ++ ++extern struct intel_iommu *alloc_iommu(struct intel_iommu *iommu, ++ struct dmar_drhd_unit *drhd); ++extern void free_iommu(struct intel_iommu *iommu); + + #endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_02_228324076234ca6a8cd34be89be78022773459f1 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_02_228324076234ca6a8cd34be89be78022773459f1 new file mode 100644 index 000000000..c6401cbf5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_02_228324076234ca6a8cd34be89be78022773459f1 @@ -0,0 +1,49 @@ +From: Suresh Siddha +Subject: dmar: use list_for_each_entry_safe() in dmar_dev_scope_init() +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 228324076234ca6a8cd34be89be78022773459f1 + +Signed-off-by: Thomas Renninger + +In dmar_dev_scope_init(), functions called under for_each_drhd_unit()/ +for_each_rmrr_units() can delete the list entry under some error conditions. + +So we should use list_for_each_entry_safe() for safe traversal. + +Signed-off-by: Suresh Siddha +Acked-by: Yinghai Lu +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -373,10 +373,10 @@ dmar_find_matched_drhd_unit(struct pci_d + + int __init dmar_dev_scope_init(void) + { +- struct dmar_drhd_unit *drhd; ++ struct dmar_drhd_unit *drhd, *drhd_n; + int ret = -ENODEV; + +- for_each_drhd_unit(drhd) { ++ list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) { + ret = dmar_parse_dev(drhd); + if (ret) + return ret; +@@ -384,8 +384,8 @@ int __init dmar_dev_scope_init(void) + + #ifdef CONFIG_DMAR + { +- struct dmar_rmrr_unit *rmrr; +- for_each_rmrr_units(rmrr) { ++ struct dmar_rmrr_unit *rmrr, *rmrr_n; ++ list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { + ret = rmrr_parse_dev(rmrr); + if (ret) + return ret; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_02_of_41_c42d9f32443397aed2d37d37df161392e6a5862f b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_02_of_41_c42d9f32443397aed2d37d37df161392e6a5862f new file mode 100644 index 000000000..1657a94cc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_02_of_41_c42d9f32443397aed2d37d37df161392e6a5862f @@ -0,0 +1,150 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: fix the need for sequential array allocation of iommus +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: c42d9f32443397aed2d37d37df161392e6a5862f + +Signed-off-by: Thomas Renninger + +Clean up the intel-iommu code related to deferred iommu flush logic. There is +no need to allocate all the iommu's as a sequential array. + +This will be used later in the interrupt-remapping patch series to +allocate iommu much early and individually for each device remapping +hardware unit. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 11 +++++++++-- + drivers/pci/intel-iommu.c | 23 +++++++---------------- + drivers/pci/intel-iommu.h | 4 ++-- + 3 files changed, 18 insertions(+), 20 deletions(-) + +--- a/drivers/pci/dmar.c ++++ b/drivers/pci/dmar.c +@@ -375,11 +375,18 @@ int __init early_dmar_detect(void) + return (ACPI_SUCCESS(status) ? 1 : 0); + } + +-struct intel_iommu *alloc_iommu(struct intel_iommu *iommu, +- struct dmar_drhd_unit *drhd) ++struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd) + { ++ struct intel_iommu *iommu; + int map_size; + u32 ver; ++ static int iommu_allocated = 0; ++ ++ iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); ++ if (!iommu) ++ return NULL; ++ ++ iommu->seq_id = iommu_allocated++; + + iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K); + if (!iommu->reg) { +--- a/drivers/pci/intel-iommu.c ++++ b/drivers/pci/intel-iommu.c +@@ -58,8 +58,6 @@ static void flush_unmaps_timeout(unsigne + + DEFINE_TIMER(unmap_timer, flush_unmaps_timeout, 0, 0); + +-static struct intel_iommu *g_iommus; +- + #define HIGH_WATER_MARK 250 + struct deferred_flush_tables { + int next; +@@ -1651,8 +1649,6 @@ int __init init_dmars(void) + * endfor + */ + for_each_drhd_unit(drhd) { +- if (drhd->ignored) +- continue; + g_num_of_iommus++; + /* + * lock not needed as this is only incremented in the single +@@ -1661,12 +1657,6 @@ int __init init_dmars(void) + */ + } + +- g_iommus = kzalloc(g_num_of_iommus * sizeof(*iommu), GFP_KERNEL); +- if (!g_iommus) { +- ret = -ENOMEM; +- goto error; +- } +- + deferred_flush = kzalloc(g_num_of_iommus * + sizeof(struct deferred_flush_tables), GFP_KERNEL); + if (!deferred_flush) { +@@ -1674,12 +1664,10 @@ int __init init_dmars(void) + goto error; + } + +- i = 0; + for_each_drhd_unit(drhd) { + if (drhd->ignored) + continue; +- iommu = alloc_iommu(&g_iommus[i], drhd); +- i++; ++ iommu = alloc_iommu(drhd); + if (!iommu) { + ret = -ENOMEM; + goto error; +@@ -1771,7 +1759,6 @@ error: + iommu = drhd->iommu; + free_iommu(iommu); + } +- kfree(g_iommus); + return ret; + } + +@@ -1928,7 +1915,10 @@ static void flush_unmaps(void) + /* just flush them all */ + for (i = 0; i < g_num_of_iommus; i++) { + if (deferred_flush[i].next) { +- iommu_flush_iotlb_global(&g_iommus[i], 0); ++ struct intel_iommu *iommu = ++ deferred_flush[i].domain[0]->iommu; ++ ++ iommu_flush_iotlb_global(iommu, 0); + for (j = 0; j < deferred_flush[i].next; j++) { + __free_iova(&deferred_flush[i].domain[j]->iovad, + deferred_flush[i].iova[j]); +@@ -1958,7 +1948,8 @@ static void add_unmap(struct dmar_domain + if (list_size == HIGH_WATER_MARK) + flush_unmaps(); + +- iommu_id = dom->iommu - g_iommus; ++ iommu_id = dom->iommu->seq_id; ++ + next = deferred_flush[iommu_id].next; + deferred_flush[iommu_id].domain[next] = dom; + deferred_flush[iommu_id].iova[next] = iova; +--- a/drivers/pci/intel-iommu.h ++++ b/drivers/pci/intel-iommu.h +@@ -182,6 +182,7 @@ struct intel_iommu { + int seg; + u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */ + spinlock_t register_lock; /* protect register handling */ ++ int seq_id; /* sequence id of the iommu */ + + #ifdef CONFIG_DMAR + unsigned long *domain_ids; /* bitmap of domains */ +@@ -198,8 +199,7 @@ struct intel_iommu { + + extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); + +-extern struct intel_iommu *alloc_iommu(struct intel_iommu *iommu, +- struct dmar_drhd_unit *drhd); ++extern struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd); + extern void free_iommu(struct intel_iommu *iommu); + + #endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_03_3f1fdb3673bb5638fa94186dc391cbc4879590bc b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_03_3f1fdb3673bb5638fa94186dc391cbc4879590bc new file mode 100644 index 000000000..8b2f9ae0f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_03_3f1fdb3673bb5638fa94186dc391cbc4879590bc @@ -0,0 +1,31 @@ +From: Yinghai Lu +Subject: dmar: initialize the return value in dmar_parse_dev() +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 3f1fdb3673bb5638fa94186dc391cbc4879590bc + +Signed-off-by: Thomas Renninger + +initialize the return value in dmar_parse_dev() + +Signed-off-by: Yinghai Lu +Signed-off-by: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -193,7 +193,7 @@ dmar_parse_dev(struct dmar_drhd_unit *dm + { + struct acpi_dmar_hardware_unit *drhd; + static int include_all; +- int ret; ++ int ret = 0; + + drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_03_of_41_1886e8a90a580f3ad343f2065c84c1b9e1dac9ef b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_03_of_41_1886e8a90a580f3ad343f2065c84c1b9e1dac9ef new file mode 100644 index 000000000..defe4fa13 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_03_of_41_1886e8a90a580f3ad343f2065c84c1b9e1dac9ef @@ -0,0 +1,287 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: code re-structuring, to be used by both DMA and Interrupt remapping +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 1886e8a90a580f3ad343f2065c84c1b9e1dac9ef + +Signed-off-by: Thomas Renninger + +Allocate the iommu during the parse of DMA remapping hardware +definition structures. And also, introduce routines for device +scope initialization which will be explicitly called during +dma-remapping initialization. + +These will be used for enabling interrupt remapping separately from the +existing DMA-remapping enabling sequence. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 89 +++++++++++++++++++++++++++++++++++++--------- + drivers/pci/intel-iommu.c | 10 ++--- + drivers/pci/intel-iommu.h | 2 - + include/linux/dmar.h | 10 ++++- + 4 files changed, 88 insertions(+), 23 deletions(-) + +--- a/drivers/pci/dmar.c ++++ b/drivers/pci/dmar.c +@@ -174,19 +174,37 @@ dmar_parse_one_drhd(struct acpi_dmar_hea + struct acpi_dmar_hardware_unit *drhd; + struct dmar_drhd_unit *dmaru; + int ret = 0; +- static int include_all; + + dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); + if (!dmaru) + return -ENOMEM; + ++ dmaru->hdr = header; + drhd = (struct acpi_dmar_hardware_unit *)header; + dmaru->reg_base_addr = drhd->address; + dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ + ++ ret = alloc_iommu(dmaru); ++ if (ret) { ++ kfree(dmaru); ++ return ret; ++ } ++ dmar_register_drhd_unit(dmaru); ++ return 0; ++} ++ ++static int __init ++dmar_parse_dev(struct dmar_drhd_unit *dmaru) ++{ ++ struct acpi_dmar_hardware_unit *drhd; ++ static int include_all; ++ int ret; ++ ++ drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; ++ + if (!dmaru->include_all) + ret = dmar_parse_dev_scope((void *)(drhd + 1), +- ((void *)drhd) + header->length, ++ ((void *)drhd) + drhd->header.length, + &dmaru->devices_cnt, &dmaru->devices, + drhd->segment); + else { +@@ -199,10 +217,10 @@ dmar_parse_one_drhd(struct acpi_dmar_hea + include_all = 1; + } + +- if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) ++ if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) { ++ list_del(&dmaru->list); + kfree(dmaru); +- else +- dmar_register_drhd_unit(dmaru); ++ } + return ret; + } + +@@ -211,23 +229,35 @@ dmar_parse_one_rmrr(struct acpi_dmar_hea + { + struct acpi_dmar_reserved_memory *rmrr; + struct dmar_rmrr_unit *rmrru; +- int ret = 0; + + rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); + if (!rmrru) + return -ENOMEM; + ++ rmrru->hdr = header; + rmrr = (struct acpi_dmar_reserved_memory *)header; + rmrru->base_address = rmrr->base_address; + rmrru->end_address = rmrr->end_address; ++ ++ dmar_register_rmrr_unit(rmrru); ++ return 0; ++} ++ ++static int __init ++rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) ++{ ++ struct acpi_dmar_reserved_memory *rmrr; ++ int ret; ++ ++ rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; + ret = dmar_parse_dev_scope((void *)(rmrr + 1), +- ((void *)rmrr) + header->length, ++ ((void *)rmrr) + rmrr->header.length, + &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); + +- if (ret || (rmrru->devices_cnt == 0)) ++ if (ret || (rmrru->devices_cnt == 0)) { ++ list_del(&rmrru->list); + kfree(rmrru); +- else +- dmar_register_rmrr_unit(rmrru); ++ } + return ret; + } + +@@ -333,15 +363,42 @@ dmar_find_matched_drhd_unit(struct pci_d + return NULL; + } + ++int __init dmar_dev_scope_init(void) ++{ ++ struct dmar_drhd_unit *drhd; ++ struct dmar_rmrr_unit *rmrr; ++ int ret = -ENODEV; ++ ++ for_each_drhd_unit(drhd) { ++ ret = dmar_parse_dev(drhd); ++ if (ret) ++ return ret; ++ } ++ ++ for_each_rmrr_units(rmrr) { ++ ret = rmrr_parse_dev(rmrr); ++ if (ret) ++ return ret; ++ } ++ ++ return ret; ++} ++ + + int __init dmar_table_init(void) + { +- ++ static int dmar_table_initialized; + int ret; + ++ if (dmar_table_initialized) ++ return 0; ++ ++ dmar_table_initialized = 1; ++ + ret = parse_dmar_table(); + if (ret) { +- printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); ++ if (ret != -ENODEV) ++ printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); + return ret; + } + +@@ -375,7 +432,7 @@ int __init early_dmar_detect(void) + return (ACPI_SUCCESS(status) ? 1 : 0); + } + +-struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd) ++int alloc_iommu(struct dmar_drhd_unit *drhd) + { + struct intel_iommu *iommu; + int map_size; +@@ -384,7 +441,7 @@ struct intel_iommu *alloc_iommu(struct d + + iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); + if (!iommu) +- return NULL; ++ return -ENOMEM; + + iommu->seq_id = iommu_allocated++; + +@@ -417,10 +474,10 @@ struct intel_iommu *alloc_iommu(struct d + spin_lock_init(&iommu->register_lock); + + drhd->iommu = iommu; +- return iommu; ++ return 0; + error: + kfree(iommu); +- return NULL; ++ return -1; + } + + void free_iommu(struct intel_iommu *iommu) +--- a/drivers/pci/intel-iommu.c ++++ b/drivers/pci/intel-iommu.c +@@ -1667,11 +1667,8 @@ int __init init_dmars(void) + for_each_drhd_unit(drhd) { + if (drhd->ignored) + continue; +- iommu = alloc_iommu(drhd); +- if (!iommu) { +- ret = -ENOMEM; +- goto error; +- } ++ ++ iommu = drhd->iommu; + + ret = iommu_init_domains(iommu); + if (ret) +@@ -2349,6 +2346,9 @@ int __init intel_iommu_init(void) + if (dmar_table_init()) + return -ENODEV; + ++ if (dmar_dev_scope_init()) ++ return -ENODEV; ++ + iommu_init_mempool(); + dmar_init_reserved_ranges(); + +--- a/drivers/pci/intel-iommu.h ++++ b/drivers/pci/intel-iommu.h +@@ -199,7 +199,7 @@ struct intel_iommu { + + extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); + +-extern struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd); ++extern int alloc_iommu(struct dmar_drhd_unit *drhd); + extern void free_iommu(struct intel_iommu *iommu); + + #endif +--- a/include/linux/dmar.h ++++ b/include/linux/dmar.h +@@ -46,12 +46,14 @@ extern int intel_iommu_init(void); + + extern int dmar_table_init(void); + extern int early_dmar_detect(void); ++extern int dmar_dev_scope_init(void); + + extern struct list_head dmar_drhd_units; + extern struct list_head dmar_rmrr_units; + + struct dmar_drhd_unit { + struct list_head list; /* list of drhd units */ ++ struct acpi_dmar_header *hdr; /* ACPI header */ + u64 reg_base_addr; /* register base address*/ + struct pci_dev **devices; /* target device array */ + int devices_cnt; /* target device count */ +@@ -62,6 +64,7 @@ struct dmar_drhd_unit { + + struct dmar_rmrr_unit { + struct list_head list; /* list of rmrr units */ ++ struct acpi_dmar_header *hdr; /* ACPI header */ + u64 base_address; /* reserved base address*/ + u64 end_address; /* reserved end address */ + struct pci_dev **devices; /* target devices */ +@@ -72,6 +75,8 @@ struct dmar_rmrr_unit { + list_for_each_entry(drhd, &dmar_drhd_units, list) + #define for_each_rmrr_units(rmrr) \ + list_for_each_entry(rmrr, &dmar_rmrr_units, list) ++ ++extern int alloc_iommu(struct dmar_drhd_unit *); + #else + static inline void detect_intel_iommu(void) + { +@@ -81,6 +86,9 @@ static inline int intel_iommu_init(void) + { + return -ENODEV; + } +- ++static inline int dmar_table_init(void) ++{ ++ return -ENODEV; ++} + #endif /* !CONFIG_DMAR */ + #endif /* __DMAR_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_04_f12c73e7fa7ebf9ad6defee2c4fb2664e743e970 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_04_f12c73e7fa7ebf9ad6defee2c4fb2664e743e970 new file mode 100644 index 000000000..d63852eff --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_04_f12c73e7fa7ebf9ad6defee2c4fb2664e743e970 @@ -0,0 +1,127 @@ +From: Yinghai Lu +Subject: dmar: fix using early fixmap mapping for DMAR table parsing +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: f12c73e7fa7ebf9ad6defee2c4fb2664e743e970 + +Signed-off-by: Thomas Renninger + +Very early detection of the DMAR tables will setup fixmap mapping. For +parsing these tables later (while enabling dma and/or interrupt remapping), +early fixmap mapping shouldn't be used. Fix it by calling table detection +routines again, which will call generic apci_get_table() for setting up +the correct mapping. + +Signed-off-by: Yinghai Lu +Signed-off-by: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 49 ++++++++++++++++++++++++++++--------------------- + include/linux/dmar.h | 1 - + 2 files changed, 28 insertions(+), 22 deletions(-) + +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -289,6 +289,24 @@ dmar_table_print_dmar_entry(struct acpi_ + } + } + ++/** ++ * dmar_table_detect - checks to see if the platform supports DMAR devices ++ */ ++static int __init dmar_table_detect(void) ++{ ++ acpi_status status = AE_OK; ++ ++ /* if we could find DMAR table, then there are DMAR devices */ ++ status = acpi_get_table(ACPI_SIG_DMAR, 0, ++ (struct acpi_table_header **)&dmar_tbl); ++ ++ if (ACPI_SUCCESS(status) && !dmar_tbl) { ++ printk (KERN_WARNING PREFIX "Unable to map DMAR\n"); ++ status = AE_NOT_FOUND; ++ } ++ ++ return (ACPI_SUCCESS(status) ? 1 : 0); ++} + + /** + * parse_dmar_table - parses the DMA reporting table +@@ -300,6 +318,12 @@ parse_dmar_table(void) + struct acpi_dmar_header *entry_header; + int ret = 0; + ++ /* ++ * Do it again, earlier dmar_tbl mapping could be mapped with ++ * fixed map. ++ */ ++ dmar_table_detect(); ++ + dmar = (struct acpi_table_dmar *)dmar_tbl; + if (!dmar) + return -ENODEV; +@@ -432,30 +456,11 @@ int __init dmar_table_init(void) + return 0; + } + +-/** +- * early_dmar_detect - checks to see if the platform supports DMAR devices +- */ +-int __init early_dmar_detect(void) +-{ +- acpi_status status = AE_OK; +- +- /* if we could find DMAR table, then there are DMAR devices */ +- status = acpi_get_table(ACPI_SIG_DMAR, 0, +- (struct acpi_table_header **)&dmar_tbl); +- +- if (ACPI_SUCCESS(status) && !dmar_tbl) { +- printk (KERN_WARNING PREFIX "Unable to map DMAR\n"); +- status = AE_NOT_FOUND; +- } +- +- return (ACPI_SUCCESS(status) ? 1 : 0); +-} +- + void __init detect_intel_iommu(void) + { + int ret; + +- ret = early_dmar_detect(); ++ ret = dmar_table_detect(); + + #ifdef CONFIG_DMAR + { +@@ -481,14 +486,16 @@ void __init detect_intel_iommu(void) + " x2apic support\n"); + + dmar_disabled = 1; +- return; ++ goto end; + } + + if (ret && !no_iommu && !iommu_detected && !swiotlb && + !dmar_disabled) + iommu_detected = 1; + } ++end: + #endif ++ dmar_tbl = NULL; + } + + +Index: linux-2.6.26/include/linux/dmar.h +=================================================================== +--- linux-2.6.26.orig/include/linux/dmar.h ++++ linux-2.6.26/include/linux/dmar.h +@@ -45,7 +45,6 @@ extern struct list_head dmar_drhd_units; + list_for_each_entry(drhd, &dmar_drhd_units, list) + + extern int dmar_table_init(void); +-extern int early_dmar_detect(void); + extern int dmar_dev_scope_init(void); + + /* Intel IOMMU detection */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_04_of_41_aaa9d1dd63bf89b62f4ea9f46de376ab1a3fbc6c b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_04_of_41_aaa9d1dd63bf89b62f4ea9f46de376ab1a3fbc6c new file mode 100644 index 000000000..937a84798 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_04_of_41_aaa9d1dd63bf89b62f4ea9f46de376ab1a3fbc6c @@ -0,0 +1,133 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: use CONFIG_DMAR for DMA-remapping specific code +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: aaa9d1dd63bf89b62f4ea9f46de376ab1a3fbc6c + +Signed-off-by: Thomas Renninger + +DMA remapping specific code covered with CONFIG_DMAR in +the generic code which will also be used later for enabling Interrupt-remapping. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 39 +++++++++++++++++++++++++++------------ + 1 file changed, 27 insertions(+), 12 deletions(-) + +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -39,7 +39,6 @@ + * these units are not supported by the architecture. + */ + LIST_HEAD(dmar_drhd_units); +-LIST_HEAD(dmar_rmrr_units); + + static struct acpi_table_header * __initdata dmar_tbl; + +@@ -55,11 +54,6 @@ static void __init dmar_register_drhd_un + list_add(&drhd->list, &dmar_drhd_units); + } + +-static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr) +-{ +- list_add(&rmrr->list, &dmar_rmrr_units); +-} +- + static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, + struct pci_dev **dev, u16 segment) + { +@@ -224,6 +218,15 @@ dmar_parse_dev(struct dmar_drhd_unit *dm + return ret; + } + ++#ifdef CONFIG_DMAR ++LIST_HEAD(dmar_rmrr_units); ++ ++static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr) ++{ ++ list_add(&rmrr->list, &dmar_rmrr_units); ++} ++ ++ + static int __init + dmar_parse_one_rmrr(struct acpi_dmar_header *header) + { +@@ -260,6 +263,7 @@ rmrr_parse_dev(struct dmar_rmrr_unit *rm + } + return ret; + } ++#endif + + static void __init + dmar_table_print_dmar_entry(struct acpi_dmar_header *header) +@@ -284,6 +288,7 @@ dmar_table_print_dmar_entry(struct acpi_ + } + } + ++ + /** + * parse_dmar_table - parses the DMA reporting table + */ +@@ -316,7 +321,9 @@ parse_dmar_table(void) + ret = dmar_parse_one_drhd(entry_header); + break; + case ACPI_DMAR_TYPE_RESERVED_MEMORY: ++#ifdef CONFIG_DMAR + ret = dmar_parse_one_rmrr(entry_header); ++#endif + break; + default: + printk(KERN_WARNING PREFIX +@@ -366,7 +373,6 @@ dmar_find_matched_drhd_unit(struct pci_d + int __init dmar_dev_scope_init(void) + { + struct dmar_drhd_unit *drhd; +- struct dmar_rmrr_unit *rmrr; + int ret = -ENODEV; + + for_each_drhd_unit(drhd) { +@@ -375,11 +381,16 @@ int __init dmar_dev_scope_init(void) + return ret; + } + +- for_each_rmrr_units(rmrr) { +- ret = rmrr_parse_dev(rmrr); +- if (ret) +- return ret; ++#ifdef CONFIG_DMAR ++ { ++ struct dmar_rmrr_unit *rmrr; ++ for_each_rmrr_units(rmrr) { ++ ret = rmrr_parse_dev(rmrr); ++ if (ret) ++ return ret; ++ } + } ++#endif + + return ret; + } +@@ -407,8 +418,12 @@ int __init dmar_table_init(void) + return -ENODEV; + } + +- if (list_empty(&dmar_rmrr_units)) ++#ifdef CONFIG_DMAR ++ if (list_empty(&dmar_rmrr_units)) { + printk(KERN_INFO PREFIX "No RMRR found\n"); ++ return -ENODEV; ++ } ++#endif + + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_05_7be42004065ce4df193aeef5befd26805267d0d9 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_05_7be42004065ce4df193aeef5befd26805267d0d9 new file mode 100644 index 000000000..39437bf9d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_05_7be42004065ce4df193aeef5befd26805267d0d9 @@ -0,0 +1,32 @@ +From: Ingo Molnar +Subject: x86, lguest: fix apic_ops build on UP +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 7be42004065ce4df193aeef5befd26805267d0d9 + +Signed-off-by: Thomas Renninger + +fix: + + arch/x86/lguest/boot.c:816: error: variable ‘lguest_basic_apic_ops’ has initializer but incomplete type + arch/x86/lguest/boot.c:817: error: unknown field ‘read’ specified in initializer + [...] + +Signed-off-by: Ingo Molnar + +--- + arch/x86/lguest/boot.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.26/arch/x86/lguest/boot.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/lguest/boot.c ++++ linux-2.6.26/arch/x86/lguest/boot.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_06_caf43bf7c6a55e89b6df5179df434d67e24aa32e b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_06_caf43bf7c6a55e89b6df5179df434d67e24aa32e new file mode 100644 index 000000000..eaeb08782 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_06_caf43bf7c6a55e89b6df5179df434d67e24aa32e @@ -0,0 +1,32 @@ +From: Ingo Molnar +Subject: x86, xen: fix apic_ops build on UP +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: caf43bf7c6a55e89b6df5179df434d67e24aa32e + +Signed-off-by: Thomas Renninger + +fix: + + arch/x86/xen/enlighten.c:615: error: variable ‘xen_basic_apic_ops’ has initializer but incomplete type + arch/x86/xen/enlighten.c:616: error: unknown field ‘read’ specified in initializer + [...] + +Signed-off-by: Ingo Molnar + +--- + arch/x86/xen/enlighten.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.26/arch/x86/xen/enlighten.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/xen/enlighten.c ++++ linux-2.6.26/arch/x86/xen/enlighten.c +@@ -36,6 +36,7 @@ + #include + + #include ++#include + #include + #include + #include diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_06_of_41_ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_06_of_41_ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6 new file mode 100644 index 000000000..8acf63fd9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_06_of_41_ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6 @@ -0,0 +1,169 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: parse ioapic scope under vt-d structures +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: ad3ad3f6a2caebf56869b83b69e23eb9fa5e0ab6 + +Signed-off-by: Thomas Renninger + +Parse the vt-d device scope structures to find the mapping between IO-APICs +and the interrupt remapping hardware units. + +This will be used later for enabling Interrupt-remapping for IOAPIC devices. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/Makefile | 2 + + drivers/pci/dmar.c | 3 + + drivers/pci/intel-iommu.h | 2 + + drivers/pci/intr_remapping.c | 70 +++++++++++++++++++++++++++++++++++++++++++ + drivers/pci/intr_remapping.h | 6 +++ + include/linux/dmar.h | 1 + 6 files changed, 84 insertions(+) + +Index: linux-2.6.26/drivers/pci/Makefile +=================================================================== +--- linux-2.6.26.orig/drivers/pci/Makefile ++++ linux-2.6.26/drivers/pci/Makefile +@@ -26,6 +26,8 @@ obj-$(CONFIG_HT_IRQ) += htirq.o + # Build Intel IOMMU support + obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o + ++obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o ++ + # + # Some architectures use the generic PCI setup functions + # +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -425,6 +425,9 @@ int __init dmar_table_init(void) + } + #endif + ++#ifdef CONFIG_INTR_REMAP ++ parse_ioapics_under_ir(); ++#endif + return 0; + } + +Index: linux-2.6.26/drivers/pci/intel-iommu.h +=================================================================== +--- linux-2.6.26.orig/drivers/pci/intel-iommu.h ++++ linux-2.6.26/drivers/pci/intel-iommu.h +@@ -114,6 +114,8 @@ static inline void dmar_writeq(void __io + #define ecap_max_iotlb_offset(e) \ + (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16) + #define ecap_coherent(e) ((e) & 0x1) ++#define ecap_eim_support(e) ((e >> 4) & 0x1) ++#define ecap_ir_support(e) ((e >> 3) & 0x1) + + + /* IOTLB_REG */ +Index: linux-2.6.26/drivers/pci/intr_remapping.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/drivers/pci/intr_remapping.c +@@ -0,0 +1,70 @@ ++#include ++#include ++#include "intel-iommu.h" ++#include "intr_remapping.h" ++ ++static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; ++static int ir_ioapic_num; ++ ++static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, ++ struct intel_iommu *iommu) ++{ ++ struct acpi_dmar_hardware_unit *drhd; ++ struct acpi_dmar_device_scope *scope; ++ void *start, *end; ++ ++ drhd = (struct acpi_dmar_hardware_unit *)header; ++ ++ start = (void *)(drhd + 1); ++ end = ((void *)drhd) + header->length; ++ ++ while (start < end) { ++ scope = start; ++ if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_IOAPIC) { ++ if (ir_ioapic_num == MAX_IO_APICS) { ++ printk(KERN_WARNING "Exceeded Max IO APICS\n"); ++ return -1; ++ } ++ ++ printk(KERN_INFO "IOAPIC id %d under DRHD base" ++ " 0x%Lx\n", scope->enumeration_id, ++ drhd->address); ++ ++ ir_ioapic[ir_ioapic_num].iommu = iommu; ++ ir_ioapic[ir_ioapic_num].id = scope->enumeration_id; ++ ir_ioapic_num++; ++ } ++ start += scope->length; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Finds the assocaition between IOAPIC's and its Interrupt-remapping ++ * hardware unit. ++ */ ++int __init parse_ioapics_under_ir(void) ++{ ++ struct dmar_drhd_unit *drhd; ++ int ir_supported = 0; ++ ++ for_each_drhd_unit(drhd) { ++ struct intel_iommu *iommu = drhd->iommu; ++ ++ if (ecap_ir_support(iommu->ecap)) { ++ if (ir_parse_ioapic_scope(drhd->hdr, iommu)) ++ return -1; ++ ++ ir_supported = 1; ++ } ++ } ++ ++ if (ir_supported && ir_ioapic_num != nr_ioapics) { ++ printk(KERN_WARNING ++ "Not all IO-APIC's listed under remapping hardware\n"); ++ return -1; ++ } ++ ++ return ir_supported; ++} +Index: linux-2.6.26/drivers/pci/intr_remapping.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/drivers/pci/intr_remapping.h +@@ -0,0 +1,6 @@ ++#include "intel-iommu.h" ++ ++struct ioapic_scope { ++ struct intel_iommu *iommu; ++ unsigned int id; ++}; +Index: linux-2.6.26/include/linux/dmar.h +=================================================================== +--- linux-2.6.26.orig/include/linux/dmar.h ++++ linux-2.6.26/include/linux/dmar.h +@@ -47,6 +47,7 @@ extern int intel_iommu_init(void); + extern int dmar_table_init(void); + extern int early_dmar_detect(void); + extern int dmar_dev_scope_init(void); ++extern int parse_ioapics_under_ir(void); + + extern struct list_head dmar_drhd_units; + extern struct list_head dmar_rmrr_units; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_07_511d9d34183662aada3890883e860b151d707e22 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_07_511d9d34183662aada3890883e860b151d707e22 new file mode 100644 index 000000000..fd5bb8d68 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_07_511d9d34183662aada3890883e860b151d707e22 @@ -0,0 +1,70 @@ +From: Suresh Siddha +Subject: x86: apic_ops for lguest +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 511d9d34183662aada3890883e860b151d707e22 + +Signed-off-by: Thomas Renninger + +apic_ops for lguest. + +Signed-off-by: Suresh Siddha +Acked-by: Yinghai Lu +Signed-off-by: Ingo Molnar + +--- + arch/x86/lguest/boot.c | 34 ++++++++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +Index: linux-2.6.26/arch/x86/lguest/boot.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/lguest/boot.c ++++ linux-2.6.26/arch/x86/lguest/boot.c +@@ -792,6 +792,37 @@ static u32 lguest_apic_read(u32 reg) + { + return 0; + } ++ ++static u64 lguest_apic_icr_read(void) ++{ ++ return 0; ++} ++ ++static void lguest_apic_icr_write(u32 low, u32 id) ++{ ++ /* Warn to see if there's any stray references */ ++ WARN_ON(1); ++} ++ ++static void lguest_apic_wait_icr_idle(void) ++{ ++ return; ++} ++ ++static u32 lguest_apic_safe_wait_icr_idle(void) ++{ ++ return 0; ++} ++ ++static struct apic_ops lguest_basic_apic_ops = { ++ .read = lguest_apic_read, ++ .write = lguest_apic_write, ++ .write_atomic = lguest_apic_write, ++ .icr_read = lguest_apic_icr_read, ++ .icr_write = lguest_apic_icr_write, ++ .wait_icr_idle = lguest_apic_wait_icr_idle, ++ .safe_wait_icr_idle = lguest_apic_safe_wait_icr_idle, ++}; + #endif + + /* STOP! Until an interrupt comes in. */ +@@ -991,8 +1022,7 @@ __init void lguest_init(void) + + #ifdef CONFIG_X86_LOCAL_APIC + /* apic read/write intercepts */ +- pv_apic_ops.apic_write = lguest_apic_write; +- pv_apic_ops.apic_read = lguest_apic_read; ++ apic_ops = &lguest_basic_apic_ops; + #endif + + /* time operations */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_07_of_41_cf1337f0447e5be8e66daa944f0ea3bcac2b6179 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_07_of_41_cf1337f0447e5be8e66daa944f0ea3bcac2b6179 new file mode 100644 index 000000000..5b573416f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_07_of_41_cf1337f0447e5be8e66daa944f0ea3bcac2b6179 @@ -0,0 +1,81 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: move IOMMU_WAIT_OP() macro to intel-iommu.h +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: cf1337f0447e5be8e66daa944f0ea3bcac2b6179 + +Signed-off-by: Thomas Renninger + +move IOMMU_WAIT_OP() macro to header file. + +This will be used by both DMA-remapping and Intr-remapping. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/intel-iommu.c | 15 --------------- + drivers/pci/intel-iommu.h | 15 +++++++++++++++ + 2 files changed, 15 insertions(+), 15 deletions(-) + +--- a/drivers/pci/intel-iommu.c ++++ b/drivers/pci/intel-iommu.c +@@ -49,8 +49,6 @@ + + #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48 + +-#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */ +- + #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1) + + +@@ -488,19 +486,6 @@ static int iommu_alloc_root_entry(struct + return 0; + } + +-#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \ +-{\ +- cycles_t start_time = get_cycles();\ +- while (1) {\ +- sts = op (iommu->reg + offset);\ +- if (cond)\ +- break;\ +- if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\ +- panic("DMAR hardware is malfunctioning\n");\ +- cpu_relax();\ +- }\ +-} +- + static void iommu_set_root_entry(struct intel_iommu *iommu) + { + void *addr; +--- a/drivers/pci/intel-iommu.h ++++ b/drivers/pci/intel-iommu.h +@@ -177,6 +177,21 @@ static inline void dmar_writeq(void __io + #define dma_frcd_source_id(c) (c & 0xffff) + #define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */ + ++#define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) /* 10sec */ ++ ++#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \ ++{\ ++ cycles_t start_time = get_cycles();\ ++ while (1) {\ ++ sts = op (iommu->reg + offset);\ ++ if (cond)\ ++ break;\ ++ if (DMAR_OPERATION_TIMEOUT < (get_cycles() - start_time))\ ++ panic("DMAR hardware is malfunctioning\n");\ ++ cpu_relax();\ ++ }\ ++} ++ + struct intel_iommu { + void __iomem *reg; /* Pointer to hardware regs, virtual addr */ + u64 cap; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_08_of_41_fe962e90cb17a8426e144dee970e77ed789d98ee b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_08_of_41_fe962e90cb17a8426e144dee970e77ed789d98ee new file mode 100644 index 000000000..7aa841812 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_08_of_41_fe962e90cb17a8426e144dee970e77ed789d98ee @@ -0,0 +1,330 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: Queued invalidation infrastructure (part of VT-d) +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: fe962e90cb17a8426e144dee970e77ed789d98ee + +Signed-off-by: Thomas Renninger + +Queued invalidation (part of Intel Virtualization Technology for +Directed I/O architecture) infrastructure. + +This will be used for invalidating the interrupt entry cache in the +case of Interrupt-remapping and IOTLB invalidation in the case +of DMA-remapping. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++ + drivers/pci/intel-iommu.c | 7 -- + drivers/pci/intel-iommu.h | 61 ++++++++++++++++++ + 3 files changed, 211 insertions(+), 7 deletions(-) + +--- a/drivers/pci/dmar.c ++++ b/drivers/pci/dmar.c +@@ -28,6 +28,7 @@ + + #include + #include ++#include + #include "iova.h" + #include "intel-iommu.h" + +@@ -511,3 +512,152 @@ void free_iommu(struct intel_iommu *iomm + iounmap(iommu->reg); + kfree(iommu); + } ++ ++/* ++ * Reclaim all the submitted descriptors which have completed its work. ++ */ ++static inline void reclaim_free_desc(struct q_inval *qi) ++{ ++ while (qi->desc_status[qi->free_tail] == QI_DONE) { ++ qi->desc_status[qi->free_tail] = QI_FREE; ++ qi->free_tail = (qi->free_tail + 1) % QI_LENGTH; ++ qi->free_cnt++; ++ } ++} ++ ++/* ++ * Submit the queued invalidation descriptor to the remapping ++ * hardware unit and wait for its completion. ++ */ ++void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu) ++{ ++ struct q_inval *qi = iommu->qi; ++ struct qi_desc *hw, wait_desc; ++ int wait_index, index; ++ unsigned long flags; ++ ++ if (!qi) ++ return; ++ ++ hw = qi->desc; ++ ++ spin_lock(&qi->q_lock); ++ while (qi->free_cnt < 3) { ++ spin_unlock(&qi->q_lock); ++ cpu_relax(); ++ spin_lock(&qi->q_lock); ++ } ++ ++ index = qi->free_head; ++ wait_index = (index + 1) % QI_LENGTH; ++ ++ qi->desc_status[index] = qi->desc_status[wait_index] = QI_IN_USE; ++ ++ hw[index] = *desc; ++ ++ wait_desc.low = QI_IWD_STATUS_DATA(2) | QI_IWD_STATUS_WRITE | QI_IWD_TYPE; ++ wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]); ++ ++ hw[wait_index] = wait_desc; ++ ++ __iommu_flush_cache(iommu, &hw[index], sizeof(struct qi_desc)); ++ __iommu_flush_cache(iommu, &hw[wait_index], sizeof(struct qi_desc)); ++ ++ qi->free_head = (qi->free_head + 2) % QI_LENGTH; ++ qi->free_cnt -= 2; ++ ++ spin_lock_irqsave(&iommu->register_lock, flags); ++ /* ++ * update the HW tail register indicating the presence of ++ * new descriptors. ++ */ ++ writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG); ++ spin_unlock_irqrestore(&iommu->register_lock, flags); ++ ++ while (qi->desc_status[wait_index] != QI_DONE) { ++ spin_unlock(&qi->q_lock); ++ cpu_relax(); ++ spin_lock(&qi->q_lock); ++ } ++ ++ qi->desc_status[index] = QI_DONE; ++ ++ reclaim_free_desc(qi); ++ spin_unlock(&qi->q_lock); ++} ++ ++/* ++ * Flush the global interrupt entry cache. ++ */ ++void qi_global_iec(struct intel_iommu *iommu) ++{ ++ struct qi_desc desc; ++ ++ desc.low = QI_IEC_TYPE; ++ desc.high = 0; ++ ++ qi_submit_sync(&desc, iommu); ++} ++ ++/* ++ * Enable Queued Invalidation interface. This is a must to support ++ * interrupt-remapping. Also used by DMA-remapping, which replaces ++ * register based IOTLB invalidation. ++ */ ++int dmar_enable_qi(struct intel_iommu *iommu) ++{ ++ u32 cmd, sts; ++ unsigned long flags; ++ struct q_inval *qi; ++ ++ if (!ecap_qis(iommu->ecap)) ++ return -ENOENT; ++ ++ /* ++ * queued invalidation is already setup and enabled. ++ */ ++ if (iommu->qi) ++ return 0; ++ ++ iommu->qi = kmalloc(sizeof(*qi), GFP_KERNEL); ++ if (!iommu->qi) ++ return -ENOMEM; ++ ++ qi = iommu->qi; ++ ++ qi->desc = (void *)(get_zeroed_page(GFP_KERNEL)); ++ if (!qi->desc) { ++ kfree(qi); ++ iommu->qi = 0; ++ return -ENOMEM; ++ } ++ ++ qi->desc_status = kmalloc(QI_LENGTH * sizeof(int), GFP_KERNEL); ++ if (!qi->desc_status) { ++ free_page((unsigned long) qi->desc); ++ kfree(qi); ++ iommu->qi = 0; ++ return -ENOMEM; ++ } ++ ++ qi->free_head = qi->free_tail = 0; ++ qi->free_cnt = QI_LENGTH; ++ ++ spin_lock_init(&qi->q_lock); ++ ++ spin_lock_irqsave(&iommu->register_lock, flags); ++ /* write zero to the tail reg */ ++ writel(0, iommu->reg + DMAR_IQT_REG); ++ ++ dmar_writeq(iommu->reg + DMAR_IQA_REG, virt_to_phys(qi->desc)); ++ ++ cmd = iommu->gcmd | DMA_GCMD_QIE; ++ iommu->gcmd |= DMA_GCMD_QIE; ++ writel(cmd, iommu->reg + DMAR_GCMD_REG); ++ ++ /* Make sure hardware complete it */ ++ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_QIES), sts); ++ spin_unlock_irqrestore(&iommu->register_lock, flags); ++ ++ return 0; ++} +--- a/drivers/pci/intel-iommu.c ++++ b/drivers/pci/intel-iommu.c +@@ -183,13 +183,6 @@ void free_iova_mem(struct iova *iova) + kmem_cache_free(iommu_iova_cache, iova); + } + +-static inline void __iommu_flush_cache( +- struct intel_iommu *iommu, void *addr, int size) +-{ +- if (!ecap_coherent(iommu->ecap)) +- clflush_cache_range(addr, size); +-} +- + /* Gets context entry for a given bus and devfn */ + static struct context_entry * device_to_context_entry(struct intel_iommu *iommu, + u8 bus, u8 devfn) +--- a/drivers/pci/intel-iommu.h ++++ b/drivers/pci/intel-iommu.h +@@ -27,6 +27,7 @@ + #include + #include "iova.h" + #include ++#include + #include "dma_remapping.h" + + /* +@@ -51,6 +52,10 @@ + #define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */ + #define DMAR_PHMBASE_REG 0x70 /* pmrr high base addr */ + #define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */ ++#define DMAR_IQH_REG 0x80 /* Invalidation queue head register */ ++#define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */ ++#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */ ++#define DMAR_ICS_REG 0x98 /* Invalidation complete status register */ + + #define OFFSET_STRIDE (9) + /* +@@ -114,6 +119,7 @@ static inline void dmar_writeq(void __io + #define ecap_max_iotlb_offset(e) \ + (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16) + #define ecap_coherent(e) ((e) & 0x1) ++#define ecap_qis(e) ((e) & 0x2) + #define ecap_eim_support(e) ((e >> 4) & 0x1) + #define ecap_ir_support(e) ((e >> 3) & 0x1) + +@@ -131,6 +137,17 @@ static inline void dmar_writeq(void __io + #define DMA_TLB_IH_NONLEAF (((u64)1) << 6) + #define DMA_TLB_MAX_SIZE (0x3f) + ++/* INVALID_DESC */ ++#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3) ++#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3) ++#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3) ++#define DMA_ID_TLB_READ_DRAIN (((u64)1) << 7) ++#define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6) ++#define DMA_ID_TLB_DID(id) (((u64)((id & 0xffff) << 16))) ++#define DMA_ID_TLB_IH_NONLEAF (((u64)1) << 6) ++#define DMA_ID_TLB_ADDR(addr) (addr) ++#define DMA_ID_TLB_ADDR_MASK(mask) (mask) ++ + /* PMEN_REG */ + #define DMA_PMEN_EPM (((u32)1)<<31) + #define DMA_PMEN_PRS (((u32)1)<<0) +@@ -140,6 +157,7 @@ static inline void dmar_writeq(void __io + #define DMA_GCMD_SRTP (((u32)1) << 30) + #define DMA_GCMD_SFL (((u32)1) << 29) + #define DMA_GCMD_EAFL (((u32)1) << 28) ++#define DMA_GCMD_QIE (((u32)1) << 26) + #define DMA_GCMD_WBF (((u32)1) << 27) + + /* GSTS_REG */ +@@ -147,6 +165,7 @@ static inline void dmar_writeq(void __io + #define DMA_GSTS_RTPS (((u32)1) << 30) + #define DMA_GSTS_FLS (((u32)1) << 29) + #define DMA_GSTS_AFLS (((u32)1) << 28) ++#define DMA_GSTS_QIES (((u32)1) << 26) + #define DMA_GSTS_WBFS (((u32)1) << 27) + + /* CCMD_REG */ +@@ -192,6 +211,40 @@ static inline void dmar_writeq(void __io + }\ + } + ++#define QI_LENGTH 256 /* queue length */ ++ ++enum { ++ QI_FREE, ++ QI_IN_USE, ++ QI_DONE ++}; ++ ++#define QI_CC_TYPE 0x1 ++#define QI_IOTLB_TYPE 0x2 ++#define QI_DIOTLB_TYPE 0x3 ++#define QI_IEC_TYPE 0x4 ++#define QI_IWD_TYPE 0x5 ++ ++#define QI_IEC_SELECTIVE (((u64)1) << 4) ++#define QI_IEC_IIDEX(idx) (((u64)(idx & 0xffff) << 32)) ++#define QI_IEC_IM(m) (((u64)(m & 0x1f) << 27)) ++ ++#define QI_IWD_STATUS_DATA(d) (((u64)d) << 32) ++#define QI_IWD_STATUS_WRITE (((u64)1) << 5) ++ ++struct qi_desc { ++ u64 low, high; ++}; ++ ++struct q_inval { ++ spinlock_t q_lock; ++ struct qi_desc *desc; /* invalidation queue */ ++ int *desc_status; /* desc status */ ++ int free_head; /* first free entry */ ++ int free_tail; /* last free entry */ ++ int free_cnt; ++}; ++ + struct intel_iommu { + void __iomem *reg; /* Pointer to hardware regs, virtual addr */ + u64 cap; +@@ -212,8 +265,16 @@ struct intel_iommu { + struct msi_msg saved_msg; + struct sys_device sysdev; + #endif ++ struct q_inval *qi; /* Queued invalidation info */ + }; + ++static inline void __iommu_flush_cache( ++ struct intel_iommu *iommu, void *addr, int size) ++{ ++ if (!ecap_coherent(iommu->ecap)) ++ clflush_cache_range(addr, size); ++} ++ + extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); + + extern int alloc_iommu(struct dmar_drhd_unit *drhd); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_09_94a8c3c2437c8946f1b6c8e0b2c560a7db8ed3c6 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_09_94a8c3c2437c8946f1b6c8e0b2c560a7db8ed3c6 new file mode 100644 index 000000000..7476f7790 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_09_94a8c3c2437c8946f1b6c8e0b2c560a7db8ed3c6 @@ -0,0 +1,193 @@ +From: Yinghai Lu +Subject: x86: let 32bit use apic_ops too - fix +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 94a8c3c2437c8946f1b6c8e0b2c560a7db8ed3c6 + +Signed-off-by: Thomas Renninger + +fix for pv - clean up the namespace there too. + +Signed-off-by: Yinghai Lu +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/paravirt.c | 4 --- + arch/x86/kernel/vmi_32.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- + arch/x86/xen/enlighten.c | 18 ++++++++--------- + include/asm-x86/paravirt.h | 23 ---------------------- + 4 files changed, 54 insertions(+), 38 deletions(-) + +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -373,10 +373,6 @@ struct pv_cpu_ops pv_cpu_ops = { + + struct pv_apic_ops pv_apic_ops = { + #ifdef CONFIG_X86_LOCAL_APIC +-#ifndef CONFIG_X86_64 +- .apic_write = native_apic_mem_write, +- .apic_read = native_apic_mem_read, +-#endif + .setup_boot_clock = setup_boot_APIC_clock, + .setup_secondary_clock = setup_secondary_APIC_clock, + .startup_ipi_hook = paravirt_nop, +--- a/arch/x86/kernel/vmi_32.c ++++ b/arch/x86/kernel/vmi_32.c +@@ -687,6 +687,49 @@ static inline int __init probe_vmi_rom(v + return 0; + } + ++#ifdef CONFIG_X86_LOCAL_APIC ++static u32 vmi_apic_read(u32 reg) ++{ ++ return 0; ++} ++ ++static void vmi_apic_write(u32 reg, u32 val) ++{ ++ /* Warn to see if there's any stray references */ ++ WARN_ON(1); ++} ++ ++static u64 vmi_apic_icr_read(void) ++{ ++ return 0; ++} ++ ++static void vmi_apic_icr_write(u32 low, u32 id) ++{ ++ /* Warn to see if there's any stray references */ ++ WARN_ON(1); ++} ++ ++static void vmi_apic_wait_icr_idle(void) ++{ ++ return; ++} ++ ++static u32 vmi_safe_apic_wait_icr_idle(void) ++{ ++ return 0; ++} ++ ++static struct apic_ops vmi_basic_apic_ops = { ++ .read = vmi_apic_read, ++ .write = vmi_apic_write, ++ .icr_read = vmi_apic_icr_read, ++ .icr_write = vmi_apic_icr_write, ++ .wait_icr_idle = vmi_apic_wait_icr_idle, ++ .safe_wait_icr_idle = vmi_safe_apic_wait_icr_idle, ++}; ++#endif ++ + /* + * VMI setup common to all processors + */ +@@ -916,8 +959,8 @@ static inline int __init activate_vmi(vo + #endif + + #ifdef CONFIG_X86_LOCAL_APIC +- para_fill(pv_apic_ops.apic_read, APICRead); +- para_fill(pv_apic_ops.apic_write, APICWrite); ++ para_fill(vmi_basic_apic_ops.read, APICRead); ++ para_fill(vmi_basic_apic_ops.write, APICWrite); + #endif + + /* +--- a/arch/x86/xen/enlighten.c ++++ b/arch/x86/xen/enlighten.c +@@ -592,7 +592,6 @@ static void xen_apic_write(u32 reg, u32 + WARN_ON(1); + } + +-#ifdef CONFIG_X86_64 + static u64 xen_apic_icr_read(void) + { + return 0; +@@ -609,6 +608,11 @@ static void xen_apic_wait_icr_idle(void) + return; + } + ++static u32 xen_safe_apic_wait_icr_idle(void) ++{ ++ return 0; ++} ++ + static struct apic_ops xen_basic_apic_ops = { + .read = xen_apic_read, + .write = xen_apic_write, +@@ -616,9 +620,8 @@ static struct apic_ops xen_basic_apic_op + .icr_read = xen_apic_icr_read, + .icr_write = xen_apic_icr_write, + .wait_icr_idle = xen_apic_wait_icr_idle, +- .safe_wait_icr_idle = xen_apic_wait_icr_idle, ++ .safe_wait_icr_idle = xen_safe_apic_wait_icr_idle, + }; +-#endif + + #endif + +@@ -1303,10 +1306,6 @@ static const struct pv_irq_ops xen_irq_o + + static const struct pv_apic_ops xen_apic_ops __initdata = { + #ifdef CONFIG_X86_LOCAL_APIC +-#ifndef CONFIG_X86_64 +- .apic_write = xen_apic_write, +- .apic_read = xen_apic_read, +-#endif + .setup_boot_clock = paravirt_nop, + .setup_secondary_clock = paravirt_nop, + .startup_ipi_hook = paravirt_nop, +@@ -1708,9 +1707,10 @@ asmlinkage void __init xen_start_kernel( + pv_irq_ops = xen_irq_ops; + pv_apic_ops = xen_apic_ops; + pv_mmu_ops = xen_mmu_ops; +-#ifdef CONFIG_X86_64 ++ ++#ifdef CONFIG_X86_LOCAL_APIC + /* +- * for 64bit, set up the basic apic ops aswell. ++ * set up the basic apic ops. + */ + apic_ops = &xen_basic_apic_ops; + #endif +--- a/include/asm-x86/paravirt.h ++++ b/include/asm-x86/paravirt.h +@@ -200,14 +200,6 @@ struct pv_irq_ops { + + struct pv_apic_ops { + #ifdef CONFIG_X86_LOCAL_APIC +-#ifndef CONFIG_X86_64 +- /* +- * Direct APIC operations, principally for VMI. Ideally +- * these shouldn't be in this interface. +- */ +- void (*apic_write)(u32 reg, u32 v); +- u32 (*apic_read)(u32 reg); +-#endif + void (*setup_boot_clock)(void); + void (*setup_secondary_clock)(void); + void (*startup_ipi_hook)(int phys_apicid, +@@ -899,21 +891,6 @@ static inline void slow_down_io(void) + } + + #ifdef CONFIG_X86_LOCAL_APIC +-/* +- * Basic functions accessing APICs. +- */ +-#ifndef CONFIG_X86_64 +-static inline void apic_write(u32 reg, u32 v) +-{ +- PVOP_VCALL2(pv_apic_ops.apic_write, reg, v); +-} +- +-static inline u32 apic_read(u32 reg) +-{ +- return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg); +-} +-#endif +- + static inline void setup_boot_clock(void) + { + PVOP_VCALL0(pv_apic_ops.setup_boot_clock); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_09_of_41_2ae21010694e56461a63bfc80e960090ce0a5ed9 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_09_of_41_2ae21010694e56461a63bfc80e960090ce0a5ed9 new file mode 100644 index 000000000..9104e4543 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_09_of_41_2ae21010694e56461a63bfc80e960090ce0a5ed9 @@ -0,0 +1,498 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: Interrupt remapping infrastructure +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 2ae21010694e56461a63bfc80e960090ce0a5ed9 + +Signed-off-by: Thomas Renninger + +Interrupt remapping (part of Intel Virtualization Tech for directed I/O) +infrastructure. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dma_remapping.h | 2 + drivers/pci/dmar.c | 16 +++++ + drivers/pci/intel-iommu.c | 25 ++----- + drivers/pci/intel-iommu.h | 24 ++++++- + drivers/pci/intr_remapping.c | 137 +++++++++++++++++++++++++++++++++++++++++++ + drivers/pci/intr_remapping.h | 2 + include/linux/dmar.h | 120 ++++++++++++++++++++++++++----------- + 7 files changed, 272 insertions(+), 54 deletions(-) + +--- a/drivers/pci/dmar.c ++++ b/drivers/pci/dmar.c +@@ -451,6 +451,22 @@ int __init early_dmar_detect(void) + return (ACPI_SUCCESS(status) ? 1 : 0); + } + ++void __init detect_intel_iommu(void) ++{ ++ int ret; ++ ++ ret = early_dmar_detect(); ++ ++#ifdef CONFIG_DMAR ++ { ++ if (ret && !no_iommu && !iommu_detected && !swiotlb && ++ !dmar_disabled) ++ iommu_detected = 1; ++ } ++#endif ++} ++ ++ + int alloc_iommu(struct dmar_drhd_unit *drhd) + { + struct intel_iommu *iommu; +--- a/drivers/pci/dma_remapping.h ++++ b/drivers/pci/dma_remapping.h +@@ -145,6 +145,8 @@ struct device_domain_info { + extern int init_dmars(void); + extern void free_dmar_iommu(struct intel_iommu *iommu); + ++extern int dmar_disabled; ++ + #ifndef CONFIG_DMAR_GFX_WA + static inline void iommu_prepare_gfx_mapping(void) + { +--- a/drivers/pci/intel-iommu.c ++++ b/drivers/pci/intel-iommu.c +@@ -78,7 +78,7 @@ static long list_size; + + static void domain_remove_dev_info(struct dmar_domain *domain); + +-static int dmar_disabled; ++int dmar_disabled; + static int __initdata dmar_map_gfx = 1; + static int dmar_forcedac; + static int intel_iommu_strict; +@@ -2259,19 +2259,6 @@ static struct dmi_system_id __initdata i + { } + }; + +- +-void __init detect_intel_iommu(void) +-{ +- if (swiotlb || no_iommu || iommu_detected || dmar_disabled) +- return; +- if (early_dmar_detect()) { +- dmi_check_system(intel_iommu_dmi_table); +- if (dmar_disabled) +- return; +- iommu_detected = 1; +- } +-} +- + static void __init init_no_remapping_devices(void) + { + struct dmar_drhd_unit *drhd; +@@ -2318,15 +2305,19 @@ int __init intel_iommu_init(void) + { + int ret = 0; + +- if (no_iommu || swiotlb || dmar_disabled) +- return -ENODEV; +- + if (dmar_table_init()) + return -ENODEV; + + if (dmar_dev_scope_init()) + return -ENODEV; + ++ /* ++ * Check the need for DMA-remapping initialization now. ++ * Above initialization will also be used by Interrupt-remapping. ++ */ ++ if (no_iommu || swiotlb || dmar_disabled) ++ return -ENODEV; ++ + iommu_init_mempool(); + dmar_init_reserved_ranges(); + +--- a/drivers/pci/intel-iommu.h ++++ b/drivers/pci/intel-iommu.h +@@ -56,6 +56,7 @@ + #define DMAR_IQT_REG 0x88 /* Invalidation queue tail register */ + #define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */ + #define DMAR_ICS_REG 0x98 /* Invalidation complete status register */ ++#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */ + + #define OFFSET_STRIDE (9) + /* +@@ -157,16 +158,20 @@ static inline void dmar_writeq(void __io + #define DMA_GCMD_SRTP (((u32)1) << 30) + #define DMA_GCMD_SFL (((u32)1) << 29) + #define DMA_GCMD_EAFL (((u32)1) << 28) +-#define DMA_GCMD_QIE (((u32)1) << 26) + #define DMA_GCMD_WBF (((u32)1) << 27) ++#define DMA_GCMD_QIE (((u32)1) << 26) ++#define DMA_GCMD_SIRTP (((u32)1) << 24) ++#define DMA_GCMD_IRE (((u32) 1) << 25) + + /* GSTS_REG */ + #define DMA_GSTS_TES (((u32)1) << 31) + #define DMA_GSTS_RTPS (((u32)1) << 30) + #define DMA_GSTS_FLS (((u32)1) << 29) + #define DMA_GSTS_AFLS (((u32)1) << 28) +-#define DMA_GSTS_QIES (((u32)1) << 26) + #define DMA_GSTS_WBFS (((u32)1) << 27) ++#define DMA_GSTS_QIES (((u32)1) << 26) ++#define DMA_GSTS_IRTPS (((u32)1) << 24) ++#define DMA_GSTS_IRES (((u32)1) << 25) + + /* CCMD_REG */ + #define DMA_CCMD_ICC (((u64)1) << 63) +@@ -245,6 +250,16 @@ struct q_inval { + int free_cnt; + }; + ++#ifdef CONFIG_INTR_REMAP ++/* 1MB - maximum possible interrupt remapping table size */ ++#define INTR_REMAP_PAGE_ORDER 8 ++#define INTR_REMAP_TABLE_REG_SIZE 0xf ++ ++struct ir_table { ++ struct irte *base; ++}; ++#endif ++ + struct intel_iommu { + void __iomem *reg; /* Pointer to hardware regs, virtual addr */ + u64 cap; +@@ -266,6 +281,9 @@ struct intel_iommu { + struct sys_device sysdev; + #endif + struct q_inval *qi; /* Queued invalidation info */ ++#ifdef CONFIG_INTR_REMAP ++ struct ir_table *ir_table; /* Interrupt remapping info */ ++#endif + }; + + static inline void __iommu_flush_cache( +@@ -279,5 +297,7 @@ extern struct dmar_drhd_unit * dmar_find + + extern int alloc_iommu(struct dmar_drhd_unit *drhd); + extern void free_iommu(struct intel_iommu *iommu); ++extern int dmar_enable_qi(struct intel_iommu *iommu); ++extern void qi_global_iec(struct intel_iommu *iommu); + + #endif +--- a/drivers/pci/intr_remapping.c ++++ b/drivers/pci/intr_remapping.c +@@ -1,10 +1,147 @@ + #include ++#include ++#include ++#include + #include + #include "intel-iommu.h" + #include "intr_remapping.h" + + static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; + static int ir_ioapic_num; ++int intr_remapping_enabled; ++ ++static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) ++{ ++ u64 addr; ++ u32 cmd, sts; ++ unsigned long flags; ++ ++ addr = virt_to_phys((void *)iommu->ir_table->base); ++ ++ spin_lock_irqsave(&iommu->register_lock, flags); ++ ++ dmar_writeq(iommu->reg + DMAR_IRTA_REG, ++ (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE); ++ ++ /* Set interrupt-remapping table pointer */ ++ cmd = iommu->gcmd | DMA_GCMD_SIRTP; ++ writel(cmd, iommu->reg + DMAR_GCMD_REG); ++ ++ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, ++ readl, (sts & DMA_GSTS_IRTPS), sts); ++ spin_unlock_irqrestore(&iommu->register_lock, flags); ++ ++ /* ++ * global invalidation of interrupt entry cache before enabling ++ * interrupt-remapping. ++ */ ++ qi_global_iec(iommu); ++ ++ spin_lock_irqsave(&iommu->register_lock, flags); ++ ++ /* Enable interrupt-remapping */ ++ cmd = iommu->gcmd | DMA_GCMD_IRE; ++ iommu->gcmd |= DMA_GCMD_IRE; ++ writel(cmd, iommu->reg + DMAR_GCMD_REG); ++ ++ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, ++ readl, (sts & DMA_GSTS_IRES), sts); ++ ++ spin_unlock_irqrestore(&iommu->register_lock, flags); ++} ++ ++ ++static int setup_intr_remapping(struct intel_iommu *iommu, int mode) ++{ ++ struct ir_table *ir_table; ++ struct page *pages; ++ ++ ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table), ++ GFP_KERNEL); ++ ++ if (!iommu->ir_table) ++ return -ENOMEM; ++ ++ pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER); ++ ++ if (!pages) { ++ printk(KERN_ERR "failed to allocate pages of order %d\n", ++ INTR_REMAP_PAGE_ORDER); ++ kfree(iommu->ir_table); ++ return -ENOMEM; ++ } ++ ++ ir_table->base = page_address(pages); ++ ++ iommu_set_intr_remapping(iommu, mode); ++ return 0; ++} ++ ++int __init enable_intr_remapping(int eim) ++{ ++ struct dmar_drhd_unit *drhd; ++ int setup = 0; ++ ++ /* ++ * check for the Interrupt-remapping support ++ */ ++ for_each_drhd_unit(drhd) { ++ struct intel_iommu *iommu = drhd->iommu; ++ ++ if (!ecap_ir_support(iommu->ecap)) ++ continue; ++ ++ if (eim && !ecap_eim_support(iommu->ecap)) { ++ printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " ++ " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); ++ return -1; ++ } ++ } ++ ++ /* ++ * Enable queued invalidation for all the DRHD's. ++ */ ++ for_each_drhd_unit(drhd) { ++ int ret; ++ struct intel_iommu *iommu = drhd->iommu; ++ ret = dmar_enable_qi(iommu); ++ ++ if (ret) { ++ printk(KERN_ERR "DRHD %Lx: failed to enable queued, " ++ " invalidation, ecap %Lx, ret %d\n", ++ drhd->reg_base_addr, iommu->ecap, ret); ++ return -1; ++ } ++ } ++ ++ /* ++ * Setup Interrupt-remapping for all the DRHD's now. ++ */ ++ for_each_drhd_unit(drhd) { ++ struct intel_iommu *iommu = drhd->iommu; ++ ++ if (!ecap_ir_support(iommu->ecap)) ++ continue; ++ ++ if (setup_intr_remapping(iommu, eim)) ++ goto error; ++ ++ setup = 1; ++ } ++ ++ if (!setup) ++ goto error; ++ ++ intr_remapping_enabled = 1; ++ ++ return 0; ++ ++error: ++ /* ++ * handle error condition gracefully here! ++ */ ++ return -1; ++} + + static int ir_parse_ioapic_scope(struct acpi_dmar_header *header, + struct intel_iommu *iommu) +--- a/drivers/pci/intr_remapping.h ++++ b/drivers/pci/intr_remapping.h +@@ -4,3 +4,5 @@ struct ioapic_scope { + struct intel_iommu *iommu; + unsigned int id; + }; ++ ++#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) +--- a/include/linux/dmar.h ++++ b/include/linux/dmar.h +@@ -25,9 +25,85 @@ + #include + #include + +-#ifdef CONFIG_DMAR ++#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) + struct intel_iommu; + ++struct dmar_drhd_unit { ++ struct list_head list; /* list of drhd units */ ++ struct acpi_dmar_header *hdr; /* ACPI header */ ++ u64 reg_base_addr; /* register base address*/ ++ struct pci_dev **devices; /* target device array */ ++ int devices_cnt; /* target device count */ ++ u8 ignored:1; /* ignore drhd */ ++ u8 include_all:1; ++ struct intel_iommu *iommu; ++}; ++ ++extern struct list_head dmar_drhd_units; ++ ++#define for_each_drhd_unit(drhd) \ ++ list_for_each_entry(drhd, &dmar_drhd_units, list) ++ ++extern int dmar_table_init(void); ++extern int early_dmar_detect(void); ++extern int dmar_dev_scope_init(void); ++ ++/* Intel IOMMU detection */ ++extern void detect_intel_iommu(void); ++ ++ ++extern int parse_ioapics_under_ir(void); ++extern int alloc_iommu(struct dmar_drhd_unit *); ++#else ++static inline void detect_intel_iommu(void) ++{ ++ return; ++} ++ ++static inline int dmar_table_init(void) ++{ ++ return -ENODEV; ++} ++#endif /* !CONFIG_DMAR && !CONFIG_INTR_REMAP */ ++ ++#ifdef CONFIG_INTR_REMAP ++extern int intr_remapping_enabled; ++extern int enable_intr_remapping(int); ++ ++struct irte { ++ union { ++ struct { ++ __u64 present : 1, ++ fpd : 1, ++ dst_mode : 1, ++ redir_hint : 1, ++ trigger_mode : 1, ++ dlvry_mode : 3, ++ avail : 4, ++ __reserved_1 : 4, ++ vector : 8, ++ __reserved_2 : 8, ++ dest_id : 32; ++ }; ++ __u64 low; ++ }; ++ ++ union { ++ struct { ++ __u64 sid : 16, ++ sq : 2, ++ svt : 2, ++ __reserved_3 : 44; ++ }; ++ __u64 high; ++ }; ++}; ++#else ++#define enable_intr_remapping(mode) (-1) ++#define intr_remapping_enabled (0) ++#endif ++ ++#ifdef CONFIG_DMAR + extern const char *dmar_get_fault_reason(u8 fault_reason); + + /* Can't use the common MSI interrupt functions +@@ -40,29 +116,8 @@ extern void dmar_msi_write(int irq, stru + extern int dmar_set_interrupt(struct intel_iommu *iommu); + extern int arch_setup_dmar_msi(unsigned int irq); + +-/* Intel IOMMU detection and initialization functions */ +-extern void detect_intel_iommu(void); +-extern int intel_iommu_init(void); +- +-extern int dmar_table_init(void); +-extern int early_dmar_detect(void); +-extern int dmar_dev_scope_init(void); +-extern int parse_ioapics_under_ir(void); +- +-extern struct list_head dmar_drhd_units; ++extern int iommu_detected, no_iommu; + extern struct list_head dmar_rmrr_units; +- +-struct dmar_drhd_unit { +- struct list_head list; /* list of drhd units */ +- struct acpi_dmar_header *hdr; /* ACPI header */ +- u64 reg_base_addr; /* register base address*/ +- struct pci_dev **devices; /* target device array */ +- int devices_cnt; /* target device count */ +- u8 ignored:1; /* ignore drhd */ +- u8 include_all:1; +- struct intel_iommu *iommu; +-}; +- + struct dmar_rmrr_unit { + struct list_head list; /* list of rmrr units */ + struct acpi_dmar_header *hdr; /* ACPI header */ +@@ -72,24 +127,19 @@ struct dmar_rmrr_unit { + int devices_cnt; /* target device count */ + }; + +-#define for_each_drhd_unit(drhd) \ +- list_for_each_entry(drhd, &dmar_drhd_units, list) + #define for_each_rmrr_units(rmrr) \ + list_for_each_entry(rmrr, &dmar_rmrr_units, list) +- +-extern int alloc_iommu(struct dmar_drhd_unit *); ++/* Intel DMAR initialization functions */ ++extern int intel_iommu_init(void); ++extern int dmar_disabled; + #else +-static inline void detect_intel_iommu(void) +-{ +- return; +-} + static inline int intel_iommu_init(void) + { ++#ifdef CONFIG_INTR_REMAP ++ return dmar_dev_scope_init(); ++#else + return -ENODEV; +-} +-static inline int dmar_table_init(void) +-{ +- return -ENODEV; ++#endif + } + #endif /* !CONFIG_DMAR */ + #endif /* __DMAR_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_10_of_41_b6fcb33ad6c05f152a672f7c96c1fab006527b80 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_10_of_41_b6fcb33ad6c05f152a672f7c96c1fab006527b80 new file mode 100644 index 000000000..da3335558 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_10_of_41_b6fcb33ad6c05f152a672f7c96c1fab006527b80 @@ -0,0 +1,337 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: routines managing Interrupt remapping table entries. +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: b6fcb33ad6c05f152a672f7c96c1fab006527b80 + +Signed-off-by: Thomas Renninger + +Routines handling the management of interrupt remapping table entries. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/intel-iommu.h | 4 + drivers/pci/intr_remapping.c | 243 +++++++++++++++++++++++++++++++++++++++++++ + include/linux/dmar.h | 12 ++ + 3 files changed, 259 insertions(+) + +Index: linux-2.6.26/drivers/pci/intel-iommu.h +=================================================================== +--- linux-2.6.26.orig/drivers/pci/intel-iommu.h ++++ linux-2.6.26/drivers/pci/intel-iommu.h +@@ -123,6 +123,7 @@ static inline void dmar_writeq(void __io + #define ecap_qis(e) ((e) & 0x2) + #define ecap_eim_support(e) ((e >> 4) & 0x1) + #define ecap_ir_support(e) ((e >> 3) & 0x1) ++#define ecap_max_handle_mask(e) ((e >> 20) & 0xf) + + + /* IOTLB_REG */ +@@ -255,6 +256,8 @@ struct q_inval { + #define INTR_REMAP_PAGE_ORDER 8 + #define INTR_REMAP_TABLE_REG_SIZE 0xf + ++#define INTR_REMAP_TABLE_ENTRIES 65536 ++ + struct ir_table { + struct irte *base; + }; +@@ -300,4 +303,5 @@ extern void free_iommu(struct intel_iomm + extern int dmar_enable_qi(struct intel_iommu *iommu); + extern void qi_global_iec(struct intel_iommu *iommu); + ++extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu); + #endif +Index: linux-2.6.26/drivers/pci/intr_remapping.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/intr_remapping.c ++++ linux-2.6.26/drivers/pci/intr_remapping.c +@@ -2,6 +2,7 @@ + #include + #include + #include ++#include + #include + #include "intel-iommu.h" + #include "intr_remapping.h" +@@ -10,6 +11,248 @@ static struct ioapic_scope ir_ioapic[MAX + static int ir_ioapic_num; + int intr_remapping_enabled; + ++static struct { ++ struct intel_iommu *iommu; ++ u16 irte_index; ++ u16 sub_handle; ++ u8 irte_mask; ++} irq_2_iommu[NR_IRQS]; ++ ++static DEFINE_SPINLOCK(irq_2_ir_lock); ++ ++int irq_remapped(int irq) ++{ ++ if (irq > NR_IRQS) ++ return 0; ++ ++ if (!irq_2_iommu[irq].iommu) ++ return 0; ++ ++ return 1; ++} ++ ++int get_irte(int irq, struct irte *entry) ++{ ++ int index; ++ ++ if (!entry || irq > NR_IRQS) ++ return -1; ++ ++ spin_lock(&irq_2_ir_lock); ++ if (!irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle; ++ *entry = *(irq_2_iommu[irq].iommu->ir_table->base + index); ++ ++ spin_unlock(&irq_2_ir_lock); ++ return 0; ++} ++ ++int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) ++{ ++ struct ir_table *table = iommu->ir_table; ++ u16 index, start_index; ++ unsigned int mask = 0; ++ int i; ++ ++ if (!count) ++ return -1; ++ ++ /* ++ * start the IRTE search from index 0. ++ */ ++ index = start_index = 0; ++ ++ if (count > 1) { ++ count = __roundup_pow_of_two(count); ++ mask = ilog2(count); ++ } ++ ++ if (mask > ecap_max_handle_mask(iommu->ecap)) { ++ printk(KERN_ERR ++ "Requested mask %x exceeds the max invalidation handle" ++ " mask value %Lx\n", mask, ++ ecap_max_handle_mask(iommu->ecap)); ++ return -1; ++ } ++ ++ spin_lock(&irq_2_ir_lock); ++ do { ++ for (i = index; i < index + count; i++) ++ if (table->base[i].present) ++ break; ++ /* empty index found */ ++ if (i == index + count) ++ break; ++ ++ index = (index + count) % INTR_REMAP_TABLE_ENTRIES; ++ ++ if (index == start_index) { ++ spin_unlock(&irq_2_ir_lock); ++ printk(KERN_ERR "can't allocate an IRTE\n"); ++ return -1; ++ } ++ } while (1); ++ ++ for (i = index; i < index + count; i++) ++ table->base[i].present = 1; ++ ++ irq_2_iommu[irq].iommu = iommu; ++ irq_2_iommu[irq].irte_index = index; ++ irq_2_iommu[irq].sub_handle = 0; ++ irq_2_iommu[irq].irte_mask = mask; ++ ++ spin_unlock(&irq_2_ir_lock); ++ ++ return index; ++} ++ ++static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask) ++{ ++ struct qi_desc desc; ++ ++ desc.low = QI_IEC_IIDEX(index) | QI_IEC_TYPE | QI_IEC_IM(mask) ++ | QI_IEC_SELECTIVE; ++ desc.high = 0; ++ ++ qi_submit_sync(&desc, iommu); ++} ++ ++int map_irq_to_irte_handle(int irq, u16 *sub_handle) ++{ ++ int index; ++ ++ spin_lock(&irq_2_ir_lock); ++ if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ *sub_handle = irq_2_iommu[irq].sub_handle; ++ index = irq_2_iommu[irq].irte_index; ++ spin_unlock(&irq_2_ir_lock); ++ return index; ++} ++ ++int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) ++{ ++ spin_lock(&irq_2_ir_lock); ++ if (irq >= NR_IRQS || irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ irq_2_iommu[irq].iommu = iommu; ++ irq_2_iommu[irq].irte_index = index; ++ irq_2_iommu[irq].sub_handle = subhandle; ++ irq_2_iommu[irq].irte_mask = 0; ++ ++ spin_unlock(&irq_2_ir_lock); ++ ++ return 0; ++} ++ ++int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index) ++{ ++ spin_lock(&irq_2_ir_lock); ++ if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ irq_2_iommu[irq].iommu = NULL; ++ irq_2_iommu[irq].irte_index = 0; ++ irq_2_iommu[irq].sub_handle = 0; ++ irq_2_iommu[irq].irte_mask = 0; ++ ++ spin_unlock(&irq_2_ir_lock); ++ ++ return 0; ++} ++ ++int modify_irte(int irq, struct irte *irte_modified) ++{ ++ int index; ++ struct irte *irte; ++ struct intel_iommu *iommu; ++ ++ spin_lock(&irq_2_ir_lock); ++ if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ iommu = irq_2_iommu[irq].iommu; ++ ++ index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle; ++ irte = &iommu->ir_table->base[index]; ++ ++ set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1)); ++ __iommu_flush_cache(iommu, irte, sizeof(*irte)); ++ ++ qi_flush_iec(iommu, index, 0); ++ ++ spin_unlock(&irq_2_ir_lock); ++ return 0; ++} ++ ++int flush_irte(int irq) ++{ ++ int index; ++ struct intel_iommu *iommu; ++ ++ spin_lock(&irq_2_ir_lock); ++ if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ iommu = irq_2_iommu[irq].iommu; ++ ++ index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle; ++ ++ qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask); ++ spin_unlock(&irq_2_ir_lock); ++ ++ return 0; ++} ++ ++int free_irte(int irq) ++{ ++ int index, i; ++ struct irte *irte; ++ struct intel_iommu *iommu; ++ ++ spin_lock(&irq_2_ir_lock); ++ if (irq >= NR_IRQS || !irq_2_iommu[irq].iommu) { ++ spin_unlock(&irq_2_ir_lock); ++ return -1; ++ } ++ ++ iommu = irq_2_iommu[irq].iommu; ++ ++ index = irq_2_iommu[irq].irte_index + irq_2_iommu[irq].sub_handle; ++ irte = &iommu->ir_table->base[index]; ++ ++ if (!irq_2_iommu[irq].sub_handle) { ++ for (i = 0; i < (1 << irq_2_iommu[irq].irte_mask); i++) ++ set_64bit((unsigned long *)irte, 0); ++ qi_flush_iec(iommu, index, irq_2_iommu[irq].irte_mask); ++ } ++ ++ irq_2_iommu[irq].iommu = NULL; ++ irq_2_iommu[irq].irte_index = 0; ++ irq_2_iommu[irq].sub_handle = 0; ++ irq_2_iommu[irq].irte_mask = 0; ++ ++ spin_unlock(&irq_2_ir_lock); ++ ++ return 0; ++} ++ + static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode) + { + u64 addr; +Index: linux-2.6.26/include/linux/dmar.h +=================================================================== +--- linux-2.6.26.orig/include/linux/dmar.h ++++ linux-2.6.26/include/linux/dmar.h +@@ -98,7 +98,19 @@ struct irte { + __u64 high; + }; + }; ++extern int get_irte(int irq, struct irte *entry); ++extern int modify_irte(int irq, struct irte *irte_modified); ++extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count); ++extern int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, ++ u16 sub_handle); ++extern int map_irq_to_irte_handle(int irq, u16 *sub_handle); ++extern int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index); ++extern int flush_irte(int irq); ++extern int free_irte(int irq); ++ ++extern int irq_remapped(int irq); + #else ++#define irq_remapped(irq) (0) + #define enable_intr_remapping(mode) (-1) + #define intr_remapping_enabled (0) + #endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_11_of_41_72b1e22dfcad1daca6906148fd956ffe404bb0bc b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_11_of_41_72b1e22dfcad1daca6906148fd956ffe404bb0bc new file mode 100644 index 000000000..2a0ed2807 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_11_of_41_72b1e22dfcad1daca6906148fd956ffe404bb0bc @@ -0,0 +1,60 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: generic irq migration support from process context +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 72b1e22dfcad1daca6906148fd956ffe404bb0bc + +Signed-off-by: Thomas Renninger + +Generic infrastructure for migrating the irq from the process context in the +presence of CONFIG_GENERIC_PENDING_IRQ. + +This will be used later for migrating irq in the presence of +interrupt-remapping. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + include/linux/irq.h | 1 + + kernel/irq/manage.c | 9 ++++++++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +Index: linux-2.6.26/include/linux/irq.h +=================================================================== +--- linux-2.6.26.orig/include/linux/irq.h ++++ linux-2.6.26/include/linux/irq.h +@@ -62,6 +62,7 @@ typedef void (*irq_flow_handler_t)(unsig + #define IRQ_MOVE_PENDING 0x00200000 /* need to re-target IRQ destination */ + #define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */ + #define IRQ_SPURIOUS_DISABLED 0x00800000 /* IRQ was disabled by the spurious trap */ ++#define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */ + + #ifdef CONFIG_IRQ_PER_CPU + # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) +Index: linux-2.6.26/kernel/irq/manage.c +=================================================================== +--- linux-2.6.26.orig/kernel/irq/manage.c ++++ linux-2.6.26/kernel/irq/manage.c +@@ -89,7 +89,14 @@ int irq_set_affinity(unsigned int irq, c + set_balance_irq_affinity(irq, cpumask); + + #ifdef CONFIG_GENERIC_PENDING_IRQ +- set_pending_irq(irq, cpumask); ++ if (desc->status & IRQ_MOVE_PCNTXT) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&desc->lock, flags); ++ desc->chip->set_affinity(irq, cpumask); ++ spin_unlock_irqrestore(&desc->lock, flags); ++ } else ++ set_pending_irq(irq, cpumask); + #else + desc->affinity = cpumask; + desc->chip->set_affinity(irq, cpumask); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_12_of_41_d94d93ca5cc36cd78c532def62772c98fe8ba5d7 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_12_of_41_d94d93ca5cc36cd78c532def62772c98fe8ba5d7 new file mode 100644 index 000000000..988fd5177 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_12_of_41_d94d93ca5cc36cd78c532def62772c98fe8ba5d7 @@ -0,0 +1,72 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: 8259 specific mask/unmask routines +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: d94d93ca5cc36cd78c532def62772c98fe8ba5d7 + +Signed-off-by: Thomas Renninger + +8259 specific mask/unmask routines which be used later while enabling +interrupt-remapping. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/i8259.c | 24 ++++++++++++++++++++++++ + include/asm-x86/i8259.h | 3 +++ + 2 files changed, 27 insertions(+) + +Index: linux-2.6.26/arch/x86/kernel/i8259.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/i8259.c ++++ linux-2.6.26/arch/x86/kernel/i8259.c +@@ -282,6 +282,30 @@ static int __init i8259A_init_sysfs(void + + device_initcall(i8259A_init_sysfs); + ++void mask_8259A(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&i8259A_lock, flags); ++ ++ outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ ++ outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ ++ ++ spin_unlock_irqrestore(&i8259A_lock, flags); ++} ++ ++void unmask_8259A(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&i8259A_lock, flags); ++ ++ outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ ++ outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ ++ ++ spin_unlock_irqrestore(&i8259A_lock, flags); ++} ++ + void init_8259A(int auto_eoi) + { + unsigned long flags; +Index: linux-2.6.26/include/asm-x86/i8259.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/i8259.h ++++ linux-2.6.26/include/asm-x86/i8259.h +@@ -57,4 +57,7 @@ static inline void outb_pic(unsigned cha + + extern struct irq_chip i8259A_chip; + ++extern void mask_8259A(void); ++extern void unmask_8259A(void); ++ + #endif /* __ASM_I8259_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_13_of_41_4dc2f96cacd1e74c688f94348a3bfd0a980817d5 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_13_of_41_4dc2f96cacd1e74c688f94348a3bfd0a980817d5 new file mode 100644 index 000000000..d956c4d00 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_13_of_41_4dc2f96cacd1e74c688f94348a3bfd0a980817d5 @@ -0,0 +1,126 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: ioapic routines which deal with initial io-apic RTE setup +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 4dc2f96cacd1e74c688f94348a3bfd0a980817d5 + +Signed-off-by: Thomas Renninger + +Generic ioapic specific routines which be used later during enabling +interrupt-remapping. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/io_apic_64.c | 66 +++++++++++++++++++++++++++++++++++++++++++ + include/asm-x86/io_apic.h | 6 +++ + 2 files changed, 72 insertions(+) + +Index: linux-2.6.26/arch/x86/kernel/io_apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/io_apic_64.c ++++ linux-2.6.26/arch/x86/kernel/io_apic_64.c +@@ -108,6 +108,9 @@ static DEFINE_SPINLOCK(vector_lock); + */ + int nr_ioapic_registers[MAX_IO_APICS]; + ++/* I/O APIC RTE contents at the OS boot up */ ++struct IO_APIC_route_entry *early_ioapic_entries[MAX_IO_APICS]; ++ + /* I/O APIC entries */ + struct mp_config_ioapic mp_ioapics[MAX_IO_APICS]; + int nr_ioapics; +@@ -440,6 +443,69 @@ static void clear_IO_APIC (void) + clear_IO_APIC_pin(apic, pin); + } + ++/* ++ * Saves and masks all the unmasked IO-APIC RTE's ++ */ ++int save_mask_IO_APIC_setup(void) ++{ ++ union IO_APIC_reg_01 reg_01; ++ unsigned long flags; ++ int apic, pin; ++ ++ /* ++ * The number of IO-APIC IRQ registers (== #pins): ++ */ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ spin_lock_irqsave(&ioapic_lock, flags); ++ reg_01.raw = io_apic_read(apic, 1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ nr_ioapic_registers[apic] = reg_01.bits.entries+1; ++ } ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ early_ioapic_entries[apic] = ++ kzalloc(sizeof(struct IO_APIC_route_entry) * ++ nr_ioapic_registers[apic], GFP_KERNEL); ++ if (!early_ioapic_entries[apic]) ++ return -ENOMEM; ++ } ++ ++ for (apic = 0; apic < nr_ioapics; apic++) ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ struct IO_APIC_route_entry entry; ++ ++ entry = early_ioapic_entries[apic][pin] = ++ ioapic_read_entry(apic, pin); ++ if (!entry.mask) { ++ entry.mask = 1; ++ ioapic_write_entry(apic, pin, entry); ++ } ++ } ++ return 0; ++} ++ ++void restore_IO_APIC_setup(void) ++{ ++ int apic, pin; ++ ++ for (apic = 0; apic < nr_ioapics; apic++) ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) ++ ioapic_write_entry(apic, pin, ++ early_ioapic_entries[apic][pin]); ++} ++ ++void reinit_intr_remapped_IO_APIC(int intr_remapping) ++{ ++ /* ++ * for now plain restore of previous settings. ++ * TBD: In the case of OS enabling interrupt-remapping, ++ * IO-APIC RTE's need to be setup to point to interrupt-remapping ++ * table entries. for now, do a plain restore, and wait for ++ * the setup_IO_APIC_irqs() to do proper initialization. ++ */ ++ restore_IO_APIC_setup(); ++} ++ + int skip_ioapic_setup; + int ioapic_force; + +Index: linux-2.6.26/include/asm-x86/io_apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/io_apic.h ++++ linux-2.6.26/include/asm-x86/io_apic.h +@@ -193,6 +193,12 @@ extern int io_apic_set_pci_routing(int i + extern int (*ioapic_renumber_irq)(int ioapic, int irq); + extern void ioapic_init_mappings(void); + ++#ifdef CONFIG_X86_64 ++extern int save_mask_IO_APIC_setup(void); ++extern void restore_IO_APIC_setup(void); ++extern void reinit_intr_remapped_IO_APIC(int); ++#endif ++ + #else /* !CONFIG_X86_IO_APIC */ + #define io_apic_assign_pci_irqs 0 + static const int timer_through_8259 = 0; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_14_of_41_0c81c746f9bdbfaafe64322d540c8b7b59c27314 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_14_of_41_0c81c746f9bdbfaafe64322d540c8b7b59c27314 new file mode 100644 index 000000000..348ebc9dc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_14_of_41_0c81c746f9bdbfaafe64322d540c8b7b59c27314 @@ -0,0 +1,215 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: introduce read_apic_id() to genapic routines +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 0c81c746f9bdbfaafe64322d540c8b7b59c27314 + +Signed-off-by: Thomas Renninger + +Move the read_apic_id() to genapic routines. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_64.c | 5 +++++ + arch/x86/kernel/genapic_64.c | 11 ----------- + arch/x86/kernel/genapic_flat_64.c | 14 +++++++++++++- + arch/x86/kernel/genx2apic_uv_x.c | 14 +++++++++++++- + include/asm-x86/genapic_64.h | 1 + + include/asm-x86/mach-default/mach_apic.h | 1 + + include/asm-x86/mach-default/mach_apicdef.h | 3 ++- + include/asm-x86/smp.h | 4 +--- + 8 files changed, 36 insertions(+), 17 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_64.c ++++ linux-2.6.26/arch/x86/kernel/apic_64.c +@@ -1095,6 +1095,11 @@ void __cpuinit generic_processor_info(in + cpu_set(cpu, cpu_present_map); + } + ++int hard_smp_processor_id(void) ++{ ++ return read_apic_id(); ++} ++ + /* + * Power management + */ +Index: linux-2.6.26/arch/x86/kernel/genapic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_64.c +@@ -79,17 +79,6 @@ int __init acpi_madt_oem_check(char *oem + return 0; + } + +-unsigned int read_apic_id(void) +-{ +- unsigned int id; +- +- WARN_ON(preemptible() && num_online_cpus() > 1); +- id = apic_read(APIC_ID); +- if (uv_system_type >= UV_X2APIC) +- id |= __get_cpu_var(x2apic_extra_bits); +- return id; +-} +- + enum uv_system_type get_uv_system_type(void) + { + return uv_system_type; +Index: linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_flat_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +@@ -15,9 +15,11 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + + static cpumask_t flat_target_cpus(void) + { +@@ -95,9 +97,17 @@ static void flat_send_IPI_all(int vector + __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); + } + ++static unsigned int read_xapic_id(void) ++{ ++ unsigned int id; ++ ++ id = GET_XAPIC_ID(apic_read(APIC_ID)); ++ return id; ++} ++ + static int flat_apic_id_registered(void) + { +- return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map); ++ return physid_isset(read_xapic_id(), phys_cpu_present_map); + } + + static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask) +@@ -123,6 +133,7 @@ struct genapic apic_flat = { + .send_IPI_mask = flat_send_IPI_mask, + .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, ++ .read_apic_id = read_xapic_id, + }; + + /* +@@ -187,4 +198,5 @@ struct genapic apic_physflat = { + .send_IPI_mask = physflat_send_IPI_mask, + .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, ++ .read_apic_id = read_xapic_id, + }; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -138,9 +139,19 @@ static unsigned int uv_cpu_mask_to_apici + return BAD_APICID; + } + ++static unsigned int uv_read_apic_id(void) ++{ ++ unsigned int id; ++ ++ WARN_ON(preemptible() && num_online_cpus() > 1); ++ id = apic_read(APIC_ID) | __get_cpu_var(x2apic_extra_bits); ++ ++ return id; ++} ++ + static unsigned int phys_pkg_id(int index_msb) + { +- return GET_APIC_ID(read_apic_id()) >> index_msb; ++ return uv_read_apic_id() >> index_msb; + } + + #ifdef ZZZ /* Needs x2apic patch */ +@@ -163,6 +174,7 @@ struct genapic apic_x2apic_uv_x = { + /* ZZZ.send_IPI_self = uv_send_IPI_self, */ + .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ ++ .read_apic_id = uv_read_apic_id, + }; + + static __cpuinit void set_x2apic_extra_bits(int pnode) +Index: linux-2.6.26/include/asm-x86/genapic_64.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/genapic_64.h ++++ linux-2.6.26/include/asm-x86/genapic_64.h +@@ -27,6 +27,7 @@ struct genapic { + /* */ + unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask); + unsigned int (*phys_pkg_id)(int index_msb); ++ unsigned int (*read_apic_id)(void); + }; + + extern struct genapic *genapic; +Index: linux-2.6.26/include/asm-x86/mach-default/mach_apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/mach-default/mach_apic.h ++++ linux-2.6.26/include/asm-x86/mach-default/mach_apic.h +@@ -30,6 +30,7 @@ static inline cpumask_t target_cpus(void + #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) + #define phys_pkg_id (genapic->phys_pkg_id) + #define vector_allocation_domain (genapic->vector_allocation_domain) ++#define read_apic_id (genapic->read_apic_id) + extern void setup_apic_routing(void); + #else + #define INT_DELIVERY_MODE dest_LowestPrio +Index: linux-2.6.26/include/asm-x86/mach-default/mach_apicdef.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/mach-default/mach_apicdef.h ++++ linux-2.6.26/include/asm-x86/mach-default/mach_apicdef.h +@@ -5,8 +5,9 @@ + + #ifdef CONFIG_X86_64 + #define APIC_ID_MASK (0xFFu<<24) +-#define GET_APIC_ID(x) (((x)>>24)&0xFFu) ++#define GET_APIC_ID(x) (x) + #define SET_APIC_ID(x) (((x)<<24)) ++#define GET_XAPIC_ID(x) (((x) >> 24) & 0xFFu) + #else + #define APIC_ID_MASK (0xF<<24) + static inline unsigned get_apic_id(unsigned long x) +Index: linux-2.6.26/include/asm-x86/smp.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/smp.h ++++ linux-2.6.26/include/asm-x86/smp.h +@@ -176,12 +176,10 @@ static inline unsigned int read_apic_id( + { + return *(u32 *)(APIC_BASE + APIC_ID); + } +-#else +-extern unsigned int read_apic_id(void); + #endif + + +-# ifdef APIC_DEFINITION ++# if defined(APIC_DEFINITION) || defined(CONFIG_X86_64) + extern int hard_smp_processor_id(void); + # else + # include diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_15_of_41_2d7a66d02e11af9ab8e16c76d22767e622b4e3d7 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_15_of_41_2d7a66d02e11af9ab8e16c76d22767e622b4e3d7 new file mode 100644 index 000000000..4b1144baf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_15_of_41_2d7a66d02e11af9ab8e16c76d22767e622b4e3d7 @@ -0,0 +1,78 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: Interrupt-remapping and x2apic support, fix +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 2d7a66d02e11af9ab8e16c76d22767e622b4e3d7 + +Signed-off-by: Thomas Renninger + +Yinghai Lu wrote: + +> Setting APIC routing to physical flat +> Kernel panic - not syncing: Boot APIC ID in local APIC unexpected (0 vs 4) +> Pid: 1, comm: swapper Not tainted 2.6.26-rc9-tip-01763-g74f94b1-dirty #320 +> +> Call Trace: +> [] ? set_cpu_sibling_map+0x38c/0x3bd +> [] ? read_xapic_id+0x25/0x3e +> [] ? verify_local_APIC+0x139/0x1b9 +> [] ? read_xapic_id+0x25/0x3e +> [] ? native_smp_prepare_cpus+0x224/0x2e9 +> [] ? kernel_init+0x64/0x341 +> [] ? child_rip+0xa/0x11 +> [] ? kernel_init+0x0/0x341 +> [] ? child_rip+0x0/0x11 +> +> +> guess read_apic_id changing cuase some problem... + +genapic's read_apic_id() returns the actual apic id extracted from +the APIC_ID register. And in some cases like UV, read_apic_id() +returns completely different values from APIC ID register. + +Use the native apic register read, rather than genapic read_apic_id() +in verify_local_APIC() + +And also, lapic_suspend() should also use native apic register read. + +Reported-by: Yinghai Lu +Signed-off-by: Suresh Siddha +Cc: "akpm@linux-foundation.org" +Cc: "arjan@linux.intel.com" +Cc: "andi@firstfloor.org" +Cc: "ebiederm@xmission.com" +Cc: "jbarnes@virtuousgeek.org" +Cc: "steiner@sgi.com" +Cc: "jeremy@goop.org" +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_64.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_64.c ++++ linux-2.6.26/arch/x86/kernel/apic_64.c +@@ -629,10 +629,10 @@ int __init verify_local_APIC(void) + /* + * The ID register is read/write in a real APIC. + */ +- reg0 = read_apic_id(); ++ reg0 = apic_read(APIC_ID); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0); + apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); +- reg1 = read_apic_id(); ++ reg1 = apic_read(APIC_ID); + apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1); + apic_write(APIC_ID, reg0); + if (reg1 != (reg0 ^ APIC_ID_MASK)) +@@ -1136,7 +1136,7 @@ static int lapic_suspend(struct sys_devi + + maxlvt = lapic_get_maxlvt(); + +- apic_pm_state.apic_id = read_apic_id(); ++ apic_pm_state.apic_id = apic_read(APIC_ID); + apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); + apic_pm_state.apic_ldr = apic_read(APIC_LDR); + apic_pm_state.apic_dfr = apic_read(APIC_DFR); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_16_of_41_1b374e4d6f8b3eb2fcd034fcc24ea8ba1dfde7aa b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_16_of_41_1b374e4d6f8b3eb2fcd034fcc24ea8ba1dfde7aa new file mode 100644 index 000000000..68c169d64 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_16_of_41_1b374e4d6f8b3eb2fcd034fcc24ea8ba1dfde7aa @@ -0,0 +1,403 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: basic apic ops support +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 1b374e4d6f8b3eb2fcd034fcc24ea8ba1dfde7aa + +Signed-off-by: Thomas Renninger + +Introduce basic apic operations which handle the apic programming. This +will be used later to introduce another specific operations for x2apic. + +For the perfomance critial accesses like IPI's, EOI etc, we use the +native operations as they are already referenced by different +indirections like genapic, irq_chip etc. + +64bit Paravirt ops can also define their apic operations accordingly. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_32.c | 6 ++++++ + arch/x86/kernel/apic_64.c | 33 +++++++++++++++++++++++++++++++-- + arch/x86/kernel/io_apic_64.c | 8 ++++---- + arch/x86/kernel/paravirt.c | 6 ++++-- + arch/x86/kernel/smpboot.c | 36 ++++++++++++++---------------------- + include/asm-x86/apic.h | 35 +++++++++++++++++++++++++++++++---- + include/asm-x86/ipi.h | 16 +++++++++++----- + include/asm-x86/paravirt.h | 2 ++ + include/asm-x86/smp.h | 2 +- + 9 files changed, 104 insertions(+), 40 deletions(-) + +--- a/arch/x86/kernel/apic_32.c ++++ b/arch/x86/kernel/apic_32.c +@@ -145,6 +145,12 @@ static int modern_apic(void) + return lapic_get_version() >= 0x14; + } + ++void apic_icr_write(u32 low, u32 id) ++{ ++ apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id)); ++ apic_write(APIC_ICR, low); ++} ++ + void apic_wait_icr_idle(void) + { + while (apic_read(APIC_ICR) & APIC_ICR_BUSY) +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -118,13 +118,13 @@ static int modern_apic(void) + return lapic_get_version() >= 0x14; + } + +-void apic_wait_icr_idle(void) ++void xapic_wait_icr_idle(void) + { + while (apic_read(APIC_ICR) & APIC_ICR_BUSY) + cpu_relax(); + } + +-u32 safe_apic_wait_icr_idle(void) ++u32 safe_xapic_wait_icr_idle(void) + { + u32 send_status; + int timeout; +@@ -140,6 +140,35 @@ u32 safe_apic_wait_icr_idle(void) + return send_status; + } + ++void xapic_icr_write(u32 low, u32 id) ++{ ++ apic_write(APIC_ICR2, id << 24); ++ apic_write(APIC_ICR, low); ++} ++ ++u64 xapic_icr_read(void) ++{ ++ u32 icr1, icr2; ++ ++ icr2 = apic_read(APIC_ICR2); ++ icr1 = apic_read(APIC_ICR); ++ ++ return (icr1 | ((u64)icr2 << 32)); ++} ++ ++static struct apic_ops xapic_ops = { ++ .read = native_apic_mem_read, ++ .write = native_apic_mem_write, ++ .icr_read = xapic_icr_read, ++ .icr_write = xapic_icr_write, ++ .wait_icr_idle = xapic_wait_icr_idle, ++ .safe_wait_icr_idle = safe_xapic_wait_icr_idle, ++}; ++ ++struct apic_ops __read_mostly *apic_ops = &xapic_ops; ++ ++EXPORT_SYMBOL_GPL(apic_ops); ++ + /** + * enable_NMI_through_LVT0 - enable NMI through local vector table 0 + */ +--- a/arch/x86/kernel/io_apic_64.c ++++ b/arch/x86/kernel/io_apic_64.c +@@ -1156,6 +1156,7 @@ static __apicdebuginit void print_APIC_b + void __apicdebuginit print_local_APIC(void * dummy) + { + unsigned int v, ver, maxlvt; ++ unsigned long icr; + + if (apic_verbosity == APIC_QUIET) + return; +@@ -1199,10 +1200,9 @@ void __apicdebuginit print_local_APIC(vo + v = apic_read(APIC_ESR); + printk(KERN_DEBUG "... APIC ESR: %08x\n", v); + +- v = apic_read(APIC_ICR); +- printk(KERN_DEBUG "... APIC ICR: %08x\n", v); +- v = apic_read(APIC_ICR2); +- printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); ++ icr = apic_icr_read(); ++ printk(KERN_DEBUG "... APIC ICR: %08x\n", icr); ++ printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32); + + v = apic_read(APIC_LVTT); + printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -373,8 +373,10 @@ struct pv_cpu_ops pv_cpu_ops = { + + struct pv_apic_ops pv_apic_ops = { + #ifdef CONFIG_X86_LOCAL_APIC +- .apic_write = native_apic_write, +- .apic_read = native_apic_read, ++#ifndef CONFIG_X86_64 ++ .apic_write = native_apic_mem_write, ++ .apic_read = native_apic_mem_read, ++#endif + .setup_boot_clock = setup_boot_APIC_clock, + .setup_secondary_clock = setup_secondary_APIC_clock, + .startup_ipi_hook = paravirt_nop, +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -123,7 +123,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_info); + + static atomic_t init_deasserted; + +-static int boot_cpu_logical_apicid; + + /* representing cpus for which sibling maps can be computed */ + static cpumask_t cpu_sibling_setup_map; +@@ -165,6 +164,8 @@ static void unmap_cpu_to_node(int cpu) + #endif + + #ifdef CONFIG_X86_32 ++static int boot_cpu_logical_apicid; ++ + u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = + { [0 ... NR_CPUS-1] = BAD_APICID }; + +@@ -548,8 +549,7 @@ static inline void __inquire_remote_apic + printk(KERN_CONT + "a previous APIC delivery may have failed\n"); + +- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); +- apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]); ++ apic_icr_write(APIC_DM_REMRD | regs[i], apicid); + + timeout = 0; + do { +@@ -580,12 +580,7 @@ wakeup_secondary_cpu(int logical_apicid, + unsigned long send_status, accept_status = 0; + int maxlvt; + +- /* Target chip */ +- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid)); +- +- /* Boot on the stack */ +- /* Kick the second */ +- apic_write(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL); ++ apic_icr_write(APIC_DM_NMI | APIC_DEST_LOGICAL, logical_apicid); + + pr_debug("Waiting for send to finish...\n"); + send_status = safe_apic_wait_icr_idle(); +@@ -635,16 +630,14 @@ wakeup_secondary_cpu(int phys_apicid, un + + pr_debug("Asserting INIT.\n"); + +- /* +- * Turn INIT on target chip +- */ +- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); +- ++ /* ++ * Turn INIT on target chip ++ */ + /* + * Send IPI + */ +- apic_write(APIC_ICR, +- APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); ++ apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT, ++ phys_apicid); + + pr_debug("Waiting for send to finish...\n"); + send_status = safe_apic_wait_icr_idle(); +@@ -654,10 +647,8 @@ wakeup_secondary_cpu(int phys_apicid, un + pr_debug("Deasserting INIT.\n"); + + /* Target chip */ +- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); +- + /* Send IPI */ +- apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); ++ apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid); + + pr_debug("Waiting for send to finish...\n"); + send_status = safe_apic_wait_icr_idle(); +@@ -700,11 +691,10 @@ wakeup_secondary_cpu(int phys_apicid, un + */ + + /* Target chip */ +- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); +- + /* Boot on the stack */ + /* Kick the second */ +- apic_write(APIC_ICR, APIC_DM_STARTUP | (start_eip >> 12)); ++ apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12), ++ phys_apicid); + + /* + * Give the other CPU some time to accept the IPI. +@@ -1173,7 +1163,9 @@ void __init native_smp_prepare_cpus(unsi + * Setup boot CPU information + */ + smp_store_cpu_info(0); /* Final full version of the data */ ++#ifdef CONFIG_X86_32 + boot_cpu_logical_apicid = logical_smp_processor_id(); ++#endif + current_thread_info()->cpu = 0; /* needed? */ + set_cpu_sibling_map(0); + +--- a/include/asm-x86/apic.h ++++ b/include/asm-x86/apic.h +@@ -47,15 +47,17 @@ extern int disable_apic; + #ifdef CONFIG_PARAVIRT + #include + #else +-#define apic_write native_apic_write +-#define apic_read native_apic_read ++#ifndef CONFIG_X86_64 ++#define apic_write native_apic_mem_write ++#define apic_read native_apic_mem_read ++#endif + #define setup_boot_clock setup_boot_APIC_clock + #define setup_secondary_clock setup_secondary_APIC_clock + #endif + + extern int is_vsmp_box(void); + +-static inline void native_apic_write(unsigned long reg, u32 v) ++static inline void native_apic_mem_write(u32 reg, u32 v) + { + volatile u32 *addr = (volatile u32 *)(APIC_BASE + reg); + +@@ -64,13 +66,38 @@ static inline void native_apic_write(uns + ASM_OUTPUT2("0" (v), "m" (*addr))); + } + +-static inline u32 native_apic_read(unsigned long reg) ++static inline u32 native_apic_mem_read(u32 reg) + { + return *((volatile u32 *)(APIC_BASE + reg)); + } + ++#ifdef CONFIG_X86_32 + extern void apic_wait_icr_idle(void); + extern u32 safe_apic_wait_icr_idle(void); ++extern void apic_icr_write(u32 low, u32 id); ++#else ++ ++struct apic_ops { ++ u32 (*read)(u32 reg); ++ void (*write)(u32 reg, u32 v); ++ void (*write_atomic)(u32 reg, u32 v); ++ u64 (*icr_read)(void); ++ void (*icr_write)(u32 low, u32 high); ++ void (*wait_icr_idle)(void); ++ u32 (*safe_wait_icr_idle)(void); ++}; ++ ++extern struct apic_ops *apic_ops; ++ ++#define apic_read (apic_ops->read) ++#define apic_write (apic_ops->write) ++#define apic_write_atomic (apic_ops->write_atomic) ++#define apic_icr_read (apic_ops->icr_read) ++#define apic_icr_write (apic_ops->icr_write) ++#define apic_wait_icr_idle (apic_ops->wait_icr_idle) ++#define safe_apic_wait_icr_idle (apic_ops->safe_wait_icr_idle) ++#endif ++ + extern int get_physical_broadcast(void); + + static inline void ack_APIC_irq(void) +--- a/include/asm-x86/ipi.h ++++ b/include/asm-x86/ipi.h +@@ -49,6 +49,12 @@ static inline int __prepare_ICR2(unsigne + return SET_APIC_DEST_FIELD(mask); + } + ++static inline void __xapic_wait_icr_idle(void) ++{ ++ while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY) ++ cpu_relax(); ++} ++ + static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, + unsigned int dest) + { +@@ -64,7 +70,7 @@ static inline void __send_IPI_shortcut(u + /* + * Wait for idle. + */ +- apic_wait_icr_idle(); ++ __xapic_wait_icr_idle(); + + /* + * No need to touch the target chip field +@@ -74,7 +80,7 @@ static inline void __send_IPI_shortcut(u + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ +- apic_write(APIC_ICR, cfg); ++ native_apic_mem_write(APIC_ICR, cfg); + } + + /* +@@ -92,13 +98,13 @@ static inline void __send_IPI_dest_field + if (unlikely(vector == NMI_VECTOR)) + safe_apic_wait_icr_idle(); + else +- apic_wait_icr_idle(); ++ __xapic_wait_icr_idle(); + + /* + * prepare target chip field + */ + cfg = __prepare_ICR2(mask); +- apic_write(APIC_ICR2, cfg); ++ native_apic_mem_write(APIC_ICR2, cfg); + + /* + * program the ICR +@@ -108,7 +114,7 @@ static inline void __send_IPI_dest_field + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ +- apic_write(APIC_ICR, cfg); ++ native_apic_mem_write(APIC_ICR, cfg); + } + + static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) +--- a/include/asm-x86/paravirt.h ++++ b/include/asm-x86/paravirt.h +@@ -901,6 +901,7 @@ static inline void slow_down_io(void) + /* + * Basic functions accessing APICs. + */ ++#ifndef CONFIG_X86_64 + static inline void apic_write(unsigned long reg, u32 v) + { + PVOP_VCALL2(pv_apic_ops.apic_write, reg, v); +@@ -910,6 +911,7 @@ static inline u32 apic_read(unsigned lon + { + return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg); + } ++#endif + + static inline void setup_boot_clock(void) + { +--- a/include/asm-x86/smp.h ++++ b/include/asm-x86/smp.h +@@ -165,13 +165,13 @@ extern int safe_smp_processor_id(void); + + #ifdef CONFIG_X86_LOCAL_APIC + ++#ifndef CONFIG_X86_64 + static inline int logical_smp_processor_id(void) + { + /* we don't want to mark this access volatile - bad code generation */ + return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR)); + } + +-#ifndef CONFIG_X86_64 + static inline unsigned int read_apic_id(void) + { + return *(u32 *)(APIC_BASE + APIC_ID); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_17_of_41_32e1d0a0651004f5fe47f85a2a5c725ad579a90c b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_17_of_41_32e1d0a0651004f5fe47f85a2a5c725ad579a90c new file mode 100644 index 000000000..4a6e12396 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_17_of_41_32e1d0a0651004f5fe47f85a2a5c725ad579a90c @@ -0,0 +1,53 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: cpuid bits for x2apic feature +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 32e1d0a0651004f5fe47f85a2a5c725ad579a90c + +Signed-off-by: Thomas Renninger + +cpuid feature for x2apic. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/cpu/feature_names.c | 2 +- + include/asm-x86/cpufeature.h | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/arch/x86/kernel/cpu/feature_names.c ++++ b/arch/x86/kernel/cpu/feature_names.c +@@ -46,7 +46,7 @@ const char * const x86_cap_flags[NCAPINT + /* Intel-defined (#2) */ + "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", + "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, +- NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt", ++ NULL, NULL, "dca", "sse4_1", "sse4_2", "x2apic", NULL, "popcnt", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* VIA/Cyrix/Centaur-defined */ +--- a/include/asm-x86/cpufeature.h ++++ b/include/asm-x86/cpufeature.h +@@ -94,6 +94,7 @@ + #define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */ + #define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ + #define X86_FEATURE_XMM4_2 (4*32+20) /* Streaming SIMD Extensions-4.2 */ ++#define X86_FEATURE_X2APIC (4*32+21) /* x2APIC */ + + /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ + #define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ +@@ -193,6 +194,7 @@ extern const char * const x86_power_flag + #define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON) + #define cpu_has_pat boot_cpu_has(X86_FEATURE_PAT) + #define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2) ++#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC) + + #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) + # define cpu_has_invlpg 1 diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_18_of_41_1cb11583a6c4ceda7426eb36f7bf0419da8dfbc2 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_18_of_41_1cb11583a6c4ceda7426eb36f7bf0419da8dfbc2 new file mode 100644 index 000000000..d424d1492 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_18_of_41_1cb11583a6c4ceda7426eb36f7bf0419da8dfbc2 @@ -0,0 +1,72 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: disable DMA-remapping if Interrupt-remapping is detected (temporary quirk) +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 1cb11583a6c4ceda7426eb36f7bf0419da8dfbc2 + +Signed-off-by: Thomas Renninger + +Interrupt-remapping enables queued invalidation. And once queued invalidation +is enabled, IOTLB invalidation also needs to use the queued invalidation +mechanism and the register based IOTLB invalidation doesn't work. + +For now, Support for IOTLB invalidation using queued invalidation is +missing. Meanwhile, disable DMA-remapping, if Interrupt-remapping +support is detected. + +For the meanwhile, if someone wants to really enable DMA-remapping, they +can use nox2apic, which will disable interrupt-remapping and as such +doesn't enable queued invalidation. + +And given that none of the release platforms support intr-remapping yet, +we should be ok for this temporary hack. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + drivers/pci/dmar.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +Index: linux-2.6.26/drivers/pci/dmar.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/dmar.c ++++ linux-2.6.26/drivers/pci/dmar.c +@@ -459,6 +459,31 @@ void __init detect_intel_iommu(void) + + #ifdef CONFIG_DMAR + { ++ struct acpi_table_dmar *dmar; ++ /* ++ * for now we will disable dma-remapping when interrupt ++ * remapping is enabled. ++ * When support for queued invalidation for IOTLB invalidation ++ * is added, we will not need this any more. ++ */ ++ dmar = (struct acpi_table_dmar *) dmar_tbl; ++ if (ret && cpu_has_x2apic && dmar->flags & 0x1) { ++ printk(KERN_INFO ++ "Queued invalidation will be enabled to support " ++ "x2apic and Intr-remapping.\n"); ++ printk(KERN_INFO ++ "Disabling IOMMU detection, because of missing " ++ "queued invalidation support for IOTLB " ++ "invalidation\n"); ++ printk(KERN_INFO ++ "Use \"nox2apic\", if you want to use Intel " ++ " IOMMU for DMA-remapping and don't care about " ++ " x2apic support\n"); ++ ++ dmar_disabled = 1; ++ return; ++ } ++ + if (ret && !no_iommu && !iommu_detected && !swiotlb && + !dmar_disabled) + iommu_detected = 1; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_19_of_41_13c88fb58d0112d47f7839f24a755715c6218822 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_19_of_41_13c88fb58d0112d47f7839f24a755715c6218822 new file mode 100644 index 000000000..e08b74404 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_19_of_41_13c88fb58d0112d47f7839f24a755715c6218822 @@ -0,0 +1,139 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: x2apic ops for x2apic mode support +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 13c88fb58d0112d47f7839f24a755715c6218822 + +Signed-off-by: Thomas Renninger + +x2apic ops for x2apic mode support. This uses MSR interface and differs +slightly from the xapic register layout. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_64.c | 35 +++++++++++++++++++++++++++++++++++ + include/asm-x86/apic.h | 23 +++++++++++++++++++++++ + include/asm-x86/apicdef.h | 3 +++ + 3 files changed, 61 insertions(+) + +Index: linux-2.6.26/arch/x86/kernel/apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_64.c ++++ linux-2.6.26/arch/x86/kernel/apic_64.c +@@ -169,6 +169,41 @@ struct apic_ops __read_mostly *apic_ops + + EXPORT_SYMBOL_GPL(apic_ops); + ++static void x2apic_wait_icr_idle(void) ++{ ++ /* no need to wait for icr idle in x2apic */ ++ return; ++} ++ ++static u32 safe_x2apic_wait_icr_idle(void) ++{ ++ /* no need to wait for icr idle in x2apic */ ++ return 0; ++} ++ ++void x2apic_icr_write(u32 low, u32 id) ++{ ++ wrmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low); ++} ++ ++u64 x2apic_icr_read(void) ++{ ++ unsigned long val; ++ ++ rdmsrl(APIC_BASE_MSR + (APIC_ICR >> 4), val); ++ return val; ++} ++ ++static struct apic_ops x2apic_ops = { ++ .read = native_apic_msr_read, ++ .write = native_apic_msr_write, ++ .write_atomic = native_apic_msr_write, ++ .icr_read = x2apic_icr_read, ++ .icr_write = x2apic_icr_write, ++ .wait_icr_idle = x2apic_wait_icr_idle, ++ .safe_wait_icr_idle = safe_x2apic_wait_icr_idle, ++}; ++ + /** + * enable_NMI_through_LVT0 - enable NMI through local vector table 0 + */ +Index: linux-2.6.26/include/asm-x86/apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/apic.h ++++ linux-2.6.26/include/asm-x86/apic.h +@@ -9,6 +9,8 @@ + #include + #include + #include ++#include ++#include + + #define ARCH_APICTIMER_STOPS_ON_C3 1 + +@@ -71,11 +73,32 @@ static inline u32 native_apic_mem_read(u + return *((volatile u32 *)(APIC_BASE + reg)); + } + ++static inline void native_apic_msr_write(u32 reg, u32 v) ++{ ++ if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR || ++ reg == APIC_LVR) ++ return; ++ ++ wrmsr(APIC_BASE_MSR + (reg >> 4), v, 0); ++} ++ ++static inline u32 native_apic_msr_read(u32 reg) ++{ ++ u32 low, high; ++ ++ if (reg == APIC_DFR) ++ return -1; ++ ++ rdmsr(APIC_BASE_MSR + (reg >> 4), low, high); ++ return low; ++} ++ + #ifdef CONFIG_X86_32 + extern void apic_wait_icr_idle(void); + extern u32 safe_apic_wait_icr_idle(void); + extern void apic_icr_write(u32 low, u32 id); + #else ++extern void x2apic_icr_write(u32 low, u32 id); + + struct apic_ops { + u32 (*read)(u32 reg); +Index: linux-2.6.26/include/asm-x86/apicdef.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/apicdef.h ++++ linux-2.6.26/include/asm-x86/apicdef.h +@@ -105,6 +105,7 @@ + #define APIC_TMICT 0x380 + #define APIC_TMCCT 0x390 + #define APIC_TDCR 0x3E0 ++#define APIC_SELF_IPI 0x3F0 + #define APIC_TDR_DIV_TMBASE (1 << 2) + #define APIC_TDR_DIV_1 0xB + #define APIC_TDR_DIV_2 0x0 +@@ -128,6 +129,8 @@ + #define APIC_EILVT3 0x530 + + #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) ++#define APIC_BASE_MSR 0x800 ++#define X2APIC_ENABLE (1UL << 10) + + #ifdef CONFIG_X86_32 + # define MAX_IO_APICS 64 diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_20_of_41_cff73a6ffaed726780b001937d2a42efde553922 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_20_of_41_cff73a6ffaed726780b001937d2a42efde553922 new file mode 100644 index 000000000..540d4e613 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_20_of_41_cff73a6ffaed726780b001937d2a42efde553922 @@ -0,0 +1,106 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: introcude self IPI to genapic routines +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: cff73a6ffaed726780b001937d2a42efde553922 + +Signed-off-by: Thomas Renninger + +Introduce self IPI op for genapic. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genapic_64.c | 2 +- + arch/x86/kernel/genapic_flat_64.c | 2 ++ + include/asm-x86/genapic_64.h | 2 ++ + include/asm-x86/hw_irq.h | 2 ++ + include/asm-x86/mach-default/mach_apic.h | 1 + + 5 files changed, 8 insertions(+), 1 deletion(-) + +Index: linux-2.6.26/arch/x86/kernel/genapic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_64.c +@@ -61,7 +61,7 @@ void __init setup_apic_routing(void) + + /* Same for both flat and physical. */ + +-void send_IPI_self(int vector) ++void apic_send_IPI_self(int vector) + { + __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL); + } +Index: linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_flat_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +@@ -131,6 +131,7 @@ struct genapic apic_flat = { + .send_IPI_all = flat_send_IPI_all, + .send_IPI_allbutself = flat_send_IPI_allbutself, + .send_IPI_mask = flat_send_IPI_mask, ++ .send_IPI_self = apic_send_IPI_self, + .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, + .read_apic_id = read_xapic_id, +@@ -196,6 +197,7 @@ struct genapic apic_physflat = { + .send_IPI_all = physflat_send_IPI_all, + .send_IPI_allbutself = physflat_send_IPI_allbutself, + .send_IPI_mask = physflat_send_IPI_mask, ++ .send_IPI_self = apic_send_IPI_self, + .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, + .read_apic_id = read_xapic_id, +Index: linux-2.6.26/include/asm-x86/genapic_64.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/genapic_64.h ++++ linux-2.6.26/include/asm-x86/genapic_64.h +@@ -24,6 +24,7 @@ struct genapic { + void (*send_IPI_mask)(cpumask_t mask, int vector); + void (*send_IPI_allbutself)(int vector); + void (*send_IPI_all)(int vector); ++ void (*send_IPI_self)(int vector); + /* */ + unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask); + unsigned int (*phys_pkg_id)(int index_msb); +@@ -36,6 +37,7 @@ extern struct genapic apic_flat; + extern struct genapic apic_physflat; + extern int acpi_madt_oem_check(char *, char *); + ++extern void apic_send_IPI_self(int vector); + enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC}; + extern enum uv_system_type get_uv_system_type(void); + extern int is_uv_system(void); +Index: linux-2.6.26/include/asm-x86/hw_irq.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/hw_irq.h ++++ linux-2.6.26/include/asm-x86/hw_irq.h +@@ -73,7 +73,9 @@ extern void enable_IO_APIC(void); + #endif + + /* IPI functions */ ++#ifdef CONFIG_X86_32 + extern void send_IPI_self(int vector); ++#endif + extern void send_IPI(int dest, int vector); + + /* Statistics */ +Index: linux-2.6.26/include/asm-x86/mach-default/mach_apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/mach-default/mach_apic.h ++++ linux-2.6.26/include/asm-x86/mach-default/mach_apic.h +@@ -31,6 +31,7 @@ static inline cpumask_t target_cpus(void + #define phys_pkg_id (genapic->phys_pkg_id) + #define vector_allocation_domain (genapic->vector_allocation_domain) + #define read_apic_id (genapic->read_apic_id) ++#define send_IPI_self (genapic->send_IPI_self) + extern void setup_apic_routing(void); + #else + #define INT_DELIVERY_MODE dest_LowestPrio diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_21_of_41_12a67cf6851871ca8df42025c94f140c303d0f7f b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_21_of_41_12a67cf6851871ca8df42025c94f140c303d0f7f new file mode 100644 index 000000000..0a002997b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_21_of_41_12a67cf6851871ca8df42025c94f140c303d0f7f @@ -0,0 +1,211 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: x2apic cluster mode support +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 12a67cf6851871ca8df42025c94f140c303d0f7f + +Signed-off-by: Thomas Renninger + +x2apic cluster mode support. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/Makefile | 1 + arch/x86/kernel/genapic_64.c | 3 + arch/x86/kernel/genx2apic_cluster.c | 135 ++++++++++++++++++++++++++++++++++++ + include/asm-x86/genapic_64.h | 1 + 4 files changed, 140 insertions(+) + +Index: linux-2.6.26/arch/x86/kernel/Makefile +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/Makefile ++++ linux-2.6.26/arch/x86/kernel/Makefile +@@ -103,6 +103,7 @@ obj-$(CONFIG_OLPC) += olpc.o + # 64 bit specific files + ifeq ($(CONFIG_X86_64),y) + obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o ++ obj-y += genx2apic_cluster.o + obj-y += bios_uv.o + obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o + obj-$(CONFIG_AUDIT) += audit_64.o +Index: linux-2.6.26/arch/x86/kernel/genapic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_64.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -38,6 +39,8 @@ void __init setup_apic_routing(void) + { + if (uv_system_type == UV_NON_UNIQUE_APIC) + genapic = &apic_x2apic_uv_x; ++ else if (cpu_has_x2apic && intr_remapping_enabled) ++ genapic = &apic_x2apic_cluster; + else + #ifdef CONFIG_ACPI + /* +Index: linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +@@ -0,0 +1,135 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid); ++ ++/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ ++ ++static cpumask_t x2apic_target_cpus(void) ++{ ++ return cpumask_of_cpu(0); ++} ++ ++/* ++ * for now each logical cpu is in its own vector allocation domain. ++ */ ++static cpumask_t x2apic_vector_allocation_domain(int cpu) ++{ ++ cpumask_t domain = CPU_MASK_NONE; ++ cpu_set(cpu, domain); ++ return domain; ++} ++ ++static void __x2apic_send_IPI_dest(unsigned int apicid, int vector, ++ unsigned int dest) ++{ ++ unsigned long cfg; ++ ++ cfg = __prepare_ICR(0, vector, dest); ++ ++ /* ++ * send the IPI. ++ */ ++ x2apic_icr_write(cfg, apicid); ++} ++ ++/* ++ * for now, we send the IPI's one by one in the cpumask. ++ * TBD: Based on the cpu mask, we can send the IPI's to the cluster group ++ * at once. We have 16 cpu's in a cluster. This will minimize IPI register ++ * writes. ++ */ ++static void x2apic_send_IPI_mask(cpumask_t mask, int vector) ++{ ++ unsigned long flags; ++ unsigned long query_cpu; ++ ++ local_irq_save(flags); ++ for_each_cpu_mask(query_cpu, mask) { ++ __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_logical_apicid, query_cpu), ++ vector, APIC_DEST_LOGICAL); ++ } ++ local_irq_restore(flags); ++} ++ ++static void x2apic_send_IPI_allbutself(int vector) ++{ ++ cpumask_t mask = cpu_online_map; ++ ++ cpu_clear(smp_processor_id(), mask); ++ ++ if (!cpus_empty(mask)) ++ x2apic_send_IPI_mask(mask, vector); ++} ++ ++static void x2apic_send_IPI_all(int vector) ++{ ++ x2apic_send_IPI_mask(cpu_online_map, vector); ++} ++ ++static int x2apic_apic_id_registered(void) ++{ ++ return 1; ++} ++ ++static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask) ++{ ++ int cpu; ++ ++ /* ++ * We're using fixed IRQ delivery, can only return one phys APIC ID. ++ * May as well be the first. ++ */ ++ cpu = first_cpu(cpumask); ++ if ((unsigned)cpu < NR_CPUS) ++ return per_cpu(x86_cpu_to_logical_apicid, cpu); ++ else ++ return BAD_APICID; ++} ++ ++static unsigned int x2apic_read_id(void) ++{ ++ return apic_read(APIC_ID); ++} ++ ++static unsigned int phys_pkg_id(int index_msb) ++{ ++ return x2apic_read_id() >> index_msb; ++} ++ ++static void x2apic_send_IPI_self(int vector) ++{ ++ apic_write(APIC_SELF_IPI, vector); ++} ++ ++static void init_x2apic_ldr(void) ++{ ++ int cpu = smp_processor_id(); ++ ++ per_cpu(x86_cpu_to_logical_apicid, cpu) = apic_read(APIC_LDR); ++ return; ++} ++ ++struct genapic apic_x2apic_cluster = { ++ .name = "cluster x2apic", ++ .int_delivery_mode = dest_LowestPrio, ++ .int_dest_mode = (APIC_DEST_LOGICAL != 0), ++ .target_cpus = x2apic_target_cpus, ++ .vector_allocation_domain = x2apic_vector_allocation_domain, ++ .apic_id_registered = x2apic_apic_id_registered, ++ .init_apic_ldr = init_x2apic_ldr, ++ .send_IPI_all = x2apic_send_IPI_all, ++ .send_IPI_allbutself = x2apic_send_IPI_allbutself, ++ .send_IPI_mask = x2apic_send_IPI_mask, ++ .send_IPI_self = x2apic_send_IPI_self, ++ .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid, ++ .phys_pkg_id = phys_pkg_id, ++ .read_apic_id = x2apic_read_id, ++}; +Index: linux-2.6.26/include/asm-x86/genapic_64.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/genapic_64.h ++++ linux-2.6.26/include/asm-x86/genapic_64.h +@@ -35,6 +35,7 @@ extern struct genapic *genapic; + + extern struct genapic apic_flat; + extern struct genapic apic_physflat; ++extern struct genapic apic_x2apic_cluster; + extern int acpi_madt_oem_check(char *, char *); + + extern void apic_send_IPI_self(int vector); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_22_of_41_5c520a6724e912a7e6153b7597192edad6752750 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_22_of_41_5c520a6724e912a7e6153b7597192edad6752750 new file mode 100644 index 000000000..935f3ea98 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_22_of_41_5c520a6724e912a7e6153b7597192edad6752750 @@ -0,0 +1,45 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: setup init_apic_ldr for UV +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 5c520a6724e912a7e6153b7597192edad6752750 + +Signed-off-by: Thomas Renninger + +Signed-off-by: Suresh Siddha +Signed-off-by: Jack Steiner +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genx2apic_uv_x.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +@@ -124,6 +124,10 @@ static int uv_apic_id_registered(void) + return 1; + } + ++static inline void uv_init_apic_ldr(void) ++{ ++} ++ + static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask) + { + int cpu; +@@ -168,6 +172,7 @@ struct genapic apic_x2apic_uv_x = { + .target_cpus = uv_target_cpus, + .vector_allocation_domain = uv_vector_allocation_domain,/* Fixme ZZZ */ + .apic_id_registered = uv_apic_id_registered, ++ .init_apic_ldr = uv_init_apic_ldr, + .send_IPI_all = uv_send_IPI_all, + .send_IPI_allbutself = uv_send_IPI_allbutself, + .send_IPI_mask = uv_send_IPI_mask, diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_23_of_41_89027d35aa5b8f45ce0f7fa0911db85b46563da0 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_23_of_41_89027d35aa5b8f45ce0f7fa0911db85b46563da0 new file mode 100644 index 000000000..7658213ba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_23_of_41_89027d35aa5b8f45ce0f7fa0911db85b46563da0 @@ -0,0 +1,555 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: IO-APIC support for interrupt-remapping +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 89027d35aa5b8f45ce0f7fa0911db85b46563da0 + +Signed-off-by: Thomas Renninger + +IO-APIC support in the presence of interrupt-remapping infrastructure. + +IO-APIC RTE will be programmed with interrupt-remapping table entry(IRTE) +index and the IRTE will contain information about the vector, cpu destination, +trigger mode etc, which traditionally was present in the IO-APIC RTE. + +Introduce a new irq_chip for cleaner irq migration (in the process +context as opposed to the current irq migration in the context of an interrupt. +interrupt-remapping infrastructure will help us achieve this cleanly). + +For edge triggered, irq migration is a simple atomic update(of vector +and cpu destination) of IRTE and flush the hardware cache. + +For level triggered, we need to modify the io-apic RTE aswell with the update +vector information, along with modifying IRTE with vector and cpu destination. +So irq migration for level triggered is little bit more complex compared to +edge triggered migration. But the good news is, we use the same algorithm +for level triggered migration as we have today, only difference being, +we now initiate the irq migration from process context instead of the +interrupt context. + +In future, when we do a directed EOI (combined with cpu EOI broadcast +suppression) to the IO-APIC, level triggered irq migration will also be +as simple as edge triggered migration and we can do the irq migration +with a simple atomic update to IO-APIC RTE. + +TBD: some tests/changes needed in the presence of fixup_irqs() for +level triggered irq migration. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_64.c | 1 + arch/x86/kernel/io_apic_64.c | 300 +++++++++++++++++++++++++++++++++++++--- + drivers/pci/intr_remapping.c | 10 + + include/asm-x86/apic.h | 8 + + include/asm-x86/io_apic.h | 14 + + include/asm-x86/irq_remapping.h | 8 + + include/linux/dmar.h | 1 + 7 files changed, 320 insertions(+), 22 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_64.c ++++ linux-2.6.26/arch/x86/kernel/apic_64.c +@@ -46,6 +46,7 @@ + static int disable_apic_timer __cpuinitdata; + static int apic_calibrate_pmtmr __initdata; + int disable_apic; ++int x2apic; + + /* Local APIC timer works in C2 */ + int local_apic_timer_c2_ok; +Index: linux-2.6.26/arch/x86/kernel/io_apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/io_apic_64.c ++++ linux-2.6.26/arch/x86/kernel/io_apic_64.c +@@ -37,6 +37,7 @@ + #include + #endif + #include ++#include + + #include + #include +@@ -49,6 +50,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -306,7 +308,12 @@ static void __target_IO_APIC_irq(unsigne + pin = entry->pin; + if (pin == -1) + break; +- io_apic_write(apic, 0x11 + pin*2, dest); ++ /* ++ * With interrupt-remapping, destination information comes ++ * from interrupt-remapping table entry. ++ */ ++ if (!irq_remapped(irq)) ++ io_apic_write(apic, 0x11 + pin*2, dest); + reg = io_apic_read(apic, 0x10 + pin*2); + reg &= ~IO_APIC_REDIR_VECTOR_MASK; + reg |= vector; +@@ -905,18 +912,98 @@ void __setup_vector_irq(int cpu) + } + + static struct irq_chip ioapic_chip; ++#ifdef CONFIG_INTR_REMAP ++static struct irq_chip ir_ioapic_chip; ++#endif + + static void ioapic_register_intr(int irq, unsigned long trigger) + { +- if (trigger) { ++ if (trigger) + irq_desc[irq].status |= IRQ_LEVEL; +- set_irq_chip_and_handler_name(irq, &ioapic_chip, +- handle_fasteoi_irq, "fasteoi"); +- } else { ++ else + irq_desc[irq].status &= ~IRQ_LEVEL; ++ ++#ifdef CONFIG_INTR_REMAP ++ if (irq_remapped(irq)) { ++ irq_desc[irq].status |= IRQ_MOVE_PCNTXT; ++ if (trigger) ++ set_irq_chip_and_handler_name(irq, &ir_ioapic_chip, ++ handle_fasteoi_irq, ++ "fasteoi"); ++ else ++ set_irq_chip_and_handler_name(irq, &ir_ioapic_chip, ++ handle_edge_irq, "edge"); ++ return; ++ } ++#endif ++ if (trigger) ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_fasteoi_irq, ++ "fasteoi"); ++ else + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_edge_irq, "edge"); ++} ++ ++static int setup_ioapic_entry(int apic, int irq, ++ struct IO_APIC_route_entry *entry, ++ unsigned int destination, int trigger, ++ int polarity, int vector) ++{ ++ /* ++ * add it to the IO-APIC irq-routing table: ++ */ ++ memset(entry,0,sizeof(*entry)); ++ ++#ifdef CONFIG_INTR_REMAP ++ if (intr_remapping_enabled) { ++ struct intel_iommu *iommu = map_ioapic_to_ir(apic); ++ struct irte irte; ++ struct IR_IO_APIC_route_entry *ir_entry = ++ (struct IR_IO_APIC_route_entry *) entry; ++ int index; ++ ++ if (!iommu) ++ panic("No mapping iommu for ioapic %d\n", apic); ++ ++ index = alloc_irte(iommu, irq, 1); ++ if (index < 0) ++ panic("Failed to allocate IRTE for ioapic %d\n", apic); ++ ++ memset(&irte, 0, sizeof(irte)); ++ ++ irte.present = 1; ++ irte.dst_mode = INT_DEST_MODE; ++ irte.trigger_mode = trigger; ++ irte.dlvry_mode = INT_DELIVERY_MODE; ++ irte.vector = vector; ++ irte.dest_id = IRTE_DEST(destination); ++ ++ modify_irte(irq, &irte); ++ ++ ir_entry->index2 = (index >> 15) & 0x1; ++ ir_entry->zero = 0; ++ ir_entry->format = 1; ++ ir_entry->index = (index & 0x7fff); ++ } else ++#endif ++ { ++ entry->delivery_mode = INT_DELIVERY_MODE; ++ entry->dest_mode = INT_DEST_MODE; ++ entry->dest = destination; + } ++ ++ entry->mask = 0; /* enable IRQ */ ++ entry->trigger = trigger; ++ entry->polarity = polarity; ++ entry->vector = vector; ++ ++ /* Mask level triggered irqs. ++ * Use IRQ_DELAYED_DISABLE for edge triggered irqs. ++ */ ++ if (trigger) ++ entry->mask = 1; ++ return 0; + } + + static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, +@@ -941,24 +1028,15 @@ static void setup_IO_APIC_irq(int apic, + apic, mp_ioapics[apic].mp_apicid, pin, cfg->vector, + irq, trigger, polarity); + +- /* +- * add it to the IO-APIC irq-routing table: +- */ +- memset(&entry,0,sizeof(entry)); + +- entry.delivery_mode = INT_DELIVERY_MODE; +- entry.dest_mode = INT_DEST_MODE; +- entry.dest = cpu_mask_to_apicid(mask); +- entry.mask = 0; /* enable IRQ */ +- entry.trigger = trigger; +- entry.polarity = polarity; +- entry.vector = cfg->vector; +- +- /* Mask level triggered irqs. +- * Use IRQ_DELAYED_DISABLE for edge triggered irqs. +- */ +- if (trigger) +- entry.mask = 1; ++ if (setup_ioapic_entry(mp_ioapics[apic].mp_apicid, irq, &entry, ++ cpu_mask_to_apicid(mask), trigger, polarity, ++ cfg->vector)) { ++ printk("Failed to setup ioapic entry for ioapic %d, pin %d\n", ++ mp_ioapics[apic].mp_apicid, pin); ++ __clear_irq_vector(irq); ++ return; ++ } + + ioapic_register_intr(irq, trigger); + if (irq < 16) +@@ -1010,6 +1088,9 @@ static void __init setup_timer_IRQ0_pin( + { + struct IO_APIC_route_entry entry; + ++ if (intr_remapping_enabled) ++ return; ++ + memset(&entry, 0, sizeof(entry)); + + /* +@@ -1463,6 +1544,147 @@ static int ioapic_retrigger_irq(unsigned + */ + + #ifdef CONFIG_SMP ++ ++#ifdef CONFIG_INTR_REMAP ++static void ir_irq_migration(struct work_struct *work); ++ ++static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration); ++ ++/* ++ * Migrate the IO-APIC irq in the presence of intr-remapping. ++ * ++ * For edge triggered, irq migration is a simple atomic update(of vector ++ * and cpu destination) of IRTE and flush the hardware cache. ++ * ++ * For level triggered, we need to modify the io-apic RTE aswell with the update ++ * vector information, along with modifying IRTE with vector and destination. ++ * So irq migration for level triggered is little bit more complex compared to ++ * edge triggered migration. But the good news is, we use the same algorithm ++ * for level triggered migration as we have today, only difference being, ++ * we now initiate the irq migration from process context instead of the ++ * interrupt context. ++ * ++ * In future, when we do a directed EOI (combined with cpu EOI broadcast ++ * suppression) to the IO-APIC, level triggered irq migration will also be ++ * as simple as edge triggered migration and we can do the irq migration ++ * with a simple atomic update to IO-APIC RTE. ++ */ ++static void migrate_ioapic_irq(int irq, cpumask_t mask) ++{ ++ struct irq_cfg *cfg = irq_cfg + irq; ++ struct irq_desc *desc = irq_desc + irq; ++ cpumask_t tmp, cleanup_mask; ++ struct irte irte; ++ int modify_ioapic_rte = desc->status & IRQ_LEVEL; ++ unsigned int dest; ++ unsigned long flags; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ return; ++ ++ if (get_irte(irq, &irte)) ++ return; ++ ++ if (assign_irq_vector(irq, mask)) ++ return; ++ ++ cpus_and(tmp, cfg->domain, mask); ++ dest = cpu_mask_to_apicid(tmp); ++ ++ if (modify_ioapic_rte) { ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __target_IO_APIC_irq(irq, dest, cfg->vector); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ } ++ ++ irte.vector = cfg->vector; ++ irte.dest_id = IRTE_DEST(dest); ++ ++ /* ++ * Modified the IRTE and flushes the Interrupt entry cache. ++ */ ++ modify_irte(irq, &irte); ++ ++ if (cfg->move_in_progress) { ++ cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); ++ cfg->move_cleanup_count = cpus_weight(cleanup_mask); ++ send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); ++ cfg->move_in_progress = 0; ++ } ++ ++ irq_desc[irq].affinity = mask; ++} ++ ++static int migrate_irq_remapped_level(int irq) ++{ ++ int ret = -1; ++ ++ mask_IO_APIC_irq(irq); ++ ++ if (io_apic_level_ack_pending(irq)) { ++ /* ++ * Interrupt in progress. Migrating irq now will change the ++ * vector information in the IO-APIC RTE and that will confuse ++ * the EOI broadcast performed by cpu. ++ * So, delay the irq migration to the next instance. ++ */ ++ schedule_delayed_work(&ir_migration_work, 1); ++ goto unmask; ++ } ++ ++ /* everthing is clear. we have right of way */ ++ migrate_ioapic_irq(irq, irq_desc[irq].pending_mask); ++ ++ ret = 0; ++ irq_desc[irq].status &= ~IRQ_MOVE_PENDING; ++ cpus_clear(irq_desc[irq].pending_mask); ++ ++unmask: ++ unmask_IO_APIC_irq(irq); ++ return ret; ++} ++ ++static void ir_irq_migration(struct work_struct *work) ++{ ++ int irq; ++ ++ for (irq = 0; irq < NR_IRQS; irq++) { ++ struct irq_desc *desc = irq_desc + irq; ++ if (desc->status & IRQ_MOVE_PENDING) { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&desc->lock, flags); ++ if (!desc->chip->set_affinity || ++ !(desc->status & IRQ_MOVE_PENDING)) { ++ desc->status &= ~IRQ_MOVE_PENDING; ++ spin_unlock_irqrestore(&desc->lock, flags); ++ continue; ++ } ++ ++ desc->chip->set_affinity(irq, ++ irq_desc[irq].pending_mask); ++ spin_unlock_irqrestore(&desc->lock, flags); ++ } ++ } ++} ++ ++/* ++ * Migrates the IRQ destination in the process context. ++ */ ++static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) ++{ ++ if (irq_desc[irq].status & IRQ_LEVEL) { ++ irq_desc[irq].status |= IRQ_MOVE_PENDING; ++ irq_desc[irq].pending_mask = mask; ++ migrate_irq_remapped_level(irq); ++ return; ++ } ++ ++ migrate_ioapic_irq(irq, mask); ++} ++#endif ++ + asmlinkage void smp_irq_move_cleanup_interrupt(void) + { + unsigned vector, me; +@@ -1519,6 +1741,17 @@ static void irq_complete_move(unsigned i + #else + static inline void irq_complete_move(unsigned int irq) {} + #endif ++#ifdef CONFIG_INTR_REMAP ++static void ack_x2apic_level(unsigned int irq) ++{ ++ ack_x2APIC_irq(); ++} ++ ++static void ack_x2apic_edge(unsigned int irq) ++{ ++ ack_x2APIC_irq(); ++} ++#endif + + static void ack_apic_edge(unsigned int irq) + { +@@ -1593,6 +1826,21 @@ static struct irq_chip ioapic_chip __rea + .retrigger = ioapic_retrigger_irq, + }; + ++#ifdef CONFIG_INTR_REMAP ++static struct irq_chip ir_ioapic_chip __read_mostly = { ++ .name = "IR-IO-APIC", ++ .startup = startup_ioapic_irq, ++ .mask = mask_IO_APIC_irq, ++ .unmask = unmask_IO_APIC_irq, ++ .ack = ack_x2apic_edge, ++ .eoi = ack_x2apic_level, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ir_ioapic_affinity_irq, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++#endif ++ + static inline void init_IO_APIC_traps(void) + { + int irq; +@@ -1778,6 +2026,8 @@ static inline void __init check_timer(vo + * 8259A. + */ + if (pin1 == -1) { ++ if (intr_remapping_enabled) ++ panic("BIOS bug: timer not connected to IO-APIC"); + pin1 = pin2; + apic1 = apic2; + no_pin1 = 1; +@@ -1804,6 +2054,8 @@ static inline void __init check_timer(vo + clear_IO_APIC_pin(0, pin1); + goto out; + } ++ if (intr_remapping_enabled) ++ panic("timer doesn't work through Interrupt-remapped IO-APIC"); + clear_IO_APIC_pin(apic1, pin1); + if (!no_pin1) + apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: " +@@ -2399,6 +2651,10 @@ void __init setup_ioapic_dest(void) + setup_IO_APIC_irq(ioapic, pin, irq, + irq_trigger(irq_entry), + irq_polarity(irq_entry)); ++#ifdef CONFIG_INTR_REMAP ++ else if (intr_remapping_enabled) ++ set_ir_ioapic_affinity_irq(irq, TARGET_CPUS); ++#endif + else + set_ioapic_affinity_irq(irq, TARGET_CPUS); + } +Index: linux-2.6.26/drivers/pci/intr_remapping.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/intr_remapping.c ++++ linux-2.6.26/drivers/pci/intr_remapping.c +@@ -220,6 +220,16 @@ int flush_irte(int irq) + return 0; + } + ++struct intel_iommu *map_ioapic_to_ir(int apic) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_IO_APICS; i++) ++ if (ir_ioapic[i].id == apic) ++ return ir_ioapic[i].iommu; ++ return NULL; ++} ++ + int free_irte(int irq) + { + int index, i; +Index: linux-2.6.26/include/asm-x86/apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/apic.h ++++ linux-2.6.26/include/asm-x86/apic.h +@@ -123,6 +123,14 @@ extern struct apic_ops *apic_ops; + + extern int get_physical_broadcast(void); + ++#ifdef CONFIG_X86_64 ++static inline void ack_x2APIC_irq(void) ++{ ++ /* Docs say use 0 for future compatibility */ ++ native_apic_msr_write(APIC_EOI, 0); ++} ++#endif ++ + static inline void ack_APIC_irq(void) + { + /* +Index: linux-2.6.26/include/asm-x86/io_apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/io_apic.h ++++ linux-2.6.26/include/asm-x86/io_apic.h +@@ -107,6 +107,20 @@ struct IO_APIC_route_entry { + + } __attribute__ ((packed)); + ++struct IR_IO_APIC_route_entry { ++ __u64 vector : 8, ++ zero : 3, ++ index2 : 1, ++ delivery_status : 1, ++ polarity : 1, ++ irr : 1, ++ trigger : 1, ++ mask : 1, ++ reserved : 31, ++ format : 1, ++ index : 15; ++} __attribute__ ((packed)); ++ + #ifdef CONFIG_X86_IO_APIC + + /* +Index: linux-2.6.26/include/asm-x86/irq_remapping.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/include/asm-x86/irq_remapping.h +@@ -0,0 +1,8 @@ ++#ifndef _ASM_IRQ_REMAPPING_H ++#define _ASM_IRQ_REMAPPING_H ++ ++extern int x2apic; ++ ++#define IRTE_DEST(dest) ((x2apic) ? dest : dest << 8) ++ ++#endif +Index: linux-2.6.26/include/linux/dmar.h +=================================================================== +--- linux-2.6.26.orig/include/linux/dmar.h ++++ linux-2.6.26/include/linux/dmar.h +@@ -109,6 +109,7 @@ extern int flush_irte(int irq); + extern int free_irte(int irq); + + extern int irq_remapped(int irq); ++extern struct intel_iommu *map_ioapic_to_ir(int apic); + #else + #define irq_remapped(irq) (0) + #define enable_intr_remapping(mode) (-1) diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_24_of_41_75c46fa61bc5b4ccd20a168ff325c58771248fcd b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_24_of_41_75c46fa61bc5b4ccd20a168ff325c58771248fcd new file mode 100644 index 000000000..449482f81 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_24_of_41_75c46fa61bc5b4ccd20a168ff325c58771248fcd @@ -0,0 +1,367 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: MSI and MSI-X support for interrupt remapping infrastructure +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 75c46fa61bc5b4ccd20a168ff325c58771248fcd + +Signed-off-by: Thomas Renninger + +MSI and MSI-X support for interrupt remapping infrastructure. + +MSI address register will be programmed with interrupt-remapping table +entry(IRTE) index and the IRTE will contain information about the vector, +cpu destination, etc. + +For MSI-X, all the IRTE's will be consecutively allocated in the table, +and the address registers will contain the starting index to the block +and the data register will contain the subindex with in that block. + +This also introduces a new irq_chip for cleaner irq migration (in the process +context as opposed to the current irq migration in the context of an interrupt. +interrupt-remapping infrastructure will help us achieve this). + +As MSI is edge triggered, irq migration is a simple atomic update(of vector +and cpu destination) of IRTE and flushing the hardware cache. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/io_apic_64.c | 230 +++++++++++++++++++++++++++++++++++++++++-- + drivers/pci/intr_remapping.c | 11 ++ + include/asm-x86/msidef.h | 4 + include/linux/dmar.h | 1 + 4 files changed, 238 insertions(+), 8 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/io_apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/io_apic_64.c ++++ linux-2.6.26/arch/x86/kernel/io_apic_64.c +@@ -2295,6 +2295,9 @@ void destroy_irq(unsigned int irq) + + dynamic_irq_cleanup(irq); + ++#ifdef CONFIG_INTR_REMAP ++ free_irte(irq); ++#endif + spin_lock_irqsave(&vector_lock, flags); + __clear_irq_vector(irq); + spin_unlock_irqrestore(&vector_lock, flags); +@@ -2313,11 +2316,42 @@ static int msi_compose_msg(struct pci_de + + tmp = TARGET_CPUS; + err = assign_irq_vector(irq, tmp); +- if (!err) { +- cpus_and(tmp, cfg->domain, tmp); +- dest = cpu_mask_to_apicid(tmp); ++ if (err) ++ return err; ++ ++ cpus_and(tmp, cfg->domain, tmp); ++ dest = cpu_mask_to_apicid(tmp); ++ ++#ifdef CONFIG_INTR_REMAP ++ if (irq_remapped(irq)) { ++ struct irte irte; ++ int ir_index; ++ u16 sub_handle; ++ ++ ir_index = map_irq_to_irte_handle(irq, &sub_handle); ++ BUG_ON(ir_index == -1); ++ ++ memset (&irte, 0, sizeof(irte)); ++ ++ irte.present = 1; ++ irte.dst_mode = INT_DEST_MODE; ++ irte.trigger_mode = 0; /* edge */ ++ irte.dlvry_mode = INT_DELIVERY_MODE; ++ irte.vector = cfg->vector; ++ irte.dest_id = IRTE_DEST(dest); ++ ++ modify_irte(irq, &irte); + + msg->address_hi = MSI_ADDR_BASE_HI; ++ msg->data = sub_handle; ++ msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT | ++ MSI_ADDR_IR_SHV | ++ MSI_ADDR_IR_INDEX1(ir_index) | ++ MSI_ADDR_IR_INDEX2(ir_index); ++ } else ++#endif ++ { ++ msg->address_hi = MSI_ADDR_BASE_HI; + msg->address_lo = + MSI_ADDR_BASE_LO | + ((INT_DEST_MODE == 0) ? +@@ -2367,6 +2401,55 @@ static void set_msi_irq_affinity(unsigne + write_msi_msg(irq, &msg); + irq_desc[irq].affinity = mask; + } ++ ++#ifdef CONFIG_INTR_REMAP ++/* ++ * Migrate the MSI irq to another cpumask. This migration is ++ * done in the process context using interrupt-remapping hardware. ++ */ ++static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ struct irq_cfg *cfg = irq_cfg + irq; ++ unsigned int dest; ++ cpumask_t tmp, cleanup_mask; ++ struct irte irte; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ return; ++ ++ if (get_irte(irq, &irte)) ++ return; ++ ++ if (assign_irq_vector(irq, mask)) ++ return; ++ ++ cpus_and(tmp, cfg->domain, mask); ++ dest = cpu_mask_to_apicid(tmp); ++ ++ irte.vector = cfg->vector; ++ irte.dest_id = IRTE_DEST(dest); ++ ++ /* ++ * atomically update the IRTE with the new destination and vector. ++ */ ++ modify_irte(irq, &irte); ++ ++ /* ++ * After this point, all the interrupts will start arriving ++ * at the new destination. So, time to cleanup the previous ++ * vector allocation. ++ */ ++ if (cfg->move_in_progress) { ++ cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); ++ cfg->move_cleanup_count = cpus_weight(cleanup_mask); ++ send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); ++ cfg->move_in_progress = 0; ++ } ++ ++ irq_desc[irq].affinity = mask; ++} ++#endif + #endif /* CONFIG_SMP */ + + /* +@@ -2384,26 +2467,157 @@ static struct irq_chip msi_chip = { + .retrigger = ioapic_retrigger_irq, + }; + +-int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) ++#ifdef CONFIG_INTR_REMAP ++static struct irq_chip msi_ir_chip = { ++ .name = "IR-PCI-MSI", ++ .unmask = unmask_msi_irq, ++ .mask = mask_msi_irq, ++ .ack = ack_x2apic_edge, ++#ifdef CONFIG_SMP ++ .set_affinity = ir_set_msi_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++/* ++ * Map the PCI dev to the corresponding remapping hardware unit ++ * and allocate 'nvec' consecutive interrupt-remapping table entries ++ * in it. ++ */ ++static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec) + { ++ struct intel_iommu *iommu; ++ int index; ++ ++ iommu = map_dev_to_ir(dev); ++ if (!iommu) { ++ printk(KERN_ERR ++ "Unable to map PCI %s to iommu\n", pci_name(dev)); ++ return -ENOENT; ++ } ++ ++ index = alloc_irte(iommu, irq, nvec); ++ if (index < 0) { ++ printk(KERN_ERR ++ "Unable to allocate %d IRTE for PCI %s\n", nvec, ++ pci_name(dev)); ++ return -ENOSPC; ++ } ++ return index; ++} ++#endif ++ ++static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq) ++{ ++ int ret; + struct msi_msg msg; ++ ++ ret = msi_compose_msg(dev, irq, &msg); ++ if (ret < 0) ++ return ret; ++ ++ set_irq_msi(irq, desc); ++ write_msi_msg(irq, &msg); ++ ++#ifdef CONFIG_INTR_REMAP ++ if (irq_remapped(irq)) { ++ struct irq_desc *desc = irq_desc + irq; ++ /* ++ * irq migration in process context ++ */ ++ desc->status |= IRQ_MOVE_PCNTXT; ++ set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge"); ++ } else ++#endif ++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); ++ ++ return 0; ++} ++ ++int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) ++{ + int irq, ret; ++ + irq = create_irq(); + if (irq < 0) + return irq; + +- ret = msi_compose_msg(dev, irq, &msg); ++#ifdef CONFIG_INTR_REMAP ++ if (!intr_remapping_enabled) ++ goto no_ir; ++ ++ ret = msi_alloc_irte(dev, irq, 1); ++ if (ret < 0) ++ goto error; ++no_ir: ++#endif ++ ret = setup_msi_irq(dev, desc, irq); + if (ret < 0) { + destroy_irq(irq); + return ret; + } ++ return 0; + +- set_irq_msi(irq, desc); +- write_msi_msg(irq, &msg); ++#ifdef CONFIG_INTR_REMAP ++error: ++ destroy_irq(irq); ++ return ret; ++#endif ++} + +- set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); ++int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ++{ ++ int irq, ret, sub_handle; ++ struct msi_desc *desc; ++#ifdef CONFIG_INTR_REMAP ++ struct intel_iommu *iommu = 0; ++ int index = 0; ++#endif + ++ sub_handle = 0; ++ list_for_each_entry(desc, &dev->msi_list, list) { ++ irq = create_irq(); ++ if (irq < 0) ++ return irq; ++#ifdef CONFIG_INTR_REMAP ++ if (!intr_remapping_enabled) ++ goto no_ir; ++ ++ if (!sub_handle) { ++ /* ++ * allocate the consecutive block of IRTE's ++ * for 'nvec' ++ */ ++ index = msi_alloc_irte(dev, irq, nvec); ++ if (index < 0) { ++ ret = index; ++ goto error; ++ } ++ } else { ++ iommu = map_dev_to_ir(dev); ++ if (!iommu) { ++ ret = -ENOENT; ++ goto error; ++ } ++ /* ++ * setup the mapping between the irq and the IRTE ++ * base index, the sub_handle pointing to the ++ * appropriate interrupt remap table entry. ++ */ ++ set_irte_irq(irq, iommu, index, sub_handle); ++ } ++no_ir: ++#endif ++ ret = setup_msi_irq(dev, desc, irq); ++ if (ret < 0) ++ goto error; ++ sub_handle++; ++ } + return 0; ++ ++error: ++ destroy_irq(irq); ++ return ret; + } + + void arch_teardown_msi_irq(unsigned int irq) +Index: linux-2.6.26/drivers/pci/intr_remapping.c +=================================================================== +--- linux-2.6.26.orig/drivers/pci/intr_remapping.c ++++ linux-2.6.26/drivers/pci/intr_remapping.c +@@ -230,6 +230,17 @@ struct intel_iommu *map_ioapic_to_ir(int + return NULL; + } + ++struct intel_iommu *map_dev_to_ir(struct pci_dev *dev) ++{ ++ struct dmar_drhd_unit *drhd; ++ ++ drhd = dmar_find_matched_drhd_unit(dev); ++ if (!drhd) ++ return NULL; ++ ++ return drhd->iommu; ++} ++ + int free_irte(int irq) + { + int index, i; +Index: linux-2.6.26/include/asm-x86/msidef.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/msidef.h ++++ linux-2.6.26/include/asm-x86/msidef.h +@@ -48,4 +48,8 @@ + #define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \ + MSI_ADDR_DEST_ID_MASK) + ++#define MSI_ADDR_IR_EXT_INT (1 << 4) ++#define MSI_ADDR_IR_SHV (1 << 3) ++#define MSI_ADDR_IR_INDEX1(index) ((index & 0x8000) >> 13) ++#define MSI_ADDR_IR_INDEX2(index) ((index & 0x7fff) << 5) + #endif /* ASM_MSIDEF_H */ +Index: linux-2.6.26/include/linux/dmar.h +=================================================================== +--- linux-2.6.26.orig/include/linux/dmar.h ++++ linux-2.6.26/include/linux/dmar.h +@@ -109,6 +109,7 @@ extern int flush_irte(int irq); + extern int free_irte(int irq); + + extern int irq_remapped(int irq); ++extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev); + extern struct intel_iommu *map_ioapic_to_ir(int apic); + #else + #define irq_remapped(irq) (0) diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_1_of_41_4c9961d56ec20c27ec5d02e49fd7427748312741 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_1_of_41_4c9961d56ec20c27ec5d02e49fd7427748312741 new file mode 100644 index 000000000..bc6826cce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_1_of_41_4c9961d56ec20c27ec5d02e49fd7427748312741 @@ -0,0 +1,233 @@ +From: Yinghai Lu +Subject: x86: make read_apic_id return final apicid +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 4c9961d56ec20c27ec5d02e49fd7427748312741 + +Signed-off-by: Thomas Renninger + +also remove GET_APIC_ID when read_apic_id is used. + +need to apply after + [PATCH] x86: mach_apicdef.h need to include before smp.h + +Signed-off-by: Yinghai Lu +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/acpi/boot.c | 2 +- + arch/x86/kernel/apic_32.c | 4 ++-- + arch/x86/kernel/apic_64.c | 6 +++--- + arch/x86/kernel/genapic_flat_64.c | 2 +- + arch/x86/kernel/io_apic_32.c | 5 ++--- + arch/x86/kernel/io_apic_64.c | 4 ++-- + arch/x86/kernel/smpboot.c | 6 +++--- + include/asm-x86/mach-default/mach_apic.h | 2 +- + include/asm-x86/mach-default/mach_apicdef.h | 3 +-- + include/asm-x86/mach-es7000/mach_apic.h | 2 +- + include/asm-x86/smp.h | 11 ++++++++--- + 11 files changed, 25 insertions(+), 22 deletions(-) + +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -775,7 +775,7 @@ static void __init acpi_register_lapic_a + + set_fixmap_nocache(FIX_APIC_BASE, address); + if (boot_cpu_physical_apicid == -1U) { +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + #ifdef CONFIG_X86_32 + apic_version[boot_cpu_physical_apicid] = + GET_APIC_VERSION(apic_read(APIC_LVR)); +--- a/arch/x86/kernel/apic_32.c ++++ b/arch/x86/kernel/apic_32.c +@@ -1211,7 +1211,7 @@ void __init init_apic_mappings(void) + * default configuration (or the MP table is broken). + */ + if (boot_cpu_physical_apicid == -1U) +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + + } + +@@ -1248,7 +1248,7 @@ int __init APIC_init_uniprocessor(void) + * might be zero if read from MP tables. Get it from LAPIC. + */ + #ifdef CONFIG_CRASH_DUMP +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + #endif + physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); + +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -1062,7 +1062,7 @@ void __init early_init_lapic_mapping(voi + * Fetch the APIC ID of the BSP in case we have a + * default configuration (or the MP table is broken). + */ +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + } + + /** +@@ -1071,7 +1071,7 @@ void __init early_init_lapic_mapping(voi + void __init init_apic_mappings(void) + { + if (x2apic) { +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + return; + } + +@@ -1094,7 +1094,7 @@ void __init init_apic_mappings(void) + * Fetch the APIC ID of the BSP in case we have a + * default configuration (or the MP table is broken). + */ +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + } + + /* +--- a/arch/x86/kernel/genapic_flat_64.c ++++ b/arch/x86/kernel/genapic_flat_64.c +@@ -101,7 +101,7 @@ static unsigned int read_xapic_id(void) + { + unsigned int id; + +- id = GET_XAPIC_ID(apic_read(APIC_ID)); ++ id = GET_APIC_ID(apic_read(APIC_ID)); + return id; + } + +--- a/arch/x86/kernel/io_apic_32.c ++++ b/arch/x86/kernel/io_apic_32.c +@@ -1490,7 +1490,7 @@ void /*__init*/ print_local_APIC(void *d + smp_processor_id(), hard_smp_processor_id()); + v = apic_read(APIC_ID); + printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, +- GET_APIC_ID(read_apic_id())); ++ GET_APIC_ID(v)); + v = apic_read(APIC_LVR); + printk(KERN_INFO "... APIC VERSION: %08x\n", v); + ver = GET_APIC_VERSION(v); +@@ -1698,8 +1698,7 @@ void disable_IO_APIC(void) + entry.dest_mode = 0; /* Physical */ + entry.delivery_mode = dest_ExtINT; /* ExtInt */ + entry.vector = 0; +- entry.dest.physical.physical_dest = +- GET_APIC_ID(read_apic_id()); ++ entry.dest.physical.physical_dest = read_apic_id(); + + /* + * Add it to the IO-APIC irq-routing table: +--- a/arch/x86/kernel/io_apic_64.c ++++ b/arch/x86/kernel/io_apic_64.c +@@ -1245,7 +1245,7 @@ void __apicdebuginit print_local_APIC(vo + printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", + smp_processor_id(), hard_smp_processor_id()); + v = apic_read(APIC_ID); +- printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(read_apic_id())); ++ printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, read_apic_id()); + v = apic_read(APIC_LVR); + printk(KERN_INFO "... APIC VERSION: %08x\n", v); + ver = GET_APIC_VERSION(v); +@@ -1438,7 +1438,7 @@ void disable_IO_APIC(void) + entry.dest_mode = 0; /* Physical */ + entry.delivery_mode = dest_ExtINT; /* ExtInt */ + entry.vector = 0; +- entry.dest = GET_APIC_ID(read_apic_id()); ++ entry.dest = read_apic_id(); + + /* + * Add it to the IO-APIC irq-routing table: +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -211,7 +211,7 @@ static void __cpuinit smp_callin(void) + /* + * (This works even if the APIC is not enabled.) + */ +- phys_id = GET_APIC_ID(read_apic_id()); ++ phys_id = read_apic_id(); + cpuid = smp_processor_id(); + if (cpu_isset(cpuid, cpu_callin_map)) { + panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__, +@@ -1181,9 +1181,9 @@ void __init native_smp_prepare_cpus(unsi + } + + preempt_disable(); +- if (GET_APIC_ID(read_apic_id()) != boot_cpu_physical_apicid) { ++ if (read_apic_id() != boot_cpu_physical_apicid) { + panic("Boot APIC ID in local APIC unexpected (%d vs %d)", +- GET_APIC_ID(read_apic_id()), boot_cpu_physical_apicid); ++ read_apic_id(), boot_cpu_physical_apicid); + /* Or can we switch back to PIC here? */ + } + preempt_enable(); +--- a/include/asm-x86/mach-default/mach_apicdef.h ++++ b/include/asm-x86/mach-default/mach_apicdef.h +@@ -5,9 +5,8 @@ + + #ifdef CONFIG_X86_64 + #define APIC_ID_MASK (0xFFu<<24) +-#define GET_APIC_ID(x) (x) ++#define GET_APIC_ID(x) (((x)>>24) & 0xFFu) + #define SET_APIC_ID(x) (((x)<<24)) +-#define GET_XAPIC_ID(x) (((x) >> 24) & 0xFFu) + #else + #define APIC_ID_MASK (0xF<<24) + static inline unsigned get_apic_id(unsigned long x) +--- a/include/asm-x86/mach-default/mach_apic.h ++++ b/include/asm-x86/mach-default/mach_apic.h +@@ -56,7 +56,7 @@ static inline void init_apic_ldr(void) + + static inline int apic_id_registered(void) + { +- return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map); ++ return physid_isset(read_apic_id(), phys_cpu_present_map); + } + + static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) +--- a/include/asm-x86/mach-es7000/mach_apic.h ++++ b/include/asm-x86/mach-es7000/mach_apic.h +@@ -141,7 +141,7 @@ static inline void setup_portio_remap(vo + extern unsigned int boot_cpu_physical_apicid; + static inline int check_phys_apicid_present(int cpu_physical_apicid) + { +- boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ boot_cpu_physical_apicid = read_apic_id(); + return (1); + } + +--- a/include/asm-x86/smp.h ++++ b/include/asm-x86/smp.h +@@ -172,9 +172,14 @@ static inline int logical_smp_processor_ + return GET_APIC_LOGICAL_ID(*(u32 *)(APIC_BASE + APIC_LDR)); + } + ++#include + static inline unsigned int read_apic_id(void) + { +- return *(u32 *)(APIC_BASE + APIC_ID); ++ unsigned int reg; ++ ++ reg = *(u32 *)(APIC_BASE + APIC_ID); ++ ++ return GET_APIC_ID(reg); + } + #endif + +@@ -182,11 +187,11 @@ static inline unsigned int read_apic_id( + # if defined(APIC_DEFINITION) || defined(CONFIG_X86_64) + extern int hard_smp_processor_id(void); + # else +-# include ++#include + static inline int hard_smp_processor_id(void) + { + /* we don't want to mark this access volatile - bad code generation */ +- return GET_APIC_ID(read_apic_id()); ++ return read_apic_id(); + } + # endif /* APIC_DEFINITION */ + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_2_of_41_c535b6a1a685eb23f96e2c221777d6c1e05080d5 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_2_of_41_c535b6a1a685eb23f96e2c221777d6c1e05080d5 new file mode 100644 index 000000000..0787fde59 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_2_of_41_c535b6a1a685eb23f96e2c221777d6c1e05080d5 @@ -0,0 +1,93 @@ +From: Yinghai Lu +Subject: x86: let 32bit use apic_ops too +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: c535b6a1a685eb23f96e2c221777d6c1e05080d5 + +Signed-off-by: Thomas Renninger + +Signed-off-by: Yinghai Lu +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_32.c | 38 ++++++++++++++++++++++++++++++-------- + include/asm-x86/apic.h | 4 ---- + 2 files changed, 30 insertions(+), 12 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/apic_32.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_32.c ++++ linux-2.6.26/arch/x86/kernel/apic_32.c +@@ -145,19 +145,13 @@ static int modern_apic(void) + return lapic_get_version() >= 0x14; + } + +-void apic_icr_write(u32 low, u32 id) +-{ +- apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id)); +- apic_write(APIC_ICR, low); +-} +- +-void apic_wait_icr_idle(void) ++void xapic_wait_icr_idle(void) + { + while (apic_read(APIC_ICR) & APIC_ICR_BUSY) + cpu_relax(); + } + +-u32 safe_apic_wait_icr_idle(void) ++u32 safe_xapic_wait_icr_idle(void) + { + u32 send_status; + int timeout; +@@ -173,6 +167,34 @@ u32 safe_apic_wait_icr_idle(void) + return send_status; + } + ++void xapic_icr_write(u32 low, u32 id) ++{ ++ apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id)); ++ apic_write(APIC_ICR, low); ++} ++ ++u64 xapic_icr_read(void) ++{ ++ u32 icr1, icr2; ++ ++ icr2 = apic_read(APIC_ICR2); ++ icr1 = apic_read(APIC_ICR); ++ ++ return icr1 | ((u64)icr2 << 32); ++} ++ ++static struct apic_ops xapic_ops = { ++ .read = native_apic_mem_read, ++ .write = native_apic_mem_write, ++ .icr_read = xapic_icr_read, ++ .icr_write = xapic_icr_write, ++ .wait_icr_idle = xapic_wait_icr_idle, ++ .safe_wait_icr_idle = safe_xapic_wait_icr_idle, ++}; ++ ++struct apic_ops __read_mostly *apic_ops = &xapic_ops; ++EXPORT_SYMBOL_GPL(apic_ops); ++ + /** + * enable_NMI_through_LVT0 - enable NMI through local vector table 0 + */ +Index: linux-2.6.26/include/asm-x86/apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/apic.h ++++ linux-2.6.26/include/asm-x86/apic.h +@@ -49,10 +49,6 @@ extern int disable_apic; + #ifdef CONFIG_PARAVIRT + #include + #else +-#ifndef CONFIG_X86_64 +-#define apic_write native_apic_mem_write +-#define apic_read native_apic_mem_read +-#endif + #define setup_boot_clock setup_boot_APIC_clock + #define setup_secondary_clock setup_secondary_APIC_clock + #endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_of_41_6e1cb38a2aef7680975e71f23de187859ee8b158 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_of_41_6e1cb38a2aef7680975e71f23de187859ee8b158 new file mode 100644 index 000000000..d3e725fcf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_25_of_41_6e1cb38a2aef7680975e71f23de187859ee8b158 @@ -0,0 +1,353 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: add x2apic support, including enabling interrupt-remapping +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 6e1cb38a2aef7680975e71f23de187859ee8b158 + +Signed-off-by: Thomas Renninger + +x2apic support. Interrupt-remapping must be enabled before enabling x2apic, +this is needed to ensure that IO interrupts continue to work properly after the +cpu mode is changed to x2apic(which uses 32bit extended physical/cluster +apic id). + +On systems where apicid's are > 255, BIOS can handover the control to OS in +x2apic mode. Or if the OS handover was in legacy xapic mode, check +if it is capable of x2apic mode. And if we succeed in enabling +Interrupt-remapping, then we can enable x2apic mode in the CPU. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + Documentation/kernel-parameters.txt | 2 + arch/x86/kernel/acpi/boot.c | 2 + arch/x86/kernel/apic_64.c | 154 +++++++++++++++++++++++++++++++++++- + arch/x86/kernel/cpu/common_64.c | 2 + arch/x86/kernel/mpparse.c | 2 + arch/x86/kernel/setup.c | 2 + arch/x86/kernel/smpboot.c | 5 + + include/asm-x86/apic.h | 14 +-- + 8 files changed, 172 insertions(+), 11 deletions(-) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1428,6 +1428,8 @@ and is between 256 and 4096 characters. + + nolapic_timer [X86-32,APIC] Do not use the local APIC timer. + ++ nox2apic [X86-64,APIC] Do not enable x2APIC mode. ++ + noltlbs [PPC] Do not use large page/tlb entries for kernel + lowmem mapping on PPC40x. + +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -1351,7 +1351,9 @@ static void __init acpi_process_madt(voi + acpi_ioapic = 1; + + smp_found_config = 1; ++#ifdef CONFIG_X86_32 + setup_apic_routing(); ++#endif + } + } + if (error == -EINVAL) { +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -39,6 +40,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -46,8 +48,12 @@ + static int disable_apic_timer __cpuinitdata; + static int apic_calibrate_pmtmr __initdata; + int disable_apic; ++int disable_x2apic; + int x2apic; + ++/* x2apic enabled before OS handover */ ++int x2apic_preenabled; ++ + /* Local APIC timer works in C2 */ + int local_apic_timer_c2_ok; + EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); +@@ -898,6 +904,125 @@ void __cpuinit end_local_APIC_setup(void + apic_pm_activate(); + } + ++void check_x2apic(void) ++{ ++ int msr, msr2; ++ ++ rdmsr(MSR_IA32_APICBASE, msr, msr2); ++ ++ if (msr & X2APIC_ENABLE) { ++ printk("x2apic enabled by BIOS, switching to x2apic ops\n"); ++ x2apic_preenabled = x2apic = 1; ++ apic_ops = &x2apic_ops; ++ } ++} ++ ++void enable_x2apic(void) ++{ ++ int msr, msr2; ++ ++ rdmsr(MSR_IA32_APICBASE, msr, msr2); ++ if (!(msr & X2APIC_ENABLE)) { ++ printk("Enabling x2apic\n"); ++ wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0); ++ } ++} ++ ++void enable_IR_x2apic(void) ++{ ++#ifdef CONFIG_INTR_REMAP ++ int ret; ++ unsigned long flags; ++ ++ if (!cpu_has_x2apic) ++ return; ++ ++ if (!x2apic_preenabled && disable_x2apic) { ++ printk(KERN_INFO ++ "Skipped enabling x2apic and Interrupt-remapping " ++ "because of nox2apic\n"); ++ return; ++ } ++ ++ if (x2apic_preenabled && disable_x2apic) ++ panic("Bios already enabled x2apic, can't enforce nox2apic"); ++ ++ if (!x2apic_preenabled && skip_ioapic_setup) { ++ printk(KERN_INFO ++ "Skipped enabling x2apic and Interrupt-remapping " ++ "because of skipping io-apic setup\n"); ++ return; ++ } ++ ++ ret = dmar_table_init(); ++ if (ret) { ++ printk(KERN_INFO ++ "dmar_table_init() failed with %d:\n", ret); ++ ++ if (x2apic_preenabled) ++ panic("x2apic enabled by bios. But IR enabling failed"); ++ else ++ printk(KERN_INFO ++ "Not enabling x2apic,Intr-remapping\n"); ++ return; ++ } ++ ++ local_irq_save(flags); ++ mask_8259A(); ++ save_mask_IO_APIC_setup(); ++ ++ ret = enable_intr_remapping(1); ++ ++ if (ret && x2apic_preenabled) { ++ local_irq_restore(flags); ++ panic("x2apic enabled by bios. But IR enabling failed"); ++ } ++ ++ if (ret) ++ goto end; ++ ++ if (!x2apic) { ++ x2apic = 1; ++ apic_ops = &x2apic_ops; ++ enable_x2apic(); ++ } ++end: ++ if (ret) ++ /* ++ * IR enabling failed ++ */ ++ restore_IO_APIC_setup(); ++ else ++ reinit_intr_remapped_IO_APIC(x2apic_preenabled); ++ ++ unmask_8259A(); ++ local_irq_restore(flags); ++ ++ if (!ret) { ++ if (!x2apic_preenabled) ++ printk(KERN_INFO ++ "Enabled x2apic and interrupt-remapping\n"); ++ else ++ printk(KERN_INFO ++ "Enabled Interrupt-remapping\n"); ++ } else ++ printk(KERN_ERR ++ "Failed to enable Interrupt-remapping and x2apic\n"); ++#else ++ if (!cpu_has_x2apic) ++ return; ++ ++ if (x2apic_preenabled) ++ panic("x2apic enabled prior OS handover," ++ " enable CONFIG_INTR_REMAP"); ++ ++ printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping " ++ " and x2apic\n"); ++#endif ++ ++ return; ++} ++ + /* + * Detect and enable local APICs on non-SMP boards. + * Original code written by Keir Fraser. +@@ -945,6 +1070,11 @@ void __init early_init_lapic_mapping(voi + */ + void __init init_apic_mappings(void) + { ++ if (x2apic) { ++ boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id()); ++ return; ++ } ++ + /* + * If no local APIC can be found then set up a fake all + * zeroes page to simulate the local APIC and another +@@ -983,6 +1113,9 @@ int __init APIC_init_uniprocessor(void) + return -1; + } + ++ enable_IR_x2apic(); ++ setup_apic_routing(); ++ + verify_local_APIC(); + + connect_bsp_APIC(); +@@ -1236,10 +1369,14 @@ static int lapic_resume(struct sys_devic + maxlvt = lapic_get_maxlvt(); + + local_irq_save(flags); +- rdmsr(MSR_IA32_APICBASE, l, h); +- l &= ~MSR_IA32_APICBASE_BASE; +- l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; +- wrmsr(MSR_IA32_APICBASE, l, h); ++ if (!x2apic) { ++ rdmsr(MSR_IA32_APICBASE, l, h); ++ l &= ~MSR_IA32_APICBASE_BASE; ++ l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; ++ wrmsr(MSR_IA32_APICBASE, l, h); ++ } else ++ enable_x2apic(); ++ + apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED); + apic_write(APIC_ID, apic_pm_state.apic_id); + apic_write(APIC_DFR, apic_pm_state.apic_dfr); +@@ -1379,6 +1516,15 @@ __cpuinit int apic_is_clustered_box(void + return (clusters > 2); + } + ++static __init int setup_nox2apic(char *str) ++{ ++ disable_x2apic = 1; ++ clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC); ++ return 0; ++} ++early_param("nox2apic", setup_nox2apic); ++ ++ + /* + * APIC command line parameters + */ +--- a/arch/x86/kernel/cpu/common_64.c ++++ b/arch/x86/kernel/cpu/common_64.c +@@ -636,6 +636,8 @@ void __cpuinit cpu_init(void) + barrier(); + + check_efer(); ++ if (cpu != 0 && x2apic) ++ enable_x2apic(); + + /* + * set up and load the per-CPU TSS +--- a/arch/x86/kernel/mpparse.c ++++ b/arch/x86/kernel/mpparse.c +@@ -397,7 +397,9 @@ static int __init smp_read_mpc(struct mp + generic_bigsmp_probe(); + #endif + ++#ifdef CONFIG_X86_32 + setup_apic_routing(); ++#endif + if (!num_processors) + printk(KERN_ERR "MPTABLE: no processors registered!\n"); + return num_processors; +--- a/arch/x86/kernel/setup.c ++++ b/arch/x86/kernel/setup.c +@@ -769,6 +769,8 @@ void __init setup_arch(char **cmdline_p) + #else + num_physpages = max_pfn; + ++ if (cpu_has_x2apic) ++ check_x2apic(); + + /* How many end-of-memory variables you have, grandma! */ + /* need this before calling reserve_initrd */ +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -1169,6 +1169,11 @@ void __init native_smp_prepare_cpus(unsi + current_thread_info()->cpu = 0; /* needed? */ + set_cpu_sibling_map(0); + ++#ifdef CONFIG_X86_64 ++ enable_IR_x2apic(); ++ setup_apic_routing(); ++#endif ++ + if (smp_sanity_check(max_cpus) < 0) { + printk(KERN_INFO "SMP disabled\n"); + disable_smp(); +--- a/include/asm-x86/apic.h ++++ b/include/asm-x86/apic.h +@@ -93,12 +93,13 @@ static inline u32 native_apic_msr_read(u + return low; + } + +-#ifdef CONFIG_X86_32 +-extern void apic_wait_icr_idle(void); +-extern u32 safe_apic_wait_icr_idle(void); +-extern void apic_icr_write(u32 low, u32 id); +-#else +-extern void x2apic_icr_write(u32 low, u32 id); ++#ifndef CONFIG_X86_32 ++ extern int x2apic, x2apic_preenabled; ++ extern void check_x2apic(void); ++ extern void enable_x2apic(void); ++ extern void enable_IR_x2apic(void); ++ extern void x2apic_icr_write(u32 low, u32 id); ++#endif + + struct apic_ops { + u32 (*read)(u32 reg); +@@ -119,7 +120,6 @@ extern struct apic_ops *apic_ops; + #define apic_icr_write (apic_ops->icr_write) + #define apic_wait_icr_idle (apic_ops->wait_icr_idle) + #define safe_apic_wait_icr_idle (apic_ops->safe_wait_icr_idle) +-#endif + + extern int get_physical_broadcast(void); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_26_of_41_2d9579a124d746a3e0e0ba45e57d80800ee80807 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_26_of_41_2d9579a124d746a3e0e0ba45e57d80800ee80807 new file mode 100644 index 000000000..de2fcfc5e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_26_of_41_2d9579a124d746a3e0e0ba45e57d80800ee80807 @@ -0,0 +1,220 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: support for x2apic physical mode support +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 2d9579a124d746a3e0e0ba45e57d80800ee80807 + +Signed-off-by: Thomas Renninger + +x2apic Physical mode support. By default we will use x2apic cluster mode. +x2apic physical mode can be selected using "x2apic_phys" boot parameter. + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + Documentation/kernel-parameters.txt | 4 + + arch/x86/kernel/Makefile | 1 + arch/x86/kernel/genapic_64.c | 18 ++++- + arch/x86/kernel/genx2apic_phys.c | 122 ++++++++++++++++++++++++++++++++++++ + include/asm-x86/genapic_64.h | 1 + 5 files changed, 143 insertions(+), 3 deletions(-) + +--- a/arch/x86/kernel/genapic_64.c ++++ b/arch/x86/kernel/genapic_64.c +@@ -30,6 +30,15 @@ DEFINE_PER_CPU(int, x2apic_extra_bits); + + struct genapic __read_mostly *genapic = &apic_flat; + ++static int x2apic_phys = 0; ++ ++static int set_x2apic_phys_mode(char *arg) ++{ ++ x2apic_phys = 1; ++ return 0; ++} ++early_param("x2apic_phys", set_x2apic_phys_mode); ++ + static enum uv_system_type uv_system_type; + + /* +@@ -39,9 +48,12 @@ void __init setup_apic_routing(void) + { + if (uv_system_type == UV_NON_UNIQUE_APIC) + genapic = &apic_x2apic_uv_x; +- else if (cpu_has_x2apic && intr_remapping_enabled) +- genapic = &apic_x2apic_cluster; +- else ++ else if (cpu_has_x2apic && intr_remapping_enabled) { ++ if (x2apic_phys) ++ genapic = &apic_x2apic_phys; ++ else ++ genapic = &apic_x2apic_cluster; ++ } else + #ifdef CONFIG_ACPI + /* + * Quirk: some x86_64 machines can only use physical APIC mode +--- /dev/null ++++ b/arch/x86/kernel/genx2apic_phys.c +@@ -0,0 +1,122 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ ++ ++static cpumask_t x2apic_target_cpus(void) ++{ ++ return cpumask_of_cpu(0); ++} ++ ++static cpumask_t x2apic_vector_allocation_domain(int cpu) ++{ ++ cpumask_t domain = CPU_MASK_NONE; ++ cpu_set(cpu, domain); ++ return domain; ++} ++ ++static void __x2apic_send_IPI_dest(unsigned int apicid, int vector, ++ unsigned int dest) ++{ ++ unsigned long cfg; ++ ++ cfg = __prepare_ICR(0, vector, dest); ++ ++ /* ++ * send the IPI. ++ */ ++ x2apic_icr_write(cfg, apicid); ++} ++ ++static void x2apic_send_IPI_mask(cpumask_t mask, int vector) ++{ ++ unsigned long flags; ++ unsigned long query_cpu; ++ ++ local_irq_save(flags); ++ for_each_cpu_mask(query_cpu, mask) { ++ __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu), ++ vector, APIC_DEST_PHYSICAL); ++ } ++ local_irq_restore(flags); ++} ++ ++static void x2apic_send_IPI_allbutself(int vector) ++{ ++ cpumask_t mask = cpu_online_map; ++ ++ cpu_clear(smp_processor_id(), mask); ++ ++ if (!cpus_empty(mask)) ++ x2apic_send_IPI_mask(mask, vector); ++} ++ ++static void x2apic_send_IPI_all(int vector) ++{ ++ x2apic_send_IPI_mask(cpu_online_map, vector); ++} ++ ++static int x2apic_apic_id_registered(void) ++{ ++ return 1; ++} ++ ++static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask) ++{ ++ int cpu; ++ ++ /* ++ * We're using fixed IRQ delivery, can only return one phys APIC ID. ++ * May as well be the first. ++ */ ++ cpu = first_cpu(cpumask); ++ if ((unsigned)cpu < NR_CPUS) ++ return per_cpu(x86_cpu_to_apicid, cpu); ++ else ++ return BAD_APICID; ++} ++ ++static unsigned int x2apic_read_id(void) ++{ ++ return apic_read(APIC_ID); ++} ++ ++static unsigned int phys_pkg_id(int index_msb) ++{ ++ return x2apic_read_id() >> index_msb; ++} ++ ++void x2apic_send_IPI_self(int vector) ++{ ++ apic_write(APIC_SELF_IPI, vector); ++} ++ ++void init_x2apic_ldr(void) ++{ ++ return; ++} ++ ++struct genapic apic_x2apic_phys = { ++ .name = "physical x2apic", ++ .int_delivery_mode = dest_Fixed, ++ .int_dest_mode = (APIC_DEST_PHYSICAL != 0), ++ .target_cpus = x2apic_target_cpus, ++ .vector_allocation_domain = x2apic_vector_allocation_domain, ++ .apic_id_registered = x2apic_apic_id_registered, ++ .init_apic_ldr = init_x2apic_ldr, ++ .send_IPI_all = x2apic_send_IPI_all, ++ .send_IPI_allbutself = x2apic_send_IPI_allbutself, ++ .send_IPI_mask = x2apic_send_IPI_mask, ++ .send_IPI_self = x2apic_send_IPI_self, ++ .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid, ++ .phys_pkg_id = phys_pkg_id, ++ .read_apic_id = x2apic_read_id, ++}; +--- a/arch/x86/kernel/Makefile ++++ b/arch/x86/kernel/Makefile +@@ -104,6 +104,7 @@ obj-$(CONFIG_OLPC) += olpc.o + ifeq ($(CONFIG_X86_64),y) + obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o + obj-y += genx2apic_cluster.o ++ obj-y += genx2apic_phys.o + obj-y += bios_uv.o + obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o + obj-$(CONFIG_AUDIT) += audit_64.o +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1430,6 +1430,10 @@ and is between 256 and 4096 characters. + + nox2apic [X86-64,APIC] Do not enable x2APIC mode. + ++ x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of ++ default x2apic cluster mode on platforms ++ supporting x2apic. ++ + noltlbs [PPC] Do not use large page/tlb entries for kernel + lowmem mapping on PPC40x. + +--- a/include/asm-x86/genapic_64.h ++++ b/include/asm-x86/genapic_64.h +@@ -36,6 +36,7 @@ extern struct genapic *genapic; + extern struct genapic apic_flat; + extern struct genapic apic_physflat; + extern struct genapic apic_x2apic_cluster; ++extern struct genapic apic_x2apic_phys; + extern int acpi_madt_oem_check(char *, char *); + + extern void apic_send_IPI_self(int vector); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_27_of_41_9fa8c481b55e80edd8c637573f87853bb6b600f5 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_27_of_41_9fa8c481b55e80edd8c637573f87853bb6b600f5 new file mode 100644 index 000000000..dca0583d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_27_of_41_9fa8c481b55e80edd8c637573f87853bb6b600f5 @@ -0,0 +1,38 @@ +From: Suresh Siddha +Subject: x64, x2apic/intr-remap: introduce CONFIG_INTR_REMAP +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 9fa8c481b55e80edd8c637573f87853bb6b600f5 + +Signed-off-by: Thomas Renninger + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Cc: arjan@linux.intel.com +Cc: andi@firstfloor.org +Cc: ebiederm@xmission.com +Cc: jbarnes@virtuousgeek.org +Cc: steiner@sgi.com +Signed-off-by: Ingo Molnar + +--- + arch/x86/Kconfig | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1703,6 +1703,14 @@ config DMAR_FLOPPY_WA + workaround will setup a 1:1 mapping for the first + 16M to make floppy (an ISA device) work. + ++config INTR_REMAP ++ bool "Support for Interrupt Remapping (EXPERIMENTAL)" ++ depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI && EXPERIMENTAL ++ help ++ Supports Interrupt remapping for IO-APIC and MSI devices. ++ To use x2apic mode in the CPU's which support x2APIC enhancements or ++ to support platforms with CPU's having > 8 bit APIC ID, say Y. ++ + source "drivers/pci/pcie/Kconfig" + + source "drivers/pci/Kconfig" diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_28_1_of_41_f910a9dc7c865896815e2a95fe33363e9522f277 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_28_1_of_41_f910a9dc7c865896815e2a95fe33363e9522f277 new file mode 100644 index 000000000..fd9a3c428 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_28_1_of_41_f910a9dc7c865896815e2a95fe33363e9522f277 @@ -0,0 +1,252 @@ +From: Yinghai Lu +Subject: x86: make 64bit have get_apic_id +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: f910a9dc7c865896815e2a95fe33363e9522f277 + +Signed-off-by: Thomas Renninger + +generalize the x2apic code some more. + +let read_apic_id become a macro (later on a function/inline) +GET_APIC_ID(apic_read(APIC_ID)) + + +#define read_apic_id() (GET_APIC_ID(apic_read(APIC_ID))) + +instead of this weird construct: + + -#define read_apic_id (genapic->read_apic_id) + +Signed-off-by: Yinghai Lu +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genapic_flat_64.c | 26 +++++++++++++++++++++++--- + arch/x86/kernel/genx2apic_cluster.c | 20 +++++++++++++++++++- + arch/x86/kernel/genx2apic_phys.c | 20 +++++++++++++++++++- + arch/x86/kernel/genx2apic_uv_x.c | 23 ++++++++++++++++++++--- + include/asm-x86/genapic_64.h | 4 +++- + include/asm-x86/mach-default/mach_apic.h | 2 +- + include/asm-x86/mach-default/mach_apicdef.h | 6 +++--- + 7 files changed, 88 insertions(+), 13 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_flat_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +@@ -97,11 +97,27 @@ static void flat_send_IPI_all(int vector + __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); + } + ++static unsigned int get_apic_id(unsigned long x) ++{ ++ unsigned int id; ++ ++ id = (((x)>>24) & 0xFFu); ++ return id; ++} ++ ++static unsigned long set_apic_id(unsigned int id) ++{ ++ unsigned long x; ++ ++ x = ((id & 0xFFu)<<24); ++ return x; ++} ++ + static unsigned int read_xapic_id(void) + { + unsigned int id; + +- id = GET_APIC_ID(apic_read(APIC_ID)); ++ id = get_apic_id(apic_read(APIC_ID)); + return id; + } + +@@ -134,7 +150,9 @@ struct genapic apic_flat = { + .send_IPI_self = apic_send_IPI_self, + .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +- .read_apic_id = read_xapic_id, ++ .get_apic_id = get_apic_id, ++ .set_apic_id = set_apic_id, ++ .apic_id_mask = (0xFFu<<24), + }; + + /* +@@ -200,5 +218,7 @@ struct genapic apic_physflat = { + .send_IPI_self = apic_send_IPI_self, + .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +- .read_apic_id = read_xapic_id, ++ .get_apic_id = get_apic_id, ++ .set_apic_id = set_apic_id, ++ .apic_id_mask = (0xFFu<<24), + }; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_cluster.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +@@ -94,6 +94,22 @@ static unsigned int x2apic_cpu_mask_to_a + return BAD_APICID; + } + ++static unsigned int get_apic_id(unsigned long x) ++{ ++ unsigned int id; ++ ++ id = x; ++ return id; ++} ++ ++static unsigned long set_apic_id(unsigned int id) ++{ ++ unsigned long x; ++ ++ x = id; ++ return x; ++} ++ + static unsigned int x2apic_read_id(void) + { + return apic_read(APIC_ID); +@@ -131,5 +147,7 @@ struct genapic apic_x2apic_cluster = { + .send_IPI_self = x2apic_send_IPI_self, + .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +- .read_apic_id = x2apic_read_id, ++ .get_apic_id = get_apic_id, ++ .set_apic_id = set_apic_id, ++ .apic_id_mask = (0xFFFFFFFFu), + }; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_phys.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +@@ -84,6 +84,22 @@ static unsigned int x2apic_cpu_mask_to_a + return BAD_APICID; + } + ++static unsigned int get_apic_id(unsigned long x) ++{ ++ unsigned int id; ++ ++ id = x; ++ return id; ++} ++ ++static unsigned long set_apic_id(unsigned int id) ++{ ++ unsigned long x; ++ ++ x = id; ++ return x; ++} ++ + static unsigned int x2apic_read_id(void) + { + return apic_read(APIC_ID); +@@ -118,5 +134,7 @@ struct genapic apic_x2apic_phys = { + .send_IPI_self = x2apic_send_IPI_self, + .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +- .read_apic_id = x2apic_read_id, ++ .get_apic_id = get_apic_id, ++ .set_apic_id = set_apic_id, ++ .apic_id_mask = (0xFFFFFFFFu), + }; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +@@ -143,16 +143,31 @@ static unsigned int uv_cpu_mask_to_apici + return BAD_APICID; + } + +-static unsigned int uv_read_apic_id(void) ++static unsigned int get_apic_id(unsigned long x) + { + unsigned int id; + + WARN_ON(preemptible() && num_online_cpus() > 1); +- id = apic_read(APIC_ID) | __get_cpu_var(x2apic_extra_bits); ++ id = x | __get_cpu_var(x2apic_extra_bits); + + return id; + } + ++static long set_apic_id(unsigned int id) ++{ ++ unsigned long x; ++ ++ /* maskout x2apic_extra_bits ? */ ++ x = id; ++ return x; ++} ++ ++static unsigned int uv_read_apic_id(void) ++{ ++ ++ return get_apic_id(apic_read(APIC_ID)); ++} ++ + static unsigned int phys_pkg_id(int index_msb) + { + return uv_read_apic_id() >> index_msb; +@@ -179,7 +194,9 @@ struct genapic apic_x2apic_uv_x = { + /* ZZZ.send_IPI_self = uv_send_IPI_self, */ + .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ +- .read_apic_id = uv_read_apic_id, ++ .get_apic_id = get_apic_id, ++ .set_apic_id = set_apic_id, ++ .apic_id_mask = (0xFFFFFFFFu), + }; + + static __cpuinit void set_x2apic_extra_bits(int pnode) +Index: linux-2.6.26/include/asm-x86/genapic_64.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/genapic_64.h ++++ linux-2.6.26/include/asm-x86/genapic_64.h +@@ -28,7 +28,9 @@ struct genapic { + /* */ + unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask); + unsigned int (*phys_pkg_id)(int index_msb); +- unsigned int (*read_apic_id)(void); ++ unsigned int (*get_apic_id)(unsigned long x); ++ unsigned long (*set_apic_id)(unsigned int id); ++ unsigned long apic_id_mask; + }; + + extern struct genapic *genapic; +Index: linux-2.6.26/include/asm-x86/mach-default/mach_apic.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/mach-default/mach_apic.h ++++ linux-2.6.26/include/asm-x86/mach-default/mach_apic.h +@@ -30,7 +30,7 @@ static inline cpumask_t target_cpus(void + #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) + #define phys_pkg_id (genapic->phys_pkg_id) + #define vector_allocation_domain (genapic->vector_allocation_domain) +-#define read_apic_id (genapic->read_apic_id) ++#define read_apic_id() (GET_APIC_ID(apic_read(APIC_ID))) + #define send_IPI_self (genapic->send_IPI_self) + extern void setup_apic_routing(void); + #else +Index: linux-2.6.26/include/asm-x86/mach-default/mach_apicdef.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/mach-default/mach_apicdef.h ++++ linux-2.6.26/include/asm-x86/mach-default/mach_apicdef.h +@@ -4,9 +4,9 @@ + #include + + #ifdef CONFIG_X86_64 +-#define APIC_ID_MASK (0xFFu<<24) +-#define GET_APIC_ID(x) (((x)>>24) & 0xFFu) +-#define SET_APIC_ID(x) (((x)<<24)) ++#define APIC_ID_MASK (genapic->apic_id_mask) ++#define GET_APIC_ID(x) (genapic->get_apic_id(x)) ++#define SET_APIC_ID(x) (genapic->set_apic_id(x)) + #else + #define APIC_ID_MASK (0xF<<24) + static inline unsigned get_apic_id(unsigned long x) diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_29_of_41_277d1f5846d84e16760131a93b7a67ebfa8eded4 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_29_of_41_277d1f5846d84e16760131a93b7a67ebfa8eded4 new file mode 100644 index 000000000..97ece5fa0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_29_of_41_277d1f5846d84e16760131a93b7a67ebfa8eded4 @@ -0,0 +1,34 @@ +From: Suresh Siddha +Subject: x2apic: uninline uv_init_apic_ldr() +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 277d1f5846d84e16760131a93b7a67ebfa8eded4 + +Signed-off-by: Thomas Renninger + +Andrew says: +> There's no point in declaring it inline if it's always called indirectly. + +And point taken! + +Signed-off-by: Suresh Siddha +Cc: akpm@linux-foundation.org +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genx2apic_uv_x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +@@ -124,7 +124,7 @@ static int uv_apic_id_registered(void) + return 1; + } + +-static inline void uv_init_apic_ldr(void) ++static void uv_init_apic_ldr(void) + { + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_30_of_41_ad66dd340f561bdde2285992314d9e4fd9b6191e b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_30_of_41_ad66dd340f561bdde2285992314d9e4fd9b6191e new file mode 100644 index 000000000..aa14897de --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_30_of_41_ad66dd340f561bdde2285992314d9e4fd9b6191e @@ -0,0 +1,155 @@ +From: Suresh Siddha +Subject: x2apic: xen64 paravirt basic apic ops +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: ad66dd340f561bdde2285992314d9e4fd9b6191e + +Signed-off-by: Thomas Renninger + +Define the Xen specific basic apic ops, in additon to paravirt apic ops, +with some misc warning fixes. + +Signed-off-by: Suresh Siddha +Cc: Jeremy Fitzhardinge +Cc: akpm@linux-foundation.org +Signed-off-by: Ingo Molnar + +--- + arch/x86/lguest/boot.c | 4 ++-- + arch/x86/xen/enlighten.c | 41 +++++++++++++++++++++++++++++++++++++++-- + include/asm-x86/paravirt.h | 11 ++++++----- + 3 files changed, 47 insertions(+), 9 deletions(-) + +Index: linux-2.6.26/arch/x86/lguest/boot.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/lguest/boot.c ++++ linux-2.6.26/arch/x86/lguest/boot.c +@@ -783,11 +783,11 @@ static void lguest_wbinvd(void) + * code qualifies for Advanced. It will also never interrupt anything. It + * does, however, allow us to get through the Linux boot code. */ + #ifdef CONFIG_X86_LOCAL_APIC +-static void lguest_apic_write(unsigned long reg, u32 v) ++static void lguest_apic_write(u32 reg, u32 v) + { + } + +-static u32 lguest_apic_read(unsigned long reg) ++static u32 lguest_apic_read(u32 reg) + { + return 0; + } +Index: linux-2.6.26/arch/x86/xen/enlighten.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/xen/enlighten.c ++++ linux-2.6.26/arch/x86/xen/enlighten.c +@@ -580,16 +580,45 @@ static void xen_io_delay(void) + } + + #ifdef CONFIG_X86_LOCAL_APIC +-static u32 xen_apic_read(unsigned long reg) ++static u32 xen_apic_read(u32 reg) + { + return 0; + } + +-static void xen_apic_write(unsigned long reg, u32 val) ++static void xen_apic_write(u32 reg, u32 val) + { + /* Warn to see if there's any stray references */ + WARN_ON(1); + } ++ ++#ifdef CONFIG_X86_64 ++static u64 xen_apic_icr_read(void) ++{ ++ return 0; ++} ++ ++static void xen_apic_icr_write(u32 low, u32 id) ++{ ++ /* Warn to see if there's any stray references */ ++ WARN_ON(1); ++} ++ ++static void xen_apic_wait_icr_idle(void) ++{ ++ return; ++} ++ ++static struct apic_ops xen_basic_apic_ops = { ++ .read = xen_apic_read, ++ .write = xen_apic_write, ++ .write_atomic = xen_apic_write, ++ .icr_read = xen_apic_icr_read, ++ .icr_write = xen_apic_icr_write, ++ .wait_icr_idle = xen_apic_wait_icr_idle, ++ .safe_wait_icr_idle = xen_apic_wait_icr_idle, ++}; ++#endif ++ + #endif + + static void xen_flush_tlb(void) +@@ -1273,8 +1302,10 @@ static const struct pv_irq_ops xen_irq_o + + static const struct pv_apic_ops xen_apic_ops __initdata = { + #ifdef CONFIG_X86_LOCAL_APIC ++#ifndef CONFIG_X86_64 + .apic_write = xen_apic_write, + .apic_read = xen_apic_read, ++#endif + .setup_boot_clock = paravirt_nop, + .setup_secondary_clock = paravirt_nop, + .startup_ipi_hook = paravirt_nop, +@@ -1676,6 +1707,12 @@ asmlinkage void __init xen_start_kernel( + pv_irq_ops = xen_irq_ops; + pv_apic_ops = xen_apic_ops; + pv_mmu_ops = xen_mmu_ops; ++#ifdef CONFIG_X86_64 ++ /* ++ * for 64bit, set up the basic apic ops aswell. ++ */ ++ apic_ops = &xen_basic_apic_ops; ++#endif + + if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { + pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; +Index: linux-2.6.26/include/asm-x86/paravirt.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/paravirt.h ++++ linux-2.6.26/include/asm-x86/paravirt.h +@@ -200,15 +200,16 @@ struct pv_irq_ops { + + struct pv_apic_ops { + #ifdef CONFIG_X86_LOCAL_APIC ++#ifndef CONFIG_X86_64 + /* + * Direct APIC operations, principally for VMI. Ideally + * these shouldn't be in this interface. + */ +- void (*apic_write)(unsigned long reg, u32 v); +- u32 (*apic_read)(unsigned long reg); ++ void (*apic_write)(u32 reg, u32 v); ++ u32 (*apic_read)(u32 reg); ++#endif + void (*setup_boot_clock)(void); + void (*setup_secondary_clock)(void); +- + void (*startup_ipi_hook)(int phys_apicid, + unsigned long start_eip, + unsigned long start_esp); +@@ -902,12 +903,12 @@ static inline void slow_down_io(void) + * Basic functions accessing APICs. + */ + #ifndef CONFIG_X86_64 +-static inline void apic_write(unsigned long reg, u32 v) ++static inline void apic_write(u32 reg, u32 v) + { + PVOP_VCALL2(pv_apic_ops.apic_write, reg, v); + } + +-static inline u32 apic_read(unsigned long reg) ++static inline u32 apic_read(u32 reg) + { + return PVOP_CALL1(unsigned long, pv_apic_ops.apic_read, reg); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_34_of_41_1b9b89e7f163336ad84200b66a17284dbf26aced b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_34_of_41_1b9b89e7f163336ad84200b66a17284dbf26aced new file mode 100644 index 000000000..d4c54acfa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_34_of_41_1b9b89e7f163336ad84200b66a17284dbf26aced @@ -0,0 +1,365 @@ +From: Yinghai Lu +Subject: x86: add apic probe for genapic 64bit, v2 +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 1b9b89e7f163336ad84200b66a17284dbf26aced + +Signed-off-by: Thomas Renninger + +introducing an APIC handling probing abstraction: + + static struct genapic *apic_probe[] __initdata = { + &apic_x2apic_uv_x, + &apic_x2apic_phys, + &apic_x2apic_cluster, + &apic_physflat, + NULL, + }; + +This way we can remove UV, x2apic specific code from genapic_64.c and +move them to their specific genapic files. + +[ v2: fix compiling when CONFIG_ACPI is not set ] + +Signed-off-by: Yinghai Lu +Cc: Jack Steiner +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genapic_64.c | 86 ++++++++++-------------------------- + arch/x86/kernel/genapic_flat_64.c | 26 ++++++++++ + arch/x86/kernel/genx2apic_cluster.c | 11 ++++ + arch/x86/kernel/genx2apic_phys.c | 21 ++++++++ + arch/x86/kernel/genx2apic_uv_x.c | 33 +++++++++++++ + include/asm-x86/genapic_64.h | 1 + 6 files changed, 117 insertions(+), 61 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/genapic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_64.c +@@ -16,62 +16,37 @@ + #include + #include + #include +-#include + + #include + #include + #include + +-#ifdef CONFIG_ACPI +-#include +-#endif +- +-DEFINE_PER_CPU(int, x2apic_extra_bits); ++extern struct genapic apic_flat; ++extern struct genapic apic_physflat; ++extern struct genapic apic_x2xpic_uv_x; ++extern struct genapic apic_x2apic_phys; ++extern struct genapic apic_x2apic_cluster; + + struct genapic __read_mostly *genapic = &apic_flat; + +-static int x2apic_phys = 0; +- +-static int set_x2apic_phys_mode(char *arg) +-{ +- x2apic_phys = 1; +- return 0; +-} +-early_param("x2apic_phys", set_x2apic_phys_mode); +- +-static enum uv_system_type uv_system_type; ++static struct genapic *apic_probe[] __initdata = { ++ &apic_x2apic_uv_x, ++ &apic_x2apic_phys, ++ &apic_x2apic_cluster, ++ &apic_physflat, ++ NULL, ++}; + + /* + * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode. + */ + void __init setup_apic_routing(void) + { +- if (uv_system_type == UV_NON_UNIQUE_APIC) +- genapic = &apic_x2apic_uv_x; +- else if (cpu_has_x2apic && intr_remapping_enabled) { +- if (x2apic_phys) +- genapic = &apic_x2apic_phys; +- else +- genapic = &apic_x2apic_cluster; +- } else +-#ifdef CONFIG_ACPI +- /* +- * Quirk: some x86_64 machines can only use physical APIC mode +- * regardless of how many processors are present (x86_64 ES7000 +- * is an example). +- */ +- if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID && +- (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) +- genapic = &apic_physflat; +- else +-#endif +- +- if (max_physical_apicid < 8) +- genapic = &apic_flat; +- else +- genapic = &apic_physflat; +- +- printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); ++ if (genapic == &apic_flat) { ++ if (max_physical_apicid >= 8) ++ genapic = &apic_physflat; ++ printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); ++ } + } + + /* Same for both flat and physical. */ +@@ -83,24 +58,15 @@ void apic_send_IPI_self(int vector) + + int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { +- if (!strcmp(oem_id, "SGI")) { +- if (!strcmp(oem_table_id, "UVL")) +- uv_system_type = UV_LEGACY_APIC; +- else if (!strcmp(oem_table_id, "UVX")) +- uv_system_type = UV_X2APIC; +- else if (!strcmp(oem_table_id, "UVH")) +- uv_system_type = UV_NON_UNIQUE_APIC; ++ int i; ++ ++ for (i = 0; apic_probe[i]; ++i) { ++ if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { ++ genapic = apic_probe[i]; ++ printk(KERN_INFO "Setting APIC routing to %s.\n", ++ genapic->name); ++ return 1; ++ } + } + return 0; + } +- +-enum uv_system_type get_uv_system_type(void) +-{ +- return uv_system_type; +-} +- +-int is_uv_system(void) +-{ +- return uv_system_type != UV_NONE; +-} +-EXPORT_SYMBOL_GPL(is_uv_system); +Index: linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_flat_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +@@ -21,6 +21,15 @@ + #include + #include + ++#ifdef CONFIG_ACPI ++#include ++#endif ++ ++static int __init flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++{ ++ return 1; ++} ++ + static cpumask_t flat_target_cpus(void) + { + return cpu_online_map; +@@ -138,6 +147,7 @@ static unsigned int phys_pkg_id(int inde + + struct genapic apic_flat = { + .name = "flat", ++ .acpi_madt_oem_check = flat_acpi_madt_oem_check, + .int_delivery_mode = dest_LowestPrio, + .int_dest_mode = (APIC_DEST_LOGICAL != 0), + .target_cpus = flat_target_cpus, +@@ -160,6 +170,21 @@ struct genapic apic_flat = { + * We cannot use logical delivery in this case because the mask + * overflows, so use physical mode. + */ ++static int __init physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++{ ++#ifdef CONFIG_ACPI ++ /* ++ * Quirk: some x86_64 machines can only use physical APIC mode ++ * regardless of how many processors are present (x86_64 ES7000 ++ * is an example). ++ */ ++ if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID && ++ (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) ++ return 1; ++#endif ++ ++ return 0; ++} + + static cpumask_t physflat_target_cpus(void) + { +@@ -206,6 +231,7 @@ static unsigned int physflat_cpu_mask_to + + struct genapic apic_physflat = { + .name = "physical flat", ++ .acpi_madt_oem_check = physflat_acpi_madt_oem_check, + .int_delivery_mode = dest_Fixed, + .int_dest_mode = (APIC_DEST_PHYSICAL != 0), + .target_cpus = physflat_target_cpus, +Index: linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_cluster.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +@@ -4,12 +4,22 @@ + #include + #include + #include ++#include ++ + #include + #include + #include + + DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid); + ++static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++{ ++ if (cpu_has_x2apic && intr_remapping_enabled) ++ return 1; ++ ++ return 0; ++} ++ + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ + + static cpumask_t x2apic_target_cpus(void) +@@ -135,6 +145,7 @@ static void init_x2apic_ldr(void) + + struct genapic apic_x2apic_cluster = { + .name = "cluster x2apic", ++ .acpi_madt_oem_check = x2apic_acpi_madt_oem_check, + .int_delivery_mode = dest_LowestPrio, + .int_dest_mode = (APIC_DEST_LOGICAL != 0), + .target_cpus = x2apic_target_cpus, +Index: linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_phys.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +@@ -4,10 +4,30 @@ + #include + #include + #include ++#include ++ + #include + #include + #include + ++DEFINE_PER_CPU(int, x2apic_extra_bits); ++ ++static int x2apic_phys; ++ ++static int set_x2apic_phys_mode(char *arg) ++{ ++ x2apic_phys = 1; ++ return 0; ++} ++early_param("x2apic_phys", set_x2apic_phys_mode); ++ ++static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++{ ++ if (cpu_has_x2apic && intr_remapping_enabled && x2apic_phys) ++ return 1; ++ ++ return 0; ++} + + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ + +@@ -122,6 +142,7 @@ void init_x2apic_ldr(void) + + struct genapic apic_x2apic_phys = { + .name = "physical x2apic", ++ .acpi_madt_oem_check = x2apic_acpi_madt_oem_check, + .int_delivery_mode = dest_Fixed, + .int_dest_mode = (APIC_DEST_PHYSICAL != 0), + .target_cpus = x2apic_target_cpus, +Index: linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +@@ -27,6 +27,34 @@ + #include + #include + ++static enum uv_system_type uv_system_type; ++ ++static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++{ ++ if (!strcmp(oem_id, "SGI")) { ++ if (!strcmp(oem_table_id, "UVL")) ++ uv_system_type = UV_LEGACY_APIC; ++ else if (!strcmp(oem_table_id, "UVX")) ++ uv_system_type = UV_X2APIC; ++ else if (!strcmp(oem_table_id, "UVH")) { ++ uv_system_type = UV_NON_UNIQUE_APIC; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++enum uv_system_type get_uv_system_type(void) ++{ ++ return uv_system_type; ++} ++ ++int is_uv_system(void) ++{ ++ return uv_system_type != UV_NONE; ++} ++EXPORT_SYMBOL(is_uv_system); ++ + DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); + EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info); + +@@ -153,7 +181,7 @@ static unsigned int get_apic_id(unsigned + return id; + } + +-static long set_apic_id(unsigned int id) ++static unsigned long set_apic_id(unsigned int id) + { + unsigned long x; + +@@ -182,6 +210,7 @@ static void uv_send_IPI_self(int vector) + + struct genapic apic_x2apic_uv_x = { + .name = "UV large system", ++ .acpi_madt_oem_check = uv_acpi_madt_oem_check, + .int_delivery_mode = dest_Fixed, + .int_dest_mode = (APIC_DEST_PHYSICAL != 0), + .target_cpus = uv_target_cpus, +@@ -435,3 +464,5 @@ void __cpuinit uv_cpu_init(void) + if (get_uv_system_type() == UV_NON_UNIQUE_APIC) + set_x2apic_extra_bits(uv_hub_info->pnode); + } ++ ++ +Index: linux-2.6.26/include/asm-x86/genapic_64.h +=================================================================== +--- linux-2.6.26.orig/include/asm-x86/genapic_64.h ++++ linux-2.6.26/include/asm-x86/genapic_64.h +@@ -14,6 +14,7 @@ + + struct genapic { + char *name; ++ int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id); + u32 int_delivery_mode; + u32 int_dest_mode; + int (*apic_id_registered)(void); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_35_of_41_d25ae38b7e005af03843833bbd811ffe8c5f8cb4 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_35_of_41_d25ae38b7e005af03843833bbd811ffe8c5f8cb4 new file mode 100644 index 000000000..6c8a142ed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_35_of_41_d25ae38b7e005af03843833bbd811ffe8c5f8cb4 @@ -0,0 +1,72 @@ +From: Yinghai Lu +Subject: x86: add apic probe for genapic 64bit - fix +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: d25ae38b7e005af03843833bbd811ffe8c5f8cb4 + +Signed-off-by: Thomas Renninger + +intr_remapping_enabled get assigned later, so need to check that +in setup_apic_routing + +Signed-off-by: Yinghai Lu +Cc: Jack Steiner +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genapic_64.c | 6 ++++++ + arch/x86/kernel/genx2apic_cluster.c | 2 +- + arch/x86/kernel/genx2apic_phys.c | 2 +- + 3 files changed, 8 insertions(+), 2 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/genapic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_64.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -42,6 +43,11 @@ static struct genapic *apic_probe[] __in + */ + void __init setup_apic_routing(void) + { ++ if (genapic == &apic_x2apic_phys || genapic == &apic_x2apic_cluster) { ++ if (!intr_remapping_enabled) ++ genapic = &apic_flat; ++ } ++ + if (genapic == &apic_flat) { + if (max_physical_apicid >= 8) + genapic = &apic_physflat; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_cluster.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +@@ -14,7 +14,7 @@ DEFINE_PER_CPU(u32, x86_cpu_to_logical_a + + static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { +- if (cpu_has_x2apic && intr_remapping_enabled) ++ if (cpu_has_x2apic) + return 1; + + return 0; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_phys.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +@@ -23,7 +23,7 @@ early_param("x2apic_phys", set_x2apic_ph + + static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { +- if (cpu_has_x2apic && intr_remapping_enabled && x2apic_phys) ++ if (cpu_has_x2apic && x2apic_phys) + return 1; + + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_36_of_41_276605dddb74cbf1b77696e32c4a947e42cec52d b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_36_of_41_276605dddb74cbf1b77696e32c4a947e42cec52d new file mode 100644 index 000000000..a7730469e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_36_of_41_276605dddb74cbf1b77696e32c4a947e42cec52d @@ -0,0 +1,65 @@ +From: Suresh Siddha +Subject: x2apic: use x2apic id reported by cpuid during topology discovery +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 276605dddb74cbf1b77696e32c4a947e42cec52d + +Signed-off-by: Thomas Renninger + +use x2apic id reported by cpuid during topology discovery, instead of the +apic id configured in the APIC. For most of the systems, x2apic id +reported by cpuid leaf 0xb will be same as the physical apic id reported +by the APIC_ID register of the APIC. We follow the suggested guidelines +and use the apic id reported by the cpuid. + +No change to non-generic UV platforms, will use the apic id reported in the +APIC_ID register as the cpuid reported apic id's may not be unique. + +Signed-off-by: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/genx2apic_cluster.c | 7 +------ + arch/x86/kernel/genx2apic_phys.c | 7 +------ + 2 files changed, 2 insertions(+), 12 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_cluster.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +@@ -120,14 +120,9 @@ static unsigned long set_apic_id(unsigne + return x; + } + +-static unsigned int x2apic_read_id(void) +-{ +- return apic_read(APIC_ID); +-} +- + static unsigned int phys_pkg_id(int index_msb) + { +- return x2apic_read_id() >> index_msb; ++ return current_cpu_data.initial_apicid >> index_msb; + } + + static void x2apic_send_IPI_self(int vector) +Index: linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_phys.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +@@ -120,14 +120,9 @@ static unsigned long set_apic_id(unsigne + return x; + } + +-static unsigned int x2apic_read_id(void) +-{ +- return apic_read(APIC_ID); +-} +- + static unsigned int phys_pkg_id(int index_msb) + { +- return x2apic_read_id() >> index_msb; ++ return current_cpu_data.initial_apicid >> index_msb; + } + + void x2apic_send_IPI_self(int vector) diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_40_of_41_bbb65d2d365efe9951290e61678dcf81ec60add4 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_40_of_41_bbb65d2d365efe9951290e61678dcf81ec60add4 new file mode 100644 index 000000000..001c33b05 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_40_of_41_bbb65d2d365efe9951290e61678dcf81ec60add4 @@ -0,0 +1,195 @@ +From: Suresh Siddha +Subject: x86: use cpuid vector 0xb when available for detecting cpu topology +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: bbb65d2d365efe9951290e61678dcf81ec60add4 + +Signed-off-by: Thomas Renninger + +cpuid leaf 0xb provides extended topology enumeration. This interface provides +the 32-bit x2APIC id of the logical processor and it also provides a new +mechanism to detect SMT and core siblings (which provides increased +addressability). + +Signed-off-by: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/cpu/addon_cpuid_features.c | 86 +++++++++++++++++++++++++++++ + arch/x86/kernel/cpu/common_64.c | 3 + + arch/x86/kernel/cpu/intel.c | 11 +++ + arch/x86/kernel/cpu/intel_64.c | 5 + + include/asm-x86/cpufeature.h | 2 + include/asm-x86/processor.h | 1 + 6 files changed, 105 insertions(+), 3 deletions(-) + +--- a/arch/x86/kernel/cpu/addon_cpuid_features.c ++++ b/arch/x86/kernel/cpu/addon_cpuid_features.c +@@ -7,6 +7,8 @@ + #include + #include + ++#include ++ + struct cpuid_bit { + u16 feature; + u8 reg; +@@ -48,6 +50,90 @@ void __cpuinit init_scattered_cpuid_feat + } + } + ++/* leaf 0xb SMT level */ ++#define SMT_LEVEL 0 ++ ++/* leaf 0xb sub-leaf types */ ++#define INVALID_TYPE 0 ++#define SMT_TYPE 1 ++#define CORE_TYPE 2 ++ ++#define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff) ++#define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f) ++#define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff) ++ ++/* ++ * Check for extended topology enumeration cpuid leaf 0xb and if it ++ * exists, use it for populating initial_apicid and cpu topology ++ * detection. ++ */ ++void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c) ++{ ++ unsigned int eax, ebx, ecx, edx, sub_index; ++ unsigned int ht_mask_width, core_plus_mask_width; ++ unsigned int core_select_mask, core_level_siblings; ++ ++ if (c->cpuid_level < 0xb) ++ return; ++ ++ cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx); ++ ++ /* ++ * check if the cpuid leaf 0xb is actually implemented. ++ */ ++ if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) ++ return; ++ ++ set_cpu_cap(c, X86_FEATURE_XTOPOLOGY); ++ ++ /* ++ * initial apic id, which also represents 32-bit extended x2apic id. ++ */ ++ c->initial_apicid = edx; ++ ++ /* ++ * Populate HT related information from sub-leaf level 0. ++ */ ++ core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx); ++ core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); ++ ++ sub_index = 1; ++ do { ++ cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx); ++ ++ /* ++ * Check for the Core type in the implemented sub leaves. ++ */ ++ if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) { ++ core_level_siblings = LEVEL_MAX_SIBLINGS(ebx); ++ core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); ++ break; ++ } ++ ++ sub_index++; ++ } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE); ++ ++ core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width; ++ ++#ifdef CONFIG_X86_32 ++ c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width) ++ & core_select_mask; ++ c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width); ++#else ++ c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask; ++ c->phys_proc_id = phys_pkg_id(core_plus_mask_width); ++#endif ++ c->x86_max_cores = (core_level_siblings / smp_num_siblings); ++ ++ ++ printk(KERN_INFO "CPU: Physical Processor ID: %d\n", ++ c->phys_proc_id); ++ if (c->x86_max_cores > 1) ++ printk(KERN_INFO "CPU: Processor Core ID: %d\n", ++ c->cpu_core_id); ++ return; ++} ++ + #ifdef CONFIG_X86_PAT + void __cpuinit validate_pat_support(struct cpuinfo_x86 *c) + { +--- a/arch/x86/kernel/cpu/common_64.c ++++ b/arch/x86/kernel/cpu/common_64.c +@@ -128,6 +128,9 @@ void __cpuinit detect_ht(struct cpuinfo_ + u32 eax, ebx, ecx, edx; + int index_msb, core_bits; + ++ if (cpu_has(c, X86_FEATURE_XTOPOLOGY)) ++ return; ++ + cpuid(1, &eax, &ebx, &ecx, &edx); + + +--- a/arch/x86/kernel/cpu/intel_64.c ++++ b/arch/x86/kernel/cpu/intel_64.c +@@ -93,7 +93,10 @@ static void __cpuinit init_intel(struct + if (c->x86 == 6) + set_cpu_cap(c, X86_FEATURE_REP_GOOD); + set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); +- c->x86_max_cores = intel_num_cpu_cores(c); ++ ++ detect_extended_topology(c); ++ if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) ++ c->x86_max_cores = intel_num_cpu_cores(c); + + srat_detect_node(); + } +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -196,9 +196,16 @@ static void __cpuinit init_intel(struct + if (p) + strcpy(c->x86_model_id, p); + +- c->x86_max_cores = num_cpu_cores(c); ++ detect_extended_topology(c); + +- detect_ht(c); ++ if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { ++ /* ++ * let's use the legacy cpuid vector 0x1 and 0x4 for topology ++ * detection. ++ */ ++ c->x86_max_cores = num_cpu_cores(c); ++ detect_ht(c); ++ } + + /* Work around errata */ + Intel_errata_workarounds(c); +--- a/include/asm-x86/cpufeature.h ++++ b/include/asm-x86/cpufeature.h +@@ -82,6 +82,8 @@ + #define X86_FEATURE_11AP (3*32+19) /* Bad local APIC aka 11AP */ + #define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ + #define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */ ++#define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */ ++ + + /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ + #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ +--- a/include/asm-x86/processor.h ++++ b/include/asm-x86/processor.h +@@ -161,6 +161,7 @@ extern void init_scattered_cpuid_feature + extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); + extern unsigned short num_cache_leaves; + ++extern void detect_extended_topology(struct cpuinfo_x86 *c); + #if defined(CONFIG_X86_HT) || defined(CONFIG_X86_64) + extern void detect_ht(struct cpuinfo_x86 *c); + #else diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_41_of_41_11c231a962c740b3216eb6565149ae5a7944cba7 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_41_of_41_11c231a962c740b3216eb6565149ae5a7944cba7 new file mode 100644 index 000000000..dc02ad282 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_41_of_41_11c231a962c740b3216eb6565149ae5a7944cba7 @@ -0,0 +1,37 @@ +From: Suresh Siddha +Subject: x86: use x2apic id reported by cpuid during topology discovery, fix +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 11c231a962c740b3216eb6565149ae5a7944cba7 + +Signed-off-by: Thomas Renninger + +v2: Fix for !SMP build + +Signed-off-by: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/cpu/addon_cpuid_features.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.26/arch/x86/kernel/cpu/addon_cpuid_features.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/cpu/addon_cpuid_features.c ++++ linux-2.6.26/arch/x86/kernel/cpu/addon_cpuid_features.c +@@ -69,6 +69,7 @@ void __cpuinit init_scattered_cpuid_feat + */ + void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c) + { ++#ifdef CONFIG_SMP + unsigned int eax, ebx, ecx, edx, sub_index; + unsigned int ht_mask_width, core_plus_mask_width; + unsigned int core_select_mask, core_level_siblings; +@@ -132,6 +133,7 @@ void __cpuinit detect_extended_topology( + printk(KERN_INFO "CPU: Processor Core ID: %d\n", + c->cpu_core_id); + return; ++#endif + } + + #ifdef CONFIG_X86_PAT diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_42_of_41_77322deb4bc676a5ee645444e7ed1a89f854473d b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_42_of_41_77322deb4bc676a5ee645444e7ed1a89f854473d new file mode 100644 index 000000000..90c408c24 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_42_of_41_77322deb4bc676a5ee645444e7ed1a89f854473d @@ -0,0 +1,112 @@ +From: Cyrill Gorcunov +Subject: x86: io-apic - interrupt remapping fix +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 77322deb4bc676a5ee645444e7ed1a89f854473d + +Signed-off-by: Thomas Renninger + +Interrupt remapping could lead to NULL dereference in case of +kzalloc failed and memory leak in other way. So fix the +both cases. + +Signed-off-by: Cyrill Gorcunov +Cc: "Maciej W. Rozycki" +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/apic_64.c | 13 ++++++++++--- + arch/x86/kernel/io_apic_64.c | 19 +++++++++++++++++-- + 2 files changed, 27 insertions(+), 5 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_64.c ++++ linux-2.6.26/arch/x86/kernel/apic_64.c +@@ -969,7 +969,12 @@ void enable_IR_x2apic(void) + + local_irq_save(flags); + mask_8259A(); +- save_mask_IO_APIC_setup(); ++ ++ ret = save_mask_IO_APIC_setup(); ++ if (ret) { ++ printk(KERN_INFO "Saving IO-APIC state failed: %d\n", ret); ++ goto end; ++ } + + ret = enable_intr_remapping(1); + +@@ -979,14 +984,15 @@ void enable_IR_x2apic(void) + } + + if (ret) +- goto end; ++ goto end_restore; + + if (!x2apic) { + x2apic = 1; + apic_ops = &x2apic_ops; + enable_x2apic(); + } +-end: ++ ++ end_restore: + if (ret) + /* + * IR enabling failed +@@ -995,6 +1001,7 @@ end: + else + reinit_intr_remapped_IO_APIC(x2apic_preenabled); + ++ end: + unmask_8259A(); + local_irq_restore(flags); + +Index: linux-2.6.26/arch/x86/kernel/io_apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/io_apic_64.c ++++ linux-2.6.26/arch/x86/kernel/io_apic_64.c +@@ -474,7 +474,7 @@ int save_mask_IO_APIC_setup(void) + kzalloc(sizeof(struct IO_APIC_route_entry) * + nr_ioapic_registers[apic], GFP_KERNEL); + if (!early_ioapic_entries[apic]) +- return -ENOMEM; ++ goto nomem; + } + + for (apic = 0; apic < nr_ioapics; apic++) +@@ -489,16 +489,31 @@ int save_mask_IO_APIC_setup(void) + } + } + return 0; ++ ++ nomem: ++ for (; apic > 0; apic--) ++ kfree(early_ioapic_entries[apic]); ++ kfree(early_ioapic_entries[apic]); ++ memset(early_ioapic_entries, 0, ++ ARRAY_SIZE(early_ioapic_entries)); ++ ++ return -ENOMEM; ++ + } + + void restore_IO_APIC_setup(void) + { + int apic, pin; + +- for (apic = 0; apic < nr_ioapics; apic++) ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ if (!early_ioapic_entries[apic]) ++ break; + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) + ioapic_write_entry(apic, pin, + early_ioapic_entries[apic][pin]); ++ kfree(early_ioapic_entries[apic]); ++ early_ioapic_entries[apic] = NULL; ++ } + } + + void reinit_intr_remapped_IO_APIC(int intr_remapping) diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_43_of_41_2c72d93f6593f386f5760ca8e7ac7026948c31d7 b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_43_of_41_2c72d93f6593f386f5760ca8e7ac7026948c31d7 new file mode 100644 index 000000000..d579a24d3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_43_of_41_2c72d93f6593f386f5760ca8e7ac7026948c31d7 @@ -0,0 +1,44 @@ +From: Yinghai Lu +Subject: x2apic: fix reserved APIC register accesses in print_local_APIC() +References: fate #303948 and fate #303984 +Patch-Mainline: queued for .28 +Commit-ID: 2c72d93f6593f386f5760ca8e7ac7026948c31d7 + +Signed-off-by: Thomas Renninger + +APIC_ARBPRI is a reserved register for XAPIC and beyond. +APIC_RRR is a reserved register except for 82489DX, APIC for Pentium processors. +APIC_EOI is a write only register. +APIC_DFR is reserved in x2apic mode. + +Access to these registers in x2apic will result in #GP fault. Fix these +apic register accesses. + +Signed-off-by: Yinghai Lu +Signed-off-by: Suresh Siddha +Cc: Maciej W. Rozycki +Signed-off-by: Ingo Molnar + +--- + arch/x86/kernel/io_apic_32.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/io_apic_32.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/io_apic_32.c ++++ linux-2.6.26/arch/x86/kernel/io_apic_32.c +@@ -1500,9 +1500,11 @@ void /*__init*/ print_local_APIC(void *d + printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); + + if (APIC_INTEGRATED(ver)) { /* !82489DX */ +- v = apic_read(APIC_ARBPRI); +- printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, +- v & APIC_ARBPRI_MASK); ++ if (!APIC_XAPIC(ver)) { ++ v = apic_read(APIC_ARBPRI); ++ printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, ++ v & APIC_ARBPRI_MASK); ++ } + v = apic_read(APIC_PROCPRI); + printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_x86-mach_apicdef.h-need-to-include-before-smp.h.patch b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_x86-mach_apicdef.h-need-to-include-before-smp.h.patch new file mode 100644 index 000000000..188417257 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_PATCH_x86-mach_apicdef.h-need-to-include-before-smp.h.patch @@ -0,0 +1,110 @@ +From: Yinghai Lu +Subject: x86: mach_apicdef.h need to include before smp.h +Patch-mainline: 2.6.28 + + +commit 4696ca5bfd2697f5686f96d59cf0b6de14869b4e +Author: Yinghai Lu +Date: Fri Jul 11 18:43:10 2008 -0700 + +x86: mach_apicdef.h need to include before smp.h + +smp.h internal has include, so need to include that at first +when genericarch use them need to have different apicdef.h + +Signed-off-by: Yinghai Lu +Cc: Suresh Siddha +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- a/arch/x86/mach-generic/bigsmp.c ++++ b/arch/x86/mach-generic/bigsmp.c +@@ -5,17 +5,16 @@ + #define APIC_DEFINITION 1 + #include + #include +-#include + #include + #include + #include + #include + #include +-#include + #include + #include +-#include + #include ++#include ++#include + #include + #include + +diff --git a/arch/x86/mach-generic/es7000.c b/arch/x86/mach-generic/es7000.c +index 4742626..9b30547 100644 +--- a/arch/x86/mach-generic/es7000.c ++++ b/arch/x86/mach-generic/es7000.c +@@ -4,16 +4,15 @@ + #define APIC_DEFINITION 1 + #include + #include +-#include + #include + #include + #include + #include + #include + #include +-#include + #include + #include ++#include + #include + #include + #include +diff --git a/arch/x86/mach-generic/numaq.c b/arch/x86/mach-generic/numaq.c +index 8091e68..95c07ef 100644 +--- a/arch/x86/mach-generic/numaq.c ++++ b/arch/x86/mach-generic/numaq.c +@@ -4,7 +4,6 @@ + #define APIC_DEFINITION 1 + #include + #include +-#include + #include + #include + #include +@@ -12,8 +11,9 @@ + #include + #include + #include +-#include + #include ++#include ++#include + #include + #include + #include +diff --git a/arch/x86/mach-generic/summit.c b/arch/x86/mach-generic/summit.c +index a97ea0f..752edd9 100644 +--- a/arch/x86/mach-generic/summit.c ++++ b/arch/x86/mach-generic/summit.c +@@ -4,17 +4,16 @@ + #define APIC_DEFINITION 1 + #include + #include +-#include + #include + #include + #include + #include + #include + #include +-#include + #include +-#include + #include ++#include ++#include + #include + #include + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x2APIC_fix_section_mismatch.patch b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_fix_section_mismatch.patch new file mode 100644 index 000000000..f3dd5fe35 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x2APIC_fix_section_mismatch.patch @@ -0,0 +1,112 @@ +From: Thomas Renninger +Subject: Fix several section mismatches +References: none +Patch-Mainline: not yet + +Signed-off-by: Thomas Renninger + +--- + arch/x86/kernel/apic_64.c | 2 +- + arch/x86/kernel/genapic_64.c | 4 ++-- + arch/x86/kernel/genapic_flat_64.c | 4 ++-- + arch/x86/kernel/genx2apic_cluster.c | 2 +- + arch/x86/kernel/genx2apic_phys.c | 2 +- + arch/x86/kernel/genx2apic_uv_x.c | 2 +- + 6 files changed, 8 insertions(+), 8 deletions(-) + +Index: linux-2.6.26/arch/x86/kernel/genapic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_64.c +@@ -30,7 +30,7 @@ extern struct genapic apic_x2apic_cluste + + struct genapic __read_mostly *genapic = &apic_flat; + +-static struct genapic *apic_probe[] __initdata = { ++static struct genapic *apic_probe[] = { + &apic_x2apic_uv_x, + &apic_x2apic_phys, + &apic_x2apic_cluster, +@@ -62,7 +62,7 @@ void apic_send_IPI_self(int vector) + __send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL); + } + +-int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++int acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { + int i; + +Index: linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genapic_flat_64.c ++++ linux-2.6.26/arch/x86/kernel/genapic_flat_64.c +@@ -25,7 +25,7 @@ + #include + #endif + +-static int __init flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { + return 1; + } +@@ -170,7 +170,7 @@ struct genapic apic_flat = { + * We cannot use logical delivery in this case because the mask + * overflows, so use physical mode. + */ +-static int __init physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { + #ifdef CONFIG_ACPI + /* +Index: linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_cluster.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_cluster.c +@@ -12,7 +12,7 @@ + + DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid); + +-static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { + if (cpu_has_x2apic) + return 1; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_phys.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_phys.c +@@ -21,7 +21,7 @@ static int set_x2apic_phys_mode(char *ar + } + early_param("x2apic_phys", set_x2apic_phys_mode); + +-static int __init x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { + if (cpu_has_x2apic && x2apic_phys) + return 1; +Index: linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.26/arch/x86/kernel/genx2apic_uv_x.c +@@ -29,7 +29,7 @@ + + static enum uv_system_type uv_system_type; + +-static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ++static int uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { + if (!strcmp(oem_id, "SGI")) { + if (!strcmp(oem_table_id, "UVL")) +Index: linux-2.6.26/arch/x86/kernel/apic_64.c +=================================================================== +--- linux-2.6.26.orig/arch/x86/kernel/apic_64.c ++++ linux-2.6.26/arch/x86/kernel/apic_64.c +@@ -928,7 +928,7 @@ void enable_x2apic(void) + } + } + +-void enable_IR_x2apic(void) ++void __init enable_IR_x2apic(void) + { + #ifdef CONFIG_INTR_REMAP + int ret; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-acpi-reroute-PCI-interrupt-to-legacy-boot-interrupt.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-acpi-reroute-PCI-interrupt-to-legacy-boot-interrupt.patch new file mode 100644 index 000000000..8c6b3ef24 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-acpi-reroute-PCI-interrupt-to-legacy-boot-interrupt.patch @@ -0,0 +1,153 @@ +From: Stefan Assmann +Subject: pci, acpi: reroute PCI interrupt to legacy boot interrupt equivalent + +Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the +IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel +does during interrupt handling). On chipsets where this INTx generation +cannot be disabled, we reroute the valid interrupts to their legacy +equivalent to get rid of spurious interrupts that might otherwise bring +down (vital) interrupt lines through spurious interrupt detection in +note_interrupt(). + +This patch benefited from discussions with Alexander Graf, Torsten Duwe, +Ihno Krumreich, Daniel Gollub, Hannes Reinecke. The conclusions we drew +and the patch itself are the authors' responsibility alone. + +Signed-off-by: Stefan Assmann +Signed-off-by: Olaf Dabrunz +Signed-off-by: Ingo Molnar +--- + drivers/acpi/pci_irq.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/pci/quirks.c | 26 ++++++++++++++++++++++ + include/linux/pci.h | 6 +++++ + 3 files changed, 88 insertions(+) + +--- a/drivers/acpi/pci_irq.c ++++ b/drivers/acpi/pci_irq.c +@@ -384,6 +384,27 @@ acpi_pci_free_irq(struct acpi_prt_entry + return irq; + } + ++#ifdef CONFIG_X86_IO_APIC ++extern int noioapicquirk; ++ ++static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) ++{ ++ struct pci_bus *bus_it; ++ ++ for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { ++ if (!bus_it->self) ++ return 0; ++ ++ printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor, ++ bus_it->self->device); ++ ++ if (bus_it->self->irq_reroute_variant) ++ return bus_it->self->irq_reroute_variant; ++ } ++ return 0; ++} ++#endif /* CONFIG_X86_IO_APIC */ ++ + /* + * acpi_pci_irq_lookup + * success: return IRQ >= 0 +@@ -413,6 +434,41 @@ acpi_pci_irq_lookup(struct pci_bus *bus, + } + + ret = func(entry, triggering, polarity, link); ++ ++#ifdef CONFIG_X86_IO_APIC ++ /* ++ * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the ++ * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel ++ * does during interrupt handling). When this INTx generation cannot be ++ * disabled, we reroute these interrupts to their legacy equivalent to ++ * get rid of spurious interrupts. ++ */ ++ if (!noioapicquirk) { ++ switch (bridge_has_boot_interrupt_variant(bus)) { ++ case 0: ++ /* no rerouting necessary */ ++ break; ++ ++ case INTEL_IRQ_REROUTE_VARIANT: ++ /* ++ * Remap according to INTx routing table in 6700PXH ++ * specs, intel order number 302628-002, section ++ * 2.15.2. Other chipsets (80332, ...) have the same ++ * mapping and are handled here as well. ++ */ ++ printk(KERN_INFO "pci irq %d -> rerouted to legacy " ++ "irq %d\n", ret, (ret % 4) + 16); ++ ret = (ret % 4) + 16; ++ break; ++ ++ default: ++ printk(KERN_INFO "not rerouting irq %d to legacy irq: " ++ "unknown mapping\n", ret); ++ break; ++ } ++ } ++#endif /* CONFIG_X86_IO_APIC */ ++ + return ret; + } + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1425,6 +1425,32 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + + #ifdef CONFIG_X86_IO_APIC + /* ++ * Boot interrupts on some chipsets cannot be turned off. For these chipsets, ++ * remap the original interrupt in the linux kernel to the boot interrupt, so ++ * that a PCI device's interrupt handler is installed on the boot interrupt ++ * line instead. ++ */ ++static void quirk_reroute_to_boot_interrupts_intel(struct pci_dev *dev) ++{ ++ if (noioapicquirk) ++ return; ++ ++ dev->irq_reroute_variant = INTEL_IRQ_REROUTE_VARIANT; ++ ++ printk(KERN_INFO "PCI quirk: reroute interrupts for 0x%04x:0x%04x\n", ++ dev->vendor, dev->device); ++ return; ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); ++ ++/* + * On some chipsets we can disable the generation of legacy INTx boot + * interrupts. + */ +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -133,6 +133,11 @@ enum pci_dev_flags { + PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, + }; + ++enum pci_irq_reroute_variant { ++ INTEL_IRQ_REROUTE_VARIANT = 1, ++ MAX_IRQ_REROUTE_VARIANTS = 3 ++}; ++ + typedef unsigned short __bitwise pci_bus_flags_t; + enum pci_bus_flags { + PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, +@@ -217,6 +222,7 @@ struct pci_dev { + unsigned int no_msi:1; /* device may not use msi */ + unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ + unsigned int broken_parity_status:1; /* Device generates false positive parity */ ++ unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ + unsigned int msi_enabled:1; + unsigned int msix_enabled:1; + unsigned int is_managed:1; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-add-PCI-IDs-for-devices-that-need-boot-irq-quirk.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-add-PCI-IDs-for-devices-that-need-boot-irq-quirk.patch new file mode 100644 index 000000000..d250c77ce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-add-PCI-IDs-for-devices-that-need-boot-irq-quirk.patch @@ -0,0 +1,31 @@ +From: Olaf Dabrunz +Subject: pci: add PCI IDs for devices that need boot irq quirks + +Signed-off-by: Stefan Assmann +Signed-off-by: Olaf Dabrunz +Signed-off-by: Ingo Molnar +--- + include/linux/pci_ids.h | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -2279,6 +2279,10 @@ + #define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 + #define PCI_DEVICE_ID_INTEL_PXH_1 0x032A + #define PCI_DEVICE_ID_INTEL_PXHV 0x032C ++#define PCI_DEVICE_ID_INTEL_80332_0 0x0330 ++#define PCI_DEVICE_ID_INTEL_80332_1 0x0332 ++#define PCI_DEVICE_ID_INTEL_80333_0 0x0370 ++#define PCI_DEVICE_ID_INTEL_80333_1 0x0372 + #define PCI_DEVICE_ID_INTEL_82375 0x0482 + #define PCI_DEVICE_ID_INTEL_82424 0x0483 + #define PCI_DEVICE_ID_INTEL_82378 0x0484 +@@ -2354,6 +2358,7 @@ + #define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4 + #define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 + #define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab ++#define PCI_DEVICE_ID_INTEL_ESB_10 0x25ac + #define PCI_DEVICE_ID_INTEL_82820_HB 0x2500 + #define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501 + #define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-apic-force-bigsmp-apic-on-IBM-EXA3-4.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-apic-force-bigsmp-apic-on-IBM-EXA3-4.patch new file mode 100644 index 000000000..312404e14 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-apic-force-bigsmp-apic-on-IBM-EXA3-4.patch @@ -0,0 +1,78 @@ +From: IBM +Subject: Use apic=bigsmp on specific xseries machines +References: bnc#440497 +Patch-Mainline: not yet + +Signed-off-by: Thomas Renninger + +diff -pruN a/arch//x86/mach-generic/bigsmp.c b/arch//x86/mach-generic/bigsmp.c +--- a/arch/x86/mach-generic/bigsmp.c 2008-12-02 09:42:57.000000000 -0800 ++++ b/arch/x86/mach-generic/bigsmp.c 2008-12-02 11:45:16.000000000 -0800 +@@ -20,7 +20,7 @@ + + static int dmi_bigsmp; /* can be set by dmi scanners */ + +-static int hp_ht_bigsmp(const struct dmi_system_id *d) ++static int force_bigsmp_apic(const struct dmi_system_id *d) + { + printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); + dmi_bigsmp = 1; +@@ -29,15 +29,35 @@ static int hp_ht_bigsmp(const struct dmi + + + static const struct dmi_system_id bigsmp_dmi_table[] = { +- { hp_ht_bigsmp, "HP ProLiant DL760 G2", ++ { force_bigsmp_apic, "HP ProLiant DL760 G2", + { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_BIOS_VERSION, "P44-"),} + }, + +- { hp_ht_bigsmp, "HP ProLiant DL740", ++ { force_bigsmp_apic, "HP ProLiant DL740", + { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), + DMI_MATCH(DMI_BIOS_VERSION, "P47-"),} + }, ++ ++ { force_bigsmp_apic, "IBM x260 / x366 / x460", ++ { DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "-[ZT"),} ++ }, ++ ++ { force_bigsmp_apic, "IBM x3800 / x3850 / x3950", ++ { DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "-[ZU"),} ++ }, ++ ++ { force_bigsmp_apic, "IBM x3800 / x3850 / x3950", ++ { DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "-[ZS"),} ++ }, ++ ++ { force_bigsmp_apic, "IBM x3850 M2 / x3950 M2", ++ { DMI_MATCH(DMI_BIOS_VENDOR, "IBM"), ++ DMI_MATCH(DMI_BIOS_VERSION, "-[A3"),} ++ }, + { } + }; + +diff -pruN a/arch//x86/mach-generic/probe.c b/arch//x86/mach-generic/probe.c +--- a/arch/x86/mach-generic/probe.c 2008-12-02 09:43:18.000000000 -0800 ++++ b/arch/x86/mach-generic/probe.c 2008-12-02 09:43:52.000000000 -0800 +@@ -106,7 +106,7 @@ int __init mps_oem_check(struct mp_confi + int i; + for (i = 0; apic_probe[i]; ++i) { + if (apic_probe[i]->mps_oem_check(mpc, oem, productid)) { +- if (!cmdline_apic) { ++ if (!cmdline_apic && genapic == &apic_default) { + genapic = apic_probe[i]; + printk(KERN_INFO "Switched to APIC driver `%s'.\n", + genapic->name); +@@ -122,7 +122,7 @@ int __init acpi_madt_oem_check(char *oem + int i; + for (i = 0; apic_probe[i]; ++i) { + if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { +- if (!cmdline_apic) { ++ if (!cmdline_apic && genapic == &apic_default) { + genapic = apic_probe[i]; + printk(KERN_INFO "Switched to APIC driver `%s'.\n", + genapic->name); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-call-boot-IRQ-quirks-at-end-of-device-init-and-during-resume.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-call-boot-IRQ-quirks-at-end-of-device-init-and-during-resume.patch new file mode 100644 index 000000000..5f61eaa73 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-call-boot-IRQ-quirks-at-end-of-device-init-and-during-resume.patch @@ -0,0 +1,91 @@ +From: Olaf Dabrunz +Subject: call boot IRQ quirks at end of device init and during resume + +It is not necessary to call boot IRQ quirks before the BARs of the bridges are +probed. The normal case is to use DECLARE_PCI_FIXUP_FINAL, so we use this +instead now. + +After a resume, we need to call the quirks again. + +Signed-off-by: Olaf Dabrunz +Signed-off-by: Stefan Assmann +--- + drivers/pci/quirks.c | 39 ++++++++++++++++++++++++++------------- + 1 file changed, 26 insertions(+), 13 deletions(-) + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1420,14 +1420,22 @@ static void quirk_reroute_to_boot_interr + dev->vendor, dev->device); + return; + } +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); + + /* + * On some chipsets we can disable the generation of legacy INTx boot +@@ -1455,7 +1463,8 @@ static void quirk_disable_intel_boot_int + printk(KERN_INFO "disabled boot interrupt on device 0x%04x:0x%04x\n", + dev->vendor, dev->device); + } +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); + + /* + * disable boot interrupts on HT-1000 +@@ -1487,7 +1496,8 @@ static void quirk_disable_broadcom_boot_ + printk(KERN_INFO "disabled boot interrupts on PCI device" + "0x%04x:0x%04x\n", dev->vendor, dev->device); + } +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); + + /* + * disable boot interrupts on AMD and ATI chipsets +@@ -1514,8 +1524,10 @@ static void quirk_disable_amd_813x_boot_ + printk(KERN_INFO "disabled boot interrupts on PCI device " + "0x%04x:0x%04x\n", dev->vendor, dev->device); + } +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); + + #define AMD_8111_PCI_IRQ_ROUTING 0x56 + +@@ -1537,7 +1549,8 @@ static void quirk_disable_amd_8111_boot_ + printk(KERN_INFO "disabled boot interrupts on PCI device " + "0x%04x:0x%04x\n", dev->vendor, dev->device); + } +-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, quirk_disable_amd_8111_boot_interrupt); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, quirk_disable_amd_8111_boot_interrupt); ++DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, quirk_disable_amd_8111_boot_interrupt); + #endif /* CONFIG_X86_IO_APIC */ + + /* diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-disable-AMD-ATI-boot-interrupt-generation.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-disable-AMD-ATI-boot-interrupt-generation.patch new file mode 100644 index 000000000..dc7f28e9f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-disable-AMD-ATI-boot-interrupt-generation.patch @@ -0,0 +1,103 @@ +From: Olaf Dabrunz + +Subject: Disable AMD/ATI legacy boot interrupt generation + +Add quirks for several AMD/ATI chipsets to prevent generation of legacy boot +interrupts. + +Integrates a separate older quirk to make IO-APIC mode work on AMD 8131 rev. A0 +and B0, which was due to an AMD erratum. + +Signed-off-by: Olaf Dabrunz +Signed-off-by: Stefan Assmann +--- + drivers/pci/quirks.c | 71 +++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 50 insertions(+), 21 deletions(-) + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -603,27 +603,6 @@ static void __init quirk_ioapic_rmw(stru + sis_apic_bug = 1; + } + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); +- +-#define AMD8131_revA0 0x01 +-#define AMD8131_revB0 0x11 +-#define AMD8131_MISC 0x40 +-#define AMD8131_NIOAMODE_BIT 0 +-static void quirk_amd_8131_ioapic(struct pci_dev *dev) +-{ +- unsigned char tmp; +- +- if (nr_ioapics == 0) +- return; +- +- if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) { +- dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n"); +- pci_read_config_byte( dev, AMD8131_MISC, &tmp); +- tmp &= ~(1 << AMD8131_NIOAMODE_BIT); +- pci_write_config_byte( dev, AMD8131_MISC, tmp); +- } +-} +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); +-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); + #endif /* CONFIG_X86_IO_APIC */ + + /* +@@ -1509,6 +1488,56 @@ static void quirk_disable_broadcom_boot_ + "0x%04x:0x%04x\n", dev->vendor, dev->device); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); ++ ++/* ++ * disable boot interrupts on AMD and ATI chipsets ++ */ ++/* ++ * NOIOAMODE needs to be disabled to disable "boot interrupts". For AMD 8131 ++ * rev. A0 and B0, NOIOAMODE needs to be disabled anyway to fix IO-APIC mode ++ * (due to an erratum). ++ */ ++#define AMD_813X_MISC 0x40 ++#define AMD_813X_NOIOAMODE (1<<0) ++ ++static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) ++{ ++ u32 pci_config_dword; ++ ++ if (noioapicquirk) ++ return; ++ ++ pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword); ++ pci_config_dword &= ~AMD_813X_NOIOAMODE; ++ pci_write_config_dword(dev, AMD_813X_MISC, pci_config_dword); ++ ++ printk(KERN_INFO "disabled boot interrupts on PCI device " ++ "0x%04x:0x%04x\n", dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); ++ ++#define AMD_8111_PCI_IRQ_ROUTING 0x56 ++ ++static void quirk_disable_amd_8111_boot_interrupt(struct pci_dev *dev) ++{ ++ u16 pci_config_word; ++ ++ if (noioapicquirk) ++ return; ++ ++ pci_read_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, &pci_config_word); ++ if (!pci_config_word) { ++ printk(KERN_INFO "boot interrupts on PCI device 0x%04x:0x%04x " ++ "already disabled\n", ++ dev->vendor, dev->device); ++ return; ++ } ++ pci_write_config_word(dev, AMD_8111_PCI_IRQ_ROUTING, 0); ++ printk(KERN_INFO "disabled boot interrupts on PCI device " ++ "0x%04x:0x%04x\n", dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, quirk_disable_amd_8111_boot_interrupt); + #endif /* CONFIG_X86_IO_APIC */ + + /* diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-disable-broadcomm-boot-interrupt-generation.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-disable-broadcomm-boot-interrupt-generation.patch new file mode 100644 index 000000000..21afbfe9d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-disable-broadcomm-boot-interrupt-generation.patch @@ -0,0 +1,51 @@ +From: Olaf Dabrunz + +Subject: Add quirk to disable boot interrupt generation on broadcom HT1000 + +Signed-off-by: Olaf Dabrunz +Signed-off-by: Stefan Assmann +--- + drivers/pci/quirks.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1477,6 +1477,38 @@ static void quirk_disable_intel_boot_int + dev->vendor, dev->device); + } + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); ++ ++/* ++ * disable boot interrupts on HT-1000 ++ */ ++#define BC_HT1000_FEATURE_REG 0x64 ++#define BC_HT1000_PIC_REGS_ENABLE (1<<0) ++#define BC_HT1000_MAP_IDX 0xC00 ++#define BC_HT1000_MAP_DATA 0xC01 ++ ++static void quirk_disable_broadcom_boot_interrupt(struct pci_dev *dev) ++{ ++ u32 pci_config_dword; ++ u8 irq; ++ ++ if (noioapicquirk) ++ return; ++ ++ pci_read_config_dword(dev, BC_HT1000_FEATURE_REG, &pci_config_dword); ++ pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword | ++ BC_HT1000_PIC_REGS_ENABLE); ++ ++ for (irq = 0x10; irq < 0x10 + 32; irq++) { ++ outb(irq, BC_HT1000_MAP_IDX); ++ outb(0x00, BC_HT1000_MAP_DATA); ++ } ++ ++ pci_write_config_dword(dev, BC_HT1000_FEATURE_REG, pci_config_dword); ++ ++ printk(KERN_INFO "disabled boot interrupts on PCI device" ++ "0x%04x:0x%04x\n", dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB, quirk_disable_broadcom_boot_interrupt); + #endif /* CONFIG_X86_IO_APIC */ + + /* diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-disable-intel-boot-interrupt-generation.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-disable-intel-boot-interrupt-generation.patch new file mode 100644 index 000000000..56bf1f475 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-disable-intel-boot-interrupt-generation.patch @@ -0,0 +1,56 @@ +From: Stefan Assmann +Subject: pci: add quirk to disable boot interrupt generation on intel 6300ESB + +Add a quirk to disable legacy boot interrupt generation on intel devices +that support disabling it. + +This patch benefited from discussions with Alexander Graf, Torsten Duwe, +Ihno Krumreich, Daniel Gollub, Hannes Reinecke. The conclusions we drew +and the patch itself are the authors' responsibility alone. + +Signed-off-by: Stefan Assmann +Signed-off-by: Olaf Dabrunz +Signed-off-by: Ingo Molnar +--- + drivers/pci/quirks.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1423,6 +1423,36 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); + ++#ifdef CONFIG_X86_IO_APIC ++/* ++ * On some chipsets we can disable the generation of legacy INTx boot ++ * interrupts. ++ */ ++ ++/* ++ * IO-APIC1 on 6300ESB generates boot interrupts, see intel order no ++ * 300641-004US, section 5.7.3. ++ */ ++#define INTEL_6300_IOAPIC_ABAR 0x40 ++#define INTEL_6300_DISABLE_BOOT_IRQ (1<<14) ++ ++static void quirk_disable_intel_boot_interrupt(struct pci_dev *dev) ++{ ++ u16 pci_config_word; ++ ++ if (noioapicquirk) ++ return; ++ ++ pci_read_config_word(dev, INTEL_6300_IOAPIC_ABAR, &pci_config_word); ++ pci_config_word |= INTEL_6300_DISABLE_BOOT_IRQ; ++ pci_write_config_word(dev, INTEL_6300_IOAPIC_ABAR, pci_config_word); ++ ++ printk(KERN_INFO "disabled boot interrupt on device 0x%04x:0x%04x\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_10, quirk_disable_intel_boot_interrupt); ++#endif /* CONFIG_X86_IO_APIC */ ++ + /* + * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size + * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes. diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-fix-kmap-contig.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-fix-kmap-contig.patch new file mode 100644 index 000000000..33e43ac99 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-fix-kmap-contig.patch @@ -0,0 +1,183 @@ +From: Nick Piggin +Subject: x86: contiguous kmap fix +References: bnc#449812 +Patch-mainline: perhaps 2.6.30 (maybe .29) + +The early fixmap pmd entry inserted at the very top of the KVA is casing the +subsequent fixmap mapping code to not provide physically linear pte pages over +the kmap atomic portion of the fixmap (which relies on said property to calculate +pte address). + +This has caused weird boot failures in kmap_atomic much later in the boot +process (initial userspace faults) on a 32-bit PAE system with a larger number +of CPUs (smaller CPU counts tend not to run over into the next page so don't +show up the problem). + +Solve this by attempting to clear out the page table, and copy any of its +entries to the new one. Also, add a bug if a nonlinear condition is encountered +and can't be resolved, which might save some hours of debugging if this fragile +scheme ever breaks again... + +Signed-off-by: Nick Piggin + +Once we have such logic, we can also use it to eliminate the early ioremap +trickery around the page table setup for the fixmap area. This also fixes +potential issues with FIX_* entries sharing the leaf page table with the early +ioremap ones getting discarded by early_ioremap_clear() and not restored by +early_ioremap_reset(). It at once eliminates the temporary (and configuration, +namely NR_CPUS, dependent) unavailability of early fixed mappings during the +time the fixmap area page tables get constructed. + +Finally, also replace the hard coded calculation of the initial table space +needed for the fixmap area with a proper one, allowing kernels configured for +large CPU counts to actually boot. + +Signed-off-by: Jan Beulich + +--- + arch/x86/mm/init_32.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- + arch/x86/mm/ioremap.c | 25 ------------------------- + include/asm-x86/io.h | 2 -- + 3 files changed, 46 insertions(+), 30 deletions(-) + +--- a/arch/x86/mm/init_32.c ++++ b/arch/x86/mm/init_32.c +@@ -137,6 +137,48 @@ static pte_t * __init one_page_table_ini + return pte_offset_kernel(pmd, 0); + } + ++static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd, ++ unsigned long vaddr, pte_t *lastpte) ++{ ++#ifdef CONFIG_HIGHMEM ++ /* ++ * Something (early fixmap) may already have put a pte ++ * page here, which causes the page table allocation ++ * to become nonlinear. Attempt to fix it, and if it ++ * is still nonlinear then we have to bug. ++ */ ++ int pmd_idx_kmap_begin = fix_to_virt(FIX_KMAP_END) >> PMD_SHIFT; ++ int pmd_idx_kmap_end = fix_to_virt(FIX_KMAP_BEGIN) >> PMD_SHIFT; ++ ++ if (pmd_idx_kmap_begin != pmd_idx_kmap_end ++ && (vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin ++ && (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end ++ && ((__pa(pte) >> PAGE_SHIFT) < table_start ++ || (__pa(pte) >> PAGE_SHIFT) >= table_end)) { ++ pte_t *newpte; ++ unsigned long phys; ++ int i; ++ ++ BUG_ON(after_init_bootmem); ++ newpte = alloc_low_page(&phys); ++ for (i = 0; i < PTRS_PER_PTE; i++) ++ set_pte(newpte + i, pte[i]); ++ ++ paravirt_alloc_pte(&init_mm, __pa(newpte) >> PAGE_SHIFT); ++ set_pmd(pmd, __pmd(__pa(newpte)|_PAGE_TABLE)); ++ BUG_ON(newpte != pte_offset_kernel(pmd, 0)); ++ __flush_tlb_all(); ++ ++ paravirt_release_pte(__pa(pte) >> PAGE_SHIFT); ++ pte = newpte; ++ } ++ BUG_ON(vaddr < fix_to_virt(FIX_KMAP_BEGIN - 1) ++ && vaddr > fix_to_virt(FIX_KMAP_END) ++ && lastpte && lastpte + PTRS_PER_PTE != pte); ++#endif ++ return pte; ++} ++ + /* + * This function initializes a certain range of kernel virtual memory + * with new bootmem page tables, everywhere page tables are missing in +@@ -153,6 +195,7 @@ page_table_range_init(unsigned long star + unsigned long vaddr; + pgd_t *pgd; + pmd_t *pmd; ++ pte_t *pte = NULL; + + vaddr = start; + pgd_idx = pgd_index(vaddr); +@@ -164,7 +207,8 @@ page_table_range_init(unsigned long star + pmd = pmd + pmd_index(vaddr); + for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); + pmd++, pmd_idx++) { +- one_page_table_init(pmd); ++ pte = page_table_kmap_check(one_page_table_init(pmd), ++ pmd, vaddr, pte); + + vaddr += PMD_SIZE; + } +@@ -447,7 +491,6 @@ static void __init early_ioremap_page_ta + * Fixed mappings, only the page table structure has to be + * created - mappings will be set by set_fixmap(): + */ +- early_ioremap_clear(); + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; + end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; + page_table_range_init(vaddr, end, pgd_base); +@@ -740,7 +783,7 @@ static void __init find_early_table_spac + tables += PAGE_ALIGN(ptes * sizeof(pte_t)); + + /* for fixmap */ +- tables += PAGE_SIZE * 2; ++ tables += PAGE_ALIGN(__end_of_fixed_addresses * sizeof(pte_t)); + + /* + * RED-PEN putting page tables only on node 0 could +--- a/arch/x86/mm/ioremap.c ++++ b/arch/x86/mm/ioremap.c +@@ -480,34 +480,9 @@ void __init early_ioremap_init(void) + } + } + +-void __init early_ioremap_clear(void) +-{ +- pmd_t *pmd; +- +- if (early_ioremap_debug) +- printk(KERN_INFO "early_ioremap_clear()\n"); +- +- pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); +- pmd_clear(pmd); +- paravirt_release_pte(__pa(bm_pte) >> PAGE_SHIFT); +- __flush_tlb_all(); +-} +- + void __init early_ioremap_reset(void) + { +- enum fixed_addresses idx; +- unsigned long addr, phys; +- pte_t *pte; +- + after_paging_init = 1; +- for (idx = FIX_BTMAP_BEGIN; idx >= FIX_BTMAP_END; idx--) { +- addr = fix_to_virt(idx); +- pte = early_ioremap_pte(addr); +- if (pte_present(*pte)) { +- phys = pte_val(*pte) & PAGE_MASK; +- set_fixmap(idx, phys); +- } +- } + } + + static void __init __early_set_fixmap(enum fixed_addresses idx, +--- a/include/asm-x86/io.h ++++ b/include/asm-x86/io.h +@@ -12,7 +12,6 @@ + */ + #ifndef __ASSEMBLY__ + extern void early_ioremap_init(void); +-extern void early_ioremap_clear(void); + extern void early_ioremap_reset(void); + extern void *early_ioremap(unsigned long offset, unsigned long size); + extern void early_iounmap(void *addr, unsigned long size); +@@ -92,7 +91,6 @@ extern void __iomem *ioremap_wc(unsigned + * A boot-time mapping is currently limited to at most 16 pages. + */ + extern void early_ioremap_init(void); +-extern void early_ioremap_clear(void); + extern void early_ioremap_reset(void); + extern void *early_ioremap(unsigned long offset, unsigned long size); + extern void early_iounmap(void *addr, unsigned long size); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-fix-nodac b/src/patches/suse-2.6.27.31/patches.arch/x86-fix-nodac new file mode 100644 index 000000000..d91724598 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-fix-nodac @@ -0,0 +1,25 @@ +From: Tejun Heo +Subject: x86: fix iommu=nodac parameter handling +References: bnc#463829 + +nodac should forbid dac not instead of enabling it. Fix it. + +Signed-off-by: Tejun Heo +Signed-off-by: Tejun Heo +--- + arch/x86/kernel/pci-dma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/pci-dma.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/arch/x86/kernel/pci-dma.c ++++ linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/pci-dma.c +@@ -175,7 +175,7 @@ static __init int iommu_setup(char *p) + if (!strncmp(p, "allowdac", 8)) + forbid_dac = 0; + if (!strncmp(p, "nodac", 5)) +- forbid_dac = -1; ++ forbid_dac = 1; + if (!strncmp(p, "usedac", 6)) { + forbid_dac = -1; + return 1; diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-hpet-pre-read b/src/patches/suse-2.6.27.31/patches.arch/x86-hpet-pre-read new file mode 100644 index 000000000..634942bb4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-hpet-pre-read @@ -0,0 +1,22 @@ +From: Takashi Iwai +Subject: x86: workaround for mccreary HPET read problem +Patch-mainline: +References: bnc#433746 + +On mccreacy platform, the read of HPET CMP register seems not updated +immediately after the write and returns the previous value instead. +A workaround is to read the register twice. + +Signed-off-by: Takashi Iwai + +--- +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -278,6 +278,7 @@ static int hpet_legacy_next_event(unsign + cnt += (u32) delta; + hpet_writel(cnt, HPET_T0_CMP); + ++ hpet_readl(HPET_T0_CMP); /* pre-read for bnc#433746 */ + /* + * We need to read back the CMP register to make sure that + * what we wrote hit the chip before we compare it to the diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-config-option-for-pci-reroute-quirks.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-config-option-for-pci-reroute-quirks.patch new file mode 100644 index 000000000..404f4bbd3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-config-option-for-pci-reroute-quirks.patch @@ -0,0 +1,123 @@ +From: Stefan Assmann +Subject: Introduce config option for pci reroute quirks + +The config option X86_REROUTE_FOR_BROKEN_BOOT_IRQS is introduced to +enable (or disable) the redirection of the interrupt handler to the boot +interrupt line by default. Depending on the existence of interrupt +masking / threaded interrupt handling in the kernel (vanilla, rt, ...) +and the maturity of the rerouting patch, users can enable or disable the +redirection by default. + +This means that the reroute quirk can be applied to any kernel without +changing it. + +Interrupt sharing could be increased if this option is enabled. However this +option is vital for threaded interrupt handling, as done by the RT kernel. +It should simplify the consolidation with the RT kernel. + +The option can be overridden by either pci=ioapicreroute or +pci=noioapicreroute. + +Signed-off-by: Stefan Assmann +Signed-off-by: Olaf Dabrunz +--- + Documentation/kernel-parameters.txt | 4 ++++ + arch/x86/Kconfig | 24 ++++++++++++++++++++++++ + arch/x86/pci/common.c | 8 ++++++++ + drivers/pci/quirks.c | 2 +- + include/asm-x86/pci.h | 2 +- + 5 files changed, 38 insertions(+), 2 deletions(-) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -624,6 +624,30 @@ config SCHED_MC + + source "kernel/Kconfig.preempt" + ++config X86_REROUTE_FOR_BROKEN_BOOT_IRQS ++ bool "Reroute for broken boot IRQs" ++ default n ++ depends on X86_IO_APIC ++ help ++ This option enables a workaround that fixes a source of ++ spurious interrupts. This is recommended when threaded ++ interrupt handling is used on systems where the generation of ++ superfluous "boot interrupts" cannot be disabled. ++ ++ Some chipsets generate a legacy INTx "boot IRQ" when the IRQ ++ entry in the chipset's IO-APIC is masked (as, e.g. the RT ++ kernel does during interrupt handling). On chipsets where this ++ boot IRQ generation cannot be disabled, this workaround keeps ++ the original IRQ line masked so that only the equivalent "boot ++ IRQ" is delivered to the CPUs. The workaround also tells the ++ kernel to set up the IRQ handler on the boot IRQ line. In this ++ way only one interrupt is delivered to the kernel. Otherwise ++ the spurious second interrupt may cause the kernel to bring ++ down (vital) interrupt lines. ++ ++ Only affects "broken" chipsets. Interrupt sharing may be ++ increased on these systems. ++ + config X86_UP_APIC + bool "Local APIC support on uniprocessors" + depends on X86_32 && !SMP && !(X86_VOYAGER || X86_GENERICARCH) +--- a/arch/x86/pci/common.c ++++ b/arch/x86/pci/common.c +@@ -24,7 +24,11 @@ unsigned int pci_early_dump_regs; + static int pci_bf_sort; + int pci_routeirq; + int noioapicquirk; ++#ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS ++int noioapicreroute = 0; ++#else + int noioapicreroute = 1; ++#endif + int pcibios_last_bus = -1; + unsigned long pirq_table_addr; + struct pci_bus *pci_root_bus; +@@ -528,6 +532,10 @@ char * __devinit pcibios_setup(char *st + if (noioapicreroute != -1) + noioapicreroute = 0; + return NULL; ++ } else if (!strcmp(str, "noioapicreroute")) { ++ if (noioapicreroute != -1) ++ noioapicreroute = 1; ++ return NULL; + } + return str; + } +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1573,6 +1573,10 @@ and is between 256 and 4096 characters. + primary IO-APIC for bridges that cannot disable + boot IRQs. This fixes a source of spurious IRQs + when the system masks IRQs. ++ noioapicreroute [APIC] Disable workaround that uses the ++ boot IRQ equivalent of an IRQ that connects to ++ a chipset where boot IRQs cannot be disabled. ++ The opposite of ioapicreroute. + biosirq [X86-32] Use PCI BIOS calls to get the interrupt + routing table. These calls are known to be buggy + on several machines and they hang the machine +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1411,7 +1411,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + */ + static void quirk_reroute_to_boot_interrupts_intel(struct pci_dev *dev) + { +- if (noioapicquirk) ++ if (noioapicquirk || noioapicreroute) + return; + + dev->irq_reroute_variant = INTEL_IRQ_REROUTE_VARIANT; +--- a/include/asm-x86/pci.h ++++ b/include/asm-x86/pci.h +@@ -20,7 +20,7 @@ struct pci_sysdata { + + extern int pci_routeirq; + extern int noioapicquirk; +-extern int ioapicreroute; ++extern int noioapicreroute; + + /* scan a bus after allocating a pci_sysdata for it */ + extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-pci-ioapicreroute-kernel-cmdline.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-pci-ioapicreroute-kernel-cmdline.patch new file mode 100644 index 000000000..0ecd3bc83 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-pci-ioapicreroute-kernel-cmdline.patch @@ -0,0 +1,77 @@ +From: Stefan Assmann +Subject: x86, pci: introduce pci=ioapicreroute kernel cmdline option + +Introduce pci=ioapicreroute kernel cmdline option to enable rerouting of boot +interrupts to the primary io-apic. + +Signed-off-by: Stefan Assmann +Signed-off-by: Olaf Dabrunz +Signed-off-by: Ingo Molnar +--- + Documentation/kernel-parameters.txt | 4 ++++ + arch/x86/pci/common.c | 5 +++++ + include/asm-x86/io_apic.h | 4 ++++ + include/asm-x86/pci.h | 1 + + 4 files changed, 14 insertions(+) + +--- a/arch/x86/pci/common.c ++++ b/arch/x86/pci/common.c +@@ -24,6 +24,7 @@ unsigned int pci_early_dump_regs; + static int pci_bf_sort; + int pci_routeirq; + int noioapicquirk; ++int noioapicreroute = 1; + int pcibios_last_bus = -1; + unsigned long pirq_table_addr; + struct pci_bus *pci_root_bus; +@@ -523,6 +524,10 @@ char * __devinit pcibios_setup(char *st + } else if (!strcmp(str, "noioapicquirk")) { + noioapicquirk = 1; + return NULL; ++ } else if (!strcmp(str, "ioapicreroute")) { ++ if (noioapicreroute != -1) ++ noioapicreroute = 0; ++ return NULL; + } + return str; + } +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1569,6 +1569,10 @@ and is between 256 and 4096 characters. + noioapicquirk [APIC] Disable all boot interrupt quirks. + Safety option to keep boot IRQs enabled. This + should never be necessary. ++ ioapicreroute [APIC] Enable rerouting of boot IRQs to the ++ primary IO-APIC for bridges that cannot disable ++ boot IRQs. This fixes a source of spurious IRQs ++ when the system masks IRQs. + biosirq [X86-32] Use PCI BIOS calls to get the interrupt + routing table. These calls are known to be buggy + on several machines and they hang the machine +--- a/include/asm-x86/io_apic.h ++++ b/include/asm-x86/io_apic.h +@@ -163,10 +163,14 @@ extern int timer_through_8259; + /* 1 if "noapic" boot option passed */ + extern int noioapicquirk; + ++/* -1 if "noapic" boot option passed */ ++extern int noioapicreroute; ++ + static inline void disable_ioapic_setup(void) + { + #ifdef CONFIG_PCI + noioapicquirk = 1; ++ noioapicreroute = -1; + #endif + skip_ioapic_setup = 1; + } +--- a/include/asm-x86/pci.h ++++ b/include/asm-x86/pci.h +@@ -20,6 +20,7 @@ struct pci_sysdata { + + extern int pci_routeirq; + extern int noioapicquirk; ++extern int ioapicreroute; + + /* scan a bus after allocating a pci_sysdata for it */ + extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-pci-noioapicquirk-kernel-cmdline.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-pci-noioapicquirk-kernel-cmdline.patch new file mode 100644 index 000000000..dd018e8e8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-introduce-pci-noioapicquirk-kernel-cmdline.patch @@ -0,0 +1,75 @@ +From: Stefan Assmann +Subject: x86, pci: introduce pci=noioapicquirk kernel cmdline option + +Introduce pci=noioapicquirk kernel cmdline option to disable all boot +interrupt quirks + +Signed-off-by: Stefan Assmann +Signed-off-by: Olaf Dabrunz +Signed-off-by: Ingo Molnar +--- + Documentation/kernel-parameters.txt | 3 +++ + arch/x86/pci/common.c | 4 ++++ + include/asm-x86/io_apic.h | 6 ++++++ + include/asm-x86/pci.h | 1 + + 4 files changed, 14 insertions(+) + +--- a/arch/x86/pci/common.c ++++ b/arch/x86/pci/common.c +@@ -23,6 +23,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS + unsigned int pci_early_dump_regs; + static int pci_bf_sort; + int pci_routeirq; ++int noioapicquirk; + int pcibios_last_bus = -1; + unsigned long pirq_table_addr; + struct pci_bus *pci_root_bus; +@@ -519,6 +520,9 @@ char * __devinit pcibios_setup(char *st + } else if (!strcmp(str, "skip_isa_align")) { + pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; + return NULL; ++ } else if (!strcmp(str, "noioapicquirk")) { ++ noioapicquirk = 1; ++ return NULL; + } + return str; + } +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1566,6 +1566,9 @@ and is between 256 and 4096 characters. + nomsi [MSI] If the PCI_MSI kernel config parameter is + enabled, this kernel boot option can be used to + disable the use of MSI interrupts system-wide. ++ noioapicquirk [APIC] Disable all boot interrupt quirks. ++ Safety option to keep boot IRQs enabled. This ++ should never be necessary. + biosirq [X86-32] Use PCI BIOS calls to get the interrupt + routing table. These calls are known to be buggy + on several machines and they hang the machine +--- a/include/asm-x86/io_apic.h ++++ b/include/asm-x86/io_apic.h +@@ -160,8 +160,14 @@ extern int skip_ioapic_setup; + /* 1 if the timer IRQ uses the '8259A Virtual Wire' mode */ + extern int timer_through_8259; + ++/* 1 if "noapic" boot option passed */ ++extern int noioapicquirk; ++ + static inline void disable_ioapic_setup(void) + { ++#ifdef CONFIG_PCI ++ noioapicquirk = 1; ++#endif + skip_ioapic_setup = 1; + } + +--- a/include/asm-x86/pci.h ++++ b/include/asm-x86/pci.h +@@ -19,6 +19,7 @@ struct pci_sysdata { + }; + + extern int pci_routeirq; ++extern int noioapicquirk; + + /* scan a bus after allocating a pci_sysdata for it */ + extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-mce-make-polling-timer-interval-per-cpu b/src/patches/suse-2.6.27.31/patches.arch/x86-mce-make-polling-timer-interval-per-cpu new file mode 100644 index 000000000..15e3561cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-mce-make-polling-timer-interval-per-cpu @@ -0,0 +1,100 @@ +From: Andi Kleen +Date: Thu, 9 Apr 2009 10:28:22 +0000 (+0200) +Subject: x86, mce: make polling timer interval per CPU +Patch-mainline: v2.6.30-rc5~52^2~1 +Git-commit: 6298c512bc1007c3ff5c9ce20e6996781651cc45 +References: bnc#507557 + +x86, mce: make polling timer interval per CPU + +The polling timer while running per CPU still uses a global next_interval +variable, which lead to some CPUs either polling too fast or too slow. +This was not a serious problem because all errors get picked up eventually, +but it's still better to avoid it. Turn next_interval into a per cpu variable. + +v2: Fix check_interval == 0 case (Hidetoshi Seto) + +[ Impact: minor bug fix ] + +Signed-off-by: Andi Kleen +Reviewed-by: Hidetoshi Seto +Signed-off-by: H. Peter Anvin +Acked-by: Jeff Mahoney +--- + arch/x86/kernel/cpu/mcheck/mce_64.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +--- a/arch/x86/kernel/cpu/mcheck/mce_64.c ++++ b/arch/x86/kernel/cpu/mcheck/mce_64.c +@@ -352,13 +352,14 @@ void mce_log_therm_throt_event(unsigned + */ + + static int check_interval = 5 * 60; /* 5 minutes */ +-static int next_interval; /* in jiffies */ ++static DEFINE_PER_CPU(int, next_interval); /* in jiffies */ + static void mcheck_timer(unsigned long); + static DEFINE_PER_CPU(struct timer_list, mce_timer); + + static void mcheck_timer(unsigned long data) + { + struct timer_list *t = &per_cpu(mce_timer, data); ++ int *n; + + WARN_ON(smp_processor_id() != data); + +@@ -369,14 +370,14 @@ static void mcheck_timer(unsigned long d + * Alert userspace if needed. If we logged an MCE, reduce the + * polling interval, otherwise increase the polling interval. + */ ++ n = &__get_cpu_var(next_interval); + if (mce_notify_user()) { +- next_interval = max(next_interval/2, HZ/100); ++ *n = max(*n/2, HZ/100); + } else { +- next_interval = min(next_interval * 2, +- (int)round_jiffies_relative(check_interval*HZ)); ++ *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ)); + } + +- t->expires = jiffies + next_interval; ++ t->expires = jiffies + *n; + add_timer(t); + } + +@@ -502,14 +503,13 @@ static void __cpuinit mce_cpu_features(s + static void mce_init_timer(void) + { + struct timer_list *t = &__get_cpu_var(mce_timer); ++ int *n = &__get_cpu_var(next_interval); + +- /* data race harmless because everyone sets to the same value */ +- if (!next_interval) +- next_interval = check_interval * HZ; +- if (!next_interval) ++ *n = check_interval * HZ; ++ if (!*n) + return; + setup_timer(t, mcheck_timer, smp_processor_id()); +- t->expires = round_jiffies(jiffies + next_interval); ++ t->expires = round_jiffies(jiffies + *n); + add_timer(t); + } + +@@ -761,7 +761,6 @@ static void mce_cpu_restart(void *data) + /* Reinit MCEs after user configuration changes */ + static void mce_restart(void) + { +- next_interval = check_interval * HZ; + on_each_cpu(mce_cpu_restart, NULL, 1); + } + +@@ -912,7 +911,8 @@ static int __cpuinit mce_cpu_callback(st + break; + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: +- t->expires = round_jiffies(jiffies + next_interval); ++ t->expires = round_jiffies(jiffies + ++ __get_cpu_var(next_interval)); + add_timer_on(t, cpu); + break; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-mce-switch-machine-check-polling-to-per-cpu-timer b/src/patches/suse-2.6.27.31/patches.arch/x86-mce-switch-machine-check-polling-to-per-cpu-timer new file mode 100644 index 000000000..db56a3a85 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-mce-switch-machine-check-polling-to-per-cpu-timer @@ -0,0 +1,189 @@ +From: Andi Kleen +Date: Thu, 12 Feb 2009 12:39:29 +0000 (+0100) +Subject: x86, mce: switch machine check polling to per CPU timer +Patch-mainline: 2.6.30-rc1 +Git-commit: 52d168e28bc11dd026b620fe1767cadde5a747cd +References: bnc#507557 + +x86, mce: switch machine check polling to per CPU timer + +Impact: Higher priority bug fix + +The machine check poller runs a single timer and then broadcasted an +IPI to all CPUs to check them. This leads to unnecessary +synchronization between CPUs. The original CPU running the timer has +to wait potentially a long time for all other CPUs answering. This is +also real time unfriendly and in general inefficient. + +This was especially a problem on systems with a lot of events where +the poller run with a higher frequency after processing some events. +There could be more and more CPU time wasted with this, to +the point of significantly slowing down machines. + +The machine check polling is actually fully independent per CPU, so +there's no reason to not just do this all with per CPU timers. This +patch implements that. + +Also switch the poller also to use standard timers instead of work +queues. It was using work queues to be able to execute a user program +on a event, but mce_notify_user() handles this case now with a +separate callback. So instead always run the poll code in in a +standard per CPU timer, which means that in the common case of not +having to execute a trigger there will be less overhead. + +This allows to clean up the initialization significantly, because +standard timers are already up when machine checks get init'ed. No +multiple initialization functions. + +Thanks to Thomas Gleixner for some help. + +Cc: thockin@google.com +v2: Use del_timer_sync() on cpu shutdown and don't try to handle +migrated timers. +v3: Add WARN_ON for timer running on unexpected CPU + +Signed-off-by: Andi Kleen +Acked-by: Thomas Gleixner +Signed-off-by: H. Peter Anvin +Acked-by: Jeff Mahoney +--- + arch/x86/kernel/cpu/mcheck/mce_64.c | 68 +++++++++++++++++++++++------------- + 1 file changed, 45 insertions(+), 23 deletions(-) + +--- a/arch/x86/kernel/cpu/mcheck/mce_64.c ++++ b/arch/x86/kernel/cpu/mcheck/mce_64.c +@@ -353,18 +353,17 @@ void mce_log_therm_throt_event(unsigned + + static int check_interval = 5 * 60; /* 5 minutes */ + static int next_interval; /* in jiffies */ +-static void mcheck_timer(struct work_struct *work); +-static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer); ++static void mcheck_timer(unsigned long); ++static DEFINE_PER_CPU(struct timer_list, mce_timer); + +-static void mcheck_check_cpu(void *info) ++static void mcheck_timer(unsigned long data) + { ++ struct timer_list *t = &per_cpu(mce_timer, data); ++ ++ WARN_ON(smp_processor_id() != data); ++ + if (mce_available(¤t_cpu_data)) + do_machine_check(NULL, 0); +-} +- +-static void mcheck_timer(struct work_struct *work) +-{ +- on_each_cpu(mcheck_check_cpu, NULL, 1); + + /* + * Alert userspace if needed. If we logged an MCE, reduce the +@@ -377,7 +376,8 @@ static void mcheck_timer(struct work_str + (int)round_jiffies_relative(check_interval*HZ)); + } + +- schedule_delayed_work(&mcheck_work, next_interval); ++ t->expires = jiffies + next_interval; ++ add_timer(t); + } + + /* +@@ -425,16 +425,11 @@ static struct notifier_block mce_idle_no + + static __init int periodic_mcheck_init(void) + { +- next_interval = check_interval * HZ; +- if (next_interval) +- schedule_delayed_work(&mcheck_work, +- round_jiffies_relative(next_interval)); +- idle_notifier_register(&mce_idle_notifier); +- return 0; ++ idle_notifier_register(&mce_idle_notifier); ++ return 0; + } + __initcall(periodic_mcheck_init); + +- + /* + * Initialize Machine Checks for a CPU. + */ +@@ -504,6 +499,20 @@ static void __cpuinit mce_cpu_features(s + } + } + ++static void mce_init_timer(void) ++{ ++ struct timer_list *t = &__get_cpu_var(mce_timer); ++ ++ /* data race harmless because everyone sets to the same value */ ++ if (!next_interval) ++ next_interval = check_interval * HZ; ++ if (!next_interval) ++ return; ++ setup_timer(t, mcheck_timer, smp_processor_id()); ++ t->expires = round_jiffies_relative(jiffies + next_interval); ++ add_timer(t); ++} ++ + /* + * Called for each booted CPU to set up machine checks. + * Must be called with preempt off. +@@ -521,6 +530,7 @@ void __cpuinit mcheck_init(struct cpuinf + + mce_init(NULL); + mce_cpu_features(c); ++ mce_init_timer(); + } + + /* +@@ -740,17 +750,19 @@ static int mce_resume(struct sys_device + return 0; + } + ++static void mce_cpu_restart(void *data) ++{ ++ del_timer_sync(&__get_cpu_var(mce_timer)); ++ if (mce_available(¤t_cpu_data)) ++ mce_init(NULL); ++ mce_init_timer(); ++} ++ + /* Reinit MCEs after user configuration changes */ + static void mce_restart(void) + { +- if (next_interval) +- cancel_delayed_work(&mcheck_work); +- /* Timer race is harmless here */ +- on_each_cpu(mce_init, NULL, 1); + next_interval = check_interval * HZ; +- if (next_interval) +- schedule_delayed_work(&mcheck_work, +- round_jiffies_relative(next_interval)); ++ on_each_cpu(mce_cpu_restart, NULL, 1); + } + + static struct sysdev_class mce_sysclass = { +@@ -879,6 +891,7 @@ static int __cpuinit mce_cpu_callback(st + unsigned long action, void *hcpu) + { + unsigned int cpu = (unsigned long)hcpu; ++ struct timer_list *t = &per_cpu(mce_timer, cpu); + + switch (action) { + case CPU_ONLINE: +@@ -893,6 +906,15 @@ static int __cpuinit mce_cpu_callback(st + threshold_cpu_callback(action, cpu); + mce_remove_device(cpu); + break; ++ case CPU_DOWN_PREPARE: ++ case CPU_DOWN_PREPARE_FROZEN: ++ del_timer_sync(t); ++ break; ++ case CPU_DOWN_FAILED: ++ case CPU_DOWN_FAILED_FROZEN: ++ t->expires = round_jiffies_relative(jiffies + next_interval); ++ add_timer_on(t, cpu); ++ break; + } + return NOTIFY_OK; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-mce-use-round_jiffies-instead-round_jiffies_relative b/src/patches/suse-2.6.27.31/patches.arch/x86-mce-use-round_jiffies-instead-round_jiffies_relative new file mode 100644 index 000000000..9f8480cf6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-mce-use-round_jiffies-instead-round_jiffies_relative @@ -0,0 +1,47 @@ +From: KOSAKI Motohiro +Date: Wed, 11 Mar 2009 01:14:26 +0000 (+0900) +Subject: x86, mce: use round_jiffies() instead round_jiffies_relative() +Patch-mainline: 2.6.30-rc3 +Git-commit: 5490fa96735ce0e2af270c0868987d644b9a38ec +References: bnc#507557 + +x86, mce: use round_jiffies() instead round_jiffies_relative() + +Impact: saving power _very_ little + +round_jiffies() round up absolute jiffies to full second. +round_jiffies_relative() round up relative jiffies to full second. + +The "t->expires" is absolute jiffies. Then, round_jiffies() should be +used instead round_jiffies_relative(). + +Signed-off-by: KOSAKI Motohiro +Cc: Andi Kleen +Cc: H. Peter Anvin +Signed-off-by: H. Peter Anvin +Acked-by: Jeff Mahoney + +--- + arch/x86/kernel/cpu/mcheck/mce_64.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/cpu/mcheck/mce_64.c ++++ b/arch/x86/kernel/cpu/mcheck/mce_64.c +@@ -509,7 +509,7 @@ static void mce_init_timer(void) + if (!next_interval) + return; + setup_timer(t, mcheck_timer, smp_processor_id()); +- t->expires = round_jiffies_relative(jiffies + next_interval); ++ t->expires = round_jiffies(jiffies + next_interval); + add_timer(t); + } + +@@ -912,7 +912,7 @@ static int __cpuinit mce_cpu_callback(st + break; + case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: +- t->expires = round_jiffies_relative(jiffies + next_interval); ++ t->expires = round_jiffies(jiffies + next_interval); + add_timer_on(t, cpu); + break; + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-mcp51-no-dac b/src/patches/suse-2.6.27.31/patches.arch/x86-mcp51-no-dac new file mode 100644 index 000000000..71b4104d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-mcp51-no-dac @@ -0,0 +1,39 @@ +From: Tejun Heo +Subject: x86: disallow DAC for MCP51 PCI bridge +References: bnc#463829 + +MCP51 corrupts DAC transfers. Disallow it. Reported by pgnet on +bnc#463829. + + https://bugzilla.novell.com/show_bug.cgi?id=463829 + +Signed-off-by: Tejun Heo +Reported-by: pgnet +Signed-off-by: Tejun Heo +--- + arch/x86/kernel/pci-dma.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +Index: linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/pci-dma.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/arch/x86/kernel/pci-dma.c ++++ linux-2.6.27-SLE11_BRANCH/arch/x86/kernel/pci-dma.c +@@ -415,4 +415,18 @@ static __devinit void via_no_dac(struct + } + } + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac); ++ ++/* ++ * MCP51 PCI bridge corrupts data for DAC. Disable it. Reported in ++ * bnc#463829. ++ */ ++static __devinit void mcp51_no_dac(struct pci_dev *dev) ++{ ++ if (forbid_dac == 0) { ++ printk(KERN_INFO ++ "PCI: MCP51 PCI bridge detected. Disabling DAC.\n"); ++ forbid_dac = 1; ++ } ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x026f, mcp51_no_dac); + #endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-pageattr-pmd-permission-fix.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-pageattr-pmd-permission-fix.patch new file mode 100644 index 000000000..4238fa740 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-pageattr-pmd-permission-fix.patch @@ -0,0 +1,75 @@ +From: Ingo Molnar +References: bnc#439348 +Subject: x86: use the right protections for split-up pagetables +Patch-mainline: yes +Git: 07a66d7c53a538e1a9759954a82bb6c07365eff9 + + Steven Rostedt found a bug in where in his modified kernel + ftrace was unable to modify the kernel text, due to the PMD + itself having been marked read-only as well in + split_large_page(). + + The fix, suggested by Linus, is to not try to 'clone' the + reference protection of a huge-page, but to use the standard + (and permissive) page protection bits of KERNPG_TABLE. + + The 'cloning' makes sense for the ptes but it's a confused and + incorrect concept at the page table level - because the + pagetable entry is a set of all ptes and hence cannot + 'clone' any single protection attribute - the ptes can be any + mixture of protections. + + With the permissive KERNPG_TABLE, even if the pte protections + get changed after this point (due to ftrace doing code-patching + or other similar activities like kprobes), the resulting combined + protections will still be correct and the pte's restrictive + (or permissive) protections will control it. + + Also update the comment. + + This bug was there for a long time but has not caused visible + problems before as it needs a rather large read-only area to + trigger. Steve possibly hacked his kernel with some really + large arrays or so. Anyway, the bug is definitely worth fixing. + + [ Huang Ying also experienced problems in this area when writing + the EFI code, but the real bug in split_large_page() was not + realized back then. ] + + Reported-by: Steven Rostedt + Reported-by: Huang Ying + Acked-by: Linus Torvalds + Signed-off-by: Ingo Molnar + +Acked-by: Nick Piggin + +--- + arch/x86/mm/pageattr.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +--- a/arch/x86/mm/pageattr.c ++++ b/arch/x86/mm/pageattr.c +@@ -557,18 +557,13 @@ static int split_large_page(pte_t *kpte, + #endif + + /* +- * Install the new, split up pagetable. Important details here: ++ * Install the new, split up pagetable. + * +- * On Intel the NX bit of all levels must be cleared to make a +- * page executable. See section 4.13.2 of Intel 64 and IA-32 +- * Architectures Software Developer's Manual). +- * +- * Mark the entry present. The current mapping might be +- * set to not present, which we preserved above. ++ * We use the standard kernel pagetable protections for the new ++ * pagetable protections, the actual ptes set above control the ++ * primary protection behavior: + */ +- ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte))); +- pgprot_val(ref_prot) |= _PAGE_PRESENT; +- __set_pmd_pte(kpte, address, mk_pte(base, ref_prot)); ++ __set_pmd_pte(kpte, address, mk_pte(base, __pgprot(_KERNPG_TABLE))); + + /* + * Intel Atom errata AAH41 workaround. diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-self-ptrace.patch b/src/patches/suse-2.6.27.31/patches.arch/x86-self-ptrace.patch new file mode 100644 index 000000000..97e16ab11 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-self-ptrace.patch @@ -0,0 +1,76 @@ +From: Gerald Schaefer +Subject: [x86] system call notification with self_ptrace +References: bnc#417299 + +Implement PTRACE SELF for x86. See patches.suse/self-ptrace.patch +for more documentation. + +Signed-off-by: Pierre Morel +Signed-off-by: Volker Sameske + +Acked-by: John Jolly +--- + + arch/x86/kernel/ptrace.c | 14 ++++++++++++++ + arch/x86/kernel/signal_32.c | 5 +++++ + arch/x86/kernel/signal_64.c | 5 +++++ + 3 files changed, 24 insertions(+) + +--- linux-2.6.26.orig/arch/x86/kernel/ptrace.c 2008-09-26 10:21:51.000000000 +0200 ++++ linux-2.6.26/arch/x86/kernel/ptrace.c 2008-09-26 10:22:23.000000000 +0200 +@@ -1429,6 +1429,17 @@ asmregparm long syscall_trace_enter(stru + /* do the secure computing check first */ + secure_computing(regs->orig_ax); + ++ if (is_self_ptracing(regs->orig_ax)) { ++ struct siginfo info; ++ ++ memset(&info, 0, sizeof(struct siginfo)); ++ info.si_signo = SIGSYS; ++ info.si_code = SYS_SYSCALL; ++ info.si_addr = (void *) regs->orig_ax; ++ send_sig_info(SIGSYS, &info, current); ++ return -1L; /* Skip system call, deliver signal. */ ++ } ++ + if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) + ret = -1L; + +@@ -1455,6 +1466,9 @@ asmregparm long syscall_trace_enter(stru + + asmregparm void syscall_trace_leave(struct pt_regs *regs) + { ++ if (is_self_ptracing(regs->orig_ax)) { ++ return; ++ } + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); + +--- linux-2.6.26.orig/arch/x86/kernel/signal_32.c 2008-09-26 10:21:51.000000000 +0200 ++++ linux-2.6.26/arch/x86/kernel/signal_32.c 2008-09-26 10:22:23.000000000 +0200 +@@ -568,6 +568,11 @@ handle_signal(unsigned long sig, siginfo + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + ++ if (current->instrumentation & PTS_SELF) { ++ clear_thread_flag(TIF_SYSCALL_TRACE); ++ current->instrumentation &= ~PTS_SELF; ++ } ++ + return 0; + } + +--- linux-2.6.26.orig/arch/x86/kernel/signal_64.c 2008-09-26 10:21:51.000000000 +0200 ++++ linux-2.6.26/arch/x86/kernel/signal_64.c 2008-09-26 10:22:23.000000000 +0200 +@@ -464,6 +464,11 @@ handle_signal(unsigned long sig, siginfo + spin_unlock_irq(¤t->sighand->siglock); + } + ++ if (current->instrumentation & PTS_SELF) { ++ clear_thread_flag(TIF_SYSCALL_TRACE); ++ current->instrumentation &= ~PTS_SELF; ++ } ++ + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-tracehook b/src/patches/suse-2.6.27.31/patches.arch/x86-tracehook new file mode 100644 index 000000000..339a25913 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-tracehook @@ -0,0 +1,509 @@ +From: Roland McGrath +Date: Sun Apr 20 14:35:12 2008 -0700 +Subject: x86 tracehook +References: FATE#304321 +Patch-mainline: no + +Apply the changes from x86-utrace branch of +git://git.kernel.org/pub/scm/linux/kernel/git/frob/linux-2.6-utrace +plus later cleanups. + +Signed-off-by: Roland McGrath +Signed-off-by: Petr Tesarik + +--- + arch/x86/Kconfig | 1 + arch/x86/kernel/ptrace.c | 34 +----- + arch/x86/kernel/signal_32.c | 11 +- + arch/x86/kernel/signal_64.c | 49 ++------- + include/asm-x86/ptrace.h | 5 + include/asm-x86/syscall.h | 213 ++++++++++++++++++++++++++++++++++++++++++ + include/asm-x86/thread_info.h | 4 + 7 files changed, 251 insertions(+), 66 deletions(-) + +--- linux-2.6.27.orig/arch/x86/Kconfig 2008-10-20 11:46:16.000000000 +0200 ++++ linux-2.6.27/arch/x86/Kconfig 2008-10-20 17:24:26.000000000 +0200 +@@ -29,6 +29,7 @@ config X86 + select HAVE_FTRACE + select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) + select HAVE_ARCH_KGDB if !X86_VOYAGER ++ select HAVE_ARCH_TRACEHOOK + select HAVE_GENERIC_DMA_COHERENT if X86_32 + select HAVE_EFFICIENT_UNALIGNED_ACCESS + +--- linux-2.6.27.orig/arch/x86/kernel/ptrace.c 2008-10-20 11:46:16.000000000 +0200 ++++ linux-2.6.27/arch/x86/kernel/ptrace.c 2008-10-20 11:46:16.000000000 +0200 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1375,30 +1376,6 @@ void send_sigtrap(struct task_struct *ts + force_sig_info(SIGTRAP, &info, tsk); + } + +-static void syscall_trace(struct pt_regs *regs) +-{ +- if (!(current->ptrace & PT_PTRACED)) +- return; +- +-#if 0 +- printk("trace %s ip %lx sp %lx ax %d origrax %d caller %lx tiflags %x ptrace %x\n", +- current->comm, +- regs->ip, regs->sp, regs->ax, regs->orig_ax, __builtin_return_address(0), +- current_thread_info()->flags, current->ptrace); +-#endif +- +- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) +- ? 0x80 : 0)); +- /* +- * this isn't the same as continuing with a signal, but it will do +- * for normal use. strace only continues with a signal if the +- * stopping signal is not SIGTRAP. -brl +- */ +- if (current->exit_code) { +- send_sig(current->exit_code, current, 1); +- current->exit_code = 0; +- } +-} + + #ifdef CONFIG_X86_32 + # define IS_IA32 1 +@@ -1443,8 +1420,9 @@ asmregparm long syscall_trace_enter(stru + if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) + ret = -1L; + +- if (ret || test_thread_flag(TIF_SYSCALL_TRACE)) +- syscall_trace(regs); ++ if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) && ++ tracehook_report_syscall_entry(regs)) ++ ret = -1L; + + if (unlikely(current->audit_context)) { + if (IS_IA32) +@@ -1473,7 +1451,7 @@ asmregparm void syscall_trace_leave(stru + audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); + + if (test_thread_flag(TIF_SYSCALL_TRACE)) +- syscall_trace(regs); ++ tracehook_report_syscall_exit(regs, 0); + + /* + * If TIF_SYSCALL_EMU is set, we only get here because of +@@ -1489,6 +1467,6 @@ asmregparm void syscall_trace_leave(stru + * system call instruction. + */ + if (test_thread_flag(TIF_SINGLESTEP) && +- (current->ptrace & PT_PTRACED)) ++ tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL)) + send_sigtrap(current, regs, 0); + } +--- linux-2.6.27.orig/arch/x86/kernel/signal_32.c 2008-10-20 11:46:16.000000000 +0200 ++++ linux-2.6.27/arch/x86/kernel/signal_32.c 2008-10-20 11:46:16.000000000 +0200 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -558,8 +559,6 @@ handle_signal(unsigned long sig, siginfo + * handler too. + */ + regs->flags &= ~X86_EFLAGS_TF; +- if (test_thread_flag(TIF_SINGLESTEP)) +- ptrace_notify(SIGTRAP); + + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); +@@ -573,6 +572,9 @@ handle_signal(unsigned long sig, siginfo + current->instrumentation &= ~PTS_SELF; + } + ++ tracehook_signal_handler(sig, info, ka, regs, ++ test_thread_flag(TIF_SINGLESTEP)); ++ + return 0; + } + +@@ -666,5 +668,10 @@ do_notify_resume(struct pt_regs *regs, v + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs); + ++ if (thread_info_flags & _TIF_NOTIFY_RESUME) { ++ clear_thread_flag(TIF_NOTIFY_RESUME); ++ tracehook_notify_resume(regs); ++ } ++ + clear_thread_flag(TIF_IRET); + } +--- linux-2.6.27.orig/arch/x86/kernel/signal_64.c 2008-10-20 11:46:16.000000000 +0200 ++++ linux-2.6.27/arch/x86/kernel/signal_64.c 2008-10-20 11:46:16.000000000 +0200 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -26,6 +27,7 @@ + #include + #include + #include ++#include + #include "sigframe.h" + + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +@@ -355,35 +357,6 @@ give_sigsegv: + } + + /* +- * Return -1L or the syscall number that @regs is executing. +- */ +-static long current_syscall(struct pt_regs *regs) +-{ +- /* +- * We always sign-extend a -1 value being set here, +- * so this is always either -1L or a syscall number. +- */ +- return regs->orig_ax; +-} +- +-/* +- * Return a value that is -EFOO if the system call in @regs->orig_ax +- * returned an error. This only works for @regs from @current. +- */ +-static long current_syscall_ret(struct pt_regs *regs) +-{ +-#ifdef CONFIG_IA32_EMULATION +- if (test_thread_flag(TIF_IA32)) +- /* +- * Sign-extend the value so (int)-EFOO becomes (long)-EFOO +- * and will match correctly in comparisons. +- */ +- return (int) regs->ax; +-#endif +- return regs->ax; +-} +- +-/* + * OK, we're invoking a handler + */ + +@@ -394,9 +367,9 @@ handle_signal(unsigned long sig, siginfo + int ret; + + /* Are we from a system call? */ +- if (current_syscall(regs) >= 0) { ++ if (syscall_get_nr(current, regs) >= 0) { + /* If so, check system call restarting.. */ +- switch (current_syscall_ret(regs)) { ++ switch (syscall_get_error(current, regs)) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + regs->ax = -EINTR; +@@ -453,8 +426,6 @@ handle_signal(unsigned long sig, siginfo + * handler too. + */ + regs->flags &= ~X86_EFLAGS_TF; +- if (test_thread_flag(TIF_SINGLESTEP)) +- ptrace_notify(SIGTRAP); + + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); +@@ -462,6 +433,9 @@ handle_signal(unsigned long sig, siginfo + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); ++ ++ tracehook_signal_handler(sig, info, ka, regs, ++ test_thread_flag(TIF_SINGLESTEP)); + } + + if (current->instrumentation & PTS_SELF) { +@@ -523,9 +497,9 @@ static void do_signal(struct pt_regs *re + } + + /* Did we come from a system call? */ +- if (current_syscall(regs) >= 0) { ++ if (syscall_get_nr(current, regs) >= 0) { + /* Restart the system call - no handlers present */ +- switch (current_syscall_ret(regs)) { ++ switch (syscall_get_error(current, regs)) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: +@@ -563,6 +537,11 @@ void do_notify_resume(struct pt_regs *re + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs); ++ ++ if (thread_info_flags & _TIF_NOTIFY_RESUME) { ++ clear_thread_flag(TIF_NOTIFY_RESUME); ++ tracehook_notify_resume(regs); ++ } + } + + void signal_fault(struct pt_regs *regs, void __user *frame, char *where) +--- linux-2.6.27.orig/include/asm-x86/ptrace.h 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27/include/asm-x86/ptrace.h 2008-10-20 17:23:29.000000000 +0200 +@@ -213,6 +213,11 @@ static inline unsigned long frame_pointe + return regs->bp; + } + ++static inline unsigned long user_stack_pointer(struct pt_regs *regs) ++{ ++ return regs->sp; ++} ++ + /* + * These are defined as per linux/ptrace.h, which see. + */ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.27/include/asm-x86/syscall.h 2008-10-20 17:32:17.000000000 +0200 +@@ -0,0 +1,213 @@ ++/* ++ * Access to user system call parameters and results ++ * ++ * Copyright (C) 2008 Red Hat, Inc. All rights reserved. ++ * ++ * This copyrighted material is made available to anyone wishing to use, ++ * modify, copy, or redistribute it subject to the terms and conditions ++ * of the GNU General Public License v.2. ++ * ++ * See asm-generic/syscall.h for descriptions of what we must do here. ++ */ ++ ++#ifndef _ASM_SYSCALL_H ++#define _ASM_SYSCALL_H 1 ++ ++#include ++#include ++ ++static inline long syscall_get_nr(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ /* ++ * We always sign-extend a -1 value being set here, ++ * so this is always either -1L or a syscall number. ++ */ ++ return regs->orig_ax; ++} ++ ++static inline void syscall_rollback(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ regs->ax = regs->orig_ax; ++} ++ ++static inline long syscall_get_error(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ unsigned long error = regs->ax; ++#ifdef CONFIG_IA32_EMULATION ++ /* ++ * TS_COMPAT is set for 32-bit syscall entries and then ++ * remains set until we return to user mode. ++ */ ++ if (task_thread_info(task)->status & TS_COMPAT) ++ /* ++ * Sign-extend the value so (int)-EFOO becomes (long)-EFOO ++ * and will match correctly in comparisons. ++ */ ++ error = (long) (int) error; ++#endif ++ return IS_ERR_VALUE(error) ? error : 0; ++} ++ ++static inline long syscall_get_return_value(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ return regs->ax; ++} ++ ++static inline void syscall_set_return_value(struct task_struct *task, ++ struct pt_regs *regs, ++ int error, long val) ++{ ++ regs->ax = (long) error ?: val; ++} ++ ++#ifdef CONFIG_X86_32 ++ ++static inline void syscall_get_arguments(struct task_struct *task, ++ struct pt_regs *regs, ++ unsigned int i, unsigned int n, ++ unsigned long *args) ++{ ++ BUG_ON(i + n > 6); ++ memcpy(args, ®s->bx + i, n * sizeof(args[0])); ++} ++ ++static inline void syscall_set_arguments(struct task_struct *task, ++ struct pt_regs *regs, ++ unsigned int i, unsigned int n, ++ const unsigned long *args) ++{ ++ BUG_ON(i + n > 6); ++ memcpy(®s->bx + i, args, n * sizeof(args[0])); ++} ++ ++#else /* CONFIG_X86_64 */ ++ ++static inline void syscall_get_arguments(struct task_struct *task, ++ struct pt_regs *regs, ++ unsigned int i, unsigned int n, ++ unsigned long *args) ++{ ++# ifdef CONFIG_IA32_EMULATION ++ if (task_thread_info(task)->status & TS_COMPAT) ++ switch (i) { ++ case 0: ++ if (!n--) break; ++ *args++ = regs->bx; ++ case 1: ++ if (!n--) break; ++ *args++ = regs->cx; ++ case 2: ++ if (!n--) break; ++ *args++ = regs->dx; ++ case 3: ++ if (!n--) break; ++ *args++ = regs->si; ++ case 4: ++ if (!n--) break; ++ *args++ = regs->di; ++ case 5: ++ if (!n--) break; ++ *args++ = regs->bp; ++ case 6: ++ if (!n--) break; ++ default: ++ BUG(); ++ break; ++ } ++ else ++# endif ++ switch (i) { ++ case 0: ++ if (!n--) break; ++ *args++ = regs->di; ++ case 1: ++ if (!n--) break; ++ *args++ = regs->si; ++ case 2: ++ if (!n--) break; ++ *args++ = regs->dx; ++ case 3: ++ if (!n--) break; ++ *args++ = regs->r10; ++ case 4: ++ if (!n--) break; ++ *args++ = regs->r8; ++ case 5: ++ if (!n--) break; ++ *args++ = regs->r9; ++ case 6: ++ if (!n--) break; ++ default: ++ BUG(); ++ break; ++ } ++} ++ ++static inline void syscall_set_arguments(struct task_struct *task, ++ struct pt_regs *regs, ++ unsigned int i, unsigned int n, ++ const unsigned long *args) ++{ ++# ifdef CONFIG_IA32_EMULATION ++ if (task_thread_info(task)->status & TS_COMPAT) ++ switch (i) { ++ case 0: ++ if (!n--) break; ++ regs->bx = *args++; ++ case 1: ++ if (!n--) break; ++ regs->cx = *args++; ++ case 2: ++ if (!n--) break; ++ regs->dx = *args++; ++ case 3: ++ if (!n--) break; ++ regs->si = *args++; ++ case 4: ++ if (!n--) break; ++ regs->di = *args++; ++ case 5: ++ if (!n--) break; ++ regs->bp = *args++; ++ case 6: ++ if (!n--) break; ++ default: ++ BUG(); ++ break; ++ } ++ else ++# endif ++ switch (i) { ++ case 0: ++ if (!n--) break; ++ regs->di = *args++; ++ case 1: ++ if (!n--) break; ++ regs->si = *args++; ++ case 2: ++ if (!n--) break; ++ regs->dx = *args++; ++ case 3: ++ if (!n--) break; ++ regs->r10 = *args++; ++ case 4: ++ if (!n--) break; ++ regs->r8 = *args++; ++ case 5: ++ if (!n--) break; ++ regs->r9 = *args++; ++ case 6: ++ if (!n--) break; ++ default: ++ BUG(); ++ break; ++ } ++} ++ ++#endif /* CONFIG_X86_32 */ ++ ++#endif /* _ASM_SYSCALL_H */ +--- linux-2.6.27.orig/include/asm-x86/thread_info.h 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27/include/asm-x86/thread_info.h 2008-10-20 17:23:10.000000000 +0200 +@@ -71,6 +71,7 @@ struct thread_info { + * Warning: layout of LSW is hardcoded in entry.S + */ + #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ ++#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ + #define TIF_SIGPENDING 2 /* signal pending */ + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ + #define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ +@@ -93,6 +94,7 @@ struct thread_info { + #define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ + + #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) ++#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) + #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) + #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +@@ -133,7 +135,7 @@ struct thread_info { + + /* Only used for 64 bit */ + #define _TIF_DO_NOTIFY_MASK \ +- (_TIF_SIGPENDING|_TIF_MCE_NOTIFY) ++ (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME) + + /* flags to check in __switch_to() */ + #define _TIF_WORK_CTXSW \ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-01-add-TSC_RELIABLE b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-01-add-TSC_RELIABLE new file mode 100644 index 000000000..4b19d7ce9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-01-add-TSC_RELIABLE @@ -0,0 +1,34 @@ +From: Alok Kataria +Subject: x86: add a synthetic TSC_RELIABLE feature bit +Patch-mainline: +References: bnc#441338 + +Impact: None, bit reservation only + +Add a synthetic TSC_RELIABLE feature bit which will be used to mark +TSC as reliable so that we could skip all the runtime checks for +TSC stablity, which have false positives in virtual environment. + +Signed-off-by: Alok N Kataria +Signed-off-by: Dan Hecht +Signed-off-by: H. Peter Anvin +Signed-off-by: Takashi Iwai +--- + + include/asm-x86/cpufeature.h | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + + +Index: linux-2.6.27.4-2-beta4/include/asm-x86/cpufeature.h +=================================================================== +--- linux-2.6.27.4-2-beta4.orig/include/asm-x86/cpufeature.h 2008-10-28 16:32:43.000000000 -0700 ++++ linux-2.6.27.4-2-beta4/include/asm-x86/cpufeature.h 2008-11-10 12:41:49.000000000 -0800 +@@ -83,7 +83,7 @@ + #define X86_FEATURE_NOPL (3*32+20) /* The NOPL (0F 1F) instructions */ + #define X86_FEATURE_AMDC1E (3*32+21) /* AMD C1E detected */ + #define X86_FEATURE_XTOPOLOGY (3*32+22) /* cpu topology enum extensions */ +- ++#define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */ + + /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ + #define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-02-add-X86_FEATURE_HYPERVISOR b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-02-add-X86_FEATURE_HYPERVISOR new file mode 100644 index 000000000..0c8012801 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-02-add-X86_FEATURE_HYPERVISOR @@ -0,0 +1,38 @@ +From: Alok Kataria +Subject: x86: add X86_FEATURE_HYPERVISOR feature bit +Patch-mainline: +References: bnc#441338 + +Impact: Number declaration only. + +Add X86_FEATURE_HYPERVISOR bit (CPUID level 1, ECX, bit 31). + +Signed-off-by: H. Peter Anvin +Signed-off-by: Alok N Kataria +Signed-off-by: Takashi Iwai +--- + + include/asm-x86/cpufeature.h | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + + +Index: linux-2.6.27.4-2-beta4/include/asm-x86/cpufeature.h +=================================================================== +--- linux-2.6.27.4-2-beta4.orig/include/asm-x86/cpufeature.h 2008-11-10 12:41:49.000000000 -0800 ++++ linux-2.6.27.4-2-beta4/include/asm-x86/cpufeature.h 2008-11-10 12:43:12.000000000 -0800 +@@ -97,6 +97,7 @@ + #define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */ + #define X86_FEATURE_XMM4_2 (4*32+20) /* Streaming SIMD Extensions-4.2 */ + #define X86_FEATURE_X2APIC (4*32+21) /* x2APIC */ ++#define X86_FEATURE_HYPERVISOR (4*32+31) /* Running on a hypervisor */ + + /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ + #define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */ +@@ -197,6 +198,7 @@ + #define cpu_has_pat boot_cpu_has(X86_FEATURE_PAT) + #define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2) + #define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC) ++#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) + + #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) + # define cpu_has_invlpg 1 diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-03-detect-from-hypervisor b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-03-detect-from-hypervisor new file mode 100644 index 000000000..9f1e82834 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-03-detect-from-hypervisor @@ -0,0 +1,372 @@ +From: Alok Kataria +Subject: x86: Hypervisor detection and get tsc_freq from hypervisor +Patch-mainline: +References: bnc#441338 + +Impact: Changes timebase calibration on Vmware. + +v3->v2 : Abstract the hypervisor detection and feature (tsc_freq) request + behind a hypervisor.c file +v2->v1 : Add a x86_hyper_vendor field to the cpuinfo_x86 structure. + This avoids multiple calls to the hypervisor detection function. + +This patch adds function to detect if we are running under VMware. +The current way to check if we are on VMware is following, +# check if "hypervisor present bit" is set, if so read the 0x40000000 + cpuid leaf and check for "VMwareVMware" signature. +# if the above fails, check the DMI vendors name for "VMware" string + if we find one we query the VMware hypervisor port to check if we are + under VMware. + +The DMI + "VMware hypervisor port check" is needed for older VMware products, +which don't implement the hypervisor signature cpuid leaf. +Also note that since we are checking for the DMI signature the hypervisor +port should never be accessed on native hardware. + +This patch also adds a hypervisor_get_tsc_freq function, instead of +calibrating the frequency which can be error prone in virtualized +environment, we ask the hypervisor for it. We get the frequency from +the hypervisor by accessing the hypervisor port if we are running on VMware. +Other hypervisors too can add code to the generic routine to get frequency on +their platform. + +Signed-off-by: Alok N Kataria +Signed-off-by: Dan Hecht +Signed-off-by: H. Peter Anvin +Signed-off-by: Takashi Iwai + +--- + + arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/common.c | 2 + arch/x86/kernel/cpu/common_64.c | 2 + arch/x86/kernel/cpu/hypervisor.c | 48 +++++++++++++++++++++ + arch/x86/kernel/cpu/vmware.c | 88 +++++++++++++++++++++++++++++++++++++++ + arch/x86/kernel/setup.c | 7 +++ + arch/x86/kernel/tsc.c | 9 +++ + include/asm-x86/hypervisor.h | 26 +++++++++++ + include/asm-x86/processor.h | 4 + + include/asm-x86/vmware.h | 26 +++++++++++ + 10 files changed, 212 insertions(+), 1 deletion(-) + create mode 100644 arch/x86/kernel/cpu/hypervisor.c + create mode 100644 arch/x86/kernel/cpu/vmware.c + create mode 100644 include/asm-x86/hypervisor.h + create mode 100644 include/asm-x86/vmware.h + + +--- a/arch/x86/kernel/cpu/Makefile ++++ b/arch/x86/kernel/cpu/Makefile +@@ -4,6 +4,7 @@ + + obj-y := intel_cacheinfo.o addon_cpuid_features.o + obj-y += proc.o feature_names.o ++obj-y += vmware.o hypervisor.o + + obj-$(CONFIG_X86_32) += common.o bugs.o + obj-$(CONFIG_X86_64) += common_64.o bugs_64.o +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #ifdef CONFIG_X86_LOCAL_APIC + #include + #include +@@ -505,6 +506,7 @@ static void __cpuinit identify_cpu(struc + c->x86, c->x86_model); + } + ++ init_hypervisor(c); + /* + * On SMP, boot_cpu_data holds the common feature set between + * all CPUs; so make sure that we indicate which features are +--- a/arch/x86/kernel/cpu/common_64.c ++++ b/arch/x86/kernel/cpu/common_64.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "cpu.h" + +@@ -387,6 +388,7 @@ static void __cpuinit identify_cpu(struc + + detect_ht(c); + ++ init_hypervisor(c); + /* + * On SMP, boot_cpu_data holds the common feature set between + * all CPUs; so make sure that we indicate which features are +--- /dev/null ++++ b/arch/x86/kernel/cpu/hypervisor.c +@@ -0,0 +1,48 @@ ++/* ++ * Common hypervisor code ++ * ++ * Copyright (C) 2008, VMware, Inc. ++ * Author : Alok N Kataria ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or ++ * NON INFRINGEMENT. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#include ++#include ++ ++static inline void __cpuinit ++detect_hypervisor_vendor(struct cpuinfo_x86 *c) ++{ ++ if (vmware_platform()) { ++ c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; ++ } else { ++ c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; ++ } ++} ++ ++unsigned long get_hypervisor_tsc_freq(void) ++{ ++ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) ++ return vmware_get_tsc_khz(); ++ return 0; ++} ++ ++void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) ++{ ++ detect_hypervisor_vendor(c); ++} ++ +--- /dev/null ++++ b/arch/x86/kernel/cpu/vmware.c +@@ -0,0 +1,88 @@ ++/* ++ * VMware Detection code. ++ * ++ * Copyright (C) 2008, VMware, Inc. ++ * Author : Alok N Kataria ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or ++ * NON INFRINGEMENT. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#include ++#include ++ ++#define CPUID_VMWARE_INFO_LEAF 0x40000000 ++#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 ++#define VMWARE_HYPERVISOR_PORT 0x5658 ++ ++#define VMWARE_PORT_CMD_GETVERSION 10 ++#define VMWARE_PORT_CMD_GETHZ 45 ++ ++#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ ++ __asm__("inl (%%dx)" : \ ++ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ ++ "0"(VMWARE_HYPERVISOR_MAGIC), \ ++ "1"(VMWARE_PORT_CMD_##cmd), \ ++ "2"(VMWARE_HYPERVISOR_PORT), "3"(0) : \ ++ "memory"); ++ ++static inline int __vmware_platform(void) ++{ ++ uint32_t eax, ebx, ecx, edx; ++ VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx); ++ return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC; ++} ++ ++static unsigned long __vmware_get_tsc_khz(void) ++{ ++ uint64_t tsc_hz; ++ uint32_t eax, ebx, ecx, edx; ++ ++ VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); ++ ++ if (eax == (uint32_t)-1) ++ return 0; ++ tsc_hz = eax | (((uint64_t)ebx) << 32); ++ do_div(tsc_hz, 1000); ++ BUG_ON(tsc_hz >> 32); ++ return tsc_hz; ++} ++ ++int vmware_platform(void) ++{ ++ if (cpu_has_hypervisor) { ++ unsigned int eax, ebx, ecx, edx; ++ char hyper_vendor_id[13]; ++ ++ cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx); ++ memcpy(hyper_vendor_id + 0, &ebx, 4); ++ memcpy(hyper_vendor_id + 4, &ecx, 4); ++ memcpy(hyper_vendor_id + 8, &edx, 4); ++ hyper_vendor_id[12] = '\0'; ++ if (!strcmp(hyper_vendor_id, "VMwareVMware")) ++ return 1; ++ } else if (dmi_available && dmi_name_in_vendors("VMware") && ++ __vmware_platform()) ++ return 1; ++ ++ return 0; ++} ++ ++unsigned long vmware_get_tsc_khz(void) ++{ ++ BUG_ON(!vmware_platform()); ++ return __vmware_get_tsc_khz(); ++} +--- a/arch/x86/kernel/setup.c ++++ b/arch/x86/kernel/setup.c +@@ -98,6 +98,7 @@ + + #include + #include ++#include + + #include + #include +@@ -896,6 +897,12 @@ void __init setup_arch(char **cmdline_p) + e820_reserve_resources(); + e820_mark_nosave_regions(max_low_pfn); + ++ /* ++ * VMware detection requires dmi to be available, so this ++ * needs to be done after dmi_scan_machine, for the BP. ++ */ ++ init_hypervisor(&boot_cpu_data); ++ + #ifdef CONFIG_X86_32 + request_resource(&iomem_resource, &video_ram_resource); + #endif +--- a/arch/x86/kernel/tsc.c ++++ b/arch/x86/kernel/tsc.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + unsigned int cpu_khz; /* TSC clocks / usec, not used here */ + EXPORT_SYMBOL(cpu_khz); +@@ -189,9 +190,15 @@ unsigned long native_calibrate_tsc(void) + { + u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2; + unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; +- unsigned long flags; ++ unsigned long flags, tsc_khz; + int hpet = is_hpet_enabled(), i; + ++ tsc_khz = get_hypervisor_tsc_freq(); ++ if (tsc_khz) { ++ printk(KERN_INFO "TSC: Frequency read from the hypervisor\n"); ++ return tsc_khz; ++ } ++ + /* + * Run 5 calibration loops to get the lowest frequency value + * (the best estimate). We use two different calibration modes +--- /dev/null ++++ b/include/asm-x86/hypervisor.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2008, VMware, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or ++ * NON INFRINGEMENT. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++#ifndef ASM_X86__HYPERVISOR_H ++#define ASM_X86__HYPERVISOR_H ++ ++extern unsigned long get_hypervisor_tsc_freq(void); ++extern void init_hypervisor(struct cpuinfo_x86 *c); ++ ++#endif +--- a/include/asm-x86/processor.h ++++ b/include/asm-x86/processor.h +@@ -109,6 +109,7 @@ struct cpuinfo_x86 { + /* Index into per_cpu list: */ + u16 cpu_index; + #endif ++ unsigned int x86_hyper_vendor; + } __attribute__((__aligned__(SMP_CACHE_BYTES))); + + #define X86_VENDOR_INTEL 0 +@@ -122,6 +123,9 @@ struct cpuinfo_x86 { + + #define X86_VENDOR_UNKNOWN 0xff + ++#define X86_HYPER_VENDOR_NONE 0 ++#define X86_HYPER_VENDOR_VMWARE 1 ++ + /* + * capabilities of CPUs + */ +--- /dev/null ++++ b/include/asm-x86/vmware.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2008, VMware, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or ++ * NON INFRINGEMENT. See the GNU General Public License for more ++ * details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++#ifndef ASM_X86__VMWARE_H ++#define ASM_X86__VMWARE_H ++ ++extern unsigned long vmware_get_tsc_khz(void); ++extern int vmware_platform(void); ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-04-use-TSC_RELIABLE b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-04-use-TSC_RELIABLE new file mode 100644 index 000000000..df569ddbd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-04-use-TSC_RELIABLE @@ -0,0 +1,121 @@ +From: Alok Kataria +Subject: x86: USE the synthetic TSC_RELIABLE feature bit. +Patch-mainline: +References: bnc#441338 + +Impact: Changes timebase calibration on Vmware. + +Use the synthetic TSC_RELIABLE bit to workaround virtualization anomalies. + +Virtual TSCs can be kept nearly in sync, but because the virtual TSC +offset is set by software, it's not perfect. So, the TSC +synchronization test can fail. Even then the TSC can be used as a +clocksource since the VMware platform exports a reliable TSC to the +guest for timekeeping purposes. Use this bit to check if we need to +skip the TSC sync checks. + +Along with this also set the CONSTANT_TSC bit when on VMware, since we +still want to use TSC as clocksource on VM running over hardware which +has unsynchronized TSC's (opteron's), since the hypervisor will take +care of providing consistent TSC to the guest. + +Signed-off-by: Alok N Kataria +Signed-off-by: Dan Hecht +Signed-off-by: H. Peter Anvin +Signed-off-by: Takashi Iwai + +--- + + arch/x86/kernel/cpu/hypervisor.c | 11 ++++++++++- + arch/x86/kernel/cpu/vmware.c | 18 ++++++++++++++++++ + arch/x86/kernel/tsc_sync.c | 8 +++++++- + include/asm-x86/vmware.h | 1 + + 4 files changed, 36 insertions(+), 2 deletions(-) + + +diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c +index 7bd5506..35ae2b7 100644 +--- a/arch/x86/kernel/cpu/hypervisor.c ++++ b/arch/x86/kernel/cpu/hypervisor.c +@@ -41,8 +41,17 @@ unsigned long get_hypervisor_tsc_freq(void) + return 0; + } + ++static inline void __cpuinit ++hypervisor_set_feature_bits(struct cpuinfo_x86 *c) ++{ ++ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { ++ vmware_set_feature_bits(c); ++ return; ++ } ++} ++ + void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) + { + detect_hypervisor_vendor(c); ++ hypervisor_set_feature_bits(c); + } +- +diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c +index d5d1b75..2ac4394 100644 +--- a/arch/x86/kernel/cpu/vmware.c ++++ b/arch/x86/kernel/cpu/vmware.c +@@ -86,3 +86,21 @@ unsigned long vmware_get_tsc_khz(void) + BUG_ON(!vmware_platform()); + return __vmware_get_tsc_khz(); + } ++ ++/* ++ * VMware hypervisor takes care of exporting a reliable TSC to the guest. ++ * Still, due to timing difference when running on virtual cpus, the TSC can ++ * be marked as unstable in some cases. For example, the TSC sync check at ++ * bootup can fail due to a marginal offset between vcpus' TSCs (though the ++ * TSCs do not drift from each other). Also, the ACPI PM timer clocksource ++ * is not suitable as a watchdog when running on a hypervisor because the ++ * kernel may miss a wrap of the counter if the vcpu is descheduled for a ++ * long time. To skip these checks at runtime we set these capability bits, ++ * so that the kernel could just trust the hypervisor with providing a ++ * reliable virtual TSC that is suitable for timekeeping. ++ */ ++void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) ++{ ++ set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); ++ set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); ++} +diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c +index 9ffb01c..5977c40 100644 +--- a/arch/x86/kernel/tsc_sync.c ++++ b/arch/x86/kernel/tsc_sync.c +@@ -108,6 +108,12 @@ void __cpuinit check_tsc_sync_source(int cpu) + if (unsynchronized_tsc()) + return; + ++ if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) { ++ printk(KERN_INFO ++ "Skipping synchronization checks as TSC is reliable.\n"); ++ return; ++ } ++ + printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:", + smp_processor_id(), cpu); + +@@ -161,7 +167,7 @@ void __cpuinit check_tsc_sync_target(void) + { + int cpus = 2; + +- if (unsynchronized_tsc()) ++ if (unsynchronized_tsc() || boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) + return; + + /* +diff --git a/include/asm-x86/vmware.h b/include/asm-x86/vmware.h +index 02dfea5..c11b7e1 100644 +--- a/include/asm-x86/vmware.h ++++ b/include/asm-x86/vmware.h +@@ -22,5 +22,6 @@ + + extern unsigned long vmware_get_tsc_khz(void); + extern int vmware_platform(void); ++extern void vmware_set_feature_bits(struct cpuinfo_x86 *c); + + #endif diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-05-skip-tsc-clocksource b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-05-skip-tsc-clocksource new file mode 100644 index 000000000..96eda075b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-05-skip-tsc-clocksource @@ -0,0 +1,135 @@ +From: Alok Kataria +Subject: x86: Skip verification by the watchdog for TSC clocksource. +Patch-mainline: +References: bnc#441338 + +Impact: Changes timekeeping on Vmware (or with tsc=reliable). + +This is achieved by resetting the CLOCKSOURCE_MUST_VERIFY flag. + +We add a tsc=reliable commandline option to enable this. +This enables legacy hardware without HPET, LAPIC, or ACPI timers +to enter high-resolution timer mode. + +Along with that have extended this to be used in virtualization environement +too. Now we also set this flag if the X86_FEATURE_TSC_RELIABLE bit is set. +This is important since there is a wrap-around problem with the acpi_pm timer. +The acpi_pm counter is just 24bits and this can overflow in ~4 seconds. With +the NO_HZ kernels in virtualized environment, there can be situations when +the guest is descheduled for longer duration, as a result we may miss the wrap +of the acpi counter. When TSC is used as a clocksource and acpi_pm timer is +being used as the watchdog clocksource this error in acpi_pm results in TSC +being marked as unstable, and essentially results in time dropping in chunks +of 4 seconds whenever this wrap is missed. Since the virtualized TSC is +reliable on VMware, we should always use the TSCs clocksource on VMware, so +we skip the verfication at runtime, by checking for the feature bit. + +Since we reset the flag for mgeode systems too, i have combined +the mgeode case with the feature bit check. + +Signed-off-by: Jeff Hansen +Signed-off-by: Alok N Kataria +Signed-off-by: Dan Hecht +Signed-off-by: H. Peter Anvin +Signed-off-by: Takashi Iwai + +--- + + Documentation/kernel-parameters.txt | 7 +++++++ + arch/x86/kernel/tsc.c | 33 +++++++++++++++++++++------------ + 2 files changed, 28 insertions(+), 12 deletions(-) + + +--- a/arch/x86/kernel/tsc.c ++++ b/arch/x86/kernel/tsc.c +@@ -32,6 +32,7 @@ static int tsc_unstable; + erroneous rdtsc usage on !cpu_has_tsc processors */ + static int tsc_disabled = -1; + ++static int tsc_clocksource_reliable; + /* + * Scheduler clock - returns current time in nanosec units. + */ +@@ -99,6 +100,15 @@ int __init notsc_setup(char *str) + + __setup("notsc", notsc_setup); + ++static int __init tsc_setup(char *str) ++{ ++ if (!strcmp(str, "reliable")) ++ tsc_clocksource_reliable = 1; ++ return 1; ++} ++ ++__setup("tsc=", tsc_setup); ++ + #define MAX_RETRIES 5 + #define SMI_TRESHOLD 50000 + +@@ -564,24 +574,21 @@ static struct dmi_system_id __initdata b + {} + }; + +-/* +- * Geode_LX - the OLPC CPU has a possibly a very reliable TSC +- */ ++static void __init check_system_tsc_reliable(void) ++{ + #ifdef CONFIG_MGEODE_LX +-/* RTSC counts during suspend */ ++ /* RTSC counts during suspend */ + #define RTSC_SUSP 0x100 +- +-static void __init check_geode_tsc_reliable(void) +-{ + unsigned long res_low, res_high; + + rdmsr_safe(MSR_GEODE_BUSCONT_CONF0, &res_low, &res_high); ++ /* Geode_LX - the OLPC CPU has a possibly a very reliable TSC */ + if (res_low & RTSC_SUSP) +- clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; +-} +-#else +-static inline void check_geode_tsc_reliable(void) { } ++ tsc_clocksource_reliable = 1; + #endif ++ if (boot_cpu_has(X86_FEATURE_TSC_RELIABLE)) ++ tsc_clocksource_reliable = 1; ++} + + /* + * Make an educated guess if the TSC is trustworthy and synchronized +@@ -616,6 +623,8 @@ static void __init init_tsc_clocksource( + { + clocksource_tsc.mult = clocksource_khz2mult(tsc_khz, + clocksource_tsc.shift); ++ if (tsc_clocksource_reliable) ++ clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY; + /* lower the rating if we already know its unstable: */ + if (check_tsc_unstable()) { + clocksource_tsc.rating = 0; +@@ -676,7 +685,7 @@ void __init tsc_init(void) + if (unsynchronized_tsc()) + mark_tsc_unstable("TSCs unsynchronized"); + +- check_geode_tsc_reliable(); ++ check_system_tsc_reliable(); + init_tsc_clocksource(); + } + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -2200,6 +2200,13 @@ and is between 256 and 4096 characters. + Format: + ,,,,,,,, + ++ tsc= Disable clocksource-must-verify flag for TSC. ++ Format: ++ [x86] reliable: mark tsc clocksource as reliable, this ++ disables clocksource verification at runtime. ++ Used to enable high-resolution timer mode on older ++ hardware, and in virtualized environment. ++ + turbografx.map[2|3]= [HW,JOY] + TurboGraFX parallel port interface + Format: diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-06-fix-vmware_get_tsc b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-06-fix-vmware_get_tsc new file mode 100644 index 000000000..057c9562a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-06-fix-vmware_get_tsc @@ -0,0 +1,46 @@ +From: Alok Kataria +Subject: x86: VMware: Fix vmware_get_tsc code +Patch-mainline: +References: bnc#441338 + +Impact: Fix possible failure to calibrate the TSC on Vmware near 4 GHz + +The current version of the code to get the tsc frequency from +the VMware hypervisor, will be broken on processor with frequency +(4G-1) HZ, because on such processors eax will have UINT_MAX +and that would be legitimate. +We instead check that EBX did change to decide if we were able to +read the frequency from the hypervisor. + +Signed-off-by: Alok N Kataria +Signed-off-by: H. Peter Anvin +Signed-off-by: Takashi Iwai + +--- + + arch/x86/kernel/cpu/vmware.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + + +diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c +index 2ac4394..a0905ec 100644 +--- a/arch/x86/kernel/cpu/vmware.c ++++ b/arch/x86/kernel/cpu/vmware.c +@@ -36,7 +36,7 @@ + "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ + "0"(VMWARE_HYPERVISOR_MAGIC), \ + "1"(VMWARE_PORT_CMD_##cmd), \ +- "2"(VMWARE_HYPERVISOR_PORT), "3"(0) : \ ++ "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \ + "memory"); + + static inline int __vmware_platform(void) +@@ -53,7 +53,7 @@ static unsigned long __vmware_get_tsc_khz(void) + + VMWARE_PORT(GETHZ, eax, ebx, ecx, edx); + +- if (eax == (uint32_t)-1) ++ if (ebx == UINT_MAX) + return 0; + tsc_hz = eax | (((uint64_t)ebx) << 32); + do_div(tsc_hz, 1000); diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-07-DMI-product-serial-key b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-07-DMI-product-serial-key new file mode 100644 index 000000000..b22aea752 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86-vmware-tsc-07-DMI-product-serial-key @@ -0,0 +1,94 @@ +From: Alok Kataria +Subject: x86: vmware: look for DMI string in the product serial key +Patch-mainline: +References: bnc#441338 + +Impact: Should permit VMware detection on older platforms where the +vendor is changed. Could theoretically cause a regression if some +weird serial number scheme contains the string "VMware" by pure +chance. Seems unlikely, especially with the mixed case. + +In some user configured cases, VMware may choose not to put a VMware specific +DMI string, but the product serial key is always there and is VMware specific. +Add a interface to check the serial key, when checking for VMware in the DMI +information. + +Signed-off-by: Alok N Kataria +Signed-off-by: H. Peter Anvin +Signed-off-by: Takashi Iwai + +--- + + arch/x86/kernel/cpu/vmware.c | 7 ++++++- + drivers/firmware/dmi_scan.c | 11 +++++++++++ + include/linux/dmi.h | 2 ++ + 3 files changed, 19 insertions(+), 1 deletions(-) + + +diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c +index a0905ec..c034bda 100644 +--- a/arch/x86/kernel/cpu/vmware.c ++++ b/arch/x86/kernel/cpu/vmware.c +@@ -61,6 +61,11 @@ static unsigned long __vmware_get_tsc_khz(void) + return tsc_hz; + } + ++/* ++ * While checking the dmi string infomation, just checking the product ++ * serial key should be enough, as this will always have a VMware ++ * specific string when running under VMware hypervisor. ++ */ + int vmware_platform(void) + { + if (cpu_has_hypervisor) { +@@ -74,7 +79,7 @@ int vmware_platform(void) + hyper_vendor_id[12] = '\0'; + if (!strcmp(hyper_vendor_id, "VMwareVMware")) + return 1; +- } else if (dmi_available && dmi_name_in_vendors("VMware") && ++ } else if (dmi_available && dmi_name_in_serial("VMware") && + __vmware_platform()) + return 1; + +diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c +index 455575b..4dd780c 100644 +--- a/drivers/firmware/dmi_scan.c ++++ b/drivers/firmware/dmi_scan.c +@@ -457,6 +457,17 @@ const char *dmi_get_system_info(int field) + } + EXPORT_SYMBOL(dmi_get_system_info); + ++/** ++ * dmi_name_in_serial - Check if string is in the DMI product serial ++ * information. ++ */ ++int dmi_name_in_serial(const char *str) ++{ ++ int f = DMI_PRODUCT_SERIAL; ++ if (dmi_ident[f] && strstr(dmi_ident[f], str)) ++ return 1; ++ return 0; ++} + + /** + * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. +diff --git a/include/linux/dmi.h b/include/linux/dmi.h +index 2a063b6..098e292 100644 +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -81,6 +81,7 @@ extern const struct dmi_device * dmi_find_device(int type, const char *name, + extern void dmi_scan_machine(void); + extern int dmi_get_year(int field); + extern int dmi_name_in_vendors(const char *str); ++extern int dmi_name_in_serial(const char *str); + extern int dmi_available; + extern int dmi_walk(void (*decode)(const struct dmi_header *)); + +@@ -93,6 +94,7 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na + static inline void dmi_scan_machine(void) { return; } + static inline int dmi_get_year(int year) { return 0; } + static inline int dmi_name_in_vendors(const char *s) { return 0; } ++static inline int dmi_name_in_serial(const char *s) { return 0; } + #define dmi_available 0 + static inline int dmi_walk(void (*decode)(const struct dmi_header *)) + { return -1; } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_64-hpet-64bit-timer.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_64-hpet-64bit-timer.patch new file mode 100644 index 000000000..2ad0b9f4f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_64-hpet-64bit-timer.patch @@ -0,0 +1,224 @@ + +From: Jiri Bohac +Subject: allow 64-bit mode for HPET Timer0 +References: bnc#456700 + +The kernel uses the HPET timers in 32-bit mode for clock-events. +While 32 bits, with a wrap-around time of >4 minutes, is probably +good enough for the clock-event purposes, on some chipsets this +has a negative side-effect on the HPET main counter. + +Unlike the original HPET specification 1.0 from 2004, which does not +mention any side-effects of setting TN_32MODE_CNF on the +individual timers, the ICH9 documentation, for example, says: + + NOTE: When this bit is set to ‘1’, the hardware counter will + do a 32-bit operation on comparator match and rollovers, thus + the upper 32-bit of the Timer 0 Comparator Value register is + ignored. The upper 32-bit of the main counter is not involved + in any rollover from lower 32-bit of the main counter and + becomes all zeros. + +(see http://www.intel.com/assets/pdf/datasheet/316972.pdf, page +819, section 21.1.5, Bit 8). I've seen this behaviour also on +ICH8. I have no idea what other chipsets are affected. But I have +seen AMD chipsets that Do The Right Thing. + +This means, that when the kernel configures the Timer 0 to 32-bit +mode, on these chipsets it also cripples the 64-bit main counter +to 32 bits. + +The HPET may be mmapped in userspace and the main counter +accessed directly by applications, expecting a 64-bit main +counter. + +This patch allows the Timer0 to be configured in 64-bit mode +on x86_64 when a hpet64 command-line option is specified. + +Signed-off-by: Jiri Bohac + +--- + arch/x86/kernel/hpet.c | 89 +++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 79 insertions(+), 10 deletions(-) + +--- a/arch/x86/kernel/hpet.c 2009-01-24 16:39:47.000000000 +0100 ++++ b/arch/x86/kernel/hpet.c 2009-01-24 16:56:04.000000000 +0100 +@@ -24,6 +24,7 @@ + */ + unsigned long hpet_address; + static void __iomem *hpet_virt_address; ++static int hpet_legacy_use_64_bits; + + unsigned long hpet_readl(unsigned long a) + { +@@ -37,6 +38,33 @@ static inline void hpet_writel(unsigned + + #ifdef CONFIG_X86_64 + #include ++static inline unsigned long hpet_read_value(unsigned long a) ++{ ++ if (hpet_legacy_use_64_bits) ++ return readq(hpet_virt_address + a); ++ else ++ return readl(hpet_virt_address + a); ++} ++ ++static void hpet_write_value(unsigned long d, unsigned long a) ++{ ++ if (hpet_legacy_use_64_bits) ++ writeq(d, hpet_virt_address + a); ++ else ++ writel(d, hpet_virt_address + a); ++} ++ ++#else ++ ++static inline unsigned long hpet_read_value(unsigned long a) ++{ ++ return readl(hpet_virt_address + a); ++} ++ ++static void hpet_write_value(unsigned long d, unsigned long a) ++{ ++ writel(d, hpet_virt_address + a); ++} + #endif + + static inline void hpet_set_mapping(void) +@@ -78,6 +106,17 @@ static int __init disable_hpet(char *str + } + __setup("nohpet", disable_hpet); + ++#ifdef CONFIG_X86_64 ++static int hpet64 = 0; ++static int __init hpet64_setup(char *str) ++{ ++ hpet64 = 1; ++ return 1; ++} ++__setup("hpet64", hpet64_setup); ++#endif ++ ++ + static inline int is_hpet_capable(void) + { + return (!boot_hpet_disable && hpet_address); +@@ -141,6 +180,7 @@ static void hpet_reserve_platform_timers + * Common hpet info + */ + static unsigned long hpet_period; ++static int hpet_legacy_use_64_bits; /* configure T0 in 64-bit mode? */ + + static void hpet_legacy_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt); +@@ -192,10 +232,38 @@ static void hpet_enable_legacy_int(void) + hpet_legacy_int_enabled = 1; + } + ++static int timer0_use_64_bits(void) ++{ ++#ifndef CONFIG_X86_64 ++ /* using the HPET in 64-bit mode without atomic 64-bit ++ * accesses is too inefficient ++ */ ++ return 0; ++#else ++ ++ if (unlikely(hpet64)) { ++ u32 id, t0_cfg; ++ id = hpet_readl(HPET_ID); ++ t0_cfg = hpet_readl(HPET_T0_CFG); ++ ++ if ((id & HPET_ID_64BIT) && (t0_cfg & HPET_TN_64BIT_CAP)) { ++ printk(KERN_DEBUG "hpet timer0 configured in 64-bit mode\n"); ++ return 1; ++ } ++ else { ++ printk(KERN_DEBUG "hpet timer0 does not support 64-bit mode\n"); ++ return 0; ++ } ++ } ++ else return 0; ++#endif ++} ++ + static void hpet_legacy_clockevent_register(void) + { + /* Start HPET legacy interrupts */ + hpet_enable_legacy_int(); ++ hpet_legacy_use_64_bits = timer0_use_64_bits(); + + /* + * The mult factor is defined as (include/linux/clockchips.h) +@@ -233,26 +301,28 @@ static void hpet_legacy_set_mode(enum cl + case CLOCK_EVT_MODE_PERIODIC: + delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult; + delta >>= hpet_clockevent.shift; +- now = hpet_readl(HPET_COUNTER); ++ now = hpet_read_value(HPET_COUNTER); + cmp = now + (unsigned long) delta; + cfg = hpet_readl(HPET_T0_CFG); + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | +- HPET_TN_SETVAL | HPET_TN_32BIT; ++ HPET_TN_SETVAL | ++ (hpet_legacy_use_64_bits ? 0 : HPET_TN_32BIT); + hpet_writel(cfg, HPET_T0_CFG); + /* + * The first write after writing TN_SETVAL to the + * config register sets the counter value, the second + * write sets the period. + */ +- hpet_writel(cmp, HPET_T0_CMP); ++ hpet_write_value(cmp, HPET_T0_CMP); + udelay(1); +- hpet_writel((unsigned long) delta, HPET_T0_CMP); ++ hpet_write_value((unsigned long) delta, HPET_T0_CMP); + break; + + case CLOCK_EVT_MODE_ONESHOT: + cfg = hpet_readl(HPET_T0_CFG); + cfg &= ~HPET_TN_PERIODIC; +- cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; ++ cfg |= HPET_TN_ENABLE | ++ (hpet_legacy_use_64_bits ? 0 : HPET_TN_32BIT); + hpet_writel(cfg, HPET_T0_CFG); + break; + +@@ -272,11 +342,11 @@ static void hpet_legacy_set_mode(enum cl + static int hpet_legacy_next_event(unsigned long delta, + struct clock_event_device *evt) + { +- u32 cnt; ++ unsigned long cnt; + +- cnt = hpet_readl(HPET_COUNTER); ++ cnt = hpet_read_value(HPET_COUNTER); + cnt += (u32) delta; +- hpet_writel(cnt, HPET_T0_CMP); ++ hpet_write_value(cnt, HPET_T0_CMP); + + hpet_readl(HPET_T0_CMP); /* pre-read for bnc#433746 */ + /* +@@ -284,9 +354,9 @@ static int hpet_legacy_next_event(unsign + * what we wrote hit the chip before we compare it to the + * counter. + */ +- WARN_ON_ONCE((u32)hpet_readl(HPET_T0_CMP) != cnt); ++ WARN_ON_ONCE((u32)hpet_readl(HPET_T0_CMP) != (u32)cnt); + +- return (s32)((u32)hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; ++ return (s32)((u32)hpet_readl(HPET_COUNTER) - (u32)cnt) >= 0 ? -ETIME : 0; + } + + /* +--- a/Documentation/kernel-parameters.txt 2009-01-24 16:39:47.000000000 +0100 ++++ b/Documentation/kernel-parameters.txt 2009-01-24 16:46:51.000000000 +0100 +@@ -475,6 +475,8 @@ and is between 256 and 4096 characters. + force: allow force enabled of undocumented chips (ICH4, + VIA, nVidia) + ++ hpet64 [X86-64,HPET] enable 64-bit mode of the HPET timer (bnc#456700) ++ + com20020= [HW,NET] ARCnet - COM20020 chipset + Format: + [,[,[,[,[,]]]]] diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_64-unwind-annotations b/src/patches/suse-2.6.27.31/patches.arch/x86_64-unwind-annotations new file mode 100644 index 000000000..a2ee3be51 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_64-unwind-annotations @@ -0,0 +1,88 @@ +From: jbeulich@novell.com +Subject: fix unwind annotations +Patch-mainline: some parts in 2.6.29 +References: bnc#472783 + +--- + arch/x86/kernel/entry_64.S | 8 +++++--- + arch/x86/kernel/head_64.S | 13 +++++++++++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +--- a/arch/x86/kernel/entry_64.S ++++ b/arch/x86/kernel/entry_64.S +@@ -275,12 +275,13 @@ ENTRY(native_usergs_sysret64) + ENTRY(ret_from_fork) + CFI_DEFAULT_STACK + push kernel_eflags(%rip) +- CFI_ADJUST_CFA_OFFSET 4 ++ CFI_ADJUST_CFA_OFFSET 8 + popf # reset kernel eflags +- CFI_ADJUST_CFA_OFFSET -4 ++ CFI_ADJUST_CFA_OFFSET -8 + call schedule_tail + GET_THREAD_INFO(%rcx) + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx) ++ CFI_REMEMBER_STATE + jnz rff_trace + rff_action: + RESTORE_REST +@@ -290,6 +291,7 @@ rff_action: + jnz int_ret_from_sys_call + RESTORE_TOP_OF_STACK %rdi,ARGOFFSET + jmp ret_from_sys_call ++ CFI_RESTORE_STATE + rff_trace: + movq %rsp,%rdi + call syscall_trace_leave +@@ -1080,7 +1082,6 @@ error_exit: + andl %edi,%edx + jnz retint_careful + jmp retint_swapgs +- CFI_ENDPROC + + error_kernelspace: + incl %ebx +@@ -1098,6 +1099,7 @@ error_kernelspace: + cmpq $gs_change,RIP(%rsp) + je error_swapgs + jmp error_sti ++ CFI_ENDPROC + KPROBE_END(error_entry) + + /* Reload gs selector with exception handling */ +--- a/arch/x86/kernel/head_64.S ++++ b/arch/x86/kernel/head_64.S +@@ -280,6 +280,8 @@ early_idt_handlers: + + ENTRY(early_idt_handler) + #ifdef CONFIG_EARLY_PRINTK ++#include ++#include + cmpl $2,early_recursion_flag(%rip) + jz 1f + incl early_recursion_flag(%rip) +@@ -295,6 +297,16 @@ ENTRY(early_idt_handler) + testl $0x27d00,%eax + je 0f + popq %r8 # get error code ++ ++ CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME ++ CFI_DEF_CFA rsp, SS+8-RIP ++# CFI_REL_OFFSET ss, SS-RIP ++ CFI_REL_OFFSET rsp, RSP-RIP ++# CFI_REL_OFFSET rflags, EFLAGS-RIP ++# CFI_REL_OFFSET cs, CS-RIP ++ CFI_REL_OFFSET rip, RIP-RIP ++ + 0: movq 0(%rsp),%rcx # get ip + movq 8(%rsp),%rdx # get cs + xorl %eax,%eax +@@ -308,6 +320,7 @@ ENTRY(early_idt_handler) + movq 0(%rsp),%rsi # get rip again + call __print_symbol + #endif ++ CFI_ENDPROC + #endif /* EARLY_PRINTK */ + 1: hlt + jmp 1b diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_agpgart-g33-stoeln-fix-2.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_agpgart-g33-stoeln-fix-2.patch new file mode 100644 index 000000000..85225ae4d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_agpgart-g33-stoeln-fix-2.patch @@ -0,0 +1,74 @@ +From: Brandon Philips +Subject: Avoid oops on G33 in 1MB stolen Mem case +References: bnc#391261 +Patch-Mainline: soon (see bug for ref) + +This is similar to f443675affe3f16dd428e46f0f7fd3f4d703eeab which was +reverted because it broke with older XOrg driver. This patch only fixes +the 1MB stolen case since it causes an oops due to a calculation +problem. + +This will not work with older X drivers without the accompanying patch +but I think avoiding an oops and making it possible to work with an +up-to-date xorg driver is reasonable. + +Explanation of the oops: + +> static void intel_i830_init_gtt_entries(void) +... +> } else if (IS_G33) { +> /* G33's GTT size defined in gmch_ctrl */ +> switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { +> case G33_PGETBL_SIZE_1M: +> size = 1024; +> break; +... +> size += 4; + +size = 1028 + +Then since we have the BIOS setting 1MB for the device in the GMCH +control we get to here: + +> } else { +> switch (gmch_ctrl & I855_GMCH_GMS_MASK) { +> case I855_GMCH_GMS_STOLEN_1M: +> gtt_entries = MB(1) - KB(size); +> break; + +MB(1) = 1 * 1024 * 1024 +KB(1028) = 1028 * 1024 + +MB(1) - KB(1028) = -4096 + +> gtt_entries /= KB(4); +> intel_private.gtt_entries = gtt_entries; + +We end up with -1 in gtt_entries. + +This leads to intel_i915_configure reading/writing to areas outside of +mapped memory and the oops. + +Signed-off-by: Brandon Philips +Acked-by: Thomas Renninger + +--- + drivers/char/agp/intel-agp.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/char/agp/intel-agp.c ++++ b/drivers/char/agp/intel-agp.c +@@ -564,6 +564,13 @@ static void intel_i830_init_gtt_entries( + } else { + switch (gmch_ctrl & I855_GMCH_GMS_MASK) { + case I855_GMCH_GMS_STOLEN_1M: ++ if (IS_G33) { ++ size = 0; ++ printk(KERN_WARNING PFX ++ "Warning: G33 chipset with 1MB" ++ " allocated. Older X.org Intel drivers" ++ " will not work.\n"); ++ } + gtt_entries = MB(1) - KB(size); + break; + case I855_GMCH_GMS_STOLEN_4M: diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_fix_llc_shared_map__cpu_llc_id_anomolies.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_fix_llc_shared_map__cpu_llc_id_anomolies.patch new file mode 100644 index 000000000..c8872f281 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_fix_llc_shared_map__cpu_llc_id_anomolies.patch @@ -0,0 +1,76 @@ +From: Suresh Siddha +Subject: x86: fix intel x86_64 llc_shared_map/cpu_llc_id anomolies +References: bnc#464329 +Patch-Mainline: In .28 x86 -tip tree, soon in .29, will possibly/hopefully pop up in stable trees +Signed-off-by: Thomas Renninger + +Date: Thu Dec 18 18:09:21 2008 -0800 +commit 345077cd98ff5532b2d1158013c3fec7b1ae85ec + + Impact: fix wrong cache sharing detection on platforms supporting > 8 bit apicid's + + In the presence of extended topology eumeration leaf 0xb provided + by cpuid, 32bit extended initial_apicid in cpuinfo_x86 struct will be + updated by detect_extended_topology(). At this instance, we should also + reinit the apicid (which could also potentially be extended to 32bit). + + With out this there will potentially be duplicate apicid's populated in the + per cpu's cpuinfo_x86 struct, resulting in wrong cache sharing topology etc + detected by init_intel_cacheinfo(). + + Reported-by: Dimitri Sivanich + Signed-off-by: Suresh Siddha + Acked-by: Dimitri Sivanich + Signed-off-by: Ingo Molnar + Cc: + +--- + arch/x86/kernel/cpu/addon_cpuid_features.c | 8 ++++++++ + arch/x86/kernel/cpu/intel.c | 9 +++++++-- + 2 files changed, 15 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/cpu/addon_cpuid_features.c ++++ b/arch/x86/kernel/cpu/addon_cpuid_features.c +@@ -120,9 +120,17 @@ void __cpuinit detect_extended_topology( + c->cpu_core_id = phys_pkg_id(c->initial_apicid, ht_mask_width) + & core_select_mask; + c->phys_proc_id = phys_pkg_id(c->initial_apicid, core_plus_mask_width); ++ /* ++ * Reinit the apicid, now that we have extended initial_apicid. ++ */ ++ c->apicid = phys_pkg_id(c->initial_apicid, 0); + #else + c->cpu_core_id = phys_pkg_id(ht_mask_width) & core_select_mask; + c->phys_proc_id = phys_pkg_id(core_plus_mask_width); ++ /* ++ * Reinit the apicid, now that we have extended initial_apicid. ++ */ ++ c->apicid = phys_pkg_id(0); + #endif + c->x86_max_cores = (core_level_siblings / smp_num_siblings); + +--- a/arch/x86/kernel/cpu/intel.c ++++ b/arch/x86/kernel/cpu/intel.c +@@ -151,6 +151,13 @@ static void __cpuinit init_intel(struct + } + #endif + ++ /* ++ * Detect the extended topology information if available. This ++ * will reinitialise the initial_apicid which will be used ++ * in init_intel_cacheinfo() ++ */ ++ detect_extended_topology(c); ++ + l2 = init_intel_cacheinfo(c); + if (c->cpuid_level > 9) { + unsigned eax = cpuid_eax(10); +@@ -196,8 +203,6 @@ static void __cpuinit init_intel(struct + if (p) + strcpy(c->x86_model_id, p); + +- detect_extended_topology(c); +- + if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) { + /* + * let's use the legacy cpuid vector 0x1 and 0x4 for topology diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_intel_cacheinfo_fix.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_intel_cacheinfo_fix.patch new file mode 100644 index 000000000..fe0ad540e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_intel_cacheinfo_fix.patch @@ -0,0 +1,33 @@ +From: Dimitri Sivanich +Subject: x86: Also move detect_extended_topology before init_intel_cacheinfo(c) in init_intel() +References: bnc#464329 +Patch-Mainline: yes or at least submitted + +This patch belongs to patches.arch/x86_fix_llc_shared_map__cpu_llc_id_anomolies.patch. +This one does the same change for 64 bit. Above patch is doing things for intel.c, +intel_64.c has been forgotten. + +Signed-off-by: Thomas Renninger + +--- + arch/x86/kernel/cpu/intel_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/kernel/cpu/intel_64.c ++++ b/arch/x86/kernel/cpu/intel_64.c +@@ -67,6 +67,7 @@ static void __cpuinit srat_detect_node(v + + static void __cpuinit init_intel(struct cpuinfo_x86 *c) + { ++ detect_extended_topology(c); + init_intel_cacheinfo(c); + if (c->cpuid_level > 9) { + unsigned eax = cpuid_eax(10); +@@ -94,7 +95,6 @@ static void __cpuinit init_intel(struct + set_cpu_cap(c, X86_FEATURE_REP_GOOD); + set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC); + +- detect_extended_topology(c); + if (!cpu_has(c, X86_FEATURE_XTOPOLOGY)) + c->x86_max_cores = intel_num_cpu_cores(c); + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_restrict_pci_early_quirks_to_root_bridges.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_restrict_pci_early_quirks_to_root_bridges.patch new file mode 100644 index 000000000..3763b83e5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_restrict_pci_early_quirks_to_root_bridges.patch @@ -0,0 +1,72 @@ +From: Andi Kleen +Subject: Only scan the root bus in early PCI quirks. +References: bnc#57886 +Patch-Mainline: submitted for .29 + +We found a situation on Linus' machine that the Nvidia timer +quirk hit on a Intel chipset system. The problem is that the +system has a fancy Nvidia card with an own PCI bridge, and +the early-quirks code looking for any NVidia bridge triggered +on it incorrectly. This didn't lead a boot failure by luck, +but the timer routing code selecting the wrong timer first and +some ugly messages. It might lead to real problems on +other systems. + +I checked all the devices which are currently checked for +by early_quirks and it turns out they are all located in +the root bus zero. + +So change the early-quirks loop to only scan bus 0. This +incidently also saves quite some unnecessary scanning work, +because early_quirks doesn't go through all the non root +busses. + +The graphics card is not on bus 0, so it is not matched +anymore. + +Signed-off-by: Andi Kleen +Signed-off-by: Thomas Renninger + +Index: linux-2.6.28-rc5-test/arch/x86/kernel/early-quirks.c +=================================================================== +--- linux-2.6.28-rc5-test.orig/arch/x86/kernel/early-quirks.c ++++ linux-2.6.28-rc5-test/arch/x86/kernel/early-quirks.c +@@ -200,6 +200,12 @@ struct chipset { + void (*f)(int num, int slot, int func); + }; + ++/* ++ * Only works for devices on the root bus. If you add any devices ++ * not on bus 0 readd another loop level in early_quirks(). But ++ * be careful because at least the Nvidia quirk here relies on ++ * only matching on bus 0. ++ */ + static struct chipset early_qrk[] __initdata = { + { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, nvidia_bugs }, +@@ -266,17 +272,17 @@ static int __init check_dev_quirk(int nu + + void __init early_quirks(void) + { +- int num, slot, func; ++ int slot, func; + + if (!early_pci_allowed()) + return; + + /* Poor man's PCI discovery */ +- for (num = 0; num < 32; num++) +- for (slot = 0; slot < 32; slot++) +- for (func = 0; func < 8; func++) { +- /* Only probe function 0 on single fn devices */ +- if (check_dev_quirk(num, slot, func)) +- break; +- } ++ /* Only scan the root bus */ ++ for (slot = 0; slot < 32; slot++) ++ for (func = 0; func < 8; func++) { ++ /* Only probe function 0 on single fn devices */ ++ if (check_dev_quirk(0, slot, func)) ++ break; ++ } + } diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi-uv-scir.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi-uv-scir.patch new file mode 100644 index 000000000..b99e167ca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi-uv-scir.patch @@ -0,0 +1,283 @@ +From: Mike Travis +Subject: SGI X86 UV: Provide a System Activity Indicator driver +References: FATE304268 bnc#426066 +Patch-mainline: 2.6.28 + +Signed-off-by: Thomas Renninger + +The SGI UV system has no LEDS but uses one of the system controller +regs to indicate the online internal state of the cpu. There is a +heartbeat bit indicating that the cpu is responding to interrupts, +and an idle bit indicating whether the cpu has been more or less than +50% idle each heartbeat period. The current period is one second. + +When a cpu panics, an error code is written by BIOS to this same reg. + +So the reg has been renamed the "System Controller Interface Reg". + +This patchset provides the following: + + * x86_64: Add base functionality for writing to the specific SCIR's + for each cpu. + + * idle: Add an idle callback to measure the idle "on" and "off" times. + + * heartbeat: Invert "heartbeat" bit to indicate the cpu is "active". + + * if hotplug enabled, all bits are set (0xff) when the cpu is disabled. + +Based on linux-2.6.tip/master. + +Signed-off-by: Mike Travis +--- + arch/x86/kernel/genx2apic_uv_x.c | 102 +++++++++++++++++++++++++++++++++++++++ + include/asm-x86/uv/uv_hub.h | 63 ++++++++++++++++++++++++ + 2 files changed, 165 insertions(+) + +--- linux-2.6.27.orig/arch/x86/kernel/genx2apic_uv_x.c ++++ linux-2.6.27/arch/x86/kernel/genx2apic_uv_x.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -19,6 +20,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -365,6 +368,104 @@ static __init void uv_rtc_init(void) + sn_rtc_cycles_per_second = ticks_per_sec; + } + ++/* ++ * percpu heartbeat timer ++ */ ++static void uv_heartbeat(unsigned long ignored) ++{ ++ struct timer_list *timer = &uv_hub_info->scir.timer; ++ unsigned char bits = uv_hub_info->scir.state; ++ ++ /* flip heartbeat bit */ ++ bits ^= SCIR_CPU_HEARTBEAT; ++ ++ /* are we the idle thread? */ ++ if (current->pid == 0) ++ bits &= ~SCIR_CPU_ACTIVITY; ++ else ++ bits |= SCIR_CPU_ACTIVITY; ++ ++ /* update system controller interface reg */ ++ uv_set_scir_bits(bits); ++ ++ /* enable next timer period */ ++ mod_timer(timer, jiffies + SCIR_CPU_HB_INTERVAL); ++} ++ ++static void __cpuinit uv_heartbeat_enable(int cpu) ++{ ++ if (!uv_cpu_hub_info(cpu)->scir.enabled) { ++ struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer; ++ ++ uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY); ++ setup_timer(timer, uv_heartbeat, cpu); ++ timer->expires = jiffies + SCIR_CPU_HB_INTERVAL; ++ add_timer_on(timer, cpu); ++ uv_cpu_hub_info(cpu)->scir.enabled = 1; ++ } ++ ++ /* check boot cpu */ ++ if (!uv_cpu_hub_info(0)->scir.enabled) ++ uv_heartbeat_enable(0); ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ ++static void __cpuinit uv_heartbeat_disable(int cpu) ++{ ++ if (uv_cpu_hub_info(cpu)->scir.enabled) { ++ uv_cpu_hub_info(cpu)->scir.enabled = 0; ++ del_timer(&uv_cpu_hub_info(cpu)->scir.timer); ++ } ++ uv_set_cpu_scir_bits(cpu, 0xff); ++} ++ ++/* ++ * cpu hotplug notifier ++ */ ++static __cpuinit int uv_scir_cpu_notify(struct notifier_block *self, ++ unsigned long action, void *hcpu) ++{ ++ long cpu = (long)hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ uv_heartbeat_enable(cpu); ++ break; ++ case CPU_DOWN_PREPARE: ++ uv_heartbeat_disable(cpu); ++ break; ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++ ++static __init void uv_scir_register_cpu_notifier(void) ++{ ++ hotcpu_notifier(uv_scir_cpu_notify, 0); ++} ++ ++#else /* !CONFIG_HOTPLUG_CPU */ ++ ++static __init void uv_scir_register_cpu_notifier(void) ++{ ++} ++ ++static __init int uv_init_heartbeat(void) ++{ ++ int cpu; ++ ++ if (is_uv_system()) ++ for_each_online_cpu(cpu) ++ uv_heartbeat_enable(cpu); ++ return 0; ++} ++ ++late_initcall(uv_init_heartbeat); ++ ++#endif /* !CONFIG_HOTPLUG_CPU */ ++ + static bool uv_system_inited; + + void __init uv_system_init(void) +@@ -443,6 +544,7 @@ void __init uv_system_init(void) + uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; + uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; + uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */ ++ uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; + uv_node_to_blade[nid] = blade; + uv_cpu_to_blade[cpu] = blade; + max_pnode = max(pnode, max_pnode); +@@ -458,6 +560,7 @@ void __init uv_system_init(void) + map_config_high(max_pnode); + map_mmioh_high(max_pnode); + uv_system_inited = true; ++ uv_scir_register_cpu_notifier(); + } + + /* +--- linux-2.6.27.orig/include/asm-x86/uv/uv_hub.h ++++ linux-2.6.27/include/asm-x86/uv/uv_hub.h +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + #include + +@@ -112,6 +113,16 @@ + */ + #define UV_MAX_NASID_VALUE (UV_MAX_NUMALINK_NODES * 2) + ++struct uv_scir_s { ++ struct timer_list timer; ++ unsigned long offset; ++ unsigned long last; ++ unsigned long idle_on; ++ unsigned long idle_off; ++ unsigned char state; ++ unsigned char enabled; ++}; ++ + /* + * The following defines attributes of the HUB chip. These attributes are + * frequently referenced and are kept in the per-cpu data areas of each cpu. +@@ -130,7 +141,9 @@ struct uv_hub_info_s { + unsigned char blade_processor_id; + unsigned char m_val; + unsigned char n_val; ++ struct uv_scir_s scir; + }; ++ + DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); + #define uv_hub_info (&__get_cpu_var(__uv_hub_info)) + #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) +@@ -162,6 +175,30 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __ + + #define UV_APIC_PNODE_SHIFT 6 + ++/* Local Bus from cpu's perspective */ ++#define LOCAL_BUS_BASE 0x1c00000 ++#define LOCAL_BUS_SIZE (4 * 1024 * 1024) ++ ++/* ++ * System Controller Interface Reg ++ * ++ * Note there are NO leds on a UV system. This register is only ++ * used by the system controller to monitor system-wide operation. ++ * There are 64 regs per node. With Nahelem cpus (2 cores per node, ++ * 8 cpus per core, 2 threads per cpu) there are 32 cpu threads on ++ * a node. ++ * ++ * The window is located at top of ACPI MMR space ++ */ ++#define SCIR_WINDOW_COUNT 64 ++#define SCIR_LOCAL_MMR_BASE (LOCAL_BUS_BASE + \ ++ LOCAL_BUS_SIZE - \ ++ SCIR_WINDOW_COUNT) ++ ++#define SCIR_CPU_HEARTBEAT 0x01 /* timer interrupt */ ++#define SCIR_CPU_ACTIVITY 0x02 /* not idle */ ++#define SCIR_CPU_HB_INTERVAL (HZ) /* once per second */ ++ + /* + * Macros for converting between kernel virtual addresses, socket local physical + * addresses, and UV global physical addresses. +@@ -276,6 +313,16 @@ static inline void uv_write_local_mmr(un + *uv_local_mmr_address(offset) = val; + } + ++static inline unsigned char uv_read_local_mmr8(unsigned long offset) ++{ ++ return *((unsigned char *)uv_local_mmr_address(offset)); ++} ++ ++static inline void uv_write_local_mmr8(unsigned long offset, unsigned char val) ++{ ++ *((unsigned char *)uv_local_mmr_address(offset)) = val; ++} ++ + /* + * Structures and definitions for converting between cpu, node, pnode, and blade + * numbers. +@@ -350,5 +397,21 @@ static inline int uv_num_possible_blades + return uv_possible_blades; + } + ++/* Update SCIR state */ ++static inline void uv_set_scir_bits(unsigned char value) ++{ ++ if (uv_hub_info->scir.state != value) { ++ uv_hub_info->scir.state = value; ++ uv_write_local_mmr8(uv_hub_info->scir.offset, value); ++ } ++} ++static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) ++{ ++ if (uv_cpu_hub_info(cpu)->scir.state != value) { ++ uv_cpu_hub_info(cpu)->scir.state = value; ++ uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value); ++ } ++} ++ + #endif /* __ASM_X86_UV_HUB__ */ + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-01-fix-smp_call_function.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-01-fix-smp_call_function.patch new file mode 100644 index 000000000..e2fe56f04 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-01-fix-smp_call_function.patch @@ -0,0 +1,72 @@ +From: Mike Travis +Date: Fri, 5 Sep 2008 14:40:20 -0700 +Subject: [PATCH] smp: reduce stack requirements for smp_call_function_mask +References: bnc#425240 FATE304266 +Patch-mainline: 2.6.28 + +* Cleanup cpumask_t usages in smp_call_function_mask to remove stack + overflow problem when NR_CPUS=4096. This removes over 1000 bytes + from the stack with NR_CPUS=4096. + +Signed-off-by: Mike Travis +Signed-off-by: Ingo Molnar +Signed-off-by: Jiri Slaby +Signed-off-by: Thomas Renninger +--- + kernel/smp.c | 12 +++++------- + 1 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/kernel/smp.c b/kernel/smp.c +index f362a85..069d066 100644 +--- a/kernel/smp.c ++++ b/kernel/smp.c +@@ -287,7 +287,7 @@ static void quiesce_dummy(void *unused) + * If a faster scheme can be made, we could go back to preferring stack based + * data -- the data allocation/free is non-zero cost. + */ +-static void smp_call_function_mask_quiesce_stack(cpumask_t mask) ++static void smp_call_function_mask_quiesce_stack(const cpumask_t *mask) + { + struct call_single_data data; + int cpu; +@@ -295,7 +295,7 @@ static void smp_call_function_mask_quiesce_stack(cpumask_t mask) + data.func = quiesce_dummy; + data.info = NULL; + +- for_each_cpu_mask(cpu, mask) { ++ for_each_cpu_mask_nr(cpu, *mask) { + data.flags = CSD_FLAG_WAIT; + generic_exec_single(cpu, &data); + } +@@ -323,7 +323,6 @@ int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, + { + struct call_function_data d; + struct call_function_data *data = NULL; +- cpumask_t allbutself; + unsigned long flags; + int cpu, num_cpus; + int slowpath = 0; +@@ -332,9 +331,8 @@ int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, + WARN_ON(irqs_disabled()); + + cpu = smp_processor_id(); +- allbutself = cpu_online_map; +- cpu_clear(cpu, allbutself); +- cpus_and(mask, mask, allbutself); ++ cpus_and(mask, mask, cpu_online_map); ++ cpu_clear(cpu, mask); + num_cpus = cpus_weight(mask); + + /* +@@ -377,7 +375,7 @@ int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, + if (wait) { + csd_flag_wait(&data->csd); + if (unlikely(slowpath)) +- smp_call_function_mask_quiesce_stack(mask); ++ smp_call_function_mask_quiesce_stack(&mask); + } + + return 0; +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-02-fix-send_call_func_ip.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-02-fix-send_call_func_ip.patch new file mode 100644 index 000000000..33d87c2b5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-02-fix-send_call_func_ip.patch @@ -0,0 +1,104 @@ +From: Mike Travis +Date: Fri, 5 Sep 2008 14:40:21 -0700 +Subject: [PATCH] x86: reduce stack requirements for send_call_func_ipi +References: bnc#425240 FATE304266 +Patch-mainline: 2.6.28 + +* By converting the internal x86 smp_ops function send_call_func_ipi + to pass a pointer to the cpumask_t variable, we greatly reduce the + stack space required when NR_CPUS=4096. + + Further reduction will be realized when the send_IPI_mask interface + is changed in 2.6.28. + +Signed-off-by: Mike Travis +Signed-off-by: Ingo Molnar +Signed-off-by: Jiri Slaby +Signed-off-by: Thomas Renninger +--- + arch/x86/kernel/smp.c | 6 +++--- + arch/x86/xen/smp.c | 6 +++--- + include/asm-x86/smp.h | 6 +++--- + 3 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c +index 361b7a4..0708394 100644 +--- a/arch/x86/kernel/smp.c ++++ b/arch/x86/kernel/smp.c +@@ -126,18 +126,18 @@ void native_send_call_func_single_ipi(int cpu) + send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_SINGLE_VECTOR); + } + +-void native_send_call_func_ipi(cpumask_t mask) ++void native_send_call_func_ipi(const cpumask_t *mask) + { + cpumask_t allbutself; + + allbutself = cpu_online_map; + cpu_clear(smp_processor_id(), allbutself); + +- if (cpus_equal(mask, allbutself) && ++ if (cpus_equal(*mask, allbutself) && + cpus_equal(cpu_online_map, cpu_callout_map)) + send_IPI_allbutself(CALL_FUNCTION_VECTOR); + else +- send_IPI_mask(mask, CALL_FUNCTION_VECTOR); ++ send_IPI_mask(*mask, CALL_FUNCTION_VECTOR); + } + + static void stop_this_cpu(void *dummy) +diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c +index d8faf79..716588b 100644 +--- a/arch/x86/xen/smp.c ++++ b/arch/x86/xen/smp.c +@@ -371,14 +371,14 @@ static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector) + xen_send_IPI_one(cpu, vector); + } + +-static void xen_smp_send_call_function_ipi(cpumask_t mask) ++static void xen_smp_send_call_function_ipi(const cpumask_t *mask) + { + int cpu; + +- xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR); ++ xen_send_IPI_mask(*mask, XEN_CALL_FUNCTION_VECTOR); + + /* Make sure other vcpus get a chance to run if they need to. */ +- for_each_cpu_mask_nr(cpu, mask) { ++ for_each_cpu_mask_nr(cpu, *mask) { + if (xen_vcpu_stolen(cpu)) { + HYPERVISOR_sched_op(SCHEDOP_yield, 0); + break; +diff --git a/include/asm-x86/smp.h b/include/asm-x86/smp.h +index 3c877f7..8eee4ef 100644 +--- a/include/asm-x86/smp.h ++++ b/include/asm-x86/smp.h +@@ -53,7 +53,7 @@ struct smp_ops { + void (*smp_send_stop)(void); + void (*smp_send_reschedule)(int cpu); + +- void (*send_call_func_ipi)(cpumask_t mask); ++ void (*send_call_func_ipi)(const cpumask_t *mask); + void (*send_call_func_single_ipi)(int cpu); + }; + +@@ -103,14 +103,14 @@ static inline void arch_send_call_function_single_ipi(int cpu) + + static inline void arch_send_call_function_ipi(cpumask_t mask) + { +- smp_ops.send_call_func_ipi(mask); ++ smp_ops.send_call_func_ipi(&mask); + } + + void native_smp_prepare_boot_cpu(void); + void native_smp_prepare_cpus(unsigned int max_cpus); + void native_smp_cpus_done(unsigned int max_cpus); + int native_cpu_up(unsigned int cpunum); +-void native_send_call_func_ipi(cpumask_t mask); ++void native_send_call_func_ipi(const cpumask_t *mask); + void native_send_call_func_single_ipi(int cpu); + + extern int __cpu_disable(void); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-04-add-for_each_cpu_mask_and.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-04-add-for_each_cpu_mask_and.patch new file mode 100644 index 000000000..7b4ecb028 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-04-add-for_each_cpu_mask_and.patch @@ -0,0 +1,106 @@ +From: Mike Travis +Subject: Add for_each_cpu_mask_and +References: bnc#425240 FATE304266 +Patch-mainline: 2.6.28 + +Signed-off-by: Thomas Renninger + +--- + include/linux/cpumask.h | 33 ++++++++++++++++++++++++--------- + lib/cpumask.c | 9 +++++++++ + 2 files changed, 33 insertions(+), 9 deletions(-) + +--- linux-2.6.27.4-HEAD_20081027185619.orig/include/linux/cpumask.h ++++ linux-2.6.27.4-HEAD_20081027185619/include/linux/cpumask.h +@@ -109,6 +109,7 @@ + * + * for_each_cpu_mask(cpu, mask) for-loop cpu over mask using NR_CPUS + * for_each_cpu_mask_nr(cpu, mask) for-loop cpu over mask using nr_cpu_ids ++ * for_each_cpu_mask_and(cpu, mask, and) for-loop cpu over (mask & and). + * + * int num_online_cpus() Number of online CPUs + * int num_possible_cpus() Number of all possible CPUs +@@ -400,29 +401,41 @@ static inline void __cpus_fold(cpumask_t + + #if NR_CPUS == 1 + +-#define nr_cpu_ids 1 +-#define first_cpu(src) ({ (void)(src); 0; }) +-#define next_cpu(n, src) ({ (void)(src); 1; }) +-#define any_online_cpu(mask) 0 +-#define for_each_cpu_mask(cpu, mask) \ ++#define nr_cpu_ids 1 ++#define first_cpu(src) ({ (void)(src); 0; }) ++#define next_cpu(n, src) ({ (void)(src); 1; }) ++#define cpumask_next_and(n, srcp, andp) ({ (void)(srcp), (void)(andp); 1; }) ++#define any_online_cpu(mask) 0 ++ ++#define for_each_cpu_mask(cpu, mask) \ + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) ++#define for_each_cpu_mask_and(cpu, mask, and) \ ++ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and) + + #else /* NR_CPUS > 1 */ + + extern int nr_cpu_ids; + int __first_cpu(const cpumask_t *srcp); + int __next_cpu(int n, const cpumask_t *srcp); ++int cpumask_next_and(int n, const cpumask_t *srcp, const cpumask_t *andp); + int __any_online_cpu(const cpumask_t *mask); + + #define first_cpu(src) __first_cpu(&(src)) + #define next_cpu(n, src) __next_cpu((n), &(src)) + #define any_online_cpu(mask) __any_online_cpu(&(mask)) ++ + #define for_each_cpu_mask(cpu, mask) \ + for ((cpu) = -1; \ + (cpu) = next_cpu((cpu), (mask)), \ +- (cpu) < NR_CPUS; ) ++ (cpu) < NR_CPUS;) ++#define for_each_cpu_mask_and(cpu, mask, and) \ ++ for ((cpu) = -1; \ ++ (cpu) = cpumask_next_and((cpu), &(mask), &(and)), \ ++ (cpu) < nr_cpu_ids;) + #endif + ++#define cpumask_first_and(mask, and) cpumask_next_and(-1, (mask), (and)) ++ + #if NR_CPUS <= 64 + + #define next_cpu_nr(n, src) next_cpu(n, src) +@@ -432,12 +445,14 @@ int __any_online_cpu(const cpumask_t *ma + #else /* NR_CPUS > 64 */ + + int __next_cpu_nr(int n, const cpumask_t *srcp); +-#define next_cpu_nr(n, src) __next_cpu_nr((n), &(src)) +-#define cpus_weight_nr(cpumask) __cpus_weight(&(cpumask), nr_cpu_ids) ++ ++#define next_cpu_nr(n, src) __next_cpu_nr((n), &(src)) ++#define cpus_weight_nr(cpumask) __cpus_weight(&(cpumask), nr_cpu_ids) ++ + #define for_each_cpu_mask_nr(cpu, mask) \ + for ((cpu) = -1; \ + (cpu) = next_cpu_nr((cpu), (mask)), \ +- (cpu) < nr_cpu_ids; ) ++ (cpu) < nr_cpu_ids;) + + #endif /* NR_CPUS > 64 */ + +--- linux-2.6.27.4-HEAD_20081027185619.orig/lib/cpumask.c ++++ linux-2.6.27.4-HEAD_20081027185619/lib/cpumask.c +@@ -15,6 +15,15 @@ int __next_cpu(int n, const cpumask_t *s + } + EXPORT_SYMBOL(__next_cpu); + ++int cpumask_next_and(int n, const cpumask_t *srcp, const cpumask_t *andp) ++{ ++ while ((n = next_cpu_nr(n, *srcp)) < nr_cpu_ids) ++ if (cpu_isset(n, *andp)) ++ break; ++ return n; ++} ++EXPORT_SYMBOL(cpumask_next_and); ++ + #if NR_CPUS > 64 + int __next_cpu_nr(int n, const cpumask_t *srcp) + { diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-05-update-send_IPI_mask.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-05-update-send_IPI_mask.patch new file mode 100644 index 000000000..107c06f2e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-05-update-send_IPI_mask.patch @@ -0,0 +1,1652 @@ +From: Mike Travis +Subject: x86 cpumask: Updates to support NR_CPUS=4096 +References: bnc#425240 FATE304266 +Patch-mainline: 2.6.28 + +Signed-off-by: Thomas Renninger + + * Add for_each_cpu_mask_and() function to eliminate need for a common use + of a temporary cpumask_t variable. + + * Change genapic interfaces to accept cpumask_t pointers where possible. + Modify external callers to use cpumask_t pointers in function calls. + + * Create new send_IPI_mask_allbutself which is the same as the + send_IPI_mask functions but removes smp_processor_id() from list. + This removes another common need for a temporary cpumask_t variable. + + * Use node_to_cpumask_ptr in place of node_to_cpumask to reduce stack + requirements in sched.c. + + * Modify arch/x86/Kconfig to enable MAXSMP and 4096 cpus. + +Signed-off-by: Mike Travis +Acked-by: Rusty Russell +Signed-off-by: Jiri Slaby [bigsmp cpu_mask_to_apicid fix] +--- + arch/x86/Kconfig | 11 +-- + arch/x86/kernel/apic_32.c | 2 + arch/x86/kernel/apic_64.c | 2 + arch/x86/kernel/crash.c | 5 - + arch/x86/kernel/genapic_flat_64.c | 76 ++++++++++++++++-------- + arch/x86/kernel/genx2apic_cluster.c | 60 +++++++++++++------ + arch/x86/kernel/genx2apic_phys.c | 55 ++++++++++++----- + arch/x86/kernel/genx2apic_uv_x.c | 43 ++++++++------ + arch/x86/kernel/io_apic_32.c | 16 ++--- + arch/x86/kernel/io_apic_64.c | 95 +++++++++++++++---------------- + arch/x86/kernel/ipi.c | 26 ++++++-- + arch/x86/kernel/smp.c | 15 ---- + arch/x86/kernel/tlb_32.c | 2 + arch/x86/kernel/tlb_64.c | 2 + arch/x86/xen/smp.c | 15 ++-- + include/asm-x86/genapic_32.h | 8 +- + include/asm-x86/genapic_64.h | 11 ++- + include/asm-x86/ipi.h | 22 ++++++- + include/asm-x86/mach-bigsmp/mach_apic.h | 8 +- + include/asm-x86/mach-bigsmp/mach_ipi.h | 21 ++++-- + include/asm-x86/mach-default/mach_apic.h | 12 +-- + include/asm-x86/mach-default/mach_ipi.h | 18 ++--- + include/asm-x86/mach-es7000/mach_apic.h | 8 +- + include/asm-x86/mach-es7000/mach_ipi.h | 20 ++++-- + include/asm-x86/mach-generic/mach_ipi.h | 1 + include/asm-x86/mach-numaq/mach_apic.h | 6 - + include/asm-x86/mach-numaq/mach_ipi.h | 22 ++++--- + include/asm-x86/mach-summit/mach_apic.h | 6 - + include/asm-x86/mach-summit/mach_ipi.h | 22 ++++--- + 29 files changed, 363 insertions(+), 247 deletions(-) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -584,15 +584,15 @@ config IOMMU_HELPER + + config MAXSMP + bool "Configure Maximum number of SMP Processors and NUMA Nodes" +- depends on X86_64 && SMP && BROKEN ++ depends on X86_64 && SMP + default n + help + Configure maximum number of CPUS and NUMA Nodes for this architecture. + If unsure, say N. + + config NR_CPUS +- int "Maximum number of CPUs (2-512)" if !MAXSMP +- range 2 512 ++ int "Maximum number of CPUs (2-4096)" ++ range 2 4096 + depends on SMP + default "4096" if MAXSMP + default "32" if X86_NUMAQ || X86_SUMMIT || X86_BIGSMP || X86_ES7000 +@@ -603,7 +603,7 @@ config NR_CPUS + minimum value which makes sense is 2. + + This is purely to save memory - each supported CPU adds +- approximately eight kilobytes to the kernel image. ++ approximately one kilobyte to the kernel image. + + config SCHED_SMT + bool "SMT (Hyperthreading) scheduler support" +@@ -1019,7 +1019,8 @@ config NUMA_EMU + number of nodes. This is only useful for debugging. + + config NODES_SHIFT +- int "Maximum NUMA Nodes (as a power of 2)" if !MAXSMP ++ int "Maximum NUMA Nodes (as a power of 2)" ++ range 9 9 if MAXSMP + range 1 9 if X86_64 + default "9" if MAXSMP + default "6" if X86_64 +--- a/arch/x86/kernel/apic_32.c ++++ b/arch/x86/kernel/apic_32.c +@@ -319,7 +319,7 @@ static void lapic_timer_setup(enum clock + static void lapic_timer_broadcast(cpumask_t mask) + { + #ifdef CONFIG_SMP +- send_IPI_mask(mask, LOCAL_TIMER_VECTOR); ++ send_IPI_mask(&mask, LOCAL_TIMER_VECTOR); + #endif + } + +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -351,7 +351,7 @@ static void lapic_timer_setup(enum clock + static void lapic_timer_broadcast(cpumask_t mask) + { + #ifdef CONFIG_SMP +- send_IPI_mask(mask, LOCAL_TIMER_VECTOR); ++ send_IPI_mask(&mask, LOCAL_TIMER_VECTOR); + #endif + } + +--- a/arch/x86/kernel/crash.c ++++ b/arch/x86/kernel/crash.c +@@ -77,10 +77,7 @@ static int crash_nmi_callback(struct not + + static void smp_send_nmi_allbutself(void) + { +- cpumask_t mask = cpu_online_map; +- cpu_clear(safe_smp_processor_id(), mask); +- if (!cpus_empty(mask)) +- send_IPI_mask(mask, NMI_VECTOR); ++ send_IPI_allbutself(NMI_VECTOR); + } + + static struct notifier_block crash_nmi_nb = { +--- a/arch/x86/kernel/genapic_flat_64.c ++++ b/arch/x86/kernel/genapic_flat_64.c +@@ -30,12 +30,12 @@ static int flat_acpi_madt_oem_check(char + return 1; + } + +-static cpumask_t flat_target_cpus(void) ++static const cpumask_t *flat_target_cpus(void) + { +- return cpu_online_map; ++ return &cpu_online_map; + } + +-static cpumask_t flat_vector_allocation_domain(int cpu) ++static void flat_vector_allocation_domain(int cpu, cpumask_t *retmask) + { + /* Careful. Some cpus do not strictly honor the set of cpus + * specified in the interrupt destination when using lowest +@@ -45,8 +45,7 @@ static cpumask_t flat_vector_allocation_ + * deliver interrupts to the wrong hyperthread when only one + * hyperthread was specified in the interrupt desitination. + */ +- cpumask_t domain = { { [0] = APIC_ALL_CPUS, } }; +- return domain; ++ *retmask = (cpumask_t) { {[0] = APIC_ALL_CPUS, } }; + } + + /* +@@ -69,9 +68,8 @@ static void flat_init_apic_ldr(void) + apic_write(APIC_LDR, val); + } + +-static void flat_send_IPI_mask(cpumask_t cpumask, int vector) ++static inline void _flat_send_IPI_mask(unsigned long mask, int vector) + { +- unsigned long mask = cpus_addr(cpumask)[0]; + unsigned long flags; + + local_irq_save(flags); +@@ -79,20 +77,40 @@ static void flat_send_IPI_mask(cpumask_t + local_irq_restore(flags); + } + ++static void flat_send_IPI_mask(const cpumask_t *cpumask, int vector) ++{ ++ unsigned long mask = cpus_addr(*cpumask)[0]; ++ ++ _flat_send_IPI_mask(mask, vector); ++} ++ ++static void flat_send_IPI_mask_allbutself(const cpumask_t *cpumask, int vector) ++{ ++ unsigned long mask = cpus_addr(*cpumask)[0]; ++ int cpu = smp_processor_id(); ++ ++ if (cpu < BITS_PER_LONG) ++ clear_bit(cpu, &mask); ++ _flat_send_IPI_mask(mask, vector); ++} ++ + static void flat_send_IPI_allbutself(int vector) + { ++ int cpu = smp_processor_id(); + #ifdef CONFIG_HOTPLUG_CPU + int hotplug = 1; + #else + int hotplug = 0; + #endif + if (hotplug || vector == NMI_VECTOR) { +- cpumask_t allbutme = cpu_online_map; ++ if (!cpus_equal(cpu_online_map, cpumask_of_cpu(cpu))) { ++ unsigned long mask = cpus_addr(cpu_online_map)[0]; + +- cpu_clear(smp_processor_id(), allbutme); ++ if (cpu < BITS_PER_LONG) ++ clear_bit(cpu, &mask); + +- if (!cpus_empty(allbutme)) +- flat_send_IPI_mask(allbutme, vector); ++ _flat_send_IPI_mask(mask, vector); ++ } + } else if (num_online_cpus() > 1) { + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL); + } +@@ -101,7 +119,7 @@ static void flat_send_IPI_allbutself(int + static void flat_send_IPI_all(int vector) + { + if (vector == NMI_VECTOR) +- flat_send_IPI_mask(cpu_online_map, vector); ++ flat_send_IPI_mask(&cpu_online_map, vector); + else + __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL); + } +@@ -135,9 +153,9 @@ static int flat_apic_id_registered(void) + return physid_isset(read_xapic_id(), phys_cpu_present_map); + } + +-static unsigned int flat_cpu_mask_to_apicid(cpumask_t cpumask) ++static unsigned int flat_cpu_mask_to_apicid(const cpumask_t *cpumask) + { +- return cpus_addr(cpumask)[0] & APIC_ALL_CPUS; ++ return cpus_addr(*cpumask)[0] & APIC_ALL_CPUS; + } + + static unsigned int phys_pkg_id(int index_msb) +@@ -157,6 +175,7 @@ struct genapic apic_flat = { + .send_IPI_all = flat_send_IPI_all, + .send_IPI_allbutself = flat_send_IPI_allbutself, + .send_IPI_mask = flat_send_IPI_mask, ++ .send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself, + .send_IPI_self = apic_send_IPI_self, + .cpu_mask_to_apicid = flat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +@@ -186,35 +205,39 @@ static int physflat_acpi_madt_oem_check( + return 0; + } + +-static cpumask_t physflat_target_cpus(void) ++static const cpumask_t *physflat_target_cpus(void) + { +- return cpu_online_map; ++ return &cpu_online_map; + } + +-static cpumask_t physflat_vector_allocation_domain(int cpu) ++static void physflat_vector_allocation_domain(int cpu, cpumask_t *retmask) + { +- return cpumask_of_cpu(cpu); ++ cpus_clear(*retmask); ++ cpu_set(cpu, *retmask); + } + +-static void physflat_send_IPI_mask(cpumask_t cpumask, int vector) ++static void physflat_send_IPI_mask(const cpumask_t *cpumask, int vector) + { + send_IPI_mask_sequence(cpumask, vector); + } + +-static void physflat_send_IPI_allbutself(int vector) ++static void physflat_send_IPI_mask_allbutself(const cpumask_t *cpumask, ++ int vector) + { +- cpumask_t allbutme = cpu_online_map; ++ send_IPI_mask_allbutself(cpumask, vector); ++} + +- cpu_clear(smp_processor_id(), allbutme); +- physflat_send_IPI_mask(allbutme, vector); ++static void physflat_send_IPI_allbutself(int vector) ++{ ++ send_IPI_mask_allbutself(&cpu_online_map, vector); + } + + static void physflat_send_IPI_all(int vector) + { +- physflat_send_IPI_mask(cpu_online_map, vector); ++ physflat_send_IPI_mask(&cpu_online_map, vector); + } + +-static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask) ++static unsigned int physflat_cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int cpu; + +@@ -222,7 +245,7 @@ static unsigned int physflat_cpu_mask_to + * We're using fixed IRQ delivery, can only return one phys APIC ID. + * May as well be the first. + */ +- cpu = first_cpu(cpumask); ++ cpu = first_cpu(*cpumask); + if ((unsigned)cpu < nr_cpu_ids) + return per_cpu(x86_cpu_to_apicid, cpu); + else +@@ -241,6 +264,7 @@ struct genapic apic_physflat = { + .send_IPI_all = physflat_send_IPI_all, + .send_IPI_allbutself = physflat_send_IPI_allbutself, + .send_IPI_mask = physflat_send_IPI_mask, ++ .send_IPI_mask_allbutself = physflat_send_IPI_mask_allbutself, + .send_IPI_self = apic_send_IPI_self, + .cpu_mask_to_apicid = physflat_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +--- a/arch/x86/kernel/genx2apic_cluster.c ++++ b/arch/x86/kernel/genx2apic_cluster.c +@@ -19,19 +19,18 @@ static int x2apic_acpi_madt_oem_check(ch + + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ + +-static cpumask_t x2apic_target_cpus(void) ++static const cpumask_t *x2apic_target_cpus(void) + { +- return cpumask_of_cpu(0); ++ return &cpumask_of_cpu(0); + } + + /* + * for now each logical cpu is in its own vector allocation domain. + */ +-static cpumask_t x2apic_vector_allocation_domain(int cpu) ++static void x2apic_vector_allocation_domain(int cpu, cpumask_t *retmask) + { +- cpumask_t domain = CPU_MASK_NONE; +- cpu_set(cpu, domain); +- return domain; ++ cpus_clear(*retmask); ++ cpu_set(cpu, *retmask); + } + + static void __x2apic_send_IPI_dest(unsigned int apicid, int vector, +@@ -53,32 +52,52 @@ static void __x2apic_send_IPI_dest(unsig + * at once. We have 16 cpu's in a cluster. This will minimize IPI register + * writes. + */ +-static void x2apic_send_IPI_mask(cpumask_t mask, int vector) ++static void x2apic_send_IPI_mask(const cpumask_t *mask, int vector) + { + unsigned long flags; + unsigned long query_cpu; + + local_irq_save(flags); +- for_each_cpu_mask(query_cpu, mask) { +- __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_logical_apicid, query_cpu), +- vector, APIC_DEST_LOGICAL); +- } ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) ++ __x2apic_send_IPI_dest( ++ per_cpu(x86_cpu_to_logical_apicid, query_cpu), ++ vector, APIC_DEST_LOGICAL); + local_irq_restore(flags); + } + +-static void x2apic_send_IPI_allbutself(int vector) ++static void x2apic_send_IPI_mask_allbutself(const cpumask_t *mask, int vector) + { +- cpumask_t mask = cpu_online_map; ++ unsigned long flags; ++ unsigned long query_cpu; ++ unsigned long this_cpu = smp_processor_id(); + +- cpu_clear(smp_processor_id(), mask); ++ local_irq_save(flags); ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) ++ if (query_cpu != this_cpu) ++ __x2apic_send_IPI_dest( ++ per_cpu(x86_cpu_to_logical_apicid, query_cpu), ++ vector, APIC_DEST_LOGICAL); ++ local_irq_restore(flags); ++} + +- if (!cpus_empty(mask)) +- x2apic_send_IPI_mask(mask, vector); ++static void x2apic_send_IPI_allbutself(int vector) ++{ ++ unsigned long flags; ++ unsigned long query_cpu; ++ unsigned long this_cpu = smp_processor_id(); ++ ++ local_irq_save(flags); ++ for_each_online_cpu(query_cpu) ++ if (query_cpu != this_cpu) ++ __x2apic_send_IPI_dest( ++ per_cpu(x86_cpu_to_logical_apicid, query_cpu), ++ vector, APIC_DEST_LOGICAL); ++ local_irq_restore(flags); + } + + static void x2apic_send_IPI_all(int vector) + { +- x2apic_send_IPI_mask(cpu_online_map, vector); ++ x2apic_send_IPI_mask(&cpu_online_map, vector); + } + + static int x2apic_apic_id_registered(void) +@@ -86,7 +105,7 @@ static int x2apic_apic_id_registered(voi + return 1; + } + +-static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask) ++static unsigned int x2apic_cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int cpu; + +@@ -94,8 +113,8 @@ static unsigned int x2apic_cpu_mask_to_a + * We're using fixed IRQ delivery, can only return one phys APIC ID. + * May as well be the first. + */ +- cpu = first_cpu(cpumask); +- if ((unsigned)cpu < NR_CPUS) ++ cpu = first_cpu(*cpumask); ++ if ((unsigned)cpu < nr_cpu_ids) + return per_cpu(x86_cpu_to_logical_apicid, cpu); + else + return BAD_APICID; +@@ -147,6 +166,7 @@ struct genapic apic_x2apic_cluster = { + .send_IPI_all = x2apic_send_IPI_all, + .send_IPI_allbutself = x2apic_send_IPI_allbutself, + .send_IPI_mask = x2apic_send_IPI_mask, ++ .send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself, + .send_IPI_self = x2apic_send_IPI_self, + .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +--- a/arch/x86/kernel/genx2apic_phys.c ++++ b/arch/x86/kernel/genx2apic_phys.c +@@ -31,16 +31,15 @@ static int x2apic_acpi_madt_oem_check(ch + + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ + +-static cpumask_t x2apic_target_cpus(void) ++static const cpumask_t *x2apic_target_cpus(void) + { +- return cpumask_of_cpu(0); ++ return &cpumask_of_cpu(0); + } + +-static cpumask_t x2apic_vector_allocation_domain(int cpu) ++static void x2apic_vector_allocation_domain(int cpu, cpumask_t *retmask) + { +- cpumask_t domain = CPU_MASK_NONE; +- cpu_set(cpu, domain); +- return domain; ++ cpus_clear(*retmask); ++ cpu_set(cpu, *retmask); + } + + static void __x2apic_send_IPI_dest(unsigned int apicid, int vector, +@@ -56,32 +55,53 @@ static void __x2apic_send_IPI_dest(unsig + x2apic_icr_write(cfg, apicid); + } + +-static void x2apic_send_IPI_mask(cpumask_t mask, int vector) ++static void x2apic_send_IPI_mask(const cpumask_t *mask, int vector) + { + unsigned long flags; + unsigned long query_cpu; + + local_irq_save(flags); +- for_each_cpu_mask(query_cpu, mask) { ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) { + __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu), + vector, APIC_DEST_PHYSICAL); + } + local_irq_restore(flags); + } + +-static void x2apic_send_IPI_allbutself(int vector) ++static void x2apic_send_IPI_mask_allbutself(const cpumask_t *mask, int vector) + { +- cpumask_t mask = cpu_online_map; ++ unsigned long flags; ++ unsigned long query_cpu; ++ unsigned long this_cpu = smp_processor_id(); ++ ++ local_irq_save(flags); ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) { ++ if (query_cpu != this_cpu) ++ __x2apic_send_IPI_dest( ++ per_cpu(x86_cpu_to_apicid, query_cpu), ++ vector, APIC_DEST_PHYSICAL); ++ } ++ local_irq_restore(flags); ++} + +- cpu_clear(smp_processor_id(), mask); ++static void x2apic_send_IPI_allbutself(int vector) ++{ ++ unsigned long flags; ++ unsigned long query_cpu; ++ unsigned long this_cpu = smp_processor_id(); + +- if (!cpus_empty(mask)) +- x2apic_send_IPI_mask(mask, vector); ++ local_irq_save(flags); ++ for_each_online_cpu(query_cpu) ++ if (query_cpu != this_cpu) ++ __x2apic_send_IPI_dest( ++ per_cpu(x86_cpu_to_apicid, query_cpu), ++ vector, APIC_DEST_PHYSICAL); ++ local_irq_restore(flags); + } + + static void x2apic_send_IPI_all(int vector) + { +- x2apic_send_IPI_mask(cpu_online_map, vector); ++ x2apic_send_IPI_mask(&cpu_online_map, vector); + } + + static int x2apic_apic_id_registered(void) +@@ -89,7 +109,7 @@ static int x2apic_apic_id_registered(voi + return 1; + } + +-static unsigned int x2apic_cpu_mask_to_apicid(cpumask_t cpumask) ++static unsigned int x2apic_cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int cpu; + +@@ -97,8 +117,8 @@ static unsigned int x2apic_cpu_mask_to_a + * We're using fixed IRQ delivery, can only return one phys APIC ID. + * May as well be the first. + */ +- cpu = first_cpu(cpumask); +- if ((unsigned)cpu < NR_CPUS) ++ cpu = first_cpu(*cpumask); ++ if ((unsigned)cpu < nr_cpu_ids) + return per_cpu(x86_cpu_to_apicid, cpu); + else + return BAD_APICID; +@@ -147,6 +167,7 @@ struct genapic apic_x2apic_phys = { + .send_IPI_all = x2apic_send_IPI_all, + .send_IPI_allbutself = x2apic_send_IPI_allbutself, + .send_IPI_mask = x2apic_send_IPI_mask, ++ .send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself, + .send_IPI_self = x2apic_send_IPI_self, + .cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, +--- a/arch/x86/kernel/genx2apic_uv_x.c ++++ b/arch/x86/kernel/genx2apic_uv_x.c +@@ -75,16 +75,15 @@ EXPORT_SYMBOL(sn_rtc_cycles_per_second); + + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ + +-static cpumask_t uv_target_cpus(void) ++static const cpumask_t *uv_target_cpus(void) + { +- return cpumask_of_cpu(0); ++ return &cpumask_of_cpu(0); + } + +-static cpumask_t uv_vector_allocation_domain(int cpu) ++static void uv_vector_allocation_domain(int cpu, cpumask_t *retmask) + { +- cpumask_t domain = CPU_MASK_NONE; +- cpu_set(cpu, domain); +- return domain; ++ cpus_clear(*retmask); ++ cpu_set(cpu, *retmask); + } + + int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip) +@@ -123,28 +122,37 @@ static void uv_send_IPI_one(int cpu, int + uv_write_global_mmr64(pnode, UVH_IPI_INT, val); + } + +-static void uv_send_IPI_mask(cpumask_t mask, int vector) ++static void uv_send_IPI_mask(const cpumask_t *mask, int vector) + { + unsigned int cpu; + +- for_each_possible_cpu(cpu) +- if (cpu_isset(cpu, mask)) ++ for_each_cpu_mask_and(cpu, *mask, cpu_online_map) ++ uv_send_IPI_one(cpu, vector); ++} ++ ++static void uv_send_IPI_mask_allbutself(const cpumask_t *mask, int vector) ++{ ++ unsigned int cpu; ++ unsigned int this_cpu = smp_processor_id(); ++ ++ for_each_cpu_mask_and(cpu, *mask, cpu_online_map) ++ if (cpu != this_cpu) + uv_send_IPI_one(cpu, vector); + } + + static void uv_send_IPI_allbutself(int vector) + { +- cpumask_t mask = cpu_online_map; +- +- cpu_clear(smp_processor_id(), mask); ++ unsigned int cpu; ++ unsigned int this_cpu = smp_processor_id(); + +- if (!cpus_empty(mask)) +- uv_send_IPI_mask(mask, vector); ++ for_each_online_cpu(cpu) ++ if (cpu != this_cpu) ++ uv_send_IPI_one(cpu, vector); + } + + static void uv_send_IPI_all(int vector) + { +- uv_send_IPI_mask(cpu_online_map, vector); ++ uv_send_IPI_mask(&cpu_online_map, vector); + } + + static int uv_apic_id_registered(void) +@@ -156,7 +164,7 @@ static void uv_init_apic_ldr(void) + { + } + +-static unsigned int uv_cpu_mask_to_apicid(cpumask_t cpumask) ++static unsigned int uv_cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int cpu; + +@@ -164,7 +172,7 @@ static unsigned int uv_cpu_mask_to_apici + * We're using fixed IRQ delivery, can only return one phys APIC ID. + * May as well be the first. + */ +- cpu = first_cpu(cpumask); ++ cpu = first_cpu(*cpumask); + if ((unsigned)cpu < nr_cpu_ids) + return per_cpu(x86_cpu_to_apicid, cpu); + else +@@ -219,6 +227,7 @@ struct genapic apic_x2apic_uv_x = { + .init_apic_ldr = uv_init_apic_ldr, + .send_IPI_all = uv_send_IPI_all, + .send_IPI_allbutself = uv_send_IPI_allbutself, ++ .send_IPI_mask_allbutself = uv_send_IPI_mask_allbutself, + .send_IPI_mask = uv_send_IPI_mask, + /* ZZZ.send_IPI_self = uv_send_IPI_self, */ + .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, +--- a/arch/x86/kernel/io_apic_32.c ++++ b/arch/x86/kernel/io_apic_32.c +@@ -344,11 +344,11 @@ static void set_ioapic_affinity_irq(unsi + + cpus_and(tmp, cpumask, cpu_online_map); + if (cpus_empty(tmp)) +- tmp = TARGET_CPUS; ++ tmp = *TARGET_CPUS; + + cpus_and(cpumask, tmp, CPU_MASK_ALL); + +- apicid_value = cpu_mask_to_apicid(cpumask); ++ apicid_value = cpu_mask_to_apicid(&cpumask); + /* Prepare to do the io_apic_write */ + apicid_value = apicid_value << 24; + spin_lock_irqsave(&ioapic_lock, flags); +@@ -926,7 +926,7 @@ void __init setup_ioapic_dest(void) + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); +- set_ioapic_affinity_irq(irq, TARGET_CPUS); ++ set_ioapic_affinity_irq(irq, *TARGET_CPUS); + } + + } +@@ -2522,13 +2522,13 @@ static void set_msi_irq_affinity(unsigne + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) +- tmp = TARGET_CPUS; ++ tmp = *TARGET_CPUS; + + vector = assign_irq_vector(irq); + if (vector < 0) + return; + +- dest = cpu_mask_to_apicid(mask); ++ dest = cpu_mask_to_apicid(&mask); + + read_msi_msg(irq, &msg); + +@@ -2615,11 +2615,11 @@ static void set_ht_irq_affinity(unsigned + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) +- tmp = TARGET_CPUS; ++ tmp = *TARGET_CPUS; + + cpus_and(mask, tmp, CPU_MASK_ALL); + +- dest = cpu_mask_to_apicid(mask); ++ dest = cpu_mask_to_apicid(&mask); + + target_ht_irq(irq, dest); + irq_desc[irq].affinity = mask; +@@ -2649,7 +2649,7 @@ int arch_setup_ht_irq(unsigned int irq, + + cpus_clear(tmp); + cpu_set(vector >> 8, tmp); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); + +--- a/arch/x86/kernel/io_apic_64.c ++++ b/arch/x86/kernel/io_apic_64.c +@@ -83,7 +83,7 @@ static struct irq_cfg irq_cfg[NR_IRQS] _ + [15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, }, + }; + +-static int assign_irq_vector(int irq, cpumask_t mask); ++static int assign_irq_vector(int irq, const cpumask_t *mask); + + int first_system_vector = 0xfe; + +@@ -335,11 +335,11 @@ static void set_ioapic_affinity_irq(unsi + if (cpus_empty(tmp)) + return; + +- if (assign_irq_vector(irq, mask)) ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(tmp, cfg->domain, mask); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + /* + * Only the high 8 bits are valid. +@@ -798,7 +798,7 @@ void unlock_vector_lock(void) + spin_unlock(&vector_lock); + } + +-static int __assign_irq_vector(int irq, cpumask_t mask) ++static int __assign_irq_vector(int irq, const cpumask_t *mask) + { + /* + * NOTE! The local APIC isn't very good at handling +@@ -815,31 +815,28 @@ static int __assign_irq_vector(int irq, + unsigned int old_vector; + int cpu; + struct irq_cfg *cfg; ++ cpumask_t tmp_mask; + + BUG_ON((unsigned)irq >= NR_IRQS); + cfg = &irq_cfg[irq]; + +- /* Only try and allocate irqs on cpus that are present */ +- cpus_and(mask, mask, cpu_online_map); +- + if ((cfg->move_in_progress) || cfg->move_cleanup_count) + return -EBUSY; + + old_vector = cfg->vector; + if (old_vector) { +- cpumask_t tmp; +- cpus_and(tmp, cfg->domain, mask); +- if (!cpus_empty(tmp)) ++ cpus_and(tmp_mask, *mask, cpu_online_map); ++ cpus_and(tmp_mask, cfg->domain, tmp_mask); ++ if (!cpus_empty(tmp_mask)) + return 0; + } + +- for_each_cpu_mask_nr(cpu, mask) { +- cpumask_t domain, new_mask; ++ /* Only try and allocate irqs on cpus that are present */ ++ for_each_cpu_mask_and(cpu, *mask, cpu_online_map) { + int new_cpu; + int vector, offset; + +- domain = vector_allocation_domain(cpu); +- cpus_and(new_mask, domain, cpu_online_map); ++ vector_allocation_domain(cpu, &tmp_mask); + + vector = current_vector; + offset = current_offset; +@@ -854,7 +851,7 @@ next: + continue; + if (vector == IA32_SYSCALL_VECTOR) + goto next; +- for_each_cpu_mask_nr(new_cpu, new_mask) ++ for_each_cpu_mask_and(new_cpu, tmp_mask, cpu_online_map) + if (per_cpu(vector_irq, new_cpu)[vector] != -1) + goto next; + /* Found one! */ +@@ -864,16 +861,16 @@ next: + cfg->move_in_progress = 1; + cfg->old_domain = cfg->domain; + } +- for_each_cpu_mask_nr(new_cpu, new_mask) ++ for_each_cpu_mask_and(new_cpu, tmp_mask, cpu_online_map) + per_cpu(vector_irq, new_cpu)[vector] = irq; + cfg->vector = vector; +- cfg->domain = domain; ++ cfg->domain = tmp_mask; + return 0; + } + return -ENOSPC; + } + +-static int assign_irq_vector(int irq, cpumask_t mask) ++static int assign_irq_vector(int irq, const cpumask_t *mask) + { + int err; + unsigned long flags; +@@ -1031,8 +1028,8 @@ static void setup_IO_APIC_irq(int apic, + if (!IO_APIC_IRQ(irq)) + return; + +- mask = TARGET_CPUS; +- if (assign_irq_vector(irq, mask)) ++ mask = *TARGET_CPUS; ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(mask, cfg->domain, mask); +@@ -1045,7 +1042,7 @@ static void setup_IO_APIC_irq(int apic, + + + if (setup_ioapic_entry(mp_ioapics[apic].mp_apicid, irq, &entry, +- cpu_mask_to_apicid(mask), trigger, polarity, ++ cpu_mask_to_apicid(&mask), trigger, polarity, + cfg->vector)) { + printk("Failed to setup ioapic entry for ioapic %d, pin %d\n", + mp_ioapics[apic].mp_apicid, pin); +@@ -1543,7 +1540,7 @@ static int ioapic_retrigger_irq(unsigned + unsigned long flags; + + spin_lock_irqsave(&vector_lock, flags); +- send_IPI_mask(cpumask_of_cpu(first_cpu(cfg->domain)), cfg->vector); ++ send_IPI_mask(&cpumask_of_cpu(first_cpu(cfg->domain)), cfg->vector); + spin_unlock_irqrestore(&vector_lock, flags); + + return 1; +@@ -1588,7 +1585,7 @@ static void migrate_ioapic_irq(int irq, + { + struct irq_cfg *cfg = irq_cfg + irq; + struct irq_desc *desc = irq_desc + irq; +- cpumask_t tmp, cleanup_mask; ++ cpumask_t tmp; + struct irte irte; + int modify_ioapic_rte = desc->status & IRQ_LEVEL; + unsigned int dest; +@@ -1601,11 +1598,11 @@ static void migrate_ioapic_irq(int irq, + if (get_irte(irq, &irte)) + return; + +- if (assign_irq_vector(irq, mask)) ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(tmp, cfg->domain, mask); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + if (modify_ioapic_rte) { + spin_lock_irqsave(&ioapic_lock, flags); +@@ -1622,9 +1619,9 @@ static void migrate_ioapic_irq(int irq, + modify_irte(irq, &irte); + + if (cfg->move_in_progress) { +- cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); +- cfg->move_cleanup_count = cpus_weight(cleanup_mask); +- send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); ++ cpus_and(tmp, cfg->old_domain, cpu_online_map); ++ cfg->move_cleanup_count = cpus_weight(tmp); ++ send_IPI_mask(&tmp, IRQ_MOVE_CLEANUP_VECTOR); + cfg->move_in_progress = 0; + } + +@@ -1749,7 +1746,7 @@ static void irq_complete_move(unsigned i + + cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); + cfg->move_cleanup_count = cpus_weight(cleanup_mask); +- send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); ++ send_IPI_mask(&cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); + cfg->move_in_progress = 0; + } + } +@@ -2329,13 +2326,13 @@ static int msi_compose_msg(struct pci_de + unsigned dest; + cpumask_t tmp; + +- tmp = TARGET_CPUS; +- err = assign_irq_vector(irq, tmp); ++ tmp = *TARGET_CPUS; ++ err = assign_irq_vector(irq, &tmp); + if (err) + return err; + + cpus_and(tmp, cfg->domain, tmp); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + #ifdef CONFIG_INTR_REMAP + if (irq_remapped(irq)) { +@@ -2400,11 +2397,11 @@ static void set_msi_irq_affinity(unsigne + if (cpus_empty(tmp)) + return; + +- if (assign_irq_vector(irq, mask)) ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(tmp, cfg->domain, mask); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + read_msi_msg(irq, &msg); + +@@ -2426,7 +2423,7 @@ static void ir_set_msi_irq_affinity(unsi + { + struct irq_cfg *cfg = irq_cfg + irq; + unsigned int dest; +- cpumask_t tmp, cleanup_mask; ++ cpumask_t tmp; + struct irte irte; + + cpus_and(tmp, mask, cpu_online_map); +@@ -2436,11 +2433,11 @@ static void ir_set_msi_irq_affinity(unsi + if (get_irte(irq, &irte)) + return; + +- if (assign_irq_vector(irq, mask)) ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(tmp, cfg->domain, mask); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + irte.vector = cfg->vector; + irte.dest_id = IRTE_DEST(dest); +@@ -2456,9 +2453,9 @@ static void ir_set_msi_irq_affinity(unsi + * vector allocation. + */ + if (cfg->move_in_progress) { +- cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); +- cfg->move_cleanup_count = cpus_weight(cleanup_mask); +- send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); ++ cpus_and(tmp, cfg->old_domain, cpu_online_map); ++ cfg->move_cleanup_count = cpus_weight(tmp); ++ send_IPI_mask(&tmp, IRQ_MOVE_CLEANUP_VECTOR); + cfg->move_in_progress = 0; + } + +@@ -2653,11 +2650,11 @@ static void dmar_msi_set_affinity(unsign + if (cpus_empty(tmp)) + return; + +- if (assign_irq_vector(irq, mask)) ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(tmp, cfg->domain, mask); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + dmar_msi_read(irq, &msg); + +@@ -2729,11 +2726,11 @@ static void set_ht_irq_affinity(unsigned + if (cpus_empty(tmp)) + return; + +- if (assign_irq_vector(irq, mask)) ++ if (assign_irq_vector(irq, &mask)) + return; + + cpus_and(tmp, cfg->domain, mask); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + target_ht_irq(irq, dest, cfg->vector); + irq_desc[irq].affinity = mask; +@@ -2757,14 +2754,14 @@ int arch_setup_ht_irq(unsigned int irq, + int err; + cpumask_t tmp; + +- tmp = TARGET_CPUS; +- err = assign_irq_vector(irq, tmp); ++ tmp = *TARGET_CPUS; ++ err = assign_irq_vector(irq, &tmp); + if (!err) { + struct ht_irq_msg msg; + unsigned dest; + + cpus_and(tmp, cfg->domain, tmp); +- dest = cpu_mask_to_apicid(tmp); ++ dest = cpu_mask_to_apicid(&tmp); + + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); + +@@ -2882,10 +2879,10 @@ void __init setup_ioapic_dest(void) + irq_polarity(irq_entry)); + #ifdef CONFIG_INTR_REMAP + else if (intr_remapping_enabled) +- set_ir_ioapic_affinity_irq(irq, TARGET_CPUS); ++ set_ir_ioapic_affinity_irq(irq, *TARGET_CPUS); + #endif + else +- set_ioapic_affinity_irq(irq, TARGET_CPUS); ++ set_ioapic_affinity_irq(irq, *TARGET_CPUS); + } + + } +--- a/arch/x86/kernel/ipi.c ++++ b/arch/x86/kernel/ipi.c +@@ -114,9 +114,9 @@ static inline void __send_IPI_dest_field + /* + * This is only used on smaller machines. + */ +-void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) ++void send_IPI_mask_bitmask(const cpumask_t *cpumask, int vector) + { +- unsigned long mask = cpus_addr(cpumask)[0]; ++ unsigned long mask = cpus_addr(*cpumask)[0]; + unsigned long flags; + + local_irq_save(flags); +@@ -125,7 +125,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu + local_irq_restore(flags); + } + +-void send_IPI_mask_sequence(cpumask_t mask, int vector) ++void send_IPI_mask_sequence(const cpumask_t *mask, int vector) + { + unsigned long flags; + unsigned int query_cpu; +@@ -137,12 +137,24 @@ void send_IPI_mask_sequence(cpumask_t ma + */ + + local_irq_save(flags); +- for_each_possible_cpu(query_cpu) { +- if (cpu_isset(query_cpu, mask)) { ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) ++ __send_IPI_dest_field(cpu_to_logical_apicid(query_cpu), vector); ++ local_irq_restore(flags); ++} ++ ++void send_IPI_mask_allbutself(const cpumask_t *mask, int vector) ++{ ++ unsigned long flags; ++ unsigned int query_cpu; ++ unsigned int this_cpu = smp_processor_id(); ++ ++ /* See Hack comment above */ ++ ++ local_irq_save(flags); ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) ++ if (query_cpu != this_cpu) + __send_IPI_dest_field(cpu_to_logical_apicid(query_cpu), + vector); +- } +- } + local_irq_restore(flags); + } + +--- a/arch/x86/kernel/smp.c ++++ b/arch/x86/kernel/smp.c +@@ -118,26 +118,17 @@ static void native_smp_send_reschedule(i + WARN_ON(1); + return; + } +- send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); ++ send_IPI_mask(&cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); + } + + void native_send_call_func_single_ipi(int cpu) + { +- send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_SINGLE_VECTOR); ++ send_IPI_mask(&cpumask_of_cpu(cpu), CALL_FUNCTION_SINGLE_VECTOR); + } + + void native_send_call_func_ipi(const cpumask_t *mask) + { +- cpumask_t allbutself; +- +- allbutself = cpu_online_map; +- cpu_clear(smp_processor_id(), allbutself); +- +- if (cpus_equal(*mask, allbutself) && +- cpus_equal(cpu_online_map, cpu_callout_map)) +- send_IPI_allbutself(CALL_FUNCTION_VECTOR); +- else +- send_IPI_mask(*mask, CALL_FUNCTION_VECTOR); ++ send_IPI_mask_allbutself(mask, CALL_FUNCTION_VECTOR); + } + + static void stop_this_cpu(void *dummy) +--- a/arch/x86/kernel/tlb_32.c ++++ b/arch/x86/kernel/tlb_32.c +@@ -158,7 +158,7 @@ void native_flush_tlb_others(const cpuma + * We have to send the IPI only to + * CPUs affected. + */ +- send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); ++ send_IPI_mask(&cpumask, INVALIDATE_TLB_VECTOR); + + while (!cpus_empty(flush_cpumask)) + /* nothing. lockup detection does not belong here */ +--- a/arch/x86/kernel/tlb_64.c ++++ b/arch/x86/kernel/tlb_64.c +@@ -186,7 +186,7 @@ void native_flush_tlb_others(const cpuma + * We have to send the IPI only to + * CPUs affected. + */ +- send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender); ++ send_IPI_mask(&cpumask, INVALIDATE_TLB_VECTOR_START + sender); + + while (!cpus_empty(f->flush_cpumask)) + cpu_relax(); +--- a/arch/x86/xen/smp.c ++++ b/arch/x86/xen/smp.c +@@ -157,7 +157,7 @@ static void __init xen_fill_possible_map + { + int i, rc; + +- for (i = 0; i < NR_CPUS; i++) { ++ for (i = 0; i < nr_cpu_ids; i++) { + rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL); + if (rc >= 0) { + num_processors++; +@@ -195,7 +195,7 @@ static void __init xen_smp_prepare_cpus( + + /* Restrict the possible_map according to max_cpus. */ + while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) { +- for (cpu = NR_CPUS - 1; !cpu_possible(cpu); cpu--) ++ for (cpu = nr_cpu_ids - 1; !cpu_possible(cpu); cpu--) + continue; + cpu_clear(cpu, cpu_possible_map); + } +@@ -361,13 +361,11 @@ static void xen_smp_send_reschedule(int + xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR); + } + +-static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector) ++static void xen_send_IPI_mask(const cpumask_t *mask, enum ipi_vector vector) + { + unsigned cpu; + +- cpus_and(mask, mask, cpu_online_map); +- +- for_each_cpu_mask_nr(cpu, mask) ++ for_each_cpu_mask_and(cpu, *mask, cpu_online_map) + xen_send_IPI_one(cpu, vector); + } + +@@ -375,7 +373,7 @@ static void xen_smp_send_call_function_i + { + int cpu; + +- xen_send_IPI_mask(*mask, XEN_CALL_FUNCTION_VECTOR); ++ xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR); + + /* Make sure other vcpus get a chance to run if they need to. */ + for_each_cpu_mask_nr(cpu, *mask) { +@@ -388,7 +386,8 @@ static void xen_smp_send_call_function_i + + static void xen_smp_send_call_function_single_ipi(int cpu) + { +- xen_send_IPI_mask(cpumask_of_cpu(cpu), XEN_CALL_FUNCTION_SINGLE_VECTOR); ++ xen_send_IPI_mask(&cpumask_of_cpu(cpu), ++ XEN_CALL_FUNCTION_SINGLE_VECTOR); + } + + static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id) +--- a/include/asm-x86/genapic_32.h ++++ b/include/asm-x86/genapic_32.h +@@ -23,7 +23,7 @@ struct genapic { + int (*probe)(void); + + int (*apic_id_registered)(void); +- cpumask_t (*target_cpus)(void); ++ const cpumask_t *(*target_cpus)(void); + int int_delivery_mode; + int int_dest_mode; + int ESR_DISABLE; +@@ -56,11 +56,12 @@ struct genapic { + + unsigned (*get_apic_id)(unsigned long x); + unsigned long apic_id_mask; +- unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask); ++ unsigned int (*cpu_mask_to_apicid)(const cpumask_t *cpumask); + + #ifdef CONFIG_SMP + /* ipi */ +- void (*send_IPI_mask)(cpumask_t mask, int vector); ++ void (*send_IPI_mask)(const cpumask_t *mask, int vector); ++ void (*send_IPI_mask_allbutself)(const cpumask_t *mask, int vector); + void (*send_IPI_allbutself)(int vector); + void (*send_IPI_all)(int vector); + #endif +@@ -106,6 +107,7 @@ struct genapic { + APICFUNC(cpu_mask_to_apicid) \ + APICFUNC(acpi_madt_oem_check) \ + IPIFUNC(send_IPI_mask) \ ++ IPIFUNC(send_IPI_mask_allbutself) \ + IPIFUNC(send_IPI_allbutself) \ + IPIFUNC(send_IPI_all) \ + APICFUNC(enable_apic_mode) \ +--- a/include/asm-x86/genapic_64.h ++++ b/include/asm-x86/genapic_64.h +@@ -1,6 +1,8 @@ + #ifndef _ASM_GENAPIC_H + #define _ASM_GENAPIC_H 1 + ++#include ++ + /* + * Copyright 2004 James Cleverdon, IBM. + * Subject to the GNU Public License, v.2 +@@ -18,16 +20,17 @@ struct genapic { + u32 int_delivery_mode; + u32 int_dest_mode; + int (*apic_id_registered)(void); +- cpumask_t (*target_cpus)(void); +- cpumask_t (*vector_allocation_domain)(int cpu); ++ const cpumask_t *(*target_cpus)(void); ++ void (*vector_allocation_domain)(int cpu, cpumask_t *retmask); + void (*init_apic_ldr)(void); + /* ipi */ +- void (*send_IPI_mask)(cpumask_t mask, int vector); ++ void (*send_IPI_mask)(const cpumask_t *mask, int vector); ++ void (*send_IPI_mask_allbutself)(const cpumask_t *mask, int vector); + void (*send_IPI_allbutself)(int vector); + void (*send_IPI_all)(int vector); + void (*send_IPI_self)(int vector); + /* */ +- unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask); ++ unsigned int (*cpu_mask_to_apicid)(const cpumask_t *cpumask); + unsigned int (*phys_pkg_id)(int index_msb); + unsigned int (*get_apic_id)(unsigned long x); + unsigned long (*set_apic_id)(unsigned int id); +--- a/include/asm-x86/ipi.h ++++ b/include/asm-x86/ipi.h +@@ -117,7 +117,7 @@ static inline void __send_IPI_dest_field + native_apic_mem_write(APIC_ICR, cfg); + } + +-static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) ++static inline void send_IPI_mask_sequence(const cpumask_t *mask, int vector) + { + unsigned long flags; + unsigned long query_cpu; +@@ -128,10 +128,26 @@ static inline void send_IPI_mask_sequenc + * - mbligh + */ + local_irq_save(flags); +- for_each_cpu_mask_nr(query_cpu, mask) { ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) + __send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, query_cpu), + vector, APIC_DEST_PHYSICAL); +- } ++ local_irq_restore(flags); ++} ++ ++static inline void send_IPI_mask_allbutself(const cpumask_t *mask, int vector) ++{ ++ unsigned long flags; ++ unsigned int query_cpu; ++ unsigned int this_cpu = smp_processor_id(); ++ ++ /* See Hack comment above */ ++ ++ local_irq_save(flags); ++ for_each_cpu_mask_and(query_cpu, *mask, cpu_online_map) ++ if (query_cpu != this_cpu) ++ __send_IPI_dest_field( ++ per_cpu(x86_cpu_to_apicid, query_cpu), ++ vector, APIC_DEST_PHYSICAL); + local_irq_restore(flags); + } + +--- a/include/asm-x86/mach-bigsmp/mach_apic.h ++++ b/include/asm-x86/mach-bigsmp/mach_apic.h +@@ -10,7 +10,7 @@ static inline int apic_id_registered(voi + } + + /* Round robin the irqs amoung the online cpus */ +-static inline cpumask_t target_cpus(void) ++static inline const cpumask_t *target_cpus(void) + { + static unsigned long cpu = NR_CPUS; + do { +@@ -19,7 +19,7 @@ static inline cpumask_t target_cpus(void + else + cpu = next_cpu(cpu, cpu_online_map); + } while (cpu >= NR_CPUS); +- return cpumask_of_cpu(cpu); ++ return &cpumask_of_cpu(cpu); + } + + #undef APIC_DEST_LOGICAL +@@ -126,12 +126,12 @@ static inline int check_phys_apicid_pres + } + + /* As we are using single CPU as destination, pick only one CPU here */ +-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ++static inline unsigned int cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int cpu; + int apicid; + +- cpu = first_cpu(cpumask); ++ cpu = first_cpu(*cpumask); + apicid = cpu_to_logical_apicid(cpu); + return apicid; + } +--- a/include/asm-x86/mach-bigsmp/mach_ipi.h ++++ b/include/asm-x86/mach-bigsmp/mach_ipi.h +@@ -1,25 +1,30 @@ + #ifndef __ASM_MACH_IPI_H + #define __ASM_MACH_IPI_H + +-void send_IPI_mask_sequence(cpumask_t mask, int vector); ++void send_IPI_mask_sequence(const cpumask_t *mask, int vector); + +-static inline void send_IPI_mask(cpumask_t mask, int vector) ++static inline void send_IPI_mask(const cpumask_t *mask, int vector) + { + send_IPI_mask_sequence(mask, vector); + } + +-static inline void send_IPI_allbutself(int vector) ++static inline void send_IPI_mask_allbutself(const cpumask_t *mask, int vector) + { +- cpumask_t mask = cpu_online_map; +- cpu_clear(smp_processor_id(), mask); ++ cpumask_t allbutself = *mask; ++ cpu_clear(smp_processor_id(), allbutself); ++ ++ if (!cpus_empty(allbutself)) ++ send_IPI_mask_sequence(&allbutself, vector); ++} + +- if (!cpus_empty(mask)) +- send_IPI_mask(mask, vector); ++static inline void send_IPI_allbutself(int vector) ++{ ++ send_IPI_mask_allbutself(&cpu_online_map, vector); + } + + static inline void send_IPI_all(int vector) + { +- send_IPI_mask(cpu_online_map, vector); ++ send_IPI_mask(&cpu_online_map, vector); + } + + #endif /* __ASM_MACH_IPI_H */ +--- a/include/asm-x86/mach-default/mach_apic.h ++++ b/include/asm-x86/mach-default/mach_apic.h +@@ -8,12 +8,12 @@ + + #define APIC_DFR_VALUE (APIC_DFR_FLAT) + +-static inline cpumask_t target_cpus(void) ++static inline const cpumask_t *target_cpus(void) + { + #ifdef CONFIG_SMP +- return cpu_online_map; ++ return &cpu_online_map; + #else +- return cpumask_of_cpu(0); ++ return &cpumask_of_cpu(0); + #endif + } + +@@ -59,9 +59,9 @@ static inline int apic_id_registered(voi + return physid_isset(read_apic_id(), phys_cpu_present_map); + } + +-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ++static inline unsigned int cpu_mask_to_apicid(const cpumask_t *cpumask) + { +- return cpus_addr(cpumask)[0]; ++ return cpus_addr(*cpumask)[0]; + } + + static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +@@ -115,7 +115,7 @@ static inline int cpu_to_logical_apicid( + + static inline int cpu_present_to_apicid(int mps_cpu) + { +- if (mps_cpu < NR_CPUS && cpu_present(mps_cpu)) ++ if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu)) + return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu); + else + return BAD_APICID; +--- a/include/asm-x86/mach-default/mach_ipi.h ++++ b/include/asm-x86/mach-default/mach_ipi.h +@@ -4,7 +4,8 @@ + /* Avoid include hell */ + #define NMI_VECTOR 0x02 + +-void send_IPI_mask_bitmask(cpumask_t mask, int vector); ++void send_IPI_mask_bitmask(const cpumask_t *mask, int vector); ++void send_IPI_mask_allbutself(const cpumask_t *mask, int vector); + void __send_IPI_shortcut(unsigned int shortcut, int vector); + + extern int no_broadcast; +@@ -12,28 +13,27 @@ extern int no_broadcast; + #ifdef CONFIG_X86_64 + #include + #define send_IPI_mask (genapic->send_IPI_mask) ++#define send_IPI_mask_allbutself (genapic->send_IPI_mask_allbutself) + #else +-static inline void send_IPI_mask(cpumask_t mask, int vector) ++static inline void send_IPI_mask(const cpumask_t *mask, int vector) + { + send_IPI_mask_bitmask(mask, vector); + } ++void send_IPI_mask_allbutself(const cpumask_t *mask, int vector); + #endif + + static inline void __local_send_IPI_allbutself(int vector) + { +- if (no_broadcast || vector == NMI_VECTOR) { +- cpumask_t mask = cpu_online_map; +- +- cpu_clear(smp_processor_id(), mask); +- send_IPI_mask(mask, vector); +- } else ++ if (no_broadcast || vector == NMI_VECTOR) ++ send_IPI_mask_allbutself(&cpu_online_map, vector); ++ else + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); + } + + static inline void __local_send_IPI_all(int vector) + { + if (no_broadcast || vector == NMI_VECTOR) +- send_IPI_mask(cpu_online_map, vector); ++ send_IPI_mask(&cpu_online_map, vector); + else + __send_IPI_shortcut(APIC_DEST_ALLINC, vector); + } +--- a/include/asm-x86/mach-es7000/mach_apic.h ++++ b/include/asm-x86/mach-es7000/mach_apic.h +@@ -9,12 +9,12 @@ static inline int apic_id_registered(voi + return (1); + } + +-static inline cpumask_t target_cpus(void) ++static inline cpumask_t *target_cpus(void) + { + #if defined CONFIG_ES7000_CLUSTERED_APIC +- return CPU_MASK_ALL; ++ return &CPU_MASK_ALL; + #else +- return cpumask_of_cpu(smp_processor_id()); ++ return &cpumask_of_cpu(smp_processor_id()); + #endif + } + #define TARGET_CPUS (target_cpus()) +@@ -145,7 +145,7 @@ static inline int check_phys_apicid_pres + return (1); + } + +-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ++static inline unsigned int cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int num_bits_set; + int cpus_found = 0; +--- a/include/asm-x86/mach-es7000/mach_ipi.h ++++ b/include/asm-x86/mach-es7000/mach_ipi.h +@@ -1,24 +1,30 @@ + #ifndef __ASM_MACH_IPI_H + #define __ASM_MACH_IPI_H + +-void send_IPI_mask_sequence(cpumask_t mask, int vector); ++void send_IPI_mask_sequence(const cpumask_t *mask, int vector); + +-static inline void send_IPI_mask(cpumask_t mask, int vector) ++static inline void send_IPI_mask(const cpumask_t *mask, int vector) + { + send_IPI_mask_sequence(mask, vector); + } + ++static inline void send_IPI_mask_allbutself(const cpumask_t *mask, int vector) ++{ ++ cpumask_t allbutself = *mask; ++ cpu_clear(smp_processor_id(), allbutself); ++ ++ if (!cpus_empty(allbutself)) ++ send_IPI_mask_sequence(&allbutself, vector); ++} ++ + static inline void send_IPI_allbutself(int vector) + { +- cpumask_t mask = cpu_online_map; +- cpu_clear(smp_processor_id(), mask); +- if (!cpus_empty(mask)) +- send_IPI_mask(mask, vector); ++ send_IPI_mask_allbutself(&cpu_online_map, vector); + } + + static inline void send_IPI_all(int vector) + { +- send_IPI_mask(cpu_online_map, vector); ++ send_IPI_mask(&cpu_online_map, vector); + } + + #endif /* __ASM_MACH_IPI_H */ +--- a/include/asm-x86/mach-generic/mach_ipi.h ++++ b/include/asm-x86/mach-generic/mach_ipi.h +@@ -4,6 +4,7 @@ + #include + + #define send_IPI_mask (genapic->send_IPI_mask) ++#define send_IPI_mask_allbutself (genapic->send_IPI_mask_allbutself) + #define send_IPI_allbutself (genapic->send_IPI_allbutself) + #define send_IPI_all (genapic->send_IPI_all) + +--- a/include/asm-x86/mach-numaq/mach_apic.h ++++ b/include/asm-x86/mach-numaq/mach_apic.h +@@ -7,9 +7,9 @@ + + #define APIC_DFR_VALUE (APIC_DFR_CLUSTER) + +-static inline cpumask_t target_cpus(void) ++static inline const cpumask_t *target_cpus(void) + { +- return CPU_MASK_ALL; ++ return &CPU_MASK_ALL; + } + + #define TARGET_CPUS (target_cpus()) +@@ -124,7 +124,7 @@ static inline void enable_apic_mode(void + * We use physical apicids here, not logical, so just return the default + * physical broadcast to stop people from breaking us + */ +-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ++static inline unsigned int cpu_mask_to_apicid(const cpumask_t *cpumask) + { + return (int) 0xF; + } +--- a/include/asm-x86/mach-numaq/mach_ipi.h ++++ b/include/asm-x86/mach-numaq/mach_ipi.h +@@ -1,25 +1,31 @@ + #ifndef __ASM_MACH_IPI_H + #define __ASM_MACH_IPI_H + +-void send_IPI_mask_sequence(cpumask_t, int vector); ++void send_IPI_mask_sequence(const cpumask_t *mask, int vector); + +-static inline void send_IPI_mask(cpumask_t mask, int vector) ++static inline void send_IPI_mask(const cpumask_t *mask, int vector) + { + send_IPI_mask_sequence(mask, vector); + } + +-static inline void send_IPI_allbutself(int vector) ++static inline void send_IPI_mask_allbutself(const cpumask_t *mask, int vector) + { +- cpumask_t mask = cpu_online_map; +- cpu_clear(smp_processor_id(), mask); ++ cpumask_t allbutself = *mask; ++ cpu_clear(smp_processor_id(), allbutself); ++ ++ if (!cpus_empty(allbutself)) ++ send_IPI_mask_sequence(&allbutself, vector); ++} + +- if (!cpus_empty(mask)) +- send_IPI_mask(mask, vector); ++static inline void send_IPI_allbutself(int vector) ++{ ++ send_IPI_mask_allbutself(&cpu_online_map, vector); + } + + static inline void send_IPI_all(int vector) + { +- send_IPI_mask(cpu_online_map, vector); ++ send_IPI_mask(&cpu_online_map, vector); + } + + #endif /* __ASM_MACH_IPI_H */ ++ +--- a/include/asm-x86/mach-summit/mach_apic.h ++++ b/include/asm-x86/mach-summit/mach_apic.h +@@ -14,13 +14,13 @@ + + #define APIC_DFR_VALUE (APIC_DFR_CLUSTER) + +-static inline cpumask_t target_cpus(void) ++static inline const cpumask_t *target_cpus(void) + { + /* CPU_MASK_ALL (0xff) has undefined behaviour with + * dest_LowestPrio mode logical clustered apic interrupt routing + * Just start on cpu 0. IRQ balancing will spread load + */ +- return cpumask_of_cpu(0); ++ return &cpumask_of_cpu(0); + } + #define TARGET_CPUS (target_cpus()) + +@@ -138,7 +138,7 @@ static inline void enable_apic_mode(void + { + } + +-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ++static inline unsigned int cpu_mask_to_apicid(const cpumask_t *cpumask) + { + int num_bits_set; + int cpus_found = 0; +--- a/include/asm-x86/mach-summit/mach_ipi.h ++++ b/include/asm-x86/mach-summit/mach_ipi.h +@@ -1,25 +1,31 @@ + #ifndef __ASM_MACH_IPI_H + #define __ASM_MACH_IPI_H + +-void send_IPI_mask_sequence(cpumask_t mask, int vector); ++void send_IPI_mask_sequence(const cpumask_t *mask, int vector); + +-static inline void send_IPI_mask(cpumask_t mask, int vector) ++static inline void send_IPI_mask(const cpumask_t *mask, int vector) + { + send_IPI_mask_sequence(mask, vector); + } + +-static inline void send_IPI_allbutself(int vector) ++static inline void send_IPI_mask_allbutself(const cpumask_t *mask, int vector) + { +- cpumask_t mask = cpu_online_map; +- cpu_clear(smp_processor_id(), mask); ++ cpumask_t allbutself = *mask; ++ cpu_clear(smp_processor_id(), allbutself); ++ ++ if (!cpus_empty(allbutself)) ++ send_IPI_mask_sequence(&allbutself, vector); ++} + +- if (!cpus_empty(mask)) +- send_IPI_mask(mask, vector); ++static inline void send_IPI_allbutself(int vector) ++{ ++ send_IPI_mask_allbutself(&cpu_online_map, vector); + } + + static inline void send_IPI_all(int vector) + { +- send_IPI_mask(cpu_online_map, vector); ++ send_IPI_mask(&cpu_online_map, vector); + } + + #endif /* __ASM_MACH_IPI_H */ ++ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-06-optimize-cpumask-in-sched_c.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-06-optimize-cpumask-in-sched_c.patch new file mode 100644 index 000000000..c24f43e0a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-06-optimize-cpumask-in-sched_c.patch @@ -0,0 +1,49 @@ +From: Mike Travis +Subject: Additional cpumask fixups +References: bnc#425240 FATE304266 +Patch-mainline: 2.6.28 + +Signed-off-by: Thomas Renninger + +--- + kernel/sched.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -6075,8 +6075,9 @@ static void move_task_off_dead_cpu(int d + + do { + /* On same node? */ +- mask = node_to_cpumask(cpu_to_node(dead_cpu)); +- cpus_and(mask, mask, p->cpus_allowed); ++ node_to_cpumask_ptr(pnodemask, cpu_to_node(dead_cpu)); ++ ++ cpus_and(mask, *pnodemask, p->cpus_allowed); + dest_cpu = any_online_cpu(mask); + + /* On any allowed CPU? */ +@@ -7086,9 +7087,9 @@ static int cpu_to_allnodes_group(int cpu + struct sched_group **sg, cpumask_t *nodemask) + { + int group; ++ node_to_cpumask_ptr(pnodemask, cpu_to_node(cpu)); + +- *nodemask = node_to_cpumask(cpu_to_node(cpu)); +- cpus_and(*nodemask, *nodemask, *cpu_map); ++ cpus_and(*nodemask, *pnodemask, *cpu_map); + group = first_cpu(*nodemask); + + if (sg) +@@ -7138,9 +7139,9 @@ static void free_sched_groups(const cpum + + for (i = 0; i < nr_node_ids; i++) { + struct sched_group *oldsg, *sg = sched_group_nodes[i]; ++ node_to_cpumask_ptr(pnodemask, i); + +- *nodemask = node_to_cpumask(i); +- cpus_and(*nodemask, *nodemask, *cpu_map); ++ cpus_and(*nodemask, *pnodemask, *cpu_map); + if (cpus_empty(*nodemask)) + continue; + diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-07_pae_compile_fixups.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-07_pae_compile_fixups.patch new file mode 100644 index 000000000..b5d9d0ac5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_cpus4096-07_pae_compile_fixups.patch @@ -0,0 +1,82 @@ +From: Thomas Renninger +Subject: more cpumask cleanups for previous (x86_sgi_cpu4096..) patches +References: Additional cpumask fixups +Patch-mainline: 2.6.28 + +Signed-off-by: Thomas Renninger + +--- + include/asm/mach-es7000/mach_apic.h | 10 +++++----- + include/asm/mach-summit/mach_apic.h | 6 +++--- + 2 files changed, 8 insertions(+), 8 deletions(-) + +Index: linux-2.6.27/include/asm/mach-summit/mach_apic.h +=================================================================== +--- linux-2.6.27.orig/include/asm-x86/mach-summit/mach_apic.h ++++ linux-2.6.27/include/asm-x86/mach-summit/mach_apic.h +@@ -145,7 +145,7 @@ static inline unsigned int cpu_mask_to_a + int cpu; + int apicid; + +- num_bits_set = cpus_weight(cpumask); ++ num_bits_set = cpus_weight(*cpumask); + /* Return id to all */ + if (num_bits_set == NR_CPUS) + return (int) 0xFF; +@@ -153,10 +153,10 @@ static inline unsigned int cpu_mask_to_a + * The cpus in the mask must all be on the apic cluster. If are not + * on the same apicid cluster return default value of TARGET_CPUS. + */ +- cpu = first_cpu(cpumask); ++ cpu = first_cpu(*cpumask); + apicid = cpu_to_logical_apicid(cpu); + while (cpus_found < num_bits_set) { +- if (cpu_isset(cpu, cpumask)) { ++ if (cpu_isset(cpu, *cpumask)) { + int new_apicid = cpu_to_logical_apicid(cpu); + if (apicid_cluster(apicid) != + apicid_cluster(new_apicid)){ +Index: linux-2.6.27/include/asm/mach-es7000/mach_apic.h +=================================================================== +--- linux-2.6.27.orig/include/asm-x86/mach-es7000/mach_apic.h ++++ linux-2.6.27/include/asm-x86/mach-es7000/mach_apic.h +@@ -9,7 +9,7 @@ static inline int apic_id_registered(voi + return (1); + } + +-static inline cpumask_t *target_cpus(void) ++static inline const cpumask_t *target_cpus(void) + { + #if defined CONFIG_ES7000_CLUSTERED_APIC + return &CPU_MASK_ALL; +@@ -81,7 +81,7 @@ static inline void setup_apic_routing(vo + int apic = per_cpu(x86_bios_cpu_apicid, smp_processor_id()); + printk("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n", + (apic_version[apic] == 0x14) ? +- "Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(TARGET_CPUS)[0]); ++ "Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(*TARGET_CPUS)[0]); + } + + static inline int multi_timer_check(int apic, int irq) +@@ -152,7 +152,7 @@ static inline unsigned int cpu_mask_to_a + int cpu; + int apicid; + +- num_bits_set = cpus_weight(cpumask); ++ num_bits_set = cpus_weight(*cpumask); + /* Return id to all */ + if (num_bits_set == NR_CPUS) + #if defined CONFIG_ES7000_CLUSTERED_APIC +@@ -164,10 +164,10 @@ static inline unsigned int cpu_mask_to_a + * The cpus in the mask must all be on the apic cluster. If are not + * on the same apicid cluster return default value of TARGET_CPUS. + */ +- cpu = first_cpu(cpumask); ++ cpu = first_cpu(*cpumask); + apicid = cpu_to_logical_apicid(cpu); + while (cpus_found < num_bits_set) { +- if (cpu_isset(cpu, cpumask)) { ++ if (cpu_isset(cpu, *cpumask)) { + int new_apicid = cpu_to_logical_apicid(cpu); + if (apicid_cluster(apicid) != + apicid_cluster(new_apicid)){ diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_uv_early_detect_oem.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_uv_early_detect_oem.patch new file mode 100644 index 000000000..c70a05c12 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_sgi_uv_early_detect_oem.patch @@ -0,0 +1,33 @@ +From: Jack Steiner +Subject: x86, uv: add early detection of UV system types +References: bnc#429984 +Patch-Mainline: yes + +I missed one line of the UV infrastructure patch. + +The code is already upstream as part of a larger UV patch +but was somehow lost from the final UV infrastructure patch that was +sent to SuSE. + +This change is necessary to detect that the system is a UV system prior +to parsing the SRAT processor information. + +Mainline Commit: 2e42060c19cb79adacc48beb5e9ec5361df976a2 + +Signed-off-by: Thomas Renninger + +--- + arch/x86/kernel/setup.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/x86/kernel/setup.c ++++ b/arch/x86/kernel/setup.c +@@ -818,6 +818,8 @@ void __init setup_arch(char **cmdline_p) + */ + acpi_boot_table_init(); + ++ early_acpi_boot_init(); ++ + #ifdef CONFIG_ACPI_NUMA + /* + * Parse SRAT to discover nodes. diff --git a/src/patches/suse-2.6.27.31/patches.arch/x86_uv_early_detect.patch b/src/patches/suse-2.6.27.31/patches.arch/x86_uv_early_detect.patch new file mode 100644 index 000000000..9eb70dd9b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.arch/x86_uv_early_detect.patch @@ -0,0 +1,197 @@ +From: Jack Steiner +Subject: Delete hacks that were necessary while waiting for x2apic code. +References: bnc#429984 +Patch-Mainline: should be in 2.6.28 + +Bug fixes related to mapping UV memory MMRs. + +Fix large APIC ids in SRAT. + +Use the correct memory allocator. Originally, uv_system_init was +called early & used the boot memory allocation. Community restructuring +move the call later - use kmalloc. + +These fixes were posted as: + http://marc.info/?l=linux-kernel&m=122217746109578&w=2 + http://marc.info/?l=linux-kernel&m=122234718018066&w=2 + http://marc.info/?l=linux-kernel&m=122480249023345&w=2 + http://lkml.org/lkml/2008/7/18/384 + +The fixes were commited to linux-2.6 with: + d2f904bb9a1ba88a58a03612abd8c6c54bdaf73a genx2apic_uv_x.c + 8da077d6f31da291ee3a7dd559671cb8ca48cbe2 genx2apic_uv_x.c + 2e42060c19cb79adacc48beb5e9ec5361df976a2 srat_64.c + +The last fix (http://lkml.org/lkml/2008/7/18/384) has not yet been accepted into +linux-2.6. I'll post the commit id when it is available. + +Signed-off-by: Thomas Renninger + +--- + arch/x86/kernel/genx2apic_uv_x.c | 57 +++++++++++++++++++-------------------- + arch/x86/mm/srat_64.c | 2 - + 2 files changed, 29 insertions(+), 30 deletions(-) + +--- a/arch/x86/kernel/genx2apic_uv_x.c ++++ b/arch/x86/kernel/genx2apic_uv_x.c +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -212,12 +211,10 @@ static unsigned int phys_pkg_id(int inde + return uv_read_apic_id() >> index_msb; + } + +-#ifdef ZZZ /* Needs x2apic patch */ + static void uv_send_IPI_self(int vector) + { + apic_write(APIC_SELF_IPI, vector); + } +-#endif + + struct genapic apic_x2apic_uv_x = { + .name = "UV large system", +@@ -232,7 +229,7 @@ struct genapic apic_x2apic_uv_x = { + .send_IPI_allbutself = uv_send_IPI_allbutself, + .send_IPI_mask_allbutself = uv_send_IPI_mask_allbutself, + .send_IPI_mask = uv_send_IPI_mask, +- /* ZZZ.send_IPI_self = uv_send_IPI_self, */ ++ .send_IPI_self = uv_send_IPI_self, + .cpu_mask_to_apicid = uv_cpu_mask_to_apicid, + .phys_pkg_id = phys_pkg_id, /* Fixme ZZZ */ + .get_apic_id = get_apic_id, +@@ -297,12 +294,13 @@ static __init void map_low_mmrs(void) + + enum map_type {map_wb, map_uc}; + +-static __init void map_high(char *id, unsigned long base, int shift, enum map_type map_type) ++static __init void map_high(char *id, unsigned long base, int shift, ++ int max_pnode, enum map_type map_type) + { + unsigned long bytes, paddr; + + paddr = base << shift; +- bytes = (1UL << shift); ++ bytes = (1UL << shift) * (max_pnode + 1); + printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, + paddr + bytes); + if (map_type == map_uc) +@@ -318,7 +316,7 @@ static __init void map_gru_high(int max_ + + gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR); + if (gru.s.enable) +- map_high("GRU", gru.s.base, shift, map_wb); ++ map_high("GRU", gru.s.base, shift, max_pnode, map_wb); + } + + static __init void map_config_high(int max_pnode) +@@ -328,7 +326,7 @@ static __init void map_config_high(int m + + cfg.v = uv_read_local_mmr(UVH_RH_GAM_CFG_OVERLAY_CONFIG_MMR); + if (cfg.s.enable) +- map_high("CONFIG", cfg.s.base, shift, map_uc); ++ map_high("CONFIG", cfg.s.base, shift, max_pnode, map_uc); + } + + static __init void map_mmr_high(int max_pnode) +@@ -338,7 +336,7 @@ static __init void map_mmr_high(int max_ + + mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); + if (mmr.s.enable) +- map_high("MMR", mmr.s.base, shift, map_uc); ++ map_high("MMR", mmr.s.base, shift, max_pnode, map_uc); + } + + static __init void map_mmioh_high(int max_pnode) +@@ -348,7 +346,7 @@ static __init void map_mmioh_high(int ma + + mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); + if (mmioh.s.enable) +- map_high("MMIOH", mmioh.s.base, shift, map_uc); ++ map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc); + } + + static __init void uv_rtc_init(void) +@@ -466,7 +464,22 @@ late_initcall(uv_init_heartbeat); + + #endif /* !CONFIG_HOTPLUG_CPU */ + +-static bool uv_system_inited; ++/* ++ * Called on each cpu to initialize the per_cpu UV data area. ++ * ZZZ hotplug not supported yet ++ */ ++void __cpuinit uv_cpu_init(void) ++{ ++ /* CPU 0 initilization will be done via uv_system_init. */ ++ if (!uv_blade_info) ++ return; ++ ++ uv_blade_info[uv_numa_blade_id()].nr_online_cpus++; ++ ++ if (get_uv_system_type() == UV_NON_UNIQUE_APIC) ++ set_x2apic_extra_bits(uv_hub_info->pnode); ++} ++ + + void __init uv_system_init(void) + { +@@ -493,16 +506,16 @@ void __init uv_system_init(void) + printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); + + bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); +- uv_blade_info = alloc_bootmem_pages(bytes); ++ uv_blade_info = kmalloc(bytes, GFP_KERNEL); + + get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size); + + bytes = sizeof(uv_node_to_blade[0]) * num_possible_nodes(); +- uv_node_to_blade = alloc_bootmem_pages(bytes); ++ uv_node_to_blade = kmalloc(bytes, GFP_KERNEL); + memset(uv_node_to_blade, 255, bytes); + + bytes = sizeof(uv_cpu_to_blade[0]) * num_possible_cpus(); +- uv_cpu_to_blade = alloc_bootmem_pages(bytes); ++ uv_cpu_to_blade = kmalloc(bytes, GFP_KERNEL); + memset(uv_cpu_to_blade, 255, bytes); + + blade = 0; +@@ -561,22 +574,8 @@ void __init uv_system_init(void) + map_mmr_high(max_pnode); + map_config_high(max_pnode); + map_mmioh_high(max_pnode); +- uv_system_inited = true; + uv_scir_register_cpu_notifier(); +-} + +-/* +- * Called on each cpu to initialize the per_cpu UV data area. +- * ZZZ hotplug not supported yet +- */ +-void __cpuinit uv_cpu_init(void) +-{ +- BUG_ON(!uv_system_inited); +- +- uv_blade_info[uv_numa_blade_id()].nr_online_cpus++; +- +- if (get_uv_system_type() == UV_NON_UNIQUE_APIC) +- set_x2apic_extra_bits(uv_hub_info->pnode); ++ uv_cpu_init(); + } + +- +--- a/arch/x86/mm/srat_64.c ++++ b/arch/x86/mm/srat_64.c +@@ -142,7 +142,7 @@ acpi_numa_processor_affinity_init(struct + return; + } + +- if (is_uv_system()) ++ if (get_uv_system_type() >= UV_X2APIC) + apic_id = (pa->apic_id << 8) | pa->local_sapic_eid; + else + apic_id = pa->apic_id; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0001-IB-ehca-Fix-problem-with-max-number-of-QPs-and-CQs.patch b/src/patches/suse-2.6.27.31/patches.drivers/0001-IB-ehca-Fix-problem-with-max-number-of-QPs-and-CQs.patch new file mode 100644 index 000000000..3661ee87f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0001-IB-ehca-Fix-problem-with-max-number-of-QPs-and-CQs.patch @@ -0,0 +1,127 @@ +From: Stefan Roscher +Subject: Fix problem with max number of QPs and CQs +References: bnc#441619 + +Because ehca adapters can differ in the maximum number of QPs and CQs +we have to save the maximum number of these ressources per adapter and not +globally per ehca driver. This fix introduces 2 new members to the shca +structure to store the maximum value for QPs and CQs per adapter. +The module parameters are now used as initial values for those variables. +If a user selects an invalid number of CQs or QPs we don't print an error any +longer, instead we will inform the user with a warning and set the values to +the respective maximum supported by the HW. + +Acked-by: John Jolly + +Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_classes.h +=================================================================== +--- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_classes.h ++++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_classes.h +@@ -128,6 +128,8 @@ struct ehca_shca { + /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */ + u32 hca_cap_mr_pgsize; + int max_mtu; ++ int max_num_qps; ++ int max_num_cqs; + atomic_t num_cqs; + atomic_t num_qps; + }; +Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_cq.c +=================================================================== +--- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_cq.c ++++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_cq.c +@@ -132,9 +132,9 @@ struct ib_cq *ehca_create_cq(struct ib_d + if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) + return ERR_PTR(-EINVAL); + +- if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) { ++ if (!atomic_add_unless(&shca->num_cqs, 1, shca->max_num_cqs)) { + ehca_err(device, "Unable to create CQ, max number of %i " +- "CQs reached.", ehca_max_cq); ++ "CQs reached.", shca->max_num_cqs); + ehca_err(device, "To increase the maximum number of CQs " + "use the number_of_cqs module parameter.\n"); + return ERR_PTR(-ENOSPC); +Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_main.c +=================================================================== +--- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_main.c ++++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_main.c +@@ -368,22 +368,23 @@ static int ehca_sense_attributes(struct + shca->hca_cap_mr_pgsize |= pgsize_map[i + 1]; + + /* Set maximum number of CQs and QPs to calculate EQ size */ +- if (ehca_max_qp == -1) +- ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES); +- else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) { +- ehca_gen_err("Requested number of QPs is out of range (1 - %i) " +- "specified by HW", rblock->max_qp); +- ret = -EINVAL; +- goto sense_attributes1; +- } +- +- if (ehca_max_cq == -1) +- ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES); +- else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) { +- ehca_gen_err("Requested number of CQs is out of range (1 - %i) " +- "specified by HW", rblock->max_cq); +- ret = -EINVAL; +- goto sense_attributes1; ++ if (shca->max_num_qps == -1) ++ shca->max_num_qps = min_t(int, rblock->max_qp, ++ EHCA_MAX_NUM_QUEUES); ++ else if (shca->max_num_qps < 1 || shca->max_num_qps > rblock->max_qp) { ++ ehca_gen_warn("The requested number of QPs is out of range " ++ "(1 - %i) specified by HW. Value is set to %i", ++ rblock->max_qp, rblock->max_qp); ++ shca->max_num_qps = rblock->max_qp; ++ } ++ ++ if (shca->max_num_cqs == -1) ++ shca->max_num_cqs = min_t(int, rblock->max_cq, ++ EHCA_MAX_NUM_QUEUES); ++ else if (shca->max_num_cqs < 1 || shca->max_num_cqs > rblock->max_cq) { ++ ehca_gen_warn("The requested number of CQs is out of range " ++ "(1 - %i) specified by HW. Value is set to %i", ++ rblock->max_cq, rblock->max_cq); + } + + /* query max MTU from first port -- it's the same for all ports */ +@@ -735,9 +736,13 @@ static int __devinit ehca_probe(struct o + ehca_gen_err("Cannot allocate shca memory."); + return -ENOMEM; + } ++ + mutex_init(&shca->modify_mutex); + atomic_set(&shca->num_cqs, 0); + atomic_set(&shca->num_qps, 0); ++ shca->max_num_qps = ehca_max_qp; ++ shca->max_num_cqs = ehca_max_cq; ++ + for (i = 0; i < ARRAY_SIZE(shca->sport); i++) + spin_lock_init(&shca->sport[i].mod_sqp_lock); + +@@ -757,7 +762,7 @@ static int __devinit ehca_probe(struct o + goto probe1; + } + +- eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp; ++ eq_size = 2 * shca->max_num_cqs + 4 * shca->max_num_qps; + /* create event queues */ + ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size); + if (ret) { +Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_qp.c +=================================================================== +--- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_qp.c ++++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_qp.c +@@ -465,9 +465,9 @@ static struct ehca_qp *internal_create_q + u32 swqe_size = 0, rwqe_size = 0, ib_qp_num; + unsigned long flags; + +- if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) { ++ if (!atomic_add_unless(&shca->num_qps, 1, shca->max_num_qps)) { + ehca_err(pd->device, "Unable to create QP, max number of %i " +- "QPs reached.", ehca_max_qp); ++ "QPs reached.", shca->max_num_qps); + ehca_err(pd->device, "To increase the maximum number of QPs " + "use the number_of_qps module parameter.\n"); + return ERR_PTR(-ENOSPC); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0001-Staging-add-TAINT_CRAP-for-all-drivers-staging-code.patch b/src/patches/suse-2.6.27.31/patches.drivers/0001-Staging-add-TAINT_CRAP-for-all-drivers-staging-code.patch new file mode 100644 index 000000000..f8c28971b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0001-Staging-add-TAINT_CRAP-for-all-drivers-staging-code.patch @@ -0,0 +1,110 @@ +From 061b1bd394ca8628b7c24eb4658ba3535da4249a Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 24 Sep 2008 14:46:44 -0700 +Subject: [PATCH 01/23] Staging: add TAINT_CRAP for all drivers/staging code +Patch-mainline: 2.6.28 + +We need to add a flag for all code that is in the drivers/staging/ +directory to prevent all other kernel developers from worrying about +issues here, and to notify users that the drivers might not be as good +as they are normally used to. + +Based on code from Andreas Gruenbacher and Jeff Mahoney to provide a +TAINT flag for the support level of a kernel module in the Novell +enterprise kernel release. + +This is the kernel portion of this feature, the ability for the flag to +be set needs to be done in the build process and will happen in a +follow-up patch. + +Cc: Andreas Gruenbacher +Cc: Jeff Mahoney +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/sysctl/kernel.txt | 1 + + include/linux/kernel.h | 1 + + kernel/module.c | 11 +++++++++++ + kernel/panic.c | 4 +++- + 4 files changed, 16 insertions(+), 1 deletion(-) + +--- a/Documentation/sysctl/kernel.txt ++++ b/Documentation/sysctl/kernel.txt +@@ -369,6 +369,7 @@ can be ORed together: + 2 - A module was force loaded by insmod -f. + Set by modutils >= 2.4.9 and module-init-tools. + 4 - Unsafe SMP processors: SMP with CPUs not designed for SMP. ++ 64 - A module from drivers/staging was loaded. + 0x40000000 - An unsupported kernel module was loaded. + 0x80000000 - An kernel module with external support was loaded. + +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -263,6 +263,7 @@ extern enum system_states { + #define TAINT_DIE (1<<7) + #define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8) + #define TAINT_WARN (1<<9) ++#define TAINT_CRAP (1<<10) + + /* + * Take the upper bits to hopefully allow them +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -1894,6 +1894,7 @@ static noinline struct module *load_modu + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + char *secstrings, *args, *modmagic, *strtab = NULL; ++ char *staging; + unsigned int i; + unsigned int symindex = 0; + unsigned int strindex = 0; +@@ -2051,6 +2052,14 @@ static noinline struct module *load_modu + goto free_hdr; + } + ++ staging = get_modinfo(sechdrs, infoindex, "staging"); ++ if (staging) { ++ add_taint_module(mod, TAINT_CRAP); ++ printk(KERN_WARNING "%s: module is from the staging directory," ++ " the quality is unknown, you have been warned.\n", ++ mod->name); ++ } ++ + /* Now copy in args */ + args = strndup_user(uargs, ~0UL >> 1); + if (IS_ERR(args)) { +@@ -2699,6 +2708,8 @@ static char *module_flags(struct module + buf[bx++] = 'P'; + if (mod->taints & TAINT_FORCED_MODULE) + buf[bx++] = 'F'; ++ if (mod->taints & TAINT_CRAP) ++ buf[bx++] = 'C'; + if (mod->taints & TAINT_NO_SUPPORT) + buf[bx++] = 'N'; + if (mod->taints & TAINT_EXTERNAL_SUPPORT) +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -178,6 +178,7 @@ EXPORT_SYMBOL(panic); + * 'U' - Userspace-defined naughtiness. + * 'A' - ACPI table overridden. + * 'W' - Taint on warning. ++ * 'C' - modules from drivers/staging are loaded. + * 'N' - Unsuported modules loaded. + * 'X' - Modules with external support loaded. + * +@@ -188,7 +189,7 @@ const char *print_tainted(void) + { + static char buf[20]; + if (tainted) { +- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c%c%c", ++ snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c%c%c%c", + tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', +@@ -199,6 +200,7 @@ const char *print_tainted(void) + tainted & TAINT_DIE ? 'D' : ' ', + tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ', + tainted & TAINT_WARN ? 'W' : ' ', ++ tainted & TAINT_CRAP ? 'C' : ' ', + tainted & TAINT_NO_SUPPORT ? 'N' : ' ', + tainted & TAINT_EXTERNAL_SUPPORT ? 'X' : ' '); + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0002-Staging-add-TAINT_CRAP-flag-to-drivers-staging-modu.patch b/src/patches/suse-2.6.27.31/patches.drivers/0002-Staging-add-TAINT_CRAP-flag-to-drivers-staging-modu.patch new file mode 100644 index 000000000..e55b38dc5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0002-Staging-add-TAINT_CRAP-flag-to-drivers-staging-modu.patch @@ -0,0 +1,50 @@ +From a9860bf05f4cb94f60f8f3459908d5621f75dd06 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 24 Sep 2008 14:46:44 -0700 +Subject: [PATCH 02/23] Staging: add TAINT_CRAP flag to drivers/staging modules +Patch-mainline: 2.6.28 + +We need to add a flag for all code that is in the drivers/staging/ +directory to prevent all other kernel developers from worrying about +issues here, and to notify users that the drivers might not be as good +as they are normally used to. + +Based on code from Andreas Gruenbacher and Jeff Mahoney to provide a +TAINT flag for the support level of a kernel module in the Novell +enterprise kernel release. + +This is the code that actually modifies the modules, adding the flag to +any files in the drivers/staging directory. + +Cc: Andreas Gruenbacher +Cc: Jeff Mahoney +Signed-off-by: Greg Kroah-Hartman +--- + scripts/mod/modpost.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1776,6 +1776,14 @@ void add_supported_flag(struct buffer *b + buf_printf(b, "\nMODULE_INFO(supported, \"%s\");\n", how); + } + ++void add_staging_flag(struct buffer *b, const char *name) ++{ ++ static const char *staging_dir = "drivers/staging"; ++ ++ if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) ++ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++} ++ + /** + * Record CRCs for unresolved symbols + **/ +@@ -2199,6 +2207,7 @@ int main(int argc, char **argv) + buf.pos = 0; + + add_header(&buf, mod); ++ add_staging_flag(&buf, mod->name); + add_supported_flag(&buf, mod); + err |= add_versions(&buf, mod); + add_depends(&buf, mod, modules); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0003-Staging-add-Kconfig-entries-and-Makefile-infrastruc.patch b/src/patches/suse-2.6.27.31/patches.drivers/0003-Staging-add-Kconfig-entries-and-Makefile-infrastruc.patch new file mode 100644 index 000000000..59259d3cf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0003-Staging-add-Kconfig-entries-and-Makefile-infrastruc.patch @@ -0,0 +1,69 @@ +From 350455891377250cf7e0eadc5f9635decc1628af Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 24 Sep 2008 14:46:44 -0700 +Subject: [PATCH 03/23] Staging: add Kconfig entries and Makefile infrastructure +Patch-mainline: 2.6.28 + +This hooks up the drivers/staging directory to the build system + +Signed-off-by: Greg Kroah-Hartman +--- + drivers/Kconfig | 2 ++ + drivers/Makefile | 1 + + drivers/staging/Kconfig | 27 +++++++++++++++++++++++++++ + drivers/staging/Makefile | 2 ++ + 4 files changed, 32 insertions(+) + create mode 100644 drivers/staging/Kconfig + create mode 100644 drivers/staging/Makefile + +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -101,4 +101,6 @@ source "drivers/auxdisplay/Kconfig" + source "drivers/uio/Kconfig" + + source "drivers/xen/Kconfig" ++ ++source "drivers/staging/Kconfig" + endmenu +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -99,3 +99,4 @@ obj-$(CONFIG_OF) += of/ + obj-$(CONFIG_SSB) += ssb/ + obj-$(CONFIG_VIRTIO) += virtio/ + obj-$(CONFIG_REGULATOR) += regulator/ ++obj-$(CONFIG_STAGING) += staging/ +--- /dev/null ++++ b/drivers/staging/Kconfig +@@ -0,0 +1,27 @@ ++menuconfig STAGING ++ bool "Staging drivers" ++ default n ++ ---help--- ++ This option allows you to select a number of drivers that are ++ not of the "normal" Linux kernel quality level. These drivers ++ are placed here in order to get a wider audience for use of ++ them. Please note that these drivers are under heavy ++ development, may or may not work, and may contain userspace ++ interfaces that most likely will be changed in the near ++ future. ++ ++ Using any of these drivers will taint your kernel which might ++ affect support options from both the community, and various ++ commercial support orginizations. ++ ++ If you wish to work on these drivers, to help improve them, or ++ to report problems you have with them, please see the ++ driver_name.README file in the drivers/staging/ directory to ++ see what needs to be worked on, and who to contact. ++ ++ If in doubt, say N here. ++ ++if STAGING ++ ++ ++endif # STAGING +--- /dev/null ++++ b/drivers/staging/Makefile +@@ -0,0 +1,2 @@ ++# Makefile for staging directory ++ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0004-Staging-add-MAINTAINERS-entry.patch b/src/patches/suse-2.6.27.31/patches.drivers/0004-Staging-add-MAINTAINERS-entry.patch new file mode 100644 index 000000000..a77fd27a8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0004-Staging-add-MAINTAINERS-entry.patch @@ -0,0 +1,30 @@ +From dbc6c2ccb9f0abd6a19406718730ce0f715b2998 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 24 Sep 2008 14:46:44 -0700 +Subject: [PATCH 04/23] Staging: add MAINTAINERS entry +Patch-mainline: 2.6.28 + +Someone has to claim this mess, might as well let everyone know who to +blame. + +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3881,6 +3881,13 @@ M: chrisw@sous-sol.org + L: stable@kernel.org + S: Maintained + ++STAGING SUBSYSTEM: ++P: Greg Kroah-Hartman ++M: gregkh@suse.de ++L: linux-kernel@vger.kernel.org ++T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/ ++S: Maintained ++ + SHARP LH SUPPORT (LH7952X & LH7A40X) + P: Marc Singer + M: elf@buici.com diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0005-Staging-add-et131x-network-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0005-Staging-add-et131x-network-driver.patch new file mode 100644 index 000000000..0560153e4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0005-Staging-add-et131x-network-driver.patch @@ -0,0 +1,14565 @@ +From cfb739b459a4d982b75f5b92cbe7d2631999e206 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 3 Apr 2008 17:30:53 -0700 +Subject: [PATCH 05/23] Staging: add et131x network driver +Patch-mainline: 2.6.28 + +This is a driver for the ET1310 network device. + +Based on the driver found at https://sourceforge.net/projects/et131x/ + +Cleaned up immensely by Olaf Hartman and Christoph +Hellwig + +Note, the powermanagement options were removed from the vendor provided +driver as they did not build properly at the time. + +TODO: + - kernel coding style cleanups + - forward port for latest network driver changes + - kill useless typecasts (e.g. in et1310_phy.c) + - alloc_etherdev is initializing memory with zero?!? + - add_timer call in et131x_netdev.c is correct? + - Add power saving functionality (suspend, sleep, resume) + - Implement a few more kernel Parameter (set mac ) + +Cc: Olaf Hartmann +Cc: Christoph Hellwig +Cc: Dean Adams +Cc: Victor Soriano +Cc: Andre-Sebastian Liebe +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 1 + + drivers/staging/Makefile | 1 + + drivers/staging/et131x/Kconfig | 18 + + drivers/staging/et131x/Makefile | 18 + + drivers/staging/et131x/README | 25 + + drivers/staging/et131x/et1310_address_map.h | 2399 +++++++++++++++++++++++++++ + drivers/staging/et131x/et1310_eeprom.c | 480 ++++++ + drivers/staging/et131x/et1310_eeprom.h | 89 + + drivers/staging/et131x/et1310_jagcore.c | 220 +++ + drivers/staging/et131x/et1310_jagcore.h | 112 ++ + drivers/staging/et131x/et1310_mac.c | 792 +++++++++ + drivers/staging/et131x/et1310_mac.h | 93 + + drivers/staging/et131x/et1310_phy.c | 1281 ++++++++++++++ + drivers/staging/et131x/et1310_phy.h | 910 ++++++++++ + drivers/staging/et131x/et1310_pm.c | 207 +++ + drivers/staging/et131x/et1310_pm.h | 125 ++ + drivers/staging/et131x/et1310_rx.c | 1391 ++++++++++++++++ + drivers/staging/et131x/et1310_rx.h | 373 +++++ + drivers/staging/et131x/et1310_tx.c | 1525 +++++++++++++++++ + drivers/staging/et131x/et1310_tx.h | 242 +++ + drivers/staging/et131x/et131x_adapter.h | 347 ++++ + drivers/staging/et131x/et131x_config.c | 325 ++++ + drivers/staging/et131x/et131x_config.h | 67 + + drivers/staging/et131x/et131x_debug.c | 218 +++ + drivers/staging/et131x/et131x_debug.h | 201 +++ + drivers/staging/et131x/et131x_defs.h | 128 ++ + drivers/staging/et131x/et131x_initpci.c | 1046 ++++++++++++ + drivers/staging/et131x/et131x_initpci.h | 73 + + drivers/staging/et131x/et131x_isr.c | 488 ++++++ + drivers/staging/et131x/et131x_isr.h | 65 + + drivers/staging/et131x/et131x_netdev.c | 856 ++++++++++ + drivers/staging/et131x/et131x_netdev.h | 64 + + drivers/staging/et131x/et131x_version.h | 81 + + 33 files changed, 14261 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/et131x/Kconfig + create mode 100644 drivers/staging/et131x/Makefile + create mode 100644 drivers/staging/et131x/README + create mode 100644 drivers/staging/et131x/et1310_address_map.h + create mode 100644 drivers/staging/et131x/et1310_eeprom.c + create mode 100644 drivers/staging/et131x/et1310_eeprom.h + create mode 100644 drivers/staging/et131x/et1310_jagcore.c + create mode 100644 drivers/staging/et131x/et1310_jagcore.h + create mode 100644 drivers/staging/et131x/et1310_mac.c + create mode 100644 drivers/staging/et131x/et1310_mac.h + create mode 100644 drivers/staging/et131x/et1310_phy.c + create mode 100644 drivers/staging/et131x/et1310_phy.h + create mode 100644 drivers/staging/et131x/et1310_pm.c + create mode 100644 drivers/staging/et131x/et1310_pm.h + create mode 100644 drivers/staging/et131x/et1310_rx.c + create mode 100644 drivers/staging/et131x/et1310_rx.h + create mode 100644 drivers/staging/et131x/et1310_tx.c + create mode 100644 drivers/staging/et131x/et1310_tx.h + create mode 100644 drivers/staging/et131x/et131x_adapter.h + create mode 100644 drivers/staging/et131x/et131x_config.c + create mode 100644 drivers/staging/et131x/et131x_config.h + create mode 100644 drivers/staging/et131x/et131x_debug.c + create mode 100644 drivers/staging/et131x/et131x_debug.h + create mode 100644 drivers/staging/et131x/et131x_defs.h + create mode 100644 drivers/staging/et131x/et131x_initpci.c + create mode 100644 drivers/staging/et131x/et131x_initpci.h + create mode 100644 drivers/staging/et131x/et131x_isr.c + create mode 100644 drivers/staging/et131x/et131x_isr.h + create mode 100644 drivers/staging/et131x/et131x_netdev.c + create mode 100644 drivers/staging/et131x/et131x_netdev.h + create mode 100644 drivers/staging/et131x/et131x_version.h + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 84832fe..4c3789d 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -23,5 +23,6 @@ menuconfig STAGING + + if STAGING + ++source "drivers/staging/et131x/Kconfig" + + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index ceb0328..933b984 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -1,2 +1,3 @@ + # Makefile for staging directory + ++obj-$(CONFIG_ET131X) += et131x/ +diff --git a/drivers/staging/et131x/Kconfig b/drivers/staging/et131x/Kconfig +new file mode 100644 +index 0000000..e11cf34 +--- /dev/null ++++ b/drivers/staging/et131x/Kconfig +@@ -0,0 +1,18 @@ ++config ET131X ++ tristate "Agere ET-1310 Gigabit Ethernet support" ++ depends on NETDEV_1000 && PCI ++ default n ++ ---help--- ++ This driver supports Agere ET-1310 ethernet adapters. ++ ++ To compile this driver as a module, choose M here. The module ++ will be called et131x. ++ ++config ET131X_DEBUG ++ bool "Enable et131x debugging" ++ depends on ET131X ++ default n ++ ---help--- ++ Say Y for detailed debug information. ++ ++ If in doubt, say N. +diff --git a/drivers/staging/et131x/Makefile b/drivers/staging/et131x/Makefile +new file mode 100644 +index 0000000..3ad571d +--- /dev/null ++++ b/drivers/staging/et131x/Makefile +@@ -0,0 +1,18 @@ ++# ++# Makefile for the Agere ET-131x ethernet driver ++# ++ ++obj-$(CONFIG_ET131X) += et131x.o ++ ++et131x-objs := et1310_eeprom.o \ ++ et1310_jagcore.o \ ++ et1310_mac.o \ ++ et1310_phy.o \ ++ et1310_pm.o \ ++ et1310_rx.o \ ++ et1310_tx.o \ ++ et131x_config.o \ ++ et131x_debug.o \ ++ et131x_initpci.o \ ++ et131x_isr.o \ ++ et131x_netdev.o +diff --git a/drivers/staging/et131x/README b/drivers/staging/et131x/README +new file mode 100644 +index 0000000..28752a5 +--- /dev/null ++++ b/drivers/staging/et131x/README +@@ -0,0 +1,25 @@ ++This is a driver for the ET1310 network device. ++ ++Based on the driver found at https://sourceforge.net/projects/et131x/ ++ ++Cleaned up immensely by Olaf Hartman and Christoph ++Hellwig ++ ++Note, the powermanagement options were removed from the vendor provided ++driver as they did not build properly at the time. ++ ++TODO: ++ - kernel coding style cleanups ++ - forward port for latest network driver changes ++ - kill useless typecasts (e.g. in et1310_phy.c) ++ - alloc_etherdev is initializing memory with zero?!? ++ - add_timer call in et131x_netdev.c is correct? ++ - Add power saving functionality (suspend, sleep, resume) ++ - Implement a few more kernel Parameter (set mac ) ++ ++Please send patches to: ++ Greg Kroah-Hartman ++ ++And Cc: Olaf Hartmann as he has this device and can ++test any changes. ++ +diff --git a/drivers/staging/et131x/et1310_address_map.h b/drivers/staging/et131x/et1310_address_map.h +new file mode 100644 +index 0000000..3c85999 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_address_map.h +@@ -0,0 +1,2399 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_address_map.h - Contains the register mapping for the ET1310 ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef _ET1310_ADDRESS_MAP_H_ ++#define _ET1310_ADDRESS_MAP_H_ ++ ++ ++/* START OF GLOBAL REGISTER ADDRESS MAP */ ++ ++typedef union _Q_ADDR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:22; // bits 10-31 ++ u32 addr:10; // bits 0-9 ++#else ++ u32 addr:10; // bits 0-9 ++ u32 unused:22; // bits 10-31 ++#endif ++ } bits; ++} Q_ADDR_t, *PQ_ADDR_t; ++ ++/* ++ * structure for tx queue start address reg in global address map ++ * located at address 0x0000 ++ * Defined earlier (Q_ADDR_t) ++ */ ++ ++/* ++ * structure for tx queue end address reg in global address map ++ * located at address 0x0004 ++ * Defined earlier (Q_ADDR_t) ++ */ ++ ++/* ++ * structure for rx queue start address reg in global address map ++ * located at address 0x0008 ++ * Defined earlier (Q_ADDR_t) ++ */ ++ ++/* ++ * structure for rx queue end address reg in global address map ++ * located at address 0x000C ++ * Defined earlier (Q_ADDR_t) ++ */ ++ ++/* ++ * structure for power management control status reg in global address map ++ * located at address 0x0010 ++ */ ++typedef union _PM_CSR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:22; // bits 10-31 ++ u32 pm_jagcore_rx_rdy:1; // bit 9 ++ u32 pm_jagcore_tx_rdy:1; // bit 8 ++ u32 pm_phy_lped_en:1; // bit 7 ++ u32 pm_phy_sw_coma:1; // bit 6 ++ u32 pm_rxclk_gate:1; // bit 5 ++ u32 pm_txclk_gate:1; // bit 4 ++ u32 pm_sysclk_gate:1; // bit 3 ++ u32 pm_jagcore_rx_en:1; // bit 2 ++ u32 pm_jagcore_tx_en:1; // bit 1 ++ u32 pm_gigephy_en:1; // bit 0 ++#else ++ u32 pm_gigephy_en:1; // bit 0 ++ u32 pm_jagcore_tx_en:1; // bit 1 ++ u32 pm_jagcore_rx_en:1; // bit 2 ++ u32 pm_sysclk_gate:1; // bit 3 ++ u32 pm_txclk_gate:1; // bit 4 ++ u32 pm_rxclk_gate:1; // bit 5 ++ u32 pm_phy_sw_coma:1; // bit 6 ++ u32 pm_phy_lped_en:1; // bit 7 ++ u32 pm_jagcore_tx_rdy:1; // bit 8 ++ u32 pm_jagcore_rx_rdy:1; // bit 9 ++ u32 unused:22; // bits 10-31 ++#endif ++ } bits; ++} PM_CSR_t, *PPM_CSR_t; ++ ++/* ++ * structure for interrupt status reg in global address map ++ * located at address 0x0018 ++ */ ++typedef union _INTERRUPT_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused5:11; // bits 21-31 ++ u32 slv_timeout:1; // bit 20 ++ u32 mac_stat_interrupt:1; // bit 19 ++ u32 rxmac_interrupt:1; // bit 18 ++ u32 txmac_interrupt:1; // bit 17 ++ u32 phy_interrupt:1; // bit 16 ++ u32 wake_on_lan:1; // bit 15 ++ u32 watchdog_interrupt:1; // bit 14 ++ u32 unused4:4; // bits 10-13 ++ u32 rxdma_err:1; // bit 9 ++ u32 rxdma_pkt_stat_ring_low:1; // bit 8 ++ u32 rxdma_fb_ring1_low:1; // bit 7 ++ u32 rxdma_fb_ring0_low:1; // bit 6 ++ u32 rxdma_xfr_done:1; // bit 5 ++ u32 txdma_err:1; // bit 4 ++ u32 txdma_isr:1; // bit 3 ++ u32 unused3:1; // bit 2 ++ u32 unused2:1; // bit 1 ++ u32 unused1:1; // bit 0 ++#else ++ u32 unused1:1; // bit 0 ++ u32 unused2:1; // bit 1 ++ u32 unused3:1; // bit 2 ++ u32 txdma_isr:1; // bit 3 ++ u32 txdma_err:1; // bit 4 ++ u32 rxdma_xfr_done:1; // bit 5 ++ u32 rxdma_fb_ring0_low:1; // bit 6 ++ u32 rxdma_fb_ring1_low:1; // bit 7 ++ u32 rxdma_pkt_stat_ring_low:1; // bit 8 ++ u32 rxdma_err:1; // bit 9 ++ u32 unused4:4; // bits 10-13 ++ u32 watchdog_interrupt:1; // bit 14 ++ u32 wake_on_lan:1; // bit 15 ++ u32 phy_interrupt:1; // bit 16 ++ u32 txmac_interrupt:1; // bit 17 ++ u32 rxmac_interrupt:1; // bit 18 ++ u32 mac_stat_interrupt:1; // bit 19 ++ u32 slv_timeout:1; // bit 20 ++ u32 unused5:11; // bits 21-31 ++#endif ++ } bits; ++} INTERRUPT_t, *PINTERRUPT_t; ++ ++/* ++ * structure for interrupt mask reg in global address map ++ * located at address 0x001C ++ * Defined earlier (INTERRUPT_t), but 'watchdog_interrupt' is not used. ++ */ ++ ++/* ++ * structure for interrupt alias clear mask reg in global address map ++ * located at address 0x0020 ++ * Defined earlier (INTERRUPT_t) ++ */ ++ ++/* ++ * structure for interrupt status alias reg in global address map ++ * located at address 0x0024 ++ * Defined earlier (INTERRUPT_t) ++ */ ++ ++/* ++ * structure for software reset reg in global address map ++ * located at address 0x0028 ++ */ ++typedef union _SW_RESET_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 selfclr_disable:1; // bit 31 ++ u32 unused:24; // bits 7-30 ++ u32 mmc_sw_reset:1; // bit 6 ++ u32 mac_stat_sw_reset:1; // bit 5 ++ u32 mac_sw_reset:1; // bit 4 ++ u32 rxmac_sw_reset:1; // bit 3 ++ u32 txmac_sw_reset:1; // bit 2 ++ u32 rxdma_sw_reset:1; // bit 1 ++ u32 txdma_sw_reset:1; // bit 0 ++#else ++ u32 txdma_sw_reset:1; // bit 0 ++ u32 rxdma_sw_reset:1; // bit 1 ++ u32 txmac_sw_reset:1; // bit 2 ++ u32 rxmac_sw_reset:1; // bit 3 ++ u32 mac_sw_reset:1; // bit 4 ++ u32 mac_stat_sw_reset:1; // bit 5 ++ u32 mmc_sw_reset:1; // bit 6 ++ u32 unused:24; // bits 7-30 ++ u32 selfclr_disable:1; // bit 31 ++#endif ++ } bits; ++} SW_RESET_t, *PSW_RESET_t; ++ ++/* ++ * structure for SLV Timer reg in global address map ++ * located at address 0x002C ++ */ ++typedef union _SLV_TIMER_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:8; // bits 24-31 ++ u32 timer_ini:24; // bits 0-23 ++#else ++ u32 timer_ini:24; // bits 0-23 ++ u32 unused:8; // bits 24-31 ++#endif ++ } bits; ++} SLV_TIMER_t, *PSLV_TIMER_t; ++ ++/* ++ * structure for MSI Configuration reg in global address map ++ * located at address 0x0030 ++ */ ++typedef union _MSI_CONFIG_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused1:13; // bits 19-31 ++ u32 msi_tc:3; // bits 16-18 ++ u32 unused2:11; // bits 5-15 ++ u32 msi_vector:5; // bits 0-4 ++#else ++ u32 msi_vector:5; // bits 0-4 ++ u32 unused2:11; // bits 5-15 ++ u32 msi_tc:3; // bits 16-18 ++ u32 unused1:13; // bits 19-31 ++#endif ++ } bits; ++} MSI_CONFIG_t, *PMSI_CONFIG_t; ++ ++/* ++ * structure for Loopback reg in global address map ++ * located at address 0x0034 ++ */ ++typedef union _LOOPBACK_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:30; // bits 2-31 ++ u32 dma_loopback:1; // bit 1 ++ u32 mac_loopback:1; // bit 0 ++#else ++ u32 mac_loopback:1; // bit 0 ++ u32 dma_loopback:1; // bit 1 ++ u32 unused:30; // bits 2-31 ++#endif ++ } bits; ++} LOOPBACK_t, *PLOOPBACK_t; ++ ++/* ++ * GLOBAL Module of JAGCore Address Mapping ++ * Located at address 0x0000 ++ */ ++typedef struct _GLOBAL_t { // Location: ++ Q_ADDR_t txq_start_addr; // 0x0000 ++ Q_ADDR_t txq_end_addr; // 0x0004 ++ Q_ADDR_t rxq_start_addr; // 0x0008 ++ Q_ADDR_t rxq_end_addr; // 0x000C ++ PM_CSR_t pm_csr; // 0x0010 ++ u32 unused; // 0x0014 ++ INTERRUPT_t int_status; // 0x0018 ++ INTERRUPT_t int_mask; // 0x001C ++ INTERRUPT_t int_alias_clr_en; // 0x0020 ++ INTERRUPT_t int_status_alias; // 0x0024 ++ SW_RESET_t sw_reset; // 0x0028 ++ SLV_TIMER_t slv_timer; // 0x002C ++ MSI_CONFIG_t msi_config; // 0x0030 ++ LOOPBACK_t loopback; // 0x0034 ++ u32 watchdog_timer; // 0x0038 ++} GLOBAL_t, *PGLOBAL_t; ++ ++/* END OF GLOBAL REGISTER ADDRESS MAP */ ++ ++ ++/* START OF TXDMA REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for txdma control status reg in txdma address map ++ * located at address 0x1000 ++ */ ++typedef union _TXDMA_CSR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused2:19; // bits 13-31 ++ u32 traffic_class:4; // bits 9-12 ++ u32 sngl_epkt_mode:1; // bit 8 ++ u32 cache_thrshld:4; // bits 4-7 ++ u32 unused1:2; // bits 2-3 ++ u32 drop_TLP_disable:1; // bit 1 ++ u32 halt:1; // bit 0 ++#else ++ u32 halt:1; // bit 0 ++ u32 drop_TLP_disable:1; // bit 1 ++ u32 unused1:2; // bits 2-3 ++ u32 cache_thrshld:4; // bits 4-7 ++ u32 sngl_epkt_mode:1; // bit 8 ++ u32 traffic_class:4; // bits 9-12 ++ u32 unused2:19; // bits 13-31 ++#endif ++ } bits; ++} TXDMA_CSR_t, *PTXDMA_CSR_t; ++ ++/* ++ * structure for txdma packet ring base address hi reg in txdma address map ++ * located at address 0x1004 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for txdma packet ring base address low reg in txdma address map ++ * located at address 0x1008 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for txdma packet ring number of descriptor reg in txdma address ++ * map. Located at address 0x100C ++ */ ++typedef union _TXDMA_PR_NUM_DES_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:22; // bits 10-31 ++ u32 pr_ndes:10; // bits 0-9 ++#else ++ u32 pr_ndes:10; // bits 0-9 ++ u32 unused:22; // bits 10-31 ++#endif ++ } bits; ++} TXDMA_PR_NUM_DES_t, *PTXDMA_PR_NUM_DES_t; ++ ++ ++typedef union _DMA10W_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:21; // bits 11-31 ++ u32 wrap:1; // bit 10 ++ u32 val:10; // bits 0-9 ++#else ++ u32 val:10; // bits 0-9 ++ u32 wrap:1; // bit 10 ++ u32 unused:21; // bits 11-31 ++#endif ++ } bits; ++} DMA10W_t, *PDMA10W_t; ++ ++/* ++ * structure for txdma tx queue write address reg in txdma address map ++ * located at address 0x1010 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for txdma tx queue write address external reg in txdma address map ++ * located at address 0x1014 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for txdma tx queue read address reg in txdma address map ++ * located at address 0x1018 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for txdma status writeback address hi reg in txdma address map ++ * located at address 0x101C ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for txdma status writeback address lo reg in txdma address map ++ * located at address 0x1020 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for txdma service request reg in txdma address map ++ * located at address 0x1024 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for txdma service complete reg in txdma address map ++ * located at address 0x1028 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++typedef union _DMA4W_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:27; // bits 5-31 ++ u32 wrap:1; // bit 4 ++ u32 val:4; // bit 0-3 ++#else ++ u32 val:4; // bits 0-3 ++ u32 wrap:1; // bit 4 ++ u32 unused:27; // bits 5-31 ++#endif ++ } bits; ++} DMA4W_t, *PDMA4W_t; ++ ++/* ++ * structure for txdma tx descriptor cache read index reg in txdma address map ++ * located at address 0x102C ++ * Defined earlier (DMA4W_t) ++ */ ++ ++/* ++ * structure for txdma tx descriptor cache write index reg in txdma address map ++ * located at address 0x1030 ++ * Defined earlier (DMA4W_t) ++ */ ++ ++/* ++ * structure for txdma error reg in txdma address map ++ * located at address 0x1034 ++ */ ++typedef union _TXDMA_ERROR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused3:22; // bits 10-31 ++ u32 WrbkRewind:1; // bit 9 ++ u32 WrbkResend:1; // bit 8 ++ u32 unused2:2; // bits 6-7 ++ u32 DescrRewind:1; // bit 5 ++ u32 DescrResend:1; // bit 4 ++ u32 unused1:2; // bits 2-3 ++ u32 PyldRewind:1; // bit 1 ++ u32 PyldResend:1; // bit 0 ++#else ++ u32 PyldResend:1; // bit 0 ++ u32 PyldRewind:1; // bit 1 ++ u32 unused1:2; // bits 2-3 ++ u32 DescrResend:1; // bit 4 ++ u32 DescrRewind:1; // bit 5 ++ u32 unused2:2; // bits 6-7 ++ u32 WrbkResend:1; // bit 8 ++ u32 WrbkRewind:1; // bit 9 ++ u32 unused3:22; // bits 10-31 ++#endif ++ } bits; ++} TXDMA_ERROR_t, *PTXDMA_ERROR_t; ++ ++/* ++ * Tx DMA Module of JAGCore Address Mapping ++ * Located at address 0x1000 ++ */ ++typedef struct _TXDMA_t { // Location: ++ TXDMA_CSR_t csr; // 0x1000 ++ u32 pr_base_hi; // 0x1004 ++ u32 pr_base_lo; // 0x1008 ++ TXDMA_PR_NUM_DES_t pr_num_des; // 0x100C ++ DMA10W_t txq_wr_addr; // 0x1010 ++ DMA10W_t txq_wr_addr_ext; // 0x1014 ++ DMA10W_t txq_rd_addr; // 0x1018 ++ u32 dma_wb_base_hi; // 0x101C ++ u32 dma_wb_base_lo; // 0x1020 ++ DMA10W_t service_request; // 0x1024 ++ DMA10W_t service_complete; // 0x1028 ++ DMA4W_t cache_rd_index; // 0x102C ++ DMA4W_t cache_wr_index; // 0x1030 ++ TXDMA_ERROR_t TxDmaError; // 0x1034 ++ u32 DescAbortCount; // 0x1038 ++ u32 PayloadAbortCnt; // 0x103c ++ u32 WriteBackAbortCnt; // 0x1040 ++ u32 DescTimeoutCnt; // 0x1044 ++ u32 PayloadTimeoutCnt; // 0x1048 ++ u32 WriteBackTimeoutCnt; // 0x104c ++ u32 DescErrorCount; // 0x1050 ++ u32 PayloadErrorCnt; // 0x1054 ++ u32 WriteBackErrorCnt; // 0x1058 ++ u32 DroppedTLPCount; // 0x105c ++ DMA10W_t NewServiceComplete; // 0x1060 ++ u32 EthernetPacketCount; // 0x1064 ++} TXDMA_t, *PTXDMA_t; ++ ++/* END OF TXDMA REGISTER ADDRESS MAP */ ++ ++ ++/* START OF RXDMA REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for control status reg in rxdma address map ++ * Located at address 0x2000 ++ */ ++typedef union _RXDMA_CSR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused2:14; // bits 18-31 ++ u32 halt_status:1; // bit 17 ++ u32 pkt_done_flush:1; // bit 16 ++ u32 pkt_drop_disable:1; // bit 15 ++ u32 unused1:1; // bit 14 ++ u32 fbr1_enable:1; // bit 13 ++ u32 fbr1_size:2; // bits 11-12 ++ u32 fbr0_enable:1; // bit 10 ++ u32 fbr0_size:2; // bits 8-9 ++ u32 dma_big_endian:1; // bit 7 ++ u32 pkt_big_endian:1; // bit 6 ++ u32 psr_big_endian:1; // bit 5 ++ u32 fbr_big_endian:1; // bit 4 ++ u32 tc:3; // bits 1-3 ++ u32 halt:1; // bit 0 ++#else ++ u32 halt:1; // bit 0 ++ u32 tc:3; // bits 1-3 ++ u32 fbr_big_endian:1; // bit 4 ++ u32 psr_big_endian:1; // bit 5 ++ u32 pkt_big_endian:1; // bit 6 ++ u32 dma_big_endian:1; // bit 7 ++ u32 fbr0_size:2; // bits 8-9 ++ u32 fbr0_enable:1; // bit 10 ++ u32 fbr1_size:2; // bits 11-12 ++ u32 fbr1_enable:1; // bit 13 ++ u32 unused1:1; // bit 14 ++ u32 pkt_drop_disable:1; // bit 15 ++ u32 pkt_done_flush:1; // bit 16 ++ u32 halt_status:1; // bit 17 ++ u32 unused2:14; // bits 18-31 ++#endif ++ } bits; ++} RXDMA_CSR_t, *PRXDMA_CSR_t; ++ ++/* ++ * structure for dma writeback lo reg in rxdma address map ++ * located at address 0x2004 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for dma writeback hi reg in rxdma address map ++ * located at address 0x2008 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for number of packets done reg in rxdma address map ++ * located at address 0x200C ++ */ ++typedef union _RXDMA_NUM_PKT_DONE_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:24; // bits 8-31 ++ u32 num_done:8; // bits 0-7 ++#else ++ u32 num_done:8; // bits 0-7 ++ u32 unused:24; // bits 8-31 ++#endif ++ } bits; ++} RXDMA_NUM_PKT_DONE_t, *PRXDMA_NUM_PKT_DONE_t; ++ ++/* ++ * structure for max packet time reg in rxdma address map ++ * located at address 0x2010 ++ */ ++typedef union _RXDMA_MAX_PKT_TIME_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:14; // bits 18-31 ++ u32 time_done:18; // bits 0-17 ++#else ++ u32 time_done:18; // bits 0-17 ++ u32 unused:14; // bits 18-31 ++#endif ++ } bits; ++} RXDMA_MAX_PKT_TIME_t, *PRXDMA_MAX_PKT_TIME_t; ++ ++/* ++ * structure for rx queue read address reg in rxdma address map ++ * located at address 0x2014 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for rx queue read address external reg in rxdma address map ++ * located at address 0x2018 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for rx queue write address reg in rxdma address map ++ * located at address 0x201C ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for packet status ring base address lo reg in rxdma address map ++ * located at address 0x2020 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for packet status ring base address hi reg in rxdma address map ++ * located at address 0x2024 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for packet status ring number of descriptors reg in rxdma address ++ * map. Located at address 0x2028 ++ */ ++typedef union _RXDMA_PSR_NUM_DES_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:20; // bits 12-31 ++ u32 psr_ndes:12; // bit 0-11 ++#else ++ u32 psr_ndes:12; // bit 0-11 ++ u32 unused:20; // bits 12-31 ++#endif ++ } bits; ++} RXDMA_PSR_NUM_DES_t, *PRXDMA_PSR_NUM_DES_t; ++ ++/* ++ * structure for packet status ring available offset reg in rxdma address map ++ * located at address 0x202C ++ */ ++typedef union _RXDMA_PSR_AVAIL_OFFSET_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:19; // bits 13-31 ++ u32 psr_avail_wrap:1; // bit 12 ++ u32 psr_avail:12; // bit 0-11 ++#else ++ u32 psr_avail:12; // bit 0-11 ++ u32 psr_avail_wrap:1; // bit 12 ++ u32 unused:19; // bits 13-31 ++#endif ++ } bits; ++} RXDMA_PSR_AVAIL_OFFSET_t, *PRXDMA_PSR_AVAIL_OFFSET_t; ++ ++/* ++ * structure for packet status ring full offset reg in rxdma address map ++ * located at address 0x2030 ++ */ ++typedef union _RXDMA_PSR_FULL_OFFSET_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:19; // bits 13-31 ++ u32 psr_full_wrap:1; // bit 12 ++ u32 psr_full:12; // bit 0-11 ++#else ++ u32 psr_full:12; // bit 0-11 ++ u32 psr_full_wrap:1; // bit 12 ++ u32 unused:19; // bits 13-31 ++#endif ++ } bits; ++} RXDMA_PSR_FULL_OFFSET_t, *PRXDMA_PSR_FULL_OFFSET_t; ++ ++/* ++ * structure for packet status ring access index reg in rxdma address map ++ * located at address 0x2034 ++ */ ++typedef union _RXDMA_PSR_ACCESS_INDEX_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:27; // bits 5-31 ++ u32 psr_ai:5; // bits 0-4 ++#else ++ u32 psr_ai:5; // bits 0-4 ++ u32 unused:27; // bits 5-31 ++#endif ++ } bits; ++} RXDMA_PSR_ACCESS_INDEX_t, *PRXDMA_PSR_ACCESS_INDEX_t; ++ ++/* ++ * structure for packet status ring minimum descriptors reg in rxdma address ++ * map. Located at address 0x2038 ++ */ ++typedef union _RXDMA_PSR_MIN_DES_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:20; // bits 12-31 ++ u32 psr_min:12; // bits 0-11 ++#else ++ u32 psr_min:12; // bits 0-11 ++ u32 unused:20; // bits 12-31 ++#endif ++ } bits; ++} RXDMA_PSR_MIN_DES_t, *PRXDMA_PSR_MIN_DES_t; ++ ++/* ++ * structure for free buffer ring base lo address reg in rxdma address map ++ * located at address 0x203C ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for free buffer ring base hi address reg in rxdma address map ++ * located at address 0x2040 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for free buffer ring number of descriptors reg in rxdma address ++ * map. Located at address 0x2044 ++ */ ++typedef union _RXDMA_FBR_NUM_DES_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:22; // bits 10-31 ++ u32 fbr_ndesc:10; // bits 0-9 ++#else ++ u32 fbr_ndesc:10; // bits 0-9 ++ u32 unused:22; // bits 10-31 ++#endif ++ } bits; ++} RXDMA_FBR_NUM_DES_t, *PRXDMA_FBR_NUM_DES_t; ++ ++/* ++ * structure for free buffer ring 0 available offset reg in rxdma address map ++ * located at address 0x2048 ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for free buffer ring 0 full offset reg in rxdma address map ++ * located at address 0x204C ++ * Defined earlier (DMA10W_t) ++ */ ++ ++/* ++ * structure for free buffer cache 0 full offset reg in rxdma address map ++ * located at address 0x2050 ++ */ ++typedef union _RXDMA_FBC_RD_INDEX_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:27; // bits 5-31 ++ u32 fbc_rdi:5; // bit 0-4 ++#else ++ u32 fbc_rdi:5; // bit 0-4 ++ u32 unused:27; // bits 5-31 ++#endif ++ } bits; ++} RXDMA_FBC_RD_INDEX_t, *PRXDMA_FBC_RD_INDEX_t; ++ ++/* ++ * structure for free buffer ring 0 minimum descriptor reg in rxdma address map ++ * located at address 0x2054 ++ */ ++typedef union _RXDMA_FBR_MIN_DES_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:22; // bits 10-31 ++ u32 fbr_min:10; // bits 0-9 ++#else ++ u32 fbr_min:10; // bits 0-9 ++ u32 unused:22; // bits 10-31 ++#endif ++ } bits; ++} RXDMA_FBR_MIN_DES_t, *PRXDMA_FBR_MIN_DES_t; ++ ++/* ++ * structure for free buffer ring 1 base address lo reg in rxdma address map ++ * located at address 0x2058 - 0x205C ++ * Defined earlier (RXDMA_FBR_BASE_LO_t and RXDMA_FBR_BASE_HI_t) ++ */ ++ ++/* ++ * structure for free buffer ring 1 number of descriptors reg in rxdma address ++ * map. Located at address 0x2060 ++ * Defined earlier (RXDMA_FBR_NUM_DES_t) ++ */ ++ ++/* ++ * structure for free buffer ring 1 available offset reg in rxdma address map ++ * located at address 0x2064 ++ * Defined Earlier (RXDMA_FBR_AVAIL_OFFSET_t) ++ */ ++ ++/* ++ * structure for free buffer ring 1 full offset reg in rxdma address map ++ * located at address 0x2068 ++ * Defined Earlier (RXDMA_FBR_FULL_OFFSET_t) ++ */ ++ ++/* ++ * structure for free buffer cache 1 read index reg in rxdma address map ++ * located at address 0x206C ++ * Defined Earlier (RXDMA_FBC_RD_INDEX_t) ++ */ ++ ++/* ++ * structure for free buffer ring 1 minimum descriptor reg in rxdma address map ++ * located at address 0x2070 ++ * Defined Earlier (RXDMA_FBR_MIN_DES_t) ++ */ ++ ++/* ++ * Rx DMA Module of JAGCore Address Mapping ++ * Located at address 0x2000 ++ */ ++typedef struct _RXDMA_t { // Location: ++ RXDMA_CSR_t csr; // 0x2000 ++ u32 dma_wb_base_lo; // 0x2004 ++ u32 dma_wb_base_hi; // 0x2008 ++ RXDMA_NUM_PKT_DONE_t num_pkt_done; // 0x200C ++ RXDMA_MAX_PKT_TIME_t max_pkt_time; // 0x2010 ++ DMA10W_t rxq_rd_addr; // 0x2014 ++ DMA10W_t rxq_rd_addr_ext; // 0x2018 ++ DMA10W_t rxq_wr_addr; // 0x201C ++ u32 psr_base_lo; // 0x2020 ++ u32 psr_base_hi; // 0x2024 ++ RXDMA_PSR_NUM_DES_t psr_num_des; // 0x2028 ++ RXDMA_PSR_AVAIL_OFFSET_t psr_avail_offset; // 0x202C ++ RXDMA_PSR_FULL_OFFSET_t psr_full_offset; // 0x2030 ++ RXDMA_PSR_ACCESS_INDEX_t psr_access_index; // 0x2034 ++ RXDMA_PSR_MIN_DES_t psr_min_des; // 0x2038 ++ u32 fbr0_base_lo; // 0x203C ++ u32 fbr0_base_hi; // 0x2040 ++ RXDMA_FBR_NUM_DES_t fbr0_num_des; // 0x2044 ++ DMA10W_t fbr0_avail_offset; // 0x2048 ++ DMA10W_t fbr0_full_offset; // 0x204C ++ RXDMA_FBC_RD_INDEX_t fbr0_rd_index; // 0x2050 ++ RXDMA_FBR_MIN_DES_t fbr0_min_des; // 0x2054 ++ u32 fbr1_base_lo; // 0x2058 ++ u32 fbr1_base_hi; // 0x205C ++ RXDMA_FBR_NUM_DES_t fbr1_num_des; // 0x2060 ++ DMA10W_t fbr1_avail_offset; // 0x2064 ++ DMA10W_t fbr1_full_offset; // 0x2068 ++ RXDMA_FBC_RD_INDEX_t fbr1_rd_index; // 0x206C ++ RXDMA_FBR_MIN_DES_t fbr1_min_des; // 0x2070 ++} RXDMA_t, *PRXDMA_t; ++ ++/* END OF RXDMA REGISTER ADDRESS MAP */ ++ ++ ++/* START OF TXMAC REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for control reg in txmac address map ++ * located at address 0x3000 ++ */ ++typedef union _TXMAC_CTL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:24; // bits 8-31 ++ u32 cklseg_diable:1; // bit 7 ++ u32 ckbcnt_disable:1; // bit 6 ++ u32 cksegnum:1; // bit 5 ++ u32 async_disable:1; // bit 4 ++ u32 fc_disable:1; // bit 3 ++ u32 mcif_disable:1; // bit 2 ++ u32 mif_disable:1; // bit 1 ++ u32 txmac_en:1; // bit 0 ++#else ++ u32 txmac_en:1; // bit 0 ++ u32 mif_disable:1; // bit 1 mac interface ++ u32 mcif_disable:1; // bit 2 mem. contr. interface ++ u32 fc_disable:1; // bit 3 ++ u32 async_disable:1; // bit 4 ++ u32 cksegnum:1; // bit 5 ++ u32 ckbcnt_disable:1; // bit 6 ++ u32 cklseg_diable:1; // bit 7 ++ u32 unused:24; // bits 8-31 ++#endif ++ } bits; ++} TXMAC_CTL_t, *PTXMAC_CTL_t; ++ ++/* ++ * structure for shadow pointer reg in txmac address map ++ * located at address 0x3004 ++ */ ++typedef union _TXMAC_SHADOW_PTR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved2:5; // bits 27-31 ++ u32 txq_rd_ptr:11; // bits 16-26 ++ u32 reserved:5; // bits 11-15 ++ u32 txq_wr_ptr:11; // bits 0-10 ++#else ++ u32 txq_wr_ptr:11; // bits 0-10 ++ u32 reserved:5; // bits 11-15 ++ u32 txq_rd_ptr:11; // bits 16-26 ++ u32 reserved2:5; // bits 27-31 ++#endif ++ } bits; ++} TXMAC_SHADOW_PTR_t, *PTXMAC_SHADOW_PTR_t; ++ ++/* ++ * structure for error count reg in txmac address map ++ * located at address 0x3008 ++ */ ++typedef union _TXMAC_ERR_CNT_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:20; // bits 12-31 ++ u32 reserved:4; // bits 8-11 ++ u32 txq_underrun:4; // bits 4-7 ++ u32 fifo_underrun:4; // bits 0-3 ++#else ++ u32 fifo_underrun:4; // bits 0-3 ++ u32 txq_underrun:4; // bits 4-7 ++ u32 reserved:4; // bits 8-11 ++ u32 unused:20; // bits 12-31 ++#endif ++ } bits; ++} TXMAC_ERR_CNT_t, *PTXMAC_ERR_CNT_t; ++ ++/* ++ * structure for max fill reg in txmac address map ++ * located at address 0x300C ++ */ ++typedef union _TXMAC_MAX_FILL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:20; // bits 12-31 ++ u32 max_fill:12; // bits 0-11 ++#else ++ u32 max_fill:12; // bits 0-11 ++ u32 unused:20; // bits 12-31 ++#endif ++ } bits; ++} TXMAC_MAX_FILL_t, *PTXMAC_MAX_FILL_t; ++ ++/* ++ * structure for cf parameter reg in txmac address map ++ * located at address 0x3010 ++ */ ++typedef union _TXMAC_CF_PARAM_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 cfep:16; // bits 16-31 ++ u32 cfpt:16; // bits 0-15 ++#else ++ u32 cfpt:16; // bits 0-15 ++ u32 cfep:16; // bits 16-31 ++#endif ++ } bits; ++} TXMAC_CF_PARAM_t, *PTXMAC_CF_PARAM_t; ++ ++/* ++ * structure for tx test reg in txmac address map ++ * located at address 0x3014 ++ */ ++typedef union _TXMAC_TXTEST_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused2:15; // bits 17-31 ++ u32 reserved1:1; // bit 16 ++ u32 txtest_en:1; // bit 15 ++ u32 unused1:4; // bits 11-14 ++ u32 txqtest_ptr:11; // bits 0-11 ++#else ++ u32 txqtest_ptr:11; // bits 0-10 ++ u32 unused1:4; // bits 11-14 ++ u32 txtest_en:1; // bit 15 ++ u32 reserved1:1; // bit 16 ++ u32 unused2:15; // bits 17-31 ++#endif ++ } bits; ++} TXMAC_TXTEST_t, *PTXMAC_TXTEST_t; ++ ++/* ++ * structure for error reg in txmac address map ++ * located at address 0x3018 ++ */ ++typedef union _TXMAC_ERR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused2:23; // bits 9-31 ++ u32 fifo_underrun:1; // bit 8 ++ u32 unused1:2; // bits 6-7 ++ u32 ctrl2_err:1; // bit 5 ++ u32 txq_underrun:1; // bit 4 ++ u32 bcnt_err:1; // bit 3 ++ u32 lseg_err:1; // bit 2 ++ u32 segnum_err:1; // bit 1 ++ u32 seg0_err:1; // bit 0 ++#else ++ u32 seg0_err:1; // bit 0 ++ u32 segnum_err:1; // bit 1 ++ u32 lseg_err:1; // bit 2 ++ u32 bcnt_err:1; // bit 3 ++ u32 txq_underrun:1; // bit 4 ++ u32 ctrl2_err:1; // bit 5 ++ u32 unused1:2; // bits 6-7 ++ u32 fifo_underrun:1; // bit 8 ++ u32 unused2:23; // bits 9-31 ++#endif ++ } bits; ++} TXMAC_ERR_t, *PTXMAC_ERR_t; ++ ++/* ++ * structure for error interrupt reg in txmac address map ++ * located at address 0x301C ++ */ ++typedef union _TXMAC_ERR_INT_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused2:23; // bits 9-31 ++ u32 fifo_underrun:1; // bit 8 ++ u32 unused1:2; // bits 6-7 ++ u32 ctrl2_err:1; // bit 5 ++ u32 txq_underrun:1; // bit 4 ++ u32 bcnt_err:1; // bit 3 ++ u32 lseg_err:1; // bit 2 ++ u32 segnum_err:1; // bit 1 ++ u32 seg0_err:1; // bit 0 ++#else ++ u32 seg0_err:1; // bit 0 ++ u32 segnum_err:1; // bit 1 ++ u32 lseg_err:1; // bit 2 ++ u32 bcnt_err:1; // bit 3 ++ u32 txq_underrun:1; // bit 4 ++ u32 ctrl2_err:1; // bit 5 ++ u32 unused1:2; // bits 6-7 ++ u32 fifo_underrun:1; // bit 8 ++ u32 unused2:23; // bits 9-31 ++#endif ++ } bits; ++} TXMAC_ERR_INT_t, *PTXMAC_ERR_INT_t; ++ ++/* ++ * structure for error interrupt reg in txmac address map ++ * located at address 0x3020 ++ */ ++typedef union _TXMAC_CP_CTRL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:30; // bits 2-31 ++ u32 bp_req:1; // bit 1 ++ u32 bp_xonxoff:1; // bit 0 ++#else ++ u32 bp_xonxoff:1; // bit 0 ++ u32 bp_req:1; // bit 1 ++ u32 unused:30; // bits 2-31 ++#endif ++ } bits; ++} TXMAC_BP_CTRL_t, *PTXMAC_BP_CTRL_t; ++ ++/* ++ * Tx MAC Module of JAGCore Address Mapping ++ */ ++typedef struct _TXMAC_t { // Location: ++ TXMAC_CTL_t ctl; // 0x3000 ++ TXMAC_SHADOW_PTR_t shadow_ptr; // 0x3004 ++ TXMAC_ERR_CNT_t err_cnt; // 0x3008 ++ TXMAC_MAX_FILL_t max_fill; // 0x300C ++ TXMAC_CF_PARAM_t cf_param; // 0x3010 ++ TXMAC_TXTEST_t tx_test; // 0x3014 ++ TXMAC_ERR_t err; // 0x3018 ++ TXMAC_ERR_INT_t err_int; // 0x301C ++ TXMAC_BP_CTRL_t bp_ctrl; // 0x3020 ++} TXMAC_t, *PTXMAC_t; ++ ++/* END OF TXMAC REGISTER ADDRESS MAP */ ++ ++/* START OF RXMAC REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for rxmac control reg in rxmac address map ++ * located at address 0x4000 ++ */ ++typedef union _RXMAC_CTRL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:25; // bits 7-31 ++ u32 rxmac_int_disable:1; // bit 6 ++ u32 async_disable:1; // bit 5 ++ u32 mif_disable:1; // bit 4 ++ u32 wol_disable:1; // bit 3 ++ u32 pkt_filter_disable:1; // bit 2 ++ u32 mcif_disable:1; // bit 1 ++ u32 rxmac_en:1; // bit 0 ++#else ++ u32 rxmac_en:1; // bit 0 ++ u32 mcif_disable:1; // bit 1 ++ u32 pkt_filter_disable:1; // bit 2 ++ u32 wol_disable:1; // bit 3 ++ u32 mif_disable:1; // bit 4 ++ u32 async_disable:1; // bit 5 ++ u32 rxmac_int_disable:1; // bit 6 ++ u32 reserved:25; // bits 7-31 ++#endif ++ } bits; ++} RXMAC_CTRL_t, *PRXMAC_CTRL_t; ++ ++/* ++ * structure for Wake On Lan Control and CRC 0 reg in rxmac address map ++ * located at address 0x4004 ++ */ ++typedef union _RXMAC_WOL_CTL_CRC0_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 crc0:16; // bits 16-31 ++ u32 reserve:4; // bits 12-15 ++ u32 ignore_pp:1; // bit 11 ++ u32 ignore_mp:1; // bit 10 ++ u32 clr_intr:1; // bit 9 ++ u32 ignore_link_chg:1; // bit 8 ++ u32 ignore_uni:1; // bit 7 ++ u32 ignore_multi:1; // bit 6 ++ u32 ignore_broad:1; // bit 5 ++ u32 valid_crc4:1; // bit 4 ++ u32 valid_crc3:1; // bit 3 ++ u32 valid_crc2:1; // bit 2 ++ u32 valid_crc1:1; // bit 1 ++ u32 valid_crc0:1; // bit 0 ++#else ++ u32 valid_crc0:1; // bit 0 ++ u32 valid_crc1:1; // bit 1 ++ u32 valid_crc2:1; // bit 2 ++ u32 valid_crc3:1; // bit 3 ++ u32 valid_crc4:1; // bit 4 ++ u32 ignore_broad:1; // bit 5 ++ u32 ignore_multi:1; // bit 6 ++ u32 ignore_uni:1; // bit 7 ++ u32 ignore_link_chg:1; // bit 8 ++ u32 clr_intr:1; // bit 9 ++ u32 ignore_mp:1; // bit 10 ++ u32 ignore_pp:1; // bit 11 ++ u32 reserve:4; // bits 12-15 ++ u32 crc0:16; // bits 16-31 ++#endif ++ } bits; ++} RXMAC_WOL_CTL_CRC0_t, *PRXMAC_WOL_CTL_CRC0_t; ++ ++/* ++ * structure for CRC 1 and CRC 2 reg in rxmac address map ++ * located at address 0x4008 ++ */ ++typedef union _RXMAC_WOL_CRC12_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 crc2:16; // bits 16-31 ++ u32 crc1:16; // bits 0-15 ++#else ++ u32 crc1:16; // bits 0-15 ++ u32 crc2:16; // bits 16-31 ++#endif ++ } bits; ++} RXMAC_WOL_CRC12_t, *PRXMAC_WOL_CRC12_t; ++ ++/* ++ * structure for CRC 3 and CRC 4 reg in rxmac address map ++ * located at address 0x400C ++ */ ++typedef union _RXMAC_WOL_CRC34_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 crc4:16; // bits 16-31 ++ u32 crc3:16; // bits 0-15 ++#else ++ u32 crc3:16; // bits 0-15 ++ u32 crc4:16; // bits 16-31 ++#endif ++ } bits; ++} RXMAC_WOL_CRC34_t, *PRXMAC_WOL_CRC34_t; ++ ++/* ++ * structure for Wake On Lan Source Address Lo reg in rxmac address map ++ * located at address 0x4010 ++ */ ++typedef union _RXMAC_WOL_SA_LO_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 sa3:8; // bits 24-31 ++ u32 sa4:8; // bits 16-23 ++ u32 sa5:8; // bits 8-15 ++ u32 sa6:8; // bits 0-7 ++#else ++ u32 sa6:8; // bits 0-7 ++ u32 sa5:8; // bits 8-15 ++ u32 sa4:8; // bits 16-23 ++ u32 sa3:8; // bits 24-31 ++#endif ++ } bits; ++} RXMAC_WOL_SA_LO_t, *PRXMAC_WOL_SA_LO_t; ++ ++/* ++ * structure for Wake On Lan Source Address Hi reg in rxmac address map ++ * located at address 0x4014 ++ */ ++typedef union _RXMAC_WOL_SA_HI_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:16; // bits 16-31 ++ u32 sa1:8; // bits 8-15 ++ u32 sa2:8; // bits 0-7 ++#else ++ u32 sa2:8; // bits 0-7 ++ u32 sa1:8; // bits 8-15 ++ u32 reserved:16; // bits 16-31 ++#endif ++ } bits; ++} RXMAC_WOL_SA_HI_t, *PRXMAC_WOL_SA_HI_t; ++ ++/* ++ * structure for Wake On Lan mask reg in rxmac address map ++ * located at address 0x4018 - 0x4064 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for Unicast Paket Filter Address 1 reg in rxmac address map ++ * located at address 0x4068 ++ */ ++typedef union _RXMAC_UNI_PF_ADDR1_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 addr1_3:8; // bits 24-31 ++ u32 addr1_4:8; // bits 16-23 ++ u32 addr1_5:8; // bits 8-15 ++ u32 addr1_6:8; // bits 0-7 ++#else ++ u32 addr1_6:8; // bits 0-7 ++ u32 addr1_5:8; // bits 8-15 ++ u32 addr1_4:8; // bits 16-23 ++ u32 addr1_3:8; // bits 24-31 ++#endif ++ } bits; ++} RXMAC_UNI_PF_ADDR1_t, *PRXMAC_UNI_PF_ADDR1_t; ++ ++/* ++ * structure for Unicast Paket Filter Address 2 reg in rxmac address map ++ * located at address 0x406C ++ */ ++typedef union _RXMAC_UNI_PF_ADDR2_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 addr2_3:8; // bits 24-31 ++ u32 addr2_4:8; // bits 16-23 ++ u32 addr2_5:8; // bits 8-15 ++ u32 addr2_6:8; // bits 0-7 ++#else ++ u32 addr2_6:8; // bits 0-7 ++ u32 addr2_5:8; // bits 8-15 ++ u32 addr2_4:8; // bits 16-23 ++ u32 addr2_3:8; // bits 24-31 ++#endif ++ } bits; ++} RXMAC_UNI_PF_ADDR2_t, *PRXMAC_UNI_PF_ADDR2_t; ++ ++/* ++ * structure for Unicast Paket Filter Address 1 & 2 reg in rxmac address map ++ * located at address 0x4070 ++ */ ++typedef union _RXMAC_UNI_PF_ADDR3_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 addr2_1:8; // bits 24-31 ++ u32 addr2_2:8; // bits 16-23 ++ u32 addr1_1:8; // bits 8-15 ++ u32 addr1_2:8; // bits 0-7 ++#else ++ u32 addr1_2:8; // bits 0-7 ++ u32 addr1_1:8; // bits 8-15 ++ u32 addr2_2:8; // bits 16-23 ++ u32 addr2_1:8; // bits 24-31 ++#endif ++ } bits; ++} RXMAC_UNI_PF_ADDR3_t, *PRXMAC_UNI_PF_ADDR3_t; ++ ++/* ++ * structure for Multicast Hash reg in rxmac address map ++ * located at address 0x4074 - 0x4080 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for Packet Filter Control reg in rxmac address map ++ * located at address 0x4084 ++ */ ++typedef union _RXMAC_PF_CTRL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused2:9; // bits 23-31 ++ u32 min_pkt_size:7; // bits 16-22 ++ u32 unused1:12; // bits 4-15 ++ u32 filter_frag_en:1; // bit 3 ++ u32 filter_uni_en:1; // bit 2 ++ u32 filter_multi_en:1; // bit 1 ++ u32 filter_broad_en:1; // bit 0 ++#else ++ u32 filter_broad_en:1; // bit 0 ++ u32 filter_multi_en:1; // bit 1 ++ u32 filter_uni_en:1; // bit 2 ++ u32 filter_frag_en:1; // bit 3 ++ u32 unused1:12; // bits 4-15 ++ u32 min_pkt_size:7; // bits 16-22 ++ u32 unused2:9; // bits 23-31 ++#endif ++ } bits; ++} RXMAC_PF_CTRL_t, *PRXMAC_PF_CTRL_t; ++ ++/* ++ * structure for Memory Controller Interface Control Max Segment reg in rxmac ++ * address map. Located at address 0x4088 ++ */ ++typedef union _RXMAC_MCIF_CTRL_MAX_SEG_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:22; // bits 10-31 ++ u32 max_size:8; // bits 2-9 ++ u32 fc_en:1; // bit 1 ++ u32 seg_en:1; // bit 0 ++#else ++ u32 seg_en:1; // bit 0 ++ u32 fc_en:1; // bit 1 ++ u32 max_size:8; // bits 2-9 ++ u32 reserved:22; // bits 10-31 ++#endif ++ } bits; ++} RXMAC_MCIF_CTRL_MAX_SEG_t, *PRXMAC_MCIF_CTRL_MAX_SEG_t; ++ ++/* ++ * structure for Memory Controller Interface Water Mark reg in rxmac address ++ * map. Located at address 0x408C ++ */ ++typedef union _RXMAC_MCIF_WATER_MARK_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved2:6; // bits 26-31 ++ u32 mark_hi:10; // bits 16-25 ++ u32 reserved1:6; // bits 10-15 ++ u32 mark_lo:10; // bits 0-9 ++#else ++ u32 mark_lo:10; // bits 0-9 ++ u32 reserved1:6; // bits 10-15 ++ u32 mark_hi:10; // bits 16-25 ++ u32 reserved2:6; // bits 26-31 ++#endif ++ } bits; ++} RXMAC_MCIF_WATER_MARK_t, *PRXMAC_MCIF_WATER_MARK_t; ++ ++/* ++ * structure for Rx Queue Dialog reg in rxmac address map. ++ * located at address 0x4090 ++ */ ++typedef union _RXMAC_RXQ_DIAG_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved2:6; // bits 26-31 ++ u32 rd_ptr:10; // bits 16-25 ++ u32 reserved1:6; // bits 10-15 ++ u32 wr_ptr:10; // bits 0-9 ++#else ++ u32 wr_ptr:10; // bits 0-9 ++ u32 reserved1:6; // bits 10-15 ++ u32 rd_ptr:10; // bits 16-25 ++ u32 reserved2:6; // bits 26-31 ++#endif ++ } bits; ++} RXMAC_RXQ_DIAG_t, *PRXMAC_RXQ_DIAG_t; ++ ++/* ++ * structure for space availiable reg in rxmac address map. ++ * located at address 0x4094 ++ */ ++typedef union _RXMAC_SPACE_AVAIL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved2:15; // bits 17-31 ++ u32 space_avail_en:1; // bit 16 ++ u32 reserved1:6; // bits 10-15 ++ u32 space_avail:10; // bits 0-9 ++#else ++ u32 space_avail:10; // bits 0-9 ++ u32 reserved1:6; // bits 10-15 ++ u32 space_avail_en:1; // bit 16 ++ u32 reserved2:15; // bits 17-31 ++#endif ++ } bits; ++} RXMAC_SPACE_AVAIL_t, *PRXMAC_SPACE_AVAIL_t; ++ ++/* ++ * structure for management interface reg in rxmac address map. ++ * located at address 0x4098 ++ */ ++typedef union _RXMAC_MIF_CTL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserve:14; // bits 18-31 ++ u32 drop_pkt_en:1; // bit 17 ++ u32 drop_pkt_mask:17; // bits 0-16 ++#else ++ u32 drop_pkt_mask:17; // bits 0-16 ++ u32 drop_pkt_en:1; // bit 17 ++ u32 reserve:14; // bits 18-31 ++#endif ++ } bits; ++} RXMAC_MIF_CTL_t, *PRXMAC_MIF_CTL_t; ++ ++/* ++ * structure for Error reg in rxmac address map. ++ * located at address 0x409C ++ */ ++typedef union _RXMAC_ERROR_REG_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserve:28; // bits 4-31 ++ u32 mif:1; // bit 3 ++ u32 async:1; // bit 2 ++ u32 pkt_filter:1; // bit 1 ++ u32 mcif:1; // bit 0 ++#else ++ u32 mcif:1; // bit 0 ++ u32 pkt_filter:1; // bit 1 ++ u32 async:1; // bit 2 ++ u32 mif:1; // bit 3 ++ u32 reserve:28; // bits 4-31 ++#endif ++ } bits; ++} RXMAC_ERROR_REG_t, *PRXMAC_ERROR_REG_t; ++ ++/* ++ * Rx MAC Module of JAGCore Address Mapping ++ */ ++typedef struct _RXMAC_t { // Location: ++ RXMAC_CTRL_t ctrl; // 0x4000 ++ RXMAC_WOL_CTL_CRC0_t crc0; // 0x4004 ++ RXMAC_WOL_CRC12_t crc12; // 0x4008 ++ RXMAC_WOL_CRC34_t crc34; // 0x400C ++ RXMAC_WOL_SA_LO_t sa_lo; // 0x4010 ++ RXMAC_WOL_SA_HI_t sa_hi; // 0x4014 ++ u32 mask0_word0; // 0x4018 ++ u32 mask0_word1; // 0x401C ++ u32 mask0_word2; // 0x4020 ++ u32 mask0_word3; // 0x4024 ++ u32 mask1_word0; // 0x4028 ++ u32 mask1_word1; // 0x402C ++ u32 mask1_word2; // 0x4030 ++ u32 mask1_word3; // 0x4034 ++ u32 mask2_word0; // 0x4038 ++ u32 mask2_word1; // 0x403C ++ u32 mask2_word2; // 0x4040 ++ u32 mask2_word3; // 0x4044 ++ u32 mask3_word0; // 0x4048 ++ u32 mask3_word1; // 0x404C ++ u32 mask3_word2; // 0x4050 ++ u32 mask3_word3; // 0x4054 ++ u32 mask4_word0; // 0x4058 ++ u32 mask4_word1; // 0x405C ++ u32 mask4_word2; // 0x4060 ++ u32 mask4_word3; // 0x4064 ++ RXMAC_UNI_PF_ADDR1_t uni_pf_addr1; // 0x4068 ++ RXMAC_UNI_PF_ADDR2_t uni_pf_addr2; // 0x406C ++ RXMAC_UNI_PF_ADDR3_t uni_pf_addr3; // 0x4070 ++ u32 multi_hash1; // 0x4074 ++ u32 multi_hash2; // 0x4078 ++ u32 multi_hash3; // 0x407C ++ u32 multi_hash4; // 0x4080 ++ RXMAC_PF_CTRL_t pf_ctrl; // 0x4084 ++ RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; // 0x4088 ++ RXMAC_MCIF_WATER_MARK_t mcif_water_mark; // 0x408C ++ RXMAC_RXQ_DIAG_t rxq_diag; // 0x4090 ++ RXMAC_SPACE_AVAIL_t space_avail; // 0x4094 ++ ++ RXMAC_MIF_CTL_t mif_ctrl; // 0x4098 ++ RXMAC_ERROR_REG_t err_reg; // 0x409C ++} RXMAC_t, *PRXMAC_t; ++ ++/* END OF TXMAC REGISTER ADDRESS MAP */ ++ ++ ++/* START OF MAC REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for configuration #1 reg in mac address map. ++ * located at address 0x5000 ++ */ ++typedef union _MAC_CFG1_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 soft_reset:1; // bit 31 ++ u32 sim_reset:1; // bit 30 ++ u32 reserved3:10; // bits 20-29 ++ u32 reset_rx_mc:1; // bit 19 ++ u32 reset_tx_mc:1; // bit 18 ++ u32 reset_rx_fun:1; // bit 17 ++ u32 reset_tx_fun:1; // bit 16 ++ u32 reserved2:7; // bits 9-15 ++ u32 loop_back:1; // bit 8 ++ u32 reserved1:2; // bits 6-7 ++ u32 rx_flow:1; // bit 5 ++ u32 tx_flow:1; // bit 4 ++ u32 syncd_rx_en:1; // bit 3 ++ u32 rx_enable:1; // bit 2 ++ u32 syncd_tx_en:1; // bit 1 ++ u32 tx_enable:1; // bit 0 ++#else ++ u32 tx_enable:1; // bit 0 ++ u32 syncd_tx_en:1; // bit 1 ++ u32 rx_enable:1; // bit 2 ++ u32 syncd_rx_en:1; // bit 3 ++ u32 tx_flow:1; // bit 4 ++ u32 rx_flow:1; // bit 5 ++ u32 reserved1:2; // bits 6-7 ++ u32 loop_back:1; // bit 8 ++ u32 reserved2:7; // bits 9-15 ++ u32 reset_tx_fun:1; // bit 16 ++ u32 reset_rx_fun:1; // bit 17 ++ u32 reset_tx_mc:1; // bit 18 ++ u32 reset_rx_mc:1; // bit 19 ++ u32 reserved3:10; // bits 20-29 ++ u32 sim_reset:1; // bit 30 ++ u32 soft_reset:1; // bit 31 ++#endif ++ } bits; ++} MAC_CFG1_t, *PMAC_CFG1_t; ++ ++/* ++ * structure for configuration #2 reg in mac address map. ++ * located at address 0x5004 ++ */ ++typedef union _MAC_CFG2_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved3:16; // bits 16-31 ++ u32 preamble_len:4; // bits 12-15 ++ u32 reserved2:2; // bits 10-11 ++ u32 if_mode:2; // bits 8-9 ++ u32 reserved1:2; // bits 6-7 ++ u32 huge_frame:1; // bit 5 ++ u32 len_check:1; // bit 4 ++ u32 undefined:1; // bit 3 ++ u32 pad_crc:1; // bit 2 ++ u32 crc_enable:1; // bit 1 ++ u32 full_duplex:1; // bit 0 ++#else ++ u32 full_duplex:1; // bit 0 ++ u32 crc_enable:1; // bit 1 ++ u32 pad_crc:1; // bit 2 ++ u32 undefined:1; // bit 3 ++ u32 len_check:1; // bit 4 ++ u32 huge_frame:1; // bit 5 ++ u32 reserved1:2; // bits 6-7 ++ u32 if_mode:2; // bits 8-9 ++ u32 reserved2:2; // bits 10-11 ++ u32 preamble_len:4; // bits 12-15 ++ u32 reserved3:16; // bits 16-31 ++#endif ++ } bits; ++} MAC_CFG2_t, *PMAC_CFG2_t; ++ ++/* ++ * structure for Interpacket gap reg in mac address map. ++ * located at address 0x5008 ++ */ ++typedef union _MAC_IPG_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:1; // bit 31 ++ u32 non_B2B_ipg_1:7; // bits 24-30 ++ u32 undefined2:1; // bit 23 ++ u32 non_B2B_ipg_2:7; // bits 16-22 ++ u32 min_ifg_enforce:8; // bits 8-15 ++ u32 undefined1:1; // bit 7 ++ u32 B2B_ipg:7; // bits 0-6 ++#else ++ u32 B2B_ipg:7; // bits 0-6 ++ u32 undefined1:1; // bit 7 ++ u32 min_ifg_enforce:8; // bits 8-15 ++ u32 non_B2B_ipg_2:7; // bits 16-22 ++ u32 undefined2:1; // bit 23 ++ u32 non_B2B_ipg_1:7; // bits 24-30 ++ u32 reserved:1; // bit 31 ++#endif ++ } bits; ++} MAC_IPG_t, *PMAC_IPG_t; ++ ++/* ++ * structure for half duplex reg in mac address map. ++ * located at address 0x500C ++ */ ++typedef union _MAC_HFDP_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved2:8; // bits 24-31 ++ u32 alt_beb_trunc:4; // bits 23-20 ++ u32 alt_beb_enable:1; // bit 19 ++ u32 bp_no_backoff:1; // bit 18 ++ u32 no_backoff:1; // bit 17 ++ u32 excess_defer:1; // bit 16 ++ u32 rexmit_max:4; // bits 12-15 ++ u32 reserved1:2; // bits 10-11 ++ u32 coll_window:10; // bits 0-9 ++#else ++ u32 coll_window:10; // bits 0-9 ++ u32 reserved1:2; // bits 10-11 ++ u32 rexmit_max:4; // bits 12-15 ++ u32 excess_defer:1; // bit 16 ++ u32 no_backoff:1; // bit 17 ++ u32 bp_no_backoff:1; // bit 18 ++ u32 alt_beb_enable:1; // bit 19 ++ u32 alt_beb_trunc:4; // bits 23-20 ++ u32 reserved2:8; // bits 24-31 ++#endif ++ } bits; ++} MAC_HFDP_t, *PMAC_HFDP_t; ++ ++/* ++ * structure for Maximum Frame Length reg in mac address map. ++ * located at address 0x5010 ++ */ ++typedef union _MAC_MAX_FM_LEN_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:16; // bits 16-31 ++ u32 max_len:16; // bits 0-15 ++#else ++ u32 max_len:16; // bits 0-15 ++ u32 reserved:16; // bits 16-31 ++#endif ++ } bits; ++} MAC_MAX_FM_LEN_t, *PMAC_MAX_FM_LEN_t; ++ ++/* ++ * structure for Reserve 1 reg in mac address map. ++ * located at address 0x5014 - 0x5018 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * structure for Test reg in mac address map. ++ * located at address 0x501C ++ */ ++typedef union _MAC_TEST_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:29; // bits 3-31 ++ u32 mac_test:3; // bits 0-2 ++#else ++ u32 mac_test:3; // bits 0-2 ++ u32 unused:29; // bits 3-31 ++#endif ++ } bits; ++} MAC_TEST_t, *PMAC_TEST_t; ++ ++/* ++ * structure for MII Management Configuration reg in mac address map. ++ * located at address 0x5020 ++ */ ++typedef union _MII_MGMT_CFG_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reset_mii_mgmt:1; // bit 31 ++ u32 reserved:25; // bits 6-30 ++ u32 scan_auto_incremt:1; // bit 5 ++ u32 preamble_suppress:1; // bit 4 ++ u32 undefined:1; // bit 3 ++ u32 mgmt_clk_reset:3; // bits 0-2 ++#else ++ u32 mgmt_clk_reset:3; // bits 0-2 ++ u32 undefined:1; // bit 3 ++ u32 preamble_suppress:1; // bit 4 ++ u32 scan_auto_incremt:1; // bit 5 ++ u32 reserved:25; // bits 6-30 ++ u32 reset_mii_mgmt:1; // bit 31 ++#endif ++ } bits; ++} MII_MGMT_CFG_t, *PMII_MGMT_CFG_t; ++ ++/* ++ * structure for MII Management Command reg in mac address map. ++ * located at address 0x5024 ++ */ ++typedef union _MII_MGMT_CMD_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:30; // bits 2-31 ++ u32 scan_cycle:1; // bit 1 ++ u32 read_cycle:1; // bit 0 ++#else ++ u32 read_cycle:1; // bit 0 ++ u32 scan_cycle:1; // bit 1 ++ u32 reserved:30; // bits 2-31 ++#endif ++ } bits; ++} MII_MGMT_CMD_t, *PMII_MGMT_CMD_t; ++ ++/* ++ * structure for MII Management Address reg in mac address map. ++ * located at address 0x5028 ++ */ ++typedef union _MII_MGMT_ADDR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved2:19; // bit 13-31 ++ u32 phy_addr:5; // bits 8-12 ++ u32 reserved1:3; // bits 5-7 ++ u32 reg_addr:5; // bits 0-4 ++#else ++ u32 reg_addr:5; // bits 0-4 ++ u32 reserved1:3; // bits 5-7 ++ u32 phy_addr:5; // bits 8-12 ++ u32 reserved2:19; // bit 13-31 ++#endif ++ } bits; ++} MII_MGMT_ADDR_t, *PMII_MGMT_ADDR_t; ++ ++/* ++ * structure for MII Management Control reg in mac address map. ++ * located at address 0x502C ++ */ ++typedef union _MII_MGMT_CTRL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:16; // bits 16-31 ++ u32 phy_ctrl:16; // bits 0-15 ++#else ++ u32 phy_ctrl:16; // bits 0-15 ++ u32 reserved:16; // bits 16-31 ++#endif ++ } bits; ++} MII_MGMT_CTRL_t, *PMII_MGMT_CTRL_t; ++ ++/* ++ * structure for MII Management Status reg in mac address map. ++ * located at address 0x5030 ++ */ ++typedef union _MII_MGMT_STAT_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:16; // bits 16-31 ++ u32 phy_stat:16; // bits 0-15 ++#else ++ u32 phy_stat:16; // bits 0-15 ++ u32 reserved:16; // bits 16-31 ++#endif ++ } bits; ++} MII_MGMT_STAT_t, *PMII_MGMT_STAT_t; ++ ++/* ++ * structure for MII Management Indicators reg in mac address map. ++ * located at address 0x5034 ++ */ ++typedef union _MII_MGMT_INDICATOR_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:29; // bits 3-31 ++ u32 not_valid:1; // bit 2 ++ u32 scanning:1; // bit 1 ++ u32 busy:1; // bit 0 ++#else ++ u32 busy:1; // bit 0 ++ u32 scanning:1; // bit 1 ++ u32 not_valid:1; // bit 2 ++ u32 reserved:29; // bits 3-31 ++#endif ++ } bits; ++} MII_MGMT_INDICATOR_t, *PMII_MGMT_INDICATOR_t; ++ ++/* ++ * structure for Interface Control reg in mac address map. ++ * located at address 0x5038 ++ */ ++typedef union _MAC_IF_CTRL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reset_if_module:1; // bit 31 ++ u32 reserved4:3; // bit 28-30 ++ u32 tbi_mode:1; // bit 27 ++ u32 ghd_mode:1; // bit 26 ++ u32 lhd_mode:1; // bit 25 ++ u32 phy_mode:1; // bit 24 ++ u32 reset_per_mii:1; // bit 23 ++ u32 reserved3:6; // bits 17-22 ++ u32 speed:1; // bit 16 ++ u32 reset_pe100x:1; // bit 15 ++ u32 reserved2:4; // bits 11-14 ++ u32 force_quiet:1; // bit 10 ++ u32 no_cipher:1; // bit 9 ++ u32 disable_link_fail:1; // bit 8 ++ u32 reset_gpsi:1; // bit 7 ++ u32 reserved1:6; // bits 1-6 ++ u32 enab_jab_protect:1; // bit 0 ++#else ++ u32 enab_jab_protect:1; // bit 0 ++ u32 reserved1:6; // bits 1-6 ++ u32 reset_gpsi:1; // bit 7 ++ u32 disable_link_fail:1; // bit 8 ++ u32 no_cipher:1; // bit 9 ++ u32 force_quiet:1; // bit 10 ++ u32 reserved2:4; // bits 11-14 ++ u32 reset_pe100x:1; // bit 15 ++ u32 speed:1; // bit 16 ++ u32 reserved3:6; // bits 17-22 ++ u32 reset_per_mii:1; // bit 23 ++ u32 phy_mode:1; // bit 24 ++ u32 lhd_mode:1; // bit 25 ++ u32 ghd_mode:1; // bit 26 ++ u32 tbi_mode:1; // bit 27 ++ u32 reserved4:3; // bit 28-30 ++ u32 reset_if_module:1; // bit 31 ++#endif ++ } bits; ++} MAC_IF_CTRL_t, *PMAC_IF_CTRL_t; ++ ++/* ++ * structure for Interface Status reg in mac address map. ++ * located at address 0x503C ++ */ ++typedef union _MAC_IF_STAT_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:22; // bits 10-31 ++ u32 excess_defer:1; // bit 9 ++ u32 clash:1; // bit 8 ++ u32 phy_jabber:1; // bit 7 ++ u32 phy_link_ok:1; // bit 6 ++ u32 phy_full_duplex:1; // bit 5 ++ u32 phy_speed:1; // bit 4 ++ u32 pe100x_link_fail:1; // bit 3 ++ u32 pe10t_loss_carrie:1; // bit 2 ++ u32 pe10t_sqe_error:1; // bit 1 ++ u32 pe10t_jabber:1; // bit 0 ++#else ++ u32 pe10t_jabber:1; // bit 0 ++ u32 pe10t_sqe_error:1; // bit 1 ++ u32 pe10t_loss_carrie:1; // bit 2 ++ u32 pe100x_link_fail:1; // bit 3 ++ u32 phy_speed:1; // bit 4 ++ u32 phy_full_duplex:1; // bit 5 ++ u32 phy_link_ok:1; // bit 6 ++ u32 phy_jabber:1; // bit 7 ++ u32 clash:1; // bit 8 ++ u32 excess_defer:1; // bit 9 ++ u32 reserved:22; // bits 10-31 ++#endif ++ } bits; ++} MAC_IF_STAT_t, *PMAC_IF_STAT_t; ++ ++/* ++ * structure for Mac Station Address, Part 1 reg in mac address map. ++ * located at address 0x5040 ++ */ ++typedef union _MAC_STATION_ADDR1_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 Octet6:8; // bits 24-31 ++ u32 Octet5:8; // bits 16-23 ++ u32 Octet4:8; // bits 8-15 ++ u32 Octet3:8; // bits 0-7 ++#else ++ u32 Octet3:8; // bits 0-7 ++ u32 Octet4:8; // bits 8-15 ++ u32 Octet5:8; // bits 16-23 ++ u32 Octet6:8; // bits 24-31 ++#endif ++ } bits; ++} MAC_STATION_ADDR1_t, *PMAC_STATION_ADDR1_t; ++ ++/* ++ * structure for Mac Station Address, Part 2 reg in mac address map. ++ * located at address 0x5044 ++ */ ++typedef union _MAC_STATION_ADDR2_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 Octet2:8; // bits 24-31 ++ u32 Octet1:8; // bits 16-23 ++ u32 reserved:16; // bits 0-15 ++#else ++ u32 reserved:16; // bit 0-15 ++ u32 Octet1:8; // bits 16-23 ++ u32 Octet2:8; // bits 24-31 ++#endif ++ } bits; ++} MAC_STATION_ADDR2_t, *PMAC_STATION_ADDR2_t; ++ ++/* ++ * MAC Module of JAGCore Address Mapping ++ */ ++typedef struct _MAC_t { // Location: ++ MAC_CFG1_t cfg1; // 0x5000 ++ MAC_CFG2_t cfg2; // 0x5004 ++ MAC_IPG_t ipg; // 0x5008 ++ MAC_HFDP_t hfdp; // 0x500C ++ MAC_MAX_FM_LEN_t max_fm_len; // 0x5010 ++ u32 rsv1; // 0x5014 ++ u32 rsv2; // 0x5018 ++ MAC_TEST_t mac_test; // 0x501C ++ MII_MGMT_CFG_t mii_mgmt_cfg; // 0x5020 ++ MII_MGMT_CMD_t mii_mgmt_cmd; // 0x5024 ++ MII_MGMT_ADDR_t mii_mgmt_addr; // 0x5028 ++ MII_MGMT_CTRL_t mii_mgmt_ctrl; // 0x502C ++ MII_MGMT_STAT_t mii_mgmt_stat; // 0x5030 ++ MII_MGMT_INDICATOR_t mii_mgmt_indicator; // 0x5034 ++ MAC_IF_CTRL_t if_ctrl; // 0x5038 ++ MAC_IF_STAT_t if_stat; // 0x503C ++ MAC_STATION_ADDR1_t station_addr_1; // 0x5040 ++ MAC_STATION_ADDR2_t station_addr_2; // 0x5044 ++} MAC_t, *PMAC_t; ++ ++/* END OF MAC REGISTER ADDRESS MAP */ ++ ++/* START OF MAC STAT REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for Carry Register One and it's Mask Register reg located in mac ++ * stat address map address 0x6130 and 0x6138. ++ */ ++typedef union _MAC_STAT_REG_1_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 tr64:1; // bit 31 ++ u32 tr127:1; // bit 30 ++ u32 tr255:1; // bit 29 ++ u32 tr511:1; // bit 28 ++ u32 tr1k:1; // bit 27 ++ u32 trmax:1; // bit 26 ++ u32 trmgv:1; // bit 25 ++ u32 unused:8; // bits 17-24 ++ u32 rbyt:1; // bit 16 ++ u32 rpkt:1; // bit 15 ++ u32 rfcs:1; // bit 14 ++ u32 rmca:1; // bit 13 ++ u32 rbca:1; // bit 12 ++ u32 rxcf:1; // bit 11 ++ u32 rxpf:1; // bit 10 ++ u32 rxuo:1; // bit 9 ++ u32 raln:1; // bit 8 ++ u32 rflr:1; // bit 7 ++ u32 rcde:1; // bit 6 ++ u32 rcse:1; // bit 5 ++ u32 rund:1; // bit 4 ++ u32 rovr:1; // bit 3 ++ u32 rfrg:1; // bit 2 ++ u32 rjbr:1; // bit 1 ++ u32 rdrp:1; // bit 0 ++#else ++ u32 rdrp:1; // bit 0 ++ u32 rjbr:1; // bit 1 ++ u32 rfrg:1; // bit 2 ++ u32 rovr:1; // bit 3 ++ u32 rund:1; // bit 4 ++ u32 rcse:1; // bit 5 ++ u32 rcde:1; // bit 6 ++ u32 rflr:1; // bit 7 ++ u32 raln:1; // bit 8 ++ u32 rxuo:1; // bit 9 ++ u32 rxpf:1; // bit 10 ++ u32 rxcf:1; // bit 11 ++ u32 rbca:1; // bit 12 ++ u32 rmca:1; // bit 13 ++ u32 rfcs:1; // bit 14 ++ u32 rpkt:1; // bit 15 ++ u32 rbyt:1; // bit 16 ++ u32 unused:8; // bits 17-24 ++ u32 trmgv:1; // bit 25 ++ u32 trmax:1; // bit 26 ++ u32 tr1k:1; // bit 27 ++ u32 tr511:1; // bit 28 ++ u32 tr255:1; // bit 29 ++ u32 tr127:1; // bit 30 ++ u32 tr64:1; // bit 31 ++#endif ++ } bits; ++} MAC_STAT_REG_1_t, *PMAC_STAT_REG_1_t; ++ ++/* ++ * structure for Carry Register Two Mask Register reg in mac stat address map. ++ * located at address 0x613C ++ */ ++typedef union _MAC_STAT_REG_2_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:12; // bit 20-31 ++ u32 tjbr:1; // bit 19 ++ u32 tfcs:1; // bit 18 ++ u32 txcf:1; // bit 17 ++ u32 tovr:1; // bit 16 ++ u32 tund:1; // bit 15 ++ u32 tfrg:1; // bit 14 ++ u32 tbyt:1; // bit 13 ++ u32 tpkt:1; // bit 12 ++ u32 tmca:1; // bit 11 ++ u32 tbca:1; // bit 10 ++ u32 txpf:1; // bit 9 ++ u32 tdfr:1; // bit 8 ++ u32 tedf:1; // bit 7 ++ u32 tscl:1; // bit 6 ++ u32 tmcl:1; // bit 5 ++ u32 tlcl:1; // bit 4 ++ u32 txcl:1; // bit 3 ++ u32 tncl:1; // bit 2 ++ u32 tpfh:1; // bit 1 ++ u32 tdrp:1; // bit 0 ++#else ++ u32 tdrp:1; // bit 0 ++ u32 tpfh:1; // bit 1 ++ u32 tncl:1; // bit 2 ++ u32 txcl:1; // bit 3 ++ u32 tlcl:1; // bit 4 ++ u32 tmcl:1; // bit 5 ++ u32 tscl:1; // bit 6 ++ u32 tedf:1; // bit 7 ++ u32 tdfr:1; // bit 8 ++ u32 txpf:1; // bit 9 ++ u32 tbca:1; // bit 10 ++ u32 tmca:1; // bit 11 ++ u32 tpkt:1; // bit 12 ++ u32 tbyt:1; // bit 13 ++ u32 tfrg:1; // bit 14 ++ u32 tund:1; // bit 15 ++ u32 tovr:1; // bit 16 ++ u32 txcf:1; // bit 17 ++ u32 tfcs:1; // bit 18 ++ u32 tjbr:1; // bit 19 ++ u32 unused:12; // bit 20-31 ++#endif ++ } bits; ++} MAC_STAT_REG_2_t, *PMAC_STAT_REG_2_t; ++ ++/* ++ * MAC STATS Module of JAGCore Address Mapping ++ */ ++typedef struct _MAC_STAT_t { // Location: ++ u32 pad[32]; // 0x6000 - 607C ++ ++ // Tx/Rx 0-64 Byte Frame Counter ++ u32 TR64; // 0x6080 ++ ++ // Tx/Rx 65-127 Byte Frame Counter ++ u32 TR127; // 0x6084 ++ ++ // Tx/Rx 128-255 Byte Frame Counter ++ u32 TR255; // 0x6088 ++ ++ // Tx/Rx 256-511 Byte Frame Counter ++ u32 TR511; // 0x608C ++ ++ // Tx/Rx 512-1023 Byte Frame Counter ++ u32 TR1K; // 0x6090 ++ ++ // Tx/Rx 1024-1518 Byte Frame Counter ++ u32 TRMax; // 0x6094 ++ ++ // Tx/Rx 1519-1522 Byte Good VLAN Frame Count ++ u32 TRMgv; // 0x6098 ++ ++ // Rx Byte Counter ++ u32 RByt; // 0x609C ++ ++ // Rx Packet Counter ++ u32 RPkt; // 0x60A0 ++ ++ // Rx FCS Error Counter ++ u32 RFcs; // 0x60A4 ++ ++ // Rx Multicast Packet Counter ++ u32 RMca; // 0x60A8 ++ ++ // Rx Broadcast Packet Counter ++ u32 RBca; // 0x60AC ++ ++ // Rx Control Frame Packet Counter ++ u32 RxCf; // 0x60B0 ++ ++ // Rx Pause Frame Packet Counter ++ u32 RxPf; // 0x60B4 ++ ++ // Rx Unknown OP Code Counter ++ u32 RxUo; // 0x60B8 ++ ++ // Rx Alignment Error Counter ++ u32 RAln; // 0x60BC ++ ++ // Rx Frame Length Error Counter ++ u32 RFlr; // 0x60C0 ++ ++ // Rx Code Error Counter ++ u32 RCde; // 0x60C4 ++ ++ // Rx Carrier Sense Error Counter ++ u32 RCse; // 0x60C8 ++ ++ // Rx Undersize Packet Counter ++ u32 RUnd; // 0x60CC ++ ++ // Rx Oversize Packet Counter ++ u32 ROvr; // 0x60D0 ++ ++ // Rx Fragment Counter ++ u32 RFrg; // 0x60D4 ++ ++ // Rx Jabber Counter ++ u32 RJbr; // 0x60D8 ++ ++ // Rx Drop ++ u32 RDrp; // 0x60DC ++ ++ // Tx Byte Counter ++ u32 TByt; // 0x60E0 ++ ++ // Tx Packet Counter ++ u32 TPkt; // 0x60E4 ++ ++ // Tx Multicast Packet Counter ++ u32 TMca; // 0x60E8 ++ ++ // Tx Broadcast Packet Counter ++ u32 TBca; // 0x60EC ++ ++ // Tx Pause Control Frame Counter ++ u32 TxPf; // 0x60F0 ++ ++ // Tx Deferral Packet Counter ++ u32 TDfr; // 0x60F4 ++ ++ // Tx Excessive Deferral Packet Counter ++ u32 TEdf; // 0x60F8 ++ ++ // Tx Single Collision Packet Counter ++ u32 TScl; // 0x60FC ++ ++ // Tx Multiple Collision Packet Counter ++ u32 TMcl; // 0x6100 ++ ++ // Tx Late Collision Packet Counter ++ u32 TLcl; // 0x6104 ++ ++ // Tx Excessive Collision Packet Counter ++ u32 TXcl; // 0x6108 ++ ++ // Tx Total Collision Packet Counter ++ u32 TNcl; // 0x610C ++ ++ // Tx Pause Frame Honored Counter ++ u32 TPfh; // 0x6110 ++ ++ // Tx Drop Frame Counter ++ u32 TDrp; // 0x6114 ++ ++ // Tx Jabber Frame Counter ++ u32 TJbr; // 0x6118 ++ ++ // Tx FCS Error Counter ++ u32 TFcs; // 0x611C ++ ++ // Tx Control Frame Counter ++ u32 TxCf; // 0x6120 ++ ++ // Tx Oversize Frame Counter ++ u32 TOvr; // 0x6124 ++ ++ // Tx Undersize Frame Counter ++ u32 TUnd; // 0x6128 ++ ++ // Tx Fragments Frame Counter ++ u32 TFrg; // 0x612C ++ ++ // Carry Register One Register ++ MAC_STAT_REG_1_t Carry1; // 0x6130 ++ ++ // Carry Register Two Register ++ MAC_STAT_REG_2_t Carry2; // 0x6134 ++ ++ // Carry Register One Mask Register ++ MAC_STAT_REG_1_t Carry1M; // 0x6138 ++ ++ // Carry Register Two Mask Register ++ MAC_STAT_REG_2_t Carry2M; // 0x613C ++} MAC_STAT_t, *PMAC_STAT_t; ++ ++/* END OF MAC STAT REGISTER ADDRESS MAP */ ++ ++ ++/* START OF MMC REGISTER ADDRESS MAP */ ++ ++/* ++ * structure for Main Memory Controller Control reg in mmc address map. ++ * located at address 0x7000 ++ */ ++typedef union _MMC_CTRL_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:25; // bits 7-31 ++ u32 force_ce:1; // bit 6 ++ u32 rxdma_disable:1; // bit 5 ++ u32 txdma_disable:1; // bit 4 ++ u32 txmac_disable:1; // bit 3 ++ u32 rxmac_disable:1; // bit 2 ++ u32 arb_disable:1; // bit 1 ++ u32 mmc_enable:1; // bit 0 ++#else ++ u32 mmc_enable:1; // bit 0 ++ u32 arb_disable:1; // bit 1 ++ u32 rxmac_disable:1; // bit 2 ++ u32 txmac_disable:1; // bit 3 ++ u32 txdma_disable:1; // bit 4 ++ u32 rxdma_disable:1; // bit 5 ++ u32 force_ce:1; // bit 6 ++ u32 reserved:25; // bits 7-31 ++#endif ++ } bits; ++} MMC_CTRL_t, *PMMC_CTRL_t; ++ ++/* ++ * structure for Main Memory Controller Host Memory Access Address reg in mmc ++ * address map. Located at address 0x7004 ++ */ ++typedef union _MMC_SRAM_ACCESS_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 byte_enable:16; // bits 16-31 ++ u32 reserved2:2; // bits 14-15 ++ u32 req_addr:10; // bits 4-13 ++ u32 reserved1:1; // bit 3 ++ u32 is_ctrl_word:1; // bit 2 ++ u32 wr_access:1; // bit 1 ++ u32 req_access:1; // bit 0 ++#else ++ u32 req_access:1; // bit 0 ++ u32 wr_access:1; // bit 1 ++ u32 is_ctrl_word:1; // bit 2 ++ u32 reserved1:1; // bit 3 ++ u32 req_addr:10; // bits 4-13 ++ u32 reserved2:2; // bits 14-15 ++ u32 byte_enable:16; // bits 16-31 ++#endif ++ } bits; ++} MMC_SRAM_ACCESS_t, *PMMC_SRAM_ACCESS_t; ++ ++/* ++ * structure for Main Memory Controller Host Memory Access Data reg in mmc ++ * address map. Located at address 0x7008 - 0x7014 ++ * Defined earlier (u32) ++ */ ++ ++/* ++ * Memory Control Module of JAGCore Address Mapping ++ */ ++typedef struct _MMC_t { // Location: ++ MMC_CTRL_t mmc_ctrl; // 0x7000 ++ MMC_SRAM_ACCESS_t sram_access; // 0x7004 ++ u32 sram_word1; // 0x7008 ++ u32 sram_word2; // 0x700C ++ u32 sram_word3; // 0x7010 ++ u32 sram_word4; // 0x7014 ++} MMC_t, *PMMC_t; ++ ++/* END OF MMC REGISTER ADDRESS MAP */ ++ ++ ++/* START OF EXP ROM REGISTER ADDRESS MAP */ ++ ++/* ++ * Expansion ROM Module of JAGCore Address Mapping ++ */ ++ ++/* Take this out until it is not empty */ ++#if 0 ++typedef struct _EXP_ROM_t { ++ ++} EXP_ROM_t, *PEXP_ROM_t; ++#endif ++ ++/* END OF EXP ROM REGISTER ADDRESS MAP */ ++ ++ ++/* ++ * JAGCore Address Mapping ++ */ ++typedef struct _ADDRESS_MAP_t { ++ GLOBAL_t global; ++ // unused section of global address map ++ u8 unused_global[4096 - sizeof(GLOBAL_t)]; ++ TXDMA_t txdma; ++ // unused section of txdma address map ++ u8 unused_txdma[4096 - sizeof(TXDMA_t)]; ++ RXDMA_t rxdma; ++ // unused section of rxdma address map ++ u8 unused_rxdma[4096 - sizeof(RXDMA_t)]; ++ TXMAC_t txmac; ++ // unused section of txmac address map ++ u8 unused_txmac[4096 - sizeof(TXMAC_t)]; ++ RXMAC_t rxmac; ++ // unused section of rxmac address map ++ u8 unused_rxmac[4096 - sizeof(RXMAC_t)]; ++ MAC_t mac; ++ // unused section of mac address map ++ u8 unused_mac[4096 - sizeof(MAC_t)]; ++ MAC_STAT_t macStat; ++ // unused section of mac stat address map ++ u8 unused_mac_stat[4096 - sizeof(MAC_STAT_t)]; ++ MMC_t mmc; ++ // unused section of mmc address map ++ u8 unused_mmc[4096 - sizeof(MMC_t)]; ++ // unused section of address map ++ u8 unused_[1015808]; ++ ++/* Take this out until it is not empty */ ++#if 0 ++ EXP_ROM_t exp_rom; ++#endif ++ ++ u8 unused_exp_rom[4096]; // MGS-size TBD ++ u8 unused__[524288]; // unused section of address map ++} ADDRESS_MAP_t, *PADDRESS_MAP_t; ++ ++#endif /* _ET1310_ADDRESS_MAP_H_ */ +diff --git a/drivers/staging/et131x/et1310_eeprom.c b/drivers/staging/et131x/et1310_eeprom.c +new file mode 100644 +index 0000000..c2b194e +--- /dev/null ++++ b/drivers/staging/et131x/et1310_eeprom.c +@@ -0,0 +1,480 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_eeprom.c - Code used to access the device's EEPROM ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++#include "et1310_eeprom.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++#include "et131x_isr.h" ++ ++#include "et1310_tx.h" ++ ++ ++/* ++ * EEPROM Defines ++ */ ++ ++/* LBCIF Register Groups (addressed via 32-bit offsets) */ ++#define LBCIF_DWORD0_GROUP_OFFSET 0xAC ++#define LBCIF_DWORD1_GROUP_OFFSET 0xB0 ++ ++/* LBCIF Registers (addressed via 8-bit offsets) */ ++#define LBCIF_ADDRESS_REGISTER_OFFSET 0xAC ++#define LBCIF_DATA_REGISTER_OFFSET 0xB0 ++#define LBCIF_CONTROL_REGISTER_OFFSET 0xB1 ++#define LBCIF_STATUS_REGISTER_OFFSET 0xB2 ++ ++/* LBCIF Control Register Bits */ ++#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01 ++#define LBCIF_CONTROL_PAGE_WRITE 0x02 ++#define LBCIF_CONTROL_UNUSED1 0x04 ++#define LBCIF_CONTROL_EEPROM_RELOAD 0x08 ++#define LBCIF_CONTROL_UNUSED2 0x10 ++#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20 ++#define LBCIF_CONTROL_I2C_WRITE 0x40 ++#define LBCIF_CONTROL_LBCIF_ENABLE 0x80 ++ ++/* LBCIF Status Register Bits */ ++#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01 ++#define LBCIF_STATUS_I2C_IDLE 0x02 ++#define LBCIF_STATUS_ACK_ERROR 0x04 ++#define LBCIF_STATUS_GENERAL_ERROR 0x08 ++#define LBCIF_STATUS_UNUSED 0x30 ++#define LBCIF_STATUS_CHECKSUM_ERROR 0x40 ++#define LBCIF_STATUS_EEPROM_PRESENT 0x80 ++ ++/* Miscellaneous Constraints */ ++#define MAX_NUM_REGISTER_POLLS 1000 ++#define MAX_NUM_WRITE_RETRIES 2 ++ ++/* ++ * Define macros that allow individual register values to be extracted from a ++ * DWORD1 register grouping ++ */ ++#define EXTRACT_DATA_REGISTER(x) (uint8_t)(x & 0xFF) ++#define EXTRACT_STATUS_REGISTER(x) (uint8_t)((x >> 16) & 0xFF) ++#define EXTRACT_CONTROL_REG(x) (uint8_t)((x >> 8) & 0xFF) ++ ++/** ++ * EepromWriteByte - Write a byte to the ET1310's EEPROM ++ * @pAdapter: pointer to our private adapter structure ++ * @unAddress: the address to write ++ * @bData: the value to write ++ * @unEepronId: the ID of the EEPROM ++ * @unAddressingMode: how the EEPROM is to be accessed ++ * ++ * Returns SUCCESS or FAILURE ++ */ ++int32_t EepromWriteByte(struct et131x_adapter *pAdapter, uint32_t unAddress, ++ uint8_t bData, uint32_t unEepromId, ++ uint32_t unAddressingMode) ++{ ++ struct pci_dev *pdev = pAdapter->pdev; ++ int32_t nIndex; ++ int32_t nRetries; ++ int32_t nError = false; ++ int32_t nI2CWriteActive = 0; ++ int32_t nWriteSuccessful = 0; ++ uint8_t bControl; ++ uint8_t bStatus = 0; ++ uint32_t unDword1 = 0; ++ uint32_t unData = 0; ++ ++ /* ++ * The following excerpt is from "Serial EEPROM HW Design ++ * Specification" Version 0.92 (9/20/2004): ++ * ++ * Single Byte Writes ++ * ++ * For an EEPROM, an I2C single byte write is defined as a START ++ * condition followed by the device address, EEPROM address, one byte ++ * of data and a STOP condition. The STOP condition will trigger the ++ * EEPROM's internally timed write cycle to the nonvolatile memory. ++ * All inputs are disabled during this write cycle and the EEPROM will ++ * not respond to any access until the internal write is complete. ++ * The steps to execute a single byte write are as follows: ++ * ++ * 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and ++ * bits 7,1:0 both equal to 1, at least once after reset. ++ * Subsequent operations need only to check that bits 1:0 are ++ * equal to 1 prior to starting a single byte write. ++ * ++ * 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0, ++ * and bits 1:0 both =0. Bit 5 should be set according to the ++ * type of EEPROM being accessed (1=two byte addressing, 0=one ++ * byte addressing). ++ * ++ * 3. Write the address to the LBCIF Address Register. ++ * ++ * 4. Write the data to the LBCIF Data Register (the I2C write will ++ * begin). ++ * ++ * 5. Monitor bit 1:0 of the LBCIF Status Register. When bits 1:0 are ++ * both equal to 1, the I2C write has completed and the internal ++ * write cycle of the EEPROM is about to start. (bits 1:0 = 01 is ++ * a legal state while waiting from both equal to 1, but bits ++ * 1:0 = 10 is invalid and implies that something is broken). ++ * ++ * 6. Check bit 3 of the LBCIF Status Register. If equal to 1, an ++ * error has occurred. ++ * ++ * 7. Check bit 2 of the LBCIF Status Register. If equal to 1 an ACK ++ * error has occurred on the address phase of the write. This ++ * could be due to an actual hardware failure or the EEPROM may ++ * still be in its internal write cycle from a previous write. ++ * This write operation was ignored and must be repeated later. ++ * ++ * 8. Set bit 6 of the LBCIF Control Register = 0. If another write is ++ * required, go to step 1. ++ */ ++ ++ /* Step 1: */ ++ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { ++ /* Read registers grouped in DWORD1 */ ++ if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET, ++ &unDword1)) { ++ nError = 1; ++ break; ++ } ++ ++ bStatus = EXTRACT_STATUS_REGISTER(unDword1); ++ ++ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && ++ bStatus & LBCIF_STATUS_I2C_IDLE) { ++ /* bits 1:0 are equal to 1 */ ++ break; ++ } ++ } ++ ++ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { ++ return FAILURE; ++ } ++ ++ /* Step 2: */ ++ bControl = 0; ++ bControl |= LBCIF_CONTROL_LBCIF_ENABLE | LBCIF_CONTROL_I2C_WRITE; ++ ++ if (unAddressingMode == DUAL_BYTE) { ++ bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR; ++ } ++ ++ if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET, ++ bControl)) { ++ return FAILURE; ++ } ++ ++ nI2CWriteActive = 1; ++ ++ /* Prepare EEPROM address for Step 3 */ ++ unAddress |= (unAddressingMode == DUAL_BYTE) ? ++ (unEepromId << 16) : (unEepromId << 8); ++ ++ for (nRetries = 0; nRetries < MAX_NUM_WRITE_RETRIES; nRetries++) { ++ /* Step 3:*/ ++ if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER_OFFSET, ++ unAddress)) { ++ break; ++ } ++ ++ /* Step 4: */ ++ if (pci_write_config_byte(pdev, LBCIF_DATA_REGISTER_OFFSET, ++ bData)) { ++ break; ++ } ++ ++ /* Step 5: */ ++ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { ++ /* Read registers grouped in DWORD1 */ ++ if (pci_read_config_dword(pdev, ++ LBCIF_DWORD1_GROUP_OFFSET, ++ &unDword1)) { ++ nError = 1; ++ break; ++ } ++ ++ bStatus = EXTRACT_STATUS_REGISTER(unDword1); ++ ++ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && ++ bStatus & LBCIF_STATUS_I2C_IDLE) { ++ /* I2C write complete */ ++ break; ++ } ++ } ++ ++ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { ++ break; ++ } ++ ++ /* ++ * Step 6: Don't break here if we are revision 1, this is ++ * so we do a blind write for load bug. ++ */ ++ if (bStatus & LBCIF_STATUS_GENERAL_ERROR ++ && pAdapter->RevisionID == 0) { ++ break; ++ } ++ ++ /* Step 7 */ ++ if (bStatus & LBCIF_STATUS_ACK_ERROR) { ++ /* ++ * This could be due to an actual hardware failure ++ * or the EEPROM may still be in its internal write ++ * cycle from a previous write. This write operation ++ * was ignored and must be repeated later. ++ */ ++ udelay(10); ++ continue; ++ } ++ ++ nWriteSuccessful = 1; ++ break; ++ } ++ ++ /* Step 8: */ ++ udelay(10); ++ nIndex = 0; ++ while (nI2CWriteActive) { ++ bControl &= ~LBCIF_CONTROL_I2C_WRITE; ++ ++ if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET, ++ bControl)) { ++ nWriteSuccessful = 0; ++ } ++ ++ /* Do read until internal ACK_ERROR goes away meaning write ++ * completed ++ */ ++ do { ++ pci_write_config_dword(pdev, ++ LBCIF_ADDRESS_REGISTER_OFFSET, ++ unAddress); ++ do { ++ pci_read_config_dword(pdev, ++ LBCIF_DATA_REGISTER_OFFSET, &unData); ++ } while ((unData & 0x00010000) == 0); ++ } while (unData & 0x00040000); ++ ++ bControl = EXTRACT_CONTROL_REG(unData); ++ ++ if (bControl != 0xC0 || nIndex == 10000) { ++ break; ++ } ++ ++ nIndex++; ++ } ++ ++ return nWriteSuccessful ? SUCCESS : FAILURE; ++} ++ ++/** ++ * EepromReadByte - Read a byte from the ET1310's EEPROM ++ * @pAdapter: pointer to our private adapter structure ++ * @unAddress: the address from which to read ++ * @pbData: a pointer to a byte in which to store the value of the read ++ * @unEepronId: the ID of the EEPROM ++ * @unAddressingMode: how the EEPROM is to be accessed ++ * ++ * Returns SUCCESS or FAILURE ++ */ ++int32_t EepromReadByte(struct et131x_adapter *pAdapter, uint32_t unAddress, ++ uint8_t *pbData, uint32_t unEepromId, ++ uint32_t unAddressingMode) ++{ ++ struct pci_dev *pdev = pAdapter->pdev; ++ int32_t nIndex; ++ int32_t nError = 0; ++ uint8_t bControl; ++ uint8_t bStatus = 0; ++ uint32_t unDword1 = 0; ++ ++ /* ++ * The following excerpt is from "Serial EEPROM HW Design ++ * Specification" Version 0.92 (9/20/2004): ++ * ++ * Single Byte Reads ++ * ++ * A single byte read is similar to the single byte write, with the ++ * exception of the data flow: ++ * ++ * 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and ++ * bits 7,1:0 both equal to 1, at least once after reset. ++ * Subsequent operations need only to check that bits 1:0 are equal ++ * to 1 prior to starting a single byte read. ++ * ++ * 2. Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0, ++ * and bits 1:0 both =0. Bit 5 should be set according to the type ++ * of EEPROM being accessed (1=two byte addressing, 0=one byte ++ * addressing). ++ * ++ * 3. Write the address to the LBCIF Address Register (I2C read will ++ * begin). ++ * ++ * 4. Monitor bit 0 of the LBCIF Status Register. When =1, I2C read ++ * is complete. (if bit 1 =1 and bit 0 stays =0, a hardware failure ++ * has occurred). ++ * ++ * 5. Check bit 2 of the LBCIF Status Register. If =1, then an error ++ * has occurred. The data that has been returned from the PHY may ++ * be invalid. ++ * ++ * 6. Regardless of error status, read data byte from LBCIF Data ++ * Register. If another byte is required, go to step 1. ++ */ ++ ++ /* Step 1: */ ++ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { ++ /* Read registers grouped in DWORD1 */ ++ if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET, ++ &unDword1)) { ++ nError = 1; ++ break; ++ } ++ ++ bStatus = EXTRACT_STATUS_REGISTER(unDword1); ++ ++ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && ++ bStatus & LBCIF_STATUS_I2C_IDLE) { ++ /* bits 1:0 are equal to 1 */ ++ break; ++ } ++ } ++ ++ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { ++ return FAILURE; ++ } ++ ++ /* Step 2: */ ++ bControl = 0; ++ bControl |= LBCIF_CONTROL_LBCIF_ENABLE; ++ ++ if (unAddressingMode == DUAL_BYTE) { ++ bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR; ++ } ++ ++ if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET, ++ bControl)) { ++ return FAILURE; ++ } ++ ++ /* Step 3: */ ++ unAddress |= (unAddressingMode == DUAL_BYTE) ? ++ (unEepromId << 16) : (unEepromId << 8); ++ ++ if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER_OFFSET, ++ unAddress)) { ++ return FAILURE; ++ } ++ ++ /* Step 4: */ ++ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { ++ /* Read registers grouped in DWORD1 */ ++ if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET, ++ &unDword1)) { ++ nError = 1; ++ break; ++ } ++ ++ bStatus = EXTRACT_STATUS_REGISTER(unDword1); ++ ++ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL ++ && bStatus & LBCIF_STATUS_I2C_IDLE) { ++ /* I2C read complete */ ++ break; ++ } ++ } ++ ++ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { ++ return FAILURE; ++ } ++ ++ /* Step 6: */ ++ *pbData = EXTRACT_DATA_REGISTER(unDword1); ++ ++ return (bStatus & LBCIF_STATUS_ACK_ERROR) ? FAILURE : SUCCESS; ++} +diff --git a/drivers/staging/et131x/et1310_eeprom.h b/drivers/staging/et131x/et1310_eeprom.h +new file mode 100644 +index 0000000..9b6f8ad +--- /dev/null ++++ b/drivers/staging/et131x/et1310_eeprom.h +@@ -0,0 +1,89 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_eeprom.h - Defines, structs, enums, prototypes, etc. used for EEPROM ++ * access routines ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET1310_EEPROM_H__ ++#define __ET1310_EEPROM_H__ ++ ++#include "et1310_address_map.h" ++ ++#ifndef SUCCESS ++#define SUCCESS 0 ++#define FAILURE 1 ++#endif ++ ++#ifndef READ ++#define READ 0 ++#define WRITE 1 ++#endif ++ ++#ifndef SINGLE_BYTE ++#define SINGLE_BYTE 0 ++#define DUAL_BYTE 1 ++#endif ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++int32_t EepromWriteByte(struct et131x_adapter *adapter, u32 unAddress, ++ u8 bData, u32 unEepromId, ++ u32 unAddressingMode); ++int32_t EepromReadByte(struct et131x_adapter *adapter, u32 unAddress, ++ u8 *pbData, u32 unEepromId, ++ u32 unAddressingMode); ++ ++#endif /* _ET1310_EEPROM_H_ */ +diff --git a/drivers/staging/et131x/et1310_jagcore.c b/drivers/staging/et131x/et1310_jagcore.c +new file mode 100644 +index 0000000..993b30e +--- /dev/null ++++ b/drivers/staging/et131x/et1310_jagcore.c +@@ -0,0 +1,220 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_jagcore.c - All code pertaining to the ET1301/ET131x's JAGcore ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/** ++ * ConfigGlobalRegs - Used to configure the global registers on the JAGCore ++ * @pAdpater: pointer to our adapter structure ++ */ ++void ConfigGlobalRegs(struct et131x_adapter *pAdapter) ++{ ++ struct _GLOBAL_t __iomem *pGbl = &pAdapter->CSRAddress->global; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ if (pAdapter->RegistryPhyLoopbk == false) { ++ if (pAdapter->RegistryJumboPacket < 2048) { ++ /* Tx / RxDMA and Tx/Rx MAC interfaces have a 1k word ++ * block of RAM that the driver can split between Tx ++ * and Rx as it desires. Our default is to split it ++ * 50/50: ++ */ ++ writel(0, &pGbl->rxq_start_addr.value); ++ writel(pAdapter->RegistryRxMemEnd, ++ &pGbl->rxq_end_addr.value); ++ writel(pAdapter->RegistryRxMemEnd + 1, ++ &pGbl->txq_start_addr.value); ++ writel(INTERNAL_MEM_SIZE - 1, ++ &pGbl->txq_end_addr.value); ++ } else if (pAdapter->RegistryJumboPacket < 8192) { ++ /* For jumbo packets > 2k but < 8k, split 50-50. */ ++ writel(0, &pGbl->rxq_start_addr.value); ++ writel(INTERNAL_MEM_RX_OFFSET, ++ &pGbl->rxq_end_addr.value); ++ writel(INTERNAL_MEM_RX_OFFSET + 1, ++ &pGbl->txq_start_addr.value); ++ writel(INTERNAL_MEM_SIZE - 1, ++ &pGbl->txq_end_addr.value); ++ } else { ++ /* 9216 is the only packet size greater than 8k that ++ * is available. The Tx buffer has to be big enough ++ * for one whole packet on the Tx side. We'll make ++ * the Tx 9408, and give the rest to Rx ++ */ ++ writel(0x0000, &pGbl->rxq_start_addr.value); ++ writel(0x01b3, &pGbl->rxq_end_addr.value); ++ writel(0x01b4, &pGbl->txq_start_addr.value); ++ writel(INTERNAL_MEM_SIZE - 1, ++ &pGbl->txq_end_addr.value); ++ } ++ ++ /* Initialize the loopback register. Disable all loopbacks. */ ++ writel(0, &pGbl->loopback.value); ++ } else { ++ /* For PHY Line loopback, the memory is configured as if Tx ++ * and Rx both have all the memory. This is because the ++ * RxMAC will write data into the space, and the TxMAC will ++ * read it out. ++ */ ++ writel(0, &pGbl->rxq_start_addr.value); ++ writel(INTERNAL_MEM_SIZE - 1, &pGbl->rxq_end_addr.value); ++ writel(0, &pGbl->txq_start_addr.value); ++ writel(INTERNAL_MEM_SIZE - 1, &pGbl->txq_end_addr.value); ++ ++ /* Initialize the loopback register (MAC loopback). */ ++ writel(1, &pGbl->loopback.value); ++ } ++ ++ /* MSI Register */ ++ writel(0, &pGbl->msi_config.value); ++ ++ /* By default, disable the watchdog timer. It will be enabled when ++ * a packet is queued. ++ */ ++ writel(0, &pGbl->watchdog_timer); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * ConfigMMCRegs - Used to configure the main memory registers in the JAGCore ++ * @pAdapter: pointer to our adapter structure ++ */ ++void ConfigMMCRegs(struct et131x_adapter *pAdapter) ++{ ++ MMC_CTRL_t mmc_ctrl = { 0 }; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* All we need to do is initialize the Memory Control Register */ ++ mmc_ctrl.bits.force_ce = 0x0; ++ mmc_ctrl.bits.rxdma_disable = 0x0; ++ mmc_ctrl.bits.txdma_disable = 0x0; ++ mmc_ctrl.bits.txmac_disable = 0x0; ++ mmc_ctrl.bits.rxmac_disable = 0x0; ++ mmc_ctrl.bits.arb_disable = 0x0; ++ mmc_ctrl.bits.mmc_enable = 0x1; ++ ++ writel(mmc_ctrl.value, &pAdapter->CSRAddress->mmc.mmc_ctrl.value); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void et131x_enable_interrupts(struct et131x_adapter *adapter) ++{ ++ uint32_t MaskValue; ++ ++ /* Enable all global interrupts */ ++ if ((adapter->FlowControl == TxOnly) || (adapter->FlowControl == Both)) { ++ MaskValue = INT_MASK_ENABLE; ++ } else { ++ MaskValue = INT_MASK_ENABLE_NO_FLOW; ++ } ++ ++ if (adapter->DriverNoPhyAccess) { ++ MaskValue |= 0x10000; ++ } ++ ++ adapter->CachedMaskValue.value = MaskValue; ++ writel(MaskValue, &adapter->CSRAddress->global.int_mask.value); ++} ++ ++void et131x_disable_interrupts(struct et131x_adapter * adapter) ++{ ++ /* Disable all global interrupts */ ++ adapter->CachedMaskValue.value = INT_MASK_DISABLE; ++ writel(INT_MASK_DISABLE, &adapter->CSRAddress->global.int_mask.value); ++} +diff --git a/drivers/staging/et131x/et1310_jagcore.h b/drivers/staging/et131x/et1310_jagcore.h +new file mode 100644 +index 0000000..9fc8293 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_jagcore.h +@@ -0,0 +1,112 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_jagcore.h - Defines, structs, enums, prototypes, etc. pertaining to ++ * the JAGCore ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET1310_JAGCORE_H__ ++#define __ET1310_JAGCORE_H__ ++ ++#include "et1310_address_map.h" ++ ++ ++#define INTERNAL_MEM_SIZE 0x400 //1024 of internal memory ++#define INTERNAL_MEM_RX_OFFSET 0x1FF //50% Tx, 50% Rx ++ ++#define REGS_MAX_ARRAY 4096 ++ ++/* ++ * For interrupts, normal running is: ++ * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt, ++ * watchdog_interrupt & txdma_xfer_done ++ * ++ * In both cases, when flow control is enabled for either Tx or bi-direction, ++ * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the ++ * buffer rings are running low. ++ */ ++#define INT_MASK_DISABLE 0xffffffff ++ ++// NOTE: Masking out MAC_STAT Interrupt for now... ++//#define INT_MASK_ENABLE 0xfff6bf17 ++//#define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7 ++#define INT_MASK_ENABLE 0xfffebf17 ++#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7 ++ ++/* DATA STRUCTURES FOR DIRECT REGISTER ACCESS */ ++ ++typedef struct { ++ u8 bReadWrite; ++ u32 nRegCount; ++ u32 nData[REGS_MAX_ARRAY]; ++ u32 nOffsets[REGS_MAX_ARRAY]; ++} JAGCORE_ACCESS_REGS, *PJAGCORE_ACCESS_REGS; ++ ++typedef struct { ++ u8 bReadWrite; ++ u32 nDataWidth; ++ u32 nRegCount; ++ u32 nOffsets[REGS_MAX_ARRAY]; ++ u32 nData[REGS_MAX_ARRAY]; ++} PCI_CFG_SPACE_REGS, *PPCI_CFG_SPACE_REGS; ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++void ConfigGlobalRegs(struct et131x_adapter *pAdapter); ++void ConfigMMCRegs(struct et131x_adapter *pAdapter); ++void et131x_enable_interrupts(struct et131x_adapter *adapter); ++void et131x_disable_interrupts(struct et131x_adapter *adapter); ++ ++#endif /* __ET1310_JAGCORE_H__ */ +diff --git a/drivers/staging/et131x/et1310_mac.c b/drivers/staging/et131x/et1310_mac.c +new file mode 100644 +index 0000000..1924968 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_mac.c +@@ -0,0 +1,792 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_mac.c - All code and routines pertaining to the MAC ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++#include "et1310_mac.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/** ++ * ConfigMacRegs1 - Initialize the first part of MAC regs ++ * @pAdpater: pointer to our adapter structure ++ */ ++void ConfigMACRegs1(struct et131x_adapter *pAdapter) ++{ ++ struct _MAC_t __iomem *pMac = &pAdapter->CSRAddress->mac; ++ MAC_STATION_ADDR1_t station1; ++ MAC_STATION_ADDR2_t station2; ++ MAC_IPG_t ipg; ++ MAC_HFDP_t hfdp; ++ MII_MGMT_CFG_t mii_mgmt_cfg; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* First we need to reset everything. Write to MAC configuration ++ * register 1 to perform reset. ++ */ ++ writel(0xC00F0000, &pMac->cfg1.value); ++ ++ /* Next lets configure the MAC Inter-packet gap register */ ++ ipg.bits.non_B2B_ipg_1 = 0x38; // 58d ++ ipg.bits.non_B2B_ipg_2 = 0x58; // 88d ++ ipg.bits.min_ifg_enforce = 0x50; // 80d ++ ipg.bits.B2B_ipg = 0x60; // 96d ++ writel(ipg.value, &pMac->ipg.value); ++ ++ /* Next lets configure the MAC Half Duplex register */ ++ hfdp.bits.alt_beb_trunc = 0xA; ++ hfdp.bits.alt_beb_enable = 0x0; ++ hfdp.bits.bp_no_backoff = 0x0; ++ hfdp.bits.no_backoff = 0x0; ++ hfdp.bits.excess_defer = 0x1; ++ hfdp.bits.rexmit_max = 0xF; ++ hfdp.bits.coll_window = 0x37; // 55d ++ writel(hfdp.value, &pMac->hfdp.value); ++ ++ /* Next lets configure the MAC Interface Control register */ ++ writel(0, &pMac->if_ctrl.value); ++ ++ /* Let's move on to setting up the mii managment configuration */ ++ mii_mgmt_cfg.bits.reset_mii_mgmt = 0; ++ mii_mgmt_cfg.bits.scan_auto_incremt = 0; ++ mii_mgmt_cfg.bits.preamble_suppress = 0; ++ mii_mgmt_cfg.bits.mgmt_clk_reset = 0x7; ++ writel(mii_mgmt_cfg.value, &pMac->mii_mgmt_cfg.value); ++ ++ /* Next lets configure the MAC Station Address register. These ++ * values are read from the EEPROM during initialization and stored ++ * in the adapter structure. We write what is stored in the adapter ++ * structure to the MAC Station Address registers high and low. This ++ * station address is used for generating and checking pause control ++ * packets. ++ */ ++ station2.bits.Octet1 = pAdapter->CurrentAddress[0]; ++ station2.bits.Octet2 = pAdapter->CurrentAddress[1]; ++ station1.bits.Octet3 = pAdapter->CurrentAddress[2]; ++ station1.bits.Octet4 = pAdapter->CurrentAddress[3]; ++ station1.bits.Octet5 = pAdapter->CurrentAddress[4]; ++ station1.bits.Octet6 = pAdapter->CurrentAddress[5]; ++ writel(station1.value, &pMac->station_addr_1.value); ++ writel(station2.value, &pMac->station_addr_2.value); ++ ++ /* Max ethernet packet in bytes that will passed by the mac without ++ * being truncated. Allow the MAC to pass 4 more than our max packet ++ * size. This is 4 for the Ethernet CRC. ++ * ++ * Packets larger than (RegistryJumboPacket) that do not contain a ++ * VLAN ID will be dropped by the Rx function. ++ */ ++ writel(pAdapter->RegistryJumboPacket + 4, &pMac->max_fm_len.value); ++ ++ /* clear out MAC config reset */ ++ writel(0, &pMac->cfg1.value); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * ConfigMacRegs2 - Initialize the second part of MAC regs ++ * @pAdpater: pointer to our adapter structure ++ */ ++void ConfigMACRegs2(struct et131x_adapter *pAdapter) ++{ ++ int32_t delay = 0; ++ struct _MAC_t __iomem *pMac = &pAdapter->CSRAddress->mac; ++ MAC_CFG1_t cfg1; ++ MAC_CFG2_t cfg2; ++ MAC_IF_CTRL_t ifctrl; ++ TXMAC_CTL_t ctl; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ ctl.value = readl(&pAdapter->CSRAddress->txmac.ctl.value); ++ cfg1.value = readl(&pMac->cfg1.value); ++ cfg2.value = readl(&pMac->cfg2.value); ++ ifctrl.value = readl(&pMac->if_ctrl.value); ++ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { ++ cfg2.bits.if_mode = 0x2; ++ ifctrl.bits.phy_mode = 0x0; ++ } else { ++ cfg2.bits.if_mode = 0x1; ++ ifctrl.bits.phy_mode = 0x1; ++ } ++ ++ /* We need to enable Rx/Tx */ ++ cfg1.bits.rx_enable = 0x1; ++ cfg1.bits.tx_enable = 0x1; ++ ++ /* Set up flow control */ ++ cfg1.bits.tx_flow = 0x1; ++ ++ if ((pAdapter->FlowControl == RxOnly) || ++ (pAdapter->FlowControl == Both)) { ++ cfg1.bits.rx_flow = 0x1; ++ } else { ++ cfg1.bits.rx_flow = 0x0; ++ } ++ ++ /* Initialize loop back to off */ ++ cfg1.bits.loop_back = 0; ++ ++ writel(cfg1.value, &pMac->cfg1.value); ++ ++ /* Now we need to initialize the MAC Configuration 2 register */ ++ cfg2.bits.preamble_len = 0x7; ++ cfg2.bits.huge_frame = 0x0; ++ /* LENGTH FIELD CHECKING bit4: Set this bit to cause the MAC to check ++ * the frame's length field to ensure it matches the actual data ++ * field length. Clear this bit if no length field checking is ++ * desired. Its default is 0. ++ */ ++ cfg2.bits.len_check = 0x1; ++ ++ if (pAdapter->RegistryPhyLoopbk == false) { ++ cfg2.bits.pad_crc = 0x1; ++ cfg2.bits.crc_enable = 0x1; ++ } else { ++ cfg2.bits.pad_crc = 0; ++ cfg2.bits.crc_enable = 0; ++ } ++ ++ /* 1 - full duplex, 0 - half-duplex */ ++ cfg2.bits.full_duplex = pAdapter->uiDuplexMode; ++ ifctrl.bits.ghd_mode = !pAdapter->uiDuplexMode; ++ ++ writel(ifctrl.value, &pMac->if_ctrl.value); ++ writel(cfg2.value, &pMac->cfg2.value); ++ ++ do { ++ udelay(10); ++ delay++; ++ cfg1.value = readl(&pMac->cfg1.value); ++ } while ((!cfg1.bits.syncd_rx_en || ++ !cfg1.bits.syncd_tx_en) && ++ delay < 100); ++ ++ if (delay == 100) { ++ DBG_ERROR(et131x_dbginfo, ++ "Syncd bits did not respond correctly cfg1 word 0x%08x\n", ++ cfg1.value); ++ } ++ ++ DBG_TRACE(et131x_dbginfo, ++ "Speed %d, Dup %d, CFG1 0x%08x, CFG2 0x%08x, if_ctrl 0x%08x\n", ++ pAdapter->uiLinkSpeed, pAdapter->uiDuplexMode, ++ readl(&pMac->cfg1.value), readl(&pMac->cfg2.value), ++ readl(&pMac->if_ctrl.value)); ++ ++ /* Enable TXMAC */ ++ ctl.bits.txmac_en = 0x1; ++ ctl.bits.fc_disable = 0x1; ++ writel(ctl.value, &pAdapter->CSRAddress->txmac.ctl.value); ++ ++ /* Ready to start the RXDMA/TXDMA engine */ ++ if (!MP_TEST_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER)) { ++ et131x_rx_dma_enable(pAdapter); ++ et131x_tx_dma_enable(pAdapter); ++ } else { ++ DBG_WARNING(et131x_dbginfo, ++ "Didn't enable Rx/Tx due to low-power mode\n"); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void ConfigRxMacRegs(struct et131x_adapter *pAdapter) ++{ ++ struct _RXMAC_t __iomem *pRxMac = &pAdapter->CSRAddress->rxmac; ++ RXMAC_WOL_SA_LO_t sa_lo; ++ RXMAC_WOL_SA_HI_t sa_hi; ++ RXMAC_PF_CTRL_t pf_ctrl = { 0 }; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Disable the MAC while it is being configured (also disable WOL) */ ++ writel(0x8, &pRxMac->ctrl.value); ++ ++ /* Initialize WOL to disabled. */ ++ writel(0, &pRxMac->crc0.value); ++ writel(0, &pRxMac->crc12.value); ++ writel(0, &pRxMac->crc34.value); ++ ++ /* We need to set the WOL mask0 - mask4 next. We initialize it to ++ * its default Values of 0x00000000 because there are not WOL masks ++ * as of this time. ++ */ ++ writel(0, &pRxMac->mask0_word0); ++ writel(0, &pRxMac->mask0_word1); ++ writel(0, &pRxMac->mask0_word2); ++ writel(0, &pRxMac->mask0_word3); ++ ++ writel(0, &pRxMac->mask1_word0); ++ writel(0, &pRxMac->mask1_word1); ++ writel(0, &pRxMac->mask1_word2); ++ writel(0, &pRxMac->mask1_word3); ++ ++ writel(0, &pRxMac->mask2_word0); ++ writel(0, &pRxMac->mask2_word1); ++ writel(0, &pRxMac->mask2_word2); ++ writel(0, &pRxMac->mask2_word3); ++ ++ writel(0, &pRxMac->mask3_word0); ++ writel(0, &pRxMac->mask3_word1); ++ writel(0, &pRxMac->mask3_word2); ++ writel(0, &pRxMac->mask3_word3); ++ ++ writel(0, &pRxMac->mask4_word0); ++ writel(0, &pRxMac->mask4_word1); ++ writel(0, &pRxMac->mask4_word2); ++ writel(0, &pRxMac->mask4_word3); ++ ++ /* Lets setup the WOL Source Address */ ++ sa_lo.bits.sa3 = pAdapter->CurrentAddress[2]; ++ sa_lo.bits.sa4 = pAdapter->CurrentAddress[3]; ++ sa_lo.bits.sa5 = pAdapter->CurrentAddress[4]; ++ sa_lo.bits.sa6 = pAdapter->CurrentAddress[5]; ++ writel(sa_lo.value, &pRxMac->sa_lo.value); ++ ++ sa_hi.bits.sa1 = pAdapter->CurrentAddress[0]; ++ sa_hi.bits.sa2 = pAdapter->CurrentAddress[1]; ++ writel(sa_hi.value, &pRxMac->sa_hi.value); ++ ++ /* Disable all Packet Filtering */ ++ writel(0, &pRxMac->pf_ctrl.value); ++ ++ /* Let's initialize the Unicast Packet filtering address */ ++ if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_DIRECTED) { ++ SetupDeviceForUnicast(pAdapter); ++ pf_ctrl.bits.filter_uni_en = 1; ++ } else { ++ writel(0, &pRxMac->uni_pf_addr1.value); ++ writel(0, &pRxMac->uni_pf_addr2.value); ++ writel(0, &pRxMac->uni_pf_addr3.value); ++ } ++ ++ /* Let's initialize the Multicast hash */ ++ if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST) { ++ pf_ctrl.bits.filter_multi_en = 0; ++ } else { ++ pf_ctrl.bits.filter_multi_en = 1; ++ SetupDeviceForMulticast(pAdapter); ++ } ++ ++ /* Runt packet filtering. Didn't work in version A silicon. */ ++ pf_ctrl.bits.min_pkt_size = NIC_MIN_PACKET_SIZE + 4; ++ pf_ctrl.bits.filter_frag_en = 1; ++ ++ if (pAdapter->RegistryJumboPacket > 8192) { ++ RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; ++ ++ /* In order to transmit jumbo packets greater than 8k, the ++ * FIFO between RxMAC and RxDMA needs to be reduced in size ++ * to (16k - Jumbo packet size). In order to implement this, ++ * we must use "cut through" mode in the RxMAC, which chops ++ * packets down into segments which are (max_size * 16). In ++ * this case we selected 256 bytes, since this is the size of ++ * the PCI-Express TLP's that the 1310 uses. ++ */ ++ mcif_ctrl_max_seg.bits.seg_en = 0x1; ++ mcif_ctrl_max_seg.bits.fc_en = 0x0; ++ mcif_ctrl_max_seg.bits.max_size = 0x10; ++ ++ writel(mcif_ctrl_max_seg.value, ++ &pRxMac->mcif_ctrl_max_seg.value); ++ } else { ++ writel(0, &pRxMac->mcif_ctrl_max_seg.value); ++ } ++ ++ /* Initialize the MCIF water marks */ ++ writel(0, &pRxMac->mcif_water_mark.value); ++ ++ /* Initialize the MIF control */ ++ writel(0, &pRxMac->mif_ctrl.value); ++ ++ /* Initialize the Space Available Register */ ++ writel(0, &pRxMac->space_avail.value); ++ ++ /* Initialize the the mif_ctrl register ++ * bit 3: Receive code error. One or more nibbles were signaled as ++ * errors during the reception of the packet. Clear this ++ * bit in Gigabit, set it in 100Mbit. This was derived ++ * experimentally at UNH. ++ * bit 4: Receive CRC error. The packet's CRC did not match the ++ * internally generated CRC. ++ * bit 5: Receive length check error. Indicates that frame length ++ * field value in the packet does not match the actual data ++ * byte length and is not a type field. ++ * bit 16: Receive frame truncated. ++ * bit 17: Drop packet enable ++ */ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS) { ++ writel(0x30038, &pRxMac->mif_ctrl.value); ++ } else { ++ writel(0x30030, &pRxMac->mif_ctrl.value); ++ } ++ ++ /* Finally we initialize RxMac to be enabled & WOL disabled. Packet ++ * filter is always enabled since it is where the runt packets are ++ * supposed to be dropped. For version A silicon, runt packet ++ * dropping doesn't work, so it is disabled in the pf_ctrl register, ++ * but we still leave the packet filter on. ++ */ ++ writel(pf_ctrl.value, &pRxMac->pf_ctrl.value); ++ writel(0x9, &pRxMac->ctrl.value); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void ConfigTxMacRegs(struct et131x_adapter *pAdapter) ++{ ++ struct _TXMAC_t __iomem *pTxMac = &pAdapter->CSRAddress->txmac; ++ TXMAC_CF_PARAM_t Local; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* We need to update the Control Frame Parameters ++ * cfpt - control frame pause timer set to 64 (0x40) ++ * cfep - control frame extended pause timer set to 0x0 ++ */ ++ if (pAdapter->FlowControl == None) { ++ writel(0, &pTxMac->cf_param.value); ++ } else { ++ Local.bits.cfpt = 0x40; ++ Local.bits.cfep = 0x0; ++ writel(Local.value, &pTxMac->cf_param.value); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void ConfigMacStatRegs(struct et131x_adapter *pAdapter) ++{ ++ struct _MAC_STAT_t __iomem *pDevMacStat = ++ &pAdapter->CSRAddress->macStat; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Next we need to initialize all the MAC_STAT registers to zero on ++ * the device. ++ */ ++ writel(0, &pDevMacStat->RFcs); ++ writel(0, &pDevMacStat->RAln); ++ writel(0, &pDevMacStat->RFlr); ++ writel(0, &pDevMacStat->RDrp); ++ writel(0, &pDevMacStat->RCde); ++ writel(0, &pDevMacStat->ROvr); ++ writel(0, &pDevMacStat->RFrg); ++ ++ writel(0, &pDevMacStat->TScl); ++ writel(0, &pDevMacStat->TDfr); ++ writel(0, &pDevMacStat->TMcl); ++ writel(0, &pDevMacStat->TLcl); ++ writel(0, &pDevMacStat->TNcl); ++ writel(0, &pDevMacStat->TOvr); ++ writel(0, &pDevMacStat->TUnd); ++ ++ /* Unmask any counters that we want to track the overflow of. ++ * Initially this will be all counters. It may become clear later ++ * that we do not need to track all counters. ++ */ ++ { ++ MAC_STAT_REG_1_t Carry1M = { 0xffffffff }; ++ ++ Carry1M.bits.rdrp = 0; ++ Carry1M.bits.rjbr = 1; ++ Carry1M.bits.rfrg = 0; ++ Carry1M.bits.rovr = 0; ++ Carry1M.bits.rund = 1; ++ Carry1M.bits.rcse = 1; ++ Carry1M.bits.rcde = 0; ++ Carry1M.bits.rflr = 0; ++ Carry1M.bits.raln = 0; ++ Carry1M.bits.rxuo = 1; ++ Carry1M.bits.rxpf = 1; ++ Carry1M.bits.rxcf = 1; ++ Carry1M.bits.rbca = 1; ++ Carry1M.bits.rmca = 1; ++ Carry1M.bits.rfcs = 0; ++ Carry1M.bits.rpkt = 1; ++ Carry1M.bits.rbyt = 1; ++ Carry1M.bits.trmgv = 1; ++ Carry1M.bits.trmax = 1; ++ Carry1M.bits.tr1k = 1; ++ Carry1M.bits.tr511 = 1; ++ Carry1M.bits.tr255 = 1; ++ Carry1M.bits.tr127 = 1; ++ Carry1M.bits.tr64 = 1; ++ ++ writel(Carry1M.value, &pDevMacStat->Carry1M.value); ++ } ++ ++ { ++ MAC_STAT_REG_2_t Carry2M = { 0xffffffff }; ++ ++ Carry2M.bits.tdrp = 1; ++ Carry2M.bits.tpfh = 1; ++ Carry2M.bits.tncl = 0; ++ Carry2M.bits.txcl = 1; ++ Carry2M.bits.tlcl = 0; ++ Carry2M.bits.tmcl = 0; ++ Carry2M.bits.tscl = 0; ++ Carry2M.bits.tedf = 1; ++ Carry2M.bits.tdfr = 0; ++ Carry2M.bits.txpf = 1; ++ Carry2M.bits.tbca = 1; ++ Carry2M.bits.tmca = 1; ++ Carry2M.bits.tpkt = 1; ++ Carry2M.bits.tbyt = 1; ++ Carry2M.bits.tfrg = 1; ++ Carry2M.bits.tund = 0; ++ Carry2M.bits.tovr = 0; ++ Carry2M.bits.txcf = 1; ++ Carry2M.bits.tfcs = 1; ++ Carry2M.bits.tjbr = 1; ++ ++ writel(Carry2M.value, &pDevMacStat->Carry2M.value); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void ConfigFlowControl(struct et131x_adapter * pAdapter) ++{ ++ if (pAdapter->uiDuplexMode == 0) { ++ pAdapter->FlowControl = None; ++ } else { ++ char RemotePause, RemoteAsyncPause; ++ ++ ET1310_PhyAccessMiBit(pAdapter, ++ TRUEPHY_BIT_READ, 5, 10, &RemotePause); ++ ET1310_PhyAccessMiBit(pAdapter, ++ TRUEPHY_BIT_READ, 5, 11, ++ &RemoteAsyncPause); ++ ++ if ((RemotePause == TRUEPHY_BIT_SET) && ++ (RemoteAsyncPause == TRUEPHY_BIT_SET)) { ++ pAdapter->FlowControl = pAdapter->RegistryFlowControl; ++ } else if ((RemotePause == TRUEPHY_BIT_SET) && ++ (RemoteAsyncPause == TRUEPHY_BIT_CLEAR)) { ++ if (pAdapter->RegistryFlowControl == Both) { ++ pAdapter->FlowControl = Both; ++ } else { ++ pAdapter->FlowControl = None; ++ } ++ } else if ((RemotePause == TRUEPHY_BIT_CLEAR) && ++ (RemoteAsyncPause == TRUEPHY_BIT_CLEAR)) { ++ pAdapter->FlowControl = None; ++ } else {/* if (RemotePause == TRUEPHY_CLEAR_BIT && ++ RemoteAsyncPause == TRUEPHY_SET_BIT) */ ++ if (pAdapter->RegistryFlowControl == Both) { ++ pAdapter->FlowControl = RxOnly; ++ } else { ++ pAdapter->FlowControl = None; ++ } ++ } ++ } ++} ++ ++/** ++ * UpdateMacStatHostCounters - Update the local copy of the statistics ++ * @pAdapter: pointer to the adapter structure ++ */ ++void UpdateMacStatHostCounters(struct et131x_adapter *pAdapter) ++{ ++ struct _ce_stats_t *stats = &pAdapter->Stats; ++ struct _MAC_STAT_t __iomem *pDevMacStat = ++ &pAdapter->CSRAddress->macStat; ++ ++ stats->collisions += readl(&pDevMacStat->TNcl); ++ stats->first_collision += readl(&pDevMacStat->TScl); ++ stats->tx_deferred += readl(&pDevMacStat->TDfr); ++ stats->excessive_collisions += readl(&pDevMacStat->TMcl); ++ stats->late_collisions += readl(&pDevMacStat->TLcl); ++ stats->tx_uflo += readl(&pDevMacStat->TUnd); ++ stats->max_pkt_error += readl(&pDevMacStat->TOvr); ++ ++ stats->alignment_err += readl(&pDevMacStat->RAln); ++ stats->crc_err += readl(&pDevMacStat->RCde); ++ stats->norcvbuf += readl(&pDevMacStat->RDrp); ++ stats->rx_ov_flow += readl(&pDevMacStat->ROvr); ++ stats->code_violations += readl(&pDevMacStat->RFcs); ++ stats->length_err += readl(&pDevMacStat->RFlr); ++ ++ stats->other_errors += readl(&pDevMacStat->RFrg); ++} ++ ++/** ++ * HandleMacStatInterrupt ++ * @pAdapter: pointer to the adapter structure ++ * ++ * One of the MACSTAT counters has wrapped. Update the local copy of ++ * the statistics held in the adapter structure, checking the "wrap" ++ * bit for each counter. ++ */ ++void HandleMacStatInterrupt(struct et131x_adapter *pAdapter) ++{ ++ MAC_STAT_REG_1_t Carry1; ++ MAC_STAT_REG_2_t Carry2; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Read the interrupt bits from the register(s). These are Clear On ++ * Write. ++ */ ++ Carry1.value = readl(&pAdapter->CSRAddress->macStat.Carry1.value); ++ Carry2.value = readl(&pAdapter->CSRAddress->macStat.Carry2.value); ++ ++ writel(Carry1.value, &pAdapter->CSRAddress->macStat.Carry1.value); ++ writel(Carry2.value, &pAdapter->CSRAddress->macStat.Carry2.value); ++ ++ /* We need to do update the host copy of all the MAC_STAT counters. ++ * For each counter, check it's overflow bit. If the overflow bit is ++ * set, then increment the host version of the count by one complete ++ * revolution of the counter. This routine is called when the counter ++ * block indicates that one of the counters has wrapped. ++ */ ++ if (Carry1.bits.rfcs) { ++ pAdapter->Stats.code_violations += COUNTER_WRAP_16_BIT; ++ } ++ if (Carry1.bits.raln) { ++ pAdapter->Stats.alignment_err += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry1.bits.rflr) { ++ pAdapter->Stats.length_err += COUNTER_WRAP_16_BIT; ++ } ++ if (Carry1.bits.rfrg) { ++ pAdapter->Stats.other_errors += COUNTER_WRAP_16_BIT; ++ } ++ if (Carry1.bits.rcde) { ++ pAdapter->Stats.crc_err += COUNTER_WRAP_16_BIT; ++ } ++ if (Carry1.bits.rovr) { ++ pAdapter->Stats.rx_ov_flow += COUNTER_WRAP_16_BIT; ++ } ++ if (Carry1.bits.rdrp) { ++ pAdapter->Stats.norcvbuf += COUNTER_WRAP_16_BIT; ++ } ++ if (Carry2.bits.tovr) { ++ pAdapter->Stats.max_pkt_error += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry2.bits.tund) { ++ pAdapter->Stats.tx_uflo += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry2.bits.tscl) { ++ pAdapter->Stats.first_collision += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry2.bits.tdfr) { ++ pAdapter->Stats.tx_deferred += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry2.bits.tmcl) { ++ pAdapter->Stats.excessive_collisions += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry2.bits.tlcl) { ++ pAdapter->Stats.late_collisions += COUNTER_WRAP_12_BIT; ++ } ++ if (Carry2.bits.tncl) { ++ pAdapter->Stats.collisions += COUNTER_WRAP_12_BIT; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void SetupDeviceForMulticast(struct et131x_adapter *pAdapter) ++{ ++ struct _RXMAC_t __iomem *rxmac = &pAdapter->CSRAddress->rxmac; ++ uint32_t nIndex; ++ uint32_t result; ++ uint32_t hash1 = 0; ++ uint32_t hash2 = 0; ++ uint32_t hash3 = 0; ++ uint32_t hash4 = 0; ++ PM_CSR_t pm_csr; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision ++ * the multi-cast LIST. If it is NOT specified, (and "ALL" is not ++ * specified) then we should pass NO multi-cast addresses to the ++ * driver. ++ */ ++ if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST) { ++ DBG_VERBOSE(et131x_dbginfo, ++ "MULTICAST flag is set, MCCount: %d\n", ++ pAdapter->MCAddressCount); ++ ++ /* Loop through our multicast array and set up the device */ ++ for (nIndex = 0; nIndex < pAdapter->MCAddressCount; nIndex++) { ++ DBG_VERBOSE(et131x_dbginfo, ++ "MCList[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ nIndex, ++ pAdapter->MCList[nIndex][0], ++ pAdapter->MCList[nIndex][1], ++ pAdapter->MCList[nIndex][2], ++ pAdapter->MCList[nIndex][3], ++ pAdapter->MCList[nIndex][4], ++ pAdapter->MCList[nIndex][5]); ++ ++ result = ether_crc(6, pAdapter->MCList[nIndex]); ++ ++ result = (result & 0x3F800000) >> 23; ++ ++ if (result < 32) { ++ hash1 |= (1 << result); ++ } else if ((31 < result) && (result < 64)) { ++ result -= 32; ++ hash2 |= (1 << result); ++ } else if ((63 < result) && (result < 96)) { ++ result -= 64; ++ hash3 |= (1 << result); ++ } else { ++ result -= 96; ++ hash4 |= (1 << result); ++ } ++ } ++ } ++ ++ /* Write out the new hash to the device */ ++ pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); ++ if (pm_csr.bits.pm_phy_sw_coma == 0) { ++ writel(hash1, &rxmac->multi_hash1); ++ writel(hash2, &rxmac->multi_hash2); ++ writel(hash3, &rxmac->multi_hash3); ++ writel(hash4, &rxmac->multi_hash4); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++void SetupDeviceForUnicast(struct et131x_adapter *pAdapter) ++{ ++ struct _RXMAC_t __iomem *rxmac = &pAdapter->CSRAddress->rxmac; ++ RXMAC_UNI_PF_ADDR1_t uni_pf1; ++ RXMAC_UNI_PF_ADDR2_t uni_pf2; ++ RXMAC_UNI_PF_ADDR3_t uni_pf3; ++ PM_CSR_t pm_csr; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Set up unicast packet filter reg 3 to be the first two octets of ++ * the MAC address for both address ++ * ++ * Set up unicast packet filter reg 2 to be the octets 2 - 5 of the ++ * MAC address for second address ++ * ++ * Set up unicast packet filter reg 3 to be the octets 2 - 5 of the ++ * MAC address for first address ++ */ ++ uni_pf3.bits.addr1_1 = pAdapter->CurrentAddress[0]; ++ uni_pf3.bits.addr1_2 = pAdapter->CurrentAddress[1]; ++ uni_pf3.bits.addr2_1 = pAdapter->CurrentAddress[0]; ++ uni_pf3.bits.addr2_2 = pAdapter->CurrentAddress[1]; ++ ++ uni_pf2.bits.addr2_3 = pAdapter->CurrentAddress[2]; ++ uni_pf2.bits.addr2_4 = pAdapter->CurrentAddress[3]; ++ uni_pf2.bits.addr2_5 = pAdapter->CurrentAddress[4]; ++ uni_pf2.bits.addr2_6 = pAdapter->CurrentAddress[5]; ++ ++ uni_pf1.bits.addr1_3 = pAdapter->CurrentAddress[2]; ++ uni_pf1.bits.addr1_4 = pAdapter->CurrentAddress[3]; ++ uni_pf1.bits.addr1_5 = pAdapter->CurrentAddress[4]; ++ uni_pf1.bits.addr1_6 = pAdapter->CurrentAddress[5]; ++ ++ pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); ++ if (pm_csr.bits.pm_phy_sw_coma == 0) { ++ writel(uni_pf1.value, &rxmac->uni_pf_addr1.value); ++ writel(uni_pf2.value, &rxmac->uni_pf_addr2.value); ++ writel(uni_pf3.value, &rxmac->uni_pf_addr3.value); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} +diff --git a/drivers/staging/et131x/et1310_mac.h b/drivers/staging/et131x/et1310_mac.h +new file mode 100644 +index 0000000..bd26cd3 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_mac.h +@@ -0,0 +1,93 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_mac.h - Defines, structs, enums, prototypes, etc. pertaining to the ++ * MAC. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef _ET1310_MAC_H_ ++#define _ET1310_MAC_H_ ++ ++ ++#include "et1310_address_map.h" ++ ++ ++#define COUNTER_WRAP_28_BIT 0x10000000 ++#define COUNTER_WRAP_22_BIT 0x400000 ++#define COUNTER_WRAP_16_BIT 0x10000 ++#define COUNTER_WRAP_12_BIT 0x1000 ++ ++#define COUNTER_MASK_28_BIT (COUNTER_WRAP_28_BIT - 1) ++#define COUNTER_MASK_22_BIT (COUNTER_WRAP_22_BIT - 1) ++#define COUNTER_MASK_16_BIT (COUNTER_WRAP_16_BIT - 1) ++#define COUNTER_MASK_12_BIT (COUNTER_WRAP_12_BIT - 1) ++ ++#define UPDATE_COUNTER(HostCnt,DevCnt) \ ++ HostCnt = HostCnt + DevCnt; ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++void ConfigMACRegs1(struct et131x_adapter *adapter); ++void ConfigMACRegs2(struct et131x_adapter *adapter); ++void ConfigRxMacRegs(struct et131x_adapter *adapter); ++void ConfigTxMacRegs(struct et131x_adapter *adapter); ++void ConfigMacStatRegs(struct et131x_adapter *adapter); ++void ConfigFlowControl(struct et131x_adapter *adapter); ++void UpdateMacStatHostCounters(struct et131x_adapter *adapter); ++void HandleMacStatInterrupt(struct et131x_adapter *adapter); ++void SetupDeviceForMulticast(struct et131x_adapter *adapter); ++void SetupDeviceForUnicast(struct et131x_adapter *adapter); ++ ++#endif /* _ET1310_MAC_H_ */ +diff --git a/drivers/staging/et131x/et1310_phy.c b/drivers/staging/et131x/et1310_phy.c +new file mode 100644 +index 0000000..6c4fa54 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_phy.c +@@ -0,0 +1,1281 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_phy.c - Routines for configuring and accessing the PHY ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_netdev.h" ++#include "et131x_initpci.h" ++ ++#include "et1310_address_map.h" ++#include "et1310_jagcore.h" ++#include "et1310_tx.h" ++#include "et1310_rx.h" ++#include "et1310_mac.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/* Prototypes for functions with local scope */ ++static int et131x_xcvr_init(struct et131x_adapter *adapter); ++ ++/** ++ * PhyMiRead - Read from the PHY through the MII Interface on the MAC ++ * @adapter: pointer to our private adapter structure ++ * @xcvrAddr: the address of the transciever ++ * @xcvrReg: the register to read ++ * @value: pointer to a 16-bit value in which the value will be stored ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int PhyMiRead(struct et131x_adapter *adapter, uint8_t xcvrAddr, ++ uint8_t xcvrReg, uint16_t *value) ++{ ++ struct _MAC_t __iomem *mac = &adapter->CSRAddress->mac; ++ int status = 0; ++ uint32_t delay; ++ MII_MGMT_ADDR_t miiAddr; ++ MII_MGMT_CMD_t miiCmd; ++ MII_MGMT_INDICATOR_t miiIndicator; ++ ++ /* Save a local copy of the registers we are dealing with so we can ++ * set them back ++ */ ++ miiAddr.value = readl(&mac->mii_mgmt_addr.value); ++ miiCmd.value = readl(&mac->mii_mgmt_cmd.value); ++ ++ /* Stop the current operation */ ++ writel(0, &mac->mii_mgmt_cmd.value); ++ ++ /* Set up the register we need to read from on the correct PHY */ ++ { ++ MII_MGMT_ADDR_t mii_mgmt_addr = { 0 }; ++ ++ mii_mgmt_addr.bits.phy_addr = xcvrAddr; ++ mii_mgmt_addr.bits.reg_addr = xcvrReg; ++ writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value); ++ } ++ ++ /* Kick the read cycle off */ ++ delay = 0; ++ ++ writel(0x1, &mac->mii_mgmt_cmd.value); ++ ++ do { ++ udelay(50); ++ delay++; ++ miiIndicator.value = readl(&mac->mii_mgmt_indicator.value); ++ } while ((miiIndicator.bits.not_valid || miiIndicator.bits.busy) && ++ delay < 50); ++ ++ /* If we hit the max delay, we could not read the register */ ++ if (delay >= 50) { ++ DBG_WARNING(et131x_dbginfo, ++ "xcvrReg 0x%08x could not be read\n", xcvrReg); ++ DBG_WARNING(et131x_dbginfo, "status is 0x%08x\n", ++ miiIndicator.value); ++ ++ status = -EIO; ++ } ++ ++ /* If we hit here we were able to read the register and we need to ++ * return the value to the caller ++ */ ++ /* TODO: make this stuff a simple readw()?! */ ++ { ++ MII_MGMT_STAT_t mii_mgmt_stat; ++ ++ mii_mgmt_stat.value = readl(&mac->mii_mgmt_stat.value); ++ *value = (uint16_t) mii_mgmt_stat.bits.phy_stat; ++ } ++ ++ /* Stop the read operation */ ++ writel(0, &mac->mii_mgmt_cmd.value); ++ ++ DBG_VERBOSE(et131x_dbginfo, " xcvr_addr = 0x%02x, " ++ "xcvr_reg = 0x%02x, " ++ "value = 0x%04x.\n", xcvrAddr, xcvrReg, *value); ++ ++ /* set the registers we touched back to the state at which we entered ++ * this function ++ */ ++ writel(miiAddr.value, &mac->mii_mgmt_addr.value); ++ writel(miiCmd.value, &mac->mii_mgmt_cmd.value); ++ ++ return status; ++} ++ ++/** ++ * MiWrite - Write to a PHY register through the MII interface of the MAC ++ * @adapter: pointer to our private adapter structure ++ * @xcvrReg: the register to read ++ * @value: 16-bit value to write ++ * ++ * Return 0 on success, errno on failure (as defined in errno.h) ++ */ ++int MiWrite(struct et131x_adapter *adapter, uint8_t xcvrReg, uint16_t value) ++{ ++ struct _MAC_t __iomem *mac = &adapter->CSRAddress->mac; ++ int status = 0; ++ uint8_t xcvrAddr = adapter->Stats.xcvr_addr; ++ uint32_t delay; ++ MII_MGMT_ADDR_t miiAddr; ++ MII_MGMT_CMD_t miiCmd; ++ MII_MGMT_INDICATOR_t miiIndicator; ++ ++ /* Save a local copy of the registers we are dealing with so we can ++ * set them back ++ */ ++ miiAddr.value = readl(&mac->mii_mgmt_addr.value); ++ miiCmd.value = readl(&mac->mii_mgmt_cmd.value); ++ ++ /* Stop the current operation */ ++ writel(0, &mac->mii_mgmt_cmd.value); ++ ++ /* Set up the register we need to write to on the correct PHY */ ++ { ++ MII_MGMT_ADDR_t mii_mgmt_addr; ++ ++ mii_mgmt_addr.bits.phy_addr = xcvrAddr; ++ mii_mgmt_addr.bits.reg_addr = xcvrReg; ++ writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value); ++ } ++ ++ /* Add the value to write to the registers to the mac */ ++ writel(value, &mac->mii_mgmt_ctrl.value); ++ delay = 0; ++ ++ do { ++ udelay(50); ++ delay++; ++ miiIndicator.value = readl(&mac->mii_mgmt_indicator.value); ++ } while (miiIndicator.bits.busy && delay < 100); ++ ++ /* If we hit the max delay, we could not write the register */ ++ if (delay == 100) { ++ uint16_t TempValue; ++ ++ DBG_WARNING(et131x_dbginfo, ++ "xcvrReg 0x%08x could not be written", xcvrReg); ++ DBG_WARNING(et131x_dbginfo, "status is 0x%08x\n", ++ miiIndicator.value); ++ DBG_WARNING(et131x_dbginfo, "command is 0x%08x\n", ++ readl(&mac->mii_mgmt_cmd.value)); ++ ++ MiRead(adapter, xcvrReg, &TempValue); ++ ++ status = -EIO; ++ } ++ ++ /* Stop the write operation */ ++ writel(0, &mac->mii_mgmt_cmd.value); ++ ++ /* set the registers we touched back to the state at which we entered ++ * this function ++ */ ++ writel(miiAddr.value, &mac->mii_mgmt_addr.value); ++ writel(miiCmd.value, &mac->mii_mgmt_cmd.value); ++ ++ DBG_VERBOSE(et131x_dbginfo, " xcvr_addr = 0x%02x, " ++ "xcvr_reg = 0x%02x, " ++ "value = 0x%04x.\n", xcvrAddr, xcvrReg, value); ++ ++ return status; ++} ++ ++/** ++ * et131x_xcvr_find - Find the PHY ID ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_xcvr_find(struct et131x_adapter *adapter) ++{ ++ int status = -ENODEV; ++ uint8_t xcvr_addr; ++ MI_IDR1_t idr1; ++ MI_IDR2_t idr2; ++ uint32_t xcvr_id; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* We need to get xcvr id and address we just get the first one */ ++ for (xcvr_addr = 0; xcvr_addr < 32; xcvr_addr++) { ++ /* Read the ID from the PHY */ ++ PhyMiRead(adapter, xcvr_addr, ++ (uint8_t) offsetof(MI_REGS_t, idr1), ++ &idr1.value); ++ PhyMiRead(adapter, xcvr_addr, ++ (uint8_t) offsetof(MI_REGS_t, idr2), ++ &idr2.value); ++ ++ xcvr_id = (uint32_t) ((idr1.value << 16) | idr2.value); ++ ++ if ((idr1.value != 0) && (idr1.value != 0xffff)) { ++ DBG_TRACE(et131x_dbginfo, ++ "Xcvr addr: 0x%02x\tXcvr_id: 0x%08x\n", ++ xcvr_addr, xcvr_id); ++ ++ adapter->Stats.xcvr_id = xcvr_id; ++ adapter->Stats.xcvr_addr = xcvr_addr; ++ ++ status = 0; ++ break; ++ } ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_setphy_normal - Set PHY for normal operation. ++ * @adapter: pointer to our private adapter structure ++ * ++ * Used by Power Management to force the PHY into 10 Base T half-duplex mode, ++ * when going to D3 in WOL mode. Also used during initialization to set the ++ * PHY for normal operation. ++ */ ++int et131x_setphy_normal(struct et131x_adapter *adapter) ++{ ++ int status; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Make sure the PHY is powered up */ ++ ET1310_PhyPowerDown(adapter, 0); ++ status = et131x_xcvr_init(adapter); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_xcvr_init - Init the phy if we are setting it into force mode ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++static int et131x_xcvr_init(struct et131x_adapter *adapter) ++{ ++ int status = 0; ++ MI_IMR_t imr; ++ MI_ISR_t isr; ++ MI_LCR2_t lcr2; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Zero out the adapter structure variable representing BMSR */ ++ adapter->Bmsr.value = 0; ++ ++ MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, isr), &isr.value); ++ ++ MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, imr), &imr.value); ++ ++ /* Set the link status interrupt only. Bad behavior when link status ++ * and auto neg are set, we run into a nested interrupt problem ++ */ ++ imr.bits.int_en = 0x1; ++ imr.bits.link_status = 0x1; ++ imr.bits.autoneg_status = 0x1; ++ ++ MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, imr), imr.value); ++ ++ /* Set the LED behavior such that LED 1 indicates speed (off = ++ * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates ++ * link and activity (on for link, blink off for activity). ++ * ++ * NOTE: Some customizations have been added here for specific ++ * vendors; The LED behavior is now determined by vendor data in the ++ * EEPROM. However, the above description is the default. ++ */ ++ if ((adapter->eepromData[1] & 0x4) == 0) { ++ MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2), ++ &lcr2.value); ++ if ((adapter->eepromData[1] & 0x8) == 0) ++ lcr2.bits.led_tx_rx = 0x3; ++ else ++ lcr2.bits.led_tx_rx = 0x4; ++ lcr2.bits.led_link = 0xa; ++ MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2), ++ lcr2.value); ++ } ++ ++ /* Determine if we need to go into a force mode and set it */ ++ if (adapter->AiForceSpeed == 0 && adapter->AiForceDpx == 0) { ++ if ((adapter->RegistryFlowControl == TxOnly) || ++ (adapter->RegistryFlowControl == Both)) { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_SET, 4, 11, NULL); ++ } else { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_CLEAR, 4, 11, NULL); ++ } ++ ++ if (adapter->RegistryFlowControl == Both) { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_SET, 4, 10, NULL); ++ } else { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_CLEAR, 4, 10, NULL); ++ } ++ ++ /* Set the phy to autonegotiation */ ++ ET1310_PhyAutoNeg(adapter, true); ++ ++ /* NOTE - Do we need this? */ ++ ET1310_PhyAccessMiBit(adapter, TRUEPHY_BIT_SET, 0, 9, NULL); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++ } else { ++ ET1310_PhyAutoNeg(adapter, false); ++ ++ /* Set to the correct force mode. */ ++ if (adapter->AiForceDpx != 1) { ++ if ((adapter->RegistryFlowControl == TxOnly) || ++ (adapter->RegistryFlowControl == Both)) { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_SET, 4, 11, ++ NULL); ++ } else { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_CLEAR, 4, 11, ++ NULL); ++ } ++ ++ if (adapter->RegistryFlowControl == Both) { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_SET, 4, 10, ++ NULL); ++ } else { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_CLEAR, 4, 10, ++ NULL); ++ } ++ } else { ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_CLEAR, 4, 10, NULL); ++ ET1310_PhyAccessMiBit(adapter, ++ TRUEPHY_BIT_CLEAR, 4, 11, NULL); ++ } ++ ++ switch (adapter->AiForceSpeed) { ++ case 10: ++ if (adapter->AiForceDpx == 1) { ++ TPAL_SetPhy10HalfDuplex(adapter); ++ } else if (adapter->AiForceDpx == 2) { ++ TPAL_SetPhy10FullDuplex(adapter); ++ } else { ++ TPAL_SetPhy10Force(adapter); ++ } ++ break; ++ case 100: ++ if (adapter->AiForceDpx == 1) { ++ TPAL_SetPhy100HalfDuplex(adapter); ++ } else if (adapter->AiForceDpx == 2) { ++ TPAL_SetPhy100FullDuplex(adapter); ++ } else { ++ TPAL_SetPhy100Force(adapter); ++ } ++ break; ++ case 1000: ++ TPAL_SetPhy1000FullDuplex(adapter); ++ break; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++ } ++} ++ ++void et131x_Mii_check(struct et131x_adapter *pAdapter, ++ MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints) ++{ ++ uint8_t ucLinkStatus; ++ uint32_t uiAutoNegStatus; ++ uint32_t uiSpeed; ++ uint32_t uiDuplex; ++ uint32_t uiMdiMdix; ++ uint32_t uiMasterSlave; ++ uint32_t uiPolarity; ++ unsigned long lockflags; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ if (bmsr_ints.bits.link_status) { ++ if (bmsr.bits.link_status) { ++ pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20; ++ ++ /* Update our state variables and indicate the ++ * connected state ++ */ ++ spin_lock_irqsave(&pAdapter->Lock, lockflags); ++ ++ pAdapter->MediaState = NETIF_STATUS_MEDIA_CONNECT; ++ MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION); ++ ++ spin_unlock_irqrestore(&pAdapter->Lock, lockflags); ++ ++ /* Don't indicate state if we're in loopback mode */ ++ if (pAdapter->RegistryPhyLoopbk == false) { ++ netif_carrier_on(pAdapter->netdev); ++ } ++ } else { ++ DBG_WARNING(et131x_dbginfo, ++ "Link down cable problem\n"); ++ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS) { ++ // NOTE - Is there a way to query this without TruePHY? ++ // && TRU_QueryCoreType(pAdapter->hTruePhy, 0) == EMI_TRUEPHY_A13O) { ++ uint16_t Register18; ++ ++ MiRead(pAdapter, 0x12, &Register18); ++ MiWrite(pAdapter, 0x12, Register18 | 0x4); ++ MiWrite(pAdapter, 0x10, Register18 | 0x8402); ++ MiWrite(pAdapter, 0x11, Register18 | 511); ++ MiWrite(pAdapter, 0x12, Register18); ++ } ++ ++ /* For the first N seconds of life, we are in "link ++ * detection" When we are in this state, we should ++ * only report "connected". When the LinkDetection ++ * Timer expires, we can report disconnected (handled ++ * in the LinkDetectionDPC). ++ */ ++ if ((MP_IS_FLAG_CLEAR ++ (pAdapter, fMP_ADAPTER_LINK_DETECTION)) ++ || (pAdapter->MediaState == ++ NETIF_STATUS_MEDIA_DISCONNECT)) { ++ spin_lock_irqsave(&pAdapter->Lock, lockflags); ++ pAdapter->MediaState = ++ NETIF_STATUS_MEDIA_DISCONNECT; ++ spin_unlock_irqrestore(&pAdapter->Lock, ++ lockflags); ++ ++ /* Only indicate state if we're in loopback ++ * mode ++ */ ++ if (pAdapter->RegistryPhyLoopbk == false) { ++ netif_carrier_off(pAdapter->netdev); ++ } ++ } ++ ++ pAdapter->uiLinkSpeed = 0; ++ pAdapter->uiDuplexMode = 0; ++ ++ /* Free the packets being actively sent & stopped */ ++ et131x_free_busy_send_packets(pAdapter); ++ ++ /* Re-initialize the send structures */ ++ et131x_init_send(pAdapter); ++ ++ /* Reset the RFD list and re-start RU */ ++ et131x_reset_recv(pAdapter); ++ ++ /* ++ * Bring the device back to the state it was during ++ * init prior to autonegotiation being complete. This ++ * way, when we get the auto-neg complete interrupt, ++ * we can complete init by calling ConfigMacREGS2. ++ */ ++ et131x_soft_reset(pAdapter); ++ ++ /* Setup ET1310 as per the documentation */ ++ et131x_adapter_setup(pAdapter); ++ ++ /* Setup the PHY into coma mode until the cable is ++ * plugged back in ++ */ ++ if (pAdapter->RegistryPhyComa == 1) { ++ EnablePhyComa(pAdapter); ++ } ++ } ++ } ++ ++ if (bmsr_ints.bits.auto_neg_complete || ++ ((pAdapter->AiForceDpx == 3) && (bmsr_ints.bits.link_status))) { ++ if (bmsr.bits.auto_neg_complete || (pAdapter->AiForceDpx == 3)) { ++ ET1310_PhyLinkStatus(pAdapter, ++ &ucLinkStatus, &uiAutoNegStatus, ++ &uiSpeed, &uiDuplex, &uiMdiMdix, ++ &uiMasterSlave, &uiPolarity); ++ ++ pAdapter->uiLinkSpeed = uiSpeed; ++ pAdapter->uiDuplexMode = uiDuplex; ++ ++ DBG_TRACE(et131x_dbginfo, ++ "pAdapter->uiLinkSpeed 0x%04x, pAdapter->uiDuplex 0x%08x\n", ++ pAdapter->uiLinkSpeed, ++ pAdapter->uiDuplexMode); ++ ++ pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20; ++ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS) { ++ // NOTE - Is there a way to query this without TruePHY? ++ // && TRU_QueryCoreType(pAdapter->hTruePhy, 0) == EMI_TRUEPHY_A13O) { ++ uint16_t Register18; ++ ++ MiRead(pAdapter, 0x12, &Register18); ++ MiWrite(pAdapter, 0x12, Register18 | 0x4); ++ MiWrite(pAdapter, 0x10, Register18 | 0x8402); ++ MiWrite(pAdapter, 0x11, Register18 | 511); ++ MiWrite(pAdapter, 0x12, Register18); ++ } ++ ++ ConfigFlowControl(pAdapter); ++ ++ if ((pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) && ++ (pAdapter->RegistryJumboPacket > 2048)) ++ { ++ ET1310_PhyAndOrReg(pAdapter, 0x16, 0xcfff, ++ 0x2000); ++ } ++ ++ SetRxDmaTimer(pAdapter); ++ ConfigMACRegs2(pAdapter); ++ } ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy10HalfDuplex - Force the phy into 10 Base T Half Duplex mode. ++ * @pAdapter: pointer to the adapter structure ++ * ++ * Also sets the MAC so it is syncd up properly ++ */ ++void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* First we need to turn off all other advertisement */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* Set our advertise values accordingly */ ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_HALF); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy10FullDuplex - Force the phy into 10 Base T Full Duplex mode. ++ * @pAdapter: pointer to the adapter structure ++ * ++ * Also sets the MAC so it is syncd up properly ++ */ ++void TPAL_SetPhy10FullDuplex(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* First we need to turn off all other advertisement */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* Set our advertise values accordingly */ ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy10Force - Force Base-T FD mode WITHOUT using autonegotiation ++ * @pAdapter: pointer to the adapter structure ++ */ ++void TPAL_SetPhy10Force(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* Disable autoneg */ ++ ET1310_PhyAutoNeg(pAdapter, false); ++ ++ /* Disable all advertisement */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* Force 10 Mbps */ ++ ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_10MBPS); ++ ++ /* Force Full duplex */ ++ ET1310_PhyDuplexMode(pAdapter, TRUEPHY_DUPLEX_FULL); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy100HalfDuplex - Force 100 Base T Half Duplex mode. ++ * @pAdapter: pointer to the adapter structure ++ * ++ * Also sets the MAC so it is syncd up properly. ++ */ ++void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* first we need to turn off all other advertisement */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* Set our advertise values accordingly */ ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_HALF); ++ ++ /* Set speed */ ++ ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_100MBPS); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy100FullDuplex - Force 100 Base T Full Duplex mode. ++ * @pAdapter: pointer to the adapter structure ++ * ++ * Also sets the MAC so it is syncd up properly ++ */ ++void TPAL_SetPhy100FullDuplex(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* First we need to turn off all other advertisement */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* Set our advertise values accordingly */ ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy100Force - Force 100 BaseT FD mode WITHOUT using autonegotiation ++ * @pAdapter: pointer to the adapter structure ++ */ ++void TPAL_SetPhy100Force(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* Disable autoneg */ ++ ET1310_PhyAutoNeg(pAdapter, false); ++ ++ /* Disable all advertisement */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* Force 100 Mbps */ ++ ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_100MBPS); ++ ++ /* Force Full duplex */ ++ ET1310_PhyDuplexMode(pAdapter, TRUEPHY_DUPLEX_FULL); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhy1000FullDuplex - Force 1000 Base T Full Duplex mode ++ * @pAdapter: pointer to the adapter structure ++ * ++ * Also sets the MAC so it is syncd up properly. ++ */ ++void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* first we need to turn off all other advertisement */ ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ ++ /* set our advertise values accordingly */ ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); ++ ++ /* power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * TPAL_SetPhyAutoNeg - Set phy to autonegotiation mode. ++ * @pAdapter: pointer to the adapter structure ++ */ ++void TPAL_SetPhyAutoNeg(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* Turn on advertisement of all capabilities */ ++ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_BOTH); ++ ++ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_BOTH); ++ ++ if (pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST) { ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); ++ } else { ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ } ++ ++ /* Make sure auto-neg is ON (it is disabled in FORCE modes) */ ++ ET1310_PhyAutoNeg(pAdapter, true); ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++ ++/* ++ * The routines which follow provide low-level access to the PHY, and are used ++ * primarily by the routines above (although there are a few places elsewhere ++ * in the driver where this level of access is required). ++ */ ++ ++static const uint16_t ConfigPhy[25][2] = { ++ /* Reg Value Register */ ++ /* Addr */ ++ {0x880B, 0x0926}, /* AfeIfCreg4B1000Msbs */ ++ {0x880C, 0x0926}, /* AfeIfCreg4B100Msbs */ ++ {0x880D, 0x0926}, /* AfeIfCreg4B10Msbs */ ++ ++ {0x880E, 0xB4D3}, /* AfeIfCreg4B1000Lsbs */ ++ {0x880F, 0xB4D3}, /* AfeIfCreg4B100Lsbs */ ++ {0x8810, 0xB4D3}, /* AfeIfCreg4B10Lsbs */ ++ ++ {0x8805, 0xB03E}, /* AfeIfCreg3B1000Msbs */ ++ {0x8806, 0xB03E}, /* AfeIfCreg3B100Msbs */ ++ {0x8807, 0xFF00}, /* AfeIfCreg3B10Msbs */ ++ ++ {0x8808, 0xE090}, /* AfeIfCreg3B1000Lsbs */ ++ {0x8809, 0xE110}, /* AfeIfCreg3B100Lsbs */ ++ {0x880A, 0x0000}, /* AfeIfCreg3B10Lsbs */ ++ ++ {0x300D, 1}, /* DisableNorm */ ++ ++ {0x280C, 0x0180}, /* LinkHoldEnd */ ++ ++ {0x1C21, 0x0002}, /* AlphaM */ ++ ++ {0x3821, 6}, /* FfeLkgTx0 */ ++ {0x381D, 1}, /* FfeLkg1g4 */ ++ {0x381E, 1}, /* FfeLkg1g5 */ ++ {0x381F, 1}, /* FfeLkg1g6 */ ++ {0x3820, 1}, /* FfeLkg1g7 */ ++ ++ {0x8402, 0x01F0}, /* Btinact */ ++ {0x800E, 20}, /* LftrainTime */ ++ {0x800F, 24}, /* DvguardTime */ ++ {0x8010, 46}, /* IdlguardTime */ ++ ++ {0, 0} ++ ++}; ++ ++/* condensed version of the phy initialization routine */ ++void ET1310_PhyInit(struct et131x_adapter *pAdapter) ++{ ++ uint16_t usData, usIndex; ++ ++ if (pAdapter == NULL) { ++ return; ++ } ++ ++ // get the identity (again ?) ++ MiRead(pAdapter, PHY_ID_1, &usData); ++ MiRead(pAdapter, PHY_ID_2, &usData); ++ ++ // what does this do/achieve ? ++ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002 ++ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0006); ++ ++ // read modem register 0402, should I do something with the return data ? ++ MiWrite(pAdapter, PHY_INDEX_REG, 0x0402); ++ MiRead(pAdapter, PHY_DATA_REG, &usData); ++ ++ // what does this do/achieve ? ++ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002); ++ ++ // get the identity (again ?) ++ MiRead(pAdapter, PHY_ID_1, &usData); ++ MiRead(pAdapter, PHY_ID_2, &usData); ++ ++ // what does this achieve ? ++ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002 ++ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0006); ++ ++ // read modem register 0402, should I do something with the return data? ++ MiWrite(pAdapter, PHY_INDEX_REG, 0x0402); ++ MiRead(pAdapter, PHY_DATA_REG, &usData); ++ ++ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002); ++ ++ // what does this achieve (should return 0x1040) ++ MiRead(pAdapter, PHY_CONTROL, &usData); ++ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002 ++ MiWrite(pAdapter, PHY_CONTROL, 0x1840); ++ ++ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0007); ++ ++ // here the writing of the array starts.... ++ usIndex = 0; ++ while (ConfigPhy[usIndex][0] != 0x0000) { ++ // write value ++ MiWrite(pAdapter, PHY_INDEX_REG, ConfigPhy[usIndex][0]); ++ MiWrite(pAdapter, PHY_DATA_REG, ConfigPhy[usIndex][1]); ++ ++ // read it back ++ MiWrite(pAdapter, PHY_INDEX_REG, ConfigPhy[usIndex][0]); ++ MiRead(pAdapter, PHY_DATA_REG, &usData); ++ ++ // do a check on the value read back ? ++ usIndex++; ++ } ++ // here the writing of the array ends... ++ ++ MiRead(pAdapter, PHY_CONTROL, &usData); // 0x1840 ++ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0007 ++ MiWrite(pAdapter, PHY_CONTROL, 0x1040); ++ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002); ++} ++ ++void ET1310_PhyReset(struct et131x_adapter *pAdapter) ++{ ++ MiWrite(pAdapter, PHY_CONTROL, 0x8000); ++} ++ ++void ET1310_PhyPowerDown(struct et131x_adapter *pAdapter, bool down) ++{ ++ uint16_t usData; ++ ++ MiRead(pAdapter, PHY_CONTROL, &usData); ++ ++ if (down == false) { ++ // Power UP ++ usData &= ~0x0800; ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++ } else { ++ // Power DOWN ++ usData |= 0x0800; ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++ } ++} ++ ++void ET1310_PhyAutoNeg(struct et131x_adapter *pAdapter, bool enable) ++{ ++ uint16_t usData; ++ ++ MiRead(pAdapter, PHY_CONTROL, &usData); ++ ++ if (enable == true) { ++ // Autonegotiation ON ++ usData |= 0x1000; ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++ } else { ++ // Autonegotiation OFF ++ usData &= ~0x1000; ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++ } ++} ++ ++void ET1310_PhyDuplexMode(struct et131x_adapter *pAdapter, uint16_t duplex) ++{ ++ uint16_t usData; ++ ++ MiRead(pAdapter, PHY_CONTROL, &usData); ++ ++ if (duplex == TRUEPHY_DUPLEX_FULL) { ++ // Set Full Duplex ++ usData |= 0x100; ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++ } else { ++ // Set Half Duplex ++ usData &= ~0x100; ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++ } ++} ++ ++void ET1310_PhySpeedSelect(struct et131x_adapter *pAdapter, uint16_t speed) ++{ ++ uint16_t usData; ++ ++ // Read the PHY control register ++ MiRead(pAdapter, PHY_CONTROL, &usData); ++ ++ // Clear all Speed settings (Bits 6, 13) ++ usData &= ~0x2040; ++ ++ // Reset the speed bits based on user selection ++ switch (speed) { ++ case TRUEPHY_SPEED_10MBPS: ++ // Bits already cleared above, do nothing ++ break; ++ ++ case TRUEPHY_SPEED_100MBPS: ++ // 100M == Set bit 13 ++ usData |= 0x2000; ++ break; ++ ++ case TRUEPHY_SPEED_1000MBPS: ++ default: ++ usData |= 0x0040; ++ break; ++ } ++ ++ // Write back the new speed ++ MiWrite(pAdapter, PHY_CONTROL, usData); ++} ++ ++void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *pAdapter, ++ uint16_t duplex) ++{ ++ uint16_t usData; ++ ++ // Read the PHY 1000 Base-T Control Register ++ MiRead(pAdapter, PHY_1000_CONTROL, &usData); ++ ++ // Clear Bits 8,9 ++ usData &= ~0x0300; ++ ++ switch (duplex) { ++ case TRUEPHY_ADV_DUPLEX_NONE: ++ // Duplex already cleared, do nothing ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_FULL: ++ // Set Bit 9 ++ usData |= 0x0200; ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_HALF: ++ // Set Bit 8 ++ usData |= 0x0100; ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_BOTH: ++ default: ++ usData |= 0x0300; ++ break; ++ } ++ ++ // Write back advertisement ++ MiWrite(pAdapter, PHY_1000_CONTROL, usData); ++} ++ ++void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *pAdapter, ++ uint16_t duplex) ++{ ++ uint16_t usData; ++ ++ // Read the Autonegotiation Register (10/100) ++ MiRead(pAdapter, PHY_AUTO_ADVERTISEMENT, &usData); ++ ++ // Clear bits 7,8 ++ usData &= ~0x0180; ++ ++ switch (duplex) { ++ case TRUEPHY_ADV_DUPLEX_NONE: ++ // Duplex already cleared, do nothing ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_FULL: ++ // Set Bit 8 ++ usData |= 0x0100; ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_HALF: ++ // Set Bit 7 ++ usData |= 0x0080; ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_BOTH: ++ default: ++ // Set Bits 7,8 ++ usData |= 0x0180; ++ break; ++ } ++ ++ // Write back advertisement ++ MiWrite(pAdapter, PHY_AUTO_ADVERTISEMENT, usData); ++} ++ ++void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *pAdapter, ++ uint16_t duplex) ++{ ++ uint16_t usData; ++ ++ // Read the Autonegotiation Register (10/100) ++ MiRead(pAdapter, PHY_AUTO_ADVERTISEMENT, &usData); ++ ++ // Clear bits 5,6 ++ usData &= ~0x0060; ++ ++ switch (duplex) { ++ case TRUEPHY_ADV_DUPLEX_NONE: ++ // Duplex already cleared, do nothing ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_FULL: ++ // Set Bit 6 ++ usData |= 0x0040; ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_HALF: ++ // Set Bit 5 ++ usData |= 0x0020; ++ break; ++ ++ case TRUEPHY_ADV_DUPLEX_BOTH: ++ default: ++ // Set Bits 5,6 ++ usData |= 0x0060; ++ break; ++ } ++ ++ // Write back advertisement ++ MiWrite(pAdapter, PHY_AUTO_ADVERTISEMENT, usData); ++} ++ ++void ET1310_PhyLinkStatus(struct et131x_adapter *pAdapter, ++ uint8_t *ucLinkStatus, ++ uint32_t *uiAutoNeg, ++ uint32_t *uiLinkSpeed, ++ uint32_t *uiDuplexMode, ++ uint32_t *uiMdiMdix, ++ uint32_t *uiMasterSlave, uint32_t *uiPolarity) ++{ ++ uint16_t usMiStatus = 0; ++ uint16_t us1000BaseT = 0; ++ uint16_t usVmiPhyStatus = 0; ++ uint16_t usControl = 0; ++ ++ MiRead(pAdapter, PHY_STATUS, &usMiStatus); ++ MiRead(pAdapter, PHY_1000_STATUS, &us1000BaseT); ++ MiRead(pAdapter, PHY_PHY_STATUS, &usVmiPhyStatus); ++ MiRead(pAdapter, PHY_CONTROL, &usControl); ++ ++ if (ucLinkStatus) { ++ *ucLinkStatus = ++ (unsigned char)((usVmiPhyStatus & 0x0040) ? 1 : 0); ++ } ++ ++ if (uiAutoNeg) { ++ *uiAutoNeg = ++ (usControl & 0x1000) ? ((usVmiPhyStatus & 0x0020) ? ++ TRUEPHY_ANEG_COMPLETE : ++ TRUEPHY_ANEG_NOT_COMPLETE) : ++ TRUEPHY_ANEG_DISABLED; ++ } ++ ++ if (uiLinkSpeed) { ++ *uiLinkSpeed = (usVmiPhyStatus & 0x0300) >> 8; ++ } ++ ++ if (uiDuplexMode) { ++ *uiDuplexMode = (usVmiPhyStatus & 0x0080) >> 7; ++ } ++ ++ if (uiMdiMdix) { ++ /* NOTE: Need to complete this */ ++ *uiMdiMdix = 0; ++ } ++ ++ if (uiMasterSlave) { ++ *uiMasterSlave = ++ (us1000BaseT & 0x4000) ? TRUEPHY_CFG_MASTER : ++ TRUEPHY_CFG_SLAVE; ++ } ++ ++ if (uiPolarity) { ++ *uiPolarity = ++ (usVmiPhyStatus & 0x0400) ? TRUEPHY_POLARITY_INVERTED : ++ TRUEPHY_POLARITY_NORMAL; ++ } ++} ++ ++void ET1310_PhyAndOrReg(struct et131x_adapter *pAdapter, ++ uint16_t regnum, uint16_t andMask, uint16_t orMask) ++{ ++ uint16_t reg; ++ ++ // Read the requested register ++ MiRead(pAdapter, regnum, ®); ++ ++ // Apply the AND mask ++ reg &= andMask; ++ ++ // Apply the OR mask ++ reg |= orMask; ++ ++ // Write the value back to the register ++ MiWrite(pAdapter, regnum, reg); ++} ++ ++void ET1310_PhyAccessMiBit(struct et131x_adapter *pAdapter, uint16_t action, ++ uint16_t regnum, uint16_t bitnum, uint8_t *value) ++{ ++ uint16_t reg; ++ uint16_t mask = 0; ++ ++ // Create a mask to isolate the requested bit ++ mask = 0x0001 << bitnum; ++ ++ // Read the requested register ++ MiRead(pAdapter, regnum, ®); ++ ++ switch (action) { ++ case TRUEPHY_BIT_READ: ++ if (value != NULL) { ++ *value = (reg & mask) >> bitnum; ++ } ++ break; ++ ++ case TRUEPHY_BIT_SET: ++ reg |= mask; ++ MiWrite(pAdapter, regnum, reg); ++ break; ++ ++ case TRUEPHY_BIT_CLEAR: ++ reg &= ~mask; ++ MiWrite(pAdapter, regnum, reg); ++ break; ++ ++ default: ++ break; ++ } ++} +diff --git a/drivers/staging/et131x/et1310_phy.h b/drivers/staging/et131x/et1310_phy.h +new file mode 100644 +index 0000000..d624cbb +--- /dev/null ++++ b/drivers/staging/et131x/et1310_phy.h +@@ -0,0 +1,910 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_phy.h - Defines, structs, enums, prototypes, etc. pertaining to the ++ * PHY. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef _ET1310_PHY_H_ ++#define _ET1310_PHY_H_ ++ ++#include "et1310_address_map.h" ++ ++#define TRUEPHY_SUCCESS 0 ++#define TRUEPHY_FAILURE 1 ++typedef void *TRUEPHY_HANDLE; ++typedef void *TRUEPHY_PLATFORM_HANDLE; ++typedef void *TRUEPHY_OSAL_HANDLE; ++ ++/* MI Register Addresses */ ++#define MI_CONTROL_REG 0 ++#define MI_STATUS_REG 1 ++#define MI_PHY_IDENTIFIER_1_REG 2 ++#define MI_PHY_IDENTIFIER_2_REG 3 ++#define MI_AUTONEG_ADVERTISEMENT_REG 4 ++#define MI_AUTONEG_LINK_PARTNER_ABILITY_REG 5 ++#define MI_AUTONEG_EXPANSION_REG 6 ++#define MI_AUTONEG_NEXT_PAGE_TRANSMIT_REG 7 ++#define MI_LINK_PARTNER_NEXT_PAGE_REG 8 ++#define MI_1000BASET_CONTROL_REG 9 ++#define MI_1000BASET_STATUS_REG 10 ++#define MI_RESERVED11_REG 11 ++#define MI_RESERVED12_REG 12 ++#define MI_RESERVED13_REG 13 ++#define MI_RESERVED14_REG 14 ++#define MI_EXTENDED_STATUS_REG 15 ++ ++/* VMI Register Addresses */ ++#define VMI_RESERVED16_REG 16 ++#define VMI_RESERVED17_REG 17 ++#define VMI_RESERVED18_REG 18 ++#define VMI_LOOPBACK_CONTROL_REG 19 ++#define VMI_RESERVED20_REG 20 ++#define VMI_MI_CONTROL_REG 21 ++#define VMI_PHY_CONFIGURATION_REG 22 ++#define VMI_PHY_CONTROL_REG 23 ++#define VMI_INTERRUPT_MASK_REG 24 ++#define VMI_INTERRUPT_STATUS_REG 25 ++#define VMI_PHY_STATUS_REG 26 ++#define VMI_LED_CONTROL_1_REG 27 ++#define VMI_LED_CONTROL_2_REG 28 ++#define VMI_RESERVED29_REG 29 ++#define VMI_RESERVED30_REG 30 ++#define VMI_RESERVED31_REG 31 ++ ++/* PHY Register Mapping(MI) Management Interface Regs */ ++typedef struct _MI_REGS_t { ++ u8 bmcr; // Basic mode control reg(Reg 0x00) ++ u8 bmsr; // Basic mode status reg(Reg 0x01) ++ u8 idr1; // Phy identifier reg 1(Reg 0x02) ++ u8 idr2; // Phy identifier reg 2(Reg 0x03) ++ u8 anar; // Auto-Negotiation advertisement(Reg 0x04) ++ u8 anlpar; // Auto-Negotiation link Partner Ability(Reg 0x05) ++ u8 aner; // Auto-Negotiation expansion reg(Reg 0x06) ++ u8 annptr; // Auto-Negotiation next page transmit reg(Reg 0x07) ++ u8 lpnpr; // link partner next page reg(Reg 0x08) ++ u8 gcr; // Gigabit basic mode control reg(Reg 0x09) ++ u8 gsr; // Gigabit basic mode status reg(Reg 0x0A) ++ u8 mi_res1[4]; // Future use by MI working group(Reg 0x0B - 0x0E) ++ u8 esr; // Extended status reg(Reg 0x0F) ++ u8 mi_res2[3]; // Future use by MI working group(Reg 0x10 - 0x12) ++ u8 loop_ctl; // Loopback Control Reg(Reg 0x13) ++ u8 mi_res3; // Future use by MI working group(Reg 0x14) ++ u8 mcr; // MI Control Reg(Reg 0x15) ++ u8 pcr; // Configuration Reg(Reg 0x16) ++ u8 phy_ctl; // PHY Control Reg(Reg 0x17) ++ u8 imr; // Interrupt Mask Reg(Reg 0x18) ++ u8 isr; // Interrupt Status Reg(Reg 0x19) ++ u8 psr; // PHY Status Reg(Reg 0x1A) ++ u8 lcr1; // LED Control 1 Reg(Reg 0x1B) ++ u8 lcr2; // LED Control 2 Reg(Reg 0x1C) ++ u8 mi_res4[3]; // Future use by MI working group(Reg 0x1D - 0x1F) ++} MI_REGS_t, *PMI_REGS_t; ++ ++/* MI Register 0: Basic mode control register */ ++typedef union _MI_BMCR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 reset:1; // bit 15 ++ u16 loopback:1; // bit 14 ++ u16 speed_sel:1; // bit 13 ++ u16 enable_autoneg:1; // bit 12 ++ u16 power_down:1; // bit 11 ++ u16 isolate:1; // bit 10 ++ u16 restart_autoneg:1; // bit 9 ++ u16 duplex_mode:1; // bit 8 ++ u16 col_test:1; // bit 7 ++ u16 speed_1000_sel:1; // bit 6 ++ u16 res1:6; // bits 0-5 ++#else ++ u16 res1:6; // bits 0-5 ++ u16 speed_1000_sel:1; // bit 6 ++ u16 col_test:1; // bit 7 ++ u16 duplex_mode:1; // bit 8 ++ u16 restart_autoneg:1; // bit 9 ++ u16 isolate:1; // bit 10 ++ u16 power_down:1; // bit 11 ++ u16 enable_autoneg:1; // bit 12 ++ u16 speed_sel:1; // bit 13 ++ u16 loopback:1; // bit 14 ++ u16 reset:1; // bit 15 ++#endif ++ } bits; ++} MI_BMCR_t, *PMI_BMCR_t; ++ ++/* MI Register 1: Basic mode status register */ ++typedef union _MI_BMSR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 link_100T4:1; // bit 15 ++ u16 link_100fdx:1; // bit 14 ++ u16 link_100hdx:1; // bit 13 ++ u16 link_10fdx:1; // bit 12 ++ u16 link_10hdx:1; // bit 11 ++ u16 link_100T2fdx:1; // bit 10 ++ u16 link_100T2hdx:1; // bit 9 ++ u16 extend_status:1; // bit 8 ++ u16 res1:1; // bit 7 ++ u16 preamble_supress:1; // bit 6 ++ u16 auto_neg_complete:1; // bit 5 ++ u16 remote_fault:1; // bit 4 ++ u16 auto_neg_able:1; // bit 3 ++ u16 link_status:1; // bit 2 ++ u16 jabber_detect:1; // bit 1 ++ u16 ext_cap:1; // bit 0 ++#else ++ u16 ext_cap:1; // bit 0 ++ u16 jabber_detect:1; // bit 1 ++ u16 link_status:1; // bit 2 ++ u16 auto_neg_able:1; // bit 3 ++ u16 remote_fault:1; // bit 4 ++ u16 auto_neg_complete:1; // bit 5 ++ u16 preamble_supress:1; // bit 6 ++ u16 res1:1; // bit 7 ++ u16 extend_status:1; // bit 8 ++ u16 link_100T2hdx:1; // bit 9 ++ u16 link_100T2fdx:1; // bit 10 ++ u16 link_10hdx:1; // bit 11 ++ u16 link_10fdx:1; // bit 12 ++ u16 link_100hdx:1; // bit 13 ++ u16 link_100fdx:1; // bit 14 ++ u16 link_100T4:1; // bit 15 ++#endif ++ } bits; ++} MI_BMSR_t, *PMI_BMSR_t; ++ ++/* MI Register 2: Physical Identifier 1 */ ++typedef union _MI_IDR1_t { ++ u16 value; ++ struct { ++ u16 ieee_address:16; // 0x0282 default(bits 0-15) ++ } bits; ++} MI_IDR1_t, *PMI_IDR1_t; ++ ++/* MI Register 3: Physical Identifier 2 */ ++typedef union _MI_IDR2_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 ieee_address:6; // 111100 default(bits 10-15) ++ u16 model_no:6; // 000001 default(bits 4-9) ++ u16 rev_no:4; // 0010 default(bits 0-3) ++#else ++ u16 rev_no:4; // 0010 default(bits 0-3) ++ u16 model_no:6; // 000001 default(bits 4-9) ++ u16 ieee_address:6; // 111100 default(bits 10-15) ++#endif ++ } bits; ++} MI_IDR2_t, *PMI_IDR2_t; ++ ++/* MI Register 4: Auto-negotiation advertisement register */ ++typedef union _MI_ANAR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 np_indication:1; // bit 15 ++ u16 res2:1; // bit 14 ++ u16 remote_fault:1; // bit 13 ++ u16 res1:1; // bit 12 ++ u16 cap_asmpause:1; // bit 11 ++ u16 cap_pause:1; // bit 10 ++ u16 cap_100T4:1; // bit 9 ++ u16 cap_100fdx:1; // bit 8 ++ u16 cap_100hdx:1; // bit 7 ++ u16 cap_10fdx:1; // bit 6 ++ u16 cap_10hdx:1; // bit 5 ++ u16 selector:5; // bits 0-4 ++#else ++ u16 selector:5; // bits 0-4 ++ u16 cap_10hdx:1; // bit 5 ++ u16 cap_10fdx:1; // bit 6 ++ u16 cap_100hdx:1; // bit 7 ++ u16 cap_100fdx:1; // bit 8 ++ u16 cap_100T4:1; // bit 9 ++ u16 cap_pause:1; // bit 10 ++ u16 cap_asmpause:1; // bit 11 ++ u16 res1:1; // bit 12 ++ u16 remote_fault:1; // bit 13 ++ u16 res2:1; // bit 14 ++ u16 np_indication:1; // bit 15 ++#endif ++ } bits; ++} MI_ANAR_t, *PMI_ANAR_t; ++ ++/* MI Register 5: Auto-negotiation link partner advertisement register */ ++typedef struct _MI_ANLPAR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 np_indication:1; // bit 15 ++ u16 acknowledge:1; // bit 14 ++ u16 remote_fault:1; // bit 13 ++ u16 res1:1; // bit 12 ++ u16 cap_asmpause:1; // bit 11 ++ u16 cap_pause:1; // bit 10 ++ u16 cap_100T4:1; // bit 9 ++ u16 cap_100fdx:1; // bit 8 ++ u16 cap_100hdx:1; // bit 7 ++ u16 cap_10fdx:1; // bit 6 ++ u16 cap_10hdx:1; // bit 5 ++ u16 selector:5; // bits 0-4 ++#else ++ u16 selector:5; // bits 0-4 ++ u16 cap_10hdx:1; // bit 5 ++ u16 cap_10fdx:1; // bit 6 ++ u16 cap_100hdx:1; // bit 7 ++ u16 cap_100fdx:1; // bit 8 ++ u16 cap_100T4:1; // bit 9 ++ u16 cap_pause:1; // bit 10 ++ u16 cap_asmpause:1; // bit 11 ++ u16 res1:1; // bit 12 ++ u16 remote_fault:1; // bit 13 ++ u16 acknowledge:1; // bit 14 ++ u16 np_indication:1; // bit 15 ++#endif ++ } bits; ++} MI_ANLPAR_t, *PMI_ANLPAR_t; ++ ++/* MI Register 6: Auto-negotiation expansion register */ ++typedef union _MI_ANER_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res:11; // bits 5-15 ++ u16 pdf:1; // bit 4 ++ u16 lp_np_able:1; // bit 3 ++ u16 np_able:1; // bit 2 ++ u16 page_rx:1; // bit 1 ++ u16 lp_an_able:1; // bit 0 ++#else ++ u16 lp_an_able:1; // bit 0 ++ u16 page_rx:1; // bit 1 ++ u16 np_able:1; // bit 2 ++ u16 lp_np_able:1; // bit 3 ++ u16 pdf:1; // bit 4 ++ u16 res:11; // bits 5-15 ++#endif ++ } bits; ++} MI_ANER_t, *PMI_ANER_t; ++ ++/* MI Register 7: Auto-negotiation next page transmit reg(0x07) */ ++typedef union _MI_ANNPTR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 np:1; // bit 15 ++ u16 res1:1; // bit 14 ++ u16 msg_page:1; // bit 13 ++ u16 ack2:1; // bit 12 ++ u16 toggle:1; // bit 11 ++ u16 msg:11; // bits 0-10 ++#else ++ u16 msg:11; // bits 0-10 ++ u16 toggle:1; // bit 11 ++ u16 ack2:1; // bit 12 ++ u16 msg_page:1; // bit 13 ++ u16 res1:1; // bit 14 ++ u16 np:1; // bit 15 ++#endif ++ } bits; ++} MI_ANNPTR_t, *PMI_ANNPTR_t; ++ ++/* MI Register 8: Link Partner Next Page Reg(0x08) */ ++typedef union _MI_LPNPR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 np:1; // bit 15 ++ u16 ack:1; // bit 14 ++ u16 msg_page:1; // bit 13 ++ u16 ack2:1; // bit 12 ++ u16 toggle:1; // bit 11 ++ u16 msg:11; // bits 0-10 ++#else ++ u16 msg:11; // bits 0-10 ++ u16 toggle:1; // bit 11 ++ u16 ack2:1; // bit 12 ++ u16 msg_page:1; // bit 13 ++ u16 ack:1; // bit 14 ++ u16 np:1; // bit 15 ++#endif ++ } bits; ++} MI_LPNPR_t, *PMI_LPNPR_t; ++ ++/* MI Register 9: 1000BaseT Control Reg(0x09) */ ++typedef union _MI_GCR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 test_mode:3; // bits 13-15 ++ u16 ms_config_en:1; // bit 12 ++ u16 ms_value:1; // bit 11 ++ u16 port_type:1; // bit 10 ++ u16 link_1000fdx:1; // bit 9 ++ u16 link_1000hdx:1; // bit 8 ++ u16 res:8; // bit 0-7 ++#else ++ u16 res:8; // bit 0-7 ++ u16 link_1000hdx:1; // bit 8 ++ u16 link_1000fdx:1; // bit 9 ++ u16 port_type:1; // bit 10 ++ u16 ms_value:1; // bit 11 ++ u16 ms_config_en:1; // bit 12 ++ u16 test_mode:3; // bits 13-15 ++#endif ++ } bits; ++} MI_GCR_t, *PMI_GCR_t; ++ ++/* MI Register 10: 1000BaseT Status Reg(0x0A) */ ++typedef union _MI_GSR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 ms_config_fault:1; // bit 15 ++ u16 ms_resolve:1; // bit 14 ++ u16 local_rx_status:1; // bit 13 ++ u16 remote_rx_status:1; // bit 12 ++ u16 link_1000fdx:1; // bit 11 ++ u16 link_1000hdx:1; // bit 10 ++ u16 res:2; // bits 8-9 ++ u16 idle_err_cnt:8; // bits 0-7 ++#else ++ u16 idle_err_cnt:8; // bits 0-7 ++ u16 res:2; // bits 8-9 ++ u16 link_1000hdx:1; // bit 10 ++ u16 link_1000fdx:1; // bit 11 ++ u16 remote_rx_status:1; // bit 12 ++ u16 local_rx_status:1; // bit 13 ++ u16 ms_resolve:1; // bit 14 ++ u16 ms_config_fault:1; // bit 15 ++#endif ++ } bits; ++} MI_GSR_t, *PMI_GSR_t; ++ ++/* MI Register 11 - 14: Reserved Regs(0x0B - 0x0E) */ ++typedef union _MI_RES_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res15:1; // bit 15 ++ u16 res14:1; // bit 14 ++ u16 res13:1; // bit 13 ++ u16 res12:1; // bit 12 ++ u16 res11:1; // bit 11 ++ u16 res10:1; // bit 10 ++ u16 res9:1; // bit 9 ++ u16 res8:1; // bit 8 ++ u16 res7:1; // bit 7 ++ u16 res6:1; // bit 6 ++ u16 res5:1; // bit 5 ++ u16 res4:1; // bit 4 ++ u16 res3:1; // bit 3 ++ u16 res2:1; // bit 2 ++ u16 res1:1; // bit 1 ++ u16 res0:1; // bit 0 ++#else ++ u16 res0:1; // bit 0 ++ u16 res1:1; // bit 1 ++ u16 res2:1; // bit 2 ++ u16 res3:1; // bit 3 ++ u16 res4:1; // bit 4 ++ u16 res5:1; // bit 5 ++ u16 res6:1; // bit 6 ++ u16 res7:1; // bit 7 ++ u16 res8:1; // bit 8 ++ u16 res9:1; // bit 9 ++ u16 res10:1; // bit 10 ++ u16 res11:1; // bit 11 ++ u16 res12:1; // bit 12 ++ u16 res13:1; // bit 13 ++ u16 res14:1; // bit 14 ++ u16 res15:1; // bit 15 ++#endif ++ } bits; ++} MI_RES_t, *PMI_RES_t; ++ ++/* MI Register 15: Extended status Reg(0x0F) */ ++typedef union _MI_ESR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 link_1000Xfdx:1; // bit 15 ++ u16 link_1000Xhdx:1; // bit 14 ++ u16 link_1000fdx:1; // bit 13 ++ u16 link_1000hdx:1; // bit 12 ++ u16 res:12; // bit 0-11 ++#else ++ u16 res:12; // bit 0-11 ++ u16 link_1000hdx:1; // bit 12 ++ u16 link_1000fdx:1; // bit 13 ++ u16 link_1000Xhdx:1; // bit 14 ++ u16 link_1000Xfdx:1; // bit 15 ++#endif ++ } bits; ++} MI_ESR_t, *PMI_ESR_t; ++ ++/* MI Register 16 - 18: Reserved Reg(0x10-0x12) */ ++ ++/* MI Register 19: Loopback Control Reg(0x13) */ ++typedef union _MI_LCR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 mii_en:1; // bit 15 ++ u16 pcs_en:1; // bit 14 ++ u16 pmd_en:1; // bit 13 ++ u16 all_digital_en:1; // bit 12 ++ u16 replica_en:1; // bit 11 ++ u16 line_driver_en:1; // bit 10 ++ u16 res:10; // bit 0-9 ++#else ++ u16 res:10; // bit 0-9 ++ u16 line_driver_en:1; // bit 10 ++ u16 replica_en:1; // bit 11 ++ u16 all_digital_en:1; // bit 12 ++ u16 pmd_en:1; // bit 13 ++ u16 pcs_en:1; // bit 14 ++ u16 mii_en:1; // bit 15 ++#endif ++ } bits; ++} MI_LCR_t, *PMI_LCR_t; ++ ++/* MI Register 20: Reserved Reg(0x14) */ ++ ++/* MI Register 21: Management Interface Control Reg(0x15) */ ++typedef union _MI_MICR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res1:5; // bits 11-15 ++ u16 mi_error_count:7; // bits 4-10 ++ u16 res2:1; // bit 3 ++ u16 ignore_10g_fr:1; // bit 2 ++ u16 res3:1; // bit 1 ++ u16 preamble_supress_en:1; // bit 0 ++#else ++ u16 preamble_supress_en:1; // bit 0 ++ u16 res3:1; // bit 1 ++ u16 ignore_10g_fr:1; // bit 2 ++ u16 res2:1; // bit 3 ++ u16 mi_error_count:7; // bits 4-10 ++ u16 res1:5; // bits 11-15 ++#endif ++ } bits; ++} MI_MICR_t, *PMI_MICR_t; ++ ++/* MI Register 22: PHY Configuration Reg(0x16) */ ++typedef union _MI_PHY_CONFIG_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 crs_tx_en:1; // bit 15 ++ u16 res1:1; // bit 14 ++ u16 tx_fifo_depth:2; // bits 12-13 ++ u16 speed_downshift:2; // bits 10-11 ++ u16 pbi_detect:1; // bit 9 ++ u16 tbi_rate:1; // bit 8 ++ u16 alternate_np:1; // bit 7 ++ u16 group_mdio_en:1; // bit 6 ++ u16 tx_clock_en:1; // bit 5 ++ u16 sys_clock_en:1; // bit 4 ++ u16 res2:1; // bit 3 ++ u16 mac_if_mode:3; // bits 0-2 ++#else ++ u16 mac_if_mode:3; // bits 0-2 ++ u16 res2:1; // bit 3 ++ u16 sys_clock_en:1; // bit 4 ++ u16 tx_clock_en:1; // bit 5 ++ u16 group_mdio_en:1; // bit 6 ++ u16 alternate_np:1; // bit 7 ++ u16 tbi_rate:1; // bit 8 ++ u16 pbi_detect:1; // bit 9 ++ u16 speed_downshift:2; // bits 10-11 ++ u16 tx_fifo_depth:2; // bits 12-13 ++ u16 res1:1; // bit 14 ++ u16 crs_tx_en:1; // bit 15 ++#endif ++ } bits; ++} MI_PHY_CONFIG_t, *PMI_PHY_CONFIG_t; ++ ++/* MI Register 23: PHY CONTROL Reg(0x17) */ ++typedef union _MI_PHY_CONTROL_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res1:1; // bit 15 ++ u16 tdr_en:1; // bit 14 ++ u16 res2:1; // bit 13 ++ u16 downshift_attempts:2; // bits 11-12 ++ u16 res3:5; // bit 6-10 ++ u16 jabber_10baseT:1; // bit 5 ++ u16 sqe_10baseT:1; // bit 4 ++ u16 tp_loopback_10baseT:1; // bit 3 ++ u16 preamble_gen_en:1; // bit 2 ++ u16 res4:1; // bit 1 ++ u16 force_int:1; // bit 0 ++#else ++ u16 force_int:1; // bit 0 ++ u16 res4:1; // bit 1 ++ u16 preamble_gen_en:1; // bit 2 ++ u16 tp_loopback_10baseT:1; // bit 3 ++ u16 sqe_10baseT:1; // bit 4 ++ u16 jabber_10baseT:1; // bit 5 ++ u16 res3:5; // bit 6-10 ++ u16 downshift_attempts:2; // bits 11-12 ++ u16 res2:1; // bit 13 ++ u16 tdr_en:1; // bit 14 ++ u16 res1:1; // bit 15 ++#endif ++ } bits; ++} MI_PHY_CONTROL_t, *PMI_PHY_CONTROL_t; ++ ++/* MI Register 24: Interrupt Mask Reg(0x18) */ ++typedef union _MI_IMR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res1:6; // bits 10-15 ++ u16 mdio_sync_lost:1; // bit 9 ++ u16 autoneg_status:1; // bit 8 ++ u16 hi_bit_err:1; // bit 7 ++ u16 np_rx:1; // bit 6 ++ u16 err_counter_full:1; // bit 5 ++ u16 fifo_over_underflow:1; // bit 4 ++ u16 rx_status:1; // bit 3 ++ u16 link_status:1; // bit 2 ++ u16 automatic_speed:1; // bit 1 ++ u16 int_en:1; // bit 0 ++#else ++ u16 int_en:1; // bit 0 ++ u16 automatic_speed:1; // bit 1 ++ u16 link_status:1; // bit 2 ++ u16 rx_status:1; // bit 3 ++ u16 fifo_over_underflow:1; // bit 4 ++ u16 err_counter_full:1; // bit 5 ++ u16 np_rx:1; // bit 6 ++ u16 hi_bit_err:1; // bit 7 ++ u16 autoneg_status:1; // bit 8 ++ u16 mdio_sync_lost:1; // bit 9 ++ u16 res1:6; // bits 10-15 ++#endif ++ } bits; ++} MI_IMR_t, *PMI_IMR_t; ++ ++/* MI Register 25: Interrupt Status Reg(0x19) */ ++typedef union _MI_ISR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res1:6; // bits 10-15 ++ u16 mdio_sync_lost:1; // bit 9 ++ u16 autoneg_status:1; // bit 8 ++ u16 hi_bit_err:1; // bit 7 ++ u16 np_rx:1; // bit 6 ++ u16 err_counter_full:1; // bit 5 ++ u16 fifo_over_underflow:1; // bit 4 ++ u16 rx_status:1; // bit 3 ++ u16 link_status:1; // bit 2 ++ u16 automatic_speed:1; // bit 1 ++ u16 int_en:1; // bit 0 ++#else ++ u16 int_en:1; // bit 0 ++ u16 automatic_speed:1; // bit 1 ++ u16 link_status:1; // bit 2 ++ u16 rx_status:1; // bit 3 ++ u16 fifo_over_underflow:1; // bit 4 ++ u16 err_counter_full:1; // bit 5 ++ u16 np_rx:1; // bit 6 ++ u16 hi_bit_err:1; // bit 7 ++ u16 autoneg_status:1; // bit 8 ++ u16 mdio_sync_lost:1; // bit 9 ++ u16 res1:6; // bits 10-15 ++#endif ++ } bits; ++} MI_ISR_t, *PMI_ISR_t; ++ ++/* MI Register 26: PHY Status Reg(0x1A) */ ++typedef union _MI_PSR_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res1:1; // bit 15 ++ u16 autoneg_fault:2; // bit 13-14 ++ u16 autoneg_status:1; // bit 12 ++ u16 mdi_x_status:1; // bit 11 ++ u16 polarity_status:1; // bit 10 ++ u16 speed_status:2; // bits 8-9 ++ u16 duplex_status:1; // bit 7 ++ u16 link_status:1; // bit 6 ++ u16 tx_status:1; // bit 5 ++ u16 rx_status:1; // bit 4 ++ u16 collision_status:1; // bit 3 ++ u16 autoneg_en:1; // bit 2 ++ u16 pause_en:1; // bit 1 ++ u16 asymmetric_dir:1; // bit 0 ++#else ++ u16 asymmetric_dir:1; // bit 0 ++ u16 pause_en:1; // bit 1 ++ u16 autoneg_en:1; // bit 2 ++ u16 collision_status:1; // bit 3 ++ u16 rx_status:1; // bit 4 ++ u16 tx_status:1; // bit 5 ++ u16 link_status:1; // bit 6 ++ u16 duplex_status:1; // bit 7 ++ u16 speed_status:2; // bits 8-9 ++ u16 polarity_status:1; // bit 10 ++ u16 mdi_x_status:1; // bit 11 ++ u16 autoneg_status:1; // bit 12 ++ u16 autoneg_fault:2; // bit 13-14 ++ u16 res1:1; // bit 15 ++#endif ++ } bits; ++} MI_PSR_t, *PMI_PSR_t; ++ ++/* MI Register 27: LED Control Reg 1(0x1B) */ ++typedef union _MI_LCR1_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 res1:2; // bits 14-15 ++ u16 led_dup_indicate:2; // bits 12-13 ++ u16 led_10baseT:2; // bits 10-11 ++ u16 led_collision:2; // bits 8-9 ++ u16 res2:2; // bits 6-7 ++ u16 res3:2; // bits 4-5 ++ u16 pulse_dur:2; // bits 2-3 ++ u16 pulse_stretch1:1; // bit 1 ++ u16 pulse_stretch0:1; // bit 0 ++#else ++ u16 pulse_stretch0:1; // bit 0 ++ u16 pulse_stretch1:1; // bit 1 ++ u16 pulse_dur:2; // bits 2-3 ++ u16 res3:2; // bits 4-5 ++ u16 res2:2; // bits 6-7 ++ u16 led_collision:2; // bits 8-9 ++ u16 led_10baseT:2; // bits 10-11 ++ u16 led_dup_indicate:2; // bits 12-13 ++ u16 res1:2; // bits 14-15 ++#endif ++ } bits; ++} MI_LCR1_t, *PMI_LCR1_t; ++ ++/* MI Register 28: LED Control Reg 2(0x1C) */ ++typedef union _MI_LCR2_t { ++ u16 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u16 led_link:4; // bits 12-15 ++ u16 led_tx_rx:4; // bits 8-11 ++ u16 led_100BaseTX:4; // bits 4-7 ++ u16 led_1000BaseT:4; // bits 0-3 ++#else ++ u16 led_1000BaseT:4; // bits 0-3 ++ u16 led_100BaseTX:4; // bits 4-7 ++ u16 led_tx_rx:4; // bits 8-11 ++ u16 led_link:4; // bits 12-15 ++#endif ++ } bits; ++} MI_LCR2_t, *PMI_LCR2_t; ++ ++/* MI Register 29 - 31: Reserved Reg(0x1D - 0x1E) */ ++ ++/* TruePHY headers */ ++typedef struct _TRUEPHY_ACCESS_MI_REGS_ { ++ TRUEPHY_HANDLE hTruePhy; ++ int32_t nPhyId; ++ u8 bReadWrite; ++ u8 *pbyRegs; ++ u8 *pwData; ++ int32_t nRegCount; ++} TRUEPHY_ACCESS_MI_REGS, *PTRUEPHY_ACCESS_MI_REGS; ++ ++/* TruePHY headers */ ++typedef struct _TAG_TPAL_ACCESS_MI_REGS_ { ++ u32 nPhyId; ++ u8 bReadWrite; ++ u32 nRegCount; ++ u16 Data[4096]; ++ u8 Regs[4096]; ++} TPAL_ACCESS_MI_REGS, *PTPAL_ACCESS_MI_REGS; ++ ++ ++typedef TRUEPHY_HANDLE TPAL_HANDLE; ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++/* OS Specific Functions*/ ++void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *adapter); ++void TPAL_SetPhy10FullDuplex(struct et131x_adapter *adapter); ++void TPAL_SetPhy10Force(struct et131x_adapter *pAdapter); ++void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *adapter); ++void TPAL_SetPhy100FullDuplex(struct et131x_adapter *adapter); ++void TPAL_SetPhy100Force(struct et131x_adapter *pAdapter); ++void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *adapter); ++void TPAL_SetPhyAutoNeg(struct et131x_adapter *adapter); ++ ++/* Prototypes for ET1310_phy.c */ ++int et131x_xcvr_find(struct et131x_adapter *adapter); ++int et131x_setphy_normal(struct et131x_adapter *adapter); ++int32_t PhyMiRead(struct et131x_adapter *adapter, ++ u8 xcvrAddr, u8 xcvrReg, u16 *value); ++ ++/* static inline function does not work because et131x_adapter is not always ++ * defined ++ */ ++#define MiRead(adapter, xcvrReg, value) \ ++ PhyMiRead((adapter), (adapter)->Stats.xcvr_addr, (xcvrReg), (value)) ++ ++int32_t MiWrite(struct et131x_adapter *adapter, ++ u8 xcvReg, u16 value); ++void et131x_Mii_check(struct et131x_adapter *pAdapter, ++ MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints); ++ ++/* This last is not strictly required (the driver could call the TPAL ++ * version instead), but this sets the adapter up correctly, and calls the ++ * access routine indirectly. This protects the driver from changes in TPAL. ++ */ ++void SetPhy_10BaseTHalfDuplex(struct et131x_adapter *adapter); ++ ++/* Defines for PHY access routines */ ++ ++// Define bit operation flags ++#define TRUEPHY_BIT_CLEAR 0 ++#define TRUEPHY_BIT_SET 1 ++#define TRUEPHY_BIT_READ 2 ++ ++// Define read/write operation flags ++#ifndef TRUEPHY_READ ++#define TRUEPHY_READ 0 ++#define TRUEPHY_WRITE 1 ++#define TRUEPHY_MASK 2 ++#endif ++ ++// Define speeds ++#define TRUEPHY_SPEED_10MBPS 0 ++#define TRUEPHY_SPEED_100MBPS 1 ++#define TRUEPHY_SPEED_1000MBPS 2 ++ ++// Define duplex modes ++#define TRUEPHY_DUPLEX_HALF 0 ++#define TRUEPHY_DUPLEX_FULL 1 ++ ++// Define master/slave configuration values ++#define TRUEPHY_CFG_SLAVE 0 ++#define TRUEPHY_CFG_MASTER 1 ++ ++// Define MDI/MDI-X settings ++#define TRUEPHY_MDI 0 ++#define TRUEPHY_MDIX 1 ++#define TRUEPHY_AUTO_MDI_MDIX 2 ++ ++// Define 10Base-T link polarities ++#define TRUEPHY_POLARITY_NORMAL 0 ++#define TRUEPHY_POLARITY_INVERTED 1 ++ ++// Define auto-negotiation results ++#define TRUEPHY_ANEG_NOT_COMPLETE 0 ++#define TRUEPHY_ANEG_COMPLETE 1 ++#define TRUEPHY_ANEG_DISABLED 2 ++ ++/* Define duplex advertisment flags */ ++#define TRUEPHY_ADV_DUPLEX_NONE 0x00 ++#define TRUEPHY_ADV_DUPLEX_FULL 0x01 ++#define TRUEPHY_ADV_DUPLEX_HALF 0x02 ++#define TRUEPHY_ADV_DUPLEX_BOTH \ ++ (TRUEPHY_ADV_DUPLEX_FULL | TRUEPHY_ADV_DUPLEX_HALF) ++ ++#define PHY_CONTROL 0x00 //#define TRU_MI_CONTROL_REGISTER 0 ++#define PHY_STATUS 0x01 //#define TRU_MI_STATUS_REGISTER 1 ++#define PHY_ID_1 0x02 //#define TRU_MI_PHY_IDENTIFIER_1_REGISTER 2 ++#define PHY_ID_2 0x03 //#define TRU_MI_PHY_IDENTIFIER_2_REGISTER 3 ++#define PHY_AUTO_ADVERTISEMENT 0x04 //#define TRU_MI_ADVERTISEMENT_REGISTER 4 ++#define PHY_AUTO_LINK_PARTNER 0x05 //#define TRU_MI_LINK_PARTNER_ABILITY_REGISTER 5 ++#define PHY_AUTO_EXPANSION 0x06 //#define TRU_MI_EXPANSION_REGISTER 6 ++#define PHY_AUTO_NEXT_PAGE_TX 0x07 //#define TRU_MI_NEXT_PAGE_TRANSMIT_REGISTER 7 ++#define PHY_LINK_PARTNER_NEXT_PAGE 0x08 //#define TRU_MI_LINK_PARTNER_NEXT_PAGE_REGISTER 8 ++#define PHY_1000_CONTROL 0x09 //#define TRU_MI_1000BASET_CONTROL_REGISTER 9 ++#define PHY_1000_STATUS 0x0A //#define TRU_MI_1000BASET_STATUS_REGISTER 10 ++ ++#define PHY_EXTENDED_STATUS 0x0F //#define TRU_MI_EXTENDED_STATUS_REGISTER 15 ++ ++// some defines for modem registers that seem to be 'reserved' ++#define PHY_INDEX_REG 0x10 ++#define PHY_DATA_REG 0x11 ++ ++#define PHY_MPHY_CONTROL_REG 0x12 //#define TRU_VMI_MPHY_CONTROL_REGISTER 18 ++ ++#define PHY_LOOPBACK_CONTROL 0x13 //#define TRU_VMI_LOOPBACK_CONTROL_1_REGISTER 19 ++ //#define TRU_VMI_LOOPBACK_CONTROL_2_REGISTER 20 ++#define PHY_REGISTER_MGMT_CONTROL 0x15 //#define TRU_VMI_MI_SEQ_CONTROL_REGISTER 21 ++#define PHY_CONFIG 0x16 //#define TRU_VMI_CONFIGURATION_REGISTER 22 ++#define PHY_PHY_CONTROL 0x17 //#define TRU_VMI_PHY_CONTROL_REGISTER 23 ++#define PHY_INTERRUPT_MASK 0x18 //#define TRU_VMI_INTERRUPT_MASK_REGISTER 24 ++#define PHY_INTERRUPT_STATUS 0x19 //#define TRU_VMI_INTERRUPT_STATUS_REGISTER 25 ++#define PHY_PHY_STATUS 0x1A //#define TRU_VMI_PHY_STATUS_REGISTER 26 ++#define PHY_LED_1 0x1B //#define TRU_VMI_LED_CONTROL_1_REGISTER 27 ++#define PHY_LED_2 0x1C //#define TRU_VMI_LED_CONTROL_2_REGISTER 28 ++ //#define TRU_VMI_LINK_CONTROL_REGISTER 29 ++ //#define TRU_VMI_TIMING_CONTROL_REGISTER ++ ++/* Prototypes for PHY access routines */ ++void ET1310_PhyInit(struct et131x_adapter *adapter); ++void ET1310_PhyReset(struct et131x_adapter *adapter); ++void ET1310_PhyPowerDown(struct et131x_adapter *adapter, bool down); ++void ET1310_PhyAutoNeg(struct et131x_adapter *adapter, bool enable); ++void ET1310_PhyDuplexMode(struct et131x_adapter *adapter, u16 duplex); ++void ET1310_PhySpeedSelect(struct et131x_adapter *adapter, u16 speed); ++void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *adapter, ++ u16 duplex); ++void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *adapter, ++ u16 duplex); ++void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *adapter, ++ u16 duplex); ++void ET1310_PhyLinkStatus(struct et131x_adapter *adapter, ++ u8 *ucLinkStatus, ++ u32 *uiAutoNeg, ++ u32 *uiLinkSpeed, ++ u32 *uiDuplexMode, ++ u32 *uiMdiMdix, ++ u32 *uiMasterSlave, u32 *uiPolarity); ++void ET1310_PhyAndOrReg(struct et131x_adapter *adapter, ++ u16 regnum, u16 andMask, u16 orMask); ++void ET1310_PhyAccessMiBit(struct et131x_adapter *adapter, ++ u16 action, ++ u16 regnum, u16 bitnum, u8 *value); ++ ++#endif /* _ET1310_PHY_H_ */ +diff --git a/drivers/staging/et131x/et1310_pm.c b/drivers/staging/et131x/et1310_pm.c +new file mode 100644 +index 0000000..9539bc6 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_pm.c +@@ -0,0 +1,207 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_pm.c - All power management related code (not completely implemented) ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++#include "et1310_mac.h" ++#include "et1310_rx.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/** ++ * EnablePhyComa - called when network cable is unplugged ++ * @pAdapter: pointer to our adapter structure ++ * ++ * driver receive an phy status change interrupt while in D0 and check that ++ * phy_status is down. ++ * ++ * -- gate off JAGCore; ++ * -- set gigE PHY in Coma mode ++ * -- wake on phy_interrupt; Perform software reset JAGCore, ++ * re-initialize jagcore and gigE PHY ++ * ++ * Add D0-ASPM-PhyLinkDown Support: ++ * -- while in D0, when there is a phy_interrupt indicating phy link ++ * down status, call the MPSetPhyComa routine to enter this active ++ * state power saving mode ++ * -- while in D0-ASPM-PhyLinkDown mode, when there is a phy_interrupt ++ * indicating linkup status, call the MPDisablePhyComa routine to ++ * restore JAGCore and gigE PHY ++ */ ++void EnablePhyComa(struct et131x_adapter *pAdapter) ++{ ++ unsigned long lockflags; ++ PM_CSR_t GlobalPmCSR; ++ int32_t LoopCounter = 10; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ GlobalPmCSR.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); ++ ++ /* Save the GbE PHY speed and duplex modes. Need to restore this ++ * when cable is plugged back in ++ */ ++ pAdapter->PoMgmt.PowerDownSpeed = pAdapter->AiForceSpeed; ++ pAdapter->PoMgmt.PowerDownDuplex = pAdapter->AiForceDpx; ++ ++ /* Stop sending packets. */ ++ spin_lock_irqsave(&pAdapter->SendHWLock, lockflags); ++ MP_SET_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER); ++ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags); ++ ++ /* Wait for outstanding Receive packets */ ++ while ((MP_GET_RCV_REF(pAdapter) != 0) && (LoopCounter-- > 0)) { ++ mdelay(2); ++ } ++ ++ /* Gate off JAGCore 3 clock domains */ ++ GlobalPmCSR.bits.pm_sysclk_gate = 0; ++ GlobalPmCSR.bits.pm_txclk_gate = 0; ++ GlobalPmCSR.bits.pm_rxclk_gate = 0; ++ writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value); ++ ++ /* Program gigE PHY in to Coma mode */ ++ GlobalPmCSR.bits.pm_phy_sw_coma = 1; ++ writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * DisablePhyComa - Disable the Phy Coma Mode ++ * @pAdapter: pointer to our adapter structure ++ */ ++void DisablePhyComa(struct et131x_adapter *pAdapter) ++{ ++ PM_CSR_t GlobalPmCSR; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ GlobalPmCSR.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); ++ ++ /* Disable phy_sw_coma register and re-enable JAGCore clocks */ ++ GlobalPmCSR.bits.pm_sysclk_gate = 1; ++ GlobalPmCSR.bits.pm_txclk_gate = 1; ++ GlobalPmCSR.bits.pm_rxclk_gate = 1; ++ GlobalPmCSR.bits.pm_phy_sw_coma = 0; ++ writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value); ++ ++ /* Restore the GbE PHY speed and duplex modes; ++ * Reset JAGCore; re-configure and initialize JAGCore and gigE PHY ++ */ ++ pAdapter->AiForceSpeed = pAdapter->PoMgmt.PowerDownSpeed; ++ pAdapter->AiForceDpx = pAdapter->PoMgmt.PowerDownDuplex; ++ ++ /* Re-initialize the send structures */ ++ et131x_init_send(pAdapter); ++ ++ /* Reset the RFD list and re-start RU */ ++ et131x_reset_recv(pAdapter); ++ ++ /* Bring the device back to the state it was during init prior to ++ * autonegotiation being complete. This way, when we get the auto-neg ++ * complete interrupt, we can complete init by calling ConfigMacREGS2. ++ */ ++ et131x_soft_reset(pAdapter); ++ ++ /* setup et1310 as per the documentation ?? */ ++ et131x_adapter_setup(pAdapter); ++ ++ /* Allow Tx to restart */ ++ MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER); ++ ++ /* Need to re-enable Rx. */ ++ et131x_rx_dma_enable(pAdapter); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ +diff --git a/drivers/staging/et131x/et1310_pm.h b/drivers/staging/et131x/et1310_pm.h +new file mode 100644 +index 0000000..6802338 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_pm.h +@@ -0,0 +1,125 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_pm.h - Defines, structs, enums, prototypes, etc. pertaining to power ++ * management. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef _ET1310_PM_H_ ++#define _ET1310_PM_H_ ++ ++#include "et1310_address_map.h" ++ ++#define MAX_WOL_PACKET_SIZE 0x80 ++#define MAX_WOL_MASK_SIZE ( MAX_WOL_PACKET_SIZE / 8 ) ++#define NUM_WOL_PATTERNS 0x5 ++#define CRC16_POLY 0x1021 ++ ++/* Definition of NDIS_DEVICE_POWER_STATE */ ++typedef enum { ++ NdisDeviceStateUnspecified = 0, ++ NdisDeviceStateD0, ++ NdisDeviceStateD1, ++ NdisDeviceStateD2, ++ NdisDeviceStateD3 ++} NDIS_DEVICE_POWER_STATE; ++ ++typedef struct _MP_POWER_MGMT { ++ /* variable putting the phy into coma mode when boot up with no cable ++ * plugged in after 5 seconds ++ */ ++ u8 TransPhyComaModeOnBoot; ++ ++ /* Array holding the five CRC values that the device is currently ++ * using for WOL. This will be queried when a pattern is to be ++ * removed. ++ */ ++ u32 localWolAndCrc0; ++ u16 WOLPatternList[NUM_WOL_PATTERNS]; ++ u8 WOLMaskList[NUM_WOL_PATTERNS][MAX_WOL_MASK_SIZE]; ++ u32 WOLMaskSize[NUM_WOL_PATTERNS]; ++ ++ /* IP address */ ++ union { ++ u32 u32; ++ u8 u8[4]; ++ } IPAddress; ++ ++ /* Current Power state of the adapter. */ ++ NDIS_DEVICE_POWER_STATE PowerState; ++ bool WOLState; ++ bool WOLEnabled; ++ bool Failed10Half; ++ bool bFailedStateTransition; ++ ++ /* Next two used to save power information at power down. This ++ * information will be used during power up to set up parts of Power ++ * Management in JAGCore ++ */ ++ u32 tx_en; ++ u32 rx_en; ++ u16 PowerDownSpeed; ++ u8 PowerDownDuplex; ++} MP_POWER_MGMT, *PMP_POWER_MGMT; ++ ++/* Forward declaration of the private adapter structure ++ * ( IS THERE A WAY TO DO THIS WITH A TYPEDEF??? ) ++ */ ++struct et131x_adapter; ++ ++u16 CalculateCCITCRC16(u8 *Pattern, u8 *Mask, u32 MaskSize); ++void EnablePhyComa(struct et131x_adapter *adapter); ++void DisablePhyComa(struct et131x_adapter *adapter); ++ ++#endif /* _ET1310_PM_H_ */ +diff --git a/drivers/staging/et131x/et1310_rx.c b/drivers/staging/et131x/et1310_rx.c +new file mode 100644 +index 0000000..ec98da5 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_rx.c +@@ -0,0 +1,1391 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_rx.c - Routines used to perform data reception ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++ ++#include "et1310_rx.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++ ++void nic_return_rfd(struct et131x_adapter *pAdapter, PMP_RFD pMpRfd); ++ ++/** ++ * et131x_rx_dma_memory_alloc ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success and errno on failure (as defined in errno.h) ++ * ++ * Allocates Free buffer ring 1 for sure, free buffer ring 0 if required, ++ * and the Packet Status Ring. ++ */ ++int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) ++{ ++ uint32_t OuterLoop, InnerLoop; ++ uint32_t bufsize; ++ uint32_t pktStatRingSize, FBRChunkSize; ++ RX_RING_t *rx_ring; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Setup some convenience pointers */ ++ rx_ring = (RX_RING_t *) & adapter->RxRing; ++ ++ /* Alloc memory for the lookup table */ ++#ifdef USE_FBR0 ++ rx_ring->Fbr[0] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL); ++#endif ++ ++ rx_ring->Fbr[1] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL); ++ ++ /* The first thing we will do is configure the sizes of the buffer ++ * rings. These will change based on jumbo packet support. Larger ++ * jumbo packets increases the size of each entry in FBR0, and the ++ * number of entries in FBR0, while at the same time decreasing the ++ * number of entries in FBR1. ++ * ++ * FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1 ++ * entries are huge in order to accomodate a "jumbo" frame, then it ++ * will have less entries. Conversely, FBR1 will now be relied upon ++ * to carry more "normal" frames, thus it's entry size also increases ++ * and the number of entries goes up too (since it now carries ++ * "small" + "regular" packets. ++ * ++ * In this scheme, we try to maintain 512 entries between the two ++ * rings. Also, FBR1 remains a constant size - when it's size doubles ++ * the number of entries halves. FBR0 increases in size, however. ++ */ ++ ++ if (adapter->RegistryJumboPacket < 2048) { ++#ifdef USE_FBR0 ++ rx_ring->Fbr0BufferSize = 256; ++ rx_ring->Fbr0NumEntries = 512; ++#endif ++ rx_ring->Fbr1BufferSize = 2048; ++ rx_ring->Fbr1NumEntries = 512; ++ } else if (adapter->RegistryJumboPacket < 4096) { ++#ifdef USE_FBR0 ++ rx_ring->Fbr0BufferSize = 512; ++ rx_ring->Fbr0NumEntries = 1024; ++#endif ++ rx_ring->Fbr1BufferSize = 4096; ++ rx_ring->Fbr1NumEntries = 512; ++ } else { ++#ifdef USE_FBR0 ++ rx_ring->Fbr0BufferSize = 1024; ++ rx_ring->Fbr0NumEntries = 768; ++#endif ++ rx_ring->Fbr1BufferSize = 16384; ++ rx_ring->Fbr1NumEntries = 128; ++ } ++ ++#ifdef USE_FBR0 ++ adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr0NumEntries + ++ adapter->RxRing.Fbr1NumEntries; ++#else ++ adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr1NumEntries; ++#endif ++ ++ /* Allocate an area of memory for Free Buffer Ring 1 */ ++ bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff; ++ rx_ring->pFbr1RingVa = pci_alloc_consistent(adapter->pdev, ++ bufsize, ++ &rx_ring->pFbr1RingPa); ++ if (!rx_ring->pFbr1RingVa) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot alloc memory for Free Buffer Ring 1\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Save physical address ++ * ++ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, ++ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses ++ * are ever returned, make sure the high part is retrieved here ++ * before storing the adjusted address. ++ */ ++ rx_ring->Fbr1Realpa = rx_ring->pFbr1RingPa; ++ ++ /* Align Free Buffer Ring 1 on a 4K boundary */ ++ et131x_align_allocated_memory(adapter, ++ &rx_ring->Fbr1Realpa, ++ &rx_ring->Fbr1offset, 0x0FFF); ++ ++ rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa + ++ rx_ring->Fbr1offset); ++ ++#ifdef USE_FBR0 ++ /* Allocate an area of memory for Free Buffer Ring 0 */ ++ bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff; ++ rx_ring->pFbr0RingVa = pci_alloc_consistent(adapter->pdev, ++ bufsize, ++ &rx_ring->pFbr0RingPa); ++ if (!rx_ring->pFbr0RingVa) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot alloc memory for Free Buffer Ring 0\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Save physical address ++ * ++ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, ++ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses ++ * are ever returned, make sure the high part is retrieved here before ++ * storing the adjusted address. ++ */ ++ rx_ring->Fbr0Realpa = rx_ring->pFbr0RingPa; ++ ++ /* Align Free Buffer Ring 0 on a 4K boundary */ ++ et131x_align_allocated_memory(adapter, ++ &rx_ring->Fbr0Realpa, ++ &rx_ring->Fbr0offset, 0x0FFF); ++ ++ rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa + ++ rx_ring->Fbr0offset); ++#endif ++ ++ for (OuterLoop = 0; OuterLoop < (rx_ring->Fbr1NumEntries / FBR_CHUNKS); ++ OuterLoop++) { ++ uint64_t Fbr1Offset; ++ uint64_t Fbr1TempPa; ++ uint32_t Fbr1Align; ++ ++ /* This code allocates an area of memory big enough for N ++ * free buffers + (buffer_size - 1) so that the buffers can ++ * be aligned on 4k boundaries. If each buffer were aligned ++ * to a buffer_size boundary, the effect would be to double ++ * the size of FBR0. By allocating N buffers at once, we ++ * reduce this overhead. ++ */ ++ if (rx_ring->Fbr1BufferSize > 4096) { ++ Fbr1Align = 4096; ++ } else { ++ Fbr1Align = rx_ring->Fbr1BufferSize; ++ } ++ ++ FBRChunkSize = ++ (FBR_CHUNKS * rx_ring->Fbr1BufferSize) + Fbr1Align - 1; ++ rx_ring->Fbr1MemVa[OuterLoop] = ++ pci_alloc_consistent(adapter->pdev, FBRChunkSize, ++ &rx_ring->Fbr1MemPa[OuterLoop]); ++ ++ if (!rx_ring->Fbr1MemVa[OuterLoop]) { ++ DBG_ERROR(et131x_dbginfo, "Could not alloc memory\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* See NOTE in "Save Physical Address" comment above */ ++ Fbr1TempPa = rx_ring->Fbr1MemPa[OuterLoop]; ++ ++ et131x_align_allocated_memory(adapter, ++ &Fbr1TempPa, ++ &Fbr1Offset, (Fbr1Align - 1)); ++ ++ for (InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++) { ++ uint32_t index = (OuterLoop * FBR_CHUNKS) + InnerLoop; ++ ++ /* Save the Virtual address of this index for quick ++ * access later ++ */ ++ rx_ring->Fbr[1]->Va[index] = ++ (uint8_t *) rx_ring->Fbr1MemVa[OuterLoop] + ++ (InnerLoop * rx_ring->Fbr1BufferSize) + Fbr1Offset; ++ ++ /* now store the physical address in the descriptor ++ * so the device can access it ++ */ ++ rx_ring->Fbr[1]->PAHigh[index] = ++ (uint32_t) (Fbr1TempPa >> 32); ++ rx_ring->Fbr[1]->PALow[index] = (uint32_t) Fbr1TempPa; ++ ++ Fbr1TempPa += rx_ring->Fbr1BufferSize; ++ ++ rx_ring->Fbr[1]->Buffer1[index] = ++ rx_ring->Fbr[1]->Va[index]; ++ rx_ring->Fbr[1]->Buffer2[index] = ++ rx_ring->Fbr[1]->Va[index] - 4; ++ } ++ } ++ ++#ifdef USE_FBR0 ++ /* Same for FBR0 (if in use) */ ++ for (OuterLoop = 0; OuterLoop < (rx_ring->Fbr0NumEntries / FBR_CHUNKS); ++ OuterLoop++) { ++ uint64_t Fbr0Offset; ++ uint64_t Fbr0TempPa; ++ ++ FBRChunkSize = ((FBR_CHUNKS + 1) * rx_ring->Fbr0BufferSize) - 1; ++ rx_ring->Fbr0MemVa[OuterLoop] = ++ pci_alloc_consistent(adapter->pdev, FBRChunkSize, ++ &rx_ring->Fbr0MemPa[OuterLoop]); ++ ++ if (!rx_ring->Fbr0MemVa[OuterLoop]) { ++ DBG_ERROR(et131x_dbginfo, "Could not alloc memory\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* See NOTE in "Save Physical Address" comment above */ ++ Fbr0TempPa = rx_ring->Fbr0MemPa[OuterLoop]; ++ ++ et131x_align_allocated_memory(adapter, ++ &Fbr0TempPa, ++ &Fbr0Offset, ++ rx_ring->Fbr0BufferSize - 1); ++ ++ for (InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++) { ++ uint32_t index = (OuterLoop * FBR_CHUNKS) + InnerLoop; ++ ++ rx_ring->Fbr[0]->Va[index] = ++ (uint8_t *) rx_ring->Fbr0MemVa[OuterLoop] + ++ (InnerLoop * rx_ring->Fbr0BufferSize) + Fbr0Offset; ++ ++ rx_ring->Fbr[0]->PAHigh[index] = ++ (uint32_t) (Fbr0TempPa >> 32); ++ rx_ring->Fbr[0]->PALow[index] = (uint32_t) Fbr0TempPa; ++ ++ Fbr0TempPa += rx_ring->Fbr0BufferSize; ++ ++ rx_ring->Fbr[0]->Buffer1[index] = ++ rx_ring->Fbr[0]->Va[index]; ++ rx_ring->Fbr[0]->Buffer2[index] = ++ rx_ring->Fbr[0]->Va[index] - 4; ++ } ++ } ++#endif ++ ++ /* Allocate an area of memory for FIFO of Packet Status ring entries */ ++ pktStatRingSize = ++ sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries; ++ ++ rx_ring->pPSRingVa = pci_alloc_consistent(adapter->pdev, ++ pktStatRingSize + 0x0fff, ++ &rx_ring->pPSRingPa); ++ ++ if (!rx_ring->pPSRingVa) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot alloc memory for Packet Status Ring\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Save physical address ++ * ++ * NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ++ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses ++ * are ever returned, make sure the high part is retrieved here before ++ * storing the adjusted address. ++ */ ++ rx_ring->pPSRingRealPa = rx_ring->pPSRingPa; ++ ++ /* Align Packet Status Ring on a 4K boundary */ ++ et131x_align_allocated_memory(adapter, ++ &rx_ring->pPSRingRealPa, ++ &rx_ring->pPSRingOffset, 0x0FFF); ++ ++ rx_ring->pPSRingVa = (void *)((uint8_t *) rx_ring->pPSRingVa + ++ rx_ring->pPSRingOffset); ++ ++ /* Allocate an area of memory for writeback of status information */ ++ rx_ring->pRxStatusVa = pci_alloc_consistent(adapter->pdev, ++ sizeof(RX_STATUS_BLOCK_t) + ++ 0x7, &rx_ring->pRxStatusPa); ++ if (!rx_ring->pRxStatusVa) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot alloc memory for Status Block\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Save physical address */ ++ rx_ring->RxStatusRealPA = rx_ring->pRxStatusPa; ++ ++ /* Align write back on an 8 byte boundary */ ++ et131x_align_allocated_memory(adapter, ++ &rx_ring->RxStatusRealPA, ++ &rx_ring->RxStatusOffset, 0x07); ++ ++ rx_ring->pRxStatusVa = (void *)((uint8_t *) rx_ring->pRxStatusVa + ++ rx_ring->RxStatusOffset); ++ rx_ring->NumRfd = NIC_DEFAULT_NUM_RFD; ++ ++ /* Recv ++ * pci_pool_create initializes a lookaside list. After successful ++ * creation, nonpaged fixed-size blocks can be allocated from and ++ * freed to the lookaside list. ++ * RFDs will be allocated from this pool. ++ */ ++ rx_ring->RecvLookaside = kmem_cache_create(adapter->netdev->name, ++ sizeof(MP_RFD), ++ 0, ++ SLAB_CACHE_DMA | ++ SLAB_HWCACHE_ALIGN, ++ NULL); ++ ++ MP_SET_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE); ++ ++ /* The RFDs are going to be put on lists later on, so initialize the ++ * lists now. ++ */ ++ INIT_LIST_HEAD(&rx_ring->RecvList); ++ INIT_LIST_HEAD(&rx_ring->RecvPendingList); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++/** ++ * et131x_rx_dma_memory_free - Free all memory allocated within this module. ++ * @adapter: pointer to our private adapter structure ++ */ ++void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) ++{ ++ uint32_t index; ++ uint32_t bufsize; ++ uint32_t pktStatRingSize; ++ PMP_RFD pMpRfd; ++ RX_RING_t *rx_ring; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Setup some convenience pointers */ ++ rx_ring = (RX_RING_t *) & adapter->RxRing; ++ ++ /* Free RFDs and associated packet descriptors */ ++ DBG_ASSERT(rx_ring->nReadyRecv == rx_ring->NumRfd); ++ ++ while (!list_empty(&rx_ring->RecvList)) { ++ pMpRfd = (MP_RFD *) list_entry(rx_ring->RecvList.next, ++ MP_RFD, list_node); ++ ++ list_del(&pMpRfd->list_node); ++ et131x_rfd_resources_free(adapter, pMpRfd); ++ } ++ ++ while (!list_empty(&rx_ring->RecvPendingList)) { ++ pMpRfd = (MP_RFD *) list_entry(rx_ring->RecvPendingList.next, ++ MP_RFD, list_node); ++ list_del(&pMpRfd->list_node); ++ et131x_rfd_resources_free(adapter, pMpRfd); ++ } ++ ++ /* Free Free Buffer Ring 1 */ ++ if (rx_ring->pFbr1RingVa) { ++ /* First the packet memory */ ++ for (index = 0; index < ++ (rx_ring->Fbr1NumEntries / FBR_CHUNKS); index++) { ++ if (rx_ring->Fbr1MemVa[index]) { ++ uint32_t Fbr1Align; ++ ++ if (rx_ring->Fbr1BufferSize > 4096) { ++ Fbr1Align = 4096; ++ } else { ++ Fbr1Align = rx_ring->Fbr1BufferSize; ++ } ++ ++ bufsize = ++ (rx_ring->Fbr1BufferSize * FBR_CHUNKS) + ++ Fbr1Align - 1; ++ ++ pci_free_consistent(adapter->pdev, ++ bufsize, ++ rx_ring->Fbr1MemVa[index], ++ rx_ring->Fbr1MemPa[index]); ++ ++ rx_ring->Fbr1MemVa[index] = NULL; ++ } ++ } ++ ++ /* Now the FIFO itself */ ++ rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa - ++ rx_ring->Fbr1offset); ++ ++ bufsize = ++ (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff; ++ ++ pci_free_consistent(adapter->pdev, ++ bufsize, ++ rx_ring->pFbr1RingVa, rx_ring->pFbr1RingPa); ++ ++ rx_ring->pFbr1RingVa = NULL; ++ } ++ ++#ifdef USE_FBR0 ++ /* Now the same for Free Buffer Ring 0 */ ++ if (rx_ring->pFbr0RingVa) { ++ /* First the packet memory */ ++ for (index = 0; index < ++ (rx_ring->Fbr0NumEntries / FBR_CHUNKS); index++) { ++ if (rx_ring->Fbr0MemVa[index]) { ++ bufsize = ++ (rx_ring->Fbr0BufferSize * ++ (FBR_CHUNKS + 1)) - 1; ++ ++ pci_free_consistent(adapter->pdev, ++ bufsize, ++ rx_ring->Fbr0MemVa[index], ++ rx_ring->Fbr0MemPa[index]); ++ ++ rx_ring->Fbr0MemVa[index] = NULL; ++ } ++ } ++ ++ /* Now the FIFO itself */ ++ rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa - ++ rx_ring->Fbr0offset); ++ ++ bufsize = ++ (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff; ++ ++ pci_free_consistent(adapter->pdev, ++ bufsize, ++ rx_ring->pFbr0RingVa, rx_ring->pFbr0RingPa); ++ ++ rx_ring->pFbr0RingVa = NULL; ++ } ++#endif ++ ++ /* Free Packet Status Ring */ ++ if (rx_ring->pPSRingVa) { ++ rx_ring->pPSRingVa = (void *)((uint8_t *) rx_ring->pPSRingVa - ++ rx_ring->pPSRingOffset); ++ ++ pktStatRingSize = ++ sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries; ++ ++ pci_free_consistent(adapter->pdev, ++ pktStatRingSize + 0x0fff, ++ rx_ring->pPSRingVa, rx_ring->pPSRingPa); ++ ++ rx_ring->pPSRingVa = NULL; ++ } ++ ++ /* Free area of memory for the writeback of status information */ ++ if (rx_ring->pRxStatusVa) { ++ rx_ring->pRxStatusVa = (void *)((uint8_t *) rx_ring->pRxStatusVa - ++ rx_ring->RxStatusOffset); ++ ++ pci_free_consistent(adapter->pdev, ++ sizeof(RX_STATUS_BLOCK_t) + 0x7, ++ rx_ring->pRxStatusVa, rx_ring->pRxStatusPa); ++ ++ rx_ring->pRxStatusVa = NULL; ++ } ++ ++ /* Free receive buffer pool */ ++ ++ /* Free receive packet pool */ ++ ++ /* Destroy the lookaside (RFD) pool */ ++ if (MP_TEST_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE)) { ++ kmem_cache_destroy(rx_ring->RecvLookaside); ++ MP_CLEAR_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE); ++ } ++ ++ /* Free the FBR Lookup Table */ ++#ifdef USE_FBR0 ++ kfree(rx_ring->Fbr[0]); ++#endif ++ ++ kfree(rx_ring->Fbr[1]); ++ ++ /* Reset Counters */ ++ rx_ring->nReadyRecv = 0; ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_init_recv - Initialize receive data structures. ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success and errno on failure (as defined in errno.h) ++ */ ++int et131x_init_recv(struct et131x_adapter *adapter) ++{ ++ int status = -ENOMEM; ++ PMP_RFD pMpRfd = NULL; ++ uint32_t RfdCount; ++ uint32_t TotalNumRfd = 0; ++ RX_RING_t *rx_ring = NULL; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Setup some convenience pointers */ ++ rx_ring = (RX_RING_t *) & adapter->RxRing; ++ ++ /* Setup each RFD */ ++ for (RfdCount = 0; RfdCount < rx_ring->NumRfd; RfdCount++) { ++ pMpRfd = (MP_RFD *) kmem_cache_alloc(rx_ring->RecvLookaside, ++ GFP_ATOMIC | GFP_DMA); ++ ++ if (!pMpRfd) { ++ DBG_ERROR(et131x_dbginfo, ++ "Couldn't alloc RFD out of kmem_cache\n"); ++ status = -ENOMEM; ++ continue; ++ } ++ ++ status = et131x_rfd_resources_alloc(adapter, pMpRfd); ++ if (status != 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "Couldn't alloc packet for RFD\n"); ++ kmem_cache_free(rx_ring->RecvLookaside, pMpRfd); ++ continue; ++ } ++ ++ /* Add this RFD to the RecvList */ ++ list_add_tail(&pMpRfd->list_node, &rx_ring->RecvList); ++ ++ /* Increment both the available RFD's, and the total RFD's. */ ++ rx_ring->nReadyRecv++; ++ TotalNumRfd++; ++ } ++ ++ if (TotalNumRfd > NIC_MIN_NUM_RFD) { ++ status = 0; ++ } ++ ++ rx_ring->NumRfd = TotalNumRfd; ++ ++ if (status != 0) { ++ kmem_cache_free(rx_ring->RecvLookaside, pMpRfd); ++ DBG_ERROR(et131x_dbginfo, ++ "Allocation problems in et131x_init_recv\n"); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_rfd_resources_alloc ++ * @adapter: pointer to our private adapter structure ++ * @pMpRfd: pointer to a RFD ++ * ++ * Returns 0 on success and errno on failure (as defined in errno.h) ++ */ ++int et131x_rfd_resources_alloc(struct et131x_adapter *adapter, MP_RFD *pMpRfd) ++{ ++ pMpRfd->Packet = NULL; ++ ++ return 0; ++} ++ ++/** ++ * et131x_rfd_resources_free - Free the packet allocated for the given RFD ++ * @adapter: pointer to our private adapter structure ++ * @pMpRfd: pointer to a RFD ++ */ ++void et131x_rfd_resources_free(struct et131x_adapter *adapter, MP_RFD *pMpRfd) ++{ ++ pMpRfd->Packet = NULL; ++ kmem_cache_free(adapter->RxRing.RecvLookaside, pMpRfd); ++} ++ ++/** ++ * ConfigRxDmaRegs - Start of Rx_DMA init sequence ++ * @pAdapter: pointer to our adapter structure ++ */ ++void ConfigRxDmaRegs(struct et131x_adapter *pAdapter) ++{ ++ struct _RXDMA_t __iomem *pRxDma = &pAdapter->CSRAddress->rxdma; ++ struct _rx_ring_t *pRxLocal = &pAdapter->RxRing; ++ PFBR_DESC_t pFbrEntry; ++ uint32_t iEntry; ++ RXDMA_PSR_NUM_DES_t psr_num_des; ++ unsigned long lockflags; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Halt RXDMA to perform the reconfigure. */ ++ et131x_rx_dma_disable(pAdapter); ++ ++ /* Load the completion writeback physical address ++ * ++ * NOTE : pci_alloc_consistent(), used above to alloc DMA regions, ++ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses ++ * are ever returned, make sure the high part is retrieved here ++ * before storing the adjusted address. ++ */ ++ writel((uint32_t) (pRxLocal->RxStatusRealPA >> 32), ++ &pRxDma->dma_wb_base_hi); ++ writel((uint32_t) pRxLocal->RxStatusRealPA, &pRxDma->dma_wb_base_lo); ++ ++ memset(pRxLocal->pRxStatusVa, 0, sizeof(RX_STATUS_BLOCK_t)); ++ ++ /* Set the address and parameters of the packet status ring into the ++ * 1310's registers ++ */ ++ writel((uint32_t) (pRxLocal->pPSRingRealPa >> 32), ++ &pRxDma->psr_base_hi); ++ writel((uint32_t) pRxLocal->pPSRingRealPa, &pRxDma->psr_base_lo); ++ writel(pRxLocal->PsrNumEntries - 1, &pRxDma->psr_num_des.value); ++ writel(0, &pRxDma->psr_full_offset.value); ++ ++ psr_num_des.value = readl(&pRxDma->psr_num_des.value); ++ writel((psr_num_des.bits.psr_ndes * LO_MARK_PERCENT_FOR_PSR) / 100, ++ &pRxDma->psr_min_des.value); ++ ++ spin_lock_irqsave(&pAdapter->RcvLock, lockflags); ++ ++ /* These local variables track the PSR in the adapter structure */ ++ pRxLocal->local_psr_full.bits.psr_full = 0; ++ pRxLocal->local_psr_full.bits.psr_full_wrap = 0; ++ ++ /* Now's the best time to initialize FBR1 contents */ ++ pFbrEntry = (PFBR_DESC_t) pRxLocal->pFbr1RingVa; ++ for (iEntry = 0; iEntry < pRxLocal->Fbr1NumEntries; iEntry++) { ++ pFbrEntry->addr_hi = pRxLocal->Fbr[1]->PAHigh[iEntry]; ++ pFbrEntry->addr_lo = pRxLocal->Fbr[1]->PALow[iEntry]; ++ pFbrEntry->word2.bits.bi = iEntry; ++ pFbrEntry++; ++ } ++ ++ /* Set the address and parameters of Free buffer ring 1 (and 0 if ++ * required) into the 1310's registers ++ */ ++ writel((uint32_t) (pRxLocal->Fbr1Realpa >> 32), &pRxDma->fbr1_base_hi); ++ writel((uint32_t) pRxLocal->Fbr1Realpa, &pRxDma->fbr1_base_lo); ++ writel(pRxLocal->Fbr1NumEntries - 1, &pRxDma->fbr1_num_des.value); ++ ++ { ++ DMA10W_t fbr1_full = { 0 }; ++ ++ fbr1_full.bits.val = 0; ++ fbr1_full.bits.wrap = 1; ++ writel(fbr1_full.value, &pRxDma->fbr1_full_offset.value); ++ } ++ ++ /* This variable tracks the free buffer ring 1 full position, so it ++ * has to match the above. ++ */ ++ pRxLocal->local_Fbr1_full.bits.val = 0; ++ pRxLocal->local_Fbr1_full.bits.wrap = 1; ++ writel(((pRxLocal->Fbr1NumEntries * LO_MARK_PERCENT_FOR_RX) / 100) - 1, ++ &pRxDma->fbr1_min_des.value); ++ ++#ifdef USE_FBR0 ++ /* Now's the best time to initialize FBR0 contents */ ++ pFbrEntry = (PFBR_DESC_t) pRxLocal->pFbr0RingVa; ++ for (iEntry = 0; iEntry < pRxLocal->Fbr0NumEntries; iEntry++) { ++ pFbrEntry->addr_hi = pRxLocal->Fbr[0]->PAHigh[iEntry]; ++ pFbrEntry->addr_lo = pRxLocal->Fbr[0]->PALow[iEntry]; ++ pFbrEntry->word2.bits.bi = iEntry; ++ pFbrEntry++; ++ } ++ ++ writel((uint32_t) (pRxLocal->Fbr0Realpa >> 32), &pRxDma->fbr0_base_hi); ++ writel((uint32_t) pRxLocal->Fbr0Realpa, &pRxDma->fbr0_base_lo); ++ writel(pRxLocal->Fbr0NumEntries - 1, &pRxDma->fbr0_num_des.value); ++ ++ { ++ DMA10W_t fbr0_full = { 0 }; ++ ++ fbr0_full.bits.val = 0; ++ fbr0_full.bits.wrap = 1; ++ writel(fbr0_full.value, &pRxDma->fbr0_full_offset.value); ++ } ++ ++ /* This variable tracks the free buffer ring 0 full position, so it ++ * has to match the above. ++ */ ++ pRxLocal->local_Fbr0_full.bits.val = 0; ++ pRxLocal->local_Fbr0_full.bits.wrap = 1; ++ writel(((pRxLocal->Fbr0NumEntries * LO_MARK_PERCENT_FOR_RX) / 100) - 1, ++ &pRxDma->fbr0_min_des.value); ++#endif ++ ++ /* Program the number of packets we will receive before generating an ++ * interrupt. ++ * For version B silicon, this value gets updated once autoneg is ++ *complete. ++ */ ++ writel(pAdapter->RegistryRxNumBuffers, &pRxDma->num_pkt_done.value); ++ ++ /* The "time_done" is not working correctly to coalesce interrupts ++ * after a given time period, but rather is giving us an interrupt ++ * regardless of whether we have received packets. ++ * This value gets updated once autoneg is complete. ++ */ ++ writel(pAdapter->RegistryRxTimeInterval, &pRxDma->max_pkt_time.value); ++ ++ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * SetRxDmaTimer - Set the heartbeat timer according to line rate. ++ * @pAdapter: pointer to our adapter structure ++ */ ++void SetRxDmaTimer(struct et131x_adapter *pAdapter) ++{ ++ /* For version B silicon, we do not use the RxDMA timer for 10 and 100 ++ * Mbits/s line rates. We do not enable and RxDMA interrupt coalescing. ++ */ ++ if ((pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS) || ++ (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS)) { ++ writel(0, &pAdapter->CSRAddress->rxdma.max_pkt_time.value); ++ writel(1, &pAdapter->CSRAddress->rxdma.num_pkt_done.value); ++ } ++} ++ ++/** ++ * et131x_rx_dma_disable - Stop of Rx_DMA on the ET1310 ++ * @pAdapter: pointer to our adapter structure ++ */ ++void et131x_rx_dma_disable(struct et131x_adapter *pAdapter) ++{ ++ RXDMA_CSR_t csr; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Setup the receive dma configuration register */ ++ writel(0x00002001, &pAdapter->CSRAddress->rxdma.csr.value); ++ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); ++ if (csr.bits.halt_status != 1) { ++ udelay(5); ++ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); ++ if (csr.bits.halt_status != 1) { ++ DBG_ERROR(et131x_dbginfo, ++ "RX Dma failed to enter halt state. CSR 0x%08x\n", ++ csr.value); ++ } ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_rx_dma_enable - re-start of Rx_DMA on the ET1310. ++ * @pAdapter: pointer to our adapter structure ++ */ ++void et131x_rx_dma_enable(struct et131x_adapter *pAdapter) ++{ ++ DBG_RX_ENTER(et131x_dbginfo); ++ ++ if (pAdapter->RegistryPhyLoopbk) { ++ /* RxDMA is disabled for loopback operation. */ ++ writel(0x1, &pAdapter->CSRAddress->rxdma.csr.value); ++ } else { ++ /* Setup the receive dma configuration register for normal operation */ ++ RXDMA_CSR_t csr = { 0 }; ++ ++ csr.bits.fbr1_enable = 1; ++ if (pAdapter->RxRing.Fbr1BufferSize == 4096) { ++ csr.bits.fbr1_size = 1; ++ } else if (pAdapter->RxRing.Fbr1BufferSize == 8192) { ++ csr.bits.fbr1_size = 2; ++ } else if (pAdapter->RxRing.Fbr1BufferSize == 16384) { ++ csr.bits.fbr1_size = 3; ++ } ++#ifdef USE_FBR0 ++ csr.bits.fbr0_enable = 1; ++ if (pAdapter->RxRing.Fbr0BufferSize == 256) { ++ csr.bits.fbr0_size = 1; ++ } else if (pAdapter->RxRing.Fbr0BufferSize == 512) { ++ csr.bits.fbr0_size = 2; ++ } else if (pAdapter->RxRing.Fbr0BufferSize == 1024) { ++ csr.bits.fbr0_size = 3; ++ } ++#endif ++ writel(csr.value, &pAdapter->CSRAddress->rxdma.csr.value); ++ ++ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); ++ if (csr.bits.halt_status != 0) { ++ udelay(5); ++ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); ++ if (csr.bits.halt_status != 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "RX Dma failed to exit halt state. CSR 0x%08x\n", ++ csr.value); ++ } ++ } ++ } ++ ++ DBG_RX_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * nic_rx_pkts - Checks the hardware for available packets ++ * @pAdapter: pointer to our adapter ++ * ++ * Returns pMpRfd, a pointer to our MPRFD. ++ * ++ * Checks the hardware for available packets, using completion ring ++ * If packets are available, it gets an RFD from the RecvList, attaches ++ * the packet to it, puts the RFD in the RecvPendList, and also returns ++ * the pointer to the RFD. ++ */ ++PMP_RFD nic_rx_pkts(struct et131x_adapter *pAdapter) ++{ ++ struct _rx_ring_t *pRxLocal = &pAdapter->RxRing; ++ PRX_STATUS_BLOCK_t pRxStatusBlock; ++ PPKT_STAT_DESC_t pPSREntry; ++ PMP_RFD pMpRfd; ++ uint32_t nIndex; ++ uint8_t *pBufVa; ++ unsigned long lockflags; ++ struct list_head *element; ++ uint8_t ringIndex; ++ uint16_t bufferIndex; ++ uint32_t localLen; ++ PKT_STAT_DESC_WORD0_t Word0; ++ ++ ++ DBG_RX_ENTER(et131x_dbginfo); ++ ++ /* RX Status block is written by the DMA engine prior to every ++ * interrupt. It contains the next to be used entry in the Packet ++ * Status Ring, and also the two Free Buffer rings. ++ */ ++ pRxStatusBlock = (PRX_STATUS_BLOCK_t) pRxLocal->pRxStatusVa; ++ ++ if (pRxStatusBlock->Word1.bits.PSRoffset == ++ pRxLocal->local_psr_full.bits.psr_full && ++ pRxStatusBlock->Word1.bits.PSRwrap == ++ pRxLocal->local_psr_full.bits.psr_full_wrap) { ++ /* Looks like this ring is not updated yet */ ++ DBG_RX(et131x_dbginfo, "(0)\n"); ++ DBG_RX_LEAVE(et131x_dbginfo); ++ return NULL; ++ } ++ ++ /* The packet status ring indicates that data is available. */ ++ pPSREntry = (PPKT_STAT_DESC_t) (pRxLocal->pPSRingVa) + ++ pRxLocal->local_psr_full.bits.psr_full; ++ ++ /* Grab any information that is required once the PSR is ++ * advanced, since we can no longer rely on the memory being ++ * accurate ++ */ ++ localLen = pPSREntry->word1.bits.length; ++ ringIndex = (uint8_t) pPSREntry->word1.bits.ri; ++ bufferIndex = (uint16_t) pPSREntry->word1.bits.bi; ++ Word0 = pPSREntry->word0; ++ ++ DBG_RX(et131x_dbginfo, "RX PACKET STATUS\n"); ++ DBG_RX(et131x_dbginfo, "\tlength : %d\n", localLen); ++ DBG_RX(et131x_dbginfo, "\tringIndex : %d\n", ringIndex); ++ DBG_RX(et131x_dbginfo, "\tbufferIndex : %d\n", bufferIndex); ++ DBG_RX(et131x_dbginfo, "\tword0 : 0x%08x\n", Word0.value); ++ ++#if 0 ++ /* Check the Status Word that the MAC has appended to the PSR ++ * entry in case the MAC has detected errors. ++ */ ++ if (Word0.value & ALCATEL_BAD_STATUS) { ++ DBG_ERROR(et131x_dbginfo, ++ "NICRxPkts >> Alcatel Status Word error." ++ "Value 0x%08x\n", pPSREntry->word0.value); ++ } ++#endif ++ ++ /* Indicate that we have used this PSR entry. */ ++ if (++pRxLocal->local_psr_full.bits.psr_full > ++ pRxLocal->PsrNumEntries - 1) { ++ pRxLocal->local_psr_full.bits.psr_full = 0; ++ pRxLocal->local_psr_full.bits.psr_full_wrap ^= 1; ++ } ++ ++ writel(pRxLocal->local_psr_full.value, ++ &pAdapter->CSRAddress->rxdma.psr_full_offset.value); ++ ++#ifndef USE_FBR0 ++ if (ringIndex != 1) { ++ DBG_ERROR(et131x_dbginfo, ++ "NICRxPkts PSR Entry %d indicates " ++ "Buffer Ring 0 in use\n", ++ pRxLocal->local_psr_full.bits.psr_full); ++ DBG_RX_LEAVE(et131x_dbginfo); ++ return NULL; ++ } ++#endif ++ ++#ifdef USE_FBR0 ++ if (ringIndex > 1 || ++ (ringIndex == 0 && ++ bufferIndex > pRxLocal->Fbr0NumEntries - 1) || ++ (ringIndex == 1 && ++ bufferIndex > pRxLocal->Fbr1NumEntries - 1)) ++#else ++ if (ringIndex != 1 || ++ bufferIndex > pRxLocal->Fbr1NumEntries - 1) ++#endif ++ { ++ /* Illegal buffer or ring index cannot be used by S/W*/ ++ DBG_ERROR(et131x_dbginfo, ++ "NICRxPkts PSR Entry %d indicates " ++ "length of %d and/or bad bi(%d)\n", ++ pRxLocal->local_psr_full.bits.psr_full, ++ localLen, bufferIndex); ++ DBG_RX_LEAVE(et131x_dbginfo); ++ return NULL; ++ } ++ ++ /* Get and fill the RFD. */ ++ spin_lock_irqsave(&pAdapter->RcvLock, lockflags); ++ ++ pMpRfd = NULL; ++ element = pRxLocal->RecvList.next; ++ pMpRfd = (PMP_RFD) list_entry(element, MP_RFD, list_node); ++ ++ if (pMpRfd == NULL) { ++ DBG_RX(et131x_dbginfo, ++ "NULL RFD returned from RecvList via list_entry()\n"); ++ DBG_RX_LEAVE(et131x_dbginfo); ++ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); ++ return NULL; ++ } ++ ++ list_del(&pMpRfd->list_node); ++ pRxLocal->nReadyRecv--; ++ ++ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); ++ ++ pMpRfd->iBufferIndex = bufferIndex; ++ pMpRfd->iRingIndex = ringIndex; ++ ++ /* In V1 silicon, there is a bug which screws up filtering of ++ * runt packets. Therefore runt packet filtering is disabled ++ * in the MAC and the packets are dropped here. They are ++ * also counted here. ++ */ ++ if (localLen < (NIC_MIN_PACKET_SIZE + 4)) { ++ pAdapter->Stats.other_errors++; ++ localLen = 0; ++ } ++ ++ if (localLen) { ++ if (pAdapter->ReplicaPhyLoopbk == 1) { ++ pBufVa = pRxLocal->Fbr[ringIndex]->Va[bufferIndex]; ++ ++ if (memcmp(&pBufVa[6], &pAdapter->CurrentAddress[0], ++ ETH_ALEN) == 0) { ++ if (memcmp(&pBufVa[42], "Replica packet", ++ ETH_HLEN)) { ++ pAdapter->ReplicaPhyLoopbkPF = 1; ++ } ++ } ++ DBG_WARNING(et131x_dbginfo, ++ "pBufVa:\t%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pBufVa[6], pBufVa[7], pBufVa[8], ++ pBufVa[9], pBufVa[10], pBufVa[11]); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "CurrentAddr:\t%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAdapter->CurrentAddress[0], ++ pAdapter->CurrentAddress[1], ++ pAdapter->CurrentAddress[2], ++ pAdapter->CurrentAddress[3], ++ pAdapter->CurrentAddress[4], ++ pAdapter->CurrentAddress[5]); ++ } ++ ++ /* Determine if this is a multicast packet coming in */ ++ if ((Word0.value & ALCATEL_MULTICAST_PKT) && ++ !(Word0.value & ALCATEL_BROADCAST_PKT)) { ++ /* Promiscuous mode and Multicast mode are ++ * not mutually exclusive as was first ++ * thought. I guess Promiscuous is just ++ * considered a super-set of the other ++ * filters. Generally filter is 0x2b when in ++ * promiscuous mode. ++ */ ++ if ((pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST) ++ && !(pAdapter->PacketFilter & ET131X_PACKET_TYPE_PROMISCUOUS) ++ && !(pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST)) { ++ pBufVa = pRxLocal->Fbr[ringIndex]-> ++ Va[bufferIndex]; ++ ++ /* Loop through our list to see if the ++ * destination address of this packet ++ * matches one in our list. ++ */ ++ for (nIndex = 0; ++ nIndex < pAdapter->MCAddressCount; ++ nIndex++) { ++ if (pBufVa[0] == ++ pAdapter->MCList[nIndex][0] ++ && pBufVa[1] == ++ pAdapter->MCList[nIndex][1] ++ && pBufVa[2] == ++ pAdapter->MCList[nIndex][2] ++ && pBufVa[3] == ++ pAdapter->MCList[nIndex][3] ++ && pBufVa[4] == ++ pAdapter->MCList[nIndex][4] ++ && pBufVa[5] == ++ pAdapter->MCList[nIndex][5]) { ++ break; ++ } ++ } ++ ++ /* If our index is equal to the number ++ * of Multicast address we have, then ++ * this means we did not find this ++ * packet's matching address in our ++ * list. Set the PacketSize to zero, ++ * so we free our RFD when we return ++ * from this function. ++ */ ++ if (nIndex == pAdapter->MCAddressCount) { ++ localLen = 0; ++ } ++ } ++ ++ if (localLen > 0) { ++ pAdapter->Stats.multircv++; ++ } ++ } else if (Word0.value & ALCATEL_BROADCAST_PKT) { ++ pAdapter->Stats.brdcstrcv++; ++ } else { ++ /* Not sure what this counter measures in ++ * promiscuous mode. Perhaps we should check ++ * the MAC address to see if it is directed ++ * to us in promiscuous mode. ++ */ ++ pAdapter->Stats.unircv++; ++ } ++ } ++ ++ if (localLen > 0) { ++ struct sk_buff *skb = NULL; ++ ++ //pMpRfd->PacketSize = localLen - 4; ++ pMpRfd->PacketSize = localLen; ++ ++ skb = dev_alloc_skb(pMpRfd->PacketSize + 2); ++ if (!skb) { ++ DBG_ERROR(et131x_dbginfo, ++ "Couldn't alloc an SKB for Rx\n"); ++ DBG_RX_LEAVE(et131x_dbginfo); ++ return NULL; ++ } ++ ++ pAdapter->net_stats.rx_bytes += pMpRfd->PacketSize; ++ ++ memcpy(skb_put(skb, pMpRfd->PacketSize), ++ pRxLocal->Fbr[ringIndex]->Va[bufferIndex], ++ pMpRfd->PacketSize); ++ ++ skb->dev = pAdapter->netdev; ++ skb->protocol = eth_type_trans(skb, pAdapter->netdev); ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ netif_rx(skb); ++ } else { ++ pMpRfd->PacketSize = 0; ++ } ++ ++ nic_return_rfd(pAdapter, pMpRfd); ++ ++ DBG_RX(et131x_dbginfo, "(1)\n"); ++ DBG_RX_LEAVE(et131x_dbginfo); ++ return pMpRfd; ++} ++ ++/** ++ * et131x_reset_recv - Reset the receive list ++ * @pAdapter: pointer to our adapter ++ * ++ * Assumption, Rcv spinlock has been acquired. ++ */ ++void et131x_reset_recv(struct et131x_adapter *pAdapter) ++{ ++ PMP_RFD pMpRfd; ++ struct list_head *element; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ DBG_ASSERT(!list_empty(&pAdapter->RxRing.RecvList)); ++ ++ /* Take all the RFD's from the pending list, and stick them on the ++ * RecvList. ++ */ ++ while (!list_empty(&pAdapter->RxRing.RecvPendingList)) { ++ element = pAdapter->RxRing.RecvPendingList.next; ++ ++ pMpRfd = (PMP_RFD) list_entry(element, MP_RFD, list_node); ++ ++ list_del(&pMpRfd->list_node); ++ list_add_tail(&pMpRfd->list_node, &pAdapter->RxRing.RecvList); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_handle_recv_interrupt - Interrupt handler for receive processing ++ * @pAdapter: pointer to our adapter ++ * ++ * Assumption, Rcv spinlock has been acquired. ++ */ ++void et131x_handle_recv_interrupt(struct et131x_adapter *pAdapter) ++{ ++ PMP_RFD pMpRfd = NULL; ++ struct sk_buff *PacketArray[NUM_PACKETS_HANDLED]; ++ PMP_RFD RFDFreeArray[NUM_PACKETS_HANDLED]; ++ uint32_t PacketArrayCount = 0; ++ uint32_t PacketsToHandle; ++ uint32_t PacketFreeCount = 0; ++ bool TempUnfinishedRec = false; ++ ++ DBG_RX_ENTER(et131x_dbginfo); ++ ++ PacketsToHandle = NUM_PACKETS_HANDLED; ++ ++ /* Process up to available RFD's */ ++ while (PacketArrayCount < PacketsToHandle) { ++ if (list_empty(&pAdapter->RxRing.RecvList)) { ++ DBG_ASSERT(pAdapter->RxRing.nReadyRecv == 0); ++ DBG_ERROR(et131x_dbginfo, "NO RFD's !!!!!!!!!!!!!\n"); ++ TempUnfinishedRec = true; ++ break; ++ } ++ ++ pMpRfd = nic_rx_pkts(pAdapter); ++ ++ if (pMpRfd == NULL) { ++ break; ++ } ++ ++ /* Do not receive any packets until a filter has been set. ++ * Do not receive any packets until we are at D0. ++ * Do not receive any packets until we have link. ++ * If length is zero, return the RFD in order to advance the ++ * Free buffer ring. ++ */ ++ if ((!pAdapter->PacketFilter) || ++ (pAdapter->PoMgmt.PowerState != NdisDeviceStateD0) || ++ (!MP_LINK_DETECTED(pAdapter)) || ++ (pMpRfd->PacketSize == 0)) { ++ continue; ++ } ++ ++ /* Increment the number of packets we received */ ++ pAdapter->Stats.ipackets++; ++ ++ /* Set the status on the packet, either resources or success */ ++ if (pAdapter->RxRing.nReadyRecv >= RFD_LOW_WATER_MARK) { ++ /* Put this RFD on the pending list ++ * ++ * NOTE: nic_rx_pkts() above is already returning the ++ * RFD to the RecvList, so don't additionally do that ++ * here. ++ * Besides, we don't really need (at this point) the ++ * pending list anyway. ++ */ ++ //spin_lock_irqsave( &pAdapter->RcvPendLock, lockflags ); ++ //list_add_tail( &pMpRfd->list_node, &pAdapter->RxRing.RecvPendingList ); ++ //spin_unlock_irqrestore( &pAdapter->RcvPendLock, lockflags ); ++ ++ /* Update the number of outstanding Recvs */ ++ //MP_INC_RCV_REF( pAdapter ); ++ } else { ++ RFDFreeArray[PacketFreeCount] = pMpRfd; ++ PacketFreeCount++; ++ ++ DBG_WARNING(et131x_dbginfo, ++ "RFD's are running out !!!!!!!!!!!!!\n"); ++ } ++ ++ PacketArray[PacketArrayCount] = pMpRfd->Packet; ++ PacketArrayCount++; ++ } ++ ++ if ((PacketArrayCount == NUM_PACKETS_HANDLED) || TempUnfinishedRec) { ++ pAdapter->RxRing.UnfinishedReceives = true; ++ writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO, ++ &pAdapter->CSRAddress->global.watchdog_timer); ++ } else { ++ /* Watchdog timer will disable itself if appropriate. */ ++ pAdapter->RxRing.UnfinishedReceives = false; ++ } ++ ++ DBG_RX_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * NICReturnRFD - Recycle a RFD and put it back onto the receive list ++ * @pAdapter: pointer to our adapter ++ * @pMpRfd: pointer to the RFD ++ */ ++void nic_return_rfd(struct et131x_adapter *pAdapter, PMP_RFD pMpRfd) ++{ ++ struct _rx_ring_t *pRxLocal = &pAdapter->RxRing; ++ struct _RXDMA_t __iomem *pRxDma = &pAdapter->CSRAddress->rxdma; ++ uint16_t bi = pMpRfd->iBufferIndex; ++ uint8_t ri = pMpRfd->iRingIndex; ++ unsigned long lockflags; ++ ++ DBG_RX_ENTER(et131x_dbginfo); ++ ++ /* We don't use any of the OOB data besides status. Otherwise, we ++ * need to clean up OOB data ++ */ ++ if ( ++#ifdef USE_FBR0 ++ (ri == 0 && bi < pRxLocal->Fbr0NumEntries) || ++#endif ++ (ri == 1 && bi < pRxLocal->Fbr1NumEntries)) { ++ spin_lock_irqsave(&pAdapter->FbrLock, lockflags); ++ ++ if (ri == 1) { ++ PFBR_DESC_t pNextDesc = ++ (PFBR_DESC_t) (pRxLocal->pFbr1RingVa) + ++ pRxLocal->local_Fbr1_full.bits.val; ++ ++ /* Handle the Free Buffer Ring advancement here. Write ++ * the PA / Buffer Index for the returned buffer into ++ * the oldest (next to be freed)FBR entry ++ */ ++ pNextDesc->addr_hi = pRxLocal->Fbr[1]->PAHigh[bi]; ++ pNextDesc->addr_lo = pRxLocal->Fbr[1]->PALow[bi]; ++ pNextDesc->word2.value = bi; ++ ++ if (++pRxLocal->local_Fbr1_full.bits.val > ++ (pRxLocal->Fbr1NumEntries - 1)) { ++ pRxLocal->local_Fbr1_full.bits.val = 0; ++ pRxLocal->local_Fbr1_full.bits.wrap ^= 1; ++ } ++ ++ writel(pRxLocal->local_Fbr1_full.value, ++ &pRxDma->fbr1_full_offset.value); ++ } ++#ifdef USE_FBR0 ++ else { ++ PFBR_DESC_t pNextDesc = ++ (PFBR_DESC_t) pRxLocal->pFbr0RingVa + ++ pRxLocal->local_Fbr0_full.bits.val; ++ ++ /* Handle the Free Buffer Ring advancement here. Write ++ * the PA / Buffer Index for the returned buffer into ++ * the oldest (next to be freed) FBR entry ++ */ ++ pNextDesc->addr_hi = pRxLocal->Fbr[0]->PAHigh[bi]; ++ pNextDesc->addr_lo = pRxLocal->Fbr[0]->PALow[bi]; ++ pNextDesc->word2.value = bi; ++ ++ if (++pRxLocal->local_Fbr0_full.bits.val > ++ (pRxLocal->Fbr0NumEntries - 1)) { ++ pRxLocal->local_Fbr0_full.bits.val = 0; ++ pRxLocal->local_Fbr0_full.bits.wrap ^= 1; ++ } ++ ++ writel(pRxLocal->local_Fbr0_full.value, ++ &pRxDma->fbr0_full_offset.value); ++ } ++#endif ++ spin_unlock_irqrestore(&pAdapter->FbrLock, lockflags); ++ } else { ++ DBG_ERROR(et131x_dbginfo, ++ "NICReturnRFD illegal Buffer Index returned\n"); ++ } ++ ++ /* The processing on this RFD is done, so put it back on the tail of ++ * our list ++ */ ++ spin_lock_irqsave(&pAdapter->RcvLock, lockflags); ++ list_add_tail(&pMpRfd->list_node, &pRxLocal->RecvList); ++ pRxLocal->nReadyRecv++; ++ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); ++ ++ DBG_ASSERT(pRxLocal->nReadyRecv <= pRxLocal->NumRfd); ++ DBG_RX_LEAVE(et131x_dbginfo); ++} +diff --git a/drivers/staging/et131x/et1310_rx.h b/drivers/staging/et131x/et1310_rx.h +new file mode 100644 +index 0000000..ea66dbc +--- /dev/null ++++ b/drivers/staging/et131x/et1310_rx.h +@@ -0,0 +1,373 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_rx.h - Defines, structs, enums, prototypes, etc. pertaining to data ++ * reception. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET1310_RX_H__ ++#define __ET1310_RX_H__ ++ ++#include "et1310_address_map.h" ++ ++#define USE_FBR0 true ++ ++#ifdef USE_FBR0 ++//#define FBR0_BUFFER_SIZE 256 ++#endif ++ ++//#define FBR1_BUFFER_SIZE 2048 ++ ++#define FBR_CHUNKS 32 ++ ++#define MAX_DESC_PER_RING_RX 1024 ++ ++/* number of RFDs - default and min */ ++#ifdef USE_FBR0 ++#define RFD_LOW_WATER_MARK 40 ++#define NIC_MIN_NUM_RFD 64 ++#define NIC_DEFAULT_NUM_RFD 1024 ++#else ++#define RFD_LOW_WATER_MARK 20 ++#define NIC_MIN_NUM_RFD 64 ++#define NIC_DEFAULT_NUM_RFD 256 ++#endif ++ ++#define NUM_PACKETS_HANDLED 256 ++ ++#define ALCATEL_BAD_STATUS 0xe47f0000 ++#define ALCATEL_MULTICAST_PKT 0x01000000 ++#define ALCATEL_BROADCAST_PKT 0x02000000 ++ ++/* typedefs for Free Buffer Descriptors */ ++typedef union _FBR_WORD2_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 reserved:22; // bits 10-31 ++ u32 bi:10; // bits 0-9(Buffer Index) ++#else ++ u32 bi:10; // bits 0-9(Buffer Index) ++ u32 reserved:22; // bit 10-31 ++#endif ++ } bits; ++} FBR_WORD2_t, *PFBR_WORD2_t; ++ ++typedef struct _FBR_DESC_t { ++ u32 addr_lo; ++ u32 addr_hi; ++ FBR_WORD2_t word2; ++} FBR_DESC_t, *PFBR_DESC_t; ++ ++/* Typedefs for Packet Status Ring Descriptors */ ++typedef union _PKT_STAT_DESC_WORD0_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ // top 16 bits are from the Alcatel Status Word as enumerated in ++ // PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2) ++#if 0 ++ u32 asw_trunc:1; // bit 31(Rx frame truncated) ++#endif ++ u32 asw_long_evt:1; // bit 31(Rx long event) ++ u32 asw_VLAN_tag:1; // bit 30(VLAN tag detected) ++ u32 asw_unsupported_op:1; // bit 29(unsupported OP code) ++ u32 asw_pause_frame:1; // bit 28(is a pause frame) ++ u32 asw_control_frame:1; // bit 27(is a control frame) ++ u32 asw_dribble_nibble:1; // bit 26(spurious bits after EOP) ++ u32 asw_broadcast:1; // bit 25(has a broadcast address) ++ u32 asw_multicast:1; // bit 24(has a multicast address) ++ u32 asw_OK:1; // bit 23(valid CRC + no code error) ++ u32 asw_too_long:1; // bit 22(frame length > 1518 bytes) ++ u32 asw_len_chk_err:1; // bit 21(frame length field incorrect) ++ u32 asw_CRC_err:1; // bit 20(CRC error) ++ u32 asw_code_err:1; // bit 19(one or more nibbles signalled as errors) ++ u32 asw_false_carrier_event:1; // bit 18(bad carrier since last good packet) ++ u32 asw_RX_DV_event:1; // bit 17(short receive event detected) ++ u32 asw_prev_pkt_dropped:1;// bit 16(e.g. IFG too small on previous) ++ u32 unused:5; // bits 11-15 ++ u32 vp:1; // bit 10(VLAN Packet) ++ u32 jp:1; // bit 9(Jumbo Packet) ++ u32 ft:1; // bit 8(Frame Truncated) ++ u32 drop:1; // bit 7(Drop packet) ++ u32 rxmac_error:1; // bit 6(RXMAC Error Indicator) ++ u32 wol:1; // bit 5(WOL Event) ++ u32 tcpp:1; // bit 4(TCP checksum pass) ++ u32 tcpa:1; // bit 3(TCP checksum assist) ++ u32 ipp:1; // bit 2(IP checksum pass) ++ u32 ipa:1; // bit 1(IP checksum assist) ++ u32 hp:1; // bit 0(hash pass) ++#else ++ u32 hp:1; // bit 0(hash pass) ++ u32 ipa:1; // bit 1(IP checksum assist) ++ u32 ipp:1; // bit 2(IP checksum pass) ++ u32 tcpa:1; // bit 3(TCP checksum assist) ++ u32 tcpp:1; // bit 4(TCP checksum pass) ++ u32 wol:1; // bit 5(WOL Event) ++ u32 rxmac_error:1; // bit 6(RXMAC Error Indicator) ++ u32 drop:1; // bit 7(Drop packet) ++ u32 ft:1; // bit 8(Frame Truncated) ++ u32 jp:1; // bit 9(Jumbo Packet) ++ u32 vp:1; // bit 10(VLAN Packet) ++ u32 unused:5; // bits 11-15 ++ u32 asw_prev_pkt_dropped:1;// bit 16(e.g. IFG too small on previous) ++ u32 asw_RX_DV_event:1; // bit 17(short receive event detected) ++ u32 asw_false_carrier_event:1; // bit 18(bad carrier since last good packet) ++ u32 asw_code_err:1; // bit 19(one or more nibbles signalled as errors) ++ u32 asw_CRC_err:1; // bit 20(CRC error) ++ u32 asw_len_chk_err:1; // bit 21(frame length field incorrect) ++ u32 asw_too_long:1; // bit 22(frame length > 1518 bytes) ++ u32 asw_OK:1; // bit 23(valid CRC + no code error) ++ u32 asw_multicast:1; // bit 24(has a multicast address) ++ u32 asw_broadcast:1; // bit 25(has a broadcast address) ++ u32 asw_dribble_nibble:1; // bit 26(spurious bits after EOP) ++ u32 asw_control_frame:1; // bit 27(is a control frame) ++ u32 asw_pause_frame:1; // bit 28(is a pause frame) ++ u32 asw_unsupported_op:1; // bit 29(unsupported OP code) ++ u32 asw_VLAN_tag:1; // bit 30(VLAN tag detected) ++ u32 asw_long_evt:1; // bit 31(Rx long event) ++#if 0 ++ u32 asw_trunc:1; // bit 31(Rx frame truncated) ++#endif ++#endif ++ } bits; ++} PKT_STAT_DESC_WORD0_t, *PPKT_STAT_WORD0_t; ++ ++typedef union _PKT_STAT_DESC_WORD1_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:4; // bits 28-31 ++ u32 ri:2; // bits 26-27(Ring Index) ++ u32 bi:10; // bits 16-25(Buffer Index) ++ u32 length:16; // bit 0-15(length in bytes) ++#else ++ u32 length:16; // bit 0-15(length in bytes) ++ u32 bi:10; // bits 16-25(Buffer Index) ++ u32 ri:2; // bits 26-27(Ring Index) ++ u32 unused:4; // bits 28-31 ++#endif ++ } bits; ++} PKT_STAT_DESC_WORD1_t, *PPKT_STAT_WORD1_t; ++ ++typedef struct _PKT_STAT_DESC_t { ++ PKT_STAT_DESC_WORD0_t word0; ++ PKT_STAT_DESC_WORD1_t word1; ++} PKT_STAT_DESC_t, *PPKT_STAT_DESC_t; ++ ++/* Typedefs for the RX DMA status word */ ++ ++/* ++ * RXSTAT_WORD0_t structure holds part of the status bits of the Rx DMA engine ++ * that get copied out to memory by the ET-1310. Word 0 is a 32 bit word ++ * whichcontains Free Buffer ring 0 and 1 available offset. ++ */ ++typedef union _rxstat_word0_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 FBR1unused:5; // bits 27-31 ++ u32 FBR1wrap:1; // bit 26 ++ u32 FBR1offset:10; // bits 16-25 ++ u32 FBR0unused:5; // bits 11-15 ++ u32 FBR0wrap:1; // bit 10 ++ u32 FBR0offset:10; // bits 0-9 ++#else ++ u32 FBR0offset:10; // bits 0-9 ++ u32 FBR0wrap:1; // bit 10 ++ u32 FBR0unused:5; // bits 11-15 ++ u32 FBR1offset:10; // bits 16-25 ++ u32 FBR1wrap:1; // bit 26 ++ u32 FBR1unused:5; // bits 27-31 ++#endif ++ } bits; ++} RXSTAT_WORD0_t, *PRXSTAT_WORD0_t; ++ ++/* ++ * RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine ++ * that get copied out to memory by the ET-1310. Word 3 is a 32 bit word ++ * which contains the Packet Status Ring available offset. ++ */ ++typedef union _rxstat_word1_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 PSRunused:3; // bits 29-31 ++ u32 PSRwrap:1; // bit 28 ++ u32 PSRoffset:12; // bits 16-27 ++ u32 reserved:16; // bits 0-15 ++#else ++ u32 reserved:16; // bits 0-15 ++ u32 PSRoffset:12; // bits 16-27 ++ u32 PSRwrap:1; // bit 28 ++ u32 PSRunused:3; // bits 29-31 ++#endif ++ } bits; ++} RXSTAT_WORD1_t, *PRXSTAT_WORD1_t; ++ ++/* ++ * RX_STATUS_BLOCK_t is sructure representing the status of the Rx DMA engine ++ * it sits in free memory, and is pointed to by 0x101c / 0x1020 ++ */ ++typedef struct _rx_status_block_t { ++ RXSTAT_WORD0_t Word0; ++ RXSTAT_WORD1_t Word1; ++} RX_STATUS_BLOCK_t, *PRX_STATUS_BLOCK_t; ++ ++/* ++ * Structure for look-up table holding free buffer ring pointers ++ */ ++typedef struct _FbrLookupTable { ++ void *Va[MAX_DESC_PER_RING_RX]; ++ void *Buffer1[MAX_DESC_PER_RING_RX]; ++ void *Buffer2[MAX_DESC_PER_RING_RX]; ++ u32 PAHigh[MAX_DESC_PER_RING_RX]; ++ u32 PALow[MAX_DESC_PER_RING_RX]; ++} FBRLOOKUPTABLE, *PFBRLOOKUPTABLE; ++ ++typedef enum { ++ ONE_PACKET_INTERRUPT, ++ FOUR_PACKET_INTERRUPT ++} eRX_INTERRUPT_STATE_t, *PeRX_INTERRUPT_STATE_t; ++ ++/* ++ * Structure to hold the skb's in a list ++ */ ++typedef struct rx_skb_list_elem { ++ struct list_head skb_list_elem; ++ dma_addr_t dma_addr; ++ struct sk_buff *skb; ++} RX_SKB_LIST_ELEM, *PRX_SKB_LIST_ELEM; ++ ++/* ++ * RX_RING_t is sructure representing the adaptor's local reference(s) to the ++ * rings ++ */ ++typedef struct _rx_ring_t { ++#ifdef USE_FBR0 ++ void *pFbr0RingVa; ++ dma_addr_t pFbr0RingPa; ++ void *Fbr0MemVa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; ++ dma_addr_t Fbr0MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; ++ uint64_t Fbr0Realpa; ++ uint64_t Fbr0offset; ++ DMA10W_t local_Fbr0_full; ++ u32 Fbr0NumEntries; ++ u32 Fbr0BufferSize; ++#endif ++ void *pFbr1RingVa; ++ dma_addr_t pFbr1RingPa; ++ void *Fbr1MemVa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; ++ dma_addr_t Fbr1MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; ++ uint64_t Fbr1Realpa; ++ uint64_t Fbr1offset; ++ FBRLOOKUPTABLE *Fbr[2]; ++ DMA10W_t local_Fbr1_full; ++ u32 Fbr1NumEntries; ++ u32 Fbr1BufferSize; ++ ++ void *pPSRingVa; ++ dma_addr_t pPSRingPa; ++ uint64_t pPSRingRealPa; ++ uint64_t pPSRingOffset; ++ RXDMA_PSR_FULL_OFFSET_t local_psr_full; ++ u32 PsrNumEntries; ++ ++ void *pRxStatusVa; ++ dma_addr_t pRxStatusPa; ++ uint64_t RxStatusRealPA; ++ uint64_t RxStatusOffset; ++ ++ struct list_head RecvBufferPool; ++ ++ /* RECV */ ++ struct list_head RecvList; ++ struct list_head RecvPendingList; ++ u32 nReadyRecv; ++ ++ u32 NumRfd; ++ ++ bool UnfinishedReceives; ++ ++ struct list_head RecvPacketPool; ++ ++ /* lookaside lists */ ++ struct kmem_cache *RecvLookaside; ++} RX_RING_t, *PRX_RING_t; ++ ++/* Forward reference of RFD */ ++struct _MP_RFD; ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++/* PROTOTYPES for Initialization */ ++int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter); ++void et131x_rx_dma_memory_free(struct et131x_adapter *adapter); ++int et131x_rfd_resources_alloc(struct et131x_adapter *adapter, ++ struct _MP_RFD *pMpRfd); ++void et131x_rfd_resources_free(struct et131x_adapter *adapter, ++ struct _MP_RFD *pMpRfd); ++int et131x_init_recv(struct et131x_adapter *adapter); ++ ++void ConfigRxDmaRegs(struct et131x_adapter *adapter); ++void SetRxDmaTimer(struct et131x_adapter *adapter); ++void et131x_rx_dma_disable(struct et131x_adapter *adapter); ++void et131x_rx_dma_enable(struct et131x_adapter *adapter); ++ ++void et131x_reset_recv(struct et131x_adapter *adapter); ++ ++void et131x_handle_recv_interrupt(struct et131x_adapter *adapter); ++ ++#endif /* __ET1310_RX_H__ */ +diff --git a/drivers/staging/et131x/et1310_tx.c b/drivers/staging/et131x/et1310_tx.c +new file mode 100644 +index 0000000..a95c260 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_tx.c +@@ -0,0 +1,1525 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_tx.c - Routines used to perform data transmission. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++#include "et131x_isr.h" ++ ++#include "et1310_tx.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++static void et131x_update_tcb_list(struct et131x_adapter *pAdapter); ++static void et131x_check_send_wait_list(struct et131x_adapter *pAdapter); ++static inline void et131x_free_send_packet(struct et131x_adapter *pAdapter, ++ PMP_TCB pMpTcb); ++static int et131x_send_packet(struct sk_buff *skb, ++ struct et131x_adapter *pAdapter); ++static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb); ++ ++/** ++ * et131x_tx_dma_memory_alloc ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success and errno on failure (as defined in errno.h). ++ * ++ * Allocates memory that will be visible both to the device and to the CPU. ++ * The OS will pass us packets, pointers to which we will insert in the Tx ++ * Descriptor queue. The device will read this queue to find the packets in ++ * memory. The device will update the "status" in memory each time it xmits a ++ * packet. ++ */ ++int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) ++{ ++ int desc_size = 0; ++ TX_RING_t *tx_ring = &adapter->TxRing; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Allocate memory for the TCB's (Transmit Control Block) */ ++ adapter->TxRing.MpTcbMem = (MP_TCB *) kcalloc(NUM_TCB, sizeof(MP_TCB), ++ GFP_ATOMIC | GFP_DMA); ++ if (!adapter->TxRing.MpTcbMem) { ++ DBG_ERROR(et131x_dbginfo, "Cannot alloc memory for TCBs\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Allocate enough memory for the Tx descriptor ring, and allocate ++ * some extra so that the ring can be aligned on a 4k boundary. ++ */ ++ desc_size = (sizeof(TX_DESC_ENTRY_t) * NUM_DESC_PER_RING_TX) + 4096 - 1; ++ tx_ring->pTxDescRingVa = ++ (PTX_DESC_ENTRY_t) pci_alloc_consistent(adapter->pdev, desc_size, ++ &tx_ring->pTxDescRingPa); ++ if (!adapter->TxRing.pTxDescRingVa) { ++ DBG_ERROR(et131x_dbginfo, "Cannot alloc memory for Tx Ring\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Save physical address ++ * ++ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, ++ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses ++ * are ever returned, make sure the high part is retrieved here before ++ * storing the adjusted address. ++ */ ++ tx_ring->pTxDescRingAdjustedPa = tx_ring->pTxDescRingPa; ++ ++ /* Align Tx Descriptor Ring on a 4k (0x1000) byte boundary */ ++ et131x_align_allocated_memory(adapter, ++ &tx_ring->pTxDescRingAdjustedPa, ++ &tx_ring->TxDescOffset, 0x0FFF); ++ ++ tx_ring->pTxDescRingVa += tx_ring->TxDescOffset; ++ ++ /* Allocate memory for the Tx status block */ ++ tx_ring->pTxStatusVa = pci_alloc_consistent(adapter->pdev, ++ sizeof(TX_STATUS_BLOCK_t), ++ &tx_ring->pTxStatusPa); ++ if (!adapter->TxRing.pTxStatusPa) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot alloc memory for Tx status block\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ /* Allocate memory for a dummy buffer */ ++ tx_ring->pTxDummyBlkVa = pci_alloc_consistent(adapter->pdev, ++ NIC_MIN_PACKET_SIZE, ++ &tx_ring->pTxDummyBlkPa); ++ if (!adapter->TxRing.pTxDummyBlkPa) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot alloc memory for Tx dummy buffer\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++/** ++ * et131x_tx_dma_memory_free - Free all memory allocated within this module ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success and errno on failure (as defined in errno.h). ++ */ ++void et131x_tx_dma_memory_free(struct et131x_adapter *adapter) ++{ ++ int desc_size = 0; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ if (adapter->TxRing.pTxDescRingVa) { ++ /* Free memory relating to Tx rings here */ ++ adapter->TxRing.pTxDescRingVa -= adapter->TxRing.TxDescOffset; ++ ++ desc_size = ++ (sizeof(TX_DESC_ENTRY_t) * NUM_DESC_PER_RING_TX) + 4096 - 1; ++ ++ pci_free_consistent(adapter->pdev, ++ desc_size, ++ adapter->TxRing.pTxDescRingVa, ++ adapter->TxRing.pTxDescRingPa); ++ ++ adapter->TxRing.pTxDescRingVa = NULL; ++ } ++ ++ /* Free memory for the Tx status block */ ++ if (adapter->TxRing.pTxStatusVa) { ++ pci_free_consistent(adapter->pdev, ++ sizeof(TX_STATUS_BLOCK_t), ++ adapter->TxRing.pTxStatusVa, ++ adapter->TxRing.pTxStatusPa); ++ ++ adapter->TxRing.pTxStatusVa = NULL; ++ } ++ ++ /* Free memory for the dummy buffer */ ++ if (adapter->TxRing.pTxDummyBlkVa) { ++ pci_free_consistent(adapter->pdev, ++ NIC_MIN_PACKET_SIZE, ++ adapter->TxRing.pTxDummyBlkVa, ++ adapter->TxRing.pTxDummyBlkPa); ++ ++ adapter->TxRing.pTxDummyBlkVa = NULL; ++ } ++ ++ /* Free the memory for MP_TCB structures */ ++ if (adapter->TxRing.MpTcbMem) { ++ kfree(adapter->TxRing.MpTcbMem); ++ adapter->TxRing.MpTcbMem = NULL; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * ConfigTxDmaRegs - Set up the tx dma section of the JAGCore. ++ * @adapter: pointer to our private adapter structure ++ */ ++void ConfigTxDmaRegs(struct et131x_adapter *pAdapter) ++{ ++ struct _TXDMA_t __iomem *pTxDma = &pAdapter->CSRAddress->txdma; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Load the hardware with the start of the transmit descriptor ring. */ ++ writel((uint32_t) (pAdapter->TxRing.pTxDescRingAdjustedPa >> 32), ++ &pTxDma->pr_base_hi); ++ writel((uint32_t) pAdapter->TxRing.pTxDescRingAdjustedPa, ++ &pTxDma->pr_base_lo); ++ ++ /* Initialise the transmit DMA engine */ ++ writel(NUM_DESC_PER_RING_TX - 1, &pTxDma->pr_num_des.value); ++ ++ /* Load the completion writeback physical address ++ * ++ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, ++ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses ++ * are ever returned, make sure the high part is retrieved here before ++ * storing the adjusted address. ++ */ ++ writel(0, &pTxDma->dma_wb_base_hi); ++ writel(pAdapter->TxRing.pTxStatusPa, &pTxDma->dma_wb_base_lo); ++ ++ memset(pAdapter->TxRing.pTxStatusVa, 0, sizeof(TX_STATUS_BLOCK_t)); ++ ++ writel(0, &pTxDma->service_request.value); ++ pAdapter->TxRing.txDmaReadyToSend.value = 0; ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_tx_dma_disable - Stop of Tx_DMA on the ET1310 ++ * @pAdapter: pointer to our adapter structure ++ */ ++void et131x_tx_dma_disable(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Setup the tramsmit dma configuration register */ ++ writel(0x101, &pAdapter->CSRAddress->txdma.csr.value); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_tx_dma_enable - re-start of Tx_DMA on the ET1310. ++ * @pAdapter: pointer to our adapter structure ++ * ++ * Mainly used after a return to the D0 (full-power) state from a lower state. ++ */ ++void et131x_tx_dma_enable(struct et131x_adapter *pAdapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ if (pAdapter->RegistryPhyLoopbk) { ++ /* TxDMA is disabled for loopback operation. */ ++ writel(0x101, &pAdapter->CSRAddress->txdma.csr.value); ++ } else { ++ TXDMA_CSR_t csr = { 0 }; ++ ++ /* Setup the transmit dma configuration register for normal ++ * operation ++ */ ++ csr.bits.sngl_epkt_mode = 1; ++ csr.bits.halt = 0; ++ csr.bits.cache_thrshld = pAdapter->RegistryDMACache; ++ writel(csr.value, &pAdapter->CSRAddress->txdma.csr.value); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_init_send - Initialize send data structures ++ * @adapter: pointer to our private adapter structure ++ */ ++void et131x_init_send(struct et131x_adapter *adapter) ++{ ++ PMP_TCB pMpTcb; ++ uint32_t TcbCount; ++ TX_RING_t *tx_ring; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Setup some convenience pointers */ ++ tx_ring = &adapter->TxRing; ++ pMpTcb = adapter->TxRing.MpTcbMem; ++ ++ tx_ring->TCBReadyQueueHead = pMpTcb; ++ ++ /* Go through and set up each TCB */ ++ for (TcbCount = 0; TcbCount < NUM_TCB; TcbCount++) { ++ memset(pMpTcb, 0, sizeof(MP_TCB)); ++ ++ /* Set the link pointer in HW TCB to the next TCB in the ++ * chain. If this is the last TCB in the chain, also set the ++ * tail pointer. ++ */ ++ if (TcbCount < NUM_TCB - 1) { ++ pMpTcb->Next = pMpTcb + 1; ++ } else { ++ tx_ring->TCBReadyQueueTail = pMpTcb; ++ pMpTcb->Next = (PMP_TCB) NULL; ++ } ++ ++ pMpTcb++; ++ } ++ ++ /* Curr send queue should now be empty */ ++ tx_ring->CurrSendHead = (PMP_TCB) NULL; ++ tx_ring->CurrSendTail = (PMP_TCB) NULL; ++ ++ INIT_LIST_HEAD(&adapter->TxRing.SendWaitQueue); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_send_packets - This function is called by the OS to send packets ++ * @skb: the packet(s) to send ++ * @netdev:device on which to TX the above packet(s) ++ * ++ * Return 0 in almost all cases; non-zero value in extreme hard failure only ++ */ ++int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev) ++{ ++ int status = 0; ++ struct et131x_adapter *pAdapter = NULL; ++ ++ DBG_TX_ENTER(et131x_dbginfo); ++ ++ pAdapter = netdev_priv(netdev); ++ ++ /* Send these packets ++ * ++ * NOTE: The Linux Tx entry point is only given one packet at a time ++ * to Tx, so the PacketCount and it's array used makes no sense here ++ */ ++ ++ /* Queue is not empty or TCB is not available */ ++ if (!list_empty(&pAdapter->TxRing.SendWaitQueue) || ++ MP_TCB_RESOURCES_NOT_AVAILABLE(pAdapter)) { ++ /* NOTE: If there's an error on send, no need to queue the ++ * packet under Linux; if we just send an error up to the ++ * netif layer, it will resend the skb to us. ++ */ ++ DBG_VERBOSE(et131x_dbginfo, "TCB Resources Not Available\n"); ++ status = -ENOMEM; ++ } else { ++ /* We need to see if the link is up; if it's not, make the ++ * netif layer think we're good and drop the packet ++ */ ++ //if( MP_SHOULD_FAIL_SEND( pAdapter ) || pAdapter->DriverNoPhyAccess ) ++ if (MP_SHOULD_FAIL_SEND(pAdapter) || pAdapter->DriverNoPhyAccess ++ || !netif_carrier_ok(netdev)) { ++ DBG_VERBOSE(et131x_dbginfo, ++ "Can't Tx, Link is DOWN; drop the packet\n"); ++ ++ dev_kfree_skb_any(skb); ++ skb = NULL; ++ ++ pAdapter->net_stats.tx_dropped++; ++ } else { ++ status = et131x_send_packet(skb, pAdapter); ++ ++ if (status == -ENOMEM) { ++ ++ /* NOTE: If there's an error on send, no need ++ * to queue the packet under Linux; if we just ++ * send an error up to the netif layer, it ++ * will resend the skb to us. ++ */ ++ DBG_WARNING(et131x_dbginfo, ++ "Resources problem, Queue tx packet\n"); ++ } else if (status != 0) { ++ /* On any other error, make netif think we're ++ * OK and drop the packet ++ */ ++ DBG_WARNING(et131x_dbginfo, ++ "General error, drop packet\n"); ++ ++ dev_kfree_skb_any(skb); ++ skb = NULL; ++ ++ pAdapter->net_stats.tx_dropped++; ++ } ++ } ++ } ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_send_packet - Do the work to send a packet ++ * @skb: the packet(s) to send ++ * @pAdapter: a pointer to the device's private adapter structure ++ * ++ * Return 0 in almost all cases; non-zero value in extreme hard failure only. ++ * ++ * Assumption: Send spinlock has been acquired ++ */ ++static int et131x_send_packet(struct sk_buff *skb, ++ struct et131x_adapter *pAdapter) ++{ ++ int status = 0; ++ PMP_TCB pMpTcb = NULL; ++ uint16_t *pShBufVa; ++ unsigned long lockflags; ++ ++ DBG_TX_ENTER(et131x_dbginfo); ++ ++ /* Is our buffer scattered, or continuous? */ ++ if (skb_shinfo(skb)->nr_frags == 0) { ++ DBG_TX(et131x_dbginfo, "Scattered buffer: NO\n"); ++ } else { ++ DBG_TX(et131x_dbginfo, "Scattered buffer: YES, Num Frags: %d\n", ++ skb_shinfo(skb)->nr_frags); ++ } ++ ++ /* All packets must have at least a MAC address and a protocol type */ ++ if (skb->len < ETH_HLEN) { ++ DBG_ERROR(et131x_dbginfo, ++ "Packet size < ETH_HLEN (14 bytes)\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ /* Get a TCB for this packet */ ++ spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags); ++ ++ pMpTcb = pAdapter->TxRing.TCBReadyQueueHead; ++ ++ if (pMpTcb == NULL) { ++ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); ++ ++ DBG_WARNING(et131x_dbginfo, "Can't obtain a TCB\n"); ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return -ENOMEM; ++ } ++ ++ pAdapter->TxRing.TCBReadyQueueHead = pMpTcb->Next; ++ ++ if (pAdapter->TxRing.TCBReadyQueueHead == NULL) { ++ pAdapter->TxRing.TCBReadyQueueTail = NULL; ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); ++ ++ pMpTcb->PacketLength = skb->len; ++ pMpTcb->Packet = skb; ++ ++ if ((skb->data != NULL) && ((skb->len - skb->data_len) >= 6)) { ++ pShBufVa = (uint16_t *) skb->data; ++ ++ if ((pShBufVa[0] == 0xffff) && ++ (pShBufVa[1] == 0xffff) && (pShBufVa[2] == 0xffff)) { ++ MP_SET_FLAG(pMpTcb, fMP_DEST_BROAD); ++ } else if ((pShBufVa[0] & 0x3) == 0x0001) { ++ MP_SET_FLAG(pMpTcb, fMP_DEST_MULTI); ++ } ++ } ++ ++ pMpTcb->Next = NULL; ++ ++ /* Call the NIC specific send handler. */ ++ if (status == 0) { ++ status = nic_send_packet(pAdapter, pMpTcb); ++ } ++ ++ if (status != 0) { ++ spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags); ++ ++ if (pAdapter->TxRing.TCBReadyQueueTail) { ++ pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb; ++ } else { ++ /* Apparently ready Q is empty. */ ++ pAdapter->TxRing.TCBReadyQueueHead = pMpTcb; ++ } ++ ++ pAdapter->TxRing.TCBReadyQueueTail = pMpTcb; ++ ++ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return status; ++ } ++ ++ DBG_ASSERT(pAdapter->TxRing.nBusySend <= NUM_TCB); ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++/** ++ * nic_send_packet - NIC specific send handler for version B silicon. ++ * @pAdapter: pointer to our adapter ++ * @pMpTcb: pointer to MP_TCB ++ * ++ * Returns 0 or errno. ++ */ ++static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb) ++{ ++ uint32_t loopIndex; ++ TX_DESC_ENTRY_t CurDesc[24]; ++ uint32_t FragmentNumber = 0; ++ uint32_t iThisCopy, iRemainder; ++ struct sk_buff *pPacket = pMpTcb->Packet; ++ uint32_t FragListCount = skb_shinfo(pPacket)->nr_frags + 1; ++ struct skb_frag_struct *pFragList = &skb_shinfo(pPacket)->frags[0]; ++ unsigned long lockflags1, lockflags2; ++ ++ DBG_TX_ENTER(et131x_dbginfo); ++ ++ /* Part of the optimizations of this send routine restrict us to ++ * sending 24 fragments at a pass. In practice we should never see ++ * more than 5 fragments. ++ * ++ * NOTE: The older version of this function (below) can handle any ++ * number of fragments. If needed, we can call this function, ++ * although it is less efficient. ++ */ ++ if (FragListCount > 23) { ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ memset(CurDesc, 0, sizeof(TX_DESC_ENTRY_t) * (FragListCount + 1)); ++ ++ for (loopIndex = 0; loopIndex < FragListCount; loopIndex++) { ++ /* If there is something in this element, lets get a ++ * descriptor from the ring and get the necessary data ++ */ ++ if (loopIndex == 0) { ++ /* If the fragments are smaller than a standard MTU, ++ * then map them to a single descriptor in the Tx ++ * Desc ring. However, if they're larger, as is ++ * possible with support for jumbo packets, then ++ * split them each across 2 descriptors. ++ * ++ * This will work until we determine why the hardware ++ * doesn't seem to like large fragments. ++ */ ++ if ((pPacket->len - pPacket->data_len) <= 1514) { ++ DBG_TX(et131x_dbginfo, ++ "Got packet of length %d, " ++ "filling desc entry %d, " ++ "TCB: 0x%p\n", ++ (pPacket->len - pPacket->data_len), ++ pAdapter->TxRing.txDmaReadyToSend.bits. ++ val, pMpTcb); ++ ++ CurDesc[FragmentNumber].DataBufferPtrHigh = 0; ++ ++ CurDesc[FragmentNumber].word2.bits. ++ length_in_bytes = ++ pPacket->len - pPacket->data_len; ++ ++ /* NOTE: Here, the dma_addr_t returned from ++ * pci_map_single() is implicitly cast as a ++ * uint32_t. Although dma_addr_t can be ++ * 64-bit, the address returned by ++ * pci_map_single() is always 32-bit ++ * addressable (as defined by the pci/dma ++ * subsystem) ++ */ ++ CurDesc[FragmentNumber++].DataBufferPtrLow = ++ pci_map_single(pAdapter->pdev, ++ pPacket->data, ++ pPacket->len - ++ pPacket->data_len, ++ PCI_DMA_TODEVICE); ++ } else { ++ DBG_TX(et131x_dbginfo, ++ "Got packet of length %d, " ++ "filling desc entry %d, " ++ "TCB: 0x%p\n", ++ (pPacket->len - pPacket->data_len), ++ pAdapter->TxRing.txDmaReadyToSend.bits. ++ val, pMpTcb); ++ ++ CurDesc[FragmentNumber].DataBufferPtrHigh = 0; ++ ++ CurDesc[FragmentNumber].word2.bits. ++ length_in_bytes = ++ ((pPacket->len - pPacket->data_len) / 2); ++ ++ /* NOTE: Here, the dma_addr_t returned from ++ * pci_map_single() is implicitly cast as a ++ * uint32_t. Although dma_addr_t can be ++ * 64-bit, the address returned by ++ * pci_map_single() is always 32-bit ++ * addressable (as defined by the pci/dma ++ * subsystem) ++ */ ++ CurDesc[FragmentNumber++].DataBufferPtrLow = ++ pci_map_single(pAdapter->pdev, ++ pPacket->data, ++ ((pPacket->len - ++ pPacket->data_len) / 2), ++ PCI_DMA_TODEVICE); ++ CurDesc[FragmentNumber].DataBufferPtrHigh = 0; ++ ++ CurDesc[FragmentNumber].word2.bits. ++ length_in_bytes = ++ ((pPacket->len - pPacket->data_len) / 2); ++ ++ /* NOTE: Here, the dma_addr_t returned from ++ * pci_map_single() is implicitly cast as a ++ * uint32_t. Although dma_addr_t can be ++ * 64-bit, the address returned by ++ * pci_map_single() is always 32-bit ++ * addressable (as defined by the pci/dma ++ * subsystem) ++ */ ++ CurDesc[FragmentNumber++].DataBufferPtrLow = ++ pci_map_single(pAdapter->pdev, ++ pPacket->data + ++ ((pPacket->len - ++ pPacket->data_len) / 2), ++ ((pPacket->len - ++ pPacket->data_len) / 2), ++ PCI_DMA_TODEVICE); ++ } ++ } else { ++ DBG_TX(et131x_dbginfo, ++ "Got packet of length %d," ++ "filling desc entry %d\n" ++ "TCB: 0x%p\n", ++ pFragList[loopIndex].size, ++ pAdapter->TxRing.txDmaReadyToSend.bits.val, ++ pMpTcb); ++ ++ CurDesc[FragmentNumber].DataBufferPtrHigh = 0; ++ ++ CurDesc[FragmentNumber].word2.bits.length_in_bytes = ++ pFragList[loopIndex - 1].size; ++ ++ /* NOTE: Here, the dma_addr_t returned from ++ * pci_map_page() is implicitly cast as a uint32_t. ++ * Although dma_addr_t can be 64-bit, the address ++ * returned by pci_map_page() is always 32-bit ++ * addressable (as defined by the pci/dma subsystem) ++ */ ++ CurDesc[FragmentNumber++].DataBufferPtrLow = ++ pci_map_page(pAdapter->pdev, ++ pFragList[loopIndex - 1].page, ++ pFragList[loopIndex - 1].page_offset, ++ pFragList[loopIndex - 1].size, ++ PCI_DMA_TODEVICE); ++ } ++ } ++ ++ if (FragmentNumber == 0) { ++ DBG_WARNING(et131x_dbginfo, "No. frags is 0\n"); ++ return -EIO; ++ } ++ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { ++ if (++pAdapter->TxRing.TxPacketsSinceLastinterrupt == ++ pAdapter->RegistryTxNumBuffers) { ++ CurDesc[FragmentNumber - 1].word3.value = 0x5; ++ pAdapter->TxRing.TxPacketsSinceLastinterrupt = 0; ++ } else { ++ CurDesc[FragmentNumber - 1].word3.value = 0x1; ++ } ++ } else { ++ CurDesc[FragmentNumber - 1].word3.value = 0x5; ++ } ++ ++ CurDesc[0].word3.bits.f = 1; ++ ++ pMpTcb->WrIndexStart = pAdapter->TxRing.txDmaReadyToSend; ++ pMpTcb->PacketStaleCount = 0; ++ ++ spin_lock_irqsave(&pAdapter->SendHWLock, lockflags1); ++ ++ iThisCopy = ++ NUM_DESC_PER_RING_TX - pAdapter->TxRing.txDmaReadyToSend.bits.val; ++ ++ if (iThisCopy >= FragmentNumber) { ++ iRemainder = 0; ++ iThisCopy = FragmentNumber; ++ } else { ++ iRemainder = FragmentNumber - iThisCopy; ++ } ++ ++ memcpy(pAdapter->TxRing.pTxDescRingVa + ++ pAdapter->TxRing.txDmaReadyToSend.bits.val, CurDesc, ++ sizeof(TX_DESC_ENTRY_t) * iThisCopy); ++ ++ pAdapter->TxRing.txDmaReadyToSend.bits.val += iThisCopy; ++ ++ if ((pAdapter->TxRing.txDmaReadyToSend.bits.val == 0) || ++ (pAdapter->TxRing.txDmaReadyToSend.bits.val == ++ NUM_DESC_PER_RING_TX)) { ++ if (pAdapter->TxRing.txDmaReadyToSend.bits.wrap) { ++ pAdapter->TxRing.txDmaReadyToSend.value = 0; ++ } else { ++ pAdapter->TxRing.txDmaReadyToSend.value = 0x400; ++ } ++ } ++ ++ if (iRemainder) { ++ memcpy(pAdapter->TxRing.pTxDescRingVa, ++ CurDesc + iThisCopy, ++ sizeof(TX_DESC_ENTRY_t) * iRemainder); ++ ++ pAdapter->TxRing.txDmaReadyToSend.bits.val += iRemainder; ++ } ++ ++ if (pAdapter->TxRing.txDmaReadyToSend.bits.val == 0) { ++ if (pAdapter->TxRing.txDmaReadyToSend.value) { ++ pMpTcb->WrIndex.value = NUM_DESC_PER_RING_TX - 1; ++ } else { ++ pMpTcb->WrIndex.value = ++ 0x400 | (NUM_DESC_PER_RING_TX - 1); ++ } ++ } else { ++ pMpTcb->WrIndex.value = ++ pAdapter->TxRing.txDmaReadyToSend.value - 1; ++ } ++ ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags2); ++ ++ if (pAdapter->TxRing.CurrSendTail) { ++ pAdapter->TxRing.CurrSendTail->Next = pMpTcb; ++ } else { ++ pAdapter->TxRing.CurrSendHead = pMpTcb; ++ } ++ ++ pAdapter->TxRing.CurrSendTail = pMpTcb; ++ ++ DBG_ASSERT(pMpTcb->Next == NULL); ++ ++ pAdapter->TxRing.nBusySend++; ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags2); ++ ++ /* Write the new write pointer back to the device. */ ++ writel(pAdapter->TxRing.txDmaReadyToSend.value, ++ &pAdapter->CSRAddress->txdma.service_request.value); ++ ++ /* For Gig only, we use Tx Interrupt coalescing. Enable the software ++ * timer to wake us up if this packet isn't followed by N more. ++ */ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { ++ writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO, ++ &pAdapter->CSRAddress->global.watchdog_timer); ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1); ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++/* ++ * NOTE: For now, keep this older version of NICSendPacket around for ++ * reference, even though it's not used ++ */ ++#if 0 ++ ++/** ++ * NICSendPacket - NIC specific send handler. ++ * @pAdapter: pointer to our adapter ++ * @pMpTcb: pointer to MP_TCB ++ * ++ * Returns 0 on succes, errno on failure. ++ * ++ * This version of the send routine is designed for version A silicon. ++ * Assumption - Send spinlock has been acquired. ++ */ ++static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb) ++{ ++ uint32_t loopIndex, fragIndex, loopEnd; ++ uint32_t iSplitFirstElement = 0; ++ uint32_t SegmentSize = 0; ++ TX_DESC_ENTRY_t CurDesc; ++ TX_DESC_ENTRY_t *CurDescPostCopy = NULL; ++ uint32_t SlotsAvailable; ++ DMA10W_t ServiceComplete; ++ unsigned int lockflags1, lockflags2; ++ struct sk_buff *pPacket = pMpTcb->Packet; ++ uint32_t FragListCount = skb_shinfo(pPacket)->nr_frags + 1; ++ struct skb_frag_struct *pFragList = &skb_shinfo(pPacket)->frags[0]; ++ ++ DBG_TX_ENTER(et131x_dbginfo); ++ ++ ServiceComplete.value = ++ readl(&pAdapter->CSRAddress->txdma.NewServiceComplete.value); ++ ++ /* ++ * Attempt to fix TWO hardware bugs: ++ * 1) NEVER write an odd number of descriptors. ++ * 2) If packet length is less than NIC_MIN_PACKET_SIZE, then pad the ++ * packet to NIC_MIN_PACKET_SIZE bytes by adding a new last ++ * descriptor IN HALF DUPLEX MODE ONLY ++ * NOTE that (2) interacts with (1). If the packet is less than ++ * NIC_MIN_PACKET_SIZE bytes then we will append a descriptor. ++ * Therefore if it is even now, it will eventually end up odd, and ++ * so will need adjusting. ++ * ++ * VLAN tags get involved since VLAN tags add another one or two ++ * segments. ++ */ ++ DBG_TX(et131x_dbginfo, ++ "pMpTcb->PacketLength: %d\n", pMpTcb->PacketLength); ++ ++ if ((pAdapter->uiDuplexMode == 0) ++ && (pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE)) { ++ DBG_TX(et131x_dbginfo, ++ "HALF DUPLEX mode AND len < MIN_PKT_SIZE\n"); ++ if ((FragListCount & 0x1) == 0) { ++ DBG_TX(et131x_dbginfo, ++ "Even number of descs, split 1st elem\n"); ++ iSplitFirstElement = 1; ++ //SegmentSize = pFragList[0].size / 2; ++ SegmentSize = (pPacket->len - pPacket->data_len) / 2; ++ } ++ } else if (FragListCount & 0x1) { ++ DBG_TX(et131x_dbginfo, "Odd number of descs, split 1st elem\n"); ++ ++ iSplitFirstElement = 1; ++ //SegmentSize = pFragList[0].size / 2; ++ SegmentSize = (pPacket->len - pPacket->data_len) / 2; ++ } ++ ++ spin_lock_irqsave(&pAdapter->SendHWLock, lockflags1); ++ ++ if (pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap == ++ ServiceComplete.bits.serv_cpl_wrap) { ++ /* The ring hasn't wrapped. Slots available should be ++ * (RING_SIZE) - the difference between the two pointers. ++ */ ++ SlotsAvailable = NUM_DESC_PER_RING_TX - ++ (pAdapter->TxRing.txDmaReadyToSend.bits.serv_req - ++ ServiceComplete.bits.serv_cpl); ++ } else { ++ /* The ring has wrapped. Slots available should be the ++ * difference between the two pointers. ++ */ ++ SlotsAvailable = ServiceComplete.bits.serv_cpl - ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; ++ } ++ ++ if ((FragListCount + iSplitFirstElement) > SlotsAvailable) { ++ DBG_WARNING(et131x_dbginfo, ++ "Not Enough Space in Tx Desc Ring\n"); ++ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1); ++ return -ENOMEM; ++ } ++ ++ loopEnd = (FragListCount) + iSplitFirstElement; ++ fragIndex = 0; ++ ++ DBG_TX(et131x_dbginfo, ++ "TCB : 0x%p\n" ++ "Packet (SKB) : 0x%p\t Packet->len: %d\t Packet->data_len: %d\n" ++ "FragListCount : %d\t iSplitFirstElement: %d\t loopEnd:%d\n", ++ pMpTcb, ++ pPacket, pPacket->len, pPacket->data_len, ++ FragListCount, iSplitFirstElement, loopEnd); ++ ++ for (loopIndex = 0; loopIndex < loopEnd; loopIndex++) { ++ if (loopIndex > iSplitFirstElement) { ++ fragIndex++; ++ } ++ ++ DBG_TX(et131x_dbginfo, ++ "In loop, loopIndex: %d\t fragIndex: %d\n", loopIndex, ++ fragIndex); ++ ++ /* If there is something in this element, let's get a ++ * descriptor from the ring and get the necessary data ++ */ ++ DBG_TX(et131x_dbginfo, ++ "Packet Length %d," ++ "filling desc entry %d\n", ++ pPacket->len, ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req); ++ ++ // NOTE - Should we do a paranoia check here to make sure the fragment ++ // actually has a length? It's HIGHLY unlikely the fragment would ++ // contain no data... ++ if (1) { ++ // NOTE - Currently always getting 32-bit addrs, and dma_addr_t is ++ // only 32-bit, so leave "high" ptr value out for now ++ CurDesc.DataBufferPtrHigh = 0; ++ ++ CurDesc.word2.value = 0; ++ CurDesc.word3.value = 0; ++ ++ if (fragIndex == 0) { ++ if (iSplitFirstElement) { ++ DBG_TX(et131x_dbginfo, ++ "Split first element: YES\n"); ++ ++ if (loopIndex == 0) { ++ DBG_TX(et131x_dbginfo, ++ "Got fragment of length %d, fragIndex: %d\n", ++ pPacket->len - ++ pPacket->data_len, ++ fragIndex); ++ DBG_TX(et131x_dbginfo, ++ "SegmentSize: %d\n", ++ SegmentSize); ++ ++ CurDesc.word2.bits. ++ length_in_bytes = ++ SegmentSize; ++ CurDesc.DataBufferPtrLow = ++ pci_map_single(pAdapter-> ++ pdev, ++ pPacket-> ++ data, ++ SegmentSize, ++ PCI_DMA_TODEVICE); ++ DBG_TX(et131x_dbginfo, ++ "pci_map_single() returns: 0x%08x\n", ++ CurDesc. ++ DataBufferPtrLow); ++ } else { ++ DBG_TX(et131x_dbginfo, ++ "Got fragment of length %d, fragIndex: %d\n", ++ pPacket->len - ++ pPacket->data_len, ++ fragIndex); ++ DBG_TX(et131x_dbginfo, ++ "Leftover Size: %d\n", ++ (pPacket->len - ++ pPacket->data_len - ++ SegmentSize)); ++ ++ CurDesc.word2.bits. ++ length_in_bytes = ++ ((pPacket->len - ++ pPacket->data_len) - ++ SegmentSize); ++ CurDesc.DataBufferPtrLow = ++ pci_map_single(pAdapter-> ++ pdev, ++ (pPacket-> ++ data + ++ SegmentSize), ++ (pPacket-> ++ len - ++ pPacket-> ++ data_len - ++ SegmentSize), ++ PCI_DMA_TODEVICE); ++ DBG_TX(et131x_dbginfo, ++ "pci_map_single() returns: 0x%08x\n", ++ CurDesc. ++ DataBufferPtrLow); ++ } ++ } else { ++ DBG_TX(et131x_dbginfo, ++ "Split first element: NO\n"); ++ ++ CurDesc.word2.bits.length_in_bytes = ++ pPacket->len - pPacket->data_len; ++ ++ CurDesc.DataBufferPtrLow = ++ pci_map_single(pAdapter->pdev, ++ pPacket->data, ++ (pPacket->len - ++ pPacket->data_len), ++ PCI_DMA_TODEVICE); ++ DBG_TX(et131x_dbginfo, ++ "pci_map_single() returns: 0x%08x\n", ++ CurDesc.DataBufferPtrLow); ++ } ++ } else { ++ ++ CurDesc.word2.bits.length_in_bytes = ++ pFragList[fragIndex - 1].size; ++ CurDesc.DataBufferPtrLow = ++ pci_map_page(pAdapter->pdev, ++ pFragList[fragIndex - 1].page, ++ pFragList[fragIndex - ++ 1].page_offset, ++ pFragList[fragIndex - 1].size, ++ PCI_DMA_TODEVICE); ++ DBG_TX(et131x_dbginfo, ++ "pci_map_page() returns: 0x%08x\n", ++ CurDesc.DataBufferPtrLow); ++ } ++ ++ if (loopIndex == 0) { ++ /* This is the first descriptor of the packet ++ * ++ * Set the "f" bit to indicate this is the ++ * first descriptor in the packet. ++ */ ++ DBG_TX(et131x_dbginfo, ++ "This is our FIRST descriptor\n"); ++ CurDesc.word3.bits.f = 1; ++ ++ pMpTcb->WrIndexStart = ++ pAdapter->TxRing.txDmaReadyToSend; ++ } ++ ++ if ((loopIndex == (loopEnd - 1)) && ++ (pAdapter->uiDuplexMode || ++ (pMpTcb->PacketLength >= NIC_MIN_PACKET_SIZE))) { ++ /* This is the Last descriptor of the packet */ ++ DBG_TX(et131x_dbginfo, ++ "THIS is our LAST descriptor\n"); ++ ++ if (pAdapter->uiLinkSpeed == ++ TRUEPHY_SPEED_1000MBPS) { ++ if (++pAdapter->TxRing. ++ TxPacketsSinceLastinterrupt >= ++ pAdapter->RegistryTxNumBuffers) { ++ CurDesc.word3.value = 0x5; ++ pAdapter->TxRing. ++ TxPacketsSinceLastinterrupt ++ = 0; ++ } else { ++ CurDesc.word3.value = 0x1; ++ } ++ } else { ++ CurDesc.word3.value = 0x5; ++ } ++ ++ /* Following index will be used during freeing ++ * of packet ++ */ ++ pMpTcb->WrIndex = ++ pAdapter->TxRing.txDmaReadyToSend; ++ pMpTcb->PacketStaleCount = 0; ++ } ++ ++ /* Copy the descriptor (filled above) into the ++ * descriptor ring at the next free entry. Advance ++ * the "next free entry" variable ++ */ ++ memcpy(pAdapter->TxRing.pTxDescRingVa + ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, ++ &CurDesc, sizeof(TX_DESC_ENTRY_t)); ++ ++ CurDescPostCopy = ++ pAdapter->TxRing.pTxDescRingVa + ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; ++ ++ DBG_TX(et131x_dbginfo, ++ "CURRENT DESCRIPTOR\n" ++ "\tAddress : 0x%p\n" ++ "\tDataBufferPtrHigh : 0x%08x\n" ++ "\tDataBufferPtrLow : 0x%08x\n" ++ "\tword2 : 0x%08x\n" ++ "\tword3 : 0x%08x\n", ++ CurDescPostCopy, ++ CurDescPostCopy->DataBufferPtrHigh, ++ CurDescPostCopy->DataBufferPtrLow, ++ CurDescPostCopy->word2.value, ++ CurDescPostCopy->word3.value); ++ ++ if (++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >= ++ NUM_DESC_PER_RING_TX) { ++ if (pAdapter->TxRing.txDmaReadyToSend.bits. ++ serv_req_wrap) { ++ pAdapter->TxRing.txDmaReadyToSend. ++ value = 0; ++ } else { ++ pAdapter->TxRing.txDmaReadyToSend. ++ value = 0x400; ++ } ++ } ++ } ++ } ++ ++ if (pAdapter->uiDuplexMode == 0 && ++ pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE) { ++ // NOTE - Same 32/64-bit issue as above... ++ CurDesc.DataBufferPtrHigh = 0x0; ++ CurDesc.DataBufferPtrLow = pAdapter->TxRing.pTxDummyBlkPa; ++ CurDesc.word2.value = 0; ++ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { ++ if (++pAdapter->TxRing.TxPacketsSinceLastinterrupt >= ++ pAdapter->RegistryTxNumBuffers) { ++ CurDesc.word3.value = 0x5; ++ pAdapter->TxRing.TxPacketsSinceLastinterrupt = ++ 0; ++ } else { ++ CurDesc.word3.value = 0x1; ++ } ++ } else { ++ CurDesc.word3.value = 0x5; ++ } ++ ++ CurDesc.word2.bits.length_in_bytes = ++ NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength; ++ ++ pMpTcb->WrIndex = pAdapter->TxRing.txDmaReadyToSend; ++ ++ memcpy(pAdapter->TxRing.pTxDescRingVa + ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, ++ &CurDesc, sizeof(TX_DESC_ENTRY_t)); ++ ++ CurDescPostCopy = ++ pAdapter->TxRing.pTxDescRingVa + ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; ++ ++ DBG_TX(et131x_dbginfo, ++ "CURRENT DESCRIPTOR\n" ++ "\tAddress : 0x%p\n" ++ "\tDataBufferPtrHigh : 0x%08x\n" ++ "\tDataBufferPtrLow : 0x%08x\n" ++ "\tword2 : 0x%08x\n" ++ "\tword3 : 0x%08x\n", ++ CurDescPostCopy, ++ CurDescPostCopy->DataBufferPtrHigh, ++ CurDescPostCopy->DataBufferPtrLow, ++ CurDescPostCopy->word2.value, ++ CurDescPostCopy->word3.value); ++ ++ if (++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >= ++ NUM_DESC_PER_RING_TX) { ++ if (pAdapter->TxRing.txDmaReadyToSend.bits. ++ serv_req_wrap) { ++ pAdapter->TxRing.txDmaReadyToSend.value = 0; ++ } else { ++ pAdapter->TxRing.txDmaReadyToSend.value = 0x400; ++ } ++ } ++ ++ DBG_TX(et131x_dbginfo, "Padding descriptor %d by %d bytes\n", ++ //pAdapter->TxRing.txDmaReadyToSend.value, ++ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, ++ NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength); ++ } ++ ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags2); ++ ++ if (pAdapter->TxRing.CurrSendTail) { ++ pAdapter->TxRing.CurrSendTail->Next = pMpTcb; ++ } else { ++ pAdapter->TxRing.CurrSendHead = pMpTcb; ++ } ++ ++ pAdapter->TxRing.CurrSendTail = pMpTcb; ++ ++ DBG_ASSERT(pMpTcb->Next == NULL); ++ ++ pAdapter->TxRing.nBusySend++; ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags2); ++ ++ /* Write the new write pointer back to the device. */ ++ writel(pAdapter->TxRing.txDmaReadyToSend.value, ++ &pAdapter->CSRAddress->txdma.service_request.value); ++ ++#ifdef CONFIG_ET131X_DEBUG ++ DumpDeviceBlock(DBG_TX_ON, pAdapter, 1); ++#endif ++ ++ /* For Gig only, we use Tx Interrupt coalescing. Enable the software ++ * timer to wake us up if this packet isn't followed by N more. ++ */ ++ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { ++ writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO, ++ &pAdapter->CSRAddress->global.watchdog_timer); ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1); ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++#endif ++ ++/** ++ * et131x_free_send_packet - Recycle a MP_TCB, complete the packet if necessary ++ * @pAdapter: pointer to our adapter ++ * @pMpTcb: pointer to MP_TCB ++ * ++ * Assumption - Send spinlock has been acquired ++ */ ++__inline void et131x_free_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb) ++{ ++ unsigned long lockflags; ++ TX_DESC_ENTRY_t *desc = NULL; ++ struct net_device_stats *stats = &pAdapter->net_stats; ++ ++ if (MP_TEST_FLAG(pMpTcb, fMP_DEST_BROAD)) { ++ atomic_inc(&pAdapter->Stats.brdcstxmt); ++ } else if (MP_TEST_FLAG(pMpTcb, fMP_DEST_MULTI)) { ++ atomic_inc(&pAdapter->Stats.multixmt); ++ } else { ++ atomic_inc(&pAdapter->Stats.unixmt); ++ } ++ ++ if (pMpTcb->Packet) { ++ stats->tx_bytes += pMpTcb->Packet->len; ++ ++ /* Iterate through the TX descriptors on the ring ++ * corresponding to this packet and umap the fragments ++ * they point to ++ */ ++ DBG_TX(et131x_dbginfo, ++ "Unmap descriptors Here\n" ++ "TCB : 0x%p\n" ++ "TCB Next : 0x%p\n" ++ "TCB PacketLength : %d\n" ++ "TCB WrIndex.value : 0x%08x\n" ++ "TCB WrIndex.bits.val : %d\n" ++ "TCB WrIndex.value : 0x%08x\n" ++ "TCB WrIndex.bits.val : %d\n", ++ pMpTcb, ++ pMpTcb->Next, ++ pMpTcb->PacketLength, ++ pMpTcb->WrIndexStart.value, ++ pMpTcb->WrIndexStart.bits.val, ++ pMpTcb->WrIndex.value, ++ pMpTcb->WrIndex.bits.val); ++ ++ do { ++ desc = ++ (TX_DESC_ENTRY_t *) (pAdapter->TxRing. ++ pTxDescRingVa + ++ pMpTcb->WrIndexStart.bits.val); ++ ++ DBG_TX(et131x_dbginfo, ++ "CURRENT DESCRIPTOR\n" ++ "\tAddress : 0x%p\n" ++ "\tDataBufferPtrHigh : 0x%08x\n" ++ "\tDataBufferPtrLow : 0x%08x\n" ++ "\tword2 : 0x%08x\n" ++ "\tword3 : 0x%08x\n", ++ desc, ++ desc->DataBufferPtrHigh, ++ desc->DataBufferPtrLow, ++ desc->word2.value, ++ desc->word3.value); ++ ++ pci_unmap_single(pAdapter->pdev, ++ desc->DataBufferPtrLow, ++ desc->word2.value, PCI_DMA_TODEVICE); ++ ++ if (++pMpTcb->WrIndexStart.bits.val >= ++ NUM_DESC_PER_RING_TX) { ++ if (pMpTcb->WrIndexStart.bits.wrap) { ++ pMpTcb->WrIndexStart.value = 0; ++ } else { ++ pMpTcb->WrIndexStart.value = 0x400; ++ } ++ } ++ } ++ while (desc != (pAdapter->TxRing.pTxDescRingVa + ++ pMpTcb->WrIndex.bits.val)); ++ ++ DBG_TX(et131x_dbginfo, ++ "Free Packet (SKB) : 0x%p\n", pMpTcb->Packet); ++ ++ dev_kfree_skb_any(pMpTcb->Packet); ++ } ++ ++ memset(pMpTcb, 0, sizeof(MP_TCB)); ++ ++ /* Add the TCB to the Ready Q */ ++ spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags); ++ ++ pAdapter->Stats.opackets++; ++ ++ if (pAdapter->TxRing.TCBReadyQueueTail) { ++ pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb; ++ } else { ++ /* Apparently ready Q is empty. */ ++ pAdapter->TxRing.TCBReadyQueueHead = pMpTcb; ++ } ++ ++ pAdapter->TxRing.TCBReadyQueueTail = pMpTcb; ++ ++ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); ++ ++ DBG_ASSERT(pAdapter->TxRing.nBusySend >= 0); ++} ++ ++/** ++ * et131x_free_busy_send_packets - Free and complete the stopped active sends ++ * @pAdapter: pointer to our adapter ++ * ++ * Assumption - Send spinlock has been acquired ++ */ ++void et131x_free_busy_send_packets(struct et131x_adapter *pAdapter) ++{ ++ PMP_TCB pMpTcb; ++ struct list_head *pEntry; ++ struct sk_buff *pPacket = NULL; ++ unsigned long lockflags; ++ uint32_t FreeCounter = 0; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ while (!list_empty(&pAdapter->TxRing.SendWaitQueue)) { ++ spin_lock_irqsave(&pAdapter->SendWaitLock, lockflags); ++ ++ pAdapter->TxRing.nWaitSend--; ++ spin_unlock_irqrestore(&pAdapter->SendWaitLock, lockflags); ++ ++ pEntry = pAdapter->TxRing.SendWaitQueue.next; ++ ++ pPacket = NULL; ++ } ++ ++ pAdapter->TxRing.nWaitSend = 0; ++ ++ /* Any packets being sent? Check the first TCB on the send list */ ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); ++ ++ pMpTcb = pAdapter->TxRing.CurrSendHead; ++ ++ while ((pMpTcb != NULL) && (FreeCounter < NUM_TCB)) { ++ PMP_TCB pNext = pMpTcb->Next; ++ ++ pAdapter->TxRing.CurrSendHead = pNext; ++ ++ if (pNext == NULL) { ++ pAdapter->TxRing.CurrSendTail = NULL; ++ } ++ ++ pAdapter->TxRing.nBusySend--; ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); ++ ++ DBG_VERBOSE(et131x_dbginfo, "pMpTcb = 0x%p\n", pMpTcb); ++ ++ FreeCounter++; ++ MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb); ++ ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); ++ ++ pMpTcb = pAdapter->TxRing.CurrSendHead; ++ } ++ ++ if (FreeCounter == NUM_TCB) { ++ DBG_ERROR(et131x_dbginfo, ++ "MpFreeBusySendPackets exitted loop for a bad reason\n"); ++ BUG(); ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); ++ ++ pAdapter->TxRing.nBusySend = 0; ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_handle_send_interrupt - Interrupt handler for sending processing ++ * @pAdapter: pointer to our adapter ++ * ++ * Re-claim the send resources, complete sends and get more to send from ++ * the send wait queue. ++ * ++ * Assumption - Send spinlock has been acquired ++ */ ++void et131x_handle_send_interrupt(struct et131x_adapter *pAdapter) ++{ ++ DBG_TX_ENTER(et131x_dbginfo); ++ ++ /* Mark as completed any packets which have been sent by the device. */ ++ et131x_update_tcb_list(pAdapter); ++ ++ /* If we queued any transmits because we didn't have any TCBs earlier, ++ * dequeue and send those packets now, as long as we have free TCBs. ++ */ ++ et131x_check_send_wait_list(pAdapter); ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_update_tcb_list - Helper routine for Send Interrupt handler ++ * @pAdapter: pointer to our adapter ++ * ++ * Re-claims the send resources and completes sends. Can also be called as ++ * part of the NIC send routine when the "ServiceComplete" indication has ++ * wrapped. ++ */ ++static void et131x_update_tcb_list(struct et131x_adapter *pAdapter) ++{ ++ unsigned long lockflags; ++ DMA10W_t ServiceComplete; ++ PMP_TCB pMpTcb; ++ ++ ServiceComplete.value = ++ readl(&pAdapter->CSRAddress->txdma.NewServiceComplete.value); ++ ++ /* Has the ring wrapped? Process any descriptors that do not have ++ * the same "wrap" indicator as the current completion indicator ++ */ ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); ++ ++ pMpTcb = pAdapter->TxRing.CurrSendHead; ++ while (pMpTcb && ++ ServiceComplete.bits.wrap != pMpTcb->WrIndex.bits.wrap && ++ ServiceComplete.bits.val < pMpTcb->WrIndex.bits.val) { ++ pAdapter->TxRing.nBusySend--; ++ pAdapter->TxRing.CurrSendHead = pMpTcb->Next; ++ if (pMpTcb->Next == NULL) { ++ pAdapter->TxRing.CurrSendTail = NULL; ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); ++ MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb); ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); ++ ++ /* Goto the next packet */ ++ pMpTcb = pAdapter->TxRing.CurrSendHead; ++ } ++ while (pMpTcb && ++ ServiceComplete.bits.wrap == pMpTcb->WrIndex.bits.wrap && ++ ServiceComplete.bits.val > pMpTcb->WrIndex.bits.val) { ++ pAdapter->TxRing.nBusySend--; ++ pAdapter->TxRing.CurrSendHead = pMpTcb->Next; ++ if (pMpTcb->Next == NULL) { ++ pAdapter->TxRing.CurrSendTail = NULL; ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); ++ MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb); ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); ++ ++ /* Goto the next packet */ ++ pMpTcb = pAdapter->TxRing.CurrSendHead; ++ } ++ ++ /* Wake up the queue when we hit a low-water mark */ ++ if (pAdapter->TxRing.nBusySend <= (NUM_TCB / 3)) { ++ netif_wake_queue(pAdapter->netdev); ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); ++} ++ ++/** ++ * et131x_check_send_wait_list - Helper routine for the interrupt handler ++ * @pAdapter: pointer to our adapter ++ * ++ * Takes packets from the send wait queue and posts them to the device (if ++ * room available). ++ */ ++static void et131x_check_send_wait_list(struct et131x_adapter *pAdapter) ++{ ++ unsigned long lockflags; ++ ++ spin_lock_irqsave(&pAdapter->SendWaitLock, lockflags); ++ ++ while (!list_empty(&pAdapter->TxRing.SendWaitQueue) && ++ MP_TCB_RESOURCES_AVAILABLE(pAdapter)) { ++ struct list_head *pEntry; ++ ++ DBG_VERBOSE(et131x_dbginfo, "Tx packets on the wait queue\n"); ++ ++ pEntry = pAdapter->TxRing.SendWaitQueue.next; ++ ++ pAdapter->TxRing.nWaitSend--; ++ ++ DBG_WARNING(et131x_dbginfo, ++ "MpHandleSendInterrupt - sent a queued pkt. Waiting %d\n", ++ pAdapter->TxRing.nWaitSend); ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->SendWaitLock, lockflags); ++} +diff --git a/drivers/staging/et131x/et1310_tx.h b/drivers/staging/et131x/et1310_tx.h +new file mode 100644 +index 0000000..2819c78 +--- /dev/null ++++ b/drivers/staging/et131x/et1310_tx.h +@@ -0,0 +1,242 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et1310_tx.h - Defines, structs, enums, prototypes, etc. pertaining to data ++ * transmission. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET1310_TX_H__ ++#define __ET1310_TX_H__ ++ ++ ++/* Typedefs for Tx Descriptor Ring */ ++ ++/* ++ * TXDESC_WORD2_t structure holds part of the control bits in the Tx Descriptor ++ * ring for the ET-1310 ++ */ ++typedef union _txdesc_word2_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 vlan_prio:3; // bits 29-31(VLAN priority) ++ u32 vlan_cfi:1; // bit 28(cfi) ++ u32 vlan_tag:12; // bits 16-27(VLAN tag) ++ u32 length_in_bytes:16; // bits 0-15(packet length) ++#else ++ u32 length_in_bytes:16; // bits 0-15(packet length) ++ u32 vlan_tag:12; // bits 16-27(VLAN tag) ++ u32 vlan_cfi:1; // bit 28(cfi) ++ u32 vlan_prio:3; // bits 29-31(VLAN priority) ++#endif /* _BIT_FIELDS_HTOL */ ++ } bits; ++} TXDESC_WORD2_t, *PTXDESC_WORD2_t; ++ ++/* ++ * TXDESC_WORD3_t structure holds part of the control bits in the Tx Descriptor ++ * ring for the ET-1310 ++ */ ++typedef union _txdesc_word3_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:17; // bits 15-31 ++ u32 udpa:1; // bit 14(UDP checksum assist) ++ u32 tcpa:1; // bit 13(TCP checksum assist) ++ u32 ipa:1; // bit 12(IP checksum assist) ++ u32 vlan:1; // bit 11(append VLAN tag) ++ u32 hp:1; // bit 10(Packet is a Huge packet) ++ u32 pp:1; // bit 9(pad packet) ++ u32 mac:1; // bit 8(MAC override) ++ u32 crc:1; // bit 7(append CRC) ++ u32 e:1; // bit 6(Tx frame has error) ++ u32 pf:1; // bit 5(send pause frame) ++ u32 bp:1; // bit 4(Issue half-duplex backpressure (XON/XOFF) ++ u32 cw:1; // bit 3(Control word - no packet data) ++ u32 ir:1; // bit 2(interrupt the processor when this pkt sent) ++ u32 f:1; // bit 1(first packet in the sequence) ++ u32 l:1; // bit 0(last packet in the sequence) ++#else ++ u32 l:1; // bit 0(last packet in the sequence) ++ u32 f:1; // bit 1(first packet in the sequence) ++ u32 ir:1; // bit 2(interrupt the processor when this pkt sent) ++ u32 cw:1; // bit 3(Control word - no packet data) ++ u32 bp:1; // bit 4(Issue half-duplex backpressure (XON/XOFF) ++ u32 pf:1; // bit 5(send pause frame) ++ u32 e:1; // bit 6(Tx frame has error) ++ u32 crc:1; // bit 7(append CRC) ++ u32 mac:1; // bit 8(MAC override) ++ u32 pp:1; // bit 9(pad packet) ++ u32 hp:1; // bit 10(Packet is a Huge packet) ++ u32 vlan:1; // bit 11(append VLAN tag) ++ u32 ipa:1; // bit 12(IP checksum assist) ++ u32 tcpa:1; // bit 13(TCP checksum assist) ++ u32 udpa:1; // bit 14(UDP checksum assist) ++ u32 unused:17; // bits 15-31 ++#endif /* _BIT_FIELDS_HTOL */ ++ } bits; ++} TXDESC_WORD3_t, *PTXDESC_WORD3_t; ++ ++/* TX_DESC_ENTRY_t is sructure representing each descriptor on the ring */ ++typedef struct _tx_desc_entry_t { ++ u32 DataBufferPtrHigh; ++ u32 DataBufferPtrLow; ++ TXDESC_WORD2_t word2; // control words how to xmit the ++ TXDESC_WORD3_t word3; // data (detailed above) ++} TX_DESC_ENTRY_t, *PTX_DESC_ENTRY_t; ++ ++ ++/* Typedefs for Tx DMA engine status writeback */ ++ ++/* ++ * TX_STATUS_BLOCK_t is sructure representing the status of the Tx DMA engine ++ * it sits in free memory, and is pointed to by 0x101c / 0x1020 ++ */ ++typedef union _tx_status_block_t { ++ u32 value; ++ struct { ++#ifdef _BIT_FIELDS_HTOL ++ u32 unused:21; // bits 11-31 ++ u32 serv_cpl_wrap:1; // bit 10 ++ u32 serv_cpl:10; // bits 0-9 ++#else ++ u32 serv_cpl:10; // bits 0-9 ++ u32 serv_cpl_wrap:1; // bit 10 ++ u32 unused:21; // bits 11-31 ++#endif ++ } bits; ++} TX_STATUS_BLOCK_t, *PTX_STATUS_BLOCK_t; ++ ++/* TCB (Transmit Control Block) */ ++typedef struct _MP_TCB { ++ struct _MP_TCB *Next; ++ u32 Flags; ++ u32 Count; ++ u32 PacketStaleCount; ++ struct sk_buff *Packet; ++ u32 PacketLength; ++ DMA10W_t WrIndex; ++ DMA10W_t WrIndexStart; ++} MP_TCB, *PMP_TCB; ++ ++/* Structure to hold the skb's in a list */ ++typedef struct tx_skb_list_elem { ++ struct list_head skb_list_elem; ++ struct sk_buff *skb; ++} TX_SKB_LIST_ELEM, *PTX_SKB_LIST_ELEM; ++ ++/* TX_RING_t is sructure representing our local reference(s) to the ring */ ++typedef struct _tx_ring_t { ++ /* TCB (Transmit Control Block) memory and lists */ ++ PMP_TCB MpTcbMem; ++ ++ /* List of TCBs that are ready to be used */ ++ PMP_TCB TCBReadyQueueHead; ++ PMP_TCB TCBReadyQueueTail; ++ ++ /* list of TCBs that are currently being sent. NOTE that access to all ++ * three of these (including nBusySend) are controlled via the ++ * TCBSendQLock. This lock should be secured prior to incementing / ++ * decrementing nBusySend, or any queue manipulation on CurrSendHead / ++ * Tail ++ */ ++ PMP_TCB CurrSendHead; ++ PMP_TCB CurrSendTail; ++ int32_t nBusySend; ++ ++ /* List of packets (not TCBs) that were queued for lack of resources */ ++ struct list_head SendWaitQueue; ++ int32_t nWaitSend; ++ ++ /* The actual descriptor ring */ ++ PTX_DESC_ENTRY_t pTxDescRingVa; ++ dma_addr_t pTxDescRingPa; ++ uint64_t pTxDescRingAdjustedPa; ++ uint64_t TxDescOffset; ++ ++ /* ReadyToSend indicates where we last wrote to in the descriptor ring. */ ++ DMA10W_t txDmaReadyToSend; ++ ++ /* The location of the write-back status block */ ++ PTX_STATUS_BLOCK_t pTxStatusVa; ++ dma_addr_t pTxStatusPa; ++ ++ /* A Block of zeroes used to pad packets that are less than 60 bytes */ ++ void *pTxDummyBlkVa; ++ dma_addr_t pTxDummyBlkPa; ++ ++ TXMAC_ERR_t TxMacErr; ++ ++ /* Variables to track the Tx interrupt coalescing features */ ++ int32_t TxPacketsSinceLastinterrupt; ++} TX_RING_t, *PTX_RING_t; ++ ++/* Forward declaration of the frag-list for the following prototypes */ ++typedef struct _MP_FRAG_LIST MP_FRAG_LIST, *PMP_FRAG_LIST; ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++/* PROTOTYPES for et1310_tx.c */ ++int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter); ++void et131x_tx_dma_memory_free(struct et131x_adapter *adapter); ++void ConfigTxDmaRegs(struct et131x_adapter *pAdapter); ++void et131x_init_send(struct et131x_adapter *adapter); ++void et131x_tx_dma_disable(struct et131x_adapter *pAdapter); ++void et131x_tx_dma_enable(struct et131x_adapter *pAdapter); ++void et131x_handle_send_interrupt(struct et131x_adapter *pAdapter); ++void et131x_free_busy_send_packets(struct et131x_adapter *pAdapter); ++int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev); ++ ++#endif /* __ET1310_TX_H__ */ +diff --git a/drivers/staging/et131x/et131x_adapter.h b/drivers/staging/et131x/et131x_adapter.h +new file mode 100644 +index 0000000..36e61a4 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_adapter.h +@@ -0,0 +1,347 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_adapter.h - Header which includes the private adapter structure, along ++ * with related support structures, macros, definitions, etc. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_ADAPTER_H__ ++#define __ET131X_ADAPTER_H__ ++ ++#include "et1310_address_map.h" ++#include "et1310_tx.h" ++#include "et1310_rx.h" ++ ++/* ++ * Do not change these values: if changed, then change also in respective ++ * TXdma and Rxdma engines ++ */ ++#define NUM_DESC_PER_RING_TX 512 // TX Do not change these values ++#define NUM_TCB 64 ++ ++/* ++ * These values are all superseded by registry entries to facilitate tuning. ++ * Once the desired performance has been achieved, the optimal registry values ++ * should be re-populated to these #defines: ++ */ ++#define NUM_TRAFFIC_CLASSES 1 ++ ++/* ++ * There are three ways of counting errors - if there are more than X errors ++ * in Y packets (represented by the "SAMPLE" macros), if there are more than ++ * N errors in a S mSec time period (the "PERIOD" macros), or if there are ++ * consecutive packets with errors (CONSEC_ERRORED_THRESH). This last covers ++ * for "Bursty" errors, and the errored packets may well not be contiguous, ++ * but several errors where the packet counter has changed by less than a ++ * small amount will cause this count to increment. ++ */ ++#define TX_PACKETS_IN_SAMPLE 10000 ++#define TX_MAX_ERRORS_IN_SAMPLE 50 ++ ++#define TX_ERROR_PERIOD 1000 ++#define TX_MAX_ERRORS_IN_PERIOD 10 ++ ++#define LINK_DETECTION_TIMER 5000 ++ ++#define TX_CONSEC_RANGE 5 ++#define TX_CONSEC_ERRORED_THRESH 10 ++ ++#define LO_MARK_PERCENT_FOR_PSR 15 ++#define LO_MARK_PERCENT_FOR_RX 15 ++ ++/* Macros for flag and ref count operations */ ++#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) ++#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) ++#define MP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) ++#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) ++#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) ++#define MP_IS_FLAG_CLEAR(_M, _F) (((_M)->Flags & (_F)) == 0) ++ ++#define MP_INC_RCV_REF(_A) atomic_inc(&(_A)->RcvRefCount) ++#define MP_DEC_RCV_REF(_A) atomic_dec(&(_A)->RcvRefCount) ++#define MP_GET_RCV_REF(_A) atomic_read(&(_A)->RcvRefCount) ++ ++/* Macros specific to the private adapter structure */ ++#define MP_TCB_RESOURCES_AVAILABLE(_M) ((_M)->TxRing.nBusySend < NUM_TCB) ++#define MP_TCB_RESOURCES_NOT_AVAILABLE(_M) ((_M)->TxRing.nBusySend >= NUM_TCB) ++ ++#define MP_SHOULD_FAIL_SEND(_M) ((_M)->Flags & fMP_ADAPTER_FAIL_SEND_MASK) ++#define MP_IS_NOT_READY(_M) ((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) ++#define MP_IS_READY(_M) !((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) ++ ++#define MP_HAS_CABLE(_M) !((_M)->Flags & fMP_ADAPTER_NO_CABLE) ++#define MP_LINK_DETECTED(_M) !((_M)->Flags & fMP_ADAPTER_LINK_DETECTION) ++ ++/* Counters for error rate monitoring */ ++typedef struct _MP_ERR_COUNTERS { ++ u32 PktCountTxPackets; ++ u32 PktCountTxErrors; ++ u32 TimerBasedTxErrors; ++ u32 PktCountLastError; ++ u32 ErredConsecPackets; ++} MP_ERR_COUNTERS, *PMP_ERR_COUNTERS; ++ ++/* RFD (Receive Frame Descriptor) */ ++typedef struct _MP_RFD { ++ struct list_head list_node; ++ struct sk_buff *Packet; ++ u32 PacketSize; // total size of receive frame ++ u16 iBufferIndex; ++ u8 iRingIndex; ++} MP_RFD, *PMP_RFD; ++ ++/* Enum for Flow Control */ ++typedef enum _eflow_control_t { ++ Both = 0, ++ TxOnly = 1, ++ RxOnly = 2, ++ None = 3 ++} eFLOW_CONTROL_t, *PeFLOW_CONTROL_t; ++ ++/* Struct to define some device statistics */ ++typedef struct _ce_stats_t { ++ /* Link Input/Output stats */ ++ uint64_t ipackets; // # of in packets ++ uint64_t opackets; // # of out packets ++ ++ /* MIB II variables ++ * ++ * NOTE: atomic_t types are only guaranteed to store 24-bits; if we ++ * MUST have 32, then we'll need another way to perform atomic ++ * operations ++ */ ++ u32 unircv; // # multicast packets received ++ atomic_t unixmt; // # multicast packets for Tx ++ u32 multircv; // # multicast packets received ++ atomic_t multixmt; // # multicast packets for Tx ++ u32 brdcstrcv; // # broadcast packets received ++ atomic_t brdcstxmt; // # broadcast packets for Tx ++ u32 norcvbuf; // # Rx packets discarded ++ u32 noxmtbuf; // # Tx packets discarded ++ ++ /* Transciever state informations. */ ++ u8 xcvr_addr; ++ u32 xcvr_id; ++ ++ /* Tx Statistics. */ ++ u32 tx_uflo; // Tx Underruns ++ ++ u32 collisions; ++ u32 excessive_collisions; ++ u32 first_collision; ++ u32 late_collisions; ++ u32 max_pkt_error; ++ u32 tx_deferred; ++ ++ /* Rx Statistics. */ ++ u32 rx_ov_flow; // Rx Over Flow ++ ++ u32 length_err; ++ u32 alignment_err; ++ u32 crc_err; ++ u32 code_violations; ++ u32 other_errors; ++ ++#ifdef CONFIG_ET131X_DEBUG ++ u32 UnhandledInterruptsPerSec; ++ u32 RxDmaInterruptsPerSec; ++ u32 TxDmaInterruptsPerSec; ++ u32 WatchDogInterruptsPerSec; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++ u32 SynchrounousIterations; ++ INTERRUPT_t InterruptStatus; ++} CE_STATS_t, *PCE_STATS_t; ++ ++/* The private adapter structure */ ++struct et131x_adapter { ++ struct net_device *netdev; ++ struct pci_dev *pdev; ++ ++ struct work_struct task; ++ ++ /* Flags that indicate current state of the adapter */ ++ u32 Flags; ++ u32 HwErrCount; ++ ++ /* Configuration */ ++ u8 PermanentAddress[ETH_ALEN]; ++ u8 CurrentAddress[ETH_ALEN]; ++ bool bOverrideAddress; ++ bool bEepromPresent; ++ u8 eepromData[2]; ++ ++ /* Spinlocks */ ++ spinlock_t Lock; ++ ++ spinlock_t TCBSendQLock; ++ spinlock_t TCBReadyQLock; ++ spinlock_t SendHWLock; ++ spinlock_t SendWaitLock; ++ ++ spinlock_t RcvLock; ++ spinlock_t RcvPendLock; ++ spinlock_t FbrLock; ++ ++ spinlock_t PHYLock; ++ ++ /* Packet Filter and look ahead size */ ++ u32 PacketFilter; ++ u32 ulLookAhead; ++ u32 uiLinkSpeed; ++ u32 uiDuplexMode; ++ u32 uiAutoNegStatus; ++ u8 ucLinkStatus; ++ ++ /* multicast list */ ++ u32 MCAddressCount; ++ u8 MCList[NIC_MAX_MCAST_LIST][ETH_ALEN]; ++ ++ /* MAC test */ ++ TXMAC_TXTEST_t TxMacTest; ++ ++ /* Pointer to the device's PCI register space */ ++ ADDRESS_MAP_t __iomem *CSRAddress; ++ ++ /* PCI config space info, for debug purposes only. */ ++ u8 RevisionID; ++ u16 VendorID; ++ u16 DeviceID; ++ u16 SubVendorID; ++ u16 SubSystemID; ++ u32 CacheFillSize; ++ u16 PciXDevCtl; ++ u8 pci_lat_timer; ++ u8 pci_hdr_type; ++ u8 pci_bist; ++ u32 pci_cfg_state[64 / sizeof(u32)]; ++ ++ /* Registry parameters */ ++ u8 SpeedDuplex; // speed/duplex ++ eFLOW_CONTROL_t RegistryFlowControl; // for 802.3x flow control ++ u8 RegistryWOLMatch; // Enable WOL pattern-matching ++ u8 RegistryWOLLink; // Link state change is independant ++ u8 RegistryPhyComa; // Phy Coma mode enable/disable ++ ++ u32 RegistryRxMemEnd; // Size of internal rx memory ++ u8 RegistryMACStat; // If set, read MACSTAT, else don't ++ u32 RegistryVlanTag; // 802.1q Vlan TAG ++ u32 RegistryJumboPacket; // Max supported ethernet packet size ++ ++ u32 RegistryTxNumBuffers; ++ u32 RegistryTxTimeInterval; ++ ++ u32 RegistryRxNumBuffers; ++ u32 RegistryRxTimeInterval; ++ ++ /* Validation helpers */ ++ u8 RegistryPMWOL; ++ u8 RegistryNMIDisable; ++ u32 RegistryDMACache; ++ u32 RegistrySCGain; ++ u8 RegistryPhyLoopbk; // Enable Phy loopback ++ ++ /* Derived from the registry: */ ++ u8 AiForceDpx; // duplex setting ++ u16 AiForceSpeed; // 'Speed', user over-ride of line speed ++ eFLOW_CONTROL_t FlowControl; // flow control validated by the far-end ++ enum { ++ NETIF_STATUS_INVALID = 0, ++ NETIF_STATUS_MEDIA_CONNECT, ++ NETIF_STATUS_MEDIA_DISCONNECT, ++ NETIF_STATUS_MAX ++ } MediaState; ++ u8 DriverNoPhyAccess; ++ ++ /* Minimize init-time */ ++ bool bQueryPending; ++ bool bSetPending; ++ bool bResetPending; ++ struct timer_list ErrorTimer; ++ bool bLinkTimerActive; ++ MP_POWER_MGMT PoMgmt; ++ INTERRUPT_t CachedMaskValue; ++ ++ atomic_t RcvRefCount; // Num packets not yet returned ++ ++ /* Xcvr status at last poll */ ++ MI_BMSR_t Bmsr; ++ ++ /* Tx Memory Variables */ ++ TX_RING_t TxRing; ++ ++ /* Rx Memory Variables */ ++ RX_RING_t RxRing; ++ ++ /* ET1310 register Access */ ++ JAGCORE_ACCESS_REGS JagCoreRegs; ++ PCI_CFG_SPACE_REGS PciCfgRegs; ++ ++ /* Loopback specifics */ ++ u8 ReplicaPhyLoopbk; // Replica Enable ++ u8 ReplicaPhyLoopbkPF; // Replica Enable Pass/Fail ++ ++ /* Stats */ ++ CE_STATS_t Stats; ++ ++ struct net_device_stats net_stats; ++ struct net_device_stats net_stats_prev; ++}; ++ ++#define MPSendPacketsHandler MPSendPackets ++#define MP_FREE_SEND_PACKET_FUN(Adapter, pMpTcb) \ ++ et131x_free_send_packet(Adapter, pMpTcb) ++#define MpSendPacketFun(Adapter, Packet) MpSendPacket(Adapter, Packet) ++ ++#endif /* __ET131X_ADAPTER_H__ */ +diff --git a/drivers/staging/et131x/et131x_config.c b/drivers/staging/et131x/et131x_config.c +new file mode 100644 +index 0000000..0adbaa6 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_config.c +@@ -0,0 +1,325 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_config.c - Handles parsing of configuration data during ++ * initialization. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_initpci.h" ++#include "et131x_config.h" ++ ++#include "et1310_tx.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/* Defines for Parameter Default/Min/Max vaules */ ++#define PARM_SPEED_DUPLEX_DEF 0 ++#define PARM_SPEED_DUPLEX_MIN 0 ++#define PARM_SPEED_DUPLEX_MAX 5 ++ ++#define PARM_VLAN_TAG_DEF 0 ++#define PARM_VLAN_TAG_MIN 0 ++#define PARM_VLAN_TAG_MAX 4095 ++ ++#define PARM_FLOW_CTL_DEF 0 ++#define PARM_FLOW_CTL_MIN 0 ++#define PARM_FLOW_CTL_MAX 3 ++ ++#define PARM_WOL_LINK_DEF 3 ++#define PARM_WOL_LINK_MIN 0 ++#define PARM_WOL_LINK_MAX 3 ++ ++#define PARM_WOL_MATCH_DEF 7 ++#define PARM_WOL_MATCH_MIN 0 ++#define PARM_WOL_MATCH_MAX 7 ++ ++#define PARM_JUMBO_PKT_DEF 1514 ++#define PARM_JUMBO_PKT_MIN 1514 ++#define PARM_JUMBO_PKT_MAX 9216 ++ ++#define PARM_PHY_COMA_DEF 0 ++#define PARM_PHY_COMA_MIN 0 ++#define PARM_PHY_COMA_MAX 1 ++ ++#define PARM_RX_NUM_BUFS_DEF 4 ++#define PARM_RX_NUM_BUFS_MIN 1 ++#define PARM_RX_NUM_BUFS_MAX 64 ++ ++#define PARM_RX_TIME_INT_DEF 10 ++#define PARM_RX_TIME_INT_MIN 2 ++#define PARM_RX_TIME_INT_MAX 320 ++ ++#define PARM_TX_NUM_BUFS_DEF 4 ++#define PARM_TX_NUM_BUFS_MIN 1 ++#define PARM_TX_NUM_BUFS_MAX 40 ++ ++#define PARM_TX_TIME_INT_DEF 40 ++#define PARM_TX_TIME_INT_MIN 1 ++#define PARM_TX_TIME_INT_MAX 140 ++ ++#define PARM_RX_MEM_END_DEF 0x2bc ++#define PARM_RX_MEM_END_MIN 0 ++#define PARM_RX_MEM_END_MAX 0x3ff ++ ++#define PARM_MAC_STAT_DEF 1 ++#define PARM_MAC_STAT_MIN 0 ++#define PARM_MAC_STAT_MAX 1 ++ ++#define PARM_SC_GAIN_DEF 7 ++#define PARM_SC_GAIN_MIN 0 ++#define PARM_SC_GAIN_MAX 7 ++ ++#define PARM_PM_WOL_DEF 0 ++#define PARM_PM_WOL_MIN 0 ++#define PARM_PM_WOL_MAX 1 ++ ++#define PARM_NMI_DISABLE_DEF 0 ++#define PARM_NMI_DISABLE_MIN 0 ++#define PARM_NMI_DISABLE_MAX 2 ++ ++#define PARM_DMA_CACHE_DEF 0 ++#define PARM_DMA_CACHE_MIN 0 ++#define PARM_DMA_CACHE_MAX 15 ++ ++#define PARM_PHY_LOOPBK_DEF 0 ++#define PARM_PHY_LOOPBK_MIN 0 ++#define PARM_PHY_LOOPBK_MAX 1 ++ ++#define PARM_MAC_ADDRESS_DEF { 0x00, 0x05, 0x3d, 0x00, 0x02, 0x00 } ++ ++/* Module parameter for disabling NMI ++ * et131x_speed_set : ++ * Set Link speed and dublex manually (0-5) [0] ++ * 1 : 10Mb Half-Duplex ++ * 2 : 10Mb Full-Duplex ++ * 3 : 100Mb Half-Duplex ++ * 4 : 100Mb Full-Duplex ++ * 5 : 1000Mb Full-Duplex ++ * 0 : Auto Speed Auto Dublex // default ++ */ ++static u32 et131x_nmi_disable = PARM_NMI_DISABLE_DEF; ++module_param(et131x_nmi_disable, uint, 0); ++MODULE_PARM_DESC(et131x_nmi_disable, "Disable NMI (0-2) [0]"); ++ ++/* Module parameter for manual speed setting ++ * et131x_nmi_disable : ++ * Disable NMI (0-2) [0] ++ * 0 : ++ * 1 : ++ * 2 : ++ */ ++static u32 et131x_speed_set = PARM_SPEED_DUPLEX_DEF; ++module_param(et131x_speed_set, uint, 0); ++MODULE_PARM_DESC(et131x_speed_set, ++ "Set Link speed and dublex manually (0-5) [0] \n 1 : 10Mb Half-Duplex \n 2 : 10Mb Full-Duplex \n 3 : 100Mb Half-Duplex \n 4 : 100Mb Full-Duplex \n 5 : 1000Mb Full-Duplex \n 0 : Auto Speed Auto Dublex"); ++ ++/** ++ * et131x_config_parse ++ * @pAdapter: pointer to the private adapter struct ++ * ++ * Parses a configuration from some location (module parameters, for example) ++ * into the private adapter struct ++ */ ++void et131x_config_parse(struct et131x_adapter *pAdapter) ++{ ++ uint8_t macAddrDef[] = PARM_MAC_ADDRESS_DEF; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* ++ * The NDIS driver uses the registry to store persistent per-device ++ * configuration, and reads this configuration into the appropriate ++ * elements of the private adapter structure on initialization. ++ * Because Linux has no analog to the registry, use this function to ++ * initialize the private adapter structure with a default ++ * configuration. ++ * ++ * One other possibility is to use a series of module parameters which ++ * can be passed in by the caller when the module is initialized. ++ * However, this implementation does not allow for seperate ++ * configurations in the event multiple devices are present, and hence ++ * will not suffice. ++ * ++ * If another method is derived which addresses this problem, this is ++ * where it should be implemented. ++ */ ++ ++ /* Set the private adapter struct with default values for the ++ * corresponding parameters ++ */ ++ if (et131x_speed_set != PARM_SPEED_DUPLEX_DEF) { ++ DBG_VERBOSE(et131x_dbginfo, "Speed set manually to : %d \n", ++ et131x_speed_set); ++ pAdapter->SpeedDuplex = et131x_speed_set; ++ } else { ++ pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF; ++ } ++ ++ // pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF; ++ ++ pAdapter->RegistryVlanTag = PARM_VLAN_TAG_DEF; ++ pAdapter->RegistryFlowControl = PARM_FLOW_CTL_DEF; ++ pAdapter->RegistryWOLLink = PARM_WOL_LINK_DEF; ++ pAdapter->RegistryWOLMatch = PARM_WOL_MATCH_DEF; ++ pAdapter->RegistryJumboPacket = PARM_JUMBO_PKT_DEF; ++ pAdapter->RegistryPhyComa = PARM_PHY_COMA_DEF; ++ pAdapter->RegistryRxNumBuffers = PARM_RX_NUM_BUFS_DEF; ++ pAdapter->RegistryRxTimeInterval = PARM_RX_TIME_INT_DEF; ++ pAdapter->RegistryTxNumBuffers = PARM_TX_NUM_BUFS_DEF; ++ pAdapter->RegistryTxTimeInterval = PARM_TX_TIME_INT_DEF; ++ pAdapter->RegistryRxMemEnd = PARM_RX_MEM_END_DEF; ++ pAdapter->RegistryMACStat = PARM_MAC_STAT_DEF; ++ pAdapter->RegistrySCGain = PARM_SC_GAIN_DEF; ++ pAdapter->RegistryPMWOL = PARM_PM_WOL_DEF; ++ ++ if (et131x_nmi_disable != PARM_NMI_DISABLE_DEF) { ++ pAdapter->RegistryNMIDisable = et131x_nmi_disable; ++ } else { ++ pAdapter->RegistryNMIDisable = PARM_NMI_DISABLE_DEF; ++ } ++ ++ pAdapter->RegistryDMACache = PARM_DMA_CACHE_DEF; ++ pAdapter->RegistryPhyLoopbk = PARM_PHY_LOOPBK_DEF; ++ ++ /* Set the MAC address to a default */ ++ memcpy(pAdapter->CurrentAddress, macAddrDef, ETH_ALEN); ++ pAdapter->bOverrideAddress = false; ++ ++ DBG_TRACE(et131x_dbginfo, ++ "Default MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAdapter->CurrentAddress[0], pAdapter->CurrentAddress[1], ++ pAdapter->CurrentAddress[2], pAdapter->CurrentAddress[3], ++ pAdapter->CurrentAddress[4], pAdapter->CurrentAddress[5]); ++ ++ /* Decode SpeedDuplex ++ * ++ * Set up as if we are auto negotiating always and then change if we ++ * go into force mode ++ */ ++ pAdapter->AiForceSpeed = 0; // Auto speed ++ pAdapter->AiForceDpx = 0; // Auto FDX ++ ++ /* If we are the 10/100 device, and gigabit is somehow requested then ++ * knock it down to 100 full. ++ */ ++ if ((pAdapter->DeviceID == ET131X_PCI_DEVICE_ID_FAST) && ++ (pAdapter->SpeedDuplex == 5)) { ++ pAdapter->SpeedDuplex = 4; ++ } ++ ++ switch (pAdapter->SpeedDuplex) { ++ case 1: // 10Mb Half-Duplex ++ pAdapter->AiForceSpeed = 10; ++ pAdapter->AiForceDpx = 1; ++ break; ++ ++ case 2: // 10Mb Full-Duplex ++ pAdapter->AiForceSpeed = 10; ++ pAdapter->AiForceDpx = 2; ++ break; ++ ++ case 3: // 100Mb Half-Duplex ++ pAdapter->AiForceSpeed = 100; ++ pAdapter->AiForceDpx = 1; ++ break; ++ ++ case 4: // 100Mb Full-Duplex ++ pAdapter->AiForceSpeed = 100; ++ pAdapter->AiForceDpx = 2; ++ break; ++ ++ case 5: // 1000Mb Full-Duplex ++ pAdapter->AiForceSpeed = 1000; ++ pAdapter->AiForceDpx = 2; ++ break; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} +diff --git a/drivers/staging/et131x/et131x_config.h b/drivers/staging/et131x/et131x_config.h +new file mode 100644 +index 0000000..642c0f6 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_config.h +@@ -0,0 +1,67 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_config.h - Defines, structs, enums, prototypes, etc. to support ++ * et131x_config.c ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_CONFIG_H__ ++#define __ET131X_CONFIG_H__ ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++void et131x_config_parse(struct et131x_adapter *adapter); ++ ++#endif /* __ET131X_CONFIG_H__ */ +diff --git a/drivers/staging/et131x/et131x_debug.c b/drivers/staging/et131x/et131x_debug.c +new file mode 100644 +index 0000000..9ee5bce +--- /dev/null ++++ b/drivers/staging/et131x/et131x_debug.c +@@ -0,0 +1,218 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_debug.c - Routines used for debugging. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifdef CONFIG_ET131X_DEBUG ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_netdev.h" ++#include "et131x_config.h" ++#include "et131x_isr.h" ++ ++#include "et1310_address_map.h" ++#include "et1310_jagcore.h" ++#include "et1310_tx.h" ++#include "et1310_rx.h" ++#include "et1310_mac.h" ++ ++/* Data for debugging facilities */ ++extern dbg_info_t *et131x_dbginfo; ++ ++/** ++ * DumpTxQueueContents - Dump out the tx queue and the shadow pointers ++ * @pAdapter: pointer to our adapter structure ++ */ ++void DumpTxQueueContents(int dbgLvl, struct et131x_adapter *pAdapter) ++{ ++ MMC_t __iomem *mmc = &pAdapter->CSRAddress->mmc; ++ uint32_t TxQueueAddr; ++ ++ if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) { ++ for (TxQueueAddr = 0x200; TxQueueAddr < 0x3ff; TxQueueAddr++) { ++ MMC_SRAM_ACCESS_t sram_access; ++ ++ sram_access.value = readl(&mmc->sram_access.value); ++ sram_access.bits.req_addr = TxQueueAddr; ++ sram_access.bits.req_access = 1; ++ writel(sram_access.value, &mmc->sram_access.value); ++ ++ DBG_PRINT("Addr 0x%x, Access 0x%08x\t" ++ "Value 1 0x%08x, Value 2 0x%08x, " ++ "Value 3 0x%08x, Value 4 0x%08x, \n", ++ TxQueueAddr, ++ readl(&mmc->sram_access.value), ++ readl(&mmc->sram_word1), ++ readl(&mmc->sram_word2), ++ readl(&mmc->sram_word3), ++ readl(&mmc->sram_word4)); ++ } ++ ++ DBG_PRINT("Shadow Pointers 0x%08x\n", ++ readl(&pAdapter->CSRAddress->txmac.shadow_ptr.value)); ++ } ++} ++ ++/** ++ * DumpDeviceBlock ++ * @pAdapter: pointer to our adapter ++ * ++ * Dumps the first 64 regs of each block of the et-1310 (each block is ++ * mapped to a new page, each page is 4096 bytes). ++ */ ++#define NUM_BLOCKS 8 ++void DumpDeviceBlock(int dbgLvl, struct et131x_adapter *pAdapter, ++ uint32_t Block) ++{ ++ uint32_t Address1, Address2; ++ uint32_t __iomem *BigDevicePointer = ++ (uint32_t __iomem *) pAdapter->CSRAddress; ++ const char *BlockNames[NUM_BLOCKS] = { ++ "Global", "Tx DMA", "Rx DMA", "Tx MAC", ++ "Rx MAC", "MAC", "MAC Stat", "MMC" ++ }; ++ ++ /* Output the debug counters to the debug terminal */ ++ if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) { ++ DBG_PRINT("%s block\n", BlockNames[Block]); ++ BigDevicePointer += Block * 1024; ++ for (Address1 = 0; Address1 < 8; Address1++) { ++ for (Address2 = 0; Address2 < 8; Address2++) { ++ if (Block == 0 && ++ (Address1 * 8 + Address2) == 6) { ++ DBG_PRINT(" ISR , "); ++ } else { ++ DBG_PRINT("0x%08x, ", ++ readl(BigDevicePointer++)); ++ } ++ } ++ DBG_PRINT("\n"); ++ } ++ DBG_PRINT("\n"); ++ } ++} ++ ++/** ++ * DumpDeviceReg ++ * @pAdapter: pointer to our adapter ++ * ++ * Dumps the first 64 regs of each block of the et-1310 (each block is ++ * mapped to a new page, each page is 4096 bytes). ++ */ ++void DumpDeviceReg(int dbgLvl, struct et131x_adapter *pAdapter) ++{ ++ uint32_t Address1, Address2; ++ uint32_t Block; ++ uint32_t __iomem *BigDevicePointer = ++ (uint32_t __iomem *) pAdapter->CSRAddress; ++ uint32_t __iomem *Pointer; ++ const char *BlockNames[NUM_BLOCKS] = { ++ "Global", "Tx DMA", "Rx DMA", "Tx MAC", ++ "Rx MAC", "MAC", "MAC Stat", "MMC" ++ }; ++ ++ /* Output the debug counters to the debug terminal */ ++ if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) { ++ for (Block = 0; Block < NUM_BLOCKS; Block++) { ++ DBG_PRINT("%s block\n", BlockNames[Block]); ++ Pointer = BigDevicePointer + (Block * 1024); ++ ++ for (Address1 = 0; Address1 < 8; Address1++) { ++ for (Address2 = 0; Address2 < 8; Address2++) { ++ DBG_PRINT("0x%08x, ", ++ readl(Pointer++)); ++ } ++ DBG_PRINT("\n"); ++ } ++ DBG_PRINT("\n"); ++ } ++ } ++} ++ ++#endif // CONFIG_ET131X_DEBUG +diff --git a/drivers/staging/et131x/et131x_debug.h b/drivers/staging/et131x/et131x_debug.h +new file mode 100644 +index 0000000..dab6080 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_debug.h +@@ -0,0 +1,201 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_debug.h - Defines, structs, enums, prototypes, etc. used for ++ * outputting debug messages to the system logging facility ++ * (ksyslogd) ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_DBG_H__ ++#define __ET131X_DBG_H__ ++ ++/* Define Masks for debugging types/levels */ ++#define DBG_ERROR_ON 0x00000001L ++#define DBG_WARNING_ON 0x00000002L ++#define DBG_NOTICE_ON 0x00000004L ++#define DBG_TRACE_ON 0x00000008L ++#define DBG_VERBOSE_ON 0x00000010L ++#define DBG_PARAM_ON 0x00000020L ++#define DBG_BREAK_ON 0x00000040L ++#define DBG_RX_ON 0x00000100L ++#define DBG_TX_ON 0x00000200L ++ ++#ifdef CONFIG_ET131X_DEBUG ++ ++/* ++ * Set the level of debugging if not done with a preprocessor define. See ++ * et131x_main.c, function et131x_init_module() for how the debug level ++ * translates into the types of messages displayed. ++ */ ++#ifndef DBG_LVL ++#define DBG_LVL 3 ++#endif /* DBG_LVL */ ++ ++#define DBG_DEFAULTS (DBG_ERROR_ON | DBG_WARNING_ON | DBG_BREAK_ON ) ++ ++#define DBG_FLAGS(A) (A)->dbgFlags ++#define DBG_NAME(A) (A)->dbgName ++#define DBG_LEVEL(A) (A)->dbgLevel ++ ++#ifndef DBG_PRINT ++#define DBG_PRINT(S...) printk(KERN_DEBUG S) ++#endif /* DBG_PRINT */ ++ ++#ifndef DBG_PRINTC ++#define DBG_PRINTC(S...) printk(S) ++#endif /* DBG_PRINTC */ ++ ++#ifndef DBG_TRAP ++#define DBG_TRAP {} /* BUG() */ ++#endif /* DBG_TRAP */ ++ ++#define _ENTER_STR ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" ++#define _LEAVE_STR "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" ++ ++#define _DBG_ENTER(A) printk(KERN_DEBUG "%s:%.*s:%s\n", DBG_NAME(A), \ ++ ++DBG_LEVEL(A), _ENTER_STR, __func__) ++#define _DBG_LEAVE(A) printk(KERN_DEBUG "%s:%.*s:%s\n", DBG_NAME(A), \ ++ DBG_LEVEL(A)--, _LEAVE_STR, __func__) ++ ++#define DBG_ENTER(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ ++ _DBG_ENTER(A);} ++ ++#define DBG_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ ++ _DBG_LEAVE(A);} ++ ++#define DBG_PARAM(A,N,F,S...) {if (DBG_FLAGS(A) & DBG_PARAM_ON) \ ++ DBG_PRINT(" %s -- "F"\n",N,S);} ++ ++#define DBG_ERROR(A,S...) \ ++ if (DBG_FLAGS(A) & DBG_ERROR_ON) { \ ++ DBG_PRINT("%s:ERROR:%s ",DBG_NAME(A), __func__); \ ++ DBG_PRINTC(S); \ ++ DBG_TRAP; \ ++ } ++ ++#define DBG_WARNING(A,S...) {if (DBG_FLAGS(A) & DBG_WARNING_ON) \ ++ {DBG_PRINT("%s:WARNING:%s ",DBG_NAME(A),__func__);DBG_PRINTC(S);}} ++ ++#define DBG_NOTICE(A,S...) {if (DBG_FLAGS(A) & DBG_NOTICE_ON) \ ++ {DBG_PRINT("%s:NOTICE:%s ",DBG_NAME(A),__func__);DBG_PRINTC(S);}} ++ ++#define DBG_TRACE(A,S...) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ ++ {DBG_PRINT("%s:TRACE:%s ",DBG_NAME(A), __func__);DBG_PRINTC(S);}} ++ ++#define DBG_VERBOSE(A,S...) {if (DBG_FLAGS(A) & DBG_VERBOSE_ON) \ ++ {DBG_PRINT("%s:VERBOSE:%s ",DBG_NAME(A), __func__);DBG_PRINTC(S);}} ++ ++#define DBG_RX(A,S...) {if (DBG_FLAGS(A) & DBG_RX_ON) \ ++ {DBG_PRINT(S);}} ++ ++#define DBG_RX_ENTER(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \ ++ _DBG_ENTER(A);} ++ ++#define DBG_RX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \ ++ _DBG_LEAVE(A);} ++ ++#define DBG_TX(A,S...) {if (DBG_FLAGS(A) & DBG_TX_ON) \ ++ {DBG_PRINT(S);}} ++ ++#define DBG_TX_ENTER(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \ ++ _DBG_ENTER(A);} ++ ++#define DBG_TX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \ ++ _DBG_LEAVE(A);} ++ ++#define DBG_ASSERT(C) {if (!(C)) \ ++ {DBG_PRINT("ASSERT(%s) -- %s#%d (%s)\n", \ ++ #C,__FILE__,__LINE__,__func__); \ ++ DBG_TRAP;}} ++#define STATIC ++ ++typedef struct { ++ char *dbgName; ++ int dbgLevel; ++ unsigned long dbgFlags; ++} dbg_info_t; ++ ++#else /* CONFIG_ET131X_DEBUG */ ++ ++#define DBG_DEFN ++#define DBG_TRAP ++#define DBG_PRINT(S...) ++#define DBG_ENTER(A) ++#define DBG_LEAVE(A) ++#define DBG_PARAM(A,N,F,S...) ++#define DBG_ERROR(A,S...) ++#define DBG_WARNING(A,S...) ++#define DBG_NOTICE(A,S...) ++#define DBG_TRACE(A,S...) ++#define DBG_VERBOSE(A,S...) ++#define DBG_RX(A,S...) ++#define DBG_RX_ENTER(A) ++#define DBG_RX_LEAVE(A) ++#define DBG_TX(A,S...) ++#define DBG_TX_ENTER(A) ++#define DBG_TX_LEAVE(A) ++#define DBG_ASSERT(C) ++#define STATIC static ++ ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/* Forward declaration of the private adapter structure */ ++struct et131x_adapter; ++ ++void DumpTxQueueContents(int dbgLvl, struct et131x_adapter *adapter); ++void DumpDeviceBlock(int dbgLvl, struct et131x_adapter *adapter, ++ unsigned int Block); ++void DumpDeviceReg(int dbgLvl, struct et131x_adapter *adapter); ++ ++#endif /* __ET131X_DBG_H__ */ +diff --git a/drivers/staging/et131x/et131x_defs.h b/drivers/staging/et131x/et131x_defs.h +new file mode 100644 +index 0000000..886cb78 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_defs.h +@@ -0,0 +1,128 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_defs.h - Defines, structs, enums, prototypes, etc. to assist with OS ++ * compatibility ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_DEFS_H__ ++#define __ET131X_DEFS_H__ ++ ++/* Packet and header sizes */ ++#define NIC_MIN_PACKET_SIZE 60 ++#define NIC_HEADER_SIZE ETH_HLEN /* 14 */ ++ ++/* Multicast list size */ ++#define NIC_MAX_MCAST_LIST 128 ++ ++/* Supported Filters */ ++#define ET131X_PACKET_TYPE_DIRECTED 0x0001 ++#define ET131X_PACKET_TYPE_MULTICAST 0x0002 ++#define ET131X_PACKET_TYPE_BROADCAST 0x0004 ++#define ET131X_PACKET_TYPE_PROMISCUOUS 0x0008 ++#define ET131X_PACKET_TYPE_ALL_MULTICAST 0x0010 ++ ++/* Tx Timeout */ ++#define ET131X_TX_TIMEOUT (1 * HZ) ++#define NIC_SEND_HANG_THRESHOLD 0 ++ ++/* MP_TCB flags */ ++#define fMP_DEST_MULTI 0x00000001 ++#define fMP_DEST_BROAD 0x00000002 ++ ++/* MP_ADAPTER flags */ ++#define fMP_ADAPTER_RECV_LOOKASIDE 0x00000004 ++#define fMP_ADAPTER_INTERRUPT_IN_USE 0x00000008 ++#define fMP_ADAPTER_SECONDARY 0x00000010 ++ ++/* MP_SHARED flags */ ++#define fMP_ADAPTER_SHUTDOWN 0x00100000 ++#define fMP_ADAPTER_LOWER_POWER 0x00200000 ++ ++#define fMP_ADAPTER_NON_RECOVER_ERROR 0x00800000 ++#define fMP_ADAPTER_RESET_IN_PROGRESS 0x01000000 ++#define fMP_ADAPTER_NO_CABLE 0x02000000 ++#define fMP_ADAPTER_HARDWARE_ERROR 0x04000000 ++#define fMP_ADAPTER_REMOVE_IN_PROGRESS 0x08000000 ++#define fMP_ADAPTER_HALT_IN_PROGRESS 0x10000000 ++#define fMP_ADAPTER_LINK_DETECTION 0x20000000 ++ ++#define fMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000 ++#define fMP_ADAPTER_NOT_READY_MASK 0x3ff00000 ++ ++/* Some offsets in PCI config space that are actually used. */ ++#define ET1310_PCI_PM_CAPABILITY 0x40 ++#define ET1310_PCI_PM_CSR 0x44 ++#define ET1310_PCI_MAX_PYLD 0x4C ++#define ET1310_PCI_DEV_CTRL 0x50 ++#define ET1310_PCI_DEV_STAT 0x52 ++#define ET1310_NMI_DISABLE 0x61 ++#define ET1310_PCI_MAC_ADDRESS 0xA4 ++#define ET1310_PCI_EEPROM_STATUS 0xB2 ++#define ET1310_PCI_PHY_INDEX_REG 0xB4 ++#define ET1310_PCI_ACK_NACK 0xC0 ++#define ET1310_PCI_REPLAY 0xC2 ++#define ET1310_PCI_L0L1LATENCY 0xCF ++#define ET1310_PCI_SEL_PHY_CTRL 0xE4 ++#define ET1310_PCI_ADVANCED_ERR 0x100 ++ ++/* PCI Vendor/Product IDs */ ++#define ET131X_PCI_VENDOR_ID 0x11C1 // Agere Systems ++#define ET131X_PCI_DEVICE_ID_GIG 0xED00 // ET1310 1000 Base-T ++#define ET131X_PCI_DEVICE_ID_FAST 0xED01 // ET1310 100 Base-T ++ ++/* Define order of magnitude converter */ ++#define NANO_IN_A_MICRO 1000 ++ ++#endif /* __ET131X_DEFS_H__ */ +diff --git a/drivers/staging/et131x/et131x_initpci.c b/drivers/staging/et131x/et131x_initpci.c +new file mode 100644 +index 0000000..4c6f171 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_initpci.c +@@ -0,0 +1,1046 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_initpci.c - Routines and data used to register the driver with the ++ * PCI (and PCI Express) subsystem, as well as basic driver ++ * init and startup. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_netdev.h" ++#include "et131x_config.h" ++#include "et131x_isr.h" ++ ++#include "et1310_address_map.h" ++#include "et1310_jagcore.h" ++#include "et1310_tx.h" ++#include "et1310_rx.h" ++#include "et1310_mac.h" ++#include "et1310_eeprom.h" ++ ++ ++int __devinit et131x_pci_setup(struct pci_dev *pdev, ++ const struct pci_device_id *ent); ++void __devexit et131x_pci_remove(struct pci_dev *pdev); ++ ++ ++/* Modinfo parameters (filled out using defines from et131x_version.h) */ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_INFO); ++MODULE_LICENSE(DRIVER_LICENSE); ++ ++/* Module Parameters and related data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++static u32 et131x_debug_level = DBG_LVL; ++static u32 et131x_debug_flags = DBG_DEFAULTS; ++ ++/* ++et131x_debug_level : ++ Level of debugging desired (0-7) ++ 7 : DBG_RX_ON | DBG_TX_ON ++ 6 : DBG_PARAM_ON ++ 5 : DBG_VERBOSE_ON ++ 4 : DBG_TRACE_ON ++ 3 : DBG_NOTICE_ON ++ 2 : no debug info ++ 1 : no debug info ++ 0 : no debug info ++*/ ++ ++module_param(et131x_debug_level, uint, 0); ++module_param(et131x_debug_flags, uint, 0); ++ ++MODULE_PARM_DESC(et131x_debug_level, "Level of debugging desired (0-7)"); ++ ++static dbg_info_t et131x_info = { DRIVER_NAME_EXT, 0, 0 }; ++dbg_info_t *et131x_dbginfo = &et131x_info; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++static struct pci_device_id et131x_pci_table[] __devinitdata = { ++ {ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_GIG, PCI_ANY_ID, ++ PCI_ANY_ID, 0, 0, 0UL}, ++ {ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_FAST, PCI_ANY_ID, ++ PCI_ANY_ID, 0, 0, 0UL}, ++ {0,} ++}; ++ ++MODULE_DEVICE_TABLE(pci, et131x_pci_table); ++ ++static struct pci_driver et131x_driver = { ++ .name = DRIVER_NAME, ++ .id_table = et131x_pci_table, ++ .probe = et131x_pci_setup, ++ .remove = __devexit_p(et131x_pci_remove), ++ .suspend = NULL, //et131x_pci_suspend, ++ .resume = NULL, //et131x_pci_resume, ++}; ++ ++ ++/** ++ * et131x_init_module - The "main" entry point called on driver initialization ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_init_module(void) ++{ ++ int result; ++ ++#ifdef CONFIG_ET131X_DEBUG ++ /* Set the level of debug messages displayed using the module ++ * parameter ++ */ ++ et131x_dbginfo->dbgFlags = et131x_debug_flags; ++ ++ switch (et131x_debug_level) { ++ case 7: ++ et131x_dbginfo->dbgFlags |= (DBG_RX_ON | DBG_TX_ON); ++ ++ case 6: ++ et131x_dbginfo->dbgFlags |= DBG_PARAM_ON; ++ ++ case 5: ++ et131x_dbginfo->dbgFlags |= DBG_VERBOSE_ON; ++ ++ case 4: ++ et131x_dbginfo->dbgFlags |= DBG_TRACE_ON; ++ ++ case 3: ++ et131x_dbginfo->dbgFlags |= DBG_NOTICE_ON; ++ ++ case 2: ++ case 1: ++ case 0: ++ default: ++ break; ++ } ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++ DBG_ENTER(et131x_dbginfo); ++ DBG_PRINT("%s\n", DRIVER_INFO); ++ ++ result = pci_register_driver(&et131x_driver); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return result; ++} ++ ++/** ++ * et131x_cleanup_module - The entry point called on driver cleanup ++ */ ++void et131x_cleanup_module(void) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ pci_unregister_driver(&et131x_driver); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/* ++ * These macros map the driver-specific init_module() and cleanup_module() ++ * routines so they can be called by the kernel. ++ */ ++module_init(et131x_init_module); ++module_exit(et131x_cleanup_module); ++ ++ ++/** ++ * et131x_find_adapter - Find the adapter and get all the assigned resources ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_find_adapter(struct et131x_adapter *adapter, struct pci_dev *pdev) ++{ ++ int result; ++ uint8_t eepromStat; ++ uint8_t maxPayload = 0; ++ uint8_t read_size_reg; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Allow disabling of Non-Maskable Interrupts in I/O space, to ++ * support validation. ++ */ ++ if (adapter->RegistryNMIDisable) { ++ uint8_t RegisterVal; ++ ++ RegisterVal = inb(ET1310_NMI_DISABLE); ++ RegisterVal &= 0xf3; ++ ++ if (adapter->RegistryNMIDisable == 2) { ++ RegisterVal |= 0xc; ++ } ++ ++ outb(ET1310_NMI_DISABLE, RegisterVal); ++ } ++ ++ /* We first need to check the EEPROM Status code located at offset ++ * 0xB2 of config space ++ */ ++ result = pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, ++ &eepromStat); ++ ++ /* THIS IS A WORKAROUND: ++ * I need to call this function twice to get my card in a ++ * LG M1 Express Dual running. I tried also a msleep before this ++ * function, because I thougth there could be some time condidions ++ * but it didn't work. Call the whole function twice also work. ++ */ ++ result = pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, ++ &eepromStat); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, "Could not read PCI config space for " ++ "EEPROM Status\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ /* Determine if the error(s) we care about are present. If they are ++ * present, we need to fail. ++ */ ++ if (eepromStat & 0x4C) { ++ result = pci_read_config_byte(pdev, PCI_REVISION_ID, ++ &adapter->RevisionID); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not read PCI config space for " ++ "Revision ID\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } else if (adapter->RevisionID == 0x01) { ++ int32_t nLoop; ++ uint8_t ucTemp[4] = { 0xFE, 0x13, 0x10, 0xFF }; ++ ++ /* Re-write the first 4 bytes if we have an eeprom ++ * present and the revision id is 1, this fixes the ++ * corruption seen with 1310 B Silicon ++ */ ++ for (nLoop = 0; nLoop < 3; nLoop++) { ++ EepromWriteByte(adapter, nLoop, ucTemp[nLoop], ++ 0, SINGLE_BYTE); ++ } ++ } ++ ++ DBG_ERROR(et131x_dbginfo, ++ "Fatal EEPROM Status Error - 0x%04x\n", eepromStat); ++ ++ /* This error could mean that there was an error reading the ++ * eeprom or that the eeprom doesn't exist. We will treat ++ * each case the same and not try to gather additional ++ * information that normally would come from the eeprom, like ++ * MAC Address ++ */ ++ adapter->bEepromPresent = false; ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } else { ++ DBG_TRACE(et131x_dbginfo, "EEPROM Status Code - 0x%04x\n", ++ eepromStat); ++ adapter->bEepromPresent = true; ++ } ++ ++ /* Read the EEPROM for information regarding LED behavior. Refer to ++ * ET1310_phy.c, et131x_xcvr_init(), for its use. ++ */ ++ EepromReadByte(adapter, 0x70, &adapter->eepromData[0], 0, SINGLE_BYTE); ++ EepromReadByte(adapter, 0x71, &adapter->eepromData[1], 0, SINGLE_BYTE); ++ ++ if (adapter->eepromData[0] != 0xcd) { ++ adapter->eepromData[1] = 0x00; // Disable all optional features ++ } ++ ++ /* Let's set up the PORT LOGIC Register. First we need to know what ++ * the max_payload_size is ++ */ ++ result = pci_read_config_byte(pdev, ET1310_PCI_MAX_PYLD, &maxPayload); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, "Could not read PCI config space for " ++ "Max Payload Size\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ /* Program the Ack/Nak latency and replay timers */ ++ maxPayload &= 0x07; // Only the lower 3 bits are valid ++ ++ if (maxPayload < 2) { ++ const uint16_t AckNak[2] = { 0x76, 0xD0 }; ++ const uint16_t Replay[2] = { 0x1E0, 0x2ED }; ++ ++ result = pci_write_config_word(pdev, ET1310_PCI_ACK_NACK, ++ AckNak[maxPayload]); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not write PCI config space " ++ "for ACK/NAK\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ result = pci_write_config_word(pdev, ET1310_PCI_REPLAY, ++ Replay[maxPayload]); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not write PCI config space " ++ "for Replay Timer\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ } ++ ++ /* l0s and l1 latency timers. We are using default values. ++ * Representing 001 for L0s and 010 for L1 ++ */ ++ result = pci_write_config_byte(pdev, ET1310_PCI_L0L1LATENCY, 0x11); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not write PCI config space for " ++ "Latency Timers\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ /* Change the max read size to 2k */ ++ result = pci_read_config_byte(pdev, 0x51, &read_size_reg); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not read PCI config space for Max read size\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ read_size_reg &= 0x8f; ++ read_size_reg |= 0x40; ++ ++ result = pci_write_config_byte(pdev, 0x51, read_size_reg); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not write PCI config space for Max read size\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ /* PCI Express Configuration registers 0x48-0x5B (Device Control) */ ++ result = pci_read_config_word(pdev, ET1310_PCI_DEV_CTRL, ++ &adapter->PciXDevCtl); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not read PCI config space for PCI Express Dev Ctl\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ ++ /* Get MAC address from config space if an eeprom exists, otherwise ++ * the MAC address there will not be valid ++ */ ++ if (adapter->bEepromPresent) { ++ int i; ++ ++ for (i = 0; i < ETH_ALEN; i++) { ++ result = pci_read_config_byte( ++ pdev, ET1310_PCI_MAC_ADDRESS + i, ++ adapter->PermanentAddress + i); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not read PCI config space for MAC address\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return -EIO; ++ } ++ } ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++/** ++ * et131x_error_timer_handler ++ * @data: timer-specific variable; here a pointer to our adapter structure ++ * ++ * The routine called when the error timer expires, to track the number of ++ * recurring errors. ++ */ ++void et131x_error_timer_handler(unsigned long data) ++{ ++ struct et131x_adapter *pAdapter = (struct et131x_adapter *) data; ++ PM_CSR_t pm_csr; ++ ++ pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); ++ ++ if (pm_csr.bits.pm_phy_sw_coma == 0) { ++ if (pAdapter->RegistryMACStat) { ++ UpdateMacStatHostCounters(pAdapter); ++ } ++ } else { ++ DBG_VERBOSE(et131x_dbginfo, ++ "No interrupts, in PHY coma, pm_csr = 0x%x\n", ++ pm_csr.value); ++ } ++ ++ if (!pAdapter->Bmsr.bits.link_status && ++ pAdapter->RegistryPhyComa && ++ pAdapter->PoMgmt.TransPhyComaModeOnBoot < 11) { ++ pAdapter->PoMgmt.TransPhyComaModeOnBoot++; ++ } ++ ++ if (pAdapter->PoMgmt.TransPhyComaModeOnBoot == 10) { ++ if (!pAdapter->Bmsr.bits.link_status ++ && pAdapter->RegistryPhyComa) { ++ if (pm_csr.bits.pm_phy_sw_coma == 0) { ++ // NOTE - This was originally a 'sync with interrupt'. How ++ // to do that under Linux? ++ et131x_enable_interrupts(pAdapter); ++ EnablePhyComa(pAdapter); ++ } ++ } ++ } ++ ++ /* This is a periodic timer, so reschedule */ ++ mod_timer(&pAdapter->ErrorTimer, jiffies + ++ TX_ERROR_PERIOD * HZ / 1000); ++} ++ ++/** ++ * et131x_link_detection_handler ++ * ++ * Timer function for link up at driver load time ++ */ ++void et131x_link_detection_handler(unsigned long data) ++{ ++ struct et131x_adapter *pAdapter = (struct et131x_adapter *) data; ++ unsigned long lockflags; ++ ++ /* Let everyone know that we have run */ ++ pAdapter->bLinkTimerActive = false; ++ ++ if (pAdapter->MediaState == 0) { ++ spin_lock_irqsave(&pAdapter->Lock, lockflags); ++ ++ pAdapter->MediaState = NETIF_STATUS_MEDIA_DISCONNECT; ++ MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION); ++ ++ spin_unlock_irqrestore(&pAdapter->Lock, lockflags); ++ ++ netif_carrier_off(pAdapter->netdev); ++ ++ pAdapter->bSetPending = false; ++ } ++} ++ ++/** ++ * et131x_adapter_setup - Set the adapter up as per cassini+ documentation ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_adapter_setup(struct et131x_adapter *pAdapter) ++{ ++ int status = 0; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Configure the JAGCore */ ++ ConfigGlobalRegs(pAdapter); ++ ++ ConfigMACRegs1(pAdapter); ++ ConfigMMCRegs(pAdapter); ++ ++ ConfigRxMacRegs(pAdapter); ++ ConfigTxMacRegs(pAdapter); ++ ++ ConfigRxDmaRegs(pAdapter); ++ ConfigTxDmaRegs(pAdapter); ++ ++ ConfigMacStatRegs(pAdapter); ++ ++ /* Move the following code to Timer function?? */ ++ status = et131x_xcvr_find(pAdapter); ++ ++ if (status != 0) { ++ DBG_WARNING(et131x_dbginfo, "Could not find the xcvr\n"); ++ } ++ ++ /* Prepare the TRUEPHY library. */ ++ ET1310_PhyInit(pAdapter); ++ ++ /* Reset the phy now so changes take place */ ++ ET1310_PhyReset(pAdapter); ++ ++ /* Power down PHY */ ++ ET1310_PhyPowerDown(pAdapter, 1); ++ ++ /* ++ * We need to turn off 1000 base half dulplex, the mac does not ++ * support it. For the 10/100 part, turn off all gig advertisement ++ */ ++ if (pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST) { ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); ++ } else { ++ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); ++ } ++ ++ /* Power up PHY */ ++ ET1310_PhyPowerDown(pAdapter, 0); ++ ++ et131x_setphy_normal(pAdapter); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_setup_hardware_properties - set up the MAC Address on the ET1310 ++ * @adapter: pointer to our private adapter structure ++ */ ++void et131x_setup_hardware_properties(struct et131x_adapter *adapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* If have our default mac from registry and no mac address from ++ * EEPROM then we need to generate the last octet and set it on the ++ * device ++ */ ++ if (!adapter->bOverrideAddress) { ++ if (adapter->PermanentAddress[0] == 0x00 && ++ adapter->PermanentAddress[1] == 0x00 && ++ adapter->PermanentAddress[2] == 0x00 && ++ adapter->PermanentAddress[3] == 0x00 && ++ adapter->PermanentAddress[4] == 0x00 && ++ adapter->PermanentAddress[5] == 0x00) { ++ /* ++ * We need to randomly generate the last octet so we ++ * decrease our chances of setting the mac address to ++ * same as another one of our cards in the system ++ */ ++ get_random_bytes(&adapter->CurrentAddress[5], 1); ++ ++ /* ++ * We have the default value in the register we are ++ * working with so we need to copy the current ++ * address into the permanent address ++ */ ++ memcpy(adapter->PermanentAddress, ++ adapter->CurrentAddress, ETH_ALEN); ++ } else { ++ /* We do not have an override address, so set the ++ * current address to the permanent address and add ++ * it to the device ++ */ ++ memcpy(adapter->CurrentAddress, ++ adapter->PermanentAddress, ETH_ALEN); ++ } ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_soft_reset - Issue a soft reset to the hardware, complete for ET1310 ++ * @adapter: pointer to our private adapter structure ++ */ ++void et131x_soft_reset(struct et131x_adapter *adapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Disable MAC Core */ ++ writel(0xc00f0000, &adapter->CSRAddress->mac.cfg1.value); ++ ++ /* Set everything to a reset value */ ++ writel(0x7F, &adapter->CSRAddress->global.sw_reset.value); ++ writel(0x000f0000, &adapter->CSRAddress->mac.cfg1.value); ++ writel(0x00000000, &adapter->CSRAddress->mac.cfg1.value); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_align_allocated_memory - Align allocated memory on a given boundary ++ * @adapter: pointer to our adapter structure ++ * @phys_addr: pointer to Physical address ++ * @offset: pointer to the offset variable ++ * @mask: correct mask ++ */ ++void et131x_align_allocated_memory(struct et131x_adapter *adapter, ++ uint64_t *phys_addr, ++ uint64_t *offset, uint64_t mask) ++{ ++ uint64_t new_addr; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ *offset = 0; ++ ++ new_addr = *phys_addr & ~mask; ++ ++ if (new_addr != *phys_addr) { ++ /* Move to next aligned block */ ++ new_addr += mask + 1; ++ /* Return offset for adjusting virt addr */ ++ *offset = new_addr - *phys_addr; ++ /* Return new physical address */ ++ *phys_addr = new_addr; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_adapter_memory_alloc ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h). ++ * ++ * Allocate all the memory blocks for send, receive and others. ++ */ ++int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) ++{ ++ int status = 0; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ do { ++ /* Allocate memory for the Tx Ring */ ++ status = et131x_tx_dma_memory_alloc(adapter); ++ if (status != 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "et131x_tx_dma_memory_alloc FAILED\n"); ++ break; ++ } ++ ++ /* Receive buffer memory allocation */ ++ status = et131x_rx_dma_memory_alloc(adapter); ++ if (status != 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "et131x_rx_dma_memory_alloc FAILED\n"); ++ et131x_tx_dma_memory_free(adapter); ++ break; ++ } ++ ++ /* Init receive data structures */ ++ status = et131x_init_recv(adapter); ++ if (status != 0) { ++ DBG_ERROR(et131x_dbginfo, "et131x_init_recv FAILED\n"); ++ et131x_tx_dma_memory_free(adapter); ++ et131x_rx_dma_memory_free(adapter); ++ break; ++ } ++ } while (0); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_adapter_memory_free - Free all memory allocated for use by Tx & Rx ++ * @adapter: pointer to our private adapter structure ++ */ ++void et131x_adapter_memory_free(struct et131x_adapter *adapter) ++{ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Free DMA memory */ ++ et131x_tx_dma_memory_free(adapter); ++ et131x_rx_dma_memory_free(adapter); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_pci_remove ++ * @pdev: a pointer to the device's pci_dev structure ++ * ++ * Registered in the pci_driver structure, this function is called when the ++ * PCI subsystem detects that a PCI device which matches the information ++ * contained in the pci_device_id table has been removed. ++ */ ++void __devexit et131x_pci_remove(struct pci_dev *pdev) ++{ ++ struct net_device *netdev; ++ struct et131x_adapter *adapter; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Retrieve the net_device pointer from the pci_dev struct, as well ++ * as the private adapter struct ++ */ ++ netdev = (struct net_device *) pci_get_drvdata(pdev); ++ adapter = netdev_priv(netdev); ++ ++ /* Perform device cleanup */ ++ unregister_netdev(netdev); ++ et131x_adapter_memory_free(adapter); ++ iounmap(adapter->CSRAddress); ++ free_netdev(netdev); ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_pci_setup - Perform device initialization ++ * @pdev: a pointer to the device's pci_dev structure ++ * @ent: this device's entry in the pci_device_id table ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ * ++ * Registered in the pci_driver structure, this function is called when the ++ * PCI subsystem finds a new PCI device which matches the information ++ * contained in the pci_device_id table. This routine is the equivalent to ++ * a device insertion routine. ++ */ ++int __devinit et131x_pci_setup(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ int result = 0; ++ int pm_cap; ++ bool pci_using_dac; ++ struct net_device *netdev = NULL; ++ struct et131x_adapter *adapter = NULL; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Enable the device via the PCI subsystem */ ++ result = pci_enable_device(pdev); ++ if (result != 0) { ++ DBG_ERROR(et131x_dbginfo, "pci_enable_device() failed\n"); ++ goto out; ++ } ++ ++ /* Perform some basic PCI checks */ ++ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { ++ DBG_ERROR(et131x_dbginfo, ++ "Can't find PCI device's base address\n"); ++ result = -ENODEV; ++ goto out; ++ } ++ ++ result = pci_request_regions(pdev, DRIVER_NAME); ++ if (result != 0) { ++ DBG_ERROR(et131x_dbginfo, "Can't get PCI resources\n"); ++ goto err_disable; ++ } ++ ++ /* Enable PCI bus mastering */ ++ DBG_TRACE(et131x_dbginfo, "Setting PCI Bus Mastering...\n"); ++ pci_set_master(pdev); ++ ++ /* Query PCI for Power Mgmt Capabilities ++ * ++ * NOTE: Now reading PowerMgmt in another location; is this still ++ * needed? ++ */ ++ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); ++ if (pm_cap == 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "Cannot find Power Management capabilities\n"); ++ result = -EIO; ++ goto err_release_res; ++ } ++ ++ /* Check the DMA addressing support of this device */ ++ if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { ++ DBG_TRACE(et131x_dbginfo, "64-bit DMA addressing supported\n"); ++ pci_using_dac = true; ++ ++ result = ++ pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); ++ if (result != 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "Unable to obtain 64 bit DMA for consistent allocations\n"); ++ goto err_release_res; ++ } ++ } else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) { ++ DBG_TRACE(et131x_dbginfo, ++ "64-bit DMA addressing NOT supported\n"); ++ DBG_TRACE(et131x_dbginfo, ++ "32-bit DMA addressing will be used\n"); ++ pci_using_dac = false; ++ } else { ++ DBG_ERROR(et131x_dbginfo, "No usable DMA addressing method\n"); ++ result = -EIO; ++ goto err_release_res; ++ } ++ ++ /* Allocate netdev and private adapter structs */ ++ DBG_TRACE(et131x_dbginfo, ++ "Allocate netdev and private adapter structs...\n"); ++ netdev = et131x_device_alloc(); ++ if (netdev == NULL) { ++ DBG_ERROR(et131x_dbginfo, "Couldn't alloc netdev struct\n"); ++ result = -ENOMEM; ++ goto err_release_res; ++ } ++ ++ /* Setup the fundamental net_device and private adapter structure elements */ ++ DBG_TRACE(et131x_dbginfo, "Setting fundamental net_device info...\n"); ++ SET_NETDEV_DEV(netdev, &pdev->dev); ++ if (pci_using_dac) { ++ //netdev->features |= NETIF_F_HIGHDMA; ++ } ++ ++ /* ++ * NOTE - Turn this on when we're ready to deal with SG-DMA ++ * ++ * NOTE: According to "Linux Device Drivers", 3rd ed, Rubini et al, ++ * if checksumming is not performed in HW, then the kernel will not ++ * use SG. ++ * From pp 510-511: ++ * ++ * "Note that the kernel does not perform scatter/gather I/O to your ++ * device if it does not also provide some form of checksumming as ++ * well. The reason is that, if the kernel has to make a pass over a ++ * fragmented ("nonlinear") packet to calculate the checksum, it ++ * might as well copy the data and coalesce the packet at the same ++ * time." ++ * ++ * This has been verified by setting the flags below and still not ++ * receiving a scattered buffer from the network stack, so leave it ++ * off until checksums are calculated in HW. ++ */ ++ //netdev->features |= NETIF_F_SG; ++ //netdev->features |= NETIF_F_NO_CSUM; ++ //netdev->features |= NETIF_F_LLTX; ++ ++ /* Allocate private adapter struct and copy in relevant information */ ++ adapter = netdev_priv(netdev); ++ adapter->pdev = pdev; ++ adapter->netdev = netdev; ++ adapter->VendorID = pdev->vendor; ++ adapter->DeviceID = pdev->device; ++ ++ /* Do the same for the netdev struct */ ++ netdev->irq = pdev->irq; ++ netdev->base_addr = pdev->resource[0].start; ++ ++ /* Initialize spinlocks here */ ++ DBG_TRACE(et131x_dbginfo, "Initialize spinlocks...\n"); ++ ++ spin_lock_init(&adapter->Lock); ++ spin_lock_init(&adapter->TCBSendQLock); ++ spin_lock_init(&adapter->TCBReadyQLock); ++ spin_lock_init(&adapter->SendHWLock); ++ spin_lock_init(&adapter->SendWaitLock); ++ spin_lock_init(&adapter->RcvLock); ++ spin_lock_init(&adapter->RcvPendLock); ++ spin_lock_init(&adapter->FbrLock); ++ spin_lock_init(&adapter->PHYLock); ++ ++ /* Parse configuration parameters into the private adapter struct */ ++ et131x_config_parse(adapter); ++ ++ /* Find the physical adapter ++ * ++ * NOTE: This is the equivalent of the MpFindAdapter() routine; can we ++ * lump it's init with the device specific init below into a ++ * single init function? ++ */ ++ //while (et131x_find_adapter(adapter, pdev) != 0); ++ et131x_find_adapter(adapter, pdev); ++ ++ /* Map the bus-relative registers to system virtual memory */ ++ DBG_TRACE(et131x_dbginfo, ++ "Mapping bus-relative registers to virtual memory...\n"); ++ ++ adapter->CSRAddress = ioremap_nocache(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)); ++ if (adapter->CSRAddress == NULL) { ++ DBG_ERROR(et131x_dbginfo, "Cannot map device registers\n"); ++ result = -ENOMEM; ++ goto err_free_dev; ++ } ++ ++ /* Perform device-specific initialization here (See code below) */ ++ ++ /* If Phy COMA mode was enabled when we went down, disable it here. */ ++ { ++ PM_CSR_t GlobalPmCSR = { 0 }; ++ ++ GlobalPmCSR.bits.pm_sysclk_gate = 1; ++ GlobalPmCSR.bits.pm_txclk_gate = 1; ++ GlobalPmCSR.bits.pm_rxclk_gate = 1; ++ writel(GlobalPmCSR.value, ++ &adapter->CSRAddress->global.pm_csr.value); ++ } ++ ++ /* Issue a global reset to the et1310 */ ++ DBG_TRACE(et131x_dbginfo, "Issuing soft reset...\n"); ++ et131x_soft_reset(adapter); ++ ++ /* Disable all interrupts (paranoid) */ ++ DBG_TRACE(et131x_dbginfo, "Disable device interrupts...\n"); ++ et131x_disable_interrupts(adapter); ++ ++ /* Allocate DMA memory */ ++ result = et131x_adapter_memory_alloc(adapter); ++ if (result != 0) { ++ DBG_ERROR(et131x_dbginfo, ++ "Could not alloc adapater memory (DMA)\n"); ++ goto err_iounmap; ++ } ++ ++ /* Init send data structures */ ++ DBG_TRACE(et131x_dbginfo, "Init send data structures...\n"); ++ et131x_init_send(adapter); ++ ++ adapter->PoMgmt.PowerState = NdisDeviceStateD0; ++ ++ /* Register the interrupt ++ * ++ * NOTE - This is being done in the open routine, where most other ++ * Linux drivers setup IRQ handlers. Make sure device ++ * interrupts are not turned on before the IRQ is registered!! ++ * ++ * What we will do here is setup the task structure for the ++ * ISR's deferred handler ++ */ ++ INIT_WORK(&adapter->task, et131x_isr_handler); ++ ++ /* Determine MAC Address, and copy into the net_device struct */ ++ DBG_TRACE(et131x_dbginfo, "Retrieve MAC address...\n"); ++ et131x_setup_hardware_properties(adapter); ++ ++ memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN); ++ ++ /* Setup et1310 as per the documentation */ ++ DBG_TRACE(et131x_dbginfo, "Setup the adapter...\n"); ++ et131x_adapter_setup(adapter); ++ ++ /* Create a timer to count errors received by the NIC */ ++ init_timer(&adapter->ErrorTimer); ++ ++ adapter->ErrorTimer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000; ++ adapter->ErrorTimer.function = et131x_error_timer_handler; ++ adapter->ErrorTimer.data = (unsigned long)adapter; ++ ++ /* Initialize link state */ ++ et131x_link_detection_handler((unsigned long)adapter); ++ ++ /* Intialize variable for counting how long we do not have link status */ ++ adapter->PoMgmt.TransPhyComaModeOnBoot = 0; ++ ++ /* We can enable interrupts now ++ * ++ * NOTE - Because registration of interrupt handler is done in the ++ * device's open(), defer enabling device interrupts to that ++ * point ++ */ ++ ++ /* Register the net_device struct with the Linux network layer */ ++ DBG_TRACE(et131x_dbginfo, "Registering net_device...\n"); ++ if ((result = register_netdev(netdev)) != 0) { ++ DBG_ERROR(et131x_dbginfo, "register_netdev() failed\n"); ++ goto err_mem_free; ++ } ++ ++ /* Register the net_device struct with the PCI subsystem. Save a copy ++ * of the PCI config space for this device now that the device has ++ * been initialized, just in case it needs to be quickly restored. ++ */ ++ pci_set_drvdata(pdev, netdev); ++ ++ pci_save_state(adapter->pdev); ++ ++out: ++ DBG_LEAVE(et131x_dbginfo); ++ return result; ++ ++err_mem_free: ++ et131x_adapter_memory_free(adapter); ++err_iounmap: ++ iounmap(adapter->CSRAddress); ++err_free_dev: ++ free_netdev(netdev); ++err_release_res: ++ pci_release_regions(pdev); ++err_disable: ++ pci_disable_device(pdev); ++ goto out; ++} +diff --git a/drivers/staging/et131x/et131x_initpci.h b/drivers/staging/et131x/et131x_initpci.h +new file mode 100644 +index 0000000..bbacb62 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_initpci.h +@@ -0,0 +1,73 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_initpci.h - Header which includes common data and function prototypes ++ * related to the driver's PCI (and PCI Express) information. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_INITPCI_H__ ++#define __ET131X_INITPCI_H__ ++ ++/* Function Prototypes */ ++void et131x_align_allocated_memory(struct et131x_adapter *adapter, ++ u64 *phys_addr, ++ u64 *offset, u64 mask); ++ ++int et131x_adapter_setup(struct et131x_adapter *adapter); ++int et131x_adapter_memory_alloc(struct et131x_adapter *adapter); ++void et131x_adapter_memory_free(struct et131x_adapter *adapter); ++void et131x_setup_hardware_properties(struct et131x_adapter *adapter); ++void et131x_soft_reset(struct et131x_adapter *adapter); ++ ++#endif /* __ET131X_INITPCI_H__ */ +diff --git a/drivers/staging/et131x/et131x_isr.c b/drivers/staging/et131x/et131x_isr.c +new file mode 100644 +index 0000000..00afad1 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_isr.c +@@ -0,0 +1,488 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_isr.c - File which contains the ISR, ISR handler, and related routines ++ * for processing interrupts from the device. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++#include "et1310_mac.h" ++ ++#include "et131x_adapter.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++/** ++ * et131x_isr - The Interrupt Service Routine for the driver. ++ * @irq: the IRQ on which the interrupt was received. ++ * @dev_id: device-specific info (here a pointer to a net_device struct) ++ * ++ * Returns a value indicating if the interrupt was handled. ++ */ ++irqreturn_t et131x_isr(int irq, void *dev_id) ++{ ++ bool handled = true; ++ struct net_device *netdev = (struct net_device *)dev_id; ++ struct et131x_adapter *adapter = NULL; ++ INTERRUPT_t status; ++ ++ if (netdev == NULL || !netif_device_present(netdev)) { ++ DBG_WARNING(et131x_dbginfo, ++ "No net_device struct or device not present\n"); ++ handled = false; ++ goto out; ++ } ++ ++ adapter = netdev_priv(netdev); ++ ++ /* If the adapter is in low power state, then it should not ++ * recognize any interrupt ++ */ ++ ++ /* Disable Device Interrupts */ ++ et131x_disable_interrupts(adapter); ++ ++ /* Get a copy of the value in the interrupt status register ++ * so we can process the interrupting section ++ */ ++ status.value = readl(&adapter->CSRAddress->global.int_status.value); ++ ++ if (adapter->FlowControl == TxOnly || ++ adapter->FlowControl == Both) { ++ status.value &= ~INT_MASK_ENABLE; ++ } else { ++ status.value &= ~INT_MASK_ENABLE_NO_FLOW; ++ } ++ ++ /* Make sure this is our interrupt */ ++ if (!status.value) { ++#ifdef CONFIG_ET131X_DEBUG ++ adapter->Stats.UnhandledInterruptsPerSec++; ++#endif ++ handled = false; ++ DBG_VERBOSE(et131x_dbginfo, "NOT OUR INTERRUPT\n"); ++ et131x_enable_interrupts(adapter); ++ goto out; ++ } ++ ++ /* This is our interrupt, so process accordingly */ ++#ifdef CONFIG_ET131X_DEBUG ++ if (status.bits.rxdma_xfr_done) { ++ adapter->Stats.RxDmaInterruptsPerSec++; ++ } ++ ++ if (status.bits.txdma_isr) { ++ adapter->Stats.TxDmaInterruptsPerSec++; ++ } ++#endif ++ ++ if (status.bits.watchdog_interrupt) { ++ PMP_TCB pMpTcb = adapter->TxRing.CurrSendHead; ++ ++ if (pMpTcb) { ++ if (++pMpTcb->PacketStaleCount > 1) { ++ status.bits.txdma_isr = 1; ++ } ++ } ++ ++ if (adapter->RxRing.UnfinishedReceives) { ++ status.bits.rxdma_xfr_done = 1; ++ } else if (pMpTcb == NULL) { ++ writel(0, &adapter->CSRAddress->global.watchdog_timer); ++ } ++ ++ status.bits.watchdog_interrupt = 0; ++#ifdef CONFIG_ET131X_DEBUG ++ adapter->Stats.WatchDogInterruptsPerSec++; ++#endif ++ } ++ ++ if (status.value == 0) { ++ /* This interrupt has in some way been "handled" by ++ * the ISR. Either it was a spurious Rx interrupt, or ++ * it was a Tx interrupt that has been filtered by ++ * the ISR. ++ */ ++ et131x_enable_interrupts(adapter); ++ goto out; ++ } ++ ++ /* We need to save the interrupt status value for use in our ++ * DPC. We will clear the software copy of that in that ++ * routine. ++ */ ++ adapter->Stats.InterruptStatus = status; ++ ++ /* Schedule the ISR handler as a bottom-half task in the ++ * kernel's tq_immediate queue, and mark the queue for ++ * execution ++ */ ++ schedule_work(&adapter->task); ++ ++out: ++ return IRQ_RETVAL(handled); ++} ++ ++/** ++ * et131x_isr_handler - The ISR handler ++ * @p_adapter, a pointer to the device's private adapter structure ++ * ++ * scheduled to run in a deferred context by the ISR. This is where the ISR's ++ * work actually gets done. ++ */ ++void et131x_isr_handler(struct work_struct *work) ++{ ++ struct et131x_adapter *pAdapter = ++ container_of(work, struct et131x_adapter, task); ++ INTERRUPT_t GlobStatus = pAdapter->Stats.InterruptStatus; ++ ADDRESS_MAP_t __iomem *iomem = pAdapter->CSRAddress; ++ ++ /* ++ * These first two are by far the most common. Once handled, we clear ++ * their two bits in the status word. If the word is now zero, we ++ * exit. ++ */ ++ /* Handle all the completed Transmit interrupts */ ++ if (GlobStatus.bits.txdma_isr) { ++ DBG_TX(et131x_dbginfo, "TXDMA_ISR interrupt\n"); ++ et131x_handle_send_interrupt(pAdapter); ++ } ++ ++ /* Handle all the completed Receives interrupts */ ++ if (GlobStatus.bits.rxdma_xfr_done) { ++ DBG_RX(et131x_dbginfo, "RXDMA_XFR_DONE interrupt\n"); ++ et131x_handle_recv_interrupt(pAdapter); ++ } ++ ++ GlobStatus.value &= 0xffffffd7; ++ ++ if (GlobStatus.value) { ++ /* Handle the TXDMA Error interrupt */ ++ if (GlobStatus.bits.txdma_err) { ++ TXDMA_ERROR_t TxDmaErr; ++ ++ /* Following read also clears the register (COR) */ ++ TxDmaErr.value = readl(&iomem->txdma.TxDmaError.value); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "TXDMA_ERR interrupt, error = %d\n", ++ TxDmaErr.value); ++ } ++ ++ /* Handle Free Buffer Ring 0 and 1 Low interrupt */ ++ if (GlobStatus.bits.rxdma_fb_ring0_low || ++ GlobStatus.bits.rxdma_fb_ring1_low) { ++ /* ++ * This indicates the number of unused buffers in ++ * RXDMA free buffer ring 0 is <= the limit you ++ * programmed. Free buffer resources need to be ++ * returned. Free buffers are consumed as packets ++ * are passed from the network to the host. The host ++ * becomes aware of the packets from the contents of ++ * the packet status ring. This ring is queried when ++ * the packet done interrupt occurs. Packets are then ++ * passed to the OS. When the OS is done with the ++ * packets the resources can be returned to the ++ * ET1310 for re-use. This interrupt is one method of ++ * returning resources. ++ */ ++ DBG_WARNING(et131x_dbginfo, ++ "RXDMA_FB_RING0_LOW or " ++ "RXDMA_FB_RING1_LOW interrupt\n"); ++ ++ /* If the user has flow control on, then we will ++ * send a pause packet, otherwise just exit ++ */ ++ if (pAdapter->FlowControl == TxOnly || ++ pAdapter->FlowControl == Both) { ++ PM_CSR_t pm_csr; ++ ++ /* Tell the device to send a pause packet via ++ * the back pressure register ++ */ ++ pm_csr.value = readl(&iomem->global.pm_csr.value); ++ if (pm_csr.bits.pm_phy_sw_coma == 0) { ++ TXMAC_BP_CTRL_t bp_ctrl = { 0 }; ++ ++ bp_ctrl.bits.bp_req = 1; ++ bp_ctrl.bits.bp_xonxoff = 1; ++ writel(bp_ctrl.value, ++ &iomem->txmac.bp_ctrl.value); ++ } ++ } ++ } ++ ++ /* Handle Packet Status Ring Low Interrupt */ ++ if (GlobStatus.bits.rxdma_pkt_stat_ring_low) { ++ DBG_WARNING(et131x_dbginfo, ++ "RXDMA_PKT_STAT_RING_LOW interrupt\n"); ++ ++ /* ++ * Same idea as with the two Free Buffer Rings. ++ * Packets going from the network to the host each ++ * consume a free buffer resource and a packet status ++ * resource. These resoures are passed to the OS. ++ * When the OS is done with the resources, they need ++ * to be returned to the ET1310. This is one method ++ * of returning the resources. ++ */ ++ } ++ ++ /* Handle RXDMA Error Interrupt */ ++ if (GlobStatus.bits.rxdma_err) { ++ /* ++ * The rxdma_error interrupt is sent when a time-out ++ * on a request issued by the JAGCore has occurred or ++ * a completion is returned with an un-successful ++ * status. In both cases the request is considered ++ * complete. The JAGCore will automatically re-try the ++ * request in question. Normally information on events ++ * like these are sent to the host using the "Advanced ++ * Error Reporting" capability. This interrupt is ++ * another way of getting similar information. The ++ * only thing required is to clear the interrupt by ++ * reading the ISR in the global resources. The ++ * JAGCore will do a re-try on the request. Normally ++ * you should never see this interrupt. If you start ++ * to see this interrupt occurring frequently then ++ * something bad has occurred. A reset might be the ++ * thing to do. ++ */ ++ // TRAP(); ++ ++ pAdapter->TxMacTest.value = ++ readl(&iomem->txmac.tx_test.value); ++ DBG_WARNING(et131x_dbginfo, ++ "RxDMA_ERR interrupt, error %x\n", ++ pAdapter->TxMacTest.value); ++ } ++ ++ /* Handle the Wake on LAN Event */ ++ if (GlobStatus.bits.wake_on_lan) { ++ /* ++ * This is a secondary interrupt for wake on LAN. ++ * The driver should never see this, if it does, ++ * something serious is wrong. We will TRAP the ++ * message when we are in DBG mode, otherwise we ++ * will ignore it. ++ */ ++ DBG_ERROR(et131x_dbginfo, "WAKE_ON_LAN interrupt\n"); ++ } ++ ++ /* Handle the PHY interrupt */ ++ if (GlobStatus.bits.phy_interrupt) { ++ PM_CSR_t pm_csr; ++ MI_BMSR_t BmsrInts, BmsrData; ++ MI_ISR_t myIsr; ++ ++ DBG_VERBOSE(et131x_dbginfo, "PHY interrupt\n"); ++ ++ /* If we are in coma mode when we get this interrupt, ++ * we need to disable it. ++ */ ++ pm_csr.value = readl(&iomem->global.pm_csr.value); ++ if (pm_csr.bits.pm_phy_sw_coma == 1) { ++ /* ++ * Check to see if we are in coma mode and if ++ * so, disable it because we will not be able ++ * to read PHY values until we are out. ++ */ ++ DBG_VERBOSE(et131x_dbginfo, ++ "Device is in COMA mode, " ++ "need to wake up\n"); ++ DisablePhyComa(pAdapter); ++ } ++ ++ /* Read the PHY ISR to clear the reason for the ++ * interrupt. ++ */ ++ MiRead(pAdapter, (uint8_t) offsetof(MI_REGS_t, isr), ++ &myIsr.value); ++ ++ if (!pAdapter->ReplicaPhyLoopbk) { ++ MiRead(pAdapter, ++ (uint8_t) offsetof(MI_REGS_t, bmsr), ++ &BmsrData.value); ++ ++ BmsrInts.value = ++ pAdapter->Bmsr.value ^ BmsrData.value; ++ pAdapter->Bmsr.value = BmsrData.value; ++ ++ DBG_VERBOSE(et131x_dbginfo, ++ "Bmsr.value = 0x%04x," ++ "Bmsr_ints.value = 0x%04x\n", ++ BmsrData.value, BmsrInts.value); ++ ++ /* Do all the cable in / cable out stuff */ ++ et131x_Mii_check(pAdapter, BmsrData, BmsrInts); ++ } ++ } ++ ++ /* Let's move on to the TxMac */ ++ if (GlobStatus.bits.txmac_interrupt) { ++ pAdapter->TxRing.TxMacErr.value = ++ readl(&iomem->txmac.err.value); ++ ++ /* ++ * When any of the errors occur and TXMAC generates ++ * an interrupt to report these errors, it usually ++ * means that TXMAC has detected an error in the data ++ * stream retrieved from the on-chip Tx Q. All of ++ * these errors are catastrophic and TXMAC won't be ++ * able to recover data when these errors occur. In ++ * a nutshell, the whole Tx path will have to be reset ++ * and re-configured afterwards. ++ */ ++ DBG_WARNING(et131x_dbginfo, ++ "TXMAC interrupt, error 0x%08x\n", ++ pAdapter->TxRing.TxMacErr.value); ++ ++ /* If we are debugging, we want to see this error, ++ * otherwise we just want the device to be reset and ++ * continue ++ */ ++ //DBG_TRAP(); ++ } ++ ++ /* Handle RXMAC Interrupt */ ++ if (GlobStatus.bits.rxmac_interrupt) { ++ /* ++ * These interrupts are catastrophic to the device, ++ * what we need to do is disable the interrupts and ++ * set the flag to cause us to reset so we can solve ++ * this issue. ++ */ ++ // MP_SET_FLAG( pAdapter, fMP_ADAPTER_HARDWARE_ERROR ); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "RXMAC interrupt, error 0x%08x. Requesting reset\n", ++ readl(&iomem->rxmac.err_reg.value)); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "Enable 0x%08x, Diag 0x%08x\n", ++ readl(&iomem->rxmac.ctrl.value), ++ readl(&iomem->rxmac.rxq_diag.value)); ++ ++ /* ++ * If we are debugging, we want to see this error, ++ * otherwise we just want the device to be reset and ++ * continue ++ */ ++ // TRAP(); ++ } ++ ++ /* Handle MAC_STAT Interrupt */ ++ if (GlobStatus.bits.mac_stat_interrupt) { ++ /* ++ * This means at least one of the un-masked counters ++ * in the MAC_STAT block has rolled over. Use this ++ * to maintain the top, software managed bits of the ++ * counter(s). ++ */ ++ DBG_VERBOSE(et131x_dbginfo, "MAC_STAT interrupt\n"); ++ HandleMacStatInterrupt(pAdapter); ++ } ++ ++ /* Handle SLV Timeout Interrupt */ ++ if (GlobStatus.bits.slv_timeout) { ++ /* ++ * This means a timeout has occured on a read or ++ * write request to one of the JAGCore registers. The ++ * Global Resources block has terminated the request ++ * and on a read request, returned a "fake" value. ++ * The most likely reasons are: Bad Address or the ++ * addressed module is in a power-down state and ++ * can't respond. ++ */ ++ DBG_VERBOSE(et131x_dbginfo, "SLV_TIMEOUT interrupt\n"); ++ } ++ } ++ ++ if (pAdapter->PoMgmt.PowerState == NdisDeviceStateD0) { ++ et131x_enable_interrupts(pAdapter); ++ } ++} +diff --git a/drivers/staging/et131x/et131x_isr.h b/drivers/staging/et131x/et131x_isr.h +new file mode 100644 +index 0000000..76a51d5 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_isr.h +@@ -0,0 +1,65 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_isr.h - Defines, structs, enums, prototypes, etc. pertaining to the ++ * ISR processing code. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_ISR_H__ ++#define __ET131X_ISR_H__ ++ ++irqreturn_t et131x_isr(int irq, void *dev_id); ++void et131x_isr_handler(struct work_struct *work); ++ ++#endif /* __ET131X_ISR_H__ */ +diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c +new file mode 100644 +index 0000000..de65972 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_netdev.c +@@ -0,0 +1,856 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_netdev.c - Routines and data required by all Linux network devices. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include "et131x_version.h" ++#include "et131x_debug.h" ++#include "et131x_defs.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "et1310_phy.h" ++#include "et1310_pm.h" ++#include "et1310_jagcore.h" ++#include "et1310_mac.h" ++#include "et1310_tx.h" ++ ++#include "et131x_adapter.h" ++#include "et131x_isr.h" ++#include "et131x_initpci.h" ++ ++/* Data for debugging facilities */ ++#ifdef CONFIG_ET131X_DEBUG ++extern dbg_info_t *et131x_dbginfo; ++#endif /* CONFIG_ET131X_DEBUG */ ++ ++struct net_device_stats *et131x_stats(struct net_device *netdev); ++int et131x_open(struct net_device *netdev); ++int et131x_close(struct net_device *netdev); ++int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd); ++void et131x_multicast(struct net_device *netdev); ++int et131x_tx(struct sk_buff *skb, struct net_device *netdev); ++void et131x_tx_timeout(struct net_device *netdev); ++int et131x_change_mtu(struct net_device *netdev, int new_mtu); ++int et131x_set_mac_addr(struct net_device *netdev, void *new_mac); ++void et131x_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); ++void et131x_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); ++void et131x_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); ++ ++/** ++ * et131x_device_alloc ++ * ++ * Returns pointer to the allocated and initialized net_device struct for ++ * this device. ++ * ++ * Create instances of net_device and wl_private for the new adapter and ++ * register the device's entry points in the net_device structure. ++ */ ++struct net_device *et131x_device_alloc(void) ++{ ++ struct net_device *netdev; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Alloc net_device and adapter structs */ ++ netdev = alloc_etherdev(sizeof(struct et131x_adapter)); ++ ++ if (netdev == NULL) { ++ DBG_ERROR(et131x_dbginfo, ++ "Alloc of net_device struct failed\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return NULL; ++ } ++ ++ /* Setup the function registration table (and other data) for a ++ * net_device ++ */ ++ //netdev->init = &et131x_init; ++ //netdev->set_config = &et131x_config; ++ netdev->get_stats = &et131x_stats; ++ netdev->open = &et131x_open; ++ netdev->stop = &et131x_close; ++ netdev->do_ioctl = &et131x_ioctl; ++ netdev->set_multicast_list = &et131x_multicast; ++ netdev->hard_start_xmit = &et131x_tx; ++ netdev->tx_timeout = &et131x_tx_timeout; ++ netdev->watchdog_timeo = ET131X_TX_TIMEOUT; ++ netdev->change_mtu = &et131x_change_mtu; ++ netdev->set_mac_address = &et131x_set_mac_addr; ++ ++ //netdev->ethtool_ops = &et131x_ethtool_ops; ++ ++ // Poll? ++ //netdev->poll = &et131x_poll; ++ //netdev->poll_controller = &et131x_poll_controller; ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return netdev; ++} ++ ++/** ++ * et131x_stats - Return the current device statistics. ++ * @netdev: device whose stats are being queried ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++struct net_device_stats *et131x_stats(struct net_device *netdev) ++{ ++ struct et131x_adapter *adapter = netdev_priv(netdev); ++ struct net_device_stats *stats = &adapter->net_stats; ++ CE_STATS_t *devstat = &adapter->Stats; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ stats->rx_packets = devstat->ipackets; ++ stats->tx_packets = devstat->opackets; ++ stats->rx_errors = devstat->length_err + devstat->alignment_err + ++ devstat->crc_err + devstat->code_violations + devstat->other_errors; ++ stats->tx_errors = devstat->max_pkt_error; ++ stats->multicast = devstat->multircv; ++ stats->collisions = devstat->collisions; ++ ++ stats->rx_length_errors = devstat->length_err; ++ stats->rx_over_errors = devstat->rx_ov_flow; ++ stats->rx_crc_errors = devstat->crc_err; ++ ++ // NOTE: These stats don't have corresponding values in CE_STATS, so we're ++ // going to have to update these directly from within the TX/RX code ++ //stats->rx_bytes = 20; //devstat->; ++ //stats->tx_bytes = 20; //devstat->; ++ //stats->rx_dropped = devstat->; ++ //stats->tx_dropped = devstat->; ++ ++ // NOTE: Not used, can't find analogous statistics ++ //stats->rx_frame_errors = devstat->; ++ //stats->rx_fifo_errors = devstat->; ++ //stats->rx_missed_errors = devstat->; ++ ++ //stats->tx_aborted_errors = devstat->; ++ //stats->tx_carrier_errors = devstat->; ++ //stats->tx_fifo_errors = devstat->; ++ //stats->tx_heartbeat_errors = devstat->; ++ //stats->tx_window_errors = devstat->; ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return stats; ++} ++ ++/** ++ * et131x_open - Open the device for use. ++ * @netdev: device to be opened ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_open(struct net_device *netdev) ++{ ++ int result = 0; ++ struct et131x_adapter *adapter = netdev_priv(netdev); ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Start the timer to track NIC errors */ ++ add_timer(&adapter->ErrorTimer); ++ ++ /* Register our ISR */ ++ DBG_TRACE(et131x_dbginfo, "Registering ISR...\n"); ++ ++ result = ++ request_irq(netdev->irq, et131x_isr, IRQF_SHARED, netdev->name, ++ netdev); ++ if (result) { ++ DBG_ERROR(et131x_dbginfo, "Could not register ISR\n"); ++ DBG_LEAVE(et131x_dbginfo); ++ return result; ++ } ++ ++ /* Enable the Tx and Rx DMA engines (if not already enabled) */ ++ et131x_rx_dma_enable(adapter); ++ et131x_tx_dma_enable(adapter); ++ ++ /* Enable device interrupts */ ++ et131x_enable_interrupts(adapter); ++ ++ MP_SET_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE); ++ ++ /* We're ready to move some data, so start the queue */ ++ netif_start_queue(netdev); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return result; ++} ++ ++/** ++ * et131x_close - Close the device ++ * @netdev: device to be closed ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_close(struct net_device *netdev) ++{ ++ struct et131x_adapter *adapter = netdev_priv(netdev); ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* First thing is to stop the queue */ ++ netif_stop_queue(netdev); ++ ++ /* Stop the Tx and Rx DMA engines */ ++ et131x_rx_dma_disable(adapter); ++ et131x_tx_dma_disable(adapter); ++ ++ /* Disable device interrupts */ ++ et131x_disable_interrupts(adapter); ++ ++ /* Deregistering ISR */ ++ MP_CLEAR_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE); ++ ++ DBG_TRACE(et131x_dbginfo, "Deregistering ISR...\n"); ++ free_irq(netdev->irq, netdev); ++ ++ /* Stop the error timer */ ++ del_timer_sync(&adapter->ErrorTimer); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return 0; ++} ++ ++/** ++ * et131x_ioctl_mii - The function which handles MII IOCTLs ++ * @netdev: device on which the query is being made ++ * @reqbuf: the request-specific data buffer ++ * @cmd: the command request code ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_ioctl_mii(struct net_device *netdev, struct ifreq *reqbuf, int cmd) ++{ ++ int status = 0; ++ struct et131x_adapter *pAdapter = netdev_priv(netdev); ++ struct mii_ioctl_data *data = if_mii(reqbuf); ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ switch (cmd) { ++ case SIOCGMIIPHY: ++ DBG_VERBOSE(et131x_dbginfo, "SIOCGMIIPHY\n"); ++ data->phy_id = pAdapter->Stats.xcvr_addr; ++ break; ++ ++ case SIOCGMIIREG: ++ DBG_VERBOSE(et131x_dbginfo, "SIOCGMIIREG\n"); ++ if (!capable(CAP_NET_ADMIN)) { ++ status = -EPERM; ++ } else { ++ status = MiRead(pAdapter, ++ data->reg_num, &data->val_out); ++ } ++ break; ++ ++ case SIOCSMIIREG: ++ DBG_VERBOSE(et131x_dbginfo, "SIOCSMIIREG\n"); ++ if (!capable(CAP_NET_ADMIN)) { ++ status = -EPERM; ++ } else { ++ status = MiWrite(pAdapter, data->reg_num, ++ data->val_in); ++ } ++ break; ++ ++ default: ++ status = -EOPNOTSUPP; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_ioctl - The I/O Control handler for the driver ++ * @netdev: device on which the control request is being made ++ * @reqbuf: a pointer to the IOCTL request buffer ++ * @cmd: the IOCTL command code ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd) ++{ ++ int status = 0; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ switch (cmd) { ++ case SIOCGMIIPHY: ++ case SIOCGMIIREG: ++ case SIOCSMIIREG: ++ status = et131x_ioctl_mii(netdev, reqbuf, cmd); ++ break; ++ ++ default: ++ DBG_WARNING(et131x_dbginfo, "Unhandled IOCTL Code: 0x%04x\n", ++ cmd); ++ status = -EOPNOTSUPP; ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_set_packet_filter - Configures the Rx Packet filtering on the device ++ * @adapter: pointer to our private adapter structure ++ * ++ * Returns 0 on success, errno on failure ++ */ ++int et131x_set_packet_filter(struct et131x_adapter *adapter) ++{ ++ int status = 0; ++ uint32_t filter = adapter->PacketFilter; ++ RXMAC_CTRL_t ctrl; ++ RXMAC_PF_CTRL_t pf_ctrl; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ ctrl.value = readl(&adapter->CSRAddress->rxmac.ctrl.value); ++ pf_ctrl.value = readl(&adapter->CSRAddress->rxmac.pf_ctrl.value); ++ ++ /* Default to disabled packet filtering. Enable it in the individual ++ * case statements that require the device to filter something ++ */ ++ ctrl.bits.pkt_filter_disable = 1; ++ ++ /* Set us to be in promiscuous mode so we receive everything, this ++ * is also true when we get a packet filter of 0 ++ */ ++ if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) { ++ pf_ctrl.bits.filter_broad_en = 0; ++ pf_ctrl.bits.filter_multi_en = 0; ++ pf_ctrl.bits.filter_uni_en = 0; ++ } else { ++ /* ++ * Set us up with Multicast packet filtering. Three cases are ++ * possible - (1) we have a multi-cast list, (2) we receive ALL ++ * multicast entries or (3) we receive none. ++ */ ++ if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) { ++ DBG_VERBOSE(et131x_dbginfo, ++ "Multicast filtering OFF (Rx ALL MULTICAST)\n"); ++ pf_ctrl.bits.filter_multi_en = 0; ++ } else { ++ DBG_VERBOSE(et131x_dbginfo, "Multicast filtering ON\n"); ++ SetupDeviceForMulticast(adapter); ++ pf_ctrl.bits.filter_multi_en = 1; ++ ctrl.bits.pkt_filter_disable = 0; ++ } ++ ++ /* Set us up with Unicast packet filtering */ ++ if (filter & ET131X_PACKET_TYPE_DIRECTED) { ++ DBG_VERBOSE(et131x_dbginfo, "Unicast Filtering ON\n"); ++ SetupDeviceForUnicast(adapter); ++ pf_ctrl.bits.filter_uni_en = 1; ++ ctrl.bits.pkt_filter_disable = 0; ++ } ++ ++ /* Set us up with Broadcast packet filtering */ ++ if (filter & ET131X_PACKET_TYPE_BROADCAST) { ++ DBG_VERBOSE(et131x_dbginfo, "Broadcast Filtering ON\n"); ++ pf_ctrl.bits.filter_broad_en = 1; ++ ctrl.bits.pkt_filter_disable = 0; ++ } else { ++ DBG_VERBOSE(et131x_dbginfo, ++ "Broadcast Filtering OFF\n"); ++ pf_ctrl.bits.filter_broad_en = 0; ++ } ++ ++ /* Setup the receive mac configuration registers - Packet ++ * Filter control + the enable / disable for packet filter ++ * in the control reg. ++ */ ++ writel(pf_ctrl.value, ++ &adapter->CSRAddress->rxmac.pf_ctrl.value); ++ writel(ctrl.value, &adapter->CSRAddress->rxmac.ctrl.value); ++ } ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_multicast - The handler to configure multicasting on the interface ++ * @netdev: a pointer to a net_device struct representing the device ++ */ ++void et131x_multicast(struct net_device *netdev) ++{ ++ struct et131x_adapter *adapter = netdev_priv(netdev); ++ uint32_t PacketFilter = 0; ++ uint32_t count; ++ unsigned long lockflags; ++ struct dev_mc_list *mclist = netdev->mc_list; ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ spin_lock_irqsave(&adapter->Lock, lockflags); ++ ++ /* Before we modify the platform-independent filter flags, store them ++ * locally. This allows us to determine if anything's changed and if ++ * we even need to bother the hardware ++ */ ++ PacketFilter = adapter->PacketFilter; ++ ++ /* Clear the 'multicast' flag locally; becuase we only have a single ++ * flag to check multicast, and multiple multicast addresses can be ++ * set, this is the easiest way to determine if more than one ++ * multicast address is being set. ++ */ ++ PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; ++ ++ /* Check the net_device flags and set the device independent flags ++ * accordingly ++ */ ++ DBG_VERBOSE(et131x_dbginfo, ++ "MULTICAST ADDR COUNT: %d\n", netdev->mc_count); ++ ++ if (netdev->flags & IFF_PROMISC) { ++ DBG_VERBOSE(et131x_dbginfo, "Request: PROMISCUOUS MODE ON\n"); ++ adapter->PacketFilter |= ET131X_PACKET_TYPE_PROMISCUOUS; ++ } else { ++ DBG_VERBOSE(et131x_dbginfo, "Request: PROMISCUOUS MODE OFF\n"); ++ adapter->PacketFilter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; ++ } ++ ++ if (netdev->flags & IFF_ALLMULTI) { ++ DBG_VERBOSE(et131x_dbginfo, "Request: ACCEPT ALL MULTICAST\n"); ++ adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; ++ } ++ ++ if (netdev->mc_count > NIC_MAX_MCAST_LIST) { ++ DBG_WARNING(et131x_dbginfo, ++ "ACCEPT ALL MULTICAST for now, as there's more Multicast " ++ "addresses than the HW supports\n"); ++ ++ adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; ++ } ++ ++ if (netdev->mc_count < 1) { ++ DBG_VERBOSE(et131x_dbginfo, "Request: REJECT ALL MULTICAST\n"); ++ adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; ++ adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; ++ } else { ++ DBG_VERBOSE(et131x_dbginfo, ++ "Request: SET MULTICAST FILTER(S)\n"); ++ adapter->PacketFilter |= ET131X_PACKET_TYPE_MULTICAST; ++ } ++ ++ /* Set values in the private adapter struct */ ++ adapter->MCAddressCount = netdev->mc_count; ++ ++ if (netdev->mc_count) { ++ if (mclist->dmi_addrlen != ETH_ALEN) { ++ DBG_WARNING(et131x_dbginfo, ++ "Multicast addrs are not ETH_ALEN in size\n"); ++ } else { ++ count = netdev->mc_count - 1; ++ memcpy(adapter->MCList[count], mclist->dmi_addr, ++ ETH_ALEN); ++ } ++ } ++ ++ /* Are the new flags different from the previous ones? If not, then no ++ * action is required ++ * ++ * NOTE - This block will always update the MCList with the hardware, ++ * even if the addresses aren't the same. ++ */ ++ if (PacketFilter != adapter->PacketFilter) { ++ /* Call the device's filter function */ ++ DBG_VERBOSE(et131x_dbginfo, "UPDATE REQUIRED, FLAGS changed\n"); ++ ++ et131x_set_packet_filter(adapter); ++ } else { ++ DBG_VERBOSE(et131x_dbginfo, ++ "NO UPDATE REQUIRED, FLAGS didn't change\n"); ++ } ++ ++ spin_unlock_irqrestore(&adapter->Lock, lockflags); ++ ++ DBG_LEAVE(et131x_dbginfo); ++} ++ ++/** ++ * et131x_tx - The handler to tx a packet on the device ++ * @skb: data to be Tx'd ++ * @netdev: device on which data is to be Tx'd ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_tx(struct sk_buff *skb, struct net_device *netdev) ++{ ++ int status = 0; ++ ++ DBG_TX_ENTER(et131x_dbginfo); ++ ++ /* Save the timestamp for the TX timeout watchdog */ ++ netdev->trans_start = jiffies; ++ ++ /* Call the device-specific data Tx routine */ ++ status = et131x_send_packets(skb, netdev); ++ ++ /* Check status and manage the netif queue if necessary */ ++ if (status != 0) { ++ if (status == -ENOMEM) { ++ DBG_VERBOSE(et131x_dbginfo, ++ "OUT OF TCBs; STOP NETIF QUEUE\n"); ++ ++ /* Put the queue to sleep until resources are ++ * available ++ */ ++ netif_stop_queue(netdev); ++ status = 1; ++ } else { ++ DBG_WARNING(et131x_dbginfo, ++ "Misc error; drop packet\n"); ++ status = 0; ++ } ++ } ++ ++ DBG_TX_LEAVE(et131x_dbginfo); ++ return status; ++} ++ ++/** ++ * et131x_tx_timeout - Timeout handler ++ * @netdev: a pointer to a net_device struct representing the device ++ * ++ * The handler called when a Tx request times out. The timeout period is ++ * specified by the 'tx_timeo" element in the net_device structure (see ++ * et131x_alloc_device() to see how this value is set). ++ */ ++void et131x_tx_timeout(struct net_device *netdev) ++{ ++ struct et131x_adapter *pAdapter = netdev_priv(netdev); ++ PMP_TCB pMpTcb; ++ unsigned long lockflags; ++ ++ DBG_WARNING(et131x_dbginfo, "TX TIMEOUT\n"); ++ ++ /* Just skip this part if the adapter is doing link detection */ ++ if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION)) { ++ DBG_ERROR(et131x_dbginfo, "Still doing link detection\n"); ++ return; ++ } ++ ++ /* Any nonrecoverable hardware error? ++ * Checks adapter->flags for any failure in phy reading ++ */ ++ if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_NON_RECOVER_ERROR)) { ++ DBG_WARNING(et131x_dbginfo, "Non recoverable error - remove\n"); ++ return; ++ } ++ ++ /* Hardware failure? */ ++ if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_HARDWARE_ERROR)) { ++ DBG_WARNING(et131x_dbginfo, "hardware error - reset\n"); ++ return; ++ } ++ ++ /* Is send stuck? */ ++ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); ++ ++ pMpTcb = pAdapter->TxRing.CurrSendHead; ++ ++ if (pMpTcb != NULL) { ++ pMpTcb->Count++; ++ ++ if (pMpTcb->Count > NIC_SEND_HANG_THRESHOLD) { ++#ifdef CONFIG_ET131X_DEBUG ++ TX_STATUS_BLOCK_t txDmaComplete = ++ *(pAdapter->TxRing.pTxStatusVa); ++ PTX_DESC_ENTRY_t pDesc = ++ pAdapter->TxRing.pTxDescRingVa + ++ pMpTcb->WrIndex.bits.val; ++#endif ++ TX_DESC_ENTRY_t StuckDescriptors[10]; ++ ++ if (pMpTcb->WrIndex.bits.val > 7) { ++ memcpy(StuckDescriptors, ++ pAdapter->TxRing.pTxDescRingVa + ++ pMpTcb->WrIndex.bits.val - 6, ++ sizeof(TX_DESC_ENTRY_t) * 10); ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, ++ lockflags); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "Send stuck - reset. pMpTcb->WrIndex %x, Flags 0x%08x\n", ++ pMpTcb->WrIndex.bits.val, ++ pMpTcb->Flags); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "pDesc 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", ++ pDesc->DataBufferPtrHigh, ++ pDesc->DataBufferPtrLow, pDesc->word2.value, ++ pDesc->word3.value); ++ ++ DBG_WARNING(et131x_dbginfo, ++ "WbStatus 0x%08x\n", txDmaComplete.value); ++ ++#ifdef CONFIG_ET131X_DEBUG ++ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 0); ++ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 1); ++ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 3); ++ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 5); ++#endif ++ et131x_close(netdev); ++ et131x_open(netdev); ++ ++ return; ++ } ++ } ++ ++ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); ++} ++ ++/** ++ * et131x_change_mtu - The handler called to change the MTU for the device ++ * @netdev: device whose MTU is to be changed ++ * @new_mtu: the desired MTU ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ */ ++int et131x_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ int result = 0; ++ struct et131x_adapter *adapter = netdev_priv(netdev); ++ ++ DBG_ENTER(et131x_dbginfo); ++ ++ /* Make sure the requested MTU is valid */ ++ if (new_mtu == 0 || new_mtu > 9216) { ++ DBG_LEAVE(et131x_dbginfo); ++ return -EINVAL; ++ } ++ ++ /* Stop the netif queue */ ++ netif_stop_queue(netdev); ++ ++ /* Stop the Tx and Rx DMA engines */ ++ et131x_rx_dma_disable(adapter); ++ et131x_tx_dma_disable(adapter); ++ ++ /* Disable device interrupts */ ++ et131x_disable_interrupts(adapter); ++ et131x_handle_send_interrupt(adapter); ++ et131x_handle_recv_interrupt(adapter); ++ ++ /* Set the new MTU */ ++ netdev->mtu = new_mtu; ++ ++ /* Free Rx DMA memory */ ++ et131x_adapter_memory_free(adapter); ++ ++ /* Set the config parameter for Jumbo Packet support */ ++ adapter->RegistryJumboPacket = new_mtu + 14; ++ et131x_soft_reset(adapter); ++ ++ /* Alloc and init Rx DMA memory */ ++ result = et131x_adapter_memory_alloc(adapter); ++ if (result != 0) { ++ DBG_WARNING(et131x_dbginfo, ++ "Change MTU failed; couldn't re-alloc DMA memory\n"); ++ return result; ++ } ++ ++ et131x_init_send(adapter); ++ ++ et131x_setup_hardware_properties(adapter); ++ memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN); ++ ++ /* Init the device with the new settings */ ++ et131x_adapter_setup(adapter); ++ ++ /* Enable interrupts */ ++ if (MP_TEST_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE)) { ++ et131x_enable_interrupts(adapter); ++ } ++ ++ /* Restart the Tx and Rx DMA engines */ ++ et131x_rx_dma_enable(adapter); ++ et131x_tx_dma_enable(adapter); ++ ++ /* Restart the netif queue */ ++ netif_wake_queue(netdev); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return result; ++} ++ ++/** ++ * et131x_set_mac_addr - handler to change the MAC address for the device ++ * @netdev: device whose MAC is to be changed ++ * @new_mac: the desired MAC address ++ * ++ * Returns 0 on success, errno on failure (as defined in errno.h) ++ * ++ * IMPLEMENTED BY : blux http://berndlux.de 22.01.2007 21:14 ++ */ ++int et131x_set_mac_addr(struct net_device *netdev, void *new_mac) ++{ ++ int result = 0; ++ struct et131x_adapter *adapter = netdev_priv(netdev); ++ struct sockaddr *address = new_mac; ++ ++ DBG_ENTER(et131x_dbginfo); ++ // begin blux ++ // DBG_VERBOSE( et131x_dbginfo, "Function not implemented!!\n" ); ++ ++ if (adapter == NULL) { ++ DBG_LEAVE(et131x_dbginfo); ++ return -ENODEV; ++ } ++ ++ /* Make sure the requested MAC is valid */ ++ if (!is_valid_ether_addr(address->sa_data)) { ++ DBG_LEAVE(et131x_dbginfo); ++ return -EINVAL; ++ } ++ ++ /* Stop the netif queue */ ++ netif_stop_queue(netdev); ++ ++ /* Stop the Tx and Rx DMA engines */ ++ et131x_rx_dma_disable(adapter); ++ et131x_tx_dma_disable(adapter); ++ ++ /* Disable device interrupts */ ++ et131x_disable_interrupts(adapter); ++ et131x_handle_send_interrupt(adapter); ++ et131x_handle_recv_interrupt(adapter); ++ ++ /* Set the new MAC */ ++ // netdev->set_mac_address = &new_mac; ++ // netdev->mtu = new_mtu; ++ ++ memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len); ++ ++ printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", ++ netdev->name, netdev->dev_addr[0], netdev->dev_addr[1], ++ netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4], ++ netdev->dev_addr[5]); ++ ++ /* Free Rx DMA memory */ ++ et131x_adapter_memory_free(adapter); ++ ++ /* Set the config parameter for Jumbo Packet support */ ++ // adapter->RegistryJumboPacket = new_mtu + 14; ++ // blux: not needet here, w'll change the MAC ++ ++ et131x_soft_reset(adapter); ++ ++ /* Alloc and init Rx DMA memory */ ++ result = et131x_adapter_memory_alloc(adapter); ++ if (result != 0) { ++ DBG_WARNING(et131x_dbginfo, ++ "Change MAC failed; couldn't re-alloc DMA memory\n"); ++ return result; ++ } ++ ++ et131x_init_send(adapter); ++ ++ et131x_setup_hardware_properties(adapter); ++ // memcpy( netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN ); ++ // blux: no, do not override our nice address ++ ++ /* Init the device with the new settings */ ++ et131x_adapter_setup(adapter); ++ ++ /* Enable interrupts */ ++ if (MP_TEST_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE)) { ++ et131x_enable_interrupts(adapter); ++ } ++ ++ /* Restart the Tx and Rx DMA engines */ ++ et131x_rx_dma_enable(adapter); ++ et131x_tx_dma_enable(adapter); ++ ++ /* Restart the netif queue */ ++ netif_wake_queue(netdev); ++ ++ DBG_LEAVE(et131x_dbginfo); ++ return result; ++} +diff --git a/drivers/staging/et131x/et131x_netdev.h b/drivers/staging/et131x/et131x_netdev.h +new file mode 100644 +index 0000000..b8acd14 +--- /dev/null ++++ b/drivers/staging/et131x/et131x_netdev.h +@@ -0,0 +1,64 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_netdev.h - Defines, structs, enums, prototypes, etc. related to the ++ * driver's net_device support. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_NETDEV_H__ ++#define __ET131X_NETDEV_H__ ++ ++struct net_device *et131x_device_alloc(void); ++ ++#endif /* __ET131X_NETDEV_H__ */ +diff --git a/drivers/staging/et131x/et131x_version.h b/drivers/staging/et131x/et131x_version.h +new file mode 100644 +index 0000000..2ea645e +--- /dev/null ++++ b/drivers/staging/et131x/et131x_version.h +@@ -0,0 +1,81 @@ ++/* ++ * Agere Systems Inc. ++ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * http://www.agere.com ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * et131x_version.h - This file provides system and device version information. ++ * ++ *------------------------------------------------------------------------------ ++ * ++ * SOFTWARE LICENSE ++ * ++ * This software is provided subject to the following terms and conditions, ++ * which you should read carefully before using the software. Using this ++ * software indicates your acceptance of these terms and conditions. If you do ++ * not agree with these terms and conditions, do not use the software. ++ * ++ * Copyright © 2005 Agere Systems Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source or binary forms, with or without ++ * modifications, are permitted provided that the following conditions are met: ++ * ++ * . Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following Disclaimer as comments in the code as ++ * well as in the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * . Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following Disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * . Neither the name of Agere Systems Inc. nor the names of the contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * Disclaimer ++ * ++ * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY ++ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN ++ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#ifndef __ET131X_VERSION_H__ ++#define __ET131X_VERSION_H__ ++ ++#define DRIVER_AUTHOR "Victor Soriano (vjsoriano@agere.com)" ++#define DRIVER_LICENSE "Dual BSD/GPL" ++#define DRIVER_DEVICE_STRING "ET1310" ++#define DRIVER_NAME "et131x" ++#define DRIVER_MAJOR_VERSION 1 ++#define DRIVER_MINOR_VERSION 2 ++#define DRIVER_PATCH_VERSION 3 ++#define DRIVER_VERSION_STRING "1.2.3" ++#define DRIVER_VENDOR "Agere Systems, http://www.agere.com" ++#define DRIVER_DESC "10/100/1000 Base-T Ethernet Driver" ++ ++#define STRUCT_MODULE "net" /* blux: missed by the kernel */ ++ ++#define DRIVER_INFO DRIVER_DESC " for the "\ ++ DRIVER_DEVICE_STRING ", v" \ ++ DRIVER_VERSION_STRING " by " \ ++ DRIVER_VENDOR ++ ++#define DRIVER_NAME_EXT "et131x.ko" ++ ++#endif /* __ET131X_VERSION_H__ */ +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0006-Staging-add-Alacritech-slicoss-network-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0006-Staging-add-Alacritech-slicoss-network-driver.patch new file mode 100644 index 000000000..b44c8deb3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0006-Staging-add-Alacritech-slicoss-network-driver.patch @@ -0,0 +1,30963 @@ +From 4d6f6af8d6e76443f298ac030b0fc4fe84bdbd6a Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 19 Mar 2008 14:27:25 -0700 +Subject: [PATCH 06/23] Staging: add Alacritech slicoss network driver +Patch-mainline: 2.6.28 + +This adds the Alacritech slicoss driver to the tree. + +This driver is supposed to support: + + Mojave cards (single port PCI Gigabit) both copper and fiber + Oasis cards (single and dual port PCI-x Gigabit) copper and fiber + Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber + +The driver was acutally tested on Oasis and Kalahari cards. + +TODO: + - move firmware loading to request_firmware() + - remove direct memory access of structures + - any remaining sparse and checkpatch.pl warnings + - any netdev recommended changes + +Many thanks to Lior Dotan for help with the cleanup +of this driver. + +Cc: Lior Dotan +Cc: Christopher Harrer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/slicoss/Kconfig | 14 + + drivers/staging/slicoss/Makefile | 1 + + drivers/staging/slicoss/README | 19 + + drivers/staging/slicoss/gbdownload.h | 8215 ++++++++++++++++++++++++++++ + drivers/staging/slicoss/gbrcvucode.h | 239 + + drivers/staging/slicoss/oasisdbgdownload.h | 6850 +++++++++++++++++++++++ + drivers/staging/slicoss/oasisdownload.h | 6848 +++++++++++++++++++++++ + drivers/staging/slicoss/oasisrcvucode.h | 205 + + drivers/staging/slicoss/slic.h | 603 ++ + drivers/staging/slicoss/slic_os.h | 163 + + drivers/staging/slicoss/slicbuild.h | 97 + + drivers/staging/slicoss/slicdbg.h | 101 + + drivers/staging/slicoss/slicdump.h | 279 + + drivers/staging/slicoss/slichw.h | 850 +++ + drivers/staging/slicoss/slicinc.h | 221 + + drivers/staging/slicoss/slicoss.c | 6074 ++++++++++++++++++++ + 18 files changed, 30782 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/slicoss/Kconfig + create mode 100644 drivers/staging/slicoss/Makefile + create mode 100644 drivers/staging/slicoss/README + create mode 100644 drivers/staging/slicoss/gbdownload.h + create mode 100644 drivers/staging/slicoss/gbrcvucode.h + create mode 100644 drivers/staging/slicoss/oasisdbgdownload.h + create mode 100644 drivers/staging/slicoss/oasisdownload.h + create mode 100644 drivers/staging/slicoss/oasisrcvucode.h + create mode 100644 drivers/staging/slicoss/slic.h + create mode 100644 drivers/staging/slicoss/slic_os.h + create mode 100644 drivers/staging/slicoss/slicbuild.h + create mode 100644 drivers/staging/slicoss/slicdbg.h + create mode 100644 drivers/staging/slicoss/slicdump.h + create mode 100644 drivers/staging/slicoss/slichw.h + create mode 100644 drivers/staging/slicoss/slicinc.h + create mode 100644 drivers/staging/slicoss/slicoss.c + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 4c3789d..e18aecc 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -25,4 +25,6 @@ if STAGING + + source "drivers/staging/et131x/Kconfig" + ++source "drivers/staging/slicoss/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 933b984..e5e4a0e 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -1,3 +1,4 @@ + # Makefile for staging directory + + obj-$(CONFIG_ET131X) += et131x/ ++obj-$(CONFIG_SLICOSS) += slicoss/ +diff --git a/drivers/staging/slicoss/Kconfig b/drivers/staging/slicoss/Kconfig +new file mode 100644 +index 0000000..d2993d3 +--- /dev/null ++++ b/drivers/staging/slicoss/Kconfig +@@ -0,0 +1,14 @@ ++config SLICOSS ++ tristate "Alacritech Gigabit IS-NIC support" ++ depends on PCI && X86 && NETDEV_1000 ++ default n ++ help ++ This driver supports Alacritech's IS-NIC gigabit ethernet cards. ++ ++ This includes the following devices: ++ Mojave cards (single port PCI Gigabit) both copper and fiber ++ Oasis cards (single and dual port PCI-x Gigabit) copper and fiber ++ Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber ++ ++ To compile this driver as a module, choose M here: the module ++ will be called slicoss. +diff --git a/drivers/staging/slicoss/Makefile b/drivers/staging/slicoss/Makefile +new file mode 100644 +index 0000000..7bc9e9b +--- /dev/null ++++ b/drivers/staging/slicoss/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_SLICOSS) += slicoss.o +diff --git a/drivers/staging/slicoss/README b/drivers/staging/slicoss/README +new file mode 100644 +index 0000000..2d5b112 +--- /dev/null ++++ b/drivers/staging/slicoss/README +@@ -0,0 +1,19 @@ ++This driver is supposed to support: ++ ++ Mojave cards (single port PCI Gigabit) both copper and fiber ++ Oasis cards (single and dual port PCI-x Gigabit) copper and fiber ++ Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber ++ ++The driver was actually tested on Oasis and Kalahari cards. ++ ++TODO: ++ - move firmware loading to request_firmware() ++ - remove direct memory access of structures ++ - any remaining sparse and checkpatch.pl warnings ++ - any netdev recommended changes ++ ++Please send patches to: ++ Greg Kroah-Hartman ++and Cc: Lior Dotan and Christopher Harrer ++ as well as they are also able to test out any ++changes. +diff --git a/drivers/staging/slicoss/gbdownload.h b/drivers/staging/slicoss/gbdownload.h +new file mode 100644 +index 0000000..0350fb9 +--- /dev/null ++++ b/drivers/staging/slicoss/gbdownload.h +@@ -0,0 +1,8215 @@ ++#define MOJAVE_UCODE_VERS_STRING "$Revision: 1.2 $" ++#define MOJAVE_UCODE_VERS_DATE "$Date: 2006/03/27 15:12:22 $" ++#define MOJAVE_UCODE_HOSTIF_ID 3 ++ ++static LONG MNumSections = 0x2; ++static ULONG MSectionSize[] = ++{ ++ 0x00008000, 0x00010000, ++}; ++ ++static ULONG MSectionStart[] = ++{ ++ 0x00000000, 0x00008000, ++}; ++ ++static u8 MojaveUCode[2][65536] = ++{ ++ { ++ 0x12, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x98, 0xb0, 0x01, 0x00, 0x04, 0x80, 0xa2, 0x40, 0xfd, 0x7f, 0x00, 0x00, ++ 0x09, 0x00, 0xa2, 0x49, 0xdd, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x80, 0xb2, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xd1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x80, 0xb2, 0x01, 0x00, 0x09, 0x00, 0xa2, 0x40, ++ 0x75, 0x7d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x0b, 0x00, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x11, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x80, 0x1f, 0xe9, 0x18, 0x31, 0x00, 0x00, 0x00, 0x00, 0x41, 0xe9, ++ 0x80, 0xb2, 0x01, 0x00, 0x0f, 0x00, 0x40, 0xe9, 0x80, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x16, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x16, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x0f, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x1c, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x11, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x01, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x22, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x22, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x0e, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xdd, 0x81, 0x01, 0x00, 0x2b, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x3c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x27, 0x00, 0x14, 0xbc, ++ 0x80, 0x32, 0x00, 0x00, 0x14, 0x01, 0x13, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x54, 0x95, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0xff, 0xff, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0xb7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xb5, 0xb3, 0x01, 0x00, ++ 0xd9, 0x00, 0x00, 0x40, 0xb3, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xb6, 0xd3, 0x01, 0x00, 0x32, 0x00, 0x95, 0xe8, 0x80, 0x32, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0xe8, 0x80, 0x88, 0x01, 0x00, 0xb8, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xff, 0xb3, 0x01, 0x00, 0x3c, 0x00, 0x22, 0x50, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xfd, 0x93, 0x01, 0x00, ++ 0xa5, 0xa5, 0x00, 0xa6, 0xb4, 0xa7, 0x01, 0x00, 0x3c, 0x00, 0xa2, 0x50, ++ 0xb5, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x3c, 0x00, 0xa2, 0x45, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0xfd, 0x93, 0x01, 0x00, 0x41, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x7f, 0x00, 0x00, 0x20, 0xf5, 0xcf, 0x01, 0x00, 0x1c, 0x01, 0x00, 0xfa, ++ 0xb3, 0x33, 0x01, 0x00, 0xa5, 0xa5, 0x00, 0xda, 0xb5, 0xab, 0x01, 0x00, ++ 0x99, 0x00, 0xa2, 0x50, 0xb5, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xfd, 0x93, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x44, 0xb3, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xd7, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0xda, 0xed, 0x8b, 0x01, 0x00, ++ 0xd5, 0x00, 0x00, 0x46, 0xb3, 0x33, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xd7, 0xb1, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xda, 0xef, 0x8b, 0x01, 0x00, 0xff, 0x00, 0x00, 0xda, ++ 0xe3, 0x8f, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x48, 0xb3, 0x33, 0x01, 0x00, ++ 0x3c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0xff, 0x00, 0x00, 0xda, ++ 0xd7, 0x8d, 0x01, 0x00, 0xff, 0xff, 0x00, 0xda, 0xf1, 0xdb, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xda, 0xe9, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xe9, 0xe3, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x4b, 0xb3, 0x33, 0x01, 0x00, ++ 0x2c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xd7, 0xb1, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x4c, 0xb3, 0x33, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0xda, 0xeb, 0xdb, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x4e, ++ 0xb3, 0x33, 0x01, 0x00, 0x03, 0x00, 0x00, 0xda, 0x81, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x81, 0xe0, 0x01, 0x00, 0xff, 0xff, 0x00, 0xda, ++ 0xb5, 0xdb, 0x01, 0x00, 0x5c, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0xda, 0xb5, 0xcf, 0x01, 0x00, 0x00, 0xf0, 0x00, 0xa7, ++ 0xb4, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0x81, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd8, 0xb1, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x50, ++ 0xb3, 0x33, 0x01, 0x00, 0xff, 0xff, 0x00, 0xda, 0xb5, 0x8b, 0x01, 0x00, ++ 0x62, 0x00, 0x26, 0x4c, 0xb5, 0x63, 0x00, 0x00, 0x01, 0x00, 0x00, 0xda, ++ 0xb5, 0xcf, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xdf, 0xb1, 0x01, 0x00, ++ 0xd5, 0x00, 0x00, 0x52, 0xb3, 0x33, 0x01, 0x00, 0xff, 0x00, 0x00, 0xda, ++ 0x4b, 0x89, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, 0xdf, 0xf7, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xef, 0xdf, 0x8b, 0x01, 0x00, 0x69, 0x00, 0x22, 0x40, ++ 0xdf, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xfd, 0x93, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xda, 0xd7, 0xe5, 0x01, 0x00, 0xf8, 0x00, 0x00, 0xda, ++ 0xb3, 0x8b, 0x01, 0x00, 0x34, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd9, 0xd7, 0xb1, 0x01, 0x00, 0x02, 0x00, 0x00, 0xd9, ++ 0xd5, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xd7, 0xb1, 0x01, 0x00, ++ 0x22, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb5, 0xf3, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0xda, 0x7b, 0x89, 0x01, 0x00, 0x00, 0x01, 0x00, 0x40, ++ 0xdd, 0x9b, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x5d, 0xb3, 0x33, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0xda, 0xe7, 0x8b, 0x01, 0x00, 0x8a, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xfd, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xe7, 0xe3, 0x01, 0x00, 0x00, 0x01, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xe7, 0x97, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0xd7, 0xb1, 0x01, 0x00, 0xd5, 0x00, 0x00, 0x5e, ++ 0xb3, 0x33, 0x01, 0x00, 0xff, 0x00, 0x00, 0xda, 0xe5, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xe5, 0xe3, 0x01, 0x00, 0x08, 0x01, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0xff, 0x00, 0x00, 0xda, 0xb5, 0x8f, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf7, 0xb5, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xd7, 0xb1, 0x01, 0x00, 0x3c, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0xe5, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0xd7, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, 0xdd, 0x9b, 0x01, 0x00, ++ 0x96, 0x00, 0x22, 0xf5, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, 0xd5, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf6, 0xeb, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf5, ++ 0xd7, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x00, 0xea, 0xd4, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf7, 0xe3, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf1, ++ 0xd7, 0xb1, 0x01, 0x00, 0x3c, 0x00, 0x00, 0xee, 0xdd, 0xcb, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xee, 0xd5, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xe9, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf4, 0xd7, 0xb1, 0x01, 0x00, ++ 0xd5, 0x00, 0x00, 0x4a, 0xb3, 0x33, 0x01, 0x00, 0xff, 0xff, 0x00, 0xda, ++ 0xdd, 0x89, 0x01, 0x00, 0xb7, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x05, 0x00, 0x00, 0xa6, ++ 0xd6, 0xb1, 0x01, 0x00, 0x9a, 0x13, 0x00, 0xeb, 0xd6, 0x99, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x02, 0x00, 0xa6, ++ 0xd6, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x00, 0xeb, 0xd6, 0x99, 0x01, 0x00, ++ 0x2c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x05, 0x00, 0x00, 0xa6, ++ 0xd6, 0xb1, 0x01, 0x00, 0x9a, 0x13, 0x00, 0xeb, 0xd6, 0x99, 0x01, 0x00, ++ 0x3c, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, ++ 0xd7, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfd, 0x93, 0x01, 0x00, ++ 0x3c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa6, ++ 0xd6, 0xb1, 0x01, 0x00, 0x00, 0x01, 0x00, 0xeb, 0xd6, 0x99, 0x01, 0x00, ++ 0x00, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x06, 0x00, 0x00, 0xa6, ++ 0xd6, 0xb1, 0x01, 0x00, 0x9a, 0x13, 0x00, 0xeb, 0xd6, 0x99, 0x01, 0x00, ++ 0x08, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x02, 0x00, 0xa6, ++ 0xd6, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x00, 0xeb, 0xd6, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xdf, 0xb1, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa6, 0xd6, 0xb1, 0x01, 0x00, 0x64, 0x00, 0x00, 0x40, ++ 0x4b, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7b, 0x99, 0x01, 0x00, ++ 0x02, 0x04, 0x00, 0x40, 0xdd, 0x99, 0x01, 0x00, 0xb7, 0x00, 0x13, 0xbc, ++ 0x80, 0x32, 0x00, 0x00, 0x02, 0x08, 0x00, 0x40, 0xdd, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0xdd, 0x91, 0x01, 0x00, 0xb8, 0x00, 0x95, 0xe8, ++ 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xe9, 0xfa, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd1, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0x42, ++ 0x80, 0x88, 0x01, 0x00, 0x34, 0x00, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0xb8, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x02, 0x80, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0xb8, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x81, 0xb0, 0x01, 0x00, 0xca, 0x00, 0x09, 0xf9, 0x81, 0x32, 0x00, 0x00, ++ 0xc8, 0x00, 0x08, 0xf9, 0x81, 0x32, 0x00, 0x00, 0xd4, 0x00, 0x1f, 0xfd, ++ 0xf9, 0x33, 0x00, 0x00, 0xc7, 0x00, 0x9e, 0xfd, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, ++ 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x19, 0xb1, 0x01, 0x00, 0xcf, 0x00, 0x0a, 0xf9, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x40, 0xfb, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0xfd, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x07, 0x80, 0xf9, 0xf3, 0x8f, 0x01, 0x00, ++ 0x00, 0x07, 0x42, 0xf9, 0xf3, 0x8f, 0x01, 0x00, 0xd3, 0x00, 0xa2, 0xff, ++ 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0xff, 0xfb, 0xef, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfc, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0xd8, 0x00, 0x06, 0xfe, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xb3, 0xe3, 0x01, 0x00, 0x1c, 0x01, 0x00, 0xfa, 0xb3, 0xc3, 0x00, 0x00, ++ 0xda, 0x00, 0x00, 0x42, 0x8d, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xeb, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x84, 0x96, 0x80, 0xb2, 0x00, 0x00, ++ 0x26, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x25, 0x01, 0x00, 0x40, ++ 0x2d, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2d, 0x81, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xb5, 0xeb, 0x01, 0x00, 0xe4, 0x00, 0x84, 0x96, ++ 0x80, 0x32, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x40, 0xb5, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xb5, 0x83, 0x01, 0x00, 0xde, 0x00, 0xa2, 0x41, ++ 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x2d, 0x81, 0x01, 0x00, ++ 0x26, 0x01, 0x00, 0x41, 0x2d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xb3, 0xc3, 0x01, 0x00, 0xda, 0x00, 0xa2, 0x41, 0x8d, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0xda, 0xb5, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x81, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd9, 0xb9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xb8, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xb9, 0xeb, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xb8, 0x97, 0x01, 0x00, 0x15, 0x00, 0x00, 0xdc, ++ 0xb9, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2d, 0x81, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xdb, 0x81, 0xb0, 0x01, 0x00, 0x27, 0x01, 0x00, 0x42, ++ 0x2d, 0x11, 0x01, 0x00, 0x25, 0x01, 0x00, 0x40, 0x2d, 0x11, 0x01, 0x00, ++ 0x28, 0x01, 0x00, 0x40, 0x2d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x2d, 0x91, 0x01, 0x00, 0x26, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x25, 0x01, 0x00, 0x40, 0x2d, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x2d, 0x81, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, 0x81, 0xd0, 0x00, 0x00, ++ 0x00, 0x00, 0x84, 0x96, 0x80, 0x32, 0x01, 0x00, 0xff, 0x00, 0xa0, 0xdc, ++ 0xb9, 0x6b, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x41, 0x2d, 0x91, 0x00, 0x00, ++ 0xf8, 0x00, 0x00, 0x41, 0x2d, 0x81, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x40, ++ 0xb3, 0x33, 0x01, 0x00, 0x00, 0x00, 0x90, 0xda, 0x8b, 0xb0, 0x00, 0x00, ++ 0x11, 0x00, 0x00, 0x45, 0x88, 0xf4, 0x01, 0x00, 0x40, 0x00, 0x00, 0x44, ++ 0x80, 0xce, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0xa3, 0x44, 0x89, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x89, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x87, 0xb0, 0x01, 0x00, ++ 0xd9, 0x00, 0x00, 0x43, 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xb5, 0xf3, 0x01, 0x00, 0x0c, 0x01, 0xa0, 0xda, 0x8b, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x87, 0xc0, 0x01, 0x00, 0x08, 0x01, 0xa2, 0x41, 0x89, 0x50, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x45, 0x88, 0x88, 0x01, 0x00, 0x10, 0x00, 0x00, 0x45, ++ 0x8a, 0xf4, 0x01, 0x00, 0x12, 0x01, 0x90, 0x44, 0x8a, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc0, 0x01, 0x00, 0xff, 0xff, 0x00, 0x45, ++ 0x8a, 0xa8, 0x01, 0x00, 0x00, 0x00, 0x80, 0x50, 0x8b, 0xe0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x40, 0xf9, 0x9b, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x40, ++ 0xb3, 0xcf, 0x01, 0x00, 0x1c, 0x01, 0x00, 0xfc, 0x19, 0x31, 0x01, 0x00, ++ 0x1c, 0x01, 0x40, 0xda, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x41, 0xda, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf9, 0xc3, 0x01, 0x00, ++ 0x16, 0x01, 0x9f, 0xda, 0x81, 0x32, 0x00, 0x00, 0x02, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x91, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd9, 0x2b, 0xb1, 0x01, 0x00, 0x1e, 0x01, 0x9f, 0x94, ++ 0x80, 0x32, 0x00, 0x00, 0x18, 0x00, 0x00, 0x94, 0x92, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xb5, 0xf3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xb4, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xb3, 0xc3, 0x01, 0x00, ++ 0x1d, 0x01, 0xa2, 0x41, 0x91, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x2b, 0xb1, 0x01, 0x00, 0x29, 0x01, 0x00, 0x51, 0x93, 0xb0, 0x00, 0x00, ++ 0x29, 0x01, 0x00, 0x4d, 0x93, 0xb0, 0x00, 0x00, 0x29, 0x01, 0x00, 0x49, ++ 0x93, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x93, 0xb0, 0x01, 0x00, ++ 0x29, 0x01, 0xa2, 0x41, 0x93, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x11, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x12, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x13, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x14, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x15, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x16, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x17, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x18, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x19, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x1d, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xa1, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x19, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x15, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x09, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x07, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x01, 0xb0, 0x01, 0x00, 0x44, 0x01, 0x20, 0x48, 0xa1, 0x51, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x50, 0x01, 0x22, 0x4b, ++ 0x74, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x60, 0x00, 0x00, 0x4b, 0x60, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, ++ 0x7e, 0xb1, 0x01, 0x00, 0x51, 0x01, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x4e, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x80, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, 0x07, 0x90, 0x01, 0x00, ++ 0xf3, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xa5, 0xb3, 0x01, 0x00, 0xaf, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x07, 0x90, 0x01, 0x00, 0xf3, 0x9f, 0x00, 0x40, 0xbf, 0xb3, 0x00, 0x00, ++ 0x5f, 0x01, 0x22, 0xcc, 0x85, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, ++ 0x07, 0x90, 0x01, 0x00, 0xf3, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, ++ 0xa3, 0xc9, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, 0xa1, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xe1, 0xb1, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, 0x68, 0x01, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x85, 0x93, 0x01, 0x00, ++ 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xba, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xa4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xbc, 0xb3, 0x01, 0x00, 0x00, 0x14, 0x2f, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe7, 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, ++ 0xa9, 0xb3, 0x01, 0x00, 0xff, 0x00, 0x00, 0xdd, 0x81, 0x88, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x40, 0x80, 0xf4, 0x01, 0x00, 0x78, 0x01, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x88, 0x01, 0x00, 0xdd, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, 0x89, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x8b, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x8f, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x91, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd2, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x55, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe1, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x80, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf1, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf2, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x77, 0x01, 0x00, 0x41, 0x81, 0xc0, 0x1a, 0x00, ++ 0x5a, 0x01, 0x51, 0x40, 0x81, 0xb2, 0x1a, 0x00, 0x5a, 0x01, 0x52, 0x40, ++ 0x81, 0xb2, 0x1a, 0x00, 0x5a, 0x01, 0x55, 0x40, 0x81, 0xb2, 0x1a, 0x00, ++ 0x5a, 0x01, 0x56, 0x40, 0x81, 0xb2, 0x1a, 0x00, 0x55, 0x01, 0x91, 0x81, ++ 0x80, 0x30, 0x1a, 0x00, 0x5a, 0x01, 0x45, 0x40, 0x81, 0xb2, 0x1a, 0x00, ++ 0x55, 0x01, 0x91, 0x82, 0x80, 0x30, 0x1a, 0x00, 0x5a, 0x01, 0x46, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x89, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x14, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0xb5, 0x01, 0x22, 0xde, 0xe1, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x81, 0xc0, 0x01, 0x00, 0x94, 0x01, 0xa2, 0x44, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x49, 0xd1, 0x01, 0x00, 0x9c, 0x01, 0x22, 0x40, ++ 0xe1, 0x6d, 0x00, 0x00, 0x98, 0x01, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x55, 0x01, 0x00, 0x41, 0xbf, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xbf, 0xb3, 0x01, 0x00, 0x55, 0x01, 0xa0, 0x0f, 0xbd, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xde, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x49, 0xc1, 0x01, 0x00, 0xb7, 0x01, 0x00, 0x40, 0x19, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x42, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, 0x19, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x42, 0xff, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x49, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0xff, 0xe1, 0xb1, 0x01, 0x00, 0x08, 0x14, 0x00, 0xa4, ++ 0x80, 0xcc, 0x01, 0x00, 0xac, 0x01, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x85, 0xc0, 0x01, 0x00, 0xaa, 0x01, 0xa2, 0x4c, ++ 0x81, 0x50, 0x00, 0x00, 0xb6, 0x01, 0x22, 0xd2, 0x81, 0x32, 0x00, 0x00, ++ 0xb1, 0x01, 0x22, 0x41, 0xa5, 0x6f, 0x00, 0x00, 0x55, 0x01, 0xa2, 0xe0, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xc1, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x89, 0x90, 0x01, 0x00, 0x00, 0x00, 0x40, 0x42, ++ 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0x43, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x88, 0x94, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x44, ++ 0xe0, 0xb1, 0x00, 0x00, 0xb3, 0x01, 0x00, 0x48, 0x49, 0xc1, 0x00, 0x00, ++ 0xb1, 0x01, 0x00, 0x5b, 0x89, 0x90, 0x00, 0x00, 0xb0, 0x9f, 0x00, 0xa0, ++ 0x9e, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xcb, 0x83, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xba, 0x01, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xc4, 0x01, 0x91, 0x82, 0x82, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x8a, 0x80, 0xb0, 0x01, 0x00, 0xb6, 0x9f, 0x00, 0x40, ++ 0x80, 0xce, 0x01, 0x00, 0xc3, 0x01, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xc4, 0x01, 0x56, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, ++ 0x6f, 0x93, 0x01, 0x00, 0xf3, 0x9f, 0x00, 0x52, 0x6f, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4d, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xcd, 0x83, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xc7, 0x01, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xd1, 0x01, 0x91, 0x81, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, ++ 0x80, 0xb0, 0x01, 0x00, 0xb6, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0xd0, 0x01, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xd1, 0x01, 0x55, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6f, 0x93, 0x01, 0x00, ++ 0xf3, 0x9f, 0x00, 0x53, 0x6f, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x14, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x23, 0x40, 0x81, 0xb0, 0x01, 0x00, 0xda, 0x01, 0x22, 0xde, ++ 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x49, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0xd5, 0x01, 0xa2, 0x44, ++ 0x81, 0x6c, 0x00, 0x00, 0x55, 0x01, 0x00, 0x43, 0xbf, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x40, 0xf8, ++ 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0xf0, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x40, 0xe1, 0xb1, 0x00, 0x00, ++ 0xe2, 0x01, 0x00, 0x40, 0x91, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2e, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x05, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, 0x08, 0x00, 0x00, 0xdd, ++ 0x81, 0xf4, 0x01, 0x00, 0xe7, 0x01, 0x00, 0x40, 0x80, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, 0xed, 0x01, 0x00, 0x40, ++ 0x81, 0xb0, 0x00, 0x00, 0x58, 0x01, 0x00, 0xde, 0xa1, 0xb3, 0x00, 0x00, ++ 0xff, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x01, 0x02, 0x00, 0x40, ++ 0x81, 0xb0, 0x00, 0x00, 0x07, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x57, 0x01, 0x00, 0xdf, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, 0xa1, 0xb1, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xd2, 0xa5, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, ++ 0xc1, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, ++ 0xf7, 0x01, 0x22, 0x44, 0xc1, 0x53, 0x00, 0x00, 0xf6, 0x01, 0x84, 0x41, ++ 0x81, 0x40, 0x00, 0x00, 0xfa, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0x45, 0xb1, 0x01, 0x00, 0xf1, 0x01, 0x00, 0x41, ++ 0xa1, 0xc1, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x5a, 0x01, 0x00, 0xdd, ++ 0xa1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, 0xb1, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x40, 0x00, 0x00, 0xd3, 0xa7, 0xcb, 0x01, 0x00, ++ 0xc5, 0x02, 0x00, 0xe0, 0xa5, 0xb3, 0x00, 0x00, 0x03, 0x00, 0x00, 0x40, ++ 0xa3, 0x9b, 0x01, 0x00, 0x58, 0x01, 0x00, 0xde, 0xa1, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xbf, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0x81, 0x90, 0x01, 0x00, 0x55, 0x01, 0xa2, 0xba, 0x80, 0x04, 0x00, 0x00, ++ 0x60, 0x00, 0x00, 0xde, 0x61, 0x99, 0x01, 0x00, 0x04, 0x02, 0xa8, 0xb1, ++ 0x80, 0x30, 0x00, 0x00, 0x57, 0x01, 0x00, 0x40, 0xe0, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xba, 0xb3, 0x01, 0x00, 0x68, 0x02, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0x5d, 0x02, 0x00, 0x4d, 0x83, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xe1, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xe3, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe5, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xe9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xeb, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf5, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf9, 0xb3, 0x01, 0x00, 0x15, 0x02, 0x22, 0x40, 0x8f, 0x6f, 0x00, 0x00, ++ 0x75, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x5d, 0x02, 0x00, 0xc7, ++ 0x83, 0x30, 0x01, 0x00, 0x7d, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x5d, 0x02, 0x00, 0x42, 0x83, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe8, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe9, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xea, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xeb, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x85, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xec, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xed, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xf0, 0xb1, 0x01, 0x00, ++ 0xe0, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xab, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xba, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbb, ++ 0xf0, 0xb1, 0x01, 0x00, 0x29, 0x02, 0xb8, 0x40, 0x81, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0x90, 0x01, 0x00, 0x2b, 0x02, 0xb9, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0x90, 0x01, 0x00, ++ 0x2d, 0x02, 0xba, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x81, 0x90, 0x01, 0x00, 0x2f, 0x02, 0xbb, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x81, 0x90, 0x01, 0x00, 0x31, 0x02, 0xbc, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x81, 0x90, 0x01, 0x00, ++ 0x33, 0x02, 0xbd, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x81, 0x90, 0x01, 0x00, 0x35, 0x02, 0xbe, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x81, 0x90, 0x01, 0x00, 0x37, 0x02, 0xbf, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x81, 0x90, 0x01, 0x00, ++ 0x39, 0x02, 0xc8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x81, 0x90, 0x01, 0x00, 0x3b, 0x02, 0xc9, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0x81, 0x90, 0x01, 0x00, 0x3d, 0x02, 0xca, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x81, 0x90, 0x01, 0x00, ++ 0x3f, 0x02, 0xcb, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x81, 0x90, 0x01, 0x00, 0x41, 0x02, 0xcc, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x81, 0x90, 0x01, 0x00, 0x43, 0x02, 0xcd, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x81, 0x90, 0x01, 0x00, ++ 0x45, 0x02, 0xce, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x81, 0x90, 0x01, 0x00, 0x47, 0x02, 0xcf, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x81, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, ++ 0xaf, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc5, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x14, 0x2e, 0x06, 0xa5, 0xb3, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0xd3, 0xa7, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf4, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xeb, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf1, 0xb1, 0x01, 0x00, ++ 0xf7, 0x01, 0x00, 0xc7, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x63, 0x02, 0x00, 0x48, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x51, 0x40, 0x1a, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x60, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x5c, 0x02, 0x49, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x52, 0x40, 0x1c, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x4e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x65, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x5c, 0x02, 0x4a, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, ++ 0x9e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd8, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa1, 0xd0, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, ++ 0xd2, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xd4, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xd6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, ++ 0xdc, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xde, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x88, 0xda, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, ++ 0x8e, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xe6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xac, 0xec, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x99, ++ 0xfa, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe0, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xe2, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xe4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe8, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xea, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xf4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xf6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xf8, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc7, ++ 0xa9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xb1, 0x01, 0x00, ++ 0x81, 0x02, 0x00, 0x40, 0x91, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0x85, 0x02, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, ++ 0x8a, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x95, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x95, 0x02, 0x00, 0x46, 0xa3, 0xb3, 0x00, 0x00, ++ 0x98, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x9e, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8c, 0x02, 0x23, 0x50, 0xa5, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xa5, 0xb3, 0x01, 0x00, 0xbc, 0x02, 0x00, 0x42, ++ 0xa5, 0x63, 0x01, 0x00, 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, 0xa1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x00, 0xb0, 0x01, 0x00, 0x94, 0x02, 0x22, 0x44, ++ 0xa5, 0x53, 0x00, 0x00, 0x91, 0x02, 0x00, 0x41, 0xa1, 0xc1, 0x00, 0x00, ++ 0x5a, 0x01, 0x00, 0xdd, 0xa1, 0xb1, 0x00, 0x00, 0xbc, 0x02, 0x00, 0xde, ++ 0xa1, 0x33, 0x01, 0x00, 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x5a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xbf, 0xb3, 0x01, 0x00, 0x55, 0x01, 0xa2, 0xd2, 0x77, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0x63, 0xb1, 0x01, 0x00, 0x9b, 0x02, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x5a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x54, ++ 0xa5, 0x33, 0x01, 0x00, 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xd0, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xd2, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0xd4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xd6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0xb1, 0x01, 0x00, ++ 0xa9, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x5d, 0x02, 0x00, 0x46, ++ 0x83, 0x30, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa0, 0x9e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe8, ++ 0x43, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x45, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xea, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xeb, ++ 0xa1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe7, 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, ++ 0xa9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd1, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, ++ 0x62, 0xdd, 0x01, 0x00, 0xb9, 0x02, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0xcc, 0x85, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe7, ++ 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xa9, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, ++ 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x46, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xb1, 0x01, 0x00, ++ 0xb8, 0x02, 0x00, 0xd4, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xcc, ++ 0x85, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xb0, 0x01, 0x00, ++ 0xc7, 0x02, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0xc6, 0x02, 0xa2, 0xf2, ++ 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcc, 0x85, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb0, 0x01, 0x00, 0xcb, 0x02, 0x80, 0xa5, ++ 0x80, 0x32, 0x00, 0x00, 0xcc, 0x02, 0x00, 0xa5, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0xcd, 0x02, 0x80, 0xa5, ++ 0x80, 0x32, 0x00, 0x00, 0x80, 0x01, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xd6, 0x02, 0x20, 0x4f, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0xd6, 0x02, 0x20, 0x4b, 0x81, 0x6c, 0x00, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0xd6, 0x02, 0x20, 0x47, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x03, 0x90, 0x00, 0x41, ++ 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x14, 0x2f, 0x4c, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xda, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0xa5, 0x80, 0xc8, 0x01, 0x00, 0xdd, 0x02, 0xa2, 0xa5, ++ 0x80, 0x6c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x90, 0x20, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, 0xe0, 0x02, 0x1f, 0x91, ++ 0x80, 0x32, 0x00, 0x00, 0x30, 0x00, 0x00, 0x90, 0x20, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, 0xe3, 0x02, 0x1f, 0x91, ++ 0x80, 0x32, 0x00, 0x00, 0x70, 0x00, 0x00, 0x90, 0x20, 0xa9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, 0xe6, 0x02, 0x1f, 0x91, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, ++ 0xe8, 0x02, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, 0x40, 0x68, 0x00, 0x90, ++ 0x20, 0xa9, 0x01, 0x00, 0xe0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x21, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x22, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x23, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x24, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x25, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x26, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x27, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x02, 0x01, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, 0x04, 0x03, 0x00, 0x40, ++ 0x80, 0x98, 0x01, 0x00, 0x06, 0x05, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x08, 0x07, 0x00, 0x41, 0x82, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xe0, 0xb1, 0x01, 0x00, ++ 0x30, 0x03, 0x00, 0x40, 0x85, 0x30, 0x01, 0x00, 0x39, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd8, 0x14, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xff, 0x02, 0xa2, 0xf8, 0x80, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x22, 0xf0, ++ 0x82, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x21, 0x91, 0x01, 0x00, ++ 0xd0, 0x14, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x30, 0x03, 0x00, 0x0c, ++ 0x85, 0x30, 0x01, 0x00, 0x30, 0x03, 0x00, 0x4d, 0x85, 0x10, 0x01, 0x00, ++ 0x30, 0x03, 0x00, 0x4e, 0x85, 0x10, 0x01, 0x00, 0xd0, 0x14, 0x20, 0x4f, ++ 0xe1, 0xb1, 0x01, 0x00, 0x30, 0x03, 0x00, 0x4f, 0x85, 0x10, 0x01, 0x00, ++ 0x39, 0x03, 0x00, 0x0c, 0x85, 0x30, 0x01, 0x00, 0xd8, 0x14, 0x20, 0x43, ++ 0x81, 0xb0, 0x01, 0x00, 0x0f, 0x03, 0x22, 0xf0, 0x9e, 0x6e, 0x00, 0x00, ++ 0x39, 0x03, 0x00, 0x4d, 0x85, 0x10, 0x01, 0x00, 0xd8, 0x14, 0x20, 0x42, ++ 0x81, 0xb0, 0x01, 0x00, 0x0f, 0x03, 0x22, 0xf0, 0x9e, 0x6e, 0x00, 0x00, ++ 0x39, 0x03, 0x00, 0x4e, 0x85, 0x10, 0x01, 0x00, 0xd8, 0x14, 0x20, 0x41, ++ 0x81, 0xb0, 0x01, 0x00, 0x11, 0x03, 0xa2, 0xf0, 0x9e, 0x6e, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0x81, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x20, 0x95, 0x01, 0x00, 0x03, 0x00, 0x00, 0x90, 0x20, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x21, 0x95, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x89, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x30, 0x03, 0x00, 0x17, 0x85, 0x30, 0x01, 0x00, 0x30, 0x03, 0x00, 0x58, ++ 0x85, 0x10, 0x01, 0x00, 0x30, 0x03, 0x00, 0x59, 0x85, 0x10, 0x01, 0x00, ++ 0xd0, 0x14, 0x20, 0x4f, 0xe1, 0xb1, 0x01, 0x00, 0x30, 0x03, 0x00, 0x5a, ++ 0x85, 0x10, 0x01, 0x00, 0x39, 0x03, 0x00, 0x17, 0x85, 0x30, 0x01, 0x00, ++ 0xd8, 0x14, 0x20, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x23, 0x03, 0x22, 0xf0, ++ 0x9e, 0x6e, 0x00, 0x00, 0x39, 0x03, 0x00, 0x58, 0x85, 0x10, 0x01, 0x00, ++ 0xd8, 0x14, 0x20, 0x41, 0x81, 0xb0, 0x01, 0x00, 0x23, 0x03, 0x22, 0xf0, ++ 0x9e, 0x6e, 0x00, 0x00, 0x39, 0x03, 0x00, 0x59, 0x85, 0x10, 0x01, 0x00, ++ 0xd8, 0x14, 0x20, 0x42, 0x81, 0xb0, 0x01, 0x00, 0x27, 0x03, 0xa2, 0xf0, ++ 0x9e, 0x6e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x90, 0x20, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x20, 0x95, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x88, 0xe0, 0x01, 0x00, ++ 0x2f, 0x03, 0xa2, 0x42, 0x21, 0x7d, 0x00, 0x00, 0xa5, 0xa5, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0xd0, 0x14, 0x20, 0x40, 0xe0, 0xb1, 0x01, 0x00, ++ 0x30, 0x03, 0x00, 0x44, 0x84, 0x30, 0x01, 0x00, 0x39, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd8, 0x14, 0x20, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x2f, 0x03, 0xa2, 0xf0, 0x80, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x89, 0xe0, 0x01, 0x00, 0xe0, 0x00, 0x80, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x70, 0x15, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0xd0, 0x14, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x87, 0xb4, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x70, 0x15, 0x00, 0x43, 0x62, 0x99, 0x01, 0x00, 0x36, 0x03, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x41, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x70, 0x15, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xf1, 0xb1, 0x01, 0x00, 0xd8, 0x14, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x87, 0xb4, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x70, 0x15, 0x00, 0x43, 0x62, 0x99, 0x01, 0x00, 0x3f, 0x03, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x87, 0xb0, 0x01, 0x00, ++ 0x42, 0x03, 0xa2, 0x41, 0x87, 0x50, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xf2, ++ 0x86, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0xf1, 0x86, 0xf4, 0x01, 0x00, ++ 0x41, 0x03, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x84, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x48, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x8f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x62, 0xb1, 0x01, 0x00, 0x49, 0x03, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xf5, 0x9f, 0x00, 0x47, 0x98, 0x30, 0x01, 0x00, ++ 0x00, 0x08, 0x00, 0x47, 0x8e, 0xc8, 0x01, 0x00, 0x47, 0x03, 0x00, 0x5c, ++ 0x8f, 0x80, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x58, 0x15, 0x2d, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2d, 0xf0, ++ 0x88, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x8a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x81, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x45, ++ 0x82, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x8b, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x82, 0x94, 0x01, 0x00, 0x20, 0x00, 0x00, 0x41, 0x60, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x8d, 0xc0, 0x01, 0x00, 0x64, 0x03, 0x22, 0x5f, ++ 0x8d, 0x6c, 0x00, 0x00, 0x55, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x53, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0x85, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x43, ++ 0x86, 0xd8, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x41, 0x85, 0x50, 0x01, 0x00, ++ 0x60, 0x03, 0x00, 0x41, 0x83, 0xe0, 0x00, 0x00, 0x5e, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0x85, 0xe0, 0x01, 0x00, ++ 0xd0, 0x14, 0x2f, 0x46, 0x84, 0x94, 0x01, 0x00, 0x20, 0x00, 0x00, 0x42, ++ 0x60, 0x99, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x07, 0x00, 0x00, 0x45, ++ 0x80, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x8b, 0xf0, 0x01, 0x00, ++ 0x00, 0x04, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0x6f, 0x03, 0xa0, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0x6d, 0x03, 0x00, 0x41, 0x82, 0xe8, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x41, 0x8e, 0xc0, 0x01, 0x00, 0xae, 0x03, 0x00, 0x40, ++ 0xa3, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x81, 0xb0, 0x01, 0x00, ++ 0x60, 0x15, 0x00, 0x40, 0x85, 0x98, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0x40, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x41, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x41, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x40, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0xa3, 0x55, 0x81, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa3, 0xc1, 0x01, 0x00, 0x73, 0x03, 0x00, 0x50, 0x85, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x7e, 0x03, 0xa2, 0x41, ++ 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0x44, 0x82, 0xf4, 0x01, 0x00, 0x1a, 0x15, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x70, 0x15, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x08, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x16, 0x00, 0x40, 0xe1, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x70, 0x15, 0x00, 0x43, ++ 0x62, 0x99, 0x01, 0x00, 0x88, 0x03, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x8a, 0x03, 0x22, 0x5a, 0x73, 0x7d, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x8b, 0x03, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, ++ 0x00, 0x08, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, 0x83, 0x03, 0xa2, 0x41, ++ 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf7, 0x0f, 0x00, 0xbc, ++ 0x80, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ }, ++ { ++ 0x31, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x34, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x35, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0x80, 0x81, 0x80, ++ 0x80, 0x32, 0x00, 0x00, 0xe6, 0x89, 0xa2, 0x40, 0x91, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x90, 0xb3, 0x01, 0x00, 0x5c, 0x95, 0x2e, 0xa2, ++ 0x80, 0xb0, 0x01, 0x00, 0xff, 0x00, 0x00, 0x80, 0xf4, 0x89, 0x01, 0x00, ++ 0x90, 0x95, 0x2a, 0xc8, 0xe5, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd3, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x44, 0xb1, 0x01, 0x00, 0x18, 0x80, 0x11, 0x81, ++ 0x98, 0x30, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x1a, 0x80, 0x11, 0x82, 0x98, 0x30, 0x00, 0x00, 0x00, 0x00, 0x52, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xe6, 0x89, 0x00, 0x48, 0xfd, 0x93, 0x00, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x23, 0x80, 0xa2, 0x42, ++ 0xfd, 0x7f, 0x00, 0x00, 0x20, 0x80, 0x00, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x22, 0x80, 0x11, 0x81, 0x82, 0x30, 0x00, 0x00, 0x22, 0x80, 0x51, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x22, 0x80, 0x11, 0x82, 0x82, 0x30, 0x00, 0x00, ++ 0x22, 0x80, 0x52, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2c, 0x80, 0x00, 0x48, ++ 0xfd, 0x93, 0x00, 0x00, 0x27, 0x80, 0x00, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x26, 0x80, 0xa2, 0x53, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x51, 0x53, ++ 0x07, 0x90, 0x01, 0x00, 0x2a, 0x80, 0x00, 0x52, 0x07, 0x90, 0x00, 0x00, ++ 0x29, 0x80, 0xa2, 0x52, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x52, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xf3, 0x93, 0x01, 0x00, 0x5c, 0x95, 0x2e, 0xa2, 0x52, 0xb3, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0x80, 0xf4, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x45, 0xb1, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x4c, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x55, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x1b, 0x84, 0x05, 0x40, 0x49, 0xb1, 0x00, 0x00, 0x1b, 0x84, 0x05, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0xe1, 0x80, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0xde, 0xb2, 0x01, 0x00, 0x77, 0x00, 0x00, 0x40, 0x4b, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xfd, 0x83, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, 0x9b, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa5, 0x9c, 0xb3, 0x01, 0x00, 0xde, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x58, 0x95, 0x20, 0x44, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0xc0, 0x00, 0xa6, 0x36, 0xb1, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x38, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x06, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x05, 0x18, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x02, 0x09, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x50, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x7b, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe0, 0x83, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x10, 0x84, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x08, 0x84, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x60, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x70, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xdd, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb3, 0x01, 0x00, 0x5c, 0x95, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x1a, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x71, 0x83, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x02, 0x00, 0x00, 0x97, ++ 0x80, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2e, 0xb1, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x40, 0x2e, 0xdd, 0x01, 0x00, 0x90, 0x01, 0x00, 0x40, ++ 0x93, 0x98, 0x01, 0x00, 0x29, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x5c, 0x81, 0x00, 0x40, 0xaf, 0x33, 0x01, 0x00, 0x61, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x55, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x49, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x77, 0x01, 0x00, 0x41, 0x81, 0xc0, 0x00, 0x00, ++ 0x71, 0x80, 0x51, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x72, 0x80, 0x52, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x73, 0x80, 0x55, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x74, 0x80, 0x56, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x55, 0x01, 0x91, 0x81, ++ 0x80, 0x30, 0x00, 0x00, 0x5a, 0x01, 0x45, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x55, 0x01, 0x91, 0x82, 0x80, 0x30, 0x00, 0x00, 0x5a, 0x01, 0x46, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x48, 0xfd, 0x93, 0x00, 0x00, ++ 0x5a, 0x01, 0x00, 0x48, 0xfd, 0x93, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x49, ++ 0xfd, 0x83, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x4a, 0xfd, 0x83, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, ++ 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x46, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0xd0, 0xe1, 0xb1, 0x00, 0x00, ++ 0x7c, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x98, 0xb0, 0x01, 0x00, 0x04, 0x80, 0x00, 0x40, 0x8b, 0xb3, 0x00, 0x00, ++ 0xb1, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x84, 0x80, 0xa2, 0x41, ++ 0x97, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa1, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x04, ++ 0x80, 0x94, 0x00, 0x00, 0x80, 0x15, 0x3f, 0x42, 0x97, 0xe3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x03, ++ 0x02, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xcb, 0x99, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcc, ++ 0xf3, 0x83, 0x01, 0x00, 0x8e, 0x80, 0xa2, 0x41, 0x97, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xcb, 0xf3, 0x93, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, ++ 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x44, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa1, 0xe0, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, ++ 0x95, 0x80, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc6, 0x02, 0x00, 0x20, ++ 0x42, 0x31, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, 0x05, 0x6c, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0xcb, 0xdb, 0x91, 0x01, 0x00, 0x00, 0x00, 0x19, 0x41, ++ 0x8b, 0xb3, 0x01, 0x00, 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x9b, 0x80, 0xa8, 0xb1, 0x8c, 0x33, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x9d, 0x80, 0xa8, 0xb1, 0x94, 0x33, 0x00, 0x00, ++ 0xa3, 0x80, 0x14, 0xc6, 0x81, 0x32, 0x00, 0x00, 0x18, 0x00, 0x00, 0xc6, ++ 0x83, 0xf4, 0x01, 0x00, 0x6a, 0x84, 0x22, 0x4f, 0x83, 0x04, 0x00, 0x00, ++ 0x7f, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc6, ++ 0x81, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x97, 0xa3, 0x01, 0x00, ++ 0x7f, 0x80, 0x1f, 0x5c, 0x97, 0x53, 0x00, 0x00, 0x9e, 0x83, 0x1d, 0xc6, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x43, 0x81, 0xf0, 0x01, 0x00, ++ 0xa9, 0x80, 0x00, 0x40, 0x10, 0xc9, 0x00, 0x00, 0x05, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x36, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xda, 0x81, 0x00, 0xca, 0x63, 0xb3, 0x00, 0x00, 0x2d, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x14, 0x81, 0x00, 0x4d, 0x83, 0xb0, 0x00, 0x00, ++ 0x1e, 0x81, 0x00, 0x4e, 0x61, 0xb1, 0x00, 0x00, 0x0d, 0x81, 0x00, 0x40, ++ 0x85, 0xb0, 0x00, 0x00, 0x14, 0x81, 0x00, 0x4c, 0x83, 0xb0, 0x00, 0x00, ++ 0xf0, 0x80, 0x00, 0x40, 0x85, 0xb0, 0x00, 0x00, 0x91, 0x81, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x3d, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x8d, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x0d, 0x81, 0x00, 0x40, ++ 0x85, 0xb0, 0x00, 0x00, 0xdd, 0x81, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, ++ 0x6a, 0x84, 0x00, 0xca, 0x9b, 0xb3, 0x00, 0x00, 0x46, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0x4e, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x55, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0x56, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0x57, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x58, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0x59, 0x81, 0x00, 0x40, ++ 0x81, 0xb0, 0x00, 0x00, 0x59, 0x81, 0x00, 0x41, 0x81, 0xb0, 0x00, 0x00, ++ 0xce, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xdd, 0x83, 0x00, 0xbb, ++ 0xab, 0xb3, 0x00, 0x00, 0xdb, 0x81, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, ++ 0xd3, 0x80, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0xdf, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xdc, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x6a, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xda, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xca, 0x77, 0xb3, 0x00, 0x00, ++ 0x15, 0x81, 0x00, 0x4d, 0x83, 0xb0, 0x00, 0x00, 0x1c, 0x81, 0x00, 0x4e, ++ 0x61, 0xb1, 0x00, 0x00, 0x0d, 0x81, 0x00, 0xbb, 0x85, 0xb0, 0x00, 0x00, ++ 0x15, 0x81, 0x00, 0x4c, 0x83, 0xb0, 0x00, 0x00, 0x0d, 0x81, 0x00, 0xbb, ++ 0x85, 0xb0, 0x00, 0x00, 0xf0, 0x80, 0x00, 0xbb, 0x85, 0xb0, 0x00, 0x00, ++ 0xe2, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xca, ++ 0x4d, 0xb3, 0x00, 0x00, 0x64, 0x82, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, ++ 0x8f, 0x82, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0xc8, 0x14, 0x2e, 0xbb, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xe0, 0xb1, 0x01, 0x00, 0xff, 0x7f, 0x00, 0xa2, ++ 0xa0, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, ++ 0x75, 0x80, 0x00, 0xca, 0xa7, 0x33, 0x01, 0x00, 0x02, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x4d, 0x93, 0x30, 0x01, 0x00, ++ 0x4e, 0x01, 0x00, 0x4e, 0x93, 0x30, 0x01, 0x00, 0x4e, 0x01, 0x00, 0x4c, ++ 0x93, 0x30, 0x01, 0x00, 0x08, 0x84, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6a, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x54, 0x95, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x6a, 0x84, 0x00, 0xca, 0xe5, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, 0xe8, 0x80, 0x22, 0x42, ++ 0x8f, 0x6f, 0x00, 0x00, 0xea, 0x80, 0x22, 0x41, 0x8f, 0x6f, 0x00, 0x00, ++ 0xec, 0x80, 0x1e, 0xca, 0x81, 0x32, 0x00, 0x00, 0xee, 0x80, 0x1f, 0xca, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xc9, 0xb1, 0x01, 0x00, ++ 0x6a, 0x84, 0x00, 0x42, 0x8f, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xcd, 0xb1, 0x01, 0x00, 0x6a, 0x84, 0x00, 0x41, 0x8f, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xcf, 0xb1, 0x01, 0x00, 0x6a, 0x84, 0x00, 0x40, ++ 0x8f, 0xb3, 0x00, 0x00, 0x00, 0x81, 0x00, 0xa6, 0xc6, 0xb1, 0x01, 0x00, ++ 0x6a, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, ++ 0xc6, 0xb1, 0x01, 0x00, 0x6a, 0x84, 0x00, 0x40, 0x8f, 0xb3, 0x00, 0x00, ++ 0x78, 0x18, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, 0x10, 0x00, 0x2f, 0x9c, ++ 0x89, 0xb0, 0x01, 0x00, 0x07, 0x81, 0x00, 0x40, 0x39, 0x33, 0x01, 0x00, ++ 0x18, 0x00, 0x2f, 0x9b, 0x89, 0xb0, 0x01, 0x00, 0x07, 0x81, 0x00, 0x40, ++ 0x37, 0x33, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x9a, 0x89, 0xb0, 0x01, 0x00, ++ 0x07, 0x81, 0x00, 0x40, 0x35, 0x33, 0x01, 0x00, 0x08, 0x00, 0x2f, 0x99, ++ 0x89, 0xb0, 0x01, 0x00, 0x07, 0x81, 0x00, 0x40, 0x33, 0x33, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0xae, 0x47, 0xc9, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x18, 0x00, 0x40, ++ 0xe1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0xae, 0x63, 0xdd, 0x01, 0x00, 0x02, 0x81, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xff, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x02, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x69, 0x93, 0x01, 0x00, 0x6a, 0x84, 0x1a, 0x44, 0x93, 0x93, 0x00, 0x00, ++ 0x05, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf0, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0xa4, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x0c, 0x81, 0xa2, 0x40, ++ 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0xe1, 0xd1, 0x01, 0x00, 0x0d, 0x81, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x62, 0xb1, 0x01, 0x00, 0x11, 0x81, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x0e, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, 0x11, 0x81, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x6a, 0x84, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x16, 0x81, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, 0x16, 0x81, 0x00, 0xbb, ++ 0x81, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x60, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, 0x17, 0x81, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, ++ 0x6a, 0x84, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x19, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x50, 0x95, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x1f, 0x81, 0x00, 0xbb, 0x87, 0xb0, 0x00, 0x00, 0x50, 0x95, 0x2f, 0x40, ++ 0x87, 0xb0, 0x01, 0x00, 0x21, 0x81, 0x22, 0x40, 0x95, 0x7f, 0x00, 0x00, ++ 0x6a, 0x84, 0x60, 0x40, 0x95, 0x83, 0x00, 0x00, 0x02, 0x00, 0x2d, 0xf0, ++ 0x84, 0xb0, 0x01, 0x00, 0x22, 0x81, 0x36, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x62, 0xb1, 0x01, 0x00, 0x23, 0x81, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x62, 0xb1, 0x01, 0x00, ++ 0x25, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0x63, 0xb1, 0x01, 0x00, 0x27, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x16, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x6a, 0x84, 0x22, 0x41, ++ 0x43, 0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0xca, 0x95, 0xcb, 0x01, 0x00, ++ 0x22, 0x81, 0x00, 0x41, 0x85, 0xc0, 0x00, 0x00, 0x2f, 0x81, 0xa2, 0x42, ++ 0x67, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x67, 0xb3, 0x01, 0x00, ++ 0x2f, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x65, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x93, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0xca, 0x69, 0x97, 0x01, 0x00, 0x6a, 0x84, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x34, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x6a, 0x84, 0x1a, 0x44, 0x93, 0x93, 0x00, 0x00, 0x6a, 0x84, 0x20, 0x43, ++ 0x95, 0x6f, 0x00, 0x00, 0x6a, 0x84, 0x80, 0xca, 0x67, 0x33, 0x00, 0x00, ++ 0x6a, 0x84, 0x22, 0x40, 0x65, 0x6f, 0x00, 0x00, 0x6a, 0x84, 0x00, 0x6f, ++ 0xdb, 0x91, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x35, 0x80, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, 0x6a, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x95, 0x93, 0x01, 0x00, ++ 0x42, 0x81, 0xa2, 0x44, 0x21, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x95, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x95, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x57, 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xc3, 0xb1, 0x01, 0x00, 0x45, 0x81, 0x22, 0x5b, 0x95, 0x7f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0xfd, 0x93, 0x01, 0x00, 0x6a, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x49, 0x81, 0x22, 0x40, 0xaf, 0x6f, 0x00, 0x00, ++ 0x1b, 0xf5, 0x00, 0xca, 0x95, 0x9b, 0x01, 0x00, 0x4a, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x1b, 0xfd, 0x00, 0xca, 0x95, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0x7f, 0xb3, 0x01, 0x00, 0x26, 0x01, 0x00, 0xca, ++ 0xc5, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x95, 0x83, 0x01, 0x00, ++ 0x6a, 0x84, 0x00, 0xca, 0xc5, 0xb1, 0x00, 0x00, 0xdf, 0x6f, 0x00, 0xca, ++ 0x95, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, 0x95, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xc7, 0xb1, 0x01, 0x00, 0x6a, 0x84, 0x22, 0x5f, ++ 0x95, 0x7f, 0x00, 0x00, 0x26, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x95, 0x83, 0x01, 0x00, 0x6a, 0x84, 0x00, 0xca, ++ 0xc7, 0xb1, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xca, 0xc9, 0xb1, 0x00, 0x00, ++ 0x6a, 0x84, 0x00, 0xca, 0xcb, 0xb1, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xca, ++ 0xcd, 0xb1, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xca, 0xcf, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x42, 0x81, 0xe0, 0x01, 0x00, 0x98, 0x14, 0x00, 0x40, ++ 0x48, 0xc9, 0x01, 0x00, 0x6a, 0x84, 0x00, 0xca, 0xe1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x09, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x5e, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, 0x60, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x20, 0x80, 0x00, 0xa6, 0x08, 0xb1, 0x01, 0x00, ++ 0x62, 0x81, 0x9f, 0x85, 0x82, 0x30, 0x00, 0x00, 0x61, 0x81, 0xa2, 0x4f, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x21, 0xb3, 0x01, 0x00, ++ 0x02, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0xc9, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x10, 0x00, 0x00, 0x41, 0x84, 0xe4, 0x01, 0x00, ++ 0x03, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0xc9, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x41, 0x86, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x84, 0x94, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x10, 0xc4, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, ++ 0x75, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x21, 0xb3, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x1c, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x72, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, ++ 0x7e, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x41, 0x01, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x50, 0x0c, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, ++ 0x7a, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x21, 0xb3, 0x01, 0x00, 0x7e, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x41, 0x01, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, 0x60, 0x0c, 0x00, 0x43, ++ 0x86, 0x98, 0x01, 0x00, 0x7e, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x21, 0xb3, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x7f, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x40, 0x13, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, 0x87, 0x81, 0x22, 0x43, ++ 0x21, 0x6f, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x84, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, ++ 0x8c, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x19, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0x89, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0x8c, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, 0x81, 0x94, 0x01, 0x00, ++ 0x8f, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x6a, 0x84, 0x00, 0x40, ++ 0x08, 0xb1, 0x00, 0x00, 0xc8, 0x14, 0x2e, 0xbb, 0x85, 0xb0, 0x01, 0x00, ++ 0x92, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x87, 0xb0, 0x01, 0x00, 0xa1, 0x81, 0x22, 0x43, 0x21, 0x6f, 0x00, 0x00, ++ 0xb0, 0x81, 0x22, 0x44, 0x21, 0x6f, 0x00, 0x00, 0x11, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0xc9, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb8, 0x81, 0x22, 0x4a, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x87, 0x90, 0x01, 0x00, 0x9c, 0x81, 0x22, 0x4d, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x87, 0x90, 0x01, 0x00, 0x9e, 0x81, 0x22, 0x4f, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, ++ 0xa0, 0x81, 0x22, 0x4e, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x87, 0x90, 0x01, 0x00, 0xb8, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0xc9, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0xc9, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb8, 0x81, 0x22, 0x42, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, ++ 0x1c, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0xc9, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xab, 0x81, 0x22, 0x45, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x87, 0x90, 0x01, 0x00, 0xad, 0x81, 0x22, 0x44, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, ++ 0xaf, 0x81, 0x22, 0x43, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x87, 0x90, 0x01, 0x00, 0xb8, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0xc9, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0xc9, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb8, 0x81, 0x22, 0x42, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x87, 0x90, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0xc9, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xbc, 0x81, 0x22, 0x4b, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0x80, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xaf, 0xb3, 0x01, 0x00, 0xc5, 0x81, 0x22, 0x40, 0x87, 0x7c, 0x00, 0x00, ++ 0xc5, 0x81, 0xa2, 0x41, 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xae, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb3, 0x01, 0x00, ++ 0xc4, 0x81, 0x22, 0x42, 0x87, 0x7c, 0x00, 0x00, 0xc5, 0x81, 0x00, 0x0b, ++ 0x7d, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x7d, 0xb3, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0xa2, 0xa0, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xa5, 0xb3, 0x01, 0x00, 0x75, 0x80, 0x00, 0xca, 0xa7, 0x33, 0x01, 0x00, ++ 0x02, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x20, 0x00, 0x00, 0x41, ++ 0x82, 0xdc, 0x01, 0x00, 0xca, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x08, 0xb1, 0x01, 0x00, 0xcc, 0x81, 0x9f, 0x85, ++ 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xd1, 0x81, 0x14, 0xf7, 0x81, 0x30, 0x00, 0x00, 0xd1, 0x81, 0xa2, 0x49, ++ 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xfd, 0x93, 0x01, 0x00, ++ 0xd4, 0x81, 0x15, 0xf8, 0x81, 0x14, 0x00, 0x00, 0xd4, 0x81, 0xa2, 0x4a, ++ 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xfd, 0x93, 0x01, 0x00, ++ 0xd6, 0x81, 0xa2, 0xc8, 0x81, 0x32, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0x80, 0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xef, 0xb3, 0x01, 0x00, 0xd8, 0x81, 0x42, 0x40, ++ 0xf1, 0x33, 0x00, 0x00, 0x04, 0x81, 0x00, 0x40, 0x68, 0x97, 0x00, 0x00, ++ 0x6a, 0x84, 0x00, 0xbb, 0x6b, 0xb3, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xbb, ++ 0xb1, 0xb3, 0x00, 0x00, 0x6a, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcc, 0x14, 0x2e, 0x40, 0x87, 0xb0, 0x01, 0x00, 0xff, 0x7f, 0x00, 0xa2, ++ 0xa0, 0x8b, 0x01, 0x00, 0xd8, 0x00, 0x00, 0x43, 0xb2, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0xda, 0x89, 0xb0, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x40, ++ 0x8b, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x89, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x89, 0xd0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x44, ++ 0x88, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x87, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xa5, 0xb3, 0x01, 0x00, 0xd8, 0x00, 0x00, 0x43, ++ 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x87, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa5, 0xc3, 0x01, 0x00, 0xf8, 0x81, 0x22, 0x44, 0x89, 0x50, 0x00, 0x00, ++ 0xf8, 0x81, 0x22, 0x44, 0x8b, 0x50, 0x00, 0x00, 0xe7, 0x81, 0xa2, 0x50, ++ 0xa5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xa5, 0xe3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xa7, 0xb3, 0x01, 0x00, 0x75, 0x80, 0x00, 0xbb, ++ 0x85, 0x30, 0x01, 0x00, 0xcc, 0x14, 0x2e, 0xd2, 0x95, 0xc3, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xb0, 0x01, 0x00, ++ 0xf5, 0x81, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0xf4, 0x81, 0xa2, 0xf2, ++ 0x80, 0x30, 0x00, 0x00, 0xe7, 0x81, 0x00, 0x40, 0xa5, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xa5, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xa7, 0xb3, 0x01, 0x00, 0x75, 0x80, 0x00, 0xbb, 0x85, 0x30, 0x01, 0x00, ++ 0x02, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x41, ++ 0xb3, 0x73, 0x01, 0x00, 0x00, 0x00, 0x80, 0x50, 0xb5, 0xf3, 0x01, 0x00, ++ 0xd8, 0x00, 0x00, 0x41, 0xb3, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, ++ 0xb3, 0xfb, 0x01, 0x00, 0x00, 0x30, 0x00, 0xa6, 0xb8, 0xb3, 0x01, 0x00, ++ 0xf2, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x25, 0x01, 0x00, 0x42, ++ 0x2d, 0x01, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xeb, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x81, 0xb0, 0x01, 0x00, 0x26, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x09, 0x82, 0x10, 0xda, 0xb5, 0x6b, 0x00, 0x00, 0x0a, 0x82, 0x00, 0x41, ++ 0x2d, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2d, 0x91, 0x01, 0x00, ++ 0x28, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x25, 0x01, 0x00, 0x40, ++ 0x2d, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2d, 0x81, 0x01, 0x00, ++ 0x06, 0x82, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x26, 0x01, 0x00, 0x42, ++ 0x2d, 0x01, 0x01, 0x00, 0x25, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x26, 0x01, 0x00, 0x42, 0x2d, 0x11, 0x01, 0x00, 0x25, 0x01, 0x00, 0x40, ++ 0x2d, 0x11, 0x01, 0x00, 0x15, 0x82, 0x04, 0x40, 0x2d, 0x01, 0x00, 0x00, ++ 0x25, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x11, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x28, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x25, 0x01, 0x00, 0x42, 0x2d, 0x01, 0x01, 0x00, 0xf2, 0x00, 0x00, 0x40, ++ 0xb9, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x2d, 0x81, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x41, 0x2d, 0x81, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x03, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x18, 0xb1, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x19, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x42, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x18, 0xb1, 0x01, 0x00, 0x1f, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x19, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x81, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf6, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x43, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, 0x29, 0x82, 0xa2, 0x54, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, 0x30, 0x82, 0xa2, 0x06, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x07, 0x91, 0xb0, 0x01, 0x00, 0xe1, 0x80, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x39, 0x82, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0x3a, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xf5, 0xb1, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xf5, 0xb1, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x42, ++ 0xb3, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf5, 0xb1, 0x01, 0x00, ++ 0x4e, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, ++ 0x50, 0x00, 0x00, 0x40, 0x91, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x8f, 0xb0, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x48, 0xb2, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xf7, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, ++ 0xf7, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x91, 0xc0, 0x01, 0x00, ++ 0x45, 0x82, 0xa2, 0x41, 0x8f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x45, 0xd1, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x16, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x34, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0x91, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x6e, 0xda, 0x8f, 0xb0, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0xda, 0xfd, 0xb1, 0x01, 0x00, ++ 0x6f, 0x82, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0x6f, 0x82, 0x22, 0x45, ++ 0xfd, 0x7f, 0x00, 0x00, 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x35, 0x82, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0x08, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfe, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6d, 0x82, 0xa2, 0x40, 0x8f, 0x6c, 0x00, 0x00, 0x72, 0x82, 0x22, 0x20, ++ 0xb5, 0x6f, 0x00, 0x00, 0x6f, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xdb, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x72, 0x82, 0x22, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x6f, 0x82, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x69, 0x93, 0x01, 0x00, 0x04, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x54, 0x16, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x46, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, 0x48, 0x00, 0x00, 0x40, ++ 0x95, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x97, 0xb0, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x4a, 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xf7, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x95, 0xc0, 0x01, 0x00, 0x85, 0x82, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, ++ 0x40, 0x16, 0x00, 0x40, 0xa1, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xa7, 0xb3, 0x01, 0x00, 0x75, 0x80, 0x00, 0xbb, 0x85, 0x30, 0x01, 0x00, ++ 0x02, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xa7, 0x82, 0x22, 0x45, ++ 0xfd, 0x7f, 0x00, 0x00, 0xe0, 0x15, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x1a, 0x00, 0x00, 0xa2, 0x80, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0xf0, 0x15, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xa0, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, ++ 0x96, 0x82, 0xa8, 0xbb, 0xe1, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x83, 0xb0, 0x01, 0x00, 0x99, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x98, 0x82, 0xa2, 0xf2, 0x82, 0x30, 0x00, 0x00, 0xe1, 0x80, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x9f, 0x82, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0xa0, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xf0, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xa7, 0x82, 0xa2, 0xfa, 0xb4, 0x6f, 0x00, 0x00, ++ 0xfc, 0x81, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, 0xa7, 0x82, 0xa2, 0xfa, ++ 0xb4, 0x6f, 0x00, 0x00, 0xfc, 0x81, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, ++ 0xaa, 0x82, 0x22, 0xfa, 0xb4, 0x6f, 0x00, 0x00, 0xa7, 0x82, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x69, 0x93, 0x01, 0x00, ++ 0x04, 0x81, 0x00, 0x58, 0x69, 0x93, 0x00, 0x00, 0x40, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x35, 0x82, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, ++ 0xf6, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x5c, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x6e, 0xfa, 0x8e, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb4, 0xb3, 0x01, 0x00, ++ 0xb8, 0x82, 0xa2, 0x40, 0x8f, 0x6c, 0x00, 0x00, 0xfc, 0x15, 0x20, 0x20, ++ 0xe1, 0xb1, 0x01, 0x00, 0xbd, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xdb, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xbd, 0x82, 0x22, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0xba, 0x82, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x69, 0x93, 0x01, 0x00, 0x04, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x34, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xc2, 0x82, 0x22, 0x50, 0xb5, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x91, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xf6, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xff, 0x81, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, 0x02, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xf8, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xff, 0x81, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, 0x04, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfa, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xff, 0x81, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, 0x08, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x94, 0xb0, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4a, ++ 0xb4, 0x8b, 0x01, 0x00, 0xff, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4a, ++ 0xb4, 0xf7, 0x01, 0x00, 0xff, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x34, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd8, 0x82, 0x22, 0x50, 0xb5, 0x6f, 0x00, 0x00, 0xd9, 0x82, 0x00, 0x50, ++ 0xb5, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xb5, 0xb3, 0x01, 0x00, ++ 0xff, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x02, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x16, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x30, 0x31, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x32, 0x33, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x34, 0x35, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x36, 0x37, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x38, 0x39, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x41, 0x42, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x43, 0x44, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x45, 0x46, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x47, 0x48, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x49, 0x4a, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf7, 0xb1, 0x01, 0x00, ++ 0xe7, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x80, 0x16, 0x2e, 0x06, ++ 0x83, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0xea, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x22, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf6, 0xb1, 0x01, 0x00, ++ 0xed, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x62, 0x00, 0x00, 0x40, ++ 0x95, 0x98, 0x01, 0x00, 0x00, 0x83, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x16, 0x2d, 0x06, 0x83, 0xb0, 0x01, 0x00, 0x80, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x5c, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0xf3, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xf9, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf9, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0x00, 0x83, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x70, 0x95, 0xb0, 0x01, 0x00, ++ 0xff, 0x82, 0x22, 0x70, 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x45, 0x67, 0x00, 0xa6, 0xe0, 0xb2, 0x01, 0x00, 0x01, 0x23, 0x00, 0x70, ++ 0xe1, 0x9a, 0x01, 0x00, 0xcd, 0xef, 0x00, 0xa6, 0xe2, 0xb2, 0x01, 0x00, ++ 0x89, 0xab, 0x00, 0x71, 0xe3, 0x9a, 0x01, 0x00, 0xba, 0x98, 0x00, 0xa6, ++ 0xe4, 0xb2, 0x01, 0x00, 0xfe, 0xdc, 0x00, 0x72, 0xe5, 0x9a, 0x01, 0x00, ++ 0x32, 0x10, 0x00, 0xa6, 0xe6, 0xb2, 0x01, 0x00, 0x76, 0x54, 0x00, 0x73, ++ 0xe7, 0x9a, 0x01, 0x00, 0xd2, 0xc3, 0x00, 0xa6, 0xe8, 0xb2, 0x01, 0x00, ++ 0xf0, 0xe1, 0x00, 0x74, 0xe9, 0x9a, 0x01, 0x00, 0x80, 0x16, 0x00, 0x4a, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf7, 0xb1, 0x01, 0x00, 0x0d, 0x83, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x80, 0x16, 0x00, 0x4a, 0x44, 0xc9, 0x01, 0x00, 0xfc, 0x16, 0x2a, 0x47, ++ 0xe7, 0xb5, 0x01, 0x00, 0x03, 0x00, 0x00, 0x4a, 0xe8, 0xe5, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, ++ 0xa3, 0x99, 0x01, 0x00, 0x80, 0x16, 0x3d, 0x46, 0x8d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x40, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0x16, 0x83, 0xa2, 0x41, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xeb, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xed, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xef, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf1, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf3, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x41, ++ 0x80, 0x88, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, 0xa2, 0xc9, 0x01, 0x00, ++ 0x33, 0x83, 0xa0, 0x50, 0x83, 0x6c, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x40, ++ 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x99, 0x84, 0x01, 0x00, ++ 0x50, 0x03, 0x00, 0x4c, 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x86, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0x98, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x99, 0x84, 0x01, 0x00, 0x50, 0x03, 0x00, 0x4c, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x86, 0xa4, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x40, 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x99, 0x84, 0x01, 0x00, 0x50, 0x03, 0x00, 0x4c, 0xa2, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x86, 0xa4, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40, 0xa4, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x20, 0x88, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x41, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x94, 0x01, 0x00, ++ 0x05, 0x00, 0x00, 0x75, 0x89, 0xe4, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x75, ++ 0x85, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x84, 0x94, 0x01, 0x00, ++ 0x3d, 0x83, 0xa3, 0x53, 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, 0x89, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x76, 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x8b, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x4c, 0x83, 0x00, 0x45, 0x88, 0x94, 0x00, 0x00, 0x27, 0x00, 0x00, 0x41, ++ 0x80, 0xce, 0x01, 0x00, 0x42, 0x83, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x76, 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x89, 0xa4, 0x01, 0x00, 0x4c, 0x83, 0x00, 0x78, 0x89, 0xa4, 0x00, 0x00, ++ 0x3b, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, 0x3f, 0x83, 0xaa, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x89, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x77, 0x89, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x76, ++ 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x88, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x4c, 0x83, 0x00, 0x45, 0x88, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x84, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x84, 0xc0, 0x01, 0x00, 0x53, 0x83, 0xa3, 0x53, ++ 0x83, 0x6c, 0x00, 0x00, 0x82, 0x5a, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, ++ 0x99, 0x79, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, 0x60, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x27, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, ++ 0x58, 0x83, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, 0xd9, 0x6e, 0x00, 0xa6, ++ 0x84, 0xc0, 0x01, 0x00, 0xa1, 0xeb, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, ++ 0x60, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x41, ++ 0x80, 0xce, 0x01, 0x00, 0x5d, 0x83, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x8f, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, 0xdc, 0xbc, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x60, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x62, 0xca, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, 0xd6, 0xc1, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x60, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x78, 0xf3, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0xf1, 0xb2, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x76, 0x89, 0xe4, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x76, 0xef, 0xf6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xee, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x75, 0xed, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xea, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x83, 0xc0, 0x01, 0x00, 0x4f, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, ++ 0x1f, 0x83, 0x2a, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, ++ 0xe1, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x76, 0xe3, 0xc2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x77, 0xe5, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, ++ 0xe7, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0xe9, 0xc2, 0x01, 0x00, ++ 0x13, 0x83, 0x81, 0x41, 0x8d, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x9d, 0x83, 0xa2, 0x4b, 0xb7, 0x6f, 0x00, 0x00, ++ 0x9d, 0x83, 0xa2, 0x41, 0x2f, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xfd, 0x93, 0x01, 0x00, 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x35, 0x82, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0x9c, 0x83, 0x22, 0x40, ++ 0x8f, 0x6c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0xfe, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xdb, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x9c, 0x83, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0x5e, 0x16, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x7c, 0x16, 0x20, 0xf6, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x31, 0xb3, 0x01, 0x00, ++ 0x80, 0x83, 0x22, 0x4f, 0x8f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, ++ 0xfd, 0x93, 0x01, 0x00, 0x82, 0x83, 0x22, 0x40, 0x8f, 0x7c, 0x00, 0x00, ++ 0x86, 0x83, 0x00, 0x54, 0xfd, 0x93, 0x00, 0x00, 0x84, 0x83, 0x22, 0x42, ++ 0x8f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xfd, 0x93, 0x01, 0x00, ++ 0x86, 0x83, 0x22, 0x41, 0x8f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, ++ 0xfd, 0x93, 0x01, 0x00, 0x9a, 0x83, 0x22, 0x51, 0xfd, 0x7f, 0x00, 0x00, ++ 0x34, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x95, 0x83, 0xa2, 0x40, 0xb5, 0x6f, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x48, 0x96, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0x97, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x4b, ++ 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xff, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x30, 0xb5, 0xb3, 0x01, 0x00, 0xff, 0x81, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x99, 0x83, 0x22, 0x40, ++ 0xb5, 0x6f, 0x00, 0x00, 0x9d, 0x83, 0x00, 0x54, 0xfd, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x51, 0xfd, 0x83, 0x01, 0x00, 0x1c, 0x00, 0x00, 0xfe, ++ 0x7f, 0xd9, 0x01, 0x00, 0x9d, 0x83, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x41, 0x99, 0xb3, 0x01, 0x00, 0xa8, 0x83, 0x22, 0x44, ++ 0x81, 0x6c, 0x00, 0x00, 0xb0, 0x83, 0x22, 0x48, 0x81, 0x6c, 0x00, 0x00, ++ 0xaa, 0x83, 0x22, 0x4c, 0x81, 0x6c, 0x00, 0x00, 0xb4, 0x83, 0x22, 0x50, ++ 0x81, 0x6c, 0x00, 0x00, 0xb5, 0x83, 0x22, 0x54, 0x81, 0x6c, 0x00, 0x00, ++ 0xb7, 0x83, 0x22, 0x58, 0x81, 0x6c, 0x00, 0x00, 0xbc, 0x83, 0x22, 0x5c, ++ 0x81, 0x6c, 0x00, 0x00, 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xbc, 0x09, 0xb0, 0x01, 0x00, 0x6a, 0x84, 0x00, 0xca, ++ 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xf3, 0x83, 0x01, 0x00, 0xae, 0x83, 0xa2, 0x42, ++ 0x05, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x05, 0xb0, 0x01, 0x00, ++ 0x6a, 0x84, 0x22, 0xca, 0x07, 0x14, 0x00, 0x00, 0x6a, 0x84, 0x00, 0x45, ++ 0xf3, 0x93, 0x00, 0x00, 0x6a, 0x84, 0x20, 0x43, 0x95, 0x6f, 0x00, 0x00, ++ 0x6a, 0x84, 0x80, 0xca, 0x05, 0x30, 0x00, 0x00, 0x6a, 0x84, 0x22, 0x01, ++ 0x80, 0x30, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xcb, 0xdb, 0x91, 0x00, 0x00, ++ 0x5c, 0x01, 0x00, 0xbc, 0xab, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, ++ 0xb1, 0xb3, 0x01, 0x00, 0x6a, 0x84, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, ++ 0xff, 0x00, 0x00, 0xca, 0x81, 0x88, 0x01, 0x00, 0x6a, 0x84, 0xa2, 0x40, ++ 0x74, 0x7d, 0x00, 0x00, 0x60, 0x00, 0x20, 0x40, 0x60, 0x99, 0x01, 0x00, ++ 0xb9, 0x83, 0xa8, 0xb1, 0x82, 0x30, 0x00, 0x00, 0xb8, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x6a, 0x84, 0x00, 0xca, 0x79, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xcb, 0x83, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xbf, 0x83, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xca, 0x83, 0x91, 0x82, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, ++ 0x80, 0xb0, 0x01, 0x00, 0xb6, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0xc8, 0x83, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xca, 0x83, 0x56, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, 0xb6, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, 0x07, 0x90, 0x01, 0x00, ++ 0xf3, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xcd, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xcf, 0x83, 0xa2, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xda, 0x83, 0x91, 0x81, ++ 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x80, 0xb0, 0x01, 0x00, ++ 0xb6, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, 0xd8, 0x83, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xda, 0x83, 0x55, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, 0xf3, 0x9f, 0x00, 0x41, ++ 0x8b, 0xb3, 0x00, 0x00, 0xb1, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0xc4, 0x14, 0x2f, 0x40, 0x99, 0xb3, 0x01, 0x00, 0x5c, 0x01, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x58, 0x15, 0x2d, 0x40, 0x8d, 0xb0, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0xf0, 0x88, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8f, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, 0x90, 0xb0, 0x01, 0x00, ++ 0x00, 0xf8, 0x00, 0x48, 0x90, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x93, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x8a, 0xb0, 0x01, 0x00, ++ 0x6a, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa6, ++ 0x80, 0xb0, 0x01, 0x00, 0xec, 0x83, 0x22, 0x40, 0x82, 0x6c, 0x00, 0x00, ++ 0xf0, 0x83, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x47, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8d, 0xc0, 0x01, 0x00, ++ 0xf5, 0x83, 0x22, 0x5f, 0x8d, 0x6c, 0x00, 0x00, 0xe7, 0x83, 0xa2, 0x41, ++ 0x93, 0x50, 0x00, 0x00, 0xe5, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xff, 0x07, 0x00, 0x47, 0x84, 0x88, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xf5, 0x9f, 0x00, 0x47, 0x80, 0x30, 0x01, 0x00, ++ 0x00, 0x02, 0x00, 0x47, 0x8e, 0xc8, 0x01, 0x00, 0xf0, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x50, 0xb3, 0x01, 0x00, ++ 0xfb, 0x83, 0x20, 0x18, 0x89, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x00, 0xa6, ++ 0x84, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x10, 0x00, 0x40, 0x55, 0x9b, 0x01, 0x00, 0xfe, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0xa6, 0x84, 0xb0, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x55, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x50, 0xd3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa8, 0x4f, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x4e, 0xd3, 0x01, 0x00, 0x5e, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6c, 0x03, 0x00, 0x42, 0x80, 0x30, 0x01, 0x00, 0xf0, 0x83, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x07, 0x84, 0x22, 0xa7, 0x8f, 0x6c, 0x00, 0x00, ++ 0x49, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xa0, 0x94, 0x2e, 0x43, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x09, 0x84, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x50, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xac, 0x94, 0x2e, 0x43, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x0d, 0x84, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xae, 0x03, 0x00, 0x40, 0xa3, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x60, 0x15, 0x00, 0x40, ++ 0x85, 0x98, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0x40, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x59, 0x41, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x41, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x40, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x41, ++ 0x81, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0x13, 0x84, 0x00, 0x50, 0x85, 0xc0, 0x00, 0x00, 0x49, 0x84, 0xa2, 0x41, ++ 0x01, 0x7d, 0x00, 0x00, 0x21, 0x84, 0x22, 0x58, 0x73, 0x7d, 0x00, 0x00, ++ 0x78, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x1c, 0x84, 0xa8, 0xb1, ++ 0x9c, 0x30, 0x00, 0x00, 0x30, 0x00, 0x38, 0x45, 0x9d, 0xe0, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x0e, 0x10, 0xc9, 0x00, 0x00, 0x21, 0x84, 0x33, 0xc4, ++ 0x81, 0x30, 0x00, 0x00, 0x24, 0x84, 0xa1, 0xad, 0x9d, 0x20, 0x00, 0x00, ++ 0x1b, 0x84, 0x13, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4e, ++ 0x5a, 0x83, 0x01, 0x00, 0x30, 0x00, 0x38, 0x45, 0x9d, 0xe0, 0x01, 0x00, ++ 0x2c, 0x84, 0x22, 0xab, 0x80, 0x04, 0x00, 0x00, 0x2a, 0x84, 0xa2, 0x40, ++ 0x01, 0x7d, 0x00, 0x00, 0x2c, 0x84, 0x22, 0x5f, 0x57, 0x7d, 0x00, 0x00, ++ 0x21, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2c, 0x84, 0x22, 0x5e, ++ 0x57, 0x7d, 0x00, 0x00, 0x84, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x31, 0x84, 0x22, 0x54, 0x73, 0x7d, 0x00, 0x00, 0x74, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x2c, 0x84, 0xa8, 0xb1, 0x00, 0x30, 0x00, 0x00, ++ 0xfa, 0x85, 0xa2, 0x5f, 0x01, 0x7c, 0x00, 0x00, 0x5c, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x33, 0x84, 0xa2, 0x5f, 0x59, 0x27, 0x00, 0x00, ++ 0x35, 0x84, 0xa2, 0x5c, 0x73, 0x7d, 0x00, 0x00, 0x3c, 0x84, 0xa2, 0x5e, ++ 0x73, 0x7d, 0x00, 0x00, 0x46, 0x84, 0x22, 0x5c, 0x73, 0x7d, 0x00, 0x00, ++ 0x47, 0x84, 0x37, 0x40, 0x81, 0x32, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x36, 0x84, 0xa8, 0xb1, 0x36, 0x30, 0x00, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x38, 0x84, 0xa8, 0xb1, ++ 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x02, 0x88, 0x01, 0x00, ++ 0x29, 0x86, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x47, 0x84, 0x34, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x3d, 0x84, 0xa8, 0xb1, 0x12, 0x30, 0x00, 0x00, 0x44, 0x84, 0x52, 0x21, ++ 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x41, 0x2f, 0xc3, 0x01, 0x00, ++ 0xff, 0x3f, 0x00, 0x09, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x01, 0xf0, 0x01, 0x00, 0x87, 0x84, 0x00, 0x34, 0x13, 0x84, 0x00, 0x00, ++ 0xff, 0x3f, 0x14, 0x09, 0x00, 0x8c, 0x01, 0x00, 0xe5, 0x84, 0x00, 0x43, ++ 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x47, 0x84, 0x33, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x13, 0x4e, ++ 0x5a, 0x93, 0x00, 0x00, 0xe6, 0x89, 0xa2, 0x48, 0xfd, 0x7f, 0x00, 0x00, ++ 0x4e, 0x84, 0x22, 0x59, 0x73, 0x7d, 0x00, 0x00, 0x79, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x4a, 0x84, 0x28, 0xb1, 0x7e, 0x31, 0x00, 0x00, ++ 0x4b, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x52, 0x84, 0x21, 0xac, ++ 0x9c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x1f, 0xc3, 0x01, 0x00, ++ 0x04, 0x00, 0xa0, 0x5f, 0x9d, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x58, 0x91, 0x01, 0x00, 0x56, 0x84, 0x22, 0x5a, 0x73, 0x7d, 0x00, 0x00, ++ 0x7a, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x53, 0x84, 0xa8, 0xb1, ++ 0x7e, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0xcf, 0x11, 0xc9, 0x00, 0x00, ++ 0x5c, 0x84, 0xa2, 0x40, 0x93, 0x7f, 0x00, 0x00, 0x5c, 0x84, 0x22, 0x44, ++ 0x93, 0x7f, 0x00, 0x00, 0x58, 0x84, 0x42, 0xa5, 0x80, 0x30, 0x00, 0x00, ++ 0x5b, 0x84, 0xa2, 0x40, 0x93, 0x7f, 0x00, 0x00, 0x71, 0x84, 0x1a, 0x40, ++ 0x93, 0x93, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x9a, 0x80, 0xa2, 0x40, 0x73, 0x7d, 0x00, 0x00, 0x9b, 0x89, 0x22, 0x44, ++ 0x21, 0x6f, 0x00, 0x00, 0x92, 0x89, 0x22, 0x40, 0x65, 0x7d, 0x00, 0x00, ++ 0xa0, 0x89, 0xa2, 0x5b, 0x73, 0x7d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x49, ++ 0x33, 0x7d, 0x00, 0x00, 0x66, 0x84, 0x22, 0x48, 0x33, 0x7d, 0x00, 0x00, ++ 0xff, 0x01, 0x00, 0x99, 0x80, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x81, 0xe0, 0x01, 0x00, 0xa8, 0x98, 0x2f, 0x40, 0x33, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe0, 0xc1, 0x01, 0x00, 0x69, 0x84, 0x22, 0x40, ++ 0xaf, 0x6f, 0x00, 0x00, 0x69, 0x84, 0x22, 0x40, 0x81, 0x6f, 0x00, 0x00, ++ 0xef, 0x89, 0x1f, 0xa5, 0x82, 0x6f, 0x00, 0x00, 0x49, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x40, 0x8b, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x62, 0xb1, 0x01, 0x00, 0x1b, 0x84, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x6c, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x6f, 0x84, 0x33, 0x40, ++ 0x1f, 0x30, 0x00, 0x00, 0x1b, 0x84, 0x13, 0x4e, 0x5a, 0x93, 0x00, 0x00, ++ 0x73, 0x84, 0xa0, 0xce, 0x81, 0x50, 0x00, 0x00, 0x85, 0x84, 0xa0, 0xcd, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x9c, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xb1, 0x81, 0xb0, 0x01, 0x00, 0x85, 0x84, 0x22, 0xb5, ++ 0x81, 0x14, 0x00, 0x00, 0x80, 0x15, 0x2f, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x77, 0x84, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x60, 0xb4, ++ 0x65, 0x97, 0x01, 0x00, 0xd0, 0x15, 0x2e, 0x40, 0x69, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x44, 0x93, 0x83, 0x01, 0x00, 0x1a, 0x00, 0x00, 0xa2, ++ 0x80, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xb1, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb5, ++ 0xf1, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, 0x80, 0x84, 0xa8, 0xa1, ++ 0xe0, 0x31, 0x00, 0x00, 0x5c, 0x84, 0x00, 0x88, 0x9e, 0xb3, 0x00, 0x00, ++ 0x5c, 0x84, 0xa2, 0x41, 0x67, 0x6f, 0x00, 0x00, 0x5c, 0x84, 0x00, 0x6f, ++ 0xdb, 0x91, 0x00, 0x00, 0x85, 0x84, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x5c, 0x84, 0x1a, 0x40, 0x93, 0x83, 0x00, 0x00, 0x00, 0x99, 0x00, 0x09, ++ 0x46, 0xc9, 0x01, 0x00, 0x3f, 0x00, 0x00, 0xf3, 0x0c, 0x88, 0x01, 0x00, ++ 0x90, 0x84, 0xa6, 0x42, 0x13, 0x60, 0x00, 0x00, 0x3f, 0x97, 0x00, 0x95, ++ 0x03, 0x30, 0x01, 0x00, 0x8b, 0x84, 0x45, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x75, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x8c, 0x84, 0xa8, 0xb1, ++ 0x0c, 0x30, 0x00, 0x00, 0x46, 0x97, 0x1d, 0x10, 0x94, 0x30, 0x01, 0x00, ++ 0x91, 0x84, 0x00, 0x58, 0x1f, 0x90, 0x00, 0x00, 0x38, 0x97, 0x00, 0x95, ++ 0x03, 0x30, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x2d, 0xf0, ++ 0x2e, 0xb0, 0x01, 0x00, 0xee, 0x07, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x98, 0x84, 0x23, 0x4b, 0xe4, 0x6d, 0x00, 0x00, 0x98, 0x84, 0x22, 0x4b, ++ 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x90, 0x01, 0x00, ++ 0x22, 0x00, 0x2f, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x9b, 0x84, 0x83, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x26, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x9d, 0x84, 0x85, 0x17, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x47, 0xc1, 0x01, 0x00, 0xa2, 0x84, 0x22, 0x55, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x43, 0xd1, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xfa, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x97, 0xe0, 0x01, 0x00, ++ 0xa3, 0x84, 0x00, 0x4b, 0x44, 0xc1, 0x00, 0x00, 0x12, 0x00, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0x28, 0x00, 0x00, 0xf6, 0x02, 0xcc, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0xa1, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x28, 0xf0, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, ++ 0x2a, 0xb0, 0x01, 0x00, 0xc0, 0x28, 0x3c, 0x46, 0x0d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x44, 0x95, 0xb0, 0x01, 0x00, 0xaf, 0x84, 0xa2, 0xf8, ++ 0x0e, 0x30, 0x00, 0x00, 0xbf, 0x84, 0x22, 0x41, 0x95, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x50, 0x49, 0xc1, 0x01, 0x00, 0xab, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xac, 0x84, 0xa2, 0xf8, 0x16, 0x6c, 0x00, 0x00, ++ 0xac, 0x84, 0xa2, 0xf8, 0x10, 0x6c, 0x00, 0x00, 0xac, 0x84, 0xa2, 0xf0, ++ 0x1a, 0x6c, 0x00, 0x00, 0xbd, 0x84, 0x22, 0x58, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, 0xb4, 0x84, 0x47, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xb8, 0x84, 0xa2, 0xf3, 0x74, 0x06, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0xe6, 0x95, 0x01, 0x00, 0xbd, 0x84, 0x1f, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x96, 0xb0, 0x01, 0x00, ++ 0x3f, 0x00, 0x1f, 0xf3, 0x0c, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0xbb, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xbd, 0x84, 0x47, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xc5, 0x84, 0x1f, 0x41, 0x2d, 0xc3, 0x00, 0x00, ++ 0xc3, 0x84, 0x22, 0x58, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x62, 0xb1, 0x01, 0x00, ++ 0xc1, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc3, 0x84, 0x47, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xec, 0x84, 0x1f, 0x41, 0x2d, 0xc3, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0x0b, 0x96, 0x00, 0x07, ++ 0x16, 0x30, 0x01, 0x00, 0xd3, 0x84, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, ++ 0xcb, 0x84, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xd2, 0x84, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, ++ 0xff, 0x96, 0x00, 0x5f, 0x01, 0x10, 0x01, 0x00, 0xd1, 0x84, 0x22, 0x40, ++ 0x95, 0x6c, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x74, 0x96, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0xdb, 0x84, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x86, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xdb, 0x84, 0x22, 0x20, 0x85, 0x6c, 0x00, 0x00, 0xd8, 0x84, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x66, 0x96, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x85, 0x98, 0x00, 0x42, ++ 0x61, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xce, 0x99, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xde, 0x84, 0x82, 0xf0, 0x18, 0x30, 0x00, 0x00, ++ 0x66, 0x8b, 0x00, 0x45, 0x8f, 0xb0, 0x00, 0x00, 0x28, 0x20, 0x00, 0xa6, ++ 0x96, 0xb0, 0x01, 0x00, 0xe2, 0x84, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, ++ 0xf5, 0x97, 0x00, 0x4b, 0x95, 0x30, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x4b, ++ 0x8f, 0xb0, 0x00, 0x00, 0x0b, 0x97, 0x00, 0x03, 0x48, 0x31, 0x01, 0x00, ++ 0xe7, 0x94, 0x00, 0x40, 0x81, 0x30, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x50, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0xe9, 0x84, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x2e, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x17, 0xb0, 0x01, 0x00, 0x00, 0x41, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, ++ 0xee, 0x07, 0x2e, 0x47, 0x97, 0x90, 0x01, 0x00, 0xff, 0x84, 0x22, 0x17, ++ 0x96, 0x04, 0x00, 0x00, 0xfd, 0x84, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, ++ 0xfd, 0x84, 0x23, 0xa2, 0x02, 0x6c, 0x00, 0x00, 0x74, 0x96, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0x04, 0x00, 0x22, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x0c, 0x00, 0x2d, 0x00, 0x12, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x80, 0x01, 0x00, ++ 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, ++ 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x03, 0xb0, 0x01, 0x00, ++ 0x1c, 0x85, 0x00, 0x5c, 0x17, 0x90, 0x00, 0x00, 0x11, 0x85, 0x22, 0x43, ++ 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x1f, 0x90, 0x01, 0x00, ++ 0x0a, 0x85, 0x22, 0x5f, 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf1, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, ++ 0xe0, 0xc9, 0x01, 0x00, 0x06, 0x85, 0x45, 0x42, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x07, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x1d, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0xff, 0x0f, 0x00, 0xf6, ++ 0x80, 0x88, 0x01, 0x00, 0x0e, 0x85, 0xa2, 0xa6, 0x81, 0x6c, 0x00, 0x00, ++ 0x11, 0x85, 0x00, 0xf2, 0x3a, 0xb0, 0x00, 0x00, 0xf7, 0x85, 0xa2, 0x4b, ++ 0xfd, 0x7f, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x15, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1c, 0x85, 0x22, 0x4a, ++ 0x2f, 0x7c, 0x00, 0x00, 0x1c, 0x85, 0x22, 0x48, 0x2f, 0x7c, 0x00, 0x00, ++ 0x0a, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x3f, 0x00, 0x00, 0xf2, ++ 0x86, 0x88, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x43, 0x84, 0x88, 0x01, 0x00, ++ 0x05, 0x00, 0x00, 0x43, 0x80, 0xf4, 0x01, 0x00, 0x98, 0x94, 0x3d, 0x42, ++ 0x81, 0xe0, 0x01, 0x00, 0x1c, 0x85, 0xa2, 0x42, 0xe0, 0x7d, 0x00, 0x00, ++ 0xf7, 0x85, 0xa2, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x15, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x1c, 0x85, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, ++ 0x09, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x41, 0x47, 0xc3, 0x01, 0x00, ++ 0x22, 0x85, 0x22, 0xa1, 0x09, 0x6c, 0x00, 0x00, 0x6b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x1f, 0x85, 0x00, 0x03, 0x48, 0xb1, 0x00, 0x00, ++ 0x5b, 0x85, 0xa3, 0x92, 0x03, 0x6c, 0x00, 0x00, 0xf4, 0x98, 0x00, 0x40, ++ 0x95, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, ++ 0x15, 0x8a, 0x22, 0x08, 0x80, 0x32, 0x00, 0x00, 0x28, 0x85, 0x22, 0x5c, ++ 0x17, 0x7c, 0x00, 0x00, 0x29, 0x85, 0x00, 0x00, 0x2a, 0xb0, 0x00, 0x00, ++ 0x12, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, 0x02, 0x00, 0x00, 0x08, ++ 0x80, 0xc8, 0x01, 0x00, 0x2d, 0x85, 0xa2, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0xf8, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x49, 0x85, 0x00, 0x5e, ++ 0x17, 0x90, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x8c, 0xcc, 0x01, 0x00, ++ 0xf8, 0x97, 0x00, 0x4c, 0x03, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, ++ 0x02, 0xb0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x15, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x36, 0x85, 0xa8, 0x54, 0x17, 0x10, 0x00, 0x00, 0x49, 0x85, 0x00, 0x5e, ++ 0x17, 0x90, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, ++ 0x48, 0x85, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, ++ 0x8c, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x03, 0xb0, 0x01, 0x00, ++ 0x19, 0x98, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, ++ 0x02, 0xb0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x09, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x15, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x49, 0x85, 0x28, 0x54, 0x17, 0x10, 0x00, 0x00, 0x45, 0x85, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x19, 0x98, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, ++ 0x4b, 0x85, 0x22, 0x50, 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, ++ 0x17, 0x90, 0x01, 0x00, 0x07, 0x00, 0x00, 0x17, 0x98, 0x88, 0x01, 0x00, ++ 0x4e, 0x85, 0xa2, 0x41, 0x99, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x17, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x4f, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x56, 0x85, 0x22, 0x43, ++ 0x2f, 0x7c, 0x00, 0x00, 0x16, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0xe4, 0xb1, 0x01, 0x00, 0xa1, 0x97, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0x59, 0x85, 0xa2, 0x5f, 0x2f, 0x7c, 0x00, 0x00, ++ 0xb9, 0x94, 0x00, 0x01, 0x38, 0x43, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x15, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x5d, 0x85, 0xa2, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0xf4, 0x85, 0x00, 0x41, ++ 0x43, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x27, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, 0x5f, 0x85, 0x35, 0x01, ++ 0x86, 0x30, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x66, 0x85, 0x28, 0xb1, 0x30, 0x30, 0x00, 0x00, 0x60, 0x85, 0x22, 0x4d, ++ 0x75, 0x7d, 0x00, 0x00, 0xe4, 0x85, 0xa2, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, 0xf3, 0x85, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x66, 0x85, 0xa8, 0xb1, 0x12, 0x30, 0x00, 0x00, 0x6f, 0x85, 0xa2, 0x40, ++ 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x2c, 0xb0, 0x01, 0x00, 0xde, 0x07, 0x00, 0x43, 0x80, 0xce, 0x01, 0x00, ++ 0x60, 0x85, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, 0x74, 0x85, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x40, 0x00, 0x3e, 0x43, 0x27, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x27, 0xc0, 0x01, 0x00, ++ 0x60, 0x85, 0xa3, 0x0b, 0x87, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, ++ 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, 0x40, 0x00, 0x2d, 0x40, ++ 0x39, 0xb0, 0x01, 0x00, 0x7c, 0x85, 0xa2, 0x40, 0x27, 0x6c, 0x00, 0x00, ++ 0x22, 0x00, 0x00, 0x08, 0x12, 0xc8, 0x01, 0x00, 0xde, 0x07, 0x00, 0x40, ++ 0x25, 0x98, 0x01, 0x00, 0x7f, 0x85, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x12, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x30, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x25, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, 0x14, 0x00, 0x20, 0x01, ++ 0xe0, 0xb1, 0x01, 0x00, 0xee, 0x07, 0x00, 0x40, 0x37, 0x98, 0x01, 0x00, ++ 0x84, 0x85, 0x23, 0x01, 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x36, 0xb0, 0x01, 0x00, 0x8f, 0x85, 0x82, 0x41, 0x23, 0x40, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x8b, 0x85, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x88, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xeb, 0x95, 0x00, 0x43, 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x32, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x23, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x44, 0xc9, 0x01, 0x00, 0x9e, 0x85, 0x22, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, ++ 0x62, 0xdd, 0x01, 0x00, 0x95, 0x85, 0xa8, 0x15, 0xe0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x33, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x25, 0xd0, 0x01, 0x00, ++ 0x0c, 0x00, 0x2d, 0x4c, 0x13, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x37, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2b, 0xc0, 0x01, 0x00, ++ 0x84, 0x85, 0x00, 0x45, 0x1f, 0x80, 0x00, 0x00, 0xa0, 0x85, 0xa3, 0x12, ++ 0x36, 0x6c, 0x00, 0x00, 0xa1, 0x85, 0x68, 0x1b, 0x28, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x68, 0x12, 0x28, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, ++ 0x62, 0xdd, 0x01, 0x00, 0xa4, 0x85, 0xa8, 0x15, 0xe0, 0x31, 0x00, 0x00, ++ 0xca, 0x85, 0x22, 0x14, 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x33, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x24, 0xd0, 0x01, 0x00, ++ 0x0c, 0x00, 0x2d, 0x14, 0x12, 0xc0, 0x01, 0x00, 0xc3, 0x85, 0xa2, 0x14, ++ 0x36, 0x50, 0x00, 0x00, 0xb4, 0x85, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xb2, 0x85, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xaf, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x2a, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x2b, 0x80, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x37, 0x98, 0x01, 0x00, 0xb9, 0x85, 0x23, 0x01, 0x36, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x36, 0xb0, 0x01, 0x00, 0xc4, 0x85, 0x22, 0x1b, ++ 0x02, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x5c, 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x15, 0xe0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0xc0, 0x85, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc4, 0x85, 0x00, 0x03, ++ 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x2a, 0xc0, 0x01, 0x00, ++ 0x84, 0x85, 0xa2, 0x40, 0x25, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x39, 0xc0, 0x01, 0x00, 0x40, 0x00, 0x3d, 0x43, 0x39, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x25, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x12, 0xb0, 0x01, 0x00, 0x84, 0x85, 0x00, 0xf0, 0x30, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, 0xd0, 0x85, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, 0xcd, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xeb, 0x95, 0x00, 0x40, 0x2b, 0x30, 0x01, 0x00, 0x18, 0x00, 0x2e, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0xd4, 0x85, 0x22, 0x50, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x56, 0x17, 0x90, 0x01, 0x00, 0x07, 0x00, 0x00, 0x17, ++ 0x98, 0x88, 0x01, 0x00, 0xd7, 0x85, 0xa2, 0x41, 0x99, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x17, 0x90, 0x01, 0x00, 0xda, 0x85, 0x22, 0x43, ++ 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x17, 0x90, 0x01, 0x00, ++ 0x16, 0x00, 0x20, 0x1d, 0xe4, 0xb1, 0x01, 0x00, 0xdc, 0x85, 0xa3, 0x40, ++ 0x27, 0x6c, 0x00, 0x00, 0xde, 0x85, 0x60, 0x5f, 0x17, 0x90, 0x00, 0x00, ++ 0x00, 0x84, 0x00, 0x0b, 0x16, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x60, 0x13, ++ 0x16, 0x94, 0x01, 0x00, 0xa1, 0x97, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, ++ 0x15, 0x8a, 0xa2, 0x5f, 0x2f, 0x7c, 0x00, 0x00, 0x14, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, ++ 0xb9, 0x94, 0x00, 0x01, 0x38, 0x43, 0x01, 0x00, 0x15, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4d, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0x62, 0xb1, 0x01, 0x00, 0xe6, 0x85, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x62, 0xb1, 0x01, 0x00, 0xe8, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xf3, 0x85, 0x22, 0x13, 0x82, 0x6c, 0x00, 0x00, ++ 0x40, 0x00, 0x3d, 0x43, 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x2c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x62, 0xb1, 0x01, 0x00, 0xee, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x62, 0xb1, 0x01, 0x00, ++ 0xf0, 0x85, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xea, 0x85, 0x00, 0x41, ++ 0x83, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x82, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0x74, 0x96, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x15, 0x8a, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x01, 0x80, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, ++ 0x0e, 0xf4, 0x01, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0x0b, 0x96, 0x00, 0x07, ++ 0x16, 0x30, 0x01, 0x00, 0x05, 0x86, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, ++ 0x03, 0x86, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x04, 0x86, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0x0d, 0x86, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x86, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0d, 0x86, 0x22, 0x20, 0x85, 0x6c, 0x00, 0x00, 0x0a, 0x86, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x66, 0x96, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x85, 0x98, 0x00, 0x42, ++ 0x61, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xce, 0x99, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, ++ 0x13, 0x86, 0x22, 0x3a, 0x01, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x8e, 0xb0, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x40, 0x01, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x2e, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x17, 0x86, 0xa2, 0x40, 0xe7, 0x6d, 0x00, 0x00, ++ 0x0a, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x40, ++ 0x01, 0xb0, 0x00, 0x00, 0x51, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x38, 0x97, 0x00, 0x95, 0x03, 0x30, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x22, 0x00, 0x2d, 0xf0, 0x2e, 0xb0, 0x01, 0x00, 0x28, 0x20, 0x00, 0xa6, ++ 0x96, 0xb0, 0x01, 0x00, 0x20, 0x86, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, ++ 0xf5, 0x97, 0x00, 0x4b, 0x95, 0x30, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x4c, ++ 0x8f, 0xb0, 0x00, 0x00, 0x22, 0x86, 0x83, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x43, 0xc1, 0x01, 0x00, 0x24, 0x86, 0x85, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x43, 0xc1, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0xf6, 0x02, 0xcc, 0x01, 0x00, 0x12, 0x00, 0x00, 0xa1, ++ 0x2a, 0xc8, 0x01, 0x00, 0x0b, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xe7, 0x94, 0x00, 0x41, 0x81, 0x30, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x2e, 0x86, 0x46, 0x47, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x2f, 0x86, 0xa8, 0x1b, 0xe0, 0x31, 0x00, 0x00, 0x1b, 0x84, 0x1e, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xe0, 0x01, 0x00, ++ 0x08, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x54, 0x86, 0x01, 0xfb, ++ 0x08, 0x30, 0x00, 0x00, 0xa7, 0x86, 0x87, 0xfb, 0x22, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0x0e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x14, 0xb0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, ++ 0x0b, 0x96, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, 0x4a, 0x86, 0x22, 0x41, ++ 0x81, 0x6c, 0x00, 0x00, 0x3e, 0x86, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x49, 0x86, 0x22, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x04, 0x7e, 0x89, 0x01, 0x00, ++ 0x42, 0x86, 0xa6, 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x5f, 0x95, 0x00, 0x40, ++ 0x05, 0x30, 0x01, 0x00, 0x47, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x84, 0xb0, 0x01, 0x00, 0xea, 0x96, 0x00, 0x40, ++ 0x05, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0x52, 0x86, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x86, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x52, 0x86, 0x22, 0x20, 0x85, 0x6c, 0x00, 0x00, 0x4f, 0x86, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x66, 0x96, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x85, 0x98, 0x00, 0x42, ++ 0x61, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xce, 0x99, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, ++ 0x56, 0x86, 0x21, 0x04, 0x80, 0x20, 0x00, 0x00, 0x57, 0x86, 0x00, 0x40, ++ 0x10, 0xc9, 0x00, 0x00, 0xa8, 0x8a, 0x00, 0x4b, 0x81, 0xb0, 0x00, 0x00, ++ 0x76, 0x86, 0x00, 0x43, 0x81, 0xb0, 0x00, 0x00, 0x7a, 0x86, 0x00, 0xfb, ++ 0x22, 0xb0, 0x00, 0x00, 0xa8, 0x8a, 0x00, 0x41, 0x81, 0xb0, 0x00, 0x00, ++ 0x66, 0x8b, 0x00, 0x4e, 0x8f, 0xb0, 0x00, 0x00, 0x72, 0x86, 0x00, 0x5a, ++ 0x8f, 0xb0, 0x00, 0x00, 0x5f, 0x86, 0x00, 0x47, 0x8f, 0xb0, 0x00, 0x00, ++ 0xa8, 0x8a, 0x00, 0x53, 0x81, 0xb0, 0x00, 0x00, 0xa8, 0x8a, 0x00, 0x56, ++ 0x81, 0xb0, 0x00, 0x00, 0x32, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x66, 0x8b, 0xa0, 0x0a, 0xe4, 0x6d, 0x00, 0x00, 0x65, 0x86, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x64, 0x86, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, ++ 0x66, 0x8b, 0x00, 0x53, 0x8f, 0xb0, 0x00, 0x00, 0x66, 0x8b, 0x00, 0x54, ++ 0x8f, 0xb0, 0x00, 0x00, 0x6e, 0x86, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, ++ 0x68, 0x86, 0xa2, 0x0a, 0xe4, 0x6d, 0x00, 0x00, 0x66, 0x8b, 0x00, 0x5d, ++ 0x8f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x80, 0xd0, 0x01, 0x00, 0x6c, 0x86, 0xa0, 0x91, ++ 0x81, 0x6c, 0x00, 0x00, 0x66, 0x8b, 0x00, 0x5e, 0x8f, 0xb0, 0x00, 0x00, ++ 0x25, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x70, 0x86, 0x20, 0x91, 0xe5, 0x6d, 0x00, 0x00, ++ 0x66, 0x8b, 0x00, 0x54, 0x8f, 0xb0, 0x00, 0x00, 0x21, 0x00, 0x00, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x66, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x32, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x66, 0x8b, 0xa0, 0x0a, ++ 0xe4, 0x6d, 0x00, 0x00, 0x24, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x66, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x82, 0xf4, 0x01, 0x00, ++ 0xa8, 0x8a, 0xa0, 0x42, 0x83, 0x6c, 0x00, 0x00, 0xa8, 0x8a, 0x00, 0x54, ++ 0x81, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x0e, 0xb0, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, 0x16, 0x88, 0x01, 0x00, ++ 0x83, 0x86, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x3d, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0xff, 0x89, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0x95, 0x86, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, ++ 0x90, 0x86, 0xa2, 0x54, 0xfd, 0x7f, 0x00, 0x00, 0x88, 0x86, 0x22, 0x55, ++ 0xfd, 0x7f, 0x00, 0x00, 0x82, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x80, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x80, 0x86, 0x22, 0x53, ++ 0xfd, 0x7f, 0x00, 0x00, 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x96, 0xb0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4b, ++ 0x80, 0xf4, 0x01, 0x00, 0x0c, 0xbc, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x90, 0x86, 0x22, 0x43, 0x80, 0x6c, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4b, ++ 0x80, 0x88, 0x01, 0x00, 0x80, 0x86, 0xa2, 0x43, 0x80, 0x6c, 0x00, 0x00, ++ 0x7c, 0x96, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x91, 0x86, 0x43, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x94, 0x86, 0xa0, 0xf0, 0x30, 0x6f, 0x00, 0x00, ++ 0x86, 0x86, 0x1b, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x41, ++ 0x31, 0xc3, 0x01, 0x00, 0x90, 0x95, 0x00, 0x40, 0x25, 0x30, 0x01, 0x00, ++ 0x99, 0x86, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x66, 0x96, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, ++ 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x07, 0x18, 0xe4, 0x01, 0x00, 0x00, 0x08, 0x00, 0x0c, ++ 0xe0, 0x99, 0x01, 0x00, 0xce, 0x99, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0xa0, 0x86, 0x30, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, ++ 0x00, 0x02, 0x00, 0xa1, 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe6, 0x91, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xa8, 0x8a, 0x00, 0x40, ++ 0x81, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x28, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x14, 0xb0, 0x01, 0x00, 0xb1, 0x86, 0x22, 0x46, 0x23, 0x7c, 0x00, 0x00, ++ 0xad, 0x86, 0x22, 0x40, 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x1f, 0x90, 0x01, 0x00, 0xaf, 0x86, 0x22, 0x41, 0x87, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x1f, 0x90, 0x01, 0x00, 0xb1, 0x86, 0x22, 0x42, ++ 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x1f, 0x90, 0x01, 0x00, ++ 0xb1, 0x86, 0x47, 0x1b, 0x2c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, ++ 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x41, 0x41, 0xc3, 0x01, 0x00, ++ 0xe0, 0x86, 0x23, 0x92, 0x15, 0x6c, 0x00, 0x00, 0xe0, 0x86, 0xa2, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0xe4, 0x86, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, ++ 0x17, 0x00, 0x00, 0xd0, 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x27, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x0a, 0x24, 0xc8, 0x01, 0x00, ++ 0xc7, 0x95, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, 0xde, 0x86, 0x22, 0x08, ++ 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x12, 0x24, 0xcc, 0x01, 0x00, 0xba, 0x86, 0xaa, 0x41, ++ 0x27, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x80, 0xcc, 0x01, 0x00, ++ 0xda, 0x86, 0x26, 0x40, 0x23, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x60, 0x00, 0x00, 0x03, 0x84, 0xc8, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x48, 0xcd, 0x01, 0x00, 0x17, 0x00, 0x00, 0xd0, ++ 0xa2, 0xc9, 0x01, 0x00, 0xc7, 0x86, 0xa2, 0x40, 0x83, 0x6c, 0x00, 0x00, ++ 0xd3, 0x86, 0x00, 0x41, 0x83, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x42, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x68, 0x21, 0x38, 0x96, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x50, 0x49, 0xc1, 0x01, 0x00, 0xcc, 0x86, 0xa2, 0x44, ++ 0x23, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x20, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0xcf, 0x86, 0xa8, 0x42, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa3, 0xc1, 0x01, 0x00, 0xc5, 0x86, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0xda, 0x86, 0x22, 0x40, 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xd7, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0xee, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, 0x17, 0x00, 0x00, 0xd0, ++ 0x2a, 0xc8, 0x01, 0x00, 0xed, 0x86, 0x00, 0x17, 0x10, 0xb0, 0x00, 0x00, ++ 0xaa, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xe4, 0x86, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc7, 0x95, 0x00, 0x92, 0x25, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x31, 0xb0, 0x01, 0x00, 0xe4, 0x86, 0x22, 0x08, ++ 0x2e, 0x30, 0x00, 0x00, 0xed, 0x86, 0x00, 0x41, 0x27, 0xb0, 0x00, 0x00, ++ 0x80, 0x80, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x3d, 0x99, 0x00, 0x0a, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0xec, 0x86, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x88, 0x1c, 0xcc, 0x01, 0x00, 0x6b, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xff, 0x89, 0x00, 0x41, 0x3f, 0xc3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x01, ++ 0x80, 0xce, 0x01, 0x00, 0x01, 0x87, 0x2a, 0x40, 0x81, 0x30, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0xf6, 0x86, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, ++ 0xf6, 0x86, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0xf6, 0x86, 0xa3, 0x07, ++ 0x03, 0x6c, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0xf9, 0x86, 0xa3, 0x40, 0x02, 0x6c, 0x00, 0x00, 0x28, 0x00, 0x00, 0x01, ++ 0xf0, 0xcd, 0x01, 0x00, 0xfb, 0x86, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0xf0, 0xcd, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x0e, 0xcc, 0x01, 0x00, 0x28, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x00, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xff, 0x86, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x08, 0xb0, 0x01, 0x00, 0xa0, 0x01, 0x2d, 0x40, ++ 0x00, 0xc0, 0x01, 0x00, 0xe7, 0x88, 0x22, 0x0f, 0x42, 0x05, 0x00, 0x00, ++ 0x12, 0x87, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x0d, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x0a, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x12, 0x87, 0x22, 0x07, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, ++ 0x42, 0xc1, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa1, 0x46, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, 0xd1, 0x87, 0xa2, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x54, 0x29, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x0e, 0xb0, 0x01, 0x00, 0x42, 0x00, 0x00, 0x03, ++ 0x0a, 0xc8, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, 0x0c, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x24, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x01, 0x00, 0x12, 0x00, 0x00, 0x08, ++ 0x10, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0xfe, 0x7f, 0x00, 0x05, 0x44, 0xc9, 0x01, 0x00, 0x23, 0x87, 0x20, 0x94, ++ 0x15, 0x6c, 0x00, 0x00, 0x24, 0x87, 0x00, 0x94, 0xe5, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0xe4, 0xb1, 0x01, 0x00, 0x3d, 0x87, 0x22, 0x01, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0xa4, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x2a, 0x87, 0xa3, 0x07, 0x02, 0x6c, 0x00, 0x00, ++ 0x2b, 0x87, 0x68, 0x01, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x07, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x0a, 0xc0, 0x01, 0x00, 0x37, 0x87, 0x22, 0x40, ++ 0x03, 0x6c, 0x00, 0x00, 0x37, 0x87, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x5f, 0x87, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x34, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0x39, 0x87, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x5f, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x42, 0x87, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, ++ 0x43, 0x87, 0x68, 0x07, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, ++ 0x1a, 0xb0, 0x01, 0x00, 0x46, 0x87, 0x80, 0x08, 0xf0, 0x31, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x11, 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x1e, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x01, 0x1f, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, 0x4a, 0x87, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x7d, 0x87, 0x22, 0x0d, 0x14, 0x6c, 0x00, 0x00, ++ 0x50, 0x87, 0x22, 0x0d, 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x10, 0xc0, 0x01, 0x00, 0x54, 0x87, 0x00, 0x0d, 0x24, 0xd0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x2b, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0xa2, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x20, 0x10, 0xc8, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, 0x56, 0x87, 0x22, 0x42, ++ 0x23, 0x6c, 0x00, 0x00, 0x5f, 0x87, 0x00, 0x41, 0x23, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x57, 0x87, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x5d, 0x87, 0x22, 0x47, 0x1f, 0x7c, 0x00, 0x00, ++ 0xfb, 0x95, 0x00, 0x43, 0x23, 0x30, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x7d, 0x87, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, 0x7c, 0x87, 0xa2, 0x0d, ++ 0x0e, 0x50, 0x00, 0x00, 0x6b, 0x87, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x69, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x66, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x70, 0x87, 0x1f, 0xf0, 0x0e, 0x30, 0x00, 0x00, 0x24, 0x87, 0x00, 0x4c, ++ 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x5f, 0x0f, 0x80, 0x01, 0x00, ++ 0x24, 0x87, 0x23, 0x07, 0x14, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, ++ 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x79, 0x87, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, 0x24, 0x87, 0x00, 0x03, ++ 0x0c, 0xb0, 0x00, 0x00, 0x24, 0x87, 0x00, 0x0d, 0x18, 0xc0, 0x00, 0x00, ++ 0x04, 0x00, 0x2e, 0x14, 0x0a, 0xd0, 0x01, 0x00, 0x12, 0x00, 0x00, 0x05, ++ 0x48, 0xcd, 0x01, 0x00, 0xfe, 0x7f, 0x00, 0x05, 0x42, 0xc9, 0x01, 0x00, ++ 0x0c, 0x00, 0x2a, 0xf2, 0xe0, 0xb1, 0x01, 0x00, 0x83, 0x87, 0x22, 0x40, ++ 0x31, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x18, 0x38, 0x96, 0x01, 0x00, ++ 0x1e, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x81, 0x00, 0xf6, ++ 0x80, 0xce, 0x01, 0x00, 0x87, 0x87, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x43, 0xc1, 0x01, 0x00, 0x89, 0x87, 0x22, 0x0b, ++ 0xed, 0x6d, 0x00, 0x00, 0x08, 0x00, 0x00, 0xa1, 0x42, 0xc9, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xa1, 0x46, 0xc9, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xfa, ++ 0x94, 0x88, 0x01, 0x00, 0x02, 0x00, 0x00, 0x4a, 0x86, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf6, 0x0e, 0xb0, 0x01, 0x00, 0x91, 0x87, 0x22, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x1f, 0x43, 0x0e, 0x50, 0x00, 0x00, ++ 0x91, 0x87, 0xa0, 0x46, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xc0, 0x01, 0x00, 0x95, 0x87, 0x22, 0x48, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x91, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x0f, 0xa2, ++ 0x42, 0x31, 0x00, 0x00, 0x98, 0x87, 0x00, 0x40, 0x89, 0xb0, 0x00, 0x00, ++ 0x0c, 0x00, 0x00, 0xa2, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x95, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x82, 0xb0, 0x01, 0x00, 0x9b, 0x87, 0xa0, 0x41, ++ 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x91, 0xc0, 0x01, 0x00, ++ 0xa0, 0x87, 0x22, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0xa0, 0x87, 0xa0, 0x43, ++ 0x89, 0x6c, 0x00, 0x00, 0xa0, 0x87, 0x20, 0x45, 0x89, 0x6c, 0x00, 0x00, ++ 0xa0, 0x87, 0xa0, 0x41, 0x0e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x89, 0xc0, 0x01, 0x00, ++ 0x98, 0x87, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, 0xa9, 0x87, 0x22, 0x48, ++ 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x48, 0x92, 0xf4, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x48, 0x90, 0x88, 0x01, 0x00, 0xa7, 0x87, 0x90, 0x48, ++ 0x92, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x93, 0xa4, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x14, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, ++ 0xf0, 0xb1, 0x01, 0x00, 0x12, 0x00, 0x00, 0x05, 0xe0, 0xcd, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, ++ 0xaf, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xbc, 0x87, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x10, 0x48, 0xc1, 0x01, 0x00, 0xb9, 0x87, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xb6, 0x87, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xbc, 0x87, 0x87, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xfb, 0x95, 0x00, 0x41, 0x23, 0x40, 0x01, 0x00, ++ 0xbe, 0x87, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0x52, 0x89, 0x00, 0x17, ++ 0x10, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0xc1, 0x87, 0xa0, 0x07, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, 0xc5, 0x87, 0x90, 0xf2, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x10, 0x00, 0x00, 0x14, ++ 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2b, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x2a, 0x94, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xcf, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xcc, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x17, ++ 0x10, 0xdc, 0x01, 0x00, 0x52, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x90, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd5, 0x87, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x66, 0x96, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x05, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x3c, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x14, 0x02, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x34, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x32, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, 0x0a, 0xc8, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x0e, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, ++ 0x0c, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x1b, 0x88, 0x22, 0x01, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0xa4, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0xea, 0x87, 0xa3, 0x07, 0x02, 0x6c, 0x00, 0x00, ++ 0xeb, 0x87, 0x68, 0x01, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x07, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x0a, 0xc0, 0x01, 0x00, 0xfd, 0x87, 0x22, 0x40, ++ 0x03, 0x6c, 0x00, 0x00, 0xf7, 0x87, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x37, 0x88, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0xf4, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0xf9, 0x87, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x37, 0x88, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0xff, 0x87, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x22, 0x00, 0x00, 0x19, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x0f, 0x00, 0x00, 0xf2, 0x3a, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x3b, 0xe0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x14, 0x02, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x01, 0x00, 0x0b, 0x88, 0x23, 0x1a, ++ 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0xc0, 0x01, 0x00, ++ 0x37, 0x88, 0x00, 0x01, 0x34, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x2d, 0x1d, ++ 0x48, 0xc1, 0x01, 0x00, 0xf0, 0x00, 0x00, 0xf2, 0x30, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x31, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x02, 0xc0, 0x01, 0x00, 0x13, 0x88, 0x22, 0x1a, ++ 0x02, 0x50, 0x00, 0x00, 0x37, 0x88, 0x00, 0x01, 0x34, 0xc0, 0x00, 0x00, ++ 0x22, 0x00, 0x00, 0x19, 0x48, 0xc9, 0x01, 0x00, 0x02, 0x00, 0x2d, 0x14, ++ 0x48, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x14, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x14, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x14, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x24, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x17, 0x10, 0xc8, 0x01, 0x00, 0x37, 0x88, 0x00, 0x1a, ++ 0x10, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x20, 0x88, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, ++ 0x21, 0x88, 0x68, 0x07, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, ++ 0x1a, 0xb0, 0x01, 0x00, 0x24, 0x88, 0x80, 0x08, 0xf0, 0x31, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x11, 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x1e, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x01, 0x1f, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, 0x28, 0x88, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x54, 0x88, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, ++ 0x54, 0x88, 0x22, 0x0d, 0x24, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x10, 0xc0, 0x01, 0x00, 0x2f, 0x88, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x37, 0x88, 0x00, 0x41, 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x30, 0x88, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0xfb, 0x95, 0x00, 0x43, 0x23, 0x30, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x53, 0x88, 0xa2, 0x0d, 0x0e, 0x50, 0x00, 0x00, 0x42, 0x88, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x40, 0x88, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x3d, 0x88, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x04, 0xb0, 0x01, 0x00, 0x47, 0x88, 0x1f, 0xf0, 0x0e, 0x30, 0x00, 0x00, ++ 0xe4, 0x87, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x5f, ++ 0x0f, 0x80, 0x01, 0x00, 0xe4, 0x87, 0x23, 0x07, 0x14, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x50, 0x88, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0xe4, 0x87, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, 0xe4, 0x87, 0x00, 0x0d, ++ 0x18, 0xc0, 0x00, 0x00, 0x71, 0x88, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x19, 0x0a, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x0a, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x02, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0x0d, 0x00, 0x2d, 0x1d, 0x48, 0xc1, 0x01, 0x00, ++ 0x09, 0x00, 0x00, 0xf3, 0x38, 0x88, 0x01, 0x00, 0x0d, 0x00, 0x20, 0x50, ++ 0xe7, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x2d, 0x40, 0x3f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf4, 0x32, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, 0x02, 0x00, 0x00, 0x1d, ++ 0x94, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, 0xb0, 0x01, 0x00, ++ 0x66, 0x88, 0xa0, 0xfc, 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xc0, 0x01, 0x00, 0x64, 0x88, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, ++ 0x04, 0x80, 0x00, 0x05, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x48, 0xc1, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x18, 0x94, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x18, ++ 0x90, 0xb0, 0x01, 0x00, 0x6e, 0x88, 0xa0, 0xfc, 0x90, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x91, 0xc0, 0x01, 0x00, 0x6c, 0x88, 0xa2, 0x41, ++ 0x95, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xe0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x05, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x16, 0xc0, 0x01, 0x00, ++ 0x76, 0x88, 0x42, 0x30, 0x3d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x41, 0x3d, 0xc3, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x42, 0xec, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, ++ 0x82, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x2e, 0x1d, 0x82, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x18, 0x82, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x80, 0xc0, 0x01, 0x00, 0x80, 0x88, 0xa0, 0x41, 0x80, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, ++ 0x92, 0xf4, 0x01, 0x00, 0x0a, 0x00, 0x2e, 0x30, 0x81, 0x84, 0x01, 0x00, ++ 0x84, 0x88, 0x90, 0x40, 0x92, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x93, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x93, 0xa4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x48, 0xc1, 0x01, 0x00, 0x04, 0x00, 0x20, 0x19, ++ 0xe8, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x16, 0xc0, 0x01, 0x00, ++ 0x8a, 0x88, 0xa0, 0x19, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x0d, 0x00, 0x2f, 0x1e, 0x32, 0xc0, 0x01, 0x00, ++ 0x8f, 0x88, 0xa2, 0x40, 0x15, 0x6c, 0x00, 0x00, 0x8e, 0x88, 0xa0, 0x1c, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0xf3, 0x38, 0x94, 0x01, 0x00, 0x10, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x1e, 0x98, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x1a, 0x98, 0xc0, 0x01, 0x00, 0x0c, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x9d, 0x88, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x9b, 0x88, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x98, 0x88, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x12, 0x00, 0x00, 0x1a, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, 0xa3, 0x88, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xb1, 0x88, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0xad, 0x88, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xaa, 0x88, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0xfb, 0x95, 0x00, 0x41, 0x23, 0x40, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0x20, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x17, 0xf0, 0x01, 0x00, 0xb6, 0x88, 0x90, 0xf2, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x17, 0xa4, 0x01, 0x00, 0x10, 0x00, 0x00, 0x14, 0x2a, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x2a, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x2b, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2a, 0x94, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xc1, 0x88, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xbe, 0x88, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x17, 0x10, 0xdc, 0x01, 0x00, 0xde, 0x88, 0x22, 0x40, ++ 0x15, 0x6c, 0x00, 0x00, 0xc9, 0x88, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x1f, 0x90, 0x01, 0x00, 0xc8, 0x88, 0x22, 0x9f, ++ 0x13, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x88, 0x1c, 0xcc, 0x01, 0x00, ++ 0x6b, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x3f, 0xc3, 0x01, 0x00, 0x4e, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xcc, 0x88, 0xa2, 0x41, 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, ++ 0x3e, 0xc0, 0x01, 0x00, 0xde, 0x88, 0x22, 0x40, 0x15, 0x6c, 0x00, 0x00, ++ 0xcf, 0x88, 0x20, 0x1e, 0x14, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x3c, 0xb0, 0x01, 0x00, 0xc7, 0x95, 0x00, 0x1e, 0x24, 0x30, 0x01, 0x00, ++ 0xd4, 0x88, 0x22, 0x08, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x11, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x10, 0xc0, 0x01, 0x00, ++ 0x37, 0x88, 0x00, 0x40, 0x17, 0xb0, 0x00, 0x00, 0x6b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xc7, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd1, 0x88, 0xa2, 0x08, 0x2e, 0x30, 0x00, 0x00, 0x80, 0x80, 0x00, 0xa6, ++ 0x04, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, 0x04, 0x00, 0x22, 0x04, ++ 0xe0, 0x31, 0x00, 0x00, 0x3d, 0x99, 0x00, 0x1f, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0xff, 0x89, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x04, 0xe0, 0x31, 0x00, 0x00, 0x4e, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe3, 0x88, 0xa2, 0x41, 0x87, 0x7c, 0x00, 0x00, ++ 0xe4, 0x88, 0x00, 0x1e, 0x3e, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x3d, 0x99, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, 0xff, 0x89, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0xef, 0x88, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xef, 0x88, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xec, 0x88, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xf4, 0x88, 0x22, 0x07, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x42, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x42, 0xc1, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa1, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x04, 0x00, 0x2e, 0x03, 0x48, 0xb1, 0x01, 0x00, 0xf7, 0x88, 0x20, 0x94, ++ 0x15, 0x6c, 0x00, 0x00, 0xf8, 0x88, 0x00, 0x94, 0xe1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0xe0, 0xb1, 0x01, 0x00, 0xfb, 0x88, 0x22, 0x40, ++ 0x31, 0x6c, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x18, 0x38, 0x96, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x89, 0xa8, 0x40, ++ 0x23, 0x30, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x52, 0x11, 0xc0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x0e, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, 0x0c, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xc1, 0x01, 0x00, ++ 0x0e, 0x89, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, 0x0f, 0x89, 0x68, 0x07, ++ 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, 0x1a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x01, 0x1f, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, ++ 0x14, 0x89, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, 0x45, 0x89, 0x22, 0x0d, ++ 0x14, 0x6c, 0x00, 0x00, 0x1a, 0x89, 0x22, 0x0d, 0x24, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x10, 0xc0, 0x01, 0x00, 0x1e, 0x89, 0x00, 0x0d, ++ 0x24, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2b, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0xa2, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x20, ++ 0x10, 0xc8, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, ++ 0x20, 0x89, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, 0x27, 0x89, 0x00, 0x41, ++ 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x21, 0x89, 0xa8, 0x5c, ++ 0x1f, 0x00, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x48, 0xb1, 0x01, 0x00, 0xc2, 0x94, 0x00, 0x43, ++ 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, 0x44, 0x89, 0xa2, 0x0d, ++ 0x0e, 0x50, 0x00, 0x00, 0x33, 0x89, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x31, 0x89, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x2e, 0x89, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x38, 0x89, 0x1f, 0xf0, 0x0e, 0x30, 0x00, 0x00, 0x09, 0x89, 0x00, 0x4c, ++ 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x5f, 0x0f, 0x80, 0x01, 0x00, ++ 0x09, 0x89, 0x23, 0x07, 0x14, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, ++ 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x41, 0x89, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, 0x09, 0x89, 0x00, 0x03, ++ 0x0c, 0xb0, 0x00, 0x00, 0x09, 0x89, 0x00, 0x0d, 0x18, 0xc0, 0x00, 0x00, ++ 0x4e, 0x89, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x10, 0x48, 0xc1, 0x01, 0x00, 0x4e, 0x89, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x4b, 0x89, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x48, 0xb1, 0x01, 0x00, 0xc2, 0x94, 0x00, 0x41, ++ 0x23, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, 0x10, 0xb0, 0x01, 0x00, ++ 0x52, 0x89, 0x00, 0x40, 0x2b, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe0, 0xb1, 0x01, 0x00, ++ 0x57, 0x89, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x88, ++ 0x1c, 0xcc, 0x01, 0x00, 0x6b, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x4e, 0x99, 0x00, 0x41, 0x3f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x3d, 0x99, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, 0x15, 0x8a, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0xf4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x3a, 0x01, 0x84, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0x0b, 0x96, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, ++ 0x66, 0x89, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, 0x64, 0x89, 0x22, 0x42, ++ 0x81, 0x6c, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x65, 0x89, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, 0xff, 0x89, 0x00, 0x40, ++ 0x0f, 0xb0, 0x00, 0x00, 0x6e, 0x89, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x86, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x6e, 0x89, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0x6b, 0x89, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x66, 0x96, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0x85, 0x98, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xce, 0x99, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x80, 0xb0, 0x01, 0x00, 0xa8, 0x8a, 0xa2, 0x5f, 0x81, 0x6c, 0x00, 0x00, ++ 0xa8, 0x00, 0x2d, 0x43, 0x19, 0x80, 0x01, 0x00, 0x37, 0x00, 0x2d, 0xf0, ++ 0x24, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x8e, 0xf4, 0x01, 0x00, ++ 0x0f, 0x00, 0x00, 0xf3, 0x90, 0x88, 0x01, 0x00, 0x7d, 0x89, 0x22, 0x48, ++ 0x8e, 0x6c, 0x00, 0x00, 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0x7d, 0x89, 0x1f, 0xf0, ++ 0x24, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x23, 0x41, 0x8f, 0x6c, 0x00, 0x00, ++ 0xa8, 0x8a, 0x00, 0x47, 0x81, 0xb0, 0x00, 0x00, 0xa8, 0x8a, 0x00, 0x48, ++ 0x81, 0xb0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xb0, 0x00, 0x2d, 0xf0, 0x14, 0xb0, 0x01, 0x00, 0x82, 0x89, 0x22, 0x0a, ++ 0x90, 0x40, 0x00, 0x00, 0x21, 0x99, 0x00, 0x40, 0x91, 0x30, 0x01, 0x00, ++ 0xa8, 0x8a, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0xb0, 0x00, 0x2d, 0x45, ++ 0x81, 0xb0, 0x01, 0x00, 0x8e, 0x89, 0x22, 0xf0, 0x2c, 0x30, 0x00, 0x00, ++ 0xa3, 0x00, 0x2d, 0x30, 0x83, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x2d, 0xf3, ++ 0x82, 0xe0, 0x01, 0x00, 0x88, 0x89, 0xa3, 0x41, 0x2c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x82, 0xb0, 0x01, 0x00, 0x98, 0x00, 0x2d, 0xf0, ++ 0x82, 0xc0, 0x01, 0x00, 0x88, 0x00, 0x2d, 0xf0, 0x82, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x98, 0xe8, 0x01, 0x00, 0xa8, 0x8a, 0x20, 0x4c, ++ 0x82, 0x6c, 0x00, 0x00, 0x7c, 0x00, 0x2d, 0x41, 0x98, 0xe8, 0x01, 0x00, ++ 0xa8, 0x8a, 0x20, 0xf0, 0x98, 0x6c, 0x00, 0x00, 0xff, 0x89, 0x22, 0x0a, ++ 0x80, 0x32, 0x00, 0x00, 0x40, 0x02, 0x00, 0x0c, 0x7e, 0x89, 0x01, 0x00, ++ 0xff, 0x89, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xa8, 0x8a, 0x00, 0x49, ++ 0x81, 0xb0, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, ++ 0x96, 0x89, 0x22, 0x43, 0x21, 0x6f, 0x00, 0x00, 0x13, 0x80, 0x00, 0x40, ++ 0x80, 0xdc, 0x01, 0x00, 0x97, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x1a, 0x80, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, 0x97, 0x89, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0xb1, 0x01, 0x00, ++ 0x99, 0x89, 0x9f, 0x85, 0x80, 0x32, 0x00, 0x00, 0x9d, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x5f, 0x84, 0x22, 0x40, 0x57, 0x7d, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x40, 0x57, 0x99, 0x01, 0x00, 0x9d, 0x89, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x49, 0x84, 0x1a, 0x5b, 0x69, 0x93, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xa0, 0x89, 0xa8, 0xb1, 0x80, 0x30, 0x00, 0x00, ++ 0xc9, 0x89, 0x1d, 0x40, 0x80, 0x32, 0x00, 0x00, 0xba, 0x89, 0x22, 0x40, ++ 0xaf, 0x6f, 0x00, 0x00, 0xba, 0x89, 0x22, 0x5b, 0x81, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x5d, 0x73, 0x7d, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xa6, 0x89, 0xa8, 0xb1, 0x94, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x62, 0xb1, 0x01, 0x00, 0xa9, 0x89, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xab, 0x89, 0x43, 0x40, 0x81, 0x32, 0x00, 0x00, 0xb9, 0x89, 0x22, 0x57, ++ 0x73, 0x7d, 0x00, 0x00, 0x77, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xad, 0x89, 0xa8, 0xb1, 0x94, 0x30, 0x00, 0x00, 0x77, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xaf, 0x89, 0xa8, 0xb1, 0x96, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x62, 0xb1, 0x01, 0x00, 0xb2, 0x89, 0xa8, 0x4a, 0x80, 0x33, 0x00, 0x00, ++ 0xb7, 0x89, 0x22, 0x5f, 0x95, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0xb5, 0x89, 0xa8, 0x4b, 0xac, 0x33, 0x00, 0x00, ++ 0x00, 0x00, 0x1b, 0xa5, 0x82, 0xb3, 0x01, 0x00, 0xba, 0x89, 0x00, 0xbe, ++ 0x83, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x40, 0x81, 0xb3, 0x01, 0x00, ++ 0x40, 0x18, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0xc7, 0x89, 0xa2, 0x40, 0x86, 0x04, 0x00, 0x00, ++ 0x1b, 0x84, 0x9c, 0x40, 0x80, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x40, ++ 0x88, 0x88, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x50, 0x47, 0x31, 0x01, 0x00, ++ 0x36, 0x00, 0x00, 0x44, 0x88, 0xcc, 0x01, 0x00, 0xc3, 0x89, 0x52, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x89, 0x00, 0x40, 0x47, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x89, 0xb0, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x48, ++ 0x47, 0x31, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x05, 0x47, 0x31, 0x01, 0x00, ++ 0x1b, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x41, 0xe1, 0xc1, 0x00, 0x00, ++ 0x78, 0x18, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, 0xd0, 0x89, 0x22, 0x54, ++ 0x81, 0x7c, 0x00, 0x00, 0xcb, 0x89, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0xb4, 0x69, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xe3, 0x89, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, 0xde, 0x89, 0x0f, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x40, 0x88, 0x88, 0x01, 0x00, ++ 0xe3, 0x89, 0x00, 0x50, 0x47, 0x31, 0x01, 0x00, 0x36, 0x00, 0x00, 0x44, ++ 0x88, 0xcc, 0x01, 0x00, 0xd6, 0x89, 0x99, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x89, 0xd0, 0x01, 0x00, 0xd8, 0x89, 0x9b, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xd0, 0x01, 0x00, ++ 0xda, 0x89, 0x1f, 0x44, 0x80, 0x32, 0x00, 0x00, 0xe3, 0x89, 0x00, 0x40, ++ 0x47, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x89, 0xb0, 0x01, 0x00, ++ 0xe3, 0x89, 0x00, 0x48, 0x47, 0x31, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x58, ++ 0x47, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x86, 0xf4, 0x01, 0x00, 0x6f, 0x00, 0x00, 0x43, ++ 0x86, 0x88, 0x01, 0x00, 0x1b, 0x84, 0x26, 0x05, 0x47, 0x31, 0x00, 0x00, ++ 0xe3, 0x89, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x44, 0xf0, 0x41, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0xe1, 0xc1, 0x01, 0x00, 0x04, 0x00, 0x00, 0xcb, 0x81, 0xc8, 0x01, 0x00, ++ 0xe9, 0x89, 0x22, 0x40, 0xf2, 0x7f, 0x00, 0x00, 0x81, 0x80, 0x00, 0x6f, ++ 0x97, 0x33, 0x01, 0x00, 0xeb, 0x89, 0x22, 0x40, 0x73, 0x7d, 0x00, 0x00, ++ 0x9b, 0x80, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, 0xe6, 0x89, 0x22, 0x59, ++ 0x73, 0x7d, 0x00, 0x00, 0x79, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xe6, 0x89, 0x28, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0xec, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x22, 0xc0, 0x95, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd6, 0x97, 0xb0, 0x01, 0x00, 0xf4, 0x89, 0x22, 0x5d, ++ 0x73, 0x7d, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xf2, 0x89, 0xa8, 0xb1, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x7f, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xc5, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x25, 0x01, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf7, 0x89, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0xf9, 0x89, 0x43, 0x5f, 0x7f, 0x13, 0x00, 0x00, 0x26, 0x01, 0x00, 0xbf, ++ 0xc5, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x7f, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5e, 0x7f, 0x93, 0x01, 0x00, 0x75, 0x98, 0x00, 0xbf, ++ 0xc5, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x06, 0x8a, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x06, 0x8a, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x03, 0x8a, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x62, 0x95, 0x22, 0x02, ++ 0x80, 0x32, 0x00, 0x00, 0x07, 0x8a, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0x62, 0x95, 0x1a, 0x02, ++ 0x68, 0x97, 0x00, 0x00, 0x11, 0x8a, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x11, 0x8a, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x0e, 0x8a, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x6c, 0x95, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, 0x12, 0x8a, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x6c, 0x95, 0x1a, 0x02, 0x68, 0x97, 0x00, 0x00, 0x1c, 0x8a, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x1c, 0x8a, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x19, 0x8a, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x6f, 0x84, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0x1d, 0x8a, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x68, 0x97, 0x01, 0x00, ++ 0x6f, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, ++ 0x56, 0xb1, 0x01, 0x00, 0x56, 0x95, 0x2f, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x6d, 0x8a, 0xa2, 0x40, 0xe7, 0x6d, 0x00, 0x00, 0xb8, 0x94, 0x29, 0x41, ++ 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0xef, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x0e, 0xb0, 0x01, 0x00, 0x29, 0x00, 0x00, 0x40, ++ 0x0d, 0x98, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, 0x12, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa7, 0x13, 0xc0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, 0x16, 0x88, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x10, 0x34, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x34, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x20, 0x18, 0x00, 0x40, 0x11, 0x98, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x51, 0x8a, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x32, 0x8a, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x07, ++ 0x84, 0x89, 0x01, 0x00, 0x39, 0x8a, 0x05, 0xc2, 0x24, 0x30, 0x00, 0x00, ++ 0x51, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x6e, 0x8a, 0x1c, 0xf0, 0x18, 0x30, 0x01, 0x00, ++ 0x51, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x48, 0x8a, 0xa0, 0x48, 0x23, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x35, 0xd0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x1a, ++ 0x42, 0xc9, 0x01, 0x00, 0x42, 0x8a, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x1a, ++ 0x62, 0xdd, 0x01, 0x00, 0x3f, 0x8a, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x6e, 0x8a, 0x00, 0xf8, 0x18, 0x30, 0x01, 0x00, ++ 0x43, 0x8a, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, 0xff, 0xff, 0x00, 0x10, ++ 0x34, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x34, 0x94, 0x01, 0x00, ++ 0x20, 0x18, 0x00, 0x40, 0x11, 0x98, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x1a, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x1a, 0x62, 0xdd, 0x01, 0x00, ++ 0x4c, 0x8a, 0xa8, 0x09, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x35, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x11, 0xc0, 0x01, 0x00, 0x5d, 0x8a, 0x22, 0x41, ++ 0x0d, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, ++ 0x59, 0x8a, 0xa0, 0xaa, 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xb0, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, 0x12, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa7, 0x13, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1b, 0xb0, 0x01, 0x00, 0x30, 0x8a, 0x00, 0x41, 0x17, 0xb0, 0x00, 0x00, ++ 0x00, 0x02, 0x00, 0x09, 0x12, 0xc8, 0x01, 0x00, 0x30, 0x8a, 0x83, 0x41, ++ 0x17, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x30, 0x8a, 0x00, 0x41, 0x1b, 0xc0, 0x00, 0x00, 0x68, 0x8a, 0x23, 0x40, ++ 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x35, 0xd0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x1a, 0x42, 0xc9, 0x01, 0x00, 0x65, 0x8a, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x1a, 0x62, 0xdd, 0x01, 0x00, 0x62, 0x8a, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x6e, 0x8a, 0x00, 0xf8, ++ 0x18, 0x30, 0x01, 0x00, 0x66, 0x8a, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, 0x6b, 0x8a, 0xa0, 0xaa, ++ 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xb0, 0x01, 0x00, ++ 0xb8, 0x94, 0x20, 0x07, 0xe4, 0xb1, 0x01, 0x00, 0x56, 0x95, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xff, 0x89, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x0c, 0x80, 0xd8, 0x01, 0x00, 0xc0, 0x02, 0x00, 0x0c, ++ 0x7e, 0x89, 0x01, 0x00, 0x80, 0x8a, 0x26, 0x54, 0x61, 0x31, 0x00, 0x00, ++ 0x76, 0x8a, 0x87, 0x0c, 0x80, 0x32, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x40, ++ 0x62, 0x99, 0x01, 0x00, 0x76, 0x8a, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x76, 0x8a, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, 0x72, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x7b, 0x8a, 0x22, 0x46, 0x19, 0x7c, 0x00, 0x00, ++ 0x0d, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x01, 0x00, ++ 0x77, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x80, 0x8a, 0x22, 0x49, ++ 0x19, 0x7c, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x54, ++ 0x77, 0x7d, 0x01, 0x00, 0x7b, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x01, 0x00, ++ 0x80, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x30, 0x94, 0x2f, 0x55, ++ 0xf1, 0x93, 0x01, 0x00, 0x00, 0x40, 0x00, 0xa6, 0x56, 0xb1, 0x01, 0x00, ++ 0x6f, 0x84, 0xa2, 0x41, 0xe5, 0x51, 0x00, 0x00, 0x64, 0x00, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x88, 0x8a, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x8b, 0x8a, 0xa2, 0x93, 0x57, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x57, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x1a, 0xab, 0x27, 0xb3, 0x01, 0x00, ++ 0x6f, 0x84, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0x6f, 0x84, 0x22, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0x6f, 0x84, 0xa2, 0x41, 0x1d, 0x53, 0x00, 0x00, ++ 0x50, 0x46, 0x00, 0x40, 0x1d, 0x9b, 0x01, 0x00, 0x34, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0x97, 0x8a, 0x22, 0x40, ++ 0xb5, 0x6f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0xff, 0x81, 0x00, 0x41, 0xb5, 0x53, 0x01, 0x00, 0x6f, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xfd, 0x83, 0x01, 0x00, ++ 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x35, 0x82, 0x00, 0x40, ++ 0x49, 0x31, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0xfc, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x91, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0xff, 0x81, 0x00, 0x40, 0xb5, 0x33, 0x01, 0x00, 0x60, 0x16, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xdb, 0x82, 0x00, 0x40, 0xb5, 0x33, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4a, ++ 0xb4, 0x8b, 0x01, 0x00, 0xff, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4a, ++ 0xb4, 0xf7, 0x01, 0x00, 0xff, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6f, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x08, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x40, 0xe6, 0xb1, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x96, 0xc0, 0x01, 0x00, ++ 0xae, 0x8a, 0x00, 0x4b, 0x10, 0xc9, 0x00, 0x00, 0xd1, 0x8d, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x05, 0x8e, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x37, 0x8e, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x37, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x37, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x37, 0x8e, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x76, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x9f, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xa3, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x0b, 0x90, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xaf, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xae, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x6f, 0x8f, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x6f, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x6f, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x9b, 0x8f, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xb9, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xb9, 0x8f, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xb9, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xe1, 0x8f, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0xf2, 0x8f, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0xf2, 0x8f, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xf4, 0x8f, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0xf4, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xf4, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xf4, 0x8f, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xfc, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x0d, 0x90, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0xfd, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x0d, 0x90, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x0e, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x90, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x6d, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x6d, 0x8f, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x6d, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x0f, 0x90, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x0f, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x0f, 0x90, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x16, 0x90, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x18, 0x90, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x24, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x8d, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xa3, 0x8e, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x0b, 0x90, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x95, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xa3, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x0b, 0x90, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xa6, 0x90, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x73, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x91, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xa3, 0x8e, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x0b, 0x90, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x08, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x20, 0x47, ++ 0xe6, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x47, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x96, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x96, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x96, 0xc0, 0x01, 0x00, ++ 0x6e, 0x8b, 0x00, 0x4b, 0x10, 0xc9, 0x00, 0x00, 0xbe, 0x90, 0x00, 0x49, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xf7, 0x90, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xfd, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x0b, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x27, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2f, 0x91, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x87, 0x91, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x86, 0x91, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x49, 0x09, 0xb0, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xe6, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xe6, 0x91, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xe6, 0x91, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xfe, 0x91, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x15, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xf2, 0x91, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x6a, 0x94, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x0b, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x27, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x87, 0x91, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x2f, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x86, 0x91, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x1b, 0x92, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x1b, 0x92, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0xba, 0x8d, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xba, 0x8d, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x1b, 0x92, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x00, 0x91, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, 0x3e, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x26, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x26, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x26, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x3e, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x26, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x4d, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x4d, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xaf, 0x92, 0x00, 0x40, 0x09, 0xb0, 0x00, 0x00, 0xcc, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xc0, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x1e, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x1e, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xcc, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xd3, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0xd3, 0x92, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xc0, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x1e, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x1e, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xc0, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xe6, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xe6, 0x91, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0xe6, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xe6, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xe6, 0x91, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x3d, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x31, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x25, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x3d, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0xba, 0x8d, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xba, 0x8d, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x31, 0x92, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x31, 0x92, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd5, 0x92, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd5, 0x92, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xd5, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0xd5, 0x92, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xef, 0x92, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x15, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xef, 0x92, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xf6, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x15, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xf6, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xf6, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x19, 0x94, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x18, 0x94, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x19, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x18, 0x94, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xe0, 0x92, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xec, 0x92, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xec, 0x92, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xec, 0x92, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xec, 0x92, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xec, 0x92, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0xec, 0x92, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0xec, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xec, 0x92, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xec, 0x92, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xfe, 0x91, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x15, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xf2, 0x91, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xb8, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x5f, 0x94, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5f, 0x94, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x5f, 0x94, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5f, 0x94, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x5f, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x5f, 0x94, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xf2, 0x91, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x6a, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xf2, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x15, 0x92, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x6a, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x6a, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x6e, 0x94, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x15, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xb0, 0x94, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x6e, 0x94, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x7f, 0x94, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5d, 0x94, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x7f, 0x94, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5d, 0x94, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x90, 0x94, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x15, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x90, 0x94, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x90, 0x94, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x0b, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x91, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xae, 0x94, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x0b, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xae, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xb0, 0x94, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x15, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xb0, 0x94, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x6b, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x6b, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x15, 0x92, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x6b, 0x94, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x6b, 0x94, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xb6, 0x94, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x5d, 0x94, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xb6, 0x94, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x5d, 0x94, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2f, 0x91, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2f, 0x91, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x25, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x25, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x2e, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x0a, 0x8a, 0x00, 0x04, 0xe6, 0xb1, 0x00, 0x00, ++ 0xba, 0x8d, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xba, 0x8d, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0x21, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xca, 0x8d, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xca, 0x8d, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xc7, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x13, 0x86, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0xcb, 0x8d, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x68, 0x97, 0x01, 0x00, ++ 0x13, 0x86, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x05, 0x00, 0x2e, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x0a, 0x8a, 0x00, 0x04, 0xe6, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0xa1, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xe0, 0xb1, 0x01, 0x00, 0x3d, 0x99, 0x00, 0x06, 0x07, 0x40, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0x07, 0xd0, 0x01, 0x00, 0xd4, 0x00, 0x2e, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0xb1, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0x96, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0x96, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x96, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x96, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x96, 0xc0, 0x01, 0x00, 0x00, 0x30, 0x00, 0x4b, ++ 0x94, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x95, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x96, 0xc0, 0x01, 0x00, 0x5e, 0x01, 0x2e, 0x34, ++ 0x97, 0x84, 0x01, 0x00, 0x02, 0x00, 0x00, 0x4b, 0xe4, 0xe5, 0x01, 0x00, ++ 0x64, 0x01, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x86, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x2e, 0xa7, 0x87, 0xc0, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x58, 0x01, 0x00, 0x43, 0xf0, 0xc9, 0x01, 0x00, ++ 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0xf4, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x08, 0x00, 0x2e, 0x40, 0x95, 0xb0, 0x01, 0x00, 0xfc, 0x8d, 0x20, 0x4b, ++ 0x94, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0xf9, 0x8d, 0x00, 0x41, 0x95, 0xc0, 0x00, 0x00, 0x10, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x03, 0x8e, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xff, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xaf, 0x97, 0x00, 0x40, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x88, 0xb0, 0x01, 0x00, 0x08, 0x8e, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x0b, 0x8e, 0xa2, 0x4c, 0xfd, 0x7f, 0x00, 0x00, ++ 0x0c, 0x8e, 0x00, 0x4c, 0xfd, 0x93, 0x00, 0x00, 0x0d, 0x8e, 0x20, 0xf0, ++ 0x56, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x56, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x64, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x70, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x13, 0x8e, 0xa8, 0x44, ++ 0xe0, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x8c, 0xc8, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x46, 0x44, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x68, 0x01, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x43, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x62, 0xb1, 0x01, 0x00, ++ 0x1b, 0x8e, 0xa8, 0x44, 0xe0, 0x31, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x09, 0x00, 0x00, 0x07, 0x86, 0xe4, 0x01, 0x00, ++ 0x38, 0x00, 0x2e, 0xa7, 0x87, 0xc0, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x23, 0x8e, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, 0x26, 0x8e, 0x22, 0x44, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x45, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x19, 0x90, 0x01, 0x00, 0x68, 0x01, 0x20, 0xa2, ++ 0xe4, 0xb1, 0x01, 0x00, 0x88, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x2a, 0x8e, 0x23, 0x0b, 0xe5, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x19, 0x90, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x50, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x58, 0x01, 0x00, 0x43, ++ 0xf0, 0xc9, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x2f, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x5c, 0x00, 0x2e, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xf0, 0x96, 0xb0, 0x01, 0x00, 0xaf, 0x97, 0x00, 0x41, ++ 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x3a, 0x8e, 0xa2, 0x49, 0x19, 0x7c, 0x00, 0x00, 0x86, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x3e, 0x8e, 0x00, 0x40, 0xe5, 0xb1, 0x00, 0x00, ++ 0x86, 0x00, 0x2f, 0x49, 0x19, 0x80, 0x01, 0x00, 0x3e, 0x8e, 0xa2, 0xf2, ++ 0x80, 0x32, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xe7, 0x91, 0x01, 0x00, 0x41, 0x8e, 0xa2, 0x46, ++ 0x19, 0x7c, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x45, 0x8e, 0x00, 0x40, 0xe5, 0xb1, 0x00, 0x00, 0xa0, 0x00, 0x2f, 0x46, ++ 0x19, 0x80, 0x01, 0x00, 0x45, 0x8e, 0xa2, 0xf2, 0x80, 0x32, 0x00, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe7, 0x91, 0x01, 0x00, 0xa8, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x34, 0x00, 0x2d, 0xf0, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0x0c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x12, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, ++ 0x16, 0x88, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x14, 0xf4, 0x01, 0x00, ++ 0x70, 0x8e, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x58, 0x8e, 0x22, 0x0a, ++ 0x16, 0x6c, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, ++ 0x84, 0x30, 0x00, 0x00, 0xe7, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x13, 0xc0, 0x01, 0x00, ++ 0x57, 0x8e, 0xa0, 0x43, 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0x4d, 0x8e, 0x00, 0x41, 0x15, 0xd0, 0x00, 0x00, ++ 0x70, 0x8e, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, ++ 0x13, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x84, 0x30, 0x00, 0x00, 0xe7, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x70, 0x8e, 0x22, 0x41, 0x15, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x11, 0xc0, 0x01, 0x00, 0x64, 0x8e, 0xa0, 0x43, ++ 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x11, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x36, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x00, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x83, 0xb0, 0x01, 0x00, 0xee, 0x97, 0x00, 0x47, ++ 0x61, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x5f, 0x95, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x6c, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x60, 0x8e, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x37, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x20, 0x98, 0x00, 0x51, ++ 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x34, 0x00, 0x2e, 0x41, 0xf5, 0xb1, 0x01, 0x00, 0x00, 0x11, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x78, 0x8e, 0x00, 0x48, 0x19, 0x90, 0x00, 0x00, ++ 0x34, 0x00, 0x2e, 0x41, 0xf5, 0xb1, 0x01, 0x00, 0x00, 0x11, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x7d, 0x8e, 0x22, 0x45, ++ 0x23, 0x7c, 0x00, 0x00, 0xb0, 0x00, 0x2f, 0xf0, 0x8c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xf0, 0x8c, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x35, 0x00, 0x2d, 0xf0, 0x8c, 0xb0, 0x01, 0x00, ++ 0x58, 0x00, 0x3e, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0x82, 0x8e, 0x22, 0x48, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8d, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x0a, 0x8c, 0xc0, 0x01, 0x00, 0x38, 0x00, 0x2a, 0x4a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0x3c, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x38, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x26, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf8, ++ 0x02, 0x30, 0x00, 0x00, 0x90, 0x8e, 0x23, 0x01, 0x14, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x4c, 0x00, 0x20, 0xf0, 0xe4, 0xb1, 0x01, 0x00, ++ 0x44, 0x00, 0x20, 0x40, 0xe0, 0xb1, 0x01, 0x00, 0x48, 0x00, 0x20, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x21, 0x99, 0x00, 0xf0, 0x24, 0x30, 0x01, 0x00, 0x99, 0x8e, 0xa2, 0x44, ++ 0x81, 0x6c, 0x00, 0x00, 0x97, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x8a, 0x96, 0x00, 0x40, 0x3b, 0x30, 0x01, 0x00, 0xbd, 0x8e, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0x99, 0x8e, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc7, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xbd, 0x8e, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0x50, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x20, 0x01, ++ 0xe4, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, ++ 0x20, 0x98, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x69, 0x96, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, 0x78, 0x8e, 0x22, 0x4a, ++ 0x80, 0x32, 0x00, 0x00, 0xa5, 0x8e, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x69, 0x96, 0x00, 0xf3, ++ 0x94, 0x30, 0x01, 0x00, 0x58, 0x00, 0x3e, 0x43, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0xf0, 0xb1, 0x01, 0x00, 0x1f, 0x00, 0x60, 0x00, ++ 0x00, 0x8c, 0x01, 0x00, 0xcf, 0x8d, 0x85, 0x11, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0xf0, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x8c, 0xc0, 0x01, 0x00, ++ 0x20, 0x98, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xaf, 0x8e, 0x00, 0x49, 0x19, 0x80, 0x00, 0x00, ++ 0xb4, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x8a, 0x96, 0x00, 0x40, ++ 0x3b, 0x30, 0x01, 0x00, 0xb8, 0x8e, 0xa2, 0x08, 0x3c, 0x30, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc7, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb8, 0x8e, 0xa2, 0x08, 0x3c, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x5f, ++ 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x50, 0x00, 0x2d, 0x10, 0x32, 0xb0, 0x01, 0x00, 0x54, 0x00, 0x2d, 0xf0, ++ 0x38, 0xb0, 0x01, 0x00, 0x4e, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x40, 0x00, 0x2d, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x14, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, 0x8c, 0xc8, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x46, 0x44, 0xc9, 0x01, 0x00, 0x68, 0x01, 0x2d, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x68, 0xf2, 0x80, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x37, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x36, 0xd0, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0x40, ++ 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x81, 0xd0, 0x01, 0x00, 0xcb, 0x8e, 0x20, 0x94, ++ 0x81, 0x6c, 0x00, 0x00, 0xb5, 0x97, 0x00, 0x94, 0xe5, 0x31, 0x01, 0x00, ++ 0xcc, 0x8e, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb5, 0x97, 0x00, 0x40, ++ 0xe4, 0x31, 0x01, 0x00, 0x20, 0x00, 0x00, 0x46, 0x62, 0xdd, 0x01, 0x00, ++ 0xcc, 0x8e, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0xdc, 0x8e, 0x82, 0x41, 0x23, 0x40, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xd6, 0x8e, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xd3, 0x8e, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x48, 0xb1, 0x01, 0x00, 0xfb, 0x95, 0x00, 0x43, ++ 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xb0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x0f, 0x1e, 0x8c, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x44, 0xc9, 0x01, 0x00, 0xe4, 0x8e, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xe0, 0x8e, 0xa3, 0x01, 0x0c, 0x6c, 0x00, 0x00, ++ 0xe1, 0x8e, 0x00, 0x06, 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x04, 0xb0, 0x01, 0x00, 0xe3, 0x8e, 0x20, 0x02, 0x36, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0x04, 0xb0, 0x01, 0x00, 0xe7, 0x8e, 0x00, 0x02, ++ 0xf0, 0xb1, 0x00, 0x00, 0xe6, 0x8e, 0xa3, 0x01, 0x0c, 0x6c, 0x00, 0x00, ++ 0xe7, 0x8e, 0x68, 0x06, 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, ++ 0x04, 0xb0, 0x01, 0x00, 0xe9, 0x8e, 0x80, 0x08, 0xf0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x11, 0x1e, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x01, 0x1f, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, 0xeb, 0x8e, 0xa8, 0x13, ++ 0xe0, 0x31, 0x00, 0x00, 0x22, 0x8f, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0x44, 0x00, 0x2d, 0x02, 0x0c, 0xd0, 0x01, 0x00, 0x12, 0x8f, 0xa2, 0x02, ++ 0x02, 0x50, 0x00, 0x00, 0xf9, 0x8e, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0xf8, 0x8e, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xf4, 0x8e, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x44, 0x00, 0x2d, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x48, 0x00, 0x2d, 0xf0, 0x38, 0xb0, 0x01, 0x00, ++ 0x4c, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, 0x38, 0x00, 0x2f, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x13, 0x8f, 0x22, 0x01, 0x14, 0x6c, 0x00, 0x00, ++ 0x06, 0x8f, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x1f, 0x80, 0x01, 0x00, 0x20, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x05, 0x8f, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x02, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x38, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x38, 0x00, 0x2d, 0xf0, ++ 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xe1, 0xc1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x22, 0x4a, ++ 0xf1, 0xb1, 0x01, 0x00, 0x44, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x0f, 0x8f, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x13, 0x8f, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0x38, 0xc0, 0x01, 0x00, 0x1d, 0x8f, 0x22, 0x06, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x1b, 0x8f, 0xa2, 0x02, 0x36, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x8f, 0x0d, ++ 0x42, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0xf8, 0x10, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x11, 0x80, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x37, 0x98, 0x01, 0x00, 0xcf, 0x8e, 0x00, 0xa1, 0x1a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, 0xcf, 0x8e, 0x00, 0x02, ++ 0x36, 0xd0, 0x00, 0x00, 0x50, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x20, 0x01, ++ 0xe4, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, ++ 0x27, 0x8f, 0x00, 0x5f, 0x01, 0xb0, 0x00, 0x00, 0x37, 0x00, 0x2d, 0x46, ++ 0x01, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x80, 0xf4, 0x01, 0x00, ++ 0x26, 0x8f, 0xa0, 0x43, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x01, 0xb0, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, 0x2d, 0x8f, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, 0x2a, 0x8f, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xfb, 0x95, 0x00, 0x10, 0x48, 0x31, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x34, 0x8f, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x31, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x60, 0x01, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, 0x39, 0x8f, 0x90, 0xf2, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x32, 0x00, 0x00, 0xa6, ++ 0x2a, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2a, 0x94, 0x01, 0x00, ++ 0x42, 0x8f, 0x22, 0x49, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x00, 0xf0, 0x00, 0x0c, 0x18, 0x8c, 0x01, 0x00, 0xf5, 0x97, 0x00, 0x4c, ++ 0x95, 0x30, 0x01, 0x00, 0x52, 0x8f, 0x00, 0x00, 0x92, 0xb0, 0x00, 0x00, ++ 0x49, 0x8f, 0x22, 0x40, 0xaf, 0x6f, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x1e, ++ 0x94, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x96, 0xb0, 0x01, 0x00, ++ 0x72, 0x98, 0x00, 0x40, 0x05, 0x30, 0x01, 0x00, 0x48, 0x8f, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x5b, 0x8f, 0x00, 0x47, 0x19, 0x80, 0x00, 0x00, ++ 0x52, 0x8f, 0x00, 0x00, 0x92, 0xb0, 0x00, 0x00, 0x49, 0x8f, 0x43, 0x48, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x1e, 0x62, 0xdd, 0x01, 0x00, ++ 0x4e, 0x8f, 0x28, 0x40, 0x05, 0x30, 0x00, 0x00, 0x4a, 0x8f, 0x22, 0x48, ++ 0x77, 0x7d, 0x00, 0x00, 0x51, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x62, 0xb1, 0x01, 0x00, 0x5a, 0x8f, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x4e, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x1b, 0x00, 0x92, 0xb0, 0x01, 0x00, 0x57, 0x8f, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0xcc, 0x95, 0x00, 0xf8, 0x00, 0x30, 0x01, 0x00, 0x54, 0x8f, 0xa2, 0x41, ++ 0x3b, 0x50, 0x00, 0x00, 0x5b, 0x8f, 0x00, 0x49, 0x00, 0xb0, 0x00, 0x00, ++ 0xff, 0x07, 0x00, 0x1e, 0x00, 0x8c, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x5b, 0x8f, 0x00, 0x49, 0x00, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x1b, 0x47, 0x19, 0x80, 0x01, 0x00, 0x5e, 0x8f, 0x22, 0x5f, ++ 0x01, 0x6c, 0x00, 0x00, 0x4b, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xaa, 0x8a, 0x00, 0x00, 0x80, 0xb0, 0x00, 0x00, 0x65, 0x8f, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x65, 0x8f, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x62, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x65, 0x8f, 0x40, 0x05, 0x48, 0x31, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x07, 0x94, 0x89, 0x01, 0x00, 0x6b, 0x8f, 0x85, 0xca, ++ 0x94, 0x30, 0x00, 0x00, 0x4b, 0x99, 0x18, 0x5c, 0x1f, 0x00, 0x01, 0x00, ++ 0x0e, 0x00, 0x00, 0x0f, 0x1e, 0x8c, 0x01, 0x00, 0x72, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x20, 0x98, 0x18, 0x00, 0x80, 0x30, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x47, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x19, 0x80, 0x01, 0x00, 0xcf, 0x8d, 0x22, 0x47, 0x19, 0x7c, 0x00, 0x00, ++ 0xc7, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x72, 0x8f, 0xa2, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb5, 0x97, 0x00, 0x40, 0x0d, 0x30, 0x01, 0x00, 0x9c, 0x01, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x98, 0x88, 0x01, 0x00, ++ 0x8b, 0x00, 0x2d, 0x50, 0x17, 0xf0, 0x01, 0x00, 0x78, 0x8f, 0x90, 0x4c, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x7a, 0x8f, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x45, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, ++ 0x68, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0xf2, ++ 0x80, 0xb0, 0x01, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0x81, 0x8f, 0x24, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x81, 0xc0, 0x01, 0x00, 0x82, 0x8f, 0x00, 0x94, 0xe5, 0xb1, 0x00, 0x00, ++ 0x02, 0x00, 0x62, 0x40, 0x7e, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, ++ 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0xf0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x88, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x94, 0x8f, 0x22, 0x40, 0xaf, 0x6f, 0x00, 0x00, ++ 0x00, 0x40, 0x00, 0x08, 0x94, 0xdc, 0x01, 0x00, 0x72, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x92, 0x8f, 0x22, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x08, 0x00, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x47, 0x19, 0x80, 0x00, 0x00, 0x94, 0x8f, 0x43, 0x48, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x50, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, ++ 0x9a, 0x8f, 0x28, 0x40, 0x05, 0x30, 0x00, 0x00, 0x95, 0x8f, 0x22, 0x48, ++ 0x77, 0x7d, 0x00, 0x00, 0xcc, 0x95, 0x1b, 0x08, 0x00, 0x30, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xcf, 0x8d, 0x1b, 0x47, ++ 0x19, 0x80, 0x00, 0x00, 0x35, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x63, 0xf3, 0x84, 0xc8, 0x01, 0x00, 0x9f, 0x8f, 0xa0, 0x43, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0xa8, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x37, 0x00, 0x2f, 0xf0, ++ 0x24, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, ++ 0xaa, 0x8f, 0xa2, 0x41, 0x9e, 0x06, 0x00, 0x00, 0xcf, 0x8d, 0x22, 0x44, ++ 0x83, 0x70, 0x00, 0x00, 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0xcf, 0x8d, 0x1f, 0xf0, ++ 0x24, 0x6c, 0x00, 0x00, 0x4b, 0x99, 0x00, 0x48, 0x81, 0x30, 0x01, 0x00, ++ 0xaa, 0x8a, 0x23, 0x41, 0x83, 0x6c, 0x00, 0x00, 0xaa, 0x8a, 0x00, 0x47, ++ 0x81, 0xb0, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, 0x85, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x36, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x00, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xee, 0x97, 0x00, 0x47, 0x61, 0x31, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x8e, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, 0x14, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x7e, 0x8e, 0xa2, 0x40, ++ 0x8f, 0x7c, 0x00, 0x00, 0xb8, 0x8f, 0x22, 0x47, 0x8f, 0x7c, 0x00, 0x00, ++ 0x7e, 0x8e, 0x00, 0x48, 0x19, 0x90, 0x00, 0x00, 0x27, 0x90, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x36, 0x00, 0x2d, 0x5d, 0x05, 0xb4, 0x01, 0x00, ++ 0x37, 0x00, 0x2d, 0xf3, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x8e, 0xb0, 0x01, 0x00, 0x5c, 0x00, 0x3d, 0x43, 0x81, 0xe0, 0x01, 0x00, ++ 0xa8, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x24, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x86, 0xdc, 0x01, 0x00, ++ 0x40, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0xce, 0x94, 0x00, 0x4a, ++ 0xf0, 0x31, 0x01, 0x00, 0x36, 0x00, 0x2f, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0xc6, 0x8f, 0xa2, 0x50, 0x8f, 0x50, 0x00, 0x00, 0x34, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x41, 0x81, 0xc0, 0x01, 0x00, 0xc9, 0x8f, 0xa0, 0x43, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x63, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x37, 0x00, 0x20, 0x47, 0xe6, 0xb1, 0x01, 0x00, 0xcf, 0x8d, 0x22, 0x47, ++ 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x47, 0x0c, 0xf4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x8f, 0x84, 0x01, 0x00, 0xde, 0x8f, 0x22, 0x47, ++ 0x0c, 0x6c, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, 0x81, 0xe0, 0x01, 0x00, ++ 0xde, 0x8f, 0x1f, 0xf0, 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xd7, 0x8f, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xd4, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xd7, 0x8f, 0x42, 0x40, 0x05, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x5d, ++ 0x69, 0x93, 0x01, 0x00, 0xdc, 0x8f, 0x23, 0x41, 0x0d, 0x6c, 0x00, 0x00, ++ 0xb9, 0x8f, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x4b, 0x99, 0x00, 0x05, ++ 0x48, 0x31, 0x01, 0x00, 0xaa, 0x8a, 0x00, 0x48, 0x81, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8d, 0x22, 0x40, 0x8f, 0x6c, 0x00, 0x00, 0x20, 0x98, 0x00, 0x5f, ++ 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xa2, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x84, 0xb0, 0x01, 0x00, 0xa6, 0x00, 0x2d, 0x49, 0x19, 0x90, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xf2, 0x80, 0xf4, 0x01, 0x00, 0xb8, 0x00, 0x2d, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x82, 0xf8, 0x01, 0x00, 0x19, 0x00, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0xed, 0x8f, 0xa0, 0x40, 0x82, 0x6c, 0x00, 0x00, ++ 0x2c, 0x01, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0xed, 0x8f, 0xa3, 0x40, ++ 0x82, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x80, 0xb0, 0x01, 0x00, ++ 0xef, 0x8f, 0x20, 0x4c, 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x85, 0xc0, 0x01, 0x00, 0x86, 0x00, 0x20, 0x40, 0xe4, 0xb1, 0x01, 0x00, ++ 0xa2, 0x00, 0x20, 0x42, 0xe6, 0xb1, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x50, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x80, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x3d, 0x99, 0x00, 0x40, ++ 0x87, 0x30, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xf0, 0x80, 0xc0, 0x01, 0x00, 0x20, 0x98, 0x00, 0x5f, ++ 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xcf, 0x8d, 0x22, 0x46, ++ 0x19, 0x7c, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x62, 0xf2, 0x96, 0xcc, 0x01, 0x00, 0xcf, 0x8d, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x20, 0x98, 0x00, 0x4a, 0x81, 0x30, 0x01, 0x00, ++ 0xf5, 0x97, 0x00, 0x46, 0x95, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xcf, 0x8d, 0x22, 0x49, 0x19, 0x7c, 0x00, 0x00, ++ 0x86, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0xf2, ++ 0x80, 0xcc, 0x01, 0x00, 0xcf, 0x8d, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x4a, 0x81, 0x30, 0x01, 0x00, 0xf5, 0x97, 0x00, 0x47, ++ 0x95, 0x30, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x5f, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xcf, 0x8d, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0xf2, 0x80, 0xc8, 0x01, 0x00, ++ 0x13, 0x90, 0x90, 0x40, 0x80, 0x32, 0x00, 0x00, 0xff, 0xff, 0x62, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0xa4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xcf, 0x8d, 0x22, 0x40, 0xe5, 0x6d, 0x00, 0x00, 0xcf, 0x8d, 0x00, 0x41, ++ 0xe5, 0xc1, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x4d, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x96, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x3d, 0x99, 0x00, 0x40, ++ 0x87, 0x30, 0x01, 0x00, 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x23, 0x90, 0x80, 0xf3, 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe7, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x19, 0x90, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x34, 0x00, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x01, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x11, 0x00, 0x40, 0xe5, 0x99, 0x01, 0x00, 0xc7, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x38, 0x90, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x63, 0x51, 0x83, 0xd0, 0x01, 0x00, ++ 0x34, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x84, 0xcc, 0x01, 0x00, 0x30, 0x90, 0x9f, 0x42, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x42, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, ++ 0x32, 0x90, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x62, 0xb1, 0x01, 0x00, 0x33, 0x90, 0xa8, 0x4b, 0x19, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, 0x35, 0x90, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xff, 0x89, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x2d, 0xf0, 0x30, 0xb0, 0x01, 0x00, ++ 0x35, 0x00, 0x2d, 0xf0, 0x28, 0xb0, 0x01, 0x00, 0x58, 0x00, 0x3e, 0x43, ++ 0xe7, 0xe1, 0x01, 0x00, 0x01, 0x00, 0x00, 0x18, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xe0, 0xb1, 0x01, 0x00, 0x38, 0x00, 0x20, 0x00, ++ 0xe0, 0xb1, 0x01, 0x00, 0x3c, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x2b, 0xb0, 0x01, 0x00, 0x04, 0x98, 0x00, 0x40, 0x0d, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x16, 0xc0, 0x01, 0x00, 0x47, 0x90, 0xa0, 0x14, ++ 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x0e, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xf8, 0xb1, 0x01, 0x00, 0xb0, 0x00, 0x2d, 0x14, 0xf8, 0xb1, 0x01, 0x00, ++ 0x10, 0x50, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x50, 0x90, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x43, 0x86, 0xc8, 0x01, 0x00, ++ 0x00, 0x30, 0x00, 0x0b, 0x16, 0xc8, 0x01, 0x00, 0x50, 0x90, 0xa4, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x01, 0x00, 0x6e, 0x43, 0x86, 0x98, 0x01, 0x00, 0x3b, 0x98, 0x00, 0x30, ++ 0x81, 0x30, 0x01, 0x00, 0x54, 0x90, 0xa0, 0x41, 0x17, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x5b, 0x90, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0xcc, 0x00, 0x2d, 0xab, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0x17, 0xc0, 0x01, 0x00, 0x5a, 0x90, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x64, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x41, 0x31, 0xc0, 0x01, 0x00, 0xbc, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x61, 0x90, 0x06, 0x0c, 0x80, 0x32, 0x00, 0x00, ++ 0xa0, 0x00, 0x20, 0xf2, 0xe4, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x09, 0x46, ++ 0x19, 0x10, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x0b, 0x98, 0x88, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x50, ++ 0x17, 0xf0, 0x01, 0x00, 0x66, 0x90, 0x90, 0x4c, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x68, 0x90, 0x22, 0x43, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x68, 0x01, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0xf2, 0x80, 0xb0, 0x01, 0x00, ++ 0x3e, 0x00, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, 0x6f, 0x90, 0x24, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x81, 0xc0, 0x01, 0x00, ++ 0x70, 0x90, 0x00, 0x94, 0xe5, 0xb1, 0x00, 0x00, 0x02, 0x00, 0x62, 0x40, ++ 0x7e, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, 0x81, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, ++ 0xf0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, ++ 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x76, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x80, 0x90, 0x22, 0x40, 0xaf, 0x6f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x08, ++ 0x94, 0xdc, 0x01, 0x00, 0x72, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x7b, 0x90, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, 0x35, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x84, 0x90, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x80, 0x90, 0x43, 0x48, 0x61, 0x31, 0x00, 0x00, 0x00, 0x50, 0x00, 0x08, ++ 0x62, 0xdd, 0x01, 0x00, 0x81, 0x90, 0xa8, 0x40, 0x05, 0x30, 0x00, 0x00, ++ 0x35, 0x00, 0x1b, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x84, 0xc8, 0x01, 0x00, 0x87, 0x90, 0xa0, 0x43, 0x85, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xe7, 0x91, 0x01, 0x00, 0x20, 0x98, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x69, 0x96, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, ++ 0x27, 0x90, 0x22, 0x4a, 0x80, 0x32, 0x00, 0x00, 0xa5, 0x8e, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x69, 0x96, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, 0x75, 0x8e, 0x22, 0x4a, ++ 0x80, 0x32, 0x00, 0x00, 0xa5, 0x8e, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0x12, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, 0x90, 0x88, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x0c, 0xf4, 0x01, 0x00, 0x9f, 0x8e, 0x22, 0x06, ++ 0x90, 0x6c, 0x00, 0x00, 0x5c, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, ++ 0xa8, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, 0x37, 0x00, 0x2f, 0xf0, ++ 0x24, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x2a, 0x50, 0xe7, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x41, 0x13, 0xc0, 0x01, 0x00, 0xa1, 0x90, 0xa0, 0x43, ++ 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xcc, 0x94, 0x00, 0x10, 0x86, 0x30, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xa3, 0x90, 0x42, 0x05, 0x48, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0x9f, 0x8e, 0x1a, 0x5d, ++ 0x69, 0x93, 0x00, 0x00, 0x36, 0x00, 0x2d, 0x10, 0x86, 0xb0, 0x01, 0x00, ++ 0x5c, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x35, 0x00, 0x2f, 0xf0, 0x24, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x6b, 0xfb, 0x84, 0xc8, 0x01, 0x00, 0xae, 0x90, 0xa0, 0x43, ++ 0x85, 0x6c, 0x00, 0x00, 0x35, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x12, 0xc8, 0x01, 0x00, 0xb1, 0x90, 0xa0, 0x43, 0x13, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x40, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0xce, 0x94, 0x00, 0x4a, 0xf0, 0x31, 0x01, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xb4, 0x90, 0x42, 0x05, ++ 0x48, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x5d, 0x69, 0x93, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x11, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, ++ 0xa3, 0x8f, 0x22, 0x41, 0x9e, 0x06, 0x00, 0x00, 0x35, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x36, 0xb0, 0x01, 0x00, 0xad, 0x8f, 0x00, 0xf0, ++ 0x00, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xbf, 0x90, 0x47, 0xf2, 0x12, 0x30, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x13, 0xf0, 0x01, 0x00, 0xc4, 0x90, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0x6b, 0x84, 0x1f, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xbe, 0x90, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xe7, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x1f, 0x42, 0x19, 0x90, 0x01, 0x00, 0x75, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xc6, 0x90, 0xa8, 0xb1, 0x0c, 0x30, 0x00, 0x00, ++ 0x46, 0x97, 0x00, 0x10, 0x94, 0x30, 0x01, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc0, 0xa8, 0x3d, 0x46, 0x0d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0xd0, 0x90, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x04, 0x00, 0x02, 0x41, 0x97, 0x40, 0x00, 0x00, 0xcd, 0x90, 0x00, 0x50, ++ 0x43, 0xc1, 0x00, 0x00, 0xdc, 0x90, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x62, 0x4b, 0x12, 0x94, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x97, 0xc0, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x94, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x4a, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf1, 0xb1, 0x01, 0x00, ++ 0x5e, 0x01, 0x00, 0x4b, 0xf0, 0xc9, 0x01, 0x00, 0x5e, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x4a, 0x62, 0xdd, 0x01, 0x00, 0xda, 0x90, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x09, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x97, 0xc0, 0x01, 0x00, ++ 0xd4, 0x00, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0xe2, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, ++ 0xe6, 0x90, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x1f, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0x62, 0xb1, 0x01, 0x00, 0xea, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xef, 0x90, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0xed, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x97, 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x96, ++ 0x97, 0xb0, 0x01, 0x00, 0xf5, 0x90, 0x20, 0x09, 0x96, 0x6c, 0x00, 0x00, ++ 0xf5, 0x90, 0x1f, 0x09, 0x96, 0x24, 0x00, 0x00, 0x6b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xf0, 0x90, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xaf, 0x97, 0x00, 0x57, 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xfb, 0x90, 0x22, 0xf3, 0x80, 0x32, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x42, ++ 0x81, 0x30, 0x01, 0x00, 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x52, 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x42, ++ 0x19, 0x80, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0x20, 0x98, 0x00, 0x52, 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xc9, 0x96, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x22, 0x40, ++ 0x95, 0x6c, 0x00, 0x00, 0x06, 0x91, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xff, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x74, 0x96, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf4, 0x98, 0x00, 0x40, ++ 0x95, 0x30, 0x01, 0x00, 0x11, 0x91, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0xff, 0x89, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x23, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0x14, 0x91, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x08, 0x00, 0x0b, 0x16, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x2a, 0xc0, 0x01, 0x00, 0xf8, 0x97, 0x00, 0x08, 0x80, 0x30, 0x01, 0x00, ++ 0x18, 0x91, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, 0x19, 0x98, 0x00, 0x43, ++ 0x61, 0x31, 0x01, 0x00, 0xda, 0x94, 0x00, 0x40, 0x8d, 0x30, 0x01, 0x00, ++ 0x00, 0x98, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x20, 0x91, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x1d, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xa1, 0x97, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x24, 0x91, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xbf, 0x8d, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0xf9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x1f, 0x90, 0x01, 0x00, ++ 0x2b, 0x91, 0x22, 0x43, 0x3d, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3d, 0x80, 0x01, 0x00, ++ 0x2c, 0x91, 0x00, 0x42, 0x19, 0x90, 0x00, 0x00, 0x14, 0x00, 0x2d, 0x45, ++ 0x1f, 0x90, 0x01, 0x00, 0x87, 0x91, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, ++ 0x87, 0x91, 0x00, 0x44, 0x19, 0x90, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x3f, 0x91, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x3b, 0x91, 0xa2, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xe3, 0x89, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, 0x38, 0x91, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x74, 0x96, 0x00, 0x15, ++ 0x94, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf9, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0xff, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x42, 0x91, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0xf9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x43, 0x91, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6f, 0x91, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x15, ++ 0x98, 0xc8, 0x01, 0x00, 0x6f, 0x91, 0xa0, 0x0b, 0x99, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, ++ 0x4b, 0x91, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x15, 0x98, 0xc8, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x0b, ++ 0x99, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x6a, 0x50, 0x99, 0xc0, 0x01, 0x00, ++ 0xc0, 0x00, 0x62, 0x01, 0x80, 0xcc, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x2d, 0x00, 0x2d, 0xf0, 0x22, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x23, 0x80, 0x01, 0x00, 0xd4, 0x00, 0x3f, 0x41, 0xe7, 0xe1, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0x11, 0xe4, 0xf5, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x47, ++ 0xe7, 0xb5, 0x01, 0x00, 0x5c, 0x91, 0x23, 0x0b, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0xe5, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x03, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x02, 0xd0, 0x01, 0x00, 0xf8, 0x97, 0x00, 0x00, ++ 0x2a, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x61, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x01, ++ 0x80, 0xce, 0x01, 0x00, 0x6d, 0x91, 0x26, 0x11, 0x00, 0x30, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xc0, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x99, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x98, 0xd0, 0x01, 0x00, 0xf8, 0x97, 0x00, 0x4c, 0x02, 0x30, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x03, 0x98, 0x01, 0x00, 0x74, 0x91, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x2f, 0x08, 0x80, 0xb0, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x15, 0xf4, 0xc9, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x01, ++ 0xe4, 0xcd, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x03, 0x98, 0x01, 0x00, ++ 0xf8, 0x97, 0x00, 0x00, 0x2a, 0x40, 0x01, 0x00, 0x79, 0x91, 0x22, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0xac, 0x00, 0x2f, 0x40, 0x13, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xc1, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x7a, 0x91, 0x00, 0x01, 0xe0, 0xd1, 0x00, 0x00, ++ 0xda, 0x94, 0x00, 0x40, 0x8d, 0x30, 0x01, 0x00, 0x80, 0x63, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0x00, 0x98, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x82, 0x91, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x7f, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xa1, 0x97, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x85, 0x91, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xba, 0x8d, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x87, 0x91, 0x00, 0x4a, ++ 0x1f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb0, 0x01, 0x00, ++ 0x24, 0x00, 0x2d, 0x15, 0x10, 0xc0, 0x01, 0x00, 0x28, 0x00, 0x2d, 0xf0, ++ 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xe0, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x15, ++ 0x1a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x2a, 0xb0, 0x01, 0x00, 0x5b, 0x97, 0x00, 0x40, ++ 0x35, 0xb0, 0x00, 0x00, 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xcb, 0x91, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0x24, 0x00, 0x20, 0x0b, ++ 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, ++ 0x22, 0x00, 0x20, 0x06, 0xe4, 0xb1, 0x01, 0x00, 0xa1, 0x91, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xa1, 0x91, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x9d, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0xc4, 0x91, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0xb2, 0x91, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x21, 0x97, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x74, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xbf, 0x91, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xa8, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xae, 0x91, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xe2, 0x95, 0x00, 0x40, 0x11, 0x30, 0x01, 0x00, 0xaf, 0x91, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb1, 0x91, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x6f, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x21, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x70, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xb5, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xbb, 0x91, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xe2, 0x95, 0x00, 0x40, ++ 0x11, 0x30, 0x01, 0x00, 0xbc, 0x91, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xbe, 0x91, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6f, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xc0, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc7, 0x91, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xe2, 0x95, 0x00, 0x40, ++ 0x11, 0x30, 0x01, 0x00, 0xc8, 0x91, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xca, 0x91, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xbf, 0x8d, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0xd2, 0x91, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xce, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xd6, 0x91, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xe2, 0x95, 0x00, 0x40, ++ 0x11, 0x30, 0x01, 0x00, 0xd7, 0x91, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x2d, 0x0a, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xdc, 0x91, 0x03, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0xdd, 0x91, 0x00, 0x41, 0x87, 0xb0, 0x00, 0x00, ++ 0x21, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0xea, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0xe1, 0x91, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xe4, 0x91, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x80, 0x01, 0x00, 0xba, 0x8d, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, ++ 0xbf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xea, 0x91, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0xcc, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xfb, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x8d, 0x98, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xc4, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0xd8, 0x98, 0x00, 0xf0, 0x84, 0x30, 0x01, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xbf, 0x8d, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xbf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xf6, 0x91, 0x22, 0x40, 0xe7, 0x6d, 0x00, 0x00, ++ 0x32, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xfe, 0x91, 0xa2, 0x40, ++ 0xe5, 0x6d, 0x00, 0x00, 0xb6, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x24, 0x00, 0x20, 0x0b, 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x20, 0x13, ++ 0xe0, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x20, 0x06, 0xe4, 0xb1, 0x01, 0x00, ++ 0x14, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, 0xbf, 0x8d, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xbf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x6f, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0c, 0x92, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0x99, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x15, 0x98, 0x50, 0x00, 0x00, ++ 0x0c, 0x92, 0x20, 0x01, 0x98, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x09, 0x92, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xac, 0x00, 0x2f, 0x00, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xe0, 0xc1, 0x01, 0x00, 0x14, 0x00, 0x2f, 0x15, 0x10, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0x01, ++ 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x19, 0x90, 0x01, 0x00, ++ 0x8e, 0x91, 0x22, 0x09, 0x80, 0x32, 0x00, 0x00, 0x20, 0x98, 0x00, 0x09, ++ 0x80, 0x30, 0x01, 0x00, 0x8e, 0x91, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x43, 0xc1, 0x01, 0x00, 0xea, 0x96, 0x00, 0xf0, ++ 0x84, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0x2c, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x42, 0x19, 0x80, 0x00, 0x00, ++ 0xdc, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xf5, 0x97, 0x00, 0x48, ++ 0x95, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x21, 0x92, 0xa8, 0x40, ++ 0x13, 0x30, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x27, 0x92, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x26, 0x92, 0x00, 0x40, ++ 0x13, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xb0, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x14, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x84, 0x30, 0x00, 0x00, ++ 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0xea, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x3f, 0x92, 0x00, 0x09, 0x00, 0xb0, 0x00, 0x00, 0xba, 0x8d, 0x87, 0x42, ++ 0x19, 0x10, 0x00, 0x00, 0x8b, 0x00, 0x2f, 0x47, 0x19, 0x80, 0x01, 0x00, ++ 0xba, 0x8d, 0x00, 0x40, 0xe7, 0x91, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x3d, 0x92, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0x51, 0x95, 0x00, 0x40, 0xe7, 0x31, 0x01, 0x00, 0x3d, 0x92, 0x22, 0x00, ++ 0x80, 0x32, 0x00, 0x00, 0x38, 0x92, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x3d, 0x92, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x32, 0x00, 0x2d, 0xf2, 0x94, 0xb0, 0x01, 0x00, 0x74, 0x96, 0x00, 0xf2, ++ 0x02, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x3e, 0x92, 0x00, 0x40, ++ 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x44, 0x92, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0x43, 0x92, 0xa2, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0xc9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x44, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf9, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xce, 0x92, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x4c, 0x92, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x49, 0x92, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xce, 0x92, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x52, 0x92, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x4d, ++ 0x81, 0x30, 0x01, 0x00, 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x74, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x96, 0xb0, 0x01, 0x00, 0x60, 0x92, 0x22, 0x42, 0x96, 0x14, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x64, 0x00, 0x68, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x70, 0x00, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x5d, 0x92, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x61, 0x92, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x65, 0x92, 0x47, 0xf2, 0x12, 0x30, 0x00, 0x00, ++ 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, 0x6a, 0x92, 0x22, 0x47, ++ 0xe7, 0x7d, 0x00, 0x00, 0x6b, 0x84, 0x1f, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x64, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0xe7, 0x91, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x09, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x97, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x72, 0x92, 0xa8, 0x40, ++ 0xe1, 0x31, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, 0x76, 0x92, 0x47, 0x05, ++ 0x48, 0x31, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x7e, 0x92, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x7c, 0x92, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x16, 0xb0, 0x01, 0x00, 0x00, 0x62, 0x00, 0x0b, ++ 0x16, 0xdc, 0x01, 0x00, 0x51, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x96, 0x92, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0xff, 0x96, 0x00, 0x5f, ++ 0x01, 0x10, 0x01, 0x00, 0x80, 0x92, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x88, 0x92, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x74, 0x96, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x80, 0x92, 0x22, 0x41, 0x97, 0x50, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x01, 0x80, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x80, 0x92, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x00, 0x98, 0x00, 0x40, 0x03, 0x30, 0x01, 0x00, 0x17, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x0c, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x4c, 0x97, 0xf0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0xe1, 0xb1, 0x01, 0x00, ++ 0xa1, 0x97, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, 0x16, 0x88, 0x01, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0xa0, 0x92, 0x30, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x81, 0x01, 0x00, ++ 0x00, 0xb7, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe6, 0x81, 0x01, 0x00, 0x10, 0x00, 0x10, 0x0f, 0x94, 0xf4, 0x01, 0x00, ++ 0xd1, 0x99, 0x00, 0x5f, 0x95, 0x04, 0x01, 0x00, 0x55, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xaa, 0x92, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, ++ 0xa8, 0x92, 0x43, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x41, ++ 0x31, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0xb8, 0x95, 0x00, 0x41, 0x81, 0x30, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xbb, 0x92, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, ++ 0xb4, 0x92, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x62, 0xb1, 0x01, 0x00, 0xb8, 0x92, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xb5, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0xb1, 0x01, 0x00, 0xb8, 0x92, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xff, 0x89, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x74, 0x00, 0x22, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0xf5, 0x97, 0x00, 0x4a, 0x95, 0x30, 0x01, 0x00, 0xdc, 0x96, 0x00, 0x5c, ++ 0x1f, 0x10, 0x01, 0x00, 0x52, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2f, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xcc, 0x92, 0x22, 0x47, ++ 0xe7, 0x7d, 0x00, 0x00, 0x51, 0x95, 0x00, 0x40, 0xe7, 0x31, 0x01, 0x00, ++ 0xcc, 0x92, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0xc7, 0x92, 0xa2, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xcc, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x32, 0x00, 0x2d, 0xf2, 0x94, 0xb0, 0x01, 0x00, ++ 0x74, 0x96, 0x00, 0xf2, 0x02, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xf5, 0x97, 0x00, 0x48, 0x95, 0x30, 0x01, 0x00, 0xdc, 0x96, 0x00, 0x5c, ++ 0x1f, 0x10, 0x01, 0x00, 0xd1, 0x92, 0x87, 0x42, 0x19, 0x10, 0x00, 0x00, ++ 0x8b, 0x00, 0x2f, 0x47, 0x19, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe7, 0x91, 0x01, 0x00, 0x20, 0x98, 0x00, 0x42, 0x81, 0x30, 0x01, 0x00, ++ 0xba, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xdc, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0xba, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0x8d, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xc4, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0xd8, 0x98, 0x00, 0xf0, ++ 0x84, 0x30, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x20, 0x98, 0x00, 0x45, 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0xba, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xe5, 0x92, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0xaf, 0x97, 0x00, 0x47, ++ 0x80, 0x30, 0x01, 0x00, 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0xe1, 0x00, 0xa6, 0x84, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x07, 0x84, 0x94, 0x01, 0x00, ++ 0xa1, 0x97, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xcc, 0x95, 0x00, 0x41, 0xe7, 0x41, 0x01, 0x00, 0xbf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6f, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x2c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x0a, ++ 0x2c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x0b, 0x96, 0x88, 0x01, 0x00, 0x01, 0x93, 0x26, 0x47, ++ 0x97, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, ++ 0x01, 0x93, 0x23, 0x4b, 0x0c, 0x6c, 0x00, 0x00, 0x33, 0x98, 0x00, 0x4b, ++ 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x16, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0xb0, 0x01, 0x00, ++ 0x33, 0x98, 0x00, 0x4b, 0x04, 0x50, 0x01, 0x00, 0x02, 0x93, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x33, 0x98, 0x00, 0x06, 0x04, 0x30, 0x01, 0x00, ++ 0x08, 0x93, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, 0x06, 0x93, 0x84, 0x48, ++ 0x1f, 0x10, 0x00, 0x00, 0xac, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x08, 0x93, 0x00, 0x0a, 0xe0, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x02, 0xb0, 0x01, 0x00, 0xda, 0x94, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x09, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, ++ 0x16, 0x93, 0x22, 0x06, 0x14, 0x50, 0x00, 0x00, 0x24, 0x97, 0x00, 0x45, ++ 0x1f, 0x00, 0x01, 0x00, 0xf5, 0x92, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x12, 0x93, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xf5, 0x92, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x08, 0x00, 0x2d, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xea, 0x96, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x1c, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x22, 0x93, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x26, 0x93, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x26, 0x93, 0xa2, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, 0x34, 0x93, 0x22, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x2c, 0x93, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0x30, 0x93, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0xf9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x31, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc9, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, ++ 0x32, 0x00, 0x2a, 0x15, 0xe4, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x16, ++ 0xe4, 0xb1, 0x00, 0x00, 0x46, 0x93, 0x22, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0xf4, 0x98, 0x00, 0x40, ++ 0x95, 0x30, 0x01, 0x00, 0x47, 0x93, 0x22, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0xac, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2b, 0x01, ++ 0xe0, 0xc1, 0x01, 0x00, 0x00, 0x2b, 0x00, 0xa6, 0x16, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xd1, 0x01, 0x00, 0xf8, 0x97, 0x00, 0x08, ++ 0x80, 0x30, 0x01, 0x00, 0x3f, 0x93, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, ++ 0x19, 0x98, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x40, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x98, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0xa1, 0x97, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xbf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x1f, 0x15, 0x1a, 0x50, 0x00, 0x00, 0x54, 0x93, 0x20, 0x16, ++ 0x1a, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x51, 0x93, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x2a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x2c, 0xd0, 0x01, 0x00, 0xac, 0x00, 0x2f, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x5b, 0x93, 0x84, 0x45, 0x1f, 0x10, 0x00, 0x00, 0x5c, 0x93, 0x00, 0x0a, ++ 0xe0, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0xb0, 0x01, 0x00, ++ 0x5b, 0x97, 0x00, 0x40, 0x35, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0x64, 0x93, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x60, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x73, 0x93, 0xa2, 0x02, 0x1a, 0x50, 0x00, 0x00, ++ 0x74, 0x93, 0x22, 0x40, 0x2d, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, ++ 0xe0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x6b, 0x93, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x10, 0xc8, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x1b, 0x98, 0x01, 0x00, 0x74, 0x93, 0x00, 0x5c, ++ 0x11, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, ++ 0xe2, 0x95, 0x00, 0x40, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x78, 0x93, 0x23, 0x0d, 0x2c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1f, 0x90, 0x01, 0x00, 0x80, 0x93, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x70, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x80, 0x93, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x7c, 0x93, 0xa8, 0x46, 0x1f, 0x00, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x2d, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xea, 0x96, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x85, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x8b, 0x93, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x8f, 0x93, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x8f, 0x93, 0xa2, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, 0xa4, 0x93, 0x22, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x95, 0x93, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0xa0, 0x93, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x99, 0x93, 0xa2, 0xf3, 0x84, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa5, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x85, 0xd0, 0x01, 0x00, 0xd4, 0x00, 0x3e, 0x41, 0x85, 0xe0, 0x01, 0x00, ++ 0x9d, 0x93, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, ++ 0x11, 0x90, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x08, 0xe4, 0xf5, 0x01, 0x00, ++ 0xf9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xa1, 0x93, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, 0x32, 0x00, 0x2a, 0x15, ++ 0xe4, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x16, 0xe4, 0xb1, 0x00, 0x00, ++ 0xa7, 0x93, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf4, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0xb4, 0x93, 0x22, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0xb1, 0x93, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0xac, 0x93, 0xa2, 0xf3, 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x85, 0xd0, 0x01, 0x00, ++ 0xd4, 0x00, 0x3e, 0x41, 0x85, 0xe0, 0x01, 0x00, 0xb0, 0x93, 0x22, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x11, 0x90, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0x08, 0xe4, 0xf5, 0x01, 0x00, 0x58, 0x01, 0x2d, 0x00, ++ 0x2a, 0xd0, 0x01, 0x00, 0x60, 0x01, 0x2d, 0xf0, 0x10, 0xb0, 0x01, 0x00, ++ 0x3f, 0x91, 0x00, 0xf0, 0x2c, 0xb0, 0x00, 0x00, 0xf4, 0x98, 0x00, 0x41, ++ 0x95, 0x30, 0x01, 0x00, 0xbb, 0x93, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x97, 0xb0, 0x01, 0x00, 0xb9, 0x93, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, ++ 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0xf4, 0x93, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xac, 0x00, 0x2f, 0x01, 0x14, 0xb0, 0x01, 0x00, ++ 0xb0, 0x00, 0x2b, 0x01, 0xe0, 0xc1, 0x01, 0x00, 0x00, 0x2b, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xd1, 0x01, 0x00, ++ 0xcb, 0x93, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0xc4, 0x93, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, ++ 0x22, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x23, 0x80, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x84, 0xb0, 0x01, 0x00, 0xce, 0x93, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x80, 0xb0, 0x01, 0x00, 0xd3, 0x93, 0x22, 0x40, ++ 0x1b, 0x6c, 0x00, 0x00, 0xf8, 0x97, 0x00, 0x01, 0x84, 0x50, 0x01, 0x00, ++ 0xdb, 0x93, 0x22, 0x40, 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x80, 0xc0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, 0x46, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa1, 0x62, 0xdd, 0x01, 0x00, ++ 0xd9, 0x93, 0xa8, 0x11, 0xe0, 0x31, 0x00, 0x00, 0xea, 0x93, 0x00, 0x5e, ++ 0x17, 0x90, 0x00, 0x00, 0xde, 0x93, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x84, 0xd0, 0x01, 0x00, 0xe3, 0x93, 0x22, 0x40, 0x1b, 0x6c, 0x00, 0x00, ++ 0x19, 0x98, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0xea, 0x93, 0x22, 0x40, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0xc0, 0x01, 0x00, ++ 0x10, 0x80, 0x00, 0x10, 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xf0, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa1, 0x62, 0xdd, 0x01, 0x00, ++ 0xe8, 0x93, 0xa8, 0x11, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xeb, 0x93, 0xa8, 0x0a, 0x02, 0x30, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, ++ 0xf2, 0x93, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, 0xff, 0x07, 0x00, 0x11, ++ 0x00, 0x8c, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x98, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0xa1, 0x97, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xbf, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x8e, 0xb0, 0x01, 0x00, 0xb3, 0x96, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0xea, 0x96, 0x00, 0x41, ++ 0x87, 0x30, 0x01, 0x00, 0x6f, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x05, 0x94, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x01, 0x94, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x07, 0x94, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x1a, 0xd0, 0x01, 0x00, 0x0d, 0x94, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xf4, 0x98, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, 0x15, 0x94, 0x22, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x38, 0x93, 0x00, 0x00, 0x2a, 0xc0, 0x00, 0x00, ++ 0xf4, 0x98, 0x00, 0x41, 0x95, 0x30, 0x01, 0x00, 0x10, 0x94, 0x22, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0xbb, 0x93, 0x00, 0x00, 0x2a, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x97, 0xb0, 0x01, 0x00, 0x13, 0x94, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, ++ 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x19, 0x94, 0x00, 0x4a, 0x1f, 0x90, 0x00, 0x00, ++ 0xf4, 0x95, 0x00, 0x00, 0x10, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x0b, 0x96, 0x88, 0x01, 0x00, 0x27, 0x94, 0x26, 0x47, ++ 0x97, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, ++ 0x27, 0x94, 0x23, 0x4b, 0x0c, 0x6c, 0x00, 0x00, 0x33, 0x98, 0x00, 0x4b, ++ 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x16, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0xb0, 0x01, 0x00, ++ 0x33, 0x98, 0x00, 0x4b, 0x04, 0x50, 0x01, 0x00, 0x28, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x33, 0x98, 0x00, 0x06, 0x04, 0x30, 0x01, 0x00, ++ 0x2d, 0x94, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x2c, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x02, 0xb0, 0x01, 0x00, 0xda, 0x94, 0x00, 0x01, ++ 0x8c, 0x30, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, ++ 0x34, 0x94, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x30, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, 0x3d, 0x94, 0x22, 0x06, ++ 0x14, 0x50, 0x00, 0x00, 0x24, 0x97, 0x00, 0x45, 0x1f, 0x00, 0x01, 0x00, ++ 0x1b, 0x94, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x39, 0x94, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x1b, 0x94, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x08, 0x00, 0x2d, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xea, 0x96, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x42, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x48, 0x94, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x4b, 0x94, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x80, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, ++ 0x59, 0x94, 0x22, 0x4a, 0x1f, 0x7c, 0x00, 0x00, 0x51, 0x94, 0xa2, 0x16, ++ 0x02, 0x30, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, ++ 0x55, 0x94, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0xf9, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x56, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x00, ++ 0x2a, 0xd0, 0x01, 0x00, 0x32, 0x00, 0x2a, 0x15, 0xe4, 0xb1, 0x01, 0x00, ++ 0xba, 0x8d, 0x00, 0x16, 0xe4, 0xb1, 0x00, 0x00, 0x35, 0x93, 0xa2, 0x16, ++ 0x02, 0x30, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xbf, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xf4, 0x95, 0x00, 0x4a, 0x1f, 0x10, 0x01, 0x00, ++ 0x49, 0x93, 0x00, 0x10, 0x32, 0xb0, 0x00, 0x00, 0x8a, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x63, 0x94, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x66, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x74, 0x96, 0x00, 0x15, 0x94, 0x30, 0x01, 0x00, ++ 0x7b, 0x96, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x68, 0x94, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0x20, 0x98, 0x00, 0x45, ++ 0x81, 0x30, 0x01, 0x00, 0xba, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xfe, 0x91, 0x00, 0x45, 0x1f, 0x90, 0x00, 0x00, 0xb6, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x6f, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x49, 0x93, 0x00, 0x01, 0x2c, 0xb0, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x7a, 0x94, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, ++ 0x73, 0x94, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x62, 0xb1, 0x01, 0x00, 0x77, 0x94, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x74, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0xb1, 0x01, 0x00, 0x77, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xff, 0x89, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x58, 0x01, 0x20, 0x08, ++ 0xe0, 0xb1, 0x01, 0x00, 0x60, 0x01, 0x20, 0x16, 0xe0, 0xb1, 0x01, 0x00, ++ 0xb6, 0x96, 0x00, 0x47, 0x1f, 0x10, 0x01, 0x00, 0x6f, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x49, 0x93, 0x00, 0x01, 0x2c, 0xb0, 0x00, 0x00, ++ 0xbf, 0x95, 0x00, 0x47, 0x1f, 0x10, 0x01, 0x00, 0x8c, 0x94, 0xa2, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x88, 0x94, 0xa2, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0x74, 0x96, 0x00, 0x15, 0x94, 0x30, 0x01, 0x00, 0x7b, 0x96, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf9, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0xaf, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0xff, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x58, 0x01, 0x20, 0x08, ++ 0xe0, 0xb1, 0x01, 0x00, 0x60, 0x01, 0x20, 0x16, 0xe0, 0xb1, 0x01, 0x00, ++ 0xf4, 0x95, 0x00, 0x10, 0x32, 0x30, 0x01, 0x00, 0x49, 0x93, 0x00, 0x40, ++ 0x13, 0xb0, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x9c, 0x94, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, 0x95, 0x94, 0x37, 0x5c, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, ++ 0x99, 0x94, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x96, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, ++ 0x99, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xff, 0x89, 0x17, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x8e, 0xb0, 0x01, 0x00, ++ 0xb3, 0x96, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0xea, 0x96, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, ++ 0x6f, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xab, 0x94, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xa7, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x3f, 0x91, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, 0x3f, 0x91, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x14, 0x00, 0x2d, 0x45, 0x1f, 0x90, 0x01, 0x00, ++ 0x87, 0x91, 0x00, 0x44, 0x19, 0x90, 0x00, 0x00, 0xb3, 0x94, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x1f, 0x90, 0x01, 0x00, ++ 0xef, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x96, 0x00, 0x4a, ++ 0x1f, 0x10, 0x01, 0x00, 0x6f, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x49, 0x93, 0x00, 0x01, 0x2c, 0xb0, 0x00, 0x00, 0xf4, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x49, 0x93, 0x00, 0x10, 0x32, 0xb0, 0x00, 0x00, ++ 0xfe, 0x91, 0x00, 0x45, 0x1f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x37, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x33, 0xc3, 0x01, 0x00, ++ 0x36, 0x00, 0x00, 0x01, 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0xd2, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xbf, 0x94, 0x85, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x9f, 0x48, 0x03, 0xd0, 0x00, 0x00, 0xc1, 0x94, 0x9c, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x4c, 0x03, 0xd0, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x01, 0x34, 0xc3, 0x01, 0x00, 0x02, 0x00, 0x2d, 0x11, ++ 0x10, 0xc1, 0x00, 0x00, 0xc6, 0x94, 0x00, 0x40, 0x43, 0xc1, 0x00, 0x00, ++ 0xc6, 0x94, 0x00, 0x50, 0x43, 0xc1, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa1, ++ 0x42, 0xc9, 0x01, 0x00, 0xca, 0x94, 0x22, 0x40, 0xe5, 0x6d, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x40, 0xe5, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x49, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x41, 0x23, 0xd0, 0x00, 0x00, 0xc6, 0x94, 0x00, 0x50, ++ 0x43, 0xd1, 0x00, 0x00, 0x40, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0, 0xb1, 0x01, 0x00, ++ 0xd0, 0x95, 0x00, 0x41, 0xe1, 0x31, 0x01, 0x00, 0x00, 0x80, 0x00, 0x43, ++ 0x44, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x03, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd7, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0x01, 0x8c, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0xe0, 0xc1, 0x01, 0x00, 0xac, 0x00, 0x2f, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0x01, 0xe0, 0xc1, 0x01, 0x00, ++ 0xe1, 0x94, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, 0xfb, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe3, 0x94, 0x22, 0x47, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x13, 0x90, 0x01, 0x00, 0x8d, 0x98, 0x00, 0x47, ++ 0x19, 0x10, 0x01, 0x00, 0xc0, 0x00, 0x2d, 0x44, 0x1f, 0x90, 0x01, 0x00, ++ 0xc4, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0xd8, 0x98, 0x00, 0xf0, ++ 0x84, 0xb0, 0x00, 0x00, 0x90, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xf8, 0x94, 0xa2, 0x4b, 0x1f, 0x7c, 0x00, 0x00, 0x4b, 0x95, 0xa2, 0x4c, ++ 0x1f, 0x7c, 0x00, 0x00, 0xf8, 0x94, 0x1f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xfb, 0x94, 0xa2, 0x01, 0x80, 0x32, 0x00, 0x00, 0xa8, 0x00, 0x2d, 0x46, ++ 0x8f, 0xb0, 0x01, 0x00, 0xf1, 0x94, 0x1f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xb4, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xf3, 0x94, 0x22, 0xf0, ++ 0x3a, 0x6c, 0x00, 0x00, 0x48, 0x95, 0x1f, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0x40, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, ++ 0x8f, 0xb0, 0x01, 0x00, 0x8a, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x49, 0x95, 0x20, 0x42, 0xe7, 0x6d, 0x00, 0x00, 0xf7, 0x94, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x59, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x58, 0x8f, 0xb0, 0x01, 0x00, 0xfa, 0x94, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5c, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x5b, 0x8f, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0xff, 0x94, 0xa2, 0x42, 0x24, 0x6c, 0x00, 0x00, 0x08, 0x95, 0x23, 0xf0, ++ 0x02, 0x6c, 0x00, 0x00, 0x05, 0x95, 0xa2, 0xf0, 0x80, 0x32, 0x00, 0x00, ++ 0x4a, 0x95, 0xa2, 0x42, 0x24, 0x6c, 0x00, 0x00, 0x4a, 0x95, 0xa2, 0x41, ++ 0x03, 0x6c, 0x00, 0x00, 0x04, 0x95, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x51, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x52, ++ 0x8f, 0xb0, 0x01, 0x00, 0x4a, 0x95, 0x1f, 0x12, 0x84, 0x50, 0x00, 0x00, ++ 0x4a, 0x95, 0xa0, 0x01, 0x84, 0x6c, 0x00, 0x00, 0xf8, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x33, 0x95, 0xa2, 0x46, 0xe7, 0x7d, 0x00, 0x00, 0x14, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x25, 0x95, 0x22, 0xf0, 0x14, 0x30, 0x00, 0x00, ++ 0x11, 0x95, 0x20, 0x0a, 0x02, 0x6c, 0x00, 0x00, 0x22, 0x95, 0x03, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0x10, 0x95, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x44, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x49, ++ 0x8f, 0xb0, 0x01, 0x00, 0x16, 0x95, 0x22, 0x0a, 0x02, 0x6c, 0x00, 0x00, ++ 0x19, 0x95, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x15, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x56, 0x8f, 0xb0, 0x01, 0x00, 0x18, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x82, 0xd0, 0x01, 0x00, ++ 0x1f, 0x95, 0x20, 0x91, 0x83, 0x6c, 0x00, 0x00, 0x1e, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x26, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x27, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x21, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x1f, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x20, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x24, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x22, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x23, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x88, 0x00, 0x2d, 0x44, ++ 0x8f, 0xb0, 0x01, 0x00, 0x2e, 0x95, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x2b, 0x95, 0xa2, 0x43, 0x3d, 0x7c, 0x00, 0x00, 0x2b, 0x95, 0xa2, 0xf2, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x80, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, 0x2d, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, 0x2b, 0x95, 0xa0, 0x91, ++ 0x03, 0x6c, 0x00, 0x00, 0x29, 0x95, 0x22, 0x43, 0x3d, 0x7c, 0x00, 0x00, ++ 0x32, 0x95, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x28, 0x00, 0x80, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x29, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x3c, 0x95, 0xa2, 0xf0, ++ 0x14, 0x30, 0x00, 0x00, 0x88, 0x00, 0x2d, 0x44, 0x8f, 0xb0, 0x01, 0x00, ++ 0x39, 0x95, 0xa2, 0xf2, 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, ++ 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, ++ 0x2b, 0x95, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x29, 0x95, 0x20, 0x91, ++ 0x03, 0x6c, 0x00, 0x00, 0x2b, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x40, 0x95, 0x20, 0x0a, 0x02, 0x6c, 0x00, 0x00, 0x3f, 0x95, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, 0x45, 0x95, 0x22, 0x0a, ++ 0x02, 0x6c, 0x00, 0x00, 0x19, 0x95, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x44, 0x95, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x56, 0x8f, 0xb0, 0x01, 0x00, ++ 0x47, 0x95, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, ++ 0x4d, 0x95, 0x00, 0x43, 0x95, 0xb0, 0x00, 0x00, 0x4d, 0x95, 0x00, 0x41, ++ 0x95, 0xb0, 0x00, 0x00, 0x4d, 0x95, 0x00, 0x42, 0x95, 0xb0, 0x00, 0x00, ++ 0x4d, 0x95, 0x00, 0x44, 0x95, 0xb0, 0x00, 0x00, 0x4d, 0x95, 0x00, 0x4c, ++ 0x95, 0xb0, 0x00, 0x00, 0xf5, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x50, 0x95, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4b, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4c, 0x8f, 0xb0, 0x01, 0x00, ++ 0x2d, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, ++ 0x84, 0xb0, 0x01, 0x00, 0x55, 0x95, 0xa2, 0xf3, 0x96, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x01, 0xb0, 0x01, 0x00, 0x2d, 0x00, 0x2a, 0x41, ++ 0xe7, 0xd1, 0x01, 0x00, 0xd4, 0x00, 0x3d, 0x41, 0x85, 0xe0, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0xf2, 0x00, 0xe4, 0x01, 0x00, 0x5b, 0x95, 0x22, 0x5a, ++ 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x90, 0x01, 0x00, ++ 0x5c, 0x95, 0x00, 0x5a, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x63, 0x41, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0xa0, 0xa5, 0x85, 0x6c, 0x01, 0x00, 0x00, 0x00, 0xe3, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x3d, 0x99, 0x00, 0xf0, ++ 0x8c, 0xb0, 0x00, 0x00, 0x69, 0x95, 0x22, 0x40, 0x0f, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x66, 0x95, 0xa2, 0x4b, ++ 0x19, 0x7c, 0x00, 0x00, 0x67, 0x95, 0x22, 0xf0, 0x18, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0x4b, 0x19, 0x90, 0x01, 0x00, 0x32, 0x96, 0x00, 0x07, ++ 0x10, 0x30, 0x01, 0x00, 0x6f, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x6b, 0x95, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0xb8, 0x95, 0x00, 0x40, ++ 0x81, 0x30, 0x01, 0x00, 0x6f, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x32, 0x96, 0x00, 0x07, 0x10, 0x30, 0x01, 0x00, ++ 0x6f, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x32, 0x96, 0x00, 0x07, 0x10, 0x30, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0x74, 0x95, 0x33, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x77, 0x95, 0xa1, 0xad, 0x95, 0x20, 0x00, 0x00, 0x85, 0x95, 0x13, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4a, 0x5a, 0x83, 0x01, 0x00, ++ 0x30, 0x00, 0x39, 0x45, 0x95, 0xe0, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x0f, ++ 0x5e, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x5f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x45, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, ++ 0x48, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x4a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0x58, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, ++ 0x4e, 0xb0, 0x01, 0x00, 0x12, 0x86, 0x00, 0x40, 0x5d, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x41, 0x97, 0xb0, 0x00, 0x00, ++ 0x82, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0x86, 0x95, 0x44, 0x07, 0x96, 0x30, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x4b, 0x84, 0x89, 0x01, 0x00, 0x00, 0x00, 0x1c, 0xc2, ++ 0x24, 0xb0, 0x01, 0x00, 0x90, 0x95, 0xa2, 0x45, 0x25, 0x7c, 0x00, 0x00, ++ 0x8a, 0x95, 0x31, 0x20, 0x85, 0x30, 0x00, 0x00, 0x91, 0x95, 0x22, 0x12, ++ 0x48, 0x7f, 0x00, 0x00, 0x51, 0x98, 0x11, 0x12, 0x48, 0x03, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x1e, 0x94, 0x01, 0x00, 0x00, 0x00, 0x80, 0x5a, 0x1f, 0x90, 0x01, 0x00, ++ 0x90, 0x95, 0x31, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, ++ 0x24, 0xb0, 0x01, 0x00, 0x91, 0x95, 0x22, 0x12, 0x48, 0x7f, 0x00, 0x00, ++ 0x51, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x9e, 0x95, 0x0b, 0xf0, 0x84, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x11, 0x12, 0x48, 0x83, 0x01, 0x00, 0x9b, 0x95, 0x22, 0x50, ++ 0x85, 0x70, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x51, 0x97, 0x00, 0xf2, 0x96, 0x30, 0x01, 0x00, 0xd1, 0x99, 0x00, 0x12, ++ 0x94, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x1f, 0x90, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4b, ++ 0x1e, 0x94, 0x01, 0x00, 0x10, 0x00, 0x00, 0x42, 0x10, 0xf4, 0x01, 0x00, ++ 0x00, 0xb7, 0x3f, 0x43, 0x11, 0xf0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x08, ++ 0x8a, 0x88, 0x01, 0x00, 0xa1, 0x95, 0x30, 0xa1, 0x0c, 0x30, 0x00, 0x00, ++ 0xa4, 0x95, 0x22, 0x45, 0xe6, 0x7d, 0x00, 0x00, 0x91, 0x95, 0x10, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x45, 0xe6, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x12, 0x48, 0x83, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, 0x85, 0x80, 0x01, 0x00, ++ 0x5e, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x51, 0x97, 0x00, 0xf2, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0xd8, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x2e, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xaf, 0x95, 0x22, 0x40, 0xe7, 0x6d, 0x00, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x08, 0x86, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0xa7, 0x87, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0xb3, 0x95, 0xa8, 0x05, 0xe0, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x4b, 0x96, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x4b, 0x1e, 0x94, 0x01, 0x00, 0x10, 0x00, 0x00, 0x0f, ++ 0x84, 0xf4, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x42, 0x84, 0x88, 0x01, 0x00, ++ 0xbc, 0x95, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, 0xbd, 0x95, 0x00, 0x42, ++ 0x68, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x6a, 0xb1, 0x01, 0x00, ++ 0xbd, 0x95, 0x31, 0x5a, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x42, ++ 0x48, 0x93, 0x01, 0x00, 0xbf, 0x95, 0x35, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xc4, 0x95, 0x28, 0xb1, ++ 0x2c, 0x30, 0x00, 0x00, 0xc0, 0x95, 0x22, 0x4d, 0x75, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x95, 0x40, 0x11, 0xb0, 0x01, 0x00, 0x6d, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xc4, 0x95, 0xa8, 0xb1, 0x10, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x95, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x7f, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xcb, 0x95, 0x28, 0xb1, 0x10, 0x30, 0x00, 0x00, ++ 0xc7, 0x95, 0x9f, 0xba, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x11, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x24, 0x11, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcd, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xac, 0x94, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xd1, 0x95, 0x32, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xd7, 0x95, 0x22, 0xf8, 0x96, 0x30, 0x00, 0x00, 0x04, 0x00, 0x22, 0xf8, ++ 0x90, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x92, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x4b, 0xf0, 0xcd, 0x01, 0x00, 0x20, 0x00, 0x92, 0x48, ++ 0xe0, 0xc9, 0x01, 0x00, 0x6c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xdb, 0x95, 0x28, 0xb1, 0x92, 0x30, 0x00, 0x00, 0xd7, 0x95, 0x22, 0x4c, ++ 0x75, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x12, 0x40, 0x91, 0xb0, 0x00, 0x00, ++ 0x6c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xdb, 0x95, 0xa8, 0xb1, ++ 0x90, 0x30, 0x00, 0x00, 0xff, 0x00, 0x00, 0x48, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x90, 0xd0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x4b, ++ 0xf0, 0xcd, 0x01, 0x00, 0x20, 0x00, 0x00, 0x48, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x92, 0x49, 0xe0, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0x82, 0x8c, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0xf0, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, ++ 0x00, 0xec, 0x00, 0x00, 0xe8, 0x95, 0x22, 0x1a, 0x00, 0x6c, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x00, 0x34, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0xe4, 0x95, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x15, 0x82, 0x8c, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0xf0, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, ++ 0x00, 0xec, 0x00, 0x00, 0xf1, 0x95, 0x22, 0x0d, 0x00, 0x6c, 0x00, 0x00, ++ 0xcc, 0x95, 0x00, 0x00, 0x1a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0xed, 0x95, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xf6, 0x95, 0x83, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x90, 0x01, 0x00, ++ 0x24, 0x00, 0x2d, 0x01, 0x2c, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x2d, 0xf0, ++ 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x02, 0x00, 0x2d, 0x11, 0x10, 0xc1, 0x00, 0x00, ++ 0xff, 0x95, 0x00, 0x40, 0x43, 0xc1, 0x00, 0x00, 0xff, 0x95, 0x00, 0x50, ++ 0x43, 0xc1, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa1, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x96, 0x22, 0x40, 0xf5, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x43, 0xd1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, 0xe5, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x49, ++ 0x1f, 0x90, 0x01, 0x00, 0x07, 0x96, 0x22, 0x11, 0x1e, 0x7c, 0x00, 0x00, ++ 0x09, 0x96, 0xa0, 0xf0, 0x16, 0x40, 0x00, 0x00, 0x09, 0x96, 0x00, 0x41, ++ 0x17, 0xc0, 0x00, 0x00, 0x09, 0x96, 0xa0, 0xf4, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, ++ 0x23, 0xd0, 0x00, 0x00, 0xff, 0x95, 0x00, 0x52, 0x43, 0xd1, 0x00, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, 0x0c, 0x96, 0x30, 0x47, ++ 0x17, 0x04, 0x00, 0x00, 0x0f, 0x96, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x90, 0x42, 0x81, 0xb0, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0x13, 0x96, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, 0x00, 0x00, 0x90, 0x41, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x14, 0x96, 0x40, 0x07, 0x96, 0x30, 0x00, 0x00, 0xdb, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x1e, 0x96, 0xa2, 0x45, 0x95, 0x7c, 0x00, 0x00, ++ 0x01, 0x97, 0x3f, 0x41, 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xe6, 0xb1, 0x01, 0x00, ++ 0x40, 0x97, 0x3e, 0x40, 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0xe6, 0xb1, 0x01, 0x00, 0x40, 0x97, 0x3e, 0x40, 0x9d, 0xe0, 0x01, 0x00, ++ 0x31, 0x96, 0x00, 0x3b, 0xe7, 0xb1, 0x00, 0x00, 0x1e, 0x96, 0x30, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x28, 0x96, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0x24, 0x96, 0xa2, 0x0b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x98, 0x42, 0x81, 0xb0, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x98, 0x41, ++ 0x81, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x21, 0xa2, 0x95, 0x20, 0x00, 0x00, ++ 0x00, 0x00, 0x10, 0x4a, 0x44, 0x83, 0x01, 0x00, 0x00, 0x97, 0x3e, 0x41, ++ 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xf6, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0xe6, 0xb1, 0x01, 0x00, 0x40, 0x97, 0x3e, 0x40, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0x07, ++ 0x92, 0x89, 0x01, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x08, 0x86, 0xf4, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x43, ++ 0x46, 0xc9, 0x01, 0x00, 0x07, 0x00, 0x00, 0x08, 0x82, 0x88, 0x01, 0x00, ++ 0x35, 0x96, 0x40, 0x08, 0x96, 0x30, 0x00, 0x00, 0xdb, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x41, 0x96, 0x22, 0x45, 0x95, 0x7c, 0x00, 0x00, ++ 0x3d, 0x96, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0f, ++ 0x96, 0xf4, 0x01, 0x00, 0x3a, 0x96, 0x31, 0x5f, 0x97, 0x04, 0x00, 0x00, ++ 0x00, 0x00, 0x11, 0x4b, 0x48, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x6a, 0xb1, 0x01, 0x00, 0x3d, 0x96, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xe6, 0x81, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x97, 0x3f, 0x41, 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x96, 0xb0, 0x01, 0x00, 0x40, 0x97, 0x3d, 0x40, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0xf3, 0x88, 0xb0, 0x01, 0x00, 0x49, 0x96, 0xa2, 0x3b, ++ 0x89, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0xa6, 0x92, 0xb1, 0x01, 0x00, 0x4a, 0x96, 0x18, 0x4a, ++ 0x44, 0x93, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x30, 0x00, 0x39, 0x45, 0x97, 0xe0, 0x01, 0x00, 0x4f, 0x96, 0x22, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x1f, 0x04, 0x00, 0x0f, 0x98, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x5e, 0x94, 0x01, 0x00, 0x51, 0x96, 0x00, 0x05, ++ 0x4a, 0xb0, 0x00, 0x00, 0x1f, 0x04, 0x00, 0xa7, 0x5e, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x4b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x52, 0x96, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x55, 0x96, 0x40, 0x07, 0x96, 0x30, 0x00, 0x00, ++ 0xdb, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x59, 0x96, 0x22, 0x45, ++ 0x95, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xd9, 0x99, 0x00, 0x4a, 0x44, 0x13, 0x01, 0x00, 0x00, 0x97, 0x3f, 0x41, ++ 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, ++ 0x40, 0x97, 0x3d, 0x40, 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x63, 0xf3, ++ 0x88, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x38, 0x45, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x0f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0x61, 0x96, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x5a, 0x96, 0xa2, 0x3b, ++ 0x89, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x38, 0x45, 0x9d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xd1, 0x99, 0x00, 0x12, ++ 0x94, 0x30, 0x01, 0x00, 0x32, 0x96, 0x00, 0x5a, 0x1f, 0x00, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x5a, 0x1f, 0x90, 0x01, 0x00, 0x11, 0x00, 0x00, 0x4a, ++ 0xe6, 0xc9, 0x01, 0x00, 0x34, 0x00, 0x2f, 0x4f, 0x95, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x63, 0x4b, ++ 0x84, 0xc8, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x43, 0x85, 0x6c, 0x01, 0x00, ++ 0x00, 0x00, 0xe3, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x2d, 0x44, ++ 0x1f, 0x90, 0x01, 0x00, 0x32, 0x00, 0x2d, 0xf2, 0x2a, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf2, 0x02, 0x30, 0x00, 0x00, 0x51, 0x95, 0x00, 0x10, ++ 0x32, 0x30, 0x01, 0x00, 0x32, 0x00, 0xa0, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x99, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x02, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x97, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x4c, 0x02, 0xd0, 0x00, 0x00, ++ 0x78, 0x96, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x36, 0xb0, 0x01, 0x00, 0x88, 0x96, 0x22, 0x41, 0x03, 0x50, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x70, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x81, 0x96, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x7c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, 0x7c, 0x96, 0x00, 0x5c, ++ 0x01, 0x80, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0x10, 0xb1, 0x00, 0x00, 0x68, 0x01, 0x2d, 0x06, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x82, 0xc0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x46, 0xc9, 0x01, 0x00, 0xc7, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xaf, 0x96, 0x22, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x68, 0x08, 0x38, 0x96, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x41, ++ 0x82, 0xcc, 0x01, 0x00, 0x8d, 0x96, 0xaa, 0x41, 0x3b, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x11, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x1d, 0x04, 0xcc, 0x01, 0x00, ++ 0xae, 0x96, 0x26, 0x46, 0x23, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, ++ 0x12, 0xc8, 0x01, 0x00, 0x64, 0x01, 0x20, 0xf0, 0xe0, 0xb1, 0x01, 0x00, ++ 0xad, 0x96, 0x22, 0x41, 0x05, 0x50, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xf8, 0x86, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x9f, 0x96, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0xac, 0x96, 0x22, 0x41, 0x05, 0x50, 0x00, 0x00, 0xaa, 0x96, 0xa2, 0x41, ++ 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x1a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xa5, 0x96, 0xa8, 0x46, 0x23, 0x30, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x42, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x13, 0xc0, 0x01, 0x00, 0x9a, 0x96, 0x00, 0x50, ++ 0x49, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x1a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xae, 0x96, 0x22, 0x40, 0x3b, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x00, 0xb0, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x5c, ++ 0x01, 0x00, 0x01, 0x00, 0xaf, 0x96, 0x00, 0x41, 0x3b, 0xd0, 0x00, 0x00, ++ 0x00, 0x00, 0x8d, 0x47, 0x80, 0x32, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0x5f, ++ 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x8c, 0xc0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, ++ 0xbb, 0x96, 0x8c, 0xf8, 0x8e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x90, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf8, 0x14, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x26, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x2e, 0xf8, 0x0c, 0xb0, 0x01, 0x00, ++ 0x0c, 0x00, 0x2a, 0x4a, 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, ++ 0xe0, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, ++ 0xc8, 0x96, 0x20, 0x0a, 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x96, 0xb0, 0x01, 0x00, ++ 0x20, 0x00, 0x20, 0xf0, 0xe4, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x20, 0x4a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x1c, 0x00, 0x20, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0xb3, 0x96, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, 0x2c, 0x00, 0x2d, 0x42, ++ 0x19, 0x90, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, 0xce, 0x96, 0xa2, 0xa5, ++ 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, 0x95, 0xb0, 0x01, 0x00, ++ 0xd1, 0x96, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x41, 0x97, 0xc0, 0x01, 0x00, 0xd4, 0x00, 0x3e, 0x41, ++ 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, ++ 0xd6, 0x96, 0xa0, 0xa5, 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x2c, 0x00, 0x20, 0x41, 0xe6, 0xb1, 0x01, 0x00, ++ 0xdb, 0x96, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, ++ 0x98, 0xdc, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x4c, 0xe4, 0xf5, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x1f, 0x80, 0x01, 0x00, 0x0b, 0x00, 0x80, 0x00, ++ 0xe4, 0xf5, 0x01, 0x00, 0xd0, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x41, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, ++ 0xe7, 0x96, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd0, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, ++ 0xf6, 0x96, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, 0x84, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x63, 0xf3, 0x96, 0xc8, 0x01, 0x00, 0xfe, 0x96, 0x9f, 0x41, ++ 0x85, 0x50, 0x00, 0x00, 0x01, 0x00, 0x00, 0xa5, 0x85, 0xcc, 0x01, 0x00, ++ 0x2d, 0x00, 0xa0, 0x42, 0xe6, 0xb1, 0x01, 0x00, 0x5e, 0x01, 0x2d, 0x00, ++ 0x80, 0xb0, 0x01, 0x00, 0x03, 0x97, 0x52, 0x43, 0x81, 0x60, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0xf2, 0x82, 0xf4, 0x01, 0x00, 0x04, 0x97, 0x00, 0x41, ++ 0x80, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x81, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5e, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x95, 0xb0, 0x00, 0x00, ++ 0x05, 0x97, 0x9e, 0xbb, 0x80, 0x32, 0x00, 0x00, 0x0a, 0x97, 0xa2, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x41, 0x95, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x15, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x2b, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x38, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x3a, 0xb0, 0x01, 0x00, 0x1f, 0x97, 0x9c, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x14, 0x97, 0xa2, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x4c, 0x1f, 0x90, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x1e, ++ 0x98, 0xf4, 0x01, 0x00, 0x13, 0x97, 0xa2, 0x48, 0x99, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x42, 0xb1, 0x01, 0x00, 0x13, 0x97, 0xa2, 0x8a, ++ 0xf1, 0x6d, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x02, 0xcc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x3e, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x00, 0xf4, ++ 0x28, 0xcc, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x1e, 0x97, 0x20, 0xf0, 0x3e, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x2b, 0xc0, 0x01, 0x00, ++ 0xbf, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0xf3, ++ 0x3a, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x07, 0x00, 0x2a, 0x0c, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x04, ++ 0xe6, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x1c, 0x00, 0x2d, 0xf0, 0x16, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x2d, 0xf0, ++ 0x26, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x06, 0x14, 0xec, 0x00, 0x00, 0x2b, 0x97, 0x22, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x06, 0x2a, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x96, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x2a, 0x4c, 0xe1, 0xc1, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x18, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x35, 0x97, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x68, 0x01, 0x96, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x3b, 0x97, 0x45, 0x42, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x3c, 0x97, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x01, 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x42, 0x97, 0x45, 0x42, 0x61, 0x31, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x43, 0x97, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x4a, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0xf1, 0xb1, 0x01, 0x00, 0xc0, 0xa8, 0x3d, 0x46, 0x0d, 0xe0, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0xa1, 0xf0, 0x89, 0x01, 0x00, 0x02, 0x00, 0x00, 0x09, ++ 0x96, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xa8, 0x97, 0xc0, 0x01, 0x00, 0x4d, 0x97, 0x46, 0x42, ++ 0x61, 0x31, 0x00, 0x00, 0x30, 0x00, 0x00, 0x4a, 0x62, 0xc9, 0x01, 0x00, ++ 0x4e, 0x97, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x99, 0x3f, 0x42, 0x97, 0xf0, 0x01, 0x00, ++ 0x52, 0x97, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, 0x5a, 0x97, 0x22, 0xf3, ++ 0x74, 0x06, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, 0x94, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0xe7, 0x85, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x55, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x62, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x57, 0x97, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa8, 0x36, 0xb0, 0x01, 0x00, 0x6a, 0x97, 0x82, 0x41, ++ 0x23, 0x40, 0x00, 0x00, 0x5f, 0x97, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0xda, 0x94, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, 0x20, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x65, 0x97, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x62, 0x97, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x6a, 0x97, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xe2, 0x95, 0x00, 0x43, ++ 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x23, 0xb0, 0x01, 0x00, ++ 0x6c, 0x97, 0xa3, 0x15, 0x0c, 0x6c, 0x00, 0x00, 0x6d, 0x97, 0x00, 0x06, ++ 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x04, 0xb0, 0x01, 0x00, ++ 0x6f, 0x97, 0x20, 0x02, 0x1a, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x04, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x0b, 0x96, 0x88, 0x01, 0x00, ++ 0x74, 0x97, 0x26, 0x47, 0x97, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x97, 0xc0, 0x01, 0x00, 0x74, 0x97, 0x23, 0x4b, 0x04, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x04, 0xb0, 0x01, 0x00, 0x33, 0x98, 0x00, 0x05, ++ 0x48, 0x31, 0x01, 0x00, 0x9e, 0x97, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0x78, 0x97, 0xa2, 0x02, 0x2a, 0x50, 0x00, 0x00, 0x9e, 0x97, 0xa2, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x7a, 0x97, 0x22, 0x02, 0x0c, 0x50, 0x00, 0x00, ++ 0x83, 0x97, 0x00, 0x02, 0x16, 0xc0, 0x00, 0x00, 0x82, 0x97, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x82, 0x97, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x7e, 0x97, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x24, 0x97, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x9e, 0x97, 0x22, 0x15, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x9d, 0x97, 0xa2, 0x02, 0x1a, 0x50, 0x00, 0x00, 0x8f, 0x97, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x70, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x8f, 0x97, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x8b, 0x97, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1b, 0x84, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x10, 0xc8, 0x01, 0x00, ++ 0x2f, 0x00, 0x2f, 0x5c, 0x11, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0xe7, 0x91, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, 0x1b, 0x98, 0x01, 0x00, ++ 0x5c, 0x97, 0x20, 0x15, 0x1a, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x22, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, ++ 0xe0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x9a, 0x97, 0xa8, 0x46, ++ 0x1f, 0x10, 0x00, 0x00, 0x5c, 0x97, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x5c, 0x97, 0x00, 0x02, 0x10, 0xc0, 0x00, 0x00, 0xa0, 0x97, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0xda, 0x94, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0x10, 0xb1, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x08, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x03, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0xa7, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x17, 0x00, 0x00, 0xd0, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x27, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x00, 0xb0, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x41, ++ 0xa3, 0x41, 0x01, 0x00, 0xab, 0x97, 0x00, 0x41, 0x27, 0xd0, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x07, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x80, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb2, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x98, 0x00, 0x40, 0x2b, 0x30, 0x01, 0x00, 0xac, 0x00, 0x2d, 0x06, ++ 0x16, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, 0x16, 0xc4, 0x01, 0x00, ++ 0xba, 0x97, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x6c, 0xf0, 0x30, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x2d, 0x40, ++ 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xf0, 0x28, 0xb0, 0x01, 0x00, ++ 0xc3, 0x97, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x43, ++ 0x86, 0xc8, 0x01, 0x00, 0x00, 0x30, 0x00, 0x0b, 0x16, 0xc8, 0x01, 0x00, ++ 0xc3, 0x97, 0xa4, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0xe4, 0x97, 0x22, 0x06, 0x80, 0x32, 0x00, 0x00, ++ 0xd0, 0x97, 0xa2, 0x06, 0x14, 0x6c, 0x00, 0x00, 0xcd, 0x97, 0x22, 0x48, ++ 0x19, 0x7c, 0x00, 0x00, 0xc8, 0x97, 0xa0, 0x41, 0x17, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x31, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x20, 0x18, 0xe0, 0xb1, 0x01, 0x00, ++ 0x8b, 0x00, 0x2d, 0x48, 0x19, 0x80, 0x01, 0x00, 0x8b, 0x00, 0x20, 0x45, ++ 0xe7, 0x91, 0x01, 0x00, 0xd0, 0x97, 0x00, 0x40, 0x87, 0x90, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, 0xd0, 0x97, 0xa0, 0x48, ++ 0x17, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0xb0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x10, 0x50, 0x00, 0x43, ++ 0xfc, 0xc9, 0x01, 0x00, 0x3b, 0x98, 0x00, 0x30, 0x81, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0xdb, 0x97, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0xcc, 0x00, 0x2d, 0xab, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0x17, 0xc0, 0x01, 0x00, 0xda, 0x97, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0xdf, 0x97, 0x64, 0xf0, ++ 0x82, 0xb0, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xdf, 0x97, 0xa2, 0xf2, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe5, 0xb1, 0x01, 0x00, 0x8c, 0x00, 0x20, 0x18, 0xe0, 0xb1, 0x01, 0x00, ++ 0x90, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x60, 0x06, ++ 0x30, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x86, 0x0c, 0x80, 0xb2, 0x00, 0x00, ++ 0xbc, 0x00, 0x2d, 0x46, 0x19, 0x90, 0x01, 0x00, 0xa0, 0x00, 0xa0, 0xf2, ++ 0xe4, 0xb1, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x10, 0x50, 0x00, 0x43, 0xfc, 0xc9, 0x01, 0x00, 0x3b, 0x98, 0x00, 0x30, ++ 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x4a, 0x19, 0xfc, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0xab, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0x17, 0xc0, 0x01, 0x00, ++ 0xed, 0x97, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xe4, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x1b, 0xe0, 0xb1, 0x00, 0x00, ++ 0xf2, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x0c, ++ 0x7e, 0x89, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x4c, 0x95, 0x60, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x4a, 0x18, 0x94, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x01, 0xf0, 0x31, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x15, ++ 0xe0, 0xb1, 0x00, 0x00, 0xfd, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xe8, 0x5f, 0x17, 0x90, 0x01, 0x00, 0x70, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x7a, 0x01, 0x2e, 0xfe, 0x92, 0xb0, 0x01, 0x00, ++ 0x8b, 0x00, 0x2d, 0xf6, 0x16, 0xb0, 0x01, 0x00, 0x0a, 0x98, 0x22, 0x43, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xa6, 0x2a, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x6e, 0x06, ++ 0x82, 0xc8, 0x01, 0x00, 0x0e, 0x98, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x45, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x4c, ++ 0x83, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x92, 0xc0, 0x01, 0x00, ++ 0x0f, 0x98, 0x42, 0x30, 0x3d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x66, 0x9e, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x41, 0x3d, 0xc3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x92, 0xc0, 0x01, 0x00, 0x06, 0x00, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x49, 0x98, 0xf4, 0x01, 0x00, ++ 0x18, 0x98, 0x26, 0x30, 0x93, 0x04, 0x00, 0x00, 0x18, 0x98, 0x90, 0x4c, ++ 0x92, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, ++ 0xff, 0xff, 0x80, 0x49, 0xec, 0xa9, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x01, 0xf0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xf0, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x15, 0xe0, 0xb1, 0x00, 0x00, 0x1d, 0x98, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x2a, 0x98, 0x22, 0x5f, 0x81, 0x7c, 0x00, 0x00, ++ 0x29, 0x98, 0xa2, 0x40, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x19, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x07, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x97, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0x29, 0x98, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x26, 0x98, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x21, 0x81, 0x84, 0x00, 0x00, ++ 0x2d, 0x98, 0xa2, 0x5f, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x43, ++ 0x19, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x19, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x96, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x02, ++ 0xf0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x13, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x08, 0xe0, 0xb1, 0x00, 0x00, 0x38, 0x98, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x7c, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xf0, 0x98, 0xf4, 0x01, 0x00, 0x41, 0x98, 0x20, 0x4c, ++ 0x84, 0x6c, 0x00, 0x00, 0x88, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x41, 0x98, 0x20, 0xf2, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x98, 0x00, 0x2d, 0x14, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x98, 0xb0, 0x01, 0x00, 0xa3, 0x00, 0x2d, 0x14, ++ 0x98, 0xd0, 0x01, 0x00, 0x46, 0x98, 0x20, 0x4c, 0x84, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x80, 0xe0, 0x01, 0x00, 0x49, 0x98, 0x23, 0x40, 0x84, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x84, 0xb0, 0x01, 0x00, 0xd0, 0x00, 0x20, 0x14, ++ 0xe0, 0xb1, 0x01, 0x00, 0x98, 0x00, 0x25, 0x42, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x6e, 0xf3, 0x80, 0xf0, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x42, ++ 0x82, 0xc0, 0x00, 0x00, 0x4f, 0x98, 0xa0, 0x40, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0xf0, ++ 0x82, 0xec, 0x00, 0x00, 0x98, 0x00, 0xa0, 0x41, 0xe0, 0xb1, 0x01, 0x00, ++ 0x52, 0x98, 0x00, 0x12, 0x10, 0xc9, 0x00, 0x00, 0x00, 0x48, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x49, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x4b, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x4d, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x4f, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x50, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x52, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x54, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x56, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x57, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x59, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x5b, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x5d, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x5e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x60, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x62, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x64, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x65, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x67, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x69, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x6b, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x6c, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x6e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x70, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x72, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x73, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x75, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x77, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x79, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x7a, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x7c, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x7e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x72, 0x98, 0x43, 0x57, 0x61, 0x31, 0x00, 0x00, 0x7e, 0x98, 0xa2, 0x57, ++ 0x73, 0x7d, 0x00, 0x00, 0x7e, 0x98, 0xa2, 0x40, 0x81, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x4a, ++ 0x62, 0xdd, 0x01, 0x00, 0x76, 0x98, 0xa8, 0x4a, 0x80, 0x33, 0x00, 0x00, ++ 0x7b, 0x98, 0x22, 0x5f, 0x95, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x79, 0x98, 0xa8, 0x4b, 0xac, 0x33, 0x00, 0x00, ++ 0x00, 0x00, 0x1b, 0xa5, 0x82, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbe, ++ 0x83, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x10, 0x00, 0x4a, 0x62, 0xdd, 0x01, 0x00, 0x82, 0x98, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x7e, 0x98, 0x22, 0x57, 0x77, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x9b, 0x20, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x82, 0x98, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x9b, 0x40, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xa8, 0x01, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x60, 0xa7, 0x97, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xa8, 0x00, 0x2d, 0x1c, 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0xf0, ++ 0x8a, 0xd0, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x8b, 0xec, 0x00, 0x00, ++ 0x8a, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xa4, 0x00, 0x2d, 0x45, 0xe0, 0xd1, 0x01, 0x00, ++ 0x97, 0x98, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, 0xbe, 0x00, 0x2f, 0xab, ++ 0x83, 0xb0, 0x01, 0x00, 0xff, 0x98, 0x00, 0x14, 0x82, 0x50, 0x01, 0x00, ++ 0x9c, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x9c, 0x98, 0x22, 0xf2, ++ 0x82, 0x30, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x9c, 0x98, 0x9f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xff, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xa8, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, 0x9c, 0x00, 0x2d, 0x30, ++ 0x81, 0xb0, 0x01, 0x00, 0x88, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0x94, 0x00, 0x2d, 0xf2, 0x86, 0xb0, 0x01, 0x00, 0xc6, 0x98, 0x23, 0xf0, ++ 0x84, 0x6c, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x42, 0x88, 0xf4, 0x01, 0x00, ++ 0xc6, 0x98, 0x20, 0x50, 0x89, 0x6c, 0x00, 0x00, 0xb5, 0x98, 0xa3, 0x92, ++ 0x87, 0x6c, 0x00, 0x00, 0xa5, 0x98, 0x00, 0x44, 0x10, 0xc9, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x0a, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x09, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x08, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x07, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x07, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x07, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x06, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x06, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x06, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x06, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x06, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x05, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x05, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x05, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x05, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x05, 0x87, 0xb0, 0x00, 0x00, 0xb6, 0x98, 0x00, 0x44, ++ 0x10, 0xc9, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0f, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x0e, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0d, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0c, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x0c, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0c, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0c, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x0c, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0c, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0b, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x0b, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0b, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0b, 0x87, 0xb0, 0x00, 0x00, ++ 0xc6, 0x98, 0x00, 0x0b, 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0b, ++ 0x87, 0xb0, 0x00, 0x00, 0xc6, 0x98, 0x00, 0x0b, 0x87, 0xb0, 0x00, 0x00, ++ 0xbf, 0x00, 0x2d, 0x43, 0x84, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf3, ++ 0x80, 0xe0, 0x01, 0x00, 0xcb, 0x98, 0x23, 0x40, 0x84, 0x6c, 0x00, 0x00, ++ 0x94, 0x00, 0x20, 0x9d, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x84, 0xb0, 0x01, 0x00, 0xcf, 0x98, 0xa2, 0xf0, 0x38, 0x6c, 0x00, 0x00, ++ 0x9c, 0x00, 0x20, 0x42, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x13, 0x94, 0x01, 0x00, 0x00, 0x00, 0x80, 0x46, 0x19, 0x80, 0x01, 0x00, ++ 0x9c, 0x00, 0x20, 0x42, 0xe0, 0xb1, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x80, 0xf4, 0x01, 0x00, ++ 0x0f, 0x00, 0x00, 0xf3, 0x82, 0x88, 0x01, 0x00, 0xd5, 0x98, 0x23, 0x41, ++ 0x80, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x13, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x89, 0x0c, 0x80, 0xb2, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xa0, 0x00, 0xa0, 0xf2, 0xe4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x9f, 0x41, 0x24, 0xec, 0x00, 0x00, 0xdf, 0x98, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x42, 0x38, 0xec, 0x00, 0x00, ++ 0xdf, 0x98, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xe1, 0x98, 0xa3, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xe5, 0x98, 0x22, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0xb4, 0x00, 0x20, 0x1d, 0xe0, 0xb1, 0x01, 0x00, 0x80, 0x00, 0x2d, 0x5f, ++ 0x13, 0x94, 0x01, 0x00, 0xe5, 0x98, 0x23, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0x80, 0x00, 0x20, 0x1d, 0xe0, 0xb1, 0x01, 0x00, 0xc0, 0x00, 0x20, 0x12, ++ 0xe0, 0xb1, 0x01, 0x00, 0xc4, 0x00, 0xa0, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xe0, 0xb1, 0x01, 0x00, 0x12, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0xee, 0x98, 0x9f, 0x41, 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x12, 0x8c, 0xd0, 0x01, 0x00, ++ 0xef, 0x98, 0x00, 0x41, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x3d, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf1, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xbf, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x08, 0x80, 0x32, 0x01, 0x00, ++ 0xf8, 0x98, 0xa2, 0x40, 0x95, 0x6c, 0x00, 0x00, 0xcc, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x82, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, ++ 0xa0, 0x98, 0x2f, 0x40, 0x11, 0xb0, 0x01, 0x00, 0xe3, 0x89, 0x00, 0x41, ++ 0x89, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf8, 0x3e, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x9f, 0x12, 0xe0, 0xed, 0x00, 0x00, 0xc8, 0x00, 0x20, 0xab, ++ 0xe1, 0xb1, 0x01, 0x00, 0xcc, 0x00, 0xa0, 0x1f, 0xe0, 0xb1, 0x01, 0x00, ++ 0x01, 0x99, 0xa3, 0x5f, 0xe7, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe7, 0xc1, 0x01, 0x00, 0xa6, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x15, 0x99, 0x22, 0xf2, 0x86, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00, 0x43, ++ 0x84, 0xf4, 0x01, 0x00, 0x01, 0x00, 0x00, 0x41, 0x80, 0xcc, 0x01, 0x00, ++ 0xb8, 0x00, 0x2d, 0x42, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x62, 0x40, ++ 0x86, 0xc0, 0x01, 0x00, 0x09, 0x99, 0x1f, 0x43, 0x80, 0x32, 0x00, 0x00, ++ 0x0a, 0x99, 0xa2, 0x40, 0x87, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x62, 0x41, ++ 0x87, 0xb0, 0x01, 0x00, 0x0e, 0x99, 0x9f, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x84, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x88, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x44, ++ 0x84, 0xf4, 0x01, 0x00, 0xb8, 0x00, 0x2e, 0x42, 0x80, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x62, 0x40, 0x88, 0xc0, 0x01, 0x00, 0x14, 0x99, 0x1f, 0x44, ++ 0x80, 0x32, 0x00, 0x00, 0x18, 0x99, 0xa2, 0x40, 0x89, 0x6c, 0x00, 0x00, ++ 0x18, 0x99, 0x62, 0x41, 0x89, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x62, 0x41, ++ 0x86, 0xe4, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x62, 0x41, 0x88, 0xe4, 0x01, 0x00, 0xa4, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xa2, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xbc, 0x00, 0x2e, 0x43, 0x87, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x86, 0xc0, 0x01, 0x00, 0x1e, 0x99, 0x20, 0x43, 0x87, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x43, 0xe5, 0xb1, 0x01, 0x00, 0x40, 0x01, 0x00, 0x43, ++ 0x80, 0xce, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x43, 0xe4, 0x31, 0x01, 0x00, ++ 0x40, 0x01, 0xe2, 0x40, 0x87, 0x98, 0x01, 0x00, 0x88, 0x00, 0x2d, 0x44, ++ 0x81, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf2, 0x2e, 0xb0, 0x01, 0x00, ++ 0x9c, 0x00, 0x2d, 0xf0, 0x86, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0xba, 0x00, 0x2d, 0xf0, 0x98, 0xb0, 0x01, 0x00, ++ 0x2b, 0x99, 0xa2, 0x12, 0x98, 0x6c, 0x00, 0x00, 0xbc, 0x00, 0x2d, 0xf2, ++ 0x98, 0xb0, 0x01, 0x00, 0x2b, 0x99, 0xa0, 0xf2, 0x98, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x17, 0x82, 0xb0, 0x01, 0x00, 0x9c, 0x00, 0x20, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0xb4, 0x00, 0x2d, 0x12, 0x86, 0xd0, 0x01, 0x00, ++ 0x2e, 0x99, 0xa3, 0x41, 0xe0, 0x6d, 0x00, 0x00, 0x2f, 0x99, 0x00, 0xf0, ++ 0x84, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0xb0, 0x01, 0x00, ++ 0x80, 0x00, 0x2d, 0x43, 0x84, 0xd0, 0x01, 0x00, 0x32, 0x99, 0x9f, 0x42, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0x34, 0x99, 0xa3, 0x42, 0x14, 0x6c, 0x00, 0x00, 0x35, 0x99, 0x00, 0x0a, ++ 0x0c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x0c, 0xb0, 0x01, 0x00, ++ 0x37, 0x99, 0xa0, 0x17, 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x17, ++ 0x0c, 0xb0, 0x01, 0x00, 0x3c, 0x99, 0x22, 0x40, 0x0d, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0xa0, 0x0a, 0x0c, 0xec, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, ++ 0x82, 0xf4, 0x01, 0x00, 0x3c, 0x99, 0xa0, 0x41, 0x0c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0xd0, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x41, 0x87, 0x94, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, ++ 0x48, 0x99, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x05, 0x00, 0x2a, 0x0c, 0xe4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x04, 0xe6, 0xb1, 0x01, 0x00, 0x52, 0x99, 0x22, 0x49, ++ 0x1f, 0x7c, 0x00, 0x00, 0x42, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0x1f, 0x80, 0x01, 0x00, 0xaa, 0x97, 0x00, 0x40, ++ 0x8d, 0xb0, 0x00, 0x00, 0x58, 0x99, 0x22, 0x40, 0xaf, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x96, 0xb0, 0x01, 0x00, 0x72, 0x98, 0x00, 0x08, ++ 0x94, 0x30, 0x01, 0x00, 0x57, 0x99, 0x22, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0xaa, 0x97, 0x00, 0x46, 0x87, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x87, 0xb0, 0x01, 0x00, 0x58, 0x99, 0x43, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x10, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, 0x5d, 0x99, 0x28, 0x40, ++ 0x87, 0x30, 0x00, 0x00, 0x59, 0x99, 0x22, 0x48, 0x77, 0x7d, 0x00, 0x00, ++ 0xaa, 0x97, 0x1b, 0x46, 0x87, 0xb0, 0x00, 0x00, 0x60, 0x99, 0x22, 0x5f, ++ 0x11, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x15, 0x62, 0x31, 0x00, 0x00, ++ 0x5e, 0x99, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x93, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0xb0, 0x01, 0x00, ++ 0xb1, 0x99, 0x00, 0x49, 0x96, 0x30, 0x01, 0x00, 0x07, 0x00, 0x00, 0x49, ++ 0x06, 0xe4, 0x01, 0x00, 0x00, 0x39, 0x00, 0x03, 0x06, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xd0, ++ 0xa0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, ++ 0x65, 0x99, 0xa0, 0x54, 0x93, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x05, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x48, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xc0, 0x01, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0x6e, 0x99, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x49, 0xb3, 0x01, 0x00, 0xb6, 0x99, 0x00, 0x40, ++ 0x49, 0x31, 0x01, 0x00, 0x00, 0xb5, 0x2e, 0x08, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x74, 0x99, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x00, 0x97, 0x2e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x78, 0x99, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x40, 0x18, 0x2e, 0x05, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x7c, 0x99, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x57, 0x95, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x30, 0x94, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x40, 0xe5, 0x99, 0x01, 0x00, 0x56, 0x95, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xb8, 0x94, 0x20, 0x41, 0xe5, 0xb1, 0x01, 0x00, ++ 0xba, 0x94, 0x20, 0x41, 0xe5, 0xb1, 0x01, 0x00, 0x98, 0x94, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x86, 0x99, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x68, 0xb1, 0x01, 0x00, 0x8a, 0x99, 0x85, 0x41, 0x97, 0x40, 0x00, 0x00, ++ 0xc3, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x39, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x37, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x35, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x33, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x41, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x3f, 0xb3, 0x01, 0x00, 0x3c, 0x00, 0x00, 0x40, ++ 0x29, 0x9b, 0x01, 0x00, 0xee, 0x05, 0x00, 0x40, 0x25, 0x9b, 0x01, 0x00, ++ 0x42, 0x00, 0x00, 0x40, 0x4b, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x2f, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2d, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x47, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x43, 0xb3, 0x01, 0x00, 0x60, 0x00, 0x00, 0x40, 0x2b, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0xef, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0xf1, 0x93, 0x01, 0x00, 0xff, 0xff, 0x00, 0xa5, 0x3c, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x2c, 0x5b, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, ++ 0x45, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x59, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x57, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x27, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x53, 0xb3, 0x01, 0x00, ++ 0xa7, 0x99, 0xa2, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0xa7, 0x99, 0xa2, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0xa8, 0x99, 0x00, 0x40, 0x1d, 0xb3, 0x00, 0x00, ++ 0x50, 0x46, 0x00, 0x40, 0x1d, 0x9b, 0x01, 0x00, 0x00, 0xc0, 0x00, 0xa6, ++ 0x88, 0xb3, 0x01, 0x00, 0xff, 0x3f, 0x00, 0xa6, 0x3a, 0xb3, 0x01, 0x00, ++ 0x00, 0xc0, 0x00, 0x9d, 0x3b, 0x9b, 0x01, 0x00, 0xb4, 0x05, 0x00, 0x40, ++ 0x23, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x4d, 0xb3, 0x01, 0x00, ++ 0x08, 0x0a, 0x00, 0xa6, 0x14, 0xb3, 0x01, 0x00, 0x01, 0x01, 0x00, 0x8a, ++ 0x15, 0x9b, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa6, 0x56, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x5e, 0x57, 0xb5, 0x01, 0x00, 0x18, 0x00, 0x00, 0x4b, ++ 0x20, 0xe4, 0x01, 0x00, 0x06, 0x00, 0x00, 0x4b, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x43, 0x00, 0x4b, 0x96, 0xc8, 0x01, 0x00, 0x18, 0x00, 0x00, 0x10, ++ 0x20, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4b, 0x20, 0x94, 0x01, 0x00, ++ 0x00, 0x99, 0x2e, 0x0a, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xb7, 0x99, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, 0x00, 0xa9, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0xbb, 0x99, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0xbf, 0x99, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xbf, 0x99, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x87, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x80, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, ++ 0x82, 0xb1, 0x01, 0x00, 0xc5, 0x99, 0x85, 0x41, 0x97, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x90, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0xa6, 0x92, 0xb1, 0x01, 0x00, 0xca, 0x99, 0x85, 0x41, ++ 0x97, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xce, 0x99, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++ 0x80, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x9c, 0x4b, 0x82, 0x89, 0x01, 0x00, ++ 0xd1, 0x99, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x80, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x9c, 0xa6, 0x82, 0xb1, 0x01, 0x00, ++ 0xd4, 0x99, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4b, ++ 0x84, 0x89, 0x01, 0x00, 0x00, 0x00, 0x9c, 0xc2, 0x24, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x80, 0x4b, ++ 0x92, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0x80, 0xa6, 0x92, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4b, ++ 0x94, 0x89, 0x01, 0x00, 0x00, 0x00, 0x80, 0xca, 0x94, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0xdf, 0x99, 0x80, 0xa5, 0x80, 0x32, 0x00, 0x00, ++ 0xe0, 0x99, 0x00, 0xa5, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x81, 0xc0, 0x01, 0x00, 0xe1, 0x99, 0x80, 0xa5, 0x80, 0x32, 0x00, 0x00, ++ 0x80, 0x01, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0xea, 0x99, 0x20, 0x4f, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xea, 0x99, 0x20, 0x4b, 0x81, 0x6c, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0xea, 0x99, 0x20, 0x47, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x82, 0xdc, 0x01, 0x00, 0x03, 0x90, 0x00, 0x41, 0x20, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x14, 0x2f, 0x4c, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0xee, 0x99, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x64, 0x00, 0x00, 0xa5, ++ 0x80, 0xc8, 0x01, 0x00, 0xf1, 0x99, 0xa2, 0xa5, 0x80, 0x6c, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x90, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0xf4, 0x99, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x90, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0xf7, 0x99, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x70, 0x00, 0x00, 0x90, 0x20, 0xa9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0xfa, 0x99, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, 0xfc, 0x99, 0x1f, 0x91, ++ 0x80, 0x32, 0x00, 0x00, 0x40, 0x68, 0x00, 0x90, 0x20, 0xa9, 0x01, 0x00, ++ 0xe0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x21, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x22, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x23, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x25, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x26, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x27, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xd0, 0x14, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x30, 0x03, 0x00, 0x40, 0x85, 0x30, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x02, 0x01, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, ++ 0x04, 0x03, 0x00, 0x40, 0x80, 0x98, 0x01, 0x00, 0x06, 0x05, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x08, 0x07, 0x00, 0x41, 0x82, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0x85, 0x98, 0x01, 0x00, ++ 0x30, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x39, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd8, 0x14, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xff, 0x02, 0xa2, 0xf8, 0x80, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x22, 0xf0, ++ 0x82, 0x6c, 0x00, 0x00, 0xff, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd0, 0x14, 0x2e, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0xa3, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc1, 0xb3, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0x1e, 0x9a, 0x00, 0x40, ++ 0x10, 0xc9, 0x00, 0x00, 0x24, 0x9a, 0x00, 0x05, 0x81, 0xb0, 0x00, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2c, 0x9a, 0x00, 0x05, ++ 0x81, 0xb0, 0x00, 0x00, 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x31, 0x9a, 0x00, 0x44, 0xa5, 0xb3, 0x00, 0x00, 0x33, 0x9a, 0x00, 0x44, ++ 0xa5, 0xb3, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xa4, 0xe7, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe0, 0x81, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc1, ++ 0xf0, 0x89, 0x01, 0x00, 0x29, 0x9a, 0x22, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x25, 0x9a, 0x00, 0x41, 0xc1, 0xc3, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xc5, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x5a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0xa4, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x91, 0xb1, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0xc9, 0xf0, 0x89, 0x01, 0x00, 0x29, 0x9a, 0x22, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0x2d, 0x9a, 0x00, 0x41, 0xc1, 0xc3, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0xde, 0x85, 0x89, 0x01, 0x00, 0x29, 0x9a, 0x00, 0xc2, ++ 0xe0, 0xb1, 0x00, 0x00, 0xff, 0xff, 0x00, 0xde, 0x95, 0x89, 0x01, 0x00, ++ 0x29, 0x9a, 0x00, 0xca, 0xe0, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x00, 0xcb, ++ 0x81, 0xc8, 0x01, 0x00, 0x6a, 0x84, 0x00, 0x40, 0xf2, 0x93, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb6, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, 0xb6, 0x9f, 0x00, 0x88, ++ 0x9a, 0xb0, 0x00, 0x00, 0xb6, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, ++ 0xb6, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, 0xb6, 0x9f, 0x00, 0x88, ++ 0x9a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x9a, 0xb0, 0x01, 0x00, ++ 0xb6, 0x9f, 0x41, 0x40, 0x81, 0x32, 0x00, 0x00, 0xb9, 0x9f, 0x22, 0x40, ++ 0x7b, 0x6f, 0x00, 0x00, 0xb6, 0x9f, 0x19, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x19, 0x41, 0x7b, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, ++ 0xc4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, 0xc6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0xa2, 0xc8, 0xb3, 0x01, 0x00, 0x08, 0x14, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0xb0, 0x9f, 0x00, 0x4d, 0x9a, 0xcc, 0x01, 0x00, ++ 0xc2, 0x9f, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xc1, 0x01, 0x00, 0xc0, 0x9f, 0xa2, 0x41, 0x9b, 0x50, 0x00, 0x00, ++ 0xc6, 0x9f, 0x80, 0x80, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x52, 0x49, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xfd, 0x93, 0x01, 0x00, ++ 0xc9, 0x9f, 0x00, 0x42, 0xcd, 0x93, 0x00, 0x00, 0x00, 0x00, 0x51, 0x4a, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0xfd, 0x93, 0x01, 0x00, ++ 0xc9, 0x9f, 0x00, 0x43, 0xcb, 0x93, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xd9, 0x9f, 0x00, 0x40, 0x19, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x9a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x49, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x40, 0xf0, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x41, 0x4d, 0x80, 0xb2, 0x01, 0x00, 0xd1, 0x9f, 0x00, 0x40, ++ 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x49, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x9a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x10, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xe2, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe3, ++ 0x43, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x45, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x7b, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x48, 0x4f, ++ 0x40, 0xb1, 0x01, 0x00, 0xd9, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x6a, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x19, 0x9a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x35, 0x9a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x10, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, ++ }, ++}; +diff --git a/drivers/staging/slicoss/gbrcvucode.h b/drivers/staging/slicoss/gbrcvucode.h +new file mode 100644 +index 0000000..dc00834 +--- /dev/null ++++ b/drivers/staging/slicoss/gbrcvucode.h +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (c) 1997-2002 Alacritech, Inc. All rights reserved ++ * ++ * $Id: gbrcvucode.h,v 1.2 2006/03/27 15:12:15 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++#define GB_RCVUCODE_VERS_STRING "$Revision: 1.2 $" ++#define GB_RCVUCODE_VERS_DATE "$Date: 2006/03/27 15:12:15 $" ++ ++static ULONG GBRcvUCodeLen = 512; ++ ++static u8 GBRcvUCode[2560] = ++{ ++0x47, 0x75, 0x01, 0x00, 0x04, 0xa0, 0x13, 0x01, 0x00, 0x1c, 0xb7, 0x5b, 0x09, ++0x30, 0x00, 0xb6, 0x5f, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x18, 0x3b, ++0x78, 0x3a, 0x00, 0x1c, 0xa2, 0x77, 0x01, 0x00, 0x1c, 0x07, 0x1d, 0x01, 0x70, ++0x18, 0xb3, 0x7b, 0xa9, 0xaa, 0x1e, 0xb4, 0x7b, 0x01, 0x0c, 0x1c, 0xb5, 0x7b, ++0x1d, 0x06, 0x1c, 0x00, 0x00, 0x40, 0x64, 0x08, 0x0c, 0x31, 0x56, 0x70, 0x04, ++0x0c, 0x31, 0x56, 0x80, 0x04, 0x0c, 0x31, 0x4a, 0x90, 0x04, 0x0c, 0x31, 0x46, ++0xa0, 0x00, 0x09, 0x25, 0x51, 0xc0, 0x04, 0x0c, 0x31, 0x4e, 0xb0, 0x00, 0xe9, ++0x24, 0x51, 0xc0, 0x04, 0xcc, 0xb3, 0x00, 0x1c, 0x1c, 0xeb, 0x2d, 0x01, 0x00, ++0x1c, 0x06, 0x56, 0x42, 0xd4, 0x08, 0x07, 0x9d, 0x00, 0x00, 0x1c, 0x7b, 0xb7, ++0x02, 0x00, 0x10, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0x06, 0x56, 0x5a, 0xc0, 0x04, ++0xa0, 0x30, 0x6c, 0x03, 0x00, 0xac, 0x30, 0x6d, 0x03, 0x00, 0xcd, 0x03, 0x3a, ++0x00, 0x1c, 0x7b, 0xb7, 0x02, 0x00, 0x1c, 0x60, 0x8e, 0x41, 0x54, 0x09, 0x29, ++0x25, 0x6d, 0x03, 0x00, 0x80, 0x8e, 0x41, 0x54, 0x09, 0x8c, 0x30, 0x8d, 0x00, ++0x04, 0x47, 0x1c, 0x01, 0x00, 0x1c, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0x00, 0x00, ++0x60, 0x00, 0x04, 0x47, 0x1c, 0x61, 0xc0, 0x04, 0x47, 0x1c, 0x6d, 0x03, 0x00, ++0x6c, 0x30, 0x01, 0x00, 0x1c, 0x4d, 0x34, 0x02, 0x00, 0x1c, 0x7b, 0xb7, 0x02, ++0x00, 0x1c, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xc8, 0x83, 0x37, 0x00, 0x1c, 0x80, ++0x01, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x60, 0x00, 0x04, 0xa0, 0x0f, 0x40, 0x54, ++0x09, 0x00, 0x00, 0x6c, 0xc3, 0x04, 0x7b, 0xfb, 0xf2, 0x00, 0x1c, 0xcc, 0x33, ++0x0d, 0x00, 0x1c, 0xb4, 0x7b, 0xfd, 0x03, 0x1c, 0x80, 0x0e, 0x40, 0x54, 0x09, ++0xe0, 0xfb, 0x05, 0x00, 0x1c, 0x00, 0x00, 0xa0, 0x03, 0x00, 0xb3, 0x0f, 0x41, ++0x54, 0x09, 0x00, 0x00, 0xe8, 0x70, 0x04, 0x00, 0x00, 0xe8, 0x80, 0x04, 0x00, ++0x00, 0xa0, 0x93, 0x00, 0x61, 0x76, 0xa1, 0xc3, 0x04, 0xc0, 0x8d, 0x41, 0x54, ++0x09, 0xe0, 0x7b, 0x00, 0xc0, 0x1f, 0xa0, 0xfd, 0xc1, 0x01, 0x00, 0xcc, 0x33, ++0x05, 0x00, 0x1c, 0xd4, 0x03, 0x00, 0x3c, 0x1c, 0xd4, 0xd3, 0x1b, 0x00, 0x1c, ++0xc0, 0xd3, 0x52, 0x00, 0x1c, 0x00, 0x00, 0x74, 0x13, 0x04, 0x8e, 0x8e, 0x42, ++0x54, 0x09, 0x5b, 0x80, 0x76, 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, ++0x00, 0x90, 0x01, 0x00, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xa0, 0x0f, 0x41, 0x54, ++0x09, 0xc0, 0x03, 0xfc, 0x7f, 0x1c, 0xa0, 0x01, 0x9c, 0x01, 0x00, 0x00, 0x00, ++0xa0, 0x01, 0x00, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xc0, 0x03, 0xfc, 0x03, 0x1c, ++0xf5, 0x77, 0x01, 0x00, 0x1c, 0x26, 0x7a, 0xf6, 0x05, 0x1c, 0xa0, 0x0f, 0x41, ++0x54, 0x09, 0xb3, 0x0f, 0x41, 0x54, 0x09, 0xb5, 0x02, 0x02, 0x00, 0x1c, 0xa0, ++0x0f, 0x41, 0x54, 0x09, 0x7a, 0x06, 0x02, 0x00, 0x1c, 0xb5, 0x02, 0x02, 0x00, ++0x1c, 0x53, 0x0f, 0x42, 0x54, 0x09, 0xaf, 0x03, 0x01, 0x00, 0x1c, 0x7a, 0x0e, ++0x42, 0x54, 0x09, 0xb5, 0x02, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x02, 0x00, 0x1c, ++0xa0, 0x3d, 0xa6, 0x11, 0x04, 0x00, 0x00, 0xa8, 0x11, 0x04, 0xd4, 0xd3, 0x52, ++0x00, 0x1c, 0xb5, 0x3e, 0xae, 0x01, 0x00, 0x20, 0xfb, 0xfd, 0xff, 0x1f, 0x80, ++0x2c, 0x84, 0x03, 0x00, 0xb9, 0x3a, 0x9a, 0x01, 0x00, 0x75, 0x3b, 0x02, 0x00, ++0x1c, 0xa7, 0x1c, 0x01, 0x00, 0x10, 0xdb, 0x83, 0x16, 0x00, 0x1c, 0xc7, 0x1d, ++0x1d, 0xc1, 0x04, 0xb9, 0x3b, 0x89, 0xc1, 0x04, 0x8b, 0x2c, 0x01, 0x00, 0x1c, ++0x6b, 0x2c, 0x31, 0xc1, 0x04, 0x00, 0x00, 0x74, 0x11, 0x00, 0xcb, 0x2c, 0x75, ++0xc1, 0x04, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0x54, ++0xd0, 0x02, 0x00, 0x1c, 0x49, 0x25, 0xad, 0x01, 0x00, 0xab, 0x2c, 0x7d, 0xc1, ++0x04, 0xa7, 0x1d, 0x6d, 0x03, 0x00, 0xcc, 0x33, 0x09, 0x00, 0x1c, 0xeb, 0x2d, ++0x01, 0x00, 0x1c, 0xea, 0x29, 0x01, 0x00, 0x1c, 0xa0, 0x0f, 0x41, 0x54, 0x09, ++0xae, 0x0f, 0x41, 0x54, 0x09, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xd4, 0x07, 0xfc, ++0x03, 0x1c, 0x99, 0x3a, 0x02, 0x00, 0x1c, 0xbb, 0x38, 0x02, 0x00, 0x1c, 0x00, ++0x38, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xf8, 0x01, 0x04, 0xdb, 0x3b, 0x7e, 0x00, ++0x1c, 0xc7, 0x1d, 0x01, 0x00, 0x1c, 0x26, 0x7a, 0x0a, 0x06, 0x1c, 0x27, 0x1d, ++0x01, 0x00, 0x1c, 0xb3, 0x0f, 0x41, 0x54, 0x09, 0x7a, 0x0e, 0x42, 0x54, 0x09, ++0x53, 0x0f, 0x42, 0x54, 0x09, 0x7a, 0x0e, 0x42, 0x54, 0x09, 0x53, 0x0f, 0x42, ++0x54, 0x09, 0x7a, 0x0e, 0x42, 0x54, 0x09, 0x53, 0x0f, 0x42, 0x54, 0x09, 0xa0, ++0x0f, 0x41, 0x54, 0x09, 0x7a, 0x06, 0x02, 0x00, 0x1c, 0x53, 0x0f, 0x42, 0x54, ++0x09, 0xaf, 0x03, 0x01, 0x00, 0x1c, 0x7a, 0x0e, 0x42, 0x54, 0x09, 0x53, 0x0f, ++0x42, 0x54, 0x09, 0x7a, 0x0e, 0x42, 0x54, 0x09, 0x53, 0x0f, 0x42, 0x54, 0x09, ++0x7a, 0x0e, 0x42, 0x54, 0x09, 0x53, 0x0f, 0x42, 0x54, 0x09, 0x7a, 0x0e, 0x42, ++0x54, 0x09, 0x00, 0x3d, 0x02, 0x00, 0x1c, 0x00, 0x00, 0x54, 0x12, 0x00, 0xcb, ++0x2c, 0x01, 0x00, 0x1c, 0x75, 0x3b, 0x02, 0x00, 0x1c, 0xa7, 0x1c, 0x01, 0x00, ++0x10, 0xa6, 0x7b, 0xf1, 0x05, 0x1c, 0x00, 0x00, 0x88, 0xc2, 0x04, 0xa6, 0x7b, ++0xf1, 0x05, 0x1c, 0x00, 0x00, 0xa0, 0xc2, 0x04, 0xcb, 0x2f, 0x05, 0x00, 0x1c, ++0x60, 0x2c, 0x00, 0x00, 0x1c, 0xc7, 0x1c, 0xe1, 0x02, 0x00, 0x53, 0x0f, 0x42, ++0x54, 0x09, 0xc0, 0x83, 0xf1, 0x32, 0x1c, 0x00, 0x00, 0x5c, 0x02, 0x04, 0x46, ++0x7a, 0xda, 0x05, 0x1c, 0x7a, 0x0e, 0x42, 0x54, 0x09, 0xc0, 0x83, 0xf1, 0x32, ++0x1c, 0x00, 0x00, 0x64, 0x02, 0x04, 0x40, 0xfa, 0x15, 0x00, 0x1c, 0x00, 0x00, ++0xa0, 0x02, 0x04, 0x46, 0x7a, 0xda, 0x05, 0x1c, 0xa0, 0x0f, 0x41, 0x54, 0x09, ++0xa0, 0x0f, 0x41, 0x54, 0x09, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xa0, 0x0f, 0x41, ++0x54, 0x09, 0xb3, 0x7b, 0x01, 0xc0, 0x1f, 0x74, 0x0e, 0x40, 0x54, 0x09, 0xc0, ++0x03, 0x9c, 0x00, 0x1c, 0x80, 0x00, 0xf0, 0x02, 0x00, 0x00, 0x00, 0xf0, 0x02, ++0x04, 0x00, 0x00, 0xc4, 0x12, 0x05, 0x07, 0x1d, 0x01, 0x00, 0x1c, 0xd4, 0xd3, ++0x2b, 0x00, 0x1c, 0xd4, 0xd3, 0x52, 0x00, 0x1c, 0x80, 0x76, 0x95, 0x13, 0x04, ++0x00, 0x00, 0xf8, 0x02, 0x00, 0xa6, 0x7b, 0xa9, 0x03, 0x10, 0xc7, 0x9c, 0x00, ++0x00, 0x1c, 0x80, 0x2c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x78, 0x02, 0x04, 0x00, ++0x00, 0x6c, 0xc3, 0x04, 0xab, 0x2d, 0xf1, 0x12, 0x05, 0x07, 0x1d, 0xcd, 0xc2, ++0x04, 0x8b, 0x2d, 0x01, 0x00, 0x1c, 0x69, 0x25, 0x01, 0x00, 0x1c, 0xa6, 0x7b, ++0xa9, 0x03, 0x10, 0xcb, 0x2f, 0x09, 0x00, 0x1c, 0x60, 0x2c, 0x00, 0x00, 0x1c, ++0x00, 0x00, 0x60, 0x03, 0x00, 0x53, 0x0f, 0x42, 0x54, 0x09, 0x46, 0x7a, 0xda, ++0x05, 0x1c, 0x7a, 0x0e, 0x42, 0x54, 0x09, 0x40, 0xfa, 0x15, 0x00, 0x1c, 0x00, ++0x00, 0x28, 0x03, 0x04, 0x46, 0x7a, 0xda, 0x05, 0x1c, 0xb5, 0x0f, 0x41, 0x54, ++0x09, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0x73, 0xec, 0x42, 0x03, 0x04, 0x60, 0x2c, ++0x00, 0x00, 0x1c, 0x00, 0x00, 0x40, 0x03, 0x00, 0xc7, 0x1c, 0x01, 0x00, 0x1c, ++0x00, 0x00, 0x40, 0x13, 0x05, 0x07, 0x1d, 0x01, 0x00, 0x1c, 0xc0, 0xd7, 0x22, ++0x00, 0x1c, 0x75, 0x56, 0x96, 0x13, 0x04, 0x60, 0x2c, 0x00, 0x00, 0x1c, 0xe7, ++0x1c, 0x5d, 0x03, 0x04, 0xe7, 0x9c, 0x00, 0x00, 0x1c, 0xa6, 0x7b, 0xa9, 0x03, ++0x10, 0x80, 0x2c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x10, 0x03, 0x04, 0x00, 0x00, ++0x6c, 0xc3, 0x04, 0xb9, 0x7b, 0x01, 0x00, 0x1c, 0x00, 0x00, 0xa0, 0xc3, 0x04, ++0xcb, 0xaf, 0xfc, 0x07, 0x1c, 0xcb, 0x2f, 0x01, 0x04, 0x1c, 0xc7, 0x9f, 0x80, ++0x03, 0x1c, 0x00, 0x00, 0xa0, 0xc3, 0x04, 0xcb, 0xaf, 0xfc, 0x07, 0x1c, 0xcb, ++0x2f, 0x0d, 0x04, 0x1c, 0xc7, 0x9f, 0x80, 0x03, 0x1c, 0x00, 0x00, 0xa0, 0xc3, ++0x04, 0xcb, 0xaf, 0x00, 0xf8, 0x1d, 0xcb, 0x2f, 0x01, 0x00, 0x1d, 0x00, 0x00, ++0xa0, 0xc3, 0x04, 0x00, 0x00, 0xa0, 0x13, 0x05, 0x07, 0x1d, 0x01, 0x00, 0x1c, ++0xc0, 0x1d, 0xf0, 0xd3, 0x08, 0x27, 0x9d, 0xf8, 0x03, 0x00, 0xa0, 0xee, 0x56, ++0xd4, 0x00, 0xfb, 0x75, 0x19, 0x14, 0x04, 0x20, 0x7b, 0x06, 0x00, 0x1c, 0xc0, ++0x1c, 0x2c, 0x04, 0x00, 0x00, 0x00, 0xc4, 0xd3, 0x08, 0x00, 0x00, 0x10, 0xf4, ++0x00, 0xc0, 0xef, 0xf2, 0x00, 0x1c, 0x20, 0x25, 0x6c, 0x14, 0x04, 0x60, 0xb7, ++0xe6, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x15, 0x00, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, ++0xcc, 0x33, 0x05, 0x02, 0x1c, 0x00, 0x00, 0x1c, 0xc5, 0x04, 0x60, 0xb7, 0x1e, ++0x05, 0x04, 0x00, 0x00, 0x1c, 0x15, 0x04, 0x00, 0x00, 0x6c, 0xc4, 0x04, 0xc0, ++0x1d, 0xac, 0xf3, 0x04, 0x00, 0x00, 0x78, 0xc4, 0x04, 0x07, 0x9d, 0x00, 0x00, ++0x1c, 0x1b, 0x74, 0x0d, 0xf4, 0x04, 0xa0, 0x0f, 0x41, 0x54, 0x09, 0xe0, 0x7b, ++0x00, 0xfc, 0x1f, 0x39, 0x7f, 0x02, 0x00, 0x1c, 0x07, 0x1d, 0xb1, 0xc3, 0x04, ++0xa6, 0x7b, 0xc1, 0x03, 0x1c, 0x00, 0x00, 0x78, 0xc4, 0x04, 0xe0, 0x1c, 0x00, ++0x00, 0x1c, 0x00, 0x00, 0xb8, 0x03, 0x04, 0xcb, 0xaf, 0x00, 0xf8, 0x1d, 0xcb, ++0x2f, 0x01, 0x10, 0x1d, 0x00, 0x00, 0xc0, 0xc3, 0x04, 0x00, 0x00, 0xc0, 0x03, ++0x04, 0xcb, 0xaf, 0x00, 0xf8, 0x1d, 0xcb, 0x2f, 0x01, 0x18, 0x1d, 0xc7, 0x9f, ++0x00, 0x0b, 0x1c, 0x00, 0x00, 0xc0, 0xc3, 0x04, 0xfb, 0x75, 0x01, 0x00, 0x1c, ++0x07, 0x1d, 0x01, 0x00, 0x1c, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x01, ++0x02, 0x1c, 0x00, 0x00, 0xc0, 0xc3, 0x04, 0xa0, 0x1c, 0x00, 0x00, 0x1c, 0xa0, ++0xee, 0xb6, 0x03, 0x04, 0xcb, 0xaf, 0xfc, 0x07, 0x1c, 0xcb, 0x2f, 0x09, 0x04, ++0x1c, 0xfb, 0x75, 0x01, 0x00, 0x1c, 0x00, 0x00, 0xc0, 0xc3, 0x04, 0xcc, 0xb3, ++0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x01, 0x02, 0x1c, 0x00, 0x00, 0x1c, 0xc5, 0x04, ++0x00, 0x00, 0x88, 0x34, 0x05, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x15, ++0x02, 0x1c, 0x47, 0x9d, 0x64, 0xc4, 0x04, 0x00, 0x00, 0x88, 0x44, 0x00, 0x80, ++0x1d, 0x8c, 0x54, 0x04, 0x87, 0x1d, 0x9d, 0x04, 0x00, 0xce, 0x76, 0x01, 0x00, ++0x1c, 0xef, 0x76, 0xad, 0xc4, 0x04, 0xa4, 0x77, 0x9d, 0x24, 0x09, 0xe4, 0x76, ++0x01, 0x00, 0x1c, 0xc4, 0x76, 0x01, 0x00, 0x1c, 0x00, 0x00, 0xa8, 0x54, 0x04, ++0xd7, 0x76, 0x01, 0x50, 0x18, 0xf6, 0x76, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, ++0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10, 0xcc, 0x30, 0x51, 0xc5, 0x04, 0xeb, ++0x2d, 0x01, 0x00, 0x1c, 0xea, 0x29, 0x01, 0x00, 0x1c, 0xc0, 0x59, 0x01, 0x00, ++0x1c, 0xf5, 0x77, 0x39, 0xc5, 0x04, 0xe0, 0x30, 0xec, 0x04, 0x00, 0x00, 0x4c, ++0xc0, 0x04, 0x00, 0x20, 0x4c, 0x04, 0x05, 0x00, 0x00, 0x00, 0xf8, 0x04, 0x00, ++0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x09, 0x02, 0x1c, 0xeb, 0x2d, 0xc5, ++0xc4, 0x04, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x19, 0x02, 0x1c, 0xeb, ++0x2d, 0xc5, 0xc4, 0x04, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x0d, 0x02, ++0x1c, 0xeb, 0x2d, 0xc5, 0xc4, 0x04, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, ++0x11, 0x02, 0x1c, 0xeb, 0x2d, 0xc5, 0xc4, 0x04, 0x00, 0x7b, 0x00, 0x80, 0x1c, ++0xae, 0x77, 0x51, 0x05, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x04, 0xd3, 0x8b, 0x00, ++0xfc, 0x1f, 0x60, 0x7a, 0x3c, 0x00, 0x1c, 0x60, 0x4c, 0xd0, 0x04, 0x00, 0xc0, ++0x2f, 0x20, 0x05, 0x1f, 0xe0, 0x30, 0xc0, 0x04, 0x00, 0x80, 0x25, 0xc0, 0x04, ++0x00, 0xb5, 0x5b, 0xc1, 0x04, 0x04, 0x69, 0x26, 0x01, 0x00, 0x1c, 0x6a, 0x2b, ++0x01, 0x00, 0x1c, 0x80, 0x1d, 0x00, 0x00, 0x1c, 0xa9, 0x25, 0x51, 0x05, 0x00, ++0xee, 0x30, 0x00, 0x00, 0x1c, 0xaf, 0x77, 0x11, 0x05, 0x00, 0xb4, 0x5f, 0x01, ++0x40, 0x18, 0x07, 0x9d, 0x54, 0x55, 0x04, 0xb7, 0x76, 0x01, 0x00, 0x1c, 0x96, ++0x76, 0x01, 0x00, 0x1c, 0x47, 0x1d, 0x01, 0x00, 0x1c, 0xa4, 0x33, 0x01, 0x60, ++0x18, 0xa4, 0x2f, 0x01, 0x60, 0x18, 0x64, 0x77, 0x01, 0x60, 0x18, 0x24, 0x77, ++0x01, 0x60, 0x18, 0x44, 0x77, 0x01, 0x00, 0x1c, 0x64, 0x88, 0x03, 0x00, 0x1c, ++0xa4, 0x3f, 0x01, 0x00, 0x1c, 0xa4, 0x3b, 0x01, 0x00, 0x1c, 0x53, 0x77, 0x01, ++0x00, 0x1c, 0xd3, 0xcf, 0x3b, 0x00, 0x1c, 0x53, 0x4f, 0x02, 0x00, 0x1c, 0xd3, ++0xcf, 0x00, 0x00, 0x1f, 0xda, 0xcf, 0x0b, 0x00, 0x1c, 0xd5, 0x57, 0x0f, 0x00, ++0x1c, 0xd3, 0xd3, 0x37, 0x00, 0x1c, 0xd4, 0x53, 0x0f, 0x00, 0x1c, 0xe0, 0x29, ++0x00, 0x00, 0x1c, 0xf5, 0xd5, 0xc0, 0x05, 0x00, 0x00, 0x00, 0xac, 0x55, 0x04, ++0x77, 0x56, 0x01, 0x00, 0x1c, 0x56, 0x53, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, ++0x10, 0x18, 0x00, 0x00, 0x04, 0xc0, 0x04, 0xf5, 0x55, 0x01, 0x00, 0x1c, 0x00, ++0x00, 0xc4, 0x55, 0x04, 0x77, 0x56, 0x01, 0x00, 0x1c, 0x56, 0x53, 0x01, 0x00, ++0x1c, 0x00, 0x00, 0x00, 0x10, 0x18, 0x00, 0x00, 0x04, 0xc0, 0x04, 0xcb, 0x2f, ++0x01, 0x18, 0x10, 0xcb, 0x2f, 0x01, 0x10, 0x10, 0xcb, 0x2f, 0x01, 0x08, 0x10, ++0xcb, 0x2f, 0x01, 0x08, 0x10, 0xcb, 0x2f, 0x01, 0x20, 0x10, 0xcb, 0x2f, 0x01, ++0x00, 0x10, 0xcb, 0x2f, 0x01, 0x28, 0x10, 0x89, 0x25, 0x6d, 0xc2, 0x04, 0x00, ++0x00, 0x04, 0xc3, 0x04, 0x00, 0x00, 0x6c, 0xc3, 0x04, 0x00, 0x00, 0x6c, 0xc3, ++0x04, 0x00, 0x00, 0x6c, 0xc3, 0x04, 0x00, 0x00, 0x6c, 0xc2, 0x04, 0x00, 0x00, ++0x04, 0xc3, 0x04, 0x00, 0x00, 0x6c, 0xc3, 0x04, 0x00, 0x00, 0x6c, 0xc3, 0x04, ++0x00, 0x00, 0x6c, 0xc3, 0x04, 0x40, 0x1c, 0x68, 0xc0, 0x04, 0x40, 0x1c, 0x98, ++0xc0, 0x04, 0xa7, 0x77, 0x6d, 0xc3, 0x04, 0x00, 0x00, 0xc0, 0xc0, 0x04, 0x27, ++0x1d, 0xed, 0xc0, 0x04, 0x00, 0x00, 0x6c, 0xc3, 0x04, 0x00, 0x00, 0x6c, 0xc3, ++0x04, 0x00, 0x00, 0x6c, 0xc3, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, ++0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, ++0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, ++0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, ++0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, 0x00, 0x00, 0x3c, 0xc6, 0x04, ++}; +diff --git a/drivers/staging/slicoss/oasisdbgdownload.h b/drivers/staging/slicoss/oasisdbgdownload.h +new file mode 100644 +index 0000000..cae5d55 +--- /dev/null ++++ b/drivers/staging/slicoss/oasisdbgdownload.h +@@ -0,0 +1,6850 @@ ++#define OASIS_UCODE_VERS_STRING "$Revision: 1.2 $" ++#define OASIS_UCODE_VERS_DATE "$Date: 2006/03/27 15:11:22 $" ++#define OASIS_UCODE_HOSTIF_ID 3 ++ ++static LONG ONumSections = 0x2; ++static ULONG OSectionSize[] = ++{ ++ 0x00004000, 0x00010000, ++}; ++ ++static ULONG OSectionStart[] = ++{ ++ 0x00000000, 0x00008000, ++}; ++ ++static u8 OasisUCode[2][65536] = ++{ ++ { ++ 0x15, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x21, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x98, 0xb0, 0x01, 0x00, 0x04, 0x80, 0xa2, 0x40, 0xfd, 0x7f, 0x00, 0x00, ++ 0x09, 0x00, 0xa2, 0x49, 0xdd, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x80, 0xb2, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xd1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x80, 0xb2, 0x01, 0x00, 0x09, 0x00, 0xa2, 0x40, ++ 0x75, 0x7d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x0b, 0x00, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x8f, 0x98, 0x18, 0x31, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x98, 0x80, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x41, 0x98, ++ 0x80, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x98, 0x80, 0xe4, 0x01, 0x00, 0x0e, 0x00, 0x40, 0x98, ++ 0x80, 0x94, 0x00, 0x00, 0x11, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x19, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x19, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x0e, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x1f, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1f, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x12, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x01, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x25, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x25, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x14, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xdd, 0x81, 0x01, 0x00, 0x12, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x33, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2a, 0x00, 0x14, 0xbc, ++ 0x80, 0x32, 0x00, 0x00, 0xfe, 0x00, 0x13, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x54, 0x95, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0xff, 0xff, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xfd, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xb3, 0x01, 0x00, ++ 0x33, 0x00, 0x18, 0xee, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x89, 0xb0, 0x01, 0x00, 0x32, 0x00, 0xa2, 0x41, 0x89, 0x50, 0x00, 0x00, ++ 0x99, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x30, 0x94, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x20, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xe0, 0xb3, 0x01, 0x00, 0x39, 0x00, 0x98, 0xee, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x80, 0xb0, 0x01, 0x00, ++ 0x3b, 0x00, 0x80, 0xf3, 0xde, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0xfd, 0x93, 0x01, 0x00, 0x3e, 0x00, 0x83, 0xf3, 0x80, 0x32, 0x00, 0x00, ++ 0xf0, 0x00, 0x00, 0xf3, 0x80, 0x88, 0x01, 0x00, 0x01, 0x80, 0x00, 0x40, ++ 0x2e, 0xdd, 0x01, 0x00, 0x00, 0x94, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x43, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0x24, 0xb1, 0x01, 0x00, 0x7c, 0x00, 0x18, 0xee, 0x80, 0x32, 0x00, 0x00, ++ 0x45, 0x00, 0x95, 0xe8, 0x80, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0xe8, ++ 0x80, 0x88, 0x01, 0x00, 0x7c, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0xec, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xd6, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xd6, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0xf8, 0xee, 0x8b, 0x01, 0x00, ++ 0x08, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0xff, 0x00, 0x00, 0xf0, ++ 0x80, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x81, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd6, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0xf8, ++ 0x80, 0x88, 0x01, 0x00, 0x3c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xf0, 0xd6, 0x8d, 0x01, 0x00, 0xff, 0xff, 0x00, 0xf0, ++ 0xf0, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0x81, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x81, 0x94, 0x01, 0x00, 0x3c, 0x01, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xd6, 0xb1, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xf8, 0x80, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x81, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x81, 0x94, 0x01, 0x00, ++ 0x3c, 0x02, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xd6, 0xb1, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0xd6, 0xb1, 0x01, 0x00, 0x1e, 0x00, 0x00, 0xf0, ++ 0x82, 0xf4, 0x01, 0x00, 0xff, 0x3f, 0x00, 0xf8, 0x80, 0xd8, 0x01, 0x00, ++ 0x64, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x81, 0xd0, 0x01, 0x00, 0xff, 0xff, 0x00, 0x40, 0x80, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xd8, 0xb1, 0x01, 0x00, 0x68, 0x00, 0x22, 0xfa, 0x80, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x81, 0xe0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x40, ++ 0x80, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xde, 0xb1, 0x01, 0x00, ++ 0x00, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0xfa, ++ 0x80, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x81, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd6, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0xfa, 0x80, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf6, 0x81, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xd6, 0xb1, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xfb, 0xd6, 0xe5, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x18, 0x00, 0x00, 0xfb, 0xd6, 0xe5, 0x01, 0x00, ++ 0x48, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0xfa, ++ 0xd6, 0xe5, 0x01, 0x00, 0x50, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xfb, 0xd6, 0xe5, 0x01, 0x00, 0x03, 0x00, 0x00, 0xfb, ++ 0x7a, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0xb1, 0x01, 0x00, ++ 0x7c, 0x00, 0x00, 0x4c, 0xdd, 0x91, 0x00, 0x00, 0x7c, 0x00, 0x95, 0xe8, ++ 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xe9, 0xfa, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd1, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0x42, ++ 0x80, 0x88, 0x01, 0x00, 0x34, 0x00, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0x7c, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x85, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x02, 0x80, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x81, 0xb0, 0x01, 0x00, 0x8e, 0x00, 0x09, 0xf9, 0x81, 0x32, 0x00, 0x00, ++ 0x8c, 0x00, 0x08, 0xf9, 0x81, 0x32, 0x00, 0x00, 0x98, 0x00, 0x1f, 0xfd, ++ 0xf9, 0x33, 0x00, 0x00, 0x8b, 0x00, 0x9e, 0xfd, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, ++ 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x19, 0xb1, 0x01, 0x00, 0x93, 0x00, 0x0a, 0xf9, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x40, 0xfb, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0xfd, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x07, 0x80, 0xf9, 0xf3, 0x8f, 0x01, 0x00, ++ 0x00, 0x07, 0x42, 0xf9, 0xf3, 0x8f, 0x01, 0x00, 0x97, 0x00, 0xa2, 0xff, ++ 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0xff, 0xfb, 0xef, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfc, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x94, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xbb, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x46, 0xfd, 0x7f, 0x01, 0x00, ++ 0x00, 0x94, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xce, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x44, 0xfd, 0x7f, 0x01, 0x00, ++ 0x00, 0x94, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x9a, 0x13, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x02, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x03, 0x01, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x9a, 0x13, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x02, 0x29, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x67, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xfd, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0xfd, 0x83, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0x40, 0x25, 0x99, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x44, 0x80, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0xfd, 0x93, 0x01, 0x00, 0xe2, 0x00, 0x00, 0x40, ++ 0x83, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x45, 0x80, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x46, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x40, 0x2b, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x46, 0x88, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x94, 0x8c, 0xb0, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x46, 0x80, 0x88, 0x01, 0x00, 0xa5, 0xa5, 0xa2, 0x40, ++ 0x80, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0xf0, 0x01, 0x00, ++ 0xc9, 0x00, 0x82, 0x41, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xfd, 0x83, 0x01, 0x00, ++ 0xd4, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x44, ++ 0x80, 0xb2, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x08, 0x83, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x45, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x44, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0x30, 0x00, 0x08, 0x83, 0x98, 0x01, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x2b, 0x99, 0x01, 0x00, 0xdb, 0x00, 0x00, 0x40, ++ 0x89, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x46, 0x80, 0xb2, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x94, 0x80, 0x88, 0x01, 0x00, 0xa5, 0xa5, 0xa2, 0x40, ++ 0x80, 0x4e, 0x01, 0x00, 0x00, 0x00, 0x80, 0x43, 0x89, 0xb0, 0x01, 0x00, ++ 0x03, 0x84, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, 0xde, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x88, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0x96, ++ 0x80, 0xb2, 0x00, 0x00, 0xdf, 0x00, 0xa2, 0x41, 0x8d, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x40, ++ 0x25, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xe0, 0x01, 0x00, ++ 0xdd, 0x00, 0x00, 0x44, 0x82, 0x14, 0x01, 0x00, 0x00, 0x00, 0x90, 0x94, ++ 0x8a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x45, 0x88, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x89, 0xd0, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x44, 0x2b, 0x41, 0x01, 0x00, ++ 0xec, 0x00, 0x08, 0x41, 0x80, 0x32, 0x00, 0x00, 0xed, 0x00, 0x00, 0x94, ++ 0x24, 0xb1, 0x00, 0x00, 0x10, 0x00, 0x00, 0x94, 0x24, 0xf5, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x94, 0xf0, 0xb1, 0x01, 0x00, 0xf2, 0x00, 0xa0, 0x44, ++ 0x89, 0x50, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x44, 0x2b, 0x41, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x94, 0xf0, 0xb1, 0x01, 0x00, 0xef, 0x00, 0x20, 0x44, ++ 0x89, 0x50, 0x00, 0x00, 0x10, 0x00, 0x00, 0x45, 0x88, 0xf4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x42, ++ 0x89, 0xd0, 0x00, 0x00, 0xf7, 0x00, 0xa0, 0xfa, 0x8a, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc0, 0x01, 0x00, 0xf5, 0x00, 0xa3, 0x42, ++ 0x89, 0x50, 0x00, 0x00, 0xff, 0xff, 0x00, 0x45, 0x88, 0x88, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x45, 0x8a, 0xf4, 0x01, 0x00, 0xfc, 0x00, 0x90, 0x44, ++ 0x8a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc0, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x45, 0x8a, 0xa8, 0x01, 0x00, 0x00, 0x00, 0x80, 0x50, ++ 0x8b, 0xe0, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x40, 0x25, 0x99, 0x01, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x2b, 0x99, 0x01, 0x00, 0x00, 0x30, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x08, 0x83, 0x14, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x94, 0x2a, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0xf9, 0x9b, 0x01, 0x00, 0xdd, 0x00, 0x00, 0xfc, 0x19, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0x40, 0x94, 0x80, 0xb2, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x44, ++ 0x2b, 0x41, 0x01, 0x00, 0x00, 0x00, 0x41, 0x94, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xf9, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x2b, 0xc1, 0x01, 0x00, 0x04, 0x01, 0x9f, 0x94, 0x80, 0x32, 0x00, 0x00, ++ 0x02, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x10, 0x01, 0x00, 0x51, ++ 0x93, 0xb0, 0x00, 0x00, 0x10, 0x01, 0x00, 0x4d, 0x93, 0xb0, 0x00, 0x00, ++ 0x10, 0x01, 0x00, 0x49, 0x93, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x93, 0xb0, 0x01, 0x00, 0x10, 0x01, 0xa2, 0x41, 0x93, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x12, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x13, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x14, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x15, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x16, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x17, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x18, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x19, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x1b, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x1e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x70, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x71, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x72, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x73, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x74, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x75, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x76, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x77, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x78, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x79, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x7a, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7b, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x7d, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xa1, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x19, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x15, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x09, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x07, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x01, 0xb0, 0x01, 0x00, 0x3b, 0x01, 0x20, 0x48, 0xa1, 0x51, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x47, 0x01, 0x22, 0x4b, ++ 0x74, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x60, 0x00, 0x00, 0x4b, 0x60, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, ++ 0x7e, 0xb1, 0x01, 0x00, 0x48, 0x01, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x45, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x05, 0x00, 0x80, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x18, 0x00, 0x00, 0xaa, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x43, 0x97, 0xf0, 0x01, 0x00, 0x07, 0x00, 0x00, 0xaa, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, ++ 0xd8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x40, 0xbf, 0xb3, 0x00, 0x00, 0x5a, 0x01, 0x22, 0xcc, ++ 0x85, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, ++ 0xd0, 0x14, 0x00, 0x40, 0xa1, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe1, 0xb1, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, ++ 0x62, 0xdd, 0x01, 0x00, 0x63, 0x01, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xcc, 0x85, 0x93, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0xa4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbc, 0xb3, 0x01, 0x00, ++ 0x00, 0x14, 0x2f, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe7, ++ 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xa9, 0xb3, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xdd, 0x81, 0x88, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0x80, 0xf4, 0x01, 0x00, 0x73, 0x01, 0x00, 0x40, 0x80, 0xc8, 0x01, 0x00, ++ 0x86, 0x01, 0x00, 0xdd, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x10, 0xb1, 0x00, 0x00, 0x87, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x88, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x89, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x8b, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc4, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x82, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x83, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, 0xb8, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x28, 0x00, 0xd4, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, ++ 0xd5, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, 0xd6, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x28, 0x00, 0xd7, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, ++ 0x72, 0x01, 0x00, 0x41, 0x81, 0xc0, 0x28, 0x00, 0x55, 0x01, 0x51, 0x49, ++ 0xfd, 0x93, 0x28, 0x00, 0x55, 0x01, 0x52, 0x4a, 0xfd, 0x93, 0x2a, 0x00, ++ 0x55, 0x01, 0x55, 0x49, 0xfd, 0x83, 0x2a, 0x00, 0x55, 0x01, 0x56, 0x4a, ++ 0xfd, 0x83, 0x2a, 0x00, 0x50, 0x01, 0x91, 0x81, 0x80, 0x30, 0x2a, 0x00, ++ 0x55, 0x01, 0x45, 0x40, 0x81, 0xb2, 0x2a, 0x00, 0x50, 0x01, 0x91, 0x82, ++ 0x80, 0x30, 0x2a, 0x00, 0x55, 0x01, 0x46, 0x40, 0x81, 0xb2, 0x2a, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x89, 0xb0, 0x2b, 0x00, 0x00, 0x00, 0x2f, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x14, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0xb3, 0x01, 0x22, 0xde, 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0x92, 0x01, 0xa2, 0x44, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xd1, 0x01, 0x00, 0x9a, 0x01, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x96, 0x01, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x50, 0x01, 0x00, 0x41, ++ 0xbf, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xbf, 0xb3, 0x01, 0x00, ++ 0x50, 0x01, 0xa0, 0x0f, 0xbd, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x49, 0xc1, 0x01, 0x00, ++ 0xb5, 0x01, 0x00, 0x40, 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x42, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, 0x85, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xde, 0x19, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x42, 0xff, ++ 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x2f, 0xff, ++ 0xe1, 0xb1, 0x01, 0x00, 0x08, 0x14, 0x00, 0xa4, 0x80, 0xcc, 0x01, 0x00, ++ 0xaa, 0x01, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x85, 0xc0, 0x01, 0x00, 0xa8, 0x01, 0xa2, 0x4c, 0x81, 0x50, 0x00, 0x00, ++ 0xb4, 0x01, 0x22, 0xd2, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x01, 0x22, 0x41, ++ 0xa5, 0x6f, 0x00, 0x00, 0x50, 0x01, 0xa2, 0xe0, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xc1, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x89, 0x90, 0x01, 0x00, 0x00, 0x00, 0x40, 0x42, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x41, 0x43, 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x88, 0x94, 0x01, 0x00, 0x55, 0x01, 0x00, 0x44, 0xe0, 0xb1, 0x00, 0x00, ++ 0xb1, 0x01, 0x00, 0x48, 0x49, 0xc1, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x5b, ++ 0x89, 0x90, 0x00, 0x00, 0xa8, 0x9f, 0x00, 0xa0, 0x9e, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x14, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0x00, 0x00, 0x23, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0xbe, 0x01, 0x22, 0xde, 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0xb9, 0x01, 0xa2, 0x44, 0x81, 0x6c, 0x00, 0x00, 0x50, 0x01, 0x00, 0x43, ++ 0xbf, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x40, 0xf8, 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0xf0, ++ 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x55, 0x01, 0x00, 0x40, ++ 0xe1, 0xb1, 0x00, 0x00, 0xc6, 0x01, 0x00, 0x40, 0x91, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x91, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2e, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0xcb, 0x01, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, ++ 0xd1, 0x01, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, 0x53, 0x01, 0x00, 0xde, ++ 0xa1, 0xb3, 0x00, 0x00, 0xe3, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe5, 0x01, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, 0xeb, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x52, 0x01, 0x00, 0xdf, 0xe1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0xa1, 0xb1, 0x01, 0x00, 0x02, 0x00, 0x00, 0xd2, 0xa5, 0xe7, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xc1, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0xdb, 0x01, 0x22, 0x44, 0xc1, 0x53, 0x00, 0x00, ++ 0xda, 0x01, 0x84, 0x41, 0x81, 0x40, 0x00, 0x00, 0xde, 0x01, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x45, 0xb1, 0x01, 0x00, ++ 0xd5, 0x01, 0x00, 0x41, 0xa1, 0xc1, 0x00, 0x00, 0xda, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x55, 0x01, 0x00, 0xdd, 0xa1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, ++ 0xda, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x40, 0x00, 0x00, 0xd3, ++ 0xa7, 0xcb, 0x01, 0x00, 0xf8, 0x02, 0x00, 0xe0, 0xa5, 0xb3, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, 0x53, 0x01, 0x00, 0xde, ++ 0xa1, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xbf, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xde, 0x81, 0x90, 0x01, 0x00, 0x50, 0x01, 0xa2, 0xba, ++ 0x80, 0x04, 0x00, 0x00, 0x60, 0x00, 0x00, 0xde, 0x61, 0x99, 0x01, 0x00, ++ 0xe8, 0x01, 0xa8, 0xb1, 0x80, 0x30, 0x00, 0x00, 0x52, 0x01, 0x00, 0x40, ++ 0xe0, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xba, 0xb3, 0x01, 0x00, ++ 0x6b, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x60, 0x02, 0x00, 0x4d, ++ 0x83, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe1, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xe3, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xe5, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe9, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xeb, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf5, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf9, 0xb3, 0x01, 0x00, 0xf9, 0x01, 0x22, 0x40, ++ 0x8f, 0x6f, 0x00, 0x00, 0x78, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x60, 0x02, 0x00, 0xc7, 0x83, 0x30, 0x01, 0x00, 0x80, 0x02, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0x60, 0x02, 0x00, 0x42, 0x83, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe8, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe9, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xea, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xeb, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x85, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xec, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xed, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb2, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa9, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xac, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xb9, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xba, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xf0, 0xb1, 0x01, 0x00, ++ 0x0c, 0x02, 0xb8, 0x40, 0x81, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0x90, 0x01, 0x00, 0x0e, 0x02, 0xb9, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0x90, 0x01, 0x00, 0x10, 0x02, 0xba, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x81, 0x90, 0x01, 0x00, ++ 0x12, 0x02, 0xbb, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x81, 0x90, 0x01, 0x00, 0x14, 0x02, 0xbc, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x81, 0x90, 0x01, 0x00, 0x16, 0x02, 0xbd, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x81, 0x90, 0x01, 0x00, ++ 0x18, 0x02, 0xbe, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x81, 0x90, 0x01, 0x00, 0x1a, 0x02, 0xbf, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x81, 0x90, 0x01, 0x00, 0x1c, 0x02, 0xc8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x81, 0x90, 0x01, 0x00, ++ 0x1e, 0x02, 0xc9, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0x81, 0x90, 0x01, 0x00, 0x20, 0x02, 0xca, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x81, 0x90, 0x01, 0x00, 0x22, 0x02, 0xcb, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x81, 0x90, 0x01, 0x00, ++ 0x24, 0x02, 0xcc, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x81, 0x90, 0x01, 0x00, 0x26, 0x02, 0xcd, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4d, 0x81, 0x90, 0x01, 0x00, 0x28, 0x02, 0xce, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x81, 0x90, 0x01, 0x00, ++ 0x2a, 0x02, 0xcf, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x81, 0x90, 0x01, 0x00, 0x2c, 0x02, 0xf0, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x81, 0x90, 0x01, 0x00, 0x2e, 0x02, 0xf1, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x81, 0x90, 0x01, 0x00, ++ 0x30, 0x02, 0xf2, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x81, 0x90, 0x01, 0x00, 0x32, 0x02, 0xf3, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0x81, 0x90, 0x01, 0x00, 0x34, 0x02, 0xf4, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x81, 0x90, 0x01, 0x00, ++ 0x36, 0x02, 0xf5, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x81, 0x90, 0x01, 0x00, 0x38, 0x02, 0xf6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x56, 0x81, 0x90, 0x01, 0x00, 0x3a, 0x02, 0xf7, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x81, 0x90, 0x01, 0x00, ++ 0x3c, 0x02, 0xf8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x81, 0x90, 0x01, 0x00, 0x3e, 0x02, 0xf9, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x59, 0x81, 0x90, 0x01, 0x00, 0x40, 0x02, 0xfa, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0x90, 0x01, 0x00, ++ 0x42, 0x02, 0xfb, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, ++ 0x81, 0x90, 0x01, 0x00, 0x44, 0x02, 0xfc, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x81, 0x90, 0x01, 0x00, 0x46, 0x02, 0xfd, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x81, 0x90, 0x01, 0x00, ++ 0x48, 0x02, 0xfe, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x81, 0x90, 0x01, 0x00, 0x4a, 0x02, 0xff, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x81, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, ++ 0xd8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x14, 0x2e, 0x06, 0xa5, 0xb3, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0xd3, 0xa7, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf4, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xeb, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf1, 0xb1, 0x01, 0x00, ++ 0xdb, 0x01, 0x00, 0xc7, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x66, 0x02, 0x00, 0x48, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x51, 0x40, 0x1a, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x63, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x5f, 0x02, 0x49, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x52, 0x40, 0x1c, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x4e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x68, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x5f, 0x02, 0x4a, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, ++ 0x9e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd8, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa1, 0xd0, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, ++ 0xd2, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xd4, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xd6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, ++ 0xdc, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xde, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x88, 0xda, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, ++ 0x8e, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xe6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xac, 0xec, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x99, ++ 0xfa, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe0, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xe2, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xe4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe8, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xea, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xf4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xf6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xf8, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc7, ++ 0xa9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xb1, 0x01, 0x00, ++ 0x84, 0x02, 0x00, 0x40, 0x91, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0x88, 0x02, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, ++ 0x8d, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x98, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x98, 0x02, 0x00, 0x46, 0xa3, 0xb3, 0x00, 0x00, ++ 0x9b, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xa1, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8f, 0x02, 0x23, 0x50, 0xa5, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xa5, 0xb3, 0x01, 0x00, 0xe8, 0x02, 0x00, 0x42, ++ 0xa5, 0x63, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, 0xa1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x00, 0xb0, 0x01, 0x00, 0x97, 0x02, 0x22, 0x44, ++ 0xa5, 0x53, 0x00, 0x00, 0x94, 0x02, 0x00, 0x41, 0xa1, 0xc1, 0x00, 0x00, ++ 0x55, 0x01, 0x00, 0xdd, 0xa1, 0xb1, 0x00, 0x00, 0xe8, 0x02, 0x00, 0xde, ++ 0xa1, 0x33, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xbf, 0xb3, 0x01, 0x00, 0x50, 0x01, 0xa2, 0xd2, 0x77, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0x63, 0xb1, 0x01, 0x00, 0x9e, 0x02, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x54, ++ 0xa5, 0x33, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xd0, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xd2, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0xd4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xd6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0xb1, 0x01, 0x00, ++ 0xac, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x60, 0x02, 0x00, 0x46, ++ 0x83, 0x30, 0x01, 0x00, 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa0, 0x9e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe8, ++ 0x43, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x45, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xea, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xeb, ++ 0xa1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd0, 0x14, 0x2e, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0xa3, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc1, 0xb3, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0xbd, 0x02, 0x00, 0x40, ++ 0x10, 0xc9, 0x00, 0x00, 0xc3, 0x02, 0x00, 0x05, 0x81, 0xb0, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xcb, 0x02, 0x00, 0x05, ++ 0x81, 0xb0, 0x00, 0x00, 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd0, 0x02, 0x00, 0x44, 0xa5, 0xb3, 0x00, 0x00, 0xd2, 0x02, 0x00, 0x44, ++ 0xa5, 0xb3, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xa4, 0xe7, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe0, 0x81, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc1, ++ 0xf0, 0x89, 0x01, 0x00, 0xc8, 0x02, 0x22, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0xc4, 0x02, 0x00, 0x41, 0xc1, 0xc3, 0x00, 0x00, 0xda, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0xa4, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x91, 0xb1, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0xc9, 0xf0, 0x89, 0x01, 0x00, 0xc8, 0x02, 0x22, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x41, 0xc1, 0xc3, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0xde, 0x85, 0x89, 0x01, 0x00, 0xc8, 0x02, 0x00, 0xc2, ++ 0xe0, 0xb1, 0x00, 0x00, 0xff, 0xff, 0x00, 0xde, 0x95, 0x89, 0x01, 0x00, ++ 0xc8, 0x02, 0x00, 0xca, 0xe0, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xa7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd8, 0xa9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, 0xe2, 0x02, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcc, 0x85, 0x93, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xe7, 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, ++ 0xa9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, ++ 0xf1, 0xb1, 0x01, 0x00, 0xe1, 0x02, 0x00, 0xd4, 0xe1, 0xb1, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xcc, ++ 0x85, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xb0, 0x01, 0x00, ++ 0xfa, 0x02, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0xf9, 0x02, 0xa2, 0xf2, ++ 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcc, 0x85, 0x83, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb5, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x41, ++ 0x99, 0xb3, 0x01, 0x00, 0x0a, 0x03, 0x22, 0x44, 0x81, 0x6c, 0x00, 0x00, ++ 0x12, 0x03, 0x22, 0x48, 0x81, 0x6c, 0x00, 0x00, 0x0c, 0x03, 0x22, 0x4c, ++ 0x81, 0x6c, 0x00, 0x00, 0x16, 0x03, 0x22, 0x50, 0x81, 0x6c, 0x00, 0x00, ++ 0x17, 0x03, 0x22, 0x54, 0x81, 0x6c, 0x00, 0x00, 0x19, 0x03, 0x22, 0x58, ++ 0x81, 0x6c, 0x00, 0x00, 0x1e, 0x03, 0x22, 0x5c, 0x81, 0x6c, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, ++ 0x09, 0xb0, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0xca, 0x01, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xf3, 0x83, 0x01, 0x00, 0x10, 0x03, 0xa2, 0x42, 0x05, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x05, 0xb0, 0x01, 0x00, 0xdd, 0x9f, 0x22, 0xca, ++ 0x07, 0x14, 0x00, 0x00, 0xdd, 0x9f, 0x00, 0x45, 0xf3, 0x93, 0x00, 0x00, ++ 0xdd, 0x9f, 0x20, 0x43, 0x95, 0x6f, 0x00, 0x00, 0xdd, 0x9f, 0x80, 0xca, ++ 0x05, 0x30, 0x00, 0x00, 0xdd, 0x9f, 0x22, 0x01, 0x80, 0x30, 0x00, 0x00, ++ 0xdd, 0x9f, 0x00, 0xcb, 0xdb, 0x91, 0x00, 0x00, 0x57, 0x01, 0x00, 0xbc, ++ 0xab, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xb1, 0xb3, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, 0xff, 0x00, 0x00, 0xca, ++ 0x81, 0x88, 0x01, 0x00, 0xdd, 0x9f, 0xa2, 0x40, 0x74, 0x7d, 0x00, 0x00, ++ 0x60, 0x00, 0x20, 0x40, 0x60, 0x99, 0x01, 0x00, 0x1b, 0x03, 0xa8, 0xb1, ++ 0x82, 0x30, 0x00, 0x00, 0x1a, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xdd, 0x9f, 0x00, 0xca, 0x79, 0xb3, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xcb, 0x83, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x22, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x2d, 0x03, 0x91, 0x82, 0x82, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x8a, 0x80, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, ++ 0x80, 0xce, 0x01, 0x00, 0x2b, 0x03, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x2d, 0x03, 0x56, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0xb5, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xcd, 0x83, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x32, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x3d, 0x03, 0x91, 0x81, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, ++ 0x80, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0x3b, 0x03, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x3d, 0x03, 0x55, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x07, 0x90, 0x01, 0x00, 0xb5, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0xc4, 0x14, 0x2f, 0x40, 0x99, 0xb3, 0x01, 0x00, ++ 0x57, 0x01, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x30, 0x94, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x90, 0x00, 0xf8, ++ 0x80, 0x98, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf2, 0x88, 0xe4, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0x4d, 0x03, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x40, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0x50, 0x03, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x40, 0x00, 0x00, 0x40, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0x53, 0x03, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, 0x55, 0x03, 0x1f, 0x91, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x08, 0x80, 0x40, 0x20, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x48, 0x84, 0x84, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x8f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x62, 0xb1, 0x01, 0x00, ++ 0x5a, 0x03, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x08, 0x00, 0x47, ++ 0x8e, 0xc8, 0x01, 0x00, 0x58, 0x03, 0x00, 0x5c, 0x8f, 0x80, 0x00, 0x00, ++ 0xe0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x58, 0x15, 0x2d, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2d, 0xf0, 0x88, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x81, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x45, 0x82, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x8b, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x94, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x60, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8d, 0xc0, 0x01, 0x00, 0x74, 0x03, 0x22, 0x5f, 0x8d, 0x6c, 0x00, 0x00, ++ 0x65, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x63, 0x03, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x40, 0x85, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x43, 0x86, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0xa6, 0x41, 0x85, 0x50, 0x01, 0x00, 0x70, 0x03, 0x00, 0x41, ++ 0x83, 0xe0, 0x00, 0x00, 0x6e, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x85, 0xe0, 0x01, 0x00, 0xd0, 0x14, 0x2f, 0x46, ++ 0x84, 0x94, 0x01, 0x00, 0x20, 0x00, 0x00, 0x42, 0x60, 0x99, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x07, 0x00, 0x00, 0x45, 0x80, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x8b, 0xf0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x85, 0x03, 0xa0, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x83, 0x03, 0x00, 0x41, 0x82, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x8e, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0x00, 0x39, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x8b, 0x03, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x44, ++ 0x82, 0xf4, 0x01, 0x00, 0x1a, 0x15, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, ++ 0x70, 0x15, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x08, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x39, 0x00, 0x40, 0xe1, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x70, 0x15, 0x00, 0x43, 0x62, 0x99, 0x01, 0x00, ++ 0x95, 0x03, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x97, 0x03, 0x22, 0x5a, ++ 0x73, 0x7d, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x98, 0x03, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0x00, 0x08, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x90, 0x03, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x58, 0x15, 0x2d, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2d, 0xf0, 0x88, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8f, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, ++ 0x90, 0xb0, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x48, 0x90, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x93, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0x8a, 0xb0, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, 0xac, 0x03, 0x22, 0x40, ++ 0x82, 0x6c, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x58, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8d, 0xc0, 0x01, 0x00, 0xb5, 0x03, 0x22, 0x5f, 0x8d, 0x6c, 0x00, 0x00, ++ 0xa7, 0x03, 0xa2, 0x41, 0x93, 0x50, 0x00, 0x00, 0xa5, 0x03, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xff, 0x07, 0x00, 0x47, 0x84, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0xa6, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xed, 0x9f, 0x00, 0x47, ++ 0x80, 0x30, 0x01, 0x00, 0x00, 0x02, 0x00, 0x47, 0x8e, 0xc8, 0x01, 0x00, ++ 0xb0, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x50, 0xb3, 0x01, 0x00, 0xbb, 0x03, 0x20, 0x18, 0x89, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0xa6, 0x84, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, 0x55, 0x9b, 0x01, 0x00, ++ 0xbe, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0xa6, ++ 0x84, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x10, 0x00, 0x40, 0x55, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x50, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x4f, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x4e, 0xd3, 0x01, 0x00, 0x6e, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x82, 0x03, 0x00, 0x42, 0x80, 0x30, 0x01, 0x00, ++ 0xb0, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc7, 0x03, 0x22, 0xa7, ++ 0x8f, 0x6c, 0x00, 0x00, 0x5a, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc4, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xc8, 0x14, 0x2e, 0xbb, 0x85, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xee, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xa0, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xca, ++ 0xa7, 0x33, 0x01, 0x00, 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd6, 0x03, 0x22, 0x42, ++ 0x75, 0x6f, 0x00, 0x00, 0xd8, 0x03, 0x22, 0x41, 0x75, 0x6f, 0x00, 0x00, ++ 0xda, 0x03, 0x1e, 0xca, 0x81, 0x32, 0x00, 0x00, 0xdc, 0x03, 0x1f, 0xca, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xc9, 0xb1, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0x42, 0x75, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xcd, 0xb1, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0x41, 0x75, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xcf, 0xb1, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0x40, ++ 0x75, 0xb3, 0x00, 0x00, 0x00, 0x81, 0x00, 0xa6, 0xc6, 0xb1, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, ++ 0xc6, 0xb1, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0x40, 0x75, 0xb3, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x45, 0x01, 0x00, 0x4d, 0x93, 0x30, 0x01, 0x00, ++ 0x45, 0x01, 0x00, 0x4e, 0x93, 0x30, 0x01, 0x00, 0x45, 0x01, 0x00, 0x4c, ++ 0x93, 0x30, 0x01, 0x00, 0xec, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x54, 0x95, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0xca, 0xe5, 0xb1, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcc, 0x14, 0x2e, 0x40, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, ++ 0xa0, 0xb3, 0x01, 0x00, 0x15, 0x04, 0x00, 0x43, 0xb2, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0xda, 0x89, 0xb0, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x40, ++ 0x8b, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x89, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x89, 0xd0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x44, ++ 0x88, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x87, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xa5, 0xb3, 0x01, 0x00, 0x15, 0x04, 0x00, 0x43, ++ 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x87, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa5, 0xc3, 0x01, 0x00, 0x0b, 0x04, 0x22, 0x44, 0x89, 0x50, 0x00, 0x00, ++ 0x0b, 0x04, 0x22, 0x44, 0x8b, 0x50, 0x00, 0x00, 0xfa, 0x03, 0xa2, 0x50, ++ 0xa5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xa5, 0xe3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xa7, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xbb, ++ 0x85, 0x30, 0x01, 0x00, 0xcc, 0x14, 0x2e, 0xd2, 0x95, 0xc3, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xb0, 0x01, 0x00, ++ 0x08, 0x04, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x07, 0x04, 0xa2, 0xf2, ++ 0x80, 0x30, 0x00, 0x00, 0xfa, 0x03, 0x00, 0x40, 0xa5, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xa5, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xa7, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xbb, 0x85, 0x30, 0x01, 0x00, ++ 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x2b, 0xb1, 0x01, 0x00, ++ 0x00, 0x10, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0xdb, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xff, 0xff, 0x00, 0x94, 0xb4, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd9, ++ 0x2b, 0xb1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xdd, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x94, ++ 0xb4, 0xb3, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd9, 0x2b, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x27, 0xb1, 0x01, 0x00, 0x06, 0xc0, 0x00, 0x40, 0x2d, 0x99, 0x01, 0x00, ++ 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x02, 0xc4, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, ++ 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x05, 0x82, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, ++ 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2d, 0x04, 0x80, 0x94, ++ 0x80, 0x32, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x28, 0x04, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x40, ++ 0x2d, 0x99, 0x01, 0x00, 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x31, 0x04, 0x00, 0x12, ++ 0x10, 0xc9, 0x00, 0x00, 0x00, 0x48, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x49, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x4b, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x4d, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x4f, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x50, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x52, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x54, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x56, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x57, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x59, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x5b, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x5d, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x5e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x60, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x62, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x64, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x65, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x67, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x69, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x6b, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x6c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x6e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x70, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x72, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x73, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x75, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x77, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x79, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x7a, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x7c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x7e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x59, 0x04, 0x00, 0x12, 0x10, 0xc9, 0x00, 0x00, ++ 0x00, 0x80, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x82, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x84, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x86, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x88, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x8a, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x8c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x8e, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x90, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x92, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x94, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x96, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x98, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x9a, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x9c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x9e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa0, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa2, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xa4, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa6, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa8, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xaa, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xac, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xae, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xb0, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xb2, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xb4, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xb6, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xb8, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xba, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xbc, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xbe, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x80, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0xa6, 0x82, 0xb1, 0x01, 0x00, 0x82, 0x04, 0x85, 0x41, ++ 0x97, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x97, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x90, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, 0x92, 0xb1, 0x01, 0x00, ++ 0x87, 0x04, 0x85, 0x41, 0x97, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x90, 0x04, 0x60, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0xb1, 0x01, 0x00, ++ 0xff, 0xff, 0xf0, 0x4b, 0x82, 0x89, 0x01, 0x00, 0x93, 0x04, 0x60, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x80, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0xf0, 0xa6, 0x82, 0xb1, 0x01, 0x00, 0x96, 0x04, 0x60, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4b, 0x84, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0xf0, 0xc2, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x90, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x80, 0x4b, 0x92, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x80, 0xa6, ++ 0x92, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4b, 0x94, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0xca, 0x94, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x00, 0x00, 0x4e, 0x98, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x98, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x98, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x88, 0x94, 0x01, 0x00, 0xa6, 0x04, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xad, 0x04, 0x22, 0x20, 0x87, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xa6, 0x04, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x1f, 0x80, 0x86, 0xb3, 0x01, 0x00, 0xb0, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x62, 0xb1, 0x01, 0x00, 0xb1, 0x04, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xb8, 0x04, 0x22, 0x4b, 0x89, 0x7c, 0x00, 0x00, 0xb6, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x62, 0xb1, 0x01, 0x00, 0xb6, 0x04, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x87, 0xb3, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x99, 0xb0, 0x01, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xc1, 0x04, 0xa8, 0xb1, 0x52, 0x33, 0x00, 0x00, 0xc6, 0x04, 0x22, 0x4b, ++ 0x53, 0x7f, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xc4, 0x04, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0xc1, 0x04, 0xa2, 0x41, ++ 0x99, 0x50, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x4f, 0x77, 0xfd, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x00, 0x00, 0x4e, 0x98, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x98, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x98, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x99, 0xe0, 0x01, 0x00, 0xd6, 0x04, 0x00, 0x4c, ++ 0x88, 0x94, 0x00, 0x00, 0xd6, 0x04, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xdd, 0x04, 0x22, 0x20, 0x87, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xd6, 0x04, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x1f, 0x80, 0x86, 0xb3, 0x01, 0x00, 0xe0, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xf0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x62, 0xb1, 0x01, 0x00, 0xe1, 0x04, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xe8, 0x04, 0x22, 0x4a, 0x89, 0x7c, 0x00, 0x00, 0xe6, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xf0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x62, 0xb1, 0x01, 0x00, 0xe6, 0x04, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x87, 0xb3, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x99, 0xb0, 0x01, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xf1, 0x04, 0xa8, 0xb1, 0x52, 0x33, 0x00, 0x00, 0xf6, 0x04, 0x22, 0x4a, ++ 0x53, 0x7f, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xf4, 0x04, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0xf1, 0x04, 0xa2, 0x41, ++ 0x99, 0x50, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x4f, 0x77, 0xfd, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x00, 0x05, 0xa8, 0xb1, 0x80, 0x30, 0x00, 0x00, 0x12, 0x05, 0x1d, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x40, 0x18, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, 0x10, 0x05, 0xa2, 0x40, ++ 0x86, 0x04, 0x00, 0x00, 0xde, 0x9f, 0x9c, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x40, 0x88, 0x88, 0x01, 0x00, 0x30, 0x05, 0x00, 0x50, ++ 0x47, 0x31, 0x01, 0x00, 0x36, 0x00, 0x00, 0x44, 0x88, 0xcc, 0x01, 0x00, ++ 0x0c, 0x05, 0x52, 0x40, 0x81, 0x32, 0x00, 0x00, 0x30, 0x05, 0x00, 0x40, ++ 0x47, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x89, 0xb0, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x48, 0x47, 0x31, 0x01, 0x00, 0x30, 0x05, 0x00, 0x05, ++ 0x47, 0x31, 0x01, 0x00, 0xde, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x1b, 0x00, 0xde, 0x9f, 0x00, 0x41, ++ 0xe1, 0xc1, 0x1a, 0x00, 0x78, 0x18, 0x00, 0x40, 0x49, 0x99, 0x1b, 0x00, ++ 0x19, 0x05, 0x22, 0x54, 0x81, 0x7c, 0x1a, 0x00, 0x14, 0x05, 0x42, 0x40, ++ 0x81, 0x32, 0x1a, 0x00, 0x00, 0x82, 0x00, 0xb3, 0x67, 0xdf, 0x1b, 0x00, ++ 0x00, 0x00, 0x1a, 0x44, 0x93, 0x93, 0x1b, 0x00, 0x28, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x1b, 0x00, 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0x27, 0x05, 0x0f, 0x40, 0x80, 0x32, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x40, ++ 0x88, 0x88, 0x01, 0x00, 0x30, 0x05, 0x00, 0x50, 0x47, 0x31, 0x01, 0x00, ++ 0x36, 0x00, 0x00, 0x44, 0x88, 0xcc, 0x01, 0x00, 0x1f, 0x05, 0x99, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xd0, 0x01, 0x00, ++ 0x21, 0x05, 0x9b, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x89, 0xd0, 0x01, 0x00, 0x23, 0x05, 0x1f, 0x44, 0x80, 0x32, 0x00, 0x00, ++ 0x30, 0x05, 0x00, 0x40, 0x47, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x89, 0xb0, 0x01, 0x00, 0x30, 0x05, 0x00, 0x48, 0x47, 0x31, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x58, 0x47, 0x31, 0x01, 0x00, 0xde, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x00, 0x00, 0x40, 0x86, 0xf4, 0x01, 0x00, ++ 0x6f, 0x00, 0x00, 0x43, 0x86, 0x88, 0x01, 0x00, 0xde, 0x9f, 0x26, 0x05, ++ 0x47, 0x31, 0x00, 0x00, 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0xde, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x44, 0xf0, 0x41, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0xe1, 0xc1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x07, ++ 0x91, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x97, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x05, 0x91, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x4c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x44, 0x05, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0x45, 0x05, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xf5, 0xb1, 0x01, 0x00, 0x10, 0x04, 0x00, 0x42, ++ 0xb3, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf5, 0xb1, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xf5, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, ++ 0xf7, 0xf5, 0x01, 0x00, 0x50, 0x00, 0x00, 0x40, 0x91, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x8f, 0xb0, 0x01, 0x00, 0x10, 0x04, 0x00, 0x48, ++ 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf7, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x91, 0xc0, 0x01, 0x00, 0x50, 0x05, 0xa2, 0x41, 0x8f, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x45, 0xd1, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x38, 0x05, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x91, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x6e, 0xda, ++ 0x8f, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x7a, 0x05, 0x22, 0x45, 0xfd, 0x7f, 0x00, 0x00, 0x40, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xdb, 0x9f, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x15, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x78, 0x05, 0xa2, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0x7d, 0x05, 0x22, 0x20, 0xb5, 0x6f, 0x00, 0x00, 0x7a, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xda, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x1f, 0x00, ++ 0x7d, 0x05, 0x22, 0x40, 0x97, 0x6c, 0x1e, 0x00, 0x7a, 0x05, 0x42, 0x40, ++ 0x81, 0x32, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x67, 0x93, 0x1f, 0x00, ++ 0xdf, 0x9f, 0x00, 0x58, 0x67, 0x93, 0x1e, 0x00, 0x54, 0x16, 0x00, 0x40, ++ 0x47, 0x99, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x1f, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x46, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, ++ 0x48, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x97, 0xb0, 0x01, 0x00, 0x10, 0x04, 0x00, 0x4a, 0xb2, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xf7, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, ++ 0xf7, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x95, 0xc0, 0x01, 0x00, ++ 0x90, 0x05, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x40, ++ 0xa5, 0x9b, 0x01, 0x00, 0x40, 0x16, 0x00, 0x40, 0xa1, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xa7, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xbb, ++ 0x85, 0x30, 0x01, 0x00, 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb8, 0x05, 0x22, 0x45, 0xfd, 0x7f, 0x00, 0x00, 0xe0, 0x15, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x1a, 0x00, 0x00, 0xa2, 0x80, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0xf0, 0x15, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, ++ 0x62, 0xdd, 0x01, 0x00, 0xa7, 0x05, 0xa8, 0xbb, 0xe1, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x83, 0xb0, 0x01, 0x00, 0xaa, 0x05, 0xa2, 0x41, ++ 0x83, 0x50, 0x00, 0x00, 0xa9, 0x05, 0xa2, 0xf2, 0x82, 0x30, 0x00, 0x00, ++ 0x4c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb0, 0x05, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xb1, 0x05, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0xf0, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb8, 0x05, 0xa2, 0xfa, ++ 0xb4, 0x6f, 0x00, 0x00, 0x10, 0x04, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, ++ 0xb8, 0x05, 0xa2, 0xfa, 0xb4, 0x6f, 0x00, 0x00, 0x10, 0x04, 0x00, 0x42, ++ 0xb3, 0x43, 0x01, 0x00, 0xbb, 0x05, 0x22, 0xfa, 0xb4, 0x6f, 0x00, 0x00, ++ 0xb8, 0x05, 0x42, 0x40, 0x81, 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x67, 0x93, 0x21, 0x00, 0xdf, 0x9f, 0x00, 0x58, 0x67, 0x93, 0x20, 0x00, ++ 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x21, 0x00, 0xdb, 0x9f, 0x00, 0x40, ++ 0x49, 0x31, 0x21, 0x00, 0xf6, 0x15, 0x00, 0x40, 0x43, 0x99, 0x21, 0x00, ++ 0x5c, 0x16, 0x00, 0x40, 0x45, 0x99, 0x21, 0x00, 0x00, 0x00, 0x6e, 0xfa, ++ 0x8e, 0xb0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xb4, 0xb3, 0x01, 0x00, 0xc9, 0x05, 0xa2, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0xfc, 0x15, 0x20, 0x20, 0xe1, 0xb1, 0x01, 0x00, 0xce, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x24, 0x00, 0xda, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x25, 0x00, ++ 0xce, 0x05, 0x22, 0x40, 0x97, 0x6c, 0x24, 0x00, 0xcb, 0x05, 0x42, 0x40, ++ 0x81, 0x32, 0x24, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x67, 0x93, 0x25, 0x00, ++ 0xdf, 0x9f, 0x00, 0x58, 0x67, 0x93, 0x24, 0x00, 0x38, 0x05, 0x00, 0x40, ++ 0x81, 0x32, 0x25, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x25, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd3, 0x05, 0x22, 0x50, ++ 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x91, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xf6, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x20, 0x04, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xf8, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x20, 0x04, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfa, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x20, 0x04, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x94, 0xb0, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x4a, 0xb4, 0x8b, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x4a, 0xb4, 0xf7, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x38, 0x05, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe9, 0x05, 0x22, 0x50, 0xb5, 0x6f, 0x00, 0x00, ++ 0xea, 0x05, 0x00, 0x50, 0xb5, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xb5, 0xb3, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x16, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x30, 0x31, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x32, 0x33, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x34, 0x35, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x36, 0x37, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x38, 0x39, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x41, 0x42, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x43, 0x44, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x45, 0x46, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x47, 0x48, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x49, 0x4a, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf7, 0xb1, 0x01, 0x00, ++ 0xfc, 0x05, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x80, 0x16, 0x2e, 0x06, ++ 0x83, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0xff, 0x05, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x22, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf6, 0xb1, 0x01, 0x00, ++ 0x02, 0x06, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x62, 0x00, 0x00, 0x40, ++ 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x16, 0x2d, 0x06, 0x83, 0xb0, 0x01, 0x00, 0x80, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x5c, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0x08, 0x06, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xf9, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf9, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x70, 0x95, 0xb0, 0x01, 0x00, ++ 0x14, 0x06, 0x22, 0x70, 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x45, 0x67, 0x00, 0xa6, 0xe0, 0xb2, 0x01, 0x00, 0x01, 0x23, 0x00, 0x70, ++ 0xe1, 0x9a, 0x01, 0x00, 0xcd, 0xef, 0x00, 0xa6, 0xe2, 0xb2, 0x01, 0x00, ++ 0x89, 0xab, 0x00, 0x71, 0xe3, 0x9a, 0x01, 0x00, 0xba, 0x98, 0x00, 0xa6, ++ 0xe4, 0xb2, 0x01, 0x00, 0xfe, 0xdc, 0x00, 0x72, 0xe5, 0x9a, 0x01, 0x00, ++ 0x32, 0x10, 0x00, 0xa6, 0xe6, 0xb2, 0x01, 0x00, 0x76, 0x54, 0x00, 0x73, ++ 0xe7, 0x9a, 0x01, 0x00, 0xd2, 0xc3, 0x00, 0xa6, 0xe8, 0xb2, 0x01, 0x00, ++ 0xf0, 0xe1, 0x00, 0x74, 0xe9, 0x9a, 0x01, 0x00, 0x80, 0x16, 0x00, 0x4a, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf7, 0xb1, 0x01, 0x00, 0x25, 0x06, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x80, 0x16, 0x00, 0x4a, 0x44, 0xc9, 0x01, 0x00, 0xfc, 0x16, 0x2a, 0x47, ++ 0xe7, 0xb5, 0x01, 0x00, 0x03, 0x00, 0x00, 0x4a, 0xe8, 0xe5, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, ++ 0xa3, 0x99, 0x01, 0x00, 0x80, 0x16, 0x3d, 0x46, 0x8d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x40, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0x2e, 0x06, 0xa2, 0x41, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xeb, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xed, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xef, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf1, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf3, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x41, ++ 0x80, 0x88, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, 0xa2, 0xc9, 0x01, 0x00, ++ 0x4b, 0x06, 0xa0, 0x50, 0x83, 0x6c, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x40, ++ 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x99, 0x84, 0x01, 0x00, ++ 0x50, 0x03, 0x00, 0x4c, 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x86, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0x98, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x99, 0x84, 0x01, 0x00, 0x50, 0x03, 0x00, 0x4c, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x86, 0xa4, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x40, 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x99, 0x84, 0x01, 0x00, 0x50, 0x03, 0x00, 0x4c, 0xa2, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x86, 0xa4, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40, 0xa4, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x20, 0x88, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x41, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x94, 0x01, 0x00, ++ 0x05, 0x00, 0x00, 0x75, 0x89, 0xe4, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x75, ++ 0x85, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x84, 0x94, 0x01, 0x00, ++ 0x55, 0x06, 0xa3, 0x53, 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, 0x89, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x76, 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x8b, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x64, 0x06, 0x00, 0x45, 0x88, 0x94, 0x00, 0x00, 0x27, 0x00, 0x00, 0x41, ++ 0x80, 0xce, 0x01, 0x00, 0x5a, 0x06, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x76, 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x89, 0xa4, 0x01, 0x00, 0x64, 0x06, 0x00, 0x78, 0x89, 0xa4, 0x00, 0x00, ++ 0x3b, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, 0x57, 0x06, 0xaa, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x89, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x77, 0x89, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x76, ++ 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x88, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x64, 0x06, 0x00, 0x45, 0x88, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x84, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x84, 0xc0, 0x01, 0x00, 0x6b, 0x06, 0xa3, 0x53, ++ 0x83, 0x6c, 0x00, 0x00, 0x82, 0x5a, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, ++ 0x99, 0x79, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, 0x78, 0x06, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x27, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, ++ 0x70, 0x06, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, 0xd9, 0x6e, 0x00, 0xa6, ++ 0x84, 0xc0, 0x01, 0x00, 0xa1, 0xeb, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, ++ 0x78, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x41, ++ 0x80, 0xce, 0x01, 0x00, 0x75, 0x06, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x8f, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, 0xdc, 0xbc, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x78, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x62, 0xca, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, 0xd6, 0xc1, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x78, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x78, 0xf3, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0xf1, 0xb2, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x76, 0x89, 0xe4, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x76, 0xef, 0xf6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xee, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x75, 0xed, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xea, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x83, 0xc0, 0x01, 0x00, 0x4f, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, ++ 0x37, 0x06, 0x2a, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, ++ 0xe1, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x76, 0xe3, 0xc2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x77, 0xe5, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, ++ 0xe7, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0xe9, 0xc2, 0x01, 0x00, ++ 0x2b, 0x06, 0x81, 0x41, 0x8d, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xfd, 0x93, 0x01, 0x00, 0x40, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xdb, 0x9f, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x15, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb9, 0x06, 0x22, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0xda, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb9, 0x06, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x5e, 0x16, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x7c, 0x16, 0x20, 0xf6, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x31, 0xb3, 0x01, 0x00, 0x9d, 0x06, 0x22, 0x4f, 0x8f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x51, 0xfd, 0x93, 0x01, 0x00, 0x9f, 0x06, 0x22, 0x40, ++ 0x8f, 0x7c, 0x00, 0x00, 0xa3, 0x06, 0x00, 0x54, 0xfd, 0x93, 0x00, 0x00, ++ 0xa1, 0x06, 0x22, 0x42, 0x8f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0xfd, 0x93, 0x01, 0x00, 0xa3, 0x06, 0x22, 0x41, 0x8f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0xfd, 0x93, 0x01, 0x00, 0xb7, 0x06, 0x22, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0x38, 0x05, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb2, 0x06, 0xa2, 0x40, 0xb5, 0x6f, 0x00, 0x00, ++ 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x48, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0x97, 0xc0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x4b, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0xb5, 0xb3, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb6, 0x06, 0x22, 0x40, 0xb5, 0x6f, 0x00, 0x00, 0xba, 0x06, 0x00, 0x54, ++ 0xfd, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xfd, 0x83, 0x01, 0x00, ++ 0x1c, 0x00, 0x00, 0xfe, 0x7f, 0xd9, 0x01, 0x00, 0xba, 0x06, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xfd, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe7, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc4, 0x06, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xe9, 0x9f, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x3c, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x14, 0x02, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x34, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x32, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, 0x0a, 0xc8, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x0e, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, ++ 0x0c, 0xc8, 0x01, 0x00, 0xea, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x0a, 0x07, 0x22, 0x01, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0xa4, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0xd9, 0x06, 0xa3, 0x07, 0x02, 0x6c, 0x00, 0x00, ++ 0xda, 0x06, 0x68, 0x01, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x07, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x0a, 0xc0, 0x01, 0x00, 0xec, 0x06, 0x22, 0x40, ++ 0x03, 0x6c, 0x00, 0x00, 0xe6, 0x06, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x23, 0x07, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0xe3, 0x06, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0xe8, 0x06, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x23, 0x07, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0xee, 0x06, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x22, 0x00, 0x00, 0x19, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x0f, 0x00, 0x00, 0xf2, 0x3a, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x3b, 0xe0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x14, 0x02, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x01, 0x00, 0xfa, 0x06, 0x23, 0x1a, ++ 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0xc0, 0x01, 0x00, ++ 0x23, 0x07, 0x00, 0x01, 0x34, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x2d, 0x1d, ++ 0x48, 0xc1, 0x01, 0x00, 0xf0, 0x00, 0x00, 0xf2, 0x30, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x31, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x02, 0xc0, 0x01, 0x00, 0x02, 0x07, 0x22, 0x1a, ++ 0x02, 0x50, 0x00, 0x00, 0x23, 0x07, 0x00, 0x01, 0x34, 0xc0, 0x00, 0x00, ++ 0x22, 0x00, 0x00, 0x19, 0x48, 0xc9, 0x01, 0x00, 0x02, 0x00, 0x2d, 0x14, ++ 0x48, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x14, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x14, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x14, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x24, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x17, 0x10, 0xc8, 0x01, 0x00, 0x23, 0x07, 0x00, 0x1a, ++ 0x10, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x0f, 0x07, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, ++ 0x10, 0x07, 0x60, 0x07, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x12, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x0d, 0x16, 0x94, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x0b, 0x16, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, 0x17, 0x07, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x40, 0x07, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, ++ 0x40, 0x07, 0x22, 0x0d, 0x24, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x10, 0xc0, 0x01, 0x00, 0x1e, 0x07, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x23, 0x07, 0x00, 0x41, 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x1f, 0x07, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x3f, 0x07, 0xa2, 0x0d, 0x0e, 0x50, 0x00, 0x00, 0x2e, 0x07, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x2c, 0x07, 0x22, 0xf2, ++ 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x29, 0x07, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x04, 0xb0, 0x01, 0x00, 0x33, 0x07, 0x1f, 0xf0, 0x0e, 0x30, 0x00, 0x00, ++ 0xd3, 0x06, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x5f, ++ 0x0f, 0x80, 0x01, 0x00, 0xd3, 0x06, 0x23, 0x07, 0x14, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x3c, 0x07, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0xd3, 0x06, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, 0xd3, 0x06, 0x00, 0x0d, ++ 0x18, 0xc0, 0x00, 0x00, 0x5f, 0x07, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x19, 0x0a, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x0a, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x02, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0x0d, 0x00, 0x2d, 0x1d, 0x48, 0xc1, 0x01, 0x00, ++ 0x09, 0x00, 0x00, 0xf3, 0x38, 0x88, 0x01, 0x00, 0x0d, 0x00, 0x20, 0x50, ++ 0xe7, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x2d, 0x40, 0x3f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf4, 0x32, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, 0x02, 0x00, 0x00, 0x1d, ++ 0x94, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, 0xb0, 0x01, 0x00, ++ 0x52, 0x07, 0xa0, 0xfc, 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xc0, 0x01, 0x00, 0x50, 0x07, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x96, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x48, 0xc1, 0x01, 0x00, 0x02, 0x00, 0x00, 0x18, 0x94, 0xf4, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x18, 0x90, 0xb0, 0x01, 0x00, 0x5c, 0x07, 0xa0, 0xfc, ++ 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x91, 0xc0, 0x01, 0x00, ++ 0x5a, 0x07, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xe0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x80, 0xb0, 0x2d, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x16, 0xb0, 0x2d, 0x00, ++ 0x22, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x48, 0xc1, 0x2d, 0x00, 0x64, 0x07, 0x43, 0x30, 0x3d, 0x07, 0x2c, 0x00, ++ 0x00, 0x00, 0x00, 0x9e, 0x85, 0xb0, 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x41, ++ 0x3d, 0xc3, 0x2d, 0x00, 0x04, 0x00, 0x20, 0x42, 0xec, 0xb1, 0x2d, 0x00, ++ 0x00, 0x00, 0x00, 0x1e, 0x82, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x2e, 0x1d, ++ 0x82, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x18, 0x82, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x80, 0xc0, 0x01, 0x00, 0x6e, 0x07, 0xa0, 0x41, ++ 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x92, 0xf4, 0x01, 0x00, 0x0a, 0x00, 0x2e, 0x30, ++ 0x81, 0x84, 0x01, 0x00, 0x72, 0x07, 0x90, 0x40, 0x92, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x93, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x48, 0xc1, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x19, 0xe8, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, ++ 0x16, 0xc0, 0x01, 0x00, 0x78, 0x07, 0xa0, 0x19, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x0d, 0x00, 0x2f, 0x1e, ++ 0x32, 0xc0, 0x01, 0x00, 0x7d, 0x07, 0xa2, 0x40, 0x15, 0x6c, 0x00, 0x00, ++ 0x7c, 0x07, 0xa0, 0x1c, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x63, 0xf3, 0x38, 0x94, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x1e, ++ 0x98, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0x1a, 0x98, 0xc0, 0x01, 0x00, ++ 0x0c, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x8b, 0x07, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x89, 0x07, 0x22, 0xf2, ++ 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x86, 0x07, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x1a, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, ++ 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, ++ 0x91, 0x07, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x9b, 0x07, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x10, 0x48, 0xc1, 0x01, 0x00, 0x9b, 0x07, 0x22, 0xf2, ++ 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x98, 0x07, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xeb, 0x9f, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x20, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, 0xa1, 0x07, 0x90, 0xf2, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x10, 0x00, 0x00, 0x14, ++ 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x2a, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x2b, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x2a, 0x94, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xac, 0x07, 0x22, 0xf2, 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xa9, 0x07, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x17, 0x10, 0xdc, 0x01, 0x00, ++ 0xc9, 0x07, 0x22, 0x40, 0x15, 0x6c, 0x00, 0x00, 0xb4, 0x07, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x1f, 0x90, 0x01, 0x00, ++ 0xb3, 0x07, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x88, ++ 0x1c, 0xcc, 0x01, 0x00, 0xe4, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x3f, 0xc3, 0x01, 0x00, 0xe6, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb7, 0x07, 0xa2, 0x41, 0x87, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x1e, 0x3e, 0xc0, 0x01, 0x00, 0xc9, 0x07, 0x22, 0x40, ++ 0x15, 0x6c, 0x00, 0x00, 0xba, 0x07, 0x20, 0x1e, 0x14, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x3c, 0xb0, 0x01, 0x00, 0xe5, 0x9f, 0x00, 0x1e, ++ 0x24, 0x30, 0x01, 0x00, 0xbf, 0x07, 0x22, 0x08, 0x2e, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x11, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1a, ++ 0x10, 0xc0, 0x01, 0x00, 0x23, 0x07, 0x00, 0x40, 0x17, 0xb0, 0x00, 0x00, ++ 0xe4, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xe5, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xbc, 0x07, 0xa2, 0x08, 0x2e, 0x30, 0x00, 0x00, ++ 0x80, 0x80, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x04, 0xe0, 0x31, 0x00, 0x00, 0xe8, 0x9f, 0x00, 0x1f, ++ 0x8c, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0xe2, 0x9f, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0x99, 0x01, 0x00, 0x04, 0x00, 0x22, 0x04, 0xe0, 0x31, 0x00, 0x00, ++ 0xe6, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xce, 0x07, 0xa2, 0x41, ++ 0x87, 0x7c, 0x00, 0x00, 0xcf, 0x07, 0x00, 0x1e, 0x3e, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x1f, 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0xe8, 0x9f, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, ++ 0xe2, 0x9f, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xf7, 0x07, 0x00, 0xbc, 0x80, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, ++ }, ++ { ++ 0x31, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x34, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x35, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0x80, 0x81, 0x80, ++ 0x80, 0x32, 0x00, 0x00, 0xe4, 0x87, 0xa2, 0x40, 0x91, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x90, 0xb3, 0x01, 0x00, 0x5c, 0x95, 0x2e, 0xa2, ++ 0x80, 0xb0, 0x01, 0x00, 0xff, 0x00, 0x00, 0x80, 0xf4, 0x89, 0x01, 0x00, ++ 0x90, 0x95, 0x2a, 0xc8, 0xe5, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd3, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x44, 0xb1, 0x01, 0x00, 0x18, 0x80, 0x11, 0x81, ++ 0x98, 0x30, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x1a, 0x80, 0x11, 0x82, 0x98, 0x30, 0x00, 0x00, 0x00, 0x00, 0x52, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xe4, 0x87, 0x00, 0x48, 0xfd, 0x93, 0x00, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x23, 0x80, 0xa2, 0x42, ++ 0xfd, 0x7f, 0x00, 0x00, 0x20, 0x80, 0x00, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x22, 0x80, 0x11, 0x81, 0x82, 0x30, 0x00, 0x00, 0x22, 0x80, 0x51, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x22, 0x80, 0x11, 0x82, 0x82, 0x30, 0x00, 0x00, ++ 0x22, 0x80, 0x52, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2c, 0x80, 0x00, 0x48, ++ 0xfd, 0x93, 0x00, 0x00, 0x27, 0x80, 0x00, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x26, 0x80, 0xa2, 0x53, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x51, 0x53, ++ 0x07, 0x90, 0x01, 0x00, 0x2a, 0x80, 0x00, 0x52, 0x07, 0x90, 0x00, 0x00, ++ 0x29, 0x80, 0xa2, 0x52, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x52, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0xf3, 0x93, 0x01, 0x00, 0x5c, 0x95, 0x2e, 0xa2, 0x52, 0xb3, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0x80, 0xf4, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x45, 0xb1, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x4c, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x55, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xc6, 0x82, 0x05, 0x40, 0x49, 0xb1, 0x00, 0x00, 0xc6, 0x82, 0x05, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x4c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0xde, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xfd, 0x83, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0x9b, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x9c, 0xb3, 0x01, 0x00, ++ 0x48, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x58, 0x95, 0x20, 0x44, ++ 0xe0, 0xb1, 0x01, 0x00, 0x04, 0x94, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x24, 0xb1, 0x01, 0x00, 0x00, 0x0c, 0x00, 0xee, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x97, 0xf0, 0x01, 0x00, ++ 0x44, 0x80, 0xa2, 0x43, 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0xc0, 0x00, 0xa6, 0x36, 0xb1, 0x01, 0x00, ++ 0xd0, 0x14, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x38, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x06, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x05, 0x10, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x02, 0x09, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x60, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x88, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xa0, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb9, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb1, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x60, 0x95, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x70, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0xdd, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x91, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7b, 0xb3, 0x01, 0x00, ++ 0x99, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb3, 0x01, 0x00, 0x5c, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x3c, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x90, 0x06, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x2f, 0x81, 0x01, 0x00, ++ 0xa2, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x9e, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x55, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x01, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xc6, 0x82, 0x00, 0x41, 0xe1, 0xc1, 0x00, 0x00, 0x78, 0x18, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0x19, 0x05, 0x22, 0x54, 0x81, 0x7c, 0x00, 0x00, ++ 0x6c, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0xb4, ++ 0x69, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x18, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x55, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x7d, 0x80, 0x22, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x7a, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x69, 0x93, 0x01, 0x00, 0x43, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x54, 0x16, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x80, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x80, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0x69, 0x93, 0x01, 0x00, 0x43, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x40, 0x05, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0xf6, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x5c, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x6e, 0xfa, 0x8e, 0xb0, 0x01, 0x00, 0xc1, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x96, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x55, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x96, 0x80, 0x22, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0x93, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x69, 0x93, 0x01, 0x00, 0x43, 0x81, 0x00, 0x58, 0x69, 0x93, 0x00, 0x00, ++ 0x38, 0x05, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xd0, 0x05, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x83, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb8, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd4, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd5, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xd6, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd7, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x72, 0x01, 0x00, 0x41, ++ 0x81, 0xc0, 0x00, 0x00, 0x55, 0x01, 0x51, 0x49, 0xfd, 0x93, 0x00, 0x00, ++ 0x55, 0x01, 0x52, 0x4a, 0xfd, 0x93, 0x00, 0x00, 0x55, 0x01, 0x55, 0x49, ++ 0xfd, 0x83, 0x00, 0x00, 0x55, 0x01, 0x56, 0x4a, 0xfd, 0x83, 0x00, 0x00, ++ 0x50, 0x01, 0x91, 0x81, 0x80, 0x30, 0x00, 0x00, 0x55, 0x01, 0x45, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x50, 0x01, 0x91, 0x82, 0x80, 0x30, 0x00, 0x00, ++ 0x55, 0x01, 0x46, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0xb4, 0x80, 0x43, 0x30, 0x3d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x41, 0x3d, 0xc3, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x42, 0xec, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x40, ++ 0x91, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x46, 0xb1, 0x01, 0x00, 0xc4, 0x80, 0xa2, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0xd0, 0xe1, 0xb1, 0x00, 0x00, ++ 0xc1, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x98, 0xb0, 0x01, 0x00, 0x04, 0x80, 0x00, 0x40, 0x8b, 0xb3, 0x00, 0x00, ++ 0xb1, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0xc9, 0x80, 0xa2, 0x42, ++ 0x97, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa1, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x04, ++ 0x80, 0x94, 0x00, 0x00, 0x80, 0x15, 0x3f, 0x42, 0x97, 0xe3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x03, ++ 0x02, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x07, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xcb, 0x99, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcc, ++ 0xf3, 0x83, 0x01, 0x00, 0xd3, 0x80, 0xa2, 0x42, 0x97, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xcb, 0xf3, 0x93, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, ++ 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x44, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa1, 0xe0, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, ++ 0xda, 0x80, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xf9, 0x02, 0x00, 0x20, ++ 0x42, 0x31, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, 0x05, 0x6c, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0xcb, 0xdb, 0x91, 0x01, 0x00, 0x00, 0x00, 0x19, 0x41, ++ 0x8b, 0xb3, 0x01, 0x00, 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xe0, 0x80, 0xa8, 0xb1, 0x8c, 0x33, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xe2, 0x80, 0xa8, 0xb1, 0x94, 0x33, 0x00, 0x00, ++ 0xe8, 0x80, 0x14, 0xc6, 0x81, 0x32, 0x00, 0x00, 0x18, 0x00, 0x00, 0xc6, ++ 0x83, 0xf4, 0x01, 0x00, 0x22, 0x83, 0x22, 0x4f, 0x83, 0x04, 0x00, 0x00, ++ 0xc4, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc6, ++ 0x81, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x97, 0xa3, 0x01, 0x00, ++ 0xc4, 0x80, 0x1f, 0x5c, 0x97, 0x53, 0x00, 0x00, 0x6d, 0x82, 0x1e, 0xc6, ++ 0x81, 0x32, 0x00, 0x00, 0xf2, 0x80, 0x22, 0x48, 0xfd, 0x7f, 0x00, 0x00, ++ 0xf2, 0x80, 0x22, 0x58, 0x81, 0x6c, 0x00, 0x00, 0xf2, 0x80, 0x22, 0x48, ++ 0x81, 0x6c, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x84, 0xcc, 0x01, 0x00, ++ 0xf2, 0x80, 0x9f, 0x42, 0x80, 0x32, 0x00, 0x00, 0x22, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc4, 0x80, 0xa2, 0xc6, 0x8f, 0x06, 0x00, 0x00, ++ 0xc4, 0x80, 0x1e, 0xc6, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x43, ++ 0x81, 0xf0, 0x01, 0x00, 0xf6, 0x80, 0x00, 0x40, 0x10, 0xc9, 0x00, 0x00, ++ 0x44, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x7e, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x39, 0x82, 0x00, 0xca, 0x63, 0xb3, 0x00, 0x00, ++ 0x75, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x55, 0x81, 0x00, 0x4d, ++ 0x83, 0xb0, 0x00, 0x00, 0x60, 0x81, 0x00, 0x4e, 0x61, 0xb1, 0x00, 0x00, ++ 0x4c, 0x81, 0x00, 0x40, 0x85, 0xb0, 0x00, 0x00, 0x55, 0x81, 0x00, 0x4c, ++ 0x83, 0xb0, 0x00, 0x00, 0x2e, 0x81, 0x00, 0x40, 0x85, 0xb0, 0x00, 0x00, ++ 0xf8, 0x81, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0x86, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0xf4, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x4c, 0x81, 0x00, 0x40, 0x85, 0xb0, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x22, 0x83, 0x00, 0xca, 0x9b, 0xb3, 0x00, 0x00, ++ 0x90, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0x94, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0x9b, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x9c, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0x9d, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0x9e, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x9f, 0x81, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, 0x9f, 0x81, 0x00, 0x41, ++ 0x81, 0xb0, 0x00, 0x00, 0x2d, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xae, 0x82, 0x00, 0xbb, 0xab, 0xb3, 0x00, 0x00, 0x3a, 0x82, 0x00, 0xca, ++ 0xcf, 0xb3, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, ++ 0xe8, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc4, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x22, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe0, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x22, 0x83, 0x00, 0xca, ++ 0x77, 0xb3, 0x00, 0x00, 0x56, 0x81, 0x00, 0x4d, 0x83, 0xb0, 0x00, 0x00, ++ 0x5e, 0x81, 0x00, 0x4e, 0x61, 0xb1, 0x00, 0x00, 0x4c, 0x81, 0x00, 0xbb, ++ 0x85, 0xb0, 0x00, 0x00, 0x56, 0x81, 0x00, 0x4c, 0x83, 0xb0, 0x00, 0x00, ++ 0x4c, 0x81, 0x00, 0xbb, 0x85, 0xb0, 0x00, 0x00, 0x2e, 0x81, 0x00, 0xbb, ++ 0x85, 0xb0, 0x00, 0x00, 0x20, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0xca, 0x4d, 0xb3, 0x00, 0x00, 0x70, 0x05, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, ++ 0x26, 0x81, 0x22, 0x42, 0x8f, 0x6f, 0x00, 0x00, 0x28, 0x81, 0x22, 0x41, ++ 0x8f, 0x6f, 0x00, 0x00, 0x2a, 0x81, 0x1e, 0xca, 0x81, 0x32, 0x00, 0x00, ++ 0x2c, 0x81, 0x1f, 0xca, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xc9, 0xb1, 0x01, 0x00, 0x22, 0x83, 0x00, 0x42, 0x8f, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xcd, 0xb1, 0x01, 0x00, 0x22, 0x83, 0x00, 0x41, ++ 0x8f, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xcf, 0xb1, 0x01, 0x00, ++ 0x22, 0x83, 0x00, 0x40, 0x8f, 0xb3, 0x00, 0x00, 0x00, 0x81, 0x00, 0xa6, ++ 0xc6, 0xb1, 0x01, 0x00, 0x22, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0xa6, 0xc6, 0xb1, 0x01, 0x00, 0x22, 0x83, 0x00, 0x40, ++ 0x8f, 0xb3, 0x00, 0x00, 0x78, 0x18, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0x10, 0x00, 0x2f, 0x9c, 0x89, 0xb0, 0x01, 0x00, 0x46, 0x81, 0x00, 0x40, ++ 0x39, 0x33, 0x01, 0x00, 0x18, 0x00, 0x2f, 0x9b, 0x89, 0xb0, 0x01, 0x00, ++ 0x46, 0x81, 0x00, 0x40, 0x37, 0x33, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x9a, ++ 0x89, 0xb0, 0x01, 0x00, 0x46, 0x81, 0x00, 0x40, 0x35, 0x33, 0x01, 0x00, ++ 0x08, 0x00, 0x2f, 0x99, 0x89, 0xb0, 0x01, 0x00, 0x46, 0x81, 0x00, 0x40, ++ 0x33, 0x33, 0x01, 0x00, 0x00, 0x80, 0x00, 0xae, 0x47, 0xc9, 0x01, 0x00, ++ 0xc4, 0x80, 0xa2, 0x40, 0xe1, 0x6d, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x18, 0x00, 0x40, ++ 0xe1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0xae, 0x63, 0xdd, 0x01, 0x00, 0x41, 0x81, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x3e, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x41, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x69, 0x93, 0x01, 0x00, 0x22, 0x83, 0x1a, 0x44, 0x93, 0x93, 0x00, 0x00, ++ 0x44, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x43, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf0, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0xa4, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x4b, 0x81, 0xa2, 0x40, ++ 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0xe1, 0xd1, 0x01, 0x00, 0x4c, 0x81, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x62, 0xb1, 0x01, 0x00, 0x52, 0x81, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x4d, 0x81, 0x22, 0x5c, 0x77, 0x7d, 0x00, 0x00, ++ 0xc4, 0x80, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x4d, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, ++ 0x52, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x22, 0x83, 0x17, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x57, 0x81, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, ++ 0x57, 0x81, 0x00, 0xbb, 0x81, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x60, 0xb1, 0x01, 0x00, 0xc4, 0x80, 0xa2, 0x41, 0x76, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, 0x59, 0x81, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, ++ 0x22, 0x83, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x5b, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x50, 0x95, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x61, 0x81, 0x00, 0xbb, 0x87, 0xb0, 0x00, 0x00, 0x50, 0x95, 0x2f, 0x40, ++ 0x87, 0xb0, 0x01, 0x00, 0x65, 0x81, 0x22, 0x40, 0x95, 0x7f, 0x00, 0x00, ++ 0xc4, 0x80, 0xa2, 0x40, 0xe1, 0x6d, 0x00, 0x00, 0xc4, 0x80, 0x22, 0x40, ++ 0x95, 0x6f, 0x00, 0x00, 0x22, 0x83, 0x60, 0x40, 0x95, 0x83, 0x00, 0x00, ++ 0x02, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, 0xc4, 0x80, 0x22, 0x40, ++ 0x85, 0x6c, 0x00, 0x00, 0xc4, 0x80, 0xa2, 0x40, 0x85, 0x7c, 0x00, 0x00, ++ 0xc4, 0x80, 0xa2, 0x4e, 0x77, 0x7d, 0x00, 0x00, 0x69, 0x81, 0x36, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x62, 0xb1, 0x01, 0x00, ++ 0x6a, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x62, 0xb1, 0x01, 0x00, 0x6c, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, 0x6e, 0x81, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x16, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x74, 0x81, 0x22, 0x41, 0x43, 0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0xca, ++ 0x95, 0xcb, 0x01, 0x00, 0x68, 0x81, 0x00, 0x41, 0x85, 0xc0, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0x40, 0xe1, 0xb1, 0x00, 0x00, 0x77, 0x81, 0xa2, 0x42, ++ 0x67, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x67, 0xb3, 0x01, 0x00, ++ 0x77, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x65, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x93, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0xca, 0x69, 0x97, 0x01, 0x00, 0x22, 0x83, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x7c, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x22, 0x83, 0x1a, 0x44, 0x93, 0x93, 0x00, 0x00, 0xc4, 0x80, 0x20, 0x43, ++ 0x95, 0x6f, 0x00, 0x00, 0x22, 0x83, 0x80, 0xca, 0x67, 0x33, 0x00, 0x00, ++ 0x22, 0x83, 0x22, 0x40, 0x65, 0x6f, 0x00, 0x00, 0xc4, 0x80, 0xa2, 0x48, ++ 0xdb, 0x7d, 0x00, 0x00, 0x22, 0x83, 0x00, 0x6f, 0xdb, 0x91, 0x00, 0x00, ++ 0x85, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x35, 0x80, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x22, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x95, 0x93, 0x01, 0x00, 0x8c, 0x81, 0xa2, 0x44, 0x21, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x95, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, 0x95, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xc3, 0xb1, 0x01, 0x00, 0x8f, 0x81, 0x22, 0x5b, ++ 0x95, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xfd, 0x93, 0x01, 0x00, ++ 0x22, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0xfd, 0x00, 0xca, ++ 0x95, 0x9b, 0x01, 0x00, 0x0d, 0x01, 0x00, 0xca, 0xc5, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x95, 0x83, 0x01, 0x00, 0x22, 0x83, 0x00, 0xca, ++ 0xc5, 0xb1, 0x00, 0x00, 0xdf, 0x6f, 0x00, 0xca, 0x95, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xc7, 0xb1, 0x01, 0x00, 0x22, 0x83, 0x22, 0x5f, 0x95, 0x7f, 0x00, 0x00, ++ 0x0d, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x95, 0x83, 0x01, 0x00, 0x22, 0x83, 0x00, 0xca, 0xc7, 0xb1, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0xca, 0xc9, 0xb1, 0x00, 0x00, 0x22, 0x83, 0x00, 0xca, ++ 0xcb, 0xb1, 0x00, 0x00, 0x22, 0x83, 0x00, 0xca, 0xcd, 0xb1, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0xca, 0xcf, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x42, ++ 0x81, 0xe0, 0x01, 0x00, 0x98, 0x14, 0x00, 0x40, 0x48, 0xc9, 0x01, 0x00, ++ 0x22, 0x83, 0x00, 0xca, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x09, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0xa4, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0xa6, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0xa6, 0x08, 0xb1, 0x01, 0x00, 0xa8, 0x81, 0x9f, 0x85, ++ 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x83, 0x84, 0x01, 0x00, ++ 0xdd, 0x81, 0x22, 0x30, 0x83, 0x6c, 0x00, 0x00, 0xa7, 0x81, 0xa2, 0x4f, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x21, 0xb3, 0x01, 0x00, ++ 0x02, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x10, 0x00, 0x00, 0x41, 0x84, 0xe4, 0x01, 0x00, ++ 0x03, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x41, 0x86, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x84, 0x94, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x10, 0xc4, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, ++ 0xbd, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x21, 0xb3, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x1c, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0xba, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, ++ 0xcf, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x41, 0x01, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x50, 0x0c, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, ++ 0xc2, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x21, 0xb3, 0x01, 0x00, 0xcf, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x41, 0x01, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, 0x60, 0x0c, 0x00, 0x43, ++ 0x86, 0x98, 0x01, 0x00, 0xcf, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x21, 0xb3, 0x01, 0x00, 0x18, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x41, 0x82, 0x88, 0x01, 0x00, 0x00, 0x77, 0x00, 0x41, ++ 0x82, 0x8c, 0x01, 0x00, 0x01, 0x02, 0x00, 0x41, 0x82, 0x98, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x18, 0x00, 0x00, 0x41, ++ 0x82, 0xdc, 0x01, 0x00, 0xcd, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x08, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0xd0, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x40, 0x13, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, 0xd8, 0x81, 0x22, 0x43, ++ 0x21, 0x6f, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0xd5, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, ++ 0xf3, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x19, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0xda, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0xf3, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x21, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x83, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5e, 0x83, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, ++ 0x83, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xc2, 0xb1, 0x01, 0x00, ++ 0x0c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x83, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xc2, 0xb1, 0x01, 0x00, ++ 0x0c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x11, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0xec, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0xef, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x40, 0x13, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x41, 0x2e, 0x99, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0x81, 0x94, 0x01, 0x00, 0xf6, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x22, 0x83, 0x00, 0x40, 0x08, 0xb1, 0x00, 0x00, ++ 0xc8, 0x14, 0x2e, 0xbb, 0x85, 0xb0, 0x01, 0x00, 0xf9, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0xb0, 0x01, 0x00, ++ 0x08, 0x82, 0x22, 0x43, 0x21, 0x6f, 0x00, 0x00, 0x17, 0x82, 0x22, 0x44, ++ 0x21, 0x6f, 0x00, 0x00, 0x11, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x28, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x1f, 0x82, 0x22, 0x4a, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, ++ 0x03, 0x82, 0x22, 0x4d, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x87, 0x90, 0x01, 0x00, 0x05, 0x82, 0x22, 0x4f, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, 0x07, 0x82, 0x22, 0x4e, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x87, 0x90, 0x01, 0x00, ++ 0x1f, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x01, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x1f, 0x82, 0x22, 0x42, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, 0x1c, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x12, 0x82, 0x22, 0x45, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x87, 0x90, 0x01, 0x00, 0x14, 0x82, 0x22, 0x44, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, 0x16, 0x82, 0x22, 0x43, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x87, 0x90, 0x01, 0x00, ++ 0x1f, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x01, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x1f, 0x82, 0x22, 0x42, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x87, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x87, 0x90, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x28, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x23, 0x82, 0x22, 0x4b, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xe0, 0xb1, 0x01, 0x00, 0xff, 0x7f, 0x00, 0xa2, 0xa0, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, 0xb8, 0x80, 0x00, 0xca, ++ 0xa7, 0x33, 0x01, 0x00, 0x41, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x29, 0x82, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0xb1, 0x01, 0x00, ++ 0x2b, 0x82, 0x9f, 0x85, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x30, 0x82, 0x14, 0xf7, 0x81, 0x30, 0x00, 0x00, ++ 0x30, 0x82, 0xa2, 0x49, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xfd, 0x93, 0x01, 0x00, 0x33, 0x82, 0x15, 0xf8, 0x81, 0x14, 0x00, 0x00, ++ 0x33, 0x82, 0xa2, 0x4a, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xfd, 0x93, 0x01, 0x00, 0x35, 0x82, 0xa2, 0xc8, 0x81, 0x32, 0x00, 0x00, ++ 0x40, 0x00, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x80, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xef, 0xb3, 0x01, 0x00, ++ 0x37, 0x82, 0x42, 0x40, 0xf1, 0x33, 0x00, 0x00, 0x43, 0x81, 0x00, 0x40, ++ 0x68, 0x97, 0x00, 0x00, 0x22, 0x83, 0x00, 0xbb, 0x6b, 0xb3, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0xbb, 0xb1, 0xb3, 0x00, 0x00, 0x22, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x18, 0xb1, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x19, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x42, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x18, 0xb1, 0x01, 0x00, 0x40, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x19, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x81, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf6, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x43, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, 0x4a, 0x82, 0xa2, 0x54, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, 0x51, 0x82, 0xa2, 0x06, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x16, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x80, 0x16, 0x2e, 0x06, ++ 0x83, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0x57, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x22, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf6, 0xb1, 0x01, 0x00, ++ 0x5a, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x62, 0x00, 0x00, 0x40, ++ 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x16, 0x2d, 0x06, 0x83, 0xb0, 0x01, 0x00, 0x80, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x5c, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0x60, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xf9, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf9, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x70, 0x95, 0xb0, 0x01, 0x00, ++ 0x6c, 0x82, 0x22, 0x70, 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0xc4, 0x80, 0xa2, 0x42, 0x97, 0x6f, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x42, 0x99, 0xb3, 0x01, 0x00, ++ 0x78, 0x82, 0x22, 0x44, 0x81, 0x6c, 0x00, 0x00, 0x80, 0x82, 0x22, 0x48, ++ 0x81, 0x6c, 0x00, 0x00, 0x7a, 0x82, 0x22, 0x4c, 0x81, 0x6c, 0x00, 0x00, ++ 0x85, 0x82, 0x22, 0x50, 0x81, 0x6c, 0x00, 0x00, 0x86, 0x82, 0x22, 0x54, ++ 0x81, 0x6c, 0x00, 0x00, 0x88, 0x82, 0x22, 0x58, 0x81, 0x6c, 0x00, 0x00, ++ 0x8d, 0x82, 0x22, 0x5c, 0x81, 0x6c, 0x00, 0x00, 0x50, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x09, 0xb0, 0x01, 0x00, ++ 0x22, 0x83, 0x00, 0xca, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf3, 0x83, 0x01, 0x00, ++ 0x7e, 0x82, 0xa2, 0x42, 0x05, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x05, 0xb0, 0x01, 0x00, 0x22, 0x83, 0x22, 0xca, 0x07, 0x14, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0x46, 0xf3, 0x93, 0x00, 0x00, 0x22, 0x83, 0x20, 0x43, ++ 0x95, 0x6f, 0x00, 0x00, 0x22, 0x83, 0x80, 0xca, 0x05, 0x30, 0x00, 0x00, ++ 0x22, 0x83, 0x22, 0x01, 0x80, 0x30, 0x00, 0x00, 0xc4, 0x80, 0xa2, 0x48, ++ 0xdb, 0x7d, 0x00, 0x00, 0x22, 0x83, 0x00, 0xcb, 0xdb, 0x91, 0x00, 0x00, ++ 0x57, 0x01, 0x00, 0xbc, 0xab, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, ++ 0xb1, 0xb3, 0x01, 0x00, 0x22, 0x83, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, ++ 0xff, 0x00, 0x00, 0xca, 0x81, 0x88, 0x01, 0x00, 0x22, 0x83, 0xa2, 0x40, ++ 0x74, 0x7d, 0x00, 0x00, 0x60, 0x00, 0x20, 0x40, 0x60, 0x99, 0x01, 0x00, ++ 0x8a, 0x82, 0xa8, 0xb1, 0x82, 0x30, 0x00, 0x00, 0x89, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x22, 0x83, 0x00, 0xca, 0x79, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xcb, 0x83, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x90, 0x82, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x9b, 0x82, 0x91, 0x82, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, ++ 0x80, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0x99, 0x82, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x9b, 0x82, 0x56, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, 0xb6, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xcd, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xa0, 0x82, 0xa2, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xab, 0x82, 0x91, 0x81, ++ 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x80, 0xb0, 0x01, 0x00, ++ 0xae, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, 0xa9, 0x82, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xab, 0x82, 0x55, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x41, ++ 0x8b, 0xb3, 0x00, 0x00, 0xb1, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0xc4, 0x14, 0x2f, 0x40, 0x99, 0xb3, 0x01, 0x00, 0x57, 0x01, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0xa0, 0x94, 0x2e, 0x43, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0xb2, 0x82, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x50, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0xac, 0x94, 0x2e, 0x43, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xb6, 0x82, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xae, 0x03, 0x00, 0x40, ++ 0xa3, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x60, 0x15, 0x00, 0x40, 0x85, 0x98, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0x40, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x59, 0x41, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x41, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x40, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x42, ++ 0x81, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0xbc, 0x82, 0xa0, 0x42, 0x81, 0x6c, 0x00, 0x00, 0xbc, 0x82, 0x00, 0x50, ++ 0x85, 0xc0, 0x00, 0x00, 0x01, 0x83, 0xa2, 0x41, 0x01, 0x7d, 0x00, 0x00, ++ 0xcf, 0x82, 0x22, 0x58, 0x73, 0x7d, 0x00, 0x00, 0x78, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xc7, 0x82, 0xa8, 0xb1, 0x9c, 0x30, 0x00, 0x00, ++ 0x30, 0x00, 0x38, 0x45, 0x9d, 0xe0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5f, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x5e, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0xc0, 0x00, 0xa6, 0x1e, 0xa4, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, ++ 0x10, 0xc9, 0x00, 0x00, 0xcf, 0x82, 0x33, 0xc4, 0x81, 0x30, 0x00, 0x00, ++ 0xd2, 0x82, 0xa1, 0xad, 0x9d, 0x20, 0x00, 0x00, 0xc6, 0x82, 0x13, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4e, 0x5a, 0x83, 0x01, 0x00, ++ 0x30, 0x00, 0x38, 0x45, 0x9d, 0xe0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5f, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5e, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x40, 0x05, 0x6c, 0x00, 0x00, 0xdd, 0x82, 0x22, 0xab, ++ 0x80, 0x04, 0x00, 0x00, 0xdb, 0x82, 0xa2, 0x40, 0x01, 0x7d, 0x00, 0x00, ++ 0xdd, 0x82, 0x22, 0x5f, 0x57, 0x7d, 0x00, 0x00, 0x0f, 0x88, 0x00, 0x5f, ++ 0x1f, 0xb4, 0x00, 0x00, 0xdd, 0x82, 0x22, 0x5e, 0x57, 0x7d, 0x00, 0x00, ++ 0x7d, 0x88, 0x00, 0x5f, 0x1f, 0xb4, 0x00, 0x00, 0xe3, 0x82, 0x22, 0x54, ++ 0x73, 0x7d, 0x00, 0x00, 0x74, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xdd, 0x82, 0xa8, 0xb1, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x1f, 0xb4, 0x01, 0x00, 0xf4, 0x84, 0xa2, 0x5f, 0x01, 0x7c, 0x00, 0x00, ++ 0x92, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xe5, 0x82, 0xa2, 0x5f, ++ 0x59, 0x27, 0x00, 0x00, 0xe7, 0x82, 0xa2, 0x5c, 0x73, 0x7d, 0x00, 0x00, ++ 0xee, 0x82, 0xa2, 0x5e, 0x73, 0x7d, 0x00, 0x00, 0xfa, 0x82, 0x22, 0x5c, ++ 0x73, 0x7d, 0x00, 0x00, 0xfb, 0x82, 0x37, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xe8, 0x82, 0xa8, 0xb1, ++ 0x36, 0x30, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xea, 0x82, 0xa8, 0xb1, 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, ++ 0x02, 0x88, 0x01, 0x00, 0x34, 0x85, 0x17, 0x5f, 0x1f, 0xb4, 0x00, 0x00, ++ 0xfb, 0x82, 0x34, 0x40, 0x81, 0x32, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xef, 0x82, 0xa8, 0xb1, 0x12, 0x30, 0x00, 0x00, ++ 0xf7, 0x82, 0x52, 0x21, 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x41, ++ 0x2f, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x1f, 0xb4, 0x01, 0x00, ++ 0xff, 0x3f, 0x00, 0x09, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x01, 0xf0, 0x01, 0x00, 0x4f, 0x83, 0x00, 0x34, 0x13, 0x84, 0x00, 0x00, ++ 0xff, 0x3f, 0x14, 0x09, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x1f, 0xb4, 0x01, 0x00, 0xc2, 0x83, 0x00, 0x43, 0x01, 0xf0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xfb, 0x82, 0x33, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4e, 0x5a, 0x7f, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x4e, 0x80, 0xe4, 0x01, 0x00, 0x00, 0x39, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, 0x06, 0x6c, 0x00, 0x00, ++ 0xc6, 0x82, 0x13, 0x4e, 0x5a, 0x93, 0x00, 0x00, 0xe4, 0x87, 0xa2, 0x48, ++ 0xfd, 0x7f, 0x00, 0x00, 0x05, 0x83, 0x02, 0xe6, 0x81, 0x32, 0x00, 0x00, ++ 0x06, 0x83, 0x83, 0xe5, 0x81, 0x32, 0x00, 0x00, 0x8e, 0x82, 0x00, 0x42, ++ 0x97, 0xb3, 0x00, 0x00, 0x9e, 0x82, 0x00, 0x42, 0x97, 0xb3, 0x00, 0x00, ++ 0x09, 0x83, 0x22, 0x46, 0xf3, 0x7f, 0x00, 0x00, 0x0c, 0x83, 0xa2, 0x41, ++ 0xf3, 0x7f, 0x00, 0x00, 0xc6, 0x80, 0x00, 0x42, 0x97, 0x33, 0x01, 0x00, ++ 0x0c, 0x83, 0x22, 0x44, 0xf3, 0x7f, 0x00, 0x00, 0x0c, 0x83, 0xa2, 0x41, ++ 0xf3, 0x7f, 0x00, 0x00, 0xc6, 0x80, 0x00, 0x6f, 0x97, 0x33, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0xac, 0x80, 0x32, 0x00, 0x00, 0x11, 0x83, 0x22, 0x5a, ++ 0x73, 0x7d, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x0e, 0x83, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0xcf, ++ 0x11, 0xc9, 0x00, 0x00, 0x17, 0x83, 0xa2, 0x40, 0x93, 0x7f, 0x00, 0x00, ++ 0x17, 0x83, 0x22, 0x44, 0x93, 0x7f, 0x00, 0x00, 0x13, 0x83, 0x42, 0xa5, ++ 0x80, 0x30, 0x00, 0x00, 0x16, 0x83, 0xa2, 0x40, 0x93, 0x7f, 0x00, 0x00, ++ 0x38, 0x83, 0x1a, 0x40, 0x93, 0x93, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xdf, 0x80, 0xa2, 0x40, 0x73, 0x7d, 0x00, 0x00, ++ 0xdf, 0x87, 0x22, 0x44, 0x21, 0x6f, 0x00, 0x00, 0xd6, 0x87, 0x22, 0x40, ++ 0x65, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xa2, 0x5b, 0x73, 0x7d, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x49, 0x33, 0x7d, 0x00, 0x00, 0x21, 0x83, 0x22, 0x48, ++ 0x33, 0x7d, 0x00, 0x00, 0xff, 0x01, 0x00, 0x99, 0x80, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x81, 0xe0, 0x01, 0x00, 0xa8, 0x98, 0x2f, 0x40, ++ 0x33, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe0, 0xc1, 0x01, 0x00, ++ 0x01, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc6, 0x82, 0x00, 0x40, ++ 0x8b, 0xb3, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5e, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x5f, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x1f, 0x90, 0x01, 0x00, 0xc6, 0x82, 0x00, 0x5f, 0x1f, 0x80, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x5e, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x5f, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x62, 0xb1, 0x01, 0x00, ++ 0xc6, 0x82, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x2c, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5e, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x5f, ++ 0x1f, 0x7c, 0x00, 0x00, 0x32, 0x83, 0x33, 0x40, 0x1f, 0x30, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x4e, 0x5a, 0x7f, 0x00, 0x00, 0x07, 0x00, 0x00, 0x4e, ++ 0x80, 0xe4, 0x01, 0x00, 0x00, 0x39, 0x00, 0x40, 0x80, 0xc8, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x40, 0x06, 0x6c, 0x00, 0x00, 0xc6, 0x82, 0x13, 0x4e, ++ 0x5a, 0x93, 0x00, 0x00, 0x3a, 0x83, 0xa0, 0xce, 0x81, 0x50, 0x00, 0x00, ++ 0x4d, 0x83, 0xa0, 0xcd, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, ++ 0x9c, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x81, 0xb0, 0x01, 0x00, ++ 0x4d, 0x83, 0x22, 0xb5, 0x81, 0x14, 0x00, 0x00, 0x80, 0x15, 0x2f, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x3e, 0x83, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0xb4, 0x65, 0x97, 0x01, 0x00, 0xd0, 0x15, 0x2e, 0x40, ++ 0x69, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x44, 0x93, 0x83, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, 0x1a, 0x00, 0x00, 0xa2, ++ 0x80, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xb1, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb5, ++ 0xf1, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, 0x48, 0x83, 0xa8, 0xa1, ++ 0xe0, 0x31, 0x00, 0x00, 0x17, 0x83, 0x00, 0x88, 0x9e, 0xb3, 0x00, 0x00, ++ 0x17, 0x83, 0xa2, 0x41, 0x67, 0x6f, 0x00, 0x00, 0x17, 0x83, 0x00, 0x6f, ++ 0xdb, 0x91, 0x00, 0x00, 0x4d, 0x83, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x17, 0x83, 0x1a, 0x40, 0x93, 0x83, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5a, 0x01, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x01, 0x6c, 0x00, 0x00, 0x00, 0x99, 0x00, 0x09, 0x46, 0xc9, 0x01, 0x00, ++ 0x3f, 0x00, 0x00, 0xf3, 0x0c, 0x88, 0x01, 0x00, 0x5c, 0x83, 0xa6, 0x42, ++ 0x13, 0x60, 0x00, 0x00, 0x95, 0x96, 0x00, 0x95, 0x03, 0x30, 0x01, 0x00, ++ 0x57, 0x83, 0x61, 0x40, 0x81, 0x32, 0x00, 0x00, 0x75, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x58, 0x83, 0xa8, 0xb1, 0x0c, 0x30, 0x00, 0x00, ++ 0xa3, 0x96, 0x71, 0x10, 0x94, 0x30, 0x01, 0x00, 0x5d, 0x83, 0x00, 0x58, ++ 0x1f, 0x90, 0x00, 0x00, 0x87, 0x96, 0x00, 0x95, 0x03, 0x30, 0x01, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x2d, 0xf0, 0x2e, 0xb0, 0x01, 0x00, ++ 0x80, 0x04, 0x00, 0x17, 0x96, 0x88, 0x01, 0x00, 0x04, 0x00, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x4a, 0xc1, 0x00, 0x17, 0x96, 0xd8, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xee, 0x07, 0x00, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x68, 0x83, 0x23, 0x4b, 0xe4, 0x6d, 0x00, 0x00, ++ 0x68, 0x83, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1f, 0x90, 0x01, 0x00, 0x22, 0x00, 0x2f, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x6b, 0x83, 0x83, 0x17, 0x80, 0x32, 0x00, 0x00, 0x26, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x6d, 0x83, 0x85, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x47, 0xc1, 0x01, 0x00, 0x72, 0x83, 0x22, 0x55, ++ 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0xd1, 0x01, 0x00, ++ 0x0f, 0x00, 0x00, 0xfa, 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x97, 0xe0, 0x01, 0x00, 0x73, 0x83, 0x00, 0x4b, 0x44, 0xc1, 0x00, 0x00, ++ 0x12, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x28, 0x00, 0x00, 0xf6, ++ 0x02, 0xcc, 0x01, 0x00, 0x0a, 0x00, 0x00, 0xa1, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x28, 0xf0, ++ 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa2, 0x2a, 0xb0, 0x01, 0x00, 0xc0, 0x28, 0x3c, 0x46, ++ 0x0d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x44, 0x95, 0xb0, 0x01, 0x00, ++ 0x7f, 0x83, 0xa2, 0xf8, 0x0e, 0x30, 0x00, 0x00, 0x8f, 0x83, 0x22, 0x41, ++ 0x95, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x49, 0xc1, 0x01, 0x00, ++ 0x7b, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x7c, 0x83, 0xa2, 0xf8, ++ 0x16, 0x6c, 0x00, 0x00, 0x7c, 0x83, 0xa2, 0xf8, 0x10, 0x6c, 0x00, 0x00, ++ 0x7c, 0x83, 0xa2, 0xf0, 0x1a, 0x6c, 0x00, 0x00, 0x8d, 0x83, 0x22, 0x58, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, ++ 0x84, 0x83, 0x65, 0x40, 0x81, 0x32, 0x00, 0x00, 0x88, 0x83, 0xa2, 0xf3, ++ 0x74, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xe6, 0x95, 0x01, 0x00, ++ 0x8d, 0x83, 0x75, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0x96, 0xb0, 0x01, 0x00, 0x3f, 0x00, 0x75, 0xf3, 0x0c, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x8b, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x8d, 0x83, 0x67, 0x40, 0x81, 0x32, 0x00, 0x00, 0x95, 0x83, 0x77, 0x41, ++ 0x2d, 0xc3, 0x00, 0x00, 0x93, 0x83, 0x22, 0x58, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0x62, 0xb1, 0x01, 0x00, 0x91, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x93, 0x83, 0x67, 0x40, 0x81, 0x32, 0x00, 0x00, 0xd3, 0x83, 0x77, 0x41, ++ 0x2d, 0xc3, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, ++ 0x12, 0x95, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, 0xa6, 0x83, 0x22, 0x41, ++ 0x81, 0x6c, 0x00, 0x00, 0x9b, 0x83, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xa5, 0x83, 0x22, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x48, 0x96, 0x00, 0x5f, 0x01, 0x10, 0x01, 0x00, ++ 0xa1, 0x83, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, ++ 0x9f, 0x95, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x0f, 0x80, 0x01, 0x00, ++ 0x01, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, ++ 0x8a, 0x30, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0xb5, 0x83, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x6a, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb5, 0x83, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0xb0, 0x83, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x87, 0x95, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0xc2, 0x97, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x4b, 0xe1, 0x7d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xb9, 0x83, 0x82, 0xf0, 0x18, 0x30, 0x00, 0x00, 0x69, 0x89, 0x00, 0x45, ++ 0x8f, 0xb0, 0x00, 0x00, 0x28, 0x20, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, ++ 0xbf, 0x83, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, 0x34, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x55, 0x97, 0x00, 0x4b, 0x95, 0x30, 0x01, 0x00, 0x69, 0x89, 0x00, 0x4b, ++ 0x8f, 0xb0, 0x00, 0x00, 0x57, 0x96, 0x00, 0x03, 0x48, 0x31, 0x01, 0x00, ++ 0xa9, 0x93, 0x00, 0x40, 0x81, 0x30, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0x00, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, ++ 0x8a, 0x30, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, 0x01, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x68, 0x50, ++ 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xce, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, ++ 0x62, 0xc9, 0x01, 0x00, 0xd0, 0x83, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x2e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x00, 0x41, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, 0xee, 0x07, 0x2e, 0x47, ++ 0x97, 0x90, 0x01, 0x00, 0xe6, 0x83, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, ++ 0xe4, 0x83, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0xe4, 0x83, 0x23, 0xa2, ++ 0x02, 0x6c, 0x00, 0x00, 0x9f, 0x95, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x97, 0x50, 0x00, 0x00, 0x0c, 0x00, 0x2d, 0x00, ++ 0x12, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x01, 0x80, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x03, 0xb0, 0x01, 0x00, 0x03, 0x84, 0x00, 0x5c, ++ 0x17, 0x90, 0x00, 0x00, 0xf8, 0x83, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x1f, 0x90, 0x01, 0x00, 0xf1, 0x83, 0x22, 0x5f, ++ 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0xf1, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0xf0, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0xed, 0x83, 0x62, 0x42, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0xee, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x72, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0xff, 0x0f, 0x00, 0xf6, 0x80, 0x88, 0x01, 0x00, ++ 0xf5, 0x83, 0xa2, 0xa6, 0x81, 0x6c, 0x00, 0x00, 0xf8, 0x83, 0x00, 0xf2, ++ 0x3a, 0xb0, 0x00, 0x00, 0xf1, 0x84, 0xa2, 0x4b, 0xfd, 0x7f, 0x00, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x03, 0x88, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x84, 0x22, 0x4a, 0x2f, 0x7c, 0x00, 0x00, ++ 0x03, 0x84, 0x22, 0x48, 0x2f, 0x7c, 0x00, 0x00, 0x0a, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x3f, 0x00, 0x00, 0xf2, 0x86, 0x88, 0x01, 0x00, ++ 0x1f, 0x00, 0x00, 0x43, 0x84, 0x88, 0x01, 0x00, 0x05, 0x00, 0x00, 0x43, ++ 0x80, 0xf4, 0x01, 0x00, 0x98, 0x94, 0x3d, 0x42, 0x81, 0xe0, 0x01, 0x00, ++ 0x03, 0x84, 0xa2, 0x42, 0xe0, 0x7d, 0x00, 0x00, 0xf1, 0x84, 0xa2, 0x4b, ++ 0xfd, 0x7f, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x03, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x02, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x05, 0x84, 0x69, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, ++ 0x09, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x79, 0x41, 0x47, 0xc3, 0x01, 0x00, ++ 0x04, 0x00, 0xa0, 0xa1, 0x09, 0x6c, 0x00, 0x00, 0x0c, 0x84, 0x22, 0xa1, ++ 0x09, 0x6c, 0x00, 0x00, 0x27, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x08, 0x84, 0x00, 0x03, 0x48, 0xb1, 0x00, 0x00, 0x46, 0x84, 0xa3, 0x92, ++ 0x03, 0x6c, 0x00, 0x00, 0x25, 0x98, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0x80, 0xb2, 0x01, 0x00, 0x03, 0x88, 0x27, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x13, 0x84, 0x22, 0x5c, 0x17, 0x7c, 0x00, 0x00, 0x14, 0x84, 0x00, 0x00, ++ 0x2a, 0xb0, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x08, 0x80, 0xc8, 0x01, 0x00, 0x18, 0x84, 0xa2, 0x43, ++ 0x2f, 0x7c, 0x00, 0x00, 0x58, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x34, 0x84, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, ++ 0x8c, 0xcc, 0x01, 0x00, 0x58, 0x97, 0x00, 0x4c, 0x03, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x46, 0x02, 0xb0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, ++ 0x2c, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x15, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x21, 0x84, 0xa8, 0x54, 0x17, 0x10, 0x00, 0x00, ++ 0x34, 0x84, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, ++ 0x2a, 0xc8, 0x01, 0x00, 0x33, 0x84, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x01, 0x8c, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x03, 0xb0, 0x01, 0x00, 0x79, 0x97, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x46, 0x02, 0xb0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0x09, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x15, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x34, 0x84, 0x28, 0x54, 0x17, 0x10, 0x00, 0x00, ++ 0x30, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x79, 0x97, 0x00, 0x43, ++ 0x61, 0x31, 0x01, 0x00, 0x36, 0x84, 0x22, 0x50, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x56, 0x17, 0x90, 0x01, 0x00, 0x07, 0x00, 0x00, 0x17, ++ 0x98, 0x88, 0x01, 0x00, 0x39, 0x84, 0xa2, 0x41, 0x99, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x17, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x3a, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x60, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x41, 0x84, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, 0x16, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xe4, 0xb1, 0x01, 0x00, ++ 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x44, 0x84, 0xa2, 0x5f, ++ 0x2f, 0x7c, 0x00, 0x00, 0x80, 0x93, 0x00, 0x01, 0x38, 0x43, 0x01, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x03, 0x88, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x48, 0x84, 0xa2, 0x4b, 0xfd, 0x7f, 0x00, 0x00, ++ 0xee, 0x84, 0x00, 0x41, 0x43, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x27, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2d, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, 0x4b, 0x84, 0x35, 0x01, ++ 0x86, 0x30, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x54, 0x84, 0x28, 0xb1, 0x30, 0x30, 0x00, 0x00, 0x4c, 0x84, 0x22, 0x4d, ++ 0x75, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80, 0xb2, 0x01, 0x00, ++ 0xdb, 0x84, 0xa7, 0x40, 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x43, 0xc3, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, 0x27, 0x6c, 0x00, 0x00, ++ 0xed, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x54, 0x84, 0xa8, 0xb1, 0x12, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x80, 0xb2, 0x01, 0x00, 0x5e, 0x84, 0xa7, 0x40, ++ 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x2c, 0xb0, 0x01, 0x00, 0xde, 0x07, 0x00, 0x43, 0x80, 0xce, 0x01, 0x00, ++ 0x4c, 0x84, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, 0x63, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x40, 0x00, 0x3e, 0x43, 0x27, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x27, 0xc0, 0x01, 0x00, ++ 0x4c, 0x84, 0xa3, 0x0b, 0x87, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, ++ 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x03, 0x48, 0x6d, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, ++ 0x2a, 0xc8, 0x01, 0x00, 0x40, 0x00, 0x2d, 0x40, 0x39, 0xb0, 0x01, 0x00, ++ 0x6d, 0x84, 0xa2, 0x40, 0x27, 0x6c, 0x00, 0x00, 0x22, 0x00, 0x00, 0x08, ++ 0x12, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x16, 0x30, 0x6c, 0x00, 0x00, ++ 0xde, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, 0x70, 0x84, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x12, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x30, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0x25, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x20, 0x01, 0xe0, 0xb1, 0x01, 0x00, 0xee, 0x07, 0x00, 0x40, ++ 0x37, 0x98, 0x01, 0x00, 0x75, 0x84, 0x23, 0x01, 0x36, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x36, 0xb0, 0x01, 0x00, 0x80, 0x84, 0x82, 0x41, ++ 0x23, 0x40, 0x00, 0x00, 0x20, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x7c, 0x84, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x79, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xed, 0x94, 0x00, 0x43, 0x23, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x44, 0xc9, 0x01, 0x00, 0x91, 0x84, 0x22, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x41, 0x23, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x0b, 0x25, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x88, 0x84, 0xa8, 0x15, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x25, 0xd0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x4c, ++ 0x13, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x37, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x2b, 0xc0, 0x01, 0x00, 0x75, 0x84, 0x00, 0x45, ++ 0x1f, 0x80, 0x00, 0x00, 0x93, 0x84, 0xa3, 0x12, 0x36, 0x6c, 0x00, 0x00, ++ 0x94, 0x84, 0x68, 0x1b, 0x28, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, ++ 0x28, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x97, 0x84, 0xa8, 0x15, 0xe0, 0x31, 0x00, 0x00, 0xbf, 0x84, 0x22, 0x14, ++ 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x14, 0x24, 0xd0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x14, ++ 0x12, 0xc0, 0x01, 0x00, 0xb7, 0x84, 0xa2, 0x14, 0x36, 0x50, 0x00, 0x00, ++ 0xa7, 0x84, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xa5, 0x84, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xa2, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xf0, 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x2b, 0x80, 0x01, 0x00, 0x04, 0x00, 0x22, 0x50, 0x2b, 0x6c, 0x00, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x37, 0x98, 0x01, 0x00, 0xad, 0x84, 0x23, 0x01, ++ 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x36, 0xb0, 0x01, 0x00, ++ 0xb8, 0x84, 0x22, 0x1b, 0x02, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x15, 0xe0, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0xb4, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xb8, 0x84, 0x00, 0x03, 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x2a, 0xc0, 0x01, 0x00, 0x75, 0x84, 0xa2, 0x40, 0x25, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x39, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x20, 0x13, ++ 0x38, 0x6c, 0x00, 0x00, 0x40, 0x00, 0x3d, 0x43, 0x39, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x25, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x12, 0xb0, 0x01, 0x00, 0x75, 0x84, 0x00, 0xf0, 0x30, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0xc6, 0x84, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x19, ++ 0x62, 0xdd, 0x01, 0x00, 0xc3, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xed, 0x94, 0x00, 0x40, ++ 0x2b, 0x30, 0x01, 0x00, 0x18, 0x00, 0x2e, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0xca, 0x84, 0x22, 0x50, 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, ++ 0x17, 0x90, 0x01, 0x00, 0x07, 0x00, 0x00, 0x17, 0x98, 0x88, 0x01, 0x00, ++ 0xcd, 0x84, 0xa2, 0x41, 0x99, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x17, 0x90, 0x01, 0x00, 0xd0, 0x84, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x17, 0x90, 0x01, 0x00, 0x16, 0x00, 0x20, 0x1d, ++ 0xe4, 0xb1, 0x01, 0x00, 0xd2, 0x84, 0xa3, 0x40, 0x27, 0x6c, 0x00, 0x00, ++ 0xd4, 0x84, 0x60, 0x5f, 0x17, 0x90, 0x00, 0x00, 0x00, 0x84, 0x00, 0x0b, ++ 0x16, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x60, 0x13, 0x16, 0x94, 0x01, 0x00, ++ 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, ++ 0x0f, 0x6c, 0x00, 0x00, 0x03, 0x88, 0xa2, 0x5f, 0x2f, 0x7c, 0x00, 0x00, ++ 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x80, 0x93, 0x00, 0x01, 0x38, 0x43, 0x01, 0x00, ++ 0x03, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x03, ++ 0x48, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x22, 0x4d, 0x75, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4d, ++ 0x61, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x62, 0xb1, 0x01, 0x00, 0xe0, 0x84, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x62, 0xb1, 0x01, 0x00, ++ 0xe2, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xed, 0x84, 0x22, 0x13, ++ 0x82, 0x6c, 0x00, 0x00, 0x40, 0x00, 0x3d, 0x43, 0x83, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x2c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x62, 0xb1, 0x01, 0x00, ++ 0xe8, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x62, 0xb1, 0x01, 0x00, 0xea, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xe4, 0x84, 0x00, 0x41, 0x83, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x82, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, ++ 0xa0, 0x98, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x30, 0x05, 0x00, 0x41, ++ 0x89, 0x30, 0x01, 0x00, 0x9f, 0x95, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, ++ 0xa6, 0x95, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x03, 0x88, 0x00, 0x40, ++ 0x0f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x80, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x00, 0x0e, 0xf4, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, ++ 0x05, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, ++ 0x8a, 0x30, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, ++ 0x12, 0x95, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, 0x05, 0x85, 0x22, 0x41, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x85, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x04, 0x85, 0x22, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x0f, 0x80, 0x01, 0x00, ++ 0x06, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, ++ 0x8a, 0x30, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0x14, 0x85, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x6a, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x14, 0x85, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0x0f, 0x85, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x87, 0x95, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0xc2, 0x97, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x4b, 0xe1, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, ++ 0x19, 0x85, 0x22, 0x3a, 0x01, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x8e, 0xb0, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, 0x01, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x2e, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x1e, 0x85, 0xa2, 0x40, 0xe7, 0x6d, 0x00, 0x00, ++ 0x0a, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, ++ 0x01, 0xb0, 0x00, 0x00, 0x17, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0x35, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x87, 0x96, 0x00, 0x95, 0x03, 0x30, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x22, 0x00, 0x2d, 0xf0, 0x2e, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x28, 0x20, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, ++ 0x2b, 0x85, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, 0x55, 0x97, 0x00, 0x4b, ++ 0x95, 0x30, 0x01, 0x00, 0x69, 0x89, 0x00, 0x4c, 0x8f, 0xb0, 0x00, 0x00, ++ 0x2d, 0x85, 0x83, 0x17, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x43, 0xc1, 0x01, 0x00, 0x2f, 0x85, 0x85, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x43, 0xc1, 0x01, 0x00, 0x28, 0x00, 0x00, 0xf6, ++ 0x02, 0xcc, 0x01, 0x00, 0x12, 0x00, 0x00, 0xa1, 0x2a, 0xc8, 0x01, 0x00, ++ 0x57, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xa9, 0x93, 0x00, 0x41, ++ 0x81, 0x30, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0x39, 0x85, 0x64, 0x47, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x3a, 0x85, 0xa8, 0x1b, ++ 0xe0, 0x31, 0x00, 0x00, 0x23, 0x83, 0x74, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x03, 0xe0, 0x01, 0x00, 0x04, 0x00, 0xa0, 0x05, ++ 0x03, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa3, 0x09, 0x03, 0x6c, 0x00, 0x00, ++ 0x08, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x6b, 0x85, 0x01, 0xfb, ++ 0x08, 0x30, 0x00, 0x00, 0xd5, 0x85, 0x87, 0xfb, 0x22, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0x0e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x14, 0xb0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, ++ 0x12, 0x95, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, 0x5c, 0x85, 0x22, 0x41, ++ 0x81, 0x6c, 0x00, 0x00, 0x4b, 0x85, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x5b, 0x85, 0x22, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x04, 0x7e, 0x89, 0x01, 0x00, ++ 0x51, 0x85, 0xa6, 0x5f, 0x0f, 0x00, 0x00, 0x00, 0x2b, 0x94, 0x00, 0x40, ++ 0x05, 0x30, 0x01, 0x00, 0x0a, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, 0x58, 0x85, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0x26, 0x96, 0x00, 0x40, 0x05, 0x30, 0x01, 0x00, 0x08, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0x69, 0x85, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x6a, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x69, 0x85, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0x66, 0x85, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x87, 0x95, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0xc2, 0x97, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, 0x6d, 0x85, 0x21, 0x04, ++ 0x80, 0x20, 0x00, 0x00, 0x6e, 0x85, 0x00, 0x40, 0x10, 0xc9, 0x00, 0x00, ++ 0xa1, 0x88, 0x00, 0x4b, 0x81, 0xb0, 0x00, 0x00, 0x9c, 0x85, 0x00, 0x43, ++ 0x81, 0xb0, 0x00, 0x00, 0xa0, 0x85, 0x00, 0xfb, 0x22, 0xb0, 0x00, 0x00, ++ 0xa1, 0x88, 0x00, 0x41, 0x81, 0xb0, 0x00, 0x00, 0x69, 0x89, 0x00, 0x4e, ++ 0x8f, 0xb0, 0x00, 0x00, 0x91, 0x85, 0x00, 0x5a, 0x8f, 0xb0, 0x00, 0x00, ++ 0x76, 0x85, 0x00, 0x47, 0x8f, 0xb0, 0x00, 0x00, 0xa1, 0x88, 0x00, 0x53, ++ 0x81, 0xb0, 0x00, 0x00, 0xa1, 0x88, 0x00, 0x56, 0x81, 0xb0, 0x00, 0x00, ++ 0x32, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x07, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x3c, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x0a, ++ 0x8a, 0x30, 0x01, 0x00, 0x3d, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x18, 0x00, 0x00, 0x11, 0x8a, 0xe4, 0x01, 0x00, 0x02, 0x99, 0x00, 0xf2, ++ 0x8a, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x69, 0x89, 0xa0, 0x0a, 0xe4, 0x6d, 0x00, 0x00, 0x84, 0x85, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x83, 0x85, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, ++ 0x69, 0x89, 0x00, 0x53, 0x8f, 0xb0, 0x00, 0x00, 0x69, 0x89, 0x00, 0x54, ++ 0x8f, 0xb0, 0x00, 0x00, 0x8d, 0x85, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, ++ 0x87, 0x85, 0xa2, 0x0a, 0xe4, 0x6d, 0x00, 0x00, 0x69, 0x89, 0x00, 0x5d, ++ 0x8f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x80, 0xd0, 0x01, 0x00, 0x8b, 0x85, 0xa0, 0x91, ++ 0x81, 0x6c, 0x00, 0x00, 0x69, 0x89, 0x00, 0x5e, 0x8f, 0xb0, 0x00, 0x00, ++ 0x25, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8f, 0x85, 0x20, 0x91, 0xe5, 0x6d, 0x00, 0x00, ++ 0x69, 0x89, 0x00, 0x54, 0x8f, 0xb0, 0x00, 0x00, 0x21, 0x00, 0x00, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x32, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x07, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x3c, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x0a, ++ 0x8a, 0x30, 0x01, 0x00, 0x3d, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0xf2, 0x8a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x69, 0x89, 0xa0, 0x0a, 0xe4, 0x6d, 0x00, 0x00, ++ 0x24, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x69, 0x89, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x82, 0xf4, 0x01, 0x00, 0xa1, 0x88, 0xa0, 0x42, ++ 0x83, 0x6c, 0x00, 0x00, 0xa1, 0x88, 0x00, 0x54, 0x81, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x0e, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x23, 0x40, ++ 0x0f, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x20, 0xaa, 0x0f, 0x6c, 0x00, 0x00, ++ 0x09, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, ++ 0x8a, 0x30, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, ++ 0x16, 0x88, 0x01, 0x00, 0xae, 0x85, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x0a, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x78, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0x1c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0xed, 0x87, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0xc0, 0x85, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, ++ 0xbb, 0x85, 0xa2, 0x54, 0xfd, 0x7f, 0x00, 0x00, 0xb3, 0x85, 0x22, 0x55, ++ 0xfd, 0x7f, 0x00, 0x00, 0x82, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0xaa, 0x85, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x22, 0x53, ++ 0xfd, 0x7f, 0x00, 0x00, 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x96, 0xb0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4b, ++ 0x80, 0xf4, 0x01, 0x00, 0x0c, 0xbc, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0xbb, 0x85, 0x22, 0x43, 0x80, 0x6c, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4b, ++ 0x80, 0x88, 0x01, 0x00, 0xaa, 0x85, 0xa2, 0x43, 0x80, 0x6c, 0x00, 0x00, ++ 0x7c, 0x96, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xbc, 0x85, 0x46, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xbf, 0x85, 0xa0, 0xf0, 0x30, 0x6f, 0x00, 0x00, ++ 0xb1, 0x85, 0x1e, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x41, ++ 0x31, 0xc3, 0x01, 0x00, 0x79, 0x94, 0x00, 0x40, 0x25, 0x30, 0x01, 0x00, ++ 0xc4, 0x85, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x87, 0x95, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, ++ 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x96, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x18, 0xe4, 0x01, 0x00, 0x00, 0x08, 0x00, 0x0c, 0xe0, 0x99, 0x01, 0x00, ++ 0x90, 0x04, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0xcc, 0x85, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe6, 0x91, 0x01, 0x00, 0x00, 0x02, 0x00, 0xa1, 0x46, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe6, 0x91, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xa1, 0x88, 0x00, 0x40, ++ 0x81, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x28, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x14, 0xb0, 0x01, 0x00, 0xe0, 0x85, 0x22, 0x46, 0x23, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x40, 0x87, 0x6c, 0x00, 0x00, 0xdc, 0x85, 0x22, 0x40, ++ 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x1f, 0x90, 0x01, 0x00, ++ 0xde, 0x85, 0x22, 0x41, 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x1f, 0x90, 0x01, 0x00, 0xe0, 0x85, 0x22, 0x42, 0x87, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x1f, 0x90, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x09, 0x7c, 0x00, 0x00, 0xe1, 0x85, 0x66, 0x1b, 0x2c, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa0, 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x76, 0x41, ++ 0x41, 0xc3, 0x01, 0x00, 0x13, 0x86, 0x23, 0x92, 0x15, 0x6c, 0x00, 0x00, ++ 0x13, 0x86, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0x19, 0x86, 0x22, 0x4b, ++ 0xfd, 0x7f, 0x00, 0x00, 0x17, 0x00, 0x00, 0xd0, 0xa2, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x27, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x0a, ++ 0x24, 0xc8, 0x01, 0x00, 0xb9, 0x94, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, ++ 0x11, 0x86, 0x22, 0x08, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa3, 0xc1, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x12, 0x24, 0xcc, 0x01, 0x00, ++ 0xea, 0x85, 0xaa, 0x41, 0x27, 0x40, 0x00, 0x00, 0x04, 0x00, 0xa3, 0x49, ++ 0x27, 0x6c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x80, 0xcc, 0x01, 0x00, ++ 0x0b, 0x86, 0x26, 0x40, 0x23, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x60, 0x00, 0x00, 0x03, 0x84, 0xc8, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x48, 0xcd, 0x01, 0x00, 0x17, 0x00, 0x00, 0xd0, ++ 0xa2, 0xc9, 0x01, 0x00, 0xf8, 0x85, 0xa2, 0x40, 0x83, 0x6c, 0x00, 0x00, ++ 0x04, 0x86, 0x00, 0x41, 0x83, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x42, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x68, 0x21, 0x38, 0x96, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x50, 0x49, 0xc1, 0x01, 0x00, 0xfd, 0x85, 0xa2, 0x44, ++ 0x23, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x20, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x86, 0xa8, 0x42, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa3, 0xc1, 0x01, 0x00, 0xf6, 0x85, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x0b, 0x86, 0x22, 0x40, 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x08, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0xee, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, ++ 0x17, 0x00, 0x00, 0xd0, 0x2a, 0xc8, 0x01, 0x00, 0x24, 0x86, 0x00, 0x17, ++ 0x10, 0xb0, 0x00, 0x00, 0x04, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x19, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb9, 0x94, 0x00, 0x92, ++ 0x25, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x31, 0xb0, 0x01, 0x00, ++ 0x0b, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, ++ 0x8a, 0x30, 0x01, 0x00, 0x19, 0x86, 0x22, 0x08, 0x2e, 0x30, 0x00, 0x00, ++ 0x24, 0x86, 0x00, 0x41, 0x27, 0xb0, 0x00, 0x00, 0x80, 0x80, 0x00, 0xa6, ++ 0x04, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x78, 0x98, 0x00, 0x0a, 0x8c, 0x30, 0x01, 0x00, 0x04, 0x00, 0x1c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, 0x04, 0x00, 0xa0, 0x9f, ++ 0x13, 0x6c, 0x00, 0x00, 0x23, 0x86, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x88, 0x1c, 0xcc, 0x01, 0x00, 0x27, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xed, 0x87, 0x00, 0x41, 0x3f, 0xc3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x01, ++ 0x80, 0xce, 0x01, 0x00, 0x38, 0x86, 0x2a, 0x40, 0x81, 0x30, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0x2d, 0x86, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, ++ 0x2d, 0x86, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0x2d, 0x86, 0xa3, 0x07, ++ 0x03, 0x6c, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x30, 0x86, 0xa3, 0x40, 0x02, 0x6c, 0x00, 0x00, 0x28, 0x00, 0x00, 0x01, ++ 0xf0, 0xcd, 0x01, 0x00, 0x32, 0x86, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0xf0, 0xcd, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x0e, 0xcc, 0x01, 0x00, 0x28, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x00, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x36, 0x86, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x04, 0x00, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x03, 0x48, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x08, 0xb0, 0x01, 0x00, ++ 0xa0, 0x01, 0x2d, 0x40, 0x00, 0xc0, 0x01, 0x00, 0x19, 0x87, 0x22, 0x0f, ++ 0x42, 0x05, 0x00, 0x00, 0x4b, 0x86, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x46, 0x86, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x43, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x4b, 0x86, 0x22, 0x07, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x42, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x42, 0xc1, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa1, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0xc0, 0x06, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x54, 0x29, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x04, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0e, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x14, 0x80, 0xce, 0x01, 0x00, ++ 0x04, 0x00, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, 0x42, 0x00, 0x00, 0x03, ++ 0x0a, 0xc8, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, 0x0c, 0xc8, 0x01, 0x00, ++ 0x10, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x24, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x01, 0x00, 0x12, 0x00, 0x00, 0x08, ++ 0x10, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0xfe, 0x7f, 0x00, 0x05, 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xa2, ++ 0x86, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xe4, 0xb1, 0x01, 0x00, ++ 0x79, 0x86, 0x22, 0x01, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, ++ 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0xa4, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x48, 0xc1, 0x01, 0x00, 0x66, 0x86, 0xa3, 0x07, ++ 0x02, 0x6c, 0x00, 0x00, 0x67, 0x86, 0x68, 0x01, 0x1a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x68, 0x07, 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x02, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0xc0, 0x01, 0x00, ++ 0x73, 0x86, 0x22, 0x40, 0x03, 0x6c, 0x00, 0x00, 0x73, 0x86, 0x22, 0x42, ++ 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x99, 0x86, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x70, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, 0x75, 0x86, 0xa8, 0x40, ++ 0x23, 0x30, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x99, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, ++ 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xc1, 0x01, 0x00, 0x7e, 0x86, 0xa3, 0x12, ++ 0x0e, 0x6c, 0x00, 0x00, 0x7f, 0x86, 0x60, 0x07, 0x1a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0x12, 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x0d, ++ 0x16, 0x94, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x16, 0xd8, 0x01, 0x00, ++ 0x14, 0x99, 0x00, 0x08, 0x98, 0x30, 0x01, 0x00, 0x00, 0x00, 0x68, 0x08, ++ 0x3e, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, 0x87, 0x86, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0xb9, 0x86, 0x22, 0x0d, 0x14, 0x6c, 0x00, 0x00, ++ 0x8d, 0x86, 0x22, 0x0d, 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x10, 0xc0, 0x01, 0x00, 0x92, 0x86, 0x00, 0x0d, 0x24, 0xd0, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x2b, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0xa2, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x20, 0x10, 0xc8, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x25, 0x98, 0x01, 0x00, 0x94, 0x86, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x99, 0x86, 0x00, 0x41, 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x95, 0x86, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0xb9, 0x86, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, 0xb8, 0x86, 0xa2, 0x0d, ++ 0x0e, 0x50, 0x00, 0x00, 0xa5, 0x86, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xa3, 0x86, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xa0, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x0e, 0x30, 0x00, 0x00, 0xab, 0x86, 0xa2, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x60, 0x86, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x5f, 0x0f, 0x80, 0x01, 0x00, 0x60, 0x86, 0x23, 0x07, ++ 0x14, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0xb5, 0x86, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0x60, 0x86, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, 0x60, 0x86, 0x00, 0x0d, ++ 0x18, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x2e, 0x14, 0x0a, 0xd0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x05, 0x48, 0xcd, 0x01, 0x00, 0xfe, 0x7f, 0x00, 0x05, ++ 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xa4, 0x86, 0x06, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0xa1, 0x86, 0x06, 0x00, 0x00, 0x0c, 0x00, 0x2a, 0xf2, ++ 0xe0, 0xb1, 0x01, 0x00, 0xc1, 0x86, 0x22, 0x40, 0x31, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0x18, 0x38, 0x96, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x81, 0x00, 0xf6, 0x80, 0xce, 0x01, 0x00, ++ 0xc5, 0x86, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x43, 0xc1, 0x01, 0x00, 0xc7, 0x86, 0x22, 0x0b, 0xed, 0x6d, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0xa1, 0x42, 0xc9, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa1, ++ 0x46, 0xc9, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xa1, 0x86, 0x06, 0x00, 0x00, ++ 0x0f, 0x00, 0x00, 0xfa, 0x94, 0x88, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x45, ++ 0x95, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x4a, 0x86, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf6, 0x0e, 0xb0, 0x01, 0x00, 0xd1, 0x86, 0x22, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x1f, 0x43, 0x0e, 0x50, 0x00, 0x00, ++ 0xd1, 0x86, 0xa0, 0x46, 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xc0, 0x01, 0x00, 0xd5, 0x86, 0x22, 0x48, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x91, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x0f, 0xa2, ++ 0x42, 0x31, 0x00, 0x00, 0xd8, 0x86, 0x00, 0x40, 0x89, 0xb0, 0x00, 0x00, ++ 0x0c, 0x00, 0x00, 0xa2, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x95, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x82, 0xb0, 0x01, 0x00, 0xdb, 0x86, 0xa0, 0x41, ++ 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x91, 0xc0, 0x01, 0x00, ++ 0xe0, 0x86, 0x22, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0xe0, 0x86, 0xa0, 0x43, ++ 0x89, 0x6c, 0x00, 0x00, 0xe0, 0x86, 0x20, 0x45, 0x89, 0x6c, 0x00, 0x00, ++ 0xe0, 0x86, 0xa0, 0x41, 0x0e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x89, 0xc0, 0x01, 0x00, ++ 0xd8, 0x86, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, 0xed, 0x86, 0x22, 0x48, ++ 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x48, 0x92, 0xf4, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x48, 0x90, 0x88, 0x01, 0x00, 0xe7, 0x86, 0x90, 0x48, ++ 0x92, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x93, 0xa4, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x43, 0x80, 0xcc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa2, 0x80, 0xc0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, ++ 0x42, 0x6d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0xa1, 0x86, 0x06, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x46, 0x1f, 0x7c, 0x00, 0x00, 0x14, 0x99, 0x00, 0x17, ++ 0x98, 0x30, 0x01, 0x00, 0xff, 0x07, 0x00, 0x17, 0x7e, 0x89, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x12, 0x00, 0x00, 0x14, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x17, 0xf0, 0xb1, 0x01, 0x00, 0x12, 0x00, 0x00, 0x05, ++ 0xe0, 0xcd, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, 0x80, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, ++ 0x62, 0xdd, 0x01, 0x00, 0xf7, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x02, 0x87, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, ++ 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x10, 0x48, 0xc1, 0x01, 0x00, ++ 0x01, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xfe, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x05, 0x87, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0x06, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x85, 0x87, 0x00, 0x17, 0x10, 0xb0, 0x00, 0x00, ++ 0x0d, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x09, 0x87, 0xa0, 0x07, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, ++ 0x0d, 0x87, 0x90, 0xf2, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x14, 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x2b, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2a, 0x94, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x17, 0x87, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x14, 0x87, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x17, 0x10, 0xdc, 0x01, 0x00, 0x85, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x21, 0x87, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x21, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x1e, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x26, 0x87, 0x22, 0x07, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x42, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x42, 0xc1, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa1, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x04, 0x00, 0x2e, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x2b, 0x87, 0x22, 0x40, 0x31, 0x6c, 0x00, 0x00, ++ 0x0c, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x60, 0x18, ++ 0x38, 0x96, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x30, 0x87, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x52, ++ 0x11, 0xc0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x04, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0e, 0xb0, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0xa4, 0x0c, 0xc8, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x15, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x3f, 0x87, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, ++ 0x40, 0x87, 0x68, 0x07, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, ++ 0x1a, 0xb0, 0x01, 0x00, 0x14, 0x99, 0x00, 0x08, 0x98, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x08, 0x3e, 0x96, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, 0x47, 0x87, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x79, 0x87, 0x22, 0x0d, 0x14, 0x6c, 0x00, 0x00, ++ 0x4d, 0x87, 0x22, 0x0d, 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x10, 0xc0, 0x01, 0x00, 0x52, 0x87, 0x00, 0x0d, 0x24, 0xd0, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x2b, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0xa2, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x20, 0x10, 0xc8, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x25, 0x98, 0x01, 0x00, 0x54, 0x87, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x59, 0x87, 0x00, 0x41, 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x55, 0x87, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, 0x78, 0x87, 0xa2, 0x0d, ++ 0x0e, 0x50, 0x00, 0x00, 0x65, 0x87, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x63, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x60, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, ++ 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x0e, 0x30, 0x00, 0x00, 0x6b, 0x87, 0xa2, 0x5f, ++ 0x0f, 0x7c, 0x00, 0x00, 0x39, 0x87, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x5f, 0x0f, 0x80, 0x01, 0x00, 0x39, 0x87, 0x23, 0x07, ++ 0x14, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x75, 0x87, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0x39, 0x87, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, 0x39, 0x87, 0x00, 0x0d, ++ 0x18, 0xc0, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x83, 0x87, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x10, 0x48, 0xc1, 0x01, 0x00, 0x83, 0x87, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x80, 0x87, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x17, 0x10, 0xb0, 0x01, 0x00, 0x85, 0x87, 0x00, 0x40, ++ 0x2b, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x04, 0xe0, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa0, 0x9f, 0x13, 0x6c, 0x00, 0x00, ++ 0x8c, 0x87, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x88, ++ 0x1c, 0xcc, 0x01, 0x00, 0x27, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x8d, 0x98, 0x00, 0x41, 0x3f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x78, 0x98, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x03, 0x88, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x00, 0x0e, 0xf4, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x84, 0x01, 0x00, ++ 0x98, 0x87, 0x22, 0x50, 0x01, 0x6c, 0x00, 0x00, 0x0d, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0x12, 0x95, 0x00, 0x07, ++ 0x16, 0x30, 0x01, 0x00, 0xa3, 0x87, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, ++ 0x9e, 0x87, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xa2, 0x87, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x0f, 0x80, 0x01, 0x00, 0x0e, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0xed, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0xb0, 0x87, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x0b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x6a, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb0, 0x87, 0x22, 0x20, 0x85, 0x6c, 0x00, 0x00, ++ 0xad, 0x87, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x87, 0x95, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, ++ 0xc2, 0x97, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xb0, 0x01, 0x00, ++ 0xa1, 0x88, 0xa2, 0x5f, 0x81, 0x6c, 0x00, 0x00, 0xa8, 0x00, 0x2d, 0x43, ++ 0x19, 0x80, 0x01, 0x00, 0x37, 0x00, 0x2d, 0xf0, 0x24, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x8e, 0xf4, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, ++ 0x90, 0x88, 0x01, 0x00, 0x04, 0x00, 0xa3, 0x43, 0x8f, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0xa3, 0x43, 0x91, 0x6c, 0x00, 0x00, 0xc1, 0x87, 0x22, 0x48, ++ 0x8e, 0x6c, 0x00, 0x00, 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0xc1, 0x87, 0x1f, 0xf0, ++ 0x24, 0x6c, 0x00, 0x00, 0xc0, 0x87, 0x23, 0x41, 0x8f, 0x6c, 0x00, 0x00, ++ 0xa1, 0x88, 0x00, 0x47, 0x81, 0xb0, 0x00, 0x00, 0xa1, 0x88, 0x00, 0x48, ++ 0x81, 0xb0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xb0, 0x00, 0x2d, 0xf0, 0x14, 0xb0, 0x01, 0x00, 0xc6, 0x87, 0x22, 0x0a, ++ 0x90, 0x40, 0x00, 0x00, 0x58, 0x98, 0x00, 0x40, 0x91, 0x30, 0x01, 0x00, ++ 0xa1, 0x88, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0xb0, 0x00, 0x2d, 0x45, ++ 0x81, 0xb0, 0x01, 0x00, 0xd2, 0x87, 0x22, 0xf0, 0x2c, 0x30, 0x00, 0x00, ++ 0xa3, 0x00, 0x2d, 0x30, 0x83, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x2d, 0xf3, ++ 0x82, 0xe0, 0x01, 0x00, 0xcc, 0x87, 0xa3, 0x41, 0x2c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x82, 0xb0, 0x01, 0x00, 0x98, 0x00, 0x2d, 0xf0, ++ 0x82, 0xc0, 0x01, 0x00, 0x88, 0x00, 0x2d, 0xf0, 0x82, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x98, 0xe8, 0x01, 0x00, 0xa1, 0x88, 0x20, 0x4c, ++ 0x82, 0x6c, 0x00, 0x00, 0x7c, 0x00, 0x2d, 0x41, 0x98, 0xe8, 0x01, 0x00, ++ 0xa1, 0x88, 0x20, 0xf0, 0x98, 0x6c, 0x00, 0x00, 0xed, 0x87, 0x22, 0x0a, ++ 0x80, 0x32, 0x00, 0x00, 0x40, 0x02, 0x00, 0x0c, 0x7e, 0x89, 0x01, 0x00, ++ 0xed, 0x87, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xa1, 0x88, 0x00, 0x49, ++ 0x81, 0xb0, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, ++ 0xda, 0x87, 0x22, 0x43, 0x21, 0x6f, 0x00, 0x00, 0x13, 0x80, 0x00, 0x40, ++ 0x80, 0xdc, 0x01, 0x00, 0xdb, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x1a, 0x80, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, 0xdb, 0x87, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0xb1, 0x01, 0x00, ++ 0xdd, 0x87, 0x9f, 0x85, 0x80, 0x32, 0x00, 0x00, 0xe1, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x1a, 0x83, 0x22, 0x40, 0x57, 0x7d, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x40, 0x57, 0x99, 0x01, 0x00, 0xe1, 0x87, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x01, 0x83, 0x1a, 0x5b, 0x69, 0x93, 0x00, 0x00, 0xe7, 0x87, 0x22, 0x46, ++ 0xf3, 0x7f, 0x00, 0x00, 0xe7, 0x87, 0xa2, 0x41, 0xf3, 0x7f, 0x00, 0x00, ++ 0xc6, 0x80, 0x00, 0x42, 0x97, 0x33, 0x01, 0x00, 0x04, 0x00, 0x00, 0xcb, ++ 0x81, 0xc8, 0x01, 0x00, 0xea, 0x87, 0x22, 0x40, 0xf2, 0x7f, 0x00, 0x00, ++ 0xc6, 0x80, 0x00, 0x6f, 0x97, 0x33, 0x01, 0x00, 0xec, 0x87, 0x22, 0x40, ++ 0x73, 0x7d, 0x00, 0x00, 0xe0, 0x80, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, ++ 0xe4, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf4, 0x87, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xf4, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xf1, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x2e, 0x94, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0xf5, 0x87, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x2e, 0x94, 0x1a, 0x02, 0x68, 0x97, 0x00, 0x00, ++ 0xff, 0x87, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xff, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xfc, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x3e, 0x94, 0x22, 0x02, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x88, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0x3e, 0x94, 0x1a, 0x02, ++ 0x68, 0x97, 0x00, 0x00, 0x0a, 0x88, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x0a, 0x88, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x07, 0x88, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x2f, 0x83, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, 0x0b, 0x88, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x02, 0x68, 0x97, 0x01, 0x00, 0x2f, 0x83, 0x00, 0x40, ++ 0x05, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, 0x56, 0xb1, 0x01, 0x00, ++ 0x56, 0x95, 0x2f, 0x40, 0x05, 0xb0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, ++ 0xe7, 0x6d, 0x00, 0x00, 0xb8, 0x94, 0x29, 0x41, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0xef, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x0e, 0xb0, 0x01, 0x00, 0x04, 0x00, 0xa3, 0x0c, 0x55, 0x6f, 0x00, 0x00, ++ 0x29, 0x00, 0x00, 0x40, 0x0d, 0x98, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x12, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x13, 0xc0, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, ++ 0x16, 0x88, 0x01, 0x00, 0xff, 0xff, 0x00, 0x10, 0x34, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0x34, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x23, 0xb0, 0x01, 0x00, 0x20, 0x18, 0x00, 0x40, 0x11, 0x98, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0xaa, 0x0f, 0x6c, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x43, 0x88, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x22, 0x88, 0x60, 0x40, 0x81, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x07, ++ 0x84, 0x89, 0x01, 0x00, 0x2b, 0x88, 0x05, 0xc2, 0x24, 0x30, 0x00, 0x00, ++ 0x58, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x60, 0x88, 0x70, 0xf0, 0x18, 0x30, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x0c, 0x82, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x41, ++ 0x0e, 0x6c, 0x00, 0x00, 0x43, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x70, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x3a, 0x88, 0xa0, 0x48, ++ 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x35, 0xd0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x1a, 0x42, 0xc9, 0x01, 0x00, 0x34, 0x88, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x1a, 0x62, 0xdd, 0x01, 0x00, 0x31, 0x88, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x60, 0x88, 0x00, 0xf8, ++ 0x18, 0x30, 0x01, 0x00, 0x35, 0x88, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x10, 0x34, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x34, 0x94, 0x01, 0x00, 0x20, 0x18, 0x00, 0x40, 0x11, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x1a, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x1a, ++ 0x62, 0xdd, 0x01, 0x00, 0x3e, 0x88, 0xa8, 0x09, 0xe0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x35, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x11, 0xc0, 0x01, 0x00, ++ 0x4f, 0x88, 0x22, 0x41, 0x0d, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xc0, 0x01, 0x00, 0x4b, 0x88, 0xa0, 0xaa, 0x0f, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x0f, 0xb0, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x12, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x13, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1b, 0xb0, 0x01, 0x00, 0x1f, 0x88, 0x00, 0x41, ++ 0x17, 0xb0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09, 0x12, 0xc8, 0x01, 0x00, ++ 0x1f, 0x88, 0x83, 0x41, 0x17, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x17, 0xb0, 0x01, 0x00, 0x1f, 0x88, 0x00, 0x41, 0x1b, 0xc0, 0x00, 0x00, ++ 0x5a, 0x88, 0x23, 0x40, 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x35, 0xd0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x1a, 0x42, 0xc9, 0x01, 0x00, ++ 0x57, 0x88, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x1a, 0x62, 0xdd, 0x01, 0x00, ++ 0x54, 0x88, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x60, 0x88, 0x00, 0xf8, 0x18, 0x30, 0x01, 0x00, 0x58, 0x88, 0xa2, 0x41, ++ 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, ++ 0x5d, 0x88, 0xa0, 0xaa, 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xb0, 0x01, 0x00, 0xb8, 0x94, 0x20, 0x07, 0xe4, 0xb1, 0x01, 0x00, ++ 0x56, 0x95, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, ++ 0x0f, 0xb0, 0x00, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x80, 0xd8, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x0c, ++ 0x7e, 0x89, 0x01, 0x00, 0x79, 0x88, 0x26, 0x54, 0x61, 0x31, 0x00, 0x00, ++ 0x6c, 0x88, 0x87, 0x0c, 0x80, 0x32, 0x00, 0x00, 0x1f, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x0c, 0x8a, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x40, ++ 0x62, 0x99, 0x01, 0x00, 0x6c, 0x88, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, 0x68, 0x88, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x74, 0x88, 0x22, 0x46, 0x19, 0x7c, 0x00, 0x00, ++ 0x2a, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x0c, ++ 0x8a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, ++ 0x0d, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, ++ 0x6d, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x79, 0x88, 0x22, 0x49, ++ 0x19, 0x7c, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x54, ++ 0x77, 0x7d, 0x00, 0x00, 0x74, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, ++ 0x79, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x30, 0x94, 0x2f, 0x55, ++ 0xf1, 0x93, 0x01, 0x00, 0x00, 0x40, 0x00, 0xa6, 0x56, 0xb1, 0x01, 0x00, ++ 0x2f, 0x83, 0xa2, 0x41, 0xe5, 0x51, 0x00, 0x00, 0x64, 0x00, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x81, 0x88, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x84, 0x88, 0xa2, 0x93, 0x57, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x57, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x1c, 0xab, 0x27, 0xb3, 0x01, 0x00, ++ 0x2f, 0x83, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0x2f, 0x83, 0x22, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0x2f, 0x83, 0xa2, 0x41, 0x1d, 0x53, 0x00, 0x00, ++ 0x50, 0x46, 0x00, 0x40, 0x1d, 0x9b, 0x01, 0x00, 0x38, 0x05, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0x90, 0x88, 0x22, 0x40, ++ 0xb5, 0x6f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x41, 0xb5, 0x53, 0x01, 0x00, 0x2f, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xfd, 0x83, 0x01, 0x00, ++ 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x40, 0x05, 0x00, 0x40, ++ 0x49, 0x31, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x91, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0xb5, 0x33, 0x01, 0x00, 0x60, 0x16, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0x55, 0x82, 0x00, 0x40, 0xb5, 0x33, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4a, ++ 0xb4, 0x8b, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4a, ++ 0xb4, 0xf7, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2f, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0xf2, 0x0e, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x02, ++ 0x80, 0x32, 0x00, 0x00, 0x05, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x08, 0xb0, 0x01, 0x00, 0xab, 0x88, 0x22, 0x50, ++ 0x81, 0x6c, 0x00, 0x00, 0x0f, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x8a, 0xe4, 0x01, 0x00, 0x02, 0x99, 0x00, 0x04, ++ 0x8a, 0x14, 0x01, 0x00, 0x04, 0x00, 0x20, 0x48, 0x09, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x20, 0x57, 0x81, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe6, 0xb1, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x04, 0x96, 0xc0, 0x01, 0x00, 0xb1, 0x88, 0x00, 0x4b, ++ 0x10, 0xc9, 0x00, 0x00, 0xe1, 0x8b, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x16, 0x8c, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x52, 0x8c, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x52, 0x8c, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x52, 0x8c, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x52, 0x8c, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x99, 0x8c, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xc8, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xcc, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x3b, 0x8e, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xdc, 0x8c, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xda, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x95, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x95, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x95, 0x8d, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xb5, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xdd, 0x8d, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xdd, 0x8d, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x0c, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x1f, 0x8e, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x1f, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x21, 0x8e, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x21, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x21, 0x8e, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x21, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x2c, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x3e, 0x8e, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x2d, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x3e, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x40, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x34, 0x8e, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, 0x93, 0x8d, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x93, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x93, 0x8d, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x42, 0x8e, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x42, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x42, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x49, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x4b, 0x8e, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x58, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xbe, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xcc, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x3b, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xc6, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xcc, 0x8c, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x3b, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xda, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x93, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xc2, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xcc, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x3b, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x02, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf2, ++ 0x0e, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0x07, 0x00, 0x2d, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x08, 0xb0, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x47, 0x8a, 0xe4, 0x01, 0x00, 0x02, 0x99, 0x00, 0x04, ++ 0x8a, 0x14, 0x01, 0x00, 0x04, 0x00, 0x20, 0x4e, 0x09, 0x6c, 0x00, 0x00, ++ 0x2a, 0x00, 0x00, 0x47, 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0x24, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x06, 0x00, 0x20, 0x47, 0xe6, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x47, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x96, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x96, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x04, 0x96, 0xc0, 0x01, 0x00, 0x7a, 0x89, 0x00, 0x4b, ++ 0x10, 0xc9, 0x00, 0x00, 0xf6, 0x8e, 0x00, 0x49, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2f, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x36, 0x8f, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x47, 0x8f, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x6a, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x64, 0x8f, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x71, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xdc, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xda, 0x8f, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x3a, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x3a, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x3a, 0x8f, 0x00, 0x49, 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, ++ 0x3a, 0x8f, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x4d, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x45, 0x90, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x45, 0x90, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x45, 0x90, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x62, 0x90, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x7a, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x53, 0x90, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x0f, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x6a, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x47, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x64, 0x8f, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xdc, 0x8f, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x71, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x62, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xda, 0x8f, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x81, 0x90, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x81, 0x90, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0xc6, 0x8b, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xc6, 0x8b, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x81, 0x90, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x3a, 0x8f, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0xac, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x8f, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x8f, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x8f, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xac, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x62, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x8f, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xbb, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xbb, 0x90, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x91, 0x00, 0x40, ++ 0x09, 0xb0, 0x00, 0x00, 0x4e, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x40, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x87, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x87, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x4e, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x57, 0x91, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x57, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x40, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x87, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x87, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x40, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x45, 0x90, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x45, 0x90, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x45, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x62, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x45, 0x90, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x45, 0x90, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xab, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x9d, 0x90, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x8e, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x8e, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0xab, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xc6, 0x8b, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xc6, 0x8b, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x9d, 0x90, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x8e, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x8e, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x9d, 0x90, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x5a, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x5a, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x5a, 0x91, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x5a, 0x91, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x77, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x7a, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x77, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x96, 0x92, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x7a, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x96, 0x92, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x96, 0x92, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xbf, 0x92, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xbd, 0x92, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xbf, 0x92, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x62, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xbd, 0x92, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x67, 0x91, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x74, 0x91, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x74, 0x91, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x74, 0x91, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x74, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x74, 0x91, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x74, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x74, 0x91, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x74, 0x91, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x74, 0x91, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x62, 0x90, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x7a, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x53, 0x90, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x7d, 0x93, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x93, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x93, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x93, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x93, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x93, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x62, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x93, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x53, 0x90, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x0f, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x53, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x7a, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x0f, 0x93, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x0f, 0x93, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x16, 0x93, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x7a, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x6e, 0x93, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x16, 0x93, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x93, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xfd, 0x92, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2c, 0x93, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xfd, 0x92, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x44, 0x93, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x7a, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x44, 0x93, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x44, 0x93, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x47, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x6a, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x67, 0x93, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x6a, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x47, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x67, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x6e, 0x93, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x7a, 0x90, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x6e, 0x93, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x10, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x10, 0x93, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x7a, 0x90, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x10, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x10, 0x93, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x77, 0x93, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xfd, 0x92, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x77, 0x93, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x62, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xfd, 0x92, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x71, 0x8f, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x71, 0x8f, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x62, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x07, 0x80, 0x32, 0x00, 0x00, 0x07, 0x00, 0x2e, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0xf8, 0x87, 0x00, 0x04, 0xe6, 0xb1, 0x00, 0x00, ++ 0xc6, 0x8b, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x09, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc6, 0x8b, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0x6d, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd8, 0x8b, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xd8, 0x8b, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xd5, 0x8b, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x1a, 0x85, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0xd9, 0x8b, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x68, 0x97, 0x01, 0x00, ++ 0x1a, 0x85, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x22, 0x07, 0x80, 0x32, 0x00, 0x00, ++ 0x05, 0x00, 0x2e, 0x4b, 0x19, 0x90, 0x01, 0x00, 0xf8, 0x87, 0x00, 0x04, ++ 0xe6, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0xa1, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0xe0, 0xb1, 0x01, 0x00, 0x78, 0x98, 0x00, 0x06, ++ 0x07, 0x40, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0x07, 0xd0, 0x01, 0x00, 0xd4, 0x00, 0x2e, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0xb1, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0x96, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0x96, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x96, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x96, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x96, 0xc0, 0x01, 0x00, 0x00, 0x30, 0x00, 0x4b, ++ 0x94, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x95, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x96, 0xc0, 0x01, 0x00, 0x5e, 0x01, 0x2e, 0x34, ++ 0x97, 0x84, 0x01, 0x00, 0x02, 0x00, 0x00, 0x4b, 0xe4, 0xe5, 0x01, 0x00, ++ 0x64, 0x01, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x86, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x2e, 0xa7, 0x87, 0xc0, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x58, 0x01, 0x00, 0x43, 0xf0, 0xc9, 0x01, 0x00, ++ 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x05, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x08, 0x00, 0x2e, 0x40, 0x95, 0xb0, 0x01, 0x00, 0x0d, 0x8c, 0x20, 0x4b, ++ 0x94, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x0a, 0x8c, 0x00, 0x41, 0x95, 0xc0, 0x00, 0x00, 0x10, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x14, 0x8c, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x10, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x09, 0x97, 0x00, 0x40, 0x81, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x88, 0xb0, 0x01, 0x00, 0x14, 0x80, 0x00, 0x03, ++ 0x98, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xa1, 0x98, 0x6c, 0x00, 0x00, ++ 0x1b, 0x8c, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, 0x1e, 0x8c, 0xa2, 0x4c, ++ 0xfd, 0x7f, 0x00, 0x00, 0x1f, 0x8c, 0x00, 0x4c, 0xfd, 0x93, 0x00, 0x00, ++ 0x20, 0x8c, 0x20, 0xf0, 0x56, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x56, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x64, 0x00, 0x00, 0x40, ++ 0x80, 0xcc, 0x01, 0x00, 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xd8, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x43, ++ 0x81, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x70, 0x00, 0x00, 0x05, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x2b, 0x8c, 0xa8, 0x44, 0xe0, 0x31, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x8c, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x46, ++ 0x44, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x68, 0x01, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x64, 0x00, 0x00, 0x43, ++ 0xf0, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x24, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x62, 0xb1, 0x01, 0x00, 0x34, 0x8c, 0xa8, 0x44, 0xe0, 0x31, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x86, 0xe4, 0x01, 0x00, 0x38, 0x00, 0x2e, 0xa7, 0x87, 0xc0, 0x01, 0x00, ++ 0x8b, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x3c, 0x8c, 0x22, 0x43, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, ++ 0x3f, 0x8c, 0x22, 0x44, 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x45, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x19, 0x90, 0x01, 0x00, ++ 0x68, 0x01, 0x20, 0xa2, 0xe4, 0xb1, 0x01, 0x00, 0x88, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x43, 0x8c, 0x23, 0x0b, 0xe5, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x19, 0x90, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x50, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x58, 0x01, 0x00, 0x43, 0xf0, 0xc9, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x48, 0x8c, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x5c, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x96, 0xb0, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf2, ++ 0x80, 0x32, 0x00, 0x00, 0x09, 0x97, 0x00, 0x41, 0x81, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x55, 0x8c, 0xa2, 0x49, ++ 0x19, 0x7c, 0x00, 0x00, 0x86, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x59, 0x8c, 0x00, 0x40, 0xe5, 0xb1, 0x00, 0x00, 0x86, 0x00, 0x2f, 0x49, ++ 0x19, 0x80, 0x01, 0x00, 0x59, 0x8c, 0xa2, 0xf2, 0x80, 0x32, 0x00, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xe7, 0x91, 0x01, 0x00, 0x5c, 0x8c, 0xa2, 0x46, 0x19, 0x7c, 0x00, 0x00, ++ 0xa0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x60, 0x8c, 0x00, 0x40, ++ 0xe5, 0xb1, 0x00, 0x00, 0xa0, 0x00, 0x2f, 0x46, 0x19, 0x80, 0x01, 0x00, ++ 0x60, 0x8c, 0xa2, 0xf2, 0x80, 0x32, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xe7, 0x91, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x4e, 0x80, 0xe4, 0x01, 0x00, 0x00, 0x39, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x40, 0x06, 0x6c, 0x00, 0x00, ++ 0xa8, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x34, 0x00, 0x2d, 0xf0, ++ 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x0c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0x12, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, 0x16, 0x88, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x14, 0xf4, 0x01, 0x00, 0x90, 0x8c, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x76, 0x8c, 0x22, 0x0a, 0x16, 0x6c, 0x00, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x84, 0x30, 0x00, 0x00, ++ 0x15, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x13, 0xc0, 0x01, 0x00, 0x75, 0x8c, 0xa0, 0x43, ++ 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x13, 0xb0, 0x01, 0x00, ++ 0x6b, 0x8c, 0x00, 0x41, 0x15, 0xd0, 0x00, 0x00, 0x90, 0x8c, 0x22, 0x0a, ++ 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x08, 0x12, 0x6c, 0x00, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x84, 0x30, 0x00, 0x00, ++ 0x15, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x90, 0x8c, 0x22, 0x41, ++ 0x15, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x11, 0xc0, 0x01, 0x00, ++ 0x83, 0x8c, 0xa0, 0x43, 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x11, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x06, 0x10, 0x6c, 0x00, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x11, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x36, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x00, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x83, 0xb0, 0x01, 0x00, 0x4e, 0x97, 0x00, 0x47, ++ 0x61, 0x31, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x2b, 0x94, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x8c, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x7f, 0x8c, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x37, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x80, 0x97, 0x00, 0x51, ++ 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf3, ++ 0x80, 0x32, 0x00, 0x00, 0x34, 0x00, 0x2e, 0x41, 0xf5, 0xb1, 0x01, 0x00, ++ 0x00, 0x11, 0x00, 0x40, 0xe5, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x48, ++ 0x19, 0x7c, 0x00, 0x00, 0x9d, 0x8c, 0x00, 0x48, 0x19, 0x90, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf3, ++ 0x80, 0x32, 0x00, 0x00, 0x34, 0x00, 0x2e, 0x41, 0xf5, 0xb1, 0x01, 0x00, ++ 0x00, 0x11, 0x00, 0x40, 0xe5, 0x99, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, ++ 0xa4, 0x8c, 0x22, 0x45, 0x23, 0x7c, 0x00, 0x00, 0xb0, 0x00, 0x2f, 0xf0, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x8c, 0xc0, 0x01, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa3, 0xf0, ++ 0x8c, 0x6c, 0x00, 0x00, 0x90, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x35, 0x00, 0x2d, 0xf0, 0x8c, 0xb0, 0x01, 0x00, 0x34, 0x00, 0x2d, 0xf3, ++ 0x84, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf3, 0x84, 0x6c, 0x00, 0x00, ++ 0x58, 0x00, 0x3e, 0x43, 0x85, 0xe0, 0x01, 0x00, 0xab, 0x8c, 0x22, 0x48, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8d, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x0a, 0x8c, 0xc0, 0x01, 0x00, 0x38, 0x00, 0x2a, 0x4a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0x3c, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x38, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x26, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf8, ++ 0x02, 0x30, 0x00, 0x00, 0xb9, 0x8c, 0x23, 0x01, 0x14, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x4c, 0x00, 0x20, 0xf0, 0xe4, 0xb1, 0x01, 0x00, ++ 0x44, 0x00, 0x20, 0x40, 0xe0, 0xb1, 0x01, 0x00, 0x48, 0x00, 0x20, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x58, 0x98, 0x00, 0xf0, 0x24, 0x30, 0x01, 0x00, 0xc2, 0x8c, 0xa2, 0x44, ++ 0x81, 0x6c, 0x00, 0x00, 0xc0, 0x8c, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xb6, 0x95, 0x00, 0x40, 0x3b, 0x30, 0x01, 0x00, 0xea, 0x8c, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0xc2, 0x8c, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb9, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xea, 0x8c, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0x50, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x20, 0x01, ++ 0xe4, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, ++ 0x80, 0x97, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x8f, 0x95, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, 0x9d, 0x8c, 0x22, 0x4a, ++ 0x80, 0x32, 0x00, 0x00, 0xce, 0x8c, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x8f, 0x95, 0x00, 0xf3, ++ 0x94, 0x30, 0x01, 0x00, 0x04, 0x00, 0x20, 0x43, 0x97, 0x6c, 0x00, 0x00, ++ 0x58, 0x00, 0x3e, 0x43, 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0xf0, 0xb1, 0x01, 0x00, 0x1f, 0x00, 0x60, 0x00, 0x00, 0x8c, 0x01, 0x00, ++ 0xdd, 0x8b, 0x85, 0x11, 0x80, 0x32, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0xf0, 0x8c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xf0, 0x8c, 0xc0, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa3, 0xf0, 0x8c, 0x6c, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x22, 0x49, 0x19, 0x7c, 0x00, 0x00, ++ 0xdc, 0x8c, 0x00, 0x49, 0x19, 0x80, 0x00, 0x00, 0xe1, 0x8c, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xb6, 0x95, 0x00, 0x40, 0x3b, 0x30, 0x01, 0x00, ++ 0xe5, 0x8c, 0xa2, 0x08, 0x3c, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x5f, ++ 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb9, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xe5, 0x8c, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x50, 0x00, 0x2d, 0x10, ++ 0x32, 0xb0, 0x01, 0x00, 0x54, 0x00, 0x2d, 0xf0, 0x38, 0xb0, 0x01, 0x00, ++ 0x4e, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, 0x40, 0x00, 0x2d, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x14, 0xb0, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x8c, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x46, ++ 0x44, 0xc9, 0x01, 0x00, 0x68, 0x01, 0x2d, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x68, 0xf2, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x37, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x36, 0xd0, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0x40, 0x10, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x81, 0xd0, 0x01, 0x00, 0x12, 0x97, 0x00, 0x40, 0xe4, 0x31, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x46, 0x62, 0xdd, 0x01, 0x00, 0xf6, 0x8c, 0xa8, 0x40, ++ 0x23, 0x30, 0x00, 0x00, 0x08, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x10, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x8d, 0x82, 0x41, ++ 0x23, 0x40, 0x00, 0x00, 0x20, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x01, 0x8d, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xfe, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, 0x44, 0xc9, 0x01, 0x00, ++ 0x0c, 0x8d, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x08, 0x8d, 0xa3, 0x01, ++ 0x0c, 0x6c, 0x00, 0x00, 0x09, 0x8d, 0x00, 0x06, 0x04, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x04, 0xb0, 0x01, 0x00, 0x0b, 0x8d, 0x20, 0x02, ++ 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x04, 0xb0, 0x01, 0x00, ++ 0x0f, 0x8d, 0x00, 0x02, 0xe0, 0xb1, 0x00, 0x00, 0x0e, 0x8d, 0xa3, 0x01, ++ 0x0c, 0x6c, 0x00, 0x00, 0x0f, 0x8d, 0x00, 0x06, 0x04, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x04, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x02, ++ 0x16, 0x94, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x16, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x08, 0x3e, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, 0x14, 0x8d, 0xa8, 0x13, ++ 0xe0, 0x31, 0x00, 0x00, 0x51, 0x8d, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0x44, 0x00, 0x2d, 0x02, 0x0c, 0xd0, 0x01, 0x00, 0x3c, 0x8d, 0xa2, 0x02, ++ 0x02, 0x50, 0x00, 0x00, 0x22, 0x8d, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x21, 0x8d, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x1d, 0x8d, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x44, 0x00, 0x2d, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x48, 0x00, 0x2d, 0xf0, 0x38, 0xb0, 0x01, 0x00, ++ 0x4c, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, 0x38, 0x00, 0x2f, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x3e, 0x8d, 0x22, 0x01, 0x14, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0xa4, 0x40, 0x81, 0x32, 0x00, 0x00, 0x30, 0x8d, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, ++ 0x20, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x2f, 0x8d, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x2c, 0x8d, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x38, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x94, 0xb0, 0x01, 0x00, 0x38, 0x00, 0x2d, 0xf0, 0x96, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0xe1, 0xc1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x22, 0x4a, 0xf1, 0xb1, 0x01, 0x00, ++ 0x44, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x39, 0x8d, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, ++ 0x3e, 0x8d, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x38, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x24, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x4c, 0x8d, 0x22, 0x06, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x33, 0xc0, 0x01, 0x00, 0x4a, 0x8d, 0xa2, 0x02, 0x36, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x8f, 0x0d, ++ 0x42, 0x31, 0x00, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x5c, 0xe1, 0x7d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0xf0, ++ 0x6a, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0xf8, 0x10, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x11, 0x80, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x37, 0x98, 0x01, 0x00, 0xfa, 0x8c, 0x00, 0xa1, 0x1a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, 0xfa, 0x8c, 0x00, 0x02, ++ 0x36, 0xd0, 0x00, 0x00, 0x50, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x20, 0x01, ++ 0xe4, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, ++ 0x58, 0x8d, 0x00, 0x5f, 0x01, 0xb0, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x02, ++ 0x02, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x02, 0x0c, 0x6c, 0x00, 0x00, ++ 0x37, 0x00, 0x2d, 0x46, 0x01, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, ++ 0x80, 0xf4, 0x01, 0x00, 0x57, 0x8d, 0xa0, 0x43, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x01, 0xb0, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, ++ 0x5e, 0x8d, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x5b, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x0d, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x65, 0x8d, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x62, 0x8d, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x60, 0x01, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, ++ 0x6a, 0x8d, 0x90, 0xf2, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, ++ 0x32, 0x00, 0x00, 0xa6, 0x2a, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x2a, 0x94, 0x01, 0x00, 0x6d, 0x8d, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0xd0, 0x00, 0x1e, 0x62, 0xdd, 0x01, 0x00, 0x72, 0x8d, 0x28, 0x40, ++ 0x05, 0x30, 0x00, 0x00, 0x6e, 0x8d, 0x22, 0x48, 0x77, 0x7d, 0x00, 0x00, ++ 0x75, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x62, 0xb1, 0x01, 0x00, 0x80, 0x8d, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x72, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, ++ 0x92, 0xb0, 0x01, 0x00, 0x7d, 0x8d, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x40, 0x3b, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa3, 0x48, ++ 0x3b, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0xc3, 0x94, 0x00, 0xf8, 0x00, 0x30, 0x01, 0x00, 0x7a, 0x8d, 0xa2, 0x41, ++ 0x3b, 0x50, 0x00, 0x00, 0x81, 0x8d, 0x00, 0x49, 0x00, 0xb0, 0x00, 0x00, ++ 0xff, 0x07, 0x00, 0x1e, 0x00, 0x8c, 0x01, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x81, 0x8d, 0x00, 0x49, 0x00, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x1d, 0x47, 0x19, 0x80, 0x01, 0x00, 0x84, 0x8d, 0x22, 0x5f, ++ 0x01, 0x6c, 0x00, 0x00, 0x87, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xa7, 0x88, 0x00, 0x00, 0x80, 0xb0, 0x00, 0x00, 0x8b, 0x8d, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x8b, 0x8d, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x88, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x8b, 0x8d, 0x40, 0x05, 0x48, 0x31, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x07, 0x94, 0x89, 0x01, 0x00, 0x91, 0x8d, 0x85, 0xca, ++ 0x94, 0x30, 0x00, 0x00, 0x87, 0x98, 0x18, 0x5c, 0x1f, 0x00, 0x01, 0x00, ++ 0x0e, 0x00, 0x00, 0x0f, 0x1e, 0x8c, 0x01, 0x00, 0xb4, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x80, 0x97, 0x18, 0x00, 0x80, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x47, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x19, 0x80, 0x01, 0x00, 0xdd, 0x8b, 0x22, 0x47, 0x19, 0x7c, 0x00, 0x00, ++ 0xb9, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x98, 0x8d, 0xa2, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x12, 0x97, 0x00, 0x40, 0x0d, 0x30, 0x01, 0x00, 0x9c, 0x01, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x98, 0x88, 0x01, 0x00, ++ 0x8b, 0x00, 0x2d, 0x50, 0x17, 0xf0, 0x01, 0x00, 0x9e, 0x8d, 0x90, 0x4c, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0xa0, 0x8d, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x45, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, ++ 0x68, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0xf2, ++ 0x80, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x62, 0x40, 0x7e, 0xcd, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x57, 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, 0xf0, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0xaa, 0x8d, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0xae, 0x8d, 0x45, 0x48, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x50, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, ++ 0xb4, 0x8d, 0x28, 0x40, 0x05, 0x30, 0x00, 0x00, 0xaf, 0x8d, 0x22, 0x48, ++ 0x77, 0x7d, 0x00, 0x00, 0xc3, 0x94, 0x1d, 0x08, 0x00, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xdd, 0x8b, 0x1d, 0x47, ++ 0x19, 0x80, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x35, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x84, 0xc8, 0x01, 0x00, 0xba, 0x8d, 0xa0, 0x43, 0x85, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, 0xa8, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x37, 0x00, 0x2f, 0xf0, 0x24, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf3, 0x9e, 0x06, 0x00, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x82, 0xcc, 0x01, 0x00, 0xc8, 0x8d, 0xa2, 0x41, 0x9e, 0x06, 0x00, 0x00, ++ 0xdd, 0x8b, 0x22, 0x44, 0x83, 0x70, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, 0x24, 0x6c, 0x00, 0x00, ++ 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x58, 0x00, 0x3d, 0x43, ++ 0xe7, 0xe1, 0x01, 0x00, 0xdd, 0x8b, 0x1f, 0xf0, 0x24, 0x6c, 0x00, 0x00, ++ 0x87, 0x98, 0x00, 0x48, 0x81, 0x30, 0x01, 0x00, 0xa7, 0x88, 0x23, 0x41, ++ 0x83, 0x6c, 0x00, 0x00, 0xa7, 0x88, 0x00, 0x47, 0x81, 0xb0, 0x00, 0x00, ++ 0x34, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0x22, 0x42, ++ 0xe6, 0x6d, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, 0x85, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x36, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x00, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x00, 0xbe, 0x06, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x4e, 0x97, 0x00, 0x47, 0x61, 0x31, 0x01, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x8e, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, ++ 0x14, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xa5, 0x8c, 0xa2, 0x40, 0x8f, 0x7c, 0x00, 0x00, 0xdb, 0x8d, 0x22, 0x47, ++ 0x8f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x48, 0x19, 0x7c, 0x00, 0x00, ++ 0xa5, 0x8c, 0x00, 0x48, 0x19, 0x90, 0x00, 0x00, 0x04, 0x00, 0x22, 0x46, ++ 0x8f, 0x7c, 0x00, 0x00, 0x5d, 0x8e, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, 0x36, 0x00, 0x2d, 0x5d, ++ 0x05, 0xb4, 0x01, 0x00, 0x37, 0x00, 0x2d, 0xf3, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x8e, 0xb0, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x47, ++ 0x7e, 0x89, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x5c, 0x00, 0x3d, 0x43, 0x81, 0xe0, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x4a, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x24, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x86, 0xdc, 0x01, 0x00, 0x40, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x8c, 0x93, 0x00, 0x4a, 0xf0, 0x31, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x36, 0x00, 0x2f, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0xef, 0x8d, 0xa2, 0x50, 0x8f, 0x50, 0x00, 0x00, 0x34, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf0, 0x00, 0x00, 0x47, 0x7e, 0x89, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x63, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0xf4, 0x8d, 0xa0, 0x43, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x63, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0x37, 0x00, 0x20, 0x47, 0xe6, 0xb1, 0x01, 0x00, ++ 0xdd, 0x8b, 0x22, 0x47, 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x47, ++ 0x0c, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8f, 0x84, 0x01, 0x00, ++ 0x09, 0x8e, 0x22, 0x47, 0x0c, 0x6c, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, ++ 0x81, 0xe0, 0x01, 0x00, 0x09, 0x8e, 0x1f, 0xf0, 0x24, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x02, 0x8e, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xff, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x02, 0x8e, 0x42, 0x40, ++ 0x05, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x5d, 0x69, 0x93, 0x01, 0x00, 0x07, 0x8e, 0x23, 0x41, ++ 0x0d, 0x6c, 0x00, 0x00, 0xdd, 0x8d, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x87, 0x98, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, 0xa7, 0x88, 0x00, 0x48, ++ 0x81, 0xb0, 0x00, 0x00, 0xdd, 0x8b, 0x22, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x40, 0x02, 0x00, 0x0c, 0x7e, 0x89, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x84, 0xb0, 0x01, 0x00, ++ 0xa6, 0x00, 0x2d, 0x49, 0x19, 0x90, 0x01, 0x00, 0x02, 0x00, 0x00, 0xf2, ++ 0x80, 0xf4, 0x01, 0x00, 0xb8, 0x00, 0x2d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x82, 0xf8, 0x01, 0x00, 0x19, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x1a, 0x8e, 0xa0, 0x40, 0x82, 0x6c, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0x1a, 0x8e, 0xa3, 0x40, 0x82, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0xb0, 0x01, 0x00, 0x1c, 0x8e, 0x20, 0x4c, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x85, 0xc0, 0x01, 0x00, ++ 0x86, 0x00, 0x20, 0x40, 0xe4, 0xb1, 0x01, 0x00, 0xa2, 0x00, 0x20, 0x42, ++ 0xe6, 0xb1, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x09, 0x97, 0x00, 0x50, 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x78, 0x98, 0x00, 0x40, 0x87, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0xb0, 0x00, 0x2f, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x80, 0xc0, 0x01, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa3, 0xf0, ++ 0x80, 0x6c, 0x00, 0x00, 0x80, 0x97, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xdd, 0x8b, 0x22, 0x46, 0x19, 0x7c, 0x00, 0x00, ++ 0xa0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0xf2, ++ 0x96, 0xcc, 0x01, 0x00, 0xdd, 0x8b, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x4a, 0x81, 0x30, 0x01, 0x00, 0x55, 0x97, 0x00, 0x46, ++ 0x95, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xdd, 0x8b, 0x22, 0x49, 0x19, 0x7c, 0x00, 0x00, 0x86, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0xf2, 0x80, 0xcc, 0x01, 0x00, ++ 0xdd, 0x8b, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x80, 0x97, 0x00, 0x4a, ++ 0x81, 0x30, 0x01, 0x00, 0x55, 0x97, 0x00, 0x47, 0x95, 0x30, 0x01, 0x00, ++ 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2b, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0xdd, 0x8b, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x46, ++ 0x19, 0x7c, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x49, 0x19, 0x7c, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x62, 0xf2, 0x80, 0xc8, 0x01, 0x00, 0x46, 0x8e, 0x90, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0xff, 0xff, 0x62, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0xa4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xdd, 0x8b, 0x22, 0x40, ++ 0xe5, 0x6d, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x41, 0xe5, 0xc1, 0x00, 0x00, ++ 0x09, 0x97, 0x00, 0x4d, 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x78, 0x98, 0x00, 0x40, 0x87, 0x30, 0x01, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x56, 0x8e, 0x80, 0xf3, ++ 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0x81, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x19, 0x90, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0xdd, 0x8b, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf3, ++ 0x80, 0x32, 0x00, 0x00, 0x34, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x11, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0xb9, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6e, 0x8e, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x51, 0x83, 0xd0, 0x01, 0x00, 0x34, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x84, 0xcc, 0x01, 0x00, ++ 0x66, 0x8e, 0x9f, 0x42, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x63, 0x42, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, 0x68, 0x8e, 0x37, 0x5c, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, ++ 0x69, 0x8e, 0xa8, 0x4b, 0x19, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0xb1, 0x01, 0x00, 0x6b, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xed, 0x87, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, ++ 0xac, 0x00, 0x2d, 0xf0, 0x30, 0xb0, 0x01, 0x00, 0x35, 0x00, 0x2d, 0xf0, ++ 0x28, 0xb0, 0x01, 0x00, 0x34, 0x00, 0x2d, 0xf3, 0x84, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf3, 0x84, 0x6c, 0x00, 0x00, 0x58, 0x00, 0x3e, 0x43, ++ 0x85, 0xe0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x18, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xe0, 0xb1, 0x01, 0x00, 0x38, 0x00, 0x20, 0x00, ++ 0xe0, 0xb1, 0x01, 0x00, 0x3c, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x2b, 0xb0, 0x01, 0x00, 0x64, 0x97, 0x00, 0x40, 0x0d, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x16, 0xc0, 0x01, 0x00, 0x7f, 0x8e, 0xa0, 0x14, ++ 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x0e, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xf8, 0xb1, 0x01, 0x00, 0xb0, 0x00, 0x2d, 0x14, 0xf8, 0xb1, 0x01, 0x00, ++ 0x10, 0x50, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x88, 0x8e, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x43, 0x86, 0xc8, 0x01, 0x00, ++ 0x00, 0x30, 0x00, 0x0b, 0x16, 0xc8, 0x01, 0x00, 0x88, 0x8e, 0xa4, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x01, 0x00, 0x6e, 0x43, 0x86, 0x98, 0x01, 0x00, 0xa8, 0x97, 0x00, 0x30, ++ 0x81, 0x30, 0x01, 0x00, 0x8c, 0x8e, 0xa0, 0x41, 0x17, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x93, 0x8e, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0xcc, 0x00, 0x2d, 0xab, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0x17, 0xc0, 0x01, 0x00, 0x92, 0x8e, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x64, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x41, 0x31, 0xc0, 0x01, 0x00, 0xbc, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x99, 0x8e, 0x06, 0x0c, 0x80, 0x32, 0x00, 0x00, ++ 0xa0, 0x00, 0x20, 0xf2, 0xe4, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x09, 0x46, ++ 0x19, 0x10, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x0b, 0x98, 0x88, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x50, ++ 0x17, 0xf0, 0x01, 0x00, 0x9e, 0x8e, 0x90, 0x4c, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0xa0, 0x8e, 0x22, 0x43, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x68, 0x01, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0xf2, 0x80, 0xb0, 0x01, 0x00, ++ 0x02, 0x00, 0x62, 0x40, 0x7e, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, ++ 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0xf0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0xaa, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xae, 0x8e, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x50, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, 0xaf, 0x8e, 0xa8, 0x40, ++ 0x05, 0x30, 0x00, 0x00, 0x35, 0x00, 0x1d, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x63, 0xf3, 0x84, 0xc8, 0x01, 0x00, 0xb5, 0x8e, 0xa0, 0x43, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf3, ++ 0x9e, 0x06, 0x00, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x41, 0x9e, 0x06, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x45, 0xe7, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0xe7, 0x91, 0x01, 0x00, 0x80, 0x97, 0x00, 0x5f, ++ 0x81, 0x30, 0x01, 0x00, 0xdd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x8f, 0x95, 0x00, 0xf3, ++ 0x94, 0x30, 0x01, 0x00, 0x5d, 0x8e, 0x22, 0x4a, 0x80, 0x32, 0x00, 0x00, ++ 0xce, 0x8c, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x8f, 0x95, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, ++ 0x97, 0x8c, 0x22, 0x4a, 0x80, 0x32, 0x00, 0x00, 0xce, 0x8c, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x12, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, ++ 0x90, 0x88, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x0c, 0xf4, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc8, 0x8c, 0x22, 0x06, ++ 0x90, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x5c, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, ++ 0x37, 0x00, 0x2f, 0xf0, 0x24, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x2a, 0x50, ++ 0xe7, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x63, 0x41, 0x13, 0xc0, 0x01, 0x00, ++ 0xd5, 0x8e, 0xa0, 0x43, 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x89, 0x93, 0x00, 0x10, 0x86, 0x30, 0x01, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xd7, 0x8e, 0x42, 0x05, ++ 0x48, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0xc8, 0x8c, 0x1a, 0x5d, 0x69, 0x93, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x36, 0x00, 0x2d, 0x10, 0x86, 0xb0, 0x01, 0x00, ++ 0x5c, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x4a, 0x80, 0x32, 0x00, 0x00, ++ 0x35, 0x00, 0x2f, 0xf0, 0x24, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x6b, 0xfb, ++ 0x84, 0xc8, 0x01, 0x00, 0xe4, 0x8e, 0xa0, 0x43, 0x85, 0x6c, 0x00, 0x00, ++ 0x35, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x12, 0xc8, 0x01, 0x00, ++ 0xe7, 0x8e, 0xa0, 0x43, 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x40, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x8c, 0x93, 0x00, 0x4a, 0xf0, 0x31, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xea, 0x8e, 0x42, 0x05, 0x48, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x5d, ++ 0x69, 0x93, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf3, 0x9e, 0x06, 0x00, 0x00, 0x11, 0x00, 0x63, 0xf3, ++ 0x82, 0xcc, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x41, 0x80, 0x32, 0x00, 0x00, ++ 0xbf, 0x8d, 0x22, 0x41, 0x9e, 0x06, 0x00, 0x00, 0x35, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x36, 0xb0, 0x01, 0x00, 0xcd, 0x8d, 0x00, 0xf0, ++ 0x00, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xf7, 0x8e, 0x65, 0xf2, 0x12, 0x30, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x13, 0xf0, 0x01, 0x00, 0xfc, 0x8e, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0x27, 0x83, 0x75, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xf6, 0x8e, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xe7, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x75, 0x42, 0x19, 0x90, 0x01, 0x00, 0x75, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xfe, 0x8e, 0xa8, 0xb1, 0x0c, 0x30, 0x00, 0x00, ++ 0xa3, 0x96, 0x00, 0x10, 0x94, 0x30, 0x01, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc0, 0xa8, 0x3d, 0x46, 0x0d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0x08, 0x8f, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x04, 0x00, 0x02, 0x41, 0x97, 0x40, 0x00, 0x00, 0x05, 0x8f, 0x00, 0x50, ++ 0x43, 0xc1, 0x00, 0x00, 0x14, 0x8f, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x62, 0x4b, 0x12, 0x94, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x97, 0xc0, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x94, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x4a, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf1, 0xb1, 0x01, 0x00, ++ 0x5e, 0x01, 0x00, 0x4b, 0xf0, 0xc9, 0x01, 0x00, 0x5e, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x4a, 0x62, 0xdd, 0x01, 0x00, 0x12, 0x8f, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x09, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x97, 0xc0, 0x01, 0x00, ++ 0xd4, 0x00, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x1a, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, ++ 0x1e, 0x8f, 0x65, 0x40, 0x81, 0x32, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x75, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0x62, 0xb1, 0x01, 0x00, 0x22, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x27, 0x8f, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x25, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x97, 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x96, ++ 0x97, 0xb0, 0x01, 0x00, 0x2d, 0x8f, 0x20, 0x09, 0x96, 0x6c, 0x00, 0x00, ++ 0x2d, 0x8f, 0x1f, 0x09, 0x96, 0x24, 0x00, 0x00, 0x27, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x28, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x09, 0x97, 0x00, 0x57, 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x2e, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x34, 0x8f, 0x22, 0xf3, ++ 0x80, 0x32, 0x00, 0x00, 0x09, 0x97, 0x00, 0x42, 0x81, 0x30, 0x01, 0x00, ++ 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x80, 0x97, 0x00, 0x52, ++ 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x42, 0x19, 0x80, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x09, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0x80, 0x97, 0x00, 0x52, 0x81, 0x30, 0x01, 0x00, ++ 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0xff, 0x95, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, ++ 0xc6, 0x8b, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, 0x24, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x42, 0x8f, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x9f, 0x95, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, ++ 0xa6, 0x95, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0xed, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x25, 0x98, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, ++ 0x4e, 0x8f, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x4e, 0x8f, 0xa2, 0x16, ++ 0x80, 0x32, 0x00, 0x00, 0xed, 0x87, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x19, 0x90, 0x01, 0x00, 0x09, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x23, 0x00, 0xa6, 0x16, 0xb0, 0x01, 0x00, 0x51, 0x8f, 0x83, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x16, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xc0, 0x01, 0x00, 0x58, 0x97, 0x00, 0x08, ++ 0x80, 0x30, 0x01, 0x00, 0x55, 0x8f, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, ++ 0x79, 0x97, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0x98, 0x93, 0x00, 0x40, ++ 0x8d, 0x30, 0x01, 0x00, 0x60, 0x97, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x5d, 0x8f, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x5a, 0x8f, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x61, 0x8f, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, 0xcd, 0x8b, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x36, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x1f, 0x90, 0x01, 0x00, ++ 0x69, 0x8f, 0x22, 0x43, 0x3d, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3d, 0x80, 0x01, 0x00, ++ 0x6a, 0x8f, 0x00, 0x42, 0x19, 0x90, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4f, ++ 0x2b, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0x14, 0x00, 0x2d, 0x45, 0x1f, 0x90, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, ++ 0x14, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa0, 0x01, 0x14, 0x6c, 0x00, 0x00, ++ 0xdc, 0x8f, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, 0xdc, 0x8f, 0x00, 0x44, ++ 0x19, 0x90, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x47, 0xe7, 0x7d, 0x00, 0x00, 0xae, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x84, 0x8f, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x84, 0x8f, 0xa2, 0x16, 0x80, 0x32, 0x00, 0x00, 0x80, 0x8f, 0xa2, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, ++ 0xa0, 0x98, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x30, 0x05, 0x00, 0x41, ++ 0x89, 0x30, 0x01, 0x00, 0x7d, 0x8f, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x9f, 0x95, 0x00, 0x15, 0x94, 0x30, 0x01, 0x00, ++ 0xa6, 0x95, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0xed, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x36, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x19, 0x90, 0x01, 0x00, 0x09, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x87, 0x8f, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x36, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x88, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xff, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc0, 0x8f, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x15, 0x98, 0xc8, 0x01, 0x00, ++ 0xc0, 0x8f, 0xa0, 0x0b, 0x99, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x7e, 0x89, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x44, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, 0x93, 0x8f, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x15, ++ 0x98, 0xc8, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x0b, 0x99, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x6a, 0x50, 0x99, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x20, 0x0b, ++ 0x99, 0x6c, 0x00, 0x00, 0xc0, 0x00, 0x62, 0x01, 0x80, 0xcc, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x2d, 0x00, 0x2d, 0xf0, ++ 0x22, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x23, 0x80, 0x01, 0x00, 0xd4, 0x00, 0x3f, 0x41, ++ 0xe7, 0xe1, 0x01, 0x00, 0x04, 0x00, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x0b, 0x00, 0x00, 0xf2, 0x98, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, ++ 0x99, 0x80, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x00, 0x98, 0x6c, 0x00, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x11, ++ 0x8a, 0x30, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x11, 0xe4, 0xf5, 0x01, 0x00, ++ 0x2f, 0x00, 0x20, 0x47, 0xe7, 0xb5, 0x01, 0x00, 0xab, 0x8f, 0x23, 0x0b, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0xe5, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x80, 0xb0, 0x01, 0x00, 0xc1, 0x00, 0x00, 0x01, ++ 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0xa4, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x02, 0xd0, 0x01, 0x00, 0x58, 0x97, 0x00, 0x00, 0x2a, 0x40, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xb2, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x05, ++ 0x48, 0x31, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x80, 0xce, 0x01, 0x00, ++ 0xbe, 0x8f, 0x26, 0x11, 0x00, 0x30, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, ++ 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x80, 0xc0, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, ++ 0x99, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0xd0, 0x01, 0x00, ++ 0x58, 0x97, 0x00, 0x4c, 0x02, 0x30, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, ++ 0x03, 0x98, 0x01, 0x00, 0xc8, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x30, 0x00, 0x2f, 0x08, 0x80, 0xb0, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x15, ++ 0xf4, 0xc9, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x01, 0xe4, 0xcd, 0x01, 0x00, ++ 0xc1, 0x00, 0x00, 0x01, 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0xa4, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0x20, 0x0b, 0xe5, 0x6d, 0x00, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x03, 0x98, 0x01, 0x00, 0x58, 0x97, 0x00, 0x00, ++ 0x2a, 0x40, 0x01, 0x00, 0xcd, 0x8f, 0x22, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0xac, 0x00, 0x2f, 0x40, 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xe0, 0xc1, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xce, 0x8f, 0x00, 0x01, 0xe0, 0xd1, 0x00, 0x00, 0x98, 0x93, 0x00, 0x40, ++ 0x8d, 0x30, 0x01, 0x00, 0x80, 0x63, 0x00, 0xa6, 0x16, 0xb0, 0x01, 0x00, ++ 0x60, 0x97, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xd6, 0x8f, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xd3, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xfa, 0x96, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0xd9, 0x8f, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, ++ 0xdc, 0x8f, 0x00, 0x4a, 0x1f, 0x90, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4f, ++ 0x2b, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x10, 0xb0, 0x01, 0x00, 0x24, 0x00, 0x2d, 0x15, 0x10, 0xc0, 0x01, 0x00, ++ 0x28, 0x00, 0x2d, 0xf0, 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x2d, 0xf0, ++ 0x26, 0xb0, 0x01, 0x00, 0x14, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x32, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x1f, 0x15, 0x1a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2a, 0xb0, 0x01, 0x00, ++ 0xb8, 0x96, 0x00, 0x40, 0x35, 0xb0, 0x00, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x26, 0x90, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, 0x24, 0x00, 0x20, 0x0b, ++ 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, ++ 0x22, 0x00, 0x20, 0x06, 0xe4, 0xb1, 0x01, 0x00, 0xfa, 0x8f, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xfa, 0x8f, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xf6, 0x8f, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x14, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, 0x14, 0x6c, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, 0x1f, 0x90, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x0d, 0x90, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x6d, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x54, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x1a, 0x90, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x03, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x09, 0x90, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xe1, 0x94, 0x00, 0x40, 0x11, 0x30, 0x01, 0x00, ++ 0x0a, 0x90, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0c, 0x90, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x83, 0x00, 0x40, ++ 0x05, 0xb0, 0x00, 0x00, 0x6d, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x49, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x10, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x16, 0x90, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xe1, 0x94, 0x00, 0x40, 0x11, 0x30, 0x01, 0x00, 0x17, 0x90, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x19, 0x90, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x2f, 0x83, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x1b, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x22, 0x90, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xe1, 0x94, 0x00, 0x40, 0x11, 0x30, 0x01, 0x00, 0x23, 0x90, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x25, 0x90, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xcd, 0x8b, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, ++ 0x14, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, ++ 0x2f, 0x90, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x2b, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, 0x33, 0x90, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xe1, 0x94, 0x00, 0x40, 0x11, 0x30, 0x01, 0x00, ++ 0x34, 0x90, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x2d, 0x0a, 0x84, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x14, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x3a, 0x90, 0x03, 0x1e, 0x80, 0x32, 0x00, 0x00, 0x3b, 0x90, 0x00, 0x41, ++ 0x87, 0xb0, 0x00, 0x00, 0x21, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x26, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x40, 0x90, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x43, 0x90, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x80, 0x01, 0x00, 0xc6, 0x8b, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, ++ 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0xba, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0x4b, 0x90, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x2f, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xce, 0x97, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xc4, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x05, 0x98, 0x00, 0xf0, ++ 0x84, 0x30, 0x01, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xcd, 0x8b, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2e, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x57, 0x90, 0x22, 0x40, ++ 0xe7, 0x6d, 0x00, 0x00, 0x32, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x62, 0x90, 0xa2, 0x40, 0xe5, 0x6d, 0x00, 0x00, 0xec, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x24, 0x00, 0x20, 0x0b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x28, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x20, 0x06, ++ 0xe4, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, ++ 0x80, 0x32, 0x00, 0x00, 0x14, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, ++ 0xcd, 0x8b, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xec, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x97, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x70, 0x90, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x99, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x15, ++ 0x98, 0x50, 0x00, 0x00, 0x70, 0x90, 0x20, 0x01, 0x98, 0x6c, 0x00, 0x00, ++ 0x70, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x6d, 0x90, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xac, 0x00, 0x2f, 0x00, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xc1, 0x01, 0x00, 0x14, 0x00, 0x2f, 0x15, ++ 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0x01, ++ 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x19, 0x90, 0x01, 0x00, ++ 0xe6, 0x8f, 0x22, 0x09, 0x80, 0x32, 0x00, 0x00, 0x80, 0x97, 0x00, 0x09, ++ 0x80, 0x30, 0x01, 0x00, 0xe6, 0x8f, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x43, 0xc1, 0x01, 0x00, 0x26, 0x96, 0x00, 0xf0, ++ 0x84, 0x30, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0xc6, 0x8b, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x2c, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x2e, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf3, ++ 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0xc6, 0x8b, 0x00, 0x42, 0x19, 0x80, 0x00, 0x00, 0x16, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x55, 0x97, 0x00, 0x48, 0x95, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x8a, 0x90, 0xa8, 0x40, 0x13, 0x30, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x90, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x8f, 0x90, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x14, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0xf0, ++ 0x84, 0x30, 0x00, 0x00, 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x26, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0xad, 0x90, 0x00, 0x09, 0x00, 0xb0, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0xc6, 0x8b, 0x87, 0x42, 0x19, 0x10, 0x00, 0x00, ++ 0x8b, 0x00, 0x2f, 0x47, 0x19, 0x80, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, ++ 0xe7, 0x91, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0x2f, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xab, 0x90, 0x22, 0x47, ++ 0xe7, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x17, 0x94, 0x00, 0x40, 0xe7, 0x31, 0x01, 0x00, 0xab, 0x90, 0x22, 0x00, ++ 0x80, 0x32, 0x00, 0x00, 0xa6, 0x90, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xab, 0x90, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x32, 0x00, 0x2d, 0xf2, 0x94, 0xb0, 0x01, 0x00, 0x9f, 0x95, 0x00, 0xf2, ++ 0x02, 0x30, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0xac, 0x90, 0x00, 0x40, ++ 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xb2, 0x90, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0xb1, 0x90, 0xa2, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0xff, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb2, 0x90, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x36, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x51, 0x91, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xba, 0x90, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xb7, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x51, 0x91, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xae, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc1, 0x90, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0xc1, 0x90, 0xa2, 0x16, ++ 0x80, 0x32, 0x00, 0x00, 0x09, 0x97, 0x00, 0x4d, 0x81, 0x30, 0x01, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x74, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x96, 0xb0, 0x01, 0x00, ++ 0xd2, 0x90, 0x22, 0x42, 0x96, 0x14, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x64, 0x00, 0x68, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x4b, 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x70, 0x00, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xce, 0x90, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xd3, 0x90, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xd7, 0x90, 0x65, 0xf2, 0x12, 0x30, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x13, 0xf0, 0x01, 0x00, 0xdc, 0x90, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0x27, 0x83, 0x75, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xd6, 0x90, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xe7, 0x91, 0x01, 0x00, ++ 0x04, 0x00, 0x75, 0x09, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0xa8, 0x97, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0xe4, 0x90, 0xa8, 0x40, 0xe1, 0x31, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x13, 0xf0, 0x01, 0x00, 0xe8, 0x90, 0x65, 0x05, 0x48, 0x31, 0x00, 0x00, ++ 0x3f, 0x00, 0x00, 0xf3, 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x75, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xf0, 0x90, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0xee, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++ 0x16, 0xb0, 0x01, 0x00, 0x00, 0x62, 0x00, 0x0b, 0x16, 0xdc, 0x01, 0x00, ++ 0x2f, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x47, ++ 0xe7, 0x7d, 0x00, 0x00, 0x17, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0d, 0x91, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0x48, 0x96, 0x00, 0x5f, ++ 0x01, 0x10, 0x01, 0x00, 0xf4, 0x90, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0xfe, 0x90, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x04, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x31, 0x03, 0x6c, 0x00, 0x00, 0x9f, 0x95, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xf4, 0x90, 0x22, 0x41, 0x97, 0x50, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x01, 0x80, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0xf4, 0x90, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x60, 0x97, 0x00, 0x40, 0x03, 0x30, 0x01, 0x00, 0x17, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x0c, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x4c, 0x97, 0xf0, 0x01, 0x00, 0x04, 0x00, 0x20, 0x4d, ++ 0x97, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0x10, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0xe1, 0xb1, 0x01, 0x00, 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, ++ 0x16, 0x88, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, ++ 0x19, 0x91, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x0b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x81, 0x01, 0x00, ++ 0x00, 0xb7, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x0b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x81, 0x01, 0x00, ++ 0x10, 0x00, 0x10, 0x0f, 0x94, 0xf4, 0x01, 0x00, 0x93, 0x04, 0x00, 0x5f, ++ 0x95, 0x04, 0x01, 0x00, 0x70, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x27, 0x91, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0x23, 0x91, 0x46, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x26, 0x91, 0xa2, 0x40, 0x31, 0x6f, 0x00, 0x00, ++ 0x04, 0x00, 0x1e, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x41, ++ 0x31, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0xa5, 0x94, 0x00, 0x41, 0x81, 0x30, 0x01, 0x00, ++ 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xae, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x3a, 0x91, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x3a, 0x91, 0xa2, 0x16, 0x80, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, 0x32, 0x91, 0x37, 0x5c, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, ++ 0x37, 0x91, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x77, 0x7d, 0x00, 0x00, 0x33, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, 0x37, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xed, 0x87, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x74, 0x00, 0x22, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x55, 0x97, 0x00, 0x4a, 0x95, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x16, 0x96, 0x00, 0x5c, ++ 0x1f, 0x10, 0x01, 0x00, 0xc1, 0x90, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x4e, 0x91, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x17, 0x94, 0x00, 0x40, ++ 0xe7, 0x31, 0x01, 0x00, 0x4e, 0x91, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, ++ 0x49, 0x91, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x4e, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x32, 0x00, 0x2d, 0xf2, ++ 0x94, 0xb0, 0x01, 0x00, 0x9f, 0x95, 0x00, 0xf2, 0x02, 0x30, 0x01, 0x00, ++ 0xa6, 0x95, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x55, 0x97, 0x00, 0x48, 0x95, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x16, 0x96, 0x00, 0x5c, ++ 0x1f, 0x10, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x55, 0x91, 0x87, 0x42, 0x19, 0x10, 0x00, 0x00, 0x8b, 0x00, 0x2f, 0x47, ++ 0x19, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0x91, 0x01, 0x00, ++ 0x80, 0x97, 0x00, 0x42, 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x16, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0xc6, 0x8b, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0xf0, 0x80, 0x32, 0x00, 0x00, 0xba, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xce, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xc4, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x05, 0x98, 0x00, 0xf0, 0x84, 0x30, 0x01, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x80, 0x97, 0x00, 0x45, ++ 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x09, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xae, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x6d, 0x91, 0xa2, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x6d, 0x91, 0xa2, 0x16, 0x80, 0x32, 0x00, 0x00, ++ 0x09, 0x97, 0x00, 0x47, 0x80, 0x30, 0x01, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0xe1, 0x00, 0xa6, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x07, ++ 0x84, 0x94, 0x01, 0x00, 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, ++ 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xc3, 0x94, 0x00, 0x41, 0xe7, 0x41, 0x01, 0x00, ++ 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, 0xec, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0xa3, 0x0a, 0x0c, 0x6c, 0x00, 0x00, ++ 0x97, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x2c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x0a, ++ 0x2c, 0x50, 0x00, 0x00, 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0xf0, 0x80, 0x32, 0x00, 0x00, 0x9b, 0x97, 0x00, 0x06, ++ 0x04, 0x30, 0x01, 0x00, 0x8a, 0x91, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, ++ 0x88, 0x91, 0x84, 0x48, 0x1f, 0x10, 0x00, 0x00, 0xac, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x8a, 0x91, 0x00, 0x0a, 0xe0, 0xc1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x02, 0xb0, 0x01, 0x00, 0x98, 0x93, 0x00, 0x01, ++ 0x8c, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x8b, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x10, 0xc0, 0x01, 0x00, 0x98, 0x91, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0x73, 0x96, 0x00, 0x45, 0x1f, 0x00, 0x01, 0x00, 0x83, 0x91, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x94, 0x91, 0xa8, 0x5c, ++ 0x1f, 0x00, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x83, 0x91, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0x1b, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x2d, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0x26, 0x96, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x9e, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xa4, 0x91, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, 0xa8, 0x91, 0x22, 0x44, ++ 0x19, 0x7c, 0x00, 0x00, 0x80, 0x97, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, ++ 0xa8, 0x91, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x80, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0xb7, 0x91, 0x22, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0xaf, 0x91, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0xb3, 0x91, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x36, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb4, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xff, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, ++ 0x32, 0x00, 0x2a, 0x15, 0xe4, 0xb1, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x16, ++ 0xe4, 0xb1, 0x00, 0x00, 0xcd, 0x91, 0x22, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x2a, 0xb0, 0x01, 0x00, 0x25, 0x98, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, ++ 0xbd, 0x91, 0xa2, 0x40, 0x11, 0x6c, 0x00, 0x00, 0xce, 0x91, 0x22, 0x40, ++ 0x2d, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x44, 0x1f, 0x7c, 0x00, 0x00, 0xac, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2b, 0x01, 0xe0, 0xc1, 0x01, 0x00, ++ 0x00, 0x2b, 0x00, 0xa6, 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xe0, 0xd1, 0x01, 0x00, 0x58, 0x97, 0x00, 0x08, 0x80, 0x30, 0x01, 0x00, ++ 0xc6, 0x91, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, 0x79, 0x97, 0x00, 0x43, ++ 0x61, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xc7, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x60, 0x97, 0x00, 0x07, ++ 0x16, 0x14, 0x01, 0x00, 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x15, ++ 0x1a, 0x50, 0x00, 0x00, 0xdc, 0x91, 0x20, 0x16, 0x1a, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x22, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0xd9, 0x91, 0xa8, 0x46, ++ 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x2a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x2c, 0xd0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x16, ++ 0x80, 0x32, 0x00, 0x00, 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0xf0, 0x80, 0x32, 0x00, 0x00, 0xac, 0x00, 0x2f, 0x40, ++ 0x23, 0xb0, 0x01, 0x00, 0xe6, 0x91, 0x84, 0x45, 0x1f, 0x10, 0x00, 0x00, ++ 0xe7, 0x91, 0x00, 0x0a, 0xe0, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x02, 0xb0, 0x01, 0x00, 0xb8, 0x96, 0x00, 0x40, 0x35, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0xf0, 0x91, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xec, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x92, 0xa2, 0x02, 0x1a, 0x50, 0x00, 0x00, ++ 0x05, 0x92, 0x22, 0x40, 0x2d, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0xe0, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0xf8, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xf0, 0x10, 0xc8, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x1b, 0x98, 0x01, 0x00, 0x05, 0x92, 0x00, 0x5c, 0x11, 0x80, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x5f, 0x1b, 0x7c, 0x00, 0x00, 0xff, 0x07, 0x00, 0x08, ++ 0x98, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x98, 0xc0, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x0b, 0x99, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, 0x23, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0xa3, 0x43, 0x23, 0x6c, 0x00, 0x00, 0xe1, 0x94, 0x00, 0x40, ++ 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x0b, 0x92, 0x23, 0x0d, 0x2c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1f, 0x90, 0x01, 0x00, 0x13, 0x92, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x70, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x13, 0x92, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x0f, 0x92, 0xa8, 0x46, ++ 0x1f, 0x00, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x2d, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, 0x26, 0x96, 0x00, 0x41, ++ 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x18, 0x92, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x1e, 0x92, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x22, 0x92, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, 0x80, 0x97, 0x00, 0x4f, ++ 0x81, 0x30, 0x01, 0x00, 0x22, 0x92, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, ++ 0x00, 0x8c, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x38, 0x92, 0x22, 0x4a, 0x1f, 0x7c, 0x00, 0x00, 0x29, 0x92, 0xa2, 0x16, ++ 0x02, 0x30, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, ++ 0x34, 0x92, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x2d, 0x92, 0xa2, 0xf3, ++ 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x85, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x85, 0xd0, 0x01, 0x00, 0xd4, 0x00, 0x3e, 0x41, ++ 0x85, 0xe0, 0x01, 0x00, 0x31, 0x92, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5a, 0x11, 0x90, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x08, ++ 0xe4, 0xf5, 0x01, 0x00, 0x36, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x35, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xff, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, ++ 0x32, 0x00, 0x2a, 0x15, 0xe4, 0xb1, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x16, ++ 0xe4, 0xb1, 0x00, 0x00, 0x3b, 0x92, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x94, 0x92, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, ++ 0x4e, 0x92, 0x22, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa0, 0x91, ++ 0x03, 0x6c, 0x00, 0x00, 0x48, 0x92, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x41, 0x92, 0xa2, 0xf3, 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x85, 0xd0, 0x01, 0x00, ++ 0xd4, 0x00, 0x3e, 0x41, 0x85, 0xe0, 0x01, 0x00, 0x45, 0x92, 0x22, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x11, 0x90, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0x08, 0xe4, 0xf5, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x08, 0x8a, 0x30, 0x01, 0x00, ++ 0x58, 0x01, 0x2d, 0x00, 0x2a, 0xd0, 0x01, 0x00, 0x60, 0x01, 0x2d, 0xf0, ++ 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x2c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x80, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x27, 0x40, ++ 0x11, 0x6c, 0x00, 0x00, 0x84, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0xa3, 0x91, 0x03, 0x6c, 0x00, 0x00, 0x25, 0x98, 0x00, 0x41, ++ 0x95, 0x30, 0x01, 0x00, 0x57, 0x92, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x57, 0x92, 0xa2, 0x16, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0x55, 0x92, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x94, 0x92, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x22, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0xac, 0x00, 0x2f, 0x01, 0x14, 0xb0, 0x01, 0x00, ++ 0xb0, 0x00, 0x2b, 0x01, 0xe0, 0xc1, 0x01, 0x00, 0x00, 0x2b, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xd1, 0x01, 0x00, 0x6a, 0x92, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x63, 0x92, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x22, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x23, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x84, 0xb0, 0x01, 0x00, 0x6d, 0x92, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x80, 0xb0, 0x01, 0x00, 0x72, 0x92, 0x22, 0x40, 0x1b, 0x6c, 0x00, 0x00, ++ 0x58, 0x97, 0x00, 0x01, 0x84, 0x50, 0x01, 0x00, 0x7b, 0x92, 0x22, 0x40, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xc0, 0x01, 0x00, ++ 0x10, 0x80, 0x00, 0x10, 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa1, 0x62, 0xdd, 0x01, 0x00, 0x78, 0x92, 0xa8, 0x11, ++ 0xe0, 0x31, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, 0x23, 0x6c, 0x00, 0x00, ++ 0x8a, 0x92, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, 0x7e, 0x92, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x84, 0xd0, 0x01, 0x00, 0x83, 0x92, 0x22, 0x40, ++ 0x1b, 0x6c, 0x00, 0x00, 0x79, 0x97, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, ++ 0x8a, 0x92, 0x22, 0x40, 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x12, 0xc0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, 0x46, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa1, ++ 0x62, 0xdd, 0x01, 0x00, 0x88, 0x92, 0xa8, 0x11, 0xe0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x8b, 0x92, 0xa8, 0x0a, 0x02, 0x30, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x05, ++ 0x48, 0x31, 0x01, 0x00, 0x92, 0x92, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, ++ 0xff, 0x07, 0x00, 0x11, 0x00, 0x8c, 0x01, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x60, 0x97, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, ++ 0xfa, 0x96, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x8e, 0xb0, 0x01, 0x00, 0xe6, 0x95, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0x0c, 0x47, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x26, 0x96, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, ++ 0x97, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0x20, 0x91, ++ 0x03, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xa8, 0x92, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xa4, 0x92, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xaa, 0x92, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x1a, 0xd0, 0x01, 0x00, 0xb1, 0x92, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x25, 0x98, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0x80, 0xb2, 0x01, 0x00, 0xba, 0x92, 0x27, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0xbd, 0x91, 0x00, 0x00, 0x2a, 0xc0, 0x00, 0x00, ++ 0x25, 0x98, 0x00, 0x41, 0x95, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0x80, 0xb2, 0x01, 0x00, 0xb5, 0x92, 0x27, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x57, 0x92, 0x00, 0x00, 0x2a, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0xb8, 0x92, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc6, 0x8b, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x09, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, 0xbf, 0x92, 0x00, 0x4a, ++ 0x1f, 0x90, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x4f, 0x2b, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0xf9, 0x94, 0x00, 0x00, 0x10, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x9b, 0x97, 0x00, 0x06, 0x04, 0x30, 0x01, 0x00, 0xcc, 0x92, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x2c, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x02, 0xb0, 0x01, 0x00, 0x98, 0x93, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, 0xd3, 0x92, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xcf, 0x92, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x10, 0xc0, 0x01, 0x00, 0xdc, 0x92, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0x73, 0x96, 0x00, 0x45, 0x1f, 0x00, 0x01, 0x00, 0xc5, 0x92, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xd8, 0x92, 0xa8, 0x5c, ++ 0x1f, 0x00, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xc5, 0x92, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x08, 0x00, 0x2d, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, 0x26, 0x96, 0x00, 0x41, ++ 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xe1, 0x92, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0xe7, 0x92, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0x80, 0x97, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xea, 0x92, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, 0x80, 0x97, 0x00, 0x4f, ++ 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xf9, 0x92, 0x22, 0x4a, 0x1f, 0x7c, 0x00, 0x00, ++ 0xf1, 0x92, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2d, 0x00, 0x2d, 0x08, ++ 0x2a, 0xb0, 0x01, 0x00, 0xf5, 0x92, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x36, 0x96, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xf6, 0x92, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xff, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, 0x32, 0x00, 0x2a, 0x15, ++ 0xe4, 0xb1, 0x01, 0x00, 0xc6, 0x8b, 0x00, 0x16, 0xe4, 0xb1, 0x00, 0x00, ++ 0xb8, 0x91, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xcd, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x22, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4f, 0x2b, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, ++ 0xf9, 0x94, 0x00, 0x4a, 0x1f, 0x10, 0x01, 0x00, 0xd0, 0x91, 0x00, 0x10, ++ 0x32, 0xb0, 0x00, 0x00, 0x8a, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x08, 0x93, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0b, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x9f, 0x95, 0x00, 0x15, 0x94, 0x30, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x0d, 0x93, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x09, 0x97, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0x80, 0x97, 0x00, 0x45, 0x81, 0x30, 0x01, 0x00, ++ 0xc6, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x62, 0x90, 0x00, 0x45, ++ 0x1f, 0x90, 0x00, 0x00, 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, 0xec, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0xa3, 0x0a, 0x0c, 0x6c, 0x00, 0x00, ++ 0x97, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd0, 0x91, 0x00, 0x01, ++ 0x2c, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, 0xae, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x26, 0x93, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x26, 0x93, 0xa2, 0x16, 0x80, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, 0x1e, 0x93, 0x37, 0x5c, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, ++ 0x23, 0x93, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x77, 0x7d, 0x00, 0x00, 0x1f, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, 0x23, 0x93, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xed, 0x87, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x58, 0x01, 0x20, 0x08, 0xe0, 0xb1, 0x01, 0x00, 0x60, 0x01, 0x20, 0x16, ++ 0xe0, 0xb1, 0x01, 0x00, 0xec, 0x95, 0x00, 0x47, 0x1f, 0x10, 0x01, 0x00, ++ 0x04, 0x00, 0xa3, 0x0a, 0x0c, 0x6c, 0x00, 0x00, 0x97, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x91, 0x00, 0x01, 0x2c, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0xae, 0x94, 0x00, 0x47, 0x1f, 0x10, 0x01, 0x00, ++ 0x3d, 0x93, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x3d, 0x93, 0xa2, 0x16, ++ 0x80, 0x32, 0x00, 0x00, 0x39, 0x93, 0xa2, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x9f, 0x95, 0x00, 0x15, ++ 0x94, 0x30, 0x01, 0x00, 0xa6, 0x95, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x36, 0x96, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x09, 0x97, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0xed, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x58, 0x01, 0x20, 0x08, 0xe0, 0xb1, 0x01, 0x00, ++ 0x60, 0x01, 0x20, 0x16, 0xe0, 0xb1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x4f, ++ 0x2b, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0xf9, 0x94, 0x00, 0x10, ++ 0x32, 0x30, 0x01, 0x00, 0xd0, 0x91, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0xae, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x52, 0x93, 0xa2, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x52, 0x93, 0xa2, 0x16, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, ++ 0x4a, 0x93, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x62, 0xb1, 0x01, 0x00, 0x4f, 0x93, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x77, 0x7d, 0x00, 0x00, 0x4b, 0x93, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, ++ 0x4f, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xed, 0x87, 0x17, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x8e, 0xb0, 0x01, 0x00, 0xe6, 0x95, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x04, 0x00, 0x0c, 0x47, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x26, 0x96, 0x00, 0x41, ++ 0x87, 0x30, 0x01, 0x00, 0x97, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x04, 0x00, 0xa0, 0x91, 0x03, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x64, 0x93, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x60, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x84, 0x8f, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, ++ 0x80, 0x97, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, 0x84, 0x8f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x4f, 0x2b, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x14, 0x00, 0x2d, 0x45, 0x1f, 0x90, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0xf0, 0x14, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa0, 0x01, ++ 0x14, 0x6c, 0x00, 0x00, 0xdc, 0x8f, 0x00, 0x44, 0x19, 0x90, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, 0x72, 0x93, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x1f, 0x90, 0x01, 0x00, ++ 0x77, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x48, ++ 0x1f, 0x7c, 0x00, 0x00, 0xec, 0x95, 0x00, 0x4a, 0x1f, 0x10, 0x01, 0x00, ++ 0x04, 0x00, 0xa3, 0x0a, 0x0c, 0x6c, 0x00, 0x00, 0x97, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x91, 0x00, 0x01, 0x2c, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4f, ++ 0x2b, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0xf9, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x91, 0x00, 0x10, 0x32, 0xb0, 0x00, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x46, ++ 0xe7, 0x7d, 0x00, 0x00, 0x62, 0x90, 0x00, 0x45, 0x1f, 0x90, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x37, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x33, 0xc3, 0x01, 0x00, 0x36, 0x00, 0x00, 0x01, 0x02, 0xcc, 0x01, 0x00, ++ 0x00, 0x00, 0xd2, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x86, 0x93, 0x85, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x48, 0x03, 0xd0, 0x00, 0x00, ++ 0x88, 0x93, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x4c, ++ 0x03, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x34, 0xc3, 0x01, 0x00, ++ 0x40, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xf0, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x12, ++ 0xf0, 0xb1, 0x01, 0x00, 0xcb, 0x94, 0x00, 0x41, 0xe1, 0x31, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x43, 0x44, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x03, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x95, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0xa5, ++ 0x8a, 0x30, 0x01, 0x00, 0xba, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0xb0, 0x00, 0x2f, 0x01, 0x8c, 0xd0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0xf0, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xe0, 0xc1, 0x01, 0x00, ++ 0xac, 0x00, 0x2f, 0x40, 0x13, 0xb0, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0x01, ++ 0xe0, 0xc1, 0x01, 0x00, 0xa3, 0x93, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, 0x2f, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xa5, 0x93, 0x22, 0x47, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x13, 0x90, 0x01, 0x00, 0xce, 0x97, 0x00, 0x47, ++ 0x19, 0x10, 0x01, 0x00, 0xc0, 0x00, 0x2d, 0x44, 0x1f, 0x90, 0x01, 0x00, ++ 0xc4, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x05, 0x98, 0x00, 0xf0, ++ 0x84, 0xb0, 0x00, 0x00, 0x90, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xba, 0x93, 0xa2, 0x4b, 0x1f, 0x7c, 0x00, 0x00, 0x0f, 0x94, 0xa2, 0x4c, ++ 0x1f, 0x7c, 0x00, 0x00, 0xba, 0x93, 0x1f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xbd, 0x93, 0xa2, 0x01, 0x80, 0x32, 0x00, 0x00, 0xa8, 0x00, 0x2d, 0x46, ++ 0x8f, 0xb0, 0x01, 0x00, 0xb3, 0x93, 0x1f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xb4, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xb5, 0x93, 0x22, 0xf0, ++ 0x3a, 0x6c, 0x00, 0x00, 0x0c, 0x94, 0x1f, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0x40, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, ++ 0x8f, 0xb0, 0x01, 0x00, 0x8a, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x0d, 0x94, 0x20, 0x42, 0xe7, 0x6d, 0x00, 0x00, 0xb9, 0x93, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x59, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x58, 0x8f, 0xb0, 0x01, 0x00, 0xbc, 0x93, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5c, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x5b, 0x8f, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0xc1, 0x93, 0xa2, 0x42, 0x24, 0x6c, 0x00, 0x00, 0xcc, 0x93, 0x23, 0xf0, ++ 0x02, 0x6c, 0x00, 0x00, 0xb0, 0x00, 0x00, 0xa1, 0x80, 0xce, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xc9, 0x93, 0xa2, 0xf0, ++ 0x80, 0x32, 0x00, 0x00, 0x0e, 0x94, 0xa2, 0x42, 0x24, 0x6c, 0x00, 0x00, ++ 0x0e, 0x94, 0xa2, 0x41, 0x03, 0x6c, 0x00, 0x00, 0xc8, 0x93, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x51, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x52, 0x8f, 0xb0, 0x01, 0x00, 0x0e, 0x94, 0x1f, 0x12, ++ 0x84, 0x50, 0x00, 0x00, 0x0e, 0x94, 0xa0, 0x01, 0x84, 0x6c, 0x00, 0x00, ++ 0xba, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xf7, 0x93, 0xa2, 0x46, 0xe7, 0x7d, 0x00, 0x00, ++ 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xe9, 0x93, 0x22, 0xf0, ++ 0x14, 0x30, 0x00, 0x00, 0xd5, 0x93, 0x20, 0x0a, 0x02, 0x6c, 0x00, 0x00, ++ 0xe6, 0x93, 0x03, 0x1e, 0x80, 0x32, 0x00, 0x00, 0xd4, 0x93, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, 0xda, 0x93, 0x22, 0x0a, ++ 0x02, 0x6c, 0x00, 0x00, 0xdd, 0x93, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xd9, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x56, 0x8f, 0xb0, 0x01, 0x00, ++ 0xdc, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x82, 0xd0, 0x01, 0x00, 0xe3, 0x93, 0x20, 0x91, 0x83, 0x6c, 0x00, 0x00, ++ 0xe2, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x26, 0x00, 0x80, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x27, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0xe5, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x1f, 0x00, 0x80, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x20, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0xe8, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x22, 0x00, 0x80, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x23, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x88, 0x00, 0x2d, 0x44, 0x8f, 0xb0, 0x01, 0x00, 0xf2, 0x93, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0xef, 0x93, 0xa2, 0x43, 0x3d, 0x7c, 0x00, 0x00, ++ 0xef, 0x93, 0xa2, 0xf2, 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, ++ 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, ++ 0xf1, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, ++ 0xef, 0x93, 0xa0, 0x91, 0x03, 0x6c, 0x00, 0x00, 0xed, 0x93, 0x22, 0x43, ++ 0x3d, 0x7c, 0x00, 0x00, 0xf6, 0x93, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x28, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x29, 0x00, 0x80, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x94, 0xa2, 0xf0, 0x14, 0x30, 0x00, 0x00, 0x88, 0x00, 0x2d, 0x44, ++ 0x8f, 0xb0, 0x01, 0x00, 0xfd, 0x93, 0xa2, 0xf2, 0x02, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0x40, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x49, ++ 0x8f, 0xb0, 0x01, 0x00, 0xef, 0x93, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xed, 0x93, 0x20, 0x91, 0x03, 0x6c, 0x00, 0x00, 0xef, 0x93, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x94, 0x20, 0x0a, 0x02, 0x6c, 0x00, 0x00, ++ 0x03, 0x94, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, ++ 0x09, 0x94, 0x22, 0x0a, 0x02, 0x6c, 0x00, 0x00, 0xdd, 0x93, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x08, 0x94, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x55, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x56, ++ 0x8f, 0xb0, 0x01, 0x00, 0x0b, 0x94, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x43, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, ++ 0x8f, 0xb0, 0x01, 0x00, 0x11, 0x94, 0x00, 0x43, 0x95, 0xb0, 0x00, 0x00, ++ 0x11, 0x94, 0x00, 0x41, 0x95, 0xb0, 0x00, 0x00, 0x11, 0x94, 0x00, 0x42, ++ 0x95, 0xb0, 0x00, 0x00, 0x11, 0x94, 0x00, 0x44, 0x95, 0xb0, 0x00, 0x00, ++ 0x11, 0x94, 0x00, 0x4c, 0x95, 0xb0, 0x00, 0x00, 0x30, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x4a, 0x8a, 0x30, 0x01, 0x00, ++ 0x55, 0x97, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x16, 0x94, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4b, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x4c, 0x8f, 0xb0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x2e, 0x00, 0x2f, 0xf3, 0x84, 0xb0, 0x01, 0x00, 0x1c, 0x94, 0xa2, 0xf3, ++ 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x01, 0xb0, 0x01, 0x00, ++ 0x2d, 0x00, 0x2a, 0x41, 0xe7, 0xd1, 0x01, 0x00, 0xd4, 0x00, 0x3d, 0x41, ++ 0x85, 0xe0, 0x01, 0x00, 0x0b, 0x00, 0x00, 0xf2, 0x00, 0xe4, 0x01, 0x00, ++ 0x22, 0x94, 0x22, 0x5a, 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1f, 0x90, 0x01, 0x00, 0x23, 0x94, 0x00, 0x5a, 0x01, 0x80, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x63, 0x41, ++ 0x85, 0xc0, 0x01, 0x00, 0x26, 0x94, 0xa0, 0xa5, 0x85, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x12, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0xa0, 0xa5, ++ 0x85, 0x6c, 0x01, 0x00, 0x00, 0x00, 0xe3, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x12, 0x00, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x78, 0x98, 0x00, 0xf0, 0x8c, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x5f, 0x1f, 0x7c, 0x00, 0x00, 0x3b, 0x94, 0x22, 0x40, ++ 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0xf0, ++ 0x98, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x07, 0x98, 0x6c, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x0c, 0x98, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x07, ++ 0x98, 0x6c, 0x00, 0x00, 0x38, 0x94, 0xa2, 0x4b, 0x19, 0x7c, 0x00, 0x00, ++ 0x39, 0x94, 0x22, 0xf0, 0x18, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x3d, 0x95, 0x00, 0x07, 0x10, 0x30, 0x01, 0x00, ++ 0x2f, 0x83, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x3d, 0x94, 0x22, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0xa5, 0x94, 0x00, 0x40, 0x81, 0x30, 0x01, 0x00, ++ 0x2f, 0x83, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x22, 0x5f, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x4b, 0x19, 0x90, 0x01, 0x00, 0x04, 0x00, 0x22, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, 0x0f, 0x6c, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0xf0, 0x96, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x07, ++ 0x96, 0x6c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0c, 0x96, 0xf4, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x07, 0x96, 0x6c, 0x00, 0x00, 0x3d, 0x95, 0x00, 0x07, ++ 0x10, 0x30, 0x01, 0x00, 0x2f, 0x83, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x5f, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x0f, 0x6c, 0x00, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x96, 0xf4, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x07, 0x96, 0x6c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0c, ++ 0x96, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x07, 0x96, 0x6c, 0x00, 0x00, ++ 0x3d, 0x95, 0x00, 0x07, 0x10, 0x30, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0x54, 0x94, 0x33, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x57, 0x94, 0xa1, 0xad, 0x95, 0x20, 0x00, 0x00, 0x69, 0x94, 0x13, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4a, 0x5a, 0x83, 0x01, 0x00, ++ 0x30, 0x00, 0x39, 0x45, 0x95, 0xe0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5f, ++ 0x5f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5e, 0x5f, 0x7c, 0x00, 0x00, ++ 0x1f, 0x00, 0x00, 0x0f, 0x5e, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, ++ 0x5f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x5f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x45, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, ++ 0x48, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x4a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0x58, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, ++ 0x4e, 0xb0, 0x01, 0x00, 0x19, 0x85, 0x00, 0x40, 0x5d, 0x98, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x44, 0x5f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x62, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x41, 0x97, 0xb0, 0x00, 0x00, 0x66, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x40, 0x05, 0x6c, 0x00, 0x00, 0x15, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x6c, 0x94, 0x60, 0x07, 0x96, 0x30, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x4b, 0x84, 0x89, 0x01, 0x00, 0x00, 0x00, 0x70, 0xc2, ++ 0x24, 0xb0, 0x01, 0x00, 0x79, 0x94, 0xa2, 0x45, 0x25, 0x7c, 0x00, 0x00, ++ 0x70, 0x94, 0x31, 0x20, 0x85, 0x30, 0x00, 0x00, 0x7a, 0x94, 0x22, 0x12, ++ 0x48, 0x7f, 0x00, 0x00, 0x58, 0x04, 0x11, 0x12, 0x48, 0x03, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x1e, 0x94, 0x01, 0x00, 0x17, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x12, 0x8a, 0xb0, 0x01, 0x00, 0x02, 0x99, 0x00, 0x5f, ++ 0x8b, 0x10, 0x01, 0x00, 0x00, 0x00, 0x80, 0x5a, 0x1f, 0x90, 0x01, 0x00, ++ 0x79, 0x94, 0x31, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, ++ 0x24, 0xb0, 0x01, 0x00, 0x7a, 0x94, 0x22, 0x12, 0x48, 0x7f, 0x00, 0x00, ++ 0x58, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x17, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x12, 0x8a, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x89, 0x94, 0x0b, 0xf0, ++ 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x48, 0x83, 0x01, 0x00, ++ 0x86, 0x94, 0x22, 0x50, 0x85, 0x70, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xae, 0x96, 0x00, 0xf2, 0x96, 0x30, 0x01, 0x00, ++ 0x93, 0x04, 0x00, 0x12, 0x94, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, ++ 0x1f, 0x90, 0x01, 0x00, 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x4b, 0x1e, 0x94, 0x01, 0x00, 0x10, 0x00, 0x00, 0x42, ++ 0x10, 0xf4, 0x01, 0x00, 0x04, 0x00, 0x22, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0xb7, 0x3f, 0x43, 0x11, 0xf0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x08, ++ 0x8a, 0x88, 0x01, 0x00, 0x8d, 0x94, 0x30, 0xa1, 0x0c, 0x30, 0x00, 0x00, ++ 0x90, 0x94, 0x22, 0x45, 0xe6, 0x7d, 0x00, 0x00, 0x7a, 0x94, 0x10, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x45, 0xe6, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x12, 0x48, 0x83, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x4b, 0x85, 0x80, 0x01, 0x00, 0x5e, 0x01, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xae, 0x96, 0x00, 0xf2, 0x96, 0x30, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0xd8, 0x00, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0x2e, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x9c, 0x94, 0x22, 0x40, 0xe7, 0x6d, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf0, 0xb1, 0x01, 0x00, ++ 0x09, 0x00, 0x00, 0x08, 0x86, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x68, 0xa7, ++ 0x87, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0xa0, 0x94, 0xa8, 0x05, ++ 0xe0, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x14, 0x00, 0x4b, 0x96, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4b, ++ 0x1e, 0x94, 0x01, 0x00, 0x04, 0x00, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x0f, 0x84, 0xf4, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x42, ++ 0x84, 0x88, 0x01, 0x00, 0xaa, 0x94, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0xab, 0x94, 0x00, 0x42, 0x68, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x6a, 0xb1, 0x01, 0x00, 0xab, 0x94, 0x31, 0x5a, 0x1f, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x42, 0x48, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x91, 0x42, ++ 0x48, 0x93, 0x01, 0x00, 0xae, 0x94, 0x35, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xb4, 0x94, 0x28, 0xb1, ++ 0x2c, 0x30, 0x00, 0x00, 0xaf, 0x94, 0x22, 0x4d, 0x75, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x2d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x95, 0x40, ++ 0x11, 0xb0, 0x01, 0x00, 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xb4, 0x94, 0xa8, 0xb1, 0x10, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0x80, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x27, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x95, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x7f, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xbf, 0x94, 0x28, 0xb1, 0x10, 0x30, 0x00, 0x00, ++ 0xb9, 0x94, 0x9f, 0xba, 0x80, 0x32, 0x00, 0x00, 0x15, 0x00, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x11, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x5c, ++ 0x11, 0x7c, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x5a, 0x11, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x08, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x24, ++ 0x11, 0x84, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, 0x01, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x5a, 0x01, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x00, ++ 0x48, 0x06, 0x00, 0x00, 0x04, 0x00, 0x1f, 0xbb, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc8, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xac, 0x94, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xcc, 0x94, 0x32, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xd4, 0x94, 0x22, 0xf8, 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x90, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x92, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x80, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x27, 0x49, ++ 0x80, 0x32, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4b, 0xf0, 0xcd, 0x01, 0x00, ++ 0x20, 0x00, 0x92, 0x48, 0xe0, 0xc9, 0x01, 0x00, 0x6c, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xd8, 0x94, 0x28, 0xb1, 0x92, 0x30, 0x00, 0x00, ++ 0xd4, 0x94, 0x22, 0x4c, 0x75, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x12, 0x40, ++ 0x91, 0xb0, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xd8, 0x94, 0xa8, 0xb1, 0x90, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0x80, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x27, 0x48, 0x80, 0x32, 0x00, 0x00, ++ 0xff, 0x00, 0x00, 0x48, 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x90, 0xd0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x4b, 0xf0, 0xcd, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x48, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x92, 0x49, ++ 0xe0, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x82, 0x8c, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x83, 0x7c, 0x00, 0x00, 0xff, 0x07, 0x00, 0xf0, 0x00, 0x8c, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x01, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x01, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x41, 0x00, 0xec, 0x00, 0x00, ++ 0xea, 0x94, 0x22, 0x1a, 0x00, 0x6c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x00, ++ 0x34, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x49, 0xc1, 0x01, 0x00, ++ 0xe4, 0x94, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x15, 0x82, 0x8c, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x83, 0x7c, 0x00, 0x00, 0xff, 0x07, 0x00, 0xf0, 0x00, 0x8c, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5c, 0x01, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0x01, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x41, 0x00, 0xec, 0x00, 0x00, ++ 0xf6, 0x94, 0x22, 0x0d, 0x00, 0x6c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x00, ++ 0x1a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x49, 0xc1, 0x01, 0x00, ++ 0xf0, 0x94, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xfb, 0x94, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x19, 0x90, 0x01, 0x00, 0x24, 0x00, 0x2d, 0x01, ++ 0x2c, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x2d, 0xf0, 0x16, 0xb0, 0x01, 0x00, ++ 0x22, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, 0x14, 0x00, 0x2f, 0xf2, ++ 0x0c, 0xb0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0xf0, 0x14, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x20, 0x01, 0x14, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x30, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x60, 0x97, 0x2e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x04, 0x95, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x64, 0x97, 0x3e, 0x43, 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x64, 0x97, 0x3e, 0x43, 0x9d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x0b, 0xe8, 0xb1, 0x01, 0x00, 0x64, 0x97, 0x3f, 0x43, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x16, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x64, 0x97, 0x3f, 0x43, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x16, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x60, 0x17, 0x3d, 0x43, ++ 0x9d, 0xe0, 0x01, 0x00, 0x10, 0x00, 0x80, 0xa1, 0x16, 0xe4, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x07, 0x16, 0x6c, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x10, 0x00, 0x00, 0x0b, 0x8a, 0xe4, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x0d, 0x8a, 0x14, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x17, 0x95, 0x30, 0x47, 0x17, 0x04, 0x00, 0x00, ++ 0x1a, 0x95, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x90, 0x42, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, ++ 0x1e, 0x95, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe6, 0x91, 0x01, 0x00, 0x00, 0x00, 0x90, 0x41, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x1f, 0x95, 0x40, 0x07, ++ 0x96, 0x30, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x29, 0x95, 0xa2, 0x45, 0x95, 0x7c, 0x00, 0x00, 0x01, 0x97, 0x3f, 0x41, ++ 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0xe6, 0xb1, 0x01, 0x00, 0x40, 0x97, 0x3e, 0x40, ++ 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xe6, 0xb1, 0x01, 0x00, ++ 0x40, 0x97, 0x3e, 0x40, 0x9d, 0xe0, 0x01, 0x00, 0x3c, 0x95, 0x00, 0x3b, ++ 0xe7, 0xb1, 0x00, 0x00, 0x29, 0x95, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x33, 0x95, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0x2f, 0x95, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x98, 0x42, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x98, 0x41, 0x81, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x21, 0xa2, 0x95, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4a, ++ 0x44, 0x83, 0x01, 0x00, 0x00, 0x97, 0x3e, 0x41, 0x95, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0xf6, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0xe6, 0xb1, 0x01, 0x00, 0x40, 0x97, 0x3e, 0x40, 0x9d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x3b, 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x90, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0x07, 0x92, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0x98, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x11, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x08, 0x8a, 0x30, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x08, 0x86, 0xf4, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x43, ++ 0x46, 0xc9, 0x01, 0x00, 0x07, 0x00, 0x00, 0x08, 0x82, 0x88, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x08, 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x41, ++ 0xe6, 0x7d, 0x00, 0x00, 0x44, 0x95, 0x40, 0x08, 0x96, 0x30, 0x00, 0x00, ++ 0x9d, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x52, 0x95, 0x22, 0x45, ++ 0x95, 0x7c, 0x00, 0x00, 0x4d, 0x95, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x0f, 0x96, 0xf4, 0x01, 0x00, 0x49, 0x95, 0x31, 0x5f, ++ 0x97, 0x04, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x4b, 0x48, 0x7f, 0x00, 0x00, ++ 0x00, 0x00, 0x11, 0x4b, 0x48, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x6a, 0xb1, 0x01, 0x00, 0x4d, 0x95, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe6, 0x81, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x97, 0x3f, 0x41, ++ 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, ++ 0x40, 0x97, 0x3d, 0x40, 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x63, 0xf3, ++ 0x88, 0xb0, 0x01, 0x00, 0x5b, 0x95, 0xa2, 0x3b, 0x89, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, ++ 0x92, 0xb1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x4a, 0x44, 0x7f, 0x00, 0x00, ++ 0x5c, 0x95, 0x18, 0x4a, 0x44, 0x93, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x3f, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x16, 0x00, 0x00, 0x12, 0x8a, 0xe4, 0x01, 0x00, 0x02, 0x99, 0x00, 0x4b, ++ 0x8a, 0x14, 0x01, 0x00, 0x30, 0x00, 0x39, 0x45, 0x97, 0xe0, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5f, 0x5f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x5e, ++ 0x5f, 0x7c, 0x00, 0x00, 0x1f, 0x04, 0x00, 0x2f, 0x7e, 0xd9, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x68, 0x95, 0x22, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x1f, 0x04, 0x00, 0x0f, 0x98, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x5e, 0x94, 0x01, 0x00, 0x6a, 0x95, 0x00, 0x05, ++ 0x4a, 0xb0, 0x00, 0x00, 0x1f, 0x04, 0x00, 0xa7, 0x5e, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x4b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x5f, 0x90, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x08, 0x4e, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x6d, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x33, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x07, 0x8a, 0x30, 0x01, 0x00, ++ 0x72, 0x95, 0x40, 0x07, 0x96, 0x30, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x76, 0x95, 0x22, 0x45, 0x95, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x4a, ++ 0x44, 0x7f, 0x00, 0x00, 0x9b, 0x04, 0x00, 0x4a, 0x44, 0x13, 0x01, 0x00, ++ 0x00, 0x97, 0x3f, 0x41, 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x96, 0xb0, 0x01, 0x00, 0x40, 0x97, 0x3d, 0x40, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0xf3, 0x88, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x38, 0x45, ++ 0x97, 0xe0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5f, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x5e, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x20, 0xaa, ++ 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x0f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x82, 0x95, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x78, 0x95, 0xa2, 0x3b, 0x89, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x38, 0x45, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x08, 0x80, 0x32, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, ++ 0x94, 0xf4, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x4a, 0x46, 0xc9, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x08, 0x96, 0x88, 0x01, 0x00, 0x04, 0x00, 0x22, 0x4b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x93, 0x04, 0x00, 0x12, 0x94, 0x30, 0x01, 0x00, ++ 0x3d, 0x95, 0x00, 0x5a, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x5a, ++ 0x1f, 0x90, 0x01, 0x00, 0x11, 0x00, 0x00, 0x4a, 0xe6, 0xc9, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x4a, 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0x24, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x34, 0x00, 0x2f, 0x4f, 0x95, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x63, 0x4b, ++ 0x84, 0xc8, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x43, 0x85, 0x6c, 0x01, 0x00, ++ 0x00, 0x00, 0xe3, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x2d, 0x44, ++ 0x1f, 0x90, 0x01, 0x00, 0x32, 0x00, 0x2d, 0xf2, 0x2a, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0xf2, ++ 0x02, 0x30, 0x00, 0x00, 0x17, 0x94, 0x00, 0x10, 0x32, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x32, 0x00, 0xa0, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x99, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x02, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x97, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x4c, 0x02, 0xd0, 0x00, 0x00, ++ 0xa3, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x36, 0xb0, 0x01, 0x00, 0xb4, 0x95, 0x22, 0x41, 0x03, 0x50, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x70, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0xac, 0x95, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x7c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x00, 0xb0, 0x01, 0x00, 0xa7, 0x95, 0x00, 0x5c, 0x01, 0x80, 0x00, 0x00, ++ 0xc3, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x10, 0xb1, 0x00, 0x00, 0x68, 0x01, 0x2d, 0x06, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x82, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x46, 0xc9, 0x01, 0x00, 0xb9, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xe2, 0x95, 0x22, 0x40, 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x68, 0x08, ++ 0x38, 0x96, 0x01, 0x00, 0x3a, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x08, 0x8a, 0x30, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x41, ++ 0x82, 0xcc, 0x01, 0x00, 0xb9, 0x95, 0xaa, 0x41, 0x3b, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x11, 0x80, 0x01, 0x00, 0x04, 0x00, 0xa3, 0x48, 0x3b, 0x6c, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x1d, 0x04, 0xcc, 0x01, 0x00, 0xe0, 0x95, 0x26, 0x46, ++ 0x23, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x12, 0xc8, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x98, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x4c, ++ 0x42, 0x6d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x64, 0x01, 0x20, 0xf0, 0xe0, 0xb1, 0x01, 0x00, 0xdf, 0x95, 0x22, 0x41, ++ 0x05, 0x50, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0xf8, 0x86, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x22, 0x44, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0xd1, 0x95, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, 0xde, 0x95, 0x22, 0x41, ++ 0x05, 0x50, 0x00, 0x00, 0xdc, 0x95, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa1, 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xd7, 0x95, 0xa8, 0x46, 0x23, 0x30, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x13, 0xc0, 0x01, 0x00, 0xcc, 0x95, 0x00, 0x50, 0x49, 0xc1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x04, 0x80, 0x00, 0x03, ++ 0x1a, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xe0, 0x95, 0x22, 0x40, ++ 0x3b, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xb0, 0x01, 0x00, ++ 0xc3, 0x94, 0x00, 0x5c, 0x01, 0x00, 0x01, 0x00, 0xe2, 0x95, 0x00, 0x41, ++ 0x3b, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x47, 0x80, 0x32, 0x01, 0x00, ++ 0xb0, 0x00, 0x2f, 0x5f, 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, ++ 0x8c, 0xc0, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0xa3, 0xf0, 0x8c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x8c, 0xb0, 0x01, 0x00, 0xf1, 0x95, 0x8c, 0xf8, 0x8e, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x19, 0x90, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf8, ++ 0x14, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x16, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x26, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x2e, 0xf8, ++ 0x0c, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2a, 0x4a, 0xe0, 0xb1, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x20, 0x1b, ++ 0xe0, 0xb1, 0x01, 0x00, 0xfe, 0x95, 0x20, 0x0a, 0x0c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x96, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x20, 0xf0, 0xe4, 0xb1, 0x01, 0x00, ++ 0x18, 0x00, 0x20, 0x4a, 0xe0, 0xb1, 0x01, 0x00, 0x1c, 0x00, 0x20, 0x4b, ++ 0xe0, 0xb1, 0x01, 0x00, 0xe6, 0x95, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, 0x2c, 0x00, 0x2d, 0x42, ++ 0x19, 0x90, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, 0x05, 0x96, 0xa2, 0xa5, ++ 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, 0x95, 0xb0, 0x01, 0x00, ++ 0x08, 0x96, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x41, 0x97, 0xc0, 0x01, 0x00, 0xd4, 0x00, 0x3e, 0x41, ++ 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, ++ 0x0d, 0x96, 0xa0, 0xa5, 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x2c, 0x00, 0x20, 0x41, 0xe6, 0xb1, 0x01, 0x00, ++ 0x12, 0x96, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, ++ 0x98, 0xdc, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x4c, 0xe4, 0xf5, 0x01, 0x00, ++ 0x13, 0x96, 0x00, 0x40, 0x1f, 0x80, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, ++ 0xe4, 0xf5, 0x01, 0x00, 0x1e, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xcb, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0xe1, 0x6d, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x41, 0x87, 0xb0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, ++ 0x05, 0x90, 0x00, 0x00, 0x23, 0x96, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcb, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, ++ 0x33, 0x96, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x82, 0x0c, 0x80, 0x32, 0x00, 0x00, ++ 0x2d, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, ++ 0x84, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x96, 0xc8, 0x01, 0x00, ++ 0x3d, 0x96, 0x9f, 0x41, 0x85, 0x50, 0x00, 0x00, 0x01, 0x00, 0x00, 0xa5, ++ 0x85, 0xcc, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x42, 0xe6, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0xa3, 0xa5, 0x97, 0x6c, 0x00, 0x00, 0xd4, 0x00, 0x3d, 0x41, ++ 0x85, 0xe0, 0x01, 0x00, 0x0b, 0x00, 0x00, 0xf2, 0x98, 0xe4, 0x01, 0x00, ++ 0x44, 0x96, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x5a, ++ 0x99, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x99, 0x80, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x00, 0x98, 0x6c, 0x00, 0x00, 0x20, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x21, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x00, 0x8a, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x00, 0x6a, 0x06, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x00, ++ 0x80, 0xb0, 0x01, 0x00, 0x4f, 0x96, 0x52, 0x43, 0x81, 0x60, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0xf2, 0x82, 0xf4, 0x01, 0x00, 0x50, 0x96, 0x00, 0x41, ++ 0x80, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x81, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5e, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x95, 0xb0, 0x00, 0x00, ++ 0x51, 0x96, 0x9e, 0xbb, 0x80, 0x32, 0x00, 0x00, 0x56, 0x96, 0xa2, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x41, 0x95, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x15, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x2b, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x38, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x3a, 0xb0, 0x01, 0x00, 0x6b, 0x96, 0x9c, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x60, 0x96, 0xa2, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x4c, 0x1f, 0x90, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x1e, ++ 0x98, 0xf4, 0x01, 0x00, 0x5f, 0x96, 0xa2, 0x48, 0x99, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x42, 0xb1, 0x01, 0x00, 0x5f, 0x96, 0xa2, 0x8a, ++ 0xf1, 0x6d, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x02, 0xcc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x3e, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x00, 0xf4, ++ 0x28, 0xcc, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x6a, 0x96, 0x20, 0xf0, 0x3e, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x2b, 0xc0, 0x01, 0x00, ++ 0xbf, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0xf3, ++ 0x3a, 0xe0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x0c, 0x96, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x07, ++ 0x96, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x07, 0x00, 0x2a, 0x0c, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x04, ++ 0xe6, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x1c, 0x00, 0x2d, 0xf0, 0x16, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x2d, 0xf0, ++ 0x26, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x06, 0x14, 0xec, 0x00, 0x00, 0x7a, 0x96, 0x22, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x06, 0x2a, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x96, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x2a, 0x4c, 0xe1, 0xc1, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x18, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x84, 0x96, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x95, ++ 0x03, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, 0x40, 0x00, 0x00, 0x03, ++ 0xf0, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x50, 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x8f, 0x96, 0x62, 0x42, 0x61, 0x31, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x90, 0x96, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x62, 0xc9, 0x01, 0x00, 0x92, 0x96, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x95, 0x03, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x50, 0x49, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x9d, 0x96, 0x62, 0x42, 0x61, 0x31, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x9e, 0x96, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0xa0, 0x96, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x30, 0x80, 0x00, 0x4a, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0xf1, 0xb1, 0x01, 0x00, 0xc0, 0xa8, 0x3d, 0x46, ++ 0x0d, 0xe0, 0x01, 0x00, 0xff, 0x7f, 0x00, 0xa1, 0xf0, 0x89, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x09, 0x96, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x60, 0xa8, 0x97, 0xc0, 0x01, 0x00, ++ 0xaa, 0x96, 0x63, 0x42, 0x61, 0x31, 0x00, 0x00, 0x30, 0x00, 0x00, 0x4a, ++ 0x62, 0xc9, 0x01, 0x00, 0xab, 0x96, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0xf3, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x97, 0xf0, 0x01, 0x00, 0xaf, 0x96, 0x65, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xb7, 0x96, 0x22, 0xf3, 0x74, 0x06, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, ++ 0x94, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe7, 0x85, 0x01, 0x00, ++ 0x00, 0x00, 0x75, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb4, 0x96, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x36, 0xb0, 0x01, 0x00, ++ 0xc7, 0x96, 0x82, 0x41, 0x23, 0x40, 0x00, 0x00, 0xbc, 0x96, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0x98, 0x93, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, ++ 0x20, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xc2, 0x96, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xbf, 0x96, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x32, 0xb0, 0x01, 0x00, 0xc7, 0x96, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xe1, 0x94, 0x00, 0x43, 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xb0, 0x01, 0x00, 0xc9, 0x96, 0xa3, 0x15, 0x0c, 0x6c, 0x00, 0x00, ++ 0xca, 0x96, 0x00, 0x06, 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x04, 0xb0, 0x01, 0x00, 0xcc, 0x96, 0x20, 0x02, 0x1a, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x04, 0xb0, 0x01, 0x00, 0x9b, 0x97, 0x00, 0x05, ++ 0x48, 0x31, 0x01, 0x00, 0xf7, 0x96, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0xd0, 0x96, 0xa2, 0x02, 0x2a, 0x50, 0x00, 0x00, 0xf7, 0x96, 0xa2, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0xd2, 0x96, 0x22, 0x02, 0x0c, 0x50, 0x00, 0x00, ++ 0xdb, 0x96, 0x00, 0x02, 0x16, 0xc0, 0x00, 0x00, 0xda, 0x96, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xda, 0x96, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xd6, 0x96, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x73, 0x96, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0xf7, 0x96, 0x22, 0x15, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0xf6, 0x96, 0xa2, 0x02, 0x1a, 0x50, 0x00, 0x00, 0xe7, 0x96, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x70, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0xe7, 0x96, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xe3, 0x96, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x23, 0x83, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x80, 0x32, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0xf0, 0x10, 0xc8, 0x01, 0x00, 0x2f, 0x00, 0x2f, 0x5c, ++ 0x11, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0xe7, 0x91, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x1b, 0x98, 0x01, 0x00, 0xb9, 0x96, 0x20, 0x15, ++ 0x1a, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0xe0, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0xf3, 0x96, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0xb9, 0x96, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0xb9, 0x96, 0x00, 0x02, ++ 0x10, 0xc0, 0x00, 0x00, 0xf9, 0x96, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x98, 0x93, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x10, 0xb1, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0x08, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0xe0, 0xc9, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0x01, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x17, 0x00, 0x00, 0xd0, 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x40, ++ 0x27, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xb0, 0x01, 0x00, ++ 0xc3, 0x94, 0x00, 0x41, 0xa3, 0x41, 0x01, 0x00, 0x05, 0x97, 0x00, 0x41, ++ 0x27, 0xd0, 0x00, 0x00, 0x36, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x40, 0x8a, 0x30, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x80, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x14, 0xbb, 0x80, 0x32, 0x00, 0x00, 0x0e, 0x97, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x64, 0x97, 0x00, 0x40, 0x2b, 0x30, 0x01, 0x00, 0xac, 0x00, 0x2d, 0x06, ++ 0x16, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, 0x16, 0xc4, 0x01, 0x00, ++ 0x18, 0x97, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x6c, 0xf0, 0x30, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x2d, 0x40, ++ 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xf0, 0x28, 0xb0, 0x01, 0x00, ++ 0x21, 0x97, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x43, ++ 0x86, 0xc8, 0x01, 0x00, 0x00, 0x30, 0x00, 0x0b, 0x16, 0xc8, 0x01, 0x00, ++ 0x21, 0x97, 0xa4, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x44, 0x97, 0x22, 0x06, 0x80, 0x32, 0x00, 0x00, ++ 0x2f, 0x97, 0xa2, 0x06, 0x14, 0x6c, 0x00, 0x00, 0x2c, 0x97, 0x22, 0x48, ++ 0x19, 0x7c, 0x00, 0x00, 0x26, 0x97, 0xa0, 0x41, 0x17, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x31, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x20, 0x18, 0xe0, 0xb1, 0x01, 0x00, ++ 0x8b, 0x00, 0x2d, 0x48, 0x19, 0x80, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x45, ++ 0xe7, 0x7d, 0x00, 0x00, 0x8b, 0x00, 0x20, 0x45, 0xe7, 0x91, 0x01, 0x00, ++ 0x2f, 0x97, 0x00, 0x40, 0x87, 0x90, 0x00, 0x00, 0x08, 0x00, 0x00, 0x43, ++ 0x86, 0x98, 0x01, 0x00, 0x2f, 0x97, 0xa0, 0x48, 0x17, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x10, 0x50, 0x00, 0x43, 0xfc, 0xc9, 0x01, 0x00, ++ 0xa8, 0x97, 0x00, 0x30, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0x3a, 0x97, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0xab, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0x17, 0xc0, 0x01, 0x00, ++ 0x39, 0x97, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x3e, 0x97, 0x64, 0xf0, 0x82, 0xb0, 0x00, 0x00, ++ 0xa4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x3e, 0x97, 0xa2, 0xf2, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xe5, 0xb1, 0x01, 0x00, ++ 0x8c, 0x00, 0x20, 0x18, 0xe0, 0xb1, 0x01, 0x00, 0x90, 0x00, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x60, 0x06, 0x30, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x86, 0x0c, 0x80, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x49, ++ 0x19, 0x7c, 0x00, 0x00, 0xbc, 0x00, 0x2d, 0x46, 0x19, 0x90, 0x01, 0x00, ++ 0xa0, 0x00, 0xa0, 0xf2, 0xe4, 0xb1, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x10, 0x50, 0x00, 0x43, 0xfc, 0xc9, 0x01, 0x00, ++ 0xa8, 0x97, 0x00, 0x30, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x4a, ++ 0x19, 0xfc, 0x00, 0x00, 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0xcc, 0x00, 0x2d, 0xab, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0x17, 0xc0, 0x01, 0x00, 0x4d, 0x97, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xe4, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x1b, ++ 0xe0, 0xb1, 0x00, 0x00, 0x52, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0xf0, 0x00, 0x0c, 0x7e, 0x89, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x4c, ++ 0x95, 0x60, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4a, 0x18, 0x94, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x01, ++ 0xf0, 0x31, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x15, 0xe0, 0xb1, 0x00, 0x00, 0x5d, 0x97, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x17, 0x90, 0x01, 0x00, ++ 0x70, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x7a, 0x01, 0x2e, 0xfe, ++ 0x92, 0xb0, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0xf6, 0x16, 0xb0, 0x01, 0x00, ++ 0x6a, 0x97, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x45, 0xc1, 0x01, 0x00, 0x04, 0x00, 0x00, 0xa6, 0x2a, 0xb0, 0x01, 0x00, ++ 0x28, 0x00, 0x6e, 0x06, 0x82, 0xc8, 0x01, 0x00, 0x6e, 0x97, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x6e, 0x4c, 0x83, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x92, 0xc0, 0x01, 0x00, 0x6f, 0x97, 0x43, 0x30, 0x3d, 0x07, 0x00, 0x00, ++ 0x00, 0x00, 0x66, 0x9e, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x41, ++ 0x3d, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x92, 0xc0, 0x01, 0x00, ++ 0x06, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x49, ++ 0x98, 0xf4, 0x01, 0x00, 0x78, 0x97, 0x26, 0x30, 0x93, 0x04, 0x00, 0x00, ++ 0x78, 0x97, 0x90, 0x4c, 0x92, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x93, 0xc0, 0x01, 0x00, 0xff, 0xff, 0x80, 0x49, 0xec, 0xa9, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x01, ++ 0xf0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x15, 0xe0, 0xb1, 0x00, 0x00, ++ 0x7d, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x22, 0x20, ++ 0x81, 0x6c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, 0x81, 0x6c, 0x00, 0x00, ++ 0x8f, 0x97, 0x22, 0x5f, 0x81, 0x7c, 0x00, 0x00, 0x8c, 0x97, 0xa2, 0x40, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x97, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0x8c, 0x97, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, ++ 0x88, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x25, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x40, 0x8a, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x21, 0x81, 0x84, 0x00, 0x00, 0x92, 0x97, 0xa2, 0x5f, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x43, 0x19, 0x7c, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x19, 0x90, 0x01, 0x00, 0x25, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x40, 0x8a, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x96, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, ++ 0x97, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x22, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0xa0, 0x97, 0xa2, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0xb4, 0x05, 0x00, 0x02, ++ 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x02, ++ 0xf0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x13, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x08, 0xe0, 0xb1, 0x00, 0x00, 0xa5, 0x97, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0xb0, 0x00, 0x00, 0xa1, 0x80, 0xce, 0x01, 0x00, 0x04, 0x00, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x7c, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xf0, 0x98, 0xf4, 0x01, 0x00, 0xb1, 0x97, 0x20, 0x4c, ++ 0x84, 0x6c, 0x00, 0x00, 0x88, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xb1, 0x97, 0x20, 0xf2, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x98, 0x00, 0x2d, 0x14, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x98, 0xb0, 0x01, 0x00, 0xa3, 0x00, 0x2d, 0x14, ++ 0x98, 0xd0, 0x01, 0x00, 0xb6, 0x97, 0x20, 0x4c, 0x84, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x84, 0xb0, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x30, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x80, 0xe0, 0x01, 0x00, ++ 0xba, 0x97, 0x23, 0x40, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x84, 0xb0, 0x01, 0x00, 0xd0, 0x00, 0x20, 0x14, 0xe0, 0xb1, 0x01, 0x00, ++ 0x98, 0x00, 0x25, 0x42, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x6e, 0xf3, ++ 0x80, 0xf0, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x42, 0x82, 0xc0, 0x00, 0x00, ++ 0xc0, 0x97, 0xa0, 0x40, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0xf0, 0x82, 0xec, 0x00, 0x00, ++ 0x98, 0x00, 0xa0, 0x41, 0xe0, 0xb1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x37, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, ++ 0x02, 0x99, 0x00, 0x05, 0x8a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0xa8, 0x01, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0xf0, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xa7, 0x97, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcb, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xa8, 0x00, 0x2d, 0x1c, ++ 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0xf0, 0x8a, 0xd0, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0x40, 0x8b, 0xec, 0x00, 0x00, 0x8a, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xa4, 0x00, 0x2d, 0x45, 0xe0, 0xd1, 0x01, 0x00, 0xd9, 0x97, 0x9c, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0xbe, 0x00, 0x2f, 0xab, 0x83, 0xb0, 0x01, 0x00, 0x35, 0x98, 0x00, 0x14, ++ 0x82, 0x50, 0x01, 0x00, 0xde, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xde, 0x97, 0x22, 0xf2, 0x82, 0x30, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xde, 0x97, 0x9f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xbe, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x35, 0x98, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xa8, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x9c, 0x00, 0x2d, 0x30, 0x81, 0xb0, 0x01, 0x00, 0x88, 0x00, 0x2d, 0xf0, ++ 0x84, 0xb0, 0x01, 0x00, 0x94, 0x00, 0x2d, 0xf2, 0x86, 0xb0, 0x01, 0x00, ++ 0xf2, 0x97, 0x23, 0xf0, 0x84, 0x6c, 0x00, 0x00, 0xe6, 0x97, 0x23, 0x92, ++ 0x87, 0x6c, 0x00, 0x00, 0xc9, 0x04, 0x00, 0xa6, 0x94, 0xb0, 0x01, 0x00, ++ 0xe8, 0x97, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x94, 0xb0, 0x01, 0x00, 0x60, 0x89, 0x00, 0x4a, 0x94, 0x98, 0x01, 0x00, ++ 0xe8, 0x97, 0x68, 0x40, 0x81, 0x32, 0x00, 0x00, 0x04, 0x00, 0x22, 0x40, ++ 0xbd, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xb0, 0xb1, 0x01, 0x00, ++ 0xbf, 0x00, 0x2d, 0x42, 0xb2, 0xb1, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf3, ++ 0x80, 0xe0, 0x01, 0x00, 0xed, 0x97, 0xd4, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x78, 0xda, 0x84, 0xc0, 0x01, 0x00, 0xf7, 0x97, 0x23, 0x40, ++ 0x84, 0x6c, 0x00, 0x00, 0x94, 0x00, 0x20, 0x9d, 0xe1, 0xb1, 0x01, 0x00, ++ 0xf7, 0x97, 0x00, 0x40, 0x84, 0xb0, 0x00, 0x00, 0xbf, 0x00, 0x2d, 0x43, ++ 0x84, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf3, 0x80, 0xe0, 0x01, 0x00, ++ 0xf7, 0x97, 0x23, 0x40, 0x84, 0x6c, 0x00, 0x00, 0x94, 0x00, 0x20, 0x9d, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x84, 0xb0, 0x01, 0x00, ++ 0xfb, 0x97, 0xa2, 0xf0, 0x38, 0x6c, 0x00, 0x00, 0x9c, 0x00, 0x20, 0x42, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x13, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x46, 0x19, 0x80, 0x01, 0x00, 0x9c, 0x00, 0x20, 0x42, ++ 0xe0, 0xb1, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x80, 0xf4, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, ++ 0x82, 0x88, 0x01, 0x00, 0x01, 0x98, 0x23, 0x41, 0x80, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x13, 0x94, 0x01, 0x00, 0x00, 0x00, 0x89, 0x0c, ++ 0x80, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x86, 0x0c, 0x80, 0x32, 0x00, 0x00, ++ 0xbc, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xa0, 0x00, 0xa0, 0xf2, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x9f, 0x41, 0x24, 0xec, 0x00, 0x00, ++ 0x0d, 0x98, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x42, ++ 0x38, 0xec, 0x00, 0x00, 0x0d, 0x98, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xb4, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x0f, 0x98, 0xa3, 0xf0, ++ 0x3a, 0x6c, 0x00, 0x00, 0x04, 0x00, 0xa4, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x13, 0x98, 0x22, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0xb4, 0x00, 0x20, 0x1d, 0xe0, 0xb1, 0x01, 0x00, 0x80, 0x00, 0x2d, 0x5f, ++ 0x13, 0x94, 0x01, 0x00, 0x13, 0x98, 0x23, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0x80, 0x00, 0x20, 0x1d, 0xe0, 0xb1, 0x01, 0x00, 0xc0, 0x00, 0x20, 0x12, ++ 0xe0, 0xb1, 0x01, 0x00, 0xc4, 0x00, 0xa0, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x27, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x42, ++ 0x8a, 0x30, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xe0, 0xb1, 0x01, 0x00, 0x12, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x1f, 0x98, 0x9f, 0x41, 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x12, 0x8c, 0xd0, 0x01, 0x00, ++ 0x20, 0x98, 0x00, 0x41, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x78, 0x98, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x22, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xae, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0xa7, 0x08, 0x80, 0x32, 0x01, 0x00, 0x32, 0x04, 0x00, 0x40, ++ 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x08, 0x8a, 0x30, 0x01, 0x00, ++ 0x2c, 0x98, 0xa2, 0x40, 0x95, 0x6c, 0x00, 0x00, 0xc3, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x82, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, ++ 0xa0, 0x98, 0x2f, 0x40, 0x11, 0xb0, 0x01, 0x00, 0x30, 0x05, 0x00, 0x41, ++ 0x89, 0xb0, 0x00, 0x00, 0xcc, 0x00, 0x00, 0xa1, 0x80, 0xce, 0x01, 0x00, ++ 0x04, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf8, ++ 0x3e, 0xec, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x12, 0xe0, 0xed, 0x00, 0x00, ++ 0xc8, 0x00, 0x20, 0xab, 0xe1, 0xb1, 0x01, 0x00, 0xcc, 0x00, 0xa0, 0x1f, ++ 0xe0, 0xb1, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, ++ 0x38, 0x98, 0xa3, 0x5f, 0xe7, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe7, 0xc1, 0x01, 0x00, 0xa6, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x4c, 0x98, 0x22, 0xf2, 0x86, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00, 0x43, ++ 0x84, 0xf4, 0x01, 0x00, 0x01, 0x00, 0x00, 0x41, 0x80, 0xcc, 0x01, 0x00, ++ 0xb8, 0x00, 0x2d, 0x42, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x62, 0x40, ++ 0x86, 0xc0, 0x01, 0x00, 0x40, 0x98, 0x1f, 0x43, 0x80, 0x32, 0x00, 0x00, ++ 0x41, 0x98, 0xa2, 0x40, 0x87, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x62, 0x41, ++ 0x87, 0xb0, 0x01, 0x00, 0x45, 0x98, 0x9f, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x84, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x88, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x44, ++ 0x84, 0xf4, 0x01, 0x00, 0xb8, 0x00, 0x2e, 0x42, 0x80, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x62, 0x40, 0x88, 0xc0, 0x01, 0x00, 0x4b, 0x98, 0x1f, 0x44, ++ 0x80, 0x32, 0x00, 0x00, 0x4f, 0x98, 0xa2, 0x40, 0x89, 0x6c, 0x00, 0x00, ++ 0x4f, 0x98, 0x62, 0x41, 0x89, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x62, 0x41, ++ 0x86, 0xe4, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x62, 0x41, 0x88, 0xe4, 0x01, 0x00, 0xa4, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xa2, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xbc, 0x00, 0x2e, 0x43, 0x87, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x86, 0xc0, 0x01, 0x00, 0x55, 0x98, 0x20, 0x43, 0x87, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x43, 0xe5, 0xb1, 0x01, 0x00, 0x40, 0x01, 0x00, 0x43, ++ 0x80, 0xce, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x43, 0xe4, 0x31, 0x01, 0x00, ++ 0x40, 0x01, 0xe2, 0x40, 0x87, 0x98, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x05, ++ 0x48, 0x6d, 0x00, 0x00, 0x04, 0x00, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, ++ 0x88, 0x00, 0x2d, 0x44, 0x81, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf2, ++ 0x2e, 0xb0, 0x01, 0x00, 0x9c, 0x00, 0x2d, 0xf0, 0x86, 0xb0, 0x01, 0x00, ++ 0x90, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0xba, 0x00, 0x2d, 0xf0, ++ 0x98, 0xb0, 0x01, 0x00, 0x64, 0x98, 0xa2, 0x12, 0x98, 0x6c, 0x00, 0x00, ++ 0xbc, 0x00, 0x2d, 0xf2, 0x98, 0xb0, 0x01, 0x00, 0x64, 0x98, 0xa0, 0xf2, ++ 0x98, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x82, 0xb0, 0x01, 0x00, ++ 0x9c, 0x00, 0x20, 0x41, 0xe0, 0xb1, 0x01, 0x00, 0xb4, 0x00, 0x2d, 0x12, ++ 0x86, 0xd0, 0x01, 0x00, 0x67, 0x98, 0xa3, 0x41, 0xe0, 0x6d, 0x00, 0x00, ++ 0x68, 0x98, 0x00, 0xf0, 0x84, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x84, 0xb0, 0x01, 0x00, 0x80, 0x00, 0x2d, 0x43, 0x84, 0xd0, 0x01, 0x00, ++ 0x6b, 0x98, 0x9f, 0x42, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x6d, 0x98, 0xa3, 0x42, 0x14, 0x6c, 0x00, 0x00, ++ 0x6e, 0x98, 0x00, 0x0a, 0x0c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x0c, 0xb0, 0x01, 0x00, 0x70, 0x98, 0xa0, 0x17, 0x0c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x17, 0x0c, 0xb0, 0x01, 0x00, 0x75, 0x98, 0x22, 0x40, ++ 0x0d, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x0c, 0xec, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0xf0, 0x82, 0xf4, 0x01, 0x00, 0x75, 0x98, 0xa0, 0x41, ++ 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xf0, 0x80, 0x32, 0x01, 0x00, ++ 0x29, 0x00, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0xcb, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x00, 0x22, 0x03, ++ 0x80, 0x32, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x41, 0x87, 0x94, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, ++ 0x05, 0x90, 0x00, 0x00, 0x84, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0xa2, 0x05, 0x48, 0x6d, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0c, ++ 0x96, 0xf4, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x07, 0x96, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x4b, 0x19, 0x90, 0x01, 0x00, 0x05, 0x00, 0x2a, 0x0c, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x04, 0xe6, 0xb1, 0x01, 0x00, ++ 0x3e, 0x04, 0x00, 0x40, 0x89, 0x98, 0x01, 0x00, 0x02, 0x99, 0x00, 0x08, ++ 0x8a, 0x30, 0x01, 0x00, 0x8f, 0x98, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x10, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, 0x95, 0x98, 0x28, 0x40, ++ 0x87, 0x30, 0x00, 0x00, 0x90, 0x98, 0x22, 0x48, 0x77, 0x7d, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x40, 0x27, 0x6c, 0x00, 0x00, 0x04, 0x97, 0x1d, 0x46, ++ 0x87, 0xb0, 0x00, 0x00, 0x98, 0x98, 0x22, 0x5f, 0x11, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x22, 0x15, 0x62, 0x31, 0x00, 0x00, 0x96, 0x98, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x14, 0x2f, 0x4c, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x9b, 0x98, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x93, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0xb0, 0x01, 0x00, ++ 0xef, 0x98, 0x00, 0x49, 0x96, 0x30, 0x01, 0x00, 0x07, 0x00, 0x00, 0x49, ++ 0x06, 0xe4, 0x01, 0x00, 0x00, 0x39, 0x00, 0x03, 0x06, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xd0, ++ 0xa0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, ++ 0xa2, 0x98, 0xa0, 0x54, 0x93, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x05, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0xab, 0x98, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x49, 0xb3, 0x01, 0x00, 0xf5, 0x98, 0x00, 0x40, ++ 0x49, 0x31, 0x01, 0x00, 0x02, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0xb5, 0x2e, 0x08, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xb2, 0x98, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x18, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, 0x00, 0x97, 0x2e, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0xb6, 0x98, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x40, 0x18, 0x2e, 0x05, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0xba, 0x98, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x57, 0x95, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x30, 0x94, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x64, 0x00, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x56, 0x95, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xb8, 0x94, 0x20, 0x41, 0xe5, 0xb1, 0x01, 0x00, 0xba, 0x94, 0x20, 0x41, ++ 0xe5, 0xb1, 0x01, 0x00, 0x98, 0x94, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xc4, 0x98, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x6f, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x68, 0xb1, 0x01, 0x00, ++ 0xc8, 0x98, 0x85, 0x41, 0x97, 0x40, 0x00, 0x00, 0x80, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x39, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x37, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x35, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x33, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x41, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x3f, 0xb3, 0x01, 0x00, 0xee, 0x05, 0x00, 0x40, 0x25, 0x9b, 0x01, 0x00, ++ 0x42, 0x00, 0x00, 0x40, 0x4b, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x2f, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2d, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x47, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x43, 0xb3, 0x01, 0x00, 0x60, 0x00, 0x00, 0x40, 0x2b, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0xef, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0xf1, 0x93, 0x01, 0x00, 0xff, 0xff, 0x00, 0xa5, 0x3c, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x2c, 0x5b, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, ++ 0x45, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x59, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x57, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x27, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x53, 0xb3, 0x01, 0x00, ++ 0xe4, 0x98, 0xa2, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0xe4, 0x98, 0xa2, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0xe5, 0x98, 0x00, 0x40, 0x1d, 0xb3, 0x00, 0x00, ++ 0x50, 0x46, 0x00, 0x40, 0x1d, 0x9b, 0x01, 0x00, 0x00, 0xc0, 0x00, 0xa6, ++ 0x88, 0xb3, 0x01, 0x00, 0xff, 0x3f, 0x00, 0xa6, 0x3a, 0xb3, 0x01, 0x00, ++ 0x00, 0xc0, 0x00, 0x9d, 0x3b, 0x9b, 0x01, 0x00, 0xb4, 0x05, 0x00, 0x40, ++ 0x23, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x4d, 0xb3, 0x01, 0x00, ++ 0x08, 0x0a, 0x00, 0xa6, 0x14, 0xb3, 0x01, 0x00, 0x01, 0x01, 0x00, 0x8a, ++ 0x15, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x87, 0xb3, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0xa6, 0x56, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x5e, ++ 0x57, 0xb5, 0x01, 0x00, 0x18, 0x00, 0x00, 0x4b, 0x20, 0xe4, 0x01, 0x00, ++ 0x06, 0x00, 0x00, 0x4b, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x43, 0x00, 0x4b, ++ 0x96, 0xc8, 0x01, 0x00, 0x18, 0x00, 0x00, 0x10, 0x20, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x20, 0x94, 0x01, 0x00, 0x00, 0x00, 0x80, 0x57, ++ 0x21, 0x90, 0x01, 0x00, 0x00, 0x99, 0x2e, 0x0a, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0xf6, 0x98, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x00, 0xa9, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xfa, 0x98, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0xfe, 0x98, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xfe, 0x98, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x4e, 0x98, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, ++ 0x98, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x99, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x80, 0x98, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x88, 0x94, 0x01, 0x00, ++ 0x08, 0x99, 0x6a, 0x40, 0x81, 0x32, 0x00, 0x00, 0x0b, 0x99, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xf0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x62, 0xb1, 0x01, 0x00, 0x0c, 0x99, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x13, 0x99, 0x22, 0x4a, 0x89, 0x7c, 0x00, 0x00, 0x11, 0x99, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xf0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x62, 0xb1, 0x01, 0x00, 0x11, 0x99, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0f, 0x98, 0xf4, 0x01, 0x00, ++ 0x04, 0x00, 0xa2, 0x5f, 0x99, 0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, ++ 0x9a, 0xb0, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, ++ 0xae, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, ++ 0x9a, 0xb0, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x88, 0x9a, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x41, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xb2, 0x9f, 0x22, 0x40, 0x7b, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x19, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x19, 0x41, 0x7b, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0xc4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, ++ 0xc6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x2f, 0xa2, 0xc8, 0xb3, 0x01, 0x00, ++ 0x08, 0x14, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, 0xa8, 0x9f, 0x00, 0x4d, ++ 0x9a, 0xcc, 0x01, 0x00, 0xbb, 0x9f, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x49, 0xc1, 0x01, 0x00, 0xb9, 0x9f, 0xa2, 0x41, ++ 0x9b, 0x50, 0x00, 0x00, 0xbf, 0x9f, 0x80, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x52, 0x49, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xfd, 0x93, 0x01, 0x00, 0xc2, 0x9f, 0x00, 0x42, 0xcd, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x51, 0x4a, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xfd, 0x93, 0x01, 0x00, 0xc2, 0x9f, 0x00, 0x43, 0xcb, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x50, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xd2, 0x9f, 0x00, 0x40, ++ 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x9a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x49, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x40, 0xf0, ++ 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x80, 0xb2, 0x01, 0x00, ++ 0xca, 0x9f, 0x00, 0x40, 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x49, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x9a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4d, ++ 0x10, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe3, 0x43, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe4, ++ 0x45, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7b, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x48, 0x4f, 0x40, 0xb1, 0x01, 0x00, 0xd2, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0xcb, ++ 0x81, 0xc8, 0x01, 0x00, 0x22, 0x83, 0x00, 0x40, 0xf2, 0x93, 0x00, 0x00, ++ 0x55, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x18, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x22, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc6, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x43, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x41, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb8, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xed, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x23, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x27, 0x83, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb9, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x8d, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x79, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x78, 0x98, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x87, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x10, 0x95, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x0a, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb1, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x19, 0x99, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, ++ }, ++}; +diff --git a/drivers/staging/slicoss/oasisdownload.h b/drivers/staging/slicoss/oasisdownload.h +new file mode 100644 +index 0000000..89a440c +--- /dev/null ++++ b/drivers/staging/slicoss/oasisdownload.h +@@ -0,0 +1,6848 @@ ++#define OASIS_UCODE_VERS_STRING "$Revision: 1.2 $" ++#define OASIS_UCODE_VERS_DATE "$Date: 2006/03/27 15:10:37 $" ++#define OASIS_UCODE_HOSTIF_ID 3 ++ ++static LONG ONumSections = 0x2; ++static ULONG OSectionSize[] = { ++ 0x00004000, 0x00010000, ++}; ++ ++static ULONG OSectionStart[] = { ++ 0x00000000, 0x00008000, ++}; ++ ++static u8 OasisUCode[2][65536] = ++{ ++ { ++ 0x15, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x21, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x98, 0xb0, 0x01, 0x00, 0x04, 0x80, 0xa2, 0x40, 0xfd, 0x7f, 0x00, 0x00, ++ 0x09, 0x00, 0xa2, 0x49, 0xdd, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x80, 0xb2, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xd1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x80, 0xb2, 0x01, 0x00, 0x09, 0x00, 0xa2, 0x40, ++ 0x75, 0x7d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x0b, 0x00, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x8f, 0x98, 0x18, 0x31, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x98, 0x80, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x41, 0x98, ++ 0x80, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x98, 0x80, 0xe4, 0x01, 0x00, 0x0e, 0x00, 0x40, 0x98, ++ 0x80, 0x94, 0x00, 0x00, 0x11, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x19, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x19, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x0e, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x1f, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x1f, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x12, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x50, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x01, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0xa5, 0x99, 0x01, 0x00, 0x25, 0x00, 0x29, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x25, 0x00, 0x14, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x14, 0x00, 0x93, 0xbc, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xdd, 0x81, 0x01, 0x00, 0x12, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x33, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2a, 0x00, 0x14, 0xbc, ++ 0x80, 0x32, 0x00, 0x00, 0xfe, 0x00, 0x13, 0xbc, 0x80, 0x32, 0x00, 0x00, ++ 0x54, 0x95, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0xff, 0xff, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xfd, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xb3, 0x01, 0x00, ++ 0x33, 0x00, 0x18, 0xee, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x89, 0xb0, 0x01, 0x00, 0x32, 0x00, 0xa2, 0x41, 0x89, 0x50, 0x00, 0x00, ++ 0x99, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x30, 0x94, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x20, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xe0, 0xb3, 0x01, 0x00, 0x39, 0x00, 0x98, 0xee, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x80, 0xb0, 0x01, 0x00, ++ 0x3b, 0x00, 0x80, 0xf3, 0xde, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0xfd, 0x93, 0x01, 0x00, 0x3e, 0x00, 0x83, 0xf3, 0x80, 0x32, 0x00, 0x00, ++ 0xf0, 0x00, 0x00, 0xf3, 0x80, 0x88, 0x01, 0x00, 0x01, 0x80, 0x00, 0x40, ++ 0x2e, 0xdd, 0x01, 0x00, 0x00, 0x94, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x43, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0x24, 0xb1, 0x01, 0x00, 0x7c, 0x00, 0x18, 0xee, 0x80, 0x32, 0x00, 0x00, ++ 0x45, 0x00, 0x95, 0xe8, 0x80, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0xe8, ++ 0x80, 0x88, 0x01, 0x00, 0x7c, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0xec, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xd6, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xd6, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0xf8, 0xee, 0x8b, 0x01, 0x00, ++ 0x08, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0xff, 0x00, 0x00, 0xf0, ++ 0x80, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x81, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd6, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0xf8, ++ 0x80, 0x88, 0x01, 0x00, 0x3c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xf0, 0xd6, 0x8d, 0x01, 0x00, 0xff, 0xff, 0x00, 0xf0, ++ 0xf0, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0x81, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x81, 0x94, 0x01, 0x00, 0x3c, 0x01, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xd6, 0xb1, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xf8, 0x80, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x81, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x81, 0x94, 0x01, 0x00, ++ 0x3c, 0x02, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xd6, 0xb1, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0xd6, 0xb1, 0x01, 0x00, 0x1e, 0x00, 0x00, 0xf0, ++ 0x82, 0xf4, 0x01, 0x00, 0xff, 0x3f, 0x00, 0xf8, 0x80, 0xd8, 0x01, 0x00, ++ 0x64, 0x00, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x81, 0xd0, 0x01, 0x00, 0xff, 0xff, 0x00, 0x40, 0x80, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xd8, 0xb1, 0x01, 0x00, 0x68, 0x00, 0x22, 0xfa, 0x80, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x81, 0xe0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x40, ++ 0x80, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xde, 0xb1, 0x01, 0x00, ++ 0x00, 0x01, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0xfa, ++ 0x80, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x81, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd6, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0xfa, 0x80, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf6, 0x81, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xd6, 0xb1, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xfb, 0xd6, 0xe5, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, ++ 0xd5, 0x99, 0x01, 0x00, 0x18, 0x00, 0x00, 0xfb, 0xd6, 0xe5, 0x01, 0x00, ++ 0x48, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0xfa, ++ 0xd6, 0xe5, 0x01, 0x00, 0x50, 0x00, 0x00, 0x40, 0xd5, 0x99, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xfb, 0xd6, 0xe5, 0x01, 0x00, 0x03, 0x00, 0x00, 0xfb, ++ 0x7a, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0xb1, 0x01, 0x00, ++ 0x7c, 0x00, 0x00, 0x4c, 0xdd, 0x91, 0x00, 0x00, 0x7c, 0x00, 0x95, 0xe8, ++ 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xe9, 0xfa, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xd1, 0xb1, 0x01, 0x00, 0xff, 0x00, 0x00, 0x42, ++ 0x80, 0x88, 0x01, 0x00, 0x34, 0x00, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0x7c, 0x00, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x85, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x02, 0x80, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x81, 0xb0, 0x01, 0x00, 0x8e, 0x00, 0x09, 0xf9, 0x81, 0x32, 0x00, 0x00, ++ 0x8c, 0x00, 0x08, 0xf9, 0x81, 0x32, 0x00, 0x00, 0x98, 0x00, 0x1f, 0xfd, ++ 0xf9, 0x33, 0x00, 0x00, 0x8b, 0x00, 0x9e, 0xfd, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, ++ 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0xf3, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x19, 0xb1, 0x01, 0x00, 0x93, 0x00, 0x0a, 0xf9, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x40, 0xfb, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0xfd, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x07, 0x80, 0xf9, 0xf3, 0x8f, 0x01, 0x00, ++ 0x00, 0x07, 0x42, 0xf9, 0xf3, 0x8f, 0x01, 0x00, 0x97, 0x00, 0xa2, 0xff, ++ 0xf7, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0xff, 0xfb, 0xef, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfc, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x94, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xbb, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x46, 0xfd, 0x7f, 0x01, 0x00, ++ 0x00, 0x94, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xce, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x44, 0xfd, 0x7f, 0x01, 0x00, ++ 0x00, 0x94, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x9a, 0x13, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x02, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x03, 0x01, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x9a, 0x13, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x02, 0x29, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x67, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xfd, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0xfd, 0x83, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0x40, 0x25, 0x99, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x44, 0x80, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0xfd, 0x93, 0x01, 0x00, 0xe2, 0x00, 0x00, 0x40, ++ 0x83, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x45, 0x80, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x46, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x40, 0x2b, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x46, 0x88, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x94, 0x8c, 0xb0, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x46, 0x80, 0x88, 0x01, 0x00, 0xa5, 0xa5, 0xa2, 0x40, ++ 0x80, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0xf0, 0x01, 0x00, ++ 0xc9, 0x00, 0x82, 0x41, 0x89, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xfd, 0x83, 0x01, 0x00, ++ 0xd4, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x44, ++ 0x80, 0xb2, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x08, 0x83, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x45, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x44, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0x30, 0x00, 0x08, 0x83, 0x98, 0x01, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x2b, 0x99, 0x01, 0x00, 0xdb, 0x00, 0x00, 0x40, ++ 0x89, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x46, 0x80, 0xb2, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x94, 0x80, 0x88, 0x01, 0x00, 0xa5, 0xa5, 0xa2, 0x40, ++ 0x80, 0x4e, 0x01, 0x00, 0x00, 0x00, 0x80, 0x43, 0x89, 0xb0, 0x01, 0x00, ++ 0x03, 0x84, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, 0xde, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x88, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0x96, ++ 0x80, 0xb2, 0x00, 0x00, 0xdf, 0x00, 0xa2, 0x41, 0x8d, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x40, ++ 0x25, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xe0, 0x01, 0x00, ++ 0xdd, 0x00, 0x00, 0x44, 0x82, 0x14, 0x01, 0x00, 0x00, 0x00, 0x90, 0x94, ++ 0x8a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x45, 0x88, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x89, 0xd0, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x44, 0x2b, 0x41, 0x01, 0x00, ++ 0xec, 0x00, 0x08, 0x41, 0x80, 0x32, 0x00, 0x00, 0xed, 0x00, 0x00, 0x94, ++ 0x24, 0xb1, 0x00, 0x00, 0x10, 0x00, 0x00, 0x94, 0x24, 0xf5, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x94, 0xf0, 0xb1, 0x01, 0x00, 0xf2, 0x00, 0xa0, 0x44, ++ 0x89, 0x50, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x44, 0x2b, 0x41, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x94, 0xf0, 0xb1, 0x01, 0x00, 0xef, 0x00, 0x20, 0x44, ++ 0x89, 0x50, 0x00, 0x00, 0x10, 0x00, 0x00, 0x45, 0x88, 0xf4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x42, ++ 0x89, 0xd0, 0x00, 0x00, 0xf7, 0x00, 0xa0, 0xfa, 0x8a, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc0, 0x01, 0x00, 0xf5, 0x00, 0xa3, 0x42, ++ 0x89, 0x50, 0x00, 0x00, 0xff, 0xff, 0x00, 0x45, 0x88, 0x88, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x45, 0x8a, 0xf4, 0x01, 0x00, 0xfc, 0x00, 0x90, 0x44, ++ 0x8a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc0, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x45, 0x8a, 0xa8, 0x01, 0x00, 0x00, 0x00, 0x80, 0x50, ++ 0x8b, 0xe0, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x40, 0x25, 0x99, 0x01, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x2b, 0x99, 0x01, 0x00, 0x00, 0x30, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x08, 0x83, 0x14, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x94, 0x2a, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0xf9, 0x9b, 0x01, 0x00, 0xdd, 0x00, 0x00, 0xfc, 0x19, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0x40, 0x94, 0x80, 0xb2, 0x01, 0x00, 0xdd, 0x00, 0x00, 0x44, ++ 0x2b, 0x41, 0x01, 0x00, 0x00, 0x00, 0x41, 0x94, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xf9, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x2b, 0xc1, 0x01, 0x00, 0x04, 0x01, 0x9f, 0x94, 0x80, 0x32, 0x00, 0x00, ++ 0x02, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x10, 0x01, 0x00, 0x51, ++ 0x93, 0xb0, 0x00, 0x00, 0x10, 0x01, 0x00, 0x4d, 0x93, 0xb0, 0x00, 0x00, ++ 0x10, 0x01, 0x00, 0x49, 0x93, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x93, 0xb0, 0x01, 0x00, 0x10, 0x01, 0xa2, 0x41, 0x93, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x12, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x13, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x14, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x15, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x16, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x17, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x18, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x19, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x1b, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x1e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x70, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x71, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x72, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x73, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x74, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x75, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x76, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x77, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x78, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x79, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x7a, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7b, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x7d, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7e, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xa1, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x19, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x15, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x09, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x07, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x01, 0xb0, 0x01, 0x00, 0x3b, 0x01, 0x20, 0x48, 0xa1, 0x51, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x47, 0x01, 0x22, 0x4b, ++ 0x74, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x60, 0x00, 0x00, 0x4b, 0x60, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, ++ 0x7e, 0xb1, 0x01, 0x00, 0x48, 0x01, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x45, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x05, 0x00, 0x80, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x18, 0x00, 0x00, 0xaa, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x43, 0x97, 0xf0, 0x01, 0x00, 0x07, 0x00, 0x00, 0xaa, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, ++ 0xd8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x40, 0xbf, 0xb3, 0x00, 0x00, 0x5a, 0x01, 0x22, 0xcc, ++ 0x85, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, ++ 0xd0, 0x14, 0x00, 0x40, 0xa1, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe1, 0xb1, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, ++ 0x62, 0xdd, 0x01, 0x00, 0x63, 0x01, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xcc, 0x85, 0x93, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x14, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0xa4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbc, 0xb3, 0x01, 0x00, ++ 0x00, 0x14, 0x2f, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe7, ++ 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xa9, 0xb3, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0xdd, 0x81, 0x88, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0x80, 0xf4, 0x01, 0x00, 0x73, 0x01, 0x00, 0x40, 0x80, 0xc8, 0x01, 0x00, ++ 0x86, 0x01, 0x00, 0xdd, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x10, 0xb1, 0x00, 0x00, 0x87, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x88, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x89, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x8b, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc4, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x82, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x83, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, 0xb8, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x28, 0x00, 0xd4, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, ++ 0xd5, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, 0xd6, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x28, 0x00, 0xd7, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x28, 0x00, ++ 0x72, 0x01, 0x00, 0x41, 0x81, 0xc0, 0x28, 0x00, 0x55, 0x01, 0x51, 0x49, ++ 0xfd, 0x93, 0x28, 0x00, 0x55, 0x01, 0x52, 0x4a, 0xfd, 0x93, 0x2a, 0x00, ++ 0x55, 0x01, 0x55, 0x49, 0xfd, 0x83, 0x2a, 0x00, 0x55, 0x01, 0x56, 0x4a, ++ 0xfd, 0x83, 0x2a, 0x00, 0x50, 0x01, 0x91, 0x81, 0x80, 0x30, 0x2a, 0x00, ++ 0x55, 0x01, 0x45, 0x40, 0x81, 0xb2, 0x2a, 0x00, 0x50, 0x01, 0x91, 0x82, ++ 0x80, 0x30, 0x2a, 0x00, 0x55, 0x01, 0x46, 0x40, 0x81, 0xb2, 0x2a, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x89, 0xb0, 0x2b, 0x00, 0x00, 0x00, 0x2f, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x14, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0xb3, 0x01, 0x22, 0xde, 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0x92, 0x01, 0xa2, 0x44, 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xd1, 0x01, 0x00, 0x9a, 0x01, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x96, 0x01, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x50, 0x01, 0x00, 0x41, ++ 0xbf, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xbf, 0xb3, 0x01, 0x00, ++ 0x50, 0x01, 0xa0, 0x0f, 0xbd, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x49, 0xc1, 0x01, 0x00, ++ 0xb5, 0x01, 0x00, 0x40, 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x42, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, 0x85, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xde, 0x19, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x42, 0xff, ++ 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x2f, 0xff, ++ 0xe1, 0xb1, 0x01, 0x00, 0x08, 0x14, 0x00, 0xa4, 0x80, 0xcc, 0x01, 0x00, ++ 0xaa, 0x01, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x85, 0xc0, 0x01, 0x00, 0xa8, 0x01, 0xa2, 0x4c, 0x81, 0x50, 0x00, 0x00, ++ 0xb4, 0x01, 0x22, 0xd2, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x01, 0x22, 0x41, ++ 0xa5, 0x6f, 0x00, 0x00, 0x50, 0x01, 0xa2, 0xe0, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xc1, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x89, 0x90, 0x01, 0x00, 0x00, 0x00, 0x40, 0x42, 0x80, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x41, 0x43, 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x88, 0x94, 0x01, 0x00, 0x55, 0x01, 0x00, 0x44, 0xe0, 0xb1, 0x00, 0x00, ++ 0xb1, 0x01, 0x00, 0x48, 0x49, 0xc1, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x5b, ++ 0x89, 0x90, 0x00, 0x00, 0xa8, 0x9f, 0x00, 0xa0, 0x9e, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x14, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0x00, 0x00, 0x23, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0xbe, 0x01, 0x22, 0xde, 0xe1, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0xb9, 0x01, 0xa2, 0x44, 0x81, 0x6c, 0x00, 0x00, 0x50, 0x01, 0x00, 0x43, ++ 0xbf, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x40, 0xf8, 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0xf0, ++ 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x55, 0x01, 0x00, 0x40, ++ 0xe1, 0xb1, 0x00, 0x00, 0xc6, 0x01, 0x00, 0x40, 0x91, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x91, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2e, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0xcb, 0x01, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, ++ 0xd1, 0x01, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, 0x53, 0x01, 0x00, 0xde, ++ 0xa1, 0xb3, 0x00, 0x00, 0xe3, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe5, 0x01, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, 0xeb, 0x01, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x52, 0x01, 0x00, 0xdf, 0xe1, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0xa1, 0xb1, 0x01, 0x00, 0x02, 0x00, 0x00, 0xd2, 0xa5, 0xe7, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xc1, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0xdb, 0x01, 0x22, 0x44, 0xc1, 0x53, 0x00, 0x00, ++ 0xda, 0x01, 0x84, 0x41, 0x81, 0x40, 0x00, 0x00, 0xde, 0x01, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x45, 0xb1, 0x01, 0x00, ++ 0xd5, 0x01, 0x00, 0x41, 0xa1, 0xc1, 0x00, 0x00, 0xda, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x55, 0x01, 0x00, 0xdd, 0xa1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb0, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, ++ 0xda, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x40, 0x00, 0x00, 0xd3, ++ 0xa7, 0xcb, 0x01, 0x00, 0xf8, 0x02, 0x00, 0xe0, 0xa5, 0xb3, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, 0x53, 0x01, 0x00, 0xde, ++ 0xa1, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xbf, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xde, 0x81, 0x90, 0x01, 0x00, 0x50, 0x01, 0xa2, 0xba, ++ 0x80, 0x04, 0x00, 0x00, 0x60, 0x00, 0x00, 0xde, 0x61, 0x99, 0x01, 0x00, ++ 0xe8, 0x01, 0xa8, 0xb1, 0x80, 0x30, 0x00, 0x00, 0x52, 0x01, 0x00, 0x40, ++ 0xe0, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xba, 0xb3, 0x01, 0x00, ++ 0x6b, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x60, 0x02, 0x00, 0x4d, ++ 0x83, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe1, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xe3, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xe5, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xe9, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xeb, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf5, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf9, 0xb3, 0x01, 0x00, 0xf9, 0x01, 0x22, 0x40, ++ 0x8f, 0x6f, 0x00, 0x00, 0x78, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x60, 0x02, 0x00, 0xc7, 0x83, 0x30, 0x01, 0x00, 0x80, 0x02, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0x60, 0x02, 0x00, 0x42, 0x83, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe8, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe9, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xea, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xeb, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x85, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xec, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xed, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb2, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa9, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xac, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xb9, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xba, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xf0, 0xb1, 0x01, 0x00, ++ 0x0c, 0x02, 0xb8, 0x40, 0x81, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0x90, 0x01, 0x00, 0x0e, 0x02, 0xb9, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0x90, 0x01, 0x00, 0x10, 0x02, 0xba, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x81, 0x90, 0x01, 0x00, ++ 0x12, 0x02, 0xbb, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x81, 0x90, 0x01, 0x00, 0x14, 0x02, 0xbc, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x81, 0x90, 0x01, 0x00, 0x16, 0x02, 0xbd, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x81, 0x90, 0x01, 0x00, ++ 0x18, 0x02, 0xbe, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x81, 0x90, 0x01, 0x00, 0x1a, 0x02, 0xbf, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x81, 0x90, 0x01, 0x00, 0x1c, 0x02, 0xc8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x81, 0x90, 0x01, 0x00, ++ 0x1e, 0x02, 0xc9, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0x81, 0x90, 0x01, 0x00, 0x20, 0x02, 0xca, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x81, 0x90, 0x01, 0x00, 0x22, 0x02, 0xcb, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x81, 0x90, 0x01, 0x00, ++ 0x24, 0x02, 0xcc, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x81, 0x90, 0x01, 0x00, 0x26, 0x02, 0xcd, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4d, 0x81, 0x90, 0x01, 0x00, 0x28, 0x02, 0xce, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x81, 0x90, 0x01, 0x00, ++ 0x2a, 0x02, 0xcf, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x81, 0x90, 0x01, 0x00, 0x2c, 0x02, 0xf0, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x81, 0x90, 0x01, 0x00, 0x2e, 0x02, 0xf1, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x81, 0x90, 0x01, 0x00, ++ 0x30, 0x02, 0xf2, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x81, 0x90, 0x01, 0x00, 0x32, 0x02, 0xf3, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0x81, 0x90, 0x01, 0x00, 0x34, 0x02, 0xf4, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x81, 0x90, 0x01, 0x00, ++ 0x36, 0x02, 0xf5, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x81, 0x90, 0x01, 0x00, 0x38, 0x02, 0xf6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x56, 0x81, 0x90, 0x01, 0x00, 0x3a, 0x02, 0xf7, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x81, 0x90, 0x01, 0x00, ++ 0x3c, 0x02, 0xf8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x81, 0x90, 0x01, 0x00, 0x3e, 0x02, 0xf9, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x59, 0x81, 0x90, 0x01, 0x00, 0x40, 0x02, 0xfa, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x81, 0x90, 0x01, 0x00, ++ 0x42, 0x02, 0xfb, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, ++ 0x81, 0x90, 0x01, 0x00, 0x44, 0x02, 0xfc, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x81, 0x90, 0x01, 0x00, 0x46, 0x02, 0xfd, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x81, 0x90, 0x01, 0x00, ++ 0x48, 0x02, 0xfe, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x81, 0x90, 0x01, 0x00, 0x4a, 0x02, 0xff, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x81, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0xa5, 0x9b, 0x01, 0x00, ++ 0xd8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd0, 0x14, 0x2e, 0x06, 0xa5, 0xb3, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0xd3, 0xa7, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf4, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xeb, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xef, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf1, 0xb1, 0x01, 0x00, ++ 0xdb, 0x01, 0x00, 0xc7, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x66, 0x02, 0x00, 0x48, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x51, 0x40, 0x1a, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x63, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x5f, 0x02, 0x49, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x52, 0x40, 0x1c, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x4e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x68, 0x02, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x5f, 0x02, 0x4a, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, ++ 0x9e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xd8, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa1, 0xd0, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, ++ 0xd2, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xd4, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xd6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, ++ 0xdc, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xde, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x88, 0xda, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, ++ 0x8e, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xe6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xac, 0xec, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x99, ++ 0xfa, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe0, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xe2, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xe4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xe8, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xea, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, ++ 0xf4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xf6, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd5, 0xf8, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc7, ++ 0xa9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xb1, 0x01, 0x00, ++ 0x84, 0x02, 0x00, 0x40, 0x91, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x40, 0xa3, 0x9b, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0x88, 0x02, 0x00, 0x40, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb1, 0x00, 0x00, ++ 0x8d, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x98, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x98, 0x02, 0x00, 0x46, 0xa3, 0xb3, 0x00, 0x00, ++ 0x9b, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xa1, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8f, 0x02, 0x23, 0x50, 0xa5, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xa5, 0xb3, 0x01, 0x00, 0xe8, 0x02, 0x00, 0x42, ++ 0xa5, 0x63, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xba, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, 0xa1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x00, 0xb0, 0x01, 0x00, 0x97, 0x02, 0x22, 0x44, ++ 0xa5, 0x53, 0x00, 0x00, 0x94, 0x02, 0x00, 0x41, 0xa1, 0xc1, 0x00, 0x00, ++ 0x55, 0x01, 0x00, 0xdd, 0xa1, 0xb1, 0x00, 0x00, 0xe8, 0x02, 0x00, 0xde, ++ 0xa1, 0x33, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xbf, 0xb3, 0x01, 0x00, 0x50, 0x01, 0xa2, 0xd2, 0x77, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xde, ++ 0x63, 0xb1, 0x01, 0x00, 0x9e, 0x02, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x54, ++ 0xa5, 0x33, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd0, 0x14, 0x2d, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xd0, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xd2, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0xd4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0xd6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0xb1, 0x01, 0x00, ++ 0xac, 0x02, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x60, 0x02, 0x00, 0x46, ++ 0x83, 0x30, 0x01, 0x00, 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa0, 0x9e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe8, ++ 0x43, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x45, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xea, 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xeb, ++ 0xa1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x40, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd0, 0x14, 0x2e, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0xa3, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc1, 0xb3, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xdd, 0x81, 0xf4, 0x01, 0x00, 0xbd, 0x02, 0x00, 0x40, ++ 0x10, 0xc9, 0x00, 0x00, 0xc3, 0x02, 0x00, 0x05, 0x81, 0xb0, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xcb, 0x02, 0x00, 0x05, ++ 0x81, 0xb0, 0x00, 0x00, 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd0, 0x02, 0x00, 0x44, 0xa5, 0xb3, 0x00, 0x00, 0xd2, 0x02, 0x00, 0x44, ++ 0xa5, 0xb3, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xa4, 0xe7, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe0, 0x81, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0xc1, ++ 0xf0, 0x89, 0x01, 0x00, 0xc8, 0x02, 0x22, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0xc4, 0x02, 0x00, 0x41, 0xc1, 0xc3, 0x00, 0x00, 0xda, 0x02, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf8, 0x02, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x55, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0xa4, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x91, 0xb1, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0xc9, 0xf0, 0x89, 0x01, 0x00, 0xc8, 0x02, 0x22, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x41, 0xc1, 0xc3, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0xde, 0x85, 0x89, 0x01, 0x00, 0xc8, 0x02, 0x00, 0xc2, ++ 0xe0, 0xb1, 0x00, 0x00, 0xff, 0xff, 0x00, 0xde, 0x95, 0x89, 0x01, 0x00, ++ 0xc8, 0x02, 0x00, 0xca, 0xe0, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xa7, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd8, 0xa9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, 0xe2, 0x02, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcc, 0x85, 0x93, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xe7, 0xa7, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd8, ++ 0xa9, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd0, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, ++ 0xf1, 0xb1, 0x01, 0x00, 0xe1, 0x02, 0x00, 0xd4, 0xe1, 0xb1, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xcc, ++ 0x85, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xb0, 0x01, 0x00, ++ 0xfa, 0x02, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0xf9, 0x02, 0xa2, 0xf2, ++ 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcc, 0x85, 0x83, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb5, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x41, ++ 0x99, 0xb3, 0x01, 0x00, 0x0a, 0x03, 0x22, 0x44, 0x81, 0x6c, 0x00, 0x00, ++ 0x12, 0x03, 0x22, 0x48, 0x81, 0x6c, 0x00, 0x00, 0x0c, 0x03, 0x22, 0x4c, ++ 0x81, 0x6c, 0x00, 0x00, 0x16, 0x03, 0x22, 0x50, 0x81, 0x6c, 0x00, 0x00, ++ 0x17, 0x03, 0x22, 0x54, 0x81, 0x6c, 0x00, 0x00, 0x19, 0x03, 0x22, 0x58, ++ 0x81, 0x6c, 0x00, 0x00, 0x1e, 0x03, 0x22, 0x5c, 0x81, 0x6c, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, ++ 0x09, 0xb0, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0xca, 0x01, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xf3, 0x83, 0x01, 0x00, 0x10, 0x03, 0xa2, 0x42, 0x05, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x05, 0xb0, 0x01, 0x00, 0xdd, 0x9f, 0x22, 0xca, ++ 0x07, 0x14, 0x00, 0x00, 0xdd, 0x9f, 0x00, 0x45, 0xf3, 0x93, 0x00, 0x00, ++ 0xdd, 0x9f, 0x20, 0x43, 0x95, 0x6f, 0x00, 0x00, 0xdd, 0x9f, 0x80, 0xca, ++ 0x05, 0x30, 0x00, 0x00, 0xdd, 0x9f, 0x22, 0x01, 0x80, 0x30, 0x00, 0x00, ++ 0xdd, 0x9f, 0x00, 0xcb, 0xdb, 0x91, 0x00, 0x00, 0x57, 0x01, 0x00, 0xbc, ++ 0xab, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xb1, 0xb3, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, 0xff, 0x00, 0x00, 0xca, ++ 0x81, 0x88, 0x01, 0x00, 0xdd, 0x9f, 0xa2, 0x40, 0x74, 0x7d, 0x00, 0x00, ++ 0x60, 0x00, 0x20, 0x40, 0x60, 0x99, 0x01, 0x00, 0x1b, 0x03, 0xa8, 0xb1, ++ 0x82, 0x30, 0x00, 0x00, 0x1a, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xdd, 0x9f, 0x00, 0xca, 0x79, 0xb3, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xcb, 0x83, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x22, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x2d, 0x03, 0x91, 0x82, 0x82, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x8a, 0x80, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, ++ 0x80, 0xce, 0x01, 0x00, 0x2b, 0x03, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x2d, 0x03, 0x56, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0xb5, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xcd, 0x83, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x32, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x3d, 0x03, 0x91, 0x81, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, ++ 0x80, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, ++ 0x3b, 0x03, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x3d, 0x03, 0x55, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb5, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x07, 0x90, 0x01, 0x00, 0xb5, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0xd8, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0xc4, 0x14, 0x2f, 0x40, 0x99, 0xb3, 0x01, 0x00, ++ 0x57, 0x01, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x30, 0x94, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x90, 0x00, 0xf8, ++ 0x80, 0x98, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf2, 0x88, 0xe4, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0x4d, 0x03, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x40, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0x50, 0x03, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x40, 0x00, 0x00, 0x40, 0x20, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x23, 0x91, 0x01, 0x00, 0x53, 0x03, 0x1f, 0x91, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x23, 0x91, 0x01, 0x00, 0x55, 0x03, 0x1f, 0x91, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x08, 0x80, 0x40, 0x20, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x48, 0x84, 0x84, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x8f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x62, 0xb1, 0x01, 0x00, ++ 0x5a, 0x03, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x08, 0x00, 0x47, ++ 0x8e, 0xc8, 0x01, 0x00, 0x58, 0x03, 0x00, 0x5c, 0x8f, 0x80, 0x00, 0x00, ++ 0xe0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x58, 0x15, 0x2d, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2d, 0xf0, 0x88, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfa, 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x81, 0xb0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x45, 0x82, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x8b, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x82, 0x94, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x60, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8d, 0xc0, 0x01, 0x00, 0x74, 0x03, 0x22, 0x5f, 0x8d, 0x6c, 0x00, 0x00, ++ 0x65, 0x03, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x63, 0x03, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x40, 0x85, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x43, 0x86, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0xa6, 0x41, 0x85, 0x50, 0x01, 0x00, 0x70, 0x03, 0x00, 0x41, ++ 0x83, 0xe0, 0x00, 0x00, 0x6e, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x85, 0xe0, 0x01, 0x00, 0xd0, 0x14, 0x2f, 0x46, ++ 0x84, 0x94, 0x01, 0x00, 0x20, 0x00, 0x00, 0x42, 0x60, 0x99, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x07, 0x00, 0x00, 0x45, 0x80, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x8b, 0xf0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x85, 0x03, 0xa0, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x83, 0x03, 0x00, 0x41, 0x82, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x8e, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x00, 0x02, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0x00, 0x39, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x8b, 0x03, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x44, ++ 0x82, 0xf4, 0x01, 0x00, 0x1a, 0x15, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, ++ 0x70, 0x15, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x08, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x39, 0x00, 0x40, 0xe1, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x70, 0x15, 0x00, 0x43, 0x62, 0x99, 0x01, 0x00, ++ 0x95, 0x03, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x97, 0x03, 0x22, 0x5a, ++ 0x73, 0x7d, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x98, 0x03, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0x00, 0x08, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x90, 0x03, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x58, 0x15, 0x2d, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0xd0, 0x14, 0x2d, 0xf0, 0x88, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8f, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, ++ 0x90, 0xb0, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x48, 0x90, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x93, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0x8a, 0xb0, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, 0xac, 0x03, 0x22, 0x40, ++ 0x82, 0x6c, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x58, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x8d, 0xc0, 0x01, 0x00, 0xb5, 0x03, 0x22, 0x5f, 0x8d, 0x6c, 0x00, 0x00, ++ 0xa7, 0x03, 0xa2, 0x41, 0x93, 0x50, 0x00, 0x00, 0xa5, 0x03, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xff, 0x07, 0x00, 0x47, 0x84, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0xa6, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xed, 0x9f, 0x00, 0x47, ++ 0x80, 0x30, 0x01, 0x00, 0x00, 0x02, 0x00, 0x47, 0x8e, 0xc8, 0x01, 0x00, ++ 0xb0, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x50, 0xb3, 0x01, 0x00, 0xbb, 0x03, 0x20, 0x18, 0x89, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0xa6, 0x84, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, 0x55, 0x9b, 0x01, 0x00, ++ 0xbe, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0xa6, ++ 0x84, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x10, 0x00, 0x40, 0x55, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x50, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x4f, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x4e, 0xd3, 0x01, 0x00, 0x6e, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x82, 0x03, 0x00, 0x42, 0x80, 0x30, 0x01, 0x00, ++ 0xb0, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc7, 0x03, 0x22, 0xa7, ++ 0x8f, 0x6c, 0x00, 0x00, 0x5a, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xc4, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xc8, 0x14, 0x2e, 0xbb, 0x85, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xee, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xa0, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xca, ++ 0xa7, 0x33, 0x01, 0x00, 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd6, 0x03, 0x22, 0x42, ++ 0x75, 0x6f, 0x00, 0x00, 0xd8, 0x03, 0x22, 0x41, 0x75, 0x6f, 0x00, 0x00, ++ 0xda, 0x03, 0x1e, 0xca, 0x81, 0x32, 0x00, 0x00, 0xdc, 0x03, 0x1f, 0xca, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xc9, 0xb1, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0x42, 0x75, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xcd, 0xb1, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0x41, 0x75, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xcf, 0xb1, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0x40, ++ 0x75, 0xb3, 0x00, 0x00, 0x00, 0x81, 0x00, 0xa6, 0xc6, 0xb1, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, ++ 0xc6, 0xb1, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0x40, 0x75, 0xb3, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x45, 0x01, 0x00, 0x4d, 0x93, 0x30, 0x01, 0x00, ++ 0x45, 0x01, 0x00, 0x4e, 0x93, 0x30, 0x01, 0x00, 0x45, 0x01, 0x00, 0x4c, ++ 0x93, 0x30, 0x01, 0x00, 0xec, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xdd, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x54, 0x95, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xdd, 0x9f, 0x00, 0xca, 0xe5, 0xb1, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcc, 0x14, 0x2e, 0x40, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, ++ 0xa0, 0xb3, 0x01, 0x00, 0x15, 0x04, 0x00, 0x43, 0xb2, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0xda, 0x89, 0xb0, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x40, ++ 0x8b, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x89, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x89, 0xd0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x44, ++ 0x88, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x87, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xa5, 0xb3, 0x01, 0x00, 0x15, 0x04, 0x00, 0x43, ++ 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x87, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xa5, 0xc3, 0x01, 0x00, 0x0b, 0x04, 0x22, 0x44, 0x89, 0x50, 0x00, 0x00, ++ 0x0b, 0x04, 0x22, 0x44, 0x8b, 0x50, 0x00, 0x00, 0xfa, 0x03, 0xa2, 0x50, ++ 0xa5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xa5, 0xe3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xa7, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xbb, ++ 0x85, 0x30, 0x01, 0x00, 0xcc, 0x14, 0x2e, 0xd2, 0x95, 0xc3, 0x01, 0x00, ++ 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xb0, 0x01, 0x00, ++ 0x08, 0x04, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x07, 0x04, 0xa2, 0xf2, ++ 0x80, 0x30, 0x00, 0x00, 0xfa, 0x03, 0x00, 0x40, 0xa5, 0xb3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xa5, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xa7, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xbb, 0x85, 0x30, 0x01, 0x00, ++ 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x2b, 0xb1, 0x01, 0x00, ++ 0x00, 0x10, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0xdb, 0x00, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xff, 0xff, 0x00, 0x94, 0xb4, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd9, ++ 0x2b, 0xb1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, ++ 0xdd, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x94, ++ 0xb4, 0xb3, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xd9, 0x2b, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x27, 0xb1, 0x01, 0x00, 0x06, 0xc0, 0x00, 0x40, 0x2d, 0x99, 0x01, 0x00, ++ 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x02, 0xc4, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, ++ 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x05, 0x82, 0x00, 0x41, 0x2c, 0x99, 0x01, 0x00, ++ 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2d, 0x04, 0x80, 0x94, ++ 0x80, 0x32, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x28, 0x04, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x40, ++ 0x2d, 0x99, 0x01, 0x00, 0xde, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x31, 0x04, 0x00, 0x12, ++ 0x10, 0xc9, 0x00, 0x00, 0x00, 0x48, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x49, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x4b, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x4d, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x4f, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x50, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x52, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x54, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x56, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x57, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x59, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x5b, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x5d, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x5e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x60, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x62, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x64, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x65, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x67, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x69, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x6b, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x6c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x80, 0x6e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x40, 0x70, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x72, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0xc0, 0x73, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x80, 0x75, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x40, 0x77, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x79, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0xc0, 0x7a, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x80, 0x7c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x40, 0x7e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x59, 0x04, 0x00, 0x12, 0x10, 0xc9, 0x00, 0x00, ++ 0x00, 0x80, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x82, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x84, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x86, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x88, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x8a, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x8c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x8e, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x90, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x92, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x94, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x96, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x98, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0x9a, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0x9c, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0x9e, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa0, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa2, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xa4, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa6, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xa8, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xaa, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xac, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xae, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xb0, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xb2, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xb4, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xb6, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xb8, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x00, 0xba, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, ++ 0x00, 0xbc, 0x80, 0x40, 0x0b, 0x98, 0x01, 0x00, 0x00, 0xbe, 0x80, 0x40, ++ 0x0b, 0x98, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x80, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0xa6, 0x82, 0xb1, 0x01, 0x00, 0x82, 0x04, 0x85, 0x41, ++ 0x97, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x97, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x90, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, 0x92, 0xb1, 0x01, 0x00, ++ 0x87, 0x04, 0x85, 0x41, 0x97, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x90, 0x04, 0x60, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0xb1, 0x01, 0x00, ++ 0xff, 0xff, 0xf0, 0x4b, 0x82, 0x89, 0x01, 0x00, 0x93, 0x04, 0x60, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x80, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0xf0, 0xa6, 0x82, 0xb1, 0x01, 0x00, 0x96, 0x04, 0x60, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4b, 0x84, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0xf0, 0xc2, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x90, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x80, 0x4b, 0x92, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, 0x01, 0x00, 0x80, 0xa6, ++ 0x92, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4b, 0x94, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0xca, 0x94, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x00, 0x00, 0x4e, 0x98, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x98, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x98, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x88, 0x94, 0x01, 0x00, 0xa6, 0x04, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xad, 0x04, 0x22, 0x20, 0x87, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xa6, 0x04, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x1f, 0x80, 0x86, 0xb3, 0x01, 0x00, 0xb0, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x62, 0xb1, 0x01, 0x00, 0xb1, 0x04, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xb8, 0x04, 0x22, 0x4b, 0x89, 0x7c, 0x00, 0x00, 0xb6, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x62, 0xb1, 0x01, 0x00, 0xb6, 0x04, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x87, 0xb3, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x99, 0xb0, 0x01, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xc1, 0x04, 0xa8, 0xb1, 0x52, 0x33, 0x00, 0x00, 0xc6, 0x04, 0x22, 0x4b, ++ 0x53, 0x7f, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xc4, 0x04, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0xc1, 0x04, 0xa2, 0x41, ++ 0x99, 0x50, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x4f, 0x77, 0xfd, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x00, 0x00, 0x4e, 0x98, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x98, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x99, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x98, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x99, 0xe0, 0x01, 0x00, 0xd6, 0x04, 0x00, 0x4c, ++ 0x88, 0x94, 0x00, 0x00, 0xd6, 0x04, 0x47, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xdd, 0x04, 0x22, 0x20, 0x87, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xd6, 0x04, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x1f, 0x80, 0x86, 0xb3, 0x01, 0x00, 0xe0, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xf0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x62, 0xb1, 0x01, 0x00, 0xe1, 0x04, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xe8, 0x04, 0x22, 0x4a, 0x89, 0x7c, 0x00, 0x00, 0xe6, 0x04, 0x22, 0x4f, ++ 0x77, 0x7d, 0x00, 0x00, 0xf0, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x62, 0xb1, 0x01, 0x00, 0xe6, 0x04, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x87, 0xb3, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x99, 0xb0, 0x01, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xf1, 0x04, 0xa8, 0xb1, 0x52, 0x33, 0x00, 0x00, 0xf6, 0x04, 0x22, 0x4a, ++ 0x53, 0x7f, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xf4, 0x04, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, 0xf1, 0x04, 0xa2, 0x41, ++ 0x99, 0x50, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x4f, 0x77, 0xfd, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x00, 0x05, 0xa8, 0xb1, 0x80, 0x30, 0x00, 0x00, 0x12, 0x05, 0x1d, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x40, 0x18, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, 0x10, 0x05, 0xa2, 0x40, ++ 0x86, 0x04, 0x00, 0x00, 0xde, 0x9f, 0x9c, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x40, 0x88, 0x88, 0x01, 0x00, 0x30, 0x05, 0x00, 0x50, ++ 0x47, 0x31, 0x01, 0x00, 0x36, 0x00, 0x00, 0x44, 0x88, 0xcc, 0x01, 0x00, ++ 0x0c, 0x05, 0x52, 0x40, 0x81, 0x32, 0x00, 0x00, 0x30, 0x05, 0x00, 0x40, ++ 0x47, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x89, 0xb0, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x48, 0x47, 0x31, 0x01, 0x00, 0x30, 0x05, 0x00, 0x05, ++ 0x47, 0x31, 0x01, 0x00, 0xde, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x1b, 0x00, 0xde, 0x9f, 0x00, 0x41, ++ 0xe1, 0xc1, 0x1a, 0x00, 0x78, 0x18, 0x00, 0x40, 0x49, 0x99, 0x1b, 0x00, ++ 0x19, 0x05, 0x22, 0x54, 0x81, 0x7c, 0x1a, 0x00, 0x14, 0x05, 0x42, 0x40, ++ 0x81, 0x32, 0x1a, 0x00, 0x00, 0x82, 0x00, 0xb3, 0x67, 0xdf, 0x1b, 0x00, ++ 0x00, 0x00, 0x1a, 0x44, 0x93, 0x93, 0x1b, 0x00, 0x28, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x1b, 0x00, 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0x27, 0x05, 0x0f, 0x40, 0x80, 0x32, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x40, ++ 0x88, 0x88, 0x01, 0x00, 0x30, 0x05, 0x00, 0x50, 0x47, 0x31, 0x01, 0x00, ++ 0x36, 0x00, 0x00, 0x44, 0x88, 0xcc, 0x01, 0x00, 0x1f, 0x05, 0x99, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xd0, 0x01, 0x00, ++ 0x21, 0x05, 0x9b, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x89, 0xd0, 0x01, 0x00, 0x23, 0x05, 0x1f, 0x44, 0x80, 0x32, 0x00, 0x00, ++ 0x30, 0x05, 0x00, 0x40, 0x47, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x89, 0xb0, 0x01, 0x00, 0x30, 0x05, 0x00, 0x48, 0x47, 0x31, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x58, 0x47, 0x31, 0x01, 0x00, 0xde, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x00, 0x00, 0x40, 0x86, 0xf4, 0x01, 0x00, ++ 0x6f, 0x00, 0x00, 0x43, 0x86, 0x88, 0x01, 0x00, 0xde, 0x9f, 0x26, 0x05, ++ 0x47, 0x31, 0x00, 0x00, 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, ++ 0xde, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x44, 0xf0, 0x41, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0xe1, 0xc1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x07, ++ 0x91, 0x30, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x97, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x05, 0x91, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x4c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x44, 0x05, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0x45, 0x05, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xf5, 0xb1, 0x01, 0x00, 0x10, 0x04, 0x00, 0x42, ++ 0xb3, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf5, 0xb1, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xf5, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, ++ 0xf7, 0xf5, 0x01, 0x00, 0x50, 0x00, 0x00, 0x40, 0x91, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x8f, 0xb0, 0x01, 0x00, 0x10, 0x04, 0x00, 0x48, ++ 0xb2, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0xf7, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x91, 0xc0, 0x01, 0x00, 0x50, 0x05, 0xa2, 0x41, 0x8f, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x45, 0xd1, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xfd, 0xb1, 0x01, 0x00, 0x38, 0x05, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x91, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x6e, 0xda, ++ 0x8f, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0xda, ++ 0xfd, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x7a, 0x05, 0x22, 0x45, 0xfd, 0x7f, 0x00, 0x00, 0x40, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xdb, 0x9f, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x15, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x78, 0x05, 0xa2, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0x7d, 0x05, 0x22, 0x20, 0xb5, 0x6f, 0x00, 0x00, 0x7a, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xda, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x1f, 0x00, ++ 0x7d, 0x05, 0x22, 0x40, 0x97, 0x6c, 0x1e, 0x00, 0x7a, 0x05, 0x42, 0x40, ++ 0x81, 0x32, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x67, 0x93, 0x1f, 0x00, ++ 0xdf, 0x9f, 0x00, 0x58, 0x67, 0x93, 0x1e, 0x00, 0x54, 0x16, 0x00, 0x40, ++ 0x47, 0x99, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x1f, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x46, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, 0xf7, 0xf5, 0x01, 0x00, ++ 0x48, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x97, 0xb0, 0x01, 0x00, 0x10, 0x04, 0x00, 0x4a, 0xb2, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xda, 0xf7, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x00, 0xda, ++ 0xf7, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x95, 0xc0, 0x01, 0x00, ++ 0x90, 0x05, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x40, ++ 0xa5, 0x9b, 0x01, 0x00, 0x40, 0x16, 0x00, 0x40, 0xa1, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xa7, 0xb3, 0x01, 0x00, 0xe1, 0x9f, 0x00, 0xbb, ++ 0x85, 0x30, 0x01, 0x00, 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb8, 0x05, 0x22, 0x45, 0xfd, 0x7f, 0x00, 0x00, 0xe0, 0x15, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x1a, 0x00, 0x00, 0xa2, 0x80, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0xf0, 0x15, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, ++ 0x62, 0xdd, 0x01, 0x00, 0xa7, 0x05, 0xa8, 0xbb, 0xe1, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x83, 0xb0, 0x01, 0x00, 0xaa, 0x05, 0xa2, 0x41, ++ 0x83, 0x50, 0x00, 0x00, 0xa9, 0x05, 0xa2, 0xf2, 0x82, 0x30, 0x00, 0x00, ++ 0x4c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb0, 0x05, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x40, 0xb3, 0x9b, 0x01, 0x00, ++ 0xb1, 0x05, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0xb3, 0x9b, 0x01, 0x00, 0xf0, 0x15, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb8, 0x05, 0xa2, 0xfa, ++ 0xb4, 0x6f, 0x00, 0x00, 0x10, 0x04, 0x00, 0x42, 0xb3, 0x43, 0x01, 0x00, ++ 0xb8, 0x05, 0xa2, 0xfa, 0xb4, 0x6f, 0x00, 0x00, 0x10, 0x04, 0x00, 0x42, ++ 0xb3, 0x43, 0x01, 0x00, 0xbb, 0x05, 0x22, 0xfa, 0xb4, 0x6f, 0x00, 0x00, ++ 0xb8, 0x05, 0x42, 0x40, 0x81, 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x67, 0x93, 0x21, 0x00, 0xdf, 0x9f, 0x00, 0x58, 0x67, 0x93, 0x20, 0x00, ++ 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x21, 0x00, 0xdb, 0x9f, 0x00, 0x40, ++ 0x49, 0x31, 0x21, 0x00, 0xf6, 0x15, 0x00, 0x40, 0x43, 0x99, 0x21, 0x00, ++ 0x5c, 0x16, 0x00, 0x40, 0x45, 0x99, 0x21, 0x00, 0x00, 0x00, 0x6e, 0xfa, ++ 0x8e, 0xb0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xb4, 0xb3, 0x01, 0x00, 0xc9, 0x05, 0xa2, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0xfc, 0x15, 0x20, 0x20, 0xe1, 0xb1, 0x01, 0x00, 0xce, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x24, 0x00, 0xda, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x25, 0x00, ++ 0xce, 0x05, 0x22, 0x40, 0x97, 0x6c, 0x24, 0x00, 0xcb, 0x05, 0x42, 0x40, ++ 0x81, 0x32, 0x24, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x67, 0x93, 0x25, 0x00, ++ 0xdf, 0x9f, 0x00, 0x58, 0x67, 0x93, 0x24, 0x00, 0x38, 0x05, 0x00, 0x40, ++ 0x81, 0x32, 0x25, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x25, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd3, 0x05, 0x22, 0x50, ++ 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x91, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xf6, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x20, 0x04, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xf8, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x20, 0x04, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfa, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x20, 0x04, 0x00, 0xf2, 0xb4, 0x33, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xfc, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x94, 0xb0, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x4a, 0xb4, 0x8b, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x4a, 0xb4, 0xf7, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x38, 0x05, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe9, 0x05, 0x22, 0x50, 0xb5, 0x6f, 0x00, 0x00, ++ 0xea, 0x05, 0x00, 0x50, 0xb5, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xb5, 0xb3, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xe0, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x16, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x30, 0x31, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x32, 0x33, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x34, 0x35, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x36, 0x37, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x38, 0x39, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x41, 0x42, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x43, 0x44, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x45, 0x46, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x47, 0x48, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x49, 0x4a, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf7, 0xb1, 0x01, 0x00, ++ 0xfc, 0x05, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x80, 0x16, 0x2e, 0x06, ++ 0x83, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0xff, 0x05, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x22, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf6, 0xb1, 0x01, 0x00, ++ 0x02, 0x06, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x62, 0x00, 0x00, 0x40, ++ 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x16, 0x2d, 0x06, 0x83, 0xb0, 0x01, 0x00, 0x80, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x5c, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0x08, 0x06, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xf9, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf9, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x70, 0x95, 0xb0, 0x01, 0x00, ++ 0x14, 0x06, 0x22, 0x70, 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x45, 0x67, 0x00, 0xa6, 0xe0, 0xb2, 0x01, 0x00, 0x01, 0x23, 0x00, 0x70, ++ 0xe1, 0x9a, 0x01, 0x00, 0xcd, 0xef, 0x00, 0xa6, 0xe2, 0xb2, 0x01, 0x00, ++ 0x89, 0xab, 0x00, 0x71, 0xe3, 0x9a, 0x01, 0x00, 0xba, 0x98, 0x00, 0xa6, ++ 0xe4, 0xb2, 0x01, 0x00, 0xfe, 0xdc, 0x00, 0x72, 0xe5, 0x9a, 0x01, 0x00, ++ 0x32, 0x10, 0x00, 0xa6, 0xe6, 0xb2, 0x01, 0x00, 0x76, 0x54, 0x00, 0x73, ++ 0xe7, 0x9a, 0x01, 0x00, 0xd2, 0xc3, 0x00, 0xa6, 0xe8, 0xb2, 0x01, 0x00, ++ 0xf0, 0xe1, 0x00, 0x74, 0xe9, 0x9a, 0x01, 0x00, 0x80, 0x16, 0x00, 0x4a, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf7, 0xb1, 0x01, 0x00, 0x25, 0x06, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x80, 0x16, 0x00, 0x4a, 0x44, 0xc9, 0x01, 0x00, 0xfc, 0x16, 0x2a, 0x47, ++ 0xe7, 0xb5, 0x01, 0x00, 0x03, 0x00, 0x00, 0x4a, 0xe8, 0xe5, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, ++ 0xa3, 0x99, 0x01, 0x00, 0x80, 0x16, 0x3d, 0x46, 0x8d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x40, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0x2e, 0x06, 0xa2, 0x41, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xeb, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xed, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xef, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf1, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf3, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x41, ++ 0x80, 0x88, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, 0xa2, 0xc9, 0x01, 0x00, ++ 0x4b, 0x06, 0xa0, 0x50, 0x83, 0x6c, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x40, ++ 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x99, 0x84, 0x01, 0x00, ++ 0x50, 0x03, 0x00, 0x4c, 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x86, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0x98, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x99, 0x84, 0x01, 0x00, 0x50, 0x03, 0x00, 0x4c, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x86, 0xa4, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x40, 0x98, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x99, 0x84, 0x01, 0x00, 0x50, 0x03, 0x00, 0x4c, 0xa2, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x86, 0xa4, 0x01, 0x00, 0x50, 0x03, 0x00, 0x40, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40, 0xa4, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x20, 0x88, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x41, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, 0x94, 0x01, 0x00, ++ 0x05, 0x00, 0x00, 0x75, 0x89, 0xe4, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x75, ++ 0x85, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x84, 0x94, 0x01, 0x00, ++ 0x55, 0x06, 0xa3, 0x53, 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, 0x89, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x76, 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x8b, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x64, 0x06, 0x00, 0x45, 0x88, 0x94, 0x00, 0x00, 0x27, 0x00, 0x00, 0x41, ++ 0x80, 0xce, 0x01, 0x00, 0x5a, 0x06, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x76, 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x89, 0xa4, 0x01, 0x00, 0x64, 0x06, 0x00, 0x78, 0x89, 0xa4, 0x00, 0x00, ++ 0x3b, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, 0x57, 0x06, 0xaa, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x89, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x77, 0x89, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x76, ++ 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x88, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0x8b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, 0x8b, 0x84, 0x01, 0x00, ++ 0x64, 0x06, 0x00, 0x45, 0x88, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x84, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x84, 0xc0, 0x01, 0x00, 0x6b, 0x06, 0xa3, 0x53, ++ 0x83, 0x6c, 0x00, 0x00, 0x82, 0x5a, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, ++ 0x99, 0x79, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, 0x78, 0x06, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x27, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, ++ 0x70, 0x06, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, 0xd9, 0x6e, 0x00, 0xa6, ++ 0x84, 0xc0, 0x01, 0x00, 0xa1, 0xeb, 0x00, 0x42, 0x84, 0xc8, 0x01, 0x00, ++ 0x78, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x41, ++ 0x80, 0xce, 0x01, 0x00, 0x75, 0x06, 0xaa, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x1b, 0x8f, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, 0xdc, 0xbc, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x78, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x62, 0xca, 0x00, 0xa6, 0x84, 0xc0, 0x01, 0x00, 0xd6, 0xc1, 0x00, 0x42, ++ 0x84, 0xc8, 0x01, 0x00, 0x78, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x78, 0xf3, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x77, ++ 0xf1, 0xb2, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x76, 0x89, 0xe4, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x76, 0xef, 0xf6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xee, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x75, 0xed, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xea, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x83, 0xc0, 0x01, 0x00, 0x4f, 0x00, 0x00, 0x41, 0x80, 0xce, 0x01, 0x00, ++ 0x37, 0x06, 0x2a, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, ++ 0xe1, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x76, 0xe3, 0xc2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x77, 0xe5, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x78, ++ 0xe7, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0xe9, 0xc2, 0x01, 0x00, ++ 0x2b, 0x06, 0x81, 0x41, 0x8d, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xfd, 0x93, 0x01, 0x00, 0x40, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0xdb, 0x9f, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x15, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb9, 0x06, 0x22, 0x40, 0x8f, 0x6c, 0x00, 0x00, ++ 0xda, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb9, 0x06, 0xa2, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x5e, 0x16, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x7c, 0x16, 0x20, 0xf6, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x31, 0xb3, 0x01, 0x00, 0x9d, 0x06, 0x22, 0x4f, 0x8f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x51, 0xfd, 0x93, 0x01, 0x00, 0x9f, 0x06, 0x22, 0x40, ++ 0x8f, 0x7c, 0x00, 0x00, 0xa3, 0x06, 0x00, 0x54, 0xfd, 0x93, 0x00, 0x00, ++ 0xa1, 0x06, 0x22, 0x42, 0x8f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, ++ 0xfd, 0x93, 0x01, 0x00, 0xa3, 0x06, 0x22, 0x41, 0x8f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x53, 0xfd, 0x93, 0x01, 0x00, 0xb7, 0x06, 0x22, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0x38, 0x05, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb2, 0x06, 0xa2, 0x40, 0xb5, 0x6f, 0x00, 0x00, ++ 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x48, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, 0x97, 0xc0, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0x4b, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0xb5, 0xb3, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xb6, 0x06, 0x22, 0x40, 0xb5, 0x6f, 0x00, 0x00, 0xba, 0x06, 0x00, 0x54, ++ 0xfd, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xfd, 0x83, 0x01, 0x00, ++ 0x1c, 0x00, 0x00, 0xfe, 0x7f, 0xd9, 0x01, 0x00, 0xba, 0x06, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xfd, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe7, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc4, 0x06, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xe9, 0x9f, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x3c, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x14, 0x02, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x34, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x32, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, 0x0a, 0xc8, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x0e, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, ++ 0x0c, 0xc8, 0x01, 0x00, 0xea, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x0a, 0x07, 0x22, 0x01, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0xa4, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0xd9, 0x06, 0xa3, 0x07, 0x02, 0x6c, 0x00, 0x00, ++ 0xda, 0x06, 0x68, 0x01, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x07, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x0a, 0xc0, 0x01, 0x00, 0xec, 0x06, 0x22, 0x40, ++ 0x03, 0x6c, 0x00, 0x00, 0xe6, 0x06, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x23, 0x07, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0xe3, 0x06, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0xe8, 0x06, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x23, 0x07, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0xee, 0x06, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, ++ 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x22, 0x00, 0x00, 0x19, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x0f, 0x00, 0x00, 0xf2, 0x3a, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x3b, 0xe0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x14, 0x02, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x01, 0x00, 0xfa, 0x06, 0x23, 0x1a, ++ 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0xc0, 0x01, 0x00, ++ 0x23, 0x07, 0x00, 0x01, 0x34, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x2d, 0x1d, ++ 0x48, 0xc1, 0x01, 0x00, 0xf0, 0x00, 0x00, 0xf2, 0x30, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x31, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0x02, 0xc0, 0x01, 0x00, 0x02, 0x07, 0x22, 0x1a, ++ 0x02, 0x50, 0x00, 0x00, 0x23, 0x07, 0x00, 0x01, 0x34, 0xc0, 0x00, 0x00, ++ 0x22, 0x00, 0x00, 0x19, 0x48, 0xc9, 0x01, 0x00, 0x02, 0x00, 0x2d, 0x14, ++ 0x48, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x14, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1d, 0x14, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x14, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x24, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x17, 0x10, 0xc8, 0x01, 0x00, 0x23, 0x07, 0x00, 0x1a, ++ 0x10, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x0f, 0x07, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, ++ 0x10, 0x07, 0x60, 0x07, 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x60, 0x12, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x0d, 0x16, 0x94, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x0b, 0x16, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, 0x17, 0x07, 0xa8, 0x5c, ++ 0x1f, 0x10, 0x00, 0x00, 0x40, 0x07, 0x22, 0x0d, 0x14, 0x50, 0x00, 0x00, ++ 0x40, 0x07, 0x22, 0x0d, 0x24, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x10, 0xc0, 0x01, 0x00, 0x1e, 0x07, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, ++ 0x23, 0x07, 0x00, 0x41, 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x1f, 0x07, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x3f, 0x07, 0xa2, 0x0d, 0x0e, 0x50, 0x00, 0x00, 0x2e, 0x07, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x2c, 0x07, 0x22, 0xf2, ++ 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x29, 0x07, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x04, 0xb0, 0x01, 0x00, 0x33, 0x07, 0x1f, 0xf0, 0x0e, 0x30, 0x00, 0x00, ++ 0xd3, 0x06, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x5f, ++ 0x0f, 0x80, 0x01, 0x00, 0xd3, 0x06, 0x23, 0x07, 0x14, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x24, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x3c, 0x07, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0xd3, 0x06, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, 0xd3, 0x06, 0x00, 0x0d, ++ 0x18, 0xc0, 0x00, 0x00, 0x5f, 0x07, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x19, 0x0a, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x0a, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0x02, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0x0d, 0x00, 0x2d, 0x1d, 0x48, 0xc1, 0x01, 0x00, ++ 0x09, 0x00, 0x00, 0xf3, 0x38, 0x88, 0x01, 0x00, 0x0d, 0x00, 0x20, 0x50, ++ 0xe7, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x2d, 0x40, 0x3f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf4, 0x32, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x14, 0x48, 0xc1, 0x01, 0x00, 0x02, 0x00, 0x00, 0x1d, ++ 0x94, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x91, 0xb0, 0x01, 0x00, ++ 0x52, 0x07, 0xa0, 0xfc, 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x91, 0xc0, 0x01, 0x00, 0x50, 0x07, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0x96, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x48, 0xc1, 0x01, 0x00, 0x02, 0x00, 0x00, 0x18, 0x94, 0xf4, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x18, 0x90, 0xb0, 0x01, 0x00, 0x5c, 0x07, 0xa0, 0xfc, ++ 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x91, 0xc0, 0x01, 0x00, ++ 0x5a, 0x07, 0xa2, 0x41, 0x95, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xe0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x80, 0xb0, 0x2d, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x16, 0xb0, 0x2d, 0x00, ++ 0x22, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x48, 0xc1, 0x2d, 0x00, 0x64, 0x07, 0x43, 0x30, 0x3d, 0x07, 0x2c, 0x00, ++ 0x00, 0x00, 0x00, 0x9e, 0x85, 0xb0, 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x41, ++ 0x3d, 0xc3, 0x2d, 0x00, 0x04, 0x00, 0x20, 0x42, 0xec, 0xb1, 0x2d, 0x00, ++ 0x00, 0x00, 0x00, 0x1e, 0x82, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x2e, 0x1d, ++ 0x82, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x18, 0x82, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x80, 0xc0, 0x01, 0x00, 0x6e, 0x07, 0xa0, 0x41, ++ 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x92, 0xf4, 0x01, 0x00, 0x0a, 0x00, 0x2e, 0x30, ++ 0x81, 0x84, 0x01, 0x00, 0x72, 0x07, 0x90, 0x40, 0x92, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x93, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x48, 0xc1, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x19, 0xe8, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1e, ++ 0x16, 0xc0, 0x01, 0x00, 0x78, 0x07, 0xa0, 0x19, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x0d, 0x00, 0x2f, 0x1e, ++ 0x32, 0xc0, 0x01, 0x00, 0x7d, 0x07, 0xa2, 0x40, 0x15, 0x6c, 0x00, 0x00, ++ 0x7c, 0x07, 0xa0, 0x1c, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x63, 0xf3, 0x38, 0x94, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x05, 0x48, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x1e, ++ 0x98, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0x1a, 0x98, 0xc0, 0x01, 0x00, ++ 0x0c, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x8b, 0x07, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x89, 0x07, 0x22, 0xf2, ++ 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x86, 0x07, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x1a, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, ++ 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, ++ 0x91, 0x07, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x9b, 0x07, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x2d, 0x10, 0x48, 0xc1, 0x01, 0x00, 0x9b, 0x07, 0x22, 0xf2, ++ 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x98, 0x07, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xeb, 0x9f, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x20, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe4, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, 0xa1, 0x07, 0x90, 0xf2, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x10, 0x00, 0x00, 0x14, ++ 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x2a, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x2b, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x2a, 0x94, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xac, 0x07, 0x22, 0xf2, 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xa9, 0x07, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xe3, 0x9f, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x17, 0x10, 0xdc, 0x01, 0x00, ++ 0xc9, 0x07, 0x22, 0x40, 0x15, 0x6c, 0x00, 0x00, 0xb4, 0x07, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x1f, 0x90, 0x01, 0x00, ++ 0xb3, 0x07, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x88, ++ 0x1c, 0xcc, 0x01, 0x00, 0xe4, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x3f, 0xc3, 0x01, 0x00, 0xe6, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb7, 0x07, 0xa2, 0x41, 0x87, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x1e, 0x3e, 0xc0, 0x01, 0x00, 0xc9, 0x07, 0x22, 0x40, ++ 0x15, 0x6c, 0x00, 0x00, 0xba, 0x07, 0x20, 0x1e, 0x14, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x3c, 0xb0, 0x01, 0x00, 0xe5, 0x9f, 0x00, 0x1e, ++ 0x24, 0x30, 0x01, 0x00, 0xbf, 0x07, 0x22, 0x08, 0x2e, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x11, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1a, ++ 0x10, 0xc0, 0x01, 0x00, 0x23, 0x07, 0x00, 0x40, 0x17, 0xb0, 0x00, 0x00, ++ 0xe4, 0x9f, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xe5, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xbc, 0x07, 0xa2, 0x08, 0x2e, 0x30, 0x00, 0x00, ++ 0x80, 0x80, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x04, 0xe0, 0x31, 0x00, 0x00, 0xe8, 0x9f, 0x00, 0x1f, ++ 0x8c, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0xe2, 0x9f, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0x99, 0x01, 0x00, 0x04, 0x00, 0x22, 0x04, 0xe0, 0x31, 0x00, 0x00, ++ 0xe6, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xce, 0x07, 0xa2, 0x41, ++ 0x87, 0x7c, 0x00, 0x00, 0xcf, 0x07, 0x00, 0x1e, 0x3e, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x1f, 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0xe8, 0x9f, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, ++ 0xe2, 0x9f, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xf7, 0x07, 0x00, 0xbc, 0x80, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x03, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x03, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, ++ }, ++ { ++ 0x31, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x34, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x35, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0x80, 0x81, 0x80, ++ 0x80, 0x32, 0x00, 0x00, 0x0e, 0x87, 0xa2, 0x40, 0x91, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x90, 0xb3, 0x01, 0x00, 0x5c, 0x95, 0x2e, 0xa2, ++ 0x80, 0xb0, 0x01, 0x00, 0xff, 0x00, 0x00, 0x80, 0xf4, 0x89, 0x01, 0x00, ++ 0x90, 0x95, 0x2a, 0xc8, 0xe5, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd0, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd2, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xd3, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xee, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x44, 0xb1, 0x01, 0x00, 0x18, 0x80, 0x11, 0x81, ++ 0x98, 0x30, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x1a, 0x80, 0x11, 0x82, 0x98, 0x30, 0x00, 0x00, 0x00, 0x00, 0x52, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x0e, 0x87, 0x00, 0x48, 0xfd, 0x93, 0x00, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x23, 0x80, 0xa2, 0x42, ++ 0xfd, 0x7f, 0x00, 0x00, 0x20, 0x80, 0x00, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x22, 0x80, 0x11, 0x81, 0x82, 0x30, 0x00, 0x00, 0x22, 0x80, 0x51, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x22, 0x80, 0x11, 0x82, 0x82, 0x30, 0x00, 0x00, ++ 0x22, 0x80, 0x52, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2c, 0x80, 0x00, 0x48, ++ 0xfd, 0x93, 0x00, 0x00, 0x27, 0x80, 0x00, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x26, 0x80, 0xa2, 0x53, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x51, 0x53, ++ 0x07, 0x90, 0x01, 0x00, 0x2a, 0x80, 0x00, 0x52, 0x07, 0x90, 0x00, 0x00, ++ 0x29, 0x80, 0xa2, 0x52, 0x07, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x52, 0x52, ++ 0x07, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, 0x07, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0xf3, 0x93, 0x01, 0x00, 0x5c, 0x95, 0x2e, 0xa2, 0x52, 0xb3, 0x01, 0x00, ++ 0xff, 0x00, 0x00, 0x80, 0xf4, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x45, 0xb1, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x4c, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x55, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xaf, 0x82, 0x05, 0x40, 0x49, 0xb1, 0x00, 0x00, 0xaf, 0x82, 0x05, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x4c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0xde, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xfd, 0x83, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, ++ 0x9b, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x9c, 0xb3, 0x01, 0x00, ++ 0x48, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x58, 0x95, 0x20, 0x44, ++ 0xe0, 0xb1, 0x01, 0x00, 0x04, 0x94, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x24, 0xb1, 0x01, 0x00, 0x00, 0x0c, 0x00, 0xee, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x97, 0xf0, 0x01, 0x00, ++ 0x44, 0x80, 0xa2, 0x43, 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xfd, 0x93, 0x01, 0x00, 0x00, 0xc0, 0x00, 0xa6, 0x36, 0xb1, 0x01, 0x00, ++ 0xd0, 0x14, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x00, 0x38, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x00, 0x06, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x05, 0x10, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, ++ 0x02, 0x09, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0xf5, 0x99, 0x01, 0x00, 0x60, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x88, 0x03, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xa0, 0x03, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xa2, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x9a, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x60, 0x95, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x70, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x49, 0xdd, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x91, 0xb3, 0x01, 0x00, 0xe0, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb3, 0x01, 0x00, 0x5c, 0x95, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x27, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x90, 0x06, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x2f, 0x81, 0x01, 0x00, 0x8d, 0x81, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xe5, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x45, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x55, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xdd, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x41, 0xe1, 0xc1, 0x00, 0x00, 0x78, 0x18, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0x19, 0x05, 0x22, 0x54, 0x81, 0x7c, 0x00, 0x00, ++ 0x6c, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0xb4, ++ 0x69, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x18, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x40, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x7d, 0x80, 0x22, 0x40, ++ 0x97, 0x6c, 0x00, 0x00, 0x7a, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x69, 0x93, 0x01, 0x00, 0x38, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x54, 0x16, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0xf4, 0xb1, 0x01, 0x00, 0x80, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x80, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0x69, 0x93, 0x01, 0x00, 0x38, 0x81, 0x00, 0x58, ++ 0x69, 0x93, 0x00, 0x00, 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x40, 0x05, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0xf6, 0x15, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x5c, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x6e, 0xfa, 0x8e, 0xb0, 0x01, 0x00, 0xc1, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x96, 0x80, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x96, 0x80, 0x22, 0x40, 0x97, 0x6c, 0x00, 0x00, ++ 0x93, 0x80, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x69, 0x93, 0x01, 0x00, 0x38, 0x81, 0x00, 0x58, 0x69, 0x93, 0x00, 0x00, ++ 0x38, 0x05, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, ++ 0xb2, 0xcb, 0x01, 0x00, 0xd0, 0x05, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x83, 0x02, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xb8, 0x02, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd4, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd5, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xd6, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd7, 0x9f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x72, 0x01, 0x00, 0x41, ++ 0x81, 0xc0, 0x00, 0x00, 0x55, 0x01, 0x51, 0x48, 0xfd, 0x93, 0x00, 0x00, ++ 0x55, 0x01, 0x52, 0x48, 0xfd, 0x93, 0x00, 0x00, 0x55, 0x01, 0x55, 0x49, ++ 0xfd, 0x83, 0x00, 0x00, 0x55, 0x01, 0x56, 0x4a, 0xfd, 0x83, 0x00, 0x00, ++ 0x50, 0x01, 0x91, 0x81, 0x80, 0x30, 0x00, 0x00, 0x55, 0x01, 0x45, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x50, 0x01, 0x91, 0x82, 0x80, 0x30, 0x00, 0x00, ++ 0x55, 0x01, 0x46, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x89, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x00, 0x05, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x48, 0xc1, 0x01, 0x00, ++ 0xb4, 0x80, 0x43, 0x30, 0x3d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x41, 0x3d, 0xc3, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x42, 0xec, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x46, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd2, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0xd0, 0xe1, 0xb1, 0x00, 0x00, 0xbf, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x98, 0xb0, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x40, 0x8b, 0xb3, 0x00, 0x00, 0xb1, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0xc7, 0x80, 0xa2, 0x42, 0x97, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0xa1, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x04, 0x80, 0x94, 0x00, 0x00, ++ 0x80, 0x15, 0x3f, 0x42, 0x97, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x03, 0x02, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x07, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0xcb, ++ 0x99, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xf3, 0x83, 0x01, 0x00, ++ 0xd1, 0x80, 0xa2, 0x42, 0x97, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, ++ 0xf3, 0x93, 0x01, 0x00, 0xae, 0x03, 0x00, 0xcb, 0xa3, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x44, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x04, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, ++ 0xe0, 0xb1, 0x01, 0x00, 0x05, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x20, 0x62, 0xdd, 0x01, 0x00, 0xd8, 0x80, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xf9, 0x02, 0x00, 0x20, 0x42, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x41, 0x05, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x80, 0xcb, ++ 0xdb, 0x91, 0x01, 0x00, 0x00, 0x00, 0x19, 0x41, 0x8b, 0xb3, 0x01, 0x00, ++ 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xde, 0x80, 0xa8, 0xb1, ++ 0x8c, 0x33, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xe0, 0x80, 0xa8, 0xb1, 0x94, 0x33, 0x00, 0x00, 0xe6, 0x80, 0x14, 0xc6, ++ 0x81, 0x32, 0x00, 0x00, 0x18, 0x00, 0x00, 0xc6, 0x83, 0xf4, 0x01, 0x00, ++ 0xf4, 0x82, 0x22, 0x4f, 0x83, 0x04, 0x00, 0x00, 0xc2, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xff, 0x01, 0x00, 0xc6, 0x81, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xc6, 0x97, 0xa3, 0x01, 0x00, 0xc2, 0x80, 0x1f, 0x5c, ++ 0x97, 0x53, 0x00, 0x00, 0x58, 0x82, 0x1e, 0xc6, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x2f, 0x43, 0x81, 0xf0, 0x01, 0x00, 0xec, 0x80, 0x00, 0x40, ++ 0x10, 0xc9, 0x00, 0x00, 0x39, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x6a, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x24, 0x82, 0x00, 0xca, ++ 0x63, 0xb3, 0x00, 0x00, 0x61, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x48, 0x81, 0x00, 0x4d, 0x83, 0xb0, 0x00, 0x00, 0x52, 0x81, 0x00, 0x4e, ++ 0x61, 0xb1, 0x00, 0x00, 0x41, 0x81, 0x00, 0x40, 0x85, 0xb0, 0x00, 0x00, ++ 0x48, 0x81, 0x00, 0x4c, 0x83, 0xb0, 0x00, 0x00, 0x24, 0x81, 0x00, 0x40, ++ 0x85, 0xb0, 0x00, 0x00, 0xe3, 0x81, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, ++ 0x71, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0xdf, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x41, 0x81, 0x00, 0x40, 0x85, 0xb0, 0x00, 0x00, ++ 0xf0, 0x03, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0xf4, 0x82, 0x00, 0xca, ++ 0x9b, 0xb3, 0x00, 0x00, 0x7b, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x7f, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0x86, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0x87, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, ++ 0x88, 0x81, 0x00, 0x40, 0xc1, 0xb1, 0x00, 0x00, 0x89, 0x81, 0x00, 0x40, ++ 0xc1, 0xb1, 0x00, 0x00, 0x8a, 0x81, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, ++ 0x8a, 0x81, 0x00, 0x41, 0x81, 0xb0, 0x00, 0x00, 0x18, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x97, 0x82, 0x00, 0xbb, 0xab, 0xb3, 0x00, 0x00, ++ 0x25, 0x82, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x26, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf4, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0xca, 0x77, 0xb3, 0x00, 0x00, 0x49, 0x81, 0x00, 0x4d, ++ 0x83, 0xb0, 0x00, 0x00, 0x50, 0x81, 0x00, 0x4e, 0x61, 0xb1, 0x00, 0x00, ++ 0x41, 0x81, 0x00, 0xbb, 0x85, 0xb0, 0x00, 0x00, 0x49, 0x81, 0x00, 0x4c, ++ 0x83, 0xb0, 0x00, 0x00, 0x41, 0x81, 0x00, 0xbb, 0x85, 0xb0, 0x00, 0x00, ++ 0x24, 0x81, 0x00, 0xbb, 0x85, 0xb0, 0x00, 0x00, 0x16, 0x81, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xf4, 0x82, 0x00, 0xca, 0x4d, 0xb3, 0x00, 0x00, ++ 0x70, 0x05, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x40, ++ 0x49, 0xb1, 0x00, 0x00, 0x1c, 0x81, 0x22, 0x42, 0x8f, 0x6f, 0x00, 0x00, ++ 0x1e, 0x81, 0x22, 0x41, 0x8f, 0x6f, 0x00, 0x00, 0x20, 0x81, 0x1e, 0xca, ++ 0x81, 0x32, 0x00, 0x00, 0x22, 0x81, 0x1f, 0xca, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xc9, 0xb1, 0x01, 0x00, 0xf4, 0x82, 0x00, 0x42, ++ 0x8f, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xcd, 0xb1, 0x01, 0x00, ++ 0xf4, 0x82, 0x00, 0x41, 0x8f, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xcf, 0xb1, 0x01, 0x00, 0xf4, 0x82, 0x00, 0x40, 0x8f, 0xb3, 0x00, 0x00, ++ 0x00, 0x81, 0x00, 0xa6, 0xc6, 0xb1, 0x01, 0x00, 0xf4, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, 0xc6, 0xb1, 0x01, 0x00, ++ 0xf4, 0x82, 0x00, 0x40, 0x8f, 0xb3, 0x00, 0x00, 0x78, 0x18, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0x10, 0x00, 0x2f, 0x9c, 0x89, 0xb0, 0x01, 0x00, ++ 0x3b, 0x81, 0x00, 0x40, 0x39, 0x33, 0x01, 0x00, 0x18, 0x00, 0x2f, 0x9b, ++ 0x89, 0xb0, 0x01, 0x00, 0x3b, 0x81, 0x00, 0x40, 0x37, 0x33, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x9a, 0x89, 0xb0, 0x01, 0x00, 0x3b, 0x81, 0x00, 0x40, ++ 0x35, 0x33, 0x01, 0x00, 0x08, 0x00, 0x2f, 0x99, 0x89, 0xb0, 0x01, 0x00, ++ 0x3b, 0x81, 0x00, 0x40, 0x33, 0x33, 0x01, 0x00, 0x00, 0x80, 0x00, 0xae, ++ 0x47, 0xc9, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x18, 0x00, 0x40, 0xe1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xae, ++ 0x63, 0xdd, 0x01, 0x00, 0x36, 0x81, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x33, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x36, 0x81, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x69, 0x93, 0x01, 0x00, ++ 0xf4, 0x82, 0x1a, 0x44, 0x93, 0x93, 0x00, 0x00, 0x39, 0x81, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x38, 0x81, 0x00, 0x58, 0x69, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf0, 0xd1, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x40, 0x81, 0xa2, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x45, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x41, 0xe1, 0xd1, 0x01, 0x00, ++ 0x41, 0x81, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x62, 0xb1, 0x01, 0x00, 0x45, 0x81, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x42, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0x63, 0xb1, 0x01, 0x00, 0x45, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xf4, 0x82, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x4a, 0x81, 0x00, 0x40, ++ 0x81, 0xb0, 0x00, 0x00, 0x4a, 0x81, 0x00, 0xbb, 0x81, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x60, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0x4b, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, 0xf4, 0x82, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x4d, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x50, 0x95, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x53, 0x81, 0x00, 0xbb, ++ 0x87, 0xb0, 0x00, 0x00, 0x50, 0x95, 0x2f, 0x40, 0x87, 0xb0, 0x01, 0x00, ++ 0x55, 0x81, 0x22, 0x40, 0x95, 0x7f, 0x00, 0x00, 0xf4, 0x82, 0x60, 0x40, ++ 0x95, 0x83, 0x00, 0x00, 0x02, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0x56, 0x81, 0x36, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x62, 0xb1, 0x01, 0x00, 0x57, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x62, 0xb1, 0x01, 0x00, 0x59, 0x81, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x63, 0xb1, 0x01, 0x00, ++ 0x5b, 0x81, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x16, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xf4, 0x82, 0x22, 0x41, 0x43, 0x51, 0x00, 0x00, ++ 0x00, 0x08, 0x00, 0xca, 0x95, 0xcb, 0x01, 0x00, 0x56, 0x81, 0x00, 0x41, ++ 0x85, 0xc0, 0x00, 0x00, 0x63, 0x81, 0xa2, 0x42, 0x67, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x67, 0xb3, 0x01, 0x00, 0x63, 0x81, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x93, 0x83, 0x01, 0x00, 0x00, 0x00, 0x1a, 0xca, ++ 0x69, 0x97, 0x01, 0x00, 0xf4, 0x82, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x68, 0x81, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0xf4, 0x82, 0x1a, 0x44, ++ 0x93, 0x93, 0x00, 0x00, 0xf4, 0x82, 0x20, 0x43, 0x95, 0x6f, 0x00, 0x00, ++ 0xf4, 0x82, 0x80, 0xca, 0x67, 0x33, 0x00, 0x00, 0xf4, 0x82, 0x22, 0x40, ++ 0x65, 0x6f, 0x00, 0x00, 0xf4, 0x82, 0x00, 0x6f, 0xdb, 0x91, 0x00, 0x00, ++ 0x85, 0x00, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x35, 0x80, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0xf4, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x95, 0x93, 0x01, 0x00, 0x77, 0x81, 0xa2, 0x44, 0x21, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x95, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5e, ++ 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, 0x95, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0xc3, 0xb1, 0x01, 0x00, 0x7a, 0x81, 0x22, 0x5b, ++ 0x95, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xfd, 0x93, 0x01, 0x00, ++ 0xf4, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1b, 0xfd, 0x00, 0xca, ++ 0x95, 0x9b, 0x01, 0x00, 0x0d, 0x01, 0x00, 0xca, 0xc5, 0x31, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x95, 0x83, 0x01, 0x00, 0xf4, 0x82, 0x00, 0xca, ++ 0xc5, 0xb1, 0x00, 0x00, 0xdf, 0x6f, 0x00, 0xca, 0x95, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x95, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0xca, ++ 0xc7, 0xb1, 0x01, 0x00, 0xf4, 0x82, 0x22, 0x5f, 0x95, 0x7f, 0x00, 0x00, ++ 0x0d, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x95, 0x83, 0x01, 0x00, 0xf4, 0x82, 0x00, 0xca, 0xc7, 0xb1, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0xca, 0xc9, 0xb1, 0x00, 0x00, 0xf4, 0x82, 0x00, 0xca, ++ 0xcb, 0xb1, 0x00, 0x00, 0xf4, 0x82, 0x00, 0xca, 0xcd, 0xb1, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0xca, 0xcf, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x42, ++ 0x81, 0xe0, 0x01, 0x00, 0x98, 0x14, 0x00, 0x40, 0x48, 0xc9, 0x01, 0x00, ++ 0xf4, 0x82, 0x00, 0xca, 0xe1, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x09, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x8f, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0x91, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0xa6, 0x08, 0xb1, 0x01, 0x00, 0x93, 0x81, 0x9f, 0x85, ++ 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x83, 0x84, 0x01, 0x00, ++ 0xc8, 0x81, 0x22, 0x30, 0x83, 0x6c, 0x00, 0x00, 0x92, 0x81, 0xa2, 0x4f, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x21, 0xb3, 0x01, 0x00, ++ 0x02, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x10, 0x00, 0x00, 0x41, 0x84, 0xe4, 0x01, 0x00, ++ 0x03, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x41, 0x86, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x84, 0x94, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x10, 0xc4, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, ++ 0xa8, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x21, 0xb3, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x1c, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0xa5, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, ++ 0xba, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x41, 0x01, 0x00, 0xa6, ++ 0x86, 0xb0, 0x01, 0x00, 0x50, 0x0c, 0x00, 0x43, 0x86, 0x98, 0x01, 0x00, ++ 0xad, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x21, 0xb3, 0x01, 0x00, 0xba, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x41, 0x01, 0x00, 0xa6, 0x86, 0xb0, 0x01, 0x00, 0x60, 0x0c, 0x00, 0x43, ++ 0x86, 0x98, 0x01, 0x00, 0xba, 0x81, 0xa2, 0x43, 0x84, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x21, 0xb3, 0x01, 0x00, 0x18, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x41, 0x82, 0x88, 0x01, 0x00, 0x00, 0x77, 0x00, 0x41, ++ 0x82, 0x8c, 0x01, 0x00, 0x01, 0x02, 0x00, 0x41, 0x82, 0x98, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x18, 0x00, 0x00, 0x41, ++ 0x82, 0xdc, 0x01, 0x00, 0xb8, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x08, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0xbb, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, ++ 0x40, 0x13, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, 0xc3, 0x81, 0x22, 0x43, ++ 0x21, 0x6f, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0xc0, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, ++ 0xde, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x19, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0xc5, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0xde, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x21, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x83, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5e, 0x83, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, ++ 0x83, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xc2, 0xb1, 0x01, 0x00, ++ 0x0c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x83, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xc2, 0xb1, 0x01, 0x00, ++ 0x0c, 0x01, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x08, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x11, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, ++ 0xd7, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0xda, 0x81, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x40, 0x13, 0x00, 0x41, ++ 0x08, 0x99, 0x01, 0x00, 0x01, 0x00, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x41, 0x2e, 0x99, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xca, 0x81, 0x94, 0x01, 0x00, 0xe1, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0xf4, 0x82, 0x00, 0x40, 0x08, 0xb1, 0x00, 0x00, ++ 0xc8, 0x14, 0x2e, 0xbb, 0x85, 0xb0, 0x01, 0x00, 0xe4, 0x81, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0xb0, 0x01, 0x00, ++ 0xf3, 0x81, 0x22, 0x43, 0x21, 0x6f, 0x00, 0x00, 0x02, 0x82, 0x22, 0x44, ++ 0x21, 0x6f, 0x00, 0x00, 0x11, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, ++ 0x13, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x0a, 0x82, 0x22, 0x4a, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, ++ 0xee, 0x81, 0x22, 0x4d, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x87, 0x90, 0x01, 0x00, 0xf0, 0x81, 0x22, 0x4f, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, 0xf2, 0x81, 0x22, 0x4e, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x87, 0x90, 0x01, 0x00, ++ 0x0a, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x01, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0a, 0x82, 0x22, 0x42, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, 0x1c, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xfd, 0x81, 0x22, 0x45, 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x87, 0x90, 0x01, 0x00, 0xff, 0x81, 0x22, 0x44, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x87, 0x90, 0x01, 0x00, 0x01, 0x82, 0x22, 0x43, ++ 0x83, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x87, 0x90, 0x01, 0x00, ++ 0x0a, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x01, 0x80, 0x00, 0xa6, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x01, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0a, 0x82, 0x22, 0x42, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x87, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x87, 0x90, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0xa6, 0x82, 0xb0, 0x01, 0x00, 0x13, 0x82, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x82, 0x22, 0x4b, 0x83, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xe0, 0xb1, 0x01, 0x00, 0xff, 0x7f, 0x00, 0xa2, 0xa0, 0x8b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xa5, 0xb3, 0x01, 0x00, 0xb8, 0x80, 0x00, 0xca, ++ 0xa7, 0x33, 0x01, 0x00, 0x36, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x41, 0x82, 0xdc, 0x01, 0x00, 0x14, 0x82, 0xa2, 0x5e, ++ 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0xb1, 0x01, 0x00, ++ 0x16, 0x82, 0x9f, 0x85, 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x1b, 0x82, 0x14, 0xf7, 0x81, 0x30, 0x00, 0x00, ++ 0x1b, 0x82, 0xa2, 0x49, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xfd, 0x93, 0x01, 0x00, 0x1e, 0x82, 0x15, 0xf8, 0x81, 0x14, 0x00, 0x00, ++ 0x1e, 0x82, 0xa2, 0x4a, 0xfd, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xfd, 0x93, 0x01, 0x00, 0x20, 0x82, 0xa2, 0xc8, 0x81, 0x32, 0x00, 0x00, ++ 0x40, 0x00, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x40, ++ 0x80, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xef, 0xb3, 0x01, 0x00, ++ 0x22, 0x82, 0x42, 0x40, 0xf1, 0x33, 0x00, 0x00, 0x38, 0x81, 0x00, 0x40, ++ 0x68, 0x97, 0x00, 0x00, 0xf4, 0x82, 0x00, 0xbb, 0x6b, 0xb3, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0xbb, 0xb1, 0xb3, 0x00, 0x00, 0xf4, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x18, 0xb1, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x19, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x42, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x43, 0xff, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x18, 0xb1, 0x01, 0x00, 0x2b, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x19, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x81, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf6, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x43, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, 0x35, 0x82, 0xa2, 0x54, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, 0x3c, 0x82, 0xa2, 0x06, ++ 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x16, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x80, 0x16, 0x2e, 0x06, ++ 0x83, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0x42, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x22, 0x00, 0x00, 0x40, ++ 0x83, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf6, 0xb1, 0x01, 0x00, ++ 0x45, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x62, 0x00, 0x00, 0x40, ++ 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x16, 0x2d, 0x06, 0x83, 0xb0, 0x01, 0x00, 0x80, 0x16, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x5c, 0x00, 0x00, 0xfb, 0xf6, 0xa9, 0x01, 0x00, ++ 0x4b, 0x82, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x71, 0xf9, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x72, 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x74, 0xf9, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x00, 0x40, 0x95, 0x98, 0x01, 0x00, 0xdc, 0x9f, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x70, 0x95, 0xb0, 0x01, 0x00, ++ 0x57, 0x82, 0x22, 0x70, 0xb5, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x42, ++ 0x99, 0xb3, 0x01, 0x00, 0x62, 0x82, 0x22, 0x44, 0x81, 0x6c, 0x00, 0x00, ++ 0x6a, 0x82, 0x22, 0x48, 0x81, 0x6c, 0x00, 0x00, 0x64, 0x82, 0x22, 0x4c, ++ 0x81, 0x6c, 0x00, 0x00, 0x6e, 0x82, 0x22, 0x50, 0x81, 0x6c, 0x00, 0x00, ++ 0x6f, 0x82, 0x22, 0x54, 0x81, 0x6c, 0x00, 0x00, 0x71, 0x82, 0x22, 0x58, ++ 0x81, 0x6c, 0x00, 0x00, 0x76, 0x82, 0x22, 0x5c, 0x81, 0x6c, 0x00, 0x00, ++ 0x50, 0x01, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, ++ 0x09, 0xb0, 0x01, 0x00, 0xf4, 0x82, 0x00, 0xca, 0x01, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xf3, 0x83, 0x01, 0x00, 0x68, 0x82, 0xa2, 0x42, 0x05, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x05, 0xb0, 0x01, 0x00, 0xf4, 0x82, 0x22, 0xca, ++ 0x07, 0x14, 0x00, 0x00, 0xf4, 0x82, 0x00, 0x46, 0xf3, 0x93, 0x00, 0x00, ++ 0xf4, 0x82, 0x20, 0x43, 0x95, 0x6f, 0x00, 0x00, 0xf4, 0x82, 0x80, 0xca, ++ 0x05, 0x30, 0x00, 0x00, 0xf4, 0x82, 0x22, 0x01, 0x80, 0x30, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0xcb, 0xdb, 0x91, 0x00, 0x00, 0x57, 0x01, 0x00, 0xbc, ++ 0xab, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xb1, 0xb3, 0x01, 0x00, ++ 0xf4, 0x82, 0x00, 0xca, 0xcf, 0xb3, 0x00, 0x00, 0xff, 0x00, 0x00, 0xca, ++ 0x81, 0x88, 0x01, 0x00, 0xf4, 0x82, 0xa2, 0x40, 0x74, 0x7d, 0x00, 0x00, ++ 0x60, 0x00, 0x20, 0x40, 0x60, 0x99, 0x01, 0x00, 0x73, 0x82, 0xa8, 0xb1, ++ 0x82, 0x30, 0x00, 0x00, 0x72, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0xca, 0x79, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0xcb, 0x83, 0x01, 0x00, ++ 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x79, 0x82, 0xa2, 0x41, ++ 0x81, 0x50, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x45, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x84, 0x82, 0x91, 0x82, ++ 0x82, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x80, 0xb0, 0x01, 0x00, ++ 0xae, 0x9f, 0x00, 0x40, 0x80, 0xce, 0x01, 0x00, 0x82, 0x82, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x84, 0x82, 0x56, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, ++ 0x07, 0x90, 0x01, 0x00, 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x41, ++ 0x8b, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x81, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xcd, 0x83, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x89, 0x82, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x46, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x46, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x94, 0x82, 0x91, 0x81, 0x82, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x89, 0x80, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, ++ 0x80, 0xce, 0x01, 0x00, 0x92, 0x82, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x94, 0x82, 0x55, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x40, ++ 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x52, 0x07, 0x90, 0x01, 0x00, ++ 0xb6, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x53, ++ 0x07, 0x90, 0x01, 0x00, 0xd8, 0x9f, 0x00, 0x41, 0x8b, 0xb3, 0x00, 0x00, ++ 0xb1, 0x03, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, 0xc4, 0x14, 0x2f, 0x40, ++ 0x99, 0xb3, 0x01, 0x00, 0x57, 0x01, 0x00, 0x40, 0x49, 0xb1, 0x00, 0x00, ++ 0xa0, 0x94, 0x2e, 0x43, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x9b, 0x82, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x50, 0x95, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xac, 0x94, 0x2e, 0x43, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x9f, 0x82, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xae, 0x03, 0x00, 0x40, 0xa3, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x60, 0x15, 0x00, 0x40, ++ 0x85, 0x98, 0x01, 0x00, 0x08, 0x00, 0x00, 0x40, 0x40, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x59, 0x41, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x41, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x40, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x57, 0x41, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x42, 0x81, 0x6c, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, 0xa5, 0x82, 0xa0, 0x42, ++ 0x81, 0x6c, 0x00, 0x00, 0xa5, 0x82, 0x00, 0x50, 0x85, 0xc0, 0x00, 0x00, ++ 0xdd, 0x82, 0xa2, 0x41, 0x01, 0x7d, 0x00, 0x00, 0xb5, 0x82, 0x22, 0x58, ++ 0x73, 0x7d, 0x00, 0x00, 0x78, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xb0, 0x82, 0xa8, 0xb1, 0x9c, 0x30, 0x00, 0x00, 0x30, 0x00, 0x38, 0x45, ++ 0x9d, 0xe0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0xc9, 0x00, 0x00, ++ 0xb5, 0x82, 0x33, 0xc4, 0x81, 0x30, 0x00, 0x00, 0xb8, 0x82, 0xa1, 0xad, ++ 0x9d, 0x20, 0x00, 0x00, 0xaf, 0x82, 0x13, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x13, 0x4e, 0x5a, 0x83, 0x01, 0x00, 0x30, 0x00, 0x38, 0x45, ++ 0x9d, 0xe0, 0x01, 0x00, 0xc0, 0x82, 0x22, 0xab, 0x80, 0x04, 0x00, 0x00, ++ 0xbe, 0x82, 0xa2, 0x40, 0x01, 0x7d, 0x00, 0x00, 0xc0, 0x82, 0x22, 0x5f, ++ 0x57, 0x7d, 0x00, 0x00, 0x36, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc0, 0x82, 0x22, 0x5e, 0x57, 0x7d, 0x00, 0x00, 0x99, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc5, 0x82, 0x22, 0x54, 0x73, 0x7d, 0x00, 0x00, ++ 0x74, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xc0, 0x82, 0xa8, 0xb1, ++ 0x00, 0x30, 0x00, 0x00, 0x8a, 0x84, 0xa2, 0x5f, 0x01, 0x7c, 0x00, 0x00, ++ 0xca, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc7, 0x82, 0xa2, 0x5f, ++ 0x59, 0x27, 0x00, 0x00, 0xc9, 0x82, 0xa2, 0x5c, 0x73, 0x7d, 0x00, 0x00, ++ 0xd0, 0x82, 0xa2, 0x5e, 0x73, 0x7d, 0x00, 0x00, 0xda, 0x82, 0x22, 0x5c, ++ 0x73, 0x7d, 0x00, 0x00, 0xdb, 0x82, 0x37, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x7c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xca, 0x82, 0xa8, 0xb1, ++ 0x36, 0x30, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xcc, 0x82, 0xa8, 0xb1, 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, ++ 0x02, 0x88, 0x01, 0x00, 0xb9, 0x84, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xdb, 0x82, 0x34, 0x40, 0x81, 0x32, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xd1, 0x82, 0xa8, 0xb1, 0x12, 0x30, 0x00, 0x00, ++ 0xd8, 0x82, 0x52, 0x21, 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14, 0x41, ++ 0x2f, 0xc3, 0x01, 0x00, 0xff, 0x3f, 0x00, 0x09, 0x00, 0x8c, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x01, 0xf0, 0x01, 0x00, 0x11, 0x83, 0x00, 0x34, ++ 0x13, 0x84, 0x00, 0x00, 0xff, 0x3f, 0x14, 0x09, 0x00, 0x8c, 0x01, 0x00, ++ 0x6f, 0x83, 0x00, 0x43, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xdb, 0x82, 0x33, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x13, 0x4e, 0x5a, 0x93, 0x00, 0x00, 0x0e, 0x87, 0xa2, 0x48, ++ 0xfd, 0x7f, 0x00, 0x00, 0x04, 0x00, 0xa2, 0xac, 0x80, 0x32, 0x00, 0x00, ++ 0xe3, 0x82, 0x22, 0x5a, 0x73, 0x7d, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xe0, 0x82, 0xa8, 0xb1, 0x7e, 0x31, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0xcf, 0x11, 0xc9, 0x00, 0x00, 0xe9, 0x82, 0xa2, 0x40, ++ 0x93, 0x7f, 0x00, 0x00, 0xe9, 0x82, 0x22, 0x44, 0x93, 0x7f, 0x00, 0x00, ++ 0xe5, 0x82, 0x42, 0xa5, 0x80, 0x30, 0x00, 0x00, 0xe8, 0x82, 0xa2, 0x40, ++ 0x93, 0x7f, 0x00, 0x00, 0xfb, 0x82, 0x1a, 0x40, 0x93, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x1a, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xdd, 0x80, 0xa2, 0x40, ++ 0x73, 0x7d, 0x00, 0x00, 0x09, 0x87, 0x22, 0x44, 0x21, 0x6f, 0x00, 0x00, ++ 0x00, 0x87, 0x22, 0x40, 0x65, 0x7d, 0x00, 0x00, 0x00, 0x05, 0xa2, 0x5b, ++ 0x73, 0x7d, 0x00, 0x00, 0x04, 0x00, 0xa2, 0x49, 0x33, 0x7d, 0x00, 0x00, ++ 0xf3, 0x82, 0x22, 0x48, 0x33, 0x7d, 0x00, 0x00, 0xff, 0x01, 0x00, 0x99, ++ 0x80, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x81, 0xe0, 0x01, 0x00, ++ 0xa8, 0x98, 0x2f, 0x40, 0x33, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe0, 0xc1, 0x01, 0x00, 0xdd, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x40, 0x8b, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x62, 0xb1, 0x01, 0x00, ++ 0xaf, 0x82, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0xf6, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xf9, 0x82, 0x33, 0x40, 0x1f, 0x30, 0x00, 0x00, ++ 0xaf, 0x82, 0x13, 0x4e, 0x5a, 0x93, 0x00, 0x00, 0xfd, 0x82, 0xa0, 0xce, ++ 0x81, 0x50, 0x00, 0x00, 0x0f, 0x83, 0xa0, 0xcd, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa5, 0x9c, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, ++ 0x81, 0xb0, 0x01, 0x00, 0x0f, 0x83, 0x22, 0xb5, 0x81, 0x14, 0x00, 0x00, ++ 0x80, 0x15, 0x2f, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x01, 0x83, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x60, 0xb4, 0x65, 0x97, 0x01, 0x00, ++ 0xd0, 0x15, 0x2e, 0x40, 0x69, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x44, ++ 0x93, 0x83, 0x01, 0x00, 0x1a, 0x00, 0x00, 0xa2, 0x80, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb1, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xf1, 0xb1, 0x01, 0x00, ++ 0x05, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x80, 0x00, 0x00, 0x40, ++ 0x62, 0xdd, 0x01, 0x00, 0x0a, 0x83, 0xa8, 0xa1, 0xe0, 0x31, 0x00, 0x00, ++ 0xe9, 0x82, 0x00, 0x88, 0x9e, 0xb3, 0x00, 0x00, 0xe9, 0x82, 0xa2, 0x41, ++ 0x67, 0x6f, 0x00, 0x00, 0xe9, 0x82, 0x00, 0x6f, 0xdb, 0x91, 0x00, 0x00, ++ 0x0f, 0x83, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0xe9, 0x82, 0x1a, 0x40, ++ 0x93, 0x83, 0x00, 0x00, 0x00, 0x99, 0x00, 0x09, 0x46, 0xc9, 0x01, 0x00, ++ 0x3f, 0x00, 0x00, 0xf3, 0x0c, 0x88, 0x01, 0x00, 0x1a, 0x83, 0xa6, 0x42, ++ 0x13, 0x60, 0x00, 0x00, 0x12, 0x94, 0x00, 0x95, 0x03, 0x30, 0x01, 0x00, ++ 0x15, 0x83, 0x61, 0x40, 0x81, 0x32, 0x00, 0x00, 0x75, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x16, 0x83, 0xa8, 0xb1, 0x0c, 0x30, 0x00, 0x00, ++ 0x1f, 0x94, 0x71, 0x10, 0x94, 0x30, 0x01, 0x00, 0x1b, 0x83, 0x00, 0x58, ++ 0x1f, 0x90, 0x00, 0x00, 0x05, 0x94, 0x00, 0x95, 0x03, 0x30, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x2d, 0xf0, 0x2e, 0xb0, 0x01, 0x00, ++ 0xee, 0x07, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, 0x22, 0x83, 0x23, 0x4b, ++ 0xe4, 0x6d, 0x00, 0x00, 0x22, 0x83, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1f, 0x90, 0x01, 0x00, 0x22, 0x00, 0x2f, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x25, 0x83, 0x83, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x26, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x27, 0x83, 0x85, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x47, 0xc1, 0x01, 0x00, ++ 0x2c, 0x83, 0x22, 0x55, 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x43, 0xd1, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xfa, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x97, 0xe0, 0x01, 0x00, 0x2d, 0x83, 0x00, 0x4b, ++ 0x44, 0xc1, 0x00, 0x00, 0x12, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0xf6, 0x02, 0xcc, 0x01, 0x00, 0x0a, 0x00, 0x00, 0xa1, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x16, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x28, 0xf0, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x2a, 0xb0, 0x01, 0x00, ++ 0xc0, 0x28, 0x3c, 0x46, 0x0d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x44, ++ 0x95, 0xb0, 0x01, 0x00, 0x39, 0x83, 0xa2, 0xf8, 0x0e, 0x30, 0x00, 0x00, ++ 0x49, 0x83, 0x22, 0x41, 0x95, 0x50, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0x35, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x36, 0x83, 0xa2, 0xf8, 0x16, 0x6c, 0x00, 0x00, 0x36, 0x83, 0xa2, 0xf8, ++ 0x10, 0x6c, 0x00, 0x00, 0x36, 0x83, 0xa2, 0xf0, 0x1a, 0x6c, 0x00, 0x00, ++ 0x47, 0x83, 0x22, 0x58, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x13, 0xf0, 0x01, 0x00, 0x3e, 0x83, 0x65, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x42, 0x83, 0xa2, 0xf3, 0x74, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0xe6, 0x95, 0x01, 0x00, 0x47, 0x83, 0x75, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0x96, 0xb0, 0x01, 0x00, 0x3f, 0x00, 0x75, 0xf3, ++ 0x0c, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0x45, 0x83, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x47, 0x83, 0x67, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x4f, 0x83, 0x77, 0x41, 0x2d, 0xc3, 0x00, 0x00, 0x4d, 0x83, 0x22, 0x58, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0x62, 0xb1, 0x01, 0x00, 0x4b, 0x83, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x4d, 0x83, 0x67, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x7c, 0x83, 0x77, 0x41, 0x2d, 0xc3, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0xd8, 0x92, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, ++ 0x5d, 0x83, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, 0x55, 0x83, 0x22, 0x42, ++ 0x81, 0x6c, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x5c, 0x83, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, 0xcc, 0x93, 0x00, 0x5f, ++ 0x01, 0x10, 0x01, 0x00, 0x5b, 0x83, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x41, 0x93, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, ++ 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x14, 0x87, 0x00, 0x40, ++ 0x0f, 0xb0, 0x00, 0x00, 0x65, 0x83, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x53, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x65, 0x83, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0x62, 0x83, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x33, 0x93, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0x25, 0x95, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x68, 0x83, 0x82, 0xf0, 0x18, 0x30, 0x00, 0x00, 0x7b, 0x88, 0x00, 0x45, ++ 0x8f, 0xb0, 0x00, 0x00, 0x28, 0x20, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, ++ 0x6c, 0x83, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, 0xc9, 0x94, 0x00, 0x4b, ++ 0x95, 0x30, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x4b, 0x8f, 0xb0, 0x00, 0x00, ++ 0xd8, 0x93, 0x00, 0x03, 0x48, 0x31, 0x01, 0x00, 0xb4, 0x91, 0x00, 0x40, ++ 0x81, 0x30, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x68, 0x50, ++ 0x03, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x77, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, ++ 0x62, 0xc9, 0x01, 0x00, 0x79, 0x83, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x2e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x00, 0x41, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, 0xee, 0x07, 0x2e, 0x47, ++ 0x97, 0x90, 0x01, 0x00, 0x8f, 0x83, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, ++ 0x8d, 0x83, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0x8d, 0x83, 0x23, 0xa2, ++ 0x02, 0x6c, 0x00, 0x00, 0x41, 0x93, 0x00, 0x52, 0x95, 0x30, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x41, 0x97, 0x50, 0x00, 0x00, 0x0c, 0x00, 0x2d, 0x00, ++ 0x12, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x01, 0x80, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x03, 0xb0, 0x01, 0x00, 0xac, 0x83, 0x00, 0x5c, ++ 0x17, 0x90, 0x00, 0x00, 0xa1, 0x83, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x1f, 0x90, 0x01, 0x00, 0x9a, 0x83, 0x22, 0x5f, ++ 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0xf1, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0xf0, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0x96, 0x83, 0x62, 0x42, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x97, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x72, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0xff, 0x0f, 0x00, 0xf6, 0x80, 0x88, 0x01, 0x00, ++ 0x9e, 0x83, 0xa2, 0xa6, 0x81, 0x6c, 0x00, 0x00, 0xa1, 0x83, 0x00, 0xf2, ++ 0x3a, 0xb0, 0x00, 0x00, 0x87, 0x84, 0xa2, 0x4b, 0xfd, 0x7f, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2a, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xac, 0x83, 0x22, 0x4a, 0x2f, 0x7c, 0x00, 0x00, ++ 0xac, 0x83, 0x22, 0x48, 0x2f, 0x7c, 0x00, 0x00, 0x0a, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x3f, 0x00, 0x00, 0xf2, 0x86, 0x88, 0x01, 0x00, ++ 0x1f, 0x00, 0x00, 0x43, 0x84, 0x88, 0x01, 0x00, 0x05, 0x00, 0x00, 0x43, ++ 0x80, 0xf4, 0x01, 0x00, 0x98, 0x94, 0x3d, 0x42, 0x81, 0xe0, 0x01, 0x00, ++ 0xac, 0x83, 0xa2, 0x42, 0xe0, 0x7d, 0x00, 0x00, 0x87, 0x84, 0xa2, 0x4b, ++ 0xfd, 0x7f, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2a, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xac, 0x83, 0x69, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x09, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x79, 0x41, 0x47, 0xc3, 0x01, 0x00, 0xb2, 0x83, 0x22, 0xa1, ++ 0x09, 0x6c, 0x00, 0x00, 0xf5, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xaf, 0x83, 0x00, 0x03, 0x48, 0xb1, 0x00, 0x00, 0xeb, 0x83, 0xa3, 0x92, ++ 0x03, 0x6c, 0x00, 0x00, 0x7d, 0x95, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, 0x2a, 0x87, 0x22, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0xb8, 0x83, 0x22, 0x5c, 0x17, 0x7c, 0x00, 0x00, ++ 0xb9, 0x83, 0x00, 0x00, 0x2a, 0xb0, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, ++ 0x2a, 0xc8, 0x01, 0x00, 0x02, 0x00, 0x00, 0x08, 0x80, 0xc8, 0x01, 0x00, ++ 0xbd, 0x83, 0xa2, 0x43, 0x2f, 0x7c, 0x00, 0x00, 0xcc, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd9, 0x83, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x01, 0x8c, 0xcc, 0x01, 0x00, 0xcc, 0x94, 0x00, 0x4c, ++ 0x03, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, 0x02, 0xb0, 0x01, 0x00, ++ 0x10, 0x80, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, ++ 0xf0, 0xcd, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x15, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0xc6, 0x83, 0xa8, 0x54, ++ 0x17, 0x10, 0x00, 0x00, 0xd9, 0x83, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, ++ 0x12, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, 0xd8, 0x83, 0x22, 0x43, ++ 0x2f, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x8c, 0xcc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x03, 0xb0, 0x01, 0x00, 0xed, 0x94, 0x00, 0x43, ++ 0x61, 0x31, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, 0x02, 0xb0, 0x01, 0x00, ++ 0x10, 0x80, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x01, ++ 0xf0, 0xcd, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x09, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x15, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0xd9, 0x83, 0x28, 0x54, ++ 0x17, 0x10, 0x00, 0x00, 0xd5, 0x83, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xed, 0x94, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0xdb, 0x83, 0x22, 0x50, ++ 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x17, 0x90, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x17, 0x98, 0x88, 0x01, 0x00, 0xde, 0x83, 0xa2, 0x41, ++ 0x99, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x17, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xdf, 0x83, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xd4, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe6, 0x83, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0x16, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1d, ++ 0xe4, 0xb1, 0x01, 0x00, 0x75, 0x94, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, ++ 0xe9, 0x83, 0xa2, 0x5f, 0x2f, 0x7c, 0x00, 0x00, 0x90, 0x91, 0x00, 0x01, ++ 0x38, 0x43, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2a, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xed, 0x83, 0xa2, 0x4b, ++ 0xfd, 0x7f, 0x00, 0x00, 0x84, 0x84, 0x00, 0x41, 0x43, 0xc3, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x27, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x11, 0xb0, 0x01, 0x00, 0xef, 0x83, 0x35, 0x01, 0x86, 0x30, 0x00, 0x00, ++ 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xf6, 0x83, 0x28, 0xb1, ++ 0x30, 0x30, 0x00, 0x00, 0xf0, 0x83, 0x22, 0x4d, 0x75, 0x7d, 0x00, 0x00, ++ 0x74, 0x84, 0xa2, 0x40, 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x43, 0xc3, 0x01, 0x00, 0x83, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xf6, 0x83, 0xa8, 0xb1, ++ 0x12, 0x30, 0x00, 0x00, 0xff, 0x83, 0xa2, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x43, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, ++ 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2c, 0xb0, 0x01, 0x00, ++ 0xde, 0x07, 0x00, 0x43, 0x80, 0xce, 0x01, 0x00, 0xf0, 0x83, 0xaa, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x04, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x40, 0x00, 0x3e, 0x43, 0x27, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x27, 0xc0, 0x01, 0x00, 0xf0, 0x83, 0xa3, 0x0b, ++ 0x87, 0x50, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, 0x1b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, ++ 0x2a, 0xc8, 0x01, 0x00, 0x40, 0x00, 0x2d, 0x40, 0x39, 0xb0, 0x01, 0x00, ++ 0x0c, 0x84, 0xa2, 0x40, 0x27, 0x6c, 0x00, 0x00, 0x22, 0x00, 0x00, 0x08, ++ 0x12, 0xc8, 0x01, 0x00, 0xde, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, ++ 0x0f, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x12, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x25, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x32, 0xb0, 0x01, 0x00, 0x14, 0x00, 0x20, 0x01, 0xe0, 0xb1, 0x01, 0x00, ++ 0xee, 0x07, 0x00, 0x40, 0x37, 0x98, 0x01, 0x00, 0x14, 0x84, 0x23, 0x01, ++ 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x36, 0xb0, 0x01, 0x00, ++ 0x1f, 0x84, 0x82, 0x41, 0x23, 0x40, 0x00, 0x00, 0x20, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x1b, 0x84, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x18, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xb8, 0x92, 0x00, 0x43, ++ 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, 0x44, 0xc9, 0x01, 0x00, ++ 0x2e, 0x84, 0x22, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x25, 0x84, 0xa8, 0x15, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x25, 0xd0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x4c, ++ 0x13, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x37, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x2b, 0xc0, 0x01, 0x00, 0x14, 0x84, 0x00, 0x45, ++ 0x1f, 0x80, 0x00, 0x00, 0x30, 0x84, 0xa3, 0x12, 0x36, 0x6c, 0x00, 0x00, ++ 0x31, 0x84, 0x68, 0x1b, 0x28, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, ++ 0x28, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x34, 0x84, 0xa8, 0x15, 0xe0, 0x31, 0x00, 0x00, 0x5a, 0x84, 0x22, 0x14, ++ 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x14, 0x24, 0xd0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x14, ++ 0x12, 0xc0, 0x01, 0x00, 0x53, 0x84, 0xa2, 0x14, 0x36, 0x50, 0x00, 0x00, ++ 0x44, 0x84, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, 0x30, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x42, 0x84, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x3f, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xf0, 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x2b, 0x80, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, 0x37, 0x98, 0x01, 0x00, ++ 0x49, 0x84, 0x23, 0x01, 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x36, 0xb0, 0x01, 0x00, 0x54, 0x84, 0x22, 0x1b, 0x02, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x15, ++ 0xe0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x50, 0x84, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x54, 0x84, 0x00, 0x03, 0x48, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x14, 0x2a, 0xc0, 0x01, 0x00, 0x14, 0x84, 0xa2, 0x40, ++ 0x25, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x39, 0xc0, 0x01, 0x00, ++ 0x40, 0x00, 0x3d, 0x43, 0x39, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0x25, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x12, 0xb0, 0x01, 0x00, ++ 0x14, 0x84, 0x00, 0xf0, 0x30, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0x60, 0x84, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x19, ++ 0x62, 0xdd, 0x01, 0x00, 0x5d, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xb8, 0x92, 0x00, 0x40, ++ 0x2b, 0x30, 0x01, 0x00, 0x18, 0x00, 0x2e, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x64, 0x84, 0x22, 0x50, 0x2f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, ++ 0x17, 0x90, 0x01, 0x00, 0x07, 0x00, 0x00, 0x17, 0x98, 0x88, 0x01, 0x00, ++ 0x67, 0x84, 0xa2, 0x41, 0x99, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, ++ 0x17, 0x90, 0x01, 0x00, 0x6a, 0x84, 0x22, 0x43, 0x2f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x17, 0x90, 0x01, 0x00, 0x16, 0x00, 0x20, 0x1d, ++ 0xe4, 0xb1, 0x01, 0x00, 0x6c, 0x84, 0xa3, 0x40, 0x27, 0x6c, 0x00, 0x00, ++ 0x6e, 0x84, 0x60, 0x5f, 0x17, 0x90, 0x00, 0x00, 0x00, 0x84, 0x00, 0x0b, ++ 0x16, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x60, 0x13, 0x16, 0x94, 0x01, 0x00, ++ 0x75, 0x94, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x2a, 0x87, 0xa2, 0x5f, ++ 0x2f, 0x7c, 0x00, 0x00, 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x90, 0x91, 0x00, 0x01, ++ 0x38, 0x43, 0x01, 0x00, 0x2a, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4d, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x62, 0xb1, 0x01, 0x00, ++ 0x76, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x62, 0xb1, 0x01, 0x00, 0x78, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x83, 0x84, 0x22, 0x13, 0x82, 0x6c, 0x00, 0x00, 0x40, 0x00, 0x3d, 0x43, ++ 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x2c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, ++ 0x62, 0xb1, 0x01, 0x00, 0x7e, 0x84, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x62, 0xb1, 0x01, 0x00, 0x80, 0x84, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x7a, 0x84, 0x00, 0x41, 0x83, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x15, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x82, 0x00, 0xa6, ++ 0x04, 0xb0, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, 0x41, 0x93, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x2a, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0x01, 0x80, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0xf4, 0x01, 0x00, ++ 0x3f, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0xd8, 0x92, 0x00, 0x07, 0x16, 0x30, 0x01, 0x00, ++ 0x95, 0x84, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, 0x93, 0x84, 0x22, 0x42, ++ 0x81, 0x6c, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x94, 0x84, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, 0x14, 0x87, 0x00, 0x40, ++ 0x0f, 0xb0, 0x00, 0x00, 0x9d, 0x84, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x53, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x9d, 0x84, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0x9a, 0x84, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x33, 0x93, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0x25, 0x95, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, 0xa3, 0x84, 0x22, 0x3a, ++ 0x01, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0xb0, 0x01, 0x00, ++ 0x7b, 0x88, 0x00, 0x40, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x2e, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xa7, 0x84, 0xa2, 0x40, 0xe7, 0x6d, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x40, 0x01, 0xb0, 0x00, 0x00, ++ 0x1e, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x05, 0x94, 0x00, 0x95, ++ 0x03, 0x30, 0x01, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x2d, 0xf0, ++ 0x2e, 0xb0, 0x01, 0x00, 0x28, 0x20, 0x00, 0xa6, 0x96, 0xb0, 0x01, 0x00, ++ 0xb0, 0x84, 0x22, 0x17, 0x96, 0x04, 0x00, 0x00, 0xc9, 0x94, 0x00, 0x4b, ++ 0x95, 0x30, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x4c, 0x8f, 0xb0, 0x00, 0x00, ++ 0xb2, 0x84, 0x83, 0x17, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x43, 0xc1, 0x01, 0x00, 0xb4, 0x84, 0x85, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0x43, 0xc1, 0x01, 0x00, 0x28, 0x00, 0x00, 0xf6, ++ 0x02, 0xcc, 0x01, 0x00, 0x12, 0x00, 0x00, 0xa1, 0x2a, 0xc8, 0x01, 0x00, ++ 0xd8, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb4, 0x91, 0x00, 0x41, ++ 0x81, 0x30, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0xbe, 0x84, 0x64, 0x47, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0xbf, 0x84, 0xa8, 0x1b, ++ 0xe0, 0x31, 0x00, 0x00, 0xaf, 0x82, 0x74, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x03, 0xe0, 0x01, 0x00, 0x08, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0xe4, 0x84, 0x01, 0xfb, 0x08, 0x30, 0x00, 0x00, ++ 0x37, 0x85, 0x87, 0xfb, 0x22, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, ++ 0x0e, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x14, 0xb0, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0xd8, 0x92, 0x00, 0x07, ++ 0x16, 0x30, 0x01, 0x00, 0xda, 0x84, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, ++ 0xce, 0x84, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xd9, 0x84, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, ++ 0x38, 0x00, 0x00, 0x04, 0x7e, 0x89, 0x01, 0x00, 0xd2, 0x84, 0xa6, 0x5f, ++ 0x0f, 0x00, 0x00, 0x00, 0x2c, 0x92, 0x00, 0x40, 0x05, 0x30, 0x01, 0x00, ++ 0xd7, 0x84, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x13, 0x00, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x0c, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x84, 0xb0, 0x01, 0x00, 0xb7, 0x93, 0x00, 0x40, 0x05, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, 0x14, 0x87, 0x00, 0x40, ++ 0x0f, 0xb0, 0x00, 0x00, 0xe2, 0x84, 0xa2, 0x5a, 0x1f, 0x7c, 0x00, 0x00, ++ 0x53, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xe2, 0x84, 0x22, 0x20, ++ 0x85, 0x6c, 0x00, 0x00, 0xdf, 0x84, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x33, 0x93, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0x25, 0x95, 0x00, 0x42, 0x61, 0x31, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x90, 0x04, 0x00, 0x07, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, 0xe6, 0x84, 0x21, 0x04, ++ 0x80, 0x20, 0x00, 0x00, 0xe7, 0x84, 0x00, 0x40, 0x10, 0xc9, 0x00, 0x00, ++ 0xbd, 0x87, 0x00, 0x4b, 0x81, 0xb0, 0x00, 0x00, 0x06, 0x85, 0x00, 0x43, ++ 0x81, 0xb0, 0x00, 0x00, 0x0a, 0x85, 0x00, 0xfb, 0x22, 0xb0, 0x00, 0x00, ++ 0xbd, 0x87, 0x00, 0x41, 0x81, 0xb0, 0x00, 0x00, 0x7b, 0x88, 0x00, 0x4e, ++ 0x8f, 0xb0, 0x00, 0x00, 0x02, 0x85, 0x00, 0x5a, 0x8f, 0xb0, 0x00, 0x00, ++ 0xef, 0x84, 0x00, 0x47, 0x8f, 0xb0, 0x00, 0x00, 0xbd, 0x87, 0x00, 0x53, ++ 0x81, 0xb0, 0x00, 0x00, 0xbd, 0x87, 0x00, 0x56, 0x81, 0xb0, 0x00, 0x00, ++ 0x32, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x7b, 0x88, 0xa0, 0x0a, ++ 0xe4, 0x6d, 0x00, 0x00, 0xf5, 0x84, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xf4, 0x84, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, 0x7b, 0x88, 0x00, 0x53, ++ 0x8f, 0xb0, 0x00, 0x00, 0x7b, 0x88, 0x00, 0x54, 0x8f, 0xb0, 0x00, 0x00, ++ 0xfe, 0x84, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, 0xf8, 0x84, 0xa2, 0x0a, ++ 0xe4, 0x6d, 0x00, 0x00, 0x7b, 0x88, 0x00, 0x5d, 0x8f, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x80, 0xd0, 0x01, 0x00, 0xfc, 0x84, 0xa0, 0x91, 0x81, 0x6c, 0x00, 0x00, ++ 0x7b, 0x88, 0x00, 0x5e, 0x8f, 0xb0, 0x00, 0x00, 0x25, 0x00, 0x00, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x85, 0x20, 0x91, 0xe5, 0x6d, 0x00, 0x00, 0x7b, 0x88, 0x00, 0x54, ++ 0x8f, 0xb0, 0x00, 0x00, 0x21, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x7b, 0x88, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x32, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x7b, 0x88, 0xa0, 0x0a, 0xe4, 0x6d, 0x00, 0x00, ++ 0x24, 0x00, 0x00, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x7b, 0x88, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x82, 0xf4, 0x01, 0x00, 0xbd, 0x87, 0xa0, 0x42, ++ 0x83, 0x6c, 0x00, 0x00, 0xbd, 0x87, 0x00, 0x54, 0x81, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x0e, 0xb0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x07, 0x16, 0x88, 0x01, 0x00, 0x13, 0x85, 0x22, 0x0b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0xc6, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0x14, 0x87, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0x25, 0x85, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0x20, 0x85, 0xa2, 0x54, ++ 0xfd, 0x7f, 0x00, 0x00, 0x18, 0x85, 0x22, 0x55, 0xfd, 0x7f, 0x00, 0x00, ++ 0x82, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x10, 0x85, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x10, 0x85, 0x22, 0x53, 0xfd, 0x7f, 0x00, 0x00, ++ 0x14, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x96, 0xb0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4b, 0x80, 0xf4, 0x01, 0x00, ++ 0x0c, 0xbc, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x20, 0x85, 0x22, 0x43, ++ 0x80, 0x6c, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4b, 0x80, 0x88, 0x01, 0x00, ++ 0x10, 0x85, 0xa2, 0x43, 0x80, 0x6c, 0x00, 0x00, 0x7c, 0x96, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x21, 0x85, 0x46, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x24, 0x85, 0xa0, 0xf0, 0x30, 0x6f, 0x00, 0x00, 0x16, 0x85, 0x1e, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x41, 0x31, 0xc3, 0x01, 0x00, ++ 0x5d, 0x92, 0x00, 0x40, 0x25, 0x30, 0x01, 0x00, 0x29, 0x85, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x33, 0x93, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x14, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x96, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x18, 0xe4, 0x01, 0x00, 0x00, 0x08, 0x00, 0x0c, 0xe0, 0x99, 0x01, 0x00, ++ 0x90, 0x04, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0x30, 0x85, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, 0x00, 0x02, 0x00, 0xa1, ++ 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, ++ 0x04, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0xbd, 0x87, 0x00, 0x40, 0x81, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x28, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x14, 0xb0, 0x01, 0x00, ++ 0x41, 0x85, 0x22, 0x46, 0x23, 0x7c, 0x00, 0x00, 0x3d, 0x85, 0x22, 0x40, ++ 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x1f, 0x90, 0x01, 0x00, ++ 0x3f, 0x85, 0x22, 0x41, 0x87, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x1f, 0x90, 0x01, 0x00, 0x41, 0x85, 0x22, 0x42, 0x87, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x1f, 0x90, 0x01, 0x00, 0x41, 0x85, 0x66, 0x1b, ++ 0x2c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x13, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x76, 0x41, 0x41, 0xc3, 0x01, 0x00, 0x70, 0x85, 0x23, 0x92, ++ 0x15, 0x6c, 0x00, 0x00, 0x70, 0x85, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0x74, 0x85, 0x22, 0x4b, 0xfd, 0x7f, 0x00, 0x00, 0x17, 0x00, 0x00, 0xd0, ++ 0xa2, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x27, 0xb0, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x0a, 0x24, 0xc8, 0x01, 0x00, 0x94, 0x92, 0x00, 0x40, ++ 0x0f, 0x30, 0x01, 0x00, 0x6e, 0x85, 0x22, 0x08, 0x40, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x12, ++ 0x24, 0xcc, 0x01, 0x00, 0x4a, 0x85, 0xaa, 0x41, 0x27, 0x40, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x13, 0x80, 0xcc, 0x01, 0x00, 0x6a, 0x85, 0x26, 0x40, ++ 0x23, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x83, 0xb0, 0x01, 0x00, ++ 0x60, 0x00, 0x00, 0x03, 0x84, 0xc8, 0x01, 0x00, 0x10, 0x00, 0x00, 0x10, ++ 0x48, 0xcd, 0x01, 0x00, 0x17, 0x00, 0x00, 0xd0, 0xa2, 0xc9, 0x01, 0x00, ++ 0x57, 0x85, 0xa2, 0x40, 0x83, 0x6c, 0x00, 0x00, 0x63, 0x85, 0x00, 0x41, ++ 0x83, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x42, 0x44, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x21, 0x38, 0x96, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0x5c, 0x85, 0xa2, 0x44, 0x23, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf1, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x20, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x5f, 0x85, 0xa8, 0x42, 0xe0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x85, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xa3, 0xc1, 0x01, 0x00, ++ 0x55, 0x85, 0xa2, 0x41, 0x81, 0x50, 0x00, 0x00, 0x6a, 0x85, 0x22, 0x40, ++ 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x67, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0x48, 0xb1, 0x01, 0x00, 0xee, 0x07, 0x00, 0x40, ++ 0x25, 0x98, 0x01, 0x00, 0x17, 0x00, 0x00, 0xd0, 0x2a, 0xc8, 0x01, 0x00, ++ 0x7d, 0x85, 0x00, 0x17, 0x10, 0xb0, 0x00, 0x00, 0x7e, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x74, 0x85, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x94, 0x92, 0x00, 0x92, 0x25, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x31, 0xb0, 0x01, 0x00, 0x74, 0x85, 0x22, 0x08, 0x2e, 0x30, 0x00, 0x00, ++ 0x7d, 0x85, 0x00, 0x41, 0x27, 0xb0, 0x00, 0x00, 0x80, 0x80, 0x00, 0xa6, ++ 0x04, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0xc6, 0x95, 0x00, 0x0a, 0x8c, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x7c, 0x85, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x88, ++ 0x1c, 0xcc, 0x01, 0x00, 0xf5, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x14, 0x87, 0x00, 0x41, 0x3f, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x00, 0x01, 0x80, 0xce, 0x01, 0x00, ++ 0x91, 0x85, 0x2a, 0x40, 0x81, 0x30, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0x86, 0x85, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, 0x86, 0x85, 0xa2, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x86, 0x85, 0xa3, 0x07, 0x03, 0x6c, 0x00, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x89, 0x85, 0xa3, 0x40, ++ 0x02, 0x6c, 0x00, 0x00, 0x28, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, ++ 0x8b, 0x85, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, ++ 0xf0, 0xcd, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x0e, 0xcc, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x8f, 0x85, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x08, 0xb0, 0x01, 0x00, 0xa0, 0x01, 0x2d, 0x40, 0x00, 0xc0, 0x01, 0x00, ++ 0x5b, 0x86, 0x22, 0x0f, 0x42, 0x05, 0x00, 0x00, 0xa2, 0x85, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x9d, 0x85, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x9a, 0x85, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xa2, 0x85, 0x22, 0x07, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x42, 0xc1, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0xa1, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0xc0, 0x06, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x54, ++ 0x29, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x0e, 0xb0, 0x01, 0x00, 0x42, 0x00, 0x00, 0x03, 0x0a, 0xc8, 0x01, 0x00, ++ 0x0c, 0x00, 0x00, 0xa4, 0x0c, 0xc8, 0x01, 0x00, 0xd6, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x14, 0x24, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, ++ 0x10, 0xc0, 0x01, 0x00, 0x12, 0x00, 0x00, 0x08, 0x10, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0xfe, 0x7f, 0x00, 0x05, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xe4, 0xb1, 0x01, 0x00, ++ 0xcb, 0x85, 0x22, 0x01, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, ++ 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0xa4, 0x80, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x48, 0xc1, 0x01, 0x00, 0xb8, 0x85, 0xa3, 0x07, ++ 0x02, 0x6c, 0x00, 0x00, 0xb9, 0x85, 0x68, 0x01, 0x1a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x68, 0x07, 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x02, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0xc0, 0x01, 0x00, ++ 0xc5, 0x85, 0x22, 0x40, 0x03, 0x6c, 0x00, 0x00, 0xc5, 0x85, 0x22, 0x42, ++ 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x23, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0xe9, 0x85, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xc2, 0x85, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, 0xc7, 0x85, 0xa8, 0x40, ++ 0x23, 0x30, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xe9, 0x85, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x44, ++ 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xc1, 0x01, 0x00, 0xd0, 0x85, 0xa3, 0x12, ++ 0x0e, 0x6c, 0x00, 0x00, 0xd1, 0x85, 0x60, 0x07, 0x1a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0x12, 0x1a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x0d, ++ 0x16, 0x94, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x16, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x08, 0x3e, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, ++ 0xd8, 0x85, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, 0x07, 0x86, 0x22, 0x0d, ++ 0x14, 0x6c, 0x00, 0x00, 0xde, 0x85, 0x22, 0x0d, 0x24, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x10, 0xc0, 0x01, 0x00, 0xe2, 0x85, 0x00, 0x0d, ++ 0x24, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2b, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0xa2, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x20, ++ 0x10, 0xc8, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, ++ 0xe4, 0x85, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, 0xe9, 0x85, 0x00, 0x41, ++ 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xe5, 0x85, 0xa8, 0x5c, ++ 0x1f, 0x00, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x07, 0x86, 0x22, 0x0d, ++ 0x14, 0x50, 0x00, 0x00, 0x06, 0x86, 0xa2, 0x0d, 0x0e, 0x50, 0x00, 0x00, ++ 0xf5, 0x85, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xf3, 0x85, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xf0, 0x85, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x06, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, 0xfa, 0x85, 0x1f, 0xf0, ++ 0x0e, 0x30, 0x00, 0x00, 0xb2, 0x85, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x5f, 0x0f, 0x80, 0x01, 0x00, 0xb2, 0x85, 0x23, 0x07, ++ 0x14, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, ++ 0x24, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, ++ 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x03, 0x86, 0xa8, 0x46, ++ 0x1f, 0x10, 0x00, 0x00, 0xb2, 0x85, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, ++ 0xb2, 0x85, 0x00, 0x0d, 0x18, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x2e, 0x14, ++ 0x0a, 0xd0, 0x01, 0x00, 0x12, 0x00, 0x00, 0x05, 0x48, 0xcd, 0x01, 0x00, ++ 0xfe, 0x7f, 0x00, 0x05, 0x42, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x2a, 0xf2, ++ 0xe0, 0xb1, 0x01, 0x00, 0x0d, 0x86, 0x22, 0x40, 0x31, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0x18, 0x38, 0x96, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x81, 0x00, 0xf6, 0x80, 0xce, 0x01, 0x00, ++ 0x11, 0x86, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x43, 0xc1, 0x01, 0x00, 0x13, 0x86, 0x22, 0x0b, 0xed, 0x6d, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0xa1, 0x42, 0xc9, 0x01, 0x00, 0x02, 0x00, 0x00, 0xa1, ++ 0x46, 0xc9, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xfa, 0x94, 0x88, 0x01, 0x00, ++ 0x02, 0x00, 0x00, 0x4a, 0x86, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf6, ++ 0x0e, 0xb0, 0x01, 0x00, 0x1b, 0x86, 0x22, 0x47, 0x1f, 0x7c, 0x00, 0x00, ++ 0x04, 0x00, 0x1f, 0x43, 0x0e, 0x50, 0x00, 0x00, 0x1b, 0x86, 0xa0, 0x46, ++ 0x0f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, ++ 0x1f, 0x86, 0x22, 0x48, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x91, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x0f, 0xa2, 0x42, 0x31, 0x00, 0x00, ++ 0x22, 0x86, 0x00, 0x40, 0x89, 0xb0, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa2, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x89, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x95, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x82, 0xb0, 0x01, 0x00, 0x25, 0x86, 0xa0, 0x41, 0x90, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x91, 0xc0, 0x01, 0x00, 0x2a, 0x86, 0x22, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x2a, 0x86, 0xa0, 0x43, 0x89, 0x6c, 0x00, 0x00, ++ 0x2a, 0x86, 0x20, 0x45, 0x89, 0x6c, 0x00, 0x00, 0x2a, 0x86, 0xa0, 0x41, ++ 0x0e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x89, 0xc0, 0x01, 0x00, 0x22, 0x86, 0xa2, 0x41, ++ 0x95, 0x50, 0x00, 0x00, 0x33, 0x86, 0x22, 0x48, 0x1f, 0x7c, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x48, 0x92, 0xf4, 0x01, 0x00, 0xff, 0xff, 0x00, 0x48, ++ 0x90, 0x88, 0x01, 0x00, 0x31, 0x86, 0x90, 0x48, 0x92, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, 0x0a, 0x00, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x93, 0xa4, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x12, 0x00, 0x00, 0x14, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf0, 0xb1, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x05, 0xe0, 0xcd, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x40, 0x62, 0xdd, 0x01, 0x00, 0x39, 0x86, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x44, 0x86, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0x43, 0x86, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x40, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x47, 0x86, 0xa2, 0x47, 0x1f, 0x7c, 0x00, 0x00, ++ 0xcc, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc0, 0x86, 0x00, 0x17, ++ 0x10, 0xb0, 0x00, 0x00, 0xd3, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x2f, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x4b, 0x86, 0xa0, 0x07, ++ 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x17, 0xf0, 0x01, 0x00, 0x4f, 0x86, 0x90, 0xf2, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x17, 0xa4, 0x01, 0x00, 0x10, 0x00, 0x00, 0x14, 0x2a, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x2b, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x2a, 0x94, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x59, 0x86, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x56, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x17, 0x10, 0xdc, 0x01, 0x00, ++ 0xc0, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x63, 0x86, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x63, 0x86, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x60, 0x86, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x68, 0x86, 0x22, 0x07, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x42, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x42, 0xc1, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0xa1, 0x46, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, ++ 0xe1, 0x91, 0x01, 0x00, 0x04, 0x00, 0x2e, 0x03, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0xe0, 0xb1, 0x01, 0x00, 0x6d, 0x86, 0x22, 0x40, ++ 0x31, 0x6c, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x18, 0x38, 0x96, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x72, 0x86, 0xa8, 0x40, ++ 0x23, 0x30, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x52, 0x11, 0xc0, 0x01, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x0e, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xa4, 0x0c, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa4, ++ 0x86, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xc1, 0x01, 0x00, ++ 0x80, 0x86, 0xa3, 0x12, 0x0e, 0x6c, 0x00, 0x00, 0x81, 0x86, 0x68, 0x07, ++ 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x68, 0x12, 0x1a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x86, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x68, 0x08, ++ 0x3e, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x02, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x43, 0x62, 0xdd, 0x01, 0x00, ++ 0x86, 0x86, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, 0xb5, 0x86, 0x22, 0x0d, ++ 0x14, 0x6c, 0x00, 0x00, 0x8c, 0x86, 0x22, 0x0d, 0x24, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x10, 0xc0, 0x01, 0x00, 0x90, 0x86, 0x00, 0x0d, ++ 0x24, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x2b, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0xa2, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x20, ++ 0x10, 0xc8, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, 0x25, 0x98, 0x01, 0x00, ++ 0x92, 0x86, 0x22, 0x42, 0x23, 0x6c, 0x00, 0x00, 0x97, 0x86, 0x00, 0x41, ++ 0x23, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x93, 0x86, 0xa8, 0x5c, ++ 0x1f, 0x00, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0x0d, ++ 0x14, 0x50, 0x00, 0x00, 0xb4, 0x86, 0xa2, 0x0d, 0x0e, 0x50, 0x00, 0x00, ++ 0xa3, 0x86, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x1f, 0x80, 0x01, 0x00, 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xa1, 0x86, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x9e, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, 0x46, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0xe1, 0x91, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x06, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x04, 0xb0, 0x01, 0x00, 0xa8, 0x86, 0x1f, 0xf0, ++ 0x0e, 0x30, 0x00, 0x00, 0x7b, 0x86, 0x00, 0x4c, 0x0d, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x5f, 0x0f, 0x80, 0x01, 0x00, 0x7b, 0x86, 0x23, 0x07, ++ 0x14, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, ++ 0x24, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, 0x24, 0x00, 0x00, 0x00, ++ 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0xb1, 0x86, 0xa8, 0x46, ++ 0x1f, 0x10, 0x00, 0x00, 0x7b, 0x86, 0x00, 0x03, 0x0c, 0xb0, 0x00, 0x00, ++ 0x7b, 0x86, 0x00, 0x0d, 0x18, 0xc0, 0x00, 0x00, 0xbe, 0x86, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x00, 0x00, 0x3c, 0x44, 0x23, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x10, ++ 0x48, 0xc1, 0x01, 0x00, 0xbe, 0x86, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xbb, 0x86, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, ++ 0x10, 0xb0, 0x01, 0x00, 0xc0, 0x86, 0x00, 0x40, 0x2b, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, ++ 0xe0, 0xb1, 0x01, 0x00, 0xc5, 0x86, 0x22, 0x9f, 0x13, 0x6c, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x88, 0x1c, 0xcc, 0x01, 0x00, 0xf5, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xd7, 0x95, 0x00, 0x41, 0x3f, 0x43, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0xc6, 0x95, 0x00, 0x40, 0x0f, 0x30, 0x01, 0x00, ++ 0x2a, 0x87, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, ++ 0x0e, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x84, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x1a, 0xf4, 0x01, 0x00, 0xd8, 0x92, 0x00, 0x07, ++ 0x16, 0x30, 0x01, 0x00, 0xd4, 0x86, 0x22, 0x41, 0x81, 0x6c, 0x00, 0x00, ++ 0xd2, 0x86, 0x22, 0x42, 0x81, 0x6c, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xd3, 0x86, 0x22, 0x5f, 0x0f, 0x7c, 0x00, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, 0xdc, 0x86, 0xa2, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x53, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xdc, 0x86, 0x22, 0x20, 0x85, 0x6c, 0x00, 0x00, 0xd9, 0x86, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x33, 0x93, 0x00, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x25, 0x95, 0x00, 0x42, ++ 0x61, 0x31, 0x01, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x90, 0x04, 0x00, 0x07, 0x96, 0x30, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x18, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xb0, 0x01, 0x00, 0xbd, 0x87, 0xa2, 0x5f, ++ 0x81, 0x6c, 0x00, 0x00, 0xa8, 0x00, 0x2d, 0x43, 0x19, 0x80, 0x01, 0x00, ++ 0x37, 0x00, 0x2d, 0xf0, 0x24, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, ++ 0x8e, 0xf4, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, 0x90, 0x88, 0x01, 0x00, ++ 0xeb, 0x86, 0x22, 0x48, 0x8e, 0x6c, 0x00, 0x00, 0x36, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, ++ 0xeb, 0x86, 0x1f, 0xf0, 0x24, 0x6c, 0x00, 0x00, 0xea, 0x86, 0x23, 0x41, ++ 0x8f, 0x6c, 0x00, 0x00, 0xbd, 0x87, 0x00, 0x47, 0x81, 0xb0, 0x00, 0x00, ++ 0xbd, 0x87, 0x00, 0x48, 0x81, 0xb0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2d, 0xf0, 0x14, 0xb0, 0x01, 0x00, ++ 0xf0, 0x86, 0x22, 0x0a, 0x90, 0x40, 0x00, 0x00, 0xaa, 0x95, 0x00, 0x40, ++ 0x91, 0x30, 0x01, 0x00, 0xbd, 0x87, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0xb0, 0x00, 0x2d, 0x45, 0x81, 0xb0, 0x01, 0x00, 0xfc, 0x86, 0x22, 0xf0, ++ 0x2c, 0x30, 0x00, 0x00, 0xa3, 0x00, 0x2d, 0x30, 0x83, 0xb0, 0x01, 0x00, ++ 0xac, 0x00, 0x2d, 0xf3, 0x82, 0xe0, 0x01, 0x00, 0xf6, 0x86, 0xa3, 0x41, ++ 0x2c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x82, 0xb0, 0x01, 0x00, ++ 0x98, 0x00, 0x2d, 0xf0, 0x82, 0xc0, 0x01, 0x00, 0x88, 0x00, 0x2d, 0xf0, ++ 0x82, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x98, 0xe8, 0x01, 0x00, ++ 0xbd, 0x87, 0x20, 0x4c, 0x82, 0x6c, 0x00, 0x00, 0x7c, 0x00, 0x2d, 0x41, ++ 0x98, 0xe8, 0x01, 0x00, 0xbd, 0x87, 0x20, 0xf0, 0x98, 0x6c, 0x00, 0x00, ++ 0x14, 0x87, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, 0x40, 0x02, 0x00, 0x0c, ++ 0x7e, 0x89, 0x01, 0x00, 0x14, 0x87, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xbd, 0x87, 0x00, 0x49, 0x81, 0xb0, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, ++ 0x80, 0xb0, 0x01, 0x00, 0x04, 0x87, 0x22, 0x43, 0x21, 0x6f, 0x00, 0x00, ++ 0x13, 0x80, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, 0x05, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x1a, 0x80, 0x00, 0x40, 0x80, 0xdc, 0x01, 0x00, ++ 0x05, 0x87, 0xa2, 0x5e, 0x0b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x08, 0xb1, 0x01, 0x00, 0x07, 0x87, 0x9f, 0x85, 0x80, 0x32, 0x00, 0x00, ++ 0x0b, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xec, 0x82, 0x22, 0x40, ++ 0x57, 0x7d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x40, 0x57, 0x99, 0x01, 0x00, ++ 0x0b, 0x87, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0xdd, 0x82, 0x1a, 0x5b, 0x69, 0x93, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0xcb, 0x81, 0xc8, 0x01, 0x00, 0x11, 0x87, 0x22, 0x40, ++ 0xf2, 0x7f, 0x00, 0x00, 0xc4, 0x80, 0x00, 0x6f, 0x97, 0x33, 0x01, 0x00, ++ 0x13, 0x87, 0x22, 0x40, 0x73, 0x7d, 0x00, 0x00, 0xde, 0x80, 0x00, 0x41, ++ 0x8b, 0xb3, 0x00, 0x00, 0x0e, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x1b, 0x87, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x1b, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x18, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x2f, 0x92, 0x22, 0x02, ++ 0x80, 0x32, 0x00, 0x00, 0x1c, 0x87, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0x2f, 0x92, 0x1a, 0x02, ++ 0x68, 0x97, 0x00, 0x00, 0x26, 0x87, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x26, 0x87, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x23, 0x87, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x39, 0x92, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, 0x27, 0x87, 0x42, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x39, 0x92, 0x1a, 0x02, 0x68, 0x97, 0x00, 0x00, 0x31, 0x87, 0x9c, 0x0f, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x31, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x2e, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xf9, 0x82, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0x32, 0x87, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x68, 0x97, 0x01, 0x00, ++ 0xf9, 0x82, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0xa6, ++ 0x56, 0xb1, 0x01, 0x00, 0x56, 0x95, 0x2f, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x82, 0x87, 0xa2, 0x40, 0xe7, 0x6d, 0x00, 0x00, 0xb8, 0x94, 0x29, 0x41, ++ 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0xef, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x0e, 0xb0, 0x01, 0x00, 0x29, 0x00, 0x00, 0x40, ++ 0x0d, 0x98, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, 0x12, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa7, 0x13, 0xc0, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, 0x16, 0x88, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x10, 0x34, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0x34, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x20, 0x18, 0x00, 0x40, 0x11, 0x98, 0x01, 0x00, 0x00, 0xb5, 0x00, 0x0d, ++ 0x42, 0xc9, 0x01, 0x00, 0x66, 0x87, 0x22, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x47, 0x87, 0x60, 0x40, 0x81, 0x32, 0x00, 0x00, 0xff, 0xff, 0x00, 0x07, ++ 0x84, 0x89, 0x01, 0x00, 0x4e, 0x87, 0x05, 0xc2, 0x24, 0x30, 0x00, 0x00, ++ 0x58, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x83, 0x87, 0x70, 0xf0, 0x18, 0x30, 0x01, 0x00, ++ 0x66, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x70, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x5d, 0x87, 0xa0, 0x48, 0x23, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x35, 0xd0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x1a, ++ 0x42, 0xc9, 0x01, 0x00, 0x57, 0x87, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x1a, ++ 0x62, 0xdd, 0x01, 0x00, 0x54, 0x87, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x20, 0x98, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x83, 0x87, 0x00, 0xf8, 0x18, 0x30, 0x01, 0x00, ++ 0x58, 0x87, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, 0xff, 0xff, 0x00, 0x10, ++ 0x34, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x34, 0x94, 0x01, 0x00, ++ 0x20, 0x18, 0x00, 0x40, 0x11, 0x98, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x1a, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x1a, 0x62, 0xdd, 0x01, 0x00, ++ 0x61, 0x87, 0xa8, 0x09, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x35, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x11, 0xc0, 0x01, 0x00, 0x72, 0x87, 0x22, 0x41, ++ 0x0d, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, ++ 0x6e, 0x87, 0xa0, 0xaa, 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x0f, 0xb0, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, 0x12, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa7, 0x13, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1b, 0xb0, 0x01, 0x00, 0x45, 0x87, 0x00, 0x41, 0x17, 0xb0, 0x00, 0x00, ++ 0x00, 0x02, 0x00, 0x09, 0x12, 0xc8, 0x01, 0x00, 0x45, 0x87, 0x83, 0x41, ++ 0x17, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x17, 0xb0, 0x01, 0x00, ++ 0x45, 0x87, 0x00, 0x41, 0x1b, 0xc0, 0x00, 0x00, 0x7d, 0x87, 0x23, 0x40, ++ 0x23, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x35, 0xd0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x1a, 0x42, 0xc9, 0x01, 0x00, 0x7a, 0x87, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x1a, 0x62, 0xdd, 0x01, 0x00, 0x77, 0x87, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x20, 0x98, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x83, 0x87, 0x00, 0xf8, ++ 0x18, 0x30, 0x01, 0x00, 0x7b, 0x87, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x0f, 0xc0, 0x01, 0x00, 0x80, 0x87, 0xa0, 0xaa, ++ 0x0f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xb0, 0x01, 0x00, ++ 0xb8, 0x94, 0x20, 0x07, 0xe4, 0xb1, 0x01, 0x00, 0x56, 0x95, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x14, 0x87, 0x00, 0x40, 0x0f, 0xb0, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x0c, 0x80, 0xd8, 0x01, 0x00, 0xc0, 0x02, 0x00, 0x0c, ++ 0x7e, 0x89, 0x01, 0x00, 0x95, 0x87, 0x26, 0x54, 0x61, 0x31, 0x00, 0x00, ++ 0x8b, 0x87, 0x87, 0x0c, 0x80, 0x32, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x40, ++ 0x62, 0x99, 0x01, 0x00, 0x8b, 0x87, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x8b, 0x87, 0xa2, 0x54, 0x77, 0x7d, 0x00, 0x00, 0x87, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x90, 0x87, 0x22, 0x46, 0x19, 0x7c, 0x00, 0x00, ++ 0x0d, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x01, 0x00, ++ 0x8c, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x95, 0x87, 0x22, 0x49, ++ 0x19, 0x7c, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x54, ++ 0x77, 0x7d, 0x01, 0x00, 0x90, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0x62, 0x99, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x54, 0x77, 0x7d, 0x01, 0x00, ++ 0x95, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x30, 0x94, 0x2f, 0x55, ++ 0xf1, 0x93, 0x01, 0x00, 0x00, 0x40, 0x00, 0xa6, 0x56, 0xb1, 0x01, 0x00, ++ 0xf9, 0x82, 0xa2, 0x41, 0xe5, 0x51, 0x00, 0x00, 0x64, 0x00, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x9d, 0x87, 0x44, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xa0, 0x87, 0xa2, 0x93, 0x57, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x57, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x1c, 0xab, 0x27, 0xb3, 0x01, 0x00, ++ 0xf9, 0x82, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, 0xf9, 0x82, 0x22, 0x51, ++ 0xfd, 0x7f, 0x00, 0x00, 0xf9, 0x82, 0xa2, 0x41, 0x1d, 0x53, 0x00, 0x00, ++ 0x50, 0x46, 0x00, 0x40, 0x1d, 0x9b, 0x01, 0x00, 0x38, 0x05, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0xac, 0x87, 0x22, 0x40, ++ 0xb5, 0x6f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x41, 0xb5, 0x53, 0x01, 0x00, 0xf9, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xfd, 0x83, 0x01, 0x00, ++ 0x40, 0x16, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x40, 0x05, 0x00, 0x40, ++ 0x49, 0x31, 0x01, 0x00, 0x1e, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x10, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0xda, ++ 0x91, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, ++ 0x20, 0x04, 0x00, 0x40, 0xb5, 0x33, 0x01, 0x00, 0x60, 0x16, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0x40, 0x82, 0x00, 0x40, 0xb5, 0x33, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0xff, 0xff, 0x00, 0x4a, ++ 0xb4, 0x8b, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x0a, 0x00, 0x00, 0x48, 0xb2, 0xcb, 0x01, 0x00, 0x10, 0x00, 0x00, 0x4a, ++ 0xb4, 0xf7, 0x01, 0x00, 0x20, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xf9, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x05, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x08, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x20, 0x40, 0xe6, 0xb1, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x96, 0xc0, 0x01, 0x00, ++ 0xc3, 0x87, 0x00, 0x4b, 0x10, 0xc9, 0x00, 0x00, 0xe6, 0x8a, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x1a, 0x8b, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x4c, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x4c, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x4c, 0x8b, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x4c, 0x8b, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x8b, 0x8b, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xb4, 0x8b, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xb8, 0x8b, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x03, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xc4, 0x8b, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xc3, 0x8b, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x73, 0x8c, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x73, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x73, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x93, 0x8c, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xb1, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xb1, 0x8c, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xb1, 0x8c, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xd9, 0x8c, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0xea, 0x8c, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0xea, 0x8c, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xec, 0x8c, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0xec, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xec, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xec, 0x8c, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xf4, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x05, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0xf5, 0x8c, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x05, 0x8d, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x06, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xfc, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x71, 0x8c, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x71, 0x8c, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x71, 0x8c, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x41, ++ 0x09, 0xb0, 0x00, 0x00, 0x07, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x07, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x07, 0x8d, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x0e, 0x8d, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x10, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x1c, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x7b, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xb8, 0x8b, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x03, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x83, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xb8, 0x8b, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x03, 0x8d, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x94, 0x8d, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x88, 0x8b, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x7f, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0xb8, 0x8b, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x03, 0x8d, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x8f, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x08, 0xb0, 0x01, 0x00, 0x06, 0x00, 0x20, 0x47, ++ 0xe6, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x47, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x96, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x96, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x96, 0xc0, 0x01, 0x00, ++ 0x83, 0x88, 0x00, 0x4b, 0x10, 0xc9, 0x00, 0x00, 0xac, 0x8d, 0x00, 0x49, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xe5, 0x8d, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xeb, 0x8d, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xf9, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x1a, 0x8e, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x15, 0x8e, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x1d, 0x8e, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x75, 0x8e, 0x00, 0x44, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x74, 0x8e, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xee, 0x8d, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0xee, 0x8d, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0xee, 0x8d, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x49, 0x09, 0xb0, 0x00, 0x00, ++ 0xee, 0x8d, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0xee, 0x8d, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0xee, 0x8d, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd4, 0x8e, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xd4, 0x8e, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd4, 0x8e, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xec, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x03, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xe0, 0x8e, 0x00, 0x45, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x41, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x1a, 0x8e, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0xf9, 0x8d, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x15, 0x8e, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x75, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0x1d, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x74, 0x8e, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x09, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x09, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8a, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8a, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x09, 0x8f, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xee, 0x8d, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, 0x2c, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x14, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x14, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x14, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x2c, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x14, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x3b, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x3b, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x9d, 0x8f, 0x00, 0x40, 0x09, 0xb0, 0x00, 0x00, 0xba, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xae, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x0c, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x0c, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xba, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xc1, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0xc1, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xae, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x0c, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x0c, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xae, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xd4, 0x8e, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd4, 0x8e, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0xd4, 0x8e, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xd4, 0x8e, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xd4, 0x8e, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x2b, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x1f, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x2b, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8a, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xcf, 0x8a, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x1f, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x1f, 0x8f, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xc3, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x4b, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xc3, 0x8f, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0xc3, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x4c, ++ 0x09, 0xb0, 0x00, 0x00, 0xc3, 0x8f, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xdd, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x03, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xdd, 0x8f, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xd8, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x03, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd8, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xd8, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xfb, 0x90, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xfa, 0x90, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xfb, 0x90, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xfa, 0x90, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xce, 0x8f, 0x00, 0x41, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xda, 0x8f, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xda, 0x8f, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xda, 0x8f, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xda, 0x8f, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xda, 0x8f, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0xda, 0x8f, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0xda, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0xda, 0x8f, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xda, 0x8f, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xec, 0x8e, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x03, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0xe0, 0x8e, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x8f, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x36, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x36, 0x91, 0x00, 0x44, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x36, 0x91, 0x00, 0x4b, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x36, 0x91, 0x00, 0x45, 0x09, 0xb0, 0x00, 0x00, ++ 0x36, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x36, 0x91, 0x00, 0x4c, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0xe0, 0x8e, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x41, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xe0, 0x8e, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x03, 0x8f, 0x00, 0x47, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x41, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x41, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x45, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x03, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x87, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x45, 0x91, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x56, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x34, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x56, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x34, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x67, 0x91, 0x00, 0x43, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x03, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x67, 0x91, 0x00, 0x43, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x67, 0x91, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0xf9, 0x8d, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x1a, 0x8e, 0x00, 0x42, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x85, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x1a, 0x8e, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0xf9, 0x8d, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x85, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x87, 0x91, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x03, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x87, 0x91, 0x00, 0x4a, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x42, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x42, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x03, 0x8f, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x42, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x42, 0x91, 0x00, 0x46, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x8d, 0x91, 0x00, 0x42, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x34, 0x91, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x8d, 0x91, 0x00, 0x46, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x48, 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x34, 0x91, 0x00, 0x4a, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x1d, 0x8e, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x1d, 0x8e, 0x00, 0x4d, 0x09, 0xb0, 0x00, 0x00, ++ 0x13, 0x8e, 0x00, 0x47, 0x09, 0xb0, 0x00, 0x00, 0x13, 0x8e, 0x00, 0x48, ++ 0x09, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, ++ 0x85, 0xb0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x20, 0x85, 0xb0, 0x00, 0x00, 0x07, 0x00, 0x2e, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x1f, 0x87, 0x00, 0x04, 0xe6, 0xb1, 0x00, 0x00, ++ 0xcf, 0x8a, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x83, 0x94, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xcf, 0x8a, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0xee, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xdf, 0x8a, 0x9c, 0x0f, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0xdf, 0x8a, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xdc, 0x8a, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xa3, 0x84, 0x22, 0x02, 0x80, 0x32, 0x00, 0x00, ++ 0xe0, 0x8a, 0x42, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x68, 0x97, 0x01, 0x00, ++ 0xa3, 0x84, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x05, 0x00, 0x2e, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x1f, 0x87, 0x00, 0x04, 0xe6, 0xb1, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0xa1, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xe0, 0xb1, 0x01, 0x00, 0xc6, 0x95, 0x00, 0x06, 0x07, 0x40, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0x07, 0xd0, 0x01, 0x00, 0xd4, 0x00, 0x2e, 0x5c, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0xb1, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0x96, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, ++ 0x96, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x96, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x96, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x96, 0xc0, 0x01, 0x00, 0x00, 0x30, 0x00, 0x4b, ++ 0x94, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x95, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x96, 0xc0, 0x01, 0x00, 0x5e, 0x01, 0x2e, 0x34, ++ 0x97, 0x84, 0x01, 0x00, 0x02, 0x00, 0x00, 0x4b, 0xe4, 0xe5, 0x01, 0x00, ++ 0x64, 0x01, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x86, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x2e, 0xa7, 0x87, 0xc0, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x10, 0x48, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x58, 0x01, 0x00, 0x43, 0xf0, 0xc9, 0x01, 0x00, ++ 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x09, 0x8b, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x08, 0x00, 0x2e, 0x40, 0x95, 0xb0, 0x01, 0x00, 0x11, 0x8b, 0x20, 0x4b, ++ 0x94, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x0e, 0x8b, 0x00, 0x41, 0x95, 0xc0, 0x00, 0x00, 0x10, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x18, 0x8b, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x14, 0x8b, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x83, 0x94, 0x00, 0x40, 0x81, 0x30, 0x01, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x86, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x88, 0xb0, 0x01, 0x00, 0x1d, 0x8b, 0x44, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x20, 0x8b, 0xa2, 0x4c, 0xfd, 0x7f, 0x00, 0x00, ++ 0x21, 0x8b, 0x00, 0x4c, 0xfd, 0x93, 0x00, 0x00, 0x22, 0x8b, 0x20, 0xf0, ++ 0x56, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x56, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x1c, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x64, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x70, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x28, 0x8b, 0xa8, 0x44, ++ 0xe0, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x8c, 0xc8, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x46, 0x44, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x40, ++ 0xf1, 0x99, 0x01, 0x00, 0x68, 0x01, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x43, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x62, 0xb1, 0x01, 0x00, ++ 0x30, 0x8b, 0xa8, 0x44, 0xe0, 0x31, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x09, 0x00, 0x00, 0x07, 0x86, 0xe4, 0x01, 0x00, ++ 0x38, 0x00, 0x2e, 0xa7, 0x87, 0xc0, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x38, 0x8b, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, 0x3b, 0x8b, 0x22, 0x44, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x45, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x19, 0x90, 0x01, 0x00, 0x68, 0x01, 0x20, 0xa2, ++ 0xe4, 0xb1, 0x01, 0x00, 0x88, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x3f, 0x8b, 0x23, 0x0b, 0xe5, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x19, 0x90, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x50, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x58, 0x01, 0x00, 0x43, ++ 0xf0, 0xc9, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x44, 0x8b, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x5c, 0x00, 0x2e, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xf0, 0x96, 0xb0, 0x01, 0x00, 0x83, 0x94, 0x00, 0x41, ++ 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x4f, 0x8b, 0xa2, 0x49, 0x19, 0x7c, 0x00, 0x00, 0x86, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x53, 0x8b, 0x00, 0x40, 0xe5, 0xb1, 0x00, 0x00, ++ 0x86, 0x00, 0x2f, 0x49, 0x19, 0x80, 0x01, 0x00, 0x53, 0x8b, 0xa2, 0xf2, ++ 0x80, 0x32, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xe7, 0x91, 0x01, 0x00, 0x56, 0x8b, 0xa2, 0x46, ++ 0x19, 0x7c, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x5a, 0x8b, 0x00, 0x40, 0xe5, 0xb1, 0x00, 0x00, 0xa0, 0x00, 0x2f, 0x46, ++ 0x19, 0x80, 0x01, 0x00, 0x5a, 0x8b, 0xa2, 0xf2, 0x80, 0x32, 0x00, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0xe7, 0x91, 0x01, 0x00, 0xa8, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x34, 0x00, 0x2d, 0xf0, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0x0c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfb, 0x12, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, ++ 0x16, 0x88, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, 0x14, 0xf4, 0x01, 0x00, ++ 0x85, 0x8b, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, 0x6d, 0x8b, 0x22, 0x0a, ++ 0x16, 0x6c, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, ++ 0x84, 0x30, 0x00, 0x00, 0x70, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x13, 0xc0, 0x01, 0x00, ++ 0x6c, 0x8b, 0xa0, 0x43, 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0x62, 0x8b, 0x00, 0x41, 0x15, 0xd0, 0x00, 0x00, ++ 0x85, 0x8b, 0x22, 0x0a, 0x80, 0x32, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x43, ++ 0x13, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x84, 0x30, 0x00, 0x00, 0x70, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x85, 0x8b, 0x22, 0x41, 0x15, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x11, 0xc0, 0x01, 0x00, 0x79, 0x8b, 0xa0, 0x43, ++ 0x11, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0xb0, 0x01, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x11, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x36, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x00, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x83, 0xb0, 0x01, 0x00, 0xc2, 0x94, 0x00, 0x47, ++ 0x61, 0x31, 0x01, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x2c, 0x92, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x81, 0x8b, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x75, 0x8b, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x37, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xf4, 0x94, 0x00, 0x51, ++ 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x34, 0x00, 0x2e, 0x41, 0xf5, 0xb1, 0x01, 0x00, 0x00, 0x11, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x8d, 0x8b, 0x00, 0x48, 0x19, 0x90, 0x00, 0x00, ++ 0x34, 0x00, 0x2e, 0x41, 0xf5, 0xb1, 0x01, 0x00, 0x00, 0x11, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x92, 0x8b, 0x22, 0x45, ++ 0x23, 0x7c, 0x00, 0x00, 0xb0, 0x00, 0x2f, 0xf0, 0x8c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xf0, 0x8c, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x35, 0x00, 0x2d, 0xf0, 0x8c, 0xb0, 0x01, 0x00, ++ 0x58, 0x00, 0x3e, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0x97, 0x8b, 0x22, 0x48, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8d, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x0a, 0x8c, 0xc0, 0x01, 0x00, 0x38, 0x00, 0x2a, 0x4a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0x3c, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x38, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x26, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf8, ++ 0x02, 0x30, 0x00, 0x00, 0xa5, 0x8b, 0x23, 0x01, 0x14, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x4c, 0x00, 0x20, 0xf0, 0xe4, 0xb1, 0x01, 0x00, ++ 0x44, 0x00, 0x20, 0x40, 0xe0, 0xb1, 0x01, 0x00, 0x48, 0x00, 0x20, 0x41, ++ 0xe0, 0xb1, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0xaa, 0x95, 0x00, 0xf0, 0x24, 0x30, 0x01, 0x00, 0xae, 0x8b, 0xa2, 0x44, ++ 0x81, 0x6c, 0x00, 0x00, 0xac, 0x8b, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x57, 0x93, 0x00, 0x40, 0x3b, 0x30, 0x01, 0x00, 0xd2, 0x8b, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0xae, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x94, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd2, 0x8b, 0xa2, 0x08, ++ 0x3c, 0x30, 0x00, 0x00, 0x50, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, ++ 0x54, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, 0x4e, 0x00, 0x20, 0x01, ++ 0xe4, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, ++ 0xf4, 0x94, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x36, 0x93, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, 0x8d, 0x8b, 0x22, 0x4a, ++ 0x80, 0x32, 0x00, 0x00, 0xba, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x36, 0x93, 0x00, 0xf3, ++ 0x94, 0x30, 0x01, 0x00, 0x58, 0x00, 0x3e, 0x43, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0xf0, 0xb1, 0x01, 0x00, 0x1f, 0x00, 0x60, 0x00, ++ 0x00, 0x8c, 0x01, 0x00, 0xe4, 0x8a, 0x85, 0x11, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0xf0, ++ 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x8c, 0xc0, 0x01, 0x00, ++ 0xf4, 0x94, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc4, 0x8b, 0x00, 0x49, 0x19, 0x80, 0x00, 0x00, ++ 0xc9, 0x8b, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x57, 0x93, 0x00, 0x40, ++ 0x3b, 0x30, 0x01, 0x00, 0xcd, 0x8b, 0xa2, 0x08, 0x3c, 0x30, 0x00, 0x00, ++ 0xf4, 0x94, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x94, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xcd, 0x8b, 0xa2, 0x08, 0x3c, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x5f, ++ 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x50, 0x00, 0x2d, 0x10, 0x32, 0xb0, 0x01, 0x00, 0x54, 0x00, 0x2d, 0xf0, ++ 0x38, 0xb0, 0x01, 0x00, 0x4e, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x40, 0x00, 0x2d, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x14, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, 0x8c, 0xc8, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x46, 0x44, 0xc9, 0x01, 0x00, 0x68, 0x01, 0x2d, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x68, 0xf2, 0x80, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x37, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x36, 0xd0, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0x40, ++ 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x52, 0x81, 0xd0, 0x01, 0x00, 0x89, 0x94, 0x00, 0x40, ++ 0xe4, 0x31, 0x01, 0x00, 0x20, 0x00, 0x00, 0x46, 0x62, 0xdd, 0x01, 0x00, ++ 0xde, 0x8b, 0xa8, 0x40, 0x23, 0x30, 0x00, 0x00, 0xce, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd6, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xec, 0x8b, 0x82, 0x41, 0x23, 0x40, 0x00, 0x00, 0x20, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0xe9, 0x8b, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xe6, 0x8b, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x23, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x44, 0xc9, 0x01, 0x00, 0xf4, 0x8b, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xf0, 0x8b, 0xa3, 0x01, 0x0c, 0x6c, 0x00, 0x00, 0xf1, 0x8b, 0x00, 0x06, ++ 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0xb0, 0x01, 0x00, ++ 0xf3, 0x8b, 0x20, 0x02, 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x04, 0xb0, 0x01, 0x00, 0xf7, 0x8b, 0x00, 0x02, 0xe0, 0xb1, 0x00, 0x00, ++ 0xf6, 0x8b, 0xa3, 0x01, 0x0c, 0x6c, 0x00, 0x00, 0xf7, 0x8b, 0x00, 0x06, ++ 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0x02, 0x16, 0x94, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, ++ 0x16, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x68, 0x08, 0x3e, 0x96, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1c, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0xfc, 0x8b, 0xa8, 0x13, 0xe0, 0x31, 0x00, 0x00, 0x33, 0x8c, 0x22, 0x02, ++ 0x14, 0x50, 0x00, 0x00, 0x44, 0x00, 0x2d, 0x02, 0x0c, 0xd0, 0x01, 0x00, ++ 0x23, 0x8c, 0xa2, 0x02, 0x02, 0x50, 0x00, 0x00, 0x0a, 0x8c, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x20, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x09, 0x8c, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x05, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x44, 0x00, 0x2d, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x48, 0x00, 0x2d, 0xf0, ++ 0x38, 0xb0, 0x01, 0x00, 0x4c, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x38, 0x00, 0x2f, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x24, 0x8c, 0x22, 0x01, ++ 0x14, 0x6c, 0x00, 0x00, 0x17, 0x8c, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0x1f, 0x80, 0x01, 0x00, 0x20, 0x00, 0x2d, 0x03, ++ 0x48, 0xb1, 0x01, 0x00, 0x16, 0x8c, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x13, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x38, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, ++ 0x38, 0x00, 0x2d, 0xf0, 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0xe1, 0xc1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x4a, 0xf1, 0xb1, 0x01, 0x00, 0x44, 0x00, 0x00, 0x05, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, ++ 0x20, 0x8c, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, 0x24, 0x8c, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0xc0, 0x01, 0x00, ++ 0x2e, 0x8c, 0x22, 0x06, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x33, 0xc0, 0x01, 0x00, 0x2c, 0x8c, 0xa2, 0x02, 0x36, 0x6c, 0x00, 0x00, ++ 0x04, 0x00, 0x8f, 0x0d, 0x42, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0xf8, ++ 0x10, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x11, 0x80, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x37, 0x98, 0x01, 0x00, 0xe2, 0x8b, 0x00, 0xa1, ++ 0x1a, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, ++ 0xe2, 0x8b, 0x00, 0x02, 0x36, 0xd0, 0x00, 0x00, 0x50, 0x00, 0x20, 0x1c, ++ 0xe0, 0xb1, 0x01, 0x00, 0x54, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, ++ 0x4e, 0x00, 0x20, 0x01, 0xe4, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x0a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x38, 0x8c, 0x00, 0x5f, 0x01, 0xb0, 0x00, 0x00, ++ 0x37, 0x00, 0x2d, 0x46, 0x01, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0xf3, ++ 0x80, 0xf4, 0x01, 0x00, 0x37, 0x8c, 0xa0, 0x43, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x01, 0xb0, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, ++ 0x3e, 0x8c, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, ++ 0x3b, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xd3, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x45, 0x8c, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x42, 0x8c, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x60, 0x01, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x17, 0xf0, 0x01, 0x00, ++ 0x4a, 0x8c, 0x90, 0xf2, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, ++ 0x32, 0x00, 0x00, 0xa6, 0x2a, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x2a, 0x94, 0x01, 0x00, 0x4d, 0x8c, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0xd0, 0x00, 0x1e, 0x62, 0xdd, 0x01, 0x00, 0x52, 0x8c, 0x28, 0x40, ++ 0x05, 0x30, 0x00, 0x00, 0x4e, 0x8c, 0x22, 0x48, 0x77, 0x7d, 0x00, 0x00, ++ 0x55, 0x8c, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x62, 0xb1, 0x01, 0x00, 0x5e, 0x8c, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x52, 0x8c, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, ++ 0x92, 0xb0, 0x01, 0x00, 0x5b, 0x8c, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x99, 0x92, 0x00, 0xf8, ++ 0x00, 0x30, 0x01, 0x00, 0x58, 0x8c, 0xa2, 0x41, 0x3b, 0x50, 0x00, 0x00, ++ 0x5f, 0x8c, 0x00, 0x49, 0x00, 0xb0, 0x00, 0x00, 0xff, 0x07, 0x00, 0x1e, ++ 0x00, 0x8c, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x5f, 0x8c, 0x00, 0x49, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x47, ++ 0x19, 0x80, 0x01, 0x00, 0x62, 0x8c, 0x22, 0x5f, 0x01, 0x6c, 0x00, 0x00, ++ 0xd4, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xbf, 0x87, 0x00, 0x00, ++ 0x80, 0xb0, 0x00, 0x00, 0x69, 0x8c, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x20, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x69, 0x8c, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x66, 0x8c, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x69, 0x8c, 0x40, 0x05, 0x48, 0x31, 0x00, 0x00, 0xff, 0xff, 0x00, 0x07, ++ 0x94, 0x89, 0x01, 0x00, 0x6f, 0x8c, 0x85, 0xca, 0x94, 0x30, 0x00, 0x00, ++ 0xd4, 0x95, 0x18, 0x5c, 0x1f, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x0f, ++ 0x1e, 0x8c, 0x01, 0x00, 0xe0, 0x86, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf4, 0x94, 0x18, 0x00, 0x80, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x47, ++ 0x19, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x80, 0x01, 0x00, ++ 0xe4, 0x8a, 0x22, 0x47, 0x19, 0x7c, 0x00, 0x00, 0x94, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x76, 0x8c, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x89, 0x94, 0x00, 0x40, ++ 0x0d, 0x30, 0x01, 0x00, 0x9c, 0x01, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0xff, 0xff, 0x00, 0x0b, 0x98, 0x88, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x50, ++ 0x17, 0xf0, 0x01, 0x00, 0x7c, 0x8c, 0x90, 0x4c, 0x16, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x7e, 0x8c, 0x22, 0x43, ++ 0xe7, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x66, 0x20, 0x17, 0xa4, 0x01, 0x00, 0x68, 0x01, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x5c, 0x01, 0x2e, 0xf2, 0x80, 0xb0, 0x01, 0x00, ++ 0x02, 0x00, 0x62, 0x40, 0x7e, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, ++ 0x81, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x40, 0xf0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0xf0, 0xb1, 0x01, 0x00, 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x88, 0x8c, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x8c, 0x8c, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x50, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, 0x92, 0x8c, 0x28, 0x40, ++ 0x05, 0x30, 0x00, 0x00, 0x8d, 0x8c, 0x22, 0x48, 0x77, 0x7d, 0x00, 0x00, ++ 0x99, 0x92, 0x1d, 0x08, 0x00, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xe4, 0x8a, 0x1d, 0x47, 0x19, 0x80, 0x00, 0x00, ++ 0x35, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x84, 0xc8, 0x01, 0x00, 0x97, 0x8c, 0xa0, 0x43, 0x85, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, 0xa8, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x37, 0x00, 0x2f, 0xf0, 0x24, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, 0xa2, 0x8c, 0xa2, 0x41, ++ 0x9e, 0x06, 0x00, 0x00, 0xe4, 0x8a, 0x22, 0x44, 0x83, 0x70, 0x00, 0x00, ++ 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x58, 0x00, 0x3d, 0x43, ++ 0xe7, 0xe1, 0x01, 0x00, 0xe4, 0x8a, 0x1f, 0xf0, 0x24, 0x6c, 0x00, 0x00, ++ 0xd4, 0x95, 0x00, 0x48, 0x81, 0x30, 0x01, 0x00, 0xbf, 0x87, 0x23, 0x41, ++ 0x83, 0x6c, 0x00, 0x00, 0xbf, 0x87, 0x00, 0x47, 0x81, 0xb0, 0x00, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x85, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x36, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, ++ 0x28, 0x00, 0x00, 0x40, 0x83, 0x98, 0x01, 0x00, 0xc2, 0x94, 0x00, 0x47, ++ 0x61, 0x31, 0x01, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2d, 0x03, 0x48, 0xb1, 0x01, 0x00, 0x08, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x8e, 0xb0, 0x01, 0x00, ++ 0x90, 0x00, 0x2d, 0xf0, 0x14, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x93, 0x8b, 0xa2, 0x40, 0x8f, 0x7c, 0x00, 0x00, ++ 0xb0, 0x8c, 0x22, 0x47, 0x8f, 0x7c, 0x00, 0x00, 0x93, 0x8b, 0x00, 0x48, ++ 0x19, 0x90, 0x00, 0x00, 0x1f, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x36, 0x00, 0x2d, 0x5d, 0x05, 0xb4, 0x01, 0x00, 0x37, 0x00, 0x2d, 0xf3, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x8e, 0xb0, 0x01, 0x00, ++ 0x5c, 0x00, 0x3d, 0x43, 0x81, 0xe0, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x24, 0xb0, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x86, 0xdc, 0x01, 0x00, 0x40, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x9b, 0x91, 0x00, 0x4a, 0xf0, 0x31, 0x01, 0x00, ++ 0x36, 0x00, 0x2f, 0x5c, 0x1f, 0x90, 0x01, 0x00, 0xbe, 0x8c, 0xa2, 0x50, ++ 0x8f, 0x50, 0x00, 0x00, 0x34, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x63, 0x41, ++ 0x81, 0xc0, 0x01, 0x00, 0xc1, 0x8c, 0xa0, 0x43, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x40, 0x81, 0xb0, 0x01, 0x00, 0x37, 0x00, 0x20, 0x47, ++ 0xe6, 0xb1, 0x01, 0x00, 0xe4, 0x8a, 0x22, 0x47, 0x80, 0x32, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x47, 0x0c, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x8f, 0x84, 0x01, 0x00, 0xd6, 0x8c, 0x22, 0x47, 0x0c, 0x6c, 0x00, 0x00, ++ 0x58, 0x00, 0x3d, 0x43, 0x81, 0xe0, 0x01, 0x00, 0xd6, 0x8c, 0x1f, 0xf0, ++ 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xcf, 0x8c, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xcc, 0x8c, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xcf, 0x8c, 0x42, 0x40, 0x05, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x93, 0x93, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x5d, 0x69, 0x93, 0x01, 0x00, ++ 0xd4, 0x8c, 0x23, 0x41, 0x0d, 0x6c, 0x00, 0x00, 0xb1, 0x8c, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xd4, 0x95, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, ++ 0xbf, 0x87, 0x00, 0x48, 0x81, 0xb0, 0x00, 0x00, 0xe4, 0x8a, 0x22, 0x40, ++ 0x8f, 0x6c, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x84, 0xb0, 0x01, 0x00, ++ 0xa6, 0x00, 0x2d, 0x49, 0x19, 0x90, 0x01, 0x00, 0x02, 0x00, 0x00, 0xf2, ++ 0x80, 0xf4, 0x01, 0x00, 0xb8, 0x00, 0x2d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x82, 0xf8, 0x01, 0x00, 0x19, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0xe5, 0x8c, 0xa0, 0x40, 0x82, 0x6c, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x40, ++ 0x81, 0x98, 0x01, 0x00, 0xe5, 0x8c, 0xa3, 0x40, 0x82, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x80, 0xb0, 0x01, 0x00, 0xe7, 0x8c, 0x20, 0x4c, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x85, 0xc0, 0x01, 0x00, ++ 0x86, 0x00, 0x20, 0x40, 0xe4, 0xb1, 0x01, 0x00, 0xa2, 0x00, 0x20, 0x42, ++ 0xe6, 0xb1, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x83, 0x94, 0x00, 0x50, 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0xc6, 0x95, 0x00, 0x40, 0x87, 0x30, 0x01, 0x00, ++ 0xb0, 0x00, 0x2f, 0x5c, 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x60, 0xf0, ++ 0x80, 0xc0, 0x01, 0x00, 0xf4, 0x94, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xe4, 0x8a, 0x22, 0x46, 0x19, 0x7c, 0x00, 0x00, ++ 0xa0, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0xf2, ++ 0x96, 0xcc, 0x01, 0x00, 0xe4, 0x8a, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xf4, 0x94, 0x00, 0x4a, 0x81, 0x30, 0x01, 0x00, 0xc9, 0x94, 0x00, 0x46, ++ 0x95, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xe4, 0x8a, 0x22, 0x49, 0x19, 0x7c, 0x00, 0x00, 0x86, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0xf2, 0x80, 0xcc, 0x01, 0x00, ++ 0xe4, 0x8a, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x4a, ++ 0x81, 0x30, 0x01, 0x00, 0xc9, 0x94, 0x00, 0x47, 0x95, 0x30, 0x01, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2c, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x62, 0xf2, 0x80, 0xc8, 0x01, 0x00, 0x0b, 0x8d, 0x90, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0xff, 0xff, 0x62, 0x40, 0x81, 0x98, 0x01, 0x00, ++ 0xa4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xe4, 0x8a, 0x22, 0x40, ++ 0xe5, 0x6d, 0x00, 0x00, 0xe4, 0x8a, 0x00, 0x41, 0xe5, 0xc1, 0x00, 0x00, ++ 0x83, 0x94, 0x00, 0x4d, 0x81, 0x30, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf0, 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x8d, 0xb0, 0x01, 0x00, 0xc6, 0x95, 0x00, 0x40, 0x87, 0x30, 0x01, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x1b, 0x8d, 0x80, 0xf3, ++ 0x96, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0x81, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x19, 0x90, 0x01, 0x00, 0xe4, 0x8a, 0x00, 0x5c, ++ 0x1f, 0x90, 0x00, 0x00, 0x34, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x40, 0xf5, 0x99, 0x01, 0x00, 0x00, 0x11, 0x00, 0x40, ++ 0xe5, 0x99, 0x01, 0x00, 0x94, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x30, 0x8d, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x51, 0x83, 0xd0, 0x01, 0x00, 0x34, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x84, 0xcc, 0x01, 0x00, ++ 0x28, 0x8d, 0x9f, 0x42, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x63, 0x42, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, 0x2a, 0x8d, 0x37, 0x5c, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, ++ 0x2b, 0x8d, 0xa8, 0x4b, 0x19, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0xb1, 0x01, 0x00, 0x2d, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x14, 0x87, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, ++ 0xac, 0x00, 0x2d, 0xf0, 0x30, 0xb0, 0x01, 0x00, 0x35, 0x00, 0x2d, 0xf0, ++ 0x28, 0xb0, 0x01, 0x00, 0x58, 0x00, 0x3e, 0x43, 0xe7, 0xe1, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x18, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x38, 0x00, 0x20, 0x00, 0xe0, 0xb1, 0x01, 0x00, ++ 0x3c, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x20, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2b, 0xb0, 0x01, 0x00, ++ 0xd8, 0x94, 0x00, 0x40, 0x0d, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0x16, 0xc0, 0x01, 0x00, 0x3f, 0x8d, 0xa0, 0x14, 0x16, 0x44, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x0e, 0x00, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf8, 0xb1, 0x01, 0x00, ++ 0xb0, 0x00, 0x2d, 0x14, 0xf8, 0xb1, 0x01, 0x00, 0x10, 0x50, 0x00, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x48, 0x8d, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x30, 0x00, 0x43, 0x86, 0xc8, 0x01, 0x00, 0x00, 0x30, 0x00, 0x0b, ++ 0x16, 0xc8, 0x01, 0x00, 0x48, 0x8d, 0xa4, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0x01, 0x00, 0x6e, 0x43, ++ 0x86, 0x98, 0x01, 0x00, 0x0f, 0x95, 0x00, 0x30, 0x81, 0x30, 0x01, 0x00, ++ 0x4c, 0x8d, 0xa0, 0x41, 0x17, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x53, 0x8d, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0xab, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0x17, 0xc0, 0x01, 0x00, ++ 0x52, 0x8d, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x64, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x90, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x60, 0x41, ++ 0x31, 0xc0, 0x01, 0x00, 0xbc, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x59, 0x8d, 0x06, 0x0c, 0x80, 0x32, 0x00, 0x00, 0xa0, 0x00, 0x20, 0xf2, ++ 0xe4, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x09, 0x46, 0x19, 0x10, 0x00, 0x00, ++ 0x9c, 0x01, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0xff, 0xff, 0x00, 0x0b, ++ 0x98, 0x88, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x50, 0x17, 0xf0, 0x01, 0x00, ++ 0x5e, 0x8d, 0x90, 0x4c, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x60, 0x8d, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x66, 0x20, ++ 0x17, 0xa4, 0x01, 0x00, 0x68, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x5c, 0x01, 0x2e, 0xf2, 0x80, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x62, 0x40, ++ 0x7e, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57, 0x81, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, 0x03, 0x00, 0x00, 0x40, ++ 0xf0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf0, 0xb1, 0x01, 0x00, ++ 0x58, 0x01, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x6a, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x6e, 0x8d, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, 0x00, 0x50, 0x00, 0x08, ++ 0x62, 0xdd, 0x01, 0x00, 0x6f, 0x8d, 0xa8, 0x40, 0x05, 0x30, 0x00, 0x00, ++ 0x35, 0x00, 0x1d, 0x40, 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x84, 0xc8, 0x01, 0x00, 0x75, 0x8d, 0xa0, 0x43, 0x85, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x63, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, ++ 0x8b, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0xe7, 0x91, 0x01, 0x00, 0xf4, 0x94, 0x00, 0x5f, 0x81, 0x30, 0x01, 0x00, ++ 0xe4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x36, 0x93, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, ++ 0x1f, 0x8d, 0x22, 0x4a, 0x80, 0x32, 0x00, 0x00, 0xba, 0x8b, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x37, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x36, 0x93, 0x00, 0xf3, 0x94, 0x30, 0x01, 0x00, 0x8a, 0x8b, 0x22, 0x4a, ++ 0x80, 0x32, 0x00, 0x00, 0xba, 0x8b, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x36, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, ++ 0x12, 0xb0, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, 0x90, 0x88, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x0c, 0xf4, 0x01, 0x00, 0xb4, 0x8b, 0x22, 0x06, ++ 0x90, 0x6c, 0x00, 0x00, 0x5c, 0x00, 0x3d, 0x43, 0x13, 0xe0, 0x01, 0x00, ++ 0xa8, 0x00, 0x2d, 0xf0, 0x94, 0xb0, 0x01, 0x00, 0x37, 0x00, 0x2f, 0xf0, ++ 0x24, 0xb0, 0x01, 0x00, 0x36, 0x00, 0x2a, 0x50, 0xe7, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x41, 0x13, 0xc0, 0x01, 0x00, 0x8f, 0x8d, 0xa0, 0x43, ++ 0x13, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x99, 0x91, 0x00, 0x10, 0x86, 0x30, 0x01, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x91, 0x8d, 0x42, 0x05, 0x48, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, 0xb4, 0x8b, 0x1a, 0x5d, ++ 0x69, 0x93, 0x00, 0x00, 0x36, 0x00, 0x2d, 0x10, 0x86, 0xb0, 0x01, 0x00, ++ 0x5c, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, 0xa8, 0x00, 0x2d, 0xf0, ++ 0x94, 0xb0, 0x01, 0x00, 0x35, 0x00, 0x2f, 0xf0, 0x24, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x6b, 0xfb, 0x84, 0xc8, 0x01, 0x00, 0x9c, 0x8d, 0xa0, 0x43, ++ 0x85, 0x6c, 0x00, 0x00, 0x35, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x01, 0x00, 0x63, 0xf3, ++ 0x12, 0xc8, 0x01, 0x00, 0x9f, 0x8d, 0xa0, 0x43, 0x13, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x40, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x9b, 0x91, 0x00, 0x4a, 0xf0, 0x31, 0x01, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xa2, 0x8d, 0x42, 0x05, ++ 0x48, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x93, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x1a, 0x5d, 0x69, 0x93, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x11, 0x00, 0x63, 0xf3, 0x82, 0xcc, 0x01, 0x00, ++ 0x9b, 0x8c, 0x22, 0x41, 0x9e, 0x06, 0x00, 0x00, 0x35, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x58, 0x00, 0x3d, 0x43, 0xe7, 0xe1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x36, 0xb0, 0x01, 0x00, 0xa5, 0x8c, 0x00, 0xf0, ++ 0x00, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xad, 0x8d, 0x65, 0xf2, 0x12, 0x30, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, ++ 0x13, 0xf0, 0x01, 0x00, 0xb2, 0x8d, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0xf5, 0x82, 0x75, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xac, 0x8d, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xe7, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x75, 0x42, 0x19, 0x90, 0x01, 0x00, 0x75, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0xb4, 0x8d, 0xa8, 0xb1, 0x0c, 0x30, 0x00, 0x00, ++ 0x1f, 0x94, 0x00, 0x10, 0x94, 0x30, 0x01, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc0, 0xa8, 0x3d, 0x46, 0x0d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0xbe, 0x8d, 0x22, 0x40, 0xe1, 0x6d, 0x00, 0x00, ++ 0x04, 0x00, 0x02, 0x41, 0x97, 0x40, 0x00, 0x00, 0xbb, 0x8d, 0x00, 0x50, ++ 0x43, 0xc1, 0x00, 0x00, 0xca, 0x8d, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x62, 0x4b, 0x12, 0x94, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x97, 0xc0, 0x01, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x94, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x4a, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf1, 0xb1, 0x01, 0x00, ++ 0x5e, 0x01, 0x00, 0x4b, 0xf0, 0xc9, 0x01, 0x00, 0x5e, 0x01, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x4a, 0x62, 0xdd, 0x01, 0x00, 0xc8, 0x8d, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x04, 0x00, 0x00, 0x09, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x97, 0xc0, 0x01, 0x00, ++ 0xd4, 0x00, 0x00, 0x05, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0xd0, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, ++ 0xd4, 0x8d, 0x65, 0x40, 0x81, 0x32, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, ++ 0x96, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x75, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0x62, 0xb1, 0x01, 0x00, 0xd8, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xdd, 0x8d, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0xdb, 0x8d, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x97, 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x96, ++ 0x97, 0xb0, 0x01, 0x00, 0xe3, 0x8d, 0x20, 0x09, 0x96, 0x6c, 0x00, 0x00, ++ 0xe3, 0x8d, 0x1f, 0x09, 0x96, 0x24, 0x00, 0x00, 0xf5, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0xde, 0x8d, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x83, 0x94, 0x00, 0x57, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xe9, 0x8d, 0x22, 0xf3, 0x80, 0x32, 0x00, 0x00, 0x83, 0x94, 0x00, 0x42, ++ 0x81, 0x30, 0x01, 0x00, 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf4, 0x94, 0x00, 0x52, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x42, ++ 0x19, 0x80, 0x00, 0x00, 0x83, 0x94, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0xf4, 0x94, 0x00, 0x52, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x96, 0x93, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x22, 0x40, ++ 0x95, 0x6c, 0x00, 0x00, 0xf4, 0x8d, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x14, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x41, 0x93, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x7d, 0x95, 0x00, 0x40, ++ 0x95, 0x30, 0x01, 0x00, 0xff, 0x8d, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x14, 0x87, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0x83, 0x94, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x23, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0x02, 0x8e, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x08, 0x00, 0x0b, 0x16, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x2a, 0xc0, 0x01, 0x00, 0xcc, 0x94, 0x00, 0x08, 0x80, 0x30, 0x01, 0x00, ++ 0x06, 0x8e, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, 0xed, 0x94, 0x00, 0x43, ++ 0x61, 0x31, 0x01, 0x00, 0xa7, 0x91, 0x00, 0x40, 0x8d, 0x30, 0x01, 0x00, ++ 0xd4, 0x94, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x0e, 0x8e, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x0b, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x75, 0x94, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x12, 0x8e, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xd4, 0x8a, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0xc6, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x1f, 0x90, 0x01, 0x00, ++ 0x19, 0x8e, 0x22, 0x43, 0x3d, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3d, 0x80, 0x01, 0x00, ++ 0x1a, 0x8e, 0x00, 0x42, 0x19, 0x90, 0x00, 0x00, 0x14, 0x00, 0x2d, 0x45, ++ 0x1f, 0x90, 0x01, 0x00, 0x75, 0x8e, 0x83, 0x1e, 0x80, 0x32, 0x00, 0x00, ++ 0x75, 0x8e, 0x00, 0x44, 0x19, 0x90, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x2d, 0x8e, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x29, 0x8e, 0xa2, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, 0x26, 0x8e, 0xa2, 0x41, ++ 0x19, 0x7c, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x41, 0x93, 0x00, 0x15, ++ 0x94, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc6, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x83, 0x94, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0x14, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x8e, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0xc6, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x31, 0x8e, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x96, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x5d, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x15, ++ 0x98, 0xc8, 0x01, 0x00, 0x5d, 0x8e, 0xa0, 0x0b, 0x99, 0x6c, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x10, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x62, 0xb1, 0x01, 0x00, ++ 0x39, 0x8e, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x15, 0x98, 0xc8, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x0b, ++ 0x99, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x6a, 0x50, 0x99, 0xc0, 0x01, 0x00, ++ 0xc0, 0x00, 0x62, 0x01, 0x80, 0xcc, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x2d, 0x00, 0x2d, 0xf0, 0x22, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x80, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x23, 0x80, 0x01, 0x00, 0xd4, 0x00, 0x3f, 0x41, 0xe7, 0xe1, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0x11, 0xe4, 0xf5, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x47, ++ 0xe7, 0xb5, 0x01, 0x00, 0x4a, 0x8e, 0x23, 0x0b, 0x81, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0xe5, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x03, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x02, 0xd0, 0x01, 0x00, 0xcc, 0x94, 0x00, 0x00, ++ 0x2a, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x4f, 0x8e, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x01, ++ 0x80, 0xce, 0x01, 0x00, 0x5b, 0x8e, 0x26, 0x11, 0x00, 0x30, 0x00, 0x00, ++ 0x10, 0x00, 0x00, 0x00, 0x2a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, ++ 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xc0, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x99, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x98, 0xd0, 0x01, 0x00, 0xcc, 0x94, 0x00, 0x4c, 0x02, 0x30, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x03, 0x98, 0x01, 0x00, 0x62, 0x8e, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x2f, 0x08, 0x80, 0xb0, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x15, 0xf4, 0xc9, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x01, ++ 0xe4, 0xcd, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x03, 0x98, 0x01, 0x00, ++ 0xcc, 0x94, 0x00, 0x00, 0x2a, 0x40, 0x01, 0x00, 0x67, 0x8e, 0x22, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0xac, 0x00, 0x2f, 0x40, 0x13, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xc1, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x68, 0x8e, 0x00, 0x01, 0xe0, 0xd1, 0x00, 0x00, ++ 0xa7, 0x91, 0x00, 0x40, 0x8d, 0x30, 0x01, 0x00, 0x80, 0x63, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0xd4, 0x94, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x70, 0x8e, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x6d, 0x8e, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x75, 0x94, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x73, 0x8e, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xcf, 0x8a, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x75, 0x8e, 0x00, 0x4a, ++ 0x1f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb0, 0x01, 0x00, ++ 0x24, 0x00, 0x2d, 0x15, 0x10, 0xc0, 0x01, 0x00, 0x28, 0x00, 0x2d, 0xf0, ++ 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xe0, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x15, ++ 0x1a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x2a, 0xb0, 0x01, 0x00, 0x34, 0x94, 0x00, 0x40, ++ 0x35, 0xb0, 0x00, 0x00, 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xb9, 0x8e, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, 0x24, 0x00, 0x20, 0x0b, ++ 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x20, 0x13, 0xe0, 0xb1, 0x01, 0x00, ++ 0x22, 0x00, 0x20, 0x06, 0xe4, 0xb1, 0x01, 0x00, 0x8f, 0x8e, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x8f, 0x8e, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x8b, 0x8e, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0xb2, 0x8e, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0xa0, 0x8e, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0xee, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x41, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xad, 0x8e, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x96, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x9c, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xaf, 0x92, 0x00, 0x40, 0x11, 0x30, 0x01, 0x00, 0x9d, 0x8e, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x9f, 0x8e, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xf9, 0x82, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0xee, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x3d, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xa3, 0x8e, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xa9, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xaf, 0x92, 0x00, 0x40, ++ 0x11, 0x30, 0x01, 0x00, 0xaa, 0x8e, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xac, 0x8e, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xf9, 0x82, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xae, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xb5, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xaf, 0x92, 0x00, 0x40, ++ 0x11, 0x30, 0x01, 0x00, 0xb6, 0x8e, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xb8, 0x8e, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xd4, 0x8a, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0xc0, 0x8e, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xbc, 0x8e, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xc4, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xaf, 0x92, 0x00, 0x40, ++ 0x11, 0x30, 0x01, 0x00, 0xc5, 0x8e, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x08, 0x00, 0x2d, 0x0a, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x20, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0xca, 0x8e, 0x03, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0xcb, 0x8e, 0x00, 0x41, 0x87, 0xb0, 0x00, 0x00, ++ 0x21, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0xb7, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0xcf, 0x8e, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0xd2, 0x8e, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0xf4, 0x94, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x80, 0x01, 0x00, 0xcf, 0x8a, 0xa2, 0x4a, 0x1f, 0x7c, 0x00, 0x00, ++ 0xd4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xd8, 0x8e, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0xcc, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x84, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x2d, 0x95, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xc0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xc4, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x61, 0x95, 0x00, 0xf0, 0x84, 0x30, 0x01, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xd4, 0x8a, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xd4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xe4, 0x8e, 0x22, 0x40, 0xe7, 0x6d, 0x00, 0x00, ++ 0x32, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xec, 0x8e, 0xa2, 0x40, ++ 0xe5, 0x6d, 0x00, 0x00, 0x83, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x24, 0x00, 0x20, 0x0b, 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x20, 0x13, ++ 0xe0, 0xb1, 0x01, 0x00, 0x22, 0x00, 0x20, 0x06, 0xe4, 0xb1, 0x01, 0x00, ++ 0x14, 0x00, 0x20, 0x0a, 0xe0, 0xb1, 0x01, 0x00, 0xd4, 0x8a, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0xd4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x83, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x3c, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xfa, 0x8e, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0x99, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x15, 0x98, 0x50, 0x00, 0x00, ++ 0xfa, 0x8e, 0x20, 0x01, 0x98, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x46, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0xf7, 0x8e, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xac, 0x00, 0x2f, 0x00, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0xe0, 0xc1, 0x01, 0x00, 0x14, 0x00, 0x2f, 0x15, 0x10, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x60, 0x01, ++ 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0x19, 0x90, 0x01, 0x00, ++ 0x7c, 0x8e, 0x22, 0x09, 0x80, 0x32, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x09, ++ 0x80, 0x30, 0x01, 0x00, 0x7c, 0x8e, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x43, 0xc1, 0x01, 0x00, 0xb7, 0x93, 0x00, 0xf0, ++ 0x84, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0x2c, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x42, 0x19, 0x80, 0x00, 0x00, ++ 0xa9, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0xc9, 0x94, 0x00, 0x48, ++ 0x95, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x0f, 0x8f, 0xa8, 0x40, ++ 0x13, 0x30, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x15, 0x8f, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x14, 0x8f, 0x00, 0x40, ++ 0x13, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xb0, 0x01, 0x00, ++ 0x08, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x14, 0x00, 0x2d, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf0, 0x84, 0x30, 0x00, 0x00, ++ 0x13, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0xb7, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x2d, 0x8f, 0x00, 0x09, 0x00, 0xb0, 0x00, 0x00, 0xcf, 0x8a, 0x87, 0x42, ++ 0x19, 0x10, 0x00, 0x00, 0x8b, 0x00, 0x2f, 0x47, 0x19, 0x80, 0x01, 0x00, ++ 0xcf, 0x8a, 0x00, 0x40, 0xe7, 0x91, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x2b, 0x8f, 0x22, 0x47, 0xe7, 0x7d, 0x00, 0x00, ++ 0x1e, 0x92, 0x00, 0x40, 0xe7, 0x31, 0x01, 0x00, 0x2b, 0x8f, 0x22, 0x00, ++ 0x80, 0x32, 0x00, 0x00, 0x26, 0x8f, 0xa2, 0x40, 0x1f, 0x7c, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2b, 0x8f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x32, 0x00, 0x2d, 0xf2, 0x94, 0xb0, 0x01, 0x00, 0x41, 0x93, 0x00, 0xf2, ++ 0x02, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x2c, 0x8f, 0x00, 0x40, ++ 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x32, 0x8f, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0x31, 0x8f, 0xa2, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x96, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x32, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc6, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xbc, 0x8f, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x3a, 0x8f, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x37, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xbc, 0x8f, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x40, 0x8f, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x83, 0x94, 0x00, 0x4d, ++ 0x81, 0x30, 0x01, 0x00, 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x74, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x96, 0xb0, 0x01, 0x00, 0x4e, 0x8f, 0x22, 0x42, 0x96, 0x14, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x64, 0x00, 0x68, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, 0x70, 0x00, 0x00, 0x05, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x4b, 0x8f, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x4f, 0x8f, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x5e, 0x01, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x53, 0x8f, 0x65, 0xf2, 0x12, 0x30, 0x00, 0x00, ++ 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, 0x58, 0x8f, 0x22, 0x47, ++ 0xe7, 0x7d, 0x00, 0x00, 0xf5, 0x82, 0x75, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x52, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, ++ 0xe7, 0x91, 0x01, 0x00, 0x04, 0x00, 0x75, 0x09, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x97, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x60, 0x8f, 0xa8, 0x40, ++ 0xe1, 0x31, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x99, 0x3f, 0x42, 0x13, 0xf0, 0x01, 0x00, 0x64, 0x8f, 0x65, 0x05, ++ 0x48, 0x31, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x75, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x6c, 0x8f, 0x22, 0x4b, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x6a, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x16, 0xb0, 0x01, 0x00, 0x00, 0x62, 0x00, 0x0b, ++ 0x16, 0xdc, 0x01, 0x00, 0x1e, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x84, 0x8f, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0xcc, 0x93, 0x00, 0x5f, ++ 0x01, 0x10, 0x01, 0x00, 0x6e, 0x8f, 0x22, 0x40, 0x95, 0x6c, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x76, 0x8f, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x04, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf2, 0x02, 0xb0, 0x01, 0x00, 0x41, 0x93, 0x00, 0x52, ++ 0x95, 0x30, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x6e, 0x8f, 0x22, 0x41, 0x97, 0x50, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5c, 0x01, 0x80, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x6e, 0x8f, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, ++ 0xd4, 0x94, 0x00, 0x40, 0x03, 0x30, 0x01, 0x00, 0x17, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x0c, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x4c, 0x97, 0xf0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0xe1, 0xb1, 0x01, 0x00, ++ 0x75, 0x94, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0x03, 0x00, 0x00, 0x07, ++ 0x1a, 0xf4, 0x01, 0x00, 0x07, 0x00, 0x00, 0x07, 0x16, 0x88, 0x01, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0x8e, 0x8f, 0x30, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x81, 0x01, 0x00, ++ 0x00, 0xb7, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, ++ 0xe6, 0x81, 0x01, 0x00, 0x10, 0x00, 0x10, 0x0f, 0x94, 0xf4, 0x01, 0x00, ++ 0x93, 0x04, 0x00, 0x5f, 0x95, 0x04, 0x01, 0x00, 0x22, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x98, 0x8f, 0x22, 0x50, 0xfd, 0x7f, 0x00, 0x00, ++ 0x96, 0x8f, 0x46, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x41, ++ 0x31, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x0f, 0xb0, 0x01, 0x00, 0x85, 0x92, 0x00, 0x41, 0x81, 0x30, 0x01, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xa9, 0x8f, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, ++ 0xa2, 0x8f, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x62, 0xb1, 0x01, 0x00, 0xa6, 0x8f, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xa3, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0xb1, 0x01, 0x00, 0xa6, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x14, 0x87, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x74, 0x00, 0x22, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0xc9, 0x94, 0x00, 0x4a, 0x95, 0x30, 0x01, 0x00, 0xa9, 0x93, 0x00, 0x5c, ++ 0x1f, 0x10, 0x01, 0x00, 0x40, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2f, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xba, 0x8f, 0x22, 0x47, ++ 0xe7, 0x7d, 0x00, 0x00, 0x1e, 0x92, 0x00, 0x40, 0xe7, 0x31, 0x01, 0x00, ++ 0xba, 0x8f, 0x22, 0x00, 0x80, 0x32, 0x00, 0x00, 0xb5, 0x8f, 0xa2, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xba, 0x8f, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x32, 0x00, 0x2d, 0xf2, 0x94, 0xb0, 0x01, 0x00, ++ 0x41, 0x93, 0x00, 0xf2, 0x02, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc9, 0x94, 0x00, 0x48, 0x95, 0x30, 0x01, 0x00, 0xa9, 0x93, 0x00, 0x5c, ++ 0x1f, 0x10, 0x01, 0x00, 0xbf, 0x8f, 0x87, 0x42, 0x19, 0x10, 0x00, 0x00, ++ 0x8b, 0x00, 0x2f, 0x47, 0x19, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe7, 0x91, 0x01, 0x00, 0xf4, 0x94, 0x00, 0x42, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xa9, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x5c, 0x1f, 0x90, 0x00, 0x00, ++ 0xba, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, 0x2d, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xc4, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x61, 0x95, 0x00, 0xf0, ++ 0x84, 0x30, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xf4, 0x94, 0x00, 0x45, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x83, 0x94, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd3, 0x8f, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x83, 0x94, 0x00, 0x47, ++ 0x80, 0x30, 0x01, 0x00, 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0xe1, 0x00, 0xa6, 0x84, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x07, 0x84, 0x94, 0x01, 0x00, ++ 0x75, 0x94, 0x00, 0x5e, 0x05, 0x10, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x99, 0x92, 0x00, 0x41, 0xe7, 0x41, 0x01, 0x00, 0xd4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x83, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x3c, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x2c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00, 0x1f, 0x0a, ++ 0x2c, 0x50, 0x00, 0x00, 0x07, 0x95, 0x00, 0x06, 0x04, 0x30, 0x01, 0x00, ++ 0xea, 0x8f, 0xa2, 0x48, 0x1f, 0x7c, 0x00, 0x00, 0xe8, 0x8f, 0x84, 0x48, ++ 0x1f, 0x10, 0x00, 0x00, 0xac, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0xea, 0x8f, 0x00, 0x0a, 0xe0, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x02, 0xb0, 0x01, 0x00, 0xa7, 0x91, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xeb, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, ++ 0xf8, 0x8f, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, 0xf1, 0x93, 0x00, 0x45, ++ 0x1f, 0x00, 0x01, 0x00, 0xe3, 0x8f, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0xf4, 0x8f, 0xa8, 0x5c, 0x1f, 0x00, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0xe3, 0x8f, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x08, 0x00, 0x2d, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xb7, 0x93, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xfe, 0x8f, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x90, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x08, 0x90, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0xf4, 0x94, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x08, 0x90, 0xa2, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, 0x16, 0x90, 0x22, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x0e, 0x90, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0x12, 0x90, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0xc6, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x13, 0x90, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x96, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, ++ 0x32, 0x00, 0x2a, 0x15, 0xe4, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x16, ++ 0xe4, 0xb1, 0x00, 0x00, 0x28, 0x90, 0x22, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0x7d, 0x95, 0x00, 0x40, ++ 0x95, 0x30, 0x01, 0x00, 0x29, 0x90, 0x22, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0xac, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2b, 0x01, ++ 0xe0, 0xc1, 0x01, 0x00, 0x00, 0x2b, 0x00, 0xa6, 0x16, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xe0, 0xd1, 0x01, 0x00, 0xcc, 0x94, 0x00, 0x08, ++ 0x80, 0x30, 0x01, 0x00, 0x21, 0x90, 0x00, 0x5e, 0x17, 0x90, 0x00, 0x00, ++ 0xed, 0x94, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x22, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xd4, 0x94, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0x75, 0x94, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xd4, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x1f, 0x15, 0x1a, 0x50, 0x00, 0x00, 0x36, 0x90, 0x20, 0x16, ++ 0x1a, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x33, 0x90, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x2a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x2c, 0xd0, 0x01, 0x00, 0xac, 0x00, 0x2f, 0x40, 0x23, 0xb0, 0x01, 0x00, ++ 0x3d, 0x90, 0x84, 0x45, 0x1f, 0x10, 0x00, 0x00, 0x3e, 0x90, 0x00, 0x0a, ++ 0xe0, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0xb0, 0x01, 0x00, ++ 0x34, 0x94, 0x00, 0x40, 0x35, 0xb0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x42, 0xc9, 0x01, 0x00, 0x46, 0x90, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x42, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x55, 0x90, 0xa2, 0x02, 0x1a, 0x50, 0x00, 0x00, ++ 0x56, 0x90, 0x22, 0x40, 0x2d, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, ++ 0xe0, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x4d, 0x90, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, 0x10, 0xc8, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x1b, 0x98, 0x01, 0x00, 0x56, 0x90, 0x00, 0x5c, ++ 0x11, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0xc0, 0x01, 0x00, ++ 0xaf, 0x92, 0x00, 0x40, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x5a, 0x90, 0x23, 0x0d, 0x2c, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x1f, 0x90, 0x01, 0x00, 0x62, 0x90, 0x22, 0x46, ++ 0x1f, 0x7c, 0x00, 0x00, 0x70, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x62, 0x90, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x5e, 0x90, 0xa8, 0x46, 0x1f, 0x00, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x08, 0x00, 0x2d, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0xb7, 0x93, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x67, 0x90, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x6d, 0x90, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x71, 0x90, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, ++ 0xf4, 0x94, 0x00, 0x4f, 0x81, 0x30, 0x01, 0x00, 0x71, 0x90, 0xa2, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, 0x86, 0x90, 0x22, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x77, 0x90, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0x82, 0x90, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0x7b, 0x90, 0xa2, 0xf3, 0x84, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xa5, 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x85, 0xd0, 0x01, 0x00, 0xd4, 0x00, 0x3e, 0x41, 0x85, 0xe0, 0x01, 0x00, ++ 0x7f, 0x90, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, ++ 0x11, 0x90, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x08, 0xe4, 0xf5, 0x01, 0x00, ++ 0xc6, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x83, 0x90, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x96, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, 0x32, 0x00, 0x2a, 0x15, ++ 0xe4, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x16, 0xe4, 0xb1, 0x00, 0x00, ++ 0x89, 0x90, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xd6, 0x90, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0x96, 0x90, 0x22, 0x47, ++ 0x1f, 0x7c, 0x00, 0x00, 0x93, 0x90, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x8e, 0x90, 0xa2, 0xf3, 0x84, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x85, 0xd0, 0x01, 0x00, ++ 0xd4, 0x00, 0x3e, 0x41, 0x85, 0xe0, 0x01, 0x00, 0x92, 0x90, 0x22, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x11, 0x90, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0x08, 0xe4, 0xf5, 0x01, 0x00, 0x58, 0x01, 0x2d, 0x00, ++ 0x2a, 0xd0, 0x01, 0x00, 0x60, 0x01, 0x2d, 0xf0, 0x10, 0xb0, 0x01, 0x00, ++ 0x2d, 0x8e, 0x00, 0xf0, 0x2c, 0xb0, 0x00, 0x00, 0x7d, 0x95, 0x00, 0x41, ++ 0x95, 0x30, 0x01, 0x00, 0x9d, 0x90, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x97, 0xb0, 0x01, 0x00, 0x9b, 0x90, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, ++ 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0xd6, 0x90, 0x00, 0x05, ++ 0x48, 0xb1, 0x00, 0x00, 0xac, 0x00, 0x2f, 0x01, 0x14, 0xb0, 0x01, 0x00, ++ 0xb0, 0x00, 0x2b, 0x01, 0xe0, 0xc1, 0x01, 0x00, 0x00, 0x2b, 0x00, 0xa6, ++ 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xd1, 0x01, 0x00, ++ 0xad, 0x90, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0xa6, 0x90, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0xf0, ++ 0x22, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x23, 0x80, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x84, 0xb0, 0x01, 0x00, 0xb0, 0x90, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x02, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x08, 0x80, 0xb0, 0x01, 0x00, 0xb5, 0x90, 0x22, 0x40, ++ 0x1b, 0x6c, 0x00, 0x00, 0xcc, 0x94, 0x00, 0x01, 0x84, 0x50, 0x01, 0x00, ++ 0xbd, 0x90, 0x22, 0x40, 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x80, 0xc0, 0x01, 0x00, 0x10, 0x80, 0x00, 0x10, 0x46, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4f, 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x40, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa1, 0x62, 0xdd, 0x01, 0x00, ++ 0xbb, 0x90, 0xa8, 0x11, 0xe0, 0x31, 0x00, 0x00, 0xcc, 0x90, 0x00, 0x5e, ++ 0x17, 0x90, 0x00, 0x00, 0xc0, 0x90, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0d, 0x02, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x84, 0xd0, 0x01, 0x00, 0xc5, 0x90, 0x22, 0x40, 0x1b, 0x6c, 0x00, 0x00, ++ 0xed, 0x94, 0x00, 0x43, 0x61, 0x31, 0x01, 0x00, 0xcc, 0x90, 0x22, 0x40, ++ 0x85, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x12, 0xc0, 0x01, 0x00, ++ 0x10, 0x80, 0x00, 0x10, 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, ++ 0x43, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x09, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, ++ 0xf0, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa1, 0x62, 0xdd, 0x01, 0x00, ++ 0xca, 0x90, 0xa8, 0x11, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0xcd, 0x90, 0xa8, 0x0a, 0x02, 0x30, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x99, 0x92, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, ++ 0xd4, 0x90, 0x23, 0x0d, 0x02, 0x6c, 0x00, 0x00, 0xff, 0x07, 0x00, 0x11, ++ 0x00, 0x8c, 0x01, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xd4, 0x94, 0x00, 0x07, 0x16, 0x14, 0x01, 0x00, 0x75, 0x94, 0x00, 0x5e, ++ 0x05, 0x10, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0xd4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x8e, 0xb0, 0x01, 0x00, 0x80, 0x93, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0xb7, 0x93, 0x00, 0x41, ++ 0x87, 0x30, 0x01, 0x00, 0x3c, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0xe7, 0x90, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0xe3, 0x90, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0xe9, 0x90, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x1a, 0xd0, 0x01, 0x00, 0xef, 0x90, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x7d, 0x95, 0x00, 0x40, 0x95, 0x30, 0x01, 0x00, 0xf7, 0x90, 0x22, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x1a, 0x90, 0x00, 0x00, 0x2a, 0xc0, 0x00, 0x00, ++ 0x7d, 0x95, 0x00, 0x41, 0x95, 0x30, 0x01, 0x00, 0xf2, 0x90, 0x22, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x9d, 0x90, 0x00, 0x00, 0x2a, 0xc0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x97, 0xb0, 0x01, 0x00, 0xf5, 0x90, 0x23, 0x0d, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x97, 0xc0, 0x01, 0x00, ++ 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, ++ 0x83, 0x94, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xfb, 0x90, 0x00, 0x4a, 0x1f, 0x90, 0x00, 0x00, ++ 0xc1, 0x92, 0x00, 0x00, 0x10, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, ++ 0x10, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x07, 0x95, 0x00, 0x06, 0x04, 0x30, 0x01, 0x00, 0x04, 0x91, 0xa2, 0x44, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, 0x2c, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, ++ 0x02, 0xb0, 0x01, 0x00, 0xa7, 0x91, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x19, 0x42, 0xc9, 0x01, 0x00, 0x0b, 0x91, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x07, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, ++ 0x10, 0xc0, 0x01, 0x00, 0x14, 0x91, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, ++ 0xf1, 0x93, 0x00, 0x45, 0x1f, 0x00, 0x01, 0x00, 0xfd, 0x90, 0x22, 0x5c, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x10, 0x91, 0xa8, 0x5c, ++ 0x1f, 0x00, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0xfd, 0x90, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x08, 0x00, 0x2d, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, 0xb7, 0x93, 0x00, 0x41, ++ 0x87, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x19, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x1f, 0x91, 0x22, 0x09, ++ 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, 0x13, 0x30, 0x01, 0x00, ++ 0x22, 0x91, 0x22, 0x44, 0x19, 0x7c, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x4f, ++ 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x80, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0x08, 0x00, 0x8c, 0x01, 0x00, 0x30, 0x91, 0x22, 0x4a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x28, 0x91, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x2d, 0x00, 0x2d, 0x08, 0x2a, 0xb0, 0x01, 0x00, 0x2c, 0x91, 0x22, 0x42, ++ 0x19, 0x7c, 0x00, 0x00, 0xc6, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2d, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x96, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2a, 0xd0, 0x01, 0x00, ++ 0x32, 0x00, 0x2a, 0x15, 0xe4, 0xb1, 0x01, 0x00, 0xcf, 0x8a, 0x00, 0x16, ++ 0xe4, 0xb1, 0x00, 0x00, 0x17, 0x90, 0xa2, 0x16, 0x02, 0x30, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2f, 0x00, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xd4, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xc1, 0x92, 0x00, 0x4a, 0x1f, 0x10, 0x01, 0x00, 0x2b, 0x90, 0x00, 0x10, ++ 0x32, 0xb0, 0x00, 0x00, 0x8a, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x3a, 0x91, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x3d, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x41, 0x93, 0x00, 0x15, 0x94, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, ++ 0x02, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x3f, 0x91, 0x22, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x83, 0x94, 0x00, 0x3a, ++ 0x81, 0x30, 0x01, 0x00, 0xf4, 0x94, 0x00, 0x45, 0x81, 0x30, 0x01, 0x00, ++ 0xcf, 0x8a, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xec, 0x8e, 0x00, 0x45, ++ 0x1f, 0x90, 0x00, 0x00, 0x83, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x3c, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2b, 0x90, 0x00, 0x01, ++ 0x2c, 0xb0, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x51, 0x91, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x01, 0x00, 0x4a, 0x91, 0x37, 0x5c, ++ 0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, ++ 0x4e, 0x91, 0x28, 0x40, 0x81, 0x32, 0x00, 0x00, 0x4b, 0x91, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, ++ 0x4e, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x14, 0x87, 0x17, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x58, 0x01, 0x20, 0x08, 0xe0, 0xb1, 0x01, 0x00, ++ 0x60, 0x01, 0x20, 0x16, 0xe0, 0xb1, 0x01, 0x00, 0x83, 0x93, 0x00, 0x47, ++ 0x1f, 0x10, 0x01, 0x00, 0x3c, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2b, 0x90, 0x00, 0x01, 0x2c, 0xb0, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x47, ++ 0x1f, 0x10, 0x01, 0x00, 0x63, 0x91, 0xa2, 0x08, 0x80, 0x32, 0x00, 0x00, ++ 0x5f, 0x91, 0xa2, 0x42, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, ++ 0x04, 0xdc, 0x01, 0x00, 0xa0, 0x98, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, ++ 0x30, 0x05, 0x00, 0x41, 0x89, 0x30, 0x01, 0x00, 0x41, 0x93, 0x00, 0x15, ++ 0x94, 0x30, 0x01, 0x00, 0x48, 0x93, 0x00, 0x4b, 0x02, 0xb0, 0x00, 0x00, ++ 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xc6, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x83, 0x94, 0x00, 0x3a, 0x81, 0x30, 0x01, 0x00, 0x14, 0x87, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x58, 0x01, 0x20, 0x08, 0xe0, 0xb1, 0x01, 0x00, ++ 0x60, 0x01, 0x20, 0x16, 0xe0, 0xb1, 0x01, 0x00, 0xc1, 0x92, 0x00, 0x10, ++ 0x32, 0x30, 0x01, 0x00, 0x2b, 0x90, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, ++ 0x8c, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x73, 0x91, 0xa2, 0x08, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x82, 0x00, 0x02, 0x04, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x03, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x00, 0xc0, 0x01, 0x00, 0x6c, 0x91, 0x37, 0x5c, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0x62, 0xb1, 0x01, 0x00, 0x70, 0x91, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x6d, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x62, 0xb1, 0x01, 0x00, 0x70, 0x91, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x14, 0x87, 0x17, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x8e, 0xb0, 0x01, 0x00, 0x80, 0x93, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0xb7, 0x93, 0x00, 0x41, 0x87, 0x30, 0x01, 0x00, 0x3c, 0x93, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, ++ 0x82, 0x91, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x7e, 0x91, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, ++ 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x2d, 0x8e, 0x22, 0x09, 0x80, 0x30, 0x00, 0x00, 0xf4, 0x94, 0x00, 0x40, ++ 0x13, 0x30, 0x01, 0x00, 0x2d, 0x8e, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x14, 0x00, 0x2d, 0x45, 0x1f, 0x90, 0x01, 0x00, 0x75, 0x8e, 0x00, 0x44, ++ 0x19, 0x90, 0x00, 0x00, 0x8a, 0x91, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x1f, 0x90, 0x01, 0x00, 0xdd, 0x8f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x83, 0x93, 0x00, 0x4a, 0x1f, 0x10, 0x01, 0x00, ++ 0x3c, 0x93, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x2b, 0x90, 0x00, 0x01, ++ 0x2c, 0xb0, 0x00, 0x00, 0xc1, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x2b, 0x90, 0x00, 0x10, 0x32, 0xb0, 0x00, 0x00, 0xec, 0x8e, 0x00, 0x45, ++ 0x1f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x37, 0xc3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x33, 0xc3, 0x01, 0x00, 0x36, 0x00, 0x00, 0x01, ++ 0x02, 0xcc, 0x01, 0x00, 0x00, 0x00, 0xd2, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x96, 0x91, 0x85, 0x17, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x48, ++ 0x03, 0xd0, 0x00, 0x00, 0x98, 0x91, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x9f, 0x4c, 0x03, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, ++ 0x34, 0xc3, 0x01, 0x00, 0x40, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0, 0xb1, 0x01, 0x00, ++ 0x9d, 0x92, 0x00, 0x41, 0xe1, 0x31, 0x01, 0x00, 0x00, 0x80, 0x00, 0x43, ++ 0x44, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x03, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xa4, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xba, 0x00, 0x20, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0x01, 0x8c, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x46, 0xe0, 0xc1, 0x01, 0x00, 0xac, 0x00, 0x2f, 0x40, ++ 0x13, 0xb0, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0x01, 0xe0, 0xc1, 0x01, 0x00, ++ 0xae, 0x91, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, 0x84, 0x95, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xb0, 0x91, 0x22, 0x47, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x13, 0x90, 0x01, 0x00, 0x2d, 0x95, 0x00, 0x47, ++ 0x19, 0x10, 0x01, 0x00, 0xc0, 0x00, 0x2d, 0x44, 0x1f, 0x90, 0x01, 0x00, ++ 0xc4, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x61, 0x95, 0x00, 0xf0, ++ 0x84, 0xb0, 0x00, 0x00, 0x90, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xc5, 0x91, 0xa2, 0x4b, 0x1f, 0x7c, 0x00, 0x00, 0x18, 0x92, 0xa2, 0x4c, ++ 0x1f, 0x7c, 0x00, 0x00, 0xc5, 0x91, 0x1f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xc8, 0x91, 0xa2, 0x01, 0x80, 0x32, 0x00, 0x00, 0xa8, 0x00, 0x2d, 0x46, ++ 0x8f, 0xb0, 0x01, 0x00, 0xbe, 0x91, 0x1f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, ++ 0xb4, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0xc0, 0x91, 0x22, 0xf0, ++ 0x3a, 0x6c, 0x00, 0x00, 0x15, 0x92, 0x1f, 0xf0, 0x3a, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0x40, 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, ++ 0x8f, 0xb0, 0x01, 0x00, 0x8a, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x16, 0x92, 0x20, 0x42, 0xe7, 0x6d, 0x00, 0x00, 0xc4, 0x91, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x59, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x58, 0x8f, 0xb0, 0x01, 0x00, 0xc7, 0x91, 0x22, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5c, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x5b, 0x8f, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xb0, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0xcc, 0x91, 0xa2, 0x42, 0x24, 0x6c, 0x00, 0x00, 0xd5, 0x91, 0x23, 0xf0, ++ 0x02, 0x6c, 0x00, 0x00, 0xd2, 0x91, 0xa2, 0xf0, 0x80, 0x32, 0x00, 0x00, ++ 0x17, 0x92, 0xa2, 0x42, 0x24, 0x6c, 0x00, 0x00, 0x17, 0x92, 0xa2, 0x41, ++ 0x03, 0x6c, 0x00, 0x00, 0xd1, 0x91, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x51, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x52, ++ 0x8f, 0xb0, 0x01, 0x00, 0x17, 0x92, 0x1f, 0x12, 0x84, 0x50, 0x00, 0x00, ++ 0x17, 0x92, 0xa0, 0x01, 0x84, 0x6c, 0x00, 0x00, 0xc5, 0x91, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x00, 0x92, 0xa2, 0x46, 0xe7, 0x7d, 0x00, 0x00, 0x14, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0xf2, 0x91, 0x22, 0xf0, 0x14, 0x30, 0x00, 0x00, ++ 0xde, 0x91, 0x20, 0x0a, 0x02, 0x6c, 0x00, 0x00, 0xef, 0x91, 0x03, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0xdd, 0x91, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x44, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x49, ++ 0x8f, 0xb0, 0x01, 0x00, 0xe3, 0x91, 0x22, 0x0a, 0x02, 0x6c, 0x00, 0x00, ++ 0xe6, 0x91, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xe2, 0x91, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x56, 0x8f, 0xb0, 0x01, 0x00, 0xe5, 0x91, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x82, 0xd0, 0x01, 0x00, ++ 0xec, 0x91, 0x20, 0x91, 0x83, 0x6c, 0x00, 0x00, 0xeb, 0x91, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x26, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x27, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0xee, 0x91, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x1f, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x20, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0xf1, 0x91, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x22, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x23, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, 0x88, 0x00, 0x2d, 0x44, ++ 0x8f, 0xb0, 0x01, 0x00, 0xfb, 0x91, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0xf8, 0x91, 0xa2, 0x43, 0x3d, 0x7c, 0x00, 0x00, 0xf8, 0x91, 0xa2, 0xf2, ++ 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x80, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, 0xfa, 0x91, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, 0xf8, 0x91, 0xa0, 0x91, ++ 0x03, 0x6c, 0x00, 0x00, 0xf6, 0x91, 0x22, 0x43, 0x3d, 0x7c, 0x00, 0x00, ++ 0xff, 0x91, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x28, 0x00, 0x80, 0x40, ++ 0x8f, 0x98, 0x01, 0x00, 0x29, 0x00, 0x80, 0x40, 0x8f, 0x98, 0x01, 0x00, ++ 0x14, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x09, 0x92, 0xa2, 0xf0, ++ 0x14, 0x30, 0x00, 0x00, 0x88, 0x00, 0x2d, 0x44, 0x8f, 0xb0, 0x01, 0x00, ++ 0x06, 0x92, 0xa2, 0xf2, 0x02, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, ++ 0x80, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, ++ 0xf8, 0x91, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xf6, 0x91, 0x20, 0x91, ++ 0x03, 0x6c, 0x00, 0x00, 0xf8, 0x91, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x0d, 0x92, 0x20, 0x0a, 0x02, 0x6c, 0x00, 0x00, 0x0c, 0x92, 0xa2, 0x40, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, 0x8f, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x49, 0x8f, 0xb0, 0x01, 0x00, 0x12, 0x92, 0x22, 0x0a, ++ 0x02, 0x6c, 0x00, 0x00, 0xe6, 0x91, 0xa2, 0x41, 0x19, 0x7c, 0x00, 0x00, ++ 0x11, 0x92, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x56, 0x8f, 0xb0, 0x01, 0x00, ++ 0x14, 0x92, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x48, 0x8f, 0xb0, 0x01, 0x00, ++ 0x1a, 0x92, 0x00, 0x43, 0x95, 0xb0, 0x00, 0x00, 0x1a, 0x92, 0x00, 0x41, ++ 0x95, 0xb0, 0x00, 0x00, 0x1a, 0x92, 0x00, 0x42, 0x95, 0xb0, 0x00, 0x00, ++ 0x1a, 0x92, 0x00, 0x44, 0x95, 0xb0, 0x00, 0x00, 0x1a, 0x92, 0x00, 0x4c, ++ 0x95, 0xb0, 0x00, 0x00, 0xc9, 0x94, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x1d, 0x92, 0xa2, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4b, ++ 0x8f, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4c, 0x8f, 0xb0, 0x01, 0x00, ++ 0x2d, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, ++ 0x84, 0xb0, 0x01, 0x00, 0x22, 0x92, 0xa2, 0xf3, 0x96, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x01, 0xb0, 0x01, 0x00, 0x2d, 0x00, 0x2a, 0x41, ++ 0xe7, 0xd1, 0x01, 0x00, 0xd4, 0x00, 0x3d, 0x41, 0x85, 0xe0, 0x01, 0x00, ++ 0x0b, 0x00, 0x00, 0xf2, 0x00, 0xe4, 0x01, 0x00, 0x28, 0x92, 0x22, 0x5a, ++ 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x90, 0x01, 0x00, ++ 0x29, 0x92, 0x00, 0x5a, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x63, 0x41, 0x85, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0xa0, 0xa5, 0x85, 0x6c, 0x01, 0x00, 0x00, 0x00, 0xe3, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0xc6, 0x95, 0x00, 0xf0, ++ 0x8c, 0xb0, 0x00, 0x00, 0x36, 0x92, 0x22, 0x40, 0x0f, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x33, 0x92, 0xa2, 0x4b, ++ 0x19, 0x7c, 0x00, 0x00, 0x34, 0x92, 0x22, 0xf0, 0x18, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x60, 0x4b, 0x19, 0x90, 0x01, 0x00, 0xff, 0x92, 0x00, 0x07, ++ 0x10, 0x30, 0x01, 0x00, 0xf9, 0x82, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x38, 0x92, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x85, 0x92, 0x00, 0x40, ++ 0x81, 0x30, 0x01, 0x00, 0xf9, 0x82, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x2f, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, ++ 0x19, 0x90, 0x01, 0x00, 0xff, 0x92, 0x00, 0x07, 0x10, 0x30, 0x01, 0x00, ++ 0xf9, 0x82, 0x00, 0x40, 0x05, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0xff, 0x92, 0x00, 0x07, 0x10, 0x30, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x05, 0xb0, 0x01, 0x00, 0x41, 0x92, 0x33, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x44, 0x92, 0xa1, 0xad, 0x95, 0x20, 0x00, 0x00, 0x52, 0x92, 0x13, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x13, 0x4a, 0x5a, 0x83, 0x01, 0x00, ++ 0x30, 0x00, 0x39, 0x45, 0x95, 0xe0, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x0f, ++ 0x5e, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x5f, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x45, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, ++ 0x48, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x4a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x0c, 0x58, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, ++ 0x4e, 0xb0, 0x01, 0x00, 0xa2, 0x84, 0x00, 0x40, 0x5d, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x58, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x41, 0x97, 0xb0, 0x00, 0x00, ++ 0x4f, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x97, 0xb0, 0x01, 0x00, 0x53, 0x92, 0x60, 0x07, 0x96, 0x30, 0x00, 0x00, ++ 0xff, 0xff, 0x00, 0x4b, 0x84, 0x89, 0x01, 0x00, 0x00, 0x00, 0x70, 0xc2, ++ 0x24, 0xb0, 0x01, 0x00, 0x5d, 0x92, 0xa2, 0x45, 0x25, 0x7c, 0x00, 0x00, ++ 0x57, 0x92, 0x31, 0x20, 0x85, 0x30, 0x00, 0x00, 0x5e, 0x92, 0x22, 0x12, ++ 0x48, 0x7f, 0x00, 0x00, 0x58, 0x04, 0x11, 0x12, 0x48, 0x03, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x1e, 0x94, 0x01, 0x00, 0x00, 0x00, 0x80, 0x5a, 0x1f, 0x90, 0x01, 0x00, ++ 0x5d, 0x92, 0x31, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, ++ 0x24, 0xb0, 0x01, 0x00, 0x5e, 0x92, 0x22, 0x12, 0x48, 0x7f, 0x00, 0x00, ++ 0x58, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x6b, 0x92, 0x0b, 0xf0, 0x84, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x11, 0x12, 0x48, 0x83, 0x01, 0x00, 0x68, 0x92, 0x22, 0x50, ++ 0x85, 0x70, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x2a, 0x94, 0x00, 0xf2, 0x96, 0x30, 0x01, 0x00, 0x93, 0x04, 0x00, 0x12, ++ 0x94, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x1f, 0x90, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x12, 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4b, ++ 0x1e, 0x94, 0x01, 0x00, 0x10, 0x00, 0x00, 0x42, 0x10, 0xf4, 0x01, 0x00, ++ 0x00, 0xb7, 0x3f, 0x43, 0x11, 0xf0, 0x01, 0x00, 0x07, 0x00, 0x00, 0x08, ++ 0x8a, 0x88, 0x01, 0x00, 0x6e, 0x92, 0x30, 0xa1, 0x0c, 0x30, 0x00, 0x00, ++ 0x71, 0x92, 0x22, 0x45, 0xe6, 0x7d, 0x00, 0x00, 0x5e, 0x92, 0x10, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x45, 0xe6, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x12, 0x48, 0x83, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x60, 0x4b, 0x85, 0x80, 0x01, 0x00, ++ 0x5e, 0x01, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x2a, 0x94, 0x00, 0xf2, ++ 0x96, 0x30, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0xd8, 0x00, 0x00, 0x40, 0x81, 0x98, 0x01, 0x00, 0x2e, 0x00, 0x2d, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x7c, 0x92, 0x22, 0x40, 0xe7, 0x6d, 0x00, 0x00, ++ 0x80, 0x00, 0x00, 0x40, 0x80, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf0, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x08, 0x86, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x68, 0xa7, 0x87, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x80, 0x92, 0xa8, 0x05, 0xe0, 0x31, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x4b, 0x96, 0xdc, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x4b, 0x1e, 0x94, 0x01, 0x00, 0x10, 0x00, 0x00, 0x0f, ++ 0x84, 0xf4, 0x01, 0x00, 0x1f, 0x00, 0x00, 0x42, 0x84, 0x88, 0x01, 0x00, ++ 0x89, 0x92, 0x22, 0x40, 0x80, 0x32, 0x00, 0x00, 0x8a, 0x92, 0x00, 0x42, ++ 0x68, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x6a, 0xb1, 0x01, 0x00, ++ 0x8a, 0x92, 0x31, 0x5a, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x42, ++ 0x48, 0x93, 0x01, 0x00, 0x8c, 0x92, 0x35, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x6d, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0x91, 0x92, 0x28, 0xb1, ++ 0x2c, 0x30, 0x00, 0x00, 0x8d, 0x92, 0x22, 0x4d, 0x75, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x95, 0x40, 0x11, 0xb0, 0x01, 0x00, 0x6d, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x91, 0x92, 0xa8, 0xb1, 0x10, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x95, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x7f, 0x00, 0x00, 0x40, ++ 0x61, 0x99, 0x01, 0x00, 0x98, 0x92, 0x28, 0xb1, 0x10, 0x30, 0x00, 0x00, ++ 0x94, 0x92, 0x9f, 0xba, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x11, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x24, 0x11, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x9a, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xac, 0x94, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x9e, 0x92, 0x32, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xa4, 0x92, 0x22, 0xf8, 0x96, 0x30, 0x00, 0x00, 0x04, 0x00, 0x22, 0xf8, ++ 0x90, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x92, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x4b, 0xf0, 0xcd, 0x01, 0x00, 0x20, 0x00, 0x92, 0x48, ++ 0xe0, 0xc9, 0x01, 0x00, 0x6c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, ++ 0xa8, 0x92, 0x28, 0xb1, 0x92, 0x30, 0x00, 0x00, 0xa4, 0x92, 0x22, 0x4c, ++ 0x75, 0x7d, 0x00, 0x00, 0x04, 0x00, 0x12, 0x40, 0x91, 0xb0, 0x00, 0x00, ++ 0x6c, 0x00, 0x00, 0x40, 0x61, 0x99, 0x01, 0x00, 0xa8, 0x92, 0xa8, 0xb1, ++ 0x90, 0x30, 0x00, 0x00, 0xff, 0x00, 0x00, 0x48, 0x96, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x90, 0xd0, 0x01, 0x00, 0x01, 0x00, 0x00, 0x4b, ++ 0xf0, 0xcd, 0x01, 0x00, 0x20, 0x00, 0x00, 0x48, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x92, 0x49, 0xe0, 0xb1, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0x82, 0x8c, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0xf0, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, ++ 0x00, 0xec, 0x00, 0x00, 0xb5, 0x92, 0x22, 0x1a, 0x00, 0x6c, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x00, 0x34, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0xb1, 0x92, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x15, 0x82, 0x8c, 0x01, 0x00, ++ 0xff, 0x07, 0x00, 0xf0, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0xa2, 0x41, ++ 0x00, 0xec, 0x00, 0x00, 0xbe, 0x92, 0x22, 0x0d, 0x00, 0x6c, 0x00, 0x00, ++ 0x99, 0x92, 0x00, 0x00, 0x1a, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0x49, 0xc1, 0x01, 0x00, 0xba, 0x92, 0xa2, 0x41, 0x23, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xc3, 0x92, 0x83, 0x1e, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x19, 0x90, 0x01, 0x00, ++ 0x24, 0x00, 0x2d, 0x01, 0x2c, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x2d, 0xf0, ++ 0x16, 0xb0, 0x01, 0x00, 0x22, 0x00, 0x2d, 0xf0, 0x26, 0xb0, 0x01, 0x00, ++ 0x14, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x30, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x60, 0x97, 0x2e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xca, 0x92, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x64, 0x97, 0x3e, 0x43, 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0xe1, 0xb1, 0x01, 0x00, 0x64, 0x97, 0x3e, 0x43, 0x9d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x0b, 0xe8, 0xb1, 0x01, 0x00, 0x64, 0x97, 0x3f, 0x43, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x16, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x64, 0x97, 0x3f, 0x43, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x16, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0xe1, 0xb1, 0x01, 0x00, 0x60, 0x17, 0x3d, 0x43, ++ 0x9d, 0xe0, 0x01, 0x00, 0x10, 0x00, 0x80, 0xa1, 0x16, 0xe4, 0x01, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x42, 0xc9, 0x01, 0x00, 0xd9, 0x92, 0x30, 0x47, ++ 0x17, 0x04, 0x00, 0x00, 0xdc, 0x92, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x90, 0x42, 0x81, 0xb0, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0xe0, 0x92, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, 0x00, 0x00, 0x90, 0x41, ++ 0x81, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0xe1, 0x92, 0x40, 0x07, 0x96, 0x30, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0xeb, 0x92, 0xa2, 0x45, 0x95, 0x7c, 0x00, 0x00, ++ 0x01, 0x97, 0x3f, 0x41, 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x96, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xe6, 0xb1, 0x01, 0x00, ++ 0x40, 0x97, 0x3e, 0x40, 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, ++ 0xe6, 0xb1, 0x01, 0x00, 0x40, 0x97, 0x3e, 0x40, 0x9d, 0xe0, 0x01, 0x00, ++ 0xfe, 0x92, 0x00, 0x3b, 0xe7, 0xb1, 0x00, 0x00, 0xeb, 0x92, 0x30, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xf5, 0x92, 0xa2, 0x0b, 0xe6, 0x7d, 0x00, 0x00, ++ 0x00, 0xb5, 0x00, 0x0d, 0x46, 0xc9, 0x01, 0x00, 0xf1, 0x92, 0xa2, 0x0b, ++ 0xe6, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x98, 0x42, 0x81, 0xb0, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x0d, ++ 0x46, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe6, 0x91, 0x01, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x98, 0x41, ++ 0x81, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x21, 0xa2, 0x95, 0x20, 0x00, 0x00, ++ 0x00, 0x00, 0x10, 0x4a, 0x44, 0x83, 0x01, 0x00, 0x00, 0x97, 0x3e, 0x41, ++ 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xf6, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4e, 0xe6, 0xb1, 0x01, 0x00, 0x40, 0x97, 0x3e, 0x40, ++ 0x9d, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, 0xff, 0xff, 0x00, 0x07, ++ 0x92, 0x89, 0x01, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x03, 0x00, 0x00, 0x08, 0x86, 0xf4, 0x01, 0x00, 0x00, 0xb7, 0x00, 0x43, ++ 0x46, 0xc9, 0x01, 0x00, 0x07, 0x00, 0x00, 0x08, 0x82, 0x88, 0x01, 0x00, ++ 0x02, 0x93, 0x40, 0x08, 0x96, 0x30, 0x00, 0x00, 0x9d, 0x04, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x0e, 0x93, 0x22, 0x45, 0x95, 0x7c, 0x00, 0x00, ++ 0x0a, 0x93, 0x22, 0x5a, 0x1f, 0x7c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0f, ++ 0x96, 0xf4, 0x01, 0x00, 0x07, 0x93, 0x31, 0x5f, 0x97, 0x04, 0x00, 0x00, ++ 0x00, 0x00, 0x11, 0x4b, 0x48, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x6a, 0xb1, 0x01, 0x00, 0x0a, 0x93, 0x30, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xe6, 0x81, 0x01, 0x00, 0x00, 0x00, 0x10, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x97, 0x3f, 0x41, 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, ++ 0x96, 0xb0, 0x01, 0x00, 0x40, 0x97, 0x3d, 0x40, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0xf3, 0x88, 0xb0, 0x01, 0x00, 0x16, 0x93, 0xa2, 0x3b, ++ 0x89, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x90, 0xb1, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0xa6, 0x92, 0xb1, 0x01, 0x00, 0x17, 0x93, 0x18, 0x4a, ++ 0x44, 0x93, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x30, 0x00, 0x39, 0x45, 0x97, 0xe0, 0x01, 0x00, 0x1c, 0x93, 0x22, 0x5a, ++ 0x1f, 0x7c, 0x00, 0x00, 0x1f, 0x04, 0x00, 0x0f, 0x98, 0xd8, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x5e, 0x94, 0x01, 0x00, 0x1e, 0x93, 0x00, 0x05, ++ 0x4a, 0xb0, 0x00, 0x00, 0x1f, 0x04, 0x00, 0xa7, 0x5e, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x4b, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x1f, 0x93, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x22, 0x93, 0x40, 0x07, 0x96, 0x30, 0x00, 0x00, ++ 0x9d, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x26, 0x93, 0x22, 0x45, ++ 0x95, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x9b, 0x04, 0x00, 0x4a, 0x44, 0x13, 0x01, 0x00, 0x00, 0x97, 0x3f, 0x41, ++ 0x95, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, ++ 0x40, 0x97, 0x3d, 0x40, 0x97, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x63, 0xf3, ++ 0x88, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x38, 0x45, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x0f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x58, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, ++ 0x2e, 0x93, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x27, 0x93, 0xa2, 0x3b, ++ 0x89, 0x6c, 0x00, 0x00, 0x30, 0x00, 0x38, 0x45, 0x9d, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x98, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x93, 0x04, 0x00, 0x12, ++ 0x94, 0x30, 0x01, 0x00, 0xff, 0x92, 0x00, 0x5a, 0x1f, 0x00, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x5a, 0x1f, 0x90, 0x01, 0x00, 0x11, 0x00, 0x00, 0x4a, ++ 0xe6, 0xc9, 0x01, 0x00, 0x34, 0x00, 0x2f, 0x4f, 0x95, 0x84, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x63, 0x4b, ++ 0x84, 0xc8, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x43, 0x85, 0x6c, 0x01, 0x00, ++ 0x00, 0x00, 0xe3, 0x40, 0x85, 0xb0, 0x01, 0x00, 0x30, 0x00, 0x2d, 0x44, ++ 0x1f, 0x90, 0x01, 0x00, 0x32, 0x00, 0x2d, 0xf2, 0x2a, 0xb0, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0xf2, 0x02, 0x30, 0x00, 0x00, 0x1e, 0x92, 0x00, 0x10, ++ 0x32, 0x30, 0x01, 0x00, 0x32, 0x00, 0xa0, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x40, ++ 0x99, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x02, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x97, 0xc0, 0x01, 0x00, 0x00, 0x00, 0xa3, 0x4c, 0x02, 0xd0, 0x00, 0x00, ++ 0x45, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, ++ 0x36, 0xb0, 0x01, 0x00, 0x55, 0x93, 0x22, 0x41, 0x03, 0x50, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, ++ 0xf1, 0xb1, 0x01, 0x00, 0x70, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, ++ 0x62, 0xb1, 0x01, 0x00, 0x4e, 0x93, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x7c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x00, 0xb0, 0x01, 0x00, 0x49, 0x93, 0x00, 0x5c, ++ 0x01, 0x80, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x1b, 0x10, 0xb1, 0x00, 0x00, 0x68, 0x01, 0x2d, 0x06, ++ 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x82, 0xc0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x46, 0xc9, 0x01, 0x00, 0x94, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x7c, 0x93, 0x22, 0x40, 0x11, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x68, 0x08, 0x38, 0x96, 0x01, 0x00, 0xf0, 0x07, 0x00, 0x41, ++ 0x82, 0xcc, 0x01, 0x00, 0x5a, 0x93, 0xaa, 0x41, 0x3b, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x10, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5c, ++ 0x11, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x1d, 0x04, 0xcc, 0x01, 0x00, ++ 0x7b, 0x93, 0x26, 0x46, 0x23, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, ++ 0x12, 0xc8, 0x01, 0x00, 0x64, 0x01, 0x20, 0xf0, 0xe0, 0xb1, 0x01, 0x00, ++ 0x7a, 0x93, 0x22, 0x41, 0x05, 0x50, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x0c, 0x00, 0x00, 0xf8, 0x86, 0xc8, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x44, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x6c, 0x93, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0x79, 0x93, 0x22, 0x41, 0x05, 0x50, 0x00, 0x00, 0x77, 0x93, 0xa2, 0x41, ++ 0x23, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x1a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x72, 0x93, 0xa8, 0x46, 0x23, 0x30, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x03, ++ 0x48, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x42, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x13, 0xc0, 0x01, 0x00, 0x67, 0x93, 0x00, 0x50, ++ 0x49, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x1a, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x7b, 0x93, 0x22, 0x40, 0x3b, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x00, 0xb0, 0x01, 0x00, 0x99, 0x92, 0x00, 0x5c, ++ 0x01, 0x00, 0x01, 0x00, 0x7c, 0x93, 0x00, 0x41, 0x3b, 0xd0, 0x00, 0x00, ++ 0x00, 0x00, 0x8d, 0x47, 0x80, 0x32, 0x01, 0x00, 0xb0, 0x00, 0x2f, 0x5f, ++ 0x13, 0xb0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x8c, 0xc0, 0x01, 0x00, ++ 0x00, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x8c, 0xb0, 0x01, 0x00, ++ 0x88, 0x93, 0x8c, 0xf8, 0x8e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, ++ 0x19, 0x90, 0x01, 0x00, 0x04, 0x00, 0x22, 0xf8, 0x14, 0x30, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x16, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x26, 0xb0, 0x01, 0x00, 0x08, 0x00, 0x2e, 0xf8, 0x0c, 0xb0, 0x01, 0x00, ++ 0x0c, 0x00, 0x2a, 0x4a, 0xe0, 0xb1, 0x01, 0x00, 0x28, 0x00, 0x00, 0x00, ++ 0xe0, 0xc9, 0x01, 0x00, 0x10, 0x00, 0x20, 0x1b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x95, 0x93, 0x20, 0x0a, 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, ++ 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x96, 0xb0, 0x01, 0x00, ++ 0x20, 0x00, 0x20, 0xf0, 0xe4, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x20, 0x4a, ++ 0xe0, 0xb1, 0x01, 0x00, 0x1c, 0x00, 0x20, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x80, 0x93, 0x00, 0x40, 0x13, 0xb0, 0x00, 0x00, 0x2c, 0x00, 0x2d, 0x42, ++ 0x19, 0x90, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, 0x82, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf3, 0x96, 0xb0, 0x01, 0x00, 0x9b, 0x93, 0xa2, 0xa5, ++ 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, 0x95, 0xb0, 0x01, 0x00, ++ 0x9e, 0x93, 0xa2, 0x40, 0x97, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x2d, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x63, 0x41, 0x97, 0xc0, 0x01, 0x00, 0xd4, 0x00, 0x3e, 0x41, ++ 0x83, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x83, 0xc0, 0x01, 0x00, ++ 0xa3, 0x93, 0xa0, 0xa5, 0x83, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x83, 0xb0, 0x01, 0x00, 0x2c, 0x00, 0x20, 0x41, 0xe6, 0xb1, 0x01, 0x00, ++ 0xa8, 0x93, 0x22, 0x40, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, ++ 0x98, 0xdc, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x4c, 0xe4, 0xf5, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x1f, 0x80, 0x01, 0x00, 0x0b, 0x00, 0x80, 0x00, ++ 0xe4, 0xf5, 0x01, 0x00, 0x9d, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x04, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0x41, 0x87, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, ++ 0xb4, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x9d, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x48, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x45, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, ++ 0xc3, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x2e, 0x00, 0x2f, 0xf3, 0x84, 0xb0, 0x01, 0x00, ++ 0x01, 0x00, 0x63, 0xf3, 0x96, 0xc8, 0x01, 0x00, 0xcb, 0x93, 0x9f, 0x41, ++ 0x85, 0x50, 0x00, 0x00, 0x01, 0x00, 0x00, 0xa5, 0x85, 0xcc, 0x01, 0x00, ++ 0x2d, 0x00, 0xa0, 0x42, 0xe6, 0xb1, 0x01, 0x00, 0x5e, 0x01, 0x2d, 0x00, ++ 0x80, 0xb0, 0x01, 0x00, 0xd0, 0x93, 0x52, 0x43, 0x81, 0x60, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0xf2, 0x82, 0xf4, 0x01, 0x00, 0xd1, 0x93, 0x00, 0x41, ++ 0x80, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x81, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x5e, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x95, 0xb0, 0x00, 0x00, ++ 0xd2, 0x93, 0x9e, 0xbb, 0x80, 0x32, 0x00, 0x00, 0xd7, 0x93, 0xa2, 0x40, ++ 0x1f, 0x7c, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x41, 0x95, 0xb0, 0x01, 0x00, 0x04, 0x00, 0x00, 0x15, ++ 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0x2b, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x24, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, ++ 0x38, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfe, 0x3a, 0xb0, 0x01, 0x00, 0xec, 0x93, 0x9c, 0x17, ++ 0x80, 0x32, 0x00, 0x00, 0xe1, 0x93, 0xa2, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x4c, 0x1f, 0x90, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x1e, ++ 0x98, 0xf4, 0x01, 0x00, 0xe0, 0x93, 0xa2, 0x48, 0x99, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x15, 0x42, 0xb1, 0x01, 0x00, 0xe0, 0x93, 0xa2, 0x8a, ++ 0xf1, 0x6d, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x02, 0xcc, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xfc, 0x3e, 0xb0, 0x01, 0x00, 0x01, 0x00, 0x00, 0xf4, ++ 0x28, 0xcc, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, ++ 0xeb, 0x93, 0x20, 0xf0, 0x3e, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x1f, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x2b, 0xc0, 0x01, 0x00, ++ 0xbf, 0x00, 0x2d, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0xf3, ++ 0x3a, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x07, 0x00, 0x2a, 0x0c, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x04, ++ 0xe6, 0xb1, 0x01, 0x00, 0x18, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x1c, 0x00, 0x2d, 0xf0, 0x16, 0xb0, 0x01, 0x00, 0x20, 0x00, 0x2d, 0xf0, ++ 0x26, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2f, 0xf2, 0x0c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x06, 0x14, 0xec, 0x00, 0x00, 0xf8, 0x93, 0x22, 0x45, ++ 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x06, 0x2a, 0xec, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xf8, 0x94, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x96, 0xb0, 0x01, 0x00, 0x0c, 0x00, 0x2d, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x2a, 0x4c, 0xe1, 0xc1, 0x01, 0x00, 0x30, 0x00, 0x00, 0x10, ++ 0x48, 0xc9, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x18, 0x00, 0x00, 0x05, 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xe0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x02, 0x94, 0xa8, 0x5c, 0x1f, 0x10, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x05, 0x48, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x03, 0xf0, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, ++ 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x50, 0x49, 0xc1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x06, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0x0c, 0x94, 0x62, 0x42, 0x61, 0x31, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x0d, 0x94, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x62, 0xc9, 0x01, 0x00, ++ 0x0f, 0x94, 0xa8, 0x00, 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, 0x48, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x01, 0xf0, 0xcd, 0x01, 0x00, 0x40, 0x00, 0x00, 0x03, ++ 0xf0, 0xc9, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0xe0, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x2e, 0x50, 0x49, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, ++ 0x19, 0x94, 0x62, 0x42, 0x61, 0x31, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x1a, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xa0, 0x00, 0x00, 0xa4, 0x62, 0xdd, 0x01, 0x00, 0x1c, 0x94, 0xa8, 0x00, ++ 0xe0, 0x31, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x30, 0x80, 0x00, 0x4a, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, ++ 0xf1, 0xb1, 0x01, 0x00, 0xc0, 0xa8, 0x3d, 0x46, 0x0d, 0xe0, 0x01, 0x00, ++ 0xff, 0x7f, 0x00, 0xa1, 0xf0, 0x89, 0x01, 0x00, 0x02, 0x00, 0x00, 0x09, ++ 0x96, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x97, 0xe0, 0x01, 0x00, ++ 0x00, 0x00, 0x60, 0xa8, 0x97, 0xc0, 0x01, 0x00, 0x26, 0x94, 0x63, 0x42, ++ 0x61, 0x31, 0x00, 0x00, 0x30, 0x00, 0x00, 0x4a, 0x62, 0xc9, 0x01, 0x00, ++ 0x27, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x99, 0x3f, 0x42, 0x97, 0xf0, 0x01, 0x00, ++ 0x2b, 0x94, 0x65, 0x40, 0x81, 0x32, 0x00, 0x00, 0x33, 0x94, 0x22, 0xf3, ++ 0x74, 0x06, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xf3, 0x94, 0x88, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0xe7, 0x85, 0x01, 0x00, 0x00, 0x00, 0x75, 0x55, ++ 0x61, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x62, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x30, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x40, 0x81, 0xb2, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa8, 0x36, 0xb0, 0x01, 0x00, 0x43, 0x94, 0x82, 0x41, ++ 0x23, 0x40, 0x00, 0x00, 0x38, 0x94, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0xa7, 0x91, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, 0x20, 0x80, 0x00, 0x10, ++ 0x42, 0xc9, 0x01, 0x00, 0x3e, 0x94, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x3b, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x23, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x32, 0xb0, 0x01, 0x00, ++ 0x43, 0x94, 0x22, 0x41, 0x19, 0x7c, 0x00, 0x00, 0xaf, 0x92, 0x00, 0x43, ++ 0x23, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x23, 0xb0, 0x01, 0x00, ++ 0x45, 0x94, 0xa3, 0x15, 0x0c, 0x6c, 0x00, 0x00, 0x46, 0x94, 0x00, 0x06, ++ 0x04, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x04, 0xb0, 0x01, 0x00, ++ 0x48, 0x94, 0x20, 0x02, 0x1a, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, ++ 0x04, 0xb0, 0x01, 0x00, 0x07, 0x95, 0x00, 0x05, 0x48, 0x31, 0x01, 0x00, ++ 0x72, 0x94, 0x22, 0x02, 0x14, 0x50, 0x00, 0x00, 0x4c, 0x94, 0xa2, 0x02, ++ 0x2a, 0x50, 0x00, 0x00, 0x72, 0x94, 0xa2, 0x45, 0x1f, 0x7c, 0x00, 0x00, ++ 0x4e, 0x94, 0x22, 0x02, 0x0c, 0x50, 0x00, 0x00, 0x57, 0x94, 0x00, 0x02, ++ 0x16, 0xc0, 0x00, 0x00, 0x56, 0x94, 0x22, 0x5c, 0x1f, 0x7c, 0x00, 0x00, ++ 0x30, 0x80, 0x00, 0x10, 0x42, 0xc9, 0x01, 0x00, 0x56, 0x94, 0x22, 0x40, ++ 0xe3, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x61, 0xb1, 0x01, 0x00, ++ 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x52, 0x94, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0x48, 0xb1, 0x01, 0x00, 0xf1, 0x93, 0x00, 0x5c, ++ 0x1f, 0x00, 0x01, 0x00, 0x72, 0x94, 0x22, 0x15, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0x33, 0xc0, 0x01, 0x00, 0x71, 0x94, 0xa2, 0x02, ++ 0x1a, 0x50, 0x00, 0x00, 0x63, 0x94, 0x22, 0x46, 0x1f, 0x7c, 0x00, 0x00, ++ 0x70, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, ++ 0x1f, 0x80, 0x01, 0x00, 0x63, 0x94, 0x22, 0x40, 0xe3, 0x6d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x5f, 0x94, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x88, 0x1c, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++ 0x48, 0xb1, 0x01, 0x00, 0x0c, 0x80, 0x00, 0x03, 0x42, 0xc9, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0xf0, 0x10, 0xc8, 0x01, 0x00, 0x2f, 0x00, 0x2f, 0x5c, ++ 0x11, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x47, 0xe7, 0x91, 0x01, 0x00, ++ 0xf0, 0x07, 0x00, 0x40, 0x1b, 0x98, 0x01, 0x00, 0x35, 0x94, 0x20, 0x15, ++ 0x1a, 0x6c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0x48, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x22, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, ++ 0xf0, 0xb1, 0x01, 0x00, 0xff, 0x07, 0x00, 0x08, 0xe0, 0x8d, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x61, 0xb1, 0x01, 0x00, 0xa0, 0x00, 0x00, 0xa4, ++ 0x62, 0xdd, 0x01, 0x00, 0x6e, 0x94, 0xa8, 0x46, 0x1f, 0x10, 0x00, 0x00, ++ 0x35, 0x94, 0x00, 0x05, 0x48, 0xb1, 0x00, 0x00, 0x35, 0x94, 0x00, 0x02, ++ 0x10, 0xc0, 0x00, 0x00, 0x74, 0x94, 0xa2, 0x44, 0x1f, 0x7c, 0x00, 0x00, ++ 0xa7, 0x91, 0x00, 0x01, 0x8c, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, ++ 0x10, 0xb1, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, 0x10, 0x00, 0x00, 0x08, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x03, 0xe0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x5c, 0x1f, 0x90, 0x00, 0x00, 0x7b, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x17, 0x00, 0x00, 0xd0, 0xa2, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x40, 0x27, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x00, 0xb0, 0x01, 0x00, 0x99, 0x92, 0x00, 0x41, 0xa3, 0x41, 0x01, 0x00, ++ 0x7f, 0x94, 0x00, 0x41, 0x27, 0xd0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x80, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x86, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd8, 0x94, 0x00, 0x40, ++ 0x2b, 0x30, 0x01, 0x00, 0xac, 0x00, 0x2d, 0x06, 0x16, 0xc0, 0x01, 0x00, ++ 0x90, 0x00, 0x2d, 0xf0, 0x16, 0xc4, 0x01, 0x00, 0x8e, 0x94, 0xa0, 0xf0, ++ 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x0e, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xf0, ++ 0x30, 0xb0, 0x01, 0x00, 0xac, 0x00, 0x2d, 0x40, 0x87, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x6c, 0xf0, 0x28, 0xb0, 0x01, 0x00, 0x97, 0x94, 0x22, 0x4a, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x43, 0x86, 0xc8, 0x01, 0x00, ++ 0x00, 0x30, 0x00, 0x0b, 0x16, 0xc8, 0x01, 0x00, 0x97, 0x94, 0xa4, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0xb8, 0x94, 0x22, 0x06, 0x80, 0x32, 0x00, 0x00, 0xa4, 0x94, 0xa2, 0x06, ++ 0x14, 0x6c, 0x00, 0x00, 0xa1, 0x94, 0x22, 0x48, 0x19, 0x7c, 0x00, 0x00, ++ 0x9c, 0x94, 0xa0, 0x41, 0x17, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0x31, 0xc0, 0x01, 0x00, ++ 0x90, 0x00, 0x20, 0x18, 0xe0, 0xb1, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0x48, ++ 0x19, 0x80, 0x01, 0x00, 0x8b, 0x00, 0x20, 0x45, 0xe7, 0x91, 0x01, 0x00, ++ 0xa4, 0x94, 0x00, 0x40, 0x87, 0x90, 0x00, 0x00, 0x08, 0x00, 0x00, 0x43, ++ 0x86, 0x98, 0x01, 0x00, 0xa4, 0x94, 0xa0, 0x48, 0x17, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, 0xb0, 0x00, 0x00, 0x40, ++ 0x43, 0x99, 0x01, 0x00, 0x10, 0x50, 0x00, 0x43, 0xfc, 0xc9, 0x01, 0x00, ++ 0x0f, 0x95, 0x00, 0x30, 0x81, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xe5, 0xb1, 0x01, 0x00, 0xaf, 0x94, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0xab, ++ 0xf9, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xab, 0x17, 0xc0, 0x01, 0x00, ++ 0xae, 0x94, 0xa0, 0xf0, 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0xb3, 0x94, 0x64, 0xf0, 0x82, 0xb0, 0x00, 0x00, ++ 0xa4, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0xb3, 0x94, 0xa2, 0xf2, ++ 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xe5, 0xb1, 0x01, 0x00, ++ 0x8c, 0x00, 0x20, 0x18, 0xe0, 0xb1, 0x01, 0x00, 0x90, 0x00, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x60, 0x06, 0x30, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x86, 0x0c, 0x80, 0xb2, 0x00, 0x00, 0xbc, 0x00, 0x2d, 0x46, ++ 0x19, 0x90, 0x01, 0x00, 0xa0, 0x00, 0xa0, 0xf2, 0xe4, 0xb1, 0x01, 0x00, ++ 0xb0, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x10, 0x50, 0x00, 0x43, ++ 0xfc, 0xc9, 0x01, 0x00, 0x0f, 0x95, 0x00, 0x30, 0x81, 0x30, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x4a, 0x19, 0xfc, 0x00, 0x00, 0x08, 0x00, 0x00, 0xa2, ++ 0x44, 0xc9, 0x01, 0x00, 0xcc, 0x00, 0x2d, 0xab, 0xf9, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xab, 0x17, 0xc0, 0x01, 0x00, 0xc1, 0x94, 0xa0, 0xf0, ++ 0x16, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x17, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0xe4, 0xf0, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x1b, 0xe0, 0xb1, 0x00, 0x00, 0xc6, 0x94, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x0c, 0x7e, 0x89, 0x01, 0x00, ++ 0x00, 0x00, 0xa6, 0x4c, 0x95, 0x60, 0x01, 0x00, 0x00, 0x00, 0x80, 0x4a, ++ 0x18, 0x94, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x01, 0xf0, 0x31, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, ++ 0xf0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, ++ 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x15, 0xe0, 0xb1, 0x00, 0x00, ++ 0xd1, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x10, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x01, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xe8, 0x5f, ++ 0x17, 0x90, 0x01, 0x00, 0x70, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x7a, 0x01, 0x2e, 0xfe, 0x92, 0xb0, 0x01, 0x00, 0x8b, 0x00, 0x2d, 0xf6, ++ 0x16, 0xb0, 0x01, 0x00, 0xde, 0x94, 0x22, 0x43, 0xe7, 0x7d, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x45, 0xc1, 0x01, 0x00, 0x04, 0x00, 0x00, 0xa6, ++ 0x2a, 0xb0, 0x01, 0x00, 0x28, 0x00, 0x6e, 0x06, 0x82, 0xc8, 0x01, 0x00, ++ 0xe2, 0x94, 0x22, 0x4a, 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, ++ 0x45, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x4c, 0x83, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x92, 0xc0, 0x01, 0x00, 0xe3, 0x94, 0x43, 0x30, ++ 0x3d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x66, 0x9e, 0x83, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x1b, 0x41, 0x3d, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x92, 0xc0, 0x01, 0x00, 0x06, 0x00, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, ++ 0x10, 0x00, 0x00, 0x49, 0x98, 0xf4, 0x01, 0x00, 0xec, 0x94, 0x26, 0x30, ++ 0x93, 0x04, 0x00, 0x00, 0xec, 0x94, 0x90, 0x4c, 0x92, 0x40, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x93, 0xc0, 0x01, 0x00, 0xff, 0xff, 0x80, 0x49, ++ 0xec, 0xa9, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x04, 0x00, 0x22, 0x01, 0xf0, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf0, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x15, ++ 0xe0, 0xb1, 0x00, 0x00, 0xf1, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xfe, 0x94, 0x22, 0x5f, 0x81, 0x7c, 0x00, 0x00, 0xfd, 0x94, 0xa2, 0x40, ++ 0x19, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x19, 0x90, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x54, 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x97, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0xfd, 0x94, 0x28, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xfa, 0x94, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x00, 0x00, 0xa2, 0x21, 0x81, 0x84, 0x00, 0x00, 0x01, 0x95, 0xa2, 0x5f, ++ 0x81, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x43, 0x19, 0x7c, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x43, 0x19, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, ++ 0x61, 0xb1, 0x01, 0x00, 0x10, 0x00, 0x00, 0x07, 0x96, 0xe4, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x96, 0x94, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x80, 0x00, 0x19, ++ 0x44, 0xc9, 0x01, 0x00, 0x04, 0x00, 0x22, 0x02, 0xf0, 0x31, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0b, 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x13, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x43, 0x61, 0xb1, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0x19, 0x62, 0xdd, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x08, ++ 0xe0, 0xb1, 0x00, 0x00, 0x0c, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x7c, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0xf0, ++ 0x98, 0xf4, 0x01, 0x00, 0x15, 0x95, 0x20, 0x4c, 0x84, 0x6c, 0x00, 0x00, ++ 0x88, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, 0x15, 0x95, 0x20, 0xf2, ++ 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, ++ 0x98, 0x00, 0x2d, 0x14, 0x82, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, ++ 0x98, 0xb0, 0x01, 0x00, 0xa3, 0x00, 0x2d, 0x14, 0x98, 0xd0, 0x01, 0x00, ++ 0x1a, 0x95, 0x20, 0x4c, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, ++ 0x84, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x80, 0xe0, 0x01, 0x00, ++ 0x1d, 0x95, 0x23, 0x40, 0x84, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x84, 0xb0, 0x01, 0x00, 0xd0, 0x00, 0x20, 0x14, 0xe0, 0xb1, 0x01, 0x00, ++ 0x98, 0x00, 0x25, 0x42, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x6e, 0xf3, ++ 0x80, 0xf0, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x42, 0x82, 0xc0, 0x00, 0x00, ++ 0x23, 0x95, 0xa0, 0x40, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x17, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0xf0, 0x82, 0xec, 0x00, 0x00, ++ 0x98, 0x00, 0xa0, 0x41, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x10, ++ 0x48, 0xb1, 0x01, 0x00, 0xa8, 0x01, 0x00, 0x40, 0xf1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x05, 0xf0, 0xb1, 0x01, 0x00, 0x09, 0x00, 0x00, 0x07, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x60, 0xa7, 0x97, 0xc0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x10, 0x62, 0xb1, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x2a, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xa8, 0x00, 0x2d, 0x1c, 0x8a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x9f, 0xf0, ++ 0x8a, 0xd0, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x40, 0x8b, 0xec, 0x00, 0x00, ++ 0x8a, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0xa4, 0x00, 0x2d, 0x45, 0xe0, 0xd1, 0x01, 0x00, ++ 0x37, 0x95, 0x9c, 0x17, 0x80, 0x32, 0x00, 0x00, 0xbe, 0x00, 0x2f, 0xab, ++ 0x83, 0xb0, 0x01, 0x00, 0x88, 0x95, 0x00, 0x14, 0x82, 0x50, 0x01, 0x00, ++ 0x3c, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x3c, 0x95, 0x22, 0xf2, ++ 0x82, 0x30, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x3c, 0x95, 0x9f, 0x1c, 0xe0, 0x6d, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x40, ++ 0x47, 0x99, 0x01, 0x00, 0x88, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0xa8, 0x00, 0x20, 0x1c, 0xe0, 0xb1, 0x01, 0x00, 0x9c, 0x00, 0x2d, 0x30, ++ 0x81, 0xb0, 0x01, 0x00, 0x88, 0x00, 0x2d, 0xf0, 0x84, 0xb0, 0x01, 0x00, ++ 0x94, 0x00, 0x2d, 0xf2, 0x86, 0xb0, 0x01, 0x00, 0x4f, 0x95, 0x23, 0xf0, ++ 0x84, 0x6c, 0x00, 0x00, 0x44, 0x95, 0x23, 0x92, 0x87, 0x6c, 0x00, 0x00, ++ 0xc9, 0x04, 0x00, 0xa6, 0x94, 0xb0, 0x01, 0x00, 0x46, 0x95, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa6, 0x94, 0xb0, 0x01, 0x00, ++ 0x60, 0x89, 0x00, 0x4a, 0x94, 0x98, 0x01, 0x00, 0x46, 0x95, 0x68, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xb0, 0xb1, 0x01, 0x00, ++ 0xbf, 0x00, 0x2d, 0x42, 0xb2, 0xb1, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf3, ++ 0x80, 0xe0, 0x01, 0x00, 0x4a, 0x95, 0xd4, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x78, 0xda, 0x84, 0xc0, 0x01, 0x00, 0x54, 0x95, 0x23, 0x40, ++ 0x84, 0x6c, 0x00, 0x00, 0x94, 0x00, 0x20, 0x9d, 0xe1, 0xb1, 0x01, 0x00, ++ 0x54, 0x95, 0x00, 0x40, 0x84, 0xb0, 0x00, 0x00, 0xbf, 0x00, 0x2d, 0x43, ++ 0x84, 0xc0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf3, 0x80, 0xe0, 0x01, 0x00, ++ 0x54, 0x95, 0x23, 0x40, 0x84, 0x6c, 0x00, 0x00, 0x94, 0x00, 0x20, 0x9d, ++ 0xe1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x84, 0xb0, 0x01, 0x00, ++ 0x58, 0x95, 0xa2, 0xf0, 0x38, 0x6c, 0x00, 0x00, 0x9c, 0x00, 0x20, 0x42, ++ 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x13, 0x94, 0x01, 0x00, ++ 0x00, 0x00, 0x80, 0x46, 0x19, 0x80, 0x01, 0x00, 0x9c, 0x00, 0x20, 0x42, ++ 0xe0, 0xb1, 0x01, 0x00, 0x37, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x04, 0x00, 0x00, 0xf3, 0x80, 0xf4, 0x01, 0x00, 0x0f, 0x00, 0x00, 0xf3, ++ 0x82, 0x88, 0x01, 0x00, 0x5e, 0x95, 0x23, 0x41, 0x80, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x5f, 0x13, 0x94, 0x01, 0x00, 0x00, 0x00, 0x89, 0x0c, ++ 0x80, 0xb2, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0xa0, 0x00, 0xa0, 0xf2, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x9f, 0x41, ++ 0x24, 0xec, 0x00, 0x00, 0x68, 0x95, 0xa6, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x9f, 0x42, 0x38, 0xec, 0x00, 0x00, 0x68, 0x95, 0xa6, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x6a, 0x95, 0xa3, 0xf0, 0x3a, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x40, 0x43, 0x99, 0x01, 0x00, ++ 0x6e, 0x95, 0x22, 0xf0, 0x3a, 0x6c, 0x00, 0x00, 0xb4, 0x00, 0x20, 0x1d, ++ 0xe0, 0xb1, 0x01, 0x00, 0x80, 0x00, 0x2d, 0x5f, 0x13, 0x94, 0x01, 0x00, ++ 0x6e, 0x95, 0x23, 0xf0, 0x3a, 0x6c, 0x00, 0x00, 0x80, 0x00, 0x20, 0x1d, ++ 0xe0, 0xb1, 0x01, 0x00, 0xc0, 0x00, 0x20, 0x12, 0xe0, 0xb1, 0x01, 0x00, ++ 0xc4, 0x00, 0xa0, 0x1c, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x42, 0xe0, 0xb1, 0x01, 0x00, ++ 0x12, 0x00, 0x00, 0x40, 0x87, 0x98, 0x01, 0x00, 0x77, 0x95, 0x9f, 0x41, ++ 0x24, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x8c, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x12, 0x8c, 0xd0, 0x01, 0x00, 0x78, 0x95, 0x00, 0x41, ++ 0x24, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8d, 0xb0, 0x01, 0x00, ++ 0xc6, 0x95, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x40, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x7a, 0x95, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x8c, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x00, 0xa2, 0x08, 0x80, 0x32, 0x01, 0x00, 0x81, 0x95, 0xa2, 0x40, ++ 0x95, 0x6c, 0x00, 0x00, 0x99, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, ++ 0x00, 0x82, 0x00, 0xa6, 0x04, 0xb0, 0x01, 0x00, 0xa0, 0x98, 0x2f, 0x40, ++ 0x11, 0xb0, 0x01, 0x00, 0x30, 0x05, 0x00, 0x41, 0x89, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x9f, 0xf8, 0x3e, 0xec, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x12, ++ 0xe0, 0xed, 0x00, 0x00, 0xc8, 0x00, 0x20, 0xab, 0xe1, 0xb1, 0x01, 0x00, ++ 0xcc, 0x00, 0xa0, 0x1f, 0xe0, 0xb1, 0x01, 0x00, 0x8a, 0x95, 0xa3, 0x5f, ++ 0xe7, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xe7, 0xc1, 0x01, 0x00, ++ 0xa6, 0x00, 0x00, 0x40, 0x47, 0x99, 0x01, 0x00, 0x9e, 0x95, 0x22, 0xf2, ++ 0x86, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00, 0x43, 0x84, 0xf4, 0x01, 0x00, ++ 0x01, 0x00, 0x00, 0x41, 0x80, 0xcc, 0x01, 0x00, 0xb8, 0x00, 0x2d, 0x42, ++ 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x62, 0x40, 0x86, 0xc0, 0x01, 0x00, ++ 0x92, 0x95, 0x1f, 0x43, 0x80, 0x32, 0x00, 0x00, 0x93, 0x95, 0xa2, 0x40, ++ 0x87, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x62, 0x41, 0x87, 0xb0, 0x01, 0x00, ++ 0x97, 0x95, 0x9f, 0x40, 0x80, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x85, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x84, 0xd0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x80, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf2, ++ 0x88, 0xb0, 0x01, 0x00, 0x02, 0x00, 0x00, 0x44, 0x84, 0xf4, 0x01, 0x00, ++ 0xb8, 0x00, 0x2e, 0x42, 0x80, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x62, 0x40, ++ 0x88, 0xc0, 0x01, 0x00, 0x9d, 0x95, 0x1f, 0x44, 0x80, 0x32, 0x00, 0x00, ++ 0xa1, 0x95, 0xa2, 0x40, 0x89, 0x6c, 0x00, 0x00, 0xa1, 0x95, 0x62, 0x41, ++ 0x89, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x62, 0x41, 0x86, 0xe4, 0x01, 0x00, ++ 0xb8, 0x00, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, 0x01, 0x00, 0x62, 0x41, ++ 0x88, 0xe4, 0x01, 0x00, 0xa4, 0x00, 0x20, 0x40, 0xe5, 0xb1, 0x01, 0x00, ++ 0xa2, 0x00, 0x20, 0x40, 0xe7, 0xb1, 0x01, 0x00, 0xbc, 0x00, 0x2e, 0x43, ++ 0x87, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x86, 0xc0, 0x01, 0x00, ++ 0xa7, 0x95, 0x20, 0x43, 0x87, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, ++ 0xe5, 0xb1, 0x01, 0x00, 0x40, 0x01, 0x00, 0x43, 0x80, 0xce, 0x01, 0x00, ++ 0x00, 0x00, 0xa4, 0x43, 0xe4, 0x31, 0x01, 0x00, 0x40, 0x01, 0xe2, 0x40, ++ 0x87, 0x98, 0x01, 0x00, 0x88, 0x00, 0x2d, 0x44, 0x81, 0xb0, 0x01, 0x00, ++ 0x90, 0x00, 0x2d, 0xf2, 0x2e, 0xb0, 0x01, 0x00, 0x9c, 0x00, 0x2d, 0xf0, ++ 0x86, 0xb0, 0x01, 0x00, 0x90, 0x00, 0x2d, 0xf0, 0x82, 0xb0, 0x01, 0x00, ++ 0xba, 0x00, 0x2d, 0xf0, 0x98, 0xb0, 0x01, 0x00, 0xb4, 0x95, 0xa2, 0x12, ++ 0x98, 0x6c, 0x00, 0x00, 0xbc, 0x00, 0x2d, 0xf2, 0x98, 0xb0, 0x01, 0x00, ++ 0xb4, 0x95, 0xa0, 0xf2, 0x98, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, ++ 0x82, 0xb0, 0x01, 0x00, 0x9c, 0x00, 0x20, 0x41, 0xe0, 0xb1, 0x01, 0x00, ++ 0xb4, 0x00, 0x2d, 0x12, 0x86, 0xd0, 0x01, 0x00, 0xb7, 0x95, 0xa3, 0x41, ++ 0xe0, 0x6d, 0x00, 0x00, 0xb8, 0x95, 0x00, 0xf0, 0x84, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x41, 0x84, 0xb0, 0x01, 0x00, 0x80, 0x00, 0x2d, 0x43, ++ 0x84, 0xd0, 0x01, 0x00, 0xbb, 0x95, 0x9f, 0x42, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x85, 0xb0, 0x01, 0x00, 0xbd, 0x95, 0xa3, 0x42, ++ 0x14, 0x6c, 0x00, 0x00, 0xbe, 0x95, 0x00, 0x0a, 0x0c, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x42, 0x0c, 0xb0, 0x01, 0x00, 0xc0, 0x95, 0xa0, 0x17, ++ 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x17, 0x0c, 0xb0, 0x01, 0x00, ++ 0xc5, 0x95, 0x22, 0x40, 0x0d, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, ++ 0x0c, 0xec, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x82, 0xf4, 0x01, 0x00, ++ 0xc5, 0x95, 0xa0, 0x41, 0x0c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xf0, ++ 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, 0x81, 0xb0, 0x01, 0x00, ++ 0x9d, 0x92, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x04, 0x80, 0x00, 0x03, ++ 0x44, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x60, 0x41, ++ 0x87, 0x94, 0x01, 0x00, 0x00, 0x80, 0x00, 0x10, 0x44, 0xc9, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x50, 0xf1, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, ++ 0xf0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0xf0, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x03, 0xe0, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x45, ++ 0x61, 0xb1, 0x01, 0x00, 0x20, 0x00, 0x00, 0x10, 0x62, 0xdd, 0x01, 0x00, ++ 0x00, 0x00, 0xa8, 0x5d, 0x05, 0x90, 0x00, 0x00, 0xd1, 0x95, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x4b, 0x19, 0x90, 0x01, 0x00, ++ 0x05, 0x00, 0x2a, 0x0c, 0xe4, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x04, ++ 0xe6, 0xb1, 0x01, 0x00, 0xd7, 0x95, 0x45, 0x48, 0x61, 0x31, 0x00, 0x00, ++ 0x00, 0x10, 0x00, 0x08, 0x62, 0xdd, 0x01, 0x00, 0xdc, 0x95, 0x28, 0x40, ++ 0x87, 0x30, 0x00, 0x00, 0xd8, 0x95, 0x22, 0x48, 0x77, 0x7d, 0x00, 0x00, ++ 0x7e, 0x94, 0x1d, 0x46, 0x87, 0xb0, 0x00, 0x00, 0xdf, 0x95, 0x22, 0x5f, ++ 0x11, 0x7c, 0x00, 0x00, 0x04, 0x00, 0x22, 0x15, 0x62, 0x31, 0x00, 0x00, ++ 0xdd, 0x95, 0xa8, 0x40, 0x81, 0x32, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x14, 0x2f, 0x4c, 0x83, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xe2, 0x95, 0xa2, 0x41, 0x83, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x49, 0xb1, 0x01, 0x00, 0x30, 0x00, 0x00, 0x40, 0xa1, 0x99, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x93, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x1f, 0xb0, 0x01, 0x00, 0x35, 0x96, 0x00, 0x49, 0x96, 0x30, 0x01, 0x00, ++ 0x07, 0x00, 0x00, 0x49, 0x06, 0xe4, 0x01, 0x00, 0x00, 0x39, 0x00, 0x03, ++ 0x06, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xb0, 0x01, 0x00, ++ 0x20, 0x00, 0x00, 0xd0, 0xa0, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x41, ++ 0x93, 0xc0, 0x01, 0x00, 0xe9, 0x95, 0xa0, 0x54, 0x93, 0x6c, 0x00, 0x00, ++ 0x00, 0x00, 0x2e, 0x05, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, ++ 0x49, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe1, 0xb1, 0x01, 0x00, ++ 0x00, 0x02, 0x00, 0xa2, 0x44, 0xc9, 0x01, 0x00, 0xf2, 0x95, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0xb3, 0x01, 0x00, ++ 0x3b, 0x96, 0x00, 0x40, 0x49, 0x31, 0x01, 0x00, 0xc8, 0x92, 0x00, 0x40, ++ 0x81, 0x32, 0x01, 0x00, 0x00, 0xb5, 0x2e, 0x08, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0xf9, 0x95, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x00, 0x97, 0x2e, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0xfd, 0x95, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x49, 0xb1, 0x01, 0x00, 0x40, 0x18, 0x2e, 0x05, ++ 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x01, 0x96, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x57, 0x95, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0x30, 0x94, 0x00, 0x40, 0x45, 0x99, 0x01, 0x00, ++ 0x64, 0x00, 0x00, 0x40, 0xe5, 0x99, 0x01, 0x00, 0x56, 0x95, 0x20, 0x40, ++ 0xe7, 0xb1, 0x01, 0x00, 0xb8, 0x94, 0x20, 0x41, 0xe5, 0xb1, 0x01, 0x00, ++ 0xba, 0x94, 0x20, 0x41, 0xe5, 0xb1, 0x01, 0x00, 0x98, 0x94, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x02, 0x00, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, 0x0b, 0x96, 0xa2, 0x41, ++ 0x97, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x97, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x68, 0xb1, 0x01, 0x00, 0x0f, 0x96, 0x85, 0x41, 0x97, 0x40, 0x00, 0x00, ++ 0x80, 0x04, 0x00, 0x40, 0x81, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x39, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x37, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x35, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x33, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x41, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x3f, 0xb3, 0x01, 0x00, 0xee, 0x05, 0x00, 0x40, ++ 0x25, 0x9b, 0x01, 0x00, 0x42, 0x00, 0x00, 0x40, 0x4b, 0x9b, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x2f, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x2d, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x47, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x43, 0xb3, 0x01, 0x00, 0x60, 0x00, 0x00, 0x40, ++ 0x2b, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x54, 0xef, 0x93, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x55, 0xf1, 0x93, 0x01, 0x00, 0xff, 0xff, 0x00, 0xa5, ++ 0x3c, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x5b, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x2c, 0x45, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x59, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x57, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x40, 0x27, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x53, 0xb3, 0x01, 0x00, 0x2b, 0x96, 0xa2, 0x50, 0xfd, 0x7f, 0x00, 0x00, ++ 0x2b, 0x96, 0xa2, 0x51, 0xfd, 0x7f, 0x00, 0x00, 0x2c, 0x96, 0x00, 0x40, ++ 0x1d, 0xb3, 0x00, 0x00, 0x50, 0x46, 0x00, 0x40, 0x1d, 0x9b, 0x01, 0x00, ++ 0x00, 0xc0, 0x00, 0xa6, 0x88, 0xb3, 0x01, 0x00, 0xff, 0x3f, 0x00, 0xa6, ++ 0x3a, 0xb3, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x9d, 0x3b, 0x9b, 0x01, 0x00, ++ 0xb4, 0x05, 0x00, 0x40, 0x23, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0x4d, 0xb3, 0x01, 0x00, 0x08, 0x0a, 0x00, 0xa6, 0x14, 0xb3, 0x01, 0x00, ++ 0x01, 0x01, 0x00, 0x8a, 0x15, 0x9b, 0x01, 0x00, 0x00, 0x80, 0x00, 0xa6, ++ 0x56, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x80, 0x5e, 0x57, 0xb5, 0x01, 0x00, ++ 0x18, 0x00, 0x00, 0x4b, 0x20, 0xe4, 0x01, 0x00, 0x06, 0x00, 0x00, 0x4b, ++ 0x96, 0xe4, 0x01, 0x00, 0x00, 0x43, 0x00, 0x4b, 0x96, 0xc8, 0x01, 0x00, ++ 0x18, 0x00, 0x00, 0x10, 0x20, 0xdc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4b, ++ 0x20, 0x94, 0x01, 0x00, 0x00, 0x00, 0x80, 0x57, 0x21, 0x90, 0x01, 0x00, ++ 0x00, 0x99, 0x2e, 0x0a, 0x97, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, ++ 0xf1, 0xb1, 0x01, 0x00, 0x3c, 0x96, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x03, 0x00, 0x40, 0x97, 0x98, 0x01, 0x00, 0x00, 0xa9, 0x00, 0x40, ++ 0x45, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0xb1, 0x01, 0x00, ++ 0x40, 0x96, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, ++ 0x97, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x55, 0x61, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x4b, 0x62, 0xb1, 0x01, 0x00, 0x44, 0x96, 0xa8, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0x44, 0x96, 0xa2, 0x41, 0x97, 0x50, 0x00, 0x00, ++ 0x00, 0x00, 0x80, 0x40, 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, ++ 0x9a, 0xb0, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, ++ 0xae, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, ++ 0x9a, 0xb0, 0x00, 0x00, 0xae, 0x9f, 0x00, 0x88, 0x9a, 0xb0, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x88, 0x9a, 0xb0, 0x01, 0x00, 0xae, 0x9f, 0x41, 0x40, ++ 0x81, 0x32, 0x00, 0x00, 0xb2, 0x9f, 0x22, 0x40, 0x7b, 0x6f, 0x00, 0x00, ++ 0x00, 0x00, 0x19, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xae, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x19, 0x41, 0x7b, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xa4, 0xc4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa1, ++ 0xc6, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x2f, 0xa2, 0xc8, 0xb3, 0x01, 0x00, ++ 0x08, 0x14, 0x00, 0x40, 0x49, 0x99, 0x01, 0x00, 0xa8, 0x9f, 0x00, 0x4d, ++ 0x9a, 0xcc, 0x01, 0x00, 0xbb, 0x9f, 0x26, 0x40, 0x81, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x4c, 0x49, 0xc1, 0x01, 0x00, 0xb9, 0x9f, 0xa2, 0x41, ++ 0x9b, 0x50, 0x00, 0x00, 0xbf, 0x9f, 0x80, 0x80, 0x80, 0x32, 0x00, 0x00, ++ 0x00, 0x00, 0x52, 0x49, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4a, ++ 0xfd, 0x93, 0x01, 0x00, 0xc2, 0x9f, 0x00, 0x42, 0xcd, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x51, 0x4a, 0xfd, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, ++ 0xfd, 0x93, 0x01, 0x00, 0xc2, 0x9f, 0x00, 0x43, 0xcb, 0x93, 0x00, 0x00, ++ 0x00, 0x00, 0x50, 0x40, 0x81, 0xb2, 0x01, 0x00, 0xd2, 0x9f, 0x00, 0x40, ++ 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x9a, 0xb0, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x44, 0x49, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x40, 0xf0, ++ 0x80, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x41, 0x4d, 0x80, 0xb2, 0x01, 0x00, ++ 0xca, 0x9f, 0x00, 0x40, 0x19, 0x99, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x44, 0x49, 0xd1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xf0, 0x9a, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x4d, ++ 0x10, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x49, 0xb1, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0xe3, 0x43, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe4, ++ 0x45, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7b, 0xb3, 0x01, 0x00, ++ 0x00, 0x00, 0x48, 0x4f, 0x40, 0xb1, 0x01, 0x00, 0xd2, 0x9f, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0xcb, ++ 0x81, 0xc8, 0x01, 0x00, 0xf4, 0x82, 0x00, 0x40, 0xf2, 0x93, 0x00, 0x00, ++ 0x40, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x40, 0x05, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x18, 0x06, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xf4, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xaf, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x38, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x36, 0x81, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xb8, 0x80, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x14, 0x87, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xaf, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xf5, 0x82, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x94, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0xd7, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x5d, 0x92, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xc6, 0x95, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x33, 0x93, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0xd6, 0x92, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0xd0, 0x92, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x9a, 0x82, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, ++ 0x81, 0xb2, 0x01, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x40, 0x81, 0xb2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, ++ 0x81, 0xb2, 0x00, 0x00, ++ }, ++}; +diff --git a/drivers/staging/slicoss/oasisrcvucode.h b/drivers/staging/slicoss/oasisrcvucode.h +new file mode 100644 +index 0000000..ef91632 +--- /dev/null ++++ b/drivers/staging/slicoss/oasisrcvucode.h +@@ -0,0 +1,205 @@ ++#define OASIS_RCVUCODE_VERS_STRING "$Revision: 1.2 $" ++#define OASIS_RCVUCODE_VERS_DATE "$Date: 2006/03/27 15:10:28 $" ++ ++static ULONG OasisRcvUCodeLen = 512; ++ ++static u8 OasisRcvUCode[2560] = ++{ ++0x47, 0x75, 0x01, 0x00, 0x04, 0xa0, 0x13, 0x01, 0x00, 0x1c, 0xb7, 0x5b, 0x09, ++0x30, 0x00, 0xb6, 0x5f, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x18, 0x3b, ++0x78, 0x3a, 0x00, 0x1c, 0xa2, 0x77, 0x01, 0x00, 0x1c, 0x07, 0x1d, 0x01, 0x70, ++0x18, 0xad, 0x7b, 0xf1, 0xff, 0x1c, 0xb3, 0x7b, 0xa9, 0xaa, 0x1e, 0xb4, 0x7b, ++0x01, 0x0c, 0x1c, 0xb5, 0x7b, 0x0d, 0x06, 0x1c, 0x00, 0x00, 0x30, 0x64, 0x08, ++0x0c, 0x31, 0x5a, 0x70, 0x04, 0x0c, 0x31, 0x5a, 0x80, 0x04, 0x0c, 0x31, 0x4e, ++0x90, 0x04, 0x0c, 0x31, 0x4a, 0xa0, 0x00, 0x09, 0x25, 0x55, 0xc0, 0x04, 0x0c, ++0x31, 0x52, 0xb0, 0x00, 0xe9, 0x24, 0x55, 0xc0, 0x04, 0xcc, 0xb3, 0x00, 0x1c, ++0x1c, 0xeb, 0x2d, 0x01, 0x00, 0x1c, 0x06, 0x56, 0x32, 0xd4, 0x08, 0x07, 0x9d, ++0x00, 0x00, 0x1c, 0x7b, 0xb7, 0x02, 0x00, 0x10, 0xa0, 0x0f, 0x31, 0x54, 0x09, ++0x06, 0x56, 0x5e, 0xc0, 0x04, 0xa0, 0x30, 0x54, 0x03, 0x00, 0xac, 0x30, 0x55, ++0x03, 0x00, 0xcd, 0x03, 0x3a, 0x00, 0x1c, 0x7b, 0xb7, 0x02, 0x00, 0x1c, 0x60, ++0x8e, 0x31, 0x54, 0x09, 0x29, 0x25, 0x55, 0x03, 0x00, 0x80, 0x8e, 0x31, 0x54, ++0x09, 0x8c, 0x30, 0x91, 0x00, 0x04, 0x47, 0x1c, 0x01, 0x00, 0x1c, 0xa0, 0x0f, ++0x31, 0x54, 0x09, 0x00, 0x00, 0x64, 0x00, 0x04, 0x47, 0x1c, 0x65, 0xc0, 0x04, ++0x47, 0x1c, 0x55, 0x03, 0x00, 0x6c, 0x30, 0x01, 0x00, 0x1c, 0x4d, 0x34, 0x02, ++0x00, 0x1c, 0x7b, 0xb7, 0x02, 0x00, 0x1c, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xc8, ++0x83, 0x37, 0x00, 0x1c, 0x80, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x64, 0x00, ++0x04, 0xa0, 0x0f, 0x30, 0x54, 0x09, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x7b, 0xfb, ++0xf2, 0x00, 0x1c, 0xcc, 0x33, 0x0d, 0x00, 0x1c, 0xb4, 0x7b, 0xfd, 0x03, 0x1c, ++0x80, 0x0e, 0x30, 0x54, 0x09, 0xe0, 0xfb, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x8c, ++0x03, 0x00, 0xb3, 0x0f, 0x31, 0x54, 0x09, 0x00, 0x00, 0xec, 0x70, 0x04, 0x00, ++0x00, 0xec, 0x80, 0x04, 0x00, 0x00, 0x8c, 0x93, 0x00, 0x61, 0x76, 0x8d, 0xc3, ++0x04, 0xc0, 0x8d, 0x31, 0x54, 0x09, 0xe0, 0x7b, 0x00, 0xc0, 0x1f, 0xa0, 0xfd, ++0xc5, 0x01, 0x00, 0xcc, 0x33, 0x05, 0x00, 0x1c, 0xd4, 0x03, 0x00, 0x3c, 0x1c, ++0xd4, 0xd3, 0x1b, 0x00, 0x1c, 0xc0, 0xd3, 0x52, 0x00, 0x1c, 0x00, 0x00, 0x5c, ++0x13, 0x04, 0x8e, 0x8e, 0x32, 0x54, 0x09, 0x5b, 0x80, 0x5e, 0x13, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x94, 0x01, 0x00, 0xa0, 0x0f, 0x31, 0x54, ++0x09, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xc0, 0x03, 0xfc, 0x7f, 0x1c, 0xa0, 0x01, ++0xa0, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0xa0, 0x0f, 0x31, 0x54, 0x09, ++0xc0, 0x03, 0xfc, 0x03, 0x1c, 0xf5, 0x77, 0x01, 0x00, 0x1c, 0x26, 0x7a, 0xe6, ++0x05, 0x1c, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xb3, 0x0f, 0x31, 0x54, 0x09, 0xb5, ++0x02, 0x02, 0x00, 0x1c, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0x7a, 0x7e, 0x02, 0x00, ++0x1c, 0xb5, 0x02, 0x02, 0x00, 0x1c, 0x53, 0x0f, 0x32, 0x54, 0x09, 0xaf, 0x03, ++0x01, 0x00, 0x1c, 0x7a, 0x0e, 0x32, 0x54, 0x09, 0xb5, 0x02, 0x02, 0x00, 0x1c, ++0x00, 0x00, 0x02, 0x00, 0x1c, 0xa0, 0x3d, 0xaa, 0x11, 0x04, 0x00, 0x00, 0xac, ++0x11, 0x04, 0xd4, 0xd3, 0x52, 0x00, 0x1c, 0xb5, 0x3e, 0xb2, 0x01, 0x00, 0x20, ++0xfb, 0xfd, 0xff, 0x1f, 0x80, 0x2c, 0x6c, 0x03, 0x00, 0xb9, 0x3a, 0x9e, 0x01, ++0x00, 0x75, 0x3b, 0x02, 0x00, 0x1c, 0xa7, 0x1c, 0x01, 0x00, 0x10, 0xdb, 0x83, ++0x16, 0x00, 0x1c, 0xc7, 0x1d, 0x21, 0xc1, 0x04, 0xb9, 0x3b, 0x8d, 0xc1, 0x04, ++0x8b, 0x2c, 0x01, 0x00, 0x1c, 0x6b, 0x2c, 0x35, 0xc1, 0x04, 0x00, 0x00, 0x78, ++0x11, 0x00, 0xcb, 0x2c, 0x79, 0xc1, 0x04, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xa0, ++0x0f, 0x31, 0x54, 0x09, 0x54, 0xd0, 0x02, 0x00, 0x1c, 0x49, 0x25, 0xb1, 0x01, ++0x00, 0xab, 0x2c, 0x81, 0xc1, 0x04, 0xa7, 0x1d, 0x55, 0x03, 0x00, 0xcc, 0x33, ++0x09, 0x00, 0x1c, 0xeb, 0x2d, 0x01, 0x00, 0x1c, 0xea, 0x29, 0x01, 0x00, 0x1c, ++0xa0, 0x0f, 0x31, 0x54, 0x09, 0xae, 0x0f, 0x31, 0x54, 0x09, 0xa0, 0x0f, 0x31, ++0x54, 0x09, 0xd4, 0x07, 0xfc, 0x03, 0x1c, 0x99, 0x3a, 0x02, 0x00, 0x1c, 0xbb, ++0x38, 0x02, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xfc, 0x01, ++0x04, 0xdb, 0x3b, 0x7e, 0x00, 0x1c, 0xc7, 0x1d, 0x01, 0x00, 0x1c, 0x26, 0x7a, ++0xfa, 0x05, 0x1c, 0x27, 0x1d, 0x01, 0x00, 0x1c, 0xb3, 0x0f, 0x31, 0x54, 0x09, ++0x7a, 0x0e, 0x32, 0x54, 0x09, 0x53, 0x0f, 0x32, 0x54, 0x09, 0x7a, 0x0e, 0x32, ++0x54, 0x09, 0x53, 0x0f, 0x32, 0x54, 0x09, 0x7a, 0x0e, 0x32, 0x54, 0x09, 0x53, ++0x0f, 0x32, 0x54, 0x09, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0x7a, 0x06, 0x02, 0x00, ++0x1c, 0x53, 0x0f, 0x32, 0x54, 0x09, 0xaf, 0x03, 0x01, 0x00, 0x1c, 0x7a, 0x0e, ++0x32, 0x54, 0x09, 0x53, 0x0f, 0x32, 0x54, 0x09, 0x7a, 0x0e, 0x32, 0x54, 0x09, ++0x53, 0x0f, 0x32, 0x54, 0x09, 0x7a, 0x0e, 0x32, 0x54, 0x09, 0x53, 0x0f, 0x32, ++0x54, 0x09, 0x7a, 0x0e, 0x32, 0x54, 0x09, 0x00, 0x3d, 0x02, 0x00, 0x1c, 0x00, ++0x00, 0x58, 0x12, 0x00, 0xcb, 0x2c, 0x01, 0x00, 0x1c, 0x75, 0x3b, 0x02, 0x00, ++0x1c, 0xa7, 0x1c, 0x01, 0x00, 0x10, 0xcb, 0x2f, 0x05, 0x00, 0x1c, 0x60, 0x2c, ++0x00, 0x00, 0x1c, 0xc7, 0x1c, 0xc9, 0x02, 0x00, 0xa0, 0x0f, 0x31, 0x54, 0x09, ++0x53, 0x07, 0x02, 0x00, 0x1c, 0x46, 0x7a, 0xca, 0x05, 0x1c, 0x7a, 0x0e, 0x32, ++0x54, 0x09, 0x40, 0xfa, 0x19, 0x00, 0x1c, 0x00, 0x00, 0x88, 0x02, 0x04, 0x46, ++0x7a, 0xca, 0x05, 0x1c, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xa0, 0x0f, 0x31, 0x54, ++0x09, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xa0, 0x0f, 0x31, 0x54, 0x09, 0xb3, 0x7b, ++0x01, 0xc0, 0x1f, 0x74, 0x0e, 0x30, 0x54, 0x09, 0xc0, 0x03, 0x9c, 0x00, 0x1c, ++0x80, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x04, 0x00, 0x00, 0xac, ++0x12, 0x05, 0x07, 0x1d, 0x01, 0x00, 0x1c, 0xd4, 0xd3, 0x2b, 0x00, 0x1c, 0xd4, ++0xd3, 0x52, 0x00, 0x1c, 0x80, 0x76, 0x7d, 0x13, 0x04, 0x00, 0x00, 0xe0, 0x02, ++0x00, 0xa6, 0x7b, 0x95, 0x03, 0x10, 0xc7, 0x9c, 0x00, 0x00, 0x1c, 0x80, 0x2c, ++0x00, 0x00, 0x1c, 0x00, 0x00, 0x6c, 0x02, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, ++0xab, 0x2d, 0xd9, 0x12, 0x05, 0x07, 0x1d, 0xb5, 0xc2, 0x04, 0x8b, 0x2d, 0x01, ++0x00, 0x1c, 0x69, 0x25, 0x01, 0x00, 0x1c, 0xa6, 0x7b, 0x95, 0x03, 0x10, 0xcb, ++0x2f, 0x09, 0x00, 0x1c, 0x60, 0x2c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x48, 0x03, ++0x00, 0x53, 0x0f, 0x32, 0x54, 0x09, 0x46, 0x7a, 0xca, 0x05, 0x1c, 0x7a, 0x0e, ++0x32, 0x54, 0x09, 0x40, 0xfa, 0x19, 0x00, 0x1c, 0x00, 0x00, 0x10, 0x03, 0x04, ++0x46, 0x7a, 0xca, 0x05, 0x1c, 0xb5, 0x0f, 0x31, 0x54, 0x09, 0xa0, 0x0f, 0x31, ++0x54, 0x09, 0x73, 0xec, 0x2a, 0x03, 0x04, 0x60, 0x2c, 0x00, 0x00, 0x1c, 0x00, ++0x00, 0x28, 0x03, 0x00, 0xc7, 0x1c, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x28, 0x13, ++0x05, 0x07, 0x1d, 0x01, 0x00, 0x1c, 0xc0, 0xd7, 0x22, 0x00, 0x1c, 0x75, 0x56, ++0x7e, 0x13, 0x04, 0x60, 0x2c, 0x00, 0x00, 0x1c, 0xe7, 0x1c, 0x45, 0x03, 0x04, ++0xe7, 0x9c, 0x00, 0x00, 0x1c, 0xa6, 0x7b, 0x95, 0x03, 0x10, 0x80, 0x2c, 0x00, ++0x00, 0x1c, 0x00, 0x00, 0xf8, 0x02, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0xb9, ++0x7b, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x8c, 0xc3, 0x04, 0xcb, 0xaf, 0xfc, 0x07, ++0x1c, 0xcb, 0x2f, 0x01, 0x04, 0x1c, 0xc7, 0x9f, 0x80, 0x03, 0x1c, 0x00, 0x00, ++0x8c, 0xc3, 0x04, 0xcb, 0xaf, 0xfc, 0x07, 0x1c, 0xcb, 0x2f, 0x0d, 0x04, 0x1c, ++0xc7, 0x9f, 0x80, 0x03, 0x1c, 0x00, 0x00, 0x8c, 0xc3, 0x04, 0xcb, 0xaf, 0x00, ++0xf8, 0x1d, 0xcb, 0x2f, 0x01, 0x00, 0x1d, 0xa6, 0x7b, 0x95, 0x03, 0x1c, 0xc7, ++0x9c, 0x8c, 0xc3, 0x04, 0x00, 0x00, 0x8c, 0x13, 0x05, 0x07, 0x1d, 0x01, 0x00, ++0x1c, 0xc0, 0x1d, 0xdc, 0xd3, 0x08, 0x27, 0x9d, 0xe4, 0x03, 0x00, 0xa0, 0xee, ++0x46, 0xd4, 0x00, 0xfb, 0x75, 0x09, 0x14, 0x04, 0x20, 0x7b, 0x06, 0x00, 0x1c, ++0xc0, 0x1c, 0x1c, 0x04, 0x00, 0x00, 0x00, 0xb0, 0xd3, 0x08, 0x00, 0x00, 0x00, ++0xf4, 0x00, 0xc0, 0xef, 0xf2, 0x00, 0x1c, 0x20, 0x25, 0x5c, 0x14, 0x04, 0x60, ++0xb7, 0xd2, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x15, 0x00, 0xcc, 0xb3, 0xfc, 0x03, ++0x1c, 0xcc, 0x33, 0x05, 0x02, 0x1c, 0x00, 0x00, 0x0c, 0xc5, 0x04, 0x60, 0xb7, ++0x0e, 0x05, 0x04, 0x00, 0x00, 0x0c, 0x15, 0x04, 0x00, 0x00, 0x5c, 0xc4, 0x04, ++0xc0, 0x1d, 0x98, 0xf3, 0x04, 0x00, 0x00, 0x68, 0xc4, 0x04, 0x07, 0x9d, 0x00, ++0x00, 0x1c, 0x1b, 0x74, 0xfd, 0xf3, 0x04, 0xa6, 0x7b, 0xf1, 0x03, 0x1c, 0xa0, ++0x0f, 0x69, 0x54, 0x09, 0xe0, 0x7b, 0x00, 0xfc, 0x1f, 0x39, 0x7f, 0x02, 0x00, ++0x1c, 0x07, 0x1d, 0x9d, 0xc3, 0x04, 0xa6, 0x7b, 0xad, 0x03, 0x1c, 0x00, 0x00, ++0x68, 0xc4, 0x04, 0xe0, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xa4, 0x03, 0x04, ++0xcb, 0xaf, 0x00, 0xf8, 0x1d, 0xcb, 0x2f, 0x01, 0x10, 0x1d, 0x00, 0x00, 0xac, ++0xc3, 0x04, 0x00, 0x00, 0xac, 0x03, 0x04, 0xcb, 0xaf, 0x00, 0xf8, 0x1d, 0xcb, ++0x2f, 0x01, 0x18, 0x1d, 0xc7, 0x9f, 0x00, 0x0b, 0x1c, 0x00, 0x00, 0xac, 0xc3, ++0x04, 0xfb, 0x75, 0x01, 0x00, 0x1c, 0x07, 0x1d, 0x01, 0x00, 0x1c, 0xcc, 0xb3, ++0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x01, 0x02, 0x1c, 0x00, 0x00, 0xac, 0xc3, 0x04, ++0xa0, 0x1c, 0x00, 0x00, 0x1c, 0xa0, 0xee, 0xa2, 0x03, 0x04, 0xcb, 0xaf, 0xfc, ++0x07, 0x1c, 0xcb, 0x2f, 0x09, 0x04, 0x1c, 0xfb, 0x75, 0x01, 0x00, 0x1c, 0x00, ++0x00, 0xac, 0xc3, 0x04, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x01, 0x02, ++0x1c, 0x00, 0x00, 0x0c, 0xc5, 0x04, 0x00, 0x00, 0x78, 0x34, 0x05, 0xcc, 0xb3, ++0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x15, 0x02, 0x1c, 0x47, 0x9d, 0x54, 0xc4, 0x04, ++0x00, 0x00, 0x78, 0x44, 0x00, 0x80, 0x1d, 0x7c, 0x54, 0x04, 0x87, 0x1d, 0x8d, ++0x04, 0x00, 0xce, 0x76, 0x01, 0x00, 0x1c, 0xef, 0x76, 0x9d, 0xc4, 0x04, 0xa4, ++0x77, 0x8d, 0x24, 0x09, 0xe4, 0x76, 0x01, 0x00, 0x1c, 0xc4, 0x76, 0x01, 0x00, ++0x1c, 0x00, 0x00, 0x98, 0x54, 0x04, 0xd7, 0x76, 0x01, 0x50, 0x18, 0xf6, 0x76, ++0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xcc, 0x30, 0x45, 0xc5, 0x04, 0xeb, 0x2d, 0x01, 0x00, 0x1c, 0xea, 0x29, 0x01, ++0x00, 0x1c, 0xc0, 0x59, 0x01, 0x00, 0x1c, 0xf5, 0x77, 0x29, 0xc5, 0x04, 0xe0, ++0x30, 0xdc, 0x04, 0x00, 0x00, 0x4c, 0xb0, 0x04, 0x00, 0x20, 0x4c, 0xf4, 0x04, ++0x00, 0x00, 0x00, 0xe8, 0x04, 0x00, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, ++0x09, 0x02, 0x1c, 0xeb, 0x2d, 0xb5, 0xc4, 0x04, 0xcc, 0xb3, 0xfc, 0x03, 0x1c, ++0xcc, 0x33, 0x19, 0x02, 0x1c, 0xeb, 0x2d, 0xb5, 0xc4, 0x04, 0xcc, 0xb3, 0xfc, ++0x03, 0x1c, 0xcc, 0x33, 0x0d, 0x02, 0x1c, 0xeb, 0x2d, 0xb5, 0xc4, 0x04, 0xcc, ++0xb3, 0xfc, 0x03, 0x1c, 0xcc, 0x33, 0x11, 0x02, 0x1c, 0xeb, 0x2d, 0xb5, 0xc4, ++0x04, 0x00, 0x7b, 0x00, 0x80, 0x1c, 0xae, 0x77, 0x45, 0x05, 0x00, 0x00, 0x00, ++0x04, 0xc0, 0x04, 0xd3, 0x8b, 0x00, 0xfc, 0x1f, 0x60, 0x7a, 0x3c, 0x00, 0x1c, ++0x60, 0x4c, 0xc0, 0x04, 0x00, 0xc0, 0x2f, 0x20, 0x05, 0x1f, 0xe0, 0x30, 0xb0, ++0x04, 0x00, 0x80, 0x25, 0xb0, 0x04, 0x00, 0xb5, 0x5b, 0xb1, 0x04, 0x04, 0x69, ++0x26, 0x01, 0x00, 0x1c, 0x6a, 0x2b, 0x01, 0x00, 0x1c, 0x80, 0x1d, 0x00, 0x00, ++0x1c, 0xa9, 0x25, 0x45, 0x05, 0x00, 0xee, 0x30, 0x00, 0x00, 0x1c, 0xaf, 0x77, ++0x01, 0x05, 0x00, 0x00, 0x00, 0xac, 0x24, 0x04, 0xb4, 0x5f, 0x01, 0x40, 0x18, ++0x07, 0x9d, 0x48, 0x55, 0x04, 0xb7, 0x76, 0x01, 0x00, 0x1c, 0x96, 0x76, 0x01, ++0x00, 0x1c, 0x47, 0x1d, 0x01, 0x00, 0x1c, 0xa4, 0x33, 0x01, 0x60, 0x18, 0xa4, ++0x2f, 0x01, 0x60, 0x18, 0x64, 0x77, 0x01, 0x60, 0x18, 0x24, 0x77, 0x01, 0x60, ++0x18, 0x44, 0x77, 0x01, 0x00, 0x1c, 0x64, 0x88, 0x03, 0x00, 0x1c, 0xa4, 0x3f, ++0x01, 0x00, 0x1c, 0xa4, 0x3b, 0x01, 0x00, 0x1c, 0x53, 0x7b, 0x00, 0xc0, 0x1c, ++0xd3, 0xcf, 0x1b, 0x00, 0x1c, 0x53, 0x4f, 0x02, 0x00, 0x1c, 0xda, 0xcf, 0x00, ++0xc0, 0x1f, 0xd5, 0x57, 0x0f, 0x00, 0x1c, 0xd3, 0xd3, 0x37, 0x00, 0x1c, 0xd4, ++0x53, 0x0f, 0x00, 0x1c, 0xe0, 0x29, 0x00, 0x00, 0x1c, 0xf5, 0xd5, 0xb0, 0x05, ++0x00, 0x00, 0x00, 0x9c, 0x55, 0x04, 0x77, 0x56, 0x01, 0x00, 0x1c, 0x56, 0x53, ++0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x18, 0x00, 0x00, 0x04, 0xc0, 0x04, ++0xf5, 0x55, 0x01, 0x00, 0x1c, 0x00, 0x00, 0xb4, 0x55, 0x04, 0x77, 0x56, 0x01, ++0x00, 0x1c, 0x56, 0x53, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x18, 0x00, ++0x00, 0x04, 0xc0, 0x04, 0xcb, 0x2f, 0x01, 0x18, 0x10, 0xcb, 0x2f, 0x01, 0x10, ++0x10, 0xcb, 0x2f, 0x01, 0x08, 0x10, 0xcb, 0x2f, 0x01, 0x08, 0x10, 0xcb, 0x2f, ++0x01, 0x20, 0x10, 0xcb, 0x2f, 0x01, 0x28, 0x10, 0xcb, 0x2f, 0x01, 0x00, 0x10, ++0x89, 0x25, 0x61, 0xc2, 0x04, 0x00, 0x00, 0xec, 0xc2, 0x04, 0x00, 0x00, 0x54, ++0xc3, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x00, ++0x00, 0x60, 0xc2, 0x04, 0x00, 0x00, 0xec, 0xc2, 0x04, 0x00, 0x00, 0x54, 0xc3, ++0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x40, 0x1c, ++0x6c, 0xc0, 0x04, 0x40, 0x1c, 0x9c, 0xc0, 0x04, 0xa7, 0x77, 0x55, 0xc3, 0x04, ++0x00, 0x00, 0xc4, 0xc0, 0x04, 0x27, 0x1d, 0xf1, 0xc0, 0x04, 0x00, 0x00, 0x54, ++0xc3, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x00, 0x00, 0x54, 0xc3, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, ++0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, ++0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, ++0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, ++0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, 0x00, 0x00, 0x2c, 0xc6, 0x04, ++}; +diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h +new file mode 100644 +index 0000000..9707e5a +--- /dev/null ++++ b/drivers/staging/slicoss/slic.h +@@ -0,0 +1,603 @@ ++/************************************************************************** ++ * ++ * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: slic.h,v 1.3 2006/07/14 16:43:02 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slic.h ++ * ++ * This is the base set of header definitions for the SLICOSS driver. ++ */ ++#ifndef __SLIC_DRIVER_H__ ++#define __SLIC_DRIVER_H__ ++ ++ ++struct slic_spinlock { ++ spinlock_t lock; ++ unsigned long flags; ++}; ++ ++#define SLIC_RSPQ_PAGES_GB 10 ++#define SLIC_RSPQ_BUFSINPAGE (PAGE_SIZE / SLIC_RSPBUF_SIZE) ++ ++typedef struct _slic_rspqueue_t { ++ ulong32 offset; ++ ulong32 pageindex; ++ ulong32 num_pages; ++ p_slic_rspbuf_t rspbuf; ++ pulong32 vaddr[SLIC_RSPQ_PAGES_GB]; ++ dma_addr_t paddr[SLIC_RSPQ_PAGES_GB]; ++} slic_rspqueue_t, *p_slic_rspqueue_t; ++ ++#define SLIC_RCVQ_EXPANSION 1 ++#define SLIC_RCVQ_ENTRIES (256 * SLIC_RCVQ_EXPANSION) ++#define SLIC_RCVQ_MINENTRIES (SLIC_RCVQ_ENTRIES / 2) ++#define SLIC_RCVQ_MAX_PROCESS_ISR ((SLIC_RCVQ_ENTRIES * 4)) ++#define SLIC_RCVQ_RCVBUFSIZE 2048 ++#define SLIC_RCVQ_FILLENTRIES (16 * SLIC_RCVQ_EXPANSION) ++#define SLIC_RCVQ_FILLTHRESH (SLIC_RCVQ_ENTRIES - SLIC_RCVQ_FILLENTRIES) ++ ++typedef struct _slic_rcvqueue_t { ++ struct sk_buff *head; ++ struct sk_buff *tail; ++ ulong32 count; ++ ulong32 size; ++ ulong32 errors; ++} slic_rcvqueue_t, *p_slic_rcvqueue_t; ++ ++typedef struct _slic_rcvbuf_info_t { ++ ulong32 id; ++ ulong32 starttime; ++ ulong32 stoptime; ++ ulong32 slicworld; ++ ulong32 lasttime; ++ ulong32 lastid; ++} slic_rcvbuf_info_t, *pslic_rcvbuf_info_t; ++/* ++ SLIC Handle structure. Used to restrict handle values to ++ 32 bits by using an index rather than an address. ++ Simplifies ucode in 64-bit systems ++*/ ++typedef struct _slic_handle_word_t { ++ union { ++ struct { ++ ushort index; ++ ushort bottombits; /* to denote num bufs to card */ ++ } parts; ++ ulong32 whole; ++ } handle; ++} slic_handle_word_t, *pslic_handle_word_t; ++ ++typedef struct _slic_handle_t { ++ slic_handle_word_t token; /* token passed between host and card*/ ++ ushort type; ++ pvoid address; /* actual address of the object*/ ++ ushort offset; ++ struct _slic_handle_t *other_handle; ++ struct _slic_handle_t *next; ++} slic_handle_t, *pslic_handle_t; ++ ++#define SLIC_HANDLE_FREE 0x0000 ++#define SLIC_HANDLE_DATA 0x0001 ++#define SLIC_HANDLE_CMD 0x0002 ++#define SLIC_HANDLE_CONTEXT 0x0003 ++#define SLIC_HANDLE_TEAM 0x0004 ++ ++#define handle_index handle.parts.index ++#define handle_bottom handle.parts.bottombits ++#define handle_token handle.whole ++ ++#define SLIC_HOSTCMD_SIZE 512 ++ ++typedef struct _slic_hostcmd_t { ++ slic_host64_cmd_t cmd64; ++ ulong32 type; ++ struct sk_buff *skb; ++ ulong32 paddrl; ++ ulong32 paddrh; ++ ulong32 busy; ++ ulong32 cmdsize; ++ ushort numbufs; ++ pslic_handle_t pslic_handle;/* handle associated with command */ ++ struct _slic_hostcmd_t *next; ++ struct _slic_hostcmd_t *next_all; ++} slic_hostcmd_t, *p_slic_hostcmd_t; ++ ++#define SLIC_CMDQ_CMDSINPAGE (PAGE_SIZE / SLIC_HOSTCMD_SIZE) ++#define SLIC_CMD_DUMB 3 ++#define SLIC_CMDQ_INITCMDS 256 ++#define SLIC_CMDQ_MAXCMDS 256 ++#define SLIC_CMDQ_MAXOUTSTAND SLIC_CMDQ_MAXCMDS ++#define SLIC_CMDQ_MAXPAGES (SLIC_CMDQ_MAXCMDS / SLIC_CMDQ_CMDSINPAGE) ++#define SLIC_CMDQ_INITPAGES (SLIC_CMDQ_INITCMDS / SLIC_CMDQ_CMDSINPAGE) ++ ++typedef struct _slic_cmdqmem_t { ++ int pagecnt; ++ pulong32 pages[SLIC_CMDQ_MAXPAGES]; ++ dma_addr_t dma_pages[SLIC_CMDQ_MAXPAGES]; ++} slic_cmdqmem_t, *p_slic_cmdqmem_t; ++ ++typedef struct _slic_cmdqueue_t { ++ p_slic_hostcmd_t head; ++ p_slic_hostcmd_t tail; ++ int count; ++ struct slic_spinlock lock; ++} slic_cmdqueue_t, *p_slic_cmdqueue_t; ++ ++#ifdef STATUS_SUCCESS ++#undef STATUS_SUCCESS ++#endif ++ ++#define STATUS_SUCCESS 0 ++#define STATUS_PENDING 0 ++#define STATUS_FAILURE -1 ++#define STATUS_ERROR -2 ++#define STATUS_NOT_SUPPORTED -3 ++#define STATUS_BUFFER_TOO_SHORT -4 ++ ++#define SLIC_MAX_CARDS 32 ++#define SLIC_MAX_PORTS 4 /* Max # of ports per card */ ++#if SLIC_DUMP_ENABLED ++/* ++Dump buffer size ++ ++This cannot be bigger than the max DMA size the card supports, ++given the current code structure in the host and ucode. ++Mojave supports 16K, Oasis supports 16K-1, so ++just set this at 15K, shouldnt make that much of a diff. ++*/ ++#define DUMP_BUF_SIZE 0x3C00 ++#endif ++ ++ ++typedef struct _mcast_address_t { ++ uchar address[6]; ++ struct _mcast_address_t *next; ++} mcast_address_t, *p_mcast_address_t; ++ ++#define CARD_DOWN 0x00000000 ++#define CARD_UP 0x00000001 ++#define CARD_FAIL 0x00000002 ++#define CARD_DIAG 0x00000003 ++#define CARD_SLEEP 0x00000004 ++ ++#define ADAPT_DOWN 0x00 ++#define ADAPT_UP 0x01 ++#define ADAPT_FAIL 0x02 ++#define ADAPT_RESET 0x03 ++#define ADAPT_SLEEP 0x04 ++ ++#define ADAPT_FLAGS_BOOTTIME 0x0001 ++#define ADAPT_FLAGS_IS64BIT 0x0002 ++#define ADAPT_FLAGS_PENDINGLINKDOWN 0x0004 ++#define ADAPT_FLAGS_FIBERMEDIA 0x0008 ++#define ADAPT_FLAGS_LOCKS_ALLOCED 0x0010 ++#define ADAPT_FLAGS_INT_REGISTERED 0x0020 ++#define ADAPT_FLAGS_LOAD_TIMER_SET 0x0040 ++#define ADAPT_FLAGS_STATS_TIMER_SET 0x0080 ++#define ADAPT_FLAGS_RESET_TIMER_SET 0x0100 ++ ++#define LINK_DOWN 0x00 ++#define LINK_CONFIG 0x01 ++#define LINK_UP 0x02 ++ ++#define LINK_10MB 0x00 ++#define LINK_100MB 0x01 ++#define LINK_AUTOSPEED 0x02 ++#define LINK_1000MB 0x03 ++#define LINK_10000MB 0x04 ++ ++#define LINK_HALFD 0x00 ++#define LINK_FULLD 0x01 ++#define LINK_AUTOD 0x02 ++ ++#define MAC_DIRECTED 0x00000001 ++#define MAC_BCAST 0x00000002 ++#define MAC_MCAST 0x00000004 ++#define MAC_PROMISC 0x00000008 ++#define MAC_LOOPBACK 0x00000010 ++#define MAC_ALLMCAST 0x00000020 ++ ++#define SLIC_DUPLEX(x) ((x == LINK_FULLD) ? "FDX" : "HDX") ++#define SLIC_SPEED(x) ((x == LINK_100MB) ? "100Mb" : ((x == LINK_1000MB) ?\ ++ "1000Mb" : " 10Mb")) ++#define SLIC_LINKSTATE(x) ((x == LINK_DOWN) ? "Down" : "Up ") ++#define SLIC_ADAPTER_STATE(x) ((x == ADAPT_UP) ? "UP" : "Down") ++#define SLIC_CARD_STATE(x) ((x == CARD_UP) ? "UP" : "Down") ++ ++typedef struct _slic_iface_stats { ++ /* ++ * Stats ++ */ ++ ulong64 xmt_bytes; ++ ulong64 xmt_ucast; ++ ulong64 xmt_mcast; ++ ulong64 xmt_bcast; ++ ulong64 xmt_errors; ++ ulong64 xmt_discards; ++ ulong64 xmit_collisions; ++ ulong64 xmit_excess_xmit_collisions; ++ ulong64 rcv_bytes; ++ ulong64 rcv_ucast; ++ ulong64 rcv_mcast; ++ ulong64 rcv_bcast; ++ ulong64 rcv_errors; ++ ulong64 rcv_discards; ++} slic_iface_stats_t, *p_slic_iface_stats_t; ++ ++typedef struct _slic_tcp_stats { ++ ulong64 xmit_tcp_segs; ++ ulong64 xmit_tcp_bytes; ++ ulong64 rcv_tcp_segs; ++ ulong64 rcv_tcp_bytes; ++} slic_tcp_stats_t, *p_slic_tcp_stats_t; ++ ++typedef struct _slicnet_stats { ++ slic_tcp_stats_t tcp; ++ slic_iface_stats_t iface; ++ ++} slicnet_stats_t, *p_slicnet_stats_t; ++ ++#define SLIC_LOADTIMER_PERIOD 1 ++#define SLIC_INTAGG_DEFAULT 200 ++#define SLIC_LOAD_0 0 ++#define SLIC_INTAGG_0 0 ++#define SLIC_LOAD_1 8000 ++#define SLIC_LOAD_2 10000 ++#define SLIC_LOAD_3 12000 ++#define SLIC_LOAD_4 14000 ++#define SLIC_LOAD_5 16000 ++#define SLIC_INTAGG_1 50 ++#define SLIC_INTAGG_2 100 ++#define SLIC_INTAGG_3 150 ++#define SLIC_INTAGG_4 200 ++#define SLIC_INTAGG_5 250 ++#define SLIC_LOAD_1GB 3000 ++#define SLIC_LOAD_2GB 6000 ++#define SLIC_LOAD_3GB 12000 ++#define SLIC_LOAD_4GB 24000 ++#define SLIC_LOAD_5GB 48000 ++#define SLIC_INTAGG_1GB 50 ++#define SLIC_INTAGG_2GB 75 ++#define SLIC_INTAGG_3GB 100 ++#define SLIC_INTAGG_4GB 100 ++#define SLIC_INTAGG_5GB 100 ++ ++typedef struct _ether_header { ++ uchar ether_dhost[6]; ++ uchar ether_shost[6]; ++ ushort ether_type; ++} ether_header, *p_ether_header; ++ ++typedef struct _sliccard_t { ++ uint busnumber; ++ uint slotnumber; ++ uint state; ++ uint cardnum; ++ uint card_size; ++ uint adapters_activated; ++ uint adapters_allocated; ++ uint adapters_sleeping; ++ uint gennumber; ++ ulong32 events; ++ ulong32 loadlevel_current; ++ ulong32 load; ++ uint reset_in_progress; ++ ulong32 pingstatus; ++ ulong32 bad_pingstatus; ++ struct timer_list loadtimer; ++ ulong32 loadtimerset; ++ uint config_set; ++ slic_config_t config; ++ struct dentry *debugfs_dir; ++ struct dentry *debugfs_cardinfo; ++ struct _adapter_t *master; ++ struct _adapter_t *adapter[SLIC_MAX_PORTS]; ++ struct _sliccard_t *next; ++ ulong32 error_interrupts; ++ ulong32 error_rmiss_interrupts; ++ ulong32 rcv_interrupts; ++ ulong32 xmit_interrupts; ++ ulong32 num_isrs; ++ ulong32 false_interrupts; ++ ulong32 max_isr_rcvs; ++ ulong32 max_isr_xmits; ++ ulong32 rcv_interrupt_yields; ++ ulong32 tx_packets; ++#if SLIC_DUMP_ENABLED ++ ulong32 dumpstatus; /* Result of dump UPR */ ++ pvoid cmdbuffer; ++ ++ ulong cmdbuffer_phys; ++ ulong32 cmdbuffer_physl; ++ ulong32 cmdbuffer_physh; ++ ++ ulong32 dump_count; ++ struct task_struct *dump_task_id; ++ ulong32 dump_wait_count; ++ uint dumpthread_running; /* has a dump thread been init'd */ ++ uint dump_requested; /* 0 no, 1 = reqstd 2=curr 3=done */ ++ ulong32 dumptime_start; ++ ulong32 dumptime_complete; ++ ulong32 dumptime_delta; ++ pvoid dumpbuffer; ++ ulong dumpbuffer_phys; ++ ulong32 dumpbuffer_physl; ++ ulong32 dumpbuffer_physh; ++ wait_queue_head_t dump_wq; ++ struct file *dumphandle; ++ mm_segment_t dumpfile_fs; ++#endif ++ ulong32 debug_ix; ++ ushort reg_type[32]; ++ ushort reg_offset[32]; ++ ulong32 reg_value[32]; ++ ulong32 reg_valueh[32]; ++} sliccard_t, *p_sliccard_t; ++ ++#define NUM_CFG_SPACES 2 ++#define NUM_CFG_REGS 64 ++#define NUM_CFG_REG_ULONGS (NUM_CFG_REGS / sizeof(ulong32)) ++ ++typedef struct _physcard_t { ++ struct _adapter_t *adapter[SLIC_MAX_PORTS]; ++ struct _physcard_t *next; ++ uint adapters_allocd; ++ ++ /* the following is not currently needed ++ ulong32 bridge_busnum; ++ ulong32 bridge_cfg[NUM_CFG_SPACES][NUM_CFG_REG_ULONGS]; ++ */ ++} physcard_t, *p_physcard_t; ++ ++typedef struct _base_driver { ++ struct slic_spinlock driver_lock; ++ ulong32 num_slic_cards; ++ ulong32 num_slic_ports; ++ ulong32 num_slic_ports_active; ++ ulong32 dynamic_intagg; ++ p_sliccard_t slic_card; ++ p_physcard_t phys_card; ++ uint cardnuminuse[SLIC_MAX_CARDS]; ++} base_driver_t, *p_base_driver_t; ++ ++extern base_driver_t slic_global; ++ ++typedef struct _slic_shmem_t { ++ volatile ulong32 isr; ++ volatile ulong32 linkstatus; ++ volatile slic_stats_t inicstats; ++} slic_shmem_t, *p_slic_shmem_t; ++ ++typedef struct _slic_reg_params_t { ++ ulong32 linkspeed; ++ ulong32 linkduplex; ++ ulong32 fail_on_bad_eeprom; ++} slic_reg_params_t, *p_reg_params_t; ++ ++typedef struct _slic_upr_t { ++ uint adapter; ++ ulong32 upr_request; ++ ulong32 upr_data; ++ ulong32 upr_data_h; ++ ulong32 upr_buffer; ++ ulong32 upr_buffer_h; ++ struct _slic_upr_t *next; ++ ++} slic_upr_t, *p_slic_upr_t; ++ ++typedef struct _slic_ifevents_ti { ++ uint oflow802; ++ uint uflow802; ++ uint Tprtoflow; ++ uint rcvearly; ++ uint Bufov; ++ uint Carre; ++ uint Longe; ++ uint Invp; ++ uint Crc; ++ uint Drbl; ++ uint Code; ++ uint IpHlen; ++ uint IpLen; ++ uint IpCsum; ++ uint TpCsum; ++ uint TpHlen; ++} slic_ifevents_t; ++ ++typedef struct _adapter_t { ++ pvoid ifp; ++ p_sliccard_t card; ++ uint port; ++ p_physcard_t physcard; ++ uint physport; ++ uint cardindex; ++ uint card_size; ++ uint chipid; ++ struct net_device *netdev; ++ struct net_device *next_netdevice; ++ struct slic_spinlock adapter_lock; ++ struct slic_spinlock reset_lock; ++ struct pci_dev *pcidev; ++ uint busnumber; ++ uint slotnumber; ++ uint functionnumber; ++ ushort vendid; ++ ushort devid; ++ ushort subsysid; ++ ulong32 irq; ++ void __iomem *memorybase; ++ ulong32 memorylength; ++ ulong32 drambase; ++ ulong32 dramlength; ++ uint queues_initialized; ++ uint allocated; ++ uint activated; ++ ulong32 intrregistered; ++ uint isp_initialized; ++ uint gennumber; ++ ulong32 curaddrupper; ++ p_slic_shmem_t pshmem; ++ dma_addr_t phys_shmem; ++ ulong32 isrcopy; ++ p_slic_regs_t slic_regs; ++ uchar state; ++ uchar linkstate; ++ uchar linkspeed; ++ uchar linkduplex; ++ uint flags; ++ uchar macaddr[6]; ++ uchar currmacaddr[6]; ++ ulong32 macopts; ++ ushort devflags_prev; ++ ulong64 mcastmask; ++ p_mcast_address_t mcastaddrs; ++ p_slic_upr_t upr_list; ++ uint upr_busy; ++ struct timer_list pingtimer; ++ ulong32 pingtimerset; ++ struct timer_list statstimer; ++ ulong32 statstimerset; ++ struct timer_list loadtimer; ++ ulong32 loadtimerset; ++ struct dentry *debugfs_entry; ++ struct slic_spinlock upr_lock; ++ struct slic_spinlock bit64reglock; ++ slic_rspqueue_t rspqueue; ++ slic_rcvqueue_t rcvqueue; ++ slic_cmdqueue_t cmdq_free; ++ slic_cmdqueue_t cmdq_done; ++ slic_cmdqueue_t cmdq_all; ++ slic_cmdqmem_t cmdqmem; ++ /* ++ * SLIC Handles ++ */ ++ slic_handle_t slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/ ++ pslic_handle_t pfree_slic_handles; /* Free object handles*/ ++ struct slic_spinlock handle_lock; /* Object handle list lock*/ ++ ushort slic_handle_ix; ++ ++ ulong32 xmitq_full; ++ ulong32 all_reg_writes; ++ ulong32 icr_reg_writes; ++ ulong32 isr_reg_writes; ++ ulong32 error_interrupts; ++ ulong32 error_rmiss_interrupts; ++ ulong32 rx_errors; ++ ulong32 rcv_drops; ++ ulong32 rcv_interrupts; ++ ulong32 xmit_interrupts; ++ ulong32 linkevent_interrupts; ++ ulong32 upr_interrupts; ++ ulong32 num_isrs; ++ ulong32 false_interrupts; ++ ulong32 tx_packets; ++ ulong32 xmit_completes; ++ ulong32 tx_drops; ++ ulong32 rcv_broadcasts; ++ ulong32 rcv_multicasts; ++ ulong32 rcv_unicasts; ++ ulong32 max_isr_rcvs; ++ ulong32 max_isr_xmits; ++ ulong32 rcv_interrupt_yields; ++ ulong32 intagg_period; ++ p_inicpm_state_t inicpm_info; ++ pvoid pinicpm_info; ++ slic_reg_params_t reg_params; ++ slic_ifevents_t if_events; ++ slic_stats_t inicstats_prev; ++ slicnet_stats_t slic_stats; ++ struct net_device_stats stats; ++} adapter_t, *p_adapter_t; ++ ++#if SLIC_DUMP_ENABLED ++#define SLIC_DUMP_REQUESTED 1 ++#define SLIC_DUMP_IN_PROGRESS 2 ++#define SLIC_DUMP_DONE 3 ++ ++/**************************************************************************** ++ * ++ * Microcode crash information structure. This ++ * structure is written out to the card's SRAM when the microcode panic's. ++ * ++ ****************************************************************************/ ++typedef struct _slic_crash_info { ++ ushort cpu_id; ++ ushort crash_pc; ++} slic_crash_info, *p_slic_crash_info; ++ ++#define CRASH_INFO_OFFSET 0x155C ++ ++#endif ++ ++#define UPDATE_STATS(largestat, newstat, oldstat) \ ++{ \ ++ if ((newstat) < (oldstat)) \ ++ (largestat) += ((newstat) + (0xFFFFFFFF - oldstat + 1)); \ ++ else \ ++ (largestat) += ((newstat) - (oldstat)); \ ++} ++ ++#define UPDATE_STATS_GB(largestat, newstat, oldstat) \ ++{ \ ++ (largestat) += ((newstat) - (oldstat)); \ ++} ++ ++#define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \ ++{ \ ++ _Result = TRUE; \ ++ if (*(pulong32)(_AddrA) != *(pulong32)(_AddrB)) \ ++ _Result = FALSE; \ ++ if (*(pushort)(&((_AddrA)[4])) != *(pushort)(&((_AddrB)[4]))) \ ++ _Result = FALSE; \ ++} ++ ++#if defined(CONFIG_X86_64) || defined(CONFIG_IA64) ++#define SLIC_GET_ADDR_LOW(_addr) (ulong32)((ulong64)(_addr) & \ ++ 0x00000000FFFFFFFF) ++#define SLIC_GET_ADDR_HIGH(_addr) (ulong32)(((ulong64)(_addr) >> 32) & \ ++ 0x00000000FFFFFFFF) ++#else ++#define SLIC_GET_ADDR_LOW(_addr) (ulong32)_addr ++#define SLIC_GET_ADDR_HIGH(_addr) (ulong32)0 ++#endif ++ ++#define FLUSH TRUE ++#define DONT_FLUSH FALSE ++ ++#define SIOCSLICDUMPCARD (SIOCDEVPRIVATE+9) ++#define SIOCSLICSETINTAGG (SIOCDEVPRIVATE+10) ++#define SIOCSLICTRACEDUMP (SIOCDEVPRIVATE+11) ++ ++#endif /* __SLIC_DRIVER_H__ */ +diff --git a/drivers/staging/slicoss/slic_os.h b/drivers/staging/slicoss/slic_os.h +new file mode 100644 +index 0000000..2064673 +--- /dev/null ++++ b/drivers/staging/slicoss/slic_os.h +@@ -0,0 +1,163 @@ ++/************************************************************************** ++ * ++ * Copyright (c)2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: slic_os.h,v 1.2 2006/03/27 15:10:15 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slic_os.h ++ * ++ * These are the Linux-specific definitions required for the SLICOSS ++ * driver, which should allow for greater portability to other OSes. ++ */ ++#ifndef _SLIC_OS_SPECIFIC_H_ ++#define _SLIC_OS_SPECIFIC_H_ ++ ++typedef unsigned char uchar; ++typedef u64 ulong64; ++typedef char *pchar; ++typedef unsigned char *puchar; ++typedef u16 *pushort; ++typedef u32 ulong32; ++typedef u32 *pulong32; ++typedef int *plong32; ++typedef unsigned int *puint; ++typedef void *pvoid; ++typedef unsigned long *pulong; ++typedef unsigned int boolean; ++typedef unsigned int wchar; ++typedef unsigned int *pwchar; ++typedef unsigned char UCHAR; ++typedef u32 ULONG; ++typedef s32 LONG; ++#define FALSE (0) ++#define TRUE (1) ++ ++#define SLIC_INIT_SPINLOCK(x) \ ++ { \ ++ spin_lock_init(&((x).lock)); \ ++ } ++#define SLIC_ACQUIRE_SPINLOCK(x) \ ++ { \ ++ spin_lock(&((x).lock)); \ ++ } ++ ++#define SLIC_RELEASE_SPINLOCK(x) \ ++ { \ ++ spin_unlock(&((x).lock)); \ ++ } ++ ++#define SLIC_ACQUIRE_IRQ_SPINLOCK(x) \ ++ { \ ++ spin_lock_irqsave(&((x).lock), (x).flags); \ ++ } ++ ++#define SLIC_RELEASE_IRQ_SPINLOCK(x) \ ++ { \ ++ spin_unlock_irqrestore(&((x).lock), (x).flags); \ ++ } ++ ++#define ATK_DEBUG 1 ++ ++#if ATK_DEBUG ++#define SLIC_TIMESTAMP(value) { \ ++ struct timeval timev; \ ++ do_gettimeofday(&timev); \ ++ value = timev.tv_sec*1000000 + timev.tv_usec; \ ++} ++#else ++#define SLIC_TIMESTAMP(value) ++#endif ++ ++#define SLIC_ALLOCATE_MEM(len, flag) kmalloc(len, flag) ++#define SLIC_DEALLOCATE_MEM(mem) kfree(mem) ++#define SLIC_DEALLOCATE_IRQ_MEM(mem) free(mem) ++#define SLIC_ALLOCATE_PAGE(x) (pulong32)get_free_page(GFP_KERNEL) ++#define SLIC_DEALLOCATE_PAGE(addr) free_page((ulong32)addr) ++#define SLIC_ALLOCATE_PCIMEM(a, sz, physp) \ ++ pci_alloc_consistent((a)->pcidev, (sz), &(physp)) ++#define SLIC_DEALLOCATE_PCIMEM(a, sz, vp, pp) \ ++ pci_free_consistent((a)->pcidev, (sz), (vp), (pp)) ++#define SLIC_GET_PHYSICAL_ADDRESS(addr) virt_to_bus((addr)) ++#define SLIC_GET_PHYSICAL_ADDRESS_HIGH(addr) 0 ++ ++#define SLIC_GET_DMA_ADDRESS_WRITE(a, ptr, sz) \ ++ pci_map_single((a)->pcidev, (ptr), (sz), PCI_DMA_TODEVICE) ++#define SLIC_GET_DMA_ADDRESS_READ(a, ptr, sz) \ ++ pci_map_single((a)->pcidev, (ptr), (sz), PCI_DMA_FROMDEVICE) ++#define SLIC_UNGET_DMA_ADDRESS_WRITE(a, pa, sz) \ ++ pci_unmap_single((a)->pcidev, (pa), (sz), PCI_DMA_TODEVICE) ++#define SLIC_UNGET_DMA_ADDRESS_READ(a, pa, sz) \ ++ pci_unmap_single((a)->pcidev, (pa), (sz), PCI_DMA_FROMDEVICE) ++ ++#define SLIC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) ++#define SLIC_EQUAL_MEMORY(src1, src2, len) (!memcmp(src1, src2, len)) ++#define SLIC_MOVE_MEMORY(dst, src, len) memcpy((dst), (src), (len)) ++ ++#define SLIC_SECS_TO_JIFFS(x) ((x) * HZ) ++#define SLIC_MS_TO_JIFFIES(x) (SLIC_SECS_TO_JIFFS((x)) / 1000) ++ ++#ifdef DEBUG_REGISTER_TRACE ++#define WRITE_REG(reg, value, flush) \ ++ { \ ++ adapter->card->reg_type[adapter->card->debug_ix] = 0; \ ++ adapter->card->reg_offset[adapter->card->debug_ix] = \ ++ ((puchar)(®)) - ((puchar)adapter->slic_regs); \ ++ adapter->card->reg_value[adapter->card->debug_ix++] = value; \ ++ if (adapter->card->debug_ix == 32) \ ++ adapter->card->debug_ix = 0; \ ++ slic_reg32_write((®), (value), (flush)); \ ++ } ++#define WRITE_REG64(a, reg, value, regh, valh, flush) \ ++ { \ ++ adapter->card->reg_type[adapter->card->debug_ix] = 1; \ ++ adapter->card->reg_offset[adapter->card->debug_ix] = \ ++ ((puchar)(®)) - ((puchar)adapter->slic_regs); \ ++ adapter->card->reg_value[adapter->card->debug_ix] = value; \ ++ adapter->card->reg_valueh[adapter->card->debug_ix++] = valh; \ ++ if (adapter->card->debug_ix == 32) \ ++ adapter->card->debug_ix = 0; \ ++ slic_reg64_write((a), (®), (value), (®h), (valh), \ ++ (flush));\ ++ } ++#else ++#define WRITE_REG(reg, value, flush) \ ++ slic_reg32_write((®), (value), (flush)) ++#define WRITE_REG64(a, reg, value, regh, valh, flush) \ ++ slic_reg64_write((a), (®), (value), (®h), (valh), (flush)) ++#endif ++#define READ_REG(reg, flush) slic_reg32_read((®), (flush)) ++#define READ_REGP16(reg, flush) slic_reg16_read((®), (flush)) ++ ++#endif /* _SLIC_OS_SPECIFIC_H_ */ ++ +diff --git a/drivers/staging/slicoss/slicbuild.h b/drivers/staging/slicoss/slicbuild.h +new file mode 100644 +index 0000000..ddf1665 +--- /dev/null ++++ b/drivers/staging/slicoss/slicbuild.h +@@ -0,0 +1,97 @@ ++/************************************************************************** ++ * ++ * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: slicbuild.h,v 1.2 2006/03/27 15:10:10 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slicbuild.h ++ * ++ * The following contains the compiler directive switches used for ++ * different SLIC build options. They can all be set in the Makefile ++ * but the defaults are defined here. ++ */ ++#ifndef _SLIC_BUILD_H_ ++#define _SLIC_BUILD_H_ ++ ++#ifndef SLIC_PRODUCTION_BUILD ++#define SLIC_PRODUCTION_BUILD 1 ++#endif ++#ifndef SLIC_FAILURE_RESET ++#define SLIC_FAILURE_RESET 1 ++#endif ++#define DBG 1 ++#ifndef SLIC_ASSERT_ENABLED ++#define SLIC_ASSERT_ENABLED 1 ++#endif ++#ifndef SLIC_MCAST_ENABLED ++#define SLIC_MCAST_ENABLED 1 ++#endif ++#ifndef SLIC_GET_STATS_ENABLED ++#define SLIC_GET_STATS_ENABLED 1 ++#endif ++#ifndef SLIC_GET_STATS_TIMER_ENABLED ++#define SLIC_GET_STATS_TIMER_ENABLED 0 ++#endif ++#ifndef SLIC_PING_TIMER_ENABLED ++#define SLIC_PING_TIMER_ENABLED 1 ++#endif ++#ifndef SLIC_IOCTL_SUPPORT_ENABLED ++#define SLIC_IOCTL_SUPPORT_ENABLED 1 ++#endif ++#ifndef ATK_DEBUG ++#define ATK_DEBUG 1 ++#endif ++#ifndef SLIC_POWER_MANAGEMENT_ENABLED ++#define SLIC_POWER_MANAGEMENT_ENABLED 0 ++#endif ++#ifndef SLIC_INTERRUPT_PROCESS_LIMIT ++#define SLIC_INTERRUPT_PROCESS_LIMIT 1 ++#endif ++#ifndef LINUX_FREES_ADAPTER_RESOURCES ++#define LINUX_FREES_ADAPTER_RESOURCES 1 ++#endif ++#ifndef SLIC_OFFLOAD_IP_CHECKSUM ++#define SLIC_OFFLOAD_IP_CHECKSUM 1 ++#endif ++#ifndef SLIC_POWER_MANAGEMENT_ENABLED ++#define SLIC_POWER_MANAGEMENT_ENABLED 0 ++#endif ++#ifndef STATS_TIMER_INTERVAL ++#define STATS_TIMER_INTERVAL 2 ++#endif ++#ifndef PING_TIMER_INTERVAL ++#define PING_TIMER_INTERVAL 1 ++#endif ++ ++#endif /* _SLIC_BUILD_H_ */ +diff --git a/drivers/staging/slicoss/slicdbg.h b/drivers/staging/slicoss/slicdbg.h +new file mode 100644 +index 0000000..c1be56f +--- /dev/null ++++ b/drivers/staging/slicoss/slicdbg.h +@@ -0,0 +1,101 @@ ++/************************************************************************** ++ * ++ * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: slicdbg.h,v 1.2 2006/03/27 15:10:04 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slicdbg.h ++ * ++ * All debug and assertion-based definitions and macros are included ++ * in this file for the SLICOSS driver. ++ */ ++#ifndef _SLIC_DEBUG_H_ ++#define _SLIC_DEBUG_H_ ++ ++#ifdef SLIC_DEFAULT_LOG_LEVEL ++#else ++#define SLICLEVEL KERN_DEBUG ++#endif ++#define SLIC_DISPLAY printk ++#define DBG_ERROR(n, args...) SLIC_DISPLAY(KERN_EMERG n, ##args) ++ ++#define SLIC_DEBUG_MESSAGE 1 ++#if SLIC_DEBUG_MESSAGE ++/*#define DBG_MSG(n, args...) SLIC_DISPLAY(SLICLEVEL n, ##args)*/ ++#define DBG_MSG(n, args...) ++#else ++#define DBG_MSG(n, args...) ++#endif ++ ++#ifdef ASSERT ++#undef ASSERT ++#endif ++ ++#if SLIC_ASSERT_ENABLED ++#ifdef CONFIG_X86_64 ++#define VALID_ADDRESS(p) (1) ++#else ++#define VALID_ADDRESS(p) (((ulong32)(p) & 0x80000000) || ((ulong32)(p) == 0)) ++#endif ++#ifndef ASSERT ++#define ASSERT(a) \ ++ { \ ++ if (!(a)) { \ ++ DBG_ERROR("ASSERT() Failure: file %s, function %s line %d\n",\ ++ __FILE__, __func__, __LINE__); \ ++ slic_assert_fail(); \ ++ } \ ++ } ++#endif ++#ifndef ASSERTMSG ++#define ASSERTMSG(a,msg) \ ++ { \ ++ if (!(a)) { \ ++ DBG_ERROR("ASSERT() Failure: file %s, function %s"\ ++ "line %d: %s\n",\ ++ __FILE__, __func__, __LINE__, (msg)); \ ++ slic_assert_fail(); \ ++ } \ ++ } ++#endif ++#else ++#ifndef ASSERT ++#define ASSERT(a) ++#endif ++#ifndef ASSERTMSG ++#define ASSERTMSG(a, msg) ++#endif ++#endif /* SLIC_ASSERT_ENABLED */ ++ ++#endif /* _SLIC_DEBUG_H_ */ +diff --git a/drivers/staging/slicoss/slicdump.h b/drivers/staging/slicoss/slicdump.h +new file mode 100644 +index 0000000..3c46094 +--- /dev/null ++++ b/drivers/staging/slicoss/slicdump.h +@@ -0,0 +1,279 @@ ++/* ++ * $Id: slicdump.h,v 1.2 2006/03/27 15:09:57 mook Exp $ ++ * ++ * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * NO LICENSE TO ANY ALACRITECH PATENT CLAIM IS GRANTED BY ANY COPYRIGHT ++ * LICENSE TO THIS OR OTHER SOFTWARE. THIS SOFTWARE MAY BE COVERED BY ++ * ALACRITECH PATENTS INCLUDING BUT NOT LIMITED TO U.S. PATENT NOS. 6,226,680, ++ * 6,247,060, 6,334,153, 6,389,479, 6,393,487, 6,427,171, 6,427,173 ++ * and 6,434,620. ++ * THIS SOFTWARE IS NOT SUBJECT TO THE GNU GENERAL PUBLIC LICENSE (GPL). ++ * ++ * The views and conclusions contained in the software and ++ * documentation are those of the authors and should not be ++ * interpreted as representing official policies, either ++ * expressed or implied, of Alacritech, Inc. ++ */ ++#ifndef _SLIC_DUMP_H_ ++#define _SLIC_DUMP_H_ ++ ++#define DEBUG_SUCCESS 0 ++ ++/*********************************************************************** ++ * ++ * Utility processor register locations ++ * ++ **********************************************************************/ ++#define UTILITY_RESET 0x0 ++#define UTILITY_ISP_ADDR 0x4 /* Interrupt status Pointer */ ++#define UTILITY_ISR_ADDR 0x8 /* Interrupt status Register */ ++#define UTILITY_ICR_ADDR 0xc /* Interrupt Control Register */ ++#define UTILITY_CPR_ADDR 0x10 /* Command Pointer Register */ ++#define UTILITY_DPR_ADDR 0x14 /* Data Pointer Register */ ++#define UTILITY_DMP_TRQ 0x18 /* Dump queue onto ALU for analyser */ ++#define UTILITY_UPP_ADDR 0x1c /* Bits 63-32 of cmd/data pointer */ ++ ++/*********************************************************************** ++ * ++ * INIC status register bits ++ * ++ ***********************************************************************/ ++#define SLIC_ISR_CC 0x10000000 /* Command complete - synchronous */ ++#define SLIC_ISR_ERR 0x01000000 /* Command Error - synchronous */ ++#define SLIC_ISR_CMD_MASK 0x11000000 /* Command status mask */ ++#define SLIC_ISR_TPH 0x00080000 /* Transmit processor halted - async */ ++#define SLIC_ISR_RPH 0x00040000 /* Receive processor halted - async */ ++ ++/*********************************************************************** ++ * ++ * INIC Control register values ++ * ++ ***********************************************************************/ ++#define SLIC_ICR_OFF 0 /* Interrupts disabled */ ++#define SLIC_ICR_ON 1 /* Interrupts enabled */ ++#define SLIC_ICR_MASK 2 /* Interrupts masked */ ++ ++#define WRITE_DREG(reg, value, flush) \ ++{ \ ++ writel((value), (reg)); \ ++ if ((flush)) { \ ++ mb(); \ ++ } \ ++} ++ ++/************************************************************************ ++ * ++ * Command Format ++ * ++ * Each command contains a command byte which is defined as follows: ++ * ++ * bits: 7-3 2 1-0 ++ * ---------------------------------------------- ++ * command Alt. Proc Processor ++ * ++ ************************************************************************/ ++ ++/* ++ * Macro to create the command byte given the command, Alt. Proc, and ++ * Processor values. Note that the macro assumes that the values are ++ * preshifted. That is, the values for alt. proc are 0 for transmit and ++ * 4 for receive. ++ */ ++#define COMMAND_BYTE(command, alt_proc, proc) ((command) | (alt_proc) | (proc)) ++ ++/* ++ * Command values ++ */ ++#define CMD_HALT 0x0 /* Send a halt to the INIC */ ++#define CMD_RUN 0x8 /* Start the halted INIC */ ++#define CMD_STEP 0x10 /* Single step the inic */ ++#define CMD_BREAK 0x18 /* Set a breakpoint - 8 byte command */ ++#define CMD_RESET_BREAK 0x20 /* Reset a breakpoint - 8 byte cmd */ ++#define CMD_DUMP 0x28 /* Dump INIC memory - 8 byte command */ ++#define CMD_LOAD 0x30 /* Load INIC memory - 8 byte command */ ++#define CMD_MAP 0x38 /* Map out a ROM instruction - 8 BC */ ++#define CMD_CAM_OPS 0x38 /* perform ops on specific CAM */ ++#define CMD_XMT 0x40 /* Transmit frame */ ++#define CMD_RCV 0x48 /* Receive frame */ ++ ++/* ++ * Alt. Proc values ++ * ++ * When the proc value is set to the utility processor, the Alt. Proc ++ * specifies which processor handles the debugging. ++ */ ++#define ALT_PROC_TRANSMIT 0x0 ++#define ALT_PROC_RECEIVE 0x4 ++ ++/* ++ * Proc values ++ */ ++#define PROC_INVALID 0x0 ++#define PROC_NONE 0x0 /* Gigabit use */ ++#define PROC_TRANSMIT 0x1 ++#define PROC_RECEIVE 0x2 ++#define PROC_UTILITY 0x3 ++ ++/****************************************************************** ++ * ++ * 8 byte command structure definitions ++ * ++ ******************************************************************/ ++ ++/* ++ * Break and Reset Break command structure ++ */ ++typedef struct _BREAK { ++ uchar command; /* Command word defined above */ ++ uchar resvd; ++ ushort count; /* Number of executions before break */ ++ ulong32 addr; /* Address of break point */ ++} BREAK, *PBREAK; ++ ++/* ++ * Dump and Load command structure ++ */ ++typedef struct _dump_cmd { ++ uchar cmd; /* Command word defined above */ ++ uchar desc; /* Descriptor values - defined below */ ++ ushort count; /* number of 4 byte words to be transferred */ ++ ulong32 addr; /* start address of dump or load */ ++} dump_cmd_t, *pdump_cmd_t; ++ ++/* ++ * Receive or Transmit a frame. ++ */ ++typedef struct _RCV_OR_XMT_FRAME { ++ uchar command; /* Command word defined above */ ++ uchar MacId; /* Mac ID of interface - transmit only */ ++ ushort count; /* Length of frame in bytes */ ++ ulong32 pad; /* not used */ ++} RCV_OR_XMT_FRAME, *PRCV_OR_XMT_FRAME; ++ ++/* ++ * Values of desc field in DUMP_OR_LOAD structure ++ */ ++#define DESC_RFILE 0x0 /* Register file */ ++#define DESC_SRAM 0x1 /* SRAM */ ++#define DESC_DRAM 0x2 /* DRAM */ ++#define DESC_QUEUE 0x3 /* queues */ ++#define DESC_REG 0x4 /* General registers (pc, status, etc) */ ++#define DESC_SENSE 0x5 /* Sense register */ ++ ++/* Descriptor field definitions for CMD_DUMP_CAM */ ++#define DUMP_CAM_A 0 ++#define DUMP_CAM_B 1 /* unused at present */ ++#define DUMP_CAM_C 2 ++#define DUMP_CAM_D 3 ++#define SEARCH_CAM_A 4 ++#define SEARCH_CAM_C 5 ++ ++/* ++ * Map command to replace a command in ROM with a command in WCS ++ */ ++typedef struct _MAP { ++ uchar command; /* Command word defined above */ ++ uchar not_used[3]; ++ ushort map_to; /* Instruction address in WCS */ ++ ushort map_out; /* Instruction address in ROM */ ++} MAP, *PMAP; ++ ++/* ++ * Misc definitions ++ */ ++#define SLIC_MAX_QUEUE 32 /* Total # of queues on the INIC (0-31)*/ ++#define SLIC_4MAX_REG 512 /* Total # of 4-port file-registers */ ++#define SLIC_1MAX_REG 384 /* Total # of file-registers */ ++#define SLIC_GBMAX_REG 1024 /* Total # of Gbit file-registers */ ++#define SLIC_NUM_REG 32 /* non-file-registers = NUM_REG in tm-simba.h */ ++#define SLIC_GB_CAMA_SZE 32 ++#define SLIC_GB_CAMB_SZE 16 ++#define SLIC_GB_CAMAB_SZE 32 ++#define SLIC_GB_CAMC_SZE 16 ++#define SLIC_GB_CAMD_SZE 16 ++#define SLIC_GB_CAMCD_SZE 32 ++ ++/* ++ * Coredump header structure ++ */ ++typedef struct _CORE_Q { ++ ulong32 queueOff; /* Offset of queue */ ++ ulong32 queuesize; /* size of queue */ ++} CORE_Q; ++ ++#define DRIVER_NAME_SIZE 32 ++ ++typedef struct _sliccore_hdr_t { ++ uchar driver_version[DRIVER_NAME_SIZE]; /* Driver version string */ ++ ulong32 RcvRegOff; /* Offset of receive registers */ ++ ulong32 RcvRegsize; /* size of receive registers */ ++ ulong32 XmtRegOff; /* Offset of transmit registers */ ++ ulong32 XmtRegsize; /* size of transmit registers */ ++ ulong32 FileRegOff; /* Offset of register file */ ++ ulong32 FileRegsize; /* size of register file */ ++ ulong32 SramOff; /* Offset of Sram */ ++ ulong32 Sramsize; /* size of Sram */ ++ ulong32 DramOff; /* Offset of Dram */ ++ ulong32 Dramsize; /* size of Dram */ ++ CORE_Q queues[SLIC_MAX_QUEUE]; /* size and offsets of queues */ ++ ulong32 CamAMOff; /* Offset of CAM A contents */ ++ ulong32 CamASize; /* Size of Cam A */ ++ ulong32 CamBMOff; /* Offset of CAM B contents */ ++ ulong32 CamBSize; /* Size of Cam B */ ++ ulong32 CamCMOff; /* Offset of CAM C contents */ ++ ulong32 CamCSize; /* Size of Cam C */ ++ ulong32 CamDMOff; /* Offset of CAM D contents */ ++ ulong32 CamDSize; /* Size of Cam D */ ++} sliccore_hdr_t, *p_sliccore_hdr_t; ++ ++/* ++ * definitions needed for our kernel-mode gdb stub. ++ */ ++/*********************************************************************** ++ * ++ * Definitions & Typedefs ++ * ++ **********************************************************************/ ++#define BUFMAX 0x20000 /* 128k - size of input/output buffer */ ++#define BUFMAXP2 5 /* 2**5 (32) 4K pages */ ++ ++#define IOCTL_SIMBA_BREAK _IOW('s', 0, unsigned long) ++/* #define IOCTL_SIMBA_INIT _IOW('s', 1, unsigned long) */ ++#define IOCTL_SIMBA_KILL_TGT_PROC _IOW('s', 2, unsigned long) ++ ++/*********************************************************************** ++ * ++ * Global variables ++ * ++ ***********************************************************************/ ++ ++#define THREADRECEIVE 1 /* bit 0 of StoppedThreads */ ++#define THREADTRANSMIT 2 /* bit 1 of StoppedThreads */ ++#define THREADBOTH 3 /* bit 0 and 1.. */ ++ ++#endif /* _SLIC_DUMP_H */ +diff --git a/drivers/staging/slicoss/slichw.h b/drivers/staging/slicoss/slichw.h +new file mode 100644 +index 0000000..d5765c4 +--- /dev/null ++++ b/drivers/staging/slicoss/slichw.h +@@ -0,0 +1,850 @@ ++/************************************************************************** ++ * ++ * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: slichw.h,v 1.3 2008/03/17 19:27:26 chris Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slichw.h ++ * ++ * This header file contains definitions that are common to our hardware. ++ */ ++#ifndef __SLICHW_H__ ++#define __SLICHW_H__ ++ ++#define PCI_VENDOR_ID_ALACRITECH 0x139A ++#define SLIC_1GB_DEVICE_ID 0x0005 ++#define SLIC_2GB_DEVICE_ID 0x0007 /*Oasis Device ID */ ++ ++#define SLIC_1GB_CICADA_SUBSYS_ID 0x0008 ++ ++#define SLIC_NBR_MACS 4 ++ ++#define SLIC_RCVBUF_SIZE 2048 ++#define SLIC_RCVBUF_HEADSIZE 34 ++#define SLIC_RCVBUF_TAILSIZE 0 ++#define SLIC_RCVBUF_DATASIZE (SLIC_RCVBUF_SIZE - (SLIC_RCVBUF_HEADSIZE +\ ++ SLIC_RCVBUF_TAILSIZE)) ++ ++#define VGBSTAT_XPERR 0x40000000 ++#define VGBSTAT_XERRSHFT 25 ++#define VGBSTAT_XCSERR 0x23 ++#define VGBSTAT_XUFLOW 0x22 ++#define VGBSTAT_XHLEN 0x20 ++#define VGBSTAT_NETERR 0x01000000 ++#define VGBSTAT_NERRSHFT 16 ++#define VGBSTAT_NERRMSK 0x1ff ++#define VGBSTAT_NCSERR 0x103 ++#define VGBSTAT_NUFLOW 0x102 ++#define VGBSTAT_NHLEN 0x100 ++#define VGBSTAT_LNKERR 0x00000080 ++#define VGBSTAT_LERRMSK 0xff ++#define VGBSTAT_LDEARLY 0x86 ++#define VGBSTAT_LBOFLO 0x85 ++#define VGBSTAT_LCODERR 0x84 ++#define VGBSTAT_LDBLNBL 0x83 ++#define VGBSTAT_LCRCERR 0x82 ++#define VGBSTAT_LOFLO 0x81 ++#define VGBSTAT_LUFLO 0x80 ++#define IRHDDR_FLEN_MSK 0x0000ffff ++#define IRHDDR_SVALID 0x80000000 ++#define IRHDDR_ERR 0x10000000 ++#define VRHSTAT_802OE 0x80000000 ++#define VRHSTAT_TPOFLO 0x10000000 ++#define VRHSTATB_802UE 0x80000000 ++#define VRHSTATB_RCVE 0x40000000 ++#define VRHSTATB_BUFF 0x20000000 ++#define VRHSTATB_CARRE 0x08000000 ++#define VRHSTATB_LONGE 0x02000000 ++#define VRHSTATB_PREA 0x01000000 ++#define VRHSTATB_CRC 0x00800000 ++#define VRHSTATB_DRBL 0x00400000 ++#define VRHSTATB_CODE 0x00200000 ++#define VRHSTATB_TPCSUM 0x00100000 ++#define VRHSTATB_TPHLEN 0x00080000 ++#define VRHSTATB_IPCSUM 0x00040000 ++#define VRHSTATB_IPLERR 0x00020000 ++#define VRHSTATB_IPHERR 0x00010000 ++#define SLIC_MAX64_BCNT 23 ++#define SLIC_MAX32_BCNT 26 ++#define IHCMD_XMT_REQ 0x01 ++#define IHFLG_IFSHFT 2 ++#define SLIC_RSPBUF_SIZE 32 ++ ++#define SLIC_RESET_MAGIC 0xDEAD ++#define ICR_INT_OFF 0 ++#define ICR_INT_ON 1 ++#define ICR_INT_MASK 2 ++ ++#define ISR_ERR 0x80000000 ++#define ISR_RCV 0x40000000 ++#define ISR_CMD 0x20000000 ++#define ISR_IO 0x60000000 ++#define ISR_UPC 0x10000000 ++#define ISR_LEVENT 0x08000000 ++#define ISR_RMISS 0x02000000 ++#define ISR_UPCERR 0x01000000 ++#define ISR_XDROP 0x00800000 ++#define ISR_UPCBSY 0x00020000 ++#define ISR_EVMSK 0xffff0000 ++#define ISR_PINGMASK 0x00700000 ++#define ISR_PINGDSMASK 0x00710000 ++#define ISR_UPCMASK 0x11000000 ++#define SLIC_WCS_START 0x80000000 ++#define SLIC_WCS_COMPARE 0x40000000 ++#define SLIC_RCVWCS_BEGIN 0x40000000 ++#define SLIC_RCVWCS_FINISH 0x80000000 ++#define SLIC_PM_MAXPATTERNS 6 ++#define SLIC_PM_PATTERNSIZE 128 ++#define SLIC_PMCAPS_WAKEONLAN 0x00000001 ++#define MIICR_REG_PCR 0x00000000 ++#define MIICR_REG_4 0x00040000 ++#define MIICR_REG_9 0x00090000 ++#define MIICR_REG_16 0x00100000 ++#define PCR_RESET 0x8000 ++#define PCR_POWERDOWN 0x0800 ++#define PCR_SPEED_100 0x2000 ++#define PCR_SPEED_1000 0x0040 ++#define PCR_AUTONEG 0x1000 ++#define PCR_AUTONEG_RST 0x0200 ++#define PCR_DUPLEX_FULL 0x0100 ++#define PSR_LINKUP 0x0004 ++ ++#define PAR_ADV100FD 0x0100 ++#define PAR_ADV100HD 0x0080 ++#define PAR_ADV10FD 0x0040 ++#define PAR_ADV10HD 0x0020 ++#define PAR_ASYMPAUSE 0x0C00 ++#define PAR_802_3 0x0001 ++ ++#define PAR_ADV1000XFD 0x0020 ++#define PAR_ADV1000XHD 0x0040 ++#define PAR_ASYMPAUSE_FIBER 0x0180 ++ ++#define PGC_ADV1000FD 0x0200 ++#define PGC_ADV1000HD 0x0100 ++#define SEEQ_LINKFAIL 0x4000 ++#define SEEQ_SPEED 0x0080 ++#define SEEQ_DUPLEX 0x0040 ++#define TDK_DUPLEX 0x0800 ++#define TDK_SPEED 0x0400 ++#define MRV_REG16_XOVERON 0x0068 ++#define MRV_REG16_XOVEROFF 0x0008 ++#define MRV_SPEED_1000 0x8000 ++#define MRV_SPEED_100 0x4000 ++#define MRV_SPEED_10 0x0000 ++#define MRV_FULLDUPLEX 0x2000 ++#define MRV_LINKUP 0x0400 ++ ++#define GIG_LINKUP 0x0001 ++#define GIG_FULLDUPLEX 0x0002 ++#define GIG_SPEED_MASK 0x000C ++#define GIG_SPEED_1000 0x0008 ++#define GIG_SPEED_100 0x0004 ++#define GIG_SPEED_10 0x0000 ++ ++#define MCR_RESET 0x80000000 ++#define MCR_CRCEN 0x40000000 ++#define MCR_FULLD 0x10000000 ++#define MCR_PAD 0x02000000 ++#define MCR_RETRYLATE 0x01000000 ++#define MCR_BOL_SHIFT 21 ++#define MCR_IPG1_SHIFT 14 ++#define MCR_IPG2_SHIFT 7 ++#define MCR_IPG3_SHIFT 0 ++#define GMCR_RESET 0x80000000 ++#define GMCR_GBIT 0x20000000 ++#define GMCR_FULLD 0x10000000 ++#define GMCR_GAPBB_SHIFT 14 ++#define GMCR_GAPR1_SHIFT 7 ++#define GMCR_GAPR2_SHIFT 0 ++#define GMCR_GAPBB_1000 0x60 ++#define GMCR_GAPR1_1000 0x2C ++#define GMCR_GAPR2_1000 0x40 ++#define GMCR_GAPBB_100 0x70 ++#define GMCR_GAPR1_100 0x2C ++#define GMCR_GAPR2_100 0x40 ++#define XCR_RESET 0x80000000 ++#define XCR_XMTEN 0x40000000 ++#define XCR_PAUSEEN 0x20000000 ++#define XCR_LOADRNG 0x10000000 ++#define RCR_RESET 0x80000000 ++#define RCR_RCVEN 0x40000000 ++#define RCR_RCVALL 0x20000000 ++#define RCR_RCVBAD 0x10000000 ++#define RCR_CTLEN 0x08000000 ++#define RCR_ADDRAEN 0x02000000 ++#define GXCR_RESET 0x80000000 ++#define GXCR_XMTEN 0x40000000 ++#define GXCR_PAUSEEN 0x20000000 ++#define GRCR_RESET 0x80000000 ++#define GRCR_RCVEN 0x40000000 ++#define GRCR_RCVALL 0x20000000 ++#define GRCR_RCVBAD 0x10000000 ++#define GRCR_CTLEN 0x08000000 ++#define GRCR_ADDRAEN 0x02000000 ++#define GRCR_HASHSIZE_SHIFT 17 ++#define GRCR_HASHSIZE 14 ++ ++#define SLIC_EEPROM_ID 0xA5A5 ++#define SLIC_SRAM_SIZE2GB (64 * 1024) ++#define SLIC_SRAM_SIZE1GB (32 * 1024) ++#define SLIC_HOSTID_DEFAULT 0xFFFF /* uninitialized hostid */ ++#define SLIC_NBR_MACS 4 ++ ++#ifndef FALSE ++#define FALSE 0 ++#else ++#undef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#else ++#undef TRUE ++#define TRUE 1 ++#endif ++ ++typedef struct _slic_rcvbuf_t { ++ uchar pad1[6]; ++ ushort pad2; ++ ulong32 pad3; ++ ulong32 pad4; ++ ulong32 buffer; ++ ulong32 length; ++ ulong32 status; ++ ulong32 pad5; ++ ushort pad6; ++ uchar data[SLIC_RCVBUF_DATASIZE]; ++} slic_rcvbuf_t, *p_slic_rcvbuf_t; ++ ++typedef struct _slic_hddr_wds { ++ union { ++ struct { ++ ulong32 frame_status; ++ ulong32 frame_status_b; ++ ulong32 time_stamp; ++ ulong32 checksum; ++ } hdrs_14port; ++ struct { ++ ulong32 frame_status; ++ ushort ByteCnt; ++ ushort TpChksum; ++ ushort CtxHash; ++ ushort MacHash; ++ ulong32 BufLnk; ++ } hdrs_gbit; ++ } u0; ++} slic_hddr_wds_t, *p_slic_hddr_wds; ++ ++#define frame_status14 u0.hdrs_14port.frame_status ++#define frame_status_b14 u0.hdrs_14port.frame_status_b ++#define frame_statusGB u0.hdrs_gbit.frame_status ++ ++typedef struct _slic_host64sg_t { ++ ulong32 paddrl; ++ ulong32 paddrh; ++ ulong32 length; ++} slic_host64sg_t, *p_slic_host64sg_t; ++ ++typedef struct _slic_host64_cmd_t { ++ ulong32 hosthandle; ++ ulong32 RSVD; ++ uchar command; ++ uchar flags; ++ union { ++ ushort rsv1; ++ ushort rsv2; ++ } u0; ++ union { ++ struct { ++ ulong32 totlen; ++ slic_host64sg_t bufs[SLIC_MAX64_BCNT]; ++ } slic_buffers; ++ } u; ++ ++} slic_host64_cmd_t, *p_slic_host64_cmd_t; ++ ++typedef struct _slic_rspbuf_t { ++ ulong32 hosthandle; ++ ulong32 pad0; ++ ulong32 pad1; ++ ulong32 status; ++ ulong32 pad2[4]; ++ ++} slic_rspbuf_t, *p_slic_rspbuf_t; ++ ++typedef ulong32 SLIC_REG; ++ ++ ++typedef struct _slic_regs_t { ++ ULONG slic_reset; /* Reset Register */ ++ ULONG pad0; ++ ++ ULONG slic_icr; /* Interrupt Control Register */ ++ ULONG pad2; ++#define SLIC_ICR 0x0008 ++ ++ ULONG slic_isp; /* Interrupt status pointer */ ++ ULONG pad1; ++#define SLIC_ISP 0x0010 ++ ++ ULONG slic_isr; /* Interrupt status */ ++ ULONG pad3; ++#define SLIC_ISR 0x0018 ++ ++ SLIC_REG slic_hbar; /* Header buffer address reg */ ++ ULONG pad4; ++ /* 31-8 - phy addr of set of contiguous hdr buffers ++ 7-0 - number of buffers passed ++ Buffers are 256 bytes long on 256-byte boundaries. */ ++#define SLIC_HBAR 0x0020 ++#define SLIC_HBAR_CNT_MSK 0x000000FF ++ ++ SLIC_REG slic_dbar; /* Data buffer handle & address reg */ ++ ULONG pad5; ++ ++ /* 4 sets of registers; Buffers are 2K bytes long 2 per 4K page. */ ++#define SLIC_DBAR 0x0028 ++#define SLIC_DBAR_SIZE 2048 ++ ++ SLIC_REG slic_cbar; /* Xmt Cmd buf addr regs.*/ ++ /* 1 per XMT interface ++ 31-5 - phy addr of host command buffer ++ 4-0 - length of cmd in multiples of 32 bytes ++ Buffers are 32 bytes up to 512 bytes long */ ++#define SLIC_CBAR 0x0030 ++#define SLIC_CBAR_LEN_MSK 0x0000001F ++#define SLIC_CBAR_ALIGN 0x00000020 ++ ++ SLIC_REG slic_wcs; /* write control store*/ ++#define SLIC_WCS 0x0034 ++#define SLIC_WCS_START 0x80000000 /*Start the SLIC (Jump to WCS)*/ ++#define SLIC_WCS_COMPARE 0x40000000 /* Compare with value in WCS*/ ++ ++ SLIC_REG slic_rbar; /* Response buffer address reg.*/ ++ ULONG pad7; ++ /*31-8 - phy addr of set of contiguous response buffers ++ 7-0 - number of buffers passed ++ Buffers are 32 bytes long on 32-byte boundaries.*/ ++#define SLIC_RBAR 0x0038 ++#define SLIC_RBAR_CNT_MSK 0x000000FF ++#define SLIC_RBAR_SIZE 32 ++ ++ SLIC_REG slic_stats; /* read statistics (UPR) */ ++ ULONG pad8; ++#define SLIC_RSTAT 0x0040 ++ ++ SLIC_REG slic_rlsr; /* read link status */ ++ ULONG pad9; ++#define SLIC_LSTAT 0x0048 ++ ++ SLIC_REG slic_wmcfg; /* Write Mac Config */ ++ ULONG pad10; ++#define SLIC_WMCFG 0x0050 ++ ++ SLIC_REG slic_wphy; /* Write phy register */ ++ ULONG pad11; ++#define SLIC_WPHY 0x0058 ++ ++ SLIC_REG slic_rcbar; /*Rcv Cmd buf addr reg*/ ++ ULONG pad12; ++#define SLIC_RCBAR 0x0060 ++ ++ SLIC_REG slic_rconfig; /* Read SLIC Config*/ ++ ULONG pad13; ++#define SLIC_RCONFIG 0x0068 ++ ++ SLIC_REG slic_intagg; /* Interrupt aggregation time*/ ++ ULONG pad14; ++#define SLIC_INTAGG 0x0070 ++ ++ SLIC_REG slic_wxcfg; /* Write XMIT config reg*/ ++ ULONG pad16; ++#define SLIC_WXCFG 0x0078 ++ ++ SLIC_REG slic_wrcfg; /* Write RCV config reg*/ ++ ULONG pad17; ++#define SLIC_WRCFG 0x0080 ++ ++ SLIC_REG slic_wraddral; /* Write rcv addr a low*/ ++ ULONG pad18; ++#define SLIC_WRADDRAL 0x0088 ++ ++ SLIC_REG slic_wraddrah; /* Write rcv addr a high*/ ++ ULONG pad19; ++#define SLIC_WRADDRAH 0x0090 ++ ++ SLIC_REG slic_wraddrbl; /* Write rcv addr b low*/ ++ ULONG pad20; ++#define SLIC_WRADDRBL 0x0098 ++ ++ SLIC_REG slic_wraddrbh; /* Write rcv addr b high*/ ++ ULONG pad21; ++#define SLIC_WRADDRBH 0x00a0 ++ ++ SLIC_REG slic_mcastlow; /* Low bits of mcast mask*/ ++ ULONG pad22; ++#define SLIC_MCASTLOW 0x00a8 ++ ++ SLIC_REG slic_mcasthigh; /* High bits of mcast mask*/ ++ ULONG pad23; ++#define SLIC_MCASTHIGH 0x00b0 ++ ++ SLIC_REG slic_ping; /* Ping the card*/ ++ ULONG pad24; ++#define SLIC_PING 0x00b8 ++ ++ SLIC_REG slic_dump_cmd; /* Dump command */ ++ ULONG pad25; ++#define SLIC_DUMP_CMD 0x00c0 ++ ++ SLIC_REG slic_dump_data; /* Dump data pointer */ ++ ULONG pad26; ++#define SLIC_DUMP_DATA 0x00c8 ++ ++ SLIC_REG slic_pcistatus; /* Read card's pci_status register */ ++ ULONG pad27; ++#define SLIC_PCISTATUS 0x00d0 ++ ++ SLIC_REG slic_wrhostid; /* Write hostid field */ ++ ULONG pad28; ++#define SLIC_WRHOSTID 0x00d8 ++#define SLIC_RDHOSTID_1GB 0x1554 ++#define SLIC_RDHOSTID_2GB 0x1554 ++ ++ SLIC_REG slic_low_power; /* Put card in a low power state */ ++ ULONG pad29; ++#define SLIC_LOW_POWER 0x00e0 ++ ++ SLIC_REG slic_quiesce; /* force slic into quiescent state ++ before soft reset */ ++ ULONG pad30; ++#define SLIC_QUIESCE 0x00e8 ++ ++ SLIC_REG slic_reset_iface; /* reset interface queues */ ++ ULONG pad31; ++#define SLIC_RESET_IFACE 0x00f0 ++ ++ SLIC_REG slic_addr_upper; /* Bits 63-32 for host i/f addrs */ ++ ULONG pad32; ++#define SLIC_ADDR_UPPER 0x00f8 /*Register is only written when it has changed*/ ++ ++ SLIC_REG slic_hbar64; /* 64 bit Header buffer address reg */ ++ ULONG pad33; ++#define SLIC_HBAR64 0x0100 ++ ++ SLIC_REG slic_dbar64; /* 64 bit Data buffer handle & address reg */ ++ ULONG pad34; ++#define SLIC_DBAR64 0x0108 ++ ++ SLIC_REG slic_cbar64; /* 64 bit Xmt Cmd buf addr regs. */ ++ ULONG pad35; ++#define SLIC_CBAR64 0x0110 ++ ++ SLIC_REG slic_rbar64; /* 64 bit Response buffer address reg.*/ ++ ULONG pad36; ++#define SLIC_RBAR64 0x0118 ++ ++ SLIC_REG slic_rcbar64; /* 64 bit Rcv Cmd buf addr reg*/ ++ ULONG pad37; ++#define SLIC_RCBAR64 0x0120 ++ ++ SLIC_REG slic_stats64; /*read statistics (64 bit UPR)*/ ++ ULONG pad38; ++#define SLIC_RSTAT64 0x0128 ++ ++ SLIC_REG slic_rcv_wcs; /*Download Gigabit RCV sequencer ucode*/ ++ ULONG pad39; ++#define SLIC_RCV_WCS 0x0130 ++#define SLIC_RCVWCS_BEGIN 0x40000000 ++#define SLIC_RCVWCS_FINISH 0x80000000 ++ ++ SLIC_REG slic_wrvlanid; /* Write VlanId field */ ++ ULONG pad40; ++#define SLIC_WRVLANID 0x0138 ++ ++ SLIC_REG slic_read_xf_info; /* Read Transformer info */ ++ ULONG pad41; ++#define SLIC_READ_XF_INFO 0x0140 ++ ++ SLIC_REG slic_write_xf_info; /* Write Transformer info */ ++ ULONG pad42; ++#define SLIC_WRITE_XF_INFO 0x0148 ++ ++ SLIC_REG RSVD1; /* TOE Only */ ++ ULONG pad43; ++ ++ SLIC_REG RSVD2; /* TOE Only */ ++ ULONG pad44; ++ ++ SLIC_REG RSVD3; /* TOE Only */ ++ ULONG pad45; ++ ++ SLIC_REG RSVD4; /* TOE Only */ ++ ULONG pad46; ++ ++ SLIC_REG slic_ticks_per_sec; /* Write card ticks per second */ ++ ULONG pad47; ++#define SLIC_TICKS_PER_SEC 0x0170 ++ ++} __iomem slic_regs_t, *p_slic_regs_t, SLIC_REGS, *PSLIC_REGS; ++ ++typedef enum _UPR_REQUEST { ++ SLIC_UPR_STATS, ++ SLIC_UPR_RLSR, ++ SLIC_UPR_WCFG, ++ SLIC_UPR_RCONFIG, ++ SLIC_UPR_RPHY, ++ SLIC_UPR_ENLB, ++ SLIC_UPR_ENCT, ++ SLIC_UPR_PDWN, ++ SLIC_UPR_PING, ++ SLIC_UPR_DUMP, ++} UPR_REQUEST; ++ ++typedef struct _inicpm_wakepattern { ++ ulong32 patternlength; ++ uchar pattern[SLIC_PM_PATTERNSIZE]; ++ uchar mask[SLIC_PM_PATTERNSIZE]; ++} inicpm_wakepattern_t, *p_inicpm_wakepattern_t; ++ ++typedef struct _inicpm_state { ++ ulong32 powercaps; ++ ulong32 powerstate; ++ ulong32 wake_linkstatus; ++ ulong32 wake_magicpacket; ++ ulong32 wake_framepattern; ++ inicpm_wakepattern_t wakepattern[SLIC_PM_MAXPATTERNS]; ++} inicpm_state_t, *p_inicpm_state_t; ++ ++typedef struct _slicpm_packet_pattern { ++ ulong32 priority; ++ ulong32 reserved; ++ ulong32 masksize; ++ ulong32 patternoffset; ++ ulong32 patternsize; ++ ulong32 patternflags; ++} slicpm_packet_pattern_t, *p_slicpm_packet_pattern_t; ++ ++typedef enum _slicpm_power_state { ++ slicpm_state_unspecified = 0, ++ slicpm_state_d0, ++ slicpm_state_d1, ++ slicpm_state_d2, ++ slicpm_state_d3, ++ slicpm_state_maximum ++} slicpm_state_t, *p_slicpm_state_t; ++ ++typedef struct _slicpm_wakeup_capabilities { ++ slicpm_state_t min_magic_packet_wakeup; ++ slicpm_state_t min_pattern_wakeup; ++ slicpm_state_t min_link_change_wakeup; ++} slicpm_wakeup_capabilities_t, *p_slicpm_wakeup_capabilities_t; ++ ++ ++typedef struct _slic_pnp_capabilities { ++ ulong32 flags; ++ slicpm_wakeup_capabilities_t wakeup_capabilities; ++} slic_pnp_capabilities_t, *p_slic_pnp_capabilities_t; ++ ++typedef struct _xmt_stats_t { ++ ulong32 xmit_tcp_bytes; ++ ulong32 xmit_tcp_segs; ++ ulong32 xmit_bytes; ++ ulong32 xmit_collisions; ++ ulong32 xmit_unicasts; ++ ulong32 xmit_other_error; ++ ulong32 xmit_excess_collisions; ++} xmt_stats100_t; ++ ++typedef struct _rcv_stats_t { ++ ulong32 rcv_tcp_bytes; ++ ulong32 rcv_tcp_segs; ++ ulong32 rcv_bytes; ++ ulong32 rcv_unicasts; ++ ulong32 rcv_other_error; ++ ulong32 rcv_drops; ++} rcv_stats100_t; ++ ++typedef struct _xmt_statsgb_t { ++ ulong64 xmit_tcp_bytes; ++ ulong64 xmit_tcp_segs; ++ ulong64 xmit_bytes; ++ ulong64 xmit_collisions; ++ ulong64 xmit_unicasts; ++ ulong64 xmit_other_error; ++ ulong64 xmit_excess_collisions; ++} xmt_statsGB_t; ++ ++typedef struct _rcv_statsgb_t { ++ ulong64 rcv_tcp_bytes; ++ ulong64 rcv_tcp_segs; ++ ulong64 rcv_bytes; ++ ulong64 rcv_unicasts; ++ u64 rcv_other_error; ++ ulong64 rcv_drops; ++} rcv_statsGB_t; ++ ++typedef struct _slic_stats { ++ union { ++ struct { ++ xmt_stats100_t xmt100; ++ rcv_stats100_t rcv100; ++ } stats_100; ++ struct { ++ xmt_statsGB_t xmtGB; ++ rcv_statsGB_t rcvGB; ++ } stats_GB; ++ } u; ++} slic_stats_t, *p_slic_stats_t; ++ ++#define xmit_tcp_segs100 u.stats_100.xmt100.xmit_tcp_segs ++#define xmit_tcp_bytes100 u.stats_100.xmt100.xmit_tcp_bytes ++#define xmit_bytes100 u.stats_100.xmt100.xmit_bytes ++#define xmit_collisions100 u.stats_100.xmt100.xmit_collisions ++#define xmit_unicasts100 u.stats_100.xmt100.xmit_unicasts ++#define xmit_other_error100 u.stats_100.xmt100.xmit_other_error ++#define xmit_excess_collisions100 u.stats_100.xmt100.xmit_excess_collisions ++#define rcv_tcp_segs100 u.stats_100.rcv100.rcv_tcp_segs ++#define rcv_tcp_bytes100 u.stats_100.rcv100.rcv_tcp_bytes ++#define rcv_bytes100 u.stats_100.rcv100.rcv_bytes ++#define rcv_unicasts100 u.stats_100.rcv100.rcv_unicasts ++#define rcv_other_error100 u.stats_100.rcv100.rcv_other_error ++#define rcv_drops100 u.stats_100.rcv100.rcv_drops ++#define xmit_tcp_segs_gb u.stats_GB.xmtGB.xmit_tcp_segs ++#define xmit_tcp_bytes_gb u.stats_GB.xmtGB.xmit_tcp_bytes ++#define xmit_bytes_gb u.stats_GB.xmtGB.xmit_bytes ++#define xmit_collisions_gb u.stats_GB.xmtGB.xmit_collisions ++#define xmit_unicasts_gb u.stats_GB.xmtGB.xmit_unicasts ++#define xmit_other_error_gb u.stats_GB.xmtGB.xmit_other_error ++#define xmit_excess_collisions_gb u.stats_GB.xmtGB.xmit_excess_collisions ++ ++#define rcv_tcp_segs_gb u.stats_GB.rcvGB.rcv_tcp_segs ++#define rcv_tcp_bytes_gb u.stats_GB.rcvGB.rcv_tcp_bytes ++#define rcv_bytes_gb u.stats_GB.rcvGB.rcv_bytes ++#define rcv_unicasts_gb u.stats_GB.rcvGB.rcv_unicasts ++#define rcv_other_error_gb u.stats_GB.rcvGB.rcv_other_error ++#define rcv_drops_gb u.stats_GB.rcvGB.rcv_drops ++ ++typedef struct _slic_config_mac_t { ++ uchar macaddrA[6]; ++ ++} slic_config_mac_t, *pslic_config_mac_t; ++ ++#define ATK_FRU_FORMAT 0x00 ++#define VENDOR1_FRU_FORMAT 0x01 ++#define VENDOR2_FRU_FORMAT 0x02 ++#define VENDOR3_FRU_FORMAT 0x03 ++#define VENDOR4_FRU_FORMAT 0x04 ++#define NO_FRU_FORMAT 0xFF ++ ++typedef struct _atk_fru_t { ++ uchar assembly[6]; ++ uchar revision[2]; ++ uchar serial[14]; ++ uchar pad[3]; ++} atk_fru_t, *patk_fru_t; ++ ++typedef struct _vendor1_fru_t { ++ uchar commodity; ++ uchar assembly[4]; ++ uchar revision[2]; ++ uchar supplier[2]; ++ uchar date[2]; ++ uchar sequence[3]; ++ uchar pad[13]; ++} vendor1_fru_t, *pvendor1_fru_t; ++ ++typedef struct _vendor2_fru_t { ++ uchar part[8]; ++ uchar supplier[5]; ++ uchar date[3]; ++ uchar sequence[4]; ++ uchar pad[7]; ++} vendor2_fru_t, *pvendor2_fru_t; ++ ++typedef struct _vendor3_fru_t { ++ uchar assembly[6]; ++ uchar revision[2]; ++ uchar serial[14]; ++ uchar pad[3]; ++} vendor3_fru_t, *pvendor3_fru_t; ++ ++typedef struct _vendor4_fru_t { ++ uchar number[8]; ++ uchar part[8]; ++ uchar version[8]; ++ uchar pad[3]; ++} vendor4_fru_t, *pvendor4_fru_t; ++ ++typedef union _oemfru_t { ++ vendor1_fru_t vendor1_fru; ++ vendor2_fru_t vendor2_fru; ++ vendor3_fru_t vendor3_fru; ++ vendor4_fru_t vendor4_fru; ++} oemfru_t, *poemfru_t; ++ ++/* ++ SLIC EEPROM structure for Mojave ++*/ ++typedef struct _slic_eeprom { ++ ushort Id; /* 00 EEPROM/FLASH Magic code 'A5A5'*/ ++ ushort EecodeSize; /* 01 Size of EEPROM Codes (bytes * 4)*/ ++ ushort FlashSize; /* 02 Flash size */ ++ ushort EepromSize; /* 03 EEPROM Size */ ++ ushort VendorId; /* 04 Vendor ID */ ++ ushort DeviceId; /* 05 Device ID */ ++ uchar RevisionId; /* 06 Revision ID */ ++ uchar ClassCode[3]; /* 07 Class Code */ ++ uchar DbgIntPin; /* 08 Debug Interrupt pin */ ++ uchar NetIntPin0; /* Network Interrupt Pin */ ++ uchar MinGrant; /* 09 Minimum grant */ ++ uchar MaxLat; /* Maximum Latency */ ++ ushort PciStatus; /* 10 PCI Status */ ++ ushort SubSysVId; /* 11 Subsystem Vendor Id */ ++ ushort SubSysId; /* 12 Subsystem ID */ ++ ushort DbgDevId; /* 13 Debug Device Id */ ++ ushort DramRomFn; /* 14 Dram/Rom function */ ++ ushort DSize2Pci; /* 15 DRAM size to PCI (bytes * 64K) */ ++ ushort RSize2Pci; /* 16 ROM extension size to PCI (bytes * 4k) */ ++ uchar NetIntPin1; /* 17 Network Interface Pin 1 (simba/leone only) */ ++ uchar NetIntPin2; /* Network Interface Pin 2 (simba/leone only) */ ++ union { ++ uchar NetIntPin3;/* 18 Network Interface Pin 3 (simba only) */ ++ uchar FreeTime;/* FreeTime setting (leone/mojave only) */ ++ } u1; ++ uchar TBIctl; /* 10-bit interface control (Mojave only) */ ++ ushort DramSize; /* 19 DRAM size (bytes * 64k) */ ++ union { ++ struct { ++ /* Mac Interface Specific portions */ ++ slic_config_mac_t MacInfo[SLIC_NBR_MACS]; ++ } mac; /* MAC access for all boards */ ++ struct { ++ /* use above struct for MAC access */ ++ slic_config_mac_t pad[SLIC_NBR_MACS - 1]; ++ ushort DeviceId2; /* Device ID for 2nd ++ PCI function */ ++ uchar IntPin2; /* Interrupt pin for ++ 2nd PCI function */ ++ uchar ClassCode2[3]; /* Class Code for 2nd ++ PCI function */ ++ } mojave; /* 2nd function access for gigabit board */ ++ } u2; ++ ushort CfgByte6; /* Config Byte 6 */ ++ ushort PMECapab; /* Power Mgment capabilities */ ++ ushort NwClkCtrls; /* NetworkClockControls */ ++ uchar FruFormat; /* Alacritech FRU format type */ ++ atk_fru_t AtkFru; /* Alacritech FRU information */ ++ uchar OemFruFormat; /* optional OEM FRU format type */ ++ oemfru_t OemFru; /* optional OEM FRU information */ ++ uchar Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes ++ *(if OEM FRU info exists) and two unusable ++ * bytes at the end */ ++} slic_eeprom_t, *pslic_eeprom_t; ++ ++/* SLIC EEPROM structure for Oasis */ ++typedef struct _oslic_eeprom_t { ++ ushort Id; /* 00 EEPROM/FLASH Magic code 'A5A5' */ ++ ushort EecodeSize; /* 01 Size of EEPROM Codes (bytes * 4)*/ ++ ushort FlashConfig0; /* 02 Flash Config for SPI device 0 */ ++ ushort FlashConfig1; /* 03 Flash Config for SPI device 1 */ ++ ushort VendorId; /* 04 Vendor ID */ ++ ushort DeviceId; /* 05 Device ID (function 0) */ ++ uchar RevisionId; /* 06 Revision ID */ ++ uchar ClassCode[3]; /* 07 Class Code for PCI function 0 */ ++ uchar IntPin1; /* 08 Interrupt pin for PCI function 1*/ ++ uchar ClassCode2[3]; /* 09 Class Code for PCI function 1 */ ++ uchar IntPin2; /* 10 Interrupt pin for PCI function 2*/ ++ uchar IntPin0; /* Interrupt pin for PCI function 0*/ ++ uchar MinGrant; /* 11 Minimum grant */ ++ uchar MaxLat; /* Maximum Latency */ ++ ushort SubSysVId; /* 12 Subsystem Vendor Id */ ++ ushort SubSysId; /* 13 Subsystem ID */ ++ ushort FlashSize; /* 14 Flash size (bytes / 4K) */ ++ ushort DSize2Pci; /* 15 DRAM size to PCI (bytes / 64K) */ ++ ushort RSize2Pci; /* 16 Flash (ROM extension) size to ++ PCI (bytes / 4K) */ ++ ushort DeviceId1; /* 17 Device Id (function 1) */ ++ ushort DeviceId2; /* 18 Device Id (function 2) */ ++ ushort CfgByte6; /* 19 Device Status Config Bytes 6-7 */ ++ ushort PMECapab; /* 20 Power Mgment capabilities */ ++ uchar MSICapab; /* 21 MSI capabilities */ ++ uchar ClockDivider; /* Clock divider */ ++ ushort PciStatusLow; /* 22 PCI Status bits 15:0 */ ++ ushort PciStatusHigh; /* 23 PCI Status bits 31:16 */ ++ ushort DramConfigLow; /* 24 DRAM Configuration bits 15:0 */ ++ ushort DramConfigHigh; /* 25 DRAM Configuration bits 31:16 */ ++ ushort DramSize; /* 26 DRAM size (bytes / 64K) */ ++ ushort GpioTbiCtl;/* 27 GPIO/TBI controls for functions 1/0 */ ++ ushort EepromSize; /* 28 EEPROM Size */ ++ slic_config_mac_t MacInfo[2]; /* 29 MAC addresses (2 ports) */ ++ uchar FruFormat; /* 35 Alacritech FRU format type */ ++ atk_fru_t AtkFru; /* Alacritech FRU information */ ++ uchar OemFruFormat; /* optional OEM FRU format type */ ++ oemfru_t OemFru; /* optional OEM FRU information */ ++ uchar Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes ++ * (if OEM FRU info exists) and two unusable ++ * bytes at the end ++ */ ++} oslic_eeprom_t, *poslic_eeprom_t; ++ ++#define MAX_EECODE_SIZE sizeof(slic_eeprom_t) ++#define MIN_EECODE_SIZE 0x62 /* code size without optional OEM FRU stuff */ ++ ++/* SLIC CONFIG structure ++ ++ This structure lives in the CARD structure and is valid for all ++ board types. It is filled in from the appropriate EEPROM structure ++ by SlicGetConfigData(). ++*/ ++typedef struct _slic_config_t { ++ boolean EepromValid; /* Valid EEPROM flag (checksum good?) */ ++ ushort DramSize; /* DRAM size (bytes / 64K) */ ++ slic_config_mac_t MacInfo[SLIC_NBR_MACS]; /* MAC addresses */ ++ uchar FruFormat; /* Alacritech FRU format type */ ++ atk_fru_t AtkFru; /* Alacritech FRU information */ ++ uchar OemFruFormat; /* optional OEM FRU format type */ ++ union { ++ vendor1_fru_t vendor1_fru; ++ vendor2_fru_t vendor2_fru; ++ vendor3_fru_t vendor3_fru; ++ vendor4_fru_t vendor4_fru; ++ } OemFru; ++} slic_config_t, *pslic_config_t; ++ ++#pragma pack() ++ ++#endif +diff --git a/drivers/staging/slicoss/slicinc.h b/drivers/staging/slicoss/slicinc.h +new file mode 100644 +index 0000000..9910306 +--- /dev/null ++++ b/drivers/staging/slicoss/slicinc.h +@@ -0,0 +1,221 @@ ++/************************************************************************** ++ * ++ * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: slicinc.h,v 1.4 2006/07/14 16:42:56 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slicinc.h ++ * ++ * This file contains all other include files and prototype definitions ++ * for the SLICOSS driver. ++ */ ++#ifndef _SLIC_INCLUDE_H_ ++#define _SLIC_INCLUDE_H_ ++ ++#include "slic_os.h" ++#include "slicdbg.h" ++#include "slichw.h" ++#include "slic.h" ++ ++int slic_entry_probe(struct pci_dev *pcidev, ++ const struct pci_device_id *ent); ++int slic_init(struct pci_dev *pcidev, ++ const struct pci_device_id *pci_tbl_entry, ++ long memaddr, ++ int chip_idx, ++ int acpi_idle_state); ++void slic_entry_remove(struct pci_dev *pcidev); ++ ++void slic_init_driver(void); ++int slic_entry_open(struct net_device *dev); ++int slic_entry_halt(struct net_device *dev); ++int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++int slic_xmit_start(struct sk_buff *skb, struct net_device *dev); ++void slic_xmit_fail(p_adapter_t adapter, ++ struct sk_buff *skb, ++ pvoid cmd, ++ ulong32 skbtype, ++ ulong32 status); ++void slic_xmit_timeout(struct net_device *dev); ++void slic_config_pci(struct pci_dev *pcidev); ++struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter); ++ ++inline void slic_reg32_write(void __iomem *reg, ulong32 value, uint flush); ++inline void slic_reg64_write(p_adapter_t adapter, void __iomem *reg, ++ ulong32 value, void __iomem *regh, ulong32 paddrh, uint flush); ++inline ulong32 slic_reg32_read(pulong32 reg, uint flush); ++inline ulong32 slic_reg16_read(pulong32 reg, uint flush); ++ ++#if SLIC_GET_STATS_ENABLED ++struct net_device_stats *slic_get_stats(struct net_device *dev); ++#endif ++ ++int slic_mac_set_address(struct net_device *dev, pvoid ptr); ++ ++int slicproc_card_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data); ++int slicproc_card_write(struct file *file, const char __user *buffer, ++ ulong count, void *data); ++void slicproc_card_create(p_sliccard_t card); ++void slicproc_card_destroy(p_sliccard_t card); ++int slicproc_adapter_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data); ++int slicproc_adapter_write(struct file *file, const char __user *buffer, ++ ulong count, void *data); ++void slicproc_adapter_create(p_adapter_t adapter); ++void slicproc_adapter_destroy(p_adapter_t adapter); ++void slicproc_create(void); ++void slicproc_destroy(void); ++ ++void slic_interrupt_process(p_adapter_t adapter, ulong32 isr); ++void slic_rcv_handler(p_adapter_t adapter); ++void slic_upr_handler(p_adapter_t adapter); ++void slic_link_event_handler(p_adapter_t adapter); ++void slic_xmit_complete(p_adapter_t adapter); ++void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr); ++int slic_rspqueue_init(p_adapter_t adapter); ++int slic_rspqueue_reset(p_adapter_t adapter); ++void slic_rspqueue_free(p_adapter_t adapter); ++p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter); ++void slic_cmdqmem_init(p_adapter_t adapter); ++void slic_cmdqmem_free(p_adapter_t adapter); ++pulong32 slic_cmdqmem_addpage(p_adapter_t adapter); ++int slic_cmdq_init(p_adapter_t adapter); ++void slic_cmdq_free(p_adapter_t adapter); ++void slic_cmdq_reset(p_adapter_t adapter); ++void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page); ++void slic_cmdq_getdone(p_adapter_t adapter); ++void slic_cmdq_putdone(p_adapter_t adapter, p_slic_hostcmd_t cmd); ++void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd); ++p_slic_hostcmd_t slic_cmdq_getfree(p_adapter_t adapter); ++int slic_rcvqueue_init(p_adapter_t adapter); ++int slic_rcvqueue_reset(p_adapter_t adapter); ++int slic_rcvqueue_fill(p_adapter_t adapter); ++ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb); ++void slic_rcvqueue_free(p_adapter_t adapter); ++void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf); ++void slic_adapter_set_hwaddr(p_adapter_t adapter); ++void slic_card_halt(p_sliccard_t card, p_adapter_t adapter); ++int slic_card_init(p_sliccard_t card, p_adapter_t adapter); ++void slic_intagg_set(p_adapter_t adapter, ulong32 value); ++int slic_card_download(p_adapter_t adapter); ++ulong32 slic_card_locate(p_adapter_t adapter); ++int slic_card_removeadapter(p_adapter_t adapter); ++void slic_card_remaster(p_adapter_t adapter); ++void slic_card_softreset(p_adapter_t adapter); ++void slic_card_up(p_adapter_t adapter); ++void slic_card_down(p_adapter_t adapter); ++ ++void slic_if_stop_queue(p_adapter_t adapter); ++void slic_if_start_queue(p_adapter_t adapter); ++int slic_if_init(p_adapter_t adapter); ++void slic_adapter_close(p_adapter_t adapter); ++int slic_adapter_allocresources(p_adapter_t adapter); ++void slic_adapter_freeresources(p_adapter_t adapter); ++void slic_link_config(p_adapter_t adapter, ulong32 linkspeed, ++ ulong32 linkduplex); ++void slic_unmap_mmio_space(p_adapter_t adapter); ++void slic_card_cleanup(p_sliccard_t card); ++void slic_init_cleanup(p_adapter_t adapter); ++void slic_card_reclaim_buffers(p_adapter_t adapter); ++void slic_soft_reset(p_adapter_t adapter); ++void slic_card_reset(p_adapter_t adapter); ++boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame); ++void slic_mac_address_config(p_adapter_t adapter); ++void slic_mac_config(p_adapter_t adapter); ++void slic_mcast_set_mask(p_adapter_t adapter); ++void slic_mac_setmcastaddrs(p_adapter_t adapter); ++int slic_mcast_add_list(p_adapter_t adapter, pchar address); ++uchar slic_mcast_get_mac_hash(pchar macaddr); ++void slic_mcast_set_bit(p_adapter_t adapter, pchar address); ++void slic_config_set(p_adapter_t adapter, boolean linkchange); ++void slic_config_clear(p_adapter_t adapter); ++void slic_config_get(p_adapter_t adapter, ulong32 config, ulong32 configh); ++void slic_timer_get_stats(ulong device); ++void slic_timer_load_check(ulong context); ++void slic_timer_ping(ulong dev); ++void slic_stall_msec(int stall); ++void slic_stall_usec(int stall); ++void slic_assert_fail(void); ++ushort slic_eeprom_cksum(pchar m, int len); ++/* upr */ ++void slic_upr_start(p_adapter_t adapter); ++void slic_link_upr_complete(p_adapter_t adapter, ulong32 Isr); ++int slic_upr_request(p_adapter_t adapter, ++ ulong32 upr_request, ++ ulong32 upr_data, ++ ulong32 upr_data_h, ++ ulong32 upr_buffer, ++ ulong32 upr_buffer_h); ++int slic_upr_queue_request(p_adapter_t adapter, ++ ulong32 upr_request, ++ ulong32 upr_data, ++ ulong32 upr_data_h, ++ ulong32 upr_buffer, ++ ulong32 upr_buffer_h); ++void slic_mcast_set_list(struct net_device *dev); ++void slic_mcast_init_crc32(void); ++ ++#if SLIC_DUMP_ENABLED ++int slic_dump_thread(void *context); ++uint slic_init_dump_thread(p_sliccard_t card); ++uchar slic_get_dump_index(pchar path); ++ulong32 slic_dump_card(p_sliccard_t card, boolean resume); ++ulong32 slic_dump_halt(p_sliccard_t card, uchar proc); ++ulong32 slic_dump_reg(p_sliccard_t card, uchar proc); ++ulong32 slic_dump_data(p_sliccard_t card, ulong32 addr, ++ ushort count, uchar desc); ++ulong32 slic_dump_queue(p_sliccard_t card, ulong32 buf_phys, ++ ulong32 buf_physh, ulong32 queue); ++ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue); ++ulong32 slic_dump_cam(p_sliccard_t card, ulong32 addr, ++ ulong32 count, uchar desc); ++ ++ulong32 slic_dump_resume(p_sliccard_t card, uchar proc); ++ulong32 slic_dump_send_cmd(p_sliccard_t card, ulong32 cmd_phys, ++ ulong32 cmd_physh, ulong32 buf_phys, ++ ulong32 buf_physh); ++ ++#define create_file(x) STATUS_SUCCESS ++#define write_file(w, x, y, z) STATUS_SUCCESS ++#define close_file(x) STATUS_SUCCESS ++#define read_file(w, x, y, z) STATUS_SUCCESS ++#define open_file(x) STATUS_SUCCESS ++ ++/* PAGE_SIZE * 16 */ ++#define DUMP_PAGE_SIZE 0xFFFF ++#define DUMP_PAGE_SIZE_HALF 0x7FFE ++#endif ++ ++#endif /* _SLIC_INCLUDE_H_ */ +diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c +new file mode 100644 +index 0000000..a8c2648 +--- /dev/null ++++ b/drivers/staging/slicoss/slicoss.c +@@ -0,0 +1,6074 @@ ++/************************************************************************** ++ * ++ * Copyright 2000-2006 Alacritech, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * Alternatively, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2 as published by the Free ++ * Software Foundation. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: slicoss.c ++ * ++ * The SLICOSS driver for Alacritech's IS-NIC products. ++ * ++ * This driver is supposed to support: ++ * ++ * Mojave cards (single port PCI Gigabit) both copper and fiber ++ * Oasis cards (single and dual port PCI-x Gigabit) copper and fiber ++ * Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber ++ * ++ * The driver was acutally tested on Oasis and Kalahari cards. ++ * ++ * ++ * NOTE: This is the standard, non-accelerated version of Alacritech's ++ * IS-NIC driver. ++ */ ++ ++#include ++ ++#define SLIC_DUMP_ENABLED 0 ++#define KLUDGE_FOR_4GB_BOUNDARY 1 ++#define DEBUG_MICROCODE 1 ++#define SLIC_PRODUCTION_BUILD 1 ++#define SLIC_FAILURE_RESET 1 ++#define DBG 1 ++#define SLIC_ASSERT_ENABLED 1 ++#define SLIC_GET_STATS_ENABLED 1 ++#define SLIC_GET_STATS_TIMER_ENABLED 0 ++#define SLIC_PING_TIMER_ENABLED 1 ++#define SLIC_POWER_MANAGEMENT_ENABLED 0 ++#define SLIC_INTERRUPT_PROCESS_LIMIT 1 ++#define LINUX_FREES_ADAPTER_RESOURCES 1 ++#define SLIC_OFFLOAD_IP_CHECKSUM 1 ++#define STATS_TIMER_INTERVAL 2 ++#define PING_TIMER_INTERVAL 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#define SLIC_ETHTOOL_SUPPORT 1 ++ ++#include ++#include "slicinc.h" ++#include "gbdownload.h" ++#include "gbrcvucode.h" ++#include "oasisrcvucode.h" ++ ++#ifdef DEBUG_MICROCODE ++#include "oasisdbgdownload.h" ++#else ++#include "oasisdownload.h" ++#endif ++ ++#if SLIC_DUMP_ENABLED ++#include "slicdump.h" ++#endif ++ ++#define SLIC_POWER_MANAGEMENT 0 ++ ++static uint slic_first_init = 1; ++static char *slic_banner = "Alacritech SLIC Technology(tm) Server "\ ++ "and Storage Accelerator (Non-Accelerated)\n"; ++ ++static char *slic_proc_version = "2.0.351 2006/07/14 12:26:00"; ++static char *slic_product_name = "SLIC Technology(tm) Server "\ ++ "and Storage Accelerator (Non-Accelerated)"; ++static char *slic_vendor = "Alacritech, Inc."; ++ ++static int slic_debug = 1; ++static int debug = -1; ++static struct net_device *head_netdevice; ++ ++base_driver_t slic_global = { {}, 0, 0, 0, 1, NULL, NULL }; ++static int intagg_delay = 100; ++static u32 dynamic_intagg; ++static int errormsg; ++static int goodmsg; ++static unsigned int rcv_count; ++static struct dentry *slic_debugfs; ++ ++#define DRV_NAME "slicoss" ++#define DRV_VERSION "2.0.1" ++#define DRV_AUTHOR "Alacritech, Inc. Engineering" ++#define DRV_DESCRIPTION "Alacritech SLIC Techonology(tm) "\ ++ "Non-Accelerated Driver" ++#define DRV_COPYRIGHT "Copyright 2000-2006 Alacritech, Inc. "\ ++ "All rights reserved." ++#define PFX DRV_NAME " " ++ ++MODULE_AUTHOR(DRV_AUTHOR); ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++module_param(dynamic_intagg, int, 0); ++MODULE_PARM_DESC(dynamic_intagg, "Dynamic Interrupt Aggregation Setting"); ++module_param(intagg_delay, int, 0); ++MODULE_PARM_DESC(intagg_delay, "uSec Interrupt Aggregation Delay"); ++ ++static struct pci_device_id slic_pci_tbl[] __devinitdata = { ++ {PCI_VENDOR_ID_ALACRITECH, ++ SLIC_1GB_DEVICE_ID, ++ PCI_ANY_ID, PCI_ANY_ID,}, ++ {PCI_VENDOR_ID_ALACRITECH, ++ SLIC_2GB_DEVICE_ID, ++ PCI_ANY_ID, PCI_ANY_ID,}, ++ {0,} ++}; ++ ++MODULE_DEVICE_TABLE(pci, slic_pci_tbl); ++ ++#define SLIC_GET_SLIC_HANDLE(_adapter, _pslic_handle) \ ++{ \ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++ _pslic_handle = _adapter->pfree_slic_handles; \ ++ if (_pslic_handle) { \ ++ ASSERT(_pslic_handle->type == SLIC_HANDLE_FREE); \ ++ _adapter->pfree_slic_handles = _pslic_handle->next; \ ++ } \ ++ SLIC_RELEASE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++} ++ ++#define SLIC_FREE_SLIC_HANDLE(_adapter, _pslic_handle) \ ++{ \ ++ _pslic_handle->type = SLIC_HANDLE_FREE; \ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++ _pslic_handle->next = _adapter->pfree_slic_handles; \ ++ _adapter->pfree_slic_handles = _pslic_handle; \ ++ SLIC_RELEASE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++} ++ ++static void slic_debug_init(void); ++static void slic_debug_cleanup(void); ++static void slic_debug_adapter_create(p_adapter_t adapter); ++static void slic_debug_adapter_destroy(p_adapter_t adapter); ++static void slic_debug_card_create(p_sliccard_t card); ++static void slic_debug_card_destroy(p_sliccard_t card); ++ ++inline void slic_reg32_write(void __iomem *reg, ulong32 value, uint flush) ++{ ++ writel(value, reg); ++ if (flush) ++ mb(); ++} ++ ++inline void slic_reg64_write(p_adapter_t adapter, ++ void __iomem *reg, ++ ulong32 value, ++ void __iomem *regh, ulong32 paddrh, uint flush) ++{ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock); ++ if (paddrh != adapter->curaddrupper) { ++ adapter->curaddrupper = paddrh; ++ writel(paddrh, regh); ++ } ++ writel(value, reg); ++ if (flush) ++ mb(); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock); ++} ++ ++inline ulong32 slic_reg32_read(u32 __iomem *reg, uint flush) ++{ ++ return readl(reg); ++} ++ ++inline ulong32 slic_reg16_read(pulong32 reg, uint flush) ++{ ++ return (ushort) readw(reg); ++} ++ ++void slic_init_driver(void) ++{ ++ if (slic_first_init) { ++ DBG_MSG("slicoss: %s slic_first_init set jiffies[%lx]\n", ++ __func__, jiffies); ++ slic_first_init = 0; ++ SLIC_INIT_SPINLOCK(slic_global.driver_lock); ++ slic_debug_init(); ++ } ++} ++ ++static void slic_dbg_macaddrs(p_adapter_t adapter) ++{ ++ DBG_MSG(" (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ adapter->netdev->name, adapter->currmacaddr[0], ++ adapter->currmacaddr[1], adapter->currmacaddr[2], ++ adapter->currmacaddr[3], adapter->currmacaddr[4], ++ adapter->currmacaddr[5]); ++ DBG_MSG(" (%s) mac %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ adapter->netdev->name, adapter->macaddr[0], ++ adapter->macaddr[1], adapter->macaddr[2], ++ adapter->macaddr[3], adapter->macaddr[4], adapter->macaddr[5]); ++ return; ++} ++ ++#ifdef DEBUG_REGISTER_TRACE ++static void slic_dbg_register_trace(p_adapter_t adapter, p_sliccard_t card) ++{ ++ uint i; ++ ++ DBG_ERROR("Dump Register Write Trace: curr_ix == %d\n", card->debug_ix); ++ for (i = 0; i < 32; i++) { ++ DBG_ERROR("%2d %d %4x %x %x\n", ++ i, card->reg_type[i], card->reg_offset[i], ++ card->reg_value[i], card->reg_valueh[i]); ++ } ++} ++} ++#endif ++ ++static void slic_init_adapter(struct net_device *netdev, ++ struct pci_dev *pcidev, ++ const struct pci_device_id *pci_tbl_entry, ++ void __iomem *memaddr, int chip_idx) ++{ ++ ushort index; ++ pslic_handle_t pslic_handle; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(netdev); ++ ++/* ++ DBG_MSG("slicoss: %s (%s)\n netdev [%p]\n adapter[%p]\n " ++ "pcidev [%p]\n", __func__, netdev->name, netdev, adapter, pcidev);*/ ++/* adapter->pcidev = pcidev;*/ ++ adapter->vendid = pci_tbl_entry->vendor; ++ adapter->devid = pci_tbl_entry->device; ++ adapter->subsysid = pci_tbl_entry->subdevice; ++ adapter->busnumber = pcidev->bus->number; ++ adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F); ++ adapter->functionnumber = (pcidev->devfn & 0x7); ++ adapter->memorylength = pci_resource_len(pcidev, 0); ++ adapter->slic_regs = (p_slic_regs_t) memaddr; ++ adapter->irq = pcidev->irq; ++/* adapter->netdev = netdev;*/ ++ adapter->next_netdevice = head_netdevice; ++ head_netdevice = netdev; ++ adapter->chipid = chip_idx; ++ adapter->port = 0; /*adapter->functionnumber;*/ ++ adapter->cardindex = adapter->port; ++ adapter->memorybase = memaddr; ++ SLIC_INIT_SPINLOCK(adapter->upr_lock); ++ SLIC_INIT_SPINLOCK(adapter->bit64reglock); ++ SLIC_INIT_SPINLOCK(adapter->adapter_lock); ++ SLIC_INIT_SPINLOCK(adapter->reset_lock); ++ SLIC_INIT_SPINLOCK(adapter->handle_lock); ++ ++ adapter->card_size = 1; ++ /* ++ Initialize slic_handle array ++ */ ++ ASSERT(SLIC_CMDQ_MAXCMDS <= 0xFFFF); ++ /* ++ Start with 1. 0 is an invalid host handle. ++ */ ++ for (index = 1, pslic_handle = &adapter->slic_handles[1]; ++ index < SLIC_CMDQ_MAXCMDS; index++, pslic_handle++) { ++ ++ pslic_handle->token.handle_index = index; ++ pslic_handle->type = SLIC_HANDLE_FREE; ++ pslic_handle->next = adapter->pfree_slic_handles; ++ adapter->pfree_slic_handles = pslic_handle; ++ } ++/* ++ DBG_MSG(".........\nix[%d] phandle[%p] pfree[%p] next[%p]\n", ++ index, pslic_handle, adapter->pfree_slic_handles, pslic_handle->next);*/ ++ adapter->pshmem = (p_slic_shmem_t) pci_alloc_consistent(adapter->pcidev, ++ sizeof ++ (slic_shmem_t), ++ &adapter-> ++ phys_shmem); ++/* ++ DBG_MSG("slicoss: %s (%s)\n pshmem [%p]\n phys_shmem[%p]\n"\ ++ "slic_regs [%p]\n", __func__, netdev->name, adapter->pshmem, ++ (pvoid)adapter->phys_shmem, adapter->slic_regs); ++*/ ++ ASSERT(adapter->pshmem); ++ ++ SLIC_ZERO_MEMORY(adapter->pshmem, sizeof(slic_shmem_t)); ++ ++ return; ++} ++ ++int __devinit slic_entry_probe(struct pci_dev *pcidev, ++ const struct pci_device_id *pci_tbl_entry) ++{ ++ static int cards_found; ++ static int did_version; ++ int err; ++ struct net_device *netdev; ++ p_adapter_t adapter; ++ void __iomem *memmapped_ioaddr = NULL; ++ ulong32 status = 0; ++ ulong mmio_start = 0; ++ ulong mmio_len = 0; ++ p_sliccard_t card = NULL; ++ ++ DBG_MSG("slicoss: %s 2.6 VERSION ENTER jiffies[%lx] cpu %d\n", ++ __func__, jiffies, smp_processor_id()); ++ ++ slic_global.dynamic_intagg = dynamic_intagg; ++ ++ err = pci_enable_device(pcidev); ++ ++ DBG_MSG("Call pci_enable_device(%p) status[%x]\n", pcidev, err); ++ if (err) ++ return err; ++ ++ if (slic_debug > 0 && did_version++ == 0) { ++ printk(slic_banner); ++ printk(slic_proc_version); ++ } ++ ++ err = pci_set_dma_mask(pcidev, DMA_64BIT_MASK); ++ if (!err) { ++ DBG_MSG("pci_set_dma_mask(DMA_64BIT_MASK) successful\n"); ++ } else { ++ err = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); ++ if (err) { ++ DBG_MSG ++ ("No usable DMA configuration, aborting err[%x]\n", ++ err); ++ return err; ++ } ++ DBG_MSG("pci_set_dma_mask(DMA_32BIT_MASK) successful\n"); ++ } ++ ++ DBG_MSG("Call pci_request_regions\n"); ++ ++ err = pci_request_regions(pcidev, DRV_NAME); ++ if (err) { ++ DBG_MSG("pci_request_regions FAILED err[%x]\n", err); ++ return err; ++ } ++ ++ DBG_MSG("call pci_set_master\n"); ++ pci_set_master(pcidev); ++ ++ DBG_MSG("call alloc_etherdev\n"); ++ netdev = alloc_etherdev(sizeof(adapter_t)); ++ if (!netdev) { ++ err = -ENOMEM; ++ goto err_out_exit_slic_probe; ++ } ++ DBG_MSG("alloc_etherdev for slic netdev[%p]\n", netdev); ++ ++ SET_NETDEV_DEV(netdev, &pcidev->dev); ++ ++ pci_set_drvdata(pcidev, netdev); ++ adapter = netdev_priv(netdev); ++ adapter->netdev = netdev; ++ adapter->pcidev = pcidev; ++ ++ mmio_start = pci_resource_start(pcidev, 0); ++ mmio_len = pci_resource_len(pcidev, 0); ++ ++ DBG_MSG("slicoss: call ioremap(mmio_start[%lx], mmio_len[%lx])\n", ++ mmio_start, mmio_len); ++ ++/* memmapped_ioaddr = (ulong32)ioremap_nocache(mmio_start, mmio_len);*/ ++ memmapped_ioaddr = ioremap(mmio_start, mmio_len); ++ DBG_MSG("slicoss: %s MEMMAPPED_IOADDR [%p]\n", __func__, ++ memmapped_ioaddr); ++ if (!memmapped_ioaddr) { ++ DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", ++ __func__, mmio_len, mmio_start); ++ goto err_out_free_mmio_region; ++ } ++ ++ DBG_MSG ++ ("slicoss: %s found Alacritech SLICOSS PCI, MMIO at %p, "\ ++ "start[%lx] len[%lx], IRQ %d.\n", ++ __func__, memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq); ++ ++ slic_config_pci(pcidev); ++ ++ slic_init_driver(); ++ ++ slic_init_adapter(netdev, ++ pcidev, pci_tbl_entry, memmapped_ioaddr, cards_found); ++ ++ status = slic_card_locate(adapter); ++ if (status) { ++ DBG_ERROR("%s cannot locate card\n", __func__); ++ goto err_out_free_mmio_region; ++ } ++ ++ card = adapter->card; ++ ++ if (!adapter->allocated) { ++ card->adapters_allocated++; ++ adapter->allocated = 1; ++ } ++ ++ DBG_MSG("slicoss: %s card: %p\n", __func__, ++ adapter->card); ++ DBG_MSG("slicoss: %s card->adapter[%d] == [%p]\n", __func__, ++ (uint) adapter->port, adapter); ++ DBG_MSG("slicoss: %s card->adapters_allocated [%d]\n", __func__, ++ card->adapters_allocated); ++ DBG_MSG("slicoss: %s card->adapters_activated [%d]\n", __func__, ++ card->adapters_activated); ++ ++ status = slic_card_init(card, adapter); ++ ++ if (status != STATUS_SUCCESS) { ++ card->state = CARD_FAIL; ++ adapter->state = ADAPT_FAIL; ++ adapter->linkstate = LINK_DOWN; ++ DBG_ERROR("slic_card_init FAILED status[%x]\n", status); ++ } else { ++ slic_adapter_set_hwaddr(adapter); ++ } ++ ++ netdev->base_addr = (unsigned long)adapter->memorybase; ++ netdev->irq = adapter->irq; ++ netdev->open = slic_entry_open; ++ netdev->stop = slic_entry_halt; ++ netdev->hard_start_xmit = slic_xmit_start; ++ netdev->do_ioctl = slic_ioctl; ++ netdev->set_mac_address = slic_mac_set_address; ++#if SLIC_GET_STATS_ENABLED ++ netdev->get_stats = slic_get_stats; ++#endif ++ netdev->set_multicast_list = slic_mcast_set_list; ++ ++ slic_debug_adapter_create(adapter); ++ ++ strcpy(netdev->name, "eth%d"); ++ err = register_netdev(netdev); ++ if (err) { ++ DBG_ERROR("Cannot register net device, aborting.\n"); ++ goto err_out_unmap; ++ } ++ ++ DBG_MSG ++ ("slicoss: addr 0x%lx, irq %d, MAC addr "\ ++ "%02X:%02X:%02X:%02X:%02X:%02X\n", ++ mmio_start, /*pci_resource_start(pcidev, 0), */ pcidev->irq, ++ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], ++ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); ++ ++ cards_found++; ++ DBG_MSG("slicoss: %s EXIT status[%x] jiffies[%lx] cpu %d\n", ++ __func__, status, jiffies, smp_processor_id()); ++ ++ return status; ++ ++err_out_unmap: ++ iounmap(memmapped_ioaddr); ++ ++err_out_free_mmio_region: ++ release_mem_region(mmio_start, mmio_len); ++ ++err_out_exit_slic_probe: ++ DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __func__, jiffies, ++ smp_processor_id()); ++ ++ return -ENODEV; ++} ++ ++int slic_entry_open(struct net_device *dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ p_sliccard_t card = adapter->card; ++ ulong32 locked = 0; ++ int status; ++ ++ ASSERT(adapter); ++ ASSERT(card); ++ DBG_MSG ++ ("slicoss: %s adapter->activated[%d] card->adapters[%x] "\ ++ "allocd[%x]\n", __func__, adapter->activated, ++ card->adapters_activated, ++ card->adapters_allocated); ++ DBG_MSG ++ ("slicoss: %s (%s): [jiffies[%lx] cpu %d] dev[%p] adapt[%p] "\ ++ "port[%d] card[%p]\n", ++ __func__, adapter->netdev->name, jiffies, smp_processor_id(), ++ adapter->netdev, adapter, adapter->port, card); ++ ++ netif_stop_queue(adapter->netdev); ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ locked = 1; ++ if (!adapter->activated) { ++ card->adapters_activated++; ++ slic_global.num_slic_ports_active++; ++ adapter->activated = 1; ++ } ++ status = slic_if_init(adapter); ++ ++ if (status != STATUS_SUCCESS) { ++ if (adapter->activated) { ++ card->adapters_activated--; ++ slic_global.num_slic_ports_active--; ++ adapter->activated = 0; ++ } ++ if (locked) { ++ SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ locked = 0; ++ } ++ return status; ++ } ++ DBG_MSG("slicoss: %s set card->master[%p] adapter[%p]\n", __func__, ++ card->master, adapter); ++ if (!card->master) ++ card->master = adapter; ++#if SLIC_DUMP_ENABLED ++ if (!(card->dumpthread_running)) ++ init_waitqueue_head(&card->dump_wq); ++#endif ++ ++ if (locked) { ++ SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ locked = 0; ++ } ++#if SLIC_DUMP_ENABLED ++ if (!(card->dumpthread_running)) { ++ DBG_MSG("attempt to initialize dump thread\n"); ++ status = slic_init_dump_thread(card); ++ /* ++ Even if the dump thread fails, we will continue at this point ++ */ ++ } ++#endif ++ ++ return STATUS_SUCCESS; ++} ++ ++void __devexit slic_entry_remove(struct pci_dev *pcidev) ++{ ++ struct net_device *dev = pci_get_drvdata(pcidev); ++ ulong32 mmio_start = 0; ++ uint mmio_len = 0; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ p_sliccard_t card; ++ ++ ASSERT(adapter); ++ DBG_MSG("slicoss: %s ENTER dev[%p] adapter[%p]\n", __func__, dev, ++ adapter); ++ slic_adapter_freeresources(adapter); ++ slic_unmap_mmio_space(adapter); ++ DBG_MSG("slicoss: %s unregister_netdev\n", __func__); ++ unregister_netdev(dev); ++ ++ mmio_start = pci_resource_start(pcidev, 0); ++ mmio_len = pci_resource_len(pcidev, 0); ++ ++ DBG_MSG("slicoss: %s rel_region(0) start[%x] len[%x]\n", __func__, ++ mmio_start, mmio_len); ++ release_mem_region(mmio_start, mmio_len); ++ ++ DBG_MSG("slicoss: %s iounmap dev->base_addr[%x]\n", __func__, ++ (uint) dev->base_addr); ++ iounmap((void __iomem *)dev->base_addr); ++ ASSERT(adapter->card); ++ card = adapter->card; ++ ASSERT(card->adapters_allocated); ++ card->adapters_allocated--; ++ adapter->allocated = 0; ++ DBG_MSG ++ ("slicoss: %s init[%x] alloc[%x] card[%p] adapter[%p]\n", ++ __func__, card->adapters_activated, card->adapters_allocated, ++ card, adapter); ++ if (!card->adapters_allocated) { ++ p_sliccard_t curr_card = slic_global.slic_card; ++ if (curr_card == card) { ++ slic_global.slic_card = card->next; ++ } else { ++ while (curr_card->next != card) ++ curr_card = curr_card->next; ++ ASSERT(curr_card); ++ curr_card->next = card->next; ++ } ++ ASSERT(slic_global.num_slic_cards); ++ slic_global.num_slic_cards--; ++ slic_card_cleanup(card); ++ } ++ DBG_MSG("slicoss: %s deallocate device\n", __func__); ++ SLIC_DEALLOCATE_MEM(dev); ++ DBG_MSG("slicoss: %s EXIT\n", __func__); ++} ++ ++int slic_entry_halt(struct net_device *dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ p_sliccard_t card = adapter->card; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ ASSERT(card); ++ DBG_MSG("slicoss: %s (%s) ENTER\n", __func__, dev->name); ++ DBG_MSG("slicoss: %s (%s) actvtd[%d] alloc[%d] state[%x] adapt[%p]\n", ++ __func__, dev->name, card->adapters_activated, ++ card->adapters_allocated, card->state, adapter); ++ slic_if_stop_queue(adapter); ++ adapter->state = ADAPT_DOWN; ++ adapter->linkstate = LINK_DOWN; ++ adapter->upr_list = NULL; ++ adapter->upr_busy = 0; ++ adapter->devflags_prev = 0; ++ DBG_MSG("slicoss: %s (%s) set adapter[%p] state to ADAPT_DOWN(%d)\n", ++ __func__, dev->name, adapter, adapter->state); ++ ASSERT(card->adapter[adapter->cardindex] == adapter); ++ WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); ++ adapter->all_reg_writes++; ++ adapter->icr_reg_writes++; ++ slic_config_clear(adapter); ++ DBG_MSG("slicoss: %s (%s) dev[%p] adapt[%p] card[%p]\n", ++ __func__, dev->name, dev, adapter, card); ++ if (adapter->activated) { ++ card->adapters_activated--; ++ slic_global.num_slic_ports_active--; ++ adapter->activated = 0; ++ } ++#ifdef AUTOMATIC_RESET ++ WRITE_REG(slic_regs->slic_reset_iface, 0, FLUSH); ++#endif ++ /* ++ * Reset the adapter's rsp, cmd, and rcv queues ++ */ ++ slic_cmdq_reset(adapter); ++ slic_rspqueue_reset(adapter); ++ slic_rcvqueue_reset(adapter); ++ ++#ifdef AUTOMATIC_RESET ++ if (!card->adapters_activated) { ++ ++#if SLIC_DUMP_ENABLED ++ if (card->dumpthread_running) { ++ uint status; ++ DBG_MSG("attempt to terminate dump thread pid[%x]\n", ++ card->dump_task_id); ++ status = kill_proc(card->dump_task_id->pid, SIGKILL, 1); ++ ++ if (!status) { ++ int count = 10 * 100; ++ while (card->dumpthread_running && --count) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule_timeout(1); ++ } ++ ++ if (!count) { ++ DBG_MSG ++ ("slicmon thread cleanup FAILED \ ++ pid[%x]\n", ++ card->dump_task_id->pid); ++ } ++ } ++ } ++#endif ++ DBG_MSG("slicoss: %s (%s) initiate CARD_HALT\n", __func__, ++ dev->name); ++ ++ slic_card_init(card, adapter); ++ } ++#endif ++ ++ DBG_MSG("slicoss: %s (%s) EXIT\n", __func__, dev->name); ++ DBG_MSG("slicoss: %s EXIT\n", __func__); ++ SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ return STATUS_SUCCESS; ++} ++ ++int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ ASSERT(rq); ++/* ++ DBG_MSG("slicoss: %s cmd[%x] rq[%p] dev[%p]\n", __func__, cmd, rq, dev); ++*/ ++ switch (cmd) { ++ case SIOCSLICSETINTAGG: ++ { ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ ulong32 data[7]; ++ ulong32 intagg; ++ ++ if (copy_from_user(data, rq->ifr_data, 28)) { ++ DBG_ERROR ++ ("copy_from_user FAILED getting initial \ ++ params\n"); ++ return -EFAULT; ++ } ++ intagg = data[0]; ++ printk(KERN_EMERG ++ "%s: set interrupt aggregation to %d\n", ++ __func__, intagg); ++ slic_intagg_set(adapter, intagg); ++ return 0; ++ } ++#ifdef SLIC_USER_REQUEST_DUMP_ENABLED ++ case SIOCSLICDUMPCARD: ++ { ++ p_adapter_t adapter = (p_adapter_t) dev->priv; ++ p_sliccard_t card; ++ ++ ASSERT(adapter); ++ ASSERT(adapter->card) ++ card = adapter->card; ++ ++ DBG_IOCTL("slic_ioctl SIOCSLIC_DUMP_CARD\n"); ++ ++ if (card->dump_requested == SLIC_DUMP_DONE) { ++ printk(SLICLEVEL ++ "SLIC Card dump to be overwritten\n"); ++ card->dump_requested = SLIC_DUMP_REQUESTED; ++ } else if ((card->dump_requested == SLIC_DUMP_REQUESTED) ++ || (card->dump_requested == ++ SLIC_DUMP_IN_PROGRESS)) { ++ printk(SLICLEVEL ++ "SLIC Card dump Requested but already \ ++ in progress... ignore\n"); ++ } else { ++ printk(SLICLEVEL ++ "SLIC Card #%d Dump Requested\n", ++ card->cardnum); ++ card->dump_requested = SLIC_DUMP_REQUESTED; ++ } ++ return 0; ++ } ++#endif ++ ++#ifdef SLIC_TRACE_DUMP_ENABLED ++ case SIOCSLICTRACEDUMP: ++ { ++ ulong data[7]; ++ ulong value; ++ ++ DBG_IOCTL("slic_ioctl SIOCSLIC_TRACE_DUMP\n"); ++ ++ if (copy_from_user(data, rq->ifr_data, 28)) { ++ PRINT_ERROR ++ ("slic: copy_from_user FAILED getting \ ++ initial simba param\n"); ++ return -EFAULT; ++ } ++ ++ value = data[0]; ++ if (tracemon_request == SLIC_DUMP_DONE) { ++ PRINT_ERROR ++ ("ATK Diagnostic Trace Dump Requested\n"); ++ tracemon_request = SLIC_DUMP_REQUESTED; ++ tracemon_request_type = value; ++ tracemon_timestamp = jiffies; ++ } else if ((tracemon_request == SLIC_DUMP_REQUESTED) || ++ (tracemon_request == ++ SLIC_DUMP_IN_PROGRESS)) { ++ PRINT_ERROR ++ ("ATK Diagnostic Trace Dump Requested but \ ++ already in progress... ignore\n"); ++ } else { ++ PRINT_ERROR ++ ("ATK Diagnostic Trace Dump Requested\n"); ++ tracemon_request = SLIC_DUMP_REQUESTED; ++ tracemon_request_type = value; ++ tracemon_timestamp = jiffies; ++ } ++ return 0; ++ } ++#endif ++#if SLIC_ETHTOOL_SUPPORT ++ case SIOCETHTOOL: ++ { ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct ethtool_cmd data; ++ struct ethtool_cmd ecmd; ++ ++ ASSERT(adapter); ++/* DBG_MSG("slicoss: %s SIOCETHTOOL\n", __func__); */ ++ if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd))) ++ return -EFAULT; ++ ++ if (ecmd.cmd == ETHTOOL_GSET) { ++ data.supported = ++ (SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++ SUPPORTED_Autoneg | SUPPORTED_MII); ++ data.port = PORT_MII; ++ data.transceiver = XCVR_INTERNAL; ++ data.phy_address = 0; ++ if (adapter->linkspeed == LINK_100MB) ++ data.speed = SPEED_100; ++ else if (adapter->linkspeed == LINK_10MB) ++ data.speed = SPEED_10; ++ else ++ data.speed = 0; ++ ++ if (adapter->linkduplex == LINK_FULLD) ++ data.duplex = DUPLEX_FULL; ++ else ++ data.duplex = DUPLEX_HALF; ++ ++ data.autoneg = AUTONEG_ENABLE; ++ data.maxtxpkt = 1; ++ data.maxrxpkt = 1; ++ if (copy_to_user ++ (rq->ifr_data, &data, sizeof(data))) ++ return -EFAULT; ++ ++ } else if (ecmd.cmd == ETHTOOL_SSET) { ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (adapter->linkspeed == LINK_100MB) ++ data.speed = SPEED_100; ++ else if (adapter->linkspeed == LINK_10MB) ++ data.speed = SPEED_10; ++ else ++ data.speed = 0; ++ ++ if (adapter->linkduplex == LINK_FULLD) ++ data.duplex = DUPLEX_FULL; ++ else ++ data.duplex = DUPLEX_HALF; ++ ++ data.autoneg = AUTONEG_ENABLE; ++ data.maxtxpkt = 1; ++ data.maxrxpkt = 1; ++ if ((ecmd.speed != data.speed) || ++ (ecmd.duplex != data.duplex)) { ++ ulong32 speed; ++ ulong32 duplex; ++ ++ if (ecmd.speed == SPEED_10) { ++ speed = 0; ++ SLIC_DISPLAY ++ ("%s: slic ETHTOOL set \ ++ link speed==10MB", ++ dev->name); ++ } else { ++ speed = PCR_SPEED_100; ++ SLIC_DISPLAY ++ ("%s: slic ETHTOOL set \ ++ link speed==100MB", ++ dev->name); ++ } ++ if (ecmd.duplex == DUPLEX_FULL) { ++ duplex = PCR_DUPLEX_FULL; ++ SLIC_DISPLAY ++ (": duplex==FULL\n"); ++ } else { ++ duplex = 0; ++ SLIC_DISPLAY ++ (": duplex==HALF\n"); ++ } ++ slic_link_config(adapter, ++ speed, duplex); ++ slic_link_event_handler(adapter); ++ } ++ } ++ return 0; ++ } ++#endif ++ default: ++/* DBG_MSG("slicoss: %s UNSUPPORTED[%x]\n", __func__, cmd); */ ++ return -EOPNOTSUPP; ++ } ++} ++ ++#define XMIT_FAIL_LINK_STATE 1 ++#define XMIT_FAIL_ZERO_LENGTH 2 ++#define XMIT_FAIL_HOSTCMD_FAIL 3 ++ ++static void slic_xmit_build_request(p_adapter_t adapter, ++ p_slic_hostcmd_t hcmd, struct sk_buff *skb) ++{ ++ p_slic_host64_cmd_t ihcmd; ++ ulong phys_addr; ++ ++ ihcmd = &hcmd->cmd64; ++ ++ ihcmd->flags = (adapter->port << IHFLG_IFSHFT); ++ ihcmd->command = IHCMD_XMT_REQ; ++ ihcmd->u.slic_buffers.totlen = skb->len; ++ phys_addr = SLIC_GET_DMA_ADDRESS_WRITE(adapter, skb->data, skb->len); ++ ihcmd->u.slic_buffers.bufs[0].paddrl = SLIC_GET_ADDR_LOW(phys_addr); ++ ihcmd->u.slic_buffers.bufs[0].paddrh = SLIC_GET_ADDR_HIGH(phys_addr); ++ ihcmd->u.slic_buffers.bufs[0].length = skb->len; ++#if defined(CONFIG_X86_64) ++ hcmd->cmdsize = (ulong32) ((((ulong64)&ihcmd->u.slic_buffers.bufs[1] - ++ (ulong64) hcmd) + 31) >> 5); ++#elif defined(CONFIG_X86) ++ hcmd->cmdsize = ((((ulong32) &ihcmd->u.slic_buffers.bufs[1] - ++ (ulong32) hcmd) + 31) >> 5); ++#else ++ Stop Compilation; ++#endif ++} ++ ++#define NORMAL_ETHFRAME 0 ++ ++int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) ++{ ++ p_sliccard_t card; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ p_slic_hostcmd_t hcmd = NULL; ++ ulong32 status = 0; ++ ulong32 skbtype = NORMAL_ETHFRAME; ++ pvoid offloadcmd = NULL; ++ ++ card = adapter->card; ++ ASSERT(card); ++/* ++ DBG_ERROR("xmit_start (%s) ENTER skb[%p] len[%d] linkstate[%x] state[%x]\n", ++ adapter->netdev->name, skb, skb->len, adapter->linkstate, ++ adapter->state); ++*/ ++ if ((adapter->linkstate != LINK_UP) || ++ (adapter->state != ADAPT_UP) || (card->state != CARD_UP)) { ++ status = XMIT_FAIL_LINK_STATE; ++ goto xmit_fail; ++ ++ } else if (skb->len == 0) { ++ status = XMIT_FAIL_ZERO_LENGTH; ++ goto xmit_fail; ++ } ++ ++ if (skbtype == NORMAL_ETHFRAME) { ++ hcmd = slic_cmdq_getfree(adapter); ++ if (!hcmd) { ++ adapter->xmitq_full = 1; ++ status = XMIT_FAIL_HOSTCMD_FAIL; ++ goto xmit_fail; ++ } ++ ASSERT(hcmd->pslic_handle); ++ ASSERT(hcmd->cmd64.hosthandle == ++ hcmd->pslic_handle->token.handle_token); ++ hcmd->skb = skb; ++ hcmd->busy = 1; ++ hcmd->type = SLIC_CMD_DUMB; ++ if (skbtype == NORMAL_ETHFRAME) ++ slic_xmit_build_request(adapter, hcmd, skb); ++ } ++ adapter->stats.tx_packets++; ++ adapter->stats.tx_bytes += skb->len; ++ ++#ifdef DEBUG_DUMP ++ if (adapter->kill_card) { ++ p_slic_host64_cmd_t ihcmd; ++ ++ ihcmd = &hcmd->cmd64; ++ ++ ihcmd->flags |= 0x40; ++ adapter->kill_card = 0; /* only do this once */ ++ } ++#endif ++ if (hcmd->paddrh == 0) { ++ WRITE_REG(adapter->slic_regs->slic_cbar, ++ (hcmd->paddrl | hcmd->cmdsize), DONT_FLUSH); ++ } else { ++ WRITE_REG64(adapter, ++ adapter->slic_regs->slic_cbar64, ++ (hcmd->paddrl | hcmd->cmdsize), ++ adapter->slic_regs->slic_addr_upper, ++ hcmd->paddrh, DONT_FLUSH); ++ } ++xmit_done: ++ return 0; ++xmit_fail: ++ slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status); ++ goto xmit_done; ++} ++ ++void slic_xmit_fail(p_adapter_t adapter, ++ struct sk_buff *skb, ++ pvoid cmd, ulong32 skbtype, ulong32 status) ++{ ++ if (adapter->xmitq_full) ++ slic_if_stop_queue(adapter); ++ if ((cmd == NULL) && (status <= XMIT_FAIL_HOSTCMD_FAIL)) { ++ switch (status) { ++ case XMIT_FAIL_LINK_STATE: ++ DBG_ERROR ++ ("(%s) reject xmit skb[%p: %x] linkstate[%s] \ ++ adapter[%s:%d] card[%s:%d]\n", ++ adapter->netdev->name, skb, skb->pkt_type, ++ SLIC_LINKSTATE(adapter->linkstate), ++ SLIC_ADAPTER_STATE(adapter->state), adapter->state, ++ SLIC_CARD_STATE(adapter->card->state), ++ adapter->card->state); ++ break; ++ case XMIT_FAIL_ZERO_LENGTH: ++ DBG_ERROR ++ ("xmit_start skb->len == 0 skb[%p] type[%x]!!!! \n", ++ skb, skb->pkt_type); ++ break; ++ case XMIT_FAIL_HOSTCMD_FAIL: ++ DBG_ERROR ++ ("xmit_start skb[%p] type[%x] No host commands \ ++ available !!!! \n", ++ skb, skb->pkt_type); ++ break; ++ default: ++ ASSERT(0); ++ } ++ } ++ dev_kfree_skb(skb); ++ adapter->stats.tx_dropped++; ++} ++ ++void slic_xmit_timeout(struct net_device *dev) ++{ ++ p_sliccard_t card; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ ulong32 i; ++ ++ ASSERT(adapter); ++ card = adapter->card; ++ ASSERT(card); ++ for (i = 0; i < card->card_size; i++) { ++ if (card->adapter[i]) ++ slic_if_stop_queue(card->adapter[i]); ++ } ++ if (!card->reset_in_progress) { ++ DBG_ERROR ++ ("%s card[%p] state[%x] adapter[%p] port[%d] state[%x]\n", ++ __func__, card, card->state, adapter, adapter->port, ++ adapter->state); ++ slic_card_reset(adapter); ++ } ++} ++ ++void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf) ++{ ++ p_slic_hddr_wds hdr = (p_slic_hddr_wds) rcvbuf->data; ++ ++ if (adapter->devid != SLIC_1GB_DEVICE_ID) { ++ if (hdr->frame_status14 & VRHSTAT_802OE) ++ adapter->if_events.oflow802++; ++ if (hdr->frame_status14 & VRHSTAT_TPOFLO) ++ adapter->if_events.Tprtoflow++; ++ if (hdr->frame_status_b14 & VRHSTATB_802UE) ++ adapter->if_events.uflow802++; ++ if (hdr->frame_status_b14 & VRHSTATB_RCVE) { ++ adapter->if_events.rcvearly++; ++ adapter->stats.rx_fifo_errors++; ++ } ++ if (hdr->frame_status_b14 & VRHSTATB_BUFF) { ++ adapter->if_events.Bufov++; ++ adapter->stats.rx_over_errors++; ++ } ++ if (hdr->frame_status_b14 & VRHSTATB_CARRE) { ++ adapter->if_events.Carre++; ++ adapter->stats.tx_carrier_errors++; ++ } ++ if (hdr->frame_status_b14 & VRHSTATB_LONGE) ++ adapter->if_events.Longe++; ++ if (hdr->frame_status_b14 & VRHSTATB_PREA) ++ adapter->if_events.Invp++; ++ if (hdr->frame_status_b14 & VRHSTATB_CRC) { ++ adapter->if_events.Crc++; ++ adapter->stats.rx_crc_errors++; ++ } ++ if (hdr->frame_status_b14 & VRHSTATB_DRBL) ++ adapter->if_events.Drbl++; ++ if (hdr->frame_status_b14 & VRHSTATB_CODE) ++ adapter->if_events.Code++; ++ if (hdr->frame_status_b14 & VRHSTATB_TPCSUM) ++ adapter->if_events.TpCsum++; ++ if (hdr->frame_status_b14 & VRHSTATB_TPHLEN) ++ adapter->if_events.TpHlen++; ++ if (hdr->frame_status_b14 & VRHSTATB_IPCSUM) ++ adapter->if_events.IpCsum++; ++ if (hdr->frame_status_b14 & VRHSTATB_IPLERR) ++ adapter->if_events.IpLen++; ++ if (hdr->frame_status_b14 & VRHSTATB_IPHERR) ++ adapter->if_events.IpHlen++; ++ } else { ++ if (hdr->frame_statusGB & VGBSTAT_XPERR) { ++ ulong32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT; ++ ++ if (xerr == VGBSTAT_XCSERR) ++ adapter->if_events.TpCsum++; ++ if (xerr == VGBSTAT_XUFLOW) ++ adapter->if_events.Tprtoflow++; ++ if (xerr == VGBSTAT_XHLEN) ++ adapter->if_events.TpHlen++; ++ } ++ if (hdr->frame_statusGB & VGBSTAT_NETERR) { ++ ulong32 nerr = ++ (hdr-> ++ frame_statusGB >> VGBSTAT_NERRSHFT) & ++ VGBSTAT_NERRMSK; ++ if (nerr == VGBSTAT_NCSERR) ++ adapter->if_events.IpCsum++; ++ if (nerr == VGBSTAT_NUFLOW) ++ adapter->if_events.IpLen++; ++ if (nerr == VGBSTAT_NHLEN) ++ adapter->if_events.IpHlen++; ++ } ++ if (hdr->frame_statusGB & VGBSTAT_LNKERR) { ++ ulong32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK; ++ ++ if (lerr == VGBSTAT_LDEARLY) ++ adapter->if_events.rcvearly++; ++ if (lerr == VGBSTAT_LBOFLO) ++ adapter->if_events.Bufov++; ++ if (lerr == VGBSTAT_LCODERR) ++ adapter->if_events.Code++; ++ if (lerr == VGBSTAT_LDBLNBL) ++ adapter->if_events.Drbl++; ++ if (lerr == VGBSTAT_LCRCERR) ++ adapter->if_events.Crc++; ++ if (lerr == VGBSTAT_LOFLO) ++ adapter->if_events.oflow802++; ++ if (lerr == VGBSTAT_LUFLO) ++ adapter->if_events.uflow802++; ++ } ++ } ++ return; ++} ++ ++#define TCP_OFFLOAD_FRAME_PUSHFLAG 0x10000000 ++#define M_FAST_PATH 0x0040 ++ ++void slic_rcv_handler(p_adapter_t adapter) ++{ ++ struct sk_buff *skb; ++ p_slic_rcvbuf_t rcvbuf; ++ ulong32 frames = 0; ++ ++ while ((skb = slic_rcvqueue_getnext(adapter))) { ++ ulong32 rx_bytes; ++ ++ ASSERT(skb->head); ++ rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ adapter->card->events++; ++ if (rcvbuf->status & IRHDDR_ERR) { ++ adapter->rx_errors++; ++ slic_rcv_handle_error(adapter, rcvbuf); ++ slic_rcvqueue_reinsert(adapter, skb); ++ continue; ++ } ++ ++ if (!slic_mac_filter(adapter, (p_ether_header) rcvbuf->data)) { ++#if 0 ++ DBG_MSG ++ ("slicoss: %s (%s) drop frame due to mac filter\n", ++ __func__, adapter->netdev->name); ++#endif ++ slic_rcvqueue_reinsert(adapter, skb); ++ continue; ++ } ++ skb_pull(skb, SLIC_RCVBUF_HEADSIZE); ++ rx_bytes = (rcvbuf->length & IRHDDR_FLEN_MSK); ++ skb_put(skb, rx_bytes); ++ adapter->stats.rx_packets++; ++ adapter->stats.rx_bytes += rx_bytes; ++#if SLIC_OFFLOAD_IP_CHECKSUM ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++#endif ++ ++ skb->dev = adapter->netdev; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ netif_rx(skb); ++ ++ ++frames; ++#if SLIC_INTERRUPT_PROCESS_LIMIT ++ if (frames >= SLIC_RCVQ_MAX_PROCESS_ISR) { ++ adapter->rcv_interrupt_yields++; ++ break; ++ } ++#endif ++ } ++ adapter->max_isr_rcvs = max(adapter->max_isr_rcvs, frames); ++} ++ ++void slic_xmit_complete(p_adapter_t adapter) ++{ ++ p_slic_hostcmd_t hcmd; ++ p_slic_rspbuf_t rspbuf; ++ ulong32 frames = 0; ++ slic_handle_word_t slic_handle_word; ++ ++ do { ++ rspbuf = slic_rspqueue_getnext(adapter); ++ if (!rspbuf) ++ break; ++ adapter->xmit_completes++; ++ adapter->card->events++; ++ /* ++ Get the complete host command buffer ++ */ ++ slic_handle_word.handle_token = rspbuf->hosthandle; ++ ASSERT(slic_handle_word.handle_index); ++ ASSERT(slic_handle_word.handle_index <= SLIC_CMDQ_MAXCMDS); ++ hcmd = ++ (p_slic_hostcmd_t) adapter->slic_handles[slic_handle_word. ++ handle_index]. ++ address; ++/* hcmd = (p_slic_hostcmd_t) rspbuf->hosthandle; */ ++ ASSERT(hcmd); ++ ASSERT(hcmd->pslic_handle == ++ &adapter->slic_handles[slic_handle_word.handle_index]); ++/* ++ DBG_ERROR("xmit_complete (%s) hcmd[%p] hosthandle[%x]\n", ++ adapter->netdev->name, hcmd, hcmd->cmd64.hosthandle); ++ DBG_ERROR(" skb[%p] len %d hcmdtype[%x]\n", hcmd->skb, ++ hcmd->skb->len, hcmd->type); ++*/ ++ if (hcmd->type == SLIC_CMD_DUMB) { ++ if (hcmd->skb) ++ dev_kfree_skb_irq(hcmd->skb); ++ slic_cmdq_putdone_irq(adapter, hcmd); ++ } ++ rspbuf->status = 0; ++ rspbuf->hosthandle = 0; ++ frames++; ++ } while (1); ++ adapter->max_isr_xmits = max(adapter->max_isr_xmits, frames); ++} ++ ++static irqreturn_t slic_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = (struct net_device *) dev_id; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ ulong32 isr; ++ ++ if ((adapter->pshmem) && (adapter->pshmem->isr)) { ++ WRITE_REG(adapter->slic_regs->slic_icr, ICR_INT_MASK, FLUSH); ++ isr = adapter->isrcopy = adapter->pshmem->isr; ++ adapter->pshmem->isr = 0; ++ adapter->num_isrs++; ++ switch (adapter->card->state) { ++ case CARD_UP: ++ if (isr & ~ISR_IO) { ++ if (isr & ISR_ERR) { ++ adapter->error_interrupts++; ++ if (isr & ISR_RMISS) { ++ int count; ++ int pre_count; ++ int errors; ++ ++ p_slic_rcvqueue_t rcvq = ++ &adapter->rcvqueue; ++ ++ adapter-> ++ error_rmiss_interrupts++; ++ if (!rcvq->errors) ++ rcv_count = rcvq->count; ++ pre_count = rcvq->count; ++ errors = rcvq->errors; ++ ++ while (rcvq->count < ++ SLIC_RCVQ_FILLTHRESH) { ++ count = ++ slic_rcvqueue_fill ++ (adapter); ++ if (!count) ++ break; ++ } ++ DBG_MSG ++ ("(%s): [%x] ISR_RMISS \ ++ initial[%x] pre[%x] \ ++ errors[%x] \ ++ post_count[%x]\n", ++ adapter->netdev->name, ++ isr, rcv_count, pre_count, ++ errors, rcvq->count); ++ } else if (isr & ISR_XDROP) { ++ DBG_ERROR ++ ("isr & ISR_ERR [%x] \ ++ ISR_XDROP \n", ++ isr); ++ } else { ++ DBG_ERROR ++ ("isr & ISR_ERR [%x]\n", ++ isr); ++ } ++ } ++ ++ if (isr & ISR_LEVENT) { ++ /*DBG_MSG("%s (%s) ISR_LEVENT \n", ++ __func__, adapter->netdev->name);*/ ++ adapter->linkevent_interrupts++; ++ slic_link_event_handler(adapter); ++ } ++ ++ if ((isr & ISR_UPC) || ++ (isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) { ++ adapter->upr_interrupts++; ++ slic_upr_request_complete(adapter, isr); ++ } ++ } ++ ++ if (isr & ISR_RCV) { ++ adapter->rcv_interrupts++; ++ slic_rcv_handler(adapter); ++ } ++ ++ if (isr & ISR_CMD) { ++ adapter->xmit_interrupts++; ++ slic_xmit_complete(adapter); ++ } ++ break; ++ ++ case CARD_DOWN: ++ if ((isr & ISR_UPC) || ++ (isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) { ++ adapter->upr_interrupts++; ++ slic_upr_request_complete(adapter, isr); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ adapter->isrcopy = 0; ++ adapter->all_reg_writes += 2; ++ adapter->isr_reg_writes++; ++ WRITE_REG(adapter->slic_regs->slic_isr, 0, FLUSH); ++ } else { ++ adapter->false_interrupts++; ++ } ++ return IRQ_HANDLED; ++} ++ ++/* ++ * slic_link_event_handler - ++ * ++ * Initiate a link configuration sequence. The link configuration begins ++ * by issuing a READ_LINK_STATUS command to the Utility Processor on the ++ * SLIC. Since the command finishes asynchronously, the slic_upr_comlete ++ * routine will follow it up witha UP configuration write command, which ++ * will also complete asynchronously. ++ * ++ */ ++void slic_link_event_handler(p_adapter_t adapter) ++{ ++ int status; ++ p_slic_shmem_t pshmem; ++ ++ if (adapter->state != ADAPT_UP) { ++ /* Adapter is not operational. Ignore. */ ++ return; ++ } ++ ++ pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ ++#if defined(CONFIG_X86_64) ++/* ++ DBG_MSG("slic_event_handler pshmem->linkstatus[%x] pshmem[%p]\n \ ++ &linkstatus[%p] &isr[%p]\n", adapter->pshmem->linkstatus, pshmem, ++ &pshmem->linkstatus, &pshmem->isr); ++*/ ++ status = slic_upr_request(adapter, ++ SLIC_UPR_RLSR, ++ SLIC_GET_ADDR_LOW(&pshmem->linkstatus), ++ SLIC_GET_ADDR_HIGH(&pshmem->linkstatus), ++ 0, 0); ++#elif defined(CONFIG_X86) ++ status = slic_upr_request(adapter, SLIC_UPR_RLSR, ++ (ulong32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */ ++ 0, 0, 0); ++#else ++ Stop compilation; ++#endif ++ ASSERT((status == STATUS_SUCCESS) || (status == STATUS_PENDING)); ++} ++ ++void slic_init_cleanup(p_adapter_t adapter) ++{ ++ DBG_MSG("slicoss: %s ENTER adapter[%p] ", __func__, adapter); ++ if (adapter->intrregistered) { ++ DBG_MSG("FREE_IRQ "); ++ adapter->intrregistered = 0; ++ free_irq(adapter->netdev->irq, adapter->netdev); ++ ++ } ++ if (adapter->pshmem) { ++ DBG_MSG("FREE_SHMEM "); ++ DBG_MSG("adapter[%p] port %d pshmem[%p] FreeShmem ", ++ adapter, adapter->port, (pvoid) adapter->pshmem); ++ pci_free_consistent(adapter->pcidev, ++ sizeof(slic_shmem_t), ++ adapter->pshmem, adapter->phys_shmem); ++ adapter->pshmem = NULL; ++ adapter->phys_shmem = (dma_addr_t) NULL; ++ } ++#if SLIC_GET_STATS_TIMER_ENABLED ++ if (adapter->statstimerset) { ++ DBG_MSG("statstimer "); ++ adapter->statstimerset = 0; ++ del_timer(&adapter->statstimer); ++ } ++#endif ++#if !SLIC_DUMP_ENABLED && SLIC_PING_TIMER_ENABLED ++/*#if SLIC_DUMP_ENABLED && SLIC_PING_TIMER_ENABLED*/ ++ if (adapter->pingtimerset) { ++ DBG_MSG("pingtimer "); ++ adapter->pingtimerset = 0; ++ del_timer(&adapter->pingtimer); ++ } ++#endif ++ slic_rspqueue_free(adapter); ++ slic_cmdq_free(adapter); ++ slic_rcvqueue_free(adapter); ++ ++ DBG_MSG("\n"); ++} ++ ++#if SLIC_GET_STATS_ENABLED ++struct net_device_stats *slic_get_stats(struct net_device *dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct net_device_stats *stats; ++ ++ ASSERT(adapter); ++ stats = &adapter->stats; ++ stats->collisions = adapter->slic_stats.iface.xmit_collisions; ++ stats->rx_errors = adapter->slic_stats.iface.rcv_errors; ++ stats->tx_errors = adapter->slic_stats.iface.xmt_errors; ++ stats->rx_missed_errors = adapter->slic_stats.iface.rcv_discards; ++ stats->tx_heartbeat_errors = 0; ++ stats->tx_aborted_errors = 0; ++ stats->tx_window_errors = 0; ++ stats->tx_fifo_errors = 0; ++ stats->rx_frame_errors = 0; ++ stats->rx_length_errors = 0; ++ return &adapter->stats; ++} ++#endif ++ ++/* ++ * Allocate a mcast_address structure to hold the multicast address. ++ * Link it in. ++ */ ++int slic_mcast_add_list(p_adapter_t adapter, pchar address) ++{ ++ p_mcast_address_t mcaddr, mlist; ++ boolean equaladdr; ++ ++ /* Check to see if it already exists */ ++ mlist = adapter->mcastaddrs; ++ while (mlist) { ++ ETHER_EQ_ADDR(mlist->address, address, equaladdr); ++ if (equaladdr) ++ return STATUS_SUCCESS; ++ mlist = mlist->next; ++ } ++ ++ /* Doesn't already exist. Allocate a structure to hold it */ ++ mcaddr = SLIC_ALLOCATE_MEM(sizeof(mcast_address_t), GFP_ATOMIC); ++ if (mcaddr == NULL) ++ return 1; ++ ++ memcpy(mcaddr->address, address, 6); ++ ++ mcaddr->next = adapter->mcastaddrs; ++ adapter->mcastaddrs = mcaddr; ++ ++ return STATUS_SUCCESS; ++} ++ ++/* ++ * Functions to obtain the CRC corresponding to the destination mac address. ++ * This is a standard ethernet CRC in that it is a 32-bit, reflected CRC using ++ * the polynomial: ++ * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + ++ * x^4 + x^2 + x^1. ++ * ++ * After the CRC for the 6 bytes is generated (but before the value is ++ * complemented), ++ * we must then transpose the value and return bits 30-23. ++ * ++ */ ++static u32 slic_crc_table[256]; /* Table of CRCs for all possible byte values */ ++static u32 slic_crc_init; /* Is table initialized */ ++ ++/* ++ * Contruct the CRC32 table ++ */ ++void slic_mcast_init_crc32(void) ++{ ++ ulong32 c; /* CRC shit reg */ ++ ulong32 e = 0; /* Poly X-or pattern */ ++ int i; /* counter */ ++ int k; /* byte being shifted into crc */ ++ ++ static int p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 }; ++ ++ for (i = 0; i < sizeof(p) / sizeof(int); i++) ++ e |= 1L << (31 - p[i]); ++ ++ for (i = 1; i < 256; i++) { ++ c = i; ++ for (k = 8; k; k--) ++ c = c & 1 ? (c >> 1) ^ e : c >> 1; ++ slic_crc_table[i] = c; ++ } ++} ++ ++/* ++ * Return the MAC hast as described above. ++ */ ++uchar slic_mcast_get_mac_hash(pchar macaddr) ++{ ++ ulong32 crc; ++ pchar p; ++ int i; ++ uchar machash = 0; ++ ++ if (!slic_crc_init) { ++ slic_mcast_init_crc32(); ++ slic_crc_init = 1; ++ } ++ ++ crc = 0xFFFFFFFF; /* Preload shift register, per crc-32 spec */ ++ for (i = 0, p = macaddr; i < 6; ++p, ++i) ++ crc = (crc >> 8) ^ slic_crc_table[(crc ^ *p) & 0xFF]; ++ ++ /* Return bits 1-8, transposed */ ++ for (i = 1; i < 9; i++) ++ machash |= (((crc >> i) & 1) << (8 - i)); ++ ++ return machash; ++} ++ ++void slic_mcast_set_bit(p_adapter_t adapter, pchar address) ++{ ++ uchar crcpoly; ++ ++ /* Get the CRC polynomial for the mac address */ ++ crcpoly = slic_mcast_get_mac_hash(address); ++ ++ /* We only have space on the SLIC for 64 entries. Lop ++ * off the top two bits. (2^6 = 64) ++ */ ++ crcpoly &= 0x3F; ++ ++ /* OR in the new bit into our 64 bit mask. */ ++ adapter->mcastmask |= (ulong64) 1 << crcpoly; ++} ++ ++void slic_mcast_set_list(struct net_device *dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ int status = STATUS_SUCCESS; ++ int i; ++ pchar addresses; ++ struct dev_mc_list *mc_list = dev->mc_list; ++ int mc_count = dev->mc_count; ++ ++ ASSERT(adapter); ++ ++ for (i = 1; i <= mc_count; i++) { ++ addresses = (pchar) &mc_list->dmi_addr; ++ if (mc_list->dmi_addrlen == 6) { ++ status = slic_mcast_add_list(adapter, addresses); ++ if (status != STATUS_SUCCESS) ++ break; ++ } else { ++ status = -EINVAL; ++ break; ++ } ++ slic_mcast_set_bit(adapter, addresses); ++ mc_list = mc_list->next; ++ } ++ ++ DBG_MSG("%s a->devflags_prev[%x] dev->flags[%x] status[%x]\n", ++ __func__, adapter->devflags_prev, dev->flags, status); ++ if (adapter->devflags_prev != dev->flags) { ++ adapter->macopts = MAC_DIRECTED; ++ if (dev->flags) { ++ if (dev->flags & IFF_BROADCAST) ++ adapter->macopts |= MAC_BCAST; ++ if (dev->flags & IFF_PROMISC) ++ adapter->macopts |= MAC_PROMISC; ++ if (dev->flags & IFF_ALLMULTI) ++ adapter->macopts |= MAC_ALLMCAST; ++ if (dev->flags & IFF_MULTICAST) ++ adapter->macopts |= MAC_MCAST; ++ } ++ adapter->devflags_prev = dev->flags; ++ DBG_MSG("%s call slic_config_set adapter->macopts[%x]\n", ++ __func__, adapter->macopts); ++ slic_config_set(adapter, TRUE); ++ } else { ++ if (status == STATUS_SUCCESS) ++ slic_mcast_set_mask(adapter); ++ } ++ return; ++} ++ ++void slic_mcast_set_mask(p_adapter_t adapter) ++{ ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ DBG_MSG("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__, ++ adapter->netdev->name, (uint) adapter->macopts, ++ adapter->mcastmask); ++ ++ if (adapter->macopts & (MAC_ALLMCAST | MAC_PROMISC)) { ++ /* Turn on all multicast addresses. We have to do this for ++ * promiscuous mode as well as ALLMCAST mode. It saves the ++ * Microcode from having to keep state about the MAC ++ * configuration. ++ */ ++/* DBG_MSG("slicoss: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n\ ++ SLUT MODE!!!\n",__func__); */ ++ WRITE_REG(slic_regs->slic_mcastlow, 0xFFFFFFFF, FLUSH); ++ WRITE_REG(slic_regs->slic_mcasthigh, 0xFFFFFFFF, FLUSH); ++/* DBG_MSG("%s (%s) WRITE to slic_regs slic_mcastlow&high 0xFFFFFFFF\n", ++ _func__, adapter->netdev->name); */ ++ } else { ++ /* Commit our multicast mast to the SLIC by writing to the ++ * multicast address mask registers ++ */ ++ DBG_MSG("%s (%s) WRITE mcastlow[%x] mcasthigh[%x]\n", ++ __func__, adapter->netdev->name, ++ ((ulong) (adapter->mcastmask & 0xFFFFFFFF)), ++ ((ulong) ((adapter->mcastmask >> 32) & 0xFFFFFFFF))); ++ ++ WRITE_REG(slic_regs->slic_mcastlow, ++ (ulong32) (adapter->mcastmask & 0xFFFFFFFF), FLUSH); ++ WRITE_REG(slic_regs->slic_mcasthigh, ++ (ulong32) ((adapter->mcastmask >> 32) & 0xFFFFFFFF), ++ FLUSH); ++ } ++} ++ ++void slic_timer_ping(ulong dev) ++{ ++ p_adapter_t adapter; ++ p_sliccard_t card; ++ ++ ASSERT(dev); ++ adapter = (p_adapter_t) ((struct net_device *) dev)->priv; ++ ASSERT(adapter); ++ card = adapter->card; ++ ASSERT(card); ++#if !SLIC_DUMP_ENABLED ++/*#if SLIC_DUMP_ENABLED*/ ++ if ((adapter->state == ADAPT_UP) && (card->state == CARD_UP)) { ++ int status; ++ ++ if (card->pingstatus != ISR_PINGMASK) { ++ if (errormsg++ < 5) { ++ DBG_MSG ++ ("%s (%s) CARD HAS CRASHED PING_status == \ ++ %x ERRORMSG# %d\n", ++ __func__, adapter->netdev->name, ++ card->pingstatus, errormsg); ++ } ++ /* ASSERT(card->pingstatus == ISR_PINGMASK); */ ++ } else { ++ if (goodmsg++ < 5) { ++ DBG_MSG ++ ("slicoss: %s (%s) PING_status == %x \ ++ GOOD!!!!!!!! msg# %d\n", ++ __func__, adapter->netdev->name, ++ card->pingstatus, errormsg); ++ } ++ } ++ card->pingstatus = 0; ++ status = slic_upr_request(adapter, SLIC_UPR_PING, 0, 0, 0, 0); ++ ++ ASSERT(status == 0); ++ } else { ++ DBG_MSG("slicoss %s (%s) adapter[%p] NOT UP!!!!\n", ++ __func__, adapter->netdev->name, adapter); ++ } ++#endif ++ adapter->pingtimer.expires = ++ jiffies + SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL); ++ add_timer(&adapter->pingtimer); ++} ++ ++void slic_if_stop_queue(p_adapter_t adapter) ++{ ++ netif_stop_queue(adapter->netdev); ++} ++ ++void slic_if_start_queue(p_adapter_t adapter) ++{ ++ netif_start_queue(adapter->netdev); ++} ++ ++/* ++ * slic_if_init ++ * ++ * Perform initialization of our slic interface. ++ * ++ */ ++int slic_if_init(p_adapter_t adapter) ++{ ++ p_sliccard_t card = adapter->card; ++ struct net_device *dev = adapter->netdev; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ p_slic_shmem_t pshmem; ++ int status = 0; ++ ++ ASSERT(card); ++ DBG_MSG("slicoss: %s (%s) ENTER states[%d:%d:%d:%d] flags[%x]\n", ++ __func__, adapter->netdev->name, ++ adapter->queues_initialized, adapter->state, adapter->linkstate, ++ card->state, dev->flags); ++ ++ /* adapter should be down at this point */ ++ if (adapter->state != ADAPT_DOWN) { ++ DBG_ERROR("slic_if_init adapter->state != ADAPT_DOWN\n"); ++ return -EIO; ++ } ++ ASSERT(adapter->linkstate == LINK_DOWN); ++ ++ adapter->devflags_prev = dev->flags; ++ adapter->macopts = MAC_DIRECTED; ++ if (dev->flags) { ++ DBG_MSG("slicoss: %s (%s) Set MAC options: ", __func__, ++ adapter->netdev->name); ++ if (dev->flags & IFF_BROADCAST) { ++ adapter->macopts |= MAC_BCAST; ++ DBG_MSG("BCAST "); ++ } ++ if (dev->flags & IFF_PROMISC) { ++ adapter->macopts |= MAC_PROMISC; ++ DBG_MSG("PROMISC "); ++ } ++ if (dev->flags & IFF_ALLMULTI) { ++ adapter->macopts |= MAC_ALLMCAST; ++ DBG_MSG("ALL_MCAST "); ++ } ++ if (dev->flags & IFF_MULTICAST) { ++ adapter->macopts |= MAC_MCAST; ++ DBG_MSG("MCAST "); ++ } ++ DBG_MSG("\n"); ++ } ++ status = slic_adapter_allocresources(adapter); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR ++ ("slic_if_init: slic_adapter_allocresources FAILED %x\n", ++ status); ++ slic_adapter_freeresources(adapter); ++ return status; ++ } ++ ++ if (!adapter->queues_initialized) { ++ DBG_MSG("slicoss: %s call slic_rspqueue_init\n", __func__); ++ if (slic_rspqueue_init(adapter)) ++ return -ENOMEM; ++ DBG_MSG ++ ("slicoss: %s call slic_cmdq_init adapter[%p] port %d \n", ++ __func__, adapter, adapter->port); ++ if (slic_cmdq_init(adapter)) ++ return -ENOMEM; ++ DBG_MSG ++ ("slicoss: %s call slic_rcvqueue_init adapter[%p] \ ++ port %d \n", __func__, adapter, adapter->port); ++ if (slic_rcvqueue_init(adapter)) ++ return -ENOMEM; ++ adapter->queues_initialized = 1; ++ } ++ DBG_MSG("slicoss: %s disable interrupts(slic)\n", __func__); ++ ++ WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); ++ slic_stall_msec(1); ++ ++ if (!adapter->isp_initialized) { ++ pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock); ++ ++#if defined(CONFIG_X86_64) ++ WRITE_REG(slic_regs->slic_addr_upper, ++ SLIC_GET_ADDR_HIGH(&pshmem->isr), DONT_FLUSH); ++ WRITE_REG(slic_regs->slic_isp, ++ SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH); ++#elif defined(CONFIG_X86) ++ WRITE_REG(slic_regs->slic_addr_upper, (ulong32) 0, DONT_FLUSH); ++ WRITE_REG(slic_regs->slic_isp, (ulong32) &pshmem->isr, FLUSH); ++#else ++ Stop Compilations ++#endif ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock); ++ adapter->isp_initialized = 1; ++ } ++ ++ adapter->state = ADAPT_UP; ++ if (!card->loadtimerset) { ++ init_timer(&card->loadtimer); ++ card->loadtimer.expires = ++ jiffies + SLIC_SECS_TO_JIFFS(SLIC_LOADTIMER_PERIOD); ++ card->loadtimer.data = (ulong) card; ++ card->loadtimer.function = &slic_timer_load_check; ++ add_timer(&card->loadtimer); ++ ++ card->loadtimerset = 1; ++ } ++#if SLIC_GET_STATS_TIMER_ENABLED ++ if (!adapter->statstimerset) { ++ DBG_MSG("slicoss: %s start getstats_timer(slic)\n", ++ __func__); ++ init_timer(&adapter->statstimer); ++ adapter->statstimer.expires = ++ jiffies + SLIC_SECS_TO_JIFFS(STATS_TIMER_INTERVAL); ++ adapter->statstimer.data = (ulong) adapter->netdev; ++ adapter->statstimer.function = &slic_timer_get_stats; ++ add_timer(&adapter->statstimer); ++ adapter->statstimerset = 1; ++ } ++#endif ++#if !SLIC_DUMP_ENABLED && SLIC_PING_TIMER_ENABLED ++/*#if SLIC_DUMP_ENABLED && SLIC_PING_TIMER_ENABLED*/ ++ if (!adapter->pingtimerset) { ++ DBG_MSG("slicoss: %s start card_ping_timer(slic)\n", ++ __func__); ++ init_timer(&adapter->pingtimer); ++ adapter->pingtimer.expires = ++ jiffies + SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL); ++ adapter->pingtimer.data = (ulong) dev; ++ adapter->pingtimer.function = &slic_timer_ping; ++ add_timer(&adapter->pingtimer); ++ adapter->pingtimerset = 1; ++ adapter->card->pingstatus = ISR_PINGMASK; ++ } ++#endif ++ ++ /* ++ * clear any pending events, then enable interrupts ++ */ ++ DBG_MSG("slicoss: %s ENABLE interrupts(slic)\n", __func__); ++ adapter->isrcopy = 0; ++ adapter->pshmem->isr = 0; ++ WRITE_REG(slic_regs->slic_isr, 0, FLUSH); ++ WRITE_REG(slic_regs->slic_icr, ICR_INT_ON, FLUSH); ++ ++ DBG_MSG("slicoss: %s call slic_link_config(slic)\n", __func__); ++ slic_link_config(adapter, LINK_AUTOSPEED, LINK_AUTOD); ++ slic_link_event_handler(adapter); ++ ++ DBG_MSG("slicoss: %s EXIT\n", __func__); ++ return STATUS_SUCCESS; ++} ++ ++void slic_unmap_mmio_space(p_adapter_t adapter) ++{ ++#if LINUX_FREES_ADAPTER_RESOURCES ++ if (adapter->slic_regs) ++ iounmap(adapter->slic_regs); ++ adapter->slic_regs = NULL; ++#endif ++} ++ ++int slic_adapter_allocresources(p_adapter_t adapter) ++{ ++ if (!adapter->intrregistered) { ++ int retval; ++ ++ DBG_MSG ++ ("slicoss: %s AllocAdaptRsrcs adapter[%p] shmem[%p] \ ++ phys_shmem[%p] dev->irq[%x] %x\n", ++ __func__, adapter, adapter->pshmem, ++ (void *)adapter->phys_shmem, adapter->netdev->irq, ++ NR_IRQS); ++ ++ SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ ++ retval = request_irq(adapter->netdev->irq, ++ &slic_interrupt, ++ IRQF_SHARED, ++ adapter->netdev->name, adapter->netdev); ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ ++ if (retval) { ++ DBG_ERROR("slicoss: request_irq (%s) FAILED [%x]\n", ++ adapter->netdev->name, retval); ++ return retval; ++ } ++ adapter->intrregistered = 1; ++ DBG_MSG ++ ("slicoss: %s AllocAdaptRsrcs adapter[%p] shmem[%p] \ ++ pshmem[%p] dev->irq[%x]\n", ++ __func__, adapter, adapter->pshmem, ++ (void *)adapter->pshmem, adapter->netdev->irq); ++ } ++ return STATUS_SUCCESS; ++} ++ ++void slic_config_pci(struct pci_dev *pcidev) ++{ ++ u16 pci_command; ++ u16 new_command; ++ ++ pci_read_config_word(pcidev, PCI_COMMAND, &pci_command); ++ DBG_MSG("slicoss: %s PCI command[%4.4x]\n", __func__, pci_command); ++ ++ new_command = pci_command | PCI_COMMAND_MASTER ++ | PCI_COMMAND_MEMORY ++ | PCI_COMMAND_INVALIDATE ++ | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; ++ if (pci_command != new_command) { ++ DBG_MSG("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n", ++ __func__, pci_command, new_command); ++ pci_write_config_word(pcidev, PCI_COMMAND, new_command); ++ } ++} ++ ++void slic_adapter_freeresources(p_adapter_t adapter) ++{ ++ DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); ++ slic_init_cleanup(adapter); ++ SLIC_ZERO_MEMORY(&adapter->stats, sizeof(struct net_device_stats)); ++ adapter->error_interrupts = 0; ++ adapter->rcv_interrupts = 0; ++ adapter->xmit_interrupts = 0; ++ adapter->linkevent_interrupts = 0; ++ adapter->upr_interrupts = 0; ++ adapter->num_isrs = 0; ++ adapter->xmit_completes = 0; ++ adapter->rcv_broadcasts = 0; ++ adapter->rcv_multicasts = 0; ++ adapter->rcv_unicasts = 0; ++ DBG_MSG("slicoss: %s EXIT\n", __func__); ++} ++ ++/* ++ * slic_link_config ++ * ++ * Write phy control to configure link duplex/speed ++ * ++ */ ++void slic_link_config(p_adapter_t adapter, ++ ulong32 linkspeed, ulong32 linkduplex) ++{ ++ ulong32 speed; ++ ulong32 duplex; ++ ulong32 phy_config; ++ ulong32 phy_advreg; ++ ulong32 phy_gctlreg; ++ ++ if (adapter->state != ADAPT_UP) { ++ DBG_MSG ++ ("%s (%s) ADAPT Not up yet, Return! speed[%x] duplex[%x]\n", ++ __func__, adapter->netdev->name, linkspeed, ++ linkduplex); ++ return; ++ } ++ DBG_MSG("slicoss: %s (%s) slic_link_config: speed[%x] duplex[%x]\n", ++ __func__, adapter->netdev->name, linkspeed, linkduplex); ++ ++ ASSERT((adapter->devid == SLIC_1GB_DEVICE_ID) ++ || (adapter->devid == SLIC_2GB_DEVICE_ID)); ++ ++ if (linkspeed > LINK_1000MB) ++ linkspeed = LINK_AUTOSPEED; ++ if (linkduplex > LINK_AUTOD) ++ linkduplex = LINK_AUTOD; ++ ++ if ((linkspeed == LINK_AUTOSPEED) || (linkspeed == LINK_1000MB)) { ++ if (adapter->flags & ADAPT_FLAGS_FIBERMEDIA) { ++ /* We've got a fiber gigabit interface, and register ++ * 4 is different in fiber mode than in copper mode ++ */ ++ ++ /* advertise FD only @1000 Mb */ ++ phy_advreg = (MIICR_REG_4 | (PAR_ADV1000XFD)); ++ /* enable PAUSE frames */ ++ phy_advreg |= PAR_ASYMPAUSE_FIBER; ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_advreg, ++ FLUSH); ++ ++ if (linkspeed == LINK_AUTOSPEED) { ++ /* reset phy, enable auto-neg */ ++ phy_config = ++ (MIICR_REG_PCR | ++ (PCR_RESET | PCR_AUTONEG | ++ PCR_AUTONEG_RST)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, ++ phy_config, FLUSH); ++ } else { /* forced 1000 Mb FD*/ ++ /* power down phy to break link ++ this may not work) */ ++ phy_config = (MIICR_REG_PCR | PCR_POWERDOWN); ++ WRITE_REG(adapter->slic_regs->slic_wphy, ++ phy_config, FLUSH); ++ /* wait, Marvell says 1 sec, ++ try to get away with 10 ms */ ++ slic_stall_msec(10); ++ ++ /* disable auto-neg, set speed/duplex, ++ soft reset phy, powerup */ ++ phy_config = ++ (MIICR_REG_PCR | ++ (PCR_RESET | PCR_SPEED_1000 | ++ PCR_DUPLEX_FULL)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, ++ phy_config, FLUSH); ++ } ++ } else { /* copper gigabit */ ++ ++ /* Auto-Negotiate or 1000 Mb must be auto negotiated ++ * We've got a copper gigabit interface, and ++ * register 4 is different in copper mode than ++ * in fiber mode ++ */ ++ if (linkspeed == LINK_AUTOSPEED) { ++ /* advertise 10/100 Mb modes */ ++ phy_advreg = ++ (MIICR_REG_4 | ++ (PAR_ADV100FD | PAR_ADV100HD | PAR_ADV10FD ++ | PAR_ADV10HD)); ++ } else { ++ /* linkspeed == LINK_1000MB - ++ don't advertise 10/100 Mb modes */ ++ phy_advreg = MIICR_REG_4; ++ } ++ /* enable PAUSE frames */ ++ phy_advreg |= PAR_ASYMPAUSE; ++ /* required by the Cicada PHY */ ++ phy_advreg |= PAR_802_3; ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_advreg, ++ FLUSH); ++ /* advertise FD only @1000 Mb */ ++ phy_gctlreg = (MIICR_REG_9 | (PGC_ADV1000FD)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_gctlreg, ++ FLUSH); ++ ++ if (adapter->subsysid != SLIC_1GB_CICADA_SUBSYS_ID) { ++ /* if a Marvell PHY ++ enable auto crossover */ ++ phy_config = ++ (MIICR_REG_16 | (MRV_REG16_XOVERON)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, ++ phy_config, FLUSH); ++ ++ /* reset phy, enable auto-neg */ ++ phy_config = ++ (MIICR_REG_PCR | ++ (PCR_RESET | PCR_AUTONEG | ++ PCR_AUTONEG_RST)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, ++ phy_config, FLUSH); ++ } else { /* it's a Cicada PHY */ ++ /* enable and restart auto-neg (don't reset) */ ++ phy_config = ++ (MIICR_REG_PCR | ++ (PCR_AUTONEG | PCR_AUTONEG_RST)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, ++ phy_config, FLUSH); ++ } ++ } ++ } else { ++ /* Forced 10/100 */ ++ if (linkspeed == LINK_10MB) ++ speed = 0; ++ else ++ speed = PCR_SPEED_100; ++ if (linkduplex == LINK_HALFD) ++ duplex = 0; ++ else ++ duplex = PCR_DUPLEX_FULL; ++ ++ if (adapter->subsysid != SLIC_1GB_CICADA_SUBSYS_ID) { ++ /* if a Marvell PHY ++ disable auto crossover */ ++ phy_config = (MIICR_REG_16 | (MRV_REG16_XOVEROFF)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_config, ++ FLUSH); ++ } ++ ++ /* power down phy to break link (this may not work) */ ++ phy_config = (MIICR_REG_PCR | (PCR_POWERDOWN | speed | duplex)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_config, FLUSH); ++ ++ /* wait, Marvell says 1 sec, try to get away with 10 ms */ ++ slic_stall_msec(10); ++ ++ if (adapter->subsysid != SLIC_1GB_CICADA_SUBSYS_ID) { ++ /* if a Marvell PHY ++ disable auto-neg, set speed, ++ soft reset phy, powerup */ ++ phy_config = ++ (MIICR_REG_PCR | (PCR_RESET | speed | duplex)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_config, ++ FLUSH); ++ } else { /* it's a Cicada PHY */ ++ /* disable auto-neg, set speed, powerup */ ++ phy_config = (MIICR_REG_PCR | (speed | duplex)); ++ WRITE_REG(adapter->slic_regs->slic_wphy, phy_config, ++ FLUSH); ++ } ++ } ++ ++ DBG_MSG ++ ("slicoss: %s (%s) EXIT slic_link_config : state[%d] \ ++ phy_config[%x]\n", __func__, adapter->netdev->name, adapter->state, ++ phy_config); ++} ++ ++void slic_card_cleanup(p_sliccard_t card) ++{ ++ DBG_MSG("slicoss: %s ENTER\n", __func__); ++ ++#if SLIC_DUMP_ENABLED ++ if (card->dumpbuffer) { ++ SLIC_DEALLOCATE_MEM(card->dumpbuffer); ++ card->dumpbuffer = NULL; ++ card->dumpbuffer_phys = 0; ++ card->dumpbuffer_physl = 0; ++ card->dumpbuffer_physh = 0; ++ } ++ if (card->cmdbuffer) { ++ SLIC_DEALLOCATE_MEM(card->cmdbuffer); ++ card->cmdbuffer = NULL; ++ card->cmdbuffer_phys = 0; ++ card->cmdbuffer_physl = 0; ++ card->cmdbuffer_physh = 0; ++ } ++#endif ++ ++ if (card->loadtimerset) { ++ card->loadtimerset = 0; ++ del_timer(&card->loadtimer); ++ } ++ ++ slic_debug_card_destroy(card); ++ ++ SLIC_DEALLOCATE_MEM(card); ++ DBG_MSG("slicoss: %s EXIT\n", __func__); ++} ++ ++static int slic_card_download_gbrcv(p_adapter_t adapter) ++{ ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ulong32 codeaddr; ++ puchar instruction = NULL; ++ ulong32 rcvucodelen = 0; ++ ++ switch (adapter->devid) { ++ case SLIC_2GB_DEVICE_ID: ++ instruction = (puchar) &OasisRcvUCode[0]; ++ rcvucodelen = OasisRcvUCodeLen; ++ break; ++ case SLIC_1GB_DEVICE_ID: ++ instruction = (puchar) &GBRcvUCode[0]; ++ rcvucodelen = GBRcvUCodeLen; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ /* start download */ ++ WRITE_REG(slic_regs->slic_rcv_wcs, SLIC_RCVWCS_BEGIN, FLUSH); ++ ++ /* download the rcv sequencer ucode */ ++ for (codeaddr = 0; codeaddr < rcvucodelen; codeaddr++) { ++ /* write out instruction address */ ++ WRITE_REG(slic_regs->slic_rcv_wcs, codeaddr, FLUSH); ++ ++ /* write out the instruction data low addr */ ++ WRITE_REG(slic_regs->slic_rcv_wcs, ++ (ulong32) *(pulong32) instruction, FLUSH); ++ instruction += 4; ++ ++ /* write out the instruction data high addr */ ++ WRITE_REG(slic_regs->slic_rcv_wcs, (ulong32) *instruction, ++ FLUSH); ++ instruction += 1; ++ } ++ ++ /* download finished */ ++ WRITE_REG(slic_regs->slic_rcv_wcs, SLIC_RCVWCS_FINISH, FLUSH); ++ ++ return 0; ++} ++ ++int slic_card_download(p_adapter_t adapter) ++{ ++ ulong32 section; ++ int thissectionsize; ++ int codeaddr; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ulong32 *instruction = NULL; ++ ulong32 *lastinstruct = NULL; ++ ulong32 *startinstruct = NULL; ++ puchar nextinstruct; ++ ulong32 baseaddress; ++ ulong32 failure; ++ ulong32 i; ++ ulong32 numsects = 0; ++ ulong32 sectsize[3]; ++ ulong32 sectstart[3]; ++ ++/* DBG_MSG ("slicoss: %s (%s) adapter[%p] card[%p] devid[%x] \ ++ jiffies[%lx] cpu %d\n", __func__, adapter->netdev->name, adapter, ++ adapter->card, adapter->devid,jiffies, smp_processor_id()); */ ++ ++ switch (adapter->devid) { ++ case SLIC_2GB_DEVICE_ID: ++/* DBG_MSG ("slicoss: %s devid==SLIC_2GB_DEVICE_ID sections[%x]\n", ++ __func__, (uint) ONumSections); */ ++ numsects = ONumSections; ++ for (i = 0; i < numsects; i++) { ++ sectsize[i] = OSectionSize[i]; ++ sectstart[i] = OSectionStart[i]; ++ } ++ break; ++ case SLIC_1GB_DEVICE_ID: ++/* DBG_MSG ("slicoss: %s devid==SLIC_1GB_DEVICE_ID sections[%x]\n", ++ __func__, (uint) MNumSections); */ ++ numsects = MNumSections; ++ for (i = 0; i < numsects; i++) { ++ sectsize[i] = MSectionSize[i]; ++ sectstart[i] = MSectionStart[i]; ++ } ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ ASSERT(numsects <= 3); ++ ++ for (section = 0; section < numsects; section++) { ++ switch (adapter->devid) { ++ case SLIC_2GB_DEVICE_ID: ++ instruction = (pulong32) &OasisUCode[section][0]; ++ baseaddress = sectstart[section]; ++ thissectionsize = sectsize[section] >> 3; ++ lastinstruct = ++ (pulong32) &OasisUCode[section][sectsize[section] - ++ 8]; ++ break; ++ case SLIC_1GB_DEVICE_ID: ++ instruction = (pulong32) &MojaveUCode[section][0]; ++ baseaddress = sectstart[section]; ++ thissectionsize = sectsize[section] >> 3; ++ lastinstruct = ++ (pulong32) &MojaveUCode[section][sectsize[section] ++ - 8]; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ baseaddress = sectstart[section]; ++ thissectionsize = sectsize[section] >> 3; ++ ++ for (codeaddr = 0; codeaddr < thissectionsize; codeaddr++) { ++ startinstruct = instruction; ++ nextinstruct = ((puchar) instruction) + 8; ++ /* Write out instruction address */ ++ WRITE_REG(slic_regs->slic_wcs, baseaddress + codeaddr, ++ FLUSH); ++ /* Write out instruction to low addr */ ++ WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); ++#ifdef CONFIG_X86_64 ++ instruction = (pulong32) ((puchar) instruction + 4); ++#else ++ instruction++; ++#endif ++ /* Write out instruction to high addr */ ++ WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); ++#ifdef CONFIG_X86_64 ++ instruction = (pulong32) ((puchar) instruction + 4); ++#else ++ instruction++; ++#endif ++ } ++ } ++ ++ for (section = 0; section < numsects; section++) { ++ switch (adapter->devid) { ++ case SLIC_2GB_DEVICE_ID: ++ instruction = (pulong32) &OasisUCode[section][0]; ++ break; ++ case SLIC_1GB_DEVICE_ID: ++ instruction = (pulong32) &MojaveUCode[section][0]; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ baseaddress = sectstart[section]; ++ if (baseaddress < 0x8000) ++ continue; ++ thissectionsize = sectsize[section] >> 3; ++ ++/* DBG_MSG ("slicoss: COMPARE secton[%x] baseaddr[%x] sectnsize[%x]\n", ++ (uint)section,baseaddress,thissectionsize);*/ ++ ++ for (codeaddr = 0; codeaddr < thissectionsize; codeaddr++) { ++ /* Write out instruction address */ ++ WRITE_REG(slic_regs->slic_wcs, ++ SLIC_WCS_COMPARE | (baseaddress + codeaddr), ++ FLUSH); ++ /* Write out instruction to low addr */ ++ WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); ++#ifdef CONFIG_X86_64 ++ instruction = (pulong32) ((puchar) instruction + 4); ++#else ++ instruction++; ++#endif ++ /* Write out instruction to high addr */ ++ WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); ++#ifdef CONFIG_X86_64 ++ instruction = (pulong32) ((puchar) instruction + 4); ++#else ++ instruction++; ++#endif ++ /* Check SRAM location zero. If it is non-zero. Abort.*/ ++ failure = READ_REG(slic_regs->slic_reset, 0); ++ if (failure) { ++ DBG_MSG ++ ("slicoss: %s FAILURE EXIT codeaddr[%x] \ ++ thissectionsize[%x] failure[%x]\n", ++ __func__, codeaddr, thissectionsize, ++ failure); ++ ++ return -EIO; ++ } ++ } ++ } ++/* DBG_MSG ("slicoss: Compare done\n");*/ ++ ++ /* Everything OK, kick off the card */ ++ slic_stall_msec(10); ++ WRITE_REG(slic_regs->slic_wcs, SLIC_WCS_START, FLUSH); ++ ++ /* stall for 20 ms, long enough for ucode to init card ++ and reach mainloop */ ++ slic_stall_msec(20); ++ ++ DBG_MSG("slicoss: %s (%s) EXIT adapter[%p] card[%p]\n", ++ __func__, adapter->netdev->name, adapter, adapter->card); ++ ++ return STATUS_SUCCESS; ++} ++ ++void slic_adapter_set_hwaddr(p_adapter_t adapter) ++{ ++ p_sliccard_t card = adapter->card; ++ ++/* DBG_MSG ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", ++ __func__, card->config_set, adapter->port, adapter->physport, ++ adapter->functionnumber); ++ ++ slic_dbg_macaddrs(adapter); */ ++ ++ if ((adapter->card) && (card->config_set)) { ++ memcpy(adapter->macaddr, ++ card->config.MacInfo[adapter->functionnumber].macaddrA, ++ sizeof(slic_config_mac_t)); ++/* DBG_MSG ("%s AFTER copying from config.macinfo into currmacaddr\n", ++ __func__); ++ slic_dbg_macaddrs(adapter);*/ ++ if (!(adapter->currmacaddr[0] || adapter->currmacaddr[1] || ++ adapter->currmacaddr[2] || adapter->currmacaddr[3] || ++ adapter->currmacaddr[4] || adapter->currmacaddr[5])) { ++ memcpy(adapter->currmacaddr, adapter->macaddr, 6); ++ } ++ if (adapter->netdev) { ++ memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, ++ 6); ++ } ++ } ++/* DBG_MSG ("%s EXIT port %d\n", __func__, adapter->port); ++ slic_dbg_macaddrs(adapter); */ ++} ++ ++void slic_card_halt(p_sliccard_t card, p_adapter_t adapter) ++{ ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ DBG_MSG("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x]\n", ++ __func__, card, adapter, card->state); ++ WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); ++ adapter->all_reg_writes++; ++ adapter->icr_reg_writes++; ++ slic_config_clear(adapter); ++ WRITE_REG(slic_regs->slic_reset_iface, 0, FLUSH); ++ slic_soft_reset(adapter); ++ DBG_MSG("slicoss: %s EXIT card[%p] adapter[%p] card->state[%x]\n", ++ __func__, card, adapter, card->state); ++ return; ++ ++} ++ ++void slic_intagg_set(p_adapter_t adapter, ulong32 value) ++{ ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ WRITE_REG(slic_regs->slic_intagg, value, FLUSH); ++ adapter->card->loadlevel_current = value; ++} ++ ++int slic_card_init(p_sliccard_t card, p_adapter_t adapter) ++{ ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ pslic_eeprom_t peeprom; ++ poslic_eeprom_t pOeeprom; ++ dma_addr_t phys_config; ++ ulong32 phys_configh; ++ ulong32 phys_configl; ++ ulong32 i = 0; ++ p_slic_shmem_t pshmem; ++ int status; ++ uint macaddrs = card->card_size; ++ ushort eecodesize; ++ ushort dramsize; ++ ushort ee_chksum; ++ ushort calc_chksum; ++ pslic_config_mac_t pmac; ++ uchar fruformat; ++ uchar oemfruformat; ++ patk_fru_t patkfru; ++ poemfru_t poemfru; ++ ++ DBG_MSG ++ ("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x] \ ++ size[%d]\n", __func__, card, adapter, card->state, card->card_size); ++ ++ /* Reset everything except PCI configuration space */ ++ slic_soft_reset(adapter); ++ ++ /* Download the microcode */ ++ status = slic_card_download(adapter); ++ ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("SLIC download failed bus %d slot %d\n", ++ (uint) adapter->busnumber, ++ (uint) adapter->slotnumber); ++ return status; ++ } ++ ++ if (!card->config_set) { ++ peeprom = pci_alloc_consistent(adapter->pcidev, ++ sizeof(slic_eeprom_t), ++ &phys_config); ++ ++ phys_configl = SLIC_GET_ADDR_LOW(phys_config); ++ phys_configh = SLIC_GET_ADDR_HIGH(phys_config); ++ ++ DBG_MSG("slicoss: %s Eeprom info adapter [%p]\n " ++ "size [%x]\n peeprom [%p]\n " ++ "phys_config [%p]\n phys_configl[%x]\n " ++ "phys_configh[%x]\n", ++ __func__, adapter, (ulong32) sizeof(slic_eeprom_t), ++ peeprom, (pvoid) phys_config, phys_configl, ++ phys_configh); ++ if (!peeprom) { ++ DBG_ERROR ++ ("SLIC eeprom read failed to get memory bus %d \ ++ slot %d\n", ++ (uint) adapter->busnumber, ++ (uint) adapter->slotnumber); ++ return -ENOMEM; ++ } else { ++ SLIC_ZERO_MEMORY(peeprom, sizeof(slic_eeprom_t)); ++ } ++ WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); ++ slic_stall_msec(1); ++ pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock); ++ WRITE_REG(slic_regs->slic_addr_upper, 0, DONT_FLUSH); ++ WRITE_REG(slic_regs->slic_isp, ++ SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock); ++ ++ slic_config_get(adapter, phys_configl, phys_configh); ++ ++ for (;;) { ++ if (adapter->pshmem->isr) { ++ DBG_MSG("%s shmem[%p] shmem->isr[%x]\n", ++ __func__, adapter->pshmem, ++ adapter->pshmem->isr); ++ ++ if (adapter->pshmem->isr & ISR_UPC) { ++ adapter->pshmem->isr = 0; ++ WRITE_REG64(adapter, ++ slic_regs->slic_isp, ++ 0, ++ slic_regs->slic_addr_upper, ++ 0, FLUSH); ++ WRITE_REG(slic_regs->slic_isr, 0, ++ FLUSH); ++ ++ slic_upr_request_complete(adapter, 0); ++ break; ++ } else { ++ adapter->pshmem->isr = 0; ++ WRITE_REG(slic_regs->slic_isr, 0, ++ FLUSH); ++ } ++ } else { ++ slic_stall_msec(1); ++ i++; ++ if (i > 5000) { ++ DBG_ERROR ++ ("SLIC: %d config data fetch timed\ ++ out!\n", adapter->port); ++ DBG_MSG("%s shmem[%p] shmem->isr[%x]\n", ++ __func__, adapter->pshmem, ++ adapter->pshmem->isr); ++ WRITE_REG64(adapter, ++ slic_regs->slic_isp, 0, ++ slic_regs->slic_addr_upper, ++ 0, FLUSH); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ switch (adapter->devid) { ++ /* Oasis card */ ++ case SLIC_2GB_DEVICE_ID: ++ /* extract EEPROM data and pointers to EEPROM data */ ++ pOeeprom = (poslic_eeprom_t) peeprom; ++ eecodesize = pOeeprom->EecodeSize; ++ dramsize = pOeeprom->DramSize; ++ pmac = pOeeprom->MacInfo; ++ fruformat = pOeeprom->FruFormat; ++ patkfru = &pOeeprom->AtkFru; ++ oemfruformat = pOeeprom->OemFruFormat; ++ poemfru = &pOeeprom->OemFru; ++ macaddrs = 2; ++ /* Minor kludge for Oasis card ++ get 2 MAC addresses from the ++ EEPROM to ensure that function 1 ++ gets the Port 1 MAC address */ ++ break; ++ default: ++ /* extract EEPROM data and pointers to EEPROM data */ ++ eecodesize = peeprom->EecodeSize; ++ dramsize = peeprom->DramSize; ++ pmac = peeprom->u2.mac.MacInfo; ++ fruformat = peeprom->FruFormat; ++ patkfru = &peeprom->AtkFru; ++ oemfruformat = peeprom->OemFruFormat; ++ poemfru = &peeprom->OemFru; ++ break; ++ } ++ ++ card->config.EepromValid = FALSE; ++ ++ /* see if the EEPROM is valid by checking it's checksum */ ++ if ((eecodesize <= MAX_EECODE_SIZE) && ++ (eecodesize >= MIN_EECODE_SIZE)) { ++ ++ ee_chksum = ++ *(pushort) ((pchar) peeprom + (eecodesize - 2)); ++ /* ++ calculate the EEPROM checksum ++ */ ++ calc_chksum = ++ ~slic_eeprom_cksum((pchar) peeprom, ++ (eecodesize - 2)); ++ /* ++ if the ucdoe chksum flag bit worked, ++ we wouldn't need this shit ++ */ ++ if (ee_chksum == calc_chksum) ++ card->config.EepromValid = TRUE; ++ } ++ /* copy in the DRAM size */ ++ card->config.DramSize = dramsize; ++ ++ /* copy in the MAC address(es) */ ++ for (i = 0; i < macaddrs; i++) { ++ memcpy(&card->config.MacInfo[i], ++ &pmac[i], sizeof(slic_config_mac_t)); ++ } ++/* DBG_MSG ("%s EEPROM Checksum Good? %d MacAddress\n",__func__, ++ card->config.EepromValid); */ ++ ++ /* copy the Alacritech FRU information */ ++ card->config.FruFormat = fruformat; ++ memcpy(&card->config.AtkFru, patkfru, sizeof(atk_fru_t)); ++ ++ pci_free_consistent(adapter->pcidev, ++ sizeof(slic_eeprom_t), ++ peeprom, phys_config); ++ DBG_MSG ++ ("slicoss: %s adapter%d [%p] size[%x] FREE peeprom[%p] \ ++ phys_config[%p]\n", ++ __func__, adapter->port, adapter, ++ (ulong32) sizeof(slic_eeprom_t), peeprom, ++ (pvoid) phys_config); ++ ++ if ((!card->config.EepromValid) && ++ (adapter->reg_params.fail_on_bad_eeprom)) { ++ WRITE_REG64(adapter, ++ slic_regs->slic_isp, ++ 0, slic_regs->slic_addr_upper, 0, FLUSH); ++ DBG_ERROR ++ ("unsupported CONFIGURATION EEPROM invalid\n"); ++ return -EINVAL; ++ } ++ ++ card->config_set = 1; ++ } ++ ++ if (slic_card_download_gbrcv(adapter)) { ++ DBG_ERROR("%s unable to download GB receive microcode\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (slic_global.dynamic_intagg) { ++ DBG_MSG ++ ("Dynamic Interrupt Aggregation[ENABLED]: slic%d \ ++ SET intagg to %d\n", ++ card->cardnum, 0); ++ slic_intagg_set(adapter, 0); ++ } else { ++ slic_intagg_set(adapter, intagg_delay); ++ DBG_MSG ++ ("Dynamic Interrupt Aggregation[DISABLED]: slic%d \ ++ SET intagg to %d\n", ++ card->cardnum, intagg_delay); ++ } ++ ++ /* ++ * Initialize ping status to "ok" ++ */ ++ card->pingstatus = ISR_PINGMASK; ++ ++#if SLIC_DUMP_ENABLED ++ if (!card->dumpbuffer) { ++ card->dumpbuffer = ++ SLIC_ALLOCATE_MEM(DUMP_PAGE_SIZE, GFP_ATOMIC); ++ ++ ASSERT(card->dumpbuffer); ++ if (card->dumpbuffer == NULL) ++ return -ENOMEM; ++ } ++ /* ++ * Smear the shared memory structure and then obtain ++ * the PHYSICAL address of this structure ++ */ ++ SLIC_ZERO_MEMORY(card->dumpbuffer, DUMP_PAGE_SIZE); ++ card->dumpbuffer_phys = SLIC_GET_PHYSICAL_ADDRESS(card->dumpbuffer); ++ card->dumpbuffer_physh = SLIC_GET_ADDR_HIGH(card->dumpbuffer_phys); ++ card->dumpbuffer_physl = SLIC_GET_ADDR_LOW(card->dumpbuffer_phys); ++ ++ /* ++ * Allocate COMMAND BUFFER ++ */ ++ if (!card->cmdbuffer) { ++ card->cmdbuffer = ++ SLIC_ALLOCATE_MEM(sizeof(dump_cmd_t), GFP_ATOMIC); ++ ++ ASSERT(card->cmdbuffer); ++ if (card->cmdbuffer == NULL) ++ return -ENOMEM; ++ } ++ /* ++ * Smear the shared memory structure and then obtain ++ * the PHYSICAL address of this structure ++ */ ++ SLIC_ZERO_MEMORY(card->cmdbuffer, sizeof(dump_cmd_t)); ++ card->cmdbuffer_phys = SLIC_GET_PHYSICAL_ADDRESS(card->cmdbuffer); ++ card->cmdbuffer_physh = SLIC_GET_ADDR_HIGH(card->cmdbuffer_phys); ++ card->cmdbuffer_physl = SLIC_GET_ADDR_LOW(card->cmdbuffer_phys); ++#endif ++ ++ /* ++ * Lastly, mark our card state as up and return success ++ */ ++ card->state = CARD_UP; ++ card->reset_in_progress = 0; ++ DBG_MSG("slicoss: %s EXIT card[%p] adapter[%p] card->state[%x]\n", ++ __func__, card, adapter, card->state); ++ ++ return STATUS_SUCCESS; ++} ++ ++ulong32 slic_card_locate(p_adapter_t adapter) ++{ ++ p_sliccard_t card = slic_global.slic_card; ++ p_physcard_t physcard = slic_global.phys_card; ++ ushort card_hostid; ++ u16 __iomem *hostid_reg; ++ uint i; ++ uint rdhostid_offset = 0; ++ ++ DBG_MSG("slicoss: %s adapter[%p] slot[%x] bus[%x] port[%x]\n", ++ __func__, adapter, adapter->slotnumber, adapter->busnumber, ++ adapter->port); ++ ++ switch (adapter->devid) { ++ case SLIC_2GB_DEVICE_ID: ++ rdhostid_offset = SLIC_RDHOSTID_2GB; ++ break; ++ case SLIC_1GB_DEVICE_ID: ++ rdhostid_offset = SLIC_RDHOSTID_1GB; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ ++ hostid_reg = ++ (u16 __iomem *) (((u8 __iomem *) (adapter->slic_regs)) + ++ rdhostid_offset); ++ DBG_MSG("slicoss: %s *hostid_reg[%p] == ", __func__, hostid_reg); ++ ++ /* read the 16 bit hostid from SRAM */ ++/* card_hostid = READ_REGP16(hostid_reg, 0);*/ ++ card_hostid = (ushort) readw(hostid_reg); ++ DBG_MSG(" card_hostid[%x]\n", card_hostid); ++ ++ /* Initialize a new card structure if need be */ ++ if (card_hostid == SLIC_HOSTID_DEFAULT) { ++ card = kzalloc(sizeof(sliccard_t), GFP_KERNEL); ++ if (card == NULL) ++ return -ENOMEM; ++ ++ card->next = slic_global.slic_card; ++ slic_global.slic_card = card; ++#if DBG ++ if (adapter->devid == SLIC_2GB_DEVICE_ID) { ++ DBG_MSG ++ ("SLICOSS ==> Initialize 2 Port Gigabit Server \ ++ and Storage Accelerator\n"); ++ } else { ++ DBG_MSG ++ ("SLICOSS ==> Initialize 1 Port Gigabit Server \ ++ and Storage Accelerator\n"); ++ } ++#endif ++ card->busnumber = adapter->busnumber; ++ card->slotnumber = adapter->slotnumber; ++ ++ /* Find an available cardnum */ ++ for (i = 0; i < SLIC_MAX_CARDS; i++) { ++ if (slic_global.cardnuminuse[i] == 0) { ++ slic_global.cardnuminuse[i] = 1; ++ card->cardnum = i; ++ break; ++ } ++ } ++ slic_global.num_slic_cards++; ++ DBG_MSG("\nCARDNUM == %d Total %d Card[%p]\n\n", ++ card->cardnum, slic_global.num_slic_cards, card); ++ ++ slic_debug_card_create(card); ++ } else { ++ DBG_MSG ++ ("slicoss: %s CARD already allocated, find the \ ++ correct card\n", __func__); ++ /* Card exists, find the card this adapter belongs to */ ++ while (card) { ++ DBG_MSG ++ ("slicoss: %s card[%p] slot[%x] bus[%x] \ ++ adaptport[%p] hostid[%x] cardnum[%x]\n", ++ __func__, card, card->slotnumber, ++ card->busnumber, card->adapter[adapter->port], ++ card_hostid, card->cardnum); ++ ++ if (card->cardnum == card_hostid) ++ break; ++ card = card->next; ++ } ++ } ++ ++ ASSERT(card); ++ if (!card) ++ return STATUS_FAILURE; ++ /* Put the adapter in the card's adapter list */ ++ ASSERT(card->adapter[adapter->port] == NULL); ++ if (!card->adapter[adapter->port]) { ++ card->adapter[adapter->port] = adapter; ++ adapter->card = card; ++ } ++ ++ card->card_size = 1; /* one port per *logical* card */ ++ ++ while (physcard) { ++ for (i = 0; i < SLIC_MAX_PORTS; i++) { ++ if (!physcard->adapter[i]) ++ continue; ++ else ++ break; ++ } ++ ASSERT(i != SLIC_MAX_PORTS); ++ if (physcard->adapter[i]->slotnumber == adapter->slotnumber) ++ break; ++ physcard = physcard->next; ++ } ++ if (!physcard) { ++ /* no structure allocated for this physical card yet */ ++ physcard = ++ (p_physcard_t) SLIC_ALLOCATE_MEM(sizeof(physcard_t), ++ GFP_ATOMIC); ++ ASSERT(physcard); ++ SLIC_ZERO_MEMORY(physcard, sizeof(physcard_t)); ++ ++ DBG_MSG ++ ("\n%s Allocate a PHYSICALcard:\n PHYSICAL_Card[%p]\n\ ++ LogicalCard [%p]\n adapter [%p]\n", ++ __func__, physcard, card, adapter); ++ ++ physcard->next = slic_global.phys_card; ++ slic_global.phys_card = physcard; ++ physcard->adapters_allocd = 1; ++ } else { ++ physcard->adapters_allocd++; ++ } ++ /* Note - this is ZERO relative */ ++ adapter->physport = physcard->adapters_allocd - 1; ++ ++ ASSERT(physcard->adapter[adapter->physport] == NULL); ++ physcard->adapter[adapter->physport] = adapter; ++ adapter->physcard = physcard; ++ DBG_MSG(" PHYSICAL_Port %d Logical_Port %d\n", adapter->physport, ++ adapter->port); ++ ++ return 0; ++} ++ ++void slic_card_remaster(p_adapter_t adapter) ++{ ++ p_sliccard_t card = adapter->card; ++ int i; ++ ++ DBG_MSG("slicoss: %s card->master[%p] == adapter[%p]??\n", ++ __func__, card->master, adapter); ++ if (card->master != adapter) ++ return; ++ card->master = NULL; ++ for (i = 0; i < SLIC_MAX_PORTS; i++) { ++ if (card->adapter[i] && (card->adapter[i] != adapter)) { ++ card->master = card->adapter[i]; ++ DBG_MSG("slicoss: %s NEW MASTER SET card->master[%p]" ++ " == card->adapter[%d]\n", __func__, ++ card->master, i); ++ break; ++ } ++ } ++} ++ ++void slic_soft_reset(p_adapter_t adapter) ++{ ++ if (adapter->card->state == CARD_UP) { ++ DBG_MSG("slicoss: %s QUIESCE adapter[%p] card[%p] devid[%x]\n", ++ __func__, adapter, adapter->card, adapter->devid); ++ WRITE_REG(adapter->slic_regs->slic_quiesce, 0, FLUSH); ++ slic_stall_msec(1); ++ } ++/* DBG_MSG ("slicoss: %s (%s) adapter[%p] card[%p] devid[%x]\n", ++ __func__, adapter->netdev->name, adapter, adapter->card, ++ adapter->devid); */ ++ ++ WRITE_REG(adapter->slic_regs->slic_reset, SLIC_RESET_MAGIC, FLUSH); ++ slic_stall_msec(1); ++} ++ ++void slic_card_reset(p_adapter_t adapter) ++{ ++ p_sliccard_t card = adapter->card; ++ p_slic_upr_t upr = adapter->upr_list; ++ p_slic_upr_t upr_next = NULL; ++ ulong32 i; ++#if SLIC_FAILURE_RESET ++ ulong32 status = 0; ++#endif ++ DBG_MSG ++ ("slicoss: %s adapter[%p] port[%d] state[%x] card[%p] state[%x]\n", ++ __func__, adapter, adapter->port, adapter->state, card, ++ card->state); ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->adapter_lock); ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->reset_lock); ++ if (card->state == CARD_DIAG) { ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock); ++ return; ++ } ++ SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ card->reset_in_progress = 1; ++#if SLIC_FAILURE_RESET ++ if (adapter->state != ADAPT_RESET) { ++ SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock); ++ return; ++ } ++ ++ adapter->state = ADAPT_DOWN; ++ adapter->linkstate = LINK_DOWN; ++#endif ++ if (adapter->gennumber == card->gennumber) { ++ for (i = 0; i < card->card_size; i++) { ++ if (card->adapter[i]) { ++ if (card->adapter[i] == adapter) ++ continue; ++ if (card->adapter[i]->state == ADAPT_UP) { ++ card->adapter[i]->state = ADAPT_RESET; ++ adapter->linkstate = LINK_DOWN; ++ } ++ } ++ } ++#if SLIC_FAILURE_RESET ++ slic_soft_reset(adapter); ++ card->state = CARD_DOWN; ++ card->master = NULL; ++ card->adapters_activated = 0; ++#endif ++ card->gennumber++; ++ } ++ adapter->gennumber = card->gennumber; ++ adapter->pshmem->isr = 0; ++ adapter->isrcopy = 0; ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock); ++ for (i = 0; i < card->card_size; i++) { ++ if (card->adapter[i]) ++ slic_cmdq_reset(card->adapter[i]); ++ } ++ while (upr) { ++ upr_next = upr->next; ++ SLIC_DEALLOCATE_MEM(upr); ++ upr = upr_next; ++ } ++ adapter->upr_list = NULL; ++ adapter->upr_busy = 0; ++#if SLIC_FAILURE_RESET ++ status = slic_if_init(adapter); ++ if ((status == 0) && (!card->master)) ++ card->master = adapter; ++ slic_mcast_set_mask(adapter); ++#endif ++ SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock); ++ DBG_MSG ++ ("slicoss: %s EXIT adapter[%p] port[%d] state[%x] card[%p] \ ++ state[%x]\n", __func__, adapter, adapter->port, adapter->state, ++ card, card->state); ++ return; ++} ++ ++void slic_config_set(p_adapter_t adapter, boolean linkchange) ++{ ++ ulong32 value; ++ ulong32 RcrReset; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ DBG_MSG("slicoss: %s (%s) slic_interface_enable[%p](%d)\n", ++ __func__, adapter->netdev->name, adapter, ++ adapter->cardindex); ++ ++ if (linkchange) { ++ /* Setup MAC */ ++ slic_mac_config(adapter); ++ RcrReset = GRCR_RESET; ++ } else { ++ slic_mac_address_config(adapter); ++ RcrReset = 0; ++ } ++ ++ if (adapter->linkduplex == LINK_FULLD) { ++ /* setup xmtcfg */ ++ value = (GXCR_RESET | /* Always reset */ ++ GXCR_XMTEN | /* Enable transmit */ ++ GXCR_PAUSEEN); /* Enable pause */ ++ ++ DBG_MSG("slicoss: FDX adapt[%p] set xmtcfg to [%x]\n", adapter, ++ value); ++ WRITE_REG(slic_regs->slic_wxcfg, value, FLUSH); ++ ++ /* Setup rcvcfg last */ ++ value = (RcrReset | /* Reset, if linkchange */ ++ GRCR_CTLEN | /* Enable CTL frames */ ++ GRCR_ADDRAEN | /* Address A enable */ ++ GRCR_RCVBAD | /* Rcv bad frames */ ++ (GRCR_HASHSIZE << GRCR_HASHSIZE_SHIFT)); ++ } else { ++ /* setup xmtcfg */ ++ value = (GXCR_RESET | /* Always reset */ ++ GXCR_XMTEN); /* Enable transmit */ ++ ++ DBG_MSG("slicoss: HDX adapt[%p] set xmtcfg to [%x]\n", adapter, ++ value); ++ WRITE_REG(slic_regs->slic_wxcfg, value, FLUSH); ++ ++ /* Setup rcvcfg last */ ++ value = (RcrReset | /* Reset, if linkchange */ ++ GRCR_ADDRAEN | /* Address A enable */ ++ GRCR_RCVBAD | /* Rcv bad frames */ ++ (GRCR_HASHSIZE << GRCR_HASHSIZE_SHIFT)); ++ } ++ ++ if (adapter->state != ADAPT_DOWN) { ++ /* Only enable receive if we are restarting or running */ ++ value |= GRCR_RCVEN; ++ } ++ ++ if (adapter->macopts & MAC_PROMISC) ++ value |= GRCR_RCVALL; ++ ++ DBG_MSG("slicoss: adapt[%p] set rcvcfg to [%x]\n", adapter, value); ++ WRITE_REG(slic_regs->slic_wrcfg, value, FLUSH); ++} ++ ++/* ++ * Turn off RCV and XMT, power down PHY ++ */ ++void slic_config_clear(p_adapter_t adapter) ++{ ++ ulong32 value; ++ ulong32 phy_config; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ /* Setup xmtcfg */ ++ value = (GXCR_RESET | /* Always reset */ ++ GXCR_PAUSEEN); /* Enable pause */ ++ ++ WRITE_REG(slic_regs->slic_wxcfg, value, FLUSH); ++ ++ value = (GRCR_RESET | /* Always reset */ ++ GRCR_CTLEN | /* Enable CTL frames */ ++ GRCR_ADDRAEN | /* Address A enable */ ++ (GRCR_HASHSIZE << GRCR_HASHSIZE_SHIFT)); ++ ++ WRITE_REG(slic_regs->slic_wrcfg, value, FLUSH); ++ ++ /* power down phy */ ++ phy_config = (MIICR_REG_PCR | (PCR_POWERDOWN)); ++ WRITE_REG(slic_regs->slic_wphy, phy_config, FLUSH); ++} ++ ++void slic_config_get(p_adapter_t adapter, ulong32 config, ulong32 config_h) ++{ ++ int status; ++ ++ status = slic_upr_request(adapter, ++ SLIC_UPR_RCONFIG, ++ (ulong32) config, (ulong32) config_h, 0, 0); ++ ASSERT(status == 0); ++} ++ ++void slic_mac_address_config(p_adapter_t adapter) ++{ ++ ulong32 value; ++ ulong32 value2; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ value = *(pulong32) &adapter->currmacaddr[2]; ++ value = ntohl(value); ++ WRITE_REG(slic_regs->slic_wraddral, value, FLUSH); ++ WRITE_REG(slic_regs->slic_wraddrbl, value, FLUSH); ++ ++ value2 = (ulong32) ((adapter->currmacaddr[0] << 8 | ++ adapter->currmacaddr[1]) & 0xFFFF); ++ ++ WRITE_REG(slic_regs->slic_wraddrah, value2, FLUSH); ++ WRITE_REG(slic_regs->slic_wraddrbh, value2, FLUSH); ++ ++ DBG_MSG("%s value1[%x] value2[%x] Call slic_mcast_set_mask\n", ++ __func__, value, value2); ++ slic_dbg_macaddrs(adapter); ++ ++ /* Write our multicast mask out to the card. This is done */ ++ /* here in addition to the slic_mcast_addr_set routine */ ++ /* because ALL_MCAST may have been enabled or disabled */ ++ slic_mcast_set_mask(adapter); ++} ++ ++void slic_mac_config(p_adapter_t adapter) ++{ ++ ulong32 value; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ++ /* Setup GMAC gaps */ ++ if (adapter->linkspeed == LINK_1000MB) { ++ value = ((GMCR_GAPBB_1000 << GMCR_GAPBB_SHIFT) | ++ (GMCR_GAPR1_1000 << GMCR_GAPR1_SHIFT) | ++ (GMCR_GAPR2_1000 << GMCR_GAPR2_SHIFT)); ++ } else { ++ value = ((GMCR_GAPBB_100 << GMCR_GAPBB_SHIFT) | ++ (GMCR_GAPR1_100 << GMCR_GAPR1_SHIFT) | ++ (GMCR_GAPR2_100 << GMCR_GAPR2_SHIFT)); ++ } ++ ++ /* enable GMII */ ++ if (adapter->linkspeed == LINK_1000MB) ++ value |= GMCR_GBIT; ++ ++ /* enable fullduplex */ ++ if ((adapter->linkduplex == LINK_FULLD) ++ || (adapter->macopts & MAC_LOOPBACK)) { ++ value |= GMCR_FULLD; ++ } ++ ++ /* write mac config */ ++ WRITE_REG(slic_regs->slic_wmcfg, value, FLUSH); ++ ++ /* setup mac addresses */ ++ slic_mac_address_config(adapter); ++} ++ ++boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame) ++{ ++ ulong32 opts = adapter->macopts; ++ pulong32 dhost4 = (pulong32) ðer_frame->ether_dhost[0]; ++ pushort dhost2 = (pushort) ðer_frame->ether_dhost[4]; ++ boolean equaladdr; ++ ++ if (opts & MAC_PROMISC) { ++ DBG_MSG("slicoss: %s (%s) PROMISCUOUS. Accept frame\n", ++ __func__, adapter->netdev->name); ++ return TRUE; ++ } ++ ++ if ((*dhost4 == 0xFFFFFFFF) && (*dhost2 == 0xFFFF)) { ++ if (opts & MAC_BCAST) { ++ adapter->rcv_broadcasts++; ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++ } ++ ++ if (ether_frame->ether_dhost[0] & 0x01) { ++ if (opts & MAC_ALLMCAST) { ++ adapter->rcv_multicasts++; ++ adapter->stats.multicast++; ++ return TRUE; ++ } ++ if (opts & MAC_MCAST) { ++ p_mcast_address_t mcaddr = adapter->mcastaddrs; ++ ++ while (mcaddr) { ++ ETHER_EQ_ADDR(mcaddr->address, ++ ether_frame->ether_dhost, ++ equaladdr); ++ if (equaladdr) { ++ adapter->rcv_multicasts++; ++ adapter->stats.multicast++; ++ return TRUE; ++ } ++ mcaddr = mcaddr->next; ++ } ++ return FALSE; ++ } else { ++ return FALSE; ++ } ++ } ++ if (opts & MAC_DIRECTED) { ++ adapter->rcv_unicasts++; ++ return TRUE; ++ } ++ return FALSE; ++ ++} ++ ++int slic_mac_set_address(struct net_device *dev, pvoid ptr) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct sockaddr *addr = ptr; ++ ++ DBG_MSG("%s ENTER (%s)\n", __func__, adapter->netdev->name); ++ ++ if (netif_running(dev)) ++ return -EBUSY; ++ if (!adapter) ++ return -EBUSY; ++ DBG_MSG("slicoss: %s (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ __func__, adapter->netdev->name, adapter->currmacaddr[0], ++ adapter->currmacaddr[1], adapter->currmacaddr[2], ++ adapter->currmacaddr[3], adapter->currmacaddr[4], ++ adapter->currmacaddr[5]); ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ memcpy(adapter->currmacaddr, addr->sa_data, dev->addr_len); ++ DBG_MSG("slicoss: %s (%s) new %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ __func__, adapter->netdev->name, adapter->currmacaddr[0], ++ adapter->currmacaddr[1], adapter->currmacaddr[2], ++ adapter->currmacaddr[3], adapter->currmacaddr[4], ++ adapter->currmacaddr[5]); ++ ++ slic_config_set(adapter, TRUE); ++ return 0; ++} ++ ++/* ++ * slic_timer_get_stats ++ * ++ * Timer function used to suck the statistics out of the card every ++ * 50 seconds or whatever STATS_TIMER_INTERVAL is set to. ++ * ++ */ ++void slic_timer_get_stats(ulong dev) ++{ ++ p_adapter_t adapter; ++ p_sliccard_t card; ++ p_slic_shmem_t pshmem; ++ ++ ASSERT(dev); ++ adapter = (p_adapter_t) ((struct net_device *)dev)->priv; ++ ASSERT(adapter); ++ card = adapter->card; ++ ASSERT(card); ++ ++ if ((card->state == CARD_UP) && ++ (adapter->state == ADAPT_UP) && (adapter->linkstate == LINK_UP)) { ++ pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++#ifdef CONFIG_X86_64 ++ slic_upr_request(adapter, ++ SLIC_UPR_STATS, ++ SLIC_GET_ADDR_LOW(&pshmem->inicstats), ++ SLIC_GET_ADDR_HIGH(&pshmem->inicstats), 0, 0); ++#elif defined(CONFIG_X86) ++ slic_upr_request(adapter, ++ SLIC_UPR_STATS, ++ (ulong32) &pshmem->inicstats, 0, 0, 0); ++#else ++ Stop compilation; ++#endif ++ } else { ++/* DBG_MSG ("slicoss: %s adapter[%p] linkstate[%x] NOT UP!\n", ++ __func__, adapter, adapter->linkstate); */ ++ } ++ adapter->statstimer.expires = jiffies + ++ SLIC_SECS_TO_JIFFS(STATS_TIMER_INTERVAL); ++ add_timer(&adapter->statstimer); ++} ++ ++void slic_timer_load_check(ulong cardaddr) ++{ ++ p_sliccard_t card = (p_sliccard_t) cardaddr; ++ p_adapter_t adapter = card->master; ++ ulong32 load = card->events; ++ ulong32 level = 0; ++ ++ if ((adapter) && (adapter->state == ADAPT_UP) && ++ (card->state == CARD_UP) && (slic_global.dynamic_intagg)) { ++ if (adapter->devid == SLIC_1GB_DEVICE_ID) { ++ if (adapter->linkspeed == LINK_1000MB) ++ level = 100; ++ else { ++ if (load > SLIC_LOAD_5) ++ level = SLIC_INTAGG_5; ++ else if (load > SLIC_LOAD_4) ++ level = SLIC_INTAGG_4; ++ else if (load > SLIC_LOAD_3) ++ level = SLIC_INTAGG_3; ++ else if (load > SLIC_LOAD_2) ++ level = SLIC_INTAGG_2; ++ else if (load > SLIC_LOAD_1) ++ level = SLIC_INTAGG_1; ++ else ++ level = SLIC_INTAGG_0; ++ } ++ if (card->loadlevel_current != level) { ++ card->loadlevel_current = level; ++ WRITE_REG(adapter->slic_regs->slic_intagg, ++ level, FLUSH); ++ } ++ } else { ++ if (load > SLIC_LOAD_5) ++ level = SLIC_INTAGG_5; ++ else if (load > SLIC_LOAD_4) ++ level = SLIC_INTAGG_4; ++ else if (load > SLIC_LOAD_3) ++ level = SLIC_INTAGG_3; ++ else if (load > SLIC_LOAD_2) ++ level = SLIC_INTAGG_2; ++ else if (load > SLIC_LOAD_1) ++ level = SLIC_INTAGG_1; ++ else ++ level = SLIC_INTAGG_0; ++ if (card->loadlevel_current != level) { ++ card->loadlevel_current = level; ++ WRITE_REG(adapter->slic_regs->slic_intagg, ++ level, FLUSH); ++ } ++ } ++ } ++ card->events = 0; ++ card->loadtimer.expires = ++ jiffies + SLIC_SECS_TO_JIFFS(SLIC_LOADTIMER_PERIOD); ++ add_timer(&card->loadtimer); ++} ++ ++void slic_stall_msec(int stall) ++{ ++ mdelay(stall); ++} ++ ++void slic_stall_usec(int stall) ++{ ++ udelay(stall); ++} ++ ++void slic_assert_fail(void) ++{ ++ ulong32 cpuid; ++ ulong32 curr_pid; ++ cpuid = smp_processor_id(); ++ curr_pid = current->pid; ++ ++ DBG_ERROR("%s CPU # %d ---- PID # %d\n", __func__, cpuid, curr_pid); ++} ++ ++int slic_upr_queue_request(p_adapter_t adapter, ++ ulong32 upr_request, ++ ulong32 upr_data, ++ ulong32 upr_data_h, ++ ulong32 upr_buffer, ulong32 upr_buffer_h) ++{ ++ p_slic_upr_t upr; ++ p_slic_upr_t uprqueue; ++ ++ upr = SLIC_ALLOCATE_MEM(sizeof(slic_upr_t), GFP_ATOMIC); ++ if (!upr) { ++ DBG_MSG("%s COULD NOT ALLOCATE UPR MEM\n", __func__); ++ ++ return -ENOMEM; ++ } ++ upr->adapter = adapter->port; ++ upr->upr_request = upr_request; ++ upr->upr_data = upr_data; ++ upr->upr_buffer = upr_buffer; ++ upr->upr_data_h = upr_data_h; ++ upr->upr_buffer_h = upr_buffer_h; ++ upr->next = NULL; ++ if (adapter->upr_list) { ++ uprqueue = adapter->upr_list; ++ ++ while (uprqueue->next) ++ uprqueue = uprqueue->next; ++ uprqueue->next = upr; ++ } else { ++ adapter->upr_list = upr; ++ } ++ return STATUS_SUCCESS; ++} ++ ++int slic_upr_request(p_adapter_t adapter, ++ ulong32 upr_request, ++ ulong32 upr_data, ++ ulong32 upr_data_h, ++ ulong32 upr_buffer, ulong32 upr_buffer_h) ++{ ++ int status; ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->upr_lock); ++ status = slic_upr_queue_request(adapter, ++ upr_request, ++ upr_data, ++ upr_data_h, upr_buffer, upr_buffer_h); ++ if (status != STATUS_SUCCESS) { ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ return status; ++ } ++ slic_upr_start(adapter); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ return STATUS_PENDING; ++} ++ ++void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr) ++{ ++ p_sliccard_t card = adapter->card; ++ p_slic_upr_t upr; ++ ++/* if (card->dump_requested) { ++ DBG_MSG("ENTER slic_upr_request_complete Dump in progress ISR[%x]\n", ++ isr); ++ } */ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->upr_lock); ++ upr = adapter->upr_list; ++ if (!upr) { ++ ASSERT(0); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ return; ++ } ++ adapter->upr_list = upr->next; ++ upr->next = NULL; ++ adapter->upr_busy = 0; ++ ASSERT(adapter->port == upr->adapter); ++ switch (upr->upr_request) { ++ case SLIC_UPR_STATS: ++ { ++#if SLIC_GET_STATS_ENABLED ++ p_slic_stats_t slicstats = ++ (p_slic_stats_t) &adapter->pshmem->inicstats; ++ p_slic_stats_t newstats = slicstats; ++ p_slic_stats_t old = &adapter->inicstats_prev; ++ p_slicnet_stats_t stst = &adapter->slic_stats; ++#endif ++ if (isr & ISR_UPCERR) { ++ DBG_ERROR ++ ("SLIC_UPR_STATS command failed isr[%x]\n", ++ isr); ++ ++ break; ++ } ++#if SLIC_GET_STATS_ENABLED ++/* DBG_MSG ("slicoss: %s rcv %lx:%lx:%lx:%lx:%lx %lx %lx " ++ "xmt %lx:%lx:%lx:%lx:%lx %lx %lx\n", ++ __func__, ++ slicstats->rcv_unicasts100, ++ slicstats->rcv_bytes100, ++ slicstats->rcv_bytes100, ++ slicstats->rcv_tcp_bytes100, ++ slicstats->rcv_tcp_segs100, ++ slicstats->rcv_other_error100, ++ slicstats->rcv_drops100, ++ slicstats->xmit_unicasts100, ++ slicstats->xmit_bytes100, ++ slicstats->xmit_bytes100, ++ slicstats->xmit_tcp_bytes100, ++ slicstats->xmit_tcp_segs100, ++ slicstats->xmit_other_error100, ++ slicstats->xmit_collisions100);*/ ++ UPDATE_STATS_GB(stst->tcp.xmit_tcp_segs, ++ newstats->xmit_tcp_segs_gb, ++ old->xmit_tcp_segs_gb); ++ ++ UPDATE_STATS_GB(stst->tcp.xmit_tcp_bytes, ++ newstats->xmit_tcp_bytes_gb, ++ old->xmit_tcp_bytes_gb); ++ ++ UPDATE_STATS_GB(stst->tcp.rcv_tcp_segs, ++ newstats->rcv_tcp_segs_gb, ++ old->rcv_tcp_segs_gb); ++ ++ UPDATE_STATS_GB(stst->tcp.rcv_tcp_bytes, ++ newstats->rcv_tcp_bytes_gb, ++ old->rcv_tcp_bytes_gb); ++ ++ UPDATE_STATS_GB(stst->iface.xmt_bytes, ++ newstats->xmit_bytes_gb, ++ old->xmit_bytes_gb); ++ ++ UPDATE_STATS_GB(stst->iface.xmt_ucast, ++ newstats->xmit_unicasts_gb, ++ old->xmit_unicasts_gb); ++ ++ UPDATE_STATS_GB(stst->iface.rcv_bytes, ++ newstats->rcv_bytes_gb, ++ old->rcv_bytes_gb); ++ ++ UPDATE_STATS_GB(stst->iface.rcv_ucast, ++ newstats->rcv_unicasts_gb, ++ old->rcv_unicasts_gb); ++ ++ UPDATE_STATS_GB(stst->iface.xmt_errors, ++ newstats->xmit_collisions_gb, ++ old->xmit_collisions_gb); ++ ++ UPDATE_STATS_GB(stst->iface.xmt_errors, ++ newstats->xmit_excess_collisions_gb, ++ old->xmit_excess_collisions_gb); ++ ++ UPDATE_STATS_GB(stst->iface.xmt_errors, ++ newstats->xmit_other_error_gb, ++ old->xmit_other_error_gb); ++ ++ UPDATE_STATS_GB(stst->iface.rcv_errors, ++ newstats->rcv_other_error_gb, ++ old->rcv_other_error_gb); ++ ++ UPDATE_STATS_GB(stst->iface.rcv_discards, ++ newstats->rcv_drops_gb, ++ old->rcv_drops_gb); ++ ++ if (newstats->rcv_drops_gb > old->rcv_drops_gb) { ++ adapter->rcv_drops += ++ (newstats->rcv_drops_gb - ++ old->rcv_drops_gb); ++ } ++ memcpy(old, newstats, sizeof(slic_stats_t)); ++#endif ++ break; ++ } ++ case SLIC_UPR_RLSR: ++ slic_link_upr_complete(adapter, isr); ++ break; ++ case SLIC_UPR_RCONFIG: ++ break; ++ case SLIC_UPR_RPHY: ++ ASSERT(0); ++ break; ++ case SLIC_UPR_ENLB: ++ ASSERT(0); ++ break; ++ case SLIC_UPR_ENCT: ++ ASSERT(0); ++ break; ++ case SLIC_UPR_PDWN: ++ ASSERT(0); ++ break; ++ case SLIC_UPR_PING: ++ card->pingstatus |= (isr & ISR_PINGDSMASK); ++ break; ++#if SLIC_DUMP_ENABLED ++ case SLIC_UPR_DUMP: ++ card->dumpstatus |= (isr & ISR_UPCMASK); ++ break; ++#endif ++ default: ++ ASSERT(0); ++ } ++ SLIC_DEALLOCATE_MEM(upr); ++ slic_upr_start(adapter); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++} ++ ++void slic_upr_start(p_adapter_t adapter) ++{ ++ p_slic_upr_t upr; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++/* ++ char * ptr1; ++ char * ptr2; ++ uint cmdoffset; ++*/ ++ upr = adapter->upr_list; ++ if (!upr) ++ return; ++ if (adapter->upr_busy) ++ return; ++ adapter->upr_busy = 1; ++ ++ switch (upr->upr_request) { ++ case SLIC_UPR_STATS: ++ if (upr->upr_data_h == 0) { ++ WRITE_REG(slic_regs->slic_stats, upr->upr_data, FLUSH); ++ } else { ++ WRITE_REG64(adapter, ++ slic_regs->slic_stats64, ++ upr->upr_data, ++ slic_regs->slic_addr_upper, ++ upr->upr_data_h, FLUSH); ++ } ++ break; ++ ++ case SLIC_UPR_RLSR: ++ WRITE_REG64(adapter, ++ slic_regs->slic_rlsr, ++ upr->upr_data, ++ slic_regs->slic_addr_upper, upr->upr_data_h, FLUSH); ++ break; ++ ++ case SLIC_UPR_RCONFIG: ++ DBG_MSG("%s SLIC_UPR_RCONFIG!!!!\n", __func__); ++ DBG_MSG("WRITE_REG64 adapter[%p]\n" ++ " a->slic_regs[%p] slic_regs[%p]\n" ++ " &slic_rconfig[%p] &slic_addr_upper[%p]\n" ++ " upr[%p]\n" ++ " uprdata[%x] uprdatah[%x]\n", ++ adapter, adapter->slic_regs, slic_regs, ++ &slic_regs->slic_rconfig, &slic_regs->slic_addr_upper, ++ upr, upr->upr_data, upr->upr_data_h); ++ WRITE_REG64(adapter, ++ slic_regs->slic_rconfig, ++ upr->upr_data, ++ slic_regs->slic_addr_upper, upr->upr_data_h, FLUSH); ++ break; ++#if SLIC_DUMP_ENABLED ++ case SLIC_UPR_DUMP: ++#if 0 ++ DBG_MSG("%s SLIC_UPR_DUMP!!!!\n", __func__); ++ DBG_MSG("WRITE_REG64 adapter[%p]\n" ++ " upr_buffer[%x] upr_bufferh[%x]\n" ++ " upr_data[%x] upr_datah[%x]\n" ++ " cmdbuff[%p] cmdbuffP[%p]\n" ++ " dumpbuff[%p] dumpbuffP[%p]\n", ++ adapter, upr->upr_buffer, upr->upr_buffer_h, ++ upr->upr_data, upr->upr_data_h, ++ adapter->card->cmdbuffer, ++ (void *)adapter->card->cmdbuffer_phys, ++ adapter->card->dumpbuffer, ( ++ void *)adapter->card->dumpbuffer_phys); ++ ++ ptr1 = (char *)slic_regs; ++ ptr2 = (char *)(&slic_regs->slic_dump_cmd); ++ cmdoffset = ptr2 - ptr1; ++ DBG_MSG("slic_dump_cmd register offset [%x]\n", cmdoffset); ++#endif ++ if (upr->upr_buffer || upr->upr_buffer_h) { ++ WRITE_REG64(adapter, ++ slic_regs->slic_dump_data, ++ upr->upr_buffer, ++ slic_regs->slic_addr_upper, ++ upr->upr_buffer_h, FLUSH); ++ } ++ WRITE_REG64(adapter, ++ slic_regs->slic_dump_cmd, ++ upr->upr_data, ++ slic_regs->slic_addr_upper, upr->upr_data_h, FLUSH); ++ break; ++#endif ++ case SLIC_UPR_PING: ++ WRITE_REG(slic_regs->slic_ping, 1, FLUSH); ++ break; ++ default: ++ ASSERT(0); ++ } ++} ++ ++void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr) ++{ ++ ulong32 linkstatus = adapter->pshmem->linkstatus; ++ uint linkup; ++ uchar linkspeed; ++ uchar linkduplex; ++ ++ DBG_MSG("%s: %s ISR[%x] linkstatus[%x]\n adapter[%p](%d)\n", ++ __func__, adapter->netdev->name, isr, linkstatus, adapter, ++ adapter->cardindex); ++ ++ if ((isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) { ++ p_slic_shmem_t pshmem; ++ ++ pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++#if defined(CONFIG_X86_64) ++ slic_upr_queue_request(adapter, ++ SLIC_UPR_RLSR, ++ SLIC_GET_ADDR_LOW(&pshmem->linkstatus), ++ SLIC_GET_ADDR_HIGH(&pshmem->linkstatus), ++ 0, 0); ++#elif defined(CONFIG_X86) ++ slic_upr_queue_request(adapter, ++ SLIC_UPR_RLSR, ++ (ulong32) &pshmem->linkstatus, ++ SLIC_GET_ADDR_HIGH(pshmem), 0, 0); ++#else ++ Stop Compilation; ++#endif ++ return; ++ } ++ if (adapter->state != ADAPT_UP) ++ return; ++ ++ ASSERT((adapter->devid == SLIC_1GB_DEVICE_ID) ++ || (adapter->devid == SLIC_2GB_DEVICE_ID)); ++ ++ linkup = linkstatus & GIG_LINKUP ? LINK_UP : LINK_DOWN; ++ if (linkstatus & GIG_SPEED_1000) { ++ linkspeed = LINK_1000MB; ++ DBG_MSG("slicoss: %s (%s) GIGABIT Speed==1000MB ", ++ __func__, adapter->netdev->name); ++ } else if (linkstatus & GIG_SPEED_100) { ++ linkspeed = LINK_100MB; ++ DBG_MSG("slicoss: %s (%s) GIGABIT Speed==100MB ", __func__, ++ adapter->netdev->name); ++ } else { ++ linkspeed = LINK_10MB; ++ DBG_MSG("slicoss: %s (%s) GIGABIT Speed==10MB ", __func__, ++ adapter->netdev->name); ++ } ++ if (linkstatus & GIG_FULLDUPLEX) { ++ linkduplex = LINK_FULLD; ++ DBG_MSG(" Duplex == FULL\n"); ++ } else { ++ linkduplex = LINK_HALFD; ++ DBG_MSG(" Duplex == HALF\n"); ++ } ++ ++ if ((adapter->linkstate == LINK_DOWN) && (linkup == LINK_DOWN)) { ++ DBG_MSG("slicoss: %s (%s) physport(%d) link still down\n", ++ __func__, adapter->netdev->name, adapter->physport); ++ return; ++ } ++ ++ /* link up event, but nothing has changed */ ++ if ((adapter->linkstate == LINK_UP) && ++ (linkup == LINK_UP) && ++ (adapter->linkspeed == linkspeed) && ++ (adapter->linkduplex == linkduplex)) { ++ DBG_MSG("slicoss: %s (%s) port(%d) link still up\n", ++ __func__, adapter->netdev->name, adapter->physport); ++ return; ++ } ++ ++ /* link has changed at this point */ ++ ++ /* link has gone from up to down */ ++ if (linkup == LINK_DOWN) { ++ adapter->linkstate = LINK_DOWN; ++ DBG_MSG("slicoss: %s %d LinkDown!\n", __func__, ++ adapter->physport); ++ return; ++ } ++ ++ /* link has gone from down to up */ ++ adapter->linkspeed = linkspeed; ++ adapter->linkduplex = linkduplex; ++ ++ if (adapter->linkstate != LINK_UP) { ++ /* setup the mac */ ++ DBG_MSG("%s call slic_config_set\n", __func__); ++ slic_config_set(adapter, TRUE); ++ adapter->linkstate = LINK_UP; ++ DBG_MSG("\n(%s) Link UP: CALL slic_if_start_queue", ++ adapter->netdev->name); ++ slic_if_start_queue(adapter); ++ } ++#if 1 ++ switch (linkspeed) { ++ case LINK_1000MB: ++ DBG_MSG ++ ("\n(%s) LINK UP!: GIGABIT SPEED == 1000MB duplex[%x]\n", ++ adapter->netdev->name, adapter->linkduplex); ++ break; ++ case LINK_100MB: ++ DBG_MSG("\n(%s) LINK UP!: SPEED == 100MB duplex[%x]\n", ++ adapter->netdev->name, adapter->linkduplex); ++ break; ++ default: ++ DBG_MSG("\n(%s) LINK UP!: SPEED == 10MB duplex[%x]\n", ++ adapter->netdev->name, adapter->linkduplex); ++ break; ++ } ++#endif ++} ++ ++/* ++ * this is here to checksum the eeprom, there is some ucode bug ++ * which prevens us from using the ucode result. ++ * remove this once ucode is fixed. ++ */ ++ushort slic_eeprom_cksum(pchar m, int len) ++{ ++#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) ++#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);\ ++ } ++ ++ pushort w; ++ ulong32 sum = 0; ++ ulong32 byte_swapped = 0; ++ ulong32 w_int; ++ ++ union { ++ char c[2]; ++ ushort s; ++ } s_util; ++ ++ union { ++ ushort s[2]; ++ int l; ++ } l_util; ++ ++ l_util.l = 0; ++ s_util.s = 0; ++ ++ w = (pushort) m; ++#ifdef CONFIG_X86_64 ++ w_int = (ulong32) ((ulong) w & 0x00000000FFFFFFFF); ++#else ++ w_int = (ulong32) (w); ++#endif ++ if ((1 & w_int) && (len > 0)) { ++ REDUCE; ++ sum <<= 8; ++ s_util.c[0] = *(puchar) w; ++ w = (pushort) ((char *)w + 1); ++ len--; ++ byte_swapped = 1; ++ } ++ ++ /* Unroll the loop to make overhead from branches &c small. */ ++ while ((len -= 32) >= 0) { ++ sum += w[0]; ++ sum += w[1]; ++ sum += w[2]; ++ sum += w[3]; ++ sum += w[4]; ++ sum += w[5]; ++ sum += w[6]; ++ sum += w[7]; ++ sum += w[8]; ++ sum += w[9]; ++ sum += w[10]; ++ sum += w[11]; ++ sum += w[12]; ++ sum += w[13]; ++ sum += w[14]; ++ sum += w[15]; ++ w = (pushort) ((ulong) w + 16); /* verify */ ++ } ++ len += 32; ++ while ((len -= 8) >= 0) { ++ sum += w[0]; ++ sum += w[1]; ++ sum += w[2]; ++ sum += w[3]; ++ w = (pushort) ((ulong) w + 4); /* verify */ ++ } ++ len += 8; ++ if (len != 0 || byte_swapped != 0) { ++ REDUCE; ++ while ((len -= 2) >= 0) ++ sum += *w++; /* verify */ ++ if (byte_swapped) { ++ REDUCE; ++ sum <<= 8; ++ byte_swapped = 0; ++ if (len == -1) { ++ s_util.c[1] = *(pchar) w; ++ sum += s_util.s; ++ len = 0; ++ } else { ++ len = -1; ++ } ++ ++ } else if (len == -1) { ++ s_util.c[0] = *(pchar) w; ++ } ++ ++ if (len == -1) { ++ s_util.c[1] = 0; ++ sum += s_util.s; ++ } ++ } ++ REDUCE; ++ return (ushort) sum; ++} ++ ++int slic_rspqueue_init(p_adapter_t adapter) ++{ ++ int i; ++ p_slic_rspqueue_t rspq = &adapter->rspqueue; ++ p_slic_regs_t slic_regs = adapter->slic_regs; ++ ulong32 paddrh = 0; ++ ++ DBG_MSG("slicoss: %s (%s) ENTER adapter[%p]\n", __func__, ++ adapter->netdev->name, adapter); ++ ASSERT(adapter->state == ADAPT_DOWN); ++ SLIC_ZERO_MEMORY(rspq, sizeof(slic_rspqueue_t)); ++ ++ rspq->num_pages = SLIC_RSPQ_PAGES_GB; ++ ++ for (i = 0; i < rspq->num_pages; i++) { ++ rspq->vaddr[i] = ++ pci_alloc_consistent(adapter->pcidev, PAGE_SIZE, ++ &rspq->paddr[i]); ++ if (!rspq->vaddr[i]) { ++ DBG_ERROR ++ ("rspqueue_init_failed pci_alloc_consistent\n"); ++ slic_rspqueue_free(adapter); ++ return STATUS_FAILURE; ++ } ++#ifndef CONFIG_X86_64 ++ ASSERT(((ulong32) rspq->vaddr[i] & 0xFFFFF000) == ++ (ulong32) rspq->vaddr[i]); ++ ASSERT(((ulong32) rspq->paddr[i] & 0xFFFFF000) == ++ (ulong32) rspq->paddr[i]); ++#endif ++ SLIC_ZERO_MEMORY(rspq->vaddr[i], PAGE_SIZE); ++/* DBG_MSG("slicoss: %s UPLOAD RSPBUFF Page pageix[%x] paddr[%p] " ++ "vaddr[%p]\n", ++ __func__, i, (void *)rspq->paddr[i], rspq->vaddr[i]); */ ++ ++ if (paddrh == 0) { ++ WRITE_REG(slic_regs->slic_rbar, ++ (rspq->paddr[i] | SLIC_RSPQ_BUFSINPAGE), ++ DONT_FLUSH); ++ } else { ++ WRITE_REG64(adapter, ++ slic_regs->slic_rbar64, ++ (rspq->paddr[i] | SLIC_RSPQ_BUFSINPAGE), ++ slic_regs->slic_addr_upper, ++ paddrh, DONT_FLUSH); ++ } ++ } ++ rspq->offset = 0; ++ rspq->pageindex = 0; ++ rspq->rspbuf = (p_slic_rspbuf_t) rspq->vaddr[0]; ++ DBG_MSG("slicoss: %s (%s) EXIT adapter[%p]\n", __func__, ++ adapter->netdev->name, adapter); ++ return STATUS_SUCCESS; ++} ++ ++int slic_rspqueue_reset(p_adapter_t adapter) ++{ ++ p_slic_rspqueue_t rspq = &adapter->rspqueue; ++ ++ DBG_MSG("slicoss: %s (%s) ENTER adapter[%p]\n", __func__, ++ adapter->netdev->name, adapter); ++ ASSERT(adapter->state == ADAPT_DOWN); ++ ASSERT(rspq); ++ ++ DBG_MSG("slicoss: Nothing to do. rspq[%p]\n" ++ " offset[%x]\n" ++ " pageix[%x]\n" ++ " rspbuf[%p]\n", ++ rspq, rspq->offset, rspq->pageindex, rspq->rspbuf); ++ ++ DBG_MSG("slicoss: %s (%s) EXIT adapter[%p]\n", __func__, ++ adapter->netdev->name, adapter); ++ return STATUS_SUCCESS; ++} ++ ++void slic_rspqueue_free(p_adapter_t adapter) ++{ ++ int i; ++ slic_rspqueue_t *rspq = &adapter->rspqueue; ++ ++ DBG_MSG("slicoss: %s adapter[%p] port %d rspq[%p] FreeRSPQ\n", ++ __func__, adapter, adapter->physport, rspq); ++ for (i = 0; i < rspq->num_pages; i++) { ++ if (rspq->vaddr[i]) { ++ DBG_MSG ++ ("slicoss: pci_free_consistent rspq->vaddr[%p] \ ++ paddr[%p]\n", ++ rspq->vaddr[i], (pvoid) rspq->paddr[i]); ++ pci_free_consistent(adapter->pcidev, PAGE_SIZE, ++ rspq->vaddr[i], rspq->paddr[i]); ++ } ++ rspq->vaddr[i] = NULL; ++ rspq->paddr[i] = 0; ++ } ++ rspq->offset = 0; ++ rspq->pageindex = 0; ++ rspq->rspbuf = NULL; ++} ++ ++p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter) ++{ ++ p_slic_rspqueue_t rspq = &adapter->rspqueue; ++ p_slic_rspbuf_t buf; ++ ++ if (!(rspq->rspbuf->status)) ++ return NULL; ++ ++ buf = rspq->rspbuf; ++#ifndef CONFIG_X86_64 ++ ASSERT((buf->status & 0xFFFFFFE0) == 0); ++#endif ++ ASSERT(buf->hosthandle); ++ if (++rspq->offset < SLIC_RSPQ_BUFSINPAGE) { ++ rspq->rspbuf++; ++#ifndef CONFIG_X86_64 ++ ASSERT(((ulong32) rspq->rspbuf & 0xFFFFFFE0) == ++ (ulong32) rspq->rspbuf); ++#endif ++ } else { ++ ASSERT(rspq->offset == SLIC_RSPQ_BUFSINPAGE); ++ WRITE_REG64(adapter, ++ adapter->slic_regs->slic_rbar64, ++ (rspq-> ++ paddr[rspq->pageindex] | SLIC_RSPQ_BUFSINPAGE), ++ adapter->slic_regs->slic_addr_upper, 0, DONT_FLUSH); ++ rspq->pageindex = (++rspq->pageindex) % rspq->num_pages; ++ rspq->offset = 0; ++ rspq->rspbuf = (p_slic_rspbuf_t) rspq->vaddr[rspq->pageindex]; ++#ifndef CONFIG_X86_64 ++ ASSERT(((ulong32) rspq->rspbuf & 0xFFFFF000) == ++ (ulong32) rspq->rspbuf); ++#endif ++ } ++#ifndef CONFIG_X86_64 ++ ASSERT(((ulong32) buf & 0xFFFFFFE0) == (ulong32) buf); ++#endif ++ return buf; ++} ++ ++void slic_cmdqmem_init(p_adapter_t adapter) ++{ ++ slic_cmdqmem_t *cmdqmem = &adapter->cmdqmem; ++ ++ SLIC_ZERO_MEMORY(cmdqmem, sizeof(slic_cmdqmem_t)); ++} ++ ++void slic_cmdqmem_free(p_adapter_t adapter) ++{ ++ slic_cmdqmem_t *cmdqmem = &adapter->cmdqmem; ++ int i; ++ ++ DBG_MSG("slicoss: (%s) adapter[%p] port %d rspq[%p] Free CMDQ Memory\n", ++ __func__, adapter, adapter->physport, cmdqmem); ++ for (i = 0; i < SLIC_CMDQ_MAXPAGES; i++) { ++ if (cmdqmem->pages[i]) { ++ DBG_MSG("slicoss: %s Deallocate page CmdQPage[%p]\n", ++ __func__, (pvoid) cmdqmem->pages[i]); ++ pci_free_consistent(adapter->pcidev, ++ PAGE_SIZE, ++ (pvoid) cmdqmem->pages[i], ++ cmdqmem->dma_pages[i]); ++ } ++ } ++ SLIC_ZERO_MEMORY(cmdqmem, sizeof(slic_cmdqmem_t)); ++} ++ ++pulong32 slic_cmdqmem_addpage(p_adapter_t adapter) ++{ ++ p_slic_cmdqmem_t cmdqmem = &adapter->cmdqmem; ++ pulong32 pageaddr; ++ ++ if (cmdqmem->pagecnt >= SLIC_CMDQ_MAXPAGES) ++ return NULL; ++ pageaddr = pci_alloc_consistent(adapter->pcidev, ++ PAGE_SIZE, ++ &cmdqmem->dma_pages[cmdqmem->pagecnt]); ++ if (!pageaddr) ++ return NULL; ++#ifndef CONFIG_X86_64 ++ ASSERT(((ulong32) pageaddr & 0xFFFFF000) == (ulong32) pageaddr); ++#endif ++ cmdqmem->pages[cmdqmem->pagecnt] = pageaddr; ++ cmdqmem->pagecnt++; ++ return pageaddr; ++} ++ ++int slic_cmdq_init(p_adapter_t adapter) ++{ ++ int i; ++ pulong32 pageaddr; ++ ++ DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); ++ ASSERT(adapter->state == ADAPT_DOWN); ++ SLIC_ZERO_MEMORY(&adapter->cmdq_all, sizeof(slic_cmdqueue_t)); ++ SLIC_ZERO_MEMORY(&adapter->cmdq_free, sizeof(slic_cmdqueue_t)); ++ SLIC_ZERO_MEMORY(&adapter->cmdq_done, sizeof(slic_cmdqueue_t)); ++ SLIC_INIT_SPINLOCK(adapter->cmdq_all.lock); ++ SLIC_INIT_SPINLOCK(adapter->cmdq_free.lock); ++ SLIC_INIT_SPINLOCK(adapter->cmdq_done.lock); ++ slic_cmdqmem_init(adapter); ++ adapter->slic_handle_ix = 1; ++ for (i = 0; i < SLIC_CMDQ_INITPAGES; i++) { ++ pageaddr = slic_cmdqmem_addpage(adapter); ++#ifndef CONFIG_X86_64 ++ ASSERT(((ulong32) pageaddr & 0xFFFFF000) == (ulong32) pageaddr); ++#endif ++ if (!pageaddr) { ++ slic_cmdq_free(adapter); ++ return STATUS_FAILURE; ++ } ++ slic_cmdq_addcmdpage(adapter, pageaddr); ++ } ++ adapter->slic_handle_ix = 1; ++ DBG_MSG("slicoss: %s reset slic_handle_ix to ONE\n", __func__); ++ ++ return STATUS_SUCCESS; ++} ++ ++void slic_cmdq_free(p_adapter_t adapter) ++{ ++ p_slic_hostcmd_t cmd; ++ ++ DBG_MSG("slicoss: %s adapter[%p] port %d FreeCommandsFrom CMDQ\n", ++ __func__, adapter, adapter->physport); ++ cmd = adapter->cmdq_all.head; ++ while (cmd) { ++ if (cmd->busy) { ++ struct sk_buff *tempskb; ++ ++ tempskb = cmd->skb; ++ if (tempskb) { ++ cmd->skb = NULL; ++ dev_kfree_skb_irq(tempskb); ++ } ++ } ++ cmd = cmd->next_all; ++ } ++ SLIC_ZERO_MEMORY(&adapter->cmdq_all, sizeof(slic_cmdqueue_t)); ++ SLIC_ZERO_MEMORY(&adapter->cmdq_free, sizeof(slic_cmdqueue_t)); ++ SLIC_ZERO_MEMORY(&adapter->cmdq_done, sizeof(slic_cmdqueue_t)); ++ slic_cmdqmem_free(adapter); ++} ++ ++void slic_cmdq_reset(p_adapter_t adapter) ++{ ++ p_slic_hostcmd_t hcmd; ++ struct sk_buff *skb; ++ ulong32 outstanding; ++ ++ DBG_MSG("%s ENTER adapter[%p]\n", __func__, adapter); ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->cmdq_free.lock); ++ SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->cmdq_done.lock); ++ outstanding = adapter->cmdq_all.count - adapter->cmdq_done.count; ++ outstanding -= adapter->cmdq_free.count; ++ hcmd = adapter->cmdq_all.head; ++ while (hcmd) { ++ if (hcmd->busy) { ++ skb = hcmd->skb; ++ ASSERT(skb); ++ DBG_MSG("slicoss: %s hcmd[%p] skb[%p] ", __func__, ++ hcmd, skb); ++ hcmd->busy = 0; ++ hcmd->skb = NULL; ++ DBG_MSG(" Free SKB\n"); ++ dev_kfree_skb_irq(skb); ++ } ++ hcmd = hcmd->next_all; ++ } ++ adapter->cmdq_free.count = 0; ++ adapter->cmdq_free.head = NULL; ++ adapter->cmdq_free.tail = NULL; ++ adapter->cmdq_done.count = 0; ++ adapter->cmdq_done.head = NULL; ++ adapter->cmdq_done.tail = NULL; ++ adapter->cmdq_free.head = adapter->cmdq_all.head; ++ hcmd = adapter->cmdq_all.head; ++ while (hcmd) { ++ adapter->cmdq_free.count++; ++ hcmd->next = hcmd->next_all; ++ hcmd = hcmd->next_all; ++ } ++ if (adapter->cmdq_free.count != adapter->cmdq_all.count) { ++ DBG_ERROR("%s free_count %d != all count %d\n", __func__, ++ adapter->cmdq_free.count, adapter->cmdq_all.count); ++ } ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->cmdq_done.lock); ++ SLIC_RELEASE_IRQ_SPINLOCK(adapter->cmdq_free.lock); ++ DBG_MSG("%s EXIT adapter[%p]\n", __func__, adapter); ++} ++ ++void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page) ++{ ++ p_slic_hostcmd_t cmd; ++ p_slic_hostcmd_t prev; ++ p_slic_hostcmd_t tail; ++ p_slic_cmdqueue_t cmdq; ++ int cmdcnt; ++ pvoid cmdaddr; ++ ulong phys_addr; ++ ulong32 phys_addrl; ++ ulong32 phys_addrh; ++ pslic_handle_t pslic_handle; ++ ++ cmdaddr = page; ++ cmd = (p_slic_hostcmd_t) cmdaddr; ++/* DBG_MSG("CMDQ Page addr[%p] ix[%d] pfree[%p]\n", cmdaddr, slic_handle_ix, ++ adapter->pfree_slic_handles); */ ++ cmdcnt = 0; ++ ++ phys_addr = SLIC_GET_PHYSICAL_ADDRESS((void *)page); ++ phys_addrl = SLIC_GET_ADDR_LOW(phys_addr); ++ phys_addrh = SLIC_GET_ADDR_HIGH(phys_addr); ++ ++ prev = NULL; ++ tail = cmd; ++ while ((cmdcnt < SLIC_CMDQ_CMDSINPAGE) && ++ (adapter->slic_handle_ix < 256)) { ++ /* Allocate and initialize a SLIC_HANDLE for this command */ ++ SLIC_GET_SLIC_HANDLE(adapter, pslic_handle); ++ if (pslic_handle == NULL) ++ ASSERT(0); ++ ASSERT(pslic_handle == ++ &adapter->slic_handles[pslic_handle->token. ++ handle_index]); ++ pslic_handle->type = SLIC_HANDLE_CMD; ++ pslic_handle->address = (pvoid) cmd; ++ pslic_handle->offset = (ushort) adapter->slic_handle_ix++; ++ pslic_handle->other_handle = NULL; ++ pslic_handle->next = NULL; ++ ++ cmd->pslic_handle = pslic_handle; ++ cmd->cmd64.hosthandle = pslic_handle->token.handle_token; ++ cmd->busy = FALSE; ++ cmd->paddrl = phys_addrl; ++ cmd->paddrh = phys_addrh; ++ cmd->next_all = prev; ++ cmd->next = prev; ++ prev = cmd; ++ phys_addrl += SLIC_HOSTCMD_SIZE; ++ cmdaddr += SLIC_HOSTCMD_SIZE; ++ ++ cmd = (p_slic_hostcmd_t) cmdaddr; ++ cmdcnt++; ++ } ++ ++ cmdq = &adapter->cmdq_all; ++ cmdq->count += cmdcnt; /* SLIC_CMDQ_CMDSINPAGE; mooktodo */ ++ tail->next_all = cmdq->head; ++ ASSERT(VALID_ADDRESS(prev)); ++ cmdq->head = prev; ++ cmdq = &adapter->cmdq_free; ++ SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock); ++ cmdq->count += cmdcnt; /* SLIC_CMDQ_CMDSINPAGE; mooktodo */ ++ tail->next = cmdq->head; ++ ASSERT(VALID_ADDRESS(prev)); ++ cmdq->head = prev; ++ SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++} ++ ++p_slic_hostcmd_t slic_cmdq_getfree(p_adapter_t adapter) ++{ ++ p_slic_cmdqueue_t cmdq = &adapter->cmdq_free; ++ p_slic_hostcmd_t cmd = NULL; ++ ++lock_and_retry: ++ SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock); ++retry: ++ cmd = cmdq->head; ++ if (cmd) { ++ cmdq->head = cmd->next; ++ cmdq->count--; ++ SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++ } else { ++ slic_cmdq_getdone(adapter); ++ cmd = cmdq->head; ++ if (cmd) { ++ goto retry; ++ } else { ++ pulong32 pageaddr; ++ ++ SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++ pageaddr = slic_cmdqmem_addpage(adapter); ++ if (pageaddr) { ++ slic_cmdq_addcmdpage(adapter, pageaddr); ++ goto lock_and_retry; ++ } ++ } ++ } ++ return cmd; ++} ++ ++void slic_cmdq_getdone(p_adapter_t adapter) ++{ ++ p_slic_cmdqueue_t done_cmdq = &adapter->cmdq_done; ++ p_slic_cmdqueue_t free_cmdq = &adapter->cmdq_free; ++ ++ ASSERT(free_cmdq->head == NULL); ++ SLIC_ACQUIRE_IRQ_SPINLOCK(done_cmdq->lock); ++ ASSERT(VALID_ADDRESS(done_cmdq->head)); ++ ++ free_cmdq->head = done_cmdq->head; ++ free_cmdq->count = done_cmdq->count; ++ done_cmdq->head = NULL; ++ done_cmdq->tail = NULL; ++ done_cmdq->count = 0; ++ SLIC_RELEASE_IRQ_SPINLOCK(done_cmdq->lock); ++} ++ ++void slic_cmdq_putdone(p_adapter_t adapter, p_slic_hostcmd_t cmd) ++{ ++ p_slic_cmdqueue_t cmdq = &adapter->cmdq_done; ++ ++ SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock); ++ cmd->busy = 0; ++ ASSERT(VALID_ADDRESS(cmdq->head)); ++ cmd->next = cmdq->head; ++ ASSERT(VALID_ADDRESS(cmd)); ++ cmdq->head = cmd; ++ cmdq->count++; ++ SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++} ++ ++void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd) ++{ ++ p_slic_cmdqueue_t cmdq = &adapter->cmdq_done; ++ ++ SLIC_ACQUIRE_SPINLOCK(cmdq->lock); ++ cmd->busy = 0; ++ ASSERT(VALID_ADDRESS(cmdq->head)); ++ cmd->next = cmdq->head; ++ ASSERT(VALID_ADDRESS(cmd)); ++ cmdq->head = cmd; ++ cmdq->count++; ++ if ((adapter->xmitq_full) && (cmdq->count > 10)) ++ netif_wake_queue(adapter->netdev); ++ SLIC_RELEASE_SPINLOCK(cmdq->lock); ++} ++ ++int slic_rcvqueue_init(p_adapter_t adapter) ++{ ++ int i, count; ++ p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ ++ DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); ++ ASSERT(adapter->state == ADAPT_DOWN); ++ rcvq->tail = NULL; ++ rcvq->head = NULL; ++ rcvq->size = SLIC_RCVQ_ENTRIES; ++ rcvq->errors = 0; ++ rcvq->count = 0; ++ i = (SLIC_RCVQ_ENTRIES / SLIC_RCVQ_FILLENTRIES); ++ count = 0; ++ while (i) { ++ count += slic_rcvqueue_fill(adapter); ++ i--; ++ } ++ if (rcvq->count < SLIC_RCVQ_MINENTRIES) { ++ slic_rcvqueue_free(adapter); ++ return STATUS_FAILURE; ++ } ++ DBG_MSG("slicoss: %s EXIT adapter[%p]\n", __func__, adapter); ++ return STATUS_SUCCESS; ++} ++ ++int slic_rcvqueue_reset(p_adapter_t adapter) ++{ ++ p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ ++ DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); ++ ASSERT(adapter->state == ADAPT_DOWN); ++ ASSERT(rcvq); ++ ++ DBG_MSG("slicoss: Nothing to do. rcvq[%p]\n" ++ " count[%x]\n" ++ " head[%p]\n" ++ " tail[%p]\n", ++ rcvq, rcvq->count, rcvq->head, rcvq->tail); ++ ++ DBG_MSG("slicoss: %s EXIT adapter[%p]\n", __func__, adapter); ++ return STATUS_SUCCESS; ++} ++ ++void slic_rcvqueue_free(p_adapter_t adapter) ++{ ++ slic_rcvqueue_t *rcvq = &adapter->rcvqueue; ++ struct sk_buff *skb; ++ ++ while (rcvq->head) { ++ skb = rcvq->head; ++ rcvq->head = rcvq->head->next; ++ dev_kfree_skb(skb); ++ } ++ rcvq->tail = NULL; ++ rcvq->head = NULL; ++ rcvq->count = 0; ++} ++ ++struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter) ++{ ++ p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ struct sk_buff *skb; ++ p_slic_rcvbuf_t rcvbuf; ++ int count; ++ ++ if (rcvq->count) { ++ skb = rcvq->head; ++ rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ ASSERT(rcvbuf); ++ ++ if (rcvbuf->status & IRHDDR_SVALID) { ++ rcvq->head = rcvq->head->next; ++ skb->next = NULL; ++ rcvq->count--; ++ } else { ++ skb = NULL; ++ } ++ } else { ++ DBG_ERROR("RcvQ Empty!! adapter[%p] rcvq[%p] count[%x]\n", ++ adapter, rcvq, rcvq->count); ++ skb = NULL; ++ } ++ while (rcvq->count < SLIC_RCVQ_FILLTHRESH) { ++ count = slic_rcvqueue_fill(adapter); ++ if (!count) ++ break; ++ } ++ if (skb) ++ rcvq->errors = 0; ++ return skb; ++} ++ ++int slic_rcvqueue_fill(p_adapter_t adapter) ++{ ++ pvoid paddr; ++ ulong32 paddrl; ++ ulong32 paddrh; ++ p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ int i = 0; ++ ++ while (i < SLIC_RCVQ_FILLENTRIES) { ++ p_slic_rcvbuf_t rcvbuf; ++ struct sk_buff *skb; ++#ifdef KLUDGE_FOR_4GB_BOUNDARY ++retry_rcvqfill: ++#endif ++ skb = alloc_skb(SLIC_RCVQ_RCVBUFSIZE, GFP_ATOMIC); ++ if (skb) { ++ paddr = (void *)SLIC_GET_DMA_ADDRESS_READ(adapter, ++ skb->data, ++ SLIC_RCVQ_RCVBUFSIZE); ++ paddrl = SLIC_GET_ADDR_LOW(paddr); ++ paddrh = SLIC_GET_ADDR_HIGH(paddr); ++ ++ skb->len = SLIC_RCVBUF_HEADSIZE; ++ rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ rcvbuf->status = 0; ++ skb->next = NULL; ++#ifdef KLUDGE_FOR_4GB_BOUNDARY ++ if (paddrl == 0) { ++ DBG_ERROR ++ ("%s: LOW 32bits PHYSICAL ADDRESS == 0 " ++ "skb[%p] PROBLEM\n" ++ " skbdata[%p]\n" ++ " skblen[%x]\n" ++ " paddr[%p]\n" ++ " paddrl[%x]\n" ++ " paddrh[%x]\n", __func__, skb, ++ skb->data, skb->len, paddr, paddrl, ++ paddrh); ++ DBG_ERROR(" rcvq->head[%p]\n" ++ " rcvq->tail[%p]\n" ++ " rcvq->count[%x]\n", ++ rcvq->head, rcvq->tail, rcvq->count); ++ DBG_ERROR("SKIP THIS SKB!!!!!!!!\n"); ++ goto retry_rcvqfill; ++ } ++#else ++ if (paddrl == 0) { ++ DBG_ERROR ++ ("\n\n%s: LOW 32bits PHYSICAL ADDRESS == 0 " ++ "skb[%p] GIVE TO CARD ANYWAY\n" ++ " skbdata[%p]\n" ++ " paddr[%p]\n" ++ " paddrl[%x]\n" ++ " paddrh[%x]\n", __func__, skb, ++ skb->data, paddr, paddrl, paddrh); ++ } ++#endif ++ if (paddrh == 0) { ++ WRITE_REG(adapter->slic_regs->slic_hbar, ++ (ulong32) paddrl, DONT_FLUSH); ++ } else { ++ WRITE_REG64(adapter, ++ adapter->slic_regs->slic_hbar64, ++ (ulong32) paddrl, ++ adapter->slic_regs->slic_addr_upper, ++ (ulong32) paddrh, DONT_FLUSH); ++ } ++ if (rcvq->head) ++ rcvq->tail->next = skb; ++ else ++ rcvq->head = skb; ++ rcvq->tail = skb; ++ rcvq->count++; ++ i++; ++ } else { ++ DBG_ERROR ++ ("%s slic_rcvqueue_fill could only get [%d] " ++ "skbuffs\n", ++ adapter->netdev->name, i); ++ break; ++ } ++ } ++ return i; ++} ++ ++ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb) ++{ ++ p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ pvoid paddr; ++ ulong32 paddrl; ++ ulong32 paddrh; ++ p_slic_rcvbuf_t rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ ++ ASSERT(skb->len == SLIC_RCVBUF_HEADSIZE); ++ paddr = (void *)SLIC_GET_DMA_ADDRESS_READ(adapter, ++ skb->head, ++ SLIC_RCVQ_RCVBUFSIZE); ++ rcvbuf->status = 0; ++ skb->next = NULL; ++ ++ paddrl = SLIC_GET_ADDR_LOW(paddr); ++ paddrh = SLIC_GET_ADDR_HIGH(paddr); ++ ++ if (paddrl == 0) { ++ DBG_ERROR ++ ("%s: LOW 32bits PHYSICAL ADDRESS == 0 skb[%p] PROBLEM\n" ++ " skbdata[%p]\n" " skblen[%x]\n" ++ " paddr[%p]\n" " paddrl[%x]\n" ++ " paddrh[%x]\n", __func__, skb, skb->data, ++ skb->len, paddr, paddrl, paddrh); ++ DBG_ERROR(" rcvq->head[%p]\n" ++ " rcvq->tail[%p]\n" ++ " rcvq->count[%x]\n", rcvq->head, rcvq->tail, ++ rcvq->count); ++ } ++ if (paddrh == 0) { ++ WRITE_REG(adapter->slic_regs->slic_hbar, (ulong32) paddrl, ++ DONT_FLUSH); ++ } else { ++ WRITE_REG64(adapter, ++ adapter->slic_regs->slic_hbar64, ++ paddrl, ++ adapter->slic_regs->slic_addr_upper, ++ paddrh, DONT_FLUSH); ++ } ++ if (rcvq->head) ++ rcvq->tail->next = skb; ++ else ++ rcvq->head = skb; ++ rcvq->tail = skb; ++ rcvq->count++; ++ return rcvq->count; ++} ++ ++static int slic_debug_card_show(struct seq_file *seq, void *v) ++{ ++#ifdef MOOKTODO ++ int i; ++ p_sliccard_t card = seq->private; ++ pslic_config_t config = &card->config; ++ puchar fru = (puchar) (&card->config.atk_fru); ++ puchar oemfru = (puchar) (&card->config.OemFru); ++#endif ++ ++ seq_printf(seq, "driver_version : %s", slic_proc_version); ++ seq_printf(seq, "Microcode versions: \n"); ++ seq_printf(seq, " Gigabit (gb) : %s %s\n", ++ MOJAVE_UCODE_VERS_STRING, MOJAVE_UCODE_VERS_DATE); ++ seq_printf(seq, " Gigabit Receiver : %s %s\n", ++ GB_RCVUCODE_VERS_STRING, GB_RCVUCODE_VERS_DATE); ++ seq_printf(seq, "Vendor : %s\n", slic_vendor); ++ seq_printf(seq, "Product Name : %s\n", slic_product_name); ++#ifdef MOOKTODO ++ seq_printf(seq, "VendorId : %4.4X\n", ++ config->VendorId); ++ seq_printf(seq, "DeviceId : %4.4X\n", ++ config->DeviceId); ++ seq_printf(seq, "RevisionId : %2.2x\n", ++ config->RevisionId); ++ seq_printf(seq, "Bus # : %d\n", card->busnumber); ++ seq_printf(seq, "Device # : %d\n", card->slotnumber); ++ seq_printf(seq, "Interfaces : %d\n", card->card_size); ++ seq_printf(seq, " Initialized : %d\n", ++ card->adapters_activated); ++ seq_printf(seq, " Allocated : %d\n", ++ card->adapters_allocated); ++ ASSERT(card->card_size <= SLIC_NBR_MACS); ++ for (i = 0; i < card->card_size; i++) { ++ seq_printf(seq, ++ " MAC%d : %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", ++ i, config->macinfo[i].macaddrA[0], ++ config->macinfo[i].macaddrA[1], ++ config->macinfo[i].macaddrA[2], ++ config->macinfo[i].macaddrA[3], ++ config->macinfo[i].macaddrA[4], ++ config->macinfo[i].macaddrA[5]); ++ } ++ seq_printf(seq, " IF Init State Duplex/Speed irq\n"); ++ seq_printf(seq, " -------------------------------\n"); ++ for (i = 0; i < card->adapters_allocated; i++) { ++ p_adapter_t adapter; ++ ++ adapter = card->adapter[i]; ++ if (adapter) { ++ seq_printf(seq, ++ " %d %d %s %s %s 0x%X\n", ++ adapter->physport, adapter->state, ++ SLIC_LINKSTATE(adapter->linkstate), ++ SLIC_DUPLEX(adapter->linkduplex), ++ SLIC_SPEED(adapter->linkspeed), ++ (uint) adapter->irq); ++ } ++ } ++ seq_printf(seq, "Generation # : %4.4X\n", card->gennumber); ++ seq_printf(seq, "RcvQ max entries : %4.4X\n", ++ SLIC_RCVQ_ENTRIES); ++ seq_printf(seq, "Ping Status : %8.8X\n", ++ card->pingstatus); ++ seq_printf(seq, "Minimum grant : %2.2x\n", ++ config->MinGrant); ++ seq_printf(seq, "Maximum Latency : %2.2x\n", config->MaxLat); ++ seq_printf(seq, "PciStatus : %4.4x\n", ++ config->Pcistatus); ++ seq_printf(seq, "Debug Device Id : %4.4x\n", ++ config->DbgDevId); ++ seq_printf(seq, "DRAM ROM Function : %4.4x\n", ++ config->DramRomFn); ++ seq_printf(seq, "Network interface Pin 1 : %2.2x\n", ++ config->NetIntPin1); ++ seq_printf(seq, "Network interface Pin 2 : %2.2x\n", ++ config->NetIntPin1); ++ seq_printf(seq, "Network interface Pin 3 : %2.2x\n", ++ config->NetIntPin1); ++ seq_printf(seq, "PM capabilities : %4.4X\n", ++ config->PMECapab); ++ seq_printf(seq, "Network Clock Controls : %4.4X\n", ++ config->NwClkCtrls); ++ ++ switch (config->FruFormat) { ++ case ATK_FRU_FORMAT: ++ { ++ seq_printf(seq, ++ "Vendor : Alacritech, Inc.\n"); ++ seq_printf(seq, ++ "Assembly # : %c%c%c%c%c%c\n", ++ fru[0], fru[1], fru[2], fru[3], fru[4], ++ fru[5]); ++ seq_printf(seq, ++ "Revision # : %c%c\n", ++ fru[6], fru[7]); ++ ++ if (config->OEMFruFormat == VENDOR4_FRU_FORMAT) { ++ seq_printf(seq, ++ "Serial # : " ++ "%c%c%c%c%c%c%c%c%c%c%c%c\n", ++ fru[8], fru[9], fru[10], ++ fru[11], fru[12], fru[13], ++ fru[16], fru[17], fru[18], ++ fru[19], fru[20], fru[21]); ++ } else { ++ seq_printf(seq, ++ "Serial # : " ++ "%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", ++ fru[8], fru[9], fru[10], ++ fru[11], fru[12], fru[13], ++ fru[14], fru[15], fru[16], ++ fru[17], fru[18], fru[19], ++ fru[20], fru[21]); ++ } ++ break; ++ } ++ ++ default: ++ { ++ seq_printf(seq, ++ "Vendor : Alacritech, Inc.\n"); ++ seq_printf(seq, ++ "Serial # : Empty FRU\n"); ++ break; ++ } ++ } ++ ++ switch (config->OEMFruFormat) { ++ case VENDOR1_FRU_FORMAT: ++ { ++ seq_printf(seq, "FRU Information:\n"); ++ seq_printf(seq, " Commodity # : %c\n", ++ oemfru[0]); ++ seq_printf(seq, ++ " Assembly # : %c%c%c%c\n", ++ oemfru[1], oemfru[2], oemfru[3], oemfru[4]); ++ seq_printf(seq, ++ " Revision # : %c%c\n", ++ oemfru[5], oemfru[6]); ++ seq_printf(seq, ++ " Supplier # : %c%c\n", ++ oemfru[7], oemfru[8]); ++ seq_printf(seq, ++ " Date : %c%c\n", ++ oemfru[9], oemfru[10]); ++ seq_sprintf(seq, ++ " Sequence # : %c%c%c\n", ++ oemfru[11], oemfru[12], oemfru[13]); ++ break; ++ } ++ ++ case VENDOR2_FRU_FORMAT: ++ { ++ seq_printf(seq, "FRU Information:\n"); ++ seq_printf(seq, ++ " Part # : " ++ "%c%c%c%c%c%c%c%c\n", ++ oemfru[0], oemfru[1], oemfru[2], ++ oemfru[3], oemfru[4], oemfru[5], ++ oemfru[6], oemfru[7]); ++ seq_printf(seq, ++ " Supplier # : %c%c%c%c%c\n", ++ oemfru[8], oemfru[9], oemfru[10], ++ oemfru[11], oemfru[12]); ++ seq_printf(seq, ++ " Date : %c%c%c\n", ++ oemfru[13], oemfru[14], oemfru[15]); ++ seq_sprintf(seq, ++ " Sequence # : %c%c%c%c\n", ++ oemfru[16], oemfru[17], oemfru[18], ++ oemfru[19]); ++ break; ++ } ++ ++ case VENDOR3_FRU_FORMAT: ++ { ++ seq_printf(seq, "FRU Information:\n"); ++ } ++ ++ case VENDOR4_FRU_FORMAT: ++ { ++ seq_printf(seq, "FRU Information:\n"); ++ seq_printf(seq, ++ " FRU Number : " ++ "%c%c%c%c%c%c%c%c\n", ++ oemfru[0], oemfru[1], oemfru[2], ++ oemfru[3], oemfru[4], oemfru[5], ++ oemfru[6], oemfru[7]); ++ seq_sprintf(seq, ++ " Part Number : " ++ "%c%c%c%c%c%c%c%c\n", ++ oemfru[8], oemfru[9], oemfru[10], ++ oemfru[11], oemfru[12], oemfru[13], ++ oemfru[14], oemfru[15]); ++ seq_printf(seq, ++ " EC Level : " ++ "%c%c%c%c%c%c%c%c\n", ++ oemfru[16], oemfru[17], oemfru[18], ++ oemfru[19], oemfru[20], oemfru[21], ++ oemfru[22], oemfru[23]); ++ break; ++ } ++ ++ default: ++ break; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int slic_debug_adapter_show(struct seq_file *seq, void *v) ++{ ++ p_adapter_t adapter = seq->private; ++ ++ if ((adapter->netdev) && (adapter->netdev->name)) { ++ seq_printf(seq, "info: interface : %s\n", ++ adapter->netdev->name); ++ } ++ seq_printf(seq, "info: status : %s\n", ++ SLIC_LINKSTATE(adapter->linkstate)); ++ seq_printf(seq, "info: port : %d\n", ++ adapter->physport); ++ seq_printf(seq, "info: speed : %s\n", ++ SLIC_SPEED(adapter->linkspeed)); ++ seq_printf(seq, "info: duplex : %s\n", ++ SLIC_DUPLEX(adapter->linkduplex)); ++ seq_printf(seq, "info: irq : 0x%X\n", ++ (uint) adapter->irq); ++ seq_printf(seq, "info: Interrupt Agg Delay: %d usec\n", ++ adapter->card->loadlevel_current); ++ seq_printf(seq, "info: RcvQ max entries : %4.4X\n", ++ SLIC_RCVQ_ENTRIES); ++ seq_printf(seq, "info: RcvQ current : %4.4X\n", ++ adapter->rcvqueue.count); ++ seq_printf(seq, "rx stats: packets : %8.8lX\n", ++ adapter->stats.rx_packets); ++ seq_printf(seq, "rx stats: bytes : %8.8lX\n", ++ adapter->stats.rx_bytes); ++ seq_printf(seq, "rx stats: broadcasts : %8.8X\n", ++ adapter->rcv_broadcasts); ++ seq_printf(seq, "rx stats: multicasts : %8.8X\n", ++ adapter->rcv_multicasts); ++ seq_printf(seq, "rx stats: unicasts : %8.8X\n", ++ adapter->rcv_unicasts); ++ seq_printf(seq, "rx stats: errors : %8.8X\n", ++ (ulong32) adapter->slic_stats.iface.rcv_errors); ++ seq_printf(seq, "rx stats: Missed errors : %8.8X\n", ++ (ulong32) adapter->slic_stats.iface.rcv_discards); ++ seq_printf(seq, "rx stats: drops : %8.8X\n", ++ (ulong32) adapter->rcv_drops); ++ seq_printf(seq, "tx stats: packets : %8.8lX\n", ++ adapter->stats.tx_packets); ++ seq_printf(seq, "tx stats: bytes : %8.8lX\n", ++ adapter->stats.tx_bytes); ++ seq_printf(seq, "tx stats: errors : %8.8X\n", ++ (ulong32) adapter->slic_stats.iface.xmt_errors); ++ seq_printf(seq, "rx stats: multicasts : %8.8lX\n", ++ adapter->stats.multicast); ++ seq_printf(seq, "tx stats: collision errors : %8.8X\n", ++ (ulong32) adapter->slic_stats.iface.xmit_collisions); ++ seq_printf(seq, "perf: Max rcv frames/isr : %8.8X\n", ++ adapter->max_isr_rcvs); ++ seq_printf(seq, "perf: Rcv interrupt yields : %8.8X\n", ++ adapter->rcv_interrupt_yields); ++ seq_printf(seq, "perf: Max xmit complete/isr : %8.8X\n", ++ adapter->max_isr_xmits); ++ seq_printf(seq, "perf: error interrupts : %8.8X\n", ++ adapter->error_interrupts); ++ seq_printf(seq, "perf: error rmiss interrupts : %8.8X\n", ++ adapter->error_rmiss_interrupts); ++ seq_printf(seq, "perf: rcv interrupts : %8.8X\n", ++ adapter->rcv_interrupts); ++ seq_printf(seq, "perf: xmit interrupts : %8.8X\n", ++ adapter->xmit_interrupts); ++ seq_printf(seq, "perf: link event interrupts : %8.8X\n", ++ adapter->linkevent_interrupts); ++ seq_printf(seq, "perf: UPR interrupts : %8.8X\n", ++ adapter->upr_interrupts); ++ seq_printf(seq, "perf: interrupt count : %8.8X\n", ++ adapter->num_isrs); ++ seq_printf(seq, "perf: false interrupts : %8.8X\n", ++ adapter->false_interrupts); ++ seq_printf(seq, "perf: All register writes : %8.8X\n", ++ adapter->all_reg_writes); ++ seq_printf(seq, "perf: ICR register writes : %8.8X\n", ++ adapter->icr_reg_writes); ++ seq_printf(seq, "perf: ISR register writes : %8.8X\n", ++ adapter->isr_reg_writes); ++ seq_printf(seq, "ifevents: overflow 802 errors : %8.8X\n", ++ adapter->if_events.oflow802); ++ seq_printf(seq, "ifevents: transport overflow errors: %8.8X\n", ++ adapter->if_events.Tprtoflow); ++ seq_printf(seq, "ifevents: underflow errors : %8.8X\n", ++ adapter->if_events.uflow802); ++ seq_printf(seq, "ifevents: receive early : %8.8X\n", ++ adapter->if_events.rcvearly); ++ seq_printf(seq, "ifevents: buffer overflows : %8.8X\n", ++ adapter->if_events.Bufov); ++ seq_printf(seq, "ifevents: carrier errors : %8.8X\n", ++ adapter->if_events.Carre); ++ seq_printf(seq, "ifevents: Long : %8.8X\n", ++ adapter->if_events.Longe); ++ seq_printf(seq, "ifevents: invalid preambles : %8.8X\n", ++ adapter->if_events.Invp); ++ seq_printf(seq, "ifevents: CRC errors : %8.8X\n", ++ adapter->if_events.Crc); ++ seq_printf(seq, "ifevents: dribble nibbles : %8.8X\n", ++ adapter->if_events.Drbl); ++ seq_printf(seq, "ifevents: Code violations : %8.8X\n", ++ adapter->if_events.Code); ++ seq_printf(seq, "ifevents: TCP checksum errors : %8.8X\n", ++ adapter->if_events.TpCsum); ++ seq_printf(seq, "ifevents: TCP header short errors : %8.8X\n", ++ adapter->if_events.TpHlen); ++ seq_printf(seq, "ifevents: IP checksum errors : %8.8X\n", ++ adapter->if_events.IpCsum); ++ seq_printf(seq, "ifevents: IP frame incompletes : %8.8X\n", ++ adapter->if_events.IpLen); ++ seq_printf(seq, "ifevents: IP headers shorts : %8.8X\n", ++ adapter->if_events.IpHlen); ++ ++ return 0; ++} ++static int slic_debug_adapter_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, slic_debug_adapter_show, inode->i_private); ++} ++ ++static int slic_debug_card_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, slic_debug_card_show, inode->i_private); ++} ++ ++static const struct file_operations slic_debug_adapter_fops = { ++ .owner = THIS_MODULE, ++ .open = slic_debug_adapter_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static const struct file_operations slic_debug_card_fops = { ++ .owner = THIS_MODULE, ++ .open = slic_debug_card_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static void slic_debug_adapter_create(p_adapter_t adapter) ++{ ++ struct dentry *d; ++ char name[7]; ++ p_sliccard_t card = adapter->card; ++ ++ if (!card->debugfs_dir) ++ return; ++ ++ sprintf(name, "port%d", adapter->port); ++ d = debugfs_create_file(name, S_IRUGO, ++ card->debugfs_dir, adapter, ++ &slic_debug_adapter_fops); ++ if (!d || IS_ERR(d)) ++ pr_info(PFX "%s: debugfs create failed\n", name); ++ else ++ adapter->debugfs_entry = d; ++} ++ ++static void slic_debug_adapter_destroy(p_adapter_t adapter) ++{ ++ if (adapter->debugfs_entry) { ++ debugfs_remove(adapter->debugfs_entry); ++ adapter->debugfs_entry = NULL; ++ } ++} ++ ++static void slic_debug_card_create(p_sliccard_t card) ++{ ++ struct dentry *d; ++ char name[IFNAMSIZ]; ++ ++ snprintf(name, sizeof(name), "slic%d", card->cardnum); ++ d = debugfs_create_dir(name, slic_debugfs); ++ if (!d || IS_ERR(d)) ++ pr_info(PFX "%s: debugfs create dir failed\n", ++ name); ++ else { ++ card->debugfs_dir = d; ++ d = debugfs_create_file("cardinfo", S_IRUGO, ++ slic_debugfs, card, ++ &slic_debug_card_fops); ++ if (!d || IS_ERR(d)) ++ pr_info(PFX "%s: debugfs create failed\n", ++ name); ++ else ++ card->debugfs_cardinfo = d; ++ } ++} ++ ++static void slic_debug_card_destroy(p_sliccard_t card) ++{ ++ int i; ++ ++ for (i = 0; i < card->card_size; i++) { ++ p_adapter_t adapter; ++ ++ adapter = card->adapter[i]; ++ if (adapter) ++ slic_debug_adapter_destroy(adapter); ++ } ++ if (card->debugfs_cardinfo) { ++ debugfs_remove(card->debugfs_cardinfo); ++ card->debugfs_cardinfo = NULL; ++ } ++ if (card->debugfs_dir) { ++ debugfs_remove(card->debugfs_dir); ++ card->debugfs_dir = NULL; ++ } ++} ++ ++static void slic_debug_init(void) ++{ ++ struct dentry *ent; ++ ++ ent = debugfs_create_dir("slic", NULL); ++ if (!ent || IS_ERR(ent)) { ++ pr_info(PFX "debugfs create directory failed\n"); ++ return; ++ } ++ ++ slic_debugfs = ent; ++} ++ ++static void slic_debug_cleanup(void) ++{ ++ if (slic_debugfs) { ++ debugfs_remove(slic_debugfs); ++ slic_debugfs = NULL; ++ } ++} ++ ++/*============================================================================= ++ ============================================================================= ++ === === ++ === SLIC DUMP MANAGEMENT SECTION === ++ === === ++ === === ++ === Dump routines === ++ === === ++ === === ++ ============================================================================= ++ ============================================================================*/ ++ ++#if SLIC_DUMP_ENABLED ++ ++#include ++ ++pvoid slic_dump_handle; /* thread handle */ ++ ++/* ++ * These are the only things you should do on a core-file: use only these ++ * functions to write out all the necessary info. ++ */ ++static int slic_dump_seek(struct file *SLIChandle, ulong32 file_offset) ++{ ++ if (SLIChandle->f_pos != file_offset) { ++ /*DBG_MSG("slic_dump_seek now needed [%x : %x]\n", ++ (ulong32)SLIChandle->f_pos, (ulong32)file_offset); */ ++ if (SLIChandle->f_op->llseek) { ++ if (SLIChandle->f_op-> ++ llseek(SLIChandle, file_offset, 0) != file_offset) ++ return 0; ++ } else { ++ SLIChandle->f_pos = file_offset; ++ } ++ } ++ return 1; ++} ++ ++static int slic_dump_write(p_sliccard_t card, ++ const void *addr, int size, ulong32 file_offset) ++{ ++ int r = 1; ++ ulong32 result = 0; ++ struct file *SLIChandle = card->dumphandle; ++ ++#ifdef HISTORICAL /* legacy */ ++ down(&SLIChandle->f_dentry->d_inode->i_sem); ++#endif ++ if (size) { ++ slic_dump_seek(SLIChandle, file_offset); ++ ++ result = ++ SLIChandle->f_op->write(SLIChandle, addr, size, ++ &SLIChandle->f_pos); ++ ++ r = result == size; ++ } ++ ++ card->dumptime_complete = jiffies; ++ card->dumptime_delta = card->dumptime_complete - card->dumptime_start; ++ card->dumptime_start = jiffies; ++ ++#ifdef HISTORICAL ++ up(&SLIChandle->f_dentry->d_inode->i_sem); ++#endif ++ if (!r) { ++ DBG_ERROR("%s: addr[%p] size[%x] result[%x] file_offset[%x]\n", ++ __func__, addr, size, result, file_offset); ++ } ++ return r; ++} ++ ++uint slic_init_dump_thread(p_sliccard_t card) ++{ ++ card->dump_task_id = kthread_run(slic_dump_thread, (void *)card, 0); ++ ++/* DBG_MSG("create slic_dump_thread dump_pid[%x]\n", card->dump_pid); */ ++ if (IS_ERR(card->dump_task_id)) { ++ DBG_MSG("create slic_dump_thread FAILED \n"); ++ return STATUS_FAILURE; ++ } ++ ++ return STATUS_SUCCESS; ++} ++ ++int slic_dump_thread(void *context) ++{ ++ p_sliccard_t card = (p_sliccard_t) context; ++ p_adapter_t adapter; ++ p_adapter_t dump_adapter = NULL; ++ ulong32 dump_complete = 0; ++ ulong32 delay = SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL); ++ p_slic_regs_t pregs; ++ ulong32 i; ++ p_slic_upr_t upr, uprnext; ++ ulong32 dump_card; ++ ++ ASSERT(card); ++ ++ card->dumpthread_running = 1; ++ ++#ifdef HISTORICAL ++ lock_kernel(); ++ /* ++ * This thread doesn't need any user-level access, ++ * so get rid of all our resources ++ */ ++ exit_files(current); /* daemonize doesn't do exit_files */ ++ current->files = init_task.files; ++ atomic_inc(¤t->files->count); ++#endif ++ ++ daemonize("%s", "slicmon"); ++ ++ /* Setup a nice name */ ++ strcpy(current->comm, "slicmon"); ++ DBG_ERROR ++ ("slic_dump_thread[slicmon] daemon is alive card[%p] pid[%x]\n", ++ card, card->dump_task_id->pid); ++ ++ /* ++ * Send me a signal to get me to die (for debugging) ++ */ ++ do { ++ /* ++ * If card state is not set to up, skip ++ */ ++ if (card->state != CARD_UP) { ++ if (card->adapters_activated) ++ goto wait; ++ else ++ goto end_thread; ++ } ++ /* ++ * Check the results of our last ping. ++ */ ++ dump_card = 0; ++#ifdef SLIC_FAILURE_DUMP ++ if (card->pingstatus != ISR_PINGMASK) { ++ DBG_MSG ++ ("\n[slicmon] CARD #%d TIMED OUT - status " ++ "%x: DUMP THE CARD!\n", ++ card->cardnum, card->pingstatus); ++ dump_card = 1; ++ } ++#else ++ /* ++ * Cause a card RESET instead? ++ */ ++ if (card->pingstatus != ISR_PINGMASK) { ++ /* todo. do we want to reset the card in production */ ++ /* DBG_MSG("\n[slicmon] CARD #%d TIMED OUT - " ++ status %x: RESET THE CARD!\n", card->cardnum, ++ card->pingstatus); */ ++ DBG_ERROR ++ ("\n[slicmon] CARD #%d TIMED OUT - status %x: " ++ "DUMP THE CARD!\n", ++ card->cardnum, card->pingstatus); ++ dump_card = 1; ++ } ++#endif ++ if ((dump_card) ++ || (card->dump_requested == SLIC_DUMP_REQUESTED)) { ++ if (card->dump_requested == SLIC_DUMP_REQUESTED) { ++ DBG_ERROR ++ ("[slicmon]: Dump card Requested: Card %x\n", ++ card->cardnum); ++ } ++ if (card->pingstatus != ISR_PINGMASK) { ++ ushort cpuid = 0; ++ ushort crashpc = 0; ++ ++ if (card->adapter[0]) { ++ if ((card->adapter[0])->memorylength >= ++ CRASH_INFO_OFFSET + ++ sizeof(slic_crash_info)) { ++ char *crashptr; ++ p_slic_crash_info crashinfo; ++ ++ crashptr = ++ ((char *)card->adapter[0]-> ++ slic_regs) + ++ CRASH_INFO_OFFSET; ++ crashinfo = ++ (p_slic_crash_info) ++ crashptr; ++ cpuid = crashinfo->cpu_id; ++ crashpc = crashinfo->crash_pc; ++ } ++ } ++ DBG_ERROR ++ ("[slicmon]: Dump card: Card %x crashed " ++ "and failed to answer PING. " ++ "CPUID[%x] PC[%x]\n ", ++ card->cardnum, cpuid, crashpc); ++ } ++ ++ card->dump_requested = SLIC_DUMP_IN_PROGRESS; ++ ++ /* ++ * Set the card state to DOWN and the adapter states ++ * to RESET.They will check this in SimbaCheckForHang ++ * and initiate interface reset (which in turn will ++ * reinitialize the card). ++ */ ++ card->state = CARD_DOWN; ++ ++ for (i = 0; i < card->card_size; i++) { ++ adapter = card->adapter[i]; ++ if (adapter) { ++ slic_if_stop_queue(adapter); ++ ++ if (adapter->state == ADAPT_UP) { ++ adapter->state = ADAPT_RESET; ++ adapter->linkstate = LINK_DOWN; ++ DBG_ERROR ++ ("[slicmon]: SLIC Card[%d] " ++ "Port[%d] adapter[%p] " ++ "down\n", ++ (uint) card->cardnum, ++ (uint) i, adapter); ++ } ++#if SLIC_GET_STATS_TIMER_ENABLED ++ /* free stats timer */ ++ if (adapter->statstimerset) { ++ adapter->statstimerset = 0; ++ del_timer(&adapter->statstimer); ++ } ++#endif ++ } ++ } ++ ++ for (i = 0; i < card->card_size; i++) { ++ adapter = card->adapter[i]; ++ if ((adapter) && (adapter->activated)) { ++ pregs = adapter->slic_regs; ++ dump_adapter = adapter; ++ ++ /* ++ * If the dump status is zero, then ++ * the utility processor has crashed. ++ * If this is the case, any pending ++ * utilityprocessor requests will not ++ * complete and our dump commands will ++ * not be issued. ++ * ++ * To avoid this we will clear any ++ * pending utility processor requests ++ * now. ++ */ ++ if (!card->pingstatus) { ++ SLIC_ACQUIRE_IRQ_SPINLOCK ++ (adapter->upr_lock); ++ upr = adapter->upr_list; ++ while (upr) { ++ uprnext = upr->next; ++ SLIC_DEALLOCATE_MEM ++ (upr); ++ upr = uprnext; ++ } ++ adapter->upr_list = 0; ++ adapter->upr_busy = 0; ++ SLIC_RELEASE_IRQ_SPINLOCK ++ (adapter->upr_lock); ++ } ++ ++ slic_dump_card(card, FALSE); ++ dump_complete = 1; ++ } ++ ++ if (dump_complete) { ++ DBG_ERROR("SLIC Dump Complete\n"); ++ /* Only dump the card one time */ ++ break; ++ } ++ } ++ ++ if (dump_adapter) { ++ DBG_ERROR ++ ("slic dump completed. " ++ "Reenable interfaces\n"); ++ slic_card_init(card, dump_adapter); ++ ++ /* ++ * Reenable the adapters that were reset ++ */ ++ for (i = 0; i < card->card_size; i++) { ++ adapter = card->adapter[i]; ++ if (adapter) { ++ if (adapter->state == ++ ADAPT_RESET) { ++ DBG_ERROR ++ ("slicdump: SLIC " ++ "Card[%d] Port[%d] adapter[%p] " ++ "bring UP\n", ++ (uint) card-> ++ cardnum, (uint) i, ++ adapter); ++ adapter->state = ++ ADAPT_DOWN; ++ adapter->linkstate = ++ LINK_DOWN; ++ slic_entry_open ++ (adapter->netdev); ++ } ++ } ++ } ++ ++ card->dump_requested = SLIC_DUMP_DONE; ++ } ++ } else { ++ /* if pingstatus != ISR_PINGMASK) || dump_requested...ELSE ++ * We received a valid ping response. ++ * Clear the Pingstatus field, find a valid adapter ++ * structure and send another ping. ++ */ ++ for (i = 0; i < card->card_size; i++) { ++ adapter = card->adapter[i]; ++ if (adapter && (adapter->state == ADAPT_UP)) { ++ card->pingstatus = 0; ++ slic_upr_request(adapter, SLIC_UPR_PING, ++ 0, 0, 0, 0); ++ break; /* Only issue one per card */ ++ } ++ } ++ } ++wait: ++ SLIC_INTERRUPTIBLE_SLEEP_ON_TIMEOUT(card->dump_wq, delay); ++ } while (!signal_pending(current)); ++ ++end_thread: ++/* DBG_MSG("[slicmon] slic_dump_thread card[%p] pid[%x] ENDING\n", ++ card, card->dump_pid); */ ++ card->dumpthread_running = 0; ++ ++ return 0; ++} ++ ++/* ++ * Read a single byte from our dump index file. This ++ * value is used as our suffix for our dump path. The ++ * value is incremented and written back to the file ++ */ ++uchar slic_get_dump_index(pchar path) ++{ ++ uchar index = 0; ++#ifdef SLIC_DUMP_INDEX_SUPPORT ++ ulong32 status; ++ pvoid FileHandle; ++ ulong32 offset; ++ ++ offset = 0; ++ ++ /* ++ * Open the index file. If one doesn't exist, create it ++ */ ++ status = create_file(&FileHandle); ++ ++ if (status != STATUS_SUCCESS) ++ return (uchar) 0; ++ ++ status = read_file(FileHandle, &index, 1, &offset); ++ ++ index++; ++ ++ status = write_file(FileHandle, &index, 1, &offset); ++ ++ close_file(FileHandle); ++#else ++ index = 0; ++#endif ++ return index; ++} ++ ++struct file *slic_dump_open_file(p_sliccard_t card) ++{ ++ struct file *SLIChandle = NULL; ++ struct dentry *dentry = NULL; ++ struct inode *inode = NULL; ++ char SLICfile[50]; ++ ++ card->dumpfile_fs = get_fs(); ++ ++ set_fs(KERNEL_DS); ++ ++ memset(SLICfile, 0, sizeof(SLICfile)); ++ sprintf(SLICfile, "/var/tmp/slic%d-dump-%d", card->cardnum, ++ (uint) card->dump_count); ++ card->dump_count++; ++ ++ SLIChandle = ++ filp_open(SLICfile, O_CREAT | O_RDWR | O_SYNC | O_LARGEFILE, 0666); ++ ++ DBG_MSG("[slicmon]: Dump Card #%d to file: %s \n", card->cardnum, ++ SLICfile); ++ ++/* DBG_MSG("[slicmon] filp_open %s SLIChandle[%p]\n", SLICfile, SLIChandle);*/ ++ ++ if (IS_ERR(SLIChandle)) ++ goto end_slicdump; ++ ++ dentry = SLIChandle->f_dentry; ++ inode = dentry->d_inode; ++ ++/* DBG_MSG("[slicmon] inode[%p] i_nlink[%x] i_mode[%x] i_op[%p] i_fop[%p]\n" ++ "f_op->write[%p]\n", ++ inode, inode->i_nlink, inode->i_mode, inode->i_op, ++ inode->i_fop, SLIChandle->f_op->write); */ ++ if (inode->i_nlink > 1) ++ goto close_slicdump; /* multiple links - don't dump */ ++#ifdef HISTORICAL ++ if (!S_ISREG(inode->i_mode)) ++ goto close_slicdump; ++#endif ++ if (!inode->i_op || !inode->i_fop) ++ goto close_slicdump; ++ ++ if (!SLIChandle->f_op->write) ++ goto close_slicdump; ++ ++ /* ++ * If we got here we have SUCCESSFULLY OPENED the dump file ++ */ ++/* DBG_MSG("opened %s SLIChandle[%p]\n", SLICfile, SLIChandle); */ ++ return SLIChandle; ++ ++close_slicdump: ++ DBG_MSG("[slicmon] slic_dump_open_file failed close SLIChandle[%p]\n", ++ SLIChandle); ++ filp_close(SLIChandle, NULL); ++ ++end_slicdump: ++ set_fs(card->dumpfile_fs); ++ ++ return NULL; ++} ++ ++void slic_dump_close_file(p_sliccard_t card) ++{ ++ ++/* DBG_MSG("[slicmon] slic_dump_CLOSE_file close SLIChandle[%p]\n", ++ card->dumphandle); */ ++ ++ filp_close(card->dumphandle, NULL); ++ ++ set_fs(card->dumpfile_fs); ++} ++ ++ulong32 slic_dump_card(p_sliccard_t card, boolean resume) ++{ ++ p_adapter_t adapter = card->master; ++ ulong32 status; ++ ulong32 queue; ++ ulong32 len, offset; ++ ulong32 sram_size, dram_size, regs; ++ sliccore_hdr_t corehdr; ++ ulong32 file_offset; ++ pchar namestr; ++ ulong32 i; ++ ulong32 max_queues = 0; ++ ulong32 result; ++ ++ card->dumphandle = slic_dump_open_file(card); ++ ++ if (card->dumphandle == NULL) { ++ DBG_MSG("[slicmon] Cant create Dump file - dump failed\n"); ++ return -ENOMEM; ++ } ++ if (!card->dumpbuffer) { ++ DBG_MSG("[slicmon] Insufficient memory for dump\n"); ++ return -ENOMEM; ++ } ++ if (!card->cmdbuffer) { ++ DBG_MSG("[slicmon] Insufficient cmd memory for dump\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Write the file version to the core header. ++ */ ++ namestr = slic_proc_version; ++ for (i = 0; i < (DRIVER_NAME_SIZE - 1); i++, namestr++) { ++ if (!namestr) ++ break; ++ corehdr.driver_version[i] = *namestr; ++ } ++ corehdr.driver_version[i] = 0; ++ ++ file_offset = sizeof(sliccore_hdr_t); ++ ++ /* ++ * Issue the following debug commands to the SLIC: ++ * - Halt both receive and transmit ++ * - Dump receive registers ++ * - Dump transmit registers ++ * - Dump sram ++ * - Dump dram ++ * - Dump queues ++ */ ++ DBG_MSG("slicDump HALT Receive Processor\n"); ++ card->dumptime_start = jiffies; ++ ++ status = slic_dump_halt(card, PROC_RECEIVE); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR ++ ("Cant halt receive sequencer - dump failed status[%x]\n", ++ status); ++ goto done; ++ } ++ ++ DBG_MSG("slicDump HALT Transmit Processor\n"); ++ status = slic_dump_halt(card, PROC_TRANSMIT); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("Cant halt transmit sequencer - dump failed\n"); ++ goto done; ++ } ++ ++ /* Dump receive regs */ ++ status = slic_dump_reg(card, PROC_RECEIVE); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("Cant dump receive registers - dump failed\n"); ++ goto done; ++ } ++ ++ DBG_MSG("slicDump Write Receive REGS len[%x] offset[%x]\n", ++ (SLIC_NUM_REG * 4), file_offset); ++ ++ result = ++ slic_dump_write(card, card->dumpbuffer, SLIC_NUM_REG * 4, ++ file_offset); ++ if (!result) { ++ DBG_ERROR ++ ("Cant write rcv registers to dump file - dump failed\n"); ++ goto done; ++ } ++ ++ corehdr.RcvRegOff = file_offset; ++ corehdr.RcvRegsize = SLIC_NUM_REG * 4; ++ file_offset += SLIC_NUM_REG * 4; ++ ++ /* Dump transmit regs */ ++ status = slic_dump_reg(card, PROC_TRANSMIT); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("Cant dump transmit registers - dump failed\n"); ++ goto done; ++ } ++ ++ DBG_MSG("slicDump Write XMIT REGS len[%x] offset[%x]\n", ++ (SLIC_NUM_REG * 4), file_offset); ++ ++ result = ++ slic_dump_write(card, card->dumpbuffer, SLIC_NUM_REG * 4, ++ file_offset); ++ if (!result) { ++ DBG_ERROR ++ ("Cant write xmt registers to dump file - dump failed\n"); ++ goto done; ++ } ++ ++ corehdr.XmtRegOff = file_offset; ++ corehdr.XmtRegsize = SLIC_NUM_REG * 4; ++ file_offset += SLIC_NUM_REG * 4; ++ ++ regs = SLIC_GBMAX_REG; ++ ++ corehdr.FileRegOff = file_offset; ++ corehdr.FileRegsize = regs * 4; ++ ++ for (offset = 0; regs;) { ++ len = MIN(regs, 16); /* Can only xfr 16 regs at a time */ ++ ++ status = slic_dump_data(card, offset, (ushort) len, DESC_RFILE); ++ ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("Cant dump register file - dump failed\n"); ++ goto done; ++ } ++ ++ DBG_MSG("slicDump Write RegisterFile len[%x] offset[%x]\n", ++ (len * 4), file_offset); ++ ++ result = ++ slic_dump_write(card, card->dumpbuffer, len * 4, ++ file_offset); ++ if (!result) { ++ DBG_ERROR ++ ("Cant write register file to dump file - " ++ "dump failed\n"); ++ goto done; ++ } ++ ++ file_offset += len * 4; ++ offset += len; ++ regs -= len; ++ } ++ ++ dram_size = card->config.DramSize * 0x10000; ++ ++ switch (adapter->devid) { ++ case SLIC_2GB_DEVICE_ID: ++ sram_size = SLIC_SRAM_SIZE2GB; ++ break; ++ case SLIC_1GB_DEVICE_ID: ++ sram_size = SLIC_SRAM_SIZE1GB; ++ break; ++ default: ++ sram_size = 0; ++ ASSERT(0); ++ break; ++ } ++ ++ corehdr.SramOff = file_offset; ++ corehdr.Sramsize = sram_size; ++ ++ for (offset = 0; sram_size;) { ++ len = MIN(sram_size, DUMP_BUF_SIZE); ++ status = slic_dump_data(card, offset, (ushort) len, DESC_SRAM); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR ++ ("[slicmon] Cant dump SRAM at offset %x - " ++ "dump failed\n", (uint) offset); ++ goto done; ++ } ++ ++ DBG_MSG("[slicmon] slicDump Write SRAM len[%x] offset[%x]\n", ++ len, file_offset); ++ ++ result = ++ slic_dump_write(card, card->dumpbuffer, len, file_offset); ++ if (!result) { ++ DBG_ERROR ++ ("[slicmon] Cant write SRAM to dump file - " ++ "dump failed\n"); ++ goto done; ++ } ++ ++ file_offset += len; ++ offset += len; ++ sram_size -= len; ++ } ++ ++ corehdr.DramOff = file_offset; ++ corehdr.Dramsize = dram_size; ++ ++ for (offset = 0; dram_size;) { ++ len = MIN(dram_size, DUMP_BUF_SIZE); ++ ++ status = slic_dump_data(card, offset, (ushort) len, DESC_DRAM); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR ++ ("[slicmon] Cant dump dram at offset %x - " ++ "dump failed\n", (uint) offset); ++ goto done; ++ } ++ ++ DBG_MSG("slicDump Write DRAM len[%x] offset[%x]\n", len, ++ file_offset); ++ ++ result = ++ slic_dump_write(card, card->dumpbuffer, len, file_offset); ++ if (!result) { ++ DBG_ERROR ++ ("[slicmon] Cant write DRAM to dump file - " ++ "dump failed\n"); ++ goto done; ++ } ++ ++ file_offset += len; ++ offset += len; ++ dram_size -= len; ++ } ++ ++ max_queues = SLIC_MAX_QUEUE; ++ ++ for (queue = 0; queue < max_queues; queue++) { ++ pulong32 qarray = (pulong32) card->dumpbuffer; ++ ulong32 qarray_physl = card->dumpbuffer_physl; ++ ulong32 qarray_physh = card->dumpbuffer_physh; ++ ulong32 qstart; ++ ulong32 qdelta; ++ ulong32 qtotal = 0; ++ ++ DBG_MSG("[slicmon] Start Dump of QUEUE #0x%x\n", (uint) queue); ++ ++ for (offset = 0; offset < (DUMP_BUF_SIZE >> 2); offset++) { ++ qstart = jiffies; ++ qdelta = 0; ++ ++ status = slic_dump_queue(card, ++ qarray_physl, ++ qarray_physh, queue); ++ qarray_physl += 4; ++ ++ if (status != STATUS_SUCCESS) ++ break; ++ ++ if (jiffies > qstart) { ++ qdelta = jiffies - qstart; ++ qtotal += qdelta; ++ } ++ } ++ ++ if (offset) ++ qdelta = qtotal / offset; ++ else ++ qdelta = 0; ++ ++/* DBG_MSG(" slicDump Write QUEUE #0x%x len[%x] offset[%x] " ++ "avgjiffs[%x]\n", queue, (offset*4), file_offset, qdelta); */ ++ ++ result = ++ slic_dump_write(card, card->dumpbuffer, offset * 4, ++ file_offset); ++ ++ if (!result) { ++ DBG_ERROR ++ ("[slicmon] Cant write QUEUES to dump file - " ++ "dump failed\n"); ++ goto done; ++ } ++ ++ corehdr.queues[queue].queueOff = file_offset; ++ corehdr.queues[queue].queuesize = offset * 4; ++ file_offset += offset * 4; ++ ++/* DBG_MSG(" Reload QUEUE #0x%x elements[%x]\n", (uint)queue, offset);*/ ++ /* ++ * Fill the queue back up ++ */ ++ for (i = 0; i < offset; i++) { ++ qstart = jiffies; ++ qdelta = 0; ++ ++ status = slic_dump_load_queue(card, qarray[i], queue); ++ if (status != STATUS_SUCCESS) ++ break; ++ ++ if (jiffies > qstart) { ++ qdelta = jiffies - qstart; ++ qtotal += qdelta; ++ } ++ } ++ ++ if (offset) ++ qdelta = qtotal / offset; ++ else ++ qdelta = 0; ++ ++/* DBG_MSG(" Reload DONE avgjiffs[%x]\n", qdelta); */ ++ ++ resume = 1; ++ } ++ ++ len = SLIC_GB_CAMAB_SZE * 4; ++ status = slic_dump_cam(card, 0, len, DUMP_CAM_A); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("[slicmon] Can't dump CAM_A - dump failed\n"); ++ goto done; ++ } ++ ++ result = slic_dump_write(card, card->dumpbuffer, len, file_offset); ++ if (result) { ++ DBG_ERROR ++ ("[slicmon] Can't write CAM_A data to dump file - " ++ "dump failed\n"); ++ goto done; ++ } ++ corehdr.CamAMOff = file_offset; ++ corehdr.CamASize = len; ++ file_offset += len; ++ ++ len = SLIC_GB_CAMCD_SZE * 4; ++ status = slic_dump_cam(card, 0, len, DUMP_CAM_C); ++ if (status) { ++ DBG_ERROR("[slicmon] Can't dump CAM_C - dump failed\n"); ++ goto done; ++ } ++ ++ result = slic_dump_write(card, card->dumpbuffer, len, file_offset); ++ if (result) { ++ DBG_ERROR ++ ("[slicmon] Can't write CAM_C data to dump file - " ++ "dump failed\n"); ++ goto done; ++ } ++ corehdr.CamCMOff = file_offset; ++ corehdr.CamCSize = len; ++ file_offset += len; ++ ++done: ++ /* ++ * Write out the core header ++ */ ++ file_offset = 0; ++ DBG_MSG("[slicmon] Write CoreHeader len[%x] offset[%x]\n", ++ (uint) sizeof(sliccore_hdr_t), file_offset); ++ ++ result = ++ slic_dump_write(card, &corehdr, sizeof(sliccore_hdr_t), ++ file_offset); ++ DBG_MSG("[slicmon] corehdr xoff[%x] xsz[%x]\n" ++ " roff[%x] rsz[%x] fileoff[%x] filesz[%x]\n" ++ " sramoff[%x] sramsz[%x], dramoff[%x] dramsz[%x]\n" ++ " corehdr_offset[%x]\n", corehdr.XmtRegOff, ++ corehdr.XmtRegsize, corehdr.RcvRegOff, corehdr.RcvRegsize, ++ corehdr.FileRegOff, corehdr.FileRegsize, corehdr.SramOff, ++ corehdr.Sramsize, corehdr.DramOff, corehdr.Dramsize, ++ (uint) sizeof(sliccore_hdr_t)); ++ for (i = 0; i < max_queues; i++) { ++ DBG_MSG("[slicmon] QUEUE 0x%x offset[%x] size[%x]\n", ++ (uint) i, corehdr.queues[i].queueOff, ++ corehdr.queues[i].queuesize); ++ ++ } ++ ++ slic_dump_close_file(card); ++ ++ if (resume) { ++ DBG_MSG("slicDump RESTART RECEIVE and XMIT PROCESSORS\n\n"); ++ slic_dump_resume(card, PROC_RECEIVE); ++ slic_dump_resume(card, PROC_TRANSMIT); ++ } ++ ++ return status; ++} ++ ++ulong32 slic_dump_halt(p_sliccard_t card, uchar proc) ++{ ++ puchar cmd = card->cmdbuffer; ++ ++ *cmd = COMMAND_BYTE(CMD_HALT, 0, proc); ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, 0, 0); ++} ++ ++ulong32 slic_dump_resume(p_sliccard_t card, uchar proc) ++{ ++ puchar cmd = card->cmdbuffer; ++ ++ *cmd = COMMAND_BYTE(CMD_RUN, 0, proc); ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, 0, 0); ++} ++ ++ulong32 slic_dump_reg(p_sliccard_t card, uchar proc) ++{ ++ pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ ++ dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, proc); ++ dump->desc = DESC_REG; ++ dump->count = 0; ++ dump->addr = 0; ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, ++ card->dumpbuffer_physl, ++ card->dumpbuffer_physh); ++} ++ ++ulong32 slic_dump_data(p_sliccard_t card, ++ ulong32 addr, ushort count, uchar desc) ++{ ++ pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ ++ dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, PROC_RECEIVE); ++ dump->desc = desc; ++ dump->count = count; ++ dump->addr = addr; ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, ++ card->dumpbuffer_physl, ++ card->dumpbuffer_physh); ++} ++ ++ulong32 slic_dump_queue(p_sliccard_t card, ++ ulong32 addr, ulong32 buf_physh, ulong32 queue) ++{ ++ pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ ++ dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, PROC_RECEIVE); ++ dump->desc = DESC_QUEUE; ++ dump->count = 1; ++ dump->addr = queue; ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, ++ addr, card->dumpbuffer_physh); ++} ++ ++ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue) ++{ ++ pdump_cmd_t load = (pdump_cmd_t) card->cmdbuffer; ++ ++ load->cmd = COMMAND_BYTE(CMD_LOAD, 0, PROC_RECEIVE); ++ load->desc = DESC_QUEUE; ++ load->count = (ushort) queue; ++ load->addr = data; ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, 0, 0); ++} ++ ++ulong32 slic_dump_cam(p_sliccard_t card, ++ ulong32 addr, ulong32 count, uchar desc) ++{ ++ pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ ++ dump->cmd = COMMAND_BYTE(CMD_CAM_OPS, 0, PROC_NONE); ++ dump->desc = desc; ++ dump->count = count; ++ dump->addr = 0; ++ ++ return slic_dump_send_cmd(card, ++ card->cmdbuffer_physl, ++ card->cmdbuffer_physh, ++ addr, card->dumpbuffer_physh); ++} ++ ++ulong32 slic_dump_send_cmd(p_sliccard_t card, ++ ulong32 cmd_physl, ++ ulong32 cmd_physh, ++ ulong32 buf_physl, ulong32 buf_physh) ++{ ++ ulong timeout = SLIC_MS_TO_JIFFIES(500); /* 500 msec */ ++ ulong32 attempts = 5; ++ ulong32 delay = SLIC_MS_TO_JIFFIES(10); /* 10 msec */ ++ p_adapter_t adapter = card->master; ++ ++ ASSERT(adapter); ++ do { ++ /* ++ * Zero the Dumpstatus field of the adapter structure ++ */ ++ card->dumpstatus = 0; ++ /* ++ * Issue the dump command via a utility processor request. ++ * ++ * Kludge: We use the Informationbuffer parameter to hold ++ * the buffer address ++ */ ++ slic_upr_request(adapter, SLIC_UPR_DUMP, cmd_physl, cmd_physh, ++ buf_physl, buf_physh); ++ ++ timeout += jiffies; ++ /* ++ * Spin until completion or timeout. ++ */ ++ while (!card->dumpstatus) { ++ int num_sleeps = 0; ++ ++ if (jiffies > timeout) { ++ /* ++ * Complete the timed-out DUMP UPR request. ++ */ ++ slic_upr_request_complete(adapter, 0); ++ DBG_ERROR ++ ("%s: TIMED OUT num_sleeps[%x] " ++ "status[%x]\n", ++ __func__, num_sleeps, STATUS_FAILURE); ++ ++ return STATUS_FAILURE; ++ } ++ num_sleeps++; ++ SLIC_INTERRUPTIBLE_SLEEP_ON_TIMEOUT(card->dump_wq, ++ delay); ++ } ++ ++ if (card->dumpstatus & ISR_UPCERR) { ++ /* ++ * Error (or queue empty) ++ */ ++/* DBG_ERROR("[slicmon] %s: DUMP_STATUS & ISR_UPCERR status[%x]\n", ++ __func__, STATUS_FAILURE); */ ++ ++ return STATUS_FAILURE; ++ } else if (card->dumpstatus & ISR_UPCBSY) { ++ /* ++ * Retry ++ */ ++ DBG_ERROR("%s: ISR_UPCBUSY attempt[%x]\n", __func__, ++ attempts); ++ ++ attempts--; ++ } else { ++ /* ++ * success ++ */ ++ return STATUS_SUCCESS; ++ } ++ ++ } while (attempts); ++ ++ DBG_ERROR("%s: GAVE UP AFTER SEVERAL ATTEMPTS status[%x]\n", ++ __func__, STATUS_FAILURE); ++ ++ /* ++ * Gave up after several attempts ++ */ ++ return STATUS_FAILURE; ++} ++ ++#endif ++/*============================================================================= ++ ============================================================================= ++ === === ++ === *** END **** END **** END **** END *** === ++ === SLIC DUMP MANAGEMENT SECTION === ++ === === ++ === === ++ === === ++ ============================================================================= ++ ============================================================================*/ ++ ++/******************************************************************************/ ++/**************** MODULE INITIATION / TERMINATION FUNCTIONS ***************/ ++/******************************************************************************/ ++ ++static struct pci_driver slic_driver = { ++ .name = DRV_NAME, ++ .id_table = slic_pci_tbl, ++ .probe = slic_entry_probe, ++ .remove = slic_entry_remove, ++#if SLIC_POWER_MANAGEMENT_ENABLED ++ .suspend = slicpm_suspend, ++ .resume = slicpm_resume, ++#endif ++/* .shutdown = slic_shutdown, MOOK_INVESTIGATE */ ++}; ++ ++static int __init slic_module_init(void) ++{ ++ struct pci_device_id *pcidev; ++ int ret; ++ ++/* DBG_MSG("slicoss: %s ENTER cpu %d\n", __func__, smp_processor_id()); */ ++ ++ slic_init_driver(); ++ ++ if (debug >= 0 && slic_debug != debug) ++ printk(SLICLEVEL "slicoss: debug level is %d.\n", debug); ++ if (debug >= 0) ++ slic_debug = debug; ++ ++ pcidev = (struct pci_device_id *)slic_driver.id_table; ++/* DBG_MSG("slicoss: %s call pci_module_init jiffies[%lx] cpu #%d\n", ++ __func__, jiffies, smp_processor_id()); */ ++ ++ ret = pci_register_driver(&slic_driver); ++ ++/* DBG_MSG("slicoss: %s EXIT after call pci_module_init jiffies[%lx] " ++ "cpu #%d status[%x]\n",__func__, jiffies, ++ smp_processor_id(), ret); */ ++ ++ return ret; ++} ++ ++static void __exit slic_module_cleanup(void) ++{ ++/* DBG_MSG("slicoss: %s ENTER\n", __func__); */ ++ pci_unregister_driver(&slic_driver); ++ slic_debug_cleanup(); ++/* DBG_MSG("slicoss: %s EXIT\n", __func__); */ ++} ++ ++module_init(slic_module_init); ++module_exit(slic_module_cleanup); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0007-Staging-add-sxg-network-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0007-Staging-add-sxg-network-driver.patch new file mode 100644 index 000000000..64b5e15d0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0007-Staging-add-sxg-network-driver.patch @@ -0,0 +1,11643 @@ +From 5db6b777f68603bf5a9eab891d83413ad894a074 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 21 Aug 2008 14:04:55 -0700 +Subject: [PATCH 07/23] Staging: add sxg network driver +Patch-mainline: 2.6.28 + +This is the first rough cut at a driver for the Alacritech SLIC +Technology Non-Accelerated 10Gbe network driver + +TODO: + - lindent the code + - remove typedefs + - remove wrappers + - checkpatch.pl cleanups + - new functionality that the card needs + +Cc: Christopher Harrer +Cc: Michael Miles +Cc: Christopher Harrer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/sxg/Kconfig | 10 + drivers/staging/sxg/Makefile | 1 + drivers/staging/sxg/README | 13 + drivers/staging/sxg/saharadbgdownload.h | 4854 ++++++++++++++++++++++++++++++++ + drivers/staging/sxg/sxg.c | 3608 +++++++++++++++++++++++ + drivers/staging/sxg/sxg.h | 773 +++++ + drivers/staging/sxg/sxg_os.h | 154 + + drivers/staging/sxg/sxgdbg.h | 190 + + drivers/staging/sxg/sxghif.h | 861 +++++ + drivers/staging/sxg/sxghw.h | 734 ++++ + drivers/staging/sxg/sxgphycode.h | 349 ++ + 13 files changed, 11550 insertions(+) + create mode 100644 drivers/staging/sxg/Kconfig + create mode 100644 drivers/staging/sxg/Makefile + create mode 100644 drivers/staging/sxg/README + create mode 100644 drivers/staging/sxg/saharadbgdownload.h + create mode 100644 drivers/staging/sxg/sxg.c + create mode 100644 drivers/staging/sxg/sxg.h + create mode 100644 drivers/staging/sxg/sxg_os.h + create mode 100644 drivers/staging/sxg/sxgdbg.h + create mode 100644 drivers/staging/sxg/sxghif.h + create mode 100644 drivers/staging/sxg/sxghw.h + create mode 100644 drivers/staging/sxg/sxgphycode.h + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -27,4 +27,6 @@ source "drivers/staging/et131x/Kconfig" + + source "drivers/staging/slicoss/Kconfig" + ++source "drivers/staging/sxg/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -2,3 +2,4 @@ + + obj-$(CONFIG_ET131X) += et131x/ + obj-$(CONFIG_SLICOSS) += slicoss/ ++obj-$(CONFIG_SXG) += sxg/ +--- /dev/null ++++ b/drivers/staging/sxg/Kconfig +@@ -0,0 +1,10 @@ ++config SXG ++ tristate "Alacritech SLIC Technology Non-Accelerated 10Gbe support" ++ depends on PCI && NETDEV_10000 ++ default n ++ help ++ This driver supports the Alacritech SLIC Technology Non-Accelerated ++ 10Gbe network cards. ++ ++ To compile this driver as a module, choose ++ M here: the module will be called sxg. +--- /dev/null ++++ b/drivers/staging/sxg/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_SXG) += sxg.o +--- /dev/null ++++ b/drivers/staging/sxg/README +@@ -0,0 +1,13 @@ ++This is the rough cut at a driver for the Alacritech SLIC Technology ++Non-Accelerated 10Gbe network driver. ++ ++TODO: ++ - lindent the code ++ - remove typedefs ++ - remove wrappers ++ - checkpatch.pl cleanups ++ - new functionality that the card needs ++ ++Please send patches to: ++ Greg Kroah-Hartman ++for any cleanups that you do to this driver. +--- /dev/null ++++ b/drivers/staging/sxg/saharadbgdownload.h +@@ -0,0 +1,4854 @@ ++#define SAHARA_UCODE_VERS_STRING "$Revision: 1.1 $" ++#define SAHARA_UCODE_VERS_DATE "$Date: 2008/06/27 12:58:27 $" ++#define SAHARA_UCODE_HOSTIF_ID 3 ++ ++static u32 SNumSections = 0x2; ++static u32 SSectionSize[] = ++{ ++ 0x0000e274, 0x0000000c, ++}; ++ ++static u32 SSectionStart[] = ++{ ++ 0x00000000, 0x00001fff, ++}; ++ ++static unsigned char SaharaUCode[2][57972] = ++{ ++{ ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0x4d, 0x29, 0x3a, ++ 0x00, 0x00, 0xb2, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x40, 0x2b, 0x92, ++ 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x98, 0x1e, 0x80, 0xe9, 0x9a, ++ 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x0f, 0x80, 0x28, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x80, 0x01, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x00, 0x02, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x40, 0x02, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x80, 0x02, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x00, 0x03, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x40, 0x03, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0x80, 0x03, 0x92, ++ 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x0f, 0xc0, 0x03, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x5f, 0x3f, 0x00, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x42, 0xff, 0xfc, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x12, 0x80, 0xfd, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x8a, 0x11, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0x8d, 0xfd, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x12, 0x80, 0xfd, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0xc0, 0x01, 0x32, ++ 0x38, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x84, 0x82, 0x4d, 0x28, 0x1a, ++ 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x60, 0x5f, 0x0a, 0xf6, 0x94, ++ 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x80, 0x18, 0x92, ++ 0x00, 0x00, 0xd2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x20, 0x92, ++ 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x21, 0x92, ++ 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x21, 0x92, ++ 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x85, 0x21, 0x90, ++ 0x00, 0x00, 0x4b, 0x03, 0x00, 0x00, 0x00, 0xec, 0x02, 0xc0, 0x22, 0x92, ++ 0x00, 0x00, 0x43, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x40, 0x18, 0x9d, ++ 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8b, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x21, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xe8, 0x02, 0x00, 0x90, 0x72, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xb2, 0x00, 0xe9, 0xb6, ++ 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x7c, 0x1e, 0xc0, 0xe7, 0x9a, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x13, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0x08, 0xb8, 0x01, 0x00, 0x94, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb3, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0xb0, 0x03, 0xb2, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x17, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x69, 0x05, 0x00, 0x10, 0x01, 0xf8, 0x02, 0x00, 0x6e, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x0a, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00, 0xb2, ++ 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x40, 0x18, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x2b, 0x32, ++ 0x00, 0x00, 0x57, 0x00, 0x80, 0x01, 0x00, 0x80, 0x12, 0x81, 0xfc, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x2b, 0xbc, ++ 0x02, 0x00, 0x57, 0x00, 0xb0, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0xb9, ++ 0x00, 0x00, 0x5a, 0x00, 0x04, 0x01, 0x00, 0x80, 0x02, 0xc0, 0xb0, 0xbc, ++ 0x00, 0x00, 0x60, 0x00, 0xa0, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x5c, 0x00, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x4a, 0xd0, 0xb6, ++ 0x00, 0x00, 0x60, 0x00, 0xa0, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0xcd, 0x4a, 0xd0, 0x34, ++ 0x00, 0x00, 0xfa, 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xd2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x54, 0x00, 0x03, 0x01, 0x00, 0xb0, 0x02, 0x40, 0x18, 0xbd, ++ 0x08, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xa3, 0x40, 0x01, 0x99, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x16, 0x32, ++ 0x00, 0x00, 0x67, 0x00, 0x03, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x80, 0xbd, ++ 0x00, 0x00, 0x76, 0x00, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0x39, ++ 0x76, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x6b, 0x00, 0x12, 0x01, 0x00, 0x5c, 0x08, 0x80, 0x22, 0xb2, ++ 0x00, 0x00, 0x65, 0x00, 0x04, 0x01, 0x00, 0x80, 0x82, 0x85, 0x80, 0xbc, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0x63, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x68, 0x8b, 0x80, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb8, 0xff, 0x85, 0x30, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x21, 0xff, 0x38, ++ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x4d, 0x80, 0x3a, ++ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x0d, 0x80, 0x3a, ++ 0x00, 0xc4, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x54, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x12, 0x80, 0x2d, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x48, 0x41, 0x80, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x86, 0x98, 0x67, 0xc0, 0x82, 0x3a, ++ 0x00, 0x00, 0x63, 0x00, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x62, 0x8b, 0x80, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x12, 0x80, 0x2d, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x08, 0x80, 0x70, 0x32, ++ 0x00, 0x00, 0x7c, 0x00, 0x90, 0x99, 0x86, 0x2c, 0x28, 0xde, 0x82, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x18, 0xc0, 0x82, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x08, 0xc5, 0x82, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0xc5, 0x82, 0xbc, ++ 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x08, 0x68, 0x8b, 0x80, 0x94, ++ 0x08, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x40, 0x01, 0x99, ++ 0x08, 0x00, 0x38, 0x03, 0x0c, 0x00, 0x00, 0xf8, 0x53, 0x40, 0x01, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x05, 0x80, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x02, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x3d, 0x32, ++ 0x00, 0x00, 0x7e, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x80, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x59, 0x00, 0x80, 0xd7, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x62, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0x3a, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0x3a, 0x80, 0xbc, ++ 0x00, 0x90, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x0d, 0x80, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x32, ++ 0x02, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x0d, 0x80, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x54, 0x02, 0xa4, 0x38, 0xb2, ++ 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2c, 0x08, 0x00, 0x37, 0x32, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x08, 0x80, 0x72, 0x32, ++ 0x00, 0x00, 0x96, 0x00, 0x9f, 0x00, 0x00, 0x5c, 0x08, 0x00, 0x72, 0xb2, ++ 0x87, 0x00, 0x95, 0x00, 0x80, 0x01, 0x00, 0x80, 0x82, 0xcd, 0x85, 0xb0, ++ 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd8, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x88, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0x9e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x52, 0x7d, 0x80, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x80, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0x05, 0x80, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0xc0, 0xf5, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x02, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0x04, 0x00, 0x00, 0xdc, 0x43, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0x9a, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x0f, 0x97, 0x00, 0x04, 0x00, 0x00, 0x80, 0x82, 0xcd, 0x85, 0xb0, ++ 0x10, 0x00, 0xa5, 0x00, 0x87, 0x00, 0x00, 0x78, 0x79, 0x21, 0x16, 0xb8, ++ 0x01, 0x00, 0xa5, 0x00, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x97, 0xbc, ++ 0x87, 0x00, 0xaf, 0x00, 0x87, 0x00, 0x00, 0x78, 0x89, 0xcd, 0x85, 0xb0, ++ 0x00, 0x00, 0xa4, 0x00, 0x04, 0x01, 0x00, 0x80, 0x12, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd8, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x88, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0xaf, 0x00, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc0, 0x85, 0xb6, ++ 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x98, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0xad, 0x00, 0x80, 0x01, 0x00, 0x80, 0xd2, 0xc1, 0x82, 0xb6, ++ 0x00, 0x00, 0xaf, 0x00, 0x80, 0x01, 0x00, 0x80, 0x72, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xa8, 0x42, 0x3d, 0x72, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x18, 0x99, 0xb1, 0xf2, 0xc0, 0x7c, 0x30, ++ 0x00, 0x00, 0xd6, 0x00, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0xc1, 0x82, 0xb6, ++ 0x00, 0x00, 0xa9, 0x00, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x32, ++ 0x80, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x80, 0xc2, 0xcd, 0x85, 0x30, ++ 0x00, 0x00, 0xc6, 0x00, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0xcd, 0x85, 0x30, ++ 0x80, 0x00, 0xc6, 0x00, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0x97, 0xbc, ++ 0xa0, 0x00, 0xc6, 0x00, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0x97, 0xbc, ++ 0x00, 0x00, 0xbd, 0x00, 0x80, 0x01, 0x00, 0x80, 0x62, 0x80, 0xfc, 0xb6, ++ 0x87, 0x00, 0xbd, 0x00, 0x87, 0x00, 0x00, 0x78, 0x89, 0xcd, 0x85, 0xb0, ++ 0x00, 0x00, 0xb9, 0x00, 0x04, 0x00, 0x00, 0x80, 0x12, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0xbd, 0x00, 0x04, 0x01, 0x00, 0x80, 0x22, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0xbd, 0x00, 0x80, 0x01, 0x00, 0x80, 0x72, 0xc1, 0x85, 0xb6, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x79, 0x61, 0x16, 0x38, ++ 0x00, 0x00, 0xc4, 0x00, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xb8, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0xc4, 0x00, 0x80, 0x01, 0x00, 0x80, 0x52, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0xc4, 0x00, 0x80, 0x00, 0x00, 0x80, 0x72, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xc4, 0x00, 0x80, 0x01, 0x00, 0x80, 0x02, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xc4, 0x00, 0x80, 0x01, 0x00, 0x80, 0xd2, 0xc1, 0x85, 0xb6, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x79, 0xe1, 0x16, 0x38, ++ 0x00, 0x00, 0xc4, 0x00, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xc8, 0xc1, 0x82, 0x94, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x04, 0x32, ++ 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xa8, 0xc1, 0x82, 0x94, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x79, 0x21, 0x17, 0x38, ++ 0x00, 0x00, 0xd6, 0x00, 0x04, 0x00, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0xd6, 0x00, 0x04, 0x01, 0x00, 0x80, 0x22, 0x80, 0x97, 0xbc, ++ 0x1f, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x89, 0x8d, 0x72, 0x30, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa9, 0xdc, 0x17, 0x38, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x22, 0x00, 0x90, 0x37, ++ 0x00, 0x00, 0xd6, 0x00, 0x80, 0x00, 0x86, 0x80, 0x22, 0x24, 0x7c, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x05, 0x80, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x80, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0x05, 0x80, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x02, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0x04, 0x00, 0x00, 0xdc, 0x43, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0xd2, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x59, 0x00, 0x80, 0xd7, ++ 0x00, 0x00, 0xdd, 0x00, 0x12, 0x01, 0x00, 0x60, 0x08, 0x40, 0x23, 0xb2, ++ 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x80, 0xd2, ++ 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0xc0, 0xf5, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x24, 0x08, 0x00, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x20, 0x08, 0xc0, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x18, 0x08, 0x80, 0x23, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x02, 0x32, ++ 0x00, 0x00, 0xe4, 0x00, 0x04, 0x00, 0x00, 0xdc, 0x43, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0xe0, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0xc0, 0xf4, 0x00, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0xc0, 0xf5, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x38, 0x02, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x05, 0x80, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x80, 0xd0, ++ 0x00, 0x00, 0xa4, 0x03, 0x12, 0x01, 0x00, 0x68, 0x02, 0x05, 0x80, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x78, 0x09, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x29, 0xc1, 0x72, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x07, 0x00, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x07, 0x80, 0x97, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x17, 0x20, 0x90, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xc0, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0xff, 0x00, 0x80, 0x01, 0x00, 0x80, 0xa2, 0xc1, 0x82, 0xb6, ++ 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x57, 0x00, 0x80, 0x97, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0xa0, 0x04, 0x39, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0x40, 0x82, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0x05, 0x80, 0xb0, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x80, 0xd0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x05, 0x80, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0x08, 0xe8, 0x81, 0x80, 0x34, ++ 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x45, 0x90, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x12, 0x00, 0x28, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x11, 0x01, 0xf0, 0x01, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x59, 0xc0, 0x6e, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x78, 0x19, 0xc0, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x4e, 0x04, 0x01, 0xec, 0x06, 0xbd, 0x97, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf4, 0x1e, 0x40, 0xef, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x09, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x36, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x77, 0xc0, 0x29, 0x37, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x17, 0x3d, 0x90, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0xf4, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x83, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x72, 0x00, 0x2b, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x3d, 0x32, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0xa4, 0x01, 0x80, 0x38, 0x00, 0x80, 0x22, 0xc0, 0x72, 0xb6, ++ 0x00, 0x00, 0x27, 0x01, 0x12, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x20, 0xb2, ++ 0x00, 0x00, 0x2c, 0x01, 0x12, 0x01, 0x00, 0x5c, 0x08, 0x80, 0x20, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x02, 0x80, 0x2c, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0xff, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x72, 0x00, 0x85, 0x30, ++ 0x00, 0x00, 0x89, 0x01, 0x04, 0x00, 0x00, 0xdc, 0x43, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0x28, 0x01, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xcd, 0x85, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x24, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x6c, 0x08, 0x00, 0x72, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4c, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x20, 0x00, 0x18, 0x08, 0x00, 0x72, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x28, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x00, 0x00, 0x80, 0x52, 0xbd, 0x82, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x30, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x08, 0x80, 0x82, 0x32, ++ 0x00, 0x00, 0x3d, 0x01, 0x06, 0x00, 0x00, 0x80, 0x62, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x3c, 0x00, 0x14, 0x28, 0x80, 0x72, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x06, 0x32, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x77, 0x4a, 0x09, 0x39, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x19, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x64, 0x01, 0x04, 0x38, 0x00, 0x78, 0xd9, 0xc5, 0x72, 0xb0, ++ 0x00, 0x00, 0x41, 0x01, 0x80, 0x01, 0x00, 0x80, 0x02, 0x80, 0x97, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x43, 0x01, 0x80, 0x01, 0x00, 0x80, 0x12, 0x80, 0x97, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x92, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x3c, 0xb8, 0x1c, 0x17, 0x38, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x28, 0xc0, 0x83, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x2c, 0x08, 0xc0, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xb8, 0xe0, 0x83, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0xcb, 0x29, 0x00, 0x20, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x63, 0x01, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x78, 0xa0, 0x81, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd8, 0xe0, 0x81, 0x3c, ++ 0x00, 0x00, 0x51, 0x01, 0x06, 0x3a, 0x00, 0x80, 0xb2, 0x5c, 0x83, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x89, 0xc1, 0x72, 0x37, ++ 0x07, 0x00, 0x50, 0x01, 0x2b, 0x01, 0x00, 0x04, 0x79, 0x0a, 0x04, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x04, 0x19, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x54, 0x01, 0x00, 0x3a, 0x00, 0x2c, 0x07, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x2c, 0xd7, 0xe0, 0x72, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x64, 0x83, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0x73, 0x01, 0x04, 0x00, 0x00, 0x28, 0xd8, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x20, 0x80, 0x3a, ++ 0x00, 0x00, 0x5e, 0x01, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0xd7, 0x10, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x41, 0x90, 0xf4, ++ 0x00, 0x00, 0x61, 0x01, 0x04, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0xbc, ++ 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0x9a, ++ 0x00, 0x00, 0x84, 0x10, 0x00, 0x00, 0x00, 0x44, 0x08, 0x80, 0x2d, 0xf2, ++ 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0xcb, 0x19, 0x00, 0x20, 0x07, 0x00, 0x00, 0x32, ++ 0x07, 0x00, 0x66, 0x01, 0x2b, 0x01, 0x00, 0x04, 0x79, 0x0a, 0x02, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x04, 0x19, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0xa7, 0xa0, 0x81, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0x73, 0x01, 0x04, 0x00, 0x00, 0x28, 0xd8, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x62, 0x60, 0x83, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x20, 0x80, 0x3a, ++ 0x00, 0x00, 0x70, 0x01, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0xd7, 0x10, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x41, 0x90, 0xf4, ++ 0x00, 0x00, 0x84, 0x10, 0x00, 0x00, 0x00, 0x44, 0x08, 0x80, 0x2d, 0xf2, ++ 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x09, 0x80, 0x73, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x08, 0x89, 0x80, 0x73, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x86, 0x32, ++ 0x41, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x8c, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x7f, 0x01, 0x29, 0x08, 0x00, 0x80, 0x07, 0xc0, 0x85, 0xb2, ++ 0x00, 0x00, 0x82, 0x01, 0x28, 0x10, 0x00, 0x8c, 0x07, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x83, 0x01, 0x00, 0x12, 0x00, 0x84, 0x07, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x8c, 0xf7, 0xe0, 0x82, 0x3a, ++ 0x00, 0x00, 0x82, 0x01, 0x28, 0x18, 0x00, 0x80, 0x07, 0x40, 0x90, 0xb2, ++ 0x00, 0x00, 0x83, 0x01, 0x00, 0x12, 0x00, 0x84, 0x07, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x84, 0x27, 0xe4, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x72, 0x00, 0x85, 0x30, ++ 0x00, 0x00, 0x87, 0x01, 0x04, 0x00, 0x00, 0xdc, 0x43, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0x83, 0x01, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x52, 0x81, 0x2c, 0xb4, ++ 0x00, 0x00, 0x89, 0x01, 0xf2, 0x01, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x8a, 0x01, 0xf0, 0x01, 0x00, 0x08, 0x38, 0x81, 0x80, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf4, 0x1e, 0x40, 0xef, 0x3c, ++ 0x00, 0x00, 0x93, 0x01, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x3b, 0x32, ++ 0x00, 0x00, 0x8e, 0x01, 0xb9, 0x00, 0x00, 0x78, 0xc9, 0x3b, 0x3a, 0xbc, ++ 0x00, 0x00, 0x92, 0x01, 0x02, 0x00, 0x00, 0x80, 0x82, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0xe2, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0xf0, 0x0e, 0x00, 0x3a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xba, 0x83, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xbd, 0x97, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0xf4, 0xbd, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x97, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x80, 0x83, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x22, 0x7a, 0xe8, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xe8, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0xc0, 0x29, 0x37, ++ 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x0d, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0xe8, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0xe8, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0x12, 0x01, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x08, 0x80, 0x72, 0x32, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x54, 0xa8, 0x5c, 0x16, 0x38, ++ 0x0b, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x2c, 0xa8, 0xdc, 0x16, 0x38, ++ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x88, 0x4d, 0x85, 0x3a, ++ 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x38, 0x00, 0x14, 0xa9, 0x9c, 0x87, 0xd9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x24, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x6c, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4c, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x20, 0x00, 0x18, 0x08, 0x00, 0x72, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x30, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x3c, 0x00, 0x14, 0x18, 0x80, 0x72, 0xbc, ++ 0x00, 0x00, 0xbb, 0x01, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x06, 0x32, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x77, 0x4a, 0x09, 0x39, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x19, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x78, 0xc0, 0x29, 0x37, ++ 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x88, 0x4d, 0x86, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x77, 0xa0, 0x81, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x40, 0x86, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0xd6, 0x01, 0x04, 0x00, 0x00, 0x1c, 0xd8, 0xe0, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xd8, 0x60, 0x86, 0x3a, ++ 0x00, 0x00, 0xca, 0x01, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0x02, 0xc0, 0x38, 0xb2, ++ 0x00, 0x00, 0xd2, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xd0, 0x01, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xcb, 0x01, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0xd4, 0x01, 0x04, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0xbc, ++ 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0x9a, ++ 0x00, 0x00, 0x32, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x08, 0x80, 0x2d, 0xf2, ++ 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xdc, 0x01, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xd7, 0x01, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0xe8, 0x01, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x84, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x22, 0x40, 0x85, 0x3a, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x40, 0x88, 0xcd, 0x74, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x28, 0x00, 0x84, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x32, ++ 0x14, 0x00, 0xe8, 0x01, 0x04, 0x00, 0x00, 0x1c, 0x88, 0x0d, 0x84, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x61, 0x85, 0x3a, ++ 0x80, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xd8, 0x60, 0x86, 0x3a, ++ 0x00, 0x00, 0xd2, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0xea, 0x01, 0x04, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0xbc, ++ 0x00, 0x00, 0xec, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0x9a, ++ 0x00, 0x00, 0x32, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x08, 0x80, 0x2d, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x22, 0xc0, 0x82, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb8, 0x60, 0x85, 0x3c, ++ 0x04, 0x00, 0xf2, 0x01, 0x81, 0x00, 0x00, 0x60, 0x88, 0xcd, 0x74, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x28, 0xf8, 0xa0, 0x75, 0x3c, ++ 0x00, 0x00, 0xf3, 0x01, 0x00, 0x08, 0x00, 0x74, 0x08, 0x80, 0x75, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x28, 0xf8, 0xa0, 0x75, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x08, 0xa1, 0x82, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xf2, 0x60, 0x2a, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x08, 0x00, 0x75, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x7c, 0x08, 0x80, 0x75, 0x32, ++ 0x09, 0x00, 0xf9, 0x01, 0x04, 0x1a, 0x00, 0x70, 0x88, 0xcd, 0x74, 0xb0, ++ 0x09, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x4c, 0x87, 0xcd, 0x74, 0x31, ++ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x88, 0x4d, 0x86, 0x31, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0x40, 0x86, 0x3a, ++ 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x82, 0xd2, ++ 0x00, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x20, 0xb2, ++ 0x00, 0x00, 0x01, 0x02, 0x12, 0x01, 0x00, 0x5c, 0x08, 0x80, 0x20, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x02, 0x80, 0x2c, 0xb2, ++ 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x40, 0x00, 0x32, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xcd, 0x85, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xe8, 0xa1, 0x82, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x22, 0xc0, 0x82, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x08, 0xe1, 0x81, 0x3a, ++ 0x00, 0x00, 0x0b, 0x02, 0x04, 0x01, 0x00, 0x80, 0x42, 0x00, 0x86, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x58, 0x07, 0x40, 0x87, 0x32, ++ 0x00, 0x00, 0x0a, 0x02, 0x8f, 0x01, 0x00, 0x74, 0x18, 0x40, 0x87, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x0d, 0x02, 0x00, 0x04, 0x00, 0x58, 0xf7, 0xa0, 0x86, 0x9a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf9, 0xa0, 0x86, 0x3a, ++ 0x28, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x58, 0x87, 0x8d, 0x97, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x22, 0x40, 0x85, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x50, 0x07, 0x80, 0x84, 0x32, ++ 0x00, 0x00, 0x11, 0x02, 0x04, 0x01, 0x00, 0x80, 0x72, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x4c, 0xc7, 0xe1, 0x74, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x78, 0xa0, 0x84, 0x3a, ++ 0x00, 0x00, 0x14, 0x02, 0x90, 0x01, 0x00, 0x78, 0xf9, 0xa1, 0x86, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x80, 0x97, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x58, 0x07, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x58, 0xa1, 0x86, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x60, 0x85, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0x86, 0x32, ++ 0x00, 0x00, 0x1a, 0x02, 0x12, 0x00, 0x00, 0x4c, 0x02, 0xc0, 0x38, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x84, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x57, 0x21, 0x80, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x57, 0x61, 0x86, 0x3a, ++ 0x00, 0x00, 0x1f, 0x02, 0x12, 0x00, 0x00, 0x4c, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x80, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0xc0, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xcb, 0x19, 0x00, 0x20, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x21, 0x80, 0x3a, ++ 0x07, 0x00, 0x27, 0x02, 0x2b, 0x01, 0x00, 0x04, 0x79, 0x0a, 0x02, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x04, 0x19, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x77, 0xa0, 0x81, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xd8, 0xa0, 0x82, 0x3c, ++ 0x00, 0x00, 0x41, 0x02, 0x04, 0x00, 0x00, 0x1c, 0xd8, 0xe0, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x62, 0x60, 0x83, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x20, 0x80, 0x3a, ++ 0x00, 0x00, 0x32, 0x02, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x00, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x3d, 0x02, 0x06, 0x01, 0x00, 0x80, 0x22, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x3a, 0x02, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x34, 0x02, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x35, 0x02, 0x00, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x22, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x34, 0x02, 0x67, 0x00, 0x00, 0x80, 0x18, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0x35, 0x02, 0x00, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0xc0, 0x00, 0x32, ++ 0x00, 0x00, 0x32, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x08, 0x80, 0x2d, 0xf2, ++ 0x00, 0x00, 0x25, 0x02, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x48, 0x02, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x43, 0x02, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0x92, ++ 0x00, 0x00, 0x4b, 0x02, 0x04, 0x00, 0x00, 0x80, 0x18, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0x43, 0x02, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x00, 0x00, 0x4f, 0x02, 0x04, 0x01, 0x00, 0x80, 0x42, 0x00, 0x86, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x89, 0x80, 0x71, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0x80, 0x71, 0x32, ++ 0x00, 0x00, 0x53, 0x02, 0x90, 0x19, 0x00, 0x04, 0xe9, 0x5c, 0x90, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x19, 0x40, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x80, 0x86, 0x32, ++ 0x41, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x8c, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x07, 0xc0, 0x85, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x8c, 0x07, 0x40, 0x85, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x80, 0x07, 0x45, 0x90, 0x30, ++ 0x00, 0x00, 0x5a, 0x02, 0x04, 0x01, 0x00, 0x80, 0x42, 0x00, 0x86, 0xbc, ++ 0x00, 0x00, 0x5b, 0x02, 0x00, 0x12, 0x00, 0x84, 0x27, 0xe4, 0x82, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x84, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x5f, 0x02, 0x27, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0xb2, ++ 0x00, 0x00, 0x5f, 0x02, 0x04, 0x00, 0x00, 0x80, 0x42, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0x5b, 0x02, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x72, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x52, 0x81, 0x2c, 0xb4, ++ 0x00, 0x00, 0x64, 0x02, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x82, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x03, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x67, 0x02, 0x04, 0x01, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0xbc, ++ 0x00, 0x00, 0x32, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x08, 0x80, 0x2d, 0xf2, ++ 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x30, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0x9a, ++ 0x08, 0x00, 0x00, 0x00, 0xc6, 0x01, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x40, 0x81, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x45, 0x81, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xa4, 0x03, 0x80, 0x01, 0x80, 0x80, 0x32, 0x0b, 0x6a, 0xb6, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x72, 0x02, 0x04, 0x06, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x06, 0x01, 0xec, 0x56, 0xe0, 0x6e, 0x9a, ++ 0x00, 0x00, 0x00, 0x00, 0xc4, 0x07, 0x01, 0xec, 0x56, 0xe0, 0x6e, 0x3a, ++ 0x08, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x03, 0xb8, 0x00, 0x00, 0x09, 0xc0, 0x6e, 0xbd, ++ 0x77, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0x0d, 0x90, 0x3a, ++ 0x2e, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x2b, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x37, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x38, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x80, 0x80, 0x32, 0x0b, 0x6a, 0xb6, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x86, 0x02, 0x04, 0x00, 0x00, 0x80, 0x52, 0x40, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x62, 0x40, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x05, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x42, 0x80, 0x2f, 0x34, ++ 0x08, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x04, 0x01, 0x14, 0x59, 0xc0, 0x6e, 0xd7, ++ 0x02, 0x00, 0x8f, 0x02, 0x04, 0xb8, 0x00, 0x80, 0x82, 0xcd, 0x6e, 0xbc, ++ 0x08, 0x00, 0x8a, 0x11, 0x04, 0xb9, 0x00, 0x80, 0x82, 0xcd, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0xec, 0x06, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x91, 0x02, 0xb5, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x80, 0xa0, 0x36, 0x0b, 0x6a, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0xe8, 0x06, 0xc0, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0x85, 0x2f, 0x30, ++ 0x00, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x60, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x40, 0x81, 0xd2, ++ 0x00, 0x00, 0xa1, 0x02, 0x80, 0x00, 0x80, 0x80, 0x32, 0x0b, 0x6a, 0xb6, ++ 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0xb8, 0x00, 0x14, 0x09, 0xc0, 0x6e, 0xd2, ++ 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0xa4, 0x02, 0x04, 0x02, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x02, 0x01, 0xec, 0x56, 0xe0, 0x6e, 0x9a, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x01, 0xec, 0x56, 0xe0, 0x6e, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2f, 0xb6, ++ 0x00, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x20, 0x00, 0x8a, 0x11, 0x04, 0x39, 0x00, 0x80, 0x82, 0xcd, 0x6e, 0xbc, ++ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x30, 0x00, 0x14, 0x09, 0x00, 0x6e, 0xd2, ++ 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x20, 0x01, 0x14, 0x09, 0x00, 0x6e, 0xd2, ++ 0x1b, 0x00, 0xaf, 0x02, 0x38, 0x01, 0x00, 0x10, 0x09, 0x00, 0x36, 0xb2, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x30, 0x01, 0x14, 0x09, 0x00, 0x6e, 0xd2, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x79, 0x0b, 0x14, 0x38, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x50, 0x01, 0x14, 0xa9, 0x5b, 0x91, 0xd9, ++ 0x00, 0x00, 0xbe, 0x02, 0x38, 0x28, 0x00, 0x18, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0xb6, 0x02, 0x04, 0x21, 0x01, 0x08, 0x69, 0x24, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x03, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xba, 0x02, 0x02, 0x30, 0x00, 0x80, 0x82, 0x9b, 0x90, 0xbc, ++ 0x00, 0x00, 0xb9, 0x02, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x04, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x05, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x30, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0xbd, 0x02, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x0a, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x0b, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xc1, 0x02, 0x04, 0x21, 0x01, 0x08, 0x69, 0x24, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x03, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xc3, 0x02, 0x02, 0x30, 0x00, 0x80, 0x82, 0x9b, 0x90, 0xbc, ++ 0x04, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xc5, 0x02, 0x9f, 0x31, 0x01, 0x0c, 0x69, 0x24, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc9, 0x02, 0x04, 0x31, 0x00, 0x80, 0x82, 0x9b, 0x90, 0xbc, ++ 0x00, 0x00, 0xc8, 0x02, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x20, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x21, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xcd, 0x02, 0x04, 0x00, 0x00, 0x80, 0x32, 0xa4, 0x90, 0xbc, ++ 0x00, 0x00, 0xcc, 0x02, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x22, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x23, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xcf, 0x02, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x20, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x21, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x8a, 0x11, 0x0c, 0x00, 0x00, 0xf8, 0x63, 0x40, 0x01, 0xb9, ++ 0x10, 0x00, 0xd4, 0x02, 0xc5, 0x01, 0x00, 0xcc, 0x02, 0x20, 0x15, 0x98, ++ 0x08, 0x00, 0x38, 0x03, 0x0c, 0x00, 0x00, 0xf8, 0x43, 0x40, 0x01, 0xb9, ++ 0x10, 0x00, 0x00, 0x00, 0xc5, 0x01, 0x00, 0xcc, 0x02, 0x20, 0x15, 0x38, ++ 0x00, 0x00, 0x7e, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x80, 0xd0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x59, 0x00, 0x80, 0xd7, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x08, 0x05, 0x80, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xfa, 0x85, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xfa, 0x85, 0xbc, ++ 0x00, 0x00, 0xdf, 0x02, 0x36, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x0e, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0xa9, 0xdb, 0x85, 0x39, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x54, 0x02, 0xa4, 0x38, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x8c, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x94, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x98, 0x28, 0x80, 0x6e, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x38, 0x22, 0x14, 0x37, ++ 0x00, 0x00, 0xeb, 0x02, 0x04, 0x30, 0x00, 0x28, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x20, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x14, 0x08, 0x80, 0x6e, 0x32, ++ 0x05, 0x00, 0xee, 0x02, 0x00, 0x30, 0x02, 0x00, 0x78, 0xe1, 0x6e, 0x99, ++ 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x78, 0x09, 0xc0, 0x6e, 0x32, ++ 0x05, 0x00, 0x00, 0x00, 0x68, 0x08, 0x00, 0x00, 0x77, 0xa1, 0x97, 0x39, ++ 0x00, 0x00, 0xf0, 0x02, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x14, 0x10, 0xf4, 0x02, 0x04, 0x00, 0x00, 0x80, 0xa2, 0x0d, 0x72, 0xb0, ++ 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x28, 0x09, 0xc0, 0x02, 0xf2, ++ 0x0d, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x09, 0x00, 0x80, 0x52, 0xbd, 0x72, 0xbc, ++ 0x00, 0x00, 0xfb, 0x02, 0x33, 0x15, 0x00, 0xa4, 0x02, 0xc0, 0x72, 0xb2, ++ 0x00, 0x00, 0x33, 0x03, 0x80, 0x01, 0x00, 0x80, 0xb2, 0x01, 0x72, 0xb6, ++ 0x01, 0x01, 0x08, 0x0a, 0x00, 0x28, 0x00, 0x80, 0xc2, 0x0d, 0x74, 0x3c, ++ 0x00, 0x00, 0x33, 0x03, 0x0b, 0x31, 0x00, 0x7c, 0x08, 0x00, 0x75, 0xb2, ++ 0x00, 0x00, 0x33, 0x03, 0x9f, 0xf0, 0x01, 0x80, 0x82, 0xdb, 0x87, 0xbc, ++ 0x00, 0x00, 0xfc, 0x02, 0x00, 0x38, 0x00, 0x88, 0x18, 0x00, 0x75, 0x9c, ++ 0x00, 0x00, 0x33, 0x03, 0x80, 0x00, 0x00, 0x80, 0xb2, 0x01, 0x72, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x08, 0x00, 0x75, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x08, 0x00, 0x75, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x74, 0x38, 0xa2, 0x75, 0x37, ++ 0x00, 0x00, 0x01, 0x03, 0x83, 0x1b, 0x00, 0x78, 0x08, 0xc0, 0x74, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xc2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0xf2, 0x02, 0x80, 0x01, 0x00, 0x80, 0x42, 0x80, 0x87, 0xb6, ++ 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x84, 0xd2, ++ 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x87, 0xd2, ++ 0x00, 0x00, 0x15, 0x03, 0x9f, 0x78, 0x01, 0x80, 0xc2, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x0a, 0x03, 0x9f, 0x99, 0x01, 0x64, 0x88, 0x1b, 0x87, 0xbc, ++ 0x00, 0x00, 0x16, 0x03, 0x9f, 0x68, 0x01, 0x64, 0x88, 0x5b, 0x86, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0xa4, 0x02, 0xc0, 0x72, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0xa4, 0xb2, 0x5b, 0x2a, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x02, 0x78, 0x09, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x17, 0x03, 0x08, 0x01, 0x00, 0x04, 0xe8, 0xa5, 0x75, 0xbc, ++ 0x0f, 0x00, 0x33, 0x03, 0x0b, 0x01, 0x00, 0x1c, 0x08, 0x00, 0x36, 0xb2, ++ 0x00, 0x00, 0x15, 0x03, 0x04, 0xa1, 0x01, 0x80, 0x82, 0x9b, 0x84, 0xbc, ++ 0x00, 0x00, 0x9d, 0x05, 0x9f, 0x98, 0x01, 0x80, 0xc2, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x9d, 0x05, 0x06, 0xb1, 0x01, 0x80, 0x82, 0x5b, 0x87, 0xbc, ++ 0x00, 0x00, 0x32, 0x03, 0x0b, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x30, 0x03, 0x02, 0xd4, 0x01, 0x80, 0x92, 0xfb, 0x6e, 0xbc, ++ 0x15, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x16, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x1c, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x28, 0x72, 0x61, 0x80, 0xb9, ++ 0x00, 0x00, 0x1a, 0x03, 0x04, 0xa1, 0x01, 0x80, 0x82, 0x9b, 0x84, 0xbc, ++ 0x00, 0x00, 0x21, 0x03, 0x06, 0xa8, 0x01, 0x80, 0x82, 0x5b, 0x80, 0xbc, ++ 0x00, 0x00, 0x1e, 0x03, 0x04, 0xa9, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x31, 0x03, 0x04, 0xa9, 0x01, 0x80, 0x82, 0x9b, 0x84, 0xbc, ++ 0x00, 0x00, 0x31, 0x03, 0x04, 0x01, 0x00, 0x80, 0x12, 0x40, 0x80, 0xbc, ++ 0x13, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x31, 0x03, 0x9f, 0xa0, 0x01, 0x78, 0x29, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x31, 0x03, 0x02, 0x01, 0x00, 0x80, 0x12, 0xa0, 0x97, 0xbc, ++ 0x00, 0x00, 0x15, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x2c, 0x03, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x02, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x27, 0x03, 0x02, 0x00, 0x00, 0x80, 0xa2, 0x60, 0x80, 0xbc, ++ 0x06, 0x00, 0x9d, 0x05, 0x2c, 0x01, 0x00, 0x1c, 0x08, 0x00, 0x36, 0xb2, ++ 0x00, 0xc0, 0x29, 0x03, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x8d, 0x2f, 0xb0, ++ 0x06, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x29, 0x03, 0x04, 0x00, 0x00, 0x80, 0xa2, 0x60, 0x80, 0xbc, ++ 0x09, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x2b, 0x03, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x07, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x02, 0x00, 0x9d, 0x05, 0x38, 0x01, 0x00, 0x1c, 0x08, 0x00, 0x36, 0xb2, ++ 0x00, 0x00, 0x2f, 0x03, 0x02, 0x0c, 0x02, 0x80, 0xa2, 0x5b, 0x80, 0xbc, ++ 0x1f, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x1e, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x34, 0x03, 0x00, 0x00, 0x00, 0x28, 0x09, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x34, 0x03, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x34, 0x03, 0x00, 0x00, 0x00, 0x28, 0x09, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x34, 0x03, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x01, 0x92, ++ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x92, 0xd2, ++ 0x0d, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0xf2, ++ 0x00, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x10, 0x00, 0x8a, 0x11, 0x2a, 0x00, 0x00, 0xcc, 0x02, 0x20, 0x15, 0xb8, ++ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x80, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x38, 0xf2, ++ 0x1d, 0x00, 0x49, 0x03, 0x80, 0x01, 0x00, 0x78, 0x09, 0xe0, 0x00, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x1d, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x22, 0x80, 0x97, 0xbc, ++ 0x14, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xa8, 0x05, 0x28, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x2c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x60, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x83, 0x40, 0x01, 0x39, ++ 0x35, 0x00, 0x54, 0x03, 0x04, 0x00, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x81, 0xd2, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x38, 0xf2, ++ 0x2b, 0x00, 0x9d, 0x05, 0x02, 0x01, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x00, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x5a, 0x03, 0x1d, 0x41, 0x02, 0x5c, 0xf8, 0x01, 0x68, 0xb4, ++ 0x41, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x8d, 0x2f, 0x91, ++ 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x59, 0xc0, 0x85, 0xd7, ++ 0x10, 0x00, 0x00, 0x00, 0xd0, 0x2c, 0x02, 0x00, 0xa9, 0xdb, 0x85, 0x39, ++ 0x00, 0x00, 0xe1, 0x02, 0x12, 0x01, 0x00, 0x54, 0x02, 0xa4, 0x38, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x64, 0x03, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x60, 0x11, 0x00, 0x78, 0x01, 0x60, 0x08, 0x00, 0x6e, 0xf2, ++ 0x2f, 0x00, 0x93, 0x05, 0xd7, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x65, 0x03, 0x06, 0xa9, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x6d, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x70, 0x03, 0x04, 0xa8, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x08, 0x89, 0x9b, 0x90, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x08, 0x89, 0x9b, 0x90, 0x3a, ++ 0x00, 0x00, 0x70, 0x03, 0x9f, 0x88, 0x01, 0x08, 0x89, 0x9b, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x04, 0xf9, 0xba, 0x6e, 0x37, ++ 0x00, 0x00, 0x6c, 0x03, 0x02, 0x00, 0x00, 0x80, 0x12, 0xa4, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x80, 0x90, 0x37, ++ 0x00, 0x00, 0x70, 0x03, 0x02, 0x01, 0x02, 0x80, 0x82, 0x9b, 0x90, 0xbc, ++ 0x30, 0x00, 0x93, 0x05, 0xd7, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x70, 0x03, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x12, 0x70, 0x03, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x8d, 0x2f, 0xb0, ++ 0x31, 0x00, 0x93, 0x05, 0xd7, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x72, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x42, 0x80, 0x2f, 0x34, ++ 0x08, 0xc0, 0x74, 0x02, 0x12, 0x01, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x81, 0xd2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x2c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x60, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x00, 0x00, 0xb0, 0x03, 0x80, 0x01, 0x80, 0x80, 0x32, 0x0b, 0x6a, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x38, 0xf2, ++ 0x2b, 0x00, 0x9d, 0x05, 0x02, 0x01, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x00, 0x00, 0x93, 0x05, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x89, 0x4d, 0x81, 0xd7, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x2c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x60, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x00, 0x00, 0xb0, 0x03, 0x80, 0x01, 0x80, 0x80, 0x32, 0x0b, 0x6a, 0xb6, ++ 0x00, 0x00, 0xdc, 0x0e, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x8a, 0x03, 0x04, 0x20, 0x01, 0x80, 0x52, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x25, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x24, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x93, 0x03, 0x04, 0x01, 0x00, 0xd8, 0x1e, 0x80, 0xed, 0xbc, ++ 0x00, 0x00, 0x8c, 0x03, 0xb7, 0x00, 0x00, 0xd8, 0x0e, 0xc0, 0xed, 0xb2, ++ 0x00, 0x00, 0x8f, 0x03, 0x04, 0x01, 0x00, 0x80, 0x42, 0x3b, 0xee, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1e, 0x00, 0xee, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0xd0, 0x0e, 0x00, 0xee, 0x32, ++ 0x00, 0x00, 0x93, 0x03, 0x80, 0x01, 0x00, 0x80, 0x92, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0x93, 0x03, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0x93, 0x03, 0x04, 0x01, 0x00, 0xb0, 0x1e, 0x00, 0xeb, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xcc, 0x02, 0x80, 0x6c, 0x32, ++ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x97, 0x03, 0x80, 0x01, 0x80, 0x80, 0x32, 0x0b, 0x6a, 0xb6, ++ 0x35, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x99, 0x03, 0x04, 0x01, 0x00, 0x80, 0x42, 0xc5, 0x2c, 0xbc, ++ 0x00, 0x00, 0x9a, 0x03, 0x00, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x12, 0xc0, 0x2c, 0x3a, ++ 0x00, 0x00, 0x95, 0x03, 0x04, 0x01, 0x00, 0x00, 0x19, 0x00, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x86, 0xc8, 0x06, 0xc0, 0x2c, 0x32, ++ 0x08, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0xf8, 0xc3, 0x40, 0x01, 0x99, ++ 0x00, 0x00, 0x9f, 0x03, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x55, 0x01, 0x80, 0xb2, 0x1b, 0x2b, 0xbc, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0x09, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa3, 0x03, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x55, 0x01, 0x80, 0xb2, 0x1b, 0x2b, 0xbc, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xad, 0x03, 0x04, 0x00, 0x00, 0x28, 0x09, 0x80, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xef, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0xd2, ++ 0x00, 0x00, 0xad, 0x03, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xb0, 0x03, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xb0, 0x03, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0x39, ++ 0xb0, 0x03, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xb0, 0x03, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xb0, 0x03, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x32, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x02, 0x99, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x0f, 0x00, 0x00, 0x32, ++ 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc2, 0x03, 0x8b, 0x01, 0x00, 0xa0, 0x12, 0x00, 0x2a, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc5, 0x03, 0x06, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2a, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc8, 0x03, 0x85, 0x01, 0x00, 0x9c, 0x12, 0xc0, 0x29, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x0b, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x13, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x0c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x06, 0x32, ++ 0x0f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x0d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x14, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x15, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x18, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x1d, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x04, 0x32, ++ 0x1e, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x1f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x32, ++ 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0xe0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x17, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x1b, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x1c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x40, 0x00, 0x32, ++ 0x16, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x1a, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x19, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x0b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x0c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x64, 0x02, 0x39, ++ 0x00, 0x00, 0xfb, 0x03, 0x85, 0x01, 0x00, 0x00, 0x19, 0x00, 0x90, 0xba, ++ 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x32, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf3, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe3, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xc3, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb3, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa3, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x83, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x63, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x53, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x43, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x33, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x13, 0x40, 0x01, 0x39, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x23, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x80, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x3f, 0x80, 0xfc, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x32, ++ 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x40, 0x38, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xd2, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x13, 0x04, 0x04, 0x01, 0x00, 0xd0, 0x12, 0x00, 0x2d, 0xbc, ++ 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0xe4, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x12, 0x00, 0x2d, 0x3a, ++ 0x4c, 0x00, 0x1a, 0x04, 0x02, 0x01, 0x00, 0x80, 0x82, 0x0d, 0x2d, 0xbc, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xae, 0x0d, 0x02, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x32, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x88, 0x86, 0xcc, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x86, 0xcc, 0x07, 0x80, 0x00, 0x3a, ++ 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x64, 0x02, 0x40, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x29, 0x40, 0x90, 0x3a, ++ 0x00, 0x00, 0x26, 0x04, 0x12, 0x00, 0x00, 0x78, 0x09, 0xc0, 0x20, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x81, 0x97, 0xb6, ++ 0x1d, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x78, 0xe9, 0xe5, 0x00, 0xb8, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x45, 0x90, 0x30, ++ 0x00, 0x00, 0x24, 0x04, 0x02, 0x01, 0x00, 0x80, 0xc2, 0x82, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x2c, 0x04, 0x8e, 0x01, 0x00, 0x80, 0x02, 0x40, 0x28, 0xb2, ++ 0x00, 0x00, 0x26, 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xd2, ++ 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x0e, 0x00, 0x36, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb9, 0x05, 0x36, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x73, 0x80, 0x97, 0x34, ++ 0x09, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x32, ++ 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x73, 0x80, 0x97, 0x34, ++ 0x09, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0xfe, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x36, 0x32, ++ 0x0a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x3b, 0x04, 0x12, 0x01, 0x00, 0x00, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0x39, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x3b, 0x04, 0x12, 0x00, 0x00, 0x04, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0x3e, 0x04, 0x9f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x3d, 0x04, 0x12, 0x00, 0x00, 0x08, 0x09, 0x40, 0x20, 0xb2, ++ 0x02, 0x00, 0x39, 0x04, 0x04, 0x01, 0x00, 0x78, 0x09, 0x24, 0x17, 0xb8, ++ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x64, 0x16, 0x38, ++ 0x00, 0x00, 0x39, 0x04, 0x04, 0x01, 0x00, 0x80, 0x02, 0x81, 0x97, 0xbc, ++ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x03, 0x00, 0x36, 0x32, ++ 0xfe, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x00, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0x44, 0x04, 0x12, 0x00, 0x00, 0x04, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0x47, 0x04, 0x9f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x46, 0x04, 0x12, 0x00, 0x00, 0x08, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x02, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x06, 0x00, 0x59, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x09, 0x64, 0x16, 0x98, ++ 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x00, 0x14, 0x08, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x97, 0x02, 0x00, 0x00, 0x00, 0x14, 0x08, 0x40, 0x90, 0x92, ++ 0x33, 0x00, 0x74, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x11, 0x00, 0x74, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x39, 0x00, 0x74, 0x03, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x14, 0x08, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x7f, 0x03, 0x00, 0x00, 0x00, 0x14, 0x08, 0x40, 0x90, 0x92, ++ 0x5a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0xcd, 0x90, 0x3a, ++ 0x0d, 0x00, 0x7c, 0x04, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xe4, 0x16, 0x98, ++ 0x0d, 0x00, 0x8e, 0x04, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xe4, 0x16, 0x98, ++ 0x0d, 0x00, 0x97, 0x04, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xe4, 0x16, 0x98, ++ 0x00, 0x00, 0xa3, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xad, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x40, 0x90, 0x9d, ++ 0x00, 0x00, 0xb3, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xbd, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc7, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x40, 0x90, 0x9d, ++ 0x00, 0x00, 0xd8, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x40, 0x90, 0x9d, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xf3, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0xf3, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x40, 0x00, 0x92, ++ 0xd8, 0x00, 0xf5, 0x04, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xdc, 0x0f, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xed, 0x04, 0x00, 0x00, 0x00, 0x78, 0x39, 0x40, 0x90, 0x97, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xec, 0x0e, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0xef, 0x04, 0x00, 0x00, 0x00, 0xe8, 0x0e, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xd4, 0x0e, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x85, 0x05, 0x00, 0x00, 0x00, 0xdc, 0x0e, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x08, 0x00, 0x15, 0x05, 0x00, 0x00, 0x00, 0x50, 0x1f, 0x24, 0x16, 0x98, ++ 0x00, 0x00, 0x27, 0x05, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x92, ++ 0x0d, 0x00, 0x32, 0x05, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xe4, 0x16, 0x98, ++ 0x00, 0x00, 0x33, 0x05, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x89, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x45, 0x90, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x22, 0x80, 0x97, 0xbc, ++ 0x3f, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x0d, 0x00, 0xb0, ++ 0x02, 0x00, 0x80, 0x04, 0xb0, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0x6b, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0xb0, 0x03, 0x80, 0x01, 0x00, 0x80, 0x02, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0xb0, 0x03, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0xb0, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x22, 0x00, 0x2b, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x00, 0x34, ++ 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x2a, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0x00, 0xb0, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0xd0, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0x39, ++ 0xb0, 0x03, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x99, ++ 0x00, 0x00, 0x91, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x02, 0x00, 0x91, 0x04, 0xb0, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0x3b, 0x40, 0xb0, 0x31, ++ 0x00, 0x00, 0x8d, 0x04, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0x2b, 0xbc, ++ 0xf1, 0x0f, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x0e, 0x00, 0x36, 0x92, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x02, 0x00, 0x98, 0x04, 0xb0, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0xb9, ++ 0x00, 0x00, 0x9b, 0x04, 0x80, 0x01, 0x00, 0x80, 0x12, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3b, 0x40, 0xb0, 0x33, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xcd, 0x4a, 0xd0, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x0c, 0x1b, 0xe4, 0xb0, 0x32, ++ 0x00, 0x00, 0xb0, 0x03, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xa1, 0x04, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x90, 0xb2, ++ 0x1f, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x80, 0x11, 0x40, 0x00, 0x99, ++ 0x00, 0x00, 0xa0, 0x04, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0xf8, 0xbc, ++ 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0xfc, 0xb6, ++ 0x00, 0x00, 0xa7, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0x85, 0x90, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x80, 0x90, 0x32, ++ 0x09, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x40, 0x90, 0x32, ++ 0x0a, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xc8, 0x0f, 0x81, 0xfc, 0x94, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x72, 0x42, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0xe2, 0x42, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x78, 0x09, 0x64, 0x90, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x73, 0x00, 0x90, 0x3c, ++ 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb6, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0x85, 0x90, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x80, 0x90, 0x32, ++ 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x40, 0x90, 0x32, ++ 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0xc0, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0x85, 0x90, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x80, 0x90, 0x32, ++ 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0e, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x40, 0x90, 0x32, ++ 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xac, 0x0e, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0xca, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0x85, 0x90, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x80, 0x90, 0x32, ++ 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x40, 0x90, 0x32, ++ 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x0f, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x48, 0x0f, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x82, 0x42, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x78, 0x09, 0x64, 0x90, 0xb5, ++ 0x00, 0x00, 0xd5, 0x04, 0x04, 0x01, 0x00, 0x80, 0x82, 0x42, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x90, 0x32, ++ 0x12, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x40, 0x90, 0x9c, ++ 0x00, 0x00, 0xdb, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0x85, 0x90, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x80, 0x90, 0x32, ++ 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x40, 0x90, 0x32, ++ 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x82, 0x42, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x78, 0x09, 0x64, 0x90, 0xb5, ++ 0x00, 0x00, 0xe5, 0x04, 0x04, 0x01, 0x00, 0x80, 0x82, 0x42, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x90, 0x32, ++ 0x11, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x40, 0x90, 0x9c, ++ 0x00, 0x00, 0xeb, 0x04, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x0e, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x88, 0x0e, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x40, 0x90, 0x37, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xa4, 0x97, 0x9a, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xbc, 0x0e, 0x80, 0xee, 0x9d, ++ 0x00, 0x00, 0xf2, 0x04, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0x00, 0x32, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xe4, 0x1e, 0x40, 0x90, 0x9c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x22, 0x00, 0x90, 0x37, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x86, 0xc0, 0x07, 0x40, 0x90, 0x92, ++ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xe4, 0x16, 0x38, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xfa, 0x04, 0x04, 0x00, 0x00, 0x80, 0x02, 0x24, 0xf6, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x3f, 0x80, 0xfc, 0x34, ++ 0x40, 0x80, 0xfc, 0x04, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0f, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x79, 0x01, 0x00, 0x34, ++ 0x02, 0x00, 0xfc, 0x04, 0xb0, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x0c, 0xab, 0xe4, 0xb0, 0x32, ++ 0x1f, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x40, 0x00, 0x99, ++ 0xea, 0x05, 0x05, 0x05, 0x04, 0x01, 0x00, 0x80, 0x82, 0x4d, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x0f, 0x00, 0x15, 0x32, ++ 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x37, 0x32, ++ 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x0f, 0x00, 0x36, 0x32, ++ 0x98, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x0b, 0x05, 0x00, 0x00, 0x00, 0xc8, 0x4f, 0x80, 0xfc, 0x95, ++ 0x36, 0x23, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x4d, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x0f, 0x80, 0x14, 0x32, ++ 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x37, 0x32, ++ 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x0f, 0x00, 0x36, 0x32, ++ 0x98, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x4f, 0x80, 0xfc, 0x34, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x8f, 0x4d, 0x90, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x60, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x7a, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xa9, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x12, 0x05, 0x80, 0x01, 0x00, 0x80, 0x02, 0x40, 0x90, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x6f, 0x80, 0xfc, 0x34, ++ 0x00, 0x00, 0x14, 0x05, 0x80, 0x01, 0x00, 0x80, 0x12, 0x40, 0x90, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x5f, 0x80, 0xfc, 0x34, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x17, 0x05, 0x04, 0x01, 0x00, 0x80, 0x32, 0x40, 0x90, 0xb0, ++ 0x80, 0x01, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xc8, 0x8f, 0x8d, 0xfc, 0x91, ++ 0x00, 0x00, 0x19, 0x05, 0x80, 0x00, 0x00, 0x80, 0x12, 0x40, 0x90, 0xb6, ++ 0x00, 0x00, 0x1a, 0x05, 0x00, 0x00, 0x00, 0xc8, 0x7f, 0x80, 0xfc, 0x95, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x7f, 0x80, 0xfc, 0x34, ++ 0x00, 0x00, 0x1c, 0x05, 0x80, 0x00, 0x00, 0x80, 0x02, 0x40, 0x90, 0xb6, ++ 0x00, 0x00, 0x1d, 0x05, 0x00, 0x00, 0x00, 0xc8, 0x8f, 0x80, 0xfc, 0x95, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x8f, 0x80, 0xfc, 0x34, ++ 0x00, 0x00, 0x20, 0x05, 0x80, 0x00, 0x00, 0x80, 0x22, 0x40, 0x90, 0xb6, ++ 0xf1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x0e, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x22, 0x05, 0x00, 0x00, 0x00, 0xc8, 0x1f, 0x81, 0xfc, 0x95, ++ 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x0e, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x1f, 0x81, 0xfc, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x82, 0x02, 0xf5, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x03, 0x00, 0x00, 0x78, 0x09, 0x00, 0xf5, 0xbd, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xe2, 0x25, 0xf5, 0xb5, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x1f, 0x24, 0x16, 0x38, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x50, 0x1f, 0x00, 0xf5, 0x9c, ++ 0x80, 0x01, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0xfc, 0xb0, ++ 0x00, 0x00, 0x2b, 0x05, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0xfd, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0xf5, 0x3a, ++ 0x8c, 0xcc, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0x80, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xec, 0x03, 0x40, 0x90, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x90, 0xbc, ++ 0x00, 0x00, 0x34, 0x05, 0xb2, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0xec, 0x16, 0xe4, 0x6e, 0x3a, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x69, 0x05, 0x17, 0x10, 0x01, 0xf8, 0x02, 0x00, 0x6e, 0xb2, ++ 0x06, 0x00, 0x3f, 0x05, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0x32, ++ 0x00, 0xc0, 0xd3, 0x0e, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x36, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x86, 0xc8, 0x06, 0x00, 0x00, 0x32, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x40, 0x05, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x46, 0x05, 0x04, 0x19, 0x86, 0x80, 0x02, 0x80, 0x6c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x12, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x08, 0x00, 0x04, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x15, 0x86, 0x2c, 0x09, 0xc0, 0x6c, 0x32, ++ 0x00, 0x00, 0x4c, 0x05, 0x22, 0x1d, 0x86, 0xc8, 0x06, 0xc0, 0x92, 0xb2, ++ 0x00, 0x00, 0x4c, 0x05, 0x00, 0x18, 0x86, 0xc8, 0x06, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x22, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x48, 0x00, 0x04, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x16, 0x86, 0x2c, 0x09, 0xc0, 0x6c, 0x32, ++ 0x00, 0x00, 0x4c, 0x05, 0x21, 0x1d, 0x86, 0xc8, 0x06, 0xc0, 0x92, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x86, 0xc8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x54, 0x05, 0x04, 0x02, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xd3, 0x0e, 0x00, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xdc, ++ 0x00, 0x00, 0x52, 0x05, 0x80, 0x00, 0x00, 0x80, 0x02, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x54, 0x05, 0x81, 0x00, 0x00, 0xf8, 0x22, 0x80, 0x2f, 0xb4, ++ 0x00, 0x00, 0x54, 0x05, 0x00, 0x18, 0x86, 0xc8, 0x06, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x54, 0x05, 0x82, 0x00, 0x00, 0xf8, 0x12, 0x80, 0x2f, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x86, 0xc8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x86, 0xc8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x0a, 0x32, ++ 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x00, 0x07, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0xc0, 0x69, 0x05, 0x18, 0x00, 0x00, 0x00, 0xa9, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x86, 0x04, 0x19, 0x80, 0x6c, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x01, 0x00, 0x80, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x0c, 0xf7, 0x7f, 0x90, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x34, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x10, 0x86, 0x80, 0x72, 0x82, 0x6c, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x86, 0xa8, 0x42, 0x80, 0x6c, 0x37, ++ 0x00, 0x00, 0x78, 0x05, 0x12, 0x00, 0x70, 0x38, 0x02, 0x00, 0x7c, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xe0, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x3c, 0x02, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x30, 0x02, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x34, 0x02, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x6b, 0x05, 0x02, 0x01, 0x00, 0x80, 0xb2, 0x82, 0x2a, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x32, ++ 0x06, 0x00, 0x3f, 0x05, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x00, 0x00, 0x39, 0x05, 0x04, 0x03, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0xe0, 0x06, 0x80, 0x2f, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0xa2, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x7a, 0x05, 0x04, 0x03, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x83, 0x05, 0x00, 0x10, 0x86, 0xc8, 0x46, 0x80, 0x2a, 0x96, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x86, 0xc8, 0x46, 0x80, 0x2a, 0x36, ++ 0x00, 0x00, 0x7e, 0x05, 0x80, 0x00, 0x00, 0x80, 0x12, 0x80, 0x2f, 0xb6, ++ 0x03, 0x00, 0x80, 0x05, 0x22, 0x00, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0xb2, ++ 0x00, 0x00, 0x80, 0x05, 0x00, 0x18, 0x86, 0xc8, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x83, 0x05, 0x80, 0x00, 0x00, 0x80, 0x22, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0x35, ++ 0x00, 0xc0, 0xd3, 0x0e, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x36, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0x3c, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0xe0, 0x06, 0x80, 0x2f, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0xa2, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x05, 0x04, 0x01, 0x00, 0x80, 0xa2, 0xc0, 0xed, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0e, 0x80, 0x02, 0x32, ++ 0x40, 0x7e, 0x05, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x0e, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x0e, 0x80, 0x07, 0x32, ++ 0x64, 0x00, 0x8f, 0x05, 0x00, 0x00, 0x00, 0xcc, 0x0e, 0x00, 0x36, 0x92, ++ 0x64, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xed, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0e, 0x40, 0x00, 0x32, ++ 0xa0, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x0e, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x0e, 0xc0, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x0e, 0x80, 0x02, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x33, 0x7b, 0xec, 0x39, ++ 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x6e, 0xc0, 0xec, 0x37, ++ 0x00, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x00, 0xd8, 0x0e, 0xc0, 0xed, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x65, 0x01, 0x80, 0xa2, 0xdb, 0x2c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x80, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x1c, 0x01, 0x80, 0x52, 0xc0, 0x6e, 0xbc, ++ 0x2b, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x3d, 0x00, 0x8a, 0x11, 0x02, 0x00, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x35, 0x00, 0x9c, 0x05, 0x04, 0x00, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x89, 0xcd, 0x81, 0x3c, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x1c, 0x01, 0x14, 0x59, 0xe4, 0x6e, 0xd9, ++ 0xa4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0xcd, 0x81, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x80, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x65, 0x01, 0x80, 0xa2, 0xdb, 0x2c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x18, 0x01, 0x80, 0x92, 0xc0, 0x6e, 0xbc, ++ 0x2b, 0x00, 0x8a, 0x11, 0x02, 0x00, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x18, 0x01, 0x14, 0x79, 0xe0, 0x6e, 0xd9, ++ 0xa4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0xcd, 0x81, 0x3a, ++ 0xe1, 0x05, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xea, 0x05, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xf3, 0x05, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xfc, 0x05, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x05, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x0e, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x17, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x20, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x29, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x32, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x3b, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x44, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x4d, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x56, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x5f, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x68, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x71, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x7a, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x83, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x8c, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x95, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x9e, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xa7, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xb0, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xb9, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xc2, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xcb, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xd4, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xdd, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xe6, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xef, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0xf8, 0x06, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x01, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x0a, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x13, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x1c, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x25, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x2e, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x37, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x40, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x49, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x00, 0x00, 0x57, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x52, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x57, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x5c, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x61, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x66, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x6b, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x70, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x75, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x7a, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x7f, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x84, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x89, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x8e, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x93, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x98, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x9d, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x88, 0x82, 0xcd, 0x6e, 0x3a, ++ 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x71, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x3b, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x79, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x88, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xda, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xda, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xda, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xea, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xea, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xea, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe8, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe8, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe8, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x86, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xd7, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7d, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xd7, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7d, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd7, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x0c, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe9, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe9, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe9, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe9, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc1, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xb8, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xc1, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc1, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x86, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x01, 0x92, ++ 0x00, 0x00, 0x81, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x76, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x76, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x76, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x76, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc9, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x47, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x4b, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xb0, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x4b, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x4b, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xa3, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x02, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x4c, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xb0, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x4c, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x4c, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x51, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x51, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x51, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x51, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x68, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x64, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x64, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x64, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x64, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7e, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x7e, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x7e, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7e, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8f, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xa0, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xa0, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb5, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xb5, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xb5, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x75, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x75, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x75, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x75, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xcc, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x02, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x88, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x88, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xa2, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa8, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x2a, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x2a, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x34, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x34, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x31, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xab, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xf3, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb6, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xb6, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xb6, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x1a, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xb4, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc3, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xc3, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe5, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe8, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xe8, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xea, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xea, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xea, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0xc2, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xc2, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x40, 0x00, 0x92, ++ 0x00, 0x00, 0xf8, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xf8, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x2e, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x22, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0x22, 0x09, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xef, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x80, 0x00, 0x92, ++ 0x00, 0x00, 0xef, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0xc0, 0x00, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x01, 0x92, ++ 0x08, 0x00, 0xa1, 0x03, 0x00, 0x18, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x99, ++ 0x08, 0x00, 0x9d, 0x03, 0x00, 0x18, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x99, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x08, 0x00, 0xa7, 0x07, 0x1d, 0x19, 0x01, 0xe8, 0x76, 0x20, 0x81, 0xb9, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xa1, 0x03, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x94, ++ 0x08, 0x00, 0xa1, 0x03, 0x00, 0x1c, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x99, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x0f, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0xec, 0x06, 0xc0, 0x6e, 0x35, ++ 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x00, 0x2d, 0x37, ++ 0xb4, 0xcc, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x99, 0xc0, 0x2c, 0x37, ++ 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x10, 0x00, 0x00, 0x87, 0xbf, 0x97, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x40, 0xfe, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x78, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0xb7, 0x07, 0xb7, 0x10, 0x02, 0xe0, 0x06, 0x80, 0x97, 0xb2, ++ 0x00, 0x00, 0xba, 0x07, 0x80, 0x00, 0x00, 0x80, 0xf2, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0xbb, 0x07, 0x00, 0x00, 0x00, 0xc8, 0xff, 0x80, 0xfc, 0x94, ++ 0x00, 0x00, 0xbc, 0x07, 0x9f, 0x99, 0x00, 0x80, 0x82, 0x1b, 0xee, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xe0, 0x0e, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x1c, 0x09, 0x00, 0x6e, 0x32, ++ 0x40, 0x00, 0xc1, 0x07, 0x06, 0x01, 0x00, 0x80, 0x82, 0xcd, 0x91, 0xbc, ++ 0x00, 0x40, 0xc2, 0x07, 0x00, 0x18, 0x02, 0xe0, 0xa6, 0xcd, 0x2c, 0x92, ++ 0x00, 0x60, 0x00, 0x00, 0x00, 0x18, 0x02, 0xe0, 0xa6, 0xcd, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x09, 0x80, 0x03, 0x32, ++ 0x00, 0x00, 0xc5, 0x07, 0x80, 0xd7, 0x01, 0x80, 0x32, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0x00, 0x92, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x18, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x24, 0x09, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x28, 0x09, 0x80, 0x6e, 0x32, ++ 0x00, 0x00, 0xd3, 0x07, 0x80, 0x0e, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xb6, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0xec, 0x06, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x01, 0x92, 0x3a, ++ 0x00, 0x00, 0xcf, 0x07, 0x80, 0xd6, 0x01, 0x80, 0x42, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x82, 0x00, 0x00, 0x00, 0x10, 0x02, 0xe0, 0xa6, 0xcd, 0x91, 0x32, ++ 0x00, 0xa0, 0x00, 0x00, 0x00, 0x2c, 0x02, 0xe8, 0x06, 0x00, 0x36, 0x32, ++ 0x28, 0x00, 0xdd, 0x07, 0x00, 0x32, 0x02, 0xec, 0x06, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0xd3, 0x01, 0x00, 0x1c, 0xd9, 0xc1, 0x91, 0x34, ++ 0x00, 0x82, 0x00, 0x00, 0x00, 0x10, 0x02, 0xe0, 0xa6, 0xcd, 0x91, 0x32, ++ 0x00, 0xa0, 0x00, 0x00, 0x00, 0x2c, 0x02, 0xe8, 0x06, 0x00, 0x36, 0x32, ++ 0x34, 0x00, 0xdd, 0x07, 0x00, 0x32, 0x02, 0xec, 0x06, 0x00, 0x36, 0x92, ++ 0x04, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0xec, 0x06, 0x00, 0x36, 0x32, ++ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x0d, 0x92, 0x3a, ++ 0x00, 0x00, 0xd9, 0x07, 0x80, 0xd6, 0x01, 0x80, 0x42, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x86, 0x00, 0x00, 0x00, 0x10, 0x02, 0xe0, 0xa6, 0xcd, 0x91, 0x32, ++ 0x04, 0xa0, 0x00, 0x00, 0x00, 0x2c, 0x02, 0xe8, 0x06, 0x00, 0x36, 0x32, ++ 0x14, 0x00, 0xdd, 0x07, 0x00, 0x32, 0x02, 0xec, 0x06, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0xd3, 0x01, 0x00, 0x1c, 0xd9, 0xc1, 0x91, 0x34, ++ 0x00, 0x86, 0x00, 0x00, 0x00, 0x10, 0x02, 0xe0, 0xa6, 0xcd, 0x91, 0x32, ++ 0x04, 0xa0, 0x00, 0x00, 0x00, 0x2c, 0x02, 0xe8, 0x06, 0x00, 0x36, 0x32, ++ 0x20, 0x00, 0xdd, 0x07, 0x00, 0x32, 0x02, 0xec, 0x06, 0x00, 0x36, 0x92, ++ 0x12, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0xec, 0x86, 0xcd, 0x91, 0x3a, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0xe8, 0x86, 0x24, 0x90, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0xe0, 0x96, 0x24, 0x14, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xe0, 0x06, 0x80, 0x91, 0x32, ++ 0x00, 0x00, 0xe3, 0x07, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x92, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x00, 0x2d, 0x37, ++ 0x00, 0xcd, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x99, 0xc0, 0x2c, 0x37, ++ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x10, 0x00, 0x00, 0x87, 0xbf, 0x97, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x40, 0xfe, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xc9, 0x01, 0x80, 0x02, 0x80, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0xec, 0x06, 0x80, 0x83, 0x32, ++ 0x01, 0x00, 0xaa, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0xf9, 0x07, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x2c, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xff, 0x07, 0x80, 0xd7, 0x01, 0x2c, 0x09, 0xc0, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xda, 0xd7, 0x01, 0xec, 0x06, 0xc0, 0x6e, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x01, 0xec, 0x06, 0x40, 0xed, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0xec, 0x06, 0x80, 0xee, 0x32, ++ 0x00, 0x00, 0x02, 0x08, 0x80, 0x01, 0x00, 0x80, 0x62, 0xc0, 0x92, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0xaa, 0x07, 0x04, 0x06, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xaa, 0x07, 0x80, 0x00, 0x00, 0x80, 0x72, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x72, 0x81, 0x2f, 0x34, ++ 0x3b, 0x00, 0xaa, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x07, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xb2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x0a, 0x08, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xa0, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x60, 0x11, 0x00, 0x78, 0x01, 0x60, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x0f, 0x08, 0x12, 0x01, 0x00, 0xc8, 0x02, 0x00, 0x20, 0xb2, ++ 0x00, 0x00, 0x12, 0x08, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x1e, 0x08, 0x12, 0x01, 0x00, 0x5c, 0x08, 0x80, 0x20, 0xb2, ++ 0x00, 0x00, 0x12, 0x08, 0x12, 0x01, 0x00, 0x60, 0x02, 0x80, 0x2c, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x14, 0x08, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x80, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0xff, 0x3a, ++ 0x00, 0x00, 0x17, 0x08, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0xaa, 0x07, 0x80, 0x00, 0x00, 0x80, 0x72, 0x81, 0x2f, 0xb6, ++ 0x3b, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x72, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x14, 0x08, 0x80, 0x6e, 0x32, ++ 0x00, 0x00, 0x12, 0x08, 0x12, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x20, 0xb2, ++ 0x00, 0x00, 0x10, 0x08, 0x12, 0x00, 0x00, 0x5c, 0x08, 0x80, 0x20, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xa0, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x78, 0xe1, 0x6e, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x20, 0x07, 0x00, 0x00, 0x32, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, 0xca, 0xe9, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x08, 0x40, 0x80, 0x32, ++ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x79, 0x21, 0x2f, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x02, 0x44, 0xe2, 0x25, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x90, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0x3c, ++ 0x00, 0x00, 0x82, 0x08, 0x04, 0xb0, 0x00, 0xe0, 0xd6, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x50, 0x08, 0x04, 0x00, 0x00, 0x3c, 0xd8, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x81, 0xbc, ++ 0x00, 0x00, 0x34, 0x08, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0xe2, 0xe0, 0x38, 0xb2, ++ 0x00, 0x00, 0x41, 0x08, 0x51, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf9, 0x81, 0x83, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0xe2, 0xe5, 0x38, 0xb2, ++ 0x00, 0x00, 0x39, 0x08, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x5c, 0x10, 0x00, 0xa0, 0x01, 0x50, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xe0, 0x06, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0x3b, 0x08, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x3f, 0x08, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x3a, 0x08, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x46, 0x08, 0x2a, 0x01, 0x00, 0x00, 0xd8, 0x20, 0x80, 0xba, ++ 0x00, 0x00, 0x45, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0xe0, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xf0, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x81, 0x83, 0x35, ++ 0x00, 0x00, 0x28, 0x08, 0x04, 0xb0, 0x00, 0x80, 0x82, 0x9b, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x0d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x42, 0x80, 0x2f, 0x35, ++ 0x08, 0xa0, 0x28, 0x08, 0x12, 0x01, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf9, 0x81, 0x83, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0xe2, 0xe5, 0x38, 0xb2, ++ 0x00, 0x00, 0x58, 0x08, 0x28, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0xba, ++ 0x00, 0x00, 0x5b, 0x10, 0x00, 0xa0, 0x01, 0x50, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x58, 0x08, 0x1d, 0xf8, 0x01, 0xe0, 0x06, 0x00, 0x85, 0xb2, ++ 0x00, 0x00, 0x58, 0x08, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0x5c, 0x08, 0x04, 0xa0, 0x00, 0xe0, 0x06, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xe8, 0x06, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x90, 0x00, 0xe0, 0x06, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x6e, 0x08, 0x00, 0x98, 0x00, 0xe0, 0x06, 0xc0, 0x84, 0x92, ++ 0x00, 0x00, 0x62, 0x08, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x5f, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x62, 0x08, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x5e, 0x08, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x80, 0x2f, 0x94, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xe0, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0xe8, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xf0, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x6a, 0x08, 0x04, 0xb0, 0x00, 0x80, 0x82, 0x9b, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x0d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x42, 0x80, 0x2f, 0x35, ++ 0x08, 0xa0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0xe0, 0x06, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xe0, 0x06, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x90, 0x00, 0xe0, 0x06, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xe8, 0x06, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0x74, 0x08, 0x2a, 0x5d, 0x01, 0xec, 0x06, 0x80, 0xee, 0xb2, ++ 0x00, 0x00, 0x71, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x74, 0x08, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x70, 0x08, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x80, 0x2f, 0x94, ++ 0x10, 0x04, 0x77, 0x08, 0x37, 0x00, 0x00, 0xf8, 0xa2, 0x8d, 0x2f, 0xb1, ++ 0x3b, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x72, 0x81, 0x2f, 0x34, ++ 0x08, 0x00, 0x00, 0x00, 0xca, 0x1c, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x39, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x7d, 0x08, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x7c, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xc2, 0x00, 0x03, 0xbc, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x80, 0x67, 0xa1, 0x73, 0x39, ++ 0x30, 0x00, 0xa4, 0x03, 0x12, 0x01, 0x00, 0x5c, 0xa2, 0x8d, 0x2c, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xd2, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x2a, 0x00, 0x00, 0x78, 0xf9, 0x81, 0x83, 0xb4, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0xe2, 0xe5, 0x38, 0xb2, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x8a, 0x08, 0x1d, 0x00, 0x00, 0x38, 0x18, 0x81, 0x83, 0xb5, ++ 0x00, 0x00, 0x8a, 0x08, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0x8d, 0x08, 0x04, 0x06, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x42, 0x80, 0x2f, 0x34, ++ 0x08, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0xb2, ++ 0x00, 0x00, 0x90, 0x08, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x5c, 0x10, 0x00, 0xa0, 0x01, 0x50, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xe0, 0x06, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0x92, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xae, 0x08, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x95, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0x35, ++ 0x00, 0x00, 0xac, 0x08, 0x04, 0x00, 0x00, 0x80, 0x02, 0x61, 0x80, 0xbc, ++ 0x00, 0x00, 0xa4, 0x08, 0x80, 0xb8, 0x00, 0x00, 0x09, 0xc0, 0x6e, 0xb2, ++ 0x40, 0x00, 0x9c, 0x08, 0x04, 0x00, 0x00, 0x80, 0x82, 0x0d, 0x90, 0xbc, ++ 0x80, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x0d, 0x90, 0xbc, ++ 0x00, 0x00, 0x9c, 0x08, 0x02, 0xb0, 0x00, 0x80, 0x82, 0x1b, 0x84, 0xbc, ++ 0x00, 0x00, 0xa4, 0x08, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x07, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xb2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0xd6, 0x01, 0x80, 0x52, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xec, 0x56, 0xc0, 0x6e, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x18, 0x00, 0x86, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xb7, 0x01, 0x78, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0xe0, 0x06, 0x00, 0x86, 0x32, ++ 0x40, 0x00, 0xae, 0x08, 0x04, 0x00, 0x00, 0x80, 0x82, 0x0d, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xa0, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x20, 0x80, 0xfa, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x00, 0x00, 0x3c, 0x18, 0x20, 0x84, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xb0, 0x00, 0x3c, 0x88, 0xdb, 0x83, 0xbe, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x01, 0x78, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf7, 0x20, 0x78, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x58, 0x78, 0x01, 0xe0, 0xf6, 0x20, 0x86, 0x3a, ++ 0x00, 0x00, 0x25, 0x08, 0x00, 0x00, 0x00, 0x04, 0xf8, 0x60, 0x80, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x81, 0x2f, 0xb6, ++ 0x2e, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xc2, 0x00, 0x03, 0xbc, ++ 0x10, 0x00, 0x00, 0x00, 0xd4, 0x18, 0x00, 0x80, 0x67, 0xa1, 0x73, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0xda, 0x5c, 0x01, 0xec, 0x06, 0x80, 0xee, 0x32, ++ 0x30, 0x00, 0xaa, 0x07, 0x12, 0x01, 0x00, 0x5c, 0xa2, 0x8d, 0x2c, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x1a, 0x08, 0x00, 0x00, 0x00, 0xf8, 0xc2, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xb8, 0x08, 0x80, 0x00, 0x00, 0x80, 0xc2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xbb, 0x08, 0x00, 0xd0, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xc2, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0xbb, 0x08, 0x04, 0xd1, 0x01, 0x80, 0x02, 0x80, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xec, 0x26, 0xc0, 0x6e, 0x34, ++ 0x00, 0x00, 0xbd, 0x08, 0x80, 0x00, 0x00, 0x80, 0x92, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc0, 0x08, 0x00, 0xc8, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x92, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0xc0, 0x08, 0x04, 0xc9, 0x01, 0x80, 0x02, 0x80, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0x34, ++ 0x10, 0x00, 0xaa, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x9a, 0x01, 0x00, 0xf8, 0x42, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0xaa, 0x07, 0x12, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x20, 0xb2, ++ 0x00, 0x00, 0xc7, 0x08, 0x12, 0x01, 0x00, 0x5c, 0x08, 0x80, 0x20, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x02, 0x80, 0x2c, 0xb2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0xff, 0x9a, ++ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x79, 0x21, 0x2f, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf9, 0x81, 0x97, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x02, 0x44, 0xe2, 0x25, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x50, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0x60, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x0c, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x1c, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x77, 0x10, 0x00, 0xa8, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf8, 0x01, 0xe0, 0x06, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xda, 0x5c, 0x01, 0xec, 0x06, 0x80, 0xee, 0x32, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0xd4, 0x08, 0x23, 0x29, 0x02, 0x04, 0x09, 0x80, 0x6e, 0xb2, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x08, 0x00, 0xd8, 0x08, 0x1d, 0x1c, 0x01, 0xe8, 0x76, 0x20, 0x81, 0xb9, ++ 0x00, 0x00, 0xd8, 0x08, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xdc, 0x08, 0x9d, 0x01, 0x00, 0x80, 0x07, 0xc0, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x80, 0x07, 0xc0, 0x91, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x80, 0x07, 0x00, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x07, 0xc0, 0x85, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x07, 0x40, 0x90, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x80, 0x87, 0x8d, 0x85, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0x07, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x80, 0x07, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0xe3, 0x08, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x30, 0x00, 0xa4, 0x03, 0x12, 0x01, 0x00, 0x5c, 0xa2, 0x8d, 0x2c, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x12, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x8d, 0x2f, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x01, 0x78, 0x09, 0x80, 0x6e, 0x32, ++ 0x00, 0x00, 0xaa, 0x07, 0xdc, 0xd1, 0x01, 0xe8, 0x06, 0x80, 0x97, 0x92, ++ 0x12, 0x00, 0xaa, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x00, 0x00, 0x18, 0x09, 0x40, 0x81, 0xf2, ++ 0x00, 0x00, 0x2f, 0x0e, 0x00, 0xa8, 0x01, 0x20, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xaa, 0x07, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x80, 0x2f, 0xb6, ++ 0x30, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x42, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0xaa, 0x07, 0x35, 0x01, 0x00, 0xf8, 0x12, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0xf6, 0x08, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x47, 0x10, 0x00, 0x98, 0x01, 0x28, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0x08, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xff, 0x08, 0x80, 0x00, 0x00, 0x80, 0x42, 0x81, 0x2f, 0xb6, ++ 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x2f, 0xd2, ++ 0x00, 0x00, 0xff, 0x08, 0x08, 0x5b, 0x01, 0xec, 0x06, 0xfb, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x34, 0x00, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0x32, ++ 0x00, 0x00, 0x06, 0x09, 0x80, 0x01, 0x00, 0x80, 0x92, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xc2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x0d, 0x09, 0x08, 0xc9, 0x01, 0xe8, 0x06, 0xbb, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x32, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x01, 0xf2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x0d, 0x09, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x92, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x0d, 0x09, 0x08, 0xd1, 0x01, 0xe8, 0x06, 0xbb, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x32, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x28, 0x09, 0xc0, 0x01, 0xf2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x81, 0x2f, 0xb6, ++ 0x17, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x07, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x13, 0x09, 0x12, 0x00, 0x00, 0xc8, 0x02, 0x00, 0x20, 0xb2, ++ 0x00, 0x00, 0x16, 0x09, 0x12, 0x01, 0x00, 0x5c, 0x08, 0x80, 0x20, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x02, 0x80, 0x2c, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0xff, 0x3a, ++ 0x00, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x79, 0x21, 0x2f, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf9, 0x81, 0x97, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x02, 0x44, 0xe2, 0x25, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xd4, 0xa0, 0x01, 0x50, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xdb, 0x79, 0x01, 0x60, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xe0, 0x06, 0x00, 0x85, 0x32, ++ 0x00, 0x00, 0x1f, 0x09, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x30, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0xa2, 0x8d, 0x2c, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x07, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xaa, 0x07, 0xda, 0x5c, 0x01, 0xec, 0x06, 0x80, 0xee, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x9f, 0x41, 0x01, 0x80, 0x52, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x2d, 0x09, 0x9f, 0x98, 0x01, 0x80, 0x52, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0x2b, 0x09, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0xaa, 0x07, 0x31, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x12, 0x81, 0x2f, 0x34, ++ 0x3a, 0x00, 0xaa, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x47, 0x10, 0x00, 0x98, 0x01, 0x28, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0xd5, 0x41, 0x01, 0xe0, 0x06, 0x40, 0x81, 0x92, ++ 0x00, 0x00, 0xaa, 0x07, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x60, 0x11, 0x00, 0x78, 0x01, 0x60, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x78, 0x09, 0x80, 0x6e, 0x32, ++ 0x00, 0x00, 0x35, 0x09, 0x04, 0xd4, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x80, 0x97, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0xe0, 0xe6, 0x25, 0x6e, 0x3a, ++ 0x00, 0x00, 0x60, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x39, 0x09, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xaa, 0x07, 0x00, 0x90, 0x01, 0xe0, 0x06, 0x00, 0x80, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0xe0, 0x06, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x1a, 0x08, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x00, 0x6e, 0x32, ++ 0x02, 0x00, 0x3f, 0x09, 0x04, 0xb9, 0x00, 0x80, 0x82, 0xcd, 0x6e, 0xbc, ++ 0x00, 0x00, 0x41, 0x09, 0x80, 0x00, 0x00, 0x80, 0x72, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0x44, 0x09, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x41, 0x09, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0xfc, 0xb6, ++ 0x00, 0x00, 0x44, 0x09, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0xf5, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x42, 0xbd, 0x97, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x99, 0xb1, 0xf2, 0xc0, 0x7c, 0x30, ++ 0x00, 0xc0, 0x48, 0x09, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x08, 0x00, 0x80, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x07, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xa2, 0x00, 0x2d, 0x37, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x99, 0xe1, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x4d, 0x09, 0x04, 0x01, 0x00, 0x78, 0x19, 0x80, 0x97, 0xbc, ++ 0x02, 0x00, 0x59, 0x09, 0x04, 0xb9, 0x00, 0x80, 0x82, 0xcd, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x48, 0xd6, 0x01, 0x00, 0x78, 0xc9, 0xcd, 0x2c, 0x32, ++ 0x00, 0x00, 0x51, 0x09, 0xb6, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x64, 0x02, 0x80, 0x97, 0xb2, ++ 0x00, 0x00, 0x53, 0x09, 0x12, 0x08, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x54, 0x09, 0x12, 0x18, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x55, 0x09, 0x12, 0x10, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xa6, 0x54, 0x01, 0xec, 0x06, 0x00, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0xe8, 0x06, 0xc0, 0x2c, 0x32, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x0e, 0x01, 0xec, 0x06, 0x00, 0x00, 0x94, ++ 0x00, 0x20, 0x00, 0x4c, 0xd6, 0x01, 0x00, 0x78, 0xc9, 0xcd, 0x2c, 0x32, ++ 0x00, 0x00, 0x5a, 0x09, 0xb6, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x64, 0x02, 0x80, 0x97, 0xb2, ++ 0x00, 0x00, 0x5c, 0x09, 0x12, 0x08, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x5d, 0x09, 0x12, 0x30, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x5e, 0x09, 0x12, 0x38, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x5f, 0x09, 0x12, 0x40, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x60, 0x09, 0x12, 0x48, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x61, 0x09, 0x12, 0x10, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x62, 0x09, 0x12, 0x18, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x63, 0x09, 0x12, 0x20, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x64, 0x09, 0x12, 0x28, 0x00, 0x64, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xa6, 0x54, 0x01, 0xec, 0x06, 0x00, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0xe8, 0x06, 0xc0, 0x2c, 0x32, ++ 0x03, 0x00, 0xa2, 0x07, 0x00, 0x0e, 0x01, 0xec, 0x06, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x02, 0x32, ++ 0x00, 0x00, 0x6b, 0x09, 0x00, 0x00, 0x00, 0x14, 0x08, 0x80, 0x3d, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x02, 0x32, ++ 0x00, 0x00, 0x6e, 0x09, 0x04, 0x00, 0x00, 0xdc, 0x53, 0x60, 0x3d, 0xb3, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x03, 0x39, ++ 0x6a, 0x09, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0x74, 0x09, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x14, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x10, 0x00, 0x82, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0xa2, 0x07, 0xca, 0x01, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x94, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x62, 0x81, 0x2f, 0xb6, ++ 0x2c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x7d, 0x09, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x29, 0x00, 0xa2, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x2c, 0x09, 0xc0, 0x85, 0xd2, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0xa1, 0x03, 0x23, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x3c, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x2c, 0x09, 0xc0, 0x85, 0xd2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0x8c, 0x09, 0x38, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0xb2, ++ 0x00, 0x00, 0x8c, 0x09, 0x1e, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8f, 0x09, 0x12, 0x01, 0x00, 0x60, 0x08, 0x40, 0x23, 0xb2, ++ 0x00, 0x82, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xf2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x24, 0x08, 0x00, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x20, 0x08, 0xc0, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x18, 0x08, 0x80, 0x23, 0xb2, ++ 0x00, 0xc0, 0x99, 0x09, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x38, 0x02, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x30, 0x02, 0x40, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x34, 0x02, 0x00, 0x86, 0xb2, ++ 0x20, 0x80, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xf2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x01, 0x0e, 0x00, 0x30, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0xfa, ++ 0x00, 0x00, 0xa2, 0x09, 0x38, 0x01, 0x00, 0x2c, 0xf8, 0x01, 0x0b, 0xb4, ++ 0x00, 0x00, 0xa2, 0x09, 0x02, 0x0d, 0x02, 0x80, 0xa2, 0x5b, 0x80, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xc8, 0xc1, 0x82, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0xa8, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x3b, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xa7, 0x09, 0x27, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x2c, 0xe8, 0xc0, 0x82, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0xd5, 0x40, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x32, ++ 0x08, 0x00, 0xb0, 0x10, 0x00, 0x18, 0x01, 0xe8, 0x76, 0x20, 0x81, 0xf9, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0xab, 0x09, 0x23, 0x19, 0x00, 0x00, 0x07, 0x80, 0x81, 0xb2, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xad, 0x09, 0x1d, 0x21, 0x00, 0x00, 0x07, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0xb0, 0x09, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xb0, 0x09, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x62, 0x80, 0x2d, 0xbc, ++ 0x10, 0x00, 0xb6, 0x09, 0x2c, 0x30, 0x00, 0x00, 0x17, 0xe0, 0x2c, 0xb9, ++ 0x00, 0x00, 0xb8, 0x09, 0x8e, 0x39, 0x00, 0x00, 0x07, 0xc0, 0x82, 0xb2, ++ 0x00, 0x00, 0xb8, 0x09, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x87, 0x92, ++ 0x00, 0x00, 0xb8, 0x09, 0x8e, 0x39, 0x00, 0x00, 0xb7, 0xc1, 0x82, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x87, 0x32, ++ 0x00, 0x00, 0xba, 0x09, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xc0, 0x09, 0x04, 0x01, 0x00, 0x80, 0x12, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0xb8, 0x09, 0x9f, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x34, ++ 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc8, 0x09, 0x1e, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0xa8, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x08, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x3b, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xa4, 0x07, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0xce, 0x09, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0xa4, 0x07, 0x12, 0x01, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x00, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x1c, 0x40, 0x02, 0x80, 0x06, 0xc0, 0x85, 0xb2, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x00, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x2c, 0x10, 0xd6, 0x01, 0x00, 0x2c, 0x09, 0xc0, 0x85, 0xd2, ++ 0x00, 0x00, 0xa1, 0x03, 0xd2, 0x01, 0x00, 0x94, 0x1e, 0x40, 0xe9, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x20, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xf2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xee, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x51, 0x01, 0x80, 0x02, 0x80, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x21, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xe8, 0x06, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0xe4, 0x09, 0x1f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xe1, 0x09, 0x9e, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa4, 0x07, 0x2a, 0x31, 0x01, 0xe0, 0x06, 0x00, 0x00, 0xb2, ++ 0x18, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0x39, ++ 0xa4, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x0c, 0x00, 0xeb, 0x09, 0x00, 0x00, 0x00, 0x58, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0xeb, 0x09, 0x00, 0x00, 0x00, 0x58, 0x08, 0x00, 0x00, 0x92, ++ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x08, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x20, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xf2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xee, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x30, 0x00, 0x28, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x25, 0x0a, 0x38, 0x00, 0x00, 0xa4, 0x08, 0x80, 0x82, 0xb2, ++ 0x00, 0x00, 0x25, 0x0a, 0x04, 0x28, 0x01, 0x04, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x50, 0x01, 0x04, 0xa8, 0x5b, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x20, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x0a, 0x0a, 0x08, 0x01, 0x00, 0x28, 0x18, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0xe0, 0xa6, 0x20, 0x00, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0xfb, 0x09, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x20, 0x00, 0x80, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x3d, 0x00, 0x0c, 0x07, 0x80, 0x83, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x08, 0x0a, 0x04, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3a, ++ 0x00, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0x66, 0x0a, 0x12, 0x01, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x6c, 0x18, 0x20, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x0f, 0x0a, 0x00, 0x38, 0x01, 0xe0, 0x06, 0x40, 0x80, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x6c, 0x18, 0x20, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x11, 0x0a, 0x9f, 0x01, 0x00, 0x04, 0x68, 0x60, 0x80, 0xbc, ++ 0x00, 0x00, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x18, 0x18, 0x20, 0x00, 0x9c, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x14, 0x0a, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x70, 0x00, 0x18, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x0d, 0x0a, 0x02, 0x01, 0x00, 0x80, 0x62, 0x60, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0x35, ++ 0x00, 0xa0, 0x0d, 0x0a, 0x12, 0x01, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x1f, 0x0a, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x1f, 0x0a, 0x04, 0x00, 0x00, 0x80, 0xa2, 0xa0, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0x35, ++ 0x00, 0xa0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xe8, 0x06, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xe0, 0x06, 0x80, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xe0, 0x06, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0xe0, 0x06, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x27, 0x0a, 0x00, 0x18, 0x00, 0xe0, 0x06, 0xc0, 0x84, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0xa3, 0x0e, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x2a, 0x0a, 0x00, 0x50, 0x01, 0x3c, 0xa8, 0x5b, 0x80, 0x9c, ++ 0x00, 0x00, 0xa4, 0x07, 0x00, 0x30, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x2f, 0x0a, 0x3e, 0x51, 0x01, 0x00, 0xa8, 0x1b, 0x80, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0xf8, 0xf2, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0xec, 0x06, 0xc0, 0xee, 0x32, ++ 0x00, 0x00, 0x2f, 0x0a, 0x80, 0x01, 0x00, 0x80, 0x32, 0x80, 0x87, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x4c, 0x0f, 0x60, 0x30, 0x01, 0xe0, 0x06, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x7b, 0x0a, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x3a, 0x0a, 0x04, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xc9, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0xa4, 0xa8, 0x60, 0x8a, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x0f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0xc0, 0x3e, 0x0a, 0x12, 0x01, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0xa4, 0xa8, 0x60, 0x8a, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x0f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xde, 0xa8, 0x01, 0x20, 0x99, 0x22, 0x6e, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x02, 0x80, 0x82, 0x1b, 0x92, 0xbc, ++ 0x00, 0x00, 0x42, 0x0a, 0x2f, 0x20, 0x01, 0xe0, 0x96, 0x22, 0x6e, 0xbc, ++ 0x00, 0x00, 0x2f, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x4a, 0x0a, 0x1f, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x45, 0x0a, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x83, 0xbc, ++ 0x00, 0x00, 0x4a, 0x0a, 0x00, 0x50, 0x01, 0xe8, 0xf6, 0x60, 0x80, 0x9c, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x78, 0x39, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x08, 0x00, 0x73, 0x11, 0x00, 0x40, 0x02, 0x14, 0x39, 0x9a, 0xfe, 0xd8, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x68, 0x12, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x4f, 0x0a, 0x2a, 0xa9, 0x01, 0xe0, 0x06, 0x00, 0x92, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x4f, 0x0a, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x4b, 0x0a, 0x04, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x52, 0x0a, 0x80, 0x01, 0x00, 0x80, 0x32, 0x80, 0x2f, 0xb6, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x32, ++ 0x00, 0xc0, 0x61, 0x0a, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x18, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x82, 0xb6, ++ 0x00, 0x00, 0x58, 0x0a, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x81, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x18, 0x00, 0x5a, 0x0a, 0x2e, 0x49, 0x01, 0xe0, 0xe6, 0xa0, 0x82, 0xb9, ++ 0x00, 0x00, 0x5b, 0x0a, 0x00, 0x5e, 0x01, 0xec, 0x76, 0x00, 0x00, 0x94, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x20, 0x80, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xf2, ++ 0x1b, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x0c, 0x00, 0xa1, 0x03, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x85, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x30, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0xc2, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x9e, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x80, 0x85, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2f, 0xb6, ++ 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xcb, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x67, 0x0a, 0x0b, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x6e, 0x0a, 0x3d, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x85, 0xb2, ++ 0x00, 0x00, 0x6e, 0x0a, 0x34, 0x00, 0x00, 0xf8, 0xd2, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x72, 0x0a, 0x80, 0x01, 0x00, 0x80, 0x92, 0x80, 0x2f, 0xb6, ++ 0x2a, 0x00, 0x78, 0x0a, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x75, 0x0a, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x78, 0x0a, 0x80, 0x01, 0x00, 0x80, 0x62, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x78, 0x0a, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0xa2, 0x07, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x85, 0xbc, ++ 0x00, 0x00, 0xc2, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x9e, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x80, 0x85, 0x92, ++ 0x00, 0x00, 0xa4, 0x07, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x80, 0x0a, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x31, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x31, 0x00, 0x80, 0x82, 0x9b, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x12, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xce, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0x86, 0x0a, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xf2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x8f, 0x0a, 0x3f, 0x00, 0x00, 0x3c, 0x08, 0x40, 0x80, 0xb2, ++ 0x00, 0x00, 0x8f, 0x0a, 0x80, 0x01, 0x00, 0x80, 0xe2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0xf8, 0xf2, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0xec, 0x06, 0xc0, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0xda, 0x0a, 0x04, 0x00, 0x00, 0x28, 0xd8, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0x3c, ++ 0x00, 0x00, 0xb0, 0x0a, 0x04, 0x00, 0x00, 0x3c, 0xd8, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x81, 0xbc, ++ 0x00, 0x00, 0x9b, 0x0a, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0x02, 0xc0, 0x38, 0xb2, ++ 0x00, 0x00, 0xae, 0x0a, 0x51, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0xa7, 0x0a, 0x28, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0xa5, 0x0a, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xa1, 0x0a, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0xa5, 0x0a, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0xa5, 0x0a, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xa3, 0x0a, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xe0, 0x16, 0x20, 0x6e, 0x3c, ++ 0x00, 0x00, 0x3c, 0x0e, 0xda, 0x5b, 0x01, 0xec, 0x06, 0x40, 0xed, 0xf2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xac, 0x0a, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xa7, 0x0a, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xaf, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x20, 0x80, 0xfa, ++ 0x00, 0x00, 0x90, 0x0a, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x9e, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0xbc, 0x0a, 0x28, 0x00, 0x00, 0x80, 0x08, 0x40, 0x00, 0xb2, ++ 0x00, 0x00, 0xba, 0x0a, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xb6, 0x0a, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0xba, 0x0a, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0xba, 0x0a, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xb8, 0x0a, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0xe0, 0x16, 0x20, 0x6e, 0x3c, ++ 0x00, 0x00, 0x3c, 0x0e, 0xda, 0x5b, 0x01, 0xec, 0x06, 0x40, 0xed, 0xf2, ++ 0x00, 0x00, 0xe0, 0x0a, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc0, 0x0a, 0x04, 0x21, 0x00, 0xe0, 0x06, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0xaf, 0x0e, 0x00, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xe0, 0x06, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xe8, 0x06, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0xc6, 0x0a, 0x2a, 0x11, 0x00, 0xe0, 0xd6, 0xe0, 0x86, 0xba, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0xc6, 0x0a, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xc2, 0x0a, 0x9f, 0x01, 0x00, 0x80, 0x18, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x08, 0x00, 0xca, 0x0a, 0x23, 0x19, 0x01, 0xe8, 0x76, 0x20, 0x81, 0xb9, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xce, 0x0a, 0x1d, 0x18, 0x00, 0xe0, 0x06, 0xc0, 0x84, 0xb2, ++ 0x00, 0x00, 0xce, 0x0a, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xd3, 0x0a, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0xd2, 0x0a, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x80, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0xa4, 0x03, 0x12, 0x01, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x19, 0x20, 0x6e, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xe2, 0xa5, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0xe4, 0x0a, 0x04, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0xe5, 0x0a, 0xc9, 0x01, 0x00, 0x14, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x45, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xef, 0x0a, 0x28, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0xee, 0x0a, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xea, 0x0a, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0xee, 0x0a, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0xee, 0x0a, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xec, 0x0a, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x3c, 0x0e, 0xda, 0x5b, 0x01, 0xec, 0x06, 0x40, 0xed, 0xf2, ++ 0x00, 0x20, 0x00, 0x80, 0xdf, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xf3, 0x0a, 0x3d, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0xb2, ++ 0x00, 0x00, 0xf3, 0x0a, 0x34, 0x00, 0x00, 0xf8, 0xd2, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0xcb, 0x10, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x81, 0x2f, 0xf5, ++ 0x08, 0x00, 0xb0, 0x10, 0x00, 0x18, 0x01, 0xe8, 0x76, 0x20, 0x81, 0xf9, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0xf8, 0x0a, 0x80, 0x01, 0x00, 0x80, 0x32, 0x80, 0x2f, 0xb6, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xfd, 0x0a, 0x29, 0x08, 0x01, 0xe4, 0x06, 0xc0, 0x2d, 0xb2, ++ 0x00, 0x00, 0x02, 0x0b, 0x1d, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x02, 0x0b, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0xff, 0x0a, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x01, 0x0b, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xfe, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0x9c, ++ 0x2a, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xc7, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x05, 0x0b, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x81, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x31, 0x00, 0x80, 0x82, 0x9b, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x00, 0x00, 0x80, 0x12, 0xa0, 0x82, 0xbc, ++ 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0xa9, 0x60, 0x80, 0xd9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0x15, 0x0b, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xf2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x8d, 0x2f, 0x31, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x20, 0x0b, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xa8, 0x60, 0x80, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x08, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x3b, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x08, 0x80, 0x82, 0xf2, ++ 0x00, 0x00, 0x21, 0x0b, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x20, 0x80, 0x3a, ++ 0x00, 0x00, 0x26, 0x0b, 0x04, 0x00, 0x00, 0x28, 0x68, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xaf, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x17, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x81, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xc7, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x2e, 0x0b, 0x3d, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x85, 0xb2, ++ 0x00, 0x00, 0x2e, 0x0b, 0x34, 0x00, 0x00, 0xf8, 0xd2, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x04, 0x08, 0x80, 0x86, 0xb2, ++ 0x00, 0x00, 0x3c, 0x0b, 0x04, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x28, 0x09, 0x80, 0x80, 0xb2, ++ 0x00, 0x00, 0xef, 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xd2, ++ 0x00, 0x00, 0x34, 0x0b, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x3a, 0x10, 0x00, 0x00, 0x00, 0x78, 0x38, 0x80, 0x87, 0xf5, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0xc2, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0xa5, 0x02, 0x23, 0x01, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x32, 0x80, 0x2f, 0x35, ++ 0x3c, 0x00, 0xa5, 0x02, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x3f, 0x0b, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x31, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x41, 0x0b, 0x12, 0x01, 0x00, 0x60, 0x08, 0x40, 0x23, 0xb2, ++ 0x00, 0x82, 0x4b, 0x0b, 0x00, 0x00, 0x00, 0x08, 0xa8, 0x8d, 0x80, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x24, 0x08, 0x00, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x20, 0x08, 0xc0, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x18, 0x08, 0x80, 0x23, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0x5c, 0x0b, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa8, 0x8d, 0x80, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x38, 0x02, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x30, 0x02, 0x40, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x34, 0x02, 0x00, 0x86, 0xb2, ++ 0x00, 0x00, 0x53, 0x0b, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x4f, 0x0b, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x53, 0x0b, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0x53, 0x0b, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x51, 0x0b, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x80, 0xd2, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0xc0, 0xf5, 0x3a, ++ 0x00, 0x00, 0xa4, 0x07, 0x00, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x39, 0x10, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x81, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x17, 0xe0, 0x2c, 0x39, ++ 0x00, 0x10, 0x00, 0x80, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x6a, 0x0b, 0x80, 0x01, 0x00, 0x80, 0x32, 0x80, 0x2f, 0xb6, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xc3, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x6e, 0x0b, 0x1d, 0x21, 0x00, 0x00, 0x07, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x71, 0x0b, 0x80, 0x01, 0x00, 0x80, 0x62, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x71, 0x0b, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x74, 0x0b, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0xa4, 0x03, 0xca, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x7e, 0x0b, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x7a, 0x0b, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x7e, 0x0b, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0x7e, 0x0b, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x7c, 0x0b, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x80, 0x0b, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x86, 0xbc, ++ 0x00, 0x00, 0x0a, 0x11, 0x00, 0x90, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x3f, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x87, 0x0b, 0x33, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0xb2, ++ 0x00, 0x00, 0x87, 0x0b, 0x80, 0x01, 0x00, 0x80, 0xb2, 0x01, 0x72, 0xb6, ++ 0x00, 0x00, 0x87, 0x0b, 0x9f, 0xf0, 0x01, 0x80, 0x82, 0xdb, 0x87, 0xbc, ++ 0x00, 0x00, 0x87, 0x0b, 0x9f, 0xf8, 0x01, 0x80, 0x22, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0xe0, 0x06, 0x00, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xe0, 0x06, 0xc0, 0x87, 0x32, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x39, ++ 0x00, 0x00, 0x8d, 0x0b, 0x80, 0x01, 0x00, 0x80, 0xd2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8d, 0x0b, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0xf8, 0x72, 0x81, 0x2f, 0x34, ++ 0x3b, 0x00, 0x8d, 0x0b, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x9d, 0x0b, 0x27, 0x09, 0x01, 0xe4, 0x06, 0xc0, 0x2d, 0xb2, ++ 0x00, 0xc0, 0x95, 0x0b, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x20, 0x80, 0xa4, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x92, ++ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x98, 0x01, 0x14, 0x09, 0x00, 0x6e, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xe0, 0x06, 0x40, 0x88, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xd5, 0x08, 0x00, 0x00, 0x07, 0x40, 0x88, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x40, 0x00, 0x80, 0xca, 0x39, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x34, ++ 0x00, 0x00, 0xa1, 0x0b, 0x1d, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xa1, 0x0b, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0xc7, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0xa4, 0x03, 0x12, 0x01, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0xae, 0x0b, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xee, 0x10, 0x00, 0x20, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x30, 0x00, 0x28, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x08, 0x80, 0x82, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x18, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xb6, 0x0b, 0x00, 0x50, 0x01, 0x3c, 0xa8, 0x5b, 0x80, 0x9c, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0xa8, 0x1b, 0x80, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0xee, 0x0b, 0x04, 0x00, 0x00, 0x28, 0xd8, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0x3c, ++ 0x00, 0x00, 0xd4, 0x0b, 0x04, 0x00, 0x00, 0x3c, 0xd8, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x81, 0xbc, ++ 0x00, 0x00, 0xc5, 0x0b, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0x02, 0xc0, 0x38, 0xb2, ++ 0x00, 0x00, 0xcd, 0x0b, 0x51, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xcb, 0x0b, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc6, 0x0b, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xd2, 0x0b, 0x2a, 0x01, 0x00, 0x00, 0xd8, 0x20, 0x80, 0xba, ++ 0x00, 0x00, 0xd1, 0x0b, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xb7, 0x0e, 0x00, 0x60, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xba, 0x0b, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x9e, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0xdb, 0x0b, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xd5, 0x0b, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x78, 0x39, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x08, 0x00, 0x73, 0x11, 0x00, 0x40, 0x02, 0x14, 0x39, 0x9a, 0xfe, 0xd8, ++ 0x08, 0x00, 0x8a, 0x11, 0x12, 0x40, 0x02, 0x68, 0x12, 0x9a, 0xfe, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0xba, ++ 0x00, 0x00, 0xa3, 0x0e, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0xe6, 0x0b, 0x00, 0x00, 0x00, 0x3c, 0x08, 0x40, 0x80, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb9, 0x0b, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x81, 0xbc, ++ 0x00, 0x00, 0xec, 0x0b, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xeb, 0x0b, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xb7, 0x0e, 0x00, 0x60, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xba, 0x0b, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x9e, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x45, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0xf6, 0x0b, 0x04, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xc9, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3a, ++ 0x00, 0xc0, 0xf7, 0x0b, 0x12, 0x01, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x20, 0x99, 0x22, 0x6e, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x02, 0x80, 0x82, 0x1b, 0x92, 0xbc, ++ 0x00, 0x00, 0xfb, 0x0b, 0x2f, 0x20, 0x01, 0xe0, 0x96, 0x22, 0x6e, 0xbc, ++ 0x00, 0x00, 0x2f, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xff, 0x0b, 0x04, 0x00, 0x00, 0x3c, 0xd8, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0xfe, 0x0b, 0x9f, 0x31, 0x01, 0xe0, 0x96, 0x22, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x07, 0x0c, 0x00, 0x50, 0x01, 0xe8, 0xf6, 0x60, 0x80, 0x9c, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x78, 0x39, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x08, 0x00, 0x73, 0x11, 0x00, 0x40, 0x02, 0x14, 0x39, 0x9a, 0xfe, 0xd8, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x68, 0x12, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x06, 0x0c, 0x9f, 0x31, 0x01, 0xe0, 0x96, 0x22, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0xe0, 0x06, 0x00, 0x92, 0x32, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x0c, 0x0c, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x08, 0x0c, 0x04, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xcb, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x14, 0x0c, 0x23, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0xba, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x15, 0x0c, 0x0b, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x1c, 0x0c, 0x3d, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x85, 0xb2, ++ 0x00, 0x00, 0x1c, 0x0c, 0x34, 0x00, 0x00, 0xf8, 0xd2, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x20, 0x0c, 0x29, 0x31, 0x01, 0x0c, 0x09, 0x00, 0x6e, 0xb2, ++ 0x2a, 0x00, 0xa2, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x27, 0x0e, 0x00, 0x0c, 0x02, 0x00, 0x09, 0x80, 0x6e, 0xf2, ++ 0x00, 0x00, 0x24, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x02, 0xe4, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x27, 0x0c, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x01, 0x00, 0x80, 0x62, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x18, 0x09, 0x40, 0x81, 0xb2, ++ 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x2f, 0x0e, 0x00, 0xa8, 0x01, 0x20, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x0c, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x27, 0x0e, 0x00, 0x0c, 0x02, 0x00, 0x09, 0x80, 0x6e, 0xf2, ++ 0x00, 0x00, 0xa4, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xc2, 0x10, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x90, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x78, 0x0b, 0x16, 0x38, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x78, 0x0b, 0x16, 0x38, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa8, 0x00, 0x2d, 0x37, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x88, 0x0d, 0x8b, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xb4, 0x08, 0x80, 0x6e, 0x32, ++ 0x00, 0x00, 0x45, 0x0c, 0x04, 0x31, 0x01, 0x90, 0x08, 0x00, 0x6e, 0xb2, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x82, 0x8d, 0x8a, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc2, 0xa2, 0x2c, 0x3a, ++ 0x18, 0x00, 0x43, 0x0c, 0x86, 0x41, 0x02, 0x78, 0x88, 0x0d, 0x78, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0xa2, 0xe2, 0x8a, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x41, 0x02, 0x80, 0xb2, 0x3f, 0x78, 0xb0, ++ 0x00, 0x00, 0x3c, 0x0c, 0x9f, 0x01, 0x00, 0xa8, 0x18, 0x80, 0x8a, 0xbc, ++ 0xb7, 0x00, 0x3c, 0x0c, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x04, 0xb8, 0x3f, 0x78, 0x30, ++ 0x00, 0x00, 0x58, 0x0c, 0x00, 0x00, 0x00, 0x04, 0xd8, 0x62, 0x80, 0x9c, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x0c, 0x02, 0x80, 0xa2, 0x1b, 0x89, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x80, 0x2f, 0xb6, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x82, 0x8d, 0x8a, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc2, 0xa2, 0x2c, 0x3a, ++ 0x18, 0x00, 0x4e, 0x0c, 0x86, 0x41, 0x02, 0x78, 0x88, 0x0d, 0x78, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0xa2, 0xe2, 0x8a, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x41, 0x02, 0x80, 0xb2, 0x3f, 0x78, 0xb0, ++ 0x00, 0x00, 0x47, 0x0c, 0x9f, 0x01, 0x00, 0xa8, 0x18, 0x80, 0x8a, 0xbc, ++ 0xb7, 0x00, 0x47, 0x0c, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x51, 0x0c, 0x28, 0x40, 0x02, 0x04, 0xb8, 0x3f, 0x78, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x04, 0xd8, 0x62, 0x80, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x40, 0x80, 0xb2, ++ 0x00, 0x00, 0x55, 0x0c, 0x02, 0x01, 0x00, 0x90, 0x18, 0x20, 0x89, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x47, 0x0c, 0x9f, 0x01, 0x00, 0xa8, 0x18, 0x80, 0x8a, 0xbc, ++ 0xb7, 0x00, 0x47, 0x0c, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x58, 0x0c, 0x04, 0x00, 0x00, 0x90, 0x18, 0x20, 0x89, 0xba, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x04, 0x48, 0x62, 0x80, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x90, 0x00, 0x00, 0xb4, 0x48, 0x62, 0x8b, 0xba, ++ 0x03, 0x00, 0x8a, 0x11, 0x04, 0x40, 0x02, 0x00, 0x08, 0x1e, 0xff, 0xb8, ++ 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x22, 0x80, 0x9a, ++ 0x00, 0x00, 0x89, 0x0c, 0x04, 0x00, 0x00, 0x80, 0xa2, 0xe2, 0x8a, 0xbc, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x82, 0x8d, 0x8a, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc2, 0xa2, 0x2c, 0x3a, ++ 0x18, 0x00, 0x87, 0x0c, 0x86, 0x40, 0x02, 0x78, 0x88, 0x0d, 0x78, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x40, 0x02, 0x04, 0xb8, 0x3f, 0x78, 0xb0, ++ 0x03, 0x00, 0x8a, 0x11, 0x04, 0x40, 0x02, 0x00, 0x08, 0x1e, 0xff, 0xb8, ++ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x80, 0xd2, ++ 0x00, 0x00, 0x67, 0x0c, 0x12, 0x01, 0x00, 0x60, 0x08, 0x40, 0x23, 0xb2, ++ 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x24, 0x08, 0x00, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x20, 0x08, 0xc0, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x18, 0x08, 0x80, 0x23, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0x72, 0x0c, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x38, 0x02, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x30, 0x02, 0x40, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x34, 0x02, 0x00, 0x86, 0xb2, ++ 0x20, 0x80, 0x64, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0xb8, 0x1b, 0x80, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x64, 0x30, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x07, 0x00, 0x82, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x17, 0xe0, 0x2c, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xf7, 0x01, 0x0b, 0x34, ++ 0x00, 0x00, 0x81, 0x0c, 0x80, 0x01, 0x00, 0x80, 0x32, 0x80, 0x87, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xb7, 0x01, 0x70, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x34, ++ 0x00, 0x00, 0x93, 0x0c, 0x02, 0x0c, 0x02, 0x80, 0xa2, 0x1b, 0x89, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x5a, 0x0c, 0x9f, 0x01, 0x00, 0xa8, 0x18, 0x80, 0x8a, 0xbc, ++ 0xb7, 0x00, 0x5a, 0x0c, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x36, 0x92, ++ 0x27, 0x00, 0x8c, 0x0c, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x78, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0xa2, 0x97, 0xbc, ++ 0x00, 0x00, 0x8e, 0x0c, 0x23, 0x55, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0xb2, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x90, 0x0c, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc7, 0x01, 0x70, 0x34, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x08, 0x00, 0x97, 0x0c, 0x23, 0x19, 0x01, 0xe8, 0x76, 0x20, 0x81, 0xb9, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x99, 0x0c, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x9c, 0x0c, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x9c, 0x0c, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc6, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xf9, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xa0, 0x0c, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0xa4, 0x03, 0xca, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x28, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0xad, 0x0c, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x18, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x82, 0xb6, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x01, 0xec, 0x66, 0x00, 0x00, 0x34, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0xe0, 0xe6, 0xa0, 0x82, 0x39, ++ 0x1b, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x20, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xc7, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0xb6, 0x0c, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x02, 0xf2, ++ 0x00, 0x00, 0xbd, 0x0c, 0x00, 0x00, 0x00, 0x5c, 0x08, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0xbd, 0x0c, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0xf2, ++ 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x28, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x20, 0x00, 0x84, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0xc7, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xc2, 0x0c, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc6, 0x0c, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x85, 0xb2, ++ 0x00, 0x00, 0xc6, 0x0c, 0x80, 0x00, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x41, 0x02, 0x80, 0x06, 0xc0, 0x85, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1c, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x4c, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x4c, 0x0d, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x85, 0x92, ++ 0x00, 0x00, 0x1a, 0x0d, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x22, 0x0d, 0x1f, 0x20, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x1a, 0x0d, 0x04, 0x30, 0x01, 0x08, 0x89, 0x9b, 0x90, 0xbc, ++ 0x00, 0x00, 0xd2, 0x0c, 0x04, 0x31, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xd0, 0x0c, 0x00, 0x50, 0x01, 0x48, 0x08, 0x80, 0x6e, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0x61, 0x80, 0x3c, ++ 0x00, 0x00, 0xeb, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x28, 0x21, 0x80, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x80, 0x90, 0xb2, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x30, 0x01, 0x48, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0xd6, 0x0c, 0x00, 0x50, 0x01, 0x04, 0xa8, 0x5b, 0x80, 0x9c, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0xa8, 0x1b, 0x80, 0x3a, ++ 0x00, 0x00, 0xe8, 0x0c, 0x07, 0x00, 0x00, 0x48, 0x18, 0xa0, 0x84, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xa0, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x05, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xa0, 0xfe, 0xd8, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x02, 0xa0, 0xfe, 0x38, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xe1, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe8, 0x0c, 0x07, 0x00, 0x00, 0x48, 0x18, 0xa0, 0x84, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xa0, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x05, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xa0, 0xfe, 0xd8, ++ 0x05, 0x00, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x68, 0x02, 0xa0, 0xfe, 0x98, ++ 0x00, 0x00, 0xeb, 0x0c, 0x04, 0x00, 0x00, 0x48, 0x18, 0xa0, 0x84, 0xba, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x04, 0x28, 0x61, 0x80, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x21, 0x80, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0xf4, 0x0c, 0x12, 0x01, 0x00, 0x60, 0x08, 0x40, 0x23, 0xb2, ++ 0x03, 0x00, 0x8a, 0x11, 0x04, 0x40, 0x02, 0x00, 0x38, 0x1a, 0xff, 0xb8, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x60, 0x80, 0x39, ++ 0x18, 0x00, 0x00, 0x00, 0xd2, 0x41, 0x02, 0x8c, 0xe6, 0xa1, 0x97, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x80, 0x84, 0x32, ++ 0x00, 0x82, 0x00, 0x00, 0xd6, 0x01, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x28, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x24, 0x08, 0x00, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x20, 0x08, 0xc0, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x18, 0x08, 0x80, 0x23, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0xfe, 0x0c, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x38, 0x02, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x30, 0x02, 0x40, 0x82, 0xb2, ++ 0x00, 0x00, 0xed, 0x0c, 0x12, 0x01, 0x00, 0x34, 0x02, 0x00, 0x86, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x07, 0x00, 0x82, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x17, 0xe0, 0x2c, 0x39, ++ 0x00, 0x00, 0x0d, 0x0d, 0x80, 0x00, 0x00, 0x80, 0x32, 0x80, 0x87, 0xb6, ++ 0x00, 0x10, 0x00, 0x80, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x0e, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x10, 0x00, 0x88, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x05, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xa0, 0xfe, 0xd8, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x02, 0xa0, 0xfe, 0x38, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xa0, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0xeb, 0x0c, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x22, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x05, 0x00, 0x1d, 0x0d, 0x00, 0x00, 0x00, 0x68, 0x02, 0xa0, 0xfe, 0x98, ++ 0x00, 0x00, 0x22, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x05, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xa0, 0xfe, 0xd8, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xa0, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x1a, 0x0d, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x00, 0x2d, 0x37, ++ 0xb4, 0xcc, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x99, 0xc0, 0x2c, 0x37, ++ 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x10, 0x00, 0x00, 0x87, 0xbf, 0x97, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x40, 0xfe, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x2b, 0x0d, 0xb6, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x20, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x64, 0xa2, 0xcd, 0x2c, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x30, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xa2, 0x07, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x62, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x39, 0x0d, 0x12, 0x01, 0x00, 0x60, 0x08, 0x40, 0x23, 0xb2, ++ 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x28, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x24, 0x08, 0x00, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x20, 0x08, 0xc0, 0x23, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x18, 0x08, 0x80, 0x23, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0x43, 0x0d, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x38, 0x02, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x82, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x30, 0x02, 0x40, 0x82, 0xb2, ++ 0x00, 0x00, 0xed, 0x0c, 0x12, 0x01, 0x00, 0x34, 0x02, 0x00, 0x86, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x00, 0x00, 0x48, 0x08, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x46, 0x0d, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x0d, 0x00, 0x50, 0x01, 0x00, 0xa8, 0x1b, 0x80, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x28, 0x09, 0x80, 0x02, 0xf2, ++ 0x00, 0x00, 0x2b, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x02, 0xf2, ++ 0x00, 0x00, 0x4f, 0x0d, 0x9a, 0x01, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0xb4, ++ 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x8d, 0x2f, 0x31, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xec, 0x06, 0xc0, 0x6e, 0x34, ++ 0x2d, 0x00, 0xa2, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xa9, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x5a, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x56, 0x0d, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x5a, 0x0d, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0x5a, 0x0d, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x58, 0x0d, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x5c, 0x0d, 0x04, 0x98, 0x01, 0x64, 0x88, 0x1b, 0x87, 0xbc, ++ 0x00, 0x00, 0x0a, 0x11, 0x00, 0x90, 0x01, 0x08, 0x09, 0x80, 0x6e, 0xf2, ++ 0x00, 0x00, 0x3f, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x30, 0x00, 0xa4, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x6c, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x68, 0x0d, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x6c, 0x0d, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0x6c, 0x0d, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x6a, 0x0d, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0xa4, 0x07, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x36, 0x00, 0xa4, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7d, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x79, 0x0d, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x7d, 0x0d, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0x7d, 0x0d, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x7b, 0x0d, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x88, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x86, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x82, 0x0d, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x86, 0x0d, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0x86, 0x0d, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0x84, 0x0d, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x30, 0x00, 0x88, 0x0d, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0xd4, 0xd5, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0xa4, 0x07, 0x12, 0x01, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xa2, 0x07, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x93, 0x0d, 0x80, 0x00, 0x00, 0x80, 0x02, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x58, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xa2, 0x07, 0x08, 0x59, 0x01, 0xec, 0x06, 0xfb, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0x9c, 0x0d, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0xec, 0x06, 0xfb, 0x6e, 0x3a, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc2, 0x10, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x81, 0x2f, 0xf4, ++ 0x00, 0x00, 0x9f, 0x0d, 0x06, 0x03, 0x01, 0x80, 0x12, 0xc0, 0x6e, 0xbc, ++ 0x18, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x19, 0x00, 0x9d, 0x05, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xe2, 0x81, 0x2f, 0xb6, ++ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x8d, 0x2f, 0x31, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x20, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x28, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x45, 0x30, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc7, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xad, 0x0d, 0x04, 0x02, 0x01, 0xec, 0x16, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xc9, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0x34, ++ 0x00, 0xc0, 0xad, 0x0d, 0x12, 0x01, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x18, 0x00, 0x36, 0x00, 0xca, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xad, 0x0d, 0x9f, 0x01, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0xb2, 0x0d, 0x3d, 0x01, 0x00, 0xb0, 0x02, 0x00, 0x85, 0xb2, ++ 0x00, 0x00, 0xb2, 0x0d, 0x34, 0x00, 0x00, 0xf8, 0xd2, 0x81, 0x2f, 0xb5, ++ 0x34, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xa4, 0x07, 0x80, 0x01, 0x00, 0x80, 0x92, 0x80, 0x2f, 0xb6, ++ 0x2a, 0x00, 0xa4, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0xc0, 0xbc, 0x0d, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x00, 0x00, 0x9d, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x72, 0xe0, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x20, 0x00, 0x80, 0xdf, 0x00, 0x00, 0x28, 0x09, 0x00, 0x37, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0x38, 0x88, 0x1b, 0x16, 0x38, ++ 0x00, 0x00, 0x00, 0x00, 0xde, 0x48, 0x01, 0x28, 0x88, 0x04, 0x6e, 0x30, ++ 0x00, 0x00, 0xc1, 0x0d, 0x80, 0x5f, 0x01, 0x80, 0x72, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x00, 0xc3, 0x0d, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x80, 0x2f, 0x94, ++ 0x00, 0x00, 0xc3, 0x0d, 0x80, 0x5f, 0x01, 0x80, 0x62, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xa9, 0x81, 0x92, 0x34, ++ 0x00, 0x00, 0xcb, 0x10, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x01, 0x00, 0xf4, ++ 0x00, 0x00, 0xc6, 0x0d, 0x12, 0x01, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc9, 0x0d, 0x80, 0x01, 0x00, 0x80, 0xd2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc9, 0x0d, 0x34, 0x00, 0x00, 0xf8, 0xd2, 0x81, 0x2f, 0xb5, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0xa4, 0x07, 0x04, 0x30, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x2a, 0x00, 0xa4, 0x07, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0xd8, 0x02, 0x80, 0x01, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0xc0, 0xd2, 0x0d, 0x18, 0x01, 0x00, 0x0c, 0xa8, 0xcd, 0x3e, 0xb2, ++ 0x00, 0x82, 0x00, 0x00, 0xd6, 0x01, 0x00, 0x08, 0x08, 0x80, 0x36, 0x32, ++ 0x1d, 0x00, 0xa1, 0x03, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xc2, 0x10, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x80, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x01, 0x78, 0x09, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x10, 0x00, 0xa0, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x07, 0x00, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x0c, 0x07, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0xf0, 0xe1, 0x0d, 0x1d, 0x40, 0x02, 0x00, 0xa8, 0x0d, 0x68, 0xb1, ++ 0x00, 0x00, 0x8a, 0x11, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x1e, 0x40, 0x02, 0x84, 0x06, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x80, 0xd0, ++ 0x00, 0x00, 0xde, 0x0d, 0xb6, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0xc0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x64, 0xa2, 0x0d, 0x80, 0xb2, ++ 0x00, 0x00, 0xda, 0x0d, 0xa6, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xe1, 0x0d, 0xb5, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x80, 0xa0, 0x36, 0x0b, 0x6a, 0x35, ++ 0x00, 0x00, 0xe6, 0x0d, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x80, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xe9, 0x01, 0x00, 0x34, ++ 0x00, 0x00, 0xef, 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xd2, ++ 0x00, 0x00, 0xeb, 0x0d, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xbc, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x39, 0x0b, 0x2e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xf3, 0x81, 0x97, 0x34, ++ 0x00, 0x00, 0xf1, 0x0d, 0x04, 0x00, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x05, 0x30, 0x30, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0xa4, 0x03, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x33, 0x0b, 0x2f, 0x32, ++ 0x00, 0x00, 0xa4, 0x03, 0x04, 0x00, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb9, 0x05, 0x30, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x02, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x80, 0x97, 0x32, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x29, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xff, 0x0d, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x2f, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x00, 0x2c, 0x32, ++ 0xd9, 0x02, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0x97, 0xbc, ++ 0x46, 0x03, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xf1, 0x0d, 0x00, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x18, 0x0e, 0x02, 0x00, 0x00, 0x80, 0xa2, 0x42, 0x80, 0xbc, ++ 0x00, 0x00, 0x18, 0x0e, 0x80, 0x00, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0x18, 0x0e, 0x1f, 0x40, 0x02, 0x08, 0xb9, 0xbf, 0x68, 0xb0, ++ 0x00, 0x00, 0x08, 0x0e, 0x80, 0x41, 0x02, 0x80, 0xe2, 0x81, 0x68, 0xb6, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x79, 0x61, 0x80, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x21, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3a, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x41, 0x02, 0x88, 0xe6, 0x21, 0x91, 0x79, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x19, 0xa0, 0x90, 0x3a, ++ 0x00, 0x00, 0x18, 0x0e, 0x06, 0x01, 0x00, 0x80, 0xd2, 0xff, 0x90, 0xbc, ++ 0x00, 0x00, 0x0c, 0x0e, 0x2c, 0x41, 0x02, 0x78, 0xf9, 0x81, 0x68, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb9, 0x81, 0x97, 0x34, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x59, 0xc0, 0x85, 0xd7, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x29, 0x1a, 0xff, 0x38, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0xb9, 0x1b, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x41, 0x02, 0x88, 0x16, 0xa0, 0x97, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x27, 0x24, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x8a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x58, 0xf2, 0xc1, 0x38, 0x74, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x08, 0x00, 0x23, 0x0e, 0x1e, 0x01, 0x00, 0x34, 0x79, 0x61, 0x80, 0xb9, ++ 0x00, 0x00, 0x8a, 0x11, 0x38, 0x00, 0x00, 0x54, 0x1f, 0x40, 0xf5, 0xba, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x40, 0x02, 0x00, 0x09, 0x40, 0x68, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb9, 0x3f, 0x90, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0xe0, 0x26, 0x24, 0x6e, 0x3a, ++ 0x08, 0x00, 0x8a, 0x11, 0x1e, 0x00, 0x00, 0x00, 0x09, 0xa4, 0xfe, 0xb8, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x05, 0x90, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0x05, 0x90, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x05, 0x90, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xd2, 0x21, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3a, ++ 0x18, 0x00, 0x00, 0x00, 0x1e, 0x41, 0x02, 0x84, 0xe6, 0x61, 0x93, 0x79, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x01, 0x80, 0x82, 0xdb, 0x90, 0x7c, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x20, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x02, 0x80, 0xa2, 0xdb, 0x90, 0x7c, ++ 0x00, 0x00, 0x2d, 0x0e, 0x06, 0x21, 0x01, 0x80, 0x82, 0x1b, 0x90, 0xbc, ++ 0x26, 0x00, 0x2e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x36, 0x92, ++ 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x12, 0x00, 0x2c, 0x3a, ++ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x92, 0xd2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0x92, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x2f, 0xa0, 0x01, 0x78, 0x89, 0x1b, 0x92, 0x7a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x78, 0x89, 0x9b, 0x97, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x00, 0xf9, 0xba, 0x6e, 0x37, ++ 0x00, 0x00, 0x39, 0x0e, 0x02, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x97, 0xbc, ++ 0x00, 0x00, 0x39, 0x0e, 0x02, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x8d, 0x97, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, 0x80, 0x82, 0x9b, 0x97, 0x7c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0xf2, 0x80, 0x2f, 0x74, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0xda, 0x5b, 0x01, 0xec, 0x06, 0x40, 0xed, 0x32, ++ 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x40, 0x89, 0xd2, ++ 0x00, 0x00, 0x42, 0x0e, 0x08, 0x5d, 0x01, 0xec, 0x16, 0x40, 0x89, 0xbc, ++ 0x00, 0x00, 0x42, 0x0e, 0x0b, 0x5d, 0x01, 0xec, 0x06, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x42, 0x0e, 0x80, 0x00, 0x00, 0x80, 0x42, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x78, 0x89, 0x1b, 0x87, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x92, 0xa1, 0x97, 0xbc, ++ 0x00, 0x00, 0x47, 0x0e, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x86, 0xbc, ++ 0x00, 0x00, 0x0a, 0x11, 0x00, 0x90, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3a, ++ 0x00, 0x00, 0x3f, 0x11, 0x33, 0x01, 0x00, 0xf8, 0x82, 0x80, 0x2f, 0xb4, ++ 0x00, 0x00, 0x3f, 0x11, 0x9f, 0xf0, 0x01, 0x80, 0x82, 0xdb, 0x87, 0xbc, ++ 0x00, 0x00, 0x3f, 0x11, 0x9f, 0xf8, 0x01, 0x80, 0x22, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0xe0, 0x06, 0x00, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xe0, 0x06, 0xc0, 0x87, 0x32, ++ 0x00, 0x00, 0x3f, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x00, 0x00, 0x80, 0x02, 0x80, 0x91, 0xbc, ++ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x50, 0x01, 0x14, 0xa9, 0x9b, 0x91, 0xd9, ++ 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x14, 0x89, 0x0d, 0x6e, 0x37, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x30, 0x01, 0x14, 0x89, 0x5b, 0x91, 0xd2, ++ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x2d, 0xd2, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x21, 0x01, 0x80, 0x82, 0x9b, 0x91, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x78, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x02, 0x80, 0x82, 0x9b, 0x97, 0xbc, ++ 0x00, 0x00, 0x71, 0x0e, 0x04, 0x21, 0x01, 0x30, 0x69, 0x24, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0xa9, 0x9b, 0x91, 0x3a, ++ 0x00, 0x00, 0x66, 0x0e, 0x1f, 0x40, 0x02, 0x24, 0x09, 0x40, 0x68, 0xb2, ++ 0x00, 0x00, 0x5c, 0x0e, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x41, 0x92, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb9, 0x7f, 0x92, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x24, 0x90, 0x3c, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x99, 0xa4, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x08, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x99, 0xa4, 0xfe, 0xd8, ++ 0x08, 0x00, 0x5c, 0x0e, 0x12, 0x01, 0x00, 0x68, 0x92, 0xa4, 0xfe, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x90, 0xbc, ++ 0x00, 0x00, 0x6b, 0x0e, 0x38, 0x50, 0x01, 0x78, 0x09, 0x80, 0x6e, 0xb2, ++ 0x00, 0x00, 0x6b, 0x0e, 0x04, 0x28, 0x01, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x28, 0x01, 0x78, 0xe9, 0x25, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x01, 0x00, 0x78, 0x69, 0xa4, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0xe0, 0x66, 0x24, 0x6e, 0x3a, ++ 0x00, 0x00, 0x6e, 0x0e, 0x38, 0x20, 0x01, 0xe0, 0x06, 0x00, 0x93, 0xb2, ++ 0x00, 0x00, 0x6f, 0x0e, 0x00, 0x28, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x77, 0x0e, 0x38, 0x51, 0x01, 0x00, 0xa9, 0x9b, 0x91, 0xba, ++ 0x00, 0x00, 0x75, 0x0e, 0x04, 0x41, 0x02, 0x08, 0xb9, 0xff, 0x68, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x41, 0x02, 0x80, 0xe2, 0xc1, 0x68, 0xb6, ++ 0x00, 0x00, 0x72, 0x0e, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x92, ++ 0x00, 0x00, 0x84, 0x0e, 0x9f, 0x31, 0x01, 0xe0, 0x66, 0x24, 0x6e, 0xbc, ++ 0x00, 0x00, 0x84, 0x0e, 0x00, 0x30, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x92, ++ 0x00, 0x00, 0x81, 0x0e, 0x04, 0x28, 0x01, 0x04, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x50, 0x01, 0x80, 0xa2, 0x5b, 0x90, 0xbc, ++ 0x00, 0x00, 0x7f, 0x0e, 0x9f, 0x01, 0x00, 0x00, 0x19, 0x24, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0xe0, 0x66, 0x24, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0xe0, 0x06, 0x24, 0x00, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0xe0, 0x06, 0x00, 0x93, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x8e, 0x0e, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xbc, ++ 0x00, 0x00, 0x84, 0x0e, 0x04, 0x41, 0x02, 0x08, 0xb9, 0xff, 0x68, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x41, 0x02, 0x80, 0xe2, 0xc1, 0x68, 0xb6, ++ 0x00, 0x00, 0x81, 0x0e, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x92, ++ 0x00, 0x00, 0x88, 0x0e, 0x02, 0x00, 0x00, 0x80, 0x22, 0x24, 0x90, 0xbc, ++ 0x00, 0x00, 0x8e, 0x0e, 0x80, 0x40, 0x02, 0x80, 0xf2, 0xc1, 0x68, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x8c, 0xb6, 0xc1, 0x68, 0x35, ++ 0x00, 0x00, 0x8e, 0x0e, 0x00, 0x00, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0x94, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x78, 0x39, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x97, 0xd2, ++ 0x08, 0x00, 0x8a, 0x11, 0x12, 0x40, 0x02, 0x68, 0x12, 0x9a, 0xfe, 0xb8, ++ 0x00, 0x00, 0x81, 0x0e, 0x04, 0x01, 0x00, 0x00, 0x29, 0x24, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x79, 0x0b, 0x16, 0x38, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x0b, 0x16, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x42, 0xe4, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xa9, 0x00, 0x2d, 0x37, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x89, 0x4d, 0x90, 0x3a, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x82, 0x0d, 0x91, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x12, 0xa4, 0x2a, 0x3a, ++ 0x00, 0x00, 0x99, 0x0e, 0x80, 0x40, 0x02, 0x80, 0xe2, 0x01, 0x7c, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x40, 0x02, 0x78, 0xb9, 0x3f, 0x7c, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe9, 0xa5, 0x90, 0x3a, ++ 0x00, 0x00, 0x9b, 0x0e, 0x9f, 0x01, 0x00, 0x10, 0x19, 0x00, 0x91, 0xbc, ++ 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x94, 0x0e, 0x04, 0x01, 0x00, 0x80, 0x42, 0xe4, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xc9, 0x24, 0x90, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x22, 0xa4, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0xe0, 0x66, 0x24, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0xe0, 0x06, 0x00, 0x93, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x18, 0x00, 0xa5, 0x0e, 0x1f, 0x41, 0x02, 0x78, 0x88, 0xcd, 0x68, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x12, 0x00, 0x2c, 0x3a, ++ 0x00, 0x00, 0xa8, 0x0e, 0x80, 0x01, 0x00, 0x80, 0x62, 0x80, 0x87, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x41, 0x02, 0x80, 0xb2, 0xff, 0x68, 0xb0, ++ 0x00, 0x00, 0xa3, 0x0e, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x92, ++ 0x03, 0x00, 0x8a, 0x11, 0x04, 0x40, 0x02, 0x00, 0x38, 0x1a, 0xff, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x40, 0x02, 0x04, 0xb8, 0xff, 0x68, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0xb8, 0x1b, 0x80, 0x3a, ++ 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x00, 0x80, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xb6, 0x0e, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xb3, 0x0e, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0xb6, 0x0e, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xb0, 0x0e, 0x9f, 0x01, 0x00, 0x80, 0x18, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x68, 0x00, 0x4c, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x70, 0x00, 0x18, 0x08, 0x00, 0x6e, 0xb2, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0xa9, 0x60, 0x81, 0xd9, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0xa2, 0xa0, 0x81, 0x7c, ++ 0x00, 0x00, 0x8a, 0x11, 0x0d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xc1, 0x0e, 0x80, 0x01, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xc1, 0x0e, 0x1b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x62, 0xe0, 0x83, 0x7c, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0x35, ++ 0x00, 0xa0, 0x00, 0x00, 0x12, 0x01, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0x72, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0xe4, 0x06, 0xc0, 0x2d, 0x32, ++ 0xee, 0xff, 0x00, 0x00, 0x00, 0x10, 0x01, 0xe0, 0x86, 0x8d, 0x2f, 0x31, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xb3, 0xe4, 0x39, 0x32, ++ 0x00, 0x00, 0xcd, 0x0e, 0x04, 0x00, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb9, 0x05, 0x30, 0x30, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe3, 0xa5, 0x03, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x33, 0x0b, 0x2f, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x78, 0xd9, 0x01, 0x30, 0x76, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xb9, 0x05, 0x30, 0x30, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0xe3, 0xa5, 0x03, 0x79, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xd8, 0x0e, 0x20, 0x00, 0x01, 0x2c, 0x09, 0xc0, 0x6e, 0xb2, ++ 0x00, 0x00, 0xd9, 0x0e, 0x00, 0x16, 0x86, 0xcc, 0x06, 0xc0, 0x92, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x86, 0xcc, 0x06, 0xc0, 0x92, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x40, 0x62, 0x8e, 0x92, 0x52, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xdf, 0x0e, 0x04, 0x00, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x42, 0x80, 0x97, 0xbc, ++ 0xdf, 0x0e, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x60, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x2f, 0xb1, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x03, 0x00, 0x38, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x02, 0x00, 0x30, 0x32, ++ 0x00, 0x00, 0x22, 0x0f, 0x04, 0x00, 0x00, 0x24, 0xd8, 0x01, 0x30, 0xb6, ++ 0xe4, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0x4d, 0x82, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0xdf, 0x0e, 0x36, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xec, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x48, 0x05, 0x30, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xf7, 0x0e, 0x32, 0x0f, 0x01, 0xbc, 0x08, 0xc0, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0xdc, 0x02, 0x40, 0x6e, 0x32, ++ 0x00, 0x00, 0xf0, 0x0e, 0x1f, 0x01, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0xf6, 0x0e, 0x1d, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0xe0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x00, 0x2d, 0x37, ++ 0x20, 0xcd, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x97, 0x3a, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x87, 0xa0, 0xea, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0xea, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x38, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0xe0, 0x26, 0x01, 0x6e, 0x35, ++ 0x00, 0x00, 0xfb, 0x0e, 0x80, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x8b, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x0e, 0x82, 0x32, ++ 0x00, 0xe0, 0x03, 0x0f, 0x12, 0x01, 0x00, 0x48, 0xa2, 0x0d, 0x90, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x32, ++ 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x00, 0x2d, 0x37, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x97, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x99, 0x00, 0x82, 0x37, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x10, 0x00, 0x00, 0x87, 0xbf, 0x97, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x40, 0xfe, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x89, 0x60, 0x38, 0x32, ++ 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xa4, 0x17, 0x38, ++ 0x00, 0x00, 0x09, 0x0f, 0x80, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x8b, 0xb6, ++ 0x00, 0x00, 0x0a, 0x0f, 0x04, 0x00, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf3, 0x41, 0x90, 0x34, ++ 0x00, 0x00, 0x0f, 0x0f, 0x04, 0x00, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x05, 0x30, 0x30, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0xa4, 0x03, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xce, 0x2c, 0x32, ++ 0x00, 0xe0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0x0d, 0x90, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0xdc, 0x02, 0x40, 0x6e, 0x32, ++ 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xa4, 0x17, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x32, 0x80, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x10, 0x01, 0x80, 0x22, 0x01, 0x6e, 0xb6, ++ 0x00, 0x00, 0x18, 0x0f, 0x1f, 0x01, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x20, 0x0f, 0x1d, 0x10, 0x01, 0xf8, 0x02, 0x00, 0x6e, 0xb2, ++ 0xe0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x00, 0x2d, 0x37, ++ 0x20, 0xcd, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x97, 0x3a, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x37, 0x8b, 0xea, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0xea, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0xf8, 0x02, 0x00, 0x6e, 0x32, ++ 0xee, 0xff, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x2f, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0xee, 0xff, 0x8a, 0x11, 0x04, 0x11, 0x01, 0x80, 0x82, 0x0d, 0x6e, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0xf8, 0x02, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0xdc, 0x02, 0x40, 0x6e, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x32, ++ 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x89, 0x4d, 0x0d, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x2b, 0x0f, 0x12, 0x00, 0x00, 0x4c, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x2c, 0x0f, 0x12, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x02, 0x90, 0x3a, ++ 0x00, 0x00, 0x28, 0x0f, 0x04, 0x01, 0x00, 0x04, 0x19, 0x40, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x3b, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x35, 0x0f, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x3a, 0x0f, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x22, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x80, 0x18, 0x00, 0x88, 0xbc, ++ 0x00, 0x00, 0x35, 0x0f, 0x12, 0x01, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x34, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x6c, 0x88, 0x1c, 0x83, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4c, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x50, 0x00, 0x18, 0xc8, 0x20, 0x72, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x81, 0x7c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x00, 0x00, 0x20, 0x88, 0x01, 0x82, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x06, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x36, 0xbc, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x77, 0x4a, 0x09, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x19, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x00, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0xc0, 0x86, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0xc0, 0x84, 0x32, ++ 0x00, 0x00, 0xa3, 0x0f, 0x04, 0x00, 0x00, 0x28, 0xd8, 0xa0, 0x82, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x09, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xd8, 0xa0, 0x81, 0x3c, ++ 0x00, 0x00, 0x67, 0x0f, 0x04, 0x00, 0x00, 0x3c, 0xd8, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x81, 0xbc, ++ 0x00, 0x00, 0x58, 0x0f, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0x02, 0xc0, 0x38, 0xb2, ++ 0x00, 0x00, 0x60, 0x0f, 0x51, 0x00, 0x00, 0xd8, 0x12, 0x80, 0x2d, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x5e, 0x0f, 0x04, 0x00, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x59, 0x0f, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x65, 0x0f, 0x2a, 0x01, 0x00, 0x00, 0xd8, 0x20, 0x80, 0xba, ++ 0x00, 0x00, 0x64, 0x0f, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xb7, 0x0e, 0x00, 0x60, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x4d, 0x0f, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x9e, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x6e, 0x0f, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x68, 0x0f, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x78, 0x39, 0x9a, 0xfe, 0x38, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x97, 0xd2, ++ 0x08, 0x00, 0x8a, 0x11, 0x12, 0x40, 0x02, 0x68, 0x12, 0x9a, 0xfe, 0xb8, ++ 0x00, 0x00, 0x8a, 0x11, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x00, 0x00, 0x86, 0x0f, 0x1f, 0x00, 0x00, 0x6c, 0xd8, 0xe0, 0x86, 0xba, ++ 0x00, 0x00, 0xa3, 0x0e, 0x51, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0xf2, ++ 0x00, 0x00, 0x79, 0x0f, 0x00, 0x00, 0x00, 0x3c, 0x08, 0x40, 0x80, 0x92, ++ 0x00, 0x00, 0x86, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7e, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x7e, 0x0f, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x7e, 0x0f, 0x80, 0x01, 0x00, 0x80, 0x32, 0x80, 0x87, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xe2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x4c, 0x0f, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x81, 0xbc, ++ 0x00, 0x00, 0x84, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x83, 0x0f, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xb7, 0x0e, 0x00, 0x60, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x4d, 0x0f, 0x4d, 0x00, 0x00, 0x00, 0x67, 0xe0, 0x83, 0x9e, ++ 0x00, 0x00, 0x89, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xa7, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xa8, 0x60, 0x8a, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x21, 0x01, 0x80, 0x82, 0x5b, 0x8a, 0xbc, ++ 0x00, 0x00, 0x8d, 0x0f, 0x2f, 0xa8, 0x01, 0x20, 0x99, 0x22, 0x6e, 0xba, ++ 0x00, 0x00, 0x2f, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x02, 0x80, 0x82, 0x1b, 0x92, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0xe0, 0x06, 0x00, 0x92, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0xe8, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x92, 0x0f, 0x23, 0x21, 0x01, 0xe0, 0x06, 0x00, 0x00, 0xb2, ++ 0x3c, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x30, 0x00, 0xe0, 0x06, 0x80, 0x82, 0xb2, ++ 0x00, 0x00, 0x9c, 0x0f, 0x04, 0x21, 0x00, 0xe0, 0x06, 0x80, 0x81, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xe2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x9a, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x99, 0x0f, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x32, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0xb7, 0x0e, 0x00, 0x60, 0x00, 0x6c, 0x08, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xe0, 0x06, 0x80, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0xe8, 0x06, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x10, 0x00, 0xe0, 0x06, 0xc0, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x2a, 0x19, 0x00, 0xe0, 0x06, 0xc0, 0x84, 0x72, ++ 0x00, 0x00, 0xa1, 0x0f, 0x12, 0x01, 0x00, 0x00, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x1d, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xa4, 0x17, 0xb8, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0x75, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xd8, 0xe0, 0x83, 0x3c, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x12, 0x00, 0x2c, 0x3a, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x32, ++ 0xee, 0x05, 0xaf, 0x0f, 0x04, 0x01, 0x00, 0x80, 0x82, 0x4d, 0xf5, 0xbc, ++ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xb1, 0x0f, 0x00, 0x00, 0x00, 0x04, 0x09, 0xc0, 0x09, 0x92, ++ 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0x80, 0x09, 0x32, ++ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x87, 0xcd, 0x00, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x60, 0xc0, 0x07, 0x80, 0x97, 0x32, ++ 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x8d, 0x2a, 0x3a, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x52, 0x81, 0x97, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x24, 0x90, 0x3a, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x0d, 0x90, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x19, 0x40, 0x90, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x52, 0x82, 0x2a, 0x3a, ++ 0x00, 0x08, 0xb1, 0x0f, 0x02, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x2a, 0xbc, ++ 0x00, 0x00, 0xc2, 0x0f, 0x06, 0x00, 0x00, 0x80, 0x02, 0x40, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x20, 0xb2, ++ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x87, 0xcd, 0x00, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x07, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x5c, 0x52, 0x81, 0x2a, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x24, 0x90, 0x3a, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x0d, 0x90, 0x36, ++ 0x00, 0x00, 0xbb, 0x0f, 0x04, 0x01, 0x00, 0x04, 0x19, 0x40, 0x90, 0xbc, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x89, 0x0d, 0x90, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0x80, 0x97, 0xb2, ++ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x89, 0x0d, 0x90, 0x36, ++ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x89, 0x4d, 0x92, 0x3c, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x82, 0x4d, 0x92, 0x36, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x89, 0x4d, 0x92, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x18, 0x9b, 0x81, 0xb2, 0xe4, 0x78, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x9b, 0x8d, 0xb7, 0xe4, 0x78, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0e, 0x80, 0x97, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x24, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x59, 0x00, 0x90, 0x36, ++ 0x00, 0x00, 0xc4, 0x0f, 0x95, 0x01, 0x00, 0x80, 0x22, 0x24, 0x90, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xec, 0x0f, 0x04, 0x01, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x09, 0xc0, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xb2, 0x45, 0x28, 0x30, ++ 0x00, 0x00, 0xdd, 0x0f, 0x86, 0x01, 0x00, 0x08, 0x09, 0x80, 0x2f, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x09, 0x40, 0x81, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x02, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x80, 0x92, 0x32, ++ 0x00, 0x00, 0xdc, 0x0f, 0x04, 0x07, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0xbc, ++ 0x00, 0x00, 0xe7, 0x0f, 0xc3, 0x07, 0x01, 0xec, 0xb6, 0xe4, 0x6e, 0x9a, ++ 0x00, 0x00, 0xe7, 0x0f, 0x00, 0x06, 0x01, 0xec, 0xb6, 0xe4, 0x6e, 0x9a, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x52, 0x80, 0x90, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x09, 0x05, 0x80, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x02, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x80, 0x92, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xf2, 0xc1, 0x92, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xfa, 0x92, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xfa, 0x92, 0xbc, ++ 0x44, 0x00, 0x2c, 0x10, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x8d, 0x2f, 0xd2, ++ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x92, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0x32, ++ 0x00, 0x00, 0xec, 0x0f, 0x04, 0x01, 0x00, 0x78, 0xd9, 0x01, 0x30, 0xb6, ++ 0x00, 0x00, 0xd4, 0x0f, 0x00, 0x00, 0x00, 0x9c, 0xb2, 0x45, 0x28, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x22, 0x80, 0x97, 0x7c, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0xe8, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0xc0, 0xe8, 0x32, ++ 0x02, 0x00, 0xf1, 0x0f, 0xb0, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0xb9, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xab, 0xe4, 0xb0, 0x32, ++ 0x00, 0x00, 0xf6, 0x0f, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x4a, 0xd0, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x28, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0xf9, 0x0f, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0xf8, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x09, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0xcd, 0x4a, 0xd0, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x4a, 0xd0, 0xb6, ++ 0x00, 0x00, 0x00, 0x10, 0x04, 0x01, 0x00, 0x28, 0x09, 0x34, 0xb0, 0xba, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xc2, 0x4a, 0xd0, 0xb6, ++ 0x00, 0x00, 0xfd, 0x0f, 0xb0, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0xcd, 0x4a, 0xd0, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x09, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0x00, 0x10, 0xb0, 0x00, 0x00, 0xa8, 0x22, 0x00, 0x2b, 0xb7, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x84, 0xc0, 0x37, 0xac, 0xb0, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x0c, 0x0b, 0x00, 0x00, 0x32, ++ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x4d, 0xb0, 0x30, ++ 0x00, 0x00, 0x08, 0x10, 0x80, 0x00, 0x00, 0x80, 0x02, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x12, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x69, 0x81, 0x97, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x0b, 0x00, 0x7c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x25, 0x01, 0x32, ++ 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x2a, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0xb0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0xd0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0x54, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x0e, 0x10, 0xb0, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xab, 0xe4, 0xb0, 0x32, ++ 0x00, 0x00, 0x13, 0x10, 0x80, 0x01, 0x00, 0x80, 0x02, 0x40, 0xd0, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x28, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0x16, 0x10, 0x04, 0x00, 0x00, 0x80, 0x02, 0x00, 0xf8, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x09, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0x0d, 0x40, 0xd0, 0x34, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x02, 0x40, 0xd0, 0xb6, ++ 0x00, 0x00, 0x1d, 0x10, 0x04, 0x01, 0x00, 0x28, 0x09, 0x34, 0xb0, 0xba, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x02, 0x40, 0xd0, 0xb6, ++ 0x00, 0x00, 0x1a, 0x10, 0xb0, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x04, 0x0d, 0x40, 0xd0, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x09, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0x1d, 0x10, 0xb0, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x84, 0xc0, 0x37, 0xac, 0xb0, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x0c, 0x0b, 0x00, 0x00, 0x32, ++ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x4d, 0xb0, 0x30, ++ 0x00, 0x00, 0x25, 0x10, 0x80, 0x00, 0x00, 0x80, 0x02, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x12, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x69, 0x81, 0x97, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x0b, 0x00, 0x7c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x25, 0x01, 0x32, ++ 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x2a, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0xb0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0xd0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0x54, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x41, 0x02, 0x80, 0x06, 0xc0, 0x92, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x92, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x97, 0xd2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x92, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x0b, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x1f, 0xc0, 0xf5, 0x3a, ++ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x92, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0xb0, 0x02, 0xc0, 0x6e, 0x32, ++ 0x00, 0x82, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x80, 0x36, 0x52, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x38, 0x80, 0x87, 0x35, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x80, 0x87, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0xe0, 0x16, 0x20, 0x6e, 0x3c, ++ 0x08, 0x00, 0x00, 0x00, 0xd2, 0x01, 0x00, 0x78, 0xe9, 0xe5, 0x83, 0x39, ++ 0x18, 0x00, 0x8a, 0x11, 0x1f, 0x41, 0x02, 0x84, 0xe6, 0xa1, 0x97, 0xb9, ++ 0x00, 0x00, 0x43, 0x10, 0x36, 0x51, 0x01, 0xe8, 0x16, 0xe0, 0x83, 0xbc, ++ 0x00, 0x00, 0x43, 0x10, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x45, 0x10, 0x38, 0x21, 0x01, 0xe0, 0x06, 0x40, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0xe0, 0x06, 0x40, 0x80, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x92, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0xd5, 0x08, 0x00, 0x00, 0x07, 0x80, 0x92, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x40, 0x00, 0x80, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x41, 0x01, 0xe0, 0x06, 0x80, 0x92, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x48, 0x02, 0xc0, 0x80, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0xe8, 0x01, 0x00, 0x74, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x62, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x80, 0x92, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x3d, 0x00, 0x0c, 0x07, 0x80, 0x83, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x48, 0x02, 0xc0, 0x80, 0x72, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x57, 0x01, 0x80, 0x02, 0xc0, 0x6e, 0x7c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x01, 0xec, 0x06, 0x80, 0x92, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x38, 0xf2, ++ 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x10, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x19, 0xa0, 0x2c, 0xd9, ++ 0x00, 0x00, 0x60, 0x10, 0x9d, 0x11, 0x02, 0x0c, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x61, 0x10, 0x00, 0xf0, 0x01, 0x1c, 0x09, 0x00, 0x6e, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x1c, 0x09, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x63, 0x10, 0x2c, 0xcd, 0x01, 0x18, 0x09, 0x80, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc9, 0xc1, 0x90, 0x34, ++ 0x00, 0x00, 0x67, 0x10, 0x3b, 0x29, 0x02, 0x04, 0x09, 0x80, 0x6e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0xd6, 0x01, 0x80, 0x52, 0xc0, 0x6e, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xec, 0x56, 0xc0, 0x6e, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xb9, 0xc1, 0x90, 0x34, ++ 0x00, 0x00, 0x77, 0x10, 0x00, 0xa8, 0x01, 0x08, 0x09, 0x00, 0x6e, 0xf2, ++ 0x00, 0x00, 0x6b, 0x10, 0x9d, 0x01, 0x00, 0x80, 0x17, 0xe0, 0x90, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x80, 0x07, 0xc0, 0x91, 0x32, ++ 0x00, 0x00, 0x6e, 0x10, 0x00, 0x38, 0x00, 0x80, 0x07, 0x00, 0xee, 0x92, ++ 0x00, 0x00, 0x6e, 0x10, 0x04, 0x01, 0x00, 0x80, 0x02, 0xc0, 0x91, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0xe0, 0x06, 0x00, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0xe0, 0x06, 0x00, 0x86, 0x32, ++ 0x00, 0x00, 0x71, 0x10, 0x39, 0x08, 0x00, 0x80, 0x07, 0xc0, 0x85, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xc2, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xd9, 0xc9, 0x01, 0xe8, 0x06, 0x80, 0x91, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xc8, 0x11, 0x00, 0x80, 0x07, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x74, 0x10, 0x3b, 0x21, 0x00, 0x80, 0x07, 0x00, 0x86, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x60, 0x18, 0x00, 0x86, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x58, 0x78, 0x01, 0xe0, 0x16, 0x20, 0x86, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x80, 0x07, 0x00, 0x85, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x7b, 0x10, 0x02, 0x0c, 0x02, 0x80, 0xa2, 0x9b, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x29, 0x00, 0x6e, 0x36, ++ 0x00, 0x00, 0x7b, 0x10, 0x02, 0x00, 0x00, 0x80, 0xe2, 0xa5, 0x90, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x78, 0x49, 0x21, 0x6e, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe9, 0xa5, 0x90, 0x3f, ++ 0x00, 0x00, 0x82, 0x10, 0x04, 0x20, 0x02, 0x08, 0x89, 0x9b, 0x90, 0xbe, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x58, 0xb8, 0x9b, 0x90, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x49, 0xa1, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x9f, 0x88, 0x01, 0x80, 0x82, 0x9b, 0x97, 0x7c, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x01, 0xe0, 0x06, 0x80, 0x97, 0x72, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x02, 0x58, 0xb8, 0x9b, 0x90, 0x76, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8b, 0x10, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x89, 0x10, 0x12, 0x01, 0x00, 0x78, 0x09, 0xc0, 0x21, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8b, 0x10, 0xca, 0x00, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x92, ++ 0x15, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x78, 0xe9, 0x65, 0x17, 0xb8, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0x35, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x6c, 0x88, 0x1c, 0x83, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4c, 0x08, 0x00, 0x72, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x50, 0x00, 0x18, 0xc8, 0x20, 0x72, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0x62, 0xa0, 0x82, 0x7c, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x00, 0x00, 0x14, 0x18, 0x40, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x00, 0x00, 0x20, 0x88, 0x01, 0x82, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x06, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x02, 0x00, 0x36, 0xbc, ++ 0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x77, 0x4a, 0x09, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x82, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x19, 0x00, 0x00, 0x07, 0x40, 0x82, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0xc1, 0x38, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xd8, 0x02, 0x40, 0x84, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x85, 0xd2, ++ 0x00, 0x00, 0xa6, 0x10, 0x80, 0x01, 0x00, 0x80, 0xf2, 0xc1, 0x85, 0xb6, ++ 0x00, 0x00, 0xa2, 0x10, 0x1f, 0x40, 0x02, 0x84, 0xe6, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0xa6, 0x10, 0x1d, 0x01, 0x00, 0xf8, 0x22, 0x81, 0x2f, 0xb4, ++ 0x00, 0x00, 0xa6, 0x10, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x95, ++ 0x00, 0x00, 0xa4, 0x10, 0x1d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x62, 0x81, 0x2f, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x02, 0x40, 0x68, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x1f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc5, 0x85, 0xd0, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x68, 0x02, 0xc5, 0x85, 0xb0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x09, 0xc5, 0x85, 0x30, ++ 0x00, 0x00, 0x8a, 0x11, 0x02, 0x01, 0x00, 0x80, 0x82, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x06, 0x01, 0x00, 0x80, 0x92, 0xba, 0x97, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x5c, 0x1f, 0xc0, 0xf5, 0x7a, ++ 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x8d, 0x2f, 0x70, ++ 0x29, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0x02, 0x81, 0x2f, 0x74, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x80, 0xa8, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0x2f, 0x70, ++ 0x00, 0x00, 0xb7, 0x10, 0x80, 0x01, 0x00, 0x80, 0xd2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x72, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0xba, 0x10, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x72, 0x81, 0x2f, 0x34, ++ 0x3b, 0x00, 0xba, 0x10, 0x12, 0x01, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xba, 0x10, 0x80, 0x01, 0x00, 0x80, 0xf2, 0x80, 0x2f, 0xb6, ++ 0x30, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0xbd, 0x10, 0x00, 0x00, 0x00, 0xf8, 0x42, 0x81, 0x2f, 0x94, ++ 0x00, 0x00, 0xbd, 0x10, 0x80, 0x01, 0x00, 0x80, 0xb2, 0x80, 0x2f, 0xb6, ++ 0x34, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x42, 0x81, 0x2f, 0x34, ++ 0x80, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x82, 0x8d, 0x2f, 0x70, ++ 0x02, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x8d, 0x2f, 0x70, ++ 0x3a, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x2c, 0x82, 0xcd, 0x2e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0x12, 0x81, 0x2f, 0x74, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x65, 0x01, 0x80, 0xa2, 0xdb, 0x2c, 0xbc, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x39, ++ 0xee, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0x71, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xcb, 0x10, 0x00, 0x00, 0x01, 0x38, 0x08, 0xc0, 0x6e, 0xf2, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x48, 0x02, 0xc0, 0x80, 0x72, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xcd, 0x10, 0x04, 0x38, 0x01, 0x78, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x11, 0x00, 0x00, 0x07, 0x80, 0x82, 0x32, ++ 0x00, 0x00, 0xd1, 0x10, 0x2e, 0x19, 0x00, 0x00, 0x07, 0x80, 0x97, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xe9, 0x81, 0x92, 0x34, ++ 0x00, 0x00, 0xd5, 0x10, 0x27, 0x31, 0x00, 0x00, 0x07, 0xc0, 0x2c, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0xd5, 0x08, 0x00, 0x00, 0x07, 0x00, 0x87, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x28, 0xe9, 0x80, 0x92, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0xe7, 0xa0, 0x92, 0x79, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x40, 0x90, 0xd2, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x44, 0x12, 0xe4, 0x38, 0xb2, ++ 0x18, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x03, 0xf9, ++ 0x00, 0x00, 0xdf, 0x10, 0x04, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0xda, 0x10, 0x67, 0x00, 0x00, 0xf8, 0xa2, 0x80, 0x2f, 0xb5, ++ 0x00, 0x00, 0x8a, 0x11, 0x12, 0x00, 0x00, 0xe8, 0x02, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0x72, 0x80, 0x2d, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xd8, 0x02, 0x40, 0x00, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x79, 0x0a, 0x91, 0x39, ++ 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x39, 0x0b, 0x91, 0x39, ++ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x59, 0x0a, 0x91, 0x39, ++ 0x09, 0x00, 0xe5, 0x10, 0xf1, 0x01, 0x00, 0x10, 0x69, 0x0b, 0x91, 0xb9, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x24, 0x86, 0xa8, 0x82, 0x8d, 0x6c, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe0, 0x07, 0x00, 0x91, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe0, 0x07, 0x40, 0x91, 0x32, ++ 0x00, 0x80, 0xeb, 0x10, 0x02, 0x01, 0x00, 0x80, 0x82, 0x8d, 0x2a, 0xbc, ++ 0x00, 0x00, 0xec, 0x10, 0xe1, 0x24, 0x86, 0xc8, 0x06, 0x00, 0x00, 0x92, ++ 0x03, 0x00, 0x00, 0x00, 0xe1, 0x24, 0x86, 0xc8, 0x86, 0x8d, 0x2a, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xf4, 0x10, 0x04, 0x30, 0x00, 0x80, 0x82, 0x9b, 0x81, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x0d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0x3c, 0x00, 0x14, 0x28, 0x80, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x02, 0x80, 0x2f, 0x35, ++ 0x00, 0xa0, 0x8a, 0x11, 0x12, 0x00, 0x00, 0x40, 0xa2, 0x8d, 0x39, 0xb2, ++ 0x00, 0x00, 0xf6, 0x10, 0x80, 0x39, 0x00, 0x80, 0xe2, 0x80, 0x6e, 0xb6, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x38, 0x00, 0x80, 0xf2, 0x80, 0x6e, 0xb6, ++ 0x00, 0xe0, 0x8a, 0x11, 0x04, 0x01, 0x00, 0x80, 0xa2, 0x8d, 0x2f, 0xb0, ++ 0x00, 0xe0, 0xfd, 0x10, 0x04, 0x38, 0x00, 0x78, 0x89, 0x8d, 0x6e, 0xb0, ++ 0x10, 0x00, 0xfd, 0x10, 0x9f, 0x01, 0x00, 0xf8, 0xe2, 0xa5, 0x2f, 0xb9, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0xee, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0x82, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0xec, 0x06, 0xc0, 0xee, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0x00, 0x18, 0x09, 0x00, 0x6e, 0x72, ++ 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xf0, ++ 0x00, 0x00, 0x2f, 0x0e, 0x00, 0xa8, 0x01, 0x20, 0x09, 0x00, 0x6e, 0x92, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xa9, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x80, 0x82, 0x9b, 0x81, 0x7c, ++ 0x00, 0x00, 0x8a, 0x11, 0x0d, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x9f, 0xbc, 0x00, 0x14, 0x28, 0x80, 0x6e, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0xf8, 0x42, 0x80, 0x2f, 0x35, ++ 0x08, 0xa0, 0x00, 0x00, 0x12, 0x01, 0x00, 0x40, 0xa2, 0xcd, 0x39, 0x72, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x80, 0x90, 0xd2, ++ 0x00, 0x00, 0x0f, 0x11, 0x33, 0xcd, 0x01, 0xbc, 0x08, 0x80, 0x6e, 0xb2, ++ 0x00, 0x00, 0x4e, 0x11, 0x00, 0x00, 0x00, 0x28, 0x29, 0x22, 0xee, 0xdc, ++ 0x00, 0x00, 0x14, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x14, 0x11, 0x04, 0xb8, 0x01, 0x28, 0x09, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x14, 0x11, 0x9f, 0x71, 0x01, 0x80, 0xc2, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xa9, 0x24, 0xee, 0x3c, ++ 0x00, 0x00, 0x4e, 0x11, 0x00, 0x00, 0x00, 0x28, 0x19, 0x80, 0x92, 0xdf, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x28, 0x11, 0x06, 0x80, 0x01, 0x80, 0x82, 0x9b, 0x90, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x90, 0xbc, ++ 0xee, 0x05, 0x20, 0x11, 0x06, 0x0c, 0x02, 0x80, 0x82, 0x8d, 0x6e, 0xbc, ++ 0x00, 0x90, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x84, 0x02, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x1a, 0x11, 0xb8, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x18, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x03, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0xe0, 0x96, 0x21, 0x6e, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x61, 0x98, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x78, 0x49, 0x40, 0x3c, 0x37, ++ 0x00, 0x00, 0x2d, 0x11, 0x00, 0x00, 0x00, 0x08, 0xe9, 0xa5, 0x90, 0x9a, ++ 0x60, 0x89, 0x20, 0x00, 0x00, 0x00, 0x00, 0x84, 0x02, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x23, 0x11, 0xb8, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0xb0, ++ 0x00, 0x00, 0x21, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x03, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0xe0, 0x96, 0x21, 0x6e, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x61, 0x98, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x2d, 0x11, 0xa8, 0x00, 0x00, 0x08, 0x19, 0x8f, 0x90, 0x9a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x99, 0xa1, 0x89, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe9, 0xa5, 0x90, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0xe0, 0x96, 0x21, 0x6e, 0x3c, ++ 0x00, 0x00, 0x00, 0x00, 0x61, 0x98, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x01, 0xec, 0x06, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x30, 0x11, 0x06, 0x00, 0x00, 0x80, 0x72, 0xa2, 0x90, 0xbc, ++ 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x80, 0x01, 0xe0, 0x06, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0xc0, 0x89, 0x32, ++ 0x00, 0x00, 0x36, 0x11, 0x04, 0x79, 0x01, 0x80, 0x82, 0x1b, 0x87, 0xbc, ++ 0x00, 0x00, 0x34, 0x11, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0xe0, 0x06, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0x92, 0x81, 0x2f, 0x75, ++ 0x00, 0x00, 0x3c, 0x11, 0x80, 0x00, 0x00, 0x80, 0x52, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x3c, 0x11, 0xd5, 0x41, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x92, ++ 0x00, 0x00, 0x39, 0x11, 0x3c, 0x90, 0x01, 0xe0, 0x06, 0x80, 0x90, 0xb2, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x01, 0x00, 0x80, 0x92, 0x81, 0x2f, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0xe8, 0x06, 0xc0, 0x8b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x95, 0x01, 0x00, 0x80, 0x02, 0x80, 0x2f, 0x72, ++ 0x00, 0x00, 0x3d, 0x11, 0x9f, 0x41, 0x01, 0x80, 0x82, 0x1b, 0x87, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x00, 0x00, 0xd9, 0x90, 0x01, 0xe0, 0x06, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0x72, 0x80, 0x2f, 0x74, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0x40, 0x87, 0xd2, ++ 0x00, 0x00, 0x47, 0x11, 0x9f, 0xd8, 0x01, 0x80, 0x22, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x47, 0x11, 0x9f, 0xe0, 0x01, 0x80, 0xc2, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x47, 0x11, 0x9f, 0xb0, 0x01, 0x80, 0xd2, 0x21, 0x6e, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x70, ++ 0x00, 0x00, 0x49, 0x11, 0x06, 0x68, 0x01, 0x80, 0x82, 0x5b, 0x87, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0xe0, 0x06, 0x40, 0x87, 0x32, ++ 0x00, 0x00, 0x4b, 0x11, 0x37, 0xb0, 0x01, 0xe0, 0x06, 0x40, 0x87, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xd2, 0x80, 0x2f, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x01, 0xe0, 0x06, 0x80, 0x84, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x01, 0xe0, 0x06, 0x00, 0x87, 0x72, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x08, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xbc, ++ 0x00, 0x00, 0x5b, 0x11, 0x04, 0xc1, 0x01, 0x84, 0x02, 0x00, 0x6e, 0xb2, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xe8, 0x86, 0x8d, 0x92, 0x37, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x01, 0xe8, 0x86, 0x8d, 0x92, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x30, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x2c, 0x89, 0x8d, 0x6e, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x01, 0x2c, 0xa9, 0xdb, 0x92, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x29, 0xc0, 0x92, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x19, 0xfb, 0x92, 0x3f, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x29, 0x80, 0x92, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xa9, 0xe4, 0x92, 0x3f, ++ 0x00, 0x00, 0x00, 0x00, 0x6f, 0xcc, 0x01, 0xe8, 0x26, 0xfb, 0x92, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x02, 0x80, 0x92, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x06, 0x40, 0x28, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x6f, 0xcc, 0x01, 0xe8, 0x86, 0xcd, 0x2a, 0x36, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x01, 0xe0, 0x06, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0xb0, 0x00, 0x80, 0x02, 0x00, 0x6e, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0xbc, 0x08, 0x00, 0x6e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0xbc, 0x88, 0xdb, 0x8b, 0x3e, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0xbc, 0x88, 0xdb, 0x8b, 0x3a, ++ 0x00, 0x00, 0x6a, 0x11, 0x9f, 0x00, 0x00, 0xbc, 0x88, 0xe1, 0x8b, 0xbc, ++ 0x00, 0x00, 0x6a, 0x11, 0x04, 0x0c, 0x02, 0x40, 0xa8, 0xdb, 0x8b, 0xbe, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x04, 0x88, 0x1b, 0x84, 0x3e, ++ 0x00, 0x00, 0x69, 0x11, 0x04, 0xb1, 0x00, 0x80, 0x82, 0x5b, 0x80, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0xc2, 0x80, 0x2f, 0x74, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x02, 0x80, 0xa2, 0x5b, 0x80, 0x7c, ++ 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x14, 0x09, 0xc0, 0x8b, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x12, 0x00, 0x2c, 0x3a, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x04, 0x65, 0x01, 0x80, 0xa2, 0xdb, 0x2c, 0xbc, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x00, 0x00, 0x80, 0xa2, 0x80, 0x2f, 0xb6, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0xe8, 0x76, 0x20, 0x81, 0x39, ++ 0xee, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf8, 0x82, 0x8d, 0x2f, 0x71, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xd9, 0x4a, 0x91, 0x39, ++ 0x39, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x09, 0x45, 0x91, 0x30, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x89, 0x4d, 0x91, 0x36, ++ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x89, 0xcd, 0x93, 0x3c, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x82, 0xcd, 0x93, 0x36, ++ 0x07, 0x00, 0x79, 0x11, 0xf3, 0x01, 0x00, 0x40, 0x89, 0xcd, 0x93, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x18, 0x9b, 0x81, 0x02, 0xe5, 0x78, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xe3, 0x18, 0x9b, 0x8d, 0x07, 0xe5, 0x78, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xd9, 0x4a, 0x91, 0x39, ++ 0x3a, 0x00, 0xe2, 0x10, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x36, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x09, 0x45, 0x91, 0x30, ++ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x89, 0x4d, 0x91, 0x36, ++ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x89, 0xcd, 0x93, 0x3c, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x82, 0xcd, 0x93, 0x36, ++ 0x07, 0x00, 0x84, 0x11, 0xf3, 0x01, 0x00, 0x40, 0x89, 0xcd, 0x93, 0xb0, ++ 0x00, 0x00, 0x8a, 0x11, 0x80, 0x19, 0x9b, 0x81, 0x02, 0xe5, 0x78, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0xe3, 0x18, 0x9b, 0x8d, 0x07, 0xe5, 0x78, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x8a, 0x11, 0x00, 0x00, 0x00, 0xb4, 0x0f, 0x40, 0xfb, 0x94, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0f, 0x40, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0f, 0x00, 0x28, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x0f, 0x00, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0f, 0x40, 0x18, 0x32, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x5f, 0xca, 0xf9, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x03, 0xc0, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x32, ++ 0x41, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x32, ++ 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0f, 0x80, 0x2a, 0x32, ++ 0x4c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x98, 0x11, 0x97, 0x12, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x01, 0x84, 0x12, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x36, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x80, 0x2a, 0x32, ++ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0xc0, 0xfa, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0xfa, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0xfa, 0x32, ++ 0x00, 0x00, 0xac, 0x11, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0xfa, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0xfb, 0x32, ++ 0x01, 0x00, 0xcf, 0x11, 0x04, 0x01, 0x00, 0xb4, 0x8f, 0x4d, 0xfb, 0xb0, ++ 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xab, 0xcd, 0xb0, 0x32, ++ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5b, 0xca, 0xb0, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x2b, 0xfe, 0xb0, 0x32, ++ 0x00, 0x00, 0xaa, 0x11, 0x12, 0x01, 0x00, 0x80, 0x02, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0xbe, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x01, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xe0, 0x07, 0x80, 0x3f, 0x52, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x8a, 0x02, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x53, 0x0a, 0x16, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0f, 0x80, 0x90, 0x32, ++ 0xa2, 0x60, 0x03, 0x00, 0x00, 0x00, 0x00, 0x58, 0x03, 0x00, 0x37, 0x32, ++ 0xb9, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x03, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x83, 0x0d, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x83, 0x0d, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x53, 0x0a, 0x00, 0x34, ++ 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc0, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0xfa, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x40, 0xfa, 0x32, ++ 0x00, 0x00, 0xc9, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0x39, ++ 0x00, 0x00, 0xc0, 0x11, 0x80, 0x01, 0x00, 0x80, 0x12, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3b, 0x40, 0xb0, 0x33, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xcd, 0x4a, 0xd0, 0x35, ++ 0x00, 0x00, 0xc4, 0x11, 0x00, 0x00, 0x00, 0x0c, 0x0b, 0x40, 0x90, 0x92, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0x39, ++ 0x00, 0x00, 0xc4, 0x11, 0x00, 0x00, 0x00, 0x04, 0x6b, 0x41, 0x90, 0x94, ++ 0x00, 0x00, 0xc4, 0x11, 0x12, 0x00, 0x00, 0x00, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0xc5, 0x11, 0x12, 0x00, 0x00, 0x04, 0x09, 0x40, 0x20, 0xb2, ++ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0xe4, 0x16, 0x38, ++ 0x00, 0x00, 0xc9, 0x11, 0x9f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0xc8, 0x11, 0x12, 0x00, 0x00, 0x08, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x02, 0x00, 0xc4, 0x11, 0x04, 0x01, 0x00, 0xbc, 0x0f, 0x24, 0x17, 0xb8, ++ 0x06, 0x00, 0xc2, 0x11, 0x04, 0x00, 0x00, 0xbc, 0x0f, 0x64, 0x16, 0xb8, ++ 0x00, 0x00, 0xbd, 0x11, 0x04, 0x00, 0x00, 0x80, 0x22, 0xc0, 0xfb, 0xbc, ++ 0x20, 0x00, 0xc4, 0x11, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xfb, 0xbc, ++ 0x00, 0x00, 0xd7, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0xd1, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0xcd, 0xf9, 0x3a, ++ 0x00, 0x00, 0xb7, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xf7, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xf8, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xfc, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x04, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x03, 0x32, ++ 0x40, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x80, 0x2a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x40, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xde, 0x11, 0x9f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0xde, 0x11, 0x12, 0x00, 0x00, 0x40, 0xf2, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0xe0, 0x11, 0x12, 0x00, 0x00, 0x9c, 0x0f, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0f, 0x00, 0x7e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0xfa, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x4c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x80, 0x2a, 0x32, ++ 0x00, 0x00, 0xad, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0xb3, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcb, 0xc1, 0xb0, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xef, 0x0f, 0x00, 0x00, 0x00, 0x28, 0x09, 0xc0, 0xb0, 0xd2, ++ 0x00, 0x00, 0xeb, 0x11, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xb2, ++ 0x00, 0x00, 0xef, 0x11, 0x12, 0x00, 0x00, 0x9c, 0x0f, 0xc0, 0x21, 0xb2, ++ 0x02, 0x00, 0xf2, 0x11, 0x04, 0x01, 0x00, 0xb4, 0x8f, 0x4d, 0xfb, 0xb0, ++ 0x00, 0x00, 0xc4, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x93, 0x40, 0x01, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x1f, 0x40, 0xfb, 0x35, ++ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x03, 0x00, 0x00, 0x34, ++ 0x00, 0x00, 0xeb, 0x11, 0x00, 0x00, 0x00, 0x0c, 0x8b, 0xc1, 0xb0, 0x94, ++ 0x00, 0x00, 0xbb, 0x12, 0x00, 0x08, 0x00, 0x00, 0x07, 0x40, 0xfa, 0x92, ++ 0x00, 0x00, 0xad, 0x12, 0x00, 0x08, 0x00, 0x00, 0x07, 0x40, 0xfa, 0xd2, ++ 0x00, 0x00, 0xf9, 0x11, 0x12, 0x00, 0x00, 0x50, 0xf2, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0xb4, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0xbd, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0xb0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x12, 0x00, 0x2a, 0x3a, ++ 0x00, 0x00, 0xff, 0x11, 0x04, 0x01, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0xbc, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xba, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x0c, 0x12, 0x04, 0x01, 0x00, 0x80, 0x02, 0x40, 0xfa, 0xb2, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x0e, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x1b, 0x12, 0x00, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0xd2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x3c, 0x32, ++ 0x00, 0x00, 0x08, 0x12, 0x8e, 0x01, 0x00, 0x80, 0x02, 0x40, 0x28, 0xb2, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xf7, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x8f, 0x4d, 0xfa, 0x3a, ++ 0x00, 0x00, 0xf7, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x00, 0x32, ++ 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x08, 0x00, 0x10, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xf9, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x00, 0x32, ++ 0x0e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x0b, 0x00, 0x14, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xf9, 0xbc, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x36, 0x32, ++ 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x27, 0x00, 0x18, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xf9, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x00, 0x32, ++ 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x20, 0x00, 0x1d, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xf9, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x03, 0xc0, 0xf9, 0x32, ++ 0x0d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0xc0, 0xfa, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x3e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0x5a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0xc0, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x3e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0x3a, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xac, 0x8f, 0xcd, 0xf9, 0x50, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x3e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x12, 0x00, 0x2b, 0x3a, ++ 0x0f, 0x00, 0x2b, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0x0d, 0x2b, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x3e, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x02, 0xc0, 0xf9, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x3a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x3a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x3a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x3a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x3d, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x3d, 0x32, ++ 0x00, 0x00, 0x36, 0x12, 0x84, 0x01, 0x00, 0xb0, 0x12, 0x00, 0x2b, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x02, 0xc0, 0xf9, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x00, 0x32, ++ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x3e, 0x00, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x30, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0x3a, ++ 0x70, 0x00, 0x3b, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xf9, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x30, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x30, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0xc0, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0xc0, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0f, 0xc0, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0xfa, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x73, 0x7e, 0xfa, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x30, 0x32, ++ 0x00, 0x00, 0x44, 0x12, 0x85, 0x01, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x25, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x0e, 0x00, 0x53, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xfa, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x4d, 0x12, 0x00, 0x00, 0x00, 0x9c, 0x3f, 0xc0, 0xf9, 0x9a, ++ 0x1c, 0x00, 0x4d, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xfa, 0xbc, ++ 0x02, 0x00, 0x25, 0x12, 0x00, 0x00, 0x00, 0x9c, 0x8f, 0xcd, 0xf9, 0xda, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x37, 0x32, ++ 0x00, 0x00, 0x25, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x0e, 0x00, 0x5b, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xfa, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x57, 0x12, 0x00, 0x00, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0x9a, ++ 0x26, 0x00, 0x57, 0x12, 0x04, 0x01, 0x00, 0x80, 0x82, 0xcd, 0xfa, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x0f, 0x40, 0x29, 0x32, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x4c, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x56, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x29, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x18, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, 0x32, ++ 0xa2, 0x60, 0x03, 0x00, 0x00, 0x00, 0x00, 0x58, 0x03, 0x00, 0x37, 0x32, ++ 0x6b, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x03, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x80, 0x2a, 0x32, ++ 0x00, 0x00, 0x6b, 0x12, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x29, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x83, 0x3e, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x83, 0x3e, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x53, 0x0a, 0x00, 0x34, ++ 0x00, 0x00, 0x6c, 0x12, 0x00, 0x00, 0x00, 0x88, 0x0f, 0x40, 0x2b, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0f, 0x00, 0x28, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x0f, 0x00, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0f, 0x80, 0x2a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0xc0, 0xf9, 0x32, ++ 0x71, 0x12, 0x97, 0x12, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x36, 0x92, ++ 0x07, 0x00, 0x74, 0x12, 0x04, 0x00, 0x00, 0x80, 0x82, 0x4d, 0x29, 0xbc, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x00, 0xfa, 0x3a, ++ 0x00, 0x00, 0x68, 0x12, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x80, 0x2a, 0x92, ++ 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x36, 0x32, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x84, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x1f, 0x00, 0x7a, 0x12, 0x04, 0x00, 0x00, 0x80, 0x82, 0xcd, 0x29, 0xbc, ++ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x8f, 0xcd, 0xfa, 0x3a, ++ 0x00, 0x00, 0x76, 0x12, 0x00, 0x00, 0x00, 0x9c, 0x12, 0xc0, 0x29, 0x9a, ++ 0x00, 0x00, 0x3a, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x30, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x82, 0x12, 0x04, 0x00, 0x00, 0x80, 0x52, 0x8a, 0xfa, 0xbc, ++ 0xa2, 0x60, 0x03, 0x00, 0x00, 0x00, 0x00, 0x58, 0x03, 0x00, 0x37, 0x32, ++ 0x82, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x03, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xa3, 0x3e, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xa3, 0x3e, 0x00, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x53, 0x0a, 0x00, 0x34, ++ 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0xf7, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x02, 0xc0, 0xfa, 0x32, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x0f, 0x40, 0x2f, 0x32, ++ 0x00, 0x00, 0x8b, 0x12, 0x04, 0x00, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0xbc, ++ 0x00, 0x00, 0x8a, 0x12, 0x04, 0x00, 0x00, 0x80, 0x02, 0x40, 0x2f, 0xb2, ++ 0x00, 0x00, 0x87, 0x12, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x2c, 0x92, ++ 0x00, 0x00, 0x87, 0x12, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x2c, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x2d, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x2d, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x2d, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x2d, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0xfb, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x2f, 0x32, ++ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x73, 0x0a, 0x02, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xe0, 0x07, 0x80, 0x3f, 0x52, ++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x03, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x28, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0xf8, 0x32, ++ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x0f, 0xc0, 0x2b, 0x32, ++ 0x00, 0x00, 0xa0, 0x12, 0x04, 0x00, 0x00, 0x9c, 0x1f, 0xc0, 0xf9, 0xbc, ++ 0x00, 0x00, 0x9f, 0x12, 0x04, 0x00, 0x00, 0x80, 0x02, 0xc0, 0x2b, 0xb2, ++ 0x00, 0x00, 0x9c, 0x12, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x28, 0x92, ++ 0x00, 0x00, 0x9c, 0x12, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x36, 0x92, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x29, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x2a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x2a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0xf9, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0x2a, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x40, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x2b, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xc0, 0xfb, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x00, 0xfb, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xb1, 0x12, 0x9f, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x07, 0x40, 0x90, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x80, 0x90, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x07, 0x40, 0x90, 0x52, ++ 0x00, 0x00, 0xb3, 0x12, 0x12, 0x00, 0x00, 0x48, 0xf2, 0x01, 0x00, 0xb4, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x90, 0x32, ++ 0x00, 0x00, 0xb5, 0x12, 0x12, 0x00, 0x00, 0x9c, 0x0f, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x50, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x0f, 0x40, 0xfb, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x4c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x36, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x07, 0x80, 0x2a, 0x32, ++ 0x00, 0x00, 0xad, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0xb3, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xd0, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcb, 0xc1, 0xb0, 0x34, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x32, ++ 0x00, 0x00, 0xc4, 0x12, 0x00, 0x00, 0x00, 0x28, 0x09, 0xc0, 0xb0, 0xd2, ++ 0x00, 0x00, 0xbe, 0x12, 0x04, 0x00, 0x00, 0x80, 0x02, 0x80, 0x92, 0xb2, ++ 0x00, 0x00, 0xc2, 0x12, 0x12, 0x00, 0x00, 0x9c, 0x0f, 0xc0, 0x21, 0xb2, ++ 0x00, 0x00, 0xc4, 0x11, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0x32, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0x39, ++ 0x00, 0x00, 0xc8, 0x12, 0x04, 0x01, 0x00, 0x28, 0x09, 0x34, 0xb0, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x09, 0x00, 0x00, 0x52, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x22, 0x00, 0x2b, 0x37, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xc0, 0x37, 0xac, 0xb0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0b, 0x00, 0x00, 0x32, ++ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x4d, 0xb0, 0x30, ++ 0x00, 0x00, 0xd8, 0x12, 0x80, 0x00, 0x00, 0x80, 0x02, 0x40, 0xb0, 0xb6, ++ 0x00, 0x00, 0xcd, 0x12, 0x12, 0x00, 0x00, 0x00, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0xce, 0x12, 0x12, 0x00, 0x00, 0x04, 0x09, 0x40, 0x20, 0xb2, ++ 0x00, 0x00, 0xd1, 0x12, 0x9f, 0x01, 0x00, 0x80, 0x02, 0x00, 0x90, 0xb2, ++ 0x00, 0x00, 0xd0, 0x12, 0x12, 0x00, 0x00, 0x08, 0x09, 0x40, 0x20, 0xb2, ++ 0x0d, 0x00, 0xcd, 0x12, 0x04, 0x01, 0x00, 0x80, 0x02, 0xe4, 0x16, 0xb8, ++ 0x02, 0x00, 0xcd, 0x12, 0x04, 0x01, 0x00, 0xbc, 0x0f, 0x24, 0x17, 0xb8, ++ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x0f, 0x64, 0x16, 0x38, ++ 0x00, 0x00, 0xcd, 0x12, 0x04, 0x01, 0x00, 0x80, 0x22, 0xc0, 0xfb, 0xbc, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc2, 0x0a, 0x00, 0x39, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3b, 0x40, 0xb0, 0x33, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xcd, 0x4a, 0xd0, 0x35, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x25, 0x01, 0x32, ++ 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x87, 0x8d, 0x2a, 0x3a, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0xb0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0xd0, 0x32, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x48, 0xf2, 0xc1, 0x38, 0x54, ++ 0x00, 0x00, 0xdc, 0x12, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++}, ++{ ++ 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x90, ++}, ++}; +--- /dev/null ++++ b/drivers/staging/sxg/sxg.c +@@ -0,0 +1,3608 @@ ++/************************************************************************** ++ * ++ * Copyright (C) 2000-2008 Alacritech, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: sxg.c ++ * ++ * The SXG driver for Alacritech's 10Gbe products. ++ * ++ * NOTE: This is the standard, non-accelerated version of Alacritech's ++ * IS-NIC driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SLIC_DUMP_ENABLED 0 ++#define SLIC_GET_STATS_ENABLED 0 ++#define LINUX_FREES_ADAPTER_RESOURCES 1 ++#define SXG_OFFLOAD_IP_CHECKSUM 0 ++#define SXG_POWER_MANAGEMENT_ENABLED 0 ++#define VPCI 0 ++#define DBG 1 ++#define ATK_DEBUG 1 ++ ++#include "sxg_os.h" ++#include "sxghw.h" ++#include "sxghif.h" ++#include "sxg.h" ++#include "sxgdbg.h" ++ ++#include "sxgphycode.h" ++#include "saharadbgdownload.h" ++ ++static int sxg_allocate_buffer_memory(p_adapter_t adapter, u32 Size, SXG_BUFFER_TYPE BufferType); ++static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, void * RcvBlock, dma_addr_t PhysicalAddress, u32 Length); ++static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, PSXG_SCATTER_GATHER SxgSgl, dma_addr_t PhysicalAddress, u32 Length); ++ ++static void sxg_mcast_init_crc32(void); ++ ++static int sxg_entry_open(p_net_device dev); ++static int sxg_entry_halt(p_net_device dev); ++static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd); ++static int sxg_send_packets(struct sk_buff *skb, p_net_device dev); ++static int sxg_transmit_packet(p_adapter_t adapter, struct sk_buff *skb); ++static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl); ++ ++static void sxg_handle_interrupt(p_adapter_t adapter); ++static int sxg_process_isr(p_adapter_t adapter, u32 MessageId); ++static u32 sxg_process_event_queue(p_adapter_t adapter, u32 RssId); ++static void sxg_complete_slow_send(p_adapter_t adapter); ++static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event); ++static void sxg_process_rcv_error(p_adapter_t adapter, u32 ErrorStatus); ++static bool sxg_mac_filter(p_adapter_t adapter, ++ p_ether_header EtherHdr, ushort length); ++ ++#if SLIC_GET_STATS_ENABLED ++static struct net_device_stats *sxg_get_stats(p_net_device dev); ++#endif ++ ++static int sxg_mac_set_address(p_net_device dev, void * ptr); ++ ++static void sxg_adapter_set_hwaddr(p_adapter_t adapter); ++ ++static void sxg_unmap_mmio_space(p_adapter_t adapter); ++static void sxg_mcast_set_mask(p_adapter_t adapter); ++ ++static int sxg_initialize_adapter(p_adapter_t adapter); ++static void sxg_stock_rcv_buffers(p_adapter_t adapter); ++static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char Index); ++static int sxg_initialize_link(p_adapter_t adapter); ++static int sxg_phy_init(p_adapter_t adapter); ++static void sxg_link_event(p_adapter_t adapter); ++static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter); ++static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState); ++static int sxg_write_mdio_reg(p_adapter_t adapter, ++ u32 DevAddr, u32 RegAddr, u32 Value); ++static int sxg_read_mdio_reg(p_adapter_t adapter, ++ u32 DevAddr, u32 RegAddr, u32 * pValue); ++static void sxg_mcast_set_list(p_net_device dev); ++ ++ ++ ++#define XXXTODO 0 ++ ++static unsigned int sxg_first_init = 1; ++static char *sxg_banner = ++ "Alacritech SLIC Technology(tm) Server and Storage 10Gbe Accelerator (Non-Accelerated)\n"; ++ ++static int sxg_debug = 1; ++static int debug = -1; ++static p_net_device head_netdevice = NULL; ++ ++static sxgbase_driver_t sxg_global = { ++ .dynamic_intagg = 1, ++}; ++static int intagg_delay = 100; ++static u32 dynamic_intagg = 0; ++ ++#define DRV_NAME "sxg" ++#define DRV_VERSION "1.0.1" ++#define DRV_AUTHOR "Alacritech, Inc. Engineering" ++#define DRV_DESCRIPTION "Alacritech SLIC Techonology(tm) Non-Accelerated 10Gbe Driver" ++#define DRV_COPYRIGHT "Copyright 2000-2008 Alacritech, Inc. All rights reserved." ++ ++MODULE_AUTHOR(DRV_AUTHOR); ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_LICENSE("GPL"); ++ ++module_param(dynamic_intagg, int, 0); ++MODULE_PARM_DESC(dynamic_intagg, "Dynamic Interrupt Aggregation Setting"); ++module_param(intagg_delay, int, 0); ++MODULE_PARM_DESC(intagg_delay, "uSec Interrupt Aggregation Delay"); ++ ++static struct pci_device_id sxg_pci_tbl[] __devinitdata = { ++ {PCI_DEVICE(SXG_VENDOR_ID, SXG_DEVICE_ID)}, ++ {0,} ++}; ++MODULE_DEVICE_TABLE(pci, sxg_pci_tbl); ++ ++/*********************************************************************** ++************************************************************************ ++************************************************************************ ++************************************************************************ ++************************************************************************/ ++ ++static inline void sxg_reg32_write(void __iomem *reg, u32 value, bool flush) ++{ ++ writel(value, reg); ++ if (flush) ++ mb(); ++} ++ ++static inline void sxg_reg64_write(p_adapter_t adapter, void __iomem *reg, ++ u64 value, u32 cpu) ++{ ++ u32 value_high = (u32) (value >> 32); ++ u32 value_low = (u32) (value & 0x00000000FFFFFFFF); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->Bit64RegLock, flags); ++ writel(value_high, (void __iomem *)(&adapter->UcodeRegs[cpu].Upper)); ++ writel(value_low, reg); ++ spin_unlock_irqrestore(&adapter->Bit64RegLock, flags); ++} ++ ++static void sxg_init_driver(void) ++{ ++ if (sxg_first_init) { ++ DBG_ERROR("sxg: %s sxg_first_init set jiffies[%lx]\n", ++ __FUNCTION__, jiffies); ++ sxg_first_init = 0; ++ spin_lock_init(&sxg_global.driver_lock); ++ } ++} ++ ++static void sxg_dbg_macaddrs(p_adapter_t adapter) ++{ ++ DBG_ERROR(" (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ adapter->netdev->name, adapter->currmacaddr[0], ++ adapter->currmacaddr[1], adapter->currmacaddr[2], ++ adapter->currmacaddr[3], adapter->currmacaddr[4], ++ adapter->currmacaddr[5]); ++ DBG_ERROR(" (%s) mac %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ adapter->netdev->name, adapter->macaddr[0], ++ adapter->macaddr[1], adapter->macaddr[2], ++ adapter->macaddr[3], adapter->macaddr[4], ++ adapter->macaddr[5]); ++ return; ++} ++ ++// SXG Globals ++static SXG_DRIVER SxgDriver; ++ ++#ifdef ATKDBG ++static sxg_trace_buffer_t LSxgTraceBuffer; ++#endif /* ATKDBG */ ++static sxg_trace_buffer_t *SxgTraceBuffer = NULL; ++ ++/* ++ * sxg_download_microcode ++ * ++ * Download Microcode to Sahara adapter ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * UcodeSel - microcode file selection ++ * ++ * Return ++ * int ++ */ ++static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel) ++{ ++ PSXG_HW_REGS HwRegs = adapter->HwRegs; ++ u32 Section; ++ u32 ThisSectionSize; ++ u32 * Instruction = NULL; ++ u32 BaseAddress, AddressOffset, Address; ++// u32 Failure; ++ u32 ValueRead; ++ u32 i; ++ u32 numSections = 0; ++ u32 sectionSize[16]; ++ u32 sectionStart[16]; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DnldUcod", ++ adapter, 0, 0, 0); ++ DBG_ERROR("sxg: %s ENTER\n", __FUNCTION__); ++ ++ switch (UcodeSel) { ++ case SXG_UCODE_SAHARA: // Sahara operational ucode ++ numSections = SNumSections; ++ for (i = 0; i < numSections; i++) { ++ sectionSize[i] = SSectionSize[i]; ++ sectionStart[i] = SSectionStart[i]; ++ } ++ break; ++ default: ++ printk(KERN_ERR KBUILD_MODNAME ++ ": Woah, big error with the microcode!\n"); ++ break; ++ } ++ ++ DBG_ERROR("sxg: RESET THE CARD\n"); ++ // First, reset the card ++ WRITE_REG(HwRegs->Reset, 0xDEAD, FLUSH); ++ ++ // Download each section of the microcode as specified in ++ // its download file. The *download.c file is generated using ++ // the saharaobjtoc facility which converts the metastep .obj ++ // file to a .c file which contains a two dimentional array. ++ for (Section = 0; Section < numSections; Section++) { ++ DBG_ERROR("sxg: SECTION # %d\n", Section); ++ switch (UcodeSel) { ++ case SXG_UCODE_SAHARA: ++ Instruction = (u32 *) & SaharaUCode[Section][0]; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ BaseAddress = sectionStart[Section]; ++ ThisSectionSize = sectionSize[Section] / 12; // Size in instructions ++ for (AddressOffset = 0; AddressOffset < ThisSectionSize; ++ AddressOffset++) { ++ Address = BaseAddress + AddressOffset; ++ ASSERT((Address & ~MICROCODE_ADDRESS_MASK) == 0); ++ // Write instruction bits 31 - 0 ++ WRITE_REG(HwRegs->UcodeDataLow, *Instruction, FLUSH); ++ // Write instruction bits 63-32 ++ WRITE_REG(HwRegs->UcodeDataMiddle, *(Instruction + 1), ++ FLUSH); ++ // Write instruction bits 95-64 ++ WRITE_REG(HwRegs->UcodeDataHigh, *(Instruction + 2), ++ FLUSH); ++ // Write instruction address with the WRITE bit set ++ WRITE_REG(HwRegs->UcodeAddr, ++ (Address | MICROCODE_ADDRESS_WRITE), FLUSH); ++ // Sahara bug in the ucode download logic - the write to DataLow ++ // for the next instruction could get corrupted. To avoid this, ++ // write to DataLow again for this instruction (which may get ++ // corrupted, but it doesn't matter), then increment the address ++ // and write the data for the next instruction to DataLow. That ++ // write should succeed. ++ WRITE_REG(HwRegs->UcodeDataLow, *Instruction, TRUE); ++ // Advance 3 u32S to start of next instruction ++ Instruction += 3; ++ } ++ } ++ // Now repeat the entire operation reading the instruction back and ++ // checking for parity errors ++ for (Section = 0; Section < numSections; Section++) { ++ DBG_ERROR("sxg: check SECTION # %d\n", Section); ++ switch (UcodeSel) { ++ case SXG_UCODE_SAHARA: ++ Instruction = (u32 *) & SaharaUCode[Section][0]; ++ break; ++ default: ++ ASSERT(0); ++ break; ++ } ++ BaseAddress = sectionStart[Section]; ++ ThisSectionSize = sectionSize[Section] / 12; // Size in instructions ++ for (AddressOffset = 0; AddressOffset < ThisSectionSize; ++ AddressOffset++) { ++ Address = BaseAddress + AddressOffset; ++ // Write the address with the READ bit set ++ WRITE_REG(HwRegs->UcodeAddr, ++ (Address | MICROCODE_ADDRESS_READ), FLUSH); ++ // Read it back and check parity bit. ++ READ_REG(HwRegs->UcodeAddr, ValueRead); ++ if (ValueRead & MICROCODE_ADDRESS_PARITY) { ++ DBG_ERROR("sxg: %s PARITY ERROR\n", ++ __FUNCTION__); ++ ++ return (FALSE); // Parity error ++ } ++ ASSERT((ValueRead & MICROCODE_ADDRESS_MASK) == Address); ++ // Read the instruction back and compare ++ READ_REG(HwRegs->UcodeDataLow, ValueRead); ++ if (ValueRead != *Instruction) { ++ DBG_ERROR("sxg: %s MISCOMPARE LOW\n", ++ __FUNCTION__); ++ return (FALSE); // Miscompare ++ } ++ READ_REG(HwRegs->UcodeDataMiddle, ValueRead); ++ if (ValueRead != *(Instruction + 1)) { ++ DBG_ERROR("sxg: %s MISCOMPARE MIDDLE\n", ++ __FUNCTION__); ++ return (FALSE); // Miscompare ++ } ++ READ_REG(HwRegs->UcodeDataHigh, ValueRead); ++ if (ValueRead != *(Instruction + 2)) { ++ DBG_ERROR("sxg: %s MISCOMPARE HIGH\n", ++ __FUNCTION__); ++ return (FALSE); // Miscompare ++ } ++ // Advance 3 u32S to start of next instruction ++ Instruction += 3; ++ } ++ } ++ ++ // Everything OK, Go. ++ WRITE_REG(HwRegs->UcodeAddr, MICROCODE_ADDRESS_GO, FLUSH); ++ ++ // Poll the CardUp register to wait for microcode to initialize ++ // Give up after 10,000 attemps (500ms). ++ for (i = 0; i < 10000; i++) { ++ udelay(50); ++ READ_REG(adapter->UcodeRegs[0].CardUp, ValueRead); ++ if (ValueRead == 0xCAFE) { ++ DBG_ERROR("sxg: %s BOO YA 0xCAFE\n", __FUNCTION__); ++ break; ++ } ++ } ++ if (i == 10000) { ++ DBG_ERROR("sxg: %s TIMEOUT\n", __FUNCTION__); ++ ++ return (FALSE); // Timeout ++ } ++ // Now write the LoadSync register. This is used to ++ // synchronize with the card so it can scribble on the memory ++ // that contained 0xCAFE from the "CardUp" step above ++ if (UcodeSel == SXG_UCODE_SAHARA) { ++ WRITE_REG(adapter->UcodeRegs[0].LoadSync, 0, FLUSH); ++ } ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDnldUcd", ++ adapter, 0, 0, 0); ++ DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__); ++ ++ return (TRUE); ++} ++ ++/* ++ * sxg_allocate_resources - Allocate memory and locks ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * int ++ */ ++static int sxg_allocate_resources(p_adapter_t adapter) ++{ ++ int status; ++ u32 i; ++ u32 RssIds, IsrCount; ++// PSXG_XMT_RING XmtRing; ++// PSXG_RCV_RING RcvRing; ++ ++ DBG_ERROR("%s ENTER\n", __FUNCTION__); ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocRes", ++ adapter, 0, 0, 0); ++ ++ // Windows tells us how many CPUs it plans to use for ++ // RSS ++ RssIds = SXG_RSS_CPU_COUNT(adapter); ++ IsrCount = adapter->MsiEnabled ? RssIds : 1; ++ ++ DBG_ERROR("%s Setup the spinlocks\n", __FUNCTION__); ++ ++ // Allocate spinlocks and initialize listheads first. ++ spin_lock_init(&adapter->RcvQLock); ++ spin_lock_init(&adapter->SglQLock); ++ spin_lock_init(&adapter->XmtZeroLock); ++ spin_lock_init(&adapter->Bit64RegLock); ++ spin_lock_init(&adapter->AdapterLock); ++ ++ DBG_ERROR("%s Setup the lists\n", __FUNCTION__); ++ ++ InitializeListHead(&adapter->FreeRcvBuffers); ++ InitializeListHead(&adapter->FreeRcvBlocks); ++ InitializeListHead(&adapter->AllRcvBlocks); ++ InitializeListHead(&adapter->FreeSglBuffers); ++ InitializeListHead(&adapter->AllSglBuffers); ++ ++ // Mark these basic allocations done. This flags essentially ++ // tells the SxgFreeResources routine that it can grab spinlocks ++ // and reference listheads. ++ adapter->BasicAllocations = TRUE; ++ // Main allocation loop. Start with the maximum supported by ++ // the microcode and back off if memory allocation ++ // fails. If we hit a minimum, fail. ++ ++ for (;;) { ++ DBG_ERROR("%s Allocate XmtRings size[%x]\n", __FUNCTION__, ++ (sizeof(SXG_XMT_RING) * 1)); ++ ++ // Start with big items first - receive and transmit rings. At the moment ++ // I'm going to keep the ring size fixed and adjust the number of ++ // TCBs if we fail. Later we might consider reducing the ring size as well.. ++ adapter->XmtRings = pci_alloc_consistent(adapter->pcidev, ++ sizeof(SXG_XMT_RING) * ++ 1, ++ &adapter->PXmtRings); ++ DBG_ERROR("%s XmtRings[%p]\n", __FUNCTION__, adapter->XmtRings); ++ ++ if (!adapter->XmtRings) { ++ goto per_tcb_allocation_failed; ++ } ++ memset(adapter->XmtRings, 0, sizeof(SXG_XMT_RING) * 1); ++ ++ DBG_ERROR("%s Allocate RcvRings size[%x]\n", __FUNCTION__, ++ (sizeof(SXG_RCV_RING) * 1)); ++ adapter->RcvRings = ++ pci_alloc_consistent(adapter->pcidev, ++ sizeof(SXG_RCV_RING) * 1, ++ &adapter->PRcvRings); ++ DBG_ERROR("%s RcvRings[%p]\n", __FUNCTION__, adapter->RcvRings); ++ if (!adapter->RcvRings) { ++ goto per_tcb_allocation_failed; ++ } ++ memset(adapter->RcvRings, 0, sizeof(SXG_RCV_RING) * 1); ++ break; ++ ++ per_tcb_allocation_failed: ++ // an allocation failed. Free any successful allocations. ++ if (adapter->XmtRings) { ++ pci_free_consistent(adapter->pcidev, ++ sizeof(SXG_XMT_RING) * 4096, ++ adapter->XmtRings, ++ adapter->PXmtRings); ++ adapter->XmtRings = NULL; ++ } ++ if (adapter->RcvRings) { ++ pci_free_consistent(adapter->pcidev, ++ sizeof(SXG_RCV_RING) * 4096, ++ adapter->RcvRings, ++ adapter->PRcvRings); ++ adapter->RcvRings = NULL; ++ } ++ // Loop around and try again.... ++ } ++ ++ DBG_ERROR("%s Initialize RCV ZERO and XMT ZERO rings\n", __FUNCTION__); ++ // Initialize rcv zero and xmt zero rings ++ SXG_INITIALIZE_RING(adapter->RcvRingZeroInfo, SXG_RCV_RING_SIZE); ++ SXG_INITIALIZE_RING(adapter->XmtRingZeroInfo, SXG_XMT_RING_SIZE); ++ ++ // Sanity check receive data structure format ++ ASSERT((adapter->ReceiveBufferSize == SXG_RCV_DATA_BUFFER_SIZE) || ++ (adapter->ReceiveBufferSize == SXG_RCV_JUMBO_BUFFER_SIZE)); ++ ASSERT(sizeof(SXG_RCV_DESCRIPTOR_BLOCK) == ++ SXG_RCV_DESCRIPTOR_BLOCK_SIZE); ++ ++ // Allocate receive data buffers. We allocate a block of buffers and ++ // a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK ++ for (i = 0; i < SXG_INITIAL_RCV_DATA_BUFFERS; ++ i += SXG_RCV_DESCRIPTORS_PER_BLOCK) { ++ sxg_allocate_buffer_memory(adapter, ++ SXG_RCV_BLOCK_SIZE(adapter-> ++ ReceiveBufferSize), ++ SXG_BUFFER_TYPE_RCV); ++ } ++ // NBL resource allocation can fail in the 'AllocateComplete' routine, which ++ // doesn't return status. Make sure we got the number of buffers we requested ++ if (adapter->FreeRcvBufferCount < SXG_INITIAL_RCV_DATA_BUFFERS) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF6", ++ adapter, adapter->FreeRcvBufferCount, SXG_MAX_ENTRIES, ++ 0); ++ return (STATUS_RESOURCES); ++ } ++ ++ DBG_ERROR("%s Allocate EventRings size[%x]\n", __FUNCTION__, ++ (sizeof(SXG_EVENT_RING) * RssIds)); ++ ++ // Allocate event queues. ++ adapter->EventRings = pci_alloc_consistent(adapter->pcidev, ++ sizeof(SXG_EVENT_RING) * ++ RssIds, ++ &adapter->PEventRings); ++ ++ if (!adapter->EventRings) { ++ // Caller will call SxgFreeAdapter to clean up above allocations ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF8", ++ adapter, SXG_MAX_ENTRIES, 0, 0); ++ status = STATUS_RESOURCES; ++ goto per_tcb_allocation_failed; ++ } ++ memset(adapter->EventRings, 0, sizeof(SXG_EVENT_RING) * RssIds); ++ ++ DBG_ERROR("%s Allocate ISR size[%x]\n", __FUNCTION__, IsrCount); ++ // Allocate ISR ++ adapter->Isr = pci_alloc_consistent(adapter->pcidev, ++ IsrCount, &adapter->PIsr); ++ if (!adapter->Isr) { ++ // Caller will call SxgFreeAdapter to clean up above allocations ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF9", ++ adapter, SXG_MAX_ENTRIES, 0, 0); ++ status = STATUS_RESOURCES; ++ goto per_tcb_allocation_failed; ++ } ++ memset(adapter->Isr, 0, sizeof(u32) * IsrCount); ++ ++ DBG_ERROR("%s Allocate shared XMT ring zero index location size[%x]\n", ++ __FUNCTION__, sizeof(u32)); ++ ++ // Allocate shared XMT ring zero index location ++ adapter->XmtRingZeroIndex = pci_alloc_consistent(adapter->pcidev, ++ sizeof(u32), ++ &adapter-> ++ PXmtRingZeroIndex); ++ if (!adapter->XmtRingZeroIndex) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF10", ++ adapter, SXG_MAX_ENTRIES, 0, 0); ++ status = STATUS_RESOURCES; ++ goto per_tcb_allocation_failed; ++ } ++ memset(adapter->XmtRingZeroIndex, 0, sizeof(u32)); ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlcResS", ++ adapter, SXG_MAX_ENTRIES, 0, 0); ++ ++ DBG_ERROR("%s EXIT\n", __FUNCTION__); ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_config_pci - ++ * ++ * Set up PCI Configuration space ++ * ++ * Arguments - ++ * pcidev - A pointer to our adapter structure ++ * ++ */ ++static void sxg_config_pci(struct pci_dev *pcidev) ++{ ++ u16 pci_command; ++ u16 new_command; ++ ++ pci_read_config_word(pcidev, PCI_COMMAND, &pci_command); ++ DBG_ERROR("sxg: %s PCI command[%4.4x]\n", __FUNCTION__, pci_command); ++ // Set the command register ++ new_command = pci_command | (PCI_COMMAND_MEMORY | // Memory Space Enable ++ PCI_COMMAND_MASTER | // Bus master enable ++ PCI_COMMAND_INVALIDATE | // Memory write and invalidate ++ PCI_COMMAND_PARITY | // Parity error response ++ PCI_COMMAND_SERR | // System ERR ++ PCI_COMMAND_FAST_BACK); // Fast back-to-back ++ if (pci_command != new_command) { ++ DBG_ERROR("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n", ++ __FUNCTION__, pci_command, new_command); ++ pci_write_config_word(pcidev, PCI_COMMAND, new_command); ++ } ++} ++ ++static int sxg_entry_probe(struct pci_dev *pcidev, ++ const struct pci_device_id *pci_tbl_entry) ++{ ++ static int did_version = 0; ++ int err; ++ struct net_device *netdev; ++ p_adapter_t adapter; ++ void __iomem *memmapped_ioaddr; ++ u32 status = 0; ++ ulong mmio_start = 0; ++ ulong mmio_len = 0; ++ ++ DBG_ERROR("sxg: %s 2.6 VERSION ENTER jiffies[%lx] cpu %d\n", ++ __FUNCTION__, jiffies, smp_processor_id()); ++ ++ // Initialize trace buffer ++#ifdef ATKDBG ++ SxgTraceBuffer = &LSxgTraceBuffer; ++ SXG_TRACE_INIT(SxgTraceBuffer, TRACE_NOISY); ++#endif ++ ++ sxg_global.dynamic_intagg = dynamic_intagg; ++ ++ err = pci_enable_device(pcidev); ++ ++ DBG_ERROR("Call pci_enable_device(%p) status[%x]\n", pcidev, err); ++ if (err) { ++ return err; ++ } ++ ++ if (sxg_debug > 0 && did_version++ == 0) { ++ printk(KERN_INFO "%s\n", sxg_banner); ++ printk(KERN_INFO "%s\n", DRV_VERSION); ++ } ++ ++ if (!(err = pci_set_dma_mask(pcidev, DMA_64BIT_MASK))) { ++ DBG_ERROR("pci_set_dma_mask(DMA_64BIT_MASK) successful\n"); ++ } else { ++ if ((err = pci_set_dma_mask(pcidev, DMA_32BIT_MASK))) { ++ DBG_ERROR ++ ("No usable DMA configuration, aborting err[%x]\n", ++ err); ++ return err; ++ } ++ DBG_ERROR("pci_set_dma_mask(DMA_32BIT_MASK) successful\n"); ++ } ++ ++ DBG_ERROR("Call pci_request_regions\n"); ++ ++ err = pci_request_regions(pcidev, DRV_NAME); ++ if (err) { ++ DBG_ERROR("pci_request_regions FAILED err[%x]\n", err); ++ return err; ++ } ++ ++ DBG_ERROR("call pci_set_master\n"); ++ pci_set_master(pcidev); ++ ++ DBG_ERROR("call alloc_etherdev\n"); ++ netdev = alloc_etherdev(sizeof(adapter_t)); ++ if (!netdev) { ++ err = -ENOMEM; ++ goto err_out_exit_sxg_probe; ++ } ++ DBG_ERROR("alloc_etherdev for slic netdev[%p]\n", netdev); ++ ++ SET_NETDEV_DEV(netdev, &pcidev->dev); ++ ++ pci_set_drvdata(pcidev, netdev); ++ adapter = netdev_priv(netdev); ++ adapter->netdev = netdev; ++ adapter->pcidev = pcidev; ++ ++ mmio_start = pci_resource_start(pcidev, 0); ++ mmio_len = pci_resource_len(pcidev, 0); ++ ++ DBG_ERROR("sxg: call ioremap(mmio_start[%lx], mmio_len[%lx])\n", ++ mmio_start, mmio_len); ++ ++ memmapped_ioaddr = ioremap(mmio_start, mmio_len); ++ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __FUNCTION__, memmapped_ioaddr); ++ if (!memmapped_ioaddr) { ++ DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", ++ __FUNCTION__, mmio_len, mmio_start); ++ goto err_out_free_mmio_region; ++ } ++ ++ DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n", ++ __func__, memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq); ++ ++ adapter->HwRegs = (void *) memmapped_ioaddr; ++ adapter->base_addr = memmapped_ioaddr; ++ ++ mmio_start = pci_resource_start(pcidev, 2); ++ mmio_len = pci_resource_len(pcidev, 2); ++ ++ DBG_ERROR("sxg: call ioremap(mmio_start[%lx], mmio_len[%lx])\n", ++ mmio_start, mmio_len); ++ ++ memmapped_ioaddr = ioremap(mmio_start, mmio_len); ++ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __func__, memmapped_ioaddr); ++ if (!memmapped_ioaddr) { ++ DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", ++ __FUNCTION__, mmio_len, mmio_start); ++ goto err_out_free_mmio_region; ++ } ++ ++ DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, " ++ "start[%lx] len[%lx], IRQ %d.\n", __func__, ++ memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq); ++ ++ adapter->UcodeRegs = (void *)memmapped_ioaddr; ++ ++ adapter->State = SXG_STATE_INITIALIZING; ++ // Maintain a list of all adapters anchored by ++ // the global SxgDriver structure. ++ adapter->Next = SxgDriver.Adapters; ++ SxgDriver.Adapters = adapter; ++ adapter->AdapterID = ++SxgDriver.AdapterID; ++ ++ // Initialize CRC table used to determine multicast hash ++ sxg_mcast_init_crc32(); ++ ++ adapter->JumboEnabled = FALSE; ++ adapter->RssEnabled = FALSE; ++ if (adapter->JumboEnabled) { ++ adapter->FrameSize = JUMBOMAXFRAME; ++ adapter->ReceiveBufferSize = SXG_RCV_JUMBO_BUFFER_SIZE; ++ } else { ++ adapter->FrameSize = ETHERMAXFRAME; ++ adapter->ReceiveBufferSize = SXG_RCV_DATA_BUFFER_SIZE; ++ } ++ ++// status = SXG_READ_EEPROM(adapter); ++// if (!status) { ++// goto sxg_init_bad; ++// } ++ ++ DBG_ERROR("sxg: %s ENTER sxg_config_pci\n", __FUNCTION__); ++ sxg_config_pci(pcidev); ++ DBG_ERROR("sxg: %s EXIT sxg_config_pci\n", __FUNCTION__); ++ ++ DBG_ERROR("sxg: %s ENTER sxg_init_driver\n", __FUNCTION__); ++ sxg_init_driver(); ++ DBG_ERROR("sxg: %s EXIT sxg_init_driver\n", __FUNCTION__); ++ ++ adapter->vendid = pci_tbl_entry->vendor; ++ adapter->devid = pci_tbl_entry->device; ++ adapter->subsysid = pci_tbl_entry->subdevice; ++ adapter->busnumber = pcidev->bus->number; ++ adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F); ++ adapter->functionnumber = (pcidev->devfn & 0x7); ++ adapter->memorylength = pci_resource_len(pcidev, 0); ++ adapter->irq = pcidev->irq; ++ adapter->next_netdevice = head_netdevice; ++ head_netdevice = netdev; ++// adapter->chipid = chip_idx; ++ adapter->port = 0; //adapter->functionnumber; ++ adapter->cardindex = adapter->port; ++ ++ // Allocate memory and other resources ++ DBG_ERROR("sxg: %s ENTER sxg_allocate_resources\n", __FUNCTION__); ++ status = sxg_allocate_resources(adapter); ++ DBG_ERROR("sxg: %s EXIT sxg_allocate_resources status %x\n", ++ __FUNCTION__, status); ++ if (status != STATUS_SUCCESS) { ++ goto err_out_unmap; ++ } ++ ++ DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __FUNCTION__); ++ if (sxg_download_microcode(adapter, SXG_UCODE_SAHARA)) { ++ DBG_ERROR("sxg: %s ENTER sxg_adapter_set_hwaddr\n", ++ __FUNCTION__); ++ sxg_adapter_set_hwaddr(adapter); ++ } else { ++ adapter->state = ADAPT_FAIL; ++ adapter->linkstate = LINK_DOWN; ++ DBG_ERROR("sxg_download_microcode FAILED status[%x]\n", status); ++ } ++ ++ netdev->base_addr = (unsigned long)adapter->base_addr; ++ netdev->irq = adapter->irq; ++ netdev->open = sxg_entry_open; ++ netdev->stop = sxg_entry_halt; ++ netdev->hard_start_xmit = sxg_send_packets; ++ netdev->do_ioctl = sxg_ioctl; ++#if XXXTODO ++ netdev->set_mac_address = sxg_mac_set_address; ++#if SLIC_GET_STATS_ENABLED ++ netdev->get_stats = sxg_get_stats; ++#endif ++ netdev->set_multicast_list = sxg_mcast_set_list; ++#endif ++ ++ strcpy(netdev->name, "eth%d"); ++// strcpy(netdev->name, pci_name(pcidev)); ++ if ((err = register_netdev(netdev))) { ++ DBG_ERROR("Cannot register net device, aborting. %s\n", ++ netdev->name); ++ goto err_out_unmap; ++ } ++ ++ DBG_ERROR ++ ("sxg: %s addr 0x%lx, irq %d, MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", ++ netdev->name, netdev->base_addr, pcidev->irq, netdev->dev_addr[0], ++ netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3], ++ netdev->dev_addr[4], netdev->dev_addr[5]); ++ ++//sxg_init_bad: ++ ASSERT(status == FALSE); ++// sxg_free_adapter(adapter); ++ ++ DBG_ERROR("sxg: %s EXIT status[%x] jiffies[%lx] cpu %d\n", __FUNCTION__, ++ status, jiffies, smp_processor_id()); ++ return status; ++ ++ err_out_unmap: ++ iounmap((void *)memmapped_ioaddr); ++ ++ err_out_free_mmio_region: ++ release_mem_region(mmio_start, mmio_len); ++ ++ err_out_exit_sxg_probe: ++ ++ DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __FUNCTION__, jiffies, ++ smp_processor_id()); ++ ++ return -ENODEV; ++} ++ ++ ++/*********************************************************************** ++ * LINE BASE Interrupt routines.. ++ ***********************************************************************/ ++/* ++ * ++ * sxg_disable_interrupt ++ * ++ * DisableInterrupt Handler ++ * ++ * Arguments: ++ * ++ * adapter: Our adapter structure ++ * ++ * Return Value: ++ * None. ++ */ ++static void sxg_disable_interrupt(p_adapter_t adapter) ++{ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DisIntr", ++ adapter, adapter->InterruptsEnabled, 0, 0); ++ // For now, RSS is disabled with line based interrupts ++ ASSERT(adapter->RssEnabled == FALSE); ++ ASSERT(adapter->MsiEnabled == FALSE); ++ // ++ // Turn off interrupts by writing to the icr register. ++ // ++ WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_DISABLE), TRUE); ++ ++ adapter->InterruptsEnabled = 0; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDisIntr", ++ adapter, adapter->InterruptsEnabled, 0, 0); ++} ++ ++/* ++ * ++ * sxg_enable_interrupt ++ * ++ * EnableInterrupt Handler ++ * ++ * Arguments: ++ * ++ * adapter: Our adapter structure ++ * ++ * Return Value: ++ * None. ++ */ ++static void sxg_enable_interrupt(p_adapter_t adapter) ++{ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "EnIntr", ++ adapter, adapter->InterruptsEnabled, 0, 0); ++ // For now, RSS is disabled with line based interrupts ++ ASSERT(adapter->RssEnabled == FALSE); ++ ASSERT(adapter->MsiEnabled == FALSE); ++ // ++ // Turn on interrupts by writing to the icr register. ++ // ++ WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_ENABLE), TRUE); ++ ++ adapter->InterruptsEnabled = 1; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XEnIntr", ++ adapter, 0, 0, 0); ++} ++ ++/* ++ * ++ * sxg_isr - Process an line-based interrupt ++ * ++ * Arguments: ++ * Context - Our adapter structure ++ * QueueDefault - Output parameter to queue to default CPU ++ * TargetCpus - Output bitmap to schedule DPC's ++ * ++ * Return Value: ++ * TRUE if our interrupt ++ */ ++static irqreturn_t sxg_isr(int irq, void *dev_id) ++{ ++ p_net_device dev = (p_net_device) dev_id; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++// u32 CpuMask = 0, i; ++ ++ adapter->Stats.NumInts++; ++ if (adapter->Isr[0] == 0) { ++ // The SLIC driver used to experience a number of spurious interrupts ++ // due to the delay associated with the masking of the interrupt ++ // (we'd bounce back in here). If we see that again with Sahara, ++ // add a READ_REG of the Icr register after the WRITE_REG below. ++ adapter->Stats.FalseInts++; ++ return IRQ_NONE; ++ } ++ // ++ // Move the Isr contents and clear the value in ++ // shared memory, and mask interrupts ++ // ++ adapter->IsrCopy[0] = adapter->Isr[0]; ++ adapter->Isr[0] = 0; ++ WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_MASK), TRUE); ++// ASSERT(adapter->IsrDpcsPending == 0); ++#if XXXTODO // RSS Stuff ++ // If RSS is enabled and the ISR specifies ++ // SXG_ISR_EVENT, then schedule DPC's ++ // based on event queues. ++ if (adapter->RssEnabled && (adapter->IsrCopy[0] & SXG_ISR_EVENT)) { ++ for (i = 0; ++ i < adapter->RssSystemInfo->ProcessorInfo.RssCpuCount; ++ i++) { ++ PSXG_EVENT_RING EventRing = &adapter->EventRings[i]; ++ PSXG_EVENT Event = ++ &EventRing->Ring[adapter->NextEvent[i]]; ++ unsigned char Cpu = adapter->RssSystemInfo->RssIdToCpu[i]; ++ if (Event->Status & EVENT_STATUS_VALID) { ++ adapter->IsrDpcsPending++; ++ CpuMask |= (1 << Cpu); ++ } ++ } ++ } ++ // Now, either schedule the CPUs specified by the CpuMask, ++ // or queue default ++ if (CpuMask) { ++ *QueueDefault = FALSE; ++ } else { ++ adapter->IsrDpcsPending = 1; ++ *QueueDefault = TRUE; ++ } ++ *TargetCpus = CpuMask; ++#endif ++ // ++ // There are no DPCs in Linux, so call the handler now ++ // ++ sxg_handle_interrupt(adapter); ++ ++ return IRQ_HANDLED; ++} ++ ++static void sxg_handle_interrupt(p_adapter_t adapter) ++{ ++// unsigned char RssId = 0; ++ u32 NewIsr; ++ ++ if (adapter->Stats.RcvNoBuffer < 5) { ++ DBG_ERROR("Enter sxg_handle_interrupt ISR[%x]\n", ++ adapter->IsrCopy[0]); ++ } ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "HndlIntr", ++ adapter, adapter->IsrCopy[0], 0, 0); ++ // For now, RSS is disabled with line based interrupts ++ ASSERT(adapter->RssEnabled == FALSE); ++ ASSERT(adapter->MsiEnabled == FALSE); ++ ASSERT(adapter->IsrCopy[0]); ++///////////////////////////// ++ ++ // Always process the event queue. ++ sxg_process_event_queue(adapter, ++ (adapter->RssEnabled ? /*RssId */ 0 : 0)); ++ ++#if XXXTODO // RSS stuff ++ if (--adapter->IsrDpcsPending) { ++ // We're done. ++ ASSERT(adapter->RssEnabled); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DPCsPend", ++ adapter, 0, 0, 0); ++ return; ++ } ++#endif ++ // ++ // Last (or only) DPC processes the ISR and clears the interrupt. ++ // ++ NewIsr = sxg_process_isr(adapter, 0); ++ // ++ // Reenable interrupts ++ // ++ adapter->IsrCopy[0] = 0; ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ClearIsr", ++ adapter, NewIsr, 0, 0); ++ ++ if (adapter->Stats.RcvNoBuffer < 5) { ++ DBG_ERROR ++ ("Exit sxg_handle_interrupt2 after enabling interrupt\n"); ++ } ++ ++ WRITE_REG(adapter->UcodeRegs[0].Isr, NewIsr, TRUE); ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XHndlInt", ++ adapter, 0, 0, 0); ++} ++ ++/* ++ * ++ * sxg_process_isr - Process an interrupt. Called from the line-based and ++ * message based interrupt DPC routines ++ * ++ * Arguments: ++ * adapter - Our adapter structure ++ * Queue - The ISR that needs processing ++ * ++ * Return Value: ++ * None ++ */ ++static int sxg_process_isr(p_adapter_t adapter, u32 MessageId) ++{ ++ u32 Isr = adapter->IsrCopy[MessageId]; ++ u32 NewIsr = 0; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ProcIsr", ++ adapter, Isr, 0, 0); ++ ++ // Error ++ if (Isr & SXG_ISR_ERR) { ++ if (Isr & SXG_ISR_PDQF) { ++ adapter->Stats.PdqFull++; ++ DBG_ERROR("%s: SXG_ISR_ERR PDQF!!\n", __FUNCTION__); ++ } ++ // No host buffer ++ if (Isr & SXG_ISR_RMISS) { ++ // There is a bunch of code in the SLIC driver which ++ // attempts to process more receive events per DPC ++ // if we start to fall behind. We'll probably ++ // need to do something similar here, but hold ++ // off for now. I don't want to make the code more ++ // complicated than strictly needed. ++ adapter->Stats.RcvNoBuffer++; ++ if (adapter->Stats.RcvNoBuffer < 5) { ++ DBG_ERROR("%s: SXG_ISR_ERR RMISS!!\n", ++ __FUNCTION__); ++ } ++ } ++ // Card crash ++ if (Isr & SXG_ISR_DEAD) { ++ // Set aside the crash info and set the adapter state to RESET ++ adapter->CrashCpu = ++ (unsigned char) ((Isr & SXG_ISR_CPU) >> SXG_ISR_CPU_SHIFT); ++ adapter->CrashLocation = (ushort) (Isr & SXG_ISR_CRASH); ++ adapter->Dead = TRUE; ++ DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __FUNCTION__, ++ adapter->CrashLocation, adapter->CrashCpu); ++ } ++ // Event ring full ++ if (Isr & SXG_ISR_ERFULL) { ++ // Same issue as RMISS, really. This means the ++ // host is falling behind the card. Need to increase ++ // event ring size, process more events per interrupt, ++ // and/or reduce/remove interrupt aggregation. ++ adapter->Stats.EventRingFull++; ++ DBG_ERROR("%s: SXG_ISR_ERR EVENT RING FULL!!\n", ++ __FUNCTION__); ++ } ++ // Transmit drop - no DRAM buffers or XMT error ++ if (Isr & SXG_ISR_XDROP) { ++ adapter->Stats.XmtDrops++; ++ adapter->Stats.XmtErrors++; ++ DBG_ERROR("%s: SXG_ISR_ERR XDROP!!\n", __FUNCTION__); ++ } ++ } ++ // Slowpath send completions ++ if (Isr & SXG_ISR_SPSEND) { ++ sxg_complete_slow_send(adapter); ++ } ++ // Dump ++ if (Isr & SXG_ISR_UPC) { ++ ASSERT(adapter->DumpCmdRunning); // Maybe change when debug is added.. ++ adapter->DumpCmdRunning = FALSE; ++ } ++ // Link event ++ if (Isr & SXG_ISR_LINK) { ++ sxg_link_event(adapter); ++ } ++ // Debug - breakpoint hit ++ if (Isr & SXG_ISR_BREAK) { ++ // At the moment AGDB isn't written to support interactive ++ // debug sessions. When it is, this interrupt will be used ++ // to signal AGDB that it has hit a breakpoint. For now, ASSERT. ++ ASSERT(0); ++ } ++ // Heartbeat response ++ if (Isr & SXG_ISR_PING) { ++ adapter->PingOutstanding = FALSE; ++ } ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XProcIsr", ++ adapter, Isr, NewIsr, 0); ++ ++ return (NewIsr); ++} ++ ++/* ++ * ++ * sxg_process_event_queue - Process our event queue ++ * ++ * Arguments: ++ * - adapter - Adapter structure ++ * - RssId - The event queue requiring processing ++ * ++ * Return Value: ++ * None. ++ */ ++static u32 sxg_process_event_queue(p_adapter_t adapter, u32 RssId) ++{ ++ PSXG_EVENT_RING EventRing = &adapter->EventRings[RssId]; ++ PSXG_EVENT Event = &EventRing->Ring[adapter->NextEvent[RssId]]; ++ u32 EventsProcessed = 0, Batches = 0; ++ u32 num_skbs = 0; ++ struct sk_buff *skb; ++#ifdef LINUX_HANDLES_RCV_INDICATION_LISTS ++ struct sk_buff *prev_skb = NULL; ++ struct sk_buff *IndicationList[SXG_RCV_ARRAYSIZE]; ++ u32 Index; ++ PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr; ++#endif ++ u32 ReturnStatus = 0; ++ ++ ASSERT((adapter->State == SXG_STATE_RUNNING) || ++ (adapter->State == SXG_STATE_PAUSING) || ++ (adapter->State == SXG_STATE_PAUSED) || ++ (adapter->State == SXG_STATE_HALTING)); ++ // We may still have unprocessed events on the queue if ++ // the card crashed. Don't process them. ++ if (adapter->Dead) { ++ return (0); ++ } ++ // In theory there should only be a single processor that ++ // accesses this queue, and only at interrupt-DPC time. So ++ // we shouldn't need a lock for any of this. ++ while (Event->Status & EVENT_STATUS_VALID) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "Event", ++ Event, Event->Code, Event->Status, ++ adapter->NextEvent); ++ switch (Event->Code) { ++ case EVENT_CODE_BUFFERS: ++ ASSERT(!(Event->CommandIndex & 0xFF00)); // SXG_RING_INFO Head & Tail == unsigned char ++ // ++ sxg_complete_descriptor_blocks(adapter, ++ Event->CommandIndex); ++ // ++ break; ++ case EVENT_CODE_SLOWRCV: ++ --adapter->RcvBuffersOnCard; ++ if ((skb = sxg_slow_receive(adapter, Event))) { ++ u32 rx_bytes; ++#ifdef LINUX_HANDLES_RCV_INDICATION_LISTS ++ // Add it to our indication list ++ SXG_ADD_RCV_PACKET(adapter, skb, prev_skb, ++ IndicationList, num_skbs); ++ // In Linux, we just pass up each skb to the protocol above at this point, ++ // there is no capability of an indication list. ++#else ++// CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE); ++ rx_bytes = Event->Length; // (rcvbuf->length & IRHDDR_FLEN_MSK); ++ skb_put(skb, rx_bytes); ++ adapter->stats.rx_packets++; ++ adapter->stats.rx_bytes += rx_bytes; ++#if SXG_OFFLOAD_IP_CHECKSUM ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++#endif ++ skb->dev = adapter->netdev; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ netif_rx(skb); ++#endif ++ } ++ break; ++ default: ++ DBG_ERROR("%s: ERROR Invalid EventCode %d\n", ++ __FUNCTION__, Event->Code); ++// ASSERT(0); ++ } ++ // See if we need to restock card receive buffers. ++ // There are two things to note here: ++ // First - This test is not SMP safe. The ++ // adapter->BuffersOnCard field is protected via atomic interlocked calls, but ++ // we do not protect it with respect to these tests. The only way to do that ++ // is with a lock, and I don't want to grab a lock every time we adjust the ++ // BuffersOnCard count. Instead, we allow the buffer replenishment to be off ++ // once in a while. The worst that can happen is the card is given one ++ // more-or-less descriptor block than the arbitrary value we've chosen. ++ // No big deal ++ // In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard is adjusted. ++ // Second - We expect this test to rarely evaluate to true. We attempt to ++ // refill descriptor blocks as they are returned to us ++ // (sxg_complete_descriptor_blocks), so The only time this should evaluate ++ // to true is when sxg_complete_descriptor_blocks failed to allocate ++ // receive buffers. ++ if (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) { ++ sxg_stock_rcv_buffers(adapter); ++ } ++ // It's more efficient to just set this to zero. ++ // But clearing the top bit saves potential debug info... ++ Event->Status &= ~EVENT_STATUS_VALID; ++ // Advanct to the next event ++ SXG_ADVANCE_INDEX(adapter->NextEvent[RssId], EVENT_RING_SIZE); ++ Event = &EventRing->Ring[adapter->NextEvent[RssId]]; ++ EventsProcessed++; ++ if (EventsProcessed == EVENT_RING_BATCH) { ++ // Release a batch of events back to the card ++ WRITE_REG(adapter->UcodeRegs[RssId].EventRelease, ++ EVENT_RING_BATCH, FALSE); ++ EventsProcessed = 0; ++ // If we've processed our batch limit, break out of the ++ // loop and return SXG_ISR_EVENT to arrange for us to ++ // be called again ++ if (Batches++ == EVENT_BATCH_LIMIT) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, ++ TRACE_NOISY, "EvtLimit", Batches, ++ adapter->NextEvent, 0, 0); ++ ReturnStatus = SXG_ISR_EVENT; ++ break; ++ } ++ } ++ } ++#ifdef LINUX_HANDLES_RCV_INDICATION_LISTS ++ // ++ // Indicate any received dumb-nic frames ++ // ++ SXG_INDICATE_PACKETS(adapter, IndicationList, num_skbs); ++#endif ++ // ++ // Release events back to the card. ++ // ++ if (EventsProcessed) { ++ WRITE_REG(adapter->UcodeRegs[RssId].EventRelease, ++ EventsProcessed, FALSE); ++ } ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XPrcEvnt", ++ Batches, EventsProcessed, adapter->NextEvent, num_skbs); ++ ++ return (ReturnStatus); ++} ++ ++/* ++ * sxg_complete_slow_send - Complete slowpath or dumb-nic sends ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ ++ * Return ++ * None ++ */ ++static void sxg_complete_slow_send(p_adapter_t adapter) ++{ ++ PSXG_XMT_RING XmtRing = &adapter->XmtRings[0]; ++ PSXG_RING_INFO XmtRingInfo = &adapter->XmtRingZeroInfo; ++ u32 * ContextType; ++ PSXG_CMD XmtCmd; ++ ++ // NOTE - This lock is dropped and regrabbed in this loop. ++ // This means two different processors can both be running ++ // through this loop. Be *very* careful. ++ spin_lock(&adapter->XmtZeroLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnds", ++ adapter, XmtRingInfo->Head, XmtRingInfo->Tail, 0); ++ ++ while (XmtRingInfo->Tail != *adapter->XmtRingZeroIndex) { ++ // Locate the current Cmd (ring descriptor entry), and ++ // associated SGL, and advance the tail ++ SXG_RETURN_CMD(XmtRing, XmtRingInfo, XmtCmd, ContextType); ++ ASSERT(ContextType); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnd", ++ XmtRingInfo->Head, XmtRingInfo->Tail, XmtCmd, 0); ++ // Clear the SGL field. ++ XmtCmd->Sgl = 0; ++ ++ switch (*ContextType) { ++ case SXG_SGL_DUMB: ++ { ++ struct sk_buff *skb; ++ // Dumb-nic send. Command context is the dumb-nic SGL ++ skb = (struct sk_buff *)ContextType; ++ // Complete the send ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, ++ TRACE_IMPORTANT, "DmSndCmp", skb, 0, ++ 0, 0); ++ ASSERT(adapter->Stats.XmtQLen); ++ adapter->Stats.XmtQLen--; // within XmtZeroLock ++ adapter->Stats.XmtOk++; ++ // Now drop the lock and complete the send back to ++ // Microsoft. We need to drop the lock because ++ // Microsoft can come back with a chimney send, which ++ // results in a double trip in SxgTcpOuput ++ spin_unlock(&adapter->XmtZeroLock); ++ SXG_COMPLETE_DUMB_SEND(adapter, skb); ++ // and reacquire.. ++ spin_lock(&adapter->XmtZeroLock); ++ } ++ break; ++ default: ++ ASSERT(0); ++ } ++ } ++ spin_unlock(&adapter->XmtZeroLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnd", ++ adapter, XmtRingInfo->Head, XmtRingInfo->Tail, 0); ++} ++ ++/* ++ * sxg_slow_receive ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * Event - Receive event ++ * ++ * Return ++ * skb ++ */ ++static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event) ++{ ++ PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr; ++ struct sk_buff *Packet; ++ ++ RcvDataBufferHdr = (PSXG_RCV_DATA_BUFFER_HDR) Event->HostHandle; ++ ASSERT(RcvDataBufferHdr); ++ ASSERT(RcvDataBufferHdr->State == SXG_BUFFER_ONCARD); ++ ASSERT(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr) == ++ RcvDataBufferHdr->VirtualAddress); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "SlowRcv", Event, ++ RcvDataBufferHdr, RcvDataBufferHdr->State, ++ RcvDataBufferHdr->VirtualAddress); ++ // Drop rcv frames in non-running state ++ switch (adapter->State) { ++ case SXG_STATE_RUNNING: ++ break; ++ case SXG_STATE_PAUSING: ++ case SXG_STATE_PAUSED: ++ case SXG_STATE_HALTING: ++ goto drop; ++ default: ++ ASSERT(0); ++ goto drop; ++ } ++ ++ // Change buffer state to UPSTREAM ++ RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; ++ if (Event->Status & EVENT_STATUS_RCVERR) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvError", ++ Event, Event->Status, Event->HostHandle, 0); ++ // XXXTODO - Remove this print later ++ DBG_ERROR("SXG: Receive error %x\n", ++ *(u32 *) ++ SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)); ++ sxg_process_rcv_error(adapter, ++ *(u32 *) ++ SXG_RECEIVE_DATA_LOCATION ++ (RcvDataBufferHdr)); ++ goto drop; ++ } ++#if XXXTODO // VLAN stuff ++ // If there's a VLAN tag, extract it and validate it ++ if (((p_ether_header) (SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)))-> ++ EtherType == ETHERTYPE_VLAN) { ++ if (SxgExtractVlanHeader(adapter, RcvDataBufferHdr, Event) != ++ STATUS_SUCCESS) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, ++ "BadVlan", Event, ++ SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), ++ Event->Length, 0); ++ goto drop; ++ } ++ } ++#endif ++ // ++ // Dumb-nic frame. See if it passes our mac filter and update stats ++ // ++ if (!sxg_mac_filter(adapter, ++ (p_ether_header) ++ SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), ++ Event->Length)) { ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr", ++ Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), ++ Event->Length, 0); ++ goto drop; ++ } ++ ++ Packet = RcvDataBufferHdr->SxgDumbRcvPacket; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumbRcv", ++ RcvDataBufferHdr, Packet, Event->Length, 0); ++ // ++ // Lastly adjust the receive packet length. ++ // ++ SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event); ++ ++ return (Packet); ++ ++ drop: ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DropRcv", ++ RcvDataBufferHdr, Event->Length, 0, 0); ++ adapter->Stats.RcvDiscards++; ++ spin_lock(&adapter->RcvQLock); ++ SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); ++ spin_unlock(&adapter->RcvQLock); ++ return (NULL); ++} ++ ++/* ++ * sxg_process_rcv_error - process receive error and update ++ * stats ++ * ++ * Arguments: ++ * adapter - Adapter structure ++ * ErrorStatus - 4-byte receive error status ++ * ++ * Return Value: ++ * None ++ */ ++static void sxg_process_rcv_error(p_adapter_t adapter, u32 ErrorStatus) ++{ ++ u32 Error; ++ ++ adapter->Stats.RcvErrors++; ++ ++ if (ErrorStatus & SXG_RCV_STATUS_TRANSPORT_ERROR) { ++ Error = ErrorStatus & SXG_RCV_STATUS_TRANSPORT_MASK; ++ switch (Error) { ++ case SXG_RCV_STATUS_TRANSPORT_CSUM: ++ adapter->Stats.TransportCsum++; ++ break; ++ case SXG_RCV_STATUS_TRANSPORT_UFLOW: ++ adapter->Stats.TransportUflow++; ++ break; ++ case SXG_RCV_STATUS_TRANSPORT_HDRLEN: ++ adapter->Stats.TransportHdrLen++; ++ break; ++ } ++ } ++ if (ErrorStatus & SXG_RCV_STATUS_NETWORK_ERROR) { ++ Error = ErrorStatus & SXG_RCV_STATUS_NETWORK_MASK; ++ switch (Error) { ++ case SXG_RCV_STATUS_NETWORK_CSUM: ++ adapter->Stats.NetworkCsum++; ++ break; ++ case SXG_RCV_STATUS_NETWORK_UFLOW: ++ adapter->Stats.NetworkUflow++; ++ break; ++ case SXG_RCV_STATUS_NETWORK_HDRLEN: ++ adapter->Stats.NetworkHdrLen++; ++ break; ++ } ++ } ++ if (ErrorStatus & SXG_RCV_STATUS_PARITY) { ++ adapter->Stats.Parity++; ++ } ++ if (ErrorStatus & SXG_RCV_STATUS_LINK_ERROR) { ++ Error = ErrorStatus & SXG_RCV_STATUS_LINK_MASK; ++ switch (Error) { ++ case SXG_RCV_STATUS_LINK_PARITY: ++ adapter->Stats.LinkParity++; ++ break; ++ case SXG_RCV_STATUS_LINK_EARLY: ++ adapter->Stats.LinkEarly++; ++ break; ++ case SXG_RCV_STATUS_LINK_BUFOFLOW: ++ adapter->Stats.LinkBufOflow++; ++ break; ++ case SXG_RCV_STATUS_LINK_CODE: ++ adapter->Stats.LinkCode++; ++ break; ++ case SXG_RCV_STATUS_LINK_DRIBBLE: ++ adapter->Stats.LinkDribble++; ++ break; ++ case SXG_RCV_STATUS_LINK_CRC: ++ adapter->Stats.LinkCrc++; ++ break; ++ case SXG_RCV_STATUS_LINK_OFLOW: ++ adapter->Stats.LinkOflow++; ++ break; ++ case SXG_RCV_STATUS_LINK_UFLOW: ++ adapter->Stats.LinkUflow++; ++ break; ++ } ++ } ++} ++ ++/* ++ * sxg_mac_filter ++ * ++ * Arguments: ++ * adapter - Adapter structure ++ * pether - Ethernet header ++ * length - Frame length ++ * ++ * Return Value: ++ * TRUE if the frame is to be allowed ++ */ ++static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr, ushort length) ++{ ++ bool EqualAddr; ++ ++ if (SXG_MULTICAST_PACKET(EtherHdr)) { ++ if (SXG_BROADCAST_PACKET(EtherHdr)) { ++ // broadcast ++ if (adapter->MacFilter & MAC_BCAST) { ++ adapter->Stats.DumbRcvBcastPkts++; ++ adapter->Stats.DumbRcvBcastBytes += length; ++ adapter->Stats.DumbRcvPkts++; ++ adapter->Stats.DumbRcvBytes += length; ++ return (TRUE); ++ } ++ } else { ++ // multicast ++ if (adapter->MacFilter & MAC_ALLMCAST) { ++ adapter->Stats.DumbRcvMcastPkts++; ++ adapter->Stats.DumbRcvMcastBytes += length; ++ adapter->Stats.DumbRcvPkts++; ++ adapter->Stats.DumbRcvBytes += length; ++ return (TRUE); ++ } ++ if (adapter->MacFilter & MAC_MCAST) { ++ PSXG_MULTICAST_ADDRESS MulticastAddrs = ++ adapter->MulticastAddrs; ++ while (MulticastAddrs) { ++ ETHER_EQ_ADDR(MulticastAddrs->Address, ++ EtherHdr->ether_dhost, ++ EqualAddr); ++ if (EqualAddr) { ++ adapter->Stats. ++ DumbRcvMcastPkts++; ++ adapter->Stats. ++ DumbRcvMcastBytes += length; ++ adapter->Stats.DumbRcvPkts++; ++ adapter->Stats.DumbRcvBytes += ++ length; ++ return (TRUE); ++ } ++ MulticastAddrs = MulticastAddrs->Next; ++ } ++ } ++ } ++ } else if (adapter->MacFilter & MAC_DIRECTED) { ++ // Not broadcast or multicast. Must be directed at us or ++ // the card is in promiscuous mode. Either way, consider it ++ // ours if MAC_DIRECTED is set ++ adapter->Stats.DumbRcvUcastPkts++; ++ adapter->Stats.DumbRcvUcastBytes += length; ++ adapter->Stats.DumbRcvPkts++; ++ adapter->Stats.DumbRcvBytes += length; ++ return (TRUE); ++ } ++ if (adapter->MacFilter & MAC_PROMISC) { ++ // Whatever it is, keep it. ++ adapter->Stats.DumbRcvPkts++; ++ adapter->Stats.DumbRcvBytes += length; ++ return (TRUE); ++ } ++ adapter->Stats.RcvDiscards++; ++ return (FALSE); ++} ++ ++static int sxg_register_interrupt(p_adapter_t adapter) ++{ ++ if (!adapter->intrregistered) { ++ int retval; ++ ++ DBG_ERROR ++ ("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x] %x\n", ++ __FUNCTION__, adapter, adapter->netdev->irq, NR_IRQS); ++ ++ spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); ++ ++ retval = request_irq(adapter->netdev->irq, ++ &sxg_isr, ++ IRQF_SHARED, ++ adapter->netdev->name, adapter->netdev); ++ ++ spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags); ++ ++ if (retval) { ++ DBG_ERROR("sxg: request_irq (%s) FAILED [%x]\n", ++ adapter->netdev->name, retval); ++ return (retval); ++ } ++ adapter->intrregistered = 1; ++ adapter->IntRegistered = TRUE; ++ // Disable RSS with line-based interrupts ++ adapter->MsiEnabled = FALSE; ++ adapter->RssEnabled = FALSE; ++ DBG_ERROR("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x]\n", ++ __FUNCTION__, adapter, adapter->netdev->irq); ++ } ++ return (STATUS_SUCCESS); ++} ++ ++static void sxg_deregister_interrupt(p_adapter_t adapter) ++{ ++ DBG_ERROR("sxg: %s ENTER adapter[%p]\n", __FUNCTION__, adapter); ++#if XXXTODO ++ slic_init_cleanup(adapter); ++#endif ++ memset(&adapter->stats, 0, sizeof(struct net_device_stats)); ++ adapter->error_interrupts = 0; ++ adapter->rcv_interrupts = 0; ++ adapter->xmit_interrupts = 0; ++ adapter->linkevent_interrupts = 0; ++ adapter->upr_interrupts = 0; ++ adapter->num_isrs = 0; ++ adapter->xmit_completes = 0; ++ adapter->rcv_broadcasts = 0; ++ adapter->rcv_multicasts = 0; ++ adapter->rcv_unicasts = 0; ++ DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__); ++} ++ ++/* ++ * sxg_if_init ++ * ++ * Perform initialization of our slic interface. ++ * ++ */ ++static int sxg_if_init(p_adapter_t adapter) ++{ ++ p_net_device dev = adapter->netdev; ++ int status = 0; ++ ++ DBG_ERROR("sxg: %s (%s) ENTER states[%d:%d:%d] flags[%x]\n", ++ __FUNCTION__, adapter->netdev->name, ++ adapter->queues_initialized, adapter->state, ++ adapter->linkstate, dev->flags); ++ ++ /* adapter should be down at this point */ ++ if (adapter->state != ADAPT_DOWN) { ++ DBG_ERROR("sxg_if_init adapter->state != ADAPT_DOWN\n"); ++ return (-EIO); ++ } ++ ASSERT(adapter->linkstate == LINK_DOWN); ++ ++ adapter->devflags_prev = dev->flags; ++ adapter->macopts = MAC_DIRECTED; ++ if (dev->flags) { ++ DBG_ERROR("sxg: %s (%s) Set MAC options: ", __FUNCTION__, ++ adapter->netdev->name); ++ if (dev->flags & IFF_BROADCAST) { ++ adapter->macopts |= MAC_BCAST; ++ DBG_ERROR("BCAST "); ++ } ++ if (dev->flags & IFF_PROMISC) { ++ adapter->macopts |= MAC_PROMISC; ++ DBG_ERROR("PROMISC "); ++ } ++ if (dev->flags & IFF_ALLMULTI) { ++ adapter->macopts |= MAC_ALLMCAST; ++ DBG_ERROR("ALL_MCAST "); ++ } ++ if (dev->flags & IFF_MULTICAST) { ++ adapter->macopts |= MAC_MCAST; ++ DBG_ERROR("MCAST "); ++ } ++ DBG_ERROR("\n"); ++ } ++ status = sxg_register_interrupt(adapter); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("sxg_if_init: sxg_register_interrupt FAILED %x\n", ++ status); ++ sxg_deregister_interrupt(adapter); ++ return (status); ++ } ++ ++ adapter->state = ADAPT_UP; ++ ++ /* ++ * clear any pending events, then enable interrupts ++ */ ++ DBG_ERROR("sxg: %s ENABLE interrupts(slic)\n", __FUNCTION__); ++ ++ return (STATUS_SUCCESS); ++} ++ ++static int sxg_entry_open(p_net_device dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ int status; ++ ++ ASSERT(adapter); ++ DBG_ERROR("sxg: %s adapter->activated[%d]\n", __FUNCTION__, ++ adapter->activated); ++ DBG_ERROR ++ ("sxg: %s (%s): [jiffies[%lx] cpu %d] dev[%p] adapt[%p] port[%d]\n", ++ __FUNCTION__, adapter->netdev->name, jiffies, smp_processor_id(), ++ adapter->netdev, adapter, adapter->port); ++ ++ netif_stop_queue(adapter->netdev); ++ ++ spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags); ++ if (!adapter->activated) { ++ sxg_global.num_sxg_ports_active++; ++ adapter->activated = 1; ++ } ++ ++ // Initialize the adapter ++ DBG_ERROR("sxg: %s ENTER sxg_initialize_adapter\n", __FUNCTION__); ++ status = sxg_initialize_adapter(adapter); ++ DBG_ERROR("sxg: %s EXIT sxg_initialize_adapter status[%x]\n", ++ __FUNCTION__, status); ++ ++ if (status == STATUS_SUCCESS) { ++ DBG_ERROR("sxg: %s ENTER sxg_if_init\n", __FUNCTION__); ++ status = sxg_if_init(adapter); ++ DBG_ERROR("sxg: %s EXIT sxg_if_init status[%x]\n", __FUNCTION__, ++ status); ++ } ++ ++ if (status != STATUS_SUCCESS) { ++ if (adapter->activated) { ++ sxg_global.num_sxg_ports_active--; ++ adapter->activated = 0; ++ } ++ spin_unlock_irqrestore(&sxg_global.driver_lock, ++ sxg_global.flags); ++ return (status); ++ } ++ DBG_ERROR("sxg: %s ENABLE ALL INTERRUPTS\n", __FUNCTION__); ++ ++ // Enable interrupts ++ SXG_ENABLE_ALL_INTERRUPTS(adapter); ++ ++ DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__); ++ ++ spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); ++ return STATUS_SUCCESS; ++} ++ ++static void __devexit sxg_entry_remove(struct pci_dev *pcidev) ++{ ++ p_net_device dev = pci_get_drvdata(pcidev); ++ u32 mmio_start = 0; ++ unsigned int mmio_len = 0; ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ ++ ASSERT(adapter); ++ DBG_ERROR("sxg: %s ENTER dev[%p] adapter[%p]\n", __FUNCTION__, dev, ++ adapter); ++ sxg_deregister_interrupt(adapter); ++ sxg_unmap_mmio_space(adapter); ++ DBG_ERROR("sxg: %s unregister_netdev\n", __FUNCTION__); ++ unregister_netdev(dev); ++ ++ mmio_start = pci_resource_start(pcidev, 0); ++ mmio_len = pci_resource_len(pcidev, 0); ++ ++ DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __FUNCTION__, ++ mmio_start, mmio_len); ++ release_mem_region(mmio_start, mmio_len); ++ ++ DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __FUNCTION__, ++ (unsigned int) dev->base_addr); ++ iounmap((char *)dev->base_addr); ++ ++ DBG_ERROR("sxg: %s deallocate device\n", __FUNCTION__); ++ kfree(dev); ++ DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__); ++} ++ ++static int sxg_entry_halt(p_net_device dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ ++ spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags); ++ DBG_ERROR("sxg: %s (%s) ENTER\n", __FUNCTION__, dev->name); ++ ++ netif_stop_queue(adapter->netdev); ++ adapter->state = ADAPT_DOWN; ++ adapter->linkstate = LINK_DOWN; ++ adapter->devflags_prev = 0; ++ DBG_ERROR("sxg: %s (%s) set adapter[%p] state to ADAPT_DOWN(%d)\n", ++ __FUNCTION__, dev->name, adapter, adapter->state); ++ ++ DBG_ERROR("sxg: %s (%s) EXIT\n", __FUNCTION__, dev->name); ++ DBG_ERROR("sxg: %s EXIT\n", __FUNCTION__); ++ spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); ++ return (STATUS_SUCCESS); ++} ++ ++static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd) ++{ ++ ASSERT(rq); ++// DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __FUNCTION__, cmd, rq, dev); ++ switch (cmd) { ++ case SIOCSLICSETINTAGG: ++ { ++// p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ u32 data[7]; ++ u32 intagg; ++ ++ if (copy_from_user(data, rq->ifr_data, 28)) { ++ DBG_ERROR ++ ("copy_from_user FAILED getting initial params\n"); ++ return -EFAULT; ++ } ++ intagg = data[0]; ++ printk(KERN_EMERG ++ "%s: set interrupt aggregation to %d\n", ++ __FUNCTION__, intagg); ++ return 0; ++ } ++ ++ default: ++// DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __FUNCTION__, cmd); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++#define NORMAL_ETHFRAME 0 ++ ++/* ++ * ++ * sxg_send_packets - Send a skb packet ++ * ++ * Arguments: ++ * skb - The packet to send ++ * dev - Our linux net device that refs our adapter ++ * ++ * Return: ++ * 0 regardless of outcome XXXTODO refer to e1000 driver ++ */ ++static int sxg_send_packets(struct sk_buff *skb, p_net_device dev) ++{ ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ u32 status = STATUS_SUCCESS; ++ ++ DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __FUNCTION__, ++ skb); ++ // Check the adapter state ++ switch (adapter->State) { ++ case SXG_STATE_INITIALIZING: ++ case SXG_STATE_HALTED: ++ case SXG_STATE_SHUTDOWN: ++ ASSERT(0); // unexpected ++ // fall through ++ case SXG_STATE_RESETTING: ++ case SXG_STATE_SLEEP: ++ case SXG_STATE_BOOTDIAG: ++ case SXG_STATE_DIAG: ++ case SXG_STATE_HALTING: ++ status = STATUS_FAILURE; ++ break; ++ case SXG_STATE_RUNNING: ++ if (adapter->LinkState != SXG_LINK_UP) { ++ status = STATUS_FAILURE; ++ } ++ break; ++ default: ++ ASSERT(0); ++ status = STATUS_FAILURE; ++ } ++ if (status != STATUS_SUCCESS) { ++ goto xmit_fail; ++ } ++ // send a packet ++ status = sxg_transmit_packet(adapter, skb); ++ if (status == STATUS_SUCCESS) { ++ goto xmit_done; ++ } ++ ++ xmit_fail: ++ // reject & complete all the packets if they cant be sent ++ if (status != STATUS_SUCCESS) { ++#if XXXTODO ++// sxg_send_packets_fail(adapter, skb, status); ++#else ++ SXG_DROP_DUMB_SEND(adapter, skb); ++ adapter->stats.tx_dropped++; ++#endif ++ } ++ DBG_ERROR("sxg: %s EXIT sxg_send_packets status[%x]\n", __FUNCTION__, ++ status); ++ ++ xmit_done: ++ return 0; ++} ++ ++/* ++ * sxg_transmit_packet ++ * ++ * This function transmits a single packet. ++ * ++ * Arguments - ++ * adapter - Pointer to our adapter structure ++ * skb - The packet to be sent ++ * ++ * Return - ++ * STATUS of send ++ */ ++static int sxg_transmit_packet(p_adapter_t adapter, struct sk_buff *skb) ++{ ++ PSCATTER_GATHER_LIST pSgl; ++ PSXG_SCATTER_GATHER SxgSgl; ++ void * SglBuffer; ++ u32 SglBufferLength; ++ ++ // The vast majority of work is done in the shared ++ // sxg_dumb_sgl routine. ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSend", ++ adapter, skb, 0, 0); ++ ++ // Allocate a SGL buffer ++ SXG_GET_SGL_BUFFER(adapter, SxgSgl); ++ if (!SxgSgl) { ++ adapter->Stats.NoSglBuf++; ++ adapter->Stats.XmtErrors++; ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "SndPktF1", ++ adapter, skb, 0, 0); ++ return (STATUS_RESOURCES); ++ } ++ ASSERT(SxgSgl->adapter == adapter); ++ SglBuffer = SXG_SGL_BUFFER(SxgSgl); ++ SglBufferLength = SXG_SGL_BUF_SIZE; ++ SxgSgl->VlanTag.VlanTci = 0; ++ SxgSgl->VlanTag.VlanTpid = 0; ++ SxgSgl->Type = SXG_SGL_DUMB; ++ SxgSgl->DumbPacket = skb; ++ pSgl = NULL; ++ ++ // Call the common sxg_dumb_sgl routine to complete the send. ++ sxg_dumb_sgl(pSgl, SxgSgl); ++ // Return success sxg_dumb_sgl (or something later) will complete it. ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_dumb_sgl ++ * ++ * Arguments: ++ * pSgl - ++ * SxgSgl - SXG_SCATTER_GATHER ++ * ++ * Return Value: ++ * None. ++ */ ++static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl) ++{ ++ p_adapter_t adapter = SxgSgl->adapter; ++ struct sk_buff *skb = SxgSgl->DumbPacket; ++ // For now, all dumb-nic sends go on RSS queue zero ++ PSXG_XMT_RING XmtRing = &adapter->XmtRings[0]; ++ PSXG_RING_INFO XmtRingInfo = &adapter->XmtRingZeroInfo; ++ PSXG_CMD XmtCmd = NULL; ++// u32 Index = 0; ++ u32 DataLength = skb->len; ++// unsigned int BufLen; ++// u32 SglOffset; ++ u64 phys_addr; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl", ++ pSgl, SxgSgl, 0, 0); ++ ++ // Set aside a pointer to the sgl ++ SxgSgl->pSgl = pSgl; ++ ++ // Sanity check that our SGL format is as we expect. ++ ASSERT(sizeof(SXG_X64_SGE) == sizeof(SCATTER_GATHER_ELEMENT)); ++ // Shouldn't be a vlan tag on this frame ++ ASSERT(SxgSgl->VlanTag.VlanTci == 0); ++ ASSERT(SxgSgl->VlanTag.VlanTpid == 0); ++ ++ // From here below we work with the SGL placed in our ++ // buffer. ++ ++ SxgSgl->Sgl.NumberOfElements = 1; ++ ++ // Grab the spinlock and acquire a command ++ spin_lock(&adapter->XmtZeroLock); ++ SXG_GET_CMD(XmtRing, XmtRingInfo, XmtCmd, SxgSgl); ++ if (XmtCmd == NULL) { ++ // Call sxg_complete_slow_send to see if we can ++ // free up any XmtRingZero entries and then try again ++ spin_unlock(&adapter->XmtZeroLock); ++ sxg_complete_slow_send(adapter); ++ spin_lock(&adapter->XmtZeroLock); ++ SXG_GET_CMD(XmtRing, XmtRingInfo, XmtCmd, SxgSgl); ++ if (XmtCmd == NULL) { ++ adapter->Stats.XmtZeroFull++; ++ goto abortcmd; ++ } ++ } ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd", ++ XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0); ++ // Update stats ++ adapter->Stats.DumbXmtPkts++; ++ adapter->Stats.DumbXmtBytes += DataLength; ++#if XXXTODO // Stats stuff ++ if (SXG_MULTICAST_PACKET(EtherHdr)) { ++ if (SXG_BROADCAST_PACKET(EtherHdr)) { ++ adapter->Stats.DumbXmtBcastPkts++; ++ adapter->Stats.DumbXmtBcastBytes += DataLength; ++ } else { ++ adapter->Stats.DumbXmtMcastPkts++; ++ adapter->Stats.DumbXmtMcastBytes += DataLength; ++ } ++ } else { ++ adapter->Stats.DumbXmtUcastPkts++; ++ adapter->Stats.DumbXmtUcastBytes += DataLength; ++ } ++#endif ++ // Fill in the command ++ // Copy out the first SGE to the command and adjust for offset ++ phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len, PCI_DMA_TODEVICE); ++ XmtCmd->Buffer.FirstSgeAddress = SXG_GET_ADDR_HIGH(phys_addr); ++ XmtCmd->Buffer.FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress << 32; ++ XmtCmd->Buffer.FirstSgeAddress = ++ XmtCmd->Buffer.FirstSgeAddress | SXG_GET_ADDR_LOW(phys_addr); ++// XmtCmd->Buffer.FirstSgeAddress = SxgSgl->Sgl.Elements[Index].Address; ++// XmtCmd->Buffer.FirstSgeAddress.LowPart += MdlOffset; ++ XmtCmd->Buffer.FirstSgeLength = DataLength; ++ // Set a pointer to the remaining SGL entries ++// XmtCmd->Sgl = SxgSgl->PhysicalAddress; ++ // Advance the physical address of the SxgSgl structure to ++ // the second SGE ++// SglOffset = (u32)((u32 *)(&SxgSgl->Sgl.Elements[Index+1]) - ++// (u32 *)SxgSgl); ++// XmtCmd->Sgl.LowPart += SglOffset; ++ XmtCmd->Buffer.SgeOffset = 0; ++ // Note - TotalLength might be overwritten with MSS below.. ++ XmtCmd->Buffer.TotalLength = DataLength; ++ XmtCmd->SgEntries = 1; //(ushort)(SxgSgl->Sgl.NumberOfElements - Index); ++ XmtCmd->Flags = 0; ++ // ++ // Advance transmit cmd descripter by 1. ++ // NOTE - See comments in SxgTcpOutput where we write ++ // to the XmtCmd register regarding CPU ID values and/or ++ // multiple commands. ++ // ++ // ++ WRITE_REG(adapter->UcodeRegs[0].XmtCmd, 1, TRUE); ++ // ++ // ++ adapter->Stats.XmtQLen++; // Stats within lock ++ spin_unlock(&adapter->XmtZeroLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2", ++ XmtCmd, pSgl, SxgSgl, 0); ++ return; ++ ++ abortcmd: ++ // NOTE - Only jump to this label AFTER grabbing the ++ // XmtZeroLock, and DO NOT DROP IT between the ++ // command allocation and the following abort. ++ if (XmtCmd) { ++ SXG_ABORT_CMD(XmtRingInfo); ++ } ++ spin_unlock(&adapter->XmtZeroLock); ++ ++// failsgl: ++ // Jump to this label if failure occurs before the ++ // XmtZeroLock is grabbed ++ adapter->Stats.XmtErrors++; ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumSGFal", ++ pSgl, SxgSgl, XmtRingInfo->Head, XmtRingInfo->Tail); ++ ++ SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket); // SxgSgl->DumbPacket is the skb ++} ++ ++/*************************************************************** ++ * Link management functions ++ ***************************************************************/ ++ ++/* ++ * sxg_initialize_link - Initialize the link stuff ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * status ++ */ ++static int sxg_initialize_link(p_adapter_t adapter) ++{ ++ PSXG_HW_REGS HwRegs = adapter->HwRegs; ++ u32 Value; ++ u32 ConfigData; ++ u32 MaxFrame; ++ int status; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "InitLink", ++ adapter, 0, 0, 0); ++ ++ // Reset PHY and XGXS module ++ WRITE_REG(HwRegs->LinkStatus, LS_SERDES_POWER_DOWN, TRUE); ++ ++ // Reset transmit configuration register ++ WRITE_REG(HwRegs->XmtConfig, XMT_CONFIG_RESET, TRUE); ++ ++ // Reset receive configuration register ++ WRITE_REG(HwRegs->RcvConfig, RCV_CONFIG_RESET, TRUE); ++ ++ // Reset all MAC modules ++ WRITE_REG(HwRegs->MacConfig0, AXGMAC_CFG0_SUB_RESET, TRUE); ++ ++ // Link address 0 ++ // XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f) ++ // is stored with the first nibble (0a) in the byte 0 ++ // of the Mac address. Possibly reverse? ++ Value = *(u32 *) adapter->MacAddr; ++ WRITE_REG(HwRegs->LinkAddress0Low, Value, TRUE); ++ // also write the MAC address to the MAC. Endian is reversed. ++ WRITE_REG(HwRegs->MacAddressLow, ntohl(Value), TRUE); ++ Value = (*(u16 *) & adapter->MacAddr[4] & 0x0000FFFF); ++ WRITE_REG(HwRegs->LinkAddress0High, Value | LINK_ADDRESS_ENABLE, TRUE); ++ // endian swap for the MAC (put high bytes in bits [31:16], swapped) ++ Value = ntohl(Value); ++ WRITE_REG(HwRegs->MacAddressHigh, Value, TRUE); ++ // Link address 1 ++ WRITE_REG(HwRegs->LinkAddress1Low, 0, TRUE); ++ WRITE_REG(HwRegs->LinkAddress1High, 0, TRUE); ++ // Link address 2 ++ WRITE_REG(HwRegs->LinkAddress2Low, 0, TRUE); ++ WRITE_REG(HwRegs->LinkAddress2High, 0, TRUE); ++ // Link address 3 ++ WRITE_REG(HwRegs->LinkAddress3Low, 0, TRUE); ++ WRITE_REG(HwRegs->LinkAddress3High, 0, TRUE); ++ ++ // Enable MAC modules ++ WRITE_REG(HwRegs->MacConfig0, 0, TRUE); ++ ++ // Configure MAC ++ WRITE_REG(HwRegs->MacConfig1, (AXGMAC_CFG1_XMT_PAUSE | // Allow sending of pause ++ AXGMAC_CFG1_XMT_EN | // Enable XMT ++ AXGMAC_CFG1_RCV_PAUSE | // Enable detection of pause ++ AXGMAC_CFG1_RCV_EN | // Enable receive ++ AXGMAC_CFG1_SHORT_ASSERT | // short frame detection ++ AXGMAC_CFG1_CHECK_LEN | // Verify frame length ++ AXGMAC_CFG1_GEN_FCS | // Generate FCS ++ AXGMAC_CFG1_PAD_64), // Pad frames to 64 bytes ++ TRUE); ++ ++ // Set AXGMAC max frame length if jumbo. Not needed for standard MTU ++ if (adapter->JumboEnabled) { ++ WRITE_REG(HwRegs->MacMaxFrameLen, AXGMAC_MAXFRAME_JUMBO, TRUE); ++ } ++ // AMIIM Configuration Register - ++ // The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion ++ // (bottom bits) of this register is used to determine the ++ // MDC frequency as specified in the A-XGMAC Design Document. ++ // This value must not be zero. The following value (62 or 0x3E) ++ // is based on our MAC transmit clock frequency (MTCLK) of 312.5 MHz. ++ // Given a maximum MDIO clock frequency of 2.5 MHz (see the PHY spec), ++ // we get: 312.5/(2*(X+1)) < 2.5 ==> X = 62. ++ // This value happens to be the default value for this register, ++ // so we really don't have to do this. ++ WRITE_REG(HwRegs->MacAmiimConfig, 0x0000003E, TRUE); ++ ++ // Power up and enable PHY and XAUI/XGXS/Serdes logic ++ WRITE_REG(HwRegs->LinkStatus, ++ (LS_PHY_CLR_RESET | ++ LS_XGXS_ENABLE | ++ LS_XGXS_CTL | LS_PHY_CLK_EN | LS_ATTN_ALARM), TRUE); ++ DBG_ERROR("After Power Up and enable PHY in sxg_initialize_link\n"); ++ ++ // Per information given by Aeluros, wait 100 ms after removing reset. ++ // It's not enough to wait for the self-clearing reset bit in reg 0 to clear. ++ mdelay(100); ++ ++ // Verify the PHY has come up by checking that the Reset bit has cleared. ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ PHY_PMA_CONTROL1, // PMA/PMD control register ++ &Value); ++ if (status != STATUS_SUCCESS) ++ return (STATUS_FAILURE); ++ if (Value & PMA_CONTROL1_RESET) // reset complete if bit is 0 ++ return (STATUS_FAILURE); ++ ++ // The SERDES should be initialized by now - confirm ++ READ_REG(HwRegs->LinkStatus, Value); ++ if (Value & LS_SERDES_DOWN) // verify SERDES is initialized ++ return (STATUS_FAILURE); ++ ++ // The XAUI link should also be up - confirm ++ if (!(Value & LS_XAUI_LINK_UP)) // verify XAUI link is up ++ return (STATUS_FAILURE); ++ ++ // Initialize the PHY ++ status = sxg_phy_init(adapter); ++ if (status != STATUS_SUCCESS) ++ return (STATUS_FAILURE); ++ ++ // Enable the Link Alarm ++ status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ LASI_CONTROL, // LASI control register ++ LASI_CTL_LS_ALARM_ENABLE); // enable link alarm bit ++ if (status != STATUS_SUCCESS) ++ return (STATUS_FAILURE); ++ ++ // XXXTODO - temporary - verify bit is set ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ LASI_CONTROL, // LASI control register ++ &Value); ++ if (status != STATUS_SUCCESS) ++ return (STATUS_FAILURE); ++ if (!(Value & LASI_CTL_LS_ALARM_ENABLE)) { ++ DBG_ERROR("Error! LASI Control Alarm Enable bit not set!\n"); ++ } ++ // Enable receive ++ MaxFrame = adapter->JumboEnabled ? JUMBOMAXFRAME : ETHERMAXFRAME; ++ ConfigData = (RCV_CONFIG_ENABLE | ++ RCV_CONFIG_ENPARSE | ++ RCV_CONFIG_RCVBAD | ++ RCV_CONFIG_RCVPAUSE | ++ RCV_CONFIG_TZIPV6 | ++ RCV_CONFIG_TZIPV4 | ++ RCV_CONFIG_HASH_16 | ++ RCV_CONFIG_SOCKET | RCV_CONFIG_BUFSIZE(MaxFrame)); ++ WRITE_REG(HwRegs->RcvConfig, ConfigData, TRUE); ++ ++ WRITE_REG(HwRegs->XmtConfig, XMT_CONFIG_ENABLE, TRUE); ++ ++ // Mark the link as down. We'll get a link event when it comes up. ++ sxg_link_state(adapter, SXG_LINK_DOWN); ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XInitLnk", ++ adapter, 0, 0, 0); ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_phy_init - Initialize the PHY ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * status ++ */ ++static int sxg_phy_init(p_adapter_t adapter) ++{ ++ u32 Value; ++ PPHY_UCODE p; ++ int status; ++ ++ DBG_ERROR("ENTER %s\n", __FUNCTION__); ++ ++ // Read a register to identify the PHY type ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ 0xC205, // PHY ID register (?) ++ &Value); // XXXTODO - add def ++ if (status != STATUS_SUCCESS) ++ return (STATUS_FAILURE); ++ ++ if (Value == 0x0012) { // 0x0012 == AEL2005C PHY(?) - XXXTODO - add def ++ DBG_ERROR ++ ("AEL2005C PHY detected. Downloading PHY microcode.\n"); ++ ++ // Initialize AEL2005C PHY and download PHY microcode ++ for (p = PhyUcode; p->Addr != 0xFFFF; p++) { ++ if (p->Addr == 0) { ++ // if address == 0, data == sleep time in ms ++ mdelay(p->Data); ++ } else { ++ // write the given data to the specified address ++ status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ p->Addr, // PHY address ++ p->Data); // PHY data ++ if (status != STATUS_SUCCESS) ++ return (STATUS_FAILURE); ++ } ++ } ++ } ++ DBG_ERROR("EXIT %s\n", __FUNCTION__); ++ ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_link_event - Process a link event notification from the card ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * None ++ */ ++static void sxg_link_event(p_adapter_t adapter) ++{ ++ PSXG_HW_REGS HwRegs = adapter->HwRegs; ++ SXG_LINK_STATE LinkState; ++ int status; ++ u32 Value; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "LinkEvnt", ++ adapter, 0, 0, 0); ++ DBG_ERROR("ENTER %s\n", __FUNCTION__); ++ ++ // Check the Link Status register. We should have a Link Alarm. ++ READ_REG(HwRegs->LinkStatus, Value); ++ if (Value & LS_LINK_ALARM) { ++ // We got a Link Status alarm. First, pause to let the ++ // link state settle (it can bounce a number of times) ++ mdelay(10); ++ ++ // Now clear the alarm by reading the LASI status register. ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ LASI_STATUS, // LASI status register ++ &Value); ++ if (status != STATUS_SUCCESS) { ++ DBG_ERROR("Error reading LASI Status MDIO register!\n"); ++ sxg_link_state(adapter, SXG_LINK_DOWN); ++// ASSERT(0); ++ } ++ ASSERT(Value & LASI_STATUS_LS_ALARM); ++ ++ // Now get and set the link state ++ LinkState = sxg_get_link_state(adapter); ++ sxg_link_state(adapter, LinkState); ++ DBG_ERROR("SXG: Link Alarm occurred. Link is %s\n", ++ ((LinkState == SXG_LINK_UP) ? "UP" : "DOWN")); ++ } else { ++ // XXXTODO - Assuming Link Attention is only being generated for the ++ // Link Alarm pin (and not for a XAUI Link Status change), then it's ++ // impossible to get here. Yet we've gotten here twice (under extreme ++ // conditions - bouncing the link up and down many times a second). ++ // Needs further investigation. ++ DBG_ERROR("SXG: sxg_link_event: Can't get here!\n"); ++ DBG_ERROR("SXG: Link Status == 0x%08X.\n", Value); ++// ASSERT(0); ++ } ++ DBG_ERROR("EXIT %s\n", __FUNCTION__); ++ ++} ++ ++/* ++ * sxg_get_link_state - Determine if the link is up or down ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * Link State ++ */ ++static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter) ++{ ++ int status; ++ u32 Value; ++ ++ DBG_ERROR("ENTER %s\n", __FUNCTION__); ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "GetLink", ++ adapter, 0, 0, 0); ++ ++ // Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if ++ // the following 3 bits (from 3 different MDIO registers) are all true. ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, // PHY PMA/PMD module ++ PHY_PMA_RCV_DET, // PMA/PMD Receive Signal Detect register ++ &Value); ++ if (status != STATUS_SUCCESS) ++ goto bad; ++ ++ // If PMA/PMD receive signal detect is 0, then the link is down ++ if (!(Value & PMA_RCV_DETECT)) ++ return (SXG_LINK_DOWN); ++ ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS, // PHY PCS module ++ PHY_PCS_10G_STATUS1, // PCS 10GBASE-R Status 1 register ++ &Value); ++ if (status != STATUS_SUCCESS) ++ goto bad; ++ ++ // If PCS is not locked to receive blocks, then the link is down ++ if (!(Value & PCS_10B_BLOCK_LOCK)) ++ return (SXG_LINK_DOWN); ++ ++ status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS, // PHY XS module ++ PHY_XS_LANE_STATUS, // XS Lane Status register ++ &Value); ++ if (status != STATUS_SUCCESS) ++ goto bad; ++ ++ // If XS transmit lanes are not aligned, then the link is down ++ if (!(Value & XS_LANE_ALIGN)) ++ return (SXG_LINK_DOWN); ++ ++ // All 3 bits are true, so the link is up ++ DBG_ERROR("EXIT %s\n", __FUNCTION__); ++ ++ return (SXG_LINK_UP); ++ ++ bad: ++ // An error occurred reading an MDIO register. This shouldn't happen. ++ DBG_ERROR("Error reading an MDIO register!\n"); ++ ASSERT(0); ++ return (SXG_LINK_DOWN); ++} ++ ++static void sxg_indicate_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState) ++{ ++ if (adapter->LinkState == SXG_LINK_UP) { ++ DBG_ERROR("%s: LINK now UP, call netif_start_queue\n", ++ __FUNCTION__); ++ netif_start_queue(adapter->netdev); ++ } else { ++ DBG_ERROR("%s: LINK now DOWN, call netif_stop_queue\n", ++ __FUNCTION__); ++ netif_stop_queue(adapter->netdev); ++ } ++} ++ ++/* ++ * sxg_link_state - Set the link state and if necessary, indicate. ++ * This routine the central point of processing for all link state changes. ++ * Nothing else in the driver should alter the link state or perform ++ * link state indications ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * LinkState - The link state ++ * ++ * Return ++ * None ++ */ ++static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState) ++{ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "LnkINDCT", ++ adapter, LinkState, adapter->LinkState, adapter->State); ++ ++ DBG_ERROR("ENTER %s\n", __FUNCTION__); ++ ++ // Hold the adapter lock during this routine. Maybe move ++ // the lock to the caller. ++ spin_lock(&adapter->AdapterLock); ++ if (LinkState == adapter->LinkState) { ++ // Nothing changed.. ++ spin_unlock(&adapter->AdapterLock); ++ DBG_ERROR("EXIT #0 %s\n", __FUNCTION__); ++ return; ++ } ++ // Save the adapter state ++ adapter->LinkState = LinkState; ++ ++ // Drop the lock and indicate link state ++ spin_unlock(&adapter->AdapterLock); ++ DBG_ERROR("EXIT #1 %s\n", __FUNCTION__); ++ ++ sxg_indicate_link_state(adapter, LinkState); ++} ++ ++/* ++ * sxg_write_mdio_reg - Write to a register on the MDIO bus ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * DevAddr - MDIO device number being addressed ++ * RegAddr - register address for the specified MDIO device ++ * Value - value to write to the MDIO register ++ * ++ * Return ++ * status ++ */ ++static int sxg_write_mdio_reg(p_adapter_t adapter, ++ u32 DevAddr, u32 RegAddr, u32 Value) ++{ ++ PSXG_HW_REGS HwRegs = adapter->HwRegs; ++ u32 AddrOp; // Address operation (written to MIIM field reg) ++ u32 WriteOp; // Write operation (written to MIIM field reg) ++ u32 Cmd; // Command (written to MIIM command reg) ++ u32 ValueRead; ++ u32 Timeout; ++ ++// DBG_ERROR("ENTER %s\n", __FUNCTION__); ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO", ++ adapter, 0, 0, 0); ++ ++ // Ensure values don't exceed field width ++ DevAddr &= 0x001F; // 5-bit field ++ RegAddr &= 0xFFFF; // 16-bit field ++ Value &= 0xFFFF; // 16-bit field ++ ++ // Set MIIM field register bits for an MIIM address operation ++ AddrOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) | ++ (DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) | ++ (MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) | ++ (MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT) | RegAddr; ++ ++ // Set MIIM field register bits for an MIIM write operation ++ WriteOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) | ++ (DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) | ++ (MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) | ++ (MIIM_OP_WRITE << AXGMAC_AMIIM_FIELD_OP_SHIFT) | Value; ++ ++ // Set MIIM command register bits to execute an MIIM command ++ Cmd = AXGMAC_AMIIM_CMD_START | AXGMAC_AMIIM_CMD_10G_OPERATION; ++ ++ // Reset the command register command bit (in case it's not 0) ++ WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE); ++ ++ // MIIM write to set the address of the specified MDIO register ++ WRITE_REG(HwRegs->MacAmiimField, AddrOp, TRUE); ++ ++ // Write to MIIM Command Register to execute to address operation ++ WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE); ++ ++ // Poll AMIIM Indicator register to wait for completion ++ Timeout = SXG_LINK_TIMEOUT; ++ do { ++ udelay(100); // Timeout in 100us units ++ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); ++ if (--Timeout == 0) { ++ return (STATUS_FAILURE); ++ } ++ } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); ++ ++ // Reset the command register command bit ++ WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE); ++ ++ // MIIM write to set up an MDIO write operation ++ WRITE_REG(HwRegs->MacAmiimField, WriteOp, TRUE); ++ ++ // Write to MIIM Command Register to execute the write operation ++ WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE); ++ ++ // Poll AMIIM Indicator register to wait for completion ++ Timeout = SXG_LINK_TIMEOUT; ++ do { ++ udelay(100); // Timeout in 100us units ++ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); ++ if (--Timeout == 0) { ++ return (STATUS_FAILURE); ++ } ++ } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); ++ ++// DBG_ERROR("EXIT %s\n", __FUNCTION__); ++ ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_read_mdio_reg - Read a register on the MDIO bus ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * DevAddr - MDIO device number being addressed ++ * RegAddr - register address for the specified MDIO device ++ * pValue - pointer to where to put data read from the MDIO register ++ * ++ * Return ++ * status ++ */ ++static int sxg_read_mdio_reg(p_adapter_t adapter, ++ u32 DevAddr, u32 RegAddr, u32 * pValue) ++{ ++ PSXG_HW_REGS HwRegs = adapter->HwRegs; ++ u32 AddrOp; // Address operation (written to MIIM field reg) ++ u32 ReadOp; // Read operation (written to MIIM field reg) ++ u32 Cmd; // Command (written to MIIM command reg) ++ u32 ValueRead; ++ u32 Timeout; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO", ++ adapter, 0, 0, 0); ++// DBG_ERROR("ENTER %s\n", __FUNCTION__); ++ ++ // Ensure values don't exceed field width ++ DevAddr &= 0x001F; // 5-bit field ++ RegAddr &= 0xFFFF; // 16-bit field ++ ++ // Set MIIM field register bits for an MIIM address operation ++ AddrOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) | ++ (DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) | ++ (MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) | ++ (MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT) | RegAddr; ++ ++ // Set MIIM field register bits for an MIIM read operation ++ ReadOp = (MIIM_PORT_NUM << AXGMAC_AMIIM_FIELD_PORT_SHIFT) | ++ (DevAddr << AXGMAC_AMIIM_FIELD_DEV_SHIFT) | ++ (MIIM_TA_10GB << AXGMAC_AMIIM_FIELD_TA_SHIFT) | ++ (MIIM_OP_READ << AXGMAC_AMIIM_FIELD_OP_SHIFT); ++ ++ // Set MIIM command register bits to execute an MIIM command ++ Cmd = AXGMAC_AMIIM_CMD_START | AXGMAC_AMIIM_CMD_10G_OPERATION; ++ ++ // Reset the command register command bit (in case it's not 0) ++ WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE); ++ ++ // MIIM write to set the address of the specified MDIO register ++ WRITE_REG(HwRegs->MacAmiimField, AddrOp, TRUE); ++ ++ // Write to MIIM Command Register to execute to address operation ++ WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE); ++ ++ // Poll AMIIM Indicator register to wait for completion ++ Timeout = SXG_LINK_TIMEOUT; ++ do { ++ udelay(100); // Timeout in 100us units ++ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); ++ if (--Timeout == 0) { ++ return (STATUS_FAILURE); ++ } ++ } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); ++ ++ // Reset the command register command bit ++ WRITE_REG(HwRegs->MacAmiimCmd, 0, TRUE); ++ ++ // MIIM write to set up an MDIO register read operation ++ WRITE_REG(HwRegs->MacAmiimField, ReadOp, TRUE); ++ ++ // Write to MIIM Command Register to execute the read operation ++ WRITE_REG(HwRegs->MacAmiimCmd, Cmd, TRUE); ++ ++ // Poll AMIIM Indicator register to wait for completion ++ Timeout = SXG_LINK_TIMEOUT; ++ do { ++ udelay(100); // Timeout in 100us units ++ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); ++ if (--Timeout == 0) { ++ return (STATUS_FAILURE); ++ } ++ } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); ++ ++ // Read the MDIO register data back from the field register ++ READ_REG(HwRegs->MacAmiimField, *pValue); ++ *pValue &= 0xFFFF; // data is in the lower 16 bits ++ ++// DBG_ERROR("EXIT %s\n", __FUNCTION__); ++ ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * Allocate a mcast_address structure to hold the multicast address. ++ * Link it in. ++ */ ++static int sxg_mcast_add_list(p_adapter_t adapter, char *address) ++{ ++ p_mcast_address_t mcaddr, mlist; ++ bool equaladdr; ++ ++ /* Check to see if it already exists */ ++ mlist = adapter->mcastaddrs; ++ while (mlist) { ++ ETHER_EQ_ADDR(mlist->address, address, equaladdr); ++ if (equaladdr) { ++ return (STATUS_SUCCESS); ++ } ++ mlist = mlist->next; ++ } ++ ++ /* Doesn't already exist. Allocate a structure to hold it */ ++ mcaddr = kmalloc(sizeof(mcast_address_t), GFP_ATOMIC); ++ if (mcaddr == NULL) ++ return 1; ++ ++ memcpy(mcaddr->address, address, 6); ++ ++ mcaddr->next = adapter->mcastaddrs; ++ adapter->mcastaddrs = mcaddr; ++ ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * Functions to obtain the CRC corresponding to the destination mac address. ++ * This is a standard ethernet CRC in that it is a 32-bit, reflected CRC using ++ * the polynomial: ++ * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1. ++ * ++ * After the CRC for the 6 bytes is generated (but before the value is complemented), ++ * we must then transpose the value and return bits 30-23. ++ * ++ */ ++static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */ ++static u32 sxg_crc_init; /* Is table initialized */ ++ ++/* ++ * Contruct the CRC32 table ++ */ ++static void sxg_mcast_init_crc32(void) ++{ ++ u32 c; /* CRC shit reg */ ++ u32 e = 0; /* Poly X-or pattern */ ++ int i; /* counter */ ++ int k; /* byte being shifted into crc */ ++ ++ static int p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 }; ++ ++ for (i = 0; i < sizeof(p) / sizeof(int); i++) { ++ e |= 1L << (31 - p[i]); ++ } ++ ++ for (i = 1; i < 256; i++) { ++ c = i; ++ for (k = 8; k; k--) { ++ c = c & 1 ? (c >> 1) ^ e : c >> 1; ++ } ++ sxg_crc_table[i] = c; ++ } ++} ++ ++/* ++ * Return the MAC hast as described above. ++ */ ++static unsigned char sxg_mcast_get_mac_hash(char *macaddr) ++{ ++ u32 crc; ++ char *p; ++ int i; ++ unsigned char machash = 0; ++ ++ if (!sxg_crc_init) { ++ sxg_mcast_init_crc32(); ++ sxg_crc_init = 1; ++ } ++ ++ crc = 0xFFFFFFFF; /* Preload shift register, per crc-32 spec */ ++ for (i = 0, p = macaddr; i < 6; ++p, ++i) { ++ crc = (crc >> 8) ^ sxg_crc_table[(crc ^ *p) & 0xFF]; ++ } ++ ++ /* Return bits 1-8, transposed */ ++ for (i = 1; i < 9; i++) { ++ machash |= (((crc >> i) & 1) << (8 - i)); ++ } ++ ++ return (machash); ++} ++ ++static void sxg_mcast_set_bit(p_adapter_t adapter, char *address) ++{ ++ unsigned char crcpoly; ++ ++ /* Get the CRC polynomial for the mac address */ ++ crcpoly = sxg_mcast_get_mac_hash(address); ++ ++ /* We only have space on the SLIC for 64 entries. Lop ++ * off the top two bits. (2^6 = 64) ++ */ ++ crcpoly &= 0x3F; ++ ++ /* OR in the new bit into our 64 bit mask. */ ++ adapter->MulticastMask |= (u64) 1 << crcpoly; ++} ++ ++static void sxg_mcast_set_list(p_net_device dev) ++{ ++#if XXXTODO ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ int status = STATUS_SUCCESS; ++ int i; ++ char *addresses; ++ struct dev_mc_list *mc_list = dev->mc_list; ++ int mc_count = dev->mc_count; ++ ++ ASSERT(adapter); ++ ++ for (i = 1; i <= mc_count; i++) { ++ addresses = (char *) & mc_list->dmi_addr; ++ if (mc_list->dmi_addrlen == 6) { ++ status = sxg_mcast_add_list(adapter, addresses); ++ if (status != STATUS_SUCCESS) { ++ break; ++ } ++ } else { ++ status = -EINVAL; ++ break; ++ } ++ sxg_mcast_set_bit(adapter, addresses); ++ mc_list = mc_list->next; ++ } ++ ++ DBG_ERROR("%s a->devflags_prev[%x] dev->flags[%x] status[%x]\n", ++ __FUNCTION__, adapter->devflags_prev, dev->flags, status); ++ if (adapter->devflags_prev != dev->flags) { ++ adapter->macopts = MAC_DIRECTED; ++ if (dev->flags) { ++ if (dev->flags & IFF_BROADCAST) { ++ adapter->macopts |= MAC_BCAST; ++ } ++ if (dev->flags & IFF_PROMISC) { ++ adapter->macopts |= MAC_PROMISC; ++ } ++ if (dev->flags & IFF_ALLMULTI) { ++ adapter->macopts |= MAC_ALLMCAST; ++ } ++ if (dev->flags & IFF_MULTICAST) { ++ adapter->macopts |= MAC_MCAST; ++ } ++ } ++ adapter->devflags_prev = dev->flags; ++ DBG_ERROR("%s call sxg_config_set adapter->macopts[%x]\n", ++ __FUNCTION__, adapter->macopts); ++ sxg_config_set(adapter, TRUE); ++ } else { ++ if (status == STATUS_SUCCESS) { ++ sxg_mcast_set_mask(adapter); ++ } ++ } ++#endif ++ return; ++} ++ ++static void sxg_mcast_set_mask(p_adapter_t adapter) ++{ ++ PSXG_UCODE_REGS sxg_regs = adapter->UcodeRegs; ++ ++ DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __FUNCTION__, ++ adapter->netdev->name, (unsigned int) adapter->MacFilter, ++ adapter->MulticastMask); ++ ++ if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) { ++ /* Turn on all multicast addresses. We have to do this for promiscuous ++ * mode as well as ALLMCAST mode. It saves the Microcode from having ++ * to keep state about the MAC configuration. ++ */ ++// DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n SLUT MODE!!!\n",__FUNCTION__); ++ WRITE_REG(sxg_regs->McastLow, 0xFFFFFFFF, FLUSH); ++ WRITE_REG(sxg_regs->McastHigh, 0xFFFFFFFF, FLUSH); ++// DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high 0xFFFFFFFF\n",__FUNCTION__, adapter->netdev->name); ++ ++ } else { ++ /* Commit our multicast mast to the SLIC by writing to the multicast ++ * address mask registers ++ */ ++ DBG_ERROR("%s (%s) WRITE mcastlow[%lx] mcasthigh[%lx]\n", ++ __FUNCTION__, adapter->netdev->name, ++ ((ulong) (adapter->MulticastMask & 0xFFFFFFFF)), ++ ((ulong) ++ ((adapter->MulticastMask >> 32) & 0xFFFFFFFF))); ++ ++ WRITE_REG(sxg_regs->McastLow, ++ (u32) (adapter->MulticastMask & 0xFFFFFFFF), ++ FLUSH); ++ WRITE_REG(sxg_regs->McastHigh, ++ (u32) ((adapter-> ++ MulticastMask >> 32) & 0xFFFFFFFF), ++ FLUSH); ++ } ++} ++ ++static void sxg_unmap_mmio_space(p_adapter_t adapter) ++{ ++#if LINUX_FREES_ADAPTER_RESOURCES ++// if (adapter->Regs) { ++// iounmap(adapter->Regs); ++// } ++// adapter->slic_regs = NULL; ++#endif ++} ++ ++#if XXXTODO ++/* ++ * SxgFreeResources - Free everything allocated in SxgAllocateResources ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * none ++ */ ++void SxgFreeResources(p_adapter_t adapter) ++{ ++ u32 RssIds, IsrCount; ++ PTCP_OBJECT TcpObject; ++ u32 i; ++ BOOLEAN TimerCancelled; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FreeRes", ++ adapter, adapter->MaxTcbs, 0, 0); ++ ++ RssIds = SXG_RSS_CPU_COUNT(adapter); ++ IsrCount = adapter->MsiEnabled ? RssIds : 1; ++ ++ if (adapter->BasicAllocations == FALSE) { ++ // No allocations have been made, including spinlocks, ++ // or listhead initializations. Return. ++ return; ++ } ++ ++ if (!(IsListEmpty(&adapter->AllRcvBlocks))) { ++ SxgFreeRcvBlocks(adapter); ++ } ++ if (!(IsListEmpty(&adapter->AllSglBuffers))) { ++ SxgFreeSglBuffers(adapter); ++ } ++ // Free event queues. ++ if (adapter->EventRings) { ++ pci_free_consistent(adapter->pcidev, ++ sizeof(SXG_EVENT_RING) * RssIds, ++ adapter->EventRings, adapter->PEventRings); ++ } ++ if (adapter->Isr) { ++ pci_free_consistent(adapter->pcidev, ++ sizeof(u32) * IsrCount, ++ adapter->Isr, adapter->PIsr); ++ } ++ if (adapter->XmtRingZeroIndex) { ++ pci_free_consistent(adapter->pcidev, ++ sizeof(u32), ++ adapter->XmtRingZeroIndex, ++ adapter->PXmtRingZeroIndex); ++ } ++ if (adapter->IndirectionTable) { ++ pci_free_consistent(adapter->pcidev, ++ SXG_MAX_RSS_TABLE_SIZE, ++ adapter->IndirectionTable, ++ adapter->PIndirectionTable); ++ } ++ ++ SXG_FREE_PACKET_POOL(adapter->PacketPoolHandle); ++ SXG_FREE_BUFFER_POOL(adapter->BufferPoolHandle); ++ ++ // Unmap register spaces ++ SxgUnmapResources(adapter); ++ ++ // Deregister DMA ++ if (adapter->DmaHandle) { ++ SXG_DEREGISTER_DMA(adapter->DmaHandle); ++ } ++ // Deregister interrupt ++ SxgDeregisterInterrupt(adapter); ++ ++ // Possibly free system info (5.2 only) ++ SXG_RELEASE_SYSTEM_INFO(adapter); ++ ++ SxgDiagFreeResources(adapter); ++ ++ SxgFreeMCastAddrs(adapter); ++ ++ if (SXG_TIMER_ALLOCATED(adapter->ResetTimer)) { ++ SXG_CANCEL_TIMER(adapter->ResetTimer, TimerCancelled); ++ SXG_FREE_TIMER(adapter->ResetTimer); ++ } ++ if (SXG_TIMER_ALLOCATED(adapter->RssTimer)) { ++ SXG_CANCEL_TIMER(adapter->RssTimer, TimerCancelled); ++ SXG_FREE_TIMER(adapter->RssTimer); ++ } ++ if (SXG_TIMER_ALLOCATED(adapter->OffloadTimer)) { ++ SXG_CANCEL_TIMER(adapter->OffloadTimer, TimerCancelled); ++ SXG_FREE_TIMER(adapter->OffloadTimer); ++ } ++ ++ adapter->BasicAllocations = FALSE; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFreeRes", ++ adapter, adapter->MaxTcbs, 0, 0); ++} ++#endif ++ ++/* ++ * sxg_allocate_complete - ++ * ++ * This routine is called when a memory allocation has completed. ++ * ++ * Arguments - ++ * p_adapter_t - Our adapter structure ++ * VirtualAddress - Memory virtual address ++ * PhysicalAddress - Memory physical address ++ * Length - Length of memory allocated (or 0) ++ * Context - The type of buffer allocated ++ * ++ * Return ++ * None. ++ */ ++static void sxg_allocate_complete(p_adapter_t adapter, ++ void *VirtualAddress, ++ dma_addr_t PhysicalAddress, ++ u32 Length, SXG_BUFFER_TYPE Context) ++{ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocCmp", ++ adapter, VirtualAddress, Length, Context); ++ ASSERT(adapter->AllocationsPending); ++ --adapter->AllocationsPending; ++ ++ switch (Context) { ++ ++ case SXG_BUFFER_TYPE_RCV: ++ sxg_allocate_rcvblock_complete(adapter, ++ VirtualAddress, ++ PhysicalAddress, Length); ++ break; ++ case SXG_BUFFER_TYPE_SGL: ++ sxg_allocate_sgl_buffer_complete(adapter, ++ (PSXG_SCATTER_GATHER) ++ VirtualAddress, ++ PhysicalAddress, Length); ++ break; ++ } ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlocCmp", ++ adapter, VirtualAddress, Length, Context); ++} ++ ++/* ++ * sxg_allocate_buffer_memory - Shared memory allocation routine used for ++ * synchronous and asynchronous buffer allocations ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * Size - block size to allocate ++ * BufferType - Type of buffer to allocate ++ * ++ * Return ++ * int ++ */ ++static int sxg_allocate_buffer_memory(p_adapter_t adapter, ++ u32 Size, SXG_BUFFER_TYPE BufferType) ++{ ++ int status; ++ void * Buffer; ++ dma_addr_t pBuffer; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocMem", ++ adapter, Size, BufferType, 0); ++ // Grab the adapter lock and check the state. ++ // If we're in anything other than INITIALIZING or ++ // RUNNING state, fail. This is to prevent ++ // allocations in an improper driver state ++ spin_lock(&adapter->AdapterLock); ++ ++ // Increment the AllocationsPending count while holding ++ // the lock. Pause processing relies on this ++ ++adapter->AllocationsPending; ++ spin_unlock(&adapter->AdapterLock); ++ ++ // At initialization time allocate resources synchronously. ++ Buffer = pci_alloc_consistent(adapter->pcidev, Size, &pBuffer); ++ if (Buffer == NULL) { ++ spin_lock(&adapter->AdapterLock); ++ // Decrement the AllocationsPending count while holding ++ // the lock. Pause processing relies on this ++ --adapter->AllocationsPending; ++ spin_unlock(&adapter->AdapterLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlcMemF1", ++ adapter, Size, BufferType, 0); ++ return (STATUS_RESOURCES); ++ } ++ sxg_allocate_complete(adapter, Buffer, pBuffer, Size, BufferType); ++ status = STATUS_SUCCESS; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlocMem", ++ adapter, Size, BufferType, status); ++ return (status); ++} ++ ++/* ++ * sxg_allocate_rcvblock_complete - Complete a receive descriptor block allocation ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * RcvBlock - receive block virtual address ++ * PhysicalAddress - Physical address ++ * Length - Memory length ++ * ++ * Return ++ * ++ */ ++static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, ++ void * RcvBlock, ++ dma_addr_t PhysicalAddress, u32 Length) ++{ ++ u32 i; ++ u32 BufferSize = adapter->ReceiveBufferSize; ++ u64 Paddr; ++ PSXG_RCV_BLOCK_HDR RcvBlockHdr; ++ unsigned char *RcvDataBuffer; ++ PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr; ++ PSXG_RCV_DESCRIPTOR_BLOCK RcvDescriptorBlock; ++ PSXG_RCV_DESCRIPTOR_BLOCK_HDR RcvDescriptorBlockHdr; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlRcvBlk", ++ adapter, RcvBlock, Length, 0); ++ if (RcvBlock == NULL) { ++ goto fail; ++ } ++ memset(RcvBlock, 0, Length); ++ ASSERT((BufferSize == SXG_RCV_DATA_BUFFER_SIZE) || ++ (BufferSize == SXG_RCV_JUMBO_BUFFER_SIZE)); ++ ASSERT(Length == SXG_RCV_BLOCK_SIZE(BufferSize)); ++ // First, initialize the contained pool of receive data ++ // buffers. This initialization requires NBL/NB/MDL allocations, ++ // If any of them fail, free the block and return without ++ // queueing the shared memory ++ RcvDataBuffer = RcvBlock; ++#if 0 ++ for (i = 0, Paddr = *PhysicalAddress; ++ i < SXG_RCV_DESCRIPTORS_PER_BLOCK; ++ i++, Paddr.LowPart += BufferSize, RcvDataBuffer += BufferSize) ++#endif ++ for (i = 0, Paddr = PhysicalAddress; ++ i < SXG_RCV_DESCRIPTORS_PER_BLOCK; ++ i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) { ++ // ++ RcvDataBufferHdr = ++ (PSXG_RCV_DATA_BUFFER_HDR) (RcvDataBuffer + ++ SXG_RCV_DATA_BUFFER_HDR_OFFSET ++ (BufferSize)); ++ RcvDataBufferHdr->VirtualAddress = RcvDataBuffer; ++ RcvDataBufferHdr->PhysicalAddress = Paddr; ++ RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; // For FREE macro assertion ++ RcvDataBufferHdr->Size = ++ SXG_RCV_BUFFER_DATA_SIZE(BufferSize); ++ ++ SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr); ++ if (RcvDataBufferHdr->SxgDumbRcvPacket == NULL) ++ goto fail; ++ ++ } ++ ++ // Place this entire block of memory on the AllRcvBlocks queue so it can be ++ // free later ++ RcvBlockHdr = ++ (PSXG_RCV_BLOCK_HDR) ((unsigned char *)RcvBlock + ++ SXG_RCV_BLOCK_HDR_OFFSET(BufferSize)); ++ RcvBlockHdr->VirtualAddress = RcvBlock; ++ RcvBlockHdr->PhysicalAddress = PhysicalAddress; ++ spin_lock(&adapter->RcvQLock); ++ adapter->AllRcvBlockCount++; ++ InsertTailList(&adapter->AllRcvBlocks, &RcvBlockHdr->AllList); ++ spin_unlock(&adapter->RcvQLock); ++ ++ // Now free the contained receive data buffers that we initialized above ++ RcvDataBuffer = RcvBlock; ++ for (i = 0, Paddr = PhysicalAddress; ++ i < SXG_RCV_DESCRIPTORS_PER_BLOCK; ++ i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) { ++ RcvDataBufferHdr = (PSXG_RCV_DATA_BUFFER_HDR) (RcvDataBuffer + ++ SXG_RCV_DATA_BUFFER_HDR_OFFSET ++ (BufferSize)); ++ spin_lock(&adapter->RcvQLock); ++ SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); ++ spin_unlock(&adapter->RcvQLock); ++ } ++ ++ // Locate the descriptor block and put it on a separate free queue ++ RcvDescriptorBlock = (PSXG_RCV_DESCRIPTOR_BLOCK) ((unsigned char *)RcvBlock + ++ SXG_RCV_DESCRIPTOR_BLOCK_OFFSET ++ (BufferSize)); ++ RcvDescriptorBlockHdr = ++ (PSXG_RCV_DESCRIPTOR_BLOCK_HDR) ((unsigned char *)RcvBlock + ++ SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET ++ (BufferSize)); ++ RcvDescriptorBlockHdr->VirtualAddress = RcvDescriptorBlock; ++ RcvDescriptorBlockHdr->PhysicalAddress = Paddr; ++ spin_lock(&adapter->RcvQLock); ++ SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter, RcvDescriptorBlockHdr); ++ spin_unlock(&adapter->RcvQLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlRBlk", ++ adapter, RcvBlock, Length, 0); ++ return; ++ fail: ++ // Free any allocated resources ++ if (RcvBlock) { ++ RcvDataBuffer = RcvBlock; ++ for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; ++ i++, RcvDataBuffer += BufferSize) { ++ RcvDataBufferHdr = ++ (PSXG_RCV_DATA_BUFFER_HDR) (RcvDataBuffer + ++ SXG_RCV_DATA_BUFFER_HDR_OFFSET ++ (BufferSize)); ++ SXG_FREE_RCV_PACKET(RcvDataBufferHdr); ++ } ++ pci_free_consistent(adapter->pcidev, ++ Length, RcvBlock, PhysicalAddress); ++ } ++ DBG_ERROR("%s: OUT OF RESOURCES\n", __FUNCTION__); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "RcvAFail", ++ adapter, adapter->FreeRcvBufferCount, ++ adapter->FreeRcvBlockCount, adapter->AllRcvBlockCount); ++ adapter->Stats.NoMem++; ++} ++ ++/* ++ * sxg_allocate_sgl_buffer_complete - Complete a SGL buffer allocation ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * SxgSgl - SXG_SCATTER_GATHER buffer ++ * PhysicalAddress - Physical address ++ * Length - Memory length ++ * ++ * Return ++ * ++ */ ++static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, ++ PSXG_SCATTER_GATHER SxgSgl, ++ dma_addr_t PhysicalAddress, u32 Length) ++{ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlSglCmp", ++ adapter, SxgSgl, Length, 0); ++ spin_lock(&adapter->SglQLock); ++ adapter->AllSglBufferCount++; ++ memset(SxgSgl, 0, sizeof(SXG_SCATTER_GATHER)); ++ SxgSgl->PhysicalAddress = PhysicalAddress; /* *PhysicalAddress; */ ++ SxgSgl->adapter = adapter; // Initialize backpointer once ++ InsertTailList(&adapter->AllSglBuffers, &SxgSgl->AllList); ++ spin_unlock(&adapter->SglQLock); ++ SxgSgl->State = SXG_BUFFER_BUSY; ++ SXG_FREE_SGL_BUFFER(adapter, SxgSgl, NULL); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlSgl", ++ adapter, SxgSgl, Length, 0); ++} ++ ++static unsigned char temp_mac_address[6] = { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 }; ++ ++static void sxg_adapter_set_hwaddr(p_adapter_t adapter) ++{ ++// DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", __FUNCTION__, ++// card->config_set, adapter->port, adapter->physport, adapter->functionnumber); ++// ++// sxg_dbg_macaddrs(adapter); ++ ++ memcpy(adapter->macaddr, temp_mac_address, sizeof(SXG_CONFIG_MAC)); ++// DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", __FUNCTION__); ++// sxg_dbg_macaddrs(adapter); ++ if (!(adapter->currmacaddr[0] || ++ adapter->currmacaddr[1] || ++ adapter->currmacaddr[2] || ++ adapter->currmacaddr[3] || ++ adapter->currmacaddr[4] || adapter->currmacaddr[5])) { ++ memcpy(adapter->currmacaddr, adapter->macaddr, 6); ++ } ++ if (adapter->netdev) { ++ memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, 6); ++ } ++// DBG_ERROR ("%s EXIT port %d\n", __FUNCTION__, adapter->port); ++ sxg_dbg_macaddrs(adapter); ++ ++} ++ ++static int sxg_mac_set_address(p_net_device dev, void * ptr) ++{ ++#if XXXTODO ++ p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct sockaddr *addr = ptr; ++ ++ DBG_ERROR("%s ENTER (%s)\n", __FUNCTION__, adapter->netdev->name); ++ ++ if (netif_running(dev)) { ++ return -EBUSY; ++ } ++ if (!adapter) { ++ return -EBUSY; ++ } ++ DBG_ERROR("sxg: %s (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ __FUNCTION__, adapter->netdev->name, adapter->currmacaddr[0], ++ adapter->currmacaddr[1], adapter->currmacaddr[2], ++ adapter->currmacaddr[3], adapter->currmacaddr[4], ++ adapter->currmacaddr[5]); ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ memcpy(adapter->currmacaddr, addr->sa_data, dev->addr_len); ++ DBG_ERROR("sxg: %s (%s) new %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", ++ __FUNCTION__, adapter->netdev->name, adapter->currmacaddr[0], ++ adapter->currmacaddr[1], adapter->currmacaddr[2], ++ adapter->currmacaddr[3], adapter->currmacaddr[4], ++ adapter->currmacaddr[5]); ++ ++ sxg_config_set(adapter, TRUE); ++#endif ++ return 0; ++} ++ ++/*****************************************************************************/ ++/************* SXG DRIVER FUNCTIONS (below) ********************************/ ++/*****************************************************************************/ ++ ++/* ++ * sxg_initialize_adapter - Initialize adapter ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * int ++ */ ++static int sxg_initialize_adapter(p_adapter_t adapter) ++{ ++ u32 RssIds, IsrCount; ++ u32 i; ++ int status; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "InitAdpt", ++ adapter, 0, 0, 0); ++ ++ RssIds = 1; // XXXTODO SXG_RSS_CPU_COUNT(adapter); ++ IsrCount = adapter->MsiEnabled ? RssIds : 1; ++ ++ // Sanity check SXG_UCODE_REGS structure definition to ++ // make sure the length is correct ++ ASSERT(sizeof(SXG_UCODE_REGS) == SXG_REGISTER_SIZE_PER_CPU); ++ ++ // Disable interrupts ++ SXG_DISABLE_ALL_INTERRUPTS(adapter); ++ ++ // Set MTU ++ ASSERT((adapter->FrameSize == ETHERMAXFRAME) || ++ (adapter->FrameSize == JUMBOMAXFRAME)); ++ WRITE_REG(adapter->UcodeRegs[0].LinkMtu, adapter->FrameSize, TRUE); ++ ++ // Set event ring base address and size ++ WRITE_REG64(adapter, ++ adapter->UcodeRegs[0].EventBase, adapter->PEventRings, 0); ++ WRITE_REG(adapter->UcodeRegs[0].EventSize, EVENT_RING_SIZE, TRUE); ++ ++ // Per-ISR initialization ++ for (i = 0; i < IsrCount; i++) { ++ u64 Addr; ++ // Set interrupt status pointer ++ Addr = adapter->PIsr + (i * sizeof(u32)); ++ WRITE_REG64(adapter, adapter->UcodeRegs[i].Isp, Addr, i); ++ } ++ ++ // XMT ring zero index ++ WRITE_REG64(adapter, ++ adapter->UcodeRegs[0].SPSendIndex, ++ adapter->PXmtRingZeroIndex, 0); ++ ++ // Per-RSS initialization ++ for (i = 0; i < RssIds; i++) { ++ // Release all event ring entries to the Microcode ++ WRITE_REG(adapter->UcodeRegs[i].EventRelease, EVENT_RING_SIZE, ++ TRUE); ++ } ++ ++ // Transmit ring base and size ++ WRITE_REG64(adapter, ++ adapter->UcodeRegs[0].XmtBase, adapter->PXmtRings, 0); ++ WRITE_REG(adapter->UcodeRegs[0].XmtSize, SXG_XMT_RING_SIZE, TRUE); ++ ++ // Receive ring base and size ++ WRITE_REG64(adapter, ++ adapter->UcodeRegs[0].RcvBase, adapter->PRcvRings, 0); ++ WRITE_REG(adapter->UcodeRegs[0].RcvSize, SXG_RCV_RING_SIZE, TRUE); ++ ++ // Populate the card with receive buffers ++ sxg_stock_rcv_buffers(adapter); ++ ++ // Initialize checksum offload capabilities. At the moment ++ // we always enable IP and TCP receive checksums on the card. ++ // Depending on the checksum configuration specified by the ++ // user, we can choose to report or ignore the checksum ++ // information provided by the card. ++ WRITE_REG(adapter->UcodeRegs[0].ReceiveChecksum, ++ SXG_RCV_TCP_CSUM_ENABLED | SXG_RCV_IP_CSUM_ENABLED, TRUE); ++ ++ // Initialize the MAC, XAUI ++ DBG_ERROR("sxg: %s ENTER sxg_initialize_link\n", __FUNCTION__); ++ status = sxg_initialize_link(adapter); ++ DBG_ERROR("sxg: %s EXIT sxg_initialize_link status[%x]\n", __FUNCTION__, ++ status); ++ if (status != STATUS_SUCCESS) { ++ return (status); ++ } ++ // Initialize Dead to FALSE. ++ // SlicCheckForHang or SlicDumpThread will take it from here. ++ adapter->Dead = FALSE; ++ adapter->PingOutstanding = FALSE; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XInit", ++ adapter, 0, 0, 0); ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_fill_descriptor_block - Populate a descriptor block and give it to ++ * the card. The caller should hold the RcvQLock ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * RcvDescriptorBlockHdr - Descriptor block to fill ++ * ++ * Return ++ * status ++ */ ++static int sxg_fill_descriptor_block(p_adapter_t adapter, ++ PSXG_RCV_DESCRIPTOR_BLOCK_HDR RcvDescriptorBlockHdr) ++{ ++ u32 i; ++ PSXG_RING_INFO RcvRingInfo = &adapter->RcvRingZeroInfo; ++ PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr; ++ PSXG_RCV_DESCRIPTOR_BLOCK RcvDescriptorBlock; ++ PSXG_CMD RingDescriptorCmd; ++ PSXG_RCV_RING RingZero = &adapter->RcvRings[0]; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FilBlk", ++ adapter, adapter->RcvBuffersOnCard, ++ adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount); ++ ++ ASSERT(RcvDescriptorBlockHdr); ++ ++ // If we don't have the resources to fill the descriptor block, ++ // return failure ++ if ((adapter->FreeRcvBufferCount < SXG_RCV_DESCRIPTORS_PER_BLOCK) || ++ SXG_RING_FULL(RcvRingInfo)) { ++ adapter->Stats.NoMem++; ++ return (STATUS_FAILURE); ++ } ++ // Get a ring descriptor command ++ SXG_GET_CMD(RingZero, ++ RcvRingInfo, RingDescriptorCmd, RcvDescriptorBlockHdr); ++ ASSERT(RingDescriptorCmd); ++ RcvDescriptorBlockHdr->State = SXG_BUFFER_ONCARD; ++ RcvDescriptorBlock = ++ (PSXG_RCV_DESCRIPTOR_BLOCK) RcvDescriptorBlockHdr->VirtualAddress; ++ ++ // Fill in the descriptor block ++ for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; i++) { ++ SXG_GET_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); ++ ASSERT(RcvDataBufferHdr); ++ SXG_REINIATIALIZE_PACKET(RcvDataBufferHdr->SxgDumbRcvPacket); ++ RcvDataBufferHdr->State = SXG_BUFFER_ONCARD; ++ RcvDescriptorBlock->Descriptors[i].VirtualAddress = (void *)RcvDataBufferHdr; ++ RcvDescriptorBlock->Descriptors[i].PhysicalAddress = ++ RcvDataBufferHdr->PhysicalAddress; ++ } ++ // Add the descriptor block to receive descriptor ring 0 ++ RingDescriptorCmd->Sgl = RcvDescriptorBlockHdr->PhysicalAddress; ++ ++ // RcvBuffersOnCard is not protected via the receive lock (see ++ // sxg_process_event_queue) We don't want to grap a lock every time a ++ // buffer is returned to us, so we use atomic interlocked functions ++ // instead. ++ adapter->RcvBuffersOnCard += SXG_RCV_DESCRIPTORS_PER_BLOCK; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DscBlk", ++ RcvDescriptorBlockHdr, ++ RingDescriptorCmd, RcvRingInfo->Head, RcvRingInfo->Tail); ++ ++ WRITE_REG(adapter->UcodeRegs[0].RcvCmd, 1, true); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFilBlk", ++ adapter, adapter->RcvBuffersOnCard, ++ adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount); ++ return (STATUS_SUCCESS); ++} ++ ++/* ++ * sxg_stock_rcv_buffers - Stock the card with receive buffers ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * ++ * Return ++ * None ++ */ ++static void sxg_stock_rcv_buffers(p_adapter_t adapter) ++{ ++ PSXG_RCV_DESCRIPTOR_BLOCK_HDR RcvDescriptorBlockHdr; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "StockBuf", ++ adapter, adapter->RcvBuffersOnCard, ++ adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount); ++ // First, see if we've got less than our minimum threshold of ++ // receive buffers, there isn't an allocation in progress, and ++ // we haven't exceeded our maximum.. get another block of buffers ++ // None of this needs to be SMP safe. It's round numbers. ++ if ((adapter->FreeRcvBufferCount < SXG_MIN_RCV_DATA_BUFFERS) && ++ (adapter->AllRcvBlockCount < SXG_MAX_RCV_BLOCKS) && ++ (adapter->AllocationsPending == 0)) { ++ sxg_allocate_buffer_memory(adapter, ++ SXG_RCV_BLOCK_SIZE(adapter-> ++ ReceiveBufferSize), ++ SXG_BUFFER_TYPE_RCV); ++ } ++ // Now grab the RcvQLock lock and proceed ++ spin_lock(&adapter->RcvQLock); ++ while (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) { ++ PLIST_ENTRY _ple; ++ ++ // Get a descriptor block ++ RcvDescriptorBlockHdr = NULL; ++ if (adapter->FreeRcvBlockCount) { ++ _ple = RemoveHeadList(&adapter->FreeRcvBlocks); ++ RcvDescriptorBlockHdr = container_of(_ple, SXG_RCV_DESCRIPTOR_BLOCK_HDR, FreeList); ++ adapter->FreeRcvBlockCount--; ++ RcvDescriptorBlockHdr->State = SXG_BUFFER_BUSY; ++ } ++ ++ if (RcvDescriptorBlockHdr == NULL) { ++ // Bail out.. ++ adapter->Stats.NoMem++; ++ break; ++ } ++ // Fill in the descriptor block and give it to the card ++ if (sxg_fill_descriptor_block(adapter, RcvDescriptorBlockHdr) == ++ STATUS_FAILURE) { ++ // Free the descriptor block ++ SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter, ++ RcvDescriptorBlockHdr); ++ break; ++ } ++ } ++ spin_unlock(&adapter->RcvQLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFilBlks", ++ adapter, adapter->RcvBuffersOnCard, ++ adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount); ++} ++ ++/* ++ * sxg_complete_descriptor_blocks - Return descriptor blocks that have been ++ * completed by the microcode ++ * ++ * Arguments - ++ * adapter - A pointer to our adapter structure ++ * Index - Where the microcode is up to ++ * ++ * Return ++ * None ++ */ ++static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char Index) ++{ ++ PSXG_RCV_RING RingZero = &adapter->RcvRings[0]; ++ PSXG_RING_INFO RcvRingInfo = &adapter->RcvRingZeroInfo; ++ PSXG_RCV_DESCRIPTOR_BLOCK_HDR RcvDescriptorBlockHdr; ++ PSXG_CMD RingDescriptorCmd; ++ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpRBlks", ++ adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail); ++ ++ // Now grab the RcvQLock lock and proceed ++ spin_lock(&adapter->RcvQLock); ++ ASSERT(Index != RcvRingInfo->Tail); ++ while (RcvRingInfo->Tail != Index) { ++ // ++ // Locate the current Cmd (ring descriptor entry), and ++ // associated receive descriptor block, and advance ++ // the tail ++ // ++ SXG_RETURN_CMD(RingZero, ++ RcvRingInfo, ++ RingDescriptorCmd, RcvDescriptorBlockHdr); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpRBlk", ++ RcvRingInfo->Head, RcvRingInfo->Tail, ++ RingDescriptorCmd, RcvDescriptorBlockHdr); ++ ++ // Clear the SGL field ++ RingDescriptorCmd->Sgl = 0; ++ // Attempt to refill it and hand it right back to the ++ // card. If we fail to refill it, free the descriptor block ++ // header. The card will be restocked later via the ++ // RcvBuffersOnCard test ++ if (sxg_fill_descriptor_block(adapter, RcvDescriptorBlockHdr) == ++ STATUS_FAILURE) { ++ SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter, ++ RcvDescriptorBlockHdr); ++ } ++ } ++ spin_unlock(&adapter->RcvQLock); ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XCRBlks", ++ adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail); ++} ++ ++ ++static struct pci_driver sxg_driver = { ++ .name = DRV_NAME, ++ .id_table = sxg_pci_tbl, ++ .probe = sxg_entry_probe, ++ .remove = sxg_entry_remove, ++#if SXG_POWER_MANAGEMENT_ENABLED ++ .suspend = sxgpm_suspend, ++ .resume = sxgpm_resume, ++#endif ++/* .shutdown = slic_shutdown, MOOK_INVESTIGATE */ ++}; ++ ++static int __init sxg_module_init(void) ++{ ++ sxg_init_driver(); ++ ++ if (debug >= 0) ++ sxg_debug = debug; ++ ++ return pci_register_driver(&sxg_driver); ++} ++ ++static void __exit sxg_module_cleanup(void) ++{ ++ pci_unregister_driver(&sxg_driver); ++} ++ ++module_init(sxg_module_init); ++module_exit(sxg_module_cleanup); +--- /dev/null ++++ b/drivers/staging/sxg/sxgdbg.h +@@ -0,0 +1,190 @@ ++/************************************************************************** ++ * ++ * Copyright © 2000-2008 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: sxgdbg.h,v 1.1 2008/06/27 12:49:28 mook Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: sxgdbg.h ++ * ++ * All debug and assertion-based definitions and macros are included ++ * in this file for the SXGOSS driver. ++ */ ++#ifndef _SXG_DEBUG_H_ ++#define _SXG_DEBUG_H_ ++ ++#define ATKDBG 1 ++#define ATK_TRACE_ENABLED 1 ++ ++#define DBG_ERROR(n, args...) printk(KERN_EMERG n, ##args) ++ ++#ifdef ASSERT ++#undef ASSERT ++#endif ++ ++#ifdef SXG_ASSERT_ENABLED ++#ifndef ASSERT ++#define ASSERT(a) \ ++ { \ ++ if (!(a)) { \ ++ DBG_ERROR("ASSERT() Failure: file %s, function %s line %d\n",\ ++ __FILE__, __FUNCTION__, __LINE__); \ ++ } \ ++ } ++#endif ++#else ++#ifndef ASSERT ++#define ASSERT(a) ++#endif ++#endif /* SXG_ASSERT_ENABLED */ ++ ++ ++#ifdef ATKDBG ++/* ++ * Global for timer granularity; every driver must have an instance ++ * of this initialized to 0 ++ */ ++ ++extern ulong ATKTimerDiv; ++ ++/* ++ * trace_entry_t - ++ * ++ * This structure defines an entry in the trace buffer. The ++ * first few fields mean the same from entry to entry, while ++ * the meaning of last several fields change to suit the ++ * needs of the trace entry. Typically they are function call ++ * parameters. ++ */ ++typedef struct _trace_entry_s { ++ char name[8]; /* 8 character name - like 's'i'm'b'a'r'c'v' */ ++ u32 time; /* Current clock tic */ ++ unsigned char cpu; /* Current CPU */ ++ unsigned char irql; /* Current IRQL */ ++ unsigned char driver; /* The driver which added the trace call */ ++ unsigned char pad2; /* pad to 4 byte boundary - will probably get used */ ++ u32 arg1; /* Caller arg1 */ ++ u32 arg2; /* Caller arg2 */ ++ u32 arg3; /* Caller arg3 */ ++ u32 arg4; /* Caller arg4 */ ++} trace_entry_t, *ptrace_entry_t; ++ ++/* ++ * Driver types for driver field in trace_entry_t ++ */ ++#define TRACE_SXG 1 ++#define TRACE_VPCI 2 ++#define TRACE_SLIC 3 ++ ++#define TRACE_ENTRIES 1024 ++ ++typedef struct _sxg_trace_buffer_t ++{ ++ unsigned int size; /* aid for windbg extension */ ++ unsigned int in; /* Where to add */ ++ unsigned int level; /* Current Trace level */ ++ spinlock_t lock; /* For MP tracing */ ++ trace_entry_t entries[TRACE_ENTRIES];/* The circular buffer */ ++} sxg_trace_buffer_t; ++ ++/* ++ * The trace levels ++ * ++ * XXX At the moment I am only defining critical, important, and noisy. ++ * I am leaving room for more if anyone wants them. ++ */ ++#define TRACE_NONE 0 /* For trace level - if no tracing wanted */ ++#define TRACE_CRITICAL 1 /* minimal tracing - only critical stuff */ ++#define TRACE_IMPORTANT 5 /* more tracing - anything important */ ++#define TRACE_NOISY 10 /* Everything in the world */ ++ ++ ++/********************************************************************** ++ * ++ * The macros themselves - ++ * ++ *********************************************************************/ ++#if ATK_TRACE_ENABLED ++#define SXG_TRACE_INIT(buffer, tlevel) \ ++{ \ ++ memset((buffer), 0, sizeof(sxg_trace_buffer_t)); \ ++ (buffer)->level = (tlevel); \ ++ (buffer)->size = TRACE_ENTRIES; \ ++ spin_lock_init(&(buffer)->lock); \ ++} ++#else ++#define SXG_TRACE_INIT(buffer, tlevel) ++#endif ++ ++/* ++ * The trace macro. This is active only if ATK_TRACE_ENABLED is set. ++ */ ++#if ATK_TRACE_ENABLED ++#define SXG_TRACE(tdriver, buffer, tlevel, tname, a1, a2, a3, a4) { \ ++ if ((buffer) && ((buffer)->level >= (tlevel))) { \ ++ unsigned int trace_irql = 0; /* ?????? FIX THIS */ \ ++ unsigned int trace_len; \ ++ ptrace_entry_t trace_entry; \ ++ struct timeval timev; \ ++ \ ++ spin_lock(&(buffer)->lock); \ ++ trace_entry = &(buffer)->entries[(buffer)->in]; \ ++ do_gettimeofday(&timev); \ ++ \ ++ memset(trace_entry->name, 0, 8); \ ++ trace_len = strlen(tname); \ ++ trace_len = trace_len > 8 ? 8 : trace_len; \ ++ memcpy(trace_entry->name, (tname), trace_len); \ ++ trace_entry->time = timev.tv_usec; \ ++ trace_entry->cpu = (unsigned char)(smp_processor_id() & 0xFF); \ ++ trace_entry->driver = (tdriver); \ ++ trace_entry->irql = trace_irql; \ ++ trace_entry->arg1 = (ulong)(a1); \ ++ trace_entry->arg2 = (ulong)(a2); \ ++ trace_entry->arg3 = (ulong)(a3); \ ++ trace_entry->arg4 = (ulong)(a4); \ ++ \ ++ (buffer)->in++; \ ++ if ((buffer)->in == TRACE_ENTRIES) \ ++ (buffer)->in = 0; \ ++ \ ++ spin_unlock(&(buffer)->lock); \ ++ } \ ++} ++#else ++#define SXG_TRACE(tdriver, buffer, tlevel, tname, a1, a2, a3, a4) ++#endif ++ ++#endif ++ ++#endif /* _SXG_DEBUG_H_ */ +--- /dev/null ++++ b/drivers/staging/sxg/sxg.h +@@ -0,0 +1,773 @@ ++/************************************************************************** ++ * ++ * Copyright © 2000-2008 Alacritech, Inc. All rights reserved. ++ * ++ * $Id: sxg.h,v 1.3 2008/07/24 17:25:08 chris Exp $ ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: sxg.h ++ * ++ * This is the base set of header definitions for the SXG driver. ++ */ ++#ifndef __SXG_DRIVER_H__ ++#define __SXG_DRIVER_H__ ++ ++#define p_net_device struct net_device * ++// SXG_STATS - Probably move these to someplace where ++// the slicstat (sxgstat?) program can get them. ++typedef struct _SXG_STATS { ++ // Xmt ++ u32 XmtNBL; // Offload send NBL count ++ u64 DumbXmtBytes; // Dumbnic send bytes ++ u64 SlowXmtBytes; // Slowpath send bytes ++ u64 FastXmtBytes; // Fastpath send bytes ++ u64 DumbXmtPkts; // Dumbnic send packets ++ u64 SlowXmtPkts; // Slowpath send packets ++ u64 FastXmtPkts; // Fastpath send packets ++ u64 DumbXmtUcastPkts; // directed packets ++ u64 DumbXmtMcastPkts; // Multicast packets ++ u64 DumbXmtBcastPkts; // OID_GEN_BROADCAST_FRAMES_RCV ++ u64 DumbXmtUcastBytes; // OID_GEN_DIRECTED_BYTES_XMIT ++ u64 DumbXmtMcastBytes; // OID_GEN_MULTICAST_BYTES_XMIT ++ u64 DumbXmtBcastBytes; // OID_GEN_BROADCAST_BYTES_XMIT ++ u64 XmtErrors; // OID_GEN_XMIT_ERROR ++ u64 XmtDiscards; // OID_GEN_XMIT_DISCARDS ++ u64 XmtOk; // OID_GEN_XMIT_OK ++ u64 XmtQLen; // OID_GEN_TRANSMIT_QUEUE_LENGTH ++ u64 XmtZeroFull; // Transmit ring zero full ++ // Rcv ++ u32 RcvNBL; // Offload recieve NBL count ++ u64 DumbRcvBytes; // dumbnic recv bytes ++ u64 DumbRcvUcastBytes; // OID_GEN_DIRECTED_BYTES_RCV ++ u64 DumbRcvMcastBytes; // OID_GEN_MULTICAST_BYTES_RCV ++ u64 DumbRcvBcastBytes; // OID_GEN_BROADCAST_BYTES_RCV ++ u64 SlowRcvBytes; // Slowpath recv bytes ++ u64 FastRcvBytes; // Fastpath recv bytes ++ u64 DumbRcvPkts; // OID_GEN_DIRECTED_FRAMES_RCV ++ u64 DumbRcvTcpPkts; // See SxgCollectStats ++ u64 DumbRcvUcastPkts; // directed packets ++ u64 DumbRcvMcastPkts; // Multicast packets ++ u64 DumbRcvBcastPkts; // OID_GEN_BROADCAST_FRAMES_RCV ++ u64 SlowRcvPkts; // OID_GEN_DIRECTED_FRAMES_RCV ++ u64 RcvErrors; // OID_GEN_RCV_ERROR ++ u64 RcvDiscards; // OID_GEN_RCV_DISCARDS ++ u64 RcvNoBuffer; // OID_GEN_RCV_NO_BUFFER ++ u64 PdqFull; // Processed Data Queue Full ++ u64 EventRingFull; // Event ring full ++ // Verbose stats ++ u64 MaxSends; // Max sends outstanding ++ u64 NoSglBuf; // SGL buffer allocation failure ++ u64 SglFail; // NDIS SGL failure ++ u64 SglAsync; // NDIS SGL failure ++ u64 NoMem; // Memory allocation failure ++ u64 NumInts; // Interrupts ++ u64 FalseInts; // Interrupt with ISR == 0 ++ u64 XmtDrops; // No sahara DRAM buffer for xmt ++ // Sahara receive status ++ u64 TransportCsum; // SXG_RCV_STATUS_TRANSPORT_CSUM ++ u64 TransportUflow; // SXG_RCV_STATUS_TRANSPORT_UFLOW ++ u64 TransportHdrLen; // SXG_RCV_STATUS_TRANSPORT_HDRLEN ++ u64 NetworkCsum; // SXG_RCV_STATUS_NETWORK_CSUM: ++ u64 NetworkUflow; // SXG_RCV_STATUS_NETWORK_UFLOW: ++ u64 NetworkHdrLen; // SXG_RCV_STATUS_NETWORK_HDRLEN: ++ u64 Parity; // SXG_RCV_STATUS_PARITY ++ u64 LinkParity; // SXG_RCV_STATUS_LINK_PARITY: ++ u64 LinkEarly; // SXG_RCV_STATUS_LINK_EARLY: ++ u64 LinkBufOflow; // SXG_RCV_STATUS_LINK_BUFOFLOW: ++ u64 LinkCode; // SXG_RCV_STATUS_LINK_CODE: ++ u64 LinkDribble; // SXG_RCV_STATUS_LINK_DRIBBLE: ++ u64 LinkCrc; // SXG_RCV_STATUS_LINK_CRC: ++ u64 LinkOflow; // SXG_RCV_STATUS_LINK_OFLOW: ++ u64 LinkUflow; // SXG_RCV_STATUS_LINK_UFLOW: ++} SXG_STATS, *PSXG_STATS; ++ ++ ++/**************************************************************************** ++ * DUMB-NIC Send path definitions ++ ****************************************************************************/ ++ ++#define SXG_COMPLETE_DUMB_SEND(_pAdapt, _skb) { \ ++ ASSERT(_skb); \ ++ dev_kfree_skb_irq(_skb); \ ++} ++ ++#define SXG_DROP_DUMB_SEND(_pAdapt, _skb) { \ ++ ASSERT(_skb); \ ++ dev_kfree_skb(_skb); \ ++} ++ ++// Locate current receive header buffer location. Use this ++// instead of RcvDataHdr->VirtualAddress since the data ++// may have been offset by SXG_ADVANCE_MDL_OFFSET ++#define SXG_RECEIVE_DATA_LOCATION(_RcvDataHdr) (_RcvDataHdr)->skb->data ++ ++/************************************************************************ ++ * Dumb-NIC receive processing ++ ************************************************************************/ ++// Define an SXG_PACKET as an NDIS_PACKET ++#define PSXG_PACKET struct sk_buff * ++// Indications array size ++#define SXG_RCV_ARRAYSIZE 64 ++ ++#define SXG_ALLOCATE_RCV_PACKET(_pAdapt, _RcvDataBufferHdr) { \ ++ struct sk_buff * skb; \ ++ skb = alloc_skb(2048, GFP_ATOMIC); \ ++ if (skb) { \ ++ (_RcvDataBufferHdr)->skb = skb; \ ++ skb->next = NULL; \ ++ } else { \ ++ (_RcvDataBufferHdr)->skb = NULL; \ ++ } \ ++} ++ ++#define SXG_FREE_RCV_PACKET(_RcvDataBufferHdr) { \ ++ if((_RcvDataBufferHdr)->skb) { \ ++ dev_kfree_skb((_RcvDataBufferHdr)->skb); \ ++ } \ ++} ++ ++// Macro to add a NDIS_PACKET to an indication array ++// If we fill up our array of packet pointers, then indicate this ++// block up now and start on a new one. ++#define SXG_ADD_RCV_PACKET(_pAdapt, _Packet, _PrevPacket, _IndicationList, _NumPackets) { \ ++ (_IndicationList)[_NumPackets] = (_Packet); \ ++ (_NumPackets)++; \ ++ if((_NumPackets) == SXG_RCV_ARRAYSIZE) { \ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "IndicRcv", \ ++ (_NumPackets), 0, 0, 0); \ ++ netif_rx((_IndicationList),(_NumPackets)); \ ++ (_NumPackets) = 0; \ ++ } \ ++} ++ ++#define SXG_INDICATE_PACKETS(_pAdapt, _IndicationList, _NumPackets) { \ ++ if(_NumPackets) { \ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "IndicRcv", \ ++ (_NumPackets), 0, 0, 0); \ ++ netif_rx((_IndicationList),(_NumPackets)); \ ++ (_NumPackets) = 0; \ ++ } \ ++} ++ ++#define SXG_REINIATIALIZE_PACKET(_Packet) \ ++ {} /*_NdisReinitializePacket(_Packet)*/ /* this is not necessary with an skb */ ++ ++// Definitions to initialize Dumb-nic Receive NBLs ++#define SXG_RCV_PACKET_BUFFER_HDR(_Packet) (((PSXG_RCV_NBL_RESERVED)((_Packet)->MiniportReservedEx))->RcvDataBufferHdr) ++ ++#define SXG_RCV_SET_CHECKSUM_INFO(_Packet, _Cpi) \ ++ NDIS_PER_PACKET_INFO_FROM_PACKET((_Packet), TcpIpChecksumPacketInfo) = (PVOID)(_Cpi) ++ ++#define SXG_RCV_SET_TOEPLITZ(_Packet, _Toeplitz, _Type, _Function) { \ ++ NDIS_PACKET_SET_HASH_VALUE((_Packet), (_Toeplitz)); \ ++ NDIS_PACKET_SET_HASH_TYPE((_Packet), (_Type)); \ ++ NDIS_PACKET_SET_HASH_FUNCTION((_Packet), (_Function)); \ ++} ++ ++#define SXG_RCV_SET_VLAN_INFO(_Packet, _VlanId, _Priority) { \ ++ NDIS_PACKET_8021Q_INFO _Packet8021qInfo; \ ++ _Packet8021qInfo.TagHeader.VlanId = (_VlanId); \ ++ _Packet8021qInfo.TagHeader.UserPriority = (_Priority); \ ++ NDIS_PER_PACKET_INFO_FROM_PACKET((_Packet), Ieee8021QNetBufferListInfo) = \ ++ _Packet8021qInfo.Value; \ ++} ++ ++#define SXG_ADJUST_RCV_PACKET(_Packet, _RcvDataBufferHdr, _Event) { \ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbRcv", \ ++ (_RcvDataBufferHdr), (_Packet), \ ++ (_Event)->Status, 0); \ ++ ASSERT((_Event)->Length <= (_RcvDataBufferHdr)->Size); \ ++ Packet->len = (_Event)->Length; \ ++} ++ ++/////////////////////////////////////////////////////////////////////////////// ++// Macros to free a receive data buffer and receive data descriptor block ++/////////////////////////////////////////////////////////////////////////////// ++// NOTE - Lock must be held with RCV macros ++#define SXG_GET_RCV_DATA_BUFFER(_pAdapt, _Hdr) { \ ++ PLIST_ENTRY _ple; \ ++ _Hdr = NULL; \ ++ if((_pAdapt)->FreeRcvBufferCount) { \ ++ ASSERT(!(IsListEmpty(&(_pAdapt)->FreeRcvBuffers))); \ ++ _ple = RemoveHeadList(&(_pAdapt)->FreeRcvBuffers); \ ++ (_Hdr) = container_of(_ple, SXG_RCV_DATA_BUFFER_HDR, FreeList); \ ++ (_pAdapt)->FreeRcvBufferCount--; \ ++ ASSERT((_Hdr)->State == SXG_BUFFER_FREE); \ ++ } \ ++} ++ ++#define SXG_FREE_RCV_DATA_BUFFER(_pAdapt, _Hdr) { \ ++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RtnDHdr", \ ++ (_Hdr), (_pAdapt)->FreeRcvBufferCount, \ ++ (_Hdr)->State, (_Hdr)->VirtualAddress); \ ++/* SXG_RESTORE_MDL_OFFSET(_Hdr); */ \ ++ (_pAdapt)->FreeRcvBufferCount++; \ ++ ASSERT(((_pAdapt)->AllRcvBlockCount * SXG_RCV_DESCRIPTORS_PER_BLOCK) >= (_pAdapt)->FreeRcvBufferCount); \ ++ ASSERT((_Hdr)->State != SXG_BUFFER_FREE); \ ++ (_Hdr)->State = SXG_BUFFER_FREE; \ ++ InsertTailList(&(_pAdapt)->FreeRcvBuffers, &((_Hdr)->FreeList)); \ ++} ++ ++#define SXG_FREE_RCV_DESCRIPTOR_BLOCK(_pAdapt, _Hdr) { \ ++ ASSERT((_Hdr)->State != SXG_BUFFER_FREE); \ ++ (_Hdr)->State = SXG_BUFFER_FREE; \ ++ (_pAdapt)->FreeRcvBlockCount++; \ ++ ASSERT((_pAdapt)->AllRcvBlockCount >= (_pAdapt)->FreeRcvBlockCount); \ ++ InsertTailList(&(_pAdapt)->FreeRcvBlocks, &(_Hdr)->FreeList); \ ++} ++ ++// SGL macros ++#define SXG_FREE_SGL_BUFFER(_pAdapt, _Sgl, _NB) { \ ++ spin_lock(&(_pAdapt)->SglQLock); \ ++ (_pAdapt)->FreeSglBufferCount++; \ ++ ASSERT((_pAdapt)->AllSglBufferCount >= (_pAdapt)->FreeSglBufferCount);\ ++ ASSERT(!((_Sgl)->State & SXG_BUFFER_FREE)); \ ++ (_Sgl)->State = SXG_BUFFER_FREE; \ ++ InsertTailList(&(_pAdapt)->FreeSglBuffers, &(_Sgl)->FreeList); \ ++ spin_unlock(&(_pAdapt)->SglQLock); \ ++} ++ ++// Get an SGL buffer from the free queue. The first part of this macro ++// attempts to keep ahead of buffer depletion by allocating more when ++// we hit a minimum threshold. Note that we don't grab the lock ++// until after that. We're dealing with round numbers here, so we don't need to, ++// and not grabbing it avoids a possible double-trip. ++#define SXG_GET_SGL_BUFFER(_pAdapt, _Sgl) { \ ++ PLIST_ENTRY _ple; \ ++ if ((_pAdapt->FreeSglBufferCount < SXG_MIN_SGL_BUFFERS) && \ ++ (_pAdapt->AllSglBufferCount < SXG_MAX_SGL_BUFFERS) && \ ++ (_pAdapt->AllocationsPending == 0)) { \ ++ sxg_allocate_buffer_memory(_pAdapt, \ ++ (sizeof(SXG_SCATTER_GATHER) + SXG_SGL_BUF_SIZE),\ ++ SXG_BUFFER_TYPE_SGL); \ ++ } \ ++ _Sgl = NULL; \ ++ spin_lock(&(_pAdapt)->SglQLock); \ ++ if((_pAdapt)->FreeSglBufferCount) { \ ++ ASSERT(!(IsListEmpty(&(_pAdapt)->FreeSglBuffers))); \ ++ _ple = RemoveHeadList(&(_pAdapt)->FreeSglBuffers); \ ++ (_Sgl) = container_of(_ple, SXG_SCATTER_GATHER, FreeList); \ ++ (_pAdapt)->FreeSglBufferCount--; \ ++ ASSERT((_Sgl)->State == SXG_BUFFER_FREE); \ ++ (_Sgl)->State = SXG_BUFFER_BUSY; \ ++ (_Sgl)->pSgl = NULL; \ ++ } \ ++ spin_unlock(&(_pAdapt)->SglQLock); \ ++} ++ ++// ++// SXG_MULTICAST_ADDRESS ++// ++// Linked list of multicast addresses. ++typedef struct _SXG_MULTICAST_ADDRESS { ++ unsigned char Address[6]; ++ struct _SXG_MULTICAST_ADDRESS *Next; ++} SXG_MULTICAST_ADDRESS, *PSXG_MULTICAST_ADDRESS; ++ ++// Structure to maintain chimney send and receive buffer queues. ++// This structure maintains NET_BUFFER_LIST queues that are ++// given to us via the Chimney MiniportTcpOffloadSend and ++// MiniportTcpOffloadReceive routines. This structure DOES NOT ++// manage our data buffer queue ++typedef struct _SXG_BUFFER_QUEUE { ++ u32 Type; // Slow or fast - See below ++ u32 Direction; // Xmt or Rcv ++ u32 Bytes; // Byte count ++ u32 * Head; // Send queue head ++ u32 * Tail; // Send queue tail ++// PNET_BUFFER_LIST NextNBL; // Short cut - next NBL ++// PNET_BUFFER NextNB; // Short cut - next NB ++} SXG_BUFFER_QUEUE, *PSXG_BUFFER_QUEUE; ++ ++#define SXG_SLOW_SEND_BUFFER 0 ++#define SXG_FAST_SEND_BUFFER 1 ++#define SXG_RECEIVE_BUFFER 2 ++ ++#define SXG_INIT_BUFFER(_Buffer, _Type) { \ ++ (_Buffer)->Type = (_Type); \ ++ if((_Type) == SXG_RECEIVE_BUFFER) { \ ++ (_Buffer)->Direction = 0; \ ++ } else { \ ++ (_Buffer)->Direction = NDIS_SG_LIST_WRITE_TO_DEVICE; \ ++ } \ ++ (_Buffer)->Bytes = 0; \ ++ (_Buffer)->Head = NULL; \ ++ (_Buffer)->Tail = NULL; \ ++} ++ ++ ++#define SXG_RSS_CPU_COUNT(_pAdapt) \ ++ ((_pAdapt)->RssEnabled ? NR_CPUS : 1) ++ ++/**************************************************************************** ++ * DRIVER and ADAPTER structures ++ ****************************************************************************/ ++ ++// Adapter states - These states closely match the adapter states ++// documented in the DDK (with a few exceptions). ++typedef enum _SXG_STATE { ++ SXG_STATE_INITIALIZING, // Initializing ++ SXG_STATE_BOOTDIAG, // Boot-Diagnostic mode ++ SXG_STATE_PAUSING, // Pausing ++ SXG_STATE_PAUSED, // Paused ++ SXG_STATE_RUNNING, // Running ++ SXG_STATE_RESETTING, // Reset in progress ++ SXG_STATE_SLEEP, // Sleeping ++ SXG_STATE_DIAG, // Diagnostic mode ++ SXG_STATE_HALTING, // Halting ++ SXG_STATE_HALTED, // Down or not-initialized ++ SXG_STATE_SHUTDOWN // shutdown ++} SXG_STATE, *PSXG_STATE; ++ ++// Link state ++typedef enum _SXG_LINK_STATE { ++ SXG_LINK_DOWN, ++ SXG_LINK_UP ++} SXG_LINK_STATE, *PSXG_LINK_STATE; ++ ++// Link initialization timeout in 100us units ++#define SXG_LINK_TIMEOUT 100000 // 10 Seconds - REDUCE! ++ ++ ++// Microcode file selection codes ++typedef enum _SXG_UCODE_SEL { ++ SXG_UCODE_SAHARA, // Sahara ucode ++ SXG_UCODE_SDIAGCPU, // Sahara CPU diagnostic ucode ++ SXG_UCODE_SDIAGSYS // Sahara system diagnostic ucode ++} SXG_UCODE_SEL; ++ ++ ++#define SXG_DISABLE_ALL_INTERRUPTS(_padapt) sxg_disable_interrupt(_padapt) ++#define SXG_ENABLE_ALL_INTERRUPTS(_padapt) sxg_enable_interrupt(_padapt) ++ ++// This probably lives in a proto.h file. Move later ++#define SXG_MULTICAST_PACKET(_pether) ((_pether)->ether_dhost[0] & 0x01) ++#define SXG_BROADCAST_PACKET(_pether) ((*(u32 *)(_pether)->ether_dhost == 0xFFFFFFFF) && \ ++ (*(u16 *)&(_pether)->ether_dhost[4] == 0xFFFF)) ++ ++// For DbgPrints ++#define SXG_ID DPFLTR_IHVNETWORK_ID ++#define SXG_ERROR DPFLTR_ERROR_LEVEL ++ ++// ++// SXG_DRIVER structure - ++// ++// contains information about the sxg driver. There is only ++// one of these, and it is defined as a global. ++typedef struct _SXG_DRIVER { ++ struct _adapter_t *Adapters; // Linked list of adapters ++ ushort AdapterID; // Maintain unique adapter ID ++} SXG_DRIVER, *PSXG_DRIVER; ++ ++#ifdef STATUS_SUCCESS ++#undef STATUS_SUCCESS ++#endif ++ ++#define STATUS_SUCCESS 0 ++#define STATUS_PENDING 0 ++#define STATUS_FAILURE -1 ++#define STATUS_ERROR -2 ++#define STATUS_NOT_SUPPORTED -3 ++#define STATUS_BUFFER_TOO_SHORT -4 ++#define STATUS_RESOURCES -5 ++ ++#define SLIC_MAX_CARDS 32 ++#define SLIC_MAX_PORTS 4 /* Max # of ports per card */ ++#if SLIC_DUMP_ENABLED ++// Dump buffer size ++// ++// This cannot be bigger than the max DMA size the card supports, ++// given the current code structure in the host and ucode. ++// Mojave supports 16K, Oasis supports 16K-1, so ++// just set this at 15K, shouldnt make that much of a diff. ++#define DUMP_BUF_SIZE 0x3C00 ++#endif ++ ++#define MIN(a, b) ((u32)(a) < (u32)(b) ? (a) : (b)) ++#define MAX(a, b) ((u32)(a) > (u32)(b) ? (a) : (b)) ++ ++typedef struct _mcast_address_t ++{ ++ unsigned char address[6]; ++ struct _mcast_address_t *next; ++} mcast_address_t, *p_mcast_address_t; ++ ++#define CARD_DOWN 0x00000000 ++#define CARD_UP 0x00000001 ++#define CARD_FAIL 0x00000002 ++#define CARD_DIAG 0x00000003 ++#define CARD_SLEEP 0x00000004 ++ ++#define ADAPT_DOWN 0x00 ++#define ADAPT_UP 0x01 ++#define ADAPT_FAIL 0x02 ++#define ADAPT_RESET 0x03 ++#define ADAPT_SLEEP 0x04 ++ ++#define ADAPT_FLAGS_BOOTTIME 0x0001 ++#define ADAPT_FLAGS_IS64BIT 0x0002 ++#define ADAPT_FLAGS_PENDINGLINKDOWN 0x0004 ++#define ADAPT_FLAGS_FIBERMEDIA 0x0008 ++#define ADAPT_FLAGS_LOCKS_ALLOCED 0x0010 ++#define ADAPT_FLAGS_INT_REGISTERED 0x0020 ++#define ADAPT_FLAGS_LOAD_TIMER_SET 0x0040 ++#define ADAPT_FLAGS_STATS_TIMER_SET 0x0080 ++#define ADAPT_FLAGS_RESET_TIMER_SET 0x0100 ++ ++#define LINK_DOWN 0x00 ++#define LINK_CONFIG 0x01 ++#define LINK_UP 0x02 ++ ++#define LINK_10MB 0x00 ++#define LINK_100MB 0x01 ++#define LINK_AUTOSPEED 0x02 ++#define LINK_1000MB 0x03 ++#define LINK_10000MB 0x04 ++ ++#define LINK_HALFD 0x00 ++#define LINK_FULLD 0x01 ++#define LINK_AUTOD 0x02 ++ ++#define MAC_DIRECTED 0x00000001 ++#define MAC_BCAST 0x00000002 ++#define MAC_MCAST 0x00000004 ++#define MAC_PROMISC 0x00000008 ++#define MAC_LOOPBACK 0x00000010 ++#define MAC_ALLMCAST 0x00000020 ++ ++#define SLIC_DUPLEX(x) ((x==LINK_FULLD) ? "FDX" : "HDX") ++#define SLIC_SPEED(x) ((x==LINK_100MB) ? "100Mb" : ((x==LINK_1000MB) ? "1000Mb" : " 10Mb")) ++#define SLIC_LINKSTATE(x) ((x==LINK_DOWN) ? "Down" : "Up ") ++#define SLIC_ADAPTER_STATE(x) ((x==ADAPT_UP) ? "UP" : "Down") ++#define SLIC_CARD_STATE(x) ((x==CARD_UP) ? "UP" : "Down") ++ ++ ++typedef struct _ether_header ++{ ++ unsigned char ether_dhost[6]; ++ unsigned char ether_shost[6]; ++ ushort ether_type; ++} ether_header, *p_ether_header; ++ ++ ++#define NUM_CFG_SPACES 2 ++#define NUM_CFG_REGS 64 ++ ++typedef struct _physcard_t ++{ ++ struct _adapter_t *adapter[SLIC_MAX_PORTS]; ++ struct _physcard_t *next; ++ unsigned int adapters_allocd; ++} physcard_t, *p_physcard_t; ++ ++typedef struct _sxgbase_driver ++{ ++ spinlock_t driver_lock; ++ unsigned long flags; /* irqsave for spinlock */ ++ u32 num_sxg_cards; ++ u32 num_sxg_ports; ++ u32 num_sxg_ports_active; ++ u32 dynamic_intagg; ++ p_physcard_t phys_card; ++} sxgbase_driver_t; ++ ++ ++typedef struct _adapter_t ++{ ++ void * ifp; ++ unsigned int port; ++ p_physcard_t physcard; ++ unsigned int physport; ++ unsigned int cardindex; ++ unsigned int card_size; ++ unsigned int chipid; ++ unsigned int busnumber; ++ unsigned int slotnumber; ++ unsigned int functionnumber; ++ ushort vendid; ++ ushort devid; ++ ushort subsysid; ++ u32 irq; ++ ++ void * sxg_adapter; ++ u32 nBusySend; ++ ++ void __iomem * base_addr; ++ u32 memorylength; ++ u32 drambase; ++ u32 dramlength; ++ unsigned int queues_initialized; ++ unsigned int allocated; ++ unsigned int activated; ++ u32 intrregistered; ++ unsigned int isp_initialized; ++ unsigned int gennumber; ++ u32 curaddrupper; ++ u32 isrcopy; ++ unsigned char state; ++ unsigned char linkstate; ++ unsigned char linkspeed; ++ unsigned char linkduplex; ++ unsigned int flags; ++ unsigned char macaddr[6]; ++ unsigned char currmacaddr[6]; ++ u32 macopts; ++ ushort devflags_prev; ++ u64 mcastmask; ++ p_mcast_address_t mcastaddrs; ++ struct timer_list pingtimer; ++ u32 pingtimerset; ++ struct timer_list statstimer; ++ u32 statstimerset; ++ struct timer_list vpci_timer; ++ u32 vpci_timerset; ++ struct timer_list loadtimer; ++ u32 loadtimerset; ++ ++ u32 xmitq_full; ++ u32 all_reg_writes; ++ u32 icr_reg_writes; ++ u32 isr_reg_writes; ++ u32 error_interrupts; ++ u32 error_rmiss_interrupts; ++ u32 rx_errors; ++ u32 rcv_drops; ++ u32 rcv_interrupts; ++ u32 xmit_interrupts; ++ u32 linkevent_interrupts; ++ u32 upr_interrupts; ++ u32 num_isrs; ++ u32 false_interrupts; ++ u32 tx_packets; ++ u32 xmit_completes; ++ u32 tx_drops; ++ u32 rcv_broadcasts; ++ u32 rcv_multicasts; ++ u32 rcv_unicasts; ++ u32 max_isr_rcvs; ++ u32 max_isr_xmits; ++ u32 rcv_interrupt_yields; ++ u32 intagg_period; ++ struct net_device_stats stats; ++ u32 * MiniportHandle; // Our miniport handle ++ SXG_STATE State; // Adapter state ++ SXG_LINK_STATE LinkState; // Link state ++ u64 LinkSpeed; // Link Speed ++ u32 PowerState; // NDIS power state ++ struct _adapter_t *Next; // Linked list ++ ushort AdapterID; // 1..n ++ unsigned char MacAddr[6]; // Our permanent HW mac address ++ unsigned char CurrMacAddr[6]; // Our Current mac address ++ p_net_device netdev; ++ p_net_device next_netdevice; ++ struct pci_dev * pcidev; ++ ++ PSXG_MULTICAST_ADDRESS MulticastAddrs; // Multicast list ++ u64 MulticastMask; // Multicast mask ++ u32 * InterruptHandle; // Register Interrupt handle ++ u32 InterruptLevel; // From Resource list ++ u32 InterruptVector; // From Resource list ++ spinlock_t AdapterLock; /* Serialize access adapter routines */ ++ spinlock_t Bit64RegLock; /* For writing 64-bit addresses */ ++ PSXG_HW_REGS HwRegs; // Sahara HW Register Memory (BAR0/1) ++ PSXG_UCODE_REGS UcodeRegs; // Microcode Register Memory (BAR2/3) ++ PSXG_TCB_REGS TcbRegs; // Same as Ucode regs - See sxghw.h ++ ushort ResetDpcCount; // For timeout ++ ushort RssDpcCount; // For timeout ++ ushort VendorID; // Vendor ID ++ ushort DeviceID; // Device ID ++ ushort SubSystemID; // Sub-System ID ++ ushort FrameSize; // Maximum frame size ++ u32 * DmaHandle; // NDIS DMA handle ++ u32 * PacketPoolHandle; // Used with NDIS 5.2 only. Don't ifdef out ++ u32 * BufferPoolHandle; // Used with NDIS 5.2 only. Don't ifdef out ++ u32 MacFilter; // NDIS MAC Filter ++ ushort IpId; // For slowpath ++ PSXG_EVENT_RING EventRings; // Host event rings. 1/CPU to 16 max ++ dma_addr_t PEventRings; // Physical address ++ u32 NextEvent[SXG_MAX_RSS]; // Current location in ring ++ dma_addr_t PTcbBuffers; // TCB Buffers - physical address ++ dma_addr_t PTcbCompBuffers; // TCB Composite Buffers - phys addr ++ PSXG_XMT_RING XmtRings; // Transmit rings ++ dma_addr_t PXmtRings; // Transmit rings - physical address ++ SXG_RING_INFO XmtRingZeroInfo; // Transmit ring 0 info ++ spinlock_t XmtZeroLock; /* Transmit ring 0 lock */ ++ u32 * XmtRingZeroIndex; // Shared XMT ring 0 index ++ dma_addr_t PXmtRingZeroIndex; // Shared XMT ring 0 index - physical ++ LIST_ENTRY FreeProtocolHeaders;// Free protocol headers ++ u32 FreeProtoHdrCount; // Count ++ void * ProtocolHeaders; // Block of protocol header ++ dma_addr_t PProtocolHeaders; // Block of protocol headers - phys ++ ++ PSXG_RCV_RING RcvRings; // Receive rings ++ dma_addr_t PRcvRings; // Receive rings - physical address ++ SXG_RING_INFO RcvRingZeroInfo; // Receive ring 0 info ++ ++ u32 * Isr; // Interrupt status register ++ dma_addr_t PIsr; // ISR - physical address ++ u32 IsrCopy[SXG_MAX_RSS]; // Copy of ISR ++ ushort InterruptsEnabled; // Bitmask of enabled vectors ++ unsigned char * IndirectionTable; // RSS indirection table ++ dma_addr_t PIndirectionTable; // Physical address ++ ushort RssTableSize; // From NDIS_RECEIVE_SCALE_PARAMETERS ++ ushort HashKeySize; // From NDIS_RECEIVE_SCALE_PARAMETERS ++ unsigned char HashSecretKey[40]; // rss key ++ u32 HashInformation; ++ // Receive buffer queues ++ spinlock_t RcvQLock; /* Receive Queue Lock */ ++ LIST_ENTRY FreeRcvBuffers; // Free SXG_DATA_BUFFER queue ++ LIST_ENTRY FreeRcvBlocks; // Free SXG_RCV_DESCRIPTOR_BLOCK Q ++ LIST_ENTRY AllRcvBlocks; // All SXG_RCV_BLOCKs ++ ushort FreeRcvBufferCount; // Number of free rcv data buffers ++ ushort FreeRcvBlockCount; // # of free rcv descriptor blocks ++ ushort AllRcvBlockCount; // Number of total receive blocks ++ ushort ReceiveBufferSize; // SXG_RCV_DATA/JUMBO_BUFFER_SIZE only ++ u32 AllocationsPending; // Receive allocation pending ++ u32 RcvBuffersOnCard; // SXG_DATA_BUFFERS owned by card ++ // SGL buffers ++ spinlock_t SglQLock; /* SGL Queue Lock */ ++ LIST_ENTRY FreeSglBuffers; // Free SXG_SCATTER_GATHER ++ LIST_ENTRY AllSglBuffers; // All SXG_SCATTER_GATHER ++ ushort FreeSglBufferCount; // Number of free SGL buffers ++ ushort AllSglBufferCount; // Number of total SGL buffers ++ u32 CurrentTime; // Tick count ++ u32 FastpathConnections;// # of fastpath connections ++ // Various single-bit flags: ++ u32 BasicAllocations:1; // Locks and listheads ++ u32 IntRegistered:1; // Interrupt registered ++ u32 PingOutstanding:1; // Ping outstanding to card ++ u32 Dead:1; // Card dead ++ u32 DumpDriver:1; // OID_SLIC_DRIVER_DUMP request ++ u32 DumpCard:1; // OID_SLIC_CARD_DUMP request ++ u32 DumpCmdRunning:1; // Dump command in progress ++ u32 DebugRunning:1; // AGDB debug in progress ++ u32 JumboEnabled:1; // Jumbo frames enabled ++ u32 MsiEnabled:1; // MSI interrupt enabled ++ u32 RssEnabled:1; // RSS Enabled ++ u32 FailOnBadEeprom:1; // Fail on Bad Eeprom ++ u32 DiagStart:1; // Init adapter for diagnostic start ++ // Stats ++ u32 PendingRcvCount; // Outstanding rcv indications ++ u32 PendingXmtCount; // Outstanding send requests ++ SXG_STATS Stats; // Statistics ++ u32 ReassBufs; // Number of reassembly buffers ++ // Card Crash Info ++ ushort CrashLocation; // Microcode crash location ++ unsigned char CrashCpu; // Sahara CPU ID ++ // Diagnostics ++ // PDIAG_CMD DiagCmds; // List of free diagnostic commands ++ // PDIAG_BUFFER DiagBuffers; // List of free diagnostic buffers ++ // PDIAG_REQ DiagReqQ; // List of outstanding (asynchronous) diag requests ++ // u32 DiagCmdTimeout; // Time out for diag cmds (seconds) XXXTODO - replace with SXG_PARAM var? ++ // unsigned char DiagDmaDesc[DMA_CPU_CTXS]; // Free DMA descriptors bit field (32 CPU ctx * 8 DMA ctx) ++ ++ ///////////////////////////////////////////////////////////////////// ++ // Put preprocessor-conditional fields at the end so we don't ++ // have to recompile sxgdbg everytime we reconfigure the driver ++ ///////////////////////////////////////////////////////////////////// ++ void * PendingSetRss; // Pending RSS parameter change ++ u32 IPv4HdrSize; // Shared 5.2/6.0 encap param ++ unsigned char * InterruptInfo; // Allocated by us during AddDevice ++#if defined(CONFIG_X86) ++ u32 AddrUpper; // Upper 32 bits of 64-bit register ++#endif ++ //#if SXG_FAILURE_DUMP ++ // NDIS_EVENT DumpThreadEvent; // syncronize dump thread ++ // BOOLEAN DumpThreadRunning; // termination flag ++ // PSXG_DUMP_CMD DumpBuffer; // 68k - Cmd and Buffer ++ // dma_addr_t PDumpBuffer; // Physical address ++ //#endif // SXG_FAILURE_DUMP ++ ++} adapter_t, *p_adapter_t; ++ ++#if SLIC_DUMP_ENABLED ++#define SLIC_DUMP_REQUESTED 1 ++#define SLIC_DUMP_IN_PROGRESS 2 ++#define SLIC_DUMP_DONE 3 ++ ++/**************************************************************************** ++ * ++ * Microcode crash information structure. This ++ * structure is written out to the card's SRAM when the microcode panic's. ++ * ++ ****************************************************************************/ ++typedef struct _slic_crash_info { ++ ushort cpu_id; ++ ushort crash_pc; ++} slic_crash_info, *p_slic_crash_info; ++ ++#define CRASH_INFO_OFFSET 0x155C ++ ++#endif ++ ++#define UPDATE_STATS(largestat, newstat, oldstat) \ ++{ \ ++ if ((newstat) < (oldstat)) \ ++ (largestat) += ((newstat) + (0xFFFFFFFF - oldstat + 1)); \ ++ else \ ++ (largestat) += ((newstat) - (oldstat)); \ ++} ++ ++#define UPDATE_STATS_GB(largestat, newstat, oldstat) \ ++{ \ ++ (largestat) += ((newstat) - (oldstat)); \ ++} ++ ++#define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \ ++{ \ ++ _Result = TRUE; \ ++ if (*(u32 *)(_AddrA) != *(u32 *)(_AddrB)) \ ++ _Result = FALSE; \ ++ if (*(u16 *)(&((_AddrA)[4])) != *(u16 *)(&((_AddrB)[4]))) \ ++ _Result = FALSE; \ ++} ++ ++#define ETHERMAXFRAME 1514 ++#define JUMBOMAXFRAME 9014 ++ ++#if defined(CONFIG_X86_64) || defined(CONFIG_IA64) ++#define SXG_GET_ADDR_LOW(_addr) (u32)((u64)(_addr) & 0x00000000FFFFFFFF) ++#define SXG_GET_ADDR_HIGH(_addr) (u32)(((u64)(_addr) >> 32) & 0x00000000FFFFFFFF) ++#else ++#define SXG_GET_ADDR_LOW(_addr) (u32)_addr ++#define SXG_GET_ADDR_HIGH(_addr) (u32)0 ++#endif ++ ++#define FLUSH TRUE ++#define DONT_FLUSH FALSE ++ ++#define SIOCSLICDUMPCARD SIOCDEVPRIVATE+9 ++#define SIOCSLICSETINTAGG SIOCDEVPRIVATE+10 ++#define SIOCSLICTRACEDUMP SIOCDEVPRIVATE+11 ++ ++#endif /* __SXG_DRIVER_H__ */ +--- /dev/null ++++ b/drivers/staging/sxg/sxghif.h +@@ -0,0 +1,861 @@ ++/* ++ * Copyright © 1997-2007 Alacritech, Inc. All rights reserved ++ * ++ * $Id: sxghif.h,v 1.5 2008/07/24 19:18:22 chris Exp $ ++ * ++ * sxghif.h: ++ * ++ * This file contains structures and definitions for the ++ * Alacritech Sahara host interface ++ */ ++ ++/******************************************************************************* ++ * UCODE Registers ++ *******************************************************************************/ ++typedef struct _SXG_UCODE_REGS { ++ // Address 0 - 0x3F = Command codes 0-15 for TCB 0. Excode 0 ++ u32 Icr; // Code = 0 (extended), ExCode = 0 - Int control ++ u32 RsvdReg1; // Code = 1 - TOE -NA ++ u32 RsvdReg2; // Code = 2 - TOE -NA ++ u32 RsvdReg3; // Code = 3 - TOE -NA ++ u32 RsvdReg4; // Code = 4 - TOE -NA ++ u32 RsvdReg5; // Code = 5 - TOE -NA ++ u32 CardUp; // Code = 6 - Microcode initialized when 1 ++ u32 RsvdReg7; // Code = 7 - TOE -NA ++ u32 CodeNotUsed[8]; // Codes 8-15 not used. ExCode = 0 ++ // This brings us to ExCode 1 at address 0x40 = Interrupt status pointer ++ u32 Isp; // Code = 0 (extended), ExCode = 1 ++ u32 PadEx1[15]; // Codes 1-15 not used with extended codes ++ // ExCode 2 = Interrupt Status Register ++ u32 Isr; // Code = 0 (extended), ExCode = 2 ++ u32 PadEx2[15]; ++ // ExCode 3 = Event base register. Location of event rings ++ u32 EventBase; // Code = 0 (extended), ExCode = 3 ++ u32 PadEx3[15]; ++ // ExCode 4 = Event ring size ++ u32 EventSize; // Code = 0 (extended), ExCode = 4 ++ u32 PadEx4[15]; ++ // ExCode 5 = TCB Buffers base address ++ u32 TcbBase; // Code = 0 (extended), ExCode = 5 ++ u32 PadEx5[15]; ++ // ExCode 6 = TCB Composite Buffers base address ++ u32 TcbCompBase; // Code = 0 (extended), ExCode = 6 ++ u32 PadEx6[15]; ++ // ExCode 7 = Transmit ring base address ++ u32 XmtBase; // Code = 0 (extended), ExCode = 7 ++ u32 PadEx7[15]; ++ // ExCode 8 = Transmit ring size ++ u32 XmtSize; // Code = 0 (extended), ExCode = 8 ++ u32 PadEx8[15]; ++ // ExCode 9 = Receive ring base address ++ u32 RcvBase; // Code = 0 (extended), ExCode = 9 ++ u32 PadEx9[15]; ++ // ExCode 10 = Receive ring size ++ u32 RcvSize; // Code = 0 (extended), ExCode = 10 ++ u32 PadEx10[15]; ++ // ExCode 11 = Read EEPROM Config ++ u32 Config; // Code = 0 (extended), ExCode = 11 ++ u32 PadEx11[15]; ++ // ExCode 12 = Multicast bits 31:0 ++ u32 McastLow; // Code = 0 (extended), ExCode = 12 ++ u32 PadEx12[15]; ++ // ExCode 13 = Multicast bits 63:32 ++ u32 McastHigh; // Code = 0 (extended), ExCode = 13 ++ u32 PadEx13[15]; ++ // ExCode 14 = Ping ++ u32 Ping; // Code = 0 (extended), ExCode = 14 ++ u32 PadEx14[15]; ++ // ExCode 15 = Link MTU ++ u32 LinkMtu; // Code = 0 (extended), ExCode = 15 ++ u32 PadEx15[15]; ++ // ExCode 16 = Download synchronization ++ u32 LoadSync; // Code = 0 (extended), ExCode = 16 ++ u32 PadEx16[15]; ++ // ExCode 17 = Upper DRAM address bits on 32-bit systems ++ u32 Upper; // Code = 0 (extended), ExCode = 17 ++ u32 PadEx17[15]; ++ // ExCode 18 = Slowpath Send Index Address ++ u32 SPSendIndex; // Code = 0 (extended), ExCode = 18 ++ u32 PadEx18[15]; ++ u32 RsvdXF; // Code = 0 (extended), ExCode = 19 ++ u32 PadEx19[15]; ++ // ExCode 20 = Aggregation ++ u32 Aggregation; // Code = 0 (extended), ExCode = 20 ++ u32 PadEx20[15]; ++ // ExCode 21 = Receive MDL push timer ++ u32 PushTicks; // Code = 0 (extended), ExCode = 21 ++ u32 PadEx21[15]; ++ // ExCode 22 = TOE NA ++ u32 AckFrequency; // Code = 0 (extended), ExCode = 22 ++ u32 PadEx22[15]; ++ // ExCode 23 = TOE NA ++ u32 RsvdReg23; ++ u32 PadEx23[15]; ++ // ExCode 24 = TOE NA ++ u32 RsvdReg24; ++ u32 PadEx24[15]; ++ // ExCode 25 = TOE NA ++ u32 RsvdReg25; // Code = 0 (extended), ExCode = 25 ++ u32 PadEx25[15]; ++ // ExCode 26 = Receive checksum requirements ++ u32 ReceiveChecksum; // Code = 0 (extended), ExCode = 26 ++ u32 PadEx26[15]; ++ // ExCode 27 = RSS Requirements ++ u32 Rss; // Code = 0 (extended), ExCode = 27 ++ u32 PadEx27[15]; ++ // ExCode 28 = RSS Table ++ u32 RssTable; // Code = 0 (extended), ExCode = 28 ++ u32 PadEx28[15]; ++ // ExCode 29 = Event ring release entries ++ u32 EventRelease; // Code = 0 (extended), ExCode = 29 ++ u32 PadEx29[15]; ++ // ExCode 30 = Number of receive bufferlist commands on ring 0 ++ u32 RcvCmd; // Code = 0 (extended), ExCode = 30 ++ u32 PadEx30[15]; ++ // ExCode 31 = slowpath transmit command - Data[31:0] = 1 ++ u32 XmtCmd; // Code = 0 (extended), ExCode = 31 ++ u32 PadEx31[15]; ++ // ExCode 32 = Dump command ++ u32 DumpCmd; // Code = 0 (extended), ExCode = 32 ++ u32 PadEx32[15]; ++ // ExCode 33 = Debug command ++ u32 DebugCmd; // Code = 0 (extended), ExCode = 33 ++ u32 PadEx33[15]; ++ // There are 128 possible extended commands - each of account for 16 ++ // words (including the non-relevent base command codes 1-15). ++ // Pad for the remainder of these here to bring us to the next CPU ++ // base. As extended codes are added, reduce the first array value in ++ // the following field ++ u32 PadToNextCpu[94][16]; // 94 = 128 - 34 (34 = Excodes 0 - 33) ++} SXG_UCODE_REGS, *PSXG_UCODE_REGS; ++ ++// Interrupt control register (0) values ++#define SXG_ICR_DISABLE 0x00000000 ++#define SXG_ICR_ENABLE 0x00000001 ++#define SXG_ICR_MASK 0x00000002 ++#define SXG_ICR_MSGID_MASK 0xFFFF0000 ++#define SXG_ICR_MSGID_SHIFT 16 ++#define SXG_ICR(_MessageId, _Data) \ ++ ((((_MessageId) << SXG_ICR_MSGID_SHIFT) & \ ++ SXG_ICR_MSGID_MASK) | (_Data)) ++ ++// The Microcode supports up to 16 RSS queues ++#define SXG_MAX_RSS 16 ++#define SXG_MAX_RSS_TABLE_SIZE 256 // 256-byte max ++ ++#define SXG_RSS_TCP6 0x00000001 // RSS TCP over IPv6 ++#define SXG_RSS_TCP4 0x00000002 // RSS TCP over IPv4 ++#define SXG_RSS_LEGACY 0x00000004 // Line-base interrupts ++#define SXG_RSS_TABLE_SIZE 0x0000FF00 // Table size mask ++#define SXG_RSS_TABLE_SHIFT 8 ++#define SXG_RSS_BASE_CPU 0x00FF0000 // Base CPU (not used) ++#define SXG_RSS_BASE_SHIFT 16 ++ ++#define SXG_RCV_IP_CSUM_ENABLED 0x00000001 // ExCode 26 (ReceiveChecksum) ++#define SXG_RCV_TCP_CSUM_ENABLED 0x00000002 // ExCode 26 (ReceiveChecksum) ++ ++#define SXG_XMT_CPUID_SHIFT 16 ++ ++#if VPCI ++#define SXG_CHECK_FOR_HANG_TIME 3000 ++#else ++#define SXG_CHECK_FOR_HANG_TIME 5 ++#endif ++ ++/* ++ * TCB registers - This is really the same register memory area as UCODE_REGS ++ * above, but defined differently. Bits 17:06 of the address define the TCB, ++ * which means each TCB area occupies 0x40 (64) bytes, or 16 u32S. What really ++ * is happening is that these registers occupy the "PadEx[15]" areas in the ++ * SXG_UCODE_REGS definition above ++ */ ++typedef struct _SXG_TCB_REGS { ++ u32 ExCode; /* Extended codes - see SXG_UCODE_REGS */ ++ u32 Xmt; /* Code = 1 - # of Xmt descriptors added to ring */ ++ u32 Rcv; /* Code = 2 - # of Rcv descriptors added to ring */ ++ u32 Rsvd1; /* Code = 3 - TOE NA */ ++ u32 Rsvd2; /* Code = 4 - TOE NA */ ++ u32 Rsvd3; /* Code = 5 - TOE NA */ ++ u32 Invalid; /* Code = 6 - Reserved for "CardUp" see above */ ++ u32 Rsvd4; /* Code = 7 - TOE NA */ ++ u32 Rsvd5; /* Code = 8 - TOE NA */ ++ u32 Pad[7]; /* Codes 8-15 - Not used. */ ++} SXG_TCB_REGS, *PSXG_TCB_REGS; ++ ++/*************************************************************************** ++ * ISR Format ++ * 31 0 ++ * _______________________________________ ++ * | | | | | | | | | ++ * |____|____|____|____|____|____|____|____| ++ * ^^^^ ^^^^ ^^^^ ^^^^ \ / ++ * ERR --|||| |||| |||| |||| ----------------- ++ * EVENT ---||| |||| |||| |||| | ++ * ----|| |||| |||| |||| |-- Crash Address ++ * UPC -----| |||| |||| |||| ++ * LEVENT -------|||| |||| |||| ++ * PDQF --------||| |||| |||| ++ * RMISS ---------|| |||| |||| ++ * BREAK ----------| |||| |||| ++ * HBEATOK ------------|||| |||| ++ * NOHBEAT -------------||| |||| ++ * ERFULL --------------|| |||| ++ * XDROP ---------------| |||| ++ * -----------------|||| ++ * -----------------||||--\ ++ * ||---|-CpuId of crash ++ * |----/ ++ ***************************************************************************/ ++#define SXG_ISR_ERR 0x80000000 // Error ++#define SXG_ISR_EVENT 0x40000000 // Event ring event ++#define SXG_ISR_NONE1 0x20000000 // Not used ++#define SXG_ISR_UPC 0x10000000 // Dump/debug command complete ++#define SXG_ISR_LINK 0x08000000 // Link event ++#define SXG_ISR_PDQF 0x04000000 // Processed data queue full ++#define SXG_ISR_RMISS 0x02000000 // Drop - no host buf ++#define SXG_ISR_BREAK 0x01000000 // Breakpoint hit ++#define SXG_ISR_PING 0x00800000 // Heartbeat response ++#define SXG_ISR_DEAD 0x00400000 // Card crash ++#define SXG_ISR_ERFULL 0x00200000 // Event ring full ++#define SXG_ISR_XDROP 0x00100000 // XMT Drop - no DRAM bufs or XMT err ++#define SXG_ISR_SPSEND 0x00080000 // Slow send complete ++#define SXG_ISR_CPU 0x00070000 // Dead CPU mask ++#define SXG_ISR_CPU_SHIFT 16 // Dead CPU shift ++#define SXG_ISR_CRASH 0x0000FFFF // Crash address mask ++ ++/*************************************************************************** ++ * ++ * Event Ring entry ++ * ++ ***************************************************************************/ ++/* ++ * 31 15 0 ++ * .___________________.___________________. ++ * |<------------ Pad 0 ------------>| ++ * |_________|_________|_________|_________|0 0x00 ++ * |<------------ Pad 1 ------------>| ++ * |_________|_________|_________|_________|4 0x04 ++ * |<------------ Pad 2 ------------>| ++ * |_________|_________|_________|_________|8 0x08 ++ * |<----------- Event Word 0 ------------>| ++ * |_________|_________|_________|_________|12 0x0c ++ * |<----------- Event Word 1 ------------>| ++ * |_________|_________|_________|_________|16 0x10 ++ * |<------------- Toeplitz ------------>| ++ * |_________|_________|_________|_________|20 0x14 ++ * |<----- Length ---->|<------ TCB Id --->| ++ * |_________|_________|_________|_________|24 0x18 ++ * |<----- Status ---->|Evnt Code|Flsh Code| ++ * |_________|_________|_________|_________|28 0x1c ++ * ^ ^^^^ ^^^^ ++ * |- VALID |||| ||||- RBUFC ++ * |||| |||-- SLOWR ++ * |||| ||--- UNUSED ++ * |||| |---- FASTC ++ * ||||------ FASTR ++ * |||------- ++ * ||-------- ++ * |--------- ++ * ++ * Slowpath status: ++ * _______________________________________ ++ * |<----- Status ---->|Evnt Code|Flsh Code| ++ * |_________|Cmd Index|_________|_________|28 0x1c ++ * ^^^ ^^^^ ++ * ||| ||||- ISTCPIP6 ++ * ||| |||-- IPONLY ++ * ||| ||--- RCVERR ++ * ||| |---- IPCBAD ++ * |||------ TCPCBAD ++ * ||------- ISTCPIP ++ * |-------- SCERR ++ * ++ */ ++#pragma pack(push, 1) ++typedef struct _SXG_EVENT { ++ u32 Pad[1]; // not used ++ u32 SndUna; // SndUna value ++ u32 Resid; // receive MDL resid ++ union { ++ void * HostHandle; // Receive host handle ++ u32 Rsvd1; // TOE NA ++ struct { ++ u32 NotUsed; ++ u32 Rsvd2; // TOE NA ++ } Flush; ++ }; ++ u32 Toeplitz; // RSS Toeplitz hash ++ union { ++ ushort Rsvd3; // TOE NA ++ ushort HdrOffset; // Slowpath ++ }; ++ ushort Length; // ++ unsigned char Rsvd4; // TOE NA ++ unsigned char Code; // Event code ++ unsigned char CommandIndex; // New ring index ++ unsigned char Status; // Event status ++} SXG_EVENT, *PSXG_EVENT; ++#pragma pack(pop) ++ ++// Event code definitions ++#define EVENT_CODE_BUFFERS 0x01 // Receive buffer list command (ring 0) ++#define EVENT_CODE_SLOWRCV 0x02 // Slowpath receive ++#define EVENT_CODE_UNUSED 0x04 // Was slowpath commands complete ++ ++// Status values ++#define EVENT_STATUS_VALID 0x80 // Entry valid ++ ++// Slowpath status ++#define EVENT_STATUS_ERROR 0x40 // Completed with error. Index in next byte ++#define EVENT_STATUS_TCPIP4 0x20 // TCPIPv4 frame ++#define EVENT_STATUS_TCPBAD 0x10 // Bad TCP checksum ++#define EVENT_STATUS_IPBAD 0x08 // Bad IP checksum ++#define EVENT_STATUS_RCVERR 0x04 // Slowpath receive error ++#define EVENT_STATUS_IPONLY 0x02 // IP frame ++#define EVENT_STATUS_TCPIP6 0x01 // TCPIPv6 frame ++#define EVENT_STATUS_TCPIP 0x21 // Combination of v4 and v6 ++ ++// Event ring ++// Size must be power of 2, between 128 and 16k ++#define EVENT_RING_SIZE 4096 // ?? ++#define EVENT_RING_BATCH 16 // Hand entries back 16 at a time. ++#define EVENT_BATCH_LIMIT 256 // Stop processing events after 256 (16 * 16) ++ ++typedef struct _SXG_EVENT_RING { ++ SXG_EVENT Ring[EVENT_RING_SIZE]; ++}SXG_EVENT_RING, *PSXG_EVENT_RING; ++ ++/*************************************************************************** ++ * ++ * TCB Buffers ++ * ++ ***************************************************************************/ ++// Maximum number of TCBS supported by hardware/microcode ++#define SXG_MAX_TCB 4096 ++// Minimum TCBs before we fail initialization ++#define SXG_MIN_TCB 512 ++// TCB Hash ++// The bucket is determined by bits 11:4 of the toeplitz if we support 4k ++// offloaded connections, 10:4 if we support 2k and so on. ++#define SXG_TCB_BUCKET_SHIFT 4 ++#define SXG_TCB_PER_BUCKET 16 ++#define SXG_TCB_BUCKET_MASK 0xFF0 // Bucket portion of TCB ID ++#define SXG_TCB_ELEMENT_MASK 0x00F // Element within bucket ++#define SXG_TCB_BUCKETS 256 // 256 * 16 = 4k ++ ++#define SXG_TCB_BUFFER_SIZE 512 // ASSERT format is correct ++ ++#define SXG_TCB_RCVQ_SIZE 736 ++ ++#define SXG_TCB_COMPOSITE_BUFFER_SIZE 1024 ++ ++#define SXG_LOCATE_TCP_FRAME_HDR(_TcpObject, _IPv6) \ ++ (((_TcpObject)->VlanId) ? \ ++ ((_IPv6) ? /* Vlan frame header = yes */ \ ++ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.SxgTcp : \ ++ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp.SxgTcp) : \ ++ ((_IPv6) ? /* Vlan frame header = No */ \ ++ &(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp6.SxgTcp : \ ++ &(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp.SxgTcp)) ++ ++#define SXG_LOCATE_IP_FRAME_HDR(_TcpObject) \ ++ (_TcpObject)->VlanId ? \ ++ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp.Ip : \ ++ &(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp.Ip ++ ++#define SXG_LOCATE_IP6_FRAME_HDR(_TcpObject) \ ++ (_TcpObject)->VlanId ? \ ++ &(_TcpObject)->CompBuffer->Frame.HasVlan.TcpIp6.Ip : \ ++ &(_TcpObject)->CompBuffer->Frame.NoVlan.TcpIp6.Ip ++ ++ ++#if DBG ++// Horrible kludge to distinguish dumb-nic, slowpath, and ++// fastpath traffic. Decrement the HopLimit by one ++// for slowpath, two for fastpath. This assumes the limit is measurably ++// greater than two, which I think is reasonable. ++// Obviously this is DBG only. Maybe remove later, or #if 0 so we ++// can set it when needed ++#define SXG_DBG_HOP_LIMIT(_TcpObject, _FastPath) { \ ++ PIPV6_HDR _Ip6FrameHdr; \ ++ if((_TcpObject)->IPv6) { \ ++ _Ip6FrameHdr = SXG_LOCATE_IP6_FRAME_HDR((_TcpObject)); \ ++ if(_FastPath) { \ ++ _Ip6FrameHdr->HopLimit = (_TcpObject)->Cached.TtlOrHopLimit - 2; \ ++ } else { \ ++ _Ip6FrameHdr->HopLimit = (_TcpObject)->Cached.TtlOrHopLimit - 1; \ ++ } \ ++ } \ ++} ++#else ++// Do nothing with free build ++#define SXG_DBG_HOP_LIMIT(_TcpObject, _FastPath) ++#endif ++ ++/*************************************************************************** ++ * Receive and transmit rings ++ ***************************************************************************/ ++#define SXG_MAX_RING_SIZE 256 ++#define SXG_XMT_RING_SIZE 128 // Start with 128 ++#define SXG_RCV_RING_SIZE 128 // Start with 128 ++#define SXG_MAX_ENTRIES 4096 ++ ++// Structure and macros to manage a ring ++typedef struct _SXG_RING_INFO { ++ unsigned char Head; // Where we add entries - Note unsigned char:RING_SIZE ++ unsigned char Tail; // Where we pull off completed entries ++ ushort Size; // Ring size - Must be multiple of 2 ++ void * Context[SXG_MAX_RING_SIZE]; // Shadow ring ++} SXG_RING_INFO, *PSXG_RING_INFO; ++ ++#define SXG_INITIALIZE_RING(_ring, _size) { \ ++ (_ring).Head = 0; \ ++ (_ring).Tail = 0; \ ++ (_ring).Size = (_size); \ ++} ++#define SXG_ADVANCE_INDEX(_index, _size) ((_index) = ((_index) + 1) & ((_size) - 1)) ++#define SXG_PREVIOUS_INDEX(_index, _size) (((_index) - 1) &((_size) - 1)) ++#define SXG_RING_EMPTY(_ring) ((_ring)->Head == (_ring)->Tail) ++#define SXG_RING_FULL(_ring) ((((_ring)->Head + 1) & ((_ring)->Size - 1)) == (_ring)->Tail) ++#define SXG_RING_ADVANCE_HEAD(_ring) SXG_ADVANCE_INDEX((_ring)->Head, ((_ring)->Size)) ++#define SXG_RING_RETREAT_HEAD(_ring) ((_ring)->Head = \ ++ SXG_PREVIOUS_INDEX((_ring)->Head, (_ring)->Size)) ++#define SXG_RING_ADVANCE_TAIL(_ring) { \ ++ ASSERT((_ring)->Tail != (_ring)->Head); \ ++ SXG_ADVANCE_INDEX((_ring)->Tail, ((_ring)->Size)); \ ++} ++// Set cmd to the next available ring entry, set the shadow context ++// entry and advance the ring. ++// The appropriate lock must be held when calling this macro ++#define SXG_GET_CMD(_ring, _ringinfo, _cmd, _context) { \ ++ if(SXG_RING_FULL(_ringinfo)) { \ ++ (_cmd) = NULL; \ ++ } else { \ ++ (_cmd) = &(_ring)->Descriptors[(_ringinfo)->Head]; \ ++ (_ringinfo)->Context[(_ringinfo)->Head] = (void *)(_context);\ ++ SXG_RING_ADVANCE_HEAD(_ringinfo); \ ++ } \ ++} ++ ++// Abort the previously allocated command by retreating the head. ++// NOTE - The appopriate lock MUST NOT BE DROPPED between the SXG_GET_CMD ++// and SXG_ABORT_CMD calls. ++#define SXG_ABORT_CMD(_ringinfo) { \ ++ ASSERT(!(SXG_RING_EMPTY(_ringinfo))); \ ++ SXG_RING_RETREAT_HEAD(_ringinfo); \ ++ (_ringinfo)->Context[(_ringinfo)->Head] = NULL; \ ++} ++ ++// For the given ring, return a pointer to the tail cmd and context, ++// clear the context and advance the tail ++#define SXG_RETURN_CMD(_ring, _ringinfo, _cmd, _context) { \ ++ (_cmd) = &(_ring)->Descriptors[(_ringinfo)->Tail]; \ ++ (_context) = (_ringinfo)->Context[(_ringinfo)->Tail]; \ ++ (_ringinfo)->Context[(_ringinfo)->Tail] = NULL; \ ++ SXG_RING_ADVANCE_TAIL(_ringinfo); \ ++} ++ ++/*************************************************************************** ++ * ++ * Host Command Buffer - commands to INIC via the Cmd Rings ++ * ++ ***************************************************************************/ ++/* ++ * 31 15 0 ++ * .___________________.___________________. ++ * |<-------------- Sgl Low -------------->| ++ * |_________|_________|_________|_________|0 0x00 ++ * |<-------------- Sgl High ------------->| ++ * |_________|_________|_________|_________|4 0x04 ++ * |<------------- Sge 0 Low ----------->| ++ * |_________|_________|_________|_________|8 0x08 ++ * |<------------- Sge 0 High ----------->| ++ * |_________|_________|_________|_________|12 0x0c ++ * |<------------ Sge 0 Length ---------->| ++ * |_________|_________|_________|_________|16 0x10 ++ * |<----------- Window Update ----------->| ++ * |<-------- SP 1st SGE offset ---------->| ++ * |_________|_________|_________|_________|20 0x14 ++ * |<----------- Total Length ------------>| ++ * |_________|_________|_________|_________|24 0x18 ++ * |<----- LCnt ------>|<----- Flags ----->| ++ * |_________|_________|_________|_________|28 0x1c ++ */ ++#pragma pack(push, 1) ++typedef struct _SXG_CMD { ++ dma_addr_t Sgl; // Physical address of SGL ++ union { ++ struct { ++ dma64_addr_t FirstSgeAddress;// Address of first SGE ++ u32 FirstSgeLength; // Length of first SGE ++ union { ++ u32 Rsvd1; // TOE NA ++ u32 SgeOffset; // Slowpath - 2nd SGE offset ++ u32 Resid; // MDL completion - clobbers update ++ }; ++ union { ++ u32 TotalLength; // Total transfer length ++ u32 Mss; // LSO MSS ++ }; ++ } Buffer; ++ }; ++ union { ++ struct { ++ unsigned char Flags:4; // slowpath flags ++ unsigned char IpHl:4; // Ip header length (>>2) ++ unsigned char MacLen; // Mac header len ++ } CsumFlags; ++ struct { ++ ushort Flags:4; // slowpath flags ++ ushort TcpHdrOff:7; // TCP ++ ushort MacLen:5; // Mac header len ++ } LsoFlags; ++ ushort Flags; // flags ++ }; ++ union { ++ ushort SgEntries; // SG entry count including first sge ++ struct { ++ unsigned char Status; // Copied from event status ++ unsigned char NotUsed; ++ } Status; ++ }; ++} SXG_CMD, *PSXG_CMD; ++#pragma pack(pop) ++ ++#pragma pack(push, 1) ++typedef struct _VLAN_HDR { ++ ushort VlanTci; ++ ushort VlanTpid; ++} VLAN_HDR, *PVLAN_HDR; ++#pragma pack(pop) ++ ++/* ++ * Slowpath Flags: ++ * ++ * ++ * LSS Flags: ++ * .--- ++ * /.--- TCP Large segment send ++ * //.--- ++ * ///.--- ++ * 3 1 1 //// ++ * 1 5 0 |||| ++ * .___________________.____________vvvv. ++ * | |MAC | TCP | | ++ * | LCnt |hlen|hdroff|Flgs| ++ * |___________________|||||||||||||____| ++ * ++ * ++ * Checksum Flags ++ * ++ * .--- ++ * /.--- ++ * //.--- Checksum TCP ++ * ///.--- Checksum IP ++ * 3 1 //// No bits - normal send ++ * 1 5 7 |||| ++ * .___________________._______________vvvv. ++ * | | Offload | IP | | ++ * | LCnt |MAC hlen |Hlen|Flgs| ++ * |___________________|____|____|____|____| ++ * ++ */ ++// Slowpath CMD flags ++#define SXG_SLOWCMD_CSUM_IP 0x01 // Checksum IP ++#define SXG_SLOWCMD_CSUM_TCP 0x02 // Checksum TCP ++#define SXG_SLOWCMD_LSO 0x04 // Large segment send ++ ++typedef struct _SXG_XMT_RING { ++ SXG_CMD Descriptors[SXG_XMT_RING_SIZE]; ++} SXG_XMT_RING, *PSXG_XMT_RING; ++ ++typedef struct _SXG_RCV_RING { ++ SXG_CMD Descriptors[SXG_RCV_RING_SIZE]; ++} SXG_RCV_RING, *PSXG_RCV_RING; ++ ++/*************************************************************************** ++ * Share memory buffer types - Used to identify asynchronous ++ * shared memory allocation ++ ***************************************************************************/ ++typedef enum { ++ SXG_BUFFER_TYPE_RCV, // Receive buffer ++ SXG_BUFFER_TYPE_SGL // SGL buffer ++} SXG_BUFFER_TYPE; ++ ++// State for SXG buffers ++#define SXG_BUFFER_FREE 0x01 ++#define SXG_BUFFER_BUSY 0x02 ++#define SXG_BUFFER_ONCARD 0x04 ++#define SXG_BUFFER_UPSTREAM 0x08 ++ ++/*************************************************************************** ++ * Receive data buffers ++ * ++ * Receive data buffers are given to the Sahara card 128 at a time. ++ * This is accomplished by filling in a "receive descriptor block" ++ * with 128 "receive descriptors". Each descriptor consists of ++ * a physical address, which the card uses as the address to ++ * DMA data into, and a virtual address, which is given back ++ * to the host in the "HostHandle" portion of an event. ++ * The receive descriptor data structure is defined below ++ * as SXG_RCV_DATA_DESCRIPTOR, and the corresponding block ++ * is defined as SXG_RCV_DESCRIPTOR_BLOCK. ++ * ++ * This receive descriptor block is given to the card by filling ++ * in the Sgl field of a SXG_CMD entry from pAdapt->RcvRings[0] ++ * with the physical address of the receive descriptor block. ++ * ++ * Both the receive buffers and the receive descriptor blocks ++ * require additional data structures to maintain them ++ * on a free queue and contain other information associated with them. ++ * Those data structures are defined as the SXG_RCV_DATA_BUFFER_HDR ++ * and SXG_RCV_DESCRIPTOR_BLOCK_HDR respectively. ++ * ++ * Since both the receive buffers and the receive descriptor block ++ * must be accessible by the card, both must be allocated out of ++ * shared memory. To ensure that we always have a descriptor ++ * block available for every 128 buffers, we allocate all of ++ * these resources together in a single block. This entire ++ * block is managed by a SXG_RCV_BLOCK_HDR, who's sole purpose ++ * is to maintain address information so that the entire block ++ * can be free later. ++ * ++ * Further complicating matters is the fact that the receive ++ * buffers must be variable in length in order to accomodate ++ * jumbo frame configurations. We configure the buffer ++ * length so that the buffer and it's corresponding SXG_RCV_DATA_BUFFER_HDR ++ * structure add up to an even boundary. Then we place the ++ * remaining data structures after 128 of them as shown in ++ * the following diagram: ++ * ++ * _________________________________________ ++ * | | ++ * | Variable length receive buffer #1 | ++ * |_________________________________________| ++ * | | ++ * | SXG_RCV_DATA_BUFFER_HDR #1 | ++ * |_________________________________________| <== Even 2k or 10k boundary ++ * | | ++ * | ... repeat 2-128 .. | ++ * |_________________________________________| ++ * | | ++ * | SXG_RCV_DESCRIPTOR_BLOCK | ++ * | Contains SXG_RCV_DATA_DESCRIPTOR * 128 | ++ * |_________________________________________| ++ * | | ++ * | SXG_RCV_DESCRIPTOR_BLOCK_HDR | ++ * |_________________________________________| ++ * | | ++ * | SXG_RCV_BLOCK_HDR | ++ * |_________________________________________| ++ * ++ * Memory consumption: ++ * Non-jumbo: ++ * Buffers and SXG_RCV_DATA_BUFFER_HDR = 2k * 128 = 256k ++ * + SXG_RCV_DESCRIPTOR_BLOCK = 2k ++ * + SXG_RCV_DESCRIPTOR_BLOCK_HDR = ~32 ++ * + SXG_RCV_BLOCK_HDR = ~32 ++ * => Total = ~258k/block ++ * ++ * Jumbo: ++ * Buffers and SXG_RCV_DATA_BUFFER_HDR = 10k * 128 = 1280k ++ * + SXG_RCV_DESCRIPTOR_BLOCK = 2k ++ * + SXG_RCV_DESCRIPTOR_BLOCK_HDR = ~32 ++ * + SXG_RCV_BLOCK_HDR = ~32 ++ * => Total = ~1282k/block ++ * ++ ***************************************************************************/ ++#define SXG_RCV_DATA_BUFFERS 4096 // Amount to give to the card ++#define SXG_INITIAL_RCV_DATA_BUFFERS 8192 // Initial pool of buffers ++#define SXG_MIN_RCV_DATA_BUFFERS 2048 // Minimum amount and when to get more ++#define SXG_MAX_RCV_BLOCKS 128 // = 16384 receive buffers ++ ++// Receive buffer header ++typedef struct _SXG_RCV_DATA_BUFFER_HDR { ++ dma_addr_t PhysicalAddress; // Buffer physical address ++ // Note - DO NOT USE the VirtualAddress field to locate data. ++ // Use the sxg.h:SXG_RECEIVE_DATA_LOCATION macro instead. ++ void *VirtualAddress; // Start of buffer ++ LIST_ENTRY FreeList; // Free queue of buffers ++ struct _SXG_RCV_DATA_BUFFER_HDR *Next; // Fastpath data buffer queue ++ u32 Size; // Buffer size ++ u32 ByteOffset; // See SXG_RESTORE_MDL_OFFSET ++ unsigned char State; // See SXG_BUFFER state above ++ unsigned char Status; // Event status (to log PUSH) ++ struct sk_buff * skb; // Double mapped (nbl and pkt) ++} SXG_RCV_DATA_BUFFER_HDR, *PSXG_RCV_DATA_BUFFER_HDR; ++ ++// SxgSlowReceive uses the PACKET (skb) contained ++// in the SXG_RCV_DATA_BUFFER_HDR when indicating dumb-nic data ++#define SxgDumbRcvPacket skb ++ ++#define SXG_RCV_DATA_HDR_SIZE 256 // Space for SXG_RCV_DATA_BUFFER_HDR ++#define SXG_RCV_DATA_BUFFER_SIZE 2048 // Non jumbo = 2k including HDR ++#define SXG_RCV_JUMBO_BUFFER_SIZE 10240 // jumbo = 10k including HDR ++ ++// Receive data descriptor ++typedef struct _SXG_RCV_DATA_DESCRIPTOR { ++ union { ++ struct sk_buff * VirtualAddress; // Host handle ++ u64 ForceTo8Bytes; // Force x86 to 8-byte boundary ++ }; ++ dma_addr_t PhysicalAddress; ++} SXG_RCV_DATA_DESCRIPTOR, *PSXG_RCV_DATA_DESCRIPTOR; ++ ++// Receive descriptor block ++#define SXG_RCV_DESCRIPTORS_PER_BLOCK 128 ++#define SXG_RCV_DESCRIPTOR_BLOCK_SIZE 2048 // For sanity check ++typedef struct _SXG_RCV_DESCRIPTOR_BLOCK { ++ SXG_RCV_DATA_DESCRIPTOR Descriptors[SXG_RCV_DESCRIPTORS_PER_BLOCK]; ++} SXG_RCV_DESCRIPTOR_BLOCK, *PSXG_RCV_DESCRIPTOR_BLOCK; ++ ++// Receive descriptor block header ++typedef struct _SXG_RCV_DESCRIPTOR_BLOCK_HDR { ++ void * VirtualAddress; // Start of 2k buffer ++ dma_addr_t PhysicalAddress; // ..and it's physical address ++ LIST_ENTRY FreeList; // Free queue of descriptor blocks ++ unsigned char State; // See SXG_BUFFER state above ++} SXG_RCV_DESCRIPTOR_BLOCK_HDR, *PSXG_RCV_DESCRIPTOR_BLOCK_HDR; ++ ++// Receive block header ++typedef struct _SXG_RCV_BLOCK_HDR { ++ void * VirtualAddress; // Start of virtual memory ++ dma_addr_t PhysicalAddress; // ..and it's physical address ++ LIST_ENTRY AllList; // Queue of all SXG_RCV_BLOCKS ++} SXG_RCV_BLOCK_HDR, *PSXG_RCV_BLOCK_HDR; ++ ++// Macros to determine data structure offsets into receive block ++#define SXG_RCV_BLOCK_SIZE(_Buffersize) \ ++ (((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) + \ ++ (sizeof(SXG_RCV_DESCRIPTOR_BLOCK)) + \ ++ (sizeof(SXG_RCV_DESCRIPTOR_BLOCK_HDR)) + \ ++ (sizeof(SXG_RCV_BLOCK_HDR))) ++#define SXG_RCV_BUFFER_DATA_SIZE(_Buffersize) \ ++ ((_Buffersize) - SXG_RCV_DATA_HDR_SIZE) ++#define SXG_RCV_DATA_BUFFER_HDR_OFFSET(_Buffersize) \ ++ ((_Buffersize) - SXG_RCV_DATA_HDR_SIZE) ++#define SXG_RCV_DESCRIPTOR_BLOCK_OFFSET(_Buffersize) \ ++ ((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) ++#define SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET(_Buffersize) \ ++ (((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) + \ ++ (sizeof(SXG_RCV_DESCRIPTOR_BLOCK))) ++#define SXG_RCV_BLOCK_HDR_OFFSET(_Buffersize) \ ++ (((_Buffersize) * SXG_RCV_DESCRIPTORS_PER_BLOCK) + \ ++ (sizeof(SXG_RCV_DESCRIPTOR_BLOCK)) + \ ++ (sizeof(SXG_RCV_DESCRIPTOR_BLOCK_HDR))) ++ ++// Use the miniport reserved portion of the NBL to locate ++// our SXG_RCV_DATA_BUFFER_HDR structure. ++typedef struct _SXG_RCV_NBL_RESERVED { ++ PSXG_RCV_DATA_BUFFER_HDR RcvDataBufferHdr; ++ void * Available; ++} SXG_RCV_NBL_RESERVED, *PSXG_RCV_NBL_RESERVED; ++ ++#define SXG_RCV_NBL_BUFFER_HDR(_NBL) (((PSXG_RCV_NBL_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(_NBL))->RcvDataBufferHdr) ++ ++/*************************************************************************** ++ * Scatter gather list buffer ++ ***************************************************************************/ ++#define SXG_INITIAL_SGL_BUFFERS 8192 // Initial pool of SGL buffers ++#define SXG_MIN_SGL_BUFFERS 2048 // Minimum amount and when to get more ++#define SXG_MAX_SGL_BUFFERS 16384 // Maximum to allocate (note ADAPT:ushort) ++ ++ ++// Self identifying structure type ++typedef enum _SXG_SGL_TYPE { ++ SXG_SGL_DUMB, // Dumb NIC SGL ++ SXG_SGL_SLOW, // Slowpath protocol header - see below ++ SXG_SGL_CHIMNEY // Chimney offload SGL ++} SXG_SGL_TYPE, PSXG_SGL_TYPE; ++ ++// Note - the description below is Microsoft specific ++// ++// The following definition specifies the amount of shared memory to allocate ++// for the SCATTER_GATHER_LIST portion of the SXG_SCATTER_GATHER data structure. ++// The following considerations apply when setting this value: ++// - First, the Sahara card is designed to read the Microsoft SGL structure ++// straight out of host memory. This means that the SGL must reside in ++// shared memory. If the length here is smaller than the SGL for the ++// NET_BUFFER, then NDIS will allocate its own buffer. The buffer ++// that NDIS allocates is not in shared memory, so when this happens, ++// the SGL will need to be copied to a set of SXG_SCATTER_GATHER buffers. ++// In other words.. we don't want this value to be too small. ++// - On the other hand.. we're allocating up to 16k of these things. If ++// we make this too big, we start to consume a ton of memory.. ++// At the moment, I'm going to limit the number of SG entries to 150. ++// If each entry maps roughly 4k, then this should cover roughly 600kB ++// NET_BUFFERs. Furthermore, since each entry is 24 bytes, the total ++// SGE portion of the structure consumes 3600 bytes, which should allow ++// the entire SXG_SCATTER_GATHER structure to reside comfortably within ++// a 4k block, providing the remaining fields stay under 500 bytes. ++// ++// So with 150 entries, the SXG_SCATTER_GATHER structure becomes roughly ++// 4k. At 16k of them, that amounts to 64M of shared memory. A ton, but ++// manageable. ++#define SXG_SGL_ENTRIES 150 ++ ++// The ucode expects an NDIS SGL structure that ++// is formatted for an x64 system. When running ++// on an x64 system, we can simply hand the NDIS SGL ++// to the card directly. For x86 systems we must reconstruct ++// the SGL. The following structure defines an x64 ++// formatted SGL entry ++typedef struct _SXG_X64_SGE { ++ dma64_addr_t Address; // same as wdm.h ++ u32 Length; // same as wdm.h ++ u32 CompilerPad;// The compiler pads to 8-bytes ++ u64 Reserved; // u32 * in wdm.h. Force to 8 bytes ++} SXG_X64_SGE, *PSXG_X64_SGE; ++ ++typedef struct _SCATTER_GATHER_ELEMENT { ++ dma64_addr_t Address; // same as wdm.h ++ u32 Length; // same as wdm.h ++ u32 CompilerPad;// The compiler pads to 8-bytes ++ u64 Reserved; // u32 * in wdm.h. Force to 8 bytes ++} SCATTER_GATHER_ELEMENT, *PSCATTER_GATHER_ELEMENT; ++ ++ ++typedef struct _SCATTER_GATHER_LIST { ++ u32 NumberOfElements; ++ u32 * Reserved; ++ SCATTER_GATHER_ELEMENT Elements[]; ++} SCATTER_GATHER_LIST, *PSCATTER_GATHER_LIST; ++ ++// The card doesn't care about anything except elements, so ++// we can leave the u32 * reserved field alone in the following ++// SGL structure. But redefine from wdm.h:SCATTER_GATHER_LIST so ++// we can specify SXG_X64_SGE and define a fixed number of elements ++typedef struct _SXG_X64_SGL { ++ u32 NumberOfElements; ++ u32 * Reserved; ++ SXG_X64_SGE Elements[SXG_SGL_ENTRIES]; ++} SXG_X64_SGL, *PSXG_X64_SGL; ++ ++typedef struct _SXG_SCATTER_GATHER { ++ SXG_SGL_TYPE Type; // FIRST! Dumb-nic or offload ++ void * adapter; // Back pointer to adapter ++ LIST_ENTRY FreeList; // Free SXG_SCATTER_GATHER blocks ++ LIST_ENTRY AllList; // All SXG_SCATTER_GATHER blocks ++ dma_addr_t PhysicalAddress;// physical address ++ unsigned char State; // See SXG_BUFFER state above ++ unsigned char CmdIndex; // Command ring index ++ struct sk_buff * DumbPacket; // Associated Packet ++ u32 Direction; // For asynchronous completions ++ u32 CurOffset; // Current SGL offset ++ u32 SglRef; // SGL reference count ++ VLAN_HDR VlanTag; // VLAN tag to be inserted into SGL ++ PSCATTER_GATHER_LIST pSgl; // SGL Addr. Possibly &Sgl ++ SXG_X64_SGL Sgl; // SGL handed to card ++} SXG_SCATTER_GATHER, *PSXG_SCATTER_GATHER; ++ ++#if defined(CONFIG_X86_64) ++#define SXG_SGL_BUFFER(_SxgSgl) (&_SxgSgl->Sgl) ++#define SXG_SGL_BUF_SIZE sizeof(SXG_X64_SGL) ++#elif defined(CONFIG_X86) ++// Force NDIS to give us it's own buffer so we can reformat to our own ++#define SXG_SGL_BUFFER(_SxgSgl) NULL ++#define SXG_SGL_BUF_SIZE 0 ++#else ++ Stop Compilation; ++#endif ++ +--- /dev/null ++++ b/drivers/staging/sxg/sxghw.h +@@ -0,0 +1,734 @@ ++/* ++ * Copyright © 1997-2007 Alacritech, Inc. All rights reserved ++ * ++ * $Id: sxghw.h,v 1.2 2008/07/24 17:24:23 chris Exp $ ++ * ++ * sxghw.h: ++ * ++ * This file contains structures and definitions for the ++ * Alacritech Sahara hardware ++ */ ++ ++ ++/******************************************************************************* ++ * Configuration space ++ *******************************************************************************/ ++// PCI Vendor ID ++#define SXG_VENDOR_ID 0x139A // Alacritech's Vendor ID ++ ++// PCI Device ID ++#define SXG_DEVICE_ID 0x0009 // Sahara Device ID ++ ++// ++// Subsystem IDs. ++// ++// The subsystem ID value is broken into bit fields as follows: ++// Bits [15:12] - Function ++// Bits [11:8] - OEM and/or operating system. ++// Bits [7:0] - Base SID. ++// ++// SSID field (bit) masks ++#define SSID_BASE_MASK 0x00FF // Base subsystem ID mask ++#define SSID_OEM_MASK 0x0F00 // Subsystem OEM mask ++#define SSID_FUNC_MASK 0xF000 // Subsystem function mask ++ ++// Base SSID's ++#define SSID_SAHARA_PROTO 0x0018 // 100022 Sahara prototype (XenPak) board ++#define SSID_SAHARA_FIBER 0x0019 // 100023 Sahara 1-port fiber board ++#define SSID_SAHARA_COPPER 0x001A // 100024 Sahara 1-port copper board ++ ++// Useful SSID macros ++#define SSID_BASE(ssid) ((ssid) & SSID_BASE_MASK) // isolate base SSID bits ++#define SSID_OEM(ssid) ((ssid) & SSID_OEM_MASK) // isolate SSID OEM bits ++#define SSID_FUNC(ssid) ((ssid) & SSID_FUNC_MASK) // isolate SSID function bits ++ ++/******************************************************************************* ++ * HW Register Space ++ *******************************************************************************/ ++#define SXG_HWREG_MEMSIZE 0x4000 // 16k ++ ++#pragma pack(push, 1) ++typedef struct _SXG_HW_REGS { ++ u32 Reset; // Write 0xdead to invoke soft reset ++ u32 Pad1; // No register defined at offset 4 ++ u32 InterruptMask0; // Deassert legacy interrupt on function 0 ++ u32 InterruptMask1; // Deassert legacy interrupt on function 1 ++ u32 UcodeDataLow; // Store microcode instruction bits 31-0 ++ u32 UcodeDataMiddle; // Store microcode instruction bits 63-32 ++ u32 UcodeDataHigh; // Store microcode instruction bits 95-64 ++ u32 UcodeAddr; // Store microcode address - See flags below ++ u32 PadTo0x80[24]; // Pad to Xcv configuration registers ++ u32 MacConfig0; // 0x80 - AXGMAC Configuration Register 0 ++ u32 MacConfig1; // 0x84 - AXGMAC Configuration Register 1 ++ u32 MacConfig2; // 0x88 - AXGMAC Configuration Register 2 ++ u32 MacConfig3; // 0x8C - AXGMAC Configuration Register 3 ++ u32 MacAddressLow; // 0x90 - AXGMAC MAC Station Address - octets 1-4 ++ u32 MacAddressHigh; // 0x94 - AXGMAC MAC Station Address - octets 5-6 ++ u32 MacReserved1[2]; // 0x98 - AXGMAC Reserved ++ u32 MacMaxFrameLen; // 0xA0 - AXGMAC Maximum Frame Length ++ u32 MacReserved2[2]; // 0xA4 - AXGMAC Reserved ++ u32 MacRevision; // 0xAC - AXGMAC Revision Level Register ++ u32 MacReserved3[4]; // 0xB0 - AXGMAC Reserved ++ u32 MacAmiimCmd; // 0xC0 - AXGMAC AMIIM Command Register ++ u32 MacAmiimField; // 0xC4 - AXGMAC AMIIM Field Register ++ u32 MacAmiimConfig; // 0xC8 - AXGMAC AMIIM Configuration Register ++ u32 MacAmiimLink; // 0xCC - AXGMAC AMIIM Link Fail Vector Register ++ u32 MacAmiimIndicator; // 0xD0 - AXGMAC AMIIM Indicator Registor ++ u32 PadTo0x100[11]; // 0xD4 - 0x100 - Pad ++ u32 XmtConfig; // 0x100 - Transmit Configuration Register ++ u32 RcvConfig; // 0x104 - Receive Configuration Register 1 ++ u32 LinkAddress0Low; // 0x108 - Link address 0 ++ u32 LinkAddress0High; // 0x10C - Link address 0 ++ u32 LinkAddress1Low; // 0x110 - Link address 1 ++ u32 LinkAddress1High; // 0x114 - Link address 1 ++ u32 LinkAddress2Low; // 0x118 - Link address 2 ++ u32 LinkAddress2High; // 0x11C - Link address 2 ++ u32 LinkAddress3Low; // 0x120 - Link address 3 ++ u32 LinkAddress3High; // 0x124 - Link address 3 ++ u32 ToeplitzKey[10]; // 0x128 - 0x150 - Toeplitz key ++ u32 SocketKey[10]; // 0x150 - 0x178 - Socket Key ++ u32 LinkStatus; // 0x178 - Link status ++ u32 ClearStats; // 0x17C - Clear Stats ++ u32 XmtErrorsLow; // 0x180 - Transmit stats - errors ++ u32 XmtErrorsHigh; // 0x184 - Transmit stats - errors ++ u32 XmtFramesLow; // 0x188 - Transmit stats - frame count ++ u32 XmtFramesHigh; // 0x18C - Transmit stats - frame count ++ u32 XmtBytesLow; // 0x190 - Transmit stats - byte count ++ u32 XmtBytesHigh; // 0x194 - Transmit stats - byte count ++ u32 XmtTcpSegmentsLow; // 0x198 - Transmit stats - TCP segments ++ u32 XmtTcpSegmentsHigh; // 0x19C - Transmit stats - TCP segments ++ u32 XmtTcpBytesLow; // 0x1A0 - Transmit stats - TCP bytes ++ u32 XmtTcpBytesHigh; // 0x1A4 - Transmit stats - TCP bytes ++ u32 RcvErrorsLow; // 0x1A8 - Receive stats - errors ++ u32 RcvErrorsHigh; // 0x1AC - Receive stats - errors ++ u32 RcvFramesLow; // 0x1B0 - Receive stats - frame count ++ u32 RcvFramesHigh; // 0x1B4 - Receive stats - frame count ++ u32 RcvBytesLow; // 0x1B8 - Receive stats - byte count ++ u32 RcvBytesHigh; // 0x1BC - Receive stats - byte count ++ u32 RcvTcpSegmentsLow; // 0x1C0 - Receive stats - TCP segments ++ u32 RcvTcpSegmentsHigh; // 0x1C4 - Receive stats - TCP segments ++ u32 RcvTcpBytesLow; // 0x1C8 - Receive stats - TCP bytes ++ u32 RcvTcpBytesHigh; // 0x1CC - Receive stats - TCP bytes ++ u32 PadTo0x200[12]; // 0x1D0 - 0x200 - Pad ++ u32 Software[1920]; // 0x200 - 0x2000 - Software defined (not used) ++ u32 MsixTable[1024]; // 0x2000 - 0x3000 - MSIX Table ++ u32 MsixBitArray[1024]; // 0x3000 - 0x4000 - MSIX Pending Bit Array ++} SXG_HW_REGS, *PSXG_HW_REGS; ++#pragma pack(pop) ++ ++// Microcode Address Flags ++#define MICROCODE_ADDRESS_GO 0x80000000 // Start microcode ++#define MICROCODE_ADDRESS_WRITE 0x40000000 // Store microcode ++#define MICROCODE_ADDRESS_READ 0x20000000 // Read microcode ++#define MICROCODE_ADDRESS_PARITY 0x10000000 // Parity error detected ++#define MICROCODE_ADDRESS_MASK 0x00001FFF // Address bits ++ ++// Link Address Registers ++#define LINK_ADDRESS_ENABLE 0x80000000 // Applied to link address high ++ ++// Microsoft register space size ++#define SXG_UCODEREG_MEMSIZE 0x40000 // 256k ++ ++// Sahara microcode register address format. The command code, ++// extended command code, and associated processor are encoded in ++// the address bits as follows ++#define SXG_ADDRESS_CODE_SHIFT 2 // Base command code ++#define SXG_ADDRESS_CODE_MASK 0x0000003C ++#define SXG_ADDRESS_EXCODE_SHIFT 6 // Extended (or sub) command code ++#define SXG_ADDRESS_EXCODE_MASK 0x00001FC0 ++#define SXG_ADDRESS_CPUID_SHIFT 13 // CPU ++#define SXG_ADDRESS_CPUID_MASK 0x0003E000 ++#define SXG_REGISTER_SIZE_PER_CPU 0x00002000 // Used to sanity check UCODE_REGS structure ++ ++// Sahara receive sequencer status values ++#define SXG_RCV_STATUS_ATTN 0x80000000 // Attention ++#define SXG_RCV_STATUS_TRANSPORT_MASK 0x3F000000 // Transport mask ++#define SXG_RCV_STATUS_TRANSPORT_ERROR 0x20000000 // Transport error ++#define SXG_RCV_STATUS_TRANSPORT_CSUM 0x23000000 // Transport cksum error ++#define SXG_RCV_STATUS_TRANSPORT_UFLOW 0x22000000 // Transport underflow ++#define SXG_RCV_STATUS_TRANSPORT_HDRLEN 0x20000000 // Transport header length ++#define SXG_RCV_STATUS_TRANSPORT_FLAGS 0x10000000 // Transport flags detected ++#define SXG_RCV_STATUS_TRANSPORT_OPTS 0x08000000 // Transport options detected ++#define SXG_RCV_STATUS_TRANSPORT_SESS_MASK 0x07000000 // Transport DDP ++#define SXG_RCV_STATUS_TRANSPORT_DDP 0x06000000 // Transport DDP ++#define SXG_RCV_STATUS_TRANSPORT_iSCSI 0x05000000 // Transport iSCSI ++#define SXG_RCV_STATUS_TRANSPORT_NFS 0x04000000 // Transport NFS ++#define SXG_RCV_STATUS_TRANSPORT_FTP 0x03000000 // Transport FTP ++#define SXG_RCV_STATUS_TRANSPORT_HTTP 0x02000000 // Transport HTTP ++#define SXG_RCV_STATUS_TRANSPORT_SMB 0x01000000 // Transport SMB ++#define SXG_RCV_STATUS_NETWORK_MASK 0x00FF0000 // Network mask ++#define SXG_RCV_STATUS_NETWORK_ERROR 0x00800000 // Network error ++#define SXG_RCV_STATUS_NETWORK_CSUM 0x00830000 // Network cksum error ++#define SXG_RCV_STATUS_NETWORK_UFLOW 0x00820000 // Network underflow error ++#define SXG_RCV_STATUS_NETWORK_HDRLEN 0x00800000 // Network header length ++#define SXG_RCV_STATUS_NETWORK_OFLOW 0x00400000 // Network overflow detected ++#define SXG_RCV_STATUS_NETWORK_MCAST 0x00200000 // Network multicast detected ++#define SXG_RCV_STATUS_NETWORK_OPTIONS 0x00100000 // Network options detected ++#define SXG_RCV_STATUS_NETWORK_OFFSET 0x00080000 // Network offset detected ++#define SXG_RCV_STATUS_NETWORK_FRAGMENT 0x00040000 // Network fragment detected ++#define SXG_RCV_STATUS_NETWORK_TRANS_MASK 0x00030000 // Network transport type mask ++#define SXG_RCV_STATUS_NETWORK_UDP 0x00020000 // UDP ++#define SXG_RCV_STATUS_NETWORK_TCP 0x00010000 // TCP ++#define SXG_RCV_STATUS_IPONLY 0x00008000 // IP-only not TCP ++#define SXG_RCV_STATUS_PKT_PRI 0x00006000 // Receive priority ++#define SXG_RCV_STATUS_PKT_PRI_SHFT 13 // Receive priority shift ++#define SXG_RCV_STATUS_PARITY 0x00001000 // MAC Receive RAM parity error ++#define SXG_RCV_STATUS_ADDRESS_MASK 0x00000F00 // Link address detection mask ++#define SXG_RCV_STATUS_ADDRESS_D 0x00000B00 // Link address D ++#define SXG_RCV_STATUS_ADDRESS_C 0x00000A00 // Link address C ++#define SXG_RCV_STATUS_ADDRESS_B 0x00000900 // Link address B ++#define SXG_RCV_STATUS_ADDRESS_A 0x00000800 // Link address A ++#define SXG_RCV_STATUS_ADDRESS_BCAST 0x00000300 // Link address broadcast ++#define SXG_RCV_STATUS_ADDRESS_MCAST 0x00000200 // Link address multicast ++#define SXG_RCV_STATUS_ADDRESS_CMCAST 0x00000100 // Link control multicast ++#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask ++#define SXG_RCV_STATUS_LINK_ERROR 0x00000080 // Link error ++#define SXG_RCV_STATUS_LINK_MASK 0x000000FF // Link status mask ++#define SXG_RCV_STATUS_LINK_PARITY 0x00000087 // RcvMacQ parity error ++#define SXG_RCV_STATUS_LINK_EARLY 0x00000086 // Data early ++#define SXG_RCV_STATUS_LINK_BUFOFLOW 0x00000085 // Buffer overflow ++#define SXG_RCV_STATUS_LINK_CODE 0x00000084 // Link code error ++#define SXG_RCV_STATUS_LINK_DRIBBLE 0x00000083 // Dribble nibble ++#define SXG_RCV_STATUS_LINK_CRC 0x00000082 // CRC error ++#define SXG_RCV_STATUS_LINK_OFLOW 0x00000081 // Link overflow ++#define SXG_RCV_STATUS_LINK_UFLOW 0x00000080 // Link underflow ++#define SXG_RCV_STATUS_LINK_8023 0x00000020 // 802.3 ++#define SXG_RCV_STATUS_LINK_SNAP 0x00000010 // Snap ++#define SXG_RCV_STATUS_LINK_VLAN 0x00000008 // VLAN ++#define SXG_RCV_STATUS_LINK_TYPE_MASK 0x00000007 // Network type mask ++#define SXG_RCV_STATUS_LINK_CONTROL 0x00000003 // Control packet ++#define SXG_RCV_STATUS_LINK_IPV6 0x00000002 // IPv6 packet ++#define SXG_RCV_STATUS_LINK_IPV4 0x00000001 // IPv4 packet ++ ++/*************************************************************************** ++ * Sahara receive and transmit configuration registers ++ ***************************************************************************/ ++#define RCV_CONFIG_RESET 0x80000000 // RcvConfig register reset ++#define RCV_CONFIG_ENABLE 0x40000000 // Enable the receive logic ++#define RCV_CONFIG_ENPARSE 0x20000000 // Enable the receive parser ++#define RCV_CONFIG_SOCKET 0x10000000 // Enable the socket detector ++#define RCV_CONFIG_RCVBAD 0x08000000 // Receive all bad frames ++#define RCV_CONFIG_CONTROL 0x04000000 // Receive all control frames ++#define RCV_CONFIG_RCVPAUSE 0x02000000 // Enable pause transmit when attn ++#define RCV_CONFIG_TZIPV6 0x01000000 // Include TCP port w/ IPv6 toeplitz ++#define RCV_CONFIG_TZIPV4 0x00800000 // Include TCP port w/ IPv4 toeplitz ++#define RCV_CONFIG_FLUSH 0x00400000 // Flush buffers ++#define RCV_CONFIG_PRIORITY_MASK 0x00300000 // Priority level ++#define RCV_CONFIG_HASH_MASK 0x00030000 // Hash depth ++#define RCV_CONFIG_HASH_8 0x00000000 // Hash depth 8 ++#define RCV_CONFIG_HASH_16 0x00010000 // Hash depth 16 ++#define RCV_CONFIG_HASH_4 0x00020000 // Hash depth 4 ++#define RCV_CONFIG_HASH_2 0x00030000 // Hash depth 2 ++#define RCV_CONFIG_BUFLEN_MASK 0x0000FFF0 // Buffer length bits 15:4. ie multiple of 16. ++#define RCV_CONFIG_SKT_DIS 0x00000008 // Disable socket detection on attn ++// Macro to determine RCV_CONFIG_BUFLEN based on maximum frame size. ++// We add 18 bytes for Sahara receive status and padding, plus 4 bytes for CRC, ++// and round up to nearest 16 byte boundary ++#define RCV_CONFIG_BUFSIZE(_MaxFrame) ((((_MaxFrame) + 22) + 15) & RCV_CONFIG_BUFLEN_MASK) ++ ++#define XMT_CONFIG_RESET 0x80000000 // XmtConfig register reset ++#define XMT_CONFIG_ENABLE 0x40000000 // Enable transmit logic ++#define XMT_CONFIG_MAC_PARITY 0x20000000 // Inhibit MAC RAM parity error ++#define XMT_CONFIG_BUF_PARITY 0x10000000 // Inhibit D2F buffer parity error ++#define XMT_CONFIG_MEM_PARITY 0x08000000 // Inhibit 1T SRAM parity error ++#define XMT_CONFIG_INVERT_PARITY 0x04000000 // Invert MAC RAM parity ++#define XMT_CONFIG_INITIAL_IPID 0x0000FFFF // Initial IPID ++ ++/*************************************************************************** ++ * A-XGMAC Registers - Occupy 0x80 - 0xD4 of the SXG_HW_REGS ++ * ++ * Full register descriptions can be found in axgmac.pdf ++ ***************************************************************************/ ++// A-XGMAC Configuration Register 0 ++#define AXGMAC_CFG0_SUB_RESET 0x80000000 // Sub module reset ++#define AXGMAC_CFG0_RCNTRL_RESET 0x00400000 // Receive control reset ++#define AXGMAC_CFG0_RFUNC_RESET 0x00200000 // Receive function reset ++#define AXGMAC_CFG0_TCNTRL_RESET 0x00040000 // Transmit control reset ++#define AXGMAC_CFG0_TFUNC_RESET 0x00020000 // Transmit function reset ++#define AXGMAC_CFG0_MII_RESET 0x00010000 // MII Management reset ++ ++// A-XGMAC Configuration Register 1 ++#define AXGMAC_CFG1_XMT_PAUSE 0x80000000 // Allow the sending of Pause frames ++#define AXGMAC_CFG1_XMT_EN 0x40000000 // Enable transmit ++#define AXGMAC_CFG1_RCV_PAUSE 0x20000000 // Allow the detection of Pause frames ++#define AXGMAC_CFG1_RCV_EN 0x10000000 // Enable receive ++#define AXGMAC_CFG1_XMT_STATE 0x04000000 // Current transmit state - READ ONLY ++#define AXGMAC_CFG1_RCV_STATE 0x01000000 // Current receive state - READ ONLY ++#define AXGMAC_CFG1_XOFF_SHORT 0x00001000 // Only pause for 64 slot on XOFF ++#define AXGMAC_CFG1_XMG_FCS1 0x00000400 // Delay transmit FCS 1 4-byte word ++#define AXGMAC_CFG1_XMG_FCS2 0x00000800 // Delay transmit FCS 2 4-byte words ++#define AXGMAC_CFG1_XMG_FCS3 0x00000C00 // Delay transmit FCS 3 4-byte words ++#define AXGMAC_CFG1_RCV_FCS1 0x00000100 // Delay receive FCS 1 4-byte word ++#define AXGMAC_CFG1_RCV_FCS2 0x00000200 // Delay receive FCS 2 4-byte words ++#define AXGMAC_CFG1_RCV_FCS3 0x00000300 // Delay receive FCS 3 4-byte words ++#define AXGMAC_CFG1_PKT_OVERRIDE 0x00000080 // Per-packet override enable ++#define AXGMAC_CFG1_SWAP 0x00000040 // Byte swap enable ++#define AXGMAC_CFG1_SHORT_ASSERT 0x00000020 // ASSERT srdrpfrm on short frame (<64) ++#define AXGMAC_CFG1_RCV_STRICT 0x00000010 // RCV only 802.3AE when CLEAR ++#define AXGMAC_CFG1_CHECK_LEN 0x00000008 // Verify frame length ++#define AXGMAC_CFG1_GEN_FCS 0x00000004 // Generate FCS ++#define AXGMAC_CFG1_PAD_MASK 0x00000003 // Mask for pad bits ++#define AXGMAC_CFG1_PAD_64 0x00000001 // Pad frames to 64 bytes ++#define AXGMAC_CFG1_PAD_VLAN 0x00000002 // Detect VLAN and pad to 68 bytes ++#define AXGMAC_CFG1_PAD_68 0x00000003 // Pad to 68 bytes ++ ++// A-XGMAC Configuration Register 2 ++#define AXGMAC_CFG2_GEN_PAUSE 0x80000000 // Generate single pause frame (test) ++#define AXGMAC_CFG2_LF_MANUAL 0x08000000 // Manual link fault sequence ++#define AXGMAC_CFG2_LF_AUTO 0x04000000 // Auto link fault sequence ++#define AXGMAC_CFG2_LF_REMOTE 0x02000000 // Remote link fault (READ ONLY) ++#define AXGMAC_CFG2_LF_LOCAL 0x01000000 // Local link fault (READ ONLY) ++#define AXGMAC_CFG2_IPG_MASK 0x001F0000 // Inter packet gap ++#define AXGMAC_CFG2_IPG_SHIFT 16 ++#define AXGMAC_CFG2_PAUSE_XMT 0x00008000 // Pause transmit module ++#define AXGMAC_CFG2_IPG_EXTEN 0x00000020 // Enable IPG extension algorithm ++#define AXGMAC_CFG2_IPGEX_MASK 0x0000001F // IPG extension ++ ++// A-XGMAC Configuration Register 3 ++#define AXGMAC_CFG3_RCV_DROP 0xFFFF0000 // Receive frame drop filter ++#define AXGMAC_CFG3_RCV_DONT_CARE 0x0000FFFF // Receive frame don't care filter ++ ++// A-XGMAC Station Address Register - Octets 1-4 ++#define AXGMAC_SARLOW_OCTET_ONE 0xFF000000 // First octet ++#define AXGMAC_SARLOW_OCTET_TWO 0x00FF0000 // Second octet ++#define AXGMAC_SARLOW_OCTET_THREE 0x0000FF00 // Third octet ++#define AXGMAC_SARLOW_OCTET_FOUR 0x000000FF // Fourth octet ++ ++// A-XGMAC Station Address Register - Octets 5-6 ++#define AXGMAC_SARHIGH_OCTET_FIVE 0xFF000000 // Fifth octet ++#define AXGMAC_SARHIGH_OCTET_SIX 0x00FF0000 // Sixth octet ++ ++// A-XGMAC Maximum frame length register ++#define AXGMAC_MAXFRAME_XMT 0x3FFF0000 // Maximum transmit frame length ++#define AXGMAC_MAXFRAME_XMT_SHIFT 16 ++#define AXGMAC_MAXFRAME_RCV 0x0000FFFF // Maximum receive frame length ++// This register doesn't need to be written for standard MTU. ++// For jumbo, I'll just statically define the value here. This ++// value sets the receive byte count to 9036 (0x234C) and the ++// transmit WORD count to 2259 (0x8D3). These values include 22 ++// bytes of padding beyond the jumbo MTU of 9014 ++#define AXGMAC_MAXFRAME_JUMBO 0x08D3234C ++ ++// A-XGMAC Revision level ++#define AXGMAC_REVISION_MASK 0x0000FFFF // Revision level ++ ++// A-XGMAC AMIIM Command Register ++#define AXGMAC_AMIIM_CMD_START 0x00000008 // Command start ++#define AXGMAC_AMIIM_CMD_MASK 0x00000007 // Command ++#define AXGMAC_AMIIM_CMD_LEGACY_WRITE 1 // 10/100/1000 Mbps Phy Write ++#define AXGMAC_AMIIM_CMD_LEGACY_READ 2 // 10/100/1000 Mbps Phy Read ++#define AXGMAC_AMIIM_CMD_MONITOR_SINGLE 3 // Monitor single PHY ++#define AXGMAC_AMIIM_CMD_MONITOR_MULTIPLE 4 // Monitor multiple contiguous PHYs ++#define AXGMAC_AMIIM_CMD_10G_OPERATION 5 // Present AMIIM Field Reg ++#define AXGMAC_AMIIM_CMD_CLEAR_LINK_FAIL 6 // Clear Link Fail Bit in MIIM ++ ++// A-XGMAC AMIIM Field Register ++#define AXGMAC_AMIIM_FIELD_ST 0xC0000000 // 2-bit ST field ++#define AXGMAC_AMIIM_FIELD_ST_SHIFT 30 ++#define AXGMAC_AMIIM_FIELD_OP 0x30000000 // 2-bit OP field ++#define AXGMAC_AMIIM_FIELD_OP_SHIFT 28 ++#define AXGMAC_AMIIM_FIELD_PORT_ADDR 0x0F800000 // Port address field (hstphyadx in spec) ++#define AXGMAC_AMIIM_FIELD_PORT_SHIFT 23 ++#define AXGMAC_AMIIM_FIELD_DEV_ADDR 0x007C0000 // Device address field (hstregadx in spec) ++#define AXGMAC_AMIIM_FIELD_DEV_SHIFT 18 ++#define AXGMAC_AMIIM_FIELD_TA 0x00030000 // 2-bit TA field ++#define AXGMAC_AMIIM_FIELD_TA_SHIFT 16 ++#define AXGMAC_AMIIM_FIELD_DATA 0x0000FFFF // Data field ++ ++// Values for the AXGMAC_AMIIM_FIELD_OP field in the A-XGMAC AMIIM Field Register ++#define MIIM_OP_ADDR 0 // MIIM Address set operation ++#define MIIM_OP_WRITE 1 // MIIM Write register operation ++#define MIIM_OP_READ 2 // MIIM Read register operation ++#define MIIM_OP_ADDR_SHIFT (MIIM_OP_ADDR << AXGMAC_AMIIM_FIELD_OP_SHIFT) ++ ++// Values for the AXGMAC_AMIIM_FIELD_PORT_ADDR field in the A-XGMAC AMIIM Field Register ++#define MIIM_PORT_NUM 1 // All Sahara MIIM modules use port 1 ++ ++// Values for the AXGMAC_AMIIM_FIELD_DEV_ADDR field in the A-XGMAC AMIIM Field Register ++#define MIIM_DEV_PHY_PMA 1 // PHY PMA/PMD module MIIM device number ++#define MIIM_DEV_PHY_PCS 3 // PHY PCS module MIIM device number ++#define MIIM_DEV_PHY_XS 4 // PHY XS module MIIM device number ++#define MIIM_DEV_XGXS 5 // XGXS MIIM device number ++ ++// Values for the AXGMAC_AMIIM_FIELD_TA field in the A-XGMAC AMIIM Field Register ++#define MIIM_TA_10GB 2 // set to 2 for 10 GB operation ++ ++// A-XGMAC AMIIM Configuration Register ++#define AXGMAC_AMIIM_CFG_NOPREAM 0x00000080 // Bypass preamble of mngmt frame ++#define AXGMAC_AMIIM_CFG_HALF_CLOCK 0x0000007F // half-clock duration of MDC output ++ ++// A-XGMAC AMIIM Indicator Register ++#define AXGMAC_AMIIM_INDC_LINK 0x00000010 // Link status from legacy PHY or MMD ++#define AXGMAC_AMIIM_INDC_MPHY 0x00000008 // Multiple phy operation in progress ++#define AXGMAC_AMIIM_INDC_SPHY 0x00000004 // Single phy operation in progress ++#define AXGMAC_AMIIM_INDC_MON 0x00000002 // Single or multiple monitor cmd ++#define AXGMAC_AMIIM_INDC_BUSY 0x00000001 // Set until cmd operation complete ++ ++// Link Status and Control Register ++#define LS_PHY_CLR_RESET 0x80000000 // Clear reset signal to PHY ++#define LS_SERDES_POWER_DOWN 0x40000000 // Power down the Sahara Serdes ++#define LS_XGXS_ENABLE 0x20000000 // Enable the XAUI XGXS logic ++#define LS_XGXS_CTL 0x10000000 // Hold XAUI XGXS logic reset until Serdes is up ++#define LS_SERDES_DOWN 0x08000000 // When 0, XAUI Serdes is up and initialization is complete ++#define LS_TRACE_DOWN 0x04000000 // When 0, Trace Serdes is up and initialization is complete ++#define LS_PHY_CLK_25MHZ 0x02000000 // Set PHY clock to 25 MHz (else 156.125 MHz) ++#define LS_PHY_CLK_EN 0x01000000 // Enable clock to PHY ++#define LS_XAUI_LINK_UP 0x00000010 // XAUI link is up ++#define LS_XAUI_LINK_CHNG 0x00000008 // XAUI link status has changed ++#define LS_LINK_ALARM 0x00000004 // Link alarm pin ++#define LS_ATTN_CTRL_MASK 0x00000003 // Mask link attention control bits ++#define LS_ATTN_ALARM 0x00000000 // 00 => Attn on link alarm ++#define LS_ATTN_ALARM_OR_STAT_CHNG 0x00000001 // 01 => Attn on link alarm or status change ++#define LS_ATTN_STAT_CHNG 0x00000002 // 10 => Attn on link status change ++#define LS_ATTN_NONE 0x00000003 // 11 => no Attn ++ ++// Link Address High Registers ++#define LINK_ADDR_ENABLE 0x80000000 // Enable this link address ++ ++ ++/*************************************************************************** ++ * XGXS XAUI XGMII Extender registers ++ * ++ * Full register descriptions can be found in mxgxs.pdf ++ ***************************************************************************/ ++// XGXS Register Map ++#define XGXS_ADDRESS_CONTROL1 0x0000 // XS Control 1 ++#define XGXS_ADDRESS_STATUS1 0x0001 // XS Status 1 ++#define XGXS_ADDRESS_DEVID_LOW 0x0002 // XS Device ID (low) ++#define XGXS_ADDRESS_DEVID_HIGH 0x0003 // XS Device ID (high) ++#define XGXS_ADDRESS_SPEED 0x0004 // XS Speed ability ++#define XGXS_ADDRESS_DEV_LOW 0x0005 // XS Devices in package ++#define XGXS_ADDRESS_DEV_HIGH 0x0006 // XS Devices in package ++#define XGXS_ADDRESS_STATUS2 0x0008 // XS Status 2 ++#define XGXS_ADDRESS_PKGID_lOW 0x000E // XS Package Identifier ++#define XGXS_ADDRESS_PKGID_HIGH 0x000F // XS Package Identifier ++#define XGXS_ADDRESS_LANE_STATUS 0x0018 // 10G XGXS Lane Status ++#define XGXS_ADDRESS_TEST_CTRL 0x0019 // 10G XGXS Test Control ++#define XGXS_ADDRESS_RESET_LO1 0x8000 // Vendor-Specific Reset Lo 1 ++#define XGXS_ADDRESS_RESET_LO2 0x8001 // Vendor-Specific Reset Lo 2 ++#define XGXS_ADDRESS_RESET_HI1 0x8002 // Vendor-Specific Reset Hi 1 ++#define XGXS_ADDRESS_RESET_HI2 0x8003 // Vendor-Specific Reset Hi 2 ++ ++// XS Control 1 register bit definitions ++#define XGXS_CONTROL1_RESET 0x8000 // Reset - self clearing ++#define XGXS_CONTROL1_LOOPBACK 0x4000 // Enable loopback ++#define XGXS_CONTROL1_SPEED1 0x2000 // 0 = unspecified, 1 = 10Gb+ ++#define XGXS_CONTROL1_LOWPOWER 0x0400 // 1 = Low power mode ++#define XGXS_CONTROL1_SPEED2 0x0040 // Same as SPEED1 (?) ++#define XGXS_CONTROL1_SPEED 0x003C // Everything reserved except zero (?) ++ ++// XS Status 1 register bit definitions ++#define XGXS_STATUS1_FAULT 0x0080 // Fault detected ++#define XGXS_STATUS1_LINK 0x0004 // 1 = Link up ++#define XGXS_STATUS1_LOWPOWER 0x0002 // 1 = Low power supported ++ ++// XS Speed register bit definitions ++#define XGXS_SPEED_10G 0x0001 // 1 = 10G capable ++ ++// XS Devices register bit definitions ++#define XGXS_DEVICES_DTE 0x0020 // DTE XS Present ++#define XGXS_DEVICES_PHY 0x0010 // PHY XS Present ++#define XGXS_DEVICES_PCS 0x0008 // PCS Present ++#define XGXS_DEVICES_WIS 0x0004 // WIS Present ++#define XGXS_DEVICES_PMD 0x0002 // PMD/PMA Present ++#define XGXS_DEVICES_CLAUSE22 0x0001 // Clause 22 registers present ++ ++// XS Devices High register bit definitions ++#define XGXS_DEVICES_VENDOR2 0x8000 // Vendor specific device 2 ++#define XGXS_DEVICES_VENDOR1 0x4000 // Vendor specific device 1 ++ ++// XS Status 2 register bit definitions ++#define XGXS_STATUS2_DEV_MASK 0xC000 // Device present mask ++#define XGXS_STATUS2_DEV_RESPOND 0x8000 // Device responding ++#define XGXS_STATUS2_XMT_FAULT 0x0800 // Transmit fault ++#define XGXS_STATUS2_RCV_FAULT 0x0400 // Receive fault ++ ++// XS Package ID High register bit definitions ++#define XGXS_PKGID_HIGH_ORG 0xFC00 // Organizationally Unique ++#define XGXS_PKGID_HIGH_MFG 0x03F0 // Manufacturer Model ++#define XGXS_PKGID_HIGH_REV 0x000F // Revision Number ++ ++// XS Lane Status register bit definitions ++#define XGXS_LANE_PHY 0x1000 // PHY/DTE lane alignment status ++#define XGXS_LANE_PATTERN 0x0800 // Pattern testing ability ++#define XGXS_LANE_LOOPBACK 0x0400 // PHY loopback ability ++#define XGXS_LANE_SYNC3 0x0008 // Lane 3 sync ++#define XGXS_LANE_SYNC2 0x0004 // Lane 2 sync ++#define XGXS_LANE_SYNC1 0x0002 // Lane 1 sync ++#define XGXS_LANE_SYNC0 0x0001 // Lane 0 sync ++ ++// XS Test Control register bit definitions ++#define XGXS_TEST_PATTERN_ENABLE 0x0004 // Test pattern enabled ++#define XGXS_TEST_PATTERN_MASK 0x0003 // Test patterns ++#define XGXS_TEST_PATTERN_RSVD 0x0003 // Test pattern - reserved ++#define XGXS_TEST_PATTERN_MIX 0x0002 // Test pattern - mixed ++#define XGXS_TEST_PATTERN_LOW 0x0001 // Test pattern - low ++#define XGXS_TEST_PATTERN_HIGH 0x0001 // Test pattern - high ++ ++/*************************************************************************** ++ * External MDIO Bus Registers ++ * ++ * Full register descriptions can be found in PHY/XENPAK/IEEE specs ++ ***************************************************************************/ ++// LASI (Link Alarm Status Interrupt) Registers (located in MIIM_DEV_PHY_PMA device) ++#define LASI_RX_ALARM_CONTROL 0x9000 // LASI RX_ALARM Control ++#define LASI_TX_ALARM_CONTROL 0x9001 // LASI TX_ALARM Control ++#define LASI_CONTROL 0x9002 // LASI Control ++#define LASI_RX_ALARM_STATUS 0x9003 // LASI RX_ALARM Status ++#define LASI_TX_ALARM_STATUS 0x9004 // LASI TX_ALARM Status ++#define LASI_STATUS 0x9005 // LASI Status ++ ++// LASI_CONTROL bit definitions ++#define LASI_CTL_RX_ALARM_ENABLE 0x0004 // Enable RX_ALARM interrupts ++#define LASI_CTL_TX_ALARM_ENABLE 0x0002 // Enable TX_ALARM interrupts ++#define LASI_CTL_LS_ALARM_ENABLE 0x0001 // Enable Link Status interrupts ++ ++// LASI_STATUS bit definitions ++#define LASI_STATUS_RX_ALARM 0x0004 // RX_ALARM status ++#define LASI_STATUS_TX_ALARM 0x0002 // TX_ALARM status ++#define LASI_STATUS_LS_ALARM 0x0001 // Link Status ++ ++// PHY registers - PMA/PMD (device 1) ++#define PHY_PMA_CONTROL1 0x0000 // PMA/PMD Control 1 ++#define PHY_PMA_STATUS1 0x0001 // PMA/PMD Status 1 ++#define PHY_PMA_RCV_DET 0x000A // PMA/PMD Receive Signal Detect ++ // other PMA/PMD registers exist and can be defined as needed ++ ++// PHY registers - PCS (device 3) ++#define PHY_PCS_CONTROL1 0x0000 // PCS Control 1 ++#define PHY_PCS_STATUS1 0x0001 // PCS Status 1 ++#define PHY_PCS_10G_STATUS1 0x0020 // PCS 10GBASE-R Status 1 ++ // other PCS registers exist and can be defined as needed ++ ++// PHY registers - XS (device 4) ++#define PHY_XS_CONTROL1 0x0000 // XS Control 1 ++#define PHY_XS_STATUS1 0x0001 // XS Status 1 ++#define PHY_XS_LANE_STATUS 0x0018 // XS Lane Status ++ // other XS registers exist and can be defined as needed ++ ++// PHY_PMA_CONTROL1 register bit definitions ++#define PMA_CONTROL1_RESET 0x8000 // PMA/PMD reset ++ ++// PHY_PMA_RCV_DET register bit definitions ++#define PMA_RCV_DETECT 0x0001 // PMA/PMD receive signal detect ++ ++// PHY_PCS_10G_STATUS1 register bit definitions ++#define PCS_10B_BLOCK_LOCK 0x0001 // PCS 10GBASE-R locked to receive blocks ++ ++// PHY_XS_LANE_STATUS register bit definitions ++#define XS_LANE_ALIGN 0x1000 // XS transmit lanes aligned ++ ++// PHY Microcode download data structure ++typedef struct _PHY_UCODE { ++ ushort Addr; ++ ushort Data; ++} PHY_UCODE, *PPHY_UCODE; ++ ++ ++/***************************************************************************** ++ * Transmit Sequencer Command Descriptor definitions ++ *****************************************************************************/ ++ ++// This descriptor must be placed in GRAM. The address of this descriptor ++// (along with a couple of control bits) is pushed onto the PxhCmdQ or PxlCmdQ ++// (Proxy high or low command queue). This data is read by the Proxy Sequencer, ++// which pushes it onto the XmtCmdQ, which is (eventually) read by the Transmit ++// Sequencer, causing a packet to be transmitted. Not all fields are valid for ++// all commands - see the Sahara spec for details. Note that this structure is ++// only valid when compiled on a little endian machine. ++#pragma pack(push, 1) ++typedef struct _XMT_DESC { ++ ushort XmtLen; // word 0, bits [15:0] - transmit length ++ unsigned char XmtCtl; // word 0, bits [23:16] - transmit control byte ++ unsigned char Cmd; // word 0, bits [31:24] - transmit command plus misc. ++ u32 XmtBufId; // word 1, bits [31:0] - transmit buffer ID ++ unsigned char TcpStrt; // word 2, bits [7:0] - byte address of TCP header ++ unsigned char IpStrt; // word 2, bits [15:8] - byte address of IP header ++ ushort IpCkSum; // word 2, bits [31:16] - partial IP checksum ++ ushort TcpCkSum; // word 3, bits [15:0] - partial TCP checksum ++ ushort Rsvd1; // word 3, bits [31:16] - PAD ++ u32 Rsvd2; // word 4, bits [31:0] - PAD ++ u32 Rsvd3; // word 5, bits [31:0] - PAD ++ u32 Rsvd4; // word 6, bits [31:0] - PAD ++ u32 Rsvd5; // word 7, bits [31:0] - PAD ++} XMT_DESC, *PXMT_DESC; ++#pragma pack(pop) ++ ++// XMT_DESC Cmd byte definitions ++ // command codes ++#define XMT_DESC_CMD_RAW_SEND 0 // raw send descriptor ++#define XMT_DESC_CMD_CSUM_INSERT 1 // checksum insert descriptor ++#define XMT_DESC_CMD_FORMAT 2 // format descriptor ++#define XMT_DESC_CMD_PRIME 3 // prime descriptor ++#define XMT_DESC_CMD_CODE_SHFT 6 // comand code shift (shift to bits [31:30] in word 0) ++ // shifted command codes ++#define XMT_RAW_SEND (XMT_DESC_CMD_RAW_SEND << XMT_DESC_CMD_CODE_SHFT) ++#define XMT_CSUM_INSERT (XMT_DESC_CMD_CSUM_INSERT << XMT_DESC_CMD_CODE_SHFT) ++#define XMT_FORMAT (XMT_DESC_CMD_FORMAT << XMT_DESC_CMD_CODE_SHFT) ++#define XMT_PRIME (XMT_DESC_CMD_PRIME << XMT_DESC_CMD_CODE_SHFT) ++ ++// XMT_DESC Control Byte (XmtCtl) definitions ++// NOTE: These bits do not work on Sahara (Rev A)! ++#define XMT_CTL_PAUSE_FRAME 0x80 // current frame is a pause control frame (for statistics) ++#define XMT_CTL_CONTROL_FRAME 0x40 // current frame is a control frame (for statistics) ++#define XMT_CTL_PER_PKT_QUAL 0x20 // per packet qualifier ++#define XMT_CTL_PAD_MODE_NONE 0x00 // do not pad frame ++#define XMT_CTL_PAD_MODE_64 0x08 // pad frame to 64 bytes ++#define XMT_CTL_PAD_MODE_VLAN_68 0x10 // pad frame to 64 bytes, and VLAN frames to 68 bytes ++#define XMT_CTL_PAD_MODE_68 0x18 // pad frame to 68 bytes ++#define XMT_CTL_GEN_FCS 0x04 // generate FCS (CRC) for this frame ++#define XMT_CTL_DELAY_FCS_0 0x00 // do not delay FCS calcution ++#define XMT_CTL_DELAY_FCS_1 0x01 // delay FCS calculation by 1 (4-byte) word ++#define XMT_CTL_DELAY_FCS_2 0x02 // delay FCS calculation by 2 (4-byte) words ++#define XMT_CTL_DELAY_FCS_3 0x03 // delay FCS calculation by 3 (4-byte) words ++ ++// XMT_DESC XmtBufId definition ++#define XMT_BUF_ID_SHFT 8 // The Xmt buffer ID is formed by dividing ++ // the buffer (DRAM) address by 256 (or << 8) ++ ++/***************************************************************************** ++ * Receiver Sequencer Definitions ++ *****************************************************************************/ ++ ++// Receive Event Queue (queues 3 - 6) bit definitions ++#define RCV_EVTQ_RBFID_MASK 0x0000FFFF // bit mask for the Receive Buffer ID ++ ++// Receive Buffer ID definition ++#define RCV_BUF_ID_SHFT 5 // The Rcv buffer ID is formed by dividing ++ // the buffer (DRAM) address by 32 (or << 5) ++ ++// Format of the 18 byte Receive Buffer returned by the ++// Receive Sequencer for received packets ++#pragma pack(push, 1) ++typedef struct _RCV_BUF_HDR { ++ u32 Status; // Status word from Rcv Seq Parser ++ ushort Length; // Rcv packet byte count ++ union { ++ ushort TcpCsum; // TCP checksum ++ struct { ++ unsigned char TcpCsumL; // lower 8 bits of the TCP checksum ++ unsigned char LinkHash; // Link hash (multicast frames only) ++ }; ++ }; ++ ushort SktHash; // Socket hash ++ unsigned char TcpHdrOffset; // TCP header offset into packet ++ unsigned char IpHdrOffset; // IP header offset into packet ++ u32 TpzHash; // Toeplitz hash ++ ushort Reserved; // Reserved ++} RCV_BUF_HDR, *PRCV_BUF_HDR; ++#pragma pack(pop) ++ ++ ++/***************************************************************************** ++ * Queue definitions ++ *****************************************************************************/ ++ ++// Ingress (read only) queue numbers ++#define PXY_BUF_Q 0 // Proxy Buffer Queue ++#define HST_EVT_Q 1 // Host Event Queue ++#define XMT_BUF_Q 2 // Transmit Buffer Queue ++#define SKT_EVL_Q 3 // RcvSqr Socket Event Low Priority Queue ++#define RCV_EVL_Q 4 // RcvSqr Rcv Event Low Priority Queue ++#define SKT_EVH_Q 5 // RcvSqr Socket Event High Priority Queue ++#define RCV_EVH_Q 6 // RcvSqr Rcv Event High Priority Queue ++#define DMA_RSP_Q 7 // Dma Response Queue - one per CPU context ++// Local (read/write) queue numbers ++#define LOCAL_A_Q 8 // Spare local Queue ++#define LOCAL_B_Q 9 // Spare local Queue ++#define LOCAL_C_Q 10 // Spare local Queue ++#define FSM_EVT_Q 11 // Finite-State-Machine Event Queue ++#define SBF_PAL_Q 12 // System Buffer Physical Address (low) Queue ++#define SBF_PAH_Q 13 // System Buffer Physical Address (high) Queue ++#define SBF_VAL_Q 14 // System Buffer Virtual Address (low) Queue ++#define SBF_VAH_Q 15 // System Buffer Virtual Address (high) Queue ++// Egress (write only) queue numbers ++#define H2G_CMD_Q 16 // Host to GlbRam DMA Command Queue ++#define H2D_CMD_Q 17 // Host to DRAM DMA Command Queue ++#define G2H_CMD_Q 18 // GlbRam to Host DMA Command Queue ++#define G2D_CMD_Q 19 // GlbRam to DRAM DMA Command Queue ++#define D2H_CMD_Q 20 // DRAM to Host DMA Command Queue ++#define D2G_CMD_Q 21 // DRAM to GlbRam DMA Command Queue ++#define D2D_CMD_Q 22 // DRAM to DRAM DMA Command Queue ++#define PXL_CMD_Q 23 // Low Priority Proxy Command Queue ++#define PXH_CMD_Q 24 // High Priority Proxy Command Queue ++#define RSQ_CMD_Q 25 // Receive Sequencer Command Queue ++#define RCV_BUF_Q 26 // Receive Buffer Queue ++ ++// Bit definitions for the Proxy Command queues (PXL_CMD_Q and PXH_CMD_Q) ++#define PXY_COPY_EN 0x00200000 // enable copy of xmt descriptor to xmt command queue ++#define PXY_SIZE_16 0x00000000 // copy 16 bytes ++#define PXY_SIZE_32 0x00100000 // copy 32 bytes ++ ++/***************************************************************************** ++ * SXG EEPROM/Flash Configuration Definitions ++ *****************************************************************************/ ++#pragma pack(push, 1) ++ ++// ++typedef struct _HW_CFG_DATA { ++ ushort Addr; ++ union { ++ ushort Data; ++ ushort Checksum; ++ }; ++} HW_CFG_DATA, *PHW_CFG_DATA; ++ ++// ++#define NUM_HW_CFG_ENTRIES ((128/sizeof(HW_CFG_DATA)) - 4) ++ ++// MAC address ++typedef struct _SXG_CONFIG_MAC { ++ unsigned char MacAddr[6]; // MAC Address ++} SXG_CONFIG_MAC, *PSXG_CONFIG_MAC; ++ ++// ++typedef struct _ATK_FRU { ++ unsigned char PartNum[6]; ++ unsigned char Revision[2]; ++ unsigned char Serial[14]; ++} ATK_FRU, *PATK_FRU; ++ ++// OEM FRU Format types ++#define ATK_FRU_FORMAT 0x0000 ++#define CPQ_FRU_FORMAT 0x0001 ++#define DELL_FRU_FORMAT 0x0002 ++#define HP_FRU_FORMAT 0x0003 ++#define IBM_FRU_FORMAT 0x0004 ++#define EMC_FRU_FORMAT 0x0005 ++#define NO_FRU_FORMAT 0xFFFF ++ ++// EEPROM/Flash Format ++typedef struct _SXG_CONFIG { ++ // ++ // Section 1 (128 bytes) ++ // ++ ushort MagicWord; // EEPROM/FLASH Magic code 'A5A5' ++ ushort SpiClks; // SPI bus clock dividers ++ HW_CFG_DATA HwCfg[NUM_HW_CFG_ENTRIES]; ++ // ++ // ++ // ++ ushort Version; // EEPROM format version ++ SXG_CONFIG_MAC MacAddr[4]; // space for 4 MAC addresses ++ ATK_FRU AtkFru; // FRU information ++ ushort OemFruFormat; // OEM FRU format type ++ unsigned char OemFru[76]; // OEM FRU information (optional) ++ ushort Checksum; // Checksum of section 2 ++ // CS info XXXTODO ++} SXG_CONFIG, *PSXG_CONFIG; ++#pragma pack(pop) ++ ++/***************************************************************************** ++ * Miscellaneous Hardware definitions ++ *****************************************************************************/ ++ ++// Sahara (ASIC level) defines ++#define SAHARA_GRAM_SIZE 0x020000 // GRAM size - 128 KB ++#define SAHARA_DRAM_SIZE 0x200000 // DRAM size - 2 MB ++#define SAHARA_QRAM_SIZE 0x004000 // QRAM size - 16K entries (64 KB) ++#define SAHARA_WCS_SIZE 0x002000 // WCS - 8K instructions (x 108 bits) ++ ++// Arabia (board level) defines ++#define FLASH_SIZE 0x080000 // 512 KB (4 Mb) ++#define EEPROM_SIZE_XFMR 512 // true EEPROM size (bytes), including xfmr area ++#define EEPROM_SIZE_NO_XFMR 256 // EEPROM size excluding xfmr area +--- /dev/null ++++ b/drivers/staging/sxg/sxg_os.h +@@ -0,0 +1,154 @@ ++/************************************************************************** ++ * ++ * Copyright (C) 2000-2008 Alacritech, Inc. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials provided ++ * with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY ALACRITECH, INC. ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALACRITECH, INC. OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ * ++ * The views and conclusions contained in the software and documentation ++ * are those of the authors and should not be interpreted as representing ++ * official policies, either expressed or implied, of Alacritech, Inc. ++ * ++ **************************************************************************/ ++ ++/* ++ * FILENAME: sxg_os.h ++ * ++ * These are the Linux-specific definitions required for the SLICOSS ++ * driver, which should allow for greater portability to other OSes. ++ */ ++#ifndef _SLIC_OS_SPECIFIC_H_ ++#define _SLIC_OS_SPECIFIC_H_ ++ ++#define FALSE (0) ++#define TRUE (1) ++ ++ ++typedef struct _LIST_ENTRY { ++ struct _LIST_ENTRY *nle_flink; ++ struct _LIST_ENTRY *nle_blink; ++} list_entry, LIST_ENTRY, *PLIST_ENTRY; ++ ++#define InitializeListHead(l) \ ++ (l)->nle_flink = (l)->nle_blink = (l) ++ ++#define IsListEmpty(h) \ ++ ((h)->nle_flink == (h)) ++ ++#define RemoveEntryList(e) \ ++ do { \ ++ list_entry *b; \ ++ list_entry *f; \ ++ \ ++ f = (e)->nle_flink; \ ++ b = (e)->nle_blink; \ ++ b->nle_flink = f; \ ++ f->nle_blink = b; \ ++ } while (0) ++ ++/* These two have to be inlined since they return things. */ ++ ++static __inline PLIST_ENTRY ++RemoveHeadList(list_entry *l) ++{ ++ list_entry *f; ++ list_entry *e; ++ ++ e = l->nle_flink; ++ f = e->nle_flink; ++ l->nle_flink = f; ++ f->nle_blink = l; ++ ++ return (e); ++} ++ ++static __inline PLIST_ENTRY ++RemoveTailList(list_entry *l) ++{ ++ list_entry *b; ++ list_entry *e; ++ ++ e = l->nle_blink; ++ b = e->nle_blink; ++ l->nle_blink = b; ++ b->nle_flink = l; ++ ++ return (e); ++} ++ ++ ++#define InsertTailList(l, e) \ ++ do { \ ++ list_entry *b; \ ++ \ ++ b = (l)->nle_blink; \ ++ (e)->nle_flink = (l); \ ++ (e)->nle_blink = b; \ ++ b->nle_flink = (e); \ ++ (l)->nle_blink = (e); \ ++ } while (0) ++ ++#define InsertHeadList(l, e) \ ++ do { \ ++ list_entry *f; \ ++ \ ++ f = (l)->nle_flink; \ ++ (e)->nle_flink = f; \ ++ (e)->nle_blink = l; \ ++ f->nle_blink = (e); \ ++ (l)->nle_flink = (e); \ ++ } while (0) ++ ++ ++#define ATK_DEBUG 1 ++ ++#if ATK_DEBUG ++#define SLIC_TIMESTAMP(value) { \ ++ struct timeval timev; \ ++ do_gettimeofday(&timev); \ ++ value = timev.tv_sec*1000000 + timev.tv_usec; \ ++} ++#else ++#define SLIC_TIMESTAMP(value) ++#endif ++ ++ ++/****************** SXG DEFINES *****************************************/ ++ ++#ifdef ATKDBG ++#define SXG_TIMESTAMP(value) { \ ++ struct timeval timev; \ ++ do_gettimeofday(&timev); \ ++ value = timev.tv_sec*1000000 + timev.tv_usec; \ ++} ++#else ++#define SXG_TIMESTAMP(value) ++#endif ++ ++#define WRITE_REG(reg,value,flush) sxg_reg32_write((®), (value), (flush)) ++#define WRITE_REG64(a,reg,value,cpu) sxg_reg64_write((a),(®),(value),(cpu)) ++#define READ_REG(reg,value) (value) = readl((void __iomem *)(®)) ++ ++#endif /* _SLIC_OS_SPECIFIC_H_ */ ++ +--- /dev/null ++++ b/drivers/staging/sxg/sxgphycode.h +@@ -0,0 +1,349 @@ ++/* ++ * Copyright (C) 1997-2008 Alacritech, Inc. All rights reserved ++ * ++ * sxgphycode.h: ++ * ++ * This file PHY microcode and register initialization data. ++ */ ++ ++/********************************************************************** ++ * PHY Microcode ++ * ++ * The following contains both PHY microcode and PHY register ++ * initialization data. It is specific to both the PHY and the ++ * type of transceiver. ++ * ++ **********************************************************************/ ++ ++/* ++ * Download for AEL2005C PHY with SR/LR transceiver (10GBASE-SR or 10GBASE-LR) ++ */ ++static PHY_UCODE PhyUcode[] = { ++ /* ++ * NOTE: An address of 0 is a special case. When the download routine ++ * sees an address of 0, it does not write to the PHY. Instead, it ++ * delays the download. The length of the delay (in ms) is given in ++ * the data field. ++ * ++ * Delays are required at certain points. ++ */ ++ ++ /* ++ * Platform-specific MDIO Patches: ++ * (include patches for 10G RX polarity flip, 50Mhz Synth, etc) ++ */ ++ /* Addr, Data */ ++ {0xc017, 0xfeb0}, /* flip RX_LOS polarity (mandatory */ ++ /* patch for SFP+ applications) */ ++ {0xC001, 0x0428}, /* flip RX serial polarity */ ++ ++ {0xc013, 0xf341}, /* invert lxmit clock (mandatory patch) */ ++ {0xc210, 0x8000}, /* reset datapath (mandatory patch) */ ++ {0xc210, 0x8100}, /* reset datapath (mandatory patch) */ ++ {0xc210, 0x8000}, /* reset datapath (mandatory patch) */ ++ {0xc210, 0x0000}, /* reset datapath (mandatory patch) */ ++ {0x0000, 0x0032}, /* wait for 50ms for datapath reset to */ ++ /* complete. (mandatory patch) */ ++ ++ /* Configure the LED's */ ++ {0xc214, 0x0099}, /* configure the LED drivers */ ++ {0xc216, 0x5f5f}, /* configure the Activity LED */ ++ {0xc217, 0x33ff}, /* configure the Link LED */ ++ ++ /* Transceiver-specific MDIO Patches: */ ++ {0xc010, 0x448a}, /* (bit 14) mask out high BER input from the */ ++ /* LOS signal in 1.000A */ ++ /* (mandatory patch for SR code)*/ ++ {0xc003, 0x0181}, /* (bit 7) enable the CDR inc setting in */ ++ /* 1.C005 (mandatory patch for SR code) */ ++ ++ /* Transceiver-specific Microcontroller Initialization: */ ++ {0xc04a, 0x5200}, /* activate microcontroller and pause */ ++ {0x0000, 0x0032}, /* wait 50ms for microcontroller before */ ++ /* writing in code. */ ++ ++ /* code block starts here: */ ++ {0xcc00, 0x2009}, ++ {0xcc01, 0x3009}, ++ {0xcc02, 0x27ff}, ++ {0xcc03, 0x300f}, ++ {0xcc04, 0x200c}, ++ {0xcc05, 0x300c}, ++ {0xcc06, 0x20c4}, ++ {0xcc07, 0x3c04}, ++ {0xcc08, 0x6437}, ++ {0xcc09, 0x20c4}, ++ {0xcc0a, 0x3c04}, ++ {0xcc0b, 0x6437}, ++ {0xcc0c, 0x25c4}, ++ {0xcc0d, 0x3c54}, ++ {0xcc0e, 0x6724}, ++ {0xcc0f, 0x25c4}, ++ {0xcc10, 0x3c54}, ++ {0xcc11, 0x6724}, ++ {0xcc12, 0x2042}, ++ {0xcc13, 0x3012}, ++ {0xcc14, 0x1002}, ++ {0xcc15, 0x2482}, ++ {0xcc16, 0x3012}, ++ {0xcc17, 0x1002}, ++ {0xcc18, 0x2a32}, ++ {0xcc19, 0x3002}, ++ {0xcc1a, 0x1002}, ++ {0xcc1b, 0x200d}, ++ {0xcc1c, 0x304d}, ++ {0xcc1d, 0x2862}, ++ {0xcc1e, 0x3012}, ++ {0xcc1f, 0x1002}, ++ {0xcc20, 0x2982}, ++ {0xcc21, 0x3002}, ++ {0xcc22, 0x1002}, ++ {0xcc23, 0x628f}, ++ {0xcc24, 0x20a4}, ++ {0xcc25, 0x3004}, ++ {0xcc26, 0x6438}, ++ {0xcc27, 0x20a4}, ++ {0xcc28, 0x3004}, ++ {0xcc29, 0x6438}, ++ {0xcc2a, 0x2015}, ++ {0xcc2b, 0x3005}, ++ {0xcc2c, 0x5853}, ++ {0xcc2d, 0x2bd2}, ++ {0xcc2e, 0x3002}, ++ {0xcc2f, 0x1342}, ++ {0xcc30, 0x200c}, ++ {0xcc31, 0x300c}, ++ {0xcc32, 0x2ff7}, ++ {0xcc33, 0x30f7}, ++ {0xcc34, 0x20c4}, ++ {0xcc35, 0x3c04}, ++ {0xcc36, 0x6724}, ++ {0xcc37, 0x20c4}, ++ {0xcc38, 0x3c04}, ++ {0xcc39, 0x6724}, ++ {0xcc3a, 0x2d32}, ++ {0xcc3b, 0x3002}, ++ {0xcc3c, 0x1002}, ++ {0xcc3d, 0x2008}, ++ {0xcc3e, 0x3008}, ++ {0xcc3f, 0x5c83}, ++ {0xcc40, 0x2d52}, ++ {0xcc41, 0x3002}, ++ {0xcc42, 0x1352}, ++ {0xcc43, 0x2008}, ++ {0xcc44, 0x3008}, ++ {0xcc45, 0x5c83}, ++ {0xcc46, 0x2d32}, ++ {0xcc47, 0x3002}, ++ {0xcc48, 0x1352}, ++ {0xcc49, 0x201c}, ++ {0xcc4a, 0x300c}, ++ {0xcc4b, 0x200d}, ++ {0xcc4c, 0x310d}, ++ {0xcc4d, 0x2862}, ++ {0xcc4e, 0x3012}, ++ {0xcc4f, 0x1002}, ++ {0xcc50, 0x2ed2}, ++ {0xcc51, 0x3002}, ++ {0xcc52, 0x1342}, ++ {0xcc53, 0x6f72}, ++ {0xcc54, 0x1002}, ++ {0xcc55, 0x628f}, ++ {0xcc56, 0x2514}, ++ {0xcc57, 0x3c64}, ++ {0xcc58, 0x6436}, ++ {0xcc59, 0x2514}, ++ {0xcc5a, 0x3c64}, ++ {0xcc5b, 0x6436}, ++ {0xcc5c, 0x2fa4}, ++ {0xcc5d, 0x3cd4}, ++ {0xcc5e, 0x6624}, ++ {0xcc5f, 0x2fa4}, ++ {0xcc60, 0x3cd4}, ++ {0xcc61, 0x6624}, ++ {0xcc62, 0x2f45}, ++ {0xcc63, 0x3015}, ++ {0xcc64, 0x5653}, ++ {0xcc65, 0x2eb2}, ++ {0xcc66, 0x3002}, ++ {0xcc67, 0x13d2}, ++ {0xcc68, 0x2ed2}, ++ {0xcc69, 0x3002}, ++ {0xcc6a, 0x1002}, ++ {0xcc6b, 0x6f72}, ++ {0xcc6c, 0x1002}, ++ {0xcc6d, 0x628f}, ++ {0xcc6e, 0x2602}, ++ {0xcc6f, 0x3012}, ++ {0xcc70, 0x1002}, ++ {0xcc71, 0x200d}, ++ {0xcc72, 0x320d}, ++ {0xcc73, 0x2862}, ++ {0xcc74, 0x3012}, ++ {0xcc75, 0x1002}, ++ {0xcc76, 0x25c4}, ++ {0xcc77, 0x3c54}, ++ {0xcc78, 0x6437}, ++ {0xcc79, 0x25c4}, ++ {0xcc7a, 0x3c54}, ++ {0xcc7b, 0x6437}, ++ {0xcc7c, 0x20c4}, ++ {0xcc7d, 0x3c04}, ++ {0xcc7e, 0x6724}, ++ {0xcc7f, 0x20c4}, ++ {0xcc80, 0x3c04}, ++ {0xcc81, 0x6724}, ++ {0xcc82, 0x6f72}, ++ {0xcc83, 0x1002}, ++ {0xcc84, 0x628f}, ++ {0xcc85, 0x26f2}, ++ {0xcc86, 0x3012}, ++ {0xcc87, 0x1002}, ++ {0xcc88, 0xc503}, ++ {0xcc89, 0xd5d5}, ++ {0xcc8a, 0xc600}, ++ {0xcc8b, 0x2a6d}, ++ {0xcc8c, 0xc601}, ++ {0xcc8d, 0x2a4c}, ++ {0xcc8e, 0xc602}, ++ {0xcc8f, 0x0111}, ++ {0xcc90, 0xc60c}, ++ {0xcc91, 0x5900}, ++ {0xcc92, 0xc710}, ++ {0xcc93, 0x0700}, ++ {0xcc94, 0xc718}, ++ {0xcc95, 0x0700}, ++ {0xcc96, 0xc720}, ++ {0xcc97, 0x4700}, ++ {0xcc98, 0xc801}, ++ {0xcc99, 0x7f50}, ++ {0xcc9a, 0xc802}, ++ {0xcc9b, 0x7760}, ++ {0xcc9c, 0xc803}, ++ {0xcc9d, 0x7fce}, ++ {0xcc9e, 0xc804}, ++ {0xcc9f, 0x5700}, ++ {0xcca0, 0xc805}, ++ {0xcca1, 0x5f11}, ++ {0xcca2, 0xc806}, ++ {0xcca3, 0x4751}, ++ {0xcca4, 0xc807}, ++ {0xcca5, 0x57e1}, ++ {0xcca6, 0xc808}, ++ {0xcca7, 0x2700}, ++ {0xcca8, 0xc809}, ++ {0xcca9, 0x0000}, ++ {0xccaa, 0xc821}, ++ {0xccab, 0x0002}, ++ {0xccac, 0xc822}, ++ {0xccad, 0x0014}, ++ {0xccae, 0xc832}, ++ {0xccaf, 0x1186}, ++ {0xccb0, 0xc847}, ++ {0xccb1, 0x1e02}, ++ {0xccb2, 0xc013}, ++ {0xccb3, 0xf341}, ++ {0xccb4, 0xc01a}, ++ {0xccb5, 0x0446}, ++ {0xccb6, 0xc024}, ++ {0xccb7, 0x1000}, ++ {0xccb8, 0xc025}, ++ {0xccb9, 0x0a00}, ++ {0xccba, 0xc026}, ++ {0xccbb, 0x0c0c}, ++ {0xccbc, 0xc027}, ++ {0xccbd, 0x0c0c}, ++ {0xccbe, 0xc029}, ++ {0xccbf, 0x00a0}, ++ {0xccc0, 0xc030}, ++ {0xccc1, 0x0a00}, ++ {0xccc2, 0xc03c}, ++ {0xccc3, 0x001c}, ++ {0xccc4, 0xc005}, ++ {0xccc5, 0x7a06}, ++ {0xccc6, 0x0000}, ++ {0xccc7, 0x0000}, ++ {0xccc8, 0x628f}, ++ {0xccc9, 0x26f2}, ++ {0xccca, 0x3012}, ++ {0xcccb, 0x1002}, ++ {0xcccc, 0xc620}, ++ {0xcccd, 0x0000}, ++ {0xccce, 0xc621}, ++ {0xcccf, 0x003f}, ++ {0xccd0, 0xc622}, ++ {0xccd1, 0x0000}, ++ {0xccd2, 0xc623}, ++ {0xccd3, 0x0000}, ++ {0xccd4, 0xc624}, ++ {0xccd5, 0x0000}, ++ {0xccd6, 0xc625}, ++ {0xccd7, 0x0000}, ++ {0xccd8, 0xc627}, ++ {0xccd9, 0x0000}, ++ {0xccda, 0xc628}, ++ {0xccdb, 0x0000}, ++ {0xccdc, 0xc62c}, ++ {0xccdd, 0x0000}, ++ {0xccde, 0x0000}, ++ {0xccdf, 0x0000}, ++ {0xcce0, 0x628f}, ++ {0xcce1, 0xd019}, ++ {0xcce2, 0x26f2}, ++ {0xcce3, 0x3012}, ++ {0xcce4, 0x1002}, ++ {0xcce5, 0xc210}, ++ {0xcce6, 0x8000}, ++ {0xcce7, 0xc210}, ++ {0xcce8, 0x8010}, ++ {0xcce9, 0xc210}, ++ {0xccea, 0x8000}, ++ {0xcceb, 0xc210}, ++ {0xccec, 0x0000}, ++ {0xcced, 0x0000}, ++ {0xccee, 0x0000}, ++ {0xccef, 0x8221}, ++ {0xccf0, 0x2752}, ++ {0xccf1, 0x3012}, ++ {0xccf2, 0x1002}, ++ {0xccf3, 0x6f72}, ++ {0xccf4, 0x1002}, ++ {0xccf5, 0x2806}, ++ {0xccf6, 0x3006}, ++ {0xccf7, 0x2007}, ++ {0xccf8, 0x3cc7}, ++ {0xccf9, 0xe161}, ++ {0xccfa, 0xc171}, ++ {0xccfb, 0x6134}, ++ {0xccfc, 0x6135}, ++ {0xccfd, 0x5453}, ++ {0xccfe, 0x2858}, ++ {0xccff, 0x3018}, ++ {0xcd00, 0x1348}, ++ {0xcd01, 0x6524}, ++ {0xcd02, 0x27b8}, ++ {0xcd03, 0x3018}, ++ {0xcd04, 0x1008}, ++ {0xcd05, 0x1002}, ++ {0xcd06, 0x628f}, ++ {0xcd07, 0x5dd3}, ++ {0xcd08, 0x2906}, ++ {0xcd09, 0x3016}, ++ {0xcd0a, 0x1306}, ++ {0xcd0b, 0x2ff7}, ++ {0xcd0c, 0x30f7}, ++ {0xcd0d, 0x60b7}, ++ {0xcd0e, 0xdffd}, ++ {0xcd0f, 0x0008}, ++ {0xcd10, 0x6f72}, ++ {0xcd11, 0x1002}, ++ {0xcd12, 0x0000}, ++ {0xcdff, 0x0a01}, ++ /* end of code block */ ++ ++ /* Unpause the microcontroller to start program */ ++ {0xca00, 0x0080}, ++ {0xca12, 0x0000}, ++ {0x0000, 0x000A}, /* wait 10ms just to be safe */ ++ {0xffff, 0xffff} /* table terminator */ ++}; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0008-Staging-add-me4000-firmware-files.patch b/src/patches/suse-2.6.27.31/patches.drivers/0008-Staging-add-me4000-firmware-files.patch new file mode 100644 index 000000000..e9ef435d7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0008-Staging-add-me4000-firmware-files.patch @@ -0,0 +1,15478 @@ +From cff338a9bd9d1acd6067d3ec93e846830e0b5974 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 21 Mar 2008 14:12:51 -0700 +Subject: [PATCH 08/23] Staging: add me4000 firmware files +Patch-mainline: 2.6.28 + +Originally written by Guenter Gebhardt + +TODO: + move this to the request_firmware() interface + +Cc: Wolfgang Beiter +Cc: Guenter Gebhardt +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/me4000/me4000_firmware.h |10033 ++++++++++++++++++++++++++++++ + drivers/staging/me4000/me4610_firmware.h | 5409 ++++++++++++++++ + 2 files changed, 15442 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/me4000/me4000_firmware.h + create mode 100644 drivers/staging/me4000/me4610_firmware.h + +diff --git a/drivers/staging/me4000/me4000_firmware.h b/drivers/staging/me4000/me4000_firmware.h +new file mode 100644 +index 0000000..87c23f6 +--- /dev/null ++++ b/drivers/staging/me4000/me4000_firmware.h +@@ -0,0 +1,10033 @@ ++/* ++ This file is copyright by Meilhaus Electronic GmbH 2003. ++ You are not allowed to distribute, sell, modify, reverse engineer or use this ++ code (or parts of it) for any other purpose or under any other conditions ++ than stated below. ++ ++ 1) You are allowed to distribute verbatim copies of this file together ++ with device drivers for the Meilhaus ME-4000, board family. ++ ++ 2) Derived work (device drivers using this file) can be published 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. Any other license terms have ++ to be agreed by Meilhaus GmbH in written. ++ ++ 2) This file is distributed WITHOUT ANY WARRANTY; ++ without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. Meilhaus is under ++ no means liable for products using this file or parts of it. ++ ++ 3) The copyright of this file has to be mentioned in derived work. ++ ++ 4) If this license terms are not valid due to any other law ++ or restrictions imposed on you, you are not allowed to use ++ this file in any way at all. ++ */ ++ ++/* Version 18 of standard firmware */ ++static unsigned char xilinx_firm[] = { ++0x00, 0x01, 0xfb, 0xdc, 0x01, 0x01, 0x04, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, ++0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0x99, 0xAA, 0x66, 0x0C, 0x00, ++0x01, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x0C, 0x80, 0x06, 0x80, 0x00, 0x00, 0x00, ++0xF0, 0x0C, 0x80, 0x04, 0x80, 0x00, 0x01, 0xFC, 0xB4, 0x0C, 0x00, 0x03, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x90, 0x0C, ++0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, ++0x00, 0x80, 0x0C, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x6E, 0x0D, 0x01, 0x49, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x80, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, ++0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x09, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xFE, 0x4B, 0x02, 0x3E, 0x00, 0xEA, 0x00, 0xA8, 0x00, 0xA0, ++0x0A, 0x80, 0x2A, 0x00, 0xAE, 0x00, 0xB8, 0x02, 0xA0, 0x02, 0x80, 0x28, 0x00, ++0xAA, 0x00, 0xB8, 0x02, 0x60, 0x02, 0x80, 0x0B, 0x00, 0x26, 0x00, 0xB8, 0x00, ++0xE0, 0x02, 0x80, 0x0B, 0x00, 0x2E, 0x00, 0xB8, 0x00, 0xE0, 0x02, 0x80, 0x0B, ++0x00, 0xAE, 0x00, 0xB8, 0x02, 0x80, 0x0A, 0xFC, 0x23, 0x01, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA0, 0x5B, 0x00, 0xF3, 0x04, 0xCC, 0x01, 0xF2, 0x96, 0xC2, ++0xDF, 0x30, 0xBB, 0x43, 0xD0, 0x73, 0xB0, 0x8F, 0xC0, 0x3D, 0x02, 0xFB, 0x48, ++0xFC, 0x13, 0x30, 0x13, 0xC0, 0x4F, 0x02, 0x3F, 0x01, 0xDC, 0x13, 0xB0, 0x4F, ++0xC0, 0x4F, 0x00, 0x3B, 0xC9, 0xCC, 0x04, 0xF2, 0x13, 0xC0, 0xFC, 0x00, 0xFB, ++0xC9, 0x8C, 0x27, 0x30, 0x03, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x08, 0x57, 0x40, 0xE1, 0x08, 0x44, 0x03, 0xD0, 0x09, 0x40, 0x13, ++0x01, 0xD1, 0x04, 0xC4, 0x1B, 0x10, 0x6D, 0x40, 0x3C, 0x02, 0xDD, 0x06, 0xF4, ++0x0F, 0x10, 0x11, 0x40, 0x27, 0x11, 0x57, 0x81, 0xC4, 0x0F, 0xD0, 0xBF, 0x40, ++0x64, 0x00, 0x51, 0x04, 0x44, 0x04, 0xD0, 0x11, 0x50, 0x34, 0x00, 0xD1, 0x00, ++0x54, 0x11, 0x14, 0x19, 0x40, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x11, 0x00, 0x37, 0x00, 0xC1, 0x00, 0x04, 0x00, 0xD8, 0x48, 0x44, 0x21, 0x00, ++0xC9, 0x00, 0x14, 0x03, 0xD0, 0xCC, 0x64, 0x33, 0x11, 0xCD, 0x06, 0x34, 0x23, ++0x50, 0x00, 0x00, 0x02, 0x01, 0x8D, 0x00, 0x04, 0x23, 0xD0, 0x0C, 0x42, 0x01, ++0x00, 0xC1, 0x00, 0x14, 0x00, 0xD0, 0x00, 0x44, 0x30, 0x09, 0xCD, 0x44, 0x44, ++0x12, 0x10, 0x00, 0x44, 0x47, 0x88, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA8, 0xB5, 0x01, 0xD1, 0x00, 0x44, 0x0A, 0xD8, 0x09, 0x40, 0x27, 0x00, 0xD1, ++0x40, 0x44, 0x03, 0x50, 0x0D, 0x60, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x03, 0x50, ++0x01, 0x40, 0x27, 0x10, 0xD5, 0x00, 0x44, 0x03, 0xCA, 0x0D, 0x40, 0x65, 0x00, ++0xC1, 0x00, 0x44, 0xC6, 0xD0, 0x19, 0x40, 0x30, 0x00, 0xD1, 0x00, 0x54, 0x09, ++0x14, 0x11, 0x40, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, ++0xE3, 0x00, 0xD3, 0x00, 0x4C, 0x0A, 0xF0, 0x0D, 0xC4, 0xF7, 0x00, 0x9B, 0x40, ++0x5C, 0x03, 0xF2, 0x0D, 0xC6, 0x37, 0x10, 0xDB, 0x00, 0x74, 0x03, 0x70, 0xA1, ++0x81, 0x37, 0x00, 0xCF, 0x03, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0xC7, 0x01, 0x93, ++0x00, 0x5D, 0x0C, 0xF0, 0x31, 0xC0, 0x34, 0x00, 0x5F, 0xC0, 0x0C, 0x07, 0x30, ++0x71, 0x80, 0x03, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, ++0x08, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0xFF, 0x18, 0xFF, 0x04, 0xAC, ++0x03, 0xB1, 0x0D, 0xC8, 0x3D, 0x00, 0xFF, 0x80, 0x7C, 0x03, 0xB4, 0x13, 0xCA, ++0xFF, 0x00, 0xF7, 0x03, 0xE4, 0x43, 0xF0, 0x0E, 0xC1, 0x0E, 0x00, 0xFF, 0x00, ++0xFC, 0x40, 0xF0, 0x0B, 0xE2, 0x3F, 0x00, 0xFF, 0x83, 0xFD, 0x25, 0xF0, 0x0B, ++0xC0, 0x1E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x25, 0x00, ++0xD3, 0x00, 0x4C, 0x0A, 0x30, 0x0D, 0xC0, 0xA4, 0x00, 0xD7, 0x00, 0x5C, 0x03, ++0xF0, 0x0D, 0xC0, 0x35, 0x00, 0xD7, 0x00, 0x0C, 0x03, 0x30, 0x41, 0xC4, 0x35, ++0x00, 0xD3, 0x02, 0x5C, 0x03, 0xF0, 0x0D, 0xC0, 0x05, 0x00, 0xDF, 0x00, 0x7C, ++0x0E, 0x30, 0x01, 0xC1, 0x37, 0x10, 0xD7, 0x04, 0x4C, 0x0B, 0x30, 0x21, 0xC0, ++0x0B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xF4, 0x01, 0xF5, ++0x00, 0x44, 0x2E, 0x10, 0x09, 0x40, 0x25, 0x00, 0xD1, 0x00, 0xC4, 0x03, 0x10, ++0x0F, 0xC0, 0x3E, 0x00, 0xF1, 0x00, 0xEC, 0x03, 0x10, 0x11, 0xC0, 0x35, 0x00, ++0xD1, 0x01, 0xDC, 0x07, 0x70, 0x2F, 0xC3, 0x23, 0x06, 0xDD, 0x20, 0x64, 0x02, ++0xB0, 0x38, 0x41, 0x37, 0x00, 0xD1, 0x03, 0x6C, 0x29, 0x50, 0xA9, 0x40, 0x4E, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x22, 0x01, 0xD1, 0x00, ++0x04, 0x29, 0x90, 0x04, 0x40, 0x24, 0x00, 0xD5, 0x00, 0x34, 0x03, 0x50, 0x0D, ++0x40, 0x33, 0x00, 0xCD, 0x00, 0x04, 0x03, 0x5D, 0x00, 0x40, 0x12, 0x20, 0x01, ++0x04, 0x10, 0x0B, 0xD0, 0x1C, 0x42, 0x21, 0x80, 0x0D, 0x40, 0x34, 0x08, 0x90, ++0x30, 0x40, 0x31, 0x10, 0xD5, 0x03, 0x04, 0x05, 0x18, 0x18, 0x44, 0x1F, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x68, 0x00, 0xE5, 0x01, 0x84, ++0x07, 0x98, 0x1B, 0x40, 0x69, 0x80, 0xE1, 0x81, 0x24, 0x07, 0x10, 0x9E, 0x40, ++0x78, 0x80, 0xED, 0x01, 0xA4, 0x07, 0x50, 0x52, 0x61, 0x79, 0x00, 0x21, 0x19, ++0x90, 0x07, 0x51, 0x1C, 0x40, 0x6A, 0x00, 0x6D, 0x41, 0xA4, 0x06, 0xD2, 0x12, ++0x40, 0x7B, 0x00, 0xF1, 0x09, 0xE4, 0x45, 0x54, 0x1A, 0x40, 0x12, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x20, 0x02, 0xC3, 0x88, 0x44, 0x02, ++0xB0, 0x88, 0x40, 0x20, 0x00, 0xD7, 0x08, 0x34, 0x03, 0x70, 0x0C, 0x40, 0x37, ++0x02, 0xDD, 0x00, 0x04, 0x03, 0x71, 0x10, 0xC0, 0x16, 0x02, 0x01, 0x80, 0x1C, ++0xC3, 0xF0, 0x0C, 0x40, 0x21, 0x00, 0xCF, 0x09, 0x3C, 0x91, 0xB0, 0x88, 0xC0, ++0x37, 0x00, 0xC7, 0x10, 0x0C, 0x11, 0x38, 0x84, 0xC1, 0x4B, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xB0, 0x2D, 0x00, 0xFF, 0x02, 0xFC, 0x02, 0x60, ++0x0B, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xDC, 0x43, 0x70, 0x0F, 0xC0, 0x3F, 0x04, ++0xF3, 0x00, 0xFC, 0x0B, 0xB0, 0x02, 0xC0, 0x3F, 0x48, 0xFF, 0x00, 0x7C, 0x2B, ++0xF0, 0x8F, 0xC0, 0x2F, 0x00, 0xFF, 0x20, 0x3C, 0x03, 0x90, 0x09, 0xC0, 0x3F, ++0x00, 0xEE, 0x20, 0x7C, 0x01, 0xD4, 0x01, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0xA0, 0x27, 0x00, 0xDF, 0x0E, 0x7C, 0x00, 0xC0, 0x0D, ++0xC0, 0x75, 0x00, 0xD3, 0x00, 0x7C, 0x53, 0x70, 0x8D, 0xC6, 0xB4, 0x04, 0xDF, ++0x00, 0x7C, 0x13, 0xB0, 0x00, 0xC0, 0x34, 0x10, 0x07, 0x80, 0x5C, 0x13, 0x30, ++0x5C, 0xC1, 0x04, 0x00, 0x9F, 0x40, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x37, 0x00, ++0x5F, 0x00, 0x4C, 0x01, 0x30, 0x09, 0xC0, 0x47, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x88, 0x29, 0x00, 0xED, 0x04, 0xB4, 0x03, 0xD0, 0x0A, 0x40, ++0x3B, 0x00, 0xE1, 0x00, 0xB4, 0x13, 0xD0, 0x4F, 0x40, 0x3A, 0x11, 0xED, 0x00, ++0xB4, 0x03, 0xD0, 0x02, 0x40, 0x39, 0x00, 0xAD, 0x00, 0x04, 0x03, 0x10, 0x2E, ++0x40, 0x08, 0x08, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0A, 0x40, 0x3B, 0x00, 0xED, ++0x20, 0xC4, 0x01, 0x10, 0x0A, 0x40, 0x4B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x00, 0x69, 0x00, 0xED, 0x01, 0xB4, 0x06, 0x90, 0x3E, 0x4C, 0x6F, ++0x10, 0xE1, 0x01, 0xB4, 0x17, 0xD0, 0x0E, 0x40, 0x7A, 0x00, 0xED, 0x0D, 0x94, ++0x27, 0xD0, 0x13, 0x41, 0x7A, 0x80, 0x6D, 0x01, 0x94, 0x37, 0x51, 0x5E, 0x40, ++0x6A, 0x04, 0xED, 0x01, 0xB4, 0x07, 0xD1, 0x1A, 0x48, 0x7B, 0x80, 0xAD, 0x01, ++0x84, 0x05, 0x14, 0x1E, 0x42, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x28, 0x23, 0x84, 0xCD, 0x00, 0x34, 0x2E, 0xD0, 0x08, 0x40, 0x23, 0x49, ++0xC1, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x32, 0x00, 0xCD, 0x00, 0x36, 0x03, ++0xD0, 0x0C, 0x40, 0x33, 0x11, 0xCD, 0x03, 0x04, 0x03, 0x50, 0x0C, 0x40, 0x70, ++0x00, 0xCD, 0x00, 0x34, 0x6F, 0xD2, 0x0C, 0x40, 0x33, 0x00, 0x8D, 0x44, 0x05, ++0x21, 0x14, 0x1C, 0x40, 0x4B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, ++0xA8, 0xD9, 0x00, 0x5F, 0x00, 0xFC, 0x01, 0xB0, 0x07, 0xC4, 0xDF, 0x01, 0x53, ++0x00, 0x7C, 0x01, 0x78, 0x05, 0xC0, 0x14, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xB0, ++0x17, 0xC0, 0x9E, 0x01, 0x7F, 0x0E, 0x5C, 0x01, 0x74, 0x05, 0xC8, 0x1E, 0x00, ++0x7F, 0x02, 0xFC, 0x0D, 0xE0, 0x07, 0xC0, 0x17, 0x20, 0x7F, 0x07, 0xCC, 0x05, ++0x10, 0x07, 0xC1, 0x5F, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, ++0x07, 0x02, 0x1F, 0x00, 0x3C, 0x40, 0xF0, 0x41, 0xC0, 0x07, 0x00, 0x1F, 0x60, ++0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, ++0xC1, 0x05, 0x10, 0x1F, 0x00, 0x7C, 0x80, 0x91, 0x01, 0xD0, 0x87, 0x01, 0x1F, ++0x30, 0x70, 0x08, 0xF0, 0x41, 0xC0, 0x07, 0x18, 0x1F, 0x40, 0x7D, 0x00, 0xF0, ++0x11, 0xC0, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, ++0x01, 0x9B, 0x00, 0x4D, 0x02, 0x30, 0x09, 0xC0, 0x25, 0x00, 0x9F, 0x00, 0x74, ++0x02, 0xF0, 0x09, 0xC0, 0x23, 0x40, 0x93, 0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC0, ++0x24, 0x00, 0x9F, 0x00, 0x44, 0x02, 0x70, 0x09, 0xC4, 0x67, 0x02, 0x9D, 0x00, ++0x4C, 0x16, 0xF0, 0x19, 0xC0, 0x27, 0x80, 0x9F, 0x03, 0x4C, 0x22, 0x34, 0x08, ++0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x66, 0x00, ++0x95, 0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, ++0xD0, 0x09, 0x40, 0x27, 0x00, 0x91, 0x00, 0x74, 0x06, 0xF0, 0xB8, 0x40, 0x24, ++0x00, 0x8D, 0x08, 0x01, 0x06, 0x30, 0x29, 0xC0, 0x27, 0x21, 0x8D, 0x00, 0x44, ++0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x8D, 0x03, 0x6C, 0x1E, 0x54, 0x29, 0x40, ++0x05, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x81, ++0x00, 0x44, 0x22, 0x10, 0x08, 0x40, 0x35, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, ++0x09, 0x40, 0x26, 0x00, 0x99, 0x00, 0x74, 0x22, 0xD0, 0x09, 0x60, 0x24, 0x80, ++0xDD, 0x80, 0x54, 0x12, 0x00, 0xA9, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x44, 0x02, ++0xD0, 0x4D, 0x43, 0x27, 0x00, 0x98, 0x10, 0x04, 0x02, 0x10, 0xA9, 0x40, 0x60, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0x85, 0x04, ++0x04, 0x1A, 0x14, 0x08, 0x40, 0x20, 0x20, 0x8D, 0x08, 0x34, 0x12, 0xD0, 0x88, ++0x64, 0x23, 0x01, 0x89, 0x08, 0x34, 0x12, 0xD0, 0x09, 0x40, 0x20, 0x02, 0xDD, ++0x00, 0x14, 0x02, 0x14, 0x08, 0x44, 0x23, 0x00, 0x9D, 0x08, 0x04, 0x02, 0xD8, ++0x08, 0x42, 0x23, 0x02, 0x9D, 0x08, 0x24, 0x22, 0x10, 0x48, 0x40, 0x41, 0x88, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x13, 0x0A, 0x4C, ++0x09, 0x30, 0xA1, 0xC0, 0x85, 0x02, 0x1D, 0x02, 0x7C, 0x28, 0xF0, 0x61, 0xC1, ++0x87, 0x02, 0x19, 0x16, 0x74, 0x00, 0xF0, 0x05, 0xC0, 0x84, 0x00, 0x1F, 0x00, ++0x5C, 0x51, 0x70, 0x41, 0x45, 0x07, 0x10, 0x1F, 0x02, 0x4D, 0x01, 0xF0, 0x01, ++0xC4, 0x87, 0x00, 0x0D, 0x02, 0x4C, 0x88, 0x30, 0x01, 0xC4, 0x74, 0xC0, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x2F, 0x00, 0x9F, 0x08, 0xFC, 0x0A, ++0xF0, 0x0B, 0xC0, 0x2B, 0x00, 0xBF, 0x04, 0x7C, 0x22, 0xF0, 0x49, 0xC0, 0x27, ++0x02, 0x93, 0x04, 0x7C, 0x22, 0x70, 0x0B, 0xD0, 0x2F, 0x01, 0xBF, 0x00, 0x6C, ++0x02, 0x70, 0x09, 0xC0, 0x2D, 0x10, 0xBF, 0x04, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, ++0x27, 0x01, 0xBF, 0x84, 0xFC, 0x12, 0xF0, 0x8B, 0xC0, 0x67, 0x60, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, 0x00, 0x93, 0x8C, 0xE8, 0x02, 0xF0, ++0x09, 0xC0, 0x27, 0x02, 0x93, 0x60, 0x7C, 0x52, 0x30, 0xC9, 0xC0, 0x25, 0x00, ++0x9B, 0x00, 0xDC, 0x02, 0xF0, 0x0B, 0xC0, 0x27, 0x00, 0xBF, 0x00, 0xCC, 0x02, ++0xB0, 0x0B, 0xC0, 0x2B, 0x28, 0x9F, 0x40, 0xBC, 0x02, 0xF0, 0x0F, 0xC0, 0x24, ++0x20, 0xBF, 0x40, 0xCC, 0x02, 0x30, 0x0B, 0xC0, 0x60, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, 0x11, 0x0C, 0x44, 0x49, 0xD0, 0x01, ++0x41, 0x07, 0x00, 0x11, 0x14, 0x74, 0x10, 0x10, 0xC1, 0x48, 0x84, 0x04, 0x11, ++0x10, 0x44, 0x20, 0xD2, 0x01, 0x40, 0x07, 0x01, 0x1D, 0x00, 0x50, 0x08, 0x14, ++0x01, 0x40, 0x17, 0x00, 0x1D, 0x14, 0x64, 0x00, 0xD0, 0x01, 0x40, 0x05, 0x0C, ++0x5D, 0x90, 0x54, 0x00, 0x14, 0x01, 0x50, 0x70, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA0, 0x27, 0x40, 0x81, 0x04, 0x34, 0x32, 0xD0, 0x08, 0x40, ++0x27, 0x40, 0x85, 0x04, 0x34, 0x52, 0x10, 0x48, 0x40, 0x21, 0x03, 0x89, 0x08, ++0x14, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x05, 0x9D, 0x00, 0x04, 0x22, 0x12, 0x8C, ++0x42, 0x23, 0x00, 0x8D, 0x04, 0x34, 0x02, 0x50, 0x09, 0x40, 0x23, 0x01, 0x8D, ++0x00, 0x44, 0x02, 0x10, 0x08, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA8, 0x25, 0x04, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x69, 0x60, 0x27, ++0x00, 0x95, 0x00, 0x34, 0x02, 0x10, 0x09, 0x60, 0x21, 0x00, 0x91, 0x00, 0x44, ++0x02, 0xD0, 0x29, 0x40, 0x27, 0x80, 0x9C, 0x02, 0x54, 0x02, 0x10, 0x09, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x64, 0x0A, 0xD0, 0x29, 0x40, 0x27, 0x80, 0x8D, 0x08, ++0x54, 0x12, 0x12, 0x19, 0x40, 0x60, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xA8, 0x27, 0x00, 0x93, 0x00, 0x7C, 0x0E, 0xF0, 0x39, 0xE0, 0x27, 0x21, ++0x97, 0x00, 0x7C, 0x02, 0x30, 0x09, 0xC2, 0x25, 0x00, 0x9B, 0x00, 0x5C, 0x02, ++0xF0, 0x29, 0xC0, 0x27, 0x00, 0x9F, 0x03, 0x4C, 0x02, 0xB0, 0x09, 0xC0, 0x67, ++0x00, 0x9F, 0x24, 0x7C, 0x02, 0xF8, 0x88, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x4C, ++0x02, 0x30, 0x59, 0xC0, 0x14, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x00, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x56, 0xF0, 0x19, 0xC0, 0x67, 0x01, 0x9B, ++0x04, 0x7C, 0x02, 0xF4, 0x08, 0xCC, 0x26, 0x00, 0x8F, 0x00, 0x7C, 0x02, 0xF0, ++0x39, 0xC2, 0x27, 0x00, 0x9F, 0x02, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x01, ++0x9F, 0x05, 0x7C, 0x22, 0xF0, 0x19, 0xC2, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xF0, 0x08, 0xC0, 0x53, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, ++0x05, 0x00, 0x0F, 0x00, 0x5C, 0x08, 0xF0, 0x21, 0xC0, 0x85, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x21, ++0xC1, 0x07, 0x00, 0x1B, 0x06, 0x4C, 0x40, 0xF0, 0x01, 0xC1, 0x04, 0x01, 0x13, ++0x02, 0x7C, 0x00, 0xB0, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x00, 0x4C, 0x20, 0x31, ++0x21, 0x80, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x18, ++0x00, 0x5D, 0x00, 0xC0, 0x05, 0x70, 0x05, 0x40, 0x10, 0x00, 0x5C, 0x00, 0x74, ++0x01, 0xD0, 0x05, 0xC0, 0x15, 0x00, 0x5D, 0x00, 0x74, 0x45, 0xD0, 0x07, 0xC0, ++0x15, 0x00, 0x61, 0x00, 0xDC, 0x4D, 0x70, 0x07, 0x40, 0xDD, 0x40, 0x51, 0x00, ++0xF4, 0x3D, 0x10, 0x77, 0x40, 0x17, 0x40, 0x71, 0x00, 0x84, 0x0D, 0xF0, 0xA7, ++0xC0, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x22, 0x20, ++0xCD, 0x80, 0x10, 0x0F, 0x50, 0x0C, 0x40, 0x33, 0x80, 0xCC, 0x00, 0x34, 0x03, ++0xD0, 0x0C, 0x00, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x02, 0xD0, 0xBC, 0x40, 0x33, ++0x00, 0xC9, 0x01, 0x24, 0x07, 0x50, 0x0C, 0x40, 0xF0, 0x00, 0xC1, 0x20, 0x34, ++0x07, 0x10, 0x4C, 0x60, 0x33, 0x90, 0xC9, 0x00, 0x04, 0x4F, 0x10, 0x2C, 0x42, ++0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x00, 0xCD, ++0x04, 0x84, 0x0B, 0x50, 0x1E, 0x40, 0x3A, 0x03, 0xED, 0x08, 0xB4, 0x03, 0xD0, ++0x8E, 0x40, 0x39, 0xA1, 0xED, 0x00, 0xB4, 0x02, 0xD0, 0x0E, 0x40, 0x7D, 0x00, ++0xFD, 0x42, 0x90, 0x03, 0x50, 0x18, 0x40, 0xFD, 0x10, 0xE1, 0x04, 0xF4, 0x06, ++0x10, 0x0E, 0x40, 0x7B, 0x00, 0xE9, 0x00, 0xC5, 0x01, 0x90, 0x0C, 0x60, 0x12, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x68, 0x00, 0xEF, 0x07, ++0x94, 0x07, 0x70, 0x1F, 0xC8, 0x7B, 0x00, 0xEF, 0x05, 0xB4, 0x0F, 0xF0, 0x1E, ++0x40, 0x7B, 0x04, 0xED, 0x01, 0xBC, 0x07, 0xF2, 0x1A, 0xC8, 0x7B, 0x24, 0xFB, ++0x01, 0xAC, 0x84, 0x70, 0x1A, 0xC0, 0x78, 0x00, 0xE1, 0x09, 0xB4, 0x06, 0x34, ++0x1E, 0xC4, 0x7F, 0x08, 0x79, 0x01, 0xCC, 0x06, 0x32, 0x16, 0xC0, 0x50, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x25, 0x10, 0xDF, 0x02, 0x7C, ++0x03, 0x70, 0xED, 0xC8, 0xB5, 0x21, 0xDF, 0x00, 0x7C, 0x43, 0xF0, 0x0D, 0xC8, ++0x37, 0x02, 0xDF, 0x88, 0x7C, 0x03, 0xD0, 0x09, 0xC0, 0x33, 0x01, 0x93, 0x80, ++0x7C, 0x01, 0x60, 0x01, 0xC0, 0x17, 0x00, 0xDF, 0x2A, 0x7C, 0x00, 0x60, 0x09, ++0xC0, 0xB7, 0x06, 0x97, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC2, 0x43, 0x60, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x6F, 0x00, 0xFF, 0x03, 0xC8, 0x21, ++0xE0, 0x3E, 0xC2, 0xFC, 0x12, 0xFF, 0x09, 0xEC, 0x07, 0x30, 0x1F, 0xC0, 0x7F, ++0x02, 0xFB, 0x01, 0xDC, 0x27, 0xF0, 0x9F, 0xC0, 0x7D, 0x04, 0xB3, 0x41, 0xBC, ++0x27, 0xB0, 0x13, 0xC0, 0x7F, 0x00, 0xFF, 0x21, 0xFC, 0x06, 0xF0, 0x1F, 0xC0, ++0x7F, 0x00, 0xFF, 0x01, 0xBC, 0x87, 0x30, 0x1F, 0xC0, 0x0B, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x39, 0x10, 0xFD, 0x04, 0x84, 0x01, 0xF0, ++0x0E, 0xC1, 0x3A, 0x00, 0xED, 0x00, 0xEC, 0x03, 0x15, 0x8E, 0x48, 0x3B, 0x40, ++0xF1, 0x00, 0x84, 0x23, 0xD0, 0xA8, 0x40, 0x3B, 0x20, 0x21, 0x00, 0xB4, 0x29, ++0x10, 0x62, 0x40, 0x3B, 0x00, 0xDF, 0x00, 0x84, 0x02, 0xF0, 0x0E, 0x40, 0x3B, ++0x02, 0xED, 0x08, 0xBC, 0x01, 0xB0, 0x0E, 0x41, 0x57, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0xED, 0x00, 0x86, 0x63, 0xD8, 0x0F, ++0x40, 0x38, 0x80, 0xFD, 0x40, 0x84, 0x23, 0x90, 0x0E, 0x40, 0x33, 0x10, 0xE1, ++0x00, 0xB4, 0x23, 0xD2, 0x22, 0x60, 0x39, 0x00, 0xA5, 0x00, 0xB4, 0x00, 0x12, ++0x02, 0x40, 0x2A, 0x00, 0xED, 0x10, 0x94, 0x02, 0xD0, 0x06, 0x40, 0x3B, 0x00, ++0x6D, 0x00, 0xF4, 0x02, 0x10, 0x06, 0x40, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x06, 0x28, 0x23, 0x00, 0xCD, 0x00, 0x04, 0x06, 0x58, 0x3C, 0x40, ++0x32, 0x00, 0xCD, 0x08, 0x24, 0x03, 0x90, 0x0C, 0x42, 0x33, 0x20, 0xC1, 0x00, ++0x16, 0x03, 0xD0, 0x00, 0x40, 0xB3, 0x00, 0x05, 0x0B, 0x36, 0x01, 0x10, 0x00, ++0x40, 0x03, 0x10, 0xCD, 0x40, 0x04, 0x10, 0x51, 0x00, 0x40, 0x33, 0x00, 0x9D, ++0x12, 0x14, 0xAF, 0x90, 0x50, 0x00, 0x1B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0xA8, 0x25, 0x01, 0xFF, 0x00, 0x4D, 0x22, 0xD0, 0x3F, 0xC0, 0x3C, ++0x00, 0xFF, 0x00, 0xCC, 0x03, 0xB0, 0x0F, 0xC0, 0x3F, 0x00, 0xF3, 0x00, 0x1C, ++0x02, 0xF0, 0x25, 0xC0, 0xBD, 0x02, 0x57, 0x0B, 0x7C, 0x03, 0x11, 0x09, 0xC0, ++0xF7, 0x02, 0xEF, 0x00, 0x5C, 0x0A, 0xD0, 0x9D, 0x40, 0x3F, 0x00, 0x9F, 0x02, ++0x70, 0x03, 0x10, 0x21, 0xC0, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x0A, 0xF0, 0x4D, 0xC4, 0x37, 0x10, ++0xDF, 0x80, 0x7C, 0x83, 0x70, 0x0D, 0xC8, 0x37, 0x00, 0xD7, 0x80, 0x64, 0x02, ++0xF0, 0x3D, 0xC0, 0x37, 0x48, 0x5A, 0x00, 0x7C, 0x03, 0x70, 0x29, 0xC0, 0x67, ++0x00, 0xD7, 0x00, 0x5C, 0x0A, 0xF0, 0x15, 0xC4, 0x37, 0x20, 0x5F, 0x02, 0x7C, ++0x09, 0xF0, 0x29, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, ++0x08, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0x30, 0x0F, 0xC0, 0x3D, 0x00, 0xFF, ++0x00, 0xFE, 0x03, 0xF2, 0x0F, 0xC2, 0x3F, 0x80, 0xFF, 0x00, 0xFC, 0x03, 0xB1, ++0x17, 0xC2, 0x3F, 0x00, 0xF3, 0x01, 0xFC, 0x06, 0xF0, 0x0B, 0xC0, 0x7F, 0x00, ++0xFF, 0x00, 0xCC, 0x02, 0xD0, 0x8F, 0xC0, 0x3F, 0x00, 0x31, 0x00, 0xCC, 0x62, ++0x30, 0x03, 0xC0, 0x03, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, ++0x56, 0x00, 0xDD, 0x00, 0x34, 0x0E, 0xD0, 0x0D, 0x40, 0x37, 0x80, 0xDD, 0x00, ++0x74, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0xA0, 0xDF, 0x20, 0x74, 0x03, 0x31, 0x9D, ++0xC0, 0x31, 0x00, 0x91, 0x0A, 0x74, 0x0F, 0x78, 0x11, 0x40, 0x87, 0x01, 0xDD, ++0x00, 0x6C, 0x44, 0x70, 0x01, 0x41, 0x37, 0x00, 0x13, 0x0F, 0x14, 0x44, 0x10, ++0x39, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0xA6, ++0x02, 0xDD, 0x00, 0x74, 0x0C, 0x90, 0x0D, 0x40, 0x37, 0x00, 0xDD, 0x80, 0x74, ++0x03, 0xD2, 0x0D, 0x48, 0x37, 0x00, 0xDD, 0x00, 0x74, 0x03, 0x90, 0x05, 0x40, ++0x37, 0x00, 0x55, 0x82, 0x74, 0x12, 0xD0, 0x19, 0x40, 0x17, 0x02, 0xD9, 0x00, ++0x44, 0x04, 0xD0, 0x09, 0x42, 0x33, 0x00, 0x95, 0x00, 0x44, 0x03, 0x10, 0x19, ++0x41, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, ++0xCD, 0x00, 0x74, 0x00, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x36, 0x03, ++0xD0, 0x0C, 0x40, 0x33, 0x20, 0xC5, 0x00, 0x34, 0x03, 0x10, 0x88, 0x48, 0x35, ++0x00, 0x45, 0x00, 0x34, 0x00, 0x58, 0x08, 0x60, 0x03, 0x00, 0xDD, 0x00, 0x25, ++0x00, 0x50, 0x00, 0x48, 0x33, 0x40, 0x45, 0x00, 0x44, 0x00, 0x11, 0x08, 0x40, ++0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x26, 0x00, 0xFF, ++0x00, 0x7C, 0x00, 0x10, 0x0F, 0xC0, 0x3D, 0x00, 0xDD, 0x00, 0xF4, 0x03, 0xF0, ++0x0D, 0xC0, 0x3F, 0x00, 0xDD, 0x00, 0x7E, 0x03, 0xB0, 0x05, 0x48, 0x3B, 0x00, ++0xD5, 0x00, 0x7C, 0x02, 0xD0, 0x09, 0xC0, 0x07, 0x00, 0xFF, 0x08, 0x4C, 0x00, ++0xF0, 0x01, 0xC0, 0x3F, 0x00, 0x17, 0x00, 0x4D, 0x00, 0x30, 0x09, 0xC0, 0x03, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x1F, 0x00, 0xFF, 0x00, ++0xFC, 0x02, 0x70, 0x0F, 0xC0, 0x3F, 0x00, 0xEF, 0x80, 0xFC, 0x03, 0xF0, 0x0F, ++0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0x71, 0x43, 0xC0, 0x3D, 0x00, 0x3B, ++0x00, 0xFC, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0xDC, 0x00, 0x78, ++0x03, 0xC0, 0x3F, 0x00, 0x33, 0x00, 0xFF, 0x80, 0xF0, 0x0B, 0xC2, 0x17, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x0F, 0x04, 0x33, 0x01, 0xC4, ++0x02, 0xB8, 0x0B, 0xC0, 0xBF, 0x01, 0xFB, 0x2C, 0xEC, 0x8E, 0x70, 0x2F, 0xC0, ++0x4F, 0x00, 0xF7, 0x18, 0x8C, 0x24, 0xF0, 0x4F, 0xC1, 0x4F, 0x02, 0xFF, 0x44, ++0xDC, 0x27, 0x30, 0x8F, 0xC0, 0x3F, 0x00, 0xE7, 0x00, 0xEC, 0x04, 0xF0, 0x0F, ++0xC0, 0x6C, 0x00, 0xFB, 0x10, 0x9C, 0x52, 0xF0, 0x13, 0xC0, 0x0C, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x87, 0x00, 0x11, 0x00, 0x6C, 0x02, ++0xF0, 0x09, 0x40, 0xBF, 0x00, 0xF1, 0x02, 0x4C, 0x13, 0x10, 0x8F, 0x40, 0x67, ++0x08, 0xF1, 0x02, 0x44, 0x10, 0xD2, 0x3F, 0xC2, 0x23, 0x08, 0xF1, 0x03, 0x44, ++0x13, 0x04, 0x6F, 0x40, 0xFC, 0x20, 0xF1, 0x0B, 0x44, 0x04, 0xD1, 0x3F, 0xC0, ++0x44, 0x00, 0xD5, 0x43, 0x74, 0x04, 0xD0, 0x15, 0xC0, 0x06, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x03, 0x00, 0x01, 0x00, 0x15, 0x00, 0x92, ++0x08, 0x42, 0x33, 0x03, 0xC9, 0x0C, 0x34, 0x03, 0x50, 0x4C, 0x44, 0x07, 0x80, ++0xC5, 0x20, 0x04, 0x12, 0xD0, 0x0C, 0x42, 0x13, 0x10, 0xC9, 0x02, 0x14, 0x03, ++0x10, 0x2C, 0x40, 0xB1, 0x00, 0xC5, 0x00, 0x07, 0x00, 0x50, 0x2C, 0x40, 0x26, ++0x00, 0xC1, 0x20, 0x34, 0x02, 0xD0, 0x05, 0x40, 0x44, 0x80, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA8, 0x41, 0x04, 0x01, 0x01, 0x54, 0x0E, 0x50, 0x19, ++0x40, 0x37, 0x00, 0xD1, 0x00, 0x44, 0x03, 0x10, 0x0D, 0x40, 0x47, 0x00, 0xD1, ++0x00, 0x44, 0x0C, 0xD0, 0x0D, 0x40, 0x25, 0x04, 0xD5, 0x00, 0x44, 0x03, 0x18, ++0x0D, 0x08, 0x34, 0x00, 0xD1, 0x00, 0x64, 0x04, 0xD0, 0x0D, 0x40, 0x64, 0x00, ++0xD5, 0x00, 0x74, 0x06, 0xD0, 0x35, 0x40, 0x0E, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xA8, 0xC7, 0x00, 0x13, 0x03, 0x54, 0x0C, 0x90, 0x51, 0xC0, ++0x37, 0x00, 0xDB, 0x00, 0x7C, 0x03, 0x70, 0x0D, 0xC4, 0x43, 0x00, 0xD7, 0x00, ++0x4C, 0x0E, 0xF0, 0x0D, 0x48, 0x97, 0x02, 0xDF, 0x00, 0x5C, 0x03, 0x32, 0x0D, ++0xC0, 0x37, 0x10, 0xD7, 0x00, 0x6E, 0x44, 0xF0, 0x0D, 0xD0, 0x62, 0x00, 0xDB, ++0x00, 0x5C, 0x16, 0xF2, 0x1D, 0xE0, 0x08, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0x80, 0x05, 0x00, 0x3F, 0x00, 0x6D, 0x80, 0xF0, 0x03, 0xC0, 0x3F, ++0x00, 0xEF, 0x00, 0xEC, 0x03, 0xF8, 0x0D, 0xC0, 0x2F, 0x80, 0xEB, 0x40, 0xFC, ++0x00, 0xF2, 0x0F, 0xC0, 0x4F, 0x00, 0xEB, 0x00, 0xFC, 0x03, 0xF0, 0x0E, 0xC0, ++0x3B, 0x04, 0xFD, 0x80, 0xDC, 0x40, 0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xFF, 0x00, ++0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x08, 0x85, 0x00, 0x1B, 0x00, 0x4D, 0x08, 0x30, 0x09, 0xC3, 0x33, 0x00, ++0xDF, 0x00, 0x5C, 0x03, 0x70, 0x0D, 0xC0, 0x85, 0x00, 0xDF, 0x00, 0x4C, 0x0A, ++0x30, 0x0D, 0xC6, 0x16, 0x00, 0xD3, 0x10, 0x5C, 0x03, 0xF0, 0x0D, 0xC0, 0x36, ++0x00, 0xDF, 0x20, 0x4C, 0x08, 0x70, 0x0C, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7E, ++0x42, 0x70, 0x2D, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0xA0, 0x04, 0x00, 0x11, 0x01, 0x44, 0x4E, 0x00, 0x69, 0x40, 0x3F, 0x10, 0xFD, ++0x00, 0x4C, 0x03, 0x10, 0x0F, 0x40, 0xA4, 0x03, 0xFD, 0x00, 0x44, 0x00, 0x12, ++0x0F, 0x40, 0x24, 0x00, 0xF0, 0x03, 0x54, 0x03, 0xD0, 0x0F, 0x40, 0x7C, 0x04, ++0xED, 0x00, 0x45, 0x04, 0xD0, 0x1F, 0x40, 0x47, 0x00, 0xFD, 0x00, 0x74, 0x0E, ++0x10, 0x0D, 0x43, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, ++0x42, 0x00, 0x09, 0x24, 0x00, 0x46, 0x90, 0x00, 0x40, 0x33, 0x20, 0xC9, 0x00, ++0x52, 0x02, 0xD0, 0x0C, 0x48, 0xA1, 0x00, 0xCC, 0x00, 0x14, 0x00, 0x10, 0x0C, ++0x48, 0x27, 0x60, 0xC1, 0x01, 0x44, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, ++0x04, 0x24, 0x04, 0xD0, 0x8C, 0x49, 0x23, 0x12, 0xCD, 0x00, 0x16, 0x04, 0x51, ++0x0D, 0x41, 0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x48, ++0x24, 0x21, 0x01, 0x84, 0x07, 0x18, 0x1E, 0x40, 0x7B, 0x00, 0xCD, 0x01, 0x94, ++0x07, 0x90, 0x9E, 0x40, 0x78, 0xA0, 0xED, 0x01, 0xD4, 0x04, 0x14, 0x1E, 0x40, ++0x69, 0x00, 0xE1, 0x11, 0x94, 0x07, 0xC0, 0x1C, 0x40, 0x79, 0x00, 0xED, 0x95, ++0x84, 0x05, 0xD2, 0x1E, 0x40, 0x4B, 0x00, 0xED, 0x09, 0xB6, 0x44, 0x10, 0x1F, ++0x40, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x00, 0x00, ++0x1B, 0x10, 0x0D, 0x21, 0xB0, 0x04, 0xC0, 0x33, 0x00, 0xCF, 0x00, 0x5C, 0x03, ++0xF0, 0x0C, 0xC8, 0x81, 0x00, 0xDE, 0x00, 0x1C, 0x03, 0x30, 0x0C, 0xC0, 0x33, ++0x03, 0xC3, 0x80, 0x1C, 0x83, 0xF0, 0x4C, 0xC0, 0x33, 0x00, 0xCF, 0x00, 0x0C, ++0x40, 0x70, 0x0C, 0xE4, 0x23, 0x22, 0xCF, 0x00, 0x1E, 0x14, 0x70, 0x0C, 0xC0, ++0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x2D, 0x12, 0x7F, ++0x08, 0xFC, 0x03, 0x54, 0x0F, 0xC0, 0x3F, 0x80, 0xFF, 0x02, 0xEC, 0x03, 0x70, ++0x0F, 0xC3, 0x1F, 0x00, 0xFF, 0x08, 0xEC, 0x03, 0xF0, 0x2E, 0xC4, 0x3E, 0x02, ++0xEF, 0x10, 0xF8, 0x23, 0xF0, 0x0F, 0xC1, 0x3E, 0x00, 0xFF, 0x06, 0xDC, 0x01, ++0xF0, 0x0F, 0xC0, 0x2F, 0x08, 0xFF, 0x20, 0xFE, 0x20, 0xF2, 0x0C, 0xC0, 0x0B, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x07, 0x00, 0x03, 0x00, ++0x4C, 0x03, 0xF0, 0x05, 0xC0, 0xB7, 0x01, 0xDB, 0x0E, 0x7C, 0x03, 0xF0, 0x5D, ++0xC1, 0x24, 0x00, 0xDF, 0x86, 0x7C, 0x86, 0x70, 0x3D, 0xC0, 0x16, 0x00, 0xDF, ++0x10, 0x7C, 0x03, 0xF0, 0x4D, 0xC1, 0x36, 0x01, 0xDF, 0x01, 0x4C, 0x00, 0xF0, ++0xAC, 0xC0, 0x24, 0x00, 0xDF, 0x01, 0x4C, 0x06, 0x30, 0x0D, 0xC0, 0x54, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x09, 0x08, 0x21, 0x00, 0x84, ++0x03, 0xD0, 0x0E, 0x40, 0xBB, 0x0D, 0xE1, 0x00, 0x9C, 0x03, 0xD0, 0x4E, 0x50, ++0x38, 0x80, 0xED, 0x12, 0xB4, 0x02, 0x10, 0x0E, 0x40, 0x18, 0x00, 0xED, 0x04, ++0xB0, 0x83, 0xD0, 0x4E, 0x42, 0xB8, 0x82, 0xCD, 0x04, 0xA5, 0x01, 0xD0, 0x4E, ++0x49, 0x29, 0x00, 0xED, 0x00, 0x94, 0x00, 0x11, 0x0E, 0xC0, 0x4A, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x49, 0x04, 0x21, 0x01, 0x84, 0x0D, ++0xD0, 0x16, 0x41, 0x73, 0x01, 0xE9, 0x05, 0x94, 0x07, 0xD0, 0x5E, 0x40, 0x68, ++0x00, 0xED, 0x05, 0xB4, 0x07, 0x50, 0x9C, 0x50, 0x79, 0x80, 0xED, 0x01, 0xB4, ++0x87, 0x58, 0x1E, 0x40, 0x78, 0x00, 0xED, 0x08, 0xA4, 0x04, 0x50, 0x1E, 0x40, ++0x78, 0x00, 0xCD, 0x01, 0x04, 0x06, 0x10, 0x1F, 0x40, 0x0C, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x77, 0x20, 0xD1, 0x04, 0x04, 0x07, 0xD0, ++0x3C, 0x41, 0x33, 0x00, 0xC1, 0x40, 0x14, 0xA7, 0xD8, 0x0C, 0x40, 0xB0, 0x00, ++0xCD, 0x00, 0x34, 0x0B, 0x10, 0x0C, 0x40, 0x71, 0x83, 0xCD, 0x00, 0x34, 0x03, ++0xD9, 0x0D, 0x50, 0x30, 0x00, 0xDD, 0x00, 0x24, 0x4B, 0xD1, 0x0C, 0x48, 0x11, ++0x14, 0xCD, 0x00, 0x16, 0x27, 0x10, 0x0C, 0x40, 0x4A, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x17, 0xA8, 0x5D, 0x40, 0x73, 0x00, 0xCD, 0x0D, 0xF0, 0x07, ++0xC0, 0x17, 0x00, 0x5B, 0x00, 0x5C, 0x01, 0xF0, 0x05, 0xC0, 0x18, 0x02, 0x5F, ++0x00, 0xFC, 0x01, 0x70, 0x05, 0xC0, 0x5D, 0x18, 0x5F, 0x00, 0x7C, 0x01, 0xF0, ++0x05, 0xC0, 0x14, 0x00, 0x5D, 0x80, 0xC5, 0x01, 0xF8, 0x05, 0xC0, 0x5C, 0x00, ++0x5F, 0x00, 0xCC, 0x01, 0x30, 0x67, 0xC0, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x00, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x10, 0xF0, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x00, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0xF0, 0x01, 0x40, 0x04, 0x20, 0x1F, 0x82, 0x7C, 0x00, 0xF0, 0x01, ++0xC0, 0x01, 0x00, 0x1F, 0x02, 0x5C, 0x80, 0xF0, 0x21, 0xC0, 0x07, 0x02, 0x1F, ++0x00, 0x7C, 0x8C, 0xF0, 0x01, 0xC1, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x67, 0x02, 0x93, 0x00, 0x4C, 0x0E, 0xF0, 0x39, 0xC0, 0x27, ++0x00, 0x97, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x02, 0x93, 0x00, 0x7C, ++0x42, 0xF0, 0x29, 0xC0, 0x27, 0x00, 0x9F, 0x02, 0x7C, 0x02, 0xB2, 0x09, 0xC2, ++0xE5, 0x00, 0x97, 0x05, 0x4C, 0x02, 0xF0, 0x08, 0xD0, 0x24, 0x00, 0x9F, 0x00, ++0x5E, 0x02, 0xF0, 0x29, 0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x20, 0xE6, 0x60, 0x91, 0x03, 0x44, 0x06, 0xD0, 0x19, 0x40, 0x27, 0x00, ++0x91, 0x00, 0x5C, 0x02, 0xD0, 0x09, 0x46, 0x27, 0x00, 0x95, 0x00, 0x74, 0x02, ++0xD0, 0x19, 0x40, 0x27, 0x00, 0x9D, 0x03, 0x74, 0x02, 0x10, 0x09, 0x48, 0xE4, ++0x04, 0x91, 0x00, 0x44, 0x26, 0xD1, 0x49, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, ++0x4E, 0xD2, 0x18, 0xC0, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA0, 0x24, 0x04, 0xD1, 0x08, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x23, 0x00, 0x95, ++0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x04, 0x99, 0x00, 0x74, 0x02, 0xD0, ++0x09, 0x40, 0x27, 0x00, 0x95, 0x02, 0x34, 0x02, 0x90, 0x09, 0x60, 0x25, 0x00, ++0x95, 0x40, 0x46, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x01, 0x9D, 0x00, 0x54, 0x22, ++0xD0, 0x09, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x20, 0x01, 0x81, 0x00, 0x04, 0x13, 0xD0, 0xC8, 0x40, 0x23, 0x11, 0x81, 0x0C, ++0x14, 0x22, 0xD0, 0x48, 0x40, 0x23, 0x00, 0x85, 0x04, 0x34, 0x22, 0xD0, 0x48, ++0x60, 0x23, 0x02, 0x8D, 0x00, 0x34, 0x22, 0x10, 0x88, 0x40, 0x20, 0x08, 0x91, ++0x00, 0x04, 0x06, 0xD0, 0x08, 0x40, 0x20, 0x00, 0x8D, 0x04, 0x34, 0x12, 0xD0, ++0x08, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x82, ++0x02, 0x53, 0x0A, 0x4D, 0x30, 0xF0, 0x45, 0xC1, 0x87, 0x02, 0x17, 0x02, 0x7C, ++0x08, 0xF0, 0xA0, 0xC0, 0x07, 0x08, 0x13, 0x0A, 0x3C, 0x08, 0xF0, 0x01, 0xC0, ++0x87, 0x00, 0x17, 0x14, 0x7C, 0x08, 0xB0, 0x60, 0xC1, 0x05, 0x85, 0x56, 0x14, ++0x44, 0x00, 0xF0, 0x41, 0xD1, 0x04, 0x00, 0x1F, 0x14, 0x5C, 0x00, 0xF0, 0x01, ++0xD0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x90, 0x2F, 0x22, ++0xBF, 0x00, 0xFC, 0x33, 0xF0, 0x4B, 0xC0, 0x27, 0x02, 0x9F, 0x0C, 0xDC, 0x12, ++0xF0, 0x89, 0xC0, 0x2F, 0x30, 0x9F, 0x08, 0xFC, 0x12, 0xF0, 0x89, 0xC8, 0x2F, ++0x01, 0x9F, 0x40, 0x7C, 0x12, 0xF0, 0x49, 0xC2, 0x27, 0x08, 0x9F, 0x00, 0xFC, ++0x02, 0xD0, 0x09, 0xC0, 0x2F, 0x08, 0x9F, 0x00, 0xFC, 0x22, 0xF0, 0x0A, 0xC0, ++0x65, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, 0x01, 0xBF, ++0x00, 0xCC, 0x32, 0xE0, 0x0B, 0xC8, 0x24, 0x00, 0x9F, 0x08, 0x6C, 0x02, 0xE0, ++0x49, 0xC1, 0x2E, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x0B, 0xD8, 0x24, 0x20, ++0xBF, 0x34, 0x7C, 0x22, 0xF0, 0x09, 0xE0, 0x2D, 0x00, 0xB3, 0x00, 0xEC, 0x02, ++0xF0, 0x4B, 0xC1, 0x2C, 0x20, 0x9F, 0x55, 0xF8, 0x02, 0xF0, 0x0A, 0xC0, 0x60, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x05, 0x1D, 0x04, ++0x44, 0xB0, 0xD0, 0x25, 0x41, 0x04, 0x04, 0x1D, 0x08, 0x44, 0x50, 0xD2, 0x41, ++0x44, 0x04, 0x00, 0x17, 0x12, 0x74, 0x40, 0x14, 0x81, 0x68, 0x04, 0x05, 0x1D, ++0x00, 0x74, 0x10, 0x71, 0x21, 0x41, 0x04, 0x00, 0x15, 0x08, 0x44, 0x00, 0xD0, ++0x01, 0x40, 0x05, 0x20, 0x1D, 0x00, 0x74, 0x00, 0xD0, 0x01, 0xC0, 0x72, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x03, 0x8D, 0x15, 0x04, ++0x92, 0xD0, 0xC8, 0x40, 0x20, 0x02, 0x8D, 0x00, 0x24, 0x12, 0xD0, 0x48, 0x41, ++0x22, 0x20, 0x8D, 0x0C, 0x36, 0x02, 0x10, 0x08, 0x40, 0x22, 0x21, 0x8D, 0x00, ++0x30, 0x12, 0xD1, 0xC8, 0x40, 0x31, 0x02, 0x81, 0x00, 0x14, 0x02, 0xD0, 0x08, ++0x40, 0x22, 0x00, 0x8D, 0x80, 0x34, 0x02, 0xD0, 0x09, 0x40, 0x40, 0x88, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x65, 0x00, 0x8D, 0x00, 0x44, 0x02, ++0xD0, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x44, 0x22, 0xD0, 0x09, 0x40, 0x24, ++0x00, 0x95, 0x00, 0x74, 0x42, 0x10, 0x09, 0x40, 0x26, 0x06, 0x9D, 0x00, 0x74, ++0x02, 0x50, 0x08, 0x48, 0x34, 0x08, 0x95, 0x20, 0x46, 0x43, 0xD0, 0x09, 0x40, ++0x67, 0x00, 0x9D, 0x00, 0x76, 0x0E, 0xD0, 0x49, 0x40, 0x62, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x88, 0xE7, 0x04, 0x9F, 0x01, 0x4D, 0x02, 0xF0, ++0x39, 0xE0, 0x24, 0x00, 0x9D, 0x00, 0x6C, 0x02, 0xF0, 0x09, 0xC0, 0x26, 0x04, ++0x9F, 0x00, 0x7C, 0x0A, 0x30, 0x09, 0x40, 0x66, 0x00, 0x9F, 0x20, 0x7C, 0x02, ++0xD0, 0x09, 0x40, 0x25, 0x00, 0x93, 0x00, 0x5D, 0x8A, 0xF0, 0x09, 0xC0, 0xE6, ++0x04, 0x9F, 0x00, 0x7C, 0x0E, 0xF0, 0x08, 0x40, 0x14, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x80, 0x25, 0x00, 0x9F, 0x04, 0x7C, 0x66, 0xF3, 0x88, ++0xD1, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC8, 0x27, 0x00, 0x9F, ++0x00, 0x7C, 0x26, 0xF0, 0x09, 0xC0, 0x25, 0x00, 0x9F, 0x20, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x27, 0x00, 0x8F, 0x00, 0x5C, 0x02, 0xF0, 0x08, 0xC1, 0x25, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC1, 0x53, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x08, 0x85, 0x02, 0x1F, 0x00, 0x4D, 0x08, 0xF8, 0x21, 0xC0, ++0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x00, 0xC4, 0x07, 0x00, 0x1F, 0x00, ++0x7C, 0x08, 0xF0, 0x00, 0xC0, 0x84, 0x00, 0x1F, 0x01, 0x4C, 0x00, 0xF0, 0x01, ++0xC0, 0x02, 0x00, 0x13, 0x00, 0x7C, 0x40, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x1F, ++0x00, 0x7C, 0x40, 0x32, 0x01, 0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0xA0, 0x1C, 0x02, 0x7D, 0x02, 0xC4, 0x01, 0xD0, 0x37, 0xC0, 0x15, ++0x00, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x48, 0x5F, 0x00, 0x5F, 0x00, 0x74, ++0x01, 0xD0, 0x15, 0x01, 0x14, 0x00, 0x7D, 0x05, 0x45, 0x01, 0xF0, 0x05, 0xC0, ++0x1D, 0x00, 0x7F, 0x20, 0xF4, 0x4D, 0xD0, 0x07, 0x40, 0x54, 0x20, 0x5D, 0x00, ++0xF4, 0x01, 0x34, 0x07, 0xD0, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0xA0, 0x72, 0x80, 0x8D, 0x10, 0x04, 0x03, 0xD0, 0xBC, 0x40, 0x31, 0x00, ++0xDD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x06, 0xCD, 0x00, 0x74, 0x03, ++0xD0, 0x18, 0x60, 0x30, 0x00, 0xCD, 0x00, 0x04, 0x03, 0x90, 0x0C, 0x40, 0xB0, ++0x01, 0xC1, 0x12, 0x34, 0x0B, 0xD0, 0x34, 0x50, 0x70, 0x00, 0xCD, 0x00, 0x34, ++0x03, 0x90, 0x0C, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0x80, 0x28, 0x01, 0x7D, 0x08, 0x84, 0x43, 0xD0, 0x0E, 0x40, 0x39, 0x00, 0xED, ++0x0C, 0xB4, 0x13, 0xDA, 0xCE, 0x40, 0x1B, 0x00, 0xED, 0x08, 0xB4, 0x13, 0xD1, ++0x0B, 0x40, 0x38, 0x21, 0x0D, 0x01, 0x86, 0x23, 0xD2, 0x4C, 0x40, 0x21, 0x00, ++0x65, 0x10, 0xB0, 0x01, 0xD0, 0x0E, 0x41, 0x38, 0x04, 0xED, 0x00, 0xF4, 0x47, ++0x10, 0x0F, 0x40, 0x16, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, ++0xF8, 0x00, 0xAF, 0x05, 0x8C, 0x07, 0xD0, 0x16, 0xC0, 0x79, 0x00, 0xEF, 0x05, ++0xBC, 0x0F, 0xF0, 0x1E, 0xC4, 0x7B, 0x20, 0xED, 0x11, 0xB4, 0x87, 0xD0, 0x0F, ++0xC0, 0x78, 0x01, 0x2F, 0x21, 0x8C, 0x57, 0xF0, 0xBE, 0xC4, 0x68, 0x00, 0xE1, ++0x01, 0xB0, 0x05, 0xF0, 0x1C, 0xC4, 0x78, 0x00, 0xEF, 0x01, 0xF8, 0x05, 0xB0, ++0x1E, 0xD0, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, ++0x00, 0x8F, 0x40, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0xB5, 0x00, 0xDF, 0x00, 0x7C, ++0x03, 0xF1, 0x4D, 0xC1, 0x37, 0x00, 0xD6, 0x44, 0x7C, 0xAB, 0xF0, 0x0D, 0xCC, ++0xB7, 0x06, 0x1F, 0x00, 0x6C, 0x03, 0x60, 0x6D, 0xC0, 0x25, 0x00, 0x5F, 0x00, ++0x7C, 0x00, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x80, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x41, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x4F, 0x00, ++0x23, 0x41, 0xDD, 0x27, 0xF8, 0x8F, 0xC0, 0xFF, 0x04, 0xFB, 0x01, 0xDC, 0x07, ++0xF0, 0x9F, 0xC0, 0x6C, 0x02, 0xFF, 0x01, 0xEC, 0x2F, 0xF2, 0x9B, 0xC2, 0x7F, ++0x42, 0x33, 0x01, 0xCC, 0x07, 0xF0, 0x1F, 0xC0, 0x48, 0x00, 0xB3, 0x89, 0xAE, ++0x25, 0x30, 0x1F, 0xC2, 0x7F, 0x02, 0xFF, 0x01, 0xFC, 0x06, 0xF0, 0x1E, 0xC0, ++0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x09, 0x00, 0x61, ++0x08, 0x85, 0x01, 0xD8, 0x0E, 0x41, 0x3F, 0x00, 0xF1, 0x00, 0x84, 0x03, 0xD2, ++0x0F, 0x54, 0x88, 0x20, 0xE7, 0x00, 0x85, 0x23, 0xD0, 0xCA, 0x40, 0x3B, 0x02, ++0x21, 0x08, 0xAC, 0x03, 0x70, 0x0F, 0x48, 0x28, 0x00, 0xEB, 0x00, 0x8C, 0x01, ++0xB0, 0x4A, 0x40, 0x3B, 0x02, 0xED, 0x00, 0x34, 0x1B, 0xD0, 0x0E, 0x50, 0x54, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x04, 0x21, 0x02, ++0x94, 0xC3, 0xD0, 0x86, 0x40, 0x3B, 0x00, 0xE9, 0x00, 0x94, 0x23, 0xD0, 0x0E, ++0x42, 0x38, 0x90, 0xED, 0x00, 0x84, 0x03, 0xD2, 0x0A, 0x00, 0x3F, 0x04, 0x01, ++0x00, 0x84, 0x23, 0xD0, 0x0E, 0x40, 0x09, 0x00, 0xA1, 0x40, 0x97, 0x01, 0x12, ++0x0E, 0x48, 0x2B, 0x10, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x00, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0xA7, 0x01, 0x01, 0x81, 0x44, ++0x0E, 0xD0, 0x31, 0x40, 0x33, 0x00, 0xC1, 0x00, 0x04, 0x03, 0xD8, 0x0C, 0x40, ++0xB0, 0x08, 0xC5, 0x00, 0x04, 0x13, 0xD0, 0x08, 0x60, 0x33, 0x00, 0x01, 0x00, ++0x24, 0x03, 0x58, 0x0C, 0x50, 0x21, 0x00, 0xC9, 0x00, 0x04, 0x40, 0x12, 0x08, ++0x40, 0x23, 0x01, 0xCD, 0x00, 0x74, 0x9E, 0xD1, 0x8C, 0x40, 0x10, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0xFD, 0x40, 0x33, 0x01, 0x5C, 0x04, ++0xD0, 0x19, 0xC0, 0x3F, 0x00, 0xFB, 0x00, 0xD4, 0x03, 0xF0, 0x0F, 0xC0, 0x74, ++0x00, 0xFE, 0x00, 0xCC, 0x03, 0xF0, 0x09, 0xC0, 0xBB, 0x80, 0x13, 0x00, 0xCC, ++0x03, 0xF0, 0x0F, 0x40, 0x25, 0x00, 0xD3, 0x00, 0x5C, 0x05, 0x10, 0x05, 0xC8, ++0x37, 0x00, 0xDF, 0x00, 0x7C, 0x4B, 0xF0, 0x0D, 0xC0, 0x54, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x08, 0x5F, 0x0A, 0x7C, 0x40, 0xF0, ++0x29, 0xC1, 0x37, 0x00, 0xDF, 0x80, 0x7C, 0x23, 0xF3, 0x0D, 0xC4, 0xC7, 0x00, ++0xC4, 0x80, 0x5C, 0x03, 0xF0, 0x09, 0xC0, 0x37, 0x01, 0x1F, 0x00, 0x7C, 0x03, ++0x70, 0x0C, 0xC0, 0x26, 0x00, 0x5F, 0x02, 0x50, 0x05, 0xF0, 0x0D, 0xC0, 0x27, ++0x00, 0xDE, 0x40, 0x7C, 0x03, 0xF0, 0x2D, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x02, 0x33, 0x20, 0xCC, 0x00, 0x30, 0x0B, ++0xC0, 0x3C, 0x00, 0xFE, 0x00, 0xFE, 0x03, 0xB2, 0x0F, 0xC2, 0x7F, 0x05, 0xFF, ++0x00, 0xCD, 0x83, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0x33, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC2, 0x0E, 0x00, 0x0F, 0x01, 0xCD, 0x01, 0x30, 0x4F, 0xC0, 0x7C, 0x01, ++0xEF, 0x00, 0xCC, 0x07, 0x30, 0x1B, 0xC0, 0x00, 0x22, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x81, 0x20, 0x76, 0x20, 0x05, 0x04, 0x44, 0x04, 0x10, 0x39, 0x41, ++0x34, 0x00, 0xDD, 0x00, 0x34, 0x03, 0x70, 0x0D, 0x40, 0xA7, 0x80, 0xDD, 0x00, ++0x44, 0x03, 0xD0, 0x0D, 0xC0, 0x35, 0x00, 0x11, 0x03, 0x74, 0x03, 0x72, 0x0D, ++0x48, 0x45, 0x00, 0x1D, 0x05, 0x04, 0x08, 0x52, 0x0C, 0x40, 0x24, 0x00, 0xDD, ++0x00, 0x44, 0x09, 0x10, 0x9C, 0x40, 0x04, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0xA0, 0x14, 0x50, 0x11, 0x00, 0x44, 0x06, 0x10, 0x11, 0x60, 0x36, ++0x10, 0xDD, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x4A, 0x07, 0x80, 0xDD, 0x00, 0x44, ++0x03, 0xD0, 0x09, 0x68, 0x37, 0x00, 0x11, 0x03, 0x74, 0x03, 0xD0, 0x0D, 0x40, ++0x44, 0x00, 0x9D, 0x08, 0x44, 0x20, 0x10, 0x0D, 0x40, 0x35, 0x00, 0xDD, 0x00, ++0x54, 0x13, 0x50, 0x05, 0x41, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x22, 0x00, 0x00, 0x51, 0x00, 0x05, 0x04, 0x14, 0x08, 0x50, 0x32, 0x00, ++0xCD, 0x00, 0x74, 0x03, 0x50, 0x0C, 0x40, 0x03, 0x00, 0xCD, 0x80, 0x04, 0x03, ++0xD0, 0x08, 0x40, 0x34, 0x20, 0x01, 0x00, 0x34, 0x03, 0x52, 0x0C, 0x40, 0x21, ++0x10, 0xCD, 0x00, 0x44, 0x00, 0x50, 0x0C, 0x44, 0x20, 0x00, 0xCD, 0x00, 0x45, ++0x0B, 0x14, 0x0D, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xB0, 0x32, 0x00, 0x11, 0x00, 0x4D, 0x02, 0x30, 0x01, 0xC2, 0x3E, 0x10, 0xDF, ++0x00, 0x74, 0x03, 0x30, 0x0F, 0xC0, 0x17, 0x10, 0xED, 0x00, 0xCC, 0x03, 0xF0, ++0x09, 0x88, 0x3F, 0x40, 0x13, 0x40, 0xFC, 0x03, 0xF0, 0x0F, 0xE0, 0x04, 0x20, ++0x1F, 0x00, 0x4E, 0x00, 0x30, 0x0D, 0xC0, 0x24, 0x00, 0xDF, 0x00, 0x4C, 0x0B, ++0x30, 0x01, 0xC0, 0x00, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, ++0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x02, 0xF1, 0x0B, 0xCA, 0x3D, 0x00, 0xFF, 0x20, ++0xFC, 0x03, 0x70, 0x0F, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, ++0xC0, 0x39, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0x40, 0x0F, 0xC0, 0x0D, 0x00, 0x3F, ++0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC8, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x13, 0xF0, ++0x0F, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x3F, ++0x00, 0xFB, 0x1C, 0xEC, 0x05, 0x30, 0x0B, 0xC0, 0x5F, 0x00, 0xBF, 0x00, 0xEC, ++0x03, 0xB0, 0x0F, 0xC1, 0x3F, 0x00, 0x3B, 0x81, 0xEC, 0x33, 0x70, 0x0F, 0xC0, ++0x4F, 0x00, 0x2F, 0x01, 0xFC, 0x84, 0xF0, 0x4F, 0x80, 0x7C, 0x00, 0x7B, 0x01, ++0xBC, 0x04, 0xF0, 0x13, 0xC2, 0x4E, 0x00, 0xFF, 0x01, 0xFE, 0x00, 0xF0, 0x03, ++0x44, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0xFF, 0x02, ++0xF1, 0x02, 0x44, 0x06, 0x14, 0x19, 0x40, 0x26, 0x00, 0x8D, 0x70, 0x74, 0xAF, ++0x10, 0x1F, 0x40, 0xFF, 0x00, 0x9D, 0x01, 0x74, 0x3B, 0x10, 0xBF, 0x40, 0x77, ++0x00, 0xDD, 0x01, 0x74, 0x07, 0xD0, 0xBF, 0x40, 0x38, 0x05, 0x91, 0x01, 0x74, ++0x04, 0xD0, 0x11, 0x40, 0x47, 0x00, 0xDD, 0x00, 0x76, 0x86, 0xD2, 0x19, 0x40, ++0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x20, 0xC8, ++0x04, 0x64, 0x01, 0x50, 0x08, 0x40, 0x21, 0x00, 0x8D, 0x04, 0x06, 0x03, 0x90, ++0x0C, 0x42, 0xB3, 0x00, 0x81, 0x00, 0x34, 0x13, 0x50, 0x0C, 0x60, 0x33, 0x20, ++0xCD, 0x80, 0x34, 0x02, 0x52, 0x0C, 0x60, 0x30, 0x40, 0x85, 0x40, 0x16, 0x00, ++0xD0, 0x00, 0x42, 0x03, 0x00, 0xC5, 0x80, 0x34, 0x00, 0xD2, 0x00, 0x42, 0x47, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, 0xD1, 0x00, ++0x44, 0x02, 0x50, 0x19, 0x40, 0x26, 0x00, 0x9D, 0x23, 0x74, 0x03, 0x50, 0x0D, ++0x40, 0x37, 0x00, 0x9C, 0x01, 0x34, 0x03, 0x10, 0x0D, 0x00, 0x37, 0x00, 0xDD, ++0x06, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0x30, 0x10, 0x95, 0x00, 0x74, 0x0E, 0xD0, ++0x11, 0x40, 0x67, 0x00, 0xDD, 0x00, 0x74, 0x06, 0xC0, 0x19, 0x40, 0x0F, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x37, 0x00, 0xDB, 0x80, 0x2C, ++0x12, 0x71, 0x11, 0xC1, 0x17, 0x01, 0x1F, 0x03, 0x4C, 0x03, 0xB0, 0x0D, 0xC0, ++0x37, 0x00, 0x13, 0x03, 0x6C, 0x03, 0x72, 0x0D, 0xC8, 0x07, 0x01, 0x1E, 0x00, ++0x7C, 0x01, 0xF0, 0x0C, 0xC0, 0x34, 0x00, 0x55, 0x05, 0x7C, 0x04, 0xD0, 0x31, ++0xC0, 0x47, 0x01, 0xDF, 0xA0, 0x74, 0x04, 0xF0, 0x19, 0xC1, 0x03, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x39, 0x00, 0xEF, 0x00, 0xFC, 0x02, ++0xB0, 0x03, 0xC0, 0x2F, 0x00, 0xBF, 0x80, 0xBC, 0x03, 0xB0, 0x0F, 0xC0, 0x3F, ++0x00, 0x3F, 0x00, 0x7C, 0x03, 0xD0, 0x0F, 0xC0, 0x3F, 0x01, 0xFF, 0x41, 0xFC, ++0x03, 0xF0, 0x0F, 0xC1, 0x3F, 0x00, 0xB3, 0x09, 0xF8, 0x02, 0xF0, 0x03, 0xC0, ++0x0F, 0x00, 0xFF, 0x00, 0xF8, 0x40, 0xF0, 0x09, 0xC1, 0x1F, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xD7, 0x00, 0x7C, 0x03, 0xF0, ++0x29, 0xC0, 0x37, 0x00, 0x1F, 0x22, 0x6C, 0x03, 0x30, 0x8D, 0xC0, 0x37, 0x00, ++0x13, 0x46, 0x7C, 0x03, 0xB2, 0x0D, 0xC4, 0x34, 0x00, 0xDF, 0x02, 0x4C, 0x17, ++0xB0, 0x8D, 0xC2, 0x37, 0x10, 0x9F, 0x80, 0x7E, 0x08, 0xB4, 0x81, 0xC8, 0x27, ++0x11, 0xDF, 0x00, 0x5E, 0x00, 0xF0, 0x29, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0xA0, 0x3C, 0x00, 0xF1, 0x00, 0x44, 0x12, 0xD0, 0x09, ++0x40, 0x27, 0x22, 0x9D, 0xA0, 0xC4, 0x4B, 0x50, 0x1F, 0x40, 0x3F, 0x00, 0x1A, ++0x03, 0xF4, 0x03, 0x10, 0x0F, 0x40, 0x74, 0x01, 0xDD, 0x00, 0x44, 0x0B, 0x10, ++0x2F, 0x42, 0x37, 0x00, 0x91, 0x0B, 0x74, 0x02, 0x21, 0x01, 0x40, 0xA7, 0x01, ++0xDD, 0x00, 0x46, 0x1A, 0x90, 0x29, 0xC0, 0x4E, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x07, 0xA0, 0x32, 0x00, 0xC5, 0x00, 0x14, 0x13, 0xD0, 0x00, 0x40, ++0x32, 0x02, 0x0D, 0x00, 0x24, 0x1F, 0x10, 0x0C, 0x48, 0x33, 0x00, 0x04, 0x00, ++0x34, 0x03, 0x90, 0x0C, 0x40, 0x43, 0x01, 0x0D, 0xA0, 0x26, 0x88, 0x10, 0x2C, ++0x48, 0x33, 0x00, 0xC4, 0x08, 0x34, 0x00, 0x10, 0x50, 0x48, 0x42, 0x20, 0xC9, ++0x80, 0x24, 0x02, 0xD2, 0x20, 0x40, 0x1E, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x80, 0x70, 0x00, 0xC1, 0x01, 0x84, 0x06, 0xD0, 0x1E, 0x40, 0x6B, ++0x00, 0x6D, 0x01, 0x84, 0x07, 0x50, 0x1E, 0x40, 0x7B, 0x02, 0xAD, 0x29, 0xB4, ++0x07, 0x10, 0x1E, 0x40, 0x4B, 0x00, 0x2D, 0x41, 0xB4, 0x07, 0x10, 0x1E, 0x60, ++0x7B, 0x22, 0xE1, 0x41, 0xF4, 0x04, 0x90, 0x92, 0x40, 0x7B, 0x00, 0xED, 0x01, ++0x84, 0x06, 0x90, 0x12, 0x40, 0x1A, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x10, 0x30, 0x00, 0xC7, 0x08, 0x1C, 0x03, 0xD0, 0x04, 0xC0, 0x23, 0x00, ++0xCF, 0x00, 0x2E, 0x03, 0x30, 0x0C, 0xE8, 0x33, 0x02, 0x87, 0x12, 0x3C, 0x03, ++0xB0, 0x0C, 0xC1, 0x03, 0x20, 0x0D, 0x01, 0x2D, 0x16, 0x30, 0x8C, 0xC0, 0x33, ++0x00, 0x87, 0x08, 0x34, 0x06, 0x30, 0x50, 0xC2, 0x13, 0x00, 0xCF, 0x00, 0x3C, ++0x03, 0xF0, 0x84, 0xC0, 0x4A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xB8, 0x3D, 0x00, 0xFC, 0x22, 0xDC, 0x02, 0xF0, 0x0F, 0x80, 0x2F, 0x02, 0xFF, ++0x00, 0x9C, 0x63, 0xF0, 0xAF, 0xC0, 0x33, 0x4A, 0x93, 0x00, 0xFC, 0x03, 0xF0, ++0x0E, 0xC1, 0x0C, 0x92, 0x1F, 0x80, 0x0C, 0x23, 0x74, 0x0F, 0xC0, 0x77, 0x00, ++0xB7, 0x08, 0x7C, 0x02, 0x70, 0x87, 0xE0, 0x3F, 0x00, 0xEF, 0x00, 0xFD, 0x02, ++0xF0, 0x0F, 0xC2, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, ++0xB7, 0x03, 0xDF, 0x02, 0x7C, 0x02, 0x30, 0x05, 0xC0, 0x37, 0x00, 0x7F, 0x01, ++0x6C, 0x03, 0xF0, 0x0D, 0xC0, 0xB7, 0x86, 0x13, 0x01, 0x5C, 0x03, 0x71, 0x5D, ++0xC0, 0x40, 0x90, 0x13, 0x00, 0x7C, 0x01, 0x38, 0x0D, 0xC4, 0x37, 0x00, 0xD3, ++0x80, 0x7C, 0x02, 0xD0, 0x11, 0xC0, 0x24, 0x80, 0xCF, 0x00, 0x4C, 0x00, 0xF1, ++0x01, 0xC0, 0x57, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x39, ++0x03, 0xED, 0x02, 0xB4, 0x02, 0x10, 0x06, 0x40, 0x2B, 0x00, 0xFD, 0x00, 0x84, ++0x93, 0xD0, 0x2E, 0x42, 0x33, 0x21, 0xA1, 0x00, 0x84, 0x13, 0xD0, 0xCE, 0x68, ++0x39, 0x30, 0xE1, 0x00, 0xB4, 0x03, 0x10, 0xCE, 0x40, 0x3F, 0x19, 0xE1, 0x20, ++0xB4, 0x02, 0xD2, 0x02, 0x44, 0x38, 0x10, 0xED, 0x00, 0x84, 0x00, 0xD0, 0x02, ++0x40, 0x4B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x00, ++0xED, 0x01, 0x94, 0x07, 0x10, 0x1E, 0x41, 0x7B, 0x08, 0x6D, 0x00, 0xB4, 0x07, ++0xD0, 0x5E, 0x40, 0x7B, 0x01, 0xB1, 0x21, 0xB4, 0x27, 0x50, 0x1C, 0x50, 0x3A, ++0x00, 0xE1, 0x01, 0x94, 0x07, 0x91, 0x9E, 0x44, 0x3B, 0x03, 0xA1, 0x01, 0xB4, ++0x46, 0xD8, 0x13, 0x44, 0x78, 0x00, 0xE5, 0x81, 0x84, 0xC7, 0xD0, 0x1A, 0x40, ++0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x08, 0xCD, ++0x00, 0x34, 0x2E, 0x15, 0x2C, 0x41, 0x23, 0x20, 0xCD, 0x13, 0x04, 0x03, 0xD0, ++0x0C, 0x40, 0x33, 0x00, 0xC1, 0x11, 0x24, 0x03, 0xD0, 0x0C, 0x44, 0x37, 0x00, ++0xC1, 0x00, 0x34, 0x87, 0x90, 0x0C, 0x40, 0x37, 0x00, 0x81, 0x00, 0x34, 0x47, ++0xD0, 0x0C, 0x40, 0x30, 0x00, 0xCD, 0x00, 0x04, 0x87, 0xD0, 0xEC, 0x40, 0x4B, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, 0x00, 0x5F, 0x00, ++0xBC, 0x0D, 0x30, 0x07, 0xC0, 0x5F, 0x01, 0x7F, 0x40, 0x7C, 0x01, 0xD0, 0x05, ++0xC0, 0x17, 0x10, 0x73, 0x03, 0x7C, 0x01, 0x71, 0x05, 0xC0, 0x9E, 0xC0, 0x73, ++0x09, 0x9C, 0x05, 0x91, 0x05, 0xC0, 0x17, 0x00, 0x61, 0x00, 0xF4, 0x01, 0xF0, ++0x27, 0x40, 0x1C, 0x80, 0x4F, 0x00, 0xC4, 0x8D, 0xF0, 0x37, 0x40, 0x5F, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x7C, ++0x48, 0xF0, 0x01, 0xC0, 0x87, 0x20, 0x1F, 0x08, 0x7C, 0x00, 0xF0, 0x01, 0xE0, ++0x07, 0x40, 0x1F, 0x08, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x84, 0x26, 0x1F, 0x8A, ++0x7C, 0x20, 0x70, 0x21, 0xC0, 0x07, 0x00, 0x1F, 0x02, 0x7C, 0x08, 0xF2, 0x01, ++0xC0, 0x87, 0x39, 0x1F, 0x00, 0x7D, 0x40, 0xF0, 0x01, 0xC0, 0x4B, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x9F, 0x00, 0x5C, 0x06, ++0x30, 0x09, 0xC0, 0x67, 0x00, 0x83, 0x00, 0x0C, 0x02, 0xB2, 0x09, 0xC8, 0x27, ++0x02, 0x9B, 0x05, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x20, 0x91, 0x00, 0x7C, ++0x22, 0xB4, 0x98, 0xC0, 0x25, 0x00, 0x93, 0x40, 0x4C, 0x26, 0x30, 0x09, 0xC1, ++0x67, 0x02, 0x9B, 0x00, 0x0C, 0x02, 0x30, 0x39, 0xC0, 0x43, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00, 0x9D, 0x00, 0x44, 0x02, 0x14, ++0x09, 0xC0, 0x21, 0x02, 0x95, 0x00, 0x44, 0x02, 0x30, 0x09, 0xC0, 0x23, 0x00, ++0x90, 0x01, 0x74, 0x02, 0xD0, 0x99, 0x40, 0x27, 0x00, 0x91, 0x04, 0x7C, 0x0E, ++0x10, 0x09, 0x40, 0x2C, 0x00, 0x9B, 0x12, 0x2C, 0x0E, 0x14, 0x99, 0x40, 0xE3, ++0x40, 0x91, 0x00, 0x44, 0x0A, 0x50, 0x39, 0x48, 0x07, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x80, 0x8D, 0x00, 0x54, 0x22, 0x10, 0x09, ++0x60, 0x27, 0x00, 0x91, 0x00, 0x44, 0x02, 0x90, 0x09, 0x44, 0x27, 0x00, 0x99, ++0x00, 0x70, 0x02, 0xD8, 0x09, 0x40, 0x67, 0x00, 0x95, 0x20, 0x76, 0x0A, 0x18, ++0x09, 0x41, 0x25, 0x00, 0x91, 0x08, 0x40, 0x02, 0x10, 0x0D, 0x40, 0x27, 0x04, ++0x91, 0x01, 0x44, 0x47, 0x11, 0x29, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0xA0, 0x01, 0x8D, 0x04, 0x04, 0x02, 0x10, 0x48, 0x40, ++0xA5, 0xA0, 0x85, 0x14, 0x04, 0x02, 0x90, 0x08, 0x40, 0x21, 0x00, 0xC9, 0x00, ++0x34, 0x22, 0xD2, 0x08, 0x40, 0x27, 0x00, 0x85, 0x00, 0x74, 0x02, 0x1A, 0x08, ++0x40, 0x20, 0x02, 0x99, 0x20, 0x24, 0x03, 0x10, 0x0C, 0x40, 0x27, 0x00, 0x81, ++0x01, 0x04, 0x12, 0x50, 0x48, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1D, 0x8A, 0x54, 0x01, 0x31, 0x01, 0xC1, 0x97, ++0x00, 0x13, 0x0A, 0x4C, 0x50, 0xB0, 0x41, 0x41, 0x07, 0x05, 0x1B, 0x00, 0x7C, ++0x58, 0xD0, 0x41, 0x41, 0x17, 0x00, 0x17, 0x20, 0x7E, 0x00, 0xB0, 0x41, 0xC1, ++0xC5, 0x00, 0x13, 0x00, 0x4D, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x0A, ++0x4C, 0x00, 0x33, 0x01, 0xC2, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x19, 0xB8, 0x67, 0x02, 0x9F, 0x08, 0xBC, 0x02, 0xD0, 0x0B, 0xC8, 0x2D, 0x01, ++0xBF, 0x00, 0x7C, 0x02, 0x70, 0x09, 0xC0, 0x27, 0x00, 0xA6, 0x00, 0x7C, 0x12, ++0xF0, 0x09, 0xC0, 0x2F, 0x00, 0xBB, 0x00, 0x9C, 0x82, 0xF0, 0x09, 0xC0, 0xA7, ++0x09, 0xBF, 0x60, 0xDC, 0x82, 0xF0, 0x0A, 0xC0, 0x2F, 0x08, 0x97, 0x00, 0xFD, ++0x22, 0xF0, 0x8B, 0xC0, 0x67, 0x48, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA0, 0x27, 0x05, 0x9F, 0x0C, 0xFC, 0x02, 0xF0, 0x09, 0x40, 0x2F, 0x02, 0x9F, ++0x84, 0xF4, 0xD2, 0x70, 0x4B, 0xC0, 0x2C, 0x00, 0xBF, 0x00, 0x7C, 0x22, 0x70, ++0x4B, 0xC0, 0x2C, 0x00, 0xB7, 0x20, 0xFC, 0x02, 0xF0, 0x0B, 0xC2, 0x64, 0x03, ++0xA5, 0x80, 0xCC, 0x02, 0x71, 0x0B, 0x40, 0x2D, 0x00, 0xBB, 0x20, 0xCC, 0x02, ++0xF0, 0x0B, 0x82, 0x64, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, ++0x47, 0x05, 0x1D, 0x4C, 0x74, 0x00, 0xC0, 0x01, 0x44, 0x07, 0x20, 0x1D, 0xB4, ++0x74, 0x00, 0x70, 0x81, 0x40, 0x84, 0x00, 0x19, 0x80, 0x74, 0xA0, 0xD0, 0x01, ++0x44, 0x06, 0x00, 0x13, 0x80, 0x5C, 0x00, 0xD0, 0x01, 0x40, 0x84, 0x10, 0x57, ++0x00, 0x4C, 0x00, 0xD0, 0x01, 0xC0, 0x15, 0x20, 0x19, 0x50, 0x6C, 0x00, 0xD0, ++0x01, 0x50, 0x70, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, ++0x00, 0x8D, 0x04, 0x34, 0x02, 0xD0, 0x88, 0x40, 0x23, 0x00, 0x8D, 0x0C, 0x34, ++0x02, 0x50, 0x08, 0x40, 0x20, 0x02, 0x8D, 0x00, 0x34, 0x02, 0x50, 0x88, 0x48, ++0x26, 0x80, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x88, 0x40, 0xA0, 0x20, 0x85, 0x00, ++0x17, 0x82, 0x50, 0x08, 0x40, 0x21, 0x00, 0x8D, 0x00, 0x24, 0x02, 0xD0, 0x08, ++0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, ++0x9D, 0x00, 0x74, 0x13, 0xD0, 0x09, 0x40, 0xA7, 0x00, 0x9D, 0x10, 0x74, 0x02, ++0x50, 0x09, 0x40, 0x24, 0x00, 0xD9, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x26, ++0x00, 0x91, 0x06, 0x56, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x10, 0x95, 0x08, 0x44, ++0x06, 0xD8, 0x19, 0x40, 0x25, 0x00, 0x99, 0x00, 0x64, 0x06, 0xD0, 0x19, 0x00, ++0x60, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, 0x2D, 0x00, 0x9F, ++0x00, 0x7C, 0x06, 0xF0, 0x59, 0xC0, 0xA7, 0x02, 0x9F, 0x03, 0x7C, 0x02, 0x70, ++0x09, 0xC4, 0x24, 0x00, 0x9F, 0x05, 0x7C, 0x02, 0x70, 0x09, 0xC0, 0x60, 0x01, ++0x9F, 0x00, 0x7C, 0x42, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x97, 0x00, 0x5C, 0x46, ++0x70, 0x59, 0xCE, 0xE5, 0x02, 0x9B, 0x00, 0x6C, 0x4E, 0xF0, 0x19, 0xC1, 0x14, ++0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x25, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x29, 0xC0, 0x67, 0x00, 0x9F, 0x04, 0x7C, 0x02, 0xF0, 0x09, ++0x50, 0x27, 0x24, 0x9F, 0x09, 0x7C, 0x02, 0xF0, 0x09, 0xC4, 0x65, 0x02, 0x9F, ++0x41, 0x78, 0x02, 0xF1, 0x08, 0xD0, 0x27, 0x08, 0x9F, 0x01, 0x78, 0x02, 0xF0, ++0x09, 0xC0, 0x67, 0x80, 0x9E, 0x00, 0x78, 0x02, 0xF1, 0x08, 0xC0, 0x53, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x5C, ++0x00, 0xF8, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0x80, 0xC0, ++0x07, 0x00, 0x1F, 0x03, 0x7C, 0x00, 0xD2, 0x00, 0xD0, 0x04, 0x00, 0x1F, 0x12, ++0x4C, 0x40, 0xB0, 0x81, 0xC0, 0x04, 0x00, 0x1F, 0x02, 0x7C, 0x18, 0xF0, 0x21, ++0xC0, 0x07, 0x04, 0x13, 0x00, 0x4C, 0x18, 0x30, 0x01, 0xC0, 0x53, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x5D, 0x00, 0xC4, 0x01, ++0x70, 0x05, 0x40, 0x9F, 0x08, 0x51, 0x00, 0xF4, 0x6D, 0xD0, 0x15, 0x40, 0x9F, ++0x00, 0x7D, 0x10, 0x74, 0x01, 0xD1, 0x15, 0x43, 0x9C, 0x10, 0x7D, 0x00, 0xEC, ++0x11, 0x70, 0x37, 0xC8, 0x16, 0x00, 0x6D, 0x10, 0xC5, 0x01, 0xD0, 0x87, 0x40, ++0x5F, 0x04, 0x61, 0x18, 0xC4, 0x09, 0xB0, 0x07, 0x40, 0x53, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x14, 0x01, 0x50, ++0x0C, 0x48, 0xB3, 0x04, 0xC1, 0x00, 0x36, 0x0E, 0xD0, 0x08, 0x40, 0xB3, 0x00, ++0xCD, 0x01, 0x34, 0x03, 0xD8, 0x1C, 0x44, 0xB2, 0x81, 0xCD, 0x0B, 0x24, 0x03, ++0x50, 0x3C, 0x41, 0x31, 0x00, 0xCD, 0x11, 0x04, 0x0E, 0xD0, 0x2C, 0x40, 0x73, ++0x00, 0xC1, 0x40, 0x04, 0x03, 0x10, 0xAC, 0x61, 0x53, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x01, 0xED, 0x09, 0x84, 0x01, 0x50, 0x0E, ++0x40, 0xFB, 0x40, 0xE1, 0x00, 0xB6, 0x02, 0xD0, 0x0E, 0x40, 0x3B, 0x04, 0xED, ++0x20, 0xB4, 0x93, 0xD0, 0x1E, 0x40, 0xAA, 0x08, 0xFD, 0x01, 0xA4, 0x00, 0x51, ++0x0E, 0x40, 0x3B, 0x02, 0x2D, 0x00, 0x86, 0x0A, 0xD0, 0x0E, 0x60, 0x7B, 0x08, ++0xE1, 0x00, 0x05, 0x87, 0x90, 0x0E, 0x60, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x10, 0x78, 0x01, 0xFF, 0x05, 0x9C, 0x05, 0x70, 0x1E, 0xC0, ++0x7F, 0x00, 0xE3, 0x0F, 0xBC, 0x06, 0xF0, 0x1A, 0x40, 0x7B, 0x00, 0x2D, 0x01, ++0xB4, 0x3F, 0xF0, 0x0C, 0xCC, 0x4A, 0x80, 0xEF, 0x01, 0xAE, 0x04, 0x70, 0x1C, ++0xC0, 0x79, 0x05, 0x2D, 0x01, 0x9C, 0x07, 0xE9, 0x1E, 0xC0, 0x7B, 0x40, 0xE1, ++0x21, 0x8C, 0x05, 0x30, 0x16, 0xC0, 0x53, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xB8, 0x35, 0x00, 0xDF, 0x10, 0x7C, 0x01, 0x70, 0x0D, 0xC0, 0x37, ++0x00, 0xDF, 0x04, 0x7C, 0x02, 0xF2, 0x0D, 0xC4, 0x37, 0x00, 0xDF, 0x00, 0x7C, ++0x83, 0xF1, 0x0D, 0xC2, 0x25, 0x00, 0xCF, 0x40, 0x7C, 0x00, 0x60, 0x0D, 0xC0, ++0xB6, 0x20, 0x1F, 0x00, 0x58, 0x83, 0xFA, 0x09, 0xC0, 0x13, 0x08, 0xCF, 0x00, ++0x74, 0x02, 0xF1, 0x05, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xA2, 0x7F, 0x14, 0xFF, 0x01, 0xFC, 0x11, 0xF0, 0x1F, 0xC0, 0x7F, 0x02, ++0xFF, 0x09, 0xFC, 0x06, 0x30, 0x9F, 0xC0, 0x7E, 0x02, 0xFF, 0x09, 0xFC, 0x07, ++0x70, 0x1F, 0xC8, 0x6F, 0x02, 0xEF, 0x41, 0xDC, 0x24, 0xF0, 0x1E, 0xC0, 0x7C, ++0x00, 0x33, 0x09, 0xF8, 0x07, 0xF0, 0x9F, 0xC0, 0x7F, 0x02, 0xFB, 0x41, 0xCC, ++0x05, 0x30, 0x97, 0xC4, 0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0x88, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x41, 0xD1, 0x0E, 0xC0, 0x39, 0x23, 0xED, ++0x08, 0xB4, 0x02, 0xB0, 0x8E, 0x08, 0x38, 0x00, 0xED, 0x08, 0xDC, 0x23, 0x30, ++0x4E, 0x44, 0x6B, 0x2A, 0xC9, 0xC0, 0x10, 0x20, 0xD0, 0x82, 0x40, 0x39, 0x00, ++0x2D, 0x0C, 0x34, 0x07, 0xD0, 0x04, 0x00, 0x3B, 0x07, 0xE7, 0x08, 0xAC, 0x29, ++0x30, 0xAE, 0xC0, 0x55, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x79, 0x00, 0xED, 0x00, 0xB4, 0x21, 0xD0, 0x0E, 0x40, 0x1B, 0x24, 0xED, 0x40, ++0x96, 0x02, 0x90, 0x8E, 0x48, 0x29, 0x08, 0x2D, 0x00, 0x90, 0x03, 0x50, 0x0A, ++0x48, 0x0B, 0x07, 0x65, 0x18, 0x94, 0x40, 0xD0, 0x0E, 0x40, 0x31, 0x00, 0x2D, ++0x80, 0xB4, 0x43, 0xD0, 0x0E, 0x48, 0x2B, 0x00, 0x65, 0x00, 0x84, 0x01, 0x90, ++0x82, 0x40, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x33, ++0x00, 0xCD, 0x00, 0x34, 0x0D, 0xD0, 0x2C, 0x40, 0xE1, 0x04, 0xCD, 0x02, 0x34, ++0x02, 0x80, 0x0C, 0x50, 0x21, 0x10, 0xCD, 0x12, 0x14, 0x03, 0x10, 0x08, 0x40, ++0x63, 0x11, 0x49, 0x01, 0x04, 0x0C, 0xC0, 0x00, 0x42, 0x31, 0x00, 0x0D, 0x00, ++0x34, 0x4B, 0xD8, 0x90, 0x42, 0x73, 0x01, 0x45, 0x00, 0x24, 0x2E, 0x14, 0x18, ++0x40, 0x19, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, ++0xFF, 0x00, 0x3C, 0x0F, 0xF0, 0x2D, 0xC1, 0x83, 0x00, 0xFF, 0x05, 0x5E, 0x03, ++0xB0, 0x08, 0xC0, 0x35, 0x00, 0xCF, 0x81, 0xDC, 0x83, 0x70, 0x09, 0xC2, 0x23, ++0x10, 0xD7, 0x00, 0x5C, 0x00, 0xF0, 0x0D, 0xC0, 0x3D, 0x08, 0x17, 0x18, 0x74, ++0x03, 0xF0, 0x39, 0x68, 0x37, 0x10, 0xD7, 0x00, 0x4C, 0x82, 0xB8, 0x59, 0xC0, ++0x77, 0x21, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xDF, ++0x40, 0x7C, 0x11, 0xF0, 0x4D, 0xC2, 0x87, 0x00, 0xDF, 0x00, 0x7C, 0x0A, 0xF1, ++0x0D, 0x40, 0xB4, 0x00, 0xDF, 0x01, 0x5C, 0x03, 0x70, 0x0D, 0x82, 0xA7, 0x00, ++0xDC, 0x44, 0x7C, 0x00, 0xF2, 0x0D, 0xC0, 0x33, 0x00, 0x16, 0x20, 0x7C, 0x03, ++0xF0, 0x09, 0xC5, 0x36, 0x00, 0xD7, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC9, 0x07, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0xFB, 0x00, ++0xFC, 0x0B, 0x30, 0x0E, 0xC0, 0x2C, 0x00, 0xF3, 0x10, 0xFC, 0x27, 0xF0, 0x09, ++0xC0, 0x38, 0x40, 0x33, 0x05, 0xCC, 0x03, 0xF0, 0x0A, 0xC0, 0x0C, 0x00, 0xF3, ++0xA0, 0xE8, 0xC0, 0x30, 0x13, 0xC0, 0x3F, 0x00, 0x3B, 0x01, 0xCC, 0x05, 0xF0, ++0x03, 0xC2, 0x3D, 0x00, 0xFB, 0x01, 0x7C, 0x42, 0xF0, 0x02, 0x40, 0x04, 0x28, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0xD1, 0x00, 0x74, ++0x02, 0x14, 0x0D, 0x60, 0x64, 0x81, 0xD5, 0x00, 0x74, 0x0E, 0xD0, 0x0D, 0x40, ++0x35, 0x81, 0xD1, 0x23, 0x4C, 0x03, 0x30, 0x0D, 0x40, 0xE5, 0x00, 0xC1, 0x00, ++0x10, 0x20, 0xB0, 0x51, 0x40, 0x37, 0x00, 0x05, 0x43, 0x44, 0x15, 0xD0, 0x11, ++0x43, 0x13, 0x00, 0xD1, 0x00, 0x7C, 0x0E, 0xD1, 0x31, 0x50, 0x04, 0x06, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x32, 0x00, 0xD9, 0x00, 0x74, 0x03, ++0x92, 0x0D, 0x50, 0x44, 0x08, 0xD1, 0x00, 0x74, 0xC3, 0xDA, 0x0D, 0x00, 0x14, ++0x20, 0x11, 0x40, 0x64, 0x03, 0xD0, 0x49, 0x40, 0xC4, 0x00, 0x91, 0x08, 0x74, ++0x40, 0x90, 0x4D, 0x40, 0x37, 0x00, 0x15, 0x14, 0x64, 0x23, 0xD1, 0x19, 0x04, ++0x37, 0x00, 0x91, 0x04, 0x74, 0x04, 0xD9, 0x19, 0x40, 0x05, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0xC1, 0x00, 0x74, 0x01, 0x90, ++0x0C, 0x40, 0x04, 0x00, 0xC5, 0x00, 0x34, 0x01, 0xD0, 0x0C, 0x40, 0x11, 0x10, ++0x01, 0x00, 0x24, 0x03, 0x50, 0x0C, 0x46, 0x05, 0xE1, 0x91, 0x02, 0x54, 0x20, ++0x90, 0x00, 0x40, 0x33, 0x00, 0x15, 0x00, 0x05, 0xB3, 0xD8, 0x00, 0x00, 0x33, ++0xC0, 0x81, 0x40, 0x24, 0x00, 0xD0, 0x08, 0x60, 0x40, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x90, 0x3E, 0x00, 0xFB, 0x00, 0x7C, 0x03, 0xB0, 0x0D, ++0x40, 0x04, 0x00, 0xF1, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x04, 0x00, 0x11, ++0x00, 0xEC, 0x03, 0xF0, 0x09, 0xC0, 0x04, 0x05, 0x13, 0x02, 0x6C, 0x00, 0xB0, ++0x01, 0x40, 0x3F, 0x00, 0x17, 0x00, 0x6C, 0x03, 0xF2, 0xA1, 0xC0, 0x27, 0x00, ++0x43, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC8, 0x05, 0x40, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0x70, 0x0F, 0xC0, ++0x2F, 0x00, 0xFF, 0x00, 0xBC, 0x01, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, 0x3F, 0x00, ++0xD0, 0x03, 0x30, 0x0B, 0xC0, 0x07, 0x10, 0x3F, 0x80, 0xEC, 0x90, 0xF0, 0x03, ++0xC0, 0x3F, 0x00, 0x3C, 0x00, 0x7C, 0x1B, 0xF0, 0x43, 0xC0, 0x3F, 0x00, 0x7F, ++0x00, 0xDC, 0x02, 0xF0, 0x0B, 0xC8, 0x17, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x80, 0x0F, 0x06, 0xAF, 0x00, 0xEC, 0x02, 0xE0, 0x1E, 0xC0, 0x0F, ++0x05, 0xFB, 0x0C, 0xFC, 0x50, 0x30, 0x43, 0xC0, 0x2C, 0x01, 0x33, 0x00, 0xCC, ++0x03, 0x30, 0x1F, 0xC0, 0x0F, 0x05, 0x23, 0x01, 0xEC, 0x03, 0xB0, 0x13, 0xC0, ++0x3F, 0x01, 0x3B, 0x01, 0xC4, 0x06, 0xB6, 0x83, 0xC0, 0x0D, 0x03, 0x37, 0x00, ++0xAC, 0x27, 0x30, 0x1E, 0xC0, 0x0E, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x10, 0x87, 0x01, 0x9D, 0x01, 0x44, 0x00, 0xD0, 0x0D, 0x40, 0x83, 0x00, ++0xF1, 0x08, 0x74, 0x10, 0x10, 0x09, 0x40, 0xB4, 0x07, 0x55, 0x10, 0x84, 0x2B, ++0x10, 0x41, 0xC3, 0x44, 0x00, 0x11, 0x01, 0xC4, 0x07, 0xB0, 0x15, 0xC0, 0xBD, ++0x12, 0xD1, 0x01, 0x44, 0x42, 0x10, 0xE1, 0x40, 0x90, 0x03, 0x11, 0x23, 0x44, ++0x12, 0x10, 0x11, 0x40, 0x0C, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++0xA0, 0x03, 0x00, 0x8D, 0x80, 0x14, 0x06, 0xC0, 0x0C, 0x40, 0x01, 0x00, 0xC9, ++0x04, 0x36, 0x40, 0x10, 0x64, 0x49, 0x20, 0x09, 0x01, 0x08, 0x04, 0xC3, 0x10, ++0x44, 0x40, 0x13, 0x00, 0x01, 0x00, 0x14, 0x0B, 0x98, 0x08, 0x42, 0x33, 0x95, ++0x15, 0x00, 0x64, 0x13, 0x10, 0x48, 0x48, 0x01, 0x00, 0x05, 0x82, 0x76, 0x11, ++0x11, 0x0C, 0x50, 0x4C, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, ++0x45, 0x00, 0xDD, 0x22, 0x54, 0x04, 0xD1, 0x0D, 0x40, 0x47, 0x10, 0xD1, 0x00, ++0x74, 0x09, 0x10, 0x0D, 0x40, 0x34, 0x00, 0xD5, 0x10, 0x44, 0x03, 0x10, 0x21, ++0x40, 0x84, 0x00, 0x11, 0x01, 0x54, 0x03, 0x80, 0x0D, 0x42, 0x35, 0x00, 0x15, ++0x10, 0x64, 0x02, 0x10, 0x09, 0x44, 0x25, 0x04, 0xD5, 0x14, 0x54, 0x03, 0x10, ++0x09, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x47, ++0x00, 0x9F, 0x09, 0x7D, 0x04, 0xF0, 0x9D, 0xC0, 0xC7, 0x20, 0xDB, 0x80, 0x7C, ++0x09, 0x31, 0x51, 0xC0, 0x64, 0x02, 0x13, 0x02, 0x4C, 0x03, 0x30, 0x2D, 0xC0, ++0xC7, 0x42, 0x13, 0x01, 0x7C, 0x03, 0xB0, 0x89, 0xC0, 0x37, 0x00, 0x9F, 0x02, ++0x2D, 0x02, 0xB1, 0xB5, 0xC0, 0x85, 0x00, 0x05, 0x03, 0x7C, 0x6F, 0x24, 0x1C, ++0x80, 0x8A, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0D, 0x00, ++0xAF, 0x00, 0xEC, 0x00, 0xF0, 0x0F, 0xC0, 0x0B, 0x10, 0xFF, 0x00, 0xBC, 0x02, ++0xF2, 0x91, 0xC0, 0x7B, 0x00, 0x2F, 0x00, 0xBC, 0x03, 0xF0, 0x57, 0xC0, 0x2D, ++0x00, 0x3E, 0x00, 0xAC, 0x83, 0xF0, 0x0B, 0xC8, 0x3B, 0x00, 0xFB, 0x49, 0xDC, ++0x02, 0xD0, 0x12, 0xC0, 0x1A, 0x40, 0xFB, 0x00, 0xEC, 0x03, 0xF4, 0x5F, 0xC0, ++0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x05, 0x80, 0x9F, ++0x07, 0x6C, 0x02, 0x70, 0x8D, 0xC0, 0x06, 0x00, 0xD3, 0x20, 0x5E, 0x09, 0x38, ++0x00, 0xC0, 0x24, 0x02, 0x5F, 0x00, 0x4C, 0x03, 0x30, 0x0D, 0xC0, 0x93, 0x00, ++0x1F, 0x06, 0x4C, 0x63, 0x30, 0x09, 0xC0, 0x34, 0x20, 0x1B, 0x20, 0x4E, 0x03, ++0xF1, 0x0D, 0xC0, 0x96, 0x0A, 0x17, 0x02, 0x6C, 0x43, 0x30, 0x0D, 0xC0, 0x28, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x44, 0x86, 0xDD, 0xC2, ++0x44, 0xE8, 0x12, 0x1D, 0x40, 0x04, 0x00, 0xF1, 0x00, 0x6C, 0x03, 0x31, 0x01, ++0x40, 0xF4, 0x02, 0xDD, 0x04, 0xC4, 0x03, 0x10, 0x05, 0xC6, 0xE7, 0x81, 0x0F, ++0x40, 0xD0, 0x0B, 0xB1, 0x1D, 0x40, 0x3D, 0x00, 0x41, 0x00, 0x4C, 0x02, 0x70, ++0x09, 0x44, 0x34, 0x12, 0xDB, 0x1B, 0x08, 0x43, 0x10, 0x7D, 0x40, 0x4D, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x02, 0x30, 0x0D, 0x00, 0x04, ++0x06, 0x10, 0x58, 0x50, 0x00, 0x00, 0xC1, 0x00, 0x24, 0x02, 0x90, 0x00, 0x40, ++0x30, 0x00, 0x8D, 0x01, 0x04, 0x27, 0x10, 0x09, 0x40, 0x23, 0x21, 0x09, 0x42, ++0x04, 0x0F, 0x50, 0xF4, 0x48, 0x30, 0x10, 0x41, 0x00, 0x06, 0x02, 0xDA, 0x00, ++0x00, 0x62, 0x40, 0xCC, 0x03, 0x01, 0x07, 0x58, 0x7C, 0x40, 0x0C, 0x20, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x4A, 0x00, 0x6D, 0x01, 0x84, 0x07, ++0x12, 0x1F, 0x44, 0x48, 0x00, 0xE1, 0x01, 0x24, 0x04, 0x10, 0x9A, 0x40, 0x78, ++0x80, 0x4D, 0x01, 0x84, 0x27, 0x10, 0x1A, 0x42, 0x59, 0x00, 0x35, 0x01, 0x94, ++0x03, 0xDC, 0x16, 0x60, 0x71, 0x02, 0xE1, 0x01, 0x84, 0x06, 0x50, 0x94, 0x40, ++0x78, 0x83, 0xE9, 0x09, 0xC4, 0x27, 0x50, 0x16, 0x40, 0x35, 0x20, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x82, 0x00, 0x8D, 0x00, 0x4C, 0x23, 0x70, ++0x88, 0xC0, 0x80, 0x42, 0xD3, 0x00, 0x34, 0x02, 0x90, 0x84, 0xC4, 0x30, 0x00, ++0x8D, 0x00, 0x0C, 0x03, 0x30, 0x44, 0x40, 0x33, 0x01, 0x0D, 0x08, 0x0C, 0x13, ++0x50, 0x04, 0x40, 0x30, 0x00, 0x03, 0x08, 0x0C, 0x83, 0xF0, 0xA0, 0xD0, 0x02, ++0x01, 0x07, 0x88, 0x0C, 0x23, 0x70, 0x4C, 0xC0, 0x48, 0x40, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xB8, 0x0D, 0x00, 0xFF, 0x08, 0xDE, 0x03, 0xF4, 0x0F, ++0xC2, 0x0D, 0x00, 0xFF, 0x00, 0xFC, 0x01, 0xF0, 0x8F, 0xC2, 0x3F, 0x00, 0xFF, ++0x40, 0xFC, 0x03, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x3F, 0x08, 0xBC, 0x1B, 0x30, ++0x8E, 0xC0, 0x3F, 0x00, 0xA7, 0xA0, 0xFD, 0x02, 0xF0, 0x87, 0xC0, 0x2F, 0x41, ++0xEF, 0x08, 0x7C, 0x23, 0xB0, 0x0D, 0xC4, 0x0B, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA8, 0x0F, 0x00, 0x1F, 0x00, 0x4C, 0x01, 0xE1, 0x09, 0xC0, ++0x07, 0x08, 0xDF, 0x06, 0x5C, 0x03, 0xF0, 0x1D, 0xC0, 0x34, 0x00, 0x93, 0x00, ++0x4C, 0x27, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x1B, 0x00, 0x7C, 0x23, 0xF8, 0x11, ++0xC0, 0x36, 0x03, 0xDB, 0x00, 0x7C, 0x02, 0xF0, 0x1D, 0xC0, 0x24, 0x00, 0x13, ++0x20, 0x4D, 0x03, 0x30, 0x0D, 0xC0, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x98, 0x29, 0x00, 0x6D, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x0B, ++0x00, 0xFD, 0x12, 0x84, 0x02, 0xD0, 0x0F, 0x48, 0x38, 0x00, 0x21, 0x00, 0x04, ++0x33, 0x14, 0x0A, 0x40, 0x3B, 0x40, 0x22, 0x00, 0xB4, 0x13, 0xD0, 0x0A, 0x40, ++0x3C, 0x02, 0xE1, 0x00, 0xB4, 0x02, 0xD0, 0x0E, 0x52, 0x3D, 0x00, 0xC5, 0x00, ++0x84, 0x02, 0x10, 0x0E, 0x40, 0x4F, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x00, 0xF9, 0x00, 0x8D, 0x01, 0x94, 0x0F, 0xD0, 0x1A, 0x40, 0x5B, 0x08, ++0xED, 0x01, 0x94, 0x07, 0xD0, 0x3E, 0x40, 0x78, 0x40, 0xC1, 0x11, 0xA5, 0x07, ++0x18, 0x1E, 0x40, 0x73, 0x00, 0x21, 0x01, 0xB4, 0x07, 0x50, 0x17, 0x46, 0x79, ++0x01, 0xE9, 0x01, 0xB4, 0x07, 0xD2, 0x1C, 0x70, 0x58, 0x00, 0x21, 0x01, 0x86, ++0x47, 0x10, 0x1E, 0x41, 0x13, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x20, 0xB3, 0x00, 0xCD, 0x00, 0x14, 0x03, 0xD0, 0x0C, 0x40, 0xB7, 0x00, 0xCD, ++0x00, 0x04, 0x17, 0xD8, 0x0C, 0x40, 0x34, 0x00, 0xC1, 0x00, 0x24, 0x03, 0x10, ++0x2C, 0x40, 0xB3, 0x01, 0xC1, 0x07, 0x34, 0x03, 0xD8, 0x2C, 0x40, 0x31, 0x00, ++0xC1, 0x48, 0x74, 0x02, 0xD0, 0x2C, 0x64, 0x71, 0x80, 0xC5, 0x0B, 0x04, 0x9B, ++0x12, 0x3C, 0x60, 0x5B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, ++0x1F, 0x00, 0x6F, 0x00, 0xDD, 0x0D, 0xF0, 0x05, 0xC0, 0x1F, 0x00, 0x5F, 0x00, ++0xDC, 0x49, 0xF0, 0x07, 0xD0, 0x14, 0x00, 0x73, 0x01, 0x6C, 0x01, 0x30, 0xD7, ++0xC0, 0x9B, 0x40, 0x73, 0x11, 0x7C, 0x01, 0xF0, 0xB7, 0x54, 0x17, 0x00, 0x7B, ++0x02, 0x7C, 0x01, 0xF0, 0x47, 0xC0, 0x5C, 0x09, 0x73, 0x80, 0x8C, 0x05, 0x35, ++0x06, 0xC0, 0x5F, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x05, ++0x00, 0x1F, 0x00, 0x6C, 0x98, 0xF2, 0x01, 0xC0, 0x07, 0x04, 0x0F, 0x00, 0x7C, ++0x00, 0xF0, 0x41, 0xC0, 0x07, 0x08, 0x0F, 0x02, 0x5C, 0x80, 0xF0, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x82, 0x7C, 0x80, 0xF0, 0x81, 0xC0, 0x04, 0x00, 0x1F, 0x04, ++0x7C, 0x00, 0xB8, 0x01, 0xC1, 0x07, 0x00, 0x0F, 0x12, 0x7C, 0x00, 0xF0, 0x21, ++0xC5, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x61, 0x04, ++0x93, 0x00, 0x0D, 0x0E, 0x30, 0x19, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x1C, 0x02, ++0xB4, 0x09, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x4D, 0x02, 0xF0, 0x09, 0xC8, 0x27, ++0x02, 0x9F, 0x40, 0x7C, 0x02, 0xF2, 0x89, 0xC0, 0x27, 0x00, 0x97, 0x00, 0x7C, ++0x02, 0x30, 0x09, 0xC8, 0x23, 0x20, 0x9B, 0x01, 0x4D, 0x22, 0x70, 0x19, 0xC2, ++0x41, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x02, 0x95, ++0x02, 0x44, 0x0E, 0x14, 0x09, 0x42, 0x27, 0x00, 0x91, 0x00, 0x44, 0x02, 0x10, ++0x09, 0x48, 0x27, 0x08, 0x91, 0x12, 0x44, 0x42, 0xD0, 0x09, 0x44, 0x67, 0x10, ++0x91, 0x00, 0x74, 0x46, 0xD0, 0x39, 0xE0, 0x25, 0x00, 0x93, 0x00, 0x5C, 0x02, ++0x50, 0x09, 0x40, 0x27, 0x00, 0x91, 0x03, 0x4C, 0x02, 0x10, 0xA9, 0x40, 0x04, ++0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x24, 0x00, 0x91, 0x02, ++0x44, 0x02, 0x90, 0x89, 0x40, 0x27, 0x00, 0x91, 0x00, 0x54, 0x02, 0x10, 0x09, ++0x40, 0x27, 0x00, 0x9D, 0x40, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x20, 0xD5, ++0x00, 0x74, 0x12, 0xD8, 0x0D, 0x45, 0x23, 0x00, 0x95, 0x00, 0x74, 0x02, 0x10, ++0x09, 0x40, 0x27, 0x40, 0x99, 0x88, 0x44, 0x42, 0x50, 0x09, 0x42, 0x71, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x20, 0x01, 0x85, 0x04, 0x04, ++0x1B, 0x90, 0x28, 0x40, 0x23, 0x41, 0x81, 0x0C, 0x04, 0x12, 0x10, 0x48, 0x40, ++0x23, 0x01, 0x8D, 0x04, 0x06, 0x12, 0xD0, 0x88, 0x40, 0x23, 0x01, 0xC1, 0x00, ++0x36, 0x02, 0xD0, 0x08, 0x44, 0x23, 0x03, 0x81, 0x00, 0x14, 0x02, 0x50, 0x08, ++0x44, 0x23, 0x02, 0xC9, 0x00, 0x44, 0x22, 0x10, 0x0D, 0x60, 0x50, 0xA8, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x86, 0x02, 0x13, 0x00, 0x4C, 0x08, ++0xB0, 0x25, 0xC0, 0x87, 0x02, 0x13, 0x02, 0x5C, 0x28, 0x30, 0xA1, 0xC0, 0x83, ++0x42, 0x1F, 0x0A, 0x44, 0x28, 0xD0, 0x21, 0x00, 0x17, 0x00, 0x1F, 0x40, 0x7C, ++0x50, 0xF0, 0x01, 0x40, 0x87, 0x00, 0x17, 0x00, 0x7C, 0x28, 0x30, 0xE1, 0xC1, ++0x87, 0x45, 0x1B, 0x14, 0x0C, 0x08, 0x70, 0x01, 0xC0, 0x75, 0xC0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x19, 0xA8, 0x2F, 0x12, 0xBF, 0x08, 0xFC, 0x0A, 0x70, ++0x0B, 0xC2, 0x2F, 0x02, 0x9F, 0x0C, 0xFC, 0x22, 0xF0, 0x8B, 0xC0, 0x2F, 0x02, ++0xB3, 0x08, 0x7C, 0x22, 0xF2, 0x4F, 0xC0, 0x2F, 0x22, 0xBF, 0x00, 0x7C, 0x02, ++0xF0, 0x0A, 0xC0, 0x25, 0x03, 0xB6, 0x00, 0xD8, 0x02, 0xF0, 0x0B, 0xC0, 0x3F, ++0x41, 0xB7, 0x00, 0xDC, 0x12, 0xF4, 0x0F, 0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, 0x05, 0xBF, 0x04, 0xCC, 0x02, 0xF0, 0x0B, ++0xC0, 0x33, 0x02, 0x93, 0x04, 0x7C, 0xD2, 0xB0, 0xC9, 0xC0, 0x2C, 0x00, 0xB3, ++0x00, 0xCC, 0x22, 0x34, 0x09, 0xC0, 0x28, 0x05, 0xBB, 0x00, 0xDC, 0x02, 0xB0, ++0x0B, 0xC0, 0x27, 0x02, 0xB3, 0x20, 0x5C, 0x8A, 0xF2, 0x49, 0xC2, 0x2D, 0x40, ++0xBE, 0x00, 0xCC, 0x02, 0x30, 0x0A, 0xD0, 0x60, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1C, 0x18, 0x15, 0x01, 0x1D, 0x08, 0x45, 0xC8, 0xD0, 0x01, 0x49, ++0x07, 0x02, 0x11, 0x14, 0x30, 0x10, 0x00, 0xC1, 0x42, 0x84, 0x04, 0x01, 0x10, ++0x44, 0x20, 0x11, 0x41, 0x83, 0x05, 0x20, 0x57, 0x40, 0x5C, 0x08, 0x01, 0x01, ++0x40, 0x03, 0x02, 0x11, 0x00, 0x64, 0x14, 0xD0, 0xD1, 0x41, 0x81, 0x44, 0x55, ++0x00, 0x04, 0x01, 0x50, 0x01, 0x40, 0x70, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x20, 0x31, 0x05, 0x8D, 0x00, 0x34, 0xB2, 0xD0, 0x08, 0x40, 0x23, ++0x00, 0x81, 0x2C, 0x34, 0x52, 0x98, 0x48, 0x48, 0x20, 0x03, 0x81, 0xC8, 0x04, ++0x02, 0x10, 0x49, 0x04, 0x20, 0x10, 0x81, 0x00, 0x14, 0x22, 0xD1, 0x08, 0x40, ++0x23, 0x20, 0x81, 0x00, 0x16, 0x12, 0xD0, 0x08, 0x40, 0x21, 0x4B, 0x8D, 0xC0, ++0x45, 0x02, 0x12, 0x09, 0x40, 0x48, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0x00, 0x25, 0x01, 0x9D, 0x03, 0x74, 0x0A, 0xD2, 0x09, 0x40, 0xA3, 0x40, ++0x91, 0x40, 0x74, 0x02, 0x10, 0x08, 0x40, 0x30, 0x00, 0x91, 0x03, 0x04, 0x02, ++0x10, 0x49, 0x50, 0x26, 0x12, 0x95, 0x00, 0x54, 0x03, 0x50, 0xA9, 0x40, 0x27, ++0x00, 0x91, 0x00, 0x64, 0x12, 0xD0, 0x09, 0x40, 0x25, 0x40, 0x95, 0x08, 0x44, ++0x12, 0x50, 0x09, 0x40, 0x60, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xA8, 0x67, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC4, 0x27, 0x00, 0x93, ++0x60, 0x7C, 0x02, 0xB0, 0x19, 0xD0, 0x24, 0x40, 0x93, 0x02, 0x44, 0x02, 0x30, ++0x08, 0xC2, 0x24, 0x08, 0x93, 0x02, 0x5C, 0x82, 0xF0, 0x19, 0xC8, 0x27, 0x40, ++0x91, 0x18, 0x5C, 0x06, 0xF0, 0x29, 0xC1, 0x25, 0x00, 0x9F, 0x00, 0x44, 0x02, ++0x20, 0x28, 0xC0, 0x14, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, ++0x65, 0x00, 0x8F, 0x00, 0x4C, 0x4E, 0xF0, 0x09, 0xC1, 0xE7, 0x30, 0x9F, 0x40, ++0x7C, 0x22, 0xF0, 0x49, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7D, 0x02, 0xF0, 0x09, ++0xC0, 0x65, 0x00, 0x9F, 0x19, 0x7C, 0x02, 0xB0, 0x09, 0xC0, 0x27, 0x10, 0x9F, ++0x01, 0x7C, 0x02, 0xF0, 0x09, 0xC8, 0xE7, 0x40, 0x8B, 0x10, 0x7C, 0x82, 0xF0, ++0x09, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x05, ++0x80, 0x1F, 0x06, 0x4E, 0x08, 0xF0, 0x01, 0xC4, 0x04, 0x80, 0x13, 0x00, 0x7E, ++0x80, 0xF0, 0x01, 0xC0, 0x07, 0x06, 0x1F, 0x12, 0x5C, 0x20, 0xF8, 0x21, 0xC0, ++0x07, 0x94, 0x13, 0x02, 0x3C, 0x00, 0xF0, 0x21, 0xC0, 0x07, 0x00, 0x1B, 0x0A, ++0x7C, 0x00, 0xE1, 0x20, 0xC0, 0x80, 0x04, 0x17, 0x20, 0x4C, 0x00, 0x30, 0x81, ++0xC2, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x1C, 0x00, ++0x7D, 0x00, 0xC4, 0x01, 0x70, 0x57, 0x40, 0x15, 0x80, 0x5B, 0x40, 0x64, 0x01, ++0xB2, 0x05, 0xC2, 0x1F, 0x20, 0x7D, 0x11, 0xC4, 0x25, 0x78, 0x05, 0xE0, 0xDB, ++0x00, 0x7B, 0x04, 0xFC, 0x2D, 0x70, 0x37, 0x44, 0x17, 0x20, 0x53, 0x40, 0x58, ++0x01, 0x70, 0x05, 0xD0, 0x1C, 0x00, 0x71, 0x00, 0xC4, 0x05, 0x14, 0x17, 0x40, ++0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, ++0x20, 0x06, 0x03, 0x50, 0x3C, 0x40, 0x30, 0x00, 0xC1, 0x00, 0x74, 0x03, 0x50, ++0x0C, 0x60, 0xF3, 0x08, 0xDD, 0x02, 0x14, 0x0F, 0xD1, 0x0C, 0x40, 0x13, 0x02, ++0xC1, 0x03, 0x34, 0x0F, 0x41, 0x4C, 0x60, 0x37, 0x80, 0x81, 0x01, 0x34, 0x03, ++0x90, 0x0C, 0x40, 0x32, 0x00, 0xC5, 0x03, 0x44, 0x1F, 0x50, 0x4C, 0x40, 0x50, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x28, 0x00, 0xAD, 0x00, ++0x86, 0x41, 0x58, 0x1E, 0x60, 0x3D, 0x10, 0xE9, 0x40, 0xB4, 0x33, 0x10, 0x4E, ++0x40, 0x39, 0x08, 0xED, 0x00, 0x84, 0x03, 0x50, 0x4E, 0x40, 0x19, 0x08, 0xE9, ++0x00, 0x94, 0x09, 0x50, 0x26, 0x40, 0x3B, 0x03, 0xA1, 0x40, 0xB6, 0x13, 0x50, ++0x8E, 0x40, 0x08, 0x04, 0xC1, 0x02, 0x84, 0x40, 0x50, 0x0E, 0x40, 0x05, 0x20, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x68, 0x00, 0xCD, 0x01, 0x85, ++0x07, 0x70, 0x17, 0xC0, 0x78, 0x01, 0xE1, 0x01, 0xB4, 0x07, 0x50, 0x5E, 0x40, ++0x7B, 0x00, 0xED, 0x01, 0x9C, 0x85, 0xD0, 0x1E, 0x60, 0x7B, 0x00, 0xE1, 0x01, ++0xB4, 0x06, 0x70, 0x1E, 0xC0, 0x7B, 0x40, 0xA3, 0x01, 0xBC, 0x1F, 0xF1, 0x5F, ++0xC0, 0x7A, 0x00, 0xE7, 0x01, 0x8D, 0x07, 0x70, 0x1E, 0xC0, 0x44, 0x40, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x2D, 0x00, 0x9F, 0x00, 0x7C, 0x01, ++0x70, 0x0D, 0xC0, 0xB7, 0x00, 0xDF, 0x00, 0x6C, 0x43, 0xF1, 0x2D, 0xC1, 0x37, ++0x30, 0xDC, 0x00, 0x7C, 0x81, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, ++0x02, 0x70, 0x0D, 0xC0, 0xB7, 0x04, 0x9B, 0x00, 0x58, 0x83, 0xFA, 0x0D, 0xCC, ++0x06, 0x00, 0xDF, 0x00, 0x7C, 0x00, 0xB0, 0x0D, 0xC0, 0x43, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x6F, 0x00, 0xF3, 0x41, 0xCC, 0x13, 0xF0, ++0x1F, 0xC0, 0xFF, 0x04, 0xFB, 0x91, 0xEC, 0x07, 0x80, 0x9F, 0xC1, 0x5C, 0x08, ++0x7B, 0x89, 0xCC, 0x06, 0x30, 0x1F, 0xC1, 0x5F, 0x00, 0xB3, 0x01, 0xF8, 0xA7, ++0xB0, 0x1F, 0xD0, 0x7C, 0x00, 0xFF, 0x21, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7D, ++0x02, 0x77, 0x01, 0xCC, 0x07, 0xB0, 0x1F, 0xC0, 0x03, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x10, 0xAD, 0x40, 0xA1, 0x30, 0x84, 0x03, 0xD0, 0x0E, ++0x45, 0x3F, 0x00, 0xE1, 0x00, 0x84, 0x63, 0x10, 0x0E, 0x48, 0x0C, 0x02, 0x31, ++0x0C, 0xC5, 0x22, 0x10, 0x0E, 0x43, 0x9B, 0x02, 0xA1, 0x02, 0xB4, 0x01, 0x50, ++0xA2, 0x40, 0x38, 0x80, 0xED, 0x10, 0xB4, 0x03, 0x70, 0x4E, 0x50, 0x18, 0x47, ++0xFB, 0x00, 0xC4, 0x08, 0x14, 0x0A, 0x48, 0x57, 0x60, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x08, 0x28, 0x00, 0x61, 0x08, 0x84, 0x63, 0xD0, 0x86, 0x40, ++0x3B, 0x00, 0xE1, 0x00, 0x24, 0x03, 0x14, 0x0C, 0x50, 0x18, 0x44, 0x61, 0x00, ++0xA4, 0x00, 0x14, 0x0E, 0x40, 0x33, 0x44, 0x21, 0x10, 0xB4, 0x03, 0x11, 0x0E, ++0x40, 0x38, 0x00, 0xED, 0x00, 0xB4, 0x43, 0xD0, 0x0E, 0x44, 0x39, 0x80, 0xF5, ++0x00, 0x84, 0x43, 0x90, 0x0E, 0x40, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x20, 0x23, 0x14, 0x01, 0x20, 0x04, 0x0E, 0xD0, 0x18, 0x40, 0xB3, ++0x04, 0xC1, 0x00, 0x04, 0x03, 0x10, 0x2C, 0x41, 0x40, 0x00, 0x01, 0x03, 0x64, ++0x00, 0x11, 0x2C, 0x40, 0xF3, 0x00, 0x01, 0x12, 0x34, 0x03, 0x50, 0x38, 0x40, ++0x30, 0x00, 0xCD, 0x03, 0x76, 0x07, 0x50, 0x0D, 0x40, 0x54, 0x00, 0x49, 0x0C, ++0x05, 0x0E, 0x10, 0x9C, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x28, 0x25, 0x00, 0x93, 0x01, 0x45, 0x0A, 0xF8, 0x09, 0xC0, 0xBF, 0x40, ++0xF3, 0x00, 0xEC, 0x0F, 0x30, 0x2F, 0xC0, 0x64, 0x00, 0x93, 0x12, 0x6C, 0x03, ++0x30, 0x0E, 0xC0, 0x17, 0x10, 0x13, 0x03, 0x7C, 0x83, 0xB0, 0x18, 0xC0, 0x3C, ++0x20, 0x9F, 0x00, 0xF4, 0x07, 0xF0, 0x5F, 0xC0, 0x75, 0x00, 0x97, 0x22, 0x04, ++0x2F, 0xB0, 0xBC, 0xC0, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x00, 0x87, 0x00, 0x0F, 0x80, 0x7E, 0x00, 0xF0, 0x21, 0xC0, 0x37, 0x00, 0xD7, ++0x80, 0x7C, 0x13, 0x70, 0x0D, 0xC0, 0x87, 0x00, 0x97, 0x02, 0x5C, 0x0A, 0xF0, ++0x0D, 0xE0, 0x17, 0x00, 0x9F, 0x20, 0x3C, 0x08, 0xF0, 0xC1, 0xC8, 0x37, 0x00, ++0x9F, 0x04, 0x7C, 0x03, 0xF1, 0x0D, 0xC0, 0xA7, 0x44, 0xDF, 0x02, 0x7C, 0x88, ++0xF2, 0x0D, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, ++0x2D, 0x00, 0x9F, 0x00, 0xEC, 0x42, 0xE0, 0x03, 0xE0, 0x3F, 0x00, 0xDF, 0x00, ++0xFC, 0x03, 0xF8, 0x0E, 0xD0, 0x2C, 0x02, 0x3F, 0x10, 0xCD, 0x07, 0x34, 0x0F, ++0xC1, 0x3C, 0x04, 0x3F, 0x00, 0xFC, 0x02, 0xB1, 0x8F, 0xC0, 0x3E, 0x00, 0xBF, ++0x00, 0xCC, 0x03, 0x30, 0x0D, 0xC0, 0x74, 0x40, 0xF7, 0x00, 0xFC, 0x17, 0x30, ++0x0F, 0x00, 0x10, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x20, 0xC6, ++0x08, 0x1D, 0x81, 0x44, 0x44, 0xD0, 0x11, 0x41, 0x37, 0x00, 0xDD, 0x00, 0x74, ++0x03, 0xD0, 0x0D, 0x40, 0xC4, 0x08, 0x19, 0x02, 0x4C, 0x0A, 0x10, 0x0D, 0x40, ++0x84, 0x00, 0x97, 0x03, 0x74, 0x06, 0xB8, 0x1D, 0x00, 0x34, 0x00, 0x8D, 0x01, ++0x54, 0x03, 0x10, 0x0D, 0x40, 0x24, 0x42, 0xD3, 0x09, 0x74, 0x05, 0x10, 0x05, ++0x48, 0x14, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x64, 0x00, ++0x9D, 0x01, 0x64, 0x04, 0xD0, 0x19, 0x40, 0x37, 0x00, 0xDD, 0x00, 0x54, 0x03, ++0xD0, 0x0D, 0x40, 0x34, 0x00, 0xCD, 0x03, 0x44, 0x19, 0x10, 0x0D, 0x50, 0x14, ++0x00, 0x18, 0x01, 0x74, 0x21, 0x10, 0x01, 0x00, 0x36, 0x00, 0x9D, 0x04, 0x44, ++0x03, 0x10, 0x0D, 0x40, 0x84, 0x40, 0xDD, 0x02, 0x74, 0x03, 0x10, 0x0D, 0x40, ++0x04, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x0D, ++0x01, 0x05, 0x00, 0xD1, 0x08, 0x48, 0x33, 0x80, 0xCD, 0x00, 0x34, 0x03, 0xD0, ++0x0C, 0x40, 0x00, 0x00, 0x8D, 0x00, 0x06, 0x00, 0x10, 0x0D, 0x60, 0x10, 0x10, ++0x85, 0x00, 0x34, 0x00, 0x91, 0x01, 0x40, 0x30, 0x00, 0x9D, 0x80, 0x16, 0x03, ++0x10, 0x0C, 0x50, 0x00, 0x00, 0x81, 0x00, 0x74, 0x00, 0x50, 0x18, 0x50, 0x41, ++0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x26, 0x00, 0x1F, 0x00, ++0x6C, 0x02, 0xF1, 0x01, 0x40, 0x3F, 0x00, 0xDF, 0x00, 0xDC, 0x03, 0xD0, 0x0F, ++0xC0, 0x34, 0x00, 0x5D, 0x00, 0x4C, 0x01, 0x30, 0x0D, 0xC0, 0x34, 0x00, 0x1F, ++0x00, 0x7C, 0x01, 0x11, 0x05, 0xC0, 0x3E, 0x00, 0x9F, 0x00, 0x4C, 0x03, 0x30, ++0x0D, 0xC0, 0x04, 0x00, 0xDF, 0x80, 0x7C, 0x00, 0x31, 0x0D, 0xC0, 0x00, 0xC0, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x0F, 0x00, 0x3F, 0x00, 0xFE, ++0x02, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x0F, 0x00, 0x3B, 0x00, 0xDC, 0x00, 0xF0, 0x0F, 0xC4, 0x3F, 0x08, 0x37, 0x00, ++0xBC, 0x00, 0xF2, 0x02, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, ++0xC0, 0x0F, 0x00, 0xF7, 0x40, 0xFC, 0x00, 0xB0, 0x0F, 0xC0, 0x16, 0x21, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x5F, 0x00, 0x73, 0x01, 0xCC, 0x07, ++0xF0, 0x1F, 0xC0, 0x3C, 0x01, 0xB3, 0x01, 0xAC, 0x05, 0xF0, 0x4F, 0xC0, 0x4D, ++0x08, 0x3F, 0x03, 0x4C, 0x04, 0xF0, 0x0F, 0xC0, 0x4F, 0x40, 0x33, 0x01, 0xFC, ++0x0C, 0x71, 0x90, 0xC0, 0x4C, 0x00, 0xA3, 0x01, 0xED, 0x04, 0xF0, 0x12, 0xC0, ++0x4F, 0x00, 0x3F, 0x02, 0xCE, 0x26, 0x34, 0x03, 0xC0, 0x0F, 0x08, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x53, 0x00, 0x51, 0x01, 0xEC, 0x07, 0xD0, ++0x1F, 0x40, 0x74, 0x00, 0x95, 0x01, 0x51, 0x06, 0xD0, 0x9F, 0x42, 0x44, 0x00, ++0x1D, 0x00, 0x4C, 0x04, 0xD0, 0x3F, 0x40, 0x47, 0x00, 0x11, 0x01, 0x74, 0x00, ++0x10, 0x45, 0x44, 0x45, 0x00, 0x11, 0x41, 0x44, 0x00, 0xD0, 0x11, 0x40, 0x47, ++0x00, 0x97, 0x82, 0x6C, 0x10, 0x10, 0x11, 0x48, 0x0F, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x11, 0xA0, 0x25, 0x00, 0x81, 0x00, 0x04, 0x03, 0x51, 0x0C, ++0x40, 0xB0, 0x00, 0x45, 0x00, 0x04, 0x01, 0x50, 0x0C, 0x40, 0x21, 0x00, 0x05, ++0x04, 0x24, 0x03, 0xD0, 0x2C, 0x40, 0x07, 0x00, 0x01, 0x00, 0x74, 0x10, 0xD0, ++0x09, 0x40, 0x35, 0x00, 0x95, 0x80, 0x14, 0x50, 0xD1, 0x00, 0x40, 0x01, 0x08, ++0x4D, 0x06, 0x44, 0x02, 0x10, 0x08, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA0, 0x27, 0x00, 0xC1, 0x00, 0x64, 0x03, 0xD0, 0x0D, 0x40, ++0x34, 0x00, 0x55, 0x06, 0x54, 0x02, 0xD0, 0x0D, 0x40, 0x44, 0x00, 0x0D, 0x81, ++0x44, 0x23, 0xD0, 0x0D, 0x40, 0x07, 0x00, 0x11, 0x04, 0x74, 0x46, 0x10, 0x0D, ++0x40, 0x35, 0x40, 0x15, 0x02, 0x50, 0x06, 0xD0, 0x11, 0x60, 0x07, 0x00, 0x95, ++0x08, 0x45, 0x06, 0x10, 0x11, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA8, 0x73, 0x00, 0x93, 0x02, 0x4C, 0x03, 0xF0, 0x0C, 0xD0, 0x34, ++0x80, 0xC7, 0x03, 0x6C, 0x1B, 0xF0, 0x0C, 0xC0, 0x65, 0x01, 0x9F, 0x01, 0x6C, ++0x4E, 0xF0, 0x0D, 0xC0, 0x83, 0x01, 0x13, 0x00, 0x3C, 0x04, 0x70, 0x3D, 0xC0, ++0xF5, 0x08, 0x87, 0x03, 0x54, 0x44, 0xF0, 0x31, 0xC1, 0x07, 0x11, 0x1F, 0x05, ++0x44, 0x06, 0x30, 0x31, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x07, 0x80, 0xFD, 0x40, 0xBF, 0x00, 0xFC, 0x03, 0xF2, 0x0F, 0xC0, 0x3B, 0x20, ++0xFF, 0x00, 0xE8, 0x96, 0xF0, 0x0F, 0xC0, 0x0F, 0x20, 0x3F, 0x00, 0xFC, 0x06, ++0xE0, 0x0D, 0xC4, 0x4E, 0x02, 0x3F, 0x41, 0xF4, 0x02, 0xF0, 0x2F, 0xC0, 0xBF, ++0x00, 0xBB, 0x02, 0xC4, 0x02, 0xD0, 0x03, 0x41, 0x0F, 0x00, 0x1F, 0x01, 0xFC, ++0x00, 0xF0, 0x03, 0xC4, 0x3F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x08, 0xA5, 0x00, 0x93, 0x02, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x6E, 0x0B, 0x30, 0x0D, 0xC0, 0xA4, 0x80, 0x9F, 0x02, 0x7C, 0x02, 0xF0, ++0x8D, 0xC2, 0x07, 0x02, 0x1E, 0x00, 0x7C, 0x18, 0xF0, 0x0D, 0xC0, 0x36, 0x01, ++0x9F, 0x06, 0x6C, 0x08, 0xF2, 0x81, 0xC8, 0x16, 0x44, 0x83, 0x02, 0x4D, 0x8A, ++0x30, 0x29, 0xC4, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0x24, 0x00, 0x91, 0x00, 0x74, 0x03, 0x50, 0x0D, 0x40, 0x3F, 0x00, 0xDD, 0x07, ++0x76, 0x1E, 0xF0, 0xAF, 0x40, 0x44, 0x00, 0x9F, 0x80, 0x74, 0x4F, 0xD0, 0x1F, ++0xC0, 0xC4, 0x00, 0x1F, 0x0C, 0x70, 0x02, 0xF0, 0x0C, 0x40, 0xF0, 0x08, 0x9D, ++0x02, 0x50, 0x02, 0xD2, 0x11, 0x50, 0x54, 0x04, 0x91, 0x09, 0x64, 0x02, 0x34, ++0x39, 0xC0, 0x6C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x22, ++0x00, 0xC1, 0x40, 0x24, 0x03, 0x10, 0x4C, 0x60, 0x33, 0x00, 0x4D, 0x04, 0x34, ++0x1E, 0x10, 0x1C, 0x40, 0x40, 0x00, 0x89, 0x00, 0x36, 0x11, 0xD0, 0x4C, 0x60, ++0x02, 0x04, 0x09, 0x00, 0x34, 0x0C, 0xDA, 0x00, 0x00, 0x82, 0x02, 0x08, 0x00, ++0x14, 0x00, 0xD0, 0x20, 0x40, 0x40, 0x00, 0x09, 0x83, 0x64, 0x32, 0x90, 0xC8, ++0x40, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x08, 0x7A, 0x40, ++0xE1, 0x01, 0x34, 0x07, 0x50, 0x1E, 0x40, 0x7B, 0x00, 0x6D, 0x81, 0xF6, 0x26, ++0xD0, 0x1C, 0x40, 0x48, 0x00, 0x25, 0x49, 0xB6, 0x25, 0xD0, 0x9E, 0x40, 0x48, ++0x00, 0x2D, 0x01, 0xB4, 0x05, 0xD1, 0x53, 0x40, 0x4A, 0x01, 0x7D, 0x81, 0x94, ++0x24, 0xD8, 0x12, 0x60, 0x4C, 0x80, 0x69, 0x21, 0xA4, 0x24, 0x10, 0x13, 0x40, ++0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0xA2, 0x00, 0x81, ++0x00, 0x2C, 0x23, 0x10, 0x0C, 0xC0, 0x33, 0x00, 0x4F, 0x00, 0x34, 0x22, 0x10, ++0x0C, 0xC1, 0x60, 0x05, 0x89, 0x07, 0x3C, 0x15, 0xF0, 0x8C, 0xC0, 0x03, 0x02, ++0x0F, 0x01, 0x38, 0x46, 0xF0, 0x50, 0xE8, 0x42, 0x10, 0xCD, 0x14, 0x14, 0x23, ++0xF0, 0x80, 0xC0, 0x00, 0x00, 0xCB, 0x10, 0x4C, 0x23, 0xB2, 0x2D, 0xE0, 0x4A, ++0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x2D, 0x00, 0xFF, 0x80, ++0xFC, 0x07, 0x70, 0x1F, 0xC0, 0x3F, 0x00, 0x7F, 0x08, 0xFC, 0x22, 0x70, 0x0D, ++0xD0, 0x27, 0x02, 0xBE, 0x00, 0xFC, 0x23, 0xF0, 0x8F, 0xC0, 0x0F, 0x02, 0x35, ++0x40, 0xFC, 0x03, 0x70, 0x0F, 0xE8, 0x3D, 0x00, 0x7F, 0x00, 0xDC, 0x23, 0xF0, ++0x03, 0xC8, 0x09, 0x02, 0xF7, 0x00, 0xDC, 0x23, 0xD0, 0x83, 0xD0, 0x0B, 0x60, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x67, 0x00, 0x93, 0x00, 0x7C, ++0x23, 0xF0, 0x1D, 0xD0, 0x34, 0x00, 0x57, 0x00, 0x7C, 0x03, 0x30, 0xDC, 0xC0, ++0x65, 0x20, 0x9B, 0x20, 0x6C, 0x04, 0xB0, 0x9D, 0xC0, 0x04, 0x00, 0x1F, 0x80, ++0x7C, 0x07, 0xBC, 0x01, 0xC0, 0x07, 0x00, 0x5F, 0x01, 0x6E, 0x07, 0x39, 0x01, ++0xC0, 0x07, 0x80, 0x5F, 0x00, 0x4C, 0x01, 0x33, 0x09, 0xC0, 0x40, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x39, 0x00, 0xAB, 0x00, 0xB4, 0x13, ++0xD0, 0x2C, 0x40, 0x38, 0x11, 0x61, 0x00, 0x8C, 0x02, 0x18, 0x4E, 0x41, 0x28, ++0x30, 0x31, 0x00, 0x84, 0x03, 0x11, 0xCC, 0x40, 0x08, 0x88, 0x2D, 0x00, 0xB4, ++0x03, 0x10, 0x0A, 0x42, 0x3B, 0x80, 0x6D, 0x00, 0x94, 0x03, 0x14, 0x02, 0x40, ++0x0B, 0x00, 0x7D, 0xC0, 0xC4, 0x01, 0xB0, 0x0A, 0x40, 0x4D, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x69, 0x00, 0xA1, 0x03, 0x94, 0x07, 0x52, ++0x5E, 0x60, 0x70, 0x03, 0x65, 0x43, 0xB4, 0x07, 0x90, 0x1E, 0x40, 0x6D, 0x00, ++0xA5, 0x01, 0x84, 0x04, 0x10, 0x1E, 0x40, 0xC9, 0x00, 0x25, 0x01, 0xB4, 0x07, ++0x10, 0x16, 0x44, 0x4B, 0x10, 0xFD, 0x01, 0x94, 0x87, 0x10, 0x16, 0x44, 0x5B, ++0x20, 0xED, 0x01, 0xA4, 0x05, 0x10, 0x1C, 0x64, 0x10, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x16, 0x28, 0x23, 0x04, 0x89, 0x00, 0x34, 0x03, 0xD0, 0x0C, ++0x40, 0x30, 0x00, 0x41, 0x45, 0x30, 0x2E, 0x10, 0x0C, 0x40, 0x30, 0x00, 0xC5, ++0x20, 0x04, 0x1F, 0x10, 0x0C, 0x50, 0xF1, 0x01, 0xCD, 0x48, 0x34, 0x0F, 0x12, ++0x3C, 0x41, 0xF3, 0x00, 0xCD, 0x22, 0x14, 0x13, 0x10, 0x1C, 0x40, 0xF3, 0x0C, ++0xCD, 0x07, 0x24, 0x4F, 0x10, 0x4C, 0x48, 0x59, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x17, 0xA0, 0x9F, 0x00, 0x73, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, ++0x14, 0x00, 0x77, 0x00, 0xB4, 0x01, 0xB5, 0x05, 0xC0, 0xDD, 0x01, 0x77, 0x08, ++0xEC, 0x0D, 0xB0, 0x05, 0xE0, 0xDD, 0x00, 0x7F, 0x0B, 0xFC, 0x15, 0xB1, 0x37, ++0xC1, 0xDB, 0x16, 0x7F, 0x02, 0xDD, 0x09, 0x30, 0x27, 0xC1, 0x5F, 0x14, 0x7F, ++0x04, 0xE4, 0x1D, 0x10, 0x17, 0x45, 0x5C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x80, 0x05, 0x00, 0x1F, 0x24, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x1F, 0x80, 0x4C, 0x10, 0xF0, 0x21, 0xC0, 0x07, 0x04, 0x12, 0x00, 0x7D, ++0x20, 0xF0, 0x01, 0x00, 0x86, 0x00, 0x1F, 0x00, 0x7C, 0x48, 0xF2, 0x01, 0xC0, ++0x87, 0x00, 0x1F, 0x0A, 0x64, 0x20, 0xF0, 0x01, 0xC1, 0x87, 0x00, 0x1F, 0x40, ++0x5D, 0x00, 0xF4, 0x01, 0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x00, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0xF0, 0x89, 0xC0, 0x27, 0x00, ++0x93, 0x80, 0x7C, 0x0A, 0x30, 0x19, 0x40, 0x27, 0x00, 0x9F, 0x00, 0x6C, 0x02, ++0xF0, 0x19, 0xC8, 0x26, 0x00, 0x93, 0x01, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x93, 0x10, 0x5C, 0x02, 0xF0, 0x19, 0xC0, 0x24, 0x00, 0x9F, 0x02, 0x6C, ++0x0A, 0x30, 0x58, 0xC4, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x20, 0x26, 0x00, 0x8D, 0x00, 0xC4, 0x02, 0xD8, 0x1B, 0x40, 0x27, 0x00, 0x95, ++0x01, 0x74, 0x02, 0x50, 0x09, 0x44, 0x27, 0x00, 0x87, 0x00, 0x44, 0x06, 0xD0, ++0x29, 0x44, 0xE3, 0x1C, 0x91, 0x01, 0x74, 0x12, 0xD0, 0x09, 0x4A, 0x67, 0x00, ++0x95, 0x22, 0x74, 0x82, 0xD0, 0x18, 0x40, 0x24, 0x08, 0x9C, 0x03, 0x04, 0x42, ++0x14, 0x19, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, ++0x24, 0x00, 0xDD, 0x00, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x23, 0x00, 0x91, 0x04, ++0x54, 0x02, 0x10, 0x69, 0x44, 0x27, 0x80, 0x9D, 0x00, 0x44, 0x06, 0xD0, 0x89, ++0x41, 0x27, 0x41, 0xD1, 0x0A, 0x74, 0x02, 0xD2, 0x0D, 0x48, 0x37, 0x02, 0x91, ++0x82, 0x74, 0x02, 0x52, 0x89, 0x00, 0x24, 0x00, 0x8D, 0x00, 0x42, 0x03, 0x10, ++0x09, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0xA0, ++0x00, 0x9D, 0x02, 0x04, 0x0A, 0xD0, 0x08, 0x40, 0xA3, 0x00, 0x85, 0x20, 0x74, ++0x03, 0x50, 0x08, 0x48, 0x23, 0x00, 0x95, 0x08, 0x04, 0x83, 0xD2, 0x08, 0x40, ++0x23, 0x00, 0x81, 0x00, 0x34, 0x22, 0xD0, 0x88, 0x40, 0x23, 0x00, 0x85, 0x80, ++0x34, 0x22, 0xD0, 0x09, 0x50, 0x30, 0x90, 0xCD, 0x68, 0x45, 0xA2, 0x10, 0x48, ++0x50, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x02, 0x00, ++0x1F, 0x00, 0x4D, 0x04, 0xD0, 0x11, 0xC0, 0x07, 0x05, 0x13, 0x80, 0x5C, 0x80, ++0x30, 0x41, 0xC1, 0x07, 0x20, 0x1F, 0x02, 0x4D, 0x00, 0xF0, 0x41, 0xC1, 0x07, ++0x00, 0x13, 0x80, 0x38, 0x08, 0xF0, 0x21, 0xC0, 0x17, 0x20, 0x13, 0x00, 0x3E, ++0x08, 0x70, 0x01, 0xC0, 0x04, 0x08, 0x1F, 0x16, 0x4C, 0x08, 0x30, 0x05, 0xC0, ++0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA8, 0x7F, 0x00, 0xBF, ++0x01, 0x7C, 0x0E, 0xD0, 0x29, 0xC0, 0x67, 0x10, 0xBF, 0x00, 0xBC, 0x02, 0xF0, ++0x09, 0xC0, 0x2B, 0x00, 0xB7, 0x04, 0x9C, 0x02, 0xF2, 0x09, 0xC0, 0x3F, 0x20, ++0xFF, 0x40, 0xFC, 0x12, 0xD0, 0x4B, 0xC0, 0x2F, 0x10, 0xAF, 0x80, 0xFE, 0x12, ++0xF0, 0x0B, 0xC8, 0x2F, 0x00, 0xBE, 0x44, 0xDC, 0x13, 0xF0, 0x8B, 0xC0, 0x77, ++0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x27, 0x00, 0x9F, 0x42, ++0x7C, 0x36, 0xF0, 0x1B, 0xC1, 0x27, 0x02, 0xBF, 0x00, 0xDC, 0x02, 0xF2, 0x4B, ++0xC1, 0x2F, 0x00, 0xDB, 0x80, 0xCC, 0x02, 0xF0, 0x0B, 0xC8, 0x2F, 0x00, 0xBF, ++0x00, 0xC4, 0x22, 0xF0, 0x09, 0x40, 0x28, 0x00, 0xBE, 0x00, 0x4C, 0x82, 0x30, ++0x0B, 0xC0, 0x2B, 0x08, 0xBF, 0x00, 0xCC, 0x02, 0x30, 0x0B, 0xC0, 0x74, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x10, 0x47, 0x05, 0x1D, 0xC1, 0x34, ++0x0C, 0xD0, 0x21, 0x40, 0x43, 0x20, 0x1D, 0x00, 0x44, 0x00, 0xD0, 0x01, 0x40, ++0x07, 0x00, 0x1D, 0x70, 0x44, 0x00, 0xD0, 0x81, 0x40, 0x07, 0x00, 0x1D, 0x00, ++0x44, 0x11, 0x72, 0x01, 0x41, 0x04, 0x30, 0x1D, 0x20, 0x54, 0x50, 0x10, 0x01, ++0x40, 0x17, 0x00, 0x1D, 0x00, 0x0C, 0x00, 0x10, 0x01, 0x44, 0x61, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x21, 0x00, 0x8D, 0x00, 0x34, 0x32, ++0xD0, 0x08, 0x40, 0x23, 0x03, 0x8D, 0x00, 0x05, 0x02, 0xD0, 0x08, 0x40, 0x23, ++0x00, 0x89, 0x04, 0x05, 0x02, 0xD0, 0x08, 0x08, 0x33, 0x00, 0x9D, 0x00, 0x05, ++0x12, 0xD8, 0x48, 0x40, 0x20, 0x00, 0x8D, 0x00, 0x14, 0x92, 0x10, 0x08, 0x60, ++0x23, 0x00, 0x8D, 0x00, 0x04, 0x82, 0x10, 0x09, 0x40, 0x4A, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x25, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, ++0x09, 0x40, 0x27, 0x08, 0xDD, 0x00, 0x44, 0x02, 0xD0, 0x0D, 0x40, 0x67, 0x20, ++0x8D, 0x18, 0x44, 0x02, 0xD0, 0x09, 0x44, 0x66, 0x10, 0x9D, 0x00, 0x44, 0x02, ++0x50, 0x28, 0x54, 0xB4, 0x02, 0x9D, 0x10, 0x55, 0x02, 0x10, 0x09, 0x41, 0x27, ++0x00, 0xDD, 0x00, 0x04, 0x02, 0x90, 0x19, 0x60, 0x63, 0x28, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0xA8, 0xEF, 0x00, 0xBF, 0x0D, 0xFC, 0x82, 0xF2, 0x09, ++0xC0, 0x2F, 0x00, 0x9F, 0x13, 0x4C, 0x02, 0xF0, 0x09, 0xC4, 0xE7, 0x24, 0x9B, ++0x81, 0x44, 0x46, 0xF2, 0x09, 0xC8, 0x67, 0x20, 0x9F, 0x00, 0x4C, 0x02, 0xF0, ++0x09, 0xC0, 0xE4, 0x00, 0x9F, 0x20, 0x54, 0x1A, 0x30, 0x29, 0xC0, 0x27, 0x00, ++0x9F, 0x12, 0x4C, 0x0E, 0x34, 0x59, 0xC0, 0x16, 0x00, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x80, 0xE5, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x05, 0x6C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x01, ++0x7C, 0x62, 0xE0, 0x09, 0x00, 0x27, 0x00, 0x9F, 0x02, 0x7C, 0x02, 0x72, 0x49, ++0xC0, 0x27, 0x00, 0x9F, 0x03, 0x7C, 0x22, 0xD4, 0x99, 0xC0, 0x27, 0x01, 0x9D, ++0x13, 0x7F, 0xD2, 0x70, 0x09, 0xC1, 0x59, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x85, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xB0, 0x01, 0xD0, 0x06, ++0x00, 0x13, 0x02, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x87, 0x80, 0x1F, 0x02, 0x5C, ++0x88, 0x30, 0x01, 0xC5, 0x85, 0x40, 0x13, 0x30, 0x4C, 0x00, 0xF0, 0x21, 0xC0, ++0x07, 0x01, 0x13, 0x23, 0x5C, 0x08, 0xF0, 0x01, 0xC1, 0x05, 0x14, 0x03, 0x00, ++0x4C, 0x00, 0x21, 0x01, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0xA0, 0x14, 0x00, 0x5D, 0x00, 0x74, 0x01, 0x58, 0x77, 0x40, 0x14, 0x00, ++0x65, 0x02, 0xD8, 0x01, 0xD0, 0x17, 0x40, 0x17, 0x80, 0x5C, 0x00, 0xD4, 0x01, ++0x11, 0x07, 0x01, 0x9D, 0x00, 0x61, 0x02, 0xC4, 0x85, 0x32, 0x05, 0xC0, 0x9D, ++0x40, 0x61, 0x10, 0x48, 0x01, 0xD1, 0x07, 0x40, 0x5F, 0x04, 0x71, 0x00, 0xD4, ++0x81, 0x50, 0x07, 0x48, 0x43, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x10, 0x78, 0x40, 0x30, 0x00, 0x41, ++0x04, 0x24, 0x02, 0xD0, 0xDC, 0x40, 0x33, 0x20, 0xCD, 0x40, 0x14, 0x03, 0x10, ++0x0C, 0x0A, 0xB0, 0x0C, 0xC1, 0x08, 0x05, 0x07, 0xD0, 0x0C, 0x40, 0x71, 0x00, ++0xC1, 0x80, 0x50, 0x83, 0xD0, 0x0C, 0x40, 0x31, 0x00, 0xC1, 0x03, 0x04, 0x2B, ++0x1C, 0x2D, 0x40, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, ++0x38, 0x01, 0xED, 0x04, 0xB4, 0x27, 0x58, 0x1A, 0x40, 0x78, 0x01, 0xF5, 0x00, ++0x94, 0x02, 0xD8, 0x0A, 0x40, 0x3B, 0x00, 0xED, 0x0C, 0x94, 0x0C, 0x10, 0x1A, ++0x4A, 0x7D, 0x00, 0xE1, 0x20, 0x84, 0x43, 0x00, 0x4E, 0x40, 0x4D, 0x24, 0xF1, ++0x40, 0xA4, 0x03, 0xD0, 0x0E, 0x40, 0x7F, 0x08, 0xE1, 0x82, 0x84, 0x01, 0x10, ++0x06, 0x44, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0xF8, ++0x00, 0xEF, 0x03, 0xBC, 0x07, 0x30, 0x1A, 0xC2, 0x78, 0x01, 0x63, 0x01, 0xAC, ++0x06, 0xF0, 0x1E, 0xC0, 0x7B, 0x00, 0xFD, 0x31, 0x96, 0x04, 0x30, 0x1A, 0x40, ++0x79, 0x00, 0x63, 0x01, 0x8C, 0x07, 0xF0, 0x1E, 0xC1, 0x49, 0x20, 0xE3, 0x01, ++0x9E, 0x17, 0xF2, 0x1E, 0xC8, 0x79, 0x40, 0xF3, 0x01, 0x8D, 0x06, 0x30, 0x1E, ++0xC0, 0x53, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x35, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x08, 0xC0, 0x37, 0x10, 0xCF, 0x00, 0x7C, 0x02, ++0xF1, 0x01, 0xC0, 0x37, 0x00, 0xDD, 0x02, 0x2C, 0x00, 0xF0, 0x08, 0xE0, 0x33, ++0x00, 0x4F, 0x00, 0x7C, 0x01, 0xA2, 0x4D, 0xC0, 0x05, 0x20, 0xCF, 0x20, 0x5C, ++0x1B, 0xF2, 0x09, 0xE0, 0x37, 0x00, 0xDD, 0x00, 0x7C, 0x00, 0xF0, 0x09, 0xC0, ++0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x79, 0x00, 0xE3, ++0x01, 0xCC, 0x13, 0xF8, 0x8F, 0xC0, 0x7D, 0x04, 0x7F, 0x09, 0xCC, 0x06, 0xF0, ++0x9F, 0xC0, 0x7F, 0x02, 0xF7, 0x01, 0x3C, 0x24, 0x70, 0x9B, 0xC0, 0x47, 0x22, ++0xBF, 0x0D, 0xCC, 0x06, 0xB0, 0x9D, 0x41, 0x4F, 0x02, 0xBF, 0x01, 0xCD, 0x4F, ++0x30, 0x9E, 0xC8, 0x7C, 0x12, 0x3B, 0x09, 0xCC, 0x07, 0x34, 0x97, 0xD8, 0x18, ++0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x18, 0x38, 0x00, 0xE1, 0x18, ++0x84, 0x03, 0xD8, 0x0E, 0x40, 0x38, 0x20, 0xED, 0x0C, 0xAC, 0x02, 0xD0, 0x0A, ++0x44, 0x33, 0x00, 0xCD, 0x08, 0xB4, 0x24, 0x10, 0xCA, 0x08, 0x7B, 0x01, 0x4D, ++0x98, 0x44, 0x43, 0x10, 0x5E, 0x40, 0x03, 0x03, 0xAD, 0x04, 0x94, 0x23, 0x10, ++0x0E, 0x42, 0x29, 0x03, 0x2D, 0x0C, 0xFC, 0x11, 0x10, 0x86, 0x40, 0x54, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7D, 0x00, 0xF1, 0x01, 0x84, ++0x27, 0xD0, 0xC8, 0x40, 0x79, 0x02, 0x7D, 0x00, 0xA6, 0x02, 0x50, 0x0A, 0x48, ++0x3B, 0x80, 0xED, 0x00, 0xF4, 0x00, 0xD0, 0x02, 0x0A, 0x09, 0x08, 0x3D, 0x06, ++0xA6, 0x22, 0x10, 0x0E, 0x44, 0x0B, 0x14, 0xBD, 0x00, 0xC6, 0x03, 0x10, 0x0E, ++0x40, 0x19, 0x10, 0x2D, 0x40, 0xC4, 0x02, 0x12, 0x06, 0x42, 0x60, 0x02, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x31, 0x00, 0xC1, 0x00, 0x04, 0x03, ++0xD8, 0x08, 0x40, 0x30, 0x00, 0xCD, 0x00, 0x24, 0x22, 0xD0, 0x00, 0x40, 0x33, ++0x00, 0xCD, 0x20, 0x34, 0x4C, 0x90, 0x00, 0x40, 0xB2, 0x01, 0x4D, 0x01, 0x24, ++0x85, 0x9A, 0x2D, 0x48, 0xC3, 0x00, 0x8D, 0x10, 0x14, 0x9B, 0x10, 0x28, 0x41, ++0x81, 0x00, 0x8D, 0x08, 0x05, 0x08, 0x10, 0xB8, 0x40, 0x08, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x35, 0x41, 0xD3, 0x01, 0x4D, 0x03, 0xD0, ++0x09, 0xC0, 0x35, 0x00, 0x5F, 0x00, 0x2C, 0x03, 0x70, 0x05, 0xC0, 0x77, 0x04, ++0xFF, 0x11, 0x7C, 0x1C, 0xF0, 0x01, 0xC0, 0x35, 0x08, 0xDF, 0x02, 0x6D, 0x09, ++0x34, 0x0F, 0xC0, 0xC7, 0x20, 0xCD, 0x81, 0xC4, 0x03, 0x30, 0x2D, 0xC0, 0x21, ++0x00, 0xDB, 0x2B, 0x44, 0x0B, 0x30, 0xB9, 0xC0, 0x74, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xDF, 0x00, 0x3C, 0x03, 0xF0, 0x29, ++0xC0, 0x37, 0x00, 0x5F, 0x42, 0x7C, 0x4A, 0xF0, 0x05, 0xC0, 0x27, 0x91, 0xDF, ++0x24, 0x7C, 0x00, 0x70, 0x09, 0xC0, 0x37, 0x0A, 0xDF, 0x02, 0x5C, 0x42, 0x70, ++0xCD, 0xC0, 0x07, 0x04, 0x9F, 0x01, 0x6C, 0x03, 0xF0, 0x25, 0x40, 0x07, 0x01, ++0xDF, 0x02, 0x7C, 0x09, 0xF0, 0x29, 0xC8, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x08, 0x3F, 0x00, 0xFF, 0x00, 0xC8, 0x03, 0x30, 0x1B, 0xC0, ++0x3F, 0x20, 0x7F, 0x41, 0xFC, 0x27, 0x30, 0x46, 0xC0, 0x7E, 0x01, 0xFF, 0x20, ++0xCC, 0x0C, 0x70, 0x03, 0xC0, 0x0F, 0x00, 0xBF, 0x08, 0xF8, 0x05, 0xB4, 0x0F, ++0xC0, 0x0D, 0x08, 0xFF, 0x00, 0xDC, 0x03, 0xF0, 0x0F, 0xC0, 0x2F, 0x10, 0xE7, ++0x01, 0xCC, 0x46, 0xF0, 0x09, 0xC0, 0x07, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x85, 0x20, 0x36, 0x00, 0xDD, 0x00, 0x54, 0x03, 0x50, 0x19, 0x40, 0x37, ++0x00, 0x1D, 0x02, 0x74, 0x0D, 0x10, 0x15, 0x40, 0x24, 0x00, 0xDD, 0x00, 0x44, ++0x0C, 0xD1, 0x19, 0xC0, 0x07, 0x01, 0x9D, 0x02, 0x74, 0x08, 0x90, 0x0D, 0x40, ++0xC4, 0x00, 0x9D, 0x03, 0x6C, 0x03, 0xD2, 0xF5, 0x40, 0x47, 0x00, 0x11, 0x01, ++0x44, 0x02, 0xD0, 0x39, 0x48, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0xA0, 0x34, 0x00, 0xCD, 0x00, 0x54, 0x03, 0x90, 0x8D, 0x41, 0x37, 0x00, ++0x5D, 0x08, 0x74, 0x43, 0x50, 0x0D, 0x40, 0x36, 0x00, 0xC9, 0x00, 0x44, 0xC0, ++0xD8, 0x11, 0x00, 0x07, 0x02, 0x9D, 0x02, 0x36, 0x18, 0x12, 0x0D, 0x40, 0x46, ++0x00, 0x9D, 0x03, 0x60, 0x03, 0xD0, 0x0D, 0x40, 0xE7, 0x00, 0x11, 0x04, 0x44, ++0x9B, 0xD0, 0x11, 0x4D, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x28, 0x30, 0x00, 0xCD, 0x00, 0x14, 0x03, 0x50, 0x04, 0x40, 0x32, 0x00, 0xCD, ++0x00, 0x34, 0x02, 0x56, 0x0C, 0x42, 0x20, 0x80, 0xCD, 0x00, 0x05, 0x10, 0xD0, ++0x18, 0x40, 0x31, 0x09, 0x4D, 0x20, 0x34, 0x22, 0x11, 0x6C, 0x50, 0x02, 0x02, ++0x8D, 0x00, 0x24, 0x03, 0xD2, 0x0C, 0x42, 0x03, 0x80, 0x01, 0x00, 0x04, 0x00, ++0xD0, 0x08, 0x4A, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB0, ++0x3E, 0x08, 0xFF, 0x00, 0xDC, 0x03, 0x30, 0x0D, 0xC0, 0x3F, 0x00, 0x5F, 0x00, ++0x74, 0x03, 0x70, 0x09, 0xC0, 0x36, 0x10, 0xFB, 0x00, 0x4C, 0x50, 0x71, 0x01, ++0x64, 0x07, 0x00, 0x9F, 0x08, 0x7C, 0x00, 0xB0, 0x6F, 0xC0, 0x07, 0xA0, 0x9F, ++0x80, 0xDC, 0x03, 0xF0, 0x0D, 0xC0, 0x07, 0x40, 0x47, 0x80, 0x4E, 0x01, 0xF2, ++0x01, 0xC0, 0x07, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA0, 0x3F, ++0x00, 0xFF, 0x00, 0xFC, 0x03, 0x70, 0x07, 0xC0, 0x3F, 0x00, 0xAF, 0x00, 0xFC, ++0x01, 0xB0, 0x03, 0xC0, 0x2F, 0x04, 0xFC, 0x10, 0xFC, 0x40, 0xF0, 0x03, 0xC0, ++0x8F, 0x08, 0x2F, 0x00, 0xFC, 0x10, 0xD2, 0x8F, 0xC0, 0x0D, 0x01, 0x2E, 0x00, ++0xBC, 0x03, 0xE0, 0x0F, 0xC2, 0x0F, 0x00, 0x3F, 0x00, 0xFD, 0x00, 0xF0, 0x0B, ++0xC2, 0x17, 0x64, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x3F, 0x00, ++0xA3, 0x40, 0xCC, 0x02, 0xF0, 0x0B, 0xC0, 0x3F, 0x11, 0xB3, 0x20, 0xFC, 0x26, ++0xB0, 0x9F, 0xD2, 0x2C, 0x00, 0xFF, 0x21, 0xEC, 0x10, 0xB2, 0x8F, 0xC8, 0x3C, ++0x12, 0xFF, 0x04, 0xEC, 0x20, 0x72, 0x0F, 0xC0, 0x7F, 0x02, 0xF3, 0x03, 0xED, ++0x1B, 0xB0, 0x9B, 0xC0, 0x7C, 0x0A, 0xDF, 0x01, 0xFC, 0x1A, 0x34, 0x49, 0xC0, ++0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3F, 0x00, 0xB1, ++0x01, 0x44, 0x82, 0x70, 0x01, 0x02, 0x3F, 0x22, 0x91, 0x00, 0x34, 0x13, 0x10, ++0x4C, 0x48, 0xB4, 0x01, 0xD1, 0x01, 0x54, 0x24, 0xD0, 0x6F, 0x60, 0xBC, 0x01, ++0xFD, 0x09, 0x44, 0x18, 0x10, 0x9F, 0x40, 0x33, 0x01, 0xD1, 0x00, 0x84, 0x1B, ++0x14, 0x48, 0x50, 0x34, 0x21, 0xDD, 0x04, 0x74, 0x12, 0x11, 0x19, 0x40, 0x0D, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x31, 0x00, 0x81, 0x00, ++0x04, 0x02, 0xD0, 0x08, 0x40, 0x33, 0x20, 0xC5, 0x20, 0x14, 0x07, 0x50, 0x0C, ++0x40, 0x81, 0x04, 0xC5, 0x00, 0x04, 0x00, 0xD0, 0x6C, 0x48, 0xB0, 0x01, 0xCD, ++0x00, 0x24, 0x1C, 0x10, 0x0C, 0x40, 0x33, 0x00, 0xC1, 0x04, 0x04, 0x0B, 0x50, ++0x0D, 0x40, 0x30, 0x01, 0xCD, 0x14, 0x34, 0x18, 0x10, 0x81, 0x40, 0x5C, 0x80, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x37, 0x00, 0x91, 0x41, 0x44, ++0x0E, 0x52, 0x11, 0x45, 0x37, 0x10, 0xD5, 0x43, 0x74, 0x07, 0x50, 0x0D, 0x44, ++0x55, 0x00, 0xD5, 0x04, 0x56, 0x88, 0xD0, 0x0C, 0x40, 0x34, 0x00, 0xDD, 0x00, ++0x24, 0x02, 0x13, 0x0D, 0x40, 0x37, 0x80, 0xC1, 0x01, 0x44, 0x03, 0x50, 0x0D, ++0x40, 0x34, 0x00, 0xDD, 0x80, 0x74, 0x06, 0x10, 0x11, 0x40, 0x1D, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x37, 0x00, 0x93, 0x01, 0x4D, 0x04, ++0xF0, 0x11, 0xC4, 0x37, 0xC0, 0xD7, 0x03, 0x7C, 0x07, 0xF0, 0x8D, 0xC0, 0xC5, ++0x00, 0xDF, 0x01, 0x4C, 0x0C, 0xB2, 0x0D, 0x40, 0x34, 0x00, 0xDF, 0x00, 0x6C, ++0x01, 0x70, 0x0D, 0xC0, 0x77, 0x0A, 0xD3, 0x80, 0x6C, 0x03, 0xF0, 0x08, 0xC4, ++0x34, 0x00, 0xDF, 0x00, 0x7C, 0x0E, 0x30, 0x39, 0xC0, 0x82, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x3D, 0x10, 0xEF, 0x00, 0xFC, 0x80, 0x70, ++0x03, 0xC0, 0x3F, 0x00, 0xFB, 0x80, 0xF8, 0x03, 0xB4, 0x0F, 0xC0, 0x1A, 0x00, ++0xFB, 0x00, 0x5C, 0x22, 0xF0, 0x0F, 0xC2, 0x37, 0x30, 0xEF, 0x00, 0x5C, 0x0D, ++0xF3, 0x0F, 0xC0, 0x7F, 0x40, 0xFF, 0x80, 0xDC, 0x03, 0xB0, 0x0B, 0xC0, 0x3F, ++0x20, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x0F, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x0A, 0x93, 0x00, 0x4C, 0x0A, 0xF2, 0x69, ++0xC0, 0x33, 0x20, 0xDF, 0x02, 0x5D, 0x83, 0xF0, 0xCD, 0xC0, 0x84, 0x00, 0xD3, ++0x01, 0x7C, 0x09, 0x70, 0x0D, 0xC0, 0x34, 0x40, 0xD3, 0x84, 0x7C, 0x81, 0x30, ++0x8D, 0xC0, 0x35, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0x70, 0x09, 0xC0, 0x34, 0x00, ++0xDB, 0x00, 0x7C, 0x08, 0xF0, 0x09, 0xC0, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0xA0, 0xF8, 0x02, 0x51, 0x20, 0x44, 0x02, 0xD0, 0x09, 0x45, ++0x3F, 0x00, 0xDD, 0x01, 0x7C, 0x83, 0x10, 0x3D, 0x40, 0x14, 0x08, 0xC0, 0x20, ++0x74, 0x03, 0x12, 0xBF, 0x40, 0xFC, 0x02, 0xF1, 0x00, 0x74, 0x83, 0x10, 0x1F, ++0x40, 0x34, 0x00, 0xD1, 0x00, 0xF4, 0x03, 0x10, 0x09, 0x40, 0x34, 0x80, 0xD1, ++0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x20, 0x30, 0x00, 0x81, 0x12, 0x04, 0x4C, 0xD9, 0x38, 0x40, 0x33, ++0x00, 0xCD, 0x09, 0x54, 0x03, 0x10, 0x2D, 0x40, 0x20, 0x08, 0xC1, 0x00, 0x34, ++0x07, 0x11, 0xAC, 0x48, 0xB1, 0x00, 0xC1, 0x01, 0x34, 0x82, 0x10, 0x1C, 0x41, ++0x36, 0x00, 0xC9, 0x20, 0x74, 0x03, 0x50, 0x08, 0x40, 0x30, 0x00, 0xC1, 0x00, ++0x74, 0x00, 0xD0, 0x01, 0x60, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x00, 0x70, 0x00, 0xA1, 0x89, 0x84, 0x07, 0xD8, 0x1E, 0x40, 0x7B, 0x02, ++0xFD, 0x09, 0xB4, 0x07, 0x12, 0x1E, 0x40, 0x68, 0x00, 0xE1, 0x81, 0xB4, 0x07, ++0x10, 0x1E, 0x40, 0x79, 0x05, 0xE1, 0x11, 0xB4, 0x27, 0x10, 0x1C, 0x40, 0xFA, ++0x00, 0xE9, 0x81, 0xB4, 0x07, 0x10, 0x1A, 0x40, 0x78, 0x00, 0xE8, 0x0B, 0xB4, ++0x84, 0xD0, 0x1A, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x18, 0x30, 0x00, 0x83, 0x20, 0x0C, 0x41, 0xF0, 0x8C, 0xC4, 0x33, 0x20, 0x4F, ++0x00, 0x1D, 0x23, 0x70, 0x8C, 0xC0, 0x84, 0x40, 0xC3, 0x00, 0x3C, 0x43, 0x74, ++0x0D, 0xC0, 0x31, 0x00, 0xC3, 0x00, 0x3C, 0x00, 0x30, 0x0C, 0xD0, 0x33, 0x00, ++0xCA, 0x08, 0x3C, 0x03, 0x74, 0x0C, 0xD0, 0x34, 0x00, 0xC3, 0x1D, 0x3C, 0x08, ++0xF0, 0x70, 0xC8, 0x4B, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, ++0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x04, 0x6F, 0x00, ++0xFC, 0xA3, 0x70, 0x0F, 0xE0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x2F, ++0xC1, 0x3E, 0x0D, 0xFF, 0x00, 0xFE, 0x03, 0xF2, 0x0F, 0xC0, 0x3D, 0x00, 0xF7, ++0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xF5, 0x28, 0xFC, 0x00, 0xF0, ++0x83, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, ++0x01, 0xB3, 0x02, 0x4D, 0x01, 0xF0, 0x05, 0xC0, 0xB7, 0x00, 0xD3, 0x80, 0x6C, ++0x03, 0xF2, 0x0D, 0xC2, 0x17, 0x00, 0xDF, 0x00, 0x7C, 0x00, 0x30, 0x2D, 0xC0, ++0xB4, 0x04, 0xD3, 0x04, 0x7C, 0x86, 0x30, 0x6D, 0xC0, 0x77, 0x00, 0xD3, 0x40, ++0x7C, 0x53, 0xB0, 0x09, 0xC0, 0x37, 0x00, 0xDF, 0x01, 0x44, 0x82, 0xF0, 0x11, ++0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x3D, 0x05, ++0xE1, 0x10, 0x84, 0x01, 0xD0, 0x06, 0x40, 0x3F, 0x04, 0xE5, 0x00, 0x84, 0x03, ++0xD0, 0x0E, 0x40, 0x3B, 0x20, 0xED, 0xA0, 0x9C, 0x02, 0x10, 0x4F, 0x42, 0x3C, ++0x21, 0xE1, 0x0A, 0x9C, 0x03, 0x18, 0x8E, 0x40, 0x3B, 0x00, 0xE1, 0x00, 0xB4, ++0x0B, 0x10, 0x0A, 0x48, 0x3B, 0x00, 0xFD, 0x00, 0x84, 0x02, 0xD0, 0x0A, 0x40, ++0x4C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x42, 0x81, ++0x01, 0x84, 0x07, 0x50, 0x1E, 0x40, 0x7B, 0x00, 0x49, 0x01, 0xA4, 0x47, 0x50, ++0x1E, 0x40, 0x5B, 0x00, 0xED, 0x01, 0x14, 0x05, 0x14, 0x1E, 0x50, 0x7A, 0x40, ++0xE1, 0x21, 0x34, 0x04, 0xD0, 0x9E, 0x60, 0x7B, 0x40, 0xE1, 0x01, 0x34, 0x17, ++0x90, 0x1A, 0x40, 0x7B, 0x00, 0xED, 0x01, 0x84, 0x04, 0xD0, 0x10, 0x40, 0x02, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x33, 0x00, 0x41, 0x0A, ++0x04, 0xC3, 0xC1, 0xBC, 0x44, 0x33, 0x00, 0x5D, 0x01, 0x04, 0x05, 0xD0, 0x08, ++0x40, 0x73, 0x0A, 0x8D, 0x20, 0x14, 0x0F, 0x10, 0x0C, 0x40, 0x32, 0x80, 0xC1, ++0x00, 0x14, 0x03, 0xD0, 0x0C, 0x40, 0x23, 0x00, 0x81, 0x40, 0x34, 0x03, 0x12, ++0x89, 0x42, 0x33, 0x00, 0xCD, 0x00, 0x04, 0x83, 0xD8, 0x1C, 0x40, 0x5A, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x15, 0x00, 0x73, 0x03, 0xCC, ++0x0D, 0xE0, 0x07, 0xC0, 0x17, 0x00, 0x7B, 0x00, 0xEC, 0x05, 0xF0, 0x15, 0xC2, ++0x1F, 0x00, 0x5F, 0x05, 0xDC, 0x61, 0x30, 0x05, 0xC0, 0x16, 0x60, 0x53, 0x80, ++0xF4, 0x01, 0xF1, 0x05, 0xC0, 0x17, 0x00, 0x53, 0x00, 0x7C, 0x01, 0xB0, 0x05, ++0xC0, 0x17, 0x10, 0x5F, 0x00, 0xCC, 0x39, 0xF0, 0x37, 0xC0, 0x5E, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x81, 0x00, 0x0F, 0x04, 0x7C, 0x28, ++0xF1, 0x01, 0xC3, 0x07, 0x10, 0x17, 0x08, 0x7C, 0x04, 0xF0, 0xA1, 0xC0, 0x07, ++0x01, 0x1F, 0x00, 0x1C, 0x00, 0xF0, 0x20, 0xC0, 0x05, 0x00, 0x1F, 0x00, 0x5C, ++0x80, 0x34, 0x21, 0xC0, 0x07, 0x02, 0x1F, 0x00, 0x3C, 0x80, 0xF0, 0x01, 0xC0, ++0x07, 0x80, 0x1E, 0x02, 0x7C, 0x00, 0xF0, 0x81, 0xC1, 0x49, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x65, 0x00, 0x93, 0x08, 0x6C, 0x06, 0xF0, ++0x89, 0xC0, 0x63, 0x00, 0x93, 0x02, 0x4C, 0x02, 0x31, 0x09, 0xD0, 0x24, 0x00, ++0x9B, 0x00, 0x7C, 0x02, 0x34, 0x09, 0xD0, 0x64, 0xC0, 0x93, 0x08, 0x7C, 0x02, ++0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x70, 0x09, 0xC0, 0x24, ++0x00, 0x97, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x20, 0x64, 0x40, 0x91, 0x00, 0x44, 0x6E, 0xD2, 0x29, ++0x40, 0x27, 0x02, 0x91, 0x03, 0x04, 0x02, 0x10, 0x39, 0x41, 0x24, 0x08, 0x91, ++0x20, 0x7C, 0x26, 0x11, 0x29, 0x40, 0x24, 0x02, 0x91, 0x02, 0x74, 0x02, 0xD0, ++0x79, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x7C, 0x02, 0xB0, 0x09, 0x40, 0x24, 0x00, ++0x9D, 0x04, 0x74, 0x02, 0xD0, 0x09, 0x42, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x24, 0x02, 0x91, 0x00, 0x64, 0x02, 0xD0, 0x29, 0x40, ++0x27, 0x00, 0x91, 0x10, 0x44, 0x02, 0x10, 0x88, 0x48, 0x20, 0x00, 0x99, 0x04, ++0x74, 0x02, 0x10, 0x09, 0x40, 0x20, 0x00, 0x91, 0x10, 0x74, 0x02, 0x50, 0x49, ++0x40, 0x67, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x50, 0x09, 0x40, 0x64, 0x00, 0x95, ++0x01, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x20, 0x20, 0x41, 0x81, 0x04, 0x04, 0x1A, 0x90, 0x08, 0x40, 0x23, ++0xC1, 0x81, 0x04, 0x45, 0x02, 0x18, 0x08, 0x40, 0x20, 0x01, 0x89, 0x00, 0x34, ++0x12, 0x10, 0x4C, 0x40, 0x20, 0x01, 0x81, 0x04, 0x34, 0x12, 0xD0, 0x48, 0x40, ++0x23, 0x00, 0x8D, 0x00, 0x34, 0x22, 0x90, 0x08, 0x54, 0x20, 0x00, 0x8D, 0x00, ++0x34, 0x12, 0xD0, 0x48, 0x60, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xB8, 0x96, 0x02, 0x13, 0x00, 0x6C, 0x08, 0xF0, 0x81, 0x44, 0x87, 0x02, ++0x13, 0x0A, 0x4C, 0x28, 0x30, 0xA1, 0xC0, 0x84, 0x02, 0x1B, 0x00, 0x7C, 0x00, ++0x30, 0xA1, 0x42, 0x84, 0x02, 0x11, 0x00, 0x7C, 0xA8, 0xF0, 0x01, 0xC0, 0x83, ++0x12, 0x1F, 0x0A, 0x7C, 0x58, 0x70, 0xA1, 0xC0, 0x84, 0x02, 0x17, 0x0A, 0x7C, ++0x28, 0xF0, 0x01, 0xC0, 0x77, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB0, 0x27, 0x02, 0xBF, 0x08, 0xF4, 0x0A, 0xF0, 0x8B, 0xC0, 0x27, 0x02, 0xFF, ++0x08, 0xFC, 0x02, 0xF4, 0x0B, 0xC2, 0x2F, 0x02, 0xB7, 0x00, 0xDC, 0x22, 0xF0, ++0x89, 0xC8, 0x27, 0x02, 0x9F, 0x08, 0xFC, 0x22, 0xF0, 0x89, 0xC0, 0x2F, 0x08, ++0xBF, 0x00, 0x5C, 0x92, 0x70, 0x0B, 0xC2, 0x27, 0x00, 0x9F, 0x00, 0xFC, 0x22, ++0xF0, 0x8B, 0xC0, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, ++0x2F, 0x05, 0xB3, 0x84, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x2F, 0x02, 0xB3, 0x04, ++0x5C, 0x02, 0x30, 0x8B, 0xE0, 0x25, 0x00, 0xB7, 0x00, 0xDC, 0x02, 0xF0, 0x4B, ++0xC0, 0x2F, 0x05, 0xBF, 0x04, 0x4C, 0x03, 0xF4, 0x0B, 0xC0, 0x2F, 0x02, 0xDF, ++0x00, 0x4C, 0x52, 0xB0, 0x89, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0x7C, 0x02, 0xE2, ++0x09, 0x00, 0x77, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, ++0x01, 0x11, 0x88, 0x74, 0x49, 0xD0, 0x05, 0x41, 0x07, 0x02, 0x15, 0x14, 0x44, ++0x90, 0x11, 0x41, 0x42, 0x87, 0x44, 0x11, 0x00, 0x74, 0x20, 0x72, 0x41, 0xC1, ++0x05, 0x01, 0x1C, 0x08, 0x54, 0x49, 0x10, 0x01, 0x44, 0x07, 0x00, 0x1D, 0x14, ++0x54, 0x10, 0x70, 0x41, 0x40, 0x07, 0x24, 0x1D, 0x00, 0x74, 0x00, 0xD0, 0x01, ++0x42, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x20, 0x05, ++0x81, 0x00, 0x34, 0x32, 0xD0, 0x88, 0x40, 0x23, 0x20, 0x81, 0x2C, 0x44, 0x56, ++0x04, 0x48, 0x40, 0x25, 0x43, 0x85, 0x40, 0x14, 0x02, 0xD0, 0xC8, 0x40, 0x23, ++0x25, 0xCD, 0x00, 0x24, 0x32, 0x10, 0x88, 0x40, 0x33, 0x00, 0x9D, 0x04, 0x04, ++0x52, 0x90, 0x48, 0x44, 0x23, 0x01, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, ++0x4B, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0x91, ++0x01, 0x74, 0x83, 0xD0, 0x89, 0x40, 0x23, 0x00, 0x95, 0x00, 0x44, 0x02, 0x10, ++0x19, 0x40, 0xA7, 0xC0, 0x91, 0x01, 0x74, 0x06, 0x50, 0x09, 0x00, 0x27, 0x08, ++0x99, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x50, 0x02, ++0x58, 0x09, 0x40, 0x27, 0x08, 0x9D, 0x00, 0x74, 0x12, 0xD0, 0x09, 0x43, 0x63, ++0x28, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x24, 0x40, 0x93, 0x05, ++0x7C, 0x0E, 0xF0, 0x39, 0xC0, 0x27, 0x00, 0x93, 0x03, 0x1D, 0x02, 0x10, 0x09, ++0xC8, 0x25, 0x40, 0x97, 0x20, 0x5C, 0x02, 0xF3, 0x09, 0xC0, 0x27, 0x10, 0x9F, ++0x00, 0x6C, 0x02, 0x70, 0x09, 0xC0, 0x67, 0x20, 0x8F, 0x01, 0x49, 0x02, 0xB0, ++0x19, 0xC8, 0x27, 0x10, 0x9F, 0x00, 0x7C, 0x16, 0xF0, 0x29, 0xC0, 0x17, 0x08, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x21, 0x10, 0x9F, 0x20, 0x7C, ++0x12, 0xF0, 0x09, 0xC1, 0x27, 0x00, 0x9F, 0x02, 0x7C, 0x26, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xE0, 0x25, 0x04, 0x9F, 0x00, ++0x5C, 0x02, 0x70, 0x09, 0xC1, 0x27, 0x01, 0x9F, 0x84, 0x6C, 0x02, 0xB0, 0x59, ++0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x59, 0xC0, 0x5B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x13, 0x04, 0x7E, 0x68, ++0xB4, 0x21, 0xD0, 0x04, 0x08, 0x1D, 0x02, 0x6C, 0x00, 0xF0, 0x01, 0xC8, 0x07, ++0x00, 0x1F, 0x08, 0x7C, 0x00, 0xF0, 0x81, 0xC0, 0x07, 0x40, 0x13, 0x00, 0x5C, ++0x08, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x0C, 0x7C, 0x08, 0x30, 0x21, 0xC2, 0x53, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1C, 0x40, 0x71, 0x01, 0xE4, 0x0D, 0x30, ++0x07, 0x41, 0x14, 0x00, 0x7D, 0x0D, 0x44, 0x01, 0x70, 0x07, 0xC0, 0x11, 0x00, ++0x5D, 0x00, 0x76, 0x05, 0x90, 0x07, 0x40, 0x9F, 0x08, 0x61, 0x02, 0x44, 0x01, ++0x70, 0x17, 0xC8, 0x9E, 0x02, 0x5D, 0x00, 0x74, 0x01, 0x52, 0x05, 0x40, 0x17, ++0x01, 0x7D, 0x03, 0x74, 0x01, 0x10, 0x05, 0x44, 0x43, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0x72, 0x00, 0x81, 0x09, 0x24, 0x0B, 0x50, 0x2C, ++0x42, 0x30, 0x00, 0xDD, 0x03, 0x24, 0x03, 0xD0, 0x9C, 0x40, 0x33, 0x00, 0x8D, ++0x01, 0x34, 0x22, 0xD0, 0x1C, 0x40, 0x33, 0x00, 0xC1, 0x10, 0x54, 0x83, 0x50, ++0xB4, 0x40, 0x30, 0x00, 0xCD, 0x40, 0x74, 0x03, 0x10, 0x0C, 0x40, 0x72, 0x00, ++0xCD, 0x81, 0x36, 0x83, 0x10, 0x0C, 0x40, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x80, 0x20, 0x05, 0xA1, 0x00, 0xA4, 0x07, 0x50, 0x1E, 0x60, ++0x38, 0x00, 0xAD, 0x04, 0x84, 0x13, 0xD0, 0x0E, 0x48, 0x3B, 0x00, 0xED, 0x80, ++0xB4, 0x03, 0x90, 0x0E, 0x44, 0x6B, 0x10, 0x21, 0x40, 0x84, 0x23, 0x40, 0x1E, ++0x40, 0x3A, 0x00, 0xED, 0x08, 0xB4, 0x13, 0x50, 0x4E, 0x40, 0x3B, 0x10, 0xAC, ++0x00, 0x34, 0x27, 0x10, 0x0E, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x18, 0xE8, 0x00, 0xA1, 0x01, 0xF4, 0x07, 0x70, 0x17, 0xC0, 0x78, ++0x00, 0xEF, 0x03, 0xAC, 0x27, 0xF0, 0x1E, 0xC0, 0x7B, 0x22, 0xED, 0x01, 0xB6, ++0x07, 0xF0, 0x16, 0x82, 0x73, 0x00, 0x03, 0x01, 0x9C, 0x17, 0x60, 0x1E, 0xC0, ++0x78, 0x08, 0xEF, 0x89, 0x3C, 0x17, 0x38, 0xDE, 0xC8, 0x7B, 0x00, 0xAF, 0x01, ++0xBC, 0x27, 0x30, 0x1E, 0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xB8, 0x05, 0x00, 0x9F, 0x00, 0x74, 0x03, 0x30, 0x05, 0xC0, 0x37, 0x08, ++0x8F, 0x00, 0x7C, 0x03, 0x70, 0x01, 0xC0, 0x35, 0x03, 0xDF, 0x00, 0x7C, 0x83, ++0xB1, 0x0D, 0xC0, 0x27, 0x00, 0x1F, 0x00, 0x7C, 0x9B, 0x51, 0x0C, 0xC0, 0x37, ++0x00, 0xDF, 0x02, 0x7C, 0x4B, 0x70, 0x8D, 0xC0, 0x37, 0x00, 0x9F, 0x00, 0x7C, ++0x03, 0xF2, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++0x20, 0x6D, 0x00, 0xF3, 0x01, 0xCC, 0x11, 0xB0, 0x1F, 0xC0, 0xFF, 0x00, 0xFF, ++0x01, 0xCC, 0x47, 0xF0, 0x1B, 0xC0, 0x7F, 0x00, 0xFF, 0x01, 0xBC, 0x07, 0x30, ++0x9F, 0xE0, 0x5C, 0x00, 0x3F, 0x01, 0xF8, 0x2F, 0x38, 0x1F, 0xC8, 0x6E, 0x28, ++0xF3, 0x81, 0xFC, 0x47, 0xFA, 0x9F, 0xC8, 0x6F, 0x00, 0x33, 0x21, 0x7C, 0x27, ++0x30, 0x9F, 0xC4, 0x1B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, ++0x29, 0x20, 0xE1, 0x08, 0x84, 0x21, 0x31, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, ++0x84, 0x03, 0xD0, 0x0A, 0x40, 0x3B, 0x14, 0xED, 0x80, 0x9C, 0x23, 0x70, 0x8A, ++0xC0, 0x28, 0x01, 0x2D, 0x20, 0x9C, 0x03, 0x30, 0x4E, 0x40, 0x0C, 0x12, 0xE1, ++0x18, 0xB4, 0x03, 0x70, 0x0E, 0x40, 0x2F, 0x30, 0x01, 0x00, 0xB4, 0x07, 0xB0, ++0x0C, 0x40, 0x57, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, ++0x00, 0xA1, 0x00, 0x84, 0x01, 0x10, 0x0E, 0x41, 0x3B, 0x00, 0x6D, 0x00, 0x84, ++0x0B, 0x50, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x03, 0x10, 0x06, 0x70, ++0x18, 0x10, 0x2D, 0x00, 0x14, 0x43, 0x1D, 0x0E, 0x40, 0x28, 0x44, 0xE5, 0x00, ++0xB4, 0x03, 0xD0, 0x0E, 0x44, 0x2B, 0x02, 0xA9, 0x00, 0xB4, 0x03, 0x10, 0x0E, ++0x40, 0x23, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x01, 0x00, ++0x81, 0x06, 0x05, 0x80, 0x10, 0x08, 0x40, 0x37, 0x00, 0x4D, 0x00, 0x04, 0x87, ++0xD0, 0x00, 0x46, 0x73, 0x08, 0xCD, 0x00, 0x14, 0x93, 0x51, 0x08, 0x40, 0x20, ++0x08, 0x0D, 0x00, 0x14, 0x03, 0x10, 0x0C, 0x40, 0x40, 0x10, 0xD5, 0x80, 0x34, ++0x03, 0x50, 0x0C, 0x60, 0x23, 0x00, 0x89, 0x20, 0x76, 0x13, 0x1C, 0xED, 0x48, ++0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x2D, 0x40, 0x93, ++0x00, 0x44, 0x06, 0x30, 0x09, 0xC0, 0x27, 0x00, 0xBF, 0x00, 0xCD, 0x07, 0xF0, ++0x05, 0xC0, 0xFF, 0x02, 0xDF, 0x00, 0x7C, 0x0B, 0x30, 0x09, 0xC4, 0x34, 0x00, ++0x1F, 0x00, 0xDC, 0x07, 0x30, 0x0D, 0xD0, 0x54, 0x00, 0xF7, 0x01, 0xFC, 0x03, ++0xF0, 0x0F, 0xC0, 0x37, 0x40, 0x1B, 0x00, 0xFC, 0x03, 0x10, 0x3D, 0xC4, 0x77, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x27, 0x00, 0x0F, 0x01, ++0x7C, 0x68, 0x70, 0x29, 0xC0, 0x27, 0x10, 0x9F, 0x00, 0x7C, 0x23, 0xF0, 0x1D, ++0xC8, 0x37, 0x00, 0xDF, 0x01, 0x1C, 0x03, 0x72, 0x25, 0xC0, 0x95, 0x00, 0x1F, ++0x82, 0x1C, 0x03, 0x70, 0x0D, 0xC0, 0x17, 0x00, 0xDB, 0x00, 0x7C, 0x03, 0x70, ++0x0D, 0xC0, 0x37, 0x00, 0x97, 0x00, 0x7C, 0x87, 0xF0, 0x0D, 0xC4, 0x17, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x2F, 0x00, 0x93, 0x00, 0x4C, ++0x02, 0xF0, 0x02, 0xC1, 0x3C, 0x00, 0xF3, 0x02, 0xCC, 0x03, 0xF0, 0x07, 0xC0, ++0x3C, 0x00, 0xFF, 0x03, 0xCC, 0x03, 0x30, 0x82, 0xC0, 0x6C, 0x40, 0x33, 0x00, ++0xFC, 0x43, 0x30, 0x0D, 0xC0, 0x4F, 0x00, 0xF3, 0x00, 0x8D, 0x03, 0x30, 0x0F, ++0xC0, 0x6F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0x30, 0x0F, 0xD0, 0x04, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x46, 0x02, 0x11, 0x02, 0x54, 0x06, ++0x90, 0x71, 0x40, 0x34, 0x00, 0x91, 0x00, 0x44, 0x03, 0xD0, 0x20, 0x40, 0x34, ++0x00, 0xCD, 0x00, 0x6C, 0x03, 0x10, 0x25, 0x41, 0x84, 0x06, 0x11, 0x01, 0x74, ++0x03, 0x10, 0x1D, 0xC0, 0x41, 0x00, 0xD1, 0x00, 0x44, 0x03, 0x50, 0x0D, 0x40, ++0x67, 0x00, 0x9D, 0x05, 0x74, 0x03, 0x10, 0x0D, 0xC2, 0x06, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x22, 0x00, 0xD1, 0x02, 0x44, 0x06, 0xD0, ++0x11, 0x40, 0x64, 0x00, 0x81, 0x00, 0x44, 0x03, 0xD8, 0x21, 0x40, 0x34, 0x00, ++0xDD, 0x00, 0x44, 0x07, 0x10, 0x09, 0x40, 0x10, 0x80, 0x11, 0x03, 0x74, 0x03, ++0x90, 0x1D, 0x41, 0x37, 0x01, 0xD1, 0x00, 0x44, 0x03, 0x10, 0x0D, 0x40, 0x37, ++0x01, 0x1D, 0x01, 0x74, 0x03, 0x14, 0x0D, 0x44, 0x04, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0xC1, 0x00, 0x14, 0x00, 0x98, 0x08, ++0x40, 0x20, 0x00, 0x81, 0x80, 0x05, 0x03, 0xD0, 0x09, 0x40, 0x30, 0x00, 0xDD, ++0x00, 0x24, 0x03, 0x14, 0x00, 0x50, 0x10, 0x00, 0x01, 0x00, 0x34, 0x03, 0x90, ++0x0C, 0x40, 0x57, 0x00, 0xC1, 0x00, 0x04, 0x03, 0x50, 0x0C, 0x40, 0x33, 0x80, ++0x0D, 0x02, 0x74, 0x03, 0x10, 0x0D, 0x4C, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x98, 0x22, 0x40, 0x93, 0x00, 0x4C, 0x02, 0xF1, 0x01, 0x50, ++0x3C, 0x00, 0x43, 0x00, 0xCC, 0x03, 0xF0, 0x05, 0xD0, 0x3C, 0x00, 0xDF, 0x00, ++0x44, 0x03, 0x30, 0x00, 0xC0, 0x04, 0x00, 0x13, 0x00, 0xFC, 0x03, 0xB0, 0x0D, ++0xC0, 0x27, 0x40, 0xF3, 0x00, 0xC4, 0x03, 0x30, 0x0F, 0xC0, 0x27, 0x00, 0x1F, ++0x02, 0xBC, 0x13, 0x30, 0xAD, 0xC2, 0x04, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0xB0, 0x0F, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0xF8, 0x0B, 0xC0, 0x3F, ++0x00, 0x7F, 0x00, 0xFC, 0x03, 0xF0, 0x03, 0x40, 0x3F, 0x00, 0xFF, 0x00, 0xFC, ++0x03, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0x74, 0x0B, 0xE0, ++0x0D, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC8, 0x2F, 0x30, 0xBF, 0x04, ++0x7C, 0x0B, 0xF0, 0x4F, 0xC0, 0x17, 0x62, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA0, 0x7F, 0x00, 0x7E, 0x01, 0xFC, 0x07, 0x30, 0x1F, 0x44, 0x3C, 0x05, ++0xF7, 0x00, 0xEC, 0x23, 0xB0, 0x4F, 0xC0, 0x49, 0x00, 0x37, 0x03, 0xFC, 0x03, ++0x32, 0x2F, 0x40, 0x3D, 0x02, 0x23, 0x03, 0xDC, 0x24, 0x78, 0x93, 0xC0, 0x48, ++0x00, 0x23, 0x01, 0xE4, 0x03, 0xB0, 0x17, 0xC0, 0x4C, 0x00, 0xFF, 0x21, 0xCC, ++0x06, 0xE0, 0x03, 0xC0, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x08, 0x7F, 0x00, 0xDD, 0x01, 0xF4, 0x07, 0x10, 0x1F, 0x40, 0xF4, 0x00, 0xF1, ++0x03, 0x84, 0x3B, 0x10, 0x9D, 0xC0, 0x64, 0x00, 0x1D, 0x00, 0xF4, 0x2F, 0x14, ++0x6F, 0x44, 0xBC, 0x03, 0x11, 0x84, 0x4C, 0x00, 0xD0, 0x41, 0xC0, 0x54, 0x48, ++0x51, 0x01, 0x44, 0x2F, 0x10, 0x11, 0x50, 0x44, 0x00, 0xFD, 0xA1, 0x44, 0x04, ++0xD1, 0x09, 0x40, 0x0C, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0x33, 0x00, 0x0D, 0x40, 0x34, 0x03, 0x91, 0x0C, 0x40, 0x30, 0x00, 0xC5, 0x22, ++0x24, 0x13, 0x91, 0x0C, 0x40, 0x01, 0x08, 0x0D, 0x84, 0x34, 0x03, 0x90, 0x2C, ++0x40, 0x31, 0x21, 0x01, 0xC0, 0x14, 0x14, 0x50, 0x01, 0x40, 0x32, 0x20, 0x91, ++0x00, 0x04, 0x03, 0x90, 0x0D, 0x40, 0x02, 0x00, 0xCD, 0x00, 0x04, 0x02, 0xD0, ++0x01, 0x42, 0x4D, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, ++0x00, 0xDD, 0x00, 0x74, 0x03, 0x90, 0x0D, 0x40, 0x34, 0x00, 0xD1, 0x60, 0x44, ++0x03, 0x10, 0x0D, 0x40, 0x64, 0x24, 0x1D, 0x01, 0x74, 0x03, 0x92, 0x0D, 0x40, ++0x32, 0x88, 0x01, 0x01, 0x54, 0x04, 0xC0, 0x19, 0x50, 0x94, 0x01, 0x90, 0x08, ++0x44, 0x03, 0xD0, 0x09, 0x40, 0x46, 0x04, 0xDD, 0x00, 0x44, 0x46, 0xD1, 0x31, ++0x40, 0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x37, 0x00, ++0x9F, 0x04, 0x3C, 0x03, 0x94, 0x0C, 0xD0, 0x34, 0x10, 0xD7, 0x00, 0x6C, 0x03, ++0xB0, 0x0D, 0xC8, 0x45, 0x10, 0x9F, 0x03, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, 0x35, ++0x00, 0x13, 0x11, 0x5C, 0x04, 0x71, 0x30, 0xC0, 0x26, 0x00, 0x13, 0x83, 0x6C, ++0x03, 0xB0, 0x48, 0xC0, 0xC6, 0x00, 0xCF, 0x00, 0x4D, 0x0E, 0xF0, 0x31, 0xD0, ++0x23, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x3D, 0x00, 0xBF, ++0x00, 0xFC, 0x03, 0x70, 0x0F, 0xC0, 0x3B, 0x00, 0xED, 0x40, 0xFC, 0x83, 0xF0, ++0x0E, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0x70, 0x0E, 0xC4, 0x3D, 0x00, ++0xBF, 0x00, 0xEC, 0x02, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x7F, 0x00, 0x3C, 0x03, ++0x10, 0x4B, 0xC0, 0x0D, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x09, 0xC0, 0x1E, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0x35, 0x20, 0x9F, 0x00, ++0x7C, 0x03, 0xF0, 0x4D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x5C, 0x83, 0x70, 0x0D, ++0xC0, 0x07, 0x00, 0x93, 0x02, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, 0x34, 0x00, 0x9F, ++0x02, 0x5C, 0x02, 0xF0, 0x29, 0xC2, 0xA7, 0x01, 0x93, 0x06, 0x7C, 0x47, 0x30, ++0x49, 0xC0, 0x87, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x01, 0xC4, 0x08, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, 0x20, 0x9D, 0x80, 0x74, ++0x03, 0xD0, 0x4D, 0x60, 0x3F, 0x00, 0xFD, 0x00, 0xC4, 0x83, 0x10, 0x0F, 0x44, ++0xA7, 0x1A, 0x91, 0x00, 0xBC, 0x13, 0xD0, 0x0F, 0x40, 0x3C, 0x00, 0x9D, 0x00, ++0x44, 0x02, 0xD0, 0x19, 0x40, 0x83, 0x01, 0xC1, 0x51, 0xC4, 0x0B, 0x50, 0x09, ++0x40, 0x87, 0x00, 0xDC, 0x00, 0x74, 0x0A, 0xD0, 0x99, 0x40, 0x6D, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x13, ++0xD0, 0x2C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x54, 0x03, 0x58, 0x0C, 0x41, 0x23, ++0x00, 0x81, 0x00, 0x34, 0x13, 0x90, 0x0C, 0x44, 0x30, 0x00, 0x0D, 0x80, 0x14, ++0x00, 0xD1, 0x00, 0x40, 0x82, 0x08, 0xC5, 0x63, 0x14, 0x03, 0x10, 0x3C, 0x40, ++0xC3, 0x03, 0xCD, 0x00, 0x34, 0x16, 0xD0, 0x19, 0x40, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x78, 0x00, 0xED, 0x81, 0xB4, 0x27, 0xD0, ++0x1E, 0x40, 0x7B, 0x00, 0xCD, 0x89, 0x84, 0x07, 0x18, 0x1E, 0x40, 0x6F, 0x01, ++0x21, 0x01, 0xB4, 0x07, 0xC0, 0x1C, 0x48, 0x78, 0x00, 0xBD, 0x41, 0x84, 0x07, ++0xD0, 0x1A, 0x41, 0x5F, 0x00, 0xE5, 0x01, 0x84, 0x07, 0x50, 0x1E, 0x40, 0x4B, ++0x01, 0xED, 0x21, 0xB4, 0x04, 0xD0, 0x5A, 0x40, 0x3D, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0x8F, 0x08, 0x3C, 0x03, 0xF0, 0x8C, ++0x40, 0x33, 0x00, 0xCF, 0x00, 0x1C, 0x23, 0x70, 0x1C, 0xC0, 0x63, 0x21, 0x83, ++0x02, 0x3E, 0x03, 0xB0, 0x8C, 0xC0, 0x30, 0x00, 0xCF, 0x08, 0x1C, 0x02, 0xF0, ++0x04, 0xC0, 0x33, 0x01, 0x87, 0x04, 0x1C, 0x23, 0x38, 0x0C, 0xC1, 0x03, 0x02, ++0xCF, 0x00, 0x3C, 0xE3, 0xF0, 0x00, 0xC1, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xB8, 0x7D, 0x00, 0xFF, 0x00, 0xFC, 0x87, 0xF0, 0x9F, 0xC0, ++0x3F, 0x00, 0xFF, 0x50, 0xFC, 0x03, 0xF2, 0x8F, 0xC0, 0x2F, 0x42, 0xBF, 0x08, ++0xDC, 0x03, 0xF8, 0x0F, 0xC2, 0x3F, 0x94, 0xFF, 0x40, 0xFC, 0x23, 0xF0, 0x8D, ++0x40, 0x3F, 0x40, 0xBB, 0x00, 0x5C, 0x63, 0xF0, 0x0F, 0xC8, 0x0F, 0x03, 0xFF, ++0x01, 0xFC, 0x03, 0xF0, 0x43, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0xA0, 0x37, 0x80, 0x9E, 0x00, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, 0x37, ++0x02, 0xDF, 0x11, 0x4C, 0x53, 0xF0, 0x0D, 0xC0, 0x07, 0x00, 0x9F, 0x20, 0x4C, ++0x03, 0xF0, 0x4D, 0xC0, 0xF7, 0x01, 0x5B, 0x00, 0x7C, 0x01, 0x72, 0x1D, 0xC0, ++0x24, 0x00, 0xDF, 0x00, 0x4C, 0x03, 0xF0, 0x08, 0xC0, 0x44, 0xC0, 0xDB, 0x01, ++0x4C, 0x01, 0xD0, 0x1D, 0x40, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0x88, 0x39, 0x01, 0xAD, 0x00, 0x34, 0x8B, 0x10, 0x2E, 0x48, 0x3B, 0x31, ++0xED, 0x04, 0xAC, 0x03, 0xD0, 0x2E, 0x40, 0x0B, 0x28, 0x3D, 0x00, 0x84, 0x3B, ++0xD0, 0xAE, 0xC0, 0x39, 0x0A, 0xE1, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x00, 0x38, ++0x00, 0xED, 0x80, 0x84, 0x13, 0xD2, 0x0A, 0x40, 0x08, 0x00, 0xC5, 0x02, 0x94, ++0x01, 0xD0, 0x0F, 0x40, 0x4C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x00, 0x79, 0x02, 0xA5, 0x43, 0xB4, 0x17, 0x10, 0x5E, 0x40, 0x7B, 0x00, 0xED, ++0x01, 0x84, 0x27, 0x58, 0x5E, 0x44, 0x6B, 0x10, 0xAD, 0x11, 0x85, 0x07, 0xD0, ++0x1E, 0x46, 0x73, 0x01, 0xE9, 0x91, 0xB4, 0x87, 0x42, 0x1E, 0x40, 0x7A, 0x00, ++0xFD, 0x01, 0x94, 0x07, 0xD0, 0x0A, 0x41, 0xC8, 0x40, 0xED, 0x05, 0x84, 0x05, ++0xD0, 0x1A, 0x40, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, ++0x33, 0x00, 0x8D, 0x00, 0x34, 0x03, 0x14, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, ++0x24, 0x03, 0xD0, 0x0C, 0x40, 0x73, 0x02, 0xCD, 0x03, 0x44, 0x03, 0xD0, 0x0C, ++0x40, 0x31, 0x00, 0xC9, 0x01, 0x34, 0x17, 0xD0, 0x5C, 0x42, 0xF2, 0x00, 0xCD, ++0x80, 0x04, 0x03, 0xD0, 0x38, 0x40, 0x70, 0x41, 0xCD, 0x40, 0x14, 0x63, 0xD0, ++0x3C, 0x49, 0x58, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, ++0x00, 0x7F, 0x00, 0x3C, 0x01, 0xB0, 0x04, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x4C, ++0x01, 0xF0, 0x04, 0xC0, 0x9F, 0x00, 0x7F, 0x01, 0x44, 0x01, 0xF0, 0x05, 0xC4, ++0x17, 0x00, 0x7B, 0x02, 0xF4, 0x15, 0x70, 0x17, 0xD0, 0x9A, 0x10, 0x7F, 0x10, ++0x5C, 0x01, 0xF0, 0x07, 0xC0, 0x1C, 0x00, 0x5F, 0x00, 0xCC, 0x05, 0xF0, 0x57, ++0xD0, 0x5C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, ++0x1F, 0x04, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x3C, 0x00, ++0xF0, 0x01, 0xC4, 0x07, 0x00, 0x1D, 0x00, 0x7C, 0x88, 0xF0, 0x01, 0xC0, 0x05, ++0x00, 0x17, 0x10, 0x7C, 0x00, 0xF0, 0x81, 0xC0, 0x05, 0x02, 0x1F, 0x00, 0x75, ++0x00, 0xF0, 0x01, 0xC0, 0x07, 0x40, 0x17, 0x80, 0x7C, 0x08, 0xF0, 0x01, 0xC0, ++0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x9F, ++0x00, 0x4C, 0x12, 0x30, 0x29, 0xC2, 0x24, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, ++0x49, 0xC0, 0x24, 0x06, 0x9F, 0x10, 0x4C, 0x22, 0x30, 0x09, 0xE0, 0x27, 0x00, ++0x97, 0x00, 0x7C, 0x02, 0x32, 0x59, 0xC0, 0x27, 0x26, 0x93, 0x80, 0x7D, 0x0A, ++0xF0, 0x19, 0xC1, 0x67, 0x02, 0x9F, 0x02, 0x7C, 0x02, 0x30, 0x59, 0xC0, 0x43, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x2E, 0x00, 0x8D, 0x00, ++0xC4, 0x1E, 0x10, 0x2B, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x79, ++0x40, 0x65, 0x00, 0x9D, 0x80, 0x68, 0x06, 0x50, 0x09, 0x60, 0x27, 0x00, 0x9D, ++0x00, 0x5C, 0x02, 0xB1, 0x39, 0xC2, 0xE7, 0x00, 0x81, 0x82, 0x6C, 0x1A, 0xD0, ++0x89, 0xC0, 0x25, 0x00, 0xBD, 0x03, 0x34, 0x1A, 0x12, 0x49, 0x40, 0x07, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x20, 0x9D, 0x40, 0x44, ++0x02, 0x10, 0x29, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x18, 0x09, 0x42, ++0x24, 0x00, 0x8D, 0x00, 0x44, 0x82, 0x12, 0x09, 0x40, 0x27, 0x00, 0x95, 0x60, ++0x34, 0x02, 0x58, 0x2D, 0x40, 0xA7, 0x80, 0xD1, 0x98, 0x64, 0x02, 0xD0, 0x09, ++0x40, 0x27, 0x00, 0x9D, 0x40, 0x74, 0x22, 0x14, 0x09, 0x40, 0x63, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x9D, 0x02, 0x04, 0x02, ++0x10, 0x08, 0x40, 0xA0, 0x00, 0x8D, 0x06, 0x34, 0x02, 0x10, 0x08, 0x40, 0x21, ++0x00, 0x8D, 0x08, 0x45, 0x83, 0x5A, 0x88, 0x60, 0x23, 0x82, 0x8D, 0x08, 0x34, ++0x22, 0xD0, 0x88, 0x40, 0x27, 0x00, 0x81, 0x00, 0x24, 0x02, 0xD0, 0x08, 0x40, ++0x31, 0x80, 0xCD, 0x00, 0x74, 0x02, 0x10, 0x48, 0x40, 0x43, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x46, 0x00, 0x1F, 0x00, 0x4D, 0x04, 0x34, ++0x11, 0x50, 0x04, 0x05, 0x0F, 0x00, 0x7C, 0x78, 0x30, 0x41, 0x41, 0x04, 0x00, ++0x1D, 0x02, 0x44, 0x50, 0x31, 0x61, 0x41, 0x87, 0x05, 0x17, 0x42, 0x74, 0x08, ++0x74, 0x20, 0xC0, 0x07, 0x00, 0x13, 0x40, 0x6C, 0x50, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x1F, 0x81, 0x7C, 0x00, 0x30, 0xA1, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x19, 0xB8, 0xA7, 0x00, 0xBF, 0x01, 0x7C, 0x0A, 0xF1, 0x29, ++0xC0, 0x67, 0x00, 0x9F, 0x09, 0x7C, 0x82, 0xF4, 0x09, 0xC0, 0x2F, 0x20, 0xBF, ++0x04, 0x7C, 0x02, 0xF0, 0x49, 0xC0, 0x27, 0x01, 0xFF, 0x24, 0xDC, 0x12, 0x00, ++0x4B, 0xC0, 0x2D, 0x40, 0xAF, 0x00, 0x6C, 0x02, 0xF0, 0x0B, 0xC8, 0x39, 0x00, ++0x9F, 0x22, 0xFC, 0x03, 0xF0, 0x8B, 0xC0, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x67, 0x01, 0x93, 0x02, 0xCC, 0x06, 0xF0, 0x1B, 0xC0, ++0x25, 0x02, 0x9B, 0xE0, 0x7C, 0x12, 0xF0, 0x4B, 0xC5, 0x2F, 0x00, 0x93, 0x00, ++0xDC, 0x02, 0x38, 0x89, 0xC0, 0x27, 0x49, 0x93, 0x00, 0x5E, 0x22, 0x30, 0x0B, ++0x40, 0x2C, 0x00, 0xA3, 0x00, 0xCC, 0x12, 0xF0, 0x0A, 0xC0, 0x2F, 0x00, 0xBB, ++0x11, 0xFC, 0x82, 0xE0, 0x0B, 0xD0, 0x74, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1C, 0x08, 0x07, 0x08, 0x0B, 0x01, 0x45, 0x00, 0xD0, 0x01, 0x46, 0x47, ++0x01, 0x1D, 0x9D, 0x74, 0x50, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x11, 0x10, 0x5C, ++0x00, 0x14, 0x81, 0x00, 0x07, 0x25, 0x11, 0x04, 0x5C, 0x10, 0x10, 0x01, 0x51, ++0x04, 0x20, 0x11, 0x00, 0x74, 0x00, 0xD2, 0x05, 0x48, 0x07, 0x10, 0x13, 0x42, ++0x74, 0x00, 0xD0, 0x05, 0x40, 0x60, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0xA0, 0xA3, 0x00, 0x81, 0x00, 0x04, 0x0A, 0xD0, 0x28, 0x40, 0x23, 0x02, ++0x8D, 0x00, 0x34, 0x32, 0xD0, 0x08, 0x40, 0x21, 0x00, 0x81, 0x04, 0x14, 0x22, ++0x90, 0x08, 0x44, 0x23, 0x03, 0x89, 0x14, 0x54, 0x12, 0x18, 0x48, 0x40, 0x22, ++0x40, 0x81, 0x00, 0x04, 0x22, 0xD0, 0x08, 0x40, 0x23, 0x00, 0x89, 0x00, 0x34, ++0x02, 0xD1, 0x08, 0x40, 0x48, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0x88, 0x25, 0x00, 0x89, 0x04, 0x44, 0x02, 0xD0, 0x0D, 0x40, 0x27, 0x00, 0x9D, ++0x80, 0x74, 0x02, 0xD0, 0x09, 0x00, 0xA7, 0x42, 0x91, 0x02, 0x54, 0x02, 0x98, ++0x09, 0x40, 0x27, 0x00, 0x91, 0x00, 0x54, 0x02, 0x10, 0x0C, 0x40, 0x26, 0x20, ++0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x01, 0x91, 0x00, 0x74, 0x02, ++0xD0, 0x0D, 0x40, 0x60, 0x28, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, ++0x25, 0x00, 0xB3, 0x81, 0x4C, 0x02, 0xF0, 0x09, 0xC8, 0x2F, 0x08, 0xBB, 0x80, ++0x7C, 0x02, 0xF1, 0x09, 0x80, 0x65, 0x00, 0x93, 0x00, 0x1C, 0x02, 0x90, 0x09, ++0x48, 0x27, 0x00, 0x9B, 0x03, 0x1C, 0x1A, 0x30, 0x59, 0xC0, 0x22, 0x01, 0x83, ++0xA7, 0x4C, 0x02, 0xD0, 0x29, 0xC4, 0x67, 0x00, 0x9B, 0x80, 0x7C, 0x2A, 0xF0, ++0x29, 0xC0, 0x14, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x25, ++0x00, 0x9F, 0x01, 0x70, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x80, 0x9C, 0xA0, 0x7C, ++0x82, 0xF0, 0x09, 0xC0, 0x67, 0x00, 0x9F, 0x03, 0x7E, 0x02, 0x50, 0x09, 0xC4, ++0x27, 0x00, 0x9F, 0x05, 0x7C, 0x02, 0xF4, 0x49, 0xE0, 0x65, 0x01, 0x9C, 0x44, ++0x5C, 0x42, 0xF0, 0x09, 0x00, 0x67, 0x04, 0x9F, 0x20, 0x7E, 0x06, 0xD0, 0x58, ++0xC1, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x01, 0x00, ++0x1F, 0x00, 0x5C, 0x40, 0xF0, 0x01, 0xE0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, ++0x31, 0x01, 0xE0, 0x06, 0x11, 0x1F, 0x00, 0x7C, 0x00, 0x90, 0x01, 0xC8, 0x03, ++0x00, 0x1F, 0x00, 0x7C, 0x80, 0xF8, 0x01, 0xC0, 0x86, 0x00, 0x1F, 0x80, 0x5C, ++0x00, 0x60, 0x01, 0xC0, 0x85, 0x00, 0x1F, 0x04, 0x4D, 0x00, 0xF0, 0x21, 0xC0, ++0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x14, 0x00, 0x5D, ++0x00, 0xD4, 0x0D, 0xD8, 0x07, 0x60, 0x17, 0x10, 0x5E, 0x00, 0x74, 0x01, 0x10, ++0x57, 0xE0, 0x9B, 0x80, 0x5D, 0x20, 0xF4, 0x01, 0xB2, 0x05, 0xC0, 0x17, 0x80, ++0x5D, 0x00, 0x7C, 0x01, 0x70, 0x17, 0xC0, 0x1C, 0x00, 0x7D, 0x02, 0xC4, 0x01, ++0xB0, 0x17, 0x40, 0x98, 0x00, 0x7F, 0x03, 0xC4, 0x45, 0xD2, 0x07, 0x48, 0x41, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x00, ++0x04, 0x2E, 0x50, 0x08, 0x40, 0x31, 0x80, 0xC9, 0x00, 0x34, 0x03, 0x13, 0x18, ++0x60, 0x32, 0x80, 0xCD, 0x00, 0x34, 0x02, 0x18, 0x0C, 0x40, 0x33, 0x10, 0xCD, ++0x00, 0x34, 0x03, 0xD0, 0x7C, 0x50, 0x20, 0x00, 0xCD, 0x1A, 0x16, 0x0B, 0x10, ++0x04, 0x00, 0xF1, 0x02, 0x8D, 0x00, 0x04, 0x1E, 0xD0, 0x8C, 0x40, 0x40, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x00, 0xED, 0x04, 0x94, ++0x02, 0xD0, 0x0A, 0x40, 0x3B, 0x01, 0xED, 0x04, 0x34, 0x07, 0x18, 0x0A, 0x40, ++0x3B, 0x00, 0xED, 0x04, 0x34, 0x02, 0x92, 0x4E, 0x40, 0x3B, 0x01, 0xED, 0x00, ++0xB4, 0x03, 0x50, 0x0E, 0x41, 0x28, 0x10, 0xAD, 0x40, 0x84, 0x04, 0x90, 0x3E, ++0x40, 0x38, 0x00, 0xAD, 0x83, 0x86, 0x03, 0xD0, 0x0A, 0x40, 0x11, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x78, 0x00, 0xEF, 0x03, 0x94, 0x07, ++0x70, 0x1A, 0xC0, 0x79, 0x01, 0xED, 0x05, 0xB4, 0x37, 0x31, 0x1E, 0x40, 0x7A, ++0x08, 0xED, 0x0B, 0xB4, 0x06, 0x34, 0x1E, 0xC0, 0x7B, 0x02, 0xED, 0x85, 0xBC, ++0x27, 0xD8, 0x17, 0xE0, 0x68, 0x00, 0xAF, 0x81, 0x9C, 0x04, 0x78, 0x16, 0xC0, ++0x79, 0x00, 0xEF, 0x01, 0x8C, 0x07, 0xF0, 0x1B, 0xC0, 0x50, 0x60, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x10, 0xDF, 0x40, 0x7C, 0x03, 0xF0, ++0x09, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x7C, 0x2B, 0xF4, 0x0D, 0xC0, 0x35, 0x00, ++0xDF, 0x00, 0x7C, 0x02, 0x70, 0x0D, 0xC0, 0x35, 0x82, 0xDF, 0x3E, 0x5C, 0x3B, ++0x70, 0x01, 0xE0, 0x25, 0x20, 0x9F, 0x00, 0x3C, 0x00, 0x70, 0x0D, 0xC2, 0x27, ++0x00, 0xC7, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xA0, 0x7F, 0x00, 0xEF, 0x09, 0xCC, 0x32, 0xF8, 0x8B, ++0xC0, 0x7C, 0x04, 0xFF, 0x11, 0xFC, 0x07, 0xF0, 0x1B, 0xC8, 0x7F, 0x00, 0xFF, ++0x01, 0xDE, 0x06, 0xF0, 0xBD, 0xC1, 0x74, 0x00, 0xFF, 0x01, 0xFC, 0x07, 0xF0, ++0x1B, 0xC0, 0x6C, 0x00, 0x9B, 0x89, 0xFC, 0x25, 0xF0, 0x17, 0xC0, 0x7C, 0x00, ++0xBB, 0x01, 0xBC, 0x07, 0x38, 0x9F, 0xC0, 0x1B, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0x80, 0x39, 0x00, 0xED, 0x1C, 0x84, 0x22, 0xD8, 0x0A, 0xC0, ++0x3A, 0xA0, 0xED, 0x08, 0xB4, 0x03, 0xD0, 0x08, 0x40, 0x13, 0x00, 0xED, 0x00, ++0x8C, 0x12, 0xD0, 0x5E, 0x40, 0x78, 0x02, 0xED, 0x00, 0x9C, 0x43, 0xD0, 0x0B, ++0x60, 0x28, 0x06, 0xAD, 0x05, 0xB4, 0x24, 0xD2, 0x0E, 0xC0, 0x3A, 0x80, 0xA5, ++0x00, 0xB4, 0x09, 0xF2, 0xC2, 0x40, 0x57, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x08, 0x39, 0x00, 0xFD, 0x81, 0xA4, 0x03, 0xD8, 0x88, 0x40, 0x78, ++0x02, 0xE5, 0x01, 0xB4, 0x03, 0x50, 0x0A, 0x40, 0x3B, 0x02, 0xFD, 0x18, 0x94, ++0x02, 0xD1, 0x4E, 0x54, 0x3A, 0x10, 0xED, 0x00, 0xB4, 0x23, 0xD0, 0x0E, 0x40, ++0x28, 0x00, 0xA9, 0x14, 0xB4, 0x80, 0xD8, 0x86, 0x40, 0x39, 0x00, 0xE1, 0x00, ++0xB4, 0x03, 0x10, 0x0E, 0x40, 0x63, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x06, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x04, 0x01, 0xD0, 0x08, 0x64, 0x32, 0x00, ++0xCD, 0x80, 0x34, 0x03, 0xD0, 0x08, 0x60, 0x13, 0x00, 0xCD, 0x81, 0x04, 0x02, ++0xD0, 0x0D, 0x40, 0x36, 0x00, 0xDD, 0x40, 0x54, 0x0F, 0xD1, 0x28, 0x44, 0xE0, ++0x10, 0x8D, 0x40, 0x34, 0x00, 0xD0, 0x88, 0x40, 0x63, 0x00, 0xC5, 0x00, 0x34, ++0x09, 0x52, 0x30, 0x40, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA8, 0x35, 0x00, 0xDF, 0x41, 0x6D, 0x02, 0xD0, 0x0D, 0xC0, 0x34, 0x00, 0xDF, ++0x00, 0xFC, 0x03, 0xF0, 0x09, 0xC8, 0xF7, 0x08, 0xFF, 0x03, 0x54, 0x83, 0xD2, ++0x0F, 0x48, 0x3E, 0x00, 0xFF, 0x08, 0xF4, 0x0B, 0xD0, 0x2D, 0xD0, 0x34, 0x02, ++0x8B, 0x01, 0x7C, 0x00, 0xD0, 0x0C, 0xC0, 0xB5, 0x06, 0x93, 0x00, 0x7C, 0x0A, ++0x10, 0x21, 0xC0, 0x57, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, ++0x33, 0x00, 0xDF, 0x10, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0xF0, 0x29, 0xC4, 0x77, 0x04, 0xDF, 0x04, 0x1C, 0x0A, 0xF0, 0x0D, ++0xC0, 0x35, 0x00, 0xDF, 0x00, 0x5C, 0x03, 0xF0, 0x4D, 0xC0, 0xA7, 0x08, 0x9F, ++0x60, 0x7C, 0x88, 0xF1, 0x2D, 0x40, 0xB6, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, ++0xA1, 0xC8, 0x37, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, ++0x00, 0xF3, 0x00, 0xFC, 0x12, 0x30, 0x2F, 0xC0, 0x3F, 0x20, 0xF3, 0x40, 0xFC, ++0x03, 0xF0, 0x1F, 0xC0, 0x2C, 0x02, 0xFF, 0x80, 0xFC, 0x87, 0x30, 0x0F, 0xD0, ++0x3C, 0x00, 0xF5, 0x00, 0xCD, 0x43, 0xB0, 0x07, 0xC0, 0x7F, 0x00, 0xBF, 0x00, ++0xCC, 0x80, 0xF0, 0x0F, 0x80, 0x3C, 0x00, 0xB3, 0x04, 0xFC, 0x40, 0xF0, 0x0A, ++0xC1, 0x04, 0x26, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x36, 0x20, ++0xD1, 0x00, 0x74, 0x06, 0x94, 0x05, 0xC0, 0x35, 0x00, 0xD1, 0x00, 0x74, 0x03, ++0xD0, 0x84, 0x41, 0x25, 0x00, 0xDD, 0x20, 0x74, 0x01, 0x10, 0x0D, 0x40, 0x34, ++0x00, 0xD1, 0x00, 0x44, 0x03, 0xB0, 0x21, 0x40, 0x17, 0x00, 0x9D, 0x23, 0x44, ++0x4C, 0xD0, 0x0D, 0x50, 0x60, 0x84, 0x95, 0x07, 0x74, 0x0C, 0xD0, 0x39, 0x50, ++0x04, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x36, 0xC0, 0xD1, ++0x00, 0x74, 0x02, 0x90, 0x0D, 0x40, 0x33, 0x00, 0xD1, 0x00, 0x74, 0x03, 0xD0, ++0x09, 0x40, 0x34, 0x00, 0xDD, 0x00, 0x64, 0x1B, 0x10, 0x0D, 0x40, 0x34, 0x00, ++0xD5, 0x00, 0x64, 0x03, 0x10, 0x01, 0x40, 0xB7, 0x01, 0x9D, 0x11, 0x44, 0x04, ++0xD0, 0x0D, 0x41, 0x45, 0x00, 0x91, 0x00, 0x74, 0x06, 0x50, 0x11, 0x40, 0x04, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0xC1, 0x00, ++0x34, 0x02, 0x90, 0x08, 0x40, 0x31, 0x00, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x08, ++0x40, 0x11, 0x00, 0xCD, 0x00, 0x34, 0x02, 0x14, 0x4C, 0x40, 0x30, 0x04, 0xC5, ++0x20, 0x04, 0x03, 0xD4, 0x00, 0x44, 0x23, 0x80, 0x8D, 0x30, 0x05, 0x40, 0xD0, ++0x0D, 0x40, 0x25, 0x00, 0x85, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x42, 0x40, 0x81, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0xF3, 0x40, 0x7C, ++0x03, 0x30, 0x0D, 0xC4, 0x3F, 0x00, 0xF3, 0x00, 0xFC, 0x03, 0xF0, 0x2D, 0xC2, ++0xA4, 0x02, 0xFD, 0x00, 0x7C, 0x03, 0x30, 0x0E, 0xC0, 0x3C, 0x01, 0xF7, 0x00, ++0xCC, 0x03, 0x32, 0x05, 0xC2, 0x37, 0x00, 0x9F, 0x00, 0x4C, 0x10, 0xF0, 0x0D, ++0xC0, 0x25, 0x00, 0x51, 0x00, 0x7C, 0x00, 0x70, 0x09, 0xC0, 0x04, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xA8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x01, ++0x78, 0x07, 0xC8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x47, 0xC1, 0x0F, ++0x00, 0xEF, 0x00, 0xFC, 0x01, 0xF0, 0x2F, 0xC0, 0x3F, 0x00, 0xFB, 0x00, 0xFC, ++0x03, 0x30, 0x03, 0xC0, 0x1F, 0x00, 0x3F, 0x00, 0x7C, 0x00, 0xF0, 0x0A, 0x40, ++0x2A, 0x08, 0x7F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x17, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x3F, 0x08, 0xA3, 0x00, 0xFC, 0x33, 0x30, ++0x9B, 0xC0, 0xEF, 0x00, 0xFF, 0x03, 0x9D, 0x27, 0xB0, 0x1F, 0xC0, 0x7C, 0x02, ++0xFB, 0x09, 0xCD, 0x07, 0x70, 0x1F, 0xC8, 0x7A, 0x08, 0xFF, 0x01, 0xFC, 0x07, ++0x31, 0x9F, 0xC0, 0x7F, 0x00, 0xFF, 0x09, 0xFE, 0x27, 0x30, 0x1F, 0xC0, 0x7A, ++0x40, 0xB3, 0x01, 0xFC, 0x00, 0x30, 0x26, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x3B, 0x38, 0xD1, 0x43, 0xF4, 0x13, 0x12, 0x4C, ++0x44, 0x27, 0x11, 0x1C, 0x84, 0x44, 0x10, 0x10, 0x11, 0x50, 0x04, 0x01, 0x11, ++0x04, 0x44, 0xD0, 0x50, 0x11, 0x40, 0x07, 0x05, 0x0D, 0x10, 0x34, 0x40, 0x10, ++0x41, 0x40, 0x07, 0x00, 0x1D, 0x44, 0x5C, 0x10, 0x10, 0x11, 0x40, 0x44, 0x00, ++0x91, 0x01, 0x5C, 0x0C, 0x14, 0x45, 0x40, 0x0F, 0x60, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x11, 0xA0, 0x23, 0x05, 0x81, 0x22, 0x14, 0x33, 0x10, 0x0C, 0x48, ++0x21, 0x01, 0xCD, 0x00, 0x44, 0x13, 0x54, 0x0D, 0x40, 0x31, 0x00, 0xC1, 0x80, ++0x04, 0x03, 0x56, 0x0C, 0x44, 0x33, 0x00, 0xCD, 0x04, 0x34, 0x13, 0x90, 0x4C, ++0x40, 0x33, 0x05, 0xCD, 0x20, 0x34, 0x13, 0x10, 0x0D, 0x40, 0x30, 0x00, 0x01, ++0x01, 0x34, 0x0A, 0xD0, 0x40, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0x88, 0x35, 0x40, 0xD1, 0x84, 0x74, 0x03, 0x14, 0x3D, 0x40, 0x27, ++0x20, 0x0D, 0x00, 0x54, 0x00, 0x90, 0x01, 0x42, 0x05, 0x00, 0x01, 0x00, 0x44, ++0x00, 0x54, 0x01, 0x60, 0x07, 0x00, 0x1D, 0x80, 0x70, 0x00, 0x90, 0x01, 0x40, ++0x07, 0x00, 0x1D, 0x20, 0x14, 0x00, 0x18, 0x01, 0x40, 0x04, 0x00, 0x51, 0x01, ++0x74, 0x00, 0xD1, 0x01, 0x40, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA0, 0x37, 0x00, 0x93, 0x01, 0x5C, 0x03, 0x30, 0x3D, 0xC0, 0x65, 0x0A, ++0xDF, 0x00, 0x4C, 0x83, 0xF0, 0x0D, 0xC8, 0x35, 0x40, 0xDB, 0x80, 0x08, 0x03, ++0x74, 0x0D, 0xC4, 0x36, 0x10, 0xDF, 0x00, 0x78, 0x03, 0xA0, 0x0D, 0xC0, 0x37, ++0x80, 0xDF, 0x00, 0x74, 0x03, 0x34, 0x0C, 0xC2, 0x36, 0x00, 0x91, 0x01, 0x3C, ++0x15, 0xF0, 0x15, 0xC0, 0x03, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x88, 0x3D, 0x00, 0xFF, 0x21, 0xF4, 0x03, 0xD0, 0x0F, 0xC0, 0x2F, 0x00, 0x3F, ++0x40, 0xE4, 0x00, 0x30, 0x03, 0xC0, 0x0E, 0x00, 0x3F, 0x00, 0xFC, 0x40, 0xF0, ++0x03, 0x00, 0x0F, 0x00, 0x3F, 0x30, 0xFC, 0x80, 0x70, 0x03, 0xC0, 0x0F, 0xA0, ++0x3F, 0x40, 0xDC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x14, 0xFF, 0x00, 0xDC, 0x24, ++0x30, 0x47, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, ++0x61, 0x10, 0x9B, 0x01, 0x6C, 0x03, 0x34, 0x3D, 0xC0, 0x24, 0x00, 0xD3, 0x50, ++0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x77, 0x00, 0xD3, 0x08, 0x4C, 0x07, 0xB0, 0x4D, ++0xC0, 0x37, 0x00, 0xD7, 0x01, 0x4C, 0x83, 0x30, 0x1D, 0xC1, 0x37, 0x00, 0xDF, ++0x01, 0x7C, 0x97, 0xF0, 0x1D, 0xC0, 0x34, 0x00, 0x93, 0x10, 0x7C, 0x20, 0x30, ++0x25, 0xD0, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xB4, ++0x02, 0xD1, 0x20, 0xD4, 0x2B, 0x10, 0x2D, 0x40, 0x64, 0x01, 0x1A, 0x03, 0x3C, ++0x00, 0x14, 0x40, 0x42, 0x87, 0x00, 0x11, 0x01, 0x44, 0x00, 0x10, 0x51, 0xC0, ++0x05, 0x40, 0x15, 0x01, 0x44, 0x04, 0x10, 0x11, 0x40, 0x07, 0x00, 0x1D, 0x21, ++0x74, 0x0C, 0xD0, 0x01, 0x44, 0xC0, 0x04, 0x59, 0x03, 0x74, 0x20, 0x00, 0xB5, ++0x40, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x20, 0x30, 0x00, ++0x89, 0x40, 0x44, 0x03, 0x90, 0x2C, 0x41, 0x60, 0x00, 0xC9, 0x02, 0x34, 0x03, ++0x10, 0x1C, 0x40, 0xB7, 0x04, 0xC1, 0x01, 0x14, 0x03, 0x90, 0x2C, 0x40, 0x33, ++0x00, 0xC9, 0x02, 0x54, 0x27, 0x91, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, ++0x0B, 0xD0, 0x0C, 0x40, 0xF0, 0x40, 0x89, 0x03, 0x14, 0x0C, 0x10, 0x9C, 0x40, ++0x4C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x78, 0x00, 0xF1, ++0x01, 0x14, 0x07, 0x90, 0x1E, 0x40, 0x68, 0x00, 0x29, 0x11, 0xC4, 0x04, 0x10, ++0x92, 0x48, 0x4B, 0x00, 0x21, 0x03, 0x94, 0x04, 0x12, 0x12, 0x40, 0x4D, 0x20, ++0x29, 0x09, 0x95, 0x0C, 0x50, 0x12, 0x40, 0x4B, 0x20, 0x2C, 0x41, 0xB0, 0x04, ++0xD0, 0x13, 0x40, 0x48, 0x00, 0xA9, 0x29, 0xB4, 0x17, 0x10, 0x1F, 0x40, 0x3C, ++0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x18, 0x20, 0x00, 0x8B, 0x00, ++0x0C, 0x03, 0x30, 0x0C, 0xC0, 0x24, 0x00, 0xCB, 0x88, 0x34, 0x23, 0x31, 0x0C, ++0xC0, 0x37, 0x00, 0xD3, 0x80, 0x5C, 0x23, 0xB0, 0x8C, 0xC0, 0x33, 0x02, 0xCF, ++0x00, 0x1C, 0x23, 0x30, 0x0C, 0xC0, 0x33, 0x00, 0xCE, 0x00, 0x3C, 0x03, 0xF2, ++0x0C, 0xC4, 0x30, 0x00, 0x43, 0x30, 0x1C, 0x03, 0x30, 0x7C, 0xC0, 0x48, 0x40, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x3D, 0x00, 0xFF, 0x00, 0xDC, ++0x4B, 0x50, 0x0F, 0xC0, 0x2F, 0x02, 0x3F, 0x28, 0xFE, 0x00, 0xF2, 0x03, 0x48, ++0x0F, 0x00, 0x3F, 0x00, 0xEC, 0x80, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x37, 0x00, ++0xEC, 0x00, 0xB0, 0x83, 0xC0, 0x0F, 0x00, 0x3F, 0x40, 0xFC, 0x00, 0xF0, 0x02, ++0xC0, 0x4F, 0x40, 0x77, 0x00, 0x3C, 0x13, 0xF2, 0x8D, 0xC0, 0x0B, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, 0x01, 0x9F, 0x00, 0x7C, 0x13, ++0xF0, 0x0D, 0xC0, 0x24, 0x00, 0xDD, 0x00, 0x7C, 0x03, 0xF0, 0x1C, 0xC0, 0x30, ++0x40, 0xD3, 0x00, 0x6F, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x4D, ++0x03, 0xF0, 0x1D, 0xD0, 0x34, 0x00, 0xDF, 0x21, 0x4D, 0x07, 0x24, 0x0D, 0xC0, ++0x33, 0x00, 0x53, 0x00, 0x4C, 0x07, 0x32, 0x15, 0xC0, 0x40, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x39, 0x22, 0xED, 0x00, 0xB4, 0x03, 0xD0, ++0x0F, 0x50, 0x28, 0x00, 0x2D, 0x00, 0xBC, 0x00, 0xD0, 0x02, 0x48, 0x09, 0x00, ++0x21, 0x00, 0x84, 0x00, 0xD2, 0x02, 0x40, 0x0B, 0x00, 0x3D, 0x00, 0x84, 0x00, ++0xD0, 0x03, 0x40, 0x08, 0x00, 0x3D, 0x00, 0xC4, 0x00, 0x10, 0x02, 0x44, 0x0B, ++0x00, 0xE1, 0x20, 0xAC, 0x03, 0xB0, 0x07, 0xC0, 0x4E, 0x68, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x69, 0x10, 0xED, 0x03, 0x94, 0x17, 0xD0, 0x1E, ++0x40, 0x68, 0x04, 0xED, 0x41, 0xB4, 0x07, 0x50, 0x1E, 0x44, 0x7C, 0x20, 0xF9, ++0x81, 0x84, 0x07, 0x50, 0x1E, 0x40, 0x7B, 0x00, 0xE5, 0x01, 0x84, 0x07, 0xD0, ++0x1E, 0x40, 0x79, 0x00, 0xED, 0x01, 0x84, 0x87, 0x18, 0x1E, 0x40, 0x7B, 0x40, ++0x71, 0x01, 0x04, 0x07, 0x10, 0x16, 0x40, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x28, 0x33, 0x00, 0xCD, 0x01, 0x34, 0x03, 0xD0, 0x24, 0x4C, ++0x30, 0x10, 0x0D, 0x00, 0x12, 0x00, 0xD0, 0x00, 0x40, 0x01, 0x10, 0x09, 0xC0, ++0x04, 0x80, 0xD0, 0x00, 0x42, 0x03, 0x08, 0x1D, 0x00, 0x44, 0x00, 0xD0, 0x00, ++0x40, 0x01, 0x00, 0x0D, 0x00, 0x06, 0x00, 0x10, 0x00, 0x40, 0x03, 0x00, 0x51, ++0x03, 0x24, 0xCF, 0x12, 0x34, 0x40, 0x58, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x17, 0xA0, 0x15, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xD0, 0x27, 0xC0, 0x54, ++0x00, 0x5F, 0x00, 0x74, 0x01, 0x70, 0x05, 0xC4, 0x14, 0x00, 0x4B, 0x00, 0x6C, ++0x01, 0xF0, 0x04, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x4C, 0x01, 0xF0, 0x05, 0xC0, ++0x15, 0x00, 0x5F, 0x00, 0x44, 0x01, 0x30, 0x05, 0xC0, 0x13, 0x00, 0x71, 0x07, ++0xCC, 0x11, 0x14, 0x17, 0x40, 0x5C, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x08, 0x04, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x21, 0xC1, 0x07, 0x00, ++0x3D, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x37, 0x02, 0xFC, 0x00, ++0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0E, ++0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x40, 0x1F, 0x06, 0x7C, ++0x00, 0xF0, 0xA1, 0xC9, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x21, 0x00, 0x93, 0x00, 0x3C, 0x02, 0xB0, 0x09, 0xC0, 0x24, 0x10, 0x9F, ++0x01, 0x4C, 0x02, 0xF0, 0x19, 0xC0, 0xE7, 0x00, 0x93, 0x00, 0x6C, 0x06, 0xF0, ++0x99, 0xC0, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x34, 0x59, 0xC0, 0x27, 0x00, ++0x9F, 0x05, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x40, 0x9B, 0x00, 0x6C, 0x02, ++0xF0, 0x49, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, ++0x26, 0x40, 0x91, 0x80, 0x74, 0x42, 0x10, 0xA9, 0x41, 0x24, 0x00, 0x8D, 0x09, ++0x5E, 0x2A, 0xD0, 0x19, 0x40, 0x63, 0x40, 0x91, 0x02, 0x45, 0x1A, 0xD0, 0x69, ++0xC2, 0x26, 0x08, 0x9D, 0x02, 0x44, 0x42, 0x10, 0x39, 0x40, 0x27, 0x00, 0x9D, ++0x02, 0x74, 0x0A, 0xD0, 0x09, 0x48, 0x67, 0x04, 0x91, 0x82, 0x44, 0x86, 0xD0, ++0x69, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x64, ++0x00, 0x91, 0x00, 0x74, 0x02, 0x10, 0x08, 0x40, 0x24, 0x00, 0x9D, 0x00, 0xC4, ++0x42, 0xD0, 0x4B, 0x40, 0x2F, 0x00, 0xB9, 0x03, 0xC4, 0x12, 0xD0, 0x0B, 0x40, ++0x2C, 0x00, 0xBD, 0x00, 0xC4, 0x06, 0x92, 0x0B, 0x44, 0x2F, 0x00, 0xBD, 0xC0, ++0xF4, 0x02, 0xD0, 0x1B, 0x40, 0x2F, 0x41, 0x91, 0x08, 0x64, 0x22, 0xD0, 0x09, ++0x40, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x2A, 0x20, 0x01, ++0x81, 0x04, 0x34, 0x12, 0x18, 0x08, 0x50, 0x20, 0x00, 0xBC, 0x00, 0x84, 0x02, ++0xD0, 0x0A, 0x40, 0x6F, 0x00, 0xB9, 0x00, 0x84, 0x02, 0xD0, 0x0A, 0x40, 0x2A, ++0x00, 0xAD, 0x01, 0x84, 0x02, 0x90, 0x1A, 0x40, 0x2B, 0x00, 0xAD, 0x41, 0xB4, ++0x06, 0xD0, 0x0A, 0x40, 0x2B, 0x00, 0x91, 0x00, 0x24, 0x02, 0xD0, 0x48, 0x40, ++0x53, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA0, 0x86, 0x02, 0x13, ++0x00, 0x7C, 0x28, 0x34, 0xA1, 0xC0, 0x84, 0x02, 0x1F, 0x0A, 0x44, 0x28, 0xF0, ++0x01, 0xC0, 0x87, 0x02, 0x1B, 0x0A, 0x4C, 0x28, 0xF0, 0x01, 0xC0, 0x85, 0x02, ++0x1F, 0x0A, 0x4C, 0x28, 0xB3, 0xA1, 0xC0, 0x87, 0x02, 0x1F, 0x0A, 0x7C, 0x28, ++0xF0, 0x01, 0xC0, 0x0F, 0x10, 0x53, 0x00, 0x6C, 0x51, 0xFA, 0xA1, 0xC0, 0x77, ++0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x88, 0x2F, 0x02, 0xBF, 0x08, ++0x7C, 0x22, 0x78, 0x0B, 0xC0, 0x2F, 0x20, 0x9E, 0x00, 0x5D, 0x02, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x87, 0x00, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, ++0x00, 0x7D, 0x02, 0x71, 0x09, 0xC0, 0x27, 0x08, 0x9F, 0x20, 0x7C, 0x82, 0xF0, ++0x09, 0xC2, 0x27, 0x00, 0xA7, 0x00, 0xDC, 0x02, 0xF0, 0x8B, 0xC0, 0x67, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x2F, 0x01, 0xB3, 0x14, 0xCC, ++0xB2, 0x30, 0x0F, 0xC0, 0x2D, 0x00, 0xBF, 0x08, 0xCC, 0x02, 0x10, 0x0B, 0xC0, ++0x2F, 0x02, 0xBF, 0x00, 0xCC, 0x02, 0x30, 0x0B, 0xC0, 0x24, 0x00, 0xB3, 0x00, ++0xFC, 0x22, 0xF0, 0x0B, 0xC0, 0x24, 0x00, 0xB3, 0x08, 0xDC, 0x02, 0x30, 0x0B, ++0xC0, 0x2F, 0x00, 0xB3, 0x00, 0xFC, 0x82, 0x30, 0x0B, 0xC0, 0x67, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x0D, 0x11, 0x00, 0x45, 0x30, ++0x10, 0x01, 0x43, 0x04, 0x04, 0x1D, 0x00, 0x04, 0x50, 0x10, 0x01, 0x40, 0x03, ++0x01, 0x1D, 0x10, 0x4C, 0x40, 0x14, 0x01, 0x50, 0x04, 0x05, 0x01, 0x04, 0x74, ++0x10, 0xD0, 0x00, 0x41, 0x00, 0x24, 0x01, 0x40, 0x5C, 0x50, 0x10, 0x01, 0x40, ++0x07, 0x00, 0x11, 0x00, 0x74, 0x00, 0x10, 0x81, 0x40, 0x73, 0x60, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x03, 0x91, 0x20, 0x04, 0x12, 0x90, ++0x49, 0x40, 0x21, 0x80, 0x8D, 0x00, 0x04, 0x12, 0x10, 0x0C, 0x40, 0x23, 0x01, ++0x8D, 0x04, 0x65, 0x02, 0x10, 0x09, 0x40, 0x24, 0x41, 0x81, 0x14, 0x34, 0x12, ++0xD8, 0x48, 0x50, 0x20, 0x00, 0x81, 0x00, 0x14, 0x12, 0x10, 0x08, 0x40, 0x23, ++0x00, 0x89, 0x00, 0x34, 0x02, 0x10, 0x08, 0x48, 0x4B, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x41, 0x91, 0x00, 0x44, 0x03, 0x90, 0x29, ++0x40, 0x24, 0x02, 0x8D, 0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x27, 0x00, 0x8D, ++0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x91, 0x00, 0x74, 0x02, 0xD0, ++0x09, 0x40, 0x24, 0x00, 0xD1, 0x00, 0x54, 0x02, 0x10, 0x09, 0x40, 0x37, 0x20, ++0x99, 0x00, 0x74, 0x0A, 0x12, 0x89, 0x40, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x00, 0x25, 0x00, 0x83, 0x89, 0x0C, 0x02, 0xB4, 0x18, 0xC0, ++0x65, 0x20, 0x9F, 0x00, 0x4D, 0x02, 0x34, 0x09, 0xC0, 0x27, 0x80, 0x9F, 0x00, ++0x6C, 0x02, 0x30, 0x08, 0xC0, 0x24, 0x00, 0x93, 0x00, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x24, 0x40, 0x93, 0x00, 0x5C, 0x02, 0x34, 0x09, 0xC0, 0x27, 0x00, 0x99, ++0x12, 0x7C, 0x02, 0x34, 0x19, 0xC0, 0x17, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x16, 0x08, 0x25, 0x00, 0x9F, 0x41, 0x7C, 0x02, 0x74, 0x29, 0xC0, 0x27, ++0x00, 0x9F, 0x50, 0x7C, 0x42, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x00, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x40, 0x97, 0x15, ++0x7E, 0x52, 0xF0, 0x09, 0xE0, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x08, 0x41, 0x40, 0x13, 0x00, 0x7C, 0x10, 0xF0, 0x41, 0xC0, 0x07, 0x00, ++0x1F, 0x08, 0x4C, 0x00, 0x34, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x00, 0x7C, 0x00, ++0xF0, 0x11, 0xF0, 0x04, 0x00, 0x1F, 0x20, 0x4C, 0x04, 0xD0, 0x01, 0xC0, 0x06, ++0x40, 0x13, 0x40, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x02, 0x0C, ++0x08, 0x14, 0x01, 0xC4, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA0, 0x5C, 0x00, 0x51, 0x00, 0xF4, 0x09, 0xD0, 0x27, 0xC0, 0x15, 0x00, 0x7D, ++0x00, 0xC6, 0x05, 0x50, 0x05, 0x40, 0x5F, 0x04, 0x73, 0x02, 0xB4, 0x29, 0xD1, ++0x07, 0xC2, 0x12, 0x00, 0x7D, 0x45, 0xC4, 0x15, 0xD0, 0x07, 0xC0, 0x14, 0x00, ++0x71, 0x02, 0xCC, 0x01, 0xD0, 0x15, 0x40, 0x9B, 0x08, 0x71, 0x02, 0xD4, 0x0D, ++0x50, 0xF7, 0x40, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, ++0x32, 0x00, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x31, 0x20, 0xCD, 0x00, ++0x64, 0x0F, 0x50, 0x08, 0x44, 0x73, 0x00, 0xC1, 0x04, 0x24, 0x03, 0xD0, 0x04, ++0x40, 0x32, 0x10, 0xCD, 0x01, 0x05, 0x03, 0x50, 0x0D, 0x40, 0x34, 0x00, 0xC1, ++0x06, 0x65, 0x07, 0xD0, 0x98, 0x40, 0x63, 0x03, 0x41, 0x08, 0x04, 0x23, 0x10, ++0x0C, 0x40, 0x52, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x08, ++0x04, 0xE1, 0x00, 0xB4, 0x43, 0x90, 0x0E, 0x40, 0x39, 0x00, 0x7D, 0x00, 0xA5, ++0x0B, 0x50, 0x0E, 0x40, 0x7B, 0x00, 0xE1, 0x00, 0xB4, 0x02, 0xD0, 0x0E, 0x41, ++0x38, 0x01, 0xED, 0x01, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x38, 0x0A, 0xE1, 0x83, ++0xA4, 0x43, 0xD0, 0x0E, 0x40, 0x1F, 0x00, 0x71, 0x01, 0x14, 0x03, 0x10, 0x12, ++0x58, 0x06, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x60, 0x00, ++0xE3, 0x01, 0xBC, 0x07, 0xD0, 0x1E, 0xC0, 0x79, 0x00, 0xEF, 0x01, 0xA4, 0x06, ++0x70, 0x1E, 0xC0, 0x6B, 0x40, 0xE3, 0x01, 0xB0, 0x05, 0xF0, 0x1E, 0x40, 0x7A, ++0x00, 0xEF, 0x01, 0x8C, 0x07, 0x70, 0x1E, 0xC0, 0x78, 0x05, 0xE3, 0x01, 0xAC, ++0x07, 0xF1, 0x1E, 0xC0, 0x6B, 0x00, 0x63, 0x81, 0x84, 0x07, 0x30, 0x18, 0xC0, ++0x46, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x05, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x01, 0xC0, 0x35, 0x10, 0x0F, 0x00, 0x5C, 0x02, 0xB0, ++0x0D, 0xC0, 0x07, 0x00, 0x17, 0x00, 0x7C, 0x80, 0xF0, 0x0C, 0xC0, 0x37, 0x04, ++0x5F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xD0, 0xB5, 0x00, 0x9F, 0x00, 0x5C, 0x01, ++0xF0, 0x0D, 0xC0, 0x33, 0x20, 0x4F, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x41, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x4D, 0x00, 0xE7, 0x21, ++0xCC, 0x07, 0xF8, 0x87, 0xC0, 0x7C, 0x02, 0xBF, 0x01, 0xCC, 0x07, 0x30, 0x1F, ++0xC0, 0x7C, 0x00, 0x73, 0x01, 0xEC, 0x05, 0x32, 0x1F, 0xC0, 0x7F, 0x04, 0xF3, ++0x01, 0xFC, 0x04, 0xB0, 0x1F, 0xC0, 0x7F, 0x10, 0xB3, 0x01, 0xCC, 0x07, 0xF0, ++0x1E, 0xC0, 0x3C, 0x00, 0xF3, 0x05, 0xCC, 0x06, 0xF0, 0x13, 0x84, 0x0B, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x8D, 0x10, 0xE1, 0x08, 0x84, ++0x21, 0x78, 0x0E, 0x44, 0x38, 0x00, 0x7D, 0x06, 0xC5, 0x03, 0x10, 0x0E, 0x40, ++0x28, 0x00, 0x71, 0x40, 0x84, 0xE0, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xA1, 0x10, ++0xB4, 0x01, 0x10, 0x0E, 0x40, 0x3B, 0x02, 0xBB, 0x18, 0x8C, 0x0A, 0xD0, 0x8E, ++0x40, 0x19, 0x02, 0xA1, 0x06, 0xAC, 0x03, 0xD0, 0x20, 0x40, 0x57, 0x60, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xE5, 0x00, 0x85, 0x01, ++0x50, 0x87, 0x40, 0x38, 0x8C, 0xAD, 0x00, 0x86, 0x01, 0x90, 0x0F, 0x40, 0x3A, ++0x40, 0xE1, 0x00, 0xC4, 0x01, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xE1, 0x00, 0xF4, ++0x0A, 0x10, 0x0E, 0x40, 0x3F, 0x00, 0x61, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, ++0x29, 0x42, 0x61, 0x0C, 0x94, 0x43, 0xD0, 0x02, 0x40, 0x23, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x01, 0x00, 0xC1, 0x00, 0x04, 0x01, 0x50, ++0x31, 0x40, 0x70, 0x00, 0x1D, 0x41, 0x02, 0x45, 0x90, 0x3C, 0x50, 0x82, 0x04, ++0x01, 0x10, 0x04, 0x08, 0x10, 0x2C, 0x42, 0x77, 0x01, 0x01, 0x05, 0x30, 0x04, ++0x10, 0xD0, 0x40, 0xB3, 0x04, 0x09, 0x05, 0x06, 0x34, 0xD0, 0x1C, 0x40, 0x91, ++0x00, 0x81, 0x13, 0x34, 0x0E, 0xD0, 0x00, 0x40, 0x1B, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x80, 0x05, 0x00, 0xD7, 0x00, 0x4C, 0x03, 0x70, 0xE9, ++0xC0, 0x74, 0x00, 0xDF, 0x05, 0x4C, 0x09, 0xB0, 0x0D, 0xC0, 0x16, 0x00, 0x93, ++0x01, 0x4C, 0x07, 0x34, 0x7C, 0x40, 0xBF, 0x00, 0x13, 0x03, 0x3C, 0x03, 0x10, ++0x21, 0xC0, 0x3B, 0x00, 0x53, 0x03, 0x4C, 0x08, 0xF0, 0x3D, 0xC0, 0xB5, 0x02, ++0x43, 0x11, 0x50, 0x0D, 0xF0, 0x09, 0x40, 0x77, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x00, 0x47, 0x00, 0x9F, 0x01, 0x7C, 0x83, 0x70, 0x09, 0xD2, ++0x27, 0x00, 0xDF, 0x04, 0x7C, 0x21, 0x70, 0x8D, 0xC0, 0xB5, 0x02, 0xDF, 0x08, ++0x7C, 0x8B, 0xF2, 0x0D, 0xC0, 0x37, 0x42, 0x9F, 0x00, 0x7C, 0x23, 0x70, 0x29, ++0xC0, 0x77, 0x00, 0x57, 0x02, 0x5C, 0x02, 0xF0, 0xCD, 0xC0, 0xF7, 0x40, 0x5F, ++0x40, 0x2C, 0x0B, 0xF2, 0x01, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x80, 0x00, 0x0B, 0x40, 0xE3, 0x00, 0xEC, 0x03, 0xF0, 0x8F, 0xC0, 0x3C, ++0x00, 0xFB, 0x00, 0xCC, 0x02, 0x30, 0x0F, 0xC1, 0x0F, 0x00, 0xBF, 0x09, 0xFC, ++0x40, 0xF0, 0x0F, 0xC1, 0x3C, 0x00, 0x33, 0x05, 0xFC, 0x03, 0xB0, 0x47, 0xC0, ++0x3D, 0x00, 0x73, 0x00, 0xCC, 0x20, 0x30, 0x9F, 0xC0, 0xFF, 0x00, 0xB3, 0x00, ++0xCC, 0x43, 0x32, 0x0B, 0xC4, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x81, 0x20, 0xC6, 0x00, 0x91, 0x00, 0x44, 0x0F, 0xF0, 0x11, 0x60, 0x61, 0x02, ++0x91, 0x02, 0x44, 0x02, 0x10, 0x0D, 0x40, 0x87, 0x04, 0x1D, 0x00, 0x5C, 0x1E, ++0xD1, 0x1D, 0x40, 0x34, 0x08, 0x11, 0x12, 0x74, 0x00, 0x10, 0x71, 0x40, 0x34, ++0x00, 0x11, 0x02, 0x4C, 0x0C, 0x10, 0x0D, 0x40, 0x33, 0x00, 0x11, 0x01, 0x44, ++0x2F, 0x15, 0x19, 0x40, 0x37, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0xA0, 0x46, 0x00, 0xD1, 0x04, 0x64, 0x04, 0xD0, 0x01, 0x40, 0x37, 0x20, 0x19, ++0x00, 0x04, 0x10, 0x10, 0x1D, 0x48, 0x17, 0x10, 0x1D, 0x00, 0x74, 0x05, 0x50, ++0x1D, 0x44, 0x34, 0x40, 0x51, 0x00, 0x74, 0x00, 0x10, 0x00, 0x40, 0x36, 0x00, ++0x81, 0x00, 0x04, 0x01, 0x10, 0x0D, 0x40, 0x37, 0x00, 0xD9, 0x01, 0x64, 0xC3, ++0x10, 0x19, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x00, 0x18, 0x81, 0x00, 0x04, 0x00, 0xD8, 0x08, 0x40, 0x26, 0x80, 0x41, 0x00, ++0x05, 0x04, 0x18, 0x0C, 0x40, 0x23, 0x00, 0x4D, 0x00, 0x34, 0x03, 0xD0, 0x1D, ++0x40, 0x30, 0x00, 0x81, 0x00, 0x74, 0x01, 0x18, 0x08, 0x50, 0x36, 0x00, 0x81, ++0x00, 0x04, 0x02, 0x14, 0x0C, 0x40, 0x37, 0x00, 0x89, 0x00, 0x04, 0x03, 0x10, ++0x00, 0x44, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x06, ++0x00, 0xD3, 0x00, 0x6C, 0x00, 0xF0, 0x05, 0x50, 0x37, 0x00, 0x1B, 0x00, 0x4C, ++0x00, 0x20, 0x0D, 0xC0, 0x13, 0x00, 0x9F, 0x00, 0x7C, 0x00, 0xF0, 0x0D, 0x50, ++0x38, 0x00, 0x53, 0x00, 0x7C, 0x02, 0x30, 0x05, 0xC0, 0x3F, 0x00, 0x53, 0x00, ++0x4C, 0x01, 0x30, 0x0D, 0xC0, 0x37, 0x10, 0x9B, 0x20, 0x6C, 0x81, 0x30, 0xA9, ++0xC0, 0x07, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0F, 0x00, ++0xBF, 0x00, 0xFC, 0x00, 0x70, 0x02, 0xC0, 0x2D, 0x00, 0x3F, 0x00, 0xFC, 0x00, ++0xF0, 0x0E, 0xC0, 0x0F, 0x00, 0x3F, 0x40, 0x9C, 0x02, 0xF0, 0x0B, 0xC0, 0x3F, ++0x00, 0x3F, 0x00, 0xBC, 0x00, 0x78, 0x03, 0xC0, 0x39, 0x00, 0x3E, 0x00, 0xDC, ++0x80, 0xF0, 0x0F, 0xC0, 0x3B, 0x00, 0xA7, 0x00, 0xFE, 0x03, 0xF0, 0x4B, 0xE0, ++0x17, 0x22, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0xDF, 0x00, 0xB3, ++0x08, 0xFC, 0x06, 0x70, 0x9F, 0xC8, 0x7E, 0x12, 0xF3, 0x09, 0xEC, 0x27, 0x11, ++0x1F, 0xC0, 0x7C, 0x00, 0xE3, 0x09, 0xDC, 0x27, 0xF0, 0x1F, 0xC0, 0x7C, 0x40, ++0xF3, 0x09, 0xBC, 0x0F, 0xF8, 0x1F, 0xC0, 0x7F, 0x00, 0xFF, 0x09, 0x9C, 0x07, ++0xF0, 0x1F, 0xC0, 0x5C, 0x00, 0x33, 0x01, 0xCC, 0x06, 0xF0, 0x1B, 0xC8, 0x0D, ++0x08, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x27, 0x01, 0x91, 0x20, ++0x44, 0x53, 0x10, 0x01, 0x40, 0x06, 0x00, 0x15, 0x00, 0x50, 0x00, 0x50, 0x11, ++0x40, 0x44, 0x08, 0x15, 0x00, 0x04, 0x10, 0xD2, 0x01, 0x41, 0x45, 0x00, 0x11, ++0x80, 0x74, 0x00, 0xD0, 0x11, 0x42, 0x03, 0x25, 0x11, 0x04, 0x64, 0x04, 0xD1, ++0x1F, 0x48, 0x74, 0x40, 0x15, 0x81, 0x54, 0x02, 0xD2, 0x09, 0x42, 0x0F, 0x60, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x37, 0x00, 0xC1, 0x44, 0x14, ++0x13, 0x50, 0x4D, 0x48, 0x37, 0x11, 0xD1, 0x84, 0x46, 0x13, 0x10, 0x0C, 0x62, ++0x30, 0x20, 0xC5, 0x04, 0x14, 0x03, 0xD0, 0x4D, 0x40, 0x30, 0x00, 0xC9, 0x44, ++0x14, 0x13, 0xD0, 0x0C, 0x40, 0x36, 0x10, 0xD5, 0x00, 0x14, 0x03, 0x58, 0x0C, ++0x40, 0x21, 0x00, 0x15, 0x20, 0x14, 0x00, 0xD8, 0x00, 0x40, 0x4F, 0x80, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x25, 0x10, 0xD1, 0x21, 0x64, 0x07, ++0x10, 0x01, 0x40, 0x07, 0x00, 0x15, 0x00, 0x54, 0x00, 0x50, 0x01, 0x70, 0x04, ++0x00, 0x15, 0x00, 0x54, 0x00, 0xD0, 0x01, 0x40, 0x05, 0x00, 0x19, 0x00, 0x74, ++0x00, 0xD0, 0x01, 0x42, 0x07, 0x00, 0x11, 0x00, 0x64, 0x00, 0xD0, 0x0D, 0x00, ++0x25, 0x00, 0x15, 0x01, 0x54, 0x44, 0xD0, 0x11, 0x41, 0x0F, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x13, 0x03, 0xD3, 0x31, 0x7C, 0x17, 0x70, ++0x0C, 0xC0, 0x37, 0x00, 0xD3, 0x00, 0x0C, 0x03, 0x30, 0x0D, 0xC0, 0x34, 0x30, ++0xD3, 0x00, 0x5C, 0x03, 0xF0, 0x0D, 0x02, 0x34, 0x00, 0xDB, 0x00, 0x7C, 0x03, ++0xD0, 0x0D, 0x40, 0x37, 0x20, 0xC7, 0x40, 0x5C, 0x03, 0xF0, 0x0D, 0xD0, 0x15, ++0x00, 0x06, 0x01, 0x5C, 0x0E, 0xF0, 0x39, 0xC0, 0x09, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0x80, 0x2D, 0x40, 0xDF, 0x00, 0xDC, 0x03, 0xF0, 0x03, ++0xC0, 0x0C, 0x00, 0x3F, 0x80, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x40, 0x3B, ++0x00, 0xEC, 0x00, 0xF0, 0x03, 0x08, 0x0F, 0x00, 0x37, 0x00, 0xFC, 0x00, 0xF0, ++0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xCC, 0x00, 0xD0, 0x0F, 0xC0, 0x3E, 0x81, ++0xBB, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x08, 0xB5, 0x00, 0xDF, 0x00, 0x4D, 0x03, 0x70, 0x8D, 0xC0, ++0x37, 0x01, 0xD3, 0x00, 0x7C, 0x03, 0x30, 0x8D, 0xC0, 0x37, 0x01, 0xD7, 0x00, ++0x4C, 0x03, 0x30, 0x0D, 0xC0, 0x37, 0x01, 0xDF, 0x00, 0x7C, 0x03, 0xB0, 0x0D, ++0xC2, 0x34, 0x00, 0xD7, 0x00, 0x6C, 0x13, 0xB0, 0x0C, 0xC0, 0x24, 0x01, 0x9F, ++0x00, 0x7C, 0x08, 0xF0, 0x21, 0x48, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x24, 0x00, 0xDD, 0x00, 0x44, 0x03, 0x10, 0x11, 0x40, 0x00, ++0x04, 0x0B, 0x00, 0x5C, 0x00, 0xB0, 0x00, 0x40, 0x83, 0x00, 0x1B, 0x00, 0x6E, ++0x00, 0x10, 0x00, 0x40, 0xC3, 0x00, 0x1D, 0x00, 0x5C, 0x00, 0x10, 0x01, 0xE8, ++0x03, 0x00, 0x11, 0x80, 0x44, 0x40, 0x10, 0x0D, 0xC0, 0x20, 0x01, 0x9D, 0x00, ++0x5C, 0x00, 0xD0, 0x11, 0x41, 0x4F, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0x20, 0x22, 0x00, 0x9D, 0x00, 0x44, 0x03, 0x50, 0x0C, 0x40, 0xB1, 0x00, ++0xC5, 0x00, 0x14, 0x03, 0x10, 0x1C, 0x40, 0x33, 0x00, 0xD1, 0x00, 0x04, 0x03, ++0x10, 0x0C, 0x48, 0x73, 0x00, 0xC9, 0x00, 0x34, 0x83, 0x90, 0x0C, 0x40, 0x30, ++0x00, 0xC5, 0x00, 0x24, 0x07, 0x80, 0x0C, 0x40, 0xE3, 0x00, 0x4D, 0x05, 0x36, ++0x12, 0xD0, 0x48, 0x40, 0x4F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x08, 0x6A, 0x00, 0xED, 0x09, 0x86, 0x07, 0x10, 0x13, 0x60, 0x4C, 0x00, 0x2D, ++0x01, 0xD4, 0x04, 0x90, 0x12, 0x40, 0x4F, 0x00, 0x38, 0x01, 0xA4, 0x04, 0x1C, ++0x12, 0x40, 0x4B, 0x04, 0x2D, 0x01, 0xD4, 0x04, 0x00, 0x13, 0x40, 0x49, 0x00, ++0x21, 0x01, 0xC4, 0x04, 0x50, 0x1C, 0x40, 0x79, 0x00, 0xED, 0x11, 0x94, 0x07, ++0xD0, 0x9A, 0x40, 0x37, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, ++0x32, 0x02, 0x0D, 0x08, 0x4C, 0x03, 0x50, 0x0C, 0x40, 0x31, 0x12, 0xD7, 0x00, ++0x1C, 0x03, 0x30, 0x0C, 0x40, 0x33, 0x00, 0xC7, 0x00, 0x04, 0x03, 0x30, 0x0C, ++0xC0, 0x33, 0x00, 0xCF, 0x08, 0x34, 0x13, 0xB0, 0x0D, 0x40, 0x30, 0x02, 0xD7, ++0x00, 0x2C, 0x03, 0xB0, 0x0C, 0xD0, 0x23, 0x02, 0xCF, 0x20, 0x3C, 0x42, 0xF0, ++0x8C, 0xC0, 0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x2D, ++0x00, 0x7F, 0x08, 0xF8, 0x03, 0xE0, 0x02, 0x80, 0x09, 0x00, 0x3B, 0x00, 0xA8, ++0x20, 0xF2, 0x81, 0xC0, 0x0B, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC8, ++0x07, 0x00, 0x3F, 0x28, 0x7C, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x40, ++0x54, 0x24, 0x20, 0x9D, 0xC0, 0x2C, 0x08, 0xFF, 0x00, 0xFC, 0x23, 0xF0, 0x8F, ++0xC2, 0x0B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x27, 0x00, ++0xDF, 0x00, 0x4C, 0x03, 0xF0, 0x1D, 0xC0, 0x35, 0x00, 0xDE, 0x00, 0x7C, 0x07, ++0x30, 0x1D, 0xC0, 0x34, 0x00, 0xDF, 0x00, 0x3C, 0x03, 0x30, 0x1D, 0xC0, 0x34, ++0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x3C, ++0x03, 0xB0, 0x0D, 0xC4, 0x24, 0x00, 0x5F, 0x00, 0x7C, 0x83, 0x30, 0x0D, 0xC2, ++0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x29, 0x00, 0xFD, ++0x00, 0x84, 0x03, 0xD0, 0x03, 0x40, 0x08, 0x00, 0x2D, 0x00, 0xB4, 0x00, 0x50, ++0x02, 0x00, 0x08, 0x88, 0x2D, 0x00, 0xB4, 0x00, 0x50, 0x02, 0x40, 0x09, 0x00, ++0x2F, 0x00, 0xA4, 0x00, 0xD1, 0x02, 0x48, 0x0B, 0x00, 0x2D, 0x20, 0xB6, 0x00, ++0x18, 0x4E, 0x40, 0x38, 0x20, 0xED, 0x00, 0xF4, 0x01, 0x10, 0x07, 0x40, 0x4C, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0x6D, 0x00, ++0x84, 0x47, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x81, 0xF4, 0x07, 0x18, 0x1F, ++0x48, 0x78, 0x80, 0xED, 0x01, 0xF6, 0x07, 0x13, 0x1F, 0x44, 0x7B, 0x80, 0xED, ++0x01, 0xB4, 0x87, 0x58, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x01, 0xF4, 0x07, 0xD8, ++0xDE, 0x40, 0x6A, 0x00, 0xED, 0x01, 0xB4, 0x07, 0x10, 0x1E, 0x40, 0x10, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x20, 0x23, 0x00, 0x4C, 0x00, 0x04, ++0x05, 0xD0, 0x00, 0x40, 0x00, 0x00, 0x0D, 0x00, 0x34, 0x00, 0x50, 0x00, 0x40, ++0x00, 0xA0, 0x0D, 0x00, 0x74, 0x00, 0x50, 0x00, 0x40, 0x03, 0x10, 0x05, 0x00, ++0x34, 0x00, 0xD0, 0x00, 0x40, 0x03, 0x00, 0x0D, 0x20, 0x34, 0x00, 0x51, 0x0C, ++0x50, 0x22, 0x00, 0x8D, 0x0F, 0x74, 0x0F, 0x1A, 0x6D, 0x40, 0x58, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x1F, 0x00, 0x7F, 0x10, 0xCC, 0x0D, ++0xF0, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0x30, 0x05, 0xD0, 0x14, ++0x00, 0x5F, 0x00, 0x7C, 0x01, 0x30, 0x05, 0xC0, 0x17, 0x00, 0x5D, 0x00, 0x7C, ++0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x3C, 0x01, 0xF0, 0x04, 0xC0, ++0x1A, 0x00, 0x7F, 0x00, 0xFC, 0x0D, 0x34, 0x07, 0xD0, 0x5C, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x00, 0x1F, 0x20, 0x7C, 0x40, 0xF2, ++0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x20, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x8F, 0x00, ++0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0D, 0x00, 0x3D, 0x00, 0xE4, 0x00, ++0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x20, 0xFC, 0x08, 0x90, 0x01, 0xC0, 0x05, ++0x00, 0x1F, 0x00, 0x7C, 0x28, 0xF0, 0x81, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x65, 0x00, 0x9F, 0x40, 0x7C, 0x02, 0xF0, 0x19, ++0xC0, 0x27, 0x00, 0x9F, 0x00, 0x5C, 0x82, 0xF0, 0x09, 0xC0, 0x27, 0x02, 0x9F, ++0x00, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0xE7, 0x80, 0x9F, 0x00, 0x4D, 0x02, 0x34, ++0x09, 0xC0, 0x27, 0x00, 0x9B, 0x00, 0x7C, 0x06, 0x72, 0x09, 0xC0, 0x24, 0x00, ++0x93, 0x05, 0x7C, 0x42, 0x30, 0x09, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x28, 0x66, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x19, 0x40, ++0x27, 0x00, 0x8D, 0x00, 0x44, 0x02, 0xD8, 0x19, 0x40, 0xE7, 0x20, 0x9D, 0x00, ++0x74, 0x02, 0x10, 0x09, 0x40, 0x27, 0x04, 0x97, 0x20, 0x44, 0x02, 0x30, 0x09, ++0x40, 0x23, 0x00, 0x91, 0x20, 0x70, 0x16, 0x30, 0x0B, 0xD0, 0x24, 0x00, 0x91, ++0x00, 0x74, 0x96, 0x50, 0x39, 0x40, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1C, 0xA0, 0x24, 0x02, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x89, 0x40, 0x6F, ++0x00, 0xBD, 0x00, 0xD4, 0x02, 0xD0, 0xAB, 0x40, 0x2F, 0x00, 0xBD, 0x00, 0xF4, ++0x02, 0x10, 0x0B, 0x60, 0x2F, 0x00, 0xAD, 0x00, 0x84, 0x02, 0x10, 0x0B, 0x40, ++0x2F, 0x80, 0xB9, 0x00, 0xF4, 0x12, 0x10, 0x69, 0x60, 0x36, 0x00, 0xD9, 0x02, ++0x74, 0x06, 0x10, 0x19, 0x41, 0x70, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x28, 0xA0, 0x00, 0x8D, 0x1C, 0x34, 0x22, 0xD0, 0x2A, 0x40, 0xEB, 0x00, ++0xBD, 0x08, 0x84, 0x22, 0xD0, 0x0A, 0x40, 0x2B, 0x00, 0xAD, 0x00, 0xB0, 0x22, ++0x10, 0x8A, 0x40, 0x2B, 0x00, 0xA5, 0x88, 0x84, 0x22, 0x10, 0x0A, 0x40, 0x2F, ++0x02, 0xA1, 0x08, 0xB4, 0x02, 0x14, 0x08, 0x64, 0x24, 0x08, 0x89, 0x00, 0x34, ++0x02, 0x50, 0x09, 0x40, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB0, 0x06, 0x00, 0x1F, 0x06, 0x7C, 0x08, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, ++0x02, 0x5C, 0x08, 0xD0, 0x01, 0xC0, 0x17, 0x00, 0x1D, 0x8A, 0x7C, 0x08, 0x34, ++0x21, 0xC0, 0x07, 0x00, 0x1D, 0x02, 0x44, 0x08, 0x30, 0x01, 0xC0, 0x87, 0x00, ++0x1B, 0x02, 0xFC, 0x00, 0x70, 0x11, 0xC0, 0x06, 0x40, 0x1B, 0x00, 0x7C, 0x28, ++0x32, 0xA1, 0xD0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, ++0x6F, 0x00, 0xBF, 0x04, 0xFC, 0x12, 0xF0, 0x19, 0x40, 0x67, 0x00, 0x9F, 0x44, ++0x3C, 0x12, 0xF2, 0x08, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x7C, 0x12, 0xF0, 0x48, ++0xC0, 0x27, 0x00, 0x97, 0x84, 0x7C, 0x12, 0x70, 0x09, 0xC2, 0x27, 0x01, 0x9F, ++0x84, 0x7C, 0x02, 0x70, 0x28, 0xC0, 0x2D, 0x00, 0xB7, 0x00, 0xFC, 0x02, 0xF0, ++0x0B, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, ++0x00, 0x93, 0x2C, 0x7C, 0x02, 0xF0, 0x0B, 0xC0, 0xAB, 0x00, 0x97, 0x00, 0x7C, ++0x02, 0xF0, 0x0B, 0xC0, 0x28, 0x00, 0x9F, 0x00, 0x7C, 0x22, 0xF0, 0x09, 0xC8, ++0x2D, 0x00, 0x93, 0x08, 0x5C, 0x02, 0x70, 0x09, 0xC0, 0x27, 0x02, 0x9F, 0x00, ++0xDC, 0x02, 0xB0, 0x1B, 0xC3, 0x2B, 0x00, 0xBF, 0x60, 0xFC, 0x82, 0x30, 0x0B, ++0xC0, 0x63, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, 0x54, 0x45, ++0x51, 0x4C, 0x74, 0x40, 0xD0, 0x51, 0x41, 0x47, 0x01, 0x11, 0x14, 0x74, 0x10, ++0xD0, 0x01, 0x40, 0x04, 0x08, 0x1D, 0x05, 0x74, 0x80, 0xD2, 0x41, 0x41, 0x04, ++0x00, 0x11, 0x04, 0x4C, 0x40, 0x10, 0x01, 0xC0, 0x05, 0x00, 0x1D, 0x14, 0x74, ++0x00, 0x10, 0x21, 0x42, 0x07, 0x08, 0x5D, 0x00, 0x74, 0x00, 0x50, 0x05, 0x40, ++0x73, 0x40, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x21, 0x00, 0x81, ++0x04, 0x34, 0x12, 0xD0, 0x08, 0x40, 0x23, 0x01, 0x85, 0x04, 0x34, 0x52, 0xD0, ++0x09, 0x62, 0x21, 0x00, 0x8D, 0x10, 0x34, 0x02, 0xD0, 0x48, 0x40, 0x25, 0x00, ++0x91, 0x04, 0x54, 0x12, 0x50, 0x08, 0x48, 0x23, 0x80, 0x8D, 0x04, 0x14, 0x02, ++0xD2, 0x08, 0x48, 0x23, 0x20, 0x8D, 0x20, 0x74, 0x02, 0x18, 0x08, 0x40, 0x4B, ++0x28, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x25, 0x00, 0x91, 0x00, ++0x74, 0x0A, 0xD0, 0x09, 0x40, 0x23, 0x00, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, ++0x00, 0x25, 0x80, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x00, 0x91, ++0x00, 0x54, 0x02, 0x10, 0x09, 0x40, 0x25, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, ++0x0D, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x76, 0x02, 0x50, 0x09, 0x40, 0x63, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x6F, 0x00, 0x93, 0x02, 0x78, ++0x02, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0x97, 0x00, 0x7C, 0x02, 0xF0, 0x08, 0xC0, ++0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0x48, 0x21, 0x40, 0x81, 0x00, ++0x54, 0x02, 0x70, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x1C, 0x02, 0xB0, 0x09, ++0xC0, 0xE7, 0x81, 0x9F, 0x02, 0x78, 0x42, 0x32, 0x29, 0xC0, 0x17, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0xA5, 0x00, 0x9F, 0x04, 0x7C, 0x26, ++0xF1, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xD0, 0x26, ++0x20, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC2, 0x27, 0x08, 0x9F, 0x00, 0x4C, ++0x02, 0xF0, 0x09, 0xC0, 0x25, 0x00, 0x9F, 0x80, 0x7C, 0x02, 0xBC, 0x09, 0xC0, ++0x67, 0x01, 0x9F, 0x09, 0x7C, 0x02, 0xF1, 0x49, 0xC0, 0x4B, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x05, 0x00, 0x1F, 0x02, 0x4D, 0x00, 0xF0, ++0x01, 0xC0, 0x06, 0x00, 0x13, 0x00, 0x7E, 0x00, 0x70, 0x01, 0xC0, 0x04, 0x00, ++0x17, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xE2, 0x07, 0x08, 0x1B, 0x00, 0x4C, 0x00, ++0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x40, 0xF0, 0x41, 0xC8, 0x87, ++0x40, 0x17, 0x00, 0x7C, 0x00, 0x34, 0x01, 0x87, 0x40, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x80, 0x54, 0x80, 0x5D, 0x00, 0x44, 0x01, 0x70, 0x45, ++0x40, 0x1C, 0x00, 0x5B, 0x00, 0x74, 0x01, 0x70, 0x07, 0x60, 0x9C, 0x00, 0x51, ++0x00, 0x74, 0x01, 0xD8, 0x05, 0xC0, 0x1F, 0x00, 0x55, 0x00, 0x1E, 0x01, 0x72, ++0x05, 0x40, 0x17, 0x08, 0x53, 0x00, 0xCC, 0x0D, 0xC0, 0x07, 0xC0, 0xDD, 0x01, ++0x70, 0x0A, 0xF0, 0x35, 0x10, 0x17, 0x50, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0xA0, 0x36, 0x10, 0xCD, 0x00, 0x16, 0x03, 0x50, 0x0C, 0x40, ++0x62, 0x00, 0xC1, 0x00, 0x34, 0x03, 0x58, 0x98, 0x48, 0xF3, 0x06, 0xCD, 0x00, ++0x34, 0x03, 0xD2, 0x0D, 0x40, 0xB3, 0x01, 0xC1, 0x00, 0x04, 0x03, 0x50, 0x0C, ++0x40, 0x33, 0x80, 0xC9, 0x00, 0x14, 0x0A, 0x90, 0x34, 0x40, 0xE3, 0x01, 0x81, ++0x02, 0x74, 0x03, 0x90, 0x0C, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x88, 0xB8, 0x11, 0xED, 0xA5, 0x96, 0x13, 0x50, 0x5E, 0x40, 0x9C, ++0x01, 0xE9, 0x08, 0xB4, 0x03, 0x50, 0x0B, 0x40, 0x5F, 0x00, 0xE9, 0x04, 0xB4, ++0x13, 0xD8, 0x0E, 0x40, 0x3D, 0x00, 0xF5, 0x00, 0x96, 0x13, 0x50, 0x0E, 0x40, ++0x7F, 0x03, 0xE1, 0x05, 0x90, 0x0B, 0xD0, 0x26, 0x60, 0x6D, 0x00, 0xE1, 0x82, ++0xB4, 0x02, 0x90, 0x1E, 0x41, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x11, 0x10, 0xF8, 0x00, 0xFD, 0x07, 0x9C, 0x17, 0x70, 0x1F, 0xC0, 0xFA, 0x01, ++0xE3, 0x01, 0xB4, 0x17, 0x70, 0x1E, 0x50, 0x6B, 0x00, 0xED, 0x05, 0xBC, 0x47, ++0xD0, 0x9E, 0x68, 0x7B, 0x08, 0xEB, 0x01, 0x84, 0x17, 0x70, 0x1E, 0xC0, 0x7B, ++0x00, 0xFB, 0x09, 0x9C, 0x07, 0xF0, 0x1E, 0x80, 0x6B, 0x00, 0xE6, 0x21, 0xFC, ++0x06, 0xB0, 0x1B, 0xC0, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA8, 0x35, 0x00, 0xDF, 0x00, 0x6C, 0x03, 0x70, 0x89, 0xC0, 0x17, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x0C, 0xC0, 0x24, 0x18, 0xD7, 0x00, 0x7C, 0xB3, 0xF0, ++0x4D, 0xC2, 0x23, 0x00, 0xC7, 0x92, 0x7C, 0x4B, 0x70, 0x0D, 0xC0, 0xB3, 0x04, ++0xDB, 0x08, 0x6C, 0x03, 0xF0, 0x0D, 0x80, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x02, ++0x70, 0x01, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, ++0x79, 0x00, 0xE3, 0x04, 0xCD, 0x53, 0x70, 0x1B, 0xC0, 0x7F, 0x40, 0xF2, 0x01, ++0xDC, 0x67, 0xF0, 0x1B, 0xC0, 0x6F, 0x00, 0xEF, 0x19, 0xCC, 0x07, 0x30, 0x1F, ++0x85, 0x7F, 0x00, 0xF3, 0x11, 0xFC, 0x67, 0x70, 0x1F, 0xC0, 0x7D, 0x00, 0xF7, ++0x01, 0xCD, 0x07, 0xF0, 0x17, 0xC0, 0x7F, 0x00, 0xFF, 0xC1, 0xF4, 0x07, 0xF2, ++0x1B, 0xC4, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x18, 0x39, ++0x00, 0xE1, 0x00, 0xAC, 0x03, 0x10, 0x0A, 0x40, 0x1B, 0x00, 0xE1, 0x08, 0xDC, ++0xC3, 0x11, 0x0A, 0xC0, 0x09, 0x09, 0xED, 0x00, 0x94, 0x23, 0x50, 0x0E, 0x42, ++0x1B, 0x00, 0xE1, 0x04, 0xDC, 0x03, 0x10, 0x8E, 0x40, 0x38, 0x00, 0xED, 0x00, ++0x84, 0x2B, 0xD0, 0x86, 0x40, 0x2B, 0x06, 0x6D, 0x08, 0xB4, 0x11, 0xD0, 0x4F, ++0xC0, 0x56, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, ++0xF1, 0x00, 0xC4, 0x23, 0x50, 0x8E, 0x41, 0x3B, 0x00, 0xE1, 0x00, 0xB4, 0x03, ++0x59, 0x8A, 0x41, 0x2A, 0x30, 0xFD, 0x10, 0xE6, 0x03, 0x90, 0x0E, 0x40, 0x3F, ++0x06, 0xE1, 0x20, 0xA6, 0x03, 0x51, 0x0F, 0x40, 0x39, 0x02, 0xED, 0x00, 0xA4, ++0x43, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x02, 0xD2, 0x0A, 0x40, ++0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x25, 0x02, 0xC1, ++0x09, 0x24, 0x07, 0x10, 0x08, 0x60, 0x53, 0x0E, 0xC1, 0x0A, 0x34, 0x07, 0x12, ++0x08, 0x41, 0xA3, 0x20, 0xCD, 0x02, 0x34, 0x1F, 0x50, 0x3C, 0x40, 0x43, 0x00, ++0xD1, 0x0B, 0x14, 0x37, 0x10, 0x3C, 0x40, 0x74, 0x00, 0xCD, 0x05, 0x24, 0x17, ++0xD1, 0x0C, 0x40, 0x23, 0x00, 0x4D, 0x26, 0x34, 0x18, 0xD0, 0x00, 0x42, 0x12, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x25, 0x40, 0xF3, 0x00, ++0xCD, 0x1B, 0x70, 0x2D, 0xC0, 0xB3, 0x00, 0xF3, 0x8A, 0xFC, 0x0B, 0x70, 0x18, ++0xC0, 0x26, 0x04, 0xFE, 0x01, 0xEC, 0x4F, 0xB0, 0x5F, 0xC0, 0x27, 0x40, 0xF3, ++0x00, 0xFC, 0x0B, 0x70, 0x9C, 0xC0, 0xBD, 0x02, 0xE7, 0x06, 0x6C, 0x0F, 0xD0, ++0x05, 0xC0, 0xE7, 0x00, 0x8D, 0x06, 0x7E, 0x00, 0xF0, 0x01, 0xD0, 0x56, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x04, 0xDF, 0x00, 0x7C, ++0x43, 0xF0, 0x0D, 0xC0, 0xB7, 0x00, 0xDF, 0x00, 0x5C, 0x03, 0x70, 0x29, 0xC0, ++0x05, 0x00, 0xDF, 0x00, 0x5C, 0x03, 0xF0, 0x0D, 0xC0, 0xA7, 0x88, 0xDF, 0x00, ++0x7C, 0x03, 0x72, 0x8D, 0xC0, 0x37, 0x82, 0xDF, 0x00, 0x5C, 0x0B, 0xB0, 0x25, ++0x88, 0xA7, 0x09, 0x9F, 0x02, 0x7C, 0x0C, 0xF0, 0x01, 0xC1, 0x05, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x3F, 0x00, 0xFB, 0x00, 0xFC, 0x03, ++0xF0, 0x0F, 0xC1, 0x5F, 0x08, 0xF3, 0x00, 0xFC, 0x43, 0xF0, 0x03, 0xC2, 0x2C, ++0x0C, 0xFF, 0x10, 0xF8, 0x83, 0xF0, 0x0F, 0xC1, 0x0D, 0x04, 0xFB, 0x90, 0xCC, ++0x03, 0xF1, 0x0F, 0xC0, 0x3F, 0x00, 0xF7, 0x40, 0xE8, 0x03, 0xD0, 0x27, 0xC0, ++0x6F, 0x00, 0x33, 0x00, 0xCC, 0x02, 0xF0, 0x03, 0xC0, 0x13, 0x22, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x85, 0x20, 0x36, 0x08, 0xD1, 0x00, 0x74, 0x83, 0xD0, ++0x09, 0x60, 0x16, 0x0A, 0xD1, 0x00, 0x74, 0x03, 0xD2, 0x15, 0x40, 0x64, 0x00, ++0xDD, 0x00, 0x5C, 0x03, 0xD0, 0x0D, 0x40, 0xC4, 0x04, 0xDD, 0x00, 0x44, 0x03, ++0xD8, 0x0D, 0x40, 0x34, 0x00, 0xD1, 0x00, 0x44, 0x07, 0xC0, 0x25, 0x42, 0xE3, ++0xC0, 0x13, 0x05, 0x44, 0x4E, 0xD0, 0x31, 0x40, 0x17, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0xA2, 0x64, 0x20, 0xD9, 0x00, 0x74, 0x03, 0xD0, 0x09, ++0x48, 0x37, 0x04, 0xD1, 0x00, 0x74, 0x03, 0x50, 0x19, 0x41, 0x45, 0x20, 0xDD, ++0x00, 0x74, 0x03, 0x50, 0x0C, 0x40, 0x67, 0x00, 0xDD, 0x00, 0x64, 0x03, 0xD0, ++0x0D, 0x40, 0x36, 0x00, 0xD5, 0x00, 0x76, 0x07, 0xD0, 0x05, 0x40, 0xB7, 0x01, ++0x91, 0x01, 0x44, 0x04, 0xD2, 0x39, 0x42, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x28, 0x20, 0x00, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x08, 0x40, ++0x33, 0x08, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x09, 0x40, 0x40, 0x00, 0xCD, 0x00, ++0x14, 0x03, 0xD0, 0x0C, 0x40, 0x00, 0x00, 0xCD, 0x00, 0x24, 0x03, 0xD0, 0x0D, ++0x40, 0x30, 0x00, 0xD1, 0x00, 0x16, 0x83, 0xD0, 0x04, 0x40, 0x13, 0x10, 0x01, ++0x00, 0x05, 0x00, 0xD0, 0x08, 0x60, 0x43, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xB0, 0x26, 0x00, 0xDB, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0x48, 0x13, ++0x40, 0xD3, 0x80, 0x7C, 0x03, 0xF1, 0x01, 0xD0, 0x04, 0x00, 0xDE, 0x00, 0xFC, ++0x03, 0x72, 0x0F, 0xC4, 0x05, 0x00, 0xFF, 0x00, 0xEC, 0x03, 0xD0, 0x0D, 0xC0, ++0x3E, 0x00, 0xE7, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0xC4, 0x37, 0x88, 0x11, 0x00, ++0x4C, 0x82, 0xF0, 0x09, 0xC0, 0x01, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xA8, 0x2F, 0x10, 0xFF, 0x00, 0xBC, 0x03, 0xF0, 0x0B, 0xC0, 0x1E, 0x00, ++0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0xC0, 0x0E, 0x00, 0xFF, 0x00, 0x9C, 0x03, ++0xF0, 0x0F, 0xC8, 0x0B, 0x00, 0xFF, 0x00, 0xDC, 0x03, 0xF0, 0x0E, 0x40, 0x3F, ++0x00, 0xFF, 0x00, 0xEC, 0x01, 0xF0, 0x0B, 0xC2, 0x1F, 0x08, 0x37, 0x00, 0xFC, ++0x00, 0xE1, 0x03, 0xC0, 0x17, 0x22, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA0, 0x2F, 0x00, 0x3B, 0x14, 0xBC, 0x0F, 0x34, 0x1F, 0xC0, 0x7E, 0x02, 0xFF, ++0x09, 0xFC, 0x07, 0xB0, 0x1F, 0xC0, 0x7C, 0x00, 0xF3, 0x09, 0x8C, 0x27, 0x72, ++0x1F, 0xC4, 0x7E, 0x02, 0xFB, 0x29, 0xCC, 0x07, 0xF0, 0x1F, 0xC0, 0x7C, 0x20, ++0xF3, 0x09, 0xCC, 0x27, 0x30, 0x83, 0xC2, 0x7C, 0x02, 0xF3, 0x24, 0xEE, 0x1A, ++0x30, 0x4B, 0xC4, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, ++0x27, 0x20, 0x01, 0x02, 0x74, 0x13, 0x18, 0x11, 0x40, 0x00, 0x00, 0x1D, 0x80, ++0x74, 0x04, 0x40, 0x11, 0x40, 0x00, 0x04, 0x11, 0x00, 0x44, 0x10, 0x10, 0x40, ++0x40, 0x00, 0x00, 0x11, 0x04, 0x44, 0x04, 0xD0, 0x11, 0x41, 0x44, 0x00, 0x13, ++0x44, 0x44, 0x10, 0x30, 0x65, 0x40, 0x34, 0x00, 0xF5, 0x0B, 0x6E, 0x10, 0x10, ++0x11, 0x40, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x02, ++0x40, 0x01, 0x40, 0x36, 0x03, 0x50, 0x0D, 0x50, 0x30, 0x01, 0xCD, 0x84, 0x34, ++0x03, 0x81, 0x0D, 0x50, 0x30, 0x01, 0xC1, 0x00, 0x24, 0x13, 0xD0, 0x0C, 0x41, ++0x30, 0x01, 0xC1, 0x04, 0x24, 0x03, 0xD0, 0x4D, 0x40, 0x34, 0x00, 0xC9, 0x04, ++0x24, 0x03, 0x10, 0x28, 0x40, 0x31, 0x81, 0xCD, 0x20, 0x04, 0x1A, 0x11, 0x88, ++0x40, 0x45, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x15, 0x00, ++0x11, 0x22, 0x34, 0x03, 0x50, 0x01, 0x44, 0x04, 0x00, 0x1D, 0x00, 0x74, 0x80, ++0x90, 0x01, 0x40, 0x04, 0x00, 0x01, 0x00, 0x24, 0x00, 0x90, 0x01, 0x40, 0x04, ++0x00, 0x01, 0x00, 0x67, 0x00, 0xD0, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x64, ++0x00, 0x10, 0x4D, 0x42, 0x36, 0x08, 0xDD, 0x00, 0x47, 0x04, 0x10, 0x19, 0x41, ++0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x67, 0x40, 0x1B, ++0x01, 0x7C, 0x27, 0x50, 0x0C, 0xC8, 0x34, 0x20, 0xDF, 0x80, 0x3C, 0x03, 0xB4, ++0x0C, 0xC0, 0x34, 0x00, 0xD3, 0x00, 0x6C, 0x03, 0xF0, 0x0D, 0xC0, 0x34, 0x00, ++0xD3, 0x00, 0x6C, 0x03, 0xF2, 0x0C, 0x80, 0x30, 0x00, 0xDB, 0x00, 0x6D, 0x03, ++0x34, 0x01, 0xD1, 0x35, 0x00, 0xDF, 0x40, 0x44, 0x04, 0x22, 0x31, 0xC0, 0x01, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x69, 0x01, 0x3F, 0x03, ++0xF8, 0x03, 0xB0, 0x03, 0x80, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0x70, 0x03, ++0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xDD, 0x00, 0x70, 0x03, 0xD0, 0x0D, 0x00, 0x37, ++0x00, 0xDC, 0x00, 0xF0, 0x03, 0xC4, 0x0F, 0x00, 0x3F, 0x00, 0xDC, 0x00, 0xF1, ++0x07, 0xC0, 0x3D, 0x20, 0xF7, 0x00, 0xF4, 0x00, 0xF5, 0x03, 0xC3, 0x1E, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x81, 0x37, 0x0A, 0x4D, ++0x03, 0x30, 0x0D, 0xC0, 0x77, 0x41, 0xD3, 0x05, 0x5C, 0x03, 0x30, 0x8D, 0xC0, ++0x35, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x34, 0x00, 0xD3, 0x01, ++0x4C, 0x03, 0x70, 0x0D, 0xC0, 0x34, 0x02, 0xD7, 0x01, 0x7C, 0x03, 0xF0, 0x09, ++0xC0, 0x37, 0x00, 0xDF, 0x10, 0x74, 0x8A, 0x33, 0x21, 0xC4, 0x0B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xB4, 0x00, 0x11, 0x81, 0x44, 0x03, ++0x10, 0x41, 0x44, 0x47, 0x00, 0x11, 0x03, 0x74, 0x00, 0xB0, 0x11, 0x40, 0x04, ++0x00, 0x11, 0x20, 0x74, 0x00, 0x14, 0x01, 0x48, 0x04, 0x00, 0x10, 0x01, 0x44, ++0x44, 0xD0, 0x11, 0x40, 0x44, 0x08, 0x11, 0x01, 0x64, 0x00, 0xD0, 0x0D, 0xC0, ++0x37, 0x10, 0xE0, 0x13, 0x34, 0x04, 0x10, 0x30, 0x00, 0x4F, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x22, 0x00, 0x41, 0x00, 0x25, 0x03, 0x50, ++0x1C, 0x40, 0xB3, 0x00, 0xC9, 0x02, 0x34, 0x43, 0x90, 0x0C, 0x41, 0x35, 0x80, ++0xC1, 0x00, 0x34, 0x03, 0x10, 0x0D, 0x40, 0x36, 0x00, 0xC1, 0x00, 0x34, 0x07, ++0x50, 0x8C, 0x40, 0x71, 0x80, 0xC9, 0x00, 0x74, 0x03, 0xD0, 0x01, 0x40, 0x36, ++0x08, 0xC4, 0x02, 0x34, 0x02, 0x54, 0x28, 0x02, 0x1F, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x80, 0x78, 0x40, 0x61, 0x09, 0xE4, 0x07, 0x10, 0x12, ++0x40, 0x4B, 0x00, 0x29, 0x09, 0xB4, 0x24, 0x90, 0x92, 0x40, 0x48, 0x00, 0x21, ++0x01, 0xF6, 0x24, 0x10, 0x12, 0x40, 0x4A, 0x00, 0x21, 0x01, 0xB4, 0x04, 0xD0, ++0x13, 0x40, 0x4D, 0x08, 0x29, 0x09, 0xA6, 0x04, 0xC0, 0x12, 0x40, 0x7B, 0x30, ++0xE9, 0x01, 0xB4, 0x66, 0x50, 0x12, 0x41, 0x1B, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x10, 0x04, 0x40, 0x45, 0x00, 0x2C, 0x03, 0x70, 0x8C, 0xC0, ++0x33, 0x00, 0xCB, 0x00, 0x1C, 0x23, 0x30, 0x0C, 0xC0, 0x31, 0x90, 0xC3, 0x00, ++0x3C, 0x03, 0x30, 0x0C, 0xC0, 0x32, 0x00, 0xD3, 0x00, 0x34, 0x03, 0x70, 0x0C, ++0xC0, 0x31, 0x00, 0xCE, 0x80, 0x3E, 0x03, 0xF0, 0x00, 0xC0, 0x37, 0x00, 0xC7, ++0x08, 0x3C, 0x22, 0x70, 0x08, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xB0, 0x1D, 0x00, 0x7F, 0x00, 0xDE, 0x03, 0xF0, 0x03, 0x60, 0x0F, ++0x00, 0x37, 0x00, 0xBC, 0x20, 0xF0, 0x02, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xF4, ++0x00, 0xF0, 0x03, 0xC0, 0x0D, 0x00, 0x3F, 0x00, 0xCD, 0x00, 0xF0, 0x02, 0xC0, ++0x0A, 0x00, 0x37, 0x80, 0xEE, 0x04, 0xF0, 0x03, 0xC0, 0x3D, 0x82, 0xF7, 0x38, ++0xBC, 0x22, 0xB0, 0x89, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0xA0, 0x37, 0x40, 0x13, 0x00, 0x6C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x40, ++0xD3, 0x01, 0x0D, 0x03, 0xB0, 0x1C, 0xD0, 0x34, 0x00, 0xDF, 0x00, 0x3C, 0x07, ++0xB4, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x01, 0x0D, 0x07, 0x30, 0x0D, 0xC0, 0x37, ++0x00, 0xDF, 0x01, 0x6D, 0x03, 0x70, 0x0D, 0xC0, 0x37, 0x80, 0xDF, 0x04, 0x3C, ++0x00, 0x30, 0x19, 0xC0, 0x54, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x88, 0x39, 0x00, 0x31, 0x00, 0x85, 0x03, 0xD0, 0x02, 0x40, 0x0F, 0x00, 0x31, ++0x00, 0x84, 0x00, 0x30, 0x02, 0x40, 0x08, 0x00, 0x2D, 0x00, 0xB4, 0x00, 0x10, ++0x02, 0x40, 0x0B, 0x00, 0x3D, 0x00, 0xA4, 0x00, 0x70, 0x02, 0x40, 0x0B, 0x00, ++0x37, 0x00, 0x8C, 0x80, 0xD0, 0x0E, 0xC0, 0x39, 0x00, 0xED, 0x14, 0x9C, 0x00, ++0x14, 0x03, 0xC0, 0x4A, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, ++0x79, 0x00, 0x29, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xE1, 0x01, ++0x94, 0x07, 0x90, 0x1F, 0x40, 0x78, 0x00, 0xED, 0x01, 0xF4, 0x07, 0x10, 0x1E, ++0x40, 0x7B, 0x00, 0xED, 0x01, 0xA4, 0x07, 0x10, 0x1E, 0x40, 0x7B, 0x00, 0xED, ++0x01, 0x84, 0x87, 0x50, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x85, 0x94, 0x06, 0x55, ++0x1B, 0x40, 0x0D, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x77, ++0x02, 0x91, 0x10, 0x04, 0x06, 0xD0, 0x00, 0x40, 0x07, 0x00, 0x01, 0x00, 0x14, ++0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x0C, 0x00, 0x34, 0x00, 0x10, 0x00, 0x40, ++0x03, 0x00, 0x0D, 0x00, 0x24, 0x00, 0x50, 0x01, 0x40, 0x03, 0x10, 0x05, 0x40, ++0x04, 0x00, 0xD0, 0xEC, 0x40, 0x31, 0x00, 0xCD, 0x00, 0x14, 0x0B, 0x50, 0x8C, ++0x40, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x9D, 0x00, ++0x7B, 0x87, 0x6C, 0x41, 0xF1, 0x05, 0xC0, 0x17, 0x00, 0x53, 0x00, 0x5C, 0x01, ++0xB4, 0x05, 0xC8, 0x14, 0x10, 0x5F, 0x00, 0x7C, 0x01, 0x30, 0x05, 0xC4, 0x17, ++0x00, 0x5F, 0x00, 0x44, 0x01, 0x30, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x4C, ++0x01, 0x70, 0x37, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x9E, 0x21, 0x50, 0xB7, 0x40, ++0x5D, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x04, 0x1F, ++0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x40, 0xE8, 0x00, 0x70, ++0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x20, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, ++0x3F, 0x00, 0xDC, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x00, 0x37, 0x20, 0xDC, 0x00, ++0xF0, 0x01, 0xE0, 0x05, 0x00, 0x1F, 0x00, 0x5E, 0x80, 0x90, 0x01, 0x80, 0x4A, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x26, 0x02, 0x93, 0x00, ++0x5C, 0x02, 0xF0, 0x89, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x7C, 0x16, 0x30, 0x09, ++0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x93, ++0x00, 0x5C, 0x02, 0xF0, 0x19, 0xC0, 0x27, 0x00, 0x9F, 0x02, 0x7C, 0x02, 0x30, ++0x09, 0xC0, 0x24, 0x10, 0x9F, 0x80, 0x7E, 0x26, 0x30, 0x89, 0xC2, 0x43, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x66, 0x00, 0x91, 0x20, 0x44, ++0x02, 0x90, 0x19, 0x44, 0xA7, 0x00, 0x91, 0x02, 0x34, 0x02, 0x10, 0x09, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x08, 0x50, 0x20, 0x40, 0x91, 0x02, ++0x74, 0x02, 0xD0, 0x19, 0x40, 0x24, 0x00, 0x9F, 0x02, 0x34, 0x02, 0x10, 0x09, ++0x40, 0x24, 0x00, 0x9D, 0x02, 0x74, 0x06, 0x14, 0x39, 0x40, 0x07, 0x00, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x40, 0x91, 0x00, 0x44, 0x02, ++0xD0, 0x09, 0x40, 0x2F, 0x00, 0xB1, 0x00, 0xF4, 0x02, 0x10, 0x0B, 0x40, 0x2F, ++0x00, 0xBD, 0x00, 0xF4, 0x82, 0xD0, 0x0B, 0x40, 0x2C, 0x00, 0xB1, 0x00, 0xF4, ++0x22, 0xD0, 0x4B, 0x40, 0x2E, 0x01, 0xBD, 0x00, 0xF4, 0x02, 0x10, 0x08, 0x40, ++0x24, 0x00, 0x9D, 0x0A, 0x54, 0x03, 0x10, 0x09, 0x40, 0x63, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x41, 0x81, 0x04, 0x05, 0x02, 0x90, ++0x0A, 0x40, 0x6B, 0x00, 0xA1, 0x01, 0xF4, 0x02, 0x15, 0x0E, 0x42, 0x2B, 0x00, ++0xAD, 0x00, 0xB4, 0x82, 0xD0, 0x0B, 0x40, 0x2C, 0x00, 0xA1, 0x01, 0xB6, 0x02, ++0xD0, 0x0A, 0x40, 0x28, 0x00, 0xAD, 0x01, 0xF4, 0x02, 0x14, 0x48, 0x40, 0x20, ++0x02, 0x8D, 0x04, 0x34, 0x12, 0x10, 0x4C, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xB0, 0x82, 0x02, 0x13, 0x0A, 0x5C, 0x28, 0xF0, 0x01, ++0xC0, 0x87, 0x42, 0x13, 0x0A, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x87, 0x02, 0x1F, ++0x0A, 0x7C, 0x28, 0xD0, 0xA1, 0xC0, 0x84, 0x02, 0x13, 0x0A, 0x7C, 0x00, 0xF0, ++0xA1, 0xC0, 0x07, 0x00, 0x1F, 0x0A, 0xFC, 0x28, 0x30, 0xA1, 0xD0, 0x84, 0x10, ++0x1F, 0x00, 0x7C, 0x28, 0x30, 0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x19, 0xB8, 0x3F, 0x02, 0xBF, 0x08, 0xFC, 0x02, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x80, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0x80, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x97, 0x00, 0x7C, 0x02, 0xF0, 0x8B, 0xC0, 0x27, 0x21, 0x9F, ++0x08, 0xFC, 0x23, 0xF8, 0x8B, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x19, 0xA0, 0x2F, 0x05, 0xA3, 0x8C, 0x5C, 0x02, 0x35, 0x0B, 0xC0, 0x2F, ++0x02, 0xBF, 0x00, 0xFC, 0x02, 0x70, 0x0B, 0xE0, 0x25, 0x00, 0x9F, 0x00, 0x4D, ++0x22, 0xF1, 0x09, 0xC0, 0x24, 0x00, 0xBF, 0x08, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, ++0x2E, 0x00, 0xBF, 0x00, 0x7C, 0x02, 0x30, 0xC9, 0xE2, 0x24, 0x80, 0xBF, 0xA0, ++0xC8, 0x83, 0x30, 0x0B, 0xC0, 0x67, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1C, 0x08, 0x03, 0x01, 0x11, 0x0C, 0x45, 0x40, 0x10, 0x01, 0x40, 0x03, 0x00, ++0x1D, 0x14, 0x74, 0x00, 0x10, 0x01, 0x40, 0x04, 0x04, 0x1D, 0x10, 0x44, 0x00, ++0xD0, 0x41, 0x41, 0x04, 0x01, 0x0D, 0x04, 0x74, 0x00, 0xD0, 0x01, 0x41, 0x04, ++0x10, 0x0D, 0x54, 0x74, 0x10, 0x50, 0xC1, 0x50, 0x04, 0x24, 0x1D, 0x00, 0x45, ++0x00, 0x10, 0x01, 0x40, 0x73, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA0, 0x23, 0x05, 0x81, 0x04, 0x04, 0x12, 0x10, 0x08, 0x40, 0x23, 0x00, 0x8D, ++0x04, 0x34, 0x02, 0x50, 0x08, 0x40, 0x20, 0x01, 0x8D, 0x00, 0x14, 0x02, 0xD0, ++0x49, 0x50, 0x20, 0x05, 0x8D, 0x04, 0x34, 0x03, 0xD0, 0x08, 0x40, 0x22, 0x00, ++0x8D, 0x04, 0x34, 0x52, 0x50, 0x58, 0x40, 0x21, 0x01, 0x8D, 0xA8, 0x04, 0x82, ++0x10, 0x08, 0x40, 0x43, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, ++0x25, 0x40, 0x91, 0x02, 0x44, 0x22, 0x10, 0x09, 0x40, 0x37, 0x00, 0x9D, 0x00, ++0x74, 0x02, 0x50, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x56, 0x02, 0xC0, 0x09, ++0x40, 0x24, 0x00, 0xDD, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x00, 0xDD, ++0x00, 0x34, 0x02, 0x50, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x40, 0x06, 0x02, 0x14, ++0x49, 0x40, 0x63, 0x28, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0xA3, ++0x00, 0x93, 0x00, 0x4C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0x50, 0x08, 0x50, 0x25, 0x08, 0x9F, 0x00, 0x5C, 0x02, 0xF2, 0x09, 0xC8, ++0x24, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x26, 0x00, 0x9D, 0x00, ++0x7C, 0x02, 0x34, 0x09, 0x40, 0x25, 0x00, 0x9D, 0x80, 0x4C, 0x0A, 0x20, 0x09, ++0xC1, 0x17, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x65, 0x02, ++0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xB0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x6C, 0x02, 0xF0, 0x09, 0xC4, 0x27, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x10, 0x64, ++0x02, 0xB0, 0x08, 0xC0, 0x27, 0x00, 0x8F, 0x10, 0x7C, 0x0A, 0xF0, 0x09, 0xC2, ++0x53, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x85, 0x20, 0x13, ++0x40, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x00, 0x4C, 0x90, 0xE2, ++0x01, 0xC0, 0x07, 0x20, 0x1F, 0x00, 0x6C, 0x00, 0xD0, 0x01, 0xC0, 0x07, 0x00, ++0x1F, 0x08, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x02, 0x13, 0x00, 0x4C, 0x00, ++0xF0, 0x01, 0xC0, 0x05, 0x08, 0x1D, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x50, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x1C, 0x02, 0x51, 0x81, ++0x45, 0x01, 0x70, 0x15, 0x40, 0x5F, 0x01, 0x71, 0x00, 0x84, 0x0D, 0x10, 0x97, ++0x40, 0x17, 0x00, 0x5D, 0x00, 0x70, 0x01, 0x98, 0x04, 0x40, 0x17, 0x00, 0x7D, ++0x00, 0x44, 0x01, 0x70, 0x05, 0x40, 0x57, 0x00, 0x7B, 0x03, 0x44, 0x01, 0xC0, ++0x05, 0x40, 0x17, 0x10, 0x7C, 0x02, 0x74, 0x01, 0x10, 0x07, 0x00, 0x50, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x72, 0x00, 0xD1, 0x00, 0x44, ++0x03, 0x50, 0x88, 0x40, 0x73, 0x40, 0xC5, 0x08, 0x04, 0x0B, 0x50, 0x2C, 0x40, ++0x33, 0x00, 0xDD, 0x00, 0x24, 0x03, 0xD2, 0x0C, 0x44, 0x33, 0x00, 0xCD, 0x10, ++0x25, 0x02, 0x50, 0x1D, 0x40, 0x63, 0x00, 0xC1, 0x0A, 0x25, 0x03, 0xD0, 0x0C, ++0x60, 0x33, 0x00, 0x4D, 0x0B, 0x34, 0x02, 0x50, 0x0C, 0x00, 0x50, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x38, 0x04, 0xB1, 0x02, 0x84, 0x33, ++0x50, 0x0E, 0x40, 0x5B, 0x00, 0x65, 0x01, 0x84, 0x43, 0x10, 0x0A, 0x41, 0x3B, ++0x01, 0xED, 0x04, 0xB4, 0x23, 0x90, 0x0E, 0x40, 0x3B, 0x10, 0xED, 0x01, 0xA4, ++0x03, 0x50, 0x2E, 0x40, 0x7B, 0x00, 0xE9, 0x21, 0xA6, 0x03, 0xD0, 0x4E, 0x40, ++0x3B, 0x01, 0x69, 0x00, 0xB4, 0x03, 0x58, 0x1C, 0x44, 0x10, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x78, 0x02, 0xE3, 0x01, 0x9C, 0x27, 0x71, ++0x1E, 0xC0, 0x7B, 0x20, 0xF7, 0x01, 0x8D, 0x06, 0x70, 0x1E, 0xC0, 0x7B, 0x00, ++0xED, 0x05, 0xAC, 0x87, 0xD0, 0x3E, 0xC0, 0x7B, 0x02, 0xEF, 0x01, 0xAC, 0x07, ++0x70, 0x1E, 0xC0, 0x7B, 0x00, 0xE3, 0x01, 0xAC, 0x97, 0xF0, 0x9E, 0xE0, 0x7B, ++0x20, 0x6D, 0x21, 0xBC, 0x07, 0x74, 0x1E, 0xC2, 0x50, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xB0, 0xBD, 0x40, 0x9F, 0x06, 0x7C, 0x03, 0x70, 0x0D, ++0xC0, 0x17, 0x00, 0x5B, 0x00, 0x3C, 0x02, 0x70, 0x09, 0xC0, 0x37, 0x04, 0xDF, ++0x02, 0x7C, 0x0B, 0xF0, 0x2D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x5C, 0x03, 0x60, ++0x0D, 0xC0, 0x33, 0x00, 0x9F, 0x00, 0x5C, 0x0B, 0xF0, 0xAD, 0xC0, 0x37, 0x00, ++0x1F, 0x00, 0x3C, 0x5B, 0xB0, 0x09, 0xC2, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xA0, 0x4F, 0x40, 0xB3, 0x03, 0xCC, 0x13, 0xF0, 0x1E, 0xC0, ++0x6C, 0x00, 0xBF, 0x01, 0x8C, 0x06, 0x30, 0x1B, 0xC0, 0x7B, 0x04, 0xF3, 0x13, ++0xCC, 0x0F, 0x30, 0x3F, 0xC0, 0x7F, 0x04, 0xFF, 0x81, 0xFC, 0x87, 0xB0, 0x1F, ++0xC0, 0x7F, 0x00, 0xBF, 0x01, 0xFC, 0x4F, 0xF0, 0x1F, 0xC0, 0x7C, 0x04, 0x7F, ++0x09, 0xCC, 0x06, 0x30, 0x9D, 0xC2, 0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0x88, 0x09, 0x00, 0xA1, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x08, ++0x04, 0x2D, 0x44, 0x84, 0x02, 0x10, 0x0A, 0x40, 0x3B, 0x00, 0xE1, 0x00, 0xC4, ++0x03, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xAD, 0x10, 0xB4, 0x03, 0x10, 0x0E, 0x40, ++0x3B, 0x00, 0xAD, 0x10, 0xBC, 0x23, 0xD0, 0x0E, 0xC0, 0x3A, 0x00, 0x6D, 0x08, ++0x84, 0x03, 0x11, 0x3E, 0x40, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x08, 0x00, 0x11, 0x00, 0x81, 0x00, 0x84, 0x63, 0xD0, 0x0F, 0x40, 0x2A, 0x00, ++0xAD, 0x00, 0xC6, 0x02, 0x10, 0x0A, 0x40, 0xBF, 0x00, 0xF1, 0x02, 0x84, 0x23, ++0x10, 0x0E, 0x40, 0x3B, 0x00, 0x6D, 0x08, 0xF4, 0x03, 0x10, 0x0E, 0x40, 0x3B, ++0x02, 0x6D, 0x08, 0xB4, 0x03, 0xD0, 0x0C, 0x40, 0x38, 0x02, 0xCD, 0x48, 0x86, ++0x03, 0x50, 0x8E, 0x40, 0x23, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++0x28, 0x13, 0x00, 0x81, 0x42, 0x06, 0x07, 0xD0, 0x4C, 0x40, 0x42, 0x01, 0x0D, ++0x0D, 0x04, 0x0E, 0x10, 0x68, 0x40, 0x73, 0x00, 0xC1, 0x01, 0x04, 0x43, 0x10, ++0x1C, 0x41, 0x33, 0x04, 0x0D, 0x05, 0x34, 0x43, 0x18, 0x38, 0x40, 0x73, 0x00, ++0x1D, 0x05, 0x16, 0x2B, 0xD1, 0x0C, 0x50, 0x30, 0x08, 0x0D, 0x00, 0x40, 0x0B, ++0x58, 0x28, 0x41, 0x1B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, ++0x21, 0x11, 0xD1, 0x02, 0xCC, 0x07, 0xF0, 0x2C, 0xC0, 0xF6, 0x00, 0xDF, 0x02, ++0x4D, 0x44, 0x34, 0x1D, 0xC0, 0x3F, 0x00, 0xE3, 0x04, 0xC4, 0x07, 0x30, 0x0F, ++0x40, 0x7B, 0x00, 0x1F, 0x03, 0x3C, 0x0B, 0x30, 0x9D, 0x40, 0xB7, 0x04, 0x5F, ++0x03, 0xB4, 0x07, 0xF0, 0x0F, 0x00, 0x3C, 0x00, 0xDF, 0x00, 0x4C, 0x22, 0x72, ++0x3D, 0xC4, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x87, ++0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x1D, 0xC0, 0x25, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x8D, 0xC0, 0x37, 0x22, 0xDF, 0x00, 0x7C, 0x23, 0xF0, 0x8D, 0xC0, ++0x37, 0x02, 0x1F, 0x02, 0x7C, 0x07, 0x70, 0x8D, 0xC0, 0x37, 0x01, 0x5F, 0x40, ++0x7C, 0x43, 0xF0, 0x1D, 0xC0, 0x37, 0x00, 0xDD, 0x02, 0x7C, 0x07, 0x96, 0x1D, ++0x40, 0x27, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x2F, 0x80, ++0xF3, 0x10, 0xCC, 0x03, 0xF0, 0x1F, 0xC0, 0x9C, 0x20, 0x7F, 0x00, 0xCC, 0x51, ++0x70, 0x0F, 0xC0, 0x3F, 0x00, 0xF3, 0x20, 0xCC, 0x03, 0xF0, 0x0F, 0xC4, 0x3F, ++0x80, 0x33, 0x00, 0xFC, 0x03, 0x31, 0x0F, 0xC0, 0x3F, 0x00, 0x7F, 0x00, 0xCC, ++0x03, 0x30, 0x0E, 0xC0, 0x3C, 0x00, 0xFF, 0xA0, 0x4C, 0x83, 0x30, 0x17, 0xC2, ++0x07, 0x24, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x20, 0x46, 0x01, 0xC1, ++0x09, 0x45, 0x03, 0xD0, 0x1D, 0x40, 0xC4, 0x10, 0x1D, 0x5B, 0x04, 0x1F, 0x50, ++0x75, 0x40, 0x33, 0x00, 0xD1, 0x00, 0x44, 0x03, 0xD0, 0x0D, 0x42, 0x37, 0x40, ++0x11, 0x02, 0x74, 0x03, 0x50, 0x0D, 0x48, 0x37, 0x20, 0x1D, 0x02, 0x6C, 0x03, ++0xB0, 0x0D, 0x40, 0x35, 0x10, 0x8D, 0x07, 0x54, 0x03, 0x14, 0x3D, 0x40, 0x87, ++0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x44, 0x00, 0x99, 0x00, ++0x44, 0x03, 0xD0, 0x8D, 0x40, 0x34, 0x00, 0xCD, 0x00, 0x44, 0x03, 0x50, 0x1D, ++0x40, 0x37, 0x00, 0xD1, 0x00, 0x44, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xD1, ++0x08, 0x74, 0x07, 0x90, 0x0D, 0x40, 0x37, 0x02, 0x9D, 0x00, 0x44, 0x03, 0x10, ++0x0D, 0x40, 0x34, 0x00, 0x1D, 0x01, 0x65, 0x02, 0x10, 0x8D, 0x40, 0x07, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x04, 0x00, 0x91, 0x80, 0x04, ++0x03, 0xD0, 0x0C, 0x40, 0x20, 0x00, 0x8D, 0x00, 0x05, 0x03, 0x50, 0x0C, 0x40, ++0x37, 0x00, 0xD1, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x37, 0x00, 0x81, 0x00, ++0x64, 0x03, 0x98, 0x0C, 0x40, 0x33, 0x00, 0x8D, 0x00, 0x65, 0x03, 0x90, 0x0C, ++0x40, 0x30, 0x00, 0x8D, 0x00, 0x14, 0x03, 0x10, 0x4C, 0x40, 0x43, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB0, 0x0E, 0x00, 0xBB, 0x40, 0xCC, 0x03, ++0xF0, 0x0D, 0xC0, 0x14, 0x00, 0x4F, 0x00, 0x4C, 0x03, 0x70, 0x0D, 0xC0, 0x3F, ++0x00, 0xF3, 0x00, 0xCC, 0x03, 0xF0, 0x0F, 0x40, 0x3F, 0x00, 0x51, 0x00, 0x7C, ++0x03, 0xB0, 0x0D, 0xC0, 0x37, 0x10, 0x5F, 0x40, 0xCC, 0x03, 0x30, 0x0F, 0xC0, ++0x34, 0x00, 0x9F, 0x20, 0xCC, 0x03, 0x30, 0x05, 0xC2, 0x07, 0x40, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC0, 0x0F, 0x00, 0x3F, 0x40, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, ++0xEF, 0x40, 0xFC, 0x03, 0xF0, 0x0F, 0xE0, 0x3F, 0x00, 0x3F, 0x80, 0xBC, 0x03, ++0x70, 0x0B, 0xC0, 0x3F, 0x10, 0x3F, 0x80, 0xDC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, ++0x20, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x2F, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA0, 0x7B, 0x00, 0xFF, 0x01, 0xCC, 0x27, 0xE0, 0x1F, ++0xC0, 0x7C, 0x02, 0xFB, 0x01, 0xBE, 0x0F, 0x11, 0x3F, 0xC0, 0x7C, 0x82, 0xF3, ++0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0xFF, 0x00, 0xFB, 0x01, 0xDC, 0x07, 0x30, ++0x9F, 0xC0, 0x5E, 0x02, 0xB3, 0x84, 0xEC, 0x31, 0xF0, 0x1F, 0xE4, 0x7F, 0x00, ++0xFF, 0xC1, 0xEC, 0x24, 0xB0, 0x17, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x08, 0x07, 0x00, 0x1D, 0x10, 0x69, 0x00, 0xF1, 0x11, 0x40, ++0x00, 0x20, 0x11, 0x01, 0x74, 0x00, 0x10, 0x01, 0x40, 0x00, 0x01, 0x17, 0x01, ++0x74, 0x04, 0xD0, 0x11, 0x40, 0x04, 0x20, 0x1D, 0x01, 0x44, 0x84, 0xB0, 0x01, ++0x40, 0x15, 0x01, 0xD5, 0x09, 0x44, 0xB3, 0xD0, 0x1F, 0x42, 0x7F, 0x00, 0xFD, ++0x01, 0x04, 0x10, 0x10, 0x19, 0x40, 0x05, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x11, 0xA0, 0x33, 0x00, 0xDD, 0x84, 0x00, 0x13, 0xD0, 0x0D, 0x40, 0x30, ++0x21, 0xC9, 0x00, 0x30, 0x13, 0x10, 0x4D, 0x40, 0x34, 0x00, 0xC1, 0x00, 0x34, ++0x83, 0xC0, 0x0D, 0x00, 0x30, 0x01, 0xCD, 0x60, 0x40, 0x03, 0x92, 0x4C, 0x40, ++0x20, 0x00, 0x85, 0x00, 0x14, 0x01, 0x50, 0x0C, 0x40, 0x33, 0x80, 0xC5, 0x00, ++0x44, 0x10, 0x91, 0x0D, 0x64, 0x44, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA8, 0x05, 0x00, 0x1D, 0x00, 0x46, 0x80, 0x50, 0x01, 0x40, 0x04, 0x00, ++0x11, 0x00, 0x74, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x15, 0x00, 0x74, 0x00, ++0xD0, 0x01, 0x50, 0x04, 0x08, 0x1D, 0x00, 0x54, 0x00, 0x98, 0x01, 0x40, 0x21, ++0x00, 0x94, 0x00, 0x64, 0x11, 0xD0, 0x0D, 0x60, 0x37, 0x00, 0xDD, 0x00, 0x44, ++0x06, 0x10, 0x09, 0x40, 0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x88, 0x37, 0x00, 0xCF, 0x00, 0x44, 0x03, 0xD1, 0x0C, 0xD0, 0x34, 0x00, 0xDB, ++0x00, 0x74, 0x03, 0x34, 0x0C, 0xD0, 0x30, 0x00, 0xD3, 0x80, 0x7C, 0x03, 0xF1, ++0x0D, 0x40, 0x36, 0x08, 0xDB, 0x00, 0x1C, 0x03, 0xB0, 0x0D, 0xC2, 0xA6, 0x00, ++0x87, 0x01, 0x7D, 0x01, 0xF0, 0x0D, 0x40, 0x37, 0x00, 0xCF, 0x00, 0x2D, 0x04, ++0xB0, 0xD4, 0x40, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, ++0x0D, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, ++0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x80, 0xF4, 0x00, 0xF0, 0x03, ++0xC0, 0x0D, 0x00, 0x3D, 0x00, 0xED, 0x40, 0xF0, 0x03, 0xC0, 0x3F, 0x08, 0xFF, ++0x05, 0xCC, 0x03, 0xF0, 0x0F, 0x40, 0x3E, 0x20, 0xFF, 0x00, 0xFE, 0x00, 0xF0, ++0x1B, 0xD0, 0x1E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, ++0x04, 0xD3, 0x01, 0x7C, 0x03, 0xF0, 0x0D, 0xC8, 0x34, 0x10, 0xD7, 0x08, 0x6E, ++0xA3, 0x30, 0x0D, 0xC0, 0x37, 0x00, 0xDB, 0x84, 0x7C, 0x83, 0xF0, 0x0D, 0xC0, ++0x37, 0x00, 0xDF, 0x08, 0x6C, 0x03, 0xF0, 0x0D, 0xC0, 0xA6, 0x20, 0x97, 0x24, ++0x6E, 0x09, 0xF0, 0x0D, 0xC0, 0x37, 0x28, 0xDF, 0x20, 0x7C, 0x02, 0x30, 0x2D, ++0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xC4, 0x01, ++0x11, 0x01, 0x74, 0x00, 0xD0, 0x01, 0xD0, 0x06, 0x00, 0x11, 0x01, 0x44, 0x04, ++0x14, 0x51, 0x40, 0x07, 0x30, 0x11, 0x10, 0x5C, 0x00, 0xD9, 0x00, 0xC1, 0x45, ++0x24, 0x0D, 0xAA, 0x64, 0x00, 0x70, 0x41, 0x40, 0x64, 0x00, 0x9B, 0x04, 0x74, ++0x01, 0xD0, 0x0D, 0x48, 0x37, 0x00, 0xDD, 0x04, 0x5C, 0x6E, 0x10, 0x09, 0xC0, ++0x4D, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x32, 0x80, 0xC1, ++0x00, 0x34, 0x03, 0xD0, 0x8C, 0x40, 0x34, 0x00, 0xC5, 0x01, 0x44, 0x07, 0x92, ++0x1C, 0x00, 0x33, 0x00, 0xC1, 0x02, 0x34, 0x03, 0xD0, 0x1C, 0x60, 0x73, 0x20, ++0xCD, 0x23, 0x34, 0x27, 0xD0, 0x1D, 0x40, 0xF0, 0x04, 0x81, 0x03, 0x34, 0x01, ++0xD0, 0x0C, 0x40, 0x73, 0x00, 0xCD, 0x05, 0x34, 0x0D, 0x10, 0x08, 0x40, 0x1F, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x4C, 0x00, 0x21, 0x01, ++0xB4, 0x04, 0xD0, 0x13, 0x40, 0x48, 0x00, 0x21, 0x01, 0xC4, 0x04, 0x98, 0x52, ++0x44, 0x4B, 0x00, 0x21, 0x05, 0x94, 0x04, 0xD0, 0x12, 0x68, 0x4B, 0x00, 0x2D, ++0x01, 0xB0, 0x04, 0x50, 0x12, 0x40, 0x79, 0x00, 0xE9, 0x01, 0xB4, 0x07, 0xD0, ++0x1E, 0x40, 0x7B, 0x00, 0xED, 0xA1, 0x94, 0x27, 0x10, 0x9A, 0x40, 0x19, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xC3, 0x00, 0x3C, ++0x03, 0xF0, 0x8C, 0x40, 0x30, 0x20, 0xC7, 0x00, 0x05, 0x23, 0xB0, 0x5C, 0xC4, ++0x33, 0x00, 0xC1, 0x05, 0x3C, 0x03, 0xD0, 0x0C, 0xC0, 0x33, 0x20, 0xCF, 0x88, ++0x3C, 0x03, 0xF2, 0x0D, 0x50, 0xA0, 0x04, 0xC3, 0x00, 0x34, 0x03, 0xF0, 0x8C, ++0xC0, 0x33, 0x06, 0xCF, 0x00, 0x3C, 0x01, 0x30, 0x88, 0xC4, 0x4B, 0x40, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x0D, 0x00, 0x3F, 0x80, 0xFC, 0x00, ++0xF0, 0x82, 0xC0, 0x0F, 0x00, 0x2E, 0x08, 0xD4, 0x00, 0x71, 0x03, 0xC0, 0x07, ++0x02, 0x17, 0x08, 0xFC, 0x00, 0xF0, 0x01, 0xC0, 0x0D, 0x00, 0x1D, 0x80, 0x64, ++0x00, 0xF0, 0x11, 0xC0, 0x20, 0x02, 0xD8, 0x00, 0x7C, 0x03, 0xF0, 0x1F, 0xC0, ++0x7F, 0x08, 0xFF, 0x01, 0xDC, 0x03, 0xF0, 0x8B, 0xC0, 0x0B, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC0, 0x35, 0x10, 0xCE, 0x01, 0x6C, 0x03, 0xD0, 0x0C, 0xC0, 0x34, 0x20, ++0xDF, 0x00, 0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x73, 0x00, 0xD7, 0x00, 0x7C, 0x03, ++0xF0, 0x0D, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x01, 0x70, 0x8D, 0xC0, 0x37, ++0x02, 0xDF, 0x00, 0x7C, 0x07, 0x30, 0x1D, 0xC0, 0x54, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x88, 0x09, 0x00, 0x2D, 0x00, 0xB4, 0x00, 0xC0, 0x02, ++0x40, 0x0B, 0x00, 0x2D, 0x00, 0x84, 0x00, 0xD0, 0x02, 0x40, 0x09, 0x00, 0x2D, ++0x00, 0xB4, 0x00, 0x50, 0x02, 0x40, 0x0B, 0x00, 0x21, 0x00, 0xA4, 0x00, 0xD0, ++0x02, 0x40, 0x3B, 0x00, 0xED, 0x02, 0x9C, 0x1B, 0xF0, 0x4E, 0x48, 0x3B, 0x01, ++0xE9, 0x02, 0xB4, 0x03, 0x10, 0x0A, 0xC0, 0x4B, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x02, 0x79, 0x08, 0xED, 0x01, 0xB4, 0x07, 0xC0, 0x1E, 0x40, ++0x7B, 0x00, 0xFD, 0x01, 0x84, 0x07, 0xD0, 0x1F, 0x40, 0x78, 0x10, 0xE4, 0x01, ++0xB4, 0x07, 0x10, 0x1E, 0x08, 0x7F, 0x00, 0xE5, 0x01, 0xB4, 0x07, 0x40, 0x1E, ++0x60, 0x6B, 0x04, 0xE5, 0x05, 0x94, 0x17, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, ++0x05, 0xB4, 0x07, 0x10, 0x1E, 0x44, 0x0E, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x28, 0x03, 0x80, 0x0D, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x44, 0x03, ++0x00, 0x0D, 0x00, 0x04, 0x00, 0xD8, 0x01, 0x42, 0x05, 0x00, 0x08, 0x00, 0x34, ++0x80, 0x52, 0x00, 0x40, 0x03, 0x00, 0x01, 0x00, 0x34, 0x00, 0x90, 0x00, 0x40, ++0xE3, 0x00, 0xCD, 0x00, 0x04, 0x06, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xC9, 0x00, ++0x34, 0x0E, 0x1C, 0x08, 0x40, 0x4B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x17, 0xA8, 0x15, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, ++0x5F, 0x00, 0x45, 0x01, 0xF0, 0x05, 0xC0, 0x14, 0x00, 0x57, 0x00, 0x7C, 0x01, ++0x30, 0x05, 0xC0, 0x17, 0x00, 0x57, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x1F, ++0x00, 0x4F, 0x00, 0xDC, 0x81, 0x78, 0x05, 0xC4, 0x17, 0x00, 0x5F, 0x80, 0xFC, ++0x25, 0x30, 0x47, 0x40, 0x5E, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x00, 0x8F, 0x20, 0x3F, 0x00, 0xFC, 0x00, 0xF2, 0x03, 0xC0, 0x0F, 0x08, 0x3F, ++0x00, 0xDC, 0x00, 0xF1, 0x03, 0xC0, 0x0F, 0x20, 0x3D, 0x00, 0xFC, 0x00, 0xF0, ++0x03, 0xC8, 0x0F, 0x00, 0x3F, 0x00, 0xEC, 0x00, 0xF0, 0x03, 0x40, 0x87, 0x01, ++0x1F, 0x00, 0x5C, 0x20, 0x70, 0x00, 0xC0, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x20, ++0xF0, 0x01, 0xE0, 0x49, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, ++0x67, 0x00, 0x9F, 0x08, 0x7C, 0x02, 0xF8, 0x29, 0xC0, 0x27, 0x00, 0x93, 0x04, ++0x7C, 0x02, 0xF0, 0x19, 0xC0, 0x24, 0x20, 0x97, 0x09, 0x4C, 0x02, 0xB0, 0x09, ++0xC0, 0x27, 0x01, 0x9F, 0x00, 0x7C, 0x22, 0xF0, 0x59, 0xC0, 0x24, 0x01, 0x9F, ++0x00, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x7C, 0x16, 0xF0, ++0x09, 0xC8, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xA6, ++0x06, 0x9D, 0x20, 0x74, 0x06, 0xD8, 0x39, 0x44, 0x23, 0x20, 0x91, 0x01, 0x74, ++0x06, 0xD0, 0x09, 0x40, 0x24, 0x08, 0x83, 0x01, 0x04, 0x02, 0x10, 0x09, 0x44, ++0x27, 0x00, 0x9D, 0x10, 0x74, 0x06, 0xD0, 0x18, 0x50, 0xE4, 0x00, 0xBD, 0x00, ++0xC4, 0x02, 0xD0, 0x0B, 0x40, 0x2C, 0x01, 0xBD, 0x40, 0x74, 0x0E, 0xD2, 0x09, ++0x42, 0x07, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x08, ++0xBD, 0x00, 0xF4, 0x06, 0xD2, 0x0B, 0x40, 0x2F, 0x00, 0xB1, 0x40, 0xF4, 0x12, ++0x50, 0x8B, 0x40, 0x2C, 0x20, 0xBD, 0x00, 0xE4, 0x02, 0x90, 0x0B, 0x60, 0x2E, ++0x00, 0xB5, 0x01, 0xF4, 0x0A, 0xD0, 0x0B, 0x40, 0x25, 0x00, 0x9D, 0x00, 0x64, ++0x13, 0xD2, 0x09, 0x40, 0x24, 0x80, 0x9D, 0x00, 0x74, 0x43, 0xD0, 0x09, 0x60, ++0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0x28, 0x00, 0xAD, ++0x02, 0xB4, 0x0A, 0xD0, 0x0E, 0x40, 0x2F, 0x00, 0xA1, 0x00, 0xB6, 0x0A, 0xD0, ++0x2A, 0x50, 0x28, 0x02, 0xBD, 0x00, 0xE5, 0x0A, 0x10, 0x0A, 0x60, 0xAB, 0x00, ++0xAD, 0x00, 0xB6, 0x02, 0xD0, 0x2B, 0x62, 0xA1, 0x00, 0x8D, 0x20, 0x04, 0x8A, ++0xD2, 0x28, 0x40, 0x20, 0x88, 0x8D, 0x80, 0x34, 0x22, 0xD0, 0x28, 0x40, 0x43, ++0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0xD0, 0x01, 0xC0, 0x87, 0x42, 0x13, 0x00, 0x7E, 0x00, 0x70, 0x01, ++0xC0, 0x84, 0x00, 0x57, 0x00, 0x2C, 0x00, 0xB0, 0x01, 0xC0, 0x06, 0x00, 0x1F, ++0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC2, 0x15, 0x00, 0x1F, 0x01, 0x4D, 0x04, 0xE0, ++0x11, 0xD0, 0x44, 0x00, 0x1D, 0x01, 0x3C, 0x08, 0xF0, 0x00, 0xE2, 0x77, 0xC0, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x27, 0x0D, 0x9F, 0x01, 0x7C, ++0x86, 0xF2, 0x09, 0xC0, 0x27, 0x10, 0x9D, 0x00, 0x7C, 0x06, 0xF0, 0x19, 0x44, ++0x27, 0x01, 0x93, 0x00, 0x5C, 0x06, 0xE0, 0x09, 0x40, 0x67, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x19, 0xC8, 0x6E, 0x00, 0xBF, 0x02, 0xF4, 0x0E, 0xF0, 0x39, ++0xC0, 0xA7, 0x08, 0x9F, 0x02, 0xFC, 0x12, 0xF0, 0x1F, 0xC0, 0x67, 0x60, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, 0x00, 0xB3, 0x02, 0xFC, 0x02, ++0xD1, 0x0A, 0xC0, 0x27, 0x10, 0xBE, 0x00, 0xD8, 0x02, 0xF0, 0x0B, 0xC0, 0x27, ++0x02, 0xBF, 0x00, 0x74, 0x02, 0xF0, 0x0B, 0xC0, 0xAF, 0x00, 0xB7, 0x00, 0xDC, ++0x02, 0xC0, 0x2B, 0xC0, 0x2F, 0x00, 0xB3, 0x01, 0xBC, 0x46, 0x30, 0xD9, 0xC0, ++0x6C, 0x01, 0xB3, 0x11, 0xC8, 0x02, 0xF0, 0x09, 0xC0, 0x67, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x05, 0x1B, 0x05, 0x74, 0x14, 0xD0, ++0x01, 0x40, 0x07, 0x04, 0x1D, 0x00, 0x74, 0x54, 0xD0, 0x11, 0x40, 0x07, 0x01, ++0x1D, 0x00, 0x74, 0x54, 0xD0, 0x01, 0xC0, 0x44, 0x00, 0x11, 0x00, 0x44, 0x00, ++0x90, 0x51, 0x40, 0x47, 0x05, 0x11, 0x20, 0x74, 0x14, 0x50, 0x31, 0x40, 0x85, ++0x00, 0x11, 0x02, 0x54, 0x00, 0xD0, 0x50, 0x41, 0x73, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x01, 0x81, 0x00, 0x34, 0x42, 0xD0, 0x08, ++0x40, 0x23, 0x00, 0xCD, 0x00, 0x14, 0x02, 0xD0, 0x48, 0x41, 0x23, 0x21, 0x8C, ++0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x27, 0x20, 0x94, 0x00, 0x14, 0x02, 0x90, ++0x08, 0x40, 0x27, 0x00, 0x81, 0x02, 0x34, 0x52, 0x50, 0xC8, 0x40, 0x20, 0x02, ++0x85, 0x00, 0x04, 0x02, 0xD0, 0x08, 0x40, 0x43, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x99, 0x20, 0x74, 0x02, 0xD0, 0x09, 0x40, ++0x27, 0x10, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x80, ++0x74, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x00, 0x91, 0x00, 0x44, 0x02, 0x90, 0x09, ++0x00, 0xA7, 0x01, 0x91, 0x00, 0x70, 0x42, 0x50, 0x08, 0x40, 0x37, 0x00, 0x95, ++0x00, 0x56, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x28, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0x08, 0x25, 0x00, 0xB3, 0x00, 0xFC, 0x02, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x00, 0xDC, 0x02, 0xF0, 0x0B, 0xC0, 0x27, 0x00, 0x9D, 0x00, 0xFC, ++0x02, 0xF0, 0x09, 0xC0, 0x2B, 0x00, 0x97, 0x00, 0x5C, 0x02, 0x90, 0x0B, 0xC0, ++0x2F, 0xC0, 0x93, 0x01, 0xFC, 0x2A, 0x71, 0x0B, 0xC8, 0x20, 0x40, 0x97, 0x40, ++0x4C, 0x9E, 0xF0, 0x2B, 0x40, 0x17, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x00, 0x25, 0x04, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xE1, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC4, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xF0, 0x09, 0xC4, 0x25, 0x00, 0x9F, 0x20, 0x7C, 0x02, 0xB0, 0x09, 0xC2, 0x67, ++0x00, 0x9F, 0x89, 0x6C, 0x02, 0xF0, 0x09, 0xC0, 0x25, 0x00, 0x9B, 0x80, 0x7C, ++0x12, 0xF0, 0x09, 0xC0, 0x53, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x08, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x3A, 0x01, 0xD0, 0x06, 0x00, 0x13, ++0x00, 0x6C, 0x00, 0xF2, 0x01, 0xC0, 0x04, 0x80, 0x13, 0x28, 0x7C, 0x00, 0xB2, ++0x01, 0xD0, 0x05, 0x40, 0x13, 0x00, 0x7C, 0x40, 0xF0, 0x01, 0xC2, 0x87, 0x00, ++0x1F, 0x00, 0x0C, 0x08, 0x31, 0x01, 0xD0, 0x04, 0x00, 0x03, 0x00, 0x4D, 0x88, ++0x30, 0x21, 0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, ++0xDC, 0x00, 0x5D, 0x40, 0x74, 0x11, 0x15, 0x57, 0xC0, 0x14, 0x10, 0x55, 0x40, ++0x74, 0x01, 0xD0, 0x05, 0x40, 0x14, 0x00, 0x7B, 0x00, 0x74, 0x01, 0x10, 0x05, ++0x40, 0x54, 0x00, 0x6B, 0x02, 0xF4, 0x0D, 0x34, 0x05, 0x40, 0x9B, 0x00, 0x7D, ++0x02, 0x6E, 0x01, 0xB0, 0x05, 0x40, 0x9C, 0x00, 0x7B, 0x1B, 0xC4, 0x05, 0x10, ++0x05, 0xC8, 0x52, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0xF6, ++0x82, 0xCD, 0x09, 0x34, 0x03, 0x10, 0x38, 0x40, 0x30, 0x00, 0x81, 0x00, 0x34, ++0x03, 0xC0, 0x0C, 0x40, 0x30, 0x00, 0x45, 0x05, 0x34, 0x03, 0x90, 0x08, 0x40, ++0x32, 0x02, 0xC1, 0x04, 0x34, 0x01, 0x18, 0x0C, 0x40, 0xE3, 0x03, 0x8D, 0x10, ++0x24, 0x03, 0x10, 0x0C, 0x44, 0xA2, 0x01, 0x89, 0x03, 0x24, 0x1B, 0x1D, 0x0C, ++0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x18, 0x80, ++0xAD, 0x44, 0xF4, 0x17, 0x10, 0x1A, 0x44, 0x7C, 0x00, 0xE5, 0x00, 0xB4, 0x12, ++0xD2, 0x5A, 0x40, 0x7C, 0x01, 0xE9, 0x00, 0xF6, 0x17, 0x10, 0x1A, 0x40, 0x2A, ++0x00, 0xE1, 0x00, 0xF4, 0x0F, 0x90, 0x0E, 0x40, 0x3B, 0x01, 0x8D, 0x11, 0xF4, ++0x0B, 0x90, 0x8E, 0x40, 0x28, 0x04, 0xA9, 0x20, 0xA4, 0x0F, 0x10, 0x5E, 0x40, ++0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x78, 0x00, 0xEF, ++0x21, 0xBC, 0x1E, 0x10, 0x1E, 0xC0, 0x78, 0x02, 0xE3, 0x01, 0xBC, 0x07, 0xD2, ++0x5F, 0xC0, 0x78, 0x04, 0xE5, 0x01, 0xBC, 0x97, 0xB0, 0x1A, 0x60, 0x7E, 0x00, ++0xE1, 0x01, 0xBC, 0x07, 0x19, 0x3E, 0xC0, 0x7B, 0x11, 0xAF, 0x01, 0xA6, 0x0E, ++0x30, 0x1C, 0x88, 0x6A, 0x00, 0xAB, 0x01, 0xEC, 0x05, 0x30, 0x3E, 0xC0, 0x50, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, 0x08, 0x9F, 0x00, ++0x3C, 0x02, 0xF0, 0x0D, 0xC8, 0xB1, 0x01, 0xDF, 0x00, 0x7C, 0x22, 0xF0, 0x89, ++0xDA, 0x33, 0x02, 0xDC, 0x00, 0x3C, 0x23, 0xF0, 0x08, 0x80, 0x25, 0x00, 0x9F, ++0x00, 0x3C, 0x03, 0x70, 0x09, 0x80, 0x17, 0x10, 0x9D, 0x00, 0x6C, 0x02, 0xC0, ++0x0D, 0xC0, 0x21, 0x00, 0x8F, 0x00, 0x5C, 0x01, 0xF0, 0x0D, 0xC8, 0x43, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x7B, 0x00, 0xF3, 0x11, 0xCC, ++0x07, 0xB8, 0x0B, 0xC0, 0x7F, 0x04, 0xFF, 0x01, 0xED, 0x07, 0x30, 0x1F, 0xC0, ++0x7F, 0x20, 0xEF, 0x09, 0x4C, 0x27, 0x30, 0x1B, 0xC0, 0x7D, 0x04, 0xFB, 0x01, ++0x9C, 0x07, 0xB0, 0x9E, 0xC2, 0x5D, 0x04, 0xBF, 0x01, 0xFC, 0x07, 0xF0, 0x1F, ++0xC8, 0x6C, 0x00, 0xF3, 0x01, 0xFC, 0x07, 0xF0, 0x1E, 0xC0, 0x08, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x19, 0x06, 0xF1, 0x40, 0xC4, 0x13, ++0x39, 0x4A, 0x40, 0x3B, 0x01, 0xED, 0x00, 0xC4, 0x02, 0x10, 0x08, 0x48, 0x3B, ++0x01, 0xC7, 0x02, 0x84, 0x77, 0x10, 0x0A, 0x40, 0x3C, 0x00, 0x61, 0x00, 0x84, ++0x03, 0x40, 0x1E, 0x40, 0x39, 0x00, 0xAD, 0x84, 0xA4, 0x13, 0xF0, 0x0E, 0x40, ++0x28, 0x00, 0xE5, 0x08, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x54, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x00, 0xA1, 0x08, 0x84, 0x02, 0x01, ++0x8A, 0x41, 0x3B, 0x10, 0xFD, 0x00, 0x84, 0x43, 0x10, 0x0E, 0x40, 0x3B, 0x20, ++0xED, 0x02, 0x80, 0x17, 0x10, 0x0B, 0x41, 0x29, 0x00, 0xF1, 0x00, 0x94, 0x03, ++0x10, 0x4F, 0x40, 0x1A, 0x00, 0xAD, 0x80, 0xB4, 0x42, 0xD0, 0x1E, 0x40, 0x20, ++0x00, 0xE5, 0x00, 0xB4, 0x01, 0xD0, 0x1F, 0x40, 0x20, 0x01, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x28, 0x03, 0x00, 0x90, 0x02, 0x44, 0x0E, 0x10, 0x3C, ++0x40, 0xB3, 0x02, 0xCD, 0x02, 0x06, 0x0E, 0x00, 0x38, 0x40, 0xF3, 0x01, 0xC9, ++0x08, 0x04, 0x4F, 0x11, 0x68, 0x42, 0xA5, 0x02, 0x01, 0x0B, 0x04, 0x4B, 0x50, ++0x08, 0x41, 0x13, 0x22, 0x8D, 0x81, 0x66, 0x1A, 0x52, 0x0C, 0x44, 0x20, 0x00, ++0xC5, 0x80, 0x74, 0x08, 0xD0, 0x0C, 0x40, 0x18, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0xA8, 0x65, 0x00, 0xD2, 0x01, 0x4C, 0x4F, 0x34, 0x18, 0xC0, ++0x7F, 0x00, 0xDF, 0x03, 0x0C, 0x07, 0x30, 0x3D, 0xC1, 0xBF, 0x04, 0xCD, 0x01, ++0x4D, 0x0B, 0x36, 0x2D, 0xE4, 0xB5, 0x02, 0x93, 0x02, 0x54, 0x42, 0x10, 0x19, ++0xC0, 0x36, 0x00, 0xDD, 0x05, 0x74, 0x0F, 0xD0, 0x0D, 0xD0, 0x34, 0x00, 0x97, ++0x20, 0x7C, 0x02, 0xF2, 0xBD, 0xD5, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x00, 0xA7, 0x20, 0x9F, 0x18, 0x7C, 0x03, 0x70, 0x29, 0xC0, 0x37, ++0x01, 0xDE, 0x08, 0x7C, 0x03, 0xF4, 0x4D, 0xC0, 0x37, 0x00, 0xD7, 0x02, 0x7C, ++0x03, 0xF0, 0x09, 0xC0, 0x26, 0x00, 0x97, 0x82, 0x7C, 0x0B, 0x70, 0x8D, 0xE0, ++0x35, 0x00, 0xDF, 0x02, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0x9D, 0x02, ++0x7C, 0x2A, 0xF0, 0x0D, 0xC0, 0xA7, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x80, 0x0A, 0x2F, 0x00, 0xFF, 0x00, 0xCC, 0x43, 0x70, 0x0F, 0xC1, 0x3C, 0x00, ++0xFF, 0x15, 0xDC, 0x66, 0x30, 0x1B, 0xC0, 0x3F, 0x20, 0xFF, 0x00, 0xCC, 0x03, ++0xF0, 0x9F, 0xC0, 0x3F, 0x00, 0x33, 0x10, 0xFC, 0x03, 0xE0, 0x0B, 0xC0, 0x7F, ++0x10, 0xE3, 0x49, 0xCC, 0x03, 0x30, 0x0F, 0xC0, 0xBF, 0x00, 0xBF, 0x22, 0xFC, ++0x40, 0x30, 0x0F, 0xC0, 0x07, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, ++0x20, 0x66, 0x00, 0x9D, 0x00, 0x44, 0x83, 0x10, 0x2D, 0x40, 0x34, 0x08, 0xDD, ++0x40, 0x74, 0x02, 0x50, 0x09, 0x44, 0x37, 0x08, 0xDD, 0x03, 0x44, 0x03, 0xD0, ++0x19, 0x68, 0x27, 0x80, 0x15, 0x13, 0x74, 0x47, 0xD2, 0x99, 0xC4, 0x51, 0x28, ++0xD1, 0x03, 0x6C, 0x27, 0xF0, 0x0D, 0x40, 0x27, 0x00, 0x9D, 0x04, 0x7C, 0x2F, ++0x11, 0x0D, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, ++0x46, 0x04, 0xDD, 0x00, 0x44, 0x12, 0x12, 0x09, 0x41, 0x36, 0x00, 0xDD, 0x00, ++0x74, 0x03, 0x12, 0x8D, 0x42, 0x37, 0x00, 0xDD, 0x01, 0x44, 0x03, 0xD0, 0x0D, ++0x42, 0x37, 0x20, 0x91, 0x01, 0x74, 0x07, 0xD0, 0x09, 0x44, 0x17, 0x02, 0x95, ++0x50, 0x44, 0x02, 0x10, 0x0D, 0x48, 0x36, 0x00, 0x9D, 0x00, 0x74, 0x0A, 0x10, ++0x0D, 0x40, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, ++0x00, 0xCD, 0x00, 0x05, 0x02, 0x10, 0x08, 0x50, 0x32, 0x08, 0xCD, 0x00, 0x74, ++0x03, 0x50, 0x8C, 0x40, 0x33, 0x00, 0xDD, 0x02, 0x04, 0x13, 0xD0, 0x08, 0x40, ++0x36, 0x00, 0x05, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x61, 0x35, 0x40, 0x45, 0x80, ++0x24, 0x02, 0x98, 0x0C, 0x40, 0x33, 0x00, 0x4D, 0x20, 0x34, 0x00, 0x10, 0x0C, ++0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x26, 0x00, ++0x9F, 0x20, 0x4C, 0x02, 0x34, 0x01, 0xC0, 0x3E, 0x00, 0xDF, 0x00, 0x58, 0x82, ++0x30, 0x09, 0xC0, 0x3F, 0x08, 0xDF, 0x02, 0x84, 0x43, 0xF0, 0x0D, 0x40, 0x27, ++0x00, 0x11, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0x40, 0x17, 0x80, 0x97, 0x80, 0x4C, ++0x02, 0x30, 0x0E, 0x80, 0x17, 0x00, 0x9F, 0x00, 0x7C, 0x00, 0x34, 0x0F, 0xC8, ++0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB0, 0x2F, 0x00, 0xBF, ++0x40, 0xFC, 0x02, 0xB0, 0x07, 0xC0, 0x3D, 0x08, 0xEF, 0x00, 0xFC, 0x02, 0xF0, ++0x4B, 0xC8, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0A, 0xC0, 0x2F, 0x00, ++0x2F, 0x00, 0xFC, 0x03, 0xD0, 0x09, 0xC0, 0x1F, 0x00, 0x7B, 0x00, 0xF8, 0x02, ++0xF0, 0x0F, 0xC2, 0x1F, 0x20, 0x7F, 0x00, 0xDC, 0x00, 0xF0, 0x0F, 0xC0, 0x17, ++0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x6F, 0x00, 0x2F, 0x04, ++0xCC, 0x06, 0x70, 0x43, 0xC1, 0x0F, 0x01, 0xE3, 0x01, 0xCC, 0x10, 0x74, 0x03, ++0xC0, 0x0F, 0x00, 0x33, 0x10, 0xCC, 0x80, 0x30, 0x03, 0xD0, 0x0C, 0x00, 0x33, ++0x04, 0xCC, 0x00, 0x34, 0x43, 0xC8, 0x7E, 0x02, 0xB3, 0x00, 0xFC, 0x53, 0xF0, ++0x12, 0xC0, 0x6D, 0x02, 0xAF, 0x01, 0xFC, 0x06, 0xF0, 0x4B, 0xC0, 0x0F, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x67, 0x00, 0x1D, 0xAB, 0x44, ++0x07, 0x10, 0x35, 0x48, 0xD7, 0x02, 0xD1, 0xA1, 0x44, 0x0D, 0x10, 0x35, 0x40, ++0x57, 0x02, 0x51, 0x43, 0x4C, 0x0D, 0x10, 0xB5, 0x40, 0xD4, 0x02, 0x51, 0x03, ++0x44, 0x0D, 0x10, 0x95, 0x40, 0x33, 0x11, 0xD1, 0x03, 0x74, 0x8F, 0xD0, 0x19, ++0x40, 0x27, 0x01, 0x9D, 0x01, 0x74, 0x04, 0xD2, 0x11, 0x40, 0x07, 0x60, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA8, 0x23, 0x00, 0x0D, 0x00, 0x44, 0x03, ++0x50, 0x08, 0x40, 0x21, 0x40, 0xC1, 0x00, 0x14, 0x0A, 0x18, 0x88, 0x40, 0x23, ++0x00, 0x81, 0x00, 0x04, 0x0A, 0x50, 0x08, 0x48, 0x20, 0x00, 0x89, 0x08, 0x06, ++0x0A, 0x10, 0x08, 0x40, 0x33, 0x01, 0x81, 0x02, 0x34, 0x03, 0xD0, 0x08, 0x40, ++0x01, 0x10, 0x85, 0x00, 0x34, 0x02, 0xD0, 0x88, 0x40, 0x47, 0x80, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x25, 0x02, 0x1D, 0xC0, 0x64, 0xC7, 0x10, ++0x05, 0x44, 0x37, 0x02, 0xD1, 0x00, 0x56, 0x08, 0x10, 0x05, 0x40, 0xB7, 0x09, ++0x91, 0x03, 0x64, 0x03, 0x50, 0x09, 0x40, 0x34, 0x00, 0x91, 0x00, 0x44, 0x0E, ++0x10, 0x09, 0x42, 0x37, 0x01, 0x91, 0x00, 0x74, 0x03, 0xD0, 0x19, 0x40, 0x57, ++0x00, 0xDD, 0x01, 0x74, 0x05, 0xD0, 0x19, 0x41, 0x0F, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xA8, 0x27, 0x00, 0xDF, 0x5A, 0x0C, 0x0F, 0x70, 0x91, ++0xC0, 0xC7, 0x04, 0xD3, 0x01, 0x5C, 0x24, 0x30, 0x11, 0xC2, 0xC7, 0x00, 0x13, ++0x02, 0x4C, 0x00, 0x70, 0x21, 0xC1, 0xC4, 0x86, 0x13, 0x1B, 0x4C, 0x08, 0x30, ++0x01, 0xC0, 0x36, 0x00, 0x93, 0x00, 0x7C, 0x03, 0xF0, 0x59, 0xC0, 0xE5, 0x00, ++0x9F, 0x07, 0x7C, 0x16, 0xF0, 0x39, 0xC0, 0x0B, 0x20, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x07, 0x80, 0x2D, 0x20, 0xBF, 0x00, 0xDC, 0x03, 0xF0, 0x17, 0xC0, ++0x4F, 0x00, 0xFD, 0x02, 0xEC, 0x01, 0xB0, 0x3F, 0xC0, 0x1A, 0x40, 0x6F, 0x00, ++0x9C, 0x0D, 0xB0, 0x07, 0xC0, 0x5B, 0x20, 0x7F, 0x00, 0xFD, 0x01, 0xF0, 0x07, ++0xC2, 0x7F, 0x40, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0x7F, ++0x00, 0xFC, 0x01, 0xF2, 0x03, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x08, 0x25, 0x00, 0xD3, 0x13, 0x4C, 0x23, 0xF0, 0x09, 0xD0, 0xA0, ++0x00, 0xDF, 0x11, 0x1C, 0x0A, 0x70, 0x09, 0xE0, 0x27, 0x00, 0x1F, 0x02, 0x4C, ++0x2A, 0x30, 0x2C, 0xC0, 0xA7, 0x02, 0x83, 0x02, 0x0D, 0x02, 0xF0, 0x2D, 0x41, ++0x74, 0x01, 0xD3, 0x00, 0x4C, 0x03, 0xF0, 0x29, 0xC0, 0x94, 0x00, 0x9F, 0x0E, ++0x4C, 0x0A, 0xF0, 0x29, 0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0xA0, 0x64, 0x01, 0x81, 0x22, 0x44, 0x03, 0xD0, 0xB5, 0x40, 0xE4, 0x02, ++0xCD, 0x02, 0x44, 0x28, 0xD0, 0xAD, 0x41, 0xB7, 0x06, 0x1D, 0x1A, 0x44, 0x07, ++0x12, 0xAD, 0x42, 0xB7, 0x00, 0x91, 0x0B, 0x6C, 0x2A, 0xD0, 0x0D, 0x41, 0xB5, ++0x08, 0xD1, 0x01, 0xC4, 0x83, 0xD0, 0x0D, 0xC0, 0x14, 0x00, 0xD1, 0x01, 0x44, ++0x99, 0xD0, 0x19, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x20, 0xE2, 0x01, 0x01, 0x00, 0x14, 0x13, 0xD0, 0x00, 0x40, 0x00, 0x28, 0xCD, ++0x00, 0x20, 0x24, 0x80, 0x10, 0x40, 0x43, 0x00, 0x0D, 0x01, 0x06, 0x90, 0x10, ++0x90, 0x40, 0x43, 0x04, 0x01, 0x00, 0x24, 0x24, 0xD0, 0x10, 0x40, 0x34, 0x00, ++0x81, 0x80, 0x24, 0x83, 0x90, 0x08, 0x40, 0x20, 0x00, 0x01, 0x02, 0x04, 0x42, ++0xD1, 0x00, 0x43, 0x0F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, ++0x6A, 0x00, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x98, 0x43, 0x58, 0x00, 0xED, 0x01, ++0xB4, 0x07, 0xD0, 0x12, 0x40, 0x6B, 0x00, 0x4C, 0x01, 0x04, 0x04, 0x10, 0x1E, ++0x40, 0x63, 0x00, 0xC1, 0x11, 0x84, 0x05, 0xD0, 0x14, 0x50, 0x78, 0x00, 0xE1, ++0x01, 0xA4, 0x07, 0xD0, 0x0B, 0x40, 0x7A, 0x12, 0xB1, 0x01, 0x85, 0x06, 0xD0, ++0x12, 0x48, 0x13, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, ++0x00, 0x03, 0x08, 0x1C, 0x03, 0xF0, 0xA8, 0xC8, 0x00, 0x84, 0xCF, 0x00, 0x3C, ++0x83, 0x70, 0x0C, 0x40, 0x13, 0x00, 0xCE, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xCA, ++0x13, 0x10, 0x43, 0x00, 0x24, 0x01, 0xF0, 0xE0, 0xC0, 0x30, 0x40, 0x83, 0x18, ++0x2C, 0x03, 0xF0, 0x88, 0xC0, 0x24, 0x40, 0x47, 0x08, 0x0C, 0x03, 0xF0, 0x00, ++0xC1, 0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x39, 0x40, ++0xFF, 0x00, 0xFC, 0x03, 0xF1, 0x8B, 0xC0, 0x1F, 0x20, 0xFF, 0x00, 0xCC, 0x03, ++0xF8, 0x07, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x8B, 0xC0, 0x3F, ++0x00, 0xFF, 0x08, 0xFC, 0x01, 0xF0, 0x83, 0xE0, 0x3F, 0x00, 0xAF, 0x00, 0xDD, ++0x43, 0xF0, 0x4F, 0xC0, 0x1D, 0x00, 0x7F, 0x00, 0xFC, 0x01, 0xF0, 0x83, 0xC0, ++0x0B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x67, 0x00, 0x53, ++0x00, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x36, 0x00, 0xD7, 0x00, 0x7C, 0x00, 0xF0, ++0x01, 0xC0, 0x07, 0x00, 0x93, 0x80, 0x7C, 0x07, 0x32, 0x01, 0xC2, 0x44, 0x00, ++0x13, 0x00, 0x4C, 0x02, 0x30, 0x09, 0xC0, 0x37, 0x00, 0x93, 0x00, 0x5C, 0x03, ++0xF0, 0x09, 0xC0, 0x57, 0x00, 0x53, 0x80, 0x7C, 0x01, 0x30, 0x19, 0xC0, 0x40, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x98, 0x39, 0x00, 0xE1, 0x00, ++0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x38, 0x08, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0A, ++0x40, 0x23, 0x40, 0xE1, 0x00, 0x36, 0x03, 0x04, 0x0C, 0x40, 0x28, 0x40, 0xE1, ++0x20, 0x04, 0x03, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xE5, 0x00, 0xB4, 0x13, 0xD0, ++0x0A, 0x40, 0x3B, 0x00, 0x61, 0x00, 0xF4, 0x01, 0xB1, 0x02, 0x40, 0x48, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x69, 0x00, 0x61, 0x01, 0xB4, ++0x07, 0xD0, 0x1C, 0x44, 0x78, 0x00, 0xE5, 0x11, 0xB6, 0x07, 0x50, 0x1E, 0x40, ++0x5B, 0x00, 0xE1, 0x01, 0xB4, 0x07, 0x10, 0x16, 0x40, 0x50, 0x00, 0x41, 0x01, ++0x84, 0x07, 0x14, 0x3E, 0x40, 0x7F, 0x00, 0xE1, 0x01, 0x94, 0x07, 0xD0, 0x1A, ++0x40, 0xDF, 0x00, 0x61, 0x01, 0xF4, 0x07, 0x10, 0x18, 0x50, 0x10, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x20, 0x33, 0x00, 0xC1, 0x13, 0x34, 0x01, ++0xD0, 0x9C, 0x40, 0xB0, 0x04, 0x8D, 0x01, 0x36, 0x03, 0xD0, 0x0C, 0x40, 0x33, ++0x00, 0xC1, 0x02, 0x34, 0x07, 0x10, 0x0C, 0x40, 0x30, 0x00, 0xC1, 0x00, 0x04, ++0x03, 0x10, 0x2C, 0x40, 0x63, 0x02, 0xC5, 0x08, 0x34, 0x03, 0xD0, 0xAC, 0x41, ++0xD3, 0x00, 0x41, 0x62, 0x34, 0x85, 0x90, 0x1C, 0x40, 0x58, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x57, 0x04, 0x73, 0x07, 0xBC, 0x09, 0xF0, ++0x07, 0xD0, 0x9E, 0x04, 0x57, 0x00, 0xFC, 0x01, 0xF0, 0x87, 0xE0, 0x1F, 0x00, ++0x73, 0x02, 0xFC, 0x1D, 0x30, 0x17, 0xD1, 0x1C, 0x00, 0x73, 0x00, 0xCD, 0x01, ++0x30, 0x27, 0xC0, 0x17, 0x00, 0x53, 0x01, 0x5C, 0x01, 0xF0, 0x17, 0xC0, 0x1F, ++0x00, 0x63, 0x07, 0xBC, 0x05, 0x30, 0x77, 0xC0, 0x5C, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x40, 0x0F, 0x00, 0x7C, 0x40, 0xF0, 0x01, ++0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, ++0x00, 0x7C, 0x40, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x04, 0xF0, ++0x01, 0xC1, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x44, ++0x1F, 0x06, 0x7C, 0x24, 0xF0, 0x41, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x30, 0x08, 0xE0, ++0x20, 0x00, 0x93, 0x00, 0x3C, 0x02, 0x30, 0x08, 0xC0, 0x20, 0x00, 0x83, 0x10, ++0x4C, 0x02, 0xF0, 0x08, 0xC0, 0x24, 0x00, 0x8F, 0x00, 0x0C, 0x02, 0x70, 0x08, ++0xC0, 0x64, 0x00, 0x93, 0x00, 0x3C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, ++0x08, 0x4C, 0x22, 0x30, 0x59, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x80, 0x44, 0x02, 0x10, 0x09, 0x10, 0x24, ++0x40, 0x91, 0x00, 0x74, 0x02, 0x14, 0x09, 0xD0, 0x24, 0x50, 0x91, 0x40, 0x4D, ++0x02, 0xD0, 0x09, 0x50, 0x24, 0x00, 0x9D, 0x00, 0x45, 0x02, 0x14, 0x09, 0x50, ++0x64, 0x42, 0x91, 0x00, 0x74, 0x06, 0x50, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x01, ++0x54, 0x06, 0x54, 0x29, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1C, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, ++0x91, 0x00, 0x74, 0x02, 0x10, 0x09, 0x00, 0x26, 0x00, 0x99, 0x00, 0x44, 0x03, ++0xD0, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x44, 0x02, 0x90, 0x09, 0x40, 0x20, ++0x00, 0x91, 0x00, 0x74, 0x12, 0x10, 0x09, 0x40, 0x37, 0x00, 0x9D, 0x00, 0x44, ++0x42, 0x11, 0x29, 0x40, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x28, 0x20, 0x00, 0x8D, 0x04, 0x05, 0x02, 0x10, 0x48, 0x40, 0x20, 0x01, 0x81, ++0x00, 0x34, 0x12, 0x10, 0x48, 0x44, 0x20, 0x01, 0x89, 0x04, 0x04, 0x12, 0xD0, ++0x48, 0x40, 0x20, 0x01, 0x8D, 0x04, 0x04, 0x12, 0x10, 0x48, 0x40, 0x60, 0x00, ++0x81, 0x04, 0x34, 0x12, 0x50, 0x08, 0x40, 0x23, 0x00, 0x8D, 0x00, 0x54, 0x02, ++0x50, 0x48, 0x40, 0x53, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, ++0x06, 0x00, 0x1F, 0x00, 0x44, 0x00, 0x34, 0x01, 0x40, 0x04, 0x00, 0x13, 0x00, ++0x7C, 0x00, 0x30, 0x01, 0xC0, 0x06, 0x00, 0x1B, 0x20, 0x4C, 0x00, 0xF0, 0x01, ++0xC0, 0x04, 0x00, 0x1F, 0x00, 0x4C, 0x00, 0x70, 0x01, 0xC0, 0x84, 0x02, 0x13, ++0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x87, 0x02, 0x5F, 0x80, 0x4C, 0x00, 0x32, ++0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA8, 0x2B, ++0x00, 0xBF, 0x28, 0xFD, 0x02, 0xF1, 0x8B, 0xC0, 0x2F, 0x0A, 0xBF, 0x20, 0xFC, ++0x22, 0xF0, 0x8B, 0xC0, 0x2F, 0x02, 0xB7, 0x08, 0xDC, 0x22, 0xF2, 0x8B, 0xC0, ++0x2F, 0x22, 0xBF, 0x08, 0xFC, 0x22, 0xF2, 0x8B, 0xC0, 0x2B, 0x00, 0xBF, 0x08, ++0x7C, 0x22, 0xF0, 0x0B, 0xC0, 0x2B, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0xF1, 0x8B, ++0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x27, 0x00, ++0x9F, 0x84, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x7C, 0x52, ++0x30, 0x49, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x49, 0xC0, 0x24, ++0x05, 0x9F, 0x04, 0x7C, 0x02, 0xF0, 0x08, 0xC0, 0x2C, 0x02, 0xB3, 0x04, 0xCC, ++0x16, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0xBF, 0x00, 0xBC, 0x02, 0xF2, 0x0B, 0xC0, ++0x63, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, 0x07, 0x00, 0x1D, ++0x28, 0x74, 0x80, 0xD0, 0x01, 0x40, 0x07, 0x02, 0x11, 0x00, 0x74, 0x00, 0x10, ++0x81, 0x40, 0x87, 0x00, 0x1D, 0x00, 0x74, 0xA0, 0x12, 0x01, 0x40, 0x04, 0x00, ++0x1D, 0x88, 0x74, 0x08, 0xD0, 0x03, 0x40, 0x04, 0x40, 0x11, 0x20, 0x45, 0x00, ++0xD0, 0x01, 0x40, 0x16, 0x14, 0x1D, 0x00, 0x74, 0x00, 0xD0, 0x01, 0x40, 0x73, ++0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x29, 0x00, 0xAD, 0x00, ++0xB4, 0x02, 0xD0, 0x9A, 0x40, 0x6B, 0x00, 0xA1, 0x00, 0xB4, 0x06, 0x10, 0x1A, ++0x40, 0x6B, 0x02, 0xAD, 0x09, 0xB4, 0x06, 0x10, 0x9A, 0x48, 0x68, 0x20, 0xAD, ++0x01, 0xB0, 0x26, 0xD0, 0x9A, 0x40, 0x20, 0x00, 0x81, 0x08, 0x04, 0x0A, 0xD0, ++0x08, 0x40, 0x23, 0x01, 0x8D, 0x80, 0x34, 0x02, 0xD0, 0x18, 0x40, 0x4B, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x65, 0x00, 0xBD, 0x00, 0xF4, ++0x8A, 0xD0, 0x0B, 0x40, 0x2F, 0x00, 0xB1, 0x00, 0xF4, 0x02, 0x10, 0x0B, 0x40, ++0x6F, 0x00, 0xBD, 0x00, 0xF4, 0x02, 0x10, 0x0B, 0x40, 0x6C, 0x00, 0xBD, 0x00, ++0xF4, 0x12, 0xD0, 0x0B, 0x50, 0x24, 0x00, 0x91, 0x04, 0x44, 0x02, 0xD0, 0x09, ++0x40, 0x26, 0x02, 0x9D, 0x02, 0x74, 0x0A, 0xD0, 0x19, 0x40, 0x63, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x26, ++0xF0, 0x29, 0xC8, 0xA7, 0x40, 0x91, 0x00, 0x7C, 0x2A, 0x34, 0x39, 0xC0, 0xA7, ++0x00, 0x9F, 0x0B, 0x7C, 0x0A, 0x34, 0xA9, 0xD0, 0xA4, 0x00, 0x9F, 0x03, 0x7C, ++0x0A, 0xF0, 0x09, 0xC0, 0x64, 0x00, 0x93, 0x00, 0x4C, 0x02, 0xF0, 0x39, 0xC1, ++0xA7, 0x00, 0x9F, 0x82, 0x7C, 0x0E, 0xF0, 0x29, 0xC0, 0x17, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x25, 0x08, 0x9F, 0x00, 0x78, 0x06, 0xF0, ++0x09, 0x80, 0x27, 0x00, 0x9F, 0x09, 0x7C, 0x02, 0xF0, 0x49, 0xC0, 0x27, 0x00, ++0x9F, 0x01, 0x3C, 0x02, 0xF0, 0x08, 0xC0, 0x27, 0x00, 0x9F, 0x09, 0x7C, 0x06, ++0xF0, 0x98, 0xC0, 0x27, 0x01, 0x8F, 0x01, 0x7C, 0x02, 0xF0, 0x89, 0xC0, 0x27, ++0x00, 0x9F, 0x28, 0x7C, 0x66, 0xF0, 0x09, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0x0D, 0x00, 0x3F, 0x00, 0xCC, 0x00, 0xF0, 0x03, ++0xC0, 0x0B, 0x00, 0x3F, 0x00, 0xBC, 0x00, 0x70, 0x03, 0xC0, 0x0C, 0x00, 0x3F, ++0x00, 0xFE, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xB0, ++0x03, 0xC0, 0x44, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, ++0x1F, 0x12, 0x7C, 0x08, 0x30, 0x01, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x80, 0x14, 0x00, 0x5D, 0x20, 0x40, 0x01, 0x70, 0x05, 0x40, ++0x17, 0x00, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x40, 0x14, 0x00, 0x5D, 0x20, ++0x74, 0x01, 0xD2, 0x05, 0x48, 0x17, 0x00, 0x5D, 0x00, 0x74, 0x01, 0x30, 0x05, ++0xC0, 0x1E, 0x00, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x40, 0x17, 0x10, 0x7D, ++0x03, 0xF4, 0x4D, 0x50, 0x17, 0x50, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0xA0, 0x02, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x50, 0x00, 0x40, 0x03, ++0x00, 0x0D, 0x00, 0x34, 0x00, 0x50, 0x00, 0x40, 0x02, 0x00, 0x0D, 0x00, 0x36, ++0x00, 0xD0, 0x00, 0x40, 0x03, 0x00, 0x09, 0x00, 0x30, 0x00, 0x14, 0x00, 0x40, ++0x34, 0x08, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x4D, 0x00, ++0x34, 0x09, 0x10, 0x8C, 0x41, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x88, 0x38, 0x00, 0xCD, 0x01, 0x84, 0x03, 0x50, 0x0E, 0x40, 0x3B, 0x00, ++0xED, 0x00, 0xB4, 0x03, 0xD0, 0x1E, 0x40, 0x3A, 0x00, 0xED, 0x00, 0xB4, 0x03, ++0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0x34, 0x07, 0x10, 0x0E, 0x40, 0x2A, ++0x00, 0xAD, 0x00, 0xB4, 0x42, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0x6D, 0x42, 0xB4, ++0x05, 0x50, 0x1E, 0x40, 0x05, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++0x10, 0x48, 0x00, 0x2F, 0x01, 0x8D, 0x84, 0x70, 0x12, 0xC0, 0x4B, 0x00, 0x2F, ++0x01, 0xBC, 0x04, 0x72, 0x10, 0xD0, 0x4A, 0x08, 0x2D, 0x21, 0xB4, 0x04, 0xF0, ++0x12, 0xC0, 0x4B, 0x00, 0x2F, 0x01, 0xBC, 0x04, 0x30, 0x12, 0xC0, 0x58, 0x00, ++0xAF, 0x01, 0xBC, 0x06, 0xF0, 0x1E, 0xC0, 0x7B, 0x03, 0xEF, 0x01, 0xBC, 0x05, ++0x30, 0x1E, 0xC0, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, ++0x35, 0x00, 0xDF, 0x00, 0x7E, 0x03, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC8, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0x9F, ++0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF0, ++0x0C, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x4D, ++0x00, 0x3F, 0x01, 0xCC, 0x20, 0xF0, 0x13, 0xC0, 0x4C, 0x00, 0x3F, 0x01, 0xCC, ++0x04, 0xF0, 0x13, 0xC0, 0x4E, 0x00, 0x33, 0x01, 0xCC, 0x84, 0xF0, 0x13, 0xC2, ++0x4F, 0x02, 0x3F, 0x09, 0xFC, 0x04, 0xF0, 0x13, 0xC0, 0x7C, 0x00, 0xBF, 0x01, ++0xFC, 0x07, 0xF0, 0x1E, 0xC0, 0x7C, 0x04, 0x73, 0x01, 0x8C, 0x07, 0x30, 0x17, ++0xC0, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x18, 0x39, 0x08, ++0xED, 0x00, 0x84, 0x03, 0xF0, 0x8E, 0x40, 0x38, 0x00, 0xED, 0x30, 0x94, 0x03, ++0xD0, 0x0E, 0x50, 0x38, 0x42, 0xE1, 0x08, 0x85, 0x23, 0xD0, 0x0E, 0x40, 0x3B, ++0x00, 0xED, 0x08, 0xB4, 0x03, 0xF0, 0x0E, 0x40, 0x08, 0x00, 0xAD, 0x00, 0xB4, ++0x03, 0xF0, 0x0E, 0xC0, 0x3B, 0x00, 0x21, 0x00, 0xAC, 0x12, 0xB0, 0x5E, 0x40, ++0x57, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x2D, ++0x18, 0x84, 0x20, 0xD8, 0x00, 0x40, 0x08, 0x00, 0x3D, 0x00, 0x84, 0x00, 0xD0, ++0x00, 0x40, 0x80, 0x00, 0x01, 0x00, 0x94, 0x00, 0xD0, 0x22, 0x40, 0x8B, 0x20, ++0x2D, 0x08, 0xB4, 0x00, 0xD0, 0x10, 0x40, 0x18, 0x04, 0xAD, 0x00, 0xB4, 0x02, ++0xD0, 0x0F, 0x40, 0x38, 0x00, 0x61, 0x10, 0x84, 0x43, 0x18, 0x4E, 0x40, 0x03, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x31, 0x00, 0xCD, 0x06, ++0x06, 0x0B, 0x50, 0x2C, 0x40, 0x30, 0x00, 0xCD, 0x00, 0x14, 0x0B, 0xD0, 0x0C, ++0x44, 0x30, 0x00, 0xC1, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, ++0x02, 0x34, 0x03, 0x50, 0x0C, 0x50, 0x50, 0x00, 0x8D, 0x00, 0x34, 0x02, 0x50, ++0x7C, 0x40, 0xF3, 0x00, 0x81, 0x03, 0x24, 0x16, 0x90, 0x2D, 0x40, 0x13, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x05, 0x00, 0x1F, 0x01, 0x4C, ++0x28, 0xD0, 0x11, 0xD0, 0x44, 0x00, 0x1F, 0x00, 0x4C, 0x04, 0xF0, 0x31, 0xC0, ++0x44, 0x00, 0x13, 0x01, 0x5C, 0x04, 0xF0, 0x11, 0xC0, 0x47, 0x00, 0x1F, 0x01, ++0x7C, 0x04, 0xD0, 0x00, 0xC0, 0x74, 0x00, 0xDF, 0x01, 0x3C, 0x02, 0xD0, 0x0D, ++0xC1, 0xB8, 0x01, 0x43, 0x03, 0x4C, 0x05, 0x30, 0xBD, 0xC0, 0x57, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x77, 0x00, 0xDF, 0x20, 0x7D, 0x87, ++0xF0, 0x1D, 0xC1, 0x77, 0x00, 0xDF, 0x00, 0x7C, 0x07, 0xF0, 0x1D, 0xC0, 0x77, ++0x10, 0xDF, 0x01, 0x7C, 0x07, 0xF0, 0x1D, 0xC0, 0x73, 0x00, 0xDF, 0x81, 0x7C, ++0x07, 0xF0, 0x1D, 0xC0, 0x27, 0x10, 0x9F, 0x08, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, ++0x35, 0x44, 0x5F, 0x10, 0x7C, 0x0B, 0xF2, 0x3D, 0xC4, 0x07, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x0F, 0x00, 0x13, 0x00, 0xFC, 0x80, 0x30, ++0x03, 0xC0, 0x0B, 0x00, 0x33, 0x00, 0xBC, 0x40, 0x30, 0x02, 0xC1, 0x0C, 0x08, ++0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x32, 0x10, 0xFC, 0x80, ++0xF0, 0x03, 0xC0, 0x0C, 0x00, 0xEF, 0x09, 0xCC, 0x02, 0x30, 0x0F, 0xC0, 0x3F, ++0x00, 0xB3, 0x00, 0xCC, 0x00, 0x30, 0x5F, 0xC0, 0x10, 0x22, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x85, 0x20, 0x32, 0x00, 0xD1, 0x00, 0x34, 0x03, 0x92, 0x0D, ++0x42, 0x37, 0x00, 0xD1, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x40, 0x34, 0x00, 0xDD, ++0x00, 0x76, 0x03, 0xD0, 0x0D, 0x42, 0x37, 0x40, 0xD1, 0x00, 0x64, 0x03, 0xD2, ++0x0D, 0xC0, 0x24, 0x08, 0x9D, 0x01, 0x44, 0x02, 0x14, 0x0D, 0x40, 0x37, 0x00, ++0x95, 0x93, 0x14, 0x0C, 0x10, 0x4D, 0x40, 0x15, 0x02, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0xA0, 0x04, 0x00, 0x11, 0x40, 0x74, 0x00, 0x90, 0x01, 0x40, ++0x07, 0x00, 0x11, 0x00, 0x74, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x1D, 0x00, ++0x74, 0x00, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x15, 0x00, 0x54, 0x00, 0xD0, 0x01, ++0x40, 0x76, 0x80, 0xD9, 0x00, 0x44, 0x03, 0x18, 0x0D, 0x40, 0x37, 0x00, 0xD1, ++0x21, 0x54, 0x0D, 0x12, 0x0D, 0x48, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x28, 0x34, 0x00, 0xC1, 0x00, 0x34, 0x03, 0x94, 0x0C, 0x40, 0x33, ++0x00, 0xC1, 0x00, 0x34, 0x03, 0x14, 0x0C, 0x40, 0x30, 0x00, 0xCD, 0x00, 0x34, ++0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xC5, 0x00, 0x34, 0x03, 0x90, 0x0C, 0x48, ++0x00, 0x00, 0x8D, 0x00, 0x05, 0x03, 0x10, 0x0C, 0x40, 0x37, 0x20, 0x15, 0x00, ++0x54, 0x02, 0x11, 0x0D, 0x40, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xB0, 0x06, 0x00, 0x13, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC8, 0x07, 0x40, ++0x13, 0x00, 0x7C, 0x00, 0x32, 0x01, 0xD0, 0x04, 0x00, 0x1F, 0x00, 0x74, 0x00, ++0xF0, 0x01, 0xC0, 0x07, 0x00, 0x17, 0x00, 0x5C, 0x00, 0xF0, 0x01, 0xD0, 0x04, ++0x10, 0xDF, 0x00, 0x4C, 0x02, 0x30, 0x0D, 0xC0, 0x3B, 0x00, 0x93, 0x00, 0x4C, ++0x02, 0x32, 0x45, 0xC0, 0x00, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xA0, 0x3F, 0x40, 0xFF, 0x80, 0xFC, 0x03, 0x51, 0x0F, 0xC0, 0x3F, 0x00, 0xEF, ++0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC4, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC0, 0x3F, 0x00, 0xFB, 0x00, 0xEC, 0x03, 0xF0, 0x0F, 0xC0, 0x0D, 0x10, ++0xBD, 0x20, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, 0x40, 0xAF, 0x80, 0xFD, 0x02, ++0xF0, 0x29, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, ++0x2F, 0x01, 0x73, 0x01, 0xFC, 0x11, 0x34, 0x33, 0xC0, 0x1E, 0x01, 0xB3, 0x14, ++0xCC, 0x07, 0xF0, 0x0B, 0xC0, 0x3C, 0x01, 0xBF, 0x80, 0xCC, 0x27, 0xF0, 0x83, ++0xC0, 0x78, 0x00, 0x23, 0x01, 0xCC, 0xB3, 0xF0, 0x4B, 0xC0, 0x1A, 0x21, 0x73, ++0x01, 0xEC, 0x10, 0xF2, 0x13, 0xC0, 0x3C, 0x05, 0x7F, 0x01, 0xFC, 0x05, 0xF0, ++0x1F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0xF7, ++0x00, 0xD1, 0x81, 0x74, 0x25, 0x12, 0x0D, 0x40, 0xD4, 0x02, 0x91, 0x03, 0x44, ++0x87, 0xD0, 0x39, 0x80, 0xFE, 0x02, 0x9D, 0x03, 0x44, 0x13, 0xD0, 0x61, 0x40, ++0x34, 0x44, 0x13, 0x81, 0xD4, 0x23, 0xD0, 0xB9, 0x40, 0xD4, 0x02, 0x91, 0x01, ++0x44, 0x31, 0xD1, 0x11, 0x40, 0xFC, 0x00, 0x9D, 0x81, 0x34, 0x87, 0xD0, 0x1D, ++0x44, 0x0F, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xA3, 0x00, ++0xC1, 0x00, 0x74, 0x01, 0x50, 0x4C, 0x40, 0x16, 0x00, 0xC5, 0x00, 0x04, 0x03, ++0xD0, 0x20, 0x40, 0x30, 0x00, 0x8D, 0x02, 0x04, 0x13, 0xD0, 0x28, 0x40, 0x30, ++0x01, 0x01, 0x00, 0x04, 0x13, 0xD0, 0x08, 0x60, 0x13, 0x00, 0x81, 0x80, 0x24, ++0x42, 0xD2, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x02, 0x50, 0x0C, 0x40, ++0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x75, 0x00, 0xD1, ++0x00, 0x74, 0x01, 0x10, 0x1D, 0x40, 0x34, 0x04, 0x95, 0x00, 0x44, 0x13, 0xD0, ++0x39, 0x60, 0x36, 0x00, 0x9D, 0x00, 0x44, 0x03, 0xD0, 0x01, 0x40, 0x74, 0x00, ++0x59, 0x00, 0x54, 0x03, 0xD0, 0x0D, 0x40, 0x15, 0x00, 0x91, 0x10, 0x44, 0x63, ++0xD0, 0x21, 0x40, 0x36, 0x00, 0x9D, 0x06, 0x74, 0x9B, 0xD8, 0x0D, 0x40, 0x0F, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xA8, 0x23, 0x40, 0x93, 0x40, ++0x3C, 0x3B, 0x71, 0x1D, 0xC0, 0xD2, 0x00, 0x97, 0x00, 0x4C, 0x07, 0xF0, 0x1D, ++0xC0, 0x34, 0x00, 0x8F, 0x00, 0x4D, 0x03, 0xF0, 0x91, 0xD0, 0x34, 0x00, 0x11, ++0x07, 0x4C, 0x03, 0xF0, 0x0C, 0xC0, 0x13, 0x46, 0x53, 0x00, 0x6C, 0x0C, 0xF0, ++0x98, 0xE0, 0x36, 0x00, 0x5F, 0x00, 0x7C, 0x05, 0xE0, 0x0D, 0xC0, 0x0B, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x25, 0x00, 0xBF, 0x45, 0xFC, ++0x05, 0xF0, 0x0F, 0xC0, 0x9F, 0x40, 0xEB, 0x00, 0xFC, 0x03, 0xF0, 0x0E, 0xC0, ++0x3F, 0x10, 0xDF, 0x04, 0xFC, 0x03, 0xF0, 0x0C, 0xC0, 0x3F, 0x40, 0xB7, 0x04, ++0xFC, 0x03, 0xF0, 0x0B, 0xC4, 0x7E, 0x00, 0xFF, 0x00, 0x7C, 0x84, 0xF0, 0x03, ++0x70, 0x35, 0x00, 0xBF, 0x01, 0xFC, 0x07, 0xF0, 0x0F, 0xC0, 0x1F, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x25, 0x00, 0x93, 0x01, 0x7C, 0x03, ++0xF0, 0x0D, 0xC0, 0x17, 0x00, 0xD3, 0x10, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x34, ++0x00, 0x97, 0x00, 0x4C, 0x03, 0xF0, 0x09, 0xC0, 0x34, 0x00, 0xDB, 0x10, 0x5C, ++0x03, 0xF0, 0x0D, 0xC0, 0x96, 0x84, 0x93, 0x02, 0x7C, 0x08, 0xB4, 0x2D, 0xC0, ++0x37, 0x00, 0xD7, 0x02, 0x7C, 0x02, 0xB0, 0x0D, 0xC0, 0x29, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1B, 0xA0, 0xE4, 0x01, 0x91, 0x00, 0x76, 0x05, 0xD0, ++0x0D, 0x40, 0x37, 0x00, 0xD1, 0x00, 0x74, 0x03, 0xF0, 0x0D, 0xC0, 0x3D, 0x01, ++0xD1, 0x00, 0x44, 0x83, 0xDA, 0x0D, 0x40, 0x34, 0x00, 0xCB, 0x82, 0xC4, 0x43, ++0xD1, 0x0D, 0xC0, 0x37, 0x10, 0x8B, 0x1A, 0x76, 0x00, 0x10, 0x05, 0x40, 0x3F, ++0x00, 0x91, 0x00, 0x74, 0x03, 0xB0, 0x1D, 0xC0, 0x4F, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0xA0, 0x22, 0x01, 0x01, 0x00, 0x34, 0x05, 0xD0, 0x0D, ++0x40, 0x33, 0x02, 0x81, 0x02, 0x34, 0x03, 0xD0, 0x08, 0x44, 0x30, 0x00, 0xC5, ++0x00, 0x24, 0x03, 0xD0, 0x04, 0x40, 0x34, 0x00, 0x01, 0x00, 0x14, 0x07, 0xC0, ++0x08, 0x40, 0xF0, 0x20, 0xC1, 0x03, 0x34, 0x00, 0x90, 0x04, 0x48, 0x33, 0x00, ++0x80, 0x00, 0x36, 0x02, 0x50, 0x8C, 0x40, 0x4E, 0x00, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0D, 0x80, 0x78, 0x20, 0xE1, 0x81, 0xB4, 0x47, 0xD0, 0x1E, 0x60, ++0x5B, 0x10, 0xA1, 0x81, 0xB4, 0x07, 0x50, 0x9B, 0x42, 0x79, 0x00, 0xA1, 0x01, ++0xA4, 0x07, 0xD8, 0x12, 0x40, 0x7C, 0x00, 0xF9, 0x01, 0xA4, 0x07, 0xD0, 0x1A, ++0x40, 0x5E, 0x04, 0xA9, 0x01, 0xB4, 0x05, 0x90, 0x52, 0x40, 0x7B, 0x00, 0xA1, ++0x01, 0xB4, 0x06, 0x90, 0x1E, 0x40, 0x36, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x10, 0x20, 0x00, 0x81, 0x00, 0x34, 0x01, 0xF2, 0x0C, 0xE0, 0x33, ++0x40, 0xC3, 0x00, 0x3C, 0x03, 0xD0, 0x0D, 0xC0, 0x30, 0x00, 0xC6, 0x20, 0x24, ++0x03, 0xD0, 0x4C, 0xC0, 0x30, 0x30, 0x83, 0x58, 0x1C, 0x03, 0xF0, 0x08, 0xC0, ++0x30, 0x00, 0x81, 0x00, 0x34, 0x02, 0xB4, 0x0C, 0xC0, 0x33, 0x40, 0x87, 0x00, ++0x3C, 0x02, 0x70, 0x0C, 0xC4, 0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xB8, 0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3B, 0x02, ++0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0xB3, 0x00, 0xBF, 0x00, 0x5C, 0x03, ++0xF0, 0x03, 0xD0, 0x3F, 0x00, 0xFF, 0x20, 0xDC, 0x03, 0xF0, 0x0E, 0xC0, 0x1F, ++0x00, 0xBF, 0x00, 0xFC, 0x23, 0x70, 0x4B, 0xCA, 0xBF, 0x82, 0xBF, 0x00, 0xFC, ++0x02, 0xF0, 0x0E, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA8, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC2, 0x77, 0x00, 0x93, ++0x80, 0x5C, 0x83, 0x70, 0x09, 0x80, 0xB5, 0x22, 0xD3, 0x00, 0x5C, 0x03, 0xF0, ++0x05, 0xC0, 0x77, 0x20, 0x53, 0x00, 0x7C, 0x33, 0xE0, 0x0D, 0xC0, 0x37, 0x00, ++0xDF, 0x00, 0x78, 0x03, 0xB0, 0x1D, 0xC0, 0x36, 0x81, 0xDF, 0x00, 0x4C, 0x02, ++0xF0, 0x0D, 0xC0, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x98, ++0xB9, 0x10, 0xAD, 0x40, 0x9C, 0x0B, 0xD3, 0x0E, 0x40, 0x13, 0x01, 0xE1, 0x00, ++0x84, 0x03, 0xD0, 0x2A, 0x40, 0x30, 0x11, 0xE1, 0x22, 0xB4, 0x83, 0xD0, 0x0E, ++0x40, 0x3B, 0x00, 0xE1, 0x00, 0xB4, 0x53, 0x80, 0x0A, 0x40, 0xBB, 0x00, 0xED, ++0x00, 0x34, 0x03, 0x10, 0x0E, 0x60, 0x38, 0x08, 0xAD, 0x00, 0x94, 0x02, 0xD0, ++0x0E, 0x40, 0x4F, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x79, ++0x05, 0xAD, 0x03, 0xB4, 0x57, 0xD0, 0x1E, 0x40, 0x7B, 0x03, 0xC1, 0x09, 0x96, ++0x47, 0xD0, 0x7C, 0x4C, 0x79, 0x60, 0xE1, 0x05, 0xB6, 0x07, 0xD0, 0x1E, 0x40, ++0x7B, 0x00, 0xE1, 0x83, 0xB4, 0x07, 0xC0, 0xDE, 0x08, 0x7B, 0x01, 0xAD, 0x01, ++0xB4, 0x07, 0x10, 0x1F, 0x40, 0x7A, 0x92, 0xED, 0x43, 0x84, 0x06, 0xD0, 0x1E, ++0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x33, 0x00, ++0x8D, 0x40, 0x14, 0x02, 0xD0, 0x3D, 0x41, 0x23, 0x00, 0xC1, 0x00, 0x04, 0x06, ++0xD0, 0x1C, 0x40, 0x30, 0x00, 0xC1, 0x00, 0x74, 0x03, 0xD0, 0xEC, 0x60, 0x23, ++0x00, 0xC1, 0x07, 0x34, 0x03, 0x91, 0x1C, 0x40, 0xA3, 0x09, 0x8D, 0x00, 0x34, ++0x1F, 0x10, 0x3C, 0x44, 0x30, 0x00, 0x8D, 0x00, 0x14, 0x02, 0xD0, 0x0C, 0x40, ++0x5B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x11, 0x10, 0x6F, ++0x00, 0xBC, 0x21, 0xF0, 0x07, 0xC1, 0x1F, 0x40, 0x53, 0x00, 0x5C, 0x01, 0x72, ++0x17, 0xC2, 0x15, 0x00, 0x52, 0x00, 0x7C, 0x01, 0xF0, 0x37, 0xC0, 0x17, 0x00, ++0x73, 0x23, 0x7C, 0x01, 0xF2, 0x15, 0xC3, 0x9F, 0x01, 0x7F, 0x05, 0xFC, 0x1D, ++0x34, 0x17, 0xC5, 0x16, 0x00, 0x7F, 0x40, 0xCC, 0x81, 0xE0, 0x05, 0xC0, 0x5F, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x87, 0x20, 0x1F, 0x04, ++0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x02, 0x1F, 0x08, 0x7C, 0x00, 0xF0, 0x01, ++0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x00, 0xC8, 0x07, 0x42, 0x1F, ++0x02, 0x3C, 0x00, 0xB0, 0x01, 0xC2, 0x03, 0x00, 0x1F, 0x00, 0x3C, 0x00, 0x70, ++0x01, 0xC0, 0x07, 0x00, 0x1B, 0x20, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x4B, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x27, 0x01, 0x9B, 0x01, 0x4C, ++0x22, 0x30, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x01, 0x4C, 0x02, 0xF0, 0x09, 0xD0, ++0x61, 0x00, 0x96, 0x04, 0x7C, 0x02, 0x70, 0x09, 0xC2, 0x24, 0x00, 0x9F, 0x00, ++0x5C, 0x02, 0x78, 0x89, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x7C, 0x02, 0x30, 0x49, ++0xC9, 0x27, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x30, 0x09, 0xC0, 0x43, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xEE, 0x00, 0x91, 0x89, 0xC4, 0x06, ++0x10, 0x09, 0x40, 0x6C, 0x00, 0xAD, 0x03, 0x44, 0x02, 0xD0, 0x0B, 0x42, 0x64, ++0x00, 0xB1, 0x07, 0x74, 0x02, 0x10, 0x09, 0x40, 0xA4, 0x82, 0x8D, 0x02, 0x44, ++0x02, 0x10, 0x0B, 0x48, 0x2F, 0x00, 0x91, 0x40, 0x74, 0x02, 0xB0, 0x79, 0x40, ++0x27, 0x00, 0x87, 0x00, 0x2C, 0x02, 0x50, 0x09, 0x40, 0x07, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x04, 0x91, 0x00, 0x44, 0x02, 0x16, ++0x0D, 0x60, 0x24, 0x01, 0x9D, 0x0A, 0x40, 0x02, 0xD0, 0x08, 0x40, 0x24, 0x02, ++0x9D, 0x00, 0x74, 0x02, 0x50, 0x09, 0x40, 0xA4, 0x20, 0x9D, 0x18, 0x54, 0x02, ++0x50, 0x09, 0x41, 0x27, 0x00, 0x91, 0x00, 0x64, 0x02, 0x00, 0x09, 0x40, 0x27, ++0x00, 0x98, 0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x73, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x81, 0x00, 0x04, 0x02, 0x10, 0x88, ++0x40, 0x20, 0x00, 0x8D, 0x00, 0x04, 0x0A, 0xD0, 0x28, 0x40, 0x20, 0x00, 0x89, ++0x00, 0x34, 0x22, 0x50, 0x88, 0x40, 0x20, 0x02, 0x8D, 0x40, 0x00, 0x0A, 0x10, ++0x08, 0x48, 0x23, 0x40, 0x81, 0x00, 0x34, 0x22, 0x98, 0x08, 0x40, 0x23, 0x20, ++0x95, 0xC2, 0x64, 0x0A, 0x10, 0x08, 0x40, 0x53, 0xA0, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xB0, 0x46, 0x40, 0x13, 0x00, 0x4C, 0x04, 0x32, 0x21, 0xD0, ++0x44, 0x00, 0x1F, 0x01, 0x4D, 0x00, 0xF0, 0x11, 0xC0, 0x05, 0x15, 0x1F, 0x01, ++0x7C, 0x08, 0x70, 0x61, 0xD1, 0x80, 0x00, 0x1D, 0x00, 0x5C, 0x50, 0x50, 0x11, ++0x40, 0x47, 0x00, 0x53, 0x40, 0x6C, 0x58, 0x30, 0x01, 0xC0, 0x07, 0x05, 0x0F, ++0x00, 0x4D, 0x00, 0x34, 0x01, 0xC4, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x19, 0xB8, 0xAF, 0x08, 0xBF, 0x00, 0xFD, 0x0A, 0xF0, 0x4B, 0xC0, 0xAF, ++0x00, 0xBF, 0x02, 0xFC, 0x06, 0xF0, 0x3B, 0xC0, 0x27, 0x00, 0xB3, 0x02, 0x7C, ++0x12, 0xB1, 0x4B, 0x80, 0x2F, 0x01, 0xBF, 0x00, 0x7C, 0x06, 0xF0, 0x2B, 0xC0, ++0xAF, 0x08, 0xBF, 0x00, 0xF8, 0x12, 0xF2, 0x0A, 0xC4, 0x27, 0x00, 0xB7, 0x01, ++0xDC, 0x06, 0xF0, 0x09, 0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0xA0, 0x6F, 0x00, 0xBF, 0x40, 0xC4, 0x56, 0xF0, 0x09, 0xC0, 0x6F, 0x01, ++0xBF, 0x41, 0x7C, 0x02, 0x30, 0x79, 0xC0, 0x2C, 0x00, 0xFF, 0x31, 0x4C, 0x22, ++0xF0, 0x49, 0xC0, 0x2C, 0x00, 0xB3, 0x00, 0xFC, 0x02, 0xB0, 0x5B, 0xC1, 0x6D, ++0x14, 0xB3, 0x60, 0x4C, 0x52, 0x32, 0x0B, 0xC0, 0x27, 0x28, 0x9F, 0x02, 0x7C, ++0x0A, 0xF0, 0x0B, 0xC6, 0x63, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, ++0x08, 0x07, 0x00, 0x1D, 0x00, 0x44, 0x08, 0xD0, 0x01, 0x43, 0x97, 0x00, 0x1D, ++0x02, 0x34, 0x54, 0x52, 0x75, 0x50, 0x84, 0x00, 0x1D, 0x02, 0x54, 0x00, 0x90, ++0x41, 0x11, 0x04, 0x41, 0x11, 0x00, 0x74, 0x9C, 0x10, 0x21, 0x40, 0x84, 0x00, ++0x51, 0x00, 0x54, 0x11, 0x50, 0x05, 0x00, 0x87, 0x10, 0x1D, 0x01, 0x74, 0x04, ++0xD0, 0x01, 0x40, 0x73, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, ++0xA3, 0x80, 0xDD, 0x00, 0x14, 0x02, 0xD0, 0x08, 0x40, 0xB3, 0x30, 0x8C, 0x02, ++0x34, 0x02, 0x10, 0xC8, 0x40, 0x22, 0x02, 0x8D, 0x00, 0x04, 0x02, 0x50, 0xC8, ++0x40, 0x20, 0x25, 0x80, 0x00, 0x34, 0x62, 0x92, 0x08, 0x60, 0x23, 0x00, 0x95, ++0x00, 0x14, 0x52, 0xD0, 0x08, 0x42, 0x23, 0x82, 0x8D, 0x00, 0x34, 0x02, 0xD0, ++0x08, 0x40, 0x4B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, ++0x00, 0x9D, 0x22, 0x54, 0x02, 0xD0, 0x69, 0x42, 0x27, 0x00, 0x9D, 0x00, 0x34, ++0x02, 0x50, 0x09, 0x40, 0x26, 0x80, 0x9D, 0x00, 0x54, 0x82, 0x90, 0x08, 0x41, ++0x20, 0x00, 0x91, 0x24, 0x76, 0x02, 0x10, 0x09, 0x40, 0x24, 0x02, 0xD5, 0x48, ++0x14, 0x02, 0x50, 0x09, 0x42, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x1A, 0xD0, 0x09, ++0x40, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, ++0x8F, 0x82, 0x5D, 0x82, 0xF0, 0x09, 0xC0, 0x27, 0x02, 0x9F, 0x00, 0xFC, 0x02, ++0x30, 0xAB, 0xC0, 0x26, 0x10, 0x9F, 0x00, 0x4C, 0x02, 0xF0, 0x29, 0xC0, 0x24, ++0x00, 0x93, 0x04, 0xFC, 0x02, 0xB0, 0x18, 0xC8, 0x27, 0x40, 0x87, 0x00, 0x5C, ++0x0A, 0x60, 0x29, 0xC0, 0x27, 0x00, 0xBF, 0x24, 0xFC, 0x02, 0xF0, 0x09, 0xC0, ++0x17, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80, 0x25, 0x00, 0x9F, ++0x00, 0x6C, 0x0E, 0xF0, 0x19, 0xC0, 0x27, 0x00, 0x9E, 0x09, 0x7C, 0x0E, 0xF0, ++0x08, 0xC0, 0x25, 0x80, 0x8F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC2, 0xA7, 0x14, ++0x9F, 0x20, 0x3C, 0x02, 0x70, 0x59, 0xCA, 0x27, 0x08, 0x9B, 0x11, 0x7C, 0x02, ++0xF8, 0x49, 0xC0, 0x27, 0x80, 0x9F, 0x00, 0x7C, 0x02, 0xF2, 0x09, 0xC0, 0x4B, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0xB0, 0x01, 0xC0, 0x87, 0x00, 0x1B, 0x10, 0x7C, 0x00, 0x30, 0x21, ++0xD0, 0x04, 0x02, 0x1F, 0x08, 0x4D, 0x00, 0xF0, 0x01, 0xE0, 0x04, 0x00, 0x17, ++0x10, 0x4C, 0x00, 0xF0, 0x41, 0xC0, 0x02, 0x40, 0x13, 0x02, 0x4C, 0x08, 0xF2, ++0x01, 0xC0, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x43, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x1C, 0x00, 0x5D, 0x00, 0x70, ++0x01, 0x18, 0x05, 0x48, 0x17, 0x00, 0x7C, 0x03, 0x74, 0x01, 0x10, 0x05, 0x50, ++0x54, 0x00, 0x7C, 0x03, 0x44, 0x01, 0xD0, 0x05, 0x40, 0x9C, 0x01, 0x7D, 0x41, ++0x7C, 0x11, 0x70, 0x07, 0xC0, 0xDE, 0x01, 0x70, 0x03, 0x68, 0x01, 0x10, 0x37, ++0x05, 0x14, 0x80, 0x5D, 0x00, 0x74, 0x01, 0xC0, 0x45, 0x40, 0x53, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x22, 0x20, 0x8D, 0x00, 0x30, 0x06, ++0x10, 0x0C, 0x40, 0x23, 0x10, 0x8C, 0x08, 0x36, 0x03, 0x10, 0x0C, 0x40, 0x30, ++0x00, 0x8D, 0x13, 0x24, 0x03, 0xC0, 0x0C, 0x40, 0xB0, 0x00, 0xCD, 0x00, 0x24, ++0x03, 0x50, 0x38, 0x40, 0x20, 0x29, 0xC0, 0x0A, 0x04, 0x03, 0x90, 0x38, 0x01, ++0x31, 0x00, 0xCD, 0x80, 0x36, 0x03, 0xC0, 0x0C, 0x40, 0x53, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x38, 0x00, 0xED, 0x40, 0xB4, 0x0F, 0x10, ++0x0E, 0x48, 0x3B, 0x00, 0xAD, 0x00, 0xB4, 0x23, 0x10, 0x4C, 0x40, 0x28, 0x00, ++0xAD, 0x00, 0xA4, 0x03, 0xD0, 0x4E, 0x60, 0x38, 0x80, 0xFD, 0x03, 0xA4, 0x23, ++0x50, 0x28, 0x40, 0x3A, 0x00, 0xF1, 0x00, 0x26, 0x23, 0x10, 0x1B, 0x40, 0x38, ++0x00, 0xED, 0x04, 0xB4, 0x13, 0x90, 0x0E, 0x40, 0x07, 0x20, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x10, 0x68, 0x00, 0xEF, 0x01, 0x3C, 0x07, 0x34, 0x3E, ++0xC0, 0x7B, 0x00, 0xAF, 0x81, 0xBC, 0x07, 0x34, 0x7E, 0x40, 0x78, 0x00, 0xAD, ++0x01, 0xA4, 0x1F, 0xF9, 0xBF, 0x40, 0x48, 0x00, 0xE7, 0x01, 0xAC, 0x17, 0x70, ++0x16, 0xE0, 0x68, 0x00, 0xE3, 0x01, 0x8C, 0x57, 0xB0, 0x1E, 0xE0, 0x79, 0x00, ++0xED, 0x03, 0xBE, 0x0F, 0xF0, 0x1E, 0xC4, 0x47, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xB8, 0x25, 0x20, 0xDF, 0x00, 0x7C, 0x03, 0xF1, 0x0D, 0x44, ++0x37, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xD0, 0x0D, 0x40, 0x27, 0x10, 0x8F, 0x00, ++0x5C, 0x4B, 0xF0, 0x6D, 0xD0, 0x07, 0x00, 0x0F, 0x00, 0x7C, 0x83, 0x70, 0x05, ++0xC0, 0x33, 0x08, 0xCF, 0x00, 0x7C, 0x0B, 0x71, 0x0C, 0xC0, 0x37, 0x10, 0xDF, ++0x00, 0x74, 0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA0, 0x6F, 0x00, 0xF3, 0x09, 0xFC, 0x83, 0x30, 0x9F, 0xC0, 0x7F, ++0x02, 0xF3, 0x01, 0xFC, 0x07, 0xF0, 0x1E, 0x80, 0x7D, 0x00, 0xBF, 0x01, 0xFC, ++0x27, 0x30, 0x1F, 0xC0, 0x7E, 0x22, 0xFF, 0x01, 0xFC, 0x06, 0xF0, 0x1F, 0xC0, ++0x6C, 0x00, 0xFF, 0x01, 0xFC, 0x07, 0xB0, 0x1B, 0xC0, 0x7F, 0x02, 0xEF, 0x09, ++0x8C, 0x07, 0x30, 0x1F, 0xC0, 0x03, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x88, 0x39, 0x00, 0xE1, 0x80, 0xB0, 0x53, 0xB4, 0x0E, 0x46, 0x3B, 0x02, ++0xE1, 0x80, 0xB4, 0x03, 0x70, 0x4E, 0x48, 0x39, 0x00, 0xAD, 0x04, 0xB4, 0x03, ++0x10, 0x0E, 0x41, 0x38, 0x00, 0xED, 0x06, 0xB4, 0x02, 0x90, 0x0E, 0xC4, 0x39, ++0x00, 0x2F, 0x00, 0xF4, 0x83, 0x10, 0x4A, 0x00, 0x3B, 0x08, 0xED, 0x20, 0xAC, ++0x03, 0xF0, 0x0E, 0x40, 0x57, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x29, 0x04, 0xE1, 0x00, 0x30, 0x33, 0x18, 0x0E, 0x60, 0x33, 0xC0, 0xE9, ++0x10, 0xB4, 0x27, 0xD0, 0x1F, 0x72, 0x3B, 0x00, 0xAD, 0x80, 0xB4, 0x03, 0x98, ++0x0C, 0x40, 0x29, 0x20, 0xEC, 0x10, 0xA4, 0x02, 0xD0, 0x0E, 0x40, 0x2A, 0x00, ++0xED, 0x00, 0xB4, 0x03, 0x50, 0x0E, 0x48, 0x3B, 0xA0, 0xFD, 0x11, 0xC4, 0x07, ++0x10, 0x0E, 0x40, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, ++0x63, 0x00, 0xC1, 0x20, 0x34, 0x8B, 0x90, 0x1C, 0x40, 0xB3, 0x01, 0x49, 0x20, ++0x34, 0x07, 0x50, 0x2C, 0x40, 0x31, 0x00, 0x8D, 0x01, 0x34, 0x03, 0x94, 0x1C, ++0x64, 0x61, 0x00, 0x0D, 0x13, 0x74, 0x82, 0x90, 0x9C, 0x40, 0xF1, 0x00, 0x05, ++0x03, 0x34, 0x03, 0x11, 0x1C, 0x40, 0x33, 0x10, 0xCD, 0x03, 0x04, 0x0B, 0x58, ++0x0C, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x65, ++0x00, 0xC3, 0x04, 0x7C, 0x07, 0x10, 0x1F, 0x40, 0x37, 0x04, 0x8B, 0x01, 0x74, ++0x03, 0xF0, 0x0D, 0xD0, 0x37, 0x00, 0xDF, 0x11, 0xFC, 0x03, 0xB0, 0x2F, 0xC0, ++0x35, 0x11, 0x5F, 0x03, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0xA6, 0x08, 0x9D, 0x04, ++0xFC, 0x17, 0x54, 0x68, 0xC0, 0x37, 0x00, 0xDF, 0xC3, 0x45, 0x13, 0x15, 0x0D, ++0xC0, 0x57, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x40, ++0xDF, 0x00, 0x7C, 0x13, 0x70, 0x8D, 0xC0, 0x37, 0x00, 0x97, 0x00, 0x7C, 0x23, ++0xF0, 0x4D, 0xD0, 0x27, 0x00, 0xDF, 0x02, 0x7C, 0x03, 0x70, 0x0D, 0x00, 0xB4, ++0x08, 0x5F, 0x80, 0x7C, 0x02, 0xB2, 0x09, 0xC0, 0x27, 0x06, 0x9F, 0x02, 0x3C, ++0x03, 0x50, 0x09, 0xC0, 0x33, 0x00, 0xDE, 0x00, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, ++0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x27, 0x00, 0xFF, ++0x90, 0xCD, 0x03, 0xF1, 0x0F, 0xC1, 0x3E, 0x00, 0xBF, 0x01, 0xCE, 0x03, 0x32, ++0x0F, 0xE0, 0x2C, 0x00, 0xBF, 0x01, 0xFC, 0x03, 0xF0, 0x0F, 0xC1, 0x5F, 0x00, ++0x7F, 0x01, 0xFC, 0x23, 0x38, 0x05, 0xE0, 0x2C, 0x01, 0x38, 0x90, 0xFC, 0x03, ++0x30, 0x4B, 0xDD, 0x3D, 0x00, 0xF3, 0x10, 0xCC, 0x43, 0x78, 0x9F, 0xC0, 0x13, ++0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x56, 0x00, 0xDD, 0x49, ++0x44, 0x03, 0x70, 0x0C, 0x40, 0x74, 0x08, 0x9D, 0x00, 0x04, 0x03, 0xB0, 0x0D, ++0xC0, 0x66, 0x80, 0x9D, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0xC0, 0x15, 0x03, 0x1D, ++0x23, 0x5C, 0x02, 0xB0, 0x04, 0x44, 0x25, 0x00, 0x1D, 0x41, 0x74, 0x03, 0x70, ++0x09, 0x40, 0x34, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0xD0, 0x1D, 0x40, 0x17, 0x02, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0xA4, 0x01, 0xDD, 0x00, 0x44, ++0x07, 0xD0, 0x0D, 0x60, 0x36, 0x02, 0x9D, 0x04, 0x44, 0x03, 0x10, 0x0C, 0x48, ++0x34, 0x02, 0xDD, 0x06, 0x74, 0x03, 0xD0, 0x0D, 0x60, 0x07, 0x00, 0x9D, 0x44, ++0x74, 0x03, 0x93, 0x0D, 0x40, 0xA4, 0x00, 0x9D, 0x01, 0x74, 0x03, 0x10, 0x29, ++0x40, 0x34, 0x00, 0xC0, 0x00, 0x44, 0x03, 0xD0, 0x0D, 0x40, 0x07, 0x20, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0xDD, 0x20, 0x04, 0x03, ++0xD0, 0x0D, 0x40, 0x30, 0x80, 0x8D, 0x00, 0x45, 0x03, 0x99, 0x0C, 0x40, 0x30, ++0x80, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x01, 0x00, 0x8D, 0x00, 0x10, ++0x02, 0x90, 0x0C, 0x60, 0x11, 0x00, 0x0D, 0x00, 0x34, 0x03, 0x50, 0x08, 0x40, ++0x30, 0x40, 0xC1, 0x00, 0x24, 0x03, 0xD0, 0x08, 0x40, 0x43, 0xA1, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x26, 0x00, 0xDD, 0x00, 0x44, 0x03, 0xF8, ++0x0D, 0xC0, 0x36, 0x00, 0xDF, 0x40, 0xC6, 0x03, 0x32, 0x0F, 0x50, 0x24, 0x20, ++0x5D, 0x00, 0xBC, 0x03, 0xF0, 0x0F, 0xC0, 0x07, 0x00, 0x9D, 0x00, 0x78, 0x03, ++0x90, 0x0D, 0x40, 0x24, 0x08, 0x1F, 0x00, 0xFC, 0x03, 0x31, 0x05, 0xC0, 0x35, ++0x00, 0xF3, 0x00, 0xCC, 0x03, 0xF0, 0x0D, 0xC0, 0x03, 0xC4, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0xB8, 0x1F, 0x20, 0xFF, 0x00, 0xFC, 0x03, 0x7A, 0x0F, ++0xC0, 0x3F, 0x00, 0x7C, 0x00, 0xFC, 0x03, 0xF3, 0x0F, 0xC0, 0x2F, 0x00, 0x7F, ++0x00, 0xFC, 0x83, 0xF1, 0x0F, 0x80, 0x0D, 0x00, 0x3E, 0x00, 0xDC, 0x82, 0xF0, ++0x0F, 0xC0, 0x1F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0x70, 0x07, 0x40, 0x3F, 0x00, ++0xF7, 0x00, 0xFC, 0x03, 0xF8, 0x0B, 0xC0, 0x17, 0x20, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x80, 0x5F, 0x00, 0x33, 0x8C, 0xCC, 0x10, 0x30, 0x1F, 0xC0, ++0x2F, 0x00, 0x33, 0x00, 0xCC, 0x02, 0x30, 0x1F, 0xE0, 0x7F, 0x00, 0xBB, 0x01, ++0xF4, 0x07, 0x70, 0x0B, 0xC0, 0x7C, 0x05, 0xFF, 0x42, 0xFC, 0x32, 0xF0, 0x4F, ++0xC8, 0x3F, 0x01, 0xFF, 0x01, 0xFC, 0x0C, 0x30, 0x4F, 0xC0, 0x4E, 0x00, 0xB3, ++0x00, 0x7C, 0x73, 0xF0, 0x4F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x08, 0x77, 0x00, 0x11, 0x0E, 0x6C, 0x24, 0x30, 0x1D, 0x40, 0x23, ++0x00, 0x51, 0x03, 0x14, 0x02, 0x50, 0x4D, 0x49, 0x33, 0x10, 0xC1, 0x10, 0x74, ++0x04, 0x10, 0xB9, 0xE0, 0xFE, 0x00, 0xFD, 0x0A, 0x74, 0x22, 0xD0, 0xBF, 0x40, ++0x3F, 0x0B, 0xCD, 0x00, 0x74, 0x00, 0x50, 0x3D, 0x40, 0x44, 0x00, 0x91, 0x0B, ++0xF4, 0x03, 0xD1, 0x1F, 0x40, 0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x11, 0xA0, 0x27, 0x00, 0x41, 0x00, 0x05, 0x00, 0x10, 0x0C, 0x40, 0x23, 0x00, ++0x81, 0x02, 0x04, 0x03, 0x10, 0x4C, 0x40, 0x33, 0x00, 0xC9, 0x00, 0x74, 0x03, ++0x54, 0x04, 0x50, 0x32, 0x20, 0xC5, 0x84, 0x34, 0x12, 0xD0, 0x0C, 0x40, 0x31, ++0x04, 0xCD, 0x00, 0x54, 0x11, 0x10, 0x2C, 0x48, 0x46, 0x80, 0xC1, 0x00, 0x14, ++0x13, 0xD0, 0x2C, 0x40, 0x47, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA8, 0x25, 0x02, 0x51, 0x00, 0x44, 0x08, 0x10, 0x0D, 0x40, 0x27, 0x02, 0x51, ++0x00, 0x54, 0x03, 0x50, 0x0D, 0x48, 0x37, 0x00, 0xD9, 0x03, 0x74, 0x18, 0x14, ++0x15, 0x50, 0x36, 0x00, 0xD9, 0x00, 0x70, 0x22, 0xD0, 0x0D, 0x40, 0x37, 0x20, ++0xDD, 0x00, 0x74, 0x09, 0x50, 0x0D, 0x40, 0x46, 0x40, 0xD1, 0x11, 0x74, 0x03, ++0xD1, 0x0D, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, ++0x53, 0x01, 0x13, 0x10, 0x44, 0x0C, 0x30, 0x0D, 0xC0, 0x27, 0x40, 0x13, 0x80, ++0x44, 0x06, 0x34, 0x0D, 0x40, 0x37, 0x00, 0xDB, 0x01, 0x3C, 0x09, 0x70, 0x31, ++0x40, 0x36, 0x30, 0xDF, 0x00, 0x78, 0x02, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x7C, 0x0C, 0x30, 0x0D, 0xC0, 0x42, 0x10, 0xD3, 0x01, 0x7C, 0x03, 0xF1, ++0x0D, 0xC0, 0x03, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x7D, ++0x50, 0xEF, 0x10, 0xBC, 0x22, 0x70, 0x0F, 0xC0, 0x2B, 0x00, 0x9F, 0x00, 0xB8, ++0x26, 0xB0, 0x0F, 0x88, 0x3F, 0x00, 0xF7, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, ++0x3F, 0x00, 0xFF, 0x20, 0xF8, 0x06, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x10, ++0xFC, 0x24, 0xF0, 0x0E, 0xC0, 0x0D, 0x28, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, ++0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x25, 0x08, ++0x1F, 0x00, 0x6C, 0x29, 0x30, 0x0D, 0xC0, 0x27, 0x01, 0xC7, 0x80, 0x4C, 0x03, ++0x34, 0x0D, 0xC0, 0x34, 0x00, 0xDF, 0x02, 0x4E, 0x08, 0x22, 0x05, 0xC8, 0x34, ++0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xDF, 0x00, 0x6D, ++0x09, 0x70, 0x0D, 0xC0, 0x07, 0x00, 0xDF, 0x0A, 0x7C, 0x03, 0xF1, 0x0D, 0xC4, ++0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x24, 0x00, 0xDD, ++0x00, 0x45, 0x03, 0x10, 0x0D, 0x40, 0xA7, 0x00, 0xD1, 0x00, 0x4D, 0x03, 0x10, ++0x0D, 0xC0, 0x76, 0x02, 0xD1, 0x00, 0x45, 0x01, 0xB0, 0x04, 0xC1, 0x3E, 0x00, ++0xFD, 0x00, 0x7C, 0x03, 0xC1, 0x1F, 0xC1, 0x3E, 0x00, 0xDD, 0x00, 0x04, 0x01, ++0x10, 0x0F, 0xC0, 0x45, 0x00, 0xDD, 0x41, 0xF4, 0x83, 0xD0, 0x5F, 0x40, 0x4F, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x22, 0x00, 0x8D, 0x01, ++0x04, 0x07, 0x10, 0x0C, 0x40, 0x32, 0x00, 0x05, 0x00, 0x04, 0x03, 0xD0, 0x0C, ++0x40, 0xF4, 0x00, 0xC5, 0x00, 0x04, 0x06, 0x18, 0x08, 0x40, 0x70, 0x00, 0xCD, ++0x80, 0x34, 0x03, 0xC0, 0x1C, 0x40, 0x30, 0x08, 0xCD, 0xC0, 0x04, 0x01, 0x50, ++0x0C, 0x40, 0x53, 0x00, 0xCD, 0x00, 0x14, 0x03, 0xD0, 0x0C, 0x40, 0x1F, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x68, 0x00, 0x2D, 0x19, 0x04, ++0x07, 0x10, 0x1E, 0x40, 0x6B, 0x00, 0x61, 0x01, 0xA4, 0x27, 0x90, 0x1E, 0x40, ++0x7A, 0x00, 0xE1, 0x01, 0xC4, 0x04, 0x99, 0x9A, 0x40, 0x7A, 0x00, 0xED, 0x81, ++0x94, 0x07, 0xD0, 0x9E, 0x40, 0x7A, 0x00, 0xED, 0x81, 0x84, 0x07, 0x10, 0x1E, ++0x40, 0x49, 0x00, 0x6D, 0x01, 0xB4, 0x27, 0xD0, 0x1E, 0x40, 0x13, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x20, 0x00, 0xDF, 0x00, 0x04, 0x03, ++0x30, 0x0C, 0xC0, 0x22, 0x02, 0x85, 0x08, 0x04, 0x23, 0xF0, 0x0D, 0x40, 0x30, ++0x04, 0xC7, 0x08, 0x04, 0x42, 0x30, 0x00, 0xC0, 0x30, 0x04, 0xCF, 0x00, 0x34, ++0x02, 0xF0, 0x8C, 0xC0, 0x30, 0x00, 0xCF, 0x80, 0x4C, 0x01, 0x70, 0x0C, 0xC0, ++0x13, 0x84, 0xCF, 0x00, 0x1C, 0x17, 0xF0, 0x0C, 0xC0, 0x4B, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x2D, 0x00, 0x7F, 0x00, 0xDD, 0x03, 0xD0, ++0x0F, 0xC0, 0x2F, 0x80, 0x7F, 0x00, 0xDE, 0xA3, 0x70, 0x0F, 0xC8, 0x3F, 0x00, ++0xF7, 0x00, 0xBC, 0x22, 0xF0, 0x0A, 0xC0, 0x3F, 0x00, 0xFF, 0x08, 0xFC, 0x22, ++0xF0, 0xAE, 0xC2, 0x3F, 0x20, 0xFF, 0x08, 0xDC, 0x21, 0xF0, 0x0F, 0xC4, 0x0F, ++0x10, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x2F, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0xA8, 0x37, 0x00, 0x9F, 0x00, 0x4C, 0x00, 0x31, 0x0D, ++0xC0, 0x3F, 0x00, 0x1F, 0x00, 0x7C, 0x07, 0x30, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x7C, 0x04, 0x30, 0x15, 0xC0, 0xB5, 0x04, 0xDF, 0x07, 0x6C, 0x03, 0xF0, ++0x5D, 0xC0, 0x36, 0x05, 0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC0, 0x53, 0x00, ++0xD1, 0x40, 0x78, 0x17, 0x34, 0x2D, 0xC0, 0x57, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x98, 0x39, 0x00, 0xED, 0x00, 0x84, 0x02, 0x10, 0x0E, 0x40, ++0x3B, 0x90, 0xAC, 0x00, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x3B, 0x10, 0xED, 0x20, ++0xB4, 0x00, 0x50, 0x0E, 0x40, 0x38, 0x01, 0xCD, 0x12, 0x84, 0x03, 0xD0, 0x0E, ++0x40, 0xB8, 0x00, 0xE7, 0x00, 0x9C, 0x03, 0xD0, 0x6E, 0x40, 0x0B, 0x00, 0xE1, ++0x00, 0xF4, 0x2B, 0x10, 0x0E, 0x40, 0x4B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x00, 0xE9, 0x00, 0x8D, 0x03, 0x24, 0x05, 0x94, 0x1E, 0x40, 0x7B, ++0x10, 0xEC, 0x03, 0xB4, 0x07, 0x90, 0x1E, 0x40, 0x7B, 0x20, 0xED, 0x01, 0xF6, ++0x07, 0x10, 0x14, 0x41, 0x79, 0x02, 0xED, 0x05, 0x84, 0x07, 0x50, 0xDC, 0x40, ++0x7A, 0x00, 0xED, 0x01, 0x96, 0x05, 0xD0, 0x1E, 0x40, 0x5B, 0x80, 0xE1, 0x41, ++0xB4, 0x17, 0x10, 0x9E, 0x40, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x20, 0x63, 0x00, 0xCD, 0x00, 0x05, 0x13, 0x90, 0x0C, 0x40, 0x33, 0x02, ++0xC9, 0x00, 0x34, 0x03, 0x90, 0x0C, 0x42, 0x33, 0x00, 0x4C, 0x08, 0x34, 0x0B, ++0x50, 0x3C, 0x40, 0x30, 0x00, 0xCC, 0x00, 0x04, 0x07, 0xD1, 0x0C, 0x40, 0x32, ++0x20, 0xC5, 0x00, 0x54, 0x0B, 0xD0, 0x0C, 0x44, 0x23, 0x00, 0xC1, 0x07, 0x34, ++0x03, 0x10, 0x0C, 0x40, 0x4B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, ++0xA8, 0x1D, 0x00, 0x7F, 0x0A, 0xEC, 0x1D, 0xB0, 0x05, 0x40, 0x57, 0x00, 0x7F, ++0x0A, 0x7C, 0x01, 0xB4, 0x05, 0xC0, 0x17, 0x10, 0x7D, 0x02, 0xFC, 0x21, 0x30, ++0x27, 0xC0, 0x15, 0x10, 0x5F, 0x00, 0x4C, 0x15, 0xF0, 0x05, 0xC0, 0x16, 0x80, ++0x5F, 0xC0, 0xDC, 0x01, 0xF1, 0x05, 0xC0, 0x1F, 0x02, 0x73, 0x02, 0x74, 0x01, ++0x30, 0x05, 0xC0, 0x5F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, ++0x07, 0x00, 0x0F, 0x02, 0x3C, 0x00, 0x70, 0x01, 0xC8, 0x07, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x10, 0x7C, 0x20, 0xF0, 0x41, ++0xC0, 0x03, 0x80, 0x1F, 0x00, 0x5D, 0x00, 0xF0, 0x01, 0xC0, 0x01, 0x80, 0x1F, ++0x02, 0x5C, 0x40, 0xF0, 0x01, 0xC0, 0x07, 0x40, 0x1F, 0x08, 0x7C, 0x00, 0xF0, ++0x01, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, ++0x00, 0x9F, 0x00, 0x4C, 0x22, 0x34, 0x09, 0xC0, 0x23, 0x00, 0x83, 0x00, 0x4C, ++0x02, 0xF0, 0x09, 0xC0, 0x67, 0x00, 0x9F, 0x00, 0x4C, 0xA2, 0xF0, 0x09, 0xC0, ++0x67, 0x00, 0x9B, 0x80, 0x7C, 0x02, 0xD2, 0x89, 0xC0, 0x27, 0x00, 0x93, 0x84, ++0x7C, 0x02, 0xB0, 0x08, 0xC0, 0x64, 0x00, 0x8F, 0x01, 0x6C, 0x02, 0xF0, 0x09, ++0xC0, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, ++0x9D, 0x03, 0x44, 0x06, 0x10, 0x09, 0x40, 0x27, 0x00, 0x95, 0x00, 0x6C, 0x22, ++0xD0, 0x09, 0x40, 0xA7, 0x00, 0x8D, 0x00, 0x6C, 0x06, 0xD0, 0x09, 0x40, 0x27, ++0x00, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, 0xC4, 0x27, 0x00, 0x91, 0x03, 0x74, ++0x02, 0x50, 0x09, 0xC0, 0x66, 0x02, 0x9D, 0x09, 0x6C, 0x02, 0xD0, 0x09, 0x40, ++0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, ++0x04, 0x44, 0x02, 0x19, 0x09, 0x40, 0x27, 0x00, 0x91, 0x00, 0x44, 0x02, 0x58, ++0x09, 0x40, 0x27, 0x05, 0x9D, 0x00, 0x66, 0x02, 0x52, 0x8D, 0x40, 0x27, 0x01, ++0x99, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x26, 0x00, 0x90, 0x02, 0x74, 0x02, ++0x10, 0x09, 0x40, 0x24, 0x00, 0x9D, 0xC0, 0x44, 0x82, 0xD0, 0x09, 0x40, 0x63, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0xA0, 0x00, 0x8D, 0x04, ++0x04, 0x12, 0x10, 0x08, 0x40, 0x33, 0x01, 0x85, 0x04, 0x24, 0x12, 0xD0, 0x08, ++0x40, 0x23, 0x00, 0x9D, 0x00, 0x04, 0x02, 0xD0, 0x48, 0x40, 0x23, 0x01, 0x81, ++0x04, 0x34, 0x12, 0xD0, 0x08, 0x48, 0x21, 0x01, 0x81, 0x00, 0x34, 0x22, 0x50, ++0x08, 0x4A, 0x22, 0x00, 0x8D, 0x04, 0x26, 0x12, 0xD0, 0x48, 0x48, 0x43, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x5F, 0x0A, 0x4C, ++0x00, 0x31, 0x01, 0x40, 0x87, 0x02, 0x13, 0x00, 0x0C, 0x28, 0x70, 0xA1, 0xC0, ++0x87, 0x02, 0x1F, 0x0A, 0x64, 0x00, 0x70, 0x01, 0xC4, 0x07, 0x00, 0x1B, 0x0A, ++0x74, 0x28, 0xF0, 0x41, 0x41, 0x87, 0x42, 0x13, 0x0A, 0x7C, 0x08, 0xB0, 0x41, ++0xC1, 0x04, 0x00, 0x1F, 0x00, 0x4C, 0x28, 0xF0, 0x01, 0xC0, 0x77, 0xC0, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x98, 0x6F, 0x00, 0xBF, 0x28, 0xF5, 0x22, ++0xF0, 0x09, 0xC0, 0x2F, 0x02, 0xBF, 0x28, 0xFC, 0x22, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0xBE, 0x40, 0xBD, 0x02, 0xF0, 0x8B, 0xC0, 0x27, 0x02, 0x9F, 0x08, 0xFC, ++0x22, 0xF0, 0x09, 0xC2, 0x27, 0x02, 0x9F, 0x00, 0xFC, 0x12, 0xF0, 0x09, 0xC0, ++0x2F, 0x00, 0xBF, 0x08, 0x7C, 0x22, 0xF0, 0x89, 0xC0, 0x67, 0x60, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0x27, 0x00, 0xBF, 0x14, 0xCC, 0x12, 0xF0, ++0x09, 0xC0, 0x2F, 0x00, 0x93, 0x00, 0xFC, 0x12, 0x70, 0x0B, 0xC0, 0x2F, 0x02, ++0x8F, 0x00, 0xBC, 0x02, 0x32, 0x0B, 0xC0, 0x2C, 0x01, 0x9F, 0x14, 0x4C, 0x32, ++0x30, 0x0B, 0xC0, 0x24, 0x00, 0xB3, 0x08, 0x4C, 0x02, 0xF2, 0x49, 0xC1, 0x2F, ++0x00, 0xBF, 0x00, 0x7C, 0x02, 0x20, 0x0B, 0xC0, 0x60, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1C, 0x08, 0x57, 0x05, 0x1D, 0x04, 0x44, 0x20, 0xD0, 0x01, ++0x48, 0x07, 0x04, 0x1B, 0x08, 0x74, 0x50, 0x10, 0x41, 0x40, 0x07, 0x81, 0x1D, ++0x50, 0x74, 0x00, 0x11, 0x81, 0xC0, 0x06, 0x00, 0x1D, 0x04, 0x45, 0x30, 0xB0, ++0x21, 0xC0, 0x06, 0x0C, 0x11, 0x00, 0x44, 0x50, 0xD0, 0x01, 0x40, 0x07, 0x00, ++0x1D, 0x02, 0x74, 0x40, 0x10, 0x01, 0xC0, 0x72, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, 0x14, 0x05, 0x02, 0xD0, 0x08, 0x40, ++0x23, 0x02, 0x81, 0x01, 0x14, 0x32, 0x51, 0x48, 0x41, 0x23, 0x01, 0x8D, 0x05, ++0x74, 0x03, 0x10, 0x08, 0x40, 0x30, 0x02, 0x89, 0x14, 0x04, 0x12, 0x10, 0x88, ++0x40, 0x20, 0x42, 0x81, 0x00, 0x24, 0x12, 0x90, 0x08, 0x40, 0x23, 0x80, 0x8D, ++0x09, 0x34, 0x02, 0x14, 0x08, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA8, 0x25, 0x02, 0x9D, 0x04, 0x44, 0x12, 0xD0, 0x09, 0x40, 0x27, ++0x02, 0x99, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, ++0x02, 0x10, 0x29, 0x40, 0x24, 0x00, 0x8D, 0x00, 0x44, 0x22, 0x94, 0x09, 0x40, ++0x26, 0x00, 0xD1, 0x00, 0x64, 0x02, 0xD0, 0x09, 0x40, 0xA7, 0x00, 0x9D, 0x08, ++0x74, 0x02, 0x11, 0x09, 0x40, 0x62, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0x08, 0x2D, 0x10, 0x9F, 0x01, 0x4C, 0x06, 0xF0, 0x09, 0x40, 0x27, 0x00, ++0x93, 0x01, 0x7C, 0x02, 0x70, 0x09, 0xC0, 0x27, 0x00, 0x9D, 0x00, 0x3C, 0x46, ++0x34, 0x09, 0x50, 0x24, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x30, 0x09, 0xC0, 0x24, ++0x00, 0x93, 0x00, 0x6D, 0x6E, 0xF0, 0x09, 0xC0, 0xA7, 0x00, 0x9F, 0x02, 0x78, ++0x02, 0x30, 0x09, 0xC0, 0x14, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x00, 0x65, 0x00, 0x9F, 0x01, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, ++0x83, 0x7E, 0x0E, 0xF0, 0x09, 0xC0, 0x27, 0x08, 0x9F, 0x49, 0x7C, 0x26, 0xF0, ++0x49, 0xC0, 0x27, 0x08, 0x9F, 0x20, 0x3C, 0x06, 0x71, 0x09, 0xC0, 0x23, 0x00, ++0x9F, 0x00, 0x5C, 0x82, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x01, 0x3C, 0x02, ++0xF0, 0x09, 0xC0, 0x53, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, ++0x85, 0x00, 0x0F, 0x01, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x01, 0x1F, 0x00, ++0x7E, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x20, 0x1B, 0x00, 0x4F, 0x00, 0xB0, 0x01, ++0xC0, 0x06, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x70, 0x00, 0xC0, 0x07, 0x00, 0x1F, ++0x00, 0x6C, 0x00, 0xF0, 0x01, 0xC0, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, ++0x01, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x14, ++0x00, 0x7D, 0x00, 0x74, 0x81, 0xD0, 0x05, 0xC0, 0x9D, 0x04, 0x5D, 0x00, 0x7E, ++0x01, 0xD0, 0x15, 0x40, 0x5F, 0x01, 0x51, 0x00, 0x44, 0x01, 0x14, 0x04, 0xD0, ++0x16, 0x00, 0x5D, 0x00, 0x74, 0x01, 0x10, 0x45, 0xC0, 0x14, 0x00, 0x7D, 0x10, ++0x44, 0x01, 0xD0, 0x05, 0x44, 0x17, 0x20, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x04, ++0x40, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, ++0xCD, 0x00, 0x34, 0x02, 0xDA, 0x0C, 0x48, 0x35, 0x20, 0xCD, 0x00, 0x74, 0x03, ++0xD0, 0x9C, 0x40, 0x33, 0x80, 0xC9, 0x20, 0x10, 0x02, 0x90, 0x8C, 0x40, 0x22, ++0x00, 0xCD, 0x00, 0x36, 0x03, 0x18, 0x08, 0x40, 0x31, 0x00, 0xDD, 0x01, 0x24, ++0x83, 0xD0, 0x0C, 0x40, 0x23, 0x82, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x08, 0x40, ++0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x81, 0xED, ++0x00, 0xB4, 0x43, 0xD9, 0x0E, 0x40, 0x39, 0x00, 0xED, 0x00, 0x94, 0x43, 0xD0, ++0x0E, 0x40, 0x6B, 0x01, 0xF1, 0x05, 0xD4, 0x03, 0x10, 0x0F, 0x50, 0x3A, 0x00, ++0xED, 0x08, 0x34, 0x03, 0x18, 0x0E, 0x40, 0x39, 0x08, 0xED, 0x00, 0xA4, 0x03, ++0xC0, 0x0E, 0x40, 0x3B, 0x80, 0xED, 0x00, 0xB4, 0x13, 0xD0, 0x0E, 0x40, 0x13, ++0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0xF8, 0x00, 0x2F, 0x01, ++0xBC, 0x07, 0xF0, 0x1E, 0xC0, 0x59, 0x00, 0xEF, 0x01, 0xB4, 0x06, 0xF0, 0x1E, ++0xE4, 0xFB, 0x00, 0xEB, 0x11, 0x94, 0x07, 0xB2, 0x1E, 0xD0, 0x7A, 0x00, 0xEF, ++0x15, 0xBC, 0x5F, 0x70, 0x1C, 0xC0, 0x79, 0x00, 0xFF, 0x01, 0xAC, 0x07, 0xE0, ++0x1E, 0xC0, 0x7B, 0x00, 0xEF, 0x01, 0xB4, 0x37, 0xF0, 0x1A, 0xC0, 0x53, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0xDF, 0x00, 0x7C, ++0x03, 0xF0, 0x0D, 0xC4, 0x15, 0x10, 0xDF, 0x00, 0x7C, 0x0A, 0xB0, 0x0D, 0xC0, ++0x03, 0x00, 0xDF, 0x08, 0x6C, 0x03, 0xF2, 0x0C, 0xD0, 0x37, 0x00, 0xDF, 0x20, ++0x7C, 0x03, 0xF4, 0x0D, 0xC0, 0x34, 0x07, 0x5F, 0x00, 0x5C, 0x03, 0xF0, 0x0D, ++0xC8, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x23, 0xF0, 0x0D, 0xC0, 0x43, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x7B, 0x00, 0xF3, 0x01, 0xCC, 0x07, ++0xFA, 0x8F, 0xC0, 0x6F, 0x02, 0xF3, 0x09, 0x8C, 0x0F, 0x30, 0x1F, 0xC0, 0x7F, ++0x00, 0xF3, 0x01, 0xEC, 0x07, 0x30, 0x1E, 0xC0, 0x7C, 0x30, 0xF7, 0x41, 0xCC, ++0x07, 0x70, 0x1F, 0xC4, 0x7C, 0x00, 0xF3, 0x01, 0xDC, 0x47, 0x72, 0x1F, 0xC8, ++0x7B, 0x22, 0xF7, 0xA1, 0xFC, 0x87, 0x32, 0x1B, 0xC2, 0x08, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x39, 0x00, 0x61, 0x40, 0x84, 0x03, 0x78, ++0x0E, 0x44, 0x2B, 0x10, 0xE1, 0x20, 0xAC, 0x03, 0x10, 0x0E, 0x40, 0x3B, 0x00, ++0xF1, 0x00, 0x84, 0x13, 0x50, 0x4E, 0x44, 0x39, 0x00, 0xF1, 0x00, 0xC4, 0x03, ++0x10, 0x0E, 0xC0, 0x3E, 0x02, 0xE1, 0x00, 0x86, 0x03, 0xF0, 0x0E, 0x40, 0x3B, ++0x40, 0xE5, 0x00, 0x34, 0x03, 0x10, 0x0E, 0x40, 0x54, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x25, 0x00, 0x84, 0x03, 0x50, 0x8E, ++0x40, 0x0B, 0x00, 0xC0, 0x20, 0x84, 0x02, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xE1, ++0x02, 0xC4, 0x03, 0x12, 0x0E, 0x60, 0x38, 0x00, 0xE5, 0x00, 0x84, 0x03, 0x10, ++0x0E, 0x40, 0x39, 0x00, 0xE1, 0x00, 0xD4, 0x03, 0x10, 0x0E, 0x40, 0x3F, 0x40, ++0xED, 0x00, 0x34, 0x03, 0x10, 0x08, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x06, 0x28, 0x33, 0x00, 0x41, 0x03, 0x05, 0x1B, 0x50, 0x0C, 0x40, ++0x43, 0x40, 0xC1, 0x02, 0x24, 0x02, 0x10, 0x0C, 0x40, 0x13, 0x00, 0xC1, 0x41, ++0x04, 0x03, 0x51, 0x0C, 0x60, 0x31, 0x00, 0xC1, 0x00, 0x05, 0x03, 0x10, 0x0C, ++0x40, 0x33, 0x00, 0x41, 0x00, 0x04, 0x0B, 0xD0, 0x0C, 0x40, 0x33, 0x02, 0x8D, ++0x42, 0x34, 0x03, 0x14, 0x0C, 0x50, 0x18, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0xA8, 0xB5, 0x42, 0xD7, 0x06, 0x0C, 0x03, 0x70, 0x0D, 0xC0, 0x27, ++0x04, 0xD3, 0x00, 0x4C, 0x02, 0x34, 0x0D, 0xC0, 0x3F, 0x40, 0xF1, 0x01, 0x0C, ++0x07, 0x30, 0xAC, 0x40, 0x30, 0x00, 0xF7, 0x00, 0xCC, 0x03, 0x30, 0x0D, 0xC0, ++0x3D, 0x00, 0xD3, 0x00, 0xDC, 0x23, 0x70, 0x0D, 0x40, 0xF7, 0x42, 0xDF, 0x02, ++0xFC, 0x03, 0x30, 0x09, 0xC0, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x37, 0x00, 0x9F, 0x10, 0x7C, 0x03, 0x70, 0x0D, 0xC0, 0xA7, 0x00, ++0xDF, 0x01, 0x5C, 0x02, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0xDF, 0x08, 0x5C, 0x63, ++0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x36, ++0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x7C, ++0x03, 0xF0, 0x09, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, ++0x08, 0x3F, 0x00, 0x33, 0x00, 0xFC, 0x03, 0x30, 0x0F, 0xC0, 0x07, 0x00, 0xF7, ++0x10, 0xFC, 0x02, 0x30, 0x5F, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0x30, ++0x9B, 0xC0, 0x34, 0x00, 0xE3, 0x00, 0xCC, 0x03, 0x30, 0x1D, 0xC0, 0x3F, 0x00, ++0xB3, 0x01, 0xFE, 0x03, 0xF0, 0x0F, 0xCA, 0xBF, 0x00, 0xFE, 0x10, 0xF4, 0x03, ++0x30, 0x5A, 0x80, 0x00, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, ++0x36, 0x00, 0x95, 0x00, 0x74, 0x07, 0x10, 0x0D, 0x40, 0xC7, 0x04, 0xD1, 0x00, ++0x74, 0x26, 0x10, 0x1D, 0x40, 0x07, 0x00, 0xD9, 0x00, 0x74, 0x03, 0x10, 0x1D, ++0x50, 0x35, 0x00, 0xDB, 0x00, 0x44, 0x03, 0x10, 0x0D, 0x40, 0x37, 0x00, 0x91, ++0x03, 0x76, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0x20, 0xDD, 0x09, 0x74, 0x03, 0x10, ++0x09, 0xC0, 0x05, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x32, ++0x00, 0xD1, 0x01, 0x74, 0x23, 0x10, 0x0D, 0x40, 0x63, 0x00, 0xD5, 0x00, 0x34, ++0x03, 0x10, 0x09, 0x40, 0x37, 0x02, 0xDD, 0x00, 0x76, 0x07, 0x10, 0x0D, 0x40, ++0x74, 0x20, 0xD1, 0x00, 0x04, 0x03, 0x10, 0x4D, 0x40, 0x33, 0x28, 0xD1, 0x04, ++0x74, 0x03, 0xD0, 0x0D, 0x40, 0x36, 0x00, 0xDD, 0x00, 0x24, 0x03, 0x00, 0x09, ++0x40, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, ++0x05, 0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x03, 0x00, 0xC1, 0x00, 0x34, 0x03, ++0x10, 0x08, 0x40, 0x33, 0x00, 0xC9, 0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x30, ++0x00, 0xC9, 0x00, 0x05, 0x03, 0x10, 0x0C, 0x40, 0x33, 0x00, 0xC1, 0x00, 0x34, ++0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCC, 0x00, 0x34, 0x23, 0x10, 0x08, 0x40, ++0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x3E, 0x00, 0x03, ++0x00, 0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x07, 0x00, 0xD7, 0x00, 0xFC, 0x02, 0x14, ++0x09, 0xC0, 0x23, 0x10, 0xFF, 0x00, 0x7C, 0x03, 0x34, 0x0D, 0xC0, 0x34, 0x00, ++0xF3, 0x00, 0xCC, 0x03, 0x30, 0x0D, 0xC0, 0x3F, 0x00, 0xC3, 0x20, 0x74, 0x03, ++0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0xFC, 0x03, 0x30, 0x09, 0xC0, 0x01, ++0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, 0x3F, 0x00, ++0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0B, ++0x80, 0x0F, 0x00, 0xFA, 0x00, 0xBC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, ++0x00, 0xFC, 0x03, 0xF0, 0x0F, 0x80, 0x3F, 0x08, 0xFF, 0x00, 0xB0, 0x03, 0xF0, ++0x0F, 0xC8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x13, 0xF0, 0x0B, 0xC0, 0x15, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xBF, 0x8C, 0xCC, ++0x12, 0x32, 0xCF, 0xC0, 0x5E, 0x22, 0xB3, 0x21, 0xFC, 0x06, 0xF0, 0xCF, 0xC4, ++0x3D, 0x03, 0x23, 0x01, 0xFC, 0x23, 0xF0, 0x13, 0xC0, 0x3F, 0x00, 0xFF, 0x4C, ++0xCC, 0x06, 0xB0, 0x17, 0xD8, 0x5C, 0x00, 0xF7, 0x04, 0xAC, 0x04, 0xB0, 0x4F, ++0xC1, 0x7A, 0x08, 0x3F, 0x01, 0xDC, 0x30, 0xB0, 0x1B, 0xC4, 0x0F, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x77, 0x00, 0xDD, 0x0E, 0x44, 0x26, ++0x10, 0xEF, 0x40, 0x24, 0x01, 0xD1, 0x04, 0x74, 0x05, 0x70, 0x2F, 0x40, 0xBC, ++0x02, 0x91, 0x01, 0xF4, 0x1B, 0x90, 0x40, 0x40, 0xFF, 0x02, 0xFD, 0x08, 0x44, ++0xC3, 0x10, 0x19, 0x40, 0x34, 0x00, 0xF1, 0x01, 0x44, 0x05, 0x10, 0x3F, 0x40, ++0x74, 0x10, 0x1D, 0xA1, 0x34, 0x38, 0xB0, 0x1C, 0x40, 0x07, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x00, 0x8D, 0x04, 0x04, 0x02, 0x10, ++0x4C, 0x40, 0x32, 0x00, 0xC1, 0x10, 0x14, 0x02, 0xD0, 0x6C, 0x48, 0x33, 0x11, ++0x45, 0x00, 0x34, 0x0B, 0xD0, 0x00, 0x41, 0x33, 0x10, 0xC5, 0x44, 0x04, 0x13, ++0x90, 0x08, 0x40, 0x00, 0x05, 0xC9, 0x08, 0x64, 0x01, 0xD0, 0x0C, 0x40, 0x30, ++0x20, 0x05, 0x00, 0x14, 0x00, 0xD0, 0x04, 0x40, 0x47, 0x80, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, 0xDD, 0x20, 0x44, 0x03, 0x10, 0x0D, ++0x40, 0xA4, 0x0A, 0xD1, 0x04, 0x74, 0x01, 0x50, 0x0D, 0x40, 0x34, 0x40, 0x95, ++0x02, 0x74, 0x03, 0xD1, 0x19, 0x42, 0x37, 0x00, 0xCD, 0x00, 0x44, 0x03, 0x90, ++0x08, 0x40, 0xB4, 0x01, 0xD9, 0x00, 0x64, 0x05, 0xD0, 0x0D, 0x50, 0x36, 0x04, ++0x1D, 0x18, 0x74, 0x01, 0xD0, 0x05, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA8, 0x37, 0x00, 0x9F, 0x09, 0x0C, 0x03, 0x34, 0x0D, 0xC0, ++0xD6, 0x08, 0x93, 0x01, 0x5C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x10, 0xD7, 0x09, ++0x7C, 0x03, 0xF0, 0x21, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x4C, 0x83, 0xB1, 0x25, ++0xC9, 0x34, 0x40, 0xDB, 0x00, 0x6C, 0x17, 0xF0, 0x0D, 0xC0, 0xA6, 0x00, 0x1F, ++0x02, 0x5C, 0x16, 0xF0, 0x39, 0xC0, 0x03, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0x80, 0x3D, 0x00, 0xEF, 0xC1, 0x7C, 0x02, 0xF2, 0x0E, 0xC0, 0x6F, ++0x00, 0xFF, 0x80, 0xFC, 0x8D, 0xF0, 0x0F, 0xC0, 0x3B, 0x00, 0xBB, 0x00, 0xFC, ++0x03, 0xB0, 0x0F, 0xC8, 0x3F, 0x00, 0xFF, 0x10, 0xDD, 0x83, 0x70, 0x0B, 0xC0, ++0x3F, 0x00, 0xF7, 0x00, 0xDC, 0x03, 0x30, 0x0F, 0xC0, 0x3D, 0x00, 0x3F, 0x01, ++0xFC, 0x0E, 0xB4, 0x2F, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x08, 0x35, 0x01, 0x93, 0x40, 0x7C, 0x03, 0x30, 0x8D, 0xC0, 0x35, 0x08, ++0xDF, 0x00, 0x4C, 0x0B, 0xF0, 0x0D, 0xC0, 0x34, 0x88, 0xDF, 0x00, 0x5C, 0x03, ++0x70, 0x25, 0xC0, 0x34, 0x08, 0xDF, 0x00, 0x7C, 0x03, 0x30, 0x2D, 0xE2, 0x27, ++0x00, 0xDF, 0x04, 0x7C, 0x09, 0xF0, 0x0D, 0xC1, 0x25, 0x00, 0x57, 0x00, 0x5C, ++0x02, 0x30, 0x05, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0xA0, 0x34, 0x00, 0xD1, 0x05, 0x74, 0x83, 0x18, 0x1F, 0x40, 0x24, 0x00, 0xDD, ++0x10, 0x44, 0x81, 0xD0, 0x0F, 0xC0, 0x3E, 0x88, 0x9F, 0x00, 0xC4, 0x03, 0x10, ++0x0D, 0x42, 0x3C, 0x00, 0xFD, 0x00, 0x74, 0x03, 0xB0, 0x09, 0x40, 0x77, 0x00, ++0xED, 0x00, 0x36, 0x05, 0x10, 0x6E, 0x40, 0xB4, 0x02, 0x1B, 0x11, 0x4C, 0x03, ++0x40, 0x05, 0xC0, 0x4E, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, ++0xB2, 0x02, 0x81, 0x00, 0x34, 0x82, 0x10, 0x1C, 0x40, 0x65, 0x02, 0xCD, 0x01, ++0x04, 0x81, 0xD0, 0x0D, 0x40, 0x30, 0x08, 0x0D, 0x00, 0x14, 0x03, 0x52, 0x00, ++0x42, 0x32, 0x20, 0xCD, 0x43, 0x74, 0x02, 0x10, 0x0C, 0x40, 0x67, 0x02, 0xCD, ++0x03, 0x24, 0x03, 0x58, 0x0C, 0x44, 0x31, 0x08, 0x05, 0x01, 0x54, 0x11, 0x10, ++0x04, 0x40, 0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x78, ++0x00, 0xA1, 0x01, 0xB4, 0x06, 0x10, 0x1C, 0x40, 0x68, 0x00, 0xED, 0x01, 0x84, ++0x05, 0xD0, 0x1E, 0x48, 0x7A, 0x00, 0x35, 0x01, 0x84, 0x27, 0x10, 0x96, 0x50, ++0x7A, 0x00, 0xED, 0x19, 0xB4, 0x03, 0x10, 0x1A, 0x40, 0x6B, 0x00, 0xED, 0x01, ++0xF4, 0x05, 0x19, 0x1C, 0x40, 0x7C, 0x00, 0x39, 0x81, 0xA4, 0x24, 0x10, 0x1E, ++0x40, 0x1A, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, ++0xC3, 0x04, 0x34, 0x02, 0x10, 0x0C, 0xC0, 0x31, 0x00, 0xDF, 0x00, 0x0D, 0x01, ++0xF8, 0x0D, 0xC0, 0x30, 0x02, 0x4D, 0x00, 0x5C, 0x07, 0x70, 0x2C, 0xC0, 0x32, ++0x02, 0xCF, 0x00, 0x7C, 0x23, 0x10, 0x08, 0x40, 0x23, 0x00, 0xCF, 0x14, 0x34, ++0x43, 0x70, 0x0C, 0xC0, 0x31, 0x00, 0xC7, 0x00, 0x1E, 0x03, 0x34, 0x04, 0xC2, ++0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x39, 0x42, 0xFF, ++0x00, 0xFC, 0x03, 0xF0, 0x2F, 0xC1, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x01, 0xF0, ++0x0F, 0x81, 0x3F, 0x00, 0xFF, 0x00, 0x7C, 0x2B, 0xB0, 0x0F, 0xC0, 0x3D, 0x04, ++0xFF, 0x10, 0xF4, 0x13, 0xF0, 0x09, 0xC0, 0x2F, 0x00, 0xFF, 0x10, 0x7C, 0x21, ++0x70, 0x0F, 0xC0, 0x1F, 0x10, 0xEF, 0x00, 0xDC, 0x03, 0xF0, 0x07, 0xC0, 0x0B, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x00, 0x9F, 0x00, ++0x4C, 0x03, 0xF0, 0x6D, 0xC0, 0x27, 0x10, 0xDF, 0x00, 0x7C, 0x03, 0xB0, 0x0D, ++0xC0, 0x37, 0x05, 0x57, 0x00, 0x5C, 0x37, 0x34, 0x08, 0xC0, 0x36, 0x01, 0xDF, ++0x12, 0x4D, 0x03, 0x70, 0x0D, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF2, ++0x4C, 0xC1, 0x66, 0x00, 0x9B, 0x01, 0x4C, 0x01, 0xB0, 0x05, 0xC0, 0x57, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x39, 0x00, 0xBD, 0x04, 0x85, ++0x0A, 0xD0, 0x0E, 0x40, 0x2B, 0x00, 0xED, 0x00, 0xB4, 0x01, 0x10, 0x8E, 0x40, ++0x3B, 0x01, 0x6D, 0x00, 0x9C, 0x13, 0x10, 0x0E, 0x40, 0x38, 0x03, 0xE7, 0x04, ++0x84, 0x03, 0xD0, 0x0A, 0x40, 0x2B, 0x08, 0xED, 0x14, 0xB4, 0x03, 0x70, 0x4E, ++0xC2, 0x3A, 0x40, 0x23, 0x00, 0x85, 0x00, 0xB0, 0x0E, 0x40, 0x4B, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x00, 0xED, 0x09, 0xA4, 0x17, ++0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x07, 0x90, 0x5E, 0x40, 0x7B, ++0x02, 0xED, 0x31, 0x16, 0x07, 0x10, 0x1F, 0x42, 0x7A, 0x00, 0xE5, 0x01, 0x84, ++0x07, 0xD0, 0x1E, 0x40, 0x6B, 0x00, 0xED, 0x05, 0xB4, 0x07, 0x50, 0xDE, 0x40, ++0x69, 0x00, 0xE9, 0x81, 0x84, 0x87, 0x90, 0x16, 0x40, 0x0F, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x04, 0x03, 0xD0, ++0x0C, 0x40, 0x23, 0x20, 0xDD, 0x40, 0x34, 0x45, 0x10, 0x0C, 0x40, 0x37, 0x08, ++0xCD, 0x06, 0x14, 0x03, 0x10, 0xBC, 0x40, 0x30, 0x00, 0xD5, 0x20, 0x04, 0x07, ++0xD0, 0x18, 0x40, 0x23, 0x00, 0xCD, 0x00, 0x34, 0x01, 0x50, 0x0C, 0x40, 0x53, ++0x30, 0xC1, 0x08, 0x04, 0x0B, 0x90, 0x04, 0x40, 0x4B, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x17, 0x88, 0x15, 0x00, 0x5F, 0x00, 0x6C, 0x41, 0xF0, 0x05, ++0xC0, 0x1F, 0x00, 0x5F, 0x00, 0xBC, 0x4D, 0xB0, 0x05, 0xC0, 0x17, 0x00, 0x6F, ++0x01, 0x5C, 0x01, 0x30, 0x37, 0xC0, 0x16, 0x00, 0x57, 0x80, 0x4C, 0x91, 0xF0, ++0x47, 0xC0, 0x9F, 0x00, 0x5F, 0x00, 0xBC, 0x15, 0x70, 0x04, 0xC0, 0x5D, 0x0C, ++0x7B, 0x03, 0xCC, 0x09, 0xA0, 0x07, 0xC0, 0x5F, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x00, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x40, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0xF0, 0x01, 0xC1, 0x07, 0x00, 0x17, 0x00, 0x7C, 0x00, 0xF0, 0x01, ++0xC0, 0x07, 0x00, 0x0F, 0x02, 0x7C, 0x40, 0x70, 0x21, 0x80, 0x86, 0x00, 0x17, ++0x12, 0x3C, 0x10, 0xF0, 0x01, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x27, 0x08, 0x8F, 0x40, 0x4D, 0x16, 0xF0, 0x99, 0xC0, 0xE7, ++0x00, 0x93, 0x09, 0x4D, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x97, 0x00, 0x5C, ++0x02, 0xF0, 0x29, 0xC0, 0x23, 0x00, 0x97, 0x00, 0x5C, 0x02, 0x34, 0x09, 0xC0, ++0x64, 0x06, 0x93, 0x03, 0x5C, 0xA2, 0x71, 0x99, 0xC0, 0x24, 0x00, 0x9F, 0x01, ++0x7C, 0x06, 0x30, 0x09, 0xC0, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x20, 0xA6, 0x00, 0xBD, 0x40, 0xC4, 0x06, 0x70, 0x09, 0x40, 0x63, 0x00, ++0x91, 0x01, 0x44, 0x02, 0x18, 0x09, 0x44, 0x27, 0x00, 0x99, 0x00, 0x44, 0x02, ++0xD0, 0x28, 0x40, 0x24, 0x08, 0x93, 0x20, 0x04, 0x02, 0x90, 0x08, 0x40, 0x60, ++0x00, 0x91, 0x04, 0x44, 0x4E, 0x10, 0x09, 0x50, 0x25, 0x10, 0x9D, 0x06, 0x74, ++0x06, 0x50, 0x09, 0x42, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA0, 0x24, 0x10, 0x9D, 0x00, 0x44, 0x0A, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x91, ++0x80, 0x44, 0x03, 0x10, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x54, 0x02, 0xD0, ++0x29, 0x40, 0x25, 0x00, 0x95, 0x00, 0x54, 0x02, 0x90, 0x09, 0x40, 0x24, 0x00, ++0x91, 0x00, 0x54, 0x02, 0x50, 0x29, 0x40, 0x24, 0x30, 0x9D, 0x08, 0x74, 0x52, ++0x10, 0x0D, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, ++0x30, 0x00, 0x8D, 0x02, 0x04, 0x02, 0x58, 0x68, 0x40, 0xA7, 0x00, 0x81, 0x02, ++0x44, 0x0A, 0x10, 0x88, 0x40, 0x23, 0x02, 0x99, 0x00, 0x04, 0x22, 0xD0, 0x89, ++0x40, 0x20, 0x00, 0x89, 0x08, 0x44, 0x22, 0x90, 0x29, 0x40, 0xA4, 0x00, 0x81, ++0x00, 0x04, 0x02, 0x12, 0x08, 0x40, 0x21, 0x00, 0x8D, 0x00, 0x34, 0x22, 0x54, ++0x28, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x30, 0x06, ++0x00, 0x1F, 0x01, 0x4C, 0x04, 0xF0, 0x01, 0xC0, 0x07, 0x40, 0x13, 0x00, 0x0C, ++0x00, 0x14, 0x61, 0xC1, 0x87, 0x0D, 0x17, 0x00, 0x5C, 0x58, 0xF1, 0x21, 0xC0, ++0x05, 0x05, 0x07, 0x16, 0x5C, 0x88, 0x30, 0x01, 0xD0, 0x04, 0x40, 0x13, 0x54, ++0x5C, 0x80, 0x78, 0x41, 0xC1, 0x14, 0x10, 0x1F, 0x00, 0x3C, 0x58, 0x30, 0x01, ++0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x38, 0x27, 0x08, ++0xBF, 0x03, 0xFC, 0x0A, 0xF0, 0x99, 0xC0, 0x6F, 0x08, 0xBF, 0x01, 0xFC, 0x06, ++0xF0, 0x49, 0xC0, 0x27, 0x09, 0xB7, 0x00, 0x7C, 0x12, 0xF0, 0x4B, 0xC2, 0x25, ++0x00, 0x97, 0x04, 0xFC, 0x12, 0x70, 0x1B, 0xC0, 0x6F, 0x30, 0x9F, 0x00, 0xFC, ++0x02, 0xF8, 0x09, 0xD2, 0x2B, 0x80, 0xAF, 0x00, 0xFC, 0x12, 0xF0, 0x1B, 0xC0, ++0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2B, 0x00, 0xBF, ++0x13, 0xFC, 0x46, 0xF0, 0x0B, 0xC0, 0xAC, 0x00, 0xBF, 0x00, 0x7C, 0x0A, 0x30, ++0xC9, 0xC0, 0x26, 0x00, 0x9B, 0x00, 0x7C, 0x22, 0xF0, 0x0B, 0xC0, 0x24, 0x05, ++0xBF, 0x0C, 0x49, 0x02, 0xF2, 0x29, 0xC2, 0xAF, 0x00, 0xAF, 0x04, 0xFC, 0x02, ++0xF0, 0x4B, 0xC0, 0x2C, 0x00, 0xBF, 0x00, 0xFC, 0x22, 0xB0, 0x09, 0xC0, 0x67, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, 0x1D, 0x07, ++0x74, 0x88, 0xD0, 0x51, 0x40, 0x44, 0x20, 0x1D, 0x05, 0x74, 0x04, 0x10, 0xC1, ++0x48, 0x84, 0x04, 0x11, 0x00, 0x74, 0x20, 0xD0, 0x45, 0x53, 0x04, 0x00, 0x1D, ++0x0C, 0x44, 0x40, 0xD0, 0x14, 0x40, 0x47, 0x00, 0x1D, 0x00, 0x74, 0x00, 0x10, ++0x81, 0x40, 0x14, 0x20, 0x5D, 0x20, 0x74, 0x20, 0x14, 0x11, 0x40, 0x73, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, 0x04, 0x34, ++0x02, 0xD0, 0x88, 0x41, 0x20, 0x00, 0x8D, 0x10, 0x34, 0x02, 0x10, 0x48, 0x40, ++0x22, 0x03, 0x89, 0x00, 0x34, 0x02, 0xD1, 0x48, 0x40, 0x20, 0x00, 0x8D, 0x04, ++0x26, 0x12, 0xD0, 0x08, 0x40, 0x23, 0x10, 0x8D, 0x08, 0x34, 0x02, 0xDC, 0x08, ++0x40, 0x20, 0x10, 0x8D, 0x00, 0x34, 0x02, 0x94, 0x48, 0x41, 0x43, 0x80, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x9D, 0x20, 0x74, 0x82, ++0xD0, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x04, 0x34, 0x02, 0x10, 0x09, 0x40, 0x20, ++0x00, 0x91, 0x10, 0x74, 0x02, 0xD0, 0x88, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x66, ++0x82, 0xD0, 0x89, 0x66, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x51, 0x09, 0x58, ++0x24, 0x00, 0x9D, 0x01, 0x74, 0x2A, 0x10, 0x69, 0x40, 0x63, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x28, 0x25, 0x00, 0xBF, 0x01, 0x7C, 0x06, 0xF0, ++0x0B, 0xD0, 0x2C, 0x03, 0xBF, 0x00, 0xFC, 0x02, 0x10, 0x09, 0xC0, 0x26, 0x00, ++0x9B, 0x00, 0x7C, 0x02, 0xF0, 0x39, 0xC0, 0x24, 0x00, 0x9D, 0x80, 0x64, 0x22, ++0xF0, 0x3B, 0xC0, 0x2F, 0x08, 0x9D, 0x00, 0x34, 0x4A, 0xF0, 0x09, 0x40, 0xA4, ++0x00, 0x9F, 0x03, 0x70, 0x06, 0xB0, 0x3B, 0xC4, 0x17, 0xA0, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x00, 0x25, 0x00, 0x9F, 0x04, 0x7C, 0x12, 0xF0, 0x09, ++0xC4, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF4, 0x08, 0xC0, 0x27, 0x10, 0x9F, ++0x04, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x40, 0x5C, 0x06, 0xF8, ++0x19, 0xC2, 0x27, 0x01, 0x9F, 0x00, 0x7C, 0x22, 0xB0, 0x09, 0x05, 0x27, 0x80, ++0x9E, 0x10, 0x6C, 0x06, 0xF0, 0x19, 0xC0, 0x53, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x13, 0x40, 0x7C, 0x00, 0xB4, 0x81, 0xC0, ++0x07, 0x00, 0x1F, 0x08, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x05, 0x00, 0x13, 0x02, ++0x7C, 0x00, 0xF0, 0xA1, 0xD0, 0x04, 0x00, 0x03, 0x00, 0x7C, 0x00, 0xF2, 0x21, ++0xC0, 0x04, 0x20, 0x13, 0x10, 0x5C, 0x98, 0xF0, 0x01, 0xD0, 0x84, 0x00, 0x1F, ++0x42, 0x2C, 0x00, 0x34, 0x21, 0xD0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0xA0, 0x1C, 0x01, 0x51, 0x01, 0xF4, 0x1D, 0x10, 0x15, 0x40, 0x17, ++0x00, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x40, 0x14, 0x00, 0x51, 0x00, 0x74, ++0x01, 0xD0, 0x97, 0xC0, 0x14, 0x00, 0x71, 0x03, 0x44, 0x01, 0x70, 0x05, 0x40, ++0x14, 0x00, 0x71, 0x01, 0xC4, 0x05, 0xD0, 0x16, 0x42, 0x1C, 0x00, 0x7D, 0x00, ++0xF4, 0x01, 0x14, 0x05, 0x40, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0xA0, 0x62, 0x00, 0xC1, 0x00, 0x34, 0x1E, 0x10, 0x0D, 0x48, 0x33, 0x00, ++0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x31, 0xC0, 0xC1, 0x00, 0x34, 0x03, ++0xD0, 0x2C, 0x40, 0x32, 0x40, 0xC1, 0x11, 0x14, 0x03, 0x50, 0x0C, 0x40, 0x32, ++0x02, 0x81, 0x00, 0x14, 0x05, 0x90, 0x18, 0x40, 0x60, 0x01, 0xC9, 0x02, 0x24, ++0x03, 0x14, 0x0C, 0x60, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x80, 0x68, 0x00, 0xA1, 0x06, 0xB4, 0x06, 0x10, 0x8E, 0x40, 0x3B, 0x01, 0xAD, ++0x04, 0xB4, 0x13, 0xD0, 0x8E, 0x40, 0x38, 0x81, 0xE1, 0x00, 0xB4, 0x13, 0xD0, ++0x0E, 0x40, 0x78, 0x00, 0xC1, 0x10, 0x84, 0x13, 0x50, 0x5E, 0x40, 0x7A, 0x11, ++0xA1, 0x11, 0x86, 0x09, 0xD0, 0x2C, 0x42, 0xA8, 0x00, 0xED, 0x00, 0x34, 0x0B, ++0x10, 0x5F, 0x60, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, ++0x68, 0x00, 0xE3, 0x07, 0xBC, 0x06, 0x30, 0x5A, 0xC0, 0xEB, 0x00, 0xEF, 0x03, ++0xB4, 0x0F, 0xF0, 0x1C, 0xC0, 0xF1, 0x00, 0xE1, 0x01, 0xBC, 0x17, 0xF0, 0x17, ++0xC4, 0x72, 0x00, 0xE3, 0x01, 0x9C, 0x17, 0x70, 0x3E, 0xC8, 0xFE, 0x40, 0xE3, ++0x01, 0x9C, 0x05, 0xB0, 0x1A, 0xC0, 0x68, 0x08, 0xED, 0x01, 0xAC, 0x05, 0x30, ++0x3E, 0xC0, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x25, ++0x50, 0x9F, 0x00, 0x3C, 0x02, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x80, 0x7C, ++0x03, 0xF0, 0x0D, 0xC2, 0xB7, 0x0D, 0xDF, 0x00, 0x7C, 0x4B, 0xF0, 0x05, 0xC0, ++0x37, 0x00, 0xDF, 0x00, 0x5C, 0x23, 0x72, 0x0D, 0xD0, 0x25, 0x00, 0xDF, 0x00, ++0x7E, 0x01, 0xF0, 0x09, 0xC4, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF4, 0x0C, ++0xC0, 0x43, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x6F, 0x00, ++0xFF, 0x09, 0xCC, 0x13, 0x30, 0x1F, 0xC0, 0x7B, 0x00, 0xF3, 0x01, 0xCC, 0x27, ++0x30, 0x5F, 0x80, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x47, 0x30, 0x1B, 0xC0, 0x7C, ++0x00, 0xBF, 0x01, 0xCC, 0x07, 0xF0, 0x1E, 0xC0, 0x68, 0x0A, 0xB1, 0x0C, 0xFC, ++0x25, 0xF0, 0x1F, 0xC0, 0x78, 0x42, 0xF3, 0x01, 0xFC, 0x06, 0xF0, 0x1F, 0xC4, ++0x08, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x80, 0x29, 0x00, 0xBD, ++0x18, 0x84, 0x43, 0x11, 0x0A, 0x48, 0x3B, 0x00, 0xA1, 0x10, 0x84, 0x23, 0x10, ++0x0E, 0x48, 0x3B, 0x00, 0xED, 0x00, 0x34, 0x03, 0x10, 0x8B, 0x41, 0x38, 0x00, ++0x7D, 0x00, 0x94, 0x03, 0xD0, 0x4E, 0x40, 0x38, 0x03, 0xA1, 0x04, 0xB4, 0x09, ++0xD0, 0x8E, 0x40, 0x19, 0x02, 0xE1, 0x00, 0xB4, 0x0A, 0xF0, 0x8E, 0x40, 0x54, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0xED, 0x40, ++0xA7, 0x22, 0x14, 0x0A, 0x40, 0x2F, 0x06, 0xB1, 0x08, 0xC4, 0x07, 0x12, 0x4E, ++0x60, 0x3B, 0x00, 0xED, 0x02, 0xB4, 0x03, 0x90, 0x02, 0x50, 0x38, 0x02, 0xAD, ++0x00, 0xA4, 0x03, 0xD0, 0x1F, 0x49, 0x2C, 0x04, 0xE9, 0x88, 0xB4, 0x01, 0xD0, ++0x0A, 0x40, 0x38, 0x80, 0x61, 0x10, 0xB4, 0x01, 0xD0, 0x1F, 0x40, 0x60, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x23, 0x00, 0x8D, 0x00, 0x24, ++0x06, 0x10, 0x09, 0x40, 0x77, 0x00, 0x81, 0x00, 0x04, 0x23, 0x10, 0x0C, 0x60, ++0x33, 0x00, 0xCD, 0x08, 0x34, 0x03, 0x91, 0x00, 0x41, 0x30, 0x00, 0x4D, 0x00, ++0x06, 0x03, 0xD2, 0x3C, 0x40, 0x60, 0x20, 0xC9, 0x00, 0x34, 0x09, 0xD0, 0x08, ++0x40, 0x31, 0x02, 0x01, 0x03, 0x30, 0x07, 0x50, 0x0C, 0x60, 0x18, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, 0xDF, 0x01, 0x6C, 0x02, ++0x30, 0x0D, 0x40, 0xB7, 0x42, 0xD3, 0x21, 0x4D, 0x03, 0x14, 0x0F, 0xC2, 0x3F, ++0x00, 0xDF, 0x00, 0xF4, 0x03, 0x90, 0x1D, 0xC0, 0x34, 0x00, 0x5F, 0x00, 0xCD, ++0x17, 0xF0, 0x3D, 0xD0, 0xF4, 0x40, 0x9A, 0x00, 0x7C, 0x09, 0xF1, 0x0D, 0xC2, ++0xF0, 0x00, 0xD1, 0x23, 0x74, 0x07, 0xD0, 0x2D, 0x50, 0x74, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xB7, 0x00, 0xDF, 0x00, 0x5C, 0x02, 0xF0, ++0x0D, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x43, 0xF0, 0x0D, 0xC0, 0x37, 0x00, ++0xDF, 0x00, 0x3C, 0x03, 0x72, 0x2D, 0xC0, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x03, ++0xF0, 0x0D, 0xC0, 0x37, 0x01, 0x97, 0x22, 0x7C, 0x0D, 0xE0, 0x0D, 0xC0, 0xB7, ++0x04, 0xDF, 0x20, 0x7C, 0x21, 0xF0, 0xCD, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x08, 0x7F, 0x02, 0xFF, 0x00, 0x7C, 0x22, 0xF0, 0x0B, ++0xD0, 0x2C, 0x00, 0xF3, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3E, 0x00, 0xFF, ++0x00, 0xDC, 0x03, 0x30, 0x9B, 0xC0, 0x3F, 0x00, 0x7F, 0x01, 0xEE, 0x03, 0xF0, ++0x0F, 0xC1, 0x3F, 0x00, 0xEF, 0x05, 0xCC, 0x41, 0xF0, 0x0B, 0xC0, 0x3D, 0x00, ++0xFB, 0x10, 0x8C, 0x10, 0x30, 0x0F, 0xC0, 0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x81, 0x20, 0xD6, 0x00, 0xDD, 0x09, 0x74, 0x0A, 0xD0, 0x0D, 0x40, ++0x64, 0x22, 0xD1, 0x20, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xDD, 0x00, ++0x74, 0x03, 0x10, 0x09, 0x40, 0x37, 0x00, 0x9D, 0x02, 0x7E, 0x03, 0xD0, 0x0D, ++0x40, 0x27, 0x00, 0xDD, 0x07, 0x44, 0x05, 0xD0, 0x38, 0xC8, 0x76, 0x01, 0x89, ++0x00, 0x54, 0x0C, 0x50, 0x0D, 0x42, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0xA0, 0x24, 0x04, 0x9D, 0x00, 0x74, 0x0B, 0xD2, 0x0D, 0x42, 0x34, ++0x40, 0xD1, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xDD, 0x00, 0x74, ++0x03, 0x10, 0x05, 0x41, 0x37, 0x80, 0x1D, 0x66, 0x74, 0x03, 0xD0, 0x0D, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x64, 0x07, 0xD2, 0x35, 0x40, 0x75, 0x00, 0xD1, 0x00, ++0x44, 0x02, 0x11, 0x0D, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x08, 0x30, 0x00, 0x8D, 0x20, 0x36, 0x03, 0xD0, 0x08, 0x40, 0x20, 0x00, ++0x81, 0x00, 0x34, 0x03, 0xD2, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, ++0x18, 0x04, 0x40, 0x33, 0xA0, 0x0D, 0x00, 0x14, 0x03, 0xD2, 0x0C, 0x48, 0x33, ++0x00, 0xCD, 0x00, 0x24, 0x03, 0xD0, 0x0C, 0x5A, 0x36, 0x00, 0xD1, 0x00, 0x14, ++0x00, 0x50, 0x0C, 0x40, 0x42, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x20, 0x26, 0x00, 0x9F, 0x20, 0x7C, 0x01, 0xF0, 0x09, 0xE8, 0x24, 0x00, 0x93, ++0x40, 0xFC, 0x03, 0xF0, 0x0D, 0x40, 0x3F, 0x00, 0xDF, 0x00, 0xBC, 0x23, 0x34, ++0x01, 0xC0, 0x37, 0x00, 0x1F, 0x00, 0x64, 0x03, 0xF0, 0x0F, 0xC0, 0x27, 0x00, ++0xDF, 0x00, 0x6C, 0x01, 0xF0, 0x09, 0xC0, 0x35, 0x80, 0x5B, 0x80, 0x4E, 0x00, ++0x32, 0x0F, 0xC8, 0x07, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, ++0x1F, 0x00, 0xBF, 0x00, 0xFC, 0x01, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0xAF, 0x20, ++0xBC, 0x03, 0xF0, 0x0F, 0xC8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x03, ++0xC0, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC2, 0x2F, 0x00, 0x3F, ++0x00, 0xDC, 0x00, 0xF0, 0x0A, 0xC0, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x80, 0xF8, ++0x0E, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xB0, 0x7F, ++0x00, 0x3F, 0x00, 0xEC, 0x07, 0x70, 0x03, 0xC0, 0x7D, 0x02, 0xF3, 0x09, 0xFC, ++0x10, 0xF0, 0x0B, 0xC0, 0x3C, 0x01, 0xBF, 0x21, 0xFC, 0x03, 0xF0, 0x0F, 0xC1, ++0x3F, 0x00, 0x3F, 0x18, 0xCD, 0x03, 0x30, 0x1F, 0xC0, 0x0F, 0x00, 0xFB, 0x00, ++0xFC, 0x03, 0xE0, 0x0F, 0xC0, 0x4C, 0x00, 0xF3, 0x00, 0xCC, 0x03, 0x30, 0x0F, ++0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x77, 0x00, ++0x5D, 0x01, 0x44, 0x07, 0x10, 0xB1, 0x40, 0x33, 0x00, 0xC1, 0x04, 0x74, 0x06, ++0xD0, 0x29, 0x41, 0x3D, 0x00, 0xDD, 0x01, 0xF4, 0x07, 0xD0, 0x0E, 0x40, 0x77, ++0x00, 0x1D, 0x82, 0x44, 0x07, 0x10, 0x2F, 0x40, 0x67, 0x00, 0x51, 0x01, 0x74, ++0x07, 0xD0, 0x15, 0x40, 0x44, 0x00, 0x5B, 0x01, 0x44, 0x05, 0x10, 0x1D, 0x40, ++0x04, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x00, 0x0D, ++0x08, 0x04, 0x03, 0x50, 0x14, 0x68, 0x31, 0x01, 0xC1, 0x00, 0x34, 0x20, 0xD0, ++0x6C, 0x40, 0xB1, 0x04, 0xCD, 0x01, 0x34, 0x23, 0xD0, 0x4C, 0x41, 0x31, 0x02, ++0x0D, 0x05, 0x24, 0x03, 0x10, 0x2C, 0x40, 0x23, 0x00, 0x85, 0x00, 0x34, 0x02, ++0x50, 0x08, 0x40, 0x01, 0x00, 0x85, 0x20, 0x04, 0x03, 0x10, 0x0C, 0x40, 0x44, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x35, 0x80, 0x5D, 0x14, ++0x65, 0x03, 0x10, 0x01, 0x40, 0x37, 0x00, 0xD1, 0x00, 0x74, 0x00, 0xD0, 0x0D, ++0x40, 0x35, 0x20, 0xDD, 0x01, 0x74, 0x03, 0xD1, 0x0D, 0x40, 0x37, 0x00, 0x1D, ++0x00, 0x64, 0x43, 0x10, 0x0D, 0x44, 0x67, 0x00, 0xD5, 0x06, 0x74, 0x03, 0xD1, ++0x0D, 0x51, 0x45, 0x40, 0xDD, 0x00, 0x44, 0x03, 0x10, 0x8D, 0x40, 0x0C, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x37, 0x00, 0x9F, 0x01, 0x6C, ++0x07, 0x70, 0x01, 0xC0, 0x75, 0x40, 0xD3, 0x00, 0x7C, 0x11, 0xF0, 0x0D, 0xC0, ++0x35, 0x00, 0xDF, 0x01, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0x5F, 0x00, ++0x6C, 0x03, 0x30, 0x0D, 0xC0, 0xE7, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x3D, ++0xC0, 0xC1, 0x84, 0xD7, 0x00, 0x4C, 0x07, 0x30, 0x0D, 0xC0, 0x08, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0x6F, 0x00, 0xDC, 0x0B, ++0xF0, 0x0F, 0xC0, 0x7F, 0x02, 0xFF, 0x00, 0xFC, 0x0F, 0xF0, 0x0D, 0xE0, 0x3F, ++0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC6, 0x3F, 0x80, 0x9F, 0x28, 0xDC, ++0x27, 0xF0, 0x0F, 0xC0, 0x2F, 0x40, 0x7B, 0x00, 0xFC, 0x03, 0xF0, 0x96, 0xC0, ++0x0E, 0x00, 0xE3, 0x00, 0xBC, 0x09, 0xF0, 0x1E, 0xC0, 0x1F, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0x9F, 0x02, 0x4C, 0x03, 0xF0, ++0x05, 0xC0, 0x34, 0x00, 0xD3, 0x00, 0x5C, 0x05, 0x70, 0x0D, 0xC8, 0x35, 0x08, ++0xD3, 0x80, 0x7C, 0x07, 0xF1, 0x0D, 0xC2, 0x34, 0x00, 0x5F, 0x00, 0x0C, 0x23, ++0x30, 0x0D, 0xC0, 0xA3, 0x00, 0x97, 0x00, 0x7C, 0x03, 0xB0, 0x29, 0xC0, 0x04, ++0x00, 0xDF, 0x00, 0x4C, 0x03, 0x30, 0x2D, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, 0x00, 0x5C, 0x00, 0x34, 0x3F, 0xD0, 0x0D, ++0xC0, 0x74, 0x01, 0xD1, 0x00, 0x44, 0x01, 0xD0, 0x9C, 0x48, 0x7C, 0x01, 0xD1, ++0x00, 0xF4, 0x03, 0xD0, 0x0F, 0x40, 0x3C, 0x01, 0x9D, 0x00, 0x6E, 0x03, 0xB0, ++0x4F, 0x40, 0x27, 0x08, 0xD1, 0x00, 0x74, 0x03, 0x10, 0x4D, 0xC0, 0x04, 0x00, ++0xDD, 0x00, 0x44, 0x93, 0x10, 0x0D, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x20, 0x32, 0x00, 0x0D, 0x00, 0x34, 0x0F, 0x90, 0x08, 0x40, ++0x34, 0x00, 0xC1, 0x00, 0x04, 0x00, 0x50, 0x08, 0x00, 0x31, 0x00, 0xC1, 0x00, ++0x34, 0x03, 0xD8, 0x0C, 0x40, 0x70, 0x00, 0x9D, 0x40, 0x04, 0x04, 0x90, 0x2C, ++0x41, 0x23, 0x00, 0xC5, 0x00, 0x36, 0x03, 0x10, 0x0C, 0x40, 0x42, 0x02, 0xCD, ++0x00, 0x24, 0x02, 0x10, 0x00, 0x40, 0x0C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x00, 0x7A, 0x08, 0xAD, 0x21, 0xB4, 0x07, 0xD2, 0x10, 0x40, 0xF8, ++0x02, 0xE1, 0x0B, 0x94, 0x26, 0xD0, 0x1A, 0x41, 0xF8, 0x00, 0xE0, 0x01, 0xB4, ++0x07, 0xD8, 0x3E, 0x40, 0x78, 0x00, 0x6D, 0x01, 0x84, 0x06, 0x90, 0x1E, 0x40, ++0x63, 0x80, 0xE1, 0x01, 0x34, 0x27, 0x10, 0x1C, 0x40, 0x48, 0x00, 0x4D, 0x01, ++0x24, 0x07, 0x10, 0x14, 0x42, 0x10, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x00, 0x32, 0x00, 0x0F, 0x00, 0x3C, 0x23, 0xF0, 0x0C, 0xC0, 0x30, 0x02, ++0xC3, 0x00, 0x1C, 0x03, 0x70, 0x8C, 0x40, 0x35, 0x00, 0xC1, 0x00, 0x3C, 0x23, ++0xF0, 0x0C, 0xC0, 0x30, 0x00, 0x8F, 0x00, 0x04, 0x11, 0x30, 0x8C, 0xC0, 0xB3, ++0x82, 0xC7, 0x00, 0x3C, 0x02, 0x30, 0x0C, 0xC0, 0x02, 0x00, 0x8F, 0x00, 0x2C, ++0x02, 0x30, 0x2C, 0xC0, 0x48, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xA8, 0x3D, 0x00, 0xBF, 0x00, 0xFE, 0xA3, 0xF0, 0x83, 0xC0, 0x3F, 0x92, 0xFF, ++0x00, 0xEC, 0x83, 0xF0, 0x0F, 0xC0, 0xBF, 0x04, 0xFF, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC0, 0x3F, 0x04, 0x7F, 0x08, 0xBC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, ++0xFF, 0x00, 0xFC, 0x03, 0x75, 0x8F, 0xD0, 0x0F, 0x00, 0xFF, 0x00, 0x5C, 0x03, ++0xF0, 0x0F, 0xE0, 0x0B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, ++0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x37, 0x00, 0xD3, 0x01, ++0x0C, 0x04, 0x30, 0x0D, 0xC0, 0xB5, 0x01, 0xDB, 0x00, 0x7C, 0x7B, 0xF0, 0xED, ++0xC1, 0x34, 0x00, 0xDF, 0x00, 0x6C, 0x03, 0xB8, 0x8D, 0xC1, 0x27, 0x00, 0xDF, ++0x01, 0x4C, 0x05, 0x10, 0x0D, 0xC4, 0x04, 0x00, 0xDF, 0x00, 0x4C, 0x03, 0x30, ++0x19, 0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x98, 0x39, ++0x00, 0xED, 0x00, 0xB4, 0x03, 0xD2, 0x0E, 0x40, 0x3B, 0x00, 0xF1, 0x00, 0x85, ++0x02, 0x50, 0x0E, 0x40, 0x33, 0x01, 0xE1, 0x00, 0xB4, 0x03, 0xD0, 0x0C, 0x40, ++0x38, 0x01, 0xCD, 0x00, 0xA4, 0x83, 0x10, 0x4E, 0xC0, 0x2B, 0x00, 0xED, 0x00, ++0x84, 0x03, 0x10, 0x0E, 0x40, 0x08, 0x00, 0xED, 0x80, 0x84, 0x03, 0x10, 0x0E, ++0x40, 0x48, 0x68, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, ++0xED, 0x01, 0xB4, 0x47, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xE1, 0x81, 0x84, 0x07, ++0x00, 0x1E, 0x41, 0x7B, 0x00, 0xE1, 0x03, 0xB4, 0x97, 0xD8, 0x5E, 0x40, 0x7A, ++0x00, 0xED, 0x01, 0x05, 0x07, 0x14, 0x5E, 0x44, 0x7B, 0x00, 0xC5, 0x01, 0x04, ++0x07, 0x90, 0x1C, 0x40, 0x4A, 0x00, 0xCD, 0x11, 0x04, 0x47, 0x10, 0x1C, 0x40, ++0x12, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x20, 0x33, 0xA0, 0xCD, ++0x1A, 0x34, 0x86, 0xD0, 0x0C, 0x41, 0x23, 0x02, 0xC1, 0x00, 0x04, 0x27, 0x5B, ++0x1D, 0x42, 0x33, 0x40, 0x41, 0x00, 0x34, 0x03, 0xD0, 0x0D, 0x50, 0x32, 0x00, ++0xCD, 0x06, 0x04, 0x07, 0x10, 0x0D, 0x40, 0xB1, 0x00, 0xCD, 0x00, 0x05, 0x07, ++0x94, 0x0C, 0x50, 0xF2, 0x04, 0xCD, 0x00, 0x05, 0x03, 0x14, 0x0C, 0x78, 0x5A, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x17, 0x00, 0x7F, 0x03, ++0x7C, 0x01, 0xF0, 0x77, 0x40, 0x57, 0x40, 0x53, 0x00, 0xCC, 0x05, 0x30, 0x05, ++0xC0, 0x17, 0x00, 0x73, 0xC1, 0x74, 0x01, 0xF0, 0x05, 0xC8, 0x16, 0x10, 0x7F, ++0x02, 0xEC, 0x11, 0xB0, 0x05, 0x40, 0x1F, 0x00, 0x7F, 0x00, 0xCC, 0x15, 0xB0, ++0x07, 0xC0, 0xDA, 0x09, 0x7F, 0x03, 0xCC, 0x05, 0x30, 0x27, 0xC0, 0x5E, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x00, 0x0F, 0x00, 0x74, ++0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, ++0x07, 0x00, 0x17, 0x01, 0x3C, 0x00, 0xF0, 0x01, 0xC0, 0x05, 0xA0, 0x1B, 0x00, ++0x3E, 0x04, 0x70, 0x01, 0xC0, 0x07, 0x04, 0x1F, 0x00, 0x7C, 0x00, 0x74, 0x01, ++0xC0, 0x85, 0x00, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xC0, 0x49, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x02, ++0xF0, 0x08, 0xD4, 0x24, 0x00, 0x93, 0x02, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x26, ++0x40, 0x93, 0x00, 0x4C, 0x02, 0xB0, 0x09, 0xD0, 0x24, 0x00, 0x9F, 0x00, 0x4C, ++0x82, 0x30, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x7C, 0x42, 0xF0, 0x08, 0xC0, ++0x24, 0x00, 0x93, 0x10, 0x4C, 0x02, 0x34, 0x09, 0xC1, 0x43, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x00, 0x44, 0x06, 0xD0, ++0x09, 0x40, 0x20, 0x00, 0x91, 0x10, 0x74, 0x02, 0xD0, 0x19, 0x48, 0xA4, 0x00, ++0x81, 0x00, 0x44, 0x02, 0x10, 0x29, 0xC0, 0x26, 0x00, 0x9D, 0x00, 0x44, 0x02, ++0xB0, 0x09, 0xC0, 0xA6, 0x00, 0x9D, 0x02, 0x5C, 0x0A, 0xD0, 0x29, 0x40, 0x24, ++0x00, 0x91, 0x02, 0x4C, 0x0A, 0x10, 0x29, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1C, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x44, 0x06, 0xD0, 0x09, ++0x48, 0x64, 0x00, 0x91, 0x00, 0x74, 0x06, 0x50, 0x89, 0x40, 0x62, 0x84, 0x99, ++0x00, 0x44, 0x06, 0x10, 0x19, 0x63, 0x64, 0x80, 0x8D, 0x00, 0x44, 0x02, 0x10, ++0x09, 0x42, 0x24, 0x04, 0x91, 0x10, 0x74, 0x42, 0xD0, 0x09, 0x51, 0x24, 0x00, ++0x99, 0x30, 0x44, 0xC3, 0x10, 0x09, 0x41, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x28, 0x20, 0x00, 0x8D, 0x04, 0x04, 0x02, 0xD0, 0x48, 0x40, ++0x34, 0x40, 0x81, 0x00, 0x34, 0x12, 0xD0, 0x4C, 0x40, 0x20, 0x81, 0x99, 0x00, ++0x04, 0x12, 0x10, 0x48, 0x40, 0x20, 0x21, 0x8D, 0x04, 0x06, 0x12, 0x90, 0x4C, ++0x48, 0x20, 0x01, 0x8D, 0x04, 0x14, 0x12, 0xD8, 0x48, 0x60, 0x20, 0x00, 0x89, ++0xC4, 0x04, 0x12, 0x10, 0x48, 0x60, 0x53, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x00, 0x4C, 0x01, 0xF0, 0x01, 0xC0, 0x80, ++0x02, 0x13, 0x0A, 0x74, 0x00, 0x70, 0xA1, 0xC0, 0x86, 0x22, 0x19, 0x00, 0x45, ++0x00, 0x30, 0xA1, 0x40, 0x04, 0x00, 0x1F, 0x0A, 0x4D, 0x00, 0x30, 0xA1, 0x40, ++0x04, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF1, 0x01, 0xC8, 0x14, 0x00, 0x13, 0x00, ++0x4C, 0x00, 0x30, 0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x19, 0xA8, 0x27, 0x00, 0xBF, 0x88, 0xFD, 0x02, 0xF0, 0x8B, 0x80, 0x2F, 0x00, ++0x9F, 0x00, 0xFC, 0xA2, 0xF0, 0x8B, 0xC0, 0x27, 0x42, 0xB7, 0x00, 0x7C, 0x22, ++0xF4, 0x89, 0xC0, 0x27, 0x22, 0xBF, 0x08, 0xFC, 0x22, 0x74, 0x89, 0xD0, 0x2F, ++0x02, 0xBF, 0x08, 0xDC, 0x22, 0xF1, 0x8B, 0xC0, 0x2F, 0x40, 0xB7, 0x28, 0xDD, ++0x22, 0xF0, 0x8B, 0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA8, 0x27, 0x00, 0x9F, 0x04, 0xFE, 0x02, 0xF0, 0x09, 0xC0, 0x2F, 0x02, 0xBF, ++0x00, 0xDC, 0x52, 0xB0, 0xCA, 0xC8, 0x2E, 0x08, 0xBF, 0xA0, 0xDC, 0x82, 0x32, ++0x4B, 0xC2, 0x6F, 0x01, 0xDF, 0x0C, 0xFC, 0x02, 0x34, 0x0B, 0xC0, 0x26, 0x00, ++0x93, 0x04, 0x5C, 0x52, 0xF0, 0x49, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0x30, 0x49, 0xC0, 0x63, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, ++0x07, 0x00, 0x1D, 0x08, 0x74, 0x00, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x14, ++0x74, 0x00, 0xD0, 0xC1, 0x40, 0x84, 0x04, 0x1D, 0x00, 0x5C, 0x20, 0x10, 0x41, ++0x43, 0x07, 0x00, 0x1D, 0x0C, 0x74, 0x08, 0x10, 0x01, 0x41, 0x04, 0x42, 0x13, ++0x00, 0x44, 0x00, 0xD0, 0x81, 0x40, 0x04, 0x00, 0x1D, 0x00, 0x7C, 0x20, 0x10, ++0x03, 0x40, 0x73, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, ++0x00, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x88, 0x40, 0x23, 0x00, 0x8D, 0x04, 0x34, ++0x02, 0x90, 0x48, 0x40, 0x22, 0x03, 0x8D, 0x00, 0x34, 0x02, 0x10, 0xC8, 0x40, ++0x23, 0x02, 0x8D, 0x44, 0x34, 0x22, 0x12, 0x88, 0x48, 0x28, 0x80, 0xA1, 0x09, ++0xB4, 0x06, 0xD0, 0x1A, 0x40, 0x28, 0x00, 0xAD, 0x89, 0xB4, 0x06, 0x10, 0x9A, ++0x40, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, ++0x9D, 0x00, 0x74, 0x06, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, ++0xD0, 0x0D, 0x60, 0x24, 0x00, 0x9D, 0x02, 0x74, 0x02, 0x10, 0x09, 0x40, 0x27, ++0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x0D, 0x40, 0xA4, 0x00, 0xB9, 0x00, 0xE4, ++0x02, 0xD0, 0x4B, 0x40, 0x2C, 0x00, 0xBC, 0x40, 0xF4, 0x02, 0x10, 0x8B, 0x40, ++0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, 0x9F, ++0x00, 0x74, 0x02, 0xF0, 0x19, 0x40, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x6A, 0x90, ++0x09, 0xC0, 0x26, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x22, 0x30, 0x09, 0xD0, 0x60, 0x00, 0x93, 0x0B, 0x7C, 0x0A, ++0xF0, 0x39, 0xD0, 0x64, 0x04, 0x9F, 0x02, 0x7C, 0x0A, 0x34, 0x39, 0xC0, 0x17, ++0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x25, 0x00, 0x9F, 0x20, ++0x7C, 0x42, 0xF0, 0x49, 0xC0, 0x67, 0x02, 0x9F, 0x00, 0x7C, 0x02, 0xD0, 0x98, ++0xC0, 0x27, 0x00, 0x9F, 0x09, 0x1C, 0x02, 0xF4, 0x09, 0xC0, 0x27, 0x80, 0x9F, ++0x00, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0x25, 0x01, 0x87, 0x01, 0x5C, 0x16, 0xF0, ++0x19, 0xC0, 0x67, 0x01, 0x9E, 0x05, 0x5C, 0x02, 0xF0, 0x19, 0xC0, 0x4B, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x4C, ++0x80, 0xF2, 0x01, 0xC2, 0x04, 0x04, 0x1F, 0x00, 0x7C, 0x08, 0x30, 0x01, 0xC0, ++0x07, 0x04, 0x13, 0x00, 0x6C, 0x00, 0xF0, 0x01, 0xD0, 0x04, 0x00, 0x1F, 0x00, ++0x4C, 0x80, 0xB0, 0x01, 0xC0, 0x06, 0x00, 0x17, 0x00, 0x7C, 0x00, 0x70, 0x00, ++0xC0, 0x04, 0x00, 0x1F, 0x00, 0x0C, 0x00, 0xF2, 0x01, 0xC0, 0x43, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x14, 0x20, 0x5D, 0x00, 0xD0, 0x11, ++0x70, 0x05, 0x40, 0x9C, 0x00, 0x7D, 0x11, 0x74, 0x01, 0x00, 0x37, 0xC1, 0x5E, ++0x00, 0x51, 0x05, 0x40, 0x05, 0xD0, 0x17, 0x40, 0x54, 0x00, 0x5D, 0x00, 0x44, ++0x01, 0x30, 0x07, 0x40, 0x14, 0x00, 0x51, 0x00, 0x74, 0x01, 0x50, 0x05, 0x50, ++0x14, 0x10, 0x5D, 0x21, 0x54, 0x01, 0xD0, 0x15, 0x40, 0x53, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x04, 0x0D, 0x50, ++0x0C, 0x40, 0x30, 0x00, 0xCD, 0x00, 0x34, 0x06, 0x10, 0x34, 0x51, 0x71, 0x00, ++0x81, 0x01, 0x34, 0x26, 0xD0, 0x1C, 0x40, 0x60, 0x02, 0xCD, 0x00, 0x04, 0x22, ++0x10, 0x85, 0x40, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x32, ++0x00, 0xC9, 0x01, 0x04, 0x03, 0xD0, 0x1C, 0x60, 0x53, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x88, 0x38, 0x00, 0xED, 0x21, 0x84, 0x03, 0x50, 0x1E, ++0x40, 0x38, 0xA0, 0xED, 0x00, 0x34, 0x0F, 0x10, 0x06, 0x40, 0x7A, 0x44, 0xA1, ++0x01, 0x94, 0x03, 0xD0, 0x1E, 0x41, 0x38, 0x00, 0xCD, 0x09, 0x04, 0x02, 0x10, ++0x06, 0x40, 0x32, 0x00, 0xE9, 0x00, 0xB4, 0x07, 0x50, 0x0A, 0x40, 0x2A, 0x00, ++0xCD, 0x11, 0x94, 0x02, 0xD0, 0x0E, 0x41, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x11, 0x10, 0x78, 0x00, 0xCF, 0x01, 0x85, 0x07, 0x70, 0x1C, 0xD0, ++0x58, 0x00, 0x2F, 0x01, 0xBC, 0x07, 0x34, 0x16, 0xC0, 0x5D, 0x00, 0xA1, 0x01, ++0xBC, 0x07, 0xF0, 0x17, 0xC0, 0x78, 0x00, 0xEE, 0x11, 0x8D, 0x06, 0x39, 0x14, ++0xC0, 0x5A, 0x00, 0x6F, 0x01, 0x3C, 0x05, 0x70, 0x14, 0xC0, 0x5A, 0x00, 0x6D, ++0x01, 0x8C, 0x05, 0xF0, 0x16, 0xC4, 0x47, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xA8, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x70, 0x0D, 0xC0, 0x07, ++0x00, 0x1F, 0x00, 0x7C, 0x03, 0x78, 0x01, 0xC8, 0x07, 0x00, 0x8F, 0x00, 0x6C, ++0x03, 0xF0, 0x05, 0xC0, 0x37, 0x00, 0xDF, 0x82, 0x7E, 0x02, 0x74, 0x07, 0xC4, ++0x15, 0x00, 0x57, 0x00, 0x7C, 0x01, 0xB4, 0x01, 0xC0, 0x05, 0x00, 0x5F, 0x20, ++0x6D, 0x00, 0xF0, 0x05, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x20, 0x7D, 0x00, 0xFF, 0x01, 0x8C, 0x13, 0x70, 0x1F, 0xC0, 0x7F, 0x00, ++0xF3, 0x01, 0xCC, 0x07, 0x30, 0x17, 0xC2, 0x6F, 0x10, 0xF2, 0x01, 0xFC, 0x07, ++0xF0, 0x1B, 0xC0, 0x7C, 0x20, 0xF7, 0x81, 0xFC, 0x06, 0xF0, 0x13, 0xC2, 0x79, ++0x00, 0xF3, 0x01, 0xFC, 0x07, 0x30, 0x1F, 0xC8, 0x7F, 0x00, 0xBB, 0x01, 0xCC, ++0x87, 0x30, 0x1B, 0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0x18, 0x39, 0x00, 0xED, 0x08, 0x8C, 0x03, 0x10, 0x0E, 0x40, 0x1F, 0x00, 0xE1, ++0x08, 0x84, 0x03, 0x14, 0x02, 0x40, 0x1B, 0x01, 0xE1, 0x00, 0xB4, 0x03, 0xD0, ++0x0A, 0x40, 0x38, 0x00, 0xE1, 0x10, 0xB4, 0x13, 0x10, 0x42, 0x40, 0x38, 0x01, ++0xE1, 0x00, 0x9C, 0x03, 0x10, 0x4A, 0x40, 0x2B, 0x20, 0xA1, 0x00, 0xAC, 0x02, ++0x10, 0x0A, 0x40, 0x54, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x39, 0x00, 0xED, 0x10, 0xA4, 0x23, 0x50, 0x0E, 0x41, 0x3B, 0x44, 0x61, 0x00, ++0x84, 0x03, 0x50, 0x06, 0x40, 0x2B, 0x00, 0xE1, 0x00, 0xB4, 0x23, 0xD0, 0x02, ++0x40, 0x38, 0x00, 0xE5, 0x00, 0x34, 0x02, 0x50, 0x02, 0x60, 0x19, 0x10, 0x61, ++0x00, 0xB4, 0x01, 0x90, 0x06, 0x44, 0x1F, 0x02, 0x01, 0x00, 0x84, 0x01, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x31, ++0x20, 0xCD, 0x03, 0x24, 0x03, 0x10, 0x0C, 0x40, 0x03, 0x00, 0x51, 0x00, 0x04, ++0x4B, 0x50, 0x00, 0x40, 0x03, 0x00, 0xC1, 0x43, 0x36, 0x03, 0xD0, 0x00, 0x40, ++0x30, 0x00, 0xC1, 0x03, 0x34, 0x0B, 0x10, 0x00, 0x40, 0x90, 0x40, 0x41, 0x42, ++0x14, 0x01, 0x90, 0x20, 0x40, 0x83, 0x2E, 0x01, 0x02, 0x24, 0x08, 0x10, 0x00, ++0x40, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, ++0xDF, 0x03, 0x6D, 0x03, 0x70, 0x3D, 0xC0, 0x67, 0x00, 0xD3, 0x00, 0x4D, 0x0B, ++0x70, 0x0D, 0xC2, 0x37, 0x40, 0x93, 0x01, 0x3C, 0x03, 0xF0, 0x0D, 0xD0, 0x30, ++0x00, 0xF7, 0x23, 0x7C, 0x0A, 0x70, 0x05, 0xC0, 0xA1, 0x00, 0x93, 0x03, 0x7C, ++0x06, 0xB0, 0x3D, 0xC0, 0xF7, 0x00, 0xD3, 0xA3, 0x4D, 0x8F, 0x34, 0x1D, 0xD0, ++0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xDF, ++0x04, 0x5C, 0x0F, 0xF0, 0x0D, 0xC0, 0x37, 0x08, 0x5F, 0x00, 0x3C, 0x03, 0xB0, ++0x09, 0xC0, 0x37, 0x20, 0x9F, 0x08, 0x7C, 0x83, 0xF0, 0x05, 0xC0, 0x37, 0x00, ++0xCF, 0x04, 0x7C, 0x02, 0x70, 0x20, 0xC0, 0x27, 0x04, 0x8F, 0x11, 0x1C, 0x46, ++0x74, 0x19, 0xC1, 0x27, 0x00, 0xD7, 0x01, 0x5C, 0x06, 0xF0, 0x1D, 0xC0, 0x07, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x3F, 0x00, 0xDF, 0x00, ++0xFC, 0x03, 0xF0, 0x0E, 0xC1, 0x0C, 0x08, 0xBF, 0x03, 0x4C, 0x03, 0x30, 0x0E, ++0xD0, 0x14, 0x00, 0xBF, 0x19, 0xCC, 0x17, 0x30, 0x89, 0xC0, 0x34, 0x00, 0xF7, ++0x00, 0xCC, 0x42, 0xF0, 0x05, 0xC0, 0x8E, 0x00, 0x37, 0x08, 0x68, 0x20, 0x30, ++0x07, 0xC0, 0x1F, 0x00, 0x7F, 0x10, 0x7C, 0x41, 0xF0, 0x07, 0xC0, 0x13, 0x22, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x36, 0x00, 0xDD, 0x00, 0x74, ++0x0F, 0xD0, 0x0D, 0xC0, 0x46, 0x00, 0x1D, 0x01, 0x44, 0x27, 0x10, 0x31, 0x40, ++0x04, 0x00, 0x8D, 0x01, 0x44, 0x07, 0x10, 0x01, 0x40, 0x34, 0x00, 0xDB, 0x00, ++0x44, 0x02, 0xD0, 0x19, 0x40, 0x44, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, ++0x40, 0x07, 0x00, 0x5D, 0x00, 0x74, 0x00, 0xD0, 0x05, 0x40, 0x17, 0x02, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0x74, 0x0F, ++0xD0, 0x0D, 0x40, 0x24, 0x01, 0x9D, 0x10, 0x54, 0x03, 0x14, 0x1D, 0x40, 0x24, ++0x20, 0x9D, 0x00, 0x46, 0x03, 0x10, 0x0C, 0x41, 0x36, 0x02, 0xD0, 0x00, 0x44, ++0x02, 0xD8, 0x11, 0x40, 0x27, 0x00, 0x95, 0x00, 0x74, 0x02, 0x50, 0x0D, 0x40, ++0x37, 0x00, 0x98, 0x00, 0x74, 0x03, 0xD0, 0x09, 0x40, 0x07, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x30, 0x80, 0xCD, 0x00, 0x34, 0x03, 0xD0, ++0x0C, 0x50, 0x12, 0x00, 0x0D, 0x00, 0x14, 0x03, 0x10, 0x08, 0x40, 0x10, 0x00, ++0x9D, 0x00, 0x04, 0x03, 0x10, 0x04, 0x48, 0x30, 0x00, 0xC9, 0x00, 0x04, 0x03, ++0xD0, 0x00, 0x40, 0x25, 0x00, 0x81, 0x00, 0x15, 0x02, 0x54, 0x08, 0x40, 0x23, ++0x80, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x43, 0xA0, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xB0, 0x36, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x24, 0x00, 0x8F, 0x00, 0x5D, 0x03, 0x14, 0x05, 0xC0, 0x24, 0x20, 0x9E, ++0x00, 0x4D, 0x03, 0x34, 0x09, 0xD0, 0x34, 0x00, 0xF7, 0x00, 0x4D, 0x02, 0xF0, ++0x01, 0xC0, 0x07, 0x00, 0x17, 0x00, 0x7C, 0x00, 0x70, 0x05, 0xC8, 0x17, 0x10, ++0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x01, 0xC0, 0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0xA8, 0x3F, 0x20, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, ++0x0D, 0x00, 0x3F, 0x00, 0xEC, 0x03, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0xBF, 0x00, ++0xFC, 0x03, 0xF0, 0x03, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, ++0xC0, 0x0E, 0x00, 0x3F, 0x20, 0xEC, 0x00, 0xB0, 0x03, 0xC0, 0x0B, 0x00, 0x3F, ++0x40, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x17, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xA0, 0x2F, 0x00, 0xBF, 0x00, 0xCC, 0x03, 0xB0, 0x1B, 0xC0, 0x2F, ++0x21, 0xF3, 0x24, 0xEC, 0x25, 0xF0, 0x1F, 0xD0, 0x3C, 0x00, 0xFB, 0x88, 0xCC, ++0x84, 0xB0, 0x4F, 0xC0, 0x7F, 0x22, 0x2F, 0x01, 0xF4, 0x05, 0x30, 0x0B, 0xC1, ++0xEF, 0x00, 0x2F, 0x01, 0xEC, 0x04, 0x30, 0x12, 0xC0, 0x5E, 0x08, 0x2F, 0x01, ++0xCE, 0x0D, 0x30, 0x0B, 0xC0, 0x0D, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x27, 0x10, 0x9D, 0x01, 0x44, 0x0F, 0x10, 0x15, 0x40, 0x67, 0x00, ++0xD1, 0x14, 0x44, 0x02, 0xD0, 0x4D, 0x40, 0xBC, 0x04, 0xF1, 0x0E, 0x44, 0x07, ++0x10, 0xBF, 0x40, 0x37, 0x00, 0x17, 0x94, 0x64, 0x05, 0x10, 0x39, 0x40, 0x37, ++0x11, 0x5D, 0x21, 0x44, 0x05, 0x51, 0x19, 0x40, 0x75, 0x30, 0x1D, 0x21, 0x46, ++0x02, 0x10, 0x11, 0xC0, 0x0D, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++0xA0, 0x23, 0x00, 0x0D, 0x80, 0x05, 0x0B, 0xD8, 0x08, 0x40, 0x23, 0x02, 0xC1, ++0x0C, 0x24, 0x02, 0x50, 0x08, 0x41, 0xB0, 0x81, 0xC9, 0x04, 0x54, 0x07, 0x90, ++0x0C, 0x40, 0x33, 0x11, 0x0D, 0x00, 0x74, 0x00, 0x10, 0x0C, 0x44, 0x31, 0x01, ++0x49, 0x00, 0x24, 0x00, 0x12, 0x0D, 0x44, 0x31, 0x00, 0x1D, 0x40, 0x64, 0x13, ++0x90, 0x08, 0x40, 0x4D, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, ++0x65, 0x00, 0x9D, 0x11, 0x44, 0x03, 0x18, 0x65, 0x40, 0x27, 0x00, 0xD1, 0x00, ++0x42, 0x02, 0xD0, 0x08, 0x40, 0x34, 0x08, 0xC1, 0x00, 0x55, 0x03, 0x10, 0x0D, ++0x40, 0x37, 0x00, 0x9D, 0x11, 0x64, 0x00, 0x1C, 0x0D, 0x40, 0x37, 0x10, 0x5D, ++0x11, 0x44, 0x45, 0x50, 0x89, 0x00, 0x75, 0x00, 0x1D, 0x10, 0x64, 0x43, 0x96, ++0x11, 0x40, 0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x47, ++0x04, 0x9F, 0x21, 0x44, 0x03, 0xF2, 0x05, 0xC0, 0x33, 0x40, 0xD3, 0x00, 0x6C, ++0x03, 0xF1, 0x0D, 0xC0, 0x34, 0x00, 0xDB, 0x00, 0x54, 0x04, 0xB0, 0x0D, 0xC0, ++0x37, 0x00, 0x1F, 0x01, 0x7C, 0x14, 0x30, 0x09, 0xC0, 0x35, 0x00, 0x5B, 0x01, ++0x2C, 0x0D, 0x30, 0x31, 0x82, 0x77, 0x01, 0x1D, 0x22, 0x64, 0x0F, 0xB1, 0x31, ++0xC1, 0x81, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x2D, 0x00, ++0xAF, 0x00, 0xBC, 0x03, 0xF0, 0x07, 0xC0, 0x3F, 0x02, 0xEF, 0x80, 0xFC, 0x82, ++0xF0, 0x8F, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xEC, 0xA0, 0xF0, 0x0F, 0xC2, 0x3F, ++0x10, 0x37, 0x00, 0xEC, 0xA4, 0x70, 0x9B, 0xC0, 0x3F, 0x00, 0x7F, 0x00, 0xFC, ++0x01, 0xF0, 0x13, 0xC0, 0x2F, 0x00, 0x3F, 0x08, 0xDD, 0x27, 0x70, 0x03, 0xC0, ++0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x05, 0x02, 0x13, ++0x10, 0x7E, 0x23, 0xB0, 0x05, 0xC0, 0x37, 0x03, 0xDF, 0x80, 0x7C, 0x03, 0xF1, ++0x09, 0xC0, 0x35, 0x80, 0xDF, 0x08, 0x4C, 0x80, 0x70, 0x0D, 0xC1, 0x37, 0x00, ++0x93, 0x02, 0x5C, 0x08, 0xF8, 0x0D, 0xC2, 0x37, 0x00, 0x5F, 0x0E, 0x78, 0x1B, ++0x70, 0x25, 0xC4, 0xA5, 0x00, 0x53, 0x00, 0x6C, 0x4B, 0x31, 0x09, 0xC4, 0x0B, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xE4, 0x02, 0x91, 0x00, ++0xF4, 0x07, 0x10, 0x05, 0x41, 0x77, 0x00, 0xFD, 0x00, 0x44, 0x02, 0xD0, 0x19, ++0xC8, 0x3E, 0x20, 0xFF, 0x00, 0x00, 0x2C, 0x10, 0x1F, 0x40, 0x37, 0x00, 0x91, ++0x00, 0x04, 0x00, 0xF0, 0x0D, 0x40, 0x37, 0x00, 0x4C, 0x01, 0x44, 0x05, 0xB0, ++0x04, 0x40, 0x24, 0x00, 0x4B, 0x04, 0x24, 0x83, 0x14, 0x71, 0x40, 0x6F, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x40, 0x00, 0x01, 0x00, 0x34, ++0x83, 0x14, 0x3C, 0x41, 0xA3, 0x10, 0xCD, 0x00, 0x14, 0x01, 0xD0, 0x9C, 0x40, ++0x35, 0x08, 0xCD, 0x01, 0x04, 0x08, 0x50, 0xBC, 0x60, 0x32, 0x00, 0x05, 0x00, ++0x14, 0x01, 0xD0, 0x68, 0x40, 0x23, 0x00, 0x49, 0x03, 0x14, 0x8C, 0xD1, 0xB4, ++0x41, 0x31, 0x00, 0x00, 0x00, 0x04, 0x23, 0x10, 0x48, 0x40, 0x0F, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x58, 0x00, 0x61, 0x01, 0xB4, 0x07, ++0x10, 0x16, 0x40, 0x6B, 0x00, 0xED, 0x01, 0x96, 0x06, 0xD0, 0x1E, 0x40, 0x7A, ++0x00, 0xC5, 0x41, 0x84, 0x47, 0x10, 0x1E, 0x68, 0x7B, 0x00, 0xF1, 0x00, 0x84, ++0x05, 0x50, 0x9A, 0x40, 0x7B, 0x02, 0x7D, 0x01, 0xC4, 0x14, 0x90, 0x1A, 0x48, ++0x79, 0x20, 0x39, 0x09, 0x85, 0x27, 0x15, 0x1A, 0x40, 0x3F, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x34, 0x02, 0x43, 0x04, 0x34, 0x03, 0x10, ++0x0C, 0xC0, 0x33, 0x10, 0xDF, 0x00, 0x1C, 0x02, 0xF0, 0x0C, 0xC0, 0x31, 0x00, ++0xCD, 0x00, 0x0C, 0x03, 0x70, 0xCC, 0xC0, 0x37, 0x42, 0x05, 0x00, 0x1C, 0x11, ++0xD0, 0x08, 0xC0, 0x33, 0x00, 0x4B, 0x00, 0x1C, 0x40, 0xF0, 0x8C, 0xC0, 0x31, ++0x02, 0xC3, 0x00, 0x6C, 0x23, 0x30, 0x88, 0xE0, 0x4B, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x38, 0x3D, 0x40, 0x7F, 0x00, 0xBC, 0x03, 0x70, 0x07, ++0xC0, 0x3F, 0x02, 0xFF, 0x00, 0xCC, 0x02, 0xF0, 0x0C, 0xC0, 0xBF, 0x20, 0xDF, ++0x00, 0x3C, 0x03, 0xC0, 0x8F, 0xC8, 0x37, 0x08, 0xFF, 0x8C, 0x7C, 0x01, 0xF0, ++0x09, 0xC0, 0x3F, 0x00, 0xFF, 0x48, 0x1C, 0x11, 0xF0, 0x89, 0xC0, 0x3A, 0x00, ++0xBF, 0x00, 0xFC, 0x23, 0xF2, 0x0F, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA0, 0x17, 0x00, 0xDF, 0x01, 0x6C, 0x03, 0xF0, 0x0D, 0xC0, ++0x27, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0C, 0xC4, 0x74, 0x03, 0xD1, 0x0E, ++0x7C, 0x80, 0x70, 0x6D, 0xE0, 0x37, 0x00, 0xD7, 0x00, 0x7C, 0x00, 0x70, 0x1D, ++0xC0, 0x36, 0x00, 0x5B, 0x00, 0x7C, 0x04, 0xB0, 0x05, 0xC0, 0x37, 0x00, 0x97, ++0x00, 0x4C, 0x03, 0x34, 0x01, 0xC0, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x80, 0x19, 0x00, 0xED, 0x00, 0x84, 0x0B, 0xC0, 0x06, 0x40, 0xAB, ++0x20, 0xED, 0x04, 0xB4, 0x02, 0xD0, 0x0E, 0x40, 0x31, 0x00, 0xE1, 0x10, 0xB4, ++0x03, 0xD0, 0xEE, 0xC0, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x00, 0xD0, 0x4E, 0x40, ++0x38, 0x00, 0x61, 0x00, 0xA4, 0x00, 0x10, 0x0E, 0x60, 0x3B, 0x00, 0x2D, 0x00, ++0x8D, 0x03, 0xB0, 0x06, 0x40, 0x4F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x00, 0x79, 0x00, 0xED, 0x01, 0x85, 0x17, 0x50, 0x1E, 0x41, 0x7B, 0x01, ++0xED, 0x09, 0xB4, 0x07, 0x50, 0x1E, 0x40, 0x78, 0x41, 0xE1, 0x05, 0x94, 0x47, ++0x50, 0x1E, 0x02, 0x7B, 0x10, 0xED, 0x01, 0xB4, 0x04, 0xD2, 0xDC, 0x00, 0x7A, ++0x24, 0x6D, 0x01, 0xD6, 0x0D, 0xD8, 0x1E, 0x40, 0x7B, 0x04, 0xE5, 0x01, 0xF4, ++0x07, 0x10, 0x1A, 0x60, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x28, 0x33, 0x00, 0xCD, 0x1A, 0x04, 0x03, 0xD0, 0x14, 0x40, 0x73, 0x02, 0xCD, ++0x00, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0x31, 0x00, 0xC1, 0x00, 0x34, 0x13, 0xD0, ++0x0C, 0x48, 0x30, 0x00, 0xDD, 0x01, 0x34, 0x06, 0xD0, 0x8C, 0x40, 0x30, 0x00, ++0x45, 0x08, 0x34, 0x0D, 0xD0, 0x8C, 0x40, 0x73, 0x00, 0xCD, 0x01, 0x04, 0x03, ++0x17, 0x0C, 0x40, 0x5B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, ++0x1D, 0x06, 0x7D, 0x03, 0x6C, 0x01, 0xF0, 0x17, 0xC0, 0x17, 0x00, 0x5F, 0x00, ++0xF4, 0x2D, 0x70, 0x04, 0xC4, 0x14, 0x10, 0x53, 0x80, 0xFC, 0x0D, 0x71, 0x05, ++0xC0, 0x17, 0x00, 0x7F, 0x07, 0xFC, 0x19, 0xF0, 0x15, 0xC0, 0x56, 0x00, 0x6F, ++0x02, 0xFC, 0x05, 0xF0, 0x27, 0xC8, 0x1F, 0x20, 0x67, 0x07, 0xFC, 0x01, 0x10, ++0x97, 0xC2, 0x5F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x05, ++0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x21, 0xC1, 0x87, 0x00, 0x1F, 0x80, 0x7C, ++0x20, 0xF2, 0x01, 0xC0, 0x07, 0x00, 0x1B, 0x00, 0x7C, 0x08, 0xF0, 0x21, 0xC0, ++0x05, 0x00, 0x1F, 0x04, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x19, 0x50, ++0x6C, 0x18, 0x10, 0x21, 0xC1, 0xC7, 0x08, 0x1B, 0x30, 0x7E, 0x0C, 0xF0, 0x81, ++0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x65, 0x00, ++0x9F, 0x44, 0x7E, 0x0A, 0xF0, 0x09, 0xD0, 0x64, 0x10, 0x9F, 0x00, 0x7C, 0x06, ++0x30, 0x09, 0xD0, 0x24, 0x80, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC2, 0x27, ++0x00, 0x93, 0xC0, 0x4C, 0x42, 0xF0, 0x29, 0xC0, 0x26, 0x00, 0x93, 0x80, 0x5C, ++0x0A, 0xF0, 0x19, 0xC0, 0x65, 0x00, 0x9F, 0x00, 0x5C, 0x26, 0x30, 0x29, 0xC0, ++0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x02, 0x9D, ++0x47, 0x74, 0x06, 0xD0, 0x48, 0x40, 0xEC, 0x10, 0x9D, 0x00, 0x34, 0x26, 0x10, ++0x09, 0xC0, 0x26, 0x10, 0x9D, 0x02, 0x74, 0x1A, 0xD0, 0x09, 0x44, 0x27, 0x00, ++0x91, 0x40, 0x4C, 0x02, 0x78, 0x1B, 0x40, 0x23, 0x00, 0x91, 0x10, 0x44, 0x0E, ++0xD0, 0x08, 0x42, 0x20, 0x10, 0x9B, 0x40, 0x0C, 0x1E, 0x54, 0x09, 0xC0, 0x07, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x00, ++0x74, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x02, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x09, ++0x40, 0x24, 0x00, 0x99, 0x10, 0x74, 0x02, 0xD0, 0x29, 0x40, 0x23, 0x00, 0x91, ++0x00, 0x64, 0x02, 0xD1, 0x29, 0x40, 0x27, 0x00, 0x91, 0x01, 0x54, 0x02, 0x50, ++0x4D, 0x40, 0x25, 0x02, 0x94, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x63, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x05, 0x8D, 0x14, 0x34, ++0x02, 0xD0, 0x09, 0x40, 0x20, 0x00, 0x8D, 0x08, 0x74, 0x0A, 0x10, 0x28, 0x40, ++0x22, 0x02, 0x8D, 0x08, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x02, 0x81, 0x08, ++0x04, 0x02, 0xD0, 0x08, 0x40, 0x27, 0x02, 0x91, 0x40, 0x04, 0x02, 0xD2, 0x09, ++0x40, 0x24, 0x00, 0x99, 0x00, 0x46, 0x22, 0x51, 0x48, 0x44, 0x43, 0x80, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x06, 0x01, 0x1F, 0x04, 0x74, 0xD0, ++0xF0, 0x01, 0xC0, 0x54, 0x10, 0x1F, 0x16, 0x7E, 0x00, 0x34, 0x01, 0x40, 0x84, ++0x05, 0x19, 0x96, 0x7C, 0x00, 0xF0, 0x41, 0xC1, 0x87, 0x00, 0x13, 0x02, 0x6D, ++0x80, 0xD0, 0x11, 0x40, 0x83, 0x40, 0x13, 0x00, 0x54, 0x01, 0x70, 0x05, 0xC0, ++0x15, 0x00, 0x17, 0x00, 0x7C, 0x08, 0x30, 0x05, 0xC0, 0x77, 0xE0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x2F, 0x25, 0xAF, 0x20, 0x7C, 0x02, 0xF0, ++0x0B, 0xC8, 0xAF, 0x00, 0x9D, 0x04, 0xFC, 0x07, 0xF0, 0x1B, 0xC0, 0x27, 0x09, ++0x9F, 0x04, 0xFC, 0x02, 0xF2, 0x09, 0xC2, 0x27, 0x41, 0xBF, 0x04, 0xFC, 0x02, ++0x50, 0x2B, 0xC0, 0x2F, 0x01, 0xBF, 0x00, 0xB4, 0x02, 0xF2, 0x0B, 0xC0, 0x2F, ++0x00, 0xA7, 0x00, 0xBC, 0x12, 0xF4, 0x8B, 0xC0, 0x75, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1C, 0xA0, 0x2F, 0x05, 0xBF, 0x04, 0xFC, 0x02, 0xF0, 0x0B, ++0xD0, 0x6C, 0x04, 0x91, 0x24, 0xFC, 0x0A, 0xF0, 0x2B, 0xD0, 0x24, 0x00, 0xBF, ++0x00, 0x9E, 0x02, 0xF0, 0x4B, 0xC0, 0x26, 0x00, 0x9F, 0x08, 0x7C, 0x82, 0x34, ++0x5B, 0xD1, 0x24, 0x02, 0xBF, 0x00, 0xEC, 0x02, 0xF2, 0x0B, 0xC0, 0x2E, 0x80, ++0xA7, 0x00, 0xCE, 0x83, 0x30, 0x0B, 0xC0, 0x74, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0x00, 0x07, 0x11, 0x1D, 0x08, 0x74, 0x08, 0xD0, 0x01, 0x40, ++0x84, 0x00, 0x11, 0x14, 0x74, 0x04, 0xD0, 0x51, 0x40, 0x84, 0x04, 0x0D, 0x10, ++0x76, 0x00, 0xD1, 0x01, 0x00, 0x04, 0x01, 0x1D, 0x04, 0x74, 0x00, 0x19, 0x21, ++0x40, 0x04, 0x00, 0x19, 0x00, 0x5C, 0x00, 0xD2, 0x01, 0x40, 0x04, 0x10, 0x1D, ++0x00, 0x05, 0x00, 0xB4, 0x01, 0x40, 0x60, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x21, 0x05, 0x8D, 0x00, 0x34, 0x22, 0xD0, 0x09, 0x40, 0x20, ++0x00, 0x81, 0x0C, 0x34, 0x02, 0xD0, 0x48, 0x40, 0x20, 0x83, 0x8D, 0x08, 0x14, ++0x02, 0xD3, 0x88, 0x00, 0x22, 0x05, 0x8D, 0x04, 0x74, 0x02, 0x10, 0x08, 0x40, ++0x20, 0x10, 0x8D, 0x00, 0x36, 0x82, 0xD0, 0x08, 0x40, 0x22, 0x00, 0x95, 0x00, ++0x54, 0x02, 0x14, 0x0C, 0x40, 0x48, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0x2A, 0x25, 0x86, 0x9D, 0x20, 0x74, 0x02, 0xD2, 0x09, 0x40, 0x24, 0x00, ++0x91, 0x20, 0x74, 0x02, 0xD0, 0x1D, 0x40, 0x24, 0x00, 0x9D, 0x40, 0x74, 0x42, ++0xD0, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x02, 0x74, 0x02, 0x10, 0x09, 0x44, 0x24, ++0x01, 0x9D, 0x02, 0x55, 0x0B, 0xD1, 0x89, 0x40, 0xE4, 0x00, 0x9D, 0x03, 0x54, ++0x2A, 0x90, 0x2D, 0x40, 0x60, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0x02, 0x25, 0x10, 0x9F, 0x12, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x93, ++0x00, 0xFC, 0x22, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x5C, 0x2A, 0xF0, ++0x09, 0xC2, 0x26, 0x00, 0x9F, 0x00, 0x3E, 0x3A, 0x10, 0x99, 0xC8, 0x24, 0x20, ++0x8F, 0x4B, 0x7C, 0x22, 0xF0, 0x49, 0xC0, 0xA6, 0x80, 0x87, 0x01, 0x54, 0x02, ++0x31, 0x09, 0xE0, 0x14, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, ++0x25, 0x0C, 0x9F, 0x84, 0x7C, 0x02, 0xF8, 0x09, 0xE0, 0x23, 0x41, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x10, 0x9F, 0x10, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x9F, 0x80, 0x7C, 0x06, 0xF8, 0x19, 0xC4, 0x67, 0x00, 0x9B, ++0x00, 0x7C, 0x02, 0xF0, 0x09, 0xE8, 0x27, 0x88, 0x9F, 0x00, 0x6C, 0x06, 0xD1, ++0x48, 0xD8, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, ++0x00, 0x1F, 0x82, 0x7C, 0x80, 0xF8, 0x41, 0xD0, 0x06, 0x40, 0x13, 0x00, 0x7C, ++0x00, 0x70, 0x41, 0xC0, 0x06, 0x00, 0x13, 0x00, 0x4D, 0xC8, 0x71, 0x01, 0x41, ++0x06, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x01, 0xC1, 0x07, 0x20, 0x1F, 0x30, ++0x5C, 0x10, 0x70, 0xC1, 0xC8, 0x87, 0x20, 0x1F, 0x10, 0x4C, 0x10, 0x32, 0x41, ++0xC4, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xDC, 0x04, ++0x7D, 0x07, 0x74, 0x15, 0x78, 0x76, 0xC0, 0x1C, 0x00, 0x51, 0x00, 0x74, 0x01, ++0x10, 0x16, 0x45, 0x14, 0x00, 0x71, 0x86, 0xC4, 0x09, 0x12, 0x16, 0x40, 0x17, ++0x00, 0x5D, 0x00, 0x74, 0x01, 0x70, 0x36, 0x40, 0x17, 0x10, 0x7D, 0x00, 0xF0, ++0x0D, 0x12, 0x36, 0x48, 0xDF, 0x02, 0x7D, 0x04, 0x80, 0x15, 0x50, 0x07, 0x50, ++0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0xF2, 0x00, 0x8D, ++0x06, 0x34, 0x07, 0x50, 0x18, 0x40, 0x20, 0x00, 0xC1, 0x00, 0x36, 0x23, 0x50, ++0x08, 0x40, 0x32, 0x40, 0xC9, 0x00, 0x04, 0x2F, 0x50, 0xBC, 0x40, 0x33, 0x00, ++0xCD, 0x00, 0x14, 0x03, 0x50, 0x28, 0x40, 0x33, 0x80, 0x4D, 0x0A, 0x34, 0x2F, ++0x50, 0x1C, 0x40, 0xD3, 0x00, 0xC9, 0x00, 0x04, 0x0B, 0x11, 0x0C, 0x40, 0x40, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x80, 0xAD, 0x00, ++0xB4, 0x03, 0x50, 0x02, 0x40, 0x28, 0x00, 0xE1, 0x00, 0xB4, 0x17, 0x18, 0x0E, ++0x40, 0x70, 0x02, 0xE9, 0x01, 0xC4, 0x07, 0x10, 0x0E, 0x40, 0x3B, 0x01, 0xED, ++0x08, 0xB4, 0x03, 0x50, 0x22, 0x40, 0x3B, 0xB0, 0x6D, 0x00, 0xB6, 0x07, 0x11, ++0x06, 0x40, 0x1B, 0x8C, 0xFD, 0x00, 0x85, 0x03, 0x10, 0x0C, 0x40, 0x10, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x78, 0x00, 0xEF, 0x01, 0xBC, ++0x07, 0x70, 0x12, 0xC0, 0x68, 0x00, 0xE3, 0x01, 0xFC, 0x0F, 0x70, 0x1A, 0xD0, ++0x7A, 0x01, 0xE9, 0x01, 0x8C, 0x07, 0x70, 0x1E, 0xE8, 0x7B, 0x03, 0xEF, 0x01, ++0xBC, 0x07, 0x70, 0x12, 0xC0, 0x7B, 0x25, 0x6F, 0x01, 0x9E, 0x06, 0x70, 0x1A, ++0xC0, 0x6B, 0x00, 0xEF, 0x01, 0x8C, 0x06, 0x34, 0x1E, 0xC0, 0x50, 0x60, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, 0x00, 0xDF, 0x00, 0x7C, 0x03, ++0x70, 0x00, 0xC0, 0x21, 0x00, 0xDF, 0x40, 0x7C, 0x03, 0xF2, 0x0C, 0xC0, 0x37, ++0x20, 0xD7, 0x80, 0x7C, 0x01, 0xF2, 0x0D, 0xC0, 0x37, 0x02, 0xDF, 0x10, 0x78, ++0x03, 0x70, 0x01, 0xC2, 0x37, 0x1A, 0x1F, 0x80, 0x3C, 0x02, 0xF0, 0x05, 0xC0, ++0x27, 0x20, 0xDF, 0x00, 0x7C, 0x02, 0xF6, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x5D, 0x00, 0xA3, 0x01, 0xCC, 0x13, 0xF8, ++0x03, 0xC0, 0x6D, 0x00, 0xFF, 0x11, 0xBC, 0x07, 0x20, 0xDB, 0xC0, 0x7C, 0x00, ++0x7F, 0x01, 0xCC, 0x07, 0xF0, 0x9F, 0xD0, 0x7C, 0x00, 0xDF, 0x09, 0xFC, 0x07, ++0xF0, 0x13, 0xC0, 0x7F, 0x20, 0x2F, 0x09, 0xEE, 0x17, 0xF0, 0x1F, 0xC0, 0x5F, ++0x00, 0xFF, 0x01, 0x8C, 0x05, 0x30, 0xDB, 0xC0, 0x18, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x00, 0x39, 0x00, 0xA1, 0x00, 0x84, 0x03, 0x78, 0x42, ++0x40, 0x28, 0x02, 0xED, 0x00, 0xB4, 0x13, 0x10, 0x8A, 0x50, 0x38, 0x11, 0x2D, ++0x04, 0x8C, 0x1A, 0xD0, 0x8A, 0x40, 0x38, 0x00, 0xED, 0x05, 0xB4, 0x03, 0x90, ++0x02, 0x40, 0x3B, 0x00, 0x2D, 0x00, 0x9E, 0x03, 0xD0, 0x0E, 0x40, 0x9B, 0x22, ++0xAD, 0x04, 0xAC, 0x01, 0x10, 0xCE, 0x48, 0x55, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0xA1, 0x00, 0x85, 0x23, 0x50, 0x82, 0x43, ++0x29, 0x00, 0xED, 0x00, 0xF4, 0x02, 0x10, 0x4B, 0x48, 0x38, 0x80, 0x6D, 0x80, ++0x84, 0x03, 0xD2, 0x06, 0x00, 0x38, 0x00, 0xED, 0x04, 0xB4, 0x03, 0xD0, 0x02, ++0x40, 0x3B, 0x00, 0x3D, 0x00, 0x84, 0x12, 0xD0, 0x0A, 0x40, 0x9B, 0x00, 0xF5, ++0x10, 0xD4, 0x20, 0x10, 0xC2, 0x44, 0x60, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x28, 0xC3, 0x00, 0x01, 0x01, 0x00, 0x02, 0x50, 0x30, 0x40, 0x20, ++0x00, 0xCD, 0x00, 0x34, 0x22, 0x10, 0x08, 0x40, 0x30, 0x00, 0x1D, 0x00, 0x04, ++0x4C, 0xD0, 0x00, 0x40, 0x30, 0x00, 0xCD, 0x04, 0x34, 0x43, 0xD0, 0x00, 0x40, ++0x77, 0x00, 0x0D, 0x12, 0x14, 0xC6, 0xD9, 0x8C, 0x40, 0x13, 0x00, 0x8D, 0x23, ++0x05, 0x03, 0x14, 0x24, 0x40, 0x09, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0xA0, 0xE5, 0x41, 0x93, 0x0A, 0x4C, 0x03, 0x70, 0x35, 0xC0, 0x35, 0x00, ++0xFF, 0x00, 0x74, 0x02, 0x34, 0x08, 0xC0, 0x3C, 0x00, 0x9F, 0x00, 0x4C, 0x4E, ++0xF0, 0x09, 0xC0, 0x3C, 0x00, 0xFF, 0x13, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x3F, ++0x01, 0x5F, 0x01, 0x4C, 0x07, 0xF1, 0xBD, 0xC0, 0xB7, 0x00, 0xD7, 0x03, 0x14, ++0x4F, 0x30, 0x94, 0xC0, 0x54, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0x08, 0x27, 0x00, 0x9F, 0x88, 0x7C, 0x03, 0x70, 0x21, 0xC0, 0xB7, 0x00, 0xDF, ++0x00, 0x7C, 0x42, 0xF0, 0x29, 0xC0, 0x37, 0x00, 0x9F, 0x00, 0x5D, 0x02, 0xF0, ++0x00, 0xC4, 0x37, 0x00, 0xDF, 0x20, 0x7C, 0x03, 0xB0, 0x25, 0xE4, 0x37, 0x00, ++0x5F, 0x01, 0x4D, 0x23, 0xF0, 0x05, 0xC0, 0xF7, 0x00, 0xDF, 0x02, 0x7C, 0x1B, ++0xF0, 0x3D, 0xC0, 0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, ++0x27, 0x04, 0xFF, 0x02, 0xFC, 0x03, 0xF0, 0x17, 0xC1, 0x6B, 0x00, 0xF7, 0x00, ++0xFC, 0x07, 0xD0, 0x1B, 0xC0, 0x3C, 0x08, 0x1F, 0x00, 0xCC, 0x02, 0xF0, 0x09, ++0xC0, 0x3D, 0x80, 0xFF, 0x80, 0xCC, 0x03, 0xF8, 0x13, 0xC0, 0x3D, 0x00, 0xF3, ++0x00, 0xFC, 0x26, 0xF0, 0x03, 0xCC, 0x2F, 0x00, 0xF7, 0x10, 0xCC, 0x02, 0x30, ++0x11, 0xC8, 0x04, 0x26, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x66, ++0x00, 0xDD, 0x00, 0x74, 0x03, 0xD0, 0x01, 0x40, 0x17, 0x00, 0xD1, 0x80, 0x74, ++0x07, 0xD0, 0x39, 0x50, 0x34, 0x00, 0x1D, 0x09, 0x44, 0x0C, 0xD0, 0x11, 0x40, ++0x34, 0x80, 0xDD, 0x00, 0x44, 0x03, 0xD8, 0x00, 0xC1, 0x34, 0x40, 0x11, 0x03, ++0x72, 0x0E, 0x70, 0x05, 0x41, 0x23, 0x00, 0xCB, 0x22, 0x44, 0x64, 0x14, 0x39, ++0xC0, 0x06, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x46, 0x0C, ++0x9D, 0x00, 0x74, 0x03, 0xD0, 0x45, 0x41, 0xB7, 0x01, 0xD5, 0x00, 0x74, 0x12, ++0xD0, 0x81, 0x40, 0x36, 0x00, 0xDD, 0x02, 0x44, 0x04, 0xD2, 0x19, 0x41, 0x34, ++0x00, 0xCD, 0x00, 0x44, 0x03, 0xD0, 0x45, 0x40, 0x36, 0x20, 0x51, 0x11, 0x64, ++0x03, 0xD0, 0x19, 0x40, 0x37, 0x00, 0x51, 0x02, 0x44, 0x01, 0x10, 0x41, 0x40, ++0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x8D, ++0x00, 0x34, 0x03, 0xD0, 0x04, 0x40, 0x32, 0x00, 0xC1, 0x00, 0x34, 0x02, 0xD0, ++0x00, 0x40, 0x32, 0x00, 0x8D, 0x00, 0x04, 0x00, 0xD2, 0x00, 0x40, 0x30, 0x00, ++0xCD, 0x10, 0x04, 0x03, 0xD0, 0x04, 0x60, 0x30, 0x00, 0x41, 0x20, 0x34, 0x01, ++0x50, 0x08, 0x40, 0x37, 0x80, 0x09, 0x00, 0x45, 0x00, 0x10, 0x0C, 0x44, 0x42, ++0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x27, 0x00, 0xD7, 0x00, 0x7C, 0x02, 0xF2, 0x01, ++0xD0, 0x36, 0x00, 0x5F, 0x00, 0x45, 0x00, 0xF0, 0x01, 0xD0, 0x3C, 0x20, 0xFD, ++0x00, 0x4D, 0x03, 0xD0, 0x05, 0xC0, 0x3F, 0x10, 0x53, 0x20, 0x74, 0x83, 0xF0, ++0x01, 0xC8, 0x37, 0x80, 0x57, 0x00, 0x4C, 0x00, 0x31, 0x01, 0xC0, 0x04, 0x44, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x2F, 0x00, 0x7F, 0x00, 0xFC, ++0x02, 0xF0, 0x06, 0xC0, 0x1F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x02, 0xC0, ++0x3D, 0x00, 0x3F, 0x00, 0xFD, 0x00, 0xF0, 0x03, 0x82, 0x3F, 0x10, 0xFF, 0x80, ++0xFC, 0x03, 0xF0, 0x07, 0xC0, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x02, 0x70, 0x03, ++0xC0, 0x3F, 0x00, 0x2D, 0x00, 0xFC, 0x00, 0xF2, 0x03, 0x80, 0x14, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xF3, 0x09, 0x8C, 0x07, ++0xF0, 0x1F, 0xC0, 0x7C, 0x00, 0xFF, 0x01, 0xFC, 0x27, 0xF0, 0x9F, 0xC0, 0x7F, ++0x02, 0xFF, 0x09, 0xFC, 0x27, 0xF0, 0x9F, 0xC0, 0x7D, 0x02, 0xEF, 0x01, 0xCC, ++0x07, 0xF0, 0x1E, 0x40, 0x3C, 0x00, 0xF3, 0x00, 0xCC, 0x03, 0xB0, 0x0F, 0xC0, ++0x3C, 0x00, 0xF3, 0x01, 0xCC, 0x07, 0x30, 0x1F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x47, 0x40, 0x11, 0x00, 0x45, 0x04, 0xD0, ++0x11, 0x52, 0x04, 0x00, 0x0D, 0x00, 0x74, 0x10, 0xD0, 0x01, 0x40, 0x07, 0x01, ++0x1D, 0x04, 0x74, 0x10, 0xD0, 0x40, 0xC0, 0x06, 0x01, 0x1D, 0x81, 0x44, 0x04, ++0xD0, 0x11, 0x40, 0x74, 0x08, 0x51, 0x21, 0x44, 0x07, 0x10, 0x15, 0x42, 0x74, ++0x00, 0xD1, 0x00, 0x44, 0x07, 0x10, 0x19, 0x48, 0x07, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x11, 0xA0, 0x37, 0x00, 0xC1, 0x04, 0x14, 0x03, 0xD0, 0x0D, ++0x60, 0x30, 0x05, 0xCD, 0x14, 0x34, 0x03, 0xD0, 0x4C, 0x40, 0x33, 0x00, 0xC5, ++0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x24, 0x03, 0xD0, ++0x0C, 0x40, 0x32, 0x00, 0x81, 0x00, 0x04, 0x02, 0x50, 0x0C, 0x40, 0x32, 0x00, ++0xC5, 0x00, 0x44, 0x02, 0x14, 0x0C, 0x40, 0x45, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA8, 0x05, 0x00, 0x01, 0x40, 0x54, 0x00, 0xD0, 0x01, 0x60, ++0x04, 0x30, 0x1D, 0x00, 0x74, 0x00, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x20, ++0x74, 0x00, 0xD0, 0x01, 0x40, 0x04, 0x00, 0x1D, 0x00, 0x64, 0x80, 0xC0, 0x01, ++0x40, 0x36, 0x00, 0xD1, 0x00, 0x44, 0x43, 0xD0, 0xAD, 0x40, 0x36, 0x04, 0xC5, ++0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA0, 0x33, 0x00, 0xD3, 0x00, 0x5C, 0x03, 0xF0, 0x0D, 0xC0, 0x34, ++0x00, 0xDF, 0x80, 0x7C, 0x83, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, ++0x03, 0xF0, 0x0D, 0x40, 0x37, 0x00, 0xDF, 0x00, 0x6C, 0x03, 0xF0, 0x0D, 0x40, ++0x86, 0x04, 0xD3, 0x09, 0x4C, 0x25, 0xF0, 0x3D, 0xC0, 0x26, 0x00, 0xD7, 0x09, ++0x0D, 0x03, 0x30, 0x09, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x07, 0x88, 0x0D, 0x00, 0x3F, 0x00, 0xEC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, ++0x3F, 0x00, 0xF4, 0x00, 0xF1, 0x03, 0xC8, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, ++0xA0, 0x03, 0xC8, 0x0F, 0x00, 0x3F, 0x00, 0xDC, 0x00, 0xF1, 0x03, 0xC8, 0x19, ++0x00, 0xCF, 0x21, 0xBC, 0x01, 0x30, 0x16, 0xC2, 0x39, 0x02, 0xFB, 0x00, 0xFC, ++0x13, 0xF0, 0x0F, 0xC0, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x08, 0x35, 0x00, 0xDF, 0x05, 0x7C, 0x03, 0x32, 0x0D, 0xC2, 0x37, 0x00, 0xDF, ++0x00, 0x4C, 0x07, 0xF0, 0x0D, 0xC0, 0x77, 0x00, 0xDF, 0x01, 0x7C, 0x07, 0xF0, ++0x0D, 0xC0, 0x74, 0x00, 0xDF, 0x01, 0x4C, 0x03, 0x30, 0x0D, 0xC0, 0xB5, 0x00, ++0x93, 0x00, 0x4C, 0x0A, 0x70, 0x0D, 0xC2, 0xA4, 0x00, 0xD7, 0x00, 0x4C, 0x02, ++0xF0, 0x09, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0x04, 0x10, 0x1D, 0x01, 0x74, 0x00, 0x14, 0xB0, 0x40, 0x07, 0x00, 0x1D, 0x00, ++0x44, 0x04, 0xC1, 0xA1, 0x42, 0x07, 0x00, 0x1D, 0x01, 0x74, 0x84, 0xD0, 0xE1, ++0x40, 0x44, 0x00, 0x0D, 0x00, 0x44, 0x00, 0xB0, 0x00, 0x40, 0x34, 0x00, 0xD1, ++0x80, 0x44, 0x13, 0x10, 0x0D, 0x40, 0x34, 0x10, 0xDD, 0x0A, 0x44, 0x46, 0xD0, ++0x1D, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x30, ++0x00, 0xCD, 0x02, 0x34, 0x03, 0x10, 0x3C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x04, ++0x1B, 0xD0, 0x0C, 0x40, 0x32, 0x00, 0xCD, 0x10, 0x34, 0x03, 0xD0, 0x0D, 0x40, ++0x30, 0x00, 0xCD, 0x00, 0x04, 0x03, 0x50, 0x0C, 0x44, 0x30, 0x00, 0xC1, 0x00, ++0x04, 0x83, 0x14, 0x08, 0x40, 0x12, 0x00, 0xC4, 0x00, 0x04, 0x03, 0xD0, 0x1C, ++0x40, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x48, 0x00, ++0x2D, 0x09, 0xF4, 0x24, 0x10, 0x12, 0x40, 0x4B, 0x00, 0x2D, 0x00, 0x84, 0x24, ++0xD0, 0x12, 0x40, 0x4B, 0x00, 0x2D, 0x41, 0xB4, 0x0C, 0xD0, 0x12, 0x60, 0xC8, ++0x00, 0x2D, 0x01, 0xC4, 0x04, 0xD2, 0x32, 0x40, 0x70, 0x00, 0x61, 0x01, 0x05, ++0x07, 0x10, 0x1C, 0x40, 0x7A, 0x00, 0xED, 0x01, 0x84, 0x07, 0xD1, 0x1A, 0x60, ++0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x30, 0x00, 0xCF, ++0x00, 0x3C, 0x03, 0x30, 0x0C, 0xC3, 0x33, 0x02, 0xCF, 0x08, 0x0C, 0x03, 0xF0, ++0x0C, 0xC2, 0x32, 0x00, 0xCD, 0x00, 0x3C, 0x03, 0xF0, 0x0C, 0xC0, 0x30, 0x00, ++0xCF, 0x00, 0x0C, 0x03, 0x70, 0x0C, 0xC0, 0x31, 0x00, 0xC3, 0x04, 0x0C, 0x03, ++0x70, 0x0C, 0xC0, 0x32, 0x00, 0xD7, 0x00, 0x0D, 0x03, 0xF2, 0x8C, 0x51, 0x48, ++0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x0D, 0x00, 0x3F, 0x00, ++0xFC, 0x00, 0xF0, 0x03, 0xC8, 0x0F, 0x08, 0x3F, 0x04, 0xFC, 0x00, 0xF0, 0x03, ++0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, ++0x40, 0xBC, 0x00, 0xB0, 0x13, 0xC4, 0x3F, 0x02, 0xFF, 0x00, 0xFE, 0x03, 0xF2, ++0x0F, 0xC0, 0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0A, 0xC2, 0x0B, 0xE0, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x37, 0x00, 0xDF, 0x01, 0x0D, ++0x07, 0x34, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x01, 0x4C, 0x07, 0x3C, 0x0D, 0xC0, ++0x77, 0x00, 0xD7, 0x01, 0x4D, 0x87, 0x34, 0x1D, 0xC0, 0x75, 0x40, 0xD3, 0x00, ++0x7E, 0x03, 0xF0, 0x1D, 0xC0, 0x24, 0x00, 0xD3, 0x00, 0x4C, 0x03, 0xB8, 0x09, ++0xC0, 0x54, 0x00, 0xDB, 0x00, 0x4D, 0x02, 0xF0, 0x09, 0xC0, 0x41, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x90, 0x08, 0x00, 0x2D, 0x00, 0x84, 0x00, ++0x18, 0x02, 0x40, 0x0B, 0x00, 0x3D, 0x00, 0xD4, 0x00, 0x10, 0x02, 0x40, 0x0F, ++0x00, 0x31, 0x00, 0xC4, 0x00, 0x10, 0x02, 0x40, 0x0C, 0x00, 0x21, 0x00, 0x9C, ++0x80, 0xD0, 0x02, 0x40, 0x39, 0x00, 0xE1, 0x00, 0x84, 0x03, 0x10, 0x0E, 0x42, ++0x38, 0x00, 0xF1, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x4B, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xED, 0x01, 0xC4, 0x87, 0x12, ++0x1E, 0x60, 0x7B, 0x80, 0xE9, 0x01, 0x84, 0x07, 0x10, 0x1E, 0x42, 0x7B, 0x20, ++0xE5, 0x01, 0xA0, 0x07, 0x10, 0x1E, 0x40, 0x7B, 0x00, 0xE9, 0x01, 0x94, 0x07, ++0xD0, 0x1F, 0x40, 0x72, 0x08, 0xC1, 0x01, 0x04, 0x07, 0x10, 0x1C, 0x40, 0x70, ++0x00, 0xE1, 0x01, 0x84, 0x06, 0xD0, 0x1A, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x16, 0x20, 0x03, 0x00, 0x0D, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x03, 0x00, 0x0D, 0x00, 0x14, 0x00, 0x18, 0x00, 0x40, 0x03, 0x00, 0x01, ++0x00, 0x24, 0x00, 0x10, 0x00, 0x40, 0x02, 0x00, 0x09, 0x00, 0x14, 0x00, 0xD0, ++0x00, 0x40, 0x33, 0x40, 0xC1, 0x00, 0x05, 0x03, 0x14, 0x0C, 0x50, 0x30, 0x52, ++0x91, 0x48, 0x04, 0x02, 0xD0, 0x1C, 0x40, 0x5B, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x17, 0x28, 0x15, 0x00, 0x5F, 0x00, 0x4C, 0x01, 0x30, 0x05, 0xC0, ++0x17, 0x00, 0x5F, 0x00, 0x4C, 0x01, 0x30, 0x04, 0xC0, 0x17, 0x10, 0x57, 0x00, ++0x64, 0x01, 0x30, 0x05, 0xC0, 0x17, 0x00, 0x5B, 0x00, 0x5C, 0x01, 0xF0, 0x05, ++0xC0, 0x1E, 0x00, 0x73, 0x02, 0xCC, 0x09, 0x30, 0x07, 0xC0, 0x5C, 0x00, 0x53, ++0x01, 0x4C, 0x01, 0xF2, 0x05, 0xC1, 0x5F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x0D, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x23, 0xC0, 0x0F, ++0x00, 0x3F, 0x20, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xDC, ++0x00, 0xF0, 0x23, 0xC0, 0x0D, 0x20, 0x37, 0x02, 0xDC, 0x00, 0xF0, 0x03, 0xE2, ++0x41, 0x00, 0x0F, 0x10, 0x7C, 0x40, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x17, 0x02, ++0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x08, 0x25, 0x00, 0x9F, 0x05, 0x7C, 0x16, 0xF0, 0x09, 0xC0, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x0A, 0xF0, 0x29, 0xC0, 0x24, 0x01, 0x9F, 0x01, 0x5C, 0x02, ++0xF0, 0x19, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x20, 0x09, 0xC0, 0x27, ++0x20, 0x93, 0x20, 0x0C, 0x02, 0x34, 0x08, 0xC0, 0x24, 0x00, 0x9F, 0x05, 0x4C, ++0x06, 0xF0, 0x09, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x20, 0x26, 0x00, 0x9D, 0x02, 0x74, 0x02, 0x90, 0x49, 0x48, 0x27, 0x00, 0x9D, ++0x00, 0x74, 0x0A, 0xD9, 0x39, 0x40, 0x24, 0x00, 0x9D, 0x02, 0x74, 0x0A, 0xD0, ++0xD9, 0x40, 0xA7, 0x80, 0x9F, 0x12, 0x34, 0x02, 0xB0, 0x09, 0x40, 0xA7, 0x20, ++0x91, 0x82, 0x44, 0x0A, 0x30, 0x29, 0x40, 0xA4, 0x00, 0x9D, 0x02, 0x44, 0x06, ++0xD0, 0x08, 0xC0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, ++0x24, 0x00, 0xBD, 0x00, 0xF4, 0x02, 0xD0, 0x0B, 0x40, 0x2F, 0x00, 0xB5, 0x00, ++0xF4, 0x02, 0xD0, 0x0B, 0x60, 0x2C, 0x00, 0xBD, 0x08, 0xF6, 0x06, 0xD0, 0x0B, ++0x40, 0x6F, 0x10, 0xBD, 0x00, 0xF4, 0x02, 0x50, 0x1B, 0x42, 0x27, 0x04, 0x91, ++0x10, 0x64, 0x42, 0x00, 0x09, 0x41, 0x24, 0x84, 0x9D, 0x00, 0x64, 0x22, 0xD0, ++0x89, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x28, ++0x00, 0xAD, 0x01, 0xB4, 0x02, 0x91, 0x0A, 0x40, 0x2B, 0x00, 0xAD, 0x00, 0xB4, ++0x06, 0xD0, 0x0B, 0x42, 0x29, 0x00, 0xAD, 0x01, 0xB4, 0x06, 0xD0, 0x0A, 0x60, ++0x6B, 0x00, 0xA5, 0x00, 0xF4, 0x02, 0xD2, 0x0A, 0x60, 0x23, 0x41, 0x81, 0x04, ++0x24, 0x92, 0x90, 0x48, 0x40, 0x20, 0x01, 0x8D, 0x40, 0x24, 0x02, 0xD0, 0x09, ++0x40, 0x42, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x06, 0x00, ++0x0F, 0x0A, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x87, 0x12, 0x17, 0x0A, 0x7C, 0x28, ++0xD0, 0xA5, 0xD0, 0x84, 0x02, 0x1D, 0x0A, 0x5C, 0x28, 0xF0, 0xA0, 0xC0, 0x87, ++0x02, 0x1D, 0x00, 0x7C, 0x00, 0x60, 0x03, 0xC0, 0x07, 0x00, 0x13, 0x00, 0x65, ++0x00, 0x32, 0x01, 0xD0, 0x04, 0x00, 0x5F, 0x0A, 0x6C, 0x00, 0xF0, 0x01, 0xC0, ++0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x27, 0x00, 0x9F, ++0x00, 0x7C, 0x02, 0xB0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x26, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xB0, 0x08, 0xC0, 0x2F, 0x02, 0xBF, 0x08, 0xDC, 0x22, ++0x70, 0x8B, 0xC0, 0x2F, 0x02, 0xBF, 0x00, 0xDD, 0x02, 0xF0, 0x0B, 0xC0, 0x77, ++0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x27, 0x00, 0xB3, 0x00, ++0xCC, 0x02, 0xF0, 0x0B, 0xC0, 0x24, 0x00, 0xBF, 0x00, 0xCC, 0x02, 0xF0, 0x0A, ++0xC0, 0x2D, 0x02, 0xB7, 0x00, 0xFE, 0x02, 0xF0, 0x8B, 0xC0, 0x2F, 0x00, 0x9F, ++0x00, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0x34, 0x00, 0x9F, 0x00, 0x6D, 0x12, 0x30, ++0x49, 0xC1, 0x24, 0x01, 0xB3, 0x00, 0xCC, 0x03, 0xF0, 0x0B, 0xC0, 0x73, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x05, 0x00, 0x11, 0x04, 0x45, ++0x00, 0xD0, 0x01, 0x40, 0x04, 0x00, 0x1D, 0x00, 0x45, 0x50, 0x70, 0x41, 0x40, ++0x04, 0x01, 0x11, 0x10, 0x74, 0x40, 0xD1, 0x01, 0x40, 0x07, 0x05, 0x1D, 0x00, ++0x74, 0x00, 0xD0, 0x01, 0x40, 0x05, 0x00, 0x1D, 0x08, 0x44, 0x00, 0x10, 0x01, ++0x40, 0x0C, 0x12, 0x01, 0x10, 0x44, 0x00, 0xD0, 0x01, 0x40, 0x63, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x25, 0x40, 0x81, 0x14, 0x04, 0x02, ++0xD0, 0x08, 0x40, 0x20, 0x00, 0x9D, 0x00, 0x04, 0x12, 0xD0, 0x48, 0x41, 0x21, ++0x21, 0x85, 0x04, 0x30, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x01, 0xAD, 0x00, 0xB4, ++0x03, 0xD0, 0x0B, 0x40, 0x6A, 0x02, 0xAD, 0x01, 0x84, 0x26, 0x10, 0x1A, 0x40, ++0x68, 0x00, 0x99, 0x04, 0x05, 0x02, 0xD0, 0x0C, 0x40, 0x4B, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0xD1, 0x00, 0x44, 0x02, 0xD0, ++0x09, 0x40, 0x24, 0x80, 0x9D, 0x40, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x00, ++0x91, 0x80, 0x74, 0x02, 0xD2, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0xF4, 0x82, ++0xD0, 0x0B, 0x40, 0x2F, 0x00, 0xBD, 0x00, 0xC4, 0x02, 0x10, 0x0B, 0x40, 0x2C, ++0x10, 0x99, 0x01, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0x00, 0x25, 0x00, 0x93, 0x00, 0x48, 0x02, 0xF0, 0x08, ++0xC0, 0x24, 0x00, 0x9F, 0x20, 0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x25, 0x00, 0x95, ++0x00, 0x74, 0x02, 0xE0, 0x09, 0x80, 0x27, 0x00, 0x9F, 0x40, 0x7E, 0x02, 0xF0, ++0x09, 0xC0, 0xA6, 0x02, 0x9F, 0x03, 0x4C, 0x2A, 0x34, 0xB9, 0xC0, 0xA4, 0x00, ++0x8B, 0xA0, 0x4C, 0x82, 0xF0, 0x09, 0xC0, 0x17, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x08, 0x24, 0x00, 0x9F, 0x80, 0x7C, 0x02, 0xF0, 0x09, 0xD0, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x70, 0x09, 0xC8, 0x27, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x25, 0x00, 0x9F, 0x03, 0x5C, 0x06, 0xF0, 0x19, 0xD0, 0x27, 0x40, 0x97, ++0x20, 0x7C, 0x12, 0xF0, 0x09, 0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x7E, 0x00, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x13, 0x10, 0x7C, 0x00, 0xF2, 0x81, 0xD1, 0x06, 0x00, 0x1F, 0x00, 0x7C, ++0x60, 0xF2, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, ++0x07, 0x00, 0x03, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x1F, 0x00, ++0x4D, 0x04, 0xF0, 0x01, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x20, 0x10, 0x00, 0x7D, 0x00, 0x76, 0x45, 0xD0, 0x07, 0xC0, 0x15, 0x20, ++0x65, 0x00, 0xF4, 0x09, 0xD0, 0x27, 0xD0, 0x16, 0x00, 0x77, 0x00, 0xF4, 0x09, ++0xD2, 0x07, 0x40, 0x1F, 0x00, 0x5D, 0x00, 0x74, 0x01, 0x14, 0x04, 0xC0, 0x15, ++0x00, 0x51, 0x01, 0x74, 0x01, 0xD0, 0x15, 0x40, 0x57, 0x10, 0x7D, 0x41, 0xC4, ++0x01, 0xD0, 0x05, 0x40, 0x43, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA0, 0x32, 0x00, 0xDD, 0x40, 0x34, 0x07, 0xD0, 0x04, 0x40, 0x31, 0x80, 0x49, ++0x00, 0x34, 0x4B, 0xD0, 0x3D, 0x40, 0x36, 0x30, 0xCD, 0x00, 0x34, 0x07, 0xD8, ++0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x31, 0x00, ++0xC1, 0x21, 0x34, 0x03, 0xD0, 0x1C, 0x40, 0x73, 0x00, 0xCD, 0x00, 0x04, 0x07, ++0xD0, 0x0C, 0x40, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, ++0x38, 0x00, 0x6D, 0x00, 0xB4, 0x03, 0xD0, 0x0A, 0x40, 0x79, 0x02, 0x6D, 0x10, ++0xB6, 0x03, 0xD0, 0x0E, 0x58, 0x2A, 0x00, 0x6D, 0x00, 0xB4, 0x01, 0xD9, 0x02, ++0x40, 0x1B, 0x00, 0xAD, 0x00, 0xB4, 0x07, 0x10, 0x06, 0x40, 0x71, 0x40, 0xE1, ++0x10, 0xB4, 0x02, 0xD0, 0x0E, 0x41, 0x3B, 0x04, 0xED, 0x02, 0x84, 0x43, 0xD0, ++0x0A, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x78, ++0x00, 0xAF, 0x01, 0xB4, 0x07, 0xD0, 0x16, 0xC0, 0x7D, 0x00, 0x6B, 0x01, 0xBC, ++0x06, 0xF0, 0x16, 0xD0, 0x7A, 0x00, 0xAF, 0x01, 0xB4, 0x06, 0xF0, 0x1E, 0xC0, ++0x6B, 0x00, 0x6F, 0x01, 0xB8, 0x07, 0x30, 0x1A, 0xC0, 0x59, 0x00, 0x63, 0x01, ++0xBC, 0x05, 0xF0, 0x16, 0xC0, 0x5B, 0x00, 0xEF, 0x01, 0x8C, 0x07, 0xF0, 0x1E, ++0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, ++0x1F, 0x00, 0x7C, 0x03, 0xF0, 0x01, 0xC0, 0x75, 0x20, 0x57, 0x00, 0x7C, 0x00, ++0xF0, 0x05, 0xD0, 0x27, 0x00, 0x17, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x1F, 0x00, 0x7C, 0x03, 0xF0, 0x01, 0xC2, 0x15, 0x00, 0x5F, 0x00, 0x7C, ++0x00, 0xF8, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, ++0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x7D, 0x00, 0xFF, ++0x01, 0xBC, 0x07, 0xF8, 0x87, 0xC0, 0x7C, 0x00, 0xB3, 0x89, 0xCC, 0x05, 0xA0, ++0x1B, 0xC0, 0x7F, 0x20, 0xF3, 0x01, 0xDC, 0x07, 0x30, 0x1F, 0xC0, 0x7C, 0x00, ++0xF3, 0x01, 0xCC, 0x06, 0xF2, 0x1F, 0xC0, 0x7F, 0x00, 0xBF, 0x01, 0xCC, 0x07, ++0xF0, 0x1B, 0xC0, 0x6C, 0x00, 0xF3, 0x01, 0xFC, 0x05, 0x30, 0x1F, 0xC0, 0x1B, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x39, 0x00, 0x6D, 0x00, ++0x9C, 0x03, 0x18, 0x0A, 0x40, 0x38, 0x00, 0xA1, 0x00, 0xC4, 0x03, 0x11, 0x0A, ++0x40, 0x2B, 0x00, 0x71, 0x00, 0xC4, 0x02, 0x10, 0x02, 0x40, 0x1C, 0x00, 0xA1, ++0x00, 0x84, 0x0A, 0xD0, 0x06, 0x40, 0x3B, 0x00, 0xAD, 0x00, 0x84, 0x02, 0xD0, ++0x0A, 0x40, 0x28, 0x12, 0xE1, 0x00, 0xB4, 0x00, 0xB0, 0x0E, 0x40, 0x57, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0xAD, 0x00, 0xB4, ++0x03, 0x50, 0x87, 0x40, 0x3C, 0x00, 0xB1, 0x00, 0x84, 0x20, 0x10, 0x02, 0x40, ++0xBF, 0x00, 0xA9, 0x00, 0x84, 0x01, 0x10, 0x0F, 0x40, 0x2A, 0x00, 0x79, 0x02, ++0x84, 0x02, 0xD0, 0x0A, 0x40, 0x1B, 0x00, 0x0D, 0x00, 0x84, 0x01, 0xD0, 0x80, ++0x40, 0x00, 0x00, 0xA1, 0x00, 0xF4, 0x40, 0x10, 0x0E, 0x40, 0x03, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0xF1, 0x00, 0x1D, 0x02, 0x34, 0x43, ++0x10, 0x00, 0x41, 0xB0, 0x04, 0x81, 0x04, 0x04, 0x34, 0x91, 0x38, 0x40, 0x23, ++0x00, 0x09, 0x0D, 0x04, 0x34, 0x10, 0x00, 0x41, 0x42, 0x43, 0x09, 0x20, 0x04, ++0x06, 0xD0, 0x10, 0x40, 0x13, 0x00, 0x0D, 0x12, 0x04, 0x00, 0xD0, 0x00, 0x40, ++0x80, 0x00, 0x01, 0x20, 0x34, 0x84, 0x90, 0x0C, 0x40, 0x0B, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0xB5, 0x00, 0xDF, 0x05, 0x7C, 0x07, 0x50, ++0x24, 0xC0, 0x38, 0x00, 0x93, 0x02, 0x44, 0x0B, 0xB0, 0x05, 0xC0, 0x73, 0x00, ++0xD9, 0x02, 0x44, 0x0B, 0x10, 0x2C, 0xC0, 0xB6, 0x00, 0xCB, 0x00, 0x0C, 0x69, ++0xF1, 0x2D, 0x41, 0x67, 0x00, 0xDF, 0x03, 0x4D, 0x07, 0xF0, 0xBD, 0xD0, 0x74, ++0x40, 0xD3, 0x00, 0x3C, 0x05, 0x30, 0x0D, 0xC0, 0x57, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0x00, 0x37, 0x06, 0x9F, 0x10, 0x5C, 0x23, 0x70, 0x1D, ++0xC0, 0x77, 0x00, 0x9F, 0x03, 0x7C, 0x02, 0x71, 0x85, 0xC0, 0x37, 0x22, 0x97, ++0x02, 0x7C, 0x01, 0xF0, 0x3D, 0xC0, 0x25, 0x00, 0x97, 0x08, 0x7C, 0x01, 0xF0, ++0x05, 0xC1, 0x63, 0x00, 0xDF, 0x81, 0x7C, 0x06, 0xF0, 0x1D, 0xC2, 0x77, 0x14, ++0xDF, 0x03, 0x7C, 0x01, 0xF0, 0x8D, 0xC2, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0x7F, 0x00, 0xCC, 0x0F, 0xF0, 0x07, 0xC0, ++0x3E, 0x00, 0xB3, 0x00, 0xFC, 0x17, 0x32, 0x03, 0xC5, 0x2C, 0x00, 0x73, 0x00, ++0xCE, 0x02, 0x30, 0x13, 0xC0, 0x1C, 0x01, 0x72, 0x00, 0xCC, 0x01, 0x30, 0x0B, ++0xC0, 0x0F, 0x02, 0x73, 0x00, 0xFC, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0xFF, ++0x00, 0xCC, 0x01, 0x30, 0x0F, 0xC0, 0x03, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x81, 0x20, 0x36, 0x00, 0x1D, 0x00, 0x44, 0x03, 0xD0, 0x05, 0x40, 0x34, ++0x20, 0x91, 0x09, 0x74, 0x04, 0x10, 0x10, 0x41, 0x24, 0x00, 0x11, 0x02, 0x44, ++0x00, 0x10, 0x11, 0x40, 0xC4, 0x01, 0x11, 0x00, 0x44, 0x09, 0x10, 0x01, 0xC0, ++0x05, 0x00, 0x51, 0x20, 0x74, 0x00, 0xD0, 0x05, 0x40, 0x17, 0x10, 0xDD, 0x00, ++0x44, 0x05, 0x10, 0x0D, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0xA0, 0x36, 0x00, 0xDD, 0x04, 0x44, 0x02, 0xD8, 0x85, 0x40, 0x36, 0x00, ++0x91, 0x02, 0x14, 0x01, 0x18, 0x15, 0x40, 0x34, 0x81, 0xC9, 0x06, 0x04, 0x03, ++0x10, 0x6D, 0x40, 0x32, 0x80, 0xD5, 0x00, 0x44, 0x00, 0x10, 0x0D, 0x40, 0x27, ++0x00, 0x91, 0x00, 0x74, 0x03, 0xD0, 0x09, 0x40, 0x27, 0x00, 0xCD, 0x86, 0x44, ++0x04, 0x10, 0x1D, 0x40, 0x07, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0x30, 0x00, 0x8D, 0x00, 0x05, 0x02, 0xD0, 0x0C, 0x40, 0x36, 0x00, 0x81, ++0x00, 0x34, 0x02, 0x14, 0x0D, 0x50, 0x34, 0x00, 0x80, 0x00, 0x05, 0x02, 0x14, ++0x0D, 0x60, 0x22, 0x40, 0x95, 0xA0, 0x04, 0x00, 0x10, 0x04, 0x40, 0x23, 0x40, ++0x81, 0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x00, 0xCD, 0x00, 0x04, 0x04, ++0x14, 0x0C, 0x40, 0x43, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0x36, 0x00, 0x5F, 0x00, 0x4C, 0x03, 0xF0, 0x05, 0xC0, 0x36, 0x00, 0x93, 0x00, ++0x7C, 0x01, 0x30, 0x01, 0xC0, 0x24, 0x10, 0x5B, 0x80, 0x46, 0x81, 0x30, 0x01, ++0xC0, 0x16, 0x00, 0x57, 0x00, 0x4C, 0x00, 0x30, 0x09, 0xC0, 0x07, 0x00, 0x13, ++0x00, 0x7C, 0x01, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0xDF, 0x00, 0x4D, 0x00, 0x30, ++0x0D, 0xC0, 0x03, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x3F, ++0x00, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x06, 0xC0, 0x39, 0x00, 0xAF, 0x80, 0xFC, ++0x00, 0xF0, 0x0B, 0xC0, 0x2B, 0x80, 0x3F, 0x00, 0xFE, 0x00, 0xF0, 0x02, 0xC0, ++0x0D, 0x00, 0x2B, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0D, 0x00, 0x3F, 0x00, ++0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0xBC, 0x00, 0xF0, 0x0F, ++0xC0, 0x17, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x2F, 0x00, ++0xFF, 0x01, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x5D, 0x00, 0x6F, 0x01, 0xCC, 0x06, ++0xF1, 0x0F, 0xC0, 0x7C, 0x00, 0x33, 0x03, 0xEC, 0x24, 0xB2, 0xCF, 0xC8, 0x3C, ++0x21, 0xFB, 0x84, 0xDC, 0x87, 0xB0, 0x0F, 0x40, 0x5C, 0x02, 0x3F, 0x08, 0xAC, ++0x85, 0xB0, 0x0F, 0xC2, 0x5F, 0x00, 0x37, 0x80, 0xCD, 0x06, 0x90, 0x0B, 0x80, ++0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x00, 0xDD, ++0x01, 0x74, 0x00, 0xD0, 0x3D, 0x42, 0x60, 0x00, 0x1D, 0x01, 0x44, 0x06, 0xD2, ++0x1D, 0x40, 0x7C, 0x00, 0x11, 0x20, 0x44, 0x10, 0x10, 0xAF, 0x40, 0x7C, 0x02, ++0xF1, 0x02, 0x44, 0x07, 0x14, 0x6D, 0x40, 0x04, 0x01, 0x9D, 0x04, 0x54, 0x85, ++0x10, 0x9F, 0x00, 0x47, 0x40, 0x93, 0x8B, 0x44, 0x52, 0x10, 0x09, 0x40, 0x0D, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x03, 0x00, 0xCD, 0x00, ++0x34, 0x00, 0xD0, 0x2C, 0x40, 0x31, 0x00, 0x4D, 0x00, 0x04, 0x02, 0xD0, 0x0C, ++0x60, 0x30, 0x20, 0x10, 0x04, 0x64, 0x10, 0x90, 0x4C, 0x48, 0x30, 0x10, 0xC9, ++0x08, 0x34, 0x03, 0x02, 0x2C, 0x45, 0x12, 0x01, 0x0D, 0x00, 0x24, 0x01, 0xD0, ++0x0C, 0x42, 0x33, 0x10, 0x09, 0x20, 0x04, 0x03, 0x10, 0x00, 0x40, 0x4D, 0x80, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x64, 0x00, 0xDD, 0x00, 0x74, ++0x04, 0xC0, 0x0D, 0x60, 0x24, 0x00, 0x1D, 0x04, 0x45, 0x02, 0xD0, 0x0D, 0x40, ++0x34, 0x08, 0x11, 0x00, 0x64, 0x44, 0x10, 0x0D, 0x48, 0x34, 0x80, 0xD1, 0x00, ++0x64, 0x03, 0x50, 0x0D, 0x40, 0x06, 0x04, 0x8D, 0x11, 0x74, 0x85, 0x54, 0x0D, ++0x42, 0x07, 0x00, 0x55, 0x08, 0x44, 0x02, 0x10, 0x11, 0x41, 0x0D, 0x20, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x66, 0x00, 0xDF, 0x00, 0x78, 0x4E, ++0xE0, 0x0D, 0xC0, 0x25, 0x10, 0x4F, 0x07, 0x4C, 0x22, 0xF0, 0x9D, 0x40, 0x34, ++0x40, 0x13, 0x0D, 0x2C, 0x0C, 0xB2, 0x0D, 0xD0, 0x34, 0x10, 0xDB, 0x00, 0x74, ++0x03, 0x30, 0x0D, 0x50, 0x06, 0x28, 0x9E, 0x01, 0x6C, 0x14, 0xF0, 0x0D, 0xC0, ++0x13, 0x00, 0x1B, 0x03, 0x4C, 0x06, 0x30, 0x19, 0xC0, 0x21, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x2D, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, ++0x0E, 0xC0, 0x2F, 0x00, 0x7F, 0x00, 0xFC, 0x06, 0xF0, 0x0E, 0xC0, 0x3F, 0x00, ++0xFF, 0x00, 0xDC, 0x02, 0x70, 0x0E, 0xC0, 0x3F, 0x00, 0xEF, 0x00, 0xDC, 0x03, ++0xB0, 0x0F, 0xC2, 0x0D, 0x10, 0xBD, 0x00, 0xDC, 0x01, 0xB4, 0x0F, 0xC0, 0x8F, ++0x50, 0x6B, 0x00, 0xFC, 0x26, 0xF4, 0x0A, 0xC0, 0x1F, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x08, 0x85, 0x02, 0xDF, 0x00, 0x7C, 0x40, 0x30, 0x0D, ++0xC0, 0x37, 0x00, 0x57, 0x02, 0x4C, 0x42, 0xF0, 0x0D, 0xC0, 0x37, 0x02, 0xDF, ++0x00, 0x7C, 0x0A, 0xF0, 0x0D, 0xC4, 0x34, 0x0A, 0xDF, 0x00, 0x5C, 0x23, 0x70, ++0x0D, 0xC1, 0x15, 0x00, 0x13, 0x02, 0x4C, 0x00, 0x50, 0x0D, 0xC9, 0x36, 0x08, ++0x17, 0x12, 0x4D, 0x03, 0xF0, 0x09, 0x82, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0xA0, 0x24, 0x00, 0xDD, 0x60, 0x70, 0x18, 0x10, 0x0F, 0x40, ++0x27, 0x00, 0x51, 0x05, 0x44, 0x4E, 0xD0, 0x0D, 0x40, 0x33, 0x00, 0xCD, 0x00, ++0x74, 0x02, 0xD0, 0xAF, 0x40, 0x38, 0x02, 0xFD, 0x00, 0x34, 0x2B, 0xB0, 0x2E, ++0x40, 0x04, 0x40, 0x11, 0x08, 0x2C, 0x03, 0x10, 0x2F, 0x48, 0x04, 0x02, 0x51, ++0x00, 0x44, 0x13, 0xD0, 0x09, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x20, 0xC0, 0x04, 0xCD, 0x00, 0x34, 0x0E, 0x50, 0x0C, 0x40, 0x13, ++0x00, 0x05, 0x06, 0x05, 0x0E, 0xD0, 0x08, 0x40, 0xF3, 0x04, 0x0D, 0x00, 0x34, ++0x00, 0xD0, 0x0C, 0x60, 0x70, 0x00, 0xCD, 0x07, 0x34, 0x03, 0x10, 0x0C, 0x48, ++0x11, 0x80, 0x04, 0x00, 0x04, 0x00, 0x40, 0x3C, 0x40, 0x90, 0x00, 0x49, 0x02, ++0x44, 0x13, 0xD1, 0x50, 0x44, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x00, 0x58, 0x00, 0xED, 0x01, 0xB4, 0x01, 0x50, 0x1E, 0x40, 0x6B, 0x00, ++0x31, 0x01, 0x84, 0x06, 0xD0, 0x1A, 0x40, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x07, ++0xD0, 0x1C, 0x40, 0x78, 0x00, 0xED, 0x31, 0xB4, 0x07, 0x90, 0x1E, 0x40, 0x48, ++0x80, 0xE5, 0x01, 0xE4, 0x04, 0x10, 0x9C, 0x40, 0x4C, 0x01, 0xC9, 0x01, 0x84, ++0x16, 0xD8, 0x9A, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x1A, 0x90, 0x02, 0xCF, 0x00, 0x7C, 0x23, 0x70, 0x0C, 0xC0, 0x33, 0x00, 0x07, ++0x04, 0x0C, 0x02, 0xF0, 0x4C, 0xC0, 0x33, 0x01, 0xCD, 0x00, 0x3C, 0x02, 0xF0, ++0x8C, 0x40, 0x30, 0x02, 0xCF, 0x00, 0x3C, 0x03, 0x30, 0xDD, 0xC0, 0x15, 0x2A, ++0x57, 0x24, 0x0C, 0x61, 0x70, 0x8C, 0xC9, 0x22, 0x90, 0x89, 0x12, 0x0C, 0x03, ++0xF0, 0x00, 0xC1, 0x4B, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, ++0x3D, 0x08, 0xFF, 0x00, 0xFC, 0x13, 0xB0, 0x0F, 0xC1, 0x2F, 0x00, 0x3F, 0x00, ++0xFC, 0x22, 0xF0, 0x0F, 0xC0, 0x77, 0x00, 0xDF, 0x08, 0xFC, 0x23, 0xF0, 0x2D, ++0x52, 0x3F, 0x20, 0xDF, 0x00, 0x3C, 0x03, 0xF4, 0x0D, 0xC0, 0x07, 0x20, 0xDB, ++0x00, 0x7C, 0x81, 0xF0, 0x8F, 0xC2, 0x0B, 0x81, 0xF7, 0x00, 0xF0, 0x12, 0xF0, ++0x03, 0xC2, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, ++0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0x1F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC0, 0x37, 0x00, 0x1F, 0x00, 0x6C, 0x01, 0xF0, 0x0D, 0xC0, ++0xB7, 0x00, 0xDF, 0x08, 0x3C, 0x03, 0x31, 0x1D, 0xC8, 0x07, 0x10, 0x9F, 0x00, ++0x4F, 0x00, 0xF0, 0x4D, 0xC8, 0x10, 0x08, 0x9B, 0x00, 0x4D, 0x83, 0x30, 0x01, ++0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x39, 0x00, ++0xED, 0x00, 0xB4, 0x03, 0xD3, 0x4E, 0x40, 0x2B, 0x00, 0x2D, 0x00, 0x9C, 0x02, ++0xD0, 0x0A, 0x60, 0xBB, 0x10, 0xFC, 0x00, 0x84, 0x03, 0xD0, 0x4E, 0x40, 0xBB, ++0x04, 0xED, 0x0C, 0xB4, 0x03, 0x40, 0x2E, 0x40, 0x0B, 0x00, 0xED, 0x20, 0x84, ++0x00, 0xD0, 0xAE, 0x40, 0x08, 0x00, 0xE7, 0x00, 0xC4, 0x83, 0x12, 0x0F, 0x40, ++0x4C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x59, 0x18, 0xE5, ++0x01, 0xB4, 0x07, 0x50, 0x5E, 0x40, 0x7B, 0x00, 0x2D, 0x01, 0xB4, 0x06, 0x50, ++0x1E, 0x40, 0x7B, 0x01, 0xED, 0x11, 0x84, 0x07, 0xD0, 0xDE, 0x40, 0x7B, 0x01, ++0xED, 0x81, 0xB4, 0x07, 0x00, 0x4E, 0x40, 0x5B, 0x20, 0xED, 0x01, 0x94, 0x04, ++0xD1, 0x5C, 0x50, 0x69, 0x00, 0x85, 0x01, 0x94, 0x0F, 0x10, 0x16, 0x40, 0x12, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0xB3, 0x80, 0xCD, 0x40, ++0x34, 0x27, 0xD0, 0x0C, 0x40, 0x23, 0x11, 0x8D, 0x03, 0x14, 0x07, 0xD0, 0x0C, ++0x40, 0x33, 0x00, 0xCD, 0x01, 0x04, 0x47, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, ++0x00, 0x34, 0x83, 0x00, 0x0C, 0x44, 0xA3, 0x02, 0xDD, 0x02, 0x04, 0x05, 0xD0, ++0x0C, 0x44, 0x01, 0x00, 0xC5, 0x07, 0x14, 0x87, 0x10, 0x6C, 0x40, 0x5A, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x20, 0x1D, 0x04, 0x5F, 0x00, 0xFC, ++0x09, 0xF0, 0x05, 0xC0, 0xDF, 0x01, 0x7F, 0x44, 0x74, 0x45, 0xF8, 0x05, 0xC0, ++0x17, 0x00, 0x7F, 0x02, 0xCD, 0x95, 0xF0, 0x05, 0x40, 0x17, 0x00, 0x5F, 0x80, ++0x3C, 0x01, 0x31, 0x05, 0xC0, 0x5F, 0x00, 0x7F, 0x02, 0x8C, 0xBD, 0xF1, 0x05, ++0xC0, 0x1D, 0x00, 0x67, 0x07, 0x5C, 0x01, 0x36, 0x27, 0xC4, 0x5E, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x05, 0x04, 0x1F, 0x00, 0x7C, 0x80, ++0xF0, 0x01, 0xC0, 0x07, 0x08, 0x1F, 0x10, 0x70, 0x00, 0xF9, 0x01, 0xC4, 0x07, ++0x00, 0x1F, 0x04, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x42, 0x7C, ++0x08, 0xF4, 0x01, 0xC0, 0x07, 0x01, 0x1D, 0x82, 0x7C, 0x00, 0xF0, 0x01, 0xA0, ++0x86, 0x00, 0x16, 0x00, 0x68, 0x08, 0xF2, 0x01, 0xD0, 0x49, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x65, 0x01, 0x97, 0x00, 0x7C, 0x4E, 0xF8, ++0x09, 0xC0, 0x27, 0x00, 0x93, 0x82, 0x7C, 0x02, 0xF0, 0x09, 0xC8, 0x27, 0x89, ++0x93, 0x80, 0x7C, 0x02, 0x30, 0x19, 0xC0, 0x64, 0x00, 0x9F, 0x00, 0x7C, 0x16, ++0x30, 0x08, 0xC0, 0x24, 0x00, 0x9F, 0x39, 0x4C, 0x02, 0x34, 0x29, 0xD8, 0x24, ++0x40, 0x91, 0x09, 0x4C, 0x0E, 0x34, 0x08, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x20, 0x66, 0x01, 0x9D, 0x00, 0x74, 0x0E, 0xD0, 0x09, ++0x60, 0x23, 0x20, 0x91, 0x03, 0x76, 0x06, 0xD0, 0x09, 0x40, 0xEB, 0x81, 0x8B, ++0x00, 0x6C, 0x02, 0x50, 0x19, 0xD0, 0x64, 0x12, 0x9D, 0x02, 0x74, 0x02, 0xB0, ++0x09, 0xC0, 0x26, 0x00, 0x9D, 0x43, 0x45, 0x2E, 0x10, 0x38, 0x48, 0xA0, 0x11, ++0x91, 0x01, 0x44, 0x02, 0x12, 0x29, 0x40, 0x05, 0x80, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x24, 0x18, 0x9D, 0x00, 0x54, 0x0A, 0xD0, 0x09, 0x40, ++0x27, 0x00, 0x91, 0x10, 0x74, 0x0E, 0xD1, 0x09, 0x48, 0x25, 0x80, 0x91, 0x00, ++0x14, 0x02, 0x10, 0x88, 0x40, 0x24, 0x00, 0x9D, 0x02, 0x54, 0x0A, 0x90, 0x09, ++0x44, 0x24, 0x00, 0x9D, 0x02, 0x44, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x95, ++0x02, 0x25, 0x02, 0x10, 0x49, 0x60, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x22, 0x20, 0x05, 0x8D, 0x00, 0x34, 0x52, 0xD0, 0x08, 0x40, 0xA7, ++0x08, 0x81, 0x00, 0x36, 0x02, 0xDA, 0x08, 0x40, 0x23, 0x00, 0x91, 0x08, 0x04, ++0x22, 0x10, 0x8C, 0x60, 0x22, 0x80, 0x8D, 0x24, 0x34, 0x02, 0x94, 0x58, 0x40, ++0x22, 0x00, 0x8D, 0x0C, 0x44, 0x03, 0x10, 0x0C, 0x40, 0x24, 0x00, 0x85, 0x00, ++0x24, 0x22, 0x10, 0x48, 0x40, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xB8, 0x06, 0x11, 0x1F, 0x00, 0x5C, 0x10, 0xD0, 0x41, 0x41, 0x07, 0x40, ++0x13, 0x00, 0x76, 0x00, 0xF0, 0x01, 0xC0, 0x47, 0x40, 0x11, 0x02, 0x54, 0x08, ++0x34, 0x61, 0xC1, 0x14, 0x15, 0x1F, 0x8A, 0x7C, 0x00, 0xB4, 0xA1, 0xC4, 0x84, ++0x02, 0x0F, 0x02, 0x4C, 0x00, 0x30, 0x41, 0xC1, 0x04, 0x00, 0x15, 0x14, 0x6C, ++0x09, 0x30, 0xA5, 0xC0, 0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB8, 0x2F, 0x05, 0x9F, 0x00, 0xFC, 0x52, 0xF0, 0x09, 0xC0, 0x6F, 0x20, 0xBF, ++0x00, 0xFC, 0x02, 0xF0, 0x2B, 0xC0, 0xA7, 0x00, 0xBF, 0x04, 0xFC, 0x12, 0xF0, ++0x49, 0x42, 0x25, 0x00, 0x9F, 0x08, 0x7C, 0x02, 0xF4, 0x89, 0xC0, 0x2D, 0x00, ++0xBF, 0x0C, 0xFC, 0x02, 0xF0, 0x09, 0xC0, 0x3F, 0x00, 0xBB, 0x00, 0xDC, 0x12, ++0xF0, 0x8B, 0xC0, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA8, ++0x2F, 0x01, 0x9F, 0x00, 0xFC, 0x32, 0xB0, 0x09, 0xC0, 0xA7, 0x20, 0xBF, 0x00, ++0xCD, 0x02, 0xF0, 0x49, 0xC5, 0x6F, 0x00, 0x9B, 0x80, 0x6E, 0x02, 0x79, 0x8B, ++0xC0, 0x2F, 0x01, 0xBB, 0x14, 0xAC, 0x82, 0x30, 0x0B, 0xCC, 0x21, 0x00, 0xBF, ++0x28, 0xCC, 0x82, 0x31, 0x4B, 0xC1, 0x2E, 0x68, 0xA3, 0x00, 0xBC, 0x02, 0xF0, ++0x0F, 0xC0, 0x77, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, ++0x05, 0x1D, 0x00, 0x70, 0x31, 0x14, 0x21, 0x40, 0x47, 0x00, 0x1D, 0x00, 0x44, ++0x00, 0xD0, 0x01, 0x00, 0x07, 0x00, 0x5A, 0x30, 0x44, 0xC0, 0xD8, 0x81, 0x40, ++0x07, 0x00, 0x11, 0x04, 0x51, 0x00, 0x10, 0x01, 0xC0, 0x05, 0x04, 0x5D, 0x08, ++0x4C, 0x00, 0x11, 0x01, 0x40, 0x07, 0x30, 0x11, 0x00, 0x64, 0x80, 0xD0, 0x01, ++0x40, 0x63, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x03, ++0x8D, 0x00, 0x34, 0x12, 0x10, 0x88, 0x40, 0x23, 0x00, 0x8D, 0x80, 0x04, 0x82, ++0xD2, 0x08, 0x0A, 0xA3, 0x00, 0x89, 0x04, 0x04, 0x02, 0x50, 0x08, 0x40, 0x23, ++0x02, 0x89, 0x14, 0x14, 0x02, 0x14, 0x08, 0x40, 0x21, 0x00, 0x8D, 0x00, 0x05, ++0x02, 0x18, 0x08, 0x48, 0x27, 0x20, 0x85, 0x00, 0x36, 0x02, 0xD0, 0x08, 0x40, ++0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0xA5, 0x00, 0x9D, ++0x00, 0x74, 0x12, 0x10, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x10, 0x44, 0x02, 0xD0, ++0x09, 0x48, 0x26, 0x20, 0x89, 0x00, 0x44, 0x02, 0xD8, 0x09, 0x40, 0x27, 0x00, ++0x91, 0x00, 0x44, 0x02, 0xD0, 0x09, 0x68, 0x25, 0x10, 0x9D, 0x04, 0x46, 0x02, ++0x99, 0x0D, 0x40, 0x27, 0x00, 0xD5, 0x00, 0x64, 0x22, 0xD0, 0x09, 0x41, 0x63, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x65, 0x00, 0x9D, 0x00, ++0x7C, 0x06, 0x30, 0x09, 0xC0, 0x2F, 0x06, 0x9F, 0x00, 0x4C, 0x02, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x9B, 0x02, 0x65, 0x42, 0x72, 0x09, 0xC2, 0x27, 0x00, 0x9B, ++0x00, 0x54, 0x02, 0x30, 0x09, 0xC0, 0x25, 0x33, 0x9F, 0x21, 0x4C, 0x46, 0x30, ++0x09, 0xC0, 0x22, 0x00, 0x95, 0xA7, 0x7E, 0x82, 0xE0, 0x39, 0xC0, 0x17, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x25, 0x25, 0x9F, 0x80, 0x3C, ++0x06, 0x70, 0x09, 0xE2, 0x27, 0x00, 0x9F, 0x10, 0x7C, 0x26, 0xF0, 0x59, 0xC0, ++0x27, 0x0C, 0x97, 0x02, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x50, ++0x5C, 0x02, 0x32, 0x09, 0xE8, 0x27, 0x10, 0x8F, 0x01, 0x5C, 0x0A, 0x74, 0x09, ++0xC1, 0xA6, 0x00, 0x9B, 0x05, 0x7E, 0x02, 0xF0, 0x59, 0xC0, 0x5B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x05, 0x00, 0x1F, 0x00, 0x6C, 0x40, ++0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x80, 0xB0, 0x01, 0xC0, 0x03, ++0x00, 0x17, 0x02, 0x7C, 0x08, 0xF0, 0x01, 0xC2, 0x00, 0x01, 0x1F, 0x00, 0x4C, ++0x00, 0xB0, 0x81, 0xC1, 0x07, 0x40, 0x17, 0x22, 0x5C, 0x10, 0xF0, 0x01, 0xC0, ++0x07, 0x00, 0x13, 0x02, 0x4C, 0x40, 0x30, 0x01, 0x82, 0x53, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x9C, 0x00, 0x5D, 0x40, 0xF4, 0x05, 0xD8, ++0x05, 0xC0, 0x15, 0x20, 0x6C, 0x00, 0xF4, 0x49, 0x10, 0x05, 0x40, 0x9F, 0x80, ++0x5B, 0x00, 0x76, 0x01, 0xD0, 0x87, 0x40, 0x9C, 0x00, 0x7D, 0x02, 0x84, 0x01, ++0xF4, 0x27, 0xC0, 0x15, 0x00, 0x71, 0x00, 0x84, 0x89, 0x10, 0x77, 0x40, 0xDF, ++0x00, 0x70, 0x07, 0xC4, 0x01, 0x16, 0x97, 0x40, 0x43, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA8, 0xF2, 0x00, 0xCD, 0x00, 0x34, 0x23, 0xD0, 0x0C, ++0x48, 0x31, 0x00, 0x88, 0x02, 0x36, 0x1F, 0x90, 0x0C, 0x40, 0x13, 0x10, 0xC5, ++0x00, 0x34, 0x03, 0x90, 0x3C, 0x60, 0xB0, 0x00, 0xD5, 0x0B, 0x00, 0x03, 0x91, ++0x3C, 0x44, 0x31, 0x00, 0xC1, 0x01, 0x34, 0x0A, 0x50, 0x14, 0x40, 0xF2, 0x01, ++0xC1, 0x07, 0x24, 0x0B, 0x12, 0x8C, 0x44, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x80, 0x38, 0x04, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, ++0x39, 0x01, 0x6D, 0x10, 0xB4, 0x04, 0x18, 0x0E, 0x40, 0x1B, 0x00, 0xE1, 0x44, ++0xB4, 0x03, 0xD0, 0x36, 0x40, 0x38, 0x00, 0xED, 0x00, 0x85, 0x03, 0xD4, 0x06, ++0x60, 0x7D, 0x02, 0xE1, 0x02, 0xE6, 0x02, 0x10, 0x06, 0x40, 0xBB, 0x20, 0xE1, ++0x61, 0xE5, 0x8F, 0x50, 0x06, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x18, 0x78, 0x00, 0xEF, 0x01, 0xBC, 0x05, 0xD0, 0x1E, 0xC0, 0xF9, ++0x00, 0x2B, 0x01, 0xBC, 0x04, 0xB1, 0x1E, 0xC0, 0x73, 0x00, 0xE5, 0x35, 0xB4, ++0x2F, 0xB0, 0x1F, 0xD0, 0x78, 0x00, 0xCF, 0x41, 0x8C, 0x05, 0xB4, 0x16, 0xC0, ++0x79, 0x03, 0xF3, 0x01, 0xBD, 0x04, 0x70, 0x16, 0xC0, 0x7B, 0x40, 0x23, 0x01, ++0xAC, 0x07, 0x31, 0x1E, 0xC4, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xB8, 0x35, 0x00, 0xDF, 0x00, 0xFC, 0x01, 0xF0, 0x0D, 0xC0, 0x35, 0x00, ++0x1E, 0x00, 0x3C, 0x00, 0xF0, 0x0D, 0xC0, 0x37, 0x10, 0xDF, 0x4A, 0x7C, 0x1B, ++0xF0, 0x05, 0xC8, 0x07, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF6, 0x05, 0xC6, 0xB5, ++0x01, 0x5E, 0x00, 0x1C, 0x00, 0x50, 0x05, 0xC0, 0x33, 0x00, 0x1F, 0x00, 0x5C, ++0x03, 0xB0, 0x09, 0xC8, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++0x20, 0x5D, 0x00, 0xF3, 0x01, 0xFC, 0x27, 0xF8, 0x8F, 0xC0, 0x7B, 0x00, 0x3B, ++0x01, 0xFC, 0x04, 0x70, 0x1F, 0xC0, 0x5F, 0x00, 0xFF, 0x09, 0xFE, 0x27, 0xB0, ++0x1B, 0xC0, 0x76, 0x00, 0xFF, 0x01, 0x8C, 0x07, 0x30, 0x93, 0xC4, 0x7F, 0x00, ++0xB3, 0x01, 0xCC, 0x16, 0xF8, 0x97, 0xC0, 0x7B, 0x00, 0xFB, 0x41, 0xF8, 0x04, ++0x34, 0x9B, 0xC0, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, ++0x19, 0x22, 0xE1, 0x40, 0xB4, 0x81, 0x78, 0x0E, 0x42, 0x3B, 0x00, 0x61, 0x00, ++0xB4, 0x00, 0xD0, 0x0E, 0x44, 0x1B, 0x21, 0xE6, 0x08, 0xF4, 0x23, 0x14, 0x0A, ++0x40, 0x78, 0x00, 0xBD, 0x00, 0x84, 0x23, 0xF0, 0x00, 0x40, 0x3B, 0x01, 0xA1, ++0x24, 0xAC, 0x12, 0xB0, 0x06, 0xC0, 0x3B, 0x06, 0xE1, 0x08, 0xB4, 0x20, 0xB0, ++0x03, 0x48, 0x55, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, ++0x04, 0xE1, 0x00, 0xB4, 0x03, 0x58, 0x8E, 0x40, 0x7F, 0x04, 0x21, 0x00, 0xB4, ++0x00, 0x50, 0x0E, 0x40, 0x19, 0x08, 0xEC, 0x42, 0xB4, 0x03, 0x10, 0x02, 0x40, ++0x38, 0x00, 0x6D, 0x00, 0xA4, 0x01, 0x10, 0x02, 0x60, 0x39, 0x24, 0xE1, 0x80, ++0xB4, 0x72, 0x1C, 0x06, 0x46, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x40, 0x50, 0x0A, ++0x42, 0x20, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x25, 0x00, ++0xC1, 0x20, 0x34, 0x08, 0x58, 0x0C, 0x40, 0xF3, 0x00, 0x49, 0x11, 0x34, 0x20, ++0xD8, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x01, 0x34, 0x03, 0x90, 0x01, 0x40, 0x02, ++0x80, 0x0D, 0x00, 0x24, 0x01, 0x90, 0x00, 0x40, 0xF3, 0x00, 0x41, 0x01, 0x34, ++0x06, 0x90, 0x04, 0x40, 0xF1, 0x00, 0xC1, 0x00, 0x36, 0x04, 0x18, 0x39, 0x40, ++0x09, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0xA5, 0x40, 0xD3, ++0x00, 0x7C, 0x6E, 0x70, 0x0D, 0x40, 0xF7, 0x40, 0x0B, 0x07, 0x7C, 0x00, 0x70, ++0x0D, 0xC2, 0x15, 0x00, 0xFF, 0x01, 0xF4, 0x4F, 0x30, 0x0D, 0xC0, 0x24, 0x00, ++0x1F, 0x00, 0x24, 0x02, 0x30, 0x01, 0xC0, 0xF9, 0x00, 0x53, 0xA3, 0x3C, 0x02, ++0x30, 0x04, 0x40, 0x77, 0x08, 0xDF, 0x25, 0x7C, 0x07, 0x50, 0x61, 0xC0, 0x54, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x27, 0x11, 0xDF, 0x00, ++0x7C, 0x0A, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0x57, 0x02, 0x7C, 0x00, 0xF0, 0x0D, ++0xC0, 0x17, 0x00, 0xD7, 0x08, 0x7C, 0x43, 0x70, 0x05, 0xD8, 0x25, 0x10, 0x9F, ++0x00, 0x5C, 0x02, 0xF0, 0x21, 0xC0, 0x37, 0x04, 0xDF, 0x08, 0x68, 0x0A, 0xF9, ++0x25, 0x80, 0x37, 0x01, 0x0E, 0x10, 0x7C, 0x0B, 0xF2, 0x21, 0xC0, 0xB7, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x07, 0x00, 0xF3, 0x00, 0xFC, ++0x00, 0xF0, 0x0E, 0xC0, 0x3E, 0x04, 0x33, 0x00, 0xEC, 0x00, 0xF0, 0x0F, 0xC0, ++0x7F, 0x00, 0xFF, 0x00, 0xEC, 0x03, 0x70, 0x2B, 0xC0, 0x2B, 0x00, 0x3B, 0x20, ++0xFC, 0x00, 0xB0, 0x03, 0xC0, 0x3F, 0x00, 0x23, 0x11, 0xCC, 0x42, 0x76, 0x87, ++0xC0, 0x3C, 0x00, 0x3F, 0x02, 0xC4, 0x07, 0xF0, 0x03, 0xC1, 0x04, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x66, 0x08, 0xD1, 0x40, 0x76, 0x04, ++0xD0, 0x0D, 0x48, 0x35, 0x00, 0x11, 0x00, 0x44, 0x14, 0xD0, 0x0D, 0xC0, 0x27, ++0x80, 0xDD, 0x80, 0x7C, 0x03, 0xD0, 0x11, 0x40, 0xC4, 0x44, 0x91, 0x21, 0x7C, ++0x07, 0xB0, 0x51, 0x40, 0x37, 0x00, 0x11, 0x0B, 0x44, 0x07, 0x10, 0x0D, 0x48, ++0xF0, 0x00, 0x11, 0x03, 0x44, 0x00, 0xD2, 0x31, 0x40, 0x04, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0xA2, 0x46, 0x04, 0xD1, 0x00, 0x74, 0x0E, 0xD0, ++0x0D, 0x40, 0x30, 0x00, 0x11, 0x30, 0x64, 0x04, 0xD0, 0x0D, 0x48, 0x17, 0x01, ++0xDD, 0x00, 0x74, 0x03, 0xD2, 0x0D, 0x40, 0x44, 0x00, 0x91, 0x83, 0x76, 0x46, ++0x90, 0x11, 0x40, 0x37, 0x00, 0x11, 0x02, 0x46, 0x0E, 0x50, 0x05, 0x40, 0x64, ++0x44, 0xD1, 0x20, 0x54, 0x18, 0xD2, 0x39, 0x40, 0x04, 0x08, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x34, 0x02, 0xD0, 0x0C, ++0x40, 0x31, 0x00, 0x51, 0x00, 0x04, 0x00, 0xD0, 0x0C, 0x40, 0x11, 0x00, 0xCD, ++0x00, 0x34, 0x03, 0xD0, 0x0C, 0x70, 0x00, 0x01, 0x81, 0x00, 0x34, 0x02, 0x99, ++0x00, 0x40, 0x37, 0x00, 0x81, 0x20, 0x04, 0x02, 0x10, 0x04, 0x40, 0x24, 0x00, ++0x01, 0x00, 0x14, 0x03, 0xD0, 0x00, 0x52, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x06, 0x00, 0xD3, 0x00, 0x74, 0x02, 0xF0, 0x0D, 0x40, ++0x3C, 0x80, 0x13, 0x00, 0x6C, 0x00, 0xF0, 0x0D, 0x60, 0x17, 0x00, 0xFD, 0x00, ++0xEC, 0x03, 0xF8, 0x00, 0xC0, 0x06, 0x00, 0x13, 0x00, 0x7C, 0x00, 0xB0, 0x81, ++0xC0, 0x3B, 0x40, 0x03, 0x00, 0x4C, 0x02, 0x70, 0x01, 0xC0, 0x24, 0x10, 0xD3, ++0x00, 0x1C, 0x00, 0xF0, 0x09, 0xC4, 0x04, 0x64, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0xB8, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC2, 0x3D, ++0x40, 0x7F, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xDC, ++0x03, 0xF0, 0x03, 0x00, 0x0F, 0x2A, 0x3F, 0x00, 0xDC, 0x03, 0x70, 0x03, 0xC0, ++0x3F, 0x00, 0x3F, 0x00, 0xBC, 0x03, 0xF0, 0x07, 0x40, 0x0F, 0x40, 0x37, 0x00, ++0xEC, 0x00, 0xF0, 0x0B, 0xC8, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA8, 0x7F, 0x00, 0x3E, 0x00, 0xFC, 0x04, 0x30, 0x1F, 0xC0, 0x2C, 0x00, ++0xBF, 0x24, 0xCC, 0x03, 0xF0, 0x43, 0xC1, 0x3D, 0x21, 0x3F, 0xA0, 0xDC, 0x13, ++0x30, 0x9E, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0x98, 0x17, 0xF0, 0x1F, 0xC0, 0x4C, ++0x00, 0xFF, 0x03, 0xFC, 0x07, 0xF0, 0x4F, 0xC0, 0x7E, 0x02, 0xFF, 0x00, 0xCC, ++0x03, 0x30, 0x83, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x10, 0x36, 0x05, 0x1D, 0x02, 0x44, 0x00, 0x10, 0x0D, 0x50, 0x24, 0x08, 0x9D, ++0x08, 0xC4, 0x2B, 0x10, 0x39, 0x44, 0x7C, 0x02, 0x9D, 0x01, 0xC4, 0x23, 0x11, ++0x1D, 0x40, 0xFF, 0x01, 0x5D, 0x01, 0xC4, 0x0F, 0xD0, 0x0D, 0x40, 0x44, 0x00, ++0xDD, 0x00, 0x5C, 0x07, 0xD0, 0xBF, 0x40, 0x34, 0x01, 0xF7, 0x03, 0xC4, 0x2F, ++0x10, 0x09, 0x40, 0x0D, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, ++0x33, 0x00, 0x0D, 0x03, 0x54, 0x00, 0x90, 0x0C, 0x40, 0x21, 0x00, 0x8D, 0x00, ++0x04, 0x83, 0x10, 0x01, 0x60, 0x30, 0x08, 0x05, 0x00, 0x24, 0x03, 0x10, 0x4C, ++0x40, 0x32, 0x06, 0x89, 0x00, 0x05, 0x23, 0xD2, 0x0C, 0x48, 0x00, 0x20, 0xCD, ++0x04, 0x36, 0x03, 0xD0, 0x0C, 0x40, 0x30, 0x01, 0xCD, 0x02, 0x05, 0x03, 0x14, ++0x40, 0x44, 0x4C, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x35, ++0x00, 0x1D, 0x01, 0x44, 0x46, 0x94, 0x0D, 0x40, 0xE5, 0x00, 0x9D, 0x20, 0x44, ++0x03, 0x10, 0x19, 0x40, 0x34, 0x00, 0x1D, 0x01, 0x64, 0x03, 0x11, 0x0D, 0x40, ++0x37, 0x20, 0xDC, 0x10, 0x44, 0x03, 0xD0, 0x8C, 0x40, 0x44, 0x00, 0xDC, 0x00, ++0x54, 0x03, 0xD0, 0x0D, 0x40, 0x34, 0x00, 0xD5, 0x00, 0x44, 0x03, 0x10, 0x49, ++0x40, 0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x37, 0x00, ++0x1F, 0x01, 0x7C, 0x0C, 0xB0, 0x0D, 0xC0, 0x65, 0x00, 0x9F, 0x80, 0x0C, 0x03, ++0xB4, 0x35, 0xC0, 0x35, 0x00, 0x9F, 0x01, 0x6C, 0x03, 0x34, 0x0D, 0xC2, 0x36, ++0x20, 0xDB, 0x80, 0x5C, 0x03, 0xE0, 0x1D, 0x80, 0x44, 0x04, 0x9F, 0x08, 0x7C, ++0x07, 0xF0, 0x0D, 0xC0, 0x36, 0x00, 0xDD, 0x00, 0x4C, 0x03, 0x30, 0x1D, 0xC0, ++0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0x2F, ++0x00, 0xFC, 0x00, 0x70, 0x0F, 0xC0, 0x2E, 0x00, 0x9F, 0x00, 0xFD, 0x03, 0xB0, ++0x0F, 0xC0, 0x3F, 0x00, 0xAF, 0x00, 0xDC, 0x03, 0xF0, 0x2F, 0xC6, 0x3F, 0x00, ++0x69, 0x08, 0xFC, 0x03, 0xF0, 0x1F, 0xD0, 0x0F, 0x00, 0xBF, 0x00, 0xFC, 0x27, ++0xF1, 0x0E, 0xC4, 0x3F, 0x01, 0xDF, 0x00, 0xBC, 0x03, 0xF0, 0x17, 0xC8, 0x1F, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x04, 0x1F, 0x21, ++0x7C, 0x02, 0xF0, 0x0D, 0xC0, 0xA7, 0x00, 0xD3, 0x00, 0x4C, 0xC3, 0x30, 0x25, ++0xC0, 0x34, 0x00, 0x17, 0x00, 0x7C, 0x13, 0xF0, 0x0D, 0xD0, 0x34, 0x00, 0x9F, ++0x21, 0x6C, 0x43, 0x30, 0x0D, 0xD1, 0x44, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC2, 0x36, 0x00, 0xCF, 0x04, 0x4C, 0x13, 0xF0, 0x0D, 0xC0, 0x8B, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xB4, 0x00, 0x1D, 0x00, 0x34, ++0x12, 0xD0, 0xBD, 0x41, 0x27, 0x04, 0xD1, 0x00, 0xD4, 0x13, 0x10, 0x0C, 0x45, ++0x3C, 0x00, 0x1D, 0x00, 0xE4, 0x03, 0xD2, 0x0D, 0x40, 0x3C, 0x00, 0xDD, 0x00, ++0xC4, 0x07, 0x10, 0x0D, 0x40, 0x04, 0x00, 0xD1, 0x20, 0x74, 0x03, 0xD0, 0x1F, ++0x40, 0x34, 0x00, 0xFD, 0x82, 0xC4, 0x0B, 0xD0, 0x05, 0x40, 0x6F, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x30, 0x00, 0x0D, 0x20, 0x34, 0x00, ++0xD0, 0x1D, 0x40, 0x33, 0x00, 0x94, 0x60, 0x24, 0x03, 0x10, 0x04, 0x40, 0x32, ++0x00, 0x0D, 0x00, 0x74, 0x03, 0xD0, 0x0C, 0x40, 0x32, 0x00, 0xCD, 0x00, 0x24, ++0x23, 0x50, 0x2C, 0x40, 0x03, 0x84, 0xC5, 0x12, 0x34, 0x03, 0xD0, 0x9C, 0x40, ++0x30, 0x00, 0xC9, 0x49, 0x24, 0x27, 0xD0, 0x05, 0x40, 0x1F, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x78, 0x00, 0x2D, 0x21, 0xB4, 0x07, 0xD0, ++0x9E, 0x40, 0x6B, 0x02, 0xA4, 0x01, 0xB4, 0x07, 0x10, 0x1F, 0x40, 0x7A, 0x00, ++0xED, 0x81, 0xA4, 0x07, 0xD0, 0x1F, 0x60, 0x7A, 0x00, 0xC9, 0x03, 0x84, 0x07, ++0x50, 0x1E, 0x40, 0x4B, 0x50, 0xE5, 0x89, 0xB4, 0x17, 0xD1, 0x1C, 0x40, 0x78, ++0x00, 0xED, 0x81, 0xA4, 0x07, 0xD0, 0x9E, 0x40, 0x37, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x18, 0x30, 0x00, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x8C, ++0xC0, 0x37, 0x08, 0x87, 0x00, 0x6C, 0x13, 0x30, 0x04, 0xC0, 0x32, 0x00, 0x4F, ++0x02, 0x3C, 0x23, 0xF0, 0x0C, 0xC0, 0x32, 0x00, 0xCF, 0x00, 0x2C, 0x03, 0x70, ++0x0D, 0xC0, 0x03, 0x00, 0xC7, 0x08, 0x3C, 0x03, 0xF0, 0x0C, 0xC0, 0x30, 0x00, ++0xCB, 0x00, 0x2C, 0x03, 0xF0, 0x84, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x38, 0x3D, 0x00, 0x3F, 0x00, 0xFC, 0x23, 0xF0, 0x8F, 0xE8, ++0x3F, 0x40, 0xBB, 0x00, 0xDC, 0x03, 0xF0, 0x0E, 0xC0, 0x3D, 0x02, 0xFF, 0x00, ++0xEC, 0x03, 0xF0, 0x0F, 0xC0, 0x3D, 0x24, 0xFF, 0x00, 0xFC, 0x23, 0xB2, 0x0F, ++0xC0, 0x08, 0x02, 0xFB, 0x28, 0xFC, 0x93, 0xF0, 0x0F, 0xD0, 0x3D, 0x00, 0xFF, ++0x00, 0xDD, 0x03, 0xF2, 0x8F, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xB0, 0x37, 0x00, 0x1F, 0x00, 0x7C, 0x02, 0xF1, 0x1D, 0xC0, 0x34, ++0x00, 0x93, 0x00, 0x4C, 0x03, 0x70, 0x05, 0xC4, 0x77, 0x01, 0x9B, 0x00, 0x7C, ++0x4B, 0xE0, 0x1D, 0xC2, 0x35, 0x05, 0xCD, 0x01, 0x4C, 0x1B, 0xF0, 0x0D, 0xC0, ++0x07, 0x00, 0xDF, 0x01, 0x1C, 0x07, 0x70, 0xCD, 0xC0, 0x37, 0x20, 0xDF, 0x0A, ++0x3C, 0x4F, 0x30, 0x09, 0xC0, 0x54, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x80, 0x39, 0x00, 0x2D, 0x00, 0xB4, 0x03, 0x70, 0x0E, 0x40, 0x1C, 0x00, ++0xA1, 0x00, 0xAC, 0x53, 0x10, 0x0E, 0x40, 0xBB, 0x04, 0xE1, 0x00, 0xB4, 0x03, ++0xD0, 0x0E, 0x40, 0x3C, 0x01, 0xE1, 0x00, 0x84, 0x53, 0xD0, 0x0E, 0x40, 0x0B, ++0x00, 0xFD, 0x00, 0x8C, 0x03, 0x10, 0x8E, 0x40, 0x3B, 0x00, 0xE7, 0x10, 0xB4, ++0x13, 0xB0, 0x00, 0xC0, 0x4E, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x00, 0x79, 0x00, 0x6D, 0x01, 0x94, 0x06, 0xD0, 0x1E, 0x40, 0x78, 0x0C, 0xC1, ++0x01, 0x04, 0x27, 0x50, 0x1E, 0x40, 0x73, 0x01, 0xE1, 0x01, 0xB4, 0x27, 0x50, ++0x3E, 0x40, 0x7B, 0x00, 0xE5, 0x01, 0x85, 0x27, 0xD0, 0x1E, 0x43, 0x4B, 0x00, ++0xED, 0x01, 0x84, 0x07, 0x10, 0x5E, 0x40, 0x6B, 0x00, 0xE5, 0x25, 0xB6, 0x37, ++0x10, 0x1A, 0x40, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, ++0x33, 0x00, 0xCD, 0x01, 0x34, 0x4B, 0x50, 0x0C, 0x60, 0x70, 0x01, 0xC1, 0x01, ++0x24, 0x03, 0x10, 0x0C, 0x41, 0x33, 0x80, 0xC1, 0x10, 0x34, 0x03, 0xD0, 0x18, ++0x40, 0x32, 0x00, 0xC1, 0x00, 0x04, 0x03, 0xD0, 0x09, 0x40, 0xF3, 0x00, 0xCD, ++0x01, 0x04, 0x06, 0x14, 0x0C, 0x40, 0x37, 0x10, 0xC5, 0x80, 0x36, 0x03, 0x90, ++0x41, 0x40, 0x4A, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x15, ++0x00, 0x7F, 0x05, 0xFC, 0x01, 0xF0, 0x05, 0xD0, 0x1C, 0x00, 0x53, 0x41, 0x4C, ++0x01, 0x70, 0x27, 0xC0, 0x17, 0x40, 0x73, 0xC2, 0x7C, 0x01, 0xF0, 0x05, 0xC0, ++0x17, 0x10, 0x7F, 0x00, 0x4C, 0x01, 0xF0, 0x15, 0xC0, 0x5F, 0x01, 0x5F, 0x01, ++0x5D, 0x15, 0x70, 0x04, 0xC2, 0x57, 0x01, 0x47, 0x00, 0x7C, 0x01, 0x30, 0x17, ++0xC1, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x85, 0x00, ++0x1F, 0x01, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x40, 0x1F, 0x08, 0x3C, 0x00, ++0xF0, 0x01, 0xC0, 0x07, 0x00, 0x17, 0x00, 0x7C, 0x80, 0xF0, 0x01, 0xC0, 0x05, ++0x00, 0x1F, 0x00, 0x7E, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x01, 0x1F, 0x08, 0x5C, ++0x00, 0xF2, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x01, 0xC8, ++0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, ++0x05, 0x4C, 0x02, 0x36, 0x09, 0xC0, 0xA3, 0x40, 0x83, 0x05, 0x4C, 0x06, 0xB0, ++0x08, 0xC0, 0x26, 0x00, 0x9F, 0x00, 0x74, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, ++0x9B, 0x00, 0x7C, 0x06, 0xF0, 0x19, 0xC0, 0x24, 0x20, 0x9F, 0x00, 0x7C, 0x26, ++0xF0, 0x09, 0xC0, 0x24, 0x00, 0x9C, 0x00, 0x48, 0x02, 0xF0, 0x09, 0xC8, 0x40, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x64, 0x00, 0x9D, 0x00, ++0x44, 0x02, 0x10, 0x19, 0x40, 0x27, 0x40, 0x91, 0x01, 0x7C, 0x2A, 0x10, 0x09, ++0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0xE0, 0x27, 0x00, 0x91, ++0x10, 0x74, 0x1E, 0xD1, 0x99, 0x40, 0xA4, 0x00, 0x9D, 0x42, 0x5C, 0x02, 0xD0, ++0x09, 0xC0, 0x26, 0x00, 0x95, 0x80, 0x54, 0x1A, 0xD0, 0x09, 0xC0, 0x06, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x02, 0x8D, 0x00, 0x04, ++0x02, 0x18, 0x49, 0x40, 0x27, 0x40, 0x91, 0x00, 0x44, 0x02, 0x90, 0x1D, 0x40, ++0x26, 0x00, 0x95, 0x00, 0x74, 0x22, 0xD0, 0x09, 0x60, 0x23, 0x00, 0x99, 0x01, ++0x74, 0x12, 0xD0, 0x29, 0x40, 0x25, 0x00, 0x9D, 0x04, 0x74, 0x02, 0x50, 0x89, ++0x40, 0x24, 0x00, 0x95, 0x18, 0x54, 0x22, 0xD0, 0x09, 0x40, 0x60, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x8D, 0x04, 0x04, 0x02, ++0x10, 0x0C, 0x40, 0x23, 0x01, 0x81, 0x04, 0x14, 0x13, 0x10, 0x48, 0x40, 0x20, ++0x01, 0x8D, 0x04, 0x36, 0x16, 0xD1, 0x08, 0x42, 0x21, 0x01, 0x81, 0x04, 0x34, ++0x12, 0xD8, 0x08, 0x40, 0x61, 0x80, 0x8D, 0x01, 0x14, 0x02, 0xD0, 0x48, 0x40, ++0x22, 0x30, 0x85, 0x44, 0x16, 0x12, 0xD0, 0x48, 0x40, 0x42, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xA0, 0x96, 0x02, 0x1F, 0x0A, 0x4D, 0x28, 0x30, ++0xA0, 0xC0, 0x87, 0x02, 0x13, 0x0A, 0x44, 0x28, 0xB0, 0x01, 0xC0, 0x06, 0x00, ++0x17, 0x10, 0x7C, 0x00, 0xF0, 0xA0, 0x40, 0x87, 0x02, 0x1B, 0x00, 0x74, 0x00, ++0xF0, 0xA1, 0xC8, 0x05, 0x00, 0x1F, 0x0A, 0x74, 0x00, 0xF0, 0x01, 0xC0, 0x84, ++0x00, 0x17, 0x00, 0x5C, 0x00, 0xF2, 0x21, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0x88, 0x27, 0x00, 0xFF, 0x08, 0xFC, 0x02, 0xF0, 0x09, ++0xC0, 0x2F, 0x02, 0xBF, 0x48, 0x7C, 0x22, 0xF0, 0x8B, 0xC4, 0x27, 0x02, 0xBF, ++0x00, 0x7C, 0x62, 0xF0, 0x0B, 0xC0, 0x27, 0x02, 0xBF, 0x08, 0x7C, 0x22, 0xF0, ++0x0B, 0xD8, 0x2E, 0x00, 0xBF, 0x40, 0xDC, 0x02, 0xF0, 0x89, 0xC2, 0x2F, 0x04, ++0x93, 0x08, 0x7C, 0x22, 0xF2, 0x8B, 0xC1, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1C, 0xA0, 0x2D, 0x00, 0xBF, 0x0C, 0xCC, 0x02, 0x30, 0x0B, 0xC0, ++0x2C, 0x02, 0xB3, 0x00, 0xFC, 0x52, 0x34, 0x4F, 0x80, 0x27, 0x00, 0x9F, 0x00, ++0xF8, 0x22, 0xF0, 0x09, 0xC0, 0x27, 0x25, 0xBF, 0x04, 0xD4, 0x02, 0x70, 0x0A, ++0xC0, 0x2C, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0xF0, 0x4B, 0xC0, 0x27, 0x00, 0xA3, ++0x80, 0xBC, 0x02, 0xF0, 0x29, 0xC0, 0x61, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0x00, 0x07, 0x01, 0x0D, 0x2C, 0x44, 0x41, 0x10, 0x01, 0x41, 0x14, ++0x02, 0x01, 0x14, 0x74, 0x10, 0x13, 0x81, 0x40, 0x87, 0x00, 0x1D, 0x00, 0x74, ++0x20, 0xD0, 0x41, 0x41, 0x06, 0x01, 0x1D, 0x08, 0x44, 0x08, 0x10, 0x01, 0x41, ++0x04, 0x00, 0x1D, 0x14, 0x74, 0x00, 0xC0, 0x81, 0x44, 0x47, 0x05, 0x1B, 0x00, ++0x74, 0x20, 0xD0, 0x11, 0x40, 0x71, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x20, 0x21, 0x05, 0x8D, 0x04, 0x05, 0x12, 0x10, 0x08, 0x40, 0x20, 0x40, ++0x81, 0x04, 0x34, 0x52, 0x10, 0x08, 0x48, 0x22, 0x02, 0x88, 0x08, 0x34, 0x02, ++0xD0, 0x48, 0x40, 0x21, 0x05, 0x8D, 0x01, 0x14, 0x22, 0xD0, 0x08, 0x40, 0x61, ++0x00, 0x8D, 0x04, 0x24, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x00, 0x81, 0x08, 0x34, ++0x02, 0xD0, 0x48, 0x40, 0x4B, 0x88, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0x28, 0x25, 0x00, 0x9D, 0x00, 0x04, 0x02, 0x10, 0x09, 0x60, 0x24, 0x01, 0xD1, ++0x00, 0x34, 0x03, 0x10, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x0A, 0x74, 0x02, 0xD0, ++0x19, 0x40, 0x24, 0x00, 0x9D, 0x08, 0x44, 0x02, 0x90, 0x08, 0x50, 0x25, 0x01, ++0x9D, 0x01, 0x74, 0x06, 0xD0, 0x09, 0x40, 0x67, 0x00, 0x98, 0x00, 0x74, 0x02, ++0xD0, 0x09, 0x40, 0x63, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, ++0x25, 0x00, 0x9F, 0x02, 0x4C, 0x02, 0x30, 0x09, 0xD0, 0xE4, 0x08, 0x93, 0x01, ++0x7C, 0x02, 0x34, 0x69, 0xC8, 0x26, 0x00, 0x9B, 0x03, 0x7C, 0x02, 0xF0, 0x09, ++0xCC, 0x27, 0x00, 0x9F, 0x01, 0x5C, 0x02, 0xF0, 0x19, 0xC0, 0x25, 0x00, 0x9E, ++0x00, 0x74, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x90, 0x00, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x17, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x25, ++0x00, 0x9F, 0x09, 0x7C, 0x02, 0xF4, 0x09, 0xC0, 0x67, 0x00, 0x9F, 0x04, 0x7C, ++0x02, 0x70, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x01, 0x7C, 0x82, 0xF0, 0x09, 0xC8, ++0x27, 0x00, 0x8F, 0x00, 0x7C, 0x42, 0x70, 0x49, 0xC0, 0x26, 0x08, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x10, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x08, ++0xC0, 0x59, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x01, ++0x1F, 0x00, 0x4C, 0x00, 0xB0, 0x01, 0xC0, 0x84, 0x40, 0x13, 0x10, 0x4C, 0x00, ++0x30, 0x21, 0xC0, 0x07, 0x20, 0x1F, 0x00, 0x7C, 0x80, 0xF0, 0x01, 0xE0, 0x07, ++0x00, 0x1F, 0x00, 0x3C, 0x00, 0xB0, 0x11, 0xC0, 0x04, 0x00, 0x1F, 0x00, 0x7C, ++0x00, 0xF0, 0x11, 0xC0, 0x07, 0x00, 0x17, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC0, ++0x51, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x5C, 0x00, 0x5D, ++0x80, 0x44, 0x05, 0x30, 0x07, 0x40, 0x54, 0x40, 0x71, 0x05, 0xC6, 0x29, 0x10, ++0x05, 0x40, 0x17, 0x00, 0x5D, 0x00, 0xF4, 0x09, 0xD0, 0x05, 0xC0, 0x17, 0x00, ++0x7D, 0x0A, 0xF4, 0x01, 0x70, 0x17, 0x40, 0x9C, 0x00, 0x7D, 0x10, 0x5C, 0x01, ++0xD0, 0x17, 0x40, 0x17, 0x00, 0x71, 0x07, 0xC4, 0x19, 0x50, 0x05, 0x48, 0x50, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x72, 0x02, 0xDD, 0x00, ++0x04, 0x03, 0x50, 0x15, 0x49, 0x76, 0x20, 0xC1, 0x02, 0x24, 0x0F, 0x10, 0x0C, ++0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x37, 0xD0, 0x0D, 0x40, 0x33, 0x00, 0xCD, ++0x0B, 0x34, 0x07, 0x50, 0x9C, 0x42, 0xA0, 0x04, 0xCD, 0x05, 0x34, 0x03, 0xD0, ++0x1C, 0x40, 0x37, 0x00, 0x05, 0x04, 0x04, 0x10, 0x10, 0x0C, 0x40, 0x51, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x18, 0x00, 0xED, 0x00, 0x84, ++0x0A, 0x10, 0x2A, 0x40, 0x32, 0x24, 0xE1, 0x01, 0xA4, 0x0A, 0x10, 0x2E, 0x48, ++0x3B, 0x00, 0xED, 0x00, 0xB4, 0x83, 0xD0, 0x4E, 0x40, 0x39, 0x00, 0xAD, 0x00, ++0xB4, 0x09, 0x40, 0x0F, 0x40, 0x18, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, ++0x49, 0x3B, 0x00, 0x25, 0x00, 0x84, 0x04, 0x50, 0x0E, 0x48, 0x10, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x69, 0x00, 0xEF, 0x01, 0xCC, 0x07, ++0x70, 0x1F, 0xD0, 0x7A, 0x00, 0xA3, 0x01, 0xE4, 0x07, 0x34, 0x1A, 0xC0, 0x7B, ++0x00, 0xED, 0x01, 0xBC, 0x05, 0xF0, 0x7E, 0x41, 0x7B, 0x05, 0xAF, 0x01, 0xB8, ++0x05, 0x70, 0x1E, 0xC0, 0x48, 0x00, 0xEF, 0x01, 0xBC, 0x06, 0xF0, 0x1E, 0xC0, ++0x7F, 0x00, 0xA5, 0x00, 0x8C, 0x06, 0x30, 0x1F, 0xC0, 0x51, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0xB0, 0x0D, 0x00, 0x9F, 0x02, 0x7D, 0x1A, 0x74, ++0x6B, 0xC0, 0x35, 0x00, 0x9F, 0x00, 0x5D, 0x1A, 0xF0, 0x09, 0xC0, 0x37, 0x00, ++0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0x9F, 0x00, 0x3C, 0x81, ++0x70, 0x0D, 0xD0, 0x17, 0x08, 0xDF, 0x00, 0x5C, 0x82, 0xF0, 0x0D, 0xC0, 0x37, ++0x00, 0xDA, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x20, 0x4D, 0x00, 0xF7, 0x03, 0xCC, 0x1B, 0x70, 0x3F, ++0xC0, 0x7C, 0x00, 0x73, 0x01, 0xCD, 0x0F, 0x30, 0x1B, 0xC0, 0x7F, 0x00, 0xF3, ++0x01, 0xFC, 0x07, 0x30, 0x1F, 0xC0, 0x7F, 0x04, 0xB3, 0x01, 0xCC, 0x85, 0xF0, ++0x1F, 0xC0, 0x4C, 0x20, 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x17, 0xC0, 0x7F, 0x00, ++0x23, 0x01, 0xCC, 0x05, 0xF0, 0x1F, 0xC0, 0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0x00, 0x0D, 0x00, 0xF1, 0x08, 0x84, 0xC3, 0x18, 0x0B, 0x40, ++0x28, 0x00, 0x71, 0x00, 0xC4, 0x22, 0x10, 0x0A, 0x40, 0x3B, 0x00, 0xE1, 0x00, ++0xB4, 0x23, 0x10, 0x0E, 0xC0, 0x39, 0x02, 0xE1, 0x02, 0x84, 0x00, 0x70, 0x07, ++0x40, 0x18, 0x20, 0xED, 0x80, 0xB4, 0x03, 0xD0, 0x02, 0x40, 0x3B, 0x00, 0x25, ++0x0A, 0xAC, 0x28, 0xD0, 0x0E, 0xC0, 0x55, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x09, 0x00, 0xED, 0x00, 0xC4, 0x23, 0x50, 0x0A, 0x50, 0x28, ++0x00, 0x25, 0x08, 0x84, 0x03, 0x10, 0x0A, 0x40, 0x33, 0x00, 0xE1, 0x00, 0x34, ++0x02, 0x10, 0x0E, 0x40, 0x33, 0x00, 0x41, 0x00, 0xA4, 0x01, 0xD0, 0x0E, 0x40, ++0x88, 0x04, 0xED, 0x00, 0xB4, 0x02, 0xD0, 0x02, 0x40, 0x3F, 0x00, 0xA1, 0x00, ++0x94, 0x03, 0xD0, 0x0E, 0x40, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x28, 0x01, 0x00, 0x89, 0x00, 0x44, 0x0B, 0x10, 0x08, 0x40, 0xE4, 0x01, ++0x05, 0x00, 0x44, 0x02, 0x10, 0x28, 0x40, 0x33, 0x00, 0xC1, 0x11, 0x34, 0x02, ++0x10, 0x0C, 0x68, 0x31, 0x00, 0x41, 0x52, 0x24, 0x00, 0x50, 0x0C, 0x40, 0x50, ++0x00, 0xDD, 0x00, 0x34, 0x02, 0xD0, 0x00, 0x40, 0x73, 0x02, 0x85, 0x00, 0x34, ++0x03, 0xD0, 0x0C, 0x40, 0x19, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA0, 0x25, 0x00, 0xDF, 0x00, 0x4D, 0x0B, 0x50, 0x05, 0xC0, 0x74, 0x40, 0x17, ++0x00, 0x44, 0x03, 0x34, 0x0C, 0xC0, 0x37, 0x00, 0xD3, 0x06, 0x7C, 0x02, 0x30, ++0x0F, 0xC0, 0x3F, 0x00, 0xD3, 0x02, 0x6C, 0x01, 0xF0, 0x1D, 0xC0, 0x44, 0x00, ++0xDF, 0x40, 0x7C, 0x02, 0xF0, 0x05, 0xC0, 0x3F, 0x00, 0x53, 0x00, 0x5C, 0x00, ++0xF0, 0x2F, 0xC0, 0x55, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, ++0x87, 0x00, 0xD7, 0x10, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x37, 0x02, 0x1A, 0x02, ++0x7C, 0x02, 0xF1, 0x09, 0xC1, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x00, 0xF0, 0x1D, ++0xC0, 0x37, 0x20, 0x1F, 0x03, 0x5C, 0x01, 0x70, 0x8D, 0xC0, 0x07, 0x28, 0xDF, ++0x02, 0x7C, 0x06, 0xF0, 0x05, 0xCA, 0x37, 0x00, 0x9F, 0x02, 0x2C, 0x0A, 0xF0, ++0x0D, 0xC0, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x0F, ++0x00, 0xFF, 0x00, 0xCC, 0x43, 0x30, 0x0F, 0xC0, 0x74, 0x01, 0x23, 0x01, 0xC4, ++0x03, 0x30, 0x0B, 0xC0, 0x3C, 0x00, 0xFF, 0x00, 0xBC, 0x00, 0x30, 0x0F, 0xC0, ++0x3B, 0x00, 0xB3, 0x00, 0x8E, 0x00, 0x30, 0x0B, 0xC0, 0x0D, 0x00, 0x7B, 0x00, ++0xCC, 0x03, 0x30, 0x07, 0xC0, 0x3F, 0x10, 0x7F, 0x00, 0xCC, 0x0C, 0x30, 0x0F, ++0xC1, 0x03, 0x2A, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0xC6, 0x24, ++0x8D, 0x00, 0x44, 0x02, 0x90, 0x19, 0xC0, 0x36, 0x40, 0x11, 0x03, 0x54, 0x0E, ++0x50, 0x09, 0x50, 0x34, 0x00, 0xDD, 0x00, 0x74, 0x4C, 0x10, 0x0D, 0x40, 0x37, ++0x00, 0x01, 0x00, 0x54, 0x0C, 0x51, 0x09, 0x40, 0xC0, 0x00, 0xDB, 0x03, 0x04, ++0x07, 0x10, 0x15, 0xC0, 0x35, 0x00, 0xCD, 0x08, 0x54, 0x06, 0x10, 0x0D, 0x40, ++0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x46, 0x80, 0xDD, ++0x00, 0x44, 0x03, 0x90, 0x18, 0x40, 0x25, 0x00, 0x51, 0x88, 0x54, 0x07, 0x10, ++0x89, 0x40, 0x34, 0x00, 0xD5, 0x00, 0x74, 0x06, 0x10, 0x0D, 0x40, 0x37, 0x00, ++0x91, 0x00, 0x46, 0x45, 0x90, 0x1C, 0x40, 0x44, 0x44, 0xD9, 0x03, 0x44, 0x12, ++0x10, 0x11, 0x60, 0x37, 0x00, 0x5D, 0x00, 0x44, 0x01, 0x10, 0x0D, 0x40, 0x07, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xDD, 0x00, ++0x04, 0x03, 0x90, 0x08, 0x40, 0x22, 0x00, 0x41, 0x00, 0x14, 0x02, 0x14, 0x08, ++0x48, 0x30, 0x00, 0xCD, 0x00, 0x34, 0x00, 0x10, 0x0C, 0x40, 0x33, 0x20, 0x41, ++0x00, 0x16, 0x00, 0xD0, 0x04, 0x40, 0x00, 0x40, 0xC9, 0x80, 0x45, 0x02, 0x14, ++0x10, 0x60, 0x31, 0x00, 0x4D, 0x00, 0x14, 0x01, 0x10, 0x0C, 0x40, 0x43, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x00, 0xFF, 0x00, 0xCD, ++0x03, 0x34, 0x0B, 0xC0, 0x25, 0x00, 0x13, 0x00, 0xDC, 0x02, 0x30, 0x09, 0xC0, ++0x34, 0x00, 0xD7, 0x00, 0x7C, 0x02, 0x11, 0x0F, 0xC0, 0x3F, 0x00, 0x53, 0x00, ++0x44, 0x00, 0xB0, 0x0D, 0xC8, 0x05, 0x40, 0x9B, 0x00, 0x4C, 0x03, 0x30, 0x01, ++0xC0, 0x37, 0x00, 0xDF, 0x00, 0x4C, 0x03, 0x30, 0x0D, 0xC0, 0x03, 0x40, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0F, 0x00, 0xBF, 0x00, 0xBC, 0x03, ++0x70, 0x0B, 0xC0, 0x2F, 0x00, 0x3F, 0x00, 0xFE, 0x00, 0xF0, 0x0B, 0xC0, 0x3F, ++0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0x7F, 0x00, 0xFC, ++0x00, 0x70, 0x0F, 0xC0, 0x0F, 0x00, 0xBF, 0x00, 0xF4, 0x03, 0xF1, 0x03, 0xCA, ++0x39, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x17, 0x60, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x2F, 0x00, 0xBF, 0x00, 0xDC, 0x53, 0xF0, ++0x03, 0xC0, 0x0F, 0x00, 0xAF, 0x01, 0xFC, 0x87, 0xF0, 0x1F, 0xD0, 0x0C, 0x00, ++0xFF, 0x01, 0xCC, 0x03, 0xF0, 0x4F, 0xC0, 0x0D, 0x02, 0xB3, 0x01, 0xEC, 0x07, ++0xF0, 0x03, 0xC0, 0x0F, 0x08, 0xEF, 0x01, 0xBC, 0x05, 0xB4, 0x1A, 0xC0, 0x7B, ++0x00, 0x33, 0x04, 0xBC, 0x02, 0x20, 0x0B, 0xC8, 0x0C, 0x08, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x00, 0x1D, 0x00, 0xF4, 0x0B, 0xD0, 0x11, ++0x40, 0x47, 0x00, 0xDD, 0x01, 0x74, 0x07, 0xD0, 0x0D, 0x40, 0x20, 0x01, 0xCC, ++0x10, 0xC4, 0x2B, 0xD0, 0x0D, 0x40, 0x27, 0x00, 0xD1, 0x01, 0x44, 0x03, 0xD0, ++0x11, 0x42, 0x07, 0x00, 0xDD, 0x01, 0x74, 0x07, 0x12, 0x19, 0x40, 0x57, 0x20, ++0x15, 0x83, 0x74, 0x06, 0x51, 0x01, 0x40, 0x0D, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x11, 0xA0, 0x03, 0x00, 0x8D, 0x00, 0x34, 0x03, 0xD0, 0x08, 0x40, ++0x03, 0x00, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x20, 0x04, 0xCD, 0x04, ++0x05, 0x03, 0xD2, 0x8C, 0x42, 0x23, 0x08, 0xD1, 0x80, 0x34, 0x03, 0xD0, 0x08, ++0x40, 0x63, 0x00, 0xCD, 0x00, 0x34, 0x81, 0x10, 0x0C, 0x40, 0x27, 0x00, 0x81, ++0x08, 0x34, 0x02, 0x19, 0x08, 0x40, 0x4C, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xA8, 0x65, 0x00, 0x1D, 0x21, 0x74, 0x03, 0xD0, 0x39, 0x40, 0x47, ++0x00, 0xDD, 0x01, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0xE4, 0x00, 0xCD, 0x20, 0x44, ++0x03, 0xD1, 0x0D, 0x40, 0x63, 0x00, 0xD1, 0x03, 0x54, 0x03, 0x90, 0x19, 0x40, ++0x67, 0x10, 0xDD, 0x04, 0x74, 0x06, 0x11, 0x1D, 0x40, 0x37, 0x00, 0x55, 0x90, ++0x74, 0x06, 0x58, 0x19, 0x42, 0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA0, 0xE7, 0x00, 0x9F, 0x11, 0x5C, 0x03, 0xF1, 0x19, 0xC0, 0x67, 0x04, ++0xDF, 0x05, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0xC4, 0x00, 0xDF, 0x01, 0x4C, 0x03, ++0xF0, 0x0D, 0xC0, 0x45, 0x40, 0xC3, 0x01, 0x7C, 0x03, 0xF0, 0x39, 0xC1, 0x67, ++0x00, 0xDF, 0x00, 0x3C, 0x0D, 0xB8, 0x39, 0xC0, 0x37, 0x00, 0x53, 0x02, 0x7C, ++0x04, 0x30, 0x11, 0xC0, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++0x88, 0x2D, 0x00, 0xBF, 0x80, 0x7C, 0x03, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0xFF, ++0x00, 0xFC, 0x03, 0xF0, 0x8F, 0xC0, 0x2F, 0x00, 0xFF, 0x02, 0xFC, 0x03, 0xF2, ++0x0F, 0xE0, 0x27, 0x80, 0xFF, 0x00, 0xEC, 0x03, 0xF0, 0x09, 0xC0, 0x0F, 0x00, ++0xFF, 0x01, 0xFC, 0x03, 0xF0, 0x03, 0xC0, 0x7F, 0x01, 0x3F, 0x04, 0xBC, 0x02, ++0xF0, 0x01, 0xC1, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, ++0x05, 0x02, 0x9F, 0x02, 0x7C, 0x03, 0x30, 0x29, 0xC0, 0xA7, 0x00, 0xDF, 0x0A, ++0x6C, 0x03, 0x70, 0x0D, 0xC0, 0x27, 0x00, 0xD3, 0x04, 0x4C, 0x13, 0xF2, 0x8D, ++0xC2, 0xA7, 0x00, 0xD7, 0x03, 0x4C, 0x47, 0xF0, 0x29, 0xC0, 0x24, 0x04, 0xDB, ++0x04, 0x4C, 0x19, 0x70, 0x2D, 0xC5, 0x34, 0x00, 0x57, 0x02, 0x7C, 0x60, 0x74, ++0x01, 0xC0, 0x28, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x24, ++0x00, 0x9D, 0x18, 0xF4, 0x2B, 0x10, 0x01, 0x40, 0x27, 0x00, 0xDD, 0x00, 0x44, ++0x03, 0xD0, 0x8D, 0x40, 0x27, 0x00, 0xD1, 0x02, 0xC4, 0x4B, 0xD0, 0x2F, 0x40, ++0x27, 0x00, 0xD1, 0x80, 0x50, 0x0B, 0xF0, 0x49, 0x00, 0x85, 0x00, 0xDD, 0x41, ++0x6C, 0x4F, 0x10, 0x0D, 0x40, 0x30, 0x02, 0x5B, 0x00, 0x70, 0x0A, 0x10, 0x21, ++0xC0, 0x4E, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x04, ++0x0D, 0x00, 0x34, 0x03, 0x10, 0x00, 0x40, 0x23, 0x00, 0xCD, 0x01, 0x24, 0x03, ++0x50, 0x3D, 0x40, 0x03, 0x00, 0xC5, 0x00, 0x04, 0x03, 0xD0, 0x4C, 0x40, 0x02, ++0x00, 0xC9, 0x00, 0x04, 0x8B, 0xD0, 0x10, 0x40, 0x00, 0x20, 0xCD, 0x02, 0x04, ++0x0B, 0x50, 0x28, 0x40, 0x32, 0x00, 0x0D, 0x07, 0x34, 0x04, 0xD4, 0x19, 0x40, ++0x0C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x58, 0x00, 0x6D, ++0x01, 0xB4, 0x27, 0x14, 0x16, 0x40, 0x7B, 0x00, 0xFD, 0x01, 0x84, 0x87, 0xD0, ++0x1E, 0x40, 0x7B, 0x10, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x48, 0x6B, 0x50, ++0xF9, 0x01, 0x94, 0x87, 0x58, 0x16, 0x50, 0x48, 0x02, 0xFD, 0x11, 0xE4, 0x17, ++0x10, 0x0F, 0x40, 0x7E, 0x8C, 0xA9, 0x01, 0xB4, 0x24, 0x90, 0x12, 0x48, 0x3E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x1A, 0x90, 0x00, 0xCF, 0x00, ++0x3C, 0x03, 0x30, 0x0C, 0xC0, 0x33, 0x00, 0xCF, 0x00, 0x2C, 0x03, 0x70, 0x0C, ++0xC1, 0x03, 0x40, 0xC5, 0x00, 0x0C, 0x23, 0xF0, 0x0C, 0x40, 0x12, 0x02, 0xD7, ++0x00, 0x0C, 0x03, 0xD0, 0x80, 0xC0, 0x30, 0x02, 0xCF, 0x00, 0x04, 0x03, 0x70, ++0x8C, 0xC0, 0x32, 0x00, 0xCF, 0x10, 0x3C, 0x22, 0xF4, 0x88, 0xC9, 0x48, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x1D, 0x00, 0xFF, 0x00, 0xFC, ++0x03, 0xF0, 0x8F, 0xC0, 0x3F, 0x10, 0xFF, 0x08, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x17, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x8F, 0xC8, 0x1F, 0x08, 0xF7, 0x00, ++0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x02, 0xFF, 0x00, 0xFC, 0x13, 0xF0, 0x4F, ++0xE0, 0x3D, 0x00, 0xFE, 0x08, 0xFC, 0x23, 0x74, 0x0F, 0xC0, 0x0B, 0x60, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, 0x08, 0x5F, 0x01, 0x4C, 0x03, ++0x70, 0x09, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC4, 0x17, ++0x00, 0xD7, 0x00, 0x5C, 0x1B, 0xF0, 0x0D, 0xC0, 0x17, 0x00, 0xDF, 0x00, 0x7C, ++0x03, 0x70, 0x0D, 0xC8, 0x37, 0x00, 0xC3, 0x00, 0x2C, 0x03, 0xB0, 0x0D, 0x40, ++0x37, 0x00, 0x9F, 0x40, 0x4C, 0x80, 0x20, 0x09, 0xC2, 0x43, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x82, 0x39, 0x00, 0x6D, 0x00, 0xC4, 0x2B, 0x10, ++0x0E, 0x40, 0x1B, 0x00, 0xE9, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x00, ++0xED, 0x00, 0xB4, 0x33, 0xD0, 0x2E, 0x40, 0x3B, 0x00, 0xEF, 0x00, 0xB4, 0x03, ++0xD0, 0x0E, 0x40, 0x3B, 0x20, 0xE1, 0x00, 0x84, 0x03, 0x50, 0x0E, 0x00, 0x3B, ++0x00, 0x8D, 0x00, 0x84, 0x01, 0xB0, 0x02, 0x40, 0x4F, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xCD, 0x03, 0xA5, 0x17, 0x50, 0x1E, ++0x40, 0x7B, 0x00, 0xED, 0x11, 0xB4, 0x07, 0xD0, 0x1E, 0x41, 0x7B, 0x00, 0xED, ++0x01, 0x96, 0x27, 0xD0, 0x1E, 0x40, 0x7B, 0x88, 0xED, 0x01, 0xB4, 0x07, 0xD0, ++0x36, 0x40, 0x73, 0x00, 0xE1, 0x01, 0xA4, 0x07, 0x90, 0x1E, 0x40, 0x7B, 0x00, ++0xED, 0x11, 0x14, 0x44, 0x19, 0x3E, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x28, 0x73, 0x00, 0xCD, 0x01, 0x24, 0x03, 0x10, 0x0C, 0x40, ++0x33, 0x00, 0x49, 0x05, 0x34, 0x03, 0xD0, 0x18, 0x40, 0xF3, 0x00, 0x8D, 0x01, ++0x74, 0x03, 0xD0, 0x0C, 0x40, 0x73, 0x02, 0x45, 0x1A, 0x34, 0x03, 0xD0, 0x5C, ++0x40, 0x77, 0x00, 0x81, 0x00, 0x04, 0x07, 0x50, 0x2C, 0x60, 0xB3, 0x00, 0xCD, ++0x47, 0x14, 0x07, 0x90, 0x1C, 0x40, 0x5B, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x17, 0xA0, 0x1D, 0x00, 0x7F, 0x02, 0x6C, 0x01, 0x70, 0x27, 0xC0, 0x9F, ++0x00, 0x7F, 0x01, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x1F, 0x00, 0x5F, 0x01, 0x5C, ++0x01, 0xF0, 0x05, 0xC0, 0xDF, 0x00, 0x7D, 0x02, 0x7C, 0x81, 0xF1, 0x37, 0xC0, ++0xDF, 0x40, 0x43, 0x00, 0xEC, 0x01, 0xB0, 0x27, 0xC0, 0x1B, 0x01, 0x7F, 0x23, ++0x9D, 0xA5, 0x20, 0xB7, 0xC0, 0x5F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x08, 0x45, 0x02, 0x1F, 0x02, 0x1C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, ++0x1D, 0x20, 0x7C, 0x00, 0xF2, 0x21, 0xC8, 0x07, 0x06, 0x1F, 0x0A, 0x7C, 0x00, ++0xF0, 0x21, 0xC0, 0x07, 0x04, 0x1F, 0x80, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x87, ++0x06, 0x1F, 0x42, 0x7C, 0x28, 0xB0, 0x41, 0xC0, 0x07, 0x04, 0x1F, 0x00, 0x64, ++0x88, 0xF0, 0x21, 0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x25, 0x00, 0x9F, 0x19, 0x7C, 0x06, 0x30, 0x08, 0xC5, 0x24, 0x04, 0x9F, ++0x08, 0x74, 0x02, 0xF0, 0x09, 0xC0, 0x23, 0x00, 0x9B, 0x01, 0x7C, 0x02, 0x30, ++0x09, 0xC2, 0x23, 0x80, 0x93, 0x04, 0x4C, 0x02, 0xF0, 0x59, 0xC0, 0x27, 0x00, ++0x93, 0x03, 0x5C, 0x02, 0x71, 0x59, 0xC0, 0xA7, 0x40, 0x83, 0x00, 0x4C, 0x22, ++0x30, 0x28, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, ++0x64, 0x00, 0x9D, 0x12, 0x74, 0x0A, 0x14, 0x09, 0x50, 0x24, 0x00, 0x97, 0x01, ++0x74, 0x02, 0xD8, 0x49, 0x40, 0x27, 0x40, 0x91, 0x11, 0x74, 0x0A, 0x50, 0x29, ++0x40, 0x27, 0xC0, 0x8B, 0x01, 0x44, 0x4A, 0xD0, 0x09, 0x44, 0xE7, 0x40, 0x91, ++0x86, 0x00, 0x12, 0x20, 0x19, 0x40, 0xE7, 0x10, 0x91, 0x01, 0x44, 0x06, 0x14, ++0x39, 0x41, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0x24, ++0x25, 0x9D, 0x00, 0x74, 0x62, 0x10, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, ++0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x91, 0x08, 0x74, 0x0A, 0x10, 0x09, 0x40, ++0x37, 0x08, 0x91, 0x00, 0x44, 0x82, 0xD0, 0x09, 0x40, 0x27, 0x01, 0x99, 0x00, ++0x50, 0x03, 0x50, 0x0D, 0x40, 0x36, 0x00, 0x99, 0x04, 0x44, 0x03, 0x10, 0x0D, ++0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x22, 0x20, 0x05, ++0x8D, 0x14, 0x36, 0x12, 0x10, 0x48, 0x40, 0x20, 0x01, 0x85, 0x80, 0x34, 0x02, ++0xD0, 0x08, 0x40, 0x23, 0x01, 0x81, 0x08, 0x74, 0x12, 0x50, 0x08, 0x40, 0x23, ++0x01, 0x91, 0x00, 0x04, 0x02, 0xD2, 0x48, 0x40, 0x33, 0x01, 0x89, 0x00, 0x44, ++0x02, 0x10, 0x08, 0x44, 0x33, 0x00, 0x89, 0x01, 0x05, 0x93, 0x10, 0x48, 0x50, ++0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x06, 0x01, 0x1F, ++0x04, 0x7C, 0x28, 0x30, 0x01, 0xC0, 0x04, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xD0, ++0xA1, 0xC0, 0x87, 0x02, 0x13, 0x02, 0x7C, 0x28, 0x30, 0xE5, 0xC5, 0x87, 0x02, ++0x11, 0x00, 0x4C, 0x28, 0xF0, 0x01, 0xC0, 0x87, 0x22, 0x1B, 0x00, 0x5C, 0x00, ++0x72, 0x01, 0xC0, 0x07, 0x00, 0x1B, 0x14, 0x4C, 0x00, 0x30, 0xA1, 0xC0, 0x74, ++0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x2F, 0x05, 0xBF, 0x14, ++0x74, 0xA2, 0xF2, 0x8B, 0xC0, 0x2F, 0x22, 0xBF, 0x00, 0x7C, 0x02, 0xF0, 0x0B, ++0xC0, 0x2F, 0x0A, 0xB7, 0x04, 0x7C, 0x22, 0xF0, 0x09, 0xC0, 0x2F, 0x02, 0xBF, ++0x00, 0x7D, 0x02, 0xF0, 0x8F, 0x00, 0x2F, 0x02, 0xB7, 0x80, 0xFC, 0x02, 0x70, ++0x0B, 0xC0, 0x2F, 0x08, 0xF7, 0x00, 0xFD, 0x23, 0xF0, 0x8B, 0xC2, 0x77, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x2F, 0x05, 0xBF, 0x0C, 0xFC, ++0x82, 0x32, 0x09, 0xC0, 0x24, 0x00, 0xB3, 0x00, 0x7C, 0x02, 0xF0, 0x8A, 0xC0, ++0x24, 0x00, 0xBF, 0x00, 0xFC, 0x22, 0x30, 0x4B, 0xC0, 0x26, 0x05, 0xBF, 0x00, ++0xFC, 0x02, 0x30, 0x0B, 0xE0, 0x2F, 0x02, 0xFF, 0x00, 0xCD, 0x02, 0xB0, 0x0F, ++0xC2, 0x2F, 0x48, 0xB3, 0x00, 0xCC, 0x02, 0xF0, 0x0B, 0xC4, 0x74, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x01, 0x1D, 0x0C, 0x74, 0x48, ++0x10, 0x05, 0x40, 0x04, 0x02, 0x51, 0x00, 0x74, 0x00, 0xD0, 0x41, 0x48, 0x84, ++0x04, 0x1D, 0x10, 0x74, 0x20, 0x14, 0x41, 0x41, 0x04, 0x01, 0x57, 0x80, 0x74, ++0x40, 0x10, 0x01, 0x60, 0x07, 0x02, 0x1D, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, ++0x17, 0x50, 0x11, 0x00, 0x45, 0x00, 0xF0, 0x01, 0xC0, 0x62, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x05, 0x8D, 0x05, 0x36, 0x32, 0x14, ++0x88, 0x40, 0x62, 0x60, 0xC1, 0x00, 0x34, 0x02, 0xD0, 0x48, 0x50, 0x20, 0x03, ++0x8D, 0x00, 0x34, 0x02, 0x10, 0xCC, 0x40, 0x22, 0x05, 0xCD, 0x00, 0x36, 0x13, ++0x10, 0x88, 0x40, 0x23, 0x00, 0x8D, 0x00, 0x24, 0x02, 0x94, 0x18, 0x40, 0x23, ++0x00, 0x85, 0x40, 0x14, 0x02, 0xD2, 0x08, 0x40, 0x48, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x04, 0x9D, 0x80, 0x74, 0x02, 0x10, 0x09, ++0x50, 0x26, 0x01, 0x91, 0x01, 0x74, 0x02, 0xD0, 0x09, 0x40, 0xA4, 0x00, 0x9D, ++0x00, 0x74, 0x02, 0x11, 0x09, 0x40, 0x64, 0x10, 0x9D, 0x01, 0x74, 0x02, 0x10, ++0x09, 0x40, 0xE7, 0x10, 0x9D, 0x00, 0x64, 0x12, 0x12, 0x09, 0x40, 0x27, 0x08, ++0xD5, 0x04, 0x44, 0x02, 0xD0, 0x29, 0x40, 0x62, 0x28, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x20, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x09, 0xC0, ++0x66, 0x00, 0x93, 0x03, 0x7C, 0x02, 0xF0, 0x19, 0xC0, 0xA4, 0x00, 0x9F, 0x01, ++0x7C, 0x02, 0x30, 0x09, 0xC0, 0xA6, 0x04, 0x9F, 0x03, 0x74, 0x02, 0x34, 0x29, ++0x40, 0xA7, 0x00, 0x8F, 0x00, 0x2C, 0x82, 0xB0, 0x29, 0xC0, 0xA3, 0x00, 0x97, ++0x02, 0x5C, 0x06, 0xF0, 0x29, 0xC0, 0x14, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x16, 0x08, 0x65, 0x0A, 0x9F, 0x14, 0x7C, 0x02, 0xF2, 0x48, 0xC0, 0x21, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF2, 0x59, 0xC0, 0x27, 0x00, 0x9F, 0x03, 0x7C, ++0x02, 0xF0, 0x08, 0xC0, 0x27, 0x00, 0x97, 0x80, 0x7C, 0x02, 0xF0, 0x09, 0x82, ++0x27, 0x00, 0x9F, 0x18, 0x5C, 0x02, 0xD0, 0x99, 0xC0, 0xA7, 0x64, 0x9B, 0x00, ++0x7C, 0x8E, 0x78, 0x38, 0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x08, 0x85, 0x04, 0x1F, 0x08, 0x7C, 0x40, 0xF1, 0x01, 0xC0, 0x07, 0x80, ++0x13, 0x20, 0x7C, 0x00, 0xF2, 0x41, 0xD0, 0x84, 0x00, 0x1F, 0x00, 0x0C, 0x00, ++0x30, 0x01, 0xC2, 0x87, 0x08, 0x1F, 0x02, 0x7E, 0x00, 0xF2, 0x21, 0xF0, 0x04, ++0x0C, 0x1B, 0x80, 0x7C, 0x00, 0x70, 0x01, 0xC9, 0x87, 0x00, 0x07, 0x80, 0x4D, ++0x08, 0x32, 0x01, 0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0xDC, 0x20, 0x7D, 0x01, 0xF6, 0x1D, 0x70, 0x05, 0x60, 0x17, 0x00, 0x51, ++0x00, 0x74, 0x01, 0xD0, 0x07, 0xC0, 0x16, 0x00, 0x7D, 0x05, 0xCD, 0x19, 0x30, ++0x27, 0x60, 0x17, 0x20, 0x5D, 0x00, 0xFC, 0xA9, 0x72, 0x45, 0x62, 0x1C, 0x11, ++0x71, 0x25, 0xDC, 0x8D, 0x14, 0x27, 0xC0, 0x9D, 0x01, 0x71, 0x89, 0xCC, 0x01, ++0x10, 0x37, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, ++0xF2, 0x02, 0xCD, 0x02, 0x74, 0x03, 0x52, 0x0C, 0x44, 0x33, 0x00, 0x81, 0x00, ++0x34, 0x03, 0xD0, 0x2D, 0x40, 0x30, 0x00, 0xCD, 0x01, 0x24, 0x1F, 0x10, 0x2C, ++0x49, 0x33, 0x10, 0x8D, 0x00, 0x74, 0x03, 0x51, 0x18, 0x40, 0x30, 0x00, 0x41, ++0x01, 0x34, 0x40, 0x10, 0x0C, 0x40, 0xA3, 0x20, 0xC5, 0x09, 0x20, 0x07, 0x10, ++0x2C, 0x41, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, ++0x00, 0xED, 0x00, 0xB4, 0x01, 0x50, 0x0E, 0x40, 0x33, 0x40, 0xE1, 0x80, 0xB4, ++0x03, 0xD8, 0x0F, 0x41, 0x38, 0x00, 0x6D, 0x01, 0x84, 0x03, 0x10, 0x0E, 0x48, ++0x3B, 0x02, 0xED, 0x40, 0xB4, 0x01, 0x50, 0x1E, 0x48, 0x59, 0x00, 0x61, 0x81, ++0xD4, 0x42, 0x10, 0x06, 0x40, 0x2D, 0x00, 0x61, 0x00, 0x04, 0x46, 0x10, 0x0E, ++0x41, 0x10, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x78, 0x00, ++0x6F, 0x01, 0xB4, 0x07, 0x70, 0x1E, 0x40, 0x7B, 0x08, 0xE1, 0x01, 0xBC, 0x07, ++0xF0, 0x1E, 0x40, 0x78, 0x81, 0xBD, 0x01, 0xEC, 0x05, 0x34, 0x1E, 0x40, 0x7B, ++0x02, 0xEF, 0x01, 0xB4, 0x07, 0x70, 0x1E, 0x40, 0x7C, 0x40, 0x6B, 0x00, 0xBC, ++0x06, 0x30, 0x1A, 0xC0, 0x6B, 0x00, 0xE7, 0x01, 0xAC, 0x07, 0x34, 0x17, 0xC0, ++0x50, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, 0x00, 0xDF, ++0x00, 0x7C, 0x81, 0x70, 0x0D, 0xC8, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC0, 0x37, 0x04, 0x1F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC8, 0xB7, 0x00, ++0xDF, 0x00, 0x5C, 0x83, 0x72, 0x0C, 0xE0, 0x16, 0x08, 0xDF, 0x00, 0x3C, 0x02, ++0xC4, 0x01, 0xC0, 0x23, 0x00, 0x0F, 0x00, 0x7C, 0x83, 0xF0, 0x01, 0xD0, 0x43, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x7D, 0x00, 0xF3, 0x01, ++0xCC, 0x13, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x1F, ++0xC0, 0x7F, 0x04, 0xF3, 0x01, 0xCC, 0x13, 0x30, 0x17, 0xC0, 0x7C, 0x02, 0xFF, ++0x89, 0xFC, 0x87, 0x30, 0x9F, 0xC0, 0x7F, 0x00, 0x73, 0x01, 0xFC, 0x26, 0xF0, ++0x17, 0xC8, 0x6B, 0x20, 0xBB, 0x01, 0xFC, 0x07, 0xD0, 0x13, 0xC0, 0x1B, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x3D, 0x50, 0x71, 0x20, 0x84, ++0x83, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x2A, 0x48, ++0x3F, 0x00, 0x61, 0x00, 0xD4, 0x08, 0x11, 0x0B, 0xC0, 0x38, 0x00, 0xE9, 0x88, ++0xDC, 0x82, 0x10, 0xCE, 0x40, 0x3B, 0x01, 0x61, 0x00, 0xB4, 0x32, 0xD0, 0x06, ++0x42, 0x3B, 0x12, 0x21, 0x30, 0xB4, 0x02, 0xD0, 0x4A, 0x42, 0x57, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x61, 0x00, 0x84, 0x20, ++0xD0, 0x0E, 0x40, 0x3B, 0x09, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x86, 0x40, 0x3B, ++0x00, 0xB1, 0x00, 0xA4, 0x21, 0x10, 0x0E, 0x40, 0x38, 0x20, 0xED, 0x08, 0xB6, ++0x03, 0x10, 0x0E, 0x49, 0x2B, 0x00, 0x61, 0x10, 0xB4, 0x02, 0xD1, 0x02, 0x40, ++0x2F, 0x00, 0x29, 0x00, 0xB4, 0x03, 0xD0, 0x02, 0x44, 0x23, 0x02, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0xE1, 0x00, 0x01, 0x07, 0x04, 0x00, 0xD0, ++0x0C, 0x40, 0x73, 0x00, 0xCD, 0x03, 0x34, 0x03, 0xD1, 0x00, 0x44, 0x33, 0x00, ++0x11, 0x00, 0x34, 0x00, 0x14, 0x09, 0x50, 0xB6, 0x10, 0xCD, 0x03, 0x34, 0x02, ++0x14, 0x3C, 0x40, 0xA3, 0x40, 0x41, 0x01, 0x34, 0x4A, 0xD0, 0x20, 0x40, 0x23, ++0x02, 0x01, 0x03, 0x34, 0x6F, 0xD0, 0x11, 0x41, 0x0B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0xA0, 0xC5, 0x00, 0x93, 0x04, 0x47, 0x02, 0xF1, 0x2D, ++0x80, 0xF7, 0x01, 0xDF, 0x07, 0x74, 0x03, 0xF0, 0x01, 0x40, 0x3F, 0x42, 0xD3, ++0x00, 0x6C, 0x02, 0x30, 0x09, 0xC0, 0x3C, 0x00, 0xDF, 0x05, 0x74, 0x02, 0x30, ++0x1D, 0xC4, 0x27, 0x00, 0x53, 0x01, 0x7C, 0x12, 0xF0, 0x25, 0xC0, 0x73, 0x00, ++0xDB, 0x03, 0x7C, 0x0B, 0xF2, 0x69, 0x40, 0x57, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x08, 0x27, 0x03, 0x9F, 0x00, 0x7E, 0x0A, 0xF0, 0x1D, 0xC0, ++0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x39, 0xC0, 0x77, 0x10, 0xDF, 0x03, ++0x5C, 0x0A, 0xF0, 0x29, 0xC0, 0x35, 0x00, 0xDB, 0x10, 0x54, 0x80, 0xF0, 0x0D, ++0xCD, 0x27, 0x01, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0x85, 0xC1, 0xB7, 0x04, 0xDF, ++0x04, 0x7C, 0x02, 0xF0, 0x29, 0xC0, 0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x80, 0x08, 0x0B, 0x00, 0x33, 0x00, 0xFC, 0x82, 0xF0, 0x0F, 0xC1, 0x3F, ++0x24, 0xFF, 0x30, 0xFC, 0x03, 0xF2, 0x03, 0xC4, 0x3B, 0x00, 0x73, 0x05, 0x8D, ++0x02, 0x30, 0x03, 0xC2, 0x3C, 0x04, 0xF3, 0x04, 0xFC, 0x00, 0xF1, 0x0E, 0xC0, ++0x06, 0x00, 0x3F, 0x00, 0xFC, 0x02, 0x70, 0x27, 0xC0, 0x3C, 0x40, 0xF3, 0x02, ++0xCC, 0x01, 0xF1, 0x0B, 0xC0, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x81, 0x20, 0xC6, 0x34, 0x91, 0x13, 0x5C, 0x16, 0xD0, 0x0D, 0x40, 0x37, 0x00, ++0xDD, 0x00, 0x74, 0x03, 0xD9, 0x39, 0x40, 0x37, 0x00, 0x51, 0x04, 0x44, 0x0E, ++0x10, 0x71, 0x40, 0x34, 0x00, 0xD3, 0x01, 0x74, 0x0C, 0xD0, 0x0D, 0x40, 0x44, ++0x00, 0x5D, 0x03, 0x34, 0x17, 0x11, 0x34, 0x40, 0xF4, 0x04, 0x81, 0x00, 0x44, ++0x07, 0xD0, 0x59, 0x48, 0x84, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0xA0, 0x46, 0x00, 0x91, 0x01, 0x74, 0x06, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xDD, ++0x04, 0x74, 0x83, 0xD0, 0x19, 0x40, 0x37, 0x00, 0x91, 0x40, 0x44, 0x06, 0x90, ++0x11, 0x40, 0x34, 0x20, 0xD1, 0x00, 0x74, 0x46, 0xD0, 0x1D, 0x40, 0x66, 0x04, ++0x5D, 0x11, 0x74, 0x06, 0x50, 0x25, 0x40, 0x74, 0x00, 0xD1, 0x00, 0x44, 0x0E, ++0xD0, 0x11, 0x40, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++0x20, 0x00, 0x81, 0x20, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, ++0x34, 0x03, 0xD0, 0x08, 0x40, 0x33, 0x48, 0x81, 0x00, 0x06, 0x00, 0x90, 0x08, ++0x40, 0x30, 0x00, 0xC1, 0x00, 0x34, 0x02, 0xD0, 0x0C, 0x42, 0x20, 0x00, 0x49, ++0x00, 0x74, 0x02, 0x18, 0x04, 0x40, 0x10, 0x00, 0xC1, 0x20, 0x04, 0x02, 0xD0, ++0x08, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++0x40, 0x13, 0x40, 0x7E, 0x00, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x20, 0x7E, ++0x03, 0xD0, 0x01, 0xC2, 0x3F, 0x00, 0x13, 0x00, 0x4C, 0x02, 0xB0, 0x01, 0xC0, ++0x3C, 0x00, 0xD3, 0x00, 0x7C, 0x00, 0xF0, 0x0D, 0xC0, 0x06, 0x00, 0x5F, 0x00, ++0x7C, 0x02, 0x70, 0x05, 0xD0, 0x34, 0x10, 0x53, 0x00, 0x4C, 0x00, 0xF2, 0x01, ++0xD0, 0x04, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x2F, 0x10, ++0xBF, 0x00, 0xDE, 0x00, 0xF0, 0x0F, 0xC6, 0x3F, 0x00, 0xFF, 0x80, 0xFC, 0x03, ++0xD0, 0x03, 0xE0, 0x3F, 0x00, 0x2F, 0x00, 0xF4, 0x00, 0x70, 0x03, 0xD0, 0x3F, ++0x00, 0xF7, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, 0x7F, 0x00, 0xFC, ++0x02, 0xF0, 0x07, 0xC8, 0x3F, 0x00, 0x3F, 0xA0, 0xFD, 0x02, 0xF0, 0x0B, 0xC0, ++0x17, 0x61, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x3F, 0x00, 0xB3, ++0x00, 0xCC, 0x02, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0xCC, 0x03, 0x30, ++0x0A, 0xC0, 0x0C, 0x01, 0x33, 0x00, 0xCC, 0x00, 0xF0, 0x03, 0xC0, 0x0B, 0x00, ++0xFB, 0x06, 0xEC, 0x05, 0x30, 0x4F, 0xC1, 0x2F, 0x00, 0xF3, 0x14, 0xFC, 0x23, ++0xF0, 0x0B, 0xC0, 0x0F, 0x00, 0xF7, 0x04, 0xCC, 0x22, 0x34, 0x03, 0xC0, 0x0C, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x07, 0x10, 0x91, 0x80, ++0x44, 0x00, 0x70, 0x01, 0x40, 0x07, 0x00, 0x9D, 0x00, 0x44, 0x43, 0x10, 0x09, ++0x48, 0x84, 0x00, 0x91, 0x00, 0x44, 0x00, 0xD0, 0x01, 0x40, 0x27, 0x00, 0xF9, ++0x0B, 0x44, 0x55, 0x15, 0x2F, 0x40, 0x6F, 0x00, 0xD1, 0x03, 0x70, 0x3B, 0xD0, ++0x39, 0x40, 0x47, 0x40, 0xF1, 0x00, 0x6C, 0x0A, 0x10, 0x15, 0x40, 0x0D, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x05, 0x01, 0x20, 0x14, ++0x00, 0xD0, 0x00, 0x40, 0x23, 0x00, 0x0D, 0x20, 0x14, 0x13, 0x10, 0x00, 0x40, ++0x01, 0x02, 0x01, 0x20, 0x04, 0x02, 0xD0, 0x08, 0x42, 0x23, 0x00, 0xC1, 0x04, ++0x24, 0x81, 0x10, 0x0C, 0x4A, 0x27, 0x08, 0xCD, 0x00, 0x34, 0x03, 0xD1, 0x88, ++0x40, 0x03, 0x00, 0xC5, 0x08, 0x44, 0xA2, 0x13, 0x08, 0x46, 0x4C, 0x80, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x05, 0x11, 0x11, 0x04, 0x54, 0x04, ++0xD0, 0x11, 0x41, 0x47, 0x00, 0x1D, 0x11, 0x74, 0x03, 0x10, 0x15, 0x40, 0x41, ++0x00, 0x11, 0x01, 0x44, 0x04, 0xD2, 0x31, 0x4C, 0xE7, 0x00, 0xD1, 0x00, 0x64, ++0x21, 0x10, 0x0D, 0x40, 0x27, 0x01, 0xDD, 0x00, 0x74, 0x03, 0xD0, 0x19, 0x48, ++0x87, 0x00, 0xD1, 0x00, 0x64, 0x46, 0x10, 0x0D, 0x40, 0x0D, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x67, 0x00, 0x93, 0x00, 0x5D, 0x46, 0xF0, ++0x39, 0xC0, 0x47, 0x01, 0x1F, 0x03, 0x5C, 0x03, 0x10, 0x29, 0xE1, 0x45, 0x40, ++0x93, 0x05, 0x4C, 0x0C, 0xD0, 0x19, 0xC0, 0xC7, 0x00, 0xDB, 0x00, 0x6C, 0x17, ++0x30, 0x0D, 0x60, 0x23, 0x40, 0xDF, 0x80, 0x7C, 0x03, 0xF2, 0x09, 0xC0, 0xC7, ++0x00, 0xD7, 0x00, 0x0C, 0x0E, 0x30, 0xB1, 0x81, 0x00, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0x80, 0x69, 0x40, 0x9F, 0x01, 0xEC, 0x00, 0x70, 0x0B, ++0xC0, 0x0F, 0x00, 0xAF, 0x20, 0x8C, 0x03, 0xF0, 0x0B, 0xE2, 0x0E, 0x00, 0xAF, ++0x00, 0xFD, 0x00, 0xF0, 0x01, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xDC, 0x06, 0xF8, ++0x0F, 0xC1, 0x6F, 0x00, 0xF2, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0x40, 0x4F, 0x02, ++0xFF, 0x00, 0xDF, 0x02, 0xF0, 0x07, 0xE0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0x83, 0x00, 0x4D, 0x0A, 0xF0, 0x21, 0xC0, ++0x24, 0x81, 0x1F, 0x02, 0x5C, 0x03, 0x30, 0xA5, 0xC0, 0x44, 0x00, 0x1B, 0x00, ++0x7C, 0x0A, 0x32, 0x29, 0xC9, 0xA6, 0x42, 0xC3, 0x00, 0x5C, 0x01, 0x34, 0x0D, ++0xC0, 0x27, 0x80, 0xD3, 0x08, 0x7C, 0x03, 0x30, 0x49, 0xC0, 0x07, 0x10, 0xDF, ++0x00, 0x4C, 0x22, 0x30, 0x09, 0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x2C, 0x14, 0x91, 0x20, 0x44, 0x2A, 0xD0, 0x89, 0x41, 0x84, ++0x00, 0x1D, 0x09, 0xF0, 0x03, 0x30, 0x85, 0x00, 0x24, 0x00, 0x11, 0x1A, 0x74, ++0x82, 0x30, 0x01, 0x40, 0xA4, 0x00, 0xFB, 0x40, 0x44, 0x01, 0x10, 0x0F, 0x40, ++0x27, 0x00, 0xF1, 0x01, 0xF4, 0x03, 0x50, 0x79, 0x40, 0x03, 0x00, 0xFD, 0x24, ++0x54, 0x02, 0xB0, 0x1C, 0x40, 0x6F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0x20, 0x30, 0x08, 0x81, 0x00, 0x20, 0x26, 0xD1, 0x38, 0x40, 0x60, 0x20, ++0x8D, 0x20, 0x34, 0x03, 0x10, 0x39, 0x40, 0x00, 0x00, 0x09, 0x03, 0x16, 0x02, ++0x10, 0x20, 0x40, 0x04, 0x01, 0xC1, 0x00, 0x54, 0x02, 0x10, 0x3C, 0x40, 0x31, ++0x00, 0xC8, 0x01, 0x14, 0x03, 0x90, 0x28, 0x40, 0x13, 0x00, 0xD9, 0x00, 0x06, ++0x03, 0x10, 0x8C, 0x40, 0x5F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x02, 0x50, 0x00, 0xE1, 0x01, 0xA4, 0x07, 0xD0, 0x16, 0x60, 0x7A, 0x20, 0xED, ++0x01, 0xB4, 0x03, 0x90, 0x1E, 0x40, 0x40, 0x00, 0xE1, 0x41, 0xB6, 0x0D, 0x94, ++0x16, 0x42, 0x4A, 0x00, 0xC9, 0x01, 0x84, 0x05, 0x10, 0x1E, 0x40, 0x7B, 0x00, ++0xE9, 0x01, 0xB4, 0x27, 0xD0, 0x1A, 0x40, 0x5B, 0x00, 0xCD, 0x01, 0x16, 0x26, ++0x90, 0x9A, 0x40, 0x3F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, ++0x30, 0x02, 0x01, 0x00, 0x0D, 0x01, 0xF0, 0x8D, 0xC0, 0x30, 0x04, 0xCD, 0x30, ++0x7C, 0x23, 0x10, 0x08, 0xC0, 0x00, 0x01, 0x0B, 0x00, 0x7C, 0x0B, 0x30, 0x88, ++0xC0, 0x12, 0x02, 0xC3, 0x00, 0x5C, 0x22, 0x32, 0x0C, 0xC1, 0x23, 0x00, 0xC9, ++0x08, 0x7C, 0x03, 0x30, 0x08, 0xC0, 0x23, 0x00, 0xCF, 0x00, 0x0C, 0x03, 0x30, ++0x04, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x1D, ++0x14, 0x7F, 0x00, 0xDD, 0x01, 0xF2, 0x87, 0xD0, 0x3D, 0x00, 0xFF, 0x08, 0xFC, ++0x13, 0x70, 0x0F, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0xFC, 0x01, 0x70, 0x0F, 0xC8, ++0x1D, 0x40, 0xFF, 0x10, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0xAB, 0x42, 0xF7, 0x20, ++0xFC, 0x03, 0x70, 0x0B, 0xC8, 0x2F, 0x12, 0xFC, 0x00, 0xFC, 0x02, 0xF0, 0x03, ++0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x27, 0x00, ++0xDF, 0x00, 0x4E, 0x03, 0x31, 0x0D, 0xC0, 0x17, 0x00, 0x5F, 0x01, 0xCC, 0x03, ++0xF0, 0x0D, 0xC0, 0x04, 0x00, 0xD3, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, 0x1F, ++0x20, 0xDF, 0x06, 0x5C, 0x00, 0xF0, 0x2D, 0xC1, 0xB6, 0x00, 0xD3, 0x00, 0x7C, ++0x03, 0xA8, 0x1D, 0xC0, 0x15, 0x00, 0xDF, 0x06, 0x4D, 0x01, 0x30, 0x1D, 0xC0, ++0x54, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x29, 0x09, 0xED, ++0x20, 0xC4, 0x03, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xFD, 0x00, 0x84, 0x07, 0xD0, ++0x0C, 0x40, 0x08, 0x00, 0xE1, 0x00, 0xB4, 0x03, 0xD8, 0x0E, 0x40, 0x3B, 0x08, ++0xFD, 0x10, 0xAC, 0x00, 0xD0, 0x2E, 0x44, 0x3B, 0x00, 0xE1, 0x02, 0xF4, 0x03, ++0x10, 0x0E, 0x40, 0x18, 0x00, 0xED, 0x16, 0xC4, 0x02, 0xB0, 0x0A, 0xC0, 0x4E, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xF9, 0x00, 0xED, 0x81, ++0x84, 0x07, 0x11, 0x1E, 0x48, 0xFB, 0x08, 0xED, 0x11, 0x84, 0x07, 0xD0, 0x1E, ++0x40, 0x48, 0x00, 0xE1, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x41, 0xFB, 0x00, 0xED, ++0x05, 0x94, 0x44, 0xD9, 0x5E, 0x40, 0x73, 0x00, 0xE5, 0x05, 0xB4, 0x07, 0x90, ++0x1C, 0x44, 0x79, 0x00, 0xED, 0x41, 0x84, 0x07, 0x10, 0x14, 0x40, 0x04, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0xB3, 0x04, 0xCD, 0x02, 0x05, ++0x83, 0x12, 0x6C, 0x60, 0x73, 0x10, 0xCD, 0x03, 0x04, 0x03, 0xD0, 0x1C, 0x50, ++0x30, 0x02, 0xC1, 0x09, 0x34, 0x0B, 0xD0, 0x3C, 0x44, 0x73, 0x01, 0xCD, 0x40, ++0x24, 0x04, 0xD8, 0x0C, 0x40, 0x73, 0x80, 0xC5, 0x00, 0x34, 0x03, 0x10, 0x0C, ++0x42, 0x30, 0x00, 0xCD, 0x00, 0x24, 0x02, 0x90, 0x00, 0x50, 0x4A, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x5D, 0x00, 0x7F, 0x00, 0xCC, 0x05, ++0x30, 0x27, 0xC0, 0x1F, 0x00, 0x7F, 0x08, 0x4D, 0x01, 0xF0, 0x17, 0xC1, 0x5C, ++0x40, 0x73, 0x01, 0xFC, 0x01, 0xF0, 0x27, 0x40, 0x5F, 0x00, 0x5F, 0x00, 0xDC, ++0x01, 0xF0, 0x05, 0xC0, 0x56, 0x41, 0x57, 0x00, 0x7C, 0x01, 0xB0, 0x05, 0xC0, ++0x1D, 0x89, 0x5F, 0x00, 0x8C, 0x01, 0x30, 0x07, 0xC0, 0x5C, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x81, 0x08, 0x1F, 0x10, 0x7C, 0x24, 0xF4, ++0xA1, 0xC0, 0x07, 0x04, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC4, 0x47, 0x08, ++0x1F, 0x26, 0x7C, 0x00, 0xF0, 0x41, 0xC2, 0x87, 0x00, 0x0F, 0x00, 0x7C, 0x00, ++0xF2, 0x00, 0xC0, 0x07, 0x00, 0x1B, 0x00, 0x7C, 0x00, 0x70, 0x01, 0xC0, 0x03, ++0x00, 0x1F, 0x00, 0x5C, 0x04, 0xF0, 0x01, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x83, 0x00, 0x0C, 0x02, 0x30, 0x89, ++0xC0, 0x27, 0x00, 0x9F, 0x01, 0x7C, 0x02, 0xF0, 0x09, 0xD0, 0x60, 0x02, 0x93, ++0x01, 0x7C, 0x46, 0xF0, 0x59, 0xC0, 0x23, 0x00, 0x9B, 0x00, 0x4C, 0x42, 0xB0, ++0x09, 0xC0, 0x22, 0x01, 0x93, 0x00, 0x3C, 0x02, 0x90, 0x49, 0xC0, 0xA7, 0x40, ++0x93, 0x00, 0x4D, 0x02, 0x14, 0x09, 0xC0, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x00, 0xE4, 0x21, 0x91, 0x00, 0x44, 0x0E, 0x14, 0x29, 0xC0, ++0x25, 0x02, 0x9D, 0x1B, 0x74, 0x02, 0xD0, 0x09, 0xC0, 0x24, 0x00, 0x95, 0x12, ++0x5C, 0x22, 0xD2, 0x19, 0x40, 0x67, 0x00, 0x91, 0x80, 0x44, 0x02, 0x10, 0x29, ++0x41, 0x64, 0x00, 0x91, 0x00, 0x74, 0x02, 0x50, 0x39, 0x41, 0x67, 0x00, 0x91, ++0x02, 0x44, 0x02, 0x10, 0x09, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x64, 0x00, 0x91, 0x00, 0x44, 0x22, 0x10, 0x09, 0x41, 0x27, ++0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x08, 0x40, 0x24, 0x00, 0x99, 0x08, 0x74, ++0x02, 0xD0, 0x09, 0x40, 0x27, 0x01, 0x99, 0x00, 0x04, 0x82, 0x94, 0x09, 0x40, ++0x26, 0x00, 0x95, 0x00, 0x74, 0x02, 0x50, 0x09, 0x40, 0x27, 0x20, 0x89, 0x42, ++0x44, 0x02, 0x50, 0x09, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x20, 0x20, 0x01, 0x81, 0x04, 0x04, 0x12, 0x10, 0x08, 0x40, 0x21, 0x82, ++0x8D, 0x10, 0x34, 0x12, 0xD0, 0x58, 0x40, 0x20, 0x01, 0x8D, 0x10, 0x14, 0x42, ++0xD0, 0x78, 0x41, 0x33, 0x06, 0x81, 0x00, 0x04, 0x02, 0x10, 0x48, 0x40, 0x20, ++0x01, 0x85, 0x04, 0x34, 0x52, 0x59, 0x48, 0x40, 0x23, 0x01, 0x89, 0x04, 0x44, ++0x12, 0x50, 0x48, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB8, 0x86, 0x42, 0x03, 0x0A, 0x45, 0x31, 0x30, 0xE1, 0x40, 0x97, 0x04, 0x1F, ++0x08, 0x7C, 0x28, 0xF0, 0xA1, 0xC0, 0x80, 0x02, 0x1B, 0x06, 0x7C, 0x19, 0xF0, ++0x21, 0xC0, 0x87, 0x01, 0x1B, 0x1E, 0x4C, 0x28, 0xB1, 0xA1, 0xC0, 0x06, 0x40, ++0x17, 0x00, 0x7C, 0x20, 0xF0, 0x01, 0x80, 0x07, 0x00, 0x0B, 0x0A, 0x4C, 0x28, ++0x70, 0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, ++0x2F, 0x0A, 0xBF, 0x08, 0xFC, 0x0A, 0xF2, 0xCB, 0xC0, 0x2D, 0x00, 0xBF, 0x00, ++0x7C, 0x22, 0xF0, 0x8B, 0xC8, 0x2D, 0x02, 0xB7, 0x14, 0xDC, 0x52, 0xF0, 0x0B, ++0xC2, 0x3F, 0x00, 0x9F, 0x00, 0xFD, 0x83, 0xF0, 0x89, 0xC0, 0x2F, 0x02, 0x9B, ++0x08, 0x7C, 0x02, 0x70, 0x8B, 0xC8, 0x2E, 0x02, 0x97, 0x08, 0xFC, 0x22, 0xB0, ++0x8B, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA8, 0x2F, ++0x05, 0xD3, 0x4C, 0xCC, 0x02, 0xF1, 0x0B, 0xC0, 0x2F, 0x02, 0xB3, 0x04, 0xFC, ++0x52, 0x30, 0xCB, 0xC0, 0x2C, 0x00, 0xB3, 0x00, 0xCC, 0x22, 0xF0, 0x4B, 0xC0, ++0x2D, 0x05, 0x9F, 0x0C, 0x5C, 0x02, 0xB0, 0x0B, 0xC0, 0x2C, 0x00, 0xB3, 0x05, ++0x5C, 0x16, 0xB0, 0x0F, 0xC0, 0x2C, 0x00, 0xBF, 0x80, 0xCD, 0x02, 0x31, 0x0B, ++0xC0, 0x64, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x01, ++0x11, 0x0C, 0x45, 0x48, 0xD0, 0x01, 0x41, 0x07, 0x02, 0x11, 0x54, 0x74, 0x00, ++0x38, 0xC1, 0xC0, 0x90, 0x04, 0x11, 0x10, 0x44, 0x20, 0xD2, 0x41, 0x41, 0x07, ++0x21, 0x1D, 0x0C, 0x44, 0x40, 0x40, 0x01, 0x41, 0x04, 0x02, 0x1B, 0x00, 0x70, ++0x54, 0x10, 0x01, 0xC0, 0x96, 0x00, 0x03, 0x10, 0x45, 0x20, 0x50, 0x01, 0x40, ++0x71, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x05, 0x81, ++0x04, 0x04, 0x32, 0xD0, 0x88, 0x60, 0x23, 0x00, 0x81, 0x2C, 0x36, 0x02, 0x18, ++0x4C, 0x62, 0x21, 0x4B, 0x80, 0x08, 0x24, 0x02, 0xD0, 0xC8, 0x40, 0x21, 0x2D, ++0x8D, 0x44, 0x74, 0x12, 0x80, 0x88, 0x50, 0x20, 0x00, 0x85, 0x02, 0x14, 0x0A, ++0x50, 0x0C, 0x48, 0x22, 0x12, 0x8D, 0x08, 0x24, 0x02, 0x10, 0x08, 0x40, 0x48, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0x91, 0x82, ++0x44, 0x42, 0xD0, 0x0D, 0x40, 0x27, 0x05, 0x91, 0x00, 0x74, 0x02, 0x10, 0x49, ++0x40, 0x25, 0x01, 0xD1, 0x00, 0x64, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x02, 0x8D, ++0x00, 0x64, 0x02, 0x10, 0x08, 0x40, 0x24, 0x01, 0x9D, 0x00, 0x74, 0x02, 0x50, ++0x0D, 0x40, 0x26, 0x00, 0x91, 0x00, 0x64, 0x02, 0x50, 0x29, 0x40, 0x61, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, 0x25, 0x42, 0x93, 0x00, 0x4D, ++0x02, 0xF0, 0x79, 0xC0, 0x67, 0x40, 0x93, 0x11, 0x7C, 0x02, 0x34, 0x39, 0xC1, ++0x25, 0x00, 0x93, 0x10, 0x6D, 0x4E, 0xF0, 0x69, 0xC0, 0xE5, 0x00, 0x9F, 0x00, ++0x7C, 0x8A, 0xB0, 0x09, 0xC0, 0x64, 0x00, 0x97, 0x00, 0x5C, 0x02, 0x70, 0x09, ++0xC0, 0xA6, 0x00, 0x9F, 0x00, 0x6D, 0x1A, 0x30, 0x29, 0xC0, 0x14, 0xA0, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x65, 0x00, 0x9F, 0x20, 0x7C, 0x26, ++0xF0, 0x49, 0xC0, 0x27, 0x00, 0x9F, 0x04, 0x3C, 0x02, 0xF0, 0x19, 0xD0, 0x24, ++0x00, 0x9F, 0x00, 0x4C, 0x26, 0xF0, 0x09, 0xC0, 0x67, 0x84, 0x9F, 0x00, 0x5C, ++0x22, 0x70, 0x09, 0xC0, 0x67, 0x08, 0x9B, 0x00, 0x7C, 0x02, 0x34, 0x09, 0xC0, ++0x67, 0x82, 0x9F, 0x00, 0x5D, 0x02, 0xF0, 0x09, 0xC0, 0x5B, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x01, 0x00, 0x0F, 0x00, 0x4E, 0x48, 0xF2, ++0x41, 0xE4, 0x87, 0x01, 0x1F, 0x08, 0x7C, 0x80, 0x70, 0x00, 0xC0, 0x84, 0x00, ++0x13, 0x01, 0x7C, 0x00, 0xF8, 0x21, 0xC4, 0x87, 0x08, 0x1F, 0x00, 0x5C, 0x08, ++0xF0, 0x01, 0xC0, 0x03, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x41, 0xC0, 0x87, ++0x40, 0x13, 0x00, 0x0C, 0x00, 0xF0, 0xA0, 0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x1C, 0x00, 0x5D, 0x20, 0xC6, 0x1D, 0x70, 0x27, ++0x40, 0x5F, 0x04, 0x7D, 0x08, 0x74, 0x15, 0xD0, 0x27, 0xC0, 0x14, 0x00, 0x71, ++0x00, 0xDC, 0x09, 0xF0, 0x37, 0x60, 0x9F, 0x00, 0x5D, 0x00, 0x04, 0x01, 0x30, ++0x47, 0x40, 0x17, 0x40, 0x52, 0x00, 0x5C, 0x01, 0xD0, 0x26, 0x40, 0x17, 0x04, ++0x74, 0x82, 0x44, 0x01, 0xD0, 0x05, 0x40, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA0, 0xF2, 0x04, 0xCD, 0x00, 0x24, 0x0F, 0x50, 0x8C, 0x40, ++0x77, 0x00, 0xCD, 0x03, 0x34, 0x03, 0xD0, 0x2C, 0x41, 0x36, 0x00, 0xD1, 0x20, ++0x34, 0x47, 0xD2, 0x0C, 0x41, 0xB3, 0x00, 0xCD, 0x00, 0x14, 0x03, 0x50, 0x1C, ++0x40, 0x23, 0x08, 0x88, 0x20, 0x74, 0x03, 0xD0, 0x20, 0x60, 0x63, 0x00, 0x90, ++0x12, 0x05, 0x03, 0xD0, 0x1C, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x80, 0xA8, 0x10, 0xED, 0x00, 0xA4, 0x01, 0x50, 0x0E, 0x40, 0x3B, ++0x20, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0B, 0x60, 0x28, 0x00, 0xE1, 0x00, 0x94, ++0x09, 0x10, 0x0E, 0x41, 0x9B, 0x08, 0xCD, 0x04, 0xC4, 0x13, 0x12, 0x06, 0x40, ++0x2B, 0x00, 0xE9, 0x00, 0xB6, 0x03, 0xD0, 0x06, 0x40, 0x63, 0x00, 0xE5, 0x00, ++0x84, 0x02, 0xD0, 0x0E, 0x60, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x18, 0x48, 0x10, 0xFF, 0x01, 0xA5, 0x07, 0x70, 0x1E, 0x40, 0x5B, 0x00, ++0xED, 0x01, 0xBC, 0x87, 0xF0, 0x16, 0xC0, 0x7A, 0x42, 0xE1, 0x01, 0xBC, 0x07, ++0xD0, 0x16, 0x40, 0x7B, 0x00, 0xEF, 0x09, 0x9D, 0x5F, 0x70, 0x16, 0xE4, 0x73, ++0x00, 0xAB, 0x01, 0xBC, 0x07, 0xF0, 0x12, 0x80, 0x7B, 0x00, 0x21, 0x01, 0x8C, ++0x07, 0xF0, 0x1E, 0xD0, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xB8, 0x05, 0x00, 0xDF, 0x16, 0x5C, 0x01, 0x70, 0x0D, 0xC0, 0x17, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xA1, 0x42, 0xD1, 0x37, 0x20, 0x1F, 0x00, 0x7C, 0x01, 0xF0, ++0x05, 0xC0, 0x27, 0x00, 0xDF, 0x08, 0x3C, 0x1B, 0x70, 0x05, 0xC0, 0x37, 0x40, ++0xD3, 0x00, 0x5C, 0x83, 0xF0, 0x0D, 0x80, 0x37, 0x00, 0x5B, 0x20, 0x7C, 0x02, ++0xF0, 0x0C, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, ++0x4D, 0x00, 0xF7, 0x31, 0xCC, 0x13, 0xF0, 0x97, 0xC0, 0x7C, 0x00, 0xFF, 0x01, ++0xFC, 0x06, 0xB0, 0x9F, 0xC0, 0x7C, 0x00, 0x73, 0x09, 0xFC, 0x27, 0xF0, 0x1F, ++0xC0, 0x7F, 0x00, 0xFF, 0x81, 0xCC, 0x07, 0x70, 0x9F, 0xC0, 0x6C, 0x40, 0xB7, ++0x41, 0xCC, 0x07, 0xB0, 0x1A, 0xC0, 0x6C, 0x20, 0xBF, 0x21, 0xCC, 0x07, 0xF0, ++0x1B, 0xC0, 0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x0D, ++0x00, 0xEB, 0x00, 0x84, 0x03, 0xD0, 0x8E, 0x40, 0x38, 0x00, 0xED, 0x00, 0xB4, ++0x22, 0xD0, 0xC6, 0x50, 0x28, 0x30, 0x60, 0x18, 0x9C, 0x23, 0xD0, 0x0E, 0xC0, ++0x39, 0x02, 0xED, 0x04, 0x84, 0x13, 0x40, 0x03, 0xC0, 0x2A, 0x00, 0xE5, 0x00, ++0xAC, 0x23, 0x10, 0x0E, 0xC2, 0x2A, 0x00, 0xE9, 0x00, 0x85, 0x42, 0xD0, 0x0E, ++0x40, 0x57, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, ++0xE5, 0x10, 0x84, 0x23, 0xD0, 0x06, 0x42, 0x18, 0x04, 0x6D, 0x00, 0xB4, 0x02, ++0xD0, 0x06, 0x42, 0x38, 0x00, 0x61, 0x80, 0xB4, 0x02, 0xD0, 0x8A, 0x40, 0xBB, ++0x00, 0xED, 0x20, 0xC4, 0x4B, 0x42, 0x06, 0x40, 0x32, 0x00, 0xA5, 0x00, 0xA4, ++0x03, 0x90, 0x02, 0x40, 0x28, 0x00, 0xA5, 0x08, 0xA4, 0x03, 0xD0, 0x0A, 0x40, ++0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x01, 0x00, 0xD1, ++0x01, 0x04, 0x02, 0xD0, 0x28, 0x50, 0x80, 0x04, 0x8D, 0x47, 0x34, 0x02, 0xD0, ++0x05, 0x58, 0x34, 0x42, 0x01, 0x91, 0x14, 0xCE, 0xD0, 0x39, 0x40, 0x01, 0x20, ++0xCD, 0x00, 0x04, 0x07, 0x00, 0x00, 0x40, 0x32, 0x40, 0xC5, 0x00, 0x24, 0x03, ++0x10, 0x0C, 0x40, 0x22, 0x00, 0xC9, 0x00, 0x24, 0x0E, 0xD0, 0x8C, 0x40, 0x1B, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x05, 0x06, 0xF5, 0x20, ++0x4C, 0x02, 0xF0, 0xB9, 0xC1, 0xA4, 0x00, 0x1F, 0x05, 0x74, 0x82, 0xB0, 0x09, ++0xC0, 0x74, 0x00, 0x93, 0x03, 0x7C, 0x42, 0xD0, 0x39, 0xC1, 0xB7, 0x00, 0xFF, ++0x00, 0xCC, 0x07, 0x70, 0x05, 0xC0, 0x26, 0x40, 0x85, 0x00, 0xEC, 0x03, 0xB0, ++0x01, 0xC8, 0x24, 0x00, 0x57, 0x80, 0x6C, 0x0E, 0xF0, 0x0D, 0xC0, 0x57, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x07, 0x20, 0xDF, 0x00, 0x7C, ++0x28, 0xF0, 0x21, 0xC0, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x02, 0xF2, 0x19, 0xC0, ++0x27, 0x04, 0x9F, 0x02, 0x7C, 0x00, 0xF0, 0x41, 0xC0, 0x17, 0x00, 0xCF, 0x00, ++0x7D, 0x03, 0xF0, 0x05, 0xC0, 0x23, 0x40, 0x9E, 0x00, 0x7C, 0x03, 0xF0, 0x01, ++0xC0, 0x27, 0x00, 0x5C, 0x00, 0x1C, 0x02, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x0B, 0x00, 0xFB, 0x00, 0xCC, 0x42, ++0xF0, 0x09, 0xC0, 0x2B, 0x00, 0xB3, 0x00, 0xFC, 0x02, 0xF0, 0x01, 0xC0, 0x34, ++0x00, 0xB3, 0x00, 0xB4, 0x00, 0x30, 0x03, 0xC0, 0x3C, 0x00, 0xDF, 0x00, 0xCC, ++0x03, 0xF0, 0x06, 0xC0, 0xEC, 0x00, 0x93, 0x08, 0x0C, 0x03, 0x34, 0x53, 0x40, ++0x38, 0x00, 0xE3, 0xC0, 0xCC, 0x56, 0x31, 0x0F, 0xC0, 0x07, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xC6, 0x01, 0xD1, 0x00, 0x44, 0x14, 0xD0, ++0x39, 0x40, 0x47, 0x01, 0x91, 0x01, 0x74, 0x02, 0xC8, 0x11, 0x50, 0x34, 0x00, ++0x1F, 0x83, 0x74, 0x0C, 0x12, 0x31, 0x44, 0xC4, 0x0C, 0xDF, 0x00, 0x54, 0x03, ++0xF0, 0x25, 0x44, 0x24, 0x00, 0x91, 0x01, 0x45, 0x03, 0xB0, 0x04, 0x40, 0x35, ++0x00, 0xD3, 0x03, 0x54, 0x02, 0x10, 0x0D, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0xA0, 0x46, 0x40, 0xD1, 0x00, 0x44, 0x04, 0xD0, 0x11, ++0x40, 0x67, 0x00, 0x11, 0x11, 0x76, 0x06, 0xD1, 0x19, 0x54, 0x34, 0x00, 0x91, ++0x01, 0x76, 0x46, 0x10, 0x39, 0x60, 0x64, 0x10, 0xDD, 0x40, 0x44, 0x03, 0xD0, ++0x25, 0x40, 0x24, 0x18, 0x91, 0x40, 0x54, 0x03, 0x10, 0x0D, 0x40, 0x25, 0x40, ++0xD1, 0x0A, 0x44, 0x02, 0x10, 0x09, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0xC1, 0x40, 0x04, 0x00, 0xD0, 0x00, 0x42, ++0x23, 0x00, 0x01, 0x00, 0x34, 0x02, 0xD0, 0x00, 0x40, 0x20, 0x00, 0x81, 0x00, ++0x34, 0x02, 0x10, 0x00, 0x70, 0x00, 0x00, 0xC5, 0x00, 0x14, 0x03, 0x10, 0x00, ++0x50, 0x20, 0x20, 0x81, 0x00, 0x14, 0x03, 0x90, 0x0C, 0x48, 0x21, 0x00, 0xC9, ++0x80, 0x14, 0x02, 0x10, 0x0C, 0x4C, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0x06, 0x00, 0xE3, 0x00, 0x4C, 0x02, 0xD0, 0x01, 0xC2, 0x27, ++0x00, 0x13, 0x00, 0x7E, 0x02, 0xC0, 0x03, 0xC0, 0x3C, 0x40, 0x91, 0x00, 0x7C, ++0x00, 0x38, 0x09, 0xC0, 0x24, 0x00, 0xFC, 0x00, 0xCC, 0x83, 0xD0, 0x05, 0xC0, ++0x24, 0x40, 0x93, 0x40, 0x5C, 0x03, 0x10, 0x09, 0xC0, 0x25, 0x00, 0xC3, 0x80, ++0x4C, 0x02, 0x34, 0x09, 0xC0, 0x07, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xB8, 0x0D, 0x00, 0xF7, 0x00, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x2F, 0x40, ++0xBF, 0x00, 0xFC, 0x02, 0xF0, 0x03, 0xC0, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x00, ++0xF0, 0x03, 0xC4, 0x0F, 0x00, 0xFF, 0x00, 0xB8, 0x03, 0xF0, 0x03, 0xC4, 0x2F, ++0x40, 0xBF, 0x00, 0xEC, 0x03, 0x70, 0x0F, 0xC0, 0x2F, 0x00, 0xF7, 0x00, 0xFC, ++0x02, 0xF0, 0x0F, 0xC0, 0x17, 0xE0, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x80, 0x7F, 0x00, 0xBF, 0x20, 0xCC, 0x13, 0x70, 0x1F, 0xC0, 0x7F, 0x02, 0xF3, ++0x01, 0xCC, 0x07, 0x30, 0x1F, 0xC0, 0x7B, 0x00, 0xFF, 0x01, 0x8C, 0x07, 0x30, ++0x1F, 0xC0, 0x7D, 0x00, 0xF3, 0x01, 0xCC, 0x07, 0x30, 0x1F, 0xC0, 0x7F, 0x00, ++0xF3, 0x03, 0xEC, 0x07, 0xB0, 0x16, 0xC0, 0x5C, 0x00, 0x2B, 0x01, 0xEC, 0x05, ++0x30, 0x0B, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, ++0x37, 0x00, 0x9D, 0x00, 0xEC, 0x0B, 0x10, 0x01, 0x40, 0x07, 0x01, 0x11, 0x00, ++0x44, 0x00, 0x14, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x20, 0x40, 0x00, 0x10, 0x01, ++0x40, 0x04, 0x00, 0x13, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x07, 0x00, 0x11, ++0x84, 0x4C, 0x04, 0x52, 0x1D, 0x40, 0x55, 0x00, 0x11, 0x01, 0x54, 0x03, 0xB4, ++0x01, 0x40, 0x0D, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, ++0x00, 0x8D, 0x00, 0x04, 0x23, 0xD0, 0x0C, 0x60, 0x33, 0x01, 0xC1, 0x00, 0x44, ++0x83, 0x10, 0x0C, 0x40, 0x33, 0x00, 0xDD, 0x00, 0x04, 0x03, 0x10, 0x0D, 0x48, ++0x34, 0x80, 0xC1, 0x00, 0x44, 0x03, 0x10, 0x0C, 0x40, 0x35, 0x00, 0xC1, 0x04, ++0x64, 0x03, 0x10, 0x04, 0x44, 0x16, 0x80, 0x59, 0x00, 0x66, 0x83, 0x5C, 0x00, ++0x44, 0x4C, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, ++0x9D, 0x21, 0x44, 0x03, 0x91, 0x01, 0x60, 0x03, 0x00, 0x11, 0x00, 0x60, 0x00, ++0x10, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, ++0x80, 0x19, 0x20, 0x44, 0x00, 0x10, 0x01, 0x40, 0x06, 0x00, 0x11, 0x00, 0x44, ++0x00, 0x50, 0x1D, 0x4C, 0x17, 0x04, 0x51, 0x10, 0x54, 0x0B, 0xDC, 0x11, 0x40, ++0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x37, 0x00, 0x1F, ++0x33, 0x44, 0x03, 0xD0, 0x0D, 0xC0, 0x37, 0x10, 0xD3, 0x00, 0x4C, 0x03, 0x30, ++0x0D, 0xC0, 0x37, 0x00, 0xDD, 0x00, 0x4D, 0x03, 0x34, 0x0C, 0xC0, 0x30, 0x00, ++0xD3, 0x20, 0x0C, 0x03, 0x10, 0x0D, 0xC0, 0x31, 0x00, 0xD3, 0x00, 0x2C, 0x03, ++0xB0, 0x18, 0xC0, 0x92, 0x00, 0x9B, 0x01, 0x2C, 0x0B, 0x70, 0x59, 0xC2, 0x00, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x10, 0xAF, 0x00, ++0xFC, 0x03, 0x72, 0x03, 0xCB, 0x0F, 0x00, 0x3F, 0x00, 0xDC, 0x00, 0xF0, 0x03, ++0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC8, 0x0E, 0x04, 0x37, ++0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x04, 0x3F, 0x00, 0xFC, 0x00, 0xF0, ++0x0F, 0xC0, 0x8D, 0x10, 0xBF, 0x08, 0xFC, 0x23, 0xB0, 0x09, 0xC0, 0x3F, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x06, 0x1F, 0x00, 0x7C, ++0x03, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xDF, 0x01, 0x7C, 0x43, 0xF0, 0x0D, 0xC0, ++0x34, 0x1B, 0xD3, 0x00, 0x4C, 0x47, 0x30, 0x1D, 0xC0, 0x77, 0x00, 0xD7, 0x01, ++0x7C, 0x47, 0xF0, 0x0D, 0xC0, 0x34, 0x02, 0xDF, 0x00, 0x4D, 0x43, 0x30, 0x0D, ++0xC0, 0x35, 0x00, 0x9F, 0x06, 0x4C, 0x0B, 0x30, 0x01, 0xC0, 0x29, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x74, 0x10, 0x9D, 0x08, 0xF4, 0x03, ++0xD1, 0x21, 0x40, 0x04, 0x00, 0x1D, 0x03, 0x1C, 0x00, 0xD0, 0x81, 0x40, 0xC4, ++0x00, 0x01, 0x00, 0x44, 0x0C, 0x12, 0x31, 0x40, 0x47, 0x00, 0x15, 0x03, 0x74, ++0x04, 0xD0, 0x21, 0x40, 0x44, 0x00, 0x1D, 0x0B, 0x46, 0x40, 0xB2, 0xAD, 0x48, ++0xC4, 0x22, 0x8B, 0x07, 0x6C, 0x0B, 0xA0, 0x91, 0xC0, 0x4C, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0xF2, 0x00, 0x0D, 0x09, 0x74, 0x17, 0xD0, ++0x0C, 0x40, 0x32, 0x00, 0xDD, 0x04, 0x34, 0x0B, 0xD0, 0x2C, 0x40, 0xF0, 0x00, ++0xC1, 0x0C, 0x54, 0x03, 0x14, 0x4C, 0x40, 0x33, 0x00, 0xD9, 0x04, 0x34, 0x0B, ++0xD0, 0x4C, 0x40, 0xB0, 0x20, 0xD9, 0x00, 0x04, 0x0B, 0x10, 0x24, 0x40, 0x53, ++0x00, 0xC1, 0x01, 0x24, 0x22, 0x90, 0x99, 0x40, 0x0F, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x80, 0x78, 0x00, 0x6D, 0x01, 0xB4, 0x47, 0xD8, 0x13, ++0x40, 0x4A, 0x00, 0x2D, 0x01, 0xB4, 0x04, 0xD0, 0x12, 0x40, 0x4C, 0x00, 0x21, ++0x01, 0xC4, 0x04, 0x10, 0x12, 0x40, 0x4F, 0x00, 0x2D, 0x08, 0xB4, 0x00, 0xD0, ++0x12, 0x40, 0x48, 0x00, 0x2D, 0x31, 0x84, 0x04, 0x90, 0x9F, 0x44, 0x5E, 0x08, ++0x79, 0x21, 0xA4, 0x0F, 0x90, 0x12, 0x48, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xCF, 0x00, 0x3C, 0x23, 0xF0, 0x0C, 0xC0, ++0x32, 0x00, 0xCF, 0x00, 0x3C, 0x03, 0xF0, 0x0D, 0xC0, 0x30, 0x00, 0xD3, 0x00, ++0x1C, 0x03, 0x30, 0x0C, 0xC0, 0x37, 0x80, 0xC9, 0x00, 0x3C, 0x03, 0xD0, 0x0D, ++0x40, 0x30, 0x00, 0xDD, 0x00, 0x04, 0x23, 0x30, 0x04, 0xC0, 0x13, 0x14, 0xC3, ++0x00, 0x4C, 0x23, 0xB0, 0x88, 0xC6, 0x4B, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xB8, 0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x83, 0xF0, 0x02, 0xC0, 0x0D, ++0x00, 0x3F, 0x00, 0xDC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x02, 0x3F, 0x08, 0x7C, ++0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x36, 0x08, 0xFC, 0x10, 0xF0, 0x01, 0x80, ++0x0F, 0x00, 0x3E, 0x00, 0xBC, 0x84, 0xF9, 0x0F, 0xC8, 0x19, 0x00, 0x7F, 0x00, ++0xFC, 0x23, 0xF0, 0x03, 0xC8, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0xA0, 0x37, 0x10, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, ++0xDF, 0x00, 0x7C, 0x07, 0x34, 0x1D, 0xD0, 0x30, 0x00, 0xD3, 0x01, 0x4D, 0x03, ++0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x70, 0x1D, 0xD0, 0x34, ++0x00, 0xD7, 0x00, 0x4C, 0x03, 0xF0, 0x1C, 0xD0, 0x54, 0x00, 0xD3, 0x00, 0x4C, ++0x03, 0xD1, 0x09, 0xC0, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x88, 0x39, 0x00, 0x6D, 0x00, 0xB4, 0x2B, 0xD0, 0x02, 0x40, 0x0B, 0x00, 0x2D, ++0x00, 0xF4, 0x00, 0x10, 0x03, 0x40, 0x08, 0x00, 0x31, 0x00, 0x84, 0x00, 0xD0, ++0x02, 0x40, 0x0B, 0x00, 0x2D, 0x00, 0xB4, 0x00, 0xD0, 0x03, 0x40, 0x08, 0x10, ++0x2D, 0x00, 0xA4, 0x00, 0xD0, 0x0E, 0x40, 0x18, 0x40, 0xE1, 0x00, 0x94, 0x03, ++0xD0, 0x0E, 0x40, 0x4F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, ++0x79, 0x00, 0xED, 0x03, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x01, ++0xB4, 0x07, 0x10, 0x1E, 0x40, 0x7C, 0x00, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x1E, ++0x40, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x78, 0x00, 0xED, ++0x01, 0xA5, 0x07, 0xD0, 0x1F, 0x49, 0x58, 0x80, 0xF5, 0x01, 0x84, 0x07, 0xD0, ++0x1E, 0x42, 0x13, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, ++0x00, 0xDD, 0x01, 0x34, 0x03, 0xD0, 0x01, 0x40, 0x03, 0x00, 0x0D, 0x00, 0x34, ++0x00, 0x10, 0x00, 0x40, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0xD0, 0x00, 0x44, ++0x07, 0x00, 0x0D, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x40, 0x00, 0x00, 0x0D, 0x00, ++0x24, 0x00, 0xD0, 0x5C, 0x44, 0xD0, 0x01, 0xC5, 0x13, 0x14, 0x4F, 0xD8, 0x5D, ++0x40, 0x5B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, 0x00, ++0x7F, 0x02, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, 0x01, ++0x30, 0x05, 0xC0, 0x14, 0x50, 0x53, 0x00, 0x4C, 0x01, 0xF0, 0x05, 0xC0, 0x17, ++0x00, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x14, 0x00, 0x5F, 0x00, 0x44, ++0x01, 0xD0, 0x27, 0xC0, 0xDC, 0x00, 0x67, 0x07, 0x8C, 0x01, 0xF0, 0x57, 0x44, ++0x5F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x87, 0x00, 0x1F, ++0x12, 0x7C, 0x00, 0xF2, 0x23, 0xC0, 0x0F, 0x00, 0x3F, 0x02, 0xFC, 0x00, 0xF0, ++0x03, 0xC8, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x23, 0xC0, 0x0F, 0x00, ++0x3F, 0x02, 0xFC, 0x80, 0xF3, 0x23, 0xC0, 0x8F, 0x00, 0x3F, 0x22, 0xDC, 0x00, ++0xF0, 0x01, 0xC0, 0x07, 0x02, 0x1B, 0x00, 0x7C, 0x20, 0xF0, 0x21, 0xC0, 0x4B, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x9F, 0x05, ++0x4C, 0x06, 0xF0, 0x99, 0xC0, 0x24, 0x00, 0x93, 0x05, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x67, 0x40, 0x93, 0x00, 0x7C, 0x02, 0xF0, 0x39, 0xC0, 0x67, 0x40, 0x93, ++0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x03, 0x4C, 0x22, 0xF0, ++0x49, 0xE0, 0xA7, 0x00, 0x9F, 0x00, 0x5E, 0x0A, 0x30, 0x09, 0xC0, 0x40, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xA6, 0x04, 0x9D, 0x12, 0x44, ++0x02, 0xD0, 0x29, 0x41, 0x20, 0x00, 0x91, 0x00, 0x74, 0x0E, 0xD0, 0x19, 0x41, ++0x27, 0x00, 0x91, 0x03, 0x74, 0x02, 0xD0, 0x19, 0x40, 0x67, 0x00, 0x91, 0x02, ++0x74, 0x02, 0xD8, 0x39, 0x40, 0x27, 0x01, 0x9D, 0x00, 0x45, 0x86, 0xD0, 0x39, ++0x40, 0x67, 0x14, 0x97, 0x0A, 0x44, 0x0A, 0x56, 0x49, 0x40, 0x04, 0x08, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x02, 0x9D, 0x00, 0x64, 0x2A, ++0xD0, 0x09, 0x40, 0x2C, 0x08, 0xB1, 0x00, 0xF4, 0x0E, 0xD0, 0x1B, 0x40, 0xAF, ++0x02, 0xB1, 0x03, 0xF4, 0x02, 0xD0, 0x0B, 0x40, 0x2F, 0x02, 0xB1, 0x02, 0xF4, ++0x0A, 0xD1, 0x1B, 0x41, 0x2F, 0x01, 0xA9, 0x00, 0xC6, 0x02, 0x91, 0x09, 0x40, ++0x25, 0x00, 0x9D, 0x42, 0x54, 0x02, 0x15, 0x49, 0x40, 0x60, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x8D, 0x14, 0x25, 0x12, 0xD0, ++0x0A, 0x40, 0x2C, 0x00, 0xE1, 0x80, 0xB4, 0x02, 0xD0, 0x0A, 0x4A, 0x2B, 0x00, ++0xA1, 0x00, 0xB4, 0x06, 0xD0, 0x0E, 0x40, 0x6B, 0x00, 0xA1, 0x00, 0xB4, 0x02, ++0xD2, 0x0A, 0x40, 0x2B, 0x00, 0xED, 0x08, 0x84, 0x02, 0xD2, 0x0C, 0x4A, 0x23, ++0x00, 0x95, 0x00, 0x64, 0x06, 0x58, 0x48, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x04, 0x6C, 0x28, 0xF0, 0xA1, ++0xC8, 0x84, 0x42, 0x13, 0x0A, 0x7C, 0x28, 0xF0, 0xA1, 0xC0, 0x87, 0x02, 0x13, ++0x0A, 0x7C, 0x28, 0xF0, 0xA1, 0xC0, 0x87, 0x02, 0x13, 0x0A, 0x7C, 0x28, 0xD0, ++0xA1, 0xC0, 0x87, 0x02, 0x0F, 0x82, 0xCC, 0x01, 0xF8, 0x01, 0xCA, 0x05, 0x00, ++0x1F, 0x00, 0x5C, 0x28, 0x30, 0xA1, 0xC0, 0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x19, 0xB8, 0x27, 0x05, 0xBF, 0x14, 0x5C, 0x22, 0xF0, 0x09, 0xD0, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC8, 0x27, 0x20, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x20, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x9F, 0x04, 0x7C, 0x02, 0xE0, 0x0B, 0xC0, 0x2B, 0x00, 0xA7, ++0x40, 0xDC, 0x02, 0xF0, 0x8B, 0xD4, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0x80, 0x2F, 0x00, 0xBF, 0x14, 0xFC, 0x32, 0x30, 0x0A, 0xC0, 0x24, ++0x00, 0xAF, 0x08, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x2F, 0x02, 0xB3, 0x00, 0xFC, ++0x02, 0xF0, 0x8B, 0xC8, 0x2F, 0x08, 0xBF, 0x00, 0xFC, 0x22, 0x70, 0x0B, 0xC0, ++0x2F, 0x00, 0xB3, 0x28, 0xCE, 0x02, 0xF0, 0x0A, 0xC0, 0x2E, 0x00, 0xB3, 0x00, ++0xFC, 0x02, 0xC1, 0x0B, 0xC2, 0x74, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1C, 0x00, 0x07, 0x05, 0x1D, 0x04, 0x74, 0x30, 0x10, 0x01, 0x41, 0x04, 0x04, ++0x1D, 0x20, 0x74, 0x50, 0xD0, 0x41, 0x4C, 0x07, 0x01, 0x11, 0x10, 0x74, 0x40, ++0xD0, 0x01, 0x40, 0x07, 0x05, 0x1D, 0x04, 0x74, 0x10, 0xD0, 0x01, 0x41, 0x07, ++0x04, 0x01, 0x00, 0x44, 0x00, 0xD0, 0x01, 0xC0, 0x16, 0x00, 0x1B, 0x00, 0x74, ++0x00, 0xD0, 0x01, 0x40, 0x60, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA2, 0x23, 0x21, 0x8D, 0x14, 0x34, 0x12, 0x10, 0x48, 0x40, 0x20, 0x00, 0x8D, ++0x00, 0x34, 0x12, 0xD0, 0x48, 0x41, 0x23, 0x01, 0x81, 0x04, 0x34, 0x02, 0xD0, ++0x08, 0x40, 0x23, 0x01, 0x8D, 0x14, 0x34, 0x12, 0x50, 0x48, 0x40, 0x27, 0x00, ++0x85, 0x00, 0x05, 0x02, 0xD0, 0x08, 0x44, 0x24, 0x00, 0x85, 0x40, 0x34, 0x82, ++0xD1, 0x08, 0x40, 0x48, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, ++0x25, 0x00, 0x9D, 0x02, 0x74, 0x02, 0x12, 0x09, 0x50, 0x24, 0x20, 0x9D, 0x00, ++0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x40, 0x99, 0x00, 0x74, 0x02, 0xD0, 0x09, ++0x40, 0x27, 0x00, 0xDD, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x20, 0x91, ++0x00, 0x64, 0x82, 0xD1, 0x19, 0x40, 0x26, 0x00, 0x9D, 0x01, 0x74, 0x0A, 0xD8, ++0x09, 0x40, 0x60, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x88, 0x27, ++0x00, 0x9D, 0x01, 0x7C, 0x02, 0x34, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF1, 0x09, 0xC0, 0x27, 0x20, 0x93, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0x40, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x70, 0x09, 0xC0, 0x27, 0x00, 0x93, 0x00, ++0x4C, 0x02, 0xF0, 0x09, 0x80, 0x20, 0x00, 0x97, 0x00, 0x7C, 0x06, 0xF0, 0x49, ++0xCA, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x25, 0x00, ++0x9F, 0x08, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x40, 0x7C, 0x02, ++0xF0, 0x09, 0xC8, 0x27, 0x00, 0x97, 0x00, 0x7C, 0x02, 0xF1, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC6, 0x27, 0x50, 0x9F, 0x80, 0x5C, ++0x02, 0xF0, 0x09, 0xC0, 0x27, 0x20, 0x9B, 0x00, 0x7E, 0x12, 0xF0, 0x49, 0xD1, ++0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, ++0x04, 0x3C, 0x40, 0x30, 0x01, 0xD0, 0x06, 0x00, 0x13, 0x00, 0x4D, 0x00, 0xF0, ++0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x11, 0xC0, 0x06, 0x00, ++0x1F, 0x01, 0x7C, 0x20, 0xF0, 0x91, 0xC0, 0x07, 0x04, 0x13, 0x80, 0x7C, 0x40, ++0xF0, 0x11, 0xC4, 0x84, 0x04, 0x1F, 0x10, 0x5C, 0x48, 0xF0, 0x21, 0xC0, 0x53, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x9C, 0x00, 0x7D, 0x12, ++0xF4, 0x01, 0x12, 0x17, 0xC0, 0x14, 0x20, 0x71, 0x0A, 0xEC, 0x01, 0xD0, 0x87, ++0x48, 0x9F, 0x80, 0x7D, 0x00, 0xF4, 0x6D, 0xD0, 0x07, 0xC0, 0x1E, 0x00, 0x7D, ++0x00, 0xF4, 0x29, 0x70, 0x07, 0xC0, 0x99, 0x00, 0x71, 0x81, 0xCC, 0x0D, 0xD1, ++0x16, 0x44, 0x1C, 0x20, 0x7D, 0x02, 0xC4, 0x15, 0xC0, 0x27, 0x40, 0x43, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0xF2, 0x03, 0xCD, 0x01, 0x34, ++0x03, 0x10, 0x9D, 0x41, 0x30, 0x00, 0xC1, 0x02, 0x04, 0x13, 0xD0, 0x2C, 0x48, ++0xB7, 0x01, 0xCD, 0x10, 0x34, 0x0B, 0xD0, 0x0C, 0x42, 0x30, 0x01, 0xCD, 0x00, ++0x34, 0x07, 0xD0, 0x1C, 0x40, 0x31, 0x00, 0xD1, 0x08, 0x14, 0x09, 0xD8, 0x9C, ++0x40, 0x31, 0x10, 0x0D, 0x01, 0x14, 0x0F, 0xD0, 0x8D, 0x40, 0x43, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x38, 0x00, 0xED, 0x00, 0x34, 0x01, ++0x10, 0x0F, 0x40, 0x78, 0x41, 0xF1, 0x01, 0x84, 0x43, 0xD0, 0x0E, 0x41, 0x3B, ++0x10, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x1E, 0x60, 0x38, 0x00, 0xED, 0x10, 0xB4, ++0x01, 0x50, 0x0E, 0x42, 0x39, 0x40, 0x21, 0x00, 0xA4, 0x08, 0xD0, 0x0E, 0x40, ++0x29, 0x00, 0x7D, 0x11, 0x84, 0x01, 0xD0, 0x06, 0x40, 0x13, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x58, 0x08, 0xEF, 0x01, 0xBC, 0x07, 0x30, ++0x1E, 0xC0, 0x7C, 0x05, 0xE3, 0x01, 0x84, 0x07, 0xF0, 0x16, 0xC0, 0x7B, 0x00, ++0xED, 0x01, 0xB4, 0x05, 0xF0, 0x1F, 0x40, 0x58, 0x00, 0xEF, 0x01, 0xBC, 0x07, ++0xF0, 0x1E, 0xC0, 0x7D, 0x00, 0xE3, 0x01, 0x9C, 0x05, 0xF0, 0x0E, 0xC0, 0x69, ++0x10, 0x2F, 0x01, 0x9C, 0x05, 0xF2, 0x1E, 0xC4, 0x53, 0x60, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xBA, 0x15, 0x00, 0xDF, 0x20, 0x7C, 0x02, 0xF4, 0x0D, ++0xC8, 0x35, 0x23, 0x9F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x07, 0x00, 0x9F, ++0x00, 0x7C, 0x01, 0xF0, 0x09, 0xD8, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC4, 0x25, 0x80, 0xDF, 0x00, 0x5C, 0x00, 0xF2, 0x0D, 0xC0, 0x26, 0x00, ++0x8F, 0x20, 0x7C, 0x00, 0xF2, 0x01, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA0, 0x7D, 0x00, 0xFF, 0x01, 0xFC, 0x87, 0xF9, 0x0F, 0xC0, ++0x7D, 0x00, 0xFF, 0x01, 0xFC, 0x25, 0xF0, 0x1E, 0xC0, 0x7C, 0x00, 0xFF, 0x09, ++0xDC, 0x07, 0xF0, 0x17, 0xC0, 0x7F, 0x0A, 0x7F, 0x81, 0xCC, 0x87, 0xF0, 0x17, ++0xC0, 0x5F, 0x22, 0xF3, 0x01, 0xCC, 0x25, 0x30, 0x1A, 0xC0, 0x78, 0x02, 0x23, ++0x01, 0xCC, 0x06, 0xF0, 0x9B, 0xC0, 0x1B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0x88, 0x39, 0x22, 0x6D, 0x00, 0xB4, 0x19, 0xD8, 0x46, 0x40, 0x3B, ++0x05, 0xED, 0x04, 0xB4, 0x83, 0xD0, 0x8E, 0x40, 0x38, 0x00, 0x6D, 0x00, 0xB4, ++0x88, 0xD0, 0x2E, 0x40, 0x3B, 0x00, 0xAD, 0x18, 0x85, 0x0A, 0xD0, 0xAE, 0x40, ++0x1F, 0x03, 0x21, 0x84, 0xC4, 0x01, 0xB0, 0x4A, 0x40, 0xA8, 0x02, 0x2F, 0x00, ++0x94, 0x02, 0xD0, 0x8A, 0x40, 0x57, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x19, 0x00, 0xED, 0x00, 0xB4, 0x81, 0xD0, 0x8A, 0x41, 0x39, 0x20, ++0x6D, 0x90, 0xB4, 0x08, 0xD1, 0x23, 0x40, 0x38, 0x00, 0xED, 0x20, 0x96, 0x23, ++0xD0, 0x0E, 0x40, 0x1B, 0x10, 0xFD, 0x00, 0x84, 0x03, 0xD0, 0x22, 0x40, 0x3B, ++0x60, 0xB1, 0x00, 0xD6, 0x01, 0x11, 0x0E, 0x48, 0x28, 0x00, 0x25, 0x0A, 0x84, ++0x40, 0xD0, 0x8A, 0x41, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x28, 0x05, 0x00, 0x8D, 0x03, 0x74, 0x00, 0xD0, 0x30, 0x44, 0xF3, 0x00, 0x1D, ++0x03, 0x74, 0x02, 0xD0, 0x08, 0x40, 0xC0, 0x00, 0x0D, 0x02, 0x74, 0x0C, 0xD0, ++0x39, 0x00, 0xE7, 0x00, 0x9D, 0x02, 0x44, 0x0E, 0xD0, 0x08, 0x40, 0xE3, 0x00, ++0x81, 0x02, 0x14, 0x08, 0x90, 0x1C, 0x44, 0x20, 0x04, 0x0D, 0x00, 0x56, 0x0C, ++0xD0, 0x28, 0x41, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x28, ++0x25, 0x00, 0x1F, 0x06, 0x7E, 0x02, 0xD8, 0x91, 0xC8, 0xB9, 0x00, 0x1F, 0x01, ++0x7C, 0x16, 0xF0, 0x59, 0xC0, 0x84, 0x04, 0x1D, 0x07, 0x5C, 0x06, 0xF0, 0x19, ++0xC0, 0x27, 0x04, 0x9F, 0x01, 0x4C, 0x06, 0xF0, 0x58, 0xC0, 0x67, 0x02, 0xC3, ++0x00, 0x1C, 0x4D, 0x10, 0x8C, 0xD0, 0xE0, 0x01, 0x17, 0x00, 0x4C, 0x0E, 0xF0, ++0x01, 0xC0, 0x57, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, ++0x00, 0x9F, 0x02, 0x7C, 0x82, 0xF0, 0x21, 0xC0, 0x37, 0x00, 0x9F, 0x10, 0x7C, ++0x0A, 0xF0, 0x09, 0xC0, 0x07, 0x08, 0x1F, 0x02, 0x7C, 0x6A, 0xF0, 0x89, 0xC1, ++0xA7, 0x04, 0x9F, 0x10, 0x7C, 0x60, 0xF0, 0x09, 0xC8, 0x87, 0x02, 0x1F, 0x23, ++0x6C, 0x00, 0xF0, 0x8D, 0xC2, 0x27, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, ++0xC0, 0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x2D, 0x00, ++0x33, 0x10, 0xFC, 0x02, 0x30, 0x0B, 0xE2, 0x3F, 0x04, 0xB3, 0x00, 0xCC, 0x00, ++0x38, 0x0B, 0xC0, 0x2F, 0x04, 0xBF, 0x10, 0xFC, 0x02, 0x30, 0x03, 0xC2, 0x2C, ++0x80, 0x33, 0x00, 0xCC, 0x00, 0x34, 0x03, 0xC0, 0x2C, 0x00, 0x7F, 0x10, 0xCC, ++0x41, 0x31, 0x0F, 0xC0, 0x2D, 0x10, 0x33, 0x00, 0xFC, 0x42, 0x30, 0x0A, 0xC0, ++0x04, 0x24, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xE6, 0x00, 0x91, ++0x05, 0x74, 0x06, 0x12, 0x39, 0x40, 0x37, 0x00, 0x91, 0x81, 0x44, 0x04, 0xB8, ++0x19, 0x44, 0x47, 0x30, 0x9D, 0x43, 0x5C, 0x0E, 0x10, 0x31, 0x40, 0x65, 0x00, ++0x1F, 0x01, 0x44, 0x0C, 0x10, 0x11, 0x40, 0x44, 0x01, 0x5D, 0x02, 0x4C, 0x0C, ++0x70, 0x3D, 0x40, 0xE4, 0x00, 0x95, 0x01, 0x74, 0x0C, 0x12, 0x71, 0x40, 0x04, ++0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0xC4, 0x40, 0x11, 0x01, ++0x74, 0x06, 0x14, 0x39, 0x44, 0x37, 0x00, 0x11, 0x03, 0x44, 0x46, 0x1A, 0x11, ++0x41, 0x67, 0x00, 0x9D, 0x43, 0x74, 0x06, 0x10, 0x11, 0x40, 0x44, 0x04, 0x11, ++0x01, 0x44, 0x06, 0x10, 0x19, 0x64, 0x66, 0x00, 0xDD, 0x02, 0x44, 0x45, 0x10, ++0xA5, 0x40, 0x66, 0x20, 0x19, 0x81, 0x74, 0x0E, 0x11, 0x11, 0x54, 0x04, 0x08, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x01, 0x00, 0x34, ++0x02, 0x10, 0x00, 0x68, 0x37, 0x00, 0x81, 0x00, 0x05, 0x02, 0x10, 0x00, 0x40, ++0x63, 0x00, 0x0D, 0x00, 0x16, 0x00, 0x14, 0x08, 0x50, 0x00, 0x40, 0x81, 0x00, ++0x05, 0x02, 0x1C, 0x09, 0x64, 0x02, 0x00, 0x1D, 0x00, 0x45, 0x00, 0x94, 0x0D, ++0x40, 0x02, 0x00, 0x0D, 0x00, 0x34, 0x02, 0x10, 0x00, 0x40, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x06, 0x00, 0x11, 0x00, 0x7C, 0x00, ++0x30, 0x09, 0x60, 0x3F, 0x40, 0x13, 0x00, 0x4C, 0x00, 0x14, 0x01, 0xC0, 0x27, ++0x20, 0x9F, 0x00, 0x7E, 0x82, 0x30, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x4C, ++0x00, 0x30, 0x01, 0xC0, 0x26, 0x00, 0x1F, 0x00, 0x4C, 0x03, 0x30, 0x0D, 0xD0, ++0x27, 0x08, 0x1B, 0x00, 0x7C, 0x02, 0x30, 0x09, 0xD0, 0x04, 0x64, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x2F, 0x00, 0xBF, 0x00, 0xFC, 0x00, 0xF1, ++0x03, 0xC2, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x80, 0xF0, 0x03, 0xC0, 0x0F, 0x00, ++0x3F, 0x00, 0xDC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x08, 0x2F, 0x00, 0xFC, 0x00, ++0xF0, 0x03, 0xC0, 0x0D, 0x00, 0x2F, 0x40, 0xCC, 0x00, 0x59, 0x0F, 0xC8, 0x2D, ++0x00, 0x37, 0x80, 0xFC, 0x02, 0xF4, 0x0B, 0xC8, 0x17, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA0, 0x0F, 0x00, 0x3F, 0x41, 0xEC, 0x02, 0xF0, 0x0F, ++0xC0, 0x2C, 0x00, 0xBF, 0x00, 0xBE, 0x07, 0xF0, 0x03, 0xC1, 0x3E, 0x00, 0xA3, ++0x01, 0xDC, 0x00, 0x30, 0x03, 0xC0, 0x0F, 0x00, 0xAC, 0x01, 0xDC, 0x33, 0x34, ++0x3F, 0xC0, 0x2F, 0x80, 0xA3, 0x01, 0xFC, 0x53, 0xF0, 0x83, 0xC0, 0x4F, 0x00, ++0x33, 0x01, 0xBC, 0x0C, 0x30, 0x13, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x08, 0x27, 0x12, 0x1D, 0x00, 0x44, 0x02, 0xD0, 0x0F, 0x44, ++0x04, 0x14, 0x1D, 0x00, 0x55, 0x07, 0xD0, 0x21, 0x50, 0x3C, 0x00, 0x91, 0x41, ++0x44, 0x02, 0x10, 0x01, 0x40, 0x27, 0x20, 0x9D, 0x11, 0x54, 0x3B, 0x10, 0x4D, ++0x40, 0x27, 0x20, 0x91, 0x10, 0x74, 0x0F, 0xD2, 0x0B, 0x40, 0x07, 0x08, 0x11, ++0x80, 0x74, 0x00, 0x14, 0x05, 0x40, 0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x03, 0x00, 0x0D, 0x00, 0x05, 0x00, 0xD0, 0x0C, 0x40, 0x20, ++0x08, 0x8D, 0x00, 0x35, 0x02, 0x50, 0x00, 0x40, 0x31, 0x00, 0xC1, 0x00, 0x14, ++0x02, 0x10, 0x08, 0x44, 0x03, 0x00, 0x9D, 0x00, 0x14, 0x03, 0x90, 0x0C, 0x60, ++0x23, 0x00, 0x81, 0x04, 0x34, 0x03, 0xD0, 0x58, 0x48, 0x23, 0x15, 0x81, 0x14, ++0x34, 0x10, 0x10, 0x00, 0x40, 0x47, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0x88, 0x65, 0x10, 0x1D, 0x03, 0x44, 0x0C, 0xD0, 0x0D, 0x40, 0x44, 0x00, ++0x1D, 0x01, 0x54, 0x12, 0xD0, 0x00, 0x40, 0x35, 0x00, 0xD1, 0x00, 0x44, 0x06, ++0x14, 0x19, 0x40, 0x47, 0x14, 0x9D, 0x00, 0x54, 0x03, 0x90, 0x0D, 0x40, 0x27, ++0x42, 0x91, 0x20, 0x74, 0x03, 0xD0, 0x1D, 0x40, 0x23, 0x00, 0x91, 0x00, 0x74, ++0x04, 0x10, 0x05, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x88, 0x47, 0x04, 0x1F, 0x01, 0x4C, 0x8E, 0xF1, 0x0D, 0xC8, 0x64, 0x20, 0x0F, ++0x43, 0x7D, 0x07, 0x70, 0x55, 0xC0, 0x35, 0x40, 0xC3, 0x00, 0x5C, 0x14, 0x30, ++0x59, 0xC0, 0xE7, 0x00, 0x8E, 0x00, 0x5C, 0x03, 0xB0, 0x0D, 0xC0, 0x37, 0x20, ++0xD1, 0x20, 0x7C, 0x03, 0xF2, 0x19, 0xC2, 0x47, 0x00, 0x13, 0x81, 0x3C, 0x02, ++0x34, 0x01, 0xC0, 0x0B, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, ++0x2D, 0x08, 0x3F, 0x00, 0xFC, 0x42, 0xF0, 0x0E, 0xC0, 0x2F, 0x00, 0x3F, 0x00, ++0xFC, 0x03, 0xF0, 0x87, 0xC0, 0x38, 0x00, 0xFF, 0x00, 0xBC, 0x42, 0xF0, 0x0B, ++0xC1, 0x2F, 0x00, 0xBF, 0x04, 0xBC, 0x03, 0x70, 0x0F, 0xC0, 0x7B, 0x20, 0xBF, ++0x00, 0xFC, 0x03, 0xD0, 0x09, 0xC0, 0x4F, 0x02, 0x3F, 0x09, 0xFC, 0x02, 0xF0, ++0x07, 0xC1, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0x05, ++0x00, 0x13, 0x02, 0x5D, 0x0A, 0xF0, 0x0D, 0xC0, 0x24, 0x00, 0x93, 0x00, 0x7C, ++0x82, 0x30, 0x27, 0xC0, 0x34, 0x44, 0xD3, 0x00, 0x6C, 0x02, 0xF0, 0x09, 0xC6, ++0x87, 0x04, 0x9F, 0x00, 0x5C, 0x03, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0xD3, 0x20, ++0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0x64, 0x00, 0x93, 0x01, 0x7C, 0x02, 0x30, 0x01, ++0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x24, 0x00, ++0x01, 0x00, 0x44, 0x06, 0xD0, 0x2F, 0xC5, 0x26, 0x00, 0x9B, 0x20, 0x74, 0x02, ++0xB0, 0x45, 0x40, 0x7C, 0x40, 0xD1, 0x01, 0x6C, 0x02, 0xD0, 0x29, 0x40, 0x87, ++0x00, 0x9D, 0x00, 0xC4, 0x03, 0x12, 0x0D, 0x40, 0xB7, 0x06, 0x91, 0x0A, 0xC4, ++0x03, 0xD0, 0x0D, 0x50, 0xE4, 0x00, 0x91, 0x03, 0x74, 0x42, 0x10, 0x05, 0x40, ++0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x22, 0x80, 0x01, ++0x12, 0x04, 0x20, 0xD0, 0x3C, 0x41, 0x00, 0x00, 0x81, 0x09, 0x24, 0x03, 0x10, ++0x00, 0x40, 0x30, 0x20, 0x8D, 0x13, 0x24, 0x08, 0x90, 0x20, 0x40, 0x83, 0x00, ++0xCD, 0x00, 0x14, 0x03, 0x50, 0x0C, 0x00, 0x23, 0x00, 0x81, 0x02, 0x04, 0x03, ++0xC0, 0x08, 0x40, 0x90, 0x14, 0x41, 0x12, 0x34, 0x85, 0x10, 0x08, 0x40, 0x1F, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x68, 0x40, 0x21, 0x01, ++0x84, 0x07, 0xD0, 0x1C, 0x40, 0x5A, 0x00, 0xE9, 0x01, 0xF4, 0x07, 0x90, 0x10, ++0x54, 0x70, 0x26, 0xAD, 0x91, 0xA4, 0x05, 0xD0, 0x12, 0x08, 0x6B, 0x02, 0xFD, ++0x01, 0x84, 0x07, 0x10, 0x1E, 0x40, 0x6B, 0x00, 0xB5, 0x01, 0x84, 0x07, 0xD0, ++0x9A, 0x40, 0x58, 0x02, 0x61, 0x81, 0xF4, 0x0D, 0x12, 0x9E, 0x40, 0x13, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x24, 0x02, 0x11, 0x00, 0x1D, ++0x21, 0xF0, 0x0C, 0x40, 0xB4, 0x00, 0xC3, 0x02, 0x3C, 0x03, 0x30, 0x40, 0xC0, ++0x30, 0x02, 0xCF, 0x00, 0x2C, 0x00, 0xB3, 0x84, 0xC0, 0x13, 0x8A, 0xCF, 0x00, ++0x5C, 0x03, 0x70, 0x0C, 0xC0, 0x27, 0x40, 0x83, 0x08, 0x0C, 0x03, 0xF0, 0x0C, ++0xC0, 0x34, 0x02, 0xC3, 0x04, 0x3C, 0x01, 0x30, 0x08, 0xC0, 0x4B, 0x40, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x2D, 0x00, 0x7F, 0x88, 0xFC, 0x01, ++0xC0, 0x0F, 0xC1, 0x1D, 0x00, 0xFF, 0x00, 0xFC, 0x23, 0xF0, 0x03, 0xC0, 0xBF, ++0x06, 0xF3, 0x08, 0xFC, 0x21, 0xF0, 0x8F, 0xC8, 0x3F, 0xA2, 0xFF, 0x08, 0xFC, ++0x23, 0xF0, 0x0F, 0xC0, 0x3E, 0x02, 0xBB, 0x20, 0xFD, 0x43, 0xF0, 0x0F, 0xC0, ++0x3F, 0x02, 0xFF, 0x00, 0xFC, 0x01, 0xF0, 0x0F, 0xC2, 0x0B, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x2F, 0x00, 0x0F, 0x00, 0x4C, 0x01, 0xF0, ++0x4D, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, 0x03, 0xF8, 0x01, 0xC0, 0xB6, 0x40, ++0xD3, 0x01, 0x7C, 0x81, 0xF2, 0x05, 0xC8, 0x77, 0x00, 0x93, 0x00, 0x6C, 0x23, ++0x30, 0x0D, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x7C, 0x03, 0xF0, 0x29, 0xC0, 0x54, ++0x00, 0x53, 0x00, 0x4C, 0x03, 0xF0, 0x09, 0xC0, 0x56, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0x88, 0x29, 0x00, 0x2D, 0x00, 0x84, 0x03, 0xD0, 0x0E, ++0x41, 0x3B, 0x00, 0x6D, 0x00, 0xB4, 0x03, 0xD0, 0x03, 0x50, 0x38, 0x01, 0xE1, ++0x00, 0x84, 0x03, 0xD1, 0x0E, 0x40, 0x3F, 0x00, 0xA1, 0x00, 0x94, 0x83, 0x10, ++0x0E, 0x40, 0x3B, 0x00, 0xA1, 0x00, 0xB6, 0x13, 0xD0, 0x8A, 0x40, 0x19, 0x00, ++0x61, 0x00, 0x84, 0x03, 0xD2, 0x0E, 0x40, 0x48, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x00, 0x69, 0x00, 0x3D, 0x01, 0x84, 0x0F, 0xD1, 0x5E, 0x40, ++0x7B, 0x00, 0xED, 0x81, 0xB4, 0x07, 0xD2, 0x12, 0x40, 0x71, 0x00, 0xE1, 0x11, ++0x94, 0x07, 0xD0, 0x16, 0x40, 0x7B, 0x00, 0xB9, 0x43, 0x24, 0x07, 0x50, 0x1E, ++0x40, 0x73, 0x00, 0xED, 0x01, 0xB4, 0x17, 0xD0, 0x1C, 0x41, 0x78, 0x00, 0xE1, ++0x01, 0x84, 0x07, 0xD0, 0x1A, 0x40, 0x0E, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x28, 0x73, 0x10, 0xCD, 0x40, 0x04, 0x0F, 0xD0, 0x0C, 0x40, 0xB3, ++0x00, 0xCD, 0x02, 0x34, 0x03, 0xD0, 0x69, 0x40, 0x37, 0x00, 0xC1, 0x00, 0x06, ++0x27, 0xD0, 0x9D, 0x40, 0x33, 0x00, 0x99, 0x00, 0x14, 0x03, 0x10, 0x0D, 0x40, ++0x77, 0x02, 0x89, 0x08, 0x34, 0x03, 0xD0, 0x6D, 0x42, 0x31, 0x00, 0xD1, 0x00, ++0x44, 0x03, 0xD0, 0x0C, 0x50, 0x48, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x17, 0xA8, 0x5D, 0x01, 0x7F, 0x02, 0xCD, 0x05, 0xF0, 0x05, 0xC0, 0x5F, 0x04, ++0x7D, 0x0B, 0x7C, 0x81, 0xF0, 0x37, 0xC0, 0x15, 0x00, 0x53, 0x00, 0xDC, 0x09, ++0xF0, 0xA7, 0xC0, 0x1F, 0x41, 0x5B, 0x00, 0x6C, 0x01, 0x34, 0x05, 0xC0, 0x17, ++0x00, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x37, 0xE0, 0x14, 0x40, 0x53, 0x00, 0x4D, ++0x01, 0xF0, 0x05, 0xC0, 0x5E, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x00, 0x07, 0x00, 0x1F, 0x12, 0x7C, 0x00, 0xF0, 0x01, 0xCC, 0x07, 0x00, 0x1F, ++0x0A, 0x7C, 0x00, 0xF8, 0x81, 0x40, 0x04, 0x10, 0x1F, 0x02, 0x5C, 0x48, 0xF8, ++0x21, 0xC2, 0x07, 0x01, 0x17, 0x00, 0x7C, 0x00, 0xF1, 0x01, 0xC0, 0x87, 0x40, ++0x17, 0x00, 0x7C, 0x80, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x04, ++0xF0, 0x01, 0xC8, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, ++0x23, 0x00, 0x9B, 0x00, 0x4E, 0x62, 0xF0, 0x19, 0xC0, 0x27, 0x04, 0x87, 0x04, ++0x4C, 0x82, 0xF0, 0x09, 0xC4, 0x24, 0x10, 0x93, 0x40, 0x7C, 0x02, 0xF2, 0x09, ++0xC0, 0x24, 0x00, 0x9E, 0x80, 0x2C, 0x02, 0x70, 0x09, 0xC0, 0x64, 0x08, 0x93, ++0x05, 0x78, 0x06, 0xF0, 0x09, 0x40, 0x26, 0x00, 0x9F, 0x01, 0x4C, 0x02, 0x30, ++0x39, 0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, ++0x00, 0x81, 0x04, 0x44, 0x0A, 0xD0, 0x19, 0x40, 0x27, 0x00, 0x9D, 0x10, 0x44, ++0x02, 0xD0, 0x09, 0xC0, 0x26, 0x40, 0x91, 0x01, 0x74, 0x16, 0xD0, 0x19, 0x40, ++0xA4, 0x00, 0x9D, 0x80, 0x4C, 0x82, 0x10, 0x09, 0x40, 0x24, 0x41, 0x91, 0x01, ++0x74, 0x06, 0xD2, 0x09, 0x40, 0xA4, 0x20, 0x9D, 0x03, 0x44, 0x02, 0x12, 0x08, ++0x40, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x08, ++0x99, 0x00, 0x44, 0x8A, 0xD0, 0x69, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x44, 0x82, ++0x50, 0x09, 0x40, 0x24, 0x02, 0x99, 0x21, 0x56, 0x12, 0x90, 0x69, 0x42, 0x24, ++0x86, 0x9D, 0x00, 0x64, 0x02, 0x50, 0x09, 0x40, 0x24, 0x02, 0x91, 0x00, 0x74, ++0x22, 0xD0, 0x09, 0x40, 0x67, 0x00, 0xBD, 0x04, 0xC4, 0x02, 0x1C, 0x0F, 0x40, ++0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x01, 0x91, ++0x00, 0x04, 0x82, 0xD0, 0x68, 0x40, 0x23, 0x00, 0x8D, 0x02, 0x04, 0x02, 0xD2, ++0x48, 0x40, 0x30, 0x01, 0xC9, 0x00, 0x34, 0x1A, 0xD8, 0x08, 0x41, 0x20, 0x80, ++0x8D, 0x00, 0x04, 0x22, 0x10, 0x08, 0x50, 0x20, 0x01, 0x81, 0x00, 0x34, 0x12, ++0xD0, 0x48, 0x40, 0x69, 0x00, 0xAD, 0x01, 0x84, 0x06, 0x00, 0x0B, 0x40, 0x40, ++0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x86, 0x22, 0x1B, 0x0A, ++0x45, 0x18, 0xF0, 0x21, 0xC0, 0x87, 0x02, 0x1F, 0x06, 0x4C, 0x00, 0xF0, 0xA1, ++0x50, 0x84, 0x02, 0x1B, 0x00, 0x5C, 0x08, 0xB0, 0x61, 0xD0, 0x84, 0x00, 0x1F, ++0x0A, 0x6C, 0x58, 0x71, 0xA1, 0xC0, 0x84, 0x02, 0x13, 0x0A, 0x7C, 0x00, 0xF0, ++0xA1, 0xC0, 0x83, 0x02, 0x0F, 0x4A, 0x4C, 0x28, 0x30, 0xA2, 0xD0, 0x74, 0xC0, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x2F, 0x12, 0xBF, 0x00, 0xFC, ++0x5A, 0xF0, 0x89, 0xC0, 0x2F, 0x02, 0xBF, 0x46, 0xFD, 0x02, 0xF0, 0x8B, 0xC0, ++0x27, 0x22, 0xA7, 0x20, 0xFC, 0x0A, 0xF0, 0x4B, 0xC3, 0x2F, 0x27, 0xAF, 0x00, ++0x5C, 0x12, 0xF0, 0x09, 0xC8, 0x2F, 0x02, 0xBD, 0x00, 0x7C, 0x22, 0xF0, 0x8B, ++0xC0, 0x26, 0x00, 0x9F, 0x00, 0x7D, 0x02, 0xF0, 0x09, 0xC0, 0x67, 0x60, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, 0x27, 0x05, 0xBF, 0x08, 0xEC, 0x02, ++0x30, 0x0B, 0xC0, 0x24, 0x00, 0xBF, 0x04, 0x7C, 0x02, 0x30, 0xCA, 0xC0, 0x2C, ++0x00, 0x83, 0x40, 0xD0, 0x22, 0xF0, 0x4B, 0xC0, 0x2F, 0x05, 0x8F, 0x88, 0x5C, ++0x82, 0xB0, 0x09, 0xC0, 0x2F, 0x02, 0xB3, 0x00, 0xFC, 0x16, 0xF0, 0x49, 0xD0, ++0x2F, 0x00, 0xBF, 0x00, 0xCC, 0x22, 0x30, 0x0B, 0xC0, 0x60, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x03, 0x01, 0x5D, 0x04, 0x44, 0x48, 0x14, ++0x01, 0x49, 0x04, 0x02, 0x17, 0x14, 0x74, 0x00, 0x14, 0xC1, 0x44, 0x80, 0x04, ++0x11, 0x00, 0x44, 0x20, 0xD2, 0x41, 0x49, 0x07, 0x21, 0x1D, 0x04, 0x44, 0x48, ++0x10, 0x01, 0x40, 0x07, 0x02, 0x11, 0x00, 0x74, 0x00, 0xD2, 0x81, 0x40, 0x16, ++0x04, 0x5D, 0x90, 0x44, 0x00, 0x10, 0x01, 0x40, 0x71, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0xA0, 0x23, 0x05, 0x8D, 0x04, 0x05, 0x32, 0x10, 0x88, ++0x40, 0x20, 0x00, 0x8D, 0x8D, 0x74, 0x02, 0x11, 0x58, 0x40, 0x20, 0x43, 0x81, ++0x40, 0x16, 0x02, 0xD0, 0xC8, 0x40, 0x23, 0x05, 0x8D, 0x24, 0x14, 0x32, 0x90, ++0x08, 0x40, 0x23, 0x00, 0x81, 0x00, 0x34, 0x0A, 0xD0, 0x08, 0x40, 0x21, 0x01, ++0x8D, 0x00, 0x44, 0x02, 0x10, 0x08, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x9D, 0x04, 0x44, 0x42, 0x10, 0x09, 0x40, ++0xA4, 0x01, 0x95, 0x40, 0x74, 0x06, 0x10, 0x09, 0x42, 0x24, 0x00, 0x91, 0x00, ++0x46, 0x03, 0xD0, 0x0D, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x44, 0x02, 0x10, 0x09, ++0x40, 0x27, 0x40, 0x91, 0x20, 0x74, 0x02, 0xD0, 0x29, 0x40, 0x24, 0x00, 0x8D, ++0x20, 0x45, 0x02, 0x00, 0x09, 0x40, 0x61, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0xA8, 0x27, 0x02, 0x9F, 0x01, 0x44, 0x02, 0x30, 0x09, 0xD0, 0x24, ++0x00, 0x9F, 0x01, 0x3C, 0x02, 0x30, 0x09, 0xF0, 0x24, 0x00, 0x83, 0x01, 0x5C, ++0x1A, 0xD2, 0x39, 0xC5, 0x27, 0x24, 0x9E, 0x00, 0x5E, 0x02, 0xB0, 0x09, 0xC0, ++0x67, 0x40, 0x93, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0xA7, 0x00, 0x9F, 0x02, ++0x4C, 0x02, 0x30, 0x09, 0xC0, 0x14, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x16, 0x80, 0x65, 0x00, 0x9F, 0x00, 0x1C, 0x26, 0xF0, 0x08, 0xC0, 0x67, 0x00, ++0x97, 0x02, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0xDF, 0x82, 0x7C, 0xC2, ++0xF0, 0x49, 0xC0, 0xE7, 0x00, 0x9D, 0x00, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0xE7, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x89, 0xC0, 0x27, 0x00, 0x9F, 0x80, 0x7C, ++0x42, 0xF4, 0x09, 0xC0, 0x53, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x08, 0x05, 0x00, 0x13, 0x00, 0x4C, 0x48, 0xF0, 0x01, 0xD3, 0x04, 0x00, 0x1F, ++0x00, 0x7C, 0x80, 0xF0, 0x81, 0xC0, 0x04, 0x40, 0x13, 0x00, 0x4C, 0x08, 0xF3, ++0x21, 0xC5, 0xC7, 0x00, 0x1F, 0x00, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, ++0x1B, 0x00, 0x6C, 0x00, 0xF0, 0x01, 0xC0, 0x84, 0x41, 0x13, 0x02, 0x4D, 0x00, ++0xF0, 0x41, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, ++0x14, 0x00, 0x71, 0x07, 0xC5, 0x0D, 0x70, 0x17, 0x40, 0x14, 0x00, 0x7D, 0x04, ++0x74, 0x01, 0xD0, 0x05, 0x42, 0x58, 0x00, 0x51, 0x00, 0xD4, 0x09, 0xD0, 0x27, ++0x40, 0x1F, 0x00, 0x5D, 0x00, 0x44, 0x01, 0x78, 0x05, 0x40, 0x5F, 0x00, 0x71, ++0x00, 0x74, 0x01, 0xD0, 0x05, 0xC0, 0x1E, 0x00, 0x71, 0x11, 0x84, 0x05, 0xD2, ++0x27, 0x40, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, ++0x00, 0x91, 0x07, 0x24, 0x2F, 0x50, 0x1C, 0x40, 0x30, 0x80, 0x4D, 0x11, 0x34, ++0x03, 0xD0, 0x0D, 0x40, 0x32, 0x10, 0xC9, 0x06, 0x04, 0x07, 0xD0, 0x3C, 0x40, ++0x33, 0x80, 0xDD, 0x00, 0x14, 0x03, 0x50, 0x0C, 0x40, 0x37, 0x86, 0x8D, 0x00, ++0x34, 0x02, 0xD0, 0x0D, 0x40, 0x30, 0x00, 0xC1, 0x00, 0x04, 0x2F, 0xD0, 0x01, ++0x40, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x78, 0x00, ++0x21, 0x24, 0x84, 0x03, 0x50, 0x0E, 0x41, 0x38, 0x02, 0x6D, 0x00, 0xB4, 0x03, ++0xD0, 0x0B, 0x50, 0x28, 0x05, 0x69, 0x10, 0xB4, 0x09, 0xD0, 0x2E, 0x42, 0x3B, ++0x04, 0xFD, 0x00, 0x84, 0x03, 0x51, 0x0E, 0x40, 0x1B, 0x00, 0x25, 0x00, 0xB4, ++0x02, 0xD2, 0x4F, 0x64, 0x7A, 0x20, 0xE1, 0x00, 0x84, 0x03, 0xD0, 0x0A, 0x60, ++0x17, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x78, 0x00, 0x23, ++0x07, 0xAD, 0x05, 0x70, 0x14, 0xC0, 0x78, 0x01, 0xEF, 0x01, 0xBC, 0x07, 0xF0, ++0x9E, 0xC0, 0x68, 0x41, 0xA9, 0x09, 0x8C, 0x07, 0xF3, 0x1E, 0xC0, 0x7B, 0x10, ++0xEF, 0x01, 0x94, 0x17, 0x70, 0x3E, 0x80, 0x7F, 0x00, 0xEF, 0x01, 0xBC, 0x07, ++0xF0, 0x5E, 0x80, 0x7C, 0x00, 0xF1, 0x01, 0x8C, 0x07, 0xF0, 0x16, 0xC0, 0x57, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0xB5, 0x42, 0x0F, 0x00, ++0x7C, 0x01, 0x72, 0x05, 0xC0, 0x77, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x49, ++0xD0, 0x07, 0x0A, 0x17, 0x00, 0x5C, 0x01, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x06, 0x7C, 0x03, 0x70, 0x1D, 0xC0, 0x27, 0x40, 0x5B, 0x00, 0x7C, 0x03, 0xF0, ++0x1C, 0xC0, 0x27, 0x00, 0xDE, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0xFF, 0x00, 0xB3, 0x01, 0xCC, ++0x23, 0xF0, 0x5F, 0xC2, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x07, 0x30, 0x1F, 0xC0, ++0x6C, 0x00, 0xFB, 0x41, 0xC8, 0x27, 0x30, 0x17, 0xC0, 0x5F, 0x20, 0xFF, 0x13, ++0xDC, 0x47, 0xB0, 0x1F, 0xC8, 0x7F, 0x00, 0xBF, 0x01, 0xDC, 0x06, 0x30, 0x1F, ++0xD1, 0x7C, 0x00, 0xFF, 0x81, 0xFC, 0x87, 0xF0, 0x1B, 0xC0, 0x03, 0x08, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x3D, 0x00, 0xA1, 0x0A, 0x84, 0x09, ++0x70, 0x0E, 0x48, 0x3B, 0x04, 0xAD, 0x00, 0xB4, 0x03, 0x10, 0x0F, 0x40, 0x28, ++0x10, 0x61, 0x04, 0xC4, 0x23, 0x10, 0x86, 0x40, 0x3B, 0x0A, 0xED, 0x00, 0xC4, ++0x03, 0xB2, 0x0E, 0x40, 0x3B, 0x00, 0x3D, 0x00, 0x84, 0x02, 0xB0, 0x0E, 0x40, ++0x38, 0x00, 0xAD, 0x88, 0xB4, 0x22, 0xD0, 0x02, 0x40, 0x57, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x39, 0x00, 0x31, 0x00, 0x84, 0x23, 0xD8, ++0x46, 0x40, 0x3B, 0x00, 0xED, 0x02, 0xF4, 0x03, 0x90, 0x2E, 0x40, 0x20, 0x00, ++0xA1, 0x20, 0x86, 0x22, 0x98, 0x2A, 0x40, 0x8B, 0x00, 0xED, 0x00, 0x94, 0x03, ++0x10, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0x94, 0x23, 0x10, 0x0C, 0x40, 0x18, ++0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x41, 0x03, 0x08, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x20, 0x33, 0x04, 0x01, 0x03, 0x45, 0x00, 0x50, 0x01, ++0x40, 0xF3, 0x00, 0x9D, 0x40, 0x36, 0x83, 0x90, 0x0C, 0x40, 0x04, 0x00, 0x01, ++0x20, 0x06, 0x02, 0x90, 0x08, 0x44, 0x23, 0x08, 0xCD, 0x00, 0x04, 0x03, 0x90, ++0x0C, 0x40, 0x33, 0x02, 0x4D, 0x08, 0x04, 0x03, 0x90, 0x1C, 0x40, 0x20, 0x00, ++0xCD, 0x00, 0x74, 0x02, 0xD0, 0x14, 0x40, 0x13, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xA0, 0xBD, 0x40, 0x73, 0x11, 0x4C, 0x0A, 0xF0, 0x09, 0xC0, ++0x3F, 0x10, 0x5F, 0x03, 0x74, 0x83, 0xB4, 0x09, 0x40, 0x2C, 0x00, 0xD3, 0x00, ++0x4C, 0x1A, 0xB0, 0x09, 0xC0, 0x27, 0x00, 0xFF, 0x00, 0xDC, 0x03, 0x30, 0x0F, ++0x40, 0x27, 0x00, 0x5F, 0x00, 0x1C, 0x02, 0x30, 0xBF, 0xC1, 0x34, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x14, 0xC0, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x00, 0x77, 0x00, 0x5F, 0x06, 0x7C, 0x62, 0xF0, 0x09, 0xC0, 0x37, ++0x01, 0x5F, 0x01, 0x7C, 0x03, 0x70, 0x09, 0xC0, 0x27, 0x00, 0xD7, 0x02, 0x7D, ++0x00, 0x70, 0x01, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF2, 0x0D, 0xC4, ++0x27, 0x00, 0x5F, 0x02, 0x7C, 0x02, 0xF0, 0x0D, 0xE0, 0x37, 0x00, 0xDF, 0x02, ++0x7C, 0x0B, 0xF1, 0x0D, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x3F, 0x00, 0x73, 0x08, 0xCC, 0x00, 0x30, 0x0B, 0xC2, 0x38, 0x00, ++0xF3, 0x00, 0xCC, 0x03, 0x31, 0x1B, 0xC0, 0x2E, 0x00, 0xF3, 0x00, 0xCC, 0x40, ++0xF0, 0x0A, 0xC4, 0x08, 0x00, 0xF3, 0x00, 0xBC, 0x03, 0x30, 0x0F, 0xC0, 0x2F, ++0x00, 0x7F, 0x01, 0x4C, 0x06, 0x30, 0x0E, 0xC8, 0x3C, 0x00, 0x7F, 0x00, 0xFC, ++0x03, 0x30, 0x83, 0xC0, 0x00, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x20, 0x36, 0x00, 0x51, 0x00, 0x45, 0x0C, 0x11, 0x39, 0x41, 0x34, 0x00, 0xD1, ++0x01, 0x2C, 0x03, 0x50, 0x09, 0x40, 0x44, 0x00, 0xC1, 0x02, 0x7C, 0x0C, 0xD0, ++0x31, 0xC0, 0x46, 0x00, 0xD1, 0x00, 0x74, 0x03, 0x50, 0x0D, 0xC0, 0x65, 0x00, ++0x5D, 0x02, 0x6C, 0x06, 0x14, 0x0D, 0x40, 0x34, 0x00, 0xDD, 0x04, 0x70, 0x07, ++0x10, 0x09, 0x40, 0x04, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA8, ++0x30, 0x40, 0x01, 0x00, 0x64, 0x06, 0x90, 0x11, 0x40, 0x34, 0x00, 0xD1, 0x01, ++0x44, 0x03, 0x18, 0x88, 0x40, 0x24, 0x01, 0xD1, 0x14, 0x44, 0x06, 0xD0, 0x11, ++0x40, 0x44, 0x00, 0xD1, 0x00, 0x54, 0x03, 0x90, 0x0D, 0x40, 0x67, 0x04, 0x49, ++0x06, 0x44, 0x22, 0x10, 0x0D, 0x40, 0x34, 0x22, 0xDD, 0x40, 0x74, 0x0F, 0x10, ++0x0D, 0x40, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, ++0x00, 0x01, 0x00, 0x05, 0x02, 0x90, 0x08, 0x56, 0x30, 0x40, 0xC1, 0x00, 0x45, ++0x03, 0x50, 0x08, 0x40, 0x20, 0x00, 0x81, 0x00, 0x14, 0x02, 0xD0, 0x00, 0x40, ++0x60, 0x00, 0xC1, 0x00, 0x34, 0x03, 0xD2, 0x0C, 0x40, 0x21, 0x00, 0x4D, 0x00, ++0x24, 0x02, 0x10, 0x0C, 0x00, 0x30, 0x08, 0x8D, 0x00, 0x34, 0x03, 0x10, 0x05, ++0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB0, 0x3E, 0x10, ++0x13, 0x00, 0x4D, 0x02, 0xB0, 0x01, 0x42, 0x34, 0x00, 0x93, 0x20, 0x46, 0x03, ++0x30, 0x0B, 0xC0, 0x26, 0x00, 0x53, 0x00, 0x44, 0x00, 0xF1, 0x09, 0x40, 0x04, ++0x40, 0xE3, 0x00, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, 0x27, 0x00, 0x5F, 0x00, 0x4C, ++0x02, 0x30, 0x0D, 0x90, 0x14, 0x00, 0x5F, 0x00, 0x7C, 0x03, 0x30, 0x09, 0xD0, ++0x00, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x98, 0x3F, 0x00, 0x2F, ++0x00, 0xFC, 0x02, 0x70, 0x0B, 0xC4, 0x3F, 0x00, 0xBF, 0x00, 0xBC, 0x03, 0xF0, ++0x0B, 0xC0, 0x0F, 0x00, 0x2F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC2, 0x0F, 0x00, ++0xFF, 0x20, 0xFC, 0x03, 0x70, 0x0F, 0xC0, 0x2D, 0x00, 0x7F, 0x00, 0xFC, 0x02, ++0xF0, 0x0F, 0xC0, 0x3F, 0x08, 0xFF, 0x00, 0xFC, 0x01, 0xF0, 0x03, 0xC0, 0x17, ++0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0xFF, 0x00, 0xFF, 0x09, ++0xFC, 0x32, 0xF0, 0x4F, 0xE1, 0x2D, 0x21, 0xFF, 0x09, 0xFC, 0x00, 0xF0, 0x0F, ++0xC0, 0x3C, 0x00, 0xFF, 0x1C, 0xCC, 0x52, 0xF0, 0x4F, 0xC0, 0x7C, 0x80, 0xFF, ++0x00, 0xCC, 0x13, 0xB0, 0x0F, 0xC0, 0x7C, 0x00, 0xFF, 0x84, 0xBC, 0x05, 0x30, ++0x1F, 0xC0, 0x7C, 0x40, 0xFB, 0x01, 0xCC, 0x04, 0xB0, 0x0B, 0xC0, 0x0C, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xCD, 0x00, 0x74, ++0x3A, 0xD0, 0x3F, 0x40, 0xA7, 0x03, 0xDD, 0x04, 0x74, 0x06, 0xD0, 0x2F, 0x40, ++0xFC, 0x00, 0xFD, 0x06, 0x44, 0x1A, 0xD0, 0xBF, 0x46, 0x74, 0x00, 0xFD, 0x06, ++0xC4, 0x3B, 0x34, 0xAF, 0x40, 0x74, 0x00, 0xFC, 0x02, 0x74, 0x05, 0x10, 0x1D, ++0x40, 0x74, 0x00, 0x91, 0x01, 0x54, 0x03, 0x52, 0x01, 0x40, 0x0D, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x01, 0xCD, 0x00, 0x34, 0x00, ++0xD0, 0x0C, 0x40, 0x03, 0x04, 0xCD, 0x04, 0x34, 0x02, 0xD0, 0x8C, 0x40, 0x32, ++0x02, 0xCD, 0x00, 0x04, 0x40, 0xD1, 0x0C, 0x40, 0x30, 0x00, 0xCD, 0x18, 0x04, ++0x43, 0x10, 0x0C, 0x42, 0x30, 0x00, 0xCD, 0x02, 0x74, 0x03, 0x10, 0x0D, 0x40, ++0x31, 0x00, 0x49, 0x80, 0x04, 0x01, 0x80, 0x08, 0x60, 0x4C, 0x80, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, 0xDD, 0x00, 0x74, 0x0C, 0xD0, ++0x0D, 0x40, 0x47, 0x00, 0xDD, 0x00, 0x74, 0x0E, 0xD0, 0x0D, 0x40, 0x36, 0x00, ++0xDD, 0x00, 0x45, 0x06, 0xD0, 0x0D, 0x40, 0x34, 0x10, 0xDD, 0x00, 0x44, 0x03, ++0x10, 0x0D, 0x40, 0x34, 0x14, 0xDD, 0x00, 0x74, 0x21, 0x10, 0x0D, 0x60, 0x74, ++0x90, 0x11, 0x00, 0x56, 0x01, 0x09, 0x31, 0x40, 0x0D, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xA0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x0C, 0xF0, 0x0D, ++0xC0, 0x67, 0x04, 0xDF, 0x00, 0x7C, 0x04, 0xF0, 0x0D, 0x40, 0x36, 0x00, 0xDF, ++0x20, 0x4C, 0x1E, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xDD, 0x00, 0x4C, 0x03, 0x30, ++0x0D, 0xC0, 0x34, 0x00, 0xDF, 0x00, 0x7C, 0x81, 0x31, 0x2C, 0xC0, 0xF0, 0x04, ++0xDB, 0x00, 0x4C, 0x16, 0xA0, 0x31, 0xC0, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x07, 0x88, 0x3D, 0x00, 0xFF, 0x00, 0x7C, 0x02, 0xF0, 0x0F, 0xC2, ++0x2F, 0x00, 0xFF, 0x00, 0x7C, 0x02, 0xF0, 0x0F, 0xD0, 0x35, 0x00, 0xDF, 0x00, ++0xFC, 0x02, 0xF0, 0x0E, 0xC0, 0x3F, 0x00, 0xEF, 0x00, 0xFC, 0x43, 0xF0, 0x0F, ++0xC4, 0x3F, 0x02, 0xFD, 0x00, 0xF8, 0x01, 0xF4, 0x2F, 0x40, 0x3F, 0x40, 0xFF, ++0x00, 0xFC, 0x67, 0xF0, 0x02, 0xC2, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x08, 0x35, 0x80, 0xDF, 0x00, 0x5C, 0x08, 0x30, 0x0D, 0xC0, 0xA4, ++0x08, 0xDF, 0x00, 0x4C, 0x08, 0x30, 0x5C, 0xC0, 0x34, 0x00, 0xC3, 0x40, 0x4C, ++0x48, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xD3, 0x00, 0x3C, 0x83, 0xF0, 0x0C, 0xC0, ++0x34, 0x04, 0xD7, 0x91, 0x4C, 0x13, 0x74, 0x0D, 0xC5, 0x35, 0x00, 0xDF, 0x84, ++0x4C, 0x05, 0xE0, 0x29, 0x81, 0x09, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0x44, 0x04, 0x10, 0x0F, 0x40, 0xE4, 0x02, ++0xDD, 0x00, 0x44, 0x00, 0xB0, 0x2F, 0x40, 0x3D, 0x00, 0xF1, 0x01, 0x44, 0x16, ++0xD0, 0x0F, 0xC0, 0x34, 0x00, 0xF7, 0x04, 0xF4, 0x4B, 0xD0, 0xAF, 0x40, 0xB5, ++0x00, 0xF0, 0x02, 0x04, 0x15, 0x10, 0x3D, 0x44, 0x34, 0x10, 0xC9, 0x80, 0x44, ++0x85, 0x90, 0x31, 0x41, 0x6D, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++0x20, 0x30, 0x10, 0xCD, 0x00, 0x04, 0x4E, 0x11, 0x0C, 0x44, 0x40, 0x00, 0xCD, ++0x00, 0x04, 0x00, 0x10, 0x2C, 0x40, 0x30, 0x08, 0xC1, 0x04, 0x24, 0x04, 0xD0, ++0x0C, 0x50, 0x32, 0x00, 0xC1, 0x07, 0x34, 0x07, 0xD0, 0x0C, 0x40, 0xD0, 0x00, ++0xC5, 0x02, 0x00, 0x09, 0x10, 0x14, 0x40, 0x83, 0x41, 0xC1, 0x02, 0x64, 0x00, ++0xD0, 0x18, 0x40, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, ++0x78, 0x00, 0xED, 0x01, 0x85, 0x07, 0x14, 0x1C, 0x50, 0x78, 0x04, 0xED, 0x01, ++0x85, 0x06, 0x10, 0x1E, 0x40, 0x78, 0x80, 0xE1, 0x11, 0xA4, 0x05, 0xD0, 0x1C, ++0x40, 0x7C, 0x00, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x59, 0x06, 0xE5, ++0x01, 0x84, 0x05, 0x10, 0x9E, 0x40, 0x7A, 0x07, 0xA1, 0x01, 0xA4, 0x06, 0x91, ++0x1A, 0x40, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0x30, ++0x00, 0xCD, 0x00, 0x1C, 0x43, 0x30, 0x0C, 0xC0, 0x10, 0x00, 0xDF, 0x00, 0x04, ++0x03, 0x10, 0x0D, 0xC0, 0x30, 0x00, 0xC3, 0x00, 0x2C, 0x21, 0xF0, 0x0C, 0xC0, ++0x36, 0x02, 0xC3, 0x00, 0x3C, 0x03, 0xF2, 0x0D, 0xE0, 0x20, 0x00, 0xD7, 0x00, ++0x0C, 0x33, 0x30, 0x8C, 0xC1, 0x23, 0x03, 0x4B, 0x20, 0x2C, 0x20, 0xF0, 0x09, ++0xC0, 0x4B, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x3D, 0x10, ++0xFF, 0x48, 0xFC, 0x23, 0xF8, 0x0F, 0xC0, 0x1F, 0x00, 0xFF, 0x00, 0xFC, 0x03, ++0xF0, 0x0F, 0xC0, 0x3F, 0x10, 0xFF, 0x02, 0x5D, 0x21, 0xF0, 0x0F, 0xC0, 0x3F, ++0x00, 0xF7, 0x10, 0x7C, 0x43, 0xF0, 0x0D, 0xC1, 0x2A, 0x00, 0xFB, 0x02, 0x7C, ++0x21, 0xF2, 0x88, 0x00, 0x28, 0x03, 0x2F, 0x08, 0xDC, 0x22, 0xF2, 0x8B, 0xC4, ++0x09, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, 0x80, 0xDF, ++0x00, 0x7E, 0x01, 0x30, 0x4D, 0xC1, 0x17, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF0, ++0xAD, 0xD0, 0x34, 0x01, 0xDF, 0x02, 0x5C, 0x03, 0xF0, 0xCD, 0xC0, 0x37, 0x00, ++0xDF, 0x04, 0x7C, 0x1B, 0xF8, 0x6D, 0xC0, 0x37, 0x00, 0xD3, 0x0E, 0x7C, 0x01, ++0xF0, 0x1D, 0xC0, 0x22, 0x40, 0xCB, 0x00, 0x4C, 0x02, 0xF0, 0x11, 0x40, 0x40, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x39, 0x00, 0xED, 0x00, ++0xF4, 0x03, 0x10, 0x4E, 0x40, 0x3B, 0x00, 0xEC, 0x00, 0xB4, 0x03, 0xD0, 0x8E, ++0x40, 0xB8, 0x05, 0xFD, 0x04, 0x84, 0x03, 0xD0, 0x0E, 0x41, 0x3B, 0x00, 0xED, ++0x0C, 0xB4, 0x53, 0x70, 0xCE, 0x40, 0x3B, 0x00, 0xE5, 0x00, 0xB4, 0x00, 0xD0, ++0x0E, 0x40, 0x28, 0x00, 0xEB, 0x00, 0x84, 0x03, 0xD0, 0x06, 0x40, 0x4C, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xE5, 0x01, 0xB4, ++0x87, 0x92, 0xDE, 0x42, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x5C, 0x40, ++0x78, 0x00, 0xFD, 0x4D, 0x94, 0x07, 0xD0, 0x5E, 0x40, 0x7B, 0x00, 0xED, 0x05, ++0xB4, 0x07, 0xD0, 0x1E, 0x44, 0x7F, 0x00, 0xE1, 0x05, 0xB4, 0x07, 0xD0, 0x1E, ++0x41, 0x6E, 0x80, 0xF9, 0x01, 0x84, 0x07, 0xD0, 0x1C, 0x60, 0x10, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xDD, 0x00, 0x74, 0x43, ++0x94, 0x0C, 0x40, 0xF3, 0x01, 0xCD, 0x00, 0x36, 0x3F, 0xD0, 0x0D, 0x40, 0x30, ++0x10, 0xDD, 0x00, 0x04, 0x47, 0x90, 0x0C, 0x42, 0x33, 0x00, 0xDD, 0x00, 0x74, ++0x03, 0x52, 0x0C, 0x40, 0xB3, 0x02, 0xC5, 0x00, 0x34, 0x00, 0xD0, 0x4C, 0x46, ++0x60, 0xA2, 0xC9, 0x09, 0x44, 0x03, 0xC0, 0x1C, 0x40, 0x58, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x15, 0x08, 0x5F, 0x00, 0xF4, 0x15, 0xB0, ++0x05, 0xC0, 0x9F, 0x01, 0x5F, 0x00, 0xFC, 0x01, 0xF2, 0x05, 0xC0, 0x14, 0x08, ++0x5F, 0x00, 0xDC, 0x19, 0xF3, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, 0x01, ++0xF0, 0x05, 0xC0, 0x5F, 0x20, 0x53, 0x00, 0xFC, 0x15, 0xF0, 0x07, 0xCC, 0x9A, ++0x20, 0x6B, 0x02, 0xCD, 0x09, 0xF0, 0x37, 0xD0, 0x5C, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x0A, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x70, 0x01, ++0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x20, 0x1F, ++0x40, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x70, ++0x21, 0xC0, 0x87, 0x01, 0x1F, 0x02, 0x7E, 0x00, 0xF2, 0x01, 0xC0, 0x07, 0x04, ++0x1F, 0x10, 0x7C, 0x48, 0xB0, 0xE1, 0xC8, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, 0x80, 0x4C, 0x02, 0x30, 0x09, 0xC0, ++0xA7, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x25, 0x80, 0x9F, 0x08, ++0x0C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x4C, 0x0E, 0x30, 0x08, ++0xC0, 0x24, 0x00, 0x97, 0x00, 0x7C, 0x86, 0x72, 0x29, 0xCA, 0xA7, 0x08, 0x97, ++0x05, 0x5C, 0x02, 0x30, 0x19, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x20, 0x24, 0x08, 0x9D, 0x20, 0x44, 0x36, 0x04, 0x09, 0x44, 0xE7, ++0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x29, 0x40, 0x25, 0x90, 0x9C, 0x01, 0x44, ++0x0A, 0x14, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x03, 0x45, 0x0A, 0xA4, 0x09, 0x51, ++0xA0, 0x00, 0x90, 0x12, 0x34, 0x26, 0x10, 0x29, 0x40, 0x27, 0x00, 0x99, 0x00, ++0x6C, 0x8A, 0x50, 0x19, 0x41, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x45, 0x02, 0x00, 0x09, 0x40, 0x27, 0x00, ++0x9D, 0x00, 0x40, 0x02, 0xD0, 0x09, 0x00, 0x24, 0x20, 0x9C, 0x10, 0x44, 0x22, ++0x10, 0x09, 0x44, 0x25, 0x00, 0x9D, 0x14, 0x44, 0x42, 0x90, 0x19, 0x40, 0x24, ++0x04, 0x95, 0x00, 0x54, 0x02, 0x40, 0x0D, 0x41, 0x26, 0x00, 0x9D, 0x42, 0x54, ++0x12, 0x10, 0x49, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x20, 0x20, 0x00, 0x8D, 0x00, 0x04, 0x12, 0x11, 0x48, 0x40, 0x33, 0x01, 0x8D, ++0x00, 0x34, 0x12, 0xD0, 0x4D, 0x4C, 0x21, 0x11, 0x8D, 0x04, 0x04, 0x13, 0x10, ++0x48, 0x60, 0x23, 0x00, 0x8D, 0x04, 0x04, 0x12, 0x90, 0x48, 0x44, 0x24, 0x00, ++0x81, 0x84, 0x76, 0x02, 0x1A, 0x08, 0x40, 0x23, 0x88, 0x89, 0x80, 0x24, 0x02, ++0x50, 0x48, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x38, ++0x86, 0x0A, 0x1F, 0x0A, 0x4C, 0x28, 0x30, 0x01, 0xC0, 0x87, 0x02, 0x1F, 0x0A, ++0x7C, 0x00, 0xF0, 0xA1, 0xC0, 0x04, 0x00, 0x1D, 0x0A, 0x4D, 0x28, 0x32, 0x01, ++0xC4, 0x07, 0x00, 0x1F, 0x0A, 0x4C, 0x28, 0x30, 0xA1, 0x40, 0x04, 0x08, 0x17, ++0x4A, 0x5C, 0x00, 0x70, 0x01, 0xC0, 0x06, 0x00, 0x17, 0x00, 0x5C, 0x29, 0x30, ++0xA1, 0xC0, 0x77, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB2, 0x25, ++0x00, 0x9F, 0x40, 0xFC, 0x22, 0xF0, 0x89, 0xC0, 0x2F, 0x02, 0x9F, 0x00, 0xFC, ++0x22, 0xF0, 0x89, 0xC0, 0x27, 0x02, 0x9F, 0x48, 0xFC, 0x22, 0xF0, 0x89, 0xC2, ++0x27, 0x00, 0x9F, 0x08, 0x7C, 0x22, 0x70, 0x89, 0xC0, 0x3B, 0x00, 0x9F, 0x08, ++0xFC, 0x02, 0xF0, 0x0A, 0xC0, 0x2F, 0x00, 0xB7, 0x80, 0xDC, 0x02, 0xF1, 0x8F, ++0xC0, 0x77, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x80, 0x27, 0x00, ++0x9F, 0x08, 0xFC, 0x02, 0x30, 0x09, 0xC0, 0x2C, 0x02, 0x93, 0x00, 0x7C, 0x52, ++0xF0, 0xCB, 0xC0, 0x27, 0x00, 0xBF, 0x00, 0xFC, 0x22, 0xB0, 0x49, 0xC0, 0x27, ++0x00, 0xBF, 0x0C, 0xFC, 0x02, 0xE0, 0x0B, 0xC0, 0x2D, 0x00, 0xB3, 0x04, 0xDC, ++0x02, 0xB0, 0x0B, 0xC0, 0x2A, 0x40, 0xB3, 0x00, 0xBC, 0x03, 0x30, 0x0B, 0xC0, ++0x77, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x01, 0x1D, ++0x04, 0x74, 0x49, 0x10, 0x01, 0x44, 0x14, 0x42, 0x01, 0x14, 0x74, 0x00, 0xD0, ++0xC1, 0x4C, 0x87, 0x10, 0x1D, 0x50, 0x74, 0x20, 0x10, 0x01, 0x40, 0x07, 0x00, ++0x1D, 0x0C, 0x74, 0x48, 0xD0, 0x01, 0x45, 0x07, 0x00, 0x11, 0x14, 0x74, 0x00, ++0xD0, 0x05, 0x40, 0x04, 0x00, 0x11, 0x00, 0x74, 0x00, 0x10, 0x01, 0x40, 0x63, ++0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x05, 0x8D, 0x04, ++0x34, 0xB2, 0x14, 0x88, 0x40, 0x20, 0x00, 0x81, 0x04, 0x36, 0x02, 0xD0, 0x48, ++0x48, 0x23, 0x82, 0x8D, 0x08, 0x34, 0x02, 0x14, 0x88, 0x60, 0x23, 0x00, 0x8D, ++0x04, 0x34, 0x32, 0xD0, 0x88, 0x40, 0x27, 0x00, 0x81, 0x0C, 0x36, 0x02, 0x52, ++0x08, 0x40, 0x23, 0x00, 0x81, 0x00, 0x14, 0x02, 0x18, 0x08, 0x40, 0x4B, 0x80, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0x9D, 0x00, 0x74, ++0x12, 0x10, 0x09, 0x50, 0x24, 0x01, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x74, 0x0B, 0x10, 0x09, 0x40, 0x27, 0x00, 0xDD, 0x00, ++0x74, 0x02, 0xD8, 0x09, 0x40, 0x27, 0x00, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, ++0x40, 0x27, 0x04, 0x91, 0x02, 0x70, 0x12, 0x19, 0x09, 0x40, 0x63, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x24, 0x00, 0x9F, 0x00, 0x78, 0x06, ++0x30, 0x09, 0xC0, 0x64, 0x00, 0x93, 0x00, 0x7C, 0x4E, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xB2, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF2, 0x09, 0xC0, 0x67, 0x40, 0x93, 0x00, 0x7C, 0x42, 0xB0, 0xB9, 0xC0, ++0x27, 0x00, 0x93, 0x00, 0x7C, 0x46, 0x34, 0x19, 0xC0, 0x17, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x3C, 0x06, 0xF0, ++0x08, 0xC0, 0x67, 0x00, 0x9C, 0x00, 0x7C, 0x12, 0xF0, 0x09, 0xC1, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x22, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xF0, 0x09, 0xC1, 0x27, 0x02, 0x9F, 0xB0, 0x7C, 0x42, 0xF0, 0x19, 0x02, 0x24, ++0x01, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x99, 0xC1, 0x5B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x01, ++0xC0, 0xC7, 0x00, 0x1F, 0x00, 0x4C, 0x08, 0x30, 0x01, 0xC0, 0x04, 0x00, 0x1F, ++0x01, 0x7C, 0x30, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x01, 0x5C, 0x04, 0xF0, ++0x01, 0xC8, 0x86, 0x09, 0x13, 0x08, 0x6D, 0x08, 0xE0, 0x41, 0xC0, 0x84, 0x00, ++0x17, 0x40, 0x6C, 0x10, 0x10, 0xA1, 0xC2, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x5D, 0x80, 0xF4, 0x1D, 0x70, 0x05, 0x40, ++0x5F, 0x20, 0x5D, 0x00, 0x4C, 0x01, 0x10, 0x27, 0x40, 0x14, 0x00, 0x7D, 0x00, ++0xF4, 0x0D, 0xD0, 0x05, 0x40, 0x17, 0x00, 0x7D, 0x01, 0xC4, 0x05, 0x70, 0x27, ++0x40, 0x18, 0x00, 0x71, 0x82, 0xC4, 0x19, 0xD0, 0x16, 0x41, 0x18, 0x01, 0x71, ++0x1B, 0xE4, 0x45, 0x10, 0x07, 0x40, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x1F, 0x58, 0x0C, 0x40, 0x77, ++0x00, 0xC9, 0x00, 0x25, 0x03, 0x14, 0x2C, 0x50, 0x30, 0x00, 0xCD, 0x01, 0x74, ++0x07, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x14, 0x03, 0x50, 0x1C, 0x50, ++0xB0, 0x42, 0xC1, 0x00, 0x04, 0x03, 0xD0, 0x2C, 0x40, 0x50, 0x40, 0xC5, 0x02, ++0x64, 0x07, 0x94, 0x1C, 0x40, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x80, 0x38, 0x02, 0xED, 0x08, 0xB4, 0x03, 0x58, 0x0E, 0x40, 0x3B, 0x0C, ++0xED, 0x05, 0x04, 0x07, 0x10, 0x1E, 0x41, 0x38, 0x00, 0x6D, 0x10, 0xB4, 0x03, ++0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x03, 0x84, 0x09, 0x50, 0x36, 0x40, 0x3C, ++0x00, 0xE1, 0x01, 0x84, 0x03, 0xD0, 0x0F, 0x40, 0x1C, 0x00, 0xE1, 0x00, 0xE6, ++0x82, 0x90, 0x16, 0x40, 0x11, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x18, 0x78, 0x00, 0xEF, 0x11, 0xBC, 0x05, 0x70, 0x1E, 0xC0, 0x7B, 0x00, 0xEF, ++0x87, 0xAC, 0x87, 0x30, 0x1F, 0xC0, 0x78, 0x00, 0xED, 0x21, 0xBC, 0x07, 0xF0, ++0x1E, 0xC0, 0x7B, 0x00, 0xCF, 0x81, 0x9C, 0x07, 0x78, 0x1F, 0xC0, 0x78, 0x00, ++0xC3, 0x81, 0x8C, 0x07, 0xDA, 0x0A, 0xC4, 0x58, 0x20, 0xE7, 0x21, 0xAE, 0x07, ++0xB1, 0x1B, 0xC4, 0x50, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, ++0x35, 0x01, 0xDF, 0x06, 0x7E, 0x01, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x16, ++0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x37, 0x20, 0xDF, 0x00, 0x7C, 0x01, 0x70, 0x05, 0xC0, 0x31, 0x00, 0x5F, ++0x00, 0x5C, 0x03, 0xF8, 0x0C, 0xC0, 0x17, 0x00, 0xDF, 0x00, 0x70, 0x02, 0x70, ++0x01, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0xFD, ++0x02, 0xF3, 0x01, 0xFC, 0x23, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, 0xF3, 0x81, 0xFC, ++0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x02, 0xFF, 0x01, 0xCC, 0x07, 0x30, 0x1F, 0xC0, ++0x7F, 0x00, 0xF7, 0x01, 0xCC, 0x27, 0x38, 0x1F, 0xC0, 0x7F, 0x00, 0x73, 0x01, ++0x8C, 0x87, 0xB8, 0x97, 0xC0, 0x5C, 0x00, 0xEF, 0x21, 0xCC, 0x05, 0xF0, 0x17, ++0xC0, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x39, 0x00, ++0xE1, 0x00, 0xB4, 0x03, 0xD8, 0x0E, 0x40, 0x3B, 0x02, 0xE1, 0x00, 0xB4, 0x03, ++0xD0, 0x82, 0x40, 0x3B, 0x00, 0x7D, 0x08, 0xC4, 0x03, 0x10, 0x0E, 0x40, 0x3B, ++0x00, 0x7D, 0x04, 0x84, 0x01, 0x14, 0x4E, 0x40, 0x3B, 0x01, 0x3B, 0x00, 0x85, ++0x43, 0x10, 0xCE, 0x40, 0x18, 0x01, 0xED, 0x08, 0x94, 0x62, 0xD0, 0x62, 0x40, ++0x54, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x08, 0xE1, ++0x00, 0xB4, 0x23, 0xD8, 0x0E, 0x40, 0x9B, 0x04, 0xE1, 0x00, 0xB4, 0x23, 0xD0, ++0x0E, 0x40, 0x3B, 0x88, 0x6D, 0x00, 0x84, 0x09, 0x10, 0x0E, 0x40, 0x3B, 0x00, ++0xE5, 0x80, 0x94, 0x03, 0x18, 0x0A, 0x4C, 0x3B, 0x10, 0xE1, 0x00, 0xB4, 0x03, ++0x90, 0x0F, 0x44, 0x89, 0x10, 0xED, 0x00, 0x84, 0x00, 0xD0, 0x0A, 0x61, 0x60, ++0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x35, 0x00, 0xC1, 0x40, ++0x34, 0x1A, 0xD0, 0x0C, 0x40, 0x67, 0xC0, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x00, ++0x40, 0x33, 0x80, 0x0D, 0x00, 0x05, 0x02, 0x10, 0x0C, 0x40, 0x33, 0x10, 0x8D, ++0x40, 0x44, 0x00, 0x18, 0x08, 0x40, 0x33, 0x20, 0x01, 0x00, 0x24, 0x03, 0x10, ++0x2C, 0x40, 0x50, 0x10, 0xCD, 0x01, 0x14, 0x0A, 0xD8, 0x20, 0x42, 0x08, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x3D, 0x00, 0xF3, 0x00, 0x7C, ++0x16, 0xD0, 0x0D, 0xC4, 0x47, 0x00, 0xF3, 0x00, 0x7C, 0x0B, 0xD0, 0x01, 0xC0, ++0x37, 0x00, 0x9F, 0x00, 0x4C, 0x04, 0x30, 0x0D, 0xC0, 0x37, 0x00, 0x17, 0x00, ++0x5C, 0x02, 0x30, 0x09, 0x00, 0x37, 0x00, 0x91, 0x00, 0x6C, 0x8B, 0xB0, 0x2C, ++0xC1, 0x50, 0x01, 0xDF, 0x00, 0x40, 0x08, 0xD0, 0x89, 0xC0, 0x74, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x02, ++0xF0, 0x0D, 0xC0, 0x07, 0x00, 0xDF, 0x00, 0x7C, 0x43, 0xF0, 0x01, 0xC0, 0x33, ++0x00, 0x1F, 0x02, 0x7C, 0x20, 0xF0, 0x0D, 0xC8, 0x37, 0x00, 0x9F, 0x02, 0x7C, ++0x0A, 0xF0, 0x09, 0xE0, 0xA7, 0x08, 0x9F, 0x42, 0x5C, 0x43, 0xF2, 0x0D, 0xD0, ++0xB7, 0x08, 0xDF, 0x2A, 0x7C, 0x08, 0xF0, 0x29, 0xD0, 0x17, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0xF3, 0x00, 0xFC, 0x00, 0xF0, ++0x0F, 0xC0, 0x27, 0x00, 0xF3, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x3F, 0x40, ++0xB3, 0x00, 0x9C, 0x02, 0x30, 0x0F, 0xC0, 0x3F, 0x00, 0x3F, 0x00, 0x7C, 0x02, ++0xB0, 0x03, 0xC0, 0x3F, 0x20, 0xAF, 0x20, 0xDC, 0x03, 0x30, 0x0F, 0xC1, 0x1D, ++0x00, 0xB6, 0x00, 0xCC, 0x42, 0x80, 0x09, 0xC0, 0x07, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x40, 0xD1, 0x00, 0x74, 0x04, 0xD0, 0x0D, ++0x60, 0x67, 0x00, 0xD1, 0x00, 0x74, 0x03, 0xD0, 0x39, 0x40, 0x37, 0x00, 0x91, ++0x03, 0x5C, 0x06, 0x10, 0x0D, 0x40, 0x37, 0x00, 0x9D, 0x01, 0x74, 0x46, 0x10, ++0x11, 0x41, 0x67, 0x01, 0x19, 0x01, 0x04, 0x06, 0xB0, 0x3D, 0x40, 0x74, 0x01, ++0x01, 0x45, 0x44, 0x4E, 0x90, 0x19, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0xA0, 0x34, 0x00, 0xD1, 0x00, 0x76, 0x04, 0xD0, 0x0D, 0x4A, ++0x47, 0x04, 0xD1, 0x00, 0x74, 0x03, 0xD0, 0x39, 0x40, 0x37, 0x00, 0x91, 0x11, ++0x74, 0x04, 0x10, 0x0D, 0x40, 0x37, 0x00, 0x1D, 0x01, 0x74, 0x04, 0x10, 0x19, ++0x40, 0x77, 0x00, 0x9D, 0x03, 0x40, 0x47, 0x10, 0x8D, 0x01, 0x55, 0x00, 0xD5, ++0x81, 0x44, 0x84, 0x90, 0x11, 0x48, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x00, 0x30, 0x00, 0xC1, 0x00, 0x34, 0x06, 0xD0, 0x0C, 0x40, 0x03, ++0x00, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x00, 0x40, 0x33, 0x00, 0x01, 0x00, 0x14, ++0x00, 0x10, 0x0C, 0x40, 0x33, 0x00, 0x0D, 0x00, 0x34, 0x00, 0x90, 0x08, 0x64, ++0x33, 0x00, 0x89, 0x00, 0x47, 0x01, 0x90, 0x0C, 0x40, 0x30, 0x08, 0xD5, 0x00, ++0x04, 0x00, 0x90, 0x00, 0x44, 0x43, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x38, 0x3A, 0x00, 0xF3, 0x00, 0x7C, 0x00, 0xF0, 0x0D, 0x40, 0x07, 0x00, ++0xF3, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x37, 0x00, 0x93, 0x00, 0x5C, 0x00, ++0x30, 0x0D, 0xC0, 0x37, 0x00, 0x1D, 0x00, 0x7C, 0x02, 0x30, 0x01, 0xC0, 0x37, ++0x00, 0x9F, 0x00, 0x5C, 0x03, 0x30, 0x0D, 0xC0, 0x15, 0x08, 0xD7, 0x00, 0x4D, ++0x80, 0xB0, 0x09, 0xC0, 0x07, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xB8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC4, 0x2F, 0x00, 0xFF, ++0x00, 0xFC, 0x03, 0xF2, 0x03, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xDC, 0x02, 0xF0, ++0x0F, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0x70, 0x03, 0xC0, 0x1B, 0x80, ++0x3F, 0x00, 0xFC, 0x01, 0xD0, 0x0E, 0xC0, 0x3F, 0x00, 0xFB, 0x00, 0xFE, 0x02, ++0xF0, 0x0B, 0xC0, 0x17, 0x42, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, ++0x6F, 0x00, 0xF3, 0x01, 0xFC, 0x40, 0xF0, 0x02, 0xC0, 0x2C, 0x00, 0xB3, 0x40, ++0xEC, 0x02, 0x70, 0x1F, 0xC0, 0x2F, 0x00, 0xFB, 0x10, 0xFC, 0x02, 0x30, 0x03, ++0xC0, 0x68, 0x00, 0xFF, 0x00, 0xCC, 0x07, 0xB0, 0x0F, 0xC0, 0x3E, 0x09, 0xFF, ++0x01, 0xAC, 0x07, 0xF0, 0x4F, 0xC0, 0x7B, 0x00, 0xB3, 0x00, 0xCD, 0x03, 0x34, ++0x0F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x21, ++0x00, 0xD1, 0x10, 0x5C, 0x00, 0xD0, 0x11, 0x40, 0x6C, 0x08, 0x91, 0x0B, 0x58, ++0x00, 0x10, 0x1D, 0xC0, 0xA5, 0x06, 0xC1, 0x12, 0x74, 0x02, 0x10, 0x11, 0xC8, ++0x65, 0x00, 0xCD, 0x00, 0x54, 0x07, 0x10, 0x0D, 0x40, 0x74, 0x12, 0xDD, 0x01, ++0x54, 0x07, 0xD2, 0xBD, 0x40, 0x77, 0x40, 0x91, 0x10, 0x44, 0x0B, 0x10, 0x1D, ++0x00, 0x0F, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x33, 0x00, ++0xC1, 0x00, 0x34, 0x04, 0xD0, 0x10, 0x40, 0x20, 0x00, 0xD1, 0x00, 0x04, 0x00, ++0x50, 0x0C, 0x40, 0x23, 0x09, 0xC1, 0x84, 0x34, 0x02, 0x12, 0x00, 0x40, 0x20, ++0x00, 0xC1, 0x00, 0x04, 0x03, 0x90, 0x0C, 0x40, 0x30, 0x00, 0xDD, 0x00, 0x04, ++0x03, 0x90, 0x0C, 0x40, 0x35, 0x80, 0x95, 0x84, 0x04, 0x70, 0x14, 0x0C, 0x40, ++0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, 0xD1, ++0x00, 0x74, 0x04, 0xD0, 0x41, 0x40, 0x64, 0x40, 0xD1, 0x08, 0x74, 0x44, 0x10, ++0x0D, 0x40, 0x27, 0x40, 0xD1, 0x00, 0x74, 0x06, 0x10, 0x01, 0x40, 0x26, 0x00, ++0xDD, 0x00, 0x54, 0x83, 0x10, 0x0D, 0x40, 0x34, 0x00, 0x1D, 0x01, 0x54, 0x13, ++0xD0, 0x0D, 0x40, 0x27, 0x40, 0xD5, 0x18, 0x44, 0x02, 0x10, 0x0D, 0x48, 0x0F, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x88, 0x36, 0x00, 0xD3, 0x00, ++0x7C, 0x04, 0xF2, 0x14, 0xD0, 0x64, 0x00, 0x83, 0x80, 0x4C, 0x0E, 0x70, 0x0D, ++0xC0, 0x27, 0x00, 0xDB, 0x00, 0x7C, 0x1E, 0x30, 0x15, 0xD0, 0x24, 0x00, 0xDF, ++0x00, 0x0C, 0x03, 0xB1, 0x0D, 0xC0, 0x36, 0x00, 0xCF, 0x81, 0x4C, 0x03, 0xF0, ++0x0D, 0xC0, 0x33, 0x00, 0x87, 0x03, 0x4C, 0x27, 0x30, 0x0D, 0xC0, 0x03, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xFF, 0x00, 0xDC, ++0x40, 0xF0, 0x07, 0xC0, 0x3F, 0x08, 0xBF, 0x00, 0x9C, 0x02, 0xD0, 0x0F, 0xC0, ++0x21, 0x00, 0xFF, 0x00, 0xBC, 0x02, 0xF0, 0x96, 0xC0, 0x6D, 0x01, 0xEF, 0x00, ++0xFC, 0x03, 0xF0, 0x0E, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xDC, 0x07, 0xF0, 0x0F, ++0xC0, 0x3F, 0x00, 0xFB, 0x01, 0xFC, 0x03, 0xF0, 0x0D, 0xC0, 0x1F, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0x35, 0x00, 0xD3, 0x00, 0x74, 0x00, ++0x30, 0x85, 0xC0, 0x25, 0x00, 0xD3, 0x00, 0x7C, 0x08, 0xF0, 0x0D, 0xC0, 0x37, ++0x00, 0xDF, 0x00, 0x4C, 0x3A, 0xD0, 0x05, 0x40, 0x24, 0x20, 0xD3, 0x08, 0x4D, ++0x03, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xD3, 0x00, 0x7C, 0x02, 0x70, 0x0D, 0xC0, ++0x37, 0x00, 0x93, 0x00, 0x4D, 0x03, 0xF0, 0x0D, 0xC0, 0x28, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, 0x00, 0xD5, 0x05, 0x74, 0x14, 0x10, ++0x07, 0xC0, 0xB2, 0x00, 0xD1, 0x00, 0x74, 0x28, 0xD0, 0x0D, 0x40, 0x37, 0x00, ++0xF1, 0x00, 0x7C, 0x06, 0xD1, 0x0D, 0x43, 0x25, 0x00, 0xF5, 0x00, 0x54, 0x2F, ++0xD0, 0x0F, 0x40, 0x7C, 0x00, 0x51, 0x11, 0x7C, 0x02, 0x10, 0x1F, 0x40, 0x37, ++0x00, 0xD1, 0x04, 0x2C, 0x2F, 0xD0, 0x0F, 0x50, 0x4C, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0xA0, 0x26, 0x00, 0xC1, 0x01, 0x34, 0x0C, 0x18, 0x10, ++0x40, 0x20, 0x04, 0x81, 0x00, 0x34, 0x06, 0xD8, 0x0C, 0x40, 0x23, 0x00, 0xC9, ++0x40, 0x14, 0x0C, 0xD0, 0x04, 0x70, 0x20, 0x40, 0xC1, 0x00, 0x04, 0x03, 0xD8, ++0x0C, 0x40, 0x71, 0x00, 0xC1, 0x00, 0x34, 0x02, 0x18, 0x1C, 0x40, 0x33, 0x00, ++0x88, 0x80, 0x14, 0x07, 0xD0, 0x0C, 0x40, 0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0F, 0x80, 0x68, 0x00, 0xE1, 0x01, 0xB4, 0x24, 0x18, 0x3B, 0x40, ++0x62, 0x00, 0xA0, 0x01, 0xB4, 0x45, 0xD8, 0x1E, 0x42, 0x6B, 0x60, 0xE1, 0x03, ++0xA4, 0x26, 0xD0, 0x14, 0x40, 0x6D, 0x00, 0xE5, 0x01, 0x94, 0x07, 0xD0, 0x1E, ++0x40, 0x79, 0x00, 0xE1, 0x01, 0xF4, 0x06, 0x10, 0x1E, 0x40, 0x7F, 0x40, 0x49, ++0x81, 0xB4, 0x47, 0xD0, 0x1E, 0x40, 0x7C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x10, 0x30, 0x08, 0xC3, 0x08, 0x7C, 0x20, 0x30, 0x00, 0x40, 0xA1, ++0x40, 0xC3, 0x00, 0x3C, 0x03, 0xF0, 0x0C, 0xC0, 0x23, 0x00, 0xCF, 0x00, 0x1C, ++0x03, 0xF0, 0x84, 0x42, 0x20, 0x02, 0xC3, 0x00, 0x0C, 0x43, 0xF0, 0x0D, 0x48, ++0x31, 0x44, 0xC3, 0x88, 0x3E, 0x02, 0x71, 0x0C, 0xC1, 0x33, 0x00, 0x0B, 0x00, ++0x1C, 0x01, 0xF0, 0x8C, 0xC0, 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xB8, 0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x20, 0xC4, 0x8B, 0xC0, 0x1F, 0x02, ++0xFF, 0x00, 0xFC, 0x23, 0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xF7, 0x10, 0xFC, 0x03, ++0xA0, 0x87, 0xC0, 0x2E, 0x10, 0xFB, 0x00, 0xEC, 0x03, 0xF0, 0x0F, 0xC0, 0x3A, ++0x02, 0x7F, 0x08, 0xDC, 0x22, 0xF4, 0x8F, 0xC0, 0x2F, 0x42, 0xF7, 0x00, 0xCE, ++0x03, 0xF0, 0x0F, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA0, 0x37, 0x00, 0xDF, 0x00, 0x7E, 0x04, 0x30, 0x01, 0xC0, 0x2C, 0x01, 0x93, ++0x00, 0xEC, 0x07, 0x30, 0x0D, 0xC0, 0x26, 0x00, 0xDF, 0x00, 0x1C, 0x02, 0x30, ++0x05, 0xC0, 0x26, 0x00, 0xFF, 0x00, 0x4C, 0x03, 0xF0, 0x8D, 0xE0, 0x37, 0x00, ++0xD3, 0x00, 0x7C, 0x02, 0xF0, 0x1D, 0xC0, 0x34, 0x00, 0x13, 0x81, 0x4C, 0x07, ++0x34, 0x0F, 0xC0, 0x57, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x88, ++0x39, 0x00, 0xED, 0x00, 0xB6, 0x00, 0x12, 0x62, 0xC0, 0x38, 0x04, 0xE1, 0x00, ++0xF4, 0x03, 0x10, 0x0E, 0x40, 0x2B, 0x00, 0xFB, 0x01, 0x84, 0x02, 0x10, 0x06, ++0x40, 0x3B, 0x00, 0xFD, 0x01, 0x85, 0x03, 0xD0, 0x4E, 0x40, 0x3B, 0x00, 0xE1, ++0x40, 0xB4, 0x02, 0xD0, 0x0E, 0x40, 0x38, 0x00, 0xE1, 0x00, 0xAD, 0x03, 0x10, ++0x1E, 0x40, 0x4F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x79, ++0x00, 0xED, 0x01, 0xB4, 0x86, 0x12, 0x13, 0x40, 0x60, 0x00, 0xED, 0x21, 0xB4, ++0x0F, 0xD0, 0x1E, 0x40, 0x73, 0x00, 0xE5, 0x05, 0xD4, 0x07, 0xD9, 0x16, 0x41, ++0x6B, 0x00, 0xED, 0x21, 0xA4, 0x07, 0x50, 0x1E, 0x40, 0x72, 0x20, 0xE1, 0x03, ++0xB4, 0x06, 0xD0, 0x1C, 0x40, 0x7E, 0x00, 0x25, 0x03, 0x84, 0x07, 0x10, 0x1E, ++0x40, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x73, 0x02, ++0xCD, 0x00, 0x34, 0x03, 0x10, 0x48, 0x06, 0x52, 0x00, 0xC9, 0x00, 0x34, 0xCF, ++0x90, 0x0C, 0x40, 0x73, 0x00, 0xC9, 0x00, 0x04, 0x13, 0x90, 0x7C, 0x40, 0x23, ++0x00, 0xDD, 0x00, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x49, 0x01, 0x34, ++0x02, 0xD0, 0x0C, 0x40, 0x70, 0x00, 0xC5, 0x04, 0x24, 0x4B, 0x10, 0x0C, 0x40, ++0x4B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x55, 0x00, 0x5F, ++0x00, 0xFC, 0x49, 0x34, 0x47, 0xD0, 0x5C, 0x41, 0x5F, 0x11, 0xFC, 0x01, 0xF4, ++0x05, 0xC0, 0x57, 0x00, 0x57, 0x00, 0xDC, 0x01, 0xE0, 0x27, 0xE0, 0x17, 0x00, ++0x5F, 0x00, 0x6E, 0x81, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x63, 0x01, 0x3C, 0x15, ++0xF2, 0x05, 0xF0, 0x54, 0x01, 0x77, 0x03, 0xC4, 0x1D, 0x30, 0x05, 0xC0, 0x5F, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x02, ++0x7C, 0xC0, 0xF0, 0x01, 0xC0, 0x85, 0x00, 0x17, 0x00, 0x7C, 0x08, 0x72, 0x01, ++0xC0, 0x07, 0x02, 0x1F, 0x02, 0x7C, 0x00, 0x74, 0x01, 0xC0, 0x07, 0x02, 0x1F, ++0x40, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x40, 0x17, 0x00, 0x7C, 0x00, 0xF0, ++0x21, 0xE0, 0x07, 0x40, 0x1A, 0x00, 0x7C, 0x08, 0xF0, 0x01, 0xC8, 0x4B, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x93, 0x02, 0x7C, ++0x02, 0xF0, 0x08, 0xC0, 0x20, 0x00, 0x83, 0x03, 0x6C, 0x06, 0xF0, 0x09, 0xC0, ++0x23, 0x40, 0x91, 0x00, 0x04, 0x26, 0x34, 0x09, 0x00, 0x27, 0x00, 0x9F, 0x00, ++0x68, 0x06, 0xD0, 0x09, 0xE0, 0xE7, 0x08, 0x93, 0x45, 0x4C, 0x06, 0x32, 0x09, ++0xC0, 0x27, 0x08, 0x93, 0x00, 0x7C, 0x22, 0xF0, 0x09, 0xC0, 0x43, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x22, 0x40, 0x91, 0x01, 0x74, 0x82, ++0xD0, 0x09, 0x40, 0xA4, 0x04, 0x91, 0x01, 0x44, 0x36, 0xD0, 0x09, 0x40, 0x27, ++0x00, 0x95, 0x12, 0x6C, 0x0A, 0x10, 0x19, 0x42, 0x27, 0x00, 0x9D, 0x20, 0x44, ++0x06, 0xF0, 0x09, 0x40, 0x63, 0x01, 0x9B, 0x01, 0x44, 0x06, 0xB0, 0x29, 0x44, ++0x23, 0x40, 0x93, 0x0E, 0x5C, 0x1E, 0xD0, 0x09, 0x40, 0x07, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x20, 0x91, 0x00, 0x54, 0x06, 0xD2, ++0x09, 0x40, 0x24, 0x00, 0x91, 0x00, 0x64, 0x02, 0xD0, 0x09, 0x40, 0x25, 0x00, ++0x8D, 0x01, 0x74, 0x02, 0x50, 0x89, 0x64, 0x27, 0x00, 0x9D, 0x00, 0x75, 0x12, ++0xD2, 0x09, 0x00, 0x27, 0x80, 0x91, 0x00, 0x45, 0x12, 0x50, 0x89, 0x41, 0x27, ++0x00, 0x99, 0x00, 0x74, 0x02, 0xD2, 0x09, 0x44, 0x63, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x22, 0x24, 0x00, 0x81, 0x00, 0x34, 0x12, 0xD0, 0x48, ++0x50, 0x20, 0x01, 0x81, 0x84, 0x04, 0x02, 0xD8, 0x08, 0x40, 0x23, 0x01, 0x89, ++0x04, 0x34, 0x13, 0x00, 0x48, 0x60, 0x23, 0x20, 0x8D, 0x04, 0x14, 0x02, 0x50, ++0xC8, 0x40, 0x23, 0x01, 0x89, 0x00, 0x04, 0x02, 0xD0, 0x08, 0x40, 0x27, 0x00, ++0x81, 0x04, 0x34, 0x12, 0xD0, 0x48, 0x48, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xB0, 0x86, 0x02, 0x53, 0x0A, 0x1C, 0x28, 0xF0, 0x05, 0x50, ++0x04, 0x40, 0x13, 0x00, 0x6C, 0x08, 0xF0, 0x01, 0xC4, 0x87, 0x02, 0x1D, 0x0A, ++0x7C, 0x28, 0x50, 0x01, 0xC0, 0x07, 0x00, 0x1D, 0x0A, 0x7C, 0x80, 0xC2, 0x61, ++0x40, 0x07, 0x05, 0x13, 0x00, 0x4C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1B, ++0x8A, 0x38, 0x28, 0xF0, 0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x19, 0xB8, 0x2F, 0x00, 0x9F, 0x00, 0xFC, 0x22, 0xF2, 0x8A, 0xD0, 0x2F, ++0x02, 0xBF, 0x08, 0xFC, 0x62, 0xF0, 0x09, 0xC0, 0x2F, 0x02, 0x97, 0x08, 0xEC, ++0x22, 0xF2, 0x8B, 0xC0, 0x2F, 0x00, 0x9B, 0x08, 0x6C, 0x02, 0xF0, 0x29, 0xCA, ++0x27, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xB0, 0x89, 0xC2, 0x2B, 0x00, 0xA7, 0x08, ++0xDC, 0x22, 0xF0, 0x89, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x19, 0xA0, 0x27, 0x00, 0xBF, 0x08, 0xFC, 0x02, 0x30, 0x0B, 0xC0, 0x2C, 0x00, ++0xBF, 0x04, 0xFC, 0x52, 0xB0, 0x0B, 0xC0, 0x27, 0x40, 0xBB, 0x00, 0xC8, 0x22, ++0x34, 0x4B, 0xC0, 0x24, 0x00, 0xBF, 0x0C, 0xDD, 0x02, 0xB0, 0x19, 0xC0, 0x6F, ++0x00, 0xB3, 0x00, 0xFC, 0x02, 0xF0, 0x5B, 0xC0, 0x20, 0x00, 0xB3, 0x00, 0xCC, ++0x22, 0x30, 0x4B, 0xC0, 0x67, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, ++0x08, 0x07, 0x01, 0x1D, 0x04, 0x36, 0xC9, 0x10, 0x05, 0xE2, 0x04, 0x02, 0x1D, ++0x00, 0x74, 0x10, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x13, 0x00, 0x54, 0x20, 0x18, ++0x01, 0xE0, 0x06, 0x80, 0x0D, 0x0C, 0x44, 0x00, 0x50, 0x11, 0x40, 0x07, 0x02, ++0x11, 0x00, 0x74, 0x00, 0xD0, 0xA1, 0x40, 0x04, 0x00, 0x11, 0x10, 0x44, 0x20, ++0x10, 0x01, 0x40, 0x73, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, ++0x23, 0x05, 0x8D, 0x04, 0x34, 0xB2, 0x10, 0x88, 0x40, 0x20, 0x00, 0x8D, 0x08, ++0x34, 0x52, 0xD0, 0x08, 0x42, 0x23, 0x00, 0x85, 0x00, 0x04, 0x02, 0x54, 0x88, ++0x42, 0x22, 0x00, 0x8D, 0x04, 0x14, 0x02, 0x10, 0x68, 0x41, 0x23, 0x00, 0x81, ++0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x26, 0x10, 0x85, 0x48, 0x04, 0x07, 0x14, ++0x88, 0x40, 0x4B, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, ++0x00, 0x9D, 0x00, 0x74, 0x06, 0x14, 0x09, 0x40, 0x26, 0x04, 0x9D, 0x01, 0x74, ++0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x89, 0x00, 0x54, 0x52, 0x10, 0x09, 0x40, ++0x26, 0x01, 0x9D, 0x00, 0x44, 0x02, 0x52, 0x09, 0x40, 0x27, 0x40, 0x91, 0x08, ++0x74, 0x12, 0xD0, 0x0D, 0x40, 0x66, 0x40, 0x95, 0x04, 0x04, 0x06, 0x10, 0x09, ++0x40, 0x63, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, ++0x9F, 0x00, 0x74, 0x0E, 0x30, 0x29, 0x50, 0xE4, 0x00, 0x9F, 0x01, 0x7C, 0x46, ++0xF0, 0x09, 0xC0, 0x67, 0x00, 0x97, 0x00, 0x4C, 0x02, 0x50, 0x09, 0x41, 0x26, ++0x80, 0x9D, 0x00, 0x5C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x92, 0x03, 0x7C, ++0x06, 0xF2, 0x09, 0xD0, 0x22, 0x00, 0x97, 0x07, 0x4D, 0x02, 0x30, 0x09, 0xC0, ++0x17, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80, 0x65, 0x02, 0x9F, ++0x10, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x25, 0x05, 0x9F, 0x00, 0x7C, 0x4E, 0xF0, ++0x09, 0xC0, 0x67, 0x02, 0x97, 0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC0, 0x67, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0x70, 0x09, 0x80, 0x23, 0x00, 0x9F, 0x00, 0x7C, 0x06, ++0xF0, 0x08, 0xC0, 0x25, 0x00, 0x9B, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC2, 0x5B, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, ++0x7C, 0x18, 0x94, 0x31, 0x50, 0x06, 0x40, 0x13, 0x00, 0x7C, 0x20, 0x70, 0x01, ++0xC0, 0x07, 0x00, 0x1D, 0x48, 0x78, 0x48, 0x32, 0x21, 0xC0, 0x07, 0x00, 0x1F, ++0x00, 0x4C, 0x40, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1B, 0x00, 0x7C, 0x00, 0xF0, ++0x41, 0xC0, 0x07, 0x00, 0x03, 0x02, 0x4C, 0x04, 0x30, 0x01, 0xC0, 0x50, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x14, 0x00, 0x7D, 0x04, 0xF4, ++0x01, 0x30, 0x46, 0x40, 0x5C, 0x00, 0x51, 0x11, 0xF4, 0x09, 0x70, 0x55, 0x40, ++0x17, 0x00, 0x7D, 0x00, 0xF4, 0x09, 0x10, 0x14, 0x40, 0x17, 0x00, 0x5D, 0x00, ++0x84, 0x41, 0x70, 0x05, 0x40, 0x1F, 0x01, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x27, ++0x40, 0x17, 0x00, 0x72, 0x00, 0xC4, 0x01, 0x14, 0x05, 0xC1, 0x52, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x03, 0x74, 0x03, ++0x10, 0x1C, 0x60, 0xB0, 0x00, 0xC1, 0x00, 0x34, 0x0B, 0x58, 0x0C, 0x40, 0x37, ++0x00, 0x8D, 0x01, 0x74, 0x09, 0x10, 0x0C, 0x40, 0x33, 0x00, 0xDD, 0x01, 0x14, ++0x8F, 0xD0, 0x0C, 0x40, 0xF3, 0x01, 0x89, 0x00, 0x34, 0x03, 0xD0, 0x24, 0x40, ++0x33, 0x80, 0x49, 0x0D, 0x04, 0x02, 0x12, 0x18, 0x00, 0x50, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x38, 0x01, 0xA9, 0x00, 0xB4, 0x18, 0x10, ++0x02, 0x40, 0x70, 0x04, 0xE1, 0x00, 0xB4, 0x01, 0x50, 0x0E, 0x40, 0x3A, 0x01, ++0x29, 0x00, 0xA4, 0x00, 0x14, 0x0A, 0x41, 0x3B, 0x00, 0xED, 0x02, 0x84, 0x03, ++0x40, 0x4E, 0x40, 0x2B, 0x00, 0xAD, 0x00, 0xB4, 0x03, 0xD0, 0x06, 0x41, 0x3F, ++0x00, 0x61, 0x00, 0x84, 0x02, 0x10, 0x18, 0x40, 0x16, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x10, 0x78, 0x01, 0xAD, 0x01, 0xBC, 0x0E, 0x30, 0x14, ++0xD0, 0x78, 0x00, 0xE3, 0x41, 0xBE, 0x07, 0x70, 0x1E, 0xC0, 0x7B, 0x01, 0x6D, ++0x01, 0x3C, 0x05, 0x30, 0x1A, 0xC0, 0x7B, 0x00, 0xEF, 0x01, 0x9D, 0x07, 0xD0, ++0x5E, 0xC2, 0x7B, 0x00, 0xAB, 0x01, 0xB4, 0x06, 0xF0, 0x16, 0xC0, 0x7B, 0x00, ++0xF9, 0x01, 0x8D, 0x07, 0x30, 0x1A, 0xC4, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xB8, 0xB5, 0x00, 0xBF, 0x00, 0x7C, 0x00, 0x70, 0x01, 0xC0, ++0x17, 0x00, 0xDF, 0x00, 0x7E, 0x03, 0xC0, 0x0D, 0xC0, 0x77, 0x00, 0x5F, 0x00, ++0xFC, 0x00, 0xF0, 0x09, 0x80, 0x37, 0x00, 0xDF, 0x02, 0x7C, 0x03, 0x70, 0x8D, ++0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x05, 0xC0, 0x37, 0x40, 0xDF, ++0x00, 0x3C, 0x00, 0xF4, 0x09, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xA0, 0xFF, 0x04, 0xB3, 0x01, 0xFC, 0x23, 0x38, 0x03, 0xC0, 0x6C, ++0x00, 0xF3, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0x40, 0x7F, 0x06, 0xF3, 0x01, 0xCC, ++0x85, 0x30, 0x1B, 0xE0, 0x7F, 0x02, 0xAF, 0x03, 0xCC, 0x06, 0xF0, 0x1F, 0xC0, ++0x4F, 0x00, 0xBF, 0x01, 0xFC, 0x07, 0xF0, 0x16, 0xC0, 0x7C, 0x40, 0xFB, 0x81, ++0xFC, 0x06, 0x31, 0x1A, 0xC0, 0x08, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x88, 0x3D, 0x00, 0xA1, 0x00, 0xB4, 0x13, 0x18, 0x42, 0x00, 0x28, 0x40, ++0xE1, 0x50, 0xB4, 0x01, 0xD0, 0x0E, 0x40, 0x3F, 0x00, 0x6F, 0x00, 0x94, 0x02, ++0x10, 0x0A, 0xC0, 0x3B, 0x00, 0xED, 0x24, 0x84, 0x03, 0xD0, 0x8E, 0x40, 0x1B, ++0x00, 0xAD, 0x00, 0xB4, 0x23, 0xD0, 0x06, 0xC0, 0x38, 0x00, 0xE1, 0x00, 0xB4, ++0x02, 0x10, 0x0A, 0x40, 0x55, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, ++0x00, 0x39, 0x00, 0x21, 0x00, 0xB4, 0x22, 0x18, 0x83, 0x40, 0x20, 0x00, 0xE9, ++0x08, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x40, 0x61, 0x00, 0x04, 0x01, 0x90, ++0x0A, 0x40, 0x3B, 0x20, 0xAD, 0x40, 0xA4, 0x03, 0xD0, 0x0E, 0x40, 0x2B, 0x00, ++0xAD, 0x00, 0xB4, 0x02, 0xD0, 0x06, 0x40, 0x3D, 0x00, 0xE1, 0x00, 0x34, 0x0B, ++0x10, 0x0A, 0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, ++0x33, 0x00, 0x11, 0x00, 0x34, 0x02, 0x12, 0x20, 0x40, 0x00, 0x00, 0xC9, 0x00, ++0x34, 0x26, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x4D, 0x00, 0x14, 0x00, 0x90, 0x28, ++0x40, 0x71, 0x00, 0xCD, 0x00, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, ++0x02, 0x24, 0x02, 0xD0, 0x04, 0x40, 0x30, 0x10, 0x81, 0x02, 0x34, 0x03, 0x11, ++0x08, 0x40, 0x19, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x3D, ++0x40, 0x93, 0x00, 0xFC, 0x03, 0x14, 0x21, 0xC0, 0xE4, 0x02, 0xDB, 0x01, 0x74, ++0x2A, 0xF0, 0x0C, 0xC0, 0x3F, 0x00, 0x93, 0x00, 0x4C, 0x01, 0xB4, 0x09, 0x40, ++0x37, 0x00, 0x9F, 0x00, 0x6D, 0x01, 0xF0, 0x0F, 0xC0, 0x37, 0x00, 0x8F, 0x13, ++0x7C, 0x02, 0xF0, 0x04, 0xC0, 0x34, 0x00, 0x53, 0x0B, 0x7C, 0x82, 0x30, 0x0D, ++0xC0, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, ++0x9F, 0x00, 0x7C, 0x20, 0xF0, 0x00, 0xD0, 0xE7, 0x10, 0xD7, 0x00, 0x7C, 0x80, ++0xF0, 0x0D, 0xC0, 0x37, 0x00, 0x17, 0x00, 0x3C, 0x40, 0x70, 0x09, 0xC0, 0x37, ++0x02, 0x9F, 0x00, 0x5C, 0x83, 0xF2, 0x0D, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, ++0x02, 0xF0, 0x05, 0xC0, 0x75, 0x00, 0x47, 0x81, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, ++0x27, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x3F, 0x00, 0xBF, ++0x00, 0x8C, 0x23, 0xB0, 0x03, 0xD1, 0x28, 0x00, 0xB3, 0x05, 0xFC, 0x00, 0xF0, ++0x0F, 0xC0, 0x38, 0x00, 0x6B, 0x00, 0xCC, 0x00, 0xB0, 0x8B, 0xE1, 0x3F, 0x00, ++0xBF, 0x00, 0xCC, 0x01, 0xF0, 0x0F, 0xC0, 0x4F, 0x00, 0xBF, 0x14, 0xDC, 0x0F, ++0xF0, 0x0F, 0xC0, 0x3C, 0x00, 0xF3, 0x00, 0x8C, 0x22, 0x10, 0x9F, 0xC0, 0x07, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x36, 0x00, 0x9D, 0x01, ++0x44, 0x04, 0x90, 0x11, 0x58, 0x44, 0x04, 0x91, 0x00, 0x76, 0x04, 0xD0, 0x0D, ++0xE0, 0x36, 0x00, 0x51, 0x00, 0x44, 0x04, 0x10, 0x09, 0xC0, 0x36, 0x00, 0x9D, ++0x00, 0x6C, 0x47, 0xD0, 0x0D, 0x40, 0x97, 0x02, 0xDD, 0x01, 0x6C, 0x07, 0xD0, ++0x3D, 0xC0, 0x32, 0x00, 0xD1, 0x01, 0x44, 0x04, 0x10, 0x1D, 0xC2, 0x25, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x10, 0x9D, 0x01, 0x44, ++0x03, 0x90, 0x11, 0x40, 0x46, 0x40, 0xD1, 0x00, 0x74, 0x0E, 0xD1, 0x19, 0x42, ++0x34, 0x00, 0xD9, 0x00, 0x44, 0x05, 0x9A, 0x09, 0x40, 0x37, 0x20, 0x8D, 0x08, ++0x46, 0x07, 0xD0, 0x0D, 0x42, 0x17, 0x04, 0x9D, 0x00, 0x54, 0x02, 0xD0, 0x1D, ++0x40, 0x34, 0x00, 0xD1, 0x01, 0x40, 0x02, 0x50, 0x09, 0x40, 0x07, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0x8D, 0x00, 0x04, 0x03, ++0x90, 0x10, 0x40, 0x02, 0x00, 0xC1, 0x00, 0x34, 0x00, 0xD2, 0x08, 0x40, 0x32, ++0x00, 0x41, 0x00, 0x04, 0x02, 0x10, 0x08, 0x60, 0x31, 0x00, 0x8D, 0x00, 0x05, ++0x03, 0xD8, 0x0C, 0x40, 0x03, 0x00, 0xDD, 0x00, 0x04, 0x02, 0xD0, 0x0C, 0x48, ++0x36, 0x00, 0xC1, 0x00, 0x04, 0x02, 0x50, 0x08, 0x40, 0x41, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0xB0, 0x3E, 0x00, 0x1F, 0x00, 0x05, 0x03, 0xB0, ++0x01, 0xC0, 0x06, 0x00, 0xD3, 0x00, 0x74, 0x02, 0xF0, 0x09, 0x40, 0x34, 0x00, ++0x4B, 0x00, 0x4C, 0x00, 0xB0, 0x09, 0x44, 0x37, 0x00, 0xBF, 0x00, 0x44, 0x03, ++0xF0, 0x0D, 0xC0, 0x07, 0x00, 0x9F, 0x00, 0x54, 0x03, 0xF0, 0x0D, 0xC0, 0x34, ++0x00, 0xD3, 0x00, 0x4D, 0x02, 0x70, 0x09, 0xC0, 0x07, 0xC0, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0x78, 0x02, ++0xC0, 0x0D, 0x00, 0xFF, 0x40, 0xF6, 0x02, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0x7F, ++0x00, 0xFD, 0x00, 0xF0, 0x0B, 0xC8, 0x3E, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC0, 0x1F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x3B, 0x00, ++0xFF, 0x00, 0xFC, 0x02, 0xB0, 0x0B, 0xC0, 0x15, 0x60, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA0, 0x7F, 0x02, 0xF3, 0x01, 0xFC, 0x27, 0xF0, 0x1F, 0xC0, ++0x7F, 0x00, 0xF3, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, 0xFF, 0x09, ++0xCC, 0x07, 0xF0, 0x3F, 0xC0, 0x7C, 0x02, 0xFF, 0x21, 0xCC, 0x07, 0x30, 0x9F, ++0xC0, 0x78, 0x00, 0xF3, 0x01, 0xFC, 0x22, 0xF0, 0x3F, 0xC0, 0x5E, 0x10, 0xBB, ++0x01, 0xEC, 0x84, 0x38, 0x0B, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x00, 0x07, 0x00, 0x11, 0x01, 0x74, 0x10, 0xD1, 0x01, 0x40, 0x47, ++0x00, 0x11, 0x04, 0x74, 0x04, 0xD0, 0x11, 0x40, 0x47, 0x00, 0x1D, 0x04, 0x44, ++0x84, 0xD0, 0x01, 0x48, 0x04, 0x01, 0x1D, 0x01, 0x44, 0x04, 0x12, 0x41, 0x40, ++0x44, 0x40, 0x11, 0x01, 0x74, 0x38, 0xD0, 0x0D, 0x40, 0x55, 0x00, 0xD1, 0x01, ++0x54, 0x03, 0xB0, 0x01, 0x40, 0x0D, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x11, 0xA0, 0x33, 0x11, 0xC1, 0x00, 0x34, 0x83, 0xD0, 0x4C, 0x41, 0x37, 0x00, ++0xC1, 0x10, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xDD, 0x00, 0x04, 0x03, ++0xD0, 0x4D, 0x40, 0x30, 0x01, 0xD5, 0xA0, 0x64, 0x83, 0x10, 0x4C, 0x40, 0x35, ++0x00, 0xC9, 0x00, 0x34, 0x10, 0xD0, 0x4C, 0x40, 0x30, 0x60, 0xD9, 0x40, 0x24, ++0x01, 0x10, 0x08, 0x44, 0x4C, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA8, 0x05, 0x40, 0x11, 0x00, 0x74, 0x00, 0xD2, 0x01, 0x40, 0x07, 0x00, 0x11, ++0x00, 0x74, 0x00, 0xD1, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x00, 0x44, 0x00, 0xD0, ++0x01, 0x48, 0x04, 0x00, 0x1D, 0x00, 0x64, 0x00, 0x10, 0x01, 0x40, 0x04, 0x20, ++0x19, 0x00, 0x74, 0x0C, 0xD0, 0x1C, 0x40, 0x75, 0x00, 0xD1, 0x01, 0x54, 0x0B, ++0x15, 0x19, 0x41, 0x0D, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, ++0x37, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x33, 0x00, 0xD3, 0x00, ++0x7C, 0x03, 0xD0, 0x0D, 0xC0, 0x37, 0x00, 0xCF, 0x00, 0x4C, 0x03, 0xF0, 0x0D, ++0xD0, 0x34, 0x00, 0xD7, 0x00, 0x6C, 0x03, 0x30, 0x0D, 0xD0, 0x34, 0x00, 0xDB, ++0x00, 0x7C, 0x0E, 0xE0, 0x1D, 0xC0, 0xC0, 0x04, 0xCB, 0x01, 0x6C, 0x04, 0x10, ++0x19, 0xC0, 0x20, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x0D, ++0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0x40, 0x0F, 0x00, 0x3F, 0x00, 0xFC, ++0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC4, ++0x0F, 0x00, 0x3F, 0x00, 0xDC, 0x00, 0xF1, 0x03, 0xC8, 0x0F, 0x00, 0x37, 0x40, ++0x7C, 0x42, 0xF0, 0x07, 0xC2, 0x1F, 0x00, 0xFF, 0x00, 0xEC, 0xA4, 0xF0, 0x00, ++0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x75, 0x01, ++0xDF, 0x00, 0x7C, 0x03, 0x30, 0x0D, 0xD0, 0x74, 0x00, 0xD3, 0x00, 0x4D, 0x03, ++0xF0, 0x0D, 0xC8, 0x37, 0x40, 0xD3, 0x00, 0x7C, 0x07, 0x30, 0x8D, 0xC1, 0x37, ++0x14, 0xDF, 0x01, 0x4C, 0x23, 0xF0, 0x0D, 0xC0, 0x76, 0x04, 0xD3, 0x40, 0x6C, ++0x28, 0x30, 0x09, 0xC0, 0x37, 0x01, 0xD3, 0x00, 0x7C, 0xC8, 0x20, 0x29, 0xC6, ++0x28, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x04, 0x00, 0x1D, ++0x0F, 0x74, 0x10, 0x10, 0x11, 0x42, 0x04, 0x00, 0x11, 0x0A, 0x44, 0x00, 0xD0, ++0x01, 0x40, 0x07, 0x00, 0x11, 0x13, 0x74, 0x00, 0x10, 0x00, 0x40, 0xC7, 0x10, ++0x0D, 0x00, 0x34, 0x04, 0xD0, 0x31, 0x40, 0x83, 0x00, 0x11, 0xA5, 0x74, 0x08, ++0x10, 0x05, 0x40, 0x37, 0x00, 0xD1, 0x11, 0x74, 0x0E, 0xB0, 0x09, 0x40, 0x4C, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xB4, 0x00, 0xCD, 0x03, ++0x34, 0x43, 0x10, 0x6C, 0x40, 0x30, 0x00, 0xC1, 0x01, 0x04, 0x03, 0xD0, 0x0C, ++0x40, 0x73, 0x00, 0xC1, 0x00, 0x14, 0x03, 0x10, 0x2C, 0x44, 0x33, 0x00, 0xCD, ++0x00, 0x34, 0x07, 0xD0, 0x7D, 0x40, 0x33, 0x80, 0xC1, 0x81, 0x34, 0x0E, 0xD0, ++0x0C, 0x40, 0xB3, 0x00, 0xC1, 0x11, 0x64, 0x02, 0x10, 0x00, 0x40, 0x0C, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x48, 0x00, 0x2D, 0x01, 0xF4, ++0x04, 0x10, 0x13, 0x48, 0x4C, 0x00, 0x21, 0x01, 0x84, 0x04, 0xD0, 0x12, 0x40, ++0x4B, 0x04, 0x21, 0x03, 0xF4, 0x04, 0x10, 0x12, 0x40, 0x4B, 0x14, 0x2D, 0x01, ++0xB4, 0x04, 0xD0, 0x12, 0x40, 0x4F, 0x40, 0x21, 0x01, 0xB4, 0x05, 0xD0, 0x1E, ++0x40, 0x7F, 0x00, 0x61, 0x01, 0xB4, 0xA7, 0x90, 0x12, 0x40, 0x3C, 0x20, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x30, 0x92, 0xCF, 0x00, 0x3C, 0x03, ++0x30, 0x0C, 0xC1, 0x30, 0x00, 0xD3, 0x10, 0x0C, 0x23, 0xF0, 0x0C, 0xC0, 0x33, ++0x00, 0xC3, 0x00, 0x1C, 0x03, 0x30, 0x0C, 0xC0, 0x33, 0x00, 0xCF, 0x00, 0x1C, ++0x03, 0xF0, 0x0C, 0xC1, 0x33, 0x20, 0xC1, 0x00, 0x3E, 0x23, 0xF4, 0x0C, 0xC0, ++0x33, 0x80, 0xC3, 0x08, 0x7C, 0x63, 0x30, 0x80, 0xD0, 0x48, 0x40, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x0D, 0x00, 0x3F, 0x00, 0xBC, 0x00, 0xF0, ++0x02, 0xC0, 0x0B, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x83, 0xC0, 0x03, 0x00, ++0x1F, 0x40, 0xBC, 0x20, 0xF2, 0x03, 0xC0, 0x0F, 0x00, 0x1F, 0x00, 0x7C, 0x00, ++0xF0, 0x81, 0xC0, 0x07, 0x02, 0x1F, 0x41, 0xFC, 0xA3, 0x20, 0x8F, 0xC8, 0x3B, ++0x00, 0x7F, 0x00, 0xFC, 0x23, 0xF0, 0x07, 0xC0, 0x0B, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x1D, 0xC0, 0x34, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x1D, 0xD0, 0x74, 0x40, 0xD3, 0x00, 0x7C, 0x03, 0xF0, ++0x1D, 0xD0, 0x30, 0x00, 0xC3, 0x00, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x80, ++0xDF, 0x00, 0x7C, 0x00, 0x30, 0x09, 0xC0, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x32, 0x88, 0x09, 0x00, 0x2D, 0x00, 0xB4, 0x00, 0xD0, 0x02, 0x40, ++0x0B, 0x20, 0x2D, 0x00, 0xB4, 0x00, 0xD0, 0x02, 0x40, 0x08, 0x00, 0x2D, 0x00, ++0xB4, 0x00, 0xD0, 0x03, 0x40, 0x0C, 0x00, 0x21, 0x00, 0xB4, 0x00, 0xD0, 0x03, ++0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x83, 0xD0, 0x06, 0x40, 0x3B, 0x20, 0x6D, ++0x40, 0xF4, 0x01, 0x10, 0x02, 0x40, 0x4F, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x00, 0x79, 0x00, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x7B, ++0x00, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1F, 0x40, 0x7A, 0x00, 0xED, 0x01, 0xB4, ++0x87, 0xD0, 0x1E, 0x40, 0x7A, 0x00, 0xE1, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, ++0x78, 0x00, 0xF1, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x20, 0xED, 0x51, ++0xB4, 0x87, 0x10, 0x1E, 0x41, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x36, 0x28, 0x03, 0x00, 0x0D, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x40, 0x03, 0x00, ++0x0D, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x40, 0x02, 0x10, 0x1D, 0x20, 0x34, 0x00, ++0xD0, 0x00, 0x40, 0x02, 0x00, 0x01, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x40, 0x00, ++0x10, 0x01, 0x00, 0x14, 0x9B, 0xD0, 0x04, 0x42, 0x33, 0x00, 0x4D, 0x01, 0x34, ++0x03, 0x11, 0x2C, 0x41, 0x5B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, ++0xA0, 0x15, 0x00, 0x4F, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC4, 0x13, 0x00, 0x5F, ++0x00, 0x7C, 0x01, 0xF0, 0x05, 0xD0, 0x16, 0x00, 0x5F, 0x00, 0x74, 0x01, 0xF0, ++0x05, 0xC2, 0x16, 0x00, 0x51, 0x00, 0x3C, 0x01, 0xF0, 0x05, 0xC4, 0x14, 0x40, ++0x53, 0x00, 0xCC, 0x09, 0xD1, 0x87, 0x40, 0x1F, 0x00, 0x7D, 0x01, 0xBC, 0x05, ++0x14, 0x27, 0xC0, 0x5F, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, ++0x0D, 0x08, 0x3F, 0x00, 0xFC, 0x00, 0xF2, 0x03, 0xC4, 0x0F, 0x00, 0x3F, 0x00, ++0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0D, 0x20, 0x3F, 0x80, 0xFC, 0x00, 0xB0, 0x03, ++0xC0, 0x0D, 0x00, 0x3F, 0x80, 0xFC, 0x00, 0xF2, 0x03, 0xC4, 0x0F, 0x00, 0x3F, ++0x00, 0x65, 0x20, 0xF0, 0x81, 0xC0, 0x07, 0x02, 0x1F, 0x00, 0x7C, 0x38, 0xF0, ++0x01, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, ++0x02, 0x9F, 0x00, 0x6C, 0x0E, 0xF0, 0x19, 0xC0, 0x27, 0x00, 0x93, 0x05, 0x7C, ++0x02, 0x30, 0x09, 0xC0, 0x67, 0x02, 0x9F, 0x08, 0x6C, 0x82, 0xF0, 0x49, 0xC0, ++0x67, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x19, 0xC8, 0x27, 0x00, 0x93, 0x05, ++0x0C, 0x02, 0x32, 0x09, 0xC2, 0x27, 0x02, 0x9D, 0x04, 0x5C, 0x02, 0x34, 0x09, ++0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xE6, 0x00, ++0x9D, 0x02, 0x44, 0x0E, 0xD8, 0x29, 0x40, 0x27, 0x00, 0x9B, 0x43, 0x34, 0x02, ++0x10, 0x09, 0x40, 0x27, 0x08, 0x9F, 0x02, 0x44, 0x02, 0xE0, 0x29, 0x40, 0xA7, ++0x00, 0x9D, 0x00, 0x74, 0x02, 0xB0, 0x29, 0x40, 0x23, 0x10, 0x8B, 0x01, 0x44, ++0x16, 0x10, 0x09, 0x48, 0xA7, 0x04, 0x8D, 0x00, 0x6C, 0x4E, 0x10, 0x09, 0x48, ++0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0x24, 0x00, 0xBD, ++0x50, 0xE6, 0x02, 0xD0, 0x8B, 0x41, 0x6F, 0x08, 0xB5, 0x40, 0xF4, 0x02, 0x10, ++0x0B, 0x40, 0x2F, 0x00, 0xBD, 0x10, 0xC4, 0x06, 0xC0, 0x0B, 0x40, 0x2F, 0x01, ++0xBD, 0x08, 0xF4, 0x06, 0x10, 0x8B, 0x40, 0x2F, 0x00, 0xB1, 0x00, 0x45, 0x22, ++0x18, 0x09, 0x40, 0x27, 0x00, 0xDC, 0x00, 0x64, 0x06, 0x10, 0x09, 0x40, 0x73, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x68, 0x00, 0xAD, 0x00, ++0x86, 0x86, 0xD0, 0x0A, 0x40, 0x2B, 0x80, 0xA1, 0x01, 0xF4, 0x02, 0x10, 0x0A, ++0x40, 0x2B, 0x00, 0xA5, 0x00, 0x84, 0x02, 0x50, 0x1A, 0x40, 0x6B, 0x00, 0xAD, ++0x00, 0xB4, 0x02, 0x90, 0x1A, 0x40, 0x2B, 0x00, 0xB9, 0x00, 0x04, 0x12, 0x14, ++0x08, 0x40, 0x23, 0x00, 0xCD, 0x00, 0x64, 0x02, 0x10, 0x48, 0x40, 0x53, 0xA0, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x86, 0x02, 0x1F, 0x00, 0x6C, ++0x28, 0xD0, 0xA1, 0xC0, 0x07, 0x00, 0x15, 0x4A, 0x7C, 0x00, 0x34, 0x01, 0xC0, ++0x07, 0x00, 0x1D, 0x0A, 0x4D, 0x00, 0xD0, 0xA1, 0xC0, 0x87, 0x02, 0x1F, 0x00, ++0x7C, 0x00, 0x30, 0xA1, 0x40, 0x07, 0x00, 0x33, 0x00, 0x4C, 0x28, 0x30, 0xA1, ++0xC0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x28, 0x39, 0xA1, 0xC0, 0x77, 0xC0, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x82, ++0xF0, 0x09, 0xC0, 0x27, 0x48, 0x9F, 0x00, 0x7C, 0x02, 0xF1, 0x08, 0xC0, 0x27, ++0x08, 0x9F, 0x40, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF2, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0xFC, 0xA2, 0xF0, 0x0B, 0xC0, ++0x2F, 0x00, 0xBF, 0x20, 0xFC, 0x02, 0xF0, 0x8F, 0xC0, 0x67, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x2F, 0x00, 0xB3, 0x00, 0xFC, 0x02, 0x30, ++0x0B, 0xC2, 0x2C, 0x00, 0xBF, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x2F, 0x28, ++0xBF, 0x00, 0xDC, 0x02, 0x30, 0x0B, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0xDC, 0x02, ++0xF0, 0x0B, 0x80, 0x2F, 0x10, 0xBF, 0x00, 0xDC, 0x52, 0x30, 0x88, 0xC2, 0x29, ++0x00, 0xB3, 0x00, 0xDC, 0x02, 0xF0, 0x09, 0xC0, 0x67, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x01, 0x11, 0x00, 0x74, 0x40, 0x12, 0x01, ++0x49, 0x04, 0x00, 0x1D, 0x14, 0x74, 0x00, 0xD0, 0x01, 0x48, 0x07, 0x20, 0x17, ++0x10, 0x74, 0x00, 0x50, 0x41, 0x41, 0x07, 0x01, 0x1D, 0x80, 0x74, 0x00, 0xD0, ++0x01, 0x49, 0x07, 0x00, 0x1D, 0x00, 0x74, 0x10, 0x10, 0x41, 0x44, 0x07, 0x00, ++0x11, 0x00, 0x5C, 0x81, 0xD2, 0x41, 0x45, 0x73, 0x60, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x00, 0x21, 0x05, 0x81, 0x60, 0x14, 0x12, 0x14, 0x08, 0x40, ++0x20, 0x00, 0x8D, 0x04, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x33, 0x00, 0x8D, 0x00, ++0x14, 0x03, 0x10, 0x48, 0x40, 0x33, 0x85, 0xCD, 0x00, 0x14, 0x03, 0xD0, 0x08, ++0x40, 0x23, 0x00, 0x8D, 0x00, 0x14, 0x52, 0xD0, 0x48, 0x40, 0x21, 0x00, 0x89, ++0x00, 0x14, 0x02, 0xD9, 0x48, 0x40, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0x08, 0x25, 0x00, 0x91, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x50, 0x24, ++0x10, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x95, 0x00, 0x74, ++0x02, 0x51, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x0D, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x74, 0x06, 0xD0, 0x89, 0x40, 0xE7, 0x00, 0x99, 0x01, ++0x50, 0x12, 0xD0, 0x09, 0x60, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0x20, 0x25, 0x00, 0x93, 0x80, 0x5C, 0x02, 0x31, 0x09, 0xC2, 0x24, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xE0, 0x27, 0x00, 0x9F, 0x40, 0x5C, 0x02, ++0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x80, 0x5C, 0x12, 0xB4, 0x09, 0xC0, 0xE1, 0x40, 0x9B, 0x01, 0x58, ++0x06, 0xF0, 0x09, 0xC4, 0x17, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x08, 0x25, 0x40, 0x9F, 0x00, 0x7C, 0x02, 0xF3, 0x09, 0x40, 0x27, 0x10, 0x9F, ++0x00, 0x7C, 0x02, 0xF0, 0x09, 0x80, 0x27, 0x00, 0x96, 0x00, 0x70, 0x02, 0x70, ++0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC2, 0x27, 0x04, ++0x9F, 0xA0, 0x7C, 0x02, 0x20, 0x09, 0xC0, 0x27, 0x00, 0x96, 0x00, 0x5C, 0x42, ++0xF1, 0x49, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, ++0x05, 0x06, 0x1F, 0x01, 0x6C, 0x10, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x1F, 0x00, ++0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, ++0xC3, 0x04, 0x00, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x08, 0x13, ++0x00, 0x4C, 0x00, 0xB0, 0x01, 0xC0, 0x05, 0x08, 0x17, 0x00, 0x6C, 0x28, 0xF0, ++0x21, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x5C, ++0x00, 0x7D, 0x11, 0xC4, 0x0D, 0x72, 0x57, 0x40, 0x14, 0x04, 0x7F, 0x41, 0x44, ++0x01, 0xD0, 0x05, 0x40, 0x17, 0x00, 0x7D, 0x20, 0x34, 0x01, 0x72, 0x07, 0xC9, ++0x1E, 0x02, 0x51, 0x00, 0x74, 0x01, 0x70, 0xD7, 0x00, 0x9F, 0x04, 0x51, 0x01, ++0xC4, 0x15, 0x00, 0x05, 0x40, 0x1C, 0x00, 0x71, 0x05, 0xE4, 0x0D, 0xD0, 0x05, ++0x40, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0xF6, 0x00, ++0x4D, 0x21, 0x64, 0x2F, 0x50, 0x4D, 0x40, 0x20, 0x20, 0xCD, 0x04, 0x04, 0x03, ++0xD0, 0x0C, 0x40, 0x23, 0x00, 0xCD, 0x0D, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0xB0, ++0x00, 0x89, 0x00, 0x34, 0x02, 0x50, 0x2C, 0x40, 0xF3, 0x00, 0x81, 0x89, 0x44, ++0x13, 0x91, 0x0C, 0x40, 0x01, 0x00, 0x85, 0x01, 0x24, 0x0F, 0xD0, 0x0C, 0x42, ++0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x00, 0xED, ++0x01, 0x86, 0x01, 0x50, 0x0E, 0x50, 0x38, 0x00, 0xF5, 0x11, 0x84, 0x03, 0xD0, ++0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x1F, 0x40, 0x5A, 0x40, ++0xE9, 0x00, 0xB4, 0x03, 0x50, 0x0E, 0x40, 0x6B, 0x40, 0xE1, 0x01, 0xC6, 0x03, ++0x10, 0x5F, 0x40, 0x2C, 0x08, 0x61, 0x00, 0xA4, 0x03, 0xD2, 0x4E, 0x60, 0x07, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x78, 0x00, 0xEF, 0x01, ++0xAC, 0x07, 0x70, 0x1F, 0xC0, 0x78, 0x20, 0xED, 0x01, 0x85, 0x07, 0xF0, 0x1E, ++0xC6, 0x7B, 0x00, 0xED, 0x01, 0xBC, 0x07, 0xF0, 0x1F, 0xC0, 0x7C, 0x00, 0xEB, ++0x01, 0xBC, 0x07, 0x70, 0x1E, 0xC0, 0x7B, 0x00, 0xE3, 0x01, 0xCC, 0x05, 0xB0, ++0x9E, 0xC0, 0x79, 0x00, 0x65, 0x41, 0xAC, 0x04, 0xF0, 0x5E, 0xC0, 0x47, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0xCF, 0x00, 0x7C, ++0x01, 0x71, 0x0D, 0xC4, 0x37, 0x00, 0xCF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0x40, ++0x37, 0x00, 0xDF, 0x40, 0x7C, 0x03, 0x70, 0x0D, 0xC0, 0x17, 0x10, 0xD7, 0x80, ++0x7C, 0x83, 0x70, 0x0D, 0xC0, 0x23, 0x00, 0xCF, 0x00, 0x7C, 0x01, 0xF0, 0x8D, ++0xC0, 0x37, 0x00, 0x5F, 0x00, 0x7C, 0x00, 0xF0, 0x8D, 0xC0, 0x43, 0x60, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x5D, 0x00, 0xFF, 0x01, 0xCC, 0x13, ++0xF0, 0x5F, 0xC0, 0x7B, 0x62, 0x73, 0x41, 0xBC, 0x07, 0x30, 0x1F, 0xC0, 0x7F, ++0x00, 0xF3, 0x01, 0xFC, 0x27, 0xF0, 0x17, 0xC0, 0x78, 0x00, 0xFB, 0x09, 0xEC, ++0x27, 0x30, 0x1E, 0xC0, 0x78, 0x00, 0xF3, 0x00, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, ++0x4C, 0x00, 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x08, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x19, 0x16, 0xED, 0x00, 0x84, 0x01, 0xD0, ++0x06, 0x40, 0x3B, 0x06, 0x65, 0x00, 0xB4, 0x03, 0x10, 0x8E, 0x40, 0x3B, 0x02, ++0x61, 0x08, 0xB4, 0x03, 0xD2, 0x47, 0x40, 0x38, 0x00, 0xE1, 0x08, 0x84, 0x03, ++0x10, 0x0E, 0x40, 0x38, 0x04, 0xE5, 0x08, 0xB4, 0x29, 0xD0, 0x0F, 0x40, 0x29, ++0x02, 0x6D, 0x00, 0xB4, 0x22, 0xD0, 0x0E, 0xC0, 0x56, 0x60, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0xFD, 0x00, 0x84, 0x23, 0xD0, 0x4E, ++0x48, 0x3B, 0x12, 0x60, 0x00, 0xF4, 0x03, 0x10, 0x2E, 0x40, 0x3F, 0x00, 0xE1, ++0x00, 0xB4, 0x03, 0xC1, 0x06, 0x60, 0x9C, 0x00, 0xF1, 0x80, 0xC6, 0x03, 0x10, ++0x87, 0x40, 0xB8, 0x00, 0xE1, 0x08, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x38, 0x00, ++0x6D, 0x00, 0xB4, 0x02, 0xD0, 0x0E, 0x40, 0x60, 0x08, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x28, 0x01, 0x00, 0xCD, 0x12, 0x44, 0x2C, 0xD0, 0xA8, 0x40, ++0xB3, 0x04, 0x11, 0x03, 0x34, 0x0B, 0x10, 0x0C, 0x40, 0xB3, 0x04, 0x91, 0x03, ++0x34, 0x0B, 0x90, 0x20, 0x40, 0x00, 0x00, 0xC1, 0x02, 0x04, 0x0B, 0x10, 0x08, ++0x41, 0x30, 0x40, 0xC5, 0x01, 0x74, 0x40, 0xD0, 0x1C, 0x40, 0x31, 0x10, 0x4D, ++0x0A, 0x30, 0x02, 0xC1, 0x2D, 0x48, 0x1A, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0xA0, 0x61, 0x00, 0xCF, 0x00, 0x4C, 0x22, 0xF0, 0x21, 0xC0, 0xF7, ++0x00, 0x93, 0x11, 0x7C, 0x0B, 0x34, 0x5C, 0xC0, 0x33, 0x00, 0x13, 0x01, 0x7C, ++0x23, 0xF0, 0x79, 0xD0, 0x64, 0x01, 0xC3, 0x08, 0x4C, 0x23, 0x30, 0x51, 0xC0, ++0x34, 0x00, 0xD3, 0x00, 0x7C, 0x06, 0xF0, 0x5F, 0xC0, 0x10, 0x20, 0xCF, 0x23, ++0x7C, 0x08, 0xC0, 0xBF, 0x80, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0x08, 0x27, 0x20, 0xDF, 0x01, 0x7C, 0x02, 0xF1, 0x21, 0xC8, 0x37, 0x00, ++0x9F, 0x02, 0x7C, 0x23, 0xF1, 0x0D, 0xC0, 0x77, 0x00, 0x1F, 0x1A, 0x7C, 0x07, ++0xF0, 0x29, 0xC8, 0x87, 0x00, 0xDF, 0x01, 0x7C, 0x07, 0xF0, 0x21, 0xC0, 0x87, ++0x00, 0xDF, 0x08, 0x7C, 0x22, 0xF0, 0x0D, 0xC0, 0x37, 0x02, 0x5F, 0x04, 0x7C, ++0x3A, 0xF1, 0x8D, 0xC0, 0x27, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, ++0x08, 0x0F, 0x00, 0xF3, 0x00, 0xCC, 0x00, 0x30, 0x03, 0xC1, 0x7C, 0x08, 0x3F, ++0x90, 0xCC, 0x43, 0xF0, 0x0F, 0xC0, 0x3C, 0x00, 0x33, 0x00, 0xCC, 0x07, 0x30, ++0x03, 0xC1, 0x2F, 0x00, 0xFF, 0x00, 0xCC, 0x07, 0xF0, 0x03, 0xC0, 0x3F, 0x00, ++0xFF, 0x12, 0xFC, 0x00, 0x30, 0x0F, 0xC1, 0x7F, 0x01, 0x73, 0x01, 0xCC, 0x00, ++0xF1, 0x0D, 0xC0, 0x14, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, ++0xE6, 0x09, 0xD0, 0x01, 0x44, 0x04, 0x12, 0x30, 0x42, 0x34, 0x08, 0x9D, 0x03, ++0x4C, 0x03, 0xD0, 0x0D, 0x60, 0x34, 0x00, 0x11, 0x25, 0x04, 0x07, 0x12, 0x39, ++0x40, 0xC7, 0x00, 0xDD, 0x80, 0x6C, 0x03, 0xD0, 0x11, 0x40, 0x87, 0x00, 0xDD, ++0x01, 0x70, 0x0C, 0x10, 0x0D, 0x40, 0x37, 0x00, 0x51, 0x08, 0x7D, 0x4C, 0xD2, ++0x0D, 0x4C, 0x14, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x66, ++0x00, 0xD1, 0x01, 0x44, 0x06, 0x98, 0x19, 0x40, 0x36, 0x01, 0x9D, 0x11, 0x64, ++0x03, 0xD0, 0x0D, 0x40, 0x74, 0x00, 0x90, 0x01, 0x44, 0x23, 0x10, 0x19, 0x41, ++0x67, 0x04, 0xDD, 0x04, 0x54, 0xA3, 0xD1, 0x19, 0x40, 0x37, 0x04, 0xDD, 0x00, ++0x74, 0x06, 0x18, 0x0D, 0x40, 0x17, 0x00, 0xD1, 0x00, 0x44, 0x04, 0xD0, 0x0D, ++0x58, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x24, 0x00, ++0x91, 0x01, 0x04, 0x02, 0x94, 0x01, 0x50, 0x32, 0x00, 0x8D, 0x00, 0x04, 0x03, ++0xD0, 0x0D, 0x40, 0x34, 0x00, 0x01, 0x00, 0x45, 0x03, 0x10, 0x08, 0x40, 0x23, ++0x00, 0xCD, 0x00, 0x24, 0x03, 0xD0, 0x08, 0x48, 0x33, 0x00, 0xCD, 0x00, 0x34, ++0x02, 0x10, 0x0C, 0x40, 0x37, 0x00, 0x51, 0x00, 0x24, 0x02, 0x90, 0x0C, 0x40, ++0x40, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x00, 0xD3, ++0x00, 0x4C, 0x02, 0xB0, 0x09, 0xC4, 0x36, 0x00, 0x1F, 0x00, 0x6D, 0x03, 0xF0, ++0x0D, 0x40, 0x34, 0x00, 0x93, 0x00, 0x4C, 0x03, 0x30, 0x01, 0xC4, 0x27, 0x00, ++0xDF, 0x00, 0x5C, 0x03, 0xF1, 0x01, 0x40, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x02, ++0x34, 0x0F, 0xC0, 0x37, 0x00, 0x53, 0x00, 0x4C, 0x00, 0xF0, 0x0D, 0xC0, 0x04, ++0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x98, 0x2F, 0x00, 0xAF, 0x00, ++0xF4, 0x02, 0x70, 0x0B, 0xC4, 0x3D, 0x10, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, ++0x80, 0x3B, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0xEF, ++0x00, 0xB8, 0x03, 0xF0, 0x0B, 0xC8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, ++0x0F, 0xC0, 0x3F, 0x00, 0x7F, 0x00, 0xFC, 0x02, 0xF8, 0x0F, 0xC0, 0x17, 0x24, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x0B, 0x80, 0x33, 0x00, 0xFC, ++0x10, 0x30, 0x0F, 0xC0, 0x3C, 0x00, 0xF3, 0x00, 0xCC, 0x27, 0x30, 0x03, 0xC8, ++0x2C, 0x05, 0xB5, 0x00, 0xCC, 0x02, 0x30, 0x83, 0xC0, 0x2F, 0x03, 0x33, 0x01, ++0xCC, 0x01, 0xF0, 0x1B, 0xC0, 0x2F, 0x01, 0x3F, 0x01, 0xCC, 0x26, 0xB0, 0x0B, ++0xC0, 0x7C, 0x00, 0xBF, 0x14, 0xFC, 0x27, 0x30, 0x4F, 0xC1, 0x0C, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x10, 0x11, 0x0A, 0x74, 0x28, ++0x12, 0x4F, 0x40, 0x7C, 0x10, 0xD5, 0x01, 0x04, 0x02, 0x10, 0x01, 0x50, 0xE4, ++0x08, 0x91, 0x08, 0x54, 0x02, 0x10, 0x0B, 0x40, 0xAF, 0x00, 0x91, 0x00, 0x44, ++0x2C, 0xD0, 0x19, 0x40, 0xE7, 0x00, 0x1D, 0x01, 0x44, 0x02, 0x14, 0x08, 0x40, ++0x74, 0x00, 0x9D, 0x03, 0x74, 0x03, 0x10, 0x3D, 0x40, 0x04, 0x60, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x23, 0x00, 0x01, 0x20, 0x34, 0x00, 0x50, ++0x0C, 0x51, 0x30, 0x00, 0xC1, 0x00, 0x04, 0x02, 0x10, 0x00, 0x40, 0x20, 0x00, ++0x85, 0x00, 0x04, 0x02, 0x14, 0x48, 0x40, 0xB7, 0x20, 0x91, 0x14, 0x16, 0x81, ++0x90, 0x0C, 0x42, 0xB3, 0x00, 0x1D, 0x00, 0x64, 0x02, 0x10, 0x08, 0x40, 0x30, ++0x00, 0x09, 0x01, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x44, 0x80, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA8, 0x25, 0x00, 0x11, 0x01, 0x74, 0x44, 0x10, 0x8D, ++0x40, 0x34, 0x00, 0xD5, 0x00, 0x44, 0x02, 0x10, 0x01, 0x40, 0x24, 0x01, 0xD1, ++0x20, 0x54, 0x46, 0x10, 0x19, 0x40, 0x27, 0x00, 0x91, 0x01, 0x54, 0x40, 0xD0, ++0x15, 0x40, 0x77, 0x00, 0x1D, 0x11, 0x64, 0x12, 0x10, 0x09, 0x41, 0x74, 0x00, ++0xDD, 0x44, 0x74, 0x23, 0x10, 0x0D, 0x40, 0x1C, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x47, 0x42, 0x11, 0x81, 0x7C, 0x0C, 0x34, 0x1D, 0xC0, ++0x34, 0x00, 0xD3, 0x00, 0x49, 0x03, 0x30, 0x15, 0xD0, 0x24, 0x00, 0x97, 0x80, ++0x4C, 0x06, 0x30, 0x39, 0xC0, 0x63, 0x40, 0x83, 0x01, 0x5D, 0x01, 0xF0, 0x19, ++0xC0, 0x77, 0x00, 0x0F, 0x01, 0x2D, 0x07, 0xB0, 0x29, 0xD0, 0x34, 0x00, 0x9F, ++0x01, 0x7E, 0x06, 0x30, 0x0D, 0xC0, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0x88, 0x6D, 0x00, 0x3F, 0x00, 0xBC, 0x00, 0xE2, 0x1E, 0xE1, 0x3F, ++0x00, 0xFF, 0x00, 0xF8, 0x03, 0xF0, 0x4E, 0xE0, 0x6B, 0x00, 0x8F, 0x20, 0x7C, ++0x02, 0xF0, 0x0F, 0xC0, 0x67, 0x22, 0xBF, 0x10, 0xEC, 0x25, 0xF0, 0x0B, 0xC0, ++0x3F, 0x08, 0x3F, 0x00, 0xDC, 0x03, 0xF0, 0x47, 0xC0, 0x3F, 0x00, 0xBF, 0x81, ++0xFE, 0x06, 0xF4, 0x0C, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x08, 0x21, 0x00, 0x13, 0x80, 0x6C, 0x18, 0x32, 0x0D, 0xC0, 0x73, 0x00, ++0xD3, 0x00, 0x7C, 0x03, 0x30, 0x05, 0xC0, 0x24, 0x00, 0x93, 0x00, 0x4C, 0x3A, ++0x34, 0x2D, 0xC0, 0x3C, 0x00, 0x93, 0x00, 0x7C, 0x01, 0x30, 0x0D, 0xC0, 0x77, ++0x00, 0x1F, 0x02, 0x7C, 0x23, 0x30, 0x24, 0xD0, 0x34, 0x00, 0xDF, 0x00, 0x4C, ++0x02, 0xF0, 0x0D, 0xE0, 0x0A, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0xA0, 0x6C, 0x01, 0x91, 0x01, 0x44, 0x0C, 0x10, 0x1D, 0xE4, 0x3F, 0x00, 0xE1, ++0x00, 0x74, 0x07, 0x10, 0x0D, 0x48, 0x24, 0x00, 0xD1, 0x00, 0x6C, 0x0A, 0x12, ++0x0D, 0x48, 0x24, 0x30, 0x9B, 0x00, 0x70, 0x15, 0x11, 0x05, 0x40, 0x34, 0x00, ++0x1D, 0x00, 0x74, 0x07, 0x10, 0xA5, 0x40, 0x34, 0x00, 0xDD, 0x84, 0x44, 0x02, ++0xD0, 0x0F, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, ++0x40, 0x00, 0x01, 0x00, 0x24, 0x84, 0x10, 0x08, 0x40, 0x33, 0x40, 0xC1, 0x80, ++0x74, 0x07, 0x90, 0x20, 0x41, 0x20, 0x40, 0x81, 0x00, 0x44, 0x03, 0x91, 0x08, ++0x40, 0x21, 0x20, 0x81, 0x02, 0x30, 0x41, 0x16, 0x0C, 0x52, 0x33, 0x00, 0x4D, ++0x00, 0x34, 0x06, 0x10, 0x08, 0x40, 0x30, 0x00, 0x8D, 0x01, 0x44, 0x02, 0xD0, ++0x0C, 0x40, 0x0C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x6C, ++0x00, 0x01, 0x11, 0x84, 0x64, 0x10, 0x1E, 0x40, 0x79, 0x40, 0xE1, 0x61, 0xB4, ++0x4E, 0x90, 0x12, 0x50, 0x78, 0x00, 0xA1, 0x11, 0xA4, 0x26, 0x90, 0x0A, 0x40, ++0x69, 0x00, 0xE9, 0x01, 0xB4, 0x06, 0x10, 0x1F, 0x40, 0x5A, 0x00, 0x6D, 0x01, ++0xB4, 0x06, 0x10, 0x1A, 0x40, 0x78, 0x20, 0x8D, 0x01, 0x84, 0x06, 0xD0, 0x1E, ++0x40, 0x19, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0x20, 0x00, ++0x03, 0x20, 0x6E, 0x20, 0x34, 0x08, 0x41, 0x33, 0x00, 0xC3, 0x00, 0x3C, 0x02, ++0x90, 0x01, 0xC1, 0x20, 0x00, 0x83, 0x00, 0x0C, 0x23, 0xB4, 0x89, 0xC0, 0x31, ++0x09, 0x83, 0x00, 0x3C, 0x00, 0x30, 0x0C, 0xC0, 0x33, 0x00, 0x0F, 0x00, 0x7C, ++0x02, 0x34, 0x08, 0xC0, 0x30, 0x00, 0xCF, 0x08, 0x0D, 0x02, 0xF2, 0x0C, 0xD0, ++0x48, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x2D, 0x40, 0x3F, ++0x00, 0xF6, 0x20, 0xF5, 0x0F, 0xC0, 0x3B, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0x50, ++0x03, 0xC0, 0x3B, 0x02, 0xFF, 0x08, 0xFC, 0xA1, 0x70, 0xCB, 0xE0, 0xBE, 0x00, ++0xBF, 0x00, 0xBC, 0x02, 0xF0, 0x06, 0xC0, 0x3D, 0x00, 0x3F, 0x00, 0xFC, 0x02, ++0xF0, 0x8B, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x0A, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x07, 0x00, 0x13, 0x00, ++0xCC, 0x00, 0x30, 0x59, 0xC8, 0x30, 0x13, 0xF7, 0x00, 0x74, 0x03, 0x70, 0x01, ++0xC0, 0x24, 0x00, 0x9E, 0x00, 0x4C, 0x03, 0x30, 0x2D, 0xC1, 0xAC, 0x00, 0x93, ++0x00, 0x7C, 0x01, 0xC0, 0x1D, 0xC0, 0x34, 0x00, 0x5B, 0x00, 0x7C, 0x02, 0x30, ++0x05, 0xD0, 0x30, 0x00, 0x93, 0x00, 0x7C, 0x07, 0x30, 0x0D, 0xC0, 0x53, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0xA9, 0x00, 0x21, 0xC0, 0x84, ++0x02, 0x11, 0x0E, 0xC1, 0x38, 0x04, 0xE1, 0x01, 0xB4, 0x03, 0xD0, 0x0F, 0x40, ++0x38, 0x00, 0xAD, 0x00, 0xBC, 0x03, 0x10, 0x0E, 0x42, 0x20, 0x00, 0xE1, 0xC0, ++0xB4, 0x03, 0xC0, 0x0E, 0xC0, 0x38, 0x00, 0x6D, 0x00, 0xB4, 0x02, 0x50, 0x0C, ++0x40, 0x38, 0x00, 0xA5, 0x00, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x4B, 0x60, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x69, 0x01, 0x21, 0x01, 0x84, 0x07, ++0x10, 0x18, 0x00, 0x78, 0x01, 0xE5, 0x01, 0xB4, 0x47, 0xD1, 0x12, 0x50, 0x6A, ++0x00, 0x8D, 0x01, 0x04, 0x07, 0x10, 0x1C, 0x48, 0x78, 0x00, 0xA0, 0x01, 0xB4, ++0x05, 0xD0, 0x1F, 0x50, 0x78, 0x00, 0x2D, 0x01, 0xB4, 0x06, 0x18, 0x1E, 0x40, ++0x68, 0x00, 0xE9, 0x01, 0xF4, 0x07, 0x10, 0x1E, 0x40, 0x03, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xD1, 0x53, 0x04, 0x03, 0x10, ++0x0C, 0x50, 0x32, 0x00, 0xC1, 0x00, 0x34, 0x07, 0xD0, 0x0D, 0x40, 0x32, 0x00, ++0xCD, 0x40, 0x34, 0x2B, 0x10, 0x5C, 0x60, 0x30, 0x00, 0x81, 0x00, 0x34, 0x03, ++0xD0, 0x04, 0x40, 0xF2, 0x00, 0x8D, 0x00, 0x34, 0x26, 0x50, 0x7C, 0x42, 0x30, ++0x00, 0xCD, 0x00, 0x34, 0x07, 0x14, 0x0C, 0x40, 0x5B, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x17, 0xA0, 0x1D, 0x00, 0x73, 0x27, 0xCC, 0x0D, 0x34, 0x05, ++0xC8, 0x10, 0x00, 0x57, 0x20, 0x7C, 0x05, 0xF0, 0x27, 0xC1, 0x16, 0x00, 0x5F, ++0x00, 0xCC, 0x05, 0x34, 0x57, 0xD0, 0x14, 0x40, 0x73, 0x00, 0xFC, 0x01, 0xF0, ++0x07, 0xC0, 0x1C, 0x01, 0x6B, 0x00, 0x7C, 0x01, 0x30, 0x77, 0xD0, 0x14, 0x00, ++0x6B, 0x00, 0x7C, 0x01, 0x30, 0x05, 0xC0, 0x5F, 0x20, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x08, 0x05, 0x40, 0x1F, 0x00, 0x7D, 0x20, 0xF0, 0x01, 0xC0, ++0x05, 0x00, 0x1F, 0x02, 0x7C, 0x00, 0xF2, 0x01, 0xC5, 0x05, 0x00, 0x1F, 0x00, ++0x7C, 0x40, 0xF0, 0x00, 0xC0, 0x03, 0x40, 0x1F, 0x04, 0x7C, 0x20, 0xF0, 0x01, ++0xC0, 0x05, 0x30, 0x1F, 0x01, 0x7C, 0x00, 0xF4, 0x21, 0xC4, 0x07, 0x00, 0x17, ++0x01, 0x7C, 0x20, 0xF0, 0x01, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x25, 0x00, 0x97, 0x00, 0x4C, 0x4A, 0x30, 0x59, 0xC0, 0xE7, ++0x00, 0x8B, 0x01, 0x6C, 0x02, 0xF0, 0x19, 0x80, 0x24, 0x10, 0x8F, 0x89, 0x4C, ++0x02, 0x38, 0x09, 0xC0, 0x24, 0x00, 0x93, 0x05, 0x7C, 0x02, 0xF0, 0x09, 0xC0, ++0x23, 0x04, 0x93, 0x01, 0x6D, 0x02, 0x30, 0x59, 0x40, 0xA4, 0x00, 0x93, 0x00, ++0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x20, 0x24, 0x00, 0x91, 0x00, 0x44, 0x0A, 0x10, 0x19, 0x40, 0x27, 0x00, ++0x91, 0x03, 0x44, 0x02, 0xD0, 0x19, 0x40, 0x24, 0x00, 0x9D, 0x01, 0x6C, 0x02, ++0x10, 0x09, 0x40, 0x24, 0x00, 0x91, 0x03, 0x74, 0x06, 0xD0, 0x09, 0x40, 0x27, ++0x20, 0x9B, 0x00, 0x2C, 0x12, 0x50, 0x79, 0x50, 0x60, 0x00, 0x9B, 0x00, 0x44, ++0x02, 0xD2, 0x09, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA0, 0x20, 0x40, 0x95, 0x20, 0x04, 0x0A, 0x56, 0x29, 0x40, 0x27, 0x40, 0x99, ++0xA8, 0x64, 0x06, 0xD8, 0x89, 0x60, 0x25, 0xA0, 0x9D, 0x00, 0x04, 0x02, 0x14, ++0x0D, 0x40, 0x26, 0x00, 0xD1, 0x00, 0x74, 0x06, 0xD8, 0x09, 0x40, 0x77, 0x00, ++0x91, 0x08, 0x66, 0x92, 0x12, 0x08, 0x42, 0x25, 0xA0, 0x99, 0x00, 0x44, 0x02, ++0xD0, 0x09, 0x40, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x20, 0x01, 0x81, 0x04, 0x04, 0x12, 0x50, 0x48, 0x40, 0x23, 0x01, 0x81, 0x04, ++0x00, 0x06, 0xD0, 0x48, 0x50, 0x21, 0x01, 0x8D, 0x04, 0x25, 0x13, 0x10, 0x48, ++0x40, 0x22, 0x11, 0xC1, 0x00, 0x36, 0x12, 0xD0, 0x08, 0x42, 0x23, 0x21, 0x99, ++0x00, 0x64, 0x02, 0x50, 0x48, 0x40, 0x25, 0x00, 0x89, 0x04, 0x05, 0x02, 0xD0, ++0x48, 0x41, 0x53, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x83, ++0x02, 0x07, 0x0A, 0x0C, 0x28, 0x72, 0xA1, 0x40, 0x07, 0x00, 0x5B, 0x00, 0x6C, ++0x28, 0xF0, 0xA1, 0xC0, 0x05, 0x00, 0x1F, 0x0A, 0x4C, 0x28, 0x10, 0xA1, 0x50, ++0x86, 0x02, 0x13, 0x0A, 0x7C, 0x01, 0xD1, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x00, ++0x6D, 0x28, 0x30, 0xA1, 0xC0, 0x05, 0x00, 0x1B, 0x00, 0x4C, 0x08, 0xF0, 0x01, ++0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x3F, 0x02, ++0xBF, 0x08, 0xFD, 0x22, 0xB0, 0x8B, 0xC0, 0x27, 0x42, 0x9F, 0x08, 0xFC, 0x02, ++0xF0, 0x8B, 0xC8, 0x2E, 0x12, 0xBF, 0x48, 0xFC, 0x22, 0xF0, 0x8B, 0xC0, 0x2D, ++0x42, 0xBF, 0x00, 0xFC, 0x22, 0xF0, 0x0A, 0xC0, 0x2F, 0x02, 0xBF, 0x00, 0xBD, ++0x02, 0xF0, 0x8B, 0xC0, 0x2E, 0x00, 0xBF, 0x08, 0xBC, 0x42, 0xF0, 0x09, 0xC0, ++0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x3F, 0x05, 0xB3, ++0x0C, 0xCC, 0x02, 0x30, 0x0B, 0xC0, 0x2F, 0x00, 0xA3, 0x04, 0x8C, 0x02, 0xF0, ++0xCB, 0xC0, 0x2C, 0x00, 0xB3, 0x00, 0xCC, 0x22, 0xF0, 0x4B, 0xC0, 0x24, 0x05, ++0xAF, 0x08, 0xFC, 0x16, 0xF0, 0x09, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0xFC, 0x02, ++0xF0, 0xCA, 0xC0, 0x3C, 0x00, 0xF3, 0x00, 0x7C, 0x22, 0xF0, 0x19, 0xC0, 0x67, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x01, 0x51, 0x0C, ++0x4C, 0x48, 0x14, 0x01, 0xC1, 0x04, 0x02, 0x11, 0x60, 0x44, 0x10, 0x70, 0xC0, ++0x40, 0x05, 0x00, 0x11, 0x10, 0x44, 0x20, 0xD0, 0x05, 0x40, 0x04, 0x01, 0x1D, ++0x04, 0x74, 0x08, 0xC0, 0x01, 0x40, 0x07, 0x02, 0x1D, 0x00, 0x74, 0x10, 0xD2, ++0xC1, 0x40, 0x04, 0x00, 0x55, 0x00, 0x74, 0x04, 0xD0, 0x01, 0x40, 0x73, 0x60, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x05, 0x81, 0x04, 0x24, ++0x32, 0x10, 0x88, 0x40, 0x21, 0x00, 0x81, 0x08, 0x04, 0x52, 0xD2, 0x48, 0x40, ++0x20, 0x00, 0x81, 0x00, 0x04, 0x06, 0xD0, 0x88, 0x44, 0x20, 0x05, 0x8D, 0x04, ++0x34, 0x22, 0xD8, 0x18, 0x40, 0x63, 0x00, 0x8D, 0x20, 0x34, 0x52, 0xD0, 0x48, ++0x40, 0x20, 0x00, 0x81, 0x08, 0x34, 0x12, 0xD0, 0x28, 0x40, 0x4B, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x65, 0x58, 0x81, 0x00, 0x44, 0x02, ++0x10, 0x09, 0x40, 0x26, 0x00, 0x91, 0x00, 0x45, 0x12, 0x50, 0x08, 0x50, 0x25, ++0x00, 0x91, 0x04, 0x45, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x20, 0x9D, 0x24, 0x74, ++0x83, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x06, 0x74, 0x02, 0xD0, 0x49, 0x41, ++0x24, 0x00, 0x95, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x25, 0x00, 0x93, 0x82, 0x6D, 0x1A, 0x32, ++0x09, 0xC0, 0x25, 0x40, 0x93, 0x00, 0x4C, 0x06, 0xF2, 0x09, 0xC0, 0x24, 0x00, ++0x93, 0x00, 0x4C, 0x06, 0xF0, 0xB9, 0xC0, 0x24, 0x00, 0x9F, 0x06, 0x7C, 0x02, ++0xF0, 0x09, 0xC0, 0xE7, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xD0, 0x24, ++0x02, 0x93, 0x09, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x17, 0xA0, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x16, 0x08, 0x25, 0x00, 0x9F, 0x03, 0x7C, 0x26, 0xF0, 0x09, ++0xC1, 0x21, 0x00, 0x8F, 0x00, 0x7C, 0x46, 0x70, 0x09, 0x40, 0x26, 0x40, 0x9F, ++0x01, 0x7C, 0x0A, 0xF0, 0x18, 0xD0, 0x67, 0x01, 0x9F, 0x00, 0x7C, 0x12, 0xF0, ++0x39, 0xC0, 0x27, 0x01, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x19, 0xD0, 0x27, 0x80, ++0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x08, 0x85, 0x00, 0x13, 0x02, 0x4C, 0x00, 0xB0, 0x01, 0xC0, ++0x04, 0x40, 0x13, 0x04, 0x4C, 0x20, 0x30, 0x01, 0xC0, 0x04, 0x80, 0x1F, 0x00, ++0x4C, 0x00, 0x34, 0x01, 0xC0, 0x04, 0x00, 0x13, 0x82, 0x4C, 0x84, 0xB0, 0x01, ++0xC0, 0x07, 0x00, 0x1F, 0x02, 0x7C, 0x40, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x1F, ++0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x00, 0x14, 0x48, 0x51, 0x00, 0xD4, 0x01, 0x34, 0x07, 0x40, 0x14, ++0x00, 0x71, 0x00, 0xC4, 0x01, 0x10, 0x07, 0x50, 0x10, 0x00, 0x5D, 0x10, 0xFC, ++0x11, 0x12, 0x05, 0x40, 0x14, 0x00, 0x71, 0x02, 0xC0, 0x05, 0x30, 0x05, 0x40, ++0x57, 0x04, 0x5D, 0x01, 0xF4, 0x41, 0xD0, 0x07, 0x40, 0x10, 0x00, 0x5D, 0x01, ++0x74, 0x01, 0x10, 0x05, 0x40, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xA0, 0x36, 0x00, 0xC1, 0x00, 0x44, 0x03, 0x10, 0x2D, 0x40, 0x30, 0x00, ++0x81, 0x00, 0x04, 0x0F, 0xD4, 0x1C, 0x40, 0x30, 0x00, 0xDD, 0x00, 0x04, 0x07, ++0x10, 0x1C, 0x40, 0x30, 0x20, 0xC1, 0x12, 0x00, 0x03, 0x0C, 0x0C, 0x40, 0x23, ++0x00, 0xCD, 0x01, 0x34, 0x01, 0x90, 0x09, 0x40, 0x20, 0x00, 0x8D, 0x00, 0x34, ++0x03, 0x10, 0x0C, 0x40, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x80, 0x30, 0x08, 0xC1, 0x00, 0x94, 0x03, 0x10, 0x02, 0x40, 0x38, 0x00, 0xA1, ++0x02, 0xC4, 0x07, 0xD0, 0x0E, 0x41, 0x38, 0x04, 0xCD, 0x00, 0xB4, 0x05, 0x10, ++0x2C, 0x40, 0x7A, 0x00, 0xF1, 0x01, 0x84, 0x0F, 0x10, 0x0E, 0x40, 0x3B, 0x00, ++0xED, 0x10, 0xB4, 0x01, 0xD0, 0x03, 0x40, 0x28, 0x00, 0xAD, 0x02, 0xB4, 0x07, ++0x10, 0x0E, 0x40, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, ++0x78, 0x40, 0xE3, 0x01, 0xCC, 0x04, 0x33, 0x12, 0x50, 0x60, 0x20, 0x23, 0x01, ++0x8D, 0x07, 0xF0, 0x1A, 0xC2, 0x78, 0x00, 0xED, 0x01, 0xC8, 0x85, 0x30, 0x1E, ++0xD0, 0x7C, 0x41, 0xE3, 0x01, 0x8D, 0x06, 0x30, 0x1E, 0xC0, 0x7B, 0x00, 0xEF, ++0x01, 0xBC, 0x07, 0xF0, 0x1E, 0xD0, 0x78, 0x00, 0xAD, 0x01, 0xFC, 0x07, 0x34, ++0x1E, 0xC0, 0x47, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0xB5, ++0x05, 0xDF, 0x02, 0x7C, 0x02, 0x70, 0x00, 0xC0, 0x37, 0x00, 0x1C, 0x00, 0x7C, ++0x03, 0x30, 0x29, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x81, 0xF0, 0x0D, 0xC0, ++0x35, 0x02, 0xDF, 0x00, 0x3D, 0x00, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x7D, 0x00, ++0xF3, 0x03, 0xCC, 0x13, 0x30, 0x17, 0xC0, 0x7C, 0x10, 0xF3, 0x01, 0xFC, 0x07, ++0xF0, 0x3F, 0xC0, 0x78, 0x00, 0xF3, 0x01, 0xCC, 0x06, 0x30, 0x1A, 0xC0, 0x7D, ++0x00, 0xFF, 0x01, 0xCC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, ++0x27, 0xF0, 0x1B, 0xD0, 0x6C, 0x00, 0xBF, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, ++0x0B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x39, 0x40, 0xF1, ++0x00, 0x86, 0x03, 0x10, 0x02, 0x40, 0x38, 0x02, 0xE1, 0x04, 0xB4, 0x00, 0xD0, ++0x8E, 0x40, 0x38, 0x00, 0xB1, 0x00, 0x84, 0x01, 0x10, 0x8A, 0x43, 0x38, 0x08, ++0xED, 0x02, 0x84, 0x02, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x23, ++0xD0, 0x82, 0x40, 0x28, 0x00, 0xED, 0x08, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x57, ++0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x02, 0xE1, 0x00, ++0x84, 0x20, 0x10, 0x00, 0x41, 0x20, 0x00, 0xA9, 0x40, 0xB4, 0x03, 0xD0, 0x08, ++0x40, 0x38, 0x06, 0xA1, 0x00, 0x84, 0x60, 0x10, 0x0B, 0x40, 0x38, 0x04, 0xED, ++0x00, 0x04, 0x00, 0x50, 0x2E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x23, 0xD8, ++0x0E, 0x40, 0x3A, 0x00, 0xA9, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x23, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x35, 0x00, 0xC1, 0x0A, 0x44, ++0x42, 0x10, 0x00, 0x48, 0x30, 0x00, 0x89, 0x00, 0x34, 0x07, 0xD0, 0xB9, 0x40, ++0x70, 0x48, 0x91, 0x01, 0x04, 0x01, 0x10, 0x28, 0x40, 0x30, 0x00, 0xDD, 0x10, ++0x04, 0x24, 0x10, 0x0C, 0x40, 0x33, 0x90, 0xCD, 0x02, 0x34, 0x02, 0xD0, 0x2D, ++0x40, 0x32, 0x00, 0xCD, 0x03, 0x34, 0x83, 0xD2, 0x0C, 0x40, 0x5B, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x25, 0x00, 0xD3, 0x03, 0x4D, 0x0B, ++0x30, 0x10, 0xC0, 0x34, 0x50, 0x9B, 0x00, 0x7C, 0x47, 0xF0, 0x2D, 0xD0, 0x60, ++0x00, 0xD3, 0x05, 0x4D, 0x0E, 0x34, 0x19, 0xD0, 0x7C, 0x00, 0xDF, 0x01, 0x4D, ++0x22, 0x70, 0x0D, 0xC0, 0xB7, 0x02, 0xCF, 0x0A, 0x7C, 0x01, 0xF0, 0xF5, 0xD0, ++0x66, 0x00, 0x9F, 0x09, 0xFC, 0x03, 0xF0, 0x0D, 0xC0, 0x57, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x77, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, ++0x21, 0xC0, 0x37, 0x00, 0x97, 0x00, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x27, 0x00, ++0xDF, 0x00, 0x7C, 0x40, 0xF1, 0x08, 0xC1, 0x37, 0x00, 0xDF, 0x01, 0x7C, 0x02, ++0x70, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC0, 0x25, ++0x02, 0x9F, 0x08, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x08, 0x2F, 0x40, 0xF3, 0x10, 0xDC, 0x04, 0x30, 0x03, ++0xC0, 0xF8, 0x00, 0x33, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC1, 0xAC, 0x40, 0xF3, ++0x00, 0x4C, 0x04, 0xF0, 0x0B, 0xE0, 0x3C, 0x00, 0xBF, 0x00, 0xCC, 0x00, 0xD0, ++0x0F, 0xC0, 0x7F, 0x01, 0xB7, 0x01, 0xCC, 0x03, 0xF0, 0x3F, 0xC0, 0xEC, 0x00, ++0xBF, 0x03, 0xCC, 0x03, 0xF0, 0x0F, 0x40, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0x91, 0x01, 0x74, 0x02, 0x10, 0x71, 0x40, ++0x74, 0x00, 0x11, 0x40, 0x74, 0x03, 0xD0, 0x31, 0x41, 0x24, 0x50, 0xD1, 0x08, ++0x44, 0x00, 0xD0, 0x99, 0x40, 0x34, 0x00, 0x9C, 0x03, 0x44, 0x0C, 0xD0, 0x0D, ++0x48, 0x37, 0x00, 0x9D, 0x09, 0x44, 0x07, 0xD0, 0x1D, 0x40, 0x24, 0x00, 0x8D, ++0x00, 0x45, 0x03, 0xD0, 0x0D, 0x40, 0x17, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0xA0, 0x66, 0x00, 0xD1, 0x08, 0x74, 0x23, 0x90, 0x11, 0x40, 0x34, ++0x80, 0xD1, 0x00, 0x74, 0x03, 0xD0, 0x1D, 0x40, 0x34, 0x00, 0x91, 0x00, 0x44, ++0x12, 0xD0, 0x09, 0x40, 0x36, 0x00, 0x5D, 0x01, 0x44, 0x06, 0xD1, 0x0D, 0x40, ++0x37, 0x00, 0xDD, 0x00, 0x74, 0x07, 0xD0, 0x05, 0x41, 0x24, 0x00, 0xDD, 0x00, ++0x44, 0x03, 0xD0, 0x0D, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x00, 0x30, 0x00, 0x81, 0x00, 0x34, 0x02, 0x90, 0x00, 0x42, 0x30, 0xC0, ++0xC1, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x50, 0x30, 0x00, 0x81, 0x00, 0x04, 0x00, ++0xD0, 0x08, 0x48, 0x30, 0x00, 0xCD, 0x00, 0x04, 0x02, 0xD8, 0x0C, 0x42, 0x33, ++0x00, 0xCD, 0x80, 0x35, 0x03, 0xD0, 0x0C, 0x70, 0x20, 0x00, 0xDD, 0x00, 0x04, ++0x03, 0xD0, 0x0C, 0x40, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0x2E, 0x00, 0xF3, 0x00, 0x1C, 0x00, 0xB0, 0x01, 0xD0, 0x34, 0x00, 0x93, ++0x00, 0x7C, 0x03, 0xF2, 0x0B, 0xC0, 0x34, 0x00, 0x93, 0x80, 0x4C, 0x80, 0xF0, ++0x09, 0xD0, 0x34, 0x00, 0x9F, 0x00, 0x4D, 0x00, 0xF0, 0x0D, 0xC0, 0x37, 0x20, ++0xD7, 0x00, 0x7C, 0x03, 0xF0, 0x0C, 0xD0, 0x24, 0x00, 0xDF, 0x00, 0x4C, 0x03, ++0xF0, 0x0D, 0xC0, 0x07, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, ++0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0x70, 0x03, 0xC0, 0x3F, 0x00, 0xBF, 0x00, ++0xFC, 0x03, 0xF0, 0x03, 0xC0, 0x3F, 0x00, 0xBF, 0x40, 0xFC, 0x00, 0xF0, 0x0B, ++0xC0, 0x3F, 0x00, 0xAF, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x3F, 0x20, 0xFF, ++0x00, 0xCC, 0x03, 0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC8, 0x17, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x2F, ++0x00, 0xBF, 0x0C, 0xCC, 0x12, 0xF0, 0x1F, 0xC0, 0xBE, 0x09, 0xBF, 0xC0, 0x9D, ++0x40, 0xB0, 0x8F, 0xC0, 0x2F, 0x01, 0xB3, 0x10, 0xDC, 0xE2, 0x30, 0x1F, 0xC0, ++0x3F, 0x01, 0xF3, 0x02, 0xCC, 0x02, 0x33, 0x16, 0xC4, 0x3C, 0x00, 0xEF, 0x01, ++0xCC, 0x33, 0x30, 0x1F, 0xC0, 0x5A, 0x00, 0xFB, 0x01, 0xAC, 0x27, 0xB0, 0x0B, ++0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x07, 0x00, ++0x1D, 0x0E, 0x44, 0x12, 0xD0, 0x4D, 0x40, 0x3C, 0x03, 0x1D, 0x03, 0x44, 0x0F, ++0x10, 0x2F, 0x40, 0x27, 0x05, 0xD1, 0x06, 0x44, 0x12, 0x10, 0x1D, 0x48, 0xBF, ++0x00, 0xF1, 0x06, 0x44, 0x2C, 0x10, 0x05, 0x41, 0xBC, 0x02, 0xDD, 0x01, 0xD4, ++0x0B, 0x10, 0x1D, 0x40, 0x74, 0x00, 0xD1, 0x01, 0x44, 0x03, 0x10, 0x01, 0x40, ++0x0F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0xA3, 0x05, 0x8D, ++0x01, 0x06, 0x62, 0xD0, 0x09, 0x41, 0x30, 0x20, 0x8D, 0x08, 0x15, 0x03, 0x92, ++0xCC, 0x40, 0x43, 0x03, 0xC5, 0x10, 0x34, 0x10, 0x12, 0x0C, 0x42, 0xB2, 0x25, ++0xC1, 0x8C, 0x04, 0x04, 0x50, 0x01, 0x50, 0x30, 0x0C, 0x5D, 0x00, 0x24, 0x33, ++0x10, 0x0C, 0x40, 0x06, 0x00, 0xD9, 0xA0, 0x64, 0x12, 0x90, 0x08, 0x40, 0x4F, ++0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x65, 0x00, 0x1D, 0x01, ++0x44, 0x06, 0xD0, 0x19, 0x50, 0x34, 0x00, 0x9D, 0x03, 0x55, 0x0F, 0x10, 0x0D, ++0x42, 0x67, 0x00, 0xD5, 0x00, 0x64, 0x0C, 0x10, 0x0D, 0x40, 0x37, 0x00, 0xD1, ++0x00, 0x44, 0x04, 0x40, 0x05, 0x40, 0x34, 0x00, 0xDD, 0x80, 0x74, 0x03, 0x10, ++0x0D, 0x40, 0x74, 0x00, 0x59, 0x01, 0x44, 0x03, 0x18, 0x11, 0x41, 0x0F, 0xA0, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x67, 0x04, 0x1F, 0x01, 0x4C, ++0x14, 0xF0, 0x5C, 0xC0, 0x34, 0x00, 0x9F, 0x01, 0x5D, 0x0F, 0xB0, 0x0D, 0xC0, ++0x47, 0x00, 0xD7, 0x00, 0x7C, 0x06, 0x30, 0x0D, 0xE0, 0x37, 0x00, 0xD1, 0x20, ++0x4C, 0x06, 0x60, 0x04, 0xC0, 0x34, 0x00, 0x9F, 0x01, 0x6E, 0x03, 0x30, 0x0C, ++0xC0, 0x76, 0x00, 0xDB, 0x05, 0x2C, 0x03, 0xB0, 0x19, 0x44, 0x23, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x05, 0x00, 0x1F, 0x10, 0xFC, 0x02, ++0xF0, 0x0F, 0xC0, 0x3F, 0x04, 0x3F, 0x40, 0xAC, 0x03, 0xF2, 0x0F, 0xC0, 0x07, ++0x0C, 0xEB, 0x05, 0x1C, 0x02, 0xF0, 0x0F, 0xC8, 0x3F, 0x00, 0xFF, 0x00, 0x3C, ++0x00, 0xB2, 0x0F, 0xC0, 0x3F, 0x00, 0xBF, 0x89, 0x9C, 0x03, 0xF0, 0x5F, 0xC8, ++0x3F, 0x40, 0xF7, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x1F, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0xA5, 0x80, 0x93, 0x00, 0x4C, 0x00, 0xF0, ++0x09, 0xC0, 0x37, 0x00, 0x93, 0x80, 0x6C, 0x0B, 0x3C, 0x0D, 0xC0, 0x04, 0x00, ++0xD3, 0x00, 0x7C, 0x02, 0x30, 0x0D, 0xC0, 0x32, 0x00, 0xDB, 0x00, 0x4C, 0x02, ++0x31, 0x0D, 0xE0, 0x34, 0x10, 0x93, 0x02, 0x4C, 0x03, 0x34, 0x4D, 0xC0, 0x74, ++0x00, 0x93, 0x00, 0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0xA0, 0x24, 0x10, 0x9B, 0x06, 0x44, 0x02, 0xD0, 0x09, ++0x40, 0x3F, 0x00, 0x81, 0x0B, 0x68, 0x07, 0xB0, 0x1F, 0xC0, 0xE4, 0x00, 0xD0, ++0x00, 0x74, 0x02, 0x10, 0x0D, 0x48, 0x3F, 0x00, 0xFB, 0x10, 0x44, 0x02, 0x00, ++0x0D, 0xC0, 0x3F, 0x00, 0x81, 0x81, 0xC4, 0x2B, 0x10, 0x2D, 0x40, 0x70, 0x00, ++0x05, 0x05, 0x6C, 0x2F, 0x10, 0x49, 0xC0, 0x6E, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x07, 0xA0, 0x02, 0x00, 0x91, 0x02, 0x24, 0x00, 0xD0, 0x08, 0x64, ++0xF3, 0x00, 0x01, 0x03, 0x20, 0x07, 0x10, 0x5C, 0x48, 0xE4, 0x00, 0xC5, 0x00, ++0x34, 0x00, 0x11, 0x0C, 0x40, 0x31, 0x02, 0xD5, 0x01, 0x04, 0x02, 0x50, 0x14, ++0x40, 0x70, 0x01, 0xC1, 0x00, 0x24, 0x23, 0x90, 0x2C, 0x40, 0x10, 0x00, 0xC1, ++0x01, 0x04, 0x07, 0x50, 0x60, 0x44, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x80, 0x58, 0x00, 0xE9, 0x01, 0xA4, 0x05, 0xD0, 0x1A, 0x60, 0x7B, ++0x04, 0x61, 0x01, 0xE4, 0x07, 0x94, 0x1E, 0x40, 0x78, 0x00, 0xE5, 0x01, 0xB4, ++0x07, 0x10, 0x1E, 0x00, 0xFB, 0x00, 0xED, 0x03, 0x84, 0x07, 0x58, 0x37, 0x41, ++0x79, 0x04, 0xF1, 0x00, 0xA0, 0x07, 0x91, 0x0E, 0x40, 0x78, 0x00, 0xF5, 0x01, ++0xE4, 0x27, 0x18, 0x12, 0x48, 0x3E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x10, 0x10, 0x00, 0xC1, 0x00, 0x24, 0x03, 0xF0, 0x08, 0xC0, 0x37, 0x00, ++0x43, 0x14, 0x2C, 0x43, 0x10, 0x8D, 0xC1, 0x10, 0x04, 0xC7, 0x00, 0x34, 0x21, ++0x30, 0x0C, 0xC0, 0x37, 0x00, 0xD7, 0x88, 0x0C, 0x01, 0x70, 0x00, 0x40, 0x34, ++0x00, 0xC3, 0x18, 0x64, 0x13, 0xB0, 0x8C, 0x40, 0x10, 0x00, 0xC3, 0x00, 0x0C, ++0x42, 0x70, 0x09, 0xC0, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x98, 0x3D, 0x20, 0xF7, 0x00, 0xDC, 0x03, 0xF0, 0x0B, 0xC0, 0x3F, 0x40, 0xEF, ++0x00, 0xFC, 0x23, 0xF5, 0x0F, 0xC4, 0x35, 0x00, 0xFB, 0x00, 0xFC, 0x03, 0xF0, ++0x0F, 0xC0, 0xBF, 0x02, 0xF3, 0x00, 0xFC, 0x01, 0xB0, 0x07, 0xC0, 0x3F, 0x00, ++0xFF, 0x0C, 0xDC, 0x03, 0x70, 0x4E, 0xC0, 0x3F, 0x00, 0xEF, 0x00, 0xFE, 0x83, ++0x70, 0x07, 0xC8, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, ++0x37, 0x80, 0x5B, 0x00, 0x5C, 0x01, 0x34, 0x09, 0xC0, 0xB7, 0x04, 0xCF, 0x80, ++0x5C, 0x03, 0xF8, 0x4D, 0xC9, 0x37, 0x00, 0xDF, 0x01, 0x4C, 0x01, 0xF0, 0x0D, ++0xC0, 0x37, 0x03, 0xDF, 0x02, 0x7E, 0x03, 0xF0, 0x05, 0xC0, 0xB6, 0x02, 0xDF, ++0x00, 0x5C, 0x5B, 0xF0, 0x1D, 0xC0, 0x36, 0x00, 0xCF, 0x20, 0x4C, 0x03, 0x22, ++0x01, 0xC4, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x1D, ++0x08, 0x63, 0x00, 0xB4, 0x01, 0x10, 0x0A, 0x40, 0xBB, 0x11, 0x6D, 0x00, 0x94, ++0x03, 0x30, 0x6E, 0x48, 0x3B, 0x00, 0xED, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, ++0x3B, 0x01, 0xED, 0x48, 0xB4, 0x03, 0xD0, 0x0F, 0x40, 0x38, 0x04, 0xAD, 0x00, ++0xB4, 0x0B, 0xD0, 0x0E, 0x40, 0x38, 0x00, 0xED, 0x80, 0xD4, 0x83, 0x10, 0x06, ++0xC0, 0x4E, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x00, ++0xE1, 0x01, 0xB4, 0x47, 0x10, 0x1A, 0x40, 0x7B, 0x00, 0xED, 0x11, 0xD4, 0x47, ++0x50, 0x1E, 0x48, 0x5B, 0x00, 0xED, 0x01, 0xA5, 0x05, 0xD0, 0x1E, 0x40, 0x7B, ++0x00, 0xED, 0x09, 0xB4, 0x07, 0xD2, 0x1E, 0x55, 0x78, 0x00, 0xAD, 0x01, 0xB4, ++0x07, 0xD0, 0x1B, 0x40, 0x7A, 0x00, 0xF5, 0x01, 0x84, 0x06, 0x14, 0x18, 0x40, ++0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x10, 0xC1, ++0x0D, 0x34, 0x07, 0x90, 0x00, 0x40, 0x33, 0x00, 0xCD, 0x03, 0x14, 0x0B, 0x90, ++0x0C, 0x40, 0xF3, 0x04, 0xCD, 0x08, 0x04, 0x07, 0xD0, 0x0C, 0x40, 0x37, 0x20, ++0xCD, 0x00, 0x34, 0x27, 0xD0, 0x4C, 0x40, 0x30, 0x00, 0x8D, 0x04, 0x34, 0x03, ++0xD0, 0x18, 0x40, 0x70, 0x08, 0xCD, 0x01, 0x14, 0x03, 0x10, 0xAD, 0x43, 0x5A, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x1D, 0x04, 0x73, 0x02, ++0xFC, 0x01, 0x30, 0x27, 0xC0, 0x17, 0x10, 0x7F, 0x02, 0xDD, 0xA9, 0x74, 0x05, ++0xC0, 0x9F, 0x00, 0x5F, 0x00, 0xEC, 0x15, 0xF0, 0x05, 0x40, 0x17, 0x80, 0x5F, ++0x00, 0xFC, 0x09, 0xF0, 0x36, 0xC0, 0x14, 0x00, 0x7F, 0x02, 0x7C, 0x01, 0xF9, ++0x15, 0xC2, 0x1E, 0x04, 0x67, 0x81, 0x44, 0x01, 0x10, 0x27, 0xC0, 0x5C, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x47, 0x40, 0x1F, 0x00, 0x7C, ++0x40, 0x70, 0x41, 0xC0, 0x83, 0x00, 0x1F, 0x12, 0x7C, 0x00, 0x74, 0x01, 0xC0, ++0x07, 0x02, 0x1F, 0x00, 0x5C, 0x04, 0xF0, 0x01, 0xC2, 0x87, 0x00, 0x1F, 0x00, ++0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x05, 0x00, 0x1F, 0x0A, 0x7C, 0x00, 0xF0, 0x81, ++0xC0, 0x07, 0x10, 0x1F, 0x08, 0x7C, 0x00, 0xF0, 0x21, 0xC0, 0x4B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x80, 0x93, 0x05, 0x3C, 0x02, ++0x30, 0x09, 0xC0, 0x67, 0x02, 0x83, 0x00, 0x4C, 0x02, 0xB0, 0x28, 0xC0, 0x64, ++0x01, 0x9E, 0x00, 0x78, 0x02, 0x30, 0x09, 0xC0, 0xA7, 0x40, 0x9B, 0x01, 0x7C, ++0x42, 0xF0, 0x59, 0xC0, 0x20, 0x01, 0x93, 0x42, 0x7C, 0x82, 0xF0, 0x39, 0xC0, ++0x27, 0x04, 0x97, 0x08, 0x6C, 0x16, 0x30, 0x89, 0xC0, 0x40, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00, 0x91, 0x01, 0x74, 0x02, 0x10, ++0x09, 0xC0, 0xA7, 0x04, 0x91, 0x86, 0x0C, 0x02, 0xB0, 0x09, 0x40, 0x64, 0x00, ++0x9D, 0x00, 0x7C, 0x02, 0x10, 0x09, 0x40, 0xE7, 0x00, 0x91, 0x01, 0x74, 0x02, ++0xD0, 0x49, 0xC0, 0xE6, 0x04, 0x91, 0x20, 0x74, 0x0E, 0xD0, 0x29, 0x40, 0x23, ++0x40, 0x9B, 0x41, 0x44, 0x46, 0x14, 0x39, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0xA0, 0x20, 0x00, 0x91, 0x00, 0x74, 0x02, 0x10, 0x09, ++0x60, 0x27, 0x00, 0x91, 0x00, 0x65, 0x22, 0x94, 0x09, 0x58, 0x26, 0x00, 0x9D, ++0x00, 0x36, 0x02, 0x10, 0x09, 0x40, 0x27, 0x00, 0x91, 0x08, 0x74, 0x02, 0xD0, ++0x09, 0x60, 0x24, 0x00, 0xD1, 0x00, 0x74, 0x22, 0xD0, 0x09, 0x40, 0x67, 0x00, ++0x95, 0x00, 0x04, 0x02, 0x12, 0x29, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x20, 0x81, 0x81, 0x05, 0x34, 0x12, 0x10, 0x08, 0x40, ++0x21, 0x09, 0x81, 0x04, 0x44, 0x12, 0x90, 0x58, 0x40, 0x62, 0x01, 0x8D, 0x04, ++0x14, 0x12, 0x10, 0x08, 0x40, 0x23, 0x01, 0xC1, 0x04, 0x34, 0x12, 0xD0, 0x09, ++0x68, 0x22, 0x01, 0xC1, 0x00, 0x36, 0x12, 0xD0, 0x0C, 0x40, 0x23, 0x08, 0x99, ++0x00, 0x05, 0x22, 0x10, 0x48, 0x50, 0x40, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1D, 0xB0, 0x86, 0x02, 0x11, 0x0A, 0x3C, 0x28, 0x30, 0xA1, 0x40, 0x87, ++0x02, 0x13, 0x40, 0x6C, 0x00, 0xB4, 0xA1, 0xC8, 0x86, 0x02, 0x0F, 0x0A, 0x74, ++0x28, 0x34, 0x01, 0x84, 0x97, 0x02, 0x1B, 0x0A, 0x7C, 0x00, 0xD0, 0xA1, 0xC0, ++0x84, 0x42, 0x13, 0x40, 0x7C, 0x29, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x17, 0x00, ++0x4C, 0x08, 0x30, 0xA1, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x19, 0x98, 0x2F, 0x4A, 0xBF, 0x08, 0xFC, 0x22, 0xD4, 0x0B, 0xC0, 0x27, 0x62, ++0xBF, 0x88, 0xBC, 0x22, 0xF4, 0x89, 0xC0, 0x2D, 0x02, 0xBF, 0x08, 0xFC, 0x22, ++0xF0, 0x09, 0xC4, 0x27, 0x02, 0x9F, 0x08, 0xFC, 0x22, 0xF0, 0x0B, 0xC0, 0x27, ++0x02, 0xBF, 0x40, 0x7C, 0x22, 0xD0, 0x0A, 0xC0, 0x2F, 0x80, 0xBF, 0x00, 0xDE, ++0x92, 0xF0, 0x8B, 0xC0, 0x77, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA0, 0x27, 0x01, 0xB3, 0x14, 0x7C, 0x32, 0x30, 0x09, 0xD0, 0x2C, 0x40, 0xA3, ++0x00, 0x9C, 0x12, 0x30, 0x4B, 0xC1, 0x2C, 0x03, 0x9F, 0x25, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x2D, 0x01, 0xBF, 0x14, 0x4C, 0x12, 0x70, 0x0B, 0xC0, 0x2F, 0x40, ++0xB3, 0x00, 0xFC, 0x12, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0xAB, 0x00, 0x8C, 0x02, ++0xF0, 0x0B, 0xC0, 0x76, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, ++0x17, 0x0D, 0x11, 0x44, 0x74, 0xB0, 0x10, 0x00, 0x41, 0x04, 0x04, 0x11, 0x08, ++0x44, 0x00, 0x90, 0x41, 0x40, 0x04, 0x03, 0x1D, 0x1A, 0x74, 0x40, 0xD0, 0x01, ++0x40, 0x07, 0x05, 0x1D, 0x04, 0x44, 0x20, 0xD0, 0x01, 0x43, 0x07, 0x04, 0x11, ++0x00, 0x74, 0x50, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x11, 0x40, 0x45, 0x00, 0xD2, ++0x05, 0x40, 0x60, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, ++0x03, 0x81, 0x34, 0x34, 0x12, 0x10, 0x48, 0x40, 0x20, 0x02, 0x81, 0x00, 0x54, ++0x27, 0x90, 0x48, 0x41, 0x20, 0x01, 0x8D, 0x04, 0x34, 0x22, 0xD0, 0x08, 0x40, ++0x21, 0x03, 0x8D, 0xB4, 0x04, 0x82, 0x50, 0x48, 0x40, 0x23, 0x02, 0xC5, 0x00, ++0x34, 0x32, 0xD0, 0x08, 0x40, 0x27, 0x80, 0x89, 0x00, 0x24, 0x82, 0xD0, 0x0C, ++0x40, 0x4A, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x40, ++0x91, 0x06, 0x74, 0x02, 0x10, 0x29, 0x40, 0x24, 0x00, 0x91, 0x04, 0x44, 0x02, ++0x90, 0x09, 0x50, 0x24, 0x01, 0x9D, 0x08, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, ++0x00, 0x9D, 0x00, 0x44, 0x02, 0xD0, 0x0D, 0x48, 0x37, 0x00, 0x95, 0x10, 0x74, ++0x82, 0xD0, 0x8D, 0x44, 0x67, 0x88, 0x91, 0x08, 0x64, 0x82, 0xD0, 0x19, 0x40, ++0x62, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x25, 0x00, 0x93, ++0x82, 0x7C, 0x1E, 0x31, 0x09, 0xC0, 0x24, 0x10, 0x93, 0x06, 0x5C, 0x0A, 0x34, ++0x09, 0xC4, 0x24, 0x01, 0x9E, 0x00, 0x7C, 0x32, 0xF0, 0x09, 0xC0, 0x25, 0x00, ++0x9F, 0x00, 0x4C, 0x1E, 0x70, 0xE9, 0xC0, 0x27, 0x00, 0x97, 0x00, 0x74, 0x02, ++0xF0, 0x09, 0xC0, 0x23, 0x00, 0x9B, 0x04, 0x6E, 0x26, 0xD2, 0x09, 0xC0, 0x16, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xE1, 0x00, 0x9F, 0x00, ++0x7C, 0x16, 0xF6, 0x99, 0xC0, 0x23, 0x28, 0x9F, 0x20, 0x7C, 0x12, 0x70, 0x09, ++0xC5, 0x27, 0x0C, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xE0, 0x27, 0xA0, 0x8F, ++0x00, 0x7D, 0x12, 0xF0, 0x19, 0xC3, 0x27, 0x00, 0x9B, 0x02, 0x7C, 0x42, 0xF0, ++0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x5E, 0x06, 0xF2, 0x08, 0xC0, 0x59, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x02, 0x7C, ++0x00, 0x30, 0x01, 0xC0, 0x06, 0x01, 0x1F, 0x02, 0x6C, 0x00, 0xB0, 0x00, 0xC0, ++0x07, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x01, 0xC0, 0x07, 0x04, 0x13, 0x00, ++0x7C, 0x08, 0xF0, 0x21, 0xC0, 0x06, 0x41, 0x13, 0x00, 0x4C, 0x00, 0x31, 0x01, ++0xC1, 0x07, 0x20, 0x1F, 0x02, 0x4D, 0x00, 0x70, 0x01, 0xC1, 0x50, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x14, 0x00, 0x7D, 0x02, 0x74, 0x01, ++0x12, 0x05, 0xC0, 0x9C, 0x04, 0x6D, 0x21, 0x04, 0x81, 0x10, 0x57, 0x40, 0x5F, ++0x01, 0x5D, 0x80, 0x74, 0x01, 0xD0, 0x05, 0x42, 0x1F, 0x20, 0x71, 0x08, 0x74, ++0x01, 0xD0, 0x57, 0xC0, 0x1C, 0x01, 0x71, 0x00, 0xC4, 0x05, 0x10, 0x27, 0xC1, ++0x9D, 0x04, 0x41, 0x05, 0xC4, 0xAD, 0x10, 0x07, 0x50, 0x40, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x13, 0x74, 0x03, 0x10, ++0x0D, 0x42, 0x30, 0x10, 0xCD, 0x04, 0x24, 0x02, 0x90, 0x3C, 0x40, 0x73, 0x00, ++0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0xF3, 0x00, 0xC1, 0x00, 0x34, 0x03, ++0xD0, 0x0C, 0x40, 0x34, 0x80, 0x49, 0x50, 0x05, 0x07, 0x10, 0x18, 0x40, 0xD3, ++0x01, 0xC5, 0x01, 0x04, 0x07, 0x50, 0x0C, 0x40, 0x40, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x88, 0x38, 0x02, 0xED, 0x02, 0x34, 0x03, 0x14, 0x4E, ++0x40, 0x38, 0x00, 0xED, 0x02, 0xC4, 0x03, 0x10, 0x0E, 0x42, 0x3B, 0x08, 0xED, ++0x0C, 0xB6, 0x03, 0xD0, 0x0E, 0x40, 0xF3, 0x00, 0xE1, 0x10, 0xB4, 0x03, 0xD0, ++0x1E, 0x40, 0x38, 0x80, 0x69, 0x01, 0x84, 0x45, 0x12, 0x0A, 0x40, 0x19, 0x00, ++0xB1, 0x00, 0xC4, 0x45, 0x10, 0x0A, 0x42, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x10, 0x78, 0x00, 0xEF, 0x01, 0xBC, 0x47, 0x30, 0x5E, 0xC2, ++0x78, 0x10, 0x6F, 0x01, 0xAC, 0x07, 0xB0, 0x1E, 0xC0, 0x7B, 0x00, 0xEF, 0x01, ++0xB4, 0x17, 0xF0, 0x1E, 0x80, 0x7B, 0x40, 0xE3, 0x01, 0xB4, 0x07, 0xF0, 0x17, ++0xD0, 0x70, 0x00, 0xEB, 0x01, 0xCC, 0x07, 0x34, 0x1A, 0xC0, 0x5B, 0x00, 0xE7, ++0x01, 0x8C, 0x07, 0x70, 0x17, 0xC0, 0x50, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xA8, 0x35, 0x04, 0xDF, 0x00, 0x7C, 0x33, 0xF0, 0x8D, 0xD0, 0x15, ++0x00, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0x05, 0xC4, 0x37, 0x10, 0xDF, 0x06, 0x7C, ++0x53, 0xF0, 0x0D, 0xC4, 0x37, 0x00, 0x5F, 0x00, 0x7C, 0x83, 0xF0, 0x05, 0xC0, ++0x35, 0x00, 0xC7, 0x00, 0x7C, 0x01, 0xF0, 0x09, 0xC4, 0x13, 0x00, 0x97, 0x00, ++0x7C, 0x01, 0xF0, 0x01, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xA0, 0x7F, 0x00, 0x7F, 0x21, 0xCC, 0x07, 0xF8, 0xAE, 0xC0, 0x5F, 0x08, ++0xEF, 0x01, 0xCC, 0x07, 0x70, 0x9F, 0xC4, 0x5C, 0x02, 0xF3, 0x0B, 0xCC, 0x47, ++0x31, 0x1F, 0x40, 0x5F, 0x20, 0x7F, 0x01, 0xCC, 0x07, 0xF0, 0x1F, 0xC0, 0x7C, ++0x00, 0xFF, 0x01, 0xFC, 0x07, 0x31, 0x9B, 0xC0, 0x7F, 0x00, 0xEF, 0x01, 0xCF, ++0x36, 0x30, 0xDF, 0xD0, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0x88, 0x39, 0x00, 0x7D, 0x10, 0x84, 0x23, 0xD8, 0x4E, 0x04, 0xB8, 0x00, 0xAD, ++0x04, 0x81, 0x03, 0x10, 0xAF, 0x40, 0x1C, 0x02, 0xF1, 0x20, 0xD5, 0x03, 0x14, ++0x0E, 0x40, 0x1A, 0x01, 0x6D, 0x08, 0x85, 0x03, 0xD0, 0x8E, 0x00, 0x39, 0x02, ++0xED, 0x00, 0xA4, 0x11, 0x10, 0x8A, 0x40, 0xBB, 0x01, 0xED, 0x04, 0xDC, 0x20, ++0x10, 0xCA, 0x40, 0x54, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x39, 0x00, 0x6D, 0x00, 0x85, 0x03, 0xD0, 0x8F, 0x40, 0x19, 0x00, 0x6D, 0x40, ++0xC0, 0x03, 0x50, 0x0E, 0x42, 0x18, 0x64, 0xE1, 0x00, 0x80, 0x43, 0x10, 0x0E, ++0x40, 0x3A, 0x08, 0xCD, 0x00, 0x84, 0x03, 0xD0, 0x07, 0x40, 0x18, 0x00, 0xED, ++0x00, 0x34, 0x03, 0x12, 0x0A, 0x48, 0x3B, 0x24, 0xFD, 0x20, 0x84, 0x52, 0x12, ++0xCA, 0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x73, ++0x12, 0x0D, 0x02, 0x04, 0x4B, 0xD0, 0x2C, 0x40, 0x04, 0x00, 0x0D, 0x08, 0x04, ++0x6F, 0x10, 0x08, 0x40, 0x40, 0x00, 0xC1, 0x40, 0x04, 0x0F, 0x10, 0x0C, 0x40, ++0x22, 0x00, 0x0D, 0x00, 0x04, 0x0F, 0xD2, 0x00, 0x40, 0x21, 0x00, 0xCD, 0x85, ++0x24, 0x00, 0x10, 0x08, 0x40, 0x73, 0x11, 0xCD, 0x00, 0x14, 0x04, 0x10, 0x38, ++0x40, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x3D, 0x00, ++0x9F, 0x00, 0xCC, 0x1F, 0xD0, 0x2F, 0x80, 0x25, 0x00, 0x8F, 0x20, 0x4C, 0x0F, ++0x74, 0x01, 0xD2, 0xE4, 0x00, 0xF3, 0x00, 0xC4, 0x07, 0x30, 0x0D, 0xC0, 0x26, ++0x00, 0x9F, 0x00, 0x4C, 0x0B, 0xF0, 0x39, 0xC1, 0x04, 0x00, 0x4F, 0x47, 0x74, ++0x02, 0x34, 0x09, 0xC0, 0xF3, 0x00, 0xDF, 0x00, 0x44, 0x07, 0x34, 0x21, 0x80, ++0x54, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x21, 0x9F, ++0x10, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0xA5, 0x00, 0x9F, 0x10, 0x7D, 0x03, 0xF0, ++0x09, 0xC0, 0xA7, 0x04, 0xDF, 0x01, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x86, 0x00, ++0x9F, 0x02, 0x7C, 0x23, 0xF0, 0x41, 0xC0, 0x87, 0x00, 0x5F, 0x40, 0x6C, 0x02, ++0xF0, 0x29, 0xC0, 0xB7, 0x00, 0x9F, 0x90, 0x5C, 0x09, 0xF0, 0xC9, 0xC0, 0x37, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x80, 0x3F, 0x00, ++0xFC, 0x03, 0xF0, 0x0F, 0xC1, 0x2F, 0x00, 0x33, 0x89, 0xCC, 0x07, 0x10, 0x03, ++0xC0, 0x0F, 0x00, 0xFF, 0x00, 0xF4, 0x43, 0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xBF, ++0x00, 0xFC, 0x43, 0xC0, 0x0B, 0xC0, 0x2C, 0x00, 0xFF, 0x00, 0xDC, 0x02, 0xF0, ++0x0B, 0xC0, 0x3F, 0x00, 0xB7, 0x00, 0xFC, 0x07, 0x34, 0x01, 0xC8, 0x07, 0x24, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x80, 0x9D, 0x07, 0x74, ++0x83, 0xD0, 0x0D, 0x42, 0xE7, 0x20, 0x11, 0x87, 0x04, 0x07, 0xB0, 0x31, 0x40, ++0xE7, 0x00, 0xDD, 0x20, 0x64, 0x03, 0xD0, 0x0D, 0x40, 0x46, 0x00, 0x99, 0x01, ++0x74, 0x83, 0x91, 0x30, 0x40, 0xE5, 0x00, 0xDD, 0x01, 0x44, 0x06, 0xD0, 0x39, ++0x40, 0x77, 0x00, 0x91, 0x00, 0x74, 0x02, 0x10, 0x31, 0x44, 0x87, 0x00, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x36, 0x20, 0x9D, 0x01, 0x74, 0x03, ++0xD0, 0x0D, 0x64, 0x47, 0x40, 0x91, 0x00, 0x44, 0x23, 0x50, 0x11, 0x40, 0x67, ++0x04, 0xDD, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0xC7, 0x00, 0x1D, 0x03, 0x74, ++0x03, 0xD0, 0x19, 0x40, 0x47, 0x00, 0x9D, 0x01, 0x54, 0xC4, 0xD0, 0x1D, 0x40, ++0x77, 0x00, 0xD5, 0x01, 0x34, 0x1A, 0x10, 0x31, 0x40, 0x07, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x8D, 0x00, 0x34, 0x03, 0xD0, ++0x0C, 0x60, 0x23, 0x00, 0x81, 0x00, 0x44, 0x03, 0xD4, 0x08, 0x40, 0x23, 0x20, ++0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x03, 0x00, 0x09, 0x00, 0x34, 0x03, ++0x90, 0x09, 0x40, 0x03, 0x00, 0xCD, 0x00, 0x04, 0x00, 0xD0, 0x0C, 0x40, 0x33, ++0x00, 0xC1, 0x00, 0x34, 0x01, 0x10, 0x08, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x3E, 0x00, 0x1D, 0x00, 0xFC, 0x03, 0xF0, 0x0F, ++0xC0, 0x07, 0x08, 0x93, 0x00, 0x4D, 0x03, 0x70, 0x01, 0xC0, 0x07, 0x00, 0xFF, ++0x00, 0xFC, 0x03, 0xF0, 0x0D, 0xC4, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF0, ++0x09, 0xD0, 0x06, 0x00, 0xDF, 0x00, 0x5C, 0x02, 0xF0, 0x09, 0xC0, 0x37, 0x00, ++0x97, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x60, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x2F, 0x00, 0x3F, 0x00, 0xBC, 0x03, 0xA0, 0x0B, 0xC0, 0x2F, 0x00, 0xFE, 0x00, ++0xEC, 0x03, 0xF0, 0x0F, 0xC0, 0x0E, 0x00, 0xBA, 0x00, 0xFC, 0x03, 0xB0, 0x0A, ++0xC0, 0x2D, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x03, 0xC2, 0x2F, 0x00, 0xBF, ++0x00, 0xFC, 0x00, 0xF2, 0x0B, 0xC0, 0x17, 0x61, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xA0, 0x2F, 0x40, 0x23, 0x10, 0xCD, 0x00, 0x30, 0x03, 0xC0, 0x4C, ++0x40, 0x33, 0x81, 0xCC, 0x24, 0x30, 0x13, 0xD0, 0x2C, 0x05, 0xF3, 0x09, 0xDC, ++0x00, 0x30, 0x4E, 0xC0, 0x2C, 0x00, 0x3F, 0x01, 0xCD, 0x04, 0xF1, 0x13, 0xC0, ++0x4C, 0x08, 0x33, 0x01, 0xFC, 0x04, 0xB0, 0x13, 0xD4, 0x4C, 0x40, 0xF3, 0x00, ++0xCD, 0x07, 0xF0, 0x4F, 0xC1, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x27, 0x00, 0x51, 0x92, 0x04, 0x08, 0x13, 0x09, 0x40, 0x04, 0x05, ++0x11, 0x10, 0x44, 0x01, 0x10, 0x01, 0x41, 0xA4, 0x05, 0xC1, 0x04, 0x44, 0x2C, ++0x10, 0x3F, 0xC0, 0x64, 0x02, 0x1D, 0x00, 0x64, 0x04, 0xD0, 0x05, 0xC0, 0x04, ++0x20, 0x11, 0x01, 0x74, 0x04, 0x10, 0x01, 0x60, 0x04, 0x00, 0xC1, 0x00, 0x44, ++0x07, 0xD1, 0x2D, 0x40, 0x0C, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++0xA0, 0x27, 0x00, 0x01, 0x05, 0x06, 0x0C, 0x10, 0x00, 0x40, 0x20, 0x01, 0x81, ++0x00, 0x14, 0x02, 0x10, 0x48, 0x48, 0x21, 0x00, 0x81, 0x04, 0x34, 0x00, 0xD4, ++0x8C, 0x44, 0x30, 0x00, 0x8D, 0x00, 0x34, 0x01, 0xD0, 0x00, 0x42, 0x46, 0x20, ++0x0D, 0x01, 0x74, 0x02, 0x10, 0x08, 0x40, 0x20, 0x00, 0xC9, 0x00, 0x24, 0x03, ++0xD0, 0x0C, 0x40, 0x4C, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA8, ++0x25, 0x02, 0x51, 0x44, 0x14, 0x04, 0x14, 0x1D, 0x40, 0x20, 0x00, 0x80, 0x00, ++0x55, 0x03, 0x14, 0x09, 0x40, 0x64, 0x00, 0x51, 0x00, 0x64, 0x0C, 0xC0, 0x1D, ++0x44, 0x76, 0x04, 0x8D, 0x00, 0x74, 0x89, 0xD0, 0x05, 0x50, 0x04, 0x00, 0x15, ++0x00, 0x74, 0x02, 0x10, 0x08, 0x40, 0x20, 0x00, 0x99, 0x00, 0x44, 0x03, 0xD0, ++0x1C, 0x40, 0x0C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x43, ++0x00, 0x13, 0x00, 0x4C, 0x04, 0x30, 0x31, 0xC2, 0x04, 0x00, 0x13, 0x01, 0x5C, ++0x00, 0x30, 0x11, 0xC0, 0xE4, 0x04, 0xD3, 0x04, 0x7C, 0x0C, 0xF0, 0x35, 0xC0, ++0xE4, 0x00, 0x1F, 0x00, 0x5C, 0x00, 0xF0, 0x21, 0xC0, 0x12, 0x00, 0x57, 0x00, ++0x3C, 0x01, 0xB0, 0x01, 0x40, 0x04, 0x00, 0xDB, 0x00, 0x4C, 0x03, 0xF0, 0x1D, ++0xC0, 0x08, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x4D, 0x00, ++0x7F, 0x00, 0xEC, 0x00, 0xF0, 0x0F, 0xC0, 0x0F, 0x12, 0x3F, 0x09, 0xEC, 0x01, ++0xF0, 0x93, 0x80, 0x2F, 0x50, 0xFF, 0x00, 0x5C, 0x00, 0x30, 0x06, 0xC0, 0x25, ++0x00, 0x3F, 0x08, 0xCC, 0x00, 0xF2, 0x07, 0xC4, 0x1F, 0x00, 0x7B, 0x00, 0xFC, ++0x81, 0xF0, 0x83, 0xC0, 0x0F, 0x02, 0xE7, 0x08, 0xFC, 0x03, 0xF0, 0x0F, 0xD4, ++0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x25, 0x40, 0x33, ++0x00, 0x4C, 0x00, 0x32, 0x31, 0xC0, 0x64, 0x00, 0x9F, 0x01, 0x4C, 0x02, 0xF0, ++0x09, 0xC0, 0x24, 0x00, 0x53, 0x04, 0x6C, 0x88, 0xB0, 0x2D, 0xC0, 0x34, 0x11, ++0x97, 0x05, 0x7C, 0x01, 0x30, 0x41, 0xC0, 0x17, 0x02, 0x5B, 0x10, 0x4C, 0x03, ++0x30, 0x19, 0xC0, 0x64, 0x00, 0x9F, 0x04, 0x4C, 0x03, 0xF0, 0x15, 0xC0, 0x08, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x24, 0x20, 0x41, 0x01, ++0x44, 0x14, 0x10, 0xBD, 0x40, 0x64, 0x00, 0x9D, 0x0B, 0x44, 0x2F, 0xD0, 0xA8, ++0xC2, 0x26, 0x00, 0xD1, 0x82, 0x04, 0x00, 0x10, 0xAD, 0x40, 0xB4, 0x00, 0x91, ++0x03, 0x70, 0x09, 0x11, 0x35, 0x40, 0x97, 0x02, 0x51, 0x13, 0x44, 0x43, 0x10, ++0xB9, 0x40, 0x64, 0x00, 0x9D, 0x02, 0x45, 0x13, 0xD0, 0x15, 0x40, 0x6C, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x20, 0x02, 0x01, 0x1A, 0x20, ++0x00, 0x14, 0x21, 0x40, 0x10, 0x00, 0x4D, 0x00, 0x60, 0x2C, 0xD0, 0x14, 0x40, ++0x34, 0x40, 0xD1, 0x02, 0x24, 0x00, 0xD0, 0x2C, 0x40, 0x00, 0x20, 0x45, 0x02, ++0x30, 0x62, 0x10, 0x19, 0x40, 0x21, 0x00, 0x80, 0x41, 0x04, 0x04, 0x10, 0x04, ++0x40, 0x10, 0x00, 0xCD, 0x00, 0x04, 0x07, 0xD0, 0x08, 0x40, 0x1C, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00, 0x31, 0x01, 0xA5, 0x04, ++0x10, 0x1B, 0x40, 0x58, 0x00, 0x6D, 0x01, 0xA4, 0x05, 0xD0, 0x16, 0x40, 0x6A, ++0x00, 0xE1, 0x01, 0x84, 0x24, 0x50, 0x9E, 0x40, 0x58, 0x00, 0x61, 0x01, 0xB6, ++0x06, 0x10, 0x1E, 0x40, 0x6F, 0x00, 0xB1, 0x81, 0xC4, 0x04, 0x10, 0x16, 0x40, ++0x58, 0x00, 0xED, 0x09, 0x84, 0x07, 0xD0, 0x2F, 0x40, 0x74, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x24, 0x01, 0x03, 0x08, 0x24, 0x00, 0x30, ++0x64, 0xC0, 0x30, 0x00, 0xDF, 0x00, 0x2C, 0x02, 0xF0, 0x0C, 0xC1, 0x14, 0x20, ++0x83, 0x00, 0x2C, 0x20, 0xF2, 0x08, 0xD0, 0x10, 0x00, 0xC7, 0x00, 0x3C, 0x03, ++0x30, 0x48, 0xC1, 0x23, 0x10, 0x83, 0x00, 0x0C, 0x02, 0x32, 0x0D, 0xD0, 0x30, ++0x00, 0x8F, 0x00, 0x0D, 0x03, 0xF0, 0x8C, 0xC8, 0x48, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x38, 0x3D, 0x40, 0x3F, 0x00, 0xDC, 0x00, 0xF0, 0x0E, ++0xC0, 0x3F, 0x00, 0xFF, 0x08, 0xDD, 0x03, 0xF2, 0x8E, 0xC4, 0x2F, 0x20, 0xFF, ++0x00, 0xFC, 0x20, 0xB0, 0x0F, 0xC2, 0x1F, 0x02, 0xFF, 0x08, 0xBC, 0x23, 0xF0, ++0x0F, 0xC0, 0x2B, 0x00, 0xA7, 0x00, 0xBC, 0x02, 0xF1, 0x0F, 0xC0, 0x3F, 0x00, ++0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x4E, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0xA0, 0x07, 0x00, 0x13, 0x00, 0x7C, 0x00, 0x34, 0x05, 0xC0, ++0x14, 0x00, 0x5F, 0x01, 0x4C, 0x00, 0xF0, 0x05, 0xC0, 0x34, 0x00, 0xCF, 0x00, ++0x4C, 0x04, 0x30, 0x4C, 0xC0, 0x34, 0x00, 0x5B, 0x00, 0x7C, 0x02, 0xF0, 0x09, ++0xD0, 0x34, 0x00, 0xD3, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0xDF, ++0x00, 0x0D, 0x03, 0x30, 0x0C, 0xD0, 0x54, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x80, 0x0D, 0x10, 0x21, 0x00, 0xF4, 0x02, 0x10, 0x0E, 0x40, 0x18, ++0x30, 0x6D, 0x00, 0x84, 0x01, 0xD0, 0x06, 0x40, 0x28, 0x00, 0xED, 0x00, 0xAC, ++0x00, 0x90, 0x0E, 0x43, 0x38, 0x48, 0x61, 0x00, 0xB4, 0x02, 0xD0, 0x0E, 0x42, ++0x38, 0x00, 0xE1, 0x00, 0xB4, 0x01, 0xD0, 0x06, 0x40, 0x1B, 0x00, 0xFD, 0x00, ++0x84, 0x03, 0x10, 0x0E, 0x60, 0x4C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x79, 0x00, 0x21, 0x01, 0xB4, 0x04, 0x10, 0x1E, 0x40, 0x78, 0x00, ++0xED, 0x01, 0x84, 0x06, 0xD0, 0x1E, 0x60, 0x78, 0x00, 0xFD, 0x01, 0x04, 0x40, ++0xD0, 0x1A, 0x40, 0x78, 0x00, 0xE9, 0x21, 0xB6, 0x07, 0xD0, 0x1A, 0x40, 0x78, ++0x00, 0xE1, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x01, 0x84, ++0x07, 0x10, 0x17, 0x40, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x28, 0x33, 0x02, 0x81, 0x00, 0x74, 0x27, 0x10, 0x7C, 0x40, 0x30, 0x00, 0xCD, ++0x00, 0x44, 0x03, 0xD0, 0x0C, 0x62, 0x20, 0x01, 0xCD, 0x83, 0x24, 0x07, 0xD0, ++0x2C, 0x40, 0x70, 0x00, 0xC1, 0x00, 0x34, 0x03, 0xD0, 0x0D, 0x42, 0x34, 0x00, ++0xC1, 0x40, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x09, 0x04, 0x03, ++0x15, 0x04, 0x60, 0x48, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x20, ++0x19, 0x40, 0x73, 0x42, 0xFC, 0x05, 0x30, 0x57, 0xD0, 0x14, 0x00, 0x5F, 0x00, ++0x4D, 0x01, 0xF0, 0x05, 0xD0, 0x1C, 0x20, 0x7F, 0x05, 0xCC, 0x09, 0x74, 0x27, ++0xC0, 0xDC, 0x03, 0x5B, 0x80, 0x3C, 0x01, 0xF1, 0x05, 0xC0, 0x14, 0x00, 0x53, ++0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x0C, 0x01, 0x30, ++0x27, 0xC0, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x85, ++0x14, 0x0F, 0x24, 0x7C, 0x04, 0xF4, 0x21, 0xC0, 0x07, 0x00, 0x1F, 0x80, 0x7C, ++0x00, 0xF0, 0x01, 0xC0, 0x03, 0x00, 0x1F, 0x10, 0x7C, 0x10, 0x30, 0x61, 0xD0, ++0x07, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xD1, 0x01, 0xC8, 0x07, 0x40, 0x1F, 0x00, ++0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x20, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, ++0xC1, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x65, 0x00, ++0x93, 0x01, 0x4C, 0x02, 0x30, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0x30, 0x89, 0xC0, 0x24, 0x00, 0x93, 0x04, 0x0C, 0x0A, 0x30, 0x29, 0xC0, 0x22, ++0x70, 0x93, 0x80, 0x7C, 0x06, 0x30, 0x09, 0xC0, 0x64, 0x02, 0x93, 0x05, 0x7C, ++0x02, 0xF0, 0x49, 0xC0, 0x27, 0x02, 0x9F, 0x01, 0x4C, 0x02, 0x30, 0x09, 0xC0, ++0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x10, 0x91, ++0x28, 0x44, 0x02, 0x10, 0x28, 0x40, 0xA4, 0x00, 0x9D, 0x02, 0x74, 0x02, 0x10, ++0x39, 0x40, 0x24, 0x20, 0x81, 0x00, 0x6C, 0x02, 0x10, 0x28, 0x40, 0xA4, 0x00, ++0x91, 0x02, 0x5C, 0x02, 0x10, 0x09, 0x40, 0xE4, 0x08, 0x91, 0x21, 0x74, 0x82, ++0xD0, 0x29, 0x40, 0xE7, 0x00, 0x9D, 0x03, 0x45, 0x02, 0x14, 0x09, 0x40, 0x04, ++0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x46, 0x91, 0x20, ++0x44, 0x02, 0x12, 0x29, 0x40, 0x24, 0x01, 0xBD, 0x04, 0xF4, 0x02, 0x18, 0x0A, ++0x40, 0x24, 0x00, 0x91, 0x80, 0x64, 0x02, 0x19, 0x0D, 0x40, 0x26, 0x00, 0x91, ++0x00, 0xF4, 0x22, 0x1C, 0x0F, 0x40, 0x2C, 0x04, 0xB1, 0x00, 0xF4, 0x06, 0xD0, ++0x0B, 0x40, 0x2F, 0x00, 0x8D, 0x0A, 0x64, 0x02, 0x10, 0x18, 0x40, 0x62, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x24, 0x01, 0x81, 0x04, 0x04, ++0x12, 0x10, 0x48, 0x50, 0x68, 0x00, 0xAD, 0x01, 0xB4, 0x02, 0x10, 0x1A, 0x42, ++0x20, 0x01, 0x91, 0x00, 0x24, 0x12, 0x10, 0x48, 0x40, 0x32, 0x01, 0xA1, 0x01, ++0xD4, 0x03, 0x10, 0x0A, 0x40, 0x28, 0x20, 0xA1, 0x01, 0xB4, 0x02, 0xD0, 0x1A, ++0x40, 0x6B, 0x00, 0x8D, 0x04, 0x25, 0x02, 0x10, 0x58, 0x50, 0x42, 0x80, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x86, 0x02, 0x53, 0x0A, 0x4D, 0x28, ++0x34, 0xA0, 0x40, 0x84, 0x02, 0x0F, 0x0A, 0x7C, 0x29, 0x30, 0xA2, 0x40, 0x84, ++0x02, 0x13, 0x0A, 0x6C, 0x00, 0x30, 0x05, 0xC0, 0x06, 0x00, 0x13, 0x0A, 0x7C, ++0x00, 0x30, 0xA0, 0xD0, 0x80, 0x02, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0xA1, 0xC0, ++0x8F, 0x02, 0x1F, 0x0A, 0x6C, 0x00, 0x30, 0xA1, 0xC0, 0x76, 0xC0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x2F, 0x02, 0xBF, 0x08, 0xFC, 0x22, 0xF0, ++0x8B, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF4, 0x09, 0xD0, 0x2F, 0x42, ++0xBF, 0x80, 0xFC, 0x22, 0xF0, 0x8B, 0xC0, 0x29, 0x82, 0x9F, 0x00, 0x5C, 0x02, ++0xF0, 0x09, 0xC0, 0x27, 0x40, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0xBF, 0x08, 0x5C, 0x02, 0xF0, 0x8B, 0xC0, 0x65, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1C, 0xA0, 0x2F, 0x01, 0xA3, 0x14, 0xFC, 0x32, 0xF0, 0x0B, ++0xD0, 0x2C, 0x00, 0xB3, 0x08, 0xFC, 0x02, 0x30, 0x0B, 0xC0, 0x26, 0x19, 0xB3, ++0x00, 0xCC, 0x06, 0x30, 0x1B, 0xC1, 0x6E, 0x04, 0xBF, 0x00, 0xFC, 0x02, 0x30, ++0x0B, 0xC0, 0x3C, 0x00, 0xF3, 0x00, 0xCC, 0x03, 0x31, 0x0B, 0xC0, 0x2C, 0x02, ++0xBF, 0x00, 0xCC, 0x02, 0xF0, 0x8F, 0xC0, 0x60, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0x00, 0x17, 0x45, 0x11, 0x04, 0x74, 0x30, 0xD0, 0x20, 0x41, ++0x14, 0x44, 0x51, 0x00, 0x74, 0x50, 0x10, 0x41, 0x50, 0x04, 0x02, 0x13, 0x00, ++0x6C, 0x28, 0x14, 0x01, 0x40, 0x04, 0x00, 0x5D, 0x04, 0x74, 0x00, 0x10, 0x01, ++0x41, 0x04, 0x04, 0x11, 0x00, 0x44, 0x00, 0x10, 0x45, 0x40, 0x14, 0x01, 0x1D, ++0x12, 0x45, 0x00, 0xD0, 0x81, 0x40, 0x70, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x21, 0x43, 0x81, 0x14, 0x34, 0x12, 0xD0, 0xC8, 0x50, 0x20, ++0x10, 0x81, 0x00, 0x74, 0x16, 0x14, 0x48, 0x41, 0x24, 0x00, 0x81, 0x00, 0x24, ++0x02, 0x90, 0x08, 0x40, 0x22, 0x00, 0x8D, 0x94, 0x74, 0x02, 0x98, 0x49, 0x40, ++0x22, 0x00, 0x91, 0x00, 0x14, 0x02, 0x90, 0x48, 0x41, 0x22, 0x11, 0x8D, 0x0C, ++0x04, 0x02, 0xD0, 0x18, 0x40, 0x48, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0x28, 0x25, 0x00, 0x91, 0x10, 0x74, 0x02, 0xD0, 0x49, 0x41, 0x20, 0x00, ++0x91, 0x00, 0x74, 0x02, 0x10, 0x29, 0x40, 0xA4, 0x00, 0x91, 0x00, 0x64, 0x62, ++0x98, 0x19, 0x44, 0x24, 0x02, 0x9D, 0x00, 0x74, 0x02, 0x9C, 0x09, 0x50, 0x22, ++0x00, 0x91, 0x00, 0x54, 0x02, 0x90, 0x08, 0x50, 0x26, 0x00, 0x9D, 0x08, 0x44, ++0x02, 0xD0, 0x08, 0x40, 0x60, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0x00, 0x25, 0x00, 0x93, 0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC0, 0xA4, 0x00, 0x93, ++0x02, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0x24, 0x40, 0x93, 0x10, 0x6D, 0x0A, 0xB0, ++0x79, 0xC0, 0x26, 0x10, 0x9F, 0x02, 0x3C, 0x02, 0xB0, 0x08, 0xC2, 0x26, 0x40, ++0x83, 0x00, 0x5C, 0x42, 0xB4, 0x29, 0xC0, 0xA6, 0x00, 0x9F, 0x00, 0x4C, 0x02, ++0xF0, 0x19, 0xC0, 0x14, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, ++0xE5, 0x00, 0x9F, 0x10, 0x7C, 0xA6, 0xF0, 0x18, 0xD0, 0x27, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF2, 0x09, 0xC0, 0x25, 0x00, 0x97, 0x15, 0x7E, 0x06, 0x70, 0x09, ++0xC0, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x26, 0x72, 0x09, 0xC1, 0x25, 0x00, 0x9F, ++0x00, 0x6D, 0x02, 0x70, 0x09, 0xC0, 0x25, 0x04, 0x9F, 0x10, 0x7E, 0x02, 0xF0, ++0x49, 0xD1, 0x5B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x81, ++0x01, 0x13, 0x02, 0x4C, 0x20, 0x34, 0x81, 0xC0, 0x86, 0x44, 0x13, 0x12, 0x6D, ++0x04, 0xF0, 0x81, 0xC0, 0x04, 0x00, 0x1F, 0x02, 0x4C, 0x88, 0x30, 0x20, 0xC0, ++0x04, 0x08, 0x1F, 0x02, 0x4D, 0x40, 0xF0, 0x01, 0xC0, 0x06, 0x00, 0x13, 0x00, ++0x7C, 0x40, 0xF0, 0x21, 0xD0, 0x84, 0x40, 0x13, 0x08, 0x4C, 0x00, 0xF0, 0x01, ++0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x1C, 0x00, ++0x71, 0x82, 0x44, 0x05, 0x10, 0x17, 0xC0, 0x9C, 0x00, 0x71, 0x02, 0x84, 0x05, ++0xD0, 0x16, 0x40, 0x10, 0x00, 0x7D, 0x00, 0x14, 0x01, 0x14, 0x37, 0x40, 0x9C, ++0x00, 0x7D, 0x03, 0xC4, 0x11, 0xD0, 0x17, 0xC0, 0x1C, 0x00, 0x71, 0x00, 0xB0, ++0x4D, 0xD0, 0x07, 0x40, 0x1C, 0x00, 0x71, 0x01, 0x45, 0x01, 0xD0, 0x17, 0x41, ++0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x32, 0x40, 0x81, ++0x02, 0x24, 0x07, 0x10, 0x0C, 0x40, 0xB0, 0x00, 0xC1, 0x02, 0x04, 0x27, 0xD0, ++0x08, 0x40, 0x30, 0x00, 0x5D, 0x00, 0x04, 0x03, 0x90, 0xB8, 0x51, 0xB0, 0x21, ++0xCD, 0x05, 0x00, 0x07, 0xD0, 0x2C, 0x40, 0x30, 0x00, 0xC1, 0x13, 0x34, 0x0B, ++0xD8, 0x0C, 0x40, 0x30, 0x00, 0x91, 0x03, 0x04, 0x02, 0xD0, 0x2C, 0x40, 0x50, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x28, 0x00, 0x31, 0x01, ++0xA4, 0x06, 0x10, 0x06, 0x40, 0x38, 0x00, 0xE1, 0x01, 0x84, 0x03, 0xD0, 0x0E, ++0x42, 0x38, 0x21, 0xED, 0x00, 0x94, 0x03, 0x90, 0x08, 0x40, 0x18, 0x04, 0xED, ++0x03, 0x84, 0x01, 0xD1, 0x2F, 0x50, 0x38, 0x00, 0x21, 0x10, 0xB4, 0x03, 0xD0, ++0x0E, 0x40, 0x78, 0x00, 0xA1, 0x00, 0x84, 0x02, 0xD0, 0x08, 0x40, 0x14, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x5C, 0x02, 0x63, 0x01, 0xEC, ++0x07, 0x30, 0x1E, 0xD1, 0x7C, 0x00, 0xF3, 0x01, 0x8C, 0x07, 0xF0, 0x1A, 0xD0, ++0xF8, 0x21, 0x3F, 0x01, 0x84, 0x07, 0xB0, 0x16, 0xC0, 0x78, 0x00, 0xFF, 0x21, ++0x8C, 0x07, 0xF0, 0x1E, 0xC0, 0x7C, 0x40, 0x23, 0x01, 0xBC, 0x07, 0xF0, 0x1F, ++0xC0, 0x7C, 0x00, 0x73, 0x01, 0x84, 0x06, 0xF0, 0x1E, 0xD0, 0x54, 0x40, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x9D, 0x00, 0x1F, 0x80, 0x5D, 0x12, ++0xF0, 0x07, 0xC0, 0x35, 0x08, 0x5F, 0x00, 0x7C, 0x03, 0xF2, 0x00, 0xC0, 0x77, ++0x00, 0x9F, 0x00, 0x3C, 0x03, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, ++0x03, 0xF0, 0x0C, 0xC0, 0x35, 0x08, 0x1F, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, ++0x37, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x01, 0xC0, 0x43, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x7D, 0x00, 0x23, 0x01, 0xCC, 0x3F, 0xF8, ++0x8B, 0xC0, 0x7C, 0x00, 0xF3, 0x01, 0xFC, 0x07, 0xB0, 0x9B, 0xC0, 0x7F, 0x00, ++0xE7, 0x01, 0x8C, 0x87, 0x24, 0x1E, 0xC0, 0x5D, 0x00, 0xF3, 0x01, 0xD4, 0x25, ++0xB0, 0x1F, 0xD8, 0x7C, 0x00, 0x32, 0x01, 0xFC, 0x05, 0xF0, 0x1F, 0xC0, 0x7C, ++0x00, 0x73, 0x01, 0xCC, 0x06, 0xF0, 0x17, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x00, 0x29, 0x00, 0x21, 0x82, 0x84, 0x62, 0x30, 0x47, ++0x40, 0x3C, 0x00, 0xE1, 0x00, 0xBC, 0x02, 0x10, 0xCE, 0x40, 0x3B, 0x00, 0xEB, ++0x00, 0xAC, 0x13, 0x30, 0x0E, 0x40, 0x98, 0x40, 0xE1, 0x08, 0x84, 0x01, 0x14, ++0x4B, 0xC1, 0x3C, 0x00, 0x21, 0x08, 0xB4, 0x08, 0xD0, 0x2E, 0x40, 0x3C, 0x00, ++0xE1, 0x00, 0x84, 0x02, 0xD0, 0x82, 0x40, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x61, 0x00, 0x04, 0x13, 0x50, 0x8A, 0x50, ++0x38, 0x00, 0xE9, 0x00, 0xF4, 0x03, 0x10, 0x0A, 0x60, 0x33, 0x00, 0xB5, 0x00, ++0xA4, 0x83, 0x80, 0x0F, 0x50, 0x3B, 0x00, 0x61, 0x00, 0x94, 0x00, 0x94, 0x0E, ++0x60, 0x38, 0x00, 0x29, 0x00, 0xB4, 0x01, 0xD0, 0x0E, 0x40, 0x38, 0x00, 0xE1, ++0x00, 0x84, 0x02, 0xD0, 0x06, 0x40, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x28, 0x51, 0x00, 0x01, 0x06, 0x05, 0x0A, 0x12, 0xB5, 0x41, 0x30, ++0x00, 0xC9, 0x00, 0x34, 0x02, 0x10, 0x04, 0x60, 0xF3, 0x40, 0x89, 0x03, 0x24, ++0x23, 0x10, 0x1C, 0x40, 0x32, 0x00, 0xD1, 0x00, 0x04, 0x01, 0x90, 0x08, 0x40, ++0x30, 0x00, 0x09, 0x00, 0x34, 0x00, 0xD0, 0x0D, 0x40, 0x30, 0x00, 0xD1, 0x00, ++0x05, 0x02, 0xD0, 0x18, 0x40, 0x13, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0xA0, 0x65, 0x40, 0x13, 0x07, 0x4C, 0x0E, 0x70, 0x09, 0xC0, 0x34, 0x00, ++0xDB, 0x00, 0x7C, 0x03, 0xB0, 0x08, 0xC2, 0x3F, 0x20, 0x07, 0x0D, 0x0C, 0x0A, ++0xB0, 0x5D, 0xC0, 0x73, 0x04, 0xD3, 0x00, 0x5C, 0x02, 0xB0, 0x0D, 0xC0, 0x34, ++0x00, 0x0B, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xD0, 0x34, 0x00, 0x93, 0x05, 0x4C, ++0x03, 0xF0, 0x0C, 0xC1, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0x08, 0x27, 0x02, 0x3F, 0x00, 0x7C, 0x02, 0x70, 0x21, 0xC0, 0x27, 0x20, 0x97, ++0x00, 0x5C, 0x07, 0xF0, 0x29, 0xC0, 0x37, 0x06, 0x97, 0x00, 0x7C, 0x42, 0xF0, ++0x0D, 0xC0, 0x35, 0x20, 0x9F, 0x00, 0x7C, 0x00, 0x72, 0x25, 0xC0, 0xA5, 0x00, ++0x13, 0x00, 0x7C, 0x08, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xF0, 0x09, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, ++0x0F, 0x60, 0x73, 0x00, 0xAC, 0x42, 0xB0, 0x03, 0xC0, 0x1C, 0x00, 0xFF, 0x00, ++0xFC, 0x03, 0x30, 0x4B, 0xC0, 0x3E, 0x00, 0x33, 0x05, 0xCC, 0x07, 0x30, 0x4F, ++0x40, 0x37, 0x00, 0xF3, 0x00, 0xEC, 0x02, 0xE0, 0x3F, 0xC0, 0x1C, 0x00, 0x31, ++0x00, 0xCC, 0x01, 0xF0, 0x07, 0x80, 0x5C, 0x00, 0x53, 0x00, 0xCC, 0x07, 0xF0, ++0x3F, 0xE0, 0x00, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xC6, ++0x00, 0x11, 0x22, 0x44, 0x06, 0x10, 0x31, 0x40, 0x14, 0x00, 0x5D, 0x01, 0x34, ++0x07, 0x10, 0x59, 0x42, 0x30, 0x40, 0x91, 0x40, 0x54, 0x03, 0x10, 0x7D, 0x40, ++0xF7, 0x00, 0x9B, 0x01, 0x44, 0x06, 0xD0, 0x05, 0x50, 0x34, 0x00, 0x11, 0x07, ++0x4C, 0x0C, 0xD0, 0x3D, 0x40, 0xD4, 0x02, 0xD1, 0x00, 0x44, 0x02, 0xD0, 0x39, ++0x50, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0xC2, 0x00, ++0x01, 0x00, 0x64, 0x13, 0x90, 0x19, 0x41, 0x76, 0x00, 0xDD, 0x88, 0x74, 0x07, ++0x14, 0x09, 0x48, 0x34, 0x00, 0x99, 0x40, 0x46, 0x12, 0x10, 0x0D, 0x48, 0x67, ++0x00, 0xD1, 0x04, 0x64, 0x04, 0xD0, 0x2C, 0x40, 0xB2, 0x01, 0x15, 0x01, 0x64, ++0x05, 0xD0, 0x8D, 0x40, 0x31, 0x04, 0x51, 0x00, 0x44, 0x13, 0xD0, 0x2D, 0x40, ++0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x01, ++0x00, 0x04, 0x02, 0x10, 0x00, 0x50, 0x62, 0x00, 0x8D, 0x00, 0x34, 0x07, 0x14, ++0x09, 0x42, 0x34, 0x00, 0x91, 0x00, 0x14, 0x02, 0x10, 0x0C, 0x60, 0x23, 0x40, ++0xC9, 0x00, 0x04, 0x00, 0xD0, 0x0C, 0x40, 0x22, 0x80, 0x05, 0x80, 0x04, 0x00, ++0xD0, 0x08, 0x40, 0x21, 0x00, 0xC1, 0x00, 0x04, 0x02, 0xD0, 0x08, 0x40, 0x40, ++0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0E, 0x00, 0x53, 0x00, ++0xEC, 0x03, 0xB2, 0x03, 0xD0, 0x36, 0x00, 0xDF, 0x80, 0x7C, 0x03, 0x14, 0x09, ++0xD0, 0x36, 0x00, 0x92, 0x00, 0x4C, 0x03, 0x34, 0x0D, 0x40, 0x27, 0x10, 0x43, ++0x00, 0x6C, 0x00, 0xF0, 0x0D, 0xD0, 0x16, 0x00, 0x17, 0x00, 0x6C, 0x01, 0xF0, ++0x04, 0xD0, 0x35, 0x00, 0xD3, 0x00, 0x4C, 0x03, 0xF0, 0x09, 0xC0, 0x00, 0xC0, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x0B, 0x00, 0x3F, 0x00, 0xFC, ++0x02, 0xF1, 0x03, 0xC0, 0x3D, 0x00, 0xFF, 0x00, 0xBC, 0x01, 0xF4, 0x0B, 0xC0, ++0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xFF, 0x00, ++0xB4, 0x00, 0xF0, 0x0F, 0xC0, 0x3D, 0x00, 0x3B, 0x00, 0xFC, 0x00, 0xF0, 0x0F, ++0xC0, 0x3E, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x17, 0x60, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x02, ++0xF0, 0x1F, 0xC8, 0x3F, 0x01, 0xBF, 0x22, 0xFC, 0x0A, 0x30, 0x0B, 0xC0, 0xBF, ++0x05, 0xEF, 0x09, 0xEC, 0x10, 0xB0, 0x3F, 0xC0, 0xBD, 0x00, 0xB3, 0x04, 0xCC, ++0x82, 0x32, 0x2F, 0xC4, 0x2F, 0x40, 0xF2, 0x01, 0xCC, 0x13, 0xF0, 0x12, 0x44, ++0x7A, 0x20, 0x33, 0xCC, 0xEC, 0x06, 0x90, 0x1F, 0x40, 0x0E, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x77, 0x00, 0xDD, 0x01, 0x74, 0x26, 0xD0, ++0x1D, 0x40, 0xBF, 0x05, 0x1D, 0x02, 0x74, 0x38, 0x10, 0xC1, 0x40, 0xBF, 0x00, ++0xDD, 0x00, 0x64, 0x2C, 0x04, 0x4D, 0x40, 0xBF, 0x08, 0x11, 0x14, 0x74, 0x40, ++0x10, 0x6F, 0x40, 0xE7, 0x00, 0xD5, 0x01, 0xC4, 0x0F, 0xD0, 0x19, 0x40, 0x74, ++0x00, 0x01, 0x22, 0x44, 0x06, 0x12, 0x1D, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0xA0, 0x31, 0x00, 0xCD, 0x00, 0x34, 0x80, 0xD8, 0x0C, ++0x40, 0xB3, 0x00, 0x8D, 0x26, 0x34, 0x02, 0x10, 0x00, 0x41, 0x33, 0x11, 0xCD, ++0x80, 0x24, 0x02, 0x00, 0x0C, 0x40, 0x31, 0x83, 0x81, 0x8C, 0x04, 0xB2, 0x12, ++0x2C, 0x60, 0x03, 0x42, 0xD5, 0x00, 0x14, 0x23, 0xD0, 0x08, 0x40, 0x33, 0x00, ++0x45, 0x26, 0x64, 0x01, 0x90, 0x0C, 0x40, 0x4E, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x28, 0x35, 0x00, 0xDD, 0x00, 0x74, 0x04, 0xD0, 0x0D, 0x44, ++0x37, 0x00, 0x9D, 0x01, 0x74, 0x04, 0x10, 0x11, 0x44, 0x37, 0x00, 0xDD, 0x00, ++0x66, 0x84, 0x10, 0x0D, 0x40, 0x37, 0x00, 0x91, 0x01, 0x74, 0x06, 0x18, 0x0D, ++0x40, 0x47, 0x00, 0x55, 0x11, 0x54, 0x03, 0xD0, 0x19, 0x43, 0x37, 0x80, 0x11, ++0x18, 0x44, 0x0E, 0x10, 0x0D, 0x42, 0x0C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x20, 0xA8, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x1E, 0xF0, 0x0D, 0xC0, 0x37, ++0x00, 0x9F, 0x87, 0x7C, 0xC4, 0x30, 0x19, 0xC2, 0x37, 0x18, 0xDF, 0x00, 0x6C, ++0x04, 0x30, 0x0D, 0xC4, 0x35, 0x08, 0x13, 0x01, 0x4C, 0x1E, 0x34, 0x0D, 0xC2, ++0x67, 0x40, 0xD7, 0x01, 0x5C, 0x03, 0xF0, 0x19, 0xC0, 0x37, 0x00, 0x95, 0x02, ++0x2C, 0x0E, 0xB0, 0x0D, 0xC0, 0x22, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x07, 0x80, 0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x82, 0xF0, 0x0F, 0xC0, 0x3F, 0x90, ++0x3F, 0x90, 0xBC, 0x00, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xFF, 0x03, 0x9C, 0x40, ++0x70, 0x0F, 0xC0, 0x37, 0x40, 0x3F, 0x40, 0xFC, 0x00, 0x70, 0x0F, 0xC0, 0x2F, ++0x00, 0xBF, 0x00, 0xEC, 0x03, 0xF0, 0x0B, 0xC0, 0x3C, 0x0C, 0x2F, 0x01, 0xFC, ++0x02, 0xF0, 0x0F, 0xC0, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x08, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0x93, ++0x02, 0x7C, 0x0A, 0x30, 0x01, 0xC0, 0x34, 0x40, 0xD3, 0x04, 0x4E, 0x02, 0xF1, ++0x0D, 0xC0, 0x30, 0x00, 0x13, 0x08, 0x7C, 0x0A, 0xF0, 0x0D, 0xC0, 0x24, 0x00, ++0xD3, 0x22, 0x7C, 0x03, 0x30, 0x29, 0xC0, 0x34, 0x00, 0x13, 0x02, 0x4C, 0x0D, ++0xF0, 0x0D, 0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xA0, ++0x34, 0x00, 0xDD, 0x00, 0x74, 0x12, 0xD1, 0x0D, 0x00, 0x3F, 0x00, 0x91, 0x80, ++0x74, 0x00, 0x10, 0x01, 0x40, 0x3C, 0x24, 0xDB, 0x02, 0x66, 0x4A, 0xD0, 0x0D, ++0x48, 0xBC, 0x42, 0x1B, 0x8B, 0x74, 0x02, 0xF0, 0x3F, 0xC1, 0x62, 0x01, 0x8A, ++0x04, 0xF0, 0x03, 0xB1, 0xA8, 0x40, 0x30, 0x00, 0x1B, 0x0E, 0x44, 0x0F, 0xD0, ++0x0C, 0x40, 0x6F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x32, ++0x00, 0xCD, 0x00, 0x34, 0x00, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x01, 0x00, 0x34, ++0x02, 0x10, 0x08, 0x40, 0xF0, 0x09, 0xD1, 0x81, 0x24, 0x0E, 0xD0, 0x0C, 0x48, ++0x70, 0x00, 0x89, 0x03, 0x74, 0x00, 0xD0, 0x6C, 0x42, 0x02, 0x01, 0xC5, 0x30, ++0x20, 0x07, 0x00, 0xBC, 0x40, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0xD0, 0x0C, ++0x40, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x80, 0x78, 0x00, ++0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0x61, 0x11, 0xB4, 0x07, ++0x10, 0x16, 0x40, 0x78, 0x00, 0xE1, 0x01, 0xA4, 0x25, 0xD0, 0x1E, 0x40, 0x78, ++0x00, 0x61, 0x01, 0xB4, 0x05, 0x50, 0x1E, 0x40, 0x7A, 0x00, 0xED, 0x01, 0xB4, ++0x07, 0x90, 0x0F, 0x40, 0x78, 0x04, 0xE9, 0x01, 0x84, 0x0E, 0xD0, 0x1E, 0x40, ++0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xCF, ++0x00, 0x3C, 0x01, 0xD0, 0x8C, 0xC0, 0x37, 0x00, 0x43, 0x00, 0x7C, 0x03, 0x10, ++0x8D, 0xD0, 0x34, 0x22, 0xC1, 0x90, 0x04, 0x2B, 0xD8, 0x0D, 0xD0, 0x30, 0x06, ++0xC9, 0x00, 0x3C, 0x01, 0xD0, 0x4D, 0xC0, 0x12, 0x00, 0xC3, 0x04, 0x2C, 0x53, ++0x30, 0x8C, 0x80, 0x30, 0x00, 0xC3, 0xE4, 0x0C, 0x83, 0xF0, 0x0C, 0xC0, 0x4B, ++0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x3D, 0x00, 0xFF, 0x00, ++0xFC, 0x01, 0xF0, 0x0F, 0xC0, 0x3F, 0x40, 0xFF, 0x00, 0xFC, 0x03, 0xF4, 0x8F, ++0xC0, 0x3F, 0x02, 0xFF, 0x00, 0x5D, 0xA1, 0xF8, 0x0F, 0xC0, 0xBF, 0x00, 0xFF, ++0x80, 0xFC, 0x03, 0xF0, 0x0F, 0xC1, 0x1B, 0x02, 0xFB, 0x00, 0xB0, 0x4B, 0xF0, ++0xCF, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x0B, 0x60, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x80, 0xDF, 0x00, 0x7C, ++0x01, 0x70, 0x0D, 0xC4, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x05, 0x30, 0x0D, 0xC2, ++0xB5, 0x02, 0xCF, 0x00, 0x5D, 0x03, 0x38, 0x1D, 0xC0, 0x35, 0x01, 0xDF, 0x00, ++0x7C, 0x03, 0xF0, 0x6D, 0xC0, 0x10, 0x00, 0xC3, 0x00, 0x6C, 0x13, 0xF0, 0x09, ++0xC0, 0x37, 0xA0, 0xDF, 0x00, 0x4C, 0x03, 0xD0, 0x0C, 0xC0, 0x42, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x88, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x03, ++0xD0, 0x0E, 0x00, 0x3B, 0x13, 0x6C, 0x00, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x3B, ++0x04, 0xED, 0x00, 0x94, 0x03, 0x41, 0x0E, 0x40, 0x38, 0x00, 0xED, 0x00, 0xB4, ++0x01, 0xD0, 0x8F, 0xC0, 0x3A, 0x00, 0xE5, 0x00, 0x84, 0x03, 0xD0, 0x0A, 0x42, ++0x3B, 0x80, 0xCD, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x4C, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x79, 0x88, 0xE5, 0x21, 0xB4, 0x47, 0xD0, ++0x1E, 0x44, 0x7B, 0x12, 0xEC, 0x01, 0x34, 0x07, 0x90, 0x1E, 0x40, 0x7B, 0x01, ++0xED, 0x21, 0x14, 0x07, 0x01, 0x1E, 0x4C, 0x79, 0x02, 0xED, 0x01, 0xB4, 0x07, ++0xD8, 0x5F, 0x40, 0x78, 0x00, 0xF5, 0x11, 0xB4, 0x17, 0xD0, 0x3A, 0x40, 0x7B, ++0x00, 0xED, 0x21, 0x84, 0x47, 0xD0, 0x1E, 0x48, 0x12, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x36, 0x0F, 0xD0, 0x0C, ++0x40, 0x33, 0x00, 0xCD, 0x01, 0x34, 0x03, 0x10, 0x9C, 0x40, 0x33, 0x00, 0x8D, ++0xA0, 0x15, 0x07, 0x10, 0x0C, 0x40, 0x30, 0x10, 0xDD, 0x03, 0x34, 0x07, 0xD0, ++0x0C, 0x40, 0xF2, 0x00, 0xC5, 0x01, 0x14, 0x03, 0xD0, 0x08, 0x40, 0x33, 0x80, ++0xDD, 0x0D, 0x04, 0x07, 0xD0, 0x0C, 0x40, 0x5A, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x17, 0xA8, 0x15, 0x08, 0x5F, 0x00, 0xFC, 0x01, 0xF0, 0x05, 0xC0, ++0x17, 0x00, 0x7F, 0x0E, 0xF4, 0x01, 0xB0, 0xA7, 0xC2, 0x15, 0x08, 0x4F, 0x05, ++0xDC, 0x1D, 0x35, 0x05, 0xC4, 0x15, 0x00, 0x7F, 0x85, 0xFC, 0xED, 0xF0, 0x05, ++0xC0, 0x1C, 0x81, 0x77, 0x01, 0x7C, 0x01, 0xF1, 0x06, 0xC0, 0x17, 0x08, 0x7D, ++0x02, 0xCD, 0x05, 0xF0, 0x04, 0xC0, 0x5E, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x40, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x1F, 0x02, 0x78, 0x04, 0x74, 0x01, 0x00, 0x07, 0x00, 0x1E, 0x00, 0x7D, ++0x40, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x06, 0x7C, 0x00, 0xC0, 0x00, 0xC0, ++0x87, 0x81, 0x1F, 0x10, 0x64, 0x08, 0xF2, 0x21, 0xC1, 0x87, 0x20, 0x1F, 0x02, ++0x7D, 0x08, 0xF0, 0x01, 0xC0, 0x49, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x08, 0x27, 0x00, 0x9F, 0x00, 0x3C, 0x02, 0x30, 0x09, 0xE0, 0x27, 0x00, ++0x83, 0x00, 0x4C, 0x02, 0xF0, 0x09, 0xC8, 0x26, 0x02, 0x9F, 0x04, 0x0C, 0x02, ++0x34, 0x09, 0xC0, 0x27, 0x01, 0x9C, 0x08, 0x0C, 0x02, 0x30, 0x59, 0xC0, 0xA0, ++0x20, 0x93, 0x00, 0x5C, 0x86, 0xF0, 0x19, 0xC0, 0xA4, 0x00, 0x9F, 0x00, 0x4C, ++0x06, 0xF0, 0x09, 0xD0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x20, 0x26, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x14, 0x09, 0x40, 0x27, 0x00, 0x91, ++0x00, 0x45, 0x02, 0xD0, 0x09, 0xD0, 0xA4, 0x00, 0x9D, 0x02, 0x6C, 0x42, 0x50, ++0x09, 0x40, 0x27, 0x21, 0x9D, 0x02, 0x45, 0x02, 0x14, 0x29, 0x50, 0xE4, 0x40, ++0x81, 0x13, 0x44, 0x86, 0xD0, 0x89, 0x40, 0x64, 0x08, 0x9D, 0x02, 0x44, 0x1A, ++0xD0, 0x19, 0x40, 0x04, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, ++0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x23, 0x00, 0x91, 0x08, ++0x44, 0x02, 0xD9, 0x0C, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x65, 0x22, 0x92, 0x09, ++0x44, 0x27, 0x00, 0xDD, 0x02, 0x56, 0x02, 0x50, 0x09, 0x48, 0x34, 0x04, 0x91, ++0xA4, 0x54, 0x2A, 0xD1, 0x29, 0x50, 0xA6, 0x00, 0x9D, 0x0A, 0x64, 0x22, 0xD0, ++0x89, 0x60, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, ++0x00, 0x8D, 0x00, 0x34, 0x12, 0x10, 0x08, 0x40, 0x23, 0x31, 0x81, 0x04, 0x04, ++0x12, 0xD8, 0x48, 0x4C, 0x20, 0x01, 0x8D, 0x01, 0x24, 0x12, 0x90, 0x08, 0x40, ++0x23, 0x21, 0x8D, 0x24, 0x16, 0x12, 0x50, 0x4C, 0x04, 0x20, 0x01, 0x90, 0x20, ++0x00, 0x12, 0xD0, 0x08, 0x40, 0x22, 0x00, 0x8D, 0x08, 0x24, 0x02, 0xD0, 0x08, ++0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, ++0x1F, 0x00, 0x74, 0x00, 0x30, 0x01, 0x40, 0x87, 0x0A, 0x53, 0x0A, 0x4C, 0x28, ++0xF0, 0xA1, 0xC2, 0x94, 0x02, 0x1F, 0x0A, 0x6C, 0x00, 0x30, 0xA0, 0xC0, 0x87, ++0x02, 0x1F, 0x0A, 0x5C, 0x28, 0x70, 0xA1, 0x80, 0x04, 0x10, 0x12, 0x00, 0x5C, ++0x00, 0xF0, 0x01, 0xC0, 0x06, 0x00, 0x1D, 0x36, 0x6D, 0x00, 0xF0, 0x01, 0xC0, ++0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x27, 0x00, 0x9F, ++0x00, 0xFC, 0x23, 0xF0, 0x09, 0xC0, 0x27, 0x42, 0xBF, 0x08, 0xFC, 0x22, 0xF0, ++0x8B, 0x40, 0x27, 0x02, 0xBF, 0x20, 0xFD, 0x22, 0x70, 0x09, 0xC0, 0x27, 0x02, ++0xBF, 0x08, 0xE8, 0x22, 0xB0, 0x89, 0xC0, 0x2F, 0x02, 0xBF, 0x00, 0x7C, 0x22, ++0xF3, 0x0B, 0xC0, 0x25, 0x00, 0xBF, 0x04, 0xDC, 0x02, 0xF0, 0x09, 0xC0, 0x77, ++0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x27, 0x00, 0x9F, 0x20, ++0xFC, 0x16, 0x30, 0x09, 0xC0, 0xE7, 0x20, 0xBF, 0x21, 0x6C, 0x13, 0xF0, 0xD9, ++0xC6, 0xEF, 0x08, 0xB3, 0x02, 0xCC, 0x16, 0xF0, 0x09, 0xC0, 0x6F, 0x04, 0xB3, ++0x07, 0x4C, 0x1E, 0xF0, 0x5B, 0xC0, 0x68, 0x00, 0xB3, 0x00, 0xFC, 0x12, 0x34, ++0x0B, 0xC2, 0x2F, 0x20, 0xBF, 0x00, 0xC4, 0x02, 0xB4, 0x0B, 0xC0, 0x77, 0x80, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, 0x1D, 0x00, 0x74, ++0x28, 0x10, 0x01, 0x4C, 0x47, 0x08, 0x1C, 0x17, 0x45, 0x51, 0xD0, 0xF5, 0x40, ++0xC7, 0x40, 0x11, 0x05, 0x54, 0x08, 0x70, 0x51, 0x41, 0x47, 0x40, 0x11, 0x03, ++0x45, 0x0D, 0xD0, 0x71, 0x51, 0x84, 0x40, 0x15, 0x00, 0x74, 0x00, 0x11, 0x01, ++0x40, 0x07, 0x00, 0x1D, 0x20, 0x44, 0x01, 0x10, 0x01, 0x40, 0x62, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, 0x23, 0x00, 0x8D, 0x00, 0x34, 0x03, ++0x10, 0x08, 0x40, 0xA3, 0x01, 0x8D, 0x02, 0x04, 0xB2, 0xD0, 0x08, 0x40, 0xA3, ++0x01, 0x81, 0x00, 0x25, 0x0E, 0xC1, 0x08, 0x40, 0x21, 0x04, 0x81, 0x07, 0x24, ++0x32, 0x50, 0x88, 0x40, 0xA2, 0x20, 0x81, 0x40, 0x34, 0x22, 0x50, 0x08, 0x40, ++0x23, 0x00, 0x8D, 0x00, 0x46, 0x03, 0xD1, 0x08, 0x40, 0x4B, 0x80, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x9D, 0x00, 0x74, 0x22, 0x10, ++0x09, 0x40, 0x27, 0x00, 0x9D, 0x14, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x37, 0x00, ++0x91, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x27, 0x80, 0x91, 0x40, 0x64, 0x12, ++0xD8, 0x09, 0x60, 0x26, 0x01, 0x95, 0x02, 0x64, 0x02, 0x58, 0x0D, 0x40, 0x27, ++0x00, 0xDD, 0x04, 0x44, 0x02, 0x50, 0x09, 0x40, 0x62, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0x28, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x0A, 0x34, 0x09, ++0xC0, 0x27, 0x08, 0x9F, 0x42, 0x4C, 0x02, 0xF0, 0x29, 0xC0, 0x27, 0x20, 0x91, ++0x08, 0x6D, 0x0A, 0xF0, 0x09, 0xC0, 0x25, 0x20, 0x93, 0x00, 0x6C, 0x06, 0x70, ++0x09, 0x42, 0xA6, 0xA1, 0x93, 0x22, 0x74, 0x02, 0x78, 0x09, 0xC1, 0x27, 0x00, ++0x9F, 0x06, 0x4D, 0x02, 0xF4, 0x09, 0xC0, 0x17, 0x80, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x00, 0x25, 0x08, 0x9F, 0x00, 0x3C, 0x02, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x80, 0x7C, 0x22, 0xF0, 0x99, 0xC0, 0x27, 0x00, 0x9F, 0x11, ++0x5C, 0x16, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x8F, 0x13, 0x5C, 0x06, 0xF0, 0x09, ++0xC0, 0x65, 0x80, 0x9F, 0x00, 0x7C, 0x02, 0xB0, 0x09, 0xC1, 0x27, 0x00, 0x9F, ++0x01, 0x7E, 0x22, 0xB4, 0x09, 0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF8, 0x01, 0xC0, 0x07, ++0x80, 0x13, 0x06, 0x7C, 0x08, 0xF0, 0x01, 0xC0, 0x47, 0x80, 0x1F, 0x00, 0x4C, ++0x00, 0x70, 0x01, 0xC0, 0x47, 0x10, 0x1F, 0x00, 0x7C, 0x08, 0x34, 0x11, 0xC0, ++0x87, 0x04, 0x13, 0x26, 0x2C, 0x10, 0xF0, 0x01, 0xC0, 0x05, 0x00, 0x1F, 0x04, ++0x7C, 0x48, 0x30, 0x81, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x20, 0x14, 0x00, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x40, 0x17, 0xC0, ++0x70, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x00, 0x5F, 0x80, 0x6F, 0x46, 0xC5, 0x05, ++0x70, 0x05, 0x40, 0x1F, 0x00, 0x7D, 0x81, 0x74, 0x01, 0x30, 0x47, 0x40, 0x1B, ++0x00, 0x71, 0x03, 0xCC, 0x09, 0x60, 0x37, 0x40, 0x1C, 0xA0, 0x7D, 0x02, 0xB4, ++0x09, 0x10, 0x05, 0x40, 0x43, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0x31, 0x10, 0xD1, ++0x03, 0x34, 0x03, 0xD2, 0x0C, 0x48, 0x77, 0x0A, 0xCD, 0x03, 0x04, 0x07, 0xD3, ++0x0C, 0x44, 0x37, 0x00, 0xCD, 0x08, 0x36, 0x03, 0x10, 0x1D, 0x40, 0xB1, 0x60, ++0x01, 0x02, 0x04, 0x23, 0xD0, 0x3C, 0x40, 0x81, 0x04, 0xDD, 0x80, 0x34, 0x0B, ++0x04, 0x1C, 0x60, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, ++0x38, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x7B, 0x00, 0xE1, 0x02, ++0xB6, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xE5, 0x80, 0x85, 0x08, 0x50, 0x0E, ++0x60, 0x9B, 0x00, 0x6D, 0x40, 0x36, 0x07, 0x18, 0x0E, 0x40, 0x3B, 0x40, 0x21, ++0x10, 0x86, 0x03, 0x50, 0x17, 0x49, 0x08, 0x00, 0xAD, 0x02, 0xB6, 0x03, 0x10, ++0x0E, 0x60, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x78, ++0x00, 0xEF, 0x01, 0xBC, 0x06, 0xD0, 0x1E, 0xC2, 0x71, 0x02, 0x61, 0x01, 0xBC, ++0x3F, 0xF0, 0xFE, 0xC0, 0x5B, 0x00, 0xED, 0x01, 0x8D, 0x05, 0x78, 0x3E, 0x41, ++0x7B, 0x00, 0xED, 0x01, 0xBC, 0x07, 0x30, 0x1E, 0xC2, 0x69, 0x00, 0x63, 0xA0, ++0x8C, 0x07, 0xD1, 0x12, 0xC0, 0x49, 0x00, 0xED, 0x81, 0xBC, 0x06, 0x38, 0x1E, ++0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB0, 0x35, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0xB7, 0x00, 0x5F, 0x00, 0x7C, 0x03, ++0xC0, 0x0D, 0x40, 0x17, 0x00, 0xCF, 0x00, 0x7C, 0x00, 0xF1, 0x2D, 0xC0, 0x37, ++0x20, 0x5F, 0x80, 0x7C, 0xB3, 0xC0, 0x0D, 0xC8, 0x27, 0x00, 0x4F, 0x00, 0x7C, ++0x03, 0xF0, 0x04, 0xC0, 0x17, 0x00, 0x9D, 0x00, 0x3C, 0x00, 0xF1, 0x0D, 0xC8, ++0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x7F, 0x00, 0xFF, ++0x01, 0xFC, 0x13, 0xF8, 0x8F, 0xC0, 0x7F, 0x04, 0xF7, 0x09, 0xCC, 0x87, 0xF0, ++0x1F, 0xC0, 0x7C, 0x00, 0xEB, 0x01, 0xEC, 0x07, 0xF9, 0x9F, 0xC0, 0x7F, 0x00, ++0xFF, 0x09, 0xCC, 0x0F, 0xB1, 0x1F, 0xC0, 0x3B, 0x00, 0x33, 0x01, 0xEE, 0x27, ++0x30, 0x17, 0xC0, 0x4F, 0x00, 0x7F, 0x81, 0xCC, 0x05, 0xC0, 0x9A, 0xC0, 0x1A, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x39, 0x00, 0xED, 0x08, ++0xB4, 0x23, 0xD0, 0x0E, 0x48, 0x3B, 0x01, 0xED, 0x00, 0x84, 0x03, 0xD1, 0x0E, ++0x4E, 0x38, 0x40, 0xE1, 0x00, 0x84, 0x00, 0x78, 0x0E, 0x40, 0x1B, 0x08, 0xFD, ++0x00, 0x84, 0x13, 0x10, 0x0E, 0x42, 0x3B, 0x03, 0xA1, 0x80, 0xBC, 0x03, 0x14, ++0x06, 0x40, 0x0B, 0x08, 0x2D, 0x98, 0x84, 0x20, 0x90, 0x0A, 0x40, 0x54, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0xED, 0x00, 0xB4, ++0x0B, 0xD0, 0x8E, 0x40, 0x3B, 0x28, 0xED, 0x00, 0xA4, 0x03, 0xD0, 0x0E, 0x40, ++0x1A, 0x00, 0xE1, 0x00, 0x84, 0x41, 0xD0, 0x0E, 0x44, 0x1B, 0x00, 0xED, 0x90, ++0xA4, 0xC3, 0x18, 0x86, 0x40, 0xAB, 0x0A, 0x61, 0x08, 0xA4, 0x01, 0x54, 0x06, ++0x40, 0x0B, 0x00, 0x6D, 0x00, 0x84, 0x40, 0xD0, 0x0E, 0x40, 0x22, 0x01, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, ++0xD0, 0x0C, 0x00, 0x33, 0x10, 0x9D, 0x0B, 0x24, 0x2F, 0xD0, 0x1C, 0x5A, 0x02, ++0x00, 0xC1, 0x40, 0x05, 0x01, 0x50, 0x0C, 0x40, 0x07, 0x00, 0x8D, 0x02, 0x24, ++0x07, 0x1A, 0x08, 0x40, 0x63, 0xC0, 0x41, 0x00, 0x14, 0x01, 0x50, 0x24, 0x40, ++0x13, 0x20, 0x0D, 0x03, 0x05, 0x0C, 0x90, 0x0C, 0x40, 0x08, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, 0xDF, 0x00, 0x3C, 0x42, 0xD0, ++0x0D, 0xC0, 0x3F, 0x00, 0x9F, 0x00, 0xEC, 0x03, 0xF0, 0x1F, 0xC0, 0x26, 0x00, ++0xC1, 0x00, 0x4C, 0x23, 0xF0, 0x0F, 0xC0, 0x27, 0x00, 0x9F, 0x01, 0xEC, 0x0F, ++0x14, 0x01, 0xE2, 0x77, 0x04, 0x13, 0x02, 0x64, 0x03, 0x50, 0xA5, 0x40, 0x07, ++0x00, 0xDF, 0x03, 0x4C, 0x0F, 0xD0, 0x0D, 0xC2, 0x56, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xDD, 0x00, 0x7C, 0x03, 0xF1, 0x0D, ++0x40, 0x37, 0x20, 0x9F, 0x10, 0x5C, 0x03, 0xF0, 0xCD, 0xC0, 0xA1, 0x10, 0x97, ++0x01, 0x7D, 0x00, 0x70, 0x0D, 0xC0, 0x87, 0x00, 0x1F, 0x04, 0x5C, 0x43, 0x72, ++0x21, 0xE0, 0xA7, 0x80, 0x1F, 0x28, 0x74, 0x03, 0xA0, 0x05, 0xC0, 0x07, 0x00, ++0x9D, 0x04, 0x7C, 0x0B, 0xB0, 0x0D, 0xC0, 0xB7, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0xFF, 0x20, 0xFC, 0x02, 0xB0, 0x0F, 0xE0, ++0x3B, 0xA0, 0x1B, 0x00, 0xCE, 0x43, 0x30, 0x0C, 0xC0, 0x24, 0x00, 0xFB, 0x00, ++0xAC, 0x01, 0xB0, 0x0F, 0xC0, 0x2F, 0x00, 0xA3, 0x00, 0xCC, 0x03, 0xF0, 0x0A, ++0xC0, 0x28, 0x10, 0x73, 0x59, 0x8C, 0x03, 0x32, 0x47, 0xC0, 0x0C, 0x00, 0xED, ++0x02, 0xCC, 0x47, 0x30, 0x0F, 0xC0, 0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x20, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x03, 0x90, 0x0D, 0x40, 0x37, ++0x98, 0x11, 0x01, 0x44, 0x03, 0x10, 0x0D, 0x42, 0x64, 0x08, 0xD1, 0x01, 0x6C, ++0x04, 0xB0, 0x0D, 0xC2, 0xE7, 0x04, 0x11, 0x01, 0x44, 0x03, 0xD0, 0x39, 0x44, ++0x64, 0x01, 0x41, 0x01, 0x6C, 0x07, 0x10, 0x24, 0x40, 0x84, 0x02, 0x1D, 0x00, ++0x05, 0x01, 0x10, 0x0D, 0x4E, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0xA0, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x03, 0x90, 0x0D, 0x48, 0x37, 0x20, ++0x11, 0x01, 0x04, 0x03, 0x10, 0x0D, 0x60, 0x44, 0x00, 0xD1, 0x11, 0x64, 0x07, ++0x92, 0x0D, 0x42, 0x67, 0x80, 0x11, 0x01, 0x64, 0x83, 0x50, 0x11, 0x41, 0x56, ++0x00, 0x19, 0x00, 0x46, 0x07, 0x10, 0x05, 0x40, 0x04, 0x04, 0x5D, 0x00, 0x44, ++0x1B, 0x14, 0x09, 0x40, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x30, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x90, 0x0C, 0x40, 0x33, 0x00, 0x81, ++0x01, 0x04, 0x03, 0x14, 0x0C, 0x60, 0x20, 0x20, 0xC1, 0x00, 0x24, 0x00, 0x92, ++0x0C, 0x60, 0x01, 0x90, 0x01, 0x01, 0x24, 0x03, 0xD0, 0x00, 0x42, 0x22, 0x00, ++0xCD, 0x00, 0x24, 0x03, 0x14, 0x04, 0x40, 0x20, 0x00, 0xCD, 0x00, 0x04, 0x02, ++0x10, 0x08, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x36, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xB0, 0x0D, 0x40, 0x3F, 0x00, 0x11, 0x20, ++0xC4, 0x03, 0x30, 0x0F, 0xC0, 0x04, 0x20, 0xDB, 0x00, 0x6D, 0x01, 0xB1, 0x0F, ++0x40, 0x27, 0x18, 0x93, 0x00, 0xAC, 0x03, 0x70, 0x01, 0xC0, 0x26, 0x00, 0x5B, ++0x00, 0x4C, 0x01, 0x30, 0x05, 0xE0, 0x04, 0x00, 0x0F, 0x00, 0x4C, 0x03, 0x30, ++0x0D, 0xC2, 0x07, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x3F, ++0x00, 0xFF, 0x00, 0xFC, 0x03, 0x78, 0x0F, 0xC0, 0x3F, 0x10, 0xB7, 0x00, 0xFC, ++0x03, 0xF0, 0x0F, 0xC0, 0x2F, 0x10, 0x7F, 0x00, 0xFC, 0x00, 0x70, 0x0F, 0xC0, ++0x2F, 0x00, 0xBF, 0x00, 0xDC, 0x03, 0xF0, 0x0B, 0xC0, 0x2D, 0x00, 0x73, 0x00, ++0xBC, 0x00, 0xF0, 0x07, 0x00, 0x0F, 0x08, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x0F, ++0xC0, 0x17, 0x61, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7B, 0x00, ++0x33, 0x00, 0xCC, 0x03, 0x30, 0x0B, 0xC0, 0x2F, 0x00, 0xA3, 0x00, 0x8C, 0x06, ++0xB0, 0x03, 0xC0, 0x68, 0x02, 0x3F, 0x01, 0x8C, 0x04, 0x70, 0x1B, 0xC0, 0x3F, ++0x00, 0x33, 0x0C, 0xCC, 0x04, 0xB0, 0x2B, 0x10, 0x4C, 0x00, 0xF3, 0x01, 0xCC, ++0x02, 0x30, 0x0B, 0xD0, 0x4C, 0x00, 0xB3, 0x00, 0xCC, 0x07, 0xF0, 0x0F, 0xC0, ++0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x14, 0x11, ++0x00, 0xC4, 0x03, 0x11, 0x49, 0x40, 0x6F, 0x00, 0x91, 0x0B, 0x44, 0x84, 0x50, ++0x01, 0x40, 0x24, 0x21, 0x1D, 0x21, 0x44, 0x84, 0x10, 0x19, 0x40, 0x3F, 0x04, ++0x11, 0x02, 0x44, 0x04, 0x10, 0x2F, 0x42, 0x24, 0x10, 0xD1, 0x20, 0x44, 0x02, ++0x10, 0x0C, 0x41, 0x44, 0x00, 0x8B, 0x00, 0x54, 0x07, 0xD0, 0x1D, 0x40, 0x0C, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x37, 0x21, 0x00, 0x00, ++0x04, 0x03, 0x10, 0x08, 0x41, 0x23, 0x00, 0xC1, 0x00, 0x44, 0x02, 0x10, 0x00, ++0x40, 0x20, 0x10, 0x1D, 0x00, 0x05, 0x00, 0x52, 0x08, 0x42, 0x33, 0x82, 0x81, ++0x02, 0x04, 0x00, 0x12, 0x68, 0x60, 0x00, 0x00, 0xD1, 0x40, 0x04, 0x06, 0x50, ++0x58, 0x40, 0x00, 0x00, 0xC1, 0x00, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x4E, 0x80, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x08, 0x51, 0x01, 0x44, ++0x03, 0x10, 0x09, 0x40, 0x67, 0x40, 0xD1, 0x00, 0x45, 0x00, 0x50, 0x11, 0x50, ++0x34, 0x00, 0x1D, 0x01, 0x44, 0x44, 0x11, 0x19, 0x41, 0x37, 0x00, 0x91, 0x00, ++0x40, 0x04, 0x18, 0x0C, 0x60, 0x40, 0x40, 0xD1, 0x04, 0x44, 0x06, 0x50, 0x41, ++0x40, 0x44, 0x20, 0xD9, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0x0E, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x73, 0x00, 0x13, 0x13, 0x4D, 0x03, ++0x34, 0x01, 0xC0, 0x67, 0x00, 0x93, 0x00, 0x4C, 0x03, 0x30, 0x39, 0xC8, 0x24, ++0x10, 0x0F, 0x03, 0x4C, 0x0C, 0x70, 0x19, 0xC8, 0x37, 0x40, 0x13, 0x04, 0x4C, ++0x18, 0x34, 0x09, 0xC0, 0xE4, 0x00, 0xC3, 0x00, 0x4D, 0x06, 0x70, 0x1D, 0xC0, ++0xC4, 0x00, 0x93, 0x01, 0x6C, 0x03, 0xF0, 0x4D, 0xD0, 0x02, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0xFD, 0x40, 0x2F, 0x00, 0xBC, 0x03, 0xF1, ++0x93, 0xC0, 0x37, 0x00, 0xAF, 0x02, 0xFC, 0x02, 0x70, 0x0D, 0xC0, 0x2F, 0x00, ++0x3F, 0x10, 0xFC, 0x80, 0xF0, 0x03, 0xC8, 0x3F, 0x20, 0x3F, 0x23, 0xFC, 0x00, ++0x70, 0x9D, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xB4, 0x1F, 0xC0, 0x0F, ++0x00, 0xAF, 0x09, 0xDC, 0x03, 0xF0, 0x01, 0xC0, 0x1D, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x08, 0x25, 0x00, 0x53, 0x00, 0x6D, 0x03, 0x32, 0x09, ++0xD0, 0x24, 0x00, 0xD3, 0x80, 0x4C, 0x03, 0x34, 0x6D, 0xC0, 0x24, 0x00, 0x13, ++0x42, 0x7C, 0x10, 0x30, 0x29, 0xD1, 0x30, 0x00, 0x83, 0x00, 0x4C, 0x18, 0x30, ++0x09, 0xC0, 0x84, 0x00, 0xD3, 0x00, 0x3C, 0x02, 0xB0, 0x11, 0xC0, 0x04, 0x00, ++0xDB, 0x00, 0x4D, 0x03, 0xF0, 0x0C, 0xC0, 0xA8, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0xA0, 0x24, 0x00, 0xD1, 0x00, 0xC4, 0x43, 0x10, 0x09, 0x40, ++0x10, 0x00, 0xD1, 0x00, 0x04, 0x46, 0x10, 0x2D, 0x50, 0x34, 0x00, 0x13, 0x82, ++0x34, 0x08, 0x10, 0x79, 0x40, 0x7C, 0x04, 0xB5, 0x20, 0x2C, 0x0C, 0xB2, 0xAD, ++0x40, 0xC4, 0x06, 0xD1, 0x01, 0x74, 0x2A, 0x10, 0x08, 0x40, 0x40, 0x00, 0xDB, ++0x00, 0x44, 0x03, 0xD0, 0x01, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x20, 0x30, 0x40, 0x81, 0x21, 0x04, 0x03, 0x14, 0x08, 0x08, 0x20, ++0x89, 0x81, 0x00, 0x06, 0x06, 0x10, 0x01, 0x40, 0x20, 0x00, 0x08, 0x03, 0x34, ++0x0C, 0x18, 0x08, 0x40, 0x70, 0x00, 0x09, 0x00, 0x14, 0x2C, 0x94, 0x8C, 0x40, ++0x02, 0x00, 0xC1, 0x41, 0x34, 0x02, 0x90, 0x0C, 0x40, 0x52, 0x40, 0xC9, 0x00, ++0x05, 0x03, 0xD0, 0x0C, 0x40, 0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x00, 0x7C, 0x40, 0xF1, 0x19, 0x04, 0x07, 0x10, 0x18, 0x40, 0x68, 0x00, ++0xB1, 0x81, 0xC6, 0x04, 0x10, 0x96, 0x40, 0x6C, 0x40, 0x21, 0x21, 0xB4, 0x44, ++0x18, 0x16, 0x62, 0x78, 0x10, 0x0D, 0x01, 0xB4, 0x04, 0x94, 0x1E, 0x40, 0x6A, ++0x00, 0xE1, 0x50, 0x36, 0x06, 0x10, 0x3E, 0x50, 0x4E, 0x04, 0xE9, 0x01, 0x86, ++0x07, 0xD0, 0x16, 0x60, 0x3C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x18, 0x30, 0x00, 0x83, 0x08, 0x0D, 0x03, 0x10, 0x08, 0xC0, 0x20, 0x40, 0xC3, ++0x00, 0x0D, 0x22, 0x30, 0x04, 0x48, 0x20, 0xB2, 0x09, 0x52, 0x3C, 0x20, 0x34, ++0x88, 0xC0, 0x30, 0x00, 0x0B, 0x00, 0x1C, 0x00, 0x90, 0x0C, 0xC0, 0x86, 0x00, ++0xC3, 0x00, 0x3C, 0x02, 0xB0, 0x00, 0xC0, 0x92, 0x10, 0xCB, 0x04, 0x0C, 0x03, ++0xF0, 0x0C, 0xD0, 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, ++0x3D, 0x00, 0xEF, 0x68, 0xFE, 0x0B, 0xF0, 0x0F, 0xC0, 0xBF, 0x00, 0xFF, 0x00, ++0xFC, 0x00, 0xF0, 0x07, 0xC0, 0x3F, 0x20, 0xBF, 0x00, 0xFC, 0x20, 0xF0, 0x8E, ++0xC0, 0x3B, 0x00, 0xB7, 0x80, 0xAD, 0x22, 0xF0, 0x8F, 0xC0, 0x2D, 0x40, 0xFF, ++0x04, 0xFC, 0x02, 0xE0, 0x0B, 0xE0, 0x09, 0x40, 0xFF, 0x00, 0xFC, 0x03, 0xF0, ++0x07, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, ++0x00, 0xD7, 0x60, 0x4C, 0x0B, 0x34, 0x01, 0xC0, 0x6F, 0x00, 0x97, 0x00, 0x7C, ++0x03, 0xF0, 0x09, 0xD0, 0x24, 0x00, 0x9F, 0x01, 0x4C, 0x00, 0xF0, 0x01, 0xC0, ++0x37, 0x81, 0x12, 0x08, 0x0C, 0x00, 0x31, 0x4D, 0xC0, 0x24, 0x00, 0xD3, 0x00, ++0x4C, 0x02, 0xB0, 0x1D, 0xD0, 0x54, 0x00, 0xD3, 0xA0, 0x4C, 0x83, 0xF0, 0x0D, ++0xC0, 0x57, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x3D, 0x00, ++0xE1, 0x00, 0x06, 0x13, 0x10, 0x02, 0x40, 0x3B, 0x00, 0xE1, 0x00, 0xB4, 0x02, ++0xD0, 0x0E, 0x42, 0x28, 0x20, 0xA8, 0x00, 0x84, 0x00, 0xD0, 0x0E, 0x40, 0x3F, ++0x05, 0x31, 0x00, 0x84, 0x00, 0xD4, 0x0F, 0x51, 0x2C, 0x00, 0xE1, 0x00, 0x04, ++0x02, 0x14, 0x0C, 0x40, 0x08, 0x40, 0xF1, 0x00, 0x94, 0x03, 0xD0, 0x0A, 0x44, ++0x4F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xC5, ++0x01, 0x84, 0x27, 0x00, 0x1E, 0x40, 0x63, 0x00, 0xED, 0x01, 0xB4, 0x47, 0xD0, ++0x3C, 0x40, 0x68, 0x08, 0xAC, 0x11, 0x84, 0x05, 0xD0, 0x1A, 0x40, 0x7B, 0x43, ++0x29, 0x05, 0xA5, 0x04, 0x98, 0x1E, 0x40, 0x68, 0x80, 0xE1, 0x01, 0x84, 0x07, ++0x10, 0x12, 0x60, 0x5C, 0x00, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x40, 0x07, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x33, 0x10, 0xD1, 0x00, ++0x04, 0x03, 0x10, 0x0C, 0x40, 0x53, 0x22, 0xC9, 0x00, 0x34, 0x0A, 0xD0, 0x15, ++0x40, 0x30, 0x00, 0xC9, 0x82, 0x04, 0x6B, 0xD0, 0x2C, 0x40, 0x33, 0x00, 0xD9, ++0x01, 0x24, 0x03, 0xD0, 0x0C, 0x50, 0xF0, 0x81, 0x91, 0x01, 0x04, 0x07, 0x10, ++0x08, 0x60, 0x20, 0x00, 0xC1, 0x00, 0x14, 0x03, 0xD0, 0x98, 0x40, 0x4B, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x20, 0x15, 0x00, 0x77, 0x8A, 0x4D, ++0x81, 0x30, 0x76, 0xC0, 0x9F, 0x00, 0x5F, 0x01, 0xFC, 0x0D, 0xF1, 0xB7, 0xC0, ++0x14, 0x20, 0x7F, 0x4B, 0xCC, 0x0D, 0xF0, 0x26, 0xC0, 0x17, 0x10, 0x7B, 0x01, ++0xAC, 0x05, 0x34, 0x05, 0xC2, 0x9C, 0x04, 0x53, 0x01, 0xCC, 0x09, 0x30, 0x07, ++0xC1, 0x1C, 0x00, 0x53, 0x00, 0x4D, 0x01, 0xF2, 0x27, 0xC2, 0x5F, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x05, 0x10, 0x1F, 0x00, 0x3C, 0x00, ++0xF0, 0x01, 0xC1, 0x07, 0x00, 0x17, 0x08, 0x7C, 0x10, 0xF0, 0x21, 0xC0, 0x07, ++0x00, 0x1B, 0x02, 0x7D, 0x08, 0xF0, 0x41, 0xC0, 0x87, 0x00, 0x17, 0x08, 0x5C, ++0x28, 0x70, 0x20, 0xD0, 0x07, 0x40, 0x1F, 0x08, 0x7D, 0x60, 0x70, 0x11, 0xC0, ++0x47, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x00, 0xC1, 0x4B, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x93, 0x00, 0x4C, 0x26, 0x30, ++0x09, 0xC0, 0x24, 0x04, 0x9F, 0x00, 0x7C, 0x16, 0xF0, 0x09, 0xC0, 0x24, 0x00, ++0x9F, 0x04, 0x7C, 0x82, 0xB0, 0x09, 0xC4, 0x26, 0x40, 0x93, 0x04, 0x4C, 0x12, ++0x34, 0x19, 0xC0, 0x24, 0x01, 0x93, 0x08, 0x0C, 0x02, 0x30, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x01, 0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x20, 0x22, 0x00, 0x91, 0x00, 0x44, 0x02, 0x11, 0x09, ++0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0xA9, 0x41, 0x24, 0x00, 0x9D, ++0x00, 0x34, 0x0A, 0x10, 0x69, 0x40, 0x24, 0x00, 0x91, 0x01, 0x44, 0x16, 0x10, ++0x19, 0xD0, 0x22, 0x00, 0x91, 0x02, 0x45, 0x02, 0x10, 0x09, 0x40, 0x27, 0x20, ++0x9D, 0x09, 0x6C, 0x02, 0xD0, 0x09, 0x50, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x24, 0x40, 0x91, 0x20, 0x44, 0x02, 0x11, 0x09, 0x40, ++0x25, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x0D, 0x50, 0x25, 0x00, 0x9D, 0x00, ++0x74, 0x06, 0x90, 0x09, 0x40, 0x22, 0x02, 0x91, 0x00, 0x64, 0x02, 0x14, 0x49, ++0x48, 0x24, 0x00, 0x91, 0x02, 0x64, 0x22, 0x18, 0x19, 0x40, 0x27, 0x00, 0x8D, ++0x00, 0x65, 0x02, 0xD0, 0x09, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x20, 0x24, 0x00, 0x81, 0x04, 0x24, 0x12, 0x10, 0x49, 0x40, 0x61, ++0x91, 0x8D, 0x04, 0x34, 0x02, 0xC0, 0x48, 0x40, 0x21, 0x00, 0x8D, 0x20, 0x74, ++0x02, 0x00, 0x08, 0x42, 0x20, 0x89, 0x81, 0x44, 0x26, 0x02, 0x18, 0x48, 0x40, ++0x26, 0x40, 0x81, 0x00, 0x24, 0x12, 0x14, 0x58, 0x40, 0x23, 0x00, 0x8D, 0x04, ++0x24, 0x02, 0xD0, 0x48, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xB8, 0x86, 0x02, 0x13, 0x0A, 0x4C, 0x28, 0x34, 0xA1, 0xD0, 0x05, 0x00, ++0x1F, 0x00, 0x7C, 0x00, 0xF0, 0xA1, 0xC0, 0x85, 0x02, 0x5F, 0x00, 0x74, 0x01, ++0xB1, 0x01, 0xC8, 0x96, 0x42, 0x13, 0x0A, 0x6D, 0x00, 0x30, 0xA5, 0x40, 0x84, ++0x0A, 0x03, 0x4A, 0x6C, 0x28, 0x30, 0xA1, 0xC0, 0x07, 0x00, 0x1F, 0x0A, 0x6D, ++0x00, 0xF0, 0x01, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB8, 0x2F, 0x10, 0xBF, 0x08, 0x5D, 0x22, 0xF0, 0x8B, 0xC0, 0x3E, 0x02, 0xBF, ++0x08, 0xF4, 0x02, 0xF0, 0x8B, 0xC0, 0x2E, 0x00, 0xAF, 0x00, 0xFC, 0x02, 0xF2, ++0x0B, 0x00, 0x27, 0x02, 0xBF, 0x88, 0xDC, 0x82, 0xF2, 0x8B, 0xC0, 0x3F, 0x00, ++0xBF, 0x00, 0xDC, 0x22, 0xD0, 0x8B, 0xC0, 0x2B, 0x00, 0xBF, 0x08, 0x7C, 0x02, ++0xF0, 0x8B, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA8, ++0x3B, 0x00, 0xF2, 0x14, 0xCC, 0x32, 0x34, 0x0B, 0xC0, 0x2C, 0x00, 0x93, 0x00, ++0xCC, 0x02, 0xF0, 0x4B, 0xC1, 0x24, 0x00, 0xB3, 0x00, 0xFC, 0x02, 0x30, 0x0B, ++0xC0, 0xED, 0x00, 0xB3, 0x03, 0xCC, 0x02, 0x30, 0x3B, 0xC0, 0x2C, 0x00, 0xBF, ++0x88, 0xFC, 0x12, 0x30, 0x4A, 0xC1, 0x2C, 0x00, 0xB3, 0x00, 0x4D, 0x02, 0xF0, ++0x09, 0xC0, 0x64, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x05, ++0x05, 0x01, 0x04, 0x04, 0x30, 0x11, 0x21, 0x43, 0x04, 0x08, 0x11, 0x08, 0x44, ++0x00, 0xD0, 0x41, 0x50, 0x04, 0x00, 0x11, 0x00, 0x74, 0x00, 0x10, 0x01, 0x40, ++0xC4, 0x08, 0x41, 0x43, 0x44, 0x01, 0x10, 0x30, 0x40, 0x00, 0x04, 0x1D, 0x00, ++0x5C, 0x51, 0x10, 0x41, 0x42, 0x04, 0x08, 0x0B, 0x12, 0x54, 0x00, 0xD0, 0x81, ++0x40, 0x70, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x25, 0x01, ++0x81, 0x94, 0x05, 0x92, 0x90, 0xCC, 0x40, 0x20, 0x02, 0x91, 0x20, 0x04, 0x02, ++0xD0, 0x48, 0x41, 0x20, 0x00, 0x81, 0x01, 0x74, 0x02, 0x10, 0x0D, 0x40, 0xA1, ++0x09, 0x81, 0x06, 0x04, 0x82, 0x10, 0x68, 0x48, 0x20, 0x00, 0x8D, 0x00, 0x34, ++0x32, 0x10, 0x48, 0x51, 0x20, 0x00, 0x89, 0x0C, 0x04, 0x02, 0xD0, 0x08, 0x40, ++0x48, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x4A, 0x91, ++0x10, 0x44, 0x02, 0x90, 0x39, 0x40, 0x24, 0x40, 0x91, 0x00, 0x44, 0x02, 0xD0, ++0x09, 0x40, 0x24, 0x00, 0x91, 0x40, 0x74, 0x12, 0x10, 0x09, 0x40, 0x24, 0x00, ++0x91, 0x00, 0x45, 0x12, 0x10, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x14, 0x02, ++0x10, 0x69, 0x40, 0x24, 0x20, 0x89, 0x00, 0x54, 0x02, 0xD0, 0x09, 0x40, 0x60, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x21, 0x00, 0x93, 0x00, ++0x4C, 0x02, 0xB0, 0x29, 0xD0, 0xA4, 0x02, 0x83, 0x00, 0x4D, 0x02, 0xF0, 0x09, ++0xC9, 0x24, 0x40, 0x93, 0x03, 0x7C, 0x4E, 0x34, 0x48, 0xC0, 0x25, 0x40, 0x93, ++0x0B, 0x4C, 0x06, 0x24, 0x09, 0xD0, 0x64, 0x02, 0x9F, 0x00, 0x7C, 0x0E, 0x34, ++0x09, 0xC0, 0xA4, 0x24, 0x9B, 0x01, 0x4D, 0x02, 0xF0, 0x09, 0xD0, 0x14, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x65, 0x10, 0x9F, 0x04, 0x3C, ++0x42, 0x70, 0x09, 0xC0, 0x67, 0x00, 0x9F, 0x02, 0x7C, 0x02, 0xF1, 0x48, 0xC0, ++0xE7, 0x00, 0x9F, 0x02, 0x7C, 0x06, 0xF1, 0x09, 0xC8, 0x23, 0x40, 0x9F, 0x01, ++0x7C, 0x06, 0xF0, 0x08, 0xC0, 0x67, 0x00, 0x9F, 0x05, 0x7C, 0x12, 0xF0, 0x19, ++0xC1, 0x27, 0x00, 0x9F, 0x04, 0x7D, 0x02, 0xF0, 0x08, 0xC0, 0x5B, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x13, 0x80, 0x4C, 0x00, ++0x30, 0x00, 0xC0, 0x83, 0x40, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x04, ++0x00, 0x1F, 0x10, 0x7E, 0x08, 0xF2, 0x01, 0xD1, 0x06, 0x01, 0x03, 0x82, 0x4C, ++0x40, 0x31, 0x01, 0xC1, 0xC6, 0x00, 0x13, 0x00, 0x4C, 0x04, 0x30, 0x20, 0xC0, ++0x84, 0x00, 0x1F, 0x00, 0x4D, 0x00, 0xF0, 0x01, 0xC0, 0x50, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x14, 0x04, 0x51, 0x01, 0xC5, 0x09, 0x10, ++0x05, 0xC0, 0x5D, 0x00, 0x51, 0x00, 0x74, 0x01, 0xD0, 0x17, 0x60, 0x14, 0x00, ++0x7D, 0x03, 0xB4, 0x01, 0xD0, 0x27, 0x44, 0x5C, 0x00, 0x5B, 0x11, 0xAC, 0x15, ++0xB1, 0x57, 0xC0, 0x1E, 0x40, 0x70, 0x00, 0xC4, 0x11, 0x14, 0x37, 0x40, 0x10, ++0x00, 0x5D, 0x11, 0x44, 0x01, 0xD0, 0x05, 0x50, 0x50, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0x32, 0x40, 0xD1, 0x00, 0x24, 0x07, 0x11, 0x0C, ++0x40, 0x31, 0x04, 0xC1, 0x00, 0x34, 0x07, 0xD0, 0x1C, 0x48, 0x34, 0x00, 0xCD, ++0x02, 0x34, 0x02, 0xD8, 0x2C, 0x60, 0x32, 0x90, 0xC9, 0x21, 0x04, 0x87, 0x58, ++0x0C, 0x42, 0x30, 0x00, 0xC0, 0x04, 0x04, 0x03, 0x10, 0x3C, 0x40, 0x20, 0x00, ++0xCD, 0x00, 0x04, 0x83, 0xD0, 0x0C, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x80, 0x3C, 0x20, 0xA1, 0x10, 0xA5, 0x1A, 0x10, 0x0E, 0x40, ++0x31, 0x04, 0xE1, 0x00, 0xB4, 0x0A, 0xD0, 0x04, 0x41, 0x38, 0x01, 0x6D, 0x02, ++0xB6, 0x40, 0xD8, 0x03, 0x40, 0xAA, 0x82, 0xE9, 0x00, 0xA4, 0x00, 0xD0, 0x0E, ++0x40, 0x7A, 0x00, 0xE1, 0x01, 0x84, 0x03, 0x10, 0x0F, 0x41, 0x28, 0x00, 0xED, ++0x00, 0x85, 0x03, 0xD0, 0x0E, 0x40, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x18, 0x78, 0x00, 0xE3, 0x01, 0xAC, 0x16, 0x34, 0x1E, 0xC0, 0x79, ++0x00, 0xE3, 0x01, 0xBC, 0x06, 0xD0, 0x16, 0x40, 0xF8, 0x01, 0x2D, 0x01, 0xB4, ++0x05, 0xF0, 0x16, 0xD0, 0x72, 0x00, 0xAB, 0x01, 0x8C, 0x04, 0x74, 0x9E, 0xC0, ++0x78, 0x00, 0xF3, 0x81, 0xCC, 0x07, 0x34, 0x1E, 0xC0, 0x68, 0x00, 0xAF, 0x01, ++0x84, 0x07, 0xF0, 0x1C, 0xC0, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xB8, 0x35, 0x40, 0x9F, 0x14, 0x5C, 0x22, 0xF0, 0x0D, 0xC0, 0x35, 0x00, ++0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x05, 0xD0, 0x77, 0x00, 0x5F, 0x00, 0x6C, 0x00, ++0xF0, 0x00, 0xD0, 0x25, 0x20, 0x9F, 0x02, 0x3C, 0x00, 0xB1, 0x09, 0xD0, 0x37, ++0x00, 0xDF, 0x00, 0x7D, 0x03, 0xE0, 0x0D, 0xC0, 0x27, 0x00, 0x9F, 0x02, 0x7D, ++0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++0x20, 0x7D, 0x00, 0xFF, 0x21, 0x8C, 0x06, 0x38, 0x8F, 0xC0, 0x6D, 0x00, 0xF3, ++0x01, 0xFC, 0x06, 0xF0, 0x1F, 0xD0, 0x7C, 0x00, 0x3F, 0x01, 0xFC, 0x06, 0xF0, ++0x13, 0xC0, 0x5F, 0x20, 0xF7, 0x23, 0xCC, 0x04, 0x31, 0x9F, 0xC0, 0x7C, 0x08, ++0xF3, 0x01, 0x8C, 0x07, 0x31, 0x0B, 0xC0, 0x6F, 0x00, 0xEF, 0x03, 0xCC, 0x07, ++0xF2, 0x1F, 0xC2, 0x08, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, ++0x39, 0x00, 0xED, 0x00, 0x84, 0x02, 0x38, 0x0F, 0x40, 0x08, 0x40, 0xE1, 0x00, ++0xBC, 0x02, 0xD0, 0x26, 0x40, 0x38, 0x02, 0x6D, 0x10, 0xB4, 0xA0, 0xD0, 0x82, ++0x40, 0x0F, 0x10, 0xE1, 0x04, 0x94, 0x10, 0x10, 0xE6, 0x41, 0x3C, 0x00, 0xF1, ++0x10, 0x84, 0x83, 0x14, 0x8A, 0x40, 0x2B, 0x04, 0xED, 0x08, 0x84, 0x03, 0xD0, ++0x0E, 0x40, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, ++0x00, 0xED, 0x00, 0x84, 0x02, 0x90, 0x8E, 0x40, 0x29, 0x00, 0xE1, 0x00, 0xB4, ++0x42, 0xD0, 0x06, 0x40, 0x38, 0x04, 0x2D, 0x00, 0xB4, 0x00, 0xD0, 0x02, 0x40, ++0x2B, 0x02, 0xED, 0x80, 0xC4, 0x00, 0x10, 0x04, 0x40, 0x38, 0x04, 0x61, 0x00, ++0xF4, 0x03, 0x10, 0x8A, 0x41, 0x2B, 0x02, 0xAD, 0x00, 0x84, 0x03, 0xD0, 0x2C, ++0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x31, 0x00, ++0xCD, 0x00, 0x44, 0x02, 0x10, 0x1C, 0x40, 0x00, 0x04, 0xC1, 0x49, 0x34, 0x02, ++0xD0, 0x25, 0x40, 0x70, 0x00, 0x4D, 0x01, 0x34, 0x00, 0xD2, 0x10, 0x40, 0x23, ++0x00, 0xC9, 0x0A, 0x14, 0xC8, 0x14, 0x04, 0x50, 0xF0, 0x00, 0x41, 0x00, 0x34, ++0x0B, 0x10, 0x18, 0x40, 0x23, 0x00, 0x9D, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, ++0x58, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x35, 0x00, 0xDF, ++0x07, 0xCC, 0x02, 0xB0, 0x4D, 0xC0, 0xE5, 0x00, 0xD3, 0x00, 0x3C, 0x02, 0xF0, ++0x05, 0xD0, 0x3C, 0x00, 0x1F, 0x02, 0x7C, 0x08, 0xF0, 0x21, 0xC1, 0x3F, 0x00, ++0xDF, 0x23, 0x0D, 0x08, 0x30, 0x11, 0xC0, 0xF4, 0x08, 0xD3, 0x00, 0x7C, 0x23, ++0x30, 0x0D, 0xC0, 0xB7, 0x00, 0x9F, 0x00, 0x4D, 0x03, 0xF0, 0x0D, 0xC0, 0x74, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x37, 0x10, 0x9F, 0x00, ++0x7E, 0x02, 0x70, 0x0D, 0xC2, 0x63, 0x10, 0xDF, 0x00, 0x5C, 0x02, 0xF0, 0xC5, ++0xC0, 0x37, 0x00, 0x5F, 0x00, 0x7C, 0x10, 0xF0, 0x41, 0xC0, 0x37, 0x00, 0xD7, ++0x10, 0x7C, 0x0C, 0xF0, 0x00, 0xC0, 0x37, 0x04, 0xDF, 0x00, 0x44, 0x0B, 0xF0, ++0x0C, 0xC1, 0x27, 0x01, 0x9F, 0x00, 0x7C, 0x03, 0xF0, 0x1D, 0xC2, 0x07, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0xEF, 0x10, 0xCC, ++0x06, 0x30, 0x0F, 0xC0, 0x04, 0x00, 0xF3, 0x00, 0xFE, 0x52, 0x30, 0x05, 0xC0, ++0x3C, 0x00, 0x37, 0x10, 0xFC, 0x80, 0xF0, 0x03, 0xC0, 0x7B, 0x00, 0x93, 0x00, ++0xCC, 0x00, 0xB0, 0x03, 0x40, 0x2C, 0x00, 0xB3, 0x00, 0xCC, 0x83, 0x32, 0x8F, ++0xC2, 0xBC, 0x00, 0xBF, 0x00, 0xCC, 0x03, 0xF0, 0x0E, 0xC0, 0x04, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0x9D, 0x20, 0x44, 0x0A, ++0x10, 0x0C, 0x50, 0xC4, 0x00, 0xD1, 0x00, 0x74, 0x06, 0x50, 0x15, 0x50, 0x35, ++0x00, 0x5D, 0x07, 0x74, 0x0C, 0xD0, 0x11, 0xC0, 0x35, 0x02, 0x81, 0x00, 0x44, ++0x4C, 0x11, 0x31, 0xC0, 0x36, 0x00, 0xD1, 0x02, 0x44, 0x43, 0x10, 0x21, 0x42, ++0x24, 0x00, 0x9D, 0x09, 0x44, 0x03, 0xD0, 0x0D, 0x40, 0x04, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x66, 0x00, 0xDD, 0x00, 0x44, 0x28, 0x10, ++0x19, 0x40, 0xE6, 0x00, 0xD1, 0x00, 0x74, 0x02, 0xD0, 0x11, 0x40, 0x36, 0x00, ++0x1D, 0x01, 0x74, 0x44, 0xD0, 0x31, 0x40, 0x17, 0x40, 0xD1, 0x00, 0x44, 0x84, ++0x10, 0x11, 0x02, 0xD3, 0x00, 0xC1, 0x11, 0x06, 0x04, 0x10, 0x29, 0x40, 0x36, ++0x00, 0xDD, 0x00, 0x44, 0x03, 0xD0, 0x0D, 0x40, 0x06, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0xCD, 0x00, 0x05, 0x00, 0x10, 0x09, ++0x40, 0x02, 0x40, 0xC1, 0x00, 0x34, 0x82, 0x50, 0x00, 0x40, 0x33, 0x08, 0x4D, ++0x40, 0x36, 0x00, 0xD0, 0x00, 0x40, 0x11, 0x80, 0xD1, 0x00, 0x44, 0x00, 0x10, ++0x00, 0x40, 0x33, 0x00, 0xC1, 0x00, 0x06, 0x02, 0x10, 0x08, 0x50, 0x22, 0x00, ++0xCD, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x42, 0x80, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x98, 0x26, 0x00, 0xEF, 0x00, 0x4C, 0x00, 0x34, 0x09, 0xC0, ++0x06, 0x00, 0xD3, 0x00, 0x74, 0x02, 0x70, 0x05, 0xC0, 0x36, 0x00, 0x17, 0x00, ++0x74, 0x00, 0xF2, 0x01, 0xC2, 0x27, 0x20, 0xF3, 0x20, 0x4C, 0x00, 0xB0, 0x03, ++0xD0, 0x07, 0x00, 0x93, 0x00, 0x4C, 0x01, 0x30, 0x09, 0xC0, 0x36, 0x00, 0xBF, ++0x00, 0x4D, 0x03, 0xF0, 0x0D, 0xC0, 0x06, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0xB8, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x0B, 0xC0, 0x0D, ++0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x07, 0xC0, 0x3D, 0x00, 0x7F, 0x00, 0xFC, ++0x00, 0xD0, 0x03, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xBD, 0x00, 0xF4, 0x03, 0xC2, ++0x3E, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x2D, 0x00, 0xBF, 0x00, ++0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x15, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x27, 0x30, 0x1F, 0xC8, 0x7F, 0x0A, ++0xFF, 0x01, 0xCC, 0x27, 0xF0, 0x1F, 0xC0, 0x7C, 0x00, 0xF3, 0x09, 0xFC, 0x27, ++0xF0, 0x3F, 0xC0, 0x7F, 0x00, 0xF3, 0x01, 0xCC, 0x27, 0x30, 0x9F, 0xC0, 0x78, ++0x00, 0xFF, 0x09, 0xCC, 0x07, 0xB0, 0x13, 0xC0, 0x7E, 0x00, 0xEF, 0x01, 0xFC, ++0x07, 0x30, 0x1F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x08, 0x77, 0x00, 0xDD, 0x01, 0x74, 0x00, 0x10, 0x11, 0x40, 0x07, 0x01, 0x1D, ++0x01, 0x44, 0x00, 0x90, 0x11, 0x40, 0x04, 0x01, 0x11, 0x00, 0x74, 0x10, 0xD0, ++0x01, 0x40, 0x47, 0x00, 0x11, 0x01, 0x44, 0x00, 0x10, 0x01, 0x48, 0x44, 0x00, ++0x1D, 0x00, 0x44, 0x87, 0x51, 0x11, 0x40, 0x74, 0x00, 0x9D, 0x01, 0x74, 0x13, ++0x10, 0x1D, 0x40, 0x0F, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, ++0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x33, 0x00, 0xDD, 0x00, ++0x04, 0x03, 0xD0, 0x0D, 0x48, 0x34, 0x14, 0xC1, 0x20, 0x34, 0x03, 0xD0, 0x4C, ++0x40, 0x37, 0x00, 0xD9, 0x00, 0x64, 0x03, 0x10, 0x0D, 0x40, 0x31, 0x00, 0xCD, ++0x04, 0x24, 0x03, 0x10, 0x01, 0x48, 0x32, 0x80, 0x8D, 0x00, 0x34, 0x43, 0x19, ++0x0C, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, ++0x00, 0xDD, 0x00, 0x74, 0x00, 0x10, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x00, 0x44, ++0x00, 0x90, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x74, 0x80, 0xD0, 0x01, 0x40, ++0x07, 0x00, 0x19, 0x00, 0x64, 0x00, 0x11, 0x01, 0x42, 0x05, 0x08, 0x1D, 0x20, ++0x64, 0x07, 0x50, 0x11, 0x41, 0x34, 0x80, 0x1D, 0x01, 0x34, 0x03, 0x18, 0x0D, ++0x42, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x37, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x37, 0x18, 0xCF, 0x00, 0x4C, 0x03, ++0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x33, ++0x00, 0xCB, 0x00, 0x6C, 0x03, 0x30, 0x0C, 0xC0, 0x35, 0x00, 0xDF, 0x00, 0x6D, ++0x07, 0x30, 0x10, 0xC2, 0x36, 0x00, 0x9F, 0x13, 0x7C, 0x03, 0x30, 0x0D, 0xC2, ++0x23, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xFF, ++0x00, 0xFC, 0x40, 0xF2, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFD, 0x00, 0xF0, ++0x03, 0xD2, 0x0F, 0x00, 0x3F, 0x00, 0xFE, 0x00, 0xF0, 0x03, 0xC2, 0x0F, 0x00, ++0x37, 0x00, 0xDC, 0x00, 0xF6, 0x03, 0xC0, 0x0E, 0x20, 0x3F, 0x00, 0xDC, 0x03, ++0xF0, 0x07, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x1F, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0x30, 0x8D, 0xC0, 0x36, 0x00, 0xDF, 0x01, 0x4C, 0x23, 0xF0, 0x0D, ++0xC2, 0x34, 0x04, 0xDF, 0x01, 0x4C, 0x43, 0xF0, 0x0D, 0xE0, 0x37, 0x00, 0xDB, ++0x01, 0x4C, 0x13, 0xF0, 0x8D, 0x80, 0x34, 0x02, 0xD3, 0x18, 0x4C, 0x0E, 0xF0, ++0x01, 0xC0, 0x37, 0x00, 0x93, 0x02, 0x4C, 0x43, 0xF0, 0x0D, 0xC0, 0x2B, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0x74, ++0x00, 0x11, 0x01, 0x40, 0x84, 0x00, 0x1D, 0x00, 0x44, 0x00, 0xD0, 0x10, 0x40, ++0x80, 0x00, 0x1D, 0x80, 0x44, 0x9C, 0xD0, 0x51, 0x40, 0xC7, 0x0A, 0x1D, 0x00, ++0x04, 0x48, 0xD0, 0x21, 0x40, 0x44, 0x20, 0x11, 0xA0, 0x2C, 0x02, 0xD0, 0xA5, ++0x40, 0x77, 0x04, 0x91, 0x00, 0x68, 0x07, 0xD0, 0x0D, 0x40, 0x4F, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x74, 0x0F, ++0x10, 0x1C, 0x40, 0x32, 0x02, 0xCD, 0x00, 0x04, 0x43, 0xD0, 0x8C, 0x40, 0xF0, ++0x08, 0xCD, 0x00, 0x04, 0x03, 0xD0, 0x4C, 0x40, 0x73, 0x02, 0xCD, 0x00, 0x04, ++0x0F, 0xD0, 0x0C, 0x40, 0x70, 0x00, 0xD1, 0x00, 0x24, 0x03, 0xD0, 0x04, 0x48, ++0x73, 0x00, 0x88, 0x00, 0x04, 0x27, 0xD0, 0x0C, 0x40, 0x0F, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x78, 0x00, 0xED, 0x01, 0xF4, 0x64, 0x10, ++0x12, 0x40, 0xC8, 0x00, 0x3D, 0x01, 0x84, 0x04, 0xD0, 0x12, 0x50, 0x48, 0x04, ++0x2D, 0x03, 0x84, 0x04, 0xD0, 0x12, 0x40, 0x4B, 0x02, 0x3D, 0x01, 0x84, 0x04, ++0xD0, 0x33, 0x40, 0x4C, 0x00, 0x31, 0x01, 0xA4, 0x07, 0xD0, 0x16, 0x40, 0x3B, ++0x00, 0xB9, 0x01, 0xA4, 0x07, 0xD0, 0x1E, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xCF, 0x00, 0x3C, 0x03, 0x30, 0x0C, ++0xC0, 0x32, 0x00, 0xCF, 0x00, 0x0C, 0x03, 0xF0, 0x0C, 0xC0, 0x30, 0x02, 0xDF, ++0x00, 0x0C, 0x03, 0xF0, 0x0C, 0x40, 0x33, 0x00, 0xCF, 0x04, 0x0C, 0x23, 0xF2, ++0x0D, 0x40, 0x30, 0x00, 0xC3, 0x00, 0x2C, 0x0B, 0xF0, 0x00, 0xC0, 0x33, 0x02, ++0x8B, 0x80, 0x0C, 0x23, 0xF0, 0x0C, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xB8, 0x3D, 0x00, 0xFF, 0x00, 0xBC, 0x00, 0xF0, 0x82, 0x80, ++0x0F, 0x02, 0x2F, 0x00, 0xFC, 0x00, 0xF1, 0x02, 0xC0, 0x0F, 0x08, 0x3F, 0x00, ++0x7C, 0x00, 0xF0, 0x83, 0xC0, 0x0F, 0x08, 0x2F, 0x00, 0x7C, 0x00, 0xF0, 0x03, ++0xD0, 0x0F, 0x00, 0x2F, 0x09, 0xFC, 0x03, 0xF0, 0x83, 0xC4, 0x3B, 0x01, 0xB7, ++0x00, 0xFC, 0x23, 0xF0, 0x0F, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0xA0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x07, 0x34, 0x0D, 0xC0, 0x77, ++0x40, 0xD3, 0x00, 0x7C, 0x07, 0x34, 0x0D, 0xC0, 0x37, 0x08, 0xDF, 0x00, 0x7C, ++0x07, 0x30, 0x1D, 0xD0, 0x70, 0x00, 0xC3, 0x01, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, ++0x37, 0x20, 0xDF, 0x40, 0x7C, 0x01, 0xF0, 0x04, 0xC0, 0x34, 0x00, 0x9F, 0x00, ++0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x88, 0x39, 0x00, 0xED, 0x00, 0xF4, 0x00, 0x10, 0x02, 0x48, 0x0F, 0x00, ++0x21, 0x00, 0xF4, 0x00, 0x10, 0x02, 0x40, 0x0B, 0x00, 0x2D, 0x00, 0xF4, 0x00, ++0x13, 0x03, 0x40, 0x08, 0x00, 0x25, 0x00, 0x84, 0x00, 0xD0, 0x02, 0x40, 0x0B, ++0x00, 0x2D, 0x00, 0xB4, 0x01, 0xD0, 0x06, 0x40, 0x38, 0x00, 0xA9, 0x00, 0xB4, ++0x03, 0xD0, 0x0E, 0x40, 0x4F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x00, 0x79, 0x00, 0xED, 0x01, 0xB4, 0x07, 0x50, 0x1E, 0x40, 0x7B, 0x00, 0xE1, ++0x01, 0xB4, 0x07, 0x10, 0x1E, 0x00, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x07, 0x54, ++0x1E, 0x40, 0x78, 0x00, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, ++0xED, 0x01, 0xB4, 0x07, 0xD0, 0x12, 0x40, 0x78, 0x80, 0xAD, 0x11, 0xB4, 0x07, ++0xD0, 0x1E, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, ++0x33, 0x00, 0xCD, 0x00, 0x34, 0x80, 0x50, 0x00, 0x40, 0x03, 0x00, 0x01, 0x00, ++0x34, 0x00, 0x10, 0x00, 0x40, 0x03, 0x00, 0x0D, 0x00, 0x34, 0x00, 0x50, 0x00, ++0x40, 0x00, 0x00, 0x05, 0x00, 0x16, 0x00, 0xD0, 0x00, 0x40, 0x03, 0x00, 0x0D, ++0x00, 0x34, 0x07, 0xD0, 0x6C, 0x40, 0x30, 0x80, 0x89, 0x01, 0x34, 0x03, 0xD0, ++0x0C, 0x40, 0x5B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x28, 0x15, ++0x00, 0x5F, 0x00, 0x7C, 0x01, 0x70, 0x05, 0xC0, 0x17, 0x00, 0x53, 0x00, 0x7C, ++0x01, 0x30, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0x70, 0x05, 0xC0, ++0x14, 0x00, 0x51, 0x00, 0x4D, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, ++0xBC, 0x95, 0xF0, 0x27, 0xD0, 0x14, 0x00, 0x6F, 0x02, 0x7C, 0x01, 0xD0, 0x05, ++0xC0, 0x5F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, ++0x1F, 0x00, 0xFC, 0x00, 0x90, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, ++0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x80, 0xFC, 0x00, 0x90, 0x03, 0xC0, 0x0F, ++0x00, 0x3F, 0x00, 0xEC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0x7C, ++0x40, 0xE0, 0x21, 0xC0, 0x07, 0x08, 0x1F, 0x10, 0x74, 0x00, 0xF0, 0x01, 0xC0, ++0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, ++0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC0, 0x27, 0x10, 0x9F, 0x00, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x19, 0xC0, 0x27, 0x01, ++0x9F, 0x00, 0x7C, 0x26, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x06, ++0x70, 0x49, 0xC0, 0xE5, 0x00, 0x9F, 0x00, 0x4C, 0x16, 0xF0, 0x09, 0xC0, 0x43, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x00, ++0x74, 0x0A, 0xD0, 0x09, 0x40, 0x27, 0x04, 0x9D, 0x00, 0x74, 0x2E, 0xD0, 0x09, ++0x46, 0xA7, 0x00, 0x9D, 0x03, 0x74, 0x2A, 0xD0, 0x29, 0x40, 0x67, 0x80, 0x9D, ++0x00, 0x74, 0x0A, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x43, 0x74, 0xA2, 0x30, ++0x38, 0x40, 0x24, 0x01, 0x9D, 0x80, 0x6C, 0x0E, 0xD1, 0x09, 0x40, 0x07, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x74, ++0x12, 0xD0, 0x4B, 0x40, 0x6F, 0x00, 0xBD, 0x01, 0xF4, 0x02, 0xD0, 0x1B, 0x40, ++0x6F, 0x00, 0xBD, 0x08, 0xF4, 0x02, 0xD0, 0x8B, 0x40, 0x2F, 0x18, 0xBD, 0x01, ++0xF4, 0x02, 0xD0, 0x1B, 0x41, 0x6F, 0x00, 0xBD, 0x04, 0x64, 0x02, 0x58, 0x09, ++0x40, 0x25, 0x08, 0x9D, 0x00, 0x44, 0x0A, 0xD0, 0x09, 0x40, 0x63, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x8D, 0x00, 0xB4, 0x06, ++0xD0, 0x0A, 0x40, 0x2B, 0x00, 0xAD, 0x00, 0xB4, 0x06, 0xD2, 0x0A, 0x40, 0x6B, ++0x00, 0xAD, 0x01, 0xB4, 0x06, 0xD0, 0x1A, 0x48, 0x6B, 0x20, 0xAD, 0xC0, 0xB4, ++0x06, 0xD0, 0x0A, 0x48, 0x2B, 0x00, 0xAD, 0x01, 0x74, 0x02, 0x10, 0x09, 0x40, ++0x20, 0x00, 0x9D, 0x00, 0x25, 0x22, 0xD0, 0x08, 0x40, 0x43, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x00, 0x7C, 0x28, 0xF0, ++0x01, 0xC2, 0x87, 0x02, 0x1F, 0x00, 0x7C, 0x28, 0xF0, 0x01, 0xC0, 0x87, 0x22, ++0x1F, 0x2A, 0x7C, 0x28, 0xF0, 0xA1, 0xC0, 0x07, 0x00, 0x1D, 0x00, 0x7C, 0x28, ++0xF0, 0xA1, 0x40, 0x07, 0x00, 0x3F, 0x0A, 0x6C, 0x00, 0x72, 0x05, 0xC0, 0x05, ++0x00, 0x1F, 0x00, 0x4C, 0x08, 0xF0, 0x01, 0xC8, 0x77, 0xE0, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x19, 0xB8, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF1, 0x09, ++0xCA, 0x27, 0x08, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, ++0x00, 0x74, 0x82, 0xF1, 0x09, 0xC0, 0x27, 0x08, 0x9F, 0x00, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0xF8, 0x02, 0x72, 0x0B, 0xC0, 0x27, 0x00, ++0xBF, 0x00, 0x7C, 0x12, 0xF8, 0x09, 0xC0, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x27, 0x00, 0x9F, 0x00, 0xFC, 0x22, 0xF0, 0x0B, 0xC6, ++0xAC, 0x18, 0xBF, 0x00, 0xFC, 0x22, 0xB0, 0x0B, 0xC0, 0xAF, 0x20, 0xBF, 0x02, ++0xCC, 0x0A, 0xF0, 0x0B, 0xC0, 0x2C, 0x00, 0xB7, 0x00, 0xFC, 0x0A, 0x30, 0x2B, ++0xC0, 0x2C, 0x20, 0xBF, 0x48, 0xBC, 0x02, 0x30, 0x0F, 0xC0, 0x2F, 0x20, 0x9F, ++0x00, 0xF4, 0x02, 0x30, 0x09, 0xC0, 0x77, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1C, 0x08, 0x07, 0x00, 0x1D, 0x00, 0x74, 0x14, 0xD0, 0x01, 0x40, 0x44, ++0x00, 0x1D, 0x00, 0x74, 0x14, 0xD0, 0x01, 0x48, 0x47, 0x01, 0x1D, 0x81, 0x44, ++0x94, 0x90, 0x11, 0x52, 0x04, 0x00, 0x11, 0x00, 0x74, 0x04, 0x10, 0x51, 0x40, ++0x04, 0x00, 0x1D, 0x05, 0x74, 0x00, 0x10, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x00, ++0x64, 0x00, 0x14, 0x01, 0x40, 0x63, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xA0, 0x23, 0x00, 0x8D, 0x00, 0x34, 0x03, 0xD0, 0x0D, 0x50, 0x21, 0x01, ++0x8D, 0x00, 0x34, 0x03, 0x90, 0x0C, 0x40, 0x23, 0x01, 0xC5, 0x04, 0x15, 0x03, ++0xD0, 0x4D, 0x41, 0x20, 0x00, 0x81, 0x00, 0x34, 0x13, 0x10, 0x08, 0x14, 0x32, ++0x20, 0x8D, 0x00, 0x76, 0x82, 0x50, 0x08, 0x48, 0x23, 0x10, 0x8D, 0x00, 0x34, ++0x02, 0x10, 0x08, 0x40, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA8, 0x25, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x25, 0x00, 0x9D, ++0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x54, 0x02, 0xD0, ++0x0D, 0x40, 0x24, 0x00, 0x91, 0xC0, 0x74, 0x02, 0x12, 0x09, 0x00, 0x24, 0x00, ++0x9D, 0x00, 0x74, 0x12, 0x54, 0x19, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x24, 0x02, ++0x10, 0x09, 0x40, 0x63, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x25, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xB0, 0x09, 0xC0, 0x27, 0x00, 0x97, 0x00, 0x5C, 0x02, 0xF0, 0x09, ++0xC0, 0x24, 0x40, 0x95, 0x00, 0x7C, 0x02, 0x34, 0x09, 0xC0, 0x26, 0x00, 0x9F, ++0x00, 0x7C, 0x4E, 0x70, 0x69, 0xC0, 0x27, 0x00, 0x9F, 0x05, 0x7C, 0x02, 0x10, ++0x09, 0x40, 0x17, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x25, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x26, 0x04, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x6C, 0x02, 0xB0, 0x09, 0xC0, ++0x27, 0x20, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC2, 0x25, 0x20, 0x9F, 0x00, ++0x7C, 0x02, 0xB2, 0x09, 0xC0, 0x27, 0x04, 0x9F, 0x04, 0x6C, 0x02, 0xF0, 0x09, ++0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, ++0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7E, 0x00, ++0x34, 0x01, 0xC0, 0x07, 0x40, 0x1B, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC4, 0x47, ++0x00, 0x1F, 0x00, 0x7C, 0x00, 0x30, 0x41, 0xC2, 0x04, 0x00, 0x13, 0x00, 0x7C, ++0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x10, 0xF0, 0x01, 0xC0, ++0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x14, 0x00, 0x5D, ++0x00, 0xF4, 0x01, 0xD0, 0x04, 0x40, 0x9F, 0x04, 0x5D, 0x01, 0xF4, 0x21, 0x10, ++0x05, 0x00, 0xDF, 0x02, 0x71, 0x88, 0xF0, 0x01, 0xD0, 0x86, 0xC0, 0x19, 0x01, ++0x5D, 0x11, 0xF4, 0x09, 0x10, 0x37, 0x48, 0x14, 0x20, 0x7B, 0x91, 0x74, 0x01, ++0x10, 0xB7, 0x40, 0x1F, 0x00, 0x5D, 0x00, 0xF4, 0x45, 0xD0, 0x05, 0x40, 0x43, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x00, ++0x34, 0x43, 0xD0, 0x08, 0x40, 0xF3, 0x00, 0x8D, 0x08, 0x34, 0x03, 0x10, 0x08, ++0x40, 0xF3, 0x20, 0xD0, 0x02, 0x34, 0x13, 0xD0, 0x2C, 0x40, 0x53, 0x00, 0x8D, ++0x40, 0x76, 0x43, 0x14, 0x3D, 0x40, 0x20, 0x00, 0xC1, 0x04, 0x74, 0x02, 0x50, ++0x30, 0x48, 0x43, 0x00, 0xCC, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x43, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x38, 0x00, 0xED, 0x00, 0xB4, ++0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x07, 0x10, 0x0E, 0x40, ++0x7B, 0x14, 0xE1, 0x40, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x39, 0x00, 0xED, 0x00, ++0xB4, 0x03, 0x12, 0x2E, 0x50, 0x78, 0x00, 0xE9, 0x00, 0xF4, 0xC2, 0x00, 0x02, ++0x41, 0x0B, 0x04, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x13, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x78, 0x00, 0xEF, 0x01, 0xBC, 0x07, ++0xF0, 0x1E, 0xC2, 0x5B, 0x00, 0xEF, 0x01, 0xF4, 0x07, 0x30, 0x1E, 0xC8, 0x7F, ++0x10, 0xE3, 0x01, 0xBC, 0x07, 0xD0, 0x1E, 0xC0, 0x7B, 0x00, 0xEF, 0x01, 0xFC, ++0x07, 0x30, 0x17, 0xC8, 0x78, 0x08, 0xE3, 0x21, 0xBC, 0x07, 0x70, 0x16, 0xC0, ++0x4B, 0x00, 0xEF, 0x21, 0xBC, 0x05, 0xF0, 0x1E, 0xC0, 0x53, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC0, 0x17, 0x08, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0x40, 0x17, 0x00, ++0xD7, 0x20, 0x7C, 0x01, 0xF0, 0x0D, 0xC4, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x01, ++0xF3, 0x05, 0xC0, 0x32, 0x10, 0x5F, 0x00, 0x7C, 0x03, 0xE0, 0x05, 0xC0, 0x07, ++0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF1, 0x0D, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xA0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x05, 0xF0, 0x1F, ++0xC0, 0x7F, 0x00, 0xF3, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7C, 0x00, 0xFF, ++0x21, 0xBC, 0x85, 0x30, 0x1F, 0xC0, 0x78, 0x02, 0xF3, 0x01, 0xFC, 0x05, 0xF0, ++0x5F, 0xC0, 0x7F, 0x00, 0xFF, 0x09, 0xFC, 0x16, 0xF0, 0x17, 0xC4, 0x6D, 0x00, ++0xFF, 0x09, 0xF4, 0x27, 0x30, 0x9F, 0xC0, 0x1B, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0x80, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x09, 0xD0, 0x0E, 0x40, ++0x3B, 0x00, 0xE1, 0x28, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x38, 0x00, 0xED, 0x08, ++0xB4, 0x03, 0x12, 0x0F, 0x40, 0x38, 0x06, 0xE1, 0x18, 0xB4, 0x43, 0xD0, 0x06, ++0x41, 0x3B, 0x00, 0xED, 0x0A, 0xB4, 0x03, 0xD0, 0x07, 0x40, 0x28, 0x00, 0xED, ++0x08, 0xF4, 0x0B, 0x14, 0x0E, 0x40, 0x57, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x01, 0xD0, 0x8E, 0x40, 0x1F, ++0x00, 0xE1, 0x00, 0xB4, 0x09, 0xD0, 0x8F, 0x40, 0x39, 0x02, 0x6D, 0x02, 0xF4, ++0x09, 0x10, 0x26, 0x40, 0xBC, 0x08, 0xE1, 0x00, 0xB4, 0x01, 0xD0, 0x4E, 0x40, ++0x3B, 0x02, 0xED, 0x80, 0xB4, 0x93, 0xD0, 0x07, 0x40, 0x19, 0x00, 0xED, 0x40, ++0xB4, 0x01, 0x12, 0x0E, 0x40, 0x23, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x08, 0xD0, 0x0C, 0x41, 0x07, 0x01, ++0xC1, 0x01, 0x34, 0x82, 0xD0, 0x2C, 0x4D, 0x65, 0x02, 0x8D, 0x88, 0x74, 0x24, ++0x10, 0x08, 0x40, 0x30, 0x00, 0xC1, 0x02, 0x34, 0x0C, 0xD0, 0x00, 0x40, 0x73, ++0x04, 0x9D, 0x0F, 0x34, 0x02, 0xD0, 0x24, 0x40, 0x00, 0x20, 0xCD, 0x09, 0x74, ++0x00, 0x10, 0x0C, 0x60, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA8, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x36, 0xF0, 0x0D, 0xC0, 0xA7, 0x00, 0xC3, ++0x12, 0x3C, 0x14, 0xF0, 0x2D, 0xC0, 0x85, 0x00, 0x0F, 0x00, 0x7C, 0x02, 0x30, ++0x51, 0x40, 0x74, 0x80, 0xD3, 0x09, 0x74, 0x26, 0xF0, 0x19, 0xC0, 0x33, 0x04, ++0x1E, 0x00, 0x7C, 0x02, 0xF0, 0x14, 0xC0, 0x05, 0x00, 0xDF, 0x01, 0x7C, 0x02, ++0x30, 0x0D, 0xC8, 0x77, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, ++0x37, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x1D, 0xC8, 0xC7, 0x20, 0xDF, 0x04, ++0x7C, 0x00, 0xF0, 0x1D, 0x00, 0x26, 0x01, 0x1D, 0x80, 0x7C, 0x0A, 0xF0, 0x01, ++0xD0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x0A, 0xF0, 0x09, 0x41, 0x37, 0x20, 0x9F, ++0x00, 0x78, 0x02, 0xC0, 0x15, 0xC0, 0x07, 0x00, 0xDF, 0x00, 0x7C, 0x0A, 0xF0, ++0x0D, 0xC0, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, ++0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x2C, 0x00, 0xF3, 0x05, 0xEC, ++0x00, 0xB0, 0x5F, 0xC0, 0x0F, 0x00, 0x33, 0x20, 0xCC, 0x02, 0x30, 0x03, 0xC0, ++0x3F, 0x00, 0xFF, 0x04, 0xFC, 0x02, 0xF0, 0x03, 0xC0, 0x3F, 0x20, 0x33, 0x20, ++0xCC, 0x17, 0xF0, 0x17, 0xD1, 0x0C, 0x00, 0xFF, 0x10, 0xFC, 0x00, 0x10, 0x0F, ++0xC2, 0x27, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, ++0xDD, 0x00, 0x74, 0x06, 0xD1, 0x0C, 0x40, 0x44, 0x08, 0xD1, 0x01, 0x44, 0x04, ++0x10, 0x1D, 0x40, 0x47, 0x01, 0x11, 0x01, 0x44, 0x06, 0x10, 0x31, 0x40, 0xF7, ++0x04, 0xDD, 0x01, 0x74, 0x1E, 0xD0, 0x51, 0x40, 0x37, 0x20, 0x11, 0x03, 0x44, ++0x03, 0xD0, 0xC5, 0x40, 0x44, 0x01, 0xDD, 0x00, 0x74, 0x2C, 0x10, 0x0D, 0x46, ++0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x00, 0xDD, ++0x00, 0x74, 0x06, 0xD0, 0x1D, 0x40, 0x64, 0x04, 0xD1, 0x00, 0x64, 0x0E, 0x10, ++0x0D, 0x40, 0x47, 0x80, 0x91, 0x03, 0x44, 0x0C, 0x10, 0x19, 0x42, 0x77, 0x00, ++0xDD, 0x00, 0x74, 0x04, 0xD0, 0x19, 0x40, 0x37, 0x09, 0x11, 0x01, 0x44, 0x02, ++0xD0, 0x05, 0x40, 0x44, 0x00, 0xDD, 0x00, 0x74, 0x82, 0x40, 0x0D, 0x40, 0x07, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x30, 0x00, 0xCD, 0x00, ++0x34, 0x02, 0xD0, 0x0D, 0x40, 0x20, 0x40, 0xC1, 0x00, 0x44, 0x02, 0x10, 0x0C, ++0x40, 0x23, 0x60, 0x91, 0x00, 0x04, 0x02, 0x16, 0x08, 0x40, 0x33, 0x20, 0xCD, ++0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x37, 0x08, 0x81, 0x20, 0x05, 0x02, 0xD0, ++0x04, 0x40, 0x00, 0x00, 0xCD, 0x00, 0x34, 0x00, 0x50, 0x0C, 0x40, 0x43, 0x20, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x36, 0x00, 0xDF, 0x00, 0x7C, ++0x00, 0xF0, 0x0D, 0xC2, 0x24, 0x00, 0xD3, 0x00, 0x6C, 0x00, 0x30, 0x0D, 0xC0, ++0x07, 0x00, 0x13, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC0, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x00, 0xF0, 0x09, 0xC0, 0x37, 0x00, 0x13, 0x40, 0x4C, 0x03, 0xF0, 0x05, ++0xC0, 0x04, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x74, 0x0D, 0xC0, 0x07, 0x40, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, ++0xF0, 0x0F, 0xC8, 0x2B, 0x08, 0xFF, 0x20, 0xFC, 0x02, 0xF0, 0x0E, 0xC0, 0x2F, ++0x00, 0xBF, 0x00, 0xFC, 0x02, 0xF0, 0x0B, 0xC2, 0x2F, 0x00, 0xFF, 0x00, 0xFC, ++0x02, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x0F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xB0, 0x0F, 0xC0, 0x17, 0x22, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x4F, 0x00, 0x33, 0x01, 0xCC, 0x24, 0x30, ++0x13, 0xC0, 0x2C, 0x02, 0xF3, 0x00, 0x8C, 0x07, 0x30, 0xCF, 0xC0, 0x2C, 0x40, ++0x33, 0x08, 0xCC, 0x23, 0x72, 0xC7, 0xC0, 0xCE, 0x00, 0x33, 0x04, 0xDC, 0x00, ++0x30, 0x13, 0xC0, 0xCF, 0x00, 0x3F, 0x01, 0xED, 0x04, 0x30, 0x13, 0xC0, 0x4C, ++0x00, 0x33, 0x01, 0xCC, 0x04, 0x30, 0x13, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x21, 0x11, 0x00, 0x44, 0x00, 0x10, 0x04, ++0x40, 0x24, 0x09, 0xF1, 0x00, 0x44, 0x03, 0x30, 0x21, 0x40, 0xB0, 0x05, 0x01, ++0x26, 0x05, 0x3B, 0x30, 0xE1, 0x40, 0x05, 0x21, 0x51, 0x0B, 0x44, 0x18, 0x15, ++0x41, 0xC0, 0x23, 0x00, 0x1D, 0x00, 0x44, 0x82, 0x10, 0x01, 0x42, 0x44, 0x00, ++0x11, 0x80, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x11, 0xA0, 0x03, 0x04, 0x11, 0x01, 0x04, 0x12, 0x10, 0x00, 0x40, ++0x00, 0x00, 0xC1, 0x00, 0x64, 0x53, 0x90, 0x3C, 0x48, 0x24, 0x02, 0x01, 0x06, ++0x25, 0x83, 0xD0, 0x05, 0x40, 0x00, 0x00, 0x09, 0x00, 0x34, 0x48, 0x90, 0x00, ++0x41, 0x03, 0x01, 0x89, 0x00, 0x44, 0x00, 0x90, 0x01, 0x40, 0x46, 0x00, 0x89, ++0x00, 0x24, 0x02, 0x10, 0x08, 0x40, 0x45, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xA8, 0x05, 0x00, 0x11, 0x40, 0x04, 0x02, 0x10, 0x05, 0x40, 0x04, ++0x12, 0xC1, 0x00, 0x64, 0x03, 0x14, 0x09, 0x40, 0x34, 0x02, 0x11, 0x01, 0x64, ++0x07, 0x10, 0x01, 0x40, 0x45, 0x04, 0x59, 0x20, 0x64, 0x44, 0x92, 0x11, 0x42, ++0x27, 0x00, 0x8C, 0x00, 0x44, 0x02, 0x98, 0x11, 0x00, 0x06, 0x00, 0x89, 0x00, ++0x24, 0x02, 0x10, 0x08, 0x40, 0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA0, 0x37, 0x40, 0x43, 0x00, 0x4C, 0x04, 0x30, 0x21, 0xC1, 0x64, 0x00, ++0xD3, 0x00, 0x2D, 0x03, 0xB0, 0x0D, 0xC4, 0xC0, 0x40, 0x13, 0x00, 0x6C, 0x07, ++0xF2, 0x0D, 0xC0, 0x84, 0x40, 0x5B, 0x81, 0x7C, 0x0C, 0xB1, 0x51, 0xE0, 0x07, ++0x00, 0x1F, 0x00, 0x4C, 0x01, 0xB0, 0x08, 0xC0, 0x12, 0x18, 0x1B, 0x01, 0x6C, ++0x04, 0x30, 0x11, 0xC0, 0x09, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++0x88, 0x3D, 0x20, 0x7F, 0x00, 0xFC, 0x24, 0xF0, 0x07, 0xC0, 0x73, 0x00, 0xFF, ++0x00, 0xDC, 0x02, 0xF0, 0x26, 0xC0, 0x0F, 0x30, 0x3F, 0x20, 0x9C, 0x03, 0xF0, ++0x05, 0xC0, 0x0D, 0x00, 0x77, 0x03, 0xDC, 0x00, 0x72, 0x03, 0xC0, 0x2D, 0x02, ++0x3F, 0x08, 0xDC, 0x03, 0x74, 0x0B, 0xC0, 0x1D, 0x18, 0x36, 0x49, 0xDC, 0x24, ++0xF0, 0x93, 0xC0, 0x1E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, ++0x75, 0x00, 0x53, 0x10, 0x4C, 0x06, 0x32, 0x01, 0xCA, 0x24, 0x00, 0xD3, 0x00, ++0x4D, 0x03, 0x30, 0x0D, 0xC0, 0x24, 0x00, 0x13, 0x02, 0x6C, 0x02, 0x30, 0x0D, ++0xC1, 0x86, 0x00, 0x4F, 0x50, 0xCC, 0x18, 0x30, 0x01, 0xC8, 0x07, 0x40, 0x93, ++0x05, 0x7C, 0x01, 0xF0, 0x09, 0xC0, 0x14, 0x04, 0x93, 0x11, 0x4C, 0x46, 0x30, ++0x59, 0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x74, ++0x00, 0x51, 0x80, 0x44, 0x06, 0x12, 0x05, 0x40, 0x34, 0x09, 0xF1, 0x00, 0x44, ++0x0B, 0x10, 0xBD, 0x40, 0xA4, 0x02, 0x35, 0x00, 0x44, 0x00, 0x10, 0x7C, 0x40, ++0x04, 0x06, 0x5D, 0x11, 0x2C, 0x08, 0x10, 0x11, 0x00, 0x67, 0x08, 0x9B, 0x23, ++0x34, 0x2B, 0xD0, 0xA9, 0x40, 0x94, 0x04, 0x91, 0x03, 0x44, 0x0E, 0x10, 0x39, ++0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x04, 0x00, ++0x89, 0x00, 0x04, 0x01, 0x10, 0x09, 0x40, 0x60, 0x00, 0xC1, 0x01, 0x04, 0x4B, ++0x14, 0x3C, 0x40, 0xA0, 0x00, 0x11, 0x00, 0x24, 0x03, 0x18, 0x24, 0x40, 0x06, ++0x08, 0x8D, 0x02, 0x14, 0x00, 0x11, 0x10, 0x48, 0x53, 0x02, 0x45, 0x00, 0x34, ++0x00, 0xD0, 0x04, 0x40, 0x61, 0x00, 0x41, 0x02, 0x04, 0x09, 0x10, 0x04, 0x02, ++0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x48, 0x00, 0xB9, ++0x09, 0x84, 0x0D, 0x10, 0x1E, 0x42, 0xF8, 0x00, 0xE1, 0x01, 0xC4, 0x87, 0x14, ++0x1C, 0x41, 0x68, 0x02, 0xA5, 0x01, 0x84, 0x07, 0x10, 0x92, 0x50, 0x48, 0x20, ++0xAD, 0x21, 0x36, 0x84, 0x18, 0x12, 0x40, 0x7B, 0x00, 0x6D, 0x01, 0xB4, 0x06, ++0xD0, 0x97, 0x40, 0x6D, 0x00, 0x61, 0x09, 0x84, 0x25, 0x10, 0x16, 0x40, 0x10, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x00, 0x40, 0x8B, 0x08, ++0x4C, 0x13, 0x30, 0x08, 0xC0, 0x00, 0x42, 0xD3, 0x10, 0x0C, 0x03, 0x30, 0x0C, ++0x40, 0x20, 0x02, 0x83, 0x00, 0x2C, 0x03, 0x12, 0x04, 0xC2, 0x02, 0x00, 0x8F, ++0x08, 0x1C, 0x12, 0x30, 0x00, 0xE5, 0x13, 0x00, 0xC7, 0x00, 0x3C, 0x20, 0xF0, ++0x04, 0xC0, 0x21, 0x00, 0xD3, 0x08, 0x4C, 0x23, 0x30, 0x0D, 0xC0, 0x48, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x0D, 0x00, 0xA7, 0x08, 0xFC, ++0x03, 0xF0, 0x0F, 0xC8, 0x1F, 0x00, 0xFF, 0x80, 0xFD, 0x03, 0xF0, 0x0F, 0xC0, ++0x3F, 0x0A, 0xBE, 0x80, 0xFC, 0x03, 0xF4, 0x03, 0xC2, 0x0F, 0x02, 0xEF, 0x20, ++0xEC, 0x02, 0xF0, 0x83, 0xC0, 0x3F, 0x02, 0xFB, 0x00, 0xFC, 0x02, 0xF1, 0x06, ++0xC0, 0x2A, 0x02, 0xFF, 0x08, 0xFC, 0x23, 0xF0, 0x8F, 0xC0, 0x0B, 0x60, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, 0x00, 0xCF, 0x00, 0x5C, 0x05, ++0x30, 0x09, 0xC0, 0x24, 0x00, 0xDF, 0x0D, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0x27, ++0x00, 0x13, 0x00, 0xCD, 0x03, 0x34, 0x0D, 0xD8, 0x05, 0x10, 0x13, 0x00, 0x7C, ++0x02, 0x70, 0x01, 0xC4, 0x13, 0x00, 0x53, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xD0, ++0x34, 0x00, 0x5F, 0x00, 0x4E, 0x01, 0x30, 0x15, 0xC0, 0x54, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x39, 0x00, 0xED, 0x80, 0x84, 0x01, 0x10, ++0x0E, 0x40, 0x38, 0x00, 0xCD, 0x10, 0x84, 0x02, 0xD0, 0x0E, 0x40, 0x2B, 0x10, ++0x81, 0x04, 0x84, 0x03, 0x10, 0x04, 0xC0, 0x0A, 0x00, 0x21, 0x00, 0xB4, 0x02, ++0x11, 0x06, 0x48, 0x3B, 0x00, 0x61, 0x00, 0xB4, 0x03, 0xD2, 0x0F, 0x40, 0x38, ++0x20, 0x6D, 0x00, 0x84, 0x01, 0x10, 0x06, 0x40, 0x48, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xED, 0x01, 0x94, 0x07, 0x10, 0x1A, ++0x50, 0x68, 0x00, 0xED, 0x05, 0x84, 0x47, 0xD8, 0x1E, 0x40, 0x6F, 0x00, 0xA1, ++0x1D, 0x85, 0x07, 0x10, 0x1E, 0x40, 0xC9, 0x18, 0xE1, 0x01, 0xF4, 0x0E, 0x50, ++0x12, 0x40, 0x5B, 0x00, 0xE1, 0x01, 0xB4, 0x05, 0xD0, 0x1E, 0x42, 0x78, 0x00, ++0xED, 0x01, 0x84, 0x87, 0x10, 0x1E, 0x40, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x28, 0x73, 0x02, 0xDD, 0x00, 0x04, 0x03, 0x10, 0x0C, 0x40, ++0xB0, 0x00, 0xCD, 0x00, 0x04, 0x07, 0xD0, 0x0D, 0x40, 0xA3, 0x01, 0xC1, 0x40, ++0x04, 0x09, 0x10, 0x8D, 0x40, 0x76, 0x00, 0xC1, 0x03, 0x34, 0x0F, 0x10, 0x88, ++0x42, 0x33, 0x00, 0xC1, 0x00, 0x34, 0x07, 0xD0, 0x0C, 0x40, 0x30, 0x00, 0xCD, ++0x00, 0x04, 0x03, 0x10, 0x0C, 0x40, 0x48, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x17, 0xA0, 0x95, 0x00, 0x5F, 0x00, 0x5C, 0x01, 0x34, 0x05, 0xC0, 0x1C, ++0x01, 0x5F, 0x00, 0x4C, 0x01, 0xF0, 0x07, 0xC0, 0xDF, 0x44, 0x73, 0x00, 0xCC, ++0x31, 0x30, 0x17, 0xC2, 0x9D, 0x40, 0x73, 0x07, 0xFC, 0x29, 0x72, 0x16, 0xC0, ++0x17, 0x50, 0x53, 0x20, 0x7C, 0x01, 0xF1, 0x05, 0xC0, 0x14, 0x10, 0x5F, 0x00, ++0x4D, 0x01, 0x34, 0x05, 0xD0, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x08, 0x05, 0x04, 0x1D, 0x00, 0x7C, 0x00, 0xF2, 0x01, 0xC8, 0x03, 0x04, ++0x1F, 0x40, 0x7D, 0x08, 0xF0, 0x01, 0xC0, 0x07, 0x10, 0x1F, 0x20, 0x7C, 0x00, ++0xF2, 0x11, 0xD0, 0x07, 0x04, 0x0F, 0x12, 0x3C, 0x08, 0xF1, 0x41, 0xC0, 0x07, ++0x00, 0x1F, 0x00, 0x7C, 0x20, 0xF0, 0x11, 0xC8, 0x07, 0x00, 0x1F, 0x00, 0x7C, ++0x00, 0xF0, 0x01, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x25, 0x00, 0x9F, 0x02, 0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x02, 0x90, ++0x01, 0x7C, 0x02, 0x34, 0x09, 0xC0, 0x24, 0x00, 0x83, 0x00, 0x4C, 0x02, 0x30, ++0x09, 0xC0, 0x64, 0x00, 0x93, 0x05, 0x4C, 0x06, 0x10, 0x09, 0xC8, 0x24, 0x00, ++0x93, 0x00, 0x64, 0x0A, 0x30, 0x09, 0xC0, 0xE4, 0x10, 0x9F, 0x02, 0x4D, 0x0A, ++0x30, 0x59, 0xC0, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, ++0xA6, 0x10, 0x9D, 0x00, 0x45, 0x0A, 0xD0, 0x08, 0xC0, 0x66, 0x00, 0x91, 0x01, ++0x34, 0x1A, 0x12, 0x09, 0x48, 0xA4, 0x02, 0x95, 0x00, 0x44, 0x02, 0x12, 0x99, ++0x51, 0x24, 0x08, 0x91, 0x25, 0x44, 0xA6, 0x10, 0x09, 0x40, 0x20, 0x00, 0x91, ++0x02, 0x04, 0x0A, 0x10, 0x29, 0x50, 0x64, 0x08, 0x9D, 0x42, 0x44, 0x0A, 0x10, ++0x39, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, ++0x80, 0xBD, 0x00, 0xC4, 0x02, 0xD0, 0x0B, 0x40, 0x24, 0x40, 0x95, 0x08, 0x74, ++0x22, 0x14, 0x09, 0x48, 0xB0, 0x00, 0xD9, 0x04, 0x24, 0x02, 0x14, 0x09, 0x40, ++0x24, 0x42, 0xD1, 0x00, 0x45, 0x42, 0x50, 0x09, 0x52, 0x24, 0x40, 0xA1, 0x00, ++0xF4, 0x02, 0x10, 0x2A, 0x42, 0x2C, 0x00, 0xAD, 0x00, 0xA4, 0x02, 0x10, 0x0B, ++0x42, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x68, 0x00, ++0xED, 0x00, 0x84, 0x06, 0xD0, 0x0B, 0x40, 0x22, 0x01, 0x85, 0x04, 0x74, 0x02, ++0x10, 0x48, 0x40, 0x20, 0x01, 0x8D, 0x04, 0x25, 0x12, 0x10, 0x48, 0x40, 0x60, ++0x20, 0x81, 0x84, 0x05, 0x12, 0x14, 0x08, 0x40, 0x2C, 0x00, 0xA1, 0x01, 0xD4, ++0x02, 0x10, 0x0A, 0x42, 0x68, 0x80, 0xAD, 0x01, 0xA4, 0x06, 0x10, 0x1A, 0x40, ++0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x86, 0x02, 0x1F, ++0x0A, 0x0D, 0x28, 0xF0, 0xA2, 0xC0, 0x94, 0x02, 0x17, 0x0A, 0x7C, 0x28, 0x30, ++0xA5, 0xD0, 0x84, 0x02, 0x1B, 0x0A, 0x2C, 0x28, 0x31, 0xA1, 0xD0, 0x80, 0x22, ++0x13, 0x00, 0x4C, 0x28, 0x70, 0xA1, 0xC0, 0x84, 0x02, 0x13, 0x0A, 0x7C, 0x29, ++0x30, 0xA1, 0xC0, 0x04, 0x00, 0x0F, 0x0A, 0x2C, 0x28, 0x32, 0xA2, 0xC0, 0x77, ++0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x27, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x2F, 0x02, 0x9B, 0x08, 0xEC, 0x02, 0xF4, 0x8B, ++0xC8, 0x2B, 0x02, 0xB7, 0x08, 0xDC, 0x23, 0xF0, 0x8B, 0xC2, 0x2F, 0x00, 0xBF, ++0x68, 0xBC, 0x22, 0xF0, 0x0B, 0xC2, 0x27, 0x00, 0x9F, 0x20, 0x6C, 0x02, 0xF4, ++0x09, 0xC8, 0x27, 0x00, 0x9F, 0x00, 0x5C, 0x02, 0xF4, 0x09, 0xC0, 0x67, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x2F, 0x00, 0xF3, 0x28, 0xDC, ++0x02, 0xF0, 0x09, 0xC0, 0x2F, 0x42, 0xB3, 0x04, 0xCC, 0x02, 0x30, 0xCF, 0xC0, ++0x2B, 0x00, 0xA3, 0x05, 0x4D, 0x16, 0x32, 0x9B, 0xC0, 0xAF, 0x10, 0xB3, 0x05, ++0xDC, 0x36, 0x30, 0x0B, 0xC4, 0x2C, 0x00, 0xB3, 0x00, 0xFC, 0x02, 0xF0, 0x8B, ++0xC0, 0x3C, 0x18, 0xBF, 0x40, 0xFC, 0x22, 0xF0, 0x0B, 0xC0, 0x63, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x01, 0x01, 0x04, 0x44, 0x41, ++0xD0, 0x01, 0x41, 0x07, 0x02, 0x11, 0x14, 0x44, 0x10, 0x10, 0xC0, 0x40, 0x87, ++0x44, 0x11, 0x17, 0x44, 0x5C, 0x14, 0x31, 0x44, 0x47, 0x00, 0x11, 0x22, 0x44, ++0x04, 0x10, 0x55, 0x41, 0x44, 0x05, 0x51, 0x14, 0x74, 0x10, 0xD0, 0x41, 0x50, ++0x04, 0x00, 0x5D, 0x10, 0x74, 0x01, 0xD0, 0x45, 0x41, 0x73, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x21, 0x45, 0x81, 0x04, 0x14, 0x12, 0xD0, ++0x08, 0x40, 0x23, 0x00, 0x81, 0x0C, 0x24, 0x52, 0x10, 0x48, 0x44, 0x23, 0x03, ++0x81, 0x08, 0x04, 0x22, 0x10, 0x68, 0x40, 0x27, 0x01, 0x89, 0x08, 0x34, 0x1A, ++0x14, 0x09, 0x50, 0x24, 0x00, 0x89, 0x24, 0x34, 0x52, 0xD1, 0x48, 0x40, 0x20, ++0x00, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x48, 0x40, 0x43, 0x80, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x28, 0x21, 0x00, 0x91, 0x00, 0x44, 0x02, 0xD2, 0x09, ++0x40, 0x27, 0x00, 0x91, 0x00, 0x65, 0x02, 0x14, 0x29, 0x40, 0xA7, 0x01, 0x91, ++0x11, 0x44, 0x12, 0x10, 0x09, 0x40, 0x67, 0x00, 0x99, 0x06, 0x64, 0x0A, 0x10, ++0x19, 0x40, 0x24, 0x40, 0x99, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x00, ++0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x20, 0x25, 0x00, 0x93, 0x00, 0x5C, 0x0A, 0xF0, 0x09, 0xC0, ++0xA7, 0x01, 0x93, 0x00, 0x6D, 0x06, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x93, 0x01, ++0x4C, 0x0A, 0x30, 0x69, 0xC0, 0x23, 0x24, 0x9B, 0x00, 0x7C, 0x06, 0x32, 0x18, ++0xC0, 0x24, 0x00, 0x9A, 0x02, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x80, 0x9F, ++0x02, 0x7C, 0x0A, 0xF0, 0x29, 0xC0, 0x17, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x16, 0x08, 0x25, 0x10, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x23, ++0x00, 0x8F, 0x00, 0x5C, 0x4E, 0xF0, 0x09, 0xC0, 0x27, 0x44, 0x8F, 0x40, 0x7C, ++0x02, 0xF2, 0x09, 0xC2, 0x27, 0x40, 0x87, 0x01, 0x54, 0xCA, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x97, 0x00, 0x7C, 0x02, 0xF1, 0x09, 0xC0, 0x27, 0x0C, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x53, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x08, 0x05, 0x04, 0x1F, 0x04, 0x4C, 0x08, 0xB4, 0x01, 0xD0, 0x04, 0x01, ++0x13, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC0, 0x00, 0x00, 0x13, 0x02, 0x4C, 0x08, ++0x30, 0x21, 0xC0, 0x84, 0x00, 0x13, 0x01, 0x0C, 0x00, 0xB4, 0x01, 0xC0, 0x07, ++0x00, 0x1F, 0x06, 0x4D, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x02, 0x1F, 0x02, 0x4D, ++0x48, 0x34, 0x21, 0xD0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0xDC, 0x00, 0x6D, 0x00, 0xC4, 0x05, 0x30, 0x05, 0x40, 0x1C, 0x00, 0x51, ++0x00, 0xC5, 0x05, 0x10, 0x07, 0x48, 0x1C, 0x00, 0x51, 0x20, 0x44, 0x01, 0x50, ++0x67, 0x40, 0x1C, 0x48, 0x71, 0x10, 0xEC, 0x09, 0x10, 0x15, 0x40, 0x13, 0x00, ++0x7D, 0x83, 0xC4, 0x01, 0x00, 0x17, 0x40, 0x1F, 0x00, 0x7D, 0x00, 0xC4, 0x09, ++0x10, 0x07, 0x40, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, ++0xF2, 0x02, 0x8D, 0x02, 0x04, 0x07, 0x50, 0x0C, 0x40, 0xB0, 0x40, 0xC5, 0x00, ++0x44, 0x0F, 0x10, 0x8C, 0x40, 0x20, 0x00, 0xC1, 0x00, 0x45, 0x03, 0x18, 0x6C, ++0x44, 0x30, 0x20, 0xC1, 0x01, 0x04, 0x07, 0x10, 0x18, 0x40, 0x33, 0x08, 0xCD, ++0x03, 0x04, 0x05, 0x10, 0x89, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x05, 0x0B, 0x10, ++0x0C, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, ++0x10, 0x2D, 0x04, 0x84, 0x47, 0x50, 0xDF, 0x42, 0x08, 0x04, 0xE5, 0x00, 0x84, ++0x41, 0x10, 0x1E, 0x40, 0x2C, 0x00, 0xF1, 0x00, 0x84, 0x13, 0x50, 0x1E, 0x50, ++0x3C, 0x05, 0x41, 0x20, 0xA4, 0x0B, 0x10, 0x0E, 0x41, 0x3B, 0x00, 0xED, 0x03, ++0x84, 0x0D, 0x11, 0x02, 0x40, 0x0B, 0x00, 0xED, 0x01, 0x84, 0x07, 0x10, 0x1E, ++0x44, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x79, 0x00, ++0xAF, 0x07, 0xCD, 0x07, 0x70, 0x1E, 0xC0, 0x40, 0x40, 0x87, 0x89, 0x8C, 0x04, ++0x34, 0x1E, 0x10, 0x78, 0x40, 0xE3, 0x31, 0xCC, 0x0F, 0x34, 0x1E, 0xC0, 0xE8, ++0x00, 0x63, 0x01, 0x0C, 0x04, 0x34, 0x1A, 0xC0, 0x7B, 0x00, 0xFF, 0x01, 0xCC, ++0x06, 0x34, 0x12, 0xC0, 0x4B, 0x00, 0xFD, 0x01, 0xCC, 0x07, 0x30, 0x1F, 0xC0, ++0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0x1F, ++0x20, 0x7C, 0x03, 0x30, 0x2C, 0xC0, 0x07, 0x00, 0xDB, 0x04, 0x3C, 0x00, 0xF2, ++0x05, 0xC0, 0x37, 0x00, 0xDF, 0x06, 0x7C, 0x5B, 0xB0, 0x88, 0xC0, 0x13, 0x00, ++0x5F, 0x20, 0x7C, 0x00, 0xF0, 0x0F, 0xC0, 0xB7, 0x0D, 0xDF, 0x00, 0xFC, 0x80, ++0xF0, 0x09, 0xC0, 0x07, 0x00, 0xDF, 0x20, 0x7C, 0x01, 0xF0, 0x09, 0xC2, 0x43, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x7D, 0x00, 0x2F, 0x01, ++0xDC, 0x13, 0xF0, 0x3F, 0xC0, 0x4C, 0x10, 0xF7, 0x01, 0xDC, 0x04, 0x30, 0x1F, ++0xC8, 0x6C, 0x00, 0xF3, 0x01, 0xCC, 0x07, 0x31, 0x1B, 0xD0, 0x6D, 0x00, 0x73, ++0x01, 0x9D, 0x04, 0xB2, 0x4F, 0xC0, 0x7C, 0x00, 0xF3, 0x01, 0xDC, 0x05, 0x30, ++0x1F, 0xC0, 0x4C, 0x00, 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x03, 0x08, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x39, 0x00, 0x27, 0x00, 0x84, ++0x0A, 0xD0, 0x8F, 0x41, 0x0C, 0x00, 0xE1, 0x00, 0xEC, 0x00, 0x12, 0x4A, 0x40, ++0x08, 0x02, 0xE0, 0x00, 0x84, 0x13, 0xA1, 0x0B, 0x40, 0x38, 0x00, 0x61, 0x08, ++0x84, 0x02, 0x50, 0x0F, 0x40, 0x3C, 0x02, 0xA7, 0x00, 0xC4, 0x21, 0x12, 0x07, ++0x40, 0x08, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x2E, 0x40, 0x57, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0xAD, 0x00, 0x94, 0x23, ++0xD0, 0x0E, 0x40, 0x08, 0x00, 0x85, 0x00, 0x94, 0x40, 0x10, 0x0E, 0x40, 0x3C, ++0x00, 0xE1, 0x08, 0x84, 0x03, 0x80, 0x02, 0x40, 0x29, 0x02, 0x21, 0x00, 0xD4, ++0x00, 0x14, 0x2E, 0x40, 0x38, 0x00, 0x61, 0x00, 0x94, 0x02, 0x10, 0x06, 0x40, ++0x08, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x03, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x35, 0x00, 0x05, 0x00, 0x04, 0x02, 0xD0, ++0x1C, 0x40, 0x00, 0x00, 0xC1, 0x00, 0x24, 0x00, 0x12, 0x31, 0x40, 0x30, 0x00, ++0xC1, 0x00, 0x05, 0x83, 0x90, 0x10, 0x40, 0x10, 0x04, 0x41, 0x61, 0x04, 0x04, ++0x54, 0x9C, 0x44, 0x30, 0x08, 0x95, 0x00, 0x04, 0x00, 0x10, 0x0C, 0x40, 0x00, ++0x00, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x08, 0x40, 0x13, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0xA0, 0x35, 0x00, 0xFF, 0x00, 0x5C, 0x03, 0xF0, 0x1F, ++0xD0, 0x24, 0x00, 0xD7, 0x00, 0x1C, 0x04, 0x30, 0x8D, 0xD5, 0x60, 0x00, 0xD3, ++0x0A, 0xCC, 0x0B, 0xB0, 0x83, 0xD1, 0x39, 0x48, 0x13, 0x10, 0x5D, 0x02, 0x30, ++0x0D, 0xC4, 0xA4, 0x00, 0xD3, 0x00, 0x5C, 0x09, 0x30, 0x0D, 0xC0, 0x00, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x08, 0x27, 0x00, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, ++0x07, 0x02, 0xDF, 0x20, 0x5C, 0x08, 0xF4, 0x2D, 0xC0, 0xE7, 0x40, 0xDF, 0x08, ++0x7C, 0x03, 0xF0, 0x09, 0xC0, 0x37, 0x02, 0x1F, 0x20, 0x7C, 0xA2, 0x74, 0x0D, ++0xC0, 0x37, 0x01, 0xD7, 0x40, 0x7C, 0x11, 0xF0, 0x2D, 0xC0, 0x07, 0x00, 0x9F, ++0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x80, 0x08, 0x1F, 0x00, 0xB3, 0x00, 0xCC, 0x01, 0xF0, 0x0F, 0xC0, 0x0B, ++0x00, 0xB2, 0x00, 0xCC, 0x00, 0x30, 0x1F, 0xC0, 0x2C, 0x40, 0x97, 0x00, 0x7C, ++0x43, 0x32, 0x53, 0xD0, 0x2E, 0x00, 0x13, 0x00, 0xFC, 0x20, 0x20, 0x1F, 0xC0, ++0x2F, 0x00, 0xFD, 0x00, 0xEC, 0x00, 0xF0, 0x0F, 0xC0, 0x0C, 0x10, 0x72, 0x00, ++0xFC, 0x27, 0xF0, 0x07, 0xC0, 0x03, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x81, 0x00, 0x06, 0x08, 0x11, 0x00, 0x45, 0x0B, 0xD0, 0x0D, 0xC8, 0x45, 0x00, ++0xD1, 0x00, 0x44, 0x04, 0x10, 0xBD, 0x41, 0x64, 0x20, 0x91, 0x08, 0x34, 0x03, ++0x12, 0x09, 0x40, 0x15, 0x00, 0x11, 0x01, 0x7C, 0x00, 0x50, 0x1D, 0x40, 0x77, ++0x00, 0xDD, 0x09, 0x44, 0x04, 0xD0, 0x3D, 0x48, 0xC4, 0x04, 0xD1, 0x00, 0x74, ++0x05, 0xD0, 0xBD, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0xA0, 0x76, 0x00, 0x41, 0x08, 0x44, 0x23, 0xD0, 0x0D, 0x40, 0x47, 0x00, 0xC5, ++0x00, 0x44, 0x0C, 0x10, 0x0D, 0x40, 0xE5, 0x00, 0xD1, 0x00, 0x74, 0x03, 0x12, ++0x00, 0x41, 0x26, 0x00, 0x11, 0x23, 0x34, 0x00, 0xD8, 0x4D, 0x40, 0x27, 0x01, ++0xDD, 0x00, 0x64, 0x44, 0xD0, 0x6C, 0x40, 0x44, 0x80, 0xD5, 0x01, 0x74, 0x03, ++0xD0, 0x0D, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x70, 0x00, 0x41, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x01, 0x00, 0xC5, 0x00, ++0x04, 0x80, 0x14, 0x0C, 0x50, 0x21, 0x00, 0xC1, 0x00, 0x74, 0x83, 0x18, 0x08, ++0x50, 0x31, 0x00, 0x01, 0x00, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, ++0x00, 0x04, 0x00, 0xD0, 0x0C, 0x40, 0x00, 0x80, 0x85, 0x01, 0x34, 0x02, 0xD0, ++0x0C, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x36, ++0x00, 0x93, 0x80, 0x4C, 0x81, 0xF0, 0x0F, 0xC0, 0x07, 0x20, 0xB7, 0x00, 0x4D, ++0x00, 0x30, 0x0C, 0x44, 0x25, 0x00, 0xB3, 0x00, 0xFC, 0x03, 0x31, 0x01, 0xC4, ++0x22, 0x00, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0x0D, 0xC2, 0x2F, 0x00, 0x4F, 0x40, ++0x6C, 0x00, 0xF0, 0x0D, 0xC0, 0x04, 0x00, 0x57, 0x00, 0x7C, 0x03, 0xF0, 0x05, ++0xC4, 0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, ++0x3F, 0x40, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, 0xFB, 0x40, 0xFC, 0x00, ++0xF0, 0x0F, 0xC0, 0x2A, 0x00, 0xBF, 0x00, 0xFC, 0x03, 0xF0, 0x03, 0x40, 0x1F, ++0x40, 0x3F, 0x00, 0xD8, 0x00, 0x72, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, ++0x00, 0xF0, 0x0F, 0xC8, 0x0F, 0x08, 0xFB, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xFF, ++0x01, 0xFC, 0x13, 0x32, 0x8B, 0xC2, 0x2C, 0x09, 0xFF, 0x01, 0xFC, 0x63, 0x30, ++0x4B, 0xC2, 0x7C, 0x00, 0xBF, 0x04, 0xCC, 0x82, 0x30, 0x2F, 0xC1, 0x7C, 0x00, ++0xF3, 0x01, 0xFC, 0x43, 0x30, 0x4F, 0x50, 0x28, 0x00, 0xF3, 0x01, 0xFE, 0x07, ++0xB0, 0x1F, 0xC0, 0x7C, 0x00, 0xF9, 0x01, 0xFC, 0x03, 0xF0, 0x1F, 0xC0, 0x0F, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x77, 0x00, 0xDD, 0x01, ++0xF4, 0x63, 0x10, 0x81, 0x46, 0xE4, 0x0A, 0xDD, 0x41, 0xF4, 0x0B, 0x50, 0x91, ++0x42, 0x74, 0x00, 0x9C, 0x22, 0x44, 0x08, 0x10, 0x2F, 0xC4, 0x34, 0x08, 0xD5, ++0x21, 0xF4, 0x0F, 0x41, 0x9F, 0x40, 0xC4, 0x02, 0xD1, 0x01, 0x74, 0x07, 0x10, ++0x15, 0x40, 0x74, 0x00, 0xD9, 0x01, 0x74, 0x07, 0xD0, 0x1D, 0x40, 0x0F, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x28, 0xCD, 0x80, 0x34, ++0x13, 0x00, 0x08, 0x48, 0x40, 0x20, 0xCD, 0x80, 0x30, 0x03, 0x12, 0x10, 0x40, ++0x30, 0x10, 0x0D, 0x1C, 0x04, 0x76, 0x10, 0x4C, 0x40, 0x33, 0x05, 0xC1, 0x40, ++0x34, 0x83, 0x80, 0x0C, 0x40, 0x20, 0x08, 0xC1, 0x80, 0x34, 0x03, 0x90, 0x0D, ++0x40, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x4F, 0x80, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, 0xDD, 0x00, 0x74, 0x03, ++0x11, 0x11, 0x40, 0x64, 0x00, 0xDD, 0x40, 0x64, 0x03, 0x10, 0x11, 0x40, 0x34, ++0x20, 0x09, 0x03, 0x04, 0x06, 0x10, 0x0D, 0x44, 0x35, 0x00, 0xD1, 0x00, 0x74, ++0x03, 0x90, 0x0D, 0x40, 0x64, 0x04, 0xD1, 0x00, 0x74, 0x03, 0x50, 0x19, 0x40, ++0x36, 0x00, 0xDD, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0x00, 0x0F, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x37, 0x00, 0xDF, 0x00, 0x74, 0x03, 0x30, ++0x31, 0xC0, 0x44, 0x00, 0xDF, 0x40, 0x7C, 0x03, 0x32, 0x19, 0xC0, 0x34, 0x08, ++0x9F, 0x01, 0x4C, 0x04, 0x30, 0x0D, 0xC6, 0x37, 0x00, 0xD1, 0x80, 0x7C, 0x83, ++0xA0, 0x0D, 0xC0, 0x64, 0x00, 0xD3, 0x00, 0x74, 0x03, 0xB0, 0x3D, 0xC1, 0x36, ++0x00, 0xDF, 0x00, 0x7C, 0x03, 0xD0, 0x0D, 0xC0, 0x83, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xFF, 0x00, 0x7C, 0x03, 0xF0, 0x02, ++0xC0, 0x07, 0x00, 0xFF, 0x40, 0xFC, 0x03, 0xF0, 0x00, 0x40, 0x3F, 0x00, 0x9F, ++0x20, 0x7C, 0x80, 0xF1, 0x0F, 0xC0, 0x3E, 0x00, 0xFD, 0x00, 0xFC, 0x03, 0x72, ++0x0F, 0x40, 0x0B, 0x00, 0xFD, 0x00, 0xFC, 0x03, 0xB0, 0x0F, 0x40, 0x3D, 0x00, ++0xFB, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xDF, 0x00, 0x3C, 0x03, 0x30, 0xA9, 0xC0, ++0x04, 0x00, 0xD3, 0x60, 0x2C, 0x63, 0x30, 0x09, 0xC0, 0x34, 0x00, 0x9B, 0x20, ++0x4C, 0x00, 0x30, 0x8C, 0xC0, 0x34, 0x00, 0xD2, 0x00, 0x3C, 0x03, 0x30, 0x0C, ++0xC0, 0x27, 0x00, 0xD7, 0x00, 0x7C, 0x23, 0xF1, 0x2D, 0xC0, 0x37, 0x10, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0xF4, 0x03, 0x10, 0x31, 0x40, 0x24, ++0x00, 0xD1, 0x00, 0xF4, 0x0B, 0x10, 0x09, 0x44, 0x34, 0x00, 0x9D, 0x00, 0x44, ++0x02, 0x12, 0xAF, 0x40, 0x74, 0x20, 0xD1, 0x00, 0xF4, 0x03, 0x10, 0x0F, 0x40, ++0x27, 0x00, 0xD1, 0x80, 0x34, 0x0F, 0xD0, 0x0C, 0x40, 0x37, 0x00, 0xDD, 0x00, ++0xF4, 0x03, 0xD0, 0x0D, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x07, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x14, 0x08, 0x41, 0x20, 0x00, ++0xC1, 0x00, 0x34, 0x0B, 0x10, 0x08, 0x40, 0x30, 0x00, 0x0D, 0x00, 0x04, 0x02, ++0x10, 0x2C, 0x40, 0x34, 0x02, 0xC1, 0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x03, ++0x00, 0xC5, 0x20, 0x34, 0x4F, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, ++0x03, 0xD0, 0x0C, 0x40, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x80, 0x78, 0x00, 0xED, 0x01, 0xB4, 0x27, 0x10, 0x1E, 0x40, 0x78, 0x00, 0xE1, ++0x01, 0xB4, 0x07, 0x10, 0x1E, 0x40, 0x78, 0x00, 0xED, 0x01, 0x84, 0x05, 0x10, ++0x1E, 0x40, 0xF8, 0x00, 0xE1, 0x01, 0xF4, 0x07, 0x10, 0x1E, 0x40, 0x5B, 0x00, ++0xE1, 0x01, 0xB0, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x07, ++0xD0, 0x1E, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, ++0x30, 0x00, 0xCF, 0x00, 0x3C, 0x03, 0x30, 0x2D, 0xC0, 0x10, 0x08, 0xC3, 0x08, ++0x7C, 0x03, 0x30, 0x44, 0xC0, 0x30, 0x02, 0x4F, 0x00, 0x0C, 0x03, 0x30, 0x8D, ++0xE0, 0x34, 0x00, 0xC3, 0x08, 0x7C, 0x23, 0x30, 0x0C, 0xC0, 0x13, 0x00, 0xC7, ++0x00, 0x3C, 0x03, 0xF1, 0x0C, 0xC0, 0x33, 0x00, 0xCF, 0x00, 0x3C, 0x03, 0xF0, ++0x0C, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x35, ++0x10, 0xDF, 0x00, 0x7C, 0x0B, 0xC0, 0x0D, 0x40, 0x37, 0x00, 0xDF, 0x00, 0x74, ++0x03, 0xF0, 0x05, 0xC0, 0x37, 0x20, 0xDE, 0x00, 0x7C, 0x03, 0xF0, 0x2D, 0xC0, ++0x37, 0x00, 0xDF, 0x08, 0x7C, 0x83, 0xB4, 0x0D, 0xC1, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x00, ++0xDF, 0x00, 0x7C, 0xB3, 0x30, 0x15, 0xC0, 0x34, 0x00, 0xDF, 0x00, 0x7C, 0x4B, ++0xF0, 0x0D, 0xC8, 0x37, 0x28, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0xAD, 0xC0, 0x37, ++0x00, 0xDF, 0x00, 0x7C, 0x53, 0xF0, 0x1D, 0xC4, 0x34, 0x10, 0xD3, 0x00, 0x7C, ++0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, ++0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x39, 0x00, 0xED, ++0x00, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x38, 0x00, 0xED, 0x00, 0xB4, 0x13, 0xD0, ++0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x01, 0xD3, 0x4E, 0x40, 0x3B, 0x00, ++0xED, 0x00, 0xB4, 0x1B, 0xD0, 0x4E, 0x41, 0x18, 0x08, 0xE1, 0x80, 0xB4, 0x03, ++0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x0B, 0xD0, 0x0E, 0x40, 0x4F, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x00, 0xED, 0x01, ++0xB0, 0x17, 0x10, 0x1C, 0x51, 0x58, 0x00, 0xED, 0x01, 0xB4, 0x27, 0xD0, 0x1E, ++0x40, 0x7B, 0x00, 0x6D, 0x21, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, ++0x01, 0xB4, 0x07, 0xD0, 0x1C, 0x40, 0x70, 0x40, 0xE1, 0x01, 0xB4, 0x07, 0xD0, ++0x1E, 0x41, 0x7B, 0x80, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x13, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x74, ++0x83, 0x10, 0x3C, 0x45, 0xF0, 0x02, 0xCD, 0x00, 0x34, 0x03, 0xD8, 0xBC, 0x40, ++0x33, 0x00, 0xDD, 0x01, 0x34, 0x2B, 0xD1, 0x0D, 0x40, 0x33, 0x00, 0xCD, 0x00, ++0x34, 0x03, 0xD0, 0x0C, 0x40, 0x70, 0x00, 0xD1, 0x80, 0x34, 0x03, 0xD0, 0x7C, ++0x40, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x60, 0x5B, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, 0x00, 0x5F, 0xC0, 0x7C, 0x01, ++0x30, 0x17, 0xC0, 0xDC, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x17, 0xC0, 0x17, ++0x00, 0x7F, 0x05, 0xFC, 0x25, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x7C, ++0x01, 0xF0, 0x05, 0xC0, 0x58, 0x01, 0x53, 0x00, 0x7C, 0x01, 0xF0, 0x37, 0xC0, ++0x17, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x5F, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF4, ++0x01, 0xC0, 0x07, 0x04, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC1, 0x06, 0x10, ++0x1F, 0x41, 0x7C, 0x00, 0xE0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, ++0xF0, 0x01, 0xD0, 0xC7, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x59, ++0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x26, 0xF0, 0x09, 0xC4, 0x27, 0x00, 0x9F, ++0x00, 0x4C, 0x02, 0xF0, 0x99, 0xC0, 0x64, 0x00, 0x9F, 0x40, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x67, 0x00, 0x97, 0x00, 0x4C, 0x02, 0x70, 0x09, 0xC0, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x19, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x76, 0x82, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, ++0x44, 0x02, 0xD0, 0x69, 0xC0, 0xA4, 0x01, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, ++0x40, 0xA7, 0x12, 0x91, 0x40, 0x0C, 0x9A, 0x11, 0x09, 0x40, 0x27, 0x00, 0x9D, ++0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x27, ++0x00, 0x9D, 0x40, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x20, 0x44, ++0x82, 0xD0, 0x09, 0x40, 0x24, 0x0A, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, ++0xA7, 0x00, 0x95, 0x00, 0x44, 0x02, 0x50, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, ++0x74, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x20, 0x20, 0x00, 0x8D, 0x00, 0x34, 0x12, 0x10, 0x58, 0x40, 0x23, 0x01, ++0x8D, 0x40, 0x34, 0x16, 0xD0, 0x48, 0x40, 0x23, 0x00, 0x8D, 0x44, 0x04, 0x12, ++0xD0, 0x48, 0x40, 0x20, 0x00, 0x8D, 0x00, 0x34, 0x12, 0xD8, 0x48, 0x40, 0x23, ++0x01, 0x91, 0x00, 0x04, 0x02, 0x10, 0x08, 0x40, 0x23, 0x00, 0x8D, 0x00, 0x34, ++0x12, 0xD0, 0x08, 0x40, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB0, 0x06, 0x00, 0x1F, 0x00, 0x3C, 0x28, 0x30, 0xA1, 0xC0, 0x07, 0x00, 0x1F, ++0x00, 0x74, 0x28, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x0A, 0x4D, 0x28, 0xF1, ++0xA1, 0x40, 0x84, 0x02, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, ++0x17, 0x00, 0x4D, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, ++0xF0, 0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x22, 0xF4, 0x8B, 0xC0, 0x2F, 0x0A, 0x9F, 0x00, ++0x7C, 0x22, 0xF0, 0x8B, 0xC0, 0x27, 0x00, 0xFF, 0x08, 0xFC, 0x22, 0xF0, 0x89, ++0xD0, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x22, 0xF0, 0x89, 0xC0, 0x2F, 0x02, 0x9F, ++0x00, 0x5C, 0x02, 0xF0, 0x0B, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x22, 0xF0, ++0x09, 0xC0, 0x77, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x27, ++0x00, 0x9F, 0x00, 0x7C, 0x1E, 0xF0, 0xDB, 0xC0, 0x67, 0x01, 0x9F, 0x00, 0xFC, ++0x36, 0x34, 0x59, 0xC0, 0x27, 0x00, 0x9F, 0x07, 0x4C, 0x1E, 0xF1, 0x7B, 0xD0, ++0xAC, 0x00, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x59, 0xC0, 0x6F, 0x01, 0x9B, 0x00, ++0xFC, 0x02, 0xF0, 0x08, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x77, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, ++0x1D, 0x00, 0x74, 0x3C, 0xD0, 0xF5, 0x42, 0x87, 0x02, 0x1D, 0x00, 0x74, 0x3C, ++0x10, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x05, 0x44, 0x1D, 0xD0, 0x71, 0x40, 0x44, ++0x01, 0x1D, 0x00, 0x74, 0x08, 0xD0, 0x21, 0x40, 0x97, 0x02, 0x11, 0x00, 0x74, ++0x00, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x00, 0x74, 0x20, 0xD0, 0x01, 0x40, ++0x63, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, ++0x00, 0x34, 0x12, 0xD0, 0x08, 0x40, 0x23, 0x00, 0x8D, 0x00, 0x34, 0x02, 0x10, ++0x28, 0x40, 0x23, 0x00, 0x8D, 0x06, 0x04, 0x0A, 0xD0, 0x28, 0x40, 0x20, 0x00, ++0x8D, 0x00, 0x34, 0x0A, 0xD0, 0x88, 0x40, 0x23, 0x00, 0x89, 0x00, 0x34, 0x02, ++0xD0, 0x08, 0x40, 0x23, 0x00, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x4B, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x9D, 0x00, ++0x74, 0x02, 0xD0, 0x49, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x69, ++0x40, 0x27, 0x00, 0x9D, 0x00, 0x44, 0x02, 0xD0, 0x0D, 0x40, 0x24, 0x00, 0x9D, ++0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x91, 0x80, 0x74, 0x82, 0xD0, ++0x89, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x63, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC0, 0xA7, 0x16, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x39, 0xC0, ++0x27, 0x00, 0x9F, 0x08, 0x4C, 0x06, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC4, 0x23, 0x00, 0x9B, 0x00, 0x7C, 0x02, 0xF0, 0x19, ++0x41, 0x27, 0x20, 0x9D, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x17, 0x80, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x3C, 0x02, 0xF0, 0x19, 0xC0, 0x27, ++0x00, 0x8F, 0x00, 0x7D, 0x16, 0xF1, 0x08, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xCA, 0x27, 0x01, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x19, 0xC0, ++0x27, 0x00, 0x9F, 0x00, 0x74, 0x02, 0xF0, 0x09, 0x80, 0x5B, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, ++0x21, 0xC0, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC4, 0x07, 0x00, ++0x1F, 0x02, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, ++0xF0, 0x01, 0xC0, 0x87, 0x04, 0x17, 0x00, 0x7C, 0x40, 0xF2, 0x21, 0xC0, 0x04, ++0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0xA0, 0x14, 0x00, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x27, ++0x40, 0x17, 0x00, 0x5D, 0x00, 0xF4, 0x19, 0xD0, 0x05, 0x40, 0x17, 0x00, 0x5D, ++0x00, 0x74, 0x01, 0xD0, 0xC7, 0x40, 0x9F, 0x83, 0x5D, 0x00, 0x74, 0x01, 0xD0, ++0x05, 0x40, 0x5F, 0x01, 0x51, 0x00, 0xF4, 0x01, 0x70, 0x05, 0x40, 0x14, 0x00, ++0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x2C, 0x41, ++0x33, 0x00, 0xCD, 0x00, 0x34, 0x47, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x00, ++0x34, 0x03, 0xD0, 0x2C, 0x40, 0xF3, 0x00, 0xCD, 0x40, 0x34, 0x03, 0xD0, 0x0C, ++0x40, 0x53, 0x08, 0xC5, 0x00, 0x34, 0x00, 0xD0, 0x0C, 0x40, 0x30, 0x00, 0xCD, ++0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0x80, 0x38, 0x00, 0xED, 0x00, 0xB4, 0x13, 0xD0, 0x0E, 0x41, 0x3B, ++0x00, 0xED, 0x00, 0xB4, 0x01, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x04, 0xB4, ++0x13, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, ++0x1B, 0x00, 0xE1, 0x40, 0xB4, 0x09, 0x50, 0x0F, 0x40, 0x38, 0x00, 0xED, 0x00, ++0xB4, 0x03, 0xD0, 0x0E, 0x42, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x10, 0x78, 0x00, 0xEF, 0x01, 0xBC, 0x17, 0xF0, 0x1E, 0xC0, 0x7B, 0x08, ++0xEF, 0x01, 0xBC, 0x07, 0xF0, 0x1E, 0xC2, 0x7B, 0x00, 0xEF, 0x0D, 0xBC, 0x37, ++0xF0, 0x16, 0xC0, 0x7B, 0x00, 0xED, 0x41, 0xBC, 0x07, 0xF0, 0x1E, 0xC0, 0x5B, ++0x00, 0xE7, 0x01, 0xBC, 0x04, 0xF0, 0x0E, 0xC4, 0x78, 0x00, 0xED, 0x01, 0xBC, ++0x07, 0xF0, 0x1E, 0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xB8, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x53, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x08, 0x7C, 0x03, 0xF0, ++0x05, 0xC4, 0x17, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC8, 0x13, 0x10, ++0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC8, 0x37, 0x08, 0xDF, 0x00, 0x7C, 0x03, ++0xF0, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, ++0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x63, 0xF0, 0x17, 0xC0, 0x7F, 0x00, 0xFF, 0x09, ++0xFC, 0x27, 0xF3, 0x1F, 0xC0, 0x7F, 0x00, 0xFF, 0x81, 0xF8, 0x47, 0x30, 0x1F, ++0x48, 0x5F, 0x02, 0xFE, 0x21, 0xFC, 0x07, 0xD0, 0x9F, 0x80, 0x5D, 0x00, 0xF3, ++0x09, 0xFC, 0x27, 0xF0, 0x1F, 0xC0, 0x7F, 0x02, 0xFF, 0x09, 0xFC, 0x07, 0xF0, ++0x1F, 0xC0, 0x1B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x39, ++0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x86, 0x41, 0x3B, 0x00, 0xED, 0x00, 0xB4, ++0x01, 0xC0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x08, 0xB4, 0x03, 0x14, 0x8E, 0x40, ++0x1A, 0x00, 0xE9, 0x00, 0xB4, 0x03, 0xD0, 0x0F, 0x42, 0x1C, 0x05, 0xE5, 0x08, ++0xB4, 0x09, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x8E, ++0x40, 0x57, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, ++0xED, 0x00, 0xB4, 0x23, 0x58, 0x06, 0x40, 0x3B, 0x06, 0xED, 0x80, 0xB0, 0x03, ++0xD1, 0x8E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x3B, ++0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0F, 0x44, 0x3D, 0x00, 0xE5, 0x40, 0xB4, ++0x81, 0xD0, 0x0E, 0x40, 0x3B, 0x20, 0xED, 0x40, 0xB4, 0x23, 0xD0, 0x0E, 0x40, ++0x23, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0x33, 0x00, 0xCD, ++0x00, 0x34, 0x03, 0xD0, 0x00, 0x40, 0xB3, 0x00, 0xCD, 0x00, 0x74, 0x00, 0x90, ++0x1C, 0x40, 0x37, 0x10, 0xCD, 0x02, 0x74, 0x27, 0x10, 0x08, 0x08, 0x02, 0x00, ++0xC9, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x70, 0x00, 0xC5, 0x40, 0x34, 0x01, ++0xD1, 0x0C, 0x40, 0x33, 0x00, 0xCC, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x40, 0x0B, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, 0xDF, 0x00, ++0xFC, 0x03, 0x70, 0x19, 0xC0, 0x77, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x2D, ++0xC3, 0x37, 0x00, 0xFF, 0x44, 0xFC, 0x03, 0x31, 0x09, 0x80, 0x27, 0x10, 0xDE, ++0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x45, 0x00, 0xD7, 0x40, 0x78, 0x01, 0xD0, ++0x0D, 0xC1, 0x37, 0x10, 0xDD, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x57, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x20, 0xDF, 0x00, 0x7C, ++0x03, 0xF0, 0x49, 0xC4, 0x37, 0x04, 0xDF, 0x20, 0x7C, 0x0A, 0xF0, 0x0D, 0xC8, ++0x37, 0x10, 0xDF, 0x10, 0x7C, 0x43, 0xF0, 0x29, 0xC4, 0x26, 0x20, 0xDB, 0x80, ++0x7C, 0x03, 0xF2, 0x0D, 0xC0, 0x87, 0x04, 0xDE, 0x00, 0x7C, 0x09, 0xF1, 0x4D, ++0xC0, 0x37, 0x10, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, ++0xF0, 0x03, 0xC0, 0x3B, 0x00, 0xF3, 0x00, 0xFC, 0x00, 0x30, 0x0F, 0xC1, 0x3F, ++0x08, 0xF3, 0x00, 0x7C, 0x03, 0x30, 0x03, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xBC, ++0x03, 0x34, 0x0F, 0xC0, 0x5F, 0x02, 0xFF, 0x00, 0xFC, 0x05, 0xD0, 0x0F, 0xC4, ++0x3D, 0x00, 0xFF, 0x00, 0xBC, 0x03, 0x30, 0x0F, 0xC4, 0x07, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x03, 0xD0, ++0x79, 0x48, 0x37, 0x30, 0xD1, 0x00, 0x74, 0x1C, 0x10, 0x0D, 0x40, 0x37, 0x00, ++0xD1, 0x00, 0x74, 0x03, 0x10, 0x31, 0x40, 0x67, 0x04, 0xDD, 0x00, 0x74, 0x03, ++0x10, 0x0D, 0x40, 0x17, 0x01, 0xDD, 0x40, 0x74, 0x8D, 0xD0, 0x0C, 0x48, 0x34, ++0x00, 0xDD, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x48, 0x87, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0x74, 0x03, 0xD0, 0x19, ++0x40, 0x37, 0x00, 0xD1, 0x00, 0x74, 0x06, 0x10, 0x0D, 0x40, 0x37, 0x40, 0xD1, ++0x00, 0x74, 0x03, 0x10, 0x11, 0x48, 0x47, 0x20, 0xDD, 0x00, 0x74, 0x03, 0x90, ++0x0D, 0x40, 0x17, 0x00, 0xDC, 0x00, 0x74, 0x11, 0xD0, 0x0D, 0x42, 0x35, 0x00, ++0xDD, 0x40, 0x74, 0x03, 0x10, 0x0D, 0x40, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0xCD, 0x00, 0x34, 0x03, 0xD2, 0x08, 0x40, ++0x33, 0x00, 0xC1, 0x80, 0x34, 0x02, 0x15, 0x0C, 0x40, 0x37, 0x20, 0xC1, 0xC0, ++0x34, 0x03, 0x14, 0x08, 0x44, 0x03, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x90, 0x0C, ++0x40, 0x13, 0x00, 0xCD, 0x00, 0x34, 0x01, 0xD0, 0x0D, 0x44, 0x30, 0x00, 0xCD, ++0x00, 0x34, 0x03, 0x10, 0x0C, 0x48, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xB0, 0x36, 0x00, 0xDF, 0x00, 0xFC, 0x03, 0xF0, 0x01, 0xC4, 0x37, ++0x40, 0xD3, 0x00, 0x7C, 0x02, 0x30, 0x0D, 0xC0, 0x37, 0x00, 0xF3, 0x00, 0xFC, ++0x03, 0x30, 0x01, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, ++0x17, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF8, 0x0D, 0xC0, 0x35, 0x80, 0xDF, 0x00, ++0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x07, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xB8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0x40, 0x3F, 0x20, ++0xFF, 0xC0, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x83, ++0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xF8, 0x03, 0x70, 0x0F, 0xC0, 0x1F, ++0x00, 0xFF, 0x00, 0xFC, 0x01, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x20, 0xFC, ++0x03, 0xF2, 0x0F, 0xC0, 0x17, 0x61, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA0, 0x7F, 0x00, 0xB3, 0x02, 0xCD, 0x27, 0x30, 0x0B, 0xC0, 0x0C, 0x05, 0x3F, ++0x04, 0xFC, 0x07, 0x30, 0x47, 0xC8, 0x3F, 0x05, 0xFF, 0x04, 0xBC, 0xD3, 0x30, ++0x9B, 0xC0, 0x2C, 0x01, 0x23, 0x89, 0xCC, 0x12, 0xF0, 0x03, 0xC8, 0x2C, 0x02, ++0x33, 0x04, 0xFC, 0x07, 0xF0, 0x0F, 0xC0, 0x7C, 0x18, 0xB3, 0x00, 0xCC, 0x04, ++0xF0, 0x1F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, ++0x37, 0x11, 0x91, 0x02, 0x44, 0x03, 0x10, 0x1B, 0x50, 0x84, 0x10, 0x1D, 0x0B, ++0x74, 0x07, 0x14, 0xBD, 0x40, 0xF7, 0x00, 0xFD, 0x49, 0xF4, 0x0F, 0x12, 0x48, ++0x50, 0xFC, 0x40, 0x11, 0x84, 0x44, 0x4A, 0xD0, 0x31, 0x44, 0xAC, 0x23, 0x13, ++0x0A, 0x74, 0x03, 0xD1, 0x04, 0x40, 0x34, 0x00, 0xD1, 0x03, 0x45, 0x05, 0xD0, ++0x1D, 0x40, 0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, ++0x04, 0x91, 0x8C, 0x34, 0x13, 0x14, 0x08, 0x40, 0x20, 0x00, 0x0D, 0x00, 0x34, ++0x03, 0x10, 0x0C, 0x40, 0x23, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x10, 0x08, 0x40, ++0xA0, 0x00, 0x05, 0x00, 0x04, 0x0A, 0xD2, 0x21, 0x40, 0x20, 0x41, 0x81, 0x00, ++0x34, 0x03, 0xD8, 0x08, 0x60, 0x32, 0x10, 0xC1, 0x82, 0x04, 0x00, 0xD0, 0x0C, ++0x40, 0x47, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x40, ++0x91, 0x01, 0x64, 0x03, 0x10, 0x89, 0x40, 0x64, 0x00, 0x1C, 0x11, 0x74, 0x03, ++0x10, 0x1D, 0x40, 0x37, 0x00, 0xDD, 0x00, 0x74, 0x03, 0x14, 0x09, 0x40, 0x34, ++0x00, 0x15, 0x01, 0x45, 0x42, 0xD0, 0x49, 0x40, 0x20, 0xC2, 0x91, 0x03, 0x74, ++0x03, 0xD0, 0x0D, 0x50, 0x36, 0x40, 0xD1, 0x01, 0x46, 0x07, 0xD0, 0x0D, 0x40, ++0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x37, 0x00, 0x83, ++0x01, 0x6C, 0x03, 0x30, 0x08, 0xC0, 0x44, 0x20, 0x1E, 0x01, 0x7C, 0x03, 0x30, ++0x3D, 0xC0, 0x37, 0x00, 0xDF, 0xC0, 0x7C, 0x03, 0x30, 0x99, 0xC0, 0x24, 0x02, ++0x17, 0x81, 0x4C, 0x02, 0xF1, 0x00, 0xD0, 0x24, 0x00, 0x13, 0x01, 0x7C, 0x03, ++0xF0, 0x0D, 0xE0, 0x36, 0x00, 0x93, 0x01, 0x4C, 0x04, 0xF2, 0x0D, 0xC2, 0x0B, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xBF, 0x00, ++0xDC, 0x03, 0xF0, 0x19, 0xC0, 0x0F, 0x10, 0x3F, 0x00, 0xF4, 0x03, 0xF1, 0x0D, ++0xC0, 0x7F, 0x12, 0xFF, 0x10, 0xBC, 0x03, 0xC0, 0x0B, 0xC0, 0x7F, 0x20, 0x3B, ++0x00, 0xF8, 0x26, 0xE1, 0x03, 0xC0, 0x27, 0x00, 0x14, 0x00, 0xFC, 0x03, 0xF0, ++0x5F, 0xC0, 0xBD, 0x00, 0xEF, 0x00, 0xFC, 0x81, 0xF1, 0x0F, 0xC0, 0x1F, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0x93, 0x04, 0x4C, ++0x13, 0xF0, 0x09, 0xC4, 0x24, 0x00, 0x13, 0x02, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, ++0x24, 0x00, 0xDF, 0x40, 0x4C, 0x03, 0xB0, 0x09, 0xC8, 0x20, 0x40, 0x13, 0x02, ++0x6C, 0x0E, 0xB0, 0x03, 0xC0, 0x37, 0x00, 0x93, 0x06, 0x6C, 0x03, 0xD0, 0x08, ++0xC0, 0x34, 0x80, 0x5F, 0x00, 0x7C, 0x00, 0x30, 0x0D, 0xC0, 0x0B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x30, 0x00, 0x91, 0x00, 0x44, 0x0B, ++0xD0, 0x09, 0x50, 0x64, 0x08, 0x91, 0x00, 0x34, 0x2B, 0xD0, 0x0D, 0x40, 0xB4, ++0x02, 0xFD, 0x06, 0xC5, 0x6F, 0x10, 0x49, 0x54, 0xB4, 0x03, 0x10, 0x24, 0x44, ++0x06, 0x10, 0xB9, 0x45, 0x37, 0x00, 0x91, 0x83, 0x44, 0x03, 0xD1, 0xAD, 0x40, ++0xB4, 0x02, 0xDD, 0x00, 0x74, 0x47, 0x10, 0x1D, 0x43, 0x4F, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x72, 0x00, 0xC1, 0x02, 0x44, 0x8B, 0xD0, ++0x68, 0x40, 0x60, 0x00, 0x05, 0x00, 0x34, 0x03, 0xD0, 0x08, 0x40, 0x12, 0x20, ++0xCD, 0x02, 0x04, 0x03, 0x90, 0x09, 0x48, 0xF0, 0x10, 0x11, 0x20, 0x04, 0x4A, ++0x92, 0x10, 0x40, 0x23, 0x20, 0x09, 0x00, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x36, ++0x10, 0xC5, 0x08, 0x34, 0x04, 0x10, 0x0C, 0x40, 0x1F, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x80, 0x78, 0x40, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x9E, ++0x40, 0x68, 0x04, 0x25, 0x01, 0xB4, 0x07, 0xD1, 0x1A, 0x50, 0x58, 0x00, 0xCD, ++0x89, 0x84, 0x07, 0x10, 0x9A, 0x40, 0x78, 0x00, 0x31, 0x29, 0x85, 0x04, 0x10, ++0x12, 0x40, 0x6B, 0x08, 0xA9, 0x01, 0x84, 0x07, 0xD0, 0x16, 0x50, 0x7A, 0x80, ++0xED, 0x41, 0xB4, 0x05, 0x10, 0x1E, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x10, 0x30, 0x04, 0x53, 0x00, 0x0E, 0x03, 0xF0, 0x08, 0xD0, ++0xA4, 0x40, 0x07, 0x08, 0x3C, 0x03, 0xF0, 0x0C, 0xC0, 0x30, 0x02, 0xCF, 0x00, ++0x0C, 0x03, 0xB0, 0x08, 0xC0, 0x30, 0x00, 0x03, 0x4A, 0x6C, 0x02, 0xB0, 0x00, ++0xC0, 0x33, 0x41, 0xCB, 0x10, 0x2C, 0x23, 0xF0, 0x0C, 0xD0, 0x32, 0x02, 0xCF, ++0x00, 0x3C, 0x00, 0x34, 0x0C, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xB8, 0x39, 0x00, 0xFF, 0x00, 0xFD, 0x03, 0xF0, 0x0B, 0xC0, 0x2F, ++0x10, 0x7B, 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, ++0x03, 0xF0, 0x0B, 0xC4, 0x3B, 0x00, 0x3F, 0x28, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, ++0x3F, 0x00, 0xF7, 0x00, 0xFC, 0x83, 0xF0, 0x0F, 0xD0, 0x3D, 0x00, 0xFF, 0x08, ++0xBC, 0x03, 0xF0, 0x0F, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0xA0, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF0, 0x49, 0xD0, 0x2C, 0x00, ++0x33, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC8, 0x37, 0x00, 0xDF, 0x04, 0x5C, 0x4F, ++0x30, 0x09, 0xC0, 0xB5, 0x00, 0x13, 0x00, 0x6C, 0x02, 0xF2, 0x01, 0xC0, 0xA7, ++0x01, 0xD3, 0x00, 0x5C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, ++0x00, 0xF0, 0x0D, 0xC0, 0x57, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x88, 0x39, 0x00, 0xAD, 0x40, 0xB4, 0x03, 0xD0, 0x8C, 0x44, 0x28, 0x00, 0x2B, ++0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xCD, 0x0E, 0x04, 0x03, 0x10, ++0x0E, 0x40, 0x30, 0x02, 0x61, 0x00, 0x86, 0x00, 0xD0, 0x02, 0x44, 0x23, 0x04, ++0xF1, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x10, 0xED, 0x00, 0xB4, 0x01, ++0xD0, 0x0E, 0x40, 0x4B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, ++0x79, 0x00, 0xAD, 0x01, 0xB4, 0x07, 0xD0, 0x1A, 0x40, 0x60, 0x00, 0xA1, 0x41, ++0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x05, 0x94, 0x37, 0x10, 0x3B, ++0x40, 0x79, 0x08, 0x29, 0x11, 0x84, 0x06, 0xD0, 0x12, 0x40, 0xFB, 0x00, 0xE1, ++0x81, 0x94, 0x87, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0xED, 0x01, 0xB4, 0x05, 0xD0, ++0x1E, 0x40, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, ++0x10, 0x8D, 0x09, 0x34, 0x03, 0xD0, 0x9C, 0x50, 0x70, 0x00, 0xC9, 0x06, 0x34, ++0x03, 0xD0, 0x3C, 0x40, 0xB3, 0x04, 0xCD, 0x00, 0x04, 0x03, 0x14, 0x1C, 0x40, ++0x30, 0xC0, 0x99, 0x06, 0x05, 0x01, 0xD1, 0x0C, 0x44, 0x73, 0x20, 0xC1, 0x03, ++0x04, 0x03, 0xD1, 0x0D, 0x41, 0x63, 0x00, 0xCD, 0x06, 0x34, 0x07, 0xD0, 0x0C, ++0x40, 0x4B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, 0x00, ++0x7F, 0x02, 0x7C, 0x01, 0xF0, 0x04, 0xC0, 0x58, 0x01, 0x73, 0x02, 0x7C, 0x01, ++0xF0, 0x16, 0xC0, 0x9F, 0x10, 0x5F, 0x00, 0x5C, 0x01, 0x30, 0x04, 0xC4, 0x15, ++0x00, 0x7B, 0x00, 0xCC, 0x45, 0xF1, 0x07, 0xC0, 0x17, 0x48, 0x73, 0x05, 0x5C, ++0x01, 0xF0, 0x27, 0xC0, 0x57, 0x00, 0x7F, 0x02, 0xFC, 0x05, 0xF0, 0x05, 0xC0, ++0x5F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, ++0x00, 0x7C, 0x00, 0xF0, 0x01, 0xD0, 0x07, 0x10, 0x1F, 0x00, 0x7C, 0x00, 0xF0, ++0x81, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x01, 0xC0, 0x07, 0x00, ++0x17, 0x00, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x10, 0x7C, 0x00, ++0xF0, 0x01, 0xC0, 0x07, 0x12, 0x1F, 0x00, 0x7C, 0x20, 0xF0, 0x01, 0xC0, 0x4B, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x93, 0x11, ++0x4C, 0x22, 0xF0, 0x09, 0xC0, 0x64, 0x00, 0x93, 0x02, 0x7C, 0x02, 0xF0, 0x09, ++0xC1, 0x20, 0x00, 0x83, 0x00, 0x6D, 0x0E, 0xF0, 0x59, 0xC0, 0x20, 0x00, 0x91, ++0x40, 0x4C, 0x02, 0x10, 0x89, 0xC0, 0x24, 0x00, 0x83, 0x08, 0x4C, 0x02, 0xF0, ++0x19, 0xC0, 0x64, 0x01, 0x90, 0x00, 0x7C, 0x02, 0x30, 0x19, 0xC0, 0x43, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xA6, 0x02, 0x91, 0x01, 0x44, ++0x06, 0xD0, 0x39, 0x41, 0x64, 0x10, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x50, ++0x24, 0x40, 0x91, 0x40, 0x44, 0x02, 0xD0, 0x19, 0x44, 0xE4, 0x40, 0x91, 0x01, ++0x04, 0x02, 0x15, 0x08, 0x40, 0x20, 0x00, 0x9B, 0x03, 0x44, 0x02, 0xD0, 0x19, ++0x40, 0x20, 0x20, 0x91, 0x09, 0x34, 0x02, 0x10, 0x19, 0x40, 0x07, 0x00, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x20, 0x44, 0xC1, 0x04, 0x45, 0x02, ++0xD0, 0x49, 0x40, 0x24, 0x01, 0x91, 0x00, 0x74, 0x02, 0xD0, 0x0D, 0x50, 0x34, ++0x10, 0x99, 0x00, 0x65, 0x02, 0xC0, 0x09, 0x40, 0x24, 0x01, 0x95, 0x04, 0x44, ++0x12, 0x51, 0x29, 0x50, 0x24, 0x20, 0x91, 0x00, 0x44, 0x02, 0xD0, 0x49, 0x50, ++0x24, 0x40, 0xDD, 0x80, 0x74, 0x12, 0x10, 0x89, 0x40, 0x63, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x81, 0x04, 0x04, 0x02, 0xD0, ++0x48, 0x40, 0x20, 0x01, 0x81, 0x04, 0x34, 0x02, 0xD0, 0x49, 0x40, 0x20, 0x01, ++0x89, 0x04, 0x04, 0x13, 0xD0, 0x08, 0x40, 0x60, 0x81, 0x85, 0x20, 0x46, 0x12, ++0x50, 0x48, 0x40, 0x24, 0x01, 0xC9, 0x04, 0x04, 0x02, 0xD0, 0x48, 0x40, 0x24, ++0x00, 0x8D, 0x04, 0x74, 0x02, 0x14, 0x08, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xB0, 0x86, 0x02, 0x13, 0x0A, 0x4C, 0x29, 0xF0, 0x01, ++0xC0, 0x84, 0x02, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x1B, ++0x00, 0x6C, 0x00, 0xD2, 0xA1, 0xC0, 0x04, 0x20, 0x07, 0x2A, 0x4C, 0x28, 0x70, ++0x01, 0xD0, 0x84, 0x42, 0x13, 0x0A, 0x4D, 0x28, 0xF0, 0xA1, 0xC0, 0x84, 0x02, ++0x1F, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x19, 0xB8, 0x27, 0x00, 0xBF, 0x08, 0x7C, 0x02, 0xF0, 0x8B, 0xD0, ++0x2F, 0x42, 0xBF, 0x08, 0x7C, 0x02, 0xF0, 0x8B, 0xD0, 0x2F, 0x02, 0x97, 0x08, ++0x7C, 0x22, 0xF0, 0x0A, 0xD0, 0x2F, 0x22, 0xBB, 0x00, 0xFD, 0x22, 0xB0, 0x8B, ++0xD0, 0x2F, 0x02, 0xBF, 0x08, 0x7C, 0x02, 0xF0, 0x8B, 0xC0, 0x2F, 0x10, 0xB3, ++0x08, 0xFC, 0x02, 0xF0, 0x09, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x2F, 0x00, 0xB7, 0x0C, 0xCC, 0x02, 0xF0, 0x0B, 0xC0, 0x2C, ++0x02, 0xB3, 0x04, 0x3C, 0x02, 0xF0, 0x49, 0xC0, 0x24, 0x00, 0x9F, 0x01, 0xCC, ++0x16, 0x30, 0x0A, 0xC0, 0x6C, 0x28, 0xBF, 0x00, 0xCC, 0x1E, 0x30, 0x5B, 0xC0, ++0x6F, 0x41, 0xB3, 0x05, 0xCC, 0x02, 0xF0, 0xCB, 0xC0, 0x2C, 0x00, 0xB3, 0x00, ++0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x60, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1C, 0x08, 0x07, 0x01, 0x11, 0x0C, 0x6C, 0x40, 0xD0, 0x01, 0x40, 0x04, 0x02, ++0x11, 0x00, 0x74, 0x00, 0xD0, 0x81, 0x40, 0x84, 0x10, 0x3D, 0x02, 0x45, 0x08, ++0xB0, 0x51, 0x40, 0x04, 0x00, 0x1D, 0x15, 0x45, 0x14, 0x10, 0x01, 0x40, 0xC3, ++0x15, 0x11, 0x14, 0x44, 0x10, 0xD1, 0xC1, 0x40, 0x04, 0x04, 0x11, 0x00, 0x74, ++0x00, 0xD0, 0x01, 0x40, 0x70, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA0, 0x23, 0x05, 0x85, 0x04, 0x04, 0x12, 0xD0, 0x88, 0x40, 0x70, 0x60, 0x81, ++0x08, 0xB4, 0x02, 0xD0, 0x1A, 0x50, 0x6A, 0x02, 0xAD, 0x02, 0x04, 0x22, 0x10, ++0x08, 0x61, 0xA0, 0x00, 0x8D, 0x81, 0x04, 0x1A, 0x90, 0x38, 0x40, 0x23, 0x42, ++0x81, 0x06, 0x04, 0x52, 0xD1, 0x58, 0x40, 0x20, 0x41, 0xC1, 0x08, 0x34, 0x06, ++0xD0, 0x0C, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, ++0x21, 0x00, 0x91, 0x10, 0x64, 0x02, 0xD0, 0x89, 0x10, 0x20, 0x01, 0x91, 0x04, ++0x74, 0x02, 0xD0, 0x0B, 0x40, 0x2E, 0x01, 0xBD, 0x00, 0x44, 0x02, 0x90, 0x09, ++0x60, 0x24, 0x00, 0x9D, 0x40, 0x44, 0x02, 0x90, 0x09, 0x40, 0x27, 0x20, 0x91, ++0x04, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x30, 0x00, 0x91, 0x11, 0x74, 0x02, 0xD0, ++0x09, 0x40, 0x60, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, 0x25, ++0x00, 0x97, 0x00, 0x4C, 0x02, 0xF0, 0x19, 0xC0, 0x24, 0x00, 0x93, 0x05, 0x7C, ++0x02, 0xF0, 0x09, 0xC0, 0xA6, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x30, 0x09, 0xD0, ++0x24, 0x20, 0x9F, 0x02, 0x4C, 0x06, 0xB0, 0x29, 0xE0, 0x67, 0x02, 0x93, 0x04, ++0x4D, 0x02, 0xF0, 0x19, 0xD0, 0x64, 0x00, 0x93, 0x03, 0x7C, 0x02, 0xF2, 0x09, ++0xD0, 0x14, 0xA0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x25, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x10, 0x9F, 0x01, 0x7C, 0x02, ++0xF0, 0x98, 0xC0, 0x25, 0x00, 0x9F, 0x40, 0x7C, 0x02, 0xF2, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x09, 0x7C, 0x0E, 0x70, 0x89, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x39, 0xC0, 0xE7, 0x00, 0x9F, 0x40, 0x7C, 0x12, 0xF0, 0x09, 0xC0, ++0x53, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x0F, ++0x03, 0x4D, 0x04, 0xF0, 0x11, 0xC0, 0x04, 0x00, 0x13, 0x00, 0x7C, 0x00, 0x30, ++0x11, 0xC0, 0x07, 0x00, 0x13, 0x00, 0x2C, 0x00, 0xF8, 0x01, 0xC1, 0x06, 0x04, ++0x13, 0x00, 0x0C, 0x40, 0xF0, 0x01, 0xC0, 0x04, 0x02, 0x13, 0x02, 0x7C, 0x00, ++0xF0, 0x41, 0xC0, 0x44, 0x02, 0x13, 0x02, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x53, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0xDC, 0x00, 0x7D, 0x01, ++0xC4, 0x15, 0x70, 0x16, 0x40, 0x9C, 0x00, 0x51, 0x01, 0x74, 0x01, 0x14, 0x05, ++0x40, 0x57, 0x00, 0x41, 0x00, 0xC4, 0x41, 0xD0, 0x07, 0x40, 0x1C, 0x20, 0x51, ++0x04, 0xC4, 0x09, 0xD1, 0x57, 0x40, 0x14, 0x10, 0x7B, 0x00, 0x74, 0x01, 0xD0, ++0x37, 0x40, 0x1C, 0x00, 0x51, 0x00, 0x45, 0x01, 0xD0, 0x04, 0x40, 0x53, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0xE2, 0x04, 0xCD, 0x01, 0x04, ++0x03, 0x50, 0x1C, 0x40, 0xB1, 0x04, 0x81, 0x01, 0x34, 0x03, 0x10, 0x0C, 0x40, ++0x73, 0x00, 0xC1, 0x00, 0x24, 0x13, 0xD0, 0x2D, 0x40, 0x72, 0x00, 0xD1, 0x40, ++0x04, 0x2A, 0x58, 0x7C, 0x40, 0x34, 0x00, 0xD1, 0x00, 0x34, 0x27, 0xD0, 0x0D, ++0x40, 0x30, 0x00, 0x81, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x53, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x04, 0xFD, 0x10, 0x84, 0x03, ++0x50, 0x06, 0x41, 0x29, 0x01, 0xA1, 0x10, 0xB4, 0x05, 0x10, 0x0E, 0x40, 0x53, ++0x04, 0x01, 0x00, 0x84, 0x00, 0xD0, 0x0B, 0x40, 0x4A, 0xC4, 0xA1, 0x00, 0x84, ++0x05, 0xD0, 0x12, 0x40, 0x38, 0x00, 0xE9, 0x00, 0xB4, 0x03, 0xD0, 0x2E, 0x40, ++0x38, 0x00, 0xC1, 0x01, 0x84, 0x03, 0xD0, 0x0E, 0x40, 0x17, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x68, 0x00, 0xEF, 0x01, 0x8C, 0x07, 0x70, ++0x10, 0xC0, 0xFD, 0x40, 0xE3, 0x01, 0xBC, 0x07, 0x30, 0x1E, 0xC0, 0x7B, 0x40, ++0xE3, 0x01, 0xAC, 0x04, 0xD0, 0x1A, 0xC0, 0x42, 0x00, 0xA3, 0x01, 0x8D, 0x02, ++0x78, 0x10, 0xC0, 0x78, 0x04, 0xE3, 0x01, 0xBC, 0x07, 0xF0, 0x1F, 0xC0, 0x7C, ++0x00, 0xE1, 0x01, 0x8C, 0x07, 0xF0, 0x1A, 0xC0, 0x57, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xB8, 0x25, 0x00, 0xCF, 0x00, 0x7C, 0x03, 0x70, 0x01, ++0xD0, 0x26, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC0, 0x17, 0x00, 0x1F, ++0x00, 0x7C, 0x00, 0xF0, 0x09, 0xC0, 0x05, 0x00, 0x8F, 0x02, 0xFC, 0x00, 0xF0, ++0x01, 0xD0, 0xB7, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xD0, 0x37, 0x50, ++0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xA0, 0x6B, 0x00, 0xF3, 0x01, 0xCC, 0x23, 0xB4, 0x13, 0xC0, ++0x6C, 0x20, 0xF3, 0x01, 0xCC, 0x07, 0xF0, 0x16, 0xC0, 0x6C, 0x00, 0xF3, 0x01, ++0xBC, 0x04, 0x30, 0x1F, 0xD0, 0x4D, 0x00, 0xF3, 0x03, 0xCC, 0x24, 0xF0, 0x13, ++0xC0, 0x7F, 0x08, 0xF3, 0x01, 0xDC, 0x06, 0x30, 0x1F, 0xC0, 0x7C, 0x10, 0xF3, ++0x81, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0x80, 0xB9, 0x00, 0x71, 0x02, 0x84, 0x03, 0x10, 0x02, 0x40, 0x28, ++0x00, 0xE1, 0x00, 0xAC, 0x01, 0xC0, 0x06, 0xC0, 0x08, 0x00, 0x21, 0x00, 0x84, ++0x08, 0x00, 0x4B, 0x40, 0x08, 0x01, 0xA5, 0x04, 0x94, 0x00, 0xD0, 0x02, 0xC0, ++0x39, 0x00, 0xE5, 0x02, 0xC4, 0x02, 0x50, 0x0E, 0x40, 0x1C, 0x00, 0xE1, 0x14, ++0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x08, 0x09, 0x00, 0xE1, 0x00, 0x84, 0x22, 0x18, 0x02, 0x41, 0x38, 0x00, ++0xA1, 0x10, 0x84, 0x03, 0xD0, 0x26, 0x40, 0x20, 0x00, 0xC1, 0x00, 0x94, 0x00, ++0x10, 0x0A, 0x45, 0x09, 0x20, 0xE1, 0x80, 0x84, 0x08, 0xD8, 0x02, 0x40, 0x33, ++0x00, 0xE1, 0x00, 0x94, 0x02, 0x10, 0x0C, 0x40, 0x38, 0x00, 0xE1, 0x00, 0xB4, ++0x0B, 0xD0, 0x0E, 0x40, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, ++0x28, 0x13, 0x00, 0x41, 0x00, 0x44, 0x02, 0x14, 0x00, 0x40, 0x20, 0x02, 0x81, ++0x01, 0x24, 0x01, 0xD0, 0x04, 0x40, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x14, ++0x18, 0x40, 0x40, 0x0A, 0x81, 0x53, 0x14, 0x04, 0xD0, 0x30, 0x40, 0x31, 0x20, ++0xC5, 0x02, 0x04, 0x02, 0x50, 0x2C, 0x40, 0x50, 0x00, 0xC1, 0x00, 0x34, 0x23, ++0xD0, 0x0C, 0x40, 0x13, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, ++0x21, 0x00, 0xD3, 0x02, 0x4C, 0x03, 0x34, 0x01, 0xD0, 0x1C, 0x50, 0x83, 0x03, ++0x4D, 0x02, 0xF0, 0x09, 0xC0, 0x74, 0x40, 0xD3, 0x00, 0x5C, 0x00, 0x30, 0x1D, ++0xC8, 0x45, 0xE0, 0x93, 0x05, 0x0C, 0x12, 0xF0, 0x69, 0xC0, 0x37, 0x00, 0xD3, ++0x02, 0x5C, 0x02, 0x31, 0x0D, 0xC4, 0x74, 0x24, 0xD3, 0x80, 0x7C, 0x07, 0xF0, ++0x0D, 0xC0, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xA7, ++0x40, 0xDF, 0x42, 0x7C, 0x03, 0x70, 0x01, 0xC0, 0x97, 0x08, 0x9F, 0x10, 0x5C, ++0x00, 0xF0, 0x09, 0xC0, 0x51, 0x00, 0x1F, 0x00, 0x5C, 0x08, 0xF0, 0x0D, 0xC0, ++0x83, 0x00, 0x9F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x02, 0xF0, 0x75, 0xD0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x0D, ++0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x6F, 0x21, ++0xB3, 0x90, 0xCC, 0x03, 0x30, 0x00, 0xC0, 0x1C, 0x00, 0xDF, 0x00, 0xCC, 0x06, ++0xF0, 0x0B, 0xC0, 0x3C, 0x00, 0xF3, 0x00, 0x8C, 0x04, 0x30, 0x4B, 0xC8, 0x04, ++0x00, 0xBD, 0x05, 0xFC, 0x02, 0x10, 0x03, 0xC1, 0x7B, 0x00, 0x33, 0x19, 0xCC, ++0x02, 0xF0, 0x0A, 0xC0, 0x2C, 0x00, 0xF1, 0x10, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x03, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xE6, 0x40, 0x91, ++0x02, 0x44, 0x07, 0x10, 0x11, 0x40, 0x94, 0x02, 0xDD, 0x00, 0x44, 0x00, 0xD0, ++0x08, 0x40, 0x14, 0x00, 0x01, 0x00, 0x44, 0x00, 0x10, 0x49, 0x40, 0xC4, 0x00, ++0x91, 0x00, 0x64, 0x04, 0x10, 0x11, 0x40, 0x37, 0x12, 0xD5, 0x03, 0x44, 0x06, ++0xD0, 0x11, 0x50, 0xA4, 0x00, 0xD1, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0x40, 0x07, ++0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x26, 0x00, 0xC1, 0x01, ++0x44, 0x07, 0x92, 0x11, 0x40, 0xA4, 0x00, 0xDD, 0x00, 0x44, 0x22, 0x50, 0x11, ++0x40, 0x24, 0x00, 0xD1, 0x00, 0x44, 0x20, 0x14, 0x04, 0x40, 0x44, 0x04, 0x91, ++0x00, 0x74, 0x04, 0xD0, 0x11, 0x44, 0x27, 0x00, 0xC1, 0x00, 0x44, 0x12, 0xD0, ++0x4D, 0x51, 0x70, 0x00, 0xD5, 0x01, 0x74, 0x07, 0xD0, 0x1D, 0x48, 0x07, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0xC1, 0x00, 0x04, ++0x07, 0x90, 0x10, 0x50, 0x20, 0x00, 0xCD, 0x00, 0x05, 0x00, 0xD0, 0x00, 0x40, ++0x00, 0x40, 0x01, 0x00, 0x06, 0x00, 0x50, 0x04, 0x40, 0x00, 0x00, 0x81, 0x00, ++0x64, 0x00, 0xD0, 0x00, 0x00, 0x23, 0x40, 0xC5, 0x20, 0x04, 0x02, 0xD0, 0x0C, ++0x48, 0x30, 0x00, 0xC5, 0x00, 0x34, 0x02, 0xD0, 0x0C, 0x40, 0x43, 0x80, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x26, 0x00, 0xD3, 0x40, 0x4C, 0x03, ++0xB4, 0x01, 0xC0, 0x30, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x70, 0x01, 0xC0, 0x24, ++0x20, 0xD3, 0x00, 0x4D, 0x00, 0x30, 0x01, 0xC0, 0x04, 0x00, 0xAB, 0x00, 0x7C, ++0x00, 0xF4, 0x01, 0xC8, 0x2F, 0x40, 0x03, 0x00, 0x4D, 0x02, 0xF0, 0x0D, 0xC0, ++0x34, 0x00, 0xD7, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0x80, 0x03, 0xC0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x2F, 0x00, 0xFF, 0x00, 0xBC, 0x01, 0x70, ++0x03, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, ++0x3F, 0x00, 0xFC, 0x00, 0x91, 0x03, 0xC0, 0x0F, 0x10, 0xBB, 0x00, 0xEC, 0x00, ++0x30, 0x03, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, ++0x00, 0xFB, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xA3, 0x80, 0xC0, 0x0E, 0x02, 0x3A, 0x08, 0xE8, 0x28, ++0xB8, 0xA3, 0xC0, 0x8E, 0x02, 0x3A, 0x08, 0xEC, 0x28, 0xA0, 0x83, 0xE0, 0x8E, ++0x82, 0x3B, 0x0A, 0xEC, 0x28, 0xA8, 0x83, 0xC0, 0x8E, 0x82, 0x3B, 0x0E, 0xE6, ++0x28, 0xA0, 0x83, 0xE0, 0x8E, 0x82, 0x3B, 0x0A, 0xEC, 0x20, 0xB8, 0x83, 0xE0, ++0x0E, 0x82, 0x3A, 0x0A, 0xEE, 0x20, 0xB0, 0x03, 0x8C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x83, 0x22, 0x20, 0x8E, 0x80, 0x3B, 0x02, 0xCA, 0x08, 0xA8, ++0x23, 0xA0, 0x8E, 0x80, 0x3A, 0x02, 0xE8, 0x08, 0xA8, 0x23, 0xE0, 0x8E, 0x00, ++0x13, 0x02, 0xE8, 0x08, 0xA8, 0x23, 0xA0, 0x84, 0x00, 0x3B, 0x02, 0xEC, 0x08, ++0x28, 0x23, 0xE0, 0x8A, 0x00, 0x39, 0x02, 0xE8, 0x08, 0xBA, 0x23, 0x40, 0x84, ++0x80, 0x3B, 0x00, 0xEE, 0x08, 0xA8, 0x03, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x21, 0x40, 0x80, 0x04, 0x01, 0x12, 0x04, 0x40, 0x10, 0x20, 0x41, ++0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, 0x84, 0x01, 0x12, ++0x06, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x06, 0x48, 0x10, 0x00, ++0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, 0x01, ++0x12, 0x04, 0x48, 0x10, 0x20, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x83, 0x00, 0x80, 0x0E, 0x00, 0x1A, 0x00, 0x6A, 0x08, 0xA2, 0x61, 0x80, ++0x86, 0xA0, 0x1A, 0x00, 0x28, 0x08, 0xA8, 0x01, 0x80, 0x06, 0x00, 0x1A, 0x80, ++0x68, 0x08, 0xAA, 0x01, 0x80, 0x86, 0x01, 0x1A, 0x00, 0x68, 0x08, 0xA8, 0x00, ++0x80, 0x86, 0x00, 0x3A, 0x02, 0x68, 0x00, 0xA0, 0x01, 0x80, 0x0E, 0x00, 0x0A, ++0x04, 0x60, 0x00, 0xA0, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA0, 0x12, 0xA0, 0x4E, 0x80, 0x3A, 0x01, 0xEA, 0x04, 0xA0, 0x13, 0xA0, 0x4E, ++0x81, 0x3A, 0x01, 0xE8, 0x04, 0xA8, 0x13, 0xA0, 0xCE, 0x80, 0x3A, 0x01, 0xE8, ++0x34, 0xA8, 0x13, 0xA0, 0xCE, 0x80, 0x3A, 0x01, 0xEA, 0x04, 0xA8, 0x13, 0xA0, ++0x4E, 0x80, 0x2A, 0x01, 0xA8, 0x04, 0xA8, 0x12, 0xA0, 0x4E, 0x80, 0x32, 0x01, ++0xEA, 0x04, 0xA8, 0x03, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, ++0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x00, 0x00, 0x06, 0x00, ++0x18, 0x01, 0x62, 0x00, 0x80, 0x81, 0x00, 0x06, 0x01, 0x18, 0x00, 0x42, 0x00, ++0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x08, 0x60, 0x10, 0x80, 0x01, 0x00, 0x06, ++0x03, 0x18, 0x00, 0x62, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, ++0x00, 0x80, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x82, ++0x20, 0x04, 0x80, 0x10, 0x00, 0x42, 0x14, 0x00, 0x10, 0x20, 0x84, 0x80, 0x10, ++0x08, 0x42, 0x10, 0x08, 0x11, 0x20, 0x04, 0x80, 0x10, 0x0C, 0x42, 0x08, 0x08, ++0x11, 0x20, 0x04, 0x80, 0x10, 0x00, 0x42, 0x00, 0x08, 0x11, 0x20, 0x04, 0x80, ++0x10, 0x04, 0x42, 0x04, 0x08, 0x01, 0x20, 0x04, 0x80, 0x10, 0x01, 0x42, 0x04, ++0x08, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0xF2, 0xA0, ++0x02, 0x03, 0x0A, 0x04, 0x28, 0x1C, 0xAA, 0x50, 0xA0, 0x02, 0x01, 0x0A, 0x06, ++0x2A, 0x10, 0xA0, 0xD0, 0x80, 0x02, 0x01, 0x0A, 0x04, 0x0A, 0x30, 0xA0, 0x50, ++0xA0, 0x02, 0x01, 0x0A, 0x0E, 0x28, 0x10, 0xA0, 0x50, 0x80, 0x82, 0x01, 0x0A, ++0x04, 0x2A, 0x14, 0xA0, 0x40, 0x80, 0x02, 0x01, 0x2A, 0x05, 0x28, 0x3C, 0xA8, ++0x00, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x80, 0xC8, ++0x00, 0xA2, 0x03, 0xA8, 0x2E, 0xA0, 0x32, 0x80, 0xEA, 0x00, 0xAA, 0x03, 0x08, ++0x0C, 0xA0, 0x3A, 0x80, 0x6A, 0x00, 0x82, 0x01, 0x08, 0x0C, 0x20, 0x3A, 0x80, ++0x6A, 0x00, 0x82, 0x03, 0x08, 0x0C, 0xA0, 0x3A, 0x80, 0xEA, 0x01, 0xA2, 0x03, ++0x08, 0x0E, 0xA0, 0x3A, 0x80, 0xE0, 0x00, 0xAA, 0x03, 0x08, 0x1C, 0x20, 0x02, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x00, 0x08, 0x80, ++0x30, 0x01, 0x20, 0x18, 0x80, 0x00, 0x00, 0xC2, 0x01, 0x08, 0x02, 0x00, 0x04, ++0x80, 0x00, 0x00, 0x82, 0x00, 0x00, 0x02, 0x00, 0x08, 0x08, 0x02, 0x00, 0x82, ++0x00, 0x10, 0x06, 0x00, 0x04, 0x80, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x80, 0x00, 0x00, 0x44, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x82, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x16, 0x40, 0x18, 0x00, 0x61, ++0x00, 0x04, 0x21, 0x10, 0x04, 0x40, 0x10, 0x00, 0x41, 0x01, 0x06, 0x01, 0x10, ++0x04, 0x40, 0x10, 0x80, 0x41, 0x00, 0x06, 0x01, 0x10, 0x06, 0x40, 0x10, 0x80, ++0x41, 0x00, 0x06, 0x01, 0x10, 0x04, 0x40, 0x10, 0x80, 0x41, 0x00, 0x06, 0x01, ++0x10, 0x04, 0x60, 0x14, 0x00, 0x41, 0x00, 0x04, 0x01, 0x10, 0x82, 0x8C, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x02, 0xA0, 0x06, 0x80, 0x9A, 0x00, ++0x6D, 0x02, 0xA0, 0x01, 0xA0, 0x26, 0x40, 0x9B, 0x00, 0x4A, 0x00, 0xB0, 0x09, ++0x88, 0x26, 0x80, 0x92, 0x00, 0x48, 0x00, 0x80, 0x09, 0xA0, 0x26, 0x40, 0x92, ++0x00, 0x48, 0x00, 0xB0, 0x09, 0x80, 0x26, 0x80, 0x9A, 0x00, 0x4A, 0x02, 0xA8, ++0x09, 0xA0, 0x24, 0x80, 0x9B, 0x00, 0x4A, 0x00, 0xA8, 0x01, 0x8C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x02, 0xC0, 0x06, 0x00, 0x1A, 0x01, 0x68, ++0x00, 0xB0, 0x01, 0xC0, 0x46, 0x80, 0x1A, 0x00, 0x6E, 0x04, 0xA8, 0x01, 0xC0, ++0x06, 0x80, 0x1B, 0x00, 0x6A, 0x00, 0xB0, 0x01, 0xE0, 0x06, 0x80, 0x1B, 0x00, ++0x6E, 0x04, 0xA8, 0x01, 0xC8, 0x06, 0x00, 0x1A, 0x00, 0x6E, 0x00, 0xB0, 0x01, ++0xE0, 0x46, 0x80, 0x1A, 0x00, 0x6E, 0x00, 0xB0, 0x01, 0x8C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xA3, 0x42, 0x20, 0x0C, 0x81, 0x31, 0x0C, 0x82, 0x10, ++0x08, 0x43, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC0, 0x30, 0x08, 0x43, 0x20, 0x0C, ++0x01, 0x30, 0x0C, 0xC2, 0x30, 0x10, 0x43, 0x20, 0x0C, 0x03, 0x30, 0x0C, 0xC0, ++0x30, 0x08, 0x43, 0x20, 0x0C, 0x81, 0x30, 0x0C, 0xC0, 0x10, 0x08, 0x43, 0x00, ++0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, 0x03, 0x8C, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, ++0x03, 0x00, 0x0C, 0x00, 0x30, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x4C, 0x00, ++0x30, 0x01, 0xC0, 0x04, 0x00, 0x03, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC0, 0x00, ++0x00, 0x03, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC0, 0x00, 0x00, 0x13, 0x08, 0x08, ++0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x21, 0x40, 0x80, 0x4C, 0x23, 0x32, 0x04, 0xCA, 0x10, 0x20, 0x43, ++0x80, 0x0C, 0x03, 0x32, 0x0C, 0xCA, 0x10, 0x20, 0x43, 0x88, 0x4C, 0x23, 0x32, ++0x05, 0xC8, 0x14, 0x20, 0x43, 0x80, 0x4C, 0x81, 0x32, 0x05, 0xCA, 0x10, 0x20, ++0x43, 0x80, 0x48, 0x03, 0x32, 0x05, 0x88, 0x10, 0x20, 0xD3, 0xA0, 0x0C, 0x03, ++0x32, 0x04, 0xCA, 0x10, 0x20, 0x03, 0x84, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA2, 0x42, 0xA0, 0x06, 0x83, 0x3A, 0x04, 0x6A, 0x10, 0xA8, 0x41, 0xA0, ++0x06, 0x83, 0x1A, 0x0C, 0x4A, 0x30, 0xA8, 0x41, 0xA0, 0x06, 0x81, 0x1A, 0x0C, ++0x4A, 0x30, 0xA8, 0x41, 0x80, 0x0E, 0x83, 0x1A, 0x0C, 0x4A, 0x30, 0x88, 0x41, ++0xA0, 0x06, 0x01, 0x0A, 0x0C, 0x08, 0x10, 0xA8, 0x41, 0xA0, 0x06, 0x83, 0x1A, ++0x04, 0x6A, 0x10, 0xA8, 0x01, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA3, 0x40, 0x00, 0x04, 0x01, 0x18, 0x04, 0xC0, 0x10, 0x00, 0x41, 0x00, 0x04, ++0x01, 0x20, 0x04, 0x40, 0x10, 0x00, 0x42, 0x00, 0x00, 0x01, 0x10, 0x04, 0x40, ++0x10, 0x80, 0x41, 0x00, 0x04, 0x01, 0x10, 0x04, 0x00, 0x10, 0x00, 0x43, 0x00, ++0x00, 0x81, 0x10, 0x04, 0x40, 0x10, 0x00, 0x41, 0x00, 0x0C, 0x01, 0x30, 0x04, ++0x40, 0x10, 0x00, 0x01, 0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, ++0x4A, 0x20, 0x2C, 0x81, 0x10, 0x0C, 0x82, 0x12, 0x88, 0x41, 0x20, 0x26, 0x81, ++0xB0, 0x04, 0x42, 0x10, 0x08, 0x43, 0x20, 0x26, 0x83, 0x90, 0x04, 0x02, 0x12, ++0x08, 0x41, 0x00, 0x26, 0x81, 0x90, 0x04, 0x42, 0x10, 0x08, 0x43, 0x20, 0x26, ++0x83, 0x90, 0x04, 0x40, 0x10, 0x88, 0xC9, 0x20, 0x0C, 0x81, 0xB0, 0x04, 0x62, ++0x12, 0x88, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x06, ++0x20, 0x1A, 0x00, 0x62, 0x00, 0x88, 0x01, 0xA8, 0x06, 0xA0, 0x1A, 0x80, 0x62, ++0x00, 0x80, 0x01, 0x28, 0x06, 0xA0, 0x1A, 0x80, 0x42, 0x00, 0x0A, 0x01, 0xA0, ++0x06, 0x80, 0x18, 0x00, 0x6A, 0x00, 0x88, 0x01, 0x28, 0x06, 0xA0, 0x1A, 0x80, ++0x6A, 0x80, 0x08, 0x01, 0xA8, 0x06, 0x80, 0x18, 0x80, 0x62, 0x00, 0xA8, 0x01, ++0x88, 0x02, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, ++0x82, 0x01, 0x0A, 0x06, 0x28, 0x18, 0xA0, 0x60, 0x80, 0x82, 0x01, 0x0A, 0x06, ++0x28, 0x18, 0xA0, 0x60, 0x80, 0x82, 0x01, 0x0A, 0x06, 0x28, 0x18, 0xA0, 0x60, ++0xA0, 0x82, 0x01, 0x2A, 0x06, 0x28, 0x18, 0xA0, 0x60, 0x80, 0x82, 0x01, 0x0A, ++0x06, 0xAA, 0x18, 0xA0, 0x60, 0x80, 0x8A, 0x01, 0x0A, 0x06, 0x28, 0x18, 0xA0, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x48, 0x80, 0x20, ++0x81, 0x02, 0x84, 0x08, 0x12, 0x20, 0x40, 0x80, 0x20, 0x81, 0x82, 0x04, 0x08, ++0x10, 0x20, 0x40, 0x80, 0x20, 0x01, 0x82, 0x04, 0x4A, 0x12, 0x20, 0x40, 0x80, ++0x20, 0x01, 0x82, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x20, 0x01, 0x82, 0x04, ++0x08, 0x10, 0x20, 0x48, 0x80, 0x00, 0x01, 0x82, 0x04, 0x48, 0x12, 0x20, 0x00, ++0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x62, 0xC0, 0x80, 0x01, ++0x03, 0x06, 0xAC, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, 0x2B, 0x06, 0xAE, 0x18, ++0xB0, 0x62, 0xC0, 0x8A, 0x81, 0x2B, 0x06, 0xAC, 0x18, 0xA0, 0x62, 0xC0, 0x8A, ++0x81, 0x29, 0x06, 0xAE, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, 0x2B, 0x06, 0xA6, ++0x18, 0xB0, 0x62, 0x60, 0x8A, 0x01, 0x2B, 0x06, 0xAC, 0x18, 0xB0, 0x02, 0x8C, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x62, 0x80, 0x8E, 0x01, 0x3A, ++0x06, 0xEE, 0x18, 0xA4, 0x63, 0x80, 0x8E, 0x81, 0x3A, 0x06, 0xE8, 0x18, 0xB0, ++0x63, 0x80, 0x8E, 0x01, 0x3A, 0x06, 0xEA, 0x18, 0xA8, 0x63, 0x80, 0x8E, 0x81, ++0x3A, 0x06, 0xE0, 0x18, 0xB0, 0x63, 0x80, 0x8E, 0x81, 0x3B, 0x06, 0xE8, 0x18, ++0xA8, 0x63, 0x20, 0x8E, 0x81, 0x3B, 0x06, 0xEA, 0x18, 0xA8, 0x03, 0x8C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x62, 0xC0, 0x8E, 0x01, 0x3A, 0x06, ++0xE8, 0x18, 0xB0, 0x63, 0xC0, 0x8E, 0x01, 0x3A, 0x06, 0xCC, 0x18, 0xA0, 0x63, ++0xC0, 0x8E, 0x01, 0x3B, 0x86, 0xEA, 0x18, 0x30, 0x63, 0xC0, 0x8E, 0x01, 0x3B, ++0x06, 0xCC, 0x18, 0xA0, 0x63, 0xC0, 0x8E, 0x01, 0x3B, 0x06, 0xEC, 0x18, 0xB0, ++0x63, 0xE0, 0x8E, 0x81, 0x3A, 0x06, 0xEE, 0x18, 0xB0, 0x03, 0x88, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x62, 0xA0, 0x8E, 0x81, 0x31, 0x06, 0xC2, ++0x18, 0xA8, 0x63, 0xA0, 0x8E, 0x81, 0x30, 0x06, 0xC2, 0x18, 0x0A, 0x63, 0xA0, ++0x8E, 0x01, 0x10, 0x06, 0xC4, 0x18, 0x30, 0x63, 0x00, 0x8C, 0x21, 0x10, 0x06, ++0xC0, 0x18, 0x08, 0x61, 0xA0, 0x8E, 0xA1, 0x38, 0x86, 0x80, 0x18, 0xA8, 0x63, ++0x00, 0x84, 0x81, 0x38, 0x06, 0xEE, 0x18, 0xA8, 0x03, 0x88, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x04, 0x01, 0x1A, 0x04, 0xE8, 0x10, ++0x20, 0x41, 0x80, 0x04, 0x01, 0x3A, 0x04, 0x48, 0x10, 0xA0, 0x43, 0x80, 0x04, ++0x01, 0x12, 0x04, 0x68, 0x10, 0x20, 0x41, 0x00, 0x04, 0x01, 0x12, 0x04, 0x48, ++0x10, 0x20, 0x43, 0x80, 0x04, 0x01, 0x32, 0x04, 0x68, 0x10, 0x20, 0x41, 0x80, ++0x04, 0x01, 0x32, 0x04, 0x48, 0x10, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x86, 0x01, 0x12, 0x06, 0x6A, 0x18, 0xA0, ++0x60, 0x88, 0x86, 0x81, 0x1A, 0x06, 0x48, 0x18, 0xA8, 0x60, 0x00, 0x82, 0x01, ++0x02, 0x86, 0x48, 0x18, 0xA0, 0x61, 0x80, 0x84, 0x01, 0x1A, 0x06, 0x48, 0x18, ++0xA8, 0x61, 0x88, 0x86, 0x01, 0x1A, 0x06, 0x48, 0x18, 0xA0, 0x61, 0x80, 0x84, ++0x01, 0x18, 0x06, 0x68, 0x18, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA2, 0x02, 0xA0, 0x0E, 0x80, 0x3A, 0x00, 0xCA, 0x00, 0x28, 0x03, ++0xA0, 0x0A, 0x80, 0x32, 0x00, 0xC8, 0x00, 0xA8, 0x02, 0xA0, 0x0C, 0x00, 0x32, ++0x00, 0xC8, 0x00, 0xA8, 0x03, 0xA0, 0x0C, 0x00, 0x32, 0x00, 0xC8, 0x00, 0xA8, ++0x03, 0xA0, 0x0C, 0x00, 0x32, 0x00, 0xE8, 0x00, 0x28, 0x03, 0xA0, 0x0C, 0x80, ++0x32, 0x00, 0xCA, 0x00, 0xA8, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA2, 0x42, 0x00, 0x06, 0x01, 0x18, 0x04, 0x40, 0x10, 0x00, 0x41, 0x00, ++0x06, 0x01, 0x10, 0x0C, 0x42, 0x10, 0x80, 0x41, 0x00, 0x04, 0x83, 0x10, 0x0C, ++0x40, 0x10, 0x80, 0xC1, 0x00, 0x04, 0x83, 0x10, 0x04, 0x42, 0x10, 0x80, 0xC1, ++0x00, 0x04, 0x83, 0x10, 0x0C, 0x42, 0x30, 0x00, 0xC0, 0x00, 0x04, 0x03, 0x10, ++0x04, 0x60, 0x10, 0x80, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA2, 0x42, 0x20, 0x04, 0x81, 0x10, 0x04, 0x62, 0x10, 0x88, 0x41, 0x20, 0x04, ++0x81, 0x18, 0x04, 0x62, 0x10, 0x08, 0x41, 0x20, 0x06, 0x81, 0x18, 0x04, 0x60, ++0x10, 0x08, 0x41, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, 0x10, 0x08, 0x41, 0x20, ++0x06, 0x81, 0x18, 0x04, 0x62, 0x10, 0x88, 0x41, 0x20, 0x06, 0x81, 0x18, 0x05, ++0x42, 0x10, 0x08, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, ++0x42, 0xA0, 0x02, 0x01, 0x0A, 0x0C, 0xA8, 0x30, 0xA8, 0x42, 0xA0, 0x02, 0x03, ++0x2A, 0x04, 0xAA, 0x10, 0xA0, 0xC0, 0xA0, 0x0A, 0x81, 0x2A, 0x84, 0xA0, 0x10, ++0xA0, 0x40, 0xA0, 0x0A, 0x81, 0x2A, 0x0C, 0xAA, 0x10, 0xA0, 0x40, 0xA8, 0x0A, ++0x81, 0x2A, 0x04, 0x2A, 0x10, 0xA8, 0x42, 0xA0, 0x0A, 0x81, 0x2A, 0x0C, 0xA8, ++0x10, 0xA8, 0x00, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++0x80, 0x0A, 0x01, 0x2A, 0x0C, 0xA8, 0x30, 0xA0, 0xC2, 0x80, 0x0A, 0x03, 0x2A, ++0x0C, 0xA8, 0x30, 0xA0, 0xC2, 0x80, 0x0A, 0x01, 0x2A, 0x04, 0xA8, 0x30, 0xA0, ++0xC2, 0x80, 0x0A, 0x01, 0x2A, 0x0C, 0xA8, 0x30, 0xA0, 0xC2, 0x80, 0x0A, 0x01, ++0x2A, 0x04, 0xA8, 0x30, 0xA0, 0x42, 0x80, 0x0A, 0x03, 0x2A, 0x05, 0xA8, 0x30, ++0xA0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, ++0x42, 0x80, 0x08, 0x00, 0x20, 0x00, 0x80, 0x10, 0x00, 0x02, 0x80, 0x08, 0x00, ++0x20, 0x04, 0x82, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x22, 0x04, 0x80, 0x00, ++0x00, 0x02, 0x20, 0x08, 0x00, 0x20, 0x04, 0x80, 0x00, 0x00, 0x02, 0x20, 0x08, ++0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x60, 0x04, 0x80, ++0x01, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x42, 0x40, 0x00, ++0x01, 0x01, 0x05, 0x04, 0x14, 0x10, 0x40, 0x40, 0x40, 0x01, 0x01, 0x0C, 0x44, ++0x10, 0x10, 0x50, 0x40, 0x00, 0x81, 0x01, 0x04, 0x00, 0x30, 0x00, 0x50, 0x00, ++0x00, 0x81, 0x01, 0x0C, 0x06, 0x10, 0x10, 0x50, 0x40, 0x00, 0x01, 0x01, 0x04, ++0x46, 0x14, 0x10, 0x40, 0x60, 0x44, 0x01, 0x01, 0x04, 0x04, 0x30, 0x10, 0x00, ++0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x00, 0xA0, 0x06, 0x80, ++0x1A, 0x00, 0x6E, 0x00, 0xA8, 0x01, 0x80, 0x06, 0x80, 0x1A, 0x00, 0x6A, 0x00, ++0xB8, 0x01, 0xA0, 0x06, 0x80, 0x1A, 0x00, 0x6A, 0x00, 0xA8, 0x01, 0xA0, 0x06, ++0x80, 0x1A, 0x00, 0x68, 0x00, 0xB0, 0x01, 0x80, 0x06, 0x80, 0x1A, 0x00, 0x6A, ++0x00, 0xA8, 0x01, 0xA0, 0x06, 0x80, 0x1B, 0x00, 0x6A, 0x00, 0xA8, 0x01, 0x88, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x02, 0xC0, 0x06, 0x00, 0x12, ++0x00, 0xE8, 0x00, 0xB0, 0x01, 0xC0, 0x06, 0x80, 0x3A, 0x00, 0x4C, 0x00, 0xA0, ++0x03, 0xC0, 0x06, 0x80, 0x13, 0x00, 0x4E, 0x00, 0xB0, 0x01, 0xC0, 0x06, 0x00, ++0x13, 0x00, 0x6E, 0x00, 0xA0, 0x03, 0xC0, 0x06, 0x00, 0x1B, 0x00, 0x4C, 0x00, ++0xB0, 0x01, 0xC0, 0x04, 0x00, 0x3A, 0x00, 0x6E, 0x00, 0xB0, 0x01, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0C, 0x80, 0x11, 0x00, ++0x62, 0x00, 0x08, 0x02, 0x20, 0x0C, 0x80, 0x18, 0x00, 0x42, 0x00, 0x8A, 0x01, ++0x20, 0x0C, 0x02, 0x10, 0x00, 0x44, 0x00, 0x10, 0x01, 0x00, 0x0C, 0x02, 0x10, ++0x00, 0x40, 0x00, 0x80, 0x01, 0x20, 0x0C, 0x00, 0x10, 0x00, 0x40, 0x00, 0x08, ++0x83, 0x00, 0x04, 0x80, 0x18, 0x00, 0xC2, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x90, 0x00, 0x40, ++0x02, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x90, 0x12, 0x40, 0x02, 0x00, 0x21, 0x00, ++0xA8, 0x01, 0x90, 0x12, 0x40, 0x02, 0x00, 0x21, 0x02, 0xAC, 0x08, 0x90, 0x22, ++0x40, 0x02, 0x00, 0x21, 0x00, 0xAC, 0x05, 0x90, 0x22, 0x40, 0x08, 0x00, 0x2B, ++0x02, 0xA4, 0x00, 0x90, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x8C, 0x00, 0x32, 0x0A, 0xCA, 0x28, ++0x22, 0xA3, 0x80, 0x8C, 0x02, 0x32, 0x06, 0x48, 0x28, 0x28, 0xA2, 0x88, 0x8C, ++0x82, 0x12, 0x00, 0x48, 0x08, 0x20, 0xA1, 0x80, 0x8C, 0x03, 0x32, 0x00, 0x48, ++0x28, 0x28, 0xA2, 0x80, 0x8C, 0x00, 0x22, 0x06, 0x08, 0x38, 0x20, 0xA3, 0x80, ++0x84, 0x82, 0x32, 0x02, 0xCA, 0x08, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xC4, 0xA0, 0x16, 0x83, 0x5A, 0x0C, 0x4A, 0x31, 0xA8, ++0xC5, 0xA0, 0x16, 0x83, 0x5A, 0x0E, 0x68, 0x31, 0xA8, 0x85, 0xA0, 0x16, 0x83, ++0x5A, 0x0C, 0x60, 0x31, 0xA8, 0x85, 0xA0, 0x16, 0x03, 0x5A, 0x0C, 0x6A, 0x31, ++0xA8, 0xC5, 0xA0, 0x16, 0x03, 0x58, 0x0E, 0x28, 0x31, 0xA8, 0xE4, 0x80, 0x12, ++0x82, 0x5A, 0x0C, 0x6A, 0x31, 0xA8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x90, 0x01, 0x40, 0x06, 0x00, 0x09, ++0x00, 0x64, 0x00, 0x90, 0x00, 0x42, 0x02, 0x00, 0x91, 0x00, 0xA4, 0x00, 0x90, ++0x00, 0x40, 0x02, 0x00, 0x91, 0x00, 0xA4, 0x80, 0x90, 0x08, 0x40, 0x02, 0x00, ++0x31, 0x00, 0xA4, 0x80, 0x80, 0x00, 0x42, 0x0C, 0x00, 0x09, 0x20, 0x64, 0x02, ++0x90, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x22, 0x42, 0x88, 0x18, 0x20, 0x42, 0x80, 0x88, 0x11, 0x22, ++0x06, 0x88, 0x18, 0x20, 0x62, 0x84, 0x88, 0x01, 0x22, 0x06, 0x88, 0x18, 0x20, ++0x60, 0x84, 0x88, 0x01, 0x22, 0x06, 0x88, 0x18, 0x20, 0x62, 0x84, 0x88, 0x21, ++0x26, 0x06, 0x88, 0x18, 0x20, 0x62, 0x80, 0x88, 0x21, 0x22, 0x06, 0x88, 0x18, ++0x20, 0x62, 0x84, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA2, 0x0A, 0x08, 0x2A, 0x20, 0x08, 0x00, 0xA8, 0x02, 0xA2, 0x0A, ++0x84, 0x2A, 0x20, 0xAA, 0x80, 0xA0, 0x02, 0xA6, 0x0A, 0x1C, 0x2A, 0x28, 0xA8, ++0xC0, 0xA0, 0x02, 0xA2, 0x0A, 0x88, 0x2A, 0x20, 0xAA, 0x80, 0xA0, 0x02, 0xA2, ++0x0A, 0x88, 0x2A, 0xA0, 0xAA, 0x80, 0xA9, 0x02, 0xA2, 0x0A, 0x18, 0x28, 0x20, ++0xA8, 0x80, 0xA8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x84, 0x42, 0x10, 0x0A, 0x41, 0xA8, 0x04, 0xA0, 0x12, 0x80, 0x42, 0x10, ++0x2A, 0x41, 0x28, 0x84, 0xA1, 0x10, 0x84, 0x4A, 0x10, 0x2A, 0x61, 0xA8, 0x04, ++0xA1, 0x10, 0x84, 0x4A, 0x18, 0x2A, 0x61, 0xA8, 0x44, 0xA1, 0x10, 0x84, 0x4A, ++0x14, 0x2A, 0x61, 0xA8, 0x04, 0xA1, 0x12, 0x84, 0x4A, 0x10, 0x2A, 0x01, 0xA8, ++0x04, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, ++0x80, 0x40, 0x81, 0x02, 0x8D, 0x08, 0x14, 0x00, 0x50, 0x80, 0x40, 0x83, 0x02, ++0x05, 0x08, 0x14, 0x20, 0x50, 0x80, 0x40, 0x01, 0x00, 0x05, 0x08, 0x14, 0x20, ++0x50, 0x00, 0x40, 0x01, 0x02, 0x05, 0x08, 0x14, 0x28, 0x50, 0x80, 0x40, 0x01, ++0x02, 0x85, 0x00, 0x14, 0x20, 0x50, 0x00, 0x40, 0x01, 0x00, 0x05, 0x00, 0x14, ++0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xC0, ++0xCA, 0x00, 0x2B, 0x03, 0xA4, 0x0C, 0x10, 0x32, 0xC0, 0xCA, 0x00, 0x01, 0x03, ++0x0C, 0x0C, 0xB0, 0x32, 0x40, 0xC0, 0x80, 0x21, 0x03, 0x86, 0x0C, 0xA1, 0x32, ++0x00, 0xC8, 0x80, 0x01, 0x03, 0x86, 0x0C, 0xA0, 0x32, 0x40, 0xC8, 0x00, 0x20, ++0x03, 0x86, 0x0C, 0x10, 0x30, 0x60, 0xC8, 0x20, 0x21, 0x03, 0x84, 0x0C, 0xB0, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA2, 0x4E, ++0x80, 0x3A, 0x09, 0xEE, 0x04, 0xA0, 0x13, 0x80, 0x4E, 0x82, 0x3A, 0x11, 0xEA, ++0x04, 0xB8, 0x13, 0x90, 0x4E, 0x90, 0x3A, 0x21, 0x6A, 0x04, 0xA8, 0x13, 0xA0, ++0x4E, 0x88, 0x3A, 0x21, 0xCA, 0x04, 0xA8, 0x13, 0x10, 0x4C, 0x84, 0x32, 0x01, ++0xE8, 0x04, 0xA8, 0x13, 0xA0, 0x4E, 0x80, 0x3B, 0x01, 0xEA, 0x04, 0xA9, 0x03, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x10, 0x12, 0x03, ++0x08, 0x8C, 0x20, 0x32, 0x80, 0xC4, 0x08, 0x02, 0x03, 0x08, 0x0C, 0x20, 0x31, ++0x82, 0xC0, 0x18, 0x02, 0x03, 0x08, 0x0C, 0x20, 0x31, 0x80, 0xC0, 0x18, 0x02, ++0x03, 0x08, 0x0C, 0x20, 0x31, 0x82, 0xC0, 0x18, 0x02, 0x03, 0x08, 0x0C, 0x20, ++0x30, 0x86, 0xC0, 0x00, 0x02, 0x23, 0x08, 0x0C, 0x20, 0x31, 0x84, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, ++0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, ++0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, ++0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, ++0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xDF, 0xD0, 0x6C, 0x43, 0xB3, 0x0D, ++0xED, 0xBF, 0x34, 0xFB, 0xD2, 0xFE, 0xCB, 0xFF, 0x0D, 0xCD, 0xBE, 0x7C, 0xDB, ++0xF0, 0xFF, 0xCB, 0xFF, 0x2F, 0xED, 0xBF, 0x7C, 0xDB, 0xF0, 0xFF, 0xCB, 0xFF, ++0x2F, 0xCD, 0xBE, 0x7C, 0xDB, 0xF0, 0xFF, 0xCB, 0xB7, 0x2F, 0xDF, 0x36, 0x7C, ++0xDB, 0xF0, 0x6D, 0x43, 0xB3, 0x2F, 0xED, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x3F, 0x32, 0xF3, 0xC8, 0xCC, 0x23, 0xF3, ++0xBF, 0xCC, 0xFC, 0x32, 0xFF, 0xCB, 0xFF, 0x23, 0x33, 0xBF, 0xFC, 0x3C, 0xF2, ++0xFF, 0xCB, 0xFF, 0x2F, 0xF3, 0xBF, 0xFC, 0x3C, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, ++0x33, 0xBF, 0xFC, 0x3C, 0xF2, 0xFF, 0xCB, 0xCF, 0x2F, 0x3F, 0x8F, 0xFC, 0x3C, ++0xF2, 0xF3, 0xC8, 0xCC, 0x2F, 0xF3, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xDC, 0x78, 0x72, 0x63, 0x48, 0xEC, 0x21, 0xB1, 0x9F, ++0xDC, 0x7E, 0x12, 0x7B, 0x48, 0x8C, 0x21, 0xB7, 0x87, 0xC4, 0x7E, 0x12, 0x63, ++0x48, 0x8C, 0x21, 0x37, 0x86, 0xC4, 0x7E, 0x12, 0x63, 0x48, 0x8C, 0x21, 0xB7, ++0x87, 0xC4, 0x7E, 0x12, 0x63, 0x48, 0x8C, 0x21, 0xB1, 0x9F, 0xC4, 0x18, 0x12, ++0x7B, 0x48, 0x8C, 0x27, 0x37, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x00, 0x0E, 0x02, 0x39, 0x0A, 0xE4, 0x20, 0x90, 0x83, ++0x00, 0x0E, 0x02, 0x39, 0x08, 0xE0, 0x20, 0x80, 0x83, 0x40, 0x0E, 0x02, 0x39, ++0x08, 0xE4, 0x20, 0x90, 0x83, 0x00, 0x0E, 0x02, 0x38, 0x0A, 0xE4, 0x20, 0x80, ++0x83, 0x40, 0x0E, 0x02, 0x38, 0x06, 0xE6, 0x20, 0x90, 0xA3, 0x40, 0x0E, 0x02, ++0x39, 0x08, 0xE4, 0x28, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x20, 0x60, 0x8E, 0x00, 0x3A, 0x02, 0xEA, 0x08, 0xA0, 0x23, 0xA0, ++0x8E, 0x00, 0x3A, 0x02, 0xEA, 0x08, 0xB8, 0x23, 0xA0, 0x8E, 0x00, 0x3A, 0x02, ++0xE8, 0x08, 0xA0, 0x23, 0xA0, 0x8E, 0x80, 0x3A, 0x02, 0xEA, 0x08, 0xA8, 0x23, ++0xA0, 0x8E, 0x80, 0x3A, 0x02, 0xEE, 0x08, 0xA8, 0x23, 0xA0, 0x8E, 0x80, 0x3A, ++0x02, 0xEA, 0x08, 0xA8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x40, 0x80, 0x04, 0x01, 0x12, 0x06, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, ++0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, ++0x10, 0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, ++0x04, 0x01, 0x12, 0x06, 0x48, 0x10, 0x20, 0x61, 0x80, 0x04, 0x01, 0x12, 0x04, ++0x48, 0x18, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x80, 0x0E, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x20, 0x06, 0x00, ++0x18, 0x00, 0x62, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, ++0x80, 0x01, 0x28, 0x06, 0x80, 0x18, 0x02, 0x60, 0x00, 0x88, 0x01, 0x00, 0x06, ++0x80, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, ++0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x20, 0x4E, 0x00, 0x38, 0x05, 0xE2, 0x04, 0x80, 0x13, 0x20, 0x4E, 0x00, 0x38, ++0x09, 0xE2, 0x04, 0x88, 0x13, 0x20, 0x4E, 0x00, 0x38, 0x01, 0xE0, 0x04, 0x80, ++0x13, 0x20, 0x4E, 0x82, 0x38, 0x05, 0xE2, 0x04, 0x88, 0x12, 0x20, 0x4E, 0x80, ++0x38, 0xA1, 0xE2, 0x04, 0x28, 0x51, 0x20, 0x4E, 0x80, 0x30, 0x01, 0xE2, 0x14, ++0x88, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x06, 0x80, 0x18, 0x00, 0x60, 0x00, 0x88, 0x01, 0x00, 0x06, 0x80, 0x18, 0x00, ++0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0x88, 0x81, ++0x00, 0x06, 0x02, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, ++0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x08, 0x10, 0x00, 0x60, 0x00, 0x80, ++0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x24, ++0x80, 0x90, 0x01, 0x42, 0x02, 0x08, 0x29, 0x20, 0x24, 0x80, 0x90, 0x02, 0x42, ++0x02, 0x08, 0x11, 0x20, 0x24, 0x80, 0x90, 0x00, 0x42, 0x02, 0x08, 0x09, 0x20, ++0xA4, 0x80, 0x90, 0x01, 0x42, 0x02, 0x08, 0x11, 0x20, 0xA4, 0x80, 0x90, 0x01, ++0x42, 0x04, 0x08, 0x39, 0x20, 0x44, 0x80, 0x18, 0x01, 0x42, 0x06, 0x08, 0x01, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x12, 0x81, ++0x48, 0x05, 0x22, 0x11, 0x88, 0x44, 0x00, 0x12, 0x81, 0x48, 0x04, 0x20, 0x31, ++0x80, 0x54, 0x20, 0x12, 0x81, 0x48, 0x04, 0x22, 0x11, 0x88, 0xC4, 0x00, 0x12, ++0x03, 0x48, 0x0D, 0x22, 0x11, 0x80, 0x54, 0x20, 0x12, 0x01, 0x48, 0x05, 0x20, ++0x15, 0x88, 0x54, 0x20, 0x52, 0x81, 0x68, 0x0D, 0x22, 0x1D, 0x88, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x30, 0x00, 0xC8, 0x00, 0x00, ++0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xCA, 0x00, 0x20, 0x03, 0xA0, 0x0C, 0x00, ++0x32, 0x00, 0xC0, 0x02, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xCA, 0x00, ++0x28, 0x03, 0x80, 0x0C, 0x80, 0x32, 0x00, 0xCA, 0x00, 0x28, 0x03, 0xA0, 0x0C, ++0x80, 0x72, 0x00, 0xCA, 0x00, 0x28, 0x03, 0x80, 0x1C, 0x80, 0x02, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x20, 0x2C, 0x00, 0x90, 0x00, ++0x00, 0x02, 0x00, 0x78, 0x00, 0x26, 0x00, 0x90, 0x03, 0x60, 0x02, 0x08, 0x03, ++0x00, 0x20, 0x00, 0x90, 0x00, 0x40, 0x02, 0x00, 0x19, 0x00, 0xE2, 0x00, 0x88, ++0x00, 0x80, 0x06, 0x80, 0x00, 0x00, 0xE2, 0x01, 0x88, 0x00, 0x20, 0x00, 0x80, ++0x28, 0x00, 0x02, 0x00, 0x08, 0x00, 0x80, 0x0A, 0x80, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x02, 0x40, 0x08, 0x80, 0x01, 0x00, 0x04, ++0x00, 0x18, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x04, 0x00, 0x10, 0x02, 0x40, ++0x00, 0x82, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x84, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x84, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x03, 0x02, 0x20, 0x06, 0x80, 0x10, 0x00, 0x42, 0x00, ++0x08, 0x01, 0x60, 0x06, 0x80, 0x10, 0x00, 0x66, 0x00, 0x88, 0x01, 0x20, 0x04, ++0x80, 0x10, 0x00, 0x42, 0x00, 0x08, 0x01, 0x40, 0x06, 0x80, 0x19, 0x00, 0x62, ++0x00, 0x98, 0x01, 0x20, 0x06, 0x80, 0x19, 0x00, 0x62, 0x00, 0x88, 0x01, 0x20, ++0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0x88, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x08, 0x80, 0x02, 0x00, 0x06, 0x00, 0x19, 0x00, 0x64, 0x00, 0x90, ++0x11, 0x00, 0x06, 0x00, 0x19, 0x01, 0x60, 0x00, 0x80, 0x01, 0x40, 0x06, 0x00, ++0x19, 0x00, 0x64, 0x00, 0x90, 0x11, 0x00, 0x46, 0x00, 0x18, 0x00, 0x64, 0x04, ++0x80, 0x01, 0x40, 0x46, 0x00, 0x18, 0x00, 0x66, 0x00, 0x90, 0x01, 0x40, 0x06, ++0x00, 0x19, 0x00, 0x64, 0x00, 0x90, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xA2, 0x42, 0x60, 0x0C, 0x01, 0x30, 0x04, 0xC2, 0x10, 0x00, 0x43, ++0x20, 0x0C, 0x01, 0x30, 0x04, 0xC2, 0x10, 0x18, 0x43, 0x20, 0x0C, 0x01, 0x30, ++0x04, 0xC0, 0x10, 0x00, 0x43, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, ++0x43, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, 0x43, 0x20, 0x0C, 0x81, ++0x30, 0x04, 0xC2, 0x10, 0x08, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x00, 0x10, 0x00, 0x4C, 0x00, 0x30, 0x00, 0xC0, 0x04, 0x00, 0x03, 0x00, ++0x4C, 0x00, 0x30, 0x00, 0xC0, 0x04, 0x00, 0x03, 0x00, 0x4C, 0x00, 0x30, 0x01, ++0xC0, 0x04, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, ++0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, ++0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x00, 0xD0, 0x00, 0x4C, 0x03, 0x30, 0x04, 0xC0, 0x34, 0x00, 0xC3, 0x20, 0x4C, ++0x03, 0x30, 0x0C, 0xC2, 0x34, 0x00, 0x43, 0x00, 0x4C, 0x03, 0x30, 0x0D, 0xC0, ++0x34, 0x00, 0xC3, 0x20, 0x0C, 0x83, 0x30, 0x04, 0xC0, 0x30, 0x08, 0x43, 0x00, ++0x0C, 0x83, 0x30, 0x04, 0xC2, 0x10, 0x00, 0x43, 0x00, 0x0C, 0x01, 0x30, 0x04, ++0xC0, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, ++0xC2, 0x20, 0x0E, 0x03, 0x10, 0x04, 0x62, 0x30, 0x00, 0xC1, 0x20, 0x06, 0x03, ++0x10, 0x0C, 0x62, 0x30, 0x88, 0x43, 0x20, 0x06, 0x03, 0x18, 0x0C, 0x40, 0x30, ++0x00, 0xC1, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, 0x30, 0x88, 0x41, 0x20, 0x06, ++0x83, 0x18, 0x04, 0x60, 0x10, 0x88, 0x41, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, ++0x10, 0x88, 0x01, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x42, ++0x00, 0x06, 0x81, 0x10, 0x04, 0x40, 0x10, 0x08, 0x41, 0x00, 0x0C, 0x81, 0x10, ++0x04, 0xC0, 0x10, 0x80, 0x41, 0x00, 0x04, 0x81, 0x10, 0x04, 0x42, 0x10, 0x08, ++0x41, 0x00, 0x08, 0x01, 0x30, 0x04, 0x40, 0x10, 0x00, 0x43, 0x00, 0x04, 0x01, ++0x30, 0x04, 0x42, 0x10, 0x00, 0x41, 0x00, 0x04, 0x01, 0x10, 0x04, 0x40, 0x10, ++0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x80, 0x42, 0x20, ++0x04, 0x81, 0x10, 0x04, 0x62, 0x10, 0x08, 0x41, 0x20, 0x0C, 0x81, 0x10, 0x04, ++0xC2, 0x10, 0x08, 0x41, 0x20, 0x06, 0x81, 0x10, 0x04, 0x42, 0x10, 0x08, 0x41, ++0x20, 0x0C, 0x83, 0x30, 0x04, 0x62, 0x10, 0x08, 0x43, 0x20, 0x06, 0x81, 0x30, ++0x04, 0x62, 0x10, 0x88, 0x41, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, 0x10, 0x88, ++0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x02, 0x00, 0x08, ++0x80, 0x00, 0x00, 0xA2, 0x00, 0x08, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80, ++0x00, 0x00, 0x02, 0x20, 0x0A, 0x80, 0x20, 0x00, 0x82, 0x00, 0x08, 0x02, 0x00, ++0x08, 0x00, 0x20, 0x00, 0xA2, 0x00, 0x00, 0x02, 0x20, 0x0A, 0x00, 0x20, 0x00, ++0xA0, 0x00, 0x88, 0x02, 0x20, 0x0A, 0x80, 0x28, 0x00, 0xA2, 0x00, 0x88, 0x42, ++0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x60, 0x00, 0x82, 0x01, ++0x08, 0x06, 0x20, 0x18, 0x80, 0x60, 0x00, 0x82, 0x01, 0x08, 0x06, 0x20, 0x18, ++0x80, 0x60, 0x00, 0x82, 0x01, 0x08, 0x06, 0x20, 0x18, 0x80, 0x60, 0x00, 0x82, ++0x01, 0x08, 0x06, 0x20, 0x18, 0x80, 0x60, 0x00, 0x82, 0x01, 0x08, 0x06, 0x20, ++0x18, 0x80, 0x60, 0x00, 0x82, 0x01, 0x28, 0x06, 0x20, 0x18, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x40, 0xA0, 0x00, 0x01, 0x02, ++0x04, 0x08, 0x10, 0x20, 0x41, 0x80, 0x00, 0x01, 0x02, 0x04, 0x48, 0x10, 0x28, ++0x40, 0x80, 0x04, 0x01, 0x02, 0x04, 0x48, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, ++0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, ++0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x62, 0xC0, 0x8A, 0x81, 0x2B, 0x06, ++0xAC, 0x18, 0xB8, 0x62, 0xC0, 0x8A, 0x81, 0x2B, 0x06, 0xAC, 0x18, 0xB0, 0x62, ++0xC0, 0x8A, 0x81, 0x2B, 0x06, 0xAE, 0x18, 0xB8, 0x62, 0xC0, 0x8A, 0x01, 0x2B, ++0x06, 0xAC, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, 0x2B, 0x06, 0xAC, 0x18, 0xB0, ++0x62, 0xC0, 0x8A, 0x01, 0x29, 0x06, 0xAC, 0x18, 0xB0, 0x02, 0x88, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x62, 0x20, 0x8E, 0x81, 0x38, 0x06, 0xE2, ++0x18, 0x88, 0x63, 0x60, 0x8E, 0x81, 0x38, 0x06, 0xE6, 0x18, 0x88, 0x63, 0x20, ++0x8E, 0x81, 0x38, 0x06, 0xE2, 0x18, 0x88, 0x63, 0x50, 0x8E, 0x81, 0x39, 0x06, ++0xE2, 0x18, 0x98, 0x63, 0x20, 0x8E, 0x81, 0x39, 0x04, 0xE2, 0x18, 0x88, 0x63, ++0x20, 0x8E, 0x81, 0x3A, 0x06, 0xE2, 0x18, 0x88, 0x03, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x80, 0x62, 0x00, 0x8E, 0x01, 0x3B, 0x06, 0xE4, 0x18, ++0xB0, 0x63, 0x00, 0x8E, 0x01, 0x39, 0x06, 0xE0, 0x18, 0x80, 0x63, 0x40, 0x8E, ++0x01, 0x39, 0x06, 0xEC, 0x18, 0xB0, 0x63, 0x80, 0x8E, 0x01, 0x38, 0x06, 0xE4, ++0x18, 0x80, 0x63, 0x40, 0x8E, 0x01, 0x38, 0x06, 0xE4, 0x18, 0x90, 0x63, 0x40, ++0x0E, 0x01, 0x39, 0x06, 0xE4, 0x18, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0A, 0xA2, 0x62, 0x60, 0x8C, 0x01, 0x30, 0x06, 0xEA, 0x18, 0x80, ++0x63, 0x20, 0x8C, 0x01, 0x30, 0x06, 0xC2, 0x18, 0x18, 0x63, 0xA0, 0x8E, 0x01, ++0x30, 0x06, 0xC0, 0x18, 0x00, 0x63, 0x20, 0x8E, 0x81, 0x30, 0x06, 0xEA, 0x18, ++0x08, 0x63, 0xA0, 0x8E, 0x81, 0x30, 0x06, 0xEA, 0x18, 0xA8, 0x63, 0xA0, 0x8E, ++0x81, 0x3A, 0x06, 0xEA, 0x18, 0xA8, 0x43, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x00, 0x48, 0x00, 0x24, 0x01, 0x9A, 0x04, 0x48, 0x12, 0x20, 0x49, ++0x80, 0x2E, 0x01, 0x90, 0x04, 0xE8, 0x12, 0x00, 0x49, 0x80, 0x24, 0x01, 0x90, ++0x04, 0x68, 0x12, 0xA0, 0x41, 0x80, 0x2C, 0x01, 0xBA, 0x04, 0x48, 0x10, 0xA0, ++0x43, 0x80, 0x24, 0x01, 0xBA, 0x04, 0x48, 0x10, 0x20, 0x49, 0x80, 0x04, 0x01, ++0x92, 0x04, 0x48, 0x12, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x00, 0x60, 0x00, 0x84, 0x01, 0x10, 0x06, 0x60, 0x18, 0x00, 0x61, 0x20, ++0x86, 0x01, 0x10, 0x06, 0x62, 0x18, 0x00, 0x61, 0x00, 0x86, 0x01, 0x10, 0x06, ++0x40, 0x18, 0x00, 0x61, 0x20, 0x86, 0x81, 0x18, 0x06, 0x60, 0x18, 0x88, 0x61, ++0x00, 0x86, 0x81, 0x58, 0x06, 0x60, 0x18, 0x80, 0x61, 0x00, 0x86, 0x01, 0x18, ++0x06, 0x60, 0x18, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA2, 0x06, 0x20, 0x1E, 0x00, 0x70, 0x00, 0xC2, 0x01, 0x00, 0x07, 0x20, 0x1E, ++0x00, 0x70, 0x00, 0xC2, 0x01, 0x88, 0x07, 0x20, 0x1C, 0x00, 0x70, 0x00, 0xC0, ++0x01, 0x00, 0x07, 0x20, 0x1C, 0x80, 0x70, 0x00, 0xE2, 0x01, 0x88, 0x07, 0x20, ++0x1E, 0x80, 0x78, 0x00, 0xC2, 0x01, 0x88, 0x07, 0x20, 0x1E, 0x80, 0x78, 0x00, ++0xE2, 0x01, 0x88, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, ++0x4A, 0x00, 0x26, 0x83, 0x90, 0x04, 0x40, 0x12, 0x08, 0x49, 0x00, 0x26, 0x81, ++0x90, 0x04, 0x40, 0x12, 0x80, 0x49, 0x00, 0x24, 0x81, 0x90, 0x04, 0x42, 0x12, ++0x08, 0x41, 0x00, 0x24, 0x01, 0x90, 0x04, 0x60, 0x10, 0x80, 0x41, 0x00, 0x26, ++0x01, 0x98, 0x04, 0x40, 0x10, 0x80, 0x49, 0x00, 0x06, 0x01, 0x98, 0x04, 0x60, ++0x12, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x42, ++0x20, 0x04, 0x81, 0x18, 0x05, 0x62, 0x10, 0x88, 0x41, 0x20, 0x04, 0x81, 0x18, ++0x04, 0x62, 0x10, 0x08, 0x51, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, 0x10, 0x88, ++0x41, 0x20, 0x06, 0x81, 0x18, 0x04, 0x42, 0x10, 0x08, 0x41, 0x20, 0x04, 0x81, ++0x10, 0x04, 0x62, 0x10, 0x08, 0x41, 0x20, 0x04, 0x81, 0x10, 0x04, 0x42, 0x10, ++0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x42, 0x00, ++0x02, 0x81, 0x28, 0x0C, 0xA2, 0x30, 0x88, 0x42, 0x00, 0x02, 0x83, 0x28, 0x0C, ++0xA0, 0x10, 0x80, 0xC0, 0x20, 0x0A, 0x83, 0x28, 0x0C, 0xA2, 0x30, 0x88, 0xC2, ++0x00, 0x0A, 0x03, 0x28, 0x04, 0x22, 0x10, 0x80, 0x40, 0x20, 0x02, 0x01, 0x08, ++0x04, 0xA2, 0x10, 0x88, 0x40, 0x20, 0x02, 0x81, 0x08, 0x04, 0x22, 0x10, 0x88, ++0x00, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x00, 0x0A, ++0x01, 0x28, 0x05, 0xA0, 0x10, 0x80, 0xC2, 0x00, 0x0A, 0x03, 0x28, 0x0C, 0xA0, ++0x10, 0x80, 0x52, 0x00, 0x0A, 0x01, 0x28, 0x04, 0xA0, 0x10, 0x80, 0xC2, 0x00, ++0x0A, 0x03, 0x28, 0x0C, 0xA0, 0x30, 0x80, 0xC2, 0x00, 0x0A, 0x03, 0x28, 0x0C, ++0x80, 0x30, 0x80, 0xC2, 0x00, 0x0A, 0x03, 0x28, 0x04, 0xA0, 0x30, 0x80, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x20, 0x06, 0x00, ++0x08, 0x00, 0x60, 0x00, 0x80, 0x11, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x04, ++0x88, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, ++0x00, 0x08, 0x01, 0x20, 0x04, 0x80, 0x10, 0x00, 0x42, 0x00, 0x08, 0x00, 0x80, ++0x04, 0x80, 0x10, 0x00, 0x42, 0x00, 0x08, 0x01, 0x20, 0x04, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x42, 0x40, 0x00, 0x81, 0x01, ++0x04, 0x04, 0x10, 0x18, 0x40, 0x40, 0x00, 0x83, 0x01, 0x05, 0x04, 0x10, 0x10, ++0x40, 0x40, 0x00, 0x81, 0x01, 0x04, 0x06, 0x10, 0x18, 0x50, 0x40, 0x40, 0x01, ++0x01, 0x0C, 0x04, 0x10, 0x10, 0x40, 0x40, 0x00, 0x01, 0x01, 0x05, 0x84, 0x10, ++0x10, 0x40, 0x40, 0x00, 0x01, 0x01, 0x04, 0x04, 0x10, 0x10, 0x00, 0x88, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x02, 0x20, 0x06, 0x80, 0x18, 0x00, ++0x62, 0x00, 0x88, 0x01, 0x60, 0x06, 0x80, 0x18, 0x00, 0x66, 0x00, 0x88, 0x01, ++0x20, 0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0x88, 0x01, 0x60, 0x06, 0x80, 0x19, ++0x00, 0x62, 0x00, 0x98, 0x01, 0x20, 0x06, 0x80, 0x19, 0x00, 0x62, 0x00, 0x88, ++0x01, 0x20, 0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x02, 0x00, 0x24, 0x00, 0x99, 0x00, 0x64, ++0x02, 0x10, 0x09, 0x00, 0x2E, 0x00, 0x91, 0x00, 0xE0, 0x00, 0x00, 0x09, 0x40, ++0x26, 0x00, 0x91, 0x00, 0x44, 0x02, 0x10, 0x09, 0x00, 0x2E, 0x00, 0xB8, 0x00, ++0x64, 0x00, 0x80, 0x0B, 0x40, 0x26, 0x00, 0xB8, 0x00, 0x64, 0x02, 0x98, 0x09, ++0x40, 0x26, 0x00, 0x99, 0x00, 0x64, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xA2, 0x06, 0x60, 0x14, 0x00, 0x50, 0x00, 0xC2, 0x01, ++0x00, 0x05, 0x20, 0x16, 0x00, 0x50, 0x00, 0x62, 0x01, 0x18, 0x05, 0x20, 0x1C, ++0x00, 0x50, 0x00, 0x40, 0x01, 0x00, 0x05, 0x20, 0x16, 0x80, 0x58, 0x00, 0xC2, ++0x01, 0x88, 0x05, 0x28, 0x1C, 0x80, 0x58, 0x00, 0xC2, 0x01, 0x08, 0x07, 0x20, ++0x1C, 0x80, 0x70, 0x08, 0xC2, 0x01, 0x08, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0A, 0x00, 0x80, 0x00, 0x04, 0x02, 0x10, 0x08, 0xC0, 0x20, 0x00, ++0xA1, 0x00, 0x04, 0x02, 0x10, 0x08, 0x40, 0x20, 0x00, 0x81, 0x00, 0x0C, 0x02, ++0x10, 0x08, 0x40, 0x20, 0x00, 0x81, 0x00, 0x04, 0x02, 0x10, 0x0A, 0xC0, 0x20, ++0x00, 0xA1, 0x00, 0x8C, 0x02, 0x10, 0x08, 0xC0, 0x28, 0x00, 0xE3, 0x00, 0x1C, ++0x02, 0x30, 0x0A, 0xC0, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x00, 0x20, 0x00, 0xA4, 0x00, 0x90, 0x02, 0xC0, 0x0A, 0x00, 0xA9, ++0x20, 0xAC, 0x00, 0xB0, 0x0A, 0xC2, 0x08, 0x00, 0x29, 0x00, 0xAC, 0x00, 0xB0, ++0x02, 0xC0, 0x0A, 0x00, 0xAB, 0x20, 0xAC, 0x82, 0xB0, 0x06, 0xC0, 0x28, 0x08, ++0xAB, 0x00, 0xAC, 0x82, 0xB0, 0x0A, 0xC0, 0x3A, 0x08, 0xAB, 0x00, 0xAC, 0x02, ++0xB0, 0x0E, 0xC0, 0x28, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xA2, 0xC2, 0x20, 0x06, 0x03, 0x18, 0x0C, 0x62, 0x30, 0x80, 0xE1, 0x20, ++0x06, 0x03, 0x18, 0x0C, 0x62, 0x30, 0x88, 0xC1, 0x20, 0x06, 0x03, 0x18, 0x0C, ++0x60, 0x30, 0x80, 0xC1, 0x20, 0x06, 0x83, 0x18, 0x0E, 0x62, 0x30, 0x88, 0xE1, ++0x20, 0x06, 0x83, 0x18, 0x0C, 0x62, 0x38, 0x80, 0xE1, 0x20, 0x06, 0x83, 0x18, ++0x0E, 0x62, 0x30, 0x88, 0x01, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x80, 0x02, 0x00, 0x04, 0x80, 0x10, 0x00, 0x40, 0x00, 0x08, 0x01, 0x00, 0x04, ++0x80, 0x10, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x80, 0x10, 0x00, 0x42, ++0x00, 0x08, 0x11, 0x00, 0x44, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x84, 0x00, 0x10, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, ++0x12, 0x22, 0x06, 0x88, 0x18, 0x20, 0x62, 0x80, 0x88, 0x11, 0x20, 0x06, 0x88, ++0x18, 0x20, 0x62, 0x84, 0x88, 0x01, 0x22, 0x06, 0x88, 0x18, 0x20, 0x62, 0x80, ++0x88, 0x01, 0x22, 0x06, 0x88, 0x18, 0x01, 0x62, 0x84, 0x88, 0x31, 0x20, 0x46, ++0x80, 0x18, 0x20, 0x62, 0x04, 0x80, 0x11, 0x20, 0x46, 0x88, 0x18, 0x01, 0x62, ++0x84, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x02, ++0x02, 0x0A, 0x88, 0x28, 0x20, 0xA2, 0x80, 0x88, 0x22, 0x00, 0x0A, 0x88, 0x28, ++0x00, 0xA0, 0x80, 0x80, 0x02, 0x22, 0x0A, 0x88, 0x28, 0x20, 0xA2, 0x80, 0x88, ++0x02, 0x02, 0x0A, 0x00, 0x28, 0x20, 0xA2, 0x80, 0x80, 0x02, 0x22, 0x0A, 0x02, ++0x28, 0x20, 0xA2, 0x80, 0x80, 0x02, 0x20, 0x0A, 0x88, 0x28, 0x20, 0xA2, 0x00, ++0x88, 0x02, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x04, ++0x42, 0x10, 0x28, 0x01, 0xA0, 0x04, 0x81, 0x12, 0x04, 0x42, 0x10, 0x28, 0x41, ++0xA0, 0x04, 0x81, 0x10, 0x04, 0x4A, 0x10, 0x28, 0x41, 0xA0, 0x04, 0x81, 0x12, ++0x04, 0x4A, 0x10, 0x28, 0x01, 0x20, 0x04, 0x81, 0x10, 0x04, 0x42, 0x10, 0x08, ++0x01, 0xA0, 0x04, 0x81, 0x10, 0x00, 0x42, 0x10, 0x08, 0x41, 0x20, 0x04, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xA0, 0x40, ++0x01, 0x00, 0x05, 0x08, 0x14, 0x00, 0x50, 0x80, 0x40, 0x01, 0x02, 0x05, 0x00, ++0x14, 0x28, 0x50, 0x00, 0x40, 0x01, 0x00, 0x05, 0x00, 0x14, 0x20, 0x50, 0x00, ++0x40, 0x01, 0x00, 0x85, 0x08, 0x34, 0x20, 0x50, 0x80, 0x40, 0x03, 0x02, 0x05, ++0x00, 0x14, 0x20, 0x50, 0x80, 0x40, 0x01, 0x02, 0x05, 0x08, 0x14, 0x20, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0xB2, 0xC0, 0xCA, 0x82, ++0x21, 0x0B, 0xA4, 0x2C, 0x18, 0xB2, 0xC0, 0xCA, 0x02, 0x28, 0x0B, 0x84, 0x2C, ++0xB0, 0xB2, 0x40, 0xC8, 0x82, 0x21, 0x0B, 0x86, 0x2C, 0x80, 0xB2, 0x40, 0xC8, ++0x02, 0x21, 0x0B, 0xAC, 0x2C, 0xB0, 0xB2, 0xC0, 0xCA, 0x02, 0x2B, 0x0B, 0x84, ++0x2C, 0xB0, 0xB2, 0xC0, 0xCA, 0x02, 0x2B, 0x0B, 0xAC, 0x2C, 0xB0, 0x02, 0x88, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x12, 0x20, 0x4E, 0x80, 0x38, ++0x01, 0xEA, 0x04, 0x88, 0x13, 0x60, 0x4E, 0x80, 0x3A, 0x01, 0xE6, 0x04, 0x88, ++0x13, 0x20, 0x4E, 0x80, 0x38, 0x01, 0xE2, 0x04, 0xA8, 0x13, 0x60, 0x4E, 0x00, ++0x39, 0x01, 0xE2, 0x24, 0x98, 0x13, 0x20, 0x4E, 0x82, 0x39, 0x01, 0xE2, 0x04, ++0x88, 0x13, 0x20, 0x4E, 0x82, 0x38, 0x01, 0xE2, 0x04, 0x88, 0x03, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x02, 0x03, 0x08, 0x0C, ++0x20, 0x30, 0x80, 0xC0, 0x00, 0x02, 0x03, 0x08, 0x0C, 0x20, 0x31, 0x80, 0xC0, ++0x10, 0x02, 0x03, 0x08, 0x0C, 0x20, 0x30, 0x80, 0xC0, 0x08, 0x02, 0x03, 0x08, ++0x0C, 0x20, 0x31, 0x82, 0xC0, 0x18, 0x02, 0x43, 0x08, 0x0C, 0x20, 0x30, 0x86, ++0xC0, 0x00, 0x02, 0x63, 0x08, 0x0C, 0x21, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, ++0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, ++0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, ++0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, ++0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x34, 0xDB, 0xD0, 0x6C, 0x43, 0xB3, 0x2F, 0xCD, 0x36, ++0xFC, 0xDF, 0xD0, 0x6C, 0x43, 0xFB, 0x0D, 0xCD, 0x36, 0x34, 0xDB, 0xD0, 0x6C, ++0x43, 0xB3, 0x0D, 0xCD, 0x36, 0x34, 0xDB, 0xD0, 0x7E, 0xC3, 0xB7, 0x2F, 0xCD, ++0x36, 0x7C, 0xDB, 0xF0, 0x7F, 0x43, 0xB3, 0x2F, 0xDF, 0x36, 0xFC, 0xFF, 0xD2, ++0x6C, 0xC3, 0xB7, 0x0D, 0xED, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xCC, 0x3C, 0x32, 0xF3, 0xC8, 0xCC, 0x2F, 0x33, 0x8F, 0xFC, ++0x3F, 0x32, 0xF3, 0xC8, 0xFC, 0x23, 0x33, 0x8F, 0xCC, 0x3C, 0x32, 0xF3, 0xC8, ++0xCC, 0x23, 0x33, 0x8F, 0xCC, 0x3C, 0x32, 0xFF, 0xC8, 0xCF, 0x2F, 0x33, 0x8F, ++0xFC, 0x3C, 0xF2, 0xFF, 0xC8, 0xCC, 0x2F, 0x3F, 0x8F, 0xFC, 0xFF, 0x32, 0xF3, ++0xC8, 0xCF, 0x23, 0xF3, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xDC, 0x18, 0x12, 0x63, 0x48, 0x8C, 0x27, 0x31, 0x86, 0xDC, 0x1E, ++0x12, 0x63, 0x48, 0xEC, 0x21, 0x37, 0x86, 0xC4, 0x78, 0x12, 0x63, 0x48, 0x8C, ++0x21, 0x31, 0x86, 0xC4, 0x1E, 0x12, 0x7B, 0xC8, 0x8D, 0x27, 0xB7, 0x87, 0xDC, ++0x7E, 0x72, 0x7B, 0x48, 0x8C, 0x27, 0xB7, 0x9F, 0xDC, 0x7E, 0x12, 0xFB, 0xC9, ++0x8D, 0x27, 0xB7, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x40, 0xE1, 0x0C, 0x85, 0x33, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, ++0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, ++0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0xCE, 0x50, 0x08, 0x40, 0x21, ++0x00, 0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0xE1, 0x0C, 0x85, 0x00, 0x14, ++0x02, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, ++0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x01, 0x02, ++0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x21, 0x40, 0x84, 0x00, 0x11, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, ++0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, ++0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, ++0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, ++0x0C, 0x80, 0x33, 0x00, 0x02, 0x04, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, ++0x02, 0x00, 0x08, 0x00, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, ++0x20, 0x00, 0x80, 0x00, 0x00, 0xCE, 0x00, 0x08, 0x00, 0x20, 0x40, 0x80, 0x00, ++0x00, 0x02, 0x04, 0x08, 0x00, 0xE0, 0x4C, 0x80, 0x00, 0x01, 0x02, 0x00, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0xCC, 0x40, 0x00, 0x10, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x44, 0x00, 0x10, 0x01, 0x00, 0x04, 0x33, 0x10, 0x00, 0x40, 0x00, 0x00, 0xC1, ++0x0C, 0x04, 0x00, 0x10, 0xCC, 0x40, 0x30, 0x03, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0xC1, 0x0C, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, ++0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, ++0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, ++0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, ++0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, ++0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, ++0xCC, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x30, 0x13, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, ++0x54, 0x08, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, ++0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, ++0x02, 0x54, 0x08, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x50, ++0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, ++0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, ++0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, ++0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, ++0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, ++0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, ++0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, ++0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x00, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, ++0xE0, 0x0C, 0x80, 0x33, 0x00, 0x02, 0x00, 0x38, 0x03, 0x20, 0x00, 0x80, 0x33, ++0x00, 0x02, 0x00, 0x38, 0x03, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x08, ++0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x38, 0x03, 0xE0, 0x0C, 0x80, ++0x00, 0x00, 0xCE, 0x00, 0x38, 0x43, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x00, 0x00, 0x21, 0x00, 0x84, 0x33, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, ++0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, ++0xCE, 0x40, 0x08, 0x00, 0xE1, 0x0C, 0x84, 0x00, 0x10, 0xCE, 0x40, 0x38, 0x03, ++0x21, 0x00, 0x84, 0x33, 0x10, 0xCE, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x33, ++0x10, 0x02, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x40, 0x00, 0x00, 0x81, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x02, ++0x10, 0x00, 0x40, 0x20, 0x00, 0x01, 0x00, 0x04, 0x02, 0x10, 0x08, 0x40, 0x00, ++0x00, 0x81, 0x00, 0x04, 0x02, 0x10, 0x00, 0x40, 0x00, 0x00, 0x81, 0x00, 0x04, ++0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x00, 0x84, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, ++0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x02, 0x40, ++0x00, 0x00, 0x21, 0x00, 0x04, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x01, 0x00, ++0x84, 0x00, 0x10, 0x02, 0x40, 0x00, 0x00, 0x01, 0x00, 0x84, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, ++0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, ++0x00, 0xC0, 0x0C, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x30, 0x03, 0x00, 0x00, 0x00, ++0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, ++0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, ++0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, ++0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, ++0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, ++0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, ++0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, ++0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, 0x85, ++0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, 0x50, ++0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, ++0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, ++0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, ++0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, ++0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, ++0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, ++0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, ++0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, ++0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, ++0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, ++0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, ++0x40, 0x80, 0x00, 0x01, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, ++0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, ++0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, ++0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, ++0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, ++0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, ++0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, ++0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x10, 0x00, 0x44, 0x00, ++0x10, 0x01, 0x00, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, ++0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0xCE, 0x54, ++0x08, 0x50, 0x21, 0x40, 0x85, 0x33, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, 0x40, ++0x85, 0x00, 0x15, 0x02, 0x54, 0x38, 0x53, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, ++0x54, 0x08, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, ++0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, ++0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, ++0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, ++0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, ++0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, ++0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, ++0x00, 0x10, 0x02, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x08, 0x00, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, 0xE0, ++0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, 0xE0, 0x0C, 0x80, 0x33, 0x00, ++0x02, 0x00, 0x38, 0x03, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, ++0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, 0x20, 0x00, 0x80, 0x33, ++0x00, 0xCE, 0x00, 0x38, 0x43, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, ++0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, ++0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, ++0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, ++0x02, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, ++0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, ++0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, ++0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, ++0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, ++0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, ++0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, ++0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x80, ++0x40, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x22, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x80, 0x40, ++0x40, 0x00, 0x00, 0x0C, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, 0x00, ++0x00, 0x22, 0x25, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, ++0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0xA0, 0x0C, 0x00, 0x05, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, 0x00, 0x00, 0x87, 0xE8, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00 ++}; +diff --git a/drivers/staging/me4000/me4610_firmware.h b/drivers/staging/me4000/me4610_firmware.h +new file mode 100644 +index 0000000..c550d99 +--- /dev/null ++++ b/drivers/staging/me4000/me4610_firmware.h +@@ -0,0 +1,5409 @@ ++/* ++ This file is copyright by Meilhaus Electronic GmbH 2003. ++ You are not allowed to distribute, sell, modify, reverse engineer or use this ++ code (or parts of it) for any other purpose or under any other conditions ++ than stated below. ++ ++ 1) You are allowed to distribute verbatim copies of this file together ++ with device drivers for the Meilhaus ME-4000, board family. ++ ++ 2) Derived work (device drivers using this file) can be published 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. Any other license terms have ++ to be agreed by Meilhaus GmbH in written. ++ ++ 2) This file is distributed WITHOUT ANY WARRANTY; ++ without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. Meilhaus is under ++ no means liable for products using this file or parts of it. ++ ++ 3) The copyright of this file has to be mentioned in derived work. ++ ++ 4) If this license terms are not valid due to any other law ++ or restrictions imposed on you, you are not allowed to use ++ this file in any way at all. ++ */ ++ ++/* Version 0 of ME-4610 firmware */ ++static unsigned char xilinx_firm_4610[] = { ++0x00, 0x01, 0x11, 0x0c, 0x01, 0x01, 0x04, 0x00, 0x00, 0x09, 0x04, 0x02, 0x00, ++0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0x99, 0xAA, 0x66, 0x0C, 0x00, ++0x01, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x0C, 0x80, 0x06, 0x80, 0x00, 0x00, 0x00, ++0xD0, 0x0C, 0x80, 0x04, 0x80, 0x00, 0x01, 0xFC, 0xB4, 0x0C, 0x00, 0x03, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x90, 0x0C, ++0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, ++0x00, 0x80, 0x0C, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x7C, 0x20, 0x40, 0x58, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x40, 0x48, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, ++0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x58, 0x80, 0x54, 0x00, ++0x44, 0x01, 0x18, 0x05, 0x60, 0x04, 0x80, 0x01, 0x00, 0x66, 0x00, 0xD8, 0x00, ++0x60, 0x0A, 0x80, 0x2D, 0x00, 0xF6, 0x00, 0xD8, 0x03, 0x60, 0x0A, 0x80, 0x69, ++0x00, 0xC6, 0x01, 0x98, 0x05, 0x20, 0x16, 0xFC, 0x23, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0xFF, 0x00, 0xBF, 0x00, 0xDC, 0x32, 0xF0, ++0x13, 0xC0, 0x4F, 0x00, 0xFB, 0x28, 0xBC, 0x04, 0xB0, 0x17, 0xC0, 0x4E, 0x12, ++0x1B, 0x10, 0xFC, 0x13, 0x30, 0x93, 0xC0, 0x4B, 0x00, 0x1F, 0x01, 0xFC, 0x24, ++0x30, 0xCF, 0xE2, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x08, 0x37, 0x01, 0x9D, 0x06, 0x44, 0x30, 0xD1, 0x11, 0x40, 0x47, 0x00, ++0xFD, 0x0A, 0x74, 0x06, 0x10, 0x09, 0x40, 0x17, 0x09, 0x11, 0x42, 0xF4, 0x0B, ++0x50, 0x49, 0x40, 0x06, 0x0C, 0x1D, 0x00, 0x74, 0x00, 0x10, 0x8F, 0x40, 0x04, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x33, 0x00, ++0x8D, 0x18, 0x05, 0x16, 0xDA, 0x08, 0x40, 0x33, 0x00, 0xCD, 0x40, 0x74, 0x03, ++0x91, 0x0C, 0x40, 0x35, 0x01, 0x0D, 0x20, 0x34, 0xA3, 0x10, 0x48, 0x40, 0x01, ++0x01, 0xCD, 0xA0, 0x74, 0x13, 0xD2, 0x4C, 0x40, 0x44, 0x80, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x34, 0x00, 0x9D, 0x01, 0x44, 0x86, ++0xD0, 0x39, 0x40, 0x07, 0x00, 0xDD, 0x00, 0x64, 0x8A, 0x10, 0x89, 0x02, 0x37, ++0x00, 0x15, 0x10, 0x74, 0x03, 0x50, 0x19, 0x07, 0x47, 0x20, 0x5D, 0x04, 0x74, ++0xA3, 0xDA, 0x0D, 0x48, 0x0C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA8, 0x77, 0x00, 0x1F, 0x91, 0x4C, 0x86, 0xE0, 0x19, 0xC0, 0x57, ++0x21, 0xDB, 0x00, 0x7C, 0x01, 0xB0, 0x05, 0x80, 0x06, 0x91, 0x1B, 0x0B, 0x7C, ++0x03, 0x31, 0x31, 0xC0, 0x47, 0x01, 0x9F, 0x44, 0x7C, 0x02, 0xD0, 0x0D, 0x60, ++0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, ++0x02, 0x3E, 0x40, 0xE8, 0x00, 0xF0, 0x0B, 0x40, 0x8F, 0x00, 0xFE, 0x00, 0xF4, ++0x48, 0xF0, 0x0B, 0xC0, 0x1F, 0x80, 0x1A, 0x20, 0xBC, 0x03, 0xE1, 0x0B, 0xC8, ++0x0E, 0x00, 0x3E, 0x01, 0xF8, 0x02, 0x30, 0x0F, 0xD1, 0x1F, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0x9F, 0x00, 0x5C, ++0x46, 0x70, 0x09, 0xC0, 0x37, 0x00, 0xDF, 0x20, 0x7C, 0x21, 0x30, 0x0D, 0xC4, ++0x34, 0x00, 0xDF, 0x00, 0x4C, 0x83, 0xB0, 0x29, 0xC0, 0x84, 0x08, 0x9F, 0x44, ++0x7C, 0x43, 0xF0, 0x0C, 0xC4, 0x0A, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0xA0, 0x34, 0x00, 0x9D, 0x00, 0x74, 0x0A, 0x90, 0x09, 0x40, ++0x67, 0x00, 0xF0, 0x80, 0x34, 0x04, 0xB0, 0xB9, 0x40, 0x32, 0x00, 0xD1, 0x41, ++0xC0, 0x03, 0xD0, 0x09, 0x40, 0x07, 0x00, 0x51, 0x00, 0x34, 0x43, 0xD0, 0x3F, ++0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, ++0x32, 0x10, 0x1D, 0x40, 0x30, 0x00, 0x90, 0x10, 0x40, 0xA3, 0x84, 0xC9, 0x00, ++0x34, 0x00, 0x10, 0x08, 0x40, 0x20, 0x00, 0xC0, 0x21, 0x00, 0x03, 0x90, 0x00, ++0x40, 0x00, 0x00, 0x49, 0x83, 0x04, 0x89, 0xD8, 0x0C, 0x40, 0x1C, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x82, 0x78, 0x02, 0xEC, 0x81, ++0xB4, 0x05, 0x9A, 0x92, 0x60, 0x4B, 0x90, 0xE1, 0xA9, 0xB6, 0x06, 0x90, 0x1A, ++0x60, 0x7A, 0x00, 0xE1, 0x13, 0xA4, 0x07, 0xC0, 0x12, 0x40, 0x4F, 0x00, 0x61, ++0x35, 0xB4, 0x25, 0xC0, 0x9F, 0x61, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x10, 0x4D, 0x00, 0x1C, 0xA1, 0x78, 0x80, ++0xE1, 0x33, 0x25, 0xCF, 0x20, 0x3C, 0x23, 0x30, 0x2C, 0xC1, 0x34, 0x08, 0x07, ++0x05, 0x0D, 0x03, 0xB0, 0xC0, 0xE8, 0x10, 0x22, 0xCF, 0x41, 0x3C, 0x17, 0xF2, ++0xDD, 0xD0, 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xB2, 0x3D, 0x08, 0xFF, 0x00, 0xFE, 0xA3, 0x80, 0x8F, 0xC2, 0x1B, 0x00, 0xFF, ++0x80, 0xFE, 0x03, 0xF0, 0x0B, 0x40, 0x3F, 0x10, 0x37, 0x08, 0xDC, 0x63, 0xF0, ++0x87, 0xC6, 0x3F, 0x08, 0xDF, 0x00, 0x7C, 0x23, 0xFA, 0x8F, 0xC2, 0x09, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x77, 0x00, 0x57, ++0x00, 0x7C, 0x03, 0xF0, 0x11, 0xC0, 0x35, 0x00, 0xDF, 0x10, 0x5C, 0x01, 0xF0, ++0x18, 0xC0, 0x66, 0x00, 0xD3, 0x00, 0x6C, 0x13, 0xF0, 0x01, 0xC8, 0x17, 0x10, ++0x9F, 0x00, 0x7C, 0x03, 0x32, 0xBD, 0xC5, 0x54, 0x20, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x98, 0x3D, 0x00, 0x61, 0x80, 0xB6, 0x01, 0xD0, ++0x0A, 0x48, 0x38, 0x00, 0xFD, 0x06, 0x84, 0x03, 0xD2, 0x0A, 0x40, 0x39, 0x40, ++0xF1, 0x80, 0x86, 0x43, 0xD0, 0x0A, 0x48, 0x1B, 0x00, 0xED, 0x00, 0xB4, 0x03, ++0x10, 0x0F, 0x40, 0x48, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0x00, 0x79, 0x80, 0xE5, 0x01, 0x94, 0x07, 0xD0, 0x17, 0x40, 0x79, 0x08, ++0xEC, 0x01, 0x94, 0x07, 0xD0, 0x1F, 0x40, 0x7B, 0x00, 0xE1, 0x01, 0x84, 0x07, ++0xD0, 0x1E, 0x60, 0x79, 0x00, 0xAD, 0x11, 0xA4, 0x07, 0x50, 0x1E, 0x40, 0x0C, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x23, 0x00, ++0xC1, 0x00, 0x34, 0x03, 0xD0, 0x0C, 0x42, 0x31, 0x02, 0xCD, 0x00, 0x14, 0x4B, ++0xD1, 0x08, 0x40, 0x31, 0x00, 0xC1, 0x0D, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x73, ++0x01, 0xCD, 0x80, 0x74, 0x0B, 0x50, 0x0C, 0x40, 0x48, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x14, 0x01, 0x77, 0x03, 0xFC, 0x29, ++0xD0, 0x17, 0xC1, 0x5D, 0x00, 0x5F, 0x00, 0x9C, 0x19, 0xD0, 0x07, 0xC0, 0x1E, ++0x00, 0x73, 0x02, 0x4C, 0x01, 0xF0, 0x47, 0xC0, 0x1F, 0x8C, 0x7F, 0x00, 0xFC, ++0x09, 0x72, 0x05, 0x40, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x08, 0x7C, 0x00, 0xD0, 0x11, 0x40, 0x46, ++0x00, 0x0E, 0x40, 0x68, 0x00, 0xF0, 0x01, 0xC0, 0x06, 0x00, 0x1F, 0x42, 0x5C, ++0x00, 0xB2, 0x11, 0xC0, 0x07, 0x00, 0x1B, 0x10, 0x7C, 0x10, 0x82, 0x01, 0xC0, ++0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x27, ++0x00, 0x8F, 0x10, 0x54, 0x0A, 0xF2, 0x09, 0x40, 0x27, 0x00, 0x9B, 0x00, 0x4C, ++0x06, 0xD0, 0x99, 0xC0, 0x27, 0x00, 0x8F, 0x04, 0x5C, 0x82, 0xE0, 0x09, 0xC0, ++0x27, 0x00, 0x97, 0x00, 0x7C, 0x02, 0x30, 0x89, 0xC2, 0x43, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x10, 0x9C, 0x00, 0x54, ++0x02, 0xD0, 0xB9, 0x40, 0xE7, 0x00, 0x9D, 0x00, 0x44, 0x6A, 0x10, 0x19, 0x04, ++0x27, 0x00, 0x9D, 0x02, 0x45, 0x02, 0xC2, 0x09, 0x40, 0x27, 0x00, 0x90, 0x13, ++0x74, 0x22, 0x10, 0x59, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x44, 0x02, 0x90, 0x09, 0x40, ++0xE7, 0x00, 0x9D, 0x80, 0x45, 0x02, 0x90, 0x09, 0x41, 0x26, 0x00, 0x9D, 0x02, ++0x44, 0x82, 0x90, 0x09, 0x40, 0x23, 0x00, 0x91, 0x01, 0x74, 0x02, 0x10, 0x09, ++0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x20, 0x02, 0x8D, 0x14, 0x14, 0x56, 0xD0, 0x0C, 0x40, 0x23, 0x08, 0x8D, 0x00, ++0x04, 0x02, 0x10, 0x08, 0x40, 0x23, 0x02, 0x8D, 0x00, 0x04, 0x02, 0xD0, 0x88, ++0x00, 0x23, 0x02, 0x81, 0x00, 0x30, 0x02, 0x14, 0x48, 0x49, 0x43, 0x80, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x86, 0x00, 0x1F, 0x24, ++0x4C, 0x10, 0xF0, 0x01, 0xC0, 0x07, 0x10, 0x1E, 0x14, 0x4C, 0x00, 0xB0, 0xA1, ++0xC2, 0x83, 0x00, 0x1F, 0x1E, 0x4C, 0x78, 0xF0, 0x21, 0xC0, 0x87, 0x00, 0x17, ++0x0A, 0x3C, 0x81, 0x30, 0x41, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x19, 0xB0, 0x2F, 0x01, 0xBF, 0x94, 0xFC, 0x52, 0xF2, 0x0A, ++0xC8, 0x2F, 0x00, 0x9C, 0x14, 0xFC, 0x02, 0xB0, 0x1F, 0x80, 0x2F, 0x01, 0xBF, ++0x81, 0x70, 0x06, 0xF1, 0x4F, 0xC0, 0x2F, 0x41, 0xBF, 0x01, 0xFC, 0x53, 0xF0, ++0x49, 0x41, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, ++0x80, 0x23, 0x00, 0x97, 0x08, 0xF0, 0x37, 0x30, 0x0A, 0xC0, 0x2F, 0x20, 0x9F, ++0x0C, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0xA2, 0x00, 0xBF, 0x10, 0x4C, 0x02, 0xF0, ++0x29, 0xC0, 0x25, 0x02, 0xB3, 0x00, 0xFC, 0x02, 0x30, 0x0B, 0xC0, 0x64, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x01, 0x01, ++0x05, 0x74, 0x3D, 0xB0, 0x01, 0x40, 0x17, 0x00, 0x1D, 0x01, 0x74, 0x01, 0xD1, ++0x01, 0x40, 0x04, 0x00, 0x0D, 0x02, 0x51, 0x28, 0x91, 0x01, 0x40, 0x14, 0x11, ++0x11, 0x00, 0x74, 0x00, 0x10, 0x01, 0x48, 0x71, 0x00, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x04, 0x85, 0x42, 0x34, 0x02, 0x59, ++0x08, 0x40, 0x23, 0x08, 0x8D, 0x02, 0x34, 0x02, 0xD0, 0x09, 0x42, 0x22, 0x10, ++0x8D, 0x00, 0x16, 0x82, 0xD0, 0x09, 0x40, 0x21, 0x00, 0xC5, 0x20, 0x74, 0x02, ++0x11, 0x08, 0x50, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0xA8, 0x21, 0x00, 0x91, 0x04, 0x74, 0x03, 0xD0, 0x39, 0x60, 0x27, 0x08, ++0x9D, 0x00, 0x74, 0x02, 0xD0, 0x8D, 0x42, 0x24, 0x00, 0x9D, 0x00, 0x54, 0x02, ++0xD0, 0x09, 0x40, 0x24, 0x40, 0x95, 0x04, 0x74, 0x02, 0x52, 0x09, 0x40, 0x61, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, 0x25, 0x08, ++0x97, 0x93, 0x78, 0x0A, 0x74, 0x19, 0xC0, 0xE7, 0x00, 0x9F, 0x00, 0x7C, 0x0A, ++0xF0, 0x08, 0xC8, 0xE6, 0x01, 0x9F, 0xB8, 0x5C, 0x02, 0xF0, 0x28, 0xC2, 0x25, ++0x00, 0x97, 0x04, 0x3C, 0x0E, 0x20, 0x09, 0xC4, 0x14, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0x64, 0x02, 0x9F, 0x00, 0x3C, 0x16, ++0xB0, 0x09, 0xC4, 0xE7, 0x00, 0x9F, 0x80, 0x7C, 0x26, 0xF0, 0x09, 0xC0, 0x27, ++0x01, 0x9F, 0x01, 0x68, 0x02, 0xB0, 0x29, 0xC4, 0x27, 0x01, 0x9B, 0x00, 0x7C, ++0x0E, 0xB4, 0x08, 0x40, 0x52, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x08, 0x05, 0x00, 0x13, 0x02, 0x4C, 0x08, 0xF0, 0x61, 0xC0, 0x07, ++0x00, 0x17, 0x00, 0x4C, 0x40, 0xF0, 0x21, 0x40, 0x04, 0x00, 0x03, 0x42, 0x5C, ++0x00, 0x30, 0x21, 0xC0, 0x87, 0x10, 0x1F, 0x00, 0x4C, 0x08, 0xF0, 0x01, 0xD1, ++0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x14, ++0x00, 0x51, 0x00, 0xC4, 0x0D, 0xD0, 0x37, 0x40, 0x1C, 0x02, 0x51, 0x20, 0xCC, ++0x41, 0xD2, 0x07, 0x48, 0x14, 0x00, 0x71, 0x49, 0x44, 0x81, 0x50, 0x05, 0x40, ++0x17, 0x00, 0x7C, 0x82, 0xC4, 0x69, 0xD0, 0x07, 0x40, 0x50, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x60, 0xC1, 0x40, 0x14, ++0xCF, 0xC0, 0xB4, 0x40, 0x72, 0x02, 0xC5, 0x00, 0x24, 0x03, 0xD0, 0x8C, 0x40, ++0x30, 0x10, 0xC1, 0x0B, 0x24, 0x03, 0x10, 0x0C, 0x40, 0x37, 0x00, 0xC9, 0x04, ++0x04, 0x80, 0xD0, 0x30, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x82, 0x3C, 0x22, 0xE1, 0x0D, 0x94, 0x43, 0xD0, 0x12, 0x40, ++0x7E, 0x00, 0xC1, 0x01, 0x84, 0x01, 0xD0, 0x0E, 0x40, 0x7C, 0x43, 0x61, 0x00, ++0xA4, 0x27, 0x50, 0x0E, 0x40, 0x3B, 0x10, 0xAD, 0x21, 0x84, 0x01, 0xD0, 0x23, ++0x44, 0x10, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, ++0x78, 0x01, 0xE3, 0x91, 0x9D, 0x07, 0xF0, 0x16, 0xC0, 0x4A, 0x00, 0xE7, 0x01, ++0xAD, 0x07, 0xE1, 0x13, 0xC0, 0x78, 0x02, 0xA3, 0x61, 0xFC, 0x37, 0x30, 0x5E, ++0xC1, 0x7B, 0x00, 0xBB, 0x01, 0x8C, 0x06, 0xFA, 0x1B, 0xC0, 0x50, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB0, 0x35, 0x04, 0xDF, 0x40, ++0x6C, 0x03, 0xF3, 0x01, 0xC0, 0x00, 0x20, 0xDF, 0x00, 0x7C, 0x01, 0xD0, 0x05, ++0x90, 0x37, 0x01, 0x1F, 0x00, 0x5C, 0x93, 0xF1, 0xAD, 0x80, 0xB7, 0x03, 0x9C, ++0x40, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xA0, 0x7F, 0x00, 0xFF, 0x01, 0xDC, 0x25, 0x30, 0x1F, ++0xC0, 0x7F, 0x00, 0xF7, 0x11, 0xFC, 0x26, 0x10, 0x1F, 0xC0, 0x7F, 0x10, 0x7F, ++0x09, 0xCC, 0x87, 0x30, 0x9F, 0xC0, 0xFC, 0x8A, 0xBF, 0x0D, 0xEC, 0x24, 0xF1, ++0x17, 0xC0, 0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0x88, 0x39, 0x24, 0xED, 0x00, 0xF4, 0x03, 0xB0, 0x4A, 0x48, 0x0B, 0x00, 0xED, ++0x04, 0xB4, 0x21, 0x10, 0x4E, 0x42, 0x7B, 0x01, 0x29, 0x01, 0x84, 0x03, 0xF0, ++0x0E, 0x44, 0x38, 0x00, 0x8D, 0x43, 0x34, 0x21, 0xD0, 0x84, 0x40, 0x57, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x39, 0x00, 0xED, ++0x10, 0x94, 0x01, 0x98, 0x02, 0x40, 0x0B, 0x04, 0xED, 0x80, 0xF4, 0x00, 0x90, ++0x02, 0x41, 0x3B, 0x01, 0x0D, 0x08, 0x94, 0x03, 0x10, 0x0E, 0x48, 0x38, 0x20, ++0x25, 0x02, 0xB4, 0x20, 0xD8, 0x0E, 0x40, 0x23, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x33, 0x00, 0xCD, 0x01, 0x74, 0x42, 0x90, ++0x00, 0x40, 0x03, 0x00, 0xCD, 0x00, 0x34, 0x2D, 0x90, 0x10, 0x40, 0x37, 0x00, ++0x19, 0x00, 0x14, 0x03, 0xD0, 0x2D, 0x40, 0xB0, 0x00, 0x0D, 0x08, 0x34, 0x03, ++0xD0, 0x0C, 0x40, 0x1B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0x88, 0x3D, 0x00, 0xFF, 0x01, 0x5C, 0x02, 0xB0, 0xA5, 0xC0, 0x27, 0x90, ++0xF7, 0x00, 0x7C, 0x27, 0xB6, 0xB9, 0xC8, 0x3F, 0x00, 0x9F, 0x20, 0xDC, 0x03, ++0x30, 0xAF, 0xC8, 0x3C, 0x08, 0x8F, 0x01, 0x6C, 0x83, 0xD0, 0x0D, 0xC8, 0x57, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, ++0xDF, 0x10, 0x7C, 0x28, 0xF0, 0x15, 0xC0, 0xA7, 0x00, 0xDF, 0x00, 0x7C, 0x03, ++0x70, 0x21, 0xC0, 0x77, 0x00, 0x1E, 0x42, 0x25, 0x83, 0xB0, 0x8D, 0xC0, 0x37, ++0x00, 0x1D, 0x02, 0x7C, 0x03, 0xD0, 0x0D, 0xC4, 0x27, 0x00, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x08, 0x3F, 0x28, 0xFB, 0x40, 0xFC, 0x02, ++0x30, 0x37, 0xC0, 0x2F, 0x04, 0xFF, 0x00, 0xFC, 0x16, 0xF0, 0x03, 0xC0, 0x3F, ++0x00, 0x33, 0x00, 0xCC, 0x03, 0x71, 0x0F, 0xE0, 0x3C, 0x0C, 0xBF, 0x20, 0xDC, ++0x03, 0xF2, 0x0B, 0xC2, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA1, 0x00, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x06, 0xB0, 0x05, 0xC0, 0xE7, ++0x00, 0xDD, 0x00, 0x74, 0x0A, 0xD0, 0x11, 0x40, 0x36, 0x00, 0x1B, 0x00, 0x6C, ++0x03, 0x10, 0x0D, 0x40, 0x35, 0x00, 0x1C, 0x03, 0x40, 0x04, 0xD0, 0x35, 0x40, ++0x84, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, ++0x00, 0xDD, 0x00, 0x74, 0x04, 0x18, 0x0D, 0x40, 0x67, 0x04, 0xDD, 0x00, 0x64, ++0x0A, 0xD0, 0x1B, 0x40, 0x37, 0x00, 0x31, 0x06, 0xC0, 0x03, 0x00, 0x0D, 0x44, ++0x36, 0x00, 0xBD, 0x01, 0x44, 0xA3, 0xD0, 0x64, 0x50, 0x04, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x80, 0xCD, 0x00, 0x36, ++0x00, 0x18, 0x0C, 0x40, 0x01, 0x00, 0xCD, 0x00, 0x34, 0x03, 0xD1, 0x00, 0x42, ++0x36, 0x21, 0x19, 0x24, 0x24, 0x03, 0x15, 0x0C, 0x40, 0x30, 0x00, 0x1D, 0x04, ++0x04, 0xA6, 0xD0, 0x28, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0xB0, 0x3E, 0x08, 0xFB, 0x80, 0x7C, 0x00, 0x14, 0x01, 0x40, ++0x27, 0x08, 0xDF, 0x00, 0x6C, 0x00, 0xF0, 0x01, 0xC2, 0x3F, 0x05, 0x13, 0x16, ++0x8C, 0x03, 0x70, 0x0E, 0xD0, 0x3C, 0x10, 0x1F, 0x1C, 0x5C, 0x01, 0xF0, 0x21, ++0xC0, 0x04, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB0, ++0x3F, 0x00, 0xFF, 0x40, 0xFC, 0x02, 0xF2, 0x03, 0xC0, 0x0F, 0x00, 0xFF, 0x40, ++0xBC, 0x00, 0xF0, 0x03, 0xC0, 0x36, 0x00, 0x1F, 0x14, 0xFC, 0x03, 0xF0, 0x0F, ++0xC4, 0x3F, 0x00, 0x1F, 0x04, 0xFD, 0x10, 0xF2, 0x43, 0x00, 0x17, 0x60, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7D, 0x02, 0xFA, 0x00, ++0xFC, 0x20, 0xB0, 0x0F, 0xC0, 0x3F, 0x20, 0xF7, 0xA0, 0xEC, 0x03, 0x30, 0x4F, ++0xC4, 0x0D, 0x10, 0x33, 0x01, 0xFC, 0x27, 0xF1, 0x33, 0xC0, 0x3E, 0x00, 0x2F, ++0x01, 0x6C, 0x80, 0xF2, 0x03, 0xC4, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x08, 0x37, 0x20, 0xF1, 0x82, 0x34, 0x3A, 0x10, 0x3F, ++0x40, 0xBE, 0x16, 0xF1, 0x89, 0xF4, 0x0F, 0x10, 0x9F, 0xC8, 0x45, 0x32, 0x95, ++0x00, 0x74, 0x11, 0xD1, 0x41, 0x40, 0x3F, 0x20, 0x1D, 0x54, 0x44, 0x04, 0xD0, ++0x01, 0x40, 0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, ++0x20, 0x33, 0x11, 0xC1, 0x36, 0x74, 0x03, 0x11, 0x2C, 0x44, 0x33, 0x01, 0xC5, ++0x80, 0x34, 0x23, 0x10, 0x0C, 0x40, 0x03, 0x00, 0x01, 0x00, 0x34, 0x13, 0x90, ++0x00, 0x40, 0x32, 0x00, 0xCD, 0x00, 0x24, 0x80, 0xD8, 0x00, 0x40, 0x47, 0x80, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x75, 0x20, 0xD1, ++0x00, 0x74, 0x07, 0x10, 0x0D, 0x40, 0x36, 0x20, 0xD1, 0x00, 0x74, 0x83, 0x10, ++0x0D, 0x40, 0x97, 0x00, 0x94, 0x04, 0x74, 0x21, 0xD0, 0x11, 0x43, 0x3F, 0x00, ++0x1D, 0x10, 0xC0, 0x60, 0xC0, 0x3B, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x37, 0x40, 0xDB, 0x00, 0x3C, 0x06, 0xB4, ++0x0D, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x6E, 0x03, 0x30, 0x0D, 0xC0, 0x83, 0x00, ++0xD3, 0x80, 0x7C, 0x97, 0xF0, 0x11, 0xC8, 0x36, 0x00, 0xDF, 0x00, 0x6C, 0x00, ++0xF1, 0x31, 0xC0, 0x0B, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x07, 0x80, 0x3D, 0x00, 0xFF, 0x80, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, 0x20, ++0xDF, 0x00, 0xFA, 0x43, 0xF0, 0x0D, 0xC2, 0x4D, 0x01, 0xFF, 0x01, 0xFC, 0x01, ++0xF0, 0x03, 0xC0, 0x3F, 0x00, 0x3F, 0x09, 0xFC, 0x00, 0xF0, 0x03, 0x40, 0x1F, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x01, ++0xDF, 0x08, 0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x33, 0x00, 0xDF, 0x40, 0x3C, 0x03, ++0xF0, 0x0D, 0xC0, 0x27, 0x08, 0xDB, 0x00, 0x7C, 0x03, 0x30, 0x21, 0xC0, 0x37, ++0x04, 0xDF, 0x02, 0x4C, 0x00, 0xF0, 0x09, 0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0xF4, 0x09, 0xFD, 0xC1, 0x74, 0x83, ++0x50, 0x3F, 0x44, 0x3F, 0x00, 0xFC, 0x0A, 0xC4, 0x8F, 0xD0, 0x0F, 0x41, 0x34, ++0x00, 0xDD, 0x01, 0x74, 0x81, 0x00, 0x01, 0x00, 0xFF, 0x00, 0x1C, 0x00, 0x44, ++0x12, 0xD0, 0x39, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0xA0, 0x76, 0x00, 0xC9, 0x47, 0x34, 0x03, 0x18, 0x0C, 0x49, 0x33, ++0x00, 0xCD, 0x03, 0x04, 0x2F, 0xD0, 0x5C, 0x40, 0x31, 0x00, 0x49, 0x00, 0x34, ++0x02, 0x10, 0x00, 0x40, 0xF3, 0x00, 0x1D, 0x00, 0x14, 0x04, 0xD0, 0x00, 0x01, ++0x1F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x78, ++0x00, 0xED, 0x01, 0xB4, 0x27, 0x50, 0x9E, 0x40, 0x7B, 0x00, 0xED, 0x35, 0x85, ++0x07, 0xD0, 0x5E, 0x40, 0x69, 0x80, 0xED, 0x03, 0xF4, 0x06, 0x90, 0x92, 0x02, ++0x7B, 0x00, 0x3D, 0x01, 0x96, 0x24, 0xD0, 0x9A, 0x48, 0x13, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x02, 0xCF, 0x08, 0x3C, ++0x03, 0x3A, 0x0C, 0xC1, 0x33, 0x00, 0xCF, 0x0D, 0x2C, 0x03, 0xF0, 0x5C, 0xC0, ++0x11, 0x00, 0x4B, 0x10, 0x3C, 0x06, 0x30, 0x00, 0xC2, 0x33, 0x06, 0xCF, 0x00, ++0x1C, 0x14, 0xF0, 0x00, 0xC1, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xB8, 0x3D, 0x00, 0xFE, 0x00, 0xF8, 0x03, 0xF8, 0x0F, 0xC9, ++0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC1, 0x1C, 0x00, 0xFF, 0x08, ++0x3C, 0x02, 0x75, 0x07, 0xC6, 0x3F, 0x00, 0xFF, 0x00, 0xED, 0x20, 0xF0, 0x0B, ++0xE8, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, ++0x37, 0x10, 0xDE, 0x44, 0x7C, 0x03, 0x30, 0x5D, 0xC2, 0x34, 0x11, 0xD3, 0x04, ++0x7C, 0x0B, 0xF3, 0x3D, 0xD1, 0x34, 0x00, 0xD3, 0x01, 0x4C, 0x03, 0xF0, 0x01, ++0xD0, 0xB4, 0x07, 0xCE, 0x00, 0x4C, 0x04, 0x32, 0x19, 0xC0, 0x54, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x38, 0x00, 0xED, 0x96, ++0xF4, 0x03, 0xB0, 0x0C, 0x55, 0x38, 0x14, 0xE1, 0x16, 0xB4, 0x5B, 0xD0, 0x4C, ++0x40, 0x20, 0x10, 0xF1, 0x80, 0x84, 0x03, 0xD0, 0x02, 0x40, 0x38, 0x01, 0xED, ++0x00, 0x84, 0x02, 0x11, 0x0B, 0xC0, 0x4A, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0x00, 0x78, 0x00, 0xED, 0x01, 0xB4, 0x07, 0x10, 0x1E, ++0x4A, 0x70, 0x13, 0xE1, 0x01, 0xA4, 0x07, 0xD0, 0x5E, 0x40, 0x78, 0x40, 0xE1, ++0x01, 0x84, 0x07, 0xD0, 0x16, 0x43, 0x78, 0x81, 0xFD, 0x01, 0x04, 0x84, 0x18, ++0x1A, 0x40, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x28, 0x23, 0x02, 0xDD, 0x00, 0x34, 0x03, 0x92, 0x0C, 0x40, 0x30, 0x40, 0xC1, ++0x20, 0x34, 0x03, 0xD0, 0x0C, 0x48, 0x30, 0x04, 0xC1, 0x08, 0x04, 0x07, 0xD0, ++0x2C, 0x41, 0x30, 0x00, 0xDD, 0x10, 0x04, 0x0F, 0x18, 0x3C, 0x40, 0x4A, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x55, 0x00, 0x5F, ++0x80, 0xFC, 0x29, 0x30, 0x05, 0xC0, 0x14, 0x00, 0x43, 0x00, 0x7C, 0x01, 0xF0, ++0x05, 0x82, 0x1C, 0x00, 0x73, 0x03, 0xCD, 0x15, 0xF0, 0x37, 0xC0, 0x14, 0x00, ++0x7F, 0x12, 0xCC, 0x15, 0x30, 0x17, 0xC0, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x20, 0x7C, 0x00, 0xF0, ++0x01, 0xC0, 0x07, 0x08, 0x1F, 0x02, 0x7C, 0x00, 0xF0, 0x01, 0xC8, 0x87, 0x00, ++0x1F, 0x10, 0x7C, 0x80, 0xF3, 0x01, 0xC0, 0x07, 0x30, 0x1F, 0x00, 0x7D, 0x10, ++0xF1, 0x81, 0xC1, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x08, 0x67, 0x00, 0x93, 0x00, 0x4C, 0x02, 0x70, 0x19, 0xC0, 0x27, 0x00, ++0x97, 0x01, 0x5C, 0x26, 0xF0, 0x19, 0xC0, 0x23, 0x00, 0x90, 0x80, 0x7C, 0x02, ++0x30, 0x09, 0xC0, 0xA4, 0x00, 0x9F, 0x05, 0x4C, 0x12, 0xF0, 0x29, 0xC0, 0x43, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xE2, 0x22, ++0x91, 0x00, 0x14, 0x02, 0x10, 0x09, 0x40, 0x27, 0x00, 0x91, 0x03, 0x44, 0x8A, ++0xD0, 0x99, 0x44, 0x27, 0x02, 0x91, 0x02, 0x74, 0x82, 0x12, 0x08, 0x42, 0x24, ++0x00, 0x9D, 0x01, 0x44, 0x02, 0xD0, 0x09, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x44, 0x91, 0x21, 0x54, 0x03, ++0x50, 0x49, 0x41, 0x23, 0x00, 0x95, 0x86, 0x54, 0x0A, 0xD1, 0x09, 0x40, 0x27, ++0x00, 0x95, 0x01, 0x34, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x44, ++0x02, 0xD0, 0x09, 0x41, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x20, 0x24, 0x00, 0xC1, 0x00, 0x54, 0x52, 0x54, 0x08, 0x40, 0x23, ++0x02, 0x81, 0x80, 0x00, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x40, 0x85, 0x01, 0x34, ++0x22, 0x10, 0x89, 0x42, 0x60, 0x01, 0x8D, 0x08, 0x04, 0x12, 0xD0, 0x48, 0x48, ++0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, ++0x00, 0x13, 0x94, 0x5C, 0x10, 0x74, 0x41, 0xC1, 0x87, 0x05, 0x16, 0x94, 0x5C, ++0x50, 0xF1, 0x45, 0xC1, 0x17, 0x05, 0x17, 0x0A, 0x7C, 0x08, 0x34, 0x20, 0xC0, ++0xC4, 0x02, 0x1F, 0x02, 0x4D, 0x04, 0xF0, 0xB1, 0xC0, 0x77, 0xC0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x2F, 0x05, 0x9F, 0x34, 0xFC, ++0x52, 0xB0, 0x09, 0xC2, 0x27, 0x01, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, ++0x2F, 0x00, 0xBB, 0x01, 0xFC, 0x12, 0xF0, 0x4B, 0xD0, 0x67, 0x02, 0xBF, 0x04, ++0xFC, 0x22, 0xF0, 0x9B, 0xC2, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x2F, 0x02, 0xBF, 0x86, 0x0C, 0x16, 0xB0, 0x4B, 0xC0, ++0x27, 0x05, 0xBB, 0x00, 0xDC, 0x82, 0x30, 0x0B, 0xC0, 0x2D, 0x00, 0xBF, 0xC0, ++0x7C, 0x22, 0x30, 0x29, 0xC0, 0x2F, 0x00, 0xB1, 0x02, 0xCC, 0x02, 0xE0, 0x0B, ++0xC0, 0x60, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, ++0x47, 0x01, 0x1D, 0x01, 0x44, 0x5C, 0x10, 0x01, 0x40, 0x87, 0x01, 0x1D, 0x00, ++0x44, 0x00, 0x14, 0xA1, 0x40, 0x04, 0x00, 0x0D, 0x00, 0x74, 0x00, 0x10, 0x01, ++0x40, 0x07, 0x00, 0x15, 0x04, 0x45, 0x00, 0xD2, 0x01, 0x48, 0x70, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, 0x06, ++0x04, 0x22, 0x92, 0x28, 0x40, 0x23, 0x04, 0x8D, 0x22, 0x04, 0x8A, 0x10, 0x08, ++0x50, 0xA0, 0x00, 0x8D, 0x00, 0x34, 0x12, 0x10, 0x08, 0x60, 0x23, 0x10, 0x81, ++0x20, 0x05, 0x83, 0xD0, 0x09, 0x60, 0x42, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x80, 0x9D, 0x00, 0x45, 0x02, 0x10, 0x09, ++0x60, 0x27, 0x00, 0x9D, 0x00, 0x47, 0x02, 0x10, 0x09, 0x00, 0x24, 0x01, 0x9D, ++0x00, 0x74, 0x02, 0x10, 0xA9, 0x40, 0x27, 0x00, 0x95, 0x14, 0x45, 0x0E, 0xD1, ++0x69, 0x40, 0x62, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0x88, 0x67, 0x02, 0x9F, 0x00, 0x4C, 0x36, 0xB0, 0x09, 0xC8, 0x27, 0x00, 0x9B, ++0x40, 0x5C, 0x02, 0x12, 0x09, 0xC0, 0x24, 0x01, 0x9E, 0x00, 0x7C, 0x02, 0x34, ++0x29, 0xC0, 0x27, 0x00, 0x83, 0x01, 0x4C, 0x0E, 0xF2, 0x29, 0xD0, 0x16, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x65, 0x10, 0x9F, ++0x00, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x50, 0x3C, 0x02, 0xF0, ++0x09, 0xC0, 0x26, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, ++0x9F, 0x01, 0x7D, 0x02, 0xF0, 0x09, 0xC0, 0x51, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x04, 0x00, 0x03, 0x00, 0x4D, 0x00, 0x50, ++0x01, 0xC0, 0x05, 0x00, 0x03, 0x08, 0x7C, 0x00, 0xF0, 0x01, 0xC1, 0x87, 0x01, ++0x13, 0x00, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x01, 0x01, 0x13, 0x02, 0x4C, 0x00, ++0x30, 0x21, 0xC1, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0xA0, 0xDC, 0x00, 0x75, 0x19, 0x44, 0x01, 0x50, 0x27, 0xC0, 0x16, 0x50, ++0x71, 0x23, 0xF4, 0x21, 0xD0, 0x06, 0x41, 0x1F, 0x20, 0x75, 0x01, 0x44, 0x01, ++0xD0, 0x05, 0x48, 0x1F, 0x18, 0x75, 0x0A, 0x44, 0x01, 0x11, 0x27, 0xC0, 0x52, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x72, 0x81, ++0xC9, 0x03, 0x04, 0x03, 0x10, 0x9C, 0x41, 0x33, 0x00, 0x81, 0x03, 0x34, 0x2B, ++0xD0, 0x2C, 0x40, 0x33, 0x00, 0xC5, 0x11, 0x44, 0x03, 0xD0, 0x0C, 0x40, 0xF1, ++0x80, 0xC9, 0x01, 0x04, 0x03, 0x12, 0x8D, 0x40, 0x52, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x78, 0x04, 0xED, 0x20, 0xC4, 0x03, ++0x50, 0x1A, 0x40, 0x7A, 0x00, 0xE1, 0x00, 0xB0, 0x01, 0xD0, 0x0E, 0x40, 0x7B, ++0x48, 0xE5, 0x11, 0x84, 0x23, 0xC0, 0x8E, 0x40, 0x13, 0x04, 0xED, 0x10, 0xC4, ++0x07, 0x1C, 0x0B, 0x40, 0x16, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0x10, 0x7C, 0x00, 0xFB, 0x81, 0x8C, 0x47, 0x74, 0x1E, 0xC0, 0x73, ++0x01, 0xA3, 0x01, 0xBC, 0x06, 0xF0, 0x1E, 0xC0, 0x7B, 0x00, 0x67, 0x81, 0x84, ++0xD7, 0xF0, 0x1E, 0xC1, 0x69, 0x20, 0xBB, 0x01, 0x8D, 0x07, 0x30, 0x1B, 0xC0, ++0x56, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, ++0x00, 0xD7, 0x00, 0x7C, 0x33, 0xF0, 0x00, 0xC0, 0xB5, 0x20, 0x9F, 0x00, 0x7C, ++0x00, 0xF1, 0x09, 0xC0, 0x33, 0x00, 0x1B, 0x00, 0x75, 0x03, 0xF2, 0x6D, 0xC0, ++0x07, 0x00, 0x97, 0x00, 0x3C, 0x02, 0xF1, 0x01, 0xC0, 0x43, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x5F, 0x00, 0x7F, 0x01, 0xFC, ++0x07, 0x70, 0x1F, 0xC0, 0xFF, 0x44, 0xB3, 0x09, 0x9C, 0x27, 0x70, 0x9F, 0xC0, ++0x7F, 0x00, 0xA3, 0x41, 0xEC, 0x07, 0x31, 0x1D, 0xC0, 0x4F, 0x00, 0xF3, 0x01, ++0xCC, 0x07, 0x30, 0x9B, 0xC0, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0x88, 0xB9, 0x00, 0x6D, 0x02, 0xB4, 0x03, 0xB0, 0x0A, 0x60, ++0x3B, 0x00, 0xC1, 0x08, 0xB4, 0x82, 0x10, 0x04, 0x48, 0x3B, 0x00, 0x21, 0x00, ++0x04, 0x37, 0x10, 0x1E, 0xC0, 0x0F, 0x00, 0xFB, 0x18, 0xC4, 0x23, 0xB2, 0xCA, ++0x50, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x19, 0x00, 0x6D, 0x08, 0xF4, 0x03, 0x50, 0x0A, 0x40, 0x39, 0x00, 0xA9, 0x80, ++0x94, 0x02, 0x50, 0x0E, 0x60, 0x1B, 0x02, 0x39, 0x00, 0xC4, 0x13, 0x10, 0x0E, ++0x41, 0x0B, 0x00, 0xB1, 0x00, 0xC4, 0x43, 0x50, 0x0A, 0x40, 0x01, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0x43, 0x20, 0x0D, 0x80, ++0x34, 0x03, 0x90, 0x00, 0x40, 0x37, 0x08, 0x49, 0x40, 0x34, 0x02, 0x10, 0x00, ++0x44, 0x53, 0x42, 0x09, 0x02, 0x04, 0x03, 0x94, 0x1D, 0x40, 0x01, 0x00, 0x89, ++0x10, 0x04, 0x06, 0xD8, 0x60, 0x40, 0x11, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0xA8, 0x64, 0x01, 0x9F, 0x00, 0xFC, 0x03, 0x74, 0x01, ++0xC0, 0x3F, 0x00, 0x9B, 0x00, 0x5C, 0x02, 0x50, 0x01, 0xC0, 0x37, 0x08, 0x13, ++0x02, 0xCC, 0x03, 0x30, 0xBF, 0x40, 0x37, 0x00, 0x53, 0x00, 0x4D, 0xAB, 0x50, ++0x09, 0xC1, 0x55, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x00, 0xA7, 0x00, 0x9F, 0x00, 0x7C, 0x43, 0xF0, 0x21, 0xC0, 0x37, 0x00, 0xD7, ++0x20, 0x7C, 0x08, 0xF0, 0x01, 0xC0, 0x33, 0x00, 0x17, 0x82, 0x5C, 0x43, 0x70, ++0x0D, 0xC0, 0x87, 0x00, 0x5F, 0xC2, 0x7C, 0x03, 0xB0, 0x29, 0x88, 0x06, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x2F, 0x20, 0x2F, ++0x80, 0xD4, 0x03, 0x3C, 0x02, 0xC8, 0x34, 0x00, 0xB3, 0x00, 0xDC, 0x00, 0xF0, ++0x2B, 0xE0, 0x24, 0x20, 0x33, 0x10, 0xF4, 0x03, 0xB0, 0x0F, 0xC0, 0x0C, 0x00, ++0x7F, 0x00, 0xCC, 0x27, 0xF0, 0x09, 0xC0, 0x03, 0x22, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xE6, 0x00, 0x9D, 0x43, 0x06, 0x03, 0x10, ++0x11, 0x40, 0x34, 0x00, 0x81, 0x00, 0x44, 0x14, 0xD0, 0x18, 0xE0, 0x26, 0x00, ++0x11, 0x04, 0x74, 0x03, 0xD0, 0x0D, 0xC0, 0x44, 0x01, 0x47, 0x85, 0x7C, 0x02, ++0xD0, 0x51, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0xA0, 0x44, 0x00, 0x9D, 0x21, 0x40, 0x03, 0x92, 0x39, 0x44, 0x34, 0x00, ++0x91, 0x00, 0x56, 0x06, 0xD2, 0x25, 0x48, 0x74, 0x00, 0x31, 0x84, 0x74, 0x83, ++0xD8, 0x0D, 0x40, 0x4C, 0x00, 0x9D, 0x01, 0x45, 0x02, 0xD0, 0x13, 0x40, 0x07, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, ++0x8D, 0x20, 0x54, 0x03, 0x12, 0x08, 0x40, 0x30, 0x20, 0xC1, 0x40, 0x16, 0x02, ++0xD0, 0x24, 0x44, 0x32, 0x10, 0x01, 0x00, 0x34, 0x33, 0xD8, 0x0C, 0x45, 0x00, ++0x10, 0x85, 0x00, 0x34, 0x22, 0xD0, 0x00, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x06, 0x08, 0x1F, 0x00, 0xD4, 0x03, ++0x32, 0x09, 0xC2, 0x3C, 0x00, 0x93, 0x2A, 0x54, 0x00, 0xD9, 0x0D, 0x40, 0x04, ++0x00, 0x13, 0x00, 0xFC, 0x9B, 0xB1, 0x0F, 0xC0, 0x04, 0x00, 0x9F, 0x00, 0x4C, ++0x02, 0xF1, 0x01, 0xC0, 0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0xB2, 0x2F, 0x00, 0xBF, 0x00, 0xAD, 0x03, 0xF1, 0x03, 0xC0, 0x3F, ++0x10, 0x7F, 0x04, 0xEC, 0x00, 0xF0, 0x03, 0xC6, 0x0F, 0x40, 0x3F, 0x00, 0x3C, ++0x0B, 0xF0, 0x0F, 0xC0, 0x0D, 0x10, 0xB7, 0x00, 0xFC, 0x12, 0xF8, 0x03, 0xC0, ++0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x2F, ++0x01, 0xBF, 0x08, 0xFC, 0x43, 0x30, 0x8F, 0xC0, 0x3F, 0x05, 0x3F, 0x03, 0xDC, ++0x23, 0xF0, 0x3B, 0xD0, 0x3C, 0x00, 0xFB, 0x00, 0xFC, 0x13, 0x30, 0x13, 0xC0, ++0x7C, 0x10, 0x3D, 0x61, 0xCC, 0x18, 0x30, 0x43, 0xC1, 0x0C, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, 0x87, 0x1D, 0x9D, 0x02, 0xDC, ++0x0F, 0x00, 0x6F, 0x40, 0xBF, 0x01, 0x1D, 0x04, 0xC4, 0x0B, 0x70, 0x0D, 0x40, ++0xFC, 0x00, 0xF1, 0x03, 0xF4, 0xA7, 0x10, 0x11, 0x40, 0x04, 0x08, 0x1D, 0x00, ++0x04, 0xAB, 0x10, 0x29, 0x51, 0x0C, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0xA0, 0x21, 0x82, 0x0D, 0x08, 0x14, 0x03, 0x10, 0x6C, 0x48, ++0x33, 0x14, 0x9D, 0x00, 0x14, 0x33, 0xD2, 0x48, 0x60, 0x30, 0x0A, 0xC9, 0x08, ++0x34, 0x03, 0x10, 0x01, 0x40, 0x30, 0x20, 0x1D, 0x00, 0x04, 0x10, 0x10, 0x40, ++0x42, 0x4D, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, ++0x47, 0x00, 0x9D, 0x03, 0x54, 0x83, 0x14, 0x0D, 0x40, 0x37, 0x00, 0x9D, 0x01, ++0x44, 0x03, 0x50, 0x0C, 0x60, 0x34, 0x10, 0xD0, 0x00, 0x74, 0x03, 0x14, 0x15, ++0x18, 0x24, 0x00, 0x1D, 0x01, 0x44, 0x81, 0x16, 0x01, 0x41, 0x0D, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xA8, 0xC7, 0x00, 0x9F, 0x01, ++0x5C, 0x03, 0x30, 0x0D, 0xC0, 0x37, 0x00, 0x0F, 0x03, 0x5C, 0x83, 0xF0, 0x8D, ++0xC0, 0x30, 0x08, 0xDB, 0x60, 0x3C, 0x03, 0x30, 0x20, 0xC4, 0x34, 0x00, 0x0F, ++0x53, 0x4C, 0x24, 0x30, 0x11, 0xC4, 0x29, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0x80, 0x0D, 0x00, 0xBF, 0x00, 0xDC, 0x03, 0xF1, 0x0D, ++0xC0, 0x3F, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0xD0, 0x1F, 0xC0, 0x3F, 0x00, 0xFF, ++0x50, 0xF0, 0x83, 0xF0, 0x03, 0xC8, 0x8F, 0x00, 0x3F, 0x00, 0xBC, 0xC7, 0xF0, ++0x3D, 0xC0, 0x1E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, ++0x08, 0xA5, 0x00, 0x1F, 0x00, 0x0C, 0x03, 0xF0, 0x0D, 0xC4, 0x35, 0x00, 0x1F, ++0x02, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x7C, 0x03, 0xF0, ++0x05, 0xC0, 0x34, 0x10, 0x1F, 0x00, 0x4C, 0x22, 0x34, 0x2C, 0xC0, 0x28, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x64, 0x04, 0x9D, ++0x00, 0xC4, 0x3B, 0xD0, 0x0F, 0x40, 0x3C, 0x00, 0x9D, 0x00, 0xFC, 0x03, 0xD0, ++0x0D, 0x48, 0x3F, 0x00, 0xF1, 0x03, 0xF4, 0x2B, 0xD0, 0xA5, 0xC0, 0x26, 0x08, ++0x1D, 0x00, 0x44, 0x0F, 0x10, 0x3D, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xE2, 0x34, 0x0D, 0x40, 0x04, 0x07, 0x90, ++0x0C, 0x44, 0x30, 0x08, 0x8C, 0x00, 0x34, 0x03, 0x90, 0x0C, 0x48, 0x32, 0x00, ++0xC0, 0x01, 0x34, 0x27, 0xD0, 0x20, 0x40, 0x30, 0x04, 0x0D, 0x00, 0x04, 0x00, ++0x10, 0x04, 0x41, 0x0C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x0D, 0x02, 0x7A, 0x02, 0x6D, 0x01, 0x84, 0x07, 0xD0, 0x9E, 0x42, 0x78, 0x00, ++0xAD, 0x01, 0x94, 0x07, 0xD0, 0x1E, 0x40, 0x73, 0x02, 0xE5, 0x01, 0xB4, 0x07, ++0xD0, 0x17, 0x40, 0x5B, 0x04, 0x3D, 0x01, 0x84, 0x06, 0x12, 0x92, 0x41, 0x34, ++0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x32, 0x00, ++0x5F, 0x08, 0x0D, 0x03, 0xF0, 0x0C, 0xC0, 0x31, 0x02, 0x8F, 0x08, 0x34, 0x03, ++0xF0, 0x4C, 0xC0, 0x33, 0x0A, 0xC7, 0x10, 0x3C, 0x03, 0xF0, 0xA1, 0xE0, 0x30, ++0x00, 0x5F, 0x00, 0x0C, 0x80, 0x30, 0x50, 0xD0, 0x48, 0x40, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xBA, 0x3D, 0x20, 0xFF, 0x00, 0xFC, 0x03, ++0xF0, 0x0F, 0xC3, 0x3F, 0x00, 0xBF, 0x28, 0xFC, 0x23, 0xF0, 0x0F, 0xC4, 0x3F, ++0x02, 0xDB, 0x10, 0xFC, 0x23, 0xF0, 0x07, 0xE0, 0x3E, 0x80, 0x7F, 0x00, 0xFC, ++0x00, 0xF8, 0x81, 0xC2, 0x0B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xA0, 0x57, 0x00, 0xD3, 0x00, 0x7C, 0x6F, 0xB0, 0x5D, 0xE0, 0xB7, ++0x14, 0x1F, 0x00, 0x7C, 0x13, 0xF0, 0x0D, 0xC0, 0xB7, 0x03, 0xD3, 0x15, 0x4C, ++0x53, 0xF0, 0x05, 0xE0, 0x77, 0x00, 0x53, 0x00, 0x7C, 0x01, 0x30, 0x0D, 0xC0, ++0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x98, 0x1D, ++0x00, 0xEB, 0x00, 0xB4, 0x03, 0x18, 0xCF, 0x60, 0xB8, 0x01, 0xED, 0x00, 0xB4, ++0x4B, 0xD0, 0x0E, 0x40, 0x3B, 0x03, 0xC1, 0x04, 0x84, 0x1B, 0xD0, 0x06, 0x40, ++0x1B, 0x20, 0x61, 0x20, 0xF4, 0x03, 0x14, 0x0F, 0x40, 0x4C, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x79, 0x14, 0x61, 0x21, 0x36, ++0x07, 0x18, 0x5E, 0x4C, 0x79, 0x00, 0x6D, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x64, ++0x71, 0x01, 0xE1, 0x41, 0x96, 0x17, 0xD0, 0x16, 0x40, 0x7F, 0x00, 0x65, 0x01, ++0xB6, 0x07, 0x94, 0x1E, 0x42, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x20, 0x33, 0x00, 0xC9, 0x0B, 0x34, 0x83, 0x10, 0x0C, 0x40, ++0x30, 0x00, 0xCD, 0x07, 0x74, 0x03, 0xD0, 0x9C, 0x60, 0x33, 0x40, 0xC1, 0x00, ++0x15, 0x03, 0xD1, 0x1C, 0x42, 0x33, 0x00, 0xC4, 0x06, 0x34, 0x17, 0x90, 0x9C, ++0x40, 0x58, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, ++0x1F, 0x00, 0x73, 0x02, 0x7C, 0x01, 0xB0, 0x05, 0xC2, 0x17, 0x00, 0x7F, 0x10, ++0x7C, 0x01, 0xF0, 0x15, 0xC0, 0x13, 0x00, 0x51, 0x00, 0x5C, 0x01, 0xF0, 0x46, ++0xC0, 0x1F, 0x00, 0x77, 0x12, 0xFA, 0x1D, 0xB0, 0xB7, 0xC4, 0x5C, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x00, 0x1F, 0x04, ++0x7C, 0x00, 0xF4, 0x01, 0xC8, 0x07, 0x00, 0x1C, 0x00, 0x7C, 0x00, 0xF0, 0x01, ++0xC0, 0x07, 0x00, 0x1F, 0x00, 0x64, 0x00, 0xF0, 0x01, 0xC4, 0x07, 0x40, 0x1B, ++0x00, 0x7C, 0x08, 0x70, 0x01, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0xE5, 0x04, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x9F, 0xA0, 0x4C, 0x02, 0x32, 0x09, 0xC8, 0x27, 0x09, 0x93, ++0x00, 0x3C, 0x92, 0x30, 0x19, 0xC1, 0x26, 0x01, 0x9F, 0x00, 0x3C, 0x06, 0x30, ++0x89, 0xC0, 0x41, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x20, 0x26, 0x10, 0x9D, 0x80, 0x74, 0x32, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, ++0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x27, 0x09, 0x91, 0x23, 0x74, 0x4E, 0x14, ++0x99, 0x42, 0xA4, 0x04, 0x9D, 0x00, 0x74, 0x0A, 0x10, 0x29, 0x44, 0x04, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x34, 0x00, 0x9D, ++0x00, 0x54, 0x02, 0xC0, 0x09, 0x40, 0x27, 0x00, 0xCD, 0x00, 0x44, 0x02, 0x50, ++0x09, 0x42, 0x25, 0x40, 0x91, 0x18, 0x74, 0x02, 0x90, 0x29, 0x40, 0x26, 0x00, ++0x9D, 0x00, 0x74, 0x22, 0x08, 0x08, 0x40, 0x71, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x30, 0x05, 0x8D, 0x54, 0x34, 0x02, 0xD0, ++0x88, 0x40, 0x23, 0x02, 0x8D, 0x88, 0x05, 0x22, 0x10, 0x88, 0x40, 0x23, 0x00, ++0x81, 0x00, 0x30, 0x02, 0x10, 0x08, 0x42, 0x20, 0x00, 0x8D, 0x00, 0x36, 0x23, ++0x10, 0x08, 0x40, 0x50, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xB0, 0x06, 0x21, 0x1F, 0x24, 0x5C, 0xD0, 0xF0, 0x61, 0xC5, 0x87, 0x05, ++0x1F, 0x02, 0x4C, 0x58, 0x70, 0x21, 0xC0, 0x05, 0x05, 0x13, 0x34, 0x7C, 0x50, ++0x30, 0x01, 0xC0, 0x86, 0x02, 0x1F, 0x0A, 0x7C, 0x58, 0x34, 0x45, 0xC1, 0x75, ++0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, 0x2F, 0x05, ++0xBF, 0x34, 0x7C, 0x02, 0xF0, 0x49, 0xC0, 0x27, 0x01, 0xBF, 0x04, 0x7C, 0x12, ++0xF4, 0x4B, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x0B, 0xC0, 0x6B, ++0x00, 0xBF, 0x21, 0xFC, 0x12, 0xF0, 0x4B, 0xC1, 0x67, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, 0x00, 0x93, 0x02, 0xDC, 0x02, ++0xF0, 0x89, 0xC0, 0xA6, 0x15, 0x9B, 0x00, 0x5C, 0x42, 0x30, 0x09, 0xC0, 0x2E, ++0x04, 0xBF, 0x00, 0xDC, 0x02, 0xB2, 0x0B, 0xC0, 0x2F, 0x08, 0x9F, 0x00, 0xCC, ++0xC2, 0x32, 0x0B, 0xD0, 0x60, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1C, 0x18, 0x07, 0x01, 0x1B, 0x60, 0x74, 0xA8, 0xD0, 0xA0, 0x42, 0x84, ++0x00, 0x11, 0x20, 0x74, 0x08, 0x10, 0x41, 0x40, 0x84, 0x00, 0x17, 0x4A, 0x44, ++0x28, 0x10, 0x01, 0x44, 0x07, 0x20, 0x1D, 0x00, 0x44, 0x08, 0x14, 0x01, 0x40, ++0x70, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, 0xA1, ++0x84, 0x81, 0x02, 0x34, 0x02, 0xD0, 0x48, 0x40, 0x22, 0x01, 0x85, 0x14, 0x34, ++0x52, 0x12, 0x09, 0x61, 0x22, 0x00, 0x8D, 0x00, 0x14, 0x02, 0x10, 0x08, 0x40, ++0x33, 0x80, 0x8D, 0x00, 0x04, 0x02, 0x10, 0x08, 0x62, 0x4A, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x25, 0x00, 0x99, 0x80, 0x74, ++0x02, 0xC0, 0x08, 0x40, 0x26, 0x20, 0x95, 0x02, 0x34, 0x02, 0x10, 0x09, 0x4A, ++0x24, 0x00, 0x95, 0x00, 0x54, 0x02, 0x10, 0x0D, 0x40, 0xA7, 0x00, 0x8D, 0x14, ++0x45, 0x02, 0x10, 0x0D, 0x40, 0x62, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0xA8, 0x27, 0x01, 0x93, 0x87, 0x7C, 0x02, 0xF0, 0x09, 0xC8, ++0x26, 0x08, 0x97, 0x00, 0x5E, 0x02, 0x10, 0x08, 0xC0, 0x26, 0x20, 0x9F, 0x20, ++0x5C, 0x02, 0xB0, 0x59, 0xC0, 0x27, 0x20, 0x9E, 0x23, 0x4C, 0x42, 0x30, 0x49, ++0xC0, 0x16, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, ++0x61, 0x02, 0x9F, 0x05, 0x7C, 0x02, 0xD0, 0x09, 0xC0, 0x21, 0x40, 0x9B, 0x84, ++0x7C, 0x02, 0xF4, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x6C, 0x42, 0xD4, 0x39, ++0xC0, 0x27, 0x00, 0x9F, 0x21, 0x7C, 0x02, 0xF0, 0x48, 0xC0, 0x49, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x84, 0x04, 0x1F, 0x02, ++0x6C, 0x00, 0xE0, 0x01, 0xC0, 0x04, 0x00, 0x13, 0x80, 0x7C, 0x00, 0x30, 0x01, ++0xC0, 0x05, 0x04, 0x1F, 0x10, 0x4C, 0x00, 0x70, 0x11, 0xC2, 0x07, 0x01, 0x1F, ++0xA2, 0x3C, 0x20, 0x10, 0x41, 0xC2, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0xA0, 0xDC, 0x00, 0x5D, 0x20, 0xD4, 0x65, 0xC0, 0x05, ++0x40, 0x14, 0x00, 0x50, 0x00, 0x74, 0x81, 0x10, 0x05, 0xC0, 0x1C, 0x00, 0x6D, ++0x20, 0x80, 0x0D, 0x70, 0x07, 0x80, 0x1D, 0x10, 0x5D, 0x80, 0xF4, 0x01, 0x10, ++0x37, 0x42, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0xA0, 0xF2, 0x02, 0xCD, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x50, 0x30, 0x80, 0xC1, ++0x00, 0x34, 0x03, 0x10, 0x0C, 0x40, 0x31, 0x00, 0xCD, 0x0A, 0x00, 0x0B, 0xD8, ++0x8C, 0x48, 0xB2, 0x00, 0xCC, 0x00, 0x36, 0x93, 0x90, 0x00, 0x44, 0x53, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x38, 0x00, 0xCD, ++0x01, 0x94, 0x00, 0xD0, 0x0E, 0x40, 0x38, 0xC2, 0xE1, 0x04, 0xB4, 0x23, 0x11, ++0x0E, 0x40, 0x38, 0x80, 0x8D, 0x00, 0x85, 0x0B, 0xD8, 0x06, 0x40, 0x09, 0x20, ++0xED, 0x04, 0x34, 0x00, 0x94, 0x0A, 0x41, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x78, 0x00, 0xEF, 0x0D, 0x84, 0x04, 0xF0, ++0x1E, 0xC1, 0x70, 0x05, 0xE1, 0x0D, 0x34, 0x57, 0x34, 0x3F, 0xC0, 0x79, 0x00, ++0xAF, 0x01, 0x8C, 0x07, 0x70, 0x16, 0xC0, 0x6B, 0x00, 0xEF, 0x0B, 0xBC, 0x07, ++0xB0, 0x16, 0xC0, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xA2, 0x15, 0x10, 0xDF, 0x84, 0x5C, 0x00, 0xF0, 0x4D, 0xC0, 0x37, 0x00, ++0xDF, 0x04, 0x7C, 0x1B, 0xF0, 0x6D, 0xC9, 0x37, 0x20, 0x1B, 0x00, 0x7C, 0x00, ++0x78, 0x05, 0xC0, 0x07, 0x10, 0xDF, 0x00, 0x7C, 0x00, 0x74, 0x0D, 0xC0, 0x43, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x7D, 0x00, ++0xFF, 0x11, 0x8C, 0x24, 0x70, 0x1F, 0xC5, 0x7C, 0x00, 0xF3, 0x11, 0xFC, 0x07, ++0x30, 0x1F, 0xC0, 0x7F, 0x02, 0xB7, 0x05, 0xFC, 0x07, 0xF8, 0x96, 0xC0, 0x6C, ++0x02, 0xF3, 0x89, 0xCC, 0x07, 0x24, 0x1B, 0xC4, 0x00, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x08, 0x39, 0x20, 0xED, 0x04, 0x84, 0x00, ++0x18, 0x0E, 0x50, 0x38, 0x22, 0xE1, 0x00, 0xB4, 0x23, 0x10, 0x0E, 0x40, 0x3B, ++0x00, 0xA7, 0x00, 0xB4, 0x23, 0xD0, 0x06, 0x48, 0x0D, 0x02, 0xFB, 0x40, 0x85, ++0x00, 0xF0, 0x88, 0xE1, 0x54, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x39, 0x04, 0xED, 0x80, 0xA4, 0x00, 0x58, 0x0C, 0x40, 0x39, ++0x00, 0xE9, 0x00, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x1B, 0x00, 0xA5, 0x04, 0xB4, ++0x03, 0xD0, 0x03, 0x46, 0x08, 0x82, 0xE1, 0x00, 0x84, 0x03, 0x50, 0x0C, 0x40, ++0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0x61, ++0x00, 0xCD, 0x41, 0x04, 0x00, 0x10, 0x0C, 0x40, 0x34, 0x00, 0xD1, 0x42, 0x34, ++0x03, 0x12, 0x8C, 0x40, 0x13, 0x00, 0x05, 0x00, 0x34, 0x00, 0xD0, 0xB0, 0x44, ++0x01, 0x00, 0xC9, 0x02, 0x04, 0x41, 0xD0, 0x34, 0x50, 0x10, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x45, 0x20, 0xFF, 0x9A, 0x6C, ++0x00, 0x41, 0x0F, 0xC0, 0x3D, 0x00, 0xFB, 0x00, 0xFC, 0x03, 0x30, 0x1F, 0xC0, ++0x37, 0x00, 0x97, 0x00, 0x7C, 0x03, 0xF0, 0x01, 0x44, 0x00, 0x06, 0xF3, 0x42, ++0x4C, 0x4B, 0x30, 0x25, 0xC0, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x00, 0xA7, 0x01, 0xDF, 0x00, 0x7C, 0x08, 0xF0, 0x0D, 0xC0, ++0x37, 0x20, 0xDF, 0x08, 0x7C, 0x03, 0xF0, 0x0D, 0xC4, 0x37, 0x00, 0x9F, 0x80, ++0x3C, 0x8B, 0xF0, 0x01, 0xC8, 0x87, 0x00, 0xDF, 0x00, 0x3C, 0x00, 0x96, 0x65, ++0xC0, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, ++0x0F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x3C, 0x00, 0xF3, 0x10, ++0x5C, 0x03, 0xE0, 0x0F, 0xC0, 0x2F, 0x02, 0xBF, 0x00, 0xFC, 0x83, 0x30, 0x03, ++0xC1, 0x0D, 0x20, 0xF3, 0x10, 0x7C, 0x07, 0x30, 0x97, 0xC2, 0x13, 0x22, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x20, 0xC6, 0x04, 0xDD, 0x00, ++0x74, 0x0C, 0xD0, 0x0D, 0x50, 0x34, 0x20, 0xD1, 0x00, 0x44, 0x03, 0xD0, 0x0D, ++0x40, 0x27, 0x00, 0x19, 0x01, 0x74, 0x18, 0x00, 0x31, 0xC0, 0x47, 0x01, 0xD1, ++0x00, 0x74, 0x20, 0x10, 0x29, 0x40, 0x17, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0xA0, 0x44, 0x00, 0xDD, 0x00, 0x74, 0x44, 0xD0, 0x0C, ++0x40, 0x34, 0x00, 0xD1, 0x00, 0x44, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0x80, 0x1D, ++0x03, 0x74, 0x10, 0x10, 0x11, 0x40, 0x4F, 0x00, 0xF1, 0x00, 0x74, 0x43, 0x19, ++0x09, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x28, 0x20, 0x20, 0xCD, 0x80, 0x24, 0x00, 0xD2, 0x0C, 0x40, 0x30, 0x20, 0xC1, ++0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x33, 0x80, 0x09, 0x00, 0x34, 0x00, 0x10, ++0x00, 0x44, 0x07, 0x40, 0xC1, 0x00, 0x34, 0x02, 0x13, 0x84, 0x40, 0x43, 0xA0, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x06, 0x00, 0xEF, ++0x80, 0x7C, 0x80, 0xF0, 0x0F, 0xC0, 0x38, 0x00, 0xF3, 0x00, 0xC5, 0x03, 0xF0, ++0x0F, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x05, 0x00, ++0xF3, 0x00, 0x7C, 0x00, 0x30, 0x09, 0xC8, 0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x85, 0xA8, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, ++0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xEC, 0x83, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, ++0x3B, 0x40, 0xFC, 0x00, 0xF0, 0x03, 0xE8, 0x0D, 0x00, 0xFF, 0x00, 0xFC, 0x00, ++0xF0, 0x43, 0xC0, 0x17, 0x21, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA8, 0x3F, 0x04, 0xB3, 0x08, 0xCC, 0x93, 0xF1, 0xCF, 0xC0, 0x3C, 0x42, ++0xF3, 0x00, 0xFC, 0x03, 0x30, 0x13, 0xC0, 0x3D, 0x05, 0xF7, 0x2C, 0xFC, 0x04, ++0xB0, 0x0F, 0xC0, 0x3E, 0x06, 0x3F, 0x04, 0xEC, 0x03, 0xF0, 0x83, 0xC0, 0x0F, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0xBF, 0x00, ++0x1B, 0x04, 0xC4, 0xAF, 0xD0, 0x6F, 0x40, 0xBC, 0x03, 0xF1, 0x84, 0xF4, 0x0F, ++0x10, 0x09, 0xC4, 0x7D, 0x08, 0xD5, 0x08, 0x74, 0x00, 0x50, 0x2F, 0x42, 0x3C, ++0x10, 0x1D, 0x12, 0xC4, 0x87, 0xD0, 0x40, 0x40, 0x07, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x04, 0x81, 0x22, 0x04, 0x03, ++0xD0, 0x2C, 0x44, 0x31, 0x01, 0xC1, 0x18, 0x24, 0x0B, 0x50, 0x04, 0x40, 0x31, ++0x00, 0xC5, 0x00, 0x74, 0x02, 0x10, 0x2C, 0x44, 0x33, 0x01, 0x8D, 0x06, 0x24, ++0x03, 0xD0, 0x00, 0x40, 0x47, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xA0, 0x34, 0x30, 0x09, 0x41, 0x46, 0x03, 0xD0, 0x0D, 0x40, 0x35, ++0x00, 0xD1, 0x00, 0x74, 0x03, 0x14, 0x0D, 0x40, 0x35, 0x00, 0xD4, 0x00, 0x74, ++0x22, 0x50, 0x0D, 0x40, 0x35, 0x00, 0xDD, 0x00, 0xC4, 0x03, 0xD0, 0x33, 0x40, ++0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x37, ++0x00, 0x93, 0x03, 0x4C, 0x83, 0xF0, 0x0D, 0xC0, 0x35, 0x20, 0xD3, 0x80, 0x7C, ++0x03, 0x72, 0x91, 0xC8, 0x35, 0x00, 0xD7, 0x80, 0x7C, 0x45, 0xB0, 0x0D, 0xC0, ++0x37, 0x18, 0x1F, 0xA2, 0x6C, 0x03, 0xF0, 0x11, 0xC0, 0x03, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xBF, 0x40, 0xFD, ++0x03, 0xF0, 0x0D, 0xC2, 0x36, 0x00, 0xFF, 0x00, 0xBC, 0x03, 0xF0, 0x03, 0xC1, ++0x3F, 0x00, 0xD9, 0x00, 0xFC, 0x41, 0xF0, 0x0D, 0xC0, 0x3E, 0x08, 0xFC, 0x09, ++0xFC, 0x03, 0xF0, 0x03, 0x80, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x08, 0x31, 0x01, 0x9F, 0x02, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, ++0x31, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0xF0, 0x01, 0xC0, 0x35, 0x00, 0xD7, 0x00, ++0x4C, 0x22, 0xB0, 0x0C, 0xC8, 0x34, 0x08, 0x07, 0x00, 0x5C, 0x03, 0x30, 0x21, ++0xC0, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0xFC, 0x0C, 0x9D, 0x00, 0xFC, 0x0F, 0xD0, 0x0F, 0x44, 0x3C, 0x00, 0xF1, 0x00, ++0xF4, 0x07, 0xD0, 0x15, 0xC2, 0x39, 0x08, 0xF0, 0x03, 0x2C, 0x8B, 0xD0, 0x0F, ++0x48, 0x3C, 0x00, 0xD5, 0x10, 0xC4, 0x2F, 0x10, 0x09, 0x40, 0x4C, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x32, 0x00, 0x0D, 0x00, ++0x34, 0x43, 0xD0, 0x0D, 0x40, 0x31, 0x00, 0xC1, 0x00, 0x34, 0x1B, 0xD2, 0x14, ++0x48, 0x32, 0x00, 0xC8, 0x87, 0x04, 0x0D, 0xD0, 0x0C, 0x00, 0x31, 0x00, 0x41, ++0x10, 0x14, 0x23, 0x10, 0x00, 0x40, 0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x88, 0x78, 0x00, 0x6D, 0x01, 0xB4, 0x67, 0xD0, 0x9E, ++0x40, 0x78, 0x00, 0xE1, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x40, 0x73, 0x48, 0xED, ++0x01, 0xA4, 0x05, 0xD1, 0x1E, 0x40, 0x71, 0x00, 0xE5, 0x01, 0xC4, 0x17, 0x14, ++0x92, 0x40, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x10, 0x30, 0x02, 0xCF, 0x0C, 0x34, 0x03, 0xF0, 0x0C, 0x48, 0x31, 0x00, 0xC3, ++0x00, 0x3C, 0x43, 0xF0, 0x04, 0xC1, 0x32, 0x00, 0xCF, 0x10, 0x0C, 0x00, 0xB0, ++0x8C, 0xD0, 0x31, 0xA0, 0x17, 0x22, 0x5C, 0x17, 0x30, 0x50, 0xD0, 0x48, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x3D, 0x0C, 0xFF, ++0x88, 0xDC, 0x83, 0xF0, 0x2F, 0x00, 0x3F, 0x00, 0xDF, 0x00, 0xF4, 0x03, 0xF0, ++0x0F, 0xC0, 0x3D, 0x30, 0xF3, 0x08, 0x7C, 0x01, 0xF0, 0x0F, 0xC0, 0x3E, 0xA0, ++0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x89, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x24, 0x5F, 0x40, 0x7C, 0x6F, 0x30, ++0xBD, 0xC0, 0xF4, 0x05, 0xD3, 0x68, 0x1C, 0x63, 0x70, 0x01, 0xD0, 0x36, 0x01, ++0xDF, 0x49, 0x4C, 0x05, 0x30, 0x4D, 0xC9, 0x37, 0x03, 0x1F, 0x00, 0x4D, 0x63, ++0xF0, 0x11, 0x84, 0x54, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x88, 0x39, 0x01, 0x6D, 0x60, 0x36, 0x13, 0x10, 0x4E, 0x40, 0xB8, 0x01, ++0xE1, 0x0C, 0x84, 0x03, 0x10, 0x07, 0xC0, 0xB8, 0x04, 0xED, 0x84, 0xAC, 0x01, ++0x10, 0x4E, 0x48, 0x3B, 0x04, 0xCD, 0x00, 0x84, 0x03, 0xD0, 0x02, 0x40, 0x48, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x01, ++0xED, 0x03, 0x94, 0x07, 0x18, 0x1E, 0x50, 0x7A, 0x00, 0xC5, 0x01, 0x94, 0x17, ++0x50, 0x12, 0x41, 0x78, 0x00, 0xCD, 0x01, 0xC4, 0x04, 0x92, 0x9E, 0x42, 0x7B, ++0x01, 0x2D, 0x21, 0x84, 0x07, 0xD0, 0x10, 0x40, 0x0D, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, ++0x15, 0x0C, 0x60, 0x30, 0x00, 0xC1, 0x00, 0x24, 0x03, 0x10, 0x14, 0x41, 0x30, ++0x00, 0xCD, 0x40, 0x24, 0x21, 0x90, 0x0C, 0x40, 0x33, 0x00, 0xCD, 0x04, 0x04, ++0x03, 0xD0, 0x8C, 0x40, 0x49, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x17, 0xA8, 0x15, 0x00, 0x7F, 0x0A, 0x7C, 0x81, 0x38, 0x05, 0xC0, 0x16, ++0x00, 0x53, 0x00, 0x5C, 0x01, 0x70, 0x27, 0xC0, 0x14, 0x00, 0x5F, 0x00, 0xCC, ++0x85, 0xB0, 0x05, 0xC0, 0x17, 0x10, 0x7F, 0x04, 0x4C, 0x01, 0xF0, 0x17, 0xC0, ++0x5D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x07, ++0x08, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x40, 0x1F, 0x00, 0x1C, ++0x00, 0xF0, 0x01, 0xC4, 0x05, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0x74, 0x01, 0xC2, ++0x07, 0x00, 0x1F, 0x02, 0x7C, 0x00, 0xF2, 0x41, 0x80, 0x4A, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x65, 0x00, 0x9F, 0x40, 0x7C, ++0x06, 0x70, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x08, 0x4C, 0x16, 0x30, 0x39, 0xC0, ++0x24, 0x00, 0x9D, 0x00, 0x74, 0x12, 0xF0, 0x09, 0xC0, 0x23, 0x00, 0x97, 0x08, ++0x5C, 0x06, 0x30, 0x09, 0xC0, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x20, 0x66, 0x0E, 0x9D, 0x20, 0x74, 0x0A, 0xD2, 0x09, 0x40, ++0x27, 0x00, 0x9D, 0x03, 0x44, 0x0E, 0x15, 0x08, 0x40, 0x64, 0x20, 0x9D, 0x1B, ++0x70, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x91, 0x11, 0x04, 0xAE, 0x10, 0x09, ++0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, ++0x24, 0x00, 0xDD, 0x00, 0x74, 0x62, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x8D, 0x02, ++0x44, 0x42, 0x11, 0x09, 0x40, 0x27, 0x09, 0x9D, 0x00, 0x70, 0x42, 0xD2, 0x09, ++0x40, 0x27, 0x00, 0x81, 0x00, 0x54, 0x0A, 0x10, 0x09, 0x40, 0x63, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x20, 0x05, 0x8D, 0x14, ++0x34, 0x02, 0xD0, 0x88, 0x40, 0x23, 0x22, 0x8D, 0x48, 0x04, 0x02, 0x11, 0x09, ++0x40, 0x21, 0x10, 0x8D, 0x08, 0x34, 0x02, 0xD8, 0x08, 0x40, 0x23, 0x40, 0x81, ++0x08, 0x04, 0x92, 0x10, 0x48, 0x48, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x01, 0x1F, 0x04, 0x7C, 0x50, 0x70, 0x60, ++0xC1, 0x83, 0x05, 0x1F, 0x96, 0x4C, 0x50, 0x30, 0xA1, 0xD0, 0x05, 0x05, 0x1F, ++0x16, 0x7C, 0x28, 0xE0, 0xE1, 0xC9, 0x07, 0x15, 0x17, 0x16, 0x5C, 0x04, 0x30, ++0x11, 0xC0, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, ++0xA8, 0x27, 0x25, 0xBF, 0x34, 0x7E, 0x02, 0xF0, 0x49, 0xC0, 0x27, 0x01, 0x9F, ++0x04, 0x7D, 0x02, 0xF0, 0x1B, 0xC0, 0x26, 0x20, 0x9F, 0x04, 0xBC, 0x07, 0xF0, ++0x19, 0xC0, 0x27, 0x05, 0xBF, 0x04, 0x7C, 0x22, 0xF4, 0xCB, 0xC1, 0x67, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, 0x2F, 0x03, 0x93, ++0x03, 0xCC, 0x12, 0x70, 0x29, 0xC0, 0xA5, 0x00, 0xBF, 0x00, 0xCC, 0x42, 0x30, ++0x0B, 0xC0, 0x2E, 0x00, 0xB3, 0x00, 0xCC, 0x02, 0xB0, 0x09, 0xC0, 0x24, 0x0B, ++0xB3, 0x40, 0xCC, 0x02, 0x30, 0x09, 0xC0, 0x67, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x47, 0x01, 0x1B, 0x43, 0x68, 0x28, 0x10, ++0x01, 0x40, 0x84, 0x02, 0x1D, 0x0E, 0x45, 0x08, 0x10, 0x01, 0x40, 0x85, 0x02, ++0x11, 0x20, 0x44, 0x00, 0x13, 0x21, 0xC0, 0x46, 0x01, 0x1B, 0x00, 0x44, 0x00, ++0x10, 0x01, 0x44, 0x73, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xA2, 0xA3, 0x10, 0x81, 0x06, 0x04, 0x02, 0x50, 0x68, 0x40, 0x21, 0x81, ++0x8D, 0x90, 0x06, 0x02, 0x10, 0x09, 0x40, 0x21, 0x40, 0x81, 0x16, 0x44, 0x02, ++0x90, 0x28, 0x40, 0xA0, 0x01, 0x81, 0x40, 0x05, 0x02, 0x90, 0x08, 0x40, 0x43, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x20, ++0x99, 0x02, 0x66, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x8D, 0x20, 0x46, 0x02, ++0x04, 0x09, 0x40, 0x25, 0x00, 0xC1, 0x00, 0x44, 0x03, 0x18, 0x09, 0x40, 0x27, ++0x20, 0x89, 0x00, 0x44, 0x02, 0x84, 0x69, 0x40, 0x63, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, 0x25, 0x20, 0x93, 0x21, 0x4C, 0x02, ++0x70, 0x09, 0xC0, 0x25, 0x00, 0x9F, 0x80, 0x4C, 0x02, 0x32, 0x09, 0xC8, 0x27, ++0x00, 0x93, 0x00, 0x4C, 0x02, 0xB1, 0x09, 0xC4, 0x24, 0x10, 0x93, 0x13, 0x4C, ++0x02, 0xB0, 0x09, 0xC0, 0x17, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x00, 0x21, 0x00, 0x8F, 0x04, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x00, 0x3C, 0x02, 0xF0, 0x89, 0xC0, 0x23, 0x00, 0x9F, 0x00, 0x7D, ++0x26, 0xF1, 0x09, 0xC4, 0x26, 0xA8, 0x9F, 0x03, 0x3C, 0x82, 0x70, 0x09, 0xC0, ++0x53, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, ++0x04, 0x1F, 0x40, 0x4C, 0x10, 0xF0, 0x00, 0xC0, 0x07, 0x80, 0x13, 0x10, 0x5C, ++0x84, 0x70, 0x01, 0xC0, 0x06, 0x00, 0x1F, 0x20, 0x4C, 0x08, 0x30, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x26, 0x4C, 0x00, 0x30, 0x21, 0xC0, 0x53, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x5C, 0x04, 0x5D, 0x00, 0x84, ++0x01, 0xD0, 0x05, 0x44, 0x17, 0x40, 0x71, 0x83, 0xF4, 0x01, 0xD0, 0x07, 0x40, ++0x14, 0x00, 0x7D, 0x00, 0x84, 0xC5, 0x34, 0x05, 0x40, 0x17, 0x00, 0x7D, 0x01, ++0xC4, 0x1D, 0x50, 0x05, 0x40, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0xA0, 0xB2, 0x20, 0xCD, 0x20, 0x24, 0x2B, 0xD1, 0x0C, 0x40, ++0x33, 0x00, 0xC9, 0x08, 0x14, 0x07, 0x52, 0x0D, 0x21, 0x72, 0x80, 0xCD, 0x01, ++0x04, 0x07, 0x10, 0x0D, 0x40, 0x37, 0x00, 0xCD, 0x00, 0x07, 0x4F, 0x50, 0x0C, ++0x46, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x82, ++0x38, 0x00, 0xCD, 0x04, 0xA4, 0x01, 0xD0, 0x4E, 0x40, 0x7B, 0x02, 0xE9, 0x00, ++0xB4, 0x0A, 0xD0, 0x27, 0x48, 0x38, 0x04, 0xED, 0x02, 0x84, 0x03, 0x10, 0x0E, ++0x40, 0x3B, 0x00, 0xED, 0x82, 0xC4, 0x03, 0x50, 0x0E, 0x40, 0x17, 0x08, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x78, 0x00, 0xEF, 0x05, ++0xAD, 0x07, 0xF0, 0x5E, 0xC0, 0x7F, 0x01, 0x69, 0x41, 0x9C, 0x05, 0x70, 0x1E, ++0xE0, 0x7A, 0x00, 0xFE, 0x01, 0xCD, 0x84, 0x30, 0x1E, 0xC0, 0x7B, 0x00, 0xFF, ++0x01, 0xCC, 0x07, 0x70, 0x9E, 0xC2, 0x57, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, 0x00, 0xDF, 0x42, 0x5C, 0x00, 0xF0, 0xAD, ++0xC0, 0x37, 0x00, 0x57, 0x00, 0x7C, 0x02, 0xF0, 0x04, 0xC0, 0x35, 0x00, 0x1F, ++0x00, 0x7C, 0x00, 0xF0, 0x0D, 0xC1, 0x37, 0x02, 0xDF, 0x00, 0x7C, 0x03, 0xF0, ++0x4D, 0xC0, 0x43, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xA0, 0x5F, 0x00, 0xF3, 0x53, 0xFC, 0x26, 0x30, 0x3F, 0xC0, 0xFF, 0x00, 0xFF, ++0x01, 0xCC, 0x07, 0xF0, 0x1B, 0xC0, 0x7F, 0x22, 0xBF, 0x01, 0xCC, 0x07, 0xF0, ++0x1F, 0xC1, 0x7C, 0x00, 0xF3, 0x01, 0xEC, 0x07, 0x30, 0x1F, 0xC1, 0x08, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0xBD, 0x00, 0xE1, ++0x00, 0xB4, 0x0A, 0x10, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x22, 0x80, 0x02, 0xD0, ++0x02, 0x40, 0x3B, 0x00, 0xAD, 0x08, 0x84, 0x23, 0xD2, 0x0E, 0x60, 0x3D, 0x00, ++0xEB, 0x00, 0x04, 0x15, 0x10, 0xDD, 0x40, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x19, 0x00, 0xE1, 0x00, 0xB4, 0x02, 0x94, ++0x0E, 0x40, 0x3B, 0x00, 0x8D, 0x00, 0x84, 0x00, 0xD0, 0x0E, 0x40, 0x3B, 0x80, ++0xED, 0x00, 0x84, 0x41, 0xD0, 0x0E, 0x40, 0x38, 0x00, 0xE1, 0x08, 0x24, 0x12, ++0x10, 0x4E, 0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x06, 0x28, 0x07, 0x10, 0xD1, 0x11, 0x36, 0x02, 0x98, 0x0C, 0x40, 0x33, 0x88, ++0x9D, 0x40, 0x04, 0x02, 0xD1, 0x30, 0x40, 0x33, 0x08, 0x1D, 0x00, 0x04, 0x00, ++0xD0, 0x0C, 0x40, 0x31, 0x00, 0x09, 0x05, 0x04, 0x80, 0x18, 0x3C, 0x50, 0x58, ++0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x24, 0x00, ++0xF3, 0x13, 0x7C, 0x02, 0xB0, 0x0F, 0xC0, 0x3F, 0x00, 0x9F, 0x40, 0x4E, 0x02, ++0xF0, 0x29, 0xC1, 0x37, 0x00, 0x5F, 0x00, 0x4C, 0x02, 0xD1, 0x0F, 0x40, 0x3C, ++0x00, 0x13, 0x13, 0x2C, 0x03, 0x30, 0x0F, 0xC1, 0x74, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0xA7, 0x00, 0xDF, 0x80, 0x7C, 0x00, ++0x70, 0x0D, 0xC0, 0x37, 0x00, 0x9F, 0x42, 0x3F, 0x02, 0xF0, 0x01, 0xC0, 0x37, ++0x00, 0x5F, 0x82, 0x7C, 0x00, 0xF0, 0x0D, 0xC8, 0x37, 0x10, 0x1F, 0xA2, 0x7C, ++0x02, 0xF5, 0x4D, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x81, 0x09, 0x2F, 0x10, 0xF3, 0x00, 0x44, 0x00, 0xF0, 0x0F, 0xC0, 0x3F, ++0x00, 0x3F, 0x08, 0xCD, 0x00, 0x30, 0x0B, 0xC1, 0x7F, 0x00, 0xFF, 0x00, 0xCC, ++0x00, 0xF0, 0x0F, 0xC0, 0x3B, 0x00, 0x03, 0x02, 0xCC, 0x25, 0x32, 0x0F, 0xC0, ++0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x66, ++0x00, 0xD5, 0x00, 0x44, 0x0C, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0x1D, 0x02, 0x44, ++0x06, 0x50, 0x31, 0x41, 0x37, 0x00, 0x1D, 0x02, 0x44, 0x0C, 0xD0, 0x0D, 0x40, ++0x37, 0x00, 0x11, 0x02, 0x44, 0x44, 0x50, 0x0D, 0x40, 0x07, 0x02, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x46, 0x00, 0xD1, 0x00, 0x54, ++0x06, 0xD8, 0x0D, 0x40, 0x37, 0x00, 0x5D, 0x00, 0x44, 0x44, 0x10, 0x13, 0x40, ++0x37, 0x12, 0x1D, 0x00, 0xE4, 0x06, 0xD0, 0x0F, 0x40, 0x37, 0x00, 0x11, 0x50, ++0x44, 0x83, 0x50, 0x0D, 0x48, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0xC5, 0x00, 0x14, 0x02, 0xD8, 0x0C, 0x40, ++0x33, 0x08, 0x4C, 0x00, 0x05, 0x00, 0x50, 0x00, 0x40, 0x33, 0x00, 0x0D, 0x00, ++0x04, 0x00, 0xD0, 0x0C, 0x48, 0x33, 0x00, 0xC1, 0x00, 0x04, 0x10, 0x51, 0x4C, ++0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90, ++0x06, 0x00, 0xF3, 0x40, 0x5C, 0x00, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0x1F, 0x00, ++0x4C, 0x00, 0x32, 0x01, 0xC0, 0x27, 0x00, 0xCF, 0x00, 0x4C, 0x00, 0xF0, 0x0E, ++0xC4, 0x37, 0x00, 0x13, 0x00, 0x4D, 0x60, 0x30, 0xAF, 0xC0, 0x07, 0xC0, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x2F, 0x20, 0xFF, 0x00, ++0xEC, 0x00, 0xF1, 0x0F, 0xC0, 0x3F, 0x00, 0x3F, 0x40, 0xFC, 0x00, 0xF0, 0x03, ++0xC2, 0x2F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xE0, 0x3F, 0x00, 0x3F, ++0x40, 0x7C, 0x10, 0xE0, 0x6D, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA8, 0x3F, 0x0B, 0xFF, 0x2C, 0xFC, 0x0A, 0xD0, 0x8F, ++0xC0, 0x4C, 0x00, 0x3F, 0x49, 0xEC, 0x93, 0x30, 0x4F, 0xC0, 0x0F, 0x10, 0x33, ++0x00, 0xFC, 0x24, 0xB0, 0x4F, 0xC0, 0x6C, 0x00, 0xF3, 0x00, 0x8C, 0x03, 0xB1, ++0x03, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x10, 0xBF, 0x01, 0xFD, 0x08, 0x74, 0x8A, 0xD0, 0x6F, 0x44, 0x64, 0x00, 0x19, ++0x00, 0xF4, 0x0F, 0x51, 0xAF, 0x40, 0x27, 0x12, 0x11, 0x41, 0x74, 0x12, 0x10, ++0x9F, 0x40, 0x74, 0x00, 0xF1, 0x42, 0x44, 0x87, 0x10, 0x11, 0x40, 0x0F, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA8, 0xB3, 0x01, 0xCD, ++0x00, 0x36, 0x1A, 0xD0, 0x2C, 0x50, 0x20, 0x00, 0x8D, 0x44, 0x24, 0x0B, 0x11, ++0x0C, 0x40, 0x01, 0x00, 0x05, 0x80, 0x74, 0x90, 0x90, 0x0C, 0x40, 0x35, 0x00, ++0xC1, 0x02, 0x04, 0x07, 0x90, 0x00, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x35, 0x00, 0xDD, 0x00, 0x74, 0x06, 0xD0, ++0x0D, 0x40, 0xE4, 0x00, 0x19, 0x01, 0x74, 0x03, 0x50, 0x0D, 0x60, 0x07, 0x00, ++0x31, 0x01, 0x74, 0x0E, 0x10, 0x0D, 0x00, 0x74, 0x00, 0xD1, 0x00, 0x44, 0x87, ++0x00, 0x11, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA8, 0x37, 0x00, 0xDF, 0x80, 0x7C, 0x8C, 0xF0, 0x0D, 0xC0, 0xC4, 0x30, ++0x9F, 0x01, 0x6C, 0x03, 0x34, 0x0D, 0xC0, 0x07, 0x00, 0x12, 0x05, 0x3C, 0x0E, ++0xB1, 0x0C, 0xC0, 0x60, 0x00, 0xD3, 0x00, 0x4C, 0x80, 0xB0, 0x19, 0xC0, 0x23, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, ++0xFF, 0x00, 0xFC, 0x02, 0xF2, 0x0E, 0x40, 0x2F, 0x08, 0x3D, 0x40, 0xFC, 0x03, ++0xB0, 0x0F, 0xC0, 0x6B, 0xD1, 0xBF, 0x40, 0xFC, 0x02, 0xF1, 0x0F, 0xC0, 0x2F, ++0x00, 0xEF, 0x10, 0xFD, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0x35, 0x08, 0xDF, 0x05, 0x7C, 0x10, ++0x70, 0x0D, 0xC6, 0x25, 0x00, 0x9F, 0xC0, 0x3C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, ++0x09, 0x1F, 0x10, 0x7C, 0x02, 0xF0, 0x4D, 0xC0, 0x06, 0x01, 0xD7, 0x00, 0x0C, ++0x01, 0x30, 0x09, 0xC0, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x3C, 0x20, 0xFD, 0x42, 0x74, 0x0E, 0xD0, 0x0F, 0x50, 0x64, ++0x00, 0x1D, 0x80, 0xF0, 0x13, 0xD0, 0xAF, 0x40, 0xB7, 0x01, 0x9D, 0x23, 0x74, ++0x02, 0xD0, 0x3F, 0x40, 0xA7, 0x80, 0xF1, 0x01, 0x54, 0x01, 0x14, 0x09, 0x41, ++0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x30, ++0x00, 0xCD, 0x02, 0x34, 0x2C, 0x50, 0x0C, 0x48, 0x00, 0x02, 0x09, 0x40, 0x30, ++0x03, 0xD0, 0x1C, 0x40, 0x13, 0x00, 0x0D, 0x0B, 0x34, 0x00, 0x90, 0x3C, 0x4C, ++0xA2, 0x08, 0xCD, 0x41, 0x04, 0x03, 0x51, 0x08, 0x40, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x78, 0x00, 0xED, 0x01, 0xB4, ++0x05, 0xD1, 0x1C, 0x40, 0xC8, 0x00, 0x2D, 0x01, 0xB6, 0x0F, 0xD0, 0x1E, 0x41, ++0x7B, 0x02, 0x2D, 0x01, 0xB4, 0x04, 0xD0, 0x1E, 0x40, 0x7F, 0x00, 0xE1, 0x41, ++0xD4, 0x2F, 0x50, 0x16, 0x60, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x02, 0x30, 0x08, 0xCF, 0x00, 0x3C, 0x03, 0x70, 0x8C, 0xC0, ++0x01, 0x00, 0x8F, 0x8A, 0x3E, 0x23, 0xF0, 0x0C, 0xC0, 0x13, 0x00, 0x4F, 0x00, ++0x3C, 0x80, 0xF1, 0x0C, 0xC1, 0x32, 0x00, 0xD7, 0x10, 0x0C, 0x23, 0x70, 0x4C, ++0xC0, 0x4B, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, ++0x3D, 0x24, 0xFF, 0x00, 0xF8, 0x03, 0xF0, 0x0F, 0x80, 0x1F, 0x00, 0xFF, 0x28, ++0xFC, 0x63, 0xF0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7C, 0x03, 0xF0, 0x0F, ++0xE9, 0x3B, 0x00, 0xFF, 0x00, 0xFC, 0x23, 0xB4, 0x0D, 0xE0, 0x0B, 0x60, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0xF7, 0x04, 0xD7, 0x02, ++0x7C, 0x05, 0x30, 0xCD, 0xC0, 0x07, 0x00, 0x9B, 0x00, 0x7C, 0x13, 0xF1, 0xCD, ++0xD0, 0x04, 0x40, 0xD3, 0x01, 0x4D, 0x00, 0xF0, 0x6D, 0xC0, 0x27, 0x80, 0xD7, ++0x02, 0x7C, 0x03, 0x34, 0x18, 0xC4, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0x80, 0x30, 0x00, 0xE1, 0x56, 0xB4, 0x03, 0xB0, 0x8E, ++0x44, 0x2B, 0x00, 0xED, 0x00, 0xB4, 0x33, 0xD0, 0x0F, 0x41, 0x2C, 0x00, 0xE1, ++0x00, 0x84, 0x01, 0xD0, 0x4E, 0x41, 0x3B, 0x80, 0xED, 0x0E, 0xB4, 0x03, 0xB0, ++0x06, 0x40, 0x4C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x00, 0x78, 0x01, 0xED, 0x01, 0x36, 0x05, 0x10, 0x5E, 0x40, 0x7B, 0x18, 0xAD, ++0x01, 0xA4, 0x17, 0xD0, 0x5E, 0x40, 0x7A, 0x00, 0xC1, 0x01, 0xA4, 0x06, 0xD0, ++0x1E, 0x40, 0x5B, 0x04, 0xED, 0x25, 0xB4, 0x07, 0x10, 0x1E, 0x40, 0x10, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x33, 0x00, 0xC9, ++0x00, 0x34, 0x43, 0x98, 0x0C, 0x40, 0x33, 0x22, 0xCD, 0x0A, 0x34, 0x03, 0xD0, ++0x0C, 0x40, 0xB2, 0x03, 0xC1, 0x0A, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x73, 0x01, ++0xCD, 0x00, 0x34, 0x03, 0x90, 0x6C, 0x40, 0x58, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x17, 0x28, 0x17, 0x10, 0x5F, 0x00, 0xFC, 0x81, 0x30, ++0x05, 0xE0, 0x5B, 0x00, 0x7B, 0x61, 0x3C, 0x01, 0xF2, 0x05, 0xC0, 0xDE, 0x00, ++0x73, 0x01, 0xEC, 0x05, 0xF0, 0x05, 0xCA, 0x1B, 0x00, 0x5F, 0x00, 0xFC, 0x01, ++0x30, 0x07, 0xD4, 0x5C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x00, 0x05, 0x08, 0x17, 0x00, 0x78, 0x20, 0xF0, 0x01, 0xC6, 0x47, 0x08, ++0x1F, 0x10, 0x7C, 0x00, 0xF0, 0x20, 0xC8, 0x01, 0x00, 0x1F, 0x04, 0x5C, 0x24, ++0xF0, 0x01, 0xC0, 0x07, 0x20, 0x1F, 0x00, 0x7C, 0x04, 0xF1, 0x21, 0xC0, 0x4B, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, ++0x8F, 0x01, 0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x02, 0x9B, 0x20, 0x4C, 0x82, ++0xB0, 0x19, 0x80, 0x24, 0x00, 0x91, 0x01, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0xE5, ++0x00, 0x93, 0x00, 0x7C, 0x02, 0x32, 0x09, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x03, 0x45, 0x8E, ++0xD0, 0x09, 0x40, 0xE7, 0x10, 0x80, 0x00, 0x44, 0x06, 0x10, 0x49, 0x50, 0x24, ++0x02, 0x91, 0x02, 0x74, 0x02, 0x10, 0x09, 0x40, 0xA7, 0x00, 0x91, 0x0B, 0x34, ++0x02, 0x14, 0x29, 0x44, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x18, 0x54, 0x2B, 0xD0, 0x09, 0x40, 0x27, ++0x00, 0x98, 0x20, 0x44, 0x52, 0x92, 0x49, 0x48, 0x25, 0x08, 0x95, 0x38, 0x34, ++0x02, 0x00, 0x09, 0x42, 0x27, 0x40, 0x91, 0x00, 0x74, 0x06, 0x1C, 0x2D, 0x40, ++0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, ++0x00, 0x89, 0x14, 0x14, 0x52, 0xD1, 0x88, 0x40, 0x23, 0x08, 0x91, 0x48, 0x00, ++0x02, 0x00, 0x08, 0x60, 0x21, 0x00, 0x85, 0x04, 0x36, 0x22, 0x14, 0x08, 0x40, ++0x23, 0x00, 0xC1, 0x14, 0x34, 0x56, 0x10, 0x48, 0x41, 0x43, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x06, 0x05, 0x1F, 0x04, 0x5C, ++0x10, 0xF0, 0x61, 0xC1, 0x17, 0x00, 0x1A, 0x02, 0x4C, 0x50, 0xB0, 0xE1, 0xC1, ++0x85, 0x47, 0x17, 0x01, 0x7C, 0x08, 0x20, 0x41, 0xC1, 0x15, 0x00, 0x13, 0x0E, ++0x7C, 0x10, 0x30, 0x41, 0xC0, 0x77, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xB8, 0x27, 0x05, 0x9F, 0x14, 0xEC, 0x52, 0xF0, 0x49, 0xC2, ++0x2F, 0x10, 0xBF, 0x44, 0x7D, 0x02, 0xF0, 0x19, 0xC2, 0x6E, 0x00, 0xBB, 0x08, ++0xFC, 0x12, 0xF0, 0x09, 0xC0, 0x2F, 0x00, 0x9F, 0x81, 0xBC, 0x02, 0xF0, 0x0B, ++0xC0, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x00, ++0xA7, 0x10, 0xBF, 0x06, 0xCC, 0x46, 0x10, 0x29, 0xC0, 0x2D, 0x00, 0x9F, 0x82, ++0xDC, 0x12, 0xF0, 0x0B, 0xC0, 0x2C, 0x05, 0xB3, 0x00, 0x7C, 0x82, 0x30, 0x4B, ++0xC1, 0x2F, 0x00, 0xB3, 0x00, 0xBC, 0x93, 0x30, 0x0B, 0xC0, 0x77, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x87, 0x00, 0x11, 0x0A, ++0x45, 0x0C, 0xB0, 0xE0, 0x40, 0x07, 0x08, 0x17, 0x00, 0x44, 0x00, 0xD0, 0xA1, ++0x40, 0x84, 0x08, 0x11, 0x00, 0x74, 0x50, 0x10, 0x21, 0x40, 0x17, 0x00, 0x11, ++0x00, 0x74, 0x00, 0x10, 0x01, 0x44, 0x63, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x20, 0xA1, 0x01, 0x85, 0x04, 0x04, 0x52, 0x58, 0x48, ++0x40, 0x23, 0x00, 0x89, 0x00, 0x14, 0x0B, 0xD0, 0x08, 0x40, 0x20, 0x00, 0x85, ++0x80, 0x34, 0x02, 0x10, 0x08, 0x42, 0x25, 0x00, 0xC1, 0x00, 0x34, 0x8A, 0x10, ++0x08, 0x40, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0x28, 0x25, 0x00, 0xD1, 0x00, 0x44, 0x03, 0xD1, 0x09, 0x40, 0x27, 0x0C, 0x95, ++0x04, 0x44, 0x02, 0xD0, 0x09, 0x10, 0x24, 0x14, 0x94, 0x04, 0x74, 0x0A, 0x14, ++0x09, 0x40, 0x27, 0x00, 0x91, 0x00, 0x74, 0x12, 0x18, 0x49, 0x40, 0x63, 0x28, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA2, 0x27, 0x10, 0x97, ++0x00, 0x48, 0x1A, 0x70, 0x09, 0xE0, 0xA5, 0x00, 0x9F, 0x93, 0x54, 0x02, 0xF0, ++0x09, 0xC4, 0xE4, 0x40, 0x97, 0x00, 0x7C, 0x02, 0x33, 0x09, 0xC0, 0x67, 0x00, ++0x91, 0x00, 0x7C, 0x06, 0x34, 0x49, 0x42, 0x17, 0x08, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x20, 0x00, 0x9F, 0x90, 0x7C, 0x12, 0xB0, ++0x09, 0xC0, 0x67, 0x09, 0x97, 0x21, 0x7C, 0x02, 0xF0, 0x08, 0xC0, 0x23, 0x11, ++0x9B, 0x00, 0x7C, 0x0A, 0xF0, 0x09, 0xC0, 0x27, 0x41, 0x9F, 0x20, 0x7C, 0x06, ++0xF0, 0x09, 0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x08, 0x04, 0x00, 0x1F, 0x00, 0x6C, 0x08, 0xF2, 0x01, 0xC0, 0x86, 0x14, ++0x1F, 0x02, 0x4C, 0x40, 0xF0, 0x01, 0xC0, 0x86, 0x03, 0x1F, 0x28, 0x7C, 0x00, ++0xF0, 0x11, 0xC4, 0x04, 0x01, 0x13, 0x10, 0x7C, 0x40, 0x30, 0x21, 0xC0, 0x50, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x14, 0x00, ++0x7D, 0x85, 0xC4, 0x81, 0xD0, 0x05, 0x58, 0xDC, 0x00, 0x5C, 0x00, 0xEC, 0x01, ++0xD0, 0x27, 0x41, 0x1F, 0x10, 0x7D, 0x00, 0x74, 0x01, 0xD0, 0x07, 0x40, 0xD8, ++0x40, 0x73, 0x02, 0xB4, 0x09, 0x15, 0x07, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x32, 0x00, 0xDD, 0x03, 0x74, 0x33, ++0xD0, 0x0C, 0x40, 0x71, 0x00, 0xDD, 0x00, 0x04, 0x0B, 0xD0, 0x2C, 0x41, 0xB2, ++0x00, 0xCC, 0x04, 0x74, 0x03, 0xD0, 0x0C, 0x40, 0x70, 0x00, 0xC1, 0x02, 0x34, ++0x03, 0x90, 0x0C, 0x40, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x04, 0x80, 0x38, 0x00, 0xED, 0x00, 0x94, 0x03, 0xD1, 0x9E, 0x40, 0x99, ++0x28, 0xFD, 0x08, 0xA0, 0x03, 0xDA, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB6, ++0x13, 0xD0, 0x1E, 0x50, 0x3C, 0x04, 0xA9, 0x00, 0xF4, 0x03, 0x90, 0x1C, 0x41, ++0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x78, ++0x10, 0xFF, 0x01, 0xBC, 0x07, 0xF1, 0x5E, 0xC1, 0x6B, 0x00, 0xFE, 0x11, 0x8C, ++0x06, 0xC0, 0x12, 0xC0, 0x6A, 0x00, 0xEF, 0x21, 0xBC, 0x47, 0xF0, 0x1C, 0xE2, ++0x58, 0x00, 0xA3, 0x01, 0xBC, 0x07, 0xB0, 0x1E, 0xD0, 0x50, 0x60, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB0, 0xB5, 0x05, 0x5F, 0x00, 0x6C, ++0x01, 0xF1, 0x2D, 0xC0, 0x06, 0x00, 0xDF, 0x06, 0x7C, 0x00, 0xF0, 0x01, 0xC0, ++0x27, 0x10, 0xDF, 0x00, 0x7C, 0x2B, 0xF0, 0x0D, 0xC0, 0x13, 0x00, 0x17, 0x40, ++0x7C, 0x03, 0x74, 0x0D, 0xD0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x06, 0x28, 0x7D, 0x04, 0x73, 0x01, 0xCD, 0x27, 0x30, 0x1F, 0xC2, ++0x7F, 0x02, 0xF7, 0x01, 0xCC, 0x05, 0xB4, 0x9F, 0xC8, 0x5F, 0x92, 0x6F, 0x09, ++0xDC, 0x07, 0xF0, 0x1F, 0xC0, 0x58, 0x40, 0xB3, 0x09, 0xCC, 0xA5, 0x30, 0x1F, ++0xC0, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x08, ++0x39, 0xA0, 0x61, 0x00, 0xAC, 0x03, 0x10, 0x4E, 0x48, 0x2B, 0x82, 0xE1, 0x00, ++0x84, 0x08, 0x10, 0x06, 0x40, 0x1B, 0x00, 0xED, 0x08, 0x84, 0x03, 0xD0, 0x06, ++0x50, 0x18, 0x02, 0xA1, 0x00, 0x85, 0x33, 0xB0, 0x0A, 0xC8, 0x56, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x39, 0x00, 0xC1, 0x08, ++0x94, 0x43, 0x18, 0x0E, 0x60, 0x2F, 0x84, 0xE5, 0x00, 0x84, 0x00, 0x10, 0x06, ++0x08, 0x1B, 0x00, 0x2D, 0x00, 0x94, 0x43, 0xD0, 0x8E, 0x40, 0x0E, 0x00, 0x81, ++0x80, 0xC4, 0x01, 0x18, 0x0E, 0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x28, 0x35, 0x00, 0x01, 0x00, 0x50, 0x02, 0x18, 0x0D, ++0x44, 0x63, 0x00, 0xC5, 0x02, 0x04, 0x00, 0x10, 0x00, 0x44, 0x83, 0x00, 0x8D, ++0x02, 0x04, 0x4F, 0xD0, 0x04, 0x40, 0xC2, 0x02, 0x01, 0x00, 0x44, 0x01, 0x90, ++0xA8, 0x40, 0x0A, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xA8, 0x3D, 0x00, 0x93, 0x00, 0x54, 0x28, 0x30, 0x0F, 0xC0, 0x67, 0x00, 0xF7, ++0x00, 0x4C, 0x02, 0x30, 0x09, 0x40, 0x27, 0x00, 0x9F, 0x06, 0xDC, 0x0F, 0xF0, ++0x0C, 0x40, 0x62, 0x08, 0x91, 0x00, 0x4C, 0x03, 0x11, 0x3D, 0xC8, 0x54, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x37, 0x00, 0x9F, ++0x02, 0x64, 0x02, 0xF0, 0x0D, 0xC0, 0x87, 0x28, 0xDA, 0x11, 0x7C, 0x0A, 0x70, ++0x09, 0xC0, 0x87, 0x10, 0xDF, 0x10, 0x7C, 0x03, 0xF0, 0x09, 0xC4, 0x05, 0x04, ++0x9F, 0xC0, 0x6C, 0x03, 0xF0, 0x2D, 0xC2, 0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x81, 0x08, 0x3F, 0x00, 0xB3, 0x80, 0x7C, 0x00, 0x31, ++0x0F, 0xE0, 0x0C, 0x04, 0xF7, 0x00, 0x7C, 0x02, 0xF0, 0x03, 0x40, 0x2F, 0x04, ++0x37, 0x00, 0xCC, 0x03, 0xF0, 0x0D, 0xC0, 0x0C, 0x40, 0xB2, 0x00, 0xFC, 0x02, ++0x70, 0x05, 0xC1, 0x05, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA1, 0x20, 0x36, 0x00, 0x91, 0x03, 0x74, 0x04, 0x10, 0x0D, 0x48, 0x44, 0x01, ++0xDD, 0x00, 0x74, 0x04, 0xD0, 0x11, 0x40, 0x47, 0x00, 0x4D, 0x00, 0x6C, 0x03, ++0xD0, 0x09, 0x40, 0x44, 0x00, 0x11, 0x07, 0x74, 0x02, 0x10, 0x44, 0x42, 0x84, ++0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x36, 0x00, ++0x11, 0x01, 0x74, 0x04, 0x10, 0x0D, 0x40, 0x64, 0x18, 0xDD, 0x00, 0x74, 0x06, ++0xD0, 0x1B, 0x60, 0xCF, 0x00, 0x1D, 0x58, 0x44, 0x03, 0xD0, 0x1D, 0x70, 0xC4, ++0x00, 0x35, 0x81, 0x74, 0x21, 0x50, 0x0D, 0x40, 0x05, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0x01, 0x00, 0x24, 0x02, ++0x10, 0x0C, 0x40, 0x20, 0x00, 0xCD, 0x00, 0x34, 0x02, 0xD0, 0x00, 0x40, 0x02, ++0x20, 0xCD, 0x00, 0x24, 0x03, 0xD0, 0x00, 0x40, 0x04, 0x00, 0x05, 0x00, 0x64, ++0x83, 0x14, 0x08, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x10, 0x3A, 0x08, 0x93, 0x00, 0x7C, 0x00, 0x30, 0x0F, 0x40, 0x04, ++0x10, 0xE7, 0x00, 0x7C, 0x02, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x17, 0x60, 0xCC, ++0x03, 0xF0, 0x0D, 0xC0, 0x04, 0x00, 0x17, 0x00, 0x7C, 0x00, 0x71, 0x05, 0xC0, ++0x05, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x38, 0x3F, ++0x20, 0xBF, 0x80, 0xFE, 0x02, 0xF0, 0x0F, 0xC0, 0x0B, 0x00, 0xFF, 0x00, 0xFC, ++0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x83, 0xF0, 0x03, 0xC8, ++0x0F, 0x00, 0x3B, 0x00, 0xBC, 0x00, 0xF0, 0x03, 0xC2, 0x17, 0x62, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x7F, 0x02, 0xFB, 0x09, 0xAC, ++0x07, 0xB0, 0x1F, 0xC0, 0x7A, 0x00, 0xFD, 0x21, 0xEC, 0x07, 0xB0, 0x1F, 0xC0, ++0x7A, 0x08, 0xFB, 0x89, 0xCC, 0x07, 0xF2, 0x1F, 0xC0, 0x7D, 0x12, 0xFB, 0x09, ++0xEC, 0x87, 0x33, 0x1E, 0xD2, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x00, 0x07, 0x01, 0x11, 0x04, 0x44, 0x04, 0x30, 0x11, 0x40, ++0x44, 0x00, 0x11, 0x01, 0x40, 0x00, 0x10, 0x40, 0x47, 0x44, 0x00, 0x0D, 0x00, ++0x44, 0x04, 0x10, 0x11, 0xC0, 0x05, 0x39, 0x11, 0x24, 0x44, 0x10, 0xB2, 0x11, ++0x44, 0x0C, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0x35, 0x18, 0xD9, 0x60, 0x34, 0x03, 0xD0, 0x0D, 0x40, 0x36, 0x00, 0xD9, 0xA0, ++0x64, 0x53, 0x92, 0x0D, 0x40, 0x33, 0x00, 0xD5, 0x00, 0x44, 0x03, 0x90, 0x0C, ++0x40, 0x36, 0x00, 0xDD, 0x04, 0x34, 0x43, 0x19, 0x0C, 0x40, 0x4C, 0x80, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA8, 0x07, 0x08, 0x11, 0x00, ++0x44, 0x00, 0xD1, 0x01, 0x40, 0x04, 0x08, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, ++0x40, 0x05, 0x00, 0x1D, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x05, 0x18, 0x15, ++0x00, 0x14, 0x00, 0x90, 0x01, 0x40, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xA0, 0x32, 0x20, 0xCB, 0x20, 0x6C, 0x03, 0xF0, 0x0D, ++0xC0, 0x36, 0x80, 0xCF, 0x00, 0x2C, 0x03, 0xB0, 0x0D, 0xC0, 0x37, 0x08, 0xDB, ++0x00, 0x4C, 0x03, 0xB0, 0x0C, 0x80, 0x36, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x32, ++0x0C, 0xC8, 0x20, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x88, 0x0D, 0x00, 0x3F, 0x80, 0xF8, 0x40, 0x30, 0x03, 0xC3, 0x0D, 0x80, 0x3E, ++0x00, 0xF8, 0x00, 0xF0, 0x03, 0xC0, 0x0E, 0x08, 0x3D, 0x00, 0xF8, 0x00, 0xB0, ++0x03, 0x82, 0x0F, 0x00, 0x3B, 0x30, 0xE8, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0x35, 0x00, 0xD7, ++0x00, 0x6C, 0x03, 0x71, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC0, 0x36, 0x04, 0xDF, 0x00, 0x5C, 0x93, 0x31, 0x0D, 0xC1, 0x34, 0x02, ++0xDF, 0x00, 0x7C, 0x03, 0x70, 0x0D, 0xC1, 0x09, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x84, 0x06, 0x11, 0x40, 0x34, 0x4C, 0x10, ++0x20, 0x41, 0x83, 0x24, 0x10, 0x00, 0x74, 0x04, 0x10, 0xB0, 0x00, 0x04, 0x00, ++0x02, 0x00, 0x04, 0x0C, 0x10, 0x31, 0x42, 0x03, 0x00, 0x0C, 0x03, 0x70, 0x80, ++0x10, 0x21, 0x40, 0x6C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0x20, 0x70, 0x10, 0xC5, 0x80, 0x24, 0x07, 0x40, 0x0C, 0x40, 0x33, 0x01, ++0xC5, 0x00, 0x24, 0x47, 0x50, 0xAC, 0x40, 0x31, 0x08, 0xC4, 0x00, 0x14, 0x0B, ++0x14, 0x3C, 0x00, 0x30, 0x04, 0xCD, 0x00, 0x34, 0x03, 0x98, 0x2C, 0x40, 0x0F, ++0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x02, 0x4C, 0x0A, ++0x21, 0x09, 0xF4, 0x04, 0x10, 0x12, 0x40, 0x4F, 0x00, 0x25, 0x37, 0xF6, 0x04, ++0x12, 0x12, 0x60, 0x49, 0x02, 0x21, 0x01, 0x84, 0x04, 0x00, 0x12, 0x41, 0x4B, ++0x02, 0x2D, 0x11, 0xB4, 0x24, 0x80, 0x12, 0x42, 0x3E, 0x20, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x30, 0x00, 0xC7, 0x00, 0x2C, 0x23, ++0x51, 0x8C, 0xC0, 0x33, 0x00, 0xCF, 0x08, 0x3C, 0x43, 0x70, 0x0C, 0xC4, 0x31, ++0x06, 0xC7, 0x00, 0x1C, 0x43, 0x30, 0x0C, 0xC0, 0x30, 0x00, 0xCF, 0x00, 0x7C, ++0x03, 0xF0, 0x0C, 0xE4, 0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x38, 0x09, 0x20, 0x3F, 0x00, 0xF0, 0x00, 0xF0, 0x03, 0xC2, 0x0F, ++0x00, 0x3B, 0x2C, 0xBC, 0x20, 0x70, 0x03, 0xC0, 0x0C, 0x02, 0x3F, 0x00, 0xBC, ++0x20, 0xF8, 0x83, 0xC0, 0x0F, 0x00, 0x1F, 0x00, 0xFC, 0x00, 0x71, 0x11, 0xC8, ++0x09, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x77, ++0x00, 0xC3, 0x40, 0x6C, 0x03, 0xF0, 0x0D, 0xC0, 0x73, 0x00, 0xC7, 0x01, 0x6C, ++0x07, 0x36, 0x0D, 0xC4, 0x70, 0x00, 0xDB, 0x40, 0x6C, 0x03, 0xF0, 0x0C, 0xD0, ++0x34, 0x40, 0xD3, 0x00, 0x7C, 0x03, 0xB0, 0x0D, 0xC0, 0x43, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x98, 0x0D, 0x08, 0x2B, 0x00, 0x84, ++0x00, 0xD2, 0x02, 0x40, 0x0B, 0x00, 0x21, 0x60, 0x84, 0x00, 0x10, 0x02, 0x42, ++0x08, 0x00, 0x31, 0x00, 0x84, 0x00, 0x90, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, ++0xB4, 0x00, 0x10, 0x02, 0x40, 0x4F, 0x68, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0xF9, 0x01, 0xA6, 0x07, 0xD9, 0x1E, 0x40, ++0x7B, 0x00, 0xF5, 0x01, 0xA4, 0x07, 0x10, 0x1E, 0x40, 0x78, 0x10, 0xE9, 0x01, ++0xB4, 0x07, 0xD0, 0x1E, 0x60, 0x78, 0x00, 0xE1, 0x01, 0xD4, 0x07, 0x90, 0x1E, ++0x60, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x20, ++0x03, 0x00, 0x19, 0x00, 0x06, 0x00, 0xD0, 0x00, 0x42, 0x03, 0x00, 0x05, 0x00, ++0x04, 0x00, 0x18, 0x00, 0x50, 0x01, 0x00, 0x01, 0x00, 0x14, 0x00, 0x90, 0x00, ++0x60, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x10, 0x00, 0x40, 0x5B, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x28, 0x15, 0x00, 0x5B, 0x80, ++0x2C, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, 0x57, 0x40, 0x6C, 0x01, 0x30, 0x05, ++0xCA, 0x14, 0x10, 0x5B, 0x00, 0x7C, 0x01, 0xF0, 0x04, 0xC0, 0x10, 0x00, 0x53, ++0x00, 0x7C, 0x01, 0xB0, 0x05, 0xC0, 0x5F, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x00, 0x8D, 0x08, 0x3F, 0x00, 0xFC, 0x08, 0xE0, 0x03, ++0xC0, 0x0F, 0x20, 0x39, 0x20, 0xFC, 0x08, 0xF0, 0x03, 0x00, 0x0E, 0x00, 0x3F, ++0x40, 0xE4, 0x80, 0xC2, 0x03, 0xC0, 0x8F, 0x00, 0x3B, 0x20, 0xFC, 0x00, 0xF0, ++0x03, 0xC0, 0x4B, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x22, 0x30, 0x49, 0xC0, 0x25, 0x00, 0x9F, ++0xC0, 0x7C, 0x02, 0xF1, 0x09, 0x80, 0xE5, 0x08, 0x9F, 0x00, 0x5C, 0x02, 0x70, ++0x09, 0xC0, 0x24, 0x00, 0x97, 0x01, 0x7C, 0x16, 0x30, 0x09, 0x80, 0x41, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xE4, 0x23, 0x9D, ++0x00, 0x45, 0x0A, 0x10, 0x18, 0x80, 0x26, 0x00, 0x9C, 0x11, 0x70, 0x06, 0xD0, ++0x28, 0x40, 0x64, 0x04, 0x8D, 0x80, 0x04, 0x02, 0x00, 0x09, 0x40, 0x64, 0x03, ++0x91, 0x02, 0x74, 0x0E, 0x10, 0x18, 0x40, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x80, 0xBD, 0x80, 0xC4, 0x02, 0x50, ++0x0B, 0x40, 0x2C, 0x01, 0xBC, 0x08, 0xF0, 0x22, 0xD2, 0x0B, 0x41, 0x2D, 0x00, ++0xBD, 0x00, 0xD4, 0x02, 0x42, 0x0B, 0x40, 0x2C, 0x00, 0xB5, 0x0A, 0xF4, 0xC2, ++0x00, 0x4B, 0x40, 0x71, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x20, 0x29, 0x00, 0xAD, 0x00, 0xD4, 0x03, 0x54, 0x1B, 0x40, 0x6A, 0x20, ++0xAC, 0xA0, 0xB0, 0xA3, 0xD1, 0x8B, 0x40, 0x29, 0x00, 0xBD, 0x68, 0xC4, 0x02, ++0x51, 0x0B, 0x40, 0x28, 0x02, 0xA1, 0x08, 0xB0, 0x22, 0x11, 0x0B, 0x44, 0x51, ++0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x07, 0x08, ++0x1F, 0x80, 0x4C, 0x00, 0x74, 0x01, 0xC0, 0x05, 0x00, 0x1F, 0x00, 0x38, 0x08, ++0xF0, 0x20, 0xC0, 0x05, 0x00, 0x1F, 0x22, 0x5C, 0x00, 0x72, 0x01, 0xD0, 0x80, ++0x00, 0x17, 0x02, 0x78, 0x08, 0x34, 0x03, 0xC0, 0x75, 0xC0, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x27, 0x05, 0x9F, 0x14, 0x6C, 0x02, ++0xB0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x12, 0xF0, 0x49, 0x80, 0x26, ++0x00, 0x9F, 0x04, 0x7C, 0x02, 0xB0, 0x09, 0xC0, 0x27, 0x01, 0x9F, 0x04, 0x3C, ++0x12, 0xF4, 0x09, 0xC0, 0x66, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1D, 0xA8, 0xAF, 0x00, 0x9F, 0x02, 0xF4, 0x02, 0x30, 0x0B, 0xC0, 0x2B, ++0x00, 0xBF, 0x80, 0xCC, 0x82, 0xF0, 0x0B, 0xD0, 0x2C, 0x00, 0x8B, 0x82, 0x8C, ++0x02, 0xB0, 0x0B, 0xC0, 0x2E, 0x00, 0xAF, 0x00, 0xCD, 0x0A, 0xB0, 0x0A, 0xC0, ++0x64, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x10, 0x47, ++0x01, 0x0D, 0x05, 0x74, 0x00, 0xB0, 0x01, 0x40, 0x07, 0x08, 0x1D, 0x00, 0x6C, ++0x10, 0xD0, 0x41, 0x40, 0x04, 0x00, 0x11, 0x00, 0x54, 0x00, 0x10, 0x01, 0x40, ++0x00, 0x01, 0x1D, 0x00, 0x45, 0x10, 0x10, 0x01, 0x42, 0x70, 0x60, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA2, 0x21, 0x00, 0x8D, 0x00, 0x34, ++0x02, 0x10, 0x0C, 0x40, 0x23, 0x08, 0x9D, 0xA0, 0x04, 0x42, 0xD0, 0x08, 0x41, ++0x24, 0x00, 0x89, 0x00, 0x64, 0x02, 0x90, 0x09, 0x40, 0x22, 0x04, 0x8D, 0x00, ++0x44, 0x02, 0x90, 0x08, 0x50, 0x48, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0x20, 0x25, 0x10, 0x9D, 0x00, 0x74, 0x03, 0x90, 0x0D, 0x40, ++0x27, 0x00, 0x9D, 0x00, 0x64, 0x02, 0xD0, 0x09, 0x40, 0x24, 0x00, 0x91, 0x00, ++0x74, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x8C, 0x00, 0x44, 0x02, 0x10, 0x09, ++0x40, 0x60, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x28, ++0x25, 0x00, 0x9F, 0x00, 0x3C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x20, ++0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x20, 0x00, 0x9B, 0x00, 0x2C, 0x02, 0xB0, 0x08, ++0xC0, 0x26, 0x00, 0x9E, 0x00, 0x4C, 0x02, 0xB0, 0x09, 0xC0, 0x14, 0x28, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80, 0x25, 0x00, 0x9F, 0x00, ++0x7C, 0x02, 0xF8, 0x09, 0xC0, 0x27, 0x10, 0x9F, 0x00, 0x7C, 0x82, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x9F, 0x00, 0x58, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, ++0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC1, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x01, 0x1F, 0x00, 0x4D, 0x10, 0xF0, 0x01, ++0xC0, 0x07, 0x04, 0x17, 0x40, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x17, ++0x00, 0x5C, 0x40, 0x30, 0x81, 0xC0, 0x07, 0x00, 0x17, 0x00, 0x5C, 0x90, 0x34, ++0x01, 0xC0, 0x41, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA0, 0xDC, 0x01, 0x5D, 0x00, 0xC4, 0x05, 0xD0, 0x87, 0x48, 0x5F, 0x04, 0x71, ++0x07, 0xF4, 0x01, 0x10, 0x07, 0x40, 0x1F, 0x02, 0x51, 0x00, 0xC0, 0x11, 0x10, ++0xB7, 0x40, 0x5F, 0x00, 0x70, 0x01, 0x84, 0x01, 0x10, 0x06, 0x40, 0x50, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0xB2, 0x08, 0xCD, ++0x00, 0x14, 0x0A, 0xD8, 0x2C, 0x40, 0xB3, 0x00, 0xD4, 0x11, 0x34, 0x07, 0x10, ++0x1D, 0x40, 0xA3, 0x00, 0xD5, 0x00, 0x14, 0x0E, 0x14, 0x1C, 0x40, 0x63, 0x00, ++0xC4, 0x05, 0x14, 0x2B, 0x14, 0x24, 0x40, 0x51, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x39, 0x00, 0xED, 0x01, 0x84, 0x08, 0xD1, ++0x0E, 0x40, 0x7F, 0x00, 0x61, 0x80, 0xB0, 0x0F, 0x10, 0x0E, 0x4D, 0x2F, 0x00, ++0xF1, 0x00, 0x84, 0x02, 0x10, 0x0E, 0x40, 0x6B, 0x04, 0xF5, 0x30, 0x84, 0x03, ++0x14, 0x07, 0x40, 0x04, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x18, 0x59, 0x00, 0xEF, 0x09, 0x9C, 0x05, 0xF1, 0x1A, 0xC0, 0x4B, 0x00, ++0xE7, 0x41, 0xFC, 0x07, 0x34, 0x16, 0xC0, 0x7B, 0x00, 0xE7, 0x77, 0x9C, 0x06, ++0x30, 0x1E, 0xC2, 0x7B, 0x00, 0x67, 0xE1, 0xDC, 0x06, 0x30, 0x16, 0x80, 0x45, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, 0x00, ++0xDF, 0x00, 0x7C, 0x00, 0xF2, 0x01, 0xC4, 0x27, 0x00, 0xDF, 0x00, 0x7C, 0x00, ++0xE0, 0x05, 0xC0, 0x33, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC4, 0x17, ++0x00, 0x5B, 0x00, 0x7C, 0x02, 0xF0, 0x05, 0xC8, 0x43, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x7F, 0x22, 0xFF, 0x11, 0xF8, 0x04, ++0xF0, 0x9F, 0xC0, 0x7F, 0x00, 0xAF, 0x01, 0xDC, 0x86, 0x30, 0x9F, 0xC8, 0x6B, ++0x00, 0xFB, 0x01, 0xCC, 0x07, 0xF0, 0x1B, 0xE4, 0x6F, 0x00, 0xB3, 0x09, 0xC4, ++0x07, 0x30, 0x16, 0xC8, 0x0A, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0x00, 0x39, 0x00, 0xED, 0x04, 0xBC, 0x40, 0xD8, 0x8A, 0x40, 0x2B, ++0x01, 0x2D, 0x00, 0x84, 0x22, 0x10, 0x8A, 0x42, 0x2B, 0x00, 0xE1, 0x08, 0x84, ++0x42, 0xD0, 0x02, 0x40, 0x2B, 0x01, 0xBB, 0x0C, 0xC4, 0x13, 0xB0, 0x0E, 0x40, ++0x54, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x19, ++0x30, 0xED, 0x40, 0xB4, 0x01, 0xD0, 0x0A, 0x48, 0x0B, 0x80, 0xED, 0x00, 0xB4, ++0x03, 0x94, 0x86, 0x44, 0x3F, 0x04, 0xE9, 0x00, 0x84, 0x03, 0xD0, 0x8A, 0x41, ++0x2B, 0x24, 0x21, 0x40, 0xD5, 0x00, 0x11, 0x07, 0x40, 0x22, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x83, 0x00, 0xCD, 0x09, 0x36, ++0x85, 0xD0, 0xA0, 0x40, 0xE3, 0x84, 0xCD, 0x0C, 0x74, 0x08, 0x90, 0x01, 0x40, ++0xD3, 0x00, 0xD1, 0x52, 0x04, 0x06, 0xD0, 0x00, 0x48, 0xD3, 0x80, 0x09, 0x03, ++0x14, 0x28, 0x90, 0xAC, 0x40, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xA0, 0xE5, 0x2C, 0xFF, 0x0B, 0x7C, 0x2C, 0xF0, 0x30, 0xC0, ++0x67, 0x01, 0xDF, 0x02, 0x7C, 0x19, 0xB0, 0xD9, 0xC0, 0xA7, 0x02, 0xFB, 0x87, ++0x4F, 0x02, 0xE0, 0x2C, 0x00, 0x07, 0x02, 0xD3, 0x11, 0x5D, 0x0D, 0x31, 0x95, ++0xC0, 0x56, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, ++0xA7, 0x00, 0xDE, 0x60, 0x5C, 0x00, 0xF0, 0x21, 0xC0, 0x27, 0x00, 0x1F, 0x02, ++0x40, 0x01, 0x70, 0x25, 0xC0, 0x27, 0x20, 0xDF, 0x80, 0x7C, 0xCA, 0xF0, 0x09, ++0xC9, 0x07, 0x00, 0xDF, 0x52, 0x68, 0x41, 0xF0, 0x05, 0xC0, 0xA7, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x09, 0x2F, 0x14, 0xFF, 0x00, ++0xFC, 0x01, 0xF8, 0x03, 0xC1, 0x0E, 0x00, 0xFF, 0x01, 0xCC, 0x43, 0x30, 0x8B, ++0xC0, 0x6C, 0x20, 0xFF, 0x00, 0xCD, 0x06, 0xF0, 0x8F, 0xC8, 0x3C, 0x00, 0x77, ++0x05, 0xFC, 0x07, 0x34, 0x03, 0xC0, 0x15, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x89, 0x20, 0x66, 0x01, 0xDD, 0x00, 0x74, 0x08, 0xD8, 0x31, ++0x40, 0x64, 0x00, 0x8D, 0x05, 0x44, 0x08, 0x50, 0x05, 0x40, 0x34, 0x00, 0xDE, ++0x00, 0x44, 0x62, 0xD0, 0x19, 0x44, 0x90, 0x00, 0x91, 0x04, 0x74, 0x4B, 0x30, ++0x00, 0x40, 0x14, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0xA0, 0x46, 0x00, 0xDD, 0x80, 0x74, 0x00, 0xD0, 0x19, 0x00, 0x46, 0x00, 0x1D, ++0x08, 0x44, 0x08, 0x10, 0x09, 0x41, 0x25, 0x02, 0xD9, 0x00, 0x64, 0x03, 0xD0, ++0x09, 0x40, 0x84, 0x30, 0x95, 0x00, 0x30, 0x20, 0x02, 0x45, 0x40, 0x05, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0xCD, ++0x00, 0x34, 0x00, 0xD0, 0x08, 0x44, 0x40, 0x00, 0x0D, 0x00, 0x05, 0x00, 0x50, ++0x00, 0x50, 0x20, 0x10, 0xC5, 0x00, 0x04, 0x01, 0xD0, 0x01, 0x10, 0x04, 0x88, ++0x41, 0x00, 0x34, 0x00, 0x11, 0x0C, 0x40, 0x40, 0xA0, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x19, 0x06, 0x00, 0xFF, 0x00, 0x7C, 0x01, 0xD0, ++0x09, 0xC0, 0x06, 0x00, 0x5F, 0x00, 0x0C, 0x03, 0x30, 0x09, 0xC0, 0x24, 0x10, ++0xED, 0x00, 0x4C, 0x03, 0xF0, 0x09, 0xC0, 0x20, 0x20, 0x17, 0x00, 0x7C, 0x00, ++0x34, 0x01, 0xC0, 0x05, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xB8, 0x2D, 0x00, 0xFF, 0x00, 0xFC, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x00, ++0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xC4, 0x1F, 0x00, 0xFF, 0x00, 0xFC, 0x01, ++0xF1, 0x03, 0xE0, 0x1F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0x70, 0x0B, 0xD0, 0x17, ++0x24, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x2F, 0x04, ++0xFF, 0x01, 0xEC, 0x52, 0xD0, 0x1F, 0xC0, 0x3E, 0x21, 0x2F, 0x01, 0xFC, 0x13, ++0x30, 0x0D, 0xC0, 0x57, 0x00, 0x8B, 0x21, 0xCE, 0x23, 0xB0, 0x6F, 0xC0, 0xBC, ++0x09, 0x3F, 0x04, 0xCC, 0x93, 0x33, 0x03, 0xC2, 0x0F, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0x87, 0x10, 0xDD, 0x00, 0x74, 0x0E, ++0xD8, 0x1D, 0x40, 0x7F, 0x0A, 0x9D, 0x01, 0xF4, 0x2F, 0x10, 0x2F, 0x44, 0x57, ++0x10, 0x91, 0x00, 0x44, 0x33, 0x10, 0x2F, 0x40, 0xBC, 0x01, 0x5D, 0x09, 0xC4, ++0xDB, 0x10, 0x01, 0x40, 0x0F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x03, 0x05, 0xCD, 0x54, 0x34, 0x00, 0xD0, 0x0C, 0x40, 0x33, ++0x00, 0xCD, 0x01, 0x34, 0x03, 0x18, 0x2C, 0x40, 0x14, 0x00, 0xDD, 0x00, 0x15, ++0x13, 0xD0, 0x6C, 0x40, 0xB1, 0x08, 0x8D, 0x00, 0x54, 0x23, 0x10, 0x00, 0x40, ++0x4D, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x45, ++0x00, 0xDD, 0x04, 0x74, 0x84, 0xD1, 0x0D, 0x40, 0x37, 0x00, 0xDC, 0x00, 0x74, ++0x03, 0x10, 0x0D, 0x40, 0x17, 0x00, 0x95, 0x00, 0x64, 0x03, 0x50, 0x0D, 0x4A, ++0x35, 0x00, 0xDD, 0x00, 0x54, 0x03, 0x10, 0x11, 0x40, 0x0F, 0x20, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x67, 0x00, 0xDF, 0x20, 0x6C, ++0x14, 0xD0, 0x0D, 0xC0, 0x36, 0x00, 0x5F, 0xE8, 0x7C, 0x03, 0x31, 0x0D, 0xC0, ++0x42, 0x00, 0x8B, 0x40, 0x4C, 0x03, 0xF0, 0x0D, 0x40, 0x35, 0x10, 0x4E, 0x52, ++0x1C, 0x03, 0x14, 0x19, 0xC0, 0x23, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0F, 0x80, 0x05, 0x00, 0xFF, 0x41, 0xFC, 0x02, 0xF2, 0x2F, 0xC1, ++0x3F, 0x0C, 0x7F, 0x01, 0xB0, 0x03, 0xF0, 0x0F, 0xC0, 0x4F, 0x02, 0xB8, 0x40, ++0xD8, 0x03, 0xB0, 0x0F, 0xC0, 0x3E, 0x00, 0xFF, 0x03, 0xEC, 0x23, 0xF4, 0x03, ++0x40, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, ++0x65, 0x01, 0xD3, 0x00, 0x7C, 0x0C, 0xF0, 0x0D, 0xC8, 0x37, 0x00, 0x5B, 0x00, ++0x4C, 0x43, 0xF0, 0x8D, 0xC0, 0x97, 0x00, 0xDF, 0x08, 0x5C, 0x03, 0xF1, 0x0D, ++0xC0, 0x37, 0x00, 0x5F, 0x00, 0x5C, 0x43, 0xF0, 0x89, 0xC0, 0x2B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x04, 0x00, 0xD1, 0x0B, ++0x74, 0x00, 0xD0, 0x3D, 0x40, 0xBF, 0x24, 0x51, 0x0A, 0xC4, 0x1B, 0xD0, 0xBF, ++0x40, 0x17, 0x06, 0x9C, 0x00, 0xC4, 0x03, 0xD0, 0x0F, 0x04, 0x3C, 0x10, 0xDC, ++0x01, 0x40, 0x0B, 0x10, 0xB9, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0x20, 0xA0, 0x00, 0xC1, 0x01, 0x24, 0x02, 0xD0, 0x1C, ++0x40, 0x33, 0x00, 0x09, 0x0B, 0x34, 0x03, 0xD0, 0x1C, 0x60, 0x83, 0x08, 0x88, ++0x01, 0x54, 0x03, 0xD0, 0x0D, 0x40, 0x30, 0x00, 0x4D, 0x13, 0x10, 0x2F, 0x50, ++0x08, 0x40, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, ++0x00, 0x78, 0x40, 0xE1, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x49, 0x7B, 0x00, 0xB5, ++0x09, 0xA4, 0x87, 0xD0, 0x5E, 0x40, 0x4B, 0x09, 0xAD, 0x25, 0x80, 0x07, 0xD0, ++0x1C, 0x40, 0x78, 0x00, 0xCD, 0x21, 0xC0, 0x27, 0x00, 0x12, 0x40, 0x3F, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x10, 0x02, 0xC3, ++0x18, 0x3C, 0x23, 0xF8, 0x0C, 0xC0, 0x33, 0x01, 0x8B, 0x08, 0x2C, 0x03, 0xF0, ++0x5C, 0x80, 0x43, 0x01, 0xCF, 0x05, 0x1C, 0x03, 0xF0, 0x4C, 0xC0, 0x31, 0x00, ++0x4F, 0x10, 0x5C, 0x37, 0x70, 0x0C, 0xC0, 0x4B, 0x60, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x3D, 0x00, 0xFF, 0x08, 0xFC, 0x23, 0xF0, ++0x0F, 0xC8, 0x3B, 0x00, 0xFB, 0x68, 0xDC, 0x23, 0xF0, 0x2F, 0xC1, 0x0F, 0x20, ++0x9F, 0x00, 0x7C, 0x03, 0xF0, 0x0F, 0xC0, 0x3C, 0x00, 0xFF, 0x08, 0x7C, 0xAB, ++0x52, 0x0F, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xA8, 0x37, 0x00, 0xDF, 0x00, 0x78, 0x01, 0xF0, 0x0D, 0xC0, 0x36, 0x04, ++0x1F, 0x00, 0x4C, 0x63, 0xF0, 0x4D, 0xC8, 0x06, 0x08, 0x93, 0x00, 0x7C, 0x03, ++0xF1, 0xFD, 0xC0, 0xB6, 0x01, 0x5F, 0x01, 0x6C, 0x0A, 0x30, 0x0D, 0xC0, 0x40, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x90, 0x39, 0x00, ++0xED, 0x80, 0xB4, 0x03, 0xC1, 0x0E, 0xC0, 0x39, 0x01, 0xED, 0x00, 0x84, 0x03, ++0xD1, 0x4E, 0x42, 0x0A, 0x00, 0xA5, 0x00, 0xB4, 0x13, 0xD1, 0x0E, 0x41, 0x38, ++0x0D, 0xED, 0x00, 0x84, 0x02, 0x12, 0x06, 0xC0, 0x4E, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x28, 0xED, 0x21, 0xB0, 0x07, ++0xD9, 0x1E, 0x40, 0x7B, 0x03, 0xAD, 0x01, 0xA4, 0x17, 0xD0, 0x5E, 0x40, 0x4A, ++0x08, 0xE1, 0x21, 0xB4, 0x27, 0xD0, 0x1C, 0x40, 0x7A, 0x02, 0x7D, 0x01, 0xA4, ++0x06, 0x10, 0x1C, 0x40, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x16, 0x00, 0x37, 0x04, 0x9D, 0x41, 0x34, 0x47, 0xD0, 0x08, 0x40, 0x31, ++0x00, 0xCD, 0x08, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x62, 0x80, 0x85, 0x00, 0x34, ++0x03, 0xD0, 0x0C, 0x40, 0x30, 0x00, 0xCD, 0x03, 0x04, 0x02, 0x10, 0x2D, 0x40, ++0x5A, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x28, 0x9F, ++0x00, 0x5D, 0x01, 0xFE, 0x1D, 0xF0, 0x15, 0xE1, 0x16, 0x00, 0x6F, 0x03, 0x6F, ++0x01, 0xF0, 0x05, 0xC0, 0x5A, 0x04, 0x53, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, ++0x16, 0x00, 0x7F, 0x10, 0x6C, 0x45, 0x30, 0x47, 0xC0, 0x5C, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x05, 0x00, 0x1F, 0x08, 0x7E, ++0x00, 0xF0, 0x01, 0xA0, 0x07, 0x00, 0x1F, 0x04, 0x5E, 0x00, 0xF0, 0x20, 0x08, ++0x07, 0x01, 0x1F, 0x80, 0x7C, 0x00, 0xD0, 0x01, 0xC0, 0x03, 0x20, 0x1D, 0x24, ++0x7C, 0x00, 0xF0, 0x21, 0xD8, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x08, 0x65, 0x00, 0x93, 0xC1, 0x2C, 0x82, 0xE1, 0x19, 0xC0, ++0x25, 0x09, 0x9F, 0x00, 0x4C, 0x92, 0xD0, 0x19, 0xC0, 0x64, 0x10, 0x93, 0x08, ++0x3C, 0x02, 0x40, 0x09, 0xC4, 0x27, 0x00, 0x93, 0x80, 0x7C, 0x02, 0x75, 0x09, ++0xC1, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, ++0x66, 0x00, 0x91, 0x81, 0x4C, 0x02, 0x10, 0x98, 0x00, 0xA5, 0x00, 0x9D, 0x18, ++0x45, 0x0A, 0xD0, 0xA9, 0x50, 0x24, 0x03, 0x95, 0x00, 0x74, 0x02, 0x13, 0x09, ++0x44, 0x27, 0x00, 0x91, 0x1B, 0x34, 0x06, 0x12, 0x69, 0x50, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x34, 0x82, 0x99, 0x08, ++0x64, 0x06, 0x10, 0x09, 0x00, 0xA4, 0x00, 0x99, 0x00, 0x54, 0x42, 0xD2, 0x09, ++0x45, 0x34, 0x00, 0x91, 0x00, 0x74, 0x02, 0x50, 0x09, 0x40, 0x27, 0x40, 0x91, ++0x00, 0x74, 0x12, 0x51, 0x0D, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x22, 0x30, 0x15, 0xC1, 0x00, 0x04, 0x52, 0x12, 0x19, ++0x42, 0x21, 0x80, 0x8D, 0x40, 0x06, 0x82, 0xD0, 0x08, 0x40, 0x24, 0x00, 0x85, ++0x00, 0x34, 0x22, 0x50, 0x88, 0x40, 0x23, 0x02, 0x81, 0x00, 0x70, 0xD2, 0x10, ++0x48, 0x41, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0x38, 0x07, 0x01, 0x1B, 0x00, 0x6C, 0x10, 0x70, 0x01, 0xC0, 0x05, 0x05, 0x1B, ++0x40, 0x48, 0xD0, 0xF0, 0xE1, 0xC1, 0x04, 0x00, 0x53, 0x0A, 0x7C, 0x58, 0x71, ++0x61, 0xC1, 0x87, 0x05, 0x13, 0x14, 0x38, 0x11, 0x70, 0x41, 0xC0, 0x74, 0xE0, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x2D, 0x45, 0xBF, ++0x14, 0xDC, 0x02, 0xB4, 0x0B, 0xC0, 0x27, 0x00, 0xAC, 0x00, 0x7C, 0x02, 0xF0, ++0x19, 0xC0, 0x2B, 0x08, 0xBF, 0x01, 0x7C, 0x12, 0xB1, 0x49, 0xC0, 0x27, 0x11, ++0xAF, 0x00, 0xFC, 0x52, 0xF0, 0x4B, 0xC1, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xA0, 0xBF, 0x00, 0xB3, 0x00, 0xFC, 0x52, 0xF0, ++0x0B, 0xC0, 0x2D, 0x05, 0xB3, 0x00, 0xCC, 0x02, 0xF0, 0x0B, 0xC0, 0x2C, 0x00, ++0xBF, 0x80, 0x6C, 0x02, 0x10, 0x09, 0xC0, 0x24, 0x00, 0xBF, 0x00, 0xCC, 0x02, ++0x32, 0x0B, 0xD0, 0x74, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0x00, 0x87, 0x00, 0x1B, 0xA4, 0x74, 0x08, 0xD0, 0x01, 0x40, 0x84, 0x48, ++0x11, 0x20, 0x44, 0x00, 0xD2, 0xA1, 0x40, 0x05, 0x00, 0x1D, 0x00, 0x40, 0x90, ++0x10, 0x41, 0x40, 0x04, 0x01, 0x1D, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x60, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, 0xA1, 0x21, ++0x81, 0x10, 0x30, 0x02, 0xD0, 0x08, 0x40, 0x21, 0x00, 0xD5, 0x00, 0x04, 0x0B, ++0xD0, 0x0D, 0x40, 0x20, 0x00, 0x8D, 0x80, 0x30, 0x4A, 0x11, 0x28, 0x41, 0xA2, ++0x04, 0x8D, 0x00, 0x05, 0x82, 0x14, 0x08, 0x40, 0x49, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0x99, 0x04, 0x74, 0x02, ++0xD0, 0x49, 0x40, 0x26, 0x08, 0x95, 0x00, 0x44, 0x02, 0xC0, 0x09, 0x40, 0x25, ++0x0D, 0x9D, 0x80, 0x14, 0x02, 0x10, 0x08, 0x46, 0x26, 0x00, 0x9D, 0x10, 0x44, ++0x02, 0x10, 0x0D, 0x40, 0x60, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0x20, 0xE5, 0x06, 0x93, 0x40, 0x78, 0x1A, 0xD1, 0x09, 0xC0, 0x25, ++0x00, 0x97, 0x0F, 0x45, 0x02, 0xF0, 0x09, 0xC0, 0xA4, 0x00, 0x8F, 0x81, 0x7E, ++0x02, 0x34, 0x09, 0xD0, 0x26, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0x30, 0x49, 0xC0, ++0x15, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x24, ++0x00, 0x9F, 0xC0, 0x7C, 0x12, 0xF0, 0x09, 0xC8, 0x25, 0x00, 0x9B, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC0, 0x67, 0x00, 0x9F, 0x05, 0x6C, 0x02, 0xF0, 0x09, 0xC0, ++0x25, 0x00, 0x9F, 0x40, 0x7C, 0x02, 0xF0, 0x49, 0xC1, 0x5B, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x10, 0x78, ++0x08, 0xF0, 0x01, 0xC1, 0x01, 0x04, 0x1F, 0x04, 0x7C, 0x90, 0xB0, 0x01, 0xC0, ++0x84, 0x00, 0x1F, 0x10, 0x4C, 0x00, 0xF1, 0x01, 0xC0, 0x07, 0x10, 0x07, 0x10, ++0x3C, 0x04, 0x30, 0x21, 0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0xDC, 0x01, 0x7D, 0x07, 0x74, 0x01, 0x10, 0x26, 0x40, ++0x1F, 0x19, 0x6D, 0x00, 0xF4, 0x09, 0x10, 0x07, 0x40, 0xDC, 0x02, 0x7D, 0x03, ++0x44, 0x01, 0xD0, 0x05, 0x40, 0x17, 0x00, 0x71, 0x45, 0xF4, 0x41, 0x11, 0x27, ++0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, ++0xF6, 0x01, 0xCD, 0x03, 0x34, 0x22, 0x58, 0x2C, 0x48, 0x73, 0x00, 0xCC, 0x00, ++0x34, 0x03, 0xD0, 0x0D, 0x40, 0x30, 0x00, 0xCD, 0x0A, 0x32, 0x03, 0xD0, 0x0C, ++0x40, 0x33, 0x80, 0xC5, 0x00, 0x34, 0x04, 0x90, 0xAD, 0x40, 0x40, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x00, 0x6D, 0x00, ++0xB4, 0x07, 0x5A, 0x2A, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xB0, 0x07, 0x52, 0x0A, ++0x40, 0x98, 0x00, 0xED, 0x00, 0x84, 0x13, 0xD0, 0x4E, 0x40, 0x7B, 0x81, 0xE1, ++0x00, 0xB4, 0x02, 0x90, 0x04, 0x44, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x18, 0x79, 0x08, 0xEF, 0x01, 0xBC, 0x87, 0x70, 0x1E, ++0xC0, 0x5B, 0x00, 0xEE, 0x01, 0xBC, 0x06, 0xF0, 0x1F, 0xC0, 0x78, 0x00, 0xBF, ++0x01, 0x9C, 0x07, 0xF0, 0xBE, 0xC4, 0x7F, 0x21, 0xE7, 0x01, 0xFC, 0x04, 0xB0, ++0x1E, 0xD0, 0x50, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xB2, 0x35, 0x00, 0x5F, 0x60, 0x3C, 0x03, 0x38, 0x01, 0xC8, 0x07, 0x00, 0xDF, ++0x00, 0x3C, 0x00, 0xB0, 0x05, 0xC0, 0x37, 0x00, 0x9F, 0x20, 0x7C, 0x2B, 0xF0, ++0x6D, 0xC8, 0xB7, 0x20, 0x9D, 0x00, 0x7C, 0x82, 0x71, 0x05, 0xC0, 0x43, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x7D, 0x02, 0xFF, ++0x81, 0xCC, 0x17, 0x71, 0x17, 0xC0, 0x6F, 0x02, 0xFF, 0x81, 0xFC, 0x85, 0xF0, ++0x9F, 0x40, 0x78, 0x02, 0xB3, 0x29, 0xFE, 0x2F, 0xB0, 0x1F, 0xE0, 0xFF, 0x04, ++0x73, 0x09, 0xFC, 0x27, 0xF1, 0x5F, 0xC0, 0x1B, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x19, 0x26, 0x6D, 0x08, 0xAC, 0x83, 0xD0, ++0x22, 0x40, 0x8B, 0x00, 0x2D, 0x00, 0xB4, 0x08, 0xD0, 0x1A, 0x40, 0x98, 0x00, ++0xA1, 0x01, 0xB4, 0x03, 0xD0, 0x0E, 0xC0, 0x39, 0x01, 0xEB, 0x00, 0x34, 0x07, ++0xD0, 0x0A, 0x40, 0x57, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x48, 0x08, 0x39, 0x18, 0xFD, 0x00, 0xA4, 0x13, 0xD0, 0x02, 0x40, 0x0B, 0x00, ++0xED, 0x10, 0xB4, 0x20, 0xD0, 0x0E, 0x40, 0x2B, 0x40, 0x21, 0x00, 0xB4, 0x83, ++0x91, 0x0E, 0x40, 0x39, 0x10, 0x61, 0x10, 0xB4, 0x02, 0xD0, 0x4E, 0x40, 0x23, ++0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x21, 0x00, ++0x1D, 0x01, 0x26, 0x07, 0xD0, 0x00, 0x40, 0x03, 0x00, 0x0D, 0x03, 0x34, 0x80, ++0xD0, 0x00, 0x40, 0xA3, 0x00, 0x01, 0x01, 0x34, 0x03, 0xD0, 0x0C, 0x48, 0x31, ++0x80, 0x85, 0x00, 0x34, 0x81, 0xD0, 0x29, 0x40, 0x0B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x04, 0x00, 0x9F, 0x01, 0x64, 0x0B, ++0x71, 0x09, 0xC0, 0x27, 0x90, 0x1F, 0x03, 0x7C, 0x02, 0xF0, 0x01, 0xC0, 0x27, ++0x20, 0xD3, 0x11, 0xFC, 0x03, 0xB0, 0x0F, 0xC0, 0x3D, 0x00, 0x81, 0x01, 0x7C, ++0x01, 0xD0, 0x29, 0xC0, 0x57, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x0D, 0x00, 0x87, 0x01, 0x9F, 0x08, 0x7C, 0x23, 0xF0, 0x19, 0xC0, 0x27, ++0x00, 0x1F, 0x32, 0x3E, 0x0A, 0xF0, 0x01, 0x40, 0x14, 0xA1, 0x9F, 0x00, 0x70, ++0x03, 0xD0, 0x0D, 0xC8, 0x35, 0x40, 0x9B, 0x10, 0x74, 0x01, 0xE0, 0x21, 0xC0, ++0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x08, 0x0B, ++0x00, 0xBB, 0x00, 0x8C, 0x43, 0xB0, 0x0B, 0xC4, 0x2B, 0x00, 0xF3, 0x00, 0xFC, ++0x02, 0x32, 0x01, 0xC4, 0x2F, 0x01, 0xBF, 0x40, 0xEC, 0x03, 0xF0, 0x0F, 0xC4, ++0x3B, 0x00, 0x37, 0x05, 0x94, 0x81, 0x33, 0x03, 0x81, 0x04, 0x28, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xC6, 0x21, 0x91, 0x07, 0x44, ++0x83, 0xB0, 0x31, 0x40, 0xE7, 0x00, 0xD1, 0x06, 0x74, 0x04, 0x10, 0x31, 0x48, ++0x77, 0x10, 0x9C, 0x01, 0x74, 0x03, 0x71, 0x0D, 0x40, 0x37, 0x00, 0x11, 0x32, ++0x44, 0x0B, 0x10, 0x31, 0x40, 0x85, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0xA0, 0x64, 0x00, 0x19, 0x01, 0x54, 0x07, 0x90, 0x19, 0x00, ++0x66, 0x00, 0x11, 0x01, 0x74, 0x06, 0x10, 0x13, 0x41, 0x07, 0x00, 0xB9, 0x01, ++0x74, 0x03, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0x55, 0x00, 0x54, 0x47, 0x50, 0x19, ++0x40, 0x05, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x00, 0x00, 0x01, 0x20, 0x14, 0x03, 0x90, 0x08, 0x62, 0x03, 0x00, 0x00, 0x00, ++0x34, 0x02, 0x14, 0x40, 0x40, 0x13, 0x00, 0x8D, 0x04, 0x34, 0x03, 0x50, 0x0C, ++0x40, 0x33, 0x08, 0xC1, 0x00, 0x14, 0x20, 0x10, 0x08, 0x42, 0x41, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x26, 0x08, 0x9B, 0x00, ++0x5E, 0x03, 0xB1, 0x09, 0xC0, 0x27, 0x40, 0xD1, 0x00, 0x7C, 0x02, 0x30, 0x41, ++0xC0, 0x07, 0x10, 0x1F, 0x1C, 0xEC, 0x03, 0xF1, 0x0F, 0xE4, 0x3B, 0x00, 0x57, ++0x00, 0x5C, 0x12, 0x34, 0x01, 0xC0, 0x05, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x45, 0xA8, 0x2F, 0x00, 0xAF, 0x00, 0xEC, 0x03, 0x70, 0x03, ++0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0xC1, 0xC1, 0x0F, 0x04, 0x1F, ++0x04, 0xFC, 0x03, 0x72, 0x0F, 0xC4, 0x3F, 0x00, 0x3F, 0x00, 0x6C, 0x30, 0xF0, ++0x03, 0xC4, 0x17, 0x62, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA0, 0x2D, 0x11, 0xBF, 0x00, 0xFC, 0x13, 0xB2, 0x93, 0xC8, 0x3D, 0x11, 0x13, ++0x08, 0xDC, 0x22, 0x32, 0x4F, 0xC8, 0x0F, 0x20, 0x7B, 0x41, 0xEC, 0x03, 0xF0, ++0x17, 0xC0, 0x3C, 0x00, 0xBF, 0x01, 0xEC, 0x00, 0x30, 0x03, 0xC4, 0x0C, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x47, 0x02, 0x9C, ++0x8C, 0xF4, 0x27, 0x04, 0x09, 0x4C, 0x7D, 0x22, 0x1D, 0x04, 0x74, 0x12, 0x50, ++0xAF, 0x42, 0x07, 0x00, 0x99, 0x81, 0x44, 0x0B, 0xD0, 0x09, 0x40, 0x3C, 0x10, ++0x9D, 0x40, 0x44, 0x00, 0x10, 0x11, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x21, 0x08, 0x0D, 0x50, 0x34, 0x03, 0x18, ++0x51, 0x44, 0x31, 0x00, 0x0D, 0x20, 0x74, 0x02, 0x10, 0x0C, 0x64, 0x01, 0x00, ++0x89, 0x00, 0x24, 0x0B, 0xD0, 0x01, 0x50, 0x30, 0x00, 0x9D, 0x00, 0x24, 0x00, ++0x10, 0x00, 0x40, 0x4C, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA8, 0x47, 0x80, 0x1D, 0x51, 0x74, 0x03, 0x10, 0x11, 0x40, 0x35, 0x00, ++0x3D, 0x02, 0xF4, 0x02, 0x50, 0x0D, 0x00, 0x4F, 0x08, 0x89, 0x08, 0x44, 0x03, ++0xD2, 0x19, 0x00, 0x3C, 0x00, 0x9D, 0x01, 0x44, 0x04, 0x10, 0x11, 0x42, 0x0C, ++0xA0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x67, 0x00, ++0x9F, 0x03, 0x7C, 0x03, 0x30, 0x18, 0xCC, 0x35, 0x18, 0x1B, 0x01, 0x5E, 0x06, ++0x20, 0x0D, 0xC0, 0xC7, 0x00, 0xDB, 0x00, 0x6C, 0x03, 0xF0, 0x1C, 0xC0, 0x34, ++0x20, 0xCF, 0x01, 0x6C, 0x84, 0x30, 0x11, 0xC0, 0x00, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x2D, 0x00, 0xBF, 0x80, 0xBC, 0x03, ++0xF0, 0x0B, 0xC0, 0x3E, 0x80, 0x1D, 0x03, 0xFC, 0x26, 0xF0, 0x0F, 0xC0, 0x2F, ++0x00, 0xBF, 0x01, 0xFC, 0x03, 0xF2, 0x0B, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, ++0x00, 0xF4, 0x09, 0xD0, 0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x08, 0x25, 0x18, 0x93, 0x01, 0x7C, 0xA3, 0xF0, 0x01, 0xC0, 0x77, ++0x00, 0x1B, 0x02, 0x4C, 0x42, 0xF0, 0x0D, 0xC0, 0x87, 0x00, 0x9F, 0x00, 0x7C, ++0x03, 0x30, 0x09, 0x80, 0x37, 0x00, 0x5F, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC1, ++0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xA0, 0x64, ++0x04, 0x91, 0x02, 0xF4, 0x2F, 0xD0, 0x01, 0x40, 0xBF, 0x00, 0x11, 0x80, 0x45, ++0x47, 0xD1, 0x0F, 0x44, 0x27, 0x00, 0x9D, 0x00, 0xF4, 0x03, 0x10, 0x09, 0x40, ++0x3F, 0x00, 0x5D, 0x00, 0x34, 0x44, 0x10, 0x38, 0x58, 0x6C, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x00, 0x60, 0x08, 0x30, 0x36, ++0x0F, 0xD8, 0x00, 0x40, 0x33, 0x01, 0x09, 0x00, 0x50, 0x0E, 0xD0, 0x9C, 0x22, ++0x43, 0x02, 0x4C, 0x80, 0x34, 0x03, 0x10, 0x00, 0x40, 0x33, 0x00, 0xCD, 0x06, ++0x34, 0x00, 0x14, 0xA0, 0x40, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0F, 0x00, 0x58, 0x02, 0xE9, 0x81, 0xB4, 0x07, 0xD0, 0x1A, 0x40, ++0x7B, 0x00, 0x21, 0x09, 0x84, 0x06, 0xD1, 0x9E, 0x40, 0x5B, 0x00, 0xAD, 0x01, ++0xB4, 0x07, 0x10, 0x1A, 0x40, 0x7B, 0x00, 0xED, 0x41, 0xB4, 0x07, 0x18, 0x9A, ++0x40, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x1A, ++0x30, 0x00, 0x4B, 0x08, 0x3C, 0x03, 0xF0, 0x80, 0xC0, 0x33, 0x00, 0x0B, 0x05, ++0x0C, 0x02, 0xF0, 0x0C, 0xC0, 0x43, 0x01, 0xCF, 0x00, 0x7C, 0x23, 0x34, 0x00, ++0x40, 0x33, 0x00, 0xCF, 0x00, 0x3C, 0x01, 0x30, 0x04, 0xC8, 0x48, 0x68, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x19, 0x00, 0xF0, 0x60, ++0xFC, 0x63, 0xF0, 0x0F, 0xC0, 0x3B, 0x02, 0xFF, 0x08, 0xF0, 0x23, 0xF0, 0x0F, ++0xC4, 0x1F, 0x02, 0xBF, 0x00, 0xFC, 0x83, 0xF0, 0x0B, 0xC0, 0xBF, 0x10, 0xFF, ++0x00, 0xBC, 0x03, 0xF1, 0x0D, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0x17, 0x10, 0x53, 0x00, 0x74, 0x5F, 0x34, 0x09, ++0xC0, 0x37, 0x00, 0x1F, 0x00, 0x4C, 0x02, 0x31, 0x9D, 0x80, 0x74, 0x00, 0xD3, ++0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0xB7, 0x82, 0xCF, 0x00, 0x2C, 0x02, 0x30, ++0x15, 0xD0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0x8A, 0x39, 0x00, 0xE1, 0x00, 0x34, 0x13, 0x10, 0x0A, 0x40, 0xBB, 0x03, 0x8D, ++0x80, 0x84, 0x02, 0x12, 0x8C, 0x42, 0x3C, 0x08, 0xA1, 0x00, 0xB4, 0x13, 0xD0, ++0x0A, 0x40, 0x3A, 0x80, 0xED, 0x00, 0x84, 0x03, 0x10, 0x0E, 0x40, 0x4C, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x40, 0x69, ++0x01, 0xB4, 0x17, 0xD0, 0x1E, 0x40, 0x7B, 0x00, 0x6D, 0x11, 0x94, 0x46, 0x90, ++0x5E, 0x40, 0x68, 0x00, 0xE1, 0x01, 0xB4, 0x37, 0x90, 0x1E, 0x40, 0x7B, 0x00, ++0x7D, 0x61, 0xA4, 0x07, 0x14, 0x14, 0x40, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0xB3, 0x00, 0xC9, 0x01, 0x34, 0x03, 0x50, ++0x8C, 0x40, 0x33, 0x00, 0xCD, 0xC3, 0x54, 0x07, 0x90, 0x0C, 0x50, 0x70, 0x01, ++0x81, 0x00, 0x34, 0x03, 0xD0, 0x48, 0x40, 0x36, 0x00, 0x4D, 0x09, 0x04, 0x03, ++0x10, 0x1C, 0x41, 0x58, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x17, 0xA0, 0x1F, 0x20, 0x7B, 0x85, 0x7C, 0x01, 0x78, 0x17, 0xC6, 0x17, 0x08, ++0x7F, 0x03, 0x5C, 0x05, 0xB6, 0x05, 0xC0, 0x5C, 0x01, 0x73, 0x02, 0x7C, 0x01, ++0xB0, 0x37, 0xC1, 0x17, 0x00, 0x7F, 0x09, 0xAC, 0x01, 0x30, 0x77, 0xC0, 0x5C, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x05, 0x24, ++0x17, 0x46, 0x7C, 0x00, 0xA0, 0x01, 0xE0, 0x83, 0x20, 0x1E, 0xA0, 0x6C, 0x00, ++0x70, 0x01, 0xC0, 0x87, 0x00, 0x1F, 0x04, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x06, ++0x00, 0x1F, 0x02, 0x7C, 0x04, 0xF0, 0x01, 0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0xA1, 0x00, 0x93, 0x08, 0x7C, 0x86, ++0xF0, 0x09, 0xC1, 0x25, 0x08, 0x93, 0x10, 0x4C, 0x02, 0x30, 0x09, 0xC0, 0x67, ++0x00, 0x9F, 0x00, 0x4C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x48, ++0x16, 0x30, 0x49, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x20, 0x26, 0x00, 0x95, 0x03, 0x74, 0x66, 0xD0, 0x09, 0x40, 0x27, ++0x20, 0x91, 0x00, 0x44, 0x0A, 0x10, 0x39, 0x44, 0xA7, 0x02, 0x8D, 0x20, 0x44, ++0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x85, 0x40, 0x44, 0x42, 0x10, 0x49, 0x40, ++0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x34, ++0x00, 0x91, 0x82, 0x74, 0x82, 0xD0, 0x09, 0x40, 0x67, 0x00, 0x81, 0x00, 0x54, ++0x0A, 0x10, 0x49, 0x49, 0xB7, 0x00, 0x9D, 0x00, 0x44, 0x02, 0xD0, 0x09, 0x40, ++0x27, 0x00, 0x91, 0x00, 0x55, 0x03, 0x10, 0x0D, 0x40, 0x63, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0xA5, 0x85, 0x14, 0x34, ++0x82, 0xD0, 0x88, 0x40, 0x33, 0x60, 0x81, 0x4C, 0x04, 0x32, 0x18, 0x08, 0x40, ++0x23, 0x01, 0x9D, 0x02, 0x04, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x01, 0x85, 0x00, ++0x14, 0xD2, 0x10, 0x48, 0x41, 0x43, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xB0, 0x07, 0x01, 0x13, 0x24, 0x7C, 0x50, 0xF0, 0x21, 0xC4, ++0x05, 0x05, 0x13, 0x03, 0x09, 0x0C, 0x30, 0xE1, 0xC1, 0xC7, 0x02, 0x1F, 0x00, ++0x4D, 0x78, 0xF0, 0xA1, 0xC8, 0xC7, 0x0A, 0x53, 0x00, 0x5C, 0x10, 0x32, 0x41, ++0xC0, 0x77, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, ++0x2B, 0x00, 0xBF, 0x14, 0x7C, 0x02, 0xF0, 0x4B, 0xC0, 0x27, 0x00, 0xBF, 0x0C, ++0xFC, 0x32, 0xF4, 0x19, 0xC2, 0x6F, 0x02, 0xBD, 0x01, 0x7C, 0x06, 0xF0, 0x1B, ++0xC0, 0x67, 0x02, 0xFF, 0x14, 0xE4, 0x52, 0xF4, 0x0B, 0xC0, 0x77, 0x40, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x7F, 0x04, 0xBF, 0x02, ++0xFC, 0x02, 0xF0, 0x29, 0xC0, 0x2D, 0x20, 0x9F, 0x00, 0xFC, 0x0A, 0x30, 0x4B, ++0xC0, 0x2C, 0x00, 0x93, 0x02, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0x24, 0x00, 0xB3, ++0x00, 0xFC, 0x0A, 0x30, 0x0B, 0xC0, 0x74, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x08, 0x17, 0x00, 0x1D, 0x02, 0x74, 0x28, 0xD0, 0x00, ++0x48, 0x87, 0x02, 0x1D, 0x04, 0x5C, 0x10, 0x14, 0xA1, 0x50, 0x04, 0x00, 0x15, ++0x01, 0x74, 0x28, 0x10, 0x01, 0x40, 0x05, 0x00, 0x1B, 0x00, 0x74, 0x10, 0x10, ++0x01, 0xC0, 0x62, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x00, 0x21, 0x20, 0x8D, 0x86, 0x34, 0x02, 0xC0, 0x08, 0x40, 0x23, 0x00, 0x8D, ++0x10, 0x30, 0x12, 0x18, 0x08, 0x40, 0x24, 0x00, 0x81, 0x01, 0x34, 0x02, 0x14, ++0x08, 0x40, 0x20, 0x00, 0x81, 0x00, 0x34, 0x13, 0x10, 0x08, 0x44, 0x48, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0xDD, ++0x0A, 0x74, 0x02, 0xC0, 0x09, 0x40, 0x37, 0x00, 0x9D, 0x02, 0x14, 0x22, 0x10, ++0x09, 0x40, 0x24, 0x00, 0x95, 0x01, 0x34, 0x02, 0x10, 0x49, 0x44, 0x25, 0x00, ++0x99, 0x00, 0x34, 0x06, 0x14, 0x49, 0x40, 0x62, 0x20, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0x0A, 0x25, 0x10, 0x9F, 0x00, 0x7C, 0x02, 0xE0, ++0x29, 0xC1, 0x27, 0x00, 0x9F, 0x02, 0x7C, 0x02, 0x30, 0x08, 0xC6, 0x64, 0x02, ++0xB3, 0x00, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0x24, 0x00, 0x93, 0x02, 0x7C, 0x06, ++0x30, 0x09, 0xC0, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x16, 0x00, 0xA5, 0x20, 0x9F, 0x21, 0x7C, 0x02, 0xF0, 0x39, 0xC0, 0x27, 0x04, ++0x9F, 0x04, 0x7C, 0x02, 0xF0, 0x09, 0x40, 0x67, 0x00, 0x9F, 0x00, 0x7C, 0x02, ++0xF2, 0x19, 0xC0, 0x23, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF2, 0x08, 0xC0, 0x5B, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, ++0x1F, 0x04, 0x6C, 0x00, 0x70, 0x21, 0xC0, 0x04, 0x02, 0x1F, 0x02, 0x7C, 0x00, ++0x31, 0x01, 0xC0, 0x04, 0x00, 0x13, 0x40, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x07, ++0x08, 0x13, 0x0A, 0x7C, 0x04, 0x30, 0xC1, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0xDC, 0x0E, 0x7D, 0x06, 0xF4, 0x41, ++0x10, 0x05, 0x80, 0x5E, 0x00, 0x5D, 0x60, 0xF4, 0x6D, 0x10, 0x37, 0x40, 0x1C, ++0x00, 0x51, 0x00, 0x6C, 0x01, 0xD0, 0x05, 0x40, 0x17, 0x00, 0x75, 0x40, 0xF4, ++0x01, 0x10, 0x17, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xA0, 0xE2, 0x00, 0xCD, 0x41, 0x24, 0x17, 0x80, 0x0C, 0x58, 0xF0, ++0x20, 0xCD, 0x00, 0x34, 0x0F, 0x90, 0x2C, 0x41, 0x74, 0x04, 0xC1, 0x00, 0x04, ++0x03, 0xD1, 0x0D, 0x40, 0x33, 0x00, 0x81, 0x10, 0x34, 0x03, 0x10, 0x2C, 0x40, ++0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, 0x29, ++0x80, 0xED, 0x80, 0xB4, 0x07, 0x94, 0xDE, 0x40, 0x28, 0x20, 0xEC, 0x08, 0x34, ++0x03, 0x90, 0x2C, 0x50, 0x20, 0x04, 0xF1, 0x45, 0xA4, 0x23, 0xD0, 0x0E, 0x40, ++0x3B, 0x00, 0x25, 0x00, 0x34, 0x03, 0x12, 0x0A, 0x40, 0x13, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x79, 0x00, 0xEF, 0x01, 0xAC, ++0x05, 0xB1, 0x5E, 0x41, 0x78, 0x00, 0xEF, 0x05, 0xBC, 0x05, 0xB0, 0x1A, 0xC0, ++0x78, 0x00, 0xF3, 0x43, 0x8C, 0x57, 0xF0, 0x1E, 0xC3, 0x73, 0x00, 0xA3, 0x01, ++0xBC, 0x07, 0x34, 0x12, 0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA8, 0x35, 0x00, 0x5F, 0x40, 0x3C, 0x00, 0x31, 0x4D, 0xC8, ++0x27, 0x08, 0xDF, 0x10, 0x7C, 0x01, 0x70, 0x09, 0xC8, 0x37, 0x40, 0xDF, 0x00, ++0x7C, 0x13, 0xF0, 0xCD, 0xC0, 0xB7, 0x02, 0x1F, 0x00, 0x7C, 0x03, 0xB4, 0x09, ++0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, ++0x6D, 0x00, 0xFF, 0x01, 0xCC, 0x06, 0xF0, 0x9F, 0xC0, 0x5F, 0x02, 0xFF, 0x09, ++0xCC, 0x27, 0xF0, 0x1B, 0xC0, 0x7D, 0x00, 0xEF, 0x41, 0xCC, 0x87, 0x70, 0x1F, ++0xC0, 0xFC, 0x00, 0xE3, 0x01, 0xCC, 0x07, 0x30, 0x1F, 0xC8, 0x1B, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x29, 0x20, 0xFD, 0x00, ++0xAC, 0x1A, 0xD2, 0xCE, 0x40, 0x2B, 0x00, 0xFD, 0x00, 0x84, 0x04, 0xD0, 0x0F, ++0xC0, 0x20, 0x01, 0xED, 0x25, 0xC4, 0x07, 0x50, 0x0E, 0xC1, 0x3A, 0x20, 0x6B, ++0x00, 0x94, 0x03, 0xB0, 0x0A, 0x40, 0x57, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x08, 0x00, 0x29, 0x00, 0xED, 0x00, 0xB4, 0x02, 0xD2, 0x0E, ++0x60, 0x0B, 0x20, 0xED, 0x00, 0x96, 0x03, 0xD0, 0x02, 0x40, 0x1B, 0x80, 0xFD, ++0x05, 0xC4, 0x03, 0x11, 0x8E, 0x40, 0x38, 0x00, 0xF1, 0x00, 0x84, 0x43, 0x10, ++0x2E, 0x40, 0x23, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x28, 0xF1, 0x04, 0x8D, 0x13, 0x34, 0x02, 0xD0, 0x2D, 0x40, 0x23, 0x00, 0xC9, ++0x03, 0x54, 0x04, 0xD0, 0x00, 0x40, 0xC0, 0x10, 0xCD, 0x04, 0x04, 0x03, 0x58, ++0x3C, 0x41, 0x32, 0x00, 0x59, 0x00, 0x14, 0x07, 0x91, 0x0C, 0x40, 0x0B, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x25, 0x10, 0x1F, ++0x12, 0x7C, 0x02, 0xF0, 0x2F, 0xC0, 0x27, 0x00, 0xFF, 0x05, 0x5C, 0x46, 0xF0, ++0x05, 0xC0, 0x07, 0x01, 0xDF, 0x07, 0xCD, 0x03, 0x32, 0x0F, 0x40, 0x3C, 0x00, ++0x53, 0x00, 0x4C, 0x07, 0x30, 0x25, 0xC0, 0x57, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x27, 0x02, 0x9F, 0x00, 0x64, 0x08, 0xF0, ++0xCD, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0x6C, 0x02, 0xF0, 0x05, 0xC0, 0x87, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xE0, 0x0D, 0xC0, 0x37, 0x00, 0x5F, 0x00, 0x7C, 0x03, ++0xF0, 0x01, 0xC2, 0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x89, 0x09, 0x3F, 0x10, 0x2F, 0x00, 0xCC, 0x80, 0xF0, 0x0F, 0xC0, 0x08, 0x00, ++0xF3, 0x10, 0xFC, 0x20, 0x30, 0x03, 0xC0, 0x0F, 0x04, 0xFF, 0x00, 0xBC, 0x03, ++0x10, 0x0F, 0xC0, 0x3F, 0x10, 0xFF, 0x01, 0x4C, 0x65, 0xF0, 0x97, 0xC0, 0x07, ++0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0xB6, 0x00, ++0x1D, 0x21, 0x54, 0x04, 0xD0, 0x0D, 0x40, 0xC4, 0x00, 0xD1, 0x40, 0x74, 0x00, ++0x10, 0x21, 0x40, 0xC6, 0x01, 0xDD, 0x00, 0x74, 0x03, 0xB0, 0x0D, 0xC0, 0x35, ++0x00, 0xDD, 0x0B, 0x54, 0x00, 0xD0, 0x2D, 0x44, 0x87, 0x02, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x24, 0x14, 0x1D, 0x01, 0x46, 0x06, ++0xD0, 0x0D, 0x40, 0x44, 0x00, 0xD1, 0x00, 0x74, 0x03, 0x10, 0x13, 0x41, 0x4F, ++0x80, 0xDD, 0x00, 0xF4, 0x03, 0x50, 0x0F, 0x40, 0x3F, 0x00, 0x9D, 0x10, 0x44, ++0x03, 0x90, 0x25, 0x40, 0x07, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x22, 0x20, 0x00, 0x8D, 0x80, 0x14, 0x00, 0xD8, 0x0C, 0x40, 0x20, ++0x00, 0xC1, 0x22, 0x34, 0x40, 0x14, 0x00, 0x40, 0x03, 0x00, 0xCD, 0x04, 0x34, ++0x13, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x8D, 0x00, 0x14, 0x07, 0xD0, 0x00, 0x40, ++0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB8, 0x06, ++0x00, 0x1F, 0x00, 0x4C, 0x02, 0xF0, 0x0F, 0xC0, 0x04, 0x00, 0xF1, 0x02, 0x74, ++0x13, 0x30, 0x01, 0xC0, 0x87, 0x02, 0xFF, 0x10, 0xFC, 0x53, 0x70, 0x0E, 0xC0, ++0x3B, 0x00, 0x9F, 0x00, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0x07, 0x60, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xB0, 0x1F, 0x00, 0xBF, 0x80, 0xF8, ++0x00, 0xF0, 0x0F, 0xC2, 0x0F, 0x00, 0xFF, 0x20, 0x7C, 0x00, 0xF0, 0x03, 0xC0, ++0x0E, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xB1, 0x0F, 0xC0, 0x3D, 0x00, 0xBF, 0x00, ++0xFC, 0x83, 0xF0, 0x0F, 0xC0, 0x17, 0x61, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xFF, 0x09, 0xFC, 0x02, 0x30, 0x4B, 0xC1, ++0x3F, 0x13, 0xFF, 0x00, 0xCC, 0x13, 0x70, 0x83, 0xC0, 0x3C, 0x40, 0xF3, 0x00, ++0xBC, 0x06, 0xB0, 0x0F, 0xC0, 0x2C, 0x17, 0x3B, 0x0C, 0xCC, 0x00, 0xB0, 0x03, ++0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, ++0x37, 0x01, 0xCD, 0x04, 0x74, 0xEA, 0x10, 0x69, 0xC8, 0xBD, 0x22, 0xFD, 0xDE, ++0xD4, 0x2F, 0x10, 0x01, 0x40, 0xFC, 0x00, 0xD1, 0x02, 0x44, 0x87, 0x10, 0x1F, ++0x40, 0xA5, 0x01, 0x11, 0x0E, 0x44, 0x08, 0x10, 0x01, 0x40, 0x0F, 0x60, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x33, 0x04, 0xCD, 0x00, ++0x34, 0x10, 0x50, 0x00, 0x41, 0x33, 0x09, 0xCD, 0x44, 0x14, 0x03, 0x10, 0x50, ++0x60, 0xB1, 0x00, 0xC5, 0x02, 0x14, 0x82, 0x90, 0x0D, 0x60, 0x34, 0x01, 0xC9, ++0x00, 0x04, 0x08, 0x12, 0x00, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA0, 0x35, 0x00, 0xDD, 0x04, 0x36, 0x0E, 0x54, 0x19, ++0x42, 0x37, 0x00, 0xDD, 0x00, 0x44, 0x03, 0x10, 0x12, 0x40, 0x35, 0x00, 0xD5, ++0x20, 0x55, 0x03, 0x10, 0x0F, 0x40, 0x55, 0x00, 0xC1, 0x18, 0x45, 0x63, 0x10, ++0x11, 0x40, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xA8, 0x37, 0x00, 0xDD, 0x00, 0x7C, 0x06, 0x70, 0x31, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x4C, 0x03, 0x30, 0x11, 0x40, 0x35, 0x00, 0xD6, 0x00, 0x7C, 0x02, 0xB0, ++0x0D, 0xC0, 0x64, 0x80, 0x1B, 0x03, 0x4E, 0x07, 0x30, 0x19, 0xC0, 0x2B, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x80, 0xFD, 0x20, 0xFF, ++0x81, 0x7E, 0x02, 0xB0, 0x01, 0xC4, 0x3D, 0x00, 0xDF, 0x00, 0xBC, 0x43, 0xB0, ++0x0B, 0xC0, 0x3E, 0x10, 0xFA, 0x00, 0xEC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, ++0xFF, 0x80, 0x7C, 0x01, 0x70, 0x03, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xDF, 0x00, 0x4C, 0x08, 0x38, ++0x21, 0xC0, 0x34, 0x08, 0xD7, 0xC0, 0x4C, 0x03, 0x70, 0x01, 0xD1, 0x30, 0x00, ++0xDF, 0x84, 0x4D, 0x42, 0x32, 0x4D, 0xC0, 0x27, 0x00, 0x1B, 0x12, 0x3C, 0x02, ++0x30, 0x09, 0xC0, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1B, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0x6C, 0x82, 0x10, 0x19, 0x41, 0x3C, 0x00, ++0xF1, 0x00, 0xC4, 0x4B, 0xD0, 0x19, 0x40, 0x3C, 0x01, 0xE7, 0x01, 0x04, 0x46, ++0x12, 0x3F, 0xC0, 0x11, 0x00, 0xDD, 0x00, 0x74, 0x1B, 0x10, 0xB9, 0x41, 0x4F, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x32, 0x00, ++0xCD, 0x00, 0x24, 0x00, 0x10, 0x58, 0x40, 0x30, 0x00, 0xD5, 0x00, 0x04, 0x0B, ++0x50, 0x20, 0x40, 0x32, 0x00, 0xC8, 0x2B, 0x04, 0x0A, 0x12, 0x0D, 0x44, 0x23, ++0x10, 0x09, 0x08, 0x34, 0x40, 0x90, 0x18, 0x40, 0x0E, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x7A, 0x00, 0xED, 0x01, 0xA4, 0x05, ++0x10, 0x1E, 0x40, 0x78, 0x00, 0xE1, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x41, 0x78, ++0x80, 0xE5, 0x01, 0xC4, 0x07, 0x10, 0x1E, 0x40, 0x79, 0x00, 0xED, 0x01, 0xB4, ++0x15, 0x90, 0x12, 0x40, 0x37, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x10, 0x32, 0x00, 0xCE, 0x40, 0x2C, 0x21, 0x10, 0x84, 0xC0, 0x34, ++0x02, 0xC7, 0x08, 0x06, 0x03, 0x70, 0x05, 0xC0, 0x32, 0x00, 0xCF, 0x40, 0x0C, ++0x02, 0x30, 0x0C, 0xC1, 0x23, 0x00, 0x0B, 0x04, 0x3C, 0x02, 0xB0, 0x0C, 0xC0, ++0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x3D, ++0x20, 0xFF, 0x80, 0xDD, 0x81, 0xF0, 0x8F, 0xC0, 0x3F, 0x00, 0xFF, 0x20, 0xFE, ++0x03, 0xF0, 0x0F, 0xC0, 0xBD, 0x04, 0xEF, 0x00, 0xFC, 0x03, 0xF5, 0x0F, 0xC0, ++0x1F, 0x00, 0xDF, 0x00, 0x7C, 0x13, 0x72, 0x0F, 0xC0, 0x0B, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x37, 0x20, 0xDF, 0x00, 0x7C, ++0x03, 0x70, 0x0D, 0xC0, 0x37, 0x01, 0xDF, 0x04, 0x7C, 0x13, 0xD1, 0x11, 0xD0, ++0x30, 0x01, 0xD3, 0x08, 0x4C, 0x06, 0x30, 0x5D, 0xC8, 0x20, 0x00, 0x17, 0x00, ++0x5C, 0x00, 0xB4, 0x0D, 0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0x88, 0x38, 0x10, 0xED, 0x20, 0xB6, 0x03, 0xD0, 0x0E, 0x40, ++0xBB, 0x03, 0xED, 0x28, 0xB4, 0x23, 0xD0, 0x0B, 0x40, 0x38, 0x00, 0xE1, 0x00, ++0xAC, 0x02, 0x50, 0xAE, 0x40, 0x38, 0x00, 0xE1, 0x40, 0xB4, 0x01, 0x10, 0x06, ++0x40, 0x4C, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, ++0x79, 0x80, 0xED, 0x81, 0x94, 0x07, 0xD8, 0x16, 0x40, 0x7B, 0x00, 0xED, 0x09, ++0xB4, 0x27, 0xD0, 0x16, 0x49, 0x78, 0x01, 0xE1, 0x05, 0x94, 0x06, 0x90, 0x5E, ++0x58, 0x6C, 0x40, 0x21, 0x03, 0x34, 0x06, 0x50, 0x1C, 0x40, 0x10, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x23, 0x80, 0x8D, 0x00, ++0x34, 0x07, 0xD8, 0xAC, 0x40, 0x33, 0x10, 0xCD, 0x00, 0x34, 0x03, 0xD0, 0x2C, ++0x40, 0x30, 0x80, 0xC1, 0x00, 0x34, 0x86, 0xD0, 0x0C, 0x40, 0x10, 0x00, 0xC1, ++0x10, 0x74, 0x2F, 0x50, 0x2D, 0x40, 0x58, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x17, 0xA8, 0x17, 0x01, 0x5F, 0x00, 0xFC, 0x0D, 0x72, 0x17, ++0xCA, 0x17, 0x08, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0x48, 0x14, 0x00, 0x43, ++0x00, 0x54, 0x01, 0xB0, 0x05, 0xC4, 0x1C, 0x01, 0x73, 0x03, 0xDC, 0x2D, 0x70, ++0x47, 0xC0, 0x5C, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x00, 0x05, 0x20, 0x1F, 0x00, 0x7C, 0x60, 0xF8, 0x01, 0xC1, 0x07, 0x00, 0x0F, ++0x00, 0x7C, 0x08, 0xF0, 0x41, 0xC8, 0x03, 0x40, 0x1F, 0x00, 0x64, 0x20, 0x73, ++0x01, 0xC0, 0x07, 0x20, 0x19, 0x02, 0x7C, 0x00, 0xB0, 0x21, 0xD0, 0x4B, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x9F, ++0x00, 0x78, 0x02, 0xF0, 0x89, 0xC2, 0x27, 0x00, 0x9B, 0x00, 0x4C, 0x06, 0xF0, ++0x09, 0xC0, 0x25, 0x01, 0x93, 0x09, 0x5C, 0x02, 0xF0, 0x99, 0xC0, 0x23, 0x00, ++0x97, 0x28, 0x44, 0x82, 0x31, 0x09, 0xC1, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xD0, ++0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x44, 0x0E, 0xD0, 0x29, 0x40, 0x27, 0x00, ++0x91, 0x03, 0x44, 0x02, 0xD0, 0x39, 0x40, 0x27, 0x00, 0x91, 0x07, 0x44, 0x0A, ++0x10, 0x29, 0x51, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1C, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x70, 0x02, 0xD0, 0x0D, 0x40, 0x27, 0x00, ++0x9D, 0x00, 0x44, 0x1A, 0xD0, 0x29, 0x00, 0x27, 0x40, 0x91, 0x02, 0x54, 0x02, ++0xD8, 0x09, 0x41, 0x27, 0x00, 0x85, 0x00, 0x54, 0x02, 0x10, 0x0D, 0x40, 0x70, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x20, 0x00, ++0x8D, 0x00, 0x34, 0x52, 0xD0, 0x4C, 0x41, 0x23, 0x02, 0x8D, 0x08, 0x04, 0x82, ++0xD0, 0xC8, 0x40, 0x23, 0x00, 0x81, 0x14, 0x04, 0x03, 0xD9, 0x48, 0x40, 0x23, ++0x00, 0x81, 0x08, 0x14, 0x82, 0x14, 0x48, 0x41, 0x50, 0xA0, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x40, 0x7C, 0x10, ++0xF0, 0x41, 0xC0, 0x87, 0x05, 0x1B, 0x16, 0x4C, 0x50, 0xF0, 0x31, 0xC0, 0x05, ++0x05, 0x03, 0x0E, 0x5C, 0x00, 0xF0, 0x11, 0xC0, 0x87, 0x05, 0x17, 0x16, 0x5D, ++0x51, 0x30, 0x41, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x19, 0xB8, 0x2F, 0x0D, 0xBF, 0x34, 0xFC, 0x52, 0xF0, 0x4B, 0xC1, 0x27, ++0x01, 0x9F, 0x04, 0x7D, 0x82, 0xF0, 0xCB, 0x80, 0x27, 0x00, 0x9F, 0x01, 0xBC, ++0x02, 0xF0, 0x88, 0xC0, 0x2F, 0x04, 0xBF, 0x04, 0xEC, 0x52, 0xF8, 0x4B, 0xC1, ++0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0xA7, ++0x00, 0xDF, 0x02, 0x54, 0x1E, 0xF0, 0x2B, 0xC0, 0x25, 0x01, 0x9F, 0x54, 0xFC, ++0x12, 0x30, 0x8B, 0xC0, 0x2E, 0x05, 0xB3, 0x01, 0xCC, 0x02, 0xF0, 0x0B, 0xC0, ++0xA4, 0x00, 0xBF, 0x00, 0xCC, 0x02, 0x32, 0x0B, 0xC0, 0x60, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, 0x03, 0x20, 0x1D, 0x01, 0x6E, ++0x08, 0x10, 0x85, 0x40, 0x00, 0x05, 0x0D, 0x04, 0x74, 0x80, 0x10, 0x01, 0x50, ++0x84, 0x00, 0x11, 0x00, 0x44, 0x00, 0xD0, 0x01, 0x40, 0x54, 0x01, 0x1D, 0x40, ++0x44, 0x00, 0xBA, 0x05, 0xC0, 0x72, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0xA0, 0x21, 0x81, 0x9D, 0x00, 0x04, 0xB2, 0x58, 0x48, 0x40, ++0x21, 0x02, 0x8D, 0x14, 0x34, 0x0A, 0x12, 0x48, 0x44, 0x20, 0x00, 0x81, 0x22, ++0x04, 0x02, 0xD0, 0x08, 0x50, 0x21, 0x01, 0x8D, 0x00, 0x14, 0x02, 0x10, 0x08, ++0x40, 0x48, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, ++0x25, 0x80, 0x9D, 0x00, 0x64, 0x62, 0x58, 0x0D, 0x40, 0x24, 0x00, 0x9C, 0x00, ++0x70, 0x02, 0x00, 0x0C, 0x60, 0x24, 0x40, 0x91, 0x00, 0x45, 0x02, 0xD0, 0x0D, ++0x40, 0x25, 0x22, 0x9D, 0x80, 0x54, 0x2A, 0x90, 0x09, 0x40, 0x62, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x67, 0x00, 0x8D, 0x40, ++0x44, 0x06, 0x68, 0x09, 0xC0, 0x25, 0x00, 0x9F, 0x00, 0x3C, 0x02, 0x30, 0x19, ++0xC4, 0x26, 0x00, 0x93, 0x00, 0x4C, 0x02, 0xF0, 0x09, 0x40, 0x25, 0x00, 0x9D, ++0x0F, 0x5C, 0x06, 0x30, 0x29, 0xC0, 0x14, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x80, 0x24, 0x01, 0x9F, 0x04, 0x3C, 0x02, 0xB0, 0x59, ++0xC0, 0x27, 0x08, 0x9F, 0x00, 0x7E, 0x02, 0xF4, 0x49, 0xC0, 0x21, 0x00, 0x9F, ++0x00, 0x7C, 0x02, 0xF0, 0x08, 0xC0, 0x66, 0x00, 0x9F, 0x11, 0x6D, 0x42, 0xF2, ++0x49, 0xC1, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x05, 0x48, 0x1B, 0x00, 0x7C, 0x00, 0xB8, 0x21, 0xC1, 0x07, 0x00, 0x17, ++0x00, 0x4C, 0x00, 0xF0, 0x01, 0xC0, 0x06, 0x00, 0x13, 0x00, 0x5C, 0x20, 0xF0, ++0x11, 0xC0, 0x05, 0x00, 0x07, 0x22, 0x4C, 0x08, 0xE0, 0x21, 0xD0, 0x40, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x14, 0x00, 0x51, ++0x00, 0x74, 0x01, 0xB8, 0x07, 0x40, 0x17, 0x00, 0x51, 0x00, 0xC4, 0x09, 0xD0, ++0x17, 0xC0, 0x14, 0x00, 0x73, 0x81, 0xC4, 0x29, 0xD0, 0x07, 0x40, 0x14, 0x00, ++0x71, 0x02, 0xC0, 0x45, 0xD1, 0x07, 0x40, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xC1, 0x80, 0x34, 0x03, 0x93, ++0x8D, 0x46, 0x33, 0x00, 0xC5, 0x00, 0x14, 0x17, 0xD0, 0x0C, 0x40, 0x22, 0x30, ++0x59, 0x8F, 0x14, 0x02, 0xC8, 0x1C, 0x40, 0x31, 0x80, 0xC5, 0x03, 0x45, 0x0B, ++0xD0, 0x8D, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x88, 0x78, 0x09, 0xE1, 0x00, 0xB4, 0x13, 0x10, 0x0E, 0x40, 0x7B, 0x03, ++0xE4, 0x0D, 0x91, 0x43, 0xD0, 0x28, 0x40, 0x30, 0x00, 0x01, 0x00, 0xA4, 0x01, ++0xD1, 0x0E, 0x41, 0x78, 0x00, 0xE1, 0x02, 0x84, 0x03, 0xD0, 0x04, 0x40, 0x04, ++0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x79, 0x04, ++0xE3, 0x0D, 0xB4, 0x0F, 0x90, 0x1E, 0xC0, 0x7B, 0x04, 0xE7, 0x15, 0x9C, 0x07, ++0xF0, 0x16, 0xE0, 0x6A, 0x00, 0x2B, 0x01, 0x9C, 0x04, 0xF0, 0x1E, 0xC0, 0x7D, ++0x00, 0x77, 0x01, 0x8D, 0x07, 0xF0, 0x1E, 0xC4, 0x44, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0x35, 0x23, 0xD7, 0x80, 0x7C, 0x43, ++0xF0, 0x0D, 0xC0, 0xB7, 0x01, 0xDB, 0x04, 0x6C, 0x03, 0xF0, 0x01, 0xC2, 0x27, ++0x40, 0x1F, 0x22, 0x5C, 0x01, 0xF0, 0x08, 0xC0, 0x37, 0x08, 0x5F, 0x00, 0x7C, ++0x01, 0xF2, 0x05, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x20, 0x7D, 0x00, 0xF3, 0x19, 0xF8, 0x27, 0x78, 0x9F, 0xC0, 0x7D, ++0x00, 0xF3, 0x01, 0xBC, 0x06, 0x30, 0x1F, 0xC0, 0x6F, 0x00, 0x63, 0x83, 0xCC, ++0x04, 0xF0, 0x17, 0xC4, 0x78, 0x00, 0xB3, 0x01, 0xCE, 0x25, 0x30, 0x1F, 0xC0, ++0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x18, 0x39, ++0x1A, 0xEB, 0x38, 0xB4, 0x03, 0x70, 0x0E, 0x40, 0x38, 0x02, 0xE1, 0x00, 0xB4, ++0x80, 0x10, 0x0E, 0x40, 0x3B, 0x01, 0x65, 0x00, 0x84, 0x08, 0xD0, 0x56, 0x40, ++0x39, 0x00, 0xA1, 0x02, 0x84, 0x28, 0x10, 0x62, 0xC0, 0x56, 0x60, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x04, 0xE1, 0x88, 0xB4, ++0x03, 0xD8, 0x06, 0x45, 0x31, 0x40, 0xE9, 0x00, 0xB4, 0x23, 0x90, 0x06, 0x40, ++0x23, 0x80, 0xA9, 0x00, 0x84, 0x00, 0xD0, 0x4C, 0x40, 0x3E, 0x00, 0x05, 0x08, ++0x05, 0x81, 0x10, 0x06, 0x40, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x20, 0x75, 0x00, 0xD8, 0x00, 0x74, 0x07, 0xDA, 0x19, 0x41, ++0x30, 0x00, 0xC9, 0x00, 0x34, 0x01, 0x93, 0x25, 0x40, 0x27, 0x00, 0x1D, 0x00, ++0x04, 0x20, 0xD0, 0x08, 0x40, 0x71, 0x40, 0x45, 0x01, 0x44, 0x80, 0x18, 0x21, ++0x40, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, ++0x7D, 0x00, 0xF3, 0x01, 0xFC, 0x13, 0xF0, 0x01, 0xC4, 0x3D, 0x00, 0xFB, 0x80, ++0x7E, 0x01, 0xB0, 0x5D, 0xC0, 0x27, 0x00, 0x1B, 0x00, 0x4D, 0x84, 0xF0, 0x09, ++0xC0, 0x7C, 0x04, 0xD5, 0x13, 0x4C, 0x3E, 0x36, 0x29, 0xC0, 0x55, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xDF, 0x40, ++0x7C, 0x43, 0x70, 0x01, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x3E, 0x08, 0x72, 0x01, ++0xC0, 0x37, 0x00, 0x17, 0x02, 0x7C, 0x01, 0xF0, 0x01, 0xC0, 0x37, 0x0C, 0xDA, ++0x04, 0x7C, 0x0A, 0xF0, 0x29, 0x80, 0x06, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x84, 0x08, 0x3F, 0x00, 0xF3, 0x00, 0xCE, 0x83, 0x30, 0x01, ++0xC0, 0x38, 0x00, 0xF3, 0x00, 0xFE, 0x83, 0x32, 0x1F, 0xC1, 0x2C, 0x10, 0x33, ++0x00, 0xCC, 0x14, 0xF0, 0x0B, 0x80, 0x3B, 0x00, 0x63, 0x08, 0xCC, 0x02, 0xF0, ++0x09, 0xD1, 0x10, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, ++0x20, 0x36, 0x00, 0xD1, 0x20, 0x44, 0x03, 0x18, 0x11, 0x40, 0x35, 0x00, 0xD1, ++0x00, 0x74, 0x12, 0x50, 0x21, 0xC0, 0x26, 0x00, 0x1B, 0x23, 0x6C, 0x09, 0xD0, ++0x21, 0x00, 0x37, 0x00, 0x91, 0x02, 0x44, 0x04, 0x10, 0x19, 0x40, 0x14, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x10, 0xD1, ++0x00, 0x44, 0x03, 0x10, 0x19, 0x40, 0x34, 0x40, 0xD1, 0x00, 0x54, 0x10, 0x50, ++0x49, 0x40, 0x24, 0x00, 0x31, 0x11, 0x44, 0x00, 0xD0, 0x15, 0x40, 0x37, 0x00, ++0x91, 0x00, 0x44, 0x86, 0x50, 0x19, 0x40, 0x04, 0x08, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x2A, 0x30, 0x00, 0xC1, 0x00, 0x04, 0x83, 0x10, ++0x08, 0x48, 0x31, 0x00, 0xC1, 0x00, 0x34, 0x00, 0x10, 0x01, 0x40, 0x36, 0x80, ++0x19, 0x00, 0x20, 0x01, 0xD0, 0x44, 0x44, 0x33, 0x00, 0x01, 0x60, 0x04, 0x82, ++0x12, 0x08, 0x40, 0x40, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x30, 0x3C, 0x08, 0xF3, 0x00, 0xC4, 0x03, 0x10, 0x01, 0x40, 0x3C, 0x00, ++0xF3, 0x00, 0x7C, 0x03, 0x70, 0x09, 0xC0, 0x24, 0x00, 0x33, 0x00, 0x4C, 0x00, ++0xF1, 0x4D, 0xC1, 0x37, 0x40, 0x13, 0x00, 0x4D, 0x02, 0x70, 0x01, 0xC0, 0x00, ++0xC4, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xA8, 0x3B, 0x00, ++0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xFF, 0x40, 0xF4, 0x00, ++0xF1, 0x03, 0xC8, 0x2F, 0x00, 0x3E, 0x20, 0xFC, 0x81, 0xF0, 0x01, 0xC0, 0x3F, ++0x20, 0x3F, 0x00, 0xFD, 0x00, 0xE0, 0x03, 0xC0, 0x17, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x3B, 0x04, 0xFF, 0xC0, 0xFC, 0x43, ++0xB2, 0x4F, 0xC0, 0x3D, 0x00, 0xEF, 0x04, 0xEC, 0x23, 0xF1, 0x12, 0xC0, 0x35, ++0x03, 0x7B, 0x01, 0xFC, 0x42, 0xB0, 0x13, 0xC0, 0x2E, 0x00, 0xBB, 0x01, 0xEC, ++0x86, 0x30, 0x03, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x08, 0xFF, 0x00, 0xFD, 0x0C, 0xF4, 0x8F, 0xD0, 0x9F, 0x48, 0xFC, ++0x22, 0xDD, 0x03, 0xC4, 0x3B, 0xD2, 0x19, 0x40, 0xB4, 0x01, 0x91, 0xE1, 0x74, ++0x0E, 0x10, 0x05, 0x43, 0x74, 0x00, 0x91, 0x01, 0x44, 0x03, 0x13, 0x11, 0x48, ++0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, ++0x18, 0xCD, 0x50, 0x34, 0x03, 0xC0, 0x0C, 0x40, 0x32, 0x00, 0xCD, 0x42, 0x24, ++0x13, 0xD2, 0x01, 0x60, 0xB1, 0x00, 0xCD, 0x00, 0x34, 0x02, 0xD0, 0x41, 0x40, ++0x22, 0x00, 0x4D, 0x00, 0x74, 0x04, 0x10, 0x00, 0x40, 0x47, 0x80, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x34, 0x08, 0xDD, 0x00, 0x74, ++0x83, 0xD0, 0x0D, 0x40, 0x36, 0x08, 0xDD, 0x00, 0x44, 0x83, 0xD0, 0x11, 0x48, ++0x34, 0x08, 0x99, 0x00, 0x74, 0x07, 0x51, 0x81, 0x41, 0x34, 0x00, 0xD5, 0x08, ++0x56, 0x91, 0x10, 0x19, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA8, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xA0, 0x0D, 0xC0, ++0x36, 0x20, 0xDF, 0x20, 0x6C, 0x03, 0xF2, 0x38, 0xC8, 0x35, 0x30, 0xDB, 0x08, ++0x7C, 0x02, 0xF0, 0x35, 0x86, 0x62, 0x00, 0xCF, 0x03, 0x3C, 0x07, 0x30, 0x11, ++0xC0, 0x03, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, ++0x3D, 0x24, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3C, 0x00, 0xFF, 0x00, ++0xFC, 0x03, 0xE0, 0x0B, 0x80, 0x36, 0x00, 0xB5, 0x00, 0xBC, 0x43, 0xB0, 0x17, ++0xC0, 0x7F, 0x0A, 0xFB, 0x00, 0xEC, 0x01, 0xF2, 0x0B, 0xC0, 0x1F, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xD7, 0x04, ++0x7C, 0x03, 0x71, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x5C, 0x03, 0xF0, 0x21, ++0xC0, 0x35, 0x00, 0xD7, 0x00, 0x7C, 0x22, 0xF0, 0x21, 0xC0, 0x27, 0x00, 0x5F, ++0x00, 0x7C, 0x11, 0x30, 0x81, 0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0xA0, 0x3C, 0x00, 0xF1, 0x82, 0xF4, 0x8F, 0x18, 0x5E, ++0x44, 0xFF, 0x24, 0xED, 0x02, 0xC4, 0x03, 0xD2, 0x81, 0x41, 0x7C, 0x00, 0x9B, ++0x00, 0x74, 0x0F, 0xC0, 0x00, 0x40, 0x37, 0x00, 0xDC, 0x09, 0x40, 0x09, 0x10, ++0x09, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++0xA0, 0xF2, 0x00, 0xC5, 0x01, 0x34, 0x17, 0x51, 0x0C, 0x40, 0xB2, 0x04, 0xCD, ++0x10, 0x14, 0x03, 0xD0, 0x00, 0x40, 0x37, 0x02, 0x05, 0x00, 0x34, 0x0B, 0xC0, ++0x00, 0x4A, 0x33, 0x10, 0x4C, 0x01, 0x14, 0x03, 0x10, 0x00, 0x41, 0x1F, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x78, 0x06, 0xE1, ++0xB1, 0xB4, 0x07, 0x10, 0x1E, 0x40, 0x7B, 0x20, 0xED, 0x89, 0x94, 0x07, 0xD0, ++0x1E, 0x42, 0x7A, 0x01, 0xA9, 0x81, 0xB4, 0x87, 0xD0, 0x16, 0x40, 0x6B, 0x00, ++0x6D, 0x31, 0xC0, 0x07, 0x10, 0x12, 0x40, 0x1B, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xC7, 0x08, 0x3C, 0x43, 0x50, ++0x0C, 0xC0, 0x33, 0x00, 0xCF, 0x20, 0x1C, 0x03, 0xF0, 0x40, 0xC0, 0x73, 0x81, ++0xC7, 0x00, 0x3C, 0x32, 0xF0, 0x40, 0xC0, 0x33, 0x00, 0x4F, 0x22, 0x1C, 0x12, ++0x30, 0x84, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xB8, 0x3D, 0x00, 0xFF, 0x40, 0xBC, 0x2B, 0xB1, 0x0F, 0xC0, 0x3F, 0x00, ++0xFF, 0x90, 0xE4, 0x03, 0xF0, 0x0B, 0xC0, 0x3D, 0x00, 0xB7, 0x00, 0xFC, 0x63, ++0xF0, 0x07, 0xC0, 0x2F, 0x02, 0x6F, 0x00, 0x1C, 0x03, 0xF0, 0x8D, 0xC2, 0x0B, ++0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x73, 0x01, ++0xDB, 0x0A, 0x7C, 0x97, 0x39, 0x6D, 0xC1, 0xB7, 0x01, 0xDF, 0x00, 0x5C, 0x4B, ++0x71, 0x18, 0xC0, 0x36, 0x20, 0x9F, 0x20, 0x7C, 0x02, 0xF0, 0x05, 0xC0, 0x32, ++0x00, 0x5B, 0x00, 0x7C, 0x03, 0x36, 0x05, 0xC0, 0x57, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0xB9, 0x05, 0xE1, 0x54, 0xB4, 0x13, ++0x18, 0x2E, 0x60, 0xBB, 0x03, 0xED, 0x04, 0x04, 0x03, 0x10, 0x0E, 0x60, 0x38, ++0x01, 0xA7, 0x00, 0xB4, 0x13, 0xD0, 0x07, 0x42, 0x28, 0x10, 0x61, 0x20, 0xB4, ++0x01, 0x10, 0x0E, 0x40, 0x4B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x00, 0x79, 0x00, 0xE9, 0x05, 0x34, 0x27, 0x12, 0x5E, 0x40, 0x7B, ++0x00, 0xCD, 0x05, 0x94, 0x27, 0x52, 0x1A, 0x64, 0x7A, 0x02, 0xED, 0x01, 0xB4, ++0x0E, 0xD0, 0x1E, 0x40, 0x7A, 0x20, 0x6D, 0x21, 0xF4, 0x07, 0x10, 0x16, 0x40, ++0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x33, ++0x08, 0xC1, 0x00, 0x34, 0x83, 0x10, 0x0C, 0x40, 0x33, 0x10, 0xCD, 0x20, 0x04, ++0x03, 0x10, 0x0C, 0x40, 0x32, 0x00, 0x85, 0x00, 0x34, 0x03, 0xD0, 0x25, 0x41, ++0x20, 0x00, 0x45, 0x08, 0x34, 0x8F, 0x10, 0xEC, 0x40, 0x4B, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA0, 0x15, 0x00, 0x5B, 0x20, 0x7C, ++0x01, 0x35, 0x05, 0xC0, 0x17, 0x00, 0x5F, 0x00, 0x5C, 0x01, 0x70, 0x27, 0xC2, ++0x16, 0x00, 0x7F, 0x22, 0x7C, 0x01, 0xF8, 0x27, 0xD3, 0x16, 0x20, 0x6F, 0x20, ++0xF4, 0x0D, 0x30, 0x17, 0xC2, 0x5F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x02, 0x7C, 0x08, 0xF0, 0x21, 0xC4, ++0x87, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x21, 0xC0, 0x05, 0x00, 0x17, 0x04, ++0x7C, 0x08, 0xF2, 0x01, 0xC0, 0x87, 0x00, 0x1A, 0x02, 0x74, 0x60, 0xF0, 0x01, ++0xC0, 0x4B, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++0x27, 0x02, 0x9F, 0x09, 0x7C, 0x06, 0xF0, 0x19, 0xC0, 0x67, 0x80, 0x83, 0x08, ++0x5C, 0x02, 0x30, 0x99, 0xC3, 0x23, 0x00, 0x92, 0x00, 0x0C, 0x86, 0x70, 0x09, ++0xC0, 0x21, 0x01, 0x93, 0x04, 0x5C, 0x06, 0x32, 0x08, 0xC2, 0x40, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xE6, 0x00, 0x9D, 0x03, ++0x74, 0x02, 0xD0, 0xA9, 0x41, 0xE3, 0x04, 0x9B, 0x01, 0x44, 0x02, 0x10, 0x09, ++0x40, 0x27, 0x00, 0x81, 0x00, 0xC4, 0x0A, 0xB0, 0x09, 0x40, 0xA4, 0x00, 0x95, ++0x00, 0x04, 0x0E, 0x10, 0x09, 0x40, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x88, 0x24, 0x04, 0x9D, 0x10, 0x74, 0x22, 0xD0, 0x09, ++0x40, 0x27, 0x01, 0x91, 0x00, 0x14, 0x02, 0x14, 0x0D, 0x41, 0x27, 0x41, 0x95, ++0x00, 0x54, 0x12, 0x50, 0x09, 0x40, 0xA5, 0x00, 0x91, 0x00, 0x54, 0x12, 0x14, ++0x89, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x20, 0x20, 0x05, 0x8D, 0x34, 0x36, 0x52, 0xD2, 0x08, 0x40, 0x23, 0x40, 0x89, ++0xC0, 0x04, 0x22, 0x10, 0x08, 0x40, 0xA3, 0x00, 0x95, 0x02, 0x14, 0x03, 0x90, ++0x88, 0x40, 0x20, 0x05, 0x94, 0x00, 0x44, 0x06, 0x10, 0x48, 0x41, 0x41, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x01, 0x1F, ++0x24, 0x7C, 0x91, 0xF0, 0x41, 0xC1, 0x07, 0x05, 0x11, 0x54, 0x5C, 0x58, 0x30, ++0x01, 0xCA, 0x07, 0x05, 0x17, 0x00, 0x5D, 0x04, 0x70, 0x21, 0xC0, 0x05, 0x01, ++0x53, 0x00, 0x5C, 0x00, 0x30, 0x45, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x27, 0x00, 0x9F, 0x54, 0x7C, 0x02, 0xF0, ++0x09, 0xC0, 0x27, 0x00, 0x97, 0x00, 0x7C, 0x12, 0xF2, 0x0B, 0xC0, 0x67, 0x00, ++0xBB, 0x01, 0xEC, 0x0A, 0x70, 0x4B, 0xC8, 0x2F, 0x00, 0xFF, 0x00, 0xAE, 0x52, ++0xF4, 0x0B, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x19, 0xA8, 0x6F, 0x04, 0xBF, 0x36, 0xFC, 0x42, 0xF0, 0x0A, 0xC0, 0x2C, 0x00, ++0xBF, 0x90, 0x7F, 0x32, 0xF0, 0x0F, 0xC0, 0xAF, 0x04, 0x9F, 0x02, 0xCD, 0x86, ++0x34, 0x89, 0xC0, 0x2F, 0x00, 0xAF, 0x00, 0xFC, 0x02, 0x30, 0x0B, 0xC0, 0x64, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, 0x07, 0x00, ++0x1D, 0x02, 0x74, 0x08, 0xD0, 0xA1, 0x52, 0x84, 0x02, 0x1D, 0x02, 0x44, 0x00, ++0x70, 0x05, 0x40, 0xC7, 0x00, 0x1D, 0x01, 0x44, 0x88, 0x10, 0x05, 0x48, 0x04, ++0x00, 0x1D, 0x00, 0x74, 0x00, 0x10, 0x01, 0x40, 0x70, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, 0x04, 0x34, 0x02, ++0xD0, 0x08, 0x40, 0x20, 0x00, 0x8D, 0x00, 0x14, 0x1A, 0xD0, 0x08, 0x62, 0x23, ++0x00, 0x8D, 0x00, 0x04, 0x0A, 0x10, 0x48, 0x40, 0x22, 0x00, 0x8D, 0x00, 0x74, ++0x03, 0x10, 0x08, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x25, 0x00, 0x9D, 0xA0, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x24, ++0x20, 0x9D, 0x00, 0x44, 0x02, 0x50, 0x09, 0x48, 0x27, 0x00, 0x8D, 0x00, 0x44, ++0x02, 0x11, 0x89, 0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x29, 0x40, ++0x60, 0x28, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, ++0x10, 0x9F, 0x00, 0x78, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x08, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0x40, 0x2F, 0x00, 0xBE, 0x07, 0x4C, 0x02, 0x31, 0x39, 0xC2, ++0x27, 0x00, 0x9F, 0x00, 0x3C, 0x16, 0x20, 0x09, 0xD0, 0x14, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x24, 0x00, 0x9F, 0x80, 0x7C, ++0x42, 0xF0, 0x08, 0xE0, 0x27, 0x0C, 0x8F, 0x10, 0x7D, 0x02, 0xF0, 0x39, 0xC0, ++0x27, 0x00, 0x9F, 0x02, 0x7C, 0x4A, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x23, ++0x7C, 0x16, 0xF4, 0x59, 0xC0, 0x53, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x08, 0x05, 0x01, 0x1F, 0x00, 0x4C, 0x20, 0x30, 0x41, 0xC0, ++0x04, 0x00, 0x12, 0x00, 0x5C, 0x80, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x13, 0x02, ++0x7C, 0x00, 0xF0, 0x21, 0xC0, 0x07, 0x24, 0x1F, 0x22, 0x5C, 0x00, 0x30, 0x41, ++0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, ++0xDC, 0x04, 0x7D, 0x00, 0xC4, 0x09, 0xF0, 0x17, 0x44, 0xDD, 0x4C, 0x71, 0x03, ++0x44, 0x01, 0x10, 0x77, 0xC0, 0x55, 0x00, 0x5B, 0x00, 0xB4, 0x11, 0xD0, 0x05, ++0x40, 0x5F, 0x00, 0x7D, 0x03, 0xC4, 0x01, 0x50, 0x36, 0x40, 0x50, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0xE2, 0x00, 0xCD, 0x45, ++0x14, 0x0A, 0x10, 0x24, 0x40, 0x70, 0x80, 0x81, 0x00, 0x14, 0x03, 0x10, 0x48, ++0x40, 0x33, 0x00, 0xC5, 0x00, 0x34, 0x02, 0xD0, 0x0D, 0x42, 0xA3, 0x00, 0x8D, ++0x12, 0x14, 0x03, 0x10, 0x8C, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x00, 0xED, 0x03, 0x94, 0x05, 0x51, 0x22, ++0x40, 0x61, 0x00, 0x81, 0x10, 0x84, 0x17, 0x14, 0x0A, 0x40, 0xFD, 0x01, 0xED, ++0x04, 0xB4, 0x02, 0xD0, 0x4E, 0x00, 0x2B, 0x04, 0xBD, 0x11, 0x84, 0x03, 0x52, ++0x00, 0x40, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x10, 0x68, 0x00, 0xCF, 0x01, 0x15, 0x04, 0x10, 0x16, 0xE0, 0x78, 0x88, 0xA3, ++0x01, 0xDC, 0x47, 0x30, 0x1E, 0xE8, 0x7F, 0x01, 0xE7, 0x03, 0xBC, 0x06, 0xF0, ++0x1E, 0xC0, 0x6B, 0x00, 0xAF, 0x41, 0xDC, 0x07, 0x32, 0x1E, 0xC0, 0x50, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0x5F, ++0x00, 0x6C, 0x01, 0xF0, 0x01, 0xC2, 0x27, 0x00, 0x9F, 0x20, 0x7E, 0x23, 0xF0, ++0x09, 0xC0, 0x37, 0x12, 0xDB, 0x00, 0x7C, 0x02, 0xF0, 0x8D, 0xC0, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xD0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x6F, 0x40, 0x73, 0x81, 0xE4, 0x04, 0xF1, ++0x17, 0xC0, 0x78, 0x00, 0xF3, 0x01, 0xFC, 0x07, 0xF0, 0x1B, 0xC0, 0x6F, 0x80, ++0xE7, 0x09, 0xCC, 0x07, 0xF0, 0x1F, 0xC2, 0x7C, 0x00, 0xFF, 0x01, 0xFC, 0x07, ++0x30, 0x17, 0xC0, 0x08, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x88, 0x29, 0x00, 0x61, 0x00, 0x84, 0x10, 0x70, 0x02, 0x40, 0x98, 0x02, ++0xE1, 0x80, 0xB4, 0x03, 0xD0, 0x0A, 0x40, 0x2B, 0x81, 0xE1, 0x00, 0x84, 0x02, ++0xD0, 0x8E, 0xC0, 0x3A, 0x00, 0xED, 0x00, 0xF4, 0x23, 0x18, 0x26, 0x40, 0x54, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x21, 0x00, ++0xE1, 0x00, 0x84, 0x00, 0xD1, 0x08, 0x40, 0x38, 0x00, 0xE1, 0x08, 0xB4, 0x03, ++0xD0, 0x0E, 0x41, 0x2B, 0x30, 0xF5, 0x01, 0x84, 0x03, 0xD0, 0x0F, 0x40, 0x28, ++0x04, 0xAD, 0x00, 0xB4, 0x02, 0x50, 0x26, 0x40, 0x20, 0x01, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x13, 0x00, 0x11, 0x40, 0x04, 0x01, ++0x50, 0x08, 0x4C, 0x10, 0x00, 0xC9, 0x00, 0x34, 0x03, 0xD0, 0x24, 0x40, 0x23, ++0x00, 0xC1, 0x04, 0x04, 0x05, 0xD0, 0x2C, 0x40, 0x22, 0x80, 0x4D, 0x00, 0x36, ++0x0C, 0x50, 0x0C, 0x52, 0x18, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0xA8, 0x25, 0x00, 0x93, 0x00, 0x4C, 0x00, 0xF0, 0x05, 0xC4, 0x14, ++0x00, 0x93, 0x00, 0xFC, 0x03, 0xD0, 0x09, 0xC4, 0x37, 0x00, 0xD7, 0x04, 0x4D, ++0x12, 0xF0, 0x3F, 0xC1, 0x24, 0x00, 0x9F, 0x0A, 0x7C, 0x0C, 0x70, 0x29, 0xC0, ++0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, ++0x10, 0x9F, 0x82, 0x5C, 0x01, 0xF0, 0x05, 0xC0, 0x03, 0x00, 0x97, 0x80, 0x7E, ++0x03, 0xF0, 0x09, 0xC0, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC1, ++0xA7, 0x00, 0x9F, 0x00, 0x7C, 0x60, 0xB4, 0x29, 0xC0, 0x27, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x0A, 0x2B, 0x20, 0x93, 0x80, 0xCC, ++0x00, 0x30, 0x07, 0xC0, 0xAF, 0x00, 0xA3, 0x09, 0x8D, 0x03, 0x32, 0x0F, 0xC1, ++0x77, 0x00, 0xFB, 0x00, 0xCC, 0x02, 0x34, 0x0F, 0x00, 0x2E, 0x00, 0xBF, 0x00, ++0xFC, 0x00, 0x30, 0x09, 0xC0, 0x07, 0x2A, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x81, 0x21, 0x36, 0x00, 0x91, 0x11, 0x14, 0x41, 0x51, 0x95, 0x40, ++0xA7, 0x00, 0x91, 0x02, 0x44, 0x03, 0x10, 0x09, 0x44, 0x67, 0x02, 0xDD, 0x00, ++0x04, 0x02, 0x30, 0x0D, 0x40, 0x27, 0x04, 0x9D, 0x00, 0x34, 0x1C, 0x10, 0xBD, ++0x44, 0x87, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, ++0x24, 0x10, 0x11, 0x81, 0x64, 0x80, 0x18, 0x05, 0x40, 0x17, 0x00, 0x91, 0x02, ++0x44, 0x03, 0x14, 0x09, 0x40, 0x27, 0x00, 0xCD, 0x00, 0x44, 0x03, 0x10, 0x0D, ++0x40, 0x36, 0x02, 0xDD, 0x00, 0x74, 0x04, 0x10, 0x01, 0x40, 0x07, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x20, 0x00, 0x01, 0x00, ++0x16, 0x80, 0x50, 0x04, 0x40, 0x13, 0x00, 0x01, 0x00, 0x04, 0x03, 0x10, 0x08, ++0x48, 0xB3, 0x20, 0xCD, 0x00, 0x05, 0x02, 0x10, 0x0C, 0x40, 0x33, 0x00, 0xCD, ++0x00, 0x74, 0x00, 0x10, 0x0C, 0x40, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0xB0, 0x26, 0x00, 0x93, 0x00, 0x4C, 0x00, 0x30, 0x09, ++0xC0, 0x27, 0x00, 0xD1, 0x00, 0xCC, 0x03, 0x30, 0x0D, 0xC0, 0x27, 0x08, 0xFB, ++0x00, 0x4C, 0x03, 0x30, 0x0D, 0xC0, 0x16, 0x00, 0x9F, 0x00, 0x7C, 0x00, 0x30, ++0x01, 0xC4, 0x07, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xA8, 0x1F, 0x00, 0xBF, 0x00, 0xFC, 0x01, 0xF0, 0x0B, 0xC0, 0x0F, 0x00, 0x7F, ++0x40, 0xFC, 0x03, 0xF1, 0x07, 0xC0, 0x2F, 0x01, 0xFF, 0x00, 0xFC, 0x01, 0x70, ++0x0E, 0xC0, 0x1F, 0x00, 0x7F, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x17, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x88, 0x7B, 0x22, 0xFB, ++0x29, 0xEC, 0x27, 0xF0, 0x9F, 0xC4, 0x7C, 0x02, 0xEF, 0x09, 0xCC, 0x07, 0x30, ++0x9F, 0xC0, 0x7C, 0x00, 0xE3, 0x01, 0xCC, 0x07, 0xF0, 0x9F, 0xC0, 0x7C, 0x00, ++0xEF, 0x09, 0xCC, 0x07, 0xF0, 0x1F, 0xC0, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x07, 0x00, 0x11, 0x04, 0x4C, 0x00, 0xD1, ++0x01, 0x00, 0x04, 0x31, 0x1D, 0x04, 0x44, 0x04, 0x50, 0x41, 0x00, 0x05, 0x05, ++0x11, 0x00, 0x5C, 0x10, 0xD0, 0x41, 0x40, 0x00, 0x25, 0x1D, 0x04, 0x44, 0x00, ++0xD0, 0x01, 0x40, 0x0F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0xA0, 0x35, 0x00, 0xD9, 0x00, 0x24, 0x13, 0x52, 0x4C, 0x42, 0x31, 0x01, ++0xCD, 0x04, 0x44, 0x83, 0x50, 0x0D, 0x0A, 0x30, 0x00, 0xD5, 0x00, 0x04, 0x43, ++0xD0, 0x4C, 0x60, 0x30, 0x00, 0xCD, 0x00, 0x05, 0x03, 0xD0, 0x0C, 0x40, 0x4D, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x07, 0x00, ++0x11, 0x00, 0x40, 0x80, 0xD0, 0x01, 0x40, 0x05, 0x00, 0x1D, 0x00, 0x47, 0x00, ++0x50, 0x01, 0x48, 0x01, 0x40, 0x15, 0x20, 0x74, 0x00, 0xD0, 0x00, 0x48, 0x05, ++0x00, 0x0D, 0x00, 0x54, 0x00, 0xC0, 0x01, 0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x36, 0x00, 0xDB, 0x00, 0x6C, 0x03, ++0xF0, 0x0D, 0xC0, 0x35, 0x00, 0xDF, 0x40, 0x0C, 0x03, 0x70, 0x0D, 0x40, 0x34, ++0x00, 0xD7, 0x00, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0xDF, 0x00, 0x4C, ++0x03, 0xE0, 0x0D, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0x80, 0x0D, 0x00, 0x3F, 0x00, 0xDC, 0x40, 0xF3, 0x03, 0xD4, 0x0E, ++0x10, 0x3F, 0x00, 0xF8, 0x40, 0xF0, 0x03, 0xC0, 0x0F, 0x20, 0x3B, 0x00, 0xDC, ++0x00, 0xF1, 0x03, 0xC0, 0x0E, 0x00, 0x3F, 0x00, 0xEC, 0x00, 0xF0, 0x03, 0xC0, ++0x1F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, ++0x00, 0xD7, 0x04, 0x7C, 0x03, 0xF0, 0x4D, 0xC0, 0x37, 0x00, 0xD7, 0x60, 0x5C, ++0x07, 0xB0, 0x0D, 0xC0, 0x37, 0x00, 0xD7, 0x00, 0x4C, 0x13, 0xF0, 0x0D, 0xC0, ++0x34, 0x40, 0xD3, 0x04, 0x4C, 0x43, 0xF0, 0x0D, 0xC0, 0xAB, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xA0, 0x00, 0x06, 0x01, 0x12, 0x74, ++0x14, 0xD0, 0x71, 0x60, 0x07, 0x00, 0x11, 0x00, 0x6C, 0x00, 0x10, 0x00, 0x40, ++0xC7, 0x02, 0x0D, 0x11, 0x6C, 0x18, 0xD2, 0x01, 0x40, 0x04, 0x00, 0x11, 0x12, ++0x6C, 0x00, 0xD0, 0xB1, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x20, 0xF0, 0x10, 0xC5, 0x80, 0x34, 0x03, 0xD1, 0x0D, 0x42, ++0x33, 0x00, 0xDD, 0x00, 0x24, 0x0B, 0x90, 0x0C, 0x40, 0xB3, 0x00, 0xC5, 0x01, ++0x04, 0x0F, 0xD8, 0x0C, 0x40, 0x32, 0x00, 0xC1, 0x01, 0x04, 0x0B, 0xD2, 0x1C, ++0x40, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x02, ++0x4C, 0x00, 0x21, 0x01, 0xB4, 0x04, 0xD9, 0x12, 0x40, 0x4F, 0x02, 0x39, 0x01, ++0xA4, 0x04, 0x10, 0x12, 0x40, 0x4B, 0x04, 0x3D, 0x01, 0xA6, 0x24, 0xD0, 0x12, ++0x68, 0x4A, 0x00, 0x31, 0x01, 0xA4, 0x04, 0xD0, 0x12, 0x53, 0x3C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xC7, 0x00, ++0x3C, 0x03, 0xF0, 0x0C, 0x48, 0x33, 0x10, 0xCF, 0x00, 0x3C, 0x03, 0xB0, 0x0C, ++0x40, 0x33, 0x00, 0xC7, 0x00, 0x0C, 0xA3, 0xF1, 0x0D, 0xCC, 0x32, 0x80, 0xC3, ++0x00, 0x0C, 0x03, 0xF0, 0x0D, 0xC0, 0x49, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x38, 0x0D, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF8, 0x03, ++0x80, 0x0B, 0x08, 0x36, 0x00, 0xBC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, ++0x00, 0xFC, 0x20, 0xD2, 0x03, 0xC0, 0x0D, 0x10, 0x3F, 0x00, 0xFC, 0x00, 0xFA, ++0x11, 0xC0, 0x09, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xA8, 0x77, 0x20, 0xD7, 0x41, 0x6C, 0x03, 0xF0, 0x0D, 0xC0, 0x74, 0x00, 0xC3, ++0x01, 0x4C, 0x03, 0xF0, 0x0D, 0xC0, 0x33, 0x00, 0xD3, 0x01, 0x4D, 0x03, 0x70, ++0x1D, 0xC0, 0x30, 0x00, 0xD3, 0x01, 0x4C, 0x07, 0x30, 0x1D, 0xD0, 0x40, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80, 0x0D, 0x48, 0x21, ++0x40, 0x84, 0x00, 0xD0, 0x02, 0x40, 0x09, 0x00, 0x25, 0x00, 0x90, 0x00, 0xD0, ++0x02, 0x40, 0x0B, 0x00, 0x35, 0x00, 0xC4, 0x00, 0x10, 0x02, 0x40, 0x09, 0x00, ++0x2B, 0x40, 0x84, 0x00, 0xB0, 0x03, 0xC0, 0x4E, 0x08, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xF9, 0x01, 0xA4, 0x07, 0xC2, ++0x1F, 0x40, 0x7C, 0x00, 0xF5, 0x01, 0x84, 0x07, 0xD0, 0x1E, 0x40, 0x7F, 0x00, ++0xE1, 0x01, 0x94, 0x07, 0x50, 0x1F, 0x48, 0x7C, 0x80, 0xE1, 0x01, 0xC4, 0x07, ++0x18, 0x1E, 0x48, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x16, 0x28, 0x03, 0x00, 0x09, 0x00, 0x40, 0x00, 0xD8, 0x00, 0x42, 0x01, 0x00, ++0x05, 0x20, 0x14, 0x00, 0xD0, 0x00, 0x40, 0x07, 0x00, 0x05, 0x00, 0x14, 0x00, ++0x50, 0x00, 0x40, 0x05, 0x08, 0x09, 0x00, 0x04, 0x00, 0x98, 0x00, 0x40, 0x5A, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x28, 0x15, 0x00, ++0x5B, 0x00, 0x6C, 0x01, 0xD0, 0x04, 0xC0, 0x14, 0x00, 0x57, 0x00, 0x4C, 0x01, ++0xF0, 0x05, 0xC4, 0x17, 0x00, 0x53, 0x00, 0x1C, 0x01, 0x70, 0x05, 0xC0, 0x14, ++0x08, 0x53, 0x60, 0x4C, 0x01, 0x30, 0x05, 0x40, 0x5C, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x8D, 0x00, 0x37, 0x02, 0xFC, 0x00, ++0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x08, 0xF0, 0x03, 0xC8, 0x0F, ++0x00, 0x3F, 0x02, 0xE4, 0x08, 0xB0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x80, 0xFD, ++0x00, 0xF0, 0x03, 0xC0, 0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x19, 0x40, 0x24, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x24, 0x00, 0x93, 0x00, 0x7C, ++0x16, 0x30, 0x09, 0xC0, 0x27, 0x40, 0x93, 0x04, 0x78, 0x16, 0xF0, 0x09, 0xC0, ++0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x24, ++0x01, 0x9D, 0x00, 0x74, 0x42, 0x14, 0x59, 0xC0, 0x26, 0x00, 0x9D, 0x00, 0x74, ++0x0A, 0xD0, 0x09, 0x40, 0xA4, 0x00, 0x91, 0x9A, 0x74, 0x8E, 0xB2, 0x09, 0x40, ++0x27, 0x10, 0x91, 0x02, 0x64, 0x16, 0xD1, 0x09, 0x40, 0x07, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x6C, 0x80, 0xBD, 0x01, 0xE4, ++0x06, 0x10, 0x4B, 0x40, 0x2D, 0x00, 0xBD, 0x00, 0xF4, 0x0E, 0xD0, 0x0A, 0x40, ++0x2C, 0x04, 0xB1, 0x00, 0xF4, 0x02, 0x10, 0x0B, 0x00, 0x2F, 0x00, 0xB1, 0x10, ++0xF4, 0x02, 0xD0, 0x0B, 0x41, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x28, 0x00, 0xEC, 0x00, 0xB4, 0x02, 0x10, 0x0B, 0x40, ++0x2B, 0x22, 0xAD, 0x08, 0xB4, 0x82, 0xD0, 0x8A, 0x60, 0x28, 0x42, 0xA1, 0x40, ++0xF4, 0x02, 0x90, 0x8A, 0x40, 0x2B, 0x0A, 0xA1, 0x08, 0xA4, 0x02, 0xD0, 0x0A, ++0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, ++0x06, 0x00, 0x1F, 0x40, 0x6C, 0x00, 0x30, 0x01, 0xC0, 0x85, 0x00, 0x1D, 0x02, ++0x7C, 0x00, 0xF0, 0x21, 0xD0, 0x84, 0x00, 0x13, 0x0A, 0x7C, 0x01, 0x30, 0x21, ++0xC0, 0x87, 0x08, 0x03, 0x22, 0x7C, 0x00, 0xF0, 0x03, 0xE0, 0x77, 0xE0, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x27, 0x05, 0x8D, 0x14, ++0x7C, 0x52, 0xF0, 0x48, 0xC1, 0x22, 0x01, 0x9F, 0x04, 0x7C, 0x02, 0xF0, 0x49, ++0xC0, 0x27, 0x01, 0x9F, 0x81, 0x7C, 0x52, 0xF0, 0x48, 0xC0, 0x27, 0x01, 0x9F, ++0x24, 0x3C, 0x52, 0xF0, 0x49, 0xC1, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xA0, 0xAF, 0x00, 0xB7, 0x02, 0xDC, 0x0A, 0xB0, 0x2B, ++0xC0, 0x27, 0x00, 0x9F, 0x02, 0xDC, 0x02, 0x30, 0x89, 0xC0, 0x2F, 0x10, 0xB3, ++0x00, 0xFC, 0x02, 0xF0, 0x29, 0xC0, 0xA7, 0x10, 0xBF, 0x00, 0xCC, 0x02, 0xB0, ++0x0B, 0xC0, 0x77, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0x00, 0x05, 0x01, 0x11, 0x81, 0x44, 0x00, 0x10, 0x41, 0x40, 0x07, 0x05, 0x1D, ++0x00, 0x44, 0x00, 0x50, 0x01, 0x40, 0x07, 0x01, 0x11, 0x00, 0x74, 0x50, 0xD0, ++0x01, 0x40, 0x07, 0x00, 0x1D, 0x00, 0x44, 0x00, 0x50, 0x01, 0x40, 0x63, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, 0x21, 0x01, 0x85, ++0x00, 0x54, 0x12, 0x90, 0x48, 0x40, 0x23, 0x80, 0x8D, 0x04, 0x44, 0x02, 0x10, ++0x48, 0x40, 0x23, 0x44, 0x81, 0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x23, 0x80, ++0x8D, 0x00, 0x06, 0x02, 0x90, 0x08, 0x40, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0x91, 0x00, 0x44, 0x03, 0x08, ++0x09, 0x40, 0x27, 0x00, 0x8C, 0x00, 0x45, 0x82, 0x50, 0x09, 0x42, 0x23, 0x08, ++0x91, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x44, 0x02, ++0xD8, 0x09, 0x40, 0x63, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0x20, 0x25, 0x00, 0x97, 0x00, 0x1C, 0x02, 0xB0, 0x09, 0xC4, 0x27, 0x00, ++0x9F, 0x00, 0x5C, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x92, 0x00, 0x7C, 0x02, ++0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x4C, 0x02, 0xB0, 0x09, 0xC8, 0x17, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x88, 0x25, 0x00, ++0x9F, 0x00, 0x7C, 0x02, 0xF8, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x80, 0x7C, 0x02, ++0xF0, 0x09, 0xC2, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x80, 0x7D, 0x42, 0x70, 0x09, 0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1D, 0x10, 0x7C, 0x10, ++0xD0, 0x01, 0xC0, 0x07, 0x00, 0x1B, 0x00, 0x5C, 0x00, 0x70, 0x01, 0xC0, 0x04, ++0x00, 0x1B, 0x49, 0x7C, 0x40, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x1F, 0x00, 0x7C, ++0x00, 0xB4, 0x41, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xA0, 0xDC, 0x00, 0x7D, 0x23, 0xF4, 0x9D, 0x10, 0x97, 0x40, 0x17, ++0x00, 0x5D, 0x00, 0xB4, 0x21, 0xD0, 0x05, 0x40, 0x1C, 0x00, 0x7D, 0x01, 0xF4, ++0x01, 0xD0, 0x05, 0x40, 0x15, 0x20, 0x7D, 0x02, 0xF4, 0x09, 0x10, 0x07, 0x40, ++0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0xB6, ++0x06, 0xDD, 0x0B, 0x34, 0x03, 0x50, 0xAC, 0x40, 0x33, 0x00, 0xCD, 0x80, 0x14, ++0x8F, 0xD0, 0x0C, 0x50, 0x70, 0x80, 0xC9, 0x21, 0x32, 0x27, 0xD0, 0x0C, 0x40, ++0x32, 0x00, 0xDD, 0x12, 0x74, 0x23, 0x10, 0x1C, 0x40, 0x43, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x39, 0x00, 0xED, 0x00, 0xF4, ++0x03, 0x10, 0x0E, 0x40, 0x3B, 0x03, 0xEC, 0x04, 0xB4, 0x0A, 0xC0, 0x5E, 0x40, ++0x38, 0x04, 0xE9, 0x00, 0xB4, 0x03, 0xD0, 0x5F, 0x40, 0x3B, 0x00, 0x2D, 0x10, ++0xB4, 0x03, 0x10, 0x2E, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x18, 0x79, 0x00, 0xEF, 0x01, 0xBC, 0x07, 0x70, 0x1E, 0xC0, ++0x7B, 0x05, 0xEB, 0x89, 0x9C, 0x07, 0x70, 0xBF, 0xC0, 0x78, 0x20, 0x2B, 0x21, ++0xBC, 0x07, 0xF0, 0x3E, 0xC0, 0x7A, 0x05, 0xEF, 0x01, 0xFC, 0x07, 0x31, 0x1E, ++0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, ++0x15, 0x10, 0x5F, 0x00, 0x3C, 0x03, 0x70, 0x0D, 0x80, 0xB7, 0x01, 0xDF, 0x0C, ++0x7C, 0x00, 0xF0, 0x4D, 0xC0, 0x17, 0x00, 0x1F, 0x20, 0x7C, 0x03, 0xF0, 0x0C, ++0x41, 0x35, 0x08, 0x1F, 0x00, 0x7C, 0x01, 0x70, 0x0D, 0xC0, 0x43, 0x60, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x7D, 0x00, 0xFF, 0x89, ++0xF8, 0x05, 0x70, 0x1F, 0xC2, 0x7D, 0x00, 0xFB, 0x01, 0xFC, 0x07, 0xF0, 0x1F, ++0xC0, 0x6F, 0x00, 0xF7, 0x01, 0xCE, 0x25, 0x30, 0x1F, 0xC0, 0x7F, 0x04, 0xF3, ++0x01, 0x8C, 0x25, 0x30, 0x1E, 0xC0, 0x18, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x08, 0x39, 0x04, 0xED, 0x08, 0xF4, 0x11, 0x00, 0x0E, ++0x40, 0x3F, 0x00, 0xE0, 0x10, 0xB4, 0x42, 0xD0, 0x8E, 0x41, 0x3B, 0x00, 0xF5, ++0x02, 0x94, 0x0B, 0x50, 0x0E, 0xC0, 0x3B, 0x00, 0x3B, 0x08, 0x85, 0x39, 0xB0, ++0x0A, 0x40, 0x55, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, ++0x00, 0x39, 0x02, 0xED, 0x08, 0xB0, 0x01, 0xD1, 0x06, 0x40, 0x39, 0x04, 0xE9, ++0x08, 0xB4, 0x02, 0xD0, 0x0E, 0x40, 0x2F, 0x00, 0x71, 0x08, 0xC4, 0x01, 0x90, ++0x0E, 0x40, 0x3F, 0x00, 0xE9, 0x00, 0xC4, 0x00, 0x18, 0x07, 0x40, 0x20, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x21, 0x10, 0x9D, ++0x03, 0x34, 0x00, 0x90, 0x89, 0x40, 0xF2, 0x80, 0xC1, 0x02, 0x34, 0x0C, 0xD0, ++0x1C, 0x60, 0x57, 0x00, 0x05, 0x06, 0x14, 0x0E, 0xD8, 0x2C, 0x40, 0xB1, 0x00, ++0xCD, 0x0A, 0x00, 0xAC, 0x98, 0x00, 0x42, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x55, 0xA0, 0xC4, 0x20, 0x1F, 0x52, 0x7C, 0x0A, 0xD0, ++0xA1, 0xC0, 0xFD, 0x80, 0xFB, 0x01, 0x7C, 0x2C, 0xF0, 0x0F, 0xC8, 0xD7, 0x01, ++0x93, 0x11, 0x4C, 0x12, 0xB0, 0x3F, 0x41, 0xBF, 0x00, 0xC9, 0x08, 0x48, 0x0E, ++0x10, 0x91, 0xC0, 0x74, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x0D, 0x08, 0x27, 0x20, 0x9F, 0x84, 0x7E, 0x60, 0x70, 0x21, 0xC8, 0x37, 0x09, ++0xDF, 0x00, 0x7C, 0x08, 0xF0, 0x0D, 0xC1, 0xA6, 0x00, 0x9E, 0x40, 0x7E, 0x40, ++0x70, 0x0D, 0xC1, 0x37, 0x22, 0x1B, 0x00, 0x7C, 0x1A, 0xF0, 0x89, 0xC4, 0x97, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x08, 0x0B, 0x84, ++0x33, 0x80, 0xCC, 0x02, 0xF0, 0x03, 0xC0, 0x3E, 0x00, 0xF7, 0x10, 0xF8, 0x00, ++0xF2, 0x0F, 0xC0, 0x1C, 0x04, 0x33, 0x80, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, ++0x04, 0xFF, 0x00, 0xCC, 0x02, 0xF0, 0x03, 0xC0, 0x04, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x46, 0x08, 0x17, 0x11, 0x4C, 0x06, ++0xD0, 0x11, 0x40, 0x34, 0x00, 0xD1, 0x80, 0x74, 0x04, 0xF0, 0x0C, 0x40, 0x85, ++0x02, 0x11, 0x03, 0x64, 0x06, 0xD0, 0x0D, 0x40, 0x37, 0x08, 0x1D, 0x11, 0x6C, ++0x04, 0xD0, 0x38, 0xC8, 0x06, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0xA0, 0x44, 0x04, 0x11, 0x21, 0x54, 0x06, 0xD8, 0x39, 0x66, 0x32, ++0x00, 0xD5, 0x00, 0x74, 0x0E, 0xD0, 0x0D, 0x40, 0x04, 0x04, 0x31, 0x21, 0x74, ++0x04, 0xD8, 0x0D, 0x40, 0x37, 0x00, 0xDD, 0x08, 0x44, 0x06, 0xD0, 0x31, 0x40, ++0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0A, 0x24, ++0x00, 0x85, 0x00, 0x05, 0x00, 0xD2, 0x08, 0x60, 0x30, 0x00, 0xC1, 0x00, 0x34, ++0x02, 0xD0, 0x0D, 0x40, 0x21, 0x20, 0x01, 0x00, 0x34, 0x00, 0xD2, 0x0C, 0x40, ++0x33, 0x00, 0x1D, 0x00, 0x24, 0x02, 0xD0, 0x09, 0x40, 0x42, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x06, 0x00, 0x11, 0x00, 0x5C, ++0x82, 0xF8, 0x01, 0xC0, 0x3E, 0x00, 0xF6, 0x00, 0x7C, 0x02, 0xF0, 0x0F, 0x40, ++0x04, 0x00, 0x13, 0x00, 0x74, 0x00, 0xF0, 0x0F, 0xC0, 0x3F, 0x90, 0x1F, 0x00, ++0x4C, 0x02, 0xF0, 0x01, 0xC0, 0x04, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x85, 0xA8, 0x2F, 0x00, 0xB6, 0x00, 0xCC, 0x02, 0xF8, 0x0B, 0xC0, ++0x3F, 0x00, 0xFE, 0x80, 0xFC, 0x00, 0x70, 0x0F, 0xC0, 0x0B, 0x40, 0x3F, 0x00, ++0xA4, 0x02, 0xF2, 0x0F, 0xC0, 0x3B, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF0, 0x03, ++0xC0, 0x17, 0x61, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, ++0x7F, 0x40, 0xF3, 0x46, 0xFC, 0x03, 0x30, 0x4F, 0xC0, 0x4F, 0x12, 0x3B, 0x4C, ++0xCC, 0x23, 0x30, 0x4F, 0xC2, 0x0C, 0x80, 0x3F, 0x01, 0xFC, 0x07, 0x71, 0x8F, ++0xC0, 0x0F, 0x08, 0x73, 0x01, 0xFC, 0x00, 0x30, 0x03, 0xC0, 0x0C, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, 0x7D, 0x00, 0xE1, 0x08, ++0xF4, 0xAF, 0x10, 0xBF, 0x40, 0x27, 0x01, 0x5D, 0x08, 0xC4, 0x3B, 0x50, 0x9F, ++0x40, 0x44, 0x00, 0x5D, 0x00, 0xF4, 0x07, 0x10, 0x0F, 0x40, 0x07, 0x00, 0xD5, ++0x81, 0x74, 0x00, 0xB1, 0x01, 0x80, 0x0E, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0x20, 0x33, 0x00, 0xC4, 0x04, 0x34, 0x03, 0x55, 0x0C, ++0x40, 0x43, 0x01, 0x8D, 0x44, 0x14, 0x03, 0x50, 0x0C, 0x50, 0x00, 0x00, 0x0D, ++0x80, 0x34, 0x03, 0x10, 0x4C, 0x40, 0x07, 0x00, 0x41, 0x00, 0x34, 0x00, 0xD0, ++0x00, 0x40, 0x4D, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA0, 0x35, 0x00, 0xD5, 0x00, 0x70, 0x03, 0x50, 0x0D, 0x40, 0x67, 0x00, 0x5D, ++0x14, 0x54, 0x03, 0x10, 0x0D, 0x00, 0x6C, 0x00, 0x5D, 0x10, 0x74, 0x03, 0x10, ++0x0F, 0x40, 0x6F, 0x00, 0xD5, 0x04, 0x70, 0x06, 0xD0, 0x11, 0x40, 0x0F, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x36, 0x00, 0xD7, ++0x00, 0x7E, 0x03, 0x70, 0x0D, 0xC4, 0x47, 0x00, 0x1B, 0x03, 0x5D, 0x03, 0x70, ++0x0D, 0x80, 0x44, 0x20, 0xDD, 0x00, 0x3C, 0x03, 0x74, 0x0D, 0xC4, 0x47, 0x00, ++0x93, 0x06, 0x78, 0x04, 0x70, 0x51, 0xC0, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xFB, 0x00, 0xBC, 0x03, 0xB0, ++0x0F, 0xC0, 0x0F, 0x00, 0x6A, 0x20, 0xEC, 0x03, 0xF0, 0x0F, 0x84, 0x0F, 0x08, ++0xFC, 0x00, 0xFE, 0x03, 0xE0, 0x0F, 0x80, 0x0F, 0x00, 0xBF, 0x01, 0xB8, 0x02, ++0xB0, 0x09, 0xC2, 0x3E, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x08, 0x31, 0x10, 0xD3, 0x40, 0x5C, 0x03, 0xF3, 0x0D, 0xC0, 0x06, 0x00, ++0x9F, 0x02, 0x2C, 0x03, 0x70, 0x4C, 0xC0, 0x26, 0x04, 0xD7, 0x22, 0x7C, 0x13, ++0x30, 0x0D, 0xC0, 0x24, 0x00, 0x9F, 0x02, 0x4C, 0x00, 0x30, 0x01, 0xC0, 0x28, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xA0, 0x34, 0x00, ++0xF1, 0x20, 0xC4, 0x17, 0xD0, 0x4F, 0x40, 0x24, 0x00, 0x5D, 0x40, 0xC0, 0x17, ++0x10, 0x7F, 0x40, 0xE7, 0x00, 0xDD, 0x06, 0x70, 0x03, 0x11, 0xAF, 0x10, 0x24, ++0x00, 0x9D, 0x45, 0x44, 0x46, 0x11, 0x19, 0x11, 0x4C, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x72, 0x40, 0xC9, 0x20, 0x24, 0x03, ++0xD0, 0x6C, 0x40, 0x22, 0x00, 0x08, 0x20, 0x20, 0x03, 0xD0, 0x1C, 0x40, 0xC2, ++0x88, 0x84, 0x20, 0x30, 0x0B, 0x10, 0x0C, 0x40, 0x04, 0x00, 0x8D, 0x21, 0x25, ++0x04, 0x14, 0x11, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x0F, 0x00, 0x70, 0x04, 0xE9, 0x01, 0xB4, 0x17, 0xD8, 0x1E, 0x40, 0x6A, ++0x08, 0xAD, 0x05, 0xA4, 0x07, 0x90, 0x1E, 0x4A, 0x5B, 0x0A, 0xED, 0x6B, 0x34, ++0x07, 0x81, 0x9E, 0x42, 0x58, 0x00, 0xAD, 0x01, 0xB6, 0x05, 0x10, 0xB6, 0x40, ++0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x18, 0x30, ++0x00, 0xCB, 0x00, 0x2C, 0x03, 0xF0, 0x0C, 0xC0, 0x22, 0x01, 0x9F, 0x00, 0x6C, ++0x03, 0xF0, 0x0C, 0xC0, 0x02, 0x04, 0x87, 0x05, 0x3C, 0x43, 0x20, 0x0D, 0xC0, ++0x10, 0x00, 0xCF, 0x00, 0x6C, 0x01, 0x30, 0x00, 0xC0, 0x48, 0x68, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x7D, 0x00, 0xF7, 0x10, 0xC1, ++0x53, 0xF0, 0x0E, 0xC0, 0x3D, 0x00, 0xBB, 0x04, 0xDC, 0x0B, 0x7A, 0x8F, 0xC1, ++0x3F, 0x08, 0xFF, 0x28, 0xFC, 0x07, 0x72, 0x2F, 0xC0, 0x3F, 0x00, 0xEF, 0x00, ++0x4C, 0x03, 0xF0, 0x07, 0xC0, 0x0B, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA0, 0x37, 0x00, 0xDF, 0x03, 0x5C, 0x4F, 0x30, 0x3D, 0xC9, ++0x04, 0x10, 0x5F, 0x40, 0x4C, 0x37, 0x30, 0x2D, 0xC0, 0x56, 0x40, 0xDB, 0x01, ++0x4C, 0x03, 0xB3, 0x2D, 0xC2, 0x14, 0x00, 0x8F, 0x00, 0x4C, 0x00, 0xF0, 0x0D, ++0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80, ++0x39, 0x01, 0xCD, 0x14, 0x02, 0x13, 0xB0, 0x4C, 0x4A, 0x08, 0x00, 0xCC, 0x00, ++0x84, 0x13, 0xB0, 0x4E, 0x41, 0x1B, 0x00, 0xE1, 0x00, 0x84, 0x0B, 0xD0, 0x0F, ++0x40, 0x18, 0x00, 0xAD, 0x00, 0x84, 0x03, 0xD0, 0x0E, 0xC0, 0x4E, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x02, 0xED, 0x01, ++0x94, 0x17, 0x10, 0x9E, 0x40, 0x79, 0x00, 0xED, 0x01, 0x04, 0x17, 0x10, 0x1E, ++0x40, 0x61, 0x88, 0xE1, 0x21, 0x96, 0x17, 0xD0, 0x9E, 0x44, 0x78, 0x00, 0xBD, ++0x01, 0x85, 0x05, 0xD0, 0x1C, 0x40, 0x11, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x16, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x14, 0x03, 0x90, 0x0C, ++0x40, 0x71, 0x01, 0xCD, 0x88, 0x04, 0x03, 0x90, 0x0C, 0x40, 0x33, 0x00, 0xC1, ++0x3A, 0x14, 0x03, 0xD0, 0x0C, 0x42, 0xF0, 0x04, 0x8D, 0x03, 0x44, 0x0B, 0xD0, ++0x8D, 0x40, 0x5B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, ++0x20, 0x15, 0x00, 0x5F, 0x00, 0x5C, 0x01, 0x30, 0x05, 0x40, 0xDD, 0x01, 0x7F, ++0xC1, 0x4D, 0x01, 0x31, 0x05, 0xC0, 0x9E, 0x04, 0x71, 0x03, 0x5C, 0x01, 0xB0, ++0x05, 0xC4, 0xDC, 0x01, 0x7F, 0x59, 0xCC, 0x09, 0xF0, 0xB7, 0x40, 0x5D, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x08, 0x05, 0x00, 0x1F, ++0x00, 0x64, 0x00, 0xF0, 0x21, 0x50, 0x06, 0x20, 0x0B, 0x80, 0x7C, 0x00, 0xF0, ++0x01, 0xC0, 0x86, 0x04, 0x17, 0x00, 0x68, 0x08, 0xA2, 0x01, 0xD0, 0x07, 0x08, ++0x1F, 0x22, 0x7C, 0x48, 0xF0, 0x01, 0xC0, 0x4A, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x65, 0x00, 0x9F, 0x00, 0x6C, 0x82, 0xF0, ++0x09, 0xC0, 0x27, 0x00, 0x97, 0x00, 0x6C, 0x22, 0xF0, 0x49, 0xC4, 0x27, 0x00, ++0x9F, 0x00, 0x7C, 0x0A, 0xD0, 0x29, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x50, 0x02, ++0x30, 0x09, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x20, 0x2C, 0x00, 0x9D, 0x40, 0x74, 0x02, 0xD0, 0xA9, 0x40, 0x27, 0x10, ++0x94, 0x00, 0x44, 0x02, 0xD0, 0x29, 0x04, 0xA7, 0x01, 0x9D, 0x11, 0xF4, 0x4E, ++0xC2, 0x29, 0x50, 0x24, 0x00, 0x8D, 0x04, 0x44, 0x2A, 0x50, 0x09, 0x40, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x02, ++0x9D, 0x00, 0x74, 0x22, 0xD0, 0x09, 0x40, 0x23, 0x00, 0x90, 0x40, 0x64, 0x02, ++0xD0, 0x09, 0x01, 0x26, 0x82, 0x9D, 0x01, 0x74, 0x02, 0xC0, 0x28, 0x40, 0x24, ++0x00, 0x9C, 0x80, 0x54, 0x02, 0x12, 0x29, 0x46, 0x60, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x21, 0x00, 0x8D, 0x48, 0x34, 0x02, ++0xD1, 0x08, 0x40, 0x23, 0x62, 0x81, 0x08, 0x04, 0x0A, 0xD0, 0x08, 0x40, 0x23, ++0x21, 0x8D, 0x20, 0x34, 0x02, 0xD0, 0xC8, 0x40, 0x20, 0x01, 0x8D, 0x80, 0x10, ++0x53, 0x52, 0x48, 0x41, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1D, 0xB8, 0x46, 0x00, 0x1F, 0x36, 0x7C, 0x50, 0xF0, 0x45, 0xC1, 0x87, ++0x00, 0x12, 0x16, 0x6C, 0x50, 0xF1, 0x41, 0x81, 0x46, 0x00, 0x0F, 0x0A, 0x7C, ++0x04, 0xF0, 0x31, 0xC4, 0xC4, 0x02, 0x1F, 0x00, 0x58, 0x10, 0x30, 0x41, 0xE2, ++0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0xA7, ++0x00, 0x9F, 0x24, 0x78, 0x82, 0xF0, 0x09, 0xCA, 0x2F, 0x01, 0xFC, 0x04, 0x7C, ++0x06, 0xF1, 0x09, 0x80, 0x2F, 0x02, 0xBF, 0x01, 0x7C, 0x0A, 0xB0, 0xC9, 0xC0, ++0x6F, 0x02, 0xBF, 0x00, 0xEC, 0x52, 0xF0, 0x4B, 0xD1, 0x77, 0x60, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x6F, 0x00, 0x9F, 0x16, 0xFC, ++0x02, 0x34, 0x4B, 0xC0, 0x24, 0x00, 0x9F, 0x02, 0xFC, 0x22, 0xF0, 0x0B, 0xC0, ++0x2C, 0x60, 0xB3, 0x00, 0xFC, 0x46, 0xF0, 0x0B, 0xC0, 0x24, 0x00, 0xB3, 0x80, ++0xCD, 0x82, 0xF0, 0x0B, 0xC0, 0x77, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0x00, 0x87, 0x00, 0x1D, 0x02, 0x74, 0x00, 0x10, 0x01, 0x40, ++0x04, 0x01, 0x0D, 0x8A, 0x74, 0x04, 0xD0, 0xA1, 0x40, 0x04, 0x08, 0x11, 0x00, ++0x74, 0x08, 0xD0, 0x41, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0xD1, 0x01, ++0x42, 0x63, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, ++0xA1, 0x00, 0x8D, 0x00, 0x34, 0x0A, 0x11, 0x2C, 0x40, 0x20, 0x24, 0x89, 0x40, ++0x34, 0x1A, 0xD0, 0x08, 0x40, 0x20, 0x10, 0x85, 0x00, 0x34, 0x02, 0xD8, 0x08, ++0x61, 0x20, 0x40, 0x95, 0x00, 0x14, 0x06, 0xD0, 0x08, 0x40, 0x4B, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x25, 0x00, 0x9D, 0x00, ++0x70, 0x02, 0x12, 0x09, 0x40, 0xA4, 0x0A, 0x9D, 0x20, 0x74, 0x02, 0xD0, 0x09, ++0x10, 0x24, 0x10, 0x95, 0x20, 0x74, 0x82, 0xD0, 0x08, 0x4C, 0x24, 0x04, 0x95, ++0x08, 0x54, 0xA3, 0xD0, 0x09, 0x40, 0x63, 0x28, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0x2A, 0x25, 0x20, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x09, ++0xD0, 0x64, 0x00, 0x9F, 0x02, 0xFC, 0x02, 0xF0, 0x09, 0xC4, 0xA4, 0x04, 0x97, ++0x00, 0x7C, 0x02, 0xF2, 0x09, 0x50, 0x64, 0x02, 0x87, 0x00, 0x5C, 0x02, 0xF0, ++0x09, 0xC0, 0x17, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x00, 0x25, 0x00, 0x9F, 0x00, 0x7E, 0x02, 0xF0, 0x08, 0xC0, 0x67, 0x20, 0x9F, ++0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC3, 0x27, 0x02, 0x9B, 0x10, 0x7C, 0x82, 0xF0, ++0x09, 0xC0, 0x67, 0x00, 0x9A, 0x00, 0x6C, 0x02, 0xF0, 0x09, 0xC0, 0x5B, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x17, ++0x00, 0x4C, 0x00, 0xB0, 0x01, 0xC8, 0x07, 0x00, 0x13, 0x02, 0x6C, 0x20, 0xF0, ++0x81, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x4C, 0x00, 0x34, 0x01, 0xC0, 0x87, 0x00, ++0x13, 0x04, 0x7C, 0x04, 0x30, 0x01, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x14, 0x04, 0x51, 0x00, 0x2C, 0x01, 0xD0, ++0xA7, 0x48, 0x17, 0x08, 0x51, 0x00, 0x44, 0x01, 0xD0, 0x26, 0x40, 0x5B, 0x20, ++0x7C, 0x83, 0xC4, 0x01, 0x11, 0x07, 0x41, 0x17, 0x00, 0x70, 0x00, 0xF4, 0x01, ++0x10, 0x07, 0x44, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x80, 0x32, 0x00, 0xC5, 0x00, 0x14, 0x27, 0x9A, 0x0C, 0x44, 0x33, 0x00, ++0xC0, 0x00, 0x24, 0x07, 0xD0, 0x2C, 0x40, 0x63, 0x20, 0xCD, 0x00, 0x00, 0x02, ++0x90, 0x5C, 0x40, 0x37, 0x00, 0x81, 0x03, 0x30, 0x03, 0x94, 0x1C, 0x40, 0x43, ++0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x79, 0x00, ++0xE1, 0x01, 0xA5, 0x03, 0xD0, 0x06, 0x40, 0x7B, 0x02, 0xE1, 0x49, 0x84, 0x02, ++0xD0, 0x06, 0x40, 0xBB, 0x80, 0x6D, 0x03, 0x84, 0x46, 0x92, 0x06, 0x40, 0x33, ++0x00, 0xE1, 0x02, 0xB4, 0x07, 0x90, 0x26, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, 0x79, 0x00, 0xF7, 0x09, 0x9C, 0x06, ++0xB0, 0x1E, 0xC0, 0x7F, 0x45, 0xE2, 0x15, 0xAC, 0x07, 0xF0, 0x1A, 0xC0, 0x6B, ++0x20, 0xBF, 0x01, 0x8C, 0x06, 0xA0, 0x1A, 0xC0, 0x7B, 0x05, 0xA3, 0x01, 0xFC, ++0x07, 0xB0, 0x1E, 0xC0, 0x53, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0xB8, 0x31, 0x00, 0xDF, 0x0C, 0x5C, 0x02, 0xF1, 0x01, 0xC0, 0xB7, ++0x01, 0xDF, 0x86, 0x7C, 0x22, 0xF0, 0x09, 0xE0, 0x26, 0x00, 0x1F, 0x00, 0x3C, ++0x02, 0x70, 0x09, 0xC0, 0x37, 0x01, 0xDF, 0x80, 0x7C, 0x02, 0x72, 0x05, 0xC0, ++0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x7D, ++0x00, 0xFF, 0x01, 0xDE, 0x27, 0x70, 0x9B, 0xC0, 0x7F, 0x00, 0xFF, 0x21, 0xDC, ++0x27, 0xF0, 0x1F, 0xC0, 0x6F, 0x00, 0x7B, 0x09, 0xCC, 0x07, 0x30, 0x1F, 0xC0, ++0x7C, 0x26, 0xBF, 0x81, 0xFC, 0x27, 0x31, 0x9F, 0xC0, 0x18, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x39, 0x00, 0xED, 0x00, 0x84, ++0x02, 0xC0, 0x22, 0x42, 0x3B, 0x00, 0xE9, 0x00, 0x80, 0x02, 0xD0, 0x22, 0x40, ++0x3B, 0x00, 0x19, 0x01, 0x94, 0x0A, 0x50, 0x06, 0x40, 0x79, 0x0A, 0xED, 0x00, ++0xB4, 0x33, 0x30, 0x22, 0x40, 0x54, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x88, 0x00, 0x39, 0x00, 0xED, 0x00, 0x94, 0x82, 0x50, 0x02, 0x00, ++0x3B, 0x00, 0xED, 0x08, 0x94, 0x03, 0xD1, 0x0A, 0x40, 0x2B, 0x00, 0x39, 0x10, ++0x24, 0x03, 0xD0, 0x04, 0x40, 0x38, 0x00, 0xAD, 0x00, 0xB4, 0x09, 0x12, 0x0E, ++0x60, 0x61, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x20, ++0x21, 0x00, 0xCD, 0x00, 0x04, 0x02, 0xD0, 0x00, 0x40, 0xF3, 0x00, 0xCD, 0x02, ++0x04, 0x02, 0xD0, 0x08, 0x48, 0x73, 0x84, 0x09, 0x01, 0x34, 0x03, 0xD0, 0x04, ++0x64, 0x31, 0x82, 0xCD, 0x00, 0x34, 0x04, 0x11, 0x00, 0x40, 0x09, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x10, 0xFF, 0x00, ++0x54, 0x03, 0x70, 0x09, 0xC0, 0x3F, 0x03, 0xFF, 0x01, 0x5C, 0x03, 0xF0, 0x09, ++0xC8, 0xA7, 0x01, 0x9B, 0x01, 0x64, 0x02, 0xB0, 0x0D, 0xCC, 0xFC, 0x12, 0x9D, ++0x0A, 0x7C, 0x90, 0x33, 0x19, 0xC2, 0x75, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x0D, 0x00, 0x37, 0x20, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x29, ++0xC0, 0x37, 0x08, 0xDB, 0x18, 0x7E, 0x02, 0xF2, 0x01, 0x40, 0x37, 0x00, 0x1E, ++0x00, 0x5C, 0x0A, 0x38, 0x05, 0xC0, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x08, 0x74, ++0x81, 0x50, 0x16, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, ++0x08, 0x3F, 0x10, 0xDF, 0x00, 0xFC, 0x0B, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xDF, ++0x00, 0xFC, 0x07, 0xF1, 0x0A, 0xC0, 0x2C, 0x40, 0x32, 0x01, 0xFC, 0x02, 0xF2, ++0x1A, 0x80, 0x3C, 0x00, 0xB3, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC1, 0x07, 0x26, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0xDD, ++0x00, 0x64, 0x07, 0xD0, 0x19, 0x42, 0x33, 0x00, 0xD1, 0x80, 0x74, 0x07, 0xD0, ++0x39, 0x40, 0x00, 0x00, 0x11, 0x07, 0x74, 0x00, 0xD0, 0x19, 0xC0, 0x37, 0x00, ++0x9B, 0x18, 0x64, 0x0C, 0xD0, 0x31, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x03, 0xD8, ++0x19, 0x40, 0x37, 0x00, 0xD9, 0x00, 0x74, 0x13, 0xD0, 0x11, 0x40, 0xA6, 0x00, ++0x35, 0x08, 0x74, 0x03, 0xC8, 0x49, 0x46, 0x39, 0x00, 0x91, 0x00, 0x60, 0x04, ++0xD0, 0x19, 0x40, 0x07, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x20, 0x30, 0x00, 0xCD, 0x00, 0x24, 0x02, 0xD8, 0x08, 0x40, 0x37, 0x00, ++0xC1, 0x00, 0x34, 0x82, 0xD0, 0x00, 0x40, 0x30, 0x80, 0x05, 0x00, 0x34, 0x02, ++0xD0, 0x00, 0x40, 0x32, 0x01, 0xC9, 0xA0, 0x24, 0x00, 0xD0, 0x00, 0x40, 0x43, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x98, 0x36, 0x00, ++0xFF, 0x00, 0x7C, 0x03, 0xF0, 0x01, 0xC0, 0x3F, 0x00, 0xFB, 0x00, 0x74, 0x02, ++0xD1, 0x01, 0xC0, 0x24, 0x00, 0x17, 0x04, 0x7C, 0x03, 0xF0, 0x01, 0xC0, 0x3D, ++0x05, 0x13, 0x40, 0x7C, 0x00, 0xF0, 0x01, 0xC2, 0x07, 0x64, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xB8, 0x2F, 0x00, 0xFF, 0x00, 0xEC, 0x02, ++0xF0, 0x03, 0xCC, 0x3F, 0x00, 0xFB, 0x00, 0xF8, 0x02, 0xF2, 0x03, 0x88, 0x1F, ++0x00, 0x1B, 0x16, 0xFC, 0x01, 0xF0, 0x03, 0xC0, 0x37, 0x00, 0x7F, 0x00, 0xFC, ++0x00, 0xF0, 0x03, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xAA, 0x7B, 0x12, 0xEF, 0x09, 0xEC, 0x07, 0xB0, 0x9E, 0xC0, 0x7A, ++0x00, 0xF7, 0x09, 0xEC, 0x07, 0xF0, 0x3F, 0xC0, 0x7B, 0x00, 0xF7, 0x29, 0xCC, ++0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, 0xF3, 0x01, 0xFC, 0xA7, 0xB0, 0x1F, 0xC0, ++0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x07, ++0x00, 0x1D, 0x44, 0x44, 0x04, 0x32, 0x01, 0x40, 0x44, 0x20, 0x11, 0x04, 0x4C, ++0x10, 0x10, 0x01, 0xC0, 0x44, 0x00, 0x11, 0x00, 0x44, 0x10, 0xD0, 0x01, 0x40, ++0x44, 0x10, 0x11, 0x20, 0x74, 0x00, 0x10, 0x11, 0xC0, 0x0E, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x33, 0x11, 0xDD, 0x00, 0x24, ++0x03, 0x91, 0x4D, 0x42, 0x33, 0x00, 0xC5, 0x00, 0x34, 0x43, 0xD0, 0x4C, 0x40, ++0x32, 0x00, 0xC5, 0x44, 0x14, 0x43, 0xD0, 0x0C, 0x62, 0x32, 0x00, 0xC1, 0x80, ++0x34, 0x13, 0x90, 0x0D, 0x42, 0x4D, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA0, 0x05, 0x00, 0x1D, 0x00, 0x54, 0x00, 0x90, 0x01, 0x40, ++0x05, 0x08, 0x01, 0x00, 0x34, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x05, 0x00, ++0x54, 0x00, 0xDA, 0x01, 0x44, 0x04, 0x40, 0x11, 0x00, 0x34, 0x00, 0x11, 0x01, ++0x40, 0x0F, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, ++0x37, 0x08, 0xDF, 0x80, 0x6C, 0x83, 0xB0, 0x0D, 0xC0, 0x37, 0x00, 0xD6, 0x00, ++0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x33, 0x00, 0xD7, 0x00, 0x5C, 0x03, 0xE0, 0x0D, ++0xC0, 0x32, 0x00, 0xD3, 0x00, 0x7C, 0x03, 0xB1, 0x0C, 0xC0, 0x21, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x0D, 0x00, 0x3F, 0x00, ++0xEC, 0x00, 0x70, 0x03, 0xC8, 0x0E, 0x20, 0x3E, 0x00, 0xCC, 0x00, 0xF0, 0x03, ++0xC0, 0x0C, 0x08, 0x3B, 0x00, 0xEC, 0x00, 0xF2, 0x03, 0xC0, 0x0E, 0x00, 0x3F, ++0x00, 0xE4, 0x00, 0xF0, 0x03, 0xC0, 0x1E, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x0A, 0x00, 0x35, 0x20, 0xD7, 0xC8, 0x5C, 0x83, 0xC0, 0x0D, ++0xC0, 0x35, 0x01, 0xD7, 0x00, 0x5C, 0x03, 0xF0, 0x4D, 0xC0, 0x36, 0x00, 0xD7, ++0x00, 0x7C, 0x13, 0x30, 0x4D, 0xC4, 0x36, 0x00, 0xD7, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xD0, 0x28, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0xA0, 0xC4, 0x00, 0x01, 0x83, 0x04, 0x04, 0x10, 0xE0, 0x40, 0x80, 0x00, 0x11, ++0x00, 0x44, 0x00, 0xD0, 0x01, 0x40, 0x07, 0x02, 0x11, 0x00, 0x74, 0x48, 0xB0, ++0x50, 0x40, 0xC7, 0x00, 0x11, 0x00, 0x70, 0x24, 0xD1, 0x01, 0x40, 0x4D, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0xB0, 0x04, 0xC5, ++0x53, 0x14, 0x03, 0x50, 0x0C, 0x42, 0x31, 0x00, 0xC5, 0x00, 0x14, 0x03, 0xD0, ++0x0D, 0x00, 0x32, 0x00, 0xC5, 0x00, 0x34, 0x0F, 0x92, 0x3C, 0x44, 0xB2, 0x09, ++0xC5, 0x00, 0x24, 0x03, 0xD0, 0x0C, 0x40, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x0F, 0x08, 0x4C, 0x06, 0x31, 0x01, 0xC4, 0x04, 0x11, ++0x13, 0x40, 0x48, 0x08, 0x25, 0x01, 0x84, 0x04, 0xD0, 0x12, 0x40, 0x4B, 0x00, ++0x21, 0x01, 0xF4, 0x04, 0xD2, 0x92, 0x40, 0x4B, 0x0C, 0x21, 0x01, 0xB4, 0x14, ++0xD0, 0x92, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x10, 0x30, 0x00, 0xC7, 0x08, 0x1C, 0x63, 0x72, 0x0C, 0xC0, 0x31, 0x02, ++0xD5, 0x00, 0x1C, 0x13, 0xF0, 0x4C, 0xC0, 0x32, 0x01, 0xC7, 0x28, 0x3C, 0x23, ++0xB0, 0x8C, 0xC0, 0x32, 0x00, 0xC6, 0x00, 0x3C, 0x63, 0xF2, 0x8C, 0xC0, 0x4A, ++0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x28, 0x0D, 0x00, ++0x3F, 0x00, 0xBC, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x0A, 0x3B, 0x08, 0xFC, 0x00, ++0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x08, 0xBC, 0xA0, 0xA0, 0x81, 0xC0, 0x0B, ++0x10, 0x1F, 0x00, 0xFC, 0x30, 0xF0, 0x90, 0xC0, 0x09, 0x60, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, 0x00, 0xD3, 0x00, 0x7E, 0x03, ++0x70, 0x0D, 0x80, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x30, ++0x00, 0xDA, 0x00, 0x5C, 0x03, 0xF0, 0x0C, 0xC0, 0x30, 0x00, 0xD3, 0x00, 0x7C, ++0x03, 0x34, 0x0D, 0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0x80, 0x0D, 0x08, 0x20, 0x00, 0xB2, 0x00, 0xD1, 0x02, 0x40, 0x0B, ++0x00, 0x2D, 0x00, 0xB4, 0x00, 0x50, 0x02, 0xC0, 0x09, 0x00, 0x21, 0xA0, 0xB4, ++0x00, 0xD0, 0x02, 0xC4, 0x0A, 0x00, 0x2B, 0x80, 0xB4, 0x00, 0x10, 0x02, 0xC0, ++0x4E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x79, ++0x20, 0xE9, 0x01, 0x94, 0x87, 0xD0, 0x1E, 0x60, 0x7B, 0x00, 0xED, 0x01, 0xF4, ++0x07, 0xD0, 0x1F, 0x40, 0x7B, 0x00, 0xE9, 0x01, 0xB4, 0x07, 0xD0, 0x1F, 0x40, ++0x7E, 0x00, 0xE9, 0x21, 0xB4, 0x07, 0x10, 0x1E, 0x40, 0x10, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x02, 0x00, 0x09, 0x00, 0x34, ++0x00, 0xD2, 0x01, 0x40, 0x03, 0x00, 0x0D, 0x00, 0x74, 0x00, 0xD0, 0x00, 0x40, ++0x01, 0x80, 0x0D, 0x00, 0x34, 0x80, 0xD0, 0x00, 0x40, 0x02, 0x00, 0x09, 0x00, ++0x36, 0x00, 0x10, 0x00, 0x40, 0x5A, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x17, 0xA0, 0x11, 0x00, 0x5B, 0x00, 0x78, 0x01, 0x70, 0x05, 0xE0, ++0x17, 0x00, 0x5F, 0x00, 0x7E, 0x01, 0xB1, 0x04, 0xC0, 0x16, 0x00, 0x5B, 0x20, ++0x5C, 0x01, 0xF0, 0x05, 0xC4, 0x14, 0x00, 0x5B, 0x20, 0x7C, 0x01, 0x30, 0x05, ++0xC0, 0x5C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, ++0x8F, 0x40, 0x37, 0x00, 0xFC, 0x00, 0xF0, 0x03, 0xE0, 0x0F, 0x00, 0x3F, 0x00, ++0xFA, 0x00, 0x70, 0x23, 0xC0, 0x0F, 0x00, 0x33, 0x00, 0xF4, 0x08, 0xF0, 0x23, ++0xC0, 0x8F, 0x00, 0x3F, 0x40, 0xF4, 0x08, 0xF0, 0x03, 0xC0, 0x4B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x01, 0x97, 0x00, ++0x7C, 0x16, 0x50, 0x09, 0xC0, 0x27, 0x10, 0x9F, 0xA0, 0x7C, 0x02, 0x33, 0x09, ++0xC2, 0x25, 0x20, 0x93, 0x40, 0x74, 0x02, 0x02, 0x09, 0x54, 0xA4, 0x00, 0x97, ++0x00, 0x7C, 0x06, 0x32, 0x29, 0xC2, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x20, 0xE6, 0x00, 0x91, 0x05, 0x34, 0x86, 0x10, 0x39, ++0x40, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x50, 0x09, 0x10, 0xA0, 0x04, 0x91, ++0x00, 0x34, 0x06, 0xB2, 0x28, 0x40, 0xE0, 0x08, 0x95, 0x00, 0x30, 0x06, 0x51, ++0x08, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA0, 0x24, 0x00, 0xB5, 0x04, 0xF4, 0x02, 0x50, 0x6B, 0x40, 0x2D, 0x00, 0xBD, ++0x80, 0xD4, 0x82, 0x18, 0x0B, 0x41, 0x2C, 0xC0, 0xB1, 0x00, 0xD4, 0x12, 0x10, ++0x2B, 0x40, 0x2D, 0x90, 0xB0, 0x80, 0xF4, 0x22, 0x12, 0x0B, 0x42, 0x60, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x3D, 0x00, 0xA1, ++0x00, 0xF4, 0x02, 0x50, 0x0A, 0x40, 0x28, 0x20, 0xAC, 0x28, 0xB4, 0x22, 0x50, ++0x0A, 0x40, 0x28, 0x00, 0xA1, 0xC8, 0xF4, 0x03, 0xD0, 0x0A, 0x40, 0x2D, 0x00, ++0xA4, 0x00, 0xF4, 0x23, 0x50, 0x0E, 0x40, 0x41, 0x80, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0x38, 0x06, 0x00, 0x17, 0x80, 0x7C, 0x00, 0x70, ++0x01, 0xC0, 0x07, 0x00, 0x1C, 0x02, 0x7C, 0x08, 0x30, 0x01, 0xC0, 0x05, 0x00, ++0x13, 0x02, 0x5C, 0x00, 0x32, 0xA1, 0xC0, 0x15, 0x00, 0x17, 0x0A, 0x38, 0x08, ++0x30, 0x03, 0xC8, 0x74, 0xE0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xB0, 0x25, 0x05, 0x9F, 0x34, 0x7C, 0x02, 0xB0, 0x49, 0xC1, 0x27, 0x00, ++0x9F, 0x04, 0x2C, 0x12, 0xF0, 0x48, 0xC9, 0x27, 0x00, 0x9F, 0x04, 0x7C, 0x52, ++0xB0, 0x19, 0xC0, 0x26, 0x00, 0x9F, 0x01, 0x7C, 0x12, 0xF0, 0x08, 0xC0, 0x77, ++0x40, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x80, 0x2F, 0x00, ++0xBF, 0x08, 0xDC, 0x02, 0xF8, 0x0B, 0xC2, 0x2F, 0x00, 0x8F, 0x02, 0x7C, 0x02, ++0x34, 0x0B, 0xC0, 0x2C, 0x00, 0x93, 0x00, 0xFC, 0x0A, 0x30, 0x0B, 0xC0, 0x2C, ++0x40, 0x83, 0x00, 0xCC, 0x02, 0xB0, 0x0B, 0xC0, 0x74, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x47, 0x01, 0x1D, 0x25, 0x44, 0x00, ++0xD1, 0x41, 0x41, 0x07, 0x00, 0x1D, 0x04, 0x74, 0x80, 0x10, 0x01, 0x42, 0x05, ++0x08, 0x11, 0x00, 0x74, 0x00, 0xB0, 0x01, 0x42, 0x04, 0x00, 0x11, 0x40, 0x44, ++0x00, 0x11, 0x01, 0x40, 0x61, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x31, 0x15, 0x8D, 0x44, 0x10, 0x02, 0xD8, 0x0C, 0x40, 0x23, ++0x00, 0x8D, 0x04, 0x34, 0x42, 0x10, 0x09, 0x40, 0x20, 0x00, 0x81, 0x14, 0x34, ++0x02, 0x10, 0x08, 0x50, 0x20, 0x80, 0x81, 0x20, 0x15, 0x02, 0xD0, 0x09, 0x40, ++0x48, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x2A, 0x25, ++0x00, 0x9D, 0x00, 0x44, 0x82, 0xD0, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, ++0x02, 0x11, 0x09, 0x40, 0x25, 0x20, 0x91, 0x00, 0x74, 0x02, 0x90, 0x08, 0x60, ++0x24, 0x00, 0x91, 0x00, 0x54, 0x02, 0xD0, 0x09, 0x40, 0x61, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x22, 0x25, 0x10, 0x9F, 0x00, 0x5C, ++0x02, 0xD0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x09, 0xC0, ++0x20, 0x08, 0x93, 0x80, 0x7C, 0x02, 0x30, 0x09, 0xC0, 0x20, 0x00, 0x93, 0x00, ++0x5C, 0x82, 0xF0, 0x09, 0xC0, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x16, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x40, 0x9F, 0x00, ++0x7C, 0x02, 0xF0, 0x09, 0xC1, 0x27, 0x04, 0x9F, 0x00, 0x6C, 0x42, 0x30, 0x09, ++0x40, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, ++0x05, 0x00, 0x17, 0x00, 0x4C, 0x00, 0xF0, 0x41, 0xC4, 0x07, 0x01, 0x17, 0x00, ++0x4C, 0x00, 0x70, 0x01, 0xC3, 0x07, 0x00, 0x1F, 0x00, 0x5C, 0x40, 0xB0, 0x01, ++0xC0, 0x04, 0x00, 0x1F, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC1, 0x51, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1C, 0x02, 0x7D, 0xD8, ++0x44, 0x01, 0x70, 0x27, 0x40, 0x9F, 0x00, 0x51, 0x20, 0x6C, 0x01, 0xD0, 0x76, ++0x42, 0xDF, 0x00, 0x5D, 0x40, 0xEC, 0x0D, 0x11, 0x27, 0x40, 0x1C, 0x00, 0x59, ++0x00, 0xD4, 0x01, 0x14, 0x06, 0x50, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0x32, 0x00, 0xD5, 0x40, 0x04, 0x26, 0xD0, 0x0C, ++0x40, 0xA3, 0x00, 0xC5, 0x00, 0x44, 0x03, 0x58, 0x0C, 0x48, 0xF3, 0x03, 0xCD, ++0x00, 0x46, 0x07, 0x90, 0x2C, 0x40, 0x32, 0x00, 0xDD, 0x00, 0x40, 0x0F, 0x00, ++0x3C, 0x40, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x80, 0x38, 0x20, 0xED, 0x40, 0x85, 0x03, 0x58, 0x0E, 0x68, 0xEF, 0x00, 0xF5, ++0x09, 0xA4, 0x23, 0xD0, 0x06, 0x40, 0x3B, 0x00, 0xFD, 0x45, 0xA4, 0x0B, 0x10, ++0x02, 0x41, 0x2A, 0x04, 0xF9, 0x04, 0x96, 0x0B, 0x12, 0x0E, 0x45, 0x10, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x59, 0x00, 0x77, ++0x01, 0x8C, 0x07, 0xF1, 0x1E, 0x40, 0x6B, 0x00, 0xE7, 0x15, 0x8C, 0x07, 0x70, ++0x16, 0x80, 0x7B, 0x00, 0xEF, 0x01, 0xDC, 0x05, 0xB0, 0x1E, 0xD0, 0x5A, 0x08, ++0xEF, 0x07, 0xCC, 0x06, 0x30, 0x1E, 0xC0, 0x51, 0x60, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x15, 0x00, 0x5F, 0x40, 0x7C, 0x83, 0xF0, ++0x0D, 0xC0, 0x23, 0x00, 0xDB, 0x06, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x37, 0x00, ++0xCF, 0x08, 0x7E, 0x83, 0xF0, 0x60, 0xD5, 0x15, 0x20, 0xDB, 0x06, 0x7C, 0x02, ++0xD0, 0x0C, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x06, 0x20, 0x7D, 0x0A, 0xFF, 0x01, 0xDC, 0xA7, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, ++0xE7, 0x01, 0x8C, 0x0F, 0xB0, 0x13, 0xC8, 0x7B, 0x00, 0xF3, 0x03, 0xCC, 0x07, ++0x30, 0x1B, 0xD0, 0x78, 0xA2, 0xFB, 0x03, 0xCC, 0x07, 0xF0, 0x1A, 0xC0, 0x18, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x39, 0x00, ++0xEC, 0x18, 0xB4, 0x83, 0xD0, 0x0E, 0x42, 0x3B, 0x28, 0xE1, 0x10, 0x94, 0x03, ++0x50, 0x22, 0x44, 0x3B, 0x06, 0xE5, 0x00, 0xD4, 0x03, 0x50, 0x43, 0x40, 0x28, ++0x02, 0xE1, 0x04, 0x84, 0x13, 0x71, 0x4A, 0x48, 0x54, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x02, 0x39, 0x10, 0xED, 0x00, 0x94, 0x03, ++0xC0, 0x06, 0x40, 0x3B, 0x04, 0xF5, 0x00, 0xE4, 0x43, 0x10, 0x02, 0x40, 0x3F, ++0x00, 0xFD, 0x00, 0xD4, 0x01, 0x50, 0x0A, 0x61, 0x18, 0x84, 0xE1, 0xB0, 0x84, ++0x42, 0xD2, 0x0A, 0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x28, 0x65, 0x00, 0x8D, 0x00, 0x36, 0x13, 0xD0, 0x39, 0x40, 0xF3, ++0x00, 0xC5, 0x03, 0x34, 0x0B, 0x50, 0xA0, 0x40, 0xF3, 0x00, 0xDD, 0x02, 0x14, ++0x2A, 0x50, 0x38, 0x62, 0x40, 0x04, 0xC9, 0x53, 0x05, 0x04, 0x50, 0x28, 0x40, ++0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xA0, 0xE5, ++0x10, 0x9F, 0x01, 0x5C, 0x43, 0xD0, 0xA1, 0xC4, 0x07, 0x02, 0xF7, 0x01, 0xEC, ++0x07, 0x30, 0xB1, 0xC8, 0xB7, 0x00, 0xFF, 0x01, 0x5E, 0x0E, 0x10, 0x99, 0xC4, ++0x44, 0x00, 0xEB, 0x00, 0x0C, 0x81, 0xF3, 0x3D, 0xC6, 0x54, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x27, 0x06, 0x9F, 0x04, 0x7C, ++0x03, 0xF0, 0x81, 0xC0, 0xA7, 0x10, 0xDA, 0x00, 0x5C, 0x43, 0x78, 0x21, 0x80, ++0x37, 0x0C, 0xD7, 0xB8, 0x78, 0x00, 0xF0, 0x09, 0xC0, 0xA7, 0x40, 0xD7, 0x00, ++0x7C, 0x81, 0x70, 0xAD, 0xC1, 0x37, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x81, 0x08, 0x0F, 0x00, 0x3B, 0x00, 0xFC, 0x03, 0xF0, 0x0B, 0xC0, ++0x0E, 0x00, 0xF3, 0x10, 0xCC, 0x03, 0xF0, 0x03, 0x40, 0x3E, 0x00, 0xF3, 0x00, ++0xFC, 0x40, 0xF0, 0x0B, 0xC0, 0x0C, 0x00, 0xF7, 0x00, 0xD4, 0x54, 0x30, 0x0F, ++0xC0, 0x04, 0x28, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, ++0xC6, 0x00, 0x11, 0x03, 0x74, 0x03, 0xD0, 0x19, 0x40, 0x60, 0x01, 0xDB, 0x00, ++0x54, 0x03, 0xD0, 0x11, 0x40, 0xD3, 0x00, 0xDB, 0x00, 0x44, 0x0C, 0xD0, 0x18, ++0xC0, 0x83, 0x20, 0xD1, 0x00, 0x54, 0x89, 0x51, 0x4C, 0x50, 0x84, 0x04, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xC6, 0x00, 0x19, 0x03, ++0x74, 0x13, 0xD8, 0x31, 0x40, 0x66, 0x00, 0xC1, 0x80, 0x44, 0x03, 0xD0, 0x11, ++0x40, 0x66, 0x04, 0xD1, 0x00, 0x44, 0xC6, 0x90, 0x1B, 0x40, 0x04, 0x06, 0xF5, ++0x00, 0x40, 0x09, 0x50, 0x45, 0x48, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x81, 0x00, 0x34, 0x83, 0xD0, 0x00, ++0x40, 0x24, 0x00, 0xCD, 0x00, 0x14, 0x03, 0xD0, 0x00, 0x40, 0x27, 0x00, 0xC9, ++0x00, 0x04, 0x82, 0xC2, 0x19, 0x40, 0x02, 0xA0, 0xD1, 0x40, 0x54, 0x02, 0x50, ++0x04, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x18, 0x06, 0x10, 0x1B, 0x00, 0x7C, 0x03, 0xDA, 0x01, 0xC0, 0x26, 0x00, 0xF3, ++0x00, 0xC4, 0x03, 0xF0, 0x01, 0xC4, 0x26, 0x00, 0xF3, 0x00, 0x5D, 0x00, 0xF0, ++0x0B, 0xC0, 0x04, 0x00, 0xE7, 0x00, 0x5C, 0x00, 0x30, 0x09, 0xD0, 0x04, 0x60, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xB8, 0x2F, 0x00, 0xBF, ++0x00, 0xFC, 0x03, 0xD0, 0x0B, 0xC0, 0x2B, 0x00, 0xFB, 0x00, 0xFC, 0x03, 0xE0, ++0x03, 0xC0, 0x2F, 0x00, 0xEF, 0x00, 0xFC, 0x02, 0xF1, 0x0B, 0xC2, 0x0F, 0x00, ++0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x0B, 0xC4, 0x17, 0x62, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x6F, 0x00, 0xBF, 0x10, 0xFC, 0x05, 0x30, ++0x16, 0xC8, 0x3F, 0x10, 0xFF, 0x14, 0xFC, 0x00, 0x30, 0x17, 0xC0, 0x2C, 0x00, ++0x63, 0x01, 0xFC, 0x0F, 0x30, 0x4B, 0xC0, 0x5F, 0x00, 0xF3, 0x01, 0xBC, 0x02, ++0xB0, 0x1F, 0xC8, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x67, 0x00, 0xDD, 0x01, 0x74, 0x05, 0x00, 0x19, 0x40, 0xFF, 0x30, ++0xFD, 0x03, 0x74, 0x0D, 0x10, 0x1D, 0x42, 0xE4, 0x00, 0x95, 0x01, 0xF4, 0x13, ++0x12, 0x19, 0x40, 0x77, 0x00, 0xF1, 0x41, 0x74, 0x02, 0x50, 0x11, 0x40, 0x0F, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x00, ++0x8D, 0x40, 0x74, 0x00, 0x00, 0x08, 0x40, 0xB3, 0x00, 0xCD, 0x00, 0x14, 0x08, ++0x14, 0x0D, 0x48, 0xB0, 0x10, 0x84, 0x00, 0x34, 0x13, 0x10, 0x8C, 0x40, 0x23, ++0x00, 0xC1, 0x00, 0x54, 0x02, 0x90, 0x0C, 0x40, 0x4F, 0x80, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA8, 0x35, 0x00, 0x9D, 0x00, 0x74, 0x10, ++0x18, 0x09, 0x40, 0x37, 0x20, 0xDD, 0x00, 0x76, 0x23, 0x10, 0x0D, 0x48, 0x30, ++0x00, 0x91, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x04, 0x23, 0x00, 0xD1, 0x40, 0x74, ++0x06, 0x50, 0x0D, 0x42, 0x0F, 0xA0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA0, 0x77, 0x00, 0x9F, 0x01, 0x3C, 0x09, 0x30, 0x0D, 0xC2, 0x37, ++0x00, 0xDF, 0x60, 0x5C, 0x13, 0x31, 0x08, 0xC8, 0x64, 0x02, 0xD3, 0x00, 0x7C, ++0x03, 0x34, 0x0D, 0xC0, 0xD7, 0x00, 0xD3, 0x00, 0x7C, 0x17, 0xB2, 0x6D, 0xC0, ++0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x88, 0x3D, ++0x21, 0x9F, 0x04, 0xFC, 0x45, 0xF4, 0x0B, 0xC2, 0x3F, 0x00, 0xFF, 0x00, 0xFC, ++0x03, 0xF0, 0x2B, 0xD0, 0x3F, 0x40, 0xFD, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x7F, 0x01, 0xFF, 0x80, 0xFC, 0x03, 0xF1, 0x23, 0xC0, 0x1F, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x01, 0x9F, 0x00, 0x5C, ++0x09, 0xB8, 0x0D, 0xC1, 0x34, 0x00, 0xDB, 0x50, 0x7C, 0x01, 0xB0, 0x0D, 0xC0, ++0x27, 0x80, 0x9E, 0x04, 0x0C, 0x03, 0xD0, 0x0D, 0xC4, 0xB7, 0x08, 0xDF, 0x40, ++0x7C, 0x13, 0x32, 0x0D, 0xC2, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x13, 0x80, 0x34, 0x00, 0x9D, 0x00, 0x44, 0x0D, 0xF0, 0x29, 0x40, ++0x3C, 0x00, 0xFD, 0x01, 0x34, 0x0B, 0x10, 0x0D, 0x48, 0x37, 0x80, 0x9F, 0x12, ++0x44, 0x2B, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xDD, 0x11, 0x34, 0x03, 0xB0, 0x1D, ++0x41, 0x6F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, ++0x30, 0x00, 0x8D, 0x00, 0x14, 0x0C, 0xD0, 0xB4, 0x50, 0x70, 0x01, 0xCD, 0x02, ++0x20, 0x10, 0x92, 0x00, 0x4C, 0x23, 0x00, 0x4D, 0x01, 0x24, 0x23, 0xD0, 0x08, ++0x40, 0x23, 0x00, 0xCD, 0x00, 0x34, 0x08, 0x1C, 0x0C, 0x40, 0x0F, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x78, 0x00, 0xED, 0x01, ++0x84, 0x44, 0x50, 0x1B, 0x40, 0x78, 0x00, 0xED, 0x01, 0x34, 0x06, 0x10, 0x1A, ++0x40, 0x7B, 0x00, 0xB5, 0x09, 0xA6, 0x97, 0xD0, 0x1A, 0x40, 0x6B, 0x00, 0xED, ++0x01, 0xF4, 0x86, 0x90, 0x12, 0x40, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x18, 0x30, 0x04, 0xCF, 0x08, 0x1C, 0x00, 0xDA, 0x08, ++0xC8, 0x30, 0x14, 0xCB, 0x10, 0x2C, 0x20, 0xB0, 0x48, 0xC0, 0x23, 0x02, 0x8D, ++0x00, 0x2C, 0x23, 0xF0, 0x8C, 0x40, 0xA3, 0x00, 0xCF, 0x8C, 0x3E, 0x00, 0x30, ++0x0C, 0xC0, 0x4B, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x38, 0x3D, 0x00, 0xFF, 0x00, 0xFC, 0x00, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xFF, ++0x12, 0xF4, 0x23, 0xF0, 0x0B, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xDD, 0x37, 0xF0, ++0x0F, 0x00, 0x2F, 0x00, 0xDF, 0x29, 0x7E, 0x22, 0xF4, 0x0F, 0xC0, 0x0B, 0x60, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x33, 0x00, 0xD3, ++0x48, 0x7C, 0x00, 0x60, 0x0C, 0xC0, 0xB4, 0x04, 0xDF, 0x04, 0x5C, 0x00, 0xF0, ++0x09, 0xC0, 0x24, 0x00, 0xD7, 0x01, 0x6C, 0x27, 0x30, 0x0D, 0xC0, 0x27, 0x00, ++0xDF, 0x00, 0x7C, 0x00, 0x30, 0x00, 0xC0, 0x40, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x39, 0x00, 0xE1, 0xC0, 0xB4, 0x00, 0xD0, ++0x0A, 0x44, 0x38, 0x00, 0xED, 0x04, 0xB4, 0x02, 0xD0, 0x0A, 0x40, 0x38, 0x00, ++0xED, 0x00, 0x04, 0x13, 0x10, 0x0E, 0x40, 0x2B, 0x00, 0xED, 0x04, 0xB4, 0x02, ++0x50, 0x02, 0x40, 0x4C, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x79, 0x10, 0xE1, 0x05, 0xB4, 0x44, 0xD8, 0x1F, 0x51, 0x78, 0x13, ++0xE9, 0x05, 0x94, 0x25, 0xD0, 0x3A, 0x40, 0xE8, 0x02, 0xAD, 0x01, 0xA4, 0x07, ++0x90, 0x1E, 0x40, 0x6B, 0x04, 0xED, 0x09, 0xF4, 0x0C, 0x10, 0x02, 0x40, 0x10, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x28, 0x33, 0x00, ++0xC1, 0x01, 0x34, 0x16, 0xD0, 0x38, 0x40, 0x30, 0x10, 0xCD, 0x00, 0x34, 0x07, ++0xD0, 0x18, 0x41, 0x70, 0x00, 0x8D, 0x00, 0x04, 0x03, 0x90, 0x9C, 0x40, 0x63, ++0x00, 0xCD, 0x00, 0x34, 0x06, 0x50, 0x8C, 0x40, 0x58, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x20, 0x15, 0x00, 0x43, 0x11, 0xFC, 0x05, ++0xF0, 0x36, 0xC0, 0x14, 0x20, 0x4F, 0x00, 0xDC, 0x15, 0xF1, 0x27, 0xD4, 0x14, ++0x00, 0x77, 0x1B, 0x6C, 0x01, 0xB5, 0x15, 0xC0, 0x1F, 0x00, 0x5F, 0x00, 0xBC, ++0x01, 0x34, 0x37, 0xC4, 0x5C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x08, 0x05, 0x42, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x21, 0xC0, 0x07, ++0x20, 0x1F, 0x00, 0x70, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, ++0x08, 0x71, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x22, 0x7C, 0x00, 0xF0, 0x01, 0xC1, ++0x4B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, ++0x00, 0x93, 0x00, 0x45, 0x06, 0x50, 0x19, 0xD1, 0x24, 0x40, 0x93, 0x08, 0x5C, ++0x42, 0xF0, 0x09, 0x40, 0x22, 0x40, 0x93, 0x02, 0x7C, 0x16, 0xF0, 0x29, 0xC0, ++0x27, 0x00, 0x93, 0x82, 0x7C, 0x06, 0x34, 0x09, 0xC0, 0x43, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x20, 0x00, 0xB1, 0x03, 0x44, ++0x02, 0xD0, 0x29, 0x40, 0x20, 0x13, 0x91, 0x40, 0xC4, 0x02, 0xD0, 0x09, 0x40, ++0x2C, 0x00, 0x91, 0x40, 0xF4, 0x0E, 0xD0, 0x09, 0x40, 0x22, 0x20, 0xB1, 0x83, ++0x74, 0x06, 0x10, 0x09, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x24, 0x40, 0x91, 0x08, 0x54, 0x1B, 0xD0, 0x69, 0x40, ++0x24, 0x00, 0x91, 0x50, 0x50, 0x1A, 0xD0, 0x08, 0x40, 0x27, 0x00, 0x91, 0x00, ++0x74, 0x0A, 0xD8, 0x09, 0x40, 0x27, 0x00, 0x91, 0x40, 0x74, 0x52, 0x10, 0x09, ++0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, ++0x21, 0x00, 0x81, 0x00, 0x04, 0x02, 0xD0, 0x08, 0x40, 0x20, 0x00, 0x80, 0x00, ++0x04, 0x02, 0xD0, 0x28, 0x40, 0xA0, 0x00, 0x81, 0x00, 0x34, 0x0A, 0x80, 0x08, ++0x40, 0xA6, 0x00, 0x81, 0x00, 0x74, 0x02, 0x14, 0x08, 0x40, 0x43, 0x80, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB8, 0x07, 0x00, 0x53, 0x01, ++0x5C, 0x00, 0x70, 0x01, 0xC0, 0x04, 0x05, 0x12, 0x14, 0x5C, 0x04, 0xF0, 0x00, ++0xC0, 0x47, 0x00, 0x13, 0x00, 0x7C, 0x04, 0xF0, 0x11, 0xC0, 0x07, 0x40, 0x53, ++0x81, 0x7C, 0x00, 0x34, 0x01, 0xC0, 0x77, 0xE0, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xB8, 0x2F, 0x00, 0xBF, 0x02, 0xFC, 0x02, 0xF0, 0x0B, ++0xC0, 0x27, 0x08, 0x9F, 0x40, 0xFC, 0x0A, 0xF1, 0x1B, 0xC0, 0xEF, 0x00, 0xEF, ++0x00, 0x7C, 0x0E, 0xF0, 0x2B, 0x00, 0x6E, 0x20, 0x9F, 0x82, 0xBC, 0x5A, 0xE0, ++0x0B, 0xC0, 0x77, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xA0, 0x29, 0x00, 0xBF, 0x01, 0xCC, 0x02, 0x34, 0x0B, 0xD0, 0x2C, 0x40, 0xA3, ++0x00, 0xBC, 0x46, 0xB0, 0x09, 0x40, 0x67, 0x00, 0xBB, 0x00, 0xC4, 0x16, 0x24, ++0x5B, 0xC0, 0xA7, 0x10, 0xB3, 0x15, 0xCD, 0x42, 0xB0, 0x0B, 0xC0, 0x74, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x07, 0x00, 0x1D, ++0x00, 0x44, 0x00, 0x10, 0x05, 0x40, 0x85, 0x02, 0x11, 0x40, 0x74, 0x08, 0x30, ++0x55, 0x41, 0xC3, 0x01, 0x11, 0x00, 0x54, 0x14, 0x10, 0x01, 0x40, 0x47, 0x08, ++0x11, 0x02, 0x44, 0x08, 0x11, 0x01, 0x40, 0x60, 0x00, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x22, 0x21, 0x00, 0x8D, 0x02, 0x14, 0x02, 0x90, ++0x08, 0x68, 0x20, 0x00, 0x81, 0x02, 0x34, 0x02, 0x90, 0x08, 0x40, 0xA3, 0x04, ++0x99, 0x00, 0x04, 0x4A, 0x10, 0x28, 0x40, 0x23, 0x00, 0x81, 0x20, 0x04, 0x52, ++0x91, 0x09, 0x42, 0x48, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0x28, 0x25, 0x00, 0x9D, 0x00, 0x44, 0x02, 0x10, 0x09, 0x64, 0x24, 0x00, ++0x90, 0x00, 0x74, 0x06, 0x10, 0x89, 0x4C, 0x27, 0x00, 0x91, 0x00, 0x14, 0x02, ++0x10, 0x09, 0x40, 0x23, 0x40, 0x91, 0x00, 0x44, 0x02, 0x90, 0x19, 0x40, 0x60, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x65, 0x02, ++0x8F, 0x09, 0x5C, 0x12, 0xB0, 0x18, 0x40, 0x24, 0x00, 0x93, 0x00, 0x7C, 0x4A, ++0xB0, 0x3B, 0xC0, 0x6F, 0x00, 0x9B, 0x00, 0xCC, 0x02, 0x30, 0x19, 0xC0, 0xEF, ++0x01, 0x93, 0x80, 0x4C, 0x02, 0xB0, 0x49, 0xD0, 0x14, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x6D, 0x12, ++0xF0, 0x59, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x70, 0x09, 0xC0, 0x23, ++0x01, 0x9F, 0x02, 0x7C, 0x02, 0xF0, 0x89, 0xC0, 0x67, 0x01, 0x9F, 0x00, 0x7C, ++0x02, 0x71, 0x09, 0xC0, 0x5B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x08, 0x05, 0x10, 0x13, 0x08, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x05, ++0xC1, 0x13, 0x08, 0x1C, 0x10, 0x34, 0x01, 0xC0, 0x07, 0x00, 0x1B, 0x00, 0x7C, ++0x00, 0x30, 0x01, 0xC0, 0x87, 0x00, 0x1F, 0x08, 0x7C, 0x00, 0x31, 0x01, 0xC0, ++0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0xDC, ++0x06, 0x71, 0x00, 0xB0, 0x1D, 0x50, 0x07, 0x42, 0x1B, 0x80, 0x71, 0x01, 0xC4, ++0x0D, 0x10, 0x05, 0x40, 0x17, 0x00, 0x71, 0x02, 0xF4, 0x61, 0xB0, 0x05, 0x40, ++0x17, 0x00, 0x6D, 0x00, 0xF4, 0x01, 0x11, 0x04, 0x40, 0x43, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0xE2, 0x00, 0x81, 0x10, 0x34, ++0x1E, 0x18, 0x04, 0x40, 0x23, 0x10, 0x85, 0x51, 0x14, 0x0D, 0x10, 0x0C, 0x40, ++0x33, 0x00, 0xD9, 0x13, 0x34, 0x06, 0x14, 0x1C, 0x40, 0x33, 0x00, 0x8D, 0x10, ++0x74, 0x02, 0x10, 0x08, 0x40, 0x43, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x82, 0x7C, 0x00, 0xA1, 0x00, 0xF4, 0x03, 0x50, 0x06, 0x40, ++0x33, 0x00, 0xA5, 0x01, 0x84, 0x09, 0x11, 0x4E, 0x40, 0x3B, 0x03, 0xE1, 0x02, ++0xB4, 0x33, 0x90, 0x0E, 0x61, 0x3B, 0x09, 0xED, 0x00, 0xB4, 0x02, 0x10, 0x0E, ++0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x18, ++0x68, 0x00, 0xA3, 0x01, 0xBC, 0x06, 0x30, 0x16, 0xC0, 0x6B, 0x00, 0xE5, 0x01, ++0x9C, 0x05, 0x30, 0x3E, 0xC0, 0x7B, 0x00, 0xEB, 0x01, 0xBC, 0x07, 0x30, 0x1E, ++0xC0, 0xFB, 0x00, 0xAF, 0x01, 0x3C, 0x01, 0x30, 0x1A, 0xC0, 0x53, 0x60, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x40, 0x9D, 0x00, ++0x3C, 0x02, 0xF0, 0x05, 0xC0, 0x27, 0x00, 0xDB, 0x00, 0x7C, 0x01, 0xF0, 0x0D, ++0xC0, 0x37, 0x00, 0xDF, 0x00, 0x3C, 0x03, 0x70, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x28, 0x6D, 0x00, 0xBB, 0x21, 0xFC, 0x06, 0xF0, 0x17, ++0xC0, 0x6F, 0x00, 0xB3, 0x01, 0xDE, 0x07, 0x31, 0x9E, 0xC8, 0x7C, 0x00, 0xAE, ++0x01, 0xEC, 0x07, 0xF8, 0x9F, 0xC0, 0x78, 0x00, 0xB3, 0x41, 0xCC, 0x06, 0x30, ++0x1B, 0xC0, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0x10, 0x29, 0x00, 0xAD, 0x08, 0xB4, 0x03, 0xD0, 0x06, 0x40, 0x3B, 0x08, 0xA1, ++0x00, 0x84, 0x13, 0xB0, 0x0E, 0x40, 0x38, 0x00, 0xED, 0x02, 0x84, 0x03, 0xD0, ++0x0E, 0xC0, 0x3A, 0x02, 0xA1, 0x00, 0x94, 0x02, 0xB0, 0x0E, 0x44, 0x54, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x29, 0x00, 0xAD, ++0x00, 0xB4, 0x02, 0xD0, 0x06, 0x40, 0x23, 0x00, 0xA1, 0x00, 0xD4, 0x01, 0x11, ++0x1F, 0x00, 0x78, 0x00, 0xED, 0x00, 0xA4, 0x03, 0xD0, 0x0E, 0x44, 0x7C, 0x00, ++0x81, 0x00, 0x84, 0x01, 0x50, 0x0B, 0x40, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x21, 0x00, 0x8D, 0x01, 0x34, 0x41, 0xD0, ++0x04, 0x40, 0x03, 0x00, 0x41, 0x00, 0x04, 0x33, 0x90, 0x2C, 0x41, 0x30, 0x20, ++0xCD, 0x0C, 0x04, 0x01, 0xD0, 0x0C, 0x40, 0x32, 0x04, 0xC1, 0x00, 0x54, 0x03, ++0xD0, 0x3C, 0x40, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xA8, 0x25, 0x10, 0xDF, 0x11, 0x7C, 0x8A, 0xF0, 0x8D, 0xC1, 0x27, 0x00, ++0x93, 0x00, 0x5C, 0x05, 0x31, 0x0D, 0xD0, 0x34, 0x01, 0x4F, 0x02, 0x6C, 0x01, ++0xF1, 0x0C, 0xC0, 0xB4, 0x40, 0x93, 0x00, 0x4C, 0xAA, 0x70, 0x29, 0xC0, 0x74, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x37, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x25, 0xC0, 0x37, 0x00, 0x8F, 0x00, 0x7E, 0x01, ++0xF0, 0x0D, 0xC0, 0x37, 0x00, 0xDF, 0x80, 0x7C, 0x09, 0xF0, 0x0D, 0xC0, 0x37, ++0x08, 0xDF, 0x00, 0x7C, 0x02, 0xB0, 0x89, 0xC0, 0x17, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x08, 0x6F, 0x00, 0xAF, 0x00, 0xDC, 0x02, ++0x34, 0x1F, 0x00, 0x6F, 0x00, 0xDF, 0x00, 0xEC, 0x89, 0xF1, 0x0F, 0xC0, 0x3F, ++0x00, 0x7F, 0x00, 0xCC, 0x01, 0x70, 0x4D, 0xD0, 0x3C, 0x00, 0xBF, 0x00, 0xCD, ++0x00, 0x34, 0x0B, 0xC1, 0x07, 0x26, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA1, 0x20, 0x36, 0x10, 0x9D, 0x03, 0x04, 0x02, 0x10, 0x89, 0x43, 0x37, ++0x00, 0xDD, 0x00, 0x44, 0x05, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xDD, 0x03, 0x44, ++0x19, 0x10, 0x0D, 0x42, 0x34, 0x00, 0xCD, 0x02, 0x44, 0x06, 0x10, 0x19, 0x40, ++0x27, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0xA6, ++0x01, 0xDD, 0x06, 0x54, 0x02, 0x10, 0x0D, 0x40, 0x27, 0x01, 0x9D, 0x00, 0x60, ++0x03, 0xD0, 0x0D, 0x44, 0x37, 0x00, 0xDD, 0x01, 0x04, 0x85, 0x50, 0x0D, 0x40, ++0x34, 0x10, 0x9D, 0x50, 0x44, 0x06, 0x10, 0x49, 0x40, 0x07, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xCD, 0x00, 0x04, ++0x03, 0x10, 0x04, 0x40, 0x33, 0x00, 0x8D, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, ++0x33, 0x80, 0xDD, 0xA0, 0x04, 0x03, 0x10, 0x0C, 0x40, 0x30, 0x00, 0x8D, 0xC0, ++0x44, 0x02, 0x10, 0x08, 0x44, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x18, 0x26, 0x00, 0x5F, 0x00, 0x5C, 0x02, 0x30, 0x0D, 0xC0, ++0x27, 0x00, 0x9F, 0x00, 0x6C, 0x00, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xDF, 0x00, ++0x4C, 0x01, 0x70, 0x09, 0x80, 0x3C, 0x00, 0x1F, 0x00, 0x4C, 0x00, 0x30, 0x09, ++0xC0, 0x07, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, ++0x1F, 0x00, 0x7F, 0x00, 0xFC, 0x01, 0xF0, 0x0B, 0xC0, 0x1F, 0x00, 0x7F, 0x00, ++0xBC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFD, 0x01, 0xD0, 0x0B, ++0xC0, 0x3F, 0x00, 0x7F, 0x00, 0xBC, 0x02, 0xF0, 0x0A, 0xC4, 0x17, 0x62, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xB3, 0x0C, ++0xDC, 0x00, 0x30, 0x4F, 0xC0, 0x3C, 0x01, 0xF3, 0x18, 0xFC, 0x32, 0x70, 0x17, ++0xC0, 0x7F, 0x00, 0x5B, 0x01, 0x8C, 0x06, 0x32, 0x1A, 0xC2, 0x7E, 0x00, 0x3B, ++0x08, 0xCD, 0x00, 0xB0, 0x03, 0xC2, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0x18, 0x37, 0x01, 0x91, 0x8E, 0x44, 0x27, 0x10, 0x3F, ++0x40, 0xBC, 0x40, 0xF5, 0x26, 0x74, 0x38, 0x10, 0x05, 0x44, 0x77, 0x00, 0x53, ++0x01, 0x54, 0x05, 0x52, 0x19, 0x40, 0x55, 0x00, 0x11, 0x06, 0x44, 0x82, 0x10, ++0x01, 0xC0, 0x0E, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0xA0, 0x33, 0x04, 0x81, 0x00, 0x54, 0x03, 0x10, 0x2C, 0x44, 0xB2, 0x05, 0xC1, ++0x00, 0x34, 0x02, 0x50, 0x44, 0x41, 0x31, 0x00, 0x4D, 0x00, 0x54, 0x03, 0x10, ++0x08, 0x40, 0x22, 0x00, 0x89, 0x02, 0x04, 0x21, 0xD0, 0x10, 0x42, 0x4F, 0x80, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x31, 0x00, 0x91, ++0x01, 0x44, 0x07, 0x10, 0x0D, 0x40, 0x36, 0x00, 0xD1, 0x00, 0x74, 0x84, 0x10, ++0x05, 0x41, 0x37, 0x01, 0x51, 0x01, 0x54, 0x09, 0x50, 0x1D, 0x00, 0x35, 0x00, ++0x11, 0x02, 0x44, 0x83, 0x51, 0x11, 0x40, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x36, 0x00, 0x13, 0x07, 0x10, 0x17, 0x30, ++0x0D, 0xC0, 0x36, 0x08, 0xD3, 0x40, 0x7C, 0x44, 0x50, 0xB1, 0xE0, 0x35, 0x20, ++0x5B, 0x07, 0x5C, 0x0B, 0x30, 0x18, 0x80, 0x36, 0x00, 0x1B, 0x02, 0x4C, 0x28, ++0xF4, 0x19, 0xC0, 0x2B, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x0F, 0x80, 0x3D, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF4, 0x0F, 0xC0, 0x39, 0x00, ++0xDF, 0x00, 0x7C, 0x40, 0xF0, 0x13, 0xC0, 0x7F, 0x00, 0x79, 0x10, 0xFC, 0x13, ++0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0x5F, 0x02, 0xBC, 0x04, 0xB0, 0x02, 0xC0, 0x1E, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, ++0x1F, 0x04, 0x4C, 0x03, 0x70, 0x0C, 0xE1, 0x35, 0x04, 0xD7, 0x08, 0x4C, 0x02, ++0x70, 0x25, 0xC0, 0x37, 0x00, 0x57, 0x02, 0x5C, 0x0B, 0xB0, 0x49, 0xC0, 0x34, ++0x00, 0x5B, 0x00, 0x4C, 0x49, 0x34, 0x09, 0xC0, 0x2B, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xA0, 0x34, 0x00, 0x9D, 0x00, 0x44, 0x03, ++0x11, 0x1F, 0xC4, 0xFC, 0x04, 0xF1, 0x00, 0x44, 0x10, 0x10, 0x05, 0x40, 0x70, ++0x00, 0x4B, 0x41, 0x68, 0x2F, 0xB0, 0x2D, 0x40, 0xB0, 0x01, 0x51, 0x00, 0x44, ++0x89, 0x00, 0x19, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x20, 0x32, 0x00, 0x1D, 0x00, 0x34, 0x83, 0x50, 0x1C, 0x40, 0x73, ++0x80, 0xC1, 0x26, 0x64, 0x0E, 0x10, 0x00, 0x48, 0x31, 0x00, 0xC5, 0x03, 0x70, ++0x0F, 0x90, 0x00, 0x48, 0x31, 0x21, 0x59, 0x0F, 0x04, 0x24, 0x10, 0x08, 0x60, ++0x0F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x7A, ++0x80, 0x6D, 0x51, 0x95, 0x47, 0x10, 0x9E, 0x41, 0x70, 0x80, 0xE1, 0x81, 0xA6, ++0x07, 0x14, 0x12, 0x00, 0x78, 0x00, 0x69, 0x05, 0xB4, 0x47, 0x99, 0xDA, 0x40, ++0x5D, 0x00, 0xA1, 0x49, 0x04, 0x26, 0x10, 0x32, 0x41, 0x37, 0x20, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x32, 0x00, 0xCF, 0x20, 0x1C, ++0x03, 0x50, 0x8C, 0x40, 0x33, 0x00, 0xC1, 0x00, 0x2C, 0x13, 0x30, 0x41, 0xC0, ++0x33, 0x24, 0x47, 0x15, 0x3C, 0x03, 0xB0, 0x5C, 0xC8, 0x21, 0x08, 0x8B, 0x05, ++0x0D, 0x08, 0x30, 0x0C, 0xC0, 0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0xB8, 0x3D, 0x20, 0xFF, 0x00, 0xE8, 0x03, 0xF0, 0xAE, 0xC0, ++0x3F, 0x40, 0xFB, 0x00, 0xDD, 0x03, 0xF1, 0x03, 0xC0, 0x3B, 0x00, 0x45, 0x80, ++0xEC, 0x03, 0xF0, 0x0D, 0xC0, 0x3A, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0xF4, 0x8F, ++0xC0, 0x0B, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, ++0x77, 0x20, 0x53, 0x20, 0x7E, 0x83, 0xF0, 0xCD, 0xC0, 0x34, 0x11, 0xDF, 0x44, ++0x5C, 0x01, 0xF0, 0x11, 0xC0, 0x32, 0x00, 0x1B, 0x00, 0x1C, 0x03, 0x70, 0x0D, ++0xC2, 0x36, 0x00, 0xDF, 0x00, 0x4D, 0x03, 0x30, 0x0D, 0xC2, 0x40, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x98, 0x3D, 0x00, 0x61, 0x00, ++0xB4, 0x83, 0x14, 0x0E, 0x40, 0xB8, 0x05, 0xFD, 0x16, 0x84, 0x03, 0xD0, 0x02, ++0x40, 0x38, 0x80, 0x27, 0x40, 0x84, 0x03, 0x11, 0x0E, 0x40, 0x18, 0x00, 0xED, ++0x00, 0x85, 0x03, 0x10, 0x07, 0x40, 0x4C, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0xE1, 0x01, 0xF6, 0x87, 0xD2, 0x4E, ++0x40, 0x7B, 0x00, 0xED, 0x01, 0x94, 0x07, 0xD0, 0x33, 0x40, 0x7B, 0x00, 0x31, ++0x01, 0x94, 0x07, 0x58, 0x1F, 0x41, 0x7A, 0x00, 0xED, 0x01, 0x04, 0x07, 0x54, ++0x1E, 0x40, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x20, 0x33, 0x00, 0xC1, 0x43, 0x36, 0x03, 0x10, 0x0C, 0x40, 0x30, 0x00, 0xDD, ++0x00, 0x44, 0x1F, 0xD0, 0x48, 0x60, 0x21, 0x02, 0x05, 0x01, 0x06, 0x0F, 0x10, ++0x3C, 0x40, 0x72, 0x00, 0xCD, 0x19, 0x04, 0x23, 0x50, 0x2D, 0x40, 0x58, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x17, 0x00, 0x71, ++0x05, 0xFC, 0x49, 0xF0, 0x05, 0xC0, 0x16, 0x00, 0x5F, 0x00, 0xDC, 0x0D, 0xF0, ++0x17, 0xC0, 0x17, 0x00, 0x63, 0x02, 0x9C, 0x6D, 0x70, 0x27, 0xE0, 0x1E, 0x09, ++0x7F, 0x02, 0xCC, 0x25, 0x70, 0x87, 0xC0, 0x5C, 0x20, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x40, 0x1F, 0x30, 0x7C, 0x10, 0x74, ++0x01, 0xC0, 0x87, 0x00, 0x1F, 0x00, 0x7E, 0x28, 0xF0, 0x01, 0xC0, 0x06, 0x08, ++0x17, 0x58, 0x7C, 0x00, 0xF0, 0x61, 0xC0, 0x85, 0x00, 0x1E, 0x82, 0x3C, 0x00, ++0x90, 0x21, 0xD0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x30, 0x19, 0xC0, 0x67, 0x01, ++0x9F, 0x01, 0x68, 0x06, 0x32, 0x09, 0xC2, 0x27, 0x00, 0x92, 0x20, 0x5C, 0x06, ++0x70, 0x19, 0xD0, 0x24, 0x00, 0x8A, 0x05, 0x44, 0x02, 0x70, 0x09, 0xC2, 0x40, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, ++0x9D, 0x11, 0x34, 0x02, 0x10, 0x59, 0x40, 0xE7, 0x00, 0x9D, 0x8B, 0x44, 0x06, ++0x10, 0x09, 0x40, 0x23, 0x00, 0x91, 0x08, 0x44, 0x8A, 0x10, 0x88, 0x40, 0xE4, ++0x20, 0x9D, 0x07, 0x44, 0x0A, 0x50, 0x29, 0x40, 0x04, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x24, 0x00, 0x9D, 0x08, 0x74, 0x12, ++0x50, 0x89, 0x42, 0x27, 0x04, 0x9D, 0x00, 0x74, 0x52, 0x50, 0x09, 0x48, 0x27, ++0x40, 0x9D, 0x90, 0x54, 0xA2, 0x53, 0x0D, 0x61, 0x64, 0x00, 0x98, 0x00, 0x54, ++0x2A, 0x51, 0x39, 0x40, 0x70, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x28, 0x20, 0x00, 0x8D, 0x14, 0x74, 0x52, 0x15, 0x48, 0x41, 0x23, ++0x25, 0xCD, 0x14, 0x14, 0x52, 0x50, 0x08, 0x40, 0x23, 0x00, 0x95, 0x00, 0x04, ++0x02, 0x11, 0x08, 0x60, 0x20, 0x00, 0x8D, 0x08, 0x14, 0x02, 0x50, 0x48, 0x51, ++0x50, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x30, 0x06, ++0x00, 0x1F, 0x04, 0x7C, 0x10, 0x70, 0x41, 0xC8, 0x07, 0x01, 0x1F, 0x04, 0x7C, ++0x10, 0x70, 0x01, 0xC8, 0x07, 0x08, 0x17, 0x00, 0x58, 0x01, 0x72, 0x01, 0xD0, ++0x14, 0x00, 0x0B, 0x16, 0x5C, 0x50, 0x70, 0x41, 0xC0, 0x74, 0xC0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA8, 0x25, 0x05, 0xBF, 0x34, 0xBC, ++0x02, 0xF6, 0x08, 0xC0, 0x27, 0x05, 0x9F, 0x14, 0xE4, 0x52, 0xB4, 0x4A, 0xC1, ++0x2F, 0x10, 0xAB, 0x00, 0xFC, 0x02, 0xF0, 0x0A, 0xC0, 0x2F, 0x00, 0xBF, 0x04, ++0xED, 0x52, 0xF0, 0x4B, 0xC1, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x27, 0x00, 0xBF, 0x11, 0xBC, 0x02, 0xC4, 0x0B, 0xC0, ++0x6E, 0x01, 0xBF, 0x54, 0xFC, 0x32, 0xF0, 0x09, 0xC8, 0x29, 0x90, 0xB3, 0x00, ++0xAD, 0x02, 0xB0, 0x0B, 0xC0, 0x2C, 0x00, 0xB7, 0x00, 0xCC, 0x12, 0x36, 0x0F, ++0xC0, 0x63, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, ++0x47, 0x05, 0x1D, 0x87, 0x74, 0x00, 0x10, 0x81, 0x40, 0x07, 0x05, 0x1D, 0x04, ++0x7C, 0x30, 0xD0, 0x05, 0x40, 0x07, 0x80, 0x55, 0x40, 0x44, 0x00, 0x12, 0x05, ++0x54, 0x04, 0x00, 0x11, 0x00, 0x45, 0x28, 0x54, 0x01, 0x40, 0x73, 0x60, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xA0, 0x21, 0x00, 0xCD, 0x10, ++0x74, 0x27, 0xC0, 0x0C, 0x40, 0xA3, 0x00, 0x8D, 0x14, 0x34, 0x13, 0xD2, 0x08, ++0x40, 0x27, 0x00, 0x81, 0x00, 0x24, 0x03, 0x90, 0x09, 0x40, 0x24, 0x00, 0x85, ++0x80, 0x04, 0x02, 0x18, 0x08, 0x40, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0x20, 0x25, 0x00, 0x9D, 0x02, 0x76, 0x02, 0x10, 0x09, ++0x40, 0x27, 0x00, 0x9D, 0x00, 0x74, 0x02, 0xC2, 0x09, 0x48, 0x27, 0x01, 0x95, ++0x00, 0x44, 0x22, 0x10, 0x09, 0x44, 0xA4, 0x02, 0x91, 0x00, 0x44, 0x22, 0x50, ++0x09, 0x00, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xA8, 0x27, 0x00, 0x9D, 0x01, 0x3C, 0x0A, 0xF0, 0x09, 0xC0, 0x26, 0x08, 0x9F, ++0x40, 0x7A, 0x42, 0xF0, 0xB9, 0xC0, 0x21, 0x80, 0x91, 0x00, 0x2C, 0x02, 0xB0, ++0x19, 0xC0, 0x64, 0x00, 0x97, 0x04, 0x4C, 0x02, 0x30, 0x49, 0xC0, 0x17, 0x28, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x25, 0x20, 0x9F, ++0x04, 0x7C, 0x16, 0xF4, 0x09, 0xC0, 0x27, 0x0C, 0x9F, 0x20, 0x5E, 0x52, 0xF0, ++0x19, 0xC0, 0x27, 0x20, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x89, 0xC1, 0x27, 0x00, ++0x9F, 0x53, 0x7C, 0x02, 0xF0, 0x49, 0xC1, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x05, 0x00, 0x1F, 0x42, 0x7C, 0x00, 0x70, ++0x11, 0xCC, 0x07, 0x00, 0x1B, 0x00, 0x4C, 0x00, 0xF0, 0x21, 0xC0, 0x07, 0x00, ++0x12, 0x30, 0x4C, 0x40, 0x70, 0x01, 0xC0, 0x85, 0x09, 0x0F, 0x8A, 0x5C, 0x00, ++0x34, 0x21, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0xA0, 0x14, 0x00, 0x7D, 0x0A, 0x74, 0x01, 0x10, 0x07, 0x40, 0x9F, 0x00, ++0x71, 0x80, 0xC4, 0x01, 0xD0, 0x05, 0xC0, 0x9F, 0x00, 0x61, 0x41, 0xC5, 0x09, ++0x10, 0x06, 0x42, 0x58, 0x08, 0x7D, 0x21, 0xC4, 0x09, 0x10, 0x07, 0x40, 0x50, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, ++0xCD, 0x00, 0x34, 0x02, 0xD0, 0x00, 0x48, 0x73, 0x80, 0xC9, 0x11, 0x14, 0x03, ++0xD0, 0x0C, 0x40, 0xB3, 0x06, 0xC1, 0x88, 0x04, 0x03, 0x51, 0x2C, 0x40, 0x31, ++0x02, 0xCD, 0x01, 0x54, 0x43, 0x90, 0x2C, 0x40, 0x53, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, 0x38, 0x01, 0xED, 0x80, 0xF4, 0x03, ++0x14, 0x02, 0x40, 0xFB, 0x00, 0xE1, 0x03, 0x94, 0x03, 0xD0, 0x8E, 0x64, 0x2B, ++0x40, 0xF1, 0x00, 0x84, 0x03, 0x10, 0x0E, 0x44, 0x18, 0x00, 0xAD, 0x00, 0xC4, ++0x03, 0x91, 0x1C, 0x40, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x11, 0x10, 0x78, 0x00, 0xEF, 0x81, 0xB4, 0x07, 0x70, 0x12, 0xCA, 0x7F, ++0x00, 0x4B, 0x01, 0x9D, 0x05, 0xF2, 0x1E, 0xC8, 0x7B, 0x80, 0x62, 0x01, 0x8C, ++0x07, 0x70, 0x1E, 0xE8, 0x69, 0x20, 0xFF, 0x01, 0xDC, 0x85, 0xB0, 0x1E, 0xD0, ++0x47, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA8, 0xB5, ++0x0A, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x01, 0xC0, 0x17, 0x00, 0xDF, 0x00, 0x6C, ++0x03, 0xF0, 0x0D, 0xC0, 0x25, 0x00, 0xCF, 0x00, 0x7C, 0x03, 0xF0, 0x0C, 0x40, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x00, 0x70, 0x09, 0xC2, 0x40, 0x00, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xFD, 0x00, 0xFF, 0x01, 0xCC, ++0x87, 0xB0, 0x17, 0x80, 0x5F, 0x00, 0xFF, 0x41, 0xFC, 0x07, 0xF9, 0x9E, 0xC0, ++0x58, 0x00, 0x73, 0x81, 0x8C, 0x86, 0xB0, 0x9E, 0xC0, 0x7D, 0x08, 0xDF, 0x01, ++0xFC, 0x07, 0x34, 0x17, 0xC2, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0x18, 0x39, 0x00, 0x7D, 0x08, 0x84, 0x23, 0x10, 0x82, 0x40, ++0x1B, 0x00, 0xED, 0x00, 0xB4, 0x01, 0xD0, 0x0E, 0x62, 0x18, 0x01, 0x6B, 0x04, ++0x84, 0x22, 0x10, 0x1C, 0xC0, 0x2A, 0x04, 0x8D, 0x0D, 0xB4, 0x29, 0xB4, 0x07, ++0x40, 0x54, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x39, 0x00, 0xED, 0x00, 0xC4, 0x03, 0x90, 0x02, 0x40, 0x3B, 0x00, 0x6D, 0x00, ++0xB4, 0x01, 0xD0, 0x0F, 0x5A, 0x18, 0x20, 0x71, 0x00, 0xF4, 0x43, 0xD0, 0x4F, ++0x40, 0x2B, 0x00, 0xED, 0x00, 0xB4, 0x01, 0x90, 0x0E, 0x40, 0x00, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x31, 0x80, 0x8D, 0x22, ++0x04, 0x0B, 0x19, 0x08, 0x40, 0x07, 0x00, 0x8D, 0x00, 0x34, 0x08, 0xD1, 0x2C, ++0x40, 0x50, 0x00, 0x49, 0x00, 0x34, 0x4A, 0x51, 0x3C, 0x40, 0xE3, 0x04, 0x0D, ++0x10, 0x34, 0x00, 0x90, 0x28, 0x51, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0xA8, 0x3D, 0x10, 0x1F, 0x01, 0x4C, 0x0B, 0xB0, 0x01, ++0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x1A, 0xF0, 0x2F, 0xC0, 0x30, 0x04, 0xC1, ++0x20, 0x7C, 0x80, 0xF0, 0x0C, 0xCC, 0xA3, 0x00, 0x5D, 0x20, 0x7C, 0x0A, 0x90, ++0x29, 0x48, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x00, 0x37, 0x28, 0x9F, 0x0C, 0x7D, 0x23, 0xF0, 0x01, 0xC0, 0x27, 0x00, 0x1F, ++0x02, 0x7C, 0x4A, 0xF0, 0x0D, 0xC0, 0x27, 0xC0, 0xD7, 0x50, 0x49, 0x0A, 0xA0, ++0xCD, 0x00, 0xA6, 0x00, 0x0F, 0x08, 0x78, 0x12, 0x74, 0x01, 0xC0, 0x07, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x3F, 0x10, 0x2F, ++0x00, 0xEC, 0x47, 0xB0, 0x02, 0xD0, 0x2C, 0x00, 0x33, 0x00, 0xBC, 0x80, 0xB0, ++0x0F, 0xC3, 0x3F, 0x00, 0x7F, 0xC0, 0xEC, 0x80, 0x71, 0x0B, 0xC0, 0x2E, 0x08, ++0x73, 0x00, 0x0D, 0x02, 0x14, 0x0A, 0xD0, 0x11, 0x22, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x85, 0x20, 0x36, 0x00, 0x9D, 0x25, 0x04, 0x27, 0x10, ++0x21, 0x40, 0x64, 0x00, 0x11, 0x05, 0x74, 0x16, 0x12, 0x0D, 0x40, 0x27, 0x10, ++0xD5, 0x01, 0x04, 0x24, 0x10, 0x19, 0x45, 0xE4, 0x01, 0x55, 0x0A, 0x44, 0x06, ++0x54, 0x71, 0x42, 0x14, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0xA0, 0x34, 0x00, 0x1D, 0x81, 0x64, 0x03, 0x90, 0x05, 0x49, 0xC4, 0x80, ++0x91, 0x01, 0x76, 0x06, 0x90, 0x0D, 0x40, 0xB7, 0x00, 0x55, 0x01, 0x66, 0x8A, ++0x50, 0x1D, 0x60, 0x66, 0x80, 0x55, 0x02, 0x44, 0x06, 0x54, 0x11, 0x40, 0x04, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x30, 0x08, ++0x0D, 0x00, 0x44, 0x03, 0x14, 0x00, 0x40, 0x00, 0x48, 0x81, 0x40, 0x36, 0x02, ++0x10, 0x0C, 0x40, 0x33, 0x00, 0x11, 0x08, 0x44, 0x02, 0x10, 0x4D, 0x60, 0x04, ++0xC0, 0x05, 0x06, 0x04, 0x00, 0x58, 0x00, 0x40, 0x40, 0xA0, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x3E, 0x00, 0x1F, 0x00, 0x6C, 0x83, ++0xB0, 0x01, 0xC0, 0x24, 0x00, 0x13, 0x00, 0x7C, 0x00, 0xB0, 0x0D, 0xC8, 0x37, ++0x40, 0x1F, 0x02, 0x6C, 0x02, 0x70, 0xE9, 0xC3, 0x26, 0x80, 0x93, 0x16, 0x4C, ++0x02, 0x70, 0x09, 0xC2, 0x01, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x85, 0xA0, 0x3F, 0x20, 0xBF, 0x00, 0xBC, 0x03, 0xF0, 0x03, 0xC0, 0x2F, ++0x00, 0xBF, 0x40, 0xFC, 0x02, 0xF1, 0x0F, 0xC0, 0x3F, 0x08, 0x2F, 0x00, 0xFC, ++0x02, 0xF0, 0x41, 0xC0, 0x2F, 0x00, 0x3F, 0x04, 0xFC, 0x00, 0xF0, 0x03, 0xC0, ++0x17, 0x22, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, ++0x00, 0x63, 0x04, 0xCC, 0x32, 0x72, 0x1F, 0xC8, 0x2C, 0x03, 0x72, 0x01, 0xCC, ++0x05, 0x70, 0x0B, 0xC0, 0x3D, 0x00, 0xBB, 0x80, 0xEC, 0x04, 0xD0, 0x9B, 0xD0, ++0x5C, 0x4A, 0xF3, 0x01, 0xCC, 0x12, 0xF1, 0x17, 0xC0, 0x0C, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x7F, 0x00, 0x51, 0x03, 0x44, ++0xB2, 0x12, 0x1F, 0x40, 0x24, 0x13, 0xD1, 0x01, 0x44, 0x07, 0x10, 0x3D, 0x40, ++0xFC, 0x00, 0xB1, 0x03, 0x44, 0x80, 0xD0, 0x45, 0x40, 0x04, 0x01, 0xF1, 0x21, ++0x44, 0x26, 0xD0, 0x1D, 0x40, 0x05, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x11, 0xA0, 0x33, 0x00, 0x55, 0x02, 0x04, 0x12, 0x50, 0x0C, 0x40, ++0x21, 0x01, 0x91, 0x00, 0x16, 0x02, 0x50, 0x88, 0x40, 0x31, 0x02, 0x89, 0x08, ++0x24, 0x00, 0xD8, 0x08, 0x40, 0x30, 0x88, 0xC1, 0x00, 0x14, 0x82, 0xD2, 0x08, ++0x40, 0x44, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA8, ++0x35, 0x00, 0xD5, 0x00, 0x44, 0x82, 0x50, 0x0D, 0x40, 0x25, 0x00, 0xD1, 0x00, ++0x10, 0x22, 0x00, 0x09, 0x40, 0x35, 0x80, 0x95, 0x04, 0x44, 0x06, 0xC0, 0x81, ++0x00, 0x34, 0x04, 0xD1, 0x40, 0x54, 0x12, 0xD0, 0x0C, 0x40, 0x0D, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x33, 0x40, 0xC7, 0x00, ++0x4C, 0x26, 0x71, 0x0D, 0xD0, 0x64, 0x00, 0x83, 0x80, 0x5C, 0x07, 0x70, 0x05, ++0xC0, 0x35, 0x00, 0x9B, 0x00, 0x6C, 0x4C, 0xF0, 0x09, 0xC8, 0x24, 0x00, 0xD3, ++0x00, 0x5C, 0x07, 0xF0, 0x0D, 0xC0, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x10, 0x7B, 0x09, 0xFC, 0x03, 0xB3, 0x0F, ++0xC0, 0x3E, 0x41, 0xBF, 0x00, 0xED, 0x83, 0xF0, 0x9F, 0x82, 0x36, 0x20, 0x9B, ++0x01, 0xFC, 0x00, 0xF0, 0x1F, 0xC0, 0x2F, 0x00, 0xFD, 0x80, 0xEC, 0x02, 0xF2, ++0x8F, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x08, 0x35, 0x12, 0xDF, 0x0A, 0x4D, 0x03, 0xF0, 0x8C, 0xC4, 0x34, 0x00, 0x9F, ++0x00, 0x7C, 0x03, 0xF0, 0x00, 0xC0, 0x73, 0x00, 0x8B, 0x00, 0x5C, 0x08, 0xF0, ++0x09, 0xC0, 0xA7, 0x00, 0xCF, 0x00, 0x7C, 0x42, 0xF2, 0x09, 0xC2, 0x08, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA2, 0x34, 0x00, 0xDD, ++0x80, 0x44, 0x03, 0xD0, 0x0D, 0x40, 0x74, 0x00, 0x9D, 0x00, 0x74, 0x03, 0xD0, ++0x0B, 0x02, 0x3F, 0x00, 0x91, 0x01, 0x44, 0x02, 0xD0, 0x0D, 0x40, 0x67, 0x04, ++0xDD, 0x00, 0x74, 0x02, 0xD2, 0x0D, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x32, 0x0C, 0x4C, 0x00, 0x44, 0x03, 0xD0, ++0x0C, 0x51, 0x34, 0x02, 0x4D, 0x00, 0x30, 0x00, 0xD0, 0x08, 0x40, 0x32, 0x00, ++0x81, 0x00, 0x14, 0x00, 0xD0, 0x0D, 0x40, 0x37, 0x00, 0xCD, 0x20, 0x34, 0x2E, ++0xD0, 0x00, 0x50, 0x1C, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x04, 0x80, 0x78, 0x00, 0x6D, 0x41, 0x84, 0x46, 0xD0, 0x1E, 0x48, 0x68, 0x00, ++0xED, 0x01, 0xB4, 0x06, 0xD0, 0x1E, 0x42, 0x7B, 0x60, 0xA1, 0x21, 0x84, 0x84, ++0xD0, 0x5E, 0x41, 0x6B, 0x00, 0xEC, 0x81, 0xB4, 0x07, 0xD2, 0x1B, 0x40, 0x18, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, ++0xCF, 0x00, 0x0C, 0x02, 0xF2, 0x0C, 0xC0, 0x20, 0x00, 0x8F, 0x00, 0x3C, 0x12, ++0xF0, 0x48, 0xC0, 0x33, 0x00, 0x83, 0x10, 0x1C, 0x80, 0xF8, 0x08, 0xE0, 0x33, ++0x00, 0xCF, 0x48, 0x3C, 0x03, 0xF0, 0x09, 0xC0, 0x48, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x7D, 0x00, 0xFF, 0x00, 0xFC, 0x42, ++0xF0, 0x1E, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3F, ++0x00, 0xB7, 0x00, 0xEC, 0x22, 0xF2, 0x4B, 0xC0, 0x3F, 0x00, 0xFE, 0x01, 0xFC, ++0x43, 0xF0, 0x09, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x11, 0xA0, 0x37, 0x00, 0x5F, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x37, ++0x00, 0x9F, 0x00, 0x78, 0x02, 0xF0, 0x85, 0xC0, 0xF0, 0x22, 0xDB, 0x14, 0x74, ++0x00, 0xE0, 0x1C, 0xC0, 0x24, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x09, 0xC0, ++0x57, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0xB9, ++0x00, 0x6D, 0x04, 0xB4, 0x13, 0xD0, 0x4E, 0x40, 0x3B, 0x00, 0xAD, 0x00, 0xB6, ++0x02, 0xD0, 0x4E, 0x50, 0x38, 0x04, 0xA1, 0x00, 0xB4, 0x02, 0xD0, 0x0E, 0x40, ++0x28, 0x00, 0xED, 0x04, 0xB4, 0x03, 0xD0, 0x0A, 0x40, 0x4B, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x89, 0xED, 0x09, 0xB4, ++0x07, 0xD0, 0x9E, 0x40, 0x79, 0x03, 0xAD, 0x01, 0xB4, 0x06, 0xD0, 0x14, 0x62, ++0x78, 0x01, 0xE9, 0x11, 0xB4, 0x04, 0xD0, 0x1F, 0x40, 0x69, 0x88, 0xED, 0x0D, ++0xB4, 0x57, 0xD0, 0x1A, 0x40, 0x0F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0x8D, 0xA0, 0x34, 0x07, 0xD0, 0x0C, 0x40, ++0x73, 0x10, 0x8D, 0x0B, 0x34, 0x2A, 0xD0, 0x2C, 0x40, 0x30, 0x00, 0xC1, 0x01, ++0x34, 0x03, 0xD0, 0xDC, 0x40, 0x21, 0x23, 0xCD, 0x00, 0x34, 0x07, 0xD0, 0x08, ++0x41, 0x4B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, ++0x11, 0x00, 0x7F, 0x20, 0x7C, 0x11, 0xF0, 0x05, 0xC0, 0x17, 0x24, 0x7F, 0x02, ++0xFC, 0x0D, 0xF0, 0x07, 0xC0, 0x14, 0x00, 0x5B, 0x01, 0xFC, 0x31, 0xF0, 0x07, ++0xD0, 0x9D, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xF0, 0x27, 0xC0, 0x5F, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x87, 0x00, 0x1F, 0x01, ++0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x10, 0x70, 0x40, 0xF0, 0x80, ++0xC0, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF1, 0x01, 0x80, 0x06, 0x28, 0x1F, ++0x80, 0x78, 0x08, 0xF0, 0x01, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0x67, 0x00, 0x93, 0x00, 0x7C, 0x26, 0xF0, 0x39, ++0xC0, 0x27, 0x01, 0x9F, 0x00, 0x4D, 0x02, 0x32, 0x09, 0xC3, 0x64, 0x00, 0x8F, ++0x01, 0x4C, 0x02, 0xF1, 0x29, 0xC0, 0x27, 0x01, 0x9F, 0x00, 0x4C, 0x06, 0x30, ++0x09, 0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x20, 0x2E, 0x00, 0xB1, 0x03, 0xF4, 0x02, 0xD0, 0x0B, 0x40, 0x6F, 0x00, 0x9D, ++0x00, 0x04, 0x02, 0x10, 0x09, 0x40, 0x24, 0x00, 0x9D, 0x01, 0x44, 0x02, 0xD0, ++0x09, 0x40, 0x67, 0x08, 0xBD, 0x00, 0x84, 0x0E, 0x10, 0x08, 0x40, 0x04, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x02, 0xD1, ++0x08, 0x74, 0x02, 0xD0, 0x09, 0x41, 0x27, 0x00, 0x8D, 0x00, 0x44, 0x02, 0x10, ++0x09, 0x50, 0x24, 0x01, 0x9D, 0x04, 0x44, 0x02, 0xD0, 0x0D, 0x42, 0x27, 0x00, ++0x8D, 0x00, 0x44, 0x1A, 0x10, 0x09, 0x40, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x81, 0x00, 0x34, 0x0A, 0xD0, ++0x08, 0x42, 0xA3, 0x08, 0x8D, 0x02, 0x44, 0x0A, 0x10, 0x68, 0x41, 0x20, 0x05, ++0x8D, 0x14, 0x05, 0x02, 0xD0, 0x28, 0x40, 0xA3, 0x08, 0x8D, 0x02, 0x05, 0x02, ++0x10, 0x29, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1D, 0xB0, 0x56, 0x40, 0x53, 0x01, 0x7C, 0x04, 0xF0, 0x11, 0xC0, 0x47, 0x00, ++0x1F, 0x00, 0x4C, 0x00, 0x34, 0x41, 0xC0, 0x04, 0x01, 0x1F, 0x04, 0x4C, 0x28, ++0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x01, 0x4C, 0x04, 0x34, 0x01, 0xD0, 0x74, ++0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0xA7, 0x00, ++0xBF, 0x02, 0xFC, 0x0E, 0xF0, 0x29, 0xC0, 0xEF, 0x00, 0xBF, 0x01, 0xFC, 0x06, ++0xF0, 0x1B, 0xC0, 0x27, 0x00, 0xBF, 0x80, 0xFC, 0x06, 0xF0, 0x1B, 0xC0, 0x6F, ++0x08, 0x9F, 0x23, 0xFC, 0x0A, 0xF0, 0x1B, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x6F, 0x00, 0xFB, 0x11, 0xCD, 0x16, ++0xF0, 0x1B, 0xC0, 0x6F, 0x01, 0x93, 0x00, 0x6C, 0x0A, 0x20, 0x59, 0x80, 0x6D, ++0x01, 0xA3, 0x05, 0x0C, 0x02, 0xF0, 0x2B, 0xC8, 0x2B, 0x00, 0x9D, 0x85, 0xCC, ++0x06, 0x30, 0x29, 0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x1C, 0x08, 0x07, 0x00, 0x11, 0x42, 0x44, 0x14, 0xD0, 0x21, 0x40, 0xC7, ++0x03, 0x51, 0x15, 0x64, 0x04, 0x10, 0x30, 0x40, 0x04, 0x00, 0x11, 0x00, 0x54, ++0x00, 0xD0, 0x51, 0x40, 0x57, 0x00, 0x1D, 0x07, 0x44, 0x28, 0x10, 0x11, 0x40, ++0x73, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0xA3, ++0x00, 0x89, 0x00, 0x04, 0x4A, 0xD0, 0x28, 0x42, 0x23, 0x04, 0x81, 0x20, 0x24, ++0x02, 0x10, 0xC8, 0x61, 0xA3, 0x00, 0x81, 0x02, 0x04, 0x02, 0x50, 0x48, 0x60, ++0x33, 0x05, 0x8D, 0x12, 0x14, 0x02, 0xD0, 0x08, 0x40, 0x43, 0x80, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x91, 0x40, 0x44, ++0x02, 0xD0, 0x09, 0x42, 0x27, 0x60, 0x91, 0x08, 0x24, 0x02, 0x10, 0x09, 0x42, ++0x26, 0x00, 0x91, 0x04, 0x54, 0x0A, 0xD0, 0x89, 0x42, 0x27, 0x01, 0x9D, 0x00, ++0x54, 0x06, 0xD0, 0x09, 0x40, 0x63, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0x28, 0x25, 0x00, 0x9B, 0x0E, 0xCC, 0x22, 0xF0, 0x09, 0xC0, ++0x2F, 0x00, 0xB3, 0x03, 0xEC, 0x12, 0x30, 0x1B, 0xC0, 0x27, 0x00, 0x93, 0x00, ++0x4C, 0x06, 0xE0, 0x1B, 0xC0, 0xEF, 0x20, 0xBF, 0x00, 0x5D, 0x02, 0xF0, 0x6B, ++0xC0, 0x17, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, ++0x25, 0x00, 0x9F, 0x10, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0xA7, 0x00, 0x9F, 0x21, ++0x7C, 0x12, 0xF4, 0x38, 0xD0, 0x21, 0x40, 0x9F, 0x00, 0x7C, 0x0A, 0xF2, 0x09, ++0xC0, 0x67, 0x08, 0x9F, 0x00, 0x2C, 0x82, 0x34, 0x39, 0xC0, 0x53, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x01, 0x01, 0x0F, 0x00, ++0x4D, 0x80, 0x30, 0x81, 0xC0, 0x07, 0x00, 0x1F, 0x02, 0x7C, 0x00, 0xF0, 0x01, ++0xC0, 0x04, 0x10, 0x17, 0x00, 0x4C, 0x08, 0x72, 0x01, 0xD0, 0x04, 0x40, 0x03, ++0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x53, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x20, 0xDC, 0x20, 0x7D, 0x00, 0x44, 0x05, 0x10, 0x07, ++0x40, 0x17, 0x04, 0x5D, 0x00, 0x74, 0x01, 0xD0, 0x05, 0xC0, 0x16, 0x00, 0x41, ++0x11, 0x44, 0x01, 0x10, 0x15, 0x43, 0x14, 0x00, 0x51, 0x00, 0xF0, 0x01, 0xC0, ++0x05, 0x40, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0xA0, 0xE2, 0x00, 0x8D, 0x00, 0x04, 0x07, 0x10, 0x08, 0x42, 0x37, 0x00, 0xCD, ++0x00, 0x30, 0x03, 0xD0, 0x0C, 0x40, 0x32, 0x00, 0x85, 0x01, 0x05, 0x03, 0x50, ++0x0C, 0x40, 0x32, 0x00, 0xC1, 0x80, 0x34, 0x02, 0xC0, 0x0C, 0x40, 0x53, 0x00, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0xB8, 0x00, 0xAD, ++0x00, 0x04, 0x77, 0x14, 0x0E, 0x40, 0x2B, 0x82, 0xED, 0x04, 0xB4, 0x13, 0xD0, ++0x4E, 0x40, 0x2A, 0x00, 0xF5, 0x00, 0xC4, 0x07, 0x50, 0xDE, 0x40, 0x7E, 0x01, ++0xE1, 0x0C, 0xB4, 0x03, 0xD1, 0x4E, 0x40, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x68, 0x00, 0xAF, 0x01, 0x84, 0x06, 0x30, ++0x1A, 0xC0, 0x7B, 0x01, 0xEF, 0x03, 0xBC, 0x0F, 0xF0, 0x5E, 0xC0, 0x6A, 0x00, ++0xE7, 0x01, 0x8C, 0x07, 0x70, 0x1F, 0x80, 0xFA, 0x00, 0xE3, 0x01, 0xBC, 0x06, ++0xF0, 0x3E, 0xC0, 0x53, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xB8, 0x35, 0x00, 0x8F, 0x00, 0x7C, 0x02, 0xC0, 0x0D, 0xC0, 0x27, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xE0, 0x8D, 0xC4, 0x23, 0x00, 0xDB, 0x00, 0x7C, 0x63, ++0xB8, 0x0D, 0xC0, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x43, ++0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x6F, 0x00, ++0xB3, 0x01, 0xFC, 0x87, 0x30, 0x1B, 0x80, 0x7F, 0x02, 0xE3, 0x01, 0x8C, 0x07, ++0x30, 0x1F, 0x40, 0x7C, 0x01, 0xFF, 0x01, 0xEC, 0x07, 0x30, 0x1B, 0xC0, 0x78, ++0x28, 0xF3, 0x21, 0xFC, 0x06, 0x30, 0x1E, 0xC8, 0x08, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x29, 0x40, 0xA1, 0x00, 0xF4, 0x03, ++0x14, 0x0A, 0x40, 0x2B, 0x48, 0xE1, 0x00, 0x84, 0x23, 0x10, 0x8E, 0x40, 0x29, ++0x00, 0xED, 0x00, 0xC4, 0x43, 0xB0, 0x0A, 0xC0, 0x3A, 0x02, 0xE1, 0x00, 0xB4, ++0x0B, 0x10, 0x8E, 0x40, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x21, 0x00, 0xA1, 0x10, 0xB4, 0x02, 0x10, 0x0A, 0x40, 0x3B, ++0x80, 0xF1, 0x01, 0xC4, 0x07, 0x10, 0x1F, 0x40, 0x28, 0x01, 0xCD, 0x00, 0xA4, ++0x03, 0x10, 0x0B, 0x41, 0x3D, 0x00, 0xE1, 0x01, 0xB4, 0x62, 0x14, 0x1F, 0x40, ++0x20, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x13, ++0x00, 0x81, 0x01, 0x34, 0x86, 0x10, 0x0C, 0x40, 0x63, 0x00, 0xC1, 0x07, 0x04, ++0x0B, 0x18, 0x3C, 0x40, 0x21, 0x00, 0xCD, 0x00, 0x04, 0x17, 0x90, 0x3C, 0x43, ++0x67, 0x00, 0xC1, 0x00, 0x34, 0x07, 0x10, 0x1C, 0x40, 0x18, 0x20, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x25, 0x00, 0xD3, 0x03, 0x7C, ++0x13, 0x30, 0x09, 0xC2, 0x77, 0x04, 0xD3, 0x04, 0x45, 0x2B, 0x34, 0x6D, 0xC0, ++0x24, 0x00, 0xDF, 0x11, 0xEC, 0x03, 0x30, 0x3C, 0xC0, 0x65, 0x44, 0xD3, 0x20, ++0x3C, 0x02, 0x30, 0x6D, 0xD0, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x00, 0x37, 0x00, 0xCF, 0x00, 0x7C, 0x03, 0xF0, 0x2D, 0xC0, ++0x27, 0x08, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0xDD, 0x40, ++0x7C, 0x83, 0xF2, 0x0D, 0xC0, 0x26, 0x00, 0xDF, 0x00, 0x7C, 0x0A, 0xF0, 0x4D, ++0xC0, 0x27, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, ++0x2F, 0x00, 0xBF, 0x10, 0x8C, 0x06, 0x31, 0x0B, 0xD0, 0xB4, 0x00, 0xFF, 0x00, ++0xCC, 0x03, 0xF0, 0x0F, 0xC1, 0xEF, 0x00, 0xFF, 0x85, 0xCC, 0x03, 0x30, 0x4F, ++0xC0, 0xEC, 0x00, 0xF3, 0x00, 0x4C, 0x16, 0x30, 0x0F, 0xC0, 0x04, 0x20, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0xDD, 0x03, ++0x44, 0x02, 0x11, 0x24, 0x40, 0x74, 0x00, 0xDD, 0x40, 0x44, 0x03, 0xD0, 0x0D, ++0x42, 0x67, 0x20, 0xCD, 0x01, 0x44, 0x03, 0x10, 0x19, 0x48, 0x74, 0x20, 0xD1, ++0x00, 0x44, 0x01, 0x00, 0x0D, 0x40, 0x84, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0xA0, 0x26, 0x00, 0xDD, 0x06, 0x44, 0xA3, 0x14, 0x09, ++0x41, 0x34, 0x00, 0xCD, 0x00, 0x64, 0x03, 0xD0, 0x0D, 0x40, 0x27, 0x10, 0xDD, ++0x00, 0x84, 0x03, 0x10, 0x09, 0x40, 0x24, 0x40, 0xC1, 0x00, 0x44, 0x02, 0x10, ++0x0C, 0x40, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0x20, 0x00, 0xCD, 0x00, 0x14, 0x02, 0x10, 0x08, 0x40, 0x20, 0x00, 0xCD, ++0x00, 0x05, 0x03, 0xD0, 0x0C, 0x40, 0x23, 0x80, 0xDD, 0x40, 0x04, 0x03, 0x14, ++0x09, 0x50, 0x20, 0x00, 0xC1, 0x40, 0x04, 0x02, 0x16, 0x0C, 0x54, 0x40, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x26, 0x00, 0x1F, ++0x00, 0x4C, 0x03, 0x30, 0x09, 0xCA, 0x24, 0x00, 0xFF, 0x00, 0xEC, 0x03, 0xF0, ++0x0F, 0xC0, 0x27, 0x00, 0xDF, 0x00, 0xCD, 0x03, 0x30, 0x09, 0xC0, 0x24, 0x00, ++0xF3, 0x00, 0x4D, 0x02, 0x30, 0x0F, 0xC0, 0x04, 0x40, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x1F, 0x00, 0x7F, 0x00, 0xED, 0x02, 0xF0, ++0x07, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0E, 0xC0, 0x2F, 0x00, ++0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0A, 0xC0, 0x2F, 0x00, 0xFF, 0x00, 0xFC, 0x01, ++0xF0, 0x0F, 0xC0, 0x17, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA0, 0x7F, 0x00, 0xF7, 0x0C, 0xCC, 0x1B, 0x70, 0x3A, 0xC0, 0xEC, 0x00, ++0xBB, 0x04, 0xFC, 0x03, 0x30, 0x1E, 0xC0, 0x3E, 0x00, 0xA7, 0x01, 0x8C, 0x06, ++0x30, 0x1B, 0xC0, 0x7E, 0x12, 0xBF, 0x04, 0xCC, 0x07, 0xF0, 0x03, 0xC4, 0x0E, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x77, 0x00, ++0xF1, 0x8E, 0xC4, 0x3B, 0x10, 0x49, 0x40, 0x24, 0x00, 0x91, 0x0E, 0xF4, 0x2F, ++0x50, 0x19, 0x40, 0xF4, 0x00, 0x5D, 0x01, 0x44, 0x50, 0x10, 0x19, 0x40, 0x34, ++0x00, 0xC9, 0x14, 0x44, 0x03, 0xD0, 0x19, 0x40, 0x04, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA2, 0x33, 0x20, 0xC5, 0x04, 0x04, 0x13, ++0x50, 0x49, 0x40, 0x30, 0x01, 0x09, 0x10, 0x14, 0x03, 0x12, 0x08, 0x60, 0x32, ++0x02, 0xCD, 0x80, 0x44, 0x10, 0x10, 0x08, 0x40, 0x33, 0x00, 0x8D, 0x0C, 0x04, ++0x03, 0xD0, 0x08, 0x40, 0x47, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0xA8, 0x35, 0x00, 0xD1, 0x00, 0x46, 0x03, 0x10, 0x19, 0x41, 0x70, ++0x00, 0x11, 0x01, 0x74, 0x03, 0x10, 0x19, 0x40, 0x34, 0x00, 0xDD, 0x84, 0x46, ++0x84, 0x10, 0x09, 0x40, 0x35, 0x00, 0x99, 0x00, 0x44, 0x03, 0xD0, 0x19, 0x41, ++0x0D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xA8, 0x36, ++0x08, 0xD7, 0x00, 0x48, 0x03, 0x70, 0x39, 0xC0, 0x44, 0x01, 0x9B, 0x05, 0x5C, ++0x83, 0x30, 0x19, 0xC0, 0x36, 0x80, 0xD7, 0x00, 0x4C, 0x4E, 0x31, 0x08, 0xC0, ++0x37, 0x02, 0x9F, 0x00, 0x4D, 0x07, 0xF0, 0x30, 0xC0, 0x03, 0x20, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x82, 0x3D, 0x10, 0xEF, 0x00, 0xFC, ++0x03, 0xF0, 0x0B, 0xC0, 0x2F, 0x00, 0xBF, 0x80, 0xFC, 0x43, 0xF0, 0x0B, 0xC0, ++0x3F, 0xA4, 0xFF, 0x01, 0xFD, 0x03, 0xF0, 0x0F, 0xC2, 0x3E, 0x00, 0xEF, 0x02, ++0xFC, 0x8F, 0xF0, 0x03, 0xC0, 0x1E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0x70, 0x21, 0xC0, ++0x35, 0x00, 0x97, 0x08, 0x0C, 0x03, 0x70, 0x01, 0xC0, 0x34, 0x02, 0xD7, 0x10, ++0x4C, 0x00, 0xB1, 0x0D, 0xC0, 0x37, 0x04, 0xD3, 0x18, 0x44, 0x03, 0xF0, 0x21, ++0xC0, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0x70, 0x00, 0xFD, 0x0F, 0xF4, 0x03, 0xD0, 0x0C, 0x60, 0x34, 0x00, 0x91, 0x03, ++0xC4, 0x4F, 0x30, 0xC0, 0xC0, 0x3C, 0x08, 0xC1, 0x11, 0x2C, 0x00, 0x10, 0x8D, ++0x40, 0xF4, 0x00, 0xD5, 0x00, 0x44, 0x0B, 0xD0, 0xB1, 0x40, 0x4C, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x72, 0x00, 0xCD, 0x03, ++0x74, 0x07, 0x50, 0x08, 0x44, 0x31, 0x00, 0x05, 0x12, 0x14, 0x0B, 0xD0, 0x18, ++0x40, 0xF0, 0x20, 0xC5, 0x00, 0x24, 0x02, 0xD2, 0x00, 0x06, 0xF3, 0x00, 0x89, ++0x01, 0x04, 0x37, 0xD0, 0x90, 0x40, 0x1D, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x06, 0x82, 0x78, 0x04, 0xED, 0x81, 0xB4, 0x4F, 0xD0, 0x1B, ++0x48, 0x7D, 0x08, 0xE1, 0x09, 0x95, 0x07, 0x00, 0x9B, 0x40, 0x78, 0x00, 0x61, ++0x01, 0xE4, 0x04, 0x10, 0x9A, 0x40, 0x78, 0x06, 0xAD, 0x01, 0x84, 0x07, 0xD9, ++0x1A, 0x48, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, ++0x10, 0x30, 0x00, 0xCD, 0x00, 0x34, 0x03, 0x70, 0x08, 0x40, 0x31, 0x00, 0x57, ++0x00, 0x1C, 0x03, 0xF0, 0x88, 0xC0, 0x30, 0x00, 0xC7, 0x00, 0x2C, 0x00, 0xB0, ++0x00, 0xC0, 0x37, 0x00, 0x8B, 0x0C, 0x0C, 0x03, 0xF0, 0x0C, 0xC0, 0x49, 0x48, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB0, 0x3D, 0x00, 0xFF, ++0x02, 0xFC, 0x4B, 0xF0, 0x8B, 0x80, 0x3A, 0x02, 0xFF, 0x00, 0xAC, 0x63, 0xF1, ++0x8B, 0xD0, 0x3B, 0x00, 0xFF, 0x48, 0xFC, 0x00, 0xF0, 0x0A, 0xC2, 0x3F, 0x00, ++0x97, 0x28, 0xFD, 0x03, 0xF0, 0x8E, 0xC0, 0x09, 0x60, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x00, 0xDF, 0x0C, 0x7C, 0x0B, 0xF0, ++0x09, 0xC0, 0x34, 0x00, 0x57, 0x01, 0x4C, 0x1B, 0xF1, 0x09, 0xC0, 0x34, 0x12, ++0xCF, 0x00, 0x4C, 0x03, 0xB0, 0x01, 0xC0, 0x76, 0x90, 0xDB, 0x00, 0x7C, 0x83, ++0x30, 0x05, 0xC0, 0x54, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x88, 0x39, 0x00, 0xED, 0x04, 0xB4, 0x13, 0xD0, 0x0F, 0x44, 0x38, 0x00, ++0xE1, 0x00, 0x84, 0x33, 0xD8, 0x0A, 0x42, 0x38, 0x00, 0xED, 0xA0, 0x84, 0x81, ++0x14, 0x0E, 0x44, 0x39, 0x00, 0xE5, 0x00, 0xB4, 0x03, 0x50, 0x0E, 0x40, 0x48, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x79, 0x00, ++0xED, 0x05, 0xB4, 0x07, 0xD0, 0x1A, 0x54, 0x7C, 0x00, 0x45, 0x01, 0x84, 0x17, ++0xC0, 0x13, 0x48, 0x78, 0x01, 0xEC, 0x01, 0xC5, 0x05, 0x12, 0x16, 0x40, 0x7D, ++0x80, 0xE1, 0xA1, 0xF4, 0x8F, 0x11, 0x1C, 0x60, 0x0C, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x00, 0xCD, 0x00, 0x34, 0x03, ++0xD8, 0x2C, 0x40, 0x30, 0x00, 0xC1, 0x03, 0x04, 0x03, 0xD0, 0x80, 0x40, 0x30, ++0x20, 0xCD, 0x05, 0x04, 0x15, 0x10, 0x0C, 0x40, 0x21, 0x00, 0xC5, 0x08, 0x74, ++0x06, 0x50, 0x2C, 0x41, 0x48, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x17, 0xA8, 0x15, 0x00, 0x5F, 0x00, 0x7C, 0x01, 0xD0, 0x47, 0xC0, 0x98, ++0x00, 0x77, 0x49, 0x4C, 0x01, 0xF0, 0xA7, 0xC8, 0x14, 0x00, 0x7F, 0x07, 0x8C, ++0x15, 0x30, 0x47, 0xC0, 0x55, 0x00, 0x5B, 0x21, 0x7C, 0x01, 0x10, 0x27, 0xD1, ++0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, ++0x00, 0x1F, 0x82, 0x7C, 0x00, 0xF1, 0x01, 0xC1, 0x07, 0x01, 0x1F, 0xA8, 0x7D, ++0x08, 0xD0, 0x21, 0xD4, 0x87, 0x00, 0x1F, 0x40, 0x7C, 0x00, 0x70, 0x21, 0xC0, ++0x05, 0x02, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x21, 0xC0, 0x4B, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x01, 0x9F, 0x03, 0x3C, ++0x02, 0x30, 0x09, 0xC0, 0x24, 0x08, 0x97, 0x01, 0x7C, 0x12, 0xF2, 0x29, 0xC0, ++0x26, 0x00, 0x9F, 0x08, 0x5C, 0x02, 0x34, 0x09, 0xC0, 0x24, 0x00, 0x8F, 0x09, ++0x4D, 0x02, 0x30, 0x48, 0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x03, 0x74, 0x0A, 0x10, 0x09, 0x40, ++0x24, 0x00, 0x91, 0x01, 0x74, 0x1A, 0xD0, 0x08, 0x41, 0xE4, 0x01, 0x8D, 0x60, ++0x44, 0x02, 0x12, 0x68, 0x40, 0x24, 0x03, 0x9D, 0x02, 0x44, 0x02, 0x30, 0x29, ++0x50, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, ++0x24, 0x00, 0x9D, 0x00, 0x74, 0x46, 0x50, 0x08, 0x42, 0x24, 0x00, 0x95, 0x08, ++0x74, 0x82, 0xD0, 0x09, 0x40, 0x27, 0x02, 0x9D, 0x00, 0x54, 0x02, 0x52, 0x0D, ++0x40, 0x24, 0x00, 0x9D, 0x02, 0x44, 0x0A, 0x10, 0x09, 0x40, 0x60, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0xCD, 0x14, ++0x34, 0x52, 0x54, 0x08, 0x40, 0x24, 0x0A, 0xC1, 0x94, 0x30, 0xD2, 0xD0, 0x09, ++0x40, 0x21, 0x00, 0x8D, 0x00, 0x44, 0x02, 0x19, 0x09, 0x70, 0x20, 0x10, 0x8D, ++0x08, 0x04, 0x02, 0x14, 0x4C, 0x41, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1D, 0xB0, 0x07, 0x00, 0x1F, 0x04, 0x7C, 0x10, 0x70, 0x01, ++0xD0, 0x84, 0x00, 0x17, 0x04, 0x78, 0x10, 0xF0, 0x01, 0xC4, 0x07, 0x05, 0x1D, ++0x40, 0x5C, 0x00, 0x30, 0x01, 0xC0, 0x04, 0x00, 0x1F, 0x16, 0x4C, 0x00, 0x30, ++0x41, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, ++0xB0, 0x27, 0x00, 0x9F, 0x14, 0x7C, 0x52, 0xB1, 0x4B, 0xC1, 0x2B, 0x01, 0xBF, ++0x94, 0x7C, 0x02, 0xF2, 0x0A, 0xC0, 0x26, 0x10, 0xFE, 0x00, 0xBC, 0x53, 0xF0, ++0x0A, 0xC0, 0x2B, 0x15, 0xBF, 0x04, 0xBC, 0x52, 0x70, 0x0B, 0xC0, 0x67, 0x60, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, 0x2F, 0x00, 0xBF, ++0x01, 0xCC, 0x5E, 0xE0, 0x28, 0xC0, 0xA7, 0x00, 0xB7, 0x09, 0xEC, 0x12, 0x70, ++0x0A, 0xC0, 0x2F, 0x04, 0xAD, 0x00, 0x4C, 0x02, 0x30, 0x0A, 0xC0, 0xAE, 0x00, ++0xBB, 0x00, 0xCD, 0x02, 0xB0, 0x0B, 0xC0, 0x67, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, 0x1D, 0x0F, 0x44, 0x08, 0xD0, ++0x01, 0x40, 0x07, 0x01, 0x11, 0x0B, 0x44, 0x00, 0x10, 0x01, 0x40, 0x87, 0x00, ++0x19, 0x00, 0x44, 0x10, 0x10, 0x01, 0x40, 0x04, 0x01, 0x11, 0x00, 0x44, 0x00, ++0x10, 0x01, 0x40, 0x73, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x10, 0xA0, 0x23, 0x00, 0x8D, 0x10, 0x04, 0x12, 0xD0, 0x48, 0x40, 0x67, 0x00, ++0x85, 0x04, 0x24, 0x0B, 0x50, 0x08, 0x40, 0x33, 0x00, 0x99, 0x00, 0x04, 0x42, ++0x10, 0x09, 0x40, 0x22, 0x01, 0x89, 0x00, 0x24, 0x02, 0x90, 0x08, 0x40, 0x43, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, ++0x9D, 0x60, 0x44, 0x02, 0xC8, 0x09, 0x41, 0x27, 0x02, 0x91, 0x00, 0x64, 0x02, ++0x10, 0x09, 0x44, 0x27, 0x00, 0x99, 0x00, 0x00, 0x02, 0x11, 0x09, 0x00, 0x64, ++0x00, 0x91, 0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x63, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x25, 0x00, 0x9F, 0x00, 0x4C, 0x02, ++0xC1, 0x39, 0xC8, 0x67, 0x00, 0x95, 0x51, 0x6C, 0x02, 0x70, 0x79, 0xC0, 0x27, ++0x00, 0x9B, 0x01, 0x4C, 0x0E, 0x30, 0x19, 0xC0, 0x26, 0x00, 0x9B, 0x00, 0x4C, ++0x06, 0xB0, 0x09, 0xC1, 0x17, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0x00, 0x25, 0x00, 0x9F, 0x00, 0x7D, 0x02, 0xF0, 0x29, 0xC0, 0x67, ++0x00, 0x8F, 0x05, 0x1C, 0x02, 0xF0, 0x99, 0xC4, 0x27, 0x24, 0x9B, 0x03, 0x7D, ++0x12, 0xF4, 0x99, 0xC3, 0x27, 0x00, 0x9F, 0x13, 0x7C, 0xD6, 0xF0, 0x49, 0xC1, ++0x53, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x04, ++0x00, 0x0F, 0x04, 0x7C, 0x00, 0xF4, 0x21, 0xC2, 0x04, 0x40, 0x13, 0x00, 0x6C, ++0x40, 0xF0, 0x01, 0xC0, 0x06, 0x00, 0x1F, 0x02, 0x5C, 0x08, 0x31, 0x01, 0xC0, ++0x04, 0x00, 0x1F, 0x00, 0x4C, 0x00, 0x30, 0x01, 0xC0, 0x50, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x54, 0x04, 0x7D, 0x00, 0xF4, ++0x61, 0x10, 0x05, 0xC0, 0x12, 0x00, 0x71, 0x07, 0xC4, 0x09, 0xD0, 0x27, 0x40, ++0x1C, 0x00, 0x6D, 0x60, 0x44, 0x01, 0x12, 0x36, 0x41, 0x1C, 0x01, 0x7D, 0x47, ++0xC4, 0x85, 0x50, 0x27, 0x40, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0xA0, 0x32, 0x80, 0xCD, 0x00, 0x34, 0x0F, 0x10, 0x0C, 0x40, ++0x30, 0x00, 0xC1, 0x07, 0x24, 0x09, 0xD1, 0xC4, 0x40, 0xB3, 0x00, 0x8D, 0x00, ++0x14, 0x03, 0x10, 0x00, 0x48, 0x35, 0x09, 0xDD, 0x03, 0x45, 0xAF, 0x10, 0xAC, ++0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, ++0x28, 0x00, 0x6D, 0x82, 0xB4, 0x07, 0x10, 0xDF, 0x40, 0x3A, 0x03, 0xE1, 0x00, ++0x84, 0x03, 0xD0, 0x13, 0x48, 0x39, 0x80, 0x7D, 0x80, 0xD4, 0x13, 0x1C, 0x02, ++0x40, 0x39, 0x10, 0xED, 0x20, 0xC4, 0x03, 0x41, 0x1C, 0x40, 0x10, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x68, 0x00, 0xEF, 0x01, ++0x3C, 0x05, 0x30, 0xDE, 0xC0, 0x7C, 0x00, 0x73, 0x01, 0xAC, 0x07, 0xF0, 0x1E, ++0xC0, 0x5B, 0x00, 0xAF, 0x01, 0x9C, 0x17, 0x30, 0x12, 0xD0, 0x79, 0x90, 0xBF, ++0x01, 0xCC, 0x07, 0x20, 0x1E, 0xC0, 0x50, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA8, 0x25, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0x31, 0x0D, ++0xC8, 0xB7, 0x05, 0x5F, 0x20, 0x70, 0x03, 0xF1, 0x01, 0xC0, 0x16, 0x00, 0x5F, ++0x80, 0x2C, 0x6B, 0xF0, 0x01, 0xD0, 0x36, 0x00, 0x9F, 0x00, 0x7C, 0x01, 0xF0, ++0x0D, 0xD0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xA0, 0x6F, 0x02, 0xF7, 0x09, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x78, 0x00, 0xFB, ++0x01, 0xFC, 0x07, 0xF0, 0x17, 0xC0, 0x7E, 0x00, 0xBB, 0x01, 0xCC, 0x17, 0xB0, ++0x97, 0xC0, 0x7C, 0x08, 0x7F, 0x01, 0xCC, 0x05, 0xF1, 0x1F, 0xC0, 0x0B, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x29, 0x00, 0x6D, ++0x48, 0xB0, 0x03, 0xD0, 0x4E, 0xC0, 0x3B, 0x01, 0x61, 0x22, 0xB4, 0x8B, 0xD0, ++0x46, 0x40, 0xB8, 0x08, 0x71, 0x00, 0xFC, 0x13, 0x10, 0xC6, 0x40, 0x38, 0x00, ++0x6D, 0x48, 0x84, 0x00, 0xD0, 0x42, 0x40, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x29, 0x20, 0xE5, 0x40, 0xB4, 0x03, 0xD0, ++0x0F, 0x40, 0x3C, 0x10, 0xE9, 0x08, 0xB4, 0x03, 0xD0, 0x07, 0x41, 0x1B, 0x02, ++0xB9, 0x08, 0xA4, 0x73, 0x92, 0x06, 0x41, 0x18, 0x00, 0x2D, 0x00, 0xA4, 0x61, ++0xD0, 0x0E, 0x60, 0x23, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x06, 0x28, 0x23, 0x00, 0x9D, 0x00, 0x34, 0x02, 0xD0, 0xEC, 0x60, 0xB2, 0x04, ++0x09, 0x01, 0x34, 0x03, 0xD0, 0x10, 0x40, 0x10, 0x00, 0x41, 0x23, 0x36, 0x0F, ++0x12, 0x34, 0x41, 0x20, 0x20, 0x0D, 0x09, 0x60, 0x04, 0xD0, 0x00, 0x40, 0x1B, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xA8, 0x25, 0x00, ++0x97, 0x00, 0x74, 0x02, 0xF0, 0x0F, 0xC0, 0x3C, 0x00, 0x9B, 0x02, 0x7C, 0x03, ++0xF0, 0x05, 0x80, 0x37, 0x00, 0x4B, 0x05, 0xEC, 0x07, 0xB0, 0x34, 0xD0, 0x04, ++0x80, 0xDF, 0x01, 0x6D, 0x06, 0xD0, 0x0D, 0x48, 0x57, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x27, 0x00, 0x1F, 0x00, 0x7C, 0x02, ++0xF0, 0x0D, 0xC0, 0x37, 0x08, 0x97, 0x0E, 0x74, 0x0B, 0xE0, 0x01, 0xA0, 0x36, ++0x10, 0x5F, 0x02, 0x5C, 0x13, 0xF0, 0x05, 0xC0, 0x87, 0x0A, 0xDF, 0x02, 0x5C, ++0x02, 0xF0, 0x0D, 0xC8, 0x27, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x81, 0x08, 0xAF, 0x00, 0x3F, 0x00, 0xEC, 0x00, 0xF0, 0x0F, 0xC0, 0x3E, ++0x00, 0x3F, 0x00, 0xFC, 0x03, 0xF1, 0x07, 0xC8, 0x17, 0x20, 0x3B, 0x18, 0xCC, ++0x03, 0xB2, 0x07, 0xD0, 0x0E, 0x00, 0xBF, 0x01, 0xFC, 0x02, 0x30, 0x23, 0xC1, ++0x07, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x26, ++0x20, 0x1D, 0x01, 0x44, 0x04, 0xD0, 0x0C, 0xC0, 0x36, 0x00, 0x1D, 0x01, 0x74, ++0x0F, 0xD0, 0x31, 0x42, 0xD7, 0x00, 0x5D, 0x52, 0x04, 0x03, 0x10, 0x35, 0x40, ++0x44, 0x04, 0x1D, 0x03, 0x74, 0x8C, 0x10, 0x21, 0x40, 0x87, 0x02, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x26, 0x80, 0x9D, 0x31, 0x64, ++0x0C, 0xD0, 0x0D, 0x40, 0x36, 0x00, 0x9D, 0x01, 0x74, 0x07, 0x50, 0x15, 0x41, ++0x77, 0x00, 0x5D, 0x00, 0x47, 0x03, 0x90, 0x1D, 0x41, 0x64, 0x00, 0x5D, 0x94, ++0x74, 0x46, 0x10, 0x2D, 0x48, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x20, 0x00, 0x0D, 0x00, 0x04, 0x02, 0xD0, 0x0D, 0x40, ++0x32, 0x00, 0x8D, 0x20, 0x34, 0x83, 0xD0, 0x00, 0x40, 0x23, 0x00, 0x4D, 0x00, ++0x46, 0x03, 0x10, 0x04, 0x40, 0x20, 0x00, 0x8D, 0x00, 0x26, 0x82, 0x1C, 0x00, ++0x40, 0x43, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, ++0x24, 0x00, 0x9F, 0x80, 0x6C, 0x00, 0xF1, 0x0F, 0xC0, 0x3E, 0x00, 0x9F, 0x00, ++0x7C, 0x03, 0x70, 0x05, 0xC4, 0x17, 0x00, 0x1B, 0x00, 0xCC, 0x03, 0xB4, 0x05, ++0xC0, 0x04, 0x00, 0x4F, 0x00, 0x7C, 0x02, 0x30, 0x01, 0xC4, 0x07, 0x40, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB0, 0x2F, 0x00, 0xBE, 0x00, ++0xFC, 0x02, 0xF0, 0x0E, 0xC0, 0x3F, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0xF0, 0x02, ++0xC0, 0x3F, 0x20, 0x7F, 0x40, 0xFC, 0x03, 0xF0, 0x06, 0xC0, 0x2F, 0x00, 0x3F, ++0x00, 0xFC, 0x00, 0xF2, 0x03, 0xE0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xBF, 0x01, 0xEC, 0x32, 0xF2, 0xC7, ++0xC8, 0x5F, 0x02, 0x33, 0xA1, 0xFC, 0x07, 0x30, 0x6B, 0xC8, 0x3F, 0x08, 0xB3, ++0x00, 0xEC, 0x04, 0x10, 0x1B, 0xC8, 0x1F, 0x03, 0xFD, 0x09, 0xCC, 0x82, 0x32, ++0x1F, 0xC6, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0x08, 0x7F, 0x00, 0xDD, 0x81, 0x74, 0x32, 0xD2, 0xC5, 0x40, 0x07, 0x11, 0xD1, ++0x01, 0xF4, 0x07, 0x10, 0x69, 0x48, 0xFF, 0x00, 0x95, 0x03, 0x74, 0x04, 0x10, ++0x1D, 0x40, 0x97, 0x01, 0xED, 0x04, 0x44, 0x0E, 0x10, 0x1F, 0x40, 0x0F, 0x60, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, 0x00, 0xCD, ++0x00, 0x24, 0x03, 0xD0, 0x44, 0x40, 0x37, 0x01, 0xC5, 0x01, 0x14, 0x83, 0x10, ++0x28, 0x40, 0x33, 0x0A, 0x01, 0x08, 0x74, 0x00, 0x10, 0x0C, 0x40, 0x93, 0x00, ++0xCD, 0x00, 0x14, 0x22, 0x1A, 0x0C, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0x88, 0x35, 0x00, 0xDD, 0x01, 0x74, 0x82, 0xD0, ++0x65, 0x40, 0x27, 0x00, 0xD0, 0x01, 0x74, 0x03, 0x50, 0x0D, 0x42, 0x37, 0x08, ++0x95, 0x20, 0x74, 0x04, 0x10, 0x1D, 0x42, 0x37, 0x09, 0xDC, 0x00, 0x54, 0x13, ++0x10, 0x0D, 0x40, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xA8, 0x37, 0x00, 0xDF, 0x05, 0x6C, 0x02, 0xF0, 0x05, 0xC0, 0xB3, 0x01, ++0xD7, 0x21, 0x3C, 0x03, 0x34, 0x1D, 0xC0, 0x37, 0x10, 0x93, 0x80, 0x28, 0x0C, ++0x32, 0x1D, 0xC1, 0x57, 0x00, 0xDF, 0x80, 0x5C, 0x86, 0x31, 0x0D, 0xC0, 0x0B, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, ++0xFE, 0x00, 0xFC, 0x23, 0xF1, 0x0F, 0xC0, 0xBF, 0x40, 0xFF, 0x00, 0xFC, 0x03, ++0xA0, 0x3B, 0xC0, 0x37, 0x04, 0xBF, 0x23, 0xF0, 0x00, 0xF0, 0x0F, 0xC1, 0x1F, ++0x00, 0xFF, 0x00, 0x2C, 0x02, 0xF0, 0x0F, 0xC4, 0x1F, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xD7, 0x00, 0x7C, 0x07, ++0x70, 0x0D, 0xC0, 0x34, 0x00, 0xD3, 0x80, 0x7C, 0x43, 0x34, 0x0D, 0xC0, 0x33, ++0x42, 0x13, 0x00, 0x4C, 0x00, 0xF0, 0x0D, 0xC0, 0xB7, 0x08, 0xC3, 0x00, 0x4C, ++0x43, 0x70, 0x0D, 0xC1, 0x0B, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x13, 0xA0, 0x34, 0x00, 0xD1, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x40, 0xB4, ++0x08, 0xDA, 0x01, 0x74, 0x07, 0x00, 0x4D, 0x46, 0xBF, 0x00, 0xB1, 0x00, 0x44, ++0x48, 0xD0, 0x2D, 0x40, 0x77, 0x04, 0xD1, 0x00, 0x40, 0x0F, 0x10, 0x3D, 0x40, ++0x6F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x32, ++0x00, 0xC1, 0x00, 0x20, 0x02, 0x10, 0x9C, 0x40, 0x60, 0x26, 0xC5, 0x01, 0x24, ++0x27, 0x10, 0x08, 0x00, 0xF3, 0x00, 0x89, 0x01, 0x35, 0x44, 0xD0, 0x2C, 0x40, ++0x33, 0x00, 0xC5, 0x29, 0x04, 0x2F, 0x90, 0xBC, 0x42, 0x0F, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x78, 0x00, 0xE1, 0x01, 0xB6, ++0x06, 0x10, 0x14, 0x58, 0x68, 0x10, 0xED, 0x51, 0x34, 0x07, 0x10, 0x1A, 0x42, ++0x7B, 0x10, 0x89, 0x01, 0x94, 0x04, 0xD0, 0x1E, 0x40, 0x5B, 0xC2, 0xE5, 0x03, ++0x84, 0x06, 0x90, 0x1E, 0x40, 0x77, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xC7, 0x00, 0x7E, 0x02, 0x70, 0x04, 0xC0, ++0x20, 0x82, 0xC7, 0x80, 0x2C, 0x13, 0x38, 0x0C, 0xE0, 0x33, 0x00, 0x0B, 0x90, ++0x1C, 0x30, 0xF0, 0x0C, 0xC0, 0xB7, 0xA0, 0xC7, 0x80, 0x0C, 0x03, 0xF0, 0x0C, ++0xC0, 0x4B, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, ++0x79, 0xC0, 0xFF, 0x00, 0xF4, 0x02, 0xF8, 0x07, 0xC8, 0x2B, 0x08, 0xFB, 0x08, ++0xFC, 0x07, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xB7, 0x10, 0xEC, 0xA0, 0xF0, 0x0F, ++0xC0, 0x3F, 0x00, 0xFB, 0x01, 0x7E, 0x23, 0x70, 0x1D, 0xC1, 0x0B, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x00, 0xDF, 0x00, ++0x7C, 0x83, 0xF0, 0x8D, 0x80, 0x27, 0x00, 0xDF, 0x40, 0x7E, 0x83, 0xF0, 0x89, ++0x40, 0x37, 0x03, 0x9F, 0x00, 0x6E, 0x00, 0xF0, 0x0D, 0xC0, 0x17, 0x10, 0xD3, ++0x00, 0x7E, 0x02, 0xF0, 0x0D, 0xC0, 0x40, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x88, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x1B, 0xD0, 0x0E, ++0x40, 0x2B, 0x00, 0xED, 0x00, 0xB6, 0x0B, 0xD0, 0x4A, 0x44, 0x3B, 0x02, 0x8D, ++0x04, 0x84, 0x80, 0xD0, 0x0E, 0x40, 0x93, 0x01, 0xE1, 0x04, 0xB4, 0x82, 0xD8, ++0x4C, 0x40, 0x4D, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0x00, 0x79, 0x02, 0xED, 0x01, 0x94, 0x07, 0xD0, 0x1E, 0x60, 0x6B, 0x24, 0xED, ++0x01, 0xB4, 0x97, 0xD0, 0x5E, 0x62, 0x7B, 0x18, 0x2D, 0x01, 0xA4, 0xC4, 0xD2, ++0x1E, 0x41, 0xFB, 0x00, 0xE1, 0x0D, 0xB4, 0x2F, 0xD1, 0x1E, 0x40, 0x10, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, 0x10, 0x4D, ++0x07, 0x74, 0x07, 0xD0, 0x38, 0x49, 0xE3, 0x20, 0xCD, 0x05, 0x34, 0x03, 0xD0, ++0x1C, 0x40, 0x33, 0x80, 0xCD, 0x00, 0x04, 0x0F, 0xD0, 0x74, 0x40, 0x63, 0x40, ++0xC1, 0x00, 0x34, 0x07, 0xD0, 0x0C, 0x40, 0x59, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, 0x00, 0x7F, 0x10, 0x7C, 0x41, 0xF0, ++0x17, 0xC0, 0xDF, 0x00, 0x7F, 0x04, 0x3C, 0x01, 0xF0, 0x05, 0xC0, 0x17, 0x00, ++0x7F, 0x11, 0xAC, 0x05, 0xF0, 0x27, 0xC8, 0xDF, 0x08, 0x53, 0x80, 0x7C, 0x01, ++0xF1, 0x04, 0xC0, 0x5C, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x00, 0x87, 0x08, 0x1F, 0x80, 0x78, 0x00, 0xF0, 0x81, 0xC8, 0x87, 0x00, ++0x1C, 0x00, 0x7C, 0x08, 0xF0, 0x81, 0x82, 0x02, 0x00, 0x0F, 0x00, 0x7C, 0x10, ++0xF0, 0x21, 0xC0, 0x03, 0x00, 0x1F, 0x02, 0x74, 0x00, 0xF0, 0x01, 0xC8, 0x4B, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x67, 0x02, ++0x9F, 0x00, 0x7C, 0x06, 0x30, 0x49, 0xC0, 0x67, 0x04, 0x9F, 0xC8, 0x7C, 0x02, ++0x31, 0x19, 0xC0, 0x27, 0x00, 0x93, 0x00, 0x4D, 0x8A, 0x30, 0x49, 0xC0, 0x67, ++0x04, 0x93, 0x08, 0x4C, 0x22, 0x30, 0x09, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0xEE, 0x00, 0x9D, 0x40, 0xF0, 0x06, ++0x10, 0x0B, 0x40, 0xA7, 0x02, 0x9D, 0x01, 0xF4, 0x0A, 0x10, 0x9B, 0x40, 0x27, ++0x01, 0x9B, 0x80, 0x44, 0x06, 0x10, 0x29, 0x44, 0x2F, 0x00, 0xB1, 0x03, 0x84, ++0x02, 0x10, 0x0B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x24, 0x04, 0x9D, 0x80, 0x70, 0x22, 0x10, 0x09, 0x40, 0x27, ++0x00, 0x9D, 0x00, 0x74, 0x42, 0x10, 0x09, 0x40, 0x27, 0x00, 0x91, 0x08, 0x44, ++0x43, 0x14, 0x29, 0x40, 0x27, 0x02, 0x80, 0x00, 0x44, 0xC2, 0x10, 0x09, 0x40, ++0x70, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, ++0x18, 0x8D, 0x42, 0x34, 0x0A, 0x14, 0x28, 0x44, 0xB3, 0x00, 0x8D, 0x00, 0x36, ++0x02, 0x11, 0x28, 0x40, 0x23, 0x45, 0x89, 0x14, 0x04, 0x02, 0x10, 0x08, 0x40, ++0xA3, 0x00, 0x81, 0x02, 0x04, 0x02, 0x10, 0x08, 0x40, 0x50, 0xA0, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x46, 0x00, 0x1F, 0x00, 0x7C, ++0x04, 0x12, 0x11, 0xC2, 0x07, 0x10, 0x1F, 0x00, 0x7C, 0x04, 0x34, 0x11, 0xC0, ++0x07, 0x01, 0x13, 0x04, 0x4C, 0x00, 0x32, 0x01, 0xC0, 0x47, 0x40, 0x53, 0x01, ++0x4C, 0x04, 0x34, 0x11, 0xD0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x19, 0xB8, 0xA7, 0x00, 0xBF, 0x01, 0xFC, 0x8E, 0xF0, 0x3B, 0xC0, ++0x7F, 0x20, 0xBE, 0x00, 0x7C, 0x0A, 0xF0, 0x3B, 0xC0, 0x27, 0x00, 0xF7, 0x00, ++0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0xEF, 0x00, 0x9C, 0x23, 0xFD, 0x0A, 0xF0, 0x29, ++0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, ++0x6B, 0x00, 0x93, 0x82, 0xFC, 0x16, 0xF0, 0x7B, 0xC1, 0x2C, 0x00, 0xB3, 0x00, ++0xFC, 0x06, 0xF0, 0x7B, 0xC1, 0x6C, 0x01, 0xBE, 0x81, 0xCC, 0x02, 0xF0, 0x0B, ++0xD0, 0xEC, 0x01, 0xBF, 0x07, 0xFC, 0x16, 0xF0, 0x1B, 0xC0, 0x60, 0x00, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x87, 0x00, 0x51, 0x05, ++0x74, 0x54, 0xD0, 0x31, 0x40, 0x40, 0x05, 0x11, 0x00, 0x74, 0x00, 0xD1, 0x31, ++0x44, 0x05, 0x00, 0x1D, 0x0A, 0x44, 0x01, 0xD0, 0x01, 0x40, 0x44, 0x20, 0x1D, ++0x03, 0x74, 0x28, 0xD2, 0x01, 0x48, 0x70, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA0, 0xA3, 0x40, 0x85, 0x44, 0x36, 0x0A, 0xD8, 0x49, ++0x40, 0x22, 0x00, 0x81, 0x21, 0x34, 0x0A, 0xD1, 0x48, 0x40, 0xA0, 0x00, 0x8D, ++0xA0, 0x04, 0x02, 0xD1, 0x08, 0x60, 0xA2, 0x11, 0xCD, 0x06, 0x34, 0x82, 0xD0, ++0x28, 0x40, 0x48, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0xA8, 0x25, 0x80, 0x95, 0x01, 0x74, 0x82, 0xD0, 0x19, 0x41, 0x22, 0x40, 0x91, ++0x00, 0x74, 0x03, 0xD0, 0x09, 0x40, 0x25, 0x00, 0x9D, 0x00, 0x44, 0x02, 0xD0, ++0x09, 0x41, 0x26, 0x05, 0x9D, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, 0x60, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, 0xB7, ++0x00, 0xFC, 0x06, 0xF2, 0x0A, 0xD0, 0xAE, 0x10, 0x93, 0x0B, 0x7C, 0x02, 0xF0, ++0x0B, 0xC0, 0x24, 0x20, 0x9F, 0x03, 0x4C, 0x8E, 0xF0, 0x08, 0xC0, 0xEE, 0x00, ++0xBF, 0x00, 0x7C, 0x06, 0xF0, 0x08, 0xD0, 0x14, 0x20, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x25, 0x00, 0x9B, 0x00, 0x7C, 0x0E, 0xF0, ++0x09, 0xC0, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x39, 0xC0, 0x27, 0x0C, ++0x8F, 0x49, 0x7D, 0x12, 0xF1, 0x49, 0xC0, 0x25, 0x00, 0x9F, 0x00, 0x7C, 0x52, ++0xF0, 0x09, 0x81, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x08, 0x01, 0x01, 0x13, 0x02, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x04, 0x00, ++0x1B, 0x08, 0x7C, 0x80, 0xF0, 0x01, 0xC0, 0x04, 0x00, 0x17, 0x88, 0x7C, 0x00, ++0xF1, 0x21, 0xC0, 0x05, 0x00, 0x1B, 0x04, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x43, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0xDC, 0x00, ++0x50, 0x00, 0x74, 0x01, 0x10, 0x05, 0x42, 0x5C, 0x02, 0x51, 0x00, 0xF4, 0x05, ++0xD0, 0x15, 0x41, 0x1C, 0x00, 0x51, 0x81, 0xF4, 0x05, 0xD0, 0x07, 0x41, 0x14, ++0x04, 0x71, 0x40, 0xF4, 0x0D, 0xD0, 0x27, 0x40, 0x53, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0xE2, 0x00, 0xC9, 0x00, 0x34, 0x07, ++0x90, 0x9C, 0x40, 0x20, 0x22, 0x89, 0x20, 0x34, 0x06, 0xD0, 0x0D, 0x40, 0xB0, ++0x0A, 0x85, 0x01, 0x34, 0x23, 0xD0, 0x08, 0x43, 0x73, 0x00, 0x89, 0x00, 0x34, ++0x0E, 0xD0, 0xA8, 0x40, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0x80, 0xA8, 0x00, 0xE9, 0x04, 0x34, 0x0E, 0x90, 0xCA, 0x50, 0x38, ++0x01, 0xE1, 0x00, 0xB4, 0x0A, 0xD0, 0x0E, 0x70, 0x48, 0x00, 0xE1, 0x00, 0xB4, ++0x00, 0xD0, 0x02, 0x40, 0x7A, 0x00, 0x61, 0x00, 0xB4, 0x42, 0xD1, 0x0A, 0x60, ++0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x68, ++0x00, 0xEB, 0x07, 0xBC, 0x07, 0xB0, 0x1C, 0xC0, 0xD8, 0x00, 0xEB, 0x01, 0xBC, ++0x06, 0xF0, 0x5F, 0xC0, 0x58, 0x00, 0xE7, 0x01, 0xBC, 0x04, 0xF1, 0x16, 0xC2, ++0x73, 0x00, 0xEB, 0x07, 0xBC, 0x06, 0xF0, 0x1A, 0xC0, 0x47, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x25, 0x40, 0xD7, 0x00, 0x7C, ++0x02, 0x74, 0x09, 0xC0, 0x17, 0x00, 0xDE, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, ++0x03, 0x00, 0xDF, 0x00, 0x7C, 0x00, 0xF0, 0x04, 0xC6, 0x35, 0x02, 0x5F, 0x00, ++0x7C, 0x02, 0xFA, 0x09, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA0, 0x7F, 0x00, 0xF3, 0x01, 0xDC, 0x47, 0x30, 0x1F, 0xC2, ++0x78, 0x00, 0xF3, 0x01, 0xFC, 0x07, 0x30, 0x1B, 0x41, 0x4D, 0x00, 0xF1, 0x09, ++0xCC, 0x06, 0xE0, 0x16, 0xE0, 0x6C, 0x01, 0xE3, 0x01, 0xCC, 0x07, 0x30, 0x9B, ++0xC2, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, ++0xB9, 0x10, 0xE1, 0x10, 0x84, 0x02, 0x12, 0x0B, 0x41, 0x38, 0x20, 0xE1, 0x00, ++0xB4, 0x02, 0x10, 0x0A, 0x40, 0x08, 0x01, 0xE1, 0x08, 0x84, 0x00, 0xD1, 0x0E, ++0xD0, 0x2C, 0x41, 0x61, 0x00, 0xC4, 0x02, 0x10, 0x8A, 0x40, 0x57, 0x60, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0xF9, 0x01, ++0x94, 0x03, 0x14, 0x8E, 0x40, 0x1C, 0x00, 0xE1, 0x00, 0x34, 0x03, 0x90, 0x0A, ++0x40, 0x08, 0x00, 0xF9, 0x00, 0xA4, 0x00, 0xD0, 0x8E, 0x41, 0x28, 0x13, 0xE1, ++0x00, 0xD4, 0x23, 0x90, 0x0A, 0x44, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x04, 0x28, 0x23, 0x00, 0xC9, 0x02, 0x06, 0x06, 0x10, 0x09, ++0x42, 0x10, 0x00, 0xC1, 0x06, 0x34, 0x02, 0x90, 0x08, 0x40, 0x00, 0x00, 0xC9, ++0x01, 0x26, 0x4C, 0xD0, 0x0C, 0x42, 0x20, 0x04, 0x41, 0x00, 0x14, 0x81, 0x90, ++0x08, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA8, 0x25, 0x00, 0xDB, 0x00, 0x5C, 0x03, 0x30, 0x1D, 0xC0, 0x74, 0x48, 0xD3, ++0x13, 0x7C, 0x02, 0xB4, 0x1D, 0xC0, 0x05, 0x00, 0xCB, 0x01, 0x6C, 0x46, 0xF0, ++0x1D, 0xE0, 0x74, 0x00, 0xD3, 0x40, 0x1D, 0x06, 0xB0, 0x0D, 0xC0, 0x57, 0x20, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x27, 0x40, 0xD7, ++0x00, 0x7C, 0x22, 0xF0, 0x49, 0xD0, 0x37, 0x02, 0xDF, 0x00, 0x7C, 0x0A, 0x70, ++0x8D, 0xD0, 0x07, 0x00, 0xD7, 0x0C, 0x5D, 0x00, 0xF0, 0x05, 0xC9, 0x35, 0x02, ++0x4F, 0x00, 0x64, 0x22, 0x74, 0x29, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x2F, 0x00, 0xFF, 0x10, 0x4C, 0x0B, 0xF0, ++0x0F, 0xC0, 0x5C, 0x00, 0xFF, 0x80, 0xEC, 0x0E, 0xF0, 0x8C, 0xC0, 0x04, 0x00, ++0xFF, 0x08, 0xCC, 0x00, 0xF0, 0x87, 0xC0, 0x7E, 0x20, 0xF3, 0x08, 0xCC, 0x02, ++0x33, 0x2F, 0xC6, 0x13, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x81, 0x00, 0x26, 0x00, 0xDD, 0x00, 0x44, 0x87, 0xD0, 0x19, 0xC0, 0xF6, 0x00, ++0xCD, 0x09, 0x44, 0x00, 0xD2, 0x19, 0x40, 0x44, 0x04, 0xDC, 0x20, 0x6C, 0x04, ++0x90, 0x04, 0x40, 0x21, 0x00, 0xD3, 0x02, 0x44, 0x02, 0x10, 0x19, 0x40, 0x17, ++0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x82, ++0xCD, 0x00, 0x44, 0x03, 0xD0, 0x4D, 0x50, 0xB4, 0x02, 0xDD, 0x00, 0x64, 0x03, ++0xD8, 0x09, 0x40, 0x44, 0x20, 0xDD, 0x00, 0x44, 0x06, 0xD0, 0x05, 0x44, 0x24, ++0x01, 0xD0, 0x10, 0x44, 0x03, 0x10, 0x0D, 0x41, 0x07, 0x00, 0x02, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0xCD, 0x00, 0x04, 0x02, ++0xD0, 0x0C, 0x40, 0x12, 0x00, 0xDD, 0x00, 0x04, 0x03, 0xD0, 0x08, 0x40, 0x00, ++0x00, 0xCD, 0x00, 0x26, 0x00, 0x90, 0x0D, 0x40, 0x35, 0x40, 0x41, 0x00, 0x05, ++0x02, 0x1C, 0x04, 0x44, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xB0, 0x16, 0x00, 0xFF, 0x40, 0x4C, 0x02, 0xF0, 0x09, 0x40, 0x14, ++0x20, 0xDF, 0x00, 0x6C, 0x03, 0xD0, 0x0D, 0xC4, 0x04, 0x08, 0xDF, 0x00, 0x4C, ++0x00, 0xF0, 0x0D, 0xC0, 0x26, 0x10, 0x53, 0x00, 0x4C, 0x03, 0x30, 0x0D, 0xC2, ++0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x1F, ++0x00, 0xEF, 0x00, 0xFC, 0x02, 0xF0, 0x0B, 0xC0, 0x1D, 0x00, 0xFF, 0x00, 0xFC, ++0x01, 0xF0, 0x0B, 0xD0, 0x0F, 0x00, 0xEF, 0x00, 0xFC, 0x00, 0xF0, 0x0F, 0xC0, ++0x2F, 0x00, 0x77, 0x40, 0xFC, 0x01, 0xF0, 0x07, 0xC0, 0x17, 0x22, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x7F, 0x00, 0xEF, 0x09, 0xDC, ++0x06, 0xF2, 0x1F, 0xC0, 0x7D, 0x00, 0xE3, 0x01, 0xDC, 0x12, 0x30, 0x13, 0xC0, ++0x4E, 0x10, 0xB3, 0x00, 0xDC, 0x32, 0x70, 0x2B, 0xC0, 0xBC, 0x00, 0xB3, 0x20, ++0xFC, 0x10, 0x30, 0x02, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0x18, 0x77, 0x00, 0xDD, 0x04, 0x44, 0x06, 0x10, 0x1D, 0x40, ++0x74, 0x00, 0xD1, 0x01, 0x44, 0x0E, 0x10, 0x11, 0x40, 0x74, 0x00, 0x51, 0x43, ++0x44, 0xB2, 0x10, 0xA1, 0x40, 0xBC, 0x03, 0x11, 0x32, 0x74, 0x26, 0x50, 0x11, ++0x40, 0x0C, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, ++0x33, 0x00, 0xCD, 0x04, 0x14, 0x03, 0x58, 0x0C, 0x40, 0x27, 0x00, 0xD5, 0x00, ++0x17, 0x08, 0x10, 0x01, 0x60, 0x06, 0x08, 0x81, 0x28, 0x16, 0x12, 0xD8, 0x40, ++0x40, 0x30, 0x00, 0x05, 0x86, 0x34, 0x00, 0x18, 0x08, 0x60, 0x4E, 0x80, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x35, 0x00, 0xDD, 0x04, ++0x54, 0x07, 0x10, 0x0D, 0x46, 0x26, 0x00, 0xD5, 0x11, 0x44, 0x0C, 0x12, 0x11, ++0x40, 0x74, 0x00, 0x91, 0x01, 0x44, 0x46, 0x18, 0x10, 0x40, 0x36, 0x00, 0x15, ++0x01, 0x74, 0x43, 0x52, 0x19, 0x41, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xA8, 0x37, 0x08, 0xDF, 0x00, 0x1E, 0x06, 0x70, 0xD5, ++0xC0, 0xD3, 0x00, 0xC7, 0x03, 0x5C, 0x0C, 0x30, 0x30, 0xC4, 0x52, 0x04, 0x92, ++0x07, 0x5D, 0x04, 0x70, 0x39, 0xC0, 0x34, 0x00, 0x97, 0x61, 0x7C, 0x8D, 0x30, ++0x39, 0xC0, 0x2A, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++0x80, 0x3D, 0x30, 0xFF, 0x01, 0xEC, 0x02, 0xF0, 0x0F, 0xC0, 0x7D, 0x02, 0xFB, ++0x00, 0xFC, 0x02, 0xF0, 0x03, 0xC0, 0x1F, 0x00, 0x6F, 0x20, 0xBC, 0x00, 0xF0, ++0x03, 0xD0, 0x3D, 0x00, 0x3B, 0x20, 0xFC, 0x24, 0xF1, 0x0B, 0xC0, 0x1F, 0x00, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0x35, 0x00, 0xDF, ++0x00, 0x5C, 0x03, 0xB0, 0x49, 0xC0, 0xA5, 0x00, 0xDB, 0x02, 0x4C, 0x00, 0xF0, ++0x21, 0xC0, 0x17, 0x02, 0xD7, 0x05, 0x6C, 0x02, 0xF1, 0x09, 0xC0, 0x37, 0x44, ++0x93, 0x02, 0x6C, 0x0B, 0xF0, 0x29, 0xC4, 0x2B, 0x20, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, 0x00, 0xDD, 0x4D, 0x40, 0x0F, 0x15, ++0x38, 0x40, 0x24, 0x10, 0x91, 0x00, 0x2C, 0x44, 0xD1, 0xB1, 0x44, 0x54, 0x10, ++0xD1, 0x01, 0x74, 0xB2, 0xD2, 0x01, 0x4A, 0xFF, 0x00, 0x90, 0x30, 0x34, 0x83, ++0xD1, 0x08, 0x40, 0x4C, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0xA0, 0x32, 0x00, 0xDD, 0x00, 0x14, 0x26, 0x10, 0x9C, 0x48, 0x31, 0x00, ++0xCC, 0x08, 0x25, 0x02, 0xD0, 0x10, 0x40, 0x11, 0x00, 0x85, 0x02, 0x34, 0x00, ++0xD0, 0x08, 0x42, 0x36, 0x00, 0x85, 0x25, 0x24, 0x00, 0xD0, 0xB0, 0x41, 0x0D, ++0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x08, 0x7A, 0x00, ++0xFD, 0x01, 0xC4, 0x1E, 0x18, 0x9F, 0x40, 0x7C, 0x10, 0xF5, 0x41, 0xB4, 0x07, ++0xD0, 0x12, 0x00, 0x58, 0x00, 0xA0, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x00, 0x73, ++0x04, 0xE5, 0x01, 0xB4, 0x04, 0xD1, 0x16, 0x00, 0x34, 0x20, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xCF, 0x00, 0x1C, 0x02, ++0x30, 0x8C, 0xC0, 0xB1, 0x00, 0xCF, 0x00, 0x2C, 0x03, 0xF0, 0xE0, 0xC3, 0x11, ++0x00, 0x87, 0x00, 0x28, 0x01, 0xF0, 0x04, 0xC0, 0x32, 0x30, 0x47, 0x00, 0x2C, ++0x03, 0xF0, 0x00, 0xC0, 0x49, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xA0, 0x3D, 0x00, 0xFF, 0x00, 0xBC, 0x12, 0x70, 0x8E, 0xC0, 0x3B, ++0x02, 0xFB, 0x88, 0xEC, 0x23, 0xF0, 0x82, 0xC0, 0x19, 0x00, 0xBB, 0x00, 0xFC, ++0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x20, 0x7B, 0x40, 0xFC, 0x23, 0xF0, 0x8F, 0xC0, ++0x09, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x37, ++0x00, 0x9F, 0x00, 0x3C, 0x06, 0x70, 0x0D, 0xE0, 0x35, 0x00, 0xDF, 0x00, 0x44, ++0x01, 0xB2, 0x05, 0xC2, 0x13, 0x00, 0xCB, 0x00, 0x6C, 0x05, 0x72, 0x0D, 0xC2, ++0xB7, 0x03, 0xDD, 0x00, 0x6C, 0x00, 0xF0, 0x15, 0x80, 0x40, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x98, 0x39, 0x10, 0xEC, 0x00, 0xB4, ++0x82, 0x10, 0x0E, 0x52, 0x38, 0x00, 0x6D, 0x00, 0x94, 0x03, 0x90, 0x06, 0x40, ++0x1B, 0x00, 0xE1, 0x00, 0xC5, 0x01, 0x10, 0x0E, 0x48, 0x3B, 0x05, 0xED, 0x00, ++0x84, 0x00, 0x90, 0x0E, 0x40, 0x4C, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x00, 0x79, 0x20, 0xAC, 0x91, 0xB4, 0x06, 0xD0, 0x1F, 0x48, ++0x79, 0x20, 0xFD, 0x01, 0xB4, 0x47, 0x90, 0x1E, 0x60, 0x5B, 0x00, 0xE9, 0x01, ++0xA4, 0x07, 0x50, 0x1E, 0x41, 0x7B, 0x00, 0xCD, 0x03, 0xB4, 0x07, 0xD8, 0x14, ++0x64, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x20, ++0x33, 0x00, 0xCD, 0x01, 0x34, 0x40, 0xD0, 0x5C, 0x40, 0x31, 0x00, 0xCD, 0x05, ++0x34, 0x03, 0x98, 0x24, 0x40, 0x93, 0x08, 0xC1, 0x08, 0x04, 0x03, 0x10, 0x2C, ++0x41, 0x33, 0x88, 0xDD, 0x00, 0x14, 0x1F, 0x90, 0x2C, 0x40, 0x58, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x17, 0x00, 0x5F, 0x01, ++0xFC, 0x09, 0xF0, 0x07, 0x40, 0x1D, 0x00, 0x7F, 0x01, 0xFC, 0x01, 0xB0, 0x77, ++0xC0, 0x5B, 0x00, 0x6B, 0x01, 0xEC, 0x29, 0x70, 0x07, 0xC0, 0x17, 0x00, 0x7F, ++0x08, 0xFC, 0x01, 0xF0, 0x47, 0x40, 0x5C, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x00, 0x1F, 0xC2, 0x7C, 0x00, 0x00, 0xA1, ++0x80, 0x06, 0x01, 0x1C, 0x08, 0x58, 0x00, 0xC3, 0x01, 0x88, 0x07, 0x02, 0x1F, ++0x42, 0x7C, 0x20, 0xF0, 0x01, 0xC0, 0x87, 0x20, 0x1F, 0x40, 0x60, 0x20, 0xB0, ++0x01, 0xD0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x25, 0x00, 0x9F, 0x03, 0x7C, 0x12, 0xF9, 0x09, 0xC8, 0x25, 0x00, 0x9F, ++0x04, 0x1C, 0x56, 0x31, 0x89, 0xC3, 0x27, 0x04, 0x97, 0x05, 0x40, 0x06, 0xF0, ++0x09, 0xC0, 0x27, 0x01, 0x9F, 0x00, 0x4C, 0x82, 0xF3, 0x39, 0xC1, 0x43, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, ++0x03, 0x74, 0x0A, 0xD8, 0x48, 0x40, 0x24, 0x10, 0x8D, 0x00, 0x44, 0x06, 0x14, ++0x19, 0x44, 0xE7, 0x81, 0x9B, 0x12, 0x44, 0x0E, 0xD0, 0x09, 0x40, 0x67, 0x20, ++0x9D, 0x0E, 0x44, 0x02, 0x78, 0x39, 0x40, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x0B, 0x98, ++0x09, 0x40, 0x25, 0x00, 0x9D, 0x02, 0x56, 0x02, 0x50, 0x09, 0x48, 0x67, 0x00, ++0x95, 0x00, 0x54, 0x1A, 0xD0, 0x0D, 0x60, 0x27, 0x00, 0xDD, 0x00, 0x44, 0x02, ++0x50, 0x29, 0x40, 0x73, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x14, 0x28, 0x20, 0x00, 0xCD, 0x00, 0x34, 0x02, 0xD0, 0x09, 0x40, 0x20, 0x00, ++0x8D, 0x80, 0x14, 0xD2, 0x50, 0x0C, 0x40, 0x23, 0x00, 0x81, 0x00, 0x10, 0x52, ++0xD0, 0x48, 0x61, 0x33, 0x0D, 0x8D, 0x14, 0x14, 0x02, 0x50, 0x48, 0x41, 0x53, ++0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x30, 0x04, 0x00, ++0x1F, 0x00, 0x7C, 0x00, 0x90, 0x01, 0xC0, 0x05, 0x00, 0x1F, 0x80, 0x5C, 0x10, ++0x70, 0x01, 0xC0, 0x07, 0x20, 0x14, 0x14, 0x4D, 0x10, 0xF0, 0x41, 0xC0, 0x07, ++0x01, 0x1F, 0x04, 0x4D, 0x50, 0x70, 0x41, 0xE2, 0x77, 0xC0, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, 0x27, 0x00, 0xBF, 0x94, 0xFC, 0x02, ++0xC0, 0x0E, 0x40, 0x3F, 0x00, 0xAF, 0x80, 0xEC, 0x02, 0xB0, 0x0B, 0xC0, 0x2F, ++0x00, 0xBF, 0x00, 0xEC, 0x52, 0xF0, 0x4B, 0x41, 0x27, 0x05, 0xBF, 0x14, 0xEC, ++0x02, 0x70, 0x0B, 0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA0, 0x27, 0x00, 0xBF, 0x08, 0xFC, 0x02, 0x79, 0x0A, 0xC0, 0x25, ++0x00, 0xBF, 0x00, 0xCC, 0x06, 0xB1, 0x0B, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0xDD, ++0x12, 0xF0, 0x99, 0xC0, 0x6D, 0x03, 0xB9, 0x0D, 0xF8, 0x02, 0x30, 0x0B, 0xC8, ++0x60, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, 0x07, ++0x00, 0x1D, 0x41, 0x74, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x1D, 0x00, 0x44, ++0x28, 0x10, 0x01, 0x40, 0x07, 0x00, 0x1D, 0x40, 0x44, 0x10, 0xD0, 0xB1, 0x40, ++0xC4, 0x03, 0x11, 0x0F, 0x74, 0x00, 0x10, 0x01, 0x50, 0x70, 0x60, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x23, 0x00, 0x8D, 0x04, 0x74, ++0x02, 0xD4, 0x08, 0x40, 0x21, 0x20, 0x9D, 0x00, 0x17, 0x02, 0x90, 0x08, 0x40, ++0x23, 0x00, 0x9D, 0x00, 0x36, 0x62, 0xD0, 0x48, 0x40, 0x23, 0x00, 0x89, 0x00, ++0x34, 0x02, 0x14, 0x08, 0x48, 0x49, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x18, 0xA0, 0x25, 0x00, 0x9D, 0x80, 0x74, 0x42, 0x12, 0x09, 0x44, ++0x24, 0x00, 0x9D, 0x40, 0x52, 0x46, 0x00, 0x09, 0x41, 0x27, 0x00, 0x9D, 0x00, ++0x74, 0x8E, 0xD0, 0x09, 0x61, 0x24, 0x00, 0x91, 0x10, 0x74, 0x02, 0x10, 0x09, ++0x40, 0x60, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, ++0x26, 0x00, 0x9D, 0x00, 0x78, 0x0A, 0xF2, 0x08, 0xC0, 0x25, 0x80, 0x9F, 0x04, ++0x5C, 0x0A, 0xB2, 0x09, 0xC2, 0x27, 0x08, 0x9F, 0x19, 0x7C, 0x02, 0xF0, 0x39, ++0xC0, 0x25, 0x20, 0x9A, 0x03, 0x7E, 0x16, 0x20, 0x09, 0xE5, 0x15, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x25, 0x00, 0x9F, 0x00, ++0x7C, 0x12, 0xF0, 0x29, 0xC0, 0xA6, 0x00, 0x9F, 0x28, 0x2C, 0x02, 0xF0, 0x09, ++0xC0, 0x27, 0x00, 0x9F, 0x90, 0x4C, 0x02, 0xF0, 0x48, 0xC4, 0x27, 0x00, 0x9F, ++0x89, 0x7E, 0x22, 0xF2, 0x08, 0xE0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0x05, 0x00, 0x1F, 0x04, 0x7C, 0x18, 0xB2, 0x41, ++0xC0, 0x04, 0x20, 0x1F, 0x06, 0x4C, 0x28, 0xF2, 0x61, 0xC0, 0x05, 0x02, 0x1F, ++0x02, 0x6C, 0x08, 0xB0, 0x21, 0xC2, 0x07, 0x00, 0x1F, 0x12, 0x1C, 0x08, 0x30, ++0x21, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0xA0, 0x14, 0x00, 0x7D, 0x11, 0xB0, 0x0D, 0x10, 0x17, 0x58, 0x14, 0x00, 0x6D, ++0x03, 0x45, 0x05, 0xD0, 0x17, 0x44, 0x9F, 0x02, 0x6D, 0x00, 0xC0, 0x01, 0x10, ++0x05, 0x40, 0x9F, 0x02, 0x7D, 0x80, 0x44, 0x01, 0x10, 0x27, 0x00, 0x50, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, ++0x00, 0x34, 0x8A, 0x90, 0xAC, 0x04, 0x30, 0x00, 0x45, 0x02, 0x12, 0x06, 0xD1, ++0x2C, 0x40, 0x91, 0x00, 0xCD, 0x22, 0x24, 0x17, 0x90, 0x0C, 0x40, 0x37, 0xA2, ++0xCD, 0x08, 0x16, 0xA7, 0x10, 0x4C, 0x50, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x38, 0x00, 0x6D, 0x00, 0xF4, 0x0A, 0x10, ++0x0E, 0x40, 0x38, 0x00, 0x6D, 0x10, 0xB4, 0x03, 0xD0, 0x0E, 0x61, 0x1B, 0x80, ++0xFD, 0x30, 0xA0, 0x47, 0x90, 0x4E, 0x40, 0x3B, 0xA0, 0x6D, 0x01, 0x84, 0x03, ++0x50, 0x2C, 0x40, 0x04, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x11, 0x10, 0x78, 0x00, 0xEF, 0x01, 0xBC, 0x06, 0xB0, 0x1E, 0xC0, 0x78, 0x20, ++0x6F, 0x01, 0x9C, 0x07, 0xF0, 0x1E, 0xE0, 0x59, 0x00, 0xEF, 0x01, 0xE8, 0x07, ++0xB0, 0xBE, 0xC0, 0x7B, 0x20, 0xFF, 0x21, 0x1C, 0x07, 0x34, 0x1E, 0xC0, 0x44, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, ++0xDF, 0x00, 0x3C, 0x02, 0xF0, 0x0D, 0xC0, 0x37, 0x10, 0x4F, 0x00, 0x4D, 0x83, ++0xF0, 0x0D, 0xE0, 0x17, 0x00, 0xCF, 0x00, 0x5C, 0x03, 0x70, 0x6D, 0xC4, 0x17, ++0x08, 0x5E, 0x40, 0x7C, 0x03, 0xB0, 0x09, 0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7D, 0x00, 0xFF, 0x01, 0xFC, 0x07, ++0x30, 0x17, 0xC0, 0x7D, 0x00, 0x7F, 0x01, 0xDC, 0x27, 0xF1, 0x9F, 0xC0, 0x5F, ++0x00, 0xEF, 0x01, 0xEC, 0x85, 0xB0, 0x9F, 0x00, 0x5F, 0x02, 0xF3, 0x4D, 0xC8, ++0x07, 0x20, 0x1F, 0xC0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0x18, 0x39, 0x00, 0x6D, 0x42, 0xB4, 0x12, 0x10, 0x0E, 0x40, 0x38, ++0x00, 0x29, 0x44, 0x80, 0x03, 0xD0, 0x0E, 0x40, 0x1B, 0x00, 0x6D, 0x02, 0x94, ++0x01, 0xD0, 0x0E, 0x43, 0x1A, 0x00, 0xE1, 0x18, 0x84, 0x53, 0x10, 0x07, 0x41, ++0x55, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, ++0x00, 0xED, 0x00, 0xF4, 0x02, 0x18, 0x2E, 0x50, 0xB9, 0x00, 0x6D, 0xB2, 0x80, ++0x43, 0xD0, 0x0E, 0x42, 0x1B, 0x04, 0xED, 0x18, 0x95, 0x01, 0x90, 0x0E, 0x42, ++0x3A, 0x30, 0xE1, 0x44, 0xB5, 0x03, 0x1C, 0x0F, 0x40, 0x00, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x30, 0x00, 0x8D, 0x00, 0x34, ++0x0A, 0x18, 0x0C, 0x58, 0x31, 0x08, 0x49, 0x01, 0x04, 0x07, 0xD0, 0x08, 0x40, ++0xD3, 0x00, 0x4D, 0x03, 0x04, 0x9C, 0xD0, 0x1D, 0x48, 0x02, 0x80, 0x91, 0x01, ++0x34, 0x13, 0x10, 0x30, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, 0x9F, 0x00, 0x74, 0x0B, 0x30, 0x2D, 0xC0, ++0x31, 0x00, 0xCF, 0x02, 0x4D, 0x23, 0xF2, 0x0D, 0xC0, 0xD7, 0x00, 0xCF, 0x09, ++0x5C, 0x1A, 0xB0, 0x3F, 0x40, 0x26, 0x20, 0x91, 0x02, 0x7C, 0x02, 0x30, 0x2D, ++0xC0, 0x54, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, ++0x37, 0x00, 0x1F, 0x01, 0x7C, 0x43, 0xF0, 0x0D, 0x40, 0x36, 0x00, 0xDB, 0x02, ++0x7C, 0x03, 0xF0, 0x6D, 0xC4, 0x17, 0x01, 0xDF, 0x00, 0x74, 0x00, 0xD0, 0x0D, ++0xC1, 0x26, 0x00, 0x1F, 0x02, 0x4C, 0x02, 0xF1, 0x4D, 0xC0, 0x07, 0x00, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x08, 0x3F, 0x08, 0x3F, 0x00, ++0xFC, 0x02, 0xF0, 0x0F, 0xC0, 0x3D, 0x08, 0x77, 0x00, 0xCC, 0x03, 0xE0, 0x9F, ++0xD0, 0x1C, 0x00, 0xF9, 0x00, 0x8D, 0x02, 0xB0, 0x0F, 0xC0, 0x24, 0x00, 0x9F, ++0x10, 0x48, 0x82, 0xD0, 0x07, 0xC0, 0x13, 0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x85, 0x20, 0x36, 0x00, 0x1D, 0x03, 0x74, 0x86, 0xD2, 0x3C, ++0x41, 0x34, 0x00, 0x51, 0x21, 0x44, 0x03, 0xD0, 0x5C, 0x40, 0x54, 0x08, 0xDD, ++0x43, 0x44, 0x4E, 0x10, 0x0D, 0x40, 0x64, 0x00, 0x1D, 0x07, 0x6C, 0xA2, 0xD2, ++0x01, 0x40, 0x17, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++0xA0, 0x34, 0x00, 0x9D, 0x01, 0x74, 0x07, 0xD0, 0x1D, 0x40, 0x35, 0x00, 0x55, ++0x03, 0x45, 0x07, 0xD2, 0x0D, 0x42, 0x55, 0x04, 0x9D, 0x81, 0x54, 0x06, 0x90, ++0x0D, 0x50, 0xC4, 0x00, 0x1D, 0x01, 0x54, 0x03, 0xD0, 0x89, 0x41, 0x07, 0x08, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x30, 0x00, 0x0D, ++0x00, 0x34, 0x07, 0xD0, 0x09, 0x40, 0x34, 0x00, 0x51, 0x00, 0x04, 0x03, 0xD0, ++0x04, 0x40, 0x10, 0x00, 0x4D, 0x00, 0x04, 0x00, 0x18, 0x0C, 0x40, 0x00, 0x00, ++0x1D, 0x00, 0x36, 0x83, 0xD0, 0x00, 0x40, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x36, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, ++0x0D, 0xC0, 0x35, 0x00, 0x57, 0x00, 0x48, 0x03, 0xF0, 0x0D, 0x40, 0x34, 0x10, ++0x5B, 0x00, 0x48, 0x02, 0xB0, 0x0F, 0xC0, 0x24, 0x00, 0x9F, 0x00, 0x5C, 0x03, ++0xF0, 0x01, 0xC8, 0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xA0, 0x3F, 0x00, 0xBF, 0x00, 0xB4, 0x00, 0xF0, 0x0A, 0xC0, 0x3F, 0x20, ++0x6F, 0x00, 0xFC, 0x03, 0xE0, 0x0F, 0xC0, 0x2F, 0x00, 0x7E, 0x00, 0xFC, 0x02, ++0xF0, 0x0F, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0xEC, 0x03, 0xF0, 0x03, 0xC0, 0x17, ++0x21, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x7F, 0x00, ++0xEF, 0x09, 0xCC, 0x27, 0xF2, 0x1F, 0xC0, 0x7C, 0x00, 0xFF, 0x01, 0xBC, 0x27, ++0xF0, 0x3F, 0xC0, 0x7F, 0x00, 0xEE, 0x09, 0xCC, 0x07, 0x31, 0x1E, 0xC0, 0x7C, ++0x00, 0xF3, 0x09, 0xFC, 0x07, 0x30, 0x1F, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x47, 0x10, 0x1D, 0x44, 0x44, 0x10, ++0xD0, 0x11, 0x40, 0x44, 0x00, 0x1D, 0x01, 0x74, 0x00, 0xD2, 0x01, 0x48, 0x47, ++0x00, 0x1D, 0x44, 0x44, 0x04, 0x50, 0x11, 0x40, 0x44, 0x00, 0x11, 0x84, 0x74, ++0x04, 0x14, 0x11, 0x40, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x11, 0xA0, 0x33, 0x00, 0xDD, 0x00, 0x14, 0x03, 0xD0, 0x0D, 0x40, 0x30, ++0x08, 0xCC, 0x80, 0x36, 0x13, 0xD0, 0x4C, 0x40, 0x33, 0x00, 0xCD, 0x00, 0x04, ++0x03, 0x11, 0x0C, 0x40, 0x30, 0x00, 0xC1, 0x80, 0x74, 0x03, 0x18, 0x0C, 0x40, ++0x44, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x05, ++0x00, 0x1D, 0x00, 0x54, 0x80, 0xD0, 0x01, 0x40, 0x04, 0x18, 0x1D, 0x00, 0x74, ++0x00, 0xD0, 0x01, 0x40, 0x07, 0x00, 0x0D, 0x00, 0x45, 0x00, 0x50, 0x01, 0x40, ++0x04, 0x00, 0x11, 0x60, 0x76, 0x00, 0x10, 0x01, 0x40, 0x0C, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x37, 0x00, 0xDF, 0x20, 0x5C, ++0x03, 0xF2, 0x0D, 0xD0, 0x34, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, ++0x37, 0x00, 0xDF, 0x00, 0x4C, 0x83, 0x30, 0x0C, 0xC0, 0x30, 0x00, 0xD3, 0x00, ++0x3C, 0x83, 0x31, 0x0D, 0xC0, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x07, 0x80, 0x0D, 0x00, 0x3F, 0x00, 0xEC, 0x00, 0xF0, 0x03, 0xC0, ++0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x00, 0xF2, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0xB0, ++0xFC, 0x00, 0xF2, 0x03, 0xD0, 0x0F, 0x00, 0x3F, 0x80, 0xFC, 0x00, 0xF0, 0x03, ++0xD1, 0x1F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, ++0x35, 0x00, 0xDF, 0x01, 0x4C, 0x03, 0x30, 0x0D, 0xC0, 0x34, 0x00, 0xD3, 0x80, ++0x4C, 0x23, 0x34, 0x8D, 0xC0, 0x74, 0x00, 0xDF, 0x00, 0x4C, 0x03, 0x30, 0x0D, ++0xC0, 0x34, 0x01, 0xD3, 0x00, 0x4C, 0x83, 0xF0, 0x0D, 0xC0, 0x0B, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x04, 0x00, 0x0D, 0x00, ++0x40, 0x40, 0x10, 0x10, 0x50, 0x04, 0x00, 0x1A, 0x05, 0x44, 0x00, 0x10, 0x11, ++0xC0, 0x86, 0x00, 0x1D, 0x03, 0x04, 0x04, 0x10, 0x11, 0x40, 0x85, 0x08, 0x11, ++0x11, 0x6E, 0x2C, 0xD0, 0x30, 0x40, 0x4F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x07, 0xA8, 0x72, 0x02, 0xCD, 0x00, 0x06, 0x07, 0x00, 0x9C, ++0x40, 0x70, 0x80, 0xC1, 0x01, 0x20, 0x87, 0x10, 0x0C, 0x42, 0x30, 0x04, 0xCD, ++0x20, 0x04, 0x23, 0x1A, 0x1C, 0x40, 0x30, 0x00, 0xC1, 0x81, 0x24, 0x07, 0xD0, ++0x3C, 0x40, 0x1F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x80, 0x48, 0x02, 0x3D, 0x01, 0x84, 0x04, 0x10, 0x92, 0x40, 0x48, 0x00, 0x39, ++0x01, 0xE4, 0x04, 0x10, 0x33, 0x40, 0x4A, 0x20, 0x2D, 0x91, 0x85, 0x14, 0x18, ++0x13, 0x41, 0x49, 0x00, 0x21, 0x01, 0xA4, 0x44, 0xD0, 0x12, 0x41, 0x1B, 0x00, ++0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xCF, ++0x80, 0x44, 0x23, 0x34, 0x0C, 0xC0, 0x30, 0x26, 0xC3, 0x00, 0x2D, 0x23, 0x30, ++0x0C, 0x40, 0x30, 0x20, 0xCF, 0x44, 0x0E, 0x03, 0x34, 0x0C, 0xC0, 0x30, 0x40, ++0xD3, 0x08, 0x25, 0x03, 0xF0, 0x0C, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x0D, 0x08, 0x3F, 0x80, 0xFD, 0x00, 0xF0, ++0x02, 0xC0, 0x0B, 0x80, 0x2F, 0x00, 0xDC, 0x20, 0xF0, 0x82, 0xE0, 0x0F, 0x02, ++0x3F, 0x00, 0xBC, 0x10, 0xF0, 0x03, 0xC0, 0x0B, 0x00, 0x3F, 0x00, 0x5E, 0x00, ++0xF0, 0x13, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0xA0, 0x33, 0x00, 0xD7, 0x00, 0x7C, 0x83, 0xF0, 0x1D, 0xC0, 0x34, 0x00, ++0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x73, 0x00, 0xD3, 0x00, 0x1C, 0x03, ++0x30, 0x0D, 0xC0, 0x33, 0x00, 0xD3, 0x00, 0x7E, 0x03, 0xF0, 0x1D, 0xC0, 0x54, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x09, 0x20, ++0x21, 0x20, 0xB4, 0x00, 0xD0, 0x02, 0x40, 0x08, 0x10, 0x2D, 0x40, 0xB4, 0x00, ++0xD0, 0x02, 0x40, 0x0B, 0x00, 0x21, 0x00, 0x84, 0x00, 0x52, 0x02, 0x40, 0x0B, ++0x00, 0x21, 0x00, 0xB6, 0x00, 0xD1, 0x02, 0x40, 0x48, 0x60, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x79, 0x00, 0xE5, 0xC1, 0xB4, 0x07, ++0xD8, 0x1F, 0x40, 0x78, 0x00, 0xED, 0x01, 0xB4, 0x07, 0xD0, 0x1E, 0x4A, 0x7B, ++0x88, 0xE1, 0x01, 0x94, 0x07, 0x94, 0x1E, 0x40, 0x7F, 0x00, 0xE9, 0x01, 0xB4, ++0x87, 0xD2, 0x1E, 0x52, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x28, 0x03, 0x00, 0x01, 0x00, 0x34, 0x00, 0xD9, 0x00, 0x56, 0x00, ++0x08, 0x0D, 0x80, 0x76, 0x00, 0xD0, 0x00, 0x44, 0x03, 0x00, 0x01, 0x40, 0x04, ++0x00, 0xD0, 0x00, 0x48, 0x03, 0x08, 0x09, 0x00, 0x34, 0x00, 0xD0, 0x00, 0x40, ++0x48, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x11, ++0x00, 0x57, 0x00, 0x3C, 0x01, 0xF0, 0x05, 0xC0, 0x10, 0x00, 0x5F, 0x00, 0x7C, ++0x01, 0xF0, 0x04, 0xC0, 0x17, 0x40, 0x43, 0x00, 0x1C, 0x01, 0xB4, 0x05, 0xC0, ++0x17, 0x00, 0x5B, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC0, 0x5C, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x0F, 0x00, 0x3F, 0x00, 0xFC, ++0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xF4, 0x00, 0xF0, 0x03, 0xC4, ++0x8F, 0x00, 0x3F, 0x00, 0xFD, 0x08, 0x70, 0x23, 0xC0, 0x8F, 0x40, 0x37, 0x00, ++0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x93, 0x09, 0x7C, 0x26, 0x30, 0x19, 0xC0, ++0x67, 0x00, 0x93, 0x08, 0x7C, 0x0A, 0x31, 0x19, 0xC8, 0x66, 0x02, 0x9F, 0x80, ++0x6C, 0x02, 0x34, 0x09, 0xC0, 0x67, 0x40, 0x92, 0x05, 0x7C, 0x02, 0xF0, 0x09, ++0xC0, 0x43, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, ++0x26, 0x00, 0x91, 0x01, 0x74, 0x02, 0x51, 0x19, 0x40, 0x27, 0x00, 0x91, 0x01, ++0x74, 0x02, 0x10, 0x89, 0x40, 0x64, 0x01, 0x9D, 0x00, 0x44, 0x12, 0x10, 0x39, ++0x48, 0x23, 0x02, 0x91, 0x01, 0x74, 0x0E, 0xD0, 0x09, 0x40, 0x07, 0x00, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x01, 0xB1, 0x80, ++0xF4, 0x02, 0x10, 0x8B, 0x40, 0x2F, 0x01, 0xB1, 0x00, 0xF4, 0x02, 0x10, 0x0B, ++0x40, 0x2E, 0x20, 0xBD, 0x00, 0xC4, 0x02, 0x10, 0x8B, 0x40, 0x2F, 0x80, 0xB5, ++0x00, 0xF4, 0x52, 0xD0, 0x0B, 0x40, 0x63, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x20, 0x2C, 0x00, 0xA1, 0x02, 0xF4, 0x0A, 0x50, 0x0A, ++0x40, 0x2F, 0x00, 0xA1, 0x00, 0xB4, 0x0A, 0x04, 0x1A, 0x40, 0x2A, 0x00, 0xBD, ++0x00, 0x85, 0x02, 0x18, 0x0E, 0x40, 0x2B, 0x00, 0xA5, 0x02, 0xB4, 0x02, 0xD0, ++0x0A, 0x40, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, ++0xB0, 0x06, 0x00, 0x13, 0x00, 0x7C, 0x00, 0x30, 0x01, 0xC8, 0x07, 0x40, 0x13, ++0x00, 0x7C, 0x00, 0x30, 0x01, 0xC0, 0x06, 0x00, 0x0F, 0x40, 0x4C, 0x00, 0x32, ++0x01, 0xC2, 0x17, 0x40, 0x17, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x77, 0xC0, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x27, 0x40, 0x9F, ++0x01, 0x7C, 0x86, 0xF0, 0x08, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x06, 0xF2, ++0x49, 0x41, 0x25, 0x20, 0x9F, 0x14, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, ++0x9B, 0x01, 0x7C, 0x02, 0xF0, 0x08, 0xC0, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, 0x00, 0xBF, 0x00, 0xCC, 0x02, 0xF0, ++0x0B, 0xC0, 0x2F, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0x30, 0x0A, 0xC0, 0x2B, 0x20, ++0xAF, 0x42, 0x8D, 0x02, 0x30, 0x0B, 0xC0, 0x28, 0x00, 0xB3, 0x02, 0xCC, 0x02, ++0xF0, 0x0A, 0xC0, 0x64, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x1C, 0x08, 0x07, 0x00, 0x1D, 0x15, 0x44, 0x54, 0xD0, 0x01, 0x48, 0x07, 0x00, ++0x1D, 0x00, 0x74, 0x14, 0x10, 0x51, 0x41, 0x07, 0x00, 0x1D, 0x81, 0x44, 0x00, ++0x50, 0x01, 0x48, 0x04, 0x10, 0x15, 0x01, 0x44, 0x00, 0xD0, 0x01, 0x40, 0x71, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, ++0x8D, 0x00, 0x04, 0x02, 0xD0, 0x08, 0x48, 0x23, 0x00, 0x8D, 0x00, 0x34, 0x42, ++0x10, 0x08, 0x40, 0x23, 0xA0, 0x8D, 0x00, 0x44, 0x03, 0x10, 0x08, 0x52, 0x20, ++0x00, 0xD1, 0x04, 0x04, 0x02, 0xD0, 0x09, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x25, 0x00, 0x9D, 0x00, 0x44, 0x02, ++0xD0, 0x09, 0x40, 0x27, 0x10, 0x9D, 0x00, 0x74, 0x02, 0x14, 0x09, 0x44, 0x27, ++0x00, 0x8D, 0x00, 0x44, 0x82, 0x50, 0x09, 0x46, 0x24, 0x00, 0x95, 0x00, 0x44, ++0x02, 0xD0, 0x09, 0x40, 0x61, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x05, 0x28, 0x25, 0x00, 0xBF, 0x00, 0xCD, 0x82, 0xF0, 0x09, 0xC0, 0x27, ++0x00, 0x9F, 0x00, 0xFC, 0x02, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x4C, ++0x02, 0x30, 0x09, 0xC0, 0x20, 0x08, 0xA3, 0x00, 0x4D, 0x02, 0xF0, 0x09, 0xC0, ++0x14, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x25, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC2, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x82, 0xF0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x53, 0x00, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x02, 0x1F, 0x00, 0x4C, ++0x00, 0xF0, 0x01, 0xC0, 0x07, 0x02, 0x1F, 0x00, 0x7C, 0x00, 0x70, 0x01, 0xD0, ++0x04, 0x40, 0x13, 0x00, 0x4C, 0x10, 0x30, 0x01, 0xC0, 0x07, 0x40, 0x13, 0x00, ++0x7C, 0x04, 0x30, 0x01, 0xC1, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x20, 0x14, 0x00, 0x5D, 0x20, 0x44, 0x01, 0xD1, 0x05, 0x40, ++0x17, 0x10, 0x5D, 0x01, 0x70, 0x01, 0xD0, 0x07, 0x40, 0xDC, 0x00, 0x71, 0x81, ++0x94, 0x01, 0x50, 0x16, 0x41, 0x1F, 0x00, 0x51, 0x00, 0xF4, 0x05, 0x11, 0x26, ++0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, ++0x62, 0x00, 0xDD, 0x08, 0x04, 0x07, 0xD0, 0x88, 0x48, 0x33, 0x00, 0x8D, 0x80, ++0x74, 0x03, 0x50, 0x04, 0x40, 0xA0, 0x06, 0xC9, 0x11, 0x06, 0x01, 0x10, 0x4C, ++0x48, 0x33, 0x0C, 0xC1, 0x80, 0x34, 0x05, 0x90, 0x18, 0x44, 0x50, 0x00, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x38, 0x00, 0xED, 0x08, ++0x84, 0x53, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xED, 0x10, 0xB4, 0x43, 0xD0, 0x1F, ++0x40, 0x5C, 0x20, 0xF9, 0x50, 0xD4, 0x80, 0x50, 0x0A, 0x40, 0x1F, 0x20, 0xE1, ++0x08, 0xF4, 0x47, 0x91, 0x2B, 0x40, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x10, 0x78, 0x00, 0xFF, 0x05, 0x8C, 0x07, 0xF0, 0x1E, ++0xC0, 0x7B, 0x00, 0xEF, 0x01, 0xBC, 0x87, 0x70, 0x1E, 0xC0, 0x48, 0x00, 0xEB, ++0x01, 0x8C, 0x07, 0x30, 0x12, 0xC0, 0x7B, 0x00, 0xA3, 0x81, 0xBC, 0x07, 0xB4, ++0x1A, 0xC0, 0x50, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0xB8, 0x35, 0x10, 0xDF, 0x00, 0x7C, 0x23, 0xF1, 0x0D, 0xC0, 0x37, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x0F, 0xC0, 0x06, 0x00, 0xD7, 0x00, 0x78, 0x02, 0xF0, ++0x01, 0xC0, 0x37, 0x00, 0x9D, 0x00, 0x3C, 0x03, 0x70, 0x09, 0xC0, 0x43, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x7F, 0x00, 0xBF, ++0x00, 0xFC, 0x06, 0x30, 0x9F, 0xC0, 0x7F, 0x00, 0xE3, 0x01, 0x8C, 0x47, 0x30, ++0x17, 0xC0, 0x4F, 0x00, 0x3F, 0x01, 0x9C, 0x04, 0x70, 0x16, 0xC4, 0x5C, 0x00, ++0xEF, 0x01, 0xCC, 0x07, 0xF0, 0x1B, 0xC2, 0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x15, 0x98, 0x39, 0x04, 0xAD, 0x0C, 0xB4, 0x02, 0x11, ++0x8E, 0x40, 0x3B, 0x10, 0xE1, 0x00, 0x84, 0x23, 0x10, 0x0E, 0x40, 0x0B, 0x10, ++0x6D, 0x0A, 0x85, 0x60, 0x55, 0x86, 0xC0, 0x9A, 0x10, 0xED, 0x00, 0x84, 0x03, ++0xD0, 0x0A, 0x44, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x39, 0x00, 0xAD, 0x08, 0xF4, 0x02, 0x10, 0x8E, 0x40, 0x3F, 0x04, ++0xE1, 0x10, 0xE4, 0x03, 0x10, 0x0E, 0x41, 0x0B, 0x00, 0x2D, 0x10, 0x94, 0x00, ++0xD0, 0x07, 0x41, 0x3A, 0x00, 0xBD, 0x0A, 0xA4, 0x03, 0xD0, 0x0A, 0x41, 0x23, ++0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x33, 0x00, ++0x8D, 0x03, 0x74, 0x0A, 0x10, 0x5C, 0x40, 0xE3, 0x00, 0xC1, 0x41, 0x24, 0x0E, ++0x10, 0x1D, 0x40, 0x83, 0x02, 0x5D, 0x03, 0x04, 0x04, 0xD0, 0x14, 0x40, 0x72, ++0x10, 0x9D, 0x01, 0x24, 0x0B, 0xD1, 0x18, 0x40, 0x1B, 0x20, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x00, 0xDF, 0x89, 0x7C, 0x03, ++0x30, 0x2D, 0xC0, 0x77, 0x40, 0xD3, 0x01, 0x6C, 0x46, 0x34, 0x19, 0xC0, 0x83, ++0x00, 0x5F, 0x41, 0x1C, 0x08, 0xF0, 0xB1, 0xC0, 0x76, 0x04, 0xDF, 0x11, 0x2C, ++0x02, 0xF0, 0x1D, 0xC2, 0x77, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x00, 0x37, 0x00, 0xDF, 0x08, 0x78, 0x17, 0xF0, 0x8D, 0xC0, 0x37, ++0x00, 0xDF, 0x10, 0x5C, 0x02, 0xF0, 0x0D, 0xC1, 0x07, 0x04, 0xDF, 0x00, 0x7C, ++0x48, 0x60, 0x01, 0xC4, 0x37, 0x00, 0xDF, 0x00, 0x5C, 0x0F, 0xF0, 0x2D, 0xC1, ++0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, ++0x06, 0xF3, 0x04, 0xFC, 0x0B, 0x30, 0x9F, 0xC8, 0x3F, 0x04, 0xFF, 0x80, 0xCC, ++0x56, 0xF0, 0x0F, 0xD0, 0x0C, 0x00, 0x73, 0x10, 0xCC, 0x00, 0xB0, 0x03, 0xC0, ++0x2F, 0x04, 0xB2, 0x03, 0xC8, 0x43, 0x30, 0x0F, 0xC0, 0x07, 0x24, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x72, 0x40, 0x91, 0x01, 0x74, ++0x06, 0x10, 0x1D, 0x44, 0x37, 0x08, 0xCD, 0x40, 0x44, 0x06, 0xD0, 0x3D, 0x40, ++0x44, 0x30, 0xDF, 0xC0, 0x45, 0x04, 0x10, 0x71, 0x44, 0x63, 0x10, 0xD1, 0x01, ++0x44, 0x17, 0xB0, 0x0D, 0x40, 0x27, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x01, 0xA0, 0x36, 0x00, 0x91, 0x80, 0x74, 0x02, 0x10, 0x0D, 0x40, ++0x37, 0x00, 0xDD, 0x04, 0x44, 0x02, 0xD0, 0x19, 0x41, 0x46, 0x00, 0x11, 0x00, ++0x44, 0x0C, 0x9A, 0x15, 0x42, 0x77, 0x00, 0xD5, 0x00, 0x77, 0x07, 0x00, 0x49, ++0x41, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++0x34, 0x00, 0x81, 0x00, 0x34, 0x02, 0x14, 0x0C, 0x40, 0x33, 0x00, 0xDD, 0x00, ++0x06, 0x03, 0xD0, 0x0C, 0x40, 0x44, 0x28, 0x45, 0x00, 0x04, 0x00, 0x10, 0x04, ++0x40, 0x33, 0x60, 0x85, 0x00, 0x34, 0x03, 0x90, 0x04, 0x40, 0x43, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x36, 0x00, 0xD3, 0x00, ++0x7C, 0x03, 0x10, 0x0D, 0xC0, 0x37, 0x20, 0xDF, 0x00, 0x4D, 0x02, 0xF0, 0x0D, ++0xC0, 0x04, 0x00, 0x01, 0x80, 0x4C, 0x00, 0xB4, 0x05, 0xC0, 0x27, 0x00, 0x97, ++0x00, 0x7C, 0x03, 0x30, 0x09, 0xC0, 0x07, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, 0xBF, 0x00, 0xBC, 0x02, 0xF1, 0x0F, ++0xC0, 0x2B, 0x10, 0xFF, 0x00, 0xFC, 0x02, 0xF0, 0x0F, 0x80, 0x0F, 0x20, 0x7F, ++0x00, 0xFD, 0x00, 0xF0, 0x07, 0xC0, 0x2F, 0x00, 0xBB, 0x40, 0xCC, 0x83, 0xF0, ++0x07, 0xC4, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, ++0xA0, 0x7F, 0x00, 0xEF, 0x01, 0x8C, 0x07, 0x70, 0x1B, 0xD0, 0x28, 0x01, 0xA7, ++0x01, 0xFC, 0x32, 0x30, 0x1A, 0xC0, 0x3C, 0x00, 0xB3, 0x14, 0xEC, 0x12, 0x30, ++0x8B, 0xC0, 0x3D, 0x0C, 0xBF, 0x08, 0xCC, 0x02, 0xF1, 0x0F, 0xC0, 0x0F, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x77, 0x00, 0x9D, ++0x01, 0x44, 0x06, 0x10, 0x11, 0x42, 0x64, 0x00, 0x51, 0x01, 0x44, 0x0A, 0x10, ++0x19, 0x40, 0xFC, 0x12, 0x91, 0x02, 0x44, 0x3A, 0x10, 0x49, 0x40, 0xBC, 0x00, ++0x9D, 0x00, 0x44, 0x2A, 0xD0, 0x0D, 0x44, 0x0F, 0x60, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x31, 0x00, 0xDD, 0x00, 0x44, 0x85, 0x50, ++0x04, 0x48, 0x00, 0x82, 0xD5, 0x00, 0x14, 0x18, 0x50, 0x09, 0x40, 0x32, 0x00, ++0x85, 0x00, 0x34, 0x40, 0x50, 0x88, 0x42, 0x31, 0x24, 0x09, 0x06, 0x04, 0x00, ++0xD0, 0x0C, 0x40, 0x4F, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x03, 0xA0, 0x37, 0x00, 0xDD, 0x11, 0x45, 0x05, 0x10, 0x11, 0x44, 0x44, 0x00, ++0xD1, 0x03, 0x04, 0x8C, 0x11, 0x89, 0x40, 0x36, 0x80, 0x94, 0x41, 0x14, 0x04, ++0x50, 0x19, 0x40, 0x34, 0x00, 0x0D, 0x11, 0x44, 0x0C, 0xD0, 0x0D, 0x20, 0x0F, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x37, 0x00, ++0xCF, 0x01, 0x0C, 0x04, 0x70, 0x10, 0x40, 0x44, 0x20, 0xC7, 0x03, 0x5C, 0x0E, ++0x70, 0x40, 0xD0, 0x32, 0x08, 0x17, 0xA3, 0x7C, 0x96, 0x71, 0x11, 0xC0, 0x35, ++0x10, 0x1F, 0x03, 0x4E, 0x0E, 0xF8, 0x0D, 0xC0, 0x0B, 0x20, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x3D, 0x00, 0xFF, 0x80, 0xFC, 0x00, ++0xF0, 0x03, 0xC0, 0x2B, 0x00, 0x7F, 0x00, 0x7C, 0x02, 0xF2, 0x0B, 0xC0, 0x3D, ++0x60, 0x9B, 0x00, 0xEC, 0x02, 0xB0, 0x00, 0xC0, 0x3F, 0x00, 0xBF, 0xA0, 0xFF, ++0x02, 0xF0, 0x0D, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x2A, 0x08, 0x35, 0x00, 0xDF, 0x03, 0x4C, 0x01, 0x30, 0x05, 0xC0, 0x07, ++0x24, 0xD3, 0x04, 0x5C, 0x02, 0x30, 0x21, 0xC0, 0x36, 0x01, 0x17, 0x00, 0x5C, ++0x82, 0xF0, 0x29, 0xC0, 0x76, 0x04, 0x13, 0x02, 0x7C, 0x06, 0x30, 0x0D, 0xC2, ++0xA9, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, ++0x08, 0xDC, 0x01, 0x46, 0x05, 0x10, 0x41, 0x48, 0x27, 0x00, 0x51, 0x81, 0x44, ++0x02, 0x10, 0x19, 0xC4, 0xBE, 0x00, 0x9B, 0x00, 0x44, 0x02, 0xD1, 0x09, 0x48, ++0xBC, 0x00, 0x11, 0x80, 0x74, 0x22, 0x10, 0x0F, 0x40, 0x4C, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x32, 0x08, 0xCD, 0x00, 0x06, ++0x33, 0x10, 0x04, 0x40, 0x23, 0x02, 0x49, 0x02, 0x14, 0x00, 0x10, 0x2C, 0x51, ++0x33, 0x00, 0x14, 0x00, 0x10, 0x00, 0xD0, 0x00, 0x40, 0xB2, 0x00, 0x81, 0x80, ++0x34, 0x00, 0x11, 0x0C, 0x48, 0x0F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x0D, 0x08, 0x7A, 0x00, 0xFD, 0x01, 0x84, 0x07, 0x11, 0x12, 0x40, ++0x7B, 0x10, 0x79, 0x11, 0x94, 0x07, 0x10, 0x1F, 0x41, 0x7B, 0x00, 0x6C, 0x01, ++0x94, 0x07, 0xD8, 0x1E, 0x40, 0x70, 0x42, 0xE1, 0x01, 0xB4, 0x07, 0x5C, 0x1E, ++0x40, 0x37, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, ++0x32, 0x00, 0xCF, 0x00, 0x04, 0x21, 0x12, 0x84, 0xC0, 0x33, 0x01, 0xCB, 0x00, ++0x1C, 0x21, 0x30, 0x4C, 0xC0, 0x33, 0x00, 0xC7, 0xE8, 0x1C, 0x81, 0xF0, 0x24, ++0xC0, 0x32, 0x02, 0xC3, 0x00, 0x7C, 0x11, 0x30, 0x0C, 0xC0, 0x4B, 0x40, 0x08, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA8, 0x3D, 0x00, 0xFF, 0x00, ++0xFC, 0x81, 0xF0, 0x83, 0xC0, 0x3F, 0x00, 0xF7, 0x00, 0xEC, 0x03, 0xF0, 0x0F, ++0xCC, 0x3A, 0x00, 0xFB, 0x00, 0xEC, 0x03, 0xF0, 0x0F, 0xC0, 0xBF, 0x02, 0xFF, ++0x48, 0xFC, 0x01, 0xB0, 0x0F, 0xC0, 0x08, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0xA2, 0x37, 0x20, 0xDF, 0x00, 0x4C, 0x03, 0xF0, 0x05, ++0xC2, 0x13, 0x00, 0x57, 0x00, 0x7C, 0x01, 0xF0, 0x1D, 0xC0, 0x36, 0x00, 0x5F, ++0x40, 0x7C, 0x01, 0x70, 0x15, 0xC0, 0x34, 0x01, 0x53, 0x01, 0x4D, 0x01, 0x10, ++0x0D, 0xC4, 0x43, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, ++0x98, 0x39, 0x08, 0xED, 0x00, 0x84, 0x01, 0xD0, 0x02, 0x40, 0x3B, 0x00, 0x61, ++0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x3A, 0x04, 0xED, 0x00, 0xB4, 0x03, 0xD0, ++0x07, 0x50, 0xBC, 0x00, 0xF1, 0x00, 0xC4, 0x03, 0x10, 0x4E, 0x40, 0x4F, 0x60, ++0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x79, 0x00, 0xFD, ++0x11, 0xA6, 0x05, 0xD0, 0x16, 0x40, 0x5B, 0x04, 0x65, 0x01, 0xB4, 0x05, 0xD0, ++0x0A, 0x50, 0x7A, 0x93, 0x6D, 0x01, 0xB4, 0x05, 0x50, 0x1E, 0x40, 0x78, 0x41, ++0xE5, 0x03, 0x84, 0x07, 0x10, 0x9E, 0x40, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x16, 0x20, 0x33, 0x00, 0x4D, 0x12, 0x06, 0xBD, 0xD0, ++0x20, 0x40, 0x33, 0x00, 0x41, 0x01, 0x74, 0x47, 0xD0, 0xEC, 0x40, 0x32, 0x80, ++0xCD, 0x0A, 0x34, 0x2B, 0xD0, 0x0C, 0x40, 0x34, 0x00, 0xC5, 0x00, 0x04, 0x8B, ++0x10, 0x0C, 0x40, 0x5B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x17, 0xA8, 0x17, 0x00, 0x6F, 0x02, 0xEC, 0x09, 0xF2, 0x07, 0xC0, 0x1B, 0x0A, ++0x77, 0x07, 0xFC, 0x15, 0xF0, 0x06, 0xC0, 0x16, 0x00, 0x7F, 0x21, 0xF4, 0x2D, ++0x78, 0x87, 0xC1, 0x14, 0x00, 0x77, 0x00, 0xCC, 0x39, 0x30, 0x05, 0xC0, 0x5F, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x80, 0x05, 0x00, ++0x1F, 0x82, 0x7D, 0x00, 0xF3, 0x01, 0x01, 0x07, 0x00, 0x1F, 0x10, 0x7C, 0x00, ++0xC0, 0x21, 0xC0, 0x05, 0x20, 0x1F, 0x10, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, ++0x00, 0x19, 0x04, 0x7C, 0x08, 0xF4, 0x01, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x25, 0x00, 0x9F, 0x04, 0x5C, 0x0E, ++0xF0, 0x49, 0xC4, 0x24, 0x08, 0x9B, 0x00, 0x4D, 0x02, 0x30, 0x99, 0x02, 0x67, ++0x01, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x10, 0x97, 0x80, 0x3C, ++0x0E, 0x70, 0x49, 0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x00, 0x44, 0x1A, 0xD0, 0x78, 0x44, 0x24, ++0x10, 0x81, 0x00, 0x44, 0x02, 0x10, 0x29, 0x44, 0xA4, 0x08, 0x9D, 0x00, 0x74, ++0x82, 0xD1, 0x09, 0x40, 0x67, 0x00, 0x91, 0x80, 0x74, 0x06, 0x10, 0x09, 0x40, ++0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xA0, 0x24, ++0x00, 0x9D, 0x00, 0x54, 0x02, 0xD0, 0x0D, 0x44, 0x34, 0x20, 0x99, 0x08, 0x44, ++0x02, 0x10, 0x09, 0x60, 0x27, 0x04, 0xDD, 0x00, 0x74, 0x02, 0xD0, 0x09, 0x40, ++0x27, 0x01, 0x95, 0x00, 0x74, 0x42, 0x50, 0x09, 0x40, 0x73, 0x00, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x28, 0x20, 0x00, 0xCD, 0x00, 0x04, ++0x02, 0xD0, 0x09, 0x48, 0x20, 0x05, 0x81, 0x00, 0x04, 0x52, 0x10, 0x0C, 0x40, ++0x21, 0x15, 0x8D, 0x14, 0x34, 0x52, 0xD0, 0x48, 0x41, 0x33, 0x05, 0x81, 0x14, ++0x34, 0x52, 0x10, 0x48, 0x40, 0x53, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x00, 0x5C, 0x00, 0xF0, 0x01, 0xC0, ++0x04, 0x01, 0x1B, 0x00, 0x4C, 0x10, 0x34, 0x01, 0xC0, 0x07, 0x21, 0x1F, 0x06, ++0x7C, 0x10, 0xF0, 0x41, 0xC8, 0x07, 0x01, 0x17, 0x04, 0x7C, 0x10, 0x70, 0x01, ++0xC4, 0x77, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xA0, ++0x27, 0x00, 0xAF, 0x00, 0xFC, 0x02, 0xF2, 0x0B, 0xD0, 0x2F, 0x00, 0xBF, 0x00, ++0xFC, 0x52, 0xF0, 0x0A, 0xC0, 0x26, 0x00, 0xBF, 0x10, 0xFC, 0x52, 0xF0, 0x4B, ++0xC1, 0x27, 0x05, 0xBF, 0x14, 0xFC, 0x52, 0xF0, 0x69, 0xC3, 0x67, 0x20, 0x0E, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0x25, 0x00, 0xBF, 0x00, ++0xCC, 0x02, 0xF0, 0x0B, 0xC0, 0x6F, 0x60, 0xB3, 0x00, 0x7C, 0x26, 0xF0, 0x0A, ++0xC0, 0x2D, 0x00, 0x93, 0x02, 0x7C, 0x52, 0x30, 0x39, 0xC1, 0xAF, 0x00, 0x9F, ++0x09, 0xCC, 0x06, 0xF0, 0x5B, 0xE0, 0x63, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x1C, 0x18, 0x07, 0x00, 0x5D, 0x00, 0x44, 0x00, 0xD0, 0x01, ++0x40, 0x07, 0x00, 0x11, 0x00, 0x74, 0x2C, 0xD0, 0x01, 0x40, 0x04, 0x00, 0x11, ++0x01, 0x74, 0x18, 0x10, 0x21, 0x40, 0x47, 0x09, 0x1D, 0x0B, 0x44, 0x00, 0xD0, ++0x01, 0x40, 0x73, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x20, 0x21, 0x00, 0x8D, 0x00, 0x04, 0x02, 0xD0, 0x08, 0x40, 0xA3, 0x00, 0x85, ++0x01, 0x34, 0x12, 0xD0, 0x09, 0x40, 0xA3, 0x80, 0x81, 0x26, 0x34, 0x42, 0x14, ++0x08, 0x40, 0xA3, 0x00, 0x8D, 0x04, 0x04, 0x0A, 0xD0, 0x68, 0x41, 0x4B, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x25, 0x00, 0x9D, ++0x00, 0x46, 0x06, 0xD3, 0x19, 0x40, 0x27, 0x04, 0x95, 0x04, 0x76, 0x12, 0xD2, ++0x49, 0x40, 0x24, 0xC0, 0x91, 0x02, 0x74, 0x82, 0x00, 0x09, 0x41, 0x27, 0x00, ++0x9D, 0x02, 0x44, 0x02, 0xD2, 0x09, 0x48, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, 0x00, 0x8F, 0x02, 0x44, 0x16, 0xF2, ++0x39, 0xC1, 0xA7, 0x00, 0x97, 0x02, 0x7C, 0x16, 0xF2, 0x09, 0xC0, 0x25, 0x00, ++0x93, 0xC2, 0x7C, 0x12, 0x30, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x09, 0x4D, 0x6E, ++0xD8, 0x09, 0x48, 0x17, 0x28, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x80, 0x25, 0x00, 0x9F, 0x02, 0x7D, 0x02, 0xF0, 0x09, 0xC0, 0x63, 0x02, ++0x9B, 0xA0, 0x7C, 0x02, 0xF1, 0x19, 0xC0, 0x27, 0x20, 0x9F, 0x05, 0x7C, 0x16, ++0xF0, 0x59, 0xC0, 0x27, 0x00, 0x8F, 0x01, 0x7C, 0x46, 0xF0, 0x09, 0xC0, 0x4B, ++0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x05, 0x00, ++0x1F, 0x04, 0x6C, 0x08, 0xF0, 0x01, 0xC0, 0x87, 0x00, 0x1F, 0x00, 0x7C, 0x08, ++0xF0, 0x01, 0xD0, 0x00, 0x00, 0x17, 0x00, 0x7C, 0x08, 0xF0, 0x21, 0xC2, 0x04, ++0x04, 0x1F, 0x02, 0x4C, 0x08, 0x30, 0x01, 0xC0, 0x40, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x14, 0x00, 0x7D, 0x02, 0xC4, 0x45, ++0xC2, 0x07, 0x00, 0x1F, 0x20, 0x7D, 0x21, 0x7C, 0x01, 0xD0, 0x16, 0x58, 0x1C, ++0x00, 0x5D, 0x00, 0x74, 0x01, 0xD1, 0x05, 0xC0, 0x1E, 0x04, 0x5D, 0x00, 0xC4, ++0x89, 0x10, 0x05, 0x50, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0xA0, 0x32, 0x00, 0x8D, 0x8B, 0x24, 0x06, 0xC8, 0xCC, 0x00, 0x53, ++0x04, 0x0C, 0x05, 0x34, 0x03, 0xD1, 0xD4, 0x40, 0x40, 0x00, 0xC5, 0x00, 0x74, ++0x03, 0xD0, 0x0C, 0x60, 0x72, 0x00, 0xCD, 0x00, 0x04, 0x0B, 0x15, 0x8C, 0x40, ++0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x38, ++0x00, 0xAD, 0x00, 0x84, 0x02, 0xD0, 0x0A, 0x40, 0xBB, 0x80, 0x2D, 0x82, 0x94, ++0x03, 0xD0, 0x07, 0x40, 0x88, 0x00, 0xED, 0x24, 0xB4, 0x23, 0xD0, 0x1F, 0x40, ++0x3A, 0x00, 0xFD, 0x80, 0x04, 0x07, 0x12, 0x1E, 0x40, 0x04, 0x20, 0x02, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x79, 0x00, 0xAF, 0x01, 0xAC, ++0x06, 0xF0, 0x1A, 0xC8, 0x5B, 0x00, 0x2F, 0x01, 0xB0, 0x07, 0xF0, 0x12, 0xCA, ++0x78, 0x00, 0xE7, 0xA3, 0xBC, 0x87, 0xF0, 0x7F, 0xC4, 0x5A, 0x00, 0xFF, 0x0F, ++0x89, 0x07, 0x32, 0x1F, 0xC0, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0x8F, 0x00, 0x5C, 0x00, 0xF0, 0x09, 0xC0, ++0x37, 0x00, 0x1F, 0x80, 0x7C, 0x03, 0xF0, 0x05, 0xC0, 0x17, 0x10, 0xDF, 0x00, ++0x7C, 0x0B, 0xF0, 0x2D, 0xC4, 0x37, 0x00, 0xDF, 0xA4, 0x7C, 0x02, 0xF0, 0x0D, ++0xC0, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, ++0x7D, 0x00, 0xBF, 0x01, 0xCC, 0x26, 0xF0, 0x9B, 0xC0, 0x6F, 0x02, 0x33, 0x09, ++0xDC, 0xEF, 0x73, 0x17, 0xC8, 0x5C, 0x22, 0xFD, 0x09, 0xFC, 0x0F, 0xF1, 0x3F, ++0xC0, 0x7F, 0x02, 0xF7, 0x81, 0xDC, 0x05, 0x10, 0x9B, 0xC0, 0x00, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x18, 0x39, 0x00, 0xAD, 0x48, ++0x85, 0x22, 0xD0, 0x0A, 0x00, 0x3B, 0x00, 0x21, 0xC0, 0x84, 0xE3, 0x10, 0x86, ++0x41, 0x98, 0x00, 0xED, 0x18, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x00, 0xE1, ++0x00, 0xF4, 0x11, 0x12, 0xCB, 0x40, 0x55, 0x60, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x2D, 0x10, 0x84, 0x2A, 0xD8, 0x0A, ++0x61, 0x2B, 0x60, 0x31, 0x50, 0x94, 0x23, 0x51, 0x06, 0x50, 0x3A, 0x98, 0xED, ++0x08, 0xB4, 0x23, 0xD0, 0x0E, 0x41, 0x1B, 0x00, 0xE1, 0x00, 0x94, 0x43, 0x99, ++0x0F, 0x44, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, ++0x20, 0x31, 0x00, 0x0D, 0x47, 0x04, 0x00, 0xD8, 0x58, 0x40, 0xB3, 0x02, 0x01, ++0x53, 0x04, 0x07, 0x58, 0x34, 0x40, 0x12, 0x80, 0xCD, 0x41, 0x24, 0x33, 0xD0, ++0x3C, 0x40, 0x23, 0x50, 0xC1, 0x42, 0x34, 0x46, 0x98, 0x0C, 0x40, 0x11, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, 0x35, 0x10, 0x9D, ++0x00, 0x4C, 0x02, 0xD0, 0x19, 0xC0, 0x93, 0x40, 0x13, 0x01, 0xDC, 0x0B, 0x70, ++0x05, 0xC0, 0x06, 0x00, 0xFF, 0x03, 0xFC, 0x0B, 0xF8, 0x3F, 0xC4, 0x27, 0x00, ++0xF3, 0x0F, 0x5C, 0x02, 0xB4, 0x0D, 0x40, 0x55, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x36, 0x00, 0xDF, 0x00, 0x7C, 0x22, 0xF0, ++0x09, 0xC0, 0x37, 0x01, 0x9F, 0x00, 0x7C, 0x13, 0x90, 0x45, 0xC0, 0x05, 0x00, ++0xDF, 0x10, 0x74, 0x03, 0xF0, 0x4D, 0xC0, 0x87, 0x00, 0xDF, 0x00, 0x7C, 0x00, ++0x70, 0x0D, 0x88, 0x07, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x84, 0x08, 0x3E, 0x00, 0xBF, 0x00, 0xFC, 0x02, 0xC0, 0x03, 0xC8, 0x1F, 0x00, ++0x3B, 0x02, 0x7C, 0x03, 0xF0, 0x07, 0xC0, 0x18, 0x00, 0xFA, 0x00, 0xAC, 0x03, ++0xB0, 0x0F, 0xC8, 0x06, 0x10, 0xEF, 0x00, 0xDC, 0x02, 0xF0, 0x0F, 0x80, 0x13, ++0x22, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x20, 0x36, 0x00, ++0x9D, 0x01, 0x74, 0x05, 0xD0, 0x11, 0x40, 0x37, 0x00, 0xD1, 0x83, 0x74, 0x03, ++0xD0, 0x14, 0x40, 0x94, 0x00, 0xD1, 0x00, 0x74, 0x03, 0x10, 0x0D, 0x40, 0xC4, ++0x04, 0xDD, 0x00, 0x44, 0x1C, 0xD2, 0x0D, 0x42, 0x17, 0x00, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0x34, 0x00, 0x9D, 0x01, 0x74, 0x06, ++0xD0, 0x69, 0x40, 0x27, 0x00, 0x19, 0x10, 0x74, 0x03, 0xD0, 0x35, 0x60, 0x14, ++0x00, 0xD5, 0x00, 0x64, 0x03, 0xD0, 0x0C, 0x60, 0x65, 0x00, 0xDD, 0x20, 0x54, ++0x04, 0xD8, 0x09, 0x40, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x28, 0x30, 0x00, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x08, 0x40, 0x33, ++0x00, 0x00, 0x20, 0x34, 0x83, 0xD0, 0x05, 0x40, 0x10, 0x00, 0xC5, 0x00, 0x34, ++0x03, 0x10, 0x0C, 0x60, 0x20, 0x00, 0xCD, 0x00, 0x06, 0x00, 0xD8, 0x08, 0x40, ++0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x36, ++0x00, 0x1F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x27, 0x00, 0x1B, 0x20, 0xFC, ++0x03, 0xF2, 0x05, 0xD0, 0x14, 0x10, 0xD7, 0x00, 0xEC, 0x03, 0xB0, 0x0F, 0xC0, ++0x04, 0x10, 0xFF, 0x20, 0x5C, 0x02, 0xF0, 0x0D, 0xC8, 0x03, 0xC0, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0xA8, 0x3F, 0x00, 0x2F, 0x00, 0xFC, ++0x80, 0xF1, 0x0B, 0xC0, 0x3B, 0x00, 0x2F, 0x00, 0xFC, 0x03, 0xF0, 0x0E, 0xC0, ++0x1F, 0x20, 0xFB, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x2F, 0x20, 0xFF, 0x00, ++0xFC, 0x00, 0xF0, 0x0F, 0xE0, 0x17, 0x21, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x03, 0xA0, 0x5F, 0x40, 0xB3, 0x00, 0xFC, 0x12, 0xF0, 0x17, 0xC0, ++0x7F, 0x00, 0x73, 0x81, 0xFC, 0x10, 0xF1, 0xC3, 0xC0, 0x2C, 0x02, 0x33, 0x81, ++0xCC, 0x23, 0x30, 0x0F, 0xC0, 0x48, 0x10, 0xBF, 0x20, 0xFC, 0x05, 0x30, 0x1F, ++0xC0, 0x0C, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, ++0x77, 0x08, 0x91, 0x4B, 0x74, 0x2E, 0xD2, 0x19, 0x00, 0x7F, 0x00, 0x51, 0x01, ++0x74, 0x2C, 0xD0, 0xE1, 0x40, 0xA4, 0x01, 0x11, 0x01, 0xC4, 0x1B, 0x51, 0xBB, ++0x48, 0x64, 0x00, 0x8D, 0x4E, 0x74, 0x07, 0x10, 0x0F, 0x48, 0x04, 0x60, 0x0C, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x23, 0x00, 0x81, 0x40, ++0x34, 0x02, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x81, 0x00, 0x34, 0x00, 0xD0, 0x09, ++0x40, 0xA0, 0x80, 0x15, 0x00, 0x04, 0x1B, 0x10, 0x0C, 0x40, 0x00, 0x00, 0x8D, ++0x10, 0x34, 0x82, 0x10, 0x0C, 0x40, 0x44, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x03, 0xA8, 0x25, 0x20, 0xD1, 0x00, 0x74, 0x02, 0xD0, 0x0D, ++0x40, 0x37, 0x00, 0x91, 0x82, 0x74, 0x04, 0xD0, 0x09, 0x48, 0x25, 0x84, 0x11, ++0x01, 0x45, 0x07, 0x53, 0x89, 0x40, 0x64, 0x00, 0x9D, 0x40, 0x34, 0x43, 0x10, ++0x0D, 0x40, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x88, 0x23, 0x00, 0xD3, 0x08, 0x7C, 0x02, 0xF0, 0x0D, 0x44, 0x33, 0x40, 0xD3, ++0x00, 0x7C, 0x0C, 0xF0, 0x88, 0xC0, 0x64, 0x40, 0x13, 0x81, 0x4C, 0x05, 0x30, ++0x1D, 0x90, 0x44, 0x00, 0x9E, 0x40, 0x7C, 0x2D, 0x34, 0x0D, 0xC0, 0x00, 0x20, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0xAD, 0x00, 0xBF, ++0x81, 0xFC, 0x13, 0xD0, 0x4B, 0x48, 0x3F, 0x00, 0xFF, 0x09, 0x7C, 0x00, 0xF0, ++0x1B, 0xC0, 0x6E, 0x2A, 0x3E, 0x10, 0xBC, 0x83, 0xF0, 0x09, 0xC4, 0x2F, 0x28, ++0xBF, 0x00, 0xF4, 0x03, 0xF1, 0x0F, 0xC0, 0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x25, 0x02, 0xD3, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC0, 0x37, 0x02, 0x93, 0x02, 0x7C, 0x00, 0x34, 0x09, 0xE0, 0x24, 0x20, ++0x1B, 0x01, 0x7C, 0x03, 0x30, 0x0D, 0xC8, 0x04, 0x44, 0xD3, 0x00, 0x4C, 0x02, ++0xF0, 0x0D, 0xC5, 0x08, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x13, 0xA0, 0x24, 0x00, 0xD1, 0x00, 0x74, 0x03, 0xD0, 0x0D, 0xC0, 0x35, 0x02, ++0x95, 0x00, 0x74, 0x04, 0x10, 0x0B, 0x42, 0x64, 0x04, 0x01, 0x03, 0x5C, 0xAF, ++0x51, 0x18, 0xC0, 0xE6, 0x18, 0xD1, 0x01, 0x6C, 0x03, 0xD0, 0x6D, 0x40, 0x4C, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x12, 0x04, ++0x81, 0x00, 0x34, 0x03, 0xD0, 0x00, 0x40, 0x33, 0x00, 0x81, 0x00, 0x34, 0x10, ++0x12, 0x00, 0x01, 0x64, 0x88, 0x09, 0x00, 0x34, 0x0F, 0x51, 0xBC, 0x41, 0x81, ++0x10, 0x85, 0x11, 0x04, 0x82, 0xD2, 0x2D, 0x42, 0x1C, 0x00, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x78, 0x82, 0xA1, 0x21, 0xB4, 0x16, ++0xD0, 0x1A, 0x40, 0x73, 0x08, 0xA5, 0x01, 0xB4, 0x04, 0x18, 0x92, 0x40, 0x68, ++0x08, 0x29, 0x01, 0x14, 0x27, 0x52, 0x1E, 0x64, 0x6F, 0x00, 0xA5, 0x29, 0xA4, ++0x06, 0xD0, 0x1E, 0x40, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x10, 0x20, 0x00, 0xC3, 0x08, 0x3C, 0x02, 0xF0, 0x08, 0x42, 0x33, ++0x02, 0x83, 0x00, 0x34, 0x48, 0x30, 0x08, 0x40, 0x20, 0x01, 0x0B, 0x00, 0x3C, ++0x43, 0x70, 0x0C, 0xC0, 0x01, 0x04, 0x87, 0x50, 0x0A, 0x02, 0xF0, 0x0D, 0xC0, ++0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xB8, 0x29, ++0x40, 0xFF, 0x08, 0xFC, 0x12, 0xF0, 0x0B, 0xC0, 0x7D, 0x08, 0xBF, 0x00, 0xFC, ++0x00, 0xD0, 0x0E, 0x52, 0x2B, 0x00, 0x37, 0x00, 0xFC, 0x0B, 0xF0, 0x0F, 0xE0, ++0x3E, 0x10, 0x9B, 0x00, 0xFC, 0x22, 0xF0, 0x1F, 0xC0, 0x0B, 0x60, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x77, 0x00, 0x93, 0x00, 0x7C, ++0x23, 0x30, 0x09, 0xC0, 0x37, 0x00, 0xDF, 0x80, 0xFC, 0x00, 0xF0, 0x09, 0xC0, ++0x06, 0x10, 0x93, 0x80, 0x3C, 0x08, 0x34, 0x4D, 0xE1, 0x07, 0x08, 0x9F, 0x01, ++0x4C, 0x02, 0xF0, 0x0D, 0xD0, 0x54, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x88, 0x39, 0x00, 0xA1, 0x04, 0xB4, 0x13, 0x10, 0x0A, 0x40, ++0xBB, 0x28, 0xEC, 0x20, 0xB4, 0x82, 0xD0, 0x6E, 0x48, 0x08, 0x00, 0xA1, 0x00, ++0xB4, 0x02, 0x50, 0x0E, 0x4A, 0x3B, 0x00, 0xBD, 0x40, 0xBC, 0x02, 0xD0, 0x4E, ++0x40, 0x48, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, ++0xED, 0x00, 0xE9, 0x09, 0x34, 0x0F, 0x10, 0x1A, 0x40, 0x7B, 0x01, 0xAD, 0x01, ++0xB4, 0x04, 0xD0, 0x18, 0x40, 0x48, 0x00, 0xA1, 0x01, 0xB4, 0x07, 0x90, 0x1E, ++0x40, 0x6B, 0x10, 0xED, 0x01, 0xA4, 0x06, 0xD0, 0x9E, 0x50, 0x0C, 0x00, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0xE3, 0x00, 0xC9, 0x88, ++0x34, 0x07, 0x10, 0x28, 0x41, 0x33, 0x00, 0x8D, 0x23, 0x34, 0x07, 0xD0, 0x0D, ++0x40, 0x14, 0x02, 0xC1, 0x01, 0x34, 0xCB, 0xD0, 0x0C, 0x40, 0x73, 0x04, 0xCD, ++0x00, 0x34, 0x02, 0xD0, 0x0D, 0x50, 0x48, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x17, 0xA8, 0xDD, 0x20, 0x5B, 0x21, 0x7C, 0x05, 0x34, 0x07, ++0xC0, 0x17, 0x00, 0x7F, 0x03, 0xFC, 0x01, 0xF1, 0x07, 0xC0, 0x5C, 0x40, 0x73, ++0x05, 0xBC, 0x1D, 0xB0, 0x05, 0xC4, 0xDF, 0x21, 0x5F, 0x00, 0xEC, 0x01, 0xF0, ++0x05, 0xC0, 0x5C, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, ++0x00, 0x87, 0x41, 0x17, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x1F, ++0x08, 0x6C, 0x30, 0xF0, 0x31, 0xD0, 0x45, 0x00, 0x1F, 0x01, 0x7C, 0x00, 0x70, ++0x21, 0xC0, 0x87, 0x10, 0x1F, 0x00, 0x7E, 0x00, 0xF0, 0x21, 0xC8, 0x4B, 0x00, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x27, 0x00, 0x8F, ++0x80, 0x4C, 0x02, 0x34, 0x09, 0xC0, 0x24, 0x00, 0x9F, 0x10, 0x4C, 0x02, 0xF0, ++0x09, 0xC0, 0x66, 0x01, 0x9B, 0x01, 0x4C, 0x02, 0xB0, 0x19, 0xC0, 0x27, 0x00, ++0x9F, 0x04, 0x7C, 0x82, 0x30, 0x09, 0xC0, 0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x26, 0x01, 0xBD, 0x00, 0x85, 0x02, 0x10, ++0x08, 0xC0, 0x2C, 0x00, 0x9D, 0x00, 0x54, 0x0A, 0xD2, 0x29, 0x40, 0xE4, 0x20, ++0x81, 0x4F, 0x54, 0x02, 0xB0, 0xD9, 0x46, 0xA7, 0x1E, 0x9D, 0x00, 0x34, 0x02, ++0x10, 0x6B, 0x40, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0xA0, 0x24, 0x80, 0x9D, 0x00, 0x44, 0x62, 0x10, 0x09, 0x40, 0x24, 0x00, ++0x8D, 0x00, 0x40, 0x2A, 0xD0, 0x19, 0x60, 0x26, 0x00, 0xD1, 0x20, 0x44, 0x2A, ++0x80, 0x09, 0x20, 0x37, 0x00, 0x9D, 0x00, 0x74, 0x02, 0x10, 0x09, 0x40, 0x60, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x20, 0x10, ++0x8D, 0x02, 0x04, 0x02, 0x10, 0x29, 0x40, 0x20, 0x00, 0x8D, 0x02, 0x14, 0x52, ++0xD0, 0x48, 0x41, 0x20, 0x0D, 0x91, 0x20, 0x54, 0x52, 0x98, 0x48, 0x49, 0x23, ++0x00, 0x8D, 0x95, 0x76, 0x0A, 0x10, 0x08, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, 0x06, 0x00, 0x1F, 0x01, 0x4C, 0x84, ++0x30, 0x01, 0xD0, 0x44, 0x00, 0x1D, 0x00, 0x4C, 0x10, 0xF0, 0x45, 0xD0, 0x12, ++0x01, 0x13, 0x00, 0x4C, 0x90, 0xB0, 0x41, 0xC0, 0x07, 0x00, 0x1F, 0x24, 0x7C, ++0x00, 0x34, 0x10, 0xD0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x19, 0xB8, 0x3B, 0x10, 0xBF, 0x03, 0xFC, 0x0A, 0xC0, 0x1F, 0xC0, 0xA5, ++0x00, 0xFF, 0x01, 0xFC, 0x02, 0xF0, 0x4B, 0xC3, 0x2F, 0x45, 0xBF, 0x00, 0xFC, ++0x52, 0x80, 0x0B, 0xC0, 0x2F, 0x00, 0xBF, 0x14, 0xFC, 0x06, 0xF0, 0x69, 0xC1, ++0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x2F, ++0x00, 0x9F, 0x07, 0xCC, 0x86, 0x34, 0x29, 0xC0, 0x6C, 0x04, 0x8F, 0x00, 0xFC, ++0x06, 0xF0, 0x5F, 0xC0, 0x6C, 0x05, 0xBB, 0x40, 0xCC, 0x06, 0x30, 0x1B, 0xC2, ++0x2C, 0x08, 0xF3, 0x05, 0x4C, 0x0A, 0xF0, 0x7B, 0xC0, 0x64, 0x00, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, 0x1D, 0x01, 0x44, ++0x80, 0x10, 0x11, 0x50, 0x84, 0x00, 0x1D, 0x21, 0x74, 0x20, 0xD0, 0x50, 0xC1, ++0x42, 0x01, 0x11, 0x00, 0x44, 0x6D, 0x50, 0x01, 0x50, 0x04, 0x00, 0x01, 0x55, ++0x44, 0x05, 0xD0, 0x61, 0x40, 0x70, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, 0x02, 0x05, 0x0A, 0x10, 0x08, 0x40, ++0x22, 0x00, 0x8D, 0x14, 0x34, 0x02, 0xD0, 0xC8, 0x40, 0x20, 0x05, 0x85, 0x00, ++0x05, 0x92, 0x58, 0x88, 0x40, 0x60, 0x40, 0x81, 0x08, 0x04, 0x82, 0xD0, 0x88, ++0x40, 0x42, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, ++0x25, 0x80, 0x8D, 0x01, 0x44, 0x12, 0x10, 0x08, 0x40, 0x26, 0x00, 0x9D, 0x80, ++0x74, 0x22, 0xD0, 0x09, 0x50, 0x26, 0x20, 0x95, 0x08, 0x04, 0x02, 0x58, 0x09, ++0x40, 0x34, 0x02, 0x91, 0x00, 0x45, 0x22, 0xD0, 0x09, 0x40, 0x62, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x67, 0x00, 0xBF, 0x80, ++0x4C, 0x06, 0x30, 0x1B, 0xC0, 0x26, 0x00, 0xBF, 0x00, 0x7C, 0x02, 0xF0, 0x49, ++0xC0, 0x64, 0x00, 0x97, 0x00, 0x4C, 0x86, 0x72, 0x09, 0xCA, 0x64, 0x20, 0x93, ++0x21, 0xCC, 0x0E, 0xF0, 0x09, 0xD0, 0x16, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x14, 0x80, 0x25, 0x02, 0x9F, 0x00, 0x7C, 0x42, 0xF0, 0x49, ++0xC0, 0x25, 0x04, 0x9F, 0x03, 0x7C, 0x06, 0xF0, 0x58, 0xD0, 0x27, 0x02, 0x93, ++0x20, 0x7C, 0x22, 0xF0, 0x08, 0xC0, 0x67, 0x00, 0x8F, 0x09, 0x7C, 0x02, 0xD0, ++0x09, 0xC0, 0x51, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, ++0x08, 0x05, 0x00, 0x13, 0x00, 0x7C, 0x00, 0xF0, 0x21, 0xC0, 0x07, 0x40, 0x13, ++0x02, 0x4D, 0x00, 0x32, 0x21, 0xF0, 0x00, 0x00, 0x13, 0x44, 0x4C, 0x20, 0x34, ++0x41, 0xC0, 0x04, 0x0A, 0x13, 0x00, 0x4C, 0x00, 0xF0, 0x81, 0xC6, 0x50, 0x20, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x5C, 0x00, 0x51, ++0x00, 0xB4, 0x01, 0xD0, 0x05, 0x40, 0x1F, 0x80, 0x51, 0x00, 0xC4, 0x09, 0x50, ++0x27, 0x50, 0x1D, 0x00, 0x61, 0xD2, 0xC4, 0x05, 0x20, 0x07, 0x40, 0x18, 0x00, ++0x75, 0x08, 0x6C, 0x01, 0xD0, 0x17, 0xD0, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x62, 0x00, 0xC9, 0x00, 0x34, 0x02, 0xD0, ++0x0C, 0x40, 0x23, 0x08, 0xC1, 0x00, 0x04, 0x4A, 0x10, 0x3C, 0x49, 0x30, 0x00, ++0xC0, 0x01, 0x05, 0x17, 0x19, 0x28, 0x40, 0x30, 0x84, 0xC1, 0x01, 0x04, 0x03, ++0xD0, 0x19, 0x40, 0x50, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0x80, 0xFC, 0x00, 0xE9, 0x04, 0xB4, 0x42, 0xD0, 0x4E, 0x40, 0xFB, 0x00, ++0xF5, 0x25, 0x84, 0x46, 0x50, 0x6E, 0x68, 0x69, 0x21, 0x21, 0x20, 0x84, 0x01, ++0x18, 0x06, 0x41, 0x38, 0x00, 0xE5, 0x10, 0xA6, 0x13, 0xD0, 0x0E, 0x40, 0x12, ++0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x68, 0x00, ++0xEB, 0x07, 0xBC, 0x06, 0xF0, 0x3E, 0xC0, 0x6B, 0x00, 0xE1, 0x03, 0x8C, 0x06, ++0x32, 0x72, 0x40, 0x28, 0x41, 0x23, 0x01, 0x84, 0x07, 0x32, 0x10, 0xC0, 0x78, ++0x00, 0xE3, 0x01, 0x8C, 0x0F, 0xF0, 0x10, 0xC0, 0x50, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x31, 0x40, 0xD7, 0x00, 0x7C, 0x02, ++0xF0, 0x0D, 0xC0, 0x33, 0x00, 0xDB, 0x00, 0x3C, 0x02, 0xF0, 0x01, 0xD8, 0x27, ++0x02, 0x0F, 0x20, 0x3C, 0x00, 0xF0, 0x01, 0xD2, 0x33, 0x10, 0x5F, 0x12, 0x7C, ++0x03, 0xF0, 0x0D, 0xC0, 0x43, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA2, 0x6F, 0x00, 0xFF, 0x01, 0xCC, 0x07, 0xF0, 0x1E, 0xC0, 0x6C, ++0x00, 0xEF, 0x01, 0xCC, 0x07, 0x32, 0x1F, 0xC0, 0x78, 0x10, 0x23, 0x01, 0x8C, ++0x05, 0x30, 0x13, 0xC0, 0x7F, 0x08, 0x7F, 0x01, 0xBC, 0x07, 0x30, 0x1F, 0xC0, ++0x0B, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x88, 0x29, ++0x00, 0xED, 0x00, 0x84, 0x03, 0xD2, 0x0E, 0x40, 0xA8, 0x00, 0xED, 0x08, 0x84, ++0x03, 0xB0, 0x2F, 0x40, 0x28, 0x01, 0x21, 0x80, 0x94, 0x00, 0x52, 0x02, 0x40, ++0x3B, 0x0A, 0x6D, 0x04, 0xB4, 0x03, 0x10, 0x0E, 0x40, 0x57, 0x20, 0x06, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0xED, 0x01, 0x84, ++0x03, 0xD0, 0x1F, 0x40, 0x28, 0x00, 0xFD, 0x01, 0x84, 0x22, 0x10, 0x8E, 0x40, ++0x2C, 0x10, 0x39, 0x08, 0x84, 0x03, 0x10, 0x02, 0x40, 0x3B, 0x00, 0x2D, 0x00, ++0xF4, 0x07, 0x10, 0x06, 0x40, 0x63, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x04, 0x28, 0x23, 0x01, 0xCD, 0x00, 0x04, 0x07, 0xD0, 0x0C, 0x41, ++0x20, 0x00, 0xCD, 0x00, 0x06, 0x45, 0x90, 0x1C, 0x40, 0x20, 0x00, 0x09, 0x01, ++0x16, 0x19, 0x50, 0x90, 0x40, 0xB3, 0x00, 0x5D, 0x00, 0x34, 0x6F, 0x10, 0x0C, ++0x40, 0x1B, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA8, ++0xA5, 0x00, 0xDF, 0x04, 0x4C, 0x12, 0xF0, 0x0D, 0xD0, 0x24, 0x00, 0xDF, 0x00, ++0x4D, 0x12, 0x30, 0x1B, 0xC0, 0x3C, 0x41, 0x1B, 0x05, 0x4C, 0x01, 0x34, 0x01, ++0xC0, 0x47, 0x12, 0x9F, 0x00, 0x7C, 0x0F, 0x36, 0x01, 0xC8, 0x57, 0x20, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xB7, 0x00, 0xDF, 0x40, ++0x7C, 0x02, 0xF0, 0x8D, 0xC0, 0x33, 0x10, 0xDF, 0x00, 0x7C, 0x02, 0xF0, 0x80, ++0xC0, 0xA7, 0x00, 0x17, 0x40, 0x7C, 0x08, 0xF1, 0x00, 0xC0, 0xD7, 0x00, 0x1F, ++0x40, 0x7C, 0x03, 0xF0, 0x0D, 0xCC, 0x27, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x08, 0x6F, 0x00, 0xEF, 0x00, 0x8C, 0x0E, 0x30, 0x0F, ++0xC0, 0x2C, 0x00, 0xF3, 0x00, 0xCC, 0x02, 0xF0, 0x33, 0xC4, 0x0C, 0x00, 0x33, ++0x00, 0xBC, 0x09, 0x30, 0x03, 0xC0, 0x1C, 0x00, 0xBF, 0x00, 0xCC, 0x03, 0x30, ++0x0B, 0xD0, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, ++0x20, 0xD6, 0x10, 0xDD, 0x40, 0x44, 0x4A, 0x10, 0x0D, 0x40, 0xF5, 0x50, 0xD1, ++0x00, 0x44, 0x02, 0xD0, 0x31, 0x42, 0x01, 0x08, 0x11, 0x23, 0x74, 0x0D, 0x10, ++0x51, 0xC0, 0xB6, 0x00, 0x1D, 0x61, 0x44, 0x03, 0x11, 0x2D, 0x40, 0x04, 0x02, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, 0xA4, 0x01, 0xDD, ++0x00, 0x44, 0x02, 0x10, 0x0C, 0x40, 0x24, 0x02, 0xC1, 0x20, 0x44, 0x03, 0xD0, ++0x0D, 0x40, 0xB4, 0x90, 0x19, 0x51, 0x74, 0x09, 0x10, 0x11, 0x00, 0x14, 0x02, ++0x1D, 0x03, 0x05, 0x83, 0x10, 0x24, 0x40, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x00, 0xCD, 0x00, 0x04, 0x02, 0x14, ++0x0C, 0x40, 0x11, 0x00, 0xC1, 0x00, 0x04, 0x03, 0xD0, 0x04, 0x40, 0x25, 0x00, ++0x01, 0x00, 0x34, 0x01, 0x14, 0x00, 0x60, 0x32, 0x00, 0x1D, 0x00, 0x04, 0x03, ++0x10, 0x0C, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xB0, 0x26, 0x00, 0xEF, 0x00, 0x4D, 0x01, 0x30, 0x0F, 0xC0, 0x24, 0x00, ++0xF3, 0x00, 0x45, 0x02, 0xF0, 0x0D, 0xC0, 0x04, 0x00, 0x13, 0x00, 0x7C, 0x01, ++0x30, 0x01, 0xC0, 0x14, 0x00, 0x3F, 0x00, 0xCC, 0x03, 0x34, 0x0D, 0xC8, 0x04, ++0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xB8, 0x1F, 0x00, ++0xFF, 0x00, 0xFC, 0x81, 0xF0, 0x0F, 0xC0, 0x1F, 0x00, 0xFF, 0x00, 0xBC, 0x01, ++0xE2, 0x07, 0x98, 0x0F, 0x40, 0x3F, 0x40, 0xFC, 0x01, 0xF0, 0x03, 0xC0, 0x3F, ++0x00, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0xFB, 0x10, 0x9C, 0x07, ++0xF0, 0x1F, 0xC0, 0x4F, 0x00, 0xBF, 0x01, 0xFC, 0x05, 0xF0, 0x17, 0xC8, 0x2E, ++0x10, 0xBF, 0x04, 0xFC, 0x03, 0x30, 0x1F, 0xC0, 0x7F, 0x08, 0xB6, 0x00, 0xFC, ++0x27, 0x70, 0x02, 0xC0, 0x0E, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0x08, 0x77, 0x00, 0xFD, 0x03, 0x44, 0x06, 0x10, 0x1D, 0x40, 0x47, ++0x00, 0xDD, 0x01, 0x74, 0x00, 0x10, 0x1D, 0x40, 0xE4, 0x02, 0x1D, 0x04, 0xF4, ++0x5B, 0x10, 0x01, 0x40, 0x47, 0x08, 0x9D, 0x01, 0x74, 0x03, 0xD0, 0x19, 0x40, ++0x0C, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0xA0, 0x33, ++0x00, 0xCD, 0x00, 0x14, 0x03, 0xD0, 0x0C, 0x40, 0x03, 0x00, 0x8D, 0x40, 0x74, ++0x51, 0x90, 0x05, 0x48, 0x02, 0x00, 0x0D, 0x12, 0x34, 0x1B, 0x10, 0x4C, 0x49, ++0x33, 0x00, 0x0D, 0x02, 0x34, 0x13, 0xD0, 0x00, 0x40, 0x4E, 0x80, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x00, 0xDD, 0x20, 0x40, ++0x07, 0x10, 0x0D, 0x40, 0x67, 0x00, 0xDD, 0x23, 0x74, 0x81, 0x14, 0x1D, 0x41, ++0x44, 0x00, 0x1D, 0x01, 0x74, 0x03, 0x14, 0x01, 0x40, 0x07, 0x08, 0x9D, 0x51, ++0x74, 0x03, 0xD0, 0x19, 0x41, 0x0C, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x88, 0x37, 0x00, 0xDF, 0x00, 0x54, 0x1F, 0xF0, 0x0D, 0xC0, ++0x47, 0x00, 0x9F, 0x01, 0x7C, 0x19, 0xF0, 0x14, 0xC0, 0xC6, 0x00, 0x9F, 0x07, ++0x74, 0x03, 0x30, 0x0D, 0xC0, 0x37, 0x00, 0x17, 0x01, 0x7C, 0x03, 0x79, 0x39, ++0xC0, 0x22, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, ++0x3C, 0x00, 0xEF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x0F, 0x00, 0xFF, 0x40, ++0xFC, 0x00, 0xF0, 0x0F, 0xC0, 0x27, 0x00, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x03, ++0xC4, 0x0F, 0x30, 0x1F, 0x20, 0xFE, 0xA7, 0xF0, 0x0B, 0x40, 0x1F, 0x00, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x35, 0x00, 0xDF, 0x00, ++0x7C, 0x03, 0x30, 0x0D, 0xC0, 0x07, 0x00, 0x1F, 0x02, 0x5C, 0x49, 0xB0, 0x25, ++0xC0, 0x06, 0x00, 0x9B, 0x00, 0x4E, 0x03, 0xF0, 0x0D, 0xC0, 0x34, 0x00, 0x17, ++0x02, 0x4C, 0x13, 0xF2, 0x29, 0xC5, 0x29, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x13, 0xA0, 0x34, 0x00, 0xFD, 0x00, 0x34, 0x07, 0x10, 0x0D, ++0xC0, 0x07, 0x00, 0xDD, 0x05, 0x04, 0x1D, 0x10, 0x0D, 0x40, 0x64, 0x00, 0x11, ++0x00, 0xEC, 0x63, 0xD0, 0x71, 0x40, 0x84, 0x0B, 0x11, 0x01, 0x44, 0x43, 0xD0, ++0x18, 0xC0, 0x4E, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, ++0xA0, 0x32, 0x00, 0xCD, 0x00, 0x34, 0x3B, 0x10, 0x0C, 0x40, 0x03, 0x00, 0xCD, ++0x00, 0x14, 0x0B, 0x94, 0x00, 0x42, 0x62, 0x00, 0x89, 0x80, 0x54, 0x07, 0xD0, ++0x4C, 0x40, 0xF1, 0x10, 0x85, 0x00, 0x04, 0x03, 0xD0, 0xB0, 0x40, 0x0D, 0x00, ++0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x78, 0x80, 0xED, ++0x41, 0xB4, 0x07, 0x10, 0x1E, 0x40, 0x49, 0x30, 0xED, 0xC9, 0x94, 0x06, 0x10, ++0x17, 0x00, 0x78, 0x00, 0xF0, 0x49, 0xB4, 0x07, 0xD0, 0x13, 0x40, 0x48, 0x00, ++0xE1, 0x11, 0x84, 0x07, 0xD0, 0x16, 0x40, 0x3E, 0x20, 0x08, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0xCF, 0x00, 0x3C, 0x01, 0x30, ++0x8C, 0x40, 0x03, 0x00, 0xCF, 0x00, 0x5C, 0x33, 0xB0, 0x00, 0xC0, 0x32, 0x04, ++0x5B, 0x80, 0x14, 0x03, 0xF2, 0x0C, 0xD0, 0x30, 0x03, 0x46, 0x08, 0x0D, 0x03, ++0xF0, 0x00, 0xC0, 0x49, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xB0, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x01, 0xF0, 0x0D, 0xC2, 0x37, 0x00, ++0xCF, 0x00, 0x6C, 0xA3, 0xF0, 0x0C, 0xC0, 0x37, 0x00, 0xDF, 0x20, 0x6C, 0x43, ++0xF0, 0x80, 0xC0, 0x03, 0x0A, 0xDF, 0x08, 0x7C, 0x23, 0xF0, 0x8D, 0xC0, 0x09, ++0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xA0, 0x37, 0x00, ++0xDF, 0x1E, 0x7C, 0x03, 0x30, 0x0D, 0xC4, 0x07, 0x00, 0xDF, 0x00, 0x5C, 0x01, ++0xF0, 0x15, 0xC0, 0x14, 0x00, 0xDF, 0x00, 0x4C, 0x4F, 0x71, 0x0D, 0xC8, 0x34, ++0x10, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x05, 0xC4, 0x40, 0x00, 0x0E, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x03, ++0x10, 0x0E, 0x48, 0x0B, 0x10, 0xED, 0x00, 0x84, 0x02, 0xD0, 0x0E, 0x40, 0x38, ++0x08, 0xFD, 0x80, 0x04, 0x03, 0x12, 0x02, 0x40, 0x08, 0x04, 0xED, 0x00, 0xB4, ++0x03, 0xD0, 0x06, 0x60, 0x4C, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x03, 0x00, 0x79, 0x00, 0xED, 0x01, 0xF4, 0x07, 0x14, 0x1E, 0x40, 0x4B, ++0x00, 0xED, 0x01, 0x94, 0x07, 0xD0, 0x17, 0x50, 0x58, 0x00, 0xED, 0x01, 0x85, ++0x07, 0x50, 0x1F, 0x40, 0x78, 0x00, 0xED, 0x01, 0xB4, 0x87, 0xD0, 0x1C, 0x40, ++0x10, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x33, ++0x00, 0xCD, 0x00, 0x34, 0x4F, 0x90, 0x0C, 0x48, 0xC3, 0x83, 0xCD, 0x12, 0x04, ++0x4B, 0xD0, 0x7C, 0x40, 0xB0, 0x0C, 0xCD, 0x02, 0x04, 0x03, 0x10, 0x01, 0x40, ++0x00, 0x00, 0xCD, 0x88, 0x30, 0x22, 0xD0, 0x1C, 0x40, 0x58, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x15, 0x00, 0x5F, 0x00, 0xBC, ++0x49, 0x30, 0x05, 0xC2, 0x9F, 0x00, 0x6F, 0x02, 0x9C, 0x09, 0xF0, 0x27, 0xC8, ++0x1C, 0x00, 0x7F, 0x00, 0x4C, 0x01, 0x70, 0x05, 0xD0, 0x14, 0x00, 0x7D, 0x21, ++0x7C, 0x05, 0xD0, 0x27, 0x40, 0x5C, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x12, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x70, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x00, 0x7C, 0x08, 0xF0, 0x81, 0xC0, 0x07, 0x00, 0x1F, 0x18, ++0x7C, 0x00, 0xF0, 0x23, 0xC0, 0x8F, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0xA1, ++0xD1, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, ++0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0x34, 0x09, 0xC0, 0x27, 0x00, 0x9F, 0x08, ++0x6C, 0x26, 0x71, 0x09, 0xC0, 0x27, 0x00, 0x9E, 0x00, 0x4C, 0x16, 0xF0, 0x09, ++0xC0, 0x25, 0x20, 0x93, 0x38, 0x78, 0x0E, 0xF2, 0x18, 0xC0, 0x40, 0x20, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, 0x00, 0x9D, 0x00, ++0x74, 0x02, 0x11, 0x09, 0x40, 0x27, 0x00, 0x9D, 0x40, 0x44, 0x06, 0x11, 0x09, ++0x44, 0x27, 0x00, 0x9D, 0x80, 0x44, 0x8E, 0xD1, 0x29, 0x40, 0x20, 0x04, 0x91, ++0x01, 0x74, 0x06, 0xD0, 0x89, 0x41, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x00, 0x74, 0x12, 0x1C, 0x09, ++0x40, 0x27, 0x00, 0x9D, 0x00, 0x64, 0x42, 0x40, 0x09, 0x42, 0x37, 0x80, 0x8D, ++0x00, 0x44, 0x02, 0xD0, 0x19, 0x41, 0x2D, 0x40, 0x91, 0x00, 0x74, 0x42, 0xD0, ++0x09, 0x40, 0x70, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0x20, 0x00, 0x8D, 0x14, 0x74, 0x02, 0x10, 0x08, 0x40, 0x23, 0x00, 0x8D, ++0x00, 0x44, 0x02, 0x10, 0x08, 0x40, 0x23, 0x05, 0x8D, 0x34, 0x04, 0x52, 0xD0, ++0x0A, 0x40, 0x2C, 0x20, 0x81, 0x14, 0x34, 0x02, 0xD0, 0x48, 0x51, 0x50, 0xA0, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x30, 0x06, 0x00, 0x1F, ++0x04, 0x7C, 0x00, 0x30, 0x01, 0xC8, 0x07, 0x00, 0x1F, 0x00, 0x6C, 0x00, 0x70, ++0x01, 0xC0, 0x07, 0x21, 0x1F, 0x04, 0x4C, 0x11, 0xF0, 0x01, 0xC0, 0x0D, 0x00, ++0x13, 0xC4, 0x7C, 0x00, 0xF0, 0x41, 0xC0, 0x74, 0xC0, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x19, 0xB0, 0x27, 0x00, 0x9F, 0x00, 0xBC, 0x03, 0xF0, ++0x09, 0xC0, 0x2F, 0x00, 0xEF, 0x80, 0xFC, 0x52, 0xF0, 0x0A, 0xC0, 0x2F, 0x00, ++0xBF, 0x14, 0x7D, 0x52, 0xF0, 0x48, 0xC5, 0x27, 0x00, 0xBF, 0x40, 0xFC, 0x52, ++0xF0, 0x0B, 0xC0, 0x67, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x18, 0xA0, 0x27, 0x00, 0x9F, 0x01, 0xFC, 0x02, 0xB0, 0x09, 0xC0, 0x27, 0x60, ++0xB3, 0x00, 0x9C, 0x0A, 0x70, 0x09, 0xC0, 0x3D, 0x00, 0x93, 0x02, 0xCC, 0xC6, ++0xF0, 0x2B, 0xC2, 0x2F, 0x00, 0xBF, 0x80, 0xCC, 0x0A, 0xD0, 0x0B, 0xC0, 0x67, ++0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x08, 0x07, 0x00, ++0x1D, 0x0A, 0x74, 0x00, 0x10, 0x01, 0x40, 0x07, 0x00, 0x11, 0x00, 0x44, 0x04, ++0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x10, 0xD0, 0x01, 0x40, 0x07, ++0x00, 0x1D, 0x00, 0x44, 0x00, 0xD0, 0x01, 0x40, 0x73, 0x60, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x8D, 0x00, 0x74, 0x02, ++0x90, 0x08, 0x40, 0x27, 0x00, 0x81, 0x00, 0x54, 0x02, 0x52, 0x09, 0x40, 0xA1, ++0x00, 0x81, 0x22, 0x04, 0x42, 0xD2, 0x08, 0x40, 0x23, 0x00, 0x8D, 0x02, 0x04, ++0x02, 0xD0, 0x08, 0x40, 0x4B, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x18, 0xA8, 0x25, 0x00, 0x9D, 0x00, 0x74, 0x06, 0x10, 0x09, 0x40, 0x27, ++0x00, 0x91, 0x00, 0x44, 0x1A, 0x12, 0x29, 0x42, 0x24, 0x40, 0x91, 0x80, 0x45, ++0x82, 0xD0, 0x09, 0x40, 0x27, 0x08, 0x9D, 0x00, 0x44, 0x03, 0xD0, 0x29, 0x40, ++0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xA8, 0x27, ++0x00, 0x9F, 0x00, 0x7C, 0x02, 0xB0, 0x09, 0xC4, 0xE3, 0x04, 0x93, 0x02, 0x5C, ++0x0E, 0x70, 0x08, 0xC0, 0xE5, 0x04, 0x92, 0x1B, 0x48, 0x02, 0xE0, 0x09, 0xC0, ++0x27, 0x00, 0x9F, 0x19, 0x4D, 0x06, 0xF0, 0x09, 0xC0, 0x17, 0x28, 0x0E, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x25, 0x00, 0x9F, 0x00, 0x7C, ++0x02, 0xF0, 0x09, 0xC4, 0x67, 0x02, 0x9F, 0x00, 0x7C, 0x06, 0xF0, 0x09, 0xC0, ++0x27, 0x01, 0x8F, 0x21, 0x7C, 0x82, 0xF0, 0x09, 0xC0, 0x27, 0x10, 0x8F, 0x01, ++0x7C, 0x12, 0xF0, 0x09, 0xC0, 0x4B, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x1F, 0x00, 0x6C, 0x08, 0xF0, 0x01, 0xC0, ++0x07, 0x00, 0x1F, 0x00, 0x7C, 0x40, 0x31, 0x21, 0xC8, 0x87, 0x00, 0x1E, 0x02, ++0x7C, 0x00, 0x32, 0x81, 0x81, 0x04, 0x04, 0x1F, 0x80, 0x4C, 0x00, 0x34, 0x01, ++0xC0, 0x43, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, ++0x14, 0x00, 0x5D, 0x00, 0x84, 0x01, 0xD0, 0x05, 0x40, 0x17, 0x10, 0x6D, 0x80, ++0xB4, 0x05, 0x10, 0x05, 0x40, 0x13, 0x00, 0x5D, 0x00, 0xF4, 0x01, 0x10, 0x27, ++0x40, 0xDC, 0x00, 0x5D, 0x05, 0xC4, 0x61, 0x12, 0x07, 0x40, 0x53, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, 0x00, 0xCD, 0x00, ++0x24, 0x05, 0xD0, 0x0C, 0x40, 0x33, 0x00, 0x8D, 0x0C, 0x34, 0x0F, 0x14, 0x0C, ++0x40, 0x33, 0x02, 0xCD, 0x00, 0x34, 0x1F, 0x50, 0x2C, 0x44, 0xD0, 0x20, 0x8D, ++0x00, 0x04, 0x0F, 0x10, 0x2C, 0x41, 0x53, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x05, 0x80, 0x38, 0x00, 0xED, 0x01, 0x84, 0x0B, 0xD0, 0x0E, ++0x40, 0x3B, 0x80, 0xAD, 0x00, 0xF4, 0x43, 0x10, 0x0E, 0x40, 0x2B, 0x00, 0xED, ++0x48, 0xB4, 0x47, 0x50, 0x1E, 0x50, 0x38, 0x04, 0xED, 0x00, 0x84, 0x05, 0x10, ++0x2E, 0x40, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0x10, 0x78, 0x00, 0xCF, 0x01, 0xAC, 0x05, 0xF0, 0x1E, 0xC4, 0x7B, 0x10, 0xAF, ++0x01, 0xBC, 0x07, 0x30, 0x1E, 0xC0, 0x7B, 0x00, 0xEF, 0x8D, 0xFC, 0x07, 0x70, ++0x17, 0xC0, 0x78, 0x08, 0xEE, 0x01, 0xCD, 0x07, 0x30, 0x1E, 0xC0, 0x47, 0x40, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, 0x35, 0x00, 0xDF, ++0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC4, 0x37, 0x00, 0x9F, 0x00, 0x7C, 0x03, 0xF0, ++0x0D, 0xC0, 0x27, 0x00, 0xDF, 0x42, 0x7C, 0x03, 0xB4, 0x0D, 0xC0, 0x37, 0x00, ++0xCF, 0x00, 0x7C, 0x01, 0xF0, 0x05, 0xC8, 0x43, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x7F, 0x00, 0xFF, 0x01, 0xFC, 0x85, 0xF0, ++0x1F, 0xC0, 0x7F, 0x02, 0x2F, 0x09, 0x8C, 0x05, 0xF0, 0x9F, 0xC2, 0x6D, 0x02, ++0xFB, 0x09, 0xFC, 0x07, 0x30, 0x1F, 0xC0, 0x7F, 0x20, 0xFF, 0x01, 0xFC, 0x07, ++0x30, 0x1F, 0xC0, 0x0A, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x15, 0x88, 0x39, 0x00, 0xED, 0x00, 0xB4, 0x03, 0xD0, 0x0E, 0x40, 0x3B, 0x00, ++0x2D, 0x10, 0x84, 0x01, 0x12, 0x0E, 0x40, 0x38, 0x04, 0xE9, 0x00, 0x84, 0x11, ++0x10, 0x06, 0x40, 0x3B, 0x00, 0xED, 0x00, 0xA4, 0x11, 0x18, 0x0A, 0x40, 0x54, ++0x60, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, ++0xED, 0x00, 0xB4, 0x01, 0xD0, 0x0E, 0x40, 0x39, 0x20, 0x3D, 0x00, 0xC5, 0x01, ++0xD0, 0x0F, 0x09, 0x29, 0x00, 0xED, 0x40, 0x96, 0x83, 0x14, 0x06, 0x40, 0x3B, ++0x02, 0xED, 0x00, 0xF4, 0x83, 0x10, 0x0E, 0x41, 0x22, 0x00, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x28, 0x33, 0x00, 0xCD, 0x40, 0x34, 0x03, ++0xD0, 0x0C, 0x64, 0xB3, 0x04, 0x0D, 0x07, 0x04, 0x0C, 0x90, 0x3C, 0x40, 0x70, ++0x00, 0xCD, 0x03, 0x04, 0x02, 0x10, 0xA1, 0x44, 0x73, 0x00, 0xCD, 0x02, 0x64, ++0x24, 0x10, 0x10, 0x40, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x15, 0xA8, 0x35, 0x00, 0xDF, 0x00, 0x7C, 0x07, 0xF0, 0x0D, 0xC0, 0x77, ++0x14, 0x9F, 0x03, 0x0C, 0x4E, 0xF0, 0x9D, 0xC0, 0xF5, 0x00, 0xFF, 0x12, 0x78, ++0x00, 0x30, 0x39, 0x40, 0x73, 0x01, 0xDD, 0x10, 0x7C, 0x02, 0x14, 0x1D, 0xC0, ++0x56, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x37, ++0x00, 0xDF, 0x00, 0x7C, 0x22, 0xF0, 0x0D, 0xC0, 0x37, 0x08, 0x9F, 0x02, 0x7C, ++0x08, 0x70, 0x0D, 0xC0, 0x27, 0x00, 0xDB, 0x04, 0x7C, 0x0A, 0xF0, 0x09, 0xC4, ++0x37, 0x00, 0xDF, 0x30, 0x6C, 0x82, 0xF0, 0x6D, 0xC0, 0xA7, 0x00, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x08, 0x3F, 0x00, 0xFF, 0x80, 0xFC, ++0x83, 0xF0, 0x0F, 0xC0, 0x3F, 0x08, 0xBF, 0x00, 0xDC, 0x42, 0x70, 0x0F, 0xC0, ++0x3D, 0x04, 0xDF, 0x40, 0x78, 0x00, 0xE0, 0x03, 0x01, 0x3C, 0x24, 0xF2, 0x80, ++0xFC, 0x00, 0x30, 0x09, 0xE0, 0x17, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x81, 0x00, 0x36, 0x00, 0xDD, 0x00, 0x74, 0x1F, 0xD0, 0x0D, 0xC0, ++0x35, 0x00, 0x8D, 0x41, 0x46, 0x16, 0x10, 0x0C, 0x46, 0x24, 0x20, 0xDD, 0x00, ++0x74, 0x0E, 0xD0, 0x19, 0xC1, 0xF6, 0x01, 0xD1, 0x00, 0x74, 0x04, 0x30, 0x41, ++0x40, 0x17, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xA0, ++0x34, 0x80, 0xDD, 0x00, 0x74, 0x07, 0xD0, 0x0D, 0x48, 0x35, 0x10, 0x9D, 0x03, ++0x54, 0x06, 0x50, 0x0D, 0x40, 0x25, 0x00, 0xDD, 0x00, 0x54, 0x0C, 0xD0, 0x19, ++0x60, 0x75, 0x10, 0xD5, 0x04, 0x74, 0x06, 0x10, 0x85, 0x40, 0x05, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, 0x80, 0xCD, 0x00, ++0x34, 0x03, 0xD0, 0x0C, 0x42, 0x31, 0x00, 0xDD, 0x20, 0x44, 0x00, 0x18, 0x0D, ++0x40, 0x30, 0x00, 0xCD, 0x00, 0x34, 0x00, 0xD0, 0x09, 0x48, 0x27, 0x80, 0xC5, ++0x00, 0x34, 0x02, 0x93, 0x00, 0x40, 0x43, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xB0, 0x36, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, ++0xC0, 0x35, 0x00, 0x9F, 0x00, 0x54, 0x02, 0x70, 0x0D, 0xC0, 0x25, 0x20, 0xFD, ++0x00, 0x5C, 0x00, 0xF0, 0x01, 0xC0, 0x35, 0x80, 0xD7, 0x80, 0x7C, 0x02, 0x24, ++0x01, 0xC0, 0x07, 0xC4, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, ++0xB8, 0x3F, 0x10, 0xFF, 0x20, 0xFC, 0x03, 0xF0, 0x0F, 0xC4, 0x3D, 0x00, 0xBF, ++0x80, 0xF4, 0x02, 0xF2, 0x0E, 0xC0, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x02, 0xF0, ++0x0B, 0xC0, 0x2E, 0x40, 0xFB, 0x00, 0xBC, 0x02, 0x70, 0x03, 0xC8, 0x17, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA0, 0x5F, 0x00, 0x7F, ++0x41, 0xFC, 0x85, 0xF0, 0x1B, 0xC0, 0x5C, 0x02, 0xAF, 0x14, 0xCC, 0x04, 0xF0, ++0xC3, 0xC0, 0x0C, 0x04, 0xB3, 0x10, 0xCC, 0x0C, 0x30, 0x8B, 0xC0, 0x3F, 0x00, ++0xB3, 0x14, 0xCC, 0x53, 0x30, 0x0B, 0xC0, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x57, 0x00, 0x9D, 0x01, 0x74, 0x05, 0xD1, ++0x15, 0x44, 0x14, 0x21, 0xFD, 0x03, 0x44, 0x10, 0xD0, 0xE1, 0x00, 0x84, 0x01, ++0xAB, 0x06, 0x44, 0x00, 0x10, 0xE9, 0x40, 0x77, 0x00, 0xB5, 0x06, 0xD4, 0x0F, ++0x10, 0x09, 0x40, 0x04, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x11, 0xA0, 0x33, 0x00, 0x8D, 0x00, 0x34, 0x02, 0xD0, 0x09, 0x40, 0x20, 0x20, ++0xCD, 0x00, 0x16, 0x40, 0xD2, 0x01, 0x50, 0x04, 0x44, 0x81, 0x10, 0x05, 0x10, ++0x10, 0x00, 0x40, 0x33, 0x00, 0xC1, 0x10, 0x04, 0x03, 0xD0, 0x48, 0x41, 0x44, ++0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xA8, 0x35, 0x01, ++0x9D, 0x04, 0x74, 0x02, 0xD0, 0x85, 0x40, 0x24, 0x00, 0xDD, 0x00, 0x55, 0x04, ++0xD0, 0x01, 0x46, 0x64, 0x00, 0x99, 0x48, 0x44, 0x04, 0x10, 0x31, 0x48, 0x37, ++0x00, 0xC5, 0x00, 0x54, 0x03, 0xD0, 0x09, 0x40, 0x0C, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA7, 0x01, 0xDF, 0x01, 0x7C, 0x27, ++0xF0, 0x0D, 0xD0, 0x74, 0x12, 0x8F, 0x00, 0x5C, 0x44, 0xF0, 0x20, 0xC1, 0xC0, ++0x00, 0x93, 0x00, 0x4C, 0x14, 0x34, 0x1D, 0xC0, 0x37, 0x00, 0x93, 0x80, 0x4C, ++0x03, 0xF4, 0x39, 0xD0, 0x08, 0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x07, 0x80, 0x6D, 0x00, 0xBF, 0x01, 0xF8, 0x07, 0xF0, 0x0F, 0xC8, 0x3F, ++0x00, 0xF8, 0x10, 0xEC, 0x00, 0xF0, 0x23, 0xC0, 0x0F, 0x00, 0xBF, 0x00, 0xFC, ++0x40, 0xF0, 0x0F, 0xC0, 0x3B, 0x10, 0x9F, 0x09, 0xB8, 0x83, 0x30, 0x3B, 0xC0, ++0x1F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x25, ++0x00, 0x9F, 0x40, 0x7C, 0x02, 0xF0, 0x0D, 0xC0, 0x27, 0x00, 0xDF, 0x80, 0x4C, ++0x00, 0x32, 0x01, 0xD0, 0x8C, 0x00, 0x93, 0x00, 0x4C, 0x00, 0xF0, 0x25, 0xC0, ++0x34, 0x00, 0xD3, 0x04, 0x4D, 0x03, 0xF0, 0x28, 0xC0, 0x0B, 0x20, 0x04, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA0, 0x24, 0x00, 0x9C, 0x00, 0x70, ++0x02, 0xD0, 0x0C, 0x60, 0x67, 0x00, 0xDD, 0x03, 0x40, 0x2C, 0x10, 0x03, 0x40, ++0x64, 0x00, 0x91, 0x0F, 0x6D, 0x08, 0x91, 0xB5, 0x40, 0xBC, 0x40, 0xD5, 0x13, ++0xC4, 0x03, 0xC0, 0x49, 0x40, 0x4F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x07, 0xA0, 0x22, 0x20, 0x4D, 0x80, 0x34, 0x02, 0xC0, 0x04, 0x48, ++0x63, 0x00, 0x8D, 0x01, 0x24, 0x04, 0x10, 0x08, 0x42, 0x40, 0x00, 0x91, 0x01, ++0x44, 0x04, 0xD1, 0x18, 0x40, 0xB0, 0x04, 0xC1, 0x02, 0x04, 0x03, 0xD0, 0x08, ++0x40, 0x1F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x80, ++0x68, 0x00, 0xED, 0x21, 0xB4, 0x06, 0xD0, 0x16, 0x40, 0x6B, 0x06, 0xED, 0x11, ++0xA5, 0x44, 0x14, 0x98, 0x50, 0x6C, 0x04, 0xE1, 0x09, 0xA4, 0x04, 0x90, 0x1E, ++0x40, 0x78, 0x02, 0xE5, 0x21, 0x84, 0x07, 0xD1, 0x16, 0x40, 0x13, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10, 0x30, 0x00, 0x8F, 0x00, ++0x3C, 0x02, 0xF0, 0x04, 0x40, 0x23, 0x0A, 0xCF, 0x00, 0x6C, 0x00, 0x32, 0x88, ++0xC8, 0x80, 0x40, 0xC3, 0x08, 0x0C, 0x40, 0xF2, 0x8D, 0xD1, 0x30, 0x02, 0xC3, ++0x00, 0x0D, 0x03, 0xF0, 0x04, 0xC0, 0x4B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xB8, 0x3D, 0x00, 0xBF, 0x80, 0xF0, 0x02, 0xF0, 0x07, ++0xC0, 0x2F, 0x0A, 0xFF, 0x02, 0xDC, 0x00, 0xF0, 0x8B, 0xD0, 0x3B, 0x42, 0xFF, ++0x08, 0xF4, 0x00, 0xB0, 0x8F, 0xC0, 0x3B, 0x02, 0xFF, 0x00, 0xFC, 0x43, 0xF0, ++0x87, 0xC0, 0x0B, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, ++0xA0, 0x67, 0x00, 0xD3, 0x20, 0x7C, 0x07, 0x34, 0x05, 0xC0, 0x70, 0x00, 0x93, ++0x06, 0x5C, 0x00, 0xF0, 0x81, 0xD0, 0x00, 0x10, 0x93, 0x86, 0x4D, 0x04, 0x30, ++0x0D, 0xC0, 0x37, 0x00, 0xD3, 0x04, 0x0D, 0x13, 0x31, 0x05, 0xC0, 0x54, 0x00, ++0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x88, 0x29, 0x00, 0xE1, ++0x00, 0xB4, 0x03, 0x10, 0x06, 0xC0, 0x3A, 0x10, 0xE1, 0x00, 0x84, 0x02, 0xD0, ++0x43, 0x40, 0x29, 0x00, 0xEB, 0x08, 0x84, 0x01, 0x51, 0x0E, 0x40, 0x3B, 0x01, ++0xF1, 0x08, 0x94, 0x43, 0x10, 0x0F, 0xC0, 0x4A, 0x20, 0x06, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x6D, 0x00, 0xA1, 0x01, 0xF6, 0x06, 0x10, ++0x16, 0x40, 0x6C, 0x10, 0xF0, 0x01, 0xB4, 0x04, 0xD0, 0x3A, 0x40, 0x4C, 0x00, ++0xC1, 0x01, 0xC6, 0x04, 0x10, 0x3E, 0x40, 0x73, 0x02, 0xE9, 0x01, 0x84, 0x03, ++0x10, 0x1E, 0x40, 0x0C, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x12, 0x28, 0x63, 0x00, 0x81, 0x04, 0x36, 0x16, 0x10, 0x14, 0x44, 0x22, 0x02, ++0xC1, 0x00, 0x24, 0x0B, 0xD1, 0x0D, 0x41, 0x30, 0x08, 0xC9, 0x00, 0x04, 0x1F, ++0x50, 0x1D, 0x40, 0x33, 0x10, 0xD9, 0x00, 0x15, 0x03, 0x10, 0xEC, 0x40, 0x4A, ++0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xA8, 0x1D, 0x01, ++0x73, 0x80, 0xFC, 0x05, 0x33, 0xE7, 0xCC, 0xDC, 0x40, 0x53, 0xC0, 0xBC, 0x15, ++0xF1, 0x27, 0xD0, 0x1C, 0x08, 0x53, 0x00, 0xCD, 0x05, 0x32, 0x17, 0xC0, 0x17, ++0x40, 0x5B, 0x00, 0x4C, 0x01, 0x30, 0x37, 0xC0, 0x5C, 0x20, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x07, 0x54, 0x1F, 0x00, 0x7C, 0x20, ++0xF0, 0x01, 0xC0, 0x07, 0x24, 0x1F, 0x02, 0x5C, 0x48, 0xF0, 0x01, 0xC0, 0x03, ++0x00, 0x1F, 0x00, 0x7C, 0x20, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x17, 0x20, 0x7C, ++0x80, 0xF0, 0x00, 0xC0, 0x4B, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x08, 0x27, 0x00, 0x9F, 0x00, 0x7C, 0x02, 0xF0, 0x09, 0xC0, 0x24, ++0x00, 0x9F, 0x05, 0x4C, 0x0E, 0x30, 0x09, 0xC0, 0x64, 0x20, 0x8A, 0x01, 0x6C, ++0x02, 0xF0, 0x09, 0xC8, 0x60, 0x00, 0x93, 0x00, 0x4C, 0x22, 0xF0, 0x89, 0xC2, ++0x40, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x26, ++0x00, 0x9D, 0x00, 0x70, 0x02, 0xD0, 0x09, 0x40, 0x25, 0x00, 0x8C, 0x00, 0x44, ++0x12, 0x10, 0x09, 0x40, 0x65, 0x08, 0x9B, 0x01, 0x6C, 0x02, 0xD0, 0xA9, 0x41, ++0xE4, 0x01, 0x91, 0x02, 0x45, 0x06, 0xD0, 0x19, 0x40, 0x04, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xA0, 0x24, 0x00, 0x9D, 0x20, 0x70, ++0x03, 0xD0, 0x0C, 0x40, 0x34, 0x00, 0x9C, 0x10, 0x44, 0x02, 0x14, 0x09, 0x40, ++0x24, 0x02, 0x9D, 0x48, 0x65, 0x12, 0xD2, 0x09, 0x40, 0x24, 0x42, 0x91, 0x14, ++0x44, 0x82, 0xD0, 0x0D, 0x44, 0x60, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0xA0, 0x10, 0x8D, 0x02, 0x34, 0x0A, 0xD0, 0x28, 0x40, ++0x21, 0x10, 0x9D, 0x14, 0x46, 0x02, 0x18, 0x48, 0x45, 0x21, 0x45, 0xCD, 0x14, ++0x24, 0x02, 0xD0, 0x48, 0x71, 0x20, 0x85, 0x81, 0x14, 0x04, 0x52, 0xD0, 0x48, ++0x41, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xB0, ++0x06, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0xD0, 0x00, 0x40, 0x04, 0x10, 0x1F, 0x04, ++0x4C, 0x00, 0x30, 0x41, 0xC4, 0x14, 0x21, 0x1F, 0x44, 0x6C, 0x00, 0xF1, 0x41, ++0xC0, 0x04, 0x01, 0x13, 0xC4, 0x4C, 0x10, 0xF0, 0x41, 0xD0, 0x74, 0xC0, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xB8, 0x7B, 0x00, 0xFF, 0x01, ++0xBC, 0x06, 0xF0, 0x1B, 0xC0, 0x2F, 0x05, 0xAE, 0x00, 0xFD, 0x52, 0xF1, 0x4F, ++0xC1, 0x2F, 0x45, 0xBB, 0x14, 0xBC, 0x52, 0xF0, 0x4B, 0xC1, 0x27, 0x40, 0xBF, ++0x14, 0x7C, 0x02, 0xF2, 0x4B, 0xC1, 0x67, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x19, 0xA0, 0xA7, 0x00, 0x93, 0x02, 0x4C, 0x02, 0x30, 0x28, ++0xC0, 0xAF, 0x00, 0xAF, 0x01, 0xDC, 0x0A, 0xF0, 0x39, 0xC0, 0xED, 0x05, 0xB3, ++0x03, 0xDC, 0x02, 0x32, 0x5B, 0xC1, 0x2C, 0x00, 0xB3, 0x01, 0xCC, 0x06, 0x30, ++0x6A, 0xC0, 0x60, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, ++0x08, 0x47, 0x01, 0x1B, 0x01, 0x6C, 0x14, 0xB0, 0x51, 0x40, 0x47, 0x00, 0x1D, ++0x02, 0x45, 0x04, 0xD1, 0x10, 0x40, 0xC0, 0x00, 0x11, 0x01, 0x45, 0x14, 0x10, ++0x75, 0xC0, 0x07, 0x10, 0x11, 0x05, 0x54, 0x00, 0x10, 0x61, 0x40, 0x70, 0x20, ++0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA0, 0x23, 0x00, 0x81, ++0x20, 0x04, 0x42, 0x10, 0x08, 0x40, 0x23, 0x08, 0x8D, 0x02, 0x14, 0x12, 0xD0, ++0x28, 0x40, 0x21, 0x00, 0x85, 0x02, 0x14, 0x46, 0x10, 0x08, 0x49, 0x21, 0x00, ++0x81, 0x12, 0x04, 0x0A, 0x10, 0x28, 0x40, 0x40, 0x80, 0x0E, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x18, 0xA8, 0x21, 0x00, 0x89, 0x00, 0x24, 0x42, 0x90, ++0x09, 0x40, 0x27, 0x00, 0x9D, 0x04, 0x44, 0x12, 0xD0, 0x19, 0x40, 0xA4, 0x00, ++0x95, 0x00, 0x44, 0x02, 0x10, 0x09, 0x40, 0x27, 0x00, 0x90, 0x04, 0x54, 0x02, ++0x10, 0x39, 0x40, 0x60, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x05, 0xA8, 0x2F, 0x02, 0xB3, 0x00, 0xCC, 0x0A, 0x30, 0x0B, 0xC0, 0xA7, 0x04, ++0x9F, 0x01, 0x5C, 0x02, 0xF0, 0x29, 0xC8, 0x25, 0x40, 0x97, 0x00, 0x5C, 0x0A, ++0x34, 0x09, 0xC8, 0x25, 0x40, 0x93, 0x00, 0x4D, 0x02, 0x34, 0x29, 0xD0, 0x14, ++0x20, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, 0x65, 0x00, ++0x9F, 0x03, 0x7C, 0x0A, 0xE0, 0x09, 0xC0, 0xA7, 0x00, 0x8F, 0x00, 0x7C, 0x02, ++0xF0, 0x08, 0xC4, 0x27, 0x01, 0x8B, 0x45, 0x7C, 0x02, 0xF0, 0x98, 0xE0, 0x21, ++0x00, 0x9F, 0x00, 0x3C, 0x02, 0xF0, 0x09, 0xC0, 0x53, 0x00, 0x06, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x05, 0x00, 0x13, 0x00, 0x4D, 0x08, ++0xF0, 0x01, 0xC0, 0x04, 0x00, 0x13, 0x10, 0x6C, 0x00, 0xF0, 0x01, 0xD0, 0x04, ++0x40, 0x13, 0x00, 0x6C, 0x00, 0x30, 0x01, 0xC0, 0x04, 0x04, 0x03, 0x80, 0x7C, ++0x00, 0x34, 0x20, 0xC0, 0x50, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x14, 0xA0, 0x14, 0x10, 0x51, 0x00, 0x44, 0x01, 0xD0, 0x05, 0x40, 0x54, ++0x01, 0x75, 0x02, 0xC4, 0x05, 0xD0, 0x05, 0x50, 0xD8, 0x40, 0x75, 0x00, 0xC4, ++0x11, 0x10, 0x47, 0x50, 0x1C, 0x00, 0x71, 0x00, 0x74, 0x01, 0x10, 0x15, 0x40, ++0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xA0, 0x32, ++0x00, 0xC1, 0x00, 0x04, 0x03, 0xD0, 0x0C, 0x40, 0x20, 0x00, 0xC1, 0x0A, 0x24, ++0x26, 0xD0, 0x0C, 0x44, 0xF0, 0x86, 0xC4, 0x09, 0x65, 0x07, 0x50, 0x0C, 0x00, ++0xF0, 0x00, 0xC5, 0x20, 0x34, 0x02, 0x10, 0x1C, 0x40, 0x50, 0x00, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x3C, 0x01, 0xF1, 0x04, 0x84, ++0xA3, 0xD0, 0x1F, 0x40, 0x78, 0x00, 0x25, 0x00, 0x84, 0x00, 0xD0, 0x4E, 0x40, ++0x28, 0x00, 0x65, 0x00, 0x85, 0x13, 0x50, 0x0A, 0x40, 0x90, 0x00, 0xA5, 0x00, ++0xB0, 0x02, 0x10, 0x0F, 0x41, 0x14, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x15, 0x10, 0x78, 0x00, 0xE3, 0x07, 0x8C, 0x17, 0xF0, 0x7E, 0xD0, ++0x6C, 0x00, 0xA3, 0x01, 0xAC, 0x05, 0xF0, 0x3E, 0xC1, 0x68, 0x00, 0x77, 0x01, ++0xED, 0x0F, 0x74, 0x13, 0x84, 0x48, 0x00, 0xA7, 0x01, 0x3C, 0x06, 0x30, 0x1E, ++0xC0, 0x54, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB8, ++0x31, 0x40, 0xCF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC0, 0x3F, 0x00, 0x9F, 0x00, ++0xFD, 0x00, 0xF0, 0x2D, 0xC0, 0x27, 0x02, 0x5D, 0x00, 0x7C, 0x03, 0x90, 0x01, ++0xC0, 0x07, 0x40, 0x1B, 0x00, 0x7C, 0x02, 0xF0, 0x0D, 0xD0, 0x43, 0x60, 0x06, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA0, 0x7F, 0x04, 0xF3, 0x01, ++0xCC, 0x27, 0x3C, 0x1F, 0xC0, 0x7B, 0x00, 0x37, 0x01, 0xDC, 0x06, 0x72, 0x1F, ++0xC0, 0x6D, 0x00, 0xF7, 0x81, 0xCC, 0x06, 0x31, 0x1B, 0xC0, 0x4C, 0x10, 0xE3, ++0x01, 0xCC, 0x06, 0xF0, 0x1F, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x15, 0x88, 0x39, 0x00, 0xE1, 0x00, 0xAC, 0x23, 0x18, 0x4E, ++0x40, 0x3B, 0x00, 0x21, 0x04, 0x84, 0x80, 0xD0, 0x4E, 0x40, 0x2C, 0x00, 0x61, ++0x02, 0x8C, 0x02, 0x10, 0x0A, 0x40, 0x09, 0x00, 0xAB, 0x00, 0x94, 0x02, 0xD0, ++0x0E, 0x40, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, ++0x00, 0x79, 0x00, 0xE1, 0x11, 0x84, 0x07, 0x12, 0x1E, 0x40, 0x3B, 0x00, 0x05, ++0x00, 0x90, 0x00, 0x50, 0x0E, 0x44, 0x09, 0x04, 0x3D, 0x10, 0x84, 0x03, 0x10, ++0x02, 0x41, 0x0A, 0x00, 0xA1, 0x00, 0x84, 0x02, 0xD0, 0x2E, 0x40, 0x03, 0x00, ++0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x28, 0x33, 0x40, 0xC1, ++0x10, 0x24, 0x03, 0x11, 0x8C, 0x40, 0x33, 0x00, 0x01, 0x00, 0x04, 0x0C, 0xD0, ++0x8C, 0x40, 0x80, 0x01, 0x09, 0x40, 0x24, 0x0F, 0x11, 0x11, 0x44, 0x03, 0x00, ++0x09, 0x00, 0x14, 0x02, 0xD0, 0x0C, 0x40, 0x13, 0x20, 0x0C, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x1D, 0xA8, 0x35, 0x00, 0xD3, 0x00, 0x0C, 0x03, 0x30, ++0x3D, 0xC0, 0x37, 0x00, 0x87, 0x00, 0x5C, 0x1E, 0x70, 0x1F, 0xC0, 0x4D, 0x00, ++0x9F, 0x00, 0xCD, 0x13, 0x34, 0x09, 0xC0, 0x06, 0x08, 0xD3, 0x00, 0x4C, 0x03, ++0xF3, 0x0D, 0xC4, 0x57, 0x20, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x01, 0x00, 0x37, 0x00, 0xDF, 0x00, 0x7C, 0x03, 0xF0, 0x0D, 0xC1, 0x37, 0x00, ++0x1F, 0x08, 0x7C, 0x40, 0xF0, 0x0D, 0xC4, 0x83, 0x00, 0x47, 0x00, 0x5C, 0x00, ++0xF0, 0x01, 0xC0, 0x85, 0x10, 0xCF, 0x00, 0x3C, 0x03, 0xF0, 0x8D, 0xC4, 0x07, ++0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x3F, 0x00, ++0xFF, 0x00, 0xCC, 0x03, 0x30, 0x0F, 0xC0, 0x3F, 0x00, 0xB3, 0x40, 0xEC, 0x00, ++0x30, 0x0D, 0xC0, 0x4D, 0x00, 0xB3, 0x02, 0xCC, 0x43, 0x10, 0x01, 0x40, 0x04, ++0x00, 0xBF, 0x01, 0xCC, 0x16, 0x30, 0x0F, 0xC0, 0x03, 0x22, 0x0C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x20, 0x36, 0x00, 0xCD, 0x00, 0x44, 0x03, ++0x14, 0x0D, 0x44, 0x73, 0x02, 0x91, 0x01, 0x04, 0x04, 0x14, 0x0D, 0x50, 0x04, ++0x86, 0x51, 0x02, 0x6C, 0x3C, 0x50, 0x31, 0x40, 0xC5, 0x01, 0x1D, 0x01, 0x44, ++0x02, 0xB0, 0x09, 0x40, 0x07, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x01, 0xA0, 0x34, 0x00, 0xDD, 0x00, 0x44, 0x03, 0x10, 0x0D, 0x40, 0x37, ++0x00, 0x11, 0x01, 0x64, 0x06, 0x10, 0x0C, 0x4A, 0x04, 0x00, 0x95, 0x00, 0x04, ++0x02, 0x50, 0x39, 0x40, 0x45, 0x10, 0xDD, 0x04, 0x40, 0x03, 0x11, 0x1D, 0x40, ++0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x30, ++0x00, 0xDD, 0x00, 0x45, 0x03, 0x10, 0x0C, 0x40, 0x37, 0x40, 0x01, 0x00, 0x44, ++0x00, 0x10, 0x0C, 0x40, 0x01, 0x80, 0x41, 0x00, 0x24, 0x00, 0x40, 0x00, 0x40, ++0x01, 0x00, 0xCD, 0x00, 0x05, 0x03, 0x80, 0x0C, 0x40, 0x43, 0x80, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xB0, 0x3A, 0x10, 0xEF, 0x00, 0x8C, ++0x03, 0x30, 0x0F, 0x40, 0x37, 0x00, 0x13, 0x00, 0x6C, 0x00, 0x38, 0x0F, 0xD0, ++0x04, 0x00, 0x95, 0x00, 0x0D, 0x03, 0x61, 0x01, 0x80, 0x05, 0x20, 0x9F, 0x00, ++0x4D, 0x02, 0x30, 0x0D, 0xC0, 0x03, 0xC0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x05, 0xB8, 0x3F, 0x00, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, ++0x3F, 0x20, 0x3F, 0x00, 0xFC, 0x00, 0xF1, 0x0F, 0xC0, 0x0E, 0x00, 0x2E, 0x00, ++0xFC, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3F, 0x00, 0xFC, 0x02, 0xF1, 0x0F, ++0xC0, 0x17, 0x60, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, ++0x82, 0xC0, 0x0E, 0x02, 0x3B, 0x08, 0xE0, 0x28, 0xB0, 0x83, 0xE0, 0x0E, 0x82, ++0x38, 0x08, 0xEC, 0x20, 0x90, 0x83, 0xC8, 0x0E, 0x02, 0x1B, 0x08, 0xEC, 0x28, ++0xA8, 0x83, 0xA0, 0x0E, 0x02, 0x3A, 0x08, 0xCC, 0x20, 0x98, 0x03, 0x8C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x22, 0xA0, 0x8E, 0xA0, ++0x3A, 0x02, 0xEA, 0x08, 0xA0, 0x23, 0x20, 0x8E, 0xA0, 0x3B, 0x02, 0xEA, 0x08, ++0xA8, 0x23, 0xA0, 0x8E, 0xA0, 0x32, 0x02, 0x4A, 0x08, 0xA8, 0x23, 0x88, 0x8E, ++0x80, 0x3A, 0x02, 0xCA, 0x08, 0xA8, 0x03, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x18, ++0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, ++0x01, 0x12, 0x04, 0x48, 0x18, 0x20, 0x41, 0xA0, 0x04, 0x01, 0x12, 0x04, 0x48, ++0x10, 0x20, 0x01, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x21, 0x00, 0x80, 0x02, 0x80, 0x1A, 0x00, 0x68, 0x00, 0xA0, 0x01, 0xA0, 0x0E, ++0x20, 0x1A, 0x00, 0x68, 0x00, 0xA0, 0x01, 0x00, 0x06, 0x00, 0x0A, 0x00, 0x28, ++0x10, 0xA8, 0x01, 0x88, 0x06, 0x80, 0x1A, 0x00, 0x68, 0x00, 0x88, 0x01, 0x04, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x12, 0xA0, 0x4E, ++0x80, 0x3A, 0x01, 0xEA, 0x14, 0xA0, 0x13, 0xA0, 0x4A, 0x80, 0x3A, 0x01, 0xEA, ++0x04, 0xA8, 0x13, 0xA0, 0x4E, 0x82, 0x3A, 0x01, 0xEA, 0x04, 0xA0, 0x13, 0x80, ++0x4A, 0x80, 0x3A, 0x01, 0xEA, 0x0C, 0xA8, 0x03, 0x8C, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, ++0x00, 0x88, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, ++0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, ++0x60, 0x00, 0x80, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xA3, 0x20, 0x20, 0x04, 0x80, 0x10, 0x01, 0x42, 0x00, 0x08, 0x11, 0x20, ++0x04, 0x80, 0x10, 0x01, 0x42, 0x04, 0x08, 0x11, 0x20, 0xC0, 0x80, 0x10, 0x01, ++0x42, 0x00, 0x00, 0x11, 0x00, 0x04, 0x80, 0x10, 0x01, 0x42, 0x04, 0x08, 0x01, ++0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xD2, 0xA0, ++0x02, 0x01, 0x0A, 0x05, 0x2A, 0x10, 0xA8, 0x50, 0x80, 0x02, 0x01, 0x0A, 0x07, ++0x2A, 0x1C, 0xA8, 0x50, 0xA0, 0x42, 0x83, 0x0A, 0x05, 0x2A, 0x10, 0xA0, 0x50, ++0x88, 0x02, 0x01, 0x0A, 0x05, 0x2A, 0x3C, 0xA0, 0x00, 0x8C, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x30, 0x80, 0xC8, 0x00, 0xAA, 0x03, ++0xA8, 0x0E, 0x20, 0x38, 0x80, 0xE0, 0x00, 0xAA, 0x07, 0x08, 0x1E, 0xA0, 0x32, ++0x80, 0xCA, 0x00, 0x22, 0x03, 0xA8, 0x0C, 0xA0, 0x3A, 0xA0, 0xCA, 0x00, 0x2A, ++0x03, 0xA8, 0x0C, 0x20, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x21, 0x72, 0x00, 0x48, 0x20, 0x18, 0x80, 0x22, 0x00, 0x00, 0x00, ++0x08, 0x40, 0x20, 0x08, 0x02, 0x00, 0x08, 0x80, 0x00, 0x00, 0x82, 0x00, 0x20, ++0x00, 0x20, 0x04, 0x80, 0x00, 0x08, 0x42, 0x00, 0x18, 0x00, 0x20, 0x08, 0x00, ++0x82, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x16, ++0x40, 0x18, 0x00, 0x41, 0x00, 0x04, 0x01, 0x1A, 0x04, 0x40, 0x10, 0x20, 0x41, ++0x80, 0x04, 0x01, 0x10, 0x04, 0x40, 0x10, 0x00, 0x61, 0x00, 0x04, 0x01, 0x10, ++0x04, 0x08, 0x10, 0x00, 0x41, 0x00, 0x04, 0x01, 0x10, 0x82, 0x8C, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x02, 0xA0, 0x06, 0x80, 0x9A, ++0x00, 0x6A, 0x02, 0x28, 0x09, 0xA0, 0x24, 0x00, 0x9B, 0x00, 0x48, 0x02, 0xA8, ++0x01, 0xA0, 0x06, 0x00, 0x1A, 0x00, 0x6A, 0x00, 0xB8, 0x09, 0xA0, 0x06, 0xA0, ++0x1B, 0x00, 0x6A, 0x00, 0xA8, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA3, 0x00, 0xC0, 0x46, 0x00, 0x1A, 0x00, 0x6C, 0x00, 0xBC, ++0x01, 0x90, 0x46, 0x00, 0x1B, 0x00, 0x6C, 0x00, 0xA8, 0x01, 0xC0, 0x06, 0x20, ++0x1B, 0x80, 0x6C, 0x04, 0xA0, 0x01, 0xE8, 0x46, 0x00, 0x1A, 0x00, 0x6C, 0x00, ++0x32, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, ++0x42, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, 0x43, 0x20, 0x08, 0x81, ++0x30, 0x04, 0xC2, 0x10, 0x18, 0x43, 0x28, 0x0C, 0x01, 0x30, 0x04, 0xC2, 0x30, ++0x08, 0x43, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, 0x03, 0x8C, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x0C, 0x00, ++0x30, 0x00, 0xC0, 0x04, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x80, 0x00, ++0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x08, ++0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x80, 0x0C, 0x83, 0x32, 0x04, 0xC8, 0x34, ++0x28, 0x43, 0x80, 0x0C, 0x83, 0x32, 0x04, 0xC8, 0x10, 0x20, 0x43, 0x80, 0x0C, ++0x01, 0x32, 0x04, 0xC8, 0x10, 0x28, 0x43, 0x80, 0x0C, 0x83, 0x32, 0x04, 0xC8, ++0x10, 0x20, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA3, 0x42, 0xA0, 0x06, 0x83, 0x1A, 0x04, 0x6A, 0x30, 0xA8, 0x41, 0xA0, 0x06, ++0x83, 0x1A, 0x04, 0x6A, 0x10, 0xA8, 0x41, 0xA0, 0x06, 0x81, 0x1A, 0x04, 0x6A, ++0x30, 0xA8, 0x41, 0x80, 0x0E, 0x83, 0x0A, 0x04, 0x6A, 0x10, 0xA8, 0x01, 0x8C, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x42, 0x00, 0x04, ++0x01, 0x30, 0x04, 0x40, 0x10, 0x00, 0x41, 0x00, 0x0C, 0x01, 0x30, 0x04, 0xC0, ++0x10, 0x00, 0x41, 0x00, 0x04, 0x01, 0x10, 0x04, 0x40, 0x10, 0x00, 0x43, 0x00, ++0x00, 0x01, 0x30, 0x04, 0x40, 0x10, 0x00, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x4A, 0x20, 0x06, 0x81, 0x30, 0x04, 0x62, ++0x12, 0x08, 0x4B, 0x20, 0x06, 0x81, 0xB0, 0x04, 0x62, 0x12, 0x88, 0x41, 0x20, ++0x26, 0x81, 0x18, 0x04, 0x62, 0x10, 0x08, 0x43, 0x00, 0x06, 0x81, 0x30, 0x04, ++0x62, 0x12, 0x88, 0x01, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x23, 0x06, 0xA0, 0x1A, 0x00, 0x62, 0x00, 0xAA, 0x01, 0x20, 0x04, 0xA0, ++0x18, 0x00, 0x62, 0x00, 0x8A, 0x01, 0xA0, 0x06, 0xA0, 0x1A, 0x80, 0x6A, 0x80, ++0xAA, 0x01, 0x20, 0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0xAA, 0x01, 0xA8, 0x02, ++0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x60, 0x80, ++0x82, 0x01, 0x2A, 0x06, 0x28, 0x18, 0xA0, 0x60, 0x80, 0x82, 0x01, 0x0A, 0x06, ++0x28, 0x18, 0xA0, 0x60, 0x00, 0x82, 0x01, 0x0A, 0x06, 0x28, 0x18, 0xA0, 0x60, ++0xA0, 0x82, 0x01, 0x0A, 0x06, 0x28, 0x18, 0xA0, 0x00, 0x04, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x48, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x48, 0x12, 0x20, 0x49, 0xA0, 0x00, 0x01, 0x92, 0x04, 0x48, 0x12, 0x28, 0x41, ++0x80, 0x20, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x88, 0x00, 0x01, 0x02, ++0x04, 0x08, 0x12, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA3, 0x62, 0xC0, 0x8A, 0x01, 0x01, 0x06, 0xAC, 0x18, 0xB0, 0x63, ++0xC0, 0x8A, 0x01, 0x2B, 0x06, 0x8C, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, 0x2A, ++0x06, 0xAC, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, 0x2B, 0x06, 0x8C, 0x18, 0xB0, ++0x02, 0x8C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x62, ++0xA0, 0x8E, 0x01, 0x3B, 0x06, 0xEA, 0x18, 0xA8, 0x63, 0xA0, 0x8E, 0x81, 0x3A, ++0x06, 0x68, 0x18, 0x88, 0x63, 0xA0, 0x8E, 0x81, 0x3A, 0x06, 0xEA, 0x18, 0x98, ++0x63, 0x20, 0x8E, 0x81, 0x3B, 0x06, 0xCA, 0x18, 0x88, 0x03, 0x8C, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x62, 0x80, 0x8E, 0x01, 0x3A, ++0x06, 0xEC, 0x18, 0xA0, 0x61, 0xC0, 0x8E, 0x01, 0x3A, 0x06, 0xE8, 0x18, 0xA0, ++0x63, 0xE0, 0x8E, 0x01, 0x1B, 0x06, 0xE0, 0x18, 0xA0, 0x63, 0xC0, 0x8E, 0x01, ++0x3A, 0x06, 0xEE, 0x18, 0xB0, 0x03, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xA2, 0x62, 0xA0, 0x8E, 0x81, 0x32, 0x06, 0xEA, 0x18, 0x08, ++0x63, 0xA0, 0x8E, 0xA1, 0x38, 0x86, 0xEA, 0x18, 0x28, 0x61, 0x20, 0x8E, 0x81, ++0x32, 0x86, 0xE8, 0x18, 0xA8, 0x63, 0xA0, 0x8E, 0xA1, 0x30, 0x06, 0xEA, 0x18, ++0xA8, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x40, 0x80, 0x04, 0x01, 0x1A, 0x84, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, 0x01, ++0x32, 0x04, 0x48, 0x10, 0x22, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x10, ++0x20, 0x41, 0x88, 0x04, 0x01, 0x3A, 0x04, 0x48, 0x10, 0x20, 0x01, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x80, 0x86, 0x81, ++0x1A, 0x06, 0x68, 0x18, 0xA0, 0x61, 0x80, 0x86, 0x81, 0x18, 0x06, 0x68, 0x18, ++0xA0, 0x61, 0x80, 0x84, 0x01, 0x1A, 0x06, 0x68, 0x18, 0xA8, 0x61, 0x80, 0x86, ++0x81, 0x1A, 0x06, 0x6A, 0x18, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xA2, 0x02, 0xA0, 0x0E, 0x80, 0x3A, 0x00, 0xCA, 0x00, ++0x22, 0x03, 0xA0, 0x0C, 0x80, 0x32, 0x00, 0xCA, 0x00, 0x28, 0x03, 0x80, 0x0E, ++0x80, 0x2A, 0x00, 0xEA, 0x00, 0xA8, 0x03, 0xA0, 0x0E, 0x80, 0x3A, 0x00, 0xE8, ++0x00, 0xA8, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xA2, 0x42, 0x00, 0x06, 0x01, 0x08, 0x04, 0x40, 0x10, 0x08, 0x41, 0x00, 0x04, ++0x01, 0x00, 0x0C, 0x40, 0x10, 0x80, 0x41, 0x00, 0x06, 0x01, 0x18, 0x04, 0x60, ++0x10, 0x80, 0x41, 0x00, 0x04, 0x01, 0x18, 0x04, 0x60, 0x10, 0x80, 0x01, 0x88, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x42, 0x20, 0x04, ++0x81, 0x10, 0x04, 0x22, 0x10, 0x88, 0x51, 0x20, 0x06, 0x81, 0x18, 0x05, 0x62, ++0x10, 0x08, 0x41, 0x00, 0x04, 0x81, 0x10, 0x04, 0x42, 0x10, 0x0A, 0x41, 0x20, ++0x06, 0x81, 0x10, 0x04, 0x40, 0x10, 0x08, 0x01, 0x88, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x42, 0xA0, 0x02, 0x01, 0x0A, 0x0C, 0xAA, ++0x30, 0xA8, 0xC2, 0xA0, 0x0A, 0x03, 0x2A, 0x04, 0xAA, 0x30, 0xA8, 0x42, 0xA0, ++0x02, 0x81, 0x0A, 0x04, 0x2A, 0x10, 0xA0, 0xC0, 0xA0, 0x02, 0x21, 0x0A, 0x04, ++0x28, 0x10, 0xA8, 0x00, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x40, 0x80, 0x0A, 0x03, 0x2A, 0x0C, 0xA8, 0x10, 0xA0, 0x52, 0x80, ++0x0A, 0x03, 0x2A, 0x05, 0xA8, 0x30, 0xA0, 0xC2, 0x80, 0x0A, 0x01, 0x2A, 0x0C, ++0xA8, 0x30, 0xA0, 0xC2, 0x80, 0x0A, 0x03, 0x2A, 0x0C, 0xA8, 0x10, 0xA0, 0x02, ++0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++0x42, 0x00, 0x08, 0x00, 0x20, 0x00, 0x88, 0x01, 0x00, 0x02, 0x00, 0x08, 0x80, ++0x20, 0x00, 0x88, 0x10, 0x00, 0x42, 0x20, 0x08, 0x01, 0x20, 0x04, 0x82, 0x00, ++0x00, 0x42, 0x00, 0x08, 0x01, 0x20, 0x04, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x42, 0x40, 0x00, 0x01, 0x01, 0x04, ++0x04, 0x10, 0x10, 0x41, 0x40, 0x44, 0x01, 0x01, 0x04, 0x04, 0x14, 0x10, 0x40, ++0x40, 0x00, 0x01, 0x01, 0x04, 0x00, 0x10, 0x10, 0x50, 0x40, 0x00, 0x01, 0x01, ++0x04, 0x04, 0x10, 0x10, 0x00, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0xA2, 0x02, 0xE0, 0x06, 0x80, 0x1B, 0x00, 0x68, 0x00, 0xA8, 0x01, ++0xA0, 0x06, 0x80, 0x1B, 0x00, 0x6E, 0x00, 0xA8, 0x01, 0x80, 0x06, 0x80, 0x1A, ++0x00, 0x6E, 0x00, 0xB8, 0x01, 0xA0, 0x06, 0x80, 0x1B, 0x00, 0x6A, 0x00, 0xA8, ++0x01, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x02, ++0xC0, 0x06, 0x00, 0x3B, 0x00, 0x6C, 0x00, 0xA0, 0x01, 0xC0, 0x06, 0x00, 0x3A, ++0x00, 0x68, 0x00, 0xB0, 0x01, 0xC0, 0x06, 0x00, 0x1A, 0x00, 0x6C, 0x00, 0xA0, ++0x03, 0xC0, 0x06, 0x00, 0x3A, 0x00, 0x4C, 0x00, 0xB0, 0x01, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0C, 0x80, 0x18, ++0x00, 0xC2, 0x00, 0x08, 0x01, 0x28, 0x0C, 0x80, 0x18, 0x80, 0xC0, 0x00, 0x08, ++0x03, 0x20, 0x0C, 0x82, 0x38, 0x00, 0xC2, 0x00, 0x88, 0x01, 0x20, 0x0C, 0x80, ++0x18, 0x00, 0xC2, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x10, 0x00, 0xC0, 0x02, 0x00, ++0x63, 0x00, 0x2C, 0x00, 0x10, 0x00, 0xC2, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x00, ++0x10, 0x00, 0xC0, 0x02, 0x00, 0x21, 0x00, 0x2C, 0x00, 0x10, 0x00, 0x40, 0x00, ++0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x20, 0x80, 0x8C, 0x82, 0x32, 0x0A, 0xC8, 0x08, 0x20, 0x21, 0x80, 0x8C, 0x82, ++0x32, 0x02, 0x88, 0x28, 0x20, 0xA3, 0x80, 0x8C, 0x02, 0x22, 0x0A, 0xC8, 0x28, ++0x28, 0xA3, 0x80, 0x8C, 0x82, 0x32, 0x0A, 0xC8, 0x08, 0x20, 0x03, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xA0, 0x16, 0x83, ++0x5A, 0x0C, 0x6A, 0x31, 0xA0, 0xC4, 0xA0, 0x16, 0x83, 0x5A, 0x0C, 0x6A, 0x31, ++0xA8, 0xC5, 0xA0, 0x16, 0x83, 0x4A, 0x0C, 0x6A, 0x31, 0xA8, 0xE5, 0xA0, 0x16, ++0x83, 0x5A, 0x0C, 0x6A, 0x31, 0xA8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x10, 0x01, 0x40, 0x02, ++0x08, 0x21, 0x00, 0x64, 0x00, 0x10, 0x00, 0x40, 0x04, 0x00, 0x01, 0x00, 0x04, ++0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x91, 0x00, 0x24, 0x00, 0x00, 0x00, 0x40, ++0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x22, 0x46, 0x88, 0x18, 0x21, 0x62, 0x80, 0x8A, 0x01, 0x26, 0x06, ++0x88, 0x18, 0x20, 0x62, 0x80, 0x88, 0x11, 0x22, 0x46, 0x88, 0x18, 0x21, 0x62, ++0x84, 0x88, 0x01, 0x22, 0x46, 0x88, 0x18, 0x21, 0x62, 0x84, 0x88, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x0A, ++0x08, 0x2A, 0x20, 0xAA, 0x80, 0x88, 0x02, 0xA2, 0x0A, 0x08, 0x2A, 0x20, 0xAA, ++0x00, 0xAA, 0x02, 0xA2, 0x0A, 0x88, 0x28, 0x20, 0xAA, 0x80, 0xA0, 0x02, 0xA6, ++0x0A, 0x08, 0x2A, 0x20, 0xAA, 0x80, 0xA8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, 0x42, 0x10, 0x0A, 0x41, 0x28, ++0x44, 0xA1, 0x10, 0x8C, 0x4A, 0x10, 0x2A, 0x41, 0x28, 0x04, 0xA1, 0x10, 0x04, ++0x42, 0x10, 0x0A, 0x41, 0x28, 0x84, 0x81, 0x10, 0x84, 0x4A, 0x10, 0x0A, 0x41, ++0x20, 0x04, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x50, 0x80, 0x40, 0x01, 0x02, 0x05, 0x00, 0x14, 0x00, 0x50, 0x80, ++0x40, 0x01, 0x02, 0x05, 0x00, 0x14, 0x00, 0x50, 0x80, 0x40, 0x01, 0x02, 0x05, ++0x08, 0x14, 0x20, 0x50, 0x80, 0x40, 0x01, 0x02, 0x05, 0x08, 0x14, 0x20, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xC0, ++0xCA, 0x20, 0x2B, 0x03, 0x8C, 0x0C, 0x30, 0x32, 0x40, 0xC0, 0x00, 0x01, 0x03, ++0x88, 0x0C, 0x30, 0x32, 0xC0, 0xCA, 0x00, 0x2B, 0x03, 0xAC, 0x0C, 0xB0, 0x32, ++0x40, 0xC0, 0x00, 0x2B, 0x03, 0xAC, 0x0C, 0xB0, 0x02, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA4, 0x4E, 0x80, 0x3A, 0x01, ++0xEA, 0x04, 0xB8, 0x13, 0xA0, 0x4E, 0x80, 0x3B, 0x41, 0xEA, 0x04, 0xA8, 0x13, ++0xA0, 0x4E, 0x84, 0x3B, 0x01, 0xEA, 0x04, 0xB8, 0x13, 0xA0, 0x4E, 0x80, 0x3B, ++0x01, 0xE2, 0x44, 0xA8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xC4, 0x10, 0x12, 0x23, 0x08, 0x8C, 0x21, 0x30, 0x80, 0xC0, ++0x10, 0x02, 0x23, 0x08, 0x0C, 0x21, 0x30, 0x84, 0xC4, 0x18, 0x12, 0x43, 0x48, ++0x8C, 0x21, 0x31, 0x82, 0xC0, 0x18, 0x12, 0xA3, 0x48, 0x8C, 0x21, 0x31, 0x84, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, ++0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, ++0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, ++0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xB4, 0xDF, 0xD0, 0x6C, 0x43, 0xB3, 0x0D, 0xCD, 0xBE, ++0x7C, 0xDB, 0xD0, 0x6C, 0x43, 0xFB, 0x0D, 0xED, 0x37, 0x34, 0xDB, 0xD0, 0x7E, ++0x43, 0xB3, 0x0D, 0xCD, 0xBE, 0x7C, 0xDB, 0xD0, 0x6C, 0x43, 0xB3, 0x0D, 0xED, ++0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xCC, 0x3F, 0x32, 0xF3, 0xC8, 0xCC, 0x23, 0x33, 0xBF, 0xFC, 0x3C, 0x32, 0xF3, ++0xC8, 0xFC, 0x23, 0xF3, 0x8F, 0xCC, 0x3C, 0x32, 0xFF, 0xC8, 0xCC, 0x23, 0x33, ++0xBF, 0xFC, 0x3C, 0x32, 0xF3, 0xC8, 0xCC, 0x23, 0xF3, 0x8F, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x78, 0x72, 0x7B, ++0x48, 0xEC, 0x27, 0x31, 0x86, 0xC4, 0x78, 0x12, 0x7B, 0x48, 0x8C, 0x27, 0xB1, ++0x9F, 0xDC, 0x7E, 0x72, 0xE3, 0xC9, 0xED, 0x27, 0xB7, 0x87, 0xC4, 0x7E, 0x72, ++0x7B, 0xC8, 0xED, 0x27, 0x37, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x8E, 0x02, 0x39, 0x08, 0xE4, 0x20, ++0x80, 0x83, 0x40, 0x0E, 0x02, 0x39, 0x08, 0xE4, 0x20, 0x90, 0x83, 0x40, 0x0E, ++0x02, 0x39, 0x08, 0xE0, 0x20, 0x90, 0x83, 0x40, 0x8E, 0x02, 0x39, 0x0A, 0xE0, ++0x28, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x20, 0xA0, 0x8E, 0x81, 0x3A, 0x02, 0xEA, 0x08, 0xA8, 0x23, 0xA0, 0x8E, ++0x80, 0x3A, 0x02, 0xEA, 0x08, 0xA8, 0x23, 0xA0, 0x8E, 0x80, 0x3A, 0x02, 0xEA, ++0x08, 0xAA, 0x23, 0xA0, 0x8E, 0x81, 0x3A, 0x06, 0xEA, 0x18, 0xB8, 0x03, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x04, ++0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, ++0x10, 0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x10, 0x20, 0x41, 0x80, ++0x84, 0x01, 0x12, 0x06, 0x48, 0x18, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x18, 0x00, 0x60, ++0x00, 0x88, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x20, ++0x06, 0x00, 0x18, 0x00, 0x62, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, ++0x62, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x20, 0x4E, 0x80, 0x38, 0x01, 0xE2, 0x04, 0x88, 0x93, 0x20, ++0x4E, 0x80, 0x38, 0x01, 0xE2, 0x04, 0x88, 0x13, 0x20, 0x4A, 0x80, 0x38, 0x01, ++0xE2, 0x04, 0x88, 0x13, 0x20, 0x4E, 0x80, 0x38, 0x01, 0xE2, 0x04, 0x88, 0x03, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, ++0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, ++0x00, 0x06, 0x00, 0x18, 0x08, 0x60, 0x28, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x64, 0x80, 0x10, 0x01, ++0x42, 0x0A, 0x08, 0x31, 0x20, 0x44, 0x80, 0x10, 0x01, 0x42, 0x0C, 0x08, 0x09, ++0x20, 0x44, 0x80, 0x90, 0x00, 0x42, 0x04, 0x08, 0x11, 0x20, 0x64, 0x80, 0x90, ++0x00, 0x42, 0x02, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0xD4, 0x20, 0x52, 0x81, 0x48, 0x05, 0x22, 0x11, 0x80, 0x54, ++0x20, 0x52, 0x81, 0x48, 0x05, 0x22, 0x15, 0x88, 0x44, 0x00, 0x52, 0x81, 0x48, ++0x04, 0x20, 0x15, 0x88, 0x54, 0x20, 0x52, 0x81, 0x48, 0x0C, 0x20, 0x11, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x30, ++0x00, 0xC8, 0x00, 0x28, 0x03, 0xA0, 0x3C, 0x20, 0x30, 0x00, 0xCA, 0x00, 0x00, ++0x03, 0xA0, 0x0C, 0x80, 0x32, 0x00, 0xCA, 0x00, 0x28, 0x03, 0xA0, 0x0C, 0x80, ++0x32, 0x00, 0xCA, 0x00, 0x28, 0x03, 0xA0, 0x04, 0x00, 0x02, 0x08, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x28, 0x00, 0x08, ++0x00, 0x20, 0x0E, 0x80, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x18, 0x80, ++0x18, 0x00, 0x02, 0x00, 0x88, 0x01, 0x60, 0x00, 0x80, 0x00, 0x00, 0x22, 0x00, ++0x88, 0x01, 0x20, 0x0A, 0x08, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x03, 0x02, 0x40, 0x08, 0x00, 0x01, 0x00, 0x04, 0x20, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, ++0x02, 0x20, 0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0x98, 0x01, 0x20, 0x06, 0x80, ++0x10, 0x00, 0x62, 0x00, 0x88, 0x01, 0x20, 0x06, 0x80, 0x18, 0x00, 0x66, 0x00, ++0x88, 0x01, 0x20, 0x06, 0x80, 0x18, 0x00, 0x66, 0x00, 0x88, 0x01, 0x0C, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x02, 0x40, 0x06, 0x00, ++0x19, 0x00, 0x64, 0x04, 0x80, 0x01, 0x40, 0x06, 0x00, 0x18, 0x00, 0x64, 0x00, ++0x90, 0x11, 0x00, 0x06, 0x00, 0x19, 0x01, 0x60, 0x00, 0x90, 0x01, 0x40, 0x06, ++0x00, 0x19, 0x01, 0x62, 0x00, 0x80, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0xA2, 0x42, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, ++0x08, 0x43, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, 0x43, 0x28, 0x0C, ++0x81, 0x30, 0x04, 0xC2, 0x10, 0x08, 0x43, 0x20, 0x0C, 0x81, 0x30, 0x04, 0xC2, ++0x10, 0x18, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x00, 0x00, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x0C, ++0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, ++0x00, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x04, 0x00, 0x03, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x00, 0x0C, ++0x01, 0x30, 0x04, 0xC0, 0x30, 0x08, 0x43, 0x00, 0x0C, 0x01, 0x30, 0x04, 0xC0, ++0x10, 0x00, 0xC3, 0x20, 0x0C, 0x01, 0x30, 0x0C, 0xC2, 0x10, 0x00, 0x43, 0x00, ++0x0C, 0x01, 0x30, 0x0C, 0xC2, 0x34, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x42, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, ++0x30, 0x88, 0x41, 0x20, 0x06, 0x81, 0x18, 0x04, 0x62, 0x10, 0x88, 0xC1, 0x20, ++0x06, 0x81, 0x18, 0x0C, 0x62, 0x10, 0x88, 0x41, 0x20, 0x06, 0x81, 0x18, 0x0C, ++0x60, 0x10, 0x88, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x80, 0x42, 0x00, 0x04, 0x01, 0x10, 0x04, 0x40, 0x10, 0x00, 0x43, 0x00, ++0x04, 0x01, 0x10, 0x04, 0x40, 0x10, 0x00, 0x41, 0x00, 0x0C, 0x01, 0x10, 0x04, ++0xC0, 0x10, 0x00, 0x41, 0x00, 0x04, 0x01, 0x10, 0x04, 0xC0, 0x10, 0x80, 0x01, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x80, 0x42, 0x20, ++0x06, 0x81, 0x18, 0x04, 0x62, 0x10, 0x08, 0x43, 0x20, 0x06, 0x81, 0x18, 0x04, ++0x62, 0x10, 0x88, 0x41, 0x20, 0x0C, 0x81, 0x18, 0x04, 0xC2, 0x10, 0x88, 0x41, ++0x20, 0x06, 0x81, 0x18, 0x04, 0xC0, 0x30, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x02, 0x20, 0x0A, 0x80, 0x28, 0x00, ++0xA2, 0x00, 0x00, 0x02, 0x20, 0x0A, 0x80, 0x28, 0x00, 0xA2, 0x00, 0x88, 0x02, ++0x00, 0x08, 0x80, 0x28, 0x00, 0x80, 0x00, 0x88, 0x02, 0x20, 0x0A, 0x80, 0x28, ++0x80, 0x80, 0x00, 0x00, 0x42, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x12, 0x00, 0x60, 0x00, 0x82, 0x01, 0x08, 0x06, 0x20, 0x18, 0x80, 0x60, ++0x00, 0x82, 0x01, 0x08, 0x06, 0x20, 0x18, 0x80, 0x60, 0x00, 0x82, 0x01, 0x08, ++0x06, 0x20, 0x18, 0x80, 0x60, 0x00, 0x82, 0x01, 0x08, 0x06, 0x20, 0x18, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x40, ++0x80, 0x00, 0x01, 0x12, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x81, 0x02, ++0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x48, 0x10, 0x20, ++0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x28, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x62, 0xC0, 0x8A, 0x01, 0x2B, ++0x06, 0xAC, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, 0x2B, 0x06, 0xAC, 0x18, 0xB0, ++0x62, 0xC0, 0x8A, 0x01, 0x2B, 0x06, 0xAC, 0x18, 0xB0, 0x62, 0xC0, 0x8A, 0x01, ++0x2B, 0x06, 0xAC, 0x18, 0xB0, 0x02, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x80, 0x62, 0x20, 0x8E, 0x81, 0x38, 0x06, 0xE2, 0x18, 0x98, ++0x63, 0x20, 0x8E, 0x81, 0x38, 0x06, 0xE2, 0x18, 0x88, 0x63, 0x40, 0x8E, 0x81, ++0x38, 0x06, 0xE6, 0x18, 0x88, 0x63, 0x20, 0x8E, 0x81, 0x38, 0x86, 0xE6, 0x18, ++0x88, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, ++0x62, 0x40, 0x8E, 0x01, 0x39, 0x06, 0xE0, 0x18, 0xA0, 0x63, 0x40, 0x8E, 0x01, ++0x39, 0x06, 0xE4, 0x18, 0x90, 0x63, 0x00, 0x8E, 0x01, 0x39, 0x06, 0xE0, 0x18, ++0x90, 0x63, 0x40, 0x8E, 0x01, 0x39, 0x06, 0xE0, 0x18, 0x80, 0x03, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xA2, 0x62, 0xA0, 0x8E, 0x81, ++0x3A, 0x06, 0xE8, 0x18, 0x88, 0x63, 0xA0, 0x8E, 0xA1, 0x3A, 0x06, 0xEA, 0x18, ++0xA8, 0x63, 0x20, 0x8C, 0x81, 0x3A, 0x06, 0xC2, 0x18, 0xA8, 0x63, 0xA0, 0x8E, ++0x81, 0x3A, 0x06, 0xC2, 0x18, 0x18, 0x43, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x00, 0x48, 0x80, 0x04, 0x01, 0x12, 0x04, 0x48, 0x12, ++0x20, 0x4B, 0x80, 0x24, 0x01, 0x12, 0x04, 0x48, 0x12, 0x20, 0x41, 0x80, 0x0E, ++0x01, 0x12, 0x04, 0xE8, 0x10, 0x20, 0x41, 0x80, 0x04, 0x01, 0x12, 0x04, 0xE8, ++0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0x00, 0x60, 0x00, 0x86, 0x01, 0x18, 0x06, 0x60, 0x18, 0x88, 0x61, 0x00, 0x86, ++0x01, 0x18, 0x06, 0x60, 0x18, 0x80, 0x61, 0x20, 0x86, 0x01, 0x18, 0x06, 0x62, ++0x18, 0x80, 0x61, 0x00, 0x86, 0x01, 0x18, 0x06, 0x62, 0x18, 0x00, 0x01, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x06, 0x20, 0x1E, ++0x80, 0x70, 0x00, 0xE2, 0x01, 0x08, 0x07, 0x20, 0x1E, 0x80, 0x70, 0x00, 0xE2, ++0x01, 0x88, 0x07, 0x20, 0x1E, 0x80, 0x78, 0x00, 0xC2, 0x01, 0x88, 0x07, 0x20, ++0x1E, 0x80, 0x78, 0x00, 0xC2, 0x01, 0x88, 0x03, 0x88, 0x0A, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x4A, 0x00, 0x06, 0x01, 0x10, 0x04, 0x60, ++0x12, 0x00, 0x49, 0x00, 0x26, 0x01, 0x10, 0x04, 0x60, 0x12, 0x80, 0x41, 0x00, ++0x06, 0x01, 0x18, 0x04, 0x40, 0x10, 0x80, 0x41, 0x00, 0x06, 0x01, 0x18, 0x04, ++0x40, 0x12, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0x80, 0x42, 0x20, 0x04, 0x81, 0x18, 0x04, 0x42, 0x10, 0x88, 0x41, 0x20, ++0x44, 0x81, 0x18, 0x04, 0x42, 0x10, 0x08, 0x41, 0x20, 0x04, 0x81, 0x10, 0x04, ++0x62, 0x10, 0x08, 0x41, 0x20, 0x04, 0x81, 0x10, 0x04, 0x62, 0x10, 0x08, 0x01, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x42, 0x20, ++0x02, 0x83, 0x28, 0x04, 0x22, 0x30, 0x80, 0x42, 0x20, 0x02, 0x83, 0x28, 0x04, ++0x22, 0x10, 0x88, 0x40, 0x00, 0x02, 0x81, 0x08, 0x0C, 0xA0, 0x10, 0x88, 0x40, ++0x20, 0x02, 0x81, 0x08, 0x0C, 0xA0, 0x10, 0x80, 0x00, 0x88, 0x0A, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x00, 0x0A, 0x03, 0x28, 0x0C, ++0xA0, 0x30, 0x80, 0xC2, 0x00, 0x4A, 0x01, 0x28, 0x0C, 0xA0, 0x30, 0x80, 0xC2, ++0x00, 0x0A, 0x03, 0x28, 0x0C, 0xA0, 0x30, 0x80, 0xC2, 0x00, 0x0A, 0x03, 0x28, ++0x0C, 0xA0, 0x10, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0x00, 0x10, 0x00, 0x06, 0x00, 0x08, 0x01, 0x20, 0x00, 0x80, 0x10, ++0x00, 0x02, 0x00, 0x08, 0x01, 0x20, 0x04, 0x80, 0x10, 0x00, 0x42, 0x00, 0x08, ++0x00, 0x20, 0x04, 0x80, 0x10, 0x00, 0x42, 0x00, 0x08, 0x00, 0x20, 0x04, 0x88, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, 0x42, ++0x40, 0x40, 0x01, 0x01, 0x04, 0x00, 0x14, 0x10, 0x40, 0x40, 0x00, 0x01, 0x01, ++0x04, 0x04, 0x10, 0x10, 0x40, 0x40, 0x00, 0x01, 0x01, 0x05, 0x04, 0x10, 0x10, ++0x40, 0x40, 0x00, 0x01, 0x01, 0x05, 0x04, 0x10, 0x10, 0x00, 0x88, 0x0A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x02, 0x20, 0x06, 0x80, 0x18, ++0x00, 0x66, 0x00, 0x98, 0x01, 0x20, 0x06, 0x80, 0x18, 0x00, 0x62, 0x00, 0x88, ++0x01, 0x60, 0x06, 0x80, 0x18, 0x00, 0x66, 0x00, 0x88, 0x01, 0x20, 0x06, 0x80, ++0x18, 0x00, 0x66, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x02, 0x80, 0x02, 0x40, 0x26, 0x00, 0x99, 0x00, 0x64, 0x02, 0x80, ++0x0B, 0x40, 0x26, 0x00, 0x99, 0x00, 0x64, 0x00, 0x90, 0x01, 0x00, 0x0E, 0x00, ++0x98, 0x00, 0xE0, 0x00, 0x90, 0x01, 0x40, 0x06, 0x80, 0x99, 0x00, 0xE0, 0x00, ++0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xA2, ++0x06, 0x20, 0x1C, 0x80, 0x70, 0x00, 0xC2, 0x01, 0x88, 0x05, 0x20, 0x1C, 0x82, ++0x70, 0x00, 0xC2, 0x01, 0x08, 0x07, 0x20, 0x16, 0x00, 0x70, 0x00, 0x62, 0x01, ++0x08, 0x07, 0x28, 0x1C, 0x00, 0x70, 0x00, 0x62, 0x01, 0x18, 0x01, 0x88, 0x0A, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x80, 0x00, 0x0C, 0x02, ++0x30, 0x0E, 0xC0, 0x20, 0x00, 0xE1, 0x00, 0x0C, 0x02, 0x30, 0x0A, 0xC0, 0x20, ++0x00, 0x83, 0x00, 0x04, 0x02, 0x30, 0x08, 0x40, 0x20, 0x00, 0x83, 0x00, 0x0C, ++0x02, 0x30, 0x0A, 0x40, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0xAC, 0x02, 0xB0, 0x0A, 0xC0, 0x2A, ++0x08, 0xAB, 0x00, 0xAC, 0x02, 0xB0, 0x0A, 0xC0, 0x28, 0x00, 0xA3, 0x20, 0x8C, ++0x02, 0xB0, 0x0A, 0xC2, 0x28, 0x00, 0xA3, 0x00, 0x8C, 0x82, 0xB0, 0x1E, 0xC2, ++0x08, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, ++0xA2, 0xC2, 0x20, 0x06, 0x83, 0x18, 0x0E, 0x62, 0x30, 0x88, 0xE1, 0x20, 0x06, ++0x83, 0x18, 0x0E, 0x62, 0x30, 0x88, 0xC1, 0x20, 0x06, 0x83, 0x18, 0x0C, 0x62, ++0x30, 0x88, 0xC1, 0x20, 0x06, 0x03, 0x18, 0x1E, 0x62, 0x30, 0x88, 0x01, 0x88, ++0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x02, 0x00, 0x44, ++0x00, 0x10, 0x00, 0x40, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x08, 0x40, ++0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0x01, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x12, 0x22, 0x06, 0x88, 0x18, 0x01, 0x62, ++0x80, 0x88, 0x11, 0x20, 0x06, 0x88, 0x18, 0x01, 0x62, 0x84, 0x88, 0x11, 0x22, ++0x46, 0x88, 0x18, 0x20, 0x62, 0x84, 0x88, 0x11, 0x22, 0x46, 0x08, 0x18, 0x40, ++0x62, 0x84, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x02, 0xA2, 0x02, 0x22, 0x0A, 0x88, 0x28, 0x20, 0xA2, 0x00, 0x80, 0x02, 0x20, ++0x0A, 0x88, 0x28, 0x20, 0xA2, 0x00, 0x88, 0x02, 0x02, 0x0A, 0x88, 0x28, 0x20, ++0xA0, 0x80, 0x88, 0x02, 0x22, 0x0A, 0x08, 0x28, 0x20, 0xA0, 0x40, 0x80, 0x02, ++0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x04, ++0x42, 0x00, 0x28, 0x41, 0x20, 0x04, 0x81, 0x12, 0x04, 0x42, 0x10, 0x0A, 0x41, ++0x20, 0x04, 0x81, 0x10, 0x04, 0x42, 0x10, 0x08, 0x41, 0xA0, 0x04, 0x81, 0x10, ++0x04, 0x42, 0x00, 0x08, 0x00, 0xA0, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x80, 0x40, 0x01, 0x00, 0x05, ++0x08, 0x14, 0x00, 0x50, 0x80, 0x40, 0x01, 0x00, 0x05, 0x08, 0x14, 0x20, 0x50, ++0x80, 0x40, 0x01, 0x02, 0x05, 0x00, 0x14, 0x20, 0x50, 0x80, 0x40, 0x01, 0x02, ++0x6D, 0x00, 0x94, 0x28, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x02, 0xA2, 0xB2, 0xC0, 0xCA, 0x02, 0x21, 0x0B, 0xAC, 0x2C, 0x10, 0xB2, ++0xC0, 0xCA, 0x02, 0x23, 0x0B, 0xAC, 0x2C, 0xB0, 0xB2, 0xC0, 0xCA, 0x02, 0x2A, ++0x0B, 0x84, 0x2C, 0xB0, 0xB2, 0xC0, 0xCA, 0x02, 0x2A, 0x2B, 0x84, 0x6C, 0xB0, ++0x02, 0x88, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x12, ++0x20, 0x4E, 0x80, 0x38, 0x01, 0xE2, 0x04, 0x98, 0x13, 0x20, 0x4E, 0x80, 0x38, ++0x01, 0xE2, 0x04, 0x80, 0x13, 0x60, 0x4E, 0x80, 0x39, 0x01, 0xE6, 0x04, 0x88, ++0x13, 0x20, 0x4E, 0x80, 0x38, 0x09, 0xE6, 0x00, 0x89, 0x03, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x10, 0x02, 0x23, 0x08, ++0x8C, 0x21, 0x30, 0x80, 0xC0, 0x10, 0x02, 0x43, 0x08, 0x8C, 0x21, 0x31, 0x84, ++0xC4, 0x08, 0x12, 0x63, 0x08, 0x8C, 0x20, 0x31, 0x86, 0xC4, 0x18, 0x12, 0x23, ++0x08, 0x8C, 0x20, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, ++0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, ++0xCB, 0xFF, 0x2F, 0xFF, 0xBF, 0xFC, 0xFF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFF, ++0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0xDB, 0xD0, 0xEC, ++0xCB, 0xB7, 0x0D, 0xED, 0x37, 0xFC, 0xDF, 0xD0, 0x6C, 0xC3, 0xB7, 0x0D, 0xED, ++0x37, 0x34, 0xDB, 0xD0, 0x6C, 0x43, 0xB3, 0x0D, 0xCD, 0x36, 0x34, 0xDB, 0xD0, ++0xEC, 0xCB, 0xB7, 0x2F, 0xED, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x3C, 0x32, 0xF3, 0xCB, 0xCF, 0x23, 0xF3, ++0x8F, 0xFC, 0x3F, 0x32, 0xF3, 0xC8, 0xCF, 0x23, 0xF3, 0x8F, 0xCC, 0x3C, 0x32, ++0xF3, 0xC8, 0xCC, 0x23, 0x33, 0x8F, 0xCC, 0x3C, 0x32, 0xF3, 0xCB, 0xCF, 0x2F, ++0xF3, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xDC, 0x78, 0x12, 0xFB, 0xC9, 0xED, 0x27, 0xB1, 0x87, 0xDC, 0x7E, 0x12, ++0xE3, 0xC9, 0xED, 0x27, 0xB7, 0x9F, 0xDC, 0x1E, 0x72, 0xFB, 0x49, 0xEC, 0x21, ++0xB7, 0x9F, 0xDC, 0x7E, 0x72, 0xFB, 0x49, 0xEC, 0x21, 0x37, 0x86, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x21, 0x00, ++0x85, 0x33, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0xCE, ++0x50, 0x30, 0x43, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, 0x50, 0x38, 0x43, 0xE1, ++0x0C, 0x85, 0x00, 0x14, 0xCE, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, ++0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, ++0x00, 0x80, 0x00, 0x00, 0x02, 0x04, 0x08, 0x00, 0x20, 0x40, 0x80, 0x00, 0x00, ++0x02, 0x00, 0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x21, 0x40, 0x84, 0x00, 0x11, 0x02, 0x44, 0x08, 0x10, 0x21, ++0x40, 0x84, 0x00, 0x11, 0x02, 0x44, 0x08, 0x10, 0x21, 0x40, 0x84, 0x00, 0x11, ++0x02, 0x44, 0x08, 0x10, 0x21, 0x40, 0x84, 0x00, 0x11, 0x02, 0x44, 0x18, 0x02, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, ++0x00, 0x80, 0x33, 0x00, 0x02, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, ++0xCE, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x02, 0x00, 0x38, 0x03, ++0xE0, 0x4C, 0x80, 0x00, 0x01, 0xCE, 0x00, 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0xCC, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x33, 0x10, 0x00, 0x40, 0x30, 0x03, ++0x01, 0x00, 0x04, 0x33, 0x10, 0xCC, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0xCC, 0x40, 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, ++0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, ++0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, ++0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, ++0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x01, 0xCC, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x33, 0x01, 0x00, 0x04, 0x30, ++0x13, 0x00, 0x40, 0x00, 0x33, 0x01, 0xCC, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, ++0x00, 0x01, 0xCC, 0x04, 0x30, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x00, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x38, ++0x53, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, 0x40, 0x85, ++0x33, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x00, 0x54, ++0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x86, 0x04, 0x08, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x21, 0x00, 0x84, ++0x00, 0x10, 0x02, 0x40, 0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, ++0x08, 0x00, 0x21, 0x00, 0x04, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, ++0x84, 0x00, 0x10, 0x86, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0xE0, 0x0C, 0x80, 0x00, 0x00, 0xCE, 0x00, ++0x08, 0x00, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, 0xE0, 0x0C, ++0x80, 0x00, 0x00, 0xCE, 0x00, 0x08, 0x00, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, ++0x00, 0x08, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, ++0x84, 0x33, 0x10, 0x02, 0x40, 0x38, 0x03, 0x21, 0x00, 0x84, 0x33, 0x10, 0xCE, ++0x40, 0x38, 0x03, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x40, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, ++0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x81, 0x00, 0x04, 0x00, ++0x10, 0x08, 0x40, 0x00, 0x00, 0x81, 0x00, 0x04, 0x02, 0x10, 0x08, 0x40, 0x00, ++0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x84, 0x00, 0x10, 0x00, 0x40, 0x08, 0x00, 0x01, ++0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x00, 0x33, 0x00, ++0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, ++0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, ++0x00, 0x85, 0x00, 0x14, 0x02, 0x50, 0x08, 0x40, 0x21, 0x00, 0x85, 0x00, 0x14, ++0x02, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, ++0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x01, ++0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, ++0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x10, 0x21, 0x40, 0x84, 0x00, 0x11, ++0x02, 0x44, 0x08, 0x10, 0x21, 0x40, 0x84, 0x00, 0x11, 0x02, 0x44, 0x08, 0x10, ++0x21, 0x40, 0x84, 0x00, 0x11, 0x02, 0x44, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, ++0x02, 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, ++0x20, 0x00, 0x80, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, ++0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, ++0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x00, 0x04, 0x00, ++0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, ++0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, ++0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, ++0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, ++0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, ++0x10, 0x01, 0x40, 0x04, 0x00, 0x11, 0x00, 0x44, 0x00, 0x10, 0x01, 0x40, 0x04, ++0x00, 0x11, 0x00, 0x44, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, ++0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, ++0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ++0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, 0x40, 0x85, ++0x00, 0x15, 0x02, 0x54, 0x08, 0x50, 0x21, 0x40, 0x85, 0x33, 0x15, 0x02, 0x54, ++0x08, 0x50, 0x21, 0x40, 0x85, 0x00, 0x15, 0x02, 0x54, 0x08, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x80, ++0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, ++0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, ++0x80, 0x00, 0x01, 0x02, 0x04, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, ++0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, ++0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, ++0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, ++0x08, 0x00, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0x02, 0x00, 0x38, 0x03, 0x20, 0x00, ++0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x03, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, ++0x00, 0x38, 0x03, 0xE0, 0x0C, 0x80, 0x33, 0x00, 0xCE, 0x00, 0x38, 0x43, 0x20, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x21, 0x00, ++0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, ++0x40, 0x08, 0x00, 0x21, 0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x00, 0x21, ++0x00, 0x84, 0x00, 0x10, 0x02, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, ++0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, ++0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, ++0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, ++0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, ++0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, ++0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, ++0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, ++0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, ++0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x80, ++0x40, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xC2, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x80, 0x40, ++0x40, 0x00, 0x00, 0x0C, 0x00, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, ++0x00, 0x80, 0x00, 0x00, 0xA4, 0x07, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, ++0xC0, 0x0C, 0x00, 0x02, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0xA0, 0x0C, 0x00, 0x05, 0x80, ++0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x80, 0x00, 0x00, 0x87, 0x5A, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00 ++}; +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0009-Staging-add-me4000-pci-data-collection-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0009-Staging-add-me4000-pci-data-collection-driver.patch new file mode 100644 index 000000000..08ad39efb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0009-Staging-add-me4000-pci-data-collection-driver.patch @@ -0,0 +1,7198 @@ +From c0f005888c6663898a040cd922947dd8caa55160 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 21 Mar 2008 14:12:51 -0700 +Subject: [PATCH 09/23] Staging: add me4000 pci data collection driver +Patch-mainline: 2.6.28 + +Originally written by Guenter Gebhardt + +TODO: + - checkpatch.pl cleanups + - sparse cleanups + - possible /proc interaction cleanups + - more info needed for Kconfig entry + - real device id? + - module parameter cleanup + +Cc: Wolfgang Beiter +Cc: Guenter Gebhardt +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/me4000/Kconfig | 10 + + drivers/staging/me4000/Makefile | 1 + + drivers/staging/me4000/README | 13 + + drivers/staging/me4000/me4000.c | 6133 +++++++++++++++++++++++++++++++++++++++ + drivers/staging/me4000/me4000.h | 954 ++++++ + 7 files changed, 7114 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/me4000/Kconfig + create mode 100644 drivers/staging/me4000/Makefile + create mode 100644 drivers/staging/me4000/README + create mode 100644 drivers/staging/me4000/me4000.c + create mode 100644 drivers/staging/me4000/me4000.h + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 6da7662..56c73bc 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -29,4 +29,6 @@ source "drivers/staging/slicoss/Kconfig" + + source "drivers/staging/sxg/Kconfig" + ++source "drivers/staging/me4000/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index cd6d6a5..97df19b 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -3,3 +3,4 @@ + obj-$(CONFIG_ET131X) += et131x/ + obj-$(CONFIG_SLICOSS) += slicoss/ + obj-$(CONFIG_SXG) += sxg/ ++obj-$(CONFIG_ME4000) += me4000/ +diff --git a/drivers/staging/me4000/Kconfig b/drivers/staging/me4000/Kconfig +new file mode 100644 +index 0000000..5e6c9de +--- /dev/null ++++ b/drivers/staging/me4000/Kconfig +@@ -0,0 +1,10 @@ ++config ME4000 ++ tristate "Meilhaus ME-4000 support" ++ default n ++ depends on PCI ++ help ++ This driver supports the Meilhaus ME-4000 family of boards ++ that do data collection and multipurpose I/O. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called me4000. +diff --git a/drivers/staging/me4000/Makefile b/drivers/staging/me4000/Makefile +new file mode 100644 +index 0000000..74487cd +--- /dev/null ++++ b/drivers/staging/me4000/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_ME4000) += me4000.o +diff --git a/drivers/staging/me4000/README b/drivers/staging/me4000/README +new file mode 100644 +index 0000000..bbb8386 +--- /dev/null ++++ b/drivers/staging/me4000/README +@@ -0,0 +1,13 @@ ++ ++TODO: ++ - checkpatch.pl cleanups ++ - sparse cleanups ++ - possible /proc interaction cleanups ++ - more info needed for Kconfig entry ++ - real device id? ++ - module parameter cleanup ++ ++Please send patches to Greg Kroah-Hartman ++and Cc: Wolfgang Beiter and ++Guenter Gebhardt ++ +diff --git a/drivers/staging/me4000/me4000.c b/drivers/staging/me4000/me4000.c +new file mode 100644 +index 0000000..862dd7f +--- /dev/null ++++ b/drivers/staging/me4000/me4000.c +@@ -0,0 +1,6133 @@ ++/* Device driver for Meilhaus ME-4000 board family. ++ * ================================================ ++ * ++ * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de) ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Author: Guenter Gebhardt ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* Include-File for the Meilhaus ME-4000 I/O board */ ++#include "me4000.h" ++#include "me4000_firmware.h" ++#include "me4610_firmware.h" ++ ++/* Administrative stuff for modinfo */ ++MODULE_AUTHOR("Guenter Gebhardt "); ++MODULE_DESCRIPTION ++ ("Device Driver Module for Meilhaus ME-4000 boards version 1.0.5"); ++MODULE_SUPPORTED_DEVICE("Meilhaus ME-4000 Multi I/O boards"); ++MODULE_LICENSE("GPL"); ++ ++/* Board specific data are kept in a global list */ ++LIST_HEAD(me4000_board_info_list); ++ ++/* Major Device Numbers. 0 means to get it automatically from the System */ ++static int me4000_ao_major_driver_no = 0; ++static int me4000_ai_major_driver_no = 0; ++static int me4000_dio_major_driver_no = 0; ++static int me4000_cnt_major_driver_no = 0; ++static int me4000_ext_int_major_driver_no = 0; ++ ++/* Let the user specify a custom major driver number */ ++module_param(me4000_ao_major_driver_no, int, 0); ++MODULE_PARM_DESC(me4000_ao_major_driver_no, ++ "Major driver number for analog output (default 0)"); ++ ++module_param(me4000_ai_major_driver_no, int, 0); ++MODULE_PARM_DESC(me4000_ai_major_driver_no, ++ "Major driver number for analog input (default 0)"); ++ ++module_param(me4000_dio_major_driver_no, int, 0); ++MODULE_PARM_DESC(me4000_dio_major_driver_no, ++ "Major driver number digital I/O (default 0)"); ++ ++module_param(me4000_cnt_major_driver_no, int, 0); ++MODULE_PARM_DESC(me4000_cnt_major_driver_no, ++ "Major driver number for counter (default 0)"); ++ ++module_param(me4000_ext_int_major_driver_no, int, 0); ++MODULE_PARM_DESC(me4000_ext_int_major_driver_no, ++ "Major driver number for external interrupt (default 0)"); ++ ++/*----------------------------------------------------------------------------- ++ Module stuff ++ ---------------------------------------------------------------------------*/ ++int init_module(void); ++void cleanup_module(void); ++ ++/*----------------------------------------------------------------------------- ++ Board detection and initialization ++ ---------------------------------------------------------------------------*/ ++static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id); ++static int me4000_xilinx_download(me4000_info_t *); ++static int me4000_reset_board(me4000_info_t *); ++ ++static void clear_board_info_list(void); ++static int get_registers(struct pci_dev *dev, me4000_info_t * info); ++static int init_board_info(struct pci_dev *dev, me4000_info_t * board_info); ++static int alloc_ao_contexts(me4000_info_t * info); ++static void release_ao_contexts(me4000_info_t * board_info); ++static int alloc_ai_context(me4000_info_t * info); ++static int alloc_dio_context(me4000_info_t * info); ++static int alloc_cnt_context(me4000_info_t * info); ++static int alloc_ext_int_context(me4000_info_t * info); ++ ++/*----------------------------------------------------------------------------- ++ Stuff used by all device parts ++ ---------------------------------------------------------------------------*/ ++static int me4000_open(struct inode *, struct file *); ++static int me4000_release(struct inode *, struct file *); ++ ++static int me4000_get_user_info(me4000_user_info_t *, ++ me4000_info_t * board_info); ++static int me4000_read_procmem(char *, char **, off_t, int, int *, void *); ++ ++/*----------------------------------------------------------------------------- ++ Analog output stuff ++ ---------------------------------------------------------------------------*/ ++static ssize_t me4000_ao_write_sing(struct file *, const char *, size_t, ++ loff_t *); ++static ssize_t me4000_ao_write_wrap(struct file *, const char *, size_t, ++ loff_t *); ++static ssize_t me4000_ao_write_cont(struct file *, const char *, size_t, ++ loff_t *); ++ ++static int me4000_ao_ioctl_sing(struct inode *, struct file *, unsigned int, ++ unsigned long); ++static int me4000_ao_ioctl_wrap(struct inode *, struct file *, unsigned int, ++ unsigned long); ++static int me4000_ao_ioctl_cont(struct inode *, struct file *, unsigned int, ++ unsigned long); ++ ++static unsigned int me4000_ao_poll_cont(struct file *, poll_table *); ++static int me4000_ao_fsync_cont(struct file *, struct dentry *, int); ++ ++static int me4000_ao_start(unsigned long *, me4000_ao_context_t *); ++static int me4000_ao_stop(me4000_ao_context_t *); ++static int me4000_ao_immediate_stop(me4000_ao_context_t *); ++static int me4000_ao_timer_set_divisor(u32 *, me4000_ao_context_t *); ++static int me4000_ao_preload(me4000_ao_context_t *); ++static int me4000_ao_preload_update(me4000_ao_context_t *); ++static int me4000_ao_ex_trig_set_edge(int *, me4000_ao_context_t *); ++static int me4000_ao_ex_trig_enable(me4000_ao_context_t *); ++static int me4000_ao_ex_trig_disable(me4000_ao_context_t *); ++static int me4000_ao_prepare(me4000_ao_context_t * ao_info); ++static int me4000_ao_reset(me4000_ao_context_t * ao_info); ++static int me4000_ao_enable_do(me4000_ao_context_t *); ++static int me4000_ao_disable_do(me4000_ao_context_t *); ++static int me4000_ao_fsm_state(int *, me4000_ao_context_t *); ++ ++static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context); ++static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context); ++static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context); ++static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * channels, ++ me4000_ao_context_t * ao_context); ++ ++static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context); ++static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context); ++static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context); ++ ++static int me4000_ao_ex_trig_timeout(unsigned long *arg, ++ me4000_ao_context_t * ao_context); ++static int me4000_ao_get_free_buffer(unsigned long *arg, ++ me4000_ao_context_t * ao_context); ++ ++/*----------------------------------------------------------------------------- ++ Analog input stuff ++ ---------------------------------------------------------------------------*/ ++static int me4000_ai_single(me4000_ai_single_t *, me4000_ai_context_t *); ++static int me4000_ai_ioctl_sing(struct inode *, struct file *, unsigned int, ++ unsigned long); ++ ++static ssize_t me4000_ai_read(struct file *, char *, size_t, loff_t *); ++static int me4000_ai_ioctl_sw(struct inode *, struct file *, unsigned int, ++ unsigned long); ++static unsigned int me4000_ai_poll(struct file *, poll_table *); ++static int me4000_ai_fasync(int fd, struct file *file_p, int mode); ++ ++static int me4000_ai_ioctl_ext(struct inode *, struct file *, unsigned int, ++ unsigned long); ++ ++static int me4000_ai_prepare(me4000_ai_context_t * ai_context); ++static int me4000_ai_reset(me4000_ai_context_t * ai_context); ++static int me4000_ai_config(me4000_ai_config_t *, me4000_ai_context_t *); ++static int me4000_ai_start(me4000_ai_context_t *); ++static int me4000_ai_start_ex(unsigned long *, me4000_ai_context_t *); ++static int me4000_ai_stop(me4000_ai_context_t *); ++static int me4000_ai_immediate_stop(me4000_ai_context_t *); ++static int me4000_ai_ex_trig_enable(me4000_ai_context_t *); ++static int me4000_ai_ex_trig_disable(me4000_ai_context_t *); ++static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t *, ++ me4000_ai_context_t *); ++static int me4000_ai_sc_setup(me4000_ai_sc_t * arg, ++ me4000_ai_context_t * ai_context); ++static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context); ++static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context); ++static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context); ++static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context); ++static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context); ++static int me4000_ai_get_count_buffer(unsigned long *arg, ++ me4000_ai_context_t * ai_context); ++ ++/*----------------------------------------------------------------------------- ++ EEPROM stuff ++ ---------------------------------------------------------------------------*/ ++static int me4000_eeprom_read(me4000_eeprom_t * arg, ++ me4000_ai_context_t * ai_context); ++static int me4000_eeprom_write(me4000_eeprom_t * arg, ++ me4000_ai_context_t * ai_context); ++static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context, ++ unsigned long cmd, int length); ++static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd, ++ int length); ++ ++/*----------------------------------------------------------------------------- ++ Digital I/O stuff ++ ---------------------------------------------------------------------------*/ ++static int me4000_dio_ioctl(struct inode *, struct file *, unsigned int, ++ unsigned long); ++static int me4000_dio_config(me4000_dio_config_t *, me4000_dio_context_t *); ++static int me4000_dio_get_byte(me4000_dio_byte_t *, me4000_dio_context_t *); ++static int me4000_dio_set_byte(me4000_dio_byte_t *, me4000_dio_context_t *); ++static int me4000_dio_reset(me4000_dio_context_t *); ++ ++/*----------------------------------------------------------------------------- ++ Counter stuff ++ ---------------------------------------------------------------------------*/ ++static int me4000_cnt_ioctl(struct inode *, struct file *, unsigned int, ++ unsigned long); ++static int me4000_cnt_config(me4000_cnt_config_t *, me4000_cnt_context_t *); ++static int me4000_cnt_read(me4000_cnt_t *, me4000_cnt_context_t *); ++static int me4000_cnt_write(me4000_cnt_t *, me4000_cnt_context_t *); ++static int me4000_cnt_reset(me4000_cnt_context_t *); ++ ++/*----------------------------------------------------------------------------- ++ External interrupt routines ++ ---------------------------------------------------------------------------*/ ++static int me4000_ext_int_ioctl(struct inode *, struct file *, unsigned int, ++ unsigned long); ++static int me4000_ext_int_enable(me4000_ext_int_context_t *); ++static int me4000_ext_int_disable(me4000_ext_int_context_t *); ++static int me4000_ext_int_count(unsigned long *arg, ++ me4000_ext_int_context_t * ext_int_context); ++static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode); ++ ++/*----------------------------------------------------------------------------- ++ The interrupt service routines ++ ---------------------------------------------------------------------------*/ ++static irqreturn_t me4000_ao_isr(int, void *); ++static irqreturn_t me4000_ai_isr(int, void *); ++static irqreturn_t me4000_ext_int_isr(int, void *); ++ ++/*----------------------------------------------------------------------------- ++ Inline functions ++ ---------------------------------------------------------------------------*/ ++static int inline me4000_buf_count(me4000_circ_buf_t, int); ++static int inline me4000_buf_space(me4000_circ_buf_t, int); ++static int inline me4000_space_to_end(me4000_circ_buf_t, int); ++static int inline me4000_values_to_end(me4000_circ_buf_t, int); ++ ++static void inline me4000_outb(unsigned char value, unsigned long port); ++static void inline me4000_outl(unsigned long value, unsigned long port); ++static unsigned long inline me4000_inl(unsigned long port); ++static unsigned char inline me4000_inb(unsigned long port); ++ ++static int me4000_buf_count(me4000_circ_buf_t buf, int size) ++{ ++ return ((buf.head - buf.tail) & (size - 1)); ++} ++ ++static int me4000_buf_space(me4000_circ_buf_t buf, int size) ++{ ++ return ((buf.tail - (buf.head + 1)) & (size - 1)); ++} ++ ++static int me4000_values_to_end(me4000_circ_buf_t buf, int size) ++{ ++ int end; ++ int n; ++ end = size - buf.tail; ++ n = (buf.head + end) & (size - 1); ++ return (n < end) ? n : end; ++} ++ ++static int me4000_space_to_end(me4000_circ_buf_t buf, int size) ++{ ++ int end; ++ int n; ++ ++ end = size - 1 - buf.head; ++ n = (end + buf.tail) & (size - 1); ++ return (n <= end) ? n : (end + 1); ++} ++ ++static void me4000_outb(unsigned char value, unsigned long port) ++{ ++ PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port); ++ outb(value, port); ++} ++ ++static void me4000_outl(unsigned long value, unsigned long port) ++{ ++ PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port); ++ outl(value, port); ++} ++ ++static unsigned long me4000_inl(unsigned long port) ++{ ++ unsigned long value; ++ value = inl(port); ++ PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port); ++ return value; ++} ++ ++static unsigned char me4000_inb(unsigned long port) ++{ ++ unsigned char value; ++ value = inb(port); ++ PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port); ++ return value; ++} ++ ++struct pci_driver me4000_driver = { ++ .name = ME4000_NAME, ++ .id_table = me4000_pci_table, ++ .probe = me4000_probe ++}; ++ ++static struct file_operations me4000_ao_fops_sing = { ++ owner:THIS_MODULE, ++ write:me4000_ao_write_sing, ++ ioctl:me4000_ao_ioctl_sing, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_ao_fops_wrap = { ++ owner:THIS_MODULE, ++ write:me4000_ao_write_wrap, ++ ioctl:me4000_ao_ioctl_wrap, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_ao_fops_cont = { ++ owner:THIS_MODULE, ++ write:me4000_ao_write_cont, ++ poll:me4000_ao_poll_cont, ++ ioctl:me4000_ao_ioctl_cont, ++ open:me4000_open, ++ release:me4000_release, ++ fsync:me4000_ao_fsync_cont, ++}; ++ ++static struct file_operations me4000_ai_fops_sing = { ++ owner:THIS_MODULE, ++ ioctl:me4000_ai_ioctl_sing, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_ai_fops_cont_sw = { ++ owner:THIS_MODULE, ++ read:me4000_ai_read, ++ poll:me4000_ai_poll, ++ ioctl:me4000_ai_ioctl_sw, ++ open:me4000_open, ++ release:me4000_release, ++ fasync:me4000_ai_fasync, ++}; ++ ++static struct file_operations me4000_ai_fops_cont_et = { ++ owner:THIS_MODULE, ++ read:me4000_ai_read, ++ poll:me4000_ai_poll, ++ ioctl:me4000_ai_ioctl_ext, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_ai_fops_cont_et_value = { ++ owner:THIS_MODULE, ++ read:me4000_ai_read, ++ poll:me4000_ai_poll, ++ ioctl:me4000_ai_ioctl_ext, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_ai_fops_cont_et_chanlist = { ++ owner:THIS_MODULE, ++ read:me4000_ai_read, ++ poll:me4000_ai_poll, ++ ioctl:me4000_ai_ioctl_ext, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_dio_fops = { ++ owner:THIS_MODULE, ++ ioctl:me4000_dio_ioctl, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_cnt_fops = { ++ owner:THIS_MODULE, ++ ioctl:me4000_cnt_ioctl, ++ open:me4000_open, ++ release:me4000_release, ++}; ++ ++static struct file_operations me4000_ext_int_fops = { ++ owner:THIS_MODULE, ++ ioctl:me4000_ext_int_ioctl, ++ open:me4000_open, ++ release:me4000_release, ++ fasync:me4000_ext_int_fasync, ++}; ++ ++static struct file_operations *me4000_ao_fops_array[] = { ++ &me4000_ao_fops_sing, // single operations ++ &me4000_ao_fops_wrap, // wraparound operations ++ &me4000_ao_fops_cont, // continous operations ++}; ++ ++static struct file_operations *me4000_ai_fops_array[] = { ++ &me4000_ai_fops_sing, // single operations ++ &me4000_ai_fops_cont_sw, // continuous operations with software start ++ &me4000_ai_fops_cont_et, // continous operations with external trigger ++ &me4000_ai_fops_cont_et_value, // sample values by external trigger ++ &me4000_ai_fops_cont_et_chanlist, // work through one channel list by external trigger ++}; ++ ++int __init me4000_init_module(void) ++{ ++ int result = 0; ++ ++ CALL_PDEBUG("init_module() is executed\n"); ++ ++ /* Register driver capabilities */ ++ result = pci_register_driver(&me4000_driver); ++ PDEBUG("init_module():%d devices detected\n", result); ++ if (result < 0) { ++ printk(KERN_ERR "ME4000:init_module():Can't register driver\n"); ++ goto INIT_ERROR_1; ++ } ++ ++ /* Allocate major number for analog output */ ++ result = ++ register_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME, ++ &me4000_ao_fops_sing); ++ if (result < 0) { ++ printk(KERN_ERR "ME4000:init_module():Can't get AO major no\n"); ++ goto INIT_ERROR_2; ++ } else { ++ me4000_ao_major_driver_no = result; ++ } ++ PDEBUG("init_module():Major driver number for AO = %ld\n", ++ me4000_ao_major_driver_no); ++ ++ /* Allocate major number for analog input */ ++ result = ++ register_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME, ++ &me4000_ai_fops_sing); ++ if (result < 0) { ++ printk(KERN_ERR "ME4000:init_module():Can't get AI major no\n"); ++ goto INIT_ERROR_3; ++ } else { ++ me4000_ai_major_driver_no = result; ++ } ++ PDEBUG("init_module():Major driver number for AI = %ld\n", ++ me4000_ai_major_driver_no); ++ ++ /* Allocate major number for digital I/O */ ++ result = ++ register_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME, ++ &me4000_dio_fops); ++ if (result < 0) { ++ printk(KERN_ERR ++ "ME4000:init_module():Can't get DIO major no\n"); ++ goto INIT_ERROR_4; ++ } else { ++ me4000_dio_major_driver_no = result; ++ } ++ PDEBUG("init_module():Major driver number for DIO = %ld\n", ++ me4000_dio_major_driver_no); ++ ++ /* Allocate major number for counter */ ++ result = ++ register_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME, ++ &me4000_cnt_fops); ++ if (result < 0) { ++ printk(KERN_ERR ++ "ME4000:init_module():Can't get CNT major no\n"); ++ goto INIT_ERROR_5; ++ } else { ++ me4000_cnt_major_driver_no = result; ++ } ++ PDEBUG("init_module():Major driver number for CNT = %ld\n", ++ me4000_cnt_major_driver_no); ++ ++ /* Allocate major number for external interrupt */ ++ result = ++ register_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME, ++ &me4000_ext_int_fops); ++ if (result < 0) { ++ printk(KERN_ERR ++ "ME4000:init_module():Can't get major no for external interrupt\n"); ++ goto INIT_ERROR_6; ++ } else { ++ me4000_ext_int_major_driver_no = result; ++ } ++ PDEBUG ++ ("init_module():Major driver number for external interrupt = %ld\n", ++ me4000_ext_int_major_driver_no); ++ ++ /* Create the /proc/me4000 entry */ ++ if (!create_proc_read_entry ++ ("me4000", 0, NULL, me4000_read_procmem, NULL)) { ++ result = -ENODEV; ++ printk(KERN_ERR ++ "ME4000:init_module():Can't create proc entry\n"); ++ goto INIT_ERROR_7; ++ } ++ ++ return 0; ++ ++ INIT_ERROR_7: ++ unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME); ++ ++ INIT_ERROR_6: ++ unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME); ++ ++ INIT_ERROR_5: ++ unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME); ++ ++ INIT_ERROR_4: ++ unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME); ++ ++ INIT_ERROR_3: ++ unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME); ++ ++ INIT_ERROR_2: ++ pci_unregister_driver(&me4000_driver); ++ clear_board_info_list(); ++ ++ INIT_ERROR_1: ++ return result; ++} ++ ++module_init(me4000_init_module); ++ ++static void clear_board_info_list(void) ++{ ++ struct list_head *board_p; ++ struct list_head *dac_p; ++ me4000_info_t *board_info; ++ me4000_ao_context_t *ao_context; ++ ++ /* Clear context lists */ ++ for (board_p = me4000_board_info_list.next; ++ board_p != &me4000_board_info_list; board_p = board_p->next) { ++ board_info = list_entry(board_p, me4000_info_t, list); ++ /* Clear analog output context list */ ++ while (!list_empty(&board_info->ao_context_list)) { ++ dac_p = board_info->ao_context_list.next; ++ ao_context = ++ list_entry(dac_p, me4000_ao_context_t, list); ++ me4000_ao_reset(ao_context); ++ free_irq(ao_context->irq, ao_context); ++ if (ao_context->circ_buf.buf) ++ kfree(ao_context->circ_buf.buf); ++ list_del(dac_p); ++ kfree(ao_context); ++ } ++ ++ /* Clear analog input context */ ++ if (board_info->ai_context->circ_buf.buf) ++ kfree(board_info->ai_context->circ_buf.buf); ++ kfree(board_info->ai_context); ++ ++ /* Clear digital I/O context */ ++ kfree(board_info->dio_context); ++ ++ /* Clear counter context */ ++ kfree(board_info->cnt_context); ++ ++ /* Clear external interrupt context */ ++ kfree(board_info->ext_int_context); ++ } ++ ++ /* Clear the board info list */ ++ while (!list_empty(&me4000_board_info_list)) { ++ board_p = me4000_board_info_list.next; ++ board_info = list_entry(board_p, me4000_info_t, list); ++ pci_release_regions(board_info->pci_dev_p); ++ list_del(board_p); ++ kfree(board_info); ++ } ++} ++ ++static int get_registers(struct pci_dev *dev, me4000_info_t * board_info) ++{ ++ ++ /*--------------------------- plx regbase ---------------------------------*/ ++ ++ board_info->plx_regbase = pci_resource_start(dev, 1); ++ if (board_info->plx_regbase == 0) { ++ printk(KERN_ERR ++ "ME4000:get_registers():PCI base address 1 is not available\n"); ++ return -ENODEV; ++ } ++ board_info->plx_regbase_size = pci_resource_len(dev, 1); ++ ++ PDEBUG ++ ("get_registers():PLX configuration registers at address 0x%4lX [0x%4lX]\n", ++ board_info->plx_regbase, board_info->plx_regbase_size); ++ ++ /*--------------------------- me4000 regbase ------------------------------*/ ++ ++ board_info->me4000_regbase = pci_resource_start(dev, 2); ++ if (board_info->me4000_regbase == 0) { ++ printk(KERN_ERR ++ "ME4000:get_registers():PCI base address 2 is not available\n"); ++ return -ENODEV; ++ } ++ board_info->me4000_regbase_size = pci_resource_len(dev, 2); ++ ++ PDEBUG("get_registers():ME4000 registers at address 0x%4lX [0x%4lX]\n", ++ board_info->me4000_regbase, board_info->me4000_regbase_size); ++ ++ /*--------------------------- timer regbase ------------------------------*/ ++ ++ board_info->timer_regbase = pci_resource_start(dev, 3); ++ if (board_info->timer_regbase == 0) { ++ printk(KERN_ERR ++ "ME4000:get_registers():PCI base address 3 is not available\n"); ++ return -ENODEV; ++ } ++ board_info->timer_regbase_size = pci_resource_len(dev, 3); ++ ++ PDEBUG("get_registers():Timer registers at address 0x%4lX [0x%4lX]\n", ++ board_info->timer_regbase, board_info->timer_regbase_size); ++ ++ /*--------------------------- program regbase ------------------------------*/ ++ ++ board_info->program_regbase = pci_resource_start(dev, 5); ++ if (board_info->program_regbase == 0) { ++ printk(KERN_ERR ++ "get_registers():ME4000:PCI base address 5 is not available\n"); ++ return -ENODEV; ++ } ++ board_info->program_regbase_size = pci_resource_len(dev, 5); ++ ++ PDEBUG("get_registers():Program registers at address 0x%4lX [0x%4lX]\n", ++ board_info->program_regbase, board_info->program_regbase_size); ++ ++ return 0; ++} ++ ++static int init_board_info(struct pci_dev *pci_dev_p, ++ me4000_info_t * board_info) ++{ ++ int i; ++ int result; ++ struct list_head *board_p; ++ board_info->pci_dev_p = pci_dev_p; ++ ++ for (i = 0; i < ME4000_BOARD_VERSIONS; i++) { ++ if (me4000_boards[i].device_id == pci_dev_p->device) { ++ board_info->board_p = &me4000_boards[i]; ++ break; ++ } ++ } ++ if (i == ME4000_BOARD_VERSIONS) { ++ printk(KERN_ERR ++ "ME4000:init_board_info():Device ID not valid\n"); ++ return -ENODEV; ++ } ++ ++ /* Get the index of the board in the global list */ ++ for (board_p = me4000_board_info_list.next, i = 0; ++ board_p != &me4000_board_info_list; board_p = board_p->next, i++) { ++ if (board_p == &board_info->list) { ++ board_info->board_count = i; ++ break; ++ } ++ } ++ if (board_p == &me4000_board_info_list) { ++ printk(KERN_ERR ++ "ME4000:init_board_info():Cannot get index of baord\n"); ++ return -ENODEV; ++ } ++ ++ /* Init list head for analog output contexts */ ++ INIT_LIST_HEAD(&board_info->ao_context_list); ++ ++ /* Init spin locks */ ++ spin_lock_init(&board_info->preload_lock); ++ spin_lock_init(&board_info->ai_ctrl_lock); ++ ++ /* Get the serial number */ ++ result = pci_read_config_dword(pci_dev_p, 0x2C, &board_info->serial_no); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ printk(KERN_WARNING ++ "ME4000:init_board_info: Can't get serial_no\n"); ++ return result; ++ } ++ PDEBUG("init_board_info():serial_no = 0x%x\n", board_info->serial_no); ++ ++ /* Get the hardware revision */ ++ result = ++ pci_read_config_byte(pci_dev_p, 0x08, &board_info->hw_revision); ++ if (result != PCIBIOS_SUCCESSFUL) { ++ printk(KERN_WARNING ++ "ME4000:init_board_info():Can't get hw_revision\n"); ++ return result; ++ } ++ PDEBUG("init_board_info():hw_revision = 0x%x\n", ++ board_info->hw_revision); ++ ++ /* Get the vendor id */ ++ board_info->vendor_id = pci_dev_p->vendor; ++ PDEBUG("init_board_info():vendor_id = 0x%x\n", board_info->vendor_id); ++ ++ /* Get the device id */ ++ board_info->device_id = pci_dev_p->device; ++ PDEBUG("init_board_info():device_id = 0x%x\n", board_info->device_id); ++ ++ /* Get the pci device number */ ++ board_info->pci_dev_no = PCI_FUNC(pci_dev_p->devfn); ++ PDEBUG("init_board_info():pci_func_no = 0x%x\n", ++ board_info->pci_func_no); ++ ++ /* Get the pci slot number */ ++ board_info->pci_dev_no = PCI_SLOT(pci_dev_p->devfn); ++ PDEBUG("init_board_info():pci_dev_no = 0x%x\n", board_info->pci_dev_no); ++ ++ /* Get the pci bus number */ ++ board_info->pci_bus_no = pci_dev_p->bus->number; ++ PDEBUG("init_board_info():pci_bus_no = 0x%x\n", board_info->pci_bus_no); ++ ++ /* Get the irq assigned to the board */ ++ board_info->irq = pci_dev_p->irq; ++ PDEBUG("init_board_info():irq = %d\n", board_info->irq); ++ ++ return 0; ++} ++ ++static int alloc_ao_contexts(me4000_info_t * info) ++{ ++ int i; ++ int err; ++ me4000_ao_context_t *ao_context; ++ ++ for (i = 0; i < info->board_p->ao.count; i++) { ++ ao_context = kmalloc(sizeof(me4000_ao_context_t), GFP_KERNEL); ++ if (!ao_context) { ++ printk(KERN_ERR ++ "alloc_ao_contexts():Can't get memory for ao context\n"); ++ release_ao_contexts(info); ++ return -ENOMEM; ++ } ++ memset(ao_context, 0, sizeof(me4000_ao_context_t)); ++ ++ spin_lock_init(&ao_context->use_lock); ++ spin_lock_init(&ao_context->int_lock); ++ ao_context->irq = info->irq; ++ init_waitqueue_head(&ao_context->wait_queue); ++ ao_context->board_info = info; ++ ++ if (info->board_p->ao.fifo_count) { ++ /* Allocate circular buffer */ ++ ao_context->circ_buf.buf = ++ kmalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL); ++ if (!ao_context->circ_buf.buf) { ++ printk(KERN_ERR ++ "alloc_ao_contexts():Can't get circular buffer\n"); ++ release_ao_contexts(info); ++ return -ENOMEM; ++ } ++ memset(ao_context->circ_buf.buf, 0, ++ ME4000_AO_BUFFER_SIZE); ++ ++ /* Clear the circular buffer */ ++ ao_context->circ_buf.head = 0; ++ ao_context->circ_buf.tail = 0; ++ } ++ ++ switch (i) { ++ case 0: ++ ao_context->ctrl_reg = ++ info->me4000_regbase + ME4000_AO_00_CTRL_REG; ++ ao_context->status_reg = ++ info->me4000_regbase + ME4000_AO_00_STATUS_REG; ++ ao_context->fifo_reg = ++ info->me4000_regbase + ME4000_AO_00_FIFO_REG; ++ ao_context->single_reg = ++ info->me4000_regbase + ME4000_AO_00_SINGLE_REG; ++ ao_context->timer_reg = ++ info->me4000_regbase + ME4000_AO_00_TIMER_REG; ++ ao_context->irq_status_reg = ++ info->me4000_regbase + ME4000_IRQ_STATUS_REG; ++ ao_context->preload_reg = ++ info->me4000_regbase + ME4000_AO_LOADSETREG_XX; ++ break; ++ case 1: ++ ao_context->ctrl_reg = ++ info->me4000_regbase + ME4000_AO_01_CTRL_REG; ++ ao_context->status_reg = ++ info->me4000_regbase + ME4000_AO_01_STATUS_REG; ++ ao_context->fifo_reg = ++ info->me4000_regbase + ME4000_AO_01_FIFO_REG; ++ ao_context->single_reg = ++ info->me4000_regbase + ME4000_AO_01_SINGLE_REG; ++ ao_context->timer_reg = ++ info->me4000_regbase + ME4000_AO_01_TIMER_REG; ++ ao_context->irq_status_reg = ++ info->me4000_regbase + ME4000_IRQ_STATUS_REG; ++ ao_context->preload_reg = ++ info->me4000_regbase + ME4000_AO_LOADSETREG_XX; ++ break; ++ case 2: ++ ao_context->ctrl_reg = ++ info->me4000_regbase + ME4000_AO_02_CTRL_REG; ++ ao_context->status_reg = ++ info->me4000_regbase + ME4000_AO_02_STATUS_REG; ++ ao_context->fifo_reg = ++ info->me4000_regbase + ME4000_AO_02_FIFO_REG; ++ ao_context->single_reg = ++ info->me4000_regbase + ME4000_AO_02_SINGLE_REG; ++ ao_context->timer_reg = ++ info->me4000_regbase + ME4000_AO_02_TIMER_REG; ++ ao_context->irq_status_reg = ++ info->me4000_regbase + ME4000_IRQ_STATUS_REG; ++ ao_context->preload_reg = ++ info->me4000_regbase + ME4000_AO_LOADSETREG_XX; ++ break; ++ case 3: ++ ao_context->ctrl_reg = ++ info->me4000_regbase + ME4000_AO_03_CTRL_REG; ++ ao_context->status_reg = ++ info->me4000_regbase + ME4000_AO_03_STATUS_REG; ++ ao_context->fifo_reg = ++ info->me4000_regbase + ME4000_AO_03_FIFO_REG; ++ ao_context->single_reg = ++ info->me4000_regbase + ME4000_AO_03_SINGLE_REG; ++ ao_context->timer_reg = ++ info->me4000_regbase + ME4000_AO_03_TIMER_REG; ++ ao_context->irq_status_reg = ++ info->me4000_regbase + ME4000_IRQ_STATUS_REG; ++ ao_context->preload_reg = ++ info->me4000_regbase + ME4000_AO_LOADSETREG_XX; ++ break; ++ default: ++ break; ++ } ++ ++ if (info->board_p->ao.fifo_count) { ++ /* Request the interrupt line */ ++ err = ++ request_irq(ao_context->irq, me4000_ao_isr, ++ IRQF_DISABLED | IRQF_SHARED, ++ ME4000_NAME, ao_context); ++ if (err) { ++ printk(KERN_ERR ++ "alloc_ao_contexts():Can't get interrupt line"); ++ if (ao_context->circ_buf.buf) ++ kfree(ao_context->circ_buf.buf); ++ kfree(ao_context); ++ release_ao_contexts(info); ++ return -ENODEV; ++ } ++ } ++ ++ list_add_tail(&ao_context->list, &info->ao_context_list); ++ ao_context->index = i; ++ } ++ ++ return 0; ++} ++ ++static void release_ao_contexts(me4000_info_t * board_info) ++{ ++ struct list_head *dac_p; ++ me4000_ao_context_t *ao_context; ++ ++ /* Clear analog output context list */ ++ while (!list_empty(&board_info->ao_context_list)) { ++ dac_p = board_info->ao_context_list.next; ++ ao_context = list_entry(dac_p, me4000_ao_context_t, list); ++ free_irq(ao_context->irq, ao_context); ++ if (ao_context->circ_buf.buf) ++ kfree(ao_context->circ_buf.buf); ++ list_del(dac_p); ++ kfree(ao_context); ++ } ++} ++ ++static int alloc_ai_context(me4000_info_t * info) ++{ ++ me4000_ai_context_t *ai_context; ++ ++ if (info->board_p->ai.count) { ++ ai_context = kmalloc(sizeof(me4000_ai_context_t), GFP_KERNEL); ++ if (!ai_context) { ++ printk(KERN_ERR ++ "ME4000:alloc_ai_context():Can't get memory for ai context\n"); ++ return -ENOMEM; ++ } ++ memset(ai_context, 0, sizeof(me4000_ai_context_t)); ++ ++ info->ai_context = ai_context; ++ ++ spin_lock_init(&ai_context->use_lock); ++ spin_lock_init(&ai_context->int_lock); ++ ai_context->number = 0; ++ ai_context->irq = info->irq; ++ init_waitqueue_head(&ai_context->wait_queue); ++ ai_context->board_info = info; ++ ++ ai_context->ctrl_reg = ++ info->me4000_regbase + ME4000_AI_CTRL_REG; ++ ai_context->status_reg = ++ info->me4000_regbase + ME4000_AI_STATUS_REG; ++ ai_context->channel_list_reg = ++ info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG; ++ ai_context->data_reg = ++ info->me4000_regbase + ME4000_AI_DATA_REG; ++ ai_context->chan_timer_reg = ++ info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG; ++ ai_context->chan_pre_timer_reg = ++ info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG; ++ ai_context->scan_timer_low_reg = ++ info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG; ++ ai_context->scan_timer_high_reg = ++ info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG; ++ ai_context->scan_pre_timer_low_reg = ++ info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG; ++ ai_context->scan_pre_timer_high_reg = ++ info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG; ++ ai_context->start_reg = ++ info->me4000_regbase + ME4000_AI_START_REG; ++ ai_context->irq_status_reg = ++ info->me4000_regbase + ME4000_IRQ_STATUS_REG; ++ ai_context->sample_counter_reg = ++ info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG; ++ } ++ ++ return 0; ++} ++ ++static int alloc_dio_context(me4000_info_t * info) ++{ ++ me4000_dio_context_t *dio_context; ++ ++ if (info->board_p->dio.count) { ++ dio_context = kmalloc(sizeof(me4000_dio_context_t), GFP_KERNEL); ++ if (!dio_context) { ++ printk(KERN_ERR ++ "ME4000:alloc_dio_context():Can't get memory for dio context\n"); ++ return -ENOMEM; ++ } ++ memset(dio_context, 0, sizeof(me4000_dio_context_t)); ++ ++ info->dio_context = dio_context; ++ ++ spin_lock_init(&dio_context->use_lock); ++ dio_context->board_info = info; ++ ++ dio_context->dio_count = info->board_p->dio.count; ++ ++ dio_context->dir_reg = ++ info->me4000_regbase + ME4000_DIO_DIR_REG; ++ dio_context->ctrl_reg = ++ info->me4000_regbase + ME4000_DIO_CTRL_REG; ++ dio_context->port_0_reg = ++ info->me4000_regbase + ME4000_DIO_PORT_0_REG; ++ dio_context->port_1_reg = ++ info->me4000_regbase + ME4000_DIO_PORT_1_REG; ++ dio_context->port_2_reg = ++ info->me4000_regbase + ME4000_DIO_PORT_2_REG; ++ dio_context->port_3_reg = ++ info->me4000_regbase + ME4000_DIO_PORT_3_REG; ++ } ++ ++ return 0; ++} ++ ++static int alloc_cnt_context(me4000_info_t * info) ++{ ++ me4000_cnt_context_t *cnt_context; ++ ++ if (info->board_p->cnt.count) { ++ cnt_context = kmalloc(sizeof(me4000_cnt_context_t), GFP_KERNEL); ++ if (!cnt_context) { ++ printk(KERN_ERR ++ "ME4000:alloc_cnt_context():Can't get memory for cnt context\n"); ++ return -ENOMEM; ++ } ++ memset(cnt_context, 0, sizeof(me4000_cnt_context_t)); ++ ++ info->cnt_context = cnt_context; ++ ++ spin_lock_init(&cnt_context->use_lock); ++ cnt_context->board_info = info; ++ ++ cnt_context->ctrl_reg = ++ info->timer_regbase + ME4000_CNT_CTRL_REG; ++ cnt_context->counter_0_reg = ++ info->timer_regbase + ME4000_CNT_COUNTER_0_REG; ++ cnt_context->counter_1_reg = ++ info->timer_regbase + ME4000_CNT_COUNTER_1_REG; ++ cnt_context->counter_2_reg = ++ info->timer_regbase + ME4000_CNT_COUNTER_2_REG; ++ } ++ ++ return 0; ++} ++ ++static int alloc_ext_int_context(me4000_info_t * info) ++{ ++ me4000_ext_int_context_t *ext_int_context; ++ ++ if (info->board_p->cnt.count) { ++ ext_int_context = ++ kmalloc(sizeof(me4000_ext_int_context_t), GFP_KERNEL); ++ if (!ext_int_context) { ++ printk(KERN_ERR ++ "ME4000:alloc_ext_int_context():Can't get memory for cnt context\n"); ++ return -ENOMEM; ++ } ++ memset(ext_int_context, 0, sizeof(me4000_ext_int_context_t)); ++ ++ info->ext_int_context = ext_int_context; ++ ++ spin_lock_init(&ext_int_context->use_lock); ++ ext_int_context->board_info = info; ++ ++ ext_int_context->fasync_ptr = NULL; ++ ext_int_context->irq = info->irq; ++ ++ ext_int_context->ctrl_reg = ++ info->me4000_regbase + ME4000_AI_CTRL_REG; ++ ext_int_context->irq_status_reg = ++ info->me4000_regbase + ME4000_IRQ_STATUS_REG; ++ } ++ ++ return 0; ++} ++ ++static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id) ++{ ++ int result = 0; ++ me4000_info_t *board_info; ++ ++ CALL_PDEBUG("me4000_probe() is executed\n"); ++ ++ /* Allocate structure for board context */ ++ board_info = kmalloc(sizeof(me4000_info_t), GFP_KERNEL); ++ if (!board_info) { ++ printk(KERN_ERR ++ "ME4000:Can't get memory for board info structure\n"); ++ result = -ENOMEM; ++ goto PROBE_ERROR_1; ++ } ++ memset(board_info, 0, sizeof(me4000_info_t)); ++ ++ /* Add to global linked list */ ++ list_add_tail(&board_info->list, &me4000_board_info_list); ++ ++ /* Get the PCI base registers */ ++ result = get_registers(dev, board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe():Cannot get registers\n"); ++ goto PROBE_ERROR_2; ++ } ++ ++ /* Enable the device */ ++ result = pci_enable_device(dev); ++ if (result < 0) { ++ printk(KERN_ERR "me4000_probe():Cannot enable PCI device\n"); ++ goto PROBE_ERROR_2; ++ } ++ ++ /* Request the PCI register regions */ ++ result = pci_request_regions(dev, ME4000_NAME); ++ if (result < 0) { ++ printk(KERN_ERR "me4000_probe():Cannot request I/O regions\n"); ++ goto PROBE_ERROR_2; ++ } ++ ++ /* Initialize board info */ ++ result = init_board_info(dev, board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe():Cannot init baord info\n"); ++ goto PROBE_ERROR_3; ++ } ++ ++ /* Download the xilinx firmware */ ++ result = me4000_xilinx_download(board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe:Can't download firmware\n"); ++ goto PROBE_ERROR_3; ++ } ++ ++ /* Make a hardware reset */ ++ result = me4000_reset_board(board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe:Can't reset board\n"); ++ goto PROBE_ERROR_3; ++ } ++ ++ /* Allocate analog output context structures */ ++ result = alloc_ao_contexts(board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe():Cannot allocate ao contexts\n"); ++ goto PROBE_ERROR_3; ++ } ++ ++ /* Allocate analog input context */ ++ result = alloc_ai_context(board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe():Cannot allocate ai context\n"); ++ goto PROBE_ERROR_4; ++ } ++ ++ /* Allocate digital I/O context */ ++ result = alloc_dio_context(board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe():Cannot allocate dio context\n"); ++ goto PROBE_ERROR_5; ++ } ++ ++ /* Allocate counter context */ ++ result = alloc_cnt_context(board_info); ++ if (result) { ++ printk(KERN_ERR "me4000_probe():Cannot allocate cnt context\n"); ++ goto PROBE_ERROR_6; ++ } ++ ++ /* Allocate external interrupt context */ ++ result = alloc_ext_int_context(board_info); ++ if (result) { ++ printk(KERN_ERR ++ "me4000_probe():Cannot allocate ext_int context\n"); ++ goto PROBE_ERROR_7; ++ } ++ ++ return 0; ++ ++ PROBE_ERROR_7: ++ kfree(board_info->cnt_context); ++ ++ PROBE_ERROR_6: ++ kfree(board_info->dio_context); ++ ++ PROBE_ERROR_5: ++ kfree(board_info->ai_context); ++ ++ PROBE_ERROR_4: ++ release_ao_contexts(board_info); ++ ++ PROBE_ERROR_3: ++ pci_release_regions(dev); ++ ++ PROBE_ERROR_2: ++ list_del(&board_info->list); ++ kfree(board_info); ++ ++ PROBE_ERROR_1: ++ return result; ++} ++ ++static int me4000_xilinx_download(me4000_info_t * info) ++{ ++ int size = 0; ++ u32 value = 0; ++ int idx = 0; ++ unsigned char *firm; ++ wait_queue_head_t queue; ++ ++ CALL_PDEBUG("me4000_xilinx_download() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ firm = (info->device_id == 0x4610) ? xilinx_firm_4610 : xilinx_firm; ++ ++ /* ++ * Set PLX local interrupt 2 polarity to high. ++ * Interrupt is thrown by init pin of xilinx. ++ */ ++ outl(0x10, info->plx_regbase + PLX_INTCSR); ++ ++ /* Set /CS and /WRITE of the Xilinx */ ++ value = inl(info->plx_regbase + PLX_ICR); ++ value |= 0x100; ++ outl(value, info->plx_regbase + PLX_ICR); ++ ++ /* Init Xilinx with CS1 */ ++ inb(info->program_regbase + 0xC8); ++ ++ /* Wait until /INIT pin is set */ ++ udelay(20); ++ if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) { ++ printk(KERN_ERR "me4000_xilinx_download():Can't init Xilinx\n"); ++ return -EIO; ++ } ++ ++ /* Reset /CS and /WRITE of the Xilinx */ ++ value = inl(info->plx_regbase + PLX_ICR); ++ value &= ~0x100; ++ outl(value, info->plx_regbase + PLX_ICR); ++ ++ /* Download Xilinx firmware */ ++ size = (firm[0] << 24) + (firm[1] << 16) + (firm[2] << 8) + firm[3]; ++ udelay(10); ++ ++ for (idx = 0; idx < size; idx++) { ++ outb(firm[16 + idx], info->program_regbase); ++ ++ udelay(10); ++ ++ /* Check if BUSY flag is low */ ++ if (inl(info->plx_regbase + PLX_ICR) & 0x20) { ++ printk(KERN_ERR ++ "me4000_xilinx_download():Xilinx is still busy (idx = %d)\n", ++ idx); ++ return -EIO; ++ } ++ } ++ ++ PDEBUG("me4000_xilinx_download():%d bytes written\n", idx); ++ ++ /* If done flag is high download was successful */ ++ if (inl(info->plx_regbase + PLX_ICR) & 0x4) { ++ PDEBUG("me4000_xilinx_download():Done flag is set\n"); ++ PDEBUG("me4000_xilinx_download():Download was successful\n"); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_xilinx_download():DONE flag is not set\n"); ++ printk(KERN_ERR ++ "ME4000:me4000_xilinx_download():Download not succesful\n"); ++ return -EIO; ++ } ++ ++ /* Set /CS and /WRITE */ ++ value = inl(info->plx_regbase + PLX_ICR); ++ value |= 0x100; ++ outl(value, info->plx_regbase + PLX_ICR); ++ ++ return 0; ++} ++ ++static int me4000_reset_board(me4000_info_t * info) ++{ ++ unsigned long icr; ++ ++ CALL_PDEBUG("me4000_reset_board() is executed\n"); ++ ++ /* Make a hardware reset */ ++ icr = me4000_inl(info->plx_regbase + PLX_ICR); ++ icr |= 0x40000000; ++ me4000_outl(icr, info->plx_regbase + PLX_ICR); ++ icr &= ~0x40000000; ++ me4000_outl(icr, info->plx_regbase + PLX_ICR); ++ ++ /* Set both stop bits in the analog input control register */ ++ me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, ++ info->me4000_regbase + ME4000_AI_CTRL_REG); ++ ++ /* Set both stop bits in the analog output control register */ ++ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, ++ info->me4000_regbase + ME4000_AO_00_CTRL_REG); ++ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, ++ info->me4000_regbase + ME4000_AO_01_CTRL_REG); ++ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, ++ info->me4000_regbase + ME4000_AO_02_CTRL_REG); ++ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, ++ info->me4000_regbase + ME4000_AO_03_CTRL_REG); ++ ++ /* 0x8000 to the DACs means an output voltage of 0V */ ++ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG); ++ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG); ++ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG); ++ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG); ++ ++ /* Enable interrupts on the PLX */ ++ me4000_outl(0x43, info->plx_regbase + PLX_INTCSR); ++ ++ /* Set the adustment register for AO demux */ ++ me4000_outl(ME4000_AO_DEMUX_ADJUST_VALUE, ++ info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG); ++ ++ /* Set digital I/O direction for port 0 to output on isolated versions */ ++ if (!(me4000_inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) { ++ me4000_outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG); ++ } ++ ++ return 0; ++} ++ ++static int me4000_open(struct inode *inode_p, struct file *file_p) ++{ ++ int board, dev, mode; ++ int err = 0; ++ int i; ++ struct list_head *ptr; ++ me4000_info_t *board_info = NULL; ++ me4000_ao_context_t *ao_context = NULL; ++ me4000_ai_context_t *ai_context = NULL; ++ me4000_dio_context_t *dio_context = NULL; ++ me4000_cnt_context_t *cnt_context = NULL; ++ me4000_ext_int_context_t *ext_int_context = NULL; ++ ++ CALL_PDEBUG("me4000_open() is executed\n"); ++ ++ /* Analog output */ ++ if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) { ++ board = AO_BOARD(inode_p->i_rdev); ++ dev = AO_PORT(inode_p->i_rdev); ++ mode = AO_MODE(inode_p->i_rdev); ++ ++ PDEBUG("me4000_open():board = %d ao = %d mode = %d\n", board, ++ dev, mode); ++ ++ /* Search for the board context */ ++ for (ptr = me4000_board_info_list.next, i = 0; ++ ptr != &me4000_board_info_list; ptr = ptr->next, i++) { ++ board_info = list_entry(ptr, me4000_info_t, list); ++ if (i == board) ++ break; ++ } ++ ++ if (ptr == &me4000_board_info_list) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Board %d not in device list\n", ++ board); ++ return -ENODEV; ++ } ++ ++ /* Search for the dac context */ ++ for (ptr = board_info->ao_context_list.next, i = 0; ++ ptr != &board_info->ao_context_list; ++ ptr = ptr->next, i++) { ++ ao_context = list_entry(ptr, me4000_ao_context_t, list); ++ if (i == dev) ++ break; ++ } ++ ++ if (ptr == &board_info->ao_context_list) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Device %d not in device list\n", ++ dev); ++ return -ENODEV; ++ } ++ ++ /* Check if mode is valid */ ++ if (mode > 2) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Mode is not valid\n"); ++ return -ENODEV; ++ } ++ ++ /* Check if mode is valid for this AO */ ++ if ((mode != ME4000_AO_CONV_MODE_SINGLE) ++ && (dev >= board_info->board_p->ao.fifo_count)) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():AO %d only in single mode available\n", ++ dev); ++ return -ENODEV; ++ } ++ ++ /* Check if already opened */ ++ spin_lock(&ao_context->use_lock); ++ if (ao_context->dac_in_use) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():AO %d already in use\n", ++ dev); ++ spin_unlock(&ao_context->use_lock); ++ return -EBUSY; ++ } ++ ao_context->dac_in_use = 1; ++ spin_unlock(&ao_context->use_lock); ++ ++ ao_context->mode = mode; ++ ++ /* Hold the context in private data */ ++ file_p->private_data = ao_context; ++ ++ /* Set file operations pointer */ ++ file_p->f_op = me4000_ao_fops_array[mode]; ++ ++ err = me4000_ao_prepare(ao_context); ++ if (err) { ++ ao_context->dac_in_use = 0; ++ return 1; ++ } ++ } ++ /* Analog input */ ++ else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) { ++ board = AI_BOARD(inode_p->i_rdev); ++ mode = AI_MODE(inode_p->i_rdev); ++ ++ PDEBUG("me4000_open():ai board = %d mode = %d\n", board, mode); ++ ++ /* Search for the board context */ ++ for (ptr = me4000_board_info_list.next, i = 0; ++ ptr != &me4000_board_info_list; ptr = ptr->next, i++) { ++ board_info = list_entry(ptr, me4000_info_t, list); ++ if (i == board) ++ break; ++ } ++ ++ if (ptr == &me4000_board_info_list) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Board %d not in device list\n", ++ board); ++ return -ENODEV; ++ } ++ ++ ai_context = board_info->ai_context; ++ ++ /* Check if mode is valid */ ++ if (mode > 5) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Mode is not valid\n"); ++ return -EINVAL; ++ } ++ ++ /* Check if already opened */ ++ spin_lock(&ai_context->use_lock); ++ if (ai_context->in_use) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():AI already in use\n"); ++ spin_unlock(&ai_context->use_lock); ++ return -EBUSY; ++ } ++ ai_context->in_use = 1; ++ spin_unlock(&ai_context->use_lock); ++ ++ ai_context->mode = mode; ++ ++ /* Hold the context in private data */ ++ file_p->private_data = ai_context; ++ ++ /* Set file operations pointer */ ++ file_p->f_op = me4000_ai_fops_array[mode]; ++ ++ /* Prepare analog input */ ++ me4000_ai_prepare(ai_context); ++ } ++ /* Digital I/O */ ++ else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) { ++ board = DIO_BOARD(inode_p->i_rdev); ++ dev = 0; ++ mode = 0; ++ ++ PDEBUG("me4000_open():board = %d\n", board); ++ ++ /* Search for the board context */ ++ for (ptr = me4000_board_info_list.next; ++ ptr != &me4000_board_info_list; ptr = ptr->next) { ++ board_info = list_entry(ptr, me4000_info_t, list); ++ if (board_info->board_count == board) ++ break; ++ } ++ ++ if (ptr == &me4000_board_info_list) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Board %d not in device list\n", ++ board); ++ return -ENODEV; ++ } ++ ++ /* Search for the dio context */ ++ dio_context = board_info->dio_context; ++ ++ /* Check if already opened */ ++ spin_lock(&dio_context->use_lock); ++ if (dio_context->in_use) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():DIO already in use\n"); ++ spin_unlock(&dio_context->use_lock); ++ return -EBUSY; ++ } ++ dio_context->in_use = 1; ++ spin_unlock(&dio_context->use_lock); ++ ++ /* Hold the context in private data */ ++ file_p->private_data = dio_context; ++ ++ /* Set file operations pointer to single functions */ ++ file_p->f_op = &me4000_dio_fops; ++ ++ //me4000_dio_reset(dio_context); ++ } ++ /* Counters */ ++ else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) { ++ board = CNT_BOARD(inode_p->i_rdev); ++ dev = 0; ++ mode = 0; ++ ++ PDEBUG("me4000_open():board = %d\n", board); ++ ++ /* Search for the board context */ ++ for (ptr = me4000_board_info_list.next; ++ ptr != &me4000_board_info_list; ptr = ptr->next) { ++ board_info = list_entry(ptr, me4000_info_t, list); ++ if (board_info->board_count == board) ++ break; ++ } ++ ++ if (ptr == &me4000_board_info_list) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Board %d not in device list\n", ++ board); ++ return -ENODEV; ++ } ++ ++ /* Get the cnt context */ ++ cnt_context = board_info->cnt_context; ++ ++ /* Check if already opened */ ++ spin_lock(&cnt_context->use_lock); ++ if (cnt_context->in_use) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():CNT already in use\n"); ++ spin_unlock(&cnt_context->use_lock); ++ return -EBUSY; ++ } ++ cnt_context->in_use = 1; ++ spin_unlock(&cnt_context->use_lock); ++ ++ /* Hold the context in private data */ ++ file_p->private_data = cnt_context; ++ ++ /* Set file operations pointer to single functions */ ++ file_p->f_op = &me4000_cnt_fops; ++ } ++ /* External Interrupt */ ++ else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) { ++ board = EXT_INT_BOARD(inode_p->i_rdev); ++ dev = 0; ++ mode = 0; ++ ++ PDEBUG("me4000_open():board = %d\n", board); ++ ++ /* Search for the board context */ ++ for (ptr = me4000_board_info_list.next; ++ ptr != &me4000_board_info_list; ptr = ptr->next) { ++ board_info = list_entry(ptr, me4000_info_t, list); ++ if (board_info->board_count == board) ++ break; ++ } ++ ++ if (ptr == &me4000_board_info_list) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Board %d not in device list\n", ++ board); ++ return -ENODEV; ++ } ++ ++ /* Get the external interrupt context */ ++ ext_int_context = board_info->ext_int_context; ++ ++ /* Check if already opened */ ++ spin_lock(&cnt_context->use_lock); ++ if (ext_int_context->in_use) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():External interrupt already in use\n"); ++ spin_unlock(&ext_int_context->use_lock); ++ return -EBUSY; ++ } ++ ext_int_context->in_use = 1; ++ spin_unlock(&ext_int_context->use_lock); ++ ++ /* Hold the context in private data */ ++ file_p->private_data = ext_int_context; ++ ++ /* Set file operations pointer to single functions */ ++ file_p->f_op = &me4000_ext_int_fops; ++ ++ /* Request the interrupt line */ ++ err = ++ request_irq(ext_int_context->irq, me4000_ext_int_isr, ++ IRQF_DISABLED | IRQF_SHARED, ME4000_NAME, ++ ext_int_context); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_open():Can't get interrupt line"); ++ ext_int_context->in_use = 0; ++ return -ENODEV; ++ } ++ ++ /* Reset the counter */ ++ me4000_ext_int_disable(ext_int_context); ++ } else { ++ printk(KERN_ERR "ME4000:me4000_open():Major number unknown\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int me4000_release(struct inode *inode_p, struct file *file_p) ++{ ++ me4000_ao_context_t *ao_context; ++ me4000_ai_context_t *ai_context; ++ me4000_dio_context_t *dio_context; ++ me4000_cnt_context_t *cnt_context; ++ me4000_ext_int_context_t *ext_int_context; ++ ++ CALL_PDEBUG("me4000_release() is executed\n"); ++ ++ if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) { ++ ao_context = file_p->private_data; ++ ++ /* Mark DAC as unused */ ++ ao_context->dac_in_use = 0; ++ } else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) { ++ ai_context = file_p->private_data; ++ ++ /* Reset the analog input */ ++ me4000_ai_reset(ai_context); ++ ++ /* Free the interrupt and the circular buffer */ ++ if (ai_context->mode) { ++ free_irq(ai_context->irq, ai_context); ++ kfree(ai_context->circ_buf.buf); ++ ai_context->circ_buf.buf = NULL; ++ ai_context->circ_buf.head = 0; ++ ai_context->circ_buf.tail = 0; ++ } ++ ++ /* Mark AI as unused */ ++ ai_context->in_use = 0; ++ } else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) { ++ dio_context = file_p->private_data; ++ ++ /* Mark digital I/O as unused */ ++ dio_context->in_use = 0; ++ } else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) { ++ cnt_context = file_p->private_data; ++ ++ /* Mark counters as unused */ ++ cnt_context->in_use = 0; ++ } else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) { ++ ext_int_context = file_p->private_data; ++ ++ /* Disable the externel interrupt */ ++ me4000_ext_int_disable(ext_int_context); ++ ++ free_irq(ext_int_context->irq, ext_int_context); ++ ++ /* Delete the fasync structure and free memory */ ++ me4000_ext_int_fasync(0, file_p, 0); ++ ++ /* Mark as unused */ ++ ext_int_context->in_use = 0; ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_release():Major number unknown\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/*------------------------------- Analog output stuff --------------------------------------*/ ++ ++static int me4000_ao_prepare(me4000_ao_context_t * ao_context) ++{ ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_prepare() is executed\n"); ++ ++ if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) { ++ /* Only do anything if not already in the correct mode */ ++ unsigned long mode = me4000_inl(ao_context->ctrl_reg); ++ if ((mode & ME4000_AO_CONV_MODE_CONTINUOUS) ++ && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) { ++ return 0; ++ } ++ ++ /* Stop any conversion */ ++ me4000_ao_immediate_stop(ao_context); ++ ++ /* Set the control register to default state */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS | ++ ME4000_AO_CTRL_BIT_ENABLE_FIFO | ++ ME4000_AO_CTRL_BIT_STOP | ++ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, ++ ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ /* Set to fastest sample rate */ ++ me4000_outl(65, ao_context->timer_reg); ++ } else if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) { ++ /* Only do anything if not already in the correct mode */ ++ unsigned long mode = me4000_inl(ao_context->ctrl_reg); ++ if ((mode & ME4000_AO_CONV_MODE_WRAPAROUND) ++ && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) { ++ return 0; ++ } ++ ++ /* Stop any conversion */ ++ me4000_ao_immediate_stop(ao_context); ++ ++ /* Set the control register to default state */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND | ++ ME4000_AO_CTRL_BIT_ENABLE_FIFO | ++ ME4000_AO_CTRL_BIT_STOP | ++ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, ++ ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ /* Set to fastest sample rate */ ++ me4000_outl(65, ao_context->timer_reg); ++ } else if (ao_context->mode == ME4000_AO_CONV_MODE_SINGLE) { ++ /* Only do anything if not already in the correct mode */ ++ unsigned long mode = me4000_inl(ao_context->ctrl_reg); ++ if (! ++ (mode & ++ (ME4000_AO_CONV_MODE_WRAPAROUND | ++ ME4000_AO_CONV_MODE_CONTINUOUS))) { ++ return 0; ++ } ++ ++ /* Stop any conversion */ ++ me4000_ao_immediate_stop(ao_context); ++ ++ /* Clear the control register */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ me4000_outl(0x0, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ /* Set voltage to 0V */ ++ me4000_outl(0x8000, ao_context->single_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_prepare():Invalid mode specified\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_reset(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ wait_queue_head_t queue; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_reset() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) { ++ /* ++ * First stop conversion of the DAC before reconfigure. ++ * This is essantial, cause of the state machine. ++ * If not stopped before configuring mode, it could ++ * walk in a undefined state. ++ */ ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ ++ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { ++ sleep_on_timeout(&queue, 1); ++ } ++ ++ /* Set to transparent mode */ ++ me4000_ao_simultaneous_disable(ao_context); ++ ++ /* Set to single mode in order to set default voltage */ ++ me4000_outl(0x0, ao_context->ctrl_reg); ++ ++ /* Set voltage to 0V */ ++ me4000_outl(0x8000, ao_context->single_reg); ++ ++ /* Set to fastest sample rate */ ++ me4000_outl(65, ao_context->timer_reg); ++ ++ /* Set the original mode and enable FIFO */ ++ me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND | ++ ME4000_AO_CTRL_BIT_ENABLE_FIFO | ++ ME4000_AO_CTRL_BIT_STOP | ++ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, ++ ao_context->ctrl_reg); ++ } else if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) { ++ /* ++ * First stop conversion of the DAC before reconfigure. ++ * This is essantial, cause of the state machine. ++ * If not stopped before configuring mode, it could ++ * walk in a undefined state. ++ */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_STOP; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { ++ sleep_on_timeout(&queue, 1); ++ } ++ ++ /* Clear the circular buffer */ ++ ao_context->circ_buf.head = 0; ++ ao_context->circ_buf.tail = 0; ++ ++ /* Set to transparent mode */ ++ me4000_ao_simultaneous_disable(ao_context); ++ ++ /* Set to single mode in order to set default voltage */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ me4000_outl(0x0, ao_context->ctrl_reg); ++ ++ /* Set voltage to 0V */ ++ me4000_outl(0x8000, ao_context->single_reg); ++ ++ /* Set to fastest sample rate */ ++ me4000_outl(65, ao_context->timer_reg); ++ ++ /* Set the original mode and enable FIFO */ ++ me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS | ++ ME4000_AO_CTRL_BIT_ENABLE_FIFO | ++ ME4000_AO_CTRL_BIT_STOP | ++ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP, ++ ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ } else { ++ /* Set to transparent mode */ ++ me4000_ao_simultaneous_disable(ao_context); ++ ++ /* Set voltage to 0V */ ++ me4000_outl(0x8000, ao_context->single_reg); ++ } ++ ++ return 0; ++} ++ ++static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff, ++ size_t cnt, loff_t * offp) ++{ ++ me4000_ao_context_t *ao_context = filep->private_data; ++ u32 value; ++ const u16 *buffer = (const u16 *)buff; ++ ++ CALL_PDEBUG("me4000_ao_write_sing() is executed\n"); ++ ++ if (cnt != 2) { ++ printk(KERN_ERR ++ "me4000_ao_write_sing():Write count is not 2\n"); ++ return -EINVAL; ++ } ++ ++ if (get_user(value, buffer)) { ++ printk(KERN_ERR ++ "me4000_ao_write_sing():Cannot copy data from user\n"); ++ return -EFAULT; ++ } ++ ++ me4000_outl(value, ao_context->single_reg); ++ ++ return 2; ++} ++ ++static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff, ++ size_t cnt, loff_t * offp) ++{ ++ me4000_ao_context_t *ao_context = filep->private_data; ++ size_t i; ++ u32 value; ++ u32 tmp; ++ const u16 *buffer = (const u16 *)buff; ++ size_t count = cnt / 2; ++ ++ CALL_PDEBUG("me4000_ao_write_wrap() is executed\n"); ++ ++ /* Check if a conversion is already running */ ++ if (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_write_wrap():There is already a conversion running\n"); ++ return -EBUSY; ++ } ++ ++ if (count > ME4000_AO_FIFO_COUNT) { ++ printk(KERN_ERR ++ "me4000_ao_write_wrap():Can't load more than %d values\n", ++ ME4000_AO_FIFO_COUNT); ++ return -ENOSPC; ++ } ++ ++ /* Reset the FIFO */ ++ tmp = inl(ao_context->ctrl_reg); ++ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_FIFO; ++ outl(tmp, ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO; ++ outl(tmp, ao_context->ctrl_reg); ++ ++ for (i = 0; i < count; i++) { ++ if (get_user(value, buffer + i)) { ++ printk(KERN_ERR ++ "me4000_ao_write_single():Cannot copy data from user\n"); ++ return -EFAULT; ++ } ++ if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG) ++ || ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG)) ++ value = value << 16; ++ outl(value, ao_context->fifo_reg); ++ } ++ CALL_PDEBUG("me4000_ao_write_wrap() is leaved with %d\n", i * 2); ++ ++ return i * 2; ++} ++ ++static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff, ++ size_t cnt, loff_t * offp) ++{ ++ me4000_ao_context_t *ao_context = filep->private_data; ++ const u16 *buffer = (const u16 *)buff; ++ size_t count = cnt / 2; ++ unsigned long flags; ++ u32 tmp; ++ int c = 0; ++ int k = 0; ++ int ret = 0; ++ u16 svalue; ++ u32 lvalue; ++ int i; ++ wait_queue_head_t queue; ++ ++ CALL_PDEBUG("me4000_ao_write_cont() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* Check count */ ++ if (count <= 0) { ++ PDEBUG("me4000_ao_write_cont():Count is 0\n"); ++ return 0; ++ } ++ ++ if (filep->f_flags & O_APPEND) { ++ PDEBUG("me4000_ao_write_cont():Append data to data stream\n"); ++ while (count > 0) { ++ if (filep->f_flags & O_NONBLOCK) { ++ if (ao_context->pipe_flag) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_write_cont():Broken pipe in nonblocking write\n"); ++ return -EPIPE; ++ } ++ c = me4000_space_to_end(ao_context->circ_buf, ++ ME4000_AO_BUFFER_COUNT); ++ if (!c) { ++ PDEBUG ++ ("me4000_ao_write_cont():Returning from nonblocking write\n"); ++ break; ++ } ++ } else { ++ wait_event_interruptible(ao_context->wait_queue, ++ (c = ++ me4000_space_to_end ++ (ao_context->circ_buf, ++ ME4000_AO_BUFFER_COUNT))); ++ if (ao_context->pipe_flag) { ++ printk(KERN_ERR ++ "me4000_ao_write_cont():Broken pipe in blocking write\n"); ++ return -EPIPE; ++ } ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "me4000_ao_write_cont():Wait for free buffer interrupted from signal\n"); ++ return -EINTR; ++ } ++ } ++ ++ PDEBUG("me4000_ao_write_cont():Space to end = %d\n", c); ++ ++ /* Only able to write size of free buffer or size of count */ ++ if (count < c) ++ c = count; ++ ++ k = 2 * c; ++ k -= copy_from_user(ao_context->circ_buf.buf + ++ ao_context->circ_buf.head, buffer, ++ k); ++ c = k / 2; ++ PDEBUG ++ ("me4000_ao_write_cont():Copy %d values from user space\n", ++ c); ++ ++ if (!c) ++ return -EFAULT; ++ ++ ao_context->circ_buf.head = ++ (ao_context->circ_buf.head + ++ c) & (ME4000_AO_BUFFER_COUNT - 1); ++ buffer += c; ++ count -= c; ++ ret += c; ++ ++ /* Values are now available so enable interrupts */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ if (me4000_buf_count ++ (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) { ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ } ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ } ++ ++ /* Wait until the state machine is stopped if O_SYNC is set */ ++ if (filep->f_flags & O_SYNC) { ++ while (inl(ao_context->status_reg) & ++ ME4000_AO_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (ao_context->pipe_flag) { ++ PDEBUG ++ ("me4000_ao_write_cont():Broken pipe detected after sync\n"); ++ return -EPIPE; ++ } ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "me4000_ao_write_cont():Wait on state machine after sync interrupted\n"); ++ return -EINTR; ++ } ++ } ++ } ++ } else { ++ PDEBUG("me4000_ao_write_cont():Preload DAC FIFO\n"); ++ if ((me4000_inl(ao_context->status_reg) & ++ ME4000_AO_STATUS_BIT_FSM)) { ++ printk(KERN_ERR ++ "me4000_ao_write_cont():Can't Preload DAC FIFO while conversion is running\n"); ++ return -EBUSY; ++ } ++ ++ /* Clear the FIFO */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AO_CTRL_BIT_ENABLE_FIFO | ++ ME4000_AO_CTRL_BIT_ENABLE_IRQ); ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ /* Clear the circular buffer */ ++ ao_context->circ_buf.head = 0; ++ ao_context->circ_buf.tail = 0; ++ ++ /* Reset the broken pipe flag */ ++ ao_context->pipe_flag = 0; ++ ++ /* Only able to write size of fifo or count */ ++ c = ME4000_AO_FIFO_COUNT; ++ if (count < c) ++ c = count; ++ ++ PDEBUG ++ ("me4000_ao_write_cont():Write %d values to DAC on 0x%lX\n", ++ c, ao_context->fifo_reg); ++ ++ /* Write values to the fifo */ ++ for (i = 0; i < c; i++) { ++ if (get_user(svalue, buffer)) ++ return -EFAULT; ++ ++ if (((ao_context->fifo_reg & 0xFF) == ++ ME4000_AO_01_FIFO_REG) ++ || ((ao_context->fifo_reg & 0xFF) == ++ ME4000_AO_03_FIFO_REG)) { ++ lvalue = ((u32) svalue) << 16; ++ } else ++ lvalue = (u32) svalue; ++ ++ outl(lvalue, ao_context->fifo_reg); ++ buffer++; ++ } ++ count -= c; ++ ret += c; ++ ++ while (1) { ++ /* Get free buffer */ ++ c = me4000_space_to_end(ao_context->circ_buf, ++ ME4000_AO_BUFFER_COUNT); ++ ++ if (c == 0) ++ return (2 * ret); ++ ++ /* Only able to write size of free buffer or size of count */ ++ if (count < c) ++ c = count; ++ ++ /* If count = 0 return to user */ ++ if (c <= 0) { ++ PDEBUG ++ ("me4000_ao_write_cont():Count reached 0\n"); ++ break; ++ } ++ ++ k = 2 * c; ++ k -= copy_from_user(ao_context->circ_buf.buf + ++ ao_context->circ_buf.head, buffer, ++ k); ++ c = k / 2; ++ PDEBUG ++ ("me4000_ao_write_cont():Wrote %d values to buffer\n", ++ c); ++ ++ if (!c) ++ return -EFAULT; ++ ++ ao_context->circ_buf.head = ++ (ao_context->circ_buf.head + ++ c) & (ME4000_AO_BUFFER_COUNT - 1); ++ buffer += c; ++ count -= c; ++ ret += c; ++ ++ /* If values in the buffer are available so enable interrupts */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ if (me4000_buf_count ++ (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) { ++ PDEBUG ++ ("me4000_ao_write_cont():Enable Interrupts\n"); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ } ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ } ++ } ++ ++ if (filep->f_flags & O_NONBLOCK) { ++ return (ret == 0) ? -EAGAIN : 2 * ret; ++ } ++ ++ return 2 * ret; ++} ++ ++static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait) ++{ ++ me4000_ao_context_t *ao_context; ++ unsigned long mask = 0; ++ ++ CALL_PDEBUG("me4000_ao_poll_cont() is executed\n"); ++ ++ ao_context = file_p->private_data; ++ ++ poll_wait(file_p, &ao_context->wait_queue, wait); ++ ++ /* Get free buffer */ ++ if (me4000_space_to_end(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) ++ mask |= POLLOUT | POLLWRNORM; ++ ++ CALL_PDEBUG("me4000_ao_poll_cont():Return mask %lX\n", mask); ++ ++ return mask; ++} ++ ++static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p, ++ int datasync) ++{ ++ me4000_ao_context_t *ao_context; ++ wait_queue_head_t queue; ++ ++ CALL_PDEBUG("me4000_ao_fsync_cont() is executed\n"); ++ ++ ao_context = file_p->private_data; ++ init_waitqueue_head(&queue); ++ ++ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (ao_context->pipe_flag) { ++ printk(KERN_ERR ++ "me4000_ao_fsync_cont():Broken pipe detected\n"); ++ return -EPIPE; ++ } ++ ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "me4000_ao_fsync_cont():Wait on state machine interrupted\n"); ++ return -EINTR; ++ } ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ao_context_t *ao_context; ++ ++ CALL_PDEBUG("me4000_ao_ioctl_sing() is executed\n"); ++ ++ ao_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ return -ENOTTY; ++ PDEBUG("me4000_ao_ioctl_sing():Wrong magic number\n"); ++ } ++ ++ switch (service) { ++ case ME4000_AO_EX_TRIG_SETUP: ++ return me4000_ao_ex_trig_set_edge((int *)arg, ao_context); ++ case ME4000_AO_EX_TRIG_ENABLE: ++ return me4000_ao_ex_trig_enable(ao_context); ++ case ME4000_AO_EX_TRIG_DISABLE: ++ return me4000_ao_ex_trig_disable(ao_context); ++ case ME4000_AO_PRELOAD: ++ return me4000_ao_preload(ao_context); ++ case ME4000_AO_PRELOAD_UPDATE: ++ return me4000_ao_preload_update(ao_context); ++ case ME4000_GET_USER_INFO: ++ return me4000_get_user_info((me4000_user_info_t *) arg, ++ ao_context->board_info); ++ case ME4000_AO_SIMULTANEOUS_EX_TRIG: ++ return me4000_ao_simultaneous_ex_trig(ao_context); ++ case ME4000_AO_SIMULTANEOUS_SW: ++ return me4000_ao_simultaneous_sw(ao_context); ++ case ME4000_AO_SIMULTANEOUS_DISABLE: ++ return me4000_ao_simultaneous_disable(ao_context); ++ case ME4000_AO_SIMULTANEOUS_UPDATE: ++ return ++ me4000_ao_simultaneous_update((me4000_ao_channel_list_t *) ++ arg, ao_context); ++ case ME4000_AO_EX_TRIG_TIMEOUT: ++ return me4000_ao_ex_trig_timeout((unsigned long *)arg, ++ ao_context); ++ case ME4000_AO_DISABLE_DO: ++ return me4000_ao_disable_do(ao_context); ++ default: ++ printk(KERN_ERR ++ "me4000_ao_ioctl_sing():Service number invalid\n"); ++ return -ENOTTY; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ao_context_t *ao_context; ++ ++ CALL_PDEBUG("me4000_ao_ioctl_wrap() is executed\n"); ++ ++ ao_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ return -ENOTTY; ++ PDEBUG("me4000_ao_ioctl_wrap():Wrong magic number\n"); ++ } ++ ++ switch (service) { ++ case ME4000_AO_START: ++ return me4000_ao_start((unsigned long *)arg, ao_context); ++ case ME4000_AO_STOP: ++ return me4000_ao_stop(ao_context); ++ case ME4000_AO_IMMEDIATE_STOP: ++ return me4000_ao_immediate_stop(ao_context); ++ case ME4000_AO_RESET: ++ return me4000_ao_reset(ao_context); ++ case ME4000_AO_TIMER_SET_DIVISOR: ++ return me4000_ao_timer_set_divisor((u32 *) arg, ao_context); ++ case ME4000_AO_EX_TRIG_SETUP: ++ return me4000_ao_ex_trig_set_edge((int *)arg, ao_context); ++ case ME4000_AO_EX_TRIG_ENABLE: ++ return me4000_ao_ex_trig_enable(ao_context); ++ case ME4000_AO_EX_TRIG_DISABLE: ++ return me4000_ao_ex_trig_disable(ao_context); ++ case ME4000_GET_USER_INFO: ++ return me4000_get_user_info((me4000_user_info_t *) arg, ++ ao_context->board_info); ++ case ME4000_AO_FSM_STATE: ++ return me4000_ao_fsm_state((int *)arg, ao_context); ++ case ME4000_AO_ENABLE_DO: ++ return me4000_ao_enable_do(ao_context); ++ case ME4000_AO_DISABLE_DO: ++ return me4000_ao_disable_do(ao_context); ++ case ME4000_AO_SYNCHRONOUS_EX_TRIG: ++ return me4000_ao_synchronous_ex_trig(ao_context); ++ case ME4000_AO_SYNCHRONOUS_SW: ++ return me4000_ao_synchronous_sw(ao_context); ++ case ME4000_AO_SYNCHRONOUS_DISABLE: ++ return me4000_ao_synchronous_disable(ao_context); ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ao_context_t *ao_context; ++ ++ CALL_PDEBUG("me4000_ao_ioctl_cont() is executed\n"); ++ ++ ao_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ return -ENOTTY; ++ PDEBUG("me4000_ao_ioctl_cont():Wrong magic number\n"); ++ } ++ ++ switch (service) { ++ case ME4000_AO_START: ++ return me4000_ao_start((unsigned long *)arg, ao_context); ++ case ME4000_AO_STOP: ++ return me4000_ao_stop(ao_context); ++ case ME4000_AO_IMMEDIATE_STOP: ++ return me4000_ao_immediate_stop(ao_context); ++ case ME4000_AO_RESET: ++ return me4000_ao_reset(ao_context); ++ case ME4000_AO_TIMER_SET_DIVISOR: ++ return me4000_ao_timer_set_divisor((u32 *) arg, ao_context); ++ case ME4000_AO_EX_TRIG_SETUP: ++ return me4000_ao_ex_trig_set_edge((int *)arg, ao_context); ++ case ME4000_AO_EX_TRIG_ENABLE: ++ return me4000_ao_ex_trig_enable(ao_context); ++ case ME4000_AO_EX_TRIG_DISABLE: ++ return me4000_ao_ex_trig_disable(ao_context); ++ case ME4000_AO_ENABLE_DO: ++ return me4000_ao_enable_do(ao_context); ++ case ME4000_AO_DISABLE_DO: ++ return me4000_ao_disable_do(ao_context); ++ case ME4000_AO_FSM_STATE: ++ return me4000_ao_fsm_state((int *)arg, ao_context); ++ case ME4000_GET_USER_INFO: ++ return me4000_get_user_info((me4000_user_info_t *) arg, ++ ao_context->board_info); ++ case ME4000_AO_SYNCHRONOUS_EX_TRIG: ++ return me4000_ao_synchronous_ex_trig(ao_context); ++ case ME4000_AO_SYNCHRONOUS_SW: ++ return me4000_ao_synchronous_sw(ao_context); ++ case ME4000_AO_SYNCHRONOUS_DISABLE: ++ return me4000_ao_synchronous_disable(ao_context); ++ case ME4000_AO_GET_FREE_BUFFER: ++ return me4000_ao_get_free_buffer((unsigned long *)arg, ++ ao_context); ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ wait_queue_head_t queue; ++ unsigned long ref; ++ unsigned long timeout; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_start() is executed\n"); ++ ++ if (get_user(timeout, arg)) { ++ printk(KERN_ERR ++ "me4000_ao_start():Cannot copy data from user\n"); ++ return -EFAULT; ++ } ++ ++ init_waitqueue_head(&queue); ++ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = inl(ao_context->ctrl_reg); ++ tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) { ++ if (timeout) { ++ ref = jiffies; ++ while (! ++ (inl(ao_context->status_reg) & ++ ME4000_AO_STATUS_BIT_FSM)) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_start():Wait on start of state machine interrupted\n"); ++ return -EINTR; ++ } ++ if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space ++ printk(KERN_ERR ++ "ME4000:me4000_ao_start():Timeout reached\n"); ++ return -EIO; ++ } ++ } ++ } ++ } else { ++ me4000_outl(0x8000, ao_context->single_reg); ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_stop(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ wait_queue_head_t queue; ++ unsigned long flags; ++ ++ init_waitqueue_head(&queue); ++ ++ CALL_PDEBUG("me4000_ao_stop() is executed\n"); ++ ++ /* Set the stop bit */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_STOP; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "me4000_ao_stop():Wait on state machine after stop interrupted\n"); ++ return -EINTR; ++ } ++ } ++ ++ /* Clear the stop bit */ ++ //tmp &= ~ME4000_AO_CTRL_BIT_STOP; ++ //me4000_outl(tmp, ao_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ wait_queue_head_t queue; ++ unsigned long flags; ++ ++ init_waitqueue_head(&queue); ++ ++ CALL_PDEBUG("me4000_ao_immediate_stop() is executed\n"); ++ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "me4000_ao_immediate_stop():Wait on state machine after stop interrupted\n"); ++ return -EINTR; ++ } ++ } ++ ++ /* Clear the stop bits */ ++ //tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); ++ //me4000_outl(tmp, ao_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ao_timer_set_divisor(u32 * arg, ++ me4000_ao_context_t * ao_context) ++{ ++ u32 divisor; ++ u32 tmp; ++ ++ CALL_PDEBUG("me4000_ao_timer set_divisor() is executed\n"); ++ ++ if (get_user(divisor, arg)) ++ return -EFAULT; ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "me4000_ao_timer_set_divisor():Can't set timer while DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ PDEBUG("me4000_ao_timer set_divisor():Divisor from user = %d\n", ++ divisor); ++ ++ /* Check if the divisor is right. ME4000_AO_MIN_TICKS is the lowest */ ++ if (divisor < ME4000_AO_MIN_TICKS) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_timer set_divisor():Divisor to low\n"); ++ return -EINVAL; ++ } ++ ++ /* Fix bug in Firmware */ ++ divisor -= 2; ++ ++ PDEBUG("me4000_ao_timer set_divisor():Divisor to HW = %d\n", divisor); ++ ++ /* Write the divisor */ ++ me4000_outl(divisor, ao_context->timer_reg); ++ ++ return 0; ++} ++ ++static int me4000_ao_ex_trig_set_edge(int *arg, ++ me4000_ao_context_t * ao_context) ++{ ++ int mode; ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_ex_trig_set_edge() is executed\n"); ++ ++ if (get_user(mode, arg)) ++ return -EFAULT; ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "me4000_ao_ex_trig_set_edge():Can't set trigger while DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ if (mode == ME4000_AO_TRIGGER_EXT_EDGE_RISING) { ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AO_CTRL_BIT_EX_TRIG_EDGE | ++ ME4000_AO_CTRL_BIT_EX_TRIG_BOTH); ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_FALLING) { ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp &= ~ME4000_AO_CTRL_BIT_EX_TRIG_BOTH; ++ tmp |= ME4000_AO_CTRL_BIT_EX_TRIG_EDGE; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_BOTH) { ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ++ ME4000_AO_CTRL_BIT_EX_TRIG_EDGE | ++ ME4000_AO_CTRL_BIT_EX_TRIG_BOTH; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ } else { ++ printk(KERN_ERR ++ "me4000_ao_ex_trig_set_edge():Invalid trigger mode\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_ex_trig_enable() is executed\n"); ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "me4000_ao_ex_trig_enable():Can't enable trigger while DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_ex_trig_disable() is executed\n"); ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "me4000_ao_ex_trig_disable():Can't disable trigger while DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ ++ CALL_PDEBUG("me4000_ao_simultaneous_disable() is executed\n"); ++ ++ /* Check if the state machine is stopped */ ++ /* Be careful here because this function is called from ++ me4000_ao_synchronous disable */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "me4000_ao_simultaneous_disable():Can't disable while DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ tmp &= ~(0x1 << ao_context->index); // Disable preload bit ++ tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ ++ return 0; ++} ++ ++static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ ++ CALL_PDEBUG("me4000_ao_simultaneous_ex_trig() is executed\n"); ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ tmp |= (0x1 << ao_context->index); // Enable preload bit ++ tmp |= (0x1 << (ao_context->index + 16)); // Enable hw simultaneous bit ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ ++ return 0; ++} ++ ++static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ ++ CALL_PDEBUG("me4000_ao_simultaneous_sw() is executed\n"); ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ tmp |= (0x1 << ao_context->index); // Enable preload bit ++ tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ ++ return 0; ++} ++ ++static int me4000_ao_preload(me4000_ao_context_t * ao_context) ++{ ++ CALL_PDEBUG("me4000_ao_preload() is executed\n"); ++ return me4000_ao_simultaneous_sw(ao_context); ++} ++ ++static int me4000_ao_preload_update(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ u32 ctrl; ++ struct list_head *entry; ++ ++ CALL_PDEBUG("me4000_ao_preload_update() is executed\n"); ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ list_for_each(entry, &ao_context->board_info->ao_context_list) { ++ /* The channels we update must be in the following state : ++ - Mode A ++ - Hardware trigger is disabled ++ - Corresponding simultaneous bit is reset ++ */ ++ ctrl = me4000_inl(ao_context->ctrl_reg); ++ if (! ++ (ctrl & ++ (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1 | ++ ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG))) { ++ if (! ++ (tmp & ++ (0x1 << ++ (((me4000_ao_context_t *) entry)->index + 16)))) { ++ tmp &= ++ ~(0x1 << ++ (((me4000_ao_context_t *) entry)->index)); ++ } ++ } ++ } ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ ++ return 0; ++} ++ ++static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg, ++ me4000_ao_context_t * ao_context) ++{ ++ int err; ++ int i; ++ u32 tmp; ++ me4000_ao_channel_list_t channels; ++ ++ CALL_PDEBUG("me4000_ao_simultaneous_update() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&channels, arg, sizeof(me4000_ao_channel_list_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_simultaneous_update():Can't copy command\n"); ++ return -EFAULT; ++ } ++ ++ channels.list = ++ kmalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL); ++ if (!channels.list) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_simultaneous_update():Can't get buffer\n"); ++ return -ENOMEM; ++ } ++ memset(channels.list, 0, sizeof(unsigned long) * channels.count); ++ ++ /* Copy channel list from user */ ++ err = ++ copy_from_user(channels.list, arg->list, ++ sizeof(unsigned long) * channels.count); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_simultaneous_update():Can't copy list\n"); ++ kfree(channels.list); ++ return -EFAULT; ++ } ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ for (i = 0; i < channels.count; i++) { ++ if (channels.list[i] > ++ ao_context->board_info->board_p->ao.count) { ++ spin_unlock(&ao_context->board_info->preload_lock); ++ kfree(channels.list); ++ printk(KERN_ERR ++ "ME4000:me4000_ao_simultaneous_update():Invalid board number specified\n"); ++ return -EFAULT; ++ } ++ tmp &= ~(0x1 << channels.list[i]); // Clear the preload bit ++ tmp &= ~(0x1 << (channels.list[i] + 16)); // Clear the hw simultaneous bit ++ } ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ kfree(channels.list); ++ ++ return 0; ++} ++ ++static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_synchronous_ex_trig() is executed\n"); ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "me4000_ao_synchronous_ex_trig(): DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ tmp &= ~(0x1 << ao_context->index); // Disable synchronous sw bit ++ tmp |= 0x1 << (ao_context->index + 16); // Enable synchronous hw bit ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ ++ /* Make runnable */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) { ++ tmp &= ++ ~(ME4000_AO_CTRL_BIT_STOP | ++ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ } ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_synchronous_sw() is executed\n"); ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR "me4000_ao_synchronous_sw(): DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock(&ao_context->board_info->preload_lock); ++ tmp = me4000_inl(ao_context->preload_reg); ++ tmp |= 0x1 << ao_context->index; // Enable synchronous sw bit ++ tmp &= ~(0x1 << (ao_context->index + 16)); // Disable synchronous hw bit ++ me4000_outl(tmp, ao_context->preload_reg); ++ spin_unlock(&ao_context->board_info->preload_lock); ++ ++ /* Make runnable */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) { ++ tmp &= ++ ~(ME4000_AO_CTRL_BIT_STOP | ++ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP); ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ } ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context) ++{ ++ return me4000_ao_simultaneous_disable(ao_context); ++} ++ ++static int me4000_ao_get_free_buffer(unsigned long *arg, ++ me4000_ao_context_t * ao_context) ++{ ++ unsigned long c; ++ int err; ++ ++ c = me4000_buf_space(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT); ++ ++ err = copy_to_user(arg, &c, sizeof(unsigned long)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_get_free_buffer():Can't copy to user space\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_ex_trig_timeout(unsigned long *arg, ++ me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ wait_queue_head_t queue; ++ unsigned long ref; ++ unsigned long timeout; ++ ++ CALL_PDEBUG("me4000_ao_ex_trig_timeout() is executed\n"); ++ ++ if (get_user(timeout, arg)) { ++ printk(KERN_ERR ++ "me4000_ao_ex_trig_timeout():Cannot copy data from user\n"); ++ return -EFAULT; ++ } ++ ++ init_waitqueue_head(&queue); ++ ++ tmp = inl(ao_context->ctrl_reg); ++ ++ if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) { ++ if (timeout) { ++ ref = jiffies; ++ while ((inl(ao_context->status_reg) & ++ ME4000_AO_STATUS_BIT_FSM)) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n"); ++ return -EINTR; ++ } ++ if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space ++ printk(KERN_ERR ++ "ME4000:me4000_ao_ex_trig_timeout():Timeout reached\n"); ++ return -EIO; ++ } ++ } ++ } else { ++ while ((inl(ao_context->status_reg) & ++ ME4000_AO_STATUS_BIT_FSM)) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n"); ++ return -EINTR; ++ } ++ } ++ } ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_ao_ex_trig_timeout():External Trigger is not enabled\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ao_enable_do(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_enable_do() is executed\n"); ++ ++ /* Only available for analog output 3 */ ++ if (ao_context->index != 3) { ++ printk(KERN_ERR ++ "me4000_ao_enable_do():Only available for analog output 3\n"); ++ return -ENOTTY; ++ } ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR "me4000_ao_enable_do(): DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ /* Set the stop bit */ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_ENABLE_DO; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ao_disable_do(me4000_ao_context_t * ao_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ao_disable_do() is executed\n"); ++ ++ /* Only available for analog output 3 */ ++ if (ao_context->index != 3) { ++ printk(KERN_ERR ++ "me4000_ao_disable():Only available for analog output 3\n"); ++ return -ENOTTY; ++ } ++ ++ /* Check if the state machine is stopped */ ++ tmp = me4000_inl(ao_context->status_reg); ++ if (tmp & ME4000_AO_STATUS_BIT_FSM) { ++ printk(KERN_ERR "me4000_ao_disable_do(): DAC is running\n"); ++ return -EBUSY; ++ } ++ ++ spin_lock_irqsave(&ao_context->int_lock, flags); ++ tmp = inl(ao_context->ctrl_reg); ++ tmp &= ~(ME4000_AO_CTRL_BIT_ENABLE_DO); ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock_irqrestore(&ao_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ao_fsm_state(int *arg, me4000_ao_context_t * ao_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ao_fsm_state() is executed\n"); ++ ++ tmp = ++ (me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) ? 1 ++ : 0; ++ ++ if (ao_context->pipe_flag) { ++ printk(KERN_ERR "me4000_ao_fsm_state():Broken pipe detected\n"); ++ return -EPIPE; ++ } ++ ++ if (put_user(tmp, arg)) { ++ printk(KERN_ERR "me4000_ao_fsm_state():Cannot copy to user\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*------------------------------- Analog input stuff --------------------------------------*/ ++ ++static int me4000_ai_prepare(me4000_ai_context_t * ai_context) ++{ ++ wait_queue_head_t queue; ++ int err; ++ ++ CALL_PDEBUG("me4000_ai_prepare() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* Set the new mode and stop bits */ ++ me4000_outl(ai_context-> ++ mode | ME4000_AI_CTRL_BIT_STOP | ++ ME4000_AI_CTRL_BIT_IMMEDIATE_STOP, ai_context->ctrl_reg); ++ ++ /* Set the timer registers */ ++ ai_context->chan_timer = 66; ++ ai_context->chan_pre_timer = 66; ++ ai_context->scan_timer_low = 0; ++ ai_context->scan_timer_high = 0; ++ ++ me4000_outl(65, ai_context->chan_timer_reg); ++ me4000_outl(65, ai_context->chan_pre_timer_reg); ++ me4000_outl(0, ai_context->scan_timer_low_reg); ++ me4000_outl(0, ai_context->scan_timer_high_reg); ++ me4000_outl(0, ai_context->scan_pre_timer_low_reg); ++ me4000_outl(0, ai_context->scan_pre_timer_high_reg); ++ ++ ai_context->channel_list_count = 0; ++ ++ if (ai_context->mode) { ++ /* Request the interrupt line */ ++ err = ++ request_irq(ai_context->irq, me4000_ai_isr, ++ IRQF_DISABLED | IRQF_SHARED, ME4000_NAME, ++ ai_context); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_prepare():Can't get interrupt line"); ++ return -ENODEV; ++ } ++ ++ /* Allocate circular buffer */ ++ ai_context->circ_buf.buf = ++ kmalloc(ME4000_AI_BUFFER_SIZE, GFP_KERNEL); ++ if (!ai_context->circ_buf.buf) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_prepare():Can't get circular buffer\n"); ++ free_irq(ai_context->irq, ai_context); ++ return -ENOMEM; ++ } ++ memset(ai_context->circ_buf.buf, 0, ME4000_AI_BUFFER_SIZE); ++ ++ /* Clear the circular buffer */ ++ ai_context->circ_buf.head = 0; ++ ai_context->circ_buf.tail = 0; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ai_reset(me4000_ai_context_t * ai_context) ++{ ++ wait_queue_head_t queue; ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ai_reset() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* ++ * First stop conversion of the state machine before reconfigure. ++ * If not stopped before configuring mode, it could ++ * walk in a undefined state. ++ */ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ ++ while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "me4000_ai_reset():Wait on state machine after stop interrupted\n"); ++ return -EINTR; ++ } ++ } ++ ++ /* Clear the control register and set the stop bits */ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, ++ ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ ++ /* Reset timer registers */ ++ ai_context->chan_timer = 66; ++ ai_context->chan_pre_timer = 66; ++ ai_context->scan_timer_low = 0; ++ ai_context->scan_timer_high = 0; ++ ai_context->sample_counter = 0; ++ ai_context->sample_counter_reload = 0; ++ ++ me4000_outl(65, ai_context->chan_timer_reg); ++ me4000_outl(65, ai_context->chan_pre_timer_reg); ++ me4000_outl(0, ai_context->scan_timer_low_reg); ++ me4000_outl(0, ai_context->scan_timer_high_reg); ++ me4000_outl(0, ai_context->scan_pre_timer_low_reg); ++ me4000_outl(0, ai_context->scan_pre_timer_high_reg); ++ me4000_outl(0, ai_context->sample_counter_reg); ++ ++ ai_context->channel_list_count = 0; ++ ++ /* Clear the circular buffer */ ++ ai_context->circ_buf.head = 0; ++ ai_context->circ_buf.tail = 0; ++ ++ return 0; ++} ++ ++static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ai_context_t *ai_context; ++ ++ CALL_PDEBUG("me4000_ai_ioctl_sing() is executed\n"); ++ ++ ai_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ printk(KERN_ERR "me4000_ai_ioctl_sing():Wrong magic number\n"); ++ return -ENOTTY; ++ } ++ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { ++ printk(KERN_ERR ++ "me4000_ai_ioctl_sing():Service number to high\n"); ++ return -ENOTTY; ++ } ++ ++ switch (service) { ++ case ME4000_AI_SINGLE: ++ return me4000_ai_single((me4000_ai_single_t *) arg, ai_context); ++ case ME4000_AI_EX_TRIG_ENABLE: ++ return me4000_ai_ex_trig_enable(ai_context); ++ case ME4000_AI_EX_TRIG_DISABLE: ++ return me4000_ai_ex_trig_disable(ai_context); ++ case ME4000_AI_EX_TRIG_SETUP: ++ return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg, ++ ai_context); ++ case ME4000_GET_USER_INFO: ++ return me4000_get_user_info((me4000_user_info_t *) arg, ++ ai_context->board_info); ++ case ME4000_AI_OFFSET_ENABLE: ++ return me4000_ai_offset_enable(ai_context); ++ case ME4000_AI_OFFSET_DISABLE: ++ return me4000_ai_offset_disable(ai_context); ++ case ME4000_AI_FULLSCALE_ENABLE: ++ return me4000_ai_fullscale_enable(ai_context); ++ case ME4000_AI_FULLSCALE_DISABLE: ++ return me4000_ai_fullscale_disable(ai_context); ++ case ME4000_AI_EEPROM_READ: ++ return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context); ++ case ME4000_AI_EEPROM_WRITE: ++ return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context); ++ default: ++ printk(KERN_ERR ++ "me4000_ai_ioctl_sing():Invalid service number\n"); ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_ai_single(me4000_ai_single_t * arg, ++ me4000_ai_context_t * ai_context) ++{ ++ me4000_ai_single_t cmd; ++ int err; ++ u32 tmp; ++ wait_queue_head_t queue; ++ unsigned long jiffy; ++ ++ CALL_PDEBUG("me4000_ai_single() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_single_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Check range parameter */ ++ switch (cmd.range) { ++ case ME4000_AI_LIST_RANGE_BIPOLAR_10: ++ case ME4000_AI_LIST_RANGE_BIPOLAR_2_5: ++ case ME4000_AI_LIST_RANGE_UNIPOLAR_10: ++ case ME4000_AI_LIST_RANGE_UNIPOLAR_2_5: ++ break; ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Invalid range specified\n"); ++ return -EINVAL; ++ } ++ ++ /* Check mode and channel number */ ++ switch (cmd.mode) { ++ case ME4000_AI_LIST_INPUT_SINGLE_ENDED: ++ if (cmd.channel >= ai_context->board_info->board_p->ai.count) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Analog input is not available\n"); ++ return -EINVAL; ++ } ++ break; ++ case ME4000_AI_LIST_INPUT_DIFFERENTIAL: ++ if (cmd.channel >= ++ ai_context->board_info->board_p->ai.diff_count) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Analog input is not available in differential mode\n"); ++ return -EINVAL; ++ } ++ break; ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Invalid mode specified\n"); ++ return -EINVAL; ++ } ++ ++ /* Clear channel list, data fifo and both stop bits */ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO | ++ ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ /* Enable channel list and data fifo */ ++ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ /* Generate channel list entry */ ++ me4000_outl(cmd.channel | cmd.range | cmd. ++ mode | ME4000_AI_LIST_LAST_ENTRY, ++ ai_context->channel_list_reg); ++ ++ /* Set the timer to maximum */ ++ me4000_outl(66, ai_context->chan_timer_reg); ++ me4000_outl(66, ai_context->chan_pre_timer_reg); ++ ++ if (tmp & ME4000_AI_CTRL_BIT_EX_TRIG) { ++ jiffy = jiffies; ++ while (! ++ (me4000_inl(ai_context->status_reg) & ++ ME4000_AI_STATUS_BIT_EF_DATA)) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Wait on start of state machine interrupted\n"); ++ return -EINTR; ++ } ++ if (((jiffies - jiffy) > (cmd.timeout * HZ / USER_HZ)) && cmd.timeout) { // 2.6 has diffrent definitions for HZ in user and kernel space ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Timeout reached\n"); ++ return -EIO; ++ } ++ } ++ } else { ++ /* Start conversion */ ++ me4000_inl(ai_context->start_reg); ++ ++ /* Wait until ready */ ++ udelay(10); ++ if (! ++ (me4000_inl(ai_context->status_reg) & ++ ME4000_AI_STATUS_BIT_EF_DATA)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Value not available after wait\n"); ++ return -EIO; ++ } ++ } ++ ++ /* Read value from data fifo */ ++ cmd.value = me4000_inl(ai_context->data_reg) & 0xFFFF; ++ ++ /* Copy result back to user */ ++ err = copy_to_user(arg, &cmd, sizeof(me4000_ai_single_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_single():Can't copy to user space\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ai_context_t *ai_context; ++ ++ CALL_PDEBUG("me4000_ai_ioctl_sw() is executed\n"); ++ ++ ai_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ printk(KERN_ERR "me4000_ai_ioctl_sw():Wrong magic number\n"); ++ return -ENOTTY; ++ } ++ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { ++ printk(KERN_ERR ++ "me4000_ai_ioctl_sw():Service number to high\n"); ++ return -ENOTTY; ++ } ++ ++ switch (service) { ++ case ME4000_AI_SC_SETUP: ++ return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context); ++ case ME4000_AI_CONFIG: ++ return me4000_ai_config((me4000_ai_config_t *) arg, ai_context); ++ case ME4000_AI_START: ++ return me4000_ai_start(ai_context); ++ case ME4000_AI_STOP: ++ return me4000_ai_stop(ai_context); ++ case ME4000_AI_IMMEDIATE_STOP: ++ return me4000_ai_immediate_stop(ai_context); ++ case ME4000_AI_FSM_STATE: ++ return me4000_ai_fsm_state((int *)arg, ai_context); ++ case ME4000_GET_USER_INFO: ++ return me4000_get_user_info((me4000_user_info_t *) arg, ++ ai_context->board_info); ++ case ME4000_AI_EEPROM_READ: ++ return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context); ++ case ME4000_AI_EEPROM_WRITE: ++ return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context); ++ case ME4000_AI_GET_COUNT_BUFFER: ++ return me4000_ai_get_count_buffer((unsigned long *)arg, ++ ai_context); ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_ai_ioctl_sw():Invalid service number %d\n", ++ service); ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ai_context_t *ai_context; ++ ++ CALL_PDEBUG("me4000_ai_ioctl_ext() is executed\n"); ++ ++ ai_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ printk(KERN_ERR "me4000_ai_ioctl_ext():Wrong magic number\n"); ++ return -ENOTTY; ++ } ++ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { ++ printk(KERN_ERR ++ "me4000_ai_ioctl_ext():Service number to high\n"); ++ return -ENOTTY; ++ } ++ ++ switch (service) { ++ case ME4000_AI_SC_SETUP: ++ return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context); ++ case ME4000_AI_CONFIG: ++ return me4000_ai_config((me4000_ai_config_t *) arg, ai_context); ++ case ME4000_AI_START: ++ return me4000_ai_start_ex((unsigned long *)arg, ai_context); ++ case ME4000_AI_STOP: ++ return me4000_ai_stop(ai_context); ++ case ME4000_AI_IMMEDIATE_STOP: ++ return me4000_ai_immediate_stop(ai_context); ++ case ME4000_AI_EX_TRIG_ENABLE: ++ return me4000_ai_ex_trig_enable(ai_context); ++ case ME4000_AI_EX_TRIG_DISABLE: ++ return me4000_ai_ex_trig_disable(ai_context); ++ case ME4000_AI_EX_TRIG_SETUP: ++ return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg, ++ ai_context); ++ case ME4000_AI_FSM_STATE: ++ return me4000_ai_fsm_state((int *)arg, ai_context); ++ case ME4000_GET_USER_INFO: ++ return me4000_get_user_info((me4000_user_info_t *) arg, ++ ai_context->board_info); ++ case ME4000_AI_GET_COUNT_BUFFER: ++ return me4000_ai_get_count_buffer((unsigned long *)arg, ++ ai_context); ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_ai_ioctl_ext():Invalid service number %d\n", ++ service); ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_ai_fasync(int fd, struct file *file_p, int mode) ++{ ++ me4000_ai_context_t *ai_context; ++ ++ CALL_PDEBUG("me4000_ao_fasync_cont() is executed\n"); ++ ++ ai_context = file_p->private_data; ++ return fasync_helper(fd, file_p, mode, &ai_context->fasync_p); ++} ++ ++static int me4000_ai_config(me4000_ai_config_t * arg, ++ me4000_ai_context_t * ai_context) ++{ ++ me4000_ai_config_t cmd; ++ u32 *list = NULL; ++ u32 mode; ++ int i; ++ int err; ++ wait_queue_head_t queue; ++ u64 scan; ++ u32 tmp; ++ ++ CALL_PDEBUG("me4000_ai_config() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* Check if conversion is stopped */ ++ if (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Conversion is not stopped\n"); ++ err = -EBUSY; ++ goto AI_CONFIG_ERR; ++ } ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_config_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Can't copy from user space\n"); ++ err = -EFAULT; ++ goto AI_CONFIG_ERR; ++ } ++ ++ PDEBUG ++ ("me4000_ai_config():chan = %ld, pre_chan = %ld, scan_low = %ld, scan_high = %ld, count = %ld\n", ++ cmd.timer.chan, cmd.timer.pre_chan, cmd.timer.scan_low, ++ cmd.timer.scan_high, cmd.channel_list.count); ++ ++ /* Check whether sample and hold is available for this board */ ++ if (cmd.sh) { ++ if (!ai_context->board_info->board_p->ai.sh_count) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Sample and Hold is not available for this board\n"); ++ err = -ENODEV; ++ goto AI_CONFIG_ERR; ++ } ++ } ++ ++ /* Check the channel list size */ ++ if (cmd.channel_list.count > ME4000_AI_CHANNEL_LIST_COUNT) { ++ printk(KERN_ERR ++ "me4000_ai_config():Channel list is to large\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ ++ /* Copy channel list from user */ ++ list = kmalloc(sizeof(u32) * cmd.channel_list.count, GFP_KERNEL); ++ if (!list) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Can't get memory for channel list\n"); ++ err = -ENOMEM; ++ goto AI_CONFIG_ERR; ++ } ++ err = ++ copy_from_user(list, cmd.channel_list.list, ++ sizeof(u32) * cmd.channel_list.count); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Can't copy from user space\n"); ++ err = -EFAULT; ++ goto AI_CONFIG_ERR; ++ } ++ ++ /* Check if last entry bit is set */ ++ if (!(list[cmd.channel_list.count - 1] & ME4000_AI_LIST_LAST_ENTRY)) { ++ printk(KERN_WARNING ++ "me4000_ai_config():Last entry bit is not set\n"); ++ list[cmd.channel_list.count - 1] |= ME4000_AI_LIST_LAST_ENTRY; ++ } ++ ++ /* Check whether mode is equal for all entries */ ++ mode = list[0] & 0x20; ++ for (i = 0; i < cmd.channel_list.count; i++) { ++ if ((list[i] & 0x20) != mode) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Mode is not equal for all entries\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ } ++ ++ /* Check whether channels are available for this mode */ ++ if (mode == ME4000_AI_LIST_INPUT_SINGLE_ENDED) { ++ for (i = 0; i < cmd.channel_list.count; i++) { ++ if ((list[i] & 0x1F) >= ++ ai_context->board_info->board_p->ai.count) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Channel is not available for single ended\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ } ++ } else if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) { ++ for (i = 0; i < cmd.channel_list.count; i++) { ++ if ((list[i] & 0x1F) >= ++ ai_context->board_info->board_p->ai.diff_count) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Channel is not available for differential\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ } ++ } ++ ++ /* Check if bipolar is set for all entries when in differential mode */ ++ if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) { ++ for (i = 0; i < cmd.channel_list.count; i++) { ++ if ((list[i] & 0xC0) != ME4000_AI_LIST_RANGE_BIPOLAR_10 ++ && (list[i] & 0xC0) != ++ ME4000_AI_LIST_RANGE_BIPOLAR_2_5) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Bipolar is not selected in differential mode\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ } ++ } ++ ++ if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE) { ++ /* Check for minimum channel divisor */ ++ if (cmd.timer.chan < ME4000_AI_MIN_TICKS) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Channel timer divisor is to low\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ ++ /* Check if minimum channel divisor is adjusted when sample and hold is activated */ ++ if ((cmd.sh) && (cmd.timer.chan != ME4000_AI_MIN_TICKS)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Channel timer divisor must be at minimum when sample and hold is activated\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ ++ /* Check for minimum channel pre divisor */ ++ if (cmd.timer.pre_chan < ME4000_AI_MIN_TICKS) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Channel pre timer divisor is to low\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ ++ /* Write the channel timers */ ++ me4000_outl(cmd.timer.chan - 1, ai_context->chan_timer_reg); ++ me4000_outl(cmd.timer.pre_chan - 1, ++ ai_context->chan_pre_timer_reg); ++ ++ /* Save the timer values in the board context */ ++ ai_context->chan_timer = cmd.timer.chan; ++ ai_context->chan_pre_timer = cmd.timer.pre_chan; ++ ++ if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST) { ++ /* Check for scan timer divisor */ ++ scan = ++ (u64) cmd.timer.scan_low | ((u64) cmd.timer. ++ scan_high << 32); ++ if (scan != 0) { ++ if (scan < ++ cmd.channel_list.count * cmd.timer.chan + ++ 1) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_config():Scan timer divisor is to low\n"); ++ err = -EINVAL; ++ goto AI_CONFIG_ERR; ++ } ++ } ++ ++ /* Write the scan timers */ ++ if (scan != 0) { ++ scan--; ++ tmp = (u32) (scan & 0xFFFFFFFF); ++ me4000_outl(tmp, ++ ai_context->scan_timer_low_reg); ++ tmp = (u32) ((scan >> 32) & 0xFFFFFFFF); ++ me4000_outl(tmp, ++ ai_context->scan_timer_high_reg); ++ ++ scan = ++ scan - (cmd.timer.chan - 1) + ++ (cmd.timer.pre_chan - 1); ++ tmp = (u32) (scan & 0xFFFFFFFF); ++ me4000_outl(tmp, ++ ai_context->scan_pre_timer_low_reg); ++ tmp = (u32) ((scan >> 32) & 0xFFFFFFFF); ++ me4000_outl(tmp, ++ ai_context-> ++ scan_pre_timer_high_reg); ++ } else { ++ me4000_outl(0x0, ++ ai_context->scan_timer_low_reg); ++ me4000_outl(0x0, ++ ai_context->scan_timer_high_reg); ++ ++ me4000_outl(0x0, ++ ai_context->scan_pre_timer_low_reg); ++ me4000_outl(0x0, ++ ai_context-> ++ scan_pre_timer_high_reg); ++ } ++ ++ ai_context->scan_timer_low = cmd.timer.scan_low; ++ ai_context->scan_timer_high = cmd.timer.scan_high; ++ } ++ } ++ ++ /* Clear the channel list */ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_CHANNEL_FIFO; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ /* Write the channel list */ ++ for (i = 0; i < cmd.channel_list.count; i++) { ++ me4000_outl(list[i], ai_context->channel_list_reg); ++ } ++ ++ /* Setup sample and hold */ ++ if (cmd.sh) { ++ tmp |= ME4000_AI_CTRL_BIT_SAMPLE_HOLD; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ } else { ++ tmp &= ~ME4000_AI_CTRL_BIT_SAMPLE_HOLD; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ } ++ ++ /* Save the channel list size in the board context */ ++ ai_context->channel_list_count = cmd.channel_list.count; ++ ++ kfree(list); ++ ++ return 0; ++ ++ AI_CONFIG_ERR: ++ ++ /* Reset the timers */ ++ ai_context->chan_timer = 66; ++ ai_context->chan_pre_timer = 66; ++ ai_context->scan_timer_low = 0; ++ ai_context->scan_timer_high = 0; ++ ++ me4000_outl(65, ai_context->chan_timer_reg); ++ me4000_outl(65, ai_context->chan_pre_timer_reg); ++ me4000_outl(0, ai_context->scan_timer_high_reg); ++ me4000_outl(0, ai_context->scan_timer_low_reg); ++ me4000_outl(0, ai_context->scan_pre_timer_high_reg); ++ me4000_outl(0, ai_context->scan_pre_timer_low_reg); ++ ++ ai_context->channel_list_count = 0; ++ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_SAMPLE_HOLD); ++ ++ if (list) ++ kfree(list); ++ ++ return err; ++ ++} ++ ++static int ai_common_start(me4000_ai_context_t * ai_context) ++{ ++ u32 tmp; ++ CALL_PDEBUG("ai_common_start() is executed\n"); ++ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ ++ /* Check if conversion is stopped */ ++ if (tmp & ME4000_AI_STATUS_BIT_FSM) { ++ printk(KERN_ERR ++ "ME4000:ai_common_start():Conversion is not stopped\n"); ++ return -EBUSY; ++ } ++ ++ /* Clear data fifo, disable all interrupts, clear sample counter reload */ ++ tmp &= ~(ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_LE_IRQ | ++ ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_SC_RELOAD); ++ ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ /* Clear circular buffer */ ++ ai_context->circ_buf.head = 0; ++ ai_context->circ_buf.tail = 0; ++ ++ /* Enable data fifo */ ++ tmp |= ME4000_AI_CTRL_BIT_DATA_FIFO; ++ ++ /* Determine interrupt setup */ ++ if (ai_context->sample_counter && !ai_context->sample_counter_reload) { ++ /* Enable Half Full Interrupt and Sample Counter Interrupt */ ++ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ; ++ } else if (ai_context->sample_counter ++ && ai_context->sample_counter_reload) { ++ if (ai_context->sample_counter <= ME4000_AI_FIFO_COUNT / 2) { ++ /* Enable only Sample Counter Interrupt */ ++ tmp |= ++ ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_SC_RELOAD; ++ } else { ++ /* Enable Half Full Interrupt and Sample Counter Interrupt */ ++ tmp |= ++ ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_HF_IRQ | ++ ME4000_AI_CTRL_BIT_SC_RELOAD; ++ } ++ } else { ++ /* Enable only Half Full Interrupt */ ++ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; ++ } ++ ++ /* Clear the stop bits */ ++ tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); ++ ++ /* Write setup to hardware */ ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ /* Write sample counter */ ++ me4000_outl(ai_context->sample_counter, ai_context->sample_counter_reg); ++ ++ return 0; ++} ++ ++static int me4000_ai_start(me4000_ai_context_t * ai_context) ++{ ++ int err; ++ CALL_PDEBUG("me4000_ai_start() is executed\n"); ++ ++ /* Prepare Hardware */ ++ err = ai_common_start(ai_context); ++ if (err) ++ return err; ++ ++ /* Start conversion by dummy read */ ++ me4000_inl(ai_context->start_reg); ++ ++ return 0; ++} ++ ++static int me4000_ai_start_ex(unsigned long *arg, ++ me4000_ai_context_t * ai_context) ++{ ++ int err; ++ wait_queue_head_t queue; ++ unsigned long ref; ++ unsigned long timeout; ++ ++ CALL_PDEBUG("me4000_ai_start_ex() is executed\n"); ++ ++ if (get_user(timeout, arg)) { ++ printk(KERN_ERR ++ "me4000_ai_start_ex():Cannot copy data from user\n"); ++ return -EFAULT; ++ } ++ ++ init_waitqueue_head(&queue); ++ ++ /* Prepare Hardware */ ++ err = ai_common_start(ai_context); ++ if (err) ++ return err; ++ ++ if (timeout) { ++ ref = jiffies; ++ while (! ++ (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) ++ { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n"); ++ return -EINTR; ++ } ++ if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space ++ printk(KERN_ERR ++ "ME4000:me4000_ai_start_ex():Timeout reached\n"); ++ return -EIO; ++ } ++ } ++ } else { ++ while (! ++ (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) ++ { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n"); ++ return -EINTR; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int me4000_ai_stop(me4000_ai_context_t * ai_context) ++{ ++ wait_queue_head_t queue; ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ai_stop() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* Disable irqs and clear data fifo */ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_DATA_FIFO); ++ /* Stop conversion of the state machine */ ++ tmp |= ME4000_AI_CTRL_BIT_STOP; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ ++ /* Clear circular buffer */ ++ ai_context->circ_buf.head = 0; ++ ai_context->circ_buf.tail = 0; ++ ++ while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n"); ++ return -EINTR; ++ } ++ } ++ ++ return 0; ++} ++ ++static int me4000_ai_immediate_stop(me4000_ai_context_t * ai_context) ++{ ++ wait_queue_head_t queue; ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ai_stop() is executed\n"); ++ ++ init_waitqueue_head(&queue); ++ ++ /* Disable irqs and clear data fifo */ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_DATA_FIFO); ++ /* Stop conversion of the state machine */ ++ tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ ++ /* Clear circular buffer */ ++ ai_context->circ_buf.head = 0; ++ ai_context->circ_buf.tail = 0; ++ ++ while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) { ++ interruptible_sleep_on_timeout(&queue, 1); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n"); ++ return -EINTR; ++ } ++ } ++ ++ return 0; ++} ++ ++static int me4000_ai_ex_trig_enable(me4000_ai_context_t * ai_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ai_ex_trig_enable() is executed\n"); ++ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_EX_TRIG; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ai_ex_trig_disable(me4000_ai_context_t * ai_context) ++{ ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ai_ex_trig_disable() is executed\n"); ++ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ ++ return 0; ++} ++ ++static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg, ++ me4000_ai_context_t * ai_context) ++{ ++ me4000_ai_trigger_t cmd; ++ int err; ++ u32 tmp; ++ unsigned long flags; ++ ++ CALL_PDEBUG("me4000_ai_ex_trig_setup() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_trigger_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_ex_trig_setup():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ ++ if (cmd.mode == ME4000_AI_TRIGGER_EXT_DIGITAL) { ++ tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG; ++ } else if (cmd.mode == ME4000_AI_TRIGGER_EXT_ANALOG) { ++ if (!ai_context->board_info->board_p->ai.ex_trig_analog) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_ex_trig_setup():No analog trigger available\n"); ++ return -EINVAL; ++ } ++ tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG; ++ } else { ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ printk(KERN_ERR ++ "ME4000:me4000_ai_ex_trig_setup():Invalid trigger mode specified\n"); ++ return -EINVAL; ++ } ++ ++ if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_RISING) { ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_EX_TRIG_BOTH | ++ ME4000_AI_CTRL_BIT_EX_TRIG_FALLING); ++ } else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_FALLING) { ++ tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_FALLING; ++ tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_BOTH; ++ } else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_BOTH) { ++ tmp |= ++ ME4000_AI_CTRL_BIT_EX_TRIG_BOTH | ++ ME4000_AI_CTRL_BIT_EX_TRIG_FALLING; ++ } else { ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ printk(KERN_ERR ++ "ME4000:me4000_ai_ex_trig_setup():Invalid trigger edge specified\n"); ++ return -EINVAL; ++ } ++ ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ return 0; ++} ++ ++static int me4000_ai_sc_setup(me4000_ai_sc_t * arg, ++ me4000_ai_context_t * ai_context) ++{ ++ me4000_ai_sc_t cmd; ++ int err; ++ ++ CALL_PDEBUG("me4000_ai_sc_setup() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_sc_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_sc_setup():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ ai_context->sample_counter = cmd.value; ++ ai_context->sample_counter_reload = cmd.reload; ++ ++ return 0; ++} ++ ++static ssize_t me4000_ai_read(struct file *filep, char *buff, size_t cnt, ++ loff_t * offp) ++{ ++ me4000_ai_context_t *ai_context = filep->private_data; ++ s16 *buffer = (s16 *) buff; ++ size_t count = cnt / 2; ++ unsigned long flags; ++ int tmp; ++ int c = 0; ++ int k = 0; ++ int ret = 0; ++ wait_queue_t wait; ++ ++ CALL_PDEBUG("me4000_ai_read() is executed\n"); ++ ++ init_waitqueue_entry(&wait, current); ++ ++ /* Check count */ ++ if (count <= 0) { ++ PDEBUG("me4000_ai_read():Count is 0\n"); ++ return 0; ++ } ++ ++ while (count > 0) { ++ if (filep->f_flags & O_NONBLOCK) { ++ c = me4000_values_to_end(ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT); ++ if (!c) { ++ PDEBUG ++ ("me4000_ai_read():Returning from nonblocking read\n"); ++ break; ++ } ++ } else { ++ /* Check if conversion is still running */ ++ if (! ++ (me4000_inl(ai_context->status_reg) & ++ ME4000_AI_STATUS_BIT_FSM)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_read():Conversion interrupted\n"); ++ return -EPIPE; ++ } ++ ++ wait_event_interruptible(ai_context->wait_queue, ++ (me4000_values_to_end ++ (ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT))); ++ if (signal_pending(current)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_read():Wait on values interrupted from signal\n"); ++ return -EINTR; ++ } ++ } ++ ++ /* Only read count values or as much as available */ ++ c = me4000_values_to_end(ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT); ++ PDEBUG("me4000_ai_read():%d values to end\n", c); ++ if (count < c) ++ c = count; ++ ++ PDEBUG("me4000_ai_read():Copy %d values to user space\n", c); ++ k = 2 * c; ++ k -= copy_to_user(buffer, ++ ai_context->circ_buf.buf + ++ ai_context->circ_buf.tail, k); ++ c = k / 2; ++ if (!c) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_read():Cannot copy new values to user\n"); ++ return -EFAULT; ++ } ++ ++ ai_context->circ_buf.tail = ++ (ai_context->circ_buf.tail + c) & (ME4000_AI_BUFFER_COUNT - ++ 1); ++ buffer += c; ++ count -= c; ++ ret += c; ++ ++ spin_lock_irqsave(&ai_context->int_lock, flags); ++ if (me4000_buf_space ++ (ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) { ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ ++ /* Determine interrupt setup */ ++ if (ai_context->sample_counter ++ && !ai_context->sample_counter_reload) { ++ /* Enable Half Full Interrupt and Sample Counter Interrupt */ ++ tmp |= ++ ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_HF_IRQ; ++ } else if (ai_context->sample_counter ++ && ai_context->sample_counter_reload) { ++ if (ai_context->sample_counter < ++ ME4000_AI_FIFO_COUNT / 2) { ++ /* Enable only Sample Counter Interrupt */ ++ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ; ++ } else { ++ /* Enable Half Full Interrupt and Sample Counter Interrupt */ ++ tmp |= ++ ME4000_AI_CTRL_BIT_SC_IRQ | ++ ME4000_AI_CTRL_BIT_HF_IRQ; ++ } ++ } else { ++ /* Enable only Half Full Interrupt */ ++ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; ++ } ++ ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ } ++ spin_unlock_irqrestore(&ai_context->int_lock, flags); ++ } ++ ++ /* Check if conversion is still running */ ++ if (!(me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_read():Conversion not running after complete read\n"); ++ return -EPIPE; ++ } ++ ++ if (filep->f_flags & O_NONBLOCK) { ++ return (k == 0) ? -EAGAIN : 2 * ret; ++ } ++ ++ CALL_PDEBUG("me4000_ai_read() is leaved\n"); ++ return ret * 2; ++} ++ ++static unsigned int me4000_ai_poll(struct file *file_p, poll_table * wait) ++{ ++ me4000_ai_context_t *ai_context; ++ unsigned long mask = 0; ++ ++ CALL_PDEBUG("me4000_ai_poll() is executed\n"); ++ ++ ai_context = file_p->private_data; ++ ++ /* Register wait queue */ ++ poll_wait(file_p, &ai_context->wait_queue, wait); ++ ++ /* Get available values */ ++ if (me4000_values_to_end(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ PDEBUG("me4000_ai_poll():Return mask %lX\n", mask); ++ ++ return mask; ++} ++ ++static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ai_offset_enable() is executed\n"); ++ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_OFFSET; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ai_offset_disable() is executed\n"); ++ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_OFFSET; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ai_fullscale_enable() is executed\n"); ++ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_FULLSCALE; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ai_fullscale_disable() is executed\n"); ++ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_FULLSCALE; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ai_fsm_state() is executed\n"); ++ ++ tmp = ++ (me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) ? 1 ++ : 0; ++ ++ if (put_user(tmp, arg)) { ++ printk(KERN_ERR "me4000_ai_fsm_state():Cannot copy to user\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int me4000_ai_get_count_buffer(unsigned long *arg, ++ me4000_ai_context_t * ai_context) ++{ ++ unsigned long c; ++ int err; ++ ++ c = me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT); ++ ++ err = copy_to_user(arg, &c, sizeof(unsigned long)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_ai_get_count_buffer():Can't copy to user space\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++/*---------------------------------- EEPROM stuff ---------------------------*/ ++ ++static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd, ++ int length) ++{ ++ int i; ++ unsigned long value; ++ ++ CALL_PDEBUG("eeprom_write_cmd() is executed\n"); ++ ++ PDEBUG("eeprom_write_cmd():Write command 0x%08lX with length = %d\n", ++ cmd, length); ++ ++ /* Get the ICR register and clear the related bits */ ++ value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR); ++ value &= ~(PLX_ICR_MASK_EEPROM); ++ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); ++ ++ /* Raise the chip select */ ++ value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT; ++ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ for (i = 0; i < length; i++) { ++ if (cmd & ((0x1 << (length - 1)) >> i)) { ++ value |= PLX_ICR_BIT_EEPROM_WRITE; ++ } else { ++ value &= ~PLX_ICR_BIT_EEPROM_WRITE; ++ } ++ ++ /* Write to EEPROM */ ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ /* Raising edge of the clock */ ++ value |= PLX_ICR_BIT_EEPROM_CLOCK_SET; ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ /* Falling edge of the clock */ ++ value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET; ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ } ++ ++ /* Clear the chip select */ ++ value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT; ++ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ /* Wait until hardware is ready for sure */ ++ mdelay(10); ++ ++ return 0; ++} ++ ++static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context, ++ unsigned long cmd, int length) ++{ ++ int i; ++ unsigned long value; ++ unsigned short id = 0; ++ ++ CALL_PDEBUG("eeprom_read_cmd() is executed\n"); ++ ++ PDEBUG("eeprom_read_cmd():Read command 0x%08lX with length = %d\n", cmd, ++ length); ++ ++ /* Get the ICR register and clear the related bits */ ++ value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR); ++ value &= ~(PLX_ICR_MASK_EEPROM); ++ ++ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); ++ ++ /* Raise the chip select */ ++ value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT; ++ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ /* Write the read command to the eeprom */ ++ for (i = 0; i < length; i++) { ++ if (cmd & ((0x1 << (length - 1)) >> i)) { ++ value |= PLX_ICR_BIT_EEPROM_WRITE; ++ } else { ++ value &= ~PLX_ICR_BIT_EEPROM_WRITE; ++ } ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ /* Raising edge of the clock */ ++ value |= PLX_ICR_BIT_EEPROM_CLOCK_SET; ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ /* Falling edge of the clock */ ++ value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET; ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ } ++ ++ /* Read the value from the eeprom */ ++ for (i = 0; i < 16; i++) { ++ /* Raising edge of the clock */ ++ value |= PLX_ICR_BIT_EEPROM_CLOCK_SET; ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ if (me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR) & ++ PLX_ICR_BIT_EEPROM_READ) { ++ id |= (0x8000 >> i); ++ PDEBUG("eeprom_read_cmd():OR with 0x%04X\n", ++ (0x8000 >> i)); ++ } else { ++ PDEBUG("eeprom_read_cmd():Dont't OR\n"); ++ } ++ ++ /* Falling edge of the clock */ ++ value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET; ++ me4000_outl(value, ++ ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ } ++ ++ /* Clear the chip select */ ++ value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT; ++ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR); ++ udelay(EEPROM_DELAY); ++ ++ return id; ++} ++ ++static int me4000_eeprom_write(me4000_eeprom_t * arg, ++ me4000_ai_context_t * ai_context) ++{ ++ int err; ++ me4000_eeprom_t setup; ++ unsigned long cmd; ++ unsigned long date_high; ++ unsigned long date_low; ++ ++ CALL_PDEBUG("me4000_eeprom_write() is executed\n"); ++ ++ err = copy_from_user(&setup, arg, sizeof(setup)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_eeprom_write():Cannot copy from user\n"); ++ return err; ++ } ++ ++ /* Enable writing */ ++ eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_ENABLE, ++ ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE); ++ ++ /* Command for date */ ++ date_high = (setup.date & 0xFFFF0000) >> 16; ++ date_low = (setup.date & 0x0000FFFF); ++ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_HIGH << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ date_high); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_LOW << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ date_low); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for unipolar 10V offset */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ uni_10_offset); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for unipolar 10V fullscale */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ uni_10_fullscale); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for unipolar 2,5V offset */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ uni_2_5_offset); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for unipolar 2,5V fullscale */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ uni_2_5_fullscale); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for bipolar 10V offset */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ bi_10_offset); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for bipolar 10V fullscale */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ bi_10_fullscale); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for bipolar 2,5V offset */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ bi_2_5_offset); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for bipolar 2,5V fullscale */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ bi_2_5_fullscale); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for differential 10V offset */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ diff_10_offset); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for differential 10V fullscale */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE ++ << ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ diff_10_fullscale); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for differential 2,5V offset */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET << ++ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ diff_2_5_offset); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Command for differential 2,5V fullscale */ ++ cmd = ++ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE ++ << ME4000_EEPROM_DATA_LENGTH) | (0xFFFF & ++ (unsigned ++ long) ++ setup. ++ diff_2_5_fullscale); ++ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE); ++ if (err) ++ return err; ++ ++ /* Disable writing */ ++ eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_DISABLE, ++ ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE); ++ ++ return 0; ++} ++ ++static int me4000_eeprom_read(me4000_eeprom_t * arg, ++ me4000_ai_context_t * ai_context) ++{ ++ int err; ++ unsigned long cmd; ++ me4000_eeprom_t setup; ++ ++ CALL_PDEBUG("me4000_eeprom_read() is executed\n"); ++ ++ /* Command for date */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_HIGH; ++ setup.date = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ setup.date <<= 16; ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_LOW; ++ setup.date |= ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for unipolar 10V offset */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET; ++ setup.uni_10_offset = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for unipolar 10V fullscale */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE; ++ setup.uni_10_fullscale = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for unipolar 2,5V offset */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET; ++ setup.uni_2_5_offset = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for unipolar 2,5V fullscale */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE; ++ setup.uni_2_5_fullscale = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for bipolar 10V offset */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET; ++ setup.bi_10_offset = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for bipolar 10V fullscale */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE; ++ setup.bi_10_fullscale = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for bipolar 2,5V offset */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET; ++ setup.bi_2_5_offset = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for bipolar 2,5V fullscale */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE; ++ setup.bi_2_5_fullscale = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for differntial 10V offset */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET; ++ setup.diff_10_offset = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for differential 10V fullscale */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE; ++ setup.diff_10_fullscale = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for differntial 2,5V offset */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET; ++ setup.diff_2_5_offset = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ /* Command for differential 2,5V fullscale */ ++ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE; ++ setup.diff_2_5_fullscale = ++ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ); ++ ++ err = copy_to_user(arg, &setup, sizeof(setup)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_eeprom_read():Cannot copy to user\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/*------------------------------------ DIO stuff ----------------------------------------------*/ ++ ++static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_dio_context_t *dio_context; ++ ++ CALL_PDEBUG("me4000_dio_ioctl() is executed\n"); ++ ++ dio_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n"); ++ return -ENOTTY; ++ } ++ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { ++ printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n"); ++ return -ENOTTY; ++ } ++ ++ switch (service) { ++ case ME4000_DIO_CONFIG: ++ return me4000_dio_config((me4000_dio_config_t *) arg, ++ dio_context); ++ case ME4000_DIO_SET_BYTE: ++ return me4000_dio_set_byte((me4000_dio_byte_t *) arg, ++ dio_context); ++ case ME4000_DIO_GET_BYTE: ++ return me4000_dio_get_byte((me4000_dio_byte_t *) arg, ++ dio_context); ++ case ME4000_DIO_RESET: ++ return me4000_dio_reset(dio_context); ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_dio_ioctl():Invalid service number %d\n", ++ service); ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_dio_config(me4000_dio_config_t * arg, ++ me4000_dio_context_t * dio_context) ++{ ++ me4000_dio_config_t cmd; ++ u32 tmp; ++ int err; ++ ++ CALL_PDEBUG("me4000_dio_config() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_dio_config_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Check port parameter */ ++ if (cmd.port >= dio_context->dio_count) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Port %d is not available\n", ++ cmd.port); ++ return -EINVAL; ++ } ++ ++ PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port, ++ cmd.mode, cmd.function); ++ ++ if (cmd.port == ME4000_DIO_PORT_A) { ++ if (cmd.mode == ME4000_DIO_PORT_INPUT) { ++ /* Check if opto isolated version */ ++ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Cannot set to input on opto isolated versions\n"); ++ return -EIO; ++ } ++ ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_0 | ++ ME4000_DIO_CTRL_BIT_MODE_1); ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_0 | ++ ME4000_DIO_CTRL_BIT_MODE_1); ++ tmp |= ME4000_DIO_CTRL_BIT_MODE_0; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_0 | ++ ME4000_DIO_CTRL_BIT_MODE_1 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_0); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_0 | ++ ME4000_DIO_CTRL_BIT_MODE_1; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_0 | ++ ME4000_DIO_CTRL_BIT_MODE_1 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_0; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Mode %d is not available\n", ++ cmd.mode); ++ return -EINVAL; ++ } ++ } else if (cmd.port == ME4000_DIO_PORT_B) { ++ if (cmd.mode == ME4000_DIO_PORT_INPUT) { ++ /* Only do anything when TTL version is installed */ ++ if ((me4000_inl(dio_context->dir_reg) & 0x1)) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_2 | ++ ME4000_DIO_CTRL_BIT_MODE_3); ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } ++ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { ++ /* Check if opto isolated version */ ++ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Cannot set to output on opto isolated versions\n"); ++ return -EIO; ++ } ++ ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_2 | ++ ME4000_DIO_CTRL_BIT_MODE_3); ++ tmp |= ME4000_DIO_CTRL_BIT_MODE_2; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { ++ /* Check if opto isolated version */ ++ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Cannot set to FIFO low output on opto isolated versions\n"); ++ return -EIO; ++ } ++ ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_2 | ++ ME4000_DIO_CTRL_BIT_MODE_3 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_1); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_2 | ++ ME4000_DIO_CTRL_BIT_MODE_3; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { ++ /* Check if opto isolated version */ ++ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Cannot set to FIFO high output on opto isolated versions\n"); ++ return -EIO; ++ } ++ ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_2 | ++ ME4000_DIO_CTRL_BIT_MODE_3 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_1; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Mode %d is not available\n", ++ cmd.mode); ++ return -EINVAL; ++ } ++ } else if (cmd.port == ME4000_DIO_PORT_C) { ++ if (cmd.mode == ME4000_DIO_PORT_INPUT) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_4 | ++ ME4000_DIO_CTRL_BIT_MODE_5); ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_4 | ++ ME4000_DIO_CTRL_BIT_MODE_5); ++ tmp |= ME4000_DIO_CTRL_BIT_MODE_4; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_4 | ++ ME4000_DIO_CTRL_BIT_MODE_5 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_2); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_4 | ++ ME4000_DIO_CTRL_BIT_MODE_5; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_4 | ++ ME4000_DIO_CTRL_BIT_MODE_5 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_2; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Mode %d is not available\n", ++ cmd.mode); ++ return -EINVAL; ++ } ++ } else if (cmd.port == ME4000_DIO_PORT_D) { ++ if (cmd.mode == ME4000_DIO_PORT_INPUT) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_6 | ++ ME4000_DIO_CTRL_BIT_MODE_7); ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_6 | ++ ME4000_DIO_CTRL_BIT_MODE_7); ++ tmp |= ME4000_DIO_CTRL_BIT_MODE_6; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_MODE_6 | ++ ME4000_DIO_CTRL_BIT_MODE_7 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_3); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_6 | ++ ME4000_DIO_CTRL_BIT_MODE_7; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp |= ++ ME4000_DIO_CTRL_BIT_MODE_6 | ++ ME4000_DIO_CTRL_BIT_MODE_7 | ++ ME4000_DIO_CTRL_BIT_FIFO_HIGH_3; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Mode %d is not available\n", ++ cmd.mode); ++ return -EINVAL; ++ } ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Port %d is not available\n", ++ cmd.port); ++ return -EINVAL; ++ } ++ ++ PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port, ++ cmd.mode, cmd.function); ++ ++ if ((cmd.mode == ME4000_DIO_FIFO_HIGH) ++ || (cmd.mode == ME4000_DIO_FIFO_LOW)) { ++ tmp = me4000_inl(dio_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_DIO_CTRL_BIT_FUNCTION_0 | ++ ME4000_DIO_CTRL_BIT_FUNCTION_1); ++ if (cmd.function == ME4000_DIO_FUNCTION_PATTERN) { ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.function == ME4000_DIO_FUNCTION_DEMUX) { ++ tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_0; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else if (cmd.function == ME4000_DIO_FUNCTION_MUX) { ++ tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_1; ++ me4000_outl(tmp, dio_context->ctrl_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_config():Invalid port function specified\n"); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int me4000_dio_set_byte(me4000_dio_byte_t * arg, ++ me4000_dio_context_t * dio_context) ++{ ++ me4000_dio_byte_t cmd; ++ int err; ++ ++ CALL_PDEBUG("me4000_dio_set_byte() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Check port parameter */ ++ if (cmd.port >= dio_context->dio_count) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Port %d is not available\n", ++ cmd.port); ++ return -EINVAL; ++ } ++ ++ if (cmd.port == ME4000_DIO_PORT_A) { ++ if ((me4000_inl(dio_context->ctrl_reg) & 0x3) != 0x1) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", ++ cmd.port); ++ return -EIO; ++ } ++ me4000_outl(cmd.byte, dio_context->port_0_reg); ++ } else if (cmd.port == ME4000_DIO_PORT_B) { ++ if ((me4000_inl(dio_context->ctrl_reg) & 0xC) != 0x4) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", ++ cmd.port); ++ return -EIO; ++ } ++ me4000_outl(cmd.byte, dio_context->port_1_reg); ++ } else if (cmd.port == ME4000_DIO_PORT_C) { ++ if ((me4000_inl(dio_context->ctrl_reg) & 0x30) != 0x10) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", ++ cmd.port); ++ return -EIO; ++ } ++ me4000_outl(cmd.byte, dio_context->port_2_reg); ++ } else if (cmd.port == ME4000_DIO_PORT_D) { ++ if ((me4000_inl(dio_context->ctrl_reg) & 0xC0) != 0x40) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n", ++ cmd.port); ++ return -EIO; ++ } ++ me4000_outl(cmd.byte, dio_context->port_3_reg); ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_set_byte():Port %d is not available\n", ++ cmd.port); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int me4000_dio_get_byte(me4000_dio_byte_t * arg, ++ me4000_dio_context_t * dio_context) ++{ ++ me4000_dio_byte_t cmd; ++ int err; ++ ++ CALL_PDEBUG("me4000_dio_get_byte() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_get_byte():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Check port parameter */ ++ if (cmd.port >= dio_context->dio_count) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_get_byte():Port %d is not available\n", ++ cmd.port); ++ return -EINVAL; ++ } ++ ++ if (cmd.port == ME4000_DIO_PORT_A) { ++ cmd.byte = me4000_inl(dio_context->port_0_reg) & 0xFF; ++ } else if (cmd.port == ME4000_DIO_PORT_B) { ++ cmd.byte = me4000_inl(dio_context->port_1_reg) & 0xFF; ++ } else if (cmd.port == ME4000_DIO_PORT_C) { ++ cmd.byte = me4000_inl(dio_context->port_2_reg) & 0xFF; ++ } else if (cmd.port == ME4000_DIO_PORT_D) { ++ cmd.byte = me4000_inl(dio_context->port_3_reg) & 0xFF; ++ } else { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_get_byte():Port %d is not available\n", ++ cmd.port); ++ return -EINVAL; ++ } ++ ++ /* Copy result back to user */ ++ err = copy_to_user(arg, &cmd, sizeof(me4000_dio_byte_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_dio_get_byte():Can't copy to user space\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int me4000_dio_reset(me4000_dio_context_t * dio_context) ++{ ++ CALL_PDEBUG("me4000_dio_reset() is executed\n"); ++ ++ /* Clear the control register */ ++ me4000_outl(0, dio_context->ctrl_reg); ++ ++ /* Check for opto isolated version */ ++ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) { ++ me4000_outl(0x1, dio_context->ctrl_reg); ++ me4000_outl(0x0, dio_context->port_0_reg); ++ } ++ ++ return 0; ++} ++ ++/*------------------------------------ COUNTER STUFF ------------------------------------*/ ++ ++static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_cnt_context_t *cnt_context; ++ ++ CALL_PDEBUG("me4000_cnt_ioctl() is executed\n"); ++ ++ cnt_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n"); ++ return -ENOTTY; ++ } ++ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { ++ printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n"); ++ return -ENOTTY; ++ } ++ ++ switch (service) { ++ case ME4000_CNT_READ: ++ return me4000_cnt_read((me4000_cnt_t *) arg, cnt_context); ++ case ME4000_CNT_WRITE: ++ return me4000_cnt_write((me4000_cnt_t *) arg, cnt_context); ++ case ME4000_CNT_CONFIG: ++ return me4000_cnt_config((me4000_cnt_config_t *) arg, ++ cnt_context); ++ case ME4000_CNT_RESET: ++ return me4000_cnt_reset(cnt_context); ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_dio_ioctl():Invalid service number %d\n", ++ service); ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_cnt_config(me4000_cnt_config_t * arg, ++ me4000_cnt_context_t * cnt_context) ++{ ++ me4000_cnt_config_t cmd; ++ u8 counter; ++ u8 mode; ++ int err; ++ ++ CALL_PDEBUG("me4000_cnt_config() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_config_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_config():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Check counter parameter */ ++ switch (cmd.counter) { ++ case ME4000_CNT_COUNTER_0: ++ counter = ME4000_CNT_CTRL_BIT_COUNTER_0; ++ break; ++ case ME4000_CNT_COUNTER_1: ++ counter = ME4000_CNT_CTRL_BIT_COUNTER_1; ++ break; ++ case ME4000_CNT_COUNTER_2: ++ counter = ME4000_CNT_CTRL_BIT_COUNTER_2; ++ break; ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_config():Counter %d is not available\n", ++ cmd.counter); ++ return -EINVAL; ++ } ++ ++ /* Check mode parameter */ ++ switch (cmd.mode) { ++ case ME4000_CNT_MODE_0: ++ mode = ME4000_CNT_CTRL_BIT_MODE_0; ++ break; ++ case ME4000_CNT_MODE_1: ++ mode = ME4000_CNT_CTRL_BIT_MODE_1; ++ break; ++ case ME4000_CNT_MODE_2: ++ mode = ME4000_CNT_CTRL_BIT_MODE_2; ++ break; ++ case ME4000_CNT_MODE_3: ++ mode = ME4000_CNT_CTRL_BIT_MODE_3; ++ break; ++ case ME4000_CNT_MODE_4: ++ mode = ME4000_CNT_CTRL_BIT_MODE_4; ++ break; ++ case ME4000_CNT_MODE_5: ++ mode = ME4000_CNT_CTRL_BIT_MODE_5; ++ break; ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_config():Mode %d is not available\n", ++ cmd.mode); ++ return -EINVAL; ++ } ++ ++ /* Write the control word */ ++ me4000_outb((counter | mode | 0x30), cnt_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_cnt_read(me4000_cnt_t * arg, ++ me4000_cnt_context_t * cnt_context) ++{ ++ me4000_cnt_t cmd; ++ u8 tmp; ++ int err; ++ ++ CALL_PDEBUG("me4000_cnt_read() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_read():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Read counter */ ++ switch (cmd.counter) { ++ case ME4000_CNT_COUNTER_0: ++ tmp = me4000_inb(cnt_context->counter_0_reg); ++ cmd.value = tmp; ++ tmp = me4000_inb(cnt_context->counter_0_reg); ++ cmd.value |= ((u16) tmp) << 8; ++ break; ++ case ME4000_CNT_COUNTER_1: ++ tmp = me4000_inb(cnt_context->counter_1_reg); ++ cmd.value = tmp; ++ tmp = me4000_inb(cnt_context->counter_1_reg); ++ cmd.value |= ((u16) tmp) << 8; ++ break; ++ case ME4000_CNT_COUNTER_2: ++ tmp = me4000_inb(cnt_context->counter_2_reg); ++ cmd.value = tmp; ++ tmp = me4000_inb(cnt_context->counter_2_reg); ++ cmd.value |= ((u16) tmp) << 8; ++ break; ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_read():Counter %d is not available\n", ++ cmd.counter); ++ return -EINVAL; ++ } ++ ++ /* Copy result back to user */ ++ err = copy_to_user(arg, &cmd, sizeof(me4000_cnt_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_read():Can't copy to user space\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int me4000_cnt_write(me4000_cnt_t * arg, ++ me4000_cnt_context_t * cnt_context) ++{ ++ me4000_cnt_t cmd; ++ u8 tmp; ++ int err; ++ ++ CALL_PDEBUG("me4000_cnt_write() is executed\n"); ++ ++ /* Copy data from user */ ++ err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t)); ++ if (err) { ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_write():Can't copy from user space\n"); ++ return -EFAULT; ++ } ++ ++ /* Write counter */ ++ switch (cmd.counter) { ++ case ME4000_CNT_COUNTER_0: ++ tmp = cmd.value & 0xFF; ++ me4000_outb(tmp, cnt_context->counter_0_reg); ++ tmp = (cmd.value >> 8) & 0xFF; ++ me4000_outb(tmp, cnt_context->counter_0_reg); ++ break; ++ case ME4000_CNT_COUNTER_1: ++ tmp = cmd.value & 0xFF; ++ me4000_outb(tmp, cnt_context->counter_1_reg); ++ tmp = (cmd.value >> 8) & 0xFF; ++ me4000_outb(tmp, cnt_context->counter_1_reg); ++ break; ++ case ME4000_CNT_COUNTER_2: ++ tmp = cmd.value & 0xFF; ++ me4000_outb(tmp, cnt_context->counter_2_reg); ++ tmp = (cmd.value >> 8) & 0xFF; ++ me4000_outb(tmp, cnt_context->counter_2_reg); ++ break; ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_cnt_write():Counter %d is not available\n", ++ cmd.counter); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int me4000_cnt_reset(me4000_cnt_context_t * cnt_context) ++{ ++ CALL_PDEBUG("me4000_cnt_reset() is executed\n"); ++ ++ /* Set the mode and value for counter 0 */ ++ me4000_outb(0x30, cnt_context->ctrl_reg); ++ me4000_outb(0x00, cnt_context->counter_0_reg); ++ me4000_outb(0x00, cnt_context->counter_0_reg); ++ ++ /* Set the mode and value for counter 1 */ ++ me4000_outb(0x70, cnt_context->ctrl_reg); ++ me4000_outb(0x00, cnt_context->counter_1_reg); ++ me4000_outb(0x00, cnt_context->counter_1_reg); ++ ++ /* Set the mode and value for counter 2 */ ++ me4000_outb(0xB0, cnt_context->ctrl_reg); ++ me4000_outb(0x00, cnt_context->counter_2_reg); ++ me4000_outb(0x00, cnt_context->counter_2_reg); ++ ++ return 0; ++} ++ ++/*------------------------------------ External Interrupt stuff ------------------------------------*/ ++ ++static int me4000_ext_int_ioctl(struct inode *inode_p, struct file *file_p, ++ unsigned int service, unsigned long arg) ++{ ++ me4000_ext_int_context_t *ext_int_context; ++ ++ CALL_PDEBUG("me4000_ext_int_ioctl() is executed\n"); ++ ++ ext_int_context = file_p->private_data; ++ ++ if (_IOC_TYPE(service) != ME4000_MAGIC) { ++ printk(KERN_ERR "me4000_ext_int_ioctl():Wrong magic number\n"); ++ return -ENOTTY; ++ } ++ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) { ++ printk(KERN_ERR ++ "me4000_ext_int_ioctl():Service number to high\n"); ++ return -ENOTTY; ++ } ++ ++ switch (service) { ++ case ME4000_EXT_INT_ENABLE: ++ return me4000_ext_int_enable(ext_int_context); ++ case ME4000_EXT_INT_DISABLE: ++ return me4000_ext_int_disable(ext_int_context); ++ case ME4000_EXT_INT_COUNT: ++ return me4000_ext_int_count((unsigned long *)arg, ++ ext_int_context); ++ default: ++ printk(KERN_ERR ++ "ME4000:me4000_ext_int_ioctl():Invalid service number %d\n", ++ service); ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static int me4000_ext_int_enable(me4000_ext_int_context_t * ext_int_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ext_int_enable() is executed\n"); ++ ++ tmp = me4000_inl(ext_int_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_EX_IRQ; ++ me4000_outl(tmp, ext_int_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ext_int_disable(me4000_ext_int_context_t * ext_int_context) ++{ ++ unsigned long tmp; ++ ++ CALL_PDEBUG("me4000_ext_int_disable() is executed\n"); ++ ++ tmp = me4000_inl(ext_int_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ; ++ me4000_outl(tmp, ext_int_context->ctrl_reg); ++ ++ return 0; ++} ++ ++static int me4000_ext_int_count(unsigned long *arg, ++ me4000_ext_int_context_t * ext_int_context) ++{ ++ ++ CALL_PDEBUG("me4000_ext_int_count() is executed\n"); ++ ++ put_user(ext_int_context->int_count, arg); ++ return 0; ++} ++ ++/*------------------------------------ General stuff ------------------------------------*/ ++ ++static int me4000_get_user_info(me4000_user_info_t * arg, ++ me4000_info_t * board_info) ++{ ++ me4000_user_info_t user_info; ++ ++ CALL_PDEBUG("me4000_get_user_info() is executed\n"); ++ ++ user_info.board_count = board_info->board_count; ++ user_info.plx_regbase = board_info->plx_regbase; ++ user_info.plx_regbase_size = board_info->plx_regbase_size; ++ user_info.me4000_regbase = board_info->me4000_regbase; ++ user_info.me4000_regbase_size = board_info->me4000_regbase_size; ++ user_info.serial_no = board_info->serial_no; ++ user_info.hw_revision = board_info->hw_revision; ++ user_info.vendor_id = board_info->vendor_id; ++ user_info.device_id = board_info->device_id; ++ user_info.pci_bus_no = board_info->pci_bus_no; ++ user_info.pci_dev_no = board_info->pci_dev_no; ++ user_info.pci_func_no = board_info->pci_func_no; ++ user_info.irq = board_info->irq; ++ user_info.irq_count = board_info->irq_count; ++ user_info.driver_version = ME4000_DRIVER_VERSION; ++ user_info.ao_count = board_info->board_p->ao.count; ++ user_info.ao_fifo_count = board_info->board_p->ao.fifo_count; ++ ++ user_info.ai_count = board_info->board_p->ai.count; ++ user_info.ai_sh_count = board_info->board_p->ai.sh_count; ++ user_info.ai_ex_trig_analog = board_info->board_p->ai.ex_trig_analog; ++ ++ user_info.dio_count = board_info->board_p->dio.count; ++ ++ user_info.cnt_count = board_info->board_p->cnt.count; ++ ++ if (copy_to_user(arg, &user_info, sizeof(me4000_user_info_t))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/*------------------------------------ ISR STUFF ------------------------------------*/ ++ ++static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode) ++{ ++ int result = 0; ++ me4000_ext_int_context_t *ext_int_context; ++ ++ CALL_PDEBUG("me4000_ext_int_fasync() is executed\n"); ++ ++ ext_int_context = file_ptr->private_data; ++ ++ result = ++ fasync_helper(fd, file_ptr, mode, &ext_int_context->fasync_ptr); ++ ++ CALL_PDEBUG("me4000_ext_int_fasync() is leaved\n"); ++ return result; ++} ++ ++static irqreturn_t me4000_ao_isr(int irq, void *dev_id) ++{ ++ u32 tmp; ++ u32 value; ++ me4000_ao_context_t *ao_context; ++ int i; ++ int c = 0; ++ int c1 = 0; ++ //unsigned long before; ++ //unsigned long after; ++ ++ ISR_PDEBUG("me4000_ao_isr() is executed\n"); ++ ++ ao_context = dev_id; ++ ++ /* Check if irq number is right */ ++ if (irq != ao_context->irq) { ++ ISR_PDEBUG("me4000_ao_isr():incorrect interrupt num: %d\n", ++ irq); ++ return IRQ_NONE; ++ } ++ ++ /* Check if this DAC rised an interrupt */ ++ if (! ++ ((0x1 << (ao_context->index + 3)) & ++ me4000_inl(ao_context->irq_status_reg))) { ++ ISR_PDEBUG("me4000_ao_isr():Not this DAC\n"); ++ return IRQ_NONE; ++ } ++ ++ /* Read status register to find out what happened */ ++ tmp = me4000_inl(ao_context->status_reg); ++ ++ if (!(tmp & ME4000_AO_STATUS_BIT_EF) && (tmp & ME4000_AO_STATUS_BIT_HF) ++ && (tmp & ME4000_AO_STATUS_BIT_HF)) { ++ c = ME4000_AO_FIFO_COUNT; ++ ISR_PDEBUG("me4000_ao_isr():Fifo empty\n"); ++ } else if ((tmp & ME4000_AO_STATUS_BIT_EF) ++ && (tmp & ME4000_AO_STATUS_BIT_HF) ++ && (tmp & ME4000_AO_STATUS_BIT_HF)) { ++ c = ME4000_AO_FIFO_COUNT / 2; ++ ISR_PDEBUG("me4000_ao_isr():Fifo under half full\n"); ++ } else { ++ c = 0; ++ ISR_PDEBUG("me4000_ao_isr():Fifo full\n"); ++ } ++ ++ ISR_PDEBUG("me4000_ao_isr():Try to write 0x%04X values\n", c); ++ ++ while (1) { ++ c1 = me4000_values_to_end(ao_context->circ_buf, ++ ME4000_AO_BUFFER_COUNT); ++ ISR_PDEBUG("me4000_ao_isr():Values to end = %d\n", c1); ++ if (c1 > c) ++ c1 = c; ++ ++ if (c1 <= 0) { ++ ISR_PDEBUG ++ ("me4000_ao_isr():Work done or buffer empty\n"); ++ break; ++ } ++ //rdtscl(before); ++ if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG) || ++ ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG)) { ++ for (i = 0; i < c1; i++) { ++ value = ++ ((u32) ++ (* ++ (ao_context->circ_buf.buf + ++ ao_context->circ_buf.tail + i))) << 16; ++ outl(value, ao_context->fifo_reg); ++ } ++ } else ++ outsw(ao_context->fifo_reg, ++ ao_context->circ_buf.buf + ++ ao_context->circ_buf.tail, c1); ++ ++ //rdtscl(after); ++ //printk(KERN_ERR"ME4000:me4000_ao_isr():Time lapse = %lu\n", after - before); ++ ++ ao_context->circ_buf.tail = ++ (ao_context->circ_buf.tail + c1) & (ME4000_AO_BUFFER_COUNT - ++ 1); ++ ISR_PDEBUG("me4000_ao_isr():%d values wrote to port 0x%04X\n", ++ c1, ao_context->fifo_reg); ++ c -= c1; ++ } ++ ++ /* If there are no values left in the buffer, disable interrupts */ ++ spin_lock(&ao_context->int_lock); ++ if (!me4000_buf_count(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) { ++ ISR_PDEBUG ++ ("me4000_ao_isr():Disable Interrupt because no values left in buffer\n"); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ } ++ spin_unlock(&ao_context->int_lock); ++ ++ /* Reset the interrupt */ ++ spin_lock(&ao_context->int_lock); ++ tmp = me4000_inl(ao_context->ctrl_reg); ++ tmp |= ME4000_AO_CTRL_BIT_RESET_IRQ; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ tmp &= ~ME4000_AO_CTRL_BIT_RESET_IRQ; ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ ++ /* If state machine is stopped, flow was interrupted */ ++ if (!(me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM)) { ++ printk(KERN_ERR "ME4000:me4000_ao_isr():Broken pipe\n"); ++ ao_context->pipe_flag = 1; // Set flag in order to inform write routine ++ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ; // Disable interrupt ++ } ++ me4000_outl(tmp, ao_context->ctrl_reg); ++ spin_unlock(&ao_context->int_lock); ++ ++ /* Wake up waiting process */ ++ wake_up_interruptible(&(ao_context->wait_queue)); ++ ++ /* Count the interrupt */ ++ ao_context->board_info->irq_count++; ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t me4000_ai_isr(int irq, void *dev_id) ++{ ++ u32 tmp; ++ me4000_ai_context_t *ai_context; ++ int i; ++ int c = 0; ++ int c1 = 0; ++#ifdef ME4000_ISR_DEBUG ++ unsigned long before; ++ unsigned long after; ++#endif ++ ++ ISR_PDEBUG("me4000_ai_isr() is executed\n"); ++ ++#ifdef ME4000_ISR_DEBUG ++ rdtscl(before); ++#endif ++ ++ ai_context = dev_id; ++ ++ /* Check if irq number is right */ ++ if (irq != ai_context->irq) { ++ ISR_PDEBUG("me4000_ai_isr():incorrect interrupt num: %d\n", ++ irq); ++ return IRQ_NONE; ++ } ++ ++ if (me4000_inl(ai_context->irq_status_reg) & ++ ME4000_IRQ_STATUS_BIT_AI_HF) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Fifo half full interrupt occured\n"); ++ ++ /* Read status register to find out what happened */ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ ++ if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && ++ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) ++ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { ++ ISR_PDEBUG("me4000_ai_isr():Fifo full\n"); ++ c = ME4000_AI_FIFO_COUNT; ++ ++ /* FIFO overflow, so stop conversion and disable all interrupts */ ++ spin_lock(&ai_context->int_lock); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_HF_IRQ | ++ ME4000_AI_CTRL_BIT_SC_IRQ); ++ outl(tmp, ai_context->ctrl_reg); ++ spin_unlock(&ai_context->int_lock); ++ } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) && ++ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) ++ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { ++ ISR_PDEBUG("me4000_ai_isr():Fifo half full\n"); ++ c = ME4000_AI_FIFO_COUNT / 2; ++ } else { ++ c = 0; ++ ISR_PDEBUG ++ ("me4000_ai_isr():Can't determine state of fifo\n"); ++ } ++ ++ ISR_PDEBUG("me4000_ai_isr():Try to read %d values\n", c); ++ ++ while (1) { ++ c1 = me4000_space_to_end(ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT); ++ ISR_PDEBUG("me4000_ai_isr():Space to end = %d\n", c1); ++ if (c1 > c) ++ c1 = c; ++ ++ if (c1 <= 0) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Work done or buffer full\n"); ++ break; ++ } ++ ++ insw(ai_context->data_reg, ++ ai_context->circ_buf.buf + ++ ai_context->circ_buf.head, c1); ++ ai_context->circ_buf.head = ++ (ai_context->circ_buf.head + ++ c1) & (ME4000_AI_BUFFER_COUNT - 1); ++ c -= c1; ++ } ++ ++ /* Work is done, so reset the interrupt */ ++ ISR_PDEBUG ++ ("me4000_ai_isr():reset interrupt fifo half full interrupt\n"); ++ spin_lock(&ai_context->int_lock); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock(&ai_context->int_lock); ++ } ++ ++ if (me4000_inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Sample counter interrupt occured\n"); ++ ++ if (!ai_context->sample_counter_reload) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Single data block available\n"); ++ ++ /* Poll data until fifo empty */ ++ for (i = 0; ++ (i < ME4000_AI_FIFO_COUNT / 2) ++ && (inl(ai_context->ctrl_reg) & ++ ME4000_AI_STATUS_BIT_EF_DATA); i++) { ++ if (me4000_space_to_end ++ (ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT)) { ++ *(ai_context->circ_buf.buf + ++ ai_context->circ_buf.head) = ++ inw(ai_context->data_reg); ++ ai_context->circ_buf.head = ++ (ai_context->circ_buf.head + ++ 1) & (ME4000_AI_BUFFER_COUNT - 1); ++ } else ++ break; ++ } ++ ISR_PDEBUG("me4000_ai_isr():%d values read\n", i); ++ } else { ++ if (ai_context->sample_counter <= ++ ME4000_AI_FIFO_COUNT / 2) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Interrupt from adjustable half full threshold\n"); ++ ++ /* Read status register to find out what happened */ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ ++ if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && ++ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) ++ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Fifo full\n"); ++ c = ME4000_AI_FIFO_COUNT; ++ ++ /* FIFO overflow, so stop conversion */ ++ spin_lock(&ai_context->int_lock); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ++ ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; ++ outl(tmp, ai_context->ctrl_reg); ++ spin_unlock(&ai_context->int_lock); ++ } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) ++ && !(tmp & ++ ME4000_AI_STATUS_BIT_HF_DATA) ++ && (tmp & ++ ME4000_AI_STATUS_BIT_EF_DATA)) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Fifo half full\n"); ++ c = ME4000_AI_FIFO_COUNT / 2; ++ } else { ++ c = ai_context->sample_counter; ++ ISR_PDEBUG ++ ("me4000_ai_isr():Sample count values\n"); ++ } ++ ++ ISR_PDEBUG ++ ("me4000_ai_isr():Try to read %d values\n", ++ c); ++ ++ while (1) { ++ c1 = me4000_space_to_end(ai_context-> ++ circ_buf, ++ ME4000_AI_BUFFER_COUNT); ++ ISR_PDEBUG ++ ("me4000_ai_isr():Space to end = %d\n", ++ c1); ++ if (c1 > c) ++ c1 = c; ++ ++ if (c1 <= 0) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Work done or buffer full\n"); ++ break; ++ } ++ ++ insw(ai_context->data_reg, ++ ai_context->circ_buf.buf + ++ ai_context->circ_buf.head, c1); ++ ai_context->circ_buf.head = ++ (ai_context->circ_buf.head + ++ c1) & (ME4000_AI_BUFFER_COUNT - 1); ++ c -= c1; ++ } ++ } else { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Multiple data block available\n"); ++ ++ /* Read status register to find out what happened */ ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ ++ if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && ++ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) ++ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Fifo full\n"); ++ c = ME4000_AI_FIFO_COUNT; ++ ++ /* FIFO overflow, so stop conversion */ ++ spin_lock(&ai_context->int_lock); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ++ ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; ++ outl(tmp, ai_context->ctrl_reg); ++ spin_unlock(&ai_context->int_lock); ++ ++ while (1) { ++ c1 = me4000_space_to_end ++ (ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT); ++ ISR_PDEBUG ++ ("me4000_ai_isr():Space to end = %d\n", ++ c1); ++ if (c1 > c) ++ c1 = c; ++ ++ if (c1 <= 0) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Work done or buffer full\n"); ++ break; ++ } ++ ++ insw(ai_context->data_reg, ++ ai_context->circ_buf.buf + ++ ai_context->circ_buf.head, ++ c1); ++ ai_context->circ_buf.head = ++ (ai_context->circ_buf.head + ++ c1) & ++ (ME4000_AI_BUFFER_COUNT - ++ 1); ++ c -= c1; ++ } ++ } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) ++ && !(tmp & ++ ME4000_AI_STATUS_BIT_HF_DATA) ++ && (tmp & ++ ME4000_AI_STATUS_BIT_EF_DATA)) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Fifo half full\n"); ++ c = ME4000_AI_FIFO_COUNT / 2; ++ ++ while (1) { ++ c1 = me4000_space_to_end ++ (ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT); ++ ISR_PDEBUG ++ ("me4000_ai_isr():Space to end = %d\n", ++ c1); ++ if (c1 > c) ++ c1 = c; ++ ++ if (c1 <= 0) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Work done or buffer full\n"); ++ break; ++ } ++ ++ insw(ai_context->data_reg, ++ ai_context->circ_buf.buf + ++ ai_context->circ_buf.head, ++ c1); ++ ai_context->circ_buf.head = ++ (ai_context->circ_buf.head + ++ c1) & ++ (ME4000_AI_BUFFER_COUNT - ++ 1); ++ c -= c1; ++ } ++ } else { ++ /* Poll data until fifo empty */ ++ for (i = 0; ++ (i < ME4000_AI_FIFO_COUNT / 2) ++ && (inl(ai_context->ctrl_reg) & ++ ME4000_AI_STATUS_BIT_EF_DATA); ++ i++) { ++ if (me4000_space_to_end ++ (ai_context->circ_buf, ++ ME4000_AI_BUFFER_COUNT)) { ++ *(ai_context->circ_buf. ++ buf + ++ ai_context->circ_buf. ++ head) = ++ inw(ai_context->data_reg); ++ ai_context->circ_buf. ++ head = ++ (ai_context-> ++ circ_buf.head + ++ 1) & ++ (ME4000_AI_BUFFER_COUNT ++ - 1); ++ } else ++ break; ++ } ++ ISR_PDEBUG ++ ("me4000_ai_isr():%d values read\n", ++ i); ++ } ++ } ++ } ++ ++ /* Work is done, so reset the interrupt */ ++ ISR_PDEBUG ++ ("me4000_ai_isr():reset interrupt from sample counter\n"); ++ spin_lock(&ai_context->int_lock); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ spin_unlock(&ai_context->int_lock); ++ } ++ ++ /* Values are now available, so wake up waiting process */ ++ if (me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) { ++ ISR_PDEBUG("me4000_ai_isr():Wake up waiting process\n"); ++ wake_up_interruptible(&(ai_context->wait_queue)); ++ } ++ ++ /* If there is no space left in the buffer, disable interrupts */ ++ spin_lock(&ai_context->int_lock); ++ if (!me4000_buf_space(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) { ++ ISR_PDEBUG ++ ("me4000_ai_isr():Disable Interrupt because no space left in buffer\n"); ++ tmp = me4000_inl(ai_context->ctrl_reg); ++ tmp &= ++ ~(ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ | ++ ME4000_AI_CTRL_BIT_LE_IRQ); ++ me4000_outl(tmp, ai_context->ctrl_reg); ++ } ++ spin_unlock(&ai_context->int_lock); ++ ++#ifdef ME4000_ISR_DEBUG ++ rdtscl(after); ++ printk(KERN_ERR "ME4000:me4000_ai_isr():Time lapse = %lu\n", ++ after - before); ++#endif ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t me4000_ext_int_isr(int irq, void *dev_id) ++{ ++ me4000_ext_int_context_t *ext_int_context; ++ unsigned long tmp; ++ ++ ISR_PDEBUG("me4000_ext_int_isr() is executed\n"); ++ ++ ext_int_context = dev_id; ++ ++ /* Check if irq number is right */ ++ if (irq != ext_int_context->irq) { ++ ISR_PDEBUG("me4000_ext_int_isr():incorrect interrupt num: %d\n", ++ irq); ++ return IRQ_NONE; ++ } ++ ++ if (me4000_inl(ext_int_context->irq_status_reg) & ++ ME4000_IRQ_STATUS_BIT_EX) { ++ ISR_PDEBUG("me4000_ext_int_isr():External interrupt occured\n"); ++ tmp = me4000_inl(ext_int_context->ctrl_reg); ++ tmp |= ME4000_AI_CTRL_BIT_EX_IRQ_RESET; ++ me4000_outl(tmp, ext_int_context->ctrl_reg); ++ tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ_RESET; ++ me4000_outl(tmp, ext_int_context->ctrl_reg); ++ ++ ext_int_context->int_count++; ++ ++ if (ext_int_context->fasync_ptr) { ++ ISR_PDEBUG ++ ("me2600_ext_int_isr():Send signal to process\n"); ++ kill_fasync(&ext_int_context->fasync_ptr, SIGIO, ++ POLL_IN); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++void __exit me4000_module_exit(void) ++{ ++ struct list_head *board_p; ++ me4000_info_t *board_info; ++ ++ CALL_PDEBUG("cleanup_module() is executed\n"); ++ ++ unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME); ++ ++ unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME); ++ ++ unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME); ++ ++ unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME); ++ ++ unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME); ++ ++ remove_proc_entry("me4000", NULL); ++ ++ pci_unregister_driver(&me4000_driver); ++ ++ /* Reset the boards */ ++ for (board_p = me4000_board_info_list.next; ++ board_p != &me4000_board_info_list; board_p = board_p->next) { ++ board_info = list_entry(board_p, me4000_info_t, list); ++ me4000_reset_board(board_info); ++ } ++ ++ clear_board_info_list(); ++} ++ ++module_exit(me4000_module_exit); ++ ++static int me4000_read_procmem(char *buf, char **start, off_t offset, int count, ++ int *eof, void *data) ++{ ++ int len = 0; ++ int limit = count - 1000; ++ me4000_info_t *board_info; ++ struct list_head *ptr; ++ ++ len += sprintf(buf + len, "\nME4000 DRIVER VERSION %X.%X.%X\n\n", ++ (ME4000_DRIVER_VERSION & 0xFF0000) >> 16, ++ (ME4000_DRIVER_VERSION & 0xFF00) >> 8, ++ (ME4000_DRIVER_VERSION & 0xFF)); ++ ++ /* Search for the board context */ ++ for (ptr = me4000_board_info_list.next; ++ (ptr != &me4000_board_info_list) && (len < limit); ++ ptr = ptr->next) { ++ board_info = list_entry(ptr, me4000_info_t, list); ++ ++ len += ++ sprintf(buf + len, "Board number %d:\n", ++ board_info->board_count); ++ len += sprintf(buf + len, "---------------\n"); ++ len += ++ sprintf(buf + len, "PLX base register = 0x%lX\n", ++ board_info->plx_regbase); ++ len += ++ sprintf(buf + len, "PLX base register size = 0x%lX\n", ++ board_info->plx_regbase_size); ++ len += ++ sprintf(buf + len, "ME4000 base register = 0x%lX\n", ++ board_info->me4000_regbase); ++ len += ++ sprintf(buf + len, "ME4000 base register size = 0x%lX\n", ++ board_info->me4000_regbase_size); ++ len += ++ sprintf(buf + len, "Serial number = 0x%X\n", ++ board_info->serial_no); ++ len += ++ sprintf(buf + len, "Hardware revision = 0x%X\n", ++ board_info->hw_revision); ++ len += ++ sprintf(buf + len, "Vendor id = 0x%X\n", ++ board_info->vendor_id); ++ len += ++ sprintf(buf + len, "Device id = 0x%X\n", ++ board_info->device_id); ++ len += ++ sprintf(buf + len, "PCI bus number = %d\n", ++ board_info->pci_bus_no); ++ len += ++ sprintf(buf + len, "PCI device number = %d\n", ++ board_info->pci_dev_no); ++ len += ++ sprintf(buf + len, "PCI function number = %d\n", ++ board_info->pci_func_no); ++ len += sprintf(buf + len, "IRQ = %u\n", board_info->irq); ++ len += ++ sprintf(buf + len, ++ "Count of interrupts since module was loaded = %d\n", ++ board_info->irq_count); ++ ++ len += ++ sprintf(buf + len, "Count of analog outputs = %d\n", ++ board_info->board_p->ao.count); ++ len += ++ sprintf(buf + len, "Count of analog output fifos = %d\n", ++ board_info->board_p->ao.fifo_count); ++ ++ len += ++ sprintf(buf + len, "Count of analog inputs = %d\n", ++ board_info->board_p->ai.count); ++ len += ++ sprintf(buf + len, ++ "Count of sample and hold devices for analog input = %d\n", ++ board_info->board_p->ai.sh_count); ++ len += ++ sprintf(buf + len, ++ "Analog external trigger available for analog input = %d\n", ++ board_info->board_p->ai.ex_trig_analog); ++ ++ len += ++ sprintf(buf + len, "Count of digital ports = %d\n", ++ board_info->board_p->dio.count); ++ ++ len += ++ sprintf(buf + len, "Count of counter devices = %d\n", ++ board_info->board_p->cnt.count); ++ len += ++ sprintf(buf + len, "AI control register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AI_CTRL_REG)); ++ ++ len += sprintf(buf + len, "AO 0 control register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_00_CTRL_REG)); ++ len += ++ sprintf(buf + len, "AO 0 status register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_00_STATUS_REG)); ++ len += ++ sprintf(buf + len, "AO 1 control register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_01_CTRL_REG)); ++ len += ++ sprintf(buf + len, "AO 1 status register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_01_STATUS_REG)); ++ len += ++ sprintf(buf + len, "AO 2 control register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_02_CTRL_REG)); ++ len += ++ sprintf(buf + len, "AO 2 status register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_02_STATUS_REG)); ++ len += ++ sprintf(buf + len, "AO 3 control register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_03_CTRL_REG)); ++ len += ++ sprintf(buf + len, "AO 3 status register = 0x%08X\n", ++ inl(board_info->me4000_regbase + ++ ME4000_AO_03_STATUS_REG)); ++ } ++ ++ *eof = 1; ++ return len; ++} +diff --git a/drivers/staging/me4000/me4000.h b/drivers/staging/me4000/me4000.h +new file mode 100644 +index 0000000..c35e4b9 +--- /dev/null ++++ b/drivers/staging/me4000/me4000.h +@@ -0,0 +1,954 @@ ++/* ++ * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de) ++ * ++ * Source File : me4000.h ++ * Author : GG (Guenter Gebhardt) ++ */ ++ ++#ifndef _ME4000_H_ ++#define _ME4000_H_ ++ ++#ifdef __KERNEL__ ++ ++/*============================================================================= ++ The version of the driver release ++ ===========================================================================*/ ++ ++#define ME4000_DRIVER_VERSION 0x10009 // Version 1.00.09 ++ ++/*============================================================================= ++ Debug section ++ ===========================================================================*/ ++ ++#undef ME4000_CALL_DEBUG // Debug function entry and exit ++#undef ME4000_ISR_DEBUG // Debug the interrupt service routine ++#undef ME4000_PORT_DEBUG // Debug port access ++#undef ME4000_DEBUG // General purpose debug masseges ++ ++#ifdef ME4000_CALL_DEBUG ++#undef CALL_PDEBUG ++#define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) ++#else ++# define CALL_PDEBUG(fmt, args...) // no debugging, do nothing ++#endif ++ ++#ifdef ME4000_ISR_DEBUG ++#undef ISR_PDEBUG ++#define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) ++#else ++#define ISR_PDEBUG(fmt, args...) // no debugging, do nothing ++#endif ++ ++#ifdef ME4000_PORT_DEBUG ++#undef PORT_PDEBUG ++#define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) ++#else ++#define PORT_PDEBUG(fmt, args...) // no debugging, do nothing ++#endif ++ ++#ifdef ME4000_DEBUG ++#undef PDEBUG ++#define PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args) ++#else ++#define PDEBUG(fmt, args...) // no debugging, do nothing ++#endif ++ ++/*============================================================================= ++ PCI vendor and device IDs ++ ===========================================================================*/ ++ ++#define PCI_VENDOR_ID_MEILHAUS 0x1402 ++ ++#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 // Low Cost version ++ ++#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 // Standard version ++#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 // Isolated version ++#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 // Standard version with Sample and Hold ++#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 // Isolated version with Sample and Hold ++ ++#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 // Standard version ++#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 // Isolated version ++#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 // Standard version with Sample and Hold ++#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 // Isolated version with Sample and Hold ++ ++#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 // Standard version ++#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 // Isolated version ++#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 // Standard version with Sample and Hold ++#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 // Isolated version with Sample and Hold ++ ++/*============================================================================= ++ Device names, for entries in /proc/.. ++ ===========================================================================*/ ++ ++#define ME4000_NAME "me4000" ++#define ME4000_AO_NAME "me4000_ao" ++#define ME4000_AI_NAME "me4000_ai" ++#define ME4000_DIO_NAME "me4000_dio" ++#define ME4000_CNT_NAME "me4000_cnt" ++#define ME4000_EXT_INT_NAME "me4000_ext_int" ++ ++/*============================================================================= ++ ME-4000 base register offsets ++ ===========================================================================*/ ++ ++#define ME4000_AO_00_CTRL_REG 0x00 // R/W ++#define ME4000_AO_00_STATUS_REG 0x04 // R/_ ++#define ME4000_AO_00_FIFO_REG 0x08 // _/W ++#define ME4000_AO_00_SINGLE_REG 0x0C // R/W ++#define ME4000_AO_00_TIMER_REG 0x10 // _/W ++ ++#define ME4000_AO_01_CTRL_REG 0x18 // R/W ++#define ME4000_AO_01_STATUS_REG 0x1C // R/_ ++#define ME4000_AO_01_FIFO_REG 0x20 // _/W ++#define ME4000_AO_01_SINGLE_REG 0x24 // R/W ++#define ME4000_AO_01_TIMER_REG 0x28 // _/W ++ ++#define ME4000_AO_02_CTRL_REG 0x30 // R/W ++#define ME4000_AO_02_STATUS_REG 0x34 // R/_ ++#define ME4000_AO_02_FIFO_REG 0x38 // _/W ++#define ME4000_AO_02_SINGLE_REG 0x3C // R/W ++#define ME4000_AO_02_TIMER_REG 0x40 // _/W ++ ++#define ME4000_AO_03_CTRL_REG 0x48 // R/W ++#define ME4000_AO_03_STATUS_REG 0x4C // R/_ ++#define ME4000_AO_03_FIFO_REG 0x50 // _/W ++#define ME4000_AO_03_SINGLE_REG 0x54 // R/W ++#define ME4000_AO_03_TIMER_REG 0x58 // _/W ++ ++#define ME4000_AI_CTRL_REG 0x74 // _/W ++#define ME4000_AI_STATUS_REG 0x74 // R/_ ++#define ME4000_AI_CHANNEL_LIST_REG 0x78 // _/W ++#define ME4000_AI_DATA_REG 0x7C // R/_ ++#define ME4000_AI_CHAN_TIMER_REG 0x80 // _/W ++#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 // _/W ++#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 // _/W ++#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W ++#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W ++#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W ++#define ME4000_AI_START_REG 0x98 // R/_ ++ ++#define ME4000_IRQ_STATUS_REG 0x9C // R/_ ++ ++#define ME4000_DIO_PORT_0_REG 0xA0 // R/W ++#define ME4000_DIO_PORT_1_REG 0xA4 // R/W ++#define ME4000_DIO_PORT_2_REG 0xA8 // R/W ++#define ME4000_DIO_PORT_3_REG 0xAC // R/W ++#define ME4000_DIO_DIR_REG 0xB0 // R/W ++ ++#define ME4000_AO_LOADSETREG_XX 0xB4 // R/W ++ ++#define ME4000_DIO_CTRL_REG 0xB8 // R/W ++ ++#define ME4000_AO_DEMUX_ADJUST_REG 0xBC // -/W ++ ++#define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 // _/W ++ ++/*============================================================================= ++ Value to adjust Demux ++ ===========================================================================*/ ++ ++#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C ++ ++/*============================================================================= ++ Counter base register offsets ++ ===========================================================================*/ ++ ++#define ME4000_CNT_COUNTER_0_REG 0x00 ++#define ME4000_CNT_COUNTER_1_REG 0x01 ++#define ME4000_CNT_COUNTER_2_REG 0x02 ++#define ME4000_CNT_CTRL_REG 0x03 ++ ++/*============================================================================= ++ PLX base register offsets ++ ===========================================================================*/ ++ ++#define PLX_INTCSR 0x4C // Interrupt control and status register ++#define PLX_ICR 0x50 // Initialization control register ++ ++/*============================================================================= ++ Bits for the PLX_ICSR register ++ ===========================================================================*/ ++ ++#define PLX_INTCSR_LOCAL_INT1_EN 0x01 // If set, local interrupt 1 is enabled (r/w) ++#define PLX_INTCSR_LOCAL_INT1_POL 0x02 // If set, local interrupt 1 polarity is active high (r/w) ++#define PLX_INTCSR_LOCAL_INT1_STATE 0x04 // If set, local interrupt 1 is active (r/_) ++#define PLX_INTCSR_LOCAL_INT2_EN 0x08 // If set, local interrupt 2 is enabled (r/w) ++#define PLX_INTCSR_LOCAL_INT2_POL 0x10 // If set, local interrupt 2 polarity is active high (r/w) ++#define PLX_INTCSR_LOCAL_INT2_STATE 0x20 // If set, local interrupt 2 is active (r/_) ++#define PLX_INTCSR_PCI_INT_EN 0x40 // If set, PCI interrupt is enabled (r/w) ++#define PLX_INTCSR_SOFT_INT 0x80 // If set, a software interrupt is generated (r/w) ++ ++/*============================================================================= ++ Bits for the PLX_ICR register ++ ===========================================================================*/ ++ ++#define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000 ++#define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000 ++#define PLX_ICR_BIT_EEPROM_WRITE 0x04000000 ++#define PLX_ICR_BIT_EEPROM_READ 0x08000000 ++#define PLX_ICR_BIT_EEPROM_VALID 0x10000000 ++ ++#define PLX_ICR_MASK_EEPROM 0x1F000000 ++ ++#define EEPROM_DELAY 1 ++ ++/*============================================================================= ++ Bits for the ME4000_AO_CTRL_REG register ++ ===========================================================================*/ ++ ++#define ME4000_AO_CTRL_BIT_MODE_0 0x001 ++#define ME4000_AO_CTRL_BIT_MODE_1 0x002 ++#define ME4000_AO_CTRL_MASK_MODE 0x003 ++#define ME4000_AO_CTRL_BIT_STOP 0x004 ++#define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008 ++#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010 ++#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020 ++#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080 ++#define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100 ++#define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200 ++#define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400 ++#define ME4000_AO_CTRL_BIT_EX_TRIG_BOTH 0x800 ++ ++/*============================================================================= ++ Bits for the ME4000_AO_STATUS_REG register ++ ===========================================================================*/ ++ ++#define ME4000_AO_STATUS_BIT_FSM 0x01 ++#define ME4000_AO_STATUS_BIT_FF 0x02 ++#define ME4000_AO_STATUS_BIT_HF 0x04 ++#define ME4000_AO_STATUS_BIT_EF 0x08 ++ ++/*============================================================================= ++ Bits for the ME4000_AI_CTRL_REG register ++ ===========================================================================*/ ++ ++#define ME4000_AI_CTRL_BIT_MODE_0 0x00000001 ++#define ME4000_AI_CTRL_BIT_MODE_1 0x00000002 ++#define ME4000_AI_CTRL_BIT_MODE_2 0x00000004 ++#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008 ++#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010 ++#define ME4000_AI_CTRL_BIT_STOP 0x00000020 ++#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040 ++#define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080 ++#define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100 ++#define ME4000_AI_CTRL_BIT_OFFSET 0x00000200 ++#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400 ++#define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800 ++#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000 ++#define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000 ++#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000 ++#define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000 ++#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000 ++#define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000 ++#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000 ++#define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000 ++#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000 ++#define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000 ++#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000 ++ ++/*============================================================================= ++ Bits for the ME4000_AI_STATUS_REG register ++ ===========================================================================*/ ++ ++#define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000 ++#define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000 ++#define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000 ++#define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000 ++#define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000 ++#define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000 ++#define ME4000_AI_STATUS_BIT_LE 0x10000000 ++#define ME4000_AI_STATUS_BIT_FSM 0x20000000 ++ ++/*============================================================================= ++ Bits for the ME4000_IRQ_STATUS_REG register ++ ===========================================================================*/ ++ ++#define ME4000_IRQ_STATUS_BIT_EX 0x01 ++#define ME4000_IRQ_STATUS_BIT_LE 0x02 ++#define ME4000_IRQ_STATUS_BIT_AI_HF 0x04 ++#define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08 ++#define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10 ++#define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20 ++#define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40 ++#define ME4000_IRQ_STATUS_BIT_SC 0x80 ++ ++/*============================================================================= ++ Bits for the ME4000_DIO_CTRL_REG register ++ ===========================================================================*/ ++ ++#define ME4000_DIO_CTRL_BIT_MODE_0 0X0001 ++#define ME4000_DIO_CTRL_BIT_MODE_1 0X0002 ++#define ME4000_DIO_CTRL_BIT_MODE_2 0X0004 ++#define ME4000_DIO_CTRL_BIT_MODE_3 0X0008 ++#define ME4000_DIO_CTRL_BIT_MODE_4 0X0010 ++#define ME4000_DIO_CTRL_BIT_MODE_5 0X0020 ++#define ME4000_DIO_CTRL_BIT_MODE_6 0X0040 ++#define ME4000_DIO_CTRL_BIT_MODE_7 0X0080 ++ ++#define ME4000_DIO_CTRL_BIT_FUNCTION_0 0X0100 ++#define ME4000_DIO_CTRL_BIT_FUNCTION_1 0X0200 ++ ++#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0X0400 ++#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0X0800 ++#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0X1000 ++#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0X2000 ++ ++/*============================================================================= ++ Bits for the ME4000_CNT_CTRL_REG register ++ ===========================================================================*/ ++ ++#define ME4000_CNT_CTRL_BIT_COUNTER_0 0x00 ++#define ME4000_CNT_CTRL_BIT_COUNTER_1 0x40 ++#define ME4000_CNT_CTRL_BIT_COUNTER_2 0x80 ++ ++#define ME4000_CNT_CTRL_BIT_MODE_0 0x00 // Change state if zero crossing ++#define ME4000_CNT_CTRL_BIT_MODE_1 0x02 // Retriggerable One-Shot ++#define ME4000_CNT_CTRL_BIT_MODE_2 0x04 // Asymmetrical divider ++#define ME4000_CNT_CTRL_BIT_MODE_3 0x06 // Symmetrical divider ++#define ME4000_CNT_CTRL_BIT_MODE_4 0x08 // Counter start by software trigger ++#define ME4000_CNT_CTRL_BIT_MODE_5 0x0A // Counter start by hardware trigger ++ ++/*============================================================================= ++ Extract information from minor device number ++ ===========================================================================*/ ++ ++#define AO_BOARD(dev) ((MINOR(dev) >> 6) & 0x3) ++#define AO_PORT(dev) ((MINOR(dev) >> 2) & 0xF) ++#define AO_MODE(dev) (MINOR(dev) & 0x3) ++ ++#define AI_BOARD(dev) ((MINOR(dev) >> 3) & 0x1F) ++#define AI_MODE(dev) (MINOR(dev) & 0x7) ++ ++#define DIO_BOARD(dev) (MINOR(dev)) ++ ++#define CNT_BOARD(dev) (MINOR(dev)) ++ ++#define EXT_INT_BOARD(dev) (MINOR(dev)) ++ ++/*============================================================================= ++ Circular buffer used for analog input/output reads/writes. ++ ===========================================================================*/ ++ ++typedef struct me4000_circ_buf { ++ s16 *buf; ++ int volatile head; ++ int volatile tail; ++} me4000_circ_buf_t; ++ ++/*============================================================================= ++ Information about the hardware capabilities ++ ===========================================================================*/ ++ ++typedef struct me4000_ao_info { ++ int count; ++ int fifo_count; ++} me4000_ao_info_t; ++ ++typedef struct me4000_ai_info { ++ int count; ++ int sh_count; ++ int diff_count; ++ int ex_trig_analog; ++} me4000_ai_info_t; ++ ++typedef struct me4000_dio_info { ++ int count; ++} me4000_dio_info_t; ++ ++typedef struct me4000_cnt_info { ++ int count; ++} me4000_cnt_info_t; ++ ++typedef struct me4000_board { ++ u16 vendor_id; ++ u16 device_id; ++ me4000_ao_info_t ao; ++ me4000_ai_info_t ai; ++ me4000_dio_info_t dio; ++ me4000_cnt_info_t cnt; ++} me4000_board_t; ++ ++static me4000_board_t me4000_boards[] = { ++ {PCI_VENDOR_ID_MEILHAUS, 0x4610, {0, 0}, {16, 0, 0, 0}, {4}, {3}}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4660, {2, 0}, {16, 0, 0, 0}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4661, {2, 0}, {16, 0, 0, 0}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4662, {2, 0}, {16, 8, 0, 0}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4663, {2, 0}, {16, 8, 0, 0}, {4}, {3}}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3}}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3}}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3}}, ++ ++ {0}, ++}; ++ ++#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1) ++ ++/*============================================================================= ++ PCI device table. ++ This is used by modprobe to translate PCI IDs to drivers. ++ ===========================================================================*/ ++ ++static struct pci_device_id me4000_pci_table[] __devinitdata = { ++ {PCI_VENDOR_ID_MEILHAUS, 0x4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4661, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4662, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ ++ {PCI_VENDOR_ID_MEILHAUS, 0x4680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4682, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {PCI_VENDOR_ID_MEILHAUS, 0x4683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ ++ {0} ++}; ++ ++MODULE_DEVICE_TABLE(pci, me4000_pci_table); ++ ++/*============================================================================= ++ Global board and subdevice information structures ++ ===========================================================================*/ ++ ++typedef struct me4000_info { ++ struct list_head list; // List of all detected boards ++ int board_count; // Index of the board after detection ++ ++ unsigned long plx_regbase; // PLX configuration space base address ++ unsigned long me4000_regbase; // Base address of the ME4000 ++ unsigned long timer_regbase; // Base address of the timer circuit ++ unsigned long program_regbase; // Base address to set the program pin for the xilinx ++ ++ unsigned long plx_regbase_size; // PLX register set space ++ unsigned long me4000_regbase_size; // ME4000 register set space ++ unsigned long timer_regbase_size; // Timer circuit register set space ++ unsigned long program_regbase_size; // Size of program base address of the ME4000 ++ ++ unsigned int serial_no; // Serial number of the board ++ unsigned char hw_revision; // Hardware revision of the board ++ unsigned short vendor_id; // Meilhaus vendor id (0x1402) ++ unsigned short device_id; // Device ID ++ ++ int pci_bus_no; // PCI bus number ++ int pci_dev_no; // PCI device number ++ int pci_func_no; // PCI function number ++ struct pci_dev *pci_dev_p; // General PCI information ++ ++ me4000_board_t *board_p; // Holds the board capabilities ++ ++ unsigned int irq; // IRQ assigned from the PCI BIOS ++ unsigned int irq_count; // Count of external interrupts ++ ++ spinlock_t preload_lock; // Guards the analog output preload register ++ spinlock_t ai_ctrl_lock; // Guards the analog input control register ++ ++ struct list_head ao_context_list; // List with analog output specific context ++ struct me4000_ai_context *ai_context; // Analog input specific context ++ struct me4000_dio_context *dio_context; // Digital I/O specific context ++ struct me4000_cnt_context *cnt_context; // Counter specific context ++ struct me4000_ext_int_context *ext_int_context; // External interrupt specific context ++} me4000_info_t; ++ ++typedef struct me4000_ao_context { ++ struct list_head list; // linked list of me4000_ao_context_t ++ int index; // Index in the list ++ int mode; // Indicates mode (0 = single, 1 = wraparound, 2 = continous) ++ int dac_in_use; // Indicates if already opend ++ spinlock_t use_lock; // Guards in_use ++ spinlock_t int_lock; // Used when locking out interrupts ++ me4000_circ_buf_t circ_buf; // Circular buffer ++ wait_queue_head_t wait_queue; // Wait queue to sleep while blocking write ++ me4000_info_t *board_info; ++ unsigned int irq; // The irq associated with this ADC ++ int volatile pipe_flag; // Indicates broken pipe set from me4000_ao_isr() ++ unsigned long ctrl_reg; ++ unsigned long status_reg; ++ unsigned long fifo_reg; ++ unsigned long single_reg; ++ unsigned long timer_reg; ++ unsigned long irq_status_reg; ++ unsigned long preload_reg; ++ struct fasync_struct *fasync_p; // Queue for asynchronous notification ++} me4000_ao_context_t; ++ ++typedef struct me4000_ai_context { ++ struct list_head list; // linked list of me4000_ai_info_t ++ int mode; // Indicates mode ++ int in_use; // Indicates if already opend ++ spinlock_t use_lock; // Guards in_use ++ spinlock_t int_lock; // Used when locking out interrupts ++ int number; // Number of the DAC ++ unsigned int irq; // The irq associated with this ADC ++ me4000_circ_buf_t circ_buf; // Circular buffer ++ wait_queue_head_t wait_queue; // Wait queue to sleep while blocking read ++ me4000_info_t *board_info; ++ ++ struct fasync_struct *fasync_p; // Queue for asynchronous notification ++ ++ unsigned long ctrl_reg; ++ unsigned long status_reg; ++ unsigned long channel_list_reg; ++ unsigned long data_reg; ++ unsigned long chan_timer_reg; ++ unsigned long chan_pre_timer_reg; ++ unsigned long scan_timer_low_reg; ++ unsigned long scan_timer_high_reg; ++ unsigned long scan_pre_timer_low_reg; ++ unsigned long scan_pre_timer_high_reg; ++ unsigned long start_reg; ++ unsigned long irq_status_reg; ++ unsigned long sample_counter_reg; ++ ++ unsigned long chan_timer; ++ unsigned long chan_pre_timer; ++ unsigned long scan_timer_low; ++ unsigned long scan_timer_high; ++ unsigned long channel_list_count; ++ unsigned long sample_counter; ++ int sample_counter_reload; ++} me4000_ai_context_t; ++ ++typedef struct me4000_dio_context { ++ struct list_head list; // linked list of me4000_dio_context_t ++ int in_use; // Indicates if already opend ++ spinlock_t use_lock; // Guards in_use ++ int number; ++ int dio_count; ++ me4000_info_t *board_info; ++ unsigned long dir_reg; ++ unsigned long ctrl_reg; ++ unsigned long port_0_reg; ++ unsigned long port_1_reg; ++ unsigned long port_2_reg; ++ unsigned long port_3_reg; ++} me4000_dio_context_t; ++ ++typedef struct me4000_cnt_context { ++ struct list_head list; // linked list of me4000_dio_context_t ++ int in_use; // Indicates if already opend ++ spinlock_t use_lock; // Guards in_use ++ int number; ++ int cnt_count; ++ me4000_info_t *board_info; ++ unsigned long ctrl_reg; ++ unsigned long counter_0_reg; ++ unsigned long counter_1_reg; ++ unsigned long counter_2_reg; ++} me4000_cnt_context_t; ++ ++typedef struct me4000_ext_int_context { ++ struct list_head list; // linked list of me4000_dio_context_t ++ int in_use; // Indicates if already opend ++ spinlock_t use_lock; // Guards in_use ++ int number; ++ me4000_info_t *board_info; ++ unsigned int irq; ++ unsigned long int_count; ++ struct fasync_struct *fasync_ptr; ++ unsigned long ctrl_reg; ++ unsigned long irq_status_reg; ++} me4000_ext_int_context_t; ++ ++#endif ++ ++/*============================================================================= ++ Application include section starts here ++ ===========================================================================*/ ++ ++/*----------------------------------------------------------------------------- ++ Defines for analog input ++ ----------------------------------------------------------------------------*/ ++ ++/* General stuff */ ++#define ME4000_AI_FIFO_COUNT 2048 ++ ++#define ME4000_AI_MIN_TICKS 66 ++#define ME4000_AI_MAX_SCAN_TICKS 0xFFFFFFFFFFLL ++ ++#define ME4000_AI_BUFFER_SIZE (32 * 1024) // Size in bytes ++ ++#define ME4000_AI_BUFFER_COUNT ((ME4000_AI_BUFFER_SIZE) / 2) // Size in values ++ ++/* Channel list defines and masks */ ++#define ME4000_AI_CHANNEL_LIST_COUNT 1024 ++ ++#define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000 ++#define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020 ++ ++#define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000 ++#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040 ++#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080 ++#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0 ++ ++#define ME4000_AI_LIST_LAST_ENTRY 0x100 ++ ++/* External trigger defines */ ++#define ME4000_AI_TRIGGER_SOFTWARE 0x0 // Use only with API ++#define ME4000_AI_TRIGGER_EXT_DIGITAL 0x1 ++#define ME4000_AI_TRIGGER_EXT_ANALOG 0x2 ++ ++#define ME4000_AI_TRIGGER_EXT_EDGE_RISING 0x0 ++#define ME4000_AI_TRIGGER_EXT_EDGE_FALLING 0x1 ++#define ME4000_AI_TRIGGER_EXT_EDGE_BOTH 0x2 ++ ++/* Sample and Hold */ ++#define ME4000_AI_SIMULTANEOUS_DISABLE 0x0 ++#define ME4000_AI_SIMULTANEOUS_ENABLE 0x1 ++ ++/* Defines for the Sample Counter */ ++#define ME4000_AI_SC_RELOAD 0x0 ++#define ME4000_AI_SC_ONCE 0x1 ++ ++/* Modes for analog input */ ++#define ME4000_AI_ACQ_MODE_SINGLE 0x00 // Catch one single value ++#define ME4000_AI_ACQ_MODE_SOFTWARE 0x01 // Continous sampling with software start ++#define ME4000_AI_ACQ_MODE_EXT 0x02 // Continous sampling with external trigger start ++#define ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE 0x03 // Sample one value by external trigger ++#define ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST 0x04 // Sample one channel list by external trigger ++ ++/* Staus of AI FSM */ ++#define ME4000_AI_STATUS_IDLE 0x0 ++#define ME4000_AI_STATUS_BUSY 0x1 ++ ++/* Voltages for calibration */ ++#define ME4000_AI_GAIN_1_UNI_OFFSET 10.0E-3 ++#define ME4000_AI_GAIN_1_UNI_FULLSCALE 9950.0E-3 ++#define ME4000_AI_GAIN_1_BI_OFFSET 0.0 ++#define ME4000_AI_GAIN_1_BI_FULLSCALE 9950.0E-3 ++#define ME4000_AI_GAIN_4_UNI_OFFSET 10.0E-3 ++#define ME4000_AI_GAIN_4_UNI_FULLSCALE 2450.0E-3 ++#define ME4000_AI_GAIN_4_BI_OFFSET 0.0 ++#define ME4000_AI_GAIN_4_BI_FULLSCALE 2450.0E-3 ++ ++/* Ideal digits for calibration */ ++#define ME4000_AI_GAIN_1_UNI_OFFSET_DIGITS (-32702) ++#define ME4000_AI_GAIN_1_UNI_FULLSCALE_DIGITS 32440 ++#define ME4000_AI_GAIN_1_BI_OFFSET_DIGITS 0 ++#define ME4000_AI_GAIN_1_BI_FULLSCALE_DIGITS 32604 ++#define ME4000_AI_GAIN_4_UNI_OFFSET_DIGITS (-32505) ++#define ME4000_AI_GAIN_4_UNI_FULLSCALE_DIGITS 31457 ++#define ME4000_AI_GAIN_4_BI_OFFSET_DIGITS 0 ++#define ME4000_AI_GAIN_4_BI_FULLSCALE_DIGITS 32113 ++ ++/*----------------------------------------------------------------------------- ++ Defines for analog output ++ ----------------------------------------------------------------------------*/ ++ ++/* General stuff */ ++#define ME4000_AO_FIFO_COUNT (4 * 1024) ++ ++#define ME4000_AO_MIN_TICKS 66 ++ ++#define ME4000_AO_BUFFER_SIZE (32 * 1024) // Size in bytes ++ ++#define ME4000_AO_BUFFER_COUNT ((ME4000_AO_BUFFER_SIZE) / 2) // Size in values ++ ++/* Conversion modes for analog output */ ++#define ME4000_AO_CONV_MODE_SINGLE 0x0 ++#define ME4000_AO_CONV_MODE_WRAPAROUND 0x1 ++#define ME4000_AO_CONV_MODE_CONTINUOUS 0x2 ++ ++/* Trigger setup */ ++#define ME4000_AO_TRIGGER_EXT_EDGE_RISING 0x0 ++#define ME4000_AO_TRIGGER_EXT_EDGE_FALLING 0x1 ++#define ME4000_AO_TRIGGER_EXT_EDGE_BOTH 0x2 ++ ++/* Status of AO FSM */ ++#define ME4000_AO_STATUS_IDLE 0x0 ++#define ME4000_AO_STATUS_BUSY 0x1 ++ ++/*----------------------------------------------------------------------------- ++ Defines for eeprom ++ ----------------------------------------------------------------------------*/ ++ ++#define ME4000_EEPROM_CMD_READ 0x180 ++#define ME4000_EEPROM_CMD_WRITE_ENABLE 0x130 ++#define ME4000_EEPROM_CMD_WRITE_DISABLE 0x100 ++#define ME4000_EEPROM_CMD_WRITE 0x1400000 ++ ++#define ME4000_EEPROM_CMD_LENGTH_READ 9 ++#define ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE 9 ++#define ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE 9 ++#define ME4000_EEPROM_CMD_LENGTH_WRITE 25 ++ ++#define ME4000_EEPROM_ADR_DATE_HIGH 0x32 ++#define ME4000_EEPROM_ADR_DATE_LOW 0x33 ++ ++#define ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET 0x34 ++#define ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE 0x35 ++#define ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET 0x36 ++#define ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE 0x37 ++#define ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET 0x38 ++#define ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE 0x39 ++ ++#define ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET 0x3A ++#define ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE 0x3B ++#define ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET 0x3C ++#define ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE 0x3D ++#define ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET 0x3E ++#define ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE 0x3F ++ ++#define ME4000_EEPROM_ADR_LENGTH 6 ++#define ME4000_EEPROM_DATA_LENGTH 16 ++ ++/*----------------------------------------------------------------------------- ++ Defines for digital I/O ++ ----------------------------------------------------------------------------*/ ++ ++#define ME4000_DIO_PORT_A 0x0 ++#define ME4000_DIO_PORT_B 0x1 ++#define ME4000_DIO_PORT_C 0x2 ++#define ME4000_DIO_PORT_D 0x3 ++ ++#define ME4000_DIO_PORT_INPUT 0x0 ++#define ME4000_DIO_PORT_OUTPUT 0x1 ++#define ME4000_DIO_FIFO_LOW 0x2 ++#define ME4000_DIO_FIFO_HIGH 0x3 ++ ++#define ME4000_DIO_FUNCTION_PATTERN 0x0 ++#define ME4000_DIO_FUNCTION_DEMUX 0x1 ++#define ME4000_DIO_FUNCTION_MUX 0x2 ++ ++/*----------------------------------------------------------------------------- ++ Defines for counters ++ ----------------------------------------------------------------------------*/ ++ ++#define ME4000_CNT_COUNTER_0 0 ++#define ME4000_CNT_COUNTER_1 1 ++#define ME4000_CNT_COUNTER_2 2 ++ ++#define ME4000_CNT_MODE_0 0 // Change state if zero crossing ++#define ME4000_CNT_MODE_1 1 // Retriggerable One-Shot ++#define ME4000_CNT_MODE_2 2 // Asymmetrical divider ++#define ME4000_CNT_MODE_3 3 // Symmetrical divider ++#define ME4000_CNT_MODE_4 4 // Counter start by software trigger ++#define ME4000_CNT_MODE_5 5 // Counter start by hardware trigger ++ ++/*----------------------------------------------------------------------------- ++ General type definitions ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct me4000_user_info { ++ int board_count; // Index of the board after detection ++ unsigned long plx_regbase; // PLX configuration space base address ++ unsigned long me4000_regbase; // Base address of the ME4000 ++ unsigned long plx_regbase_size; // PLX register set space ++ unsigned long me4000_regbase_size; // ME4000 register set space ++ unsigned long serial_no; // Serial number of the board ++ unsigned char hw_revision; // Hardware revision of the board ++ unsigned short vendor_id; // Meilhaus vendor id (0x1402) ++ unsigned short device_id; // Device ID ++ int pci_bus_no; // PCI bus number ++ int pci_dev_no; // PCI device number ++ int pci_func_no; // PCI function number ++ char irq; // IRQ assigned from the PCI BIOS ++ int irq_count; // Count of external interrupts ++ ++ int driver_version; // Version of the driver release ++ ++ int ao_count; // Count of analog output channels ++ int ao_fifo_count; // Count fo analog output fifos ++ ++ int ai_count; // Count of analog input channels ++ int ai_sh_count; // Count of sample and hold devices ++ int ai_ex_trig_analog; // Flag to indicate if analogous external trigger is available ++ ++ int dio_count; // Count of digital I/O ports ++ ++ int cnt_count; // Count of counters ++} me4000_user_info_t; ++ ++/*----------------------------------------------------------------------------- ++ Type definitions for analog output ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct me4000_ao_channel_list { ++ unsigned long count; ++ unsigned long *list; ++} me4000_ao_channel_list_t; ++ ++/*----------------------------------------------------------------------------- ++ Type definitions for analog input ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct me4000_ai_channel_list { ++ unsigned long count; ++ unsigned long *list; ++} me4000_ai_channel_list_t; ++ ++typedef struct me4000_ai_timer { ++ unsigned long pre_chan; ++ unsigned long chan; ++ unsigned long scan_low; ++ unsigned long scan_high; ++} me4000_ai_timer_t; ++ ++typedef struct me4000_ai_config { ++ me4000_ai_timer_t timer; ++ me4000_ai_channel_list_t channel_list; ++ int sh; ++} me4000_ai_config_t; ++ ++typedef struct me4000_ai_single { ++ int channel; ++ int range; ++ int mode; ++ short value; ++ unsigned long timeout; ++} me4000_ai_single_t; ++ ++typedef struct me4000_ai_trigger { ++ int mode; ++ int edge; ++} me4000_ai_trigger_t; ++ ++typedef struct me4000_ai_sc { ++ unsigned long value; ++ int reload; ++} me4000_ai_sc_t; ++ ++/*----------------------------------------------------------------------------- ++ Type definitions for eeprom ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct me4000_eeprom { ++ unsigned long date; ++ short uni_10_offset; ++ short uni_10_fullscale; ++ short uni_2_5_offset; ++ short uni_2_5_fullscale; ++ short bi_10_offset; ++ short bi_10_fullscale; ++ short bi_2_5_offset; ++ short bi_2_5_fullscale; ++ short diff_10_offset; ++ short diff_10_fullscale; ++ short diff_2_5_offset; ++ short diff_2_5_fullscale; ++} me4000_eeprom_t; ++ ++/*----------------------------------------------------------------------------- ++ Type definitions for digital I/O ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct me4000_dio_config { ++ int port; ++ int mode; ++ int function; ++} me4000_dio_config_t; ++ ++typedef struct me4000_dio_byte { ++ int port; ++ unsigned char byte; ++} me4000_dio_byte_t; ++ ++/*----------------------------------------------------------------------------- ++ Type definitions for counters ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct me4000_cnt { ++ int counter; ++ unsigned short value; ++} me4000_cnt_t; ++ ++typedef struct me4000_cnt_config { ++ int counter; ++ int mode; ++} me4000_cnt_config_t; ++ ++/*----------------------------------------------------------------------------- ++ Type definitions for external interrupt ++ ----------------------------------------------------------------------------*/ ++ ++typedef struct { ++ int int1_count; ++ int int2_count; ++} me4000_int_type; ++ ++/*----------------------------------------------------------------------------- ++ The ioctls of the board ++ ----------------------------------------------------------------------------*/ ++ ++#define ME4000_IOCTL_MAXNR 50 ++#define ME4000_MAGIC 'y' ++#define ME4000_GET_USER_INFO _IOR (ME4000_MAGIC, 0, me4000_user_info_t) ++ ++#define ME4000_AO_START _IOW (ME4000_MAGIC, 1, unsigned long) ++#define ME4000_AO_STOP _IO (ME4000_MAGIC, 2) ++#define ME4000_AO_IMMEDIATE_STOP _IO (ME4000_MAGIC, 3) ++#define ME4000_AO_RESET _IO (ME4000_MAGIC, 4) ++#define ME4000_AO_PRELOAD _IO (ME4000_MAGIC, 5) ++#define ME4000_AO_PRELOAD_UPDATE _IO (ME4000_MAGIC, 6) ++#define ME4000_AO_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 7) ++#define ME4000_AO_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 8) ++#define ME4000_AO_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 9, int) ++#define ME4000_AO_TIMER_SET_DIVISOR _IOW (ME4000_MAGIC, 10, unsigned long) ++#define ME4000_AO_ENABLE_DO _IO (ME4000_MAGIC, 11) ++#define ME4000_AO_DISABLE_DO _IO (ME4000_MAGIC, 12) ++#define ME4000_AO_FSM_STATE _IOR (ME4000_MAGIC, 13, int) ++ ++#define ME4000_AI_SINGLE _IOR (ME4000_MAGIC, 14, me4000_ai_single_t) ++#define ME4000_AI_START _IOW (ME4000_MAGIC, 15, unsigned long) ++#define ME4000_AI_STOP _IO (ME4000_MAGIC, 16) ++#define ME4000_AI_IMMEDIATE_STOP _IO (ME4000_MAGIC, 17) ++#define ME4000_AI_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 18) ++#define ME4000_AI_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 19) ++#define ME4000_AI_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 20, me4000_ai_trigger_t) ++#define ME4000_AI_CONFIG _IOW (ME4000_MAGIC, 21, me4000_ai_config_t) ++#define ME4000_AI_SC_SETUP _IOW (ME4000_MAGIC, 22, me4000_ai_sc_t) ++#define ME4000_AI_FSM_STATE _IOR (ME4000_MAGIC, 23, int) ++ ++#define ME4000_DIO_CONFIG _IOW (ME4000_MAGIC, 24, me4000_dio_config_t) ++#define ME4000_DIO_GET_BYTE _IOR (ME4000_MAGIC, 25, me4000_dio_byte_t) ++#define ME4000_DIO_SET_BYTE _IOW (ME4000_MAGIC, 26, me4000_dio_byte_t) ++#define ME4000_DIO_RESET _IO (ME4000_MAGIC, 27) ++ ++#define ME4000_CNT_READ _IOR (ME4000_MAGIC, 28, me4000_cnt_t) ++#define ME4000_CNT_WRITE _IOW (ME4000_MAGIC, 29, me4000_cnt_t) ++#define ME4000_CNT_CONFIG _IOW (ME4000_MAGIC, 30, me4000_cnt_config_t) ++#define ME4000_CNT_RESET _IO (ME4000_MAGIC, 31) ++ ++#define ME4000_EXT_INT_DISABLE _IO (ME4000_MAGIC, 32) ++#define ME4000_EXT_INT_ENABLE _IO (ME4000_MAGIC, 33) ++#define ME4000_EXT_INT_COUNT _IOR (ME4000_MAGIC, 34, int) ++ ++#define ME4000_AI_OFFSET_ENABLE _IO (ME4000_MAGIC, 35) ++#define ME4000_AI_OFFSET_DISABLE _IO (ME4000_MAGIC, 36) ++#define ME4000_AI_FULLSCALE_ENABLE _IO (ME4000_MAGIC, 37) ++#define ME4000_AI_FULLSCALE_DISABLE _IO (ME4000_MAGIC, 38) ++ ++#define ME4000_AI_EEPROM_READ _IOR (ME4000_MAGIC, 39, me4000_eeprom_t) ++#define ME4000_AI_EEPROM_WRITE _IOW (ME4000_MAGIC, 40, me4000_eeprom_t) ++ ++#define ME4000_AO_SIMULTANEOUS_EX_TRIG _IO (ME4000_MAGIC, 41) ++#define ME4000_AO_SIMULTANEOUS_SW _IO (ME4000_MAGIC, 42) ++#define ME4000_AO_SIMULTANEOUS_DISABLE _IO (ME4000_MAGIC, 43) ++#define ME4000_AO_SIMULTANEOUS_UPDATE _IOW (ME4000_MAGIC, 44, me4000_ao_channel_list_t) ++ ++#define ME4000_AO_SYNCHRONOUS_EX_TRIG _IO (ME4000_MAGIC, 45) ++#define ME4000_AO_SYNCHRONOUS_SW _IO (ME4000_MAGIC, 46) ++#define ME4000_AO_SYNCHRONOUS_DISABLE _IO (ME4000_MAGIC, 47) ++ ++#define ME4000_AO_EX_TRIG_TIMEOUT _IOW (ME4000_MAGIC, 48, unsigned long) ++#define ME4000_AO_GET_FREE_BUFFER _IOR (ME4000_MAGIC, 49, unsigned long) ++ ++#define ME4000_AI_GET_COUNT_BUFFER _IOR (ME4000_MAGIC, 50, unsigned long) ++ ++#endif +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0010-Staging-add-the-go7007-video-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0010-Staging-add-the-go7007-video-driver.patch new file mode 100644 index 000000000..8b3715ad2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0010-Staging-add-the-go7007-video-driver.patch @@ -0,0 +1,9473 @@ +From 866b8695d67e83f47194731d3a7ba55826a7ec70 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Fri, 15 Feb 2008 16:53:09 -0800 +Subject: [PATCH 10/23] Staging: add the go7007 video driver +Patch-mainline: 2.6.28 + +Todo: + - checkpatch.pl cleanups + - sparse cleanups + - lots of little modules, should be merged together + and added to the build. + - testing? + - handle churn in v4l layer. + +Many thanks to Ross Cohen for cleanup patches on +this driver. + +Cc: Ross Cohen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/go7007/Kconfig | 25 + + drivers/staging/go7007/Makefile | 18 + + drivers/staging/go7007/README | 11 + + drivers/staging/go7007/go7007-driver.c | 688 +++++++++++++ + drivers/staging/go7007/go7007-fw.c | 1639 +++++++++++++++++++++++++++++++ + drivers/staging/go7007/go7007-i2c.c | 309 ++++++ + drivers/staging/go7007/go7007-priv.h | 279 ++++++ + drivers/staging/go7007/go7007-usb.c | 1229 +++++++++++++++++++++++ + drivers/staging/go7007/go7007-v4l2.c | 1503 ++++++++++++++++++++++++++++ + drivers/staging/go7007/go7007.h | 114 +++ + drivers/staging/go7007/saa7134-go7007.c | 484 +++++++++ + drivers/staging/go7007/snd-go7007.c | 305 ++++++ + drivers/staging/go7007/wis-i2c.h | 55 + + drivers/staging/go7007/wis-ov7640.c | 131 +++ + drivers/staging/go7007/wis-saa7113.c | 363 +++++++ + drivers/staging/go7007/wis-saa7115.c | 492 +++++++++ + drivers/staging/go7007/wis-sony-tuner.c | 741 ++++++++++++++ + drivers/staging/go7007/wis-tw2804.c | 381 +++++++ + drivers/staging/go7007/wis-tw9903.c | 363 +++++++ + drivers/staging/go7007/wis-uda1342.c | 136 +++ + 22 files changed, 9269 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/go7007/Kconfig + create mode 100644 drivers/staging/go7007/Makefile + create mode 100644 drivers/staging/go7007/README + create mode 100644 drivers/staging/go7007/go7007-driver.c + create mode 100644 drivers/staging/go7007/go7007-fw.c + create mode 100644 drivers/staging/go7007/go7007-i2c.c + create mode 100644 drivers/staging/go7007/go7007-priv.h + create mode 100644 drivers/staging/go7007/go7007-usb.c + create mode 100644 drivers/staging/go7007/go7007-v4l2.c + create mode 100644 drivers/staging/go7007/go7007.h + create mode 100644 drivers/staging/go7007/saa7134-go7007.c + create mode 100644 drivers/staging/go7007/snd-go7007.c + create mode 100644 drivers/staging/go7007/wis-i2c.h + create mode 100644 drivers/staging/go7007/wis-ov7640.c + create mode 100644 drivers/staging/go7007/wis-saa7113.c + create mode 100644 drivers/staging/go7007/wis-saa7115.c + create mode 100644 drivers/staging/go7007/wis-sony-tuner.c + create mode 100644 drivers/staging/go7007/wis-tw2804.c + create mode 100644 drivers/staging/go7007/wis-tw9903.c + create mode 100644 drivers/staging/go7007/wis-uda1342.c + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 56c73bc..f16bc9c 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -31,4 +31,6 @@ source "drivers/staging/sxg/Kconfig" + + source "drivers/staging/me4000/Kconfig" + ++source "drivers/staging/go7007/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 97df19b..aa61662 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -4,3 +4,4 @@ obj-$(CONFIG_ET131X) += et131x/ + obj-$(CONFIG_SLICOSS) += slicoss/ + obj-$(CONFIG_SXG) += sxg/ + obj-$(CONFIG_ME4000) += me4000/ ++obj-$(CONFIG_VIDEO_GO7007) += go7007/ +diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig +new file mode 100644 +index 0000000..57a121c +--- /dev/null ++++ b/drivers/staging/go7007/Kconfig +@@ -0,0 +1,25 @@ ++config VIDEO_GO7007 ++ tristate "Go 7007 support" ++ depends on VIDEO_DEV && PCI && I2C && INPUT ++ select VIDEOBUF_DMA_SG ++ select VIDEO_IR ++ select VIDEO_TUNER ++ select VIDEO_TVEEPROM ++ select CRC32 ++ default N ++ ---help--- ++ This is a video4linux driver for some wierd device... ++ ++ To compile this driver as a module, choose M here: the ++ module will be called go7007 ++ ++config VIDEO_GO7007_USB ++ tristate "Go 7007 USB support" ++ depends on VIDEO_GO7007 && USB ++ default N ++ ---help--- ++ This is a video4linux driver for some wierd device... ++ ++ To compile this driver as a module, choose M here: the ++ module will be called go7007-usb ++ +diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/go7007/Makefile +new file mode 100644 +index 0000000..9b9310c +--- /dev/null ++++ b/drivers/staging/go7007/Makefile +@@ -0,0 +1,18 @@ ++#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \ ++ wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \ ++ wis-tw2804.o ++ ++ ++obj-$(CONFIG_VIDEO_GO7007) += go7007.o ++obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o ++ ++go7007-objs += go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o snd-go7007.o ++ ++ ++#ifneq ($(SAA7134_BUILD),) ++#obj-m += saa7134-go7007.o ++#endif ++ ++EXTRA_CFLAGS += -Idrivers/staging/saa7134 ++EXTRA_CFLAGS += -Idrivers/media/dvb/frontends ++EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +diff --git a/drivers/staging/go7007/README b/drivers/staging/go7007/README +new file mode 100644 +index 0000000..48f4476 +--- /dev/null ++++ b/drivers/staging/go7007/README +@@ -0,0 +1,11 @@ ++Todo: ++ - checkpatch.pl cleanups ++ - sparse cleanups ++ - lots of little modules, should be merged together ++ and added to the build. ++ - testing? ++ - handle churn in v4l layer. ++ ++Please send patchs to Greg Kroah-Hartman and Cc: Ross ++Cohen as well. ++ +diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c +new file mode 100644 +index 0000000..5a336ff +--- /dev/null ++++ b/drivers/staging/go7007/go7007-driver.c +@@ -0,0 +1,688 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "go7007-priv.h" ++#include "wis-i2c.h" ++ ++/* ++ * Wait for an interrupt to be delivered from the GO7007SB and return ++ * the associated value and data. ++ * ++ * Must be called with the hw_lock held. ++ */ ++int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data) ++{ ++ go->interrupt_available = 0; ++ go->hpi_ops->read_interrupt(go); ++ if (wait_event_timeout(go->interrupt_waitq, ++ go->interrupt_available, 5*HZ) < 0) { ++ printk(KERN_ERR "go7007: timeout waiting for read interrupt\n"); ++ return -1; ++ } ++ if (!go->interrupt_available) ++ return -1; ++ go->interrupt_available = 0; ++ *value = go->interrupt_value & 0xfffe; ++ *data = go->interrupt_data; ++ return 0; ++} ++EXPORT_SYMBOL(go7007_read_interrupt); ++ ++/* ++ * Read a register/address on the GO7007SB. ++ * ++ * Must be called with the hw_lock held. ++ */ ++int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data) ++{ ++ int count = 100; ++ u16 value; ++ ++ if (go7007_write_interrupt(go, 0x0010, addr) < 0) ++ return -EIO; ++ while (count-- > 0) { ++ if (go7007_read_interrupt(go, &value, data) == 0 && ++ value == 0xa000) ++ return 0; ++ } ++ return -EIO; ++} ++EXPORT_SYMBOL(go7007_read_addr); ++ ++/* ++ * Send the boot firmware to the encoder, which just wakes it up and lets ++ * us talk to the GPIO pins and on-board I2C adapter. ++ * ++ * Must be called with the hw_lock held. ++ */ ++static int go7007_load_encoder(struct go7007 *go) ++{ ++ const struct firmware *fw_entry; ++ char fw_name[] = "go7007fw.bin"; ++ void *bounce; ++ int fw_len, rv = 0; ++ u16 intr_val, intr_data; ++ ++ if (request_firmware(&fw_entry, fw_name, go->dev)) { ++ printk(KERN_ERR ++ "go7007: unable to load firmware from file \"%s\"\n", ++ fw_name); ++ return -1; ++ } ++ if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) { ++ printk(KERN_ERR "go7007: file \"%s\" does not appear to be " ++ "go7007 firmware\n", fw_name); ++ release_firmware(fw_entry); ++ return -1; ++ } ++ fw_len = fw_entry->size - 16; ++ bounce = kmalloc(fw_len, GFP_KERNEL); ++ if (bounce == NULL) { ++ printk(KERN_ERR "go7007: unable to allocate %d bytes for " ++ "firmware transfer\n", fw_len); ++ release_firmware(fw_entry); ++ return -1; ++ } ++ memcpy(bounce, fw_entry->data + 16, fw_len); ++ release_firmware(fw_entry); ++ if (go7007_interface_reset(go) < 0 || ++ go7007_send_firmware(go, bounce, fw_len) < 0 || ++ go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || ++ (intr_val & ~0x1) != 0x5a5a) { ++ printk(KERN_ERR "go7007: error transferring firmware\n"); ++ rv = -1; ++ } ++ kfree(bounce); ++ return rv; ++} ++ ++/* ++ * Boot the encoder and register the I2C adapter if requested. Do the ++ * minimum initialization necessary, since the board-specific code may ++ * still need to probe the board ID. ++ * ++ * Must NOT be called with the hw_lock held. ++ */ ++int go7007_boot_encoder(struct go7007 *go, int init_i2c) ++{ ++ int ret; ++ ++ down(&go->hw_lock); ++ ret = go7007_load_encoder(go); ++ up(&go->hw_lock); ++ if (ret < 0) ++ return -1; ++ if (!init_i2c) ++ return 0; ++ if (go7007_i2c_init(go) < 0) ++ return -1; ++ go->i2c_adapter_online = 1; ++ return 0; ++} ++EXPORT_SYMBOL(go7007_boot_encoder); ++ ++/* ++ * Configure any hardware-related registers in the GO7007, such as GPIO ++ * pins and bus parameters, which are board-specific. This assumes ++ * the boot firmware has already been downloaded. ++ * ++ * Must be called with the hw_lock held. ++ */ ++static int go7007_init_encoder(struct go7007 *go) ++{ ++ if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) { ++ go7007_write_addr(go, 0x1000, 0x0811); ++ go7007_write_addr(go, 0x1000, 0x0c11); ++ } ++ if (go->board_id == GO7007_BOARDID_MATRIX_REV) { ++ /* Set GPIO pin 0 to be an output (audio clock control) */ ++ go7007_write_addr(go, 0x3c82, 0x0001); ++ go7007_write_addr(go, 0x3c80, 0x00fe); ++ } ++ return 0; ++} ++ ++/* ++ * Send the boot firmware to the GO7007 and configure the registers. This ++ * is the only way to stop the encoder once it has started streaming video. ++ * ++ * Must be called with the hw_lock held. ++ */ ++int go7007_reset_encoder(struct go7007 *go) ++{ ++ if (go7007_load_encoder(go) < 0) ++ return -1; ++ return go7007_init_encoder(go); ++} ++ ++/* ++ * Attempt to instantiate an I2C client by ID, probably loading a module. ++ */ ++static int init_i2c_module(struct i2c_adapter *adapter, int id, int addr) ++{ ++ char *modname; ++ ++ switch (id) { ++ case I2C_DRIVERID_WIS_SAA7115: ++ modname = "wis-saa7115"; ++ break; ++ case I2C_DRIVERID_WIS_SAA7113: ++ modname = "wis-saa7113"; ++ break; ++ case I2C_DRIVERID_WIS_UDA1342: ++ modname = "wis-uda1342"; ++ break; ++ case I2C_DRIVERID_WIS_SONY_TUNER: ++ modname = "wis-sony-tuner"; ++ break; ++ case I2C_DRIVERID_WIS_TW9903: ++ modname = "wis-tw9903"; ++ break; ++ case I2C_DRIVERID_WIS_TW2804: ++ modname = "wis-tw2804"; ++ break; ++ case I2C_DRIVERID_WIS_OV7640: ++ modname = "wis-ov7640"; ++ break; ++ default: ++ modname = NULL; ++ break; ++ } ++ if (modname != NULL) ++ request_module(modname); ++ if (wis_i2c_probe_device(adapter, id, addr) == 1) ++ return 0; ++ if (modname != NULL) ++ printk(KERN_INFO ++ "go7007: probing for module %s failed", modname); ++ else ++ printk(KERN_INFO ++ "go7007: sensor %u seems to be unsupported!\n", id); ++ return -1; ++} ++ ++/* ++ * Finalize the GO7007 hardware setup, register the on-board I2C adapter ++ * (if used on this board), load the I2C client driver for the sensor ++ * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2 ++ * interfaces. ++ * ++ * Must NOT be called with the hw_lock held. ++ */ ++int go7007_register_encoder(struct go7007 *go) ++{ ++ int i, ret; ++ ++ printk(KERN_INFO "go7007: registering new %s\n", go->name); ++ ++ down(&go->hw_lock); ++ ret = go7007_init_encoder(go); ++ up(&go->hw_lock); ++ if (ret < 0) ++ return -1; ++ ++ if (!go->i2c_adapter_online && ++ go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { ++ if (go7007_i2c_init(go) < 0) ++ return -1; ++ go->i2c_adapter_online = 1; ++ } ++ if (go->i2c_adapter_online) { ++ for (i = 0; i < go->board_info->num_i2c_devs; ++i) ++ init_i2c_module(&go->i2c_adapter, ++ go->board_info->i2c_devs[i].id, ++ go->board_info->i2c_devs[i].addr); ++#ifdef TUNER_SET_TYPE_ADDR ++ if (go->tuner_type >= 0) { ++ struct tuner_setup tun_setup = { ++ .mode_mask = T_ANALOG_TV, ++ .addr = ADDR_UNSET, ++ .type = go->tuner_type ++ }; ++ i2c_clients_command(&go->i2c_adapter, ++ TUNER_SET_TYPE_ADDR, &tun_setup); ++ } ++#else ++ if (go->tuner_type >= 0) ++ i2c_clients_command(&go->i2c_adapter, ++ TUNER_SET_TYPE, &go->tuner_type); ++#endif ++ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) ++ i2c_clients_command(&go->i2c_adapter, ++ DECODER_SET_CHANNEL, &go->channel_number); ++ } ++ if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { ++ go->audio_enabled = 1; ++ go7007_snd_init(go); ++ } ++ return go7007_v4l2_init(go); ++} ++EXPORT_SYMBOL(go7007_register_encoder); ++ ++/* ++ * Send the encode firmware to the encoder, which will cause it ++ * to immediately start delivering the video and audio streams. ++ * ++ * Must be called with the hw_lock held. ++ */ ++int go7007_start_encoder(struct go7007 *go) ++{ ++ u8 *fw; ++ int fw_len, rv = 0, i; ++ u16 intr_val, intr_data; ++ ++ go->modet_enable = 0; ++ if (!go->dvd_mode) ++ for (i = 0; i < 4; ++i) { ++ if (go->modet[i].enable) { ++ go->modet_enable = 1; ++ continue; ++ } ++ go->modet[i].pixel_threshold = 32767; ++ go->modet[i].motion_threshold = 32767; ++ go->modet[i].mb_threshold = 32767; ++ } ++ ++ if (go7007_construct_fw_image(go, &fw, &fw_len) < 0) ++ return -1; ++ ++ if (go7007_send_firmware(go, fw, fw_len) < 0 || ++ go7007_read_interrupt(go, &intr_val, &intr_data) < 0) { ++ printk(KERN_ERR "go7007: error transferring firmware\n"); ++ rv = -1; ++ goto start_error; ++ } ++ ++ go->state = STATE_DATA; ++ go->parse_length = 0; ++ go->seen_frame = 0; ++ if (go7007_stream_start(go) < 0) { ++ printk(KERN_ERR "go7007: error starting stream transfer\n"); ++ rv = -1; ++ goto start_error; ++ } ++ ++start_error: ++ kfree(fw); ++ return rv; ++} ++ ++/* ++ * Store a byte in the current video buffer, if there is one. ++ */ ++static inline void store_byte(struct go7007_buffer *gobuf, u8 byte) ++{ ++ if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) { ++ unsigned int pgidx = gobuf->offset >> PAGE_SHIFT; ++ unsigned int pgoff = gobuf->offset & ~PAGE_MASK; ++ ++ *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte; ++ ++gobuf->offset; ++ ++gobuf->bytesused; ++ } ++} ++ ++/* ++ * Deliver the last video buffer and get a new one to start writing to. ++ */ ++static void frame_boundary(struct go7007 *go) ++{ ++ struct go7007_buffer *gobuf; ++ int i; ++ ++ if (go->active_buf) { ++ if (go->active_buf->modet_active) { ++ if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) { ++ for (i = 0; i < 216; ++i) ++ store_byte(go->active_buf, ++ go->active_map[i]); ++ go->active_buf->bytesused -= 216; ++ } else ++ go->active_buf->modet_active = 0; ++ } ++ go->active_buf->state = BUF_STATE_DONE; ++ wake_up_interruptible(&go->frame_waitq); ++ go->active_buf = NULL; ++ } ++ list_for_each_entry(gobuf, &go->stream, stream) ++ if (gobuf->state == BUF_STATE_QUEUED) { ++ gobuf->seq = go->next_seq; ++ do_gettimeofday(&gobuf->timestamp); ++ go->active_buf = gobuf; ++ break; ++ } ++ ++go->next_seq; ++} ++ ++static void write_bitmap_word(struct go7007 *go) ++{ ++ int x, y, i, stride = ((go->width >> 4) + 7) >> 3; ++ ++ for (i = 0; i < 16; ++i) { ++ y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4); ++ x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4); ++ go->active_map[stride * y + (x >> 3)] |= ++ (go->modet_word & 1) << (x & 0x7); ++ go->modet_word >>= 1; ++ } ++} ++ ++/* ++ * Parse a chunk of the video stream into frames. The frames are not ++ * delimited by the hardware, so we have to parse the frame boundaries ++ * based on the type of video stream we're receiving. ++ */ ++void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) ++{ ++ int i, seq_start_code = -1, frame_start_code = -1; ++ ++ spin_lock(&go->spinlock); ++ ++ switch (go->format) { ++ case GO7007_FORMAT_MPEG4: ++ seq_start_code = 0xB0; ++ frame_start_code = 0xB6; ++ break; ++ case GO7007_FORMAT_MPEG1: ++ case GO7007_FORMAT_MPEG2: ++ seq_start_code = 0xB3; ++ frame_start_code = 0x00; ++ break; ++ } ++ ++ for (i = 0; i < length; ++i) { ++ if (go->active_buf != NULL && ++ go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) { ++ printk(KERN_DEBUG "go7007: dropping oversized frame\n"); ++ go->active_buf->offset -= go->active_buf->bytesused; ++ go->active_buf->bytesused = 0; ++ go->active_buf->modet_active = 0; ++ go->active_buf = NULL; ++ } ++ ++ switch (go->state) { ++ case STATE_DATA: ++ switch (buf[i]) { ++ case 0x00: ++ go->state = STATE_00; ++ break; ++ case 0xFF: ++ go->state = STATE_FF; ++ break; ++ default: ++ store_byte(go->active_buf, buf[i]); ++ break; ++ } ++ break; ++ case STATE_00: ++ switch (buf[i]) { ++ case 0x00: ++ go->state = STATE_00_00; ++ break; ++ case 0xFF: ++ store_byte(go->active_buf, 0x00); ++ go->state = STATE_FF; ++ break; ++ default: ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, buf[i]); ++ go->state = STATE_DATA; ++ break; ++ } ++ break; ++ case STATE_00_00: ++ switch (buf[i]) { ++ case 0x00: ++ store_byte(go->active_buf, 0x00); ++ /* go->state remains STATE_00_00 */ ++ break; ++ case 0x01: ++ go->state = STATE_00_00_01; ++ break; ++ case 0xFF: ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, 0x00); ++ go->state = STATE_FF; ++ break; ++ default: ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, buf[i]); ++ go->state = STATE_DATA; ++ break; ++ } ++ break; ++ case STATE_00_00_01: ++ /* If this is the start of a new MPEG frame, ++ * get a new buffer */ ++ if ((go->format == GO7007_FORMAT_MPEG1 || ++ go->format == GO7007_FORMAT_MPEG2 || ++ go->format == GO7007_FORMAT_MPEG4) && ++ (buf[i] == seq_start_code || ++ buf[i] == 0xB8 || /* GOP code */ ++ buf[i] == frame_start_code)) { ++ if (go->active_buf == NULL || go->seen_frame) ++ frame_boundary(go); ++ if (buf[i] == frame_start_code) { ++ if (go->active_buf != NULL) ++ go->active_buf->frame_offset = ++ go->active_buf->offset; ++ go->seen_frame = 1; ++ } else { ++ go->seen_frame = 0; ++ } ++ } ++ /* Handle any special chunk types, or just write the ++ * start code to the (potentially new) buffer */ ++ switch (buf[i]) { ++ case 0xF5: /* timestamp */ ++ go->parse_length = 12; ++ go->state = STATE_UNPARSED; ++ break; ++ case 0xF6: /* vbi */ ++ go->state = STATE_VBI_LEN_A; ++ break; ++ case 0xF8: /* MD map */ ++ go->parse_length = 0; ++ memset(go->active_map, 0, ++ sizeof(go->active_map)); ++ go->state = STATE_MODET_MAP; ++ break; ++ case 0xFF: /* Potential JPEG start code */ ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, 0x01); ++ go->state = STATE_FF; ++ break; ++ default: ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, 0x00); ++ store_byte(go->active_buf, 0x01); ++ store_byte(go->active_buf, buf[i]); ++ go->state = STATE_DATA; ++ break; ++ } ++ break; ++ case STATE_FF: ++ switch (buf[i]) { ++ case 0x00: ++ store_byte(go->active_buf, 0xFF); ++ go->state = STATE_00; ++ break; ++ case 0xFF: ++ store_byte(go->active_buf, 0xFF); ++ /* go->state remains STATE_FF */ ++ break; ++ case 0xD8: ++ if (go->format == GO7007_FORMAT_MJPEG) ++ frame_boundary(go); ++ /* fall through */ ++ default: ++ store_byte(go->active_buf, 0xFF); ++ store_byte(go->active_buf, buf[i]); ++ go->state = STATE_DATA; ++ break; ++ } ++ break; ++ case STATE_VBI_LEN_A: ++ go->parse_length = buf[i] << 8; ++ go->state = STATE_VBI_LEN_B; ++ break; ++ case STATE_VBI_LEN_B: ++ go->parse_length |= buf[i]; ++ if (go->parse_length > 0) ++ go->state = STATE_UNPARSED; ++ else ++ go->state = STATE_DATA; ++ break; ++ case STATE_MODET_MAP: ++ if (go->parse_length < 204) { ++ if (go->parse_length & 1) { ++ go->modet_word |= buf[i]; ++ write_bitmap_word(go); ++ } else ++ go->modet_word = buf[i] << 8; ++ } else if (go->parse_length == 207 && go->active_buf) { ++ go->active_buf->modet_active = buf[i]; ++ } ++ if (++go->parse_length == 208) ++ go->state = STATE_DATA; ++ break; ++ case STATE_UNPARSED: ++ if (--go->parse_length == 0) ++ go->state = STATE_DATA; ++ break; ++ } ++ } ++ ++ spin_unlock(&go->spinlock); ++} ++EXPORT_SYMBOL(go7007_parse_video_stream); ++ ++/* ++ * Allocate a new go7007 struct. Used by the hardware-specific probe. ++ */ ++struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) ++{ ++ struct go7007 *go; ++ int i; ++ ++ go = kmalloc(sizeof(struct go7007), GFP_KERNEL); ++ if (go == NULL) ++ return NULL; ++ go->dev = dev; ++ go->board_info = board; ++ go->board_id = 0; ++ go->tuner_type = -1; ++ go->channel_number = 0; ++ go->name[0] = 0; ++ init_MUTEX(&go->hw_lock); ++ init_waitqueue_head(&go->frame_waitq); ++ spin_lock_init(&go->spinlock); ++ go->video_dev = NULL; ++ go->ref_count = 0; ++ go->status = STATUS_INIT; ++ memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); ++ go->i2c_adapter_online = 0; ++ go->interrupt_available = 0; ++ init_waitqueue_head(&go->interrupt_waitq); ++ go->in_use = 0; ++ go->input = 0; ++ if (board->sensor_flags & GO7007_SENSOR_TV) { ++ go->standard = GO7007_STD_NTSC; ++ go->width = 720; ++ go->height = 480; ++ go->sensor_framerate = 30000; ++ } else { ++ go->standard = GO7007_STD_OTHER; ++ go->width = board->sensor_width; ++ go->height = board->sensor_height; ++ go->sensor_framerate = board->sensor_framerate; ++ } ++ go->encoder_v_offset = board->sensor_v_offset; ++ go->encoder_h_offset = board->sensor_h_offset; ++ go->encoder_h_halve = 0; ++ go->encoder_v_halve = 0; ++ go->encoder_subsample = 0; ++ go->streaming = 0; ++ go->format = GO7007_FORMAT_MJPEG; ++ go->bitrate = 1500000; ++ go->fps_scale = 1; ++ go->pali = 0; ++ go->aspect_ratio = GO7007_RATIO_1_1; ++ go->gop_size = 0; ++ go->ipb = 0; ++ go->closed_gop = 0; ++ go->repeat_seqhead = 0; ++ go->seq_header_enable = 0; ++ go->gop_header_enable = 0; ++ go->dvd_mode = 0; ++ go->interlace_coding = 0; ++ for (i = 0; i < 4; ++i) ++ go->modet[i].enable = 0;; ++ for (i = 0; i < 1624; ++i) ++ go->modet_map[i] = 0; ++ go->audio_deliver = NULL; ++ go->audio_enabled = 0; ++ INIT_LIST_HEAD(&go->stream); ++ ++ return go; ++} ++EXPORT_SYMBOL(go7007_alloc); ++ ++/* ++ * Detach and unregister the encoder. The go7007 struct won't be freed ++ * until v4l2 finishes releasing its resources and all associated fds are ++ * closed by applications. ++ */ ++void go7007_remove(struct go7007 *go) ++{ ++ if (go->i2c_adapter_online) { ++ if (i2c_del_adapter(&go->i2c_adapter) == 0) ++ go->i2c_adapter_online = 0; ++ else ++ printk(KERN_ERR ++ "go7007: error removing I2C adapter!\n"); ++ } ++ ++ if (go->audio_enabled) ++ go7007_snd_remove(go); ++ go7007_v4l2_remove(go); ++} ++EXPORT_SYMBOL(go7007_remove); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/go7007/go7007-fw.c +new file mode 100644 +index 0000000..c2aea10 +--- /dev/null ++++ b/drivers/staging/go7007/go7007-fw.c +@@ -0,0 +1,1639 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++/* ++ * This file contains code to generate a firmware image for the GO7007SB ++ * encoder. Much of the firmware is read verbatim from a file, but some of ++ * it concerning bitrate control and other things that can be configured at ++ * run-time are generated dynamically. Note that the format headers ++ * generated here do not affect the functioning of the encoder; they are ++ * merely parroted back to the host at the start of each frame. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "go7007-priv.h" ++ ++/* Constants used in the source firmware image to describe code segments */ ++ ++#define FLAG_MODE_MJPEG (1) ++#define FLAG_MODE_MPEG1 (1<<1) ++#define FLAG_MODE_MPEG2 (1<<2) ++#define FLAG_MODE_MPEG4 (1<<3) ++#define FLAG_MODE_H263 (1<<4) ++#define FLAG_MODE_ALL (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \ ++ FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \ ++ FLAG_MODE_H263) ++#define FLAG_SPECIAL (1<<8) ++ ++#define SPECIAL_FRM_HEAD 0 ++#define SPECIAL_BRC_CTRL 1 ++#define SPECIAL_CONFIG 2 ++#define SPECIAL_SEQHEAD 3 ++#define SPECIAL_AV_SYNC 4 ++#define SPECIAL_FINAL 5 ++#define SPECIAL_AUDIO 6 ++#define SPECIAL_MODET 7 ++ ++/* Little data class for creating MPEG headers bit-by-bit */ ++ ++struct code_gen { ++ unsigned char *p; /* destination */ ++ u32 a; /* collects bits at the top of the variable */ ++ int b; /* bit position of most recently-written bit */ ++ int len; /* written out so far */ ++}; ++ ++#define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 } ++ ++#define CODE_ADD(name, val, length) do { \ ++ name.b -= (length); \ ++ name.a |= (val) << name.b; \ ++ while (name.b <= 24) { \ ++ *name.p = name.a >> 24; \ ++ ++name.p; \ ++ name.a <<= 8; \ ++ name.b += 8; \ ++ name.len += 8; \ ++ } \ ++} while (0) ++ ++#define CODE_LENGTH(name) (name.len + (32 - name.b)) ++ ++/* Tables for creating the bitrate control data */ ++ ++static const s16 converge_speed_ip[101] = { ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, ++ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, ++ 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, ++ 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, ++ 19, 20, 22, 23, 25, 27, 30, 32, 35, 38, ++ 41, 45, 49, 53, 58, 63, 69, 76, 83, 91, ++ 100 ++}; ++ ++static const s16 converge_speed_ipb[101] = { ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, ++ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, ++ 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, ++ 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, ++ 9, 9, 10, 10, 11, 12, 12, 13, 14, 14, ++ 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, ++ 28, 30, 32, 34, 37, 40, 42, 46, 49, 53, ++ 57, 61, 66, 71, 77, 83, 90, 97, 106, 115, ++ 125, 135, 147, 161, 175, 191, 209, 228, 249, 273, ++ 300 ++}; ++ ++static const s16 LAMBDA_table[4][101] = { ++ { 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, ++ 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, ++ 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, ++ 27, 27, 28, 28, 29, 29, 30, 31, 31, 32, ++ 32, 33, 33, 34, 35, 35, 36, 37, 37, 38, ++ 39, 39, 40, 41, 42, 42, 43, 44, 45, 46, ++ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, ++ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, ++ 67, 68, 69, 70, 72, 73, 74, 76, 77, 78, ++ 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, ++ 96 ++ }, ++ { ++ 20, 20, 20, 21, 21, 21, 22, 22, 23, 23, ++ 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, ++ 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, ++ 34, 34, 35, 36, 36, 37, 38, 38, 39, 40, ++ 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, ++ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, ++ 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, ++ 70, 71, 72, 73, 75, 76, 78, 79, 80, 82, ++ 83, 85, 86, 88, 90, 91, 93, 95, 96, 98, ++ 100, 102, 103, 105, 107, 109, 111, 113, 115, 117, ++ 120 ++ }, ++ { ++ 24, 24, 24, 25, 25, 26, 26, 27, 27, 28, ++ 28, 29, 29, 30, 30, 31, 31, 32, 33, 33, ++ 34, 34, 35, 36, 36, 37, 38, 38, 39, 40, ++ 41, 41, 42, 43, 44, 44, 45, 46, 47, 48, ++ 49, 50, 50, 51, 52, 53, 54, 55, 56, 57, ++ 58, 59, 60, 62, 63, 64, 65, 66, 67, 69, ++ 70, 71, 72, 74, 75, 76, 78, 79, 81, 82, ++ 84, 85, 87, 88, 90, 92, 93, 95, 97, 98, ++ 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, ++ 120, 122, 124, 127, 129, 131, 134, 136, 138, 141, ++ 144 ++ }, ++ { ++ 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, ++ 38, 38, 39, 40, 41, 41, 42, 43, 44, 44, ++ 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, ++ 54, 55, 56, 57, 58, 59, 60, 62, 63, 64, ++ 65, 66, 67, 69, 70, 71, 72, 74, 75, 76, ++ 78, 79, 81, 82, 84, 85, 87, 88, 90, 92, ++ 93, 95, 97, 98, 100, 102, 104, 106, 108, 110, ++ 112, 114, 116, 118, 120, 122, 124, 127, 129, 131, ++ 134, 136, 139, 141, 144, 146, 149, 152, 154, 157, ++ 160, 163, 166, 169, 172, 175, 178, 181, 185, 188, ++ 192 ++ } ++}; ++ ++/* MPEG blank frame generation tables */ ++ ++enum mpeg_frame_type { ++ PFRAME, ++ BFRAME_PRE, ++ BFRAME_POST, ++ BFRAME_BIDIR, ++ BFRAME_EMPTY ++}; ++ ++static const u32 addrinctab[33][2] = { ++ { 0x01, 1 }, { 0x03, 3 }, { 0x02, 3 }, { 0x03, 4 }, ++ { 0x02, 4 }, { 0x03, 5 }, { 0x02, 5 }, { 0x07, 7 }, ++ { 0x06, 7 }, { 0x0b, 8 }, { 0x0a, 8 }, { 0x09, 8 }, ++ { 0x08, 8 }, { 0x07, 8 }, { 0x06, 8 }, { 0x17, 10 }, ++ { 0x16, 10 }, { 0x15, 10 }, { 0x14, 10 }, { 0x13, 10 }, ++ { 0x12, 10 }, { 0x23, 11 }, { 0x22, 11 }, { 0x21, 11 }, ++ { 0x20, 11 }, { 0x1f, 11 }, { 0x1e, 11 }, { 0x1d, 11 }, ++ { 0x1c, 11 }, { 0x1b, 11 }, { 0x1a, 11 }, { 0x19, 11 }, ++ { 0x18, 11 } ++}; ++ ++/* Standard JPEG tables */ ++ ++static const u8 default_intra_quant_table[] = { ++ 8, 16, 19, 22, 26, 27, 29, 34, ++ 16, 16, 22, 24, 27, 29, 34, 37, ++ 19, 22, 26, 27, 29, 34, 34, 38, ++ 22, 22, 26, 27, 29, 34, 37, 40, ++ 22, 26, 27, 29, 32, 35, 40, 48, ++ 26, 27, 29, 32, 35, 40, 48, 58, ++ 26, 27, 29, 34, 38, 46, 56, 69, ++ 27, 29, 35, 38, 46, 56, 69, 83 ++}; ++ ++static const u8 bits_dc_luminance[] = { ++ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++static const u8 val_dc_luminance[] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ++}; ++ ++static const u8 bits_dc_chrominance[] = { ++ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 ++}; ++ ++static const u8 val_dc_chrominance[] = { ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ++}; ++ ++static const u8 bits_ac_luminance[] = { ++ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d ++}; ++ ++static const u8 val_ac_luminance[] = { ++ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, ++ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, ++ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, ++ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, ++ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, ++ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, ++ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, ++ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, ++ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, ++ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, ++ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, ++ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, ++ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, ++ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, ++ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, ++ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, ++ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, ++ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, ++ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, ++ 0xf9, 0xfa ++}; ++ ++static const u8 bits_ac_chrominance[] = { ++ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 ++}; ++ ++static const u8 val_ac_chrominance[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, ++ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, ++ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, ++ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, ++ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, ++ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, ++ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, ++ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, ++ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, ++ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, ++ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, ++ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, ++ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, ++ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, ++ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, ++ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, ++ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, ++ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, ++ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, ++ 0xf9, 0xfa ++}; ++ ++/* Zig-zag mapping for quant table ++ * ++ * OK, let's do this mapping on the actual table above so it doesn't have ++ * to be done on the fly. ++ */ ++static const int zz[64] = { ++ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, ++ 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, ++ 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, ++ 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 ++}; ++ ++static int copy_packages(u16 *dest, u16 *src, int pkg_cnt, int space) ++{ ++ int i, cnt = pkg_cnt * 32; ++ ++ if (space < cnt) ++ return -1; ++ ++ for (i = 0; i < cnt; ++i) ++ dest[i] = __cpu_to_le16(src[i]); ++ ++ return cnt; ++} ++ ++static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q) ++{ ++ int i, p = 0; ++ ++ buf[p++] = 0xff; ++ buf[p++] = 0xd8; ++ buf[p++] = 0xff; ++ buf[p++] = 0xdb; ++ buf[p++] = 0; ++ buf[p++] = 2 + 65; ++ buf[p++] = 0; ++ buf[p++] = default_intra_quant_table[0]; ++ for (i = 1; i < 64; ++i) ++ /* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */ ++ buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3; ++ buf[p++] = 0xff; ++ buf[p++] = 0xc0; ++ buf[p++] = 0; ++ buf[p++] = 17; ++ buf[p++] = 8; ++ buf[p++] = go->height >> 8; ++ buf[p++] = go->height & 0xff; ++ buf[p++] = go->width >> 8; ++ buf[p++] = go->width & 0xff; ++ buf[p++] = 3; ++ buf[p++] = 1; ++ buf[p++] = 0x22; ++ buf[p++] = 0; ++ buf[p++] = 2; ++ buf[p++] = 0x11; ++ buf[p++] = 0; ++ buf[p++] = 3; ++ buf[p++] = 0x11; ++ buf[p++] = 0; ++ buf[p++] = 0xff; ++ buf[p++] = 0xc4; ++ buf[p++] = 418 >> 8; ++ buf[p++] = 418 & 0xff; ++ buf[p++] = 0x00; ++ memcpy(buf + p, bits_dc_luminance + 1, 16); ++ p += 16; ++ memcpy(buf + p, val_dc_luminance, sizeof(val_dc_luminance)); ++ p += sizeof(val_dc_luminance); ++ buf[p++] = 0x01; ++ memcpy(buf + p, bits_dc_chrominance + 1, 16); ++ p += 16; ++ memcpy(buf + p, val_dc_chrominance, sizeof(val_dc_chrominance)); ++ p += sizeof(val_dc_chrominance); ++ buf[p++] = 0x10; ++ memcpy(buf + p, bits_ac_luminance + 1, 16); ++ p += 16; ++ memcpy(buf + p, val_ac_luminance, sizeof(val_ac_luminance)); ++ p += sizeof(val_ac_luminance); ++ buf[p++] = 0x11; ++ memcpy(buf + p, bits_ac_chrominance + 1, 16); ++ p += 16; ++ memcpy(buf + p, val_ac_chrominance, sizeof(val_ac_chrominance)); ++ p += sizeof(val_ac_chrominance); ++ buf[p++] = 0xff; ++ buf[p++] = 0xda; ++ buf[p++] = 0; ++ buf[p++] = 12; ++ buf[p++] = 3; ++ buf[p++] = 1; ++ buf[p++] = 0x00; ++ buf[p++] = 2; ++ buf[p++] = 0x11; ++ buf[p++] = 3; ++ buf[p++] = 0x11; ++ buf[p++] = 0; ++ buf[p++] = 63; ++ buf[p++] = 0; ++ return p; ++} ++ ++static int gen_mjpeghdr_to_package(struct go7007 *go, u16 *code, int space) ++{ ++ u8 *buf; ++ u16 mem = 0x3e00; ++ unsigned int addr = 0x19; ++ int size = 0, i, off = 0, chunk; ++ ++ buf = kmalloc(4096, GFP_KERNEL); ++ if (buf == NULL) { ++ printk(KERN_ERR "go7007: unable to allocate 4096 bytes for " ++ "firmware construction\n"); ++ return -1; ++ } ++ memset(buf, 0, 4096); ++ ++ for (i = 1; i < 32; ++i) { ++ mjpeg_frame_header(go, buf + size, i); ++ size += 80; ++ } ++ chunk = mjpeg_frame_header(go, buf + size, 1); ++ memmove(buf + size, buf + size + 80, chunk - 80); ++ size += chunk - 80; ++ ++ for (i = 0; i < size; i += chunk * 2) { ++ if (space - off < 32) { ++ off = -1; ++ goto done; ++ } ++ ++ code[off + 1] = __cpu_to_le16(0x8000 | mem); ++ ++ chunk = 28; ++ if (mem + chunk > 0x4000) ++ chunk = 0x4000 - mem; ++ if (i + 2 * chunk > size) ++ chunk = (size - i) / 2; ++ ++ if (chunk < 28) { ++ code[off] = __cpu_to_le16(0x4000 | chunk); ++ code[off + 31] = __cpu_to_le16(addr++); ++ mem = 0x3e00; ++ } else { ++ code[off] = __cpu_to_le16(0x1000 | 28); ++ code[off + 31] = 0; ++ mem += 28; ++ } ++ ++ memcpy(&code[off + 2], buf + i, chunk * 2); ++ off += 32; ++ } ++done: ++ kfree(buf); ++ return off; ++} ++ ++static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf, ++ int modulo, int pict_struct, enum mpeg_frame_type frame) ++{ ++ int i, j, mb_code, mb_len; ++ int rows = go->interlace_coding ? go->height / 32 : go->height / 16; ++ CODE_GEN(c, buf + 6); ++ ++ switch (frame) { ++ case PFRAME: ++ mb_code = 0x1; ++ mb_len = 3; ++ break; ++ case BFRAME_PRE: ++ mb_code = 0x2; ++ mb_len = 4; ++ break; ++ case BFRAME_POST: ++ mb_code = 0x2; ++ mb_len = 3; ++ break; ++ case BFRAME_BIDIR: ++ mb_code = 0x2; ++ mb_len = 2; ++ break; ++ default: /* keep the compiler happy */ ++ mb_code = mb_len = 0; ++ break; ++ } ++ ++ CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13); ++ CODE_ADD(c, 0xffff, 16); ++ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); ++ if (frame != PFRAME) ++ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); ++ else ++ CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */ ++ CODE_ADD(c, 0, 3); /* What is this?? */ ++ /* Byte-align with zeros */ ++ j = 8 - (CODE_LENGTH(c) % 8); ++ if (j != 8) ++ CODE_ADD(c, 0, j); ++ ++ if (go->format == GO7007_FORMAT_MPEG2) { ++ CODE_ADD(c, 0x1, 24); ++ CODE_ADD(c, 0xb5, 8); ++ CODE_ADD(c, 0x844, 12); ++ CODE_ADD(c, frame == PFRAME ? 0xff : 0x44, 8); ++ if (go->interlace_coding) { ++ CODE_ADD(c, pict_struct, 4); ++ if (go->dvd_mode) ++ CODE_ADD(c, 0x000, 11); ++ else ++ CODE_ADD(c, 0x200, 11); ++ } else { ++ CODE_ADD(c, 0x3, 4); ++ CODE_ADD(c, 0x20c, 11); ++ } ++ /* Byte-align with zeros */ ++ j = 8 - (CODE_LENGTH(c) % 8); ++ if (j != 8) ++ CODE_ADD(c, 0, j); ++ } ++ ++ for (i = 0; i < rows; ++i) { ++ CODE_ADD(c, 1, 24); ++ CODE_ADD(c, i + 1, 8); ++ CODE_ADD(c, 0x2, 6); ++ CODE_ADD(c, 0x1, 1); ++ CODE_ADD(c, mb_code, mb_len); ++ if (go->interlace_coding) { ++ CODE_ADD(c, 0x1, 2); ++ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); ++ } ++ if (frame == BFRAME_BIDIR) { ++ CODE_ADD(c, 0x3, 2); ++ if (go->interlace_coding) ++ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); ++ } ++ CODE_ADD(c, 0x3, 2); ++ for (j = (go->width >> 4) - 2; j >= 33; j -= 33) ++ CODE_ADD(c, 0x8, 11); ++ CODE_ADD(c, addrinctab[j][0], addrinctab[j][1]); ++ CODE_ADD(c, mb_code, mb_len); ++ if (go->interlace_coding) { ++ CODE_ADD(c, 0x1, 2); ++ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); ++ } ++ if (frame == BFRAME_BIDIR) { ++ CODE_ADD(c, 0x3, 2); ++ if (go->interlace_coding) ++ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1); ++ } ++ CODE_ADD(c, 0x3, 2); ++ ++ /* Byte-align with zeros */ ++ j = 8 - (CODE_LENGTH(c) % 8); ++ if (j != 8) ++ CODE_ADD(c, 0, j); ++ } ++ ++ i = CODE_LENGTH(c) + 4 * 8; ++ buf[2] = 0x00; ++ buf[3] = 0x00; ++ buf[4] = 0x01; ++ buf[5] = 0x00; ++ return i; ++} ++ ++static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext) ++{ ++ int i, aspect_ratio, picture_rate; ++ CODE_GEN(c, buf + 6); ++ ++ if (go->format == GO7007_FORMAT_MPEG1) { ++ switch (go->aspect_ratio) { ++ case GO7007_RATIO_4_3: ++ aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; ++ break; ++ case GO7007_RATIO_16_9: ++ aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4; ++ break; ++ default: ++ aspect_ratio = 1; ++ break; ++ } ++ } else { ++ switch (go->aspect_ratio) { ++ case GO7007_RATIO_4_3: ++ aspect_ratio = 2; ++ break; ++ case GO7007_RATIO_16_9: ++ aspect_ratio = 3; ++ break; ++ default: ++ aspect_ratio = 1; ++ break; ++ } ++ } ++ switch (go->sensor_framerate) { ++ case 24000: ++ picture_rate = 1; ++ break; ++ case 24024: ++ picture_rate = 2; ++ break; ++ case 25025: ++ picture_rate = go->interlace_coding ? 6 : 3; ++ break; ++ case 30000: ++ picture_rate = go->interlace_coding ? 7 : 4; ++ break; ++ case 30030: ++ picture_rate = go->interlace_coding ? 8 : 5; ++ break; ++ default: ++ picture_rate = 5; /* 30 fps seems like a reasonable default */ ++ break; ++ } ++ ++ CODE_ADD(c, go->width, 12); ++ CODE_ADD(c, go->height, 12); ++ CODE_ADD(c, aspect_ratio, 4); ++ CODE_ADD(c, picture_rate, 4); ++ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18); ++ CODE_ADD(c, 1, 1); ++ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10); ++ CODE_ADD(c, 0, 3); ++ ++ /* Byte-align with zeros */ ++ i = 8 - (CODE_LENGTH(c) % 8); ++ if (i != 8) ++ CODE_ADD(c, 0, i); ++ ++ if (go->format == GO7007_FORMAT_MPEG2) { ++ CODE_ADD(c, 0x1, 24); ++ CODE_ADD(c, 0xb5, 8); ++ CODE_ADD(c, 0x148, 12); ++ if (go->interlace_coding) ++ CODE_ADD(c, 0x20001, 20); ++ else ++ CODE_ADD(c, 0xa0001, 20); ++ CODE_ADD(c, 0, 16); ++ ++ /* Byte-align with zeros */ ++ i = 8 - (CODE_LENGTH(c) % 8); ++ if (i != 8) ++ CODE_ADD(c, 0, i); ++ ++ if (ext) { ++ CODE_ADD(c, 0x1, 24); ++ CODE_ADD(c, 0xb52, 12); ++ CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1, 3); ++ CODE_ADD(c, 0x105, 9); ++ CODE_ADD(c, 0x505, 16); ++ CODE_ADD(c, go->width, 14); ++ CODE_ADD(c, 1, 1); ++ CODE_ADD(c, go->height, 14); ++ ++ /* Byte-align with zeros */ ++ i = 8 - (CODE_LENGTH(c) % 8); ++ if (i != 8) ++ CODE_ADD(c, 0, i); ++ } ++ } ++ ++ i = CODE_LENGTH(c) + 4 * 8; ++ buf[0] = i & 0xff; ++ buf[1] = i >> 8; ++ buf[2] = 0x00; ++ buf[3] = 0x00; ++ buf[4] = 0x01; ++ buf[5] = 0xb3; ++ return i; ++} ++ ++static int gen_mpeg1hdr_to_package(struct go7007 *go, ++ u16 *code, int space, int *framelen) ++{ ++ u8 *buf; ++ u16 mem = 0x3e00; ++ unsigned int addr = 0x19; ++ int i, off = 0, chunk; ++ ++ buf = kmalloc(5120, GFP_KERNEL); ++ if (buf == NULL) { ++ printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " ++ "firmware construction\n"); ++ return -1; ++ } ++ memset(buf, 0, 5120); ++ framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME); ++ if (go->interlace_coding) ++ framelen[0] += mpeg1_frame_header(go, buf + framelen[0] / 8, ++ 0, 2, PFRAME); ++ buf[0] = framelen[0] & 0xff; ++ buf[1] = framelen[0] >> 8; ++ i = 368; ++ framelen[1] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_PRE); ++ if (go->interlace_coding) ++ framelen[1] += mpeg1_frame_header(go, buf + i + framelen[1] / 8, ++ 0, 2, BFRAME_PRE); ++ buf[i] = framelen[1] & 0xff; ++ buf[i + 1] = framelen[1] >> 8; ++ i += 1632; ++ framelen[2] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_POST); ++ if (go->interlace_coding) ++ framelen[2] += mpeg1_frame_header(go, buf + i + framelen[2] / 8, ++ 0, 2, BFRAME_POST); ++ buf[i] = framelen[2] & 0xff; ++ buf[i + 1] = framelen[2] >> 8; ++ i += 1432; ++ framelen[3] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_BIDIR); ++ if (go->interlace_coding) ++ framelen[3] += mpeg1_frame_header(go, buf + i + framelen[3] / 8, ++ 0, 2, BFRAME_BIDIR); ++ buf[i] = framelen[3] & 0xff; ++ buf[i + 1] = framelen[3] >> 8; ++ i += 1632 + 16; ++ mpeg1_sequence_header(go, buf + i, 0); ++ i += 40; ++ for (i = 0; i < 5120; i += chunk * 2) { ++ if (space - off < 32) { ++ off = -1; ++ goto done; ++ } ++ ++ code[off + 1] = __cpu_to_le16(0x8000 | mem); ++ ++ chunk = 28; ++ if (mem + chunk > 0x4000) ++ chunk = 0x4000 - mem; ++ if (i + 2 * chunk > 5120) ++ chunk = (5120 - i) / 2; ++ ++ if (chunk < 28) { ++ code[off] = __cpu_to_le16(0x4000 | chunk); ++ code[off + 31] = __cpu_to_le16(addr); ++ if (mem + chunk == 0x4000) { ++ mem = 0x3e00; ++ ++addr; ++ } ++ } else { ++ code[off] = __cpu_to_le16(0x1000 | 28); ++ code[off + 31] = 0; ++ mem += 28; ++ } ++ ++ memcpy(&code[off + 2], buf + i, chunk * 2); ++ off += 32; ++ } ++done: ++ kfree(buf); ++ return off; ++} ++ ++static int vti_bitlen(struct go7007 *go) ++{ ++ unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale; ++ ++ for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i); ++ return i + 1; ++} ++ ++static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf, ++ int modulo, enum mpeg_frame_type frame) ++{ ++ int i; ++ CODE_GEN(c, buf + 6); ++ int mb_count = (go->width >> 4) * (go->height >> 4); ++ ++ CODE_ADD(c, frame == PFRAME ? 0x1 : 0x2, 2); ++ if (modulo) ++ CODE_ADD(c, 0x1, 1); ++ CODE_ADD(c, 0x1, 2); ++ CODE_ADD(c, 0, vti_bitlen(go)); ++ CODE_ADD(c, 0x3, 2); ++ if (frame == PFRAME) ++ CODE_ADD(c, 0, 1); ++ CODE_ADD(c, 0xc, 11); ++ if (frame != PFRAME) ++ CODE_ADD(c, 0x4, 3); ++ if (frame != BFRAME_EMPTY) { ++ for (i = 0; i < mb_count; ++i) { ++ switch (frame) { ++ case PFRAME: ++ CODE_ADD(c, 0x1, 1); ++ break; ++ case BFRAME_PRE: ++ CODE_ADD(c, 0x47, 8); ++ break; ++ case BFRAME_POST: ++ CODE_ADD(c, 0x27, 7); ++ break; ++ case BFRAME_BIDIR: ++ CODE_ADD(c, 0x5f, 8); ++ break; ++ case BFRAME_EMPTY: /* keep compiler quiet */ ++ break; ++ } ++ } ++ } ++ ++ /* Byte-align with a zero followed by ones */ ++ i = 8 - (CODE_LENGTH(c) % 8); ++ CODE_ADD(c, 0, 1); ++ CODE_ADD(c, (1 << (i - 1)) - 1, i - 1); ++ ++ i = CODE_LENGTH(c) + 4 * 8; ++ buf[0] = i & 0xff; ++ buf[1] = i >> 8; ++ buf[2] = 0x00; ++ buf[3] = 0x00; ++ buf[4] = 0x01; ++ buf[5] = 0xb6; ++ return i; ++} ++ ++static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext) ++{ ++ const unsigned char head[] = { 0x00, 0x00, 0x01, 0xb0, go->pali, ++ 0x00, 0x00, 0x01, 0xb5, 0x09, ++ 0x00, 0x00, 0x01, 0x00, ++ 0x00, 0x00, 0x01, 0x20, }; ++ int i, aspect_ratio; ++ int fps = go->sensor_framerate / go->fps_scale; ++ CODE_GEN(c, buf + 2 + sizeof(head)); ++ ++ switch (go->aspect_ratio) { ++ case GO7007_RATIO_4_3: ++ aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; ++ break; ++ case GO7007_RATIO_16_9: ++ aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4; ++ break; ++ default: ++ aspect_ratio = 1; ++ break; ++ } ++ ++ memcpy(buf + 2, head, sizeof(head)); ++ CODE_ADD(c, 0x191, 17); ++ CODE_ADD(c, aspect_ratio, 4); ++ CODE_ADD(c, 0x1, 4); ++ CODE_ADD(c, fps, 16); ++ CODE_ADD(c, 0x3, 2); ++ CODE_ADD(c, 1001, vti_bitlen(go)); ++ CODE_ADD(c, 1, 1); ++ CODE_ADD(c, go->width, 13); ++ CODE_ADD(c, 1, 1); ++ CODE_ADD(c, go->height, 13); ++ CODE_ADD(c, 0x2830, 14); ++ ++ /* Byte-align */ ++ i = 8 - (CODE_LENGTH(c) % 8); ++ CODE_ADD(c, 0, 1); ++ CODE_ADD(c, (1 << (i - 1)) - 1, i - 1); ++ ++ i = CODE_LENGTH(c) + sizeof(head) * 8; ++ buf[0] = i & 0xff; ++ buf[1] = i >> 8; ++ return i; ++} ++ ++static int gen_mpeg4hdr_to_package(struct go7007 *go, ++ u16 *code, int space, int *framelen) ++{ ++ u8 *buf; ++ u16 mem = 0x3e00; ++ unsigned int addr = 0x19; ++ int i, off = 0, chunk; ++ ++ buf = kmalloc(5120, GFP_KERNEL); ++ if (buf == NULL) { ++ printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " ++ "firmware construction\n"); ++ return -1; ++ } ++ memset(buf, 0, 5120); ++ framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME); ++ i = 368; ++ framelen[1] = mpeg4_frame_header(go, buf + i, 0, BFRAME_PRE); ++ i += 1632; ++ framelen[2] = mpeg4_frame_header(go, buf + i, 0, BFRAME_POST); ++ i += 1432; ++ framelen[3] = mpeg4_frame_header(go, buf + i, 0, BFRAME_BIDIR); ++ i += 1632; ++ mpeg4_frame_header(go, buf + i, 0, BFRAME_EMPTY); ++ i += 16; ++ mpeg4_sequence_header(go, buf + i, 0); ++ i += 40; ++ for (i = 0; i < 5120; i += chunk * 2) { ++ if (space - off < 32) { ++ off = -1; ++ goto done; ++ } ++ ++ code[off + 1] = __cpu_to_le16(0x8000 | mem); ++ ++ chunk = 28; ++ if (mem + chunk > 0x4000) ++ chunk = 0x4000 - mem; ++ if (i + 2 * chunk > 5120) ++ chunk = (5120 - i) / 2; ++ ++ if (chunk < 28) { ++ code[off] = __cpu_to_le16(0x4000 | chunk); ++ code[off + 31] = __cpu_to_le16(addr); ++ if (mem + chunk == 0x4000) { ++ mem = 0x3e00; ++ ++addr; ++ } ++ } else { ++ code[off] = __cpu_to_le16(0x1000 | 28); ++ code[off + 31] = 0; ++ mem += 28; ++ } ++ ++ memcpy(&code[off + 2], buf + i, chunk * 2); ++ off += 32; ++ } ++ mem = 0x3e00; ++ addr = go->ipb ? 0x14f9 : 0x0af9; ++ memset(buf, 0, 5120); ++ framelen[4] = mpeg4_frame_header(go, buf, 1, PFRAME); ++ i = 368; ++ framelen[5] = mpeg4_frame_header(go, buf + i, 1, BFRAME_PRE); ++ i += 1632; ++ framelen[6] = mpeg4_frame_header(go, buf + i, 1, BFRAME_POST); ++ i += 1432; ++ framelen[7] = mpeg4_frame_header(go, buf + i, 1, BFRAME_BIDIR); ++ i += 1632; ++ mpeg4_frame_header(go, buf + i, 1, BFRAME_EMPTY); ++ i += 16; ++ for (i = 0; i < 5120; i += chunk * 2) { ++ if (space - off < 32) { ++ off = -1; ++ goto done; ++ } ++ ++ code[off + 1] = __cpu_to_le16(0x8000 | mem); ++ ++ chunk = 28; ++ if (mem + chunk > 0x4000) ++ chunk = 0x4000 - mem; ++ if (i + 2 * chunk > 5120) ++ chunk = (5120 - i) / 2; ++ ++ if (chunk < 28) { ++ code[off] = __cpu_to_le16(0x4000 | chunk); ++ code[off + 31] = __cpu_to_le16(addr); ++ if (mem + chunk == 0x4000) { ++ mem = 0x3e00; ++ ++addr; ++ } ++ } else { ++ code[off] = __cpu_to_le16(0x1000 | 28); ++ code[off + 31] = 0; ++ mem += 28; ++ } ++ ++ memcpy(&code[off + 2], buf + i, chunk * 2); ++ off += 32; ++ } ++done: ++ kfree(buf); ++ return off; ++} ++ ++static int brctrl_to_package(struct go7007 *go, ++ u16 *code, int space, int *framelen) ++{ ++ int converge_speed = 0; ++ int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ? ++ 100 : 0; ++ int peak_rate = 6 * go->bitrate / 5; ++ int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ? ++ go->bitrate : ++ (go->dvd_mode ? 900000 : peak_rate); ++ int fps = go->sensor_framerate / go->fps_scale; ++ int q = 0; ++ /* Bizarre math below depends on rounding errors in division */ ++ u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1) * 1001 / fps; ++ u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps; ++ u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000); ++ u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32); ++ u32 cplx[] = { ++ q > 0 ? sgop_expt_addr * q : ++ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, ++ q > 0 ? sgop_expt_addr * q : ++ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, ++ q > 0 ? sgop_expt_addr * q : ++ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, ++ q > 0 ? sgop_expt_addr * q : ++ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32, ++ }; ++ u32 calc_q = q > 0 ? q : cplx[0] / sgop_expt_addr; ++ u16 pack[] = { ++ 0x200e, 0x0000, ++ 0xBF20, go->ipb ? converge_speed_ipb[converge_speed] ++ : converge_speed_ip[converge_speed], ++ 0xBF21, go->ipb ? 2 : 0, ++ 0xBF22, go->ipb ? LAMBDA_table[0][lambda / 2 + 50] ++ : 32767, ++ 0xBF23, go->ipb ? LAMBDA_table[1][lambda] : 32767, ++ 0xBF24, 32767, ++ 0xBF25, lambda > 99 ? 32767 : LAMBDA_table[3][lambda], ++ 0xBF26, sgop_expt_addr & 0x0000FFFF, ++ 0xBF27, sgop_expt_addr >> 16, ++ 0xBF28, sgop_peak_addr & 0x0000FFFF, ++ 0xBF29, sgop_peak_addr >> 16, ++ 0xBF2A, vbv_alert_addr & 0x0000FFFF, ++ 0xBF2B, vbv_alert_addr >> 16, ++ 0xBF2C, 0, ++ 0xBF2D, 0, ++ 0, 0, ++ ++ 0x200e, 0x0000, ++ 0xBF2E, vbv_alert_addr & 0x0000FFFF, ++ 0xBF2F, vbv_alert_addr >> 16, ++ 0xBF30, cplx[0] & 0x0000FFFF, ++ 0xBF31, cplx[0] >> 16, ++ 0xBF32, cplx[1] & 0x0000FFFF, ++ 0xBF33, cplx[1] >> 16, ++ 0xBF34, cplx[2] & 0x0000FFFF, ++ 0xBF35, cplx[2] >> 16, ++ 0xBF36, cplx[3] & 0x0000FFFF, ++ 0xBF37, cplx[3] >> 16, ++ 0xBF38, 0, ++ 0xBF39, 0, ++ 0xBF3A, total_expt_addr & 0x0000FFFF, ++ 0xBF3B, total_expt_addr >> 16, ++ 0, 0, ++ ++ 0x200e, 0x0000, ++ 0xBF3C, total_expt_addr & 0x0000FFFF, ++ 0xBF3D, total_expt_addr >> 16, ++ 0xBF3E, 0, ++ 0xBF3F, 0, ++ 0xBF48, 0, ++ 0xBF49, 0, ++ 0xBF4A, calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q), ++ 0xBF4B, 4, ++ 0xBF4C, 0, ++ 0xBF4D, 0, ++ 0xBF4E, 0, ++ 0xBF4F, 0, ++ 0xBF50, 0, ++ 0xBF51, 0, ++ 0, 0, ++ ++ 0x200e, 0x0000, ++ 0xBF40, sgop_expt_addr & 0x0000FFFF, ++ 0xBF41, sgop_expt_addr >> 16, ++ 0xBF42, 0, ++ 0xBF43, 0, ++ 0xBF44, 0, ++ 0xBF45, 0, ++ 0xBF46, (go->width >> 4) * (go->height >> 4), ++ 0xBF47, 0, ++ 0xBF64, 0, ++ 0xBF65, 0, ++ 0xBF18, framelen[4], ++ 0xBF19, framelen[5], ++ 0xBF1A, framelen[6], ++ 0xBF1B, framelen[7], ++ 0, 0, ++ ++#if 0 /* Remove once we don't care about matching */ ++ 0x200e, 0x0000, ++ 0xBF56, 4, ++ 0xBF57, 0, ++ 0xBF58, 5, ++ 0xBF59, 0, ++ 0xBF5A, 6, ++ 0xBF5B, 0, ++ 0xBF5C, 8, ++ 0xBF5D, 0, ++ 0xBF5E, 1, ++ 0xBF5F, 0, ++ 0xBF60, 1, ++ 0xBF61, 0, ++ 0xBF62, 0, ++ 0xBF63, 0, ++ 0, 0, ++#else ++ 0x2008, 0x0000, ++ 0xBF56, 4, ++ 0xBF57, 0, ++ 0xBF58, 5, ++ 0xBF59, 0, ++ 0xBF5A, 6, ++ 0xBF5B, 0, ++ 0xBF5C, 8, ++ 0xBF5D, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++#endif ++ ++ 0x200e, 0x0000, ++ 0xBF10, 0, ++ 0xBF11, 0, ++ 0xBF12, 0, ++ 0xBF13, 0, ++ 0xBF14, 0, ++ 0xBF15, 0, ++ 0xBF16, 0, ++ 0xBF17, 0, ++ 0xBF7E, 0, ++ 0xBF7F, 1, ++ 0xBF52, framelen[0], ++ 0xBF53, framelen[1], ++ 0xBF54, framelen[2], ++ 0xBF55, framelen[3], ++ 0, 0, ++ }; ++ ++ return copy_packages(code, pack, 6, space); ++} ++ ++static int config_package(struct go7007 *go, u16 *code, int space) ++{ ++ int fps = go->sensor_framerate / go->fps_scale / 1000; ++ int rows = go->interlace_coding ? go->height / 32 : go->height / 16; ++ int brc_window_size = fps; ++ int q_min = 2, q_max = 31; ++ int THACCoeffSet0 = 0; ++ u16 pack[] = { ++ 0x200e, 0x0000, ++ 0xc002, 0x14b4, ++ 0xc003, 0x28b4, ++ 0xc004, 0x3c5a, ++ 0xdc05, 0x2a77, ++ 0xc6c3, go->format == GO7007_FORMAT_MPEG4 ? 0 : ++ (go->format == GO7007_FORMAT_H263 ? 0 : 1), ++ 0xc680, go->format == GO7007_FORMAT_MPEG4 ? 0xf1 : ++ (go->format == GO7007_FORMAT_H263 ? 0x61 : ++ 0xd3), ++ 0xc780, 0x0140, ++ 0xe009, 0x0001, ++ 0xc60f, 0x0008, ++ 0xd4ff, 0x0002, ++ 0xe403, 2340, ++ 0xe406, 75, ++ 0xd411, 0x0001, ++ 0xd410, 0xa1d6, ++ 0x0001, 0x2801, ++ ++ 0x200d, 0x0000, ++ 0xe402, 0x018b, ++ 0xe401, 0x8b01, ++ 0xd472, (go->board_info->sensor_flags & ++ GO7007_SENSOR_TV) && ++ (!go->interlace_coding) ? ++ 0x01b0 : 0x0170, ++ 0xd475, (go->board_info->sensor_flags & ++ GO7007_SENSOR_TV) && ++ (!go->interlace_coding) ? ++ 0x0008 : 0x0009, ++ 0xc404, go->interlace_coding ? 0x44 : ++ (go->format == GO7007_FORMAT_MPEG4 ? 0x11 : ++ (go->format == GO7007_FORMAT_MPEG1 ? 0x02 : ++ (go->format == GO7007_FORMAT_MPEG2 ? 0x04 : ++ (go->format == GO7007_FORMAT_H263 ? 0x08 : ++ 0x20)))), ++ 0xbf0a, (go->format == GO7007_FORMAT_MPEG4 ? 8 : ++ (go->format == GO7007_FORMAT_MPEG1 ? 1 : ++ (go->format == GO7007_FORMAT_MPEG2 ? 2 : ++ (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) | ++ ((go->repeat_seqhead ? 1 : 0) << 6) | ++ ((go->dvd_mode ? 1 : 0) << 9) | ++ ((go->gop_header_enable ? 1 : 0) << 10), ++ 0xbf0b, 0, ++ 0xdd5a, go->ipb ? 0x14 : 0x0a, ++ 0xbf0c, 0, ++ 0xbf0d, 0, ++ 0xc683, THACCoeffSet0, ++ 0xc40a, (go->width << 4) | rows, ++ 0xe01a, go->board_info->hpi_buffer_cap, ++ 0, 0, ++ 0, 0, ++ ++ 0x2008, 0, ++ 0xe402, 0x88, ++ 0xe401, 0x8f01, ++ 0xbf6a, 0, ++ 0xbf6b, 0, ++ 0xbf6c, 0, ++ 0xbf6d, 0, ++ 0xbf6e, 0, ++ 0xbf6f, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ ++ 0x200e, 0, ++ 0xbf66, brc_window_size, ++ 0xbf67, 0, ++ 0xbf68, q_min, ++ 0xbf69, q_max, ++ 0xbfe0, 0, ++ 0xbfe1, 0, ++ 0xbfe2, 0, ++ 0xbfe3, go->ipb ? 3 : 1, ++ 0xc031, go->board_info->sensor_flags & ++ GO7007_SENSOR_VBI ? 1 : 0, ++ 0xc01c, 0x1f, ++ 0xdd8c, 0x15, ++ 0xdd94, 0x15, ++ 0xdd88, go->ipb ? 0x1401 : 0x0a01, ++ 0xdd90, go->ipb ? 0x1401 : 0x0a01, ++ 0, 0, ++ ++ 0x200e, 0, ++ 0xbfe4, 0, ++ 0xbfe5, 0, ++ 0xbfe6, 0, ++ 0xbfe7, fps << 8, ++ 0xbfe8, 0x3a00, ++ 0xbfe9, 0, ++ 0xbfea, 0, ++ 0xbfeb, 0, ++ 0xbfec, (go->interlace_coding ? 1 << 15 : 0) | ++ (go->modet_enable ? 0xa : 0) | ++ (go->board_info->sensor_flags & ++ GO7007_SENSOR_VBI ? 1 : 0), ++ 0xbfed, 0, ++ 0xbfee, 0, ++ 0xbfef, 0, ++ 0xbff0, go->board_info->sensor_flags & ++ GO7007_SENSOR_TV ? 0xf060 : 0xb060, ++ 0xbff1, 0, ++ 0, 0, ++ }; ++ ++ return copy_packages(code, pack, 5, space); ++} ++ ++static int seqhead_to_package(struct go7007 *go, u16 *code, int space, ++ int (*sequence_header_func)(struct go7007 *go, ++ unsigned char *buf, int ext)) ++{ ++ int vop_time_increment_bitlength = vti_bitlen(go); ++ int fps = go->sensor_framerate / go->fps_scale * ++ (go->interlace_coding ? 2 : 1); ++ unsigned char buf[40] = { }; ++ int len = sequence_header_func(go, buf, 1); ++ u16 pack[] = { ++ 0x2006, 0, ++ 0xbf08, fps, ++ 0xbf09, 0, ++ 0xbff2, vop_time_increment_bitlength, ++ 0xbff3, (1 << vop_time_increment_bitlength) - 1, ++ 0xbfe6, 0, ++ 0xbfe7, (fps / 1000) << 8, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ ++ 0x2007, 0, ++ 0xc800, buf[2] << 8 | buf[3], ++ 0xc801, buf[4] << 8 | buf[5], ++ 0xc802, buf[6] << 8 | buf[7], ++ 0xc803, buf[8] << 8 | buf[9], ++ 0xc406, 64, ++ 0xc407, len - 64, ++ 0xc61b, 1, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ ++ 0x200e, 0, ++ 0xc808, buf[10] << 8 | buf[11], ++ 0xc809, buf[12] << 8 | buf[13], ++ 0xc80a, buf[14] << 8 | buf[15], ++ 0xc80b, buf[16] << 8 | buf[17], ++ 0xc80c, buf[18] << 8 | buf[19], ++ 0xc80d, buf[20] << 8 | buf[21], ++ 0xc80e, buf[22] << 8 | buf[23], ++ 0xc80f, buf[24] << 8 | buf[25], ++ 0xc810, buf[26] << 8 | buf[27], ++ 0xc811, buf[28] << 8 | buf[29], ++ 0xc812, buf[30] << 8 | buf[31], ++ 0xc813, buf[32] << 8 | buf[33], ++ 0xc814, buf[34] << 8 | buf[35], ++ 0xc815, buf[36] << 8 | buf[37], ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ }; ++ ++ return copy_packages(code, pack, 3, space); ++} ++ ++static int relative_prime(int big, int little) ++{ ++ int remainder; ++ ++ while (little != 0) { ++ remainder = big % little; ++ big = little; ++ little = remainder; ++ } ++ return big; ++} ++ ++static int avsync_to_package(struct go7007 *go, u16 *code, int space) ++{ ++ int arate = go->board_info->audio_rate * 1001 * go->fps_scale; ++ int ratio = arate / go->sensor_framerate; ++ int adjratio = ratio * 215 / 100; ++ int rprime = relative_prime(go->sensor_framerate, ++ arate % go->sensor_framerate); ++ int f1 = (arate % go->sensor_framerate) / rprime; ++ int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime; ++ u16 pack[] = { ++ 0x200e, 0, ++ 0xbf98, (u16)((-adjratio) & 0xffff), ++ 0xbf99, (u16)((-adjratio) >> 16), ++ 0xbf92, 0, ++ 0xbf93, 0, ++ 0xbff4, f1 > f2 ? f1 : f2, ++ 0xbff5, f1 < f2 ? f1 : f2, ++ 0xbff6, f1 < f2 ? ratio : ratio + 1, ++ 0xbff7, f1 > f2 ? ratio : ratio + 1, ++ 0xbff8, 0, ++ 0xbff9, 0, ++ 0xbffa, adjratio & 0xffff, ++ 0xbffb, adjratio >> 16, ++ 0xbf94, 0, ++ 0xbf95, 0, ++ 0, 0, ++ }; ++ ++ return copy_packages(code, pack, 1, space); ++} ++ ++static int final_package(struct go7007 *go, u16 *code, int space) ++{ ++ int rows = go->interlace_coding ? go->height / 32 : go->height / 16; ++ u16 pack[] = { ++ 0x8000, ++ 0, ++ 0, ++ 0, ++ 0, ++ 0, ++ 0, ++ 2, ++ ((go->board_info->sensor_flags & GO7007_SENSOR_TV) && ++ (!go->interlace_coding) ? ++ (1 << 14) | (1 << 9) : 0) | ++ ((go->encoder_subsample ? 1 : 0) << 8) | ++ (go->board_info->sensor_flags & ++ GO7007_SENSOR_CONFIG_MASK), ++ ((go->encoder_v_halve ? 1 : 0) << 14) | ++ (go->encoder_v_halve ? rows << 9 : rows << 8) | ++ (go->encoder_h_halve ? 1 << 6 : 0) | ++ (go->encoder_h_halve ? go->width >> 3 : go->width >> 4), ++ (1 << 15) | (go->encoder_v_offset << 6) | ++ (1 << 7) | (go->encoder_h_offset >> 2), ++ (1 << 6), ++ 0, ++ 0, ++ ((go->fps_scale - 1) << 8) | ++ (go->board_info->sensor_flags & GO7007_SENSOR_TV ? ++ (1 << 7) : 0) | ++ 0x41, ++ go->ipb ? 0xd4c : 0x36b, ++ (rows << 8) | (go->width >> 4), ++ go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0, ++ (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) | ++ ((go->closed_gop ? 1 : 0) << 12) | ++ ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) | ++ /* (1 << 9) | */ ++ ((go->ipb ? 3 : 0) << 7) | ++ ((go->modet_enable ? 1 : 0) << 2) | ++ ((go->dvd_mode ? 1 : 0) << 1) | 1, ++ (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 : ++ (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 : ++ (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 : ++ (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 : ++ (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))), ++ go->ipb ? 0x1f15 : 0x1f0b, ++ go->ipb ? 0x0015 : 0x000b, ++ go->ipb ? 0xa800 : 0x5800, ++ 0xffff, ++ 0x0020 + 0x034b * 0, ++ 0x0020 + 0x034b * 1, ++ 0x0020 + 0x034b * 2, ++ 0x0020 + 0x034b * 3, ++ 0x0020 + 0x034b * 4, ++ 0x0020 + 0x034b * 5, ++ go->ipb ? (go->gop_size / 3) : go->gop_size, ++ (go->height >> 4) * (go->width >> 4) * 110 / 100, ++ }; ++ ++ return copy_packages(code, pack, 1, space); ++} ++ ++static int audio_to_package(struct go7007 *go, u16 *code, int space) ++{ ++ int clock_config = ((go->board_info->audio_flags & ++ GO7007_AUDIO_I2S_MASTER ? 1 : 0) << 11) | ++ ((go->board_info->audio_flags & ++ GO7007_AUDIO_OKI_MODE ? 1 : 0) << 8) | ++ (((go->board_info->audio_bclk_div / 4) - 1) << 4) | ++ (go->board_info->audio_main_div - 1); ++ u16 pack[] = { ++ 0x200d, 0, ++ 0x9002, 0, ++ 0x9002, 0, ++ 0x9031, 0, ++ 0x9032, 0, ++ 0x9033, 0, ++ 0x9034, 0, ++ 0x9035, 0, ++ 0x9036, 0, ++ 0x9037, 0, ++ 0x9040, 0, ++ 0x9000, clock_config, ++ 0x9001, (go->board_info->audio_flags & 0xffff) | ++ (1 << 9), ++ 0x9000, ((go->board_info->audio_flags & ++ GO7007_AUDIO_I2S_MASTER ? ++ 1 : 0) << 10) | ++ clock_config, ++ 0, 0, ++ 0, 0, ++ 0x2005, 0, ++ 0x9041, 0, ++ 0x9042, 256, ++ 0x9043, 0, ++ 0x9044, 16, ++ 0x9045, 16, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ 0, 0, ++ }; ++ ++ return copy_packages(code, pack, 2, space); ++} ++ ++static int modet_to_package(struct go7007 *go, u16 *code, int space) ++{ ++ int ret, mb, i, addr, cnt = 0; ++ u16 pack[32]; ++ u16 thresholds[] = { ++ 0x200e, 0, ++ 0xbf82, go->modet[0].pixel_threshold, ++ 0xbf83, go->modet[1].pixel_threshold, ++ 0xbf84, go->modet[2].pixel_threshold, ++ 0xbf85, go->modet[3].pixel_threshold, ++ 0xbf86, go->modet[0].motion_threshold, ++ 0xbf87, go->modet[1].motion_threshold, ++ 0xbf88, go->modet[2].motion_threshold, ++ 0xbf89, go->modet[3].motion_threshold, ++ 0xbf8a, go->modet[0].mb_threshold, ++ 0xbf8b, go->modet[1].mb_threshold, ++ 0xbf8c, go->modet[2].mb_threshold, ++ 0xbf8d, go->modet[3].mb_threshold, ++ 0xbf8e, 0, ++ 0xbf8f, 0, ++ 0, 0, ++ }; ++ ++ ret = copy_packages(code, thresholds, 1, space); ++ if (ret < 0) ++ return -1; ++ cnt += ret; ++ ++ addr = 0xbac0; ++ memset(pack, 0, 64); ++ i = 0; ++ for (mb = 0; mb < 1624; ++mb) { ++ pack[i * 2 + 3] <<= 2; ++ pack[i * 2 + 3] |= go->modet_map[mb]; ++ if (mb % 8 != 7) ++ continue; ++ pack[i * 2 + 2] = addr++; ++ ++i; ++ if (i == 10 || mb == 1623) { ++ pack[0] = 0x2000 | i; ++ ret = copy_packages(code + cnt, pack, 1, space - cnt); ++ if (ret < 0) ++ return -1; ++ cnt += ret; ++ i = 0; ++ memset(pack, 0, 64); ++ } ++ pack[i * 2 + 3] = 0; ++ } ++ ++ memset(pack, 0, 64); ++ i = 0; ++ for (addr = 0xbb90; addr < 0xbbfa; ++addr) { ++ pack[i * 2 + 2] = addr; ++ pack[i * 2 + 3] = 0; ++ ++i; ++ if (i == 10 || addr == 0xbbf9) { ++ pack[0] = 0x2000 | i; ++ ret = copy_packages(code + cnt, pack, 1, space - cnt); ++ if (ret < 0) ++ return -1; ++ cnt += ret; ++ i = 0; ++ memset(pack, 0, 64); ++ } ++ } ++ return cnt; ++} ++ ++static int do_special(struct go7007 *go, u16 type, u16 *code, int space, ++ int *framelen) ++{ ++ switch (type) { ++ case SPECIAL_FRM_HEAD: ++ switch (go->format) { ++ case GO7007_FORMAT_MJPEG: ++ return gen_mjpeghdr_to_package(go, code, space); ++ case GO7007_FORMAT_MPEG1: ++ case GO7007_FORMAT_MPEG2: ++ return gen_mpeg1hdr_to_package(go, code, space, ++ framelen); ++ case GO7007_FORMAT_MPEG4: ++ return gen_mpeg4hdr_to_package(go, code, space, ++ framelen); ++ } ++ case SPECIAL_BRC_CTRL: ++ return brctrl_to_package(go, code, space, framelen); ++ case SPECIAL_CONFIG: ++ return config_package(go, code, space); ++ case SPECIAL_SEQHEAD: ++ switch (go->format) { ++ case GO7007_FORMAT_MPEG1: ++ case GO7007_FORMAT_MPEG2: ++ return seqhead_to_package(go, code, space, ++ mpeg1_sequence_header); ++ case GO7007_FORMAT_MPEG4: ++ return seqhead_to_package(go, code, space, ++ mpeg4_sequence_header); ++ default: ++ return 0; ++ } ++ case SPECIAL_AV_SYNC: ++ return avsync_to_package(go, code, space); ++ case SPECIAL_FINAL: ++ return final_package(go, code, space); ++ case SPECIAL_AUDIO: ++ return audio_to_package(go, code, space); ++ case SPECIAL_MODET: ++ return modet_to_package(go, code, space); ++ } ++ printk(KERN_ERR ++ "go7007: firmware file contains unsupported feature %04x\n", ++ type); ++ return -1; ++} ++ ++int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) ++{ ++ const struct firmware *fw_entry; ++ u16 *code, *src; ++ int framelen[8] = { }; /* holds the lengths of empty frame templates */ ++ int codespace = 64 * 1024, i = 0, srclen, chunk_len, chunk_flags; ++ int mode_flag; ++ int ret; ++ ++ switch (go->format) { ++ case GO7007_FORMAT_MJPEG: ++ mode_flag = FLAG_MODE_MJPEG; ++ break; ++ case GO7007_FORMAT_MPEG1: ++ mode_flag = FLAG_MODE_MPEG1; ++ break; ++ case GO7007_FORMAT_MPEG2: ++ mode_flag = FLAG_MODE_MPEG2; ++ break; ++ case GO7007_FORMAT_MPEG4: ++ mode_flag = FLAG_MODE_MPEG4; ++ break; ++ default: ++ return -1; ++ } ++ if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) { ++ printk(KERN_ERR ++ "go7007: unable to load firmware from file \"%s\"\n", ++ go->board_info->firmware); ++ return -1; ++ } ++ code = kmalloc(codespace * 2, GFP_KERNEL); ++ if (code == NULL) { ++ printk(KERN_ERR "go7007: unable to allocate %d bytes for " ++ "firmware construction\n", codespace * 2); ++ goto fw_failed; ++ } ++ memset(code, 0, codespace * 2); ++ src = (u16 *)fw_entry->data; ++ srclen = fw_entry->size / 2; ++ while (srclen >= 2) { ++ chunk_flags = __le16_to_cpu(src[0]); ++ chunk_len = __le16_to_cpu(src[1]); ++ if (chunk_len + 2 > srclen) { ++ printk(KERN_ERR "go7007: firmware file \"%s\" " ++ "appears to be corrupted\n", ++ go->board_info->firmware); ++ goto fw_failed; ++ } ++ if (chunk_flags & mode_flag) { ++ if (chunk_flags & FLAG_SPECIAL) { ++ ret = do_special(go, __le16_to_cpu(src[2]), ++ &code[i], codespace - i, framelen); ++ if (ret < 0) { ++ printk(KERN_ERR "go7007: insufficient " ++ "memory for firmware " ++ "construction\n"); ++ goto fw_failed; ++ } ++ i += ret; ++ } else { ++ if (codespace - i < chunk_len) { ++ printk(KERN_ERR "go7007: insufficient " ++ "memory for firmware " ++ "construction\n"); ++ goto fw_failed; ++ } ++ memcpy(&code[i], &src[2], chunk_len * 2); ++ i += chunk_len; ++ } ++ } ++ srclen -= chunk_len + 2; ++ src += chunk_len + 2; ++ } ++ release_firmware(fw_entry); ++ *fw = (u8 *)code; ++ *fwlen = i * 2; ++ return 0; ++ ++fw_failed: ++ kfree(code); ++ release_firmware(fw_entry); ++ return -1; ++} +diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/go7007/go7007-i2c.c +new file mode 100644 +index 0000000..10baae3 +--- /dev/null ++++ b/drivers/staging/go7007/go7007-i2c.c +@@ -0,0 +1,309 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "go7007-priv.h" ++#include "wis-i2c.h" ++ ++/************** Registration interface for I2C client drivers **************/ ++ ++/* Since there's no way to auto-probe the I2C devices connected to the I2C ++ * bus on the go7007, we have this silly little registration system that ++ * client drivers can use to register their I2C driver ID and their ++ * detect_client function (the one that's normally passed to i2c_probe). ++ * ++ * When a new go7007 device is connected, we can look up in a board info ++ * table by the USB or PCI vendor/product/revision ID to determine ++ * which I2C client module to load. The client driver module will register ++ * itself here, and then we can call the registered detect_client function ++ * to force-load a new client at the address listed in the board info table. ++ * ++ * Really the I2C subsystem should have a way to force-load I2C client ++ * drivers when we have a priori knowledge of what's on the bus, especially ++ * since the existing I2C auto-probe mechanism is so hokey, but we'll use ++ * our own mechanism for the time being. */ ++ ++struct wis_i2c_client_driver { ++ unsigned int id; ++ found_proc found_proc; ++ struct list_head list; ++}; ++ ++static LIST_HEAD(i2c_client_drivers); ++static DECLARE_MUTEX(i2c_client_driver_list_lock); ++ ++/* Client drivers register here by their I2C driver ID */ ++int wis_i2c_add_driver(unsigned int id, found_proc found_proc) ++{ ++ struct wis_i2c_client_driver *driver; ++ ++ driver = kmalloc(sizeof(struct wis_i2c_client_driver), GFP_KERNEL); ++ if (driver == NULL) ++ return -ENOMEM; ++ driver->id = id; ++ driver->found_proc = found_proc; ++ ++ down(&i2c_client_driver_list_lock); ++ list_add_tail(&driver->list, &i2c_client_drivers); ++ up(&i2c_client_driver_list_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(wis_i2c_add_driver); ++ ++void wis_i2c_del_driver(found_proc found_proc) ++{ ++ struct wis_i2c_client_driver *driver, *next; ++ ++ down(&i2c_client_driver_list_lock); ++ list_for_each_entry_safe(driver, next, &i2c_client_drivers, list) ++ if (driver->found_proc == found_proc) { ++ list_del(&driver->list); ++ kfree(driver); ++ } ++ up(&i2c_client_driver_list_lock); ++} ++EXPORT_SYMBOL(wis_i2c_del_driver); ++ ++/* The main go7007 driver calls this to instantiate a client by driver ++ * ID and bus address, which are both stored in the board info table */ ++int wis_i2c_probe_device(struct i2c_adapter *adapter, ++ unsigned int id, int addr) ++{ ++ struct wis_i2c_client_driver *driver; ++ int found = 0; ++ ++ if (addr < 0 || addr > 0x7f) ++ return -1; ++ down(&i2c_client_driver_list_lock); ++ list_for_each_entry(driver, &i2c_client_drivers, list) ++ if (driver->id == id) { ++ if (driver->found_proc(adapter, addr, 0) == 0) ++ found = 1; ++ break; ++ } ++ up(&i2c_client_driver_list_lock); ++ return found; ++} ++ ++/********************* Driver for on-board I2C adapter *********************/ ++ ++/* #define GO7007_I2C_DEBUG */ ++ ++#define SPI_I2C_ADDR_BASE 0x1400 ++#define STATUS_REG_ADDR (SPI_I2C_ADDR_BASE + 0x2) ++#define I2C_CTRL_REG_ADDR (SPI_I2C_ADDR_BASE + 0x6) ++#define I2C_DEV_UP_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x7) ++#define I2C_LO_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x8) ++#define I2C_DATA_REG_ADDR (SPI_I2C_ADDR_BASE + 0x9) ++#define I2C_CLKFREQ_REG_ADDR (SPI_I2C_ADDR_BASE + 0xa) ++ ++#define I2C_STATE_MASK 0x0007 ++#define I2C_READ_READY_MASK 0x0008 ++ ++/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs ++ * on the Adlink PCI-MPG24, so access is shared between all of them. */ ++static DECLARE_MUTEX(adlink_mpg24_i2c_lock); ++ ++static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, ++ u16 command, int flags, u8 *data) ++{ ++ int i, ret = -1; ++ u16 val; ++ ++ if (go->status == STATUS_SHUTDOWN) ++ return -1; ++ ++#ifdef GO7007_I2C_DEBUG ++ if (read) ++ printk(KERN_DEBUG "go7007-i2c: reading 0x%02x on 0x%02x\n", ++ command, addr); ++ else ++ printk(KERN_DEBUG ++ "go7007-i2c: writing 0x%02x to 0x%02x on 0x%02x\n", ++ *data, command, addr); ++#endif ++ ++ down(&go->hw_lock); ++ ++ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { ++ /* Bridge the I2C port on this GO7007 to the shared bus */ ++ down(&adlink_mpg24_i2c_lock); ++ go7007_write_addr(go, 0x3c82, 0x0020); ++ } ++ ++ /* Wait for I2C adapter to be ready */ ++ for (i = 0; i < 10; ++i) { ++ if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0) ++ goto i2c_done; ++ if (!(val & I2C_STATE_MASK)) ++ break; ++ msleep(100); ++ } ++ if (i == 10) { ++ printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n"); ++ goto i2c_done; ++ } ++ ++ /* Set target register (command) */ ++ go7007_write_addr(go, I2C_CTRL_REG_ADDR, flags); ++ go7007_write_addr(go, I2C_LO_ADDR_REG_ADDR, command); ++ ++ /* If we're writing, send the data and target address and we're done */ ++ if (!read) { ++ go7007_write_addr(go, I2C_DATA_REG_ADDR, *data); ++ go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR, ++ (addr << 9) | (command >> 8)); ++ ret = 0; ++ goto i2c_done; ++ } ++ ++ /* Otherwise, we're reading. First clear i2c_rx_data_rdy. */ ++ if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0) ++ goto i2c_done; ++ ++ /* Send the target address plus read flag */ ++ go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR, ++ (addr << 9) | 0x0100 | (command >> 8)); ++ ++ /* Wait for i2c_rx_data_rdy */ ++ for (i = 0; i < 10; ++i) { ++ if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0) ++ goto i2c_done; ++ if (val & I2C_READ_READY_MASK) ++ break; ++ msleep(100); ++ } ++ if (i == 10) { ++ printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n"); ++ goto i2c_done; ++ } ++ ++ /* Retrieve the read byte */ ++ if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0) ++ goto i2c_done; ++ *data = val; ++ ret = 0; ++ ++i2c_done: ++ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { ++ /* Isolate the I2C port on this GO7007 from the shared bus */ ++ go7007_write_addr(go, 0x3c82, 0x0000); ++ up(&adlink_mpg24_i2c_lock); ++ } ++ up(&go->hw_lock); ++ return ret; ++} ++ ++static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ++ unsigned short flags, char read_write, ++ u8 command, int size, union i2c_smbus_data *data) ++{ ++ struct go7007 *go = i2c_get_adapdata(adapter); ++ ++ if (size != I2C_SMBUS_BYTE_DATA) ++ return -1; ++ return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command, ++ flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte); ++} ++ ++/* VERY LIMITED I2C master xfer function -- only needed because the ++ * SMBus functions only support 8-bit commands and the SAA7135 uses ++ * 16-bit commands. The I2C interface on the GO7007, as limited as ++ * it is, does support this mode. */ ++ ++static int go7007_i2c_master_xfer(struct i2c_adapter *adapter, ++ struct i2c_msg msgs[], int num) ++{ ++ struct go7007 *go = i2c_get_adapdata(adapter); ++ int i; ++ ++ for (i = 0; i < num; ++i) { ++ /* We can only do two things here -- write three bytes, or ++ * write two bytes and read one byte. */ ++ if (msgs[i].len == 2) { ++ if (i + 1 == num || msgs[i].addr != msgs[i + 1].addr || ++ (msgs[i].flags & I2C_M_RD) || ++ !(msgs[i + 1].flags & I2C_M_RD) || ++ msgs[i + 1].len != 1) ++ return -1; ++ if (go7007_i2c_xfer(go, msgs[i].addr, 1, ++ (msgs[i].buf[0] << 8) | msgs[i].buf[1], ++ 0x01, &msgs[i + 1].buf[0]) < 0) ++ return -1; ++ ++i; ++ } else if (msgs[i].len == 3) { ++ if (msgs[i].flags & I2C_M_RD) ++ return -1; ++ if (msgs[i].len != 3) ++ return -1; ++ if (go7007_i2c_xfer(go, msgs[i].addr, 0, ++ (msgs[i].buf[0] << 8) | msgs[i].buf[1], ++ 0x01, &msgs[i].buf[2]) < 0) ++ return -1; ++ } else ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static u32 go7007_functionality(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_SMBUS_BYTE_DATA; ++} ++ ++static struct i2c_algorithm go7007_algo = { ++ .smbus_xfer = go7007_smbus_xfer, ++ .master_xfer = go7007_i2c_master_xfer, ++ .functionality = go7007_functionality, ++}; ++ ++static struct i2c_adapter go7007_adap_templ = { ++ .owner = THIS_MODULE, ++ .class = I2C_CLASS_TV_ANALOG, ++ .name = "WIS GO7007SB", ++ .id = I2C_ALGO_GO7007, ++ .algo = &go7007_algo, ++}; ++ ++int go7007_i2c_init(struct go7007 *go) ++{ ++ memcpy(&go->i2c_adapter, &go7007_adap_templ, ++ sizeof(go7007_adap_templ)); ++ go->i2c_adapter.dev.parent = go->dev; ++ i2c_set_adapdata(&go->i2c_adapter, go); ++ if (i2c_add_adapter(&go->i2c_adapter) < 0) { ++ printk(KERN_ERR ++ "go7007-i2c: error: i2c_add_adapter failed\n"); ++ return -1; ++ } ++ return 0; ++} +diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/go7007/go7007-priv.h +new file mode 100644 +index 0000000..005542d +--- /dev/null ++++ b/drivers/staging/go7007/go7007-priv.h +@@ -0,0 +1,279 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++/* ++ * This is the private include file for the go7007 driver. It should not ++ * be included by anybody but the driver itself, and especially not by ++ * user-space applications. ++ */ ++ ++struct go7007; ++ ++/* IDs to activate board-specific support code */ ++#define GO7007_BOARDID_MATRIX_II 0 ++#define GO7007_BOARDID_MATRIX_RELOAD 1 ++#define GO7007_BOARDID_STAR_TREK 2 ++#define GO7007_BOARDID_PCI_VOYAGER 3 ++#define GO7007_BOARDID_XMEN 4 ++#define GO7007_BOARDID_XMEN_II 5 ++#define GO7007_BOARDID_XMEN_III 6 ++#define GO7007_BOARDID_MATRIX_REV 7 ++#define GO7007_BOARDID_PX_M402U 16 ++#define GO7007_BOARDID_PX_TV402U_ANY 17 /* need to check tuner model */ ++#define GO7007_BOARDID_PX_TV402U_NA 18 /* detected NTSC tuner */ ++#define GO7007_BOARDID_PX_TV402U_EU 19 /* detected PAL tuner */ ++#define GO7007_BOARDID_PX_TV402U_JP 20 /* detected NTSC-J tuner */ ++#define GO7007_BOARDID_LIFEVIEW_LR192 21 /* TV Walker Ultra */ ++#define GO7007_BOARDID_ENDURA 22 ++#define GO7007_BOARDID_ADLINK_MPG24 23 ++ ++/* Various characteristics of each board */ ++#define GO7007_BOARD_HAS_AUDIO (1<<0) ++#define GO7007_BOARD_USE_ONBOARD_I2C (1<<1) ++#define GO7007_BOARD_HAS_TUNER (1<<2) ++ ++/* Characteristics of sensor devices */ ++#define GO7007_SENSOR_VALID_POLAR (1<<0) ++#define GO7007_SENSOR_HREF_POLAR (1<<1) ++#define GO7007_SENSOR_VREF_POLAR (1<<2) ++#define GO7007_SENSOR_FIELD_ID_POLAR (1<<3) ++#define GO7007_SENSOR_BIT_WIDTH (1<<4) ++#define GO7007_SENSOR_VALID_ENABLE (1<<5) ++#define GO7007_SENSOR_656 (1<<6) ++#define GO7007_SENSOR_CONFIG_MASK 0x7f ++#define GO7007_SENSOR_TV (1<<7) ++#define GO7007_SENSOR_VBI (1<<8) ++#define GO7007_SENSOR_SCALING (1<<9) ++ ++/* Characteristics of audio sensor devices */ ++#define GO7007_AUDIO_I2S_MODE_1 (1) ++#define GO7007_AUDIO_I2S_MODE_2 (2) ++#define GO7007_AUDIO_I2S_MODE_3 (3) ++#define GO7007_AUDIO_BCLK_POLAR (1<<2) ++#define GO7007_AUDIO_WORD_14 (14<<4) ++#define GO7007_AUDIO_WORD_16 (16<<4) ++#define GO7007_AUDIO_ONE_CHANNEL (1<<11) ++#define GO7007_AUDIO_I2S_MASTER (1<<16) ++#define GO7007_AUDIO_OKI_MODE (1<<17) ++ ++struct go7007_board_info { ++ char *firmware; ++ unsigned int flags; ++ int hpi_buffer_cap; ++ unsigned int sensor_flags; ++ int sensor_width; ++ int sensor_height; ++ int sensor_framerate; ++ int sensor_h_offset; ++ int sensor_v_offset; ++ unsigned int audio_flags; ++ int audio_rate; ++ int audio_bclk_div; ++ int audio_main_div; ++ int num_i2c_devs; ++ struct { ++ int id; ++ int addr; ++ } i2c_devs[4]; ++ int num_inputs; ++ struct { ++ int video_input; ++ int audio_input; ++ char *name; ++ } inputs[4]; ++}; ++ ++struct go7007_hpi_ops { ++ int (*interface_reset)(struct go7007 *go); ++ int (*write_interrupt)(struct go7007 *go, int addr, int data); ++ int (*read_interrupt)(struct go7007 *go); ++ int (*stream_start)(struct go7007 *go); ++ int (*stream_stop)(struct go7007 *go); ++ int (*send_firmware)(struct go7007 *go, u8 *data, int len); ++}; ++ ++/* The video buffer size must be a multiple of PAGE_SIZE */ ++#define GO7007_BUF_PAGES (128 * 1024 / PAGE_SIZE) ++#define GO7007_BUF_SIZE (GO7007_BUF_PAGES << PAGE_SHIFT) ++ ++struct go7007_buffer { ++ struct go7007 *go; /* Reverse reference for VMA ops */ ++ int index; /* Reverse reference for DQBUF */ ++ enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state; ++ u32 seq; ++ struct timeval timestamp; ++ struct list_head stream; ++ struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */ ++ unsigned long user_addr; ++ unsigned int page_count; ++ unsigned int offset; ++ unsigned int bytesused; ++ unsigned int frame_offset; ++ u32 modet_active; ++ int mapped; ++}; ++ ++struct go7007_file { ++ struct go7007 *go; ++ struct semaphore lock; ++ int buf_count; ++ struct go7007_buffer *bufs; ++}; ++ ++#define GO7007_FORMAT_MJPEG 0 ++#define GO7007_FORMAT_MPEG4 1 ++#define GO7007_FORMAT_MPEG1 2 ++#define GO7007_FORMAT_MPEG2 3 ++#define GO7007_FORMAT_H263 4 ++ ++#define GO7007_RATIO_1_1 0 ++#define GO7007_RATIO_4_3 1 ++#define GO7007_RATIO_16_9 2 ++ ++enum go7007_parser_state { ++ STATE_DATA, ++ STATE_00, ++ STATE_00_00, ++ STATE_00_00_01, ++ STATE_FF, ++ STATE_VBI_LEN_A, ++ STATE_VBI_LEN_B, ++ STATE_MODET_MAP, ++ STATE_UNPARSED, ++}; ++ ++struct go7007 { ++ struct device *dev; ++ struct go7007_board_info *board_info; ++ unsigned int board_id; ++ int tuner_type; ++ int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */ ++ char name[64]; ++ struct video_device *video_dev; ++ int ref_count; ++ enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; ++ spinlock_t spinlock; ++ struct semaphore hw_lock; ++ int streaming; ++ int in_use; ++ int audio_enabled; ++ ++ /* Video input */ ++ int input; ++ enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard; ++ int sensor_framerate; ++ int width; ++ int height; ++ int encoder_h_offset; ++ int encoder_v_offset; ++ unsigned int encoder_h_halve:1; ++ unsigned int encoder_v_halve:1; ++ unsigned int encoder_subsample:1; ++ ++ /* Encoder config */ ++ int format; ++ int bitrate; ++ int fps_scale; ++ int pali; ++ int aspect_ratio; ++ int gop_size; ++ unsigned int ipb:1; ++ unsigned int closed_gop:1; ++ unsigned int repeat_seqhead:1; ++ unsigned int seq_header_enable:1; ++ unsigned int gop_header_enable:1; ++ unsigned int dvd_mode:1; ++ unsigned int interlace_coding:1; ++ ++ /* Motion detection */ ++ unsigned int modet_enable:1; ++ struct { ++ unsigned int enable:1; ++ int pixel_threshold; ++ int motion_threshold; ++ int mb_threshold; ++ } modet[4]; ++ unsigned char modet_map[1624]; ++ unsigned char active_map[216]; ++ ++ /* Video streaming */ ++ struct go7007_buffer *active_buf; ++ enum go7007_parser_state state; ++ int parse_length; ++ u16 modet_word; ++ int seen_frame; ++ u32 next_seq; ++ struct list_head stream; ++ wait_queue_head_t frame_waitq; ++ ++ /* Audio streaming */ ++ void (*audio_deliver)(struct go7007 *go, u8 *buf, int length); ++ void *snd_context; ++ ++ /* I2C */ ++ int i2c_adapter_online; ++ struct i2c_adapter i2c_adapter; ++ ++ /* HPI driver */ ++ struct go7007_hpi_ops *hpi_ops; ++ void *hpi_context; ++ int interrupt_available; ++ wait_queue_head_t interrupt_waitq; ++ unsigned short interrupt_value; ++ unsigned short interrupt_data; ++}; ++ ++/* All of these must be called with the hpi_lock semaphore held! */ ++#define go7007_interface_reset(go) \ ++ ((go)->hpi_ops->interface_reset(go)) ++#define go7007_write_interrupt(go, x, y) \ ++ ((go)->hpi_ops->write_interrupt)((go), (x), (y)) ++#define go7007_stream_start(go) \ ++ ((go)->hpi_ops->stream_start(go)) ++#define go7007_stream_stop(go) \ ++ ((go)->hpi_ops->stream_stop(go)) ++#define go7007_send_firmware(go, x, y) \ ++ ((go)->hpi_ops->send_firmware)((go), (x), (y)) ++#define go7007_write_addr(go, x, y) \ ++ ((go)->hpi_ops->write_interrupt)((go), (x)|0x8000, (y)) ++ ++/* go7007-driver.c */ ++int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data); ++int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data); ++int go7007_boot_encoder(struct go7007 *go, int init_i2c); ++int go7007_reset_encoder(struct go7007 *go); ++int go7007_register_encoder(struct go7007 *go); ++int go7007_start_encoder(struct go7007 *go); ++void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); ++struct go7007 *go7007_alloc(struct go7007_board_info *board, ++ struct device *dev); ++void go7007_remove(struct go7007 *go); ++ ++/* go7007-fw.c */ ++int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen); ++ ++/* go7007-i2c.c */ ++int go7007_i2c_init(struct go7007 *go); ++int go7007_i2c_remove(struct go7007 *go); ++ ++/* go7007-v4l2.c */ ++int go7007_v4l2_init(struct go7007 *go); ++void go7007_v4l2_remove(struct go7007 *go); ++ ++/* snd-go7007.c */ ++int go7007_snd_init(struct go7007 *go); ++int go7007_snd_remove(struct go7007 *go); +diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c +new file mode 100644 +index 0000000..d4ed6d2 +--- /dev/null ++++ b/drivers/staging/go7007/go7007-usb.c +@@ -0,0 +1,1229 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "go7007-priv.h" ++#include "wis-i2c.h" ++ ++static unsigned int assume_endura; ++module_param(assume_endura, int, 0644); ++MODULE_PARM_DESC(assume_endura, "when probing fails, hardware is a Pelco Endura"); ++ ++/* #define GO7007_USB_DEBUG */ ++/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */ ++ ++#define HPI_STATUS_ADDR 0xFFF4 ++#define INT_PARAM_ADDR 0xFFF6 ++#define INT_INDEX_ADDR 0xFFF8 ++ ++/* ++ * Pipes on EZ-USB interface: ++ * 0 snd - Control ++ * 0 rcv - Control ++ * 2 snd - Download firmware (control) ++ * 4 rcv - Read Interrupt (interrupt) ++ * 6 rcv - Read Video (bulk) ++ * 8 rcv - Read Audio (bulk) ++ */ ++ ++#define GO7007_USB_EZUSB (1<<0) ++#define GO7007_USB_EZUSB_I2C (1<<1) ++ ++struct go7007_usb_board { ++ unsigned int flags; ++ struct go7007_board_info main_info; ++}; ++ ++struct go7007_usb { ++ struct go7007_usb_board *board; ++ struct semaphore i2c_lock; ++ struct usb_device *usbdev; ++ struct urb *video_urbs[8]; ++ struct urb *audio_urbs[8]; ++ struct urb *intr_urb; ++}; ++ ++/*********************** Product specification data ***********************/ ++ ++static struct go7007_usb_board board_matrix_ii = { ++ .flags = GO7007_USB_EZUSB, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_HAS_AUDIO | ++ GO7007_BOARD_USE_ONBOARD_I2C, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 48000, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_VALID_ENABLE | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI | ++ GO7007_SENSOR_SCALING, ++ .num_i2c_devs = 1, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_SAA7115, ++ .addr = 0x20, ++ }, ++ }, ++ .num_inputs = 2, ++ .inputs = { ++ { ++ .video_input = 0, ++ .name = "Composite", ++ }, ++ { ++ .video_input = 9, ++ .name = "S-Video", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_matrix_reload = { ++ .flags = GO7007_USB_EZUSB, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_HAS_AUDIO | ++ GO7007_BOARD_USE_ONBOARD_I2C, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_I2S_MASTER | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 48000, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_TV, ++ .num_i2c_devs = 1, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_SAA7113, ++ .addr = 0x25, ++ }, ++ }, ++ .num_inputs = 2, ++ .inputs = { ++ { ++ .video_input = 0, ++ .name = "Composite", ++ }, ++ { ++ .video_input = 9, ++ .name = "S-Video", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_star_trek = { ++ .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_HAS_AUDIO, /* | ++ GO7007_BOARD_HAS_TUNER, */ ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_VALID_ENABLE | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI | ++ GO7007_SENSOR_SCALING, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_WORD_16, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .num_i2c_devs = 1, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_SAA7115, ++ .addr = 0x20, ++ }, ++ }, ++ .num_inputs = 2, ++ .inputs = { ++ { ++ .video_input = 1, ++ /* .audio_input = AUDIO_EXTERN, */ ++ .name = "Composite", ++ }, ++ { ++ .video_input = 8, ++ /* .audio_input = AUDIO_EXTERN, */ ++ .name = "S-Video", ++ }, ++ /* { ++ * .video_input = 3, ++ * .audio_input = AUDIO_TUNER, ++ * .name = "Tuner", ++ * }, ++ */ ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_px_tv402u = { ++ .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_HAS_AUDIO | ++ GO7007_BOARD_HAS_TUNER, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_VALID_ENABLE | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI | ++ GO7007_SENSOR_SCALING, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_WORD_16, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .num_i2c_devs = 3, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_SAA7115, ++ .addr = 0x20, ++ }, ++ { ++ .id = I2C_DRIVERID_WIS_UDA1342, ++ .addr = 0x1a, ++ }, ++ { ++ .id = I2C_DRIVERID_WIS_SONY_TUNER, ++ .addr = 0x60, ++ }, ++ }, ++ .num_inputs = 3, ++ .inputs = { ++ { ++ .video_input = 1, ++ .audio_input = TVAUDIO_INPUT_EXTERN, ++ .name = "Composite", ++ }, ++ { ++ .video_input = 8, ++ .audio_input = TVAUDIO_INPUT_EXTERN, ++ .name = "S-Video", ++ }, ++ { ++ .video_input = 3, ++ .audio_input = TVAUDIO_INPUT_TUNER, ++ .name = "Tuner", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_xmen = { ++ .flags = 0, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_USE_ONBOARD_I2C, ++ .hpi_buffer_cap = 0, ++ .sensor_flags = GO7007_SENSOR_VREF_POLAR, ++ .sensor_width = 320, ++ .sensor_height = 240, ++ .sensor_framerate = 30030, ++ .audio_flags = GO7007_AUDIO_ONE_CHANNEL | ++ GO7007_AUDIO_I2S_MODE_3 | ++ GO7007_AUDIO_WORD_14 | ++ GO7007_AUDIO_I2S_MASTER | ++ GO7007_AUDIO_BCLK_POLAR | ++ GO7007_AUDIO_OKI_MODE, ++ .audio_rate = 8000, ++ .audio_bclk_div = 48, ++ .audio_main_div = 1, ++ .num_i2c_devs = 1, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_OV7640, ++ .addr = 0x21, ++ }, ++ }, ++ .num_inputs = 1, ++ .inputs = { ++ { ++ .name = "Camera", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_matrix_revolution = { ++ .flags = GO7007_USB_EZUSB, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_HAS_AUDIO | ++ GO7007_BOARD_USE_ONBOARD_I2C, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_I2S_MASTER | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 48000, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI, ++ .num_i2c_devs = 1, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_TW9903, ++ .addr = 0x44, ++ }, ++ }, ++ .num_inputs = 2, ++ .inputs = { ++ { ++ .video_input = 2, ++ .name = "Composite", ++ }, ++ { ++ .video_input = 8, ++ .name = "S-Video", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_lifeview_lr192 = { ++ .flags = GO7007_USB_EZUSB, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_HAS_AUDIO | ++ GO7007_BOARD_USE_ONBOARD_I2C, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 48000, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_VALID_ENABLE | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI | ++ GO7007_SENSOR_SCALING, ++ .num_i2c_devs = 0, ++ .num_inputs = 1, ++ .inputs = { ++ { ++ .video_input = 0, ++ .name = "Composite", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_endura = { ++ .flags = 0, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = 0, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_I2S_MASTER | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 8000, ++ .audio_bclk_div = 48, ++ .audio_main_div = 8, ++ .hpi_buffer_cap = 0, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_TV, ++ .sensor_h_offset = 8, ++ .num_i2c_devs = 0, ++ .num_inputs = 1, ++ .inputs = { ++ { ++ .name = "Camera", ++ }, ++ }, ++ }, ++}; ++ ++static struct go7007_usb_board board_adlink_mpg24 = { ++ .flags = 0, ++ .main_info = { ++ .firmware = "go7007tv.bin", ++ .flags = GO7007_BOARD_USE_ONBOARD_I2C, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_I2S_MASTER | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 48000, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 0, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI, ++ .num_i2c_devs = 1, ++ .i2c_devs = { ++ { ++ .id = I2C_DRIVERID_WIS_TW2804, ++ .addr = 0x00, /* yes, really */ ++ }, ++ }, ++ .num_inputs = 1, ++ .inputs = { ++ { ++ .name = "Composite", ++ }, ++ }, ++ }, ++}; ++ ++static struct usb_device_id go7007_usb_id_table[] = { ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | ++ USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x200, /* Revision number of XMen */ ++ .bcdDevice_hi = 0x200, ++ .bInterfaceClass = 255, ++ .bInterfaceSubClass = 0, ++ .bInterfaceProtocol = 255, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x202, /* Revision number of Matrix II */ ++ .bcdDevice_hi = 0x202, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x204, /* Revision number of Matrix */ ++ .bcdDevice_hi = 0x204, /* Reloaded */ ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | ++ USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x205, /* Revision number of XMen-II */ ++ .bcdDevice_hi = 0x205, ++ .bInterfaceClass = 255, ++ .bInterfaceSubClass = 0, ++ .bInterfaceProtocol = 255, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x208, /* Revision number of Star Trek */ ++ .bcdDevice_hi = 0x208, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | ++ USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x209, /* Revision number of XMen-III */ ++ .bcdDevice_hi = 0x209, ++ .bInterfaceClass = 255, ++ .bInterfaceSubClass = 0, ++ .bInterfaceProtocol = 255, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ ++ .idProduct = 0x7007, /* Product ID of GO7007SB chip */ ++ .bcdDevice_lo = 0x210, /* Revision number of Matrix */ ++ .bcdDevice_hi = 0x210, /* Revolution */ ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x093b, /* Vendor ID of Plextor */ ++ .idProduct = 0xa102, /* Product ID of M402U */ ++ .bcdDevice_lo = 0x1, /* revision number of Blueberry */ ++ .bcdDevice_hi = 0x1, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x093b, /* Vendor ID of Plextor */ ++ .idProduct = 0xa104, /* Product ID of TV402U */ ++ .bcdDevice_lo = 0x1, ++ .bcdDevice_hi = 0x1, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY, ++ }, ++ { ++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, ++ .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */ ++ .idProduct = 0xde00, /* Product ID of Lifeview LR192 */ ++ .bcdDevice_lo = 0x1, ++ .bcdDevice_hi = 0x1, ++ .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192, ++ }, ++ { } /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, go7007_usb_id_table); ++ ++/********************* Driver for EZ-USB HPI interface *********************/ ++ ++static int go7007_usb_vendor_request(struct go7007 *go, int request, ++ int value, int index, void *transfer_buffer, int length, int in) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ int timeout = 5000; ++ ++ if (in) { ++ return usb_control_msg(usb->usbdev, ++ usb_rcvctrlpipe(usb->usbdev, 0), request, ++ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, ++ value, index, transfer_buffer, length, timeout); ++ } else { ++ return usb_control_msg(usb->usbdev, ++ usb_sndctrlpipe(usb->usbdev, 0), request, ++ USB_TYPE_VENDOR | USB_RECIP_DEVICE, ++ value, index, transfer_buffer, length, timeout); ++ } ++} ++ ++static int go7007_usb_interface_reset(struct go7007 *go) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ u16 intr_val, intr_data; ++ ++ /* Reset encoder */ ++ if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) ++ return -1; ++ msleep(100); ++ ++ if (usb->board->flags & GO7007_USB_EZUSB) { ++ /* Reset buffer in EZ-USB */ ++#ifdef GO7007_USB_DEBUG ++ printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n"); ++#endif ++ if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 || ++ go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0) ++ return -1; ++ ++ /* Reset encoder again */ ++ if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) ++ return -1; ++ msleep(100); ++ } ++ ++ /* Wait for an interrupt to indicate successful hardware reset */ ++ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || ++ (intr_val & ~0x1) != 0x55aa) { ++ printk(KERN_ERR ++ "go7007-usb: unable to reset the USB interface\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, ++ int addr, int data) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ int i, r; ++ u16 status_reg; ++ int timeout = 500; ++ ++#ifdef GO7007_USB_DEBUG ++ printk(KERN_DEBUG ++ "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); ++#endif ++ ++ for (i = 0; i < 100; ++i) { ++ r = usb_control_msg(usb->usbdev, ++ usb_rcvctrlpipe(usb->usbdev, 0), 0x14, ++ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, ++ 0, HPI_STATUS_ADDR, &status_reg, ++ sizeof(status_reg), timeout); ++ if (r < 0) ++ goto write_int_error; ++ __le16_to_cpus(&status_reg); ++ if (!(status_reg & 0x0010)) ++ break; ++ msleep(10); ++ } ++ if (i == 100) { ++ printk(KERN_ERR ++ "go7007-usb: device is hung, status reg = 0x%04x\n", ++ status_reg); ++ return -1; ++ } ++ r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12, ++ USB_TYPE_VENDOR | USB_RECIP_DEVICE, data, ++ INT_PARAM_ADDR, NULL, 0, timeout); ++ if (r < 0) ++ goto write_int_error; ++ r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), ++ 0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr, ++ INT_INDEX_ADDR, NULL, 0, timeout); ++ if (r < 0) ++ goto write_int_error; ++ return 0; ++ ++write_int_error: ++ printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); ++ return r; ++} ++ ++static int go7007_usb_onboard_write_interrupt(struct go7007 *go, ++ int addr, int data) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ u8 *tbuf; ++ int r; ++ int timeout = 500; ++ ++#ifdef GO7007_USB_DEBUG ++ printk(KERN_DEBUG ++ "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); ++#endif ++ ++ tbuf = kmalloc(8, GFP_KERNEL); ++ if (tbuf == NULL) ++ return -ENOMEM; ++ memset(tbuf, 0, 8); ++ tbuf[0] = data & 0xff; ++ tbuf[1] = data >> 8; ++ tbuf[2] = addr & 0xff; ++ tbuf[3] = addr >> 8; ++ r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00, ++ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa, ++ 0xf0f0, tbuf, 8, timeout); ++ kfree(tbuf); ++ if (r < 0) { ++ printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); ++ return r; ++ } ++ return 0; ++} ++ ++static void go7007_usb_readinterrupt_complete(struct urb *urb) ++{ ++ struct go7007 *go = (struct go7007 *)urb->context; ++ u16 *regs = (u16 *)urb->transfer_buffer; ++ ++ if (urb->status != 0) { ++ if (urb->status != -ESHUTDOWN && ++ go->status != STATUS_SHUTDOWN) { ++ printk(KERN_ERR ++ "go7007-usb: error in read interrupt: %d\n", ++ urb->status); ++ } else { ++ wake_up(&go->interrupt_waitq); ++ return; ++ } ++ } else if (urb->actual_length != urb->transfer_buffer_length) { ++ printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n"); ++ } else { ++ go->interrupt_available = 1; ++ go->interrupt_data = __le16_to_cpu(regs[0]); ++ go->interrupt_value = __le16_to_cpu(regs[1]); ++#ifdef GO7007_USB_DEBUG ++ printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n", ++ go->interrupt_value, go->interrupt_data); ++#endif ++ } ++ ++ wake_up(&go->interrupt_waitq); ++} ++ ++static int go7007_usb_read_interrupt(struct go7007 *go) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ int r; ++ ++ r = usb_submit_urb(usb->intr_urb, GFP_KERNEL); ++ if (r < 0) { ++ printk(KERN_ERR ++ "go7007-usb: unable to submit interrupt urb: %d\n", r); ++ return r; ++ } ++ return 0; ++} ++ ++static void go7007_usb_read_video_pipe_complete(struct urb *urb) ++{ ++ struct go7007 *go = (struct go7007 *)urb->context; ++ int r; ++ ++ if (!go->streaming) { ++ wake_up_interruptible(&go->frame_waitq); ++ return; ++ } ++ if (urb->status != 0) { ++ printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", ++ urb->status); ++ return; ++ } ++ if (urb->actual_length != urb->transfer_buffer_length) { ++ printk(KERN_ERR "go7007-usb: short read in video pipe!\n"); ++ return; ++ } ++ go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length); ++ r = usb_submit_urb(urb, GFP_ATOMIC); ++ if (r < 0) ++ printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r); ++} ++ ++static void go7007_usb_read_audio_pipe_complete(struct urb *urb) ++{ ++ struct go7007 *go = (struct go7007 *)urb->context; ++ int r; ++ ++ if (!go->streaming) ++ return; ++ if (urb->status != 0) { ++ printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", ++ urb->status); ++ return; ++ } ++ if (urb->actual_length != urb->transfer_buffer_length) { ++ printk(KERN_ERR "go7007-usb: short read in audio pipe!\n"); ++ return; ++ } ++ if (go->audio_deliver != NULL) ++ go->audio_deliver(go, urb->transfer_buffer, urb->actual_length); ++ r = usb_submit_urb(urb, GFP_ATOMIC); ++ if (r < 0) ++ printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r); ++} ++ ++static int go7007_usb_stream_start(struct go7007 *go) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ int i, r; ++ ++ for (i = 0; i < 8; ++i) { ++ r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL); ++ if (r < 0) { ++ printk(KERN_ERR "go7007-usb: error submitting video " ++ "urb %d: %d\n", i, r); ++ goto video_submit_failed; ++ } ++ } ++ if (!go->audio_enabled) ++ return 0; ++ ++ for (i = 0; i < 8; ++i) { ++ r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL); ++ if (r < 0) { ++ printk(KERN_ERR "go7007-usb: error submitting audio " ++ "urb %d: %d\n", i, r); ++ goto audio_submit_failed; ++ } ++ } ++ return 0; ++ ++audio_submit_failed: ++ for (i = 0; i < 8; ++i) ++ usb_kill_urb(usb->audio_urbs[i]); ++video_submit_failed: ++ for (i = 0; i < 8; ++i) ++ usb_kill_urb(usb->video_urbs[i]); ++ return -1; ++} ++ ++static int go7007_usb_stream_stop(struct go7007 *go) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ int i; ++ ++ if (go->status == STATUS_SHUTDOWN) ++ return 0; ++ for (i = 0; i < 8; ++i) ++ usb_kill_urb(usb->video_urbs[i]); ++ if (go->audio_enabled) ++ for (i = 0; i < 8; ++i) ++ usb_kill_urb(usb->audio_urbs[i]); ++ return 0; ++} ++ ++static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) ++{ ++ struct go7007_usb *usb = go->hpi_context; ++ int transferred, pipe; ++ int timeout = 500; ++ ++#ifdef GO7007_USB_DEBUG ++ printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len); ++#endif ++ ++ if (usb->board->flags & GO7007_USB_EZUSB) ++ pipe = usb_sndbulkpipe(usb->usbdev, 2); ++ else ++ pipe = usb_sndbulkpipe(usb->usbdev, 3); ++ ++ return usb_bulk_msg(usb->usbdev, pipe, data, len, ++ &transferred, timeout); ++} ++ ++static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = { ++ .interface_reset = go7007_usb_interface_reset, ++ .write_interrupt = go7007_usb_ezusb_write_interrupt, ++ .read_interrupt = go7007_usb_read_interrupt, ++ .stream_start = go7007_usb_stream_start, ++ .stream_stop = go7007_usb_stream_stop, ++ .send_firmware = go7007_usb_send_firmware, ++}; ++ ++static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = { ++ .interface_reset = go7007_usb_interface_reset, ++ .write_interrupt = go7007_usb_onboard_write_interrupt, ++ .read_interrupt = go7007_usb_read_interrupt, ++ .stream_start = go7007_usb_stream_start, ++ .stream_stop = go7007_usb_stream_stop, ++ .send_firmware = go7007_usb_send_firmware, ++}; ++ ++/********************* Driver for EZ-USB I2C adapter *********************/ ++ ++static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, ++ struct i2c_msg msgs[], int num) ++{ ++ struct go7007 *go = i2c_get_adapdata(adapter); ++ struct go7007_usb *usb = go->hpi_context; ++ u8 buf[16]; ++ int buf_len, i; ++ int ret = -1; ++ ++ if (go->status == STATUS_SHUTDOWN) ++ return -1; ++ ++ down(&usb->i2c_lock); ++ ++ for (i = 0; i < num; ++i) { ++ /* The hardware command is "write some bytes then read some ++ * bytes", so we try to coalesce a write followed by a read ++ * into a single USB transaction */ ++ if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr && ++ !(msgs[i].flags & I2C_M_RD) && ++ (msgs[i + 1].flags & I2C_M_RD)) { ++#ifdef GO7007_I2C_DEBUG ++ printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d " ++ "bytes on %02x\n", msgs[i].len, ++ msgs[i + 1].len, msgs[i].addr); ++#endif ++ buf[0] = 0x01; ++ buf[1] = msgs[i].len + 1; ++ buf[2] = msgs[i].addr << 1; ++ memcpy(&buf[3], msgs[i].buf, msgs[i].len); ++ buf_len = msgs[i].len + 3; ++ buf[buf_len++] = msgs[++i].len; ++ } else if (msgs[i].flags & I2C_M_RD) { ++#ifdef GO7007_I2C_DEBUG ++ printk(KERN_DEBUG "go7007-usb: i2c read %d " ++ "bytes on %02x\n", msgs[i].len, ++ msgs[i].addr); ++#endif ++ buf[0] = 0x01; ++ buf[1] = 1; ++ buf[2] = msgs[i].addr << 1; ++ buf[3] = msgs[i].len; ++ buf_len = 4; ++ } else { ++#ifdef GO7007_I2C_DEBUG ++ printk(KERN_DEBUG "go7007-usb: i2c write %d " ++ "bytes on %02x\n", msgs[i].len, ++ msgs[i].addr); ++#endif ++ buf[0] = 0x00; ++ buf[1] = msgs[i].len + 1; ++ buf[2] = msgs[i].addr << 1; ++ memcpy(&buf[3], msgs[i].buf, msgs[i].len); ++ buf_len = msgs[i].len + 3; ++ buf[buf_len++] = 0; ++ } ++ if (go7007_usb_vendor_request(go, 0x24, 0, 0, ++ buf, buf_len, 0) < 0) ++ goto i2c_done; ++ if (msgs[i].flags & I2C_M_RD) { ++ memset(buf, 0, sizeof(buf)); ++ if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf, ++ msgs[i].len + 1, 1) < 0) ++ goto i2c_done; ++ memcpy(msgs[i].buf, buf + 1, msgs[i].len); ++ } ++ } ++ ret = 0; ++ ++i2c_done: ++ up(&usb->i2c_lock); ++ return ret; ++} ++ ++static u32 go7007_usb_functionality(struct i2c_adapter *adapter) ++{ ++ /* No errors are reported by the hardware, so we don't bother ++ * supporting quick writes to avoid confusing probing */ ++ return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK; ++} ++ ++static struct i2c_algorithm go7007_usb_algo = { ++ .master_xfer = go7007_usb_i2c_master_xfer, ++ .functionality = go7007_usb_functionality, ++}; ++ ++static struct i2c_adapter go7007_usb_adap_templ = { ++ .owner = THIS_MODULE, ++ .class = I2C_CLASS_TV_ANALOG, ++ .name = "WIS GO7007SB EZ-USB", ++ .id = I2C_ALGO_GO7007_USB, ++ .algo = &go7007_usb_algo, ++}; ++ ++/********************* USB add/remove functions *********************/ ++ ++static int go7007_usb_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct go7007 *go; ++ struct go7007_usb *usb; ++ struct go7007_usb_board *board; ++ struct usb_device *usbdev = interface_to_usbdev(intf); ++ char *name; ++ int video_pipe, i, v_urb_len; ++ ++ printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n"); ++ ++ switch (id->driver_info) { ++ case GO7007_BOARDID_MATRIX_II: ++ name = "WIS Matrix II or compatible"; ++ board = &board_matrix_ii; ++ break; ++ case GO7007_BOARDID_MATRIX_RELOAD: ++ name = "WIS Matrix Reloaded or compatible"; ++ board = &board_matrix_reload; ++ break; ++ case GO7007_BOARDID_MATRIX_REV: ++ name = "WIS Matrix Revolution or compatible"; ++ board = &board_matrix_revolution; ++ break; ++ case GO7007_BOARDID_STAR_TREK: ++ name = "WIS Star Trek or compatible"; ++ board = &board_star_trek; ++ break; ++ case GO7007_BOARDID_XMEN: ++ name = "WIS XMen or compatible"; ++ board = &board_xmen; ++ break; ++ case GO7007_BOARDID_XMEN_II: ++ name = "WIS XMen II or compatible"; ++ board = &board_xmen; ++ break; ++ case GO7007_BOARDID_XMEN_III: ++ name = "WIS XMen III or compatible"; ++ board = &board_xmen; ++ break; ++ case GO7007_BOARDID_PX_M402U: ++ name = "Plextor PX-M402U"; ++ board = &board_matrix_ii; ++ break; ++ case GO7007_BOARDID_PX_TV402U_ANY: ++ name = "Plextor PX-TV402U (unknown tuner)"; ++ board = &board_px_tv402u; ++ break; ++ case GO7007_BOARDID_LIFEVIEW_LR192: ++ printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra " ++ "is not supported. Sorry!\n"); ++ return 0; ++ name = "Lifeview TV Walker Ultra"; ++ board = &board_lifeview_lr192; ++ break; ++ default: ++ printk(KERN_ERR "go7007-usb: unknown board ID %d!\n", ++ (unsigned int)id->driver_info); ++ return 0; ++ } ++ ++ usb = kmalloc(sizeof(struct go7007_usb), GFP_KERNEL); ++ if (usb == NULL) ++ return -ENOMEM; ++ memset(usb, 0, sizeof(struct go7007_usb)); ++ ++ /* Allocate the URB and buffer for receiving incoming interrupts */ ++ usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (usb->intr_urb == NULL) ++ goto allocfail; ++ usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL); ++ if (usb->intr_urb->transfer_buffer == NULL) ++ goto allocfail; ++ ++ go = go7007_alloc(&board->main_info, &intf->dev); ++ if (go == NULL) ++ goto allocfail; ++ usb->board = board; ++ usb->usbdev = usbdev; ++ go->board_id = id->driver_info; ++ strncpy(go->name, name, sizeof(go->name)); ++ if (board->flags & GO7007_USB_EZUSB) ++ go->hpi_ops = &go7007_usb_ezusb_hpi_ops; ++ else ++ go->hpi_ops = &go7007_usb_onboard_hpi_ops; ++ go->hpi_context = usb; ++ usb_fill_int_urb(usb->intr_urb, usb->usbdev, ++ usb_rcvintpipe(usb->usbdev, 4), ++ usb->intr_urb->transfer_buffer, 2*sizeof(u16), ++ go7007_usb_readinterrupt_complete, go, 8); ++ usb_set_intfdata(intf, go); ++ ++ /* Boot the GO7007 */ ++ if (go7007_boot_encoder(go, go->board_info->flags & ++ GO7007_BOARD_USE_ONBOARD_I2C) < 0) ++ goto initfail; ++ ++ /* Register the EZ-USB I2C adapter, if we're using it */ ++ if (board->flags & GO7007_USB_EZUSB_I2C) { ++ memcpy(&go->i2c_adapter, &go7007_usb_adap_templ, ++ sizeof(go7007_usb_adap_templ)); ++ init_MUTEX(&usb->i2c_lock); ++ go->i2c_adapter.dev.parent = go->dev; ++ i2c_set_adapdata(&go->i2c_adapter, go); ++ if (i2c_add_adapter(&go->i2c_adapter) < 0) { ++ printk(KERN_ERR ++ "go7007-usb: error: i2c_add_adapter failed\n"); ++ goto initfail; ++ } ++ go->i2c_adapter_online = 1; ++ } ++ ++ /* Pelco and Adlink reused the XMen and XMen-III vendor and product ++ * IDs for their own incompatible designs. We can detect XMen boards ++ * by probing the sensor, but there is no way to probe the sensors on ++ * the Pelco and Adlink designs so we default to the Adlink. If it ++ * is actually a Pelco, the user must set the assume_endura module ++ * parameter. */ ++ if ((go->board_id == GO7007_BOARDID_XMEN || ++ go->board_id == GO7007_BOARDID_XMEN_III) && ++ go->i2c_adapter_online) { ++ union i2c_smbus_data data; ++ ++ /* Check to see if register 0x0A is 0x76 */ ++ i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB, ++ I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data); ++ if (data.byte != 0x76) { ++ if (assume_endura) { ++ go->board_id = GO7007_BOARDID_ENDURA; ++ usb->board = board = &board_endura; ++ go->board_info = &board->main_info; ++ strncpy(go->name, "Pelco Endura", ++ sizeof(go->name)); ++ } else { ++ u16 channel; ++ ++ /* set GPIO5 to be an output, currently low */ ++ go7007_write_addr(go, 0x3c82, 0x0000); ++ go7007_write_addr(go, 0x3c80, 0x00df); ++ /* read channel number from GPIO[1:0] */ ++ go7007_read_addr(go, 0x3c81, &channel); ++ channel &= 0x3; ++ go->board_id = GO7007_BOARDID_ADLINK_MPG24; ++ usb->board = board = &board_adlink_mpg24; ++ go->board_info = &board->main_info; ++ go->channel_number = channel; ++ snprintf(go->name, sizeof(go->name), ++ "Adlink PCI-MPG24, channel #%d", ++ channel); ++ } ++ } ++ } ++ ++ /* Probe the tuner model on the TV402U */ ++ if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) { ++ u8 data[3]; ++ ++ /* Board strapping indicates tuner model */ ++ if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) { ++ printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); ++ goto initfail; ++ } ++ switch (data[0] >> 6) { ++ case 1: ++ go->board_id = GO7007_BOARDID_PX_TV402U_EU; ++ go->tuner_type = TUNER_SONY_BTF_PG472Z; ++ strncpy(go->name, "Plextor PX-TV402U-EU", ++ sizeof(go->name)); ++ break; ++ case 2: ++ go->board_id = GO7007_BOARDID_PX_TV402U_JP; ++ go->tuner_type = TUNER_SONY_BTF_PK467Z; ++ strncpy(go->name, "Plextor PX-TV402U-JP", ++ sizeof(go->name)); ++ break; ++ case 3: ++ go->board_id = GO7007_BOARDID_PX_TV402U_NA; ++ go->tuner_type = TUNER_SONY_BTF_PB463Z; ++ strncpy(go->name, "Plextor PX-TV402U-NA", ++ sizeof(go->name)); ++ break; ++ default: ++ printk(KERN_DEBUG "go7007-usb: unable to detect " ++ "tuner type!\n"); ++ break; ++ } ++ /* Configure tuner mode selection inputs connected ++ * to the EZ-USB GPIO output pins */ ++ if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0, ++ NULL, 0, 0) < 0) { ++ printk(KERN_ERR ++ "go7007-usb: GPIO write failed!\n"); ++ goto initfail; ++ } ++ } ++ ++ /* Print a nasty message if the user attempts to use a USB2.0 device in ++ * a USB1.1 port. There will be silent corruption of the stream. */ ++ if ((board->flags & GO7007_USB_EZUSB) && ++ usbdev->speed != USB_SPEED_HIGH) ++ printk(KERN_ERR "go7007-usb: *** WARNING *** This device " ++ "must be connected to a USB 2.0 port! " ++ "Attempting to capture video through a USB 1.1 " ++ "port will result in stream corruption, even " ++ "at low bitrates!\n"); ++ ++ /* Do any final GO7007 initialization, then register the ++ * V4L2 and ALSA interfaces */ ++ if (go7007_register_encoder(go) < 0) ++ goto initfail; ++ ++ /* Allocate the URBs and buffers for receiving the video stream */ ++ if (board->flags & GO7007_USB_EZUSB) { ++ v_urb_len = 1024; ++ video_pipe = usb_rcvbulkpipe(usb->usbdev, 6); ++ } else { ++ v_urb_len = 512; ++ video_pipe = usb_rcvbulkpipe(usb->usbdev, 1); ++ } ++ for (i = 0; i < 8; ++i) { ++ usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); ++ if (usb->video_urbs[i] == NULL) ++ goto initfail; ++ usb->video_urbs[i]->transfer_buffer = ++ kmalloc(v_urb_len, GFP_KERNEL); ++ if (usb->video_urbs[i]->transfer_buffer == NULL) ++ goto initfail; ++ usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe, ++ usb->video_urbs[i]->transfer_buffer, v_urb_len, ++ go7007_usb_read_video_pipe_complete, go); ++ } ++ ++ /* Allocate the URBs and buffers for receiving the audio stream */ ++ if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled) ++ for (i = 0; i < 8; ++i) { ++ usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); ++ if (usb->audio_urbs[i] == NULL) ++ goto initfail; ++ usb->audio_urbs[i]->transfer_buffer = kmalloc(4096, ++ GFP_KERNEL); ++ if (usb->audio_urbs[i]->transfer_buffer == NULL) ++ goto initfail; ++ usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev, ++ usb_rcvbulkpipe(usb->usbdev, 8), ++ usb->audio_urbs[i]->transfer_buffer, 4096, ++ go7007_usb_read_audio_pipe_complete, go); ++ } ++ ++ ++ go->status = STATUS_ONLINE; ++ return 0; ++ ++initfail: ++ go->status = STATUS_SHUTDOWN; ++ return 0; ++ ++allocfail: ++ if (usb->intr_urb) { ++ kfree(usb->intr_urb->transfer_buffer); ++ usb_free_urb(usb->intr_urb); ++ } ++ kfree(usb); ++ return -ENOMEM; ++} ++ ++static void go7007_usb_disconnect(struct usb_interface *intf) ++{ ++ struct go7007 *go = usb_get_intfdata(intf); ++ struct go7007_usb *usb = go->hpi_context; ++ int i; ++ ++ go->status = STATUS_SHUTDOWN; ++ usb_kill_urb(usb->intr_urb); ++ ++ /* Free USB-related structs */ ++ for (i = 0; i < 8; ++i) { ++ if (usb->video_urbs[i] != NULL) { ++ if (usb->video_urbs[i]->transfer_buffer != NULL) ++ kfree(usb->video_urbs[i]->transfer_buffer); ++ usb_free_urb(usb->video_urbs[i]); ++ } ++ if (usb->audio_urbs[i] != NULL) { ++ if (usb->audio_urbs[i]->transfer_buffer != NULL) ++ kfree(usb->audio_urbs[i]->transfer_buffer); ++ usb_free_urb(usb->audio_urbs[i]); ++ } ++ } ++ kfree(usb->intr_urb->transfer_buffer); ++ usb_free_urb(usb->intr_urb); ++ ++ kfree(go->hpi_context); ++ ++ go7007_remove(go); ++} ++ ++static struct usb_driver go7007_usb_driver = { ++ .name = "go7007", ++ .probe = go7007_usb_probe, ++ .disconnect = go7007_usb_disconnect, ++ .id_table = go7007_usb_id_table, ++}; ++ ++static int __init go7007_usb_init(void) ++{ ++ return usb_register(&go7007_usb_driver); ++} ++ ++static void __exit go7007_usb_cleanup(void) ++{ ++ usb_deregister(&go7007_usb_driver); ++} ++ ++module_init(go7007_usb_init); ++module_exit(go7007_usb_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c +new file mode 100644 +index 0000000..d54d019 +--- /dev/null ++++ b/drivers/staging/go7007/go7007-v4l2.c +@@ -0,0 +1,1503 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "go7007.h" ++#include "go7007-priv.h" ++#include "wis-i2c.h" ++ ++static void deactivate_buffer(struct go7007_buffer *gobuf) ++{ ++ int i; ++ ++ if (gobuf->state != BUF_STATE_IDLE) { ++ list_del(&gobuf->stream); ++ gobuf->state = BUF_STATE_IDLE; ++ } ++ if (gobuf->page_count > 0) { ++ for (i = 0; i < gobuf->page_count; ++i) ++ page_cache_release(gobuf->pages[i]); ++ gobuf->page_count = 0; ++ } ++} ++ ++static void abort_queued(struct go7007 *go) ++{ ++ struct go7007_buffer *gobuf, *next; ++ ++ list_for_each_entry_safe(gobuf, next, &go->stream, stream) { ++ deactivate_buffer(gobuf); ++ } ++} ++ ++static int go7007_streamoff(struct go7007 *go) ++{ ++ int retval = -EINVAL; ++ unsigned long flags; ++ ++ down(&go->hw_lock); ++ if (go->streaming) { ++ go->streaming = 0; ++ go7007_stream_stop(go); ++ spin_lock_irqsave(&go->spinlock, flags); ++ abort_queued(go); ++ spin_unlock_irqrestore(&go->spinlock, flags); ++ go7007_reset_encoder(go); ++ retval = 0; ++ } ++ up(&go->hw_lock); ++ return 0; ++} ++ ++static int go7007_open(struct inode *inode, struct file *file) ++{ ++ struct go7007 *go = video_get_drvdata(video_devdata(file)); ++ struct go7007_file *gofh; ++ ++ if (go->status != STATUS_ONLINE) ++ return -EBUSY; ++ gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL); ++ if (gofh == NULL) ++ return -ENOMEM; ++ ++go->ref_count; ++ gofh->go = go; ++ init_MUTEX(&gofh->lock); ++ gofh->buf_count = 0; ++ file->private_data = gofh; ++ return 0; ++} ++ ++static int go7007_release(struct inode *inode, struct file *file) ++{ ++ struct go7007_file *gofh = file->private_data; ++ struct go7007 *go = gofh->go; ++ ++ if (gofh->buf_count > 0) { ++ go7007_streamoff(go); ++ go->in_use = 0; ++ kfree(gofh->bufs); ++ gofh->buf_count = 0; ++ } ++ kfree(gofh); ++ if (--go->ref_count == 0) ++ kfree(go); ++ file->private_data = NULL; ++ return 0; ++} ++ ++static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) ++{ ++ u8 *f = page_address(gobuf->pages[0]); ++ ++ switch (format) { ++ case GO7007_FORMAT_MJPEG: ++ return V4L2_BUF_FLAG_KEYFRAME; ++ case GO7007_FORMAT_MPEG4: ++ switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) { ++ case 0: ++ return V4L2_BUF_FLAG_KEYFRAME; ++ case 1: ++ return V4L2_BUF_FLAG_PFRAME; ++ case 2: ++ return V4L2_BUF_FLAG_BFRAME; ++ default: ++ return 0; ++ } ++ case GO7007_FORMAT_MPEG1: ++ case GO7007_FORMAT_MPEG2: ++ switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) { ++ case 1: ++ return V4L2_BUF_FLAG_KEYFRAME; ++ case 2: ++ return V4L2_BUF_FLAG_PFRAME; ++ case 3: ++ return V4L2_BUF_FLAG_BFRAME; ++ default: ++ return 0; ++ } ++ } ++ ++ return 0; ++} ++ ++static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) ++{ ++ int sensor_height = 0, sensor_width = 0; ++ int width, height, i; ++ ++ if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && ++ fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG && ++ fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4) ++ return -EINVAL; ++ ++ switch (go->standard) { ++ case GO7007_STD_NTSC: ++ sensor_width = 720; ++ sensor_height = 480; ++ break; ++ case GO7007_STD_PAL: ++ sensor_width = 720; ++ sensor_height = 576; ++ break; ++ case GO7007_STD_OTHER: ++ sensor_width = go->board_info->sensor_width; ++ sensor_height = go->board_info->sensor_height; ++ break; ++ } ++ ++ if (fmt == NULL) { ++ width = sensor_width; ++ height = sensor_height; ++ } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { ++ if (fmt->fmt.pix.width > sensor_width) ++ width = sensor_width; ++ else if (fmt->fmt.pix.width < 144) ++ width = 144; ++ else ++ width = fmt->fmt.pix.width & ~0x0f; ++ ++ if (fmt->fmt.pix.height > sensor_height) ++ height = sensor_height; ++ else if (fmt->fmt.pix.height < 96) ++ height = 96; ++ else ++ height = fmt->fmt.pix.height & ~0x0f; ++ } else { ++ int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height; ++ int sensor_size = sensor_width * sensor_height; ++ ++ if (64 * requested_size < 9 * sensor_size) { ++ width = sensor_width / 4; ++ height = sensor_height / 4; ++ } else if (64 * requested_size < 36 * sensor_size) { ++ width = sensor_width / 2; ++ height = sensor_height / 2; ++ } else { ++ width = sensor_width; ++ height = sensor_height; ++ } ++ width &= ~0xf; ++ height &= ~0xf; ++ } ++ ++ if (fmt != NULL) { ++ u32 pixelformat = fmt->fmt.pix.pixelformat; ++ ++ memset(fmt, 0, sizeof(*fmt)); ++ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ fmt->fmt.pix.width = width; ++ fmt->fmt.pix.height = height; ++ fmt->fmt.pix.pixelformat = pixelformat; ++ fmt->fmt.pix.field = V4L2_FIELD_NONE; ++ fmt->fmt.pix.bytesperline = 0; ++ fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; ++ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ ++ } ++ ++ if (try) ++ return 0; ++ ++ go->width = width; ++ go->height = height; ++ go->encoder_h_offset = go->board_info->sensor_h_offset; ++ go->encoder_v_offset = go->board_info->sensor_v_offset; ++ for (i = 0; i < 4; ++i) ++ go->modet[i].enable = 0; ++ for (i = 0; i < 1624; ++i) ++ go->modet_map[i] = 0; ++ ++ if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { ++ struct video_decoder_resolution res; ++ ++ res.width = width; ++ if (height > sensor_height / 2) { ++ res.height = height / 2; ++ go->encoder_v_halve = 0; ++ } else { ++ res.height = height; ++ go->encoder_v_halve = 1; ++ } ++ if (go->i2c_adapter_online) ++ i2c_clients_command(&go->i2c_adapter, ++ DECODER_SET_RESOLUTION, &res); ++ } else { ++ if (width <= sensor_width / 4) { ++ go->encoder_h_halve = 1; ++ go->encoder_v_halve = 1; ++ go->encoder_subsample = 1; ++ } else if (width <= sensor_width / 2) { ++ go->encoder_h_halve = 1; ++ go->encoder_v_halve = 1; ++ go->encoder_subsample = 0; ++ } else { ++ go->encoder_h_halve = 0; ++ go->encoder_v_halve = 0; ++ go->encoder_subsample = 0; ++ } ++ } ++ ++ if (fmt == NULL) ++ return 0; ++ ++ switch (fmt->fmt.pix.pixelformat) { ++ case V4L2_PIX_FMT_MPEG: ++ if (go->format == GO7007_FORMAT_MPEG1 || ++ go->format == GO7007_FORMAT_MPEG2 || ++ go->format == GO7007_FORMAT_MPEG4) ++ break; ++ go->format = GO7007_FORMAT_MPEG1; ++ go->pali = 0; ++ go->aspect_ratio = GO7007_RATIO_1_1; ++ go->gop_size = go->sensor_framerate / 1000; ++ go->ipb = 0; ++ go->closed_gop = 1; ++ go->repeat_seqhead = 1; ++ go->seq_header_enable = 1; ++ go->gop_header_enable = 1; ++ go->dvd_mode = 0; ++ break; ++ /* Backwards compatibility only! */ ++ case V4L2_PIX_FMT_MPEG4: ++ if (go->format == GO7007_FORMAT_MPEG4) ++ break; ++ go->format = GO7007_FORMAT_MPEG4; ++ go->pali = 0xf5; ++ go->aspect_ratio = GO7007_RATIO_1_1; ++ go->gop_size = go->sensor_framerate / 1000; ++ go->ipb = 0; ++ go->closed_gop = 1; ++ go->repeat_seqhead = 1; ++ go->seq_header_enable = 1; ++ go->gop_header_enable = 1; ++ go->dvd_mode = 0; ++ break; ++ case V4L2_PIX_FMT_MJPEG: ++ go->format = GO7007_FORMAT_MJPEG; ++ go->pali = 0; ++ go->aspect_ratio = GO7007_RATIO_1_1; ++ go->gop_size = 0; ++ go->ipb = 0; ++ go->closed_gop = 0; ++ go->repeat_seqhead = 0; ++ go->seq_header_enable = 0; ++ go->gop_header_enable = 0; ++ go->dvd_mode = 0; ++ break; ++ } ++ return 0; ++} ++ ++static int clip_to_modet_map(struct go7007 *go, int region, ++ struct v4l2_clip *clip_list) ++{ ++ struct v4l2_clip clip, *clip_ptr; ++ int x, y, mbnum; ++ ++ /* Check if coordinates are OK and if any macroblocks are already ++ * used by other regions (besides 0) */ ++ clip_ptr = clip_list; ++ while (clip_ptr) { ++ if (copy_from_user(&clip, clip_ptr, sizeof(clip))) ++ return -EFAULT; ++ if (clip.c.left < 0 || (clip.c.left & 0xF) || ++ clip.c.width <= 0 || (clip.c.width & 0xF)) ++ return -EINVAL; ++ if (clip.c.left + clip.c.width > go->width) ++ return -EINVAL; ++ if (clip.c.top < 0 || (clip.c.top & 0xF) || ++ clip.c.height <= 0 || (clip.c.height & 0xF)) ++ return -EINVAL; ++ if (clip.c.top + clip.c.height > go->height) ++ return -EINVAL; ++ for (y = 0; y < clip.c.height; y += 16) ++ for (x = 0; x < clip.c.width; x += 16) { ++ mbnum = (go->width >> 4) * ++ ((clip.c.top + y) >> 4) + ++ ((clip.c.left + x) >> 4); ++ if (go->modet_map[mbnum] != 0 && ++ go->modet_map[mbnum] != region) ++ return -EBUSY; ++ } ++ clip_ptr = clip.next; ++ } ++ ++ /* Clear old region macroblocks */ ++ for (mbnum = 0; mbnum < 1624; ++mbnum) ++ if (go->modet_map[mbnum] == region) ++ go->modet_map[mbnum] = 0; ++ ++ /* Claim macroblocks in this list */ ++ clip_ptr = clip_list; ++ while (clip_ptr) { ++ if (copy_from_user(&clip, clip_ptr, sizeof(clip))) ++ return -EFAULT; ++ for (y = 0; y < clip.c.height; y += 16) ++ for (x = 0; x < clip.c.width; x += 16) { ++ mbnum = (go->width >> 4) * ++ ((clip.c.top + y) >> 4) + ++ ((clip.c.left + x) >> 4); ++ go->modet_map[mbnum] = region; ++ } ++ clip_ptr = clip.next; ++ } ++ return 0; ++} ++ ++static int go7007_do_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, void *arg) ++{ ++ struct go7007_file *gofh = file->private_data; ++ struct go7007 *go = gofh->go; ++ unsigned long flags; ++ int retval = 0; ++ ++ switch (cmd) { ++ case VIDIOC_QUERYCAP: ++ { ++ struct v4l2_capability *cap = arg; ++ ++ memset(cap, 0, sizeof(*cap)); ++ strcpy(cap->driver, "go7007"); ++ strncpy(cap->card, go->name, sizeof(cap->card)); ++ cap->version = KERNEL_VERSION(0, 9, 8); ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | ++ V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */ ++ if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) ++ cap->capabilities |= V4L2_CAP_TUNER; ++ return 0; ++ } ++ case VIDIOC_ENUM_FMT: ++ { ++ struct v4l2_fmtdesc *fmt = arg; ++ unsigned int index; ++ char *desc; ++ u32 pixelformat; ++ ++ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ switch (fmt->index) { ++ case 0: ++ pixelformat = V4L2_PIX_FMT_MJPEG; ++ desc = "Motion-JPEG"; ++ break; ++ case 1: ++ pixelformat = V4L2_PIX_FMT_MPEG; ++ desc = "MPEG1/MPEG2/MPEG4"; ++ break; ++ default: ++ return -EINVAL; ++ } ++ index = fmt->index; ++ memset(fmt, 0, sizeof(*fmt)); ++ fmt->index = index; ++ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ fmt->flags = V4L2_FMT_FLAG_COMPRESSED; ++ strncpy(fmt->description, desc, sizeof(fmt->description)); ++ fmt->pixelformat = pixelformat; ++ ++ return 0; ++ } ++ case VIDIOC_TRY_FMT: ++ { ++ struct v4l2_format *fmt = arg; ++ ++ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ return set_capture_size(go, fmt, 1); ++ } ++ case VIDIOC_G_FMT: ++ { ++ struct v4l2_format *fmt = arg; ++ ++ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ memset(fmt, 0, sizeof(*fmt)); ++ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ fmt->fmt.pix.width = go->width; ++ fmt->fmt.pix.height = go->height; ++ fmt->fmt.pix.pixelformat = go->format == GO7007_FORMAT_MJPEG ? ++ V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG; ++ fmt->fmt.pix.field = V4L2_FIELD_NONE; ++ fmt->fmt.pix.bytesperline = 0; ++ fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; ++ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ ++ return 0; ++ } ++ case VIDIOC_S_FMT: ++ { ++ struct v4l2_format *fmt = arg; ++ ++ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (go->streaming) ++ return -EBUSY; ++ return set_capture_size(go, fmt, 0); ++ } ++ case VIDIOC_G_FBUF: ++ case VIDIOC_S_FBUF: ++ return -EINVAL; ++ case VIDIOC_REQBUFS: ++ { ++ struct v4l2_requestbuffers *req = arg; ++ unsigned int count, i; ++ ++ if (go->streaming) ++ return -EBUSY; ++ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || ++ req->memory != V4L2_MEMORY_MMAP) ++ return -EINVAL; ++ ++ down(&gofh->lock); ++ retval = -EBUSY; ++ for (i = 0; i < gofh->buf_count; ++i) ++ if (gofh->bufs[i].mapped > 0) ++ goto unlock_and_return; ++ down(&go->hw_lock); ++ if (go->in_use > 0 && gofh->buf_count == 0) { ++ up(&go->hw_lock); ++ goto unlock_and_return; ++ } ++ if (gofh->buf_count > 0) ++ kfree(gofh->bufs); ++ retval = -ENOMEM; ++ count = req->count; ++ if (count > 0) { ++ if (count < 2) ++ count = 2; ++ if (count > 32) ++ count = 32; ++ gofh->bufs = kmalloc(count * ++ sizeof(struct go7007_buffer), ++ GFP_KERNEL); ++ if (gofh->bufs == NULL) { ++ up(&go->hw_lock); ++ goto unlock_and_return; ++ } ++ memset(gofh->bufs, 0, ++ count * sizeof(struct go7007_buffer)); ++ for (i = 0; i < count; ++i) { ++ gofh->bufs[i].go = go; ++ gofh->bufs[i].index = i; ++ gofh->bufs[i].state = BUF_STATE_IDLE; ++ gofh->bufs[i].mapped = 0; ++ } ++ go->in_use = 1; ++ } else { ++ go->in_use = 0; ++ } ++ gofh->buf_count = count; ++ up(&go->hw_lock); ++ up(&gofh->lock); ++ memset(req, 0, sizeof(*req)); ++ req->count = count; ++ req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ req->memory = V4L2_MEMORY_MMAP; ++ return 0; ++ } ++ case VIDIOC_QUERYBUF: ++ { ++ struct v4l2_buffer *buf = arg; ++ unsigned int index; ++ ++ retval = -EINVAL; ++ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ index = buf->index; ++ down(&gofh->lock); ++ if (index >= gofh->buf_count) ++ goto unlock_and_return; ++ memset(buf, 0, sizeof(*buf)); ++ buf->index = index; ++ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ switch (gofh->bufs[index].state) { ++ case BUF_STATE_QUEUED: ++ buf->flags = V4L2_BUF_FLAG_QUEUED; ++ break; ++ case BUF_STATE_DONE: ++ buf->flags = V4L2_BUF_FLAG_DONE; ++ break; ++ default: ++ buf->flags = 0; ++ } ++ if (gofh->bufs[index].mapped) ++ buf->flags |= V4L2_BUF_FLAG_MAPPED; ++ buf->memory = V4L2_MEMORY_MMAP; ++ buf->m.offset = index * GO7007_BUF_SIZE; ++ buf->length = GO7007_BUF_SIZE; ++ up(&gofh->lock); ++ ++ return 0; ++ } ++ case VIDIOC_QBUF: ++ { ++ struct v4l2_buffer *buf = arg; ++ struct go7007_buffer *gobuf; ++ int ret; ++ ++ retval = -EINVAL; ++ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || ++ buf->memory != V4L2_MEMORY_MMAP) ++ return -EINVAL; ++ down(&gofh->lock); ++ if (buf->index < 0 || buf->index >= gofh->buf_count) ++ goto unlock_and_return; ++ gobuf = &gofh->bufs[buf->index]; ++ if (gobuf->mapped == 0) ++ goto unlock_and_return; ++ retval = -EBUSY; ++ if (gobuf->state != BUF_STATE_IDLE) ++ goto unlock_and_return; ++ /* offset will be 0 until we really support USERPTR streaming */ ++ gobuf->offset = gobuf->user_addr & ~PAGE_MASK; ++ gobuf->bytesused = 0; ++ gobuf->frame_offset = 0; ++ gobuf->modet_active = 0; ++ if (gobuf->offset > 0) ++ gobuf->page_count = GO7007_BUF_PAGES + 1; ++ else ++ gobuf->page_count = GO7007_BUF_PAGES; ++ retval = -ENOMEM; ++ down_read(¤t->mm->mmap_sem); ++ ret = get_user_pages(current, current->mm, ++ gobuf->user_addr & PAGE_MASK, gobuf->page_count, ++ 1, 1, gobuf->pages, NULL); ++ up_read(¤t->mm->mmap_sem); ++ if (ret != gobuf->page_count) { ++ int i; ++ for (i = 0; i < ret; ++i) ++ page_cache_release(gobuf->pages[i]); ++ gobuf->page_count = 0; ++ goto unlock_and_return; ++ } ++ gobuf->state = BUF_STATE_QUEUED; ++ spin_lock_irqsave(&go->spinlock, flags); ++ list_add_tail(&gobuf->stream, &go->stream); ++ spin_unlock_irqrestore(&go->spinlock, flags); ++ up(&gofh->lock); ++ return 0; ++ } ++ case VIDIOC_DQBUF: ++ { ++ struct v4l2_buffer *buf = arg; ++ struct go7007_buffer *gobuf; ++ u32 frame_type_flag; ++ DEFINE_WAIT(wait); ++ ++ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (buf->memory != V4L2_MEMORY_MMAP) ++ return -EINVAL; ++ down(&gofh->lock); ++ retval = -EINVAL; ++ if (list_empty(&go->stream)) ++ goto unlock_and_return; ++ gobuf = list_entry(go->stream.next, ++ struct go7007_buffer, stream); ++ retval = -EAGAIN; ++ if (gobuf->state != BUF_STATE_DONE && ++ !(file->f_flags & O_NONBLOCK)) { ++ for (;;) { ++ prepare_to_wait(&go->frame_waitq, &wait, ++ TASK_INTERRUPTIBLE); ++ if (gobuf->state == BUF_STATE_DONE) ++ break; ++ if (signal_pending(current)) { ++ retval = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } ++ finish_wait(&go->frame_waitq, &wait); ++ } ++ if (gobuf->state != BUF_STATE_DONE) ++ goto unlock_and_return; ++ spin_lock_irqsave(&go->spinlock, flags); ++ deactivate_buffer(gobuf); ++ spin_unlock_irqrestore(&go->spinlock, flags); ++ frame_type_flag = get_frame_type_flag(gobuf, go->format); ++ gobuf->state = BUF_STATE_IDLE; ++ memset(buf, 0, sizeof(*buf)); ++ buf->index = gobuf->index; ++ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ buf->bytesused = gobuf->bytesused; ++ buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag; ++ buf->field = V4L2_FIELD_NONE; ++ buf->timestamp = gobuf->timestamp; ++ buf->sequence = gobuf->seq; ++ buf->memory = V4L2_MEMORY_MMAP; ++ buf->m.offset = gobuf->index * GO7007_BUF_SIZE; ++ buf->length = GO7007_BUF_SIZE; ++ buf->reserved = gobuf->modet_active; ++ up(&gofh->lock); ++ return 0; ++ } ++ case VIDIOC_STREAMON: ++ { ++ unsigned int *type = arg; ++ ++ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ down(&gofh->lock); ++ down(&go->hw_lock); ++ if (!go->streaming) { ++ go->streaming = 1; ++ go->next_seq = 0; ++ go->active_buf = NULL; ++ if (go7007_start_encoder(go) < 0) ++ retval = -EIO; ++ else ++ retval = 0; ++ } ++ up(&go->hw_lock); ++ up(&gofh->lock); ++ return retval; ++ } ++ case VIDIOC_STREAMOFF: ++ { ++ unsigned int *type = arg; ++ ++ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ down(&gofh->lock); ++ go7007_streamoff(go); ++ up(&gofh->lock); ++ return 0; ++ } ++ case VIDIOC_QUERYCTRL: ++ { ++ struct v4l2_queryctrl *ctrl = arg; ++ u32 id; ++ ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ id = ctrl->id; ++ memset(ctrl, 0, sizeof(*ctrl)); ++ ctrl->id = id; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, arg); ++ return ctrl->name[0] == 0 ? -EINVAL : 0; ++ } ++ case VIDIOC_G_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ struct v4l2_queryctrl query; ++ ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ memset(&query, 0, sizeof(query)); ++ query.id = ctrl->id; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query); ++ if (query.name[0] == 0) ++ return -EINVAL; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, arg); ++ return 0; ++ } ++ case VIDIOC_S_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ struct v4l2_queryctrl query; ++ ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ memset(&query, 0, sizeof(query)); ++ query.id = ctrl->id; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query); ++ if (query.name[0] == 0) ++ return -EINVAL; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, arg); ++ return 0; ++ } ++ case VIDIOC_G_PARM: ++ { ++ struct v4l2_streamparm *parm = arg; ++ struct v4l2_fract timeperframe = { ++ .numerator = 1001 * go->fps_scale, ++ .denominator = go->sensor_framerate, ++ }; ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ memset(parm, 0, sizeof(*parm)); ++ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; ++ parm->parm.capture.timeperframe = timeperframe; ++ return 0; ++ } ++ case VIDIOC_S_PARM: ++ { ++ struct v4l2_streamparm *parm = arg; ++ unsigned int n, d; ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (parm->parm.capture.capturemode != 0) ++ return -EINVAL; ++ n = go->sensor_framerate * ++ parm->parm.capture.timeperframe.numerator; ++ d = 1001 * parm->parm.capture.timeperframe.denominator; ++ if (n != 0 && d != 0 && n > d) ++ go->fps_scale = (n + d/2) / d; ++ else ++ go->fps_scale = 1; ++ return 0; ++ } ++ case VIDIOC_ENUMSTD: ++ { ++ struct v4l2_standard *std = arg; ++ ++ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && ++ go->input == go->board_info->num_inputs - 1) { ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ i2c_clients_command(&go->i2c_adapter, ++ VIDIOC_ENUMSTD, arg); ++ if (!std->id) /* hack to indicate EINVAL from tuner */ ++ return -EINVAL; ++ } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { ++ switch (std->index) { ++ case 0: ++ v4l2_video_std_construct(std, ++ V4L2_STD_NTSC, "NTSC"); ++ break; ++ case 1: ++ v4l2_video_std_construct(std, ++ V4L2_STD_PAL | V4L2_STD_SECAM, ++ "PAL/SECAM"); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ if (std->index != 0) ++ return -EINVAL; ++ memset(std, 0, sizeof(*std)); ++ snprintf(std->name, sizeof(std->name), "%dx%d, %dfps", ++ go->board_info->sensor_width, ++ go->board_info->sensor_height, ++ go->board_info->sensor_framerate / 1000); ++ std->frameperiod.numerator = 1001; ++ std->frameperiod.denominator = ++ go->board_info->sensor_framerate; ++ } ++ return 0; ++ } ++ case VIDIOC_G_STD: ++ { ++ v4l2_std_id *std = arg; ++ ++ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && ++ go->input == go->board_info->num_inputs - 1) { ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ i2c_clients_command(&go->i2c_adapter, ++ VIDIOC_G_STD, arg); ++ } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { ++ if (go->standard == GO7007_STD_NTSC) ++ *std = V4L2_STD_NTSC; ++ else ++ *std = V4L2_STD_PAL | V4L2_STD_SECAM; ++ } else ++ *std = 0; ++ return 0; ++ } ++ case VIDIOC_S_STD: ++ { ++ v4l2_std_id *std = arg; ++ int norm; ++ ++ if (go->streaming) ++ return -EBUSY; ++ if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && ++ *std != 0) ++ return -EINVAL; ++ if (*std == 0) ++ return -EINVAL; ++ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && ++ go->input == go->board_info->num_inputs - 1) { ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ i2c_clients_command(&go->i2c_adapter, ++ VIDIOC_S_STD, arg); ++ if (!*std) /* hack to indicate EINVAL from tuner */ ++ return -EINVAL; ++ } ++ if (*std & V4L2_STD_NTSC) { ++ go->standard = GO7007_STD_NTSC; ++ go->sensor_framerate = 30000; ++ norm = VIDEO_MODE_NTSC; ++ } else if (*std & V4L2_STD_PAL) { ++ go->standard = GO7007_STD_PAL; ++ go->sensor_framerate = 25025; ++ norm = VIDEO_MODE_PAL; ++ } else if (*std & V4L2_STD_SECAM) { ++ go->standard = GO7007_STD_PAL; ++ go->sensor_framerate = 25025; ++ norm = VIDEO_MODE_SECAM; ++ } else ++ return -EINVAL; ++ if (go->i2c_adapter_online) ++ i2c_clients_command(&go->i2c_adapter, ++ DECODER_SET_NORM, &norm); ++ set_capture_size(go, NULL, 0); ++ return 0; ++ } ++ case VIDIOC_QUERYSTD: ++ { ++ v4l2_std_id *std = arg; ++ ++ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && ++ go->input == go->board_info->num_inputs - 1) { ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ i2c_clients_command(&go->i2c_adapter, ++ VIDIOC_QUERYSTD, arg); ++ } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) ++ *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; ++ else ++ *std = 0; ++ return 0; ++ } ++ case VIDIOC_ENUMINPUT: ++ { ++ struct v4l2_input *inp = arg; ++ int index; ++ ++ if (inp->index >= go->board_info->num_inputs) ++ return -EINVAL; ++ index = inp->index; ++ memset(inp, 0, sizeof(*inp)); ++ inp->index = index; ++ strncpy(inp->name, go->board_info->inputs[index].name, ++ sizeof(inp->name)); ++ /* If this board has a tuner, it will be the last input */ ++ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && ++ index == go->board_info->num_inputs - 1) ++ inp->type = V4L2_INPUT_TYPE_TUNER; ++ else ++ inp->type = V4L2_INPUT_TYPE_CAMERA; ++ inp->audioset = 0; ++ inp->tuner = 0; ++ if (go->board_info->sensor_flags & GO7007_SENSOR_TV) ++ inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | ++ V4L2_STD_SECAM; ++ else ++ inp->std = 0; ++ return 0; ++ } ++ case VIDIOC_G_INPUT: ++ { ++ int *input = arg; ++ ++ *input = go->input; ++ return 0; ++ } ++ case VIDIOC_S_INPUT: ++ { ++ int *input = arg; ++ ++ if (*input >= go->board_info->num_inputs) ++ return -EINVAL; ++ if (go->streaming) ++ return -EBUSY; ++ go->input = *input; ++ if (go->i2c_adapter_online) { ++ i2c_clients_command(&go->i2c_adapter, DECODER_SET_INPUT, ++ &go->board_info->inputs[*input].video_input); ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO, ++ &go->board_info->inputs[*input].audio_input); ++ } ++ return 0; ++ } ++ case VIDIOC_G_TUNER: ++ { ++ struct v4l2_tuner *t = arg; ++ ++ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) ++ return -EINVAL; ++ if (t->index != 0) ++ return -EINVAL; ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, arg); ++ t->index = 0; ++ return 0; ++ } ++ case VIDIOC_S_TUNER: ++ { ++ struct v4l2_tuner *t = arg; ++ ++ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) ++ return -EINVAL; ++ if (t->index != 0) ++ return -EINVAL; ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ switch (go->board_id) { ++ case GO7007_BOARDID_PX_TV402U_NA: ++ case GO7007_BOARDID_PX_TV402U_JP: ++ /* No selectable options currently */ ++ if (t->audmode != V4L2_TUNER_MODE_STEREO) ++ return -EINVAL; ++ break; ++ } ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, arg); ++ return 0; ++ } ++ case VIDIOC_G_FREQUENCY: ++ { ++ struct v4l2_frequency *f = arg; ++ ++ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) ++ return -EINVAL; ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ memset(f, 0, sizeof(*f)); ++ f->type = V4L2_TUNER_ANALOG_TV; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, arg); ++ return 0; ++ } ++ case VIDIOC_S_FREQUENCY: ++ { ++ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) ++ return -EINVAL; ++ if (!go->i2c_adapter_online) ++ return -EIO; ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, arg); ++ return 0; ++ } ++ case VIDIOC_CROPCAP: ++ { ++ struct v4l2_cropcap *cropcap = arg; ++ ++ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ memset(cropcap, 0, sizeof(*cropcap)); ++ cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ /* These specify the raw input of the sensor */ ++ switch (go->standard) { ++ case GO7007_STD_NTSC: ++ cropcap->bounds.top = 0; ++ cropcap->bounds.left = 0; ++ cropcap->bounds.width = 720; ++ cropcap->bounds.height = 480; ++ cropcap->defrect.top = 0; ++ cropcap->defrect.left = 0; ++ cropcap->defrect.width = 720; ++ cropcap->defrect.height = 480; ++ break; ++ case GO7007_STD_PAL: ++ cropcap->bounds.top = 0; ++ cropcap->bounds.left = 0; ++ cropcap->bounds.width = 720; ++ cropcap->bounds.height = 576; ++ cropcap->defrect.top = 0; ++ cropcap->defrect.left = 0; ++ cropcap->defrect.width = 720; ++ cropcap->defrect.height = 576; ++ break; ++ case GO7007_STD_OTHER: ++ cropcap->bounds.top = 0; ++ cropcap->bounds.left = 0; ++ cropcap->bounds.width = go->board_info->sensor_width; ++ cropcap->bounds.height = go->board_info->sensor_height; ++ cropcap->defrect.top = 0; ++ cropcap->defrect.left = 0; ++ cropcap->defrect.width = go->board_info->sensor_width; ++ cropcap->defrect.height = go->board_info->sensor_height; ++ break; ++ } ++ ++ return 0; ++ } ++ case VIDIOC_G_CROP: ++ { ++ struct v4l2_crop *crop = arg; ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ memset(crop, 0, sizeof(*crop)); ++ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ /* These specify the raw input of the sensor */ ++ switch (go->standard) { ++ case GO7007_STD_NTSC: ++ crop->c.top = 0; ++ crop->c.left = 0; ++ crop->c.width = 720; ++ crop->c.height = 480; ++ break; ++ case GO7007_STD_PAL: ++ crop->c.top = 0; ++ crop->c.left = 0; ++ crop->c.width = 720; ++ crop->c.height = 576; ++ break; ++ case GO7007_STD_OTHER: ++ crop->c.top = 0; ++ crop->c.left = 0; ++ crop->c.width = go->board_info->sensor_width; ++ crop->c.height = go->board_info->sensor_height; ++ break; ++ } ++ ++ return 0; ++ } ++ case VIDIOC_S_CROP: ++ { ++ struct v4l2_crop *crop = arg; ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ return 0; ++ } ++ case VIDIOC_G_JPEGCOMP: ++ { ++ struct v4l2_jpegcompression *params = arg; ++ ++ memset(params, 0, sizeof(*params)); ++ params->quality = 50; /* ?? */ ++ params->jpeg_markers = V4L2_JPEG_MARKER_DHT | ++ V4L2_JPEG_MARKER_DQT; ++ ++ return 0; ++ } ++ case VIDIOC_S_JPEGCOMP: ++ { ++ struct v4l2_jpegcompression *params = arg; ++ ++ if (params->quality != 50 || ++ params->jpeg_markers != (V4L2_JPEG_MARKER_DHT | ++ V4L2_JPEG_MARKER_DQT)) ++ return -EINVAL; ++ return 0; ++ } ++ /* Temporary ioctls for controlling compression characteristics */ ++ case GO7007IOC_S_BITRATE: ++ { ++ int *bitrate = arg; ++ ++ if (go->streaming) ++ return -EINVAL; ++ /* Upper bound is kind of arbitrary here */ ++ if (*bitrate < 64000 || *bitrate > 10000000) ++ return -EINVAL; ++ go->bitrate = *bitrate; ++ return 0; ++ } ++ case GO7007IOC_G_BITRATE: ++ { ++ int *bitrate = arg; ++ ++ *bitrate = go->bitrate; ++ return 0; ++ } ++ case GO7007IOC_S_COMP_PARAMS: ++ { ++ struct go7007_comp_params *comp = arg; ++ ++ if (go->format == GO7007_FORMAT_MJPEG) ++ return -EINVAL; ++ if (comp->gop_size > 0) ++ go->gop_size = comp->gop_size; ++ else ++ go->gop_size = go->sensor_framerate / 1000; ++ if (go->gop_size != 15) ++ go->dvd_mode = 0; ++ /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */ ++ if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { ++ switch (comp->aspect_ratio) { ++ case GO7007_ASPECT_RATIO_4_3_NTSC: ++ case GO7007_ASPECT_RATIO_4_3_PAL: ++ go->aspect_ratio = GO7007_RATIO_4_3; ++ break; ++ case GO7007_ASPECT_RATIO_16_9_NTSC: ++ case GO7007_ASPECT_RATIO_16_9_PAL: ++ go->aspect_ratio = GO7007_RATIO_16_9; ++ break; ++ default: ++ go->aspect_ratio = GO7007_RATIO_1_1; ++ break; ++ } ++ } ++ if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) { ++ go->dvd_mode = 0; ++ go->seq_header_enable = 0; ++ } else { ++ go->seq_header_enable = 1; ++ } ++ /* fall-through */ ++ } ++ case GO7007IOC_G_COMP_PARAMS: ++ { ++ struct go7007_comp_params *comp = arg; ++ ++ if (go->format == GO7007_FORMAT_MJPEG) ++ return -EINVAL; ++ memset(comp, 0, sizeof(*comp)); ++ comp->gop_size = go->gop_size; ++ comp->max_b_frames = go->ipb ? 2 : 0; ++ switch (go->aspect_ratio) { ++ case GO7007_RATIO_4_3: ++ if (go->standard == GO7007_STD_NTSC) ++ comp->aspect_ratio = ++ GO7007_ASPECT_RATIO_4_3_NTSC; ++ else ++ comp->aspect_ratio = ++ GO7007_ASPECT_RATIO_4_3_PAL; ++ break; ++ case GO7007_RATIO_16_9: ++ if (go->standard == GO7007_STD_NTSC) ++ comp->aspect_ratio = ++ GO7007_ASPECT_RATIO_16_9_NTSC; ++ else ++ comp->aspect_ratio = ++ GO7007_ASPECT_RATIO_16_9_PAL; ++ break; ++ default: ++ comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1; ++ break; ++ } ++ if (go->closed_gop) ++ comp->flags |= GO7007_COMP_CLOSED_GOP; ++ if (!go->seq_header_enable) ++ comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER; ++ return 0; ++ } ++ case GO7007IOC_S_MPEG_PARAMS: ++ { ++ struct go7007_mpeg_params *mpeg = arg; ++ ++ if (go->format != GO7007_FORMAT_MPEG1 && ++ go->format != GO7007_FORMAT_MPEG2 && ++ go->format != GO7007_FORMAT_MPEG4) ++ return -EINVAL; ++ ++ if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) { ++ go->format = GO7007_FORMAT_MPEG2; ++ go->bitrate = 9800000; ++ go->gop_size = 15; ++ go->pali = 0x48; ++ go->closed_gop = 1; ++ go->repeat_seqhead = 0; ++ go->seq_header_enable = 1; ++ go->gop_header_enable = 1; ++ go->dvd_mode = 1; ++ } else { ++ switch (mpeg->mpeg_video_standard) { ++ case GO7007_MPEG_VIDEO_MPEG1: ++ go->format = GO7007_FORMAT_MPEG1; ++ go->pali = 0; ++ break; ++ case GO7007_MPEG_VIDEO_MPEG2: ++ go->format = GO7007_FORMAT_MPEG2; ++ if (mpeg->pali >> 24 == 2) ++ go->pali = mpeg->pali & 0xff; ++ else ++ go->pali = 0x48; ++ break; ++ case GO7007_MPEG_VIDEO_MPEG4: ++ go->format = GO7007_FORMAT_MPEG4; ++ if (mpeg->pali >> 24 == 4) ++ go->pali = mpeg->pali & 0xff; ++ else ++ go->pali = 0xf5; ++ break; ++ default: ++ return -EINVAL; ++ } ++ go->gop_header_enable = ++ mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER ++ ? 0 : 1; ++ if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) ++ go->repeat_seqhead = 1; ++ else ++ go->repeat_seqhead = 0; ++ go->dvd_mode = 0; ++ } ++ /* fall-through */ ++ } ++ case GO7007IOC_G_MPEG_PARAMS: ++ { ++ struct go7007_mpeg_params *mpeg = arg; ++ ++ memset(mpeg, 0, sizeof(*mpeg)); ++ switch (go->format) { ++ case GO7007_FORMAT_MPEG1: ++ mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1; ++ mpeg->pali = 0; ++ break; ++ case GO7007_FORMAT_MPEG2: ++ mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2; ++ mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali); ++ break; ++ case GO7007_FORMAT_MPEG4: ++ mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4; ++ mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali); ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (!go->gop_header_enable) ++ mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER; ++ if (go->repeat_seqhead) ++ mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER; ++ if (go->dvd_mode) ++ mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE; ++ return 0; ++ } ++ case GO7007IOC_S_MD_PARAMS: ++ { ++ struct go7007_md_params *mdp = arg; ++ ++ if (mdp->region > 3) ++ return -EINVAL; ++ if (mdp->trigger > 0) { ++ go->modet[mdp->region].pixel_threshold = ++ mdp->pixel_threshold >> 1; ++ go->modet[mdp->region].motion_threshold = ++ mdp->motion_threshold >> 1; ++ go->modet[mdp->region].mb_threshold = ++ mdp->trigger >> 1; ++ go->modet[mdp->region].enable = 1; ++ } else ++ go->modet[mdp->region].enable = 0; ++ /* fall-through */ ++ } ++ case GO7007IOC_G_MD_PARAMS: ++ { ++ struct go7007_md_params *mdp = arg; ++ int region = mdp->region; ++ ++ if (mdp->region > 3) ++ return -EINVAL; ++ memset(mdp, 0, sizeof(struct go7007_md_params)); ++ mdp->region = region; ++ if (!go->modet[region].enable) ++ return 0; ++ mdp->pixel_threshold = ++ (go->modet[region].pixel_threshold << 1) + 1; ++ mdp->motion_threshold = ++ (go->modet[region].motion_threshold << 1) + 1; ++ mdp->trigger = ++ (go->modet[region].mb_threshold << 1) + 1; ++ return 0; ++ } ++ case GO7007IOC_S_MD_REGION: ++ { ++ struct go7007_md_region *region = arg; ++ ++ if (region->region < 1 || region->region > 3) ++ return -EINVAL; ++ return clip_to_modet_map(go, region->region, region->clips); ++ } ++ default: ++ printk(KERN_DEBUG "go7007: unsupported ioctl %d\n", cmd); ++ return -ENOIOCTLCMD; ++ } ++ return 0; ++ ++unlock_and_return: ++ up(&gofh->lock); ++ return retval; ++} ++ ++static int go7007_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct go7007_file *gofh = file->private_data; ++ ++ if (gofh->go->status != STATUS_ONLINE) ++ return -EIO; ++ ++ return video_usercopy(inode, file, cmd, arg, go7007_do_ioctl); ++} ++ ++static ssize_t go7007_read(struct file *file, char __user *data, ++ size_t count, loff_t *ppos) ++{ ++ return -EINVAL; ++} ++ ++static void go7007_vm_open(struct vm_area_struct *vma) ++{ ++ struct go7007_buffer *gobuf = vma->vm_private_data; ++ ++ ++gobuf->mapped; ++} ++ ++static void go7007_vm_close(struct vm_area_struct *vma) ++{ ++ struct go7007_buffer *gobuf = vma->vm_private_data; ++ unsigned long flags; ++ ++ if (--gobuf->mapped == 0) { ++ spin_lock_irqsave(&gobuf->go->spinlock, flags); ++ deactivate_buffer(gobuf); ++ spin_unlock_irqrestore(&gobuf->go->spinlock, flags); ++ } ++} ++ ++/* Copied from videobuf-dma-sg.c */ ++static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ struct page *page; ++ ++ page = alloc_page(GFP_USER | __GFP_DMA32); ++ if (!page) ++ return VM_FAULT_OOM; ++ clear_user_page(page_address(page), (unsigned long)vmf->virtual_address, ++ page); ++ vmf->page = page; ++ return 0; ++} ++ ++static struct vm_operations_struct go7007_vm_ops = { ++ .open = go7007_vm_open, ++ .close = go7007_vm_close, ++ .fault = go7007_vm_fault, ++}; ++ ++static int go7007_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct go7007_file *gofh = file->private_data; ++ unsigned int index; ++ ++ if (gofh->go->status != STATUS_ONLINE) ++ return -EIO; ++ if (!(vma->vm_flags & VM_SHARED)) ++ return -EINVAL; /* only support VM_SHARED mapping */ ++ if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE) ++ return -EINVAL; /* must map exactly one full buffer */ ++ down(&gofh->lock); ++ index = vma->vm_pgoff / GO7007_BUF_PAGES; ++ if (index >= gofh->buf_count) { ++ up(&gofh->lock); ++ return -EINVAL; /* trying to map beyond requested buffers */ ++ } ++ if (index * GO7007_BUF_PAGES != vma->vm_pgoff) { ++ up(&gofh->lock); ++ return -EINVAL; /* offset is not aligned on buffer boundary */ ++ } ++ if (gofh->bufs[index].mapped > 0) { ++ up(&gofh->lock); ++ return -EBUSY; ++ } ++ gofh->bufs[index].mapped = 1; ++ gofh->bufs[index].user_addr = vma->vm_start; ++ vma->vm_ops = &go7007_vm_ops; ++ vma->vm_flags |= VM_DONTEXPAND; ++ vma->vm_flags &= ~VM_IO; ++ vma->vm_private_data = &gofh->bufs[index]; ++ up(&gofh->lock); ++ return 0; ++} ++ ++static unsigned int go7007_poll(struct file *file, poll_table *wait) ++{ ++ struct go7007_file *gofh = file->private_data; ++ struct go7007_buffer *gobuf; ++ ++ if (list_empty(&gofh->go->stream)) ++ return POLLERR; ++ gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream); ++ poll_wait(file, &gofh->go->frame_waitq, wait); ++ if (gobuf->state == BUF_STATE_DONE) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++static void go7007_vfl_release(struct video_device *vfd) ++{ ++ struct go7007 *go = video_get_drvdata(vfd); ++ ++ video_device_release(vfd); ++ if (--go->ref_count == 0) ++ kfree(go); ++} ++ ++static struct file_operations go7007_fops = { ++ .owner = THIS_MODULE, ++ .open = go7007_open, ++ .release = go7007_release, ++ .ioctl = go7007_ioctl, ++ .llseek = no_llseek, ++ .read = go7007_read, ++ .mmap = go7007_mmap, ++ .poll = go7007_poll, ++}; ++ ++static struct video_device go7007_template = { ++ .name = "go7007", ++ .fops = &go7007_fops, ++ .minor = -1, ++ .release = go7007_vfl_release, ++}; ++ ++int go7007_v4l2_init(struct go7007 *go) ++{ ++ int rv; ++ ++ go->video_dev = video_device_alloc(); ++ if (go->video_dev == NULL) ++ return -ENOMEM; ++ memcpy(go->video_dev, &go7007_template, sizeof(go7007_template)); ++ go->video_dev->parent = go->dev; ++ rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); ++ if (rv < 0) { ++ video_device_release(go->video_dev); ++ go->video_dev = NULL; ++ return rv; ++ } ++ video_set_drvdata(go->video_dev, go); ++ ++go->ref_count; ++ ++ return 0; ++} ++ ++void go7007_v4l2_remove(struct go7007 *go) ++{ ++ unsigned long flags; ++ ++ down(&go->hw_lock); ++ if (go->streaming) { ++ go->streaming = 0; ++ go7007_stream_stop(go); ++ spin_lock_irqsave(&go->spinlock, flags); ++ abort_queued(go); ++ spin_unlock_irqrestore(&go->spinlock, flags); ++ } ++ up(&go->hw_lock); ++ if (go->video_dev) ++ video_unregister_device(go->video_dev); ++} +diff --git a/drivers/staging/go7007/go7007.h b/drivers/staging/go7007/go7007.h +new file mode 100644 +index 0000000..7399c91 +--- /dev/null ++++ b/drivers/staging/go7007/go7007.h +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and the associated README documentation file (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS ++ * to select between MPEG1, MPEG2, and MPEG4 */ ++#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */ ++ ++/* These will be replaced with a better interface ++ * soon, so don't get too attached to them */ ++#define GO7007IOC_S_BITRATE _IOW('V', BASE_VIDIOC_PRIVATE + 0, int) ++#define GO7007IOC_G_BITRATE _IOR('V', BASE_VIDIOC_PRIVATE + 1, int) ++ ++enum go7007_aspect_ratio { ++ GO7007_ASPECT_RATIO_1_1 = 0, ++ GO7007_ASPECT_RATIO_4_3_NTSC = 1, ++ GO7007_ASPECT_RATIO_4_3_PAL = 2, ++ GO7007_ASPECT_RATIO_16_9_NTSC = 3, ++ GO7007_ASPECT_RATIO_16_9_PAL = 4, ++}; ++ ++/* Used to set generic compression parameters */ ++struct go7007_comp_params { ++ __u32 gop_size; ++ __u32 max_b_frames; ++ enum go7007_aspect_ratio aspect_ratio; ++ __u32 flags; ++ __u32 reserved[8]; ++}; ++ ++#define GO7007_COMP_CLOSED_GOP 0x00000001 ++#define GO7007_COMP_OMIT_SEQ_HEADER 0x00000002 ++ ++enum go7007_mpeg_video_standard { ++ GO7007_MPEG_VIDEO_MPEG1 = 0, ++ GO7007_MPEG_VIDEO_MPEG2 = 1, ++ GO7007_MPEG_VIDEO_MPEG4 = 2, ++}; ++ ++/* Used to set parameters for V4L2_PIX_FMT_MPEG format */ ++struct go7007_mpeg_params { ++ enum go7007_mpeg_video_standard mpeg_video_standard; ++ __u32 flags; ++ __u32 pali; ++ __u32 reserved[8]; ++}; ++ ++#define GO7007_MPEG_FORCE_DVD_MODE 0x00000001 ++#define GO7007_MPEG_OMIT_GOP_HEADER 0x00000002 ++#define GO7007_MPEG_REPEAT_SEQHEADER 0x00000004 ++ ++#define GO7007_MPEG_PROFILE(format, pali) (((format)<<24)|(pali)) ++ ++#define GO7007_MPEG2_PROFILE_MAIN_MAIN GO7007_MPEG_PROFILE(2, 0x48) ++ ++#define GO7007_MPEG4_PROFILE_S_L0 GO7007_MPEG_PROFILE(4, 0x08) ++#define GO7007_MPEG4_PROFILE_S_L1 GO7007_MPEG_PROFILE(4, 0x01) ++#define GO7007_MPEG4_PROFILE_S_L2 GO7007_MPEG_PROFILE(4, 0x02) ++#define GO7007_MPEG4_PROFILE_S_L3 GO7007_MPEG_PROFILE(4, 0x03) ++#define GO7007_MPEG4_PROFILE_ARTS_L1 GO7007_MPEG_PROFILE(4, 0x91) ++#define GO7007_MPEG4_PROFILE_ARTS_L2 GO7007_MPEG_PROFILE(4, 0x92) ++#define GO7007_MPEG4_PROFILE_ARTS_L3 GO7007_MPEG_PROFILE(4, 0x93) ++#define GO7007_MPEG4_PROFILE_ARTS_L4 GO7007_MPEG_PROFILE(4, 0x94) ++#define GO7007_MPEG4_PROFILE_AS_L0 GO7007_MPEG_PROFILE(4, 0xf0) ++#define GO7007_MPEG4_PROFILE_AS_L1 GO7007_MPEG_PROFILE(4, 0xf1) ++#define GO7007_MPEG4_PROFILE_AS_L2 GO7007_MPEG_PROFILE(4, 0xf2) ++#define GO7007_MPEG4_PROFILE_AS_L3 GO7007_MPEG_PROFILE(4, 0xf3) ++#define GO7007_MPEG4_PROFILE_AS_L4 GO7007_MPEG_PROFILE(4, 0xf4) ++#define GO7007_MPEG4_PROFILE_AS_L5 GO7007_MPEG_PROFILE(4, 0xf5) ++ ++struct go7007_md_params { ++ __u16 region; ++ __u16 trigger; ++ __u16 pixel_threshold; ++ __u16 motion_threshold; ++ __u32 reserved[8]; ++}; ++ ++struct go7007_md_region { ++ __u16 region; ++ __u16 flags; ++ struct v4l2_clip *clips; ++ __u32 reserved[8]; ++}; ++ ++#define GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \ ++ struct go7007_mpeg_params) ++#define GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \ ++ struct go7007_mpeg_params) ++#define GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \ ++ struct go7007_comp_params) ++#define GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \ ++ struct go7007_comp_params) ++#define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \ ++ struct go7007_md_params) ++#define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \ ++ struct go7007_md_params) ++#define GO7007IOC_S_MD_REGION _IOW('V', BASE_VIDIOC_PRIVATE + 8, \ ++ struct go7007_md_region) +diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/go7007/saa7134-go7007.c +new file mode 100644 +index 0000000..c4a6d8e +--- /dev/null ++++ b/drivers/staging/go7007/saa7134-go7007.c +@@ -0,0 +1,484 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "saa7134-reg.h" ++#include "saa7134.h" ++#include "go7007-priv.h" ++ ++#define GO7007_HPI_DEBUG ++ ++enum hpi_address { ++ HPI_ADDR_VIDEO_BUFFER = 0xe4, ++ HPI_ADDR_INIT_BUFFER = 0xea, ++ HPI_ADDR_INTR_RET_VALUE = 0xee, ++ HPI_ADDR_INTR_RET_DATA = 0xec, ++ HPI_ADDR_INTR_STATUS = 0xf4, ++ HPI_ADDR_INTR_WR_PARAM = 0xf6, ++ HPI_ADDR_INTR_WR_INDEX = 0xf8, ++}; ++ ++enum gpio_command { ++ GPIO_COMMAND_RESET = 0x00, /* 000b */ ++ GPIO_COMMAND_REQ1 = 0x04, /* 001b */ ++ GPIO_COMMAND_WRITE = 0x20, /* 010b */ ++ GPIO_COMMAND_REQ2 = 0x24, /* 011b */ ++ GPIO_COMMAND_READ = 0x80, /* 100b */ ++ GPIO_COMMAND_VIDEO = 0x84, /* 101b */ ++ GPIO_COMMAND_IDLE = 0xA0, /* 110b */ ++ GPIO_COMMAND_ADDR = 0xA4, /* 111b */ ++}; ++ ++struct saa7134_go7007 { ++ struct saa7134_dev *dev; ++ u8 *top; ++ u8 *bottom; ++ dma_addr_t top_dma; ++ dma_addr_t bottom_dma; ++}; ++ ++static struct go7007_board_info board_voyager = { ++ .firmware = "go7007tv.bin", ++ .flags = 0, ++ .sensor_flags = GO7007_SENSOR_656 | ++ GO7007_SENSOR_VALID_ENABLE | ++ GO7007_SENSOR_TV | ++ GO7007_SENSOR_VBI, ++ .audio_flags = GO7007_AUDIO_I2S_MODE_1 | ++ GO7007_AUDIO_WORD_16, ++ .audio_rate = 48000, ++ .audio_bclk_div = 8, ++ .audio_main_div = 2, ++ .hpi_buffer_cap = 7, ++ .num_inputs = 1, ++ .inputs = { ++ { ++ .name = "SAA7134", ++ }, ++ }, ++}; ++ ++/********************* Driver for GPIO HPI interface *********************/ ++ ++static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data) ++{ ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); ++ ++ /* Write HPI address */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++ /* Write low byte */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++ /* Write high byte */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++ return 0; ++} ++ ++static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data) ++{ ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); ++ ++ /* Write HPI address */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); ++ ++ /* Read low byte */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); ++ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ *data = saa_readb(SAA7134_GPIO_GPSTATUS0); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++ /* Read high byte */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); ++ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8; ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++ return 0; ++} ++ ++static int saa7134_go7007_interface_reset(struct go7007 *go) ++{ ++ struct saa7134_go7007 *saa = go->hpi_context; ++ struct saa7134_dev *dev = saa->dev; ++ u32 status; ++ u16 intr_val, intr_data; ++ int count = 20; ++ ++ saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */ ++ saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4); ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); ++ ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET); ++ msleep(1); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); ++ msleep(10); ++ ++ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ ++ status = saa_readb(SAA7134_GPIO_GPSTATUS2); ++ /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */ ++ ++ /* enter command mode...(?) */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); ++ ++ do { ++ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); ++ status = saa_readb(SAA7134_GPIO_GPSTATUS2); ++ /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ ++ } while (--count > 0); ++ ++ /* Wait for an interrupt to indicate successful hardware reset */ ++ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || ++ (intr_val & ~0x1) != 0x55aa) { ++ printk(KERN_ERR ++ "saa7134-go7007: unable to reset the GO7007\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data) ++{ ++ struct saa7134_go7007 *saa = go->hpi_context; ++ struct saa7134_dev *dev = saa->dev; ++ int i; ++ u16 status_reg; ++ ++#ifdef GO7007_HPI_DEBUG ++ printk(KERN_DEBUG ++ "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data); ++#endif ++ ++ for (i = 0; i < 100; ++i) { ++ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); ++ if (!(status_reg & 0x0010)) ++ break; ++ msleep(10); ++ } ++ if (i == 100) { ++ printk(KERN_ERR ++ "saa7134-go7007: device is hung, status reg = 0x%04x\n", ++ status_reg); ++ return -1; ++ } ++ gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data); ++ gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr); ++ ++ return 0; ++} ++ ++static int saa7134_go7007_read_interrupt(struct go7007 *go) ++{ ++ struct saa7134_go7007 *saa = go->hpi_context; ++ struct saa7134_dev *dev = saa->dev; ++ ++ /* XXX we need to wait if there is no interrupt available */ ++ go->interrupt_available = 1; ++ gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value); ++ gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data); ++#ifdef GO7007_HPI_DEBUG ++ printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n", ++ go->interrupt_value, go->interrupt_data); ++#endif ++ return 0; ++} ++ ++static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, ++ unsigned long status) ++{ ++ struct go7007 *go = video_get_drvdata(dev->empress_dev); ++ struct saa7134_go7007 *saa = go->hpi_context; ++ ++ if (!go->streaming) ++ return; ++ if (0 != (status & 0x000f0000)) ++ printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n", ++ (status >> 16) & 0x0f); ++ if (status & 0x100000) { ++ dma_sync_single(&dev->pci->dev, ++ saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); ++ go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); ++ saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); ++ } else { ++ dma_sync_single(&dev->pci->dev, ++ saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); ++ go7007_parse_video_stream(go, saa->top, PAGE_SIZE); ++ saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); ++ } ++} ++ ++static int saa7134_go7007_stream_start(struct go7007 *go) ++{ ++ struct saa7134_go7007 *saa = go->hpi_context; ++ struct saa7134_dev *dev = saa->dev; ++ ++ saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), ++ 0, PAGE_SIZE, DMA_FROM_DEVICE); ++ if (!saa->top_dma) ++ return -ENOMEM; ++ saa->bottom_dma = dma_map_page(&dev->pci->dev, ++ virt_to_page(saa->bottom), ++ 0, PAGE_SIZE, DMA_FROM_DEVICE); ++ if (!saa->bottom_dma) { ++ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, ++ DMA_FROM_DEVICE); ++ return -ENOMEM; ++ } ++ ++ saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000); ++ saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200); ++ ++ /* Set HPI interface for video */ ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); ++ ++ /* Enable TS interface */ ++ saa_writeb(SAA7134_TS_PARALLEL, 0xe6); ++ ++ /* Reset TS interface */ ++ saa_setb(SAA7134_TS_SERIAL1, 0x01); ++ saa_clearb(SAA7134_TS_SERIAL1, 0x01); ++ ++ /* Set up transfer block size */ ++ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); ++ saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); ++ saa_writeb(SAA7134_TS_DMA1, 0); ++ saa_writeb(SAA7134_TS_DMA2, 0); ++ ++ /* Enable video streaming mode */ ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); ++ ++ saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); ++ saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); ++ saa_writel(SAA7134_RS_PITCH(5), 128); ++ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); ++ ++ /* Enable TS FIFO */ ++ saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); ++ ++ /* Enable DMA IRQ */ ++ saa_setl(SAA7134_IRQ1, ++ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); ++ ++ return 0; ++} ++ ++static int saa7134_go7007_stream_stop(struct go7007 *go) ++{ ++ struct saa7134_go7007 *saa = go->hpi_context; ++ struct saa7134_dev *dev = saa->dev; ++ ++ /* Shut down TS FIFO */ ++ saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); ++ ++ /* Disable DMA IRQ */ ++ saa_clearl(SAA7134_IRQ1, ++ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); ++ ++ /* Disable TS interface */ ++ saa_clearb(SAA7134_TS_PARALLEL, 0x80); ++ ++ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, ++ DMA_FROM_DEVICE); ++ dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, ++ DMA_FROM_DEVICE); ++ ++ return 0; ++} ++ ++static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) ++{ ++ struct saa7134_go7007 *saa = go->hpi_context; ++ struct saa7134_dev *dev = saa->dev; ++ u16 status_reg; ++ int i; ++ ++#ifdef GO7007_HPI_DEBUG ++ printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer " ++ "sending %d bytes\n", len); ++#endif ++ ++ while (len > 0) { ++ i = len > 64 ? 64 : len; ++ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ while (i-- > 0) { ++ saa_writeb(SAA7134_GPIO_GPSTATUS0, *data); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); ++ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); ++ ++data; ++ --len; ++ } ++ for (i = 0; i < 100; ++i) { ++ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); ++ if (!(status_reg & 0x0002)) ++ break; ++ } ++ if (i == 100) { ++ printk(KERN_ERR "saa7134-go7007: device is hung, " ++ "status reg = 0x%04x\n", status_reg); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { ++ .interface_reset = saa7134_go7007_interface_reset, ++ .write_interrupt = saa7134_go7007_write_interrupt, ++ .read_interrupt = saa7134_go7007_read_interrupt, ++ .stream_start = saa7134_go7007_stream_start, ++ .stream_stop = saa7134_go7007_stream_stop, ++ .send_firmware = saa7134_go7007_send_firmware, ++}; ++ ++/********************* Add/remove functions *********************/ ++ ++static int saa7134_go7007_init(struct saa7134_dev *dev) ++{ ++ struct go7007 *go; ++ struct saa7134_go7007 *saa; ++ ++ printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n"); ++ ++ saa = kmalloc(sizeof(struct saa7134_go7007), GFP_KERNEL); ++ if (saa == NULL) ++ return -ENOMEM; ++ memset(saa, 0, sizeof(struct saa7134_go7007)); ++ ++ /* Allocate a couple pages for receiving the compressed stream */ ++ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); ++ if (!saa->top) ++ goto allocfail; ++ saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL); ++ if (!saa->bottom) ++ goto allocfail; ++ ++ go = go7007_alloc(&board_voyager, &dev->pci->dev); ++ if (go == NULL) ++ goto allocfail; ++ go->board_id = GO7007_BOARDID_PCI_VOYAGER; ++ strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); ++ go->hpi_ops = &saa7134_go7007_hpi_ops; ++ go->hpi_context = saa; ++ saa->dev = dev; ++ ++ /* Boot the GO7007 */ ++ if (go7007_boot_encoder(go, go->board_info->flags & ++ GO7007_BOARD_USE_ONBOARD_I2C) < 0) ++ goto initfail; ++ ++ /* Do any final GO7007 initialization, then register the ++ * V4L2 and ALSA interfaces */ ++ if (go7007_register_encoder(go) < 0) ++ goto initfail; ++ dev->empress_dev = go->video_dev; ++ video_set_drvdata(dev->empress_dev, go); ++ ++ go->status = STATUS_ONLINE; ++ return 0; ++ ++initfail: ++ go->status = STATUS_SHUTDOWN; ++ return 0; ++ ++allocfail: ++ if (saa->top) ++ free_page((unsigned long)saa->top); ++ if (saa->bottom) ++ free_page((unsigned long)saa->bottom); ++ kfree(saa); ++ return -ENOMEM; ++} ++ ++static int saa7134_go7007_fini(struct saa7134_dev *dev) ++{ ++ struct go7007 *go; ++ struct saa7134_go7007 *saa; ++ ++ if (NULL == dev->empress_dev) ++ return 0; ++ ++ go = video_get_drvdata(dev->empress_dev); ++ saa = go->hpi_context; ++ go->status = STATUS_SHUTDOWN; ++ free_page((unsigned long)saa->top); ++ free_page((unsigned long)saa->bottom); ++ kfree(saa); ++ go7007_remove(go); ++ dev->empress_dev = NULL; ++ ++ return 0; ++} ++ ++static struct saa7134_mpeg_ops saa7134_go7007_ops = { ++ .type = SAA7134_MPEG_GO7007, ++ .init = saa7134_go7007_init, ++ .fini = saa7134_go7007_fini, ++ .irq_ts_done = saa7134_go7007_irq_ts_done, ++}; ++ ++static int __init saa7134_go7007_mod_init(void) ++{ ++ return saa7134_ts_register(&saa7134_go7007_ops); ++} ++ ++static void __exit saa7134_go7007_mod_cleanup(void) ++{ ++ saa7134_ts_unregister(&saa7134_go7007_ops); ++} ++ ++module_init(saa7134_go7007_mod_init); ++module_exit(saa7134_go7007_mod_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c +new file mode 100644 +index 0000000..f5cac08 +--- /dev/null ++++ b/drivers/staging/go7007/snd-go7007.c +@@ -0,0 +1,305 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "go7007-priv.h" ++ ++static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; ++static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; ++static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; ++ ++module_param_array(index, int, NULL, 0444); ++module_param_array(id, charp, NULL, 0444); ++module_param_array(enable, bool, NULL, 0444); ++MODULE_PARM_DESC(index, "Index value for the go7007 audio driver"); ++MODULE_PARM_DESC(index, "ID string for the go7007 audio driver"); ++MODULE_PARM_DESC(index, "Enable for the go7007 audio driver"); ++ ++struct go7007_snd { ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ struct snd_pcm_substream *substream; ++ spinlock_t lock; ++ int w_idx; ++ int hw_ptr; ++ int avail; ++ int capturing; ++}; ++ ++static struct snd_pcm_hardware go7007_snd_capture_hw = { ++ .info = (SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_BLOCK_TRANSFER | ++ SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .rates = SNDRV_PCM_RATE_48000, ++ .rate_min = 48000, ++ .rate_max = 48000, ++ .channels_min = 2, ++ .channels_max = 2, ++ .buffer_bytes_max = (128*1024), ++ .period_bytes_min = 4096, ++ .period_bytes_max = (128*1024), ++ .periods_min = 1, ++ .periods_max = 32, ++}; ++ ++static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length) ++{ ++ struct go7007_snd *gosnd = go->snd_context; ++ struct snd_pcm_runtime *runtime = gosnd->substream->runtime; ++ int frames = bytes_to_frames(runtime, length); ++ ++ spin_lock(&gosnd->lock); ++ gosnd->hw_ptr += frames; ++ if (gosnd->hw_ptr >= runtime->buffer_size) ++ gosnd->hw_ptr -= runtime->buffer_size; ++ gosnd->avail += frames; ++ spin_unlock(&gosnd->lock); ++ if (gosnd->w_idx + length > runtime->dma_bytes) { ++ int cpy = runtime->dma_bytes - gosnd->w_idx; ++ ++ memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy); ++ length -= cpy; ++ buf += cpy; ++ gosnd->w_idx = 0; ++ } ++ memcpy(runtime->dma_area + gosnd->w_idx, buf, length); ++ gosnd->w_idx += length; ++ spin_lock(&gosnd->lock); ++ if (gosnd->avail < runtime->period_size) { ++ spin_unlock(&gosnd->lock); ++ return; ++ } ++ gosnd->avail -= runtime->period_size; ++ spin_unlock(&gosnd->lock); ++ if (gosnd->capturing) ++ snd_pcm_period_elapsed(gosnd->substream); ++} ++ ++static int go7007_snd_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params) ++{ ++ struct go7007 *go = snd_pcm_substream_chip(substream); ++ unsigned int bytes; ++ ++ bytes = params_buffer_bytes(hw_params); ++ if (substream->runtime->dma_bytes > 0) ++ vfree(substream->runtime->dma_area); ++ substream->runtime->dma_bytes = 0; ++ substream->runtime->dma_area = vmalloc(bytes); ++ if (substream->runtime->dma_area == NULL) ++ return -ENOMEM; ++ substream->runtime->dma_bytes = bytes; ++ go->audio_deliver = parse_audio_stream_data; ++ return 0; ++} ++ ++static int go7007_snd_hw_free(struct snd_pcm_substream *substream) ++{ ++ struct go7007 *go = snd_pcm_substream_chip(substream); ++ ++ go->audio_deliver = NULL; ++ if (substream->runtime->dma_bytes > 0) ++ vfree(substream->runtime->dma_area); ++ substream->runtime->dma_bytes = 0; ++ return 0; ++} ++ ++static int go7007_snd_capture_open(struct snd_pcm_substream *substream) ++{ ++ struct go7007 *go = snd_pcm_substream_chip(substream); ++ struct go7007_snd *gosnd = go->snd_context; ++ unsigned long flags; ++ int r; ++ ++ spin_lock_irqsave(&gosnd->lock, flags); ++ if (gosnd->substream == NULL) { ++ gosnd->substream = substream; ++ substream->runtime->hw = go7007_snd_capture_hw; ++ r = 0; ++ } else ++ r = -EBUSY; ++ spin_unlock_irqrestore(&gosnd->lock, flags); ++ return r; ++} ++ ++static int go7007_snd_capture_close(struct snd_pcm_substream *substream) ++{ ++ struct go7007 *go = snd_pcm_substream_chip(substream); ++ struct go7007_snd *gosnd = go->snd_context; ++ ++ gosnd->substream = NULL; ++ return 0; ++} ++ ++static int go7007_snd_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ return 0; ++} ++ ++static int go7007_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct go7007 *go = snd_pcm_substream_chip(substream); ++ struct go7007_snd *gosnd = go->snd_context; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ /* Just set a flag to indicate we should signal ALSA when ++ * sound comes in */ ++ gosnd->capturing = 1; ++ return 0; ++ case SNDRV_PCM_TRIGGER_STOP: ++ gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0; ++ gosnd->capturing = 0; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substream) ++{ ++ struct go7007 *go = snd_pcm_substream_chip(substream); ++ struct go7007_snd *gosnd = go->snd_context; ++ ++ return gosnd->hw_ptr; ++} ++ ++static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream, ++ unsigned long offset) ++{ ++ return vmalloc_to_page(substream->runtime->dma_area + offset); ++} ++ ++static struct snd_pcm_ops go7007_snd_capture_ops = { ++ .open = go7007_snd_capture_open, ++ .close = go7007_snd_capture_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = go7007_snd_hw_params, ++ .hw_free = go7007_snd_hw_free, ++ .prepare = go7007_snd_pcm_prepare, ++ .trigger = go7007_snd_pcm_trigger, ++ .pointer = go7007_snd_pcm_pointer, ++ .page = go7007_snd_pcm_page, ++}; ++ ++static int go7007_snd_free(struct snd_device *device) ++{ ++ struct go7007 *go = device->device_data; ++ ++ kfree(go->snd_context); ++ go->snd_context = NULL; ++ if (--go->ref_count == 0) ++ kfree(go); ++ return 0; ++} ++ ++static struct snd_device_ops go7007_snd_device_ops = { ++ .dev_free = go7007_snd_free, ++}; ++ ++int go7007_snd_init(struct go7007 *go) ++{ ++ static int dev; ++ struct go7007_snd *gosnd; ++ int ret = 0; ++ ++ if (dev >= SNDRV_CARDS) ++ return -ENODEV; ++ if (!enable[dev]) { ++ dev++; ++ return -ENOENT; ++ } ++ gosnd = kmalloc(sizeof(struct go7007_snd), GFP_KERNEL); ++ if (gosnd == NULL) ++ return -ENOMEM; ++ spin_lock_init(&gosnd->lock); ++ gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0; ++ gosnd->capturing = 0; ++ gosnd->card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); ++ if (gosnd->card == NULL) { ++ kfree(gosnd); ++ return -ENOMEM; ++ } ++ ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go, ++ &go7007_snd_device_ops); ++ if (ret < 0) { ++ kfree(gosnd); ++ return ret; ++ } ++ snd_card_set_dev(gosnd->card, go->dev); ++ ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm); ++ if (ret < 0) { ++ snd_card_free(gosnd->card); ++ kfree(gosnd); ++ return ret; ++ } ++ strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver)); ++ strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver)); ++ strncpy(gosnd->card->longname, gosnd->card->shortname, ++ sizeof(gosnd->card->longname)); ++ ++ gosnd->pcm->private_data = go; ++ snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE, ++ &go7007_snd_capture_ops); ++ ++ ret = snd_card_register(gosnd->card); ++ if (ret < 0) { ++ snd_card_free(gosnd->card); ++ kfree(gosnd); ++ return ret; ++ } ++ ++ gosnd->substream = NULL; ++ go->snd_context = gosnd; ++ ++dev; ++ ++go->ref_count; ++ ++ return 0; ++} ++EXPORT_SYMBOL(go7007_snd_init); ++ ++int go7007_snd_remove(struct go7007 *go) ++{ ++ struct go7007_snd *gosnd = go->snd_context; ++ ++ snd_card_disconnect(gosnd->card); ++ snd_card_free_when_closed(gosnd->card); ++ return 0; ++} ++EXPORT_SYMBOL(go7007_snd_remove); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/go7007/wis-i2c.h +new file mode 100644 +index 0000000..993f658 +--- /dev/null ++++ b/drivers/staging/go7007/wis-i2c.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++/* Temporary I2C IDs -- these need to be replaced with real registered IDs */ ++#define I2C_DRIVERID_WIS_SAA7115 0xf0f0 ++#define I2C_DRIVERID_WIS_UDA1342 0xf0f1 ++#define I2C_DRIVERID_WIS_SONY_TUNER 0xf0f2 ++#define I2C_DRIVERID_WIS_TW9903 0xf0f3 ++#define I2C_DRIVERID_WIS_SAA7113 0xf0f4 ++#define I2C_DRIVERID_WIS_OV7640 0xf0f5 ++#define I2C_DRIVERID_WIS_TW2804 0xf0f6 ++#define I2C_ALGO_GO7007 0xf00000 ++#define I2C_ALGO_GO7007_USB 0xf10000 ++ ++/* Flag to indicate that the client needs to be accessed with SCCB semantics */ ++/* We re-use the I2C_M_TEN value so the flag passes through the masks in the ++ * core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */ ++#define I2C_CLIENT_SCCB 0x10 ++ ++typedef int (*found_proc) (struct i2c_adapter *, int, int); ++int wis_i2c_add_driver(unsigned int id, found_proc found_proc); ++void wis_i2c_del_driver(found_proc found_proc); ++ ++int wis_i2c_probe_device(struct i2c_adapter *adapter, ++ unsigned int id, int addr); ++ ++/* Definitions for new video decoder commands */ ++ ++struct video_decoder_resolution { ++ unsigned int width; ++ unsigned int height; ++}; ++ ++#define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution) ++#define DECODER_SET_CHANNEL _IOW('d', 201, int) ++ ++/* Sony tuner types */ ++ ++#define TUNER_SONY_BTF_PG472Z 200 ++#define TUNER_SONY_BTF_PK467Z 201 ++#define TUNER_SONY_BTF_PB463Z 202 +diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c +new file mode 100644 +index 0000000..815615a +--- /dev/null ++++ b/drivers/staging/go7007/wis-ov7640.c +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++struct wis_ov7640 { ++ int brightness; ++ int contrast; ++ int saturation; ++ int hue; ++}; ++ ++static u8 initial_registers[] = ++{ ++ 0x12, 0x80, ++ 0x12, 0x54, ++ 0x14, 0x24, ++ 0x15, 0x01, ++ 0x28, 0x20, ++ 0x75, 0x82, ++ 0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */ ++}; ++ ++static int write_regs(struct i2c_client *client, u8 *regs) ++{ ++ int i; ++ ++ for (i = 0; regs[i] != 0xFF; i += 2) ++ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) ++ return -1; ++ return 0; ++} ++ ++static struct i2c_driver wis_ov7640_driver; ++ ++static struct i2c_client wis_ov7640_client_templ = { ++ .name = "OV7640 (WIS)", ++ .driver = &wis_ov7640_driver, ++}; ++ ++static int wis_ov7640_detect(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct i2c_client *client; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_ov7640_client_templ, ++ sizeof(wis_ov7640_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ client->flags = I2C_CLIENT_SCCB; ++ ++ printk(KERN_DEBUG ++ "wis-ov7640: initializing OV7640 at address %d on %s\n", ++ addr, adapter->name); ++ ++ if (write_regs(client, initial_registers) < 0) { ++ printk(KERN_ERR "wis-ov7640: error initializing OV7640\n"); ++ kfree(client); ++ return 0; ++ } ++ ++ i2c_attach_client(client); ++ return 0; ++} ++ ++static int wis_ov7640_detach(struct i2c_client *client) ++{ ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(client); ++ return 0; ++} ++ ++static struct i2c_driver wis_ov7640_driver = { ++ .driver = { ++ .name = "WIS OV7640 I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_OV7640, ++ .detach_client = wis_ov7640_detach, ++}; ++ ++static int __init wis_ov7640_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_ov7640_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_ov7640_driver.id, wis_ov7640_detect); ++} ++ ++static void __exit wis_ov7640_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_ov7640_detect); ++ i2c_del_driver(&wis_ov7640_driver); ++} ++ ++module_init(wis_ov7640_init); ++module_exit(wis_ov7640_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c +new file mode 100644 +index 0000000..4b14ca8 +--- /dev/null ++++ b/drivers/staging/go7007/wis-saa7113.c +@@ -0,0 +1,363 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++struct wis_saa7113 { ++ int norm; ++ int brightness; ++ int contrast; ++ int saturation; ++ int hue; ++}; ++ ++static u8 initial_registers[] = ++{ ++ 0x01, 0x08, ++ 0x02, 0xc0, ++ 0x03, 0x33, ++ 0x04, 0x00, ++ 0x05, 0x00, ++ 0x06, 0xe9, ++ 0x07, 0x0d, ++ 0x08, 0xd8, ++ 0x09, 0x40, ++ 0x0a, 0x80, ++ 0x0b, 0x47, ++ 0x0c, 0x40, ++ 0x0d, 0x00, ++ 0x0e, 0x01, ++ 0x0f, 0x2a, ++ 0x10, 0x40, ++ 0x11, 0x0c, ++ 0x12, 0xfe, ++ 0x13, 0x00, ++ 0x14, 0x00, ++ 0x15, 0x04, ++ 0x16, 0x00, ++ 0x17, 0x00, ++ 0x18, 0x00, ++ 0x19, 0x00, ++ 0x1a, 0x00, ++ 0x1b, 0x00, ++ 0x1c, 0x00, ++ 0x1d, 0x00, ++ 0x1e, 0x00, ++ 0x1f, 0xc8, ++ 0x40, 0x00, ++ 0x41, 0xff, ++ 0x42, 0xff, ++ 0x43, 0xff, ++ 0x44, 0xff, ++ 0x45, 0xff, ++ 0x46, 0xff, ++ 0x47, 0xff, ++ 0x48, 0xff, ++ 0x49, 0xff, ++ 0x4a, 0xff, ++ 0x4b, 0xff, ++ 0x4c, 0xff, ++ 0x4d, 0xff, ++ 0x4e, 0xff, ++ 0x4f, 0xff, ++ 0x50, 0xff, ++ 0x51, 0xff, ++ 0x52, 0xff, ++ 0x53, 0xff, ++ 0x54, 0xff, ++ 0x55, 0xff, ++ 0x56, 0xff, ++ 0x57, 0xff, ++ 0x58, 0x00, ++ 0x59, 0x54, ++ 0x5a, 0x07, ++ 0x5b, 0x83, ++ 0x5c, 0x00, ++ 0x5d, 0x00, ++ 0x5e, 0x00, ++ 0x5f, 0x00, ++ 0x60, 0x00, ++ 0x61, 0x00, ++ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ ++}; ++ ++static int write_reg(struct i2c_client *client, u8 reg, u8 value) ++{ ++ return i2c_smbus_write_byte_data(client, reg, value); ++} ++ ++static int write_regs(struct i2c_client *client, u8 *regs) ++{ ++ int i; ++ ++ for (i = 0; regs[i] != 0x00; i += 2) ++ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) ++ return -1; ++ return 0; ++} ++ ++static int wis_saa7113_command(struct i2c_client *client, ++ unsigned int cmd, void *arg) ++{ ++ struct wis_saa7113 *dec = i2c_get_clientdata(client); ++ ++ switch (cmd) { ++ case DECODER_SET_INPUT: ++ { ++ int *input = arg; ++ ++ i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); ++ i2c_smbus_write_byte_data(client, 0x09, ++ *input < 6 ? 0x40 : 0x80); ++ break; ++ } ++ case DECODER_SET_NORM: ++ { ++ int *input = arg; ++ dec->norm = *input; ++ switch (dec->norm) { ++ case VIDEO_MODE_PAL: ++ write_reg(client, 0x0e, 0x01); ++ write_reg(client, 0x10, 0x48); ++ break; ++ case VIDEO_MODE_NTSC: ++ write_reg(client, 0x0e, 0x01); ++ write_reg(client, 0x10, 0x40); ++ break; ++ case VIDEO_MODE_SECAM: ++ write_reg(client, 0x0e, 0x50); ++ write_reg(client, 0x10, 0x48); ++ break; ++ } ++ break; ++ } ++ case VIDIOC_QUERYCTRL: ++ { ++ struct v4l2_queryctrl *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 128; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 71; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_SATURATION: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 64; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_HUE: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); ++ ctrl->minimum = -128; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 0; ++ ctrl->flags = 0; ++ break; ++ } ++ break; ++ } ++ case VIDIOC_S_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ if (ctrl->value > 255) ++ dec->brightness = 255; ++ else if (ctrl->value < 0) ++ dec->brightness = 0; ++ else ++ dec->brightness = ctrl->value; ++ write_reg(client, 0x0a, dec->brightness); ++ break; ++ case V4L2_CID_CONTRAST: ++ if (ctrl->value > 127) ++ dec->contrast = 127; ++ else if (ctrl->value < 0) ++ dec->contrast = 0; ++ else ++ dec->contrast = ctrl->value; ++ write_reg(client, 0x0b, dec->contrast); ++ break; ++ case V4L2_CID_SATURATION: ++ if (ctrl->value > 127) ++ dec->saturation = 127; ++ else if (ctrl->value < 0) ++ dec->saturation = 0; ++ else ++ dec->saturation = ctrl->value; ++ write_reg(client, 0x0c, dec->saturation); ++ break; ++ case V4L2_CID_HUE: ++ if (ctrl->value > 127) ++ dec->hue = 127; ++ else if (ctrl->value < -128) ++ dec->hue = -128; ++ else ++ dec->hue = ctrl->value; ++ write_reg(client, 0x0d, dec->hue); ++ break; ++ } ++ break; ++ } ++ case VIDIOC_G_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->value = dec->brightness; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->value = dec->contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ ctrl->value = dec->saturation; ++ break; ++ case V4L2_CID_HUE: ++ ctrl->value = dec->hue; ++ break; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct i2c_driver wis_saa7113_driver; ++ ++static struct i2c_client wis_saa7113_client_templ = { ++ .name = "SAA7113 (WIS)", ++ .driver = &wis_saa7113_driver, ++}; ++ ++static int wis_saa7113_detect(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct i2c_client *client; ++ struct wis_saa7113 *dec; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_saa7113_client_templ, ++ sizeof(wis_saa7113_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ ++ dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL); ++ if (dec == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ dec->norm = VIDEO_MODE_NTSC; ++ dec->brightness = 128; ++ dec->contrast = 71; ++ dec->saturation = 64; ++ dec->hue = 0; ++ i2c_set_clientdata(client, dec); ++ ++ printk(KERN_DEBUG ++ "wis-saa7113: initializing SAA7113 at address %d on %s\n", ++ addr, adapter->name); ++ ++ if (write_regs(client, initial_registers) < 0) { ++ printk(KERN_ERR ++ "wis-saa7113: error initializing SAA7113\n"); ++ kfree(client); ++ kfree(dec); ++ return 0; ++ } ++ ++ i2c_attach_client(client); ++ return 0; ++} ++ ++static int wis_saa7113_detach(struct i2c_client *client) ++{ ++ struct wis_saa7113 *dec = i2c_get_clientdata(client); ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(client); ++ kfree(dec); ++ return 0; ++} ++ ++static struct i2c_driver wis_saa7113_driver = { ++ .driver = { ++ .name = "WIS SAA7113 I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_SAA7113, ++ .detach_client = wis_saa7113_detach, ++ .command = wis_saa7113_command, ++}; ++ ++static int __init wis_saa7113_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_saa7113_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_saa7113_driver.id, wis_saa7113_detect); ++} ++ ++static void __exit wis_saa7113_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_saa7113_detect); ++ i2c_del_driver(&wis_saa7113_driver); ++} ++ ++module_init(wis_saa7113_init); ++module_exit(wis_saa7113_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c +new file mode 100644 +index 0000000..bd40bf4 +--- /dev/null ++++ b/drivers/staging/go7007/wis-saa7115.c +@@ -0,0 +1,492 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++struct wis_saa7115 { ++ int norm; ++ int brightness; ++ int contrast; ++ int saturation; ++ int hue; ++}; ++ ++static u8 initial_registers[] = ++{ ++ 0x01, 0x08, ++ 0x02, 0xc0, ++ 0x03, 0x20, ++ 0x04, 0x80, ++ 0x05, 0x80, ++ 0x06, 0xeb, ++ 0x07, 0xe0, ++ 0x08, 0xf0, /* always toggle FID */ ++ 0x09, 0x40, ++ 0x0a, 0x80, ++ 0x0b, 0x40, ++ 0x0c, 0x40, ++ 0x0d, 0x00, ++ 0x0e, 0x03, ++ 0x0f, 0x2a, ++ 0x10, 0x0e, ++ 0x11, 0x00, ++ 0x12, 0x8d, ++ 0x13, 0x00, ++ 0x14, 0x00, ++ 0x15, 0x11, ++ 0x16, 0x01, ++ 0x17, 0xda, ++ 0x18, 0x40, ++ 0x19, 0x80, ++ 0x1a, 0x00, ++ 0x1b, 0x42, ++ 0x1c, 0xa9, ++ 0x30, 0x66, ++ 0x31, 0x90, ++ 0x32, 0x01, ++ 0x34, 0x00, ++ 0x35, 0x00, ++ 0x36, 0x20, ++ 0x38, 0x03, ++ 0x39, 0x20, ++ 0x3a, 0x88, ++ 0x40, 0x00, ++ 0x41, 0xff, ++ 0x42, 0xff, ++ 0x43, 0xff, ++ 0x44, 0xff, ++ 0x45, 0xff, ++ 0x46, 0xff, ++ 0x47, 0xff, ++ 0x48, 0xff, ++ 0x49, 0xff, ++ 0x4a, 0xff, ++ 0x4b, 0xff, ++ 0x4c, 0xff, ++ 0x4d, 0xff, ++ 0x4e, 0xff, ++ 0x4f, 0xff, ++ 0x50, 0xff, ++ 0x51, 0xff, ++ 0x52, 0xff, ++ 0x53, 0xff, ++ 0x54, 0xf4 /*0xff*/, ++ 0x55, 0xff, ++ 0x56, 0xff, ++ 0x57, 0xff, ++ 0x58, 0x40, ++ 0x59, 0x47, ++ 0x5a, 0x06 /*0x03*/, ++ 0x5b, 0x83, ++ 0x5d, 0x06, ++ 0x5e, 0x00, ++ 0x80, 0x30, /* window defined scaler operation, task A and B enabled */ ++ 0x81, 0x03, /* use scaler datapath generated V */ ++ 0x83, 0x00, ++ 0x84, 0x00, ++ 0x85, 0x00, ++ 0x86, 0x45, ++ 0x87, 0x31, ++ 0x88, 0xc0, ++ 0x90, 0x02, /* task A process top field */ ++ 0x91, 0x08, ++ 0x92, 0x09, ++ 0x93, 0x80, ++ 0x94, 0x06, ++ 0x95, 0x00, ++ 0x96, 0xc0, ++ 0x97, 0x02, ++ 0x98, 0x12, ++ 0x99, 0x00, ++ 0x9a, 0xf2, ++ 0x9b, 0x00, ++ 0x9c, 0xd0, ++ 0x9d, 0x02, ++ 0x9e, 0xf2, ++ 0x9f, 0x00, ++ 0xa0, 0x01, ++ 0xa1, 0x01, ++ 0xa2, 0x01, ++ 0xa4, 0x80, ++ 0xa5, 0x40, ++ 0xa6, 0x40, ++ 0xa8, 0x00, ++ 0xa9, 0x04, ++ 0xaa, 0x00, ++ 0xac, 0x00, ++ 0xad, 0x02, ++ 0xae, 0x00, ++ 0xb0, 0x00, ++ 0xb1, 0x04, ++ 0xb2, 0x00, ++ 0xb3, 0x04, ++ 0xb4, 0x00, ++ 0xb8, 0x00, ++ 0xbc, 0x00, ++ 0xc0, 0x03, /* task B process bottom field */ ++ 0xc1, 0x08, ++ 0xc2, 0x09, ++ 0xc3, 0x80, ++ 0xc4, 0x06, ++ 0xc5, 0x00, ++ 0xc6, 0xc0, ++ 0xc7, 0x02, ++ 0xc8, 0x12, ++ 0xc9, 0x00, ++ 0xca, 0xf2, ++ 0xcb, 0x00, ++ 0xcc, 0xd0, ++ 0xcd, 0x02, ++ 0xce, 0xf2, ++ 0xcf, 0x00, ++ 0xd0, 0x01, ++ 0xd1, 0x01, ++ 0xd2, 0x01, ++ 0xd4, 0x80, ++ 0xd5, 0x40, ++ 0xd6, 0x40, ++ 0xd8, 0x00, ++ 0xd9, 0x04, ++ 0xda, 0x00, ++ 0xdc, 0x00, ++ 0xdd, 0x02, ++ 0xde, 0x00, ++ 0xe0, 0x00, ++ 0xe1, 0x04, ++ 0xe2, 0x00, ++ 0xe3, 0x04, ++ 0xe4, 0x00, ++ 0xe8, 0x00, ++ 0x88, 0xf0, /* End of original static list */ ++ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ ++}; ++ ++static int write_reg(struct i2c_client *client, u8 reg, u8 value) ++{ ++ return i2c_smbus_write_byte_data(client, reg, value); ++} ++ ++static int write_regs(struct i2c_client *client, u8 *regs) ++{ ++ int i; ++ ++ for (i = 0; regs[i] != 0x00; i += 2) ++ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) ++ return -1; ++ return 0; ++} ++ ++static int wis_saa7115_command(struct i2c_client *client, ++ unsigned int cmd, void *arg) ++{ ++ struct wis_saa7115 *dec = i2c_get_clientdata(client); ++ ++ switch (cmd) { ++ case DECODER_SET_INPUT: ++ { ++ int *input = arg; ++ ++ i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); ++ i2c_smbus_write_byte_data(client, 0x09, ++ *input < 6 ? 0x40 : 0xC0); ++ break; ++ } ++ case DECODER_SET_RESOLUTION: ++ { ++ struct video_decoder_resolution *res = arg; ++ /* Course-grained scaler */ ++ int h_integer_scaler = res->width < 704 ? 704 / res->width : 1; ++ /* Fine-grained scaler to take care of remainder */ ++ int h_scaling_increment = (704 / h_integer_scaler) * ++ 1024 / res->width; ++ /* Fine-grained scaler only */ ++ int v_scaling_increment = (dec->norm == VIDEO_MODE_NTSC ? ++ 240 : 288) * 1024 / res->height; ++ u8 regs[] = { ++ 0x88, 0xc0, ++ 0x9c, res->width & 0xff, ++ 0x9d, res->width >> 8, ++ 0x9e, res->height & 0xff, ++ 0x9f, res->height >> 8, ++ 0xa0, h_integer_scaler, ++ 0xa1, 1, ++ 0xa2, 1, ++ 0xa8, h_scaling_increment & 0xff, ++ 0xa9, h_scaling_increment >> 8, ++ 0xac, (h_scaling_increment / 2) & 0xff, ++ 0xad, (h_scaling_increment / 2) >> 8, ++ 0xb0, v_scaling_increment & 0xff, ++ 0xb1, v_scaling_increment >> 8, ++ 0xb2, v_scaling_increment & 0xff, ++ 0xb3, v_scaling_increment >> 8, ++ 0xcc, res->width & 0xff, ++ 0xcd, res->width >> 8, ++ 0xce, res->height & 0xff, ++ 0xcf, res->height >> 8, ++ 0xd0, h_integer_scaler, ++ 0xd1, 1, ++ 0xd2, 1, ++ 0xd8, h_scaling_increment & 0xff, ++ 0xd9, h_scaling_increment >> 8, ++ 0xdc, (h_scaling_increment / 2) & 0xff, ++ 0xdd, (h_scaling_increment / 2) >> 8, ++ 0xe0, v_scaling_increment & 0xff, ++ 0xe1, v_scaling_increment >> 8, ++ 0xe2, v_scaling_increment & 0xff, ++ 0xe3, v_scaling_increment >> 8, ++ 0x88, 0xf0, ++ 0, 0, ++ }; ++ write_regs(client, regs); ++ break; ++ } ++ case DECODER_SET_NORM: ++ { ++ int *input = arg; ++ u8 regs[] = { ++ 0x88, 0xc0, ++ 0x98, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16, ++ 0x9a, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20, ++ 0x9b, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01, ++ 0xc8, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16, ++ 0xca, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20, ++ 0xcb, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01, ++ 0x88, 0xf0, ++ 0x30, *input == VIDEO_MODE_NTSC ? 0x66 : 0x00, ++ 0x31, *input == VIDEO_MODE_NTSC ? 0x90 : 0xe0, ++ 0, 0, ++ }; ++ write_regs(client, regs); ++ dec->norm = *input; ++ break; ++ } ++ case VIDIOC_QUERYCTRL: ++ { ++ struct v4l2_queryctrl *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 128; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 64; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_SATURATION: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 64; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_HUE: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); ++ ctrl->minimum = -128; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 0; ++ ctrl->flags = 0; ++ break; ++ } ++ break; ++ } ++ case VIDIOC_S_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ if (ctrl->value > 255) ++ dec->brightness = 255; ++ else if (ctrl->value < 0) ++ dec->brightness = 0; ++ else ++ dec->brightness = ctrl->value; ++ write_reg(client, 0x0a, dec->brightness); ++ break; ++ case V4L2_CID_CONTRAST: ++ if (ctrl->value > 127) ++ dec->contrast = 127; ++ else if (ctrl->value < 0) ++ dec->contrast = 0; ++ else ++ dec->contrast = ctrl->value; ++ write_reg(client, 0x0b, dec->contrast); ++ break; ++ case V4L2_CID_SATURATION: ++ if (ctrl->value > 127) ++ dec->saturation = 127; ++ else if (ctrl->value < 0) ++ dec->saturation = 0; ++ else ++ dec->saturation = ctrl->value; ++ write_reg(client, 0x0c, dec->saturation); ++ break; ++ case V4L2_CID_HUE: ++ if (ctrl->value > 127) ++ dec->hue = 127; ++ else if (ctrl->value < -128) ++ dec->hue = -128; ++ else ++ dec->hue = ctrl->value; ++ write_reg(client, 0x0d, dec->hue); ++ break; ++ } ++ break; ++ } ++ case VIDIOC_G_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->value = dec->brightness; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->value = dec->contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ ctrl->value = dec->saturation; ++ break; ++ case V4L2_CID_HUE: ++ ctrl->value = dec->hue; ++ break; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct i2c_driver wis_saa7115_driver; ++ ++static struct i2c_client wis_saa7115_client_templ = { ++ .name = "SAA7115 (WIS)", ++ .driver = &wis_saa7115_driver, ++}; ++ ++static int wis_saa7115_detect(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct i2c_client *client; ++ struct wis_saa7115 *dec; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_saa7115_client_templ, ++ sizeof(wis_saa7115_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ ++ dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL); ++ if (dec == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ dec->norm = VIDEO_MODE_NTSC; ++ dec->brightness = 128; ++ dec->contrast = 64; ++ dec->saturation = 64; ++ dec->hue = 0; ++ i2c_set_clientdata(client, dec); ++ ++ printk(KERN_DEBUG ++ "wis-saa7115: initializing SAA7115 at address %d on %s\n", ++ addr, adapter->name); ++ ++ if (write_regs(client, initial_registers) < 0) { ++ printk(KERN_ERR ++ "wis-saa7115: error initializing SAA7115\n"); ++ kfree(client); ++ kfree(dec); ++ return 0; ++ } ++ ++ i2c_attach_client(client); ++ return 0; ++} ++ ++static int wis_saa7115_detach(struct i2c_client *client) ++{ ++ struct wis_saa7115 *dec = i2c_get_clientdata(client); ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(client); ++ kfree(dec); ++ return 0; ++} ++ ++static struct i2c_driver wis_saa7115_driver = { ++ .driver = { ++ .name = "WIS SAA7115 I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_SAA7115, ++ .detach_client = wis_saa7115_detach, ++ .command = wis_saa7115_command, ++}; ++ ++static int __init wis_saa7115_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_saa7115_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_saa7115_driver.id, wis_saa7115_detect); ++} ++ ++static void __exit wis_saa7115_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_saa7115_detect); ++ i2c_del_driver(&wis_saa7115_driver); ++} ++ ++module_init(wis_saa7115_init); ++module_exit(wis_saa7115_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c +new file mode 100644 +index 0000000..82e66d6 +--- /dev/null ++++ b/drivers/staging/go7007/wis-sony-tuner.c +@@ -0,0 +1,741 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++/* #define MPX_DEBUG */ ++ ++/* AS(IF/MPX) pin: LOW HIGH/OPEN ++ * IF/MPX address: 0x42/0x40 0x43/0x44 ++ */ ++#define IF_I2C_ADDR 0x43 ++#define MPX_I2C_ADDR 0x44 ++ ++static v4l2_std_id force_band; ++static char force_band_str[] = "-"; ++module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644); ++static int force_mpx_mode = -1; ++module_param(force_mpx_mode, int, 0644); ++ ++/* Store tuner info in the same format as tuner.c, so maybe we can put the ++ * Sony tuner support in there. */ ++struct sony_tunertype { ++ char *name; ++ unsigned char Vendor; /* unused here */ ++ unsigned char Type; /* unused here */ ++ ++ unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ ++ unsigned short thresh2; /* band switch VHF_HI <=> UHF */ ++ unsigned char VHF_L; ++ unsigned char VHF_H; ++ unsigned char UHF; ++ unsigned char config; ++ unsigned short IFPCoff; ++}; ++ ++/* This array is indexed by (tuner_type - 200) */ ++static struct sony_tunertype sony_tuners[] = { ++ { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0, ++ 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623}, ++ { "Sony NTSC_JP (BTF-PK467Z)", 0, 0, ++ 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940}, ++ { "Sony NTSC (BTF-PB463Z)", 0, 0, ++ 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732}, ++}; ++ ++struct wis_sony_tuner { ++ int type; ++ v4l2_std_id std; ++ unsigned int freq; ++ int mpxmode; ++ u32 audmode; ++}; ++ ++/* Basically the same as default_set_tv_freq() in tuner.c */ ++static int set_freq(struct i2c_client *client, int freq) ++{ ++ struct wis_sony_tuner *t = i2c_get_clientdata(client); ++ char *band_name; ++ int n; ++ int band_select; ++ struct sony_tunertype *tun; ++ u8 buffer[4]; ++ ++ tun = &sony_tuners[t->type - 200]; ++ if (freq < tun->thresh1) { ++ band_name = "VHF_L"; ++ band_select = tun->VHF_L; ++ } else if (freq < tun->thresh2) { ++ band_name = "VHF_H"; ++ band_select = tun->VHF_H; ++ } else { ++ band_name = "UHF"; ++ band_select = tun->UHF; ++ } ++ printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n", ++ freq / 16, (freq % 16) * 625, band_name); ++ n = freq + tun->IFPCoff; ++ ++ buffer[0] = n >> 8; ++ buffer[1] = n & 0xff; ++ buffer[2] = tun->config; ++ buffer[3] = band_select; ++ i2c_master_send(client, buffer, 4); ++ ++ return 0; ++} ++ ++static int mpx_write(struct i2c_client *client, int dev, int addr, int val) ++{ ++ u8 buffer[5]; ++ struct i2c_msg msg; ++ ++ buffer[0] = dev; ++ buffer[1] = addr >> 8; ++ buffer[2] = addr & 0xff; ++ buffer[3] = val >> 8; ++ buffer[4] = val & 0xff; ++ msg.addr = MPX_I2C_ADDR; ++ msg.flags = 0; ++ msg.len = 5; ++ msg.buf = buffer; ++ i2c_transfer(client->adapter, &msg, 1); ++ return 0; ++} ++ ++/* ++ * MPX register values for the BTF-PG472Z: ++ * ++ * FM_ NICAM_ SCART_ ++ * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME ++ * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000 ++ * --------------------------------------------------------------- ++ * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500 ++ * ++ * B/G ++ * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500 ++ * A2 1003 0020 0100 2601 5000 XXXX 0003 7500 ++ * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500 ++ * ++ * I ++ * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500 ++ * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500 ++ * ++ * D/K ++ * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500 ++ * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500 ++ * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500 ++ * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500 ++ * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500 ++ * ++ * L/L' ++ * Mono 0003 0200 0100 7C03 5000 2200 0009 7500 ++ * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500 ++ * ++ * M ++ * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500 ++ * ++ * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX. ++ * ++ * Bilingual selection in A2/NICAM: ++ * ++ * High byte of SOURCE Left chan Right chan ++ * 0x01 MAIN SUB ++ * 0x03 MAIN MAIN ++ * 0x04 SUB SUB ++ * ++ * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or ++ * 0x00 (all other bands). Force mono in A2 with FMONO_A2: ++ * ++ * FMONO_A2 ++ * 10/0022 ++ * -------- ++ * Forced mono ON 07F0 ++ * Forced mono OFF 0190 ++ */ ++ ++static struct { ++ enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode; ++ u16 modus; ++ u16 source; ++ u16 acb; ++ u16 fm_prescale; ++ u16 nicam_prescale; ++ u16 scart_prescale; ++ u16 system; ++ u16 volume; ++} mpx_audio_modes[] = { ++ /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, ++ 0x5000, 0x0000, 0x0001, 0x7500 }, ++ /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, ++ 0x5000, 0x0000, 0x0003, 0x7500 }, ++ /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, ++ 0x5000, 0x0000, 0x0003, 0x7500 }, ++ /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, ++ 0x5000, 0x0000, 0x0008, 0x7500 }, ++ /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, ++ 0x7900, 0x0000, 0x000A, 0x7500 }, ++ /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, ++ 0x7900, 0x0000, 0x000A, 0x7500 }, ++ /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, ++ 0x5000, 0x0000, 0x0004, 0x7500 }, ++ /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, ++ 0x5000, 0x0000, 0x0004, 0x7500 }, ++ /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, ++ 0x5000, 0x0000, 0x0005, 0x7500 }, ++ /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, ++ 0x5000, 0x0000, 0x0007, 0x7500 }, ++ /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, ++ 0x5000, 0x0000, 0x000B, 0x7500 }, ++ /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03, ++ 0x5000, 0x2200, 0x0009, 0x7500 }, ++ /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03, ++ 0x5000, 0x0000, 0x0009, 0x7500 }, ++}; ++ ++#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes) ++ ++static int mpx_setup(struct i2c_client *client) ++{ ++ struct wis_sony_tuner *t = i2c_get_clientdata(client); ++ u16 source = 0; ++ u8 buffer[3]; ++ struct i2c_msg msg; ++ ++ /* reset MPX */ ++ buffer[0] = 0x00; ++ buffer[1] = 0x80; ++ buffer[2] = 0x00; ++ msg.addr = MPX_I2C_ADDR; ++ msg.flags = 0; ++ msg.len = 3; ++ msg.buf = buffer; ++ i2c_transfer(client->adapter, &msg, 1); ++ buffer[1] = 0x00; ++ i2c_transfer(client->adapter, &msg, 1); ++ ++ if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) { ++ switch (t->audmode) { ++ case V4L2_TUNER_MODE_MONO: ++ switch (mpx_audio_modes[t->mpxmode].audio_mode) { ++ case AUD_A2: ++ source = mpx_audio_modes[t->mpxmode].source; ++ break; ++ case AUD_NICAM: ++ source = 0x0000; ++ break; ++ case AUD_NICAM_L: ++ source = 0x0200; ++ break; ++ default: ++ break; ++ } ++ break; ++ case V4L2_TUNER_MODE_STEREO: ++ source = mpx_audio_modes[t->mpxmode].source; ++ break; ++ case V4L2_TUNER_MODE_LANG1: ++ source = 0x0300; ++ break; ++ case V4L2_TUNER_MODE_LANG2: ++ source = 0x0400; ++ break; ++ } ++ source |= mpx_audio_modes[t->mpxmode].source & 0x00ff; ++ } else ++ source = mpx_audio_modes[t->mpxmode].source; ++ ++ mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus); ++ mpx_write(client, 0x12, 0x0008, source); ++ mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb); ++ mpx_write(client, 0x12, 0x000e, ++ mpx_audio_modes[t->mpxmode].fm_prescale); ++ mpx_write(client, 0x12, 0x0010, ++ mpx_audio_modes[t->mpxmode].nicam_prescale); ++ mpx_write(client, 0x12, 0x000d, ++ mpx_audio_modes[t->mpxmode].scart_prescale); ++ mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system); ++ mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume); ++ if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2) ++ mpx_write(client, 0x10, 0x0022, ++ t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190); ++ ++#ifdef MPX_DEBUG ++ { ++ u8 buf1[3], buf2[2]; ++ struct i2c_msg msgs[2]; ++ ++ printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x " ++ "%04x %04x %04x %04x %04x %04x\n", ++ mpx_audio_modes[t->mpxmode].modus, ++ source, ++ mpx_audio_modes[t->mpxmode].acb, ++ mpx_audio_modes[t->mpxmode].fm_prescale, ++ mpx_audio_modes[t->mpxmode].nicam_prescale, ++ mpx_audio_modes[t->mpxmode].scart_prescale, ++ mpx_audio_modes[t->mpxmode].system, ++ mpx_audio_modes[t->mpxmode].volume); ++ buf1[0] = 0x11; ++ buf1[1] = 0x00; ++ buf1[2] = 0x7e; ++ msgs[0].addr = MPX_I2C_ADDR; ++ msgs[0].flags = 0; ++ msgs[0].len = 3; ++ msgs[0].buf = buf1; ++ msgs[1].addr = MPX_I2C_ADDR; ++ msgs[1].flags = I2C_M_RD; ++ msgs[1].len = 2; ++ msgs[1].buf = buf2; ++ i2c_transfer(client->adapter, msgs, 2); ++ printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n", ++ buf2[0], buf2[1]); ++ buf1[0] = 0x11; ++ buf1[1] = 0x02; ++ buf1[2] = 0x00; ++ i2c_transfer(client->adapter, msgs, 2); ++ printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n", ++ buf2[0], buf2[1]); ++ } ++#endif ++ return 0; ++} ++ ++/* ++ * IF configuration values for the BTF-PG472Z: ++ * ++ * B/G: 0x94 0x70 0x49 ++ * I: 0x14 0x70 0x4a ++ * D/K: 0x14 0x70 0x4b ++ * L: 0x04 0x70 0x4b ++ * L': 0x44 0x70 0x53 ++ * M: 0x50 0x30 0x4c ++ */ ++ ++static int set_if(struct i2c_client *client) ++{ ++ struct wis_sony_tuner *t = i2c_get_clientdata(client); ++ u8 buffer[4]; ++ struct i2c_msg msg; ++ int default_mpx_mode = 0; ++ ++ /* configure IF */ ++ buffer[0] = 0; ++ if (t->std & V4L2_STD_PAL_BG) { ++ buffer[1] = 0x94; ++ buffer[2] = 0x70; ++ buffer[3] = 0x49; ++ default_mpx_mode = 1; ++ } else if (t->std & V4L2_STD_PAL_I) { ++ buffer[1] = 0x14; ++ buffer[2] = 0x70; ++ buffer[3] = 0x4a; ++ default_mpx_mode = 4; ++ } else if (t->std & V4L2_STD_PAL_DK) { ++ buffer[1] = 0x14; ++ buffer[2] = 0x70; ++ buffer[3] = 0x4b; ++ default_mpx_mode = 6; ++ } else if (t->std & V4L2_STD_SECAM_L) { ++ buffer[1] = 0x04; ++ buffer[2] = 0x70; ++ buffer[3] = 0x4b; ++ default_mpx_mode = 11; ++ } ++ msg.addr = IF_I2C_ADDR; ++ msg.flags = 0; ++ msg.len = 4; ++ msg.buf = buffer; ++ i2c_transfer(client->adapter, &msg, 1); ++ ++ /* Select MPX mode if not forced by the user */ ++ if (force_mpx_mode >= 0 || force_mpx_mode < MPX_NUM_MODES) ++ t->mpxmode = force_mpx_mode; ++ else ++ t->mpxmode = default_mpx_mode; ++ printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n", ++ t->mpxmode); ++ mpx_setup(client); ++ ++ return 0; ++} ++ ++static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ++{ ++ struct wis_sony_tuner *t = i2c_get_clientdata(client); ++ ++ switch (cmd) { ++#ifdef TUNER_SET_TYPE_ADDR ++ case TUNER_SET_TYPE_ADDR: ++ { ++ struct tuner_setup *tun_setup = arg; ++ int *type = &tun_setup->type; ++#else ++ case TUNER_SET_TYPE: ++ { ++ int *type = arg; ++#endif ++ ++ if (t->type >= 0) { ++ if (t->type != *type) ++ printk(KERN_ERR "wis-sony-tuner: type already " ++ "set to %d, ignoring request for %d\n", ++ t->type, *type); ++ break; ++ } ++ t->type = *type; ++ switch (t->type) { ++ case TUNER_SONY_BTF_PG472Z: ++ switch (force_band_str[0]) { ++ case 'b': ++ case 'B': ++ case 'g': ++ case 'G': ++ printk(KERN_INFO "wis-sony-tuner: forcing " ++ "tuner to PAL-B/G bands\n"); ++ force_band = V4L2_STD_PAL_BG; ++ break; ++ case 'i': ++ case 'I': ++ printk(KERN_INFO "wis-sony-tuner: forcing " ++ "tuner to PAL-I band\n"); ++ force_band = V4L2_STD_PAL_I; ++ break; ++ case 'd': ++ case 'D': ++ case 'k': ++ case 'K': ++ printk(KERN_INFO "wis-sony-tuner: forcing " ++ "tuner to PAL-D/K bands\n"); ++ force_band = V4L2_STD_PAL_I; ++ break; ++ case 'l': ++ case 'L': ++ printk(KERN_INFO "wis-sony-tuner: forcing " ++ "tuner to SECAM-L band\n"); ++ force_band = V4L2_STD_SECAM_L; ++ break; ++ default: ++ force_band = 0; ++ break; ++ } ++ if (force_band) ++ t->std = force_band; ++ else ++ t->std = V4L2_STD_PAL_BG; ++ set_if(client); ++ break; ++ case TUNER_SONY_BTF_PK467Z: ++ t->std = V4L2_STD_NTSC_M_JP; ++ break; ++ case TUNER_SONY_BTF_PB463Z: ++ t->std = V4L2_STD_NTSC_M; ++ break; ++ default: ++ printk(KERN_ERR "wis-sony-tuner: tuner type %d is not " ++ "supported by this module\n", *type); ++ break; ++ } ++ if (type >= 0) ++ printk(KERN_INFO ++ "wis-sony-tuner: type set to %d (%s)\n", ++ t->type, sony_tuners[t->type - 200].name); ++ break; ++ } ++ case VIDIOC_G_FREQUENCY: ++ { ++ struct v4l2_frequency *f = arg; ++ ++ f->frequency = t->freq; ++ break; ++ } ++ case VIDIOC_S_FREQUENCY: ++ { ++ struct v4l2_frequency *f = arg; ++ ++ t->freq = f->frequency; ++ set_freq(client, t->freq); ++ break; ++ } ++ case VIDIOC_ENUMSTD: ++ { ++ struct v4l2_standard *std = arg; ++ ++ switch (t->type) { ++ case TUNER_SONY_BTF_PG472Z: ++ switch (std->index) { ++ case 0: ++ v4l2_video_std_construct(std, ++ V4L2_STD_PAL_BG, "PAL-B/G"); ++ break; ++ case 1: ++ v4l2_video_std_construct(std, ++ V4L2_STD_PAL_I, "PAL-I"); ++ break; ++ case 2: ++ v4l2_video_std_construct(std, ++ V4L2_STD_PAL_DK, "PAL-D/K"); ++ break; ++ case 3: ++ v4l2_video_std_construct(std, ++ V4L2_STD_SECAM_L, "SECAM-L"); ++ break; ++ default: ++ std->id = 0; /* hack to indicate EINVAL */ ++ break; ++ } ++ break; ++ case TUNER_SONY_BTF_PK467Z: ++ if (std->index != 0) { ++ std->id = 0; /* hack to indicate EINVAL */ ++ break; ++ } ++ v4l2_video_std_construct(std, ++ V4L2_STD_NTSC_M_JP, "NTSC-J"); ++ break; ++ case TUNER_SONY_BTF_PB463Z: ++ if (std->index != 0) { ++ std->id = 0; /* hack to indicate EINVAL */ ++ break; ++ } ++ v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC"); ++ break; ++ } ++ break; ++ } ++ case VIDIOC_G_STD: ++ { ++ v4l2_std_id *std = arg; ++ ++ *std = t->std; ++ break; ++ } ++ case VIDIOC_S_STD: ++ { ++ v4l2_std_id *std = arg; ++ v4l2_std_id old = t->std; ++ ++ switch (t->type) { ++ case TUNER_SONY_BTF_PG472Z: ++ if (force_band && (*std & force_band) != *std && ++ *std != V4L2_STD_PAL && ++ *std != V4L2_STD_SECAM) { ++ printk(KERN_DEBUG "wis-sony-tuner: ignoring " ++ "requested TV standard in " ++ "favor of force_band value\n"); ++ t->std = force_band; ++ } else if (*std & V4L2_STD_PAL_BG) { /* default */ ++ t->std = V4L2_STD_PAL_BG; ++ } else if (*std & V4L2_STD_PAL_I) { ++ t->std = V4L2_STD_PAL_I; ++ } else if (*std & V4L2_STD_PAL_DK) { ++ t->std = V4L2_STD_PAL_DK; ++ } else if (*std & V4L2_STD_SECAM_L) { ++ t->std = V4L2_STD_SECAM_L; ++ } else { ++ printk(KERN_ERR "wis-sony-tuner: TV standard " ++ "not supported\n"); ++ *std = 0; /* hack to indicate EINVAL */ ++ break; ++ } ++ if (old != t->std) ++ set_if(client); ++ break; ++ case TUNER_SONY_BTF_PK467Z: ++ if (!(*std & V4L2_STD_NTSC_M_JP)) { ++ printk(KERN_ERR "wis-sony-tuner: TV standard " ++ "not supported\n"); ++ *std = 0; /* hack to indicate EINVAL */ ++ } ++ break; ++ case TUNER_SONY_BTF_PB463Z: ++ if (!(*std & V4L2_STD_NTSC_M)) { ++ printk(KERN_ERR "wis-sony-tuner: TV standard " ++ "not supported\n"); ++ *std = 0; /* hack to indicate EINVAL */ ++ } ++ break; ++ } ++ break; ++ } ++ case VIDIOC_QUERYSTD: ++ { ++ v4l2_std_id *std = arg; ++ ++ switch (t->type) { ++ case TUNER_SONY_BTF_PG472Z: ++ if (force_band) ++ *std = force_band; ++ else ++ *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I | ++ V4L2_STD_PAL_DK | V4L2_STD_SECAM_L; ++ break; ++ case TUNER_SONY_BTF_PK467Z: ++ *std = V4L2_STD_NTSC_M_JP; ++ break; ++ case TUNER_SONY_BTF_PB463Z: ++ *std = V4L2_STD_NTSC_M; ++ break; ++ } ++ break; ++ } ++ case VIDIOC_G_TUNER: ++ { ++ struct v4l2_tuner *tun = arg; ++ ++ memset(t, 0, sizeof(*tun)); ++ strcpy(tun->name, "Television"); ++ tun->type = V4L2_TUNER_ANALOG_TV; ++ tun->rangelow = 0UL; /* does anything use these? */ ++ tun->rangehigh = 0xffffffffUL; ++ switch (t->type) { ++ case TUNER_SONY_BTF_PG472Z: ++ tun->capability = V4L2_TUNER_CAP_NORM | ++ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | ++ V4L2_TUNER_CAP_LANG2; ++ tun->rxsubchans = V4L2_TUNER_SUB_MONO | ++ V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | ++ V4L2_TUNER_SUB_LANG2; ++ break; ++ case TUNER_SONY_BTF_PK467Z: ++ case TUNER_SONY_BTF_PB463Z: ++ tun->capability = V4L2_TUNER_CAP_STEREO; ++ tun->rxsubchans = V4L2_TUNER_SUB_MONO | ++ V4L2_TUNER_SUB_STEREO; ++ break; ++ } ++ tun->audmode = t->audmode; ++ return 0; ++ } ++ case VIDIOC_S_TUNER: ++ { ++ struct v4l2_tuner *tun = arg; ++ ++ switch (t->type) { ++ case TUNER_SONY_BTF_PG472Z: ++ if (tun->audmode != t->audmode) { ++ t->audmode = tun->audmode; ++ mpx_setup(client); ++ } ++ break; ++ case TUNER_SONY_BTF_PK467Z: ++ case TUNER_SONY_BTF_PB463Z: ++ break; ++ } ++ return 0; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct i2c_driver wis_sony_tuner_driver; ++ ++static struct i2c_client wis_sony_tuner_client_templ = { ++ .name = "Sony TV Tuner (WIS)", ++ .driver = &wis_sony_tuner_driver, ++}; ++ ++static int wis_sony_tuner_detect(struct i2c_adapter *adapter, ++ int addr, int kind) ++{ ++ struct i2c_client *client; ++ struct wis_sony_tuner *t; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_sony_tuner_client_templ, ++ sizeof(wis_sony_tuner_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ ++ t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL); ++ if (t == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ t->type = -1; ++ t->freq = 0; ++ t->mpxmode = 0; ++ t->audmode = V4L2_TUNER_MODE_STEREO; ++ i2c_set_clientdata(client, t); ++ ++ printk(KERN_DEBUG ++ "wis-sony-tuner: initializing tuner at address %d on %s\n", ++ addr, adapter->name); ++ ++ i2c_attach_client(client); ++ ++ return 0; ++} ++ ++static int wis_sony_tuner_detach(struct i2c_client *client) ++{ ++ struct wis_sony_tuner *t = i2c_get_clientdata(client); ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(t); ++ kfree(client); ++ return 0; ++} ++ ++static struct i2c_driver wis_sony_tuner_driver = { ++ .driver = { ++ .name = "WIS Sony TV Tuner I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_SONY_TUNER, ++ .detach_client = wis_sony_tuner_detach, ++ .command = tuner_command, ++}; ++ ++static int __init wis_sony_tuner_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_sony_tuner_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_sony_tuner_driver.id, ++ wis_sony_tuner_detect); ++} ++ ++static void __exit wis_sony_tuner_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_sony_tuner_detect); ++ i2c_del_driver(&wis_sony_tuner_driver); ++} ++ ++module_init(wis_sony_tuner_init); ++module_exit(wis_sony_tuner_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c +new file mode 100644 +index 0000000..69ed7bf +--- /dev/null ++++ b/drivers/staging/go7007/wis-tw2804.c +@@ -0,0 +1,381 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++struct wis_tw2804 { ++ int channel; ++ int norm; ++ int brightness; ++ int contrast; ++ int saturation; ++ int hue; ++}; ++ ++static u8 global_registers[] = ++{ ++ 0x39, 0x00, ++ 0x3a, 0xff, ++ 0x3b, 0x84, ++ 0x3c, 0x80, ++ 0x3d, 0x80, ++ 0x3e, 0x82, ++ 0x3f, 0x82, ++ 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ ++}; ++ ++static u8 channel_registers[] = ++{ ++ 0x01, 0xc4, ++ 0x02, 0xa5, ++ 0x03, 0x20, ++ 0x04, 0xd0, ++ 0x05, 0x20, ++ 0x06, 0xd0, ++ 0x07, 0x88, ++ 0x08, 0x20, ++ 0x09, 0x07, ++ 0x0a, 0xf0, ++ 0x0b, 0x07, ++ 0x0c, 0xf0, ++ 0x0d, 0x40, ++ 0x0e, 0xd2, ++ 0x0f, 0x80, ++ 0x10, 0x80, ++ 0x11, 0x80, ++ 0x12, 0x80, ++ 0x13, 0x1f, ++ 0x14, 0x00, ++ 0x15, 0x00, ++ 0x16, 0x00, ++ 0x17, 0x00, ++ 0x18, 0xff, ++ 0x19, 0xff, ++ 0x1a, 0xff, ++ 0x1b, 0xff, ++ 0x1c, 0xff, ++ 0x1d, 0xff, ++ 0x1e, 0xff, ++ 0x1f, 0xff, ++ 0x20, 0x07, ++ 0x21, 0x07, ++ 0x22, 0x00, ++ 0x23, 0x91, ++ 0x24, 0x51, ++ 0x25, 0x03, ++ 0x26, 0x00, ++ 0x27, 0x00, ++ 0x28, 0x00, ++ 0x29, 0x00, ++ 0x2a, 0x00, ++ 0x2b, 0x00, ++ 0x2c, 0x00, ++ 0x2d, 0x00, ++ 0x2e, 0x00, ++ 0x2f, 0x00, ++ 0x30, 0x00, ++ 0x31, 0x00, ++ 0x32, 0x00, ++ 0x33, 0x00, ++ 0x34, 0x00, ++ 0x35, 0x00, ++ 0x36, 0x00, ++ 0x37, 0x00, ++ 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ ++}; ++ ++static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel) ++{ ++ return i2c_smbus_write_byte_data(client, reg | (channel << 6), value); ++} ++ ++static int write_regs(struct i2c_client *client, u8 *regs, int channel) ++{ ++ int i; ++ ++ for (i = 0; regs[i] != 0xff; i += 2) ++ if (i2c_smbus_write_byte_data(client, ++ regs[i] | (channel << 6), regs[i + 1]) < 0) ++ return -1; ++ return 0; ++} ++ ++static int wis_tw2804_command(struct i2c_client *client, ++ unsigned int cmd, void *arg) ++{ ++ struct wis_tw2804 *dec = i2c_get_clientdata(client); ++ ++ if (cmd == DECODER_SET_CHANNEL) { ++ int *input = arg; ++ ++ if (*input < 0 || *input > 3) { ++ printk(KERN_ERR "wis-tw2804: channel %d is not " ++ "between 0 and 3!\n", *input); ++ return 0; ++ } ++ dec->channel = *input; ++ printk(KERN_DEBUG "wis-tw2804: initializing TW2804 " ++ "channel %d\n", dec->channel); ++ if (dec->channel == 0 && ++ write_regs(client, global_registers, 0) < 0) { ++ printk(KERN_ERR "wis-tw2804: error initializing " ++ "TW2804 global registers\n"); ++ return 0; ++ } ++ if (write_regs(client, channel_registers, dec->channel) < 0) { ++ printk(KERN_ERR "wis-tw2804: error initializing " ++ "TW2804 channel %d\n", dec->channel); ++ return 0; ++ } ++ return 0; ++ } ++ ++ if (dec->channel < 0) { ++ printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until " ++ "channel number is set\n", cmd); ++ return 0; ++ } ++ ++ switch (cmd) { ++ case DECODER_SET_NORM: ++ { ++ int *input = arg; ++ u8 regs[] = { ++ 0x01, *input == VIDEO_MODE_NTSC ? 0xc4 : 0x84, ++ 0x09, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04, ++ 0x0a, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, ++ 0x0b, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04, ++ 0x0c, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, ++ 0x0d, *input == VIDEO_MODE_NTSC ? 0x40 : 0x4a, ++ 0x16, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40, ++ 0x17, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40, ++ 0x20, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f, ++ 0x21, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f, ++ 0xff, 0xff, ++ }; ++ write_regs(client, regs, dec->channel); ++ dec->norm = *input; ++ break; ++ } ++ case VIDIOC_QUERYCTRL: ++ { ++ struct v4l2_queryctrl *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 128; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 128; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_SATURATION: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 128; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_HUE: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 128; ++ ctrl->flags = 0; ++ break; ++ } ++ break; ++ } ++ case VIDIOC_S_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ if (ctrl->value > 255) ++ dec->brightness = 255; ++ else if (ctrl->value < 0) ++ dec->brightness = 0; ++ else ++ dec->brightness = ctrl->value; ++ write_reg(client, 0x12, dec->brightness, dec->channel); ++ break; ++ case V4L2_CID_CONTRAST: ++ if (ctrl->value > 255) ++ dec->contrast = 255; ++ else if (ctrl->value < 0) ++ dec->contrast = 0; ++ else ++ dec->contrast = ctrl->value; ++ write_reg(client, 0x11, dec->contrast, dec->channel); ++ break; ++ case V4L2_CID_SATURATION: ++ if (ctrl->value > 255) ++ dec->saturation = 255; ++ else if (ctrl->value < 0) ++ dec->saturation = 0; ++ else ++ dec->saturation = ctrl->value; ++ write_reg(client, 0x10, dec->saturation, dec->channel); ++ break; ++ case V4L2_CID_HUE: ++ if (ctrl->value > 255) ++ dec->hue = 255; ++ else if (ctrl->value < 0) ++ dec->hue = 0; ++ else ++ dec->hue = ctrl->value; ++ write_reg(client, 0x0f, dec->hue, dec->channel); ++ break; ++ } ++ break; ++ } ++ case VIDIOC_G_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->value = dec->brightness; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->value = dec->contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ ctrl->value = dec->saturation; ++ break; ++ case V4L2_CID_HUE: ++ ctrl->value = dec->hue; ++ break; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct i2c_driver wis_tw2804_driver; ++ ++static struct i2c_client wis_tw2804_client_templ = { ++ .name = "TW2804 (WIS)", ++ .driver = &wis_tw2804_driver, ++}; ++ ++static int wis_tw2804_detect(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct i2c_client *client; ++ struct wis_tw2804 *dec; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_tw2804_client_templ, ++ sizeof(wis_tw2804_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ ++ dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL); ++ if (dec == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ dec->channel = -1; ++ dec->norm = VIDEO_MODE_NTSC; ++ dec->brightness = 128; ++ dec->contrast = 128; ++ dec->saturation = 128; ++ dec->hue = 128; ++ i2c_set_clientdata(client, dec); ++ ++ printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n", ++ addr, adapter->name); ++ ++ i2c_attach_client(client); ++ return 0; ++} ++ ++static int wis_tw2804_detach(struct i2c_client *client) ++{ ++ struct wis_tw2804 *dec = i2c_get_clientdata(client); ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(client); ++ kfree(dec); ++ return 0; ++} ++ ++static struct i2c_driver wis_tw2804_driver = { ++ .driver = { ++ .name = "WIS TW2804 I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_TW2804, ++ .detach_client = wis_tw2804_detach, ++ .command = wis_tw2804_command, ++}; ++ ++static int __init wis_tw2804_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_tw2804_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_tw2804_driver.id, wis_tw2804_detect); ++} ++ ++static void __exit wis_tw2804_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_tw2804_detect); ++ i2c_del_driver(&wis_tw2804_driver); ++} ++ ++module_init(wis_tw2804_init); ++module_exit(wis_tw2804_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c +new file mode 100644 +index 0000000..1cdf01a +--- /dev/null ++++ b/drivers/staging/go7007/wis-tw9903.c +@@ -0,0 +1,363 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++struct wis_tw9903 { ++ int norm; ++ int brightness; ++ int contrast; ++ int hue; ++}; ++ ++static u8 initial_registers[] = ++{ ++ 0x02, 0x44, /* input 1, composite */ ++ 0x03, 0x92, /* correct digital format */ ++ 0x04, 0x00, ++ 0x05, 0x80, /* or 0x00 for PAL */ ++ 0x06, 0x40, /* second internal current reference */ ++ 0x07, 0x02, /* window */ ++ 0x08, 0x14, /* window */ ++ 0x09, 0xf0, /* window */ ++ 0x0a, 0x81, /* window */ ++ 0x0b, 0xd0, /* window */ ++ 0x0c, 0x8c, ++ 0x0d, 0x00, /* scaling */ ++ 0x0e, 0x11, /* scaling */ ++ 0x0f, 0x00, /* scaling */ ++ 0x10, 0x00, /* brightness */ ++ 0x11, 0x60, /* contrast */ ++ 0x12, 0x01, /* sharpness */ ++ 0x13, 0x7f, /* U gain */ ++ 0x14, 0x5a, /* V gain */ ++ 0x15, 0x00, /* hue */ ++ 0x16, 0xc3, /* sharpness */ ++ 0x18, 0x00, ++ 0x19, 0x58, /* vbi */ ++ 0x1a, 0x80, ++ 0x1c, 0x0f, /* video norm */ ++ 0x1d, 0x7f, /* video norm */ ++ 0x20, 0xa0, /* clamping gain (working 0x50) */ ++ 0x21, 0x22, ++ 0x22, 0xf0, ++ 0x23, 0xfe, ++ 0x24, 0x3c, ++ 0x25, 0x38, ++ 0x26, 0x44, ++ 0x27, 0x20, ++ 0x28, 0x00, ++ 0x29, 0x15, ++ 0x2a, 0xa0, ++ 0x2b, 0x44, ++ 0x2c, 0x37, ++ 0x2d, 0x00, ++ 0x2e, 0xa5, /* burst PLL control (working: a9) */ ++ 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */ ++ 0x31, 0x00, ++ 0x33, 0x22, ++ 0x34, 0x11, ++ 0x35, 0x35, ++ 0x3b, 0x05, ++ 0x06, 0xc0, /* reset device */ ++ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ ++}; ++ ++static int write_reg(struct i2c_client *client, u8 reg, u8 value) ++{ ++ return i2c_smbus_write_byte_data(client, reg, value); ++} ++ ++static int write_regs(struct i2c_client *client, u8 *regs) ++{ ++ int i; ++ ++ for (i = 0; regs[i] != 0x00; i += 2) ++ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) ++ return -1; ++ return 0; ++} ++ ++static int wis_tw9903_command(struct i2c_client *client, ++ unsigned int cmd, void *arg) ++{ ++ struct wis_tw9903 *dec = i2c_get_clientdata(client); ++ ++ switch (cmd) { ++ case DECODER_SET_INPUT: ++ { ++ int *input = arg; ++ ++ i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1)); ++ break; ++ } ++#if 0 /* The scaler on this thing seems to be horribly broken */ ++ case DECODER_SET_RESOLUTION: ++ { ++ struct video_decoder_resolution *res = arg; ++ /*int hscale = 256 * 720 / res->width;*/ ++ int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8)); ++ int vscale = 256 * (dec->norm == VIDEO_MODE_NTSC ? 240 : 288) ++ / res->height; ++ u8 regs[] = { ++ 0x0d, vscale & 0xff, ++ 0x0f, hscale & 0xff, ++ 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8), ++ 0x06, 0xc0, /* reset device */ ++ 0, 0, ++ }; ++ printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n", ++ vscale, hscale); ++ /*write_regs(client, regs);*/ ++ break; ++ } ++#endif ++ case DECODER_SET_NORM: ++ { ++ int *input = arg; ++ u8 regs[] = { ++ 0x05, *input == VIDEO_MODE_NTSC ? 0x80 : 0x00, ++ 0x07, *input == VIDEO_MODE_NTSC ? 0x02 : 0x12, ++ 0x08, *input == VIDEO_MODE_NTSC ? 0x14 : 0x18, ++ 0x09, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, ++ 0, 0, ++ }; ++ write_regs(client, regs); ++ dec->norm = *input; ++ break; ++ } ++ case VIDIOC_QUERYCTRL: ++ { ++ struct v4l2_queryctrl *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); ++ ctrl->minimum = -128; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 0x00; ++ ctrl->flags = 0; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 255; ++ ctrl->step = 1; ++ ctrl->default_value = 0x60; ++ ctrl->flags = 0; ++ break; ++#if 0 ++ /* I don't understand how the Chroma Gain registers work... */ ++ case V4L2_CID_SATURATION: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); ++ ctrl->minimum = 0; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 64; ++ ctrl->flags = 0; ++ break; ++#endif ++ case V4L2_CID_HUE: ++ ctrl->type = V4L2_CTRL_TYPE_INTEGER; ++ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); ++ ctrl->minimum = -128; ++ ctrl->maximum = 127; ++ ctrl->step = 1; ++ ctrl->default_value = 0; ++ ctrl->flags = 0; ++ break; ++ } ++ break; ++ } ++ case VIDIOC_S_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ if (ctrl->value > 127) ++ dec->brightness = 127; ++ else if (ctrl->value < -128) ++ dec->brightness = -128; ++ else ++ dec->brightness = ctrl->value; ++ write_reg(client, 0x10, dec->brightness); ++ break; ++ case V4L2_CID_CONTRAST: ++ if (ctrl->value > 255) ++ dec->contrast = 255; ++ else if (ctrl->value < 0) ++ dec->contrast = 0; ++ else ++ dec->contrast = ctrl->value; ++ write_reg(client, 0x11, dec->contrast); ++ break; ++#if 0 ++ case V4L2_CID_SATURATION: ++ if (ctrl->value > 127) ++ dec->saturation = 127; ++ else if (ctrl->value < 0) ++ dec->saturation = 0; ++ else ++ dec->saturation = ctrl->value; ++ /*write_reg(client, 0x0c, dec->saturation);*/ ++ break; ++#endif ++ case V4L2_CID_HUE: ++ if (ctrl->value > 127) ++ dec->hue = 127; ++ else if (ctrl->value < -128) ++ dec->hue = -128; ++ else ++ dec->hue = ctrl->value; ++ write_reg(client, 0x15, dec->hue); ++ break; ++ } ++ break; ++ } ++ case VIDIOC_G_CTRL: ++ { ++ struct v4l2_control *ctrl = arg; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ ctrl->value = dec->brightness; ++ break; ++ case V4L2_CID_CONTRAST: ++ ctrl->value = dec->contrast; ++ break; ++#if 0 ++ case V4L2_CID_SATURATION: ++ ctrl->value = dec->saturation; ++ break; ++#endif ++ case V4L2_CID_HUE: ++ ctrl->value = dec->hue; ++ break; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct i2c_driver wis_tw9903_driver; ++ ++static struct i2c_client wis_tw9903_client_templ = { ++ .name = "TW9903 (WIS)", ++ .driver = &wis_tw9903_driver, ++}; ++ ++static int wis_tw9903_detect(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct i2c_client *client; ++ struct wis_tw9903 *dec; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_tw9903_client_templ, ++ sizeof(wis_tw9903_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ ++ dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL); ++ if (dec == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ dec->norm = VIDEO_MODE_NTSC; ++ dec->brightness = 0; ++ dec->contrast = 0x60; ++ dec->hue = 0; ++ i2c_set_clientdata(client, dec); ++ ++ printk(KERN_DEBUG ++ "wis-tw9903: initializing TW9903 at address %d on %s\n", ++ addr, adapter->name); ++ ++ if (write_regs(client, initial_registers) < 0) { ++ printk(KERN_ERR "wis-tw9903: error initializing TW9903\n"); ++ kfree(client); ++ kfree(dec); ++ return 0; ++ } ++ ++ i2c_attach_client(client); ++ return 0; ++} ++ ++static int wis_tw9903_detach(struct i2c_client *client) ++{ ++ struct wis_tw9903 *dec = i2c_get_clientdata(client); ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(client); ++ kfree(dec); ++ return 0; ++} ++ ++static struct i2c_driver wis_tw9903_driver = { ++ .driver = { ++ .name = "WIS TW9903 I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_TW9903, ++ .detach_client = wis_tw9903_detach, ++ .command = wis_tw9903_command, ++}; ++ ++static int __init wis_tw9903_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_tw9903_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_tw9903_driver.id, wis_tw9903_detect); ++} ++ ++static void __exit wis_tw9903_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_tw9903_detect); ++ i2c_del_driver(&wis_tw9903_driver); ++} ++ ++module_init(wis_tw9903_init); ++module_exit(wis_tw9903_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c +new file mode 100644 +index 0000000..28c10bf +--- /dev/null ++++ b/drivers/staging/go7007/wis-uda1342.c +@@ -0,0 +1,136 @@ ++/* ++ * Copyright (C) 2005-2006 Micronas USA Inc. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wis-i2c.h" ++ ++static int write_reg(struct i2c_client *client, int reg, int value) ++{ ++ /* UDA1342 wants MSB first, but SMBus sends LSB first */ ++ i2c_smbus_write_word_data(client, reg, swab16(value)); ++ return 0; ++} ++ ++static int wis_uda1342_command(struct i2c_client *client, ++ unsigned int cmd, void *arg) ++{ ++ switch (cmd) { ++ case VIDIOC_S_AUDIO: ++ { ++ int *inp = arg; ++ ++ switch (*inp) { ++ case TVAUDIO_INPUT_TUNER: ++ write_reg(client, 0x00, 0x1441); /* select input 2 */ ++ break; ++ case TVAUDIO_INPUT_EXTERN: ++ write_reg(client, 0x00, 0x1241); /* select input 1 */ ++ break; ++ default: ++ printk(KERN_ERR "wis-uda1342: input %d not supported\n", ++ *inp); ++ break; ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static struct i2c_driver wis_uda1342_driver; ++ ++static struct i2c_client wis_uda1342_client_templ = { ++ .name = "UDA1342 (WIS)", ++ .driver = &wis_uda1342_driver, ++}; ++ ++static int wis_uda1342_detect(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct i2c_client *client; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) ++ return 0; ++ ++ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ memcpy(client, &wis_uda1342_client_templ, ++ sizeof(wis_uda1342_client_templ)); ++ client->adapter = adapter; ++ client->addr = addr; ++ ++ printk(KERN_DEBUG ++ "wis-uda1342: initializing UDA1342 at address %d on %s\n", ++ addr, adapter->name); ++ ++ write_reg(client, 0x00, 0x8000); /* reset registers */ ++ write_reg(client, 0x00, 0x1241); /* select input 1 */ ++ ++ i2c_attach_client(client); ++ return 0; ++} ++ ++static int wis_uda1342_detach(struct i2c_client *client) ++{ ++ int r; ++ ++ r = i2c_detach_client(client); ++ if (r < 0) ++ return r; ++ ++ kfree(client); ++ return 0; ++} ++ ++static struct i2c_driver wis_uda1342_driver = { ++ .driver = { ++ .name = "WIS UDA1342 I2C driver", ++ }, ++ .id = I2C_DRIVERID_WIS_UDA1342, ++ .detach_client = wis_uda1342_detach, ++ .command = wis_uda1342_command, ++}; ++ ++static int __init wis_uda1342_init(void) ++{ ++ int r; ++ ++ r = i2c_add_driver(&wis_uda1342_driver); ++ if (r < 0) ++ return r; ++ return wis_i2c_add_driver(wis_uda1342_driver.id, wis_uda1342_detect); ++} ++ ++static void __exit wis_uda1342_cleanup(void) ++{ ++ wis_i2c_del_driver(wis_uda1342_detect); ++ i2c_del_driver(&wis_uda1342_driver); ++} ++ ++module_init(wis_uda1342_init); ++module_exit(wis_uda1342_cleanup); ++ ++MODULE_LICENSE("GPL v2"); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0011-Staging-USB-IP-add-common-functions-needed.patch b/src/patches/suse-2.6.27.31/patches.drivers/0011-Staging-USB-IP-add-common-functions-needed.patch new file mode 100644 index 000000000..66c3f8450 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0011-Staging-USB-IP-add-common-functions-needed.patch @@ -0,0 +1,1661 @@ +From 05a1f28e879e3b4d6a9c08e30b1898943f77b6e7 Mon Sep 17 00:00:00 2001 +From: Takahiro Hirofuchi +Date: Wed, 9 Jul 2008 14:56:51 -0600 +Subject: [PATCH 11/23] Staging: USB/IP: add common functions needed +Patch-mainline: 2.6.28 + +This adds the common functions needed by both the host and client side +of the USB/IP code. + +Brian Merrell cleaned up a lot of this code and submitted it for +inclusion. Greg also did a lot of cleanup. + +Signed-off-by: Brian G. Merrell +Cc: Takahiro Hirofuchi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/usbip/Kconfig | 14 + + drivers/staging/usbip/Makefile | 6 + + drivers/staging/usbip/README | 6 + + drivers/staging/usbip/usbip_common.c | 997 ++++++++++++++++++++++++++++++++++ + drivers/staging/usbip/usbip_common.h | 406 ++++++++++++++ + drivers/staging/usbip/usbip_event.c | 141 +++++ + 8 files changed, 1573 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/usbip/Kconfig + create mode 100644 drivers/staging/usbip/Makefile + create mode 100644 drivers/staging/usbip/README + create mode 100644 drivers/staging/usbip/usbip_common.c + create mode 100644 drivers/staging/usbip/usbip_common.h + create mode 100644 drivers/staging/usbip/usbip_event.c + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index f16bc9c..4dbf795 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -33,4 +33,6 @@ source "drivers/staging/me4000/Kconfig" + + source "drivers/staging/go7007/Kconfig" + ++source "drivers/staging/usbip/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index aa61662..be42c0d 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -5,3 +5,4 @@ obj-$(CONFIG_SLICOSS) += slicoss/ + obj-$(CONFIG_SXG) += sxg/ + obj-$(CONFIG_ME4000) += me4000/ + obj-$(CONFIG_VIDEO_GO7007) += go7007/ ++obj-$(CONFIG_USB_IP_COMMON) += usbip/ +diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig +new file mode 100644 +index 0000000..37efb5e +--- /dev/null ++++ b/drivers/staging/usbip/Kconfig +@@ -0,0 +1,14 @@ ++config USB_IP_COMMON ++ tristate "USB IP support (EXPERIMENTAL)" ++ depends on USB && EXPERIMENTAL ++ default N ++ ---help--- ++ This enables pushing USB packets over IP to allow remote ++ machines access to USB devices directly. For more details, ++ and links to the userspace utility programs to let this work ++ properly, see http://usbip.naist.jp/ ++ ++ To compile this driver as a module, choose M here: the ++ module will be called usbip_common_mod. ++ ++ If unsure, say N. +diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile +new file mode 100644 +index 0000000..ce925ca +--- /dev/null ++++ b/drivers/staging/usbip/Makefile +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_USB_IP_COMMON) += usbip_common_mod.o ++usbip_common_mod-objs := usbip_common.o usbip_event.o ++ ++ifeq ($(CONFIG_USB_DEBUG),y) ++ EXTRA_CFLAGS += -DDEBUG ++endif +diff --git a/drivers/staging/usbip/README b/drivers/staging/usbip/README +new file mode 100644 +index 0000000..c11be57 +--- /dev/null ++++ b/drivers/staging/usbip/README +@@ -0,0 +1,6 @@ ++TODO: ++ - more discussion about the protocol ++ - testing ++ - review of the userspace interface ++ ++Please send patches for this code to Greg Kroah-Hartman +diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c +new file mode 100644 +index 0000000..e64918f +--- /dev/null ++++ b/drivers/staging/usbip/usbip_common.c +@@ -0,0 +1,997 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "usbip_common.h" ++ ++/* version information */ ++#define DRIVER_VERSION "1.0" ++#define DRIVER_AUTHOR "Takahiro Hirofuchi " ++#define DRIVER_DESC "usbip common driver" ++ ++/*-------------------------------------------------------------------------*/ ++/* debug routines */ ++ ++#ifdef CONFIG_USB_DEBUG ++unsigned long usbip_debug_flag = 0xffffffff; ++#else ++unsigned long usbip_debug_flag; ++#endif ++EXPORT_SYMBOL_GPL(usbip_debug_flag); ++ ++ ++/* FIXME */ ++struct device_attribute dev_attr_usbip_debug; ++EXPORT_SYMBOL_GPL(dev_attr_usbip_debug); ++ ++ ++static ssize_t show_flag(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf, "%lx\n", usbip_debug_flag); ++} ++ ++static ssize_t store_flag(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long flag; ++ ++ sscanf(buf, "%lx", &flag); ++ usbip_debug_flag = flag; ++ ++ return count; ++} ++DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag); ++ ++static void usbip_dump_buffer(char *buff, int bufflen) ++{ ++ int i; ++ ++ if (bufflen > 128) { ++ for (i = 0; i < 128; i++) { ++ if (i%24 == 0) ++ printk(" "); ++ printk("%02x ", (unsigned char) buff[i]); ++ if (i%4 == 3) ++ printk("| "); ++ if (i%24 == 23) ++ printk("\n"); ++ } ++ printk("... (%d byte)\n", bufflen); ++ return; ++ } ++ ++ for (i = 0; i < bufflen; i++) { ++ if (i%24 == 0) ++ printk(" "); ++ printk("%02x ", (unsigned char) buff[i]); ++ if (i%4 == 3) ++ printk("| "); ++ if (i%24 == 23) ++ printk("\n"); ++ } ++ printk("\n"); ++ ++} ++ ++static void usbip_dump_pipe(unsigned int p) ++{ ++ unsigned char type = usb_pipetype(p); ++ unsigned char ep = usb_pipeendpoint(p); ++ unsigned char dev = usb_pipedevice(p); ++ unsigned char dir = usb_pipein(p); ++ ++ printk("dev(%d) ", dev); ++ printk("ep(%d) ", ep); ++ printk("%s ", dir ? "IN" : "OUT"); ++ ++ switch (type) { ++ case PIPE_ISOCHRONOUS: ++ printk("%s ", "ISO"); ++ break; ++ case PIPE_INTERRUPT: ++ printk("%s ", "INT"); ++ break; ++ case PIPE_CONTROL: ++ printk("%s ", "CTL"); ++ break; ++ case PIPE_BULK: ++ printk("%s ", "BLK"); ++ break; ++ default: ++ printk("ERR"); ++ } ++ ++ printk("\n"); ++ ++} ++ ++static void usbip_dump_usb_device(struct usb_device *udev) ++{ ++ struct device *dev = &udev->dev; ++ int i; ++ ++ dev_dbg(dev, " devnum(%d) devpath(%s)", ++ udev->devnum, udev->devpath); ++ ++ switch (udev->speed) { ++ case USB_SPEED_HIGH: ++ printk(" SPD_HIGH"); ++ break; ++ case USB_SPEED_FULL: ++ printk(" SPD_FULL"); ++ break; ++ case USB_SPEED_LOW: ++ printk(" SPD_LOW"); ++ break; ++ case USB_SPEED_UNKNOWN: ++ printk(" SPD_UNKNOWN"); ++ break; ++ default: ++ printk(" SPD_ERROR"); ++ } ++ ++ printk(" tt %p, ttport %d", udev->tt, udev->ttport); ++ printk("\n"); ++ ++ dev_dbg(dev, " "); ++ for (i = 0; i < 16; i++) ++ printk(" %2u", i); ++ printk("\n"); ++ ++ dev_dbg(dev, " toggle0(IN) :"); ++ for (i = 0; i < 16; i++) ++ printk(" %2u", (udev->toggle[0] & (1 << i)) ? 1 : 0); ++ printk("\n"); ++ ++ dev_dbg(dev, " toggle1(OUT):"); ++ for (i = 0; i < 16; i++) ++ printk(" %2u", (udev->toggle[1] & (1 << i)) ? 1 : 0); ++ printk("\n"); ++ ++ ++ dev_dbg(dev, " epmaxp_in :"); ++ for (i = 0; i < 16; i++) { ++ if (udev->ep_in[i]) ++ printk(" %2u", ++ le16_to_cpu(udev->ep_in[i]->desc.wMaxPacketSize)); ++ } ++ printk("\n"); ++ ++ dev_dbg(dev, " epmaxp_out :"); ++ for (i = 0; i < 16; i++) { ++ if (udev->ep_out[i]) ++ printk(" %2u", ++ le16_to_cpu(udev->ep_out[i]->desc.wMaxPacketSize)); ++ } ++ printk("\n"); ++ ++ dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus); ++ ++ dev_dbg(dev, "descriptor %p, config %p, actconfig %p, " ++ "rawdescriptors %p\n", &udev->descriptor, udev->config, ++ udev->actconfig, udev->rawdescriptors); ++ ++ dev_dbg(dev, "have_langid %d, string_langid %d\n", ++ udev->have_langid, udev->string_langid); ++ ++ dev_dbg(dev, "maxchild %d, children %p\n", ++ udev->maxchild, udev->children); ++} ++ ++static void usbip_dump_request_type(__u8 rt) ++{ ++ switch (rt & USB_RECIP_MASK) { ++ case USB_RECIP_DEVICE: ++ printk("DEVICE"); ++ break; ++ case USB_RECIP_INTERFACE: ++ printk("INTERF"); ++ break; ++ case USB_RECIP_ENDPOINT: ++ printk("ENDPOI"); ++ break; ++ case USB_RECIP_OTHER: ++ printk("OTHER "); ++ break; ++ default: ++ printk("------"); ++ } ++} ++ ++static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd) ++{ ++ if (!cmd) { ++ printk(" %s : null pointer\n", __FUNCTION__); ++ return; ++ } ++ ++ printk(" "); ++ printk("bRequestType(%02X) ", cmd->bRequestType); ++ printk("bRequest(%02X) " , cmd->bRequest); ++ printk("wValue(%04X) ", cmd->wValue); ++ printk("wIndex(%04X) ", cmd->wIndex); ++ printk("wLength(%04X) ", cmd->wLength); ++ ++ printk("\n "); ++ ++ if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { ++ printk("STANDARD "); ++ switch (cmd->bRequest) { ++ case USB_REQ_GET_STATUS: ++ printk("GET_STATUS"); ++ break; ++ case USB_REQ_CLEAR_FEATURE: ++ printk("CLEAR_FEAT"); ++ break; ++ case USB_REQ_SET_FEATURE: ++ printk("SET_FEAT "); ++ break; ++ case USB_REQ_SET_ADDRESS: ++ printk("SET_ADDRRS"); ++ break; ++ case USB_REQ_GET_DESCRIPTOR: ++ printk("GET_DESCRI"); ++ break; ++ case USB_REQ_SET_DESCRIPTOR: ++ printk("SET_DESCRI"); ++ break; ++ case USB_REQ_GET_CONFIGURATION: ++ printk("GET_CONFIG"); ++ break; ++ case USB_REQ_SET_CONFIGURATION: ++ printk("SET_CONFIG"); ++ break; ++ case USB_REQ_GET_INTERFACE: ++ printk("GET_INTERF"); ++ break; ++ case USB_REQ_SET_INTERFACE: ++ printk("SET_INTERF"); ++ break; ++ case USB_REQ_SYNCH_FRAME: ++ printk("SYNC_FRAME"); ++ break; ++ default: ++ printk("REQ(%02X) ", cmd->bRequest); ++ } ++ ++ printk(" "); ++ usbip_dump_request_type(cmd->bRequestType); ++ ++ } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) ++ printk("CLASS "); ++ ++ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) ++ printk("VENDOR "); ++ ++ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_RESERVED) ++ printk("RESERVED"); ++ ++ printk("\n"); ++} ++ ++void usbip_dump_urb(struct urb *urb) ++{ ++ struct device *dev; ++ ++ if (!urb) { ++ printk(KERN_DEBUG KBUILD_MODNAME ++ ":%s: urb: null pointer!!\n", __func__); ++ return; ++ } ++ ++ if (!urb->dev) { ++ printk(KERN_DEBUG KBUILD_MODNAME ++ ":%s: urb->dev: null pointer!!\n", __func__); ++ return; ++ } ++ dev = &urb->dev->dev; ++ ++ dev_dbg(dev, " urb :%p\n", urb); ++ dev_dbg(dev, " dev :%p\n", urb->dev); ++ ++ usbip_dump_usb_device(urb->dev); ++ ++ dev_dbg(dev, " pipe :%08x ", urb->pipe); ++ ++ usbip_dump_pipe(urb->pipe); ++ ++ dev_dbg(dev, " status :%d\n", urb->status); ++ dev_dbg(dev, " transfer_flags :%08X\n", urb->transfer_flags); ++ dev_dbg(dev, " transfer_buffer :%p\n", urb->transfer_buffer); ++ dev_dbg(dev, " transfer_buffer_length:%d\n", urb->transfer_buffer_length); ++ dev_dbg(dev, " actual_length :%d\n", urb->actual_length); ++ dev_dbg(dev, " setup_packet :%p\n", urb->setup_packet); ++ ++ if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL) ++ usbip_dump_usb_ctrlrequest( ++ (struct usb_ctrlrequest *)urb->setup_packet); ++ ++ dev_dbg(dev, " start_frame :%d\n", urb->start_frame); ++ dev_dbg(dev, " number_of_packets :%d\n", urb->number_of_packets); ++ dev_dbg(dev, " interval :%d\n", urb->interval); ++ dev_dbg(dev, " error_count :%d\n", urb->error_count); ++ dev_dbg(dev, " context :%p\n", urb->context); ++ dev_dbg(dev, " complete :%p\n", urb->complete); ++} ++EXPORT_SYMBOL_GPL(usbip_dump_urb); ++ ++void usbip_dump_header(struct usbip_header *pdu) ++{ ++ udbg("BASE: cmd %u seq %u devid %u dir %u ep %u\n", ++ pdu->base.command, ++ pdu->base.seqnum, ++ pdu->base.devid, ++ pdu->base.direction, ++ pdu->base.ep); ++ ++ switch (pdu->base.command) { ++ case USBIP_CMD_SUBMIT: ++ udbg("CMD_SUBMIT: x_flags %u x_len %u sf %u #p %u iv %u\n", ++ pdu->u.cmd_submit.transfer_flags, ++ pdu->u.cmd_submit.transfer_buffer_length, ++ pdu->u.cmd_submit.start_frame, ++ pdu->u.cmd_submit.number_of_packets, ++ pdu->u.cmd_submit.interval); ++ break; ++ case USBIP_CMD_UNLINK: ++ udbg("CMD_UNLINK: seq %u\n", pdu->u.cmd_unlink.seqnum); ++ break; ++ case USBIP_RET_SUBMIT: ++ udbg("RET_SUBMIT: st %d al %u sf %d ec %d\n", ++ pdu->u.ret_submit.status, ++ pdu->u.ret_submit.actual_length, ++ pdu->u.ret_submit.start_frame, ++ pdu->u.ret_submit.error_count); ++ case USBIP_RET_UNLINK: ++ udbg("RET_UNLINK: status %d\n", pdu->u.ret_unlink.status); ++ break; ++ default: ++ /* NOT REACHED */ ++ udbg("UNKNOWN\n"); ++ } ++} ++EXPORT_SYMBOL_GPL(usbip_dump_header); ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* thread routines */ ++ ++int usbip_thread(void *param) ++{ ++ struct usbip_task *ut = param; ++ ++ if (!ut) ++ return -EINVAL; ++ ++ lock_kernel(); ++ daemonize(ut->name); ++ allow_signal(SIGKILL); ++ ut->thread = current; ++ unlock_kernel(); ++ ++ /* srv.rb must wait for rx_thread starting */ ++ complete(&ut->thread_done); ++ ++ /* start of while loop */ ++ ut->loop_ops(ut); ++ ++ /* end of loop */ ++ ut->thread = NULL; ++ ++ complete_and_exit(&ut->thread_done, 0); ++} ++ ++void usbip_start_threads(struct usbip_device *ud) ++{ ++ /* ++ * threads are invoked per one device (per one connection). ++ */ ++ kernel_thread(usbip_thread, (void *)&ud->tcp_rx, 0); ++ kernel_thread(usbip_thread, (void *)&ud->tcp_tx, 0); ++ ++ /* confirm threads are starting */ ++ wait_for_completion(&ud->tcp_rx.thread_done); ++ wait_for_completion(&ud->tcp_tx.thread_done); ++} ++EXPORT_SYMBOL_GPL(usbip_start_threads); ++ ++void usbip_stop_threads(struct usbip_device *ud) ++{ ++ /* kill threads related to this sdev, if v.c. exists */ ++ if (ud->tcp_rx.thread != NULL) { ++ send_sig(SIGKILL, ud->tcp_rx.thread, 1); ++ wait_for_completion(&ud->tcp_rx.thread_done); ++ udbg("rx_thread for ud %p has finished\n", ud); ++ } ++ ++ if (ud->tcp_tx.thread != NULL) { ++ send_sig(SIGKILL, ud->tcp_tx.thread, 1); ++ wait_for_completion(&ud->tcp_tx.thread_done); ++ udbg("tx_thread for ud %p has finished\n", ud); ++ } ++} ++EXPORT_SYMBOL_GPL(usbip_stop_threads); ++ ++void usbip_task_init(struct usbip_task *ut, char *name, ++ void (*loop_ops)(struct usbip_task *)) ++{ ++ ut->thread = NULL; ++ init_completion(&ut->thread_done); ++ ut->name = name; ++ ut->loop_ops = loop_ops; ++} ++EXPORT_SYMBOL_GPL(usbip_task_init); ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* socket routines */ ++ ++ /* Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */ ++int usbip_xmit(int send, struct socket *sock, char *buf, ++ int size, int msg_flags) ++{ ++ int result; ++ struct msghdr msg; ++ struct kvec iov; ++ int total = 0; ++ ++ /* for blocks of if (dbg_flag_xmit) */ ++ char *bp = buf; ++ int osize = size; ++ ++ dbg_xmit("enter\n"); ++ ++ if (!sock || !buf || !size) { ++ printk(KERN_ERR "%s: invalid arg, sock %p buff %p size %d\n", ++ __func__, sock, buf, size); ++ return -EINVAL; ++ } ++ ++ ++ if (dbg_flag_xmit) { ++ if (send) { ++ if (!in_interrupt()) ++ printk(KERN_DEBUG "%-10s:", current->comm); ++ else ++ printk(KERN_DEBUG "interupt :"); ++ ++ printk("%s: sending... , sock %p, buf %p, " ++ "size %d, msg_flags %d\n", __func__, ++ sock, buf, size, msg_flags); ++ usbip_dump_buffer(buf, size); ++ } ++ } ++ ++ ++ do { ++ sock->sk->sk_allocation = GFP_NOIO; ++ iov.iov_base = buf; ++ iov.iov_len = size; ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ msg.msg_namelen = 0; ++ msg.msg_flags = msg_flags | MSG_NOSIGNAL; ++ ++ if (send) ++ result = kernel_sendmsg(sock, &msg, &iov, 1, size); ++ else ++ result = kernel_recvmsg(sock, &msg, &iov, 1, size, ++ MSG_WAITALL); ++ ++ if (result <= 0) { ++ udbg("usbip_xmit: %s sock %p buf %p size %u ret %d" ++ " total %d\n", ++ send ? "send" : "receive", sock, buf, ++ size, result, total); ++ goto err; ++ } ++ ++ size -= result; ++ buf += result; ++ total += result; ++ ++ } while (size > 0); ++ ++ ++ if (dbg_flag_xmit) { ++ if (!send) { ++ if (!in_interrupt()) ++ printk(KERN_DEBUG "%-10s:", current->comm); ++ else ++ printk(KERN_DEBUG "interupt :"); ++ ++ printk("usbip_xmit: receiving....\n"); ++ usbip_dump_buffer(bp, osize); ++ printk("usbip_xmit: received, osize %d ret %d size %d " ++ "total %d\n", osize, result, size, ++ total); ++ } ++ ++ if (send) ++ printk("usbip_xmit: send, total %d\n", total); ++ } ++ ++ return total; ++ ++err: ++ return result; ++} ++EXPORT_SYMBOL_GPL(usbip_xmit); ++ ++ ++/* now a usrland utility should set options. */ ++#if 0 ++int setquickack(struct socket *socket) ++{ ++ mm_segment_t oldfs; ++ int val = 1; ++ int ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_QUICKACK, ++ (char __user *) &val, sizeof(ret)); ++ set_fs(oldfs); ++ ++ return ret; ++} ++ ++int setnodelay(struct socket *socket) ++{ ++ mm_segment_t oldfs; ++ int val = 1; ++ int ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_NODELAY, ++ (char __user *) &val, sizeof(ret)); ++ set_fs(oldfs); ++ ++ return ret; ++} ++ ++int setkeepalive(struct socket *socket) ++{ ++ mm_segment_t oldfs; ++ int val = 1; ++ int ret; ++ ++ oldfs = get_fs(); ++ set_fs(get_ds()); ++ ret = socket->ops->setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, ++ (char __user *) &val, sizeof(ret)); ++ set_fs(oldfs); ++ ++ return ret; ++} ++ ++void setreuse(struct socket *socket) ++{ ++ socket->sk->sk_reuse = 1; ++} ++#endif ++ ++struct socket *sockfd_to_socket(unsigned int sockfd) ++{ ++ struct socket *socket; ++ struct file *file; ++ struct inode *inode; ++ ++ file = fget(sockfd); ++ if (!file) { ++ printk(KERN_ERR "%s: invalid sockfd\n", __func__); ++ return NULL; ++ } ++ ++ inode = file->f_dentry->d_inode; ++ ++ if (!inode || !S_ISSOCK(inode->i_mode)) ++ return NULL; ++ ++ socket = SOCKET_I(inode); ++ ++ return socket; ++} ++EXPORT_SYMBOL_GPL(sockfd_to_socket); ++ ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* pdu routines */ ++ ++/* there may be more cases to tweak the flags. */ ++static unsigned int tweak_transfer_flags(unsigned int flags) ++{ ++ ++ if (flags & URB_NO_TRANSFER_DMA_MAP) ++ /* ++ * vhci_hcd does not provide DMA-mapped I/O. The upper ++ * driver does not need to set this flag. The remote ++ * usbip.ko does not still perform DMA-mapped I/O for ++ * DMA-caplable host controllers. So, clear this flag. ++ */ ++ flags &= ~URB_NO_TRANSFER_DMA_MAP; ++ ++ if (flags & URB_NO_SETUP_DMA_MAP) ++ flags &= ~URB_NO_SETUP_DMA_MAP; ++ ++ return flags; ++} ++ ++static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb, ++ int pack) ++{ ++ struct usbip_header_cmd_submit *spdu = &pdu->u.cmd_submit; ++ ++ /* ++ * Some members are not still implemented in usbip. I hope this issue ++ * will be discussed when usbip is ported to other operating systems. ++ */ ++ if (pack) { ++ /* vhci_tx.c */ ++ spdu->transfer_flags = ++ tweak_transfer_flags(urb->transfer_flags); ++ spdu->transfer_buffer_length = urb->transfer_buffer_length; ++ spdu->start_frame = urb->start_frame; ++ spdu->number_of_packets = urb->number_of_packets; ++ spdu->interval = urb->interval; ++ } else { ++ /* stub_rx.c */ ++ urb->transfer_flags = spdu->transfer_flags; ++ ++ urb->transfer_buffer_length = spdu->transfer_buffer_length; ++ urb->start_frame = spdu->start_frame; ++ urb->number_of_packets = spdu->number_of_packets; ++ urb->interval = spdu->interval; ++ } ++} ++ ++static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb, ++ int pack) ++{ ++ struct usbip_header_ret_submit *rpdu = &pdu->u.ret_submit; ++ ++ if (pack) { ++ /* stub_tx.c */ ++ ++ rpdu->status = urb->status; ++ rpdu->actual_length = urb->actual_length; ++ rpdu->start_frame = urb->start_frame; ++ rpdu->error_count = urb->error_count; ++ } else { ++ /* vhci_rx.c */ ++ ++ urb->status = rpdu->status; ++ urb->actual_length = rpdu->actual_length; ++ urb->start_frame = rpdu->start_frame; ++ urb->error_count = rpdu->error_count; ++ } ++} ++ ++ ++void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, ++ int pack) ++{ ++ switch (cmd) { ++ case USBIP_CMD_SUBMIT: ++ usbip_pack_cmd_submit(pdu, urb, pack); ++ break; ++ case USBIP_RET_SUBMIT: ++ usbip_pack_ret_submit(pdu, urb, pack); ++ break; ++ default: ++ err("unknown command"); ++ /* NOTREACHED */ ++ /* BUG(); */ ++ } ++} ++EXPORT_SYMBOL_GPL(usbip_pack_pdu); ++ ++ ++static void correct_endian_basic(struct usbip_header_basic *base, int send) ++{ ++ if (send) { ++ base->command = cpu_to_be32(base->command); ++ base->seqnum = cpu_to_be32(base->seqnum); ++ base->devid = cpu_to_be32(base->devid); ++ base->direction = cpu_to_be32(base->direction); ++ base->ep = cpu_to_be32(base->ep); ++ } else { ++ base->command = be32_to_cpu(base->command); ++ base->seqnum = be32_to_cpu(base->seqnum); ++ base->devid = be32_to_cpu(base->devid); ++ base->direction = be32_to_cpu(base->direction); ++ base->ep = be32_to_cpu(base->ep); ++ } ++} ++ ++static void correct_endian_cmd_submit(struct usbip_header_cmd_submit *pdu, ++ int send) ++{ ++ if (send) { ++ pdu->transfer_flags = cpu_to_be32(pdu->transfer_flags); ++ ++ cpu_to_be32s(&pdu->transfer_buffer_length); ++ cpu_to_be32s(&pdu->start_frame); ++ cpu_to_be32s(&pdu->number_of_packets); ++ cpu_to_be32s(&pdu->interval); ++ } else { ++ pdu->transfer_flags = be32_to_cpu(pdu->transfer_flags); ++ ++ be32_to_cpus(&pdu->transfer_buffer_length); ++ be32_to_cpus(&pdu->start_frame); ++ be32_to_cpus(&pdu->number_of_packets); ++ be32_to_cpus(&pdu->interval); ++ } ++} ++ ++static void correct_endian_ret_submit(struct usbip_header_ret_submit *pdu, ++ int send) ++{ ++ if (send) { ++ cpu_to_be32s(&pdu->status); ++ cpu_to_be32s(&pdu->actual_length); ++ cpu_to_be32s(&pdu->start_frame); ++ cpu_to_be32s(&pdu->error_count); ++ } else { ++ be32_to_cpus(&pdu->status); ++ be32_to_cpus(&pdu->actual_length); ++ be32_to_cpus(&pdu->start_frame); ++ be32_to_cpus(&pdu->error_count); ++ } ++} ++ ++static void correct_endian_cmd_unlink(struct usbip_header_cmd_unlink *pdu, ++ int send) ++{ ++ if (send) ++ pdu->seqnum = cpu_to_be32(pdu->seqnum); ++ else ++ pdu->seqnum = be32_to_cpu(pdu->seqnum); ++} ++ ++static void correct_endian_ret_unlink(struct usbip_header_ret_unlink *pdu, ++ int send) ++{ ++ if (send) ++ cpu_to_be32s(&pdu->status); ++ else ++ be32_to_cpus(&pdu->status); ++} ++ ++void usbip_header_correct_endian(struct usbip_header *pdu, int send) ++{ ++ __u32 cmd = 0; ++ ++ if (send) ++ cmd = pdu->base.command; ++ ++ correct_endian_basic(&pdu->base, send); ++ ++ if (!send) ++ cmd = pdu->base.command; ++ ++ switch (cmd) { ++ case USBIP_CMD_SUBMIT: ++ correct_endian_cmd_submit(&pdu->u.cmd_submit, send); ++ break; ++ case USBIP_RET_SUBMIT: ++ correct_endian_ret_submit(&pdu->u.ret_submit, send); ++ break; ++ case USBIP_CMD_UNLINK: ++ correct_endian_cmd_unlink(&pdu->u.cmd_unlink, send); ++ break; ++ case USBIP_RET_UNLINK: ++ correct_endian_ret_unlink(&pdu->u.ret_unlink, send); ++ break; ++ default: ++ /* NOTREACHED */ ++ err("unknown command in pdu header: %d", cmd); ++ /* BUG(); */ ++ } ++} ++EXPORT_SYMBOL_GPL(usbip_header_correct_endian); ++ ++static void usbip_iso_pakcet_correct_endian( ++ struct usbip_iso_packet_descriptor *iso, ++ int send) ++{ ++ /* does not need all members. but copy all simply. */ ++ if (send) { ++ iso->offset = cpu_to_be32(iso->offset); ++ iso->length = cpu_to_be32(iso->length); ++ iso->status = cpu_to_be32(iso->status); ++ iso->actual_length = cpu_to_be32(iso->actual_length); ++ } else { ++ iso->offset = be32_to_cpu(iso->offset); ++ iso->length = be32_to_cpu(iso->length); ++ iso->status = be32_to_cpu(iso->status); ++ iso->actual_length = be32_to_cpu(iso->actual_length); ++ } ++} ++ ++static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso, ++ struct usb_iso_packet_descriptor *uiso, int pack) ++{ ++ if (pack) { ++ iso->offset = uiso->offset; ++ iso->length = uiso->length; ++ iso->status = uiso->status; ++ iso->actual_length = uiso->actual_length; ++ } else { ++ uiso->offset = iso->offset; ++ uiso->length = iso->length; ++ uiso->status = iso->status; ++ uiso->actual_length = iso->actual_length; ++ } ++} ++ ++ ++/* must free buffer */ ++void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen) ++{ ++ void *buff; ++ struct usbip_iso_packet_descriptor *iso; ++ int np = urb->number_of_packets; ++ ssize_t size = np * sizeof(*iso); ++ int i; ++ ++ buff = kzalloc(size, GFP_KERNEL); ++ if (!buff) ++ return NULL; ++ ++ for (i = 0; i < np; i++) { ++ iso = buff + (i * sizeof(*iso)); ++ ++ usbip_pack_iso(iso, &urb->iso_frame_desc[i], 1); ++ usbip_iso_pakcet_correct_endian(iso, 1); ++ } ++ ++ *bufflen = size; ++ ++ return buff; ++} ++EXPORT_SYMBOL_GPL(usbip_alloc_iso_desc_pdu); ++ ++/* some members of urb must be substituted before. */ ++int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) ++{ ++ void *buff; ++ struct usbip_iso_packet_descriptor *iso; ++ int np = urb->number_of_packets; ++ int size = np * sizeof(*iso); ++ int i; ++ int ret; ++ ++ if (!usb_pipeisoc(urb->pipe)) ++ return 0; ++ ++ /* my Bluetooth dongle gets ISO URBs which are np = 0 */ ++ if (np == 0) { ++ /* uinfo("iso np == 0\n"); */ ++ /* usbip_dump_urb(urb); */ ++ return 0; ++ } ++ ++ buff = kzalloc(size, GFP_KERNEL); ++ if (!buff) ++ return -ENOMEM; ++ ++ ret = usbip_xmit(0, ud->tcp_socket, buff, size, 0); ++ if (ret != size) { ++ dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n", ++ ret); ++ kfree(buff); ++ ++ if (ud->side == USBIP_STUB) ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ else ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ ++ return -EPIPE; ++ } ++ ++ for (i = 0; i < np; i++) { ++ iso = buff + (i * sizeof(*iso)); ++ ++ usbip_iso_pakcet_correct_endian(iso, 0); ++ usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); ++ } ++ ++ ++ kfree(buff); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(usbip_recv_iso); ++ ++ ++/* some members of urb must be substituted before. */ ++int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) ++{ ++ int ret; ++ int size; ++ ++ if (ud->side == USBIP_STUB) { ++ /* stub_rx.c */ ++ /* the direction of urb must be OUT. */ ++ if (usb_pipein(urb->pipe)) ++ return 0; ++ ++ size = urb->transfer_buffer_length; ++ } else { ++ /* vhci_rx.c */ ++ /* the direction of urb must be IN. */ ++ if (usb_pipeout(urb->pipe)) ++ return 0; ++ ++ size = urb->actual_length; ++ } ++ ++ /* no need to recv xbuff */ ++ if (!(size > 0)) ++ return 0; ++ ++ ret = usbip_xmit(0, ud->tcp_socket, (char *)urb->transfer_buffer, ++ size, 0); ++ if (ret != size) { ++ dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); ++ if (ud->side == USBIP_STUB) { ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ } else { ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ return -EPIPE; ++ } ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(usbip_recv_xbuff); ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int __init usbip_common_init(void) ++{ ++ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "" DRIVER_VERSION); ++ ++ return 0; ++} ++ ++static void __exit usbip_common_exit(void) ++{ ++ return; ++} ++ ++ ++ ++ ++module_init(usbip_common_init); ++module_exit(usbip_common_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h +new file mode 100644 +index 0000000..b0186b7 +--- /dev/null ++++ b/drivers/staging/usbip/usbip_common.h +@@ -0,0 +1,406 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifndef __VHCI_COMMON_H ++#define __VHCI_COMMON_H ++ ++ ++#include ++#include ++#include ++#include ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * define macros to print messages ++ */ ++ ++/** ++ * udbg - print debug messages if CONFIG_USB_DEBUG is defined ++ * @fmt: ++ * @args: ++ */ ++ ++#ifdef CONFIG_USB_DEBUG ++ ++#define udbg(fmt, args...) \ ++ do { \ ++ printk(KERN_DEBUG "%-10s:(%s,%d) %s: " fmt, \ ++ (in_interrupt() ? "interrupt" : (current)->comm),\ ++ __FILE__, __LINE__, __func__, ##args); \ ++ } while (0) ++ ++#else /* CONFIG_USB_DEBUG */ ++ ++#define udbg(fmt, args...) do { } while (0) ++ ++#endif /* CONFIG_USB_DEBUG */ ++ ++ ++enum { ++ usbip_debug_xmit = (1 << 0), ++ usbip_debug_sysfs = (1 << 1), ++ usbip_debug_urb = (1 << 2), ++ usbip_debug_eh = (1 << 3), ++ ++ usbip_debug_stub_cmp = (1 << 8), ++ usbip_debug_stub_dev = (1 << 9), ++ usbip_debug_stub_rx = (1 << 10), ++ usbip_debug_stub_tx = (1 << 11), ++ ++ usbip_debug_vhci_rh = (1 << 8), ++ usbip_debug_vhci_hc = (1 << 9), ++ usbip_debug_vhci_rx = (1 << 10), ++ usbip_debug_vhci_tx = (1 << 11), ++ usbip_debug_vhci_sysfs = (1 << 12) ++}; ++ ++#define dbg_flag_xmit (usbip_debug_flag & usbip_debug_xmit) ++#define dbg_flag_vhci_rh (usbip_debug_flag & usbip_debug_vhci_rh) ++#define dbg_flag_vhci_hc (usbip_debug_flag & usbip_debug_vhci_hc) ++#define dbg_flag_vhci_rx (usbip_debug_flag & usbip_debug_vhci_rx) ++#define dbg_flag_vhci_tx (usbip_debug_flag & usbip_debug_vhci_tx) ++#define dbg_flag_vhci_sysfs (usbip_debug_flag & usbip_debug_vhci_sysfs) ++#define dbg_flag_stub_rx (usbip_debug_flag & usbip_debug_stub_rx) ++#define dbg_flag_stub_tx (usbip_debug_flag & usbip_debug_stub_tx) ++ ++extern unsigned long usbip_debug_flag; ++extern struct device_attribute dev_attr_usbip_debug; ++ ++#define dbg_with_flag(flag, fmt, args...) \ ++ do { \ ++ if (flag & usbip_debug_flag) \ ++ udbg(fmt , ##args); \ ++ } while (0) ++ ++#define dbg_sysfs(fmt, args...) \ ++ dbg_with_flag(usbip_debug_sysfs, fmt , ##args) ++#define dbg_xmit(fmt, args...) \ ++ dbg_with_flag(usbip_debug_xmit, fmt , ##args) ++#define dbg_urb(fmt, args...) \ ++ dbg_with_flag(usbip_debug_urb, fmt , ##args) ++#define dbg_eh(fmt, args...) \ ++ dbg_with_flag(usbip_debug_eh, fmt , ##args) ++ ++#define dbg_vhci_rh(fmt, args...) \ ++ dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args) ++#define dbg_vhci_hc(fmt, args...) \ ++ dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args) ++#define dbg_vhci_rx(fmt, args...) \ ++ dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args) ++#define dbg_vhci_tx(fmt, args...) \ ++ dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args) ++#define dbg_vhci_sysfs(fmt, args...) \ ++ dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args) ++ ++#define dbg_stub_cmp(fmt, args...) \ ++ dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args) ++#define dbg_stub_rx(fmt, args...) \ ++ dbg_with_flag(usbip_debug_stub_rx, fmt , ##args) ++#define dbg_stub_tx(fmt, args...) \ ++ dbg_with_flag(usbip_debug_stub_tx, fmt , ##args) ++ ++ ++/** ++ * uerr - print error messages ++ * @fmt: ++ * @args: ++ */ ++#define uerr(fmt, args...) \ ++ do { \ ++ printk(KERN_ERR "%-10s: ***ERROR*** (%s,%d) %s: " fmt, \ ++ (in_interrupt() ? "interrupt" : (current)->comm),\ ++ __FILE__, __LINE__, __func__, ##args); \ ++ } while (0) ++ ++/** ++ * uinfo - print information messages ++ * @fmt: ++ * @args: ++ */ ++#define uinfo(fmt, args...) \ ++ do { \ ++ printk(KERN_INFO "usbip: " fmt , ## args); \ ++ } while (0) ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * USB/IP request headers. ++ * Currently, we define 4 request types: ++ * ++ * - CMD_SUBMIT transfers a USB request, corresponding to usb_submit_urb(). ++ * (client to server) ++ * - RET_RETURN transfers the result of CMD_SUBMIT. ++ * (server to client) ++ * - CMD_UNLINK transfers an unlink request of a pending USB request. ++ * (client to server) ++ * - RET_UNLINK transfers the result of CMD_UNLINK. ++ * (server to client) ++ * ++ * Note: The below request formats are based on the USB subsystem of Linux. Its ++ * details will be defined when other implementations come. ++ * ++ * ++ */ ++ ++/* ++ * A basic header followed by other additional headers. ++ */ ++struct usbip_header_basic { ++#define USBIP_CMD_SUBMIT 0x0001 ++#define USBIP_CMD_UNLINK 0x0002 ++#define USBIP_RET_SUBMIT 0x0003 ++#define USBIP_RET_UNLINK 0x0004 ++ __u32 command; ++ ++ /* sequencial number which identifies requests. ++ * incremented per connections */ ++ __u32 seqnum; ++ ++ /* devid is used to specify a remote USB device uniquely instead ++ * of busnum and devnum in Linux. In the case of Linux stub_driver, ++ * this value is ((busnum << 16) | devnum) */ ++ __u32 devid; ++ ++#define USBIP_DIR_OUT 0 ++#define USBIP_DIR_IN 1 ++ __u32 direction; ++ __u32 ep; /* endpoint number */ ++} __attribute__ ((packed)); ++ ++/* ++ * An additional header for a CMD_SUBMIT packet. ++ */ ++struct usbip_header_cmd_submit { ++ /* these values are basically the same as in a URB. */ ++ ++ /* the same in a URB. */ ++ __u32 transfer_flags; ++ ++ /* set the following data size (out), ++ * or expected reading data size (in) */ ++ __s32 transfer_buffer_length; ++ ++ /* it is difficult for usbip to sync frames (reserved only?) */ ++ __s32 start_frame; ++ ++ /* the number of iso descriptors that follows this header */ ++ __s32 number_of_packets; ++ ++ /* the maximum time within which this request works in a host ++ * controller of a server side */ ++ __s32 interval; ++ ++ /* set setup packet data for a CTRL request */ ++ unsigned char setup[8]; ++} __attribute__ ((packed)); ++ ++/* ++ * An additional header for a RET_SUBMIT packet. ++ */ ++struct usbip_header_ret_submit { ++ __s32 status; ++ __s32 actual_length; /* returned data length */ ++ __s32 start_frame; /* ISO and INT */ ++ __s32 number_of_packets; /* ISO only */ ++ __s32 error_count; /* ISO only */ ++} __attribute__ ((packed)); ++ ++/* ++ * An additional header for a CMD_UNLINK packet. ++ */ ++struct usbip_header_cmd_unlink { ++ __u32 seqnum; /* URB's seqnum which will be unlinked */ ++} __attribute__ ((packed)); ++ ++ ++/* ++ * An additional header for a RET_UNLINK packet. ++ */ ++struct usbip_header_ret_unlink { ++ __s32 status; ++} __attribute__ ((packed)); ++ ++ ++/* the same as usb_iso_packet_descriptor but packed for pdu */ ++struct usbip_iso_packet_descriptor { ++ __u32 offset; ++ __u32 length; /* expected length */ ++ __u32 actual_length; ++ __u32 status; ++} __attribute__ ((packed)); ++ ++ ++/* ++ * All usbip packets use a common header to keep code simple. ++ */ ++struct usbip_header { ++ struct usbip_header_basic base; ++ ++ union { ++ struct usbip_header_cmd_submit cmd_submit; ++ struct usbip_header_ret_submit ret_submit; ++ struct usbip_header_cmd_unlink cmd_unlink; ++ struct usbip_header_ret_unlink ret_unlink; ++ } u; ++} __attribute__ ((packed)); ++ ++ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++ ++int usbip_xmit(int, struct socket *, char *, int, int); ++int usbip_sendmsg(struct socket *, struct msghdr *, int); ++ ++ ++static inline int interface_to_busnum(struct usb_interface *interface) ++{ ++ struct usb_device *udev = interface_to_usbdev(interface); ++ return udev->bus->busnum; ++} ++ ++static inline int interface_to_devnum(struct usb_interface *interface) ++{ ++ struct usb_device *udev = interface_to_usbdev(interface); ++ return udev->devnum; ++} ++ ++static inline int interface_to_infnum(struct usb_interface *interface) ++{ ++ return interface->cur_altsetting->desc.bInterfaceNumber; ++} ++ ++#if 0 ++int setnodelay(struct socket *); ++int setquickack(struct socket *); ++int setkeepalive(struct socket *socket); ++void setreuse(struct socket *); ++#endif ++ ++struct socket *sockfd_to_socket(unsigned int); ++int set_sockaddr(struct socket *socket, struct sockaddr_storage *ss); ++ ++void usbip_dump_urb(struct urb *purb); ++void usbip_dump_header(struct usbip_header *pdu); ++ ++ ++struct usbip_device; ++ ++struct usbip_task { ++ struct task_struct *thread; ++ struct completion thread_done; ++ char *name; ++ void (*loop_ops)(struct usbip_task *); ++}; ++ ++enum usbip_side { ++ USBIP_VHCI, ++ USBIP_STUB, ++}; ++ ++enum usbip_status { ++ /* sdev is available. */ ++ SDEV_ST_AVAILABLE = 0x01, ++ /* sdev is now used. */ ++ SDEV_ST_USED, ++ /* sdev is unusable because of a fatal error. */ ++ SDEV_ST_ERROR, ++ ++ /* vdev does not connect a remote device. */ ++ VDEV_ST_NULL, ++ /* vdev is used, but the USB address is not assigned yet */ ++ VDEV_ST_NOTASSIGNED, ++ VDEV_ST_USED, ++ VDEV_ST_ERROR ++}; ++ ++/* a common structure for stub_device and vhci_device */ ++struct usbip_device { ++ enum usbip_side side; ++ ++ enum usbip_status status; ++ ++ /* lock for status */ ++ spinlock_t lock; ++ ++ struct socket *tcp_socket; ++ ++ struct usbip_task tcp_rx; ++ struct usbip_task tcp_tx; ++ ++ /* event handler */ ++#define USBIP_EH_SHUTDOWN (1 << 0) ++#define USBIP_EH_BYE (1 << 1) ++#define USBIP_EH_RESET (1 << 2) ++#define USBIP_EH_UNUSABLE (1 << 3) ++ ++#define SDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE) ++#define SDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) ++#define SDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) ++#define SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) ++#define SDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) ++ ++#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE) ++#define VDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) ++#define VDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) ++#define VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) ++ ++ unsigned long event; ++ struct usbip_task eh; ++ wait_queue_head_t eh_waitq; ++ ++ struct eh_ops { ++ void (*shutdown)(struct usbip_device *); ++ void (*reset)(struct usbip_device *); ++ void (*unusable)(struct usbip_device *); ++ } eh_ops; ++}; ++ ++ ++void usbip_task_init(struct usbip_task *ut, char *, ++ void (*loop_ops)(struct usbip_task *)); ++ ++void usbip_start_threads(struct usbip_device *ud); ++void usbip_stop_threads(struct usbip_device *ud); ++int usbip_thread(void *param); ++ ++void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, ++ int pack); ++ ++void usbip_header_correct_endian(struct usbip_header *pdu, int send); ++/* some members of urb must be substituted before. */ ++int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); ++/* some members of urb must be substituted before. */ ++int usbip_recv_iso(struct usbip_device *ud, struct urb *urb); ++void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); ++ ++ ++/* usbip_event.c */ ++void usbip_start_eh(struct usbip_device *ud); ++void usbip_stop_eh(struct usbip_device *ud); ++void usbip_event_add(struct usbip_device *ud, unsigned long event); ++int usbip_event_happend(struct usbip_device *ud); ++ ++ ++#endif +diff --git a/drivers/staging/usbip/usbip_event.c b/drivers/staging/usbip/usbip_event.c +new file mode 100644 +index 0000000..4318553 +--- /dev/null ++++ b/drivers/staging/usbip/usbip_event.c +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++ ++static int event_handler(struct usbip_device *ud) ++{ ++ dbg_eh("enter\n"); ++ ++ /* ++ * Events are handled by only this thread. ++ */ ++ while (usbip_event_happend(ud)) { ++ dbg_eh("pending event %lx\n", ud->event); ++ ++ /* ++ * NOTE: shutdown must come first. ++ * Shutdown the device. ++ */ ++ if (ud->event & USBIP_EH_SHUTDOWN) { ++ ud->eh_ops.shutdown(ud); ++ ++ ud->event &= ~USBIP_EH_SHUTDOWN; ++ ++ break; ++ } ++ ++ /* Stop the error handler. */ ++ if (ud->event & USBIP_EH_BYE) ++ return -1; ++ ++ /* Reset the device. */ ++ if (ud->event & USBIP_EH_RESET) { ++ ud->eh_ops.reset(ud); ++ ++ ud->event &= ~USBIP_EH_RESET; ++ ++ break; ++ } ++ ++ /* Mark the device as unusable. */ ++ if (ud->event & USBIP_EH_UNUSABLE) { ++ ud->eh_ops.unusable(ud); ++ ++ ud->event &= ~USBIP_EH_UNUSABLE; ++ ++ break; ++ } ++ ++ /* NOTREACHED */ ++ printk(KERN_ERR "%s: unknown event\n", __func__); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void event_handler_loop(struct usbip_task *ut) ++{ ++ struct usbip_device *ud = container_of(ut, struct usbip_device, eh); ++ ++ while (1) { ++ if (signal_pending(current)) { ++ dbg_eh("signal catched!\n"); ++ break; ++ } ++ ++ if (event_handler(ud) < 0) ++ break; ++ ++ wait_event_interruptible(ud->eh_waitq, usbip_event_happend(ud)); ++ dbg_eh("wakeup\n"); ++ } ++} ++ ++void usbip_start_eh(struct usbip_device *ud) ++{ ++ struct usbip_task *eh = &ud->eh; ++ ++ init_waitqueue_head(&ud->eh_waitq); ++ ud->event = 0; ++ ++ usbip_task_init(eh, "usbip_eh", event_handler_loop); ++ ++ kernel_thread(usbip_thread, (void *)eh, 0); ++ ++ wait_for_completion(&eh->thread_done); ++} ++EXPORT_SYMBOL_GPL(usbip_start_eh); ++ ++void usbip_stop_eh(struct usbip_device *ud) ++{ ++ struct usbip_task *eh = &ud->eh; ++ ++ wait_for_completion(&eh->thread_done); ++ dbg_eh("usbip_eh has finished\n"); ++} ++EXPORT_SYMBOL_GPL(usbip_stop_eh); ++ ++void usbip_event_add(struct usbip_device *ud, unsigned long event) ++{ ++ spin_lock(&ud->lock); ++ ++ ud->event |= event; ++ ++ wake_up(&ud->eh_waitq); ++ ++ spin_unlock(&ud->lock); ++} ++EXPORT_SYMBOL_GPL(usbip_event_add); ++ ++int usbip_event_happend(struct usbip_device *ud) ++{ ++ int happend = 0; ++ ++ spin_lock(&ud->lock); ++ ++ if (ud->event != 0) ++ happend = 1; ++ ++ spin_unlock(&ud->lock); ++ ++ return happend; ++} ++EXPORT_SYMBOL_GPL(usbip_event_happend); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0012-Staging-USB-IP-add-client-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0012-Staging-USB-IP-add-client-driver.patch new file mode 100644 index 000000000..c872321a3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0012-Staging-USB-IP-add-client-driver.patch @@ -0,0 +1,2252 @@ +From 04679b3489e048cd5dae79e050a3afed8e4e42b6 Mon Sep 17 00:00:00 2001 +From: Takahiro Hirofuchi +Date: Wed, 9 Jul 2008 14:56:51 -0600 +Subject: [PATCH 12/23] Staging: USB/IP: add client driver +Patch-mainline: 2.6.28 + +This adds the USB IP client driver + +Brian Merrell cleaned up a lot of this code and submitted it for +inclusion. Greg also did a lot of cleanup. + +Signed-off-by: Brian G. Merrell +Cc: Takahiro Hirofuchi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/usbip/Kconfig | 11 + + drivers/staging/usbip/Makefile | 3 + + drivers/staging/usbip/vhci.h | 142 ++++ + drivers/staging/usbip/vhci_hcd.c | 1275 ++++++++++++++++++++++++++++++++++++ + drivers/staging/usbip/vhci_rx.c | 251 +++++++ + drivers/staging/usbip/vhci_sysfs.c | 250 +++++++ + drivers/staging/usbip/vhci_tx.c | 239 +++++++ + 7 files changed, 2171 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/usbip/vhci.h + create mode 100644 drivers/staging/usbip/vhci_hcd.c + create mode 100644 drivers/staging/usbip/vhci_rx.c + create mode 100644 drivers/staging/usbip/vhci_sysfs.c + create mode 100644 drivers/staging/usbip/vhci_tx.c + +diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig +index 37efb5e..c4d68e1 100644 +--- a/drivers/staging/usbip/Kconfig ++++ b/drivers/staging/usbip/Kconfig +@@ -12,3 +12,14 @@ config USB_IP_COMMON + module will be called usbip_common_mod. + + If unsure, say N. ++ ++config USB_IP_VHCI_HCD ++ tristate "USB IP client driver" ++ depends on USB_IP_COMMON ++ default N ++ ---help--- ++ This enables the USB IP host controller driver which will ++ run on the client machine. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called vhci_hcd. +diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile +index ce925ca..6ef4c39 100644 +--- a/drivers/staging/usbip/Makefile ++++ b/drivers/staging/usbip/Makefile +@@ -1,6 +1,9 @@ + obj-$(CONFIG_USB_IP_COMMON) += usbip_common_mod.o + usbip_common_mod-objs := usbip_common.o usbip_event.o + ++obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o ++vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o ++ + ifeq ($(CONFIG_USB_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG + endif +diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h +new file mode 100644 +index 0000000..5e37517 +--- /dev/null ++++ b/drivers/staging/usbip/vhci.h +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include "../../usb/core/hcd.h" ++ ++ ++struct vhci_device { ++ struct usb_device *udev; ++ ++ /* ++ * devid specifies a remote usb device uniquely instead ++ * of combination of busnum and devnum. ++ */ ++ __u32 devid; ++ ++ /* speed of a remote device */ ++ enum usb_device_speed speed; ++ ++ /* vhci root-hub port to which this device is attached */ ++ __u32 rhport; ++ ++ struct usbip_device ud; ++ ++ ++ /* lock for the below link lists */ ++ spinlock_t priv_lock; ++ ++ /* vhci_priv is linked to one of them. */ ++ struct list_head priv_tx; ++ struct list_head priv_rx; ++ ++ /* vhci_unlink is linked to one of them */ ++ struct list_head unlink_tx; ++ struct list_head unlink_rx; ++ ++ /* vhci_tx thread sleeps for this queue */ ++ wait_queue_head_t waitq_tx; ++}; ++ ++ ++/* urb->hcpriv, use container_of() */ ++struct vhci_priv { ++ unsigned long seqnum; ++ struct list_head list; ++ ++ struct vhci_device *vdev; ++ struct urb *urb; ++}; ++ ++ ++struct vhci_unlink { ++ /* seqnum of this request */ ++ unsigned long seqnum; ++ ++ struct list_head list; ++ ++ /* seqnum of the unlink target */ ++ unsigned long unlink_seqnum; ++}; ++ ++/* ++ * The number of ports is less than 16 ? ++ * USB_MAXCHILDREN is statically defined to 16 in usb.h. Its maximum value ++ * would be 31 because the event_bits[1] of struct usb_hub is defined as ++ * unsigned long in hub.h ++ */ ++#define VHCI_NPORTS 8 ++ ++/* for usb_bus.hcpriv */ ++struct vhci_hcd { ++ spinlock_t lock; ++ ++ u32 port_status[VHCI_NPORTS]; ++ ++ unsigned resuming:1; ++ unsigned long re_timeout; ++ ++ atomic_t seqnum; ++ ++ /* ++ * NOTE: ++ * wIndex shows the port number and begins from 1. ++ * But, the index of this array begins from 0. ++ */ ++ struct vhci_device vdev[VHCI_NPORTS]; ++ ++ /* vhci_device which has not been assiged its address yet */ ++ int pending_port; ++}; ++ ++ ++extern struct vhci_hcd *the_controller; ++extern struct attribute_group dev_attr_group; ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* prototype declaration */ ++ ++/* vhci_hcd.c */ ++void rh_port_connect(int rhport, enum usb_device_speed speed); ++void rh_port_disconnect(int rhport); ++void vhci_rx_loop(struct usbip_task *ut); ++void vhci_tx_loop(struct usbip_task *ut); ++ ++#define hardware (&the_controller->pdev.dev) ++ ++static inline struct vhci_device *port_to_vdev(__u32 port) ++{ ++ return &the_controller->vdev[port]; ++} ++ ++static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd) ++{ ++ return (struct vhci_hcd *) (hcd->hcd_priv); ++} ++ ++static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci) ++{ ++ return container_of((void *) vhci, struct usb_hcd, hcd_priv); ++} ++ ++static inline struct device *vhci_dev(struct vhci_hcd *vhci) ++{ ++ return vhci_to_hcd(vhci)->self.controller; ++} +diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c +new file mode 100644 +index 0000000..5b5a2e3 +--- /dev/null ++++ b/drivers/staging/usbip/vhci_hcd.c +@@ -0,0 +1,1275 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++ ++#include "usbip_common.h" ++#include "vhci.h" ++ ++#define DRIVER_VERSION "1.0" ++#define DRIVER_AUTHOR "Takahiro Hirofuchi" ++#define DRIVER_DESC "Virtual Host Controller Interface Driver for USB/IP" ++#define DRIVER_LICENCE "GPL" ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE(DRIVER_LICENCE); ++ ++ ++ ++/* ++ * TODO ++ * - update root hub emulation ++ * - move the emulation code to userland ? ++ * porting to other operating systems ++ * minimize kernel code ++ * - add suspend/resume code ++ * - clean up everything ++ */ ++ ++ ++/* See usb gadget dummy hcd */ ++ ++ ++static int vhci_hub_status(struct usb_hcd *hcd, char *buff); ++static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ++ u16 wIndex, char *buff, u16 wLength); ++static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, ++ gfp_t mem_flags); ++static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); ++static int vhci_start(struct usb_hcd *vhci_hcd); ++static void vhci_stop(struct usb_hcd *hcd); ++static int vhci_get_frame_number(struct usb_hcd *hcd); ++ ++static const char driver_name[] = "vhci_hcd"; ++static const char driver_desc[] = "USB/IP Virtual Host Contoroller"; ++ ++struct vhci_hcd *the_controller; ++ ++static const char *bit_desc[] = { ++ "CONNECTION", /*0*/ ++ "ENABLE", /*1*/ ++ "SUSPEND", /*2*/ ++ "OVER_CURRENT", /*3*/ ++ "RESET", /*4*/ ++ "R5", /*5*/ ++ "R6", /*6*/ ++ "R7", /*7*/ ++ "POWER", /*8*/ ++ "LOWSPEED", /*9*/ ++ "HIGHSPEED", /*10*/ ++ "PORT_TEST", /*11*/ ++ "INDICATOR", /*12*/ ++ "R13", /*13*/ ++ "R14", /*14*/ ++ "R15", /*15*/ ++ "C_CONNECTION", /*16*/ ++ "C_ENABLE", /*17*/ ++ "C_SUSPEND", /*18*/ ++ "C_OVER_CURRENT", /*19*/ ++ "C_RESET", /*20*/ ++ "R21", /*21*/ ++ "R22", /*22*/ ++ "R23", /*23*/ ++ "R24", /*24*/ ++ "R25", /*25*/ ++ "R26", /*26*/ ++ "R27", /*27*/ ++ "R28", /*28*/ ++ "R29", /*29*/ ++ "R30", /*30*/ ++ "R31", /*31*/ ++}; ++ ++ ++static void dump_port_status(u32 status) ++{ ++ int i = 0; ++ ++ printk(KERN_DEBUG "status %08x:", status); ++ for (i = 0; i < 32; i++) { ++ if (status & (1 << i)) ++ printk(" %s", bit_desc[i]); ++ } ++ ++ printk("\n"); ++} ++ ++ ++ ++void rh_port_connect(int rhport, enum usb_device_speed speed) ++{ ++ unsigned long flags; ++ ++ dbg_vhci_rh("rh_port_connect %d\n", rhport); ++ ++ spin_lock_irqsave(&the_controller->lock, flags); ++ ++ the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION ++ | (1 << USB_PORT_FEAT_C_CONNECTION); ++ ++ switch (speed) { ++ case USB_SPEED_HIGH: ++ the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED; ++ break; ++ case USB_SPEED_LOW: ++ the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED; ++ break; ++ default: ++ break; ++ } ++ ++ /* spin_lock(&the_controller->vdev[rhport].ud.lock); ++ * the_controller->vdev[rhport].ud.status = VDEV_CONNECT; ++ * spin_unlock(&the_controller->vdev[rhport].ud.lock); */ ++ ++ the_controller->pending_port = rhport; ++ ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ ++ usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); ++} ++ ++void rh_port_disconnect(int rhport) ++{ ++ unsigned long flags; ++ ++ dbg_vhci_rh("rh_port_disconnect %d\n", rhport); ++ ++ spin_lock_irqsave(&the_controller->lock, flags); ++ /* stop_activity(dum, driver); */ ++ the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION; ++ the_controller->port_status[rhport] |= ++ (1 << USB_PORT_FEAT_C_CONNECTION); ++ ++ ++ /* not yet complete the disconnection ++ * spin_lock(&vdev->ud.lock); ++ * vdev->ud.status = VHC_ST_DISCONNECT; ++ * spin_unlock(&vdev->ud.lock); */ ++ ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++} ++ ++ ++ ++/*----------------------------------------------------------------------*/ ++ ++#define PORT_C_MASK \ ++ ((USB_PORT_STAT_C_CONNECTION \ ++ | USB_PORT_STAT_C_ENABLE \ ++ | USB_PORT_STAT_C_SUSPEND \ ++ | USB_PORT_STAT_C_OVERCURRENT \ ++ | USB_PORT_STAT_C_RESET) << 16) ++ ++/* ++ * This function is almostly the same as dummy_hcd.c:dummy_hub_status() without ++ * suspend/resume support. But, it is modified to provide multiple ports. ++ * ++ * @buf: a bitmap to show which port status has been changed. ++ * bit 0: reserved or used for another purpose? ++ * bit 1: the status of port 0 has been changed. ++ * bit 2: the status of port 1 has been changed. ++ * ... ++ * bit 7: the status of port 6 has been changed. ++ * bit 8: the status of port 7 has been changed. ++ * ... ++ * bit 15: the status of port 14 has been changed. ++ * ++ * So, the maximum number of ports is 31 ( port 0 to port 30) ? ++ * ++ * The return value is the actual transfered length in byte. If nothing has ++ * been changed, return 0. In the case that the number of ports is less than or ++ * equal to 6 (VHCI_NPORTS==7), return 1. ++ * ++ */ ++static int vhci_hub_status(struct usb_hcd *hcd, char *buf) ++{ ++ struct vhci_hcd *vhci; ++ unsigned long flags; ++ int retval = 0; ++ ++ /* the enough buffer is allocated according to USB_MAXCHILDREN */ ++ unsigned long *event_bits = (unsigned long *) buf; ++ int rhport; ++ int changed = 0; ++ ++ ++ *event_bits = 0; ++ ++ vhci = hcd_to_vhci(hcd); ++ ++ spin_lock_irqsave(&vhci->lock, flags); ++ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { ++ dbg_vhci_rh("hw accessible flag in on?\n"); ++ goto done; ++ } ++ ++ /* check pseudo status register for each port */ ++ for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { ++ if ((vhci->port_status[rhport] & PORT_C_MASK)) { ++ /* The status of a port has been changed, */ ++ dbg_vhci_rh("port %d is changed\n", rhport); ++ ++ *event_bits |= 1 << (rhport + 1); ++ changed = 1; ++ } ++ } ++ ++ uinfo("changed %d\n", changed); ++ ++ if (hcd->state == HC_STATE_SUSPENDED) ++ usb_hcd_resume_root_hub(hcd); ++ ++ if (changed) ++ retval = 1 + (VHCI_NPORTS / 8); ++ else ++ retval = 0; ++ ++done: ++ spin_unlock_irqrestore(&vhci->lock, flags); ++ return retval; ++} ++ ++/* See hub_configure in hub.c */ ++static inline void hub_descriptor(struct usb_hub_descriptor *desc) ++{ ++ memset(desc, 0, sizeof(*desc)); ++ desc->bDescriptorType = 0x29; ++ desc->bDescLength = 9; ++ desc->wHubCharacteristics = (__force __u16) ++ (__constant_cpu_to_le16(0x0001)); ++ desc->bNbrPorts = VHCI_NPORTS; ++ desc->bitmap[0] = 0xff; ++ desc->bitmap[1] = 0xff; ++} ++ ++static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ++ u16 wIndex, char *buf, u16 wLength) ++{ ++ struct vhci_hcd *dum; ++ int retval = 0; ++ unsigned long flags; ++ int rhport; ++ ++ u32 prev_port_status[VHCI_NPORTS]; ++ ++ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) ++ return -ETIMEDOUT; ++ ++ /* ++ * NOTE: ++ * wIndex shows the port number and begins from 1. ++ */ ++ dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, ++ wIndex); ++ if (wIndex > VHCI_NPORTS) ++ printk(KERN_ERR "%s: invalid port number %d\n", __func__, wIndex); ++ rhport = ((__u8)(wIndex & 0x00ff)) - 1; ++ ++ dum = hcd_to_vhci(hcd); ++ ++ spin_lock_irqsave(&dum->lock, flags); ++ ++ /* store old status and compare now and old later */ ++ if (dbg_flag_vhci_rh) { ++ int i = 0; ++ for (i = 0; i < VHCI_NPORTS; i++) ++ prev_port_status[i] = dum->port_status[i]; ++ } ++ ++ switch (typeReq) { ++ case ClearHubFeature: ++ dbg_vhci_rh(" ClearHubFeature\n"); ++ break; ++ case ClearPortFeature: ++ switch (wValue) { ++ case USB_PORT_FEAT_SUSPEND: ++ if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) { ++ /* 20msec signaling */ ++ dum->resuming = 1; ++ dum->re_timeout = ++ jiffies + msecs_to_jiffies(20); ++ } ++ break; ++ case USB_PORT_FEAT_POWER: ++ dbg_vhci_rh(" ClearPortFeature: USB_PORT_FEAT_POWER\n"); ++ dum->port_status[rhport] = 0; ++ /* dum->address = 0; */ ++ /* dum->hdev = 0; */ ++ dum->resuming = 0; ++ break; ++ case USB_PORT_FEAT_C_RESET: ++ dbg_vhci_rh(" ClearPortFeature: " ++ "USB_PORT_FEAT_C_RESET\n"); ++ switch (dum->vdev[rhport].speed) { ++ case USB_SPEED_HIGH: ++ dum->port_status[rhport] |= ++ USB_PORT_STAT_HIGH_SPEED; ++ break; ++ case USB_SPEED_LOW: ++ dum->port_status[rhport] |= ++ USB_PORT_STAT_LOW_SPEED; ++ break; ++ default: ++ break; ++ } ++ default: ++ dbg_vhci_rh(" ClearPortFeature: default %x\n", wValue); ++ dum->port_status[rhport] &= ~(1 << wValue); ++ } ++ break; ++ case GetHubDescriptor: ++ dbg_vhci_rh(" GetHubDescriptor\n"); ++ hub_descriptor((struct usb_hub_descriptor *) buf); ++ break; ++ case GetHubStatus: ++ dbg_vhci_rh(" GetHubStatus\n"); ++ *(__le32 *) buf = __constant_cpu_to_le32(0); ++ break; ++ case GetPortStatus: ++ dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); ++ if (wIndex > VHCI_NPORTS || wIndex < 1) { ++ printk(KERN_ERR "%s: invalid port number %d\n", ++ __func__, wIndex); ++ retval = -EPIPE; ++ } ++ ++ /* we do no care of resume. */ ++ ++ /* whoever resets or resumes must GetPortStatus to ++ * complete it!! ++ * */ ++ if (dum->resuming && time_after(jiffies, dum->re_timeout)) { ++ printk(KERN_ERR "%s: not yet\n", __func__); ++ dum->port_status[rhport] |= ++ (1 << USB_PORT_FEAT_C_SUSPEND); ++ dum->port_status[rhport] &= ++ ~(1 << USB_PORT_FEAT_SUSPEND); ++ dum->resuming = 0; ++ dum->re_timeout = 0; ++ /* if (dum->driver && dum->driver->resume) { ++ * spin_unlock (&dum->lock); ++ * dum->driver->resume (&dum->gadget); ++ * spin_lock (&dum->lock); ++ * } */ ++ } ++ ++ if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) != ++ 0 && time_after(jiffies, dum->re_timeout)) { ++ dum->port_status[rhport] |= ++ (1 << USB_PORT_FEAT_C_RESET); ++ dum->port_status[rhport] &= ++ ~(1 << USB_PORT_FEAT_RESET); ++ dum->re_timeout = 0; ++ ++ if (dum->vdev[rhport].ud.status == ++ VDEV_ST_NOTASSIGNED) { ++ dbg_vhci_rh(" enable rhport %d (status %u)\n", ++ rhport, ++ dum->vdev[rhport].ud.status); ++ dum->port_status[rhport] |= ++ USB_PORT_STAT_ENABLE; ++ } ++#if 0 ++ if (dum->driver) { ++ ++ dum->port_status[rhport] |= ++ USB_PORT_STAT_ENABLE; ++ /* give it the best speed we agree on */ ++ dum->gadget.speed = dum->driver->speed; ++ dum->gadget.ep0->maxpacket = 64; ++ switch (dum->gadget.speed) { ++ case USB_SPEED_HIGH: ++ dum->port_status[rhport] |= ++ USB_PORT_STAT_HIGH_SPEED; ++ break; ++ case USB_SPEED_LOW: ++ dum->gadget.ep0->maxpacket = 8; ++ dum->port_status[rhport] |= ++ USB_PORT_STAT_LOW_SPEED; ++ break; ++ default: ++ dum->gadget.speed = USB_SPEED_FULL; ++ break; ++ } ++ } ++#endif ++ ++ } ++ ((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]); ++ ((u16 *) buf)[1] = ++ cpu_to_le16(dum->port_status[rhport] >> 16); ++ ++ dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0], ++ ((u16 *)buf)[1]); ++ break; ++ case SetHubFeature: ++ dbg_vhci_rh(" SetHubFeature\n"); ++ retval = -EPIPE; ++ break; ++ case SetPortFeature: ++ switch (wValue) { ++ case USB_PORT_FEAT_SUSPEND: ++ dbg_vhci_rh(" SetPortFeature: " ++ "USB_PORT_FEAT_SUSPEND\n"); ++ printk(KERN_ERR "%s: not yet\n", __func__); ++#if 0 ++ dum->port_status[rhport] |= ++ (1 << USB_PORT_FEAT_SUSPEND); ++ if (dum->driver->suspend) { ++ spin_unlock(&dum->lock); ++ dum->driver->suspend(&dum->gadget); ++ spin_lock(&dum->lock); ++ } ++#endif ++ break; ++ case USB_PORT_FEAT_RESET: ++ dbg_vhci_rh(" SetPortFeature: USB_PORT_FEAT_RESET\n"); ++ /* if it's already running, disconnect first */ ++ if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) { ++ dum->port_status[rhport] &= ++ ~(USB_PORT_STAT_ENABLE | ++ USB_PORT_STAT_LOW_SPEED | ++ USB_PORT_STAT_HIGH_SPEED); ++#if 0 ++ if (dum->driver) { ++ dev_dbg(hardware, "disconnect\n"); ++ stop_activity(dum, dum->driver); ++ } ++#endif ++ ++ /* FIXME test that code path! */ ++ } ++ /* 50msec reset signaling */ ++ dum->re_timeout = jiffies + msecs_to_jiffies(50); ++ ++ /* FALLTHROUGH */ ++ default: ++ dbg_vhci_rh(" SetPortFeature: default %d\n", wValue); ++ dum->port_status[rhport] |= (1 << wValue); ++ } ++ break; ++ ++ default: ++ printk(KERN_ERR "%s: default: no such request\n", __func__); ++ /* dev_dbg (hardware, ++ * "hub control req%04x v%04x i%04x l%d\n", ++ * typeReq, wValue, wIndex, wLength); */ ++ ++ /* "protocol stall" on error */ ++ retval = -EPIPE; ++ } ++ ++ if (dbg_flag_vhci_rh) { ++ printk(KERN_DEBUG "port %d\n", rhport); ++ dump_port_status(prev_port_status[rhport]); ++ dump_port_status(dum->port_status[rhport]); ++ } ++ dbg_vhci_rh(" bye\n"); ++ ++ spin_unlock_irqrestore(&dum->lock, flags); ++ ++ return retval; ++} ++ ++ ++ ++/*----------------------------------------------------------------------*/ ++ ++static struct vhci_device *get_vdev(struct usb_device *udev) ++{ ++ int i; ++ ++ if (!udev) ++ return NULL; ++ ++ for (i = 0; i < VHCI_NPORTS; i++) ++ if (the_controller->vdev[i].udev == udev) ++ return port_to_vdev(i); ++ ++ return NULL; ++} ++ ++static void vhci_tx_urb(struct urb *urb) ++{ ++ struct vhci_device *vdev = get_vdev(urb->dev); ++ struct vhci_priv *priv; ++ unsigned long flag; ++ ++ if (!vdev) { ++ err("could not get virtual device"); ++ /* BUG(); */ ++ return; ++ } ++ ++ spin_lock_irqsave(&vdev->priv_lock, flag); ++ ++ priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC); ++ if (!priv) { ++ dev_err(&urb->dev->dev, "malloc vhci_priv\n"); ++ spin_unlock_irqrestore(&vdev->priv_lock, flag); ++ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); ++ return; ++ } ++ ++ priv->seqnum = atomic_inc_return(&the_controller->seqnum); ++ if (priv->seqnum == 0xffff) ++ uinfo("seqnum max\n"); ++ ++ priv->vdev = vdev; ++ priv->urb = urb; ++ ++ urb->hcpriv = (void *) priv; ++ ++ ++ list_add_tail(&priv->list, &vdev->priv_tx); ++ ++ wake_up(&vdev->waitq_tx); ++ spin_unlock_irqrestore(&vdev->priv_lock, flag); ++} ++ ++static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, ++ gfp_t mem_flags) ++{ ++ struct device *dev = &urb->dev->dev; ++ int ret = 0; ++ unsigned long flags; ++ ++ dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", ++ hcd, urb, mem_flags); ++ ++ /* patch to usb_sg_init() is in 2.5.60 */ ++ BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); ++ ++ spin_lock_irqsave(&the_controller->lock, flags); ++ ++ /* check HC is active or not */ ++ if (!HC_IS_RUNNING(hcd->state)) { ++ dev_err(dev, "HC is not running\n"); ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ return -ENODEV; ++ } ++ ++ if (urb->status != -EINPROGRESS) { ++ dev_err(dev, "URB already unlinked!, status %d\n", urb->status); ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ return urb->status; ++ } ++ ++ ret = usb_hcd_link_urb_to_ep(hcd, urb); ++ if (ret) ++ goto no_need_unlink; ++ ++ /* ++ * The enumelation process is as follows; ++ * ++ * 1. Get_Descriptor request to DevAddrs(0) EndPoint(0) ++ * to get max packet length of default pipe ++ * ++ * 2. Set_Address request to DevAddr(0) EndPoint(0) ++ * ++ */ ++ ++ if (usb_pipedevice(urb->pipe) == 0) { ++ __u8 type = usb_pipetype(urb->pipe); ++ struct usb_ctrlrequest *ctrlreq = ++ (struct usb_ctrlrequest *) urb->setup_packet; ++ struct vhci_device *vdev = ++ port_to_vdev(the_controller->pending_port); ++ ++ if (type != PIPE_CONTROL || !ctrlreq) { ++ dev_err(dev, "invalid request to devnum 0\n"); ++ ret = EINVAL; ++ goto no_need_xmit; ++ } ++ ++ switch (ctrlreq->bRequest) { ++ case USB_REQ_SET_ADDRESS: ++ /* set_address may come when a device is reset */ ++ dev_info(dev, "SetAddress Request (%d) to port %d\n", ++ ctrlreq->wValue, vdev->rhport); ++ ++ vdev->udev = urb->dev; ++ ++ spin_lock(&vdev->ud.lock); ++ vdev->ud.status = VDEV_ST_USED; ++ spin_unlock(&vdev->ud.lock); ++ ++ if (urb->status == -EINPROGRESS) { ++ /* This request is successfully completed. */ ++ /* If not -EINPROGRESS, possibly unlinked. */ ++ urb->status = 0; ++ } ++ ++ goto no_need_xmit; ++ ++ case USB_REQ_GET_DESCRIPTOR: ++ if (ctrlreq->wValue == (USB_DT_DEVICE << 8)) ++ dbg_vhci_hc("Not yet?: " ++ "Get_Descriptor to device 0 " ++ "(get max pipe size)\n"); ++ ++ /* FIXME: reference count? (usb_get_dev()) */ ++ vdev->udev = urb->dev; ++ goto out; ++ ++ default: ++ /* NOT REACHED */ ++ dev_err(dev, "invalid request to devnum 0 bRequest %u, " ++ "wValue %u\n", ctrlreq->bRequest, ++ ctrlreq->wValue); ++ ret = -EINVAL; ++ goto no_need_xmit; ++ } ++ ++ } ++ ++out: ++ vhci_tx_urb(urb); ++ ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ ++ return 0; ++ ++no_need_xmit: ++ usb_hcd_unlink_urb_from_ep(hcd, urb); ++no_need_unlink: ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ ++ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); ++ ++ return 0; ++} ++ ++/* ++ * vhci_rx gives back the urb after receiving the reply of the urb. If an ++ * unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives ++ * back its urb. For the driver unlinking the urb, the content of the urb is ++ * not important, but the calling to its completion handler is important; the ++ * completion of unlinking is notified by the completion handler. ++ * ++ * ++ * CLIENT SIDE ++ * ++ * - When vhci_hcd receives RET_SUBMIT, ++ * ++ * - case 1a). the urb of the pdu is not unlinking. ++ * - normal case ++ * => just give back the urb ++ * ++ * - case 1b). the urb of the pdu is unlinking. ++ * - usbip.ko will return a reply of the unlinking request. ++ * => give back the urb now and go to case 2b). ++ * ++ * - When vhci_hcd receives RET_UNLINK, ++ * ++ * - case 2a). a submit request is still pending in vhci_hcd. ++ * - urb was really pending in usbip.ko and urb_unlink_urb() was ++ * completed there. ++ * => free a pending submit request ++ * => notify unlink completeness by giving back the urb ++ * ++ * - case 2b). a submit request is *not* pending in vhci_hcd. ++ * - urb was already given back to the core driver. ++ * => do not give back the urb ++ * ++ * ++ * SERVER SIDE ++ * ++ * - When usbip receives CMD_UNLINK, ++ * ++ * - case 3a). the urb of the unlink request is now in submission. ++ * => do usb_unlink_urb(). ++ * => after the unlink is completed, send RET_UNLINK. ++ * ++ * - case 3b). the urb of the unlink request is not in submission. ++ * - may be already completed or never be received ++ * => send RET_UNLINK ++ * ++ */ ++static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ++{ ++ unsigned long flags; ++ struct vhci_priv *priv; ++ struct vhci_device *vdev; ++ ++ uinfo("vhci_hcd: dequeue a urb %p\n", urb); ++ ++ ++ spin_lock_irqsave(&the_controller->lock, flags); ++ ++ priv = urb->hcpriv; ++ if (!priv) { ++ /* URB was never linked! or will be soon given back by ++ * vhci_rx. */ ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ return 0; ++ } ++ ++ { ++ int ret = 0; ++ ret = usb_hcd_check_unlink_urb(hcd, urb, status); ++ if (ret) { ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ return 0; ++ } ++ } ++ ++ /* send unlink request here? */ ++ vdev = priv->vdev; ++ ++ if (!vdev->ud.tcp_socket) { ++ /* tcp connection is closed */ ++ unsigned long flags2; ++ ++ spin_lock_irqsave(&vdev->priv_lock, flags2); ++ ++ uinfo("vhci_hcd: device %p seems to be disconnected\n", vdev); ++ list_del(&priv->list); ++ kfree(priv); ++ urb->hcpriv = NULL; ++ ++ spin_unlock_irqrestore(&vdev->priv_lock, flags2); ++ ++ } else { ++ /* tcp connection is alive */ ++ unsigned long flags2; ++ struct vhci_unlink *unlink; ++ ++ spin_lock_irqsave(&vdev->priv_lock, flags2); ++ ++ /* setup CMD_UNLINK pdu */ ++ unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC); ++ if (!unlink) { ++ uerr("malloc vhci_unlink\n"); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags2); ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); ++ return -ENOMEM; ++ } ++ ++ unlink->seqnum = atomic_inc_return(&the_controller->seqnum); ++ if (unlink->seqnum == 0xffff) ++ uinfo("seqnum max\n"); ++ ++ unlink->unlink_seqnum = priv->seqnum; ++ ++ uinfo("vhci_hcd: device %p seems to be still connected\n", ++ vdev); ++ ++ /* send cmd_unlink and try to cancel the pending URB in the ++ * peer */ ++ list_add_tail(&unlink->list, &vdev->unlink_tx); ++ wake_up(&vdev->waitq_tx); ++ ++ spin_unlock_irqrestore(&vdev->priv_lock, flags2); ++ } ++ ++ ++ /* ++ * If tcp connection is alive, we have sent CMD_UNLINK. ++ * vhci_rx will receive RET_UNLINK and give back the URB. ++ * Otherwise, we give back it here. ++ */ ++ if (!vdev->ud.tcp_socket) { ++ /* tcp connection is closed */ ++ uinfo("vhci_hcd: vhci_urb_dequeue() gives back urb %p\n", urb); ++ ++ usb_hcd_unlink_urb_from_ep(hcd, urb); ++ ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, ++ urb->status); ++ spin_lock_irqsave(&the_controller->lock, flags); ++ } ++ ++ spin_unlock_irqrestore(&the_controller->lock, flags); ++ ++ dbg_vhci_hc("leave\n"); ++ return 0; ++} ++ ++ ++static void vhci_device_unlink_cleanup(struct vhci_device *vdev) ++{ ++ struct vhci_unlink *unlink, *tmp; ++ ++ spin_lock(&vdev->priv_lock); ++ ++ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { ++ list_del(&unlink->list); ++ kfree(unlink); ++ } ++ ++ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { ++ list_del(&unlink->list); ++ kfree(unlink); ++ } ++ ++ spin_unlock(&vdev->priv_lock); ++} ++ ++/* ++ * The important thing is that only one context begins cleanup. ++ * This is why error handling and cleanup become simple. ++ * We do not want to consider race condition as possible. ++ */ ++static void vhci_shutdown_connection(struct usbip_device *ud) ++{ ++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); ++ ++ /* need this? see stub_dev.c */ ++ if (ud->tcp_socket) { ++ udbg("shutdown tcp_socket %p\n", ud->tcp_socket); ++ kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); ++ } ++ ++ usbip_stop_threads(&vdev->ud); ++ uinfo("stop threads\n"); ++ ++ /* active connection is closed */ ++ if (vdev->ud.tcp_socket != NULL) { ++ sock_release(vdev->ud.tcp_socket); ++ vdev->ud.tcp_socket = NULL; ++ } ++ uinfo("release socket\n"); ++ ++ vhci_device_unlink_cleanup(vdev); ++ ++ /* ++ * rh_port_disconnect() is a trigger of ... ++ * usb_disable_device(): ++ * disable all the endpoints for a USB device. ++ * usb_disable_endpoint(): ++ * disable endpoints. pending urbs are unlinked(dequeued). ++ * ++ * NOTE: After calling rh_port_disconnect(), the USB device drivers of a ++ * deteched device should release used urbs in a cleanup function(i.e. ++ * xxx_disconnect()). Therefore, vhci_hcd does not need to release ++ * pushed urbs and their private data in this function. ++ * ++ * NOTE: vhci_dequeue() must be considered carefully. When shutdowning ++ * a connection, vhci_shutdown_connection() expects vhci_dequeue() ++ * gives back pushed urbs and frees their private data by request of ++ * the cleanup function of a USB driver. When unlinking a urb with an ++ * active connection, vhci_dequeue() does not give back the urb which ++ * is actually given back by vhci_rx after receiving its return pdu. ++ * ++ */ ++ rh_port_disconnect(vdev->rhport); ++ ++ uinfo("disconnect device\n"); ++} ++ ++ ++static void vhci_device_reset(struct usbip_device *ud) ++{ ++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); ++ ++ spin_lock(&ud->lock); ++ ++ vdev->speed = 0; ++ vdev->devid = 0; ++ ++ ud->tcp_socket = NULL; ++ ++ ud->status = VDEV_ST_NULL; ++ ++ spin_unlock(&ud->lock); ++} ++ ++static void vhci_device_unusable(struct usbip_device *ud) ++{ ++ spin_lock(&ud->lock); ++ ++ ud->status = VDEV_ST_ERROR; ++ ++ spin_unlock(&ud->lock); ++} ++ ++static void vhci_device_init(struct vhci_device *vdev) ++{ ++ memset(vdev, 0, sizeof(*vdev)); ++ ++ usbip_task_init(&vdev->ud.tcp_rx, "vhci_rx", vhci_rx_loop); ++ usbip_task_init(&vdev->ud.tcp_tx, "vhci_tx", vhci_tx_loop); ++ ++ vdev->ud.side = USBIP_VHCI; ++ vdev->ud.status = VDEV_ST_NULL; ++ /* vdev->ud.lock = SPIN_LOCK_UNLOCKED; */ ++ spin_lock_init(&vdev->ud.lock); ++ ++ INIT_LIST_HEAD(&vdev->priv_rx); ++ INIT_LIST_HEAD(&vdev->priv_tx); ++ INIT_LIST_HEAD(&vdev->unlink_tx); ++ INIT_LIST_HEAD(&vdev->unlink_rx); ++ /* vdev->priv_lock = SPIN_LOCK_UNLOCKED; */ ++ spin_lock_init(&vdev->priv_lock); ++ ++ init_waitqueue_head(&vdev->waitq_tx); ++ ++ vdev->ud.eh_ops.shutdown = vhci_shutdown_connection; ++ vdev->ud.eh_ops.reset = vhci_device_reset; ++ vdev->ud.eh_ops.unusable = vhci_device_unusable; ++ ++ usbip_start_eh(&vdev->ud); ++} ++ ++ ++/*----------------------------------------------------------------------*/ ++ ++static int vhci_start(struct usb_hcd *hcd) ++{ ++ struct vhci_hcd *vhci = hcd_to_vhci(hcd); ++ int rhport; ++ int err = 0; ++ ++ dbg_vhci_hc("enter vhci_start\n"); ++ ++ ++ /* initialize private data of usb_hcd */ ++ ++ for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { ++ struct vhci_device *vdev = &vhci->vdev[rhport]; ++ vhci_device_init(vdev); ++ vdev->rhport = rhport; ++ } ++ ++ atomic_set(&vhci->seqnum, 0); ++ spin_lock_init(&vhci->lock); ++ ++ ++ ++ hcd->power_budget = 0; /* no limit */ ++ hcd->state = HC_STATE_RUNNING; ++ hcd->uses_new_polling = 1; ++ ++ ++ /* vhci_hcd is now ready to be controlled through sysfs */ ++ err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group); ++ if (err) { ++ uerr("create sysfs files\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void vhci_stop(struct usb_hcd *hcd) ++{ ++ struct vhci_hcd *vhci = hcd_to_vhci(hcd); ++ int rhport = 0; ++ ++ dbg_vhci_hc("stop VHCI controller\n"); ++ ++ ++ /* 1. remove the userland interface of vhci_hcd */ ++ sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group); ++ ++ /* 2. shutdown all the ports of vhci_hcd */ ++ for (rhport = 0 ; rhport < VHCI_NPORTS; rhport++) { ++ struct vhci_device *vdev = &vhci->vdev[rhport]; ++ ++ usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED); ++ usbip_stop_eh(&vdev->ud); ++ } ++ ++ ++ uinfo("vhci_stop done\n"); ++} ++ ++/*----------------------------------------------------------------------*/ ++ ++static int vhci_get_frame_number(struct usb_hcd *hcd) ++{ ++ uerr("Not yet implemented\n"); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PM ++ ++/* FIXME: suspend/resume */ ++static int vhci_bus_suspend(struct usb_hcd *hcd) ++{ ++ struct vhci_hcd *vhci = hcd_to_vhci(hcd); ++ ++ dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); ++ ++ spin_lock_irq(&vhci->lock); ++ /* vhci->rh_state = DUMMY_RH_SUSPENDED; ++ * set_link_state(vhci); */ ++ hcd->state = HC_STATE_SUSPENDED; ++ spin_unlock_irq(&vhci->lock); ++ ++ return 0; ++} ++ ++static int vhci_bus_resume(struct usb_hcd *hcd) ++{ ++ struct vhci_hcd *vhci = hcd_to_vhci(hcd); ++ int rc = 0; ++ ++ dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); ++ ++ spin_lock_irq(&vhci->lock); ++ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { ++ rc = -ESHUTDOWN; ++ } else { ++ /* vhci->rh_state = DUMMY_RH_RUNNING; ++ * set_link_state(vhci); ++ * if (!list_empty(&vhci->urbp_list)) ++ * mod_timer(&vhci->timer, jiffies); */ ++ hcd->state = HC_STATE_RUNNING; ++ } ++ spin_unlock_irq(&vhci->lock); ++ return rc; ++ ++ return 0; ++} ++ ++#else ++ ++#define vhci_bus_suspend NULL ++#define vhci_bus_resume NULL ++#endif ++ ++ ++ ++static struct hc_driver vhci_hc_driver = { ++ .description = driver_name, ++ .product_desc = driver_desc, ++ .hcd_priv_size = sizeof(struct vhci_hcd), ++ ++ .flags = HCD_USB2, ++ ++ .start = vhci_start, ++ .stop = vhci_stop, ++ ++ .urb_enqueue = vhci_urb_enqueue, ++ .urb_dequeue = vhci_urb_dequeue, ++ ++ .get_frame_number = vhci_get_frame_number, ++ ++ .hub_status_data = vhci_hub_status, ++ .hub_control = vhci_hub_control, ++ .bus_suspend = vhci_bus_suspend, ++ .bus_resume = vhci_bus_resume, ++}; ++ ++static int vhci_hcd_probe(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd; ++ int ret; ++ ++ uinfo("proving...\n"); ++ ++ dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id); ++ ++ /* will be removed */ ++ if (pdev->dev.dma_mask) { ++ dev_info(&pdev->dev, "vhci_hcd DMA not supported\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Allocate and initialize hcd. ++ * Our private data is also allocated automatically. ++ */ ++ hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, pdev->dev.bus_id); ++ if (!hcd) { ++ uerr("create hcd failed\n"); ++ return -ENOMEM; ++ } ++ ++ ++ /* this is private data for vhci_hcd */ ++ the_controller = hcd_to_vhci(hcd); ++ ++ /* ++ * Finish generic HCD structure initialization and register. ++ * Call the driver's reset() and start() routines. ++ */ ++ ret = usb_add_hcd(hcd, 0, 0); ++ if (ret != 0) { ++ uerr("usb_add_hcd failed %d\n", ret); ++ usb_put_hcd(hcd); ++ the_controller = NULL; ++ return ret; ++ } ++ ++ ++ dbg_vhci_hc("bye\n"); ++ return 0; ++} ++ ++ ++static int vhci_hcd_remove(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd; ++ ++ hcd = platform_get_drvdata(pdev); ++ if (!hcd) ++ return 0; ++ ++ /* ++ * Disconnects the root hub, ++ * then reverses the effects of usb_add_hcd(), ++ * invoking the HCD's stop() methods. ++ */ ++ usb_remove_hcd(hcd); ++ usb_put_hcd(hcd); ++ the_controller = NULL; ++ ++ ++ return 0; ++} ++ ++ ++ ++#ifdef CONFIG_PM ++ ++/* what should happen for USB/IP under suspend/resume? */ ++static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct usb_hcd *hcd; ++ int rhport = 0; ++ int connected = 0; ++ int ret = 0; ++ ++ dev_dbg(&pdev->dev, "%s\n", __func__); ++ ++ hcd = platform_get_drvdata(pdev); ++ ++ spin_lock(&the_controller->lock); ++ ++ for (rhport = 0; rhport < VHCI_NPORTS; rhport++) ++ if (the_controller->port_status[rhport] & ++ USB_PORT_STAT_CONNECTION) ++ connected += 1; ++ ++ spin_unlock(&the_controller->lock); ++ ++ if (connected > 0) { ++ uinfo("We have %d active connection%s. Do not suspend.\n", ++ connected, (connected == 1 ? "" : "s")); ++ ret = -EBUSY; ++ } else { ++ uinfo("suspend vhci_hcd"); ++ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); ++ } ++ ++ return ret; ++} ++ ++static int vhci_hcd_resume(struct platform_device *pdev) ++{ ++ struct usb_hcd *hcd; ++ ++ dev_dbg(&pdev->dev, "%s\n", __func__); ++ ++ hcd = platform_get_drvdata(pdev); ++ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); ++ usb_hcd_poll_rh_status(hcd); ++ ++ return 0; ++} ++ ++#else ++ ++#define vhci_hcd_suspend NULL ++#define vhci_hcd_resume NULL ++ ++#endif ++ ++ ++static struct platform_driver vhci_driver = { ++ .probe = vhci_hcd_probe, ++ .remove = __devexit_p(vhci_hcd_remove), ++ .suspend = vhci_hcd_suspend, ++ .resume = vhci_hcd_resume, ++ .driver = { ++ .name = (char *) driver_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++/*----------------------------------------------------------------------*/ ++ ++/* ++ * The VHCI 'device' is 'virtual'; not a real plug&play hardware. ++ * We need to add this virtual device as a platform device arbitrarily: ++ * 1. platform_device_register() ++ */ ++static void the_pdev_release(struct device *dev) ++{ ++ return; ++} ++ ++static struct platform_device the_pdev = { ++ /* should be the same name as driver_name */ ++ .name = (char *) driver_name, ++ .id = -1, ++ .dev = { ++ /* .driver = &vhci_driver, */ ++ .release = the_pdev_release, ++ }, ++}; ++ ++static int __init vhci_init(void) ++{ ++ int ret; ++ ++ dbg_vhci_hc("enter\n"); ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ printk(KERN_INFO KBUILD_MODNAME ": %s, %s\n", driver_name, ++ DRIVER_VERSION); ++ ++ ret = platform_driver_register(&vhci_driver); ++ if (ret < 0) ++ goto err_driver_register; ++ ++ ret = platform_device_register(&the_pdev); ++ if (ret < 0) ++ goto err_platform_device_register; ++ ++ dbg_vhci_hc("bye\n"); ++ return ret; ++ ++ /* error occurred */ ++err_platform_device_register: ++ platform_driver_unregister(&vhci_driver); ++ ++err_driver_register: ++ dbg_vhci_hc("bye\n"); ++ return ret; ++} ++module_init(vhci_init); ++ ++static void __exit vhci_cleanup(void) ++{ ++ dbg_vhci_hc("enter\n"); ++ ++ platform_device_unregister(&the_pdev); ++ platform_driver_unregister(&vhci_driver); ++ ++ dbg_vhci_hc("bye\n"); ++} ++module_exit(vhci_cleanup); +diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c +new file mode 100644 +index 0000000..933ccaf +--- /dev/null ++++ b/drivers/staging/usbip/vhci_rx.c +@@ -0,0 +1,251 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++#include "vhci.h" ++ ++ ++/* get URB from transmitted urb queue */ ++static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, ++ __u32 seqnum) ++{ ++ struct vhci_priv *priv, *tmp; ++ struct urb *urb = NULL; ++ int status; ++ ++ spin_lock(&vdev->priv_lock); ++ ++ list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) { ++ if (priv->seqnum == seqnum) { ++ urb = priv->urb; ++ status = urb->status; ++ ++ dbg_vhci_rx("find urb %p vurb %p seqnum %u\n", ++ urb, priv, seqnum); ++ ++ /* TODO: fix logic here to improve indent situtation */ ++ if (status != -EINPROGRESS) { ++ if (status == -ENOENT || ++ status == -ECONNRESET) ++ dev_info(&urb->dev->dev, ++ "urb %p was unlinked " ++ "%ssynchronuously.\n", urb, ++ status == -ENOENT ? "" : "a"); ++ else ++ dev_info(&urb->dev->dev, ++ "urb %p may be in a error, " ++ "status %d\n", urb, status); ++ } ++ ++ list_del(&priv->list); ++ kfree(priv); ++ urb->hcpriv = NULL; ++ ++ break; ++ } ++ } ++ ++ spin_unlock(&vdev->priv_lock); ++ ++ return urb; ++} ++ ++static void vhci_recv_ret_submit(struct vhci_device *vdev, ++ struct usbip_header *pdu) ++{ ++ struct usbip_device *ud = &vdev->ud; ++ struct urb *urb; ++ ++ ++ urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); ++ ++ ++ if (!urb) { ++ uerr("cannot find a urb of seqnum %u\n", pdu->base.seqnum); ++ uinfo("max seqnum %d\n", atomic_read(&the_controller->seqnum)); ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ return; ++ } ++ ++ ++ /* unpack the pdu to a urb */ ++ usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0); ++ ++ ++ /* recv transfer buffer */ ++ if (usbip_recv_xbuff(ud, urb) < 0) ++ return; ++ ++ ++ /* recv iso_packet_descriptor */ ++ if (usbip_recv_iso(ud, urb) < 0) ++ return; ++ ++ ++ if (dbg_flag_vhci_rx) ++ usbip_dump_urb(urb); ++ ++ ++ dbg_vhci_rx("now giveback urb %p\n", urb); ++ ++ spin_lock(&the_controller->lock); ++ usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); ++ spin_unlock(&the_controller->lock); ++ ++ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); ++ ++ ++ dbg_vhci_rx("Leave\n"); ++ ++ return; ++} ++ ++ ++static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev, ++ struct usbip_header *pdu) ++{ ++ struct vhci_unlink *unlink, *tmp; ++ ++ spin_lock(&vdev->priv_lock); ++ ++ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { ++ uinfo("unlink->seqnum %lu\n", unlink->seqnum); ++ if (unlink->seqnum == pdu->base.seqnum) { ++ dbg_vhci_rx("found pending unlink, %lu\n", ++ unlink->seqnum); ++ list_del(&unlink->list); ++ ++ spin_unlock(&vdev->priv_lock); ++ return unlink; ++ } ++ } ++ ++ spin_unlock(&vdev->priv_lock); ++ ++ return NULL; ++} ++ ++ ++static void vhci_recv_ret_unlink(struct vhci_device *vdev, ++ struct usbip_header *pdu) ++{ ++ struct vhci_unlink *unlink; ++ struct urb *urb; ++ ++ usbip_dump_header(pdu); ++ ++ unlink = dequeue_pending_unlink(vdev, pdu); ++ if (!unlink) { ++ uinfo("cannot find the pending unlink %u\n", pdu->base.seqnum); ++ return; ++ } ++ ++ urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); ++ if (!urb) { ++ /* ++ * I get the result of a unlink request. But, it seems that I ++ * already received the result of its submit result and gave ++ * back the URB. ++ */ ++ uinfo("the urb (seqnum %d) was already given backed\n", ++ pdu->base.seqnum); ++ } else { ++ dbg_vhci_rx("now giveback urb %p\n", urb); ++ ++ /* If unlink is succeed, status is -ECONNRESET */ ++ urb->status = pdu->u.ret_unlink.status; ++ uinfo("%d\n", urb->status); ++ ++ spin_lock(&the_controller->lock); ++ usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); ++ spin_unlock(&the_controller->lock); ++ ++ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, ++ urb->status); ++ } ++ ++ kfree(unlink); ++ ++ return; ++} ++ ++/* recv a pdu */ ++static void vhci_rx_pdu(struct usbip_device *ud) ++{ ++ int ret; ++ struct usbip_header pdu; ++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); ++ ++ ++ dbg_vhci_rx("Enter\n"); ++ ++ memset(&pdu, 0, sizeof(pdu)); ++ ++ ++ /* 1. receive a pdu header */ ++ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0); ++ if (ret != sizeof(pdu)) { ++ uerr("receiving pdu failed! size is %d, should be %d\n", ++ ret, sizeof(pdu)); ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ return; ++ } ++ ++ usbip_header_correct_endian(&pdu, 0); ++ ++ if (dbg_flag_vhci_rx) ++ usbip_dump_header(&pdu); ++ ++ switch (pdu.base.command) { ++ case USBIP_RET_SUBMIT: ++ vhci_recv_ret_submit(vdev, &pdu); ++ break; ++ case USBIP_RET_UNLINK: ++ vhci_recv_ret_unlink(vdev, &pdu); ++ break; ++ default: ++ /* NOTREACHED */ ++ uerr("unknown pdu %u\n", pdu.base.command); ++ usbip_dump_header(&pdu); ++ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); ++ } ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++void vhci_rx_loop(struct usbip_task *ut) ++{ ++ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_rx); ++ ++ ++ while (1) { ++ if (signal_pending(current)) { ++ dbg_vhci_rx("signal catched!\n"); ++ break; ++ } ++ ++ ++ if (usbip_event_happend(ud)) ++ break; ++ ++ vhci_rx_pdu(ud); ++ } ++} ++ +diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c +new file mode 100644 +index 0000000..24c2851 +--- /dev/null ++++ b/drivers/staging/usbip/vhci_sysfs.c +@@ -0,0 +1,250 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++#include "vhci.h" ++ ++#include ++ ++/* TODO: refine locking ?*/ ++ ++/* Sysfs entry to show port status */ ++static ssize_t show_status(struct device *dev, struct device_attribute *attr, ++ char *out) ++{ ++ char *s = out; ++ int i = 0; ++ ++ if (!the_controller || !out) ++ BUG(); ++ ++ spin_lock(&the_controller->lock); ++ ++ /* ++ * output example: ++ * prt sta spd dev socket local_busid ++ * 000 004 000 000 c5a7bb80 1-2.3 ++ * 001 004 000 000 d8cee980 2-3.4 ++ * ++ * IP address can be retrieved from a socket pointer address by looking ++ * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a ++ * port number and its peer IP address. ++ */ ++ out += sprintf(out, "prt sta spd bus dev socket " ++ "local_busid\n"); ++ ++ for (i = 0; i < VHCI_NPORTS; i++) { ++ struct vhci_device *vdev = port_to_vdev(i); ++ ++ spin_lock(&vdev->ud.lock); ++ ++ out += sprintf(out, "%03u %03u ", i, vdev->ud.status); ++ ++ if (vdev->ud.status == VDEV_ST_USED) { ++ out += sprintf(out, "%03u %08x ", ++ vdev->speed, vdev->devid); ++ out += sprintf(out, "%16p ", vdev->ud.tcp_socket); ++ out += sprintf(out, "%s", vdev->udev->dev.bus_id); ++ ++ } else ++ out += sprintf(out, "000 000 000 0000000000000000 0-0"); ++ ++ out += sprintf(out, "\n"); ++ ++ spin_unlock(&vdev->ud.lock); ++ } ++ ++ spin_unlock(&the_controller->lock); ++ ++ return out - s; ++} ++static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); ++ ++/* Sysfs entry to shutdown a virtual connection */ ++static int vhci_port_disconnect(__u32 rhport) ++{ ++ struct vhci_device *vdev; ++ ++ dbg_vhci_sysfs("enter\n"); ++ ++ /* lock */ ++ spin_lock(&the_controller->lock); ++ ++ vdev = port_to_vdev(rhport); ++ ++ spin_lock(&vdev->ud.lock); ++ if (vdev->ud.status == VDEV_ST_NULL) { ++ uerr("not connected %d\n", vdev->ud.status); ++ ++ /* unlock */ ++ spin_unlock(&vdev->ud.lock); ++ spin_unlock(&the_controller->lock); ++ ++ return -EINVAL; ++ } ++ ++ /* unlock */ ++ spin_unlock(&vdev->ud.lock); ++ spin_unlock(&the_controller->lock); ++ ++ usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); ++ ++ return 0; ++} ++ ++static ssize_t store_detach(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int err; ++ __u32 rhport = 0; ++ ++ sscanf(buf, "%u", &rhport); ++ ++ /* check rhport */ ++ if (rhport >= VHCI_NPORTS) { ++ uerr("invalid port %u\n", rhport); ++ return -EINVAL; ++ } ++ ++ err = vhci_port_disconnect(rhport); ++ if (err < 0) ++ return -EINVAL; ++ ++ dbg_vhci_sysfs("Leave\n"); ++ return count; ++} ++static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); ++ ++/* Sysfs entry to establish a virtual connection */ ++static int valid_args(__u32 rhport, enum usb_device_speed speed) ++{ ++ /* check rhport */ ++ if ((rhport < 0) || (rhport >= VHCI_NPORTS)) { ++ uerr("port %u\n", rhport); ++ return -EINVAL; ++ } ++ ++ /* check speed */ ++ switch (speed) { ++ case USB_SPEED_LOW: ++ case USB_SPEED_FULL: ++ case USB_SPEED_HIGH: ++ case USB_SPEED_VARIABLE: ++ break; ++ default: ++ uerr("speed %d\n", speed); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* ++ * To start a new USB/IP attachment, a userland program needs to setup a TCP ++ * connection and then write its socket descriptor with remote device ++ * information into this sysfs file. ++ * ++ * A remote device is virtually attached to the root-hub port of @rhport with ++ * @speed. @devid is embedded into a request to specify the remote device in a ++ * server host. ++ * ++ * write() returns 0 on success, else negative errno. ++ */ ++static ssize_t store_attach(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct vhci_device *vdev; ++ struct socket *socket; ++ int sockfd = 0; ++ __u32 rhport = 0, devid = 0, speed = 0; ++ ++ /* ++ * @rhport: port number of vhci_hcd ++ * @sockfd: socket descriptor of an established TCP connection ++ * @devid: unique device identifier in a remote host ++ * @speed: usb device speed in a remote host ++ */ ++ sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed); ++ ++ dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", ++ rhport, sockfd, devid, speed); ++ ++ ++ /* check received parameters */ ++ if (valid_args(rhport, speed) < 0) ++ return -EINVAL; ++ ++ /* check sockfd */ ++ socket = sockfd_to_socket(sockfd); ++ if (!socket) ++ return -EINVAL; ++ ++ /* now need lock until setting vdev status as used */ ++ ++ /* begin a lock */ ++ spin_lock(&the_controller->lock); ++ ++ vdev = port_to_vdev(rhport); ++ ++ spin_lock(&vdev->ud.lock); ++ ++ if (vdev->ud.status != VDEV_ST_NULL) { ++ /* end of the lock */ ++ spin_unlock(&vdev->ud.lock); ++ spin_unlock(&the_controller->lock); ++ ++ uerr("port %d already used\n", rhport); ++ return -EINVAL; ++ } ++ ++ uinfo("rhport(%u) sockfd(%d) devid(%u) speed(%u)\n", ++ rhport, sockfd, devid, speed); ++ ++ vdev->devid = devid; ++ vdev->speed = speed; ++ vdev->ud.tcp_socket = socket; ++ vdev->ud.status = VDEV_ST_NOTASSIGNED; ++ ++ spin_unlock(&vdev->ud.lock); ++ spin_unlock(&the_controller->lock); ++ /* end the lock */ ++ ++ /* ++ * this function will sleep, so should be out of the lock. but, it's ok ++ * because we already marked vdev as being used. really? ++ */ ++ usbip_start_threads(&vdev->ud); ++ ++ rh_port_connect(rhport, speed); ++ ++ return count; ++} ++static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach); ++ ++static struct attribute *dev_attrs[] = { ++ &dev_attr_status.attr, ++ &dev_attr_detach.attr, ++ &dev_attr_attach.attr, ++ &dev_attr_usbip_debug.attr, ++ NULL, ++}; ++ ++struct attribute_group dev_attr_group = { ++ .attrs = dev_attrs, ++}; +diff --git a/drivers/staging/usbip/vhci_tx.c b/drivers/staging/usbip/vhci_tx.c +new file mode 100644 +index 0000000..1f552a9 +--- /dev/null ++++ b/drivers/staging/usbip/vhci_tx.c +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++#include "vhci.h" ++ ++ ++static void setup_cmd_submit_pdu(struct usbip_header *pdup, struct urb *urb) ++{ ++ struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv); ++ struct vhci_device *vdev = priv->vdev; ++ ++ dbg_vhci_tx("URB, local devnum %u, remote devid %u\n", ++ usb_pipedevice(urb->pipe), vdev->devid); ++ ++ pdup->base.command = USBIP_CMD_SUBMIT; ++ pdup->base.seqnum = priv->seqnum; ++ pdup->base.devid = vdev->devid; ++ if (usb_pipein(urb->pipe)) ++ pdup->base.direction = USBIP_DIR_IN; ++ else ++ pdup->base.direction = USBIP_DIR_OUT; ++ pdup->base.ep = usb_pipeendpoint(urb->pipe); ++ ++ usbip_pack_pdu(pdup, urb, USBIP_CMD_SUBMIT, 1); ++ ++ if (urb->setup_packet) ++ memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8); ++} ++ ++static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev) ++{ ++ unsigned long flags; ++ struct vhci_priv *priv, *tmp; ++ ++ spin_lock_irqsave(&vdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) { ++ list_move_tail(&priv->list, &vdev->priv_rx); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); ++ return priv; ++ } ++ ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); ++ ++ return NULL; ++} ++ ++ ++ ++static int vhci_send_cmd_submit(struct vhci_device *vdev) ++{ ++ struct vhci_priv *priv = NULL; ++ ++ struct msghdr msg; ++ struct kvec iov[3]; ++ size_t txsize; ++ ++ size_t total_size = 0; ++ ++ while ((priv = dequeue_from_priv_tx(vdev)) != NULL) { ++ int ret; ++ struct urb *urb = priv->urb; ++ struct usbip_header pdu_header; ++ void *iso_buffer = NULL; ++ ++ txsize = 0; ++ memset(&pdu_header, 0, sizeof(pdu_header)); ++ memset(&msg, 0, sizeof(msg)); ++ memset(&iov, 0, sizeof(iov)); ++ ++ dbg_vhci_tx("setup txdata urb %p\n", urb); ++ ++ ++ /* 1. setup usbip_header */ ++ setup_cmd_submit_pdu(&pdu_header, urb); ++ usbip_header_correct_endian(&pdu_header, 1); ++ ++ iov[0].iov_base = &pdu_header; ++ iov[0].iov_len = sizeof(pdu_header); ++ txsize += sizeof(pdu_header); ++ ++ /* 2. setup transfer buffer */ ++ if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) { ++ iov[1].iov_base = urb->transfer_buffer; ++ iov[1].iov_len = urb->transfer_buffer_length; ++ txsize += urb->transfer_buffer_length; ++ } ++ ++ /* 3. setup iso_packet_descriptor */ ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ ssize_t len = 0; ++ ++ iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len); ++ if (!iso_buffer) { ++ usbip_event_add(&vdev->ud, ++ SDEV_EVENT_ERROR_MALLOC); ++ return -1; ++ } ++ ++ iov[2].iov_base = iso_buffer; ++ iov[2].iov_len = len; ++ txsize += len; ++ } ++ ++ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize); ++ if (ret != txsize) { ++ uerr("sendmsg failed!, retval %d for %zd\n", ret, ++ txsize); ++ kfree(iso_buffer); ++ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP); ++ return -1; ++ } ++ ++ kfree(iso_buffer); ++ dbg_vhci_tx("send txdata\n"); ++ ++ total_size += txsize; ++ } ++ ++ return total_size; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev) ++{ ++ unsigned long flags; ++ struct vhci_unlink *unlink, *tmp; ++ ++ spin_lock_irqsave(&vdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { ++ list_move_tail(&unlink->list, &vdev->unlink_rx); ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); ++ return unlink; ++ } ++ ++ spin_unlock_irqrestore(&vdev->priv_lock, flags); ++ ++ return NULL; ++} ++ ++static int vhci_send_cmd_unlink(struct vhci_device *vdev) ++{ ++ struct vhci_unlink *unlink = NULL; ++ ++ struct msghdr msg; ++ struct kvec iov[3]; ++ size_t txsize; ++ ++ size_t total_size = 0; ++ ++ while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) { ++ int ret; ++ struct usbip_header pdu_header; ++ ++ txsize = 0; ++ memset(&pdu_header, 0, sizeof(pdu_header)); ++ memset(&msg, 0, sizeof(msg)); ++ memset(&iov, 0, sizeof(iov)); ++ ++ dbg_vhci_tx("setup cmd unlink, %lu \n", unlink->seqnum); ++ ++ ++ /* 1. setup usbip_header */ ++ pdu_header.base.command = USBIP_CMD_UNLINK; ++ pdu_header.base.seqnum = unlink->seqnum; ++ pdu_header.base.devid = vdev->devid; ++ pdu_header.base.ep = 0; ++ pdu_header.u.cmd_unlink.seqnum = unlink->unlink_seqnum; ++ ++ usbip_header_correct_endian(&pdu_header, 1); ++ ++ iov[0].iov_base = &pdu_header; ++ iov[0].iov_len = sizeof(pdu_header); ++ txsize += sizeof(pdu_header); ++ ++ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize); ++ if (ret != txsize) { ++ uerr("sendmsg failed!, retval %d for %zd\n", ret, ++ txsize); ++ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP); ++ return -1; ++ } ++ ++ ++ dbg_vhci_tx("send txdata\n"); ++ ++ total_size += txsize; ++ } ++ ++ return total_size; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++void vhci_tx_loop(struct usbip_task *ut) ++{ ++ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_tx); ++ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); ++ ++ while (1) { ++ if (signal_pending(current)) { ++ uinfo("vhci_tx signal catched\n"); ++ break; ++ } ++ ++ if (vhci_send_cmd_submit(vdev) < 0) ++ break; ++ ++ if (vhci_send_cmd_unlink(vdev) < 0) ++ break; ++ ++ wait_event_interruptible(vdev->waitq_tx, ++ (!list_empty(&vdev->priv_tx) || ++ !list_empty(&vdev->unlink_tx))); ++ ++ dbg_vhci_tx("pending urbs ?, now wake up\n"); ++ } ++} +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0013-Staging-USB-IP-add-host-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0013-Staging-USB-IP-add-host-driver.patch new file mode 100644 index 000000000..174e81caa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0013-Staging-USB-IP-add-host-driver.patch @@ -0,0 +1,1959 @@ +From 4d7b5c7f8ad49b7f01fb8aed83c560ac43cfbda8 Mon Sep 17 00:00:00 2001 +From: Takahiro Hirofuchi +Date: Wed, 9 Jul 2008 14:56:51 -0600 +Subject: [PATCH 13/23] Staging: USB/IP: add host driver +Patch-mainline: 2.6.28 + +This adds the USB IP client driver + +Brian Merrell cleaned up a lot of this code and submitted it for +inclusion. Greg also did a lot of cleanup. + +Signed-off-by: Brian G. Merrell +Cc: Takahiro Hirofuchi +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/usbip/Kconfig | 11 + + drivers/staging/usbip/Makefile | 3 + + drivers/staging/usbip/stub.h | 95 ++++++ + drivers/staging/usbip/stub_dev.c | 483 +++++++++++++++++++++++++++++ + drivers/staging/usbip/stub_main.c | 300 ++++++++++++++++++ + drivers/staging/usbip/stub_rx.c | 615 +++++++++++++++++++++++++++++++++++++ + drivers/staging/usbip/stub_tx.c | 371 ++++++++++++++++++++++ + 7 files changed, 1878 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/usbip/stub.h + create mode 100644 drivers/staging/usbip/stub_dev.c + create mode 100644 drivers/staging/usbip/stub_main.c + create mode 100644 drivers/staging/usbip/stub_rx.c + create mode 100644 drivers/staging/usbip/stub_tx.c + +diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig +index c4d68e1..7426235 100644 +--- a/drivers/staging/usbip/Kconfig ++++ b/drivers/staging/usbip/Kconfig +@@ -23,3 +23,14 @@ config USB_IP_VHCI_HCD + + To compile this driver as a module, choose M here: the + module will be called vhci_hcd. ++ ++config USB_IP_HOST ++ tristate "USB IP host driver" ++ depends on USB_IP_COMMON ++ default N ++ ---help--- ++ This enables the USB IP device driver which will run on the ++ host machine. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called usbip. +diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile +index 6ef4c39..179f421 100644 +--- a/drivers/staging/usbip/Makefile ++++ b/drivers/staging/usbip/Makefile +@@ -4,6 +4,9 @@ usbip_common_mod-objs := usbip_common.o usbip_event.o + obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o + vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o + ++obj-$(CONFIG_USB_IP_HOST) += usbip.o ++usbip-objs := stub_dev.o stub_main.o stub_rx.o stub_tx.o ++ + ifeq ($(CONFIG_USB_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG + endif +diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h +new file mode 100644 +index 0000000..f541a3a +--- /dev/null ++++ b/drivers/staging/usbip/stub.h +@@ -0,0 +1,95 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct stub_device { ++ struct usb_interface *interface; ++ struct list_head list; ++ ++ struct usbip_device ud; ++ __u32 devid; ++ ++ /* ++ * stub_priv preserves private data of each urb. ++ * It is allocated as stub_priv_cache and assigned to urb->context. ++ * ++ * stub_priv is always linked to any one of 3 lists; ++ * priv_init: linked to this until the comletion of a urb. ++ * priv_tx : linked to this after the completion of a urb. ++ * priv_free: linked to this after the sending of the result. ++ * ++ * Any of these list operations should be locked by priv_lock. ++ */ ++ spinlock_t priv_lock; ++ struct list_head priv_init; ++ struct list_head priv_tx; ++ struct list_head priv_free; ++ ++ /* see comments for unlinking in stub_rx.c */ ++ struct list_head unlink_tx; ++ struct list_head unlink_free; ++ ++ ++ wait_queue_head_t tx_waitq; ++}; ++ ++/* private data into urb->priv */ ++struct stub_priv { ++ unsigned long seqnum; ++ struct list_head list; ++ struct stub_device *sdev; ++ struct urb *urb; ++ ++ int unlinking; ++}; ++ ++struct stub_unlink { ++ unsigned long seqnum; ++ struct list_head list; ++ __u32 status; ++}; ++ ++ ++extern struct kmem_cache *stub_priv_cache; ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* prototype declarations */ ++ ++/* stub_tx.c */ ++void stub_complete(struct urb *); ++void stub_tx_loop(struct usbip_task *); ++ ++/* stub_dev.c */ ++extern struct usb_driver stub_driver; ++ ++/* stub_rx.c */ ++void stub_rx_loop(struct usbip_task *); ++void stub_enqueue_ret_unlink(struct stub_device *, __u32, __u32); ++ ++/* stub_main.c */ ++int match_busid(char *busid); ++void stub_device_cleanup_urbs(struct stub_device *sdev); +diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c +new file mode 100644 +index 0000000..ee455a0 +--- /dev/null ++++ b/drivers/staging/usbip/stub_dev.c +@@ -0,0 +1,483 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++#include "stub.h" ++ ++ ++ ++static int stub_probe(struct usb_interface *interface, ++ const struct usb_device_id *id); ++static void stub_disconnect(struct usb_interface *interface); ++ ++ ++/* ++ * Define device IDs here if you want to explicitly limit exportable devices. ++ * In the most cases, wild card matching will be ok because driver binding can ++ * be changed dynamically by a userland program. ++ */ ++static struct usb_device_id stub_table[] = { ++#if 0 ++ /* just an example */ ++ { USB_DEVICE(0x05ac, 0x0301) }, /* Mac 1 button mouse */ ++ { USB_DEVICE(0x0430, 0x0009) }, /* Plat Home Keyboard */ ++ { USB_DEVICE(0x059b, 0x0001) }, /* Iomega USB Zip 100 */ ++ { USB_DEVICE(0x04b3, 0x4427) }, /* IBM USB CD-ROM */ ++ { USB_DEVICE(0x05a9, 0xa511) }, /* LifeView USB cam */ ++ { USB_DEVICE(0x55aa, 0x0201) }, /* Imation card reader */ ++ { USB_DEVICE(0x046d, 0x0870) }, /* Qcam Express(QV-30) */ ++ { USB_DEVICE(0x04bb, 0x0101) }, /* IO-DATA HD 120GB */ ++ { USB_DEVICE(0x04bb, 0x0904) }, /* IO-DATA USB-ET/TX */ ++ { USB_DEVICE(0x04bb, 0x0201) }, /* IO-DATA USB-ET/TX */ ++ { USB_DEVICE(0x08bb, 0x2702) }, /* ONKYO USB Speaker */ ++ { USB_DEVICE(0x046d, 0x08b2) }, /* Logicool Qcam 4000 Pro */ ++#endif ++ /* magic for wild card */ ++ { .driver_info = 1 }, ++ { 0, } /* Terminating entry */ ++}; ++MODULE_DEVICE_TABLE(usb, stub_table); ++ ++struct usb_driver stub_driver = { ++ .name = "usbip", ++ .probe = stub_probe, ++ .disconnect = stub_disconnect, ++ .id_table = stub_table, ++}; ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Define sysfs entries for a usbip-bound device */ ++ ++ ++/* ++ * usbip_status shows status of usbip as long as this driver is bound to the ++ * target device. ++ */ ++static ssize_t show_status(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct stub_device *sdev = dev_get_drvdata(dev); ++ int status; ++ ++ if (!sdev) { ++ dev_err(dev, "sdev is null\n"); ++ return -ENODEV; ++ } ++ ++ spin_lock(&sdev->ud.lock); ++ status = sdev->ud.status; ++ spin_unlock(&sdev->ud.lock); ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", status); ++} ++static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL); ++ ++/* ++ * usbip_sockfd gets a socket descriptor of an established TCP connection that ++ * is used to transfer usbip requests by kernel threads. -1 is a magic number ++ * by which usbip connection is finished. ++ */ ++static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct stub_device *sdev = dev_get_drvdata(dev); ++ int sockfd = 0; ++ struct socket *socket; ++ ++ if (!sdev) { ++ dev_err(dev, "sdev is null\n"); ++ return -ENODEV; ++ } ++ ++ sscanf(buf, "%d", &sockfd); ++ ++ if (sockfd != -1) { ++ dev_info(dev, "stub up\n"); ++ ++ spin_lock(&sdev->ud.lock); ++ ++ if (sdev->ud.status != SDEV_ST_AVAILABLE) { ++ dev_err(dev, "not ready\n"); ++ spin_unlock(&sdev->ud.lock); ++ return -EINVAL; ++ } ++ ++ socket = sockfd_to_socket(sockfd); ++ if (!socket) { ++ spin_unlock(&sdev->ud.lock); ++ return -EINVAL; ++ } ++ ++#if 0 ++ setnodelay(socket); ++ setkeepalive(socket); ++ setreuse(socket); ++#endif ++ ++ sdev->ud.tcp_socket = socket; ++ ++ spin_unlock(&sdev->ud.lock); ++ ++ usbip_start_threads(&sdev->ud); ++ ++ spin_lock(&sdev->ud.lock); ++ sdev->ud.status = SDEV_ST_USED; ++ spin_unlock(&sdev->ud.lock); ++ ++ } else { ++ dev_info(dev, "stub down\n"); ++ ++ spin_lock(&sdev->ud.lock); ++ if (sdev->ud.status != SDEV_ST_USED) { ++ spin_unlock(&sdev->ud.lock); ++ return -EINVAL; ++ } ++ spin_unlock(&sdev->ud.lock); ++ ++ usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN); ++ } ++ ++ return count; ++} ++static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd); ++ ++static int stub_add_files(struct device *dev) ++{ ++ int err = 0; ++ ++ err = device_create_file(dev, &dev_attr_usbip_status); ++ if (err) ++ goto err_status; ++ ++ err = device_create_file(dev, &dev_attr_usbip_sockfd); ++ if (err) ++ goto err_sockfd; ++ ++ err = device_create_file(dev, &dev_attr_usbip_debug); ++ if (err) ++ goto err_debug; ++ ++ return 0; ++ ++err_debug: ++ device_remove_file(dev, &dev_attr_usbip_sockfd); ++ ++err_sockfd: ++ device_remove_file(dev, &dev_attr_usbip_status); ++ ++err_status: ++ return err; ++} ++ ++static void stub_remove_files(struct device *dev) ++{ ++ device_remove_file(dev, &dev_attr_usbip_status); ++ device_remove_file(dev, &dev_attr_usbip_sockfd); ++ device_remove_file(dev, &dev_attr_usbip_debug); ++} ++ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Event handler functions called by an event handler thread */ ++ ++static void stub_shutdown_connection(struct usbip_device *ud) ++{ ++ struct stub_device *sdev = container_of(ud, struct stub_device, ud); ++ ++ /* ++ * When removing an exported device, kernel panic sometimes occurred ++ * and then EIP was sk_wait_data of stub_rx thread. Is this because ++ * sk_wait_data returned though stub_rx thread was already finished by ++ * step 1? ++ */ ++ if (ud->tcp_socket) { ++ udbg("shutdown tcp_socket %p\n", ud->tcp_socket); ++ kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); ++ } ++ ++ /* 1. stop threads */ ++ usbip_stop_threads(ud); ++ ++ /* 2. close the socket */ ++ /* ++ * tcp_socket is freed after threads are killed. ++ * So usbip_xmit do not touch NULL socket. ++ */ ++ if (ud->tcp_socket) { ++ sock_release(ud->tcp_socket); ++ ud->tcp_socket = NULL; ++ } ++ ++ /* 3. free used data */ ++ stub_device_cleanup_urbs(sdev); ++ ++ /* 4. free stub_unlink */ ++ { ++ unsigned long flags; ++ struct stub_unlink *unlink, *tmp; ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) { ++ list_del(&unlink->list); ++ kfree(unlink); ++ } ++ ++ list_for_each_entry_safe(unlink, tmp, ++ &sdev->unlink_free, list) { ++ list_del(&unlink->list); ++ kfree(unlink); ++ } ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ } ++} ++ ++static void stub_device_reset(struct usbip_device *ud) ++{ ++ struct stub_device *sdev = container_of(ud, struct stub_device, ud); ++ struct usb_device *udev = interface_to_usbdev(sdev->interface); ++ int ret; ++ ++ udbg("device reset"); ++ ret = usb_lock_device_for_reset(udev, sdev->interface); ++ if (ret < 0) { ++ dev_err(&udev->dev, "lock for reset\n"); ++ ++ spin_lock(&ud->lock); ++ ud->status = SDEV_ST_ERROR; ++ spin_unlock(&ud->lock); ++ ++ return; ++ } ++ ++ /* try to reset the device */ ++ ret = usb_reset_device(udev); ++ ++ usb_unlock_device(udev); ++ ++ spin_lock(&ud->lock); ++ if (ret) { ++ dev_err(&udev->dev, "device reset\n"); ++ ud->status = SDEV_ST_ERROR; ++ ++ } else { ++ dev_info(&udev->dev, "device reset\n"); ++ ud->status = SDEV_ST_AVAILABLE; ++ ++ } ++ spin_unlock(&ud->lock); ++ ++ return; ++} ++ ++static void stub_device_unusable(struct usbip_device *ud) ++{ ++ spin_lock(&ud->lock); ++ ud->status = SDEV_ST_ERROR; ++ spin_unlock(&ud->lock); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/** ++ * stub_device_alloc - allocate a new stub_device struct ++ * @interface: usb_interface of a new device ++ * ++ * Allocates and initializes a new stub_device struct. ++ */ ++static struct stub_device *stub_device_alloc(struct usb_interface *interface) ++{ ++ struct stub_device *sdev; ++ int busnum = interface_to_busnum(interface); ++ int devnum = interface_to_devnum(interface); ++ ++ dev_dbg(&interface->dev, "allocating stub device"); ++ ++ /* yes, it's a new device */ ++ sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL); ++ if (!sdev) { ++ dev_err(&interface->dev, "no memory for stub_device\n"); ++ return NULL; ++ } ++ ++ sdev->interface = interface; ++ ++ /* ++ * devid is defined with devnum when this driver is first allocated. ++ * devnum may change later if a device is reset. However, devid never ++ * changes during a usbip connection. ++ */ ++ sdev->devid = (busnum << 16) | devnum; ++ ++ usbip_task_init(&sdev->ud.tcp_rx, "stub_rx", stub_rx_loop); ++ usbip_task_init(&sdev->ud.tcp_tx, "stub_tx", stub_tx_loop); ++ ++ sdev->ud.side = USBIP_STUB; ++ sdev->ud.status = SDEV_ST_AVAILABLE; ++ /* sdev->ud.lock = SPIN_LOCK_UNLOCKED; */ ++ spin_lock_init(&sdev->ud.lock); ++ sdev->ud.tcp_socket = NULL; ++ ++ INIT_LIST_HEAD(&sdev->priv_init); ++ INIT_LIST_HEAD(&sdev->priv_tx); ++ INIT_LIST_HEAD(&sdev->priv_free); ++ INIT_LIST_HEAD(&sdev->unlink_free); ++ INIT_LIST_HEAD(&sdev->unlink_tx); ++ /* sdev->priv_lock = SPIN_LOCK_UNLOCKED; */ ++ spin_lock_init(&sdev->priv_lock); ++ ++ init_waitqueue_head(&sdev->tx_waitq); ++ ++ sdev->ud.eh_ops.shutdown = stub_shutdown_connection; ++ sdev->ud.eh_ops.reset = stub_device_reset; ++ sdev->ud.eh_ops.unusable = stub_device_unusable; ++ ++ usbip_start_eh(&sdev->ud); ++ ++ udbg("register new interface\n"); ++ return sdev; ++} ++ ++static int stub_device_free(struct stub_device *sdev) ++{ ++ if (!sdev) ++ return -EINVAL; ++ ++ kfree(sdev); ++ udbg("kfree udev ok\n"); ++ ++ return 0; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* ++ * If a usb device has multiple active interfaces, this driver is bound to all ++ * the active interfaces. However, usbip exports *a* usb device (i.e., not *an* ++ * active interface). Currently, a userland program must ensure that it ++ * looks at the usbip's sysfs entries of only the first active interface. ++ * ++ * TODO: use "struct usb_device_driver" to bind a usb device. ++ * However, it seems it is not fully supported in mainline kernel yet ++ * (2.6.19.2). ++ */ ++static int stub_probe(struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *udev = interface_to_usbdev(interface); ++ struct stub_device *sdev = NULL; ++ char *udev_busid = interface->dev.parent->bus_id; ++ int err = 0; ++ ++ dev_dbg(&interface->dev, "Enter\n"); ++ ++ /* check we should claim or not by busid_table */ ++ if (match_busid(udev_busid)) { ++ dev_info(&interface->dev, ++ "this device %s is not in match_busid table. skip!\n", ++ udev_busid); ++ ++ /* ++ * Return value should be ENODEV or ENOXIO to continue trying ++ * other matched drivers by the driver core. ++ * See driver_probe_device() in driver/base/dd.c ++ */ ++ return -ENODEV; ++ } ++ ++ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) { ++ udbg("this device %s is a usb hub device. skip!\n", ++ udev_busid); ++ return -ENODEV; ++ } ++ ++ if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { ++ udbg("this device %s is attached on vhci_hcd. skip!\n", ++ udev_busid); ++ return -ENODEV; ++ } ++ ++ /* ok. this is my device. */ ++ sdev = stub_device_alloc(interface); ++ if (!sdev) ++ return -ENOMEM; ++ ++ dev_info(&interface->dev, "USB/IP Stub: register a new interface " ++ "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, ++ interface->cur_altsetting->desc.bInterfaceNumber); ++ ++ /* set private data to usb_interface */ ++ usb_set_intfdata(interface, sdev); ++ ++ err = stub_add_files(&interface->dev); ++ if (err) { ++ dev_err(&interface->dev, "create sysfs files for %s\n", ++ udev_busid); ++ return err; ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * called in usb_disconnect() or usb_deregister() ++ * but only if actconfig(active configuration) exists ++ */ ++static void stub_disconnect(struct usb_interface *interface) ++{ ++ struct stub_device *sdev = usb_get_intfdata(interface); ++ ++ udbg("Enter\n"); ++ ++ /* get stub_device */ ++ if (!sdev) { ++ err(" could not get device from inteface data"); ++ /* BUG(); */ ++ return; ++ } ++ ++ usb_set_intfdata(interface, NULL); ++ ++ ++ /* ++ * NOTE: ++ * rx/tx threads are invoked for each usb_device. ++ */ ++ stub_remove_files(&interface->dev); ++ ++ /* 1. shutdown the current connection */ ++ usbip_event_add(&sdev->ud, SDEV_EVENT_REMOVED); ++ ++ /* 2. wait for the stop of the event handler */ ++ usbip_stop_eh(&sdev->ud); ++ ++ /* 3. free sdev */ ++ stub_device_free(sdev); ++ ++ ++ udbg("bye\n"); ++} +diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c +new file mode 100644 +index 0000000..c665d7f +--- /dev/null ++++ b/drivers/staging/usbip/stub_main.c +@@ -0,0 +1,300 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++ ++#include "usbip_common.h" ++#include "stub.h" ++ ++/* Version Information */ ++#define DRIVER_VERSION "1.0" ++#define DRIVER_AUTHOR "Takahiro Hirofuchi" ++#define DRIVER_DESC "Stub Driver for USB/IP" ++ ++/* stub_priv is allocated from stub_priv_cache */ ++struct kmem_cache *stub_priv_cache; ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Define sysfs entries for the usbip driver */ ++ ++ ++/* ++ * busid_tables defines matching busids that usbip can grab. A user can change ++ * dynamically what device is locally used and what device is exported to a ++ * remote host. ++ */ ++#define MAX_BUSID 16 ++static char busid_table[MAX_BUSID][BUS_ID_SIZE]; ++static spinlock_t busid_table_lock; ++ ++ ++int match_busid(char *busid) ++{ ++ int i; ++ ++ spin_lock(&busid_table_lock); ++ ++ for (i = 0; i < MAX_BUSID; i++) ++ if (busid_table[i][0]) ++ if (!strncmp(busid_table[i], busid, BUS_ID_SIZE)) { ++ /* already registerd */ ++ spin_unlock(&busid_table_lock); ++ return 0; ++ } ++ ++ spin_unlock(&busid_table_lock); ++ ++ return 1; ++} ++ ++static ssize_t show_match_busid(struct device_driver *drv, char *buf) ++{ ++ int i; ++ char *out = buf; ++ ++ spin_lock(&busid_table_lock); ++ ++ for (i = 0; i < MAX_BUSID; i++) ++ if (busid_table[i][0]) ++ out += sprintf(out, "%s ", busid_table[i]); ++ ++ spin_unlock(&busid_table_lock); ++ ++ out += sprintf(out, "\n"); ++ ++ return out - buf; ++} ++ ++static int add_match_busid(char *busid) ++{ ++ int i; ++ ++ if (!match_busid(busid)) ++ return 0; ++ ++ spin_lock(&busid_table_lock); ++ ++ for (i = 0; i < MAX_BUSID; i++) ++ if (!busid_table[i][0]) { ++ strncpy(busid_table[i], busid, BUS_ID_SIZE); ++ spin_unlock(&busid_table_lock); ++ return 0; ++ } ++ ++ spin_unlock(&busid_table_lock); ++ ++ return -1; ++} ++ ++static int del_match_busid(char *busid) ++{ ++ int i; ++ ++ spin_lock(&busid_table_lock); ++ ++ for (i = 0; i < MAX_BUSID; i++) ++ if (!strncmp(busid_table[i], busid, BUS_ID_SIZE)) { ++ /* found */ ++ memset(busid_table[i], 0, BUS_ID_SIZE); ++ spin_unlock(&busid_table_lock); ++ return 0; ++ } ++ ++ spin_unlock(&busid_table_lock); ++ ++ return -1; ++} ++ ++static ssize_t store_match_busid(struct device_driver *dev, const char *buf, ++ size_t count) ++{ ++ int len; ++ char busid[BUS_ID_SIZE]; ++ ++ if (count < 5) ++ return -EINVAL; ++ ++ /* strnlen() does not include \0 */ ++ len = strnlen(buf + 4, BUS_ID_SIZE); ++ ++ /* busid needs to include \0 termination */ ++ if (!(len < BUS_ID_SIZE)) ++ return -EINVAL; ++ ++ strncpy(busid, buf + 4, BUS_ID_SIZE); ++ ++ ++ if (!strncmp(buf, "add ", 4)) { ++ if (add_match_busid(busid) < 0) ++ return -ENOMEM; ++ else { ++ udbg("add busid %s\n", busid); ++ return count; ++ } ++ } else if (!strncmp(buf, "del ", 4)) { ++ if (del_match_busid(busid) < 0) ++ return -ENODEV; ++ else { ++ udbg("del busid %s\n", busid); ++ return count; ++ } ++ } else ++ return -EINVAL; ++} ++ ++static DRIVER_ATTR(match_busid, S_IRUSR|S_IWUSR, show_match_busid, ++ store_match_busid); ++ ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++/* Cleanup functions used to free private data */ ++ ++static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead) ++{ ++ struct stub_priv *priv, *tmp; ++ ++ list_for_each_entry_safe(priv, tmp, listhead, list) { ++ list_del(&priv->list); ++ return priv; ++ } ++ ++ return NULL; ++} ++ ++static struct stub_priv *stub_priv_pop(struct stub_device *sdev) ++{ ++ unsigned long flags; ++ struct stub_priv *priv; ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ priv = stub_priv_pop_from_listhead(&sdev->priv_init); ++ if (priv) { ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ return priv; ++ } ++ ++ priv = stub_priv_pop_from_listhead(&sdev->priv_tx); ++ if (priv) { ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ return priv; ++ } ++ ++ priv = stub_priv_pop_from_listhead(&sdev->priv_free); ++ if (priv) { ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ return priv; ++ } ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ return NULL; ++} ++ ++void stub_device_cleanup_urbs(struct stub_device *sdev) ++{ ++ struct stub_priv *priv; ++ ++ udbg("free sdev %p\n", sdev); ++ ++ while ((priv = stub_priv_pop(sdev))) { ++ struct urb *urb = priv->urb; ++ ++ udbg(" free urb %p\n", urb); ++ usb_kill_urb(urb); ++ ++ kmem_cache_free(stub_priv_cache, priv); ++ ++ if (urb->transfer_buffer != NULL) ++ kfree(urb->transfer_buffer); ++ ++ if (urb->setup_packet != NULL) ++ kfree(urb->setup_packet); ++ ++ usb_free_urb(urb); ++ } ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int __init usb_stub_init(void) ++{ ++ int ret; ++ ++ stub_priv_cache = kmem_cache_create("stub_priv", ++ sizeof(struct stub_priv), 0, ++ SLAB_HWCACHE_ALIGN, NULL); ++ ++ if (!stub_priv_cache) { ++ printk(KERN_ERR KBUILD_MODNAME ++ ": create stub_priv_cache error\n"); ++ return -ENOMEM; ++ } ++ ++ ret = usb_register(&stub_driver); ++ if (ret) { ++ printk(KERN_ERR KBUILD_MODNAME ": usb_register failed %d\n", ++ ret); ++ goto error_usb_register; ++ } ++ ++ printk(KERN_INFO KBUILD_MODNAME ":" ++ DRIVER_DESC ":" DRIVER_VERSION "\n"); ++ ++ memset(busid_table, 0, sizeof(busid_table)); ++ spin_lock_init(&busid_table_lock); ++ ++ ret = driver_create_file(&stub_driver.drvwrap.driver, ++ &driver_attr_match_busid); ++ ++ if (ret) { ++ printk(KERN_ERR KBUILD_MODNAME ": create driver sysfs\n"); ++ goto error_create_file; ++ } ++ ++ return ret; ++error_create_file: ++ usb_deregister(&stub_driver); ++error_usb_register: ++ kmem_cache_destroy(stub_priv_cache); ++ return ret; ++} ++ ++static void __exit usb_stub_exit(void) ++{ ++ driver_remove_file(&stub_driver.drvwrap.driver, ++ &driver_attr_match_busid); ++ ++ /* ++ * deregister() calls stub_disconnect() for all devices. Device ++ * specific data is cleared in stub_disconnect(). ++ */ ++ usb_deregister(&stub_driver); ++ ++ kmem_cache_destroy(stub_priv_cache); ++} ++ ++module_init(usb_stub_init); ++module_exit(usb_stub_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c +new file mode 100644 +index 0000000..36ce898 +--- /dev/null ++++ b/drivers/staging/usbip/stub_rx.c +@@ -0,0 +1,615 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++#include "stub.h" ++#include "../../usb/core/hcd.h" ++ ++ ++static int is_clear_halt_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ ++ return (req->bRequest == USB_REQ_CLEAR_FEATURE) && ++ (req->bRequestType == USB_RECIP_ENDPOINT) && ++ (req->wValue == USB_ENDPOINT_HALT); ++} ++ ++static int is_set_interface_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ ++ return (req->bRequest == USB_REQ_SET_INTERFACE) && ++ (req->bRequestType == USB_RECIP_INTERFACE); ++} ++ ++static int is_set_configuration_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ ++ return (req->bRequest == USB_REQ_SET_CONFIGURATION) && ++ (req->bRequestType == USB_RECIP_DEVICE); ++} ++ ++static int is_reset_device_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ __u16 value; ++ __u16 index; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ value = le16_to_cpu(req->wValue); ++ index = le16_to_cpu(req->wIndex); ++ ++ if ((req->bRequest == USB_REQ_SET_FEATURE) && ++ (req->bRequestType == USB_RT_PORT) && ++ (value = USB_PORT_FEAT_RESET)) { ++ dbg_stub_rx("reset_device_cmd, port %u\n", index); ++ return 1; ++ } else ++ return 0; ++} ++ ++static int tweak_clear_halt_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ int target_endp; ++ int target_dir; ++ int target_pipe; ++ int ret; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ ++ /* ++ * The stalled endpoint is specified in the wIndex value. The endpoint ++ * of the urb is the target of this clear_halt request (i.e., control ++ * endpoint). ++ */ ++ target_endp = le16_to_cpu(req->wIndex) & 0x000f; ++ ++ /* the stalled endpoint direction is IN or OUT?. USB_DIR_IN is 0x80. */ ++ target_dir = le16_to_cpu(req->wIndex) & 0x0080; ++ ++ if (target_dir) ++ target_pipe = usb_rcvctrlpipe(urb->dev, target_endp); ++ else ++ target_pipe = usb_sndctrlpipe(urb->dev, target_endp); ++ ++ ret = usb_clear_halt(urb->dev, target_pipe); ++ if (ret < 0) ++ uinfo("clear_halt error: devnum %d endp %d, %d\n", ++ urb->dev->devnum, target_endp, ret); ++ else ++ uinfo("clear_halt done: devnum %d endp %d\n", ++ urb->dev->devnum, target_endp); ++ ++ return ret; ++} ++ ++static int tweak_set_interface_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ __u16 alternate; ++ __u16 interface; ++ int ret; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ alternate = le16_to_cpu(req->wValue); ++ interface = le16_to_cpu(req->wIndex); ++ ++ dbg_stub_rx("set_interface: inf %u alt %u\n", interface, alternate); ++ ++ ret = usb_set_interface(urb->dev, interface, alternate); ++ if (ret < 0) ++ uinfo("set_interface error: inf %u alt %u, %d\n", ++ interface, alternate, ret); ++ else ++ uinfo("set_interface done: inf %u alt %u\n", ++ interface, ++ alternate); ++ ++ return ret; ++} ++ ++static int tweak_set_configuration_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ __u16 config; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ config = le16_to_cpu(req->wValue); ++ ++ /* ++ * I have never seen a multi-config device. Very rare. ++ * For most devices, this will be called to choose a default ++ * configuration only once in an initialization phase. ++ * ++ * set_configuration may change a device configuration and its device ++ * drivers will be unbound and assigned for a new device configuration. ++ * This means this usbip driver will be also unbound when called, then ++ * eventually reassigned to the device as far as driver matching ++ * condition is kept. ++ * ++ * Unfortunatelly, an existing usbip connection will be dropped ++ * due to this driver unbinding. So, skip here. ++ * A user may need to set a special configuration value before ++ * exporting the device. ++ */ ++ uinfo("set_configuration (%d) to %s\n", config, urb->dev->dev.bus_id); ++ uinfo("but, skip!\n"); ++ ++ return 0; ++ /* return usb_driver_set_configuration(urb->dev, config); */ ++} ++ ++static int tweak_reset_device_cmd(struct urb *urb) ++{ ++ struct usb_ctrlrequest *req; ++ __u16 value; ++ __u16 index; ++ int ret; ++ ++ req = (struct usb_ctrlrequest *) urb->setup_packet; ++ value = le16_to_cpu(req->wValue); ++ index = le16_to_cpu(req->wIndex); ++ ++ uinfo("reset_device (port %d) to %s\n", index, urb->dev->dev.bus_id); ++ ++ /* all interfaces should be owned by usbip driver, so just reset it. */ ++ ret = usb_lock_device_for_reset(urb->dev, NULL); ++ if (ret < 0) { ++ dev_err(&urb->dev->dev, "lock for reset\n"); ++ return ret; ++ } ++ ++ /* try to reset the device */ ++ ret = usb_reset_device(urb->dev); ++ if (ret < 0) ++ dev_err(&urb->dev->dev, "device reset\n"); ++ ++ usb_unlock_device(urb->dev); ++ ++ return ret; ++} ++ ++/* ++ * clear_halt, set_interface, and set_configuration require special tricks. ++ */ ++static void tweak_special_requests(struct urb *urb) ++{ ++ if (!urb || !urb->setup_packet) ++ return; ++ ++ if (usb_pipetype(urb->pipe) != PIPE_CONTROL) ++ return; ++ ++ if (is_clear_halt_cmd(urb)) ++ /* tweak clear_halt */ ++ tweak_clear_halt_cmd(urb); ++ ++ else if (is_set_interface_cmd(urb)) ++ /* tweak set_interface */ ++ tweak_set_interface_cmd(urb); ++ ++ else if (is_set_configuration_cmd(urb)) ++ /* tweak set_configuration */ ++ tweak_set_configuration_cmd(urb); ++ ++ else if (is_reset_device_cmd(urb)) ++ tweak_reset_device_cmd(urb); ++ else ++ dbg_stub_rx("no need to tweak\n"); ++} ++ ++/* ++ * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb(). ++ * By unlinking the urb asynchronously, stub_rx can continuously ++ * process coming urbs. Even if the urb is unlinked, its completion ++ * handler will be called and stub_tx will send a return pdu. ++ * ++ * See also comments about unlinking strategy in vhci_hcd.c. ++ */ ++static int stub_recv_cmd_unlink(struct stub_device *sdev, ++ struct usbip_header *pdu) ++{ ++ struct list_head *listhead = &sdev->priv_init; ++ struct list_head *ptr; ++ unsigned long flags; ++ ++ struct stub_priv *priv; ++ ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ for (ptr = listhead->next; ptr != listhead; ptr = ptr->next) { ++ priv = list_entry(ptr, struct stub_priv, list); ++ if (priv->seqnum == pdu->u.cmd_unlink.seqnum) { ++ int ret; ++ ++ dev_info(&priv->urb->dev->dev, "unlink urb %p\n", ++ priv->urb); ++ ++ /* ++ * This matched urb is not completed yet (i.e., be in ++ * flight in usb hcd hardware/driver). Now we are ++ * cancelling it. The unlinking flag means that we are ++ * now not going to return the normal result pdu of a ++ * submission request, but going to return a result pdu ++ * of the unlink request. ++ */ ++ priv->unlinking = 1; ++ ++ /* ++ * In the case that unlinking flag is on, prev->seqnum ++ * is changed from the seqnum of the cancelling urb to ++ * the seqnum of the unlink request. This will be used ++ * to make the result pdu of the unlink request. ++ */ ++ priv->seqnum = pdu->base.seqnum; ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ /* ++ * usb_unlink_urb() is now out of spinlocking to avoid ++ * spinlock recursion since stub_complete() is ++ * sometimes called in this context but not in the ++ * interrupt context. If stub_complete() is executed ++ * before we call usb_unlink_urb(), usb_unlink_urb() ++ * will return an error value. In this case, stub_tx ++ * will return the result pdu of this unlink request ++ * though submission is completed and actual unlinking ++ * is not executed. OK? ++ */ ++ /* In the above case, urb->status is not -ECONNRESET, ++ * so a driver in a client host will know the failure ++ * of the unlink request ? ++ */ ++ ret = usb_unlink_urb(priv->urb); ++ if (ret != -EINPROGRESS) ++ dev_err(&priv->urb->dev->dev, ++ "failed to unlink a urb %p, ret %d\n", ++ priv->urb, ret); ++ return 0; ++ } ++ } ++ ++ dbg_stub_rx("seqnum %d is not pending\n", pdu->u.cmd_unlink.seqnum); ++ ++ /* ++ * The urb of the unlink target is not found in priv_init queue. It was ++ * already completed and its results is/was going to be sent by a ++ * CMD_RET pdu. In this case, usb_unlink_urb() is not needed. We only ++ * return the completeness of this unlink request to vhci_hcd. ++ */ ++ stub_enqueue_ret_unlink(sdev, pdu->base.seqnum, 0); ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ ++ return 0; ++} ++ ++static int valid_request(struct stub_device *sdev, struct usbip_header *pdu) ++{ ++ struct usbip_device *ud = &sdev->ud; ++ ++ if (pdu->base.devid == sdev->devid) { ++ spin_lock(&ud->lock); ++ if (ud->status == SDEV_ST_USED) { ++ /* A request is valid. */ ++ spin_unlock(&ud->lock); ++ return 1; ++ } ++ spin_unlock(&ud->lock); ++ } ++ ++ return 0; ++} ++ ++static struct stub_priv *stub_priv_alloc(struct stub_device *sdev, ++ struct usbip_header *pdu) ++{ ++ struct stub_priv *priv; ++ struct usbip_device *ud = &sdev->ud; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ priv = kmem_cache_alloc(stub_priv_cache, GFP_ATOMIC); ++ if (!priv) { ++ dev_err(&sdev->interface->dev, "alloc stub_priv\n"); ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); ++ return NULL; ++ } ++ ++ memset(priv, 0, sizeof(struct stub_priv)); ++ ++ priv->seqnum = pdu->base.seqnum; ++ priv->sdev = sdev; ++ ++ /* ++ * After a stub_priv is linked to a list_head, ++ * our error handler can free allocated data. ++ */ ++ list_add_tail(&priv->list, &sdev->priv_init); ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ return priv; ++} ++ ++ ++static struct usb_host_endpoint *get_ep_from_epnum(struct usb_device *udev, ++ int epnum0) ++{ ++ struct usb_host_config *config; ++ int i = 0, j = 0; ++ struct usb_host_endpoint *ep = NULL; ++ int epnum; ++ int found = 0; ++ ++ if (epnum0 == 0) ++ return &udev->ep0; ++ ++ config = udev->actconfig; ++ if (!config) ++ return NULL; ++ ++ for (i = 0; i < config->desc.bNumInterfaces; i++) { ++ struct usb_host_interface *setting; ++ ++ setting = config->interface[i]->cur_altsetting; ++ ++ for (j = 0; j < setting->desc.bNumEndpoints; j++) { ++ ep = &setting->endpoint[j]; ++ epnum = (ep->desc.bEndpointAddress & 0x7f); ++ ++ if (epnum == epnum0) { ++ /* uinfo("found epnum %d\n", epnum0); */ ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (found) ++ return ep; ++ else ++ return NULL; ++} ++ ++ ++static int get_pipe(struct stub_device *sdev, int epnum, int dir) ++{ ++ struct usb_device *udev = interface_to_usbdev(sdev->interface); ++ struct usb_host_endpoint *ep; ++ struct usb_endpoint_descriptor *epd = NULL; ++ ++ ep = get_ep_from_epnum(udev, epnum); ++ if (!ep) { ++ dev_err(&sdev->interface->dev, "no such endpoint?, %d\n", ++ epnum); ++ BUG(); ++ } ++ ++ epd = &ep->desc; ++ ++ ++#if 0 ++ /* epnum 0 is always control */ ++ if (epnum == 0) { ++ if (dir == USBIP_DIR_OUT) ++ return usb_sndctrlpipe(udev, 0); ++ else ++ return usb_rcvctrlpipe(udev, 0); ++ } ++#endif ++ ++ if (usb_endpoint_xfer_control(epd)) { ++ if (dir == USBIP_DIR_OUT) ++ return usb_sndctrlpipe(udev, epnum); ++ else ++ return usb_rcvctrlpipe(udev, epnum); ++ } ++ ++ if (usb_endpoint_xfer_bulk(epd)) { ++ if (dir == USBIP_DIR_OUT) ++ return usb_sndbulkpipe(udev, epnum); ++ else ++ return usb_rcvbulkpipe(udev, epnum); ++ } ++ ++ if (usb_endpoint_xfer_int(epd)) { ++ if (dir == USBIP_DIR_OUT) ++ return usb_sndintpipe(udev, epnum); ++ else ++ return usb_rcvintpipe(udev, epnum); ++ } ++ ++ if (usb_endpoint_xfer_isoc(epd)) { ++ if (dir == USBIP_DIR_OUT) ++ return usb_sndisocpipe(udev, epnum); ++ else ++ return usb_rcvisocpipe(udev, epnum); ++ } ++ ++ /* NOT REACHED */ ++ dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum); ++ return 0; ++} ++ ++static void stub_recv_cmd_submit(struct stub_device *sdev, ++ struct usbip_header *pdu) ++{ ++ int ret; ++ struct stub_priv *priv; ++ struct usbip_device *ud = &sdev->ud; ++ struct usb_device *udev = interface_to_usbdev(sdev->interface); ++ int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction); ++ ++ ++ priv = stub_priv_alloc(sdev, pdu); ++ if (!priv) ++ return; ++ ++ /* setup a urb */ ++ if (usb_pipeisoc(pipe)) ++ priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets, ++ GFP_KERNEL); ++ else ++ priv->urb = usb_alloc_urb(0, GFP_KERNEL); ++ ++ if (!priv->urb) { ++ dev_err(&sdev->interface->dev, "malloc urb\n"); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); ++ return; ++ } ++ ++ /* set priv->urb->transfer_buffer */ ++ if (pdu->u.cmd_submit.transfer_buffer_length > 0) { ++ priv->urb->transfer_buffer = ++ kzalloc(pdu->u.cmd_submit.transfer_buffer_length, ++ GFP_KERNEL); ++ if (!priv->urb->transfer_buffer) { ++ dev_err(&sdev->interface->dev, "malloc x_buff\n"); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); ++ return; ++ } ++ } ++ ++ /* set priv->urb->setup_packet */ ++ priv->urb->setup_packet = kzalloc(8, GFP_KERNEL); ++ if (!priv->urb->setup_packet) { ++ dev_err(&sdev->interface->dev, "allocate setup_packet\n"); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); ++ return; ++ } ++ memcpy(priv->urb->setup_packet, &pdu->u.cmd_submit.setup, 8); ++ ++ /* set other members from the base header of pdu */ ++ priv->urb->context = (void *) priv; ++ priv->urb->dev = udev; ++ priv->urb->pipe = pipe; ++ priv->urb->complete = stub_complete; ++ ++ usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0); ++ ++ ++ if (usbip_recv_xbuff(ud, priv->urb) < 0) ++ return; ++ ++ if (usbip_recv_iso(ud, priv->urb) < 0) ++ return; ++ ++ /* no need to submit an intercepted request, but harmless? */ ++ tweak_special_requests(priv->urb); ++ ++ /* urb is now ready to submit */ ++ ret = usb_submit_urb(priv->urb, GFP_KERNEL); ++ ++ if (ret == 0) ++ dbg_stub_rx("submit urb ok, seqnum %u\n", pdu->base.seqnum); ++ else { ++ dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret); ++ usbip_dump_header(pdu); ++ usbip_dump_urb(priv->urb); ++ ++ /* ++ * Pessimistic. ++ * This connection will be discarded. ++ */ ++ usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT); ++ } ++ ++ dbg_stub_rx("Leave\n"); ++ return; ++} ++ ++/* recv a pdu */ ++static void stub_rx_pdu(struct usbip_device *ud) ++{ ++ int ret; ++ struct usbip_header pdu; ++ struct stub_device *sdev = container_of(ud, struct stub_device, ud); ++ struct device *dev = &sdev->interface->dev; ++ ++ dbg_stub_rx("Enter\n"); ++ ++ memset(&pdu, 0, sizeof(pdu)); ++ ++ /* 1. receive a pdu header */ ++ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0); ++ if (ret != sizeof(pdu)) { ++ dev_err(dev, "recv a header, %d\n", ret); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ return; ++ } ++ ++ usbip_header_correct_endian(&pdu, 0); ++ ++ if (dbg_flag_stub_rx) ++ usbip_dump_header(&pdu); ++ ++ if (!valid_request(sdev, &pdu)) { ++ dev_err(dev, "recv invalid request\n"); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ return; ++ } ++ ++ switch (pdu.base.command) { ++ case USBIP_CMD_UNLINK: ++ stub_recv_cmd_unlink(sdev, &pdu); ++ break; ++ ++ case USBIP_CMD_SUBMIT: ++ stub_recv_cmd_submit(sdev, &pdu); ++ break; ++ ++ default: ++ /* NOTREACHED */ ++ dev_err(dev, "unknown pdu\n"); ++ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); ++ return; ++ } ++ ++} ++ ++void stub_rx_loop(struct usbip_task *ut) ++{ ++ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_rx); ++ ++ while (1) { ++ if (signal_pending(current)) { ++ dbg_stub_rx("signal caught!\n"); ++ break; ++ } ++ ++ if (usbip_event_happend(ud)) ++ break; ++ ++ stub_rx_pdu(ud); ++ } ++} +diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c +new file mode 100644 +index 0000000..d5563cd +--- /dev/null ++++ b/drivers/staging/usbip/stub_tx.c +@@ -0,0 +1,371 @@ ++/* ++ * Copyright (C) 2003-2008 Takahiro Hirofuchi ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#include "usbip_common.h" ++#include "stub.h" ++ ++ ++static void stub_free_priv_and_urb(struct stub_priv *priv) ++{ ++ struct urb *urb = priv->urb; ++ ++ kfree(urb->setup_packet); ++ kfree(urb->transfer_buffer); ++ list_del(&priv->list); ++ kmem_cache_free(stub_priv_cache, priv); ++ usb_free_urb(urb); ++} ++ ++/* be in spin_lock_irqsave(&sdev->priv_lock, flags) */ ++void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum, ++ __u32 status) ++{ ++ struct stub_unlink *unlink; ++ ++ unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC); ++ if (!unlink) { ++ dev_err(&sdev->interface->dev, "alloc stub_unlink\n"); ++ usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC); ++ return; ++ } ++ ++ unlink->seqnum = seqnum; ++ unlink->status = status; ++ ++ list_add_tail(&unlink->list, &sdev->unlink_tx); ++} ++ ++/** ++ * stub_complete - completion handler of a usbip urb ++ * @urb: pointer to the urb completed ++ * @regs: ++ * ++ * When a urb has completed, the USB core driver calls this function mostly in ++ * the interrupt context. To return the result of a urb, the completed urb is ++ * linked to the pending list of returning. ++ * ++ */ ++void stub_complete(struct urb *urb) ++{ ++ struct stub_priv *priv = (struct stub_priv *) urb->context; ++ struct stub_device *sdev = priv->sdev; ++ unsigned long flags; ++ ++ dbg_stub_tx("complete! status %d\n", urb->status); ++ ++ ++ switch (urb->status) { ++ case 0: ++ /* OK */ ++ break; ++ case -ENOENT: ++ uinfo("stopped by a call of usb_kill_urb() because of" ++ "cleaning up a virtual connection\n"); ++ return; ++ case -ECONNRESET: ++ uinfo("unlinked by a call of usb_unlink_urb()\n"); ++ break; ++ case -EPIPE: ++ uinfo("endpoint %d is stalled\n", usb_pipeendpoint(urb->pipe)); ++ break; ++ case -ESHUTDOWN: ++ uinfo("device removed?\n"); ++ break; ++ default: ++ uinfo("urb completion with non-zero status %d\n", urb->status); ++ } ++ ++ /* link a urb to the queue of tx. */ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ if (priv->unlinking) { ++ stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status); ++ stub_free_priv_and_urb(priv); ++ } else ++ list_move_tail(&priv->list, &sdev->priv_tx); ++ ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ /* wake up tx_thread */ ++ wake_up(&sdev->tx_waitq); ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* fill PDU */ ++ ++static inline void setup_base_pdu(struct usbip_header_basic *base, ++ __u32 command, __u32 seqnum) ++{ ++ base->command = command; ++ base->seqnum = seqnum; ++ base->devid = 0; ++ base->ep = 0; ++ base->direction = 0; ++} ++ ++static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb) ++{ ++ struct stub_priv *priv = (struct stub_priv *) urb->context; ++ ++ setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, priv->seqnum); ++ ++ usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1); ++} ++ ++static void setup_ret_unlink_pdu(struct usbip_header *rpdu, ++ struct stub_unlink *unlink) ++{ ++ setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum); ++ ++ rpdu->u.ret_unlink.status = unlink->status; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* send RET_SUBMIT */ ++ ++static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev) ++{ ++ unsigned long flags; ++ struct stub_priv *priv, *tmp; ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) { ++ list_move_tail(&priv->list, &sdev->priv_free); ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ return priv; ++ } ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ return NULL; ++} ++ ++static int stub_send_ret_submit(struct stub_device *sdev) ++{ ++ unsigned long flags; ++ struct stub_priv *priv, *tmp; ++ ++ struct msghdr msg; ++ struct kvec iov[3]; ++ size_t txsize; ++ ++ size_t total_size = 0; ++ ++ while ((priv = dequeue_from_priv_tx(sdev)) != NULL) { ++ int ret; ++ struct urb *urb = priv->urb; ++ struct usbip_header pdu_header; ++ void *iso_buffer = NULL; ++ ++ txsize = 0; ++ memset(&pdu_header, 0, sizeof(pdu_header)); ++ memset(&msg, 0, sizeof(msg)); ++ memset(&iov, 0, sizeof(iov)); ++ ++ dbg_stub_tx("setup txdata urb %p\n", urb); ++ ++ ++ /* 1. setup usbip_header */ ++ setup_ret_submit_pdu(&pdu_header, urb); ++ usbip_header_correct_endian(&pdu_header, 1); ++ ++ iov[0].iov_base = &pdu_header; ++ iov[0].iov_len = sizeof(pdu_header); ++ txsize += sizeof(pdu_header); ++ ++ /* 2. setup transfer buffer */ ++ if (usb_pipein(urb->pipe) && urb->actual_length > 0) { ++ iov[1].iov_base = urb->transfer_buffer; ++ iov[1].iov_len = urb->actual_length; ++ txsize += urb->actual_length; ++ } ++ ++ /* 3. setup iso_packet_descriptor */ ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ ssize_t len = 0; ++ ++ iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len); ++ if (!iso_buffer) { ++ usbip_event_add(&sdev->ud, ++ SDEV_EVENT_ERROR_MALLOC); ++ return -1; ++ } ++ ++ iov[2].iov_base = iso_buffer; ++ iov[2].iov_len = len; ++ txsize += len; ++ } ++ ++ ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, ++ 3, txsize); ++ if (ret != txsize) { ++ dev_err(&sdev->interface->dev, ++ "sendmsg failed!, retval %d for %zd\n", ++ ret, txsize); ++ kfree(iso_buffer); ++ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); ++ return -1; ++ } ++ ++ kfree(iso_buffer); ++ dbg_stub_tx("send txdata\n"); ++ ++ total_size += txsize; ++ } ++ ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { ++ stub_free_priv_and_urb(priv); ++ } ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ return total_size; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++/* send RET_UNLINK */ ++ ++static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev) ++{ ++ unsigned long flags; ++ struct stub_unlink *unlink, *tmp; ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) { ++ list_move_tail(&unlink->list, &sdev->unlink_free); ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ return unlink; ++ } ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ return NULL; ++} ++ ++ ++static int stub_send_ret_unlink(struct stub_device *sdev) ++{ ++ unsigned long flags; ++ struct stub_unlink *unlink, *tmp; ++ ++ struct msghdr msg; ++ struct kvec iov[1]; ++ size_t txsize; ++ ++ size_t total_size = 0; ++ ++ while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) { ++ int ret; ++ struct usbip_header pdu_header; ++ ++ txsize = 0; ++ memset(&pdu_header, 0, sizeof(pdu_header)); ++ memset(&msg, 0, sizeof(msg)); ++ memset(&iov, 0, sizeof(iov)); ++ ++ dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum); ++ ++ /* 1. setup usbip_header */ ++ setup_ret_unlink_pdu(&pdu_header, unlink); ++ usbip_header_correct_endian(&pdu_header, 1); ++ ++ iov[0].iov_base = &pdu_header; ++ iov[0].iov_len = sizeof(pdu_header); ++ txsize += sizeof(pdu_header); ++ ++ ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, ++ 1, txsize); ++ if (ret != txsize) { ++ dev_err(&sdev->interface->dev, ++ "sendmsg failed!, retval %d for %zd\n", ++ ret, txsize); ++ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); ++ return -1; ++ } ++ ++ ++ dbg_stub_tx("send txdata\n"); ++ ++ total_size += txsize; ++ } ++ ++ ++ spin_lock_irqsave(&sdev->priv_lock, flags); ++ ++ list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) { ++ list_del(&unlink->list); ++ kfree(unlink); ++ } ++ ++ spin_unlock_irqrestore(&sdev->priv_lock, flags); ++ ++ return total_size; ++} ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++void stub_tx_loop(struct usbip_task *ut) ++{ ++ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_tx); ++ struct stub_device *sdev = container_of(ud, struct stub_device, ud); ++ ++ while (1) { ++ if (signal_pending(current)) { ++ dbg_stub_tx("signal catched\n"); ++ break; ++ } ++ ++ if (usbip_event_happend(ud)) ++ break; ++ ++ /* ++ * send_ret_submit comes earlier than send_ret_unlink. stub_rx ++ * looks at only priv_init queue. If the completion of a URB is ++ * earlier than the receive of CMD_UNLINK, priv is moved to ++ * priv_tx queue and stub_rx does not find the target priv. In ++ * this case, vhci_rx receives the result of the submit request ++ * and then receives the result of the unlink request. The ++ * result of the submit is given back to the usbcore as the ++ * completion of the unlink request. The request of the ++ * unlink is ignored. This is ok because a driver who calls ++ * usb_unlink_urb() understands the unlink was too late by ++ * getting the status of the given-backed URB which has the ++ * status of usb_submit_urb(). ++ */ ++ if (stub_send_ret_submit(sdev) < 0) ++ break; ++ ++ if (stub_send_ret_unlink(sdev) < 0) ++ break; ++ ++ wait_event_interruptible(sdev->tx_waitq, ++ (!list_empty(&sdev->priv_tx) || ++ !list_empty(&sdev->unlink_tx))); ++ } ++} +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0014-Staging-add-w35und-wifi-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0014-Staging-add-w35und-wifi-driver.patch new file mode 100644 index 000000000..3fd2bebad --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0014-Staging-add-w35und-wifi-driver.patch @@ -0,0 +1,14970 @@ +From 66101de10957e07a6fd0365d5af9adf650246d14 Mon Sep 17 00:00:00 2001 +From: Pavel Machek +Date: Wed, 1 Oct 2008 14:36:56 +0200 +Subject: [PATCH 14/23] Staging: add w35und wifi driver +Patch-mainline: 2.6.28 + +This is driver for w35und usb wifi -- also in kohjinsha +subnotebook. It should work well enough to associate and ping, but it +obviously needs to be rewritten two more times... + +OTOH worst horrors (like embedded wifi stack) should have been fixed +already... + +Signed-off-by: Pavel Machek +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/winbond/Kconfig | 7 + + drivers/staging/winbond/Makefile | 18 + + drivers/staging/winbond/README | 10 + + drivers/staging/winbond/adapter.h | 23 + + drivers/staging/winbond/bss_f.h | 59 + + drivers/staging/winbond/bssdscpt.h | 156 ++ + drivers/staging/winbond/ds_tkip.h | 33 + + drivers/staging/winbond/gl_80211.h | 125 ++ + drivers/staging/winbond/ioctls.h | 678 ++++++++ + drivers/staging/winbond/linux/common.h | 143 ++ + drivers/staging/winbond/linux/sysdef.h | 73 + + drivers/staging/winbond/linux/wb35reg.c | 747 ++++++++ + drivers/staging/winbond/linux/wb35reg_f.h | 56 + + drivers/staging/winbond/linux/wb35reg_s.h | 170 ++ + drivers/staging/winbond/linux/wb35rx.c | 337 ++++ + drivers/staging/winbond/linux/wb35rx_f.h | 17 + + drivers/staging/winbond/linux/wb35rx_s.h | 48 + + drivers/staging/winbond/linux/wb35tx.c | 313 ++++ + drivers/staging/winbond/linux/wb35tx_f.h | 20 + + drivers/staging/winbond/linux/wb35tx_s.h | 47 + + drivers/staging/winbond/linux/wbusb.c | 404 +++++ + drivers/staging/winbond/linux/wbusb_f.h | 34 + + drivers/staging/winbond/linux/wbusb_s.h | 42 + + drivers/staging/winbond/localpara.h | 275 +++ + drivers/staging/winbond/mac_structures.h | 670 +++++++ + drivers/staging/winbond/mds.c | 630 +++++++ + drivers/staging/winbond/mds_f.h | 33 + + drivers/staging/winbond/mds_s.h | 183 ++ + drivers/staging/winbond/mlme_mib.h | 84 + + drivers/staging/winbond/mlme_s.h | 195 +++ + drivers/staging/winbond/mlmetxrx.c | 150 ++ + drivers/staging/winbond/mlmetxrx_f.h | 52 + + drivers/staging/winbond/mto.c | 1229 +++++++++++++ + drivers/staging/winbond/mto.h | 265 +++ + drivers/staging/winbond/mto_f.h | 7 + + drivers/staging/winbond/os_common.h | 2 + + drivers/staging/winbond/phy_calibration.c | 1759 +++++++++++++++++++ + drivers/staging/winbond/phy_calibration.h | 101 ++ + drivers/staging/winbond/reg.c | 2683 +++++++++++++++++++++++++++++ + drivers/staging/winbond/rxisr.c | 30 + + drivers/staging/winbond/scan_s.h | 115 ++ + drivers/staging/winbond/sme_api.c | 13 + + drivers/staging/winbond/sme_api.h | 265 +++ + drivers/staging/winbond/sme_s.h | 228 +++ + drivers/staging/winbond/wb35_ver.h | 30 + + drivers/staging/winbond/wbhal.c | 878 ++++++++++ + drivers/staging/winbond/wbhal_f.h | 122 ++ + drivers/staging/winbond/wbhal_s.h | 615 +++++++ + drivers/staging/winbond/wblinux.c | 277 +++ + drivers/staging/winbond/wblinux_f.h | 23 + + drivers/staging/winbond/wblinux_s.h | 45 + + 53 files changed, 14522 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/winbond/Kconfig + create mode 100644 drivers/staging/winbond/Makefile + create mode 100644 drivers/staging/winbond/README + create mode 100644 drivers/staging/winbond/adapter.h + create mode 100644 drivers/staging/winbond/bss_f.h + create mode 100644 drivers/staging/winbond/bssdscpt.h + create mode 100644 drivers/staging/winbond/ds_tkip.h + create mode 100644 drivers/staging/winbond/gl_80211.h + create mode 100644 drivers/staging/winbond/ioctls.h + create mode 100644 drivers/staging/winbond/linux/common.h + create mode 100644 drivers/staging/winbond/linux/sysdef.h + create mode 100644 drivers/staging/winbond/linux/wb35reg.c + create mode 100644 drivers/staging/winbond/linux/wb35reg_f.h + create mode 100644 drivers/staging/winbond/linux/wb35reg_s.h + create mode 100644 drivers/staging/winbond/linux/wb35rx.c + create mode 100644 drivers/staging/winbond/linux/wb35rx_f.h + create mode 100644 drivers/staging/winbond/linux/wb35rx_s.h + create mode 100644 drivers/staging/winbond/linux/wb35tx.c + create mode 100644 drivers/staging/winbond/linux/wb35tx_f.h + create mode 100644 drivers/staging/winbond/linux/wb35tx_s.h + create mode 100644 drivers/staging/winbond/linux/wbusb.c + create mode 100644 drivers/staging/winbond/linux/wbusb_f.h + create mode 100644 drivers/staging/winbond/linux/wbusb_s.h + create mode 100644 drivers/staging/winbond/localpara.h + create mode 100644 drivers/staging/winbond/mac_structures.h + create mode 100644 drivers/staging/winbond/mds.c + create mode 100644 drivers/staging/winbond/mds_f.h + create mode 100644 drivers/staging/winbond/mds_s.h + create mode 100644 drivers/staging/winbond/mlme_mib.h + create mode 100644 drivers/staging/winbond/mlme_s.h + create mode 100644 drivers/staging/winbond/mlmetxrx.c + create mode 100644 drivers/staging/winbond/mlmetxrx_f.h + create mode 100644 drivers/staging/winbond/mto.c + create mode 100644 drivers/staging/winbond/mto.h + create mode 100644 drivers/staging/winbond/mto_f.h + create mode 100644 drivers/staging/winbond/os_common.h + create mode 100644 drivers/staging/winbond/phy_calibration.c + create mode 100644 drivers/staging/winbond/phy_calibration.h + create mode 100644 drivers/staging/winbond/reg.c + create mode 100644 drivers/staging/winbond/rxisr.c + create mode 100644 drivers/staging/winbond/scan_s.h + create mode 100644 drivers/staging/winbond/sme_api.c + create mode 100644 drivers/staging/winbond/sme_api.h + create mode 100644 drivers/staging/winbond/sme_s.h + create mode 100644 drivers/staging/winbond/wb35_ver.h + create mode 100644 drivers/staging/winbond/wbhal.c + create mode 100644 drivers/staging/winbond/wbhal_f.h + create mode 100644 drivers/staging/winbond/wbhal_s.h + create mode 100644 drivers/staging/winbond/wblinux.c + create mode 100644 drivers/staging/winbond/wblinux_f.h + create mode 100644 drivers/staging/winbond/wblinux_s.h + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 4dbf795..fdbdf84 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -35,4 +35,6 @@ source "drivers/staging/go7007/Kconfig" + + source "drivers/staging/usbip/Kconfig" + ++source "drivers/staging/winbond/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index be42c0d..9b576c9 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -6,3 +6,4 @@ obj-$(CONFIG_SXG) += sxg/ + obj-$(CONFIG_ME4000) += me4000/ + obj-$(CONFIG_VIDEO_GO7007) += go7007/ + obj-$(CONFIG_USB_IP_COMMON) += usbip/ ++obj-$(CONFIG_W35UND) += winbond/ +diff --git a/drivers/staging/winbond/Kconfig b/drivers/staging/winbond/Kconfig +new file mode 100644 +index 0000000..10d72be +--- /dev/null ++++ b/drivers/staging/winbond/Kconfig +@@ -0,0 +1,7 @@ ++config W35UND ++ tristate "Winbond driver" ++ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL && !4KSTACKS ++ default n ++ ---help--- ++ This is highly experimental driver for winbond wifi card on some Kohjinsha notebooks ++ Check http://code.google.com/p/winbondport/ for new version +diff --git a/drivers/staging/winbond/Makefile b/drivers/staging/winbond/Makefile +new file mode 100644 +index 0000000..29c98bf +--- /dev/null ++++ b/drivers/staging/winbond/Makefile +@@ -0,0 +1,18 @@ ++ DRIVER_DIR=./linux ++ ++w35und-objs := $(DRIVER_DIR)/wbusb.o $(DRIVER_DIR)/wb35reg.o $(DRIVER_DIR)/wb35rx.o $(DRIVER_DIR)/wb35tx.o \ ++ mds.o \ ++ mlmetxrx.o \ ++ mto.o \ ++ phy_calibration.o \ ++ reg.o \ ++ rxisr.o \ ++ sme_api.o \ ++ wbhal.o \ ++ wblinux.o \ ++ ++ ++obj-$(CONFIG_W35UND) += w35und.o ++ ++ ++ +diff --git a/drivers/staging/winbond/README b/drivers/staging/winbond/README +new file mode 100644 +index 0000000..707b6b3 +--- /dev/null ++++ b/drivers/staging/winbond/README +@@ -0,0 +1,10 @@ ++TODO: ++ - sparse cleanups ++ - checkpatch cleanups ++ - kerneldoc cleanups ++ - remove typedefs ++ - remove unused ioctls ++ - use cfg80211 for regulatory stuff ++ ++Please send patches to Greg Kroah-Hartman and ++Pavel Machek +diff --git a/drivers/staging/winbond/adapter.h b/drivers/staging/winbond/adapter.h +new file mode 100644 +index 0000000..609701d +--- /dev/null ++++ b/drivers/staging/winbond/adapter.h +@@ -0,0 +1,23 @@ ++// ++// ADAPTER.H - ++// Windows NDIS global variable 'Adapter' typedef ++// ++#define MAX_ANSI_STRING 40 ++typedef struct WB32_ADAPTER ++{ ++ u32 AdapterIndex; // 20060703.4 Add for using pAdapterContext global Adapter point ++ ++ WB_LOCALDESCRIPT sLocalPara; // Myself connected parameters ++ PWB_BSSDESCRIPTION asBSSDescriptElement; ++ ++ MLME_FRAME sMlmeFrame; // connect to peerSTA parameters ++ ++ MTO_PARAMETERS sMtoPara; // MTO_struct ... ++ hw_data_t sHwData; //For HAL ++ MDS Mds; ++ ++ WBLINUX WbLinux; ++ struct iw_statistics iw_stats; ++ ++ u8 LinkName[MAX_ANSI_STRING]; ++} WB32_ADAPTER, ADAPTER, *PWB32_ADAPTER, *PADAPTER; +diff --git a/drivers/staging/winbond/bss_f.h b/drivers/staging/winbond/bss_f.h +new file mode 100644 +index 0000000..c957bc9 +--- /dev/null ++++ b/drivers/staging/winbond/bss_f.h +@@ -0,0 +1,59 @@ ++// ++// BSS descriptor DataBase management global function ++// ++ ++void vBSSdescriptionInit(PWB32_ADAPTER Adapter); ++void vBSSfoundList(PWB32_ADAPTER Adapter); ++u8 boChanFilter(PWB32_ADAPTER Adapter, u8 ChanNo); ++u16 wBSSallocateEntry(PWB32_ADAPTER Adapter); ++u16 wBSSGetEntry(PWB32_ADAPTER Adapter); ++void vSimpleHouseKeeping(PWB32_ADAPTER Adapter); ++u16 wBSShouseKeeping(PWB32_ADAPTER Adapter); ++void ClearBSSdescpt(PWB32_ADAPTER Adapter, u16 i); ++u16 wBSSfindBssID(PWB32_ADAPTER Adapter, u8 *pbBssid); ++u16 wBSSfindDedicateCandidate(PWB32_ADAPTER Adapter, struct SSID_Element *psSsid, u8 *pbBssid); ++u16 wBSSfindMACaddr(PWB32_ADAPTER Adapter, u8 *pbMacAddr); ++u16 wBSSsearchMACaddr(PWB32_ADAPTER Adapter, u8 *pbMacAddr, u8 band); ++u16 wBSSaddScanData(PWB32_ADAPTER, u16, psRXDATA); ++u16 wBSSUpdateScanData(PWB32_ADAPTER Adapter, u16 wBssIdx, psRXDATA psRcvData); ++u16 wBSScreateIBSSdata(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData); ++void DesiredRate2BSSdescriptor(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData, ++ u8 *pBasicRateSet, u8 BasicRateCount, ++ u8 *pOperationRateSet, u8 OperationRateCount); ++void DesiredRate2InfoElement(PWB32_ADAPTER Adapter, u8 *addr, u16 *iFildOffset, ++ u8 *pBasicRateSet, u8 BasicRateCount, ++ u8 *pOperationRateSet, u8 OperationRateCount); ++void BSSAddIBSSdata(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData); ++unsigned char boCmpMacAddr( PUCHAR, PUCHAR ); ++unsigned char boCmpSSID(struct SSID_Element *psSSID1, struct SSID_Element *psSSID2); ++u16 wBSSfindSSID(PWB32_ADAPTER Adapter, struct SSID_Element *psSsid); ++u16 wRoamingQuery(PWB32_ADAPTER Adapter); ++void vRateToBitmap(PWB32_ADAPTER Adapter, u16 index); ++u8 bRateToBitmapIndex(PWB32_ADAPTER Adapter, u8 bRate); ++u8 bBitmapToRate(u8 i); ++unsigned char boIsERPsta(PWB32_ADAPTER Adapter, u16 i); ++unsigned char boCheckConnect(PWB32_ADAPTER Adapter); ++unsigned char boCheckSignal(PWB32_ADAPTER Adapter); ++void AddIBSSIe(PWB32_ADAPTER Adapter,PWB_BSSDESCRIPTION psDesData );//added by ws for WPA_None06/01/04 ++void BssScanUpToDate(PWB32_ADAPTER Adapter); ++void BssUpToDate(PWB32_ADAPTER Adapter); ++void RateSort(u8 *RateArray, u8 num, u8 mode); ++void RateReSortForSRate(PWB32_ADAPTER Adapter, u8 *RateArray, u8 num); ++void Assemble_IE(PWB32_ADAPTER Adapter, u16 wBssIdx); ++void SetMaxTxRate(PWB32_ADAPTER Adapter); ++ ++void CreateWpaIE(PWB32_ADAPTER Adapter, u16* iFildOffset, PUCHAR msg, struct Management_Frame* msgHeader, ++ struct Association_Request_Frame_Body* msgBody, u16 iMSindex); //added by WS 05/14/05 ++ ++#ifdef _WPA2_ ++void CreateRsnIE(PWB32_ADAPTER Adapter, u16* iFildOffset, PUCHAR msg, struct Management_Frame* msgHeader, ++ struct Association_Request_Frame_Body* msgBody, u16 iMSindex);//added by WS 05/14/05 ++ ++u16 SearchPmkid(PWB32_ADAPTER Adapter, struct Management_Frame* msgHeader, ++ struct PMKID_Information_Element * AssoReq_PMKID ); ++#endif ++ ++ ++ ++ ++ +diff --git a/drivers/staging/winbond/bssdscpt.h b/drivers/staging/winbond/bssdscpt.h +new file mode 100644 +index 0000000..97150a2 +--- /dev/null ++++ b/drivers/staging/winbond/bssdscpt.h +@@ -0,0 +1,156 @@ ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// bssdscpt.c ++// BSS descriptor data base ++// history : ++// ++// Description: ++// BSS descriptor data base will store the information of the stations at the ++// surrounding environment. The first entry( psBSS(0) ) will not be used and the ++// second one( psBSS(1) ) will be used for the broadcast address. ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++//#define MAX_ACC_RSSI_COUNT 10 ++#define MAX_ACC_RSSI_COUNT 6 ++ ++/////////////////////////////////////////////////////////////////////////// ++// ++// BSS Description set Element , to store scan received Beacon information ++// ++// Our's differs slightly from the specs. The specify a PHY_Parameter_Set. ++// Since we're only doing a DS design right now, we just have a DS structure. ++////////////////////////////////////////////////////////////////////////////// ++typedef struct BSSDescriptionElement ++{ ++ u32 SlotValid; ++ u32 PowerSaveMode; ++ RXLAYER1 RxLayer1; ++ ++ u8 abPeerAddress[ MAC_ADDR_LENGTH + 2 ]; // peer MAC Address associated with this session. 6-OCTET value ++ u32 dwBgScanStamp; // BgScan Sequence Counter stamp, record psROAM->dwScanCounter. ++ ++ u16 Beacon_Period; ++ u16 wATIM_Window; ++ ++ u8 abBssID[ MAC_ADDR_LENGTH + 2 ]; // 6B ++ ++ u8 bBssType; ++ u8 DTIM_Period; // 1 octet usually from TIM element, if present ++ u8 boInTimerHandler; ++ u8 boERP; // analysis ERP or (extended) supported rate element ++ ++ u8 Timestamp[8]; ++ u8 BasicRate[32]; ++ u8 OperationalRate[32]; ++ u32 dwBasicRateBitmap; //bit map, retrieve from SupportedRateSet ++ u32 dwOperationalRateBitmap; //bit map, retrieve from SupportedRateSet and ++ // ExtendedSupportedRateSet ++ // For RSSI calculating ++ u32 HalRssi[MAX_ACC_RSSI_COUNT]; // Encode. It must use MACRO of HAL to get the LNA and AGC data ++ u32 HalRssiIndex; ++ ++ ////From beacon/probe response ++ struct SSID_Element SSID; // 34B ++ u8 reserved_1[ 2 ]; ++ ++ struct Capability_Information_Element CapabilityInformation; // 2B ++ u8 reserved_2[ 2 ]; ++ ++ struct CF_Parameter_Set_Element CF_Parameter_Set; // 8B ++ struct IBSS_Parameter_Set_Element IBSS_Parameter_Set; // 4B ++ struct TIM_Element TIM_Element_Set; // 256B ++ ++ struct DS_Parameter_Set_Element DS_Parameter_Set; // 3B ++ u8 reserved_3; ++ ++ struct ERP_Information_Element ERP_Information_Set; // 3B ++ u8 reserved_4; ++ ++ struct Supported_Rates_Element SupportedRateSet; // 10B ++ u8 reserved_5[2]; ++ ++ struct Extended_Supported_Rates_Element ExtendedSupportedRateSet; // 257B ++ u8 reserved_6[3]; ++ ++ u8 band; ++ u8 reserved_7[3]; ++ ++ // for MLME module ++ u16 wState; // the current state of the system ++ u16 wIndex; // THIS BSS element entry index ++ ++ void* psAdapter; // pointer to THIS Adapter ++ OS_TIMER nTimer; // MLME timer ++ ++ // Authentication ++ u16 wAuthAlgo; // peer MAC MLME use Auth algorithm, default OPEN_AUTH ++ u16 wAuthSeqNum; // current local MAC sendout AuthReq sequence number ++ ++ u8 auth_challengeText[128]; ++ ++ ////For XP: ++ u32 ies_len; // information element length ++ u8 ies[256]; // information element ++ ++ ////For WPA ++ u8 RsnIe_Type[2]; //added by ws for distinguish WPA and WPA2 05/14/04 ++ u8 RsnIe_len; ++ u8 Rsn_Num; ++ ++ // to record the rsn cipher suites,addded by ws 09/05/04 ++ SUITE_SELECTOR group_cipher; // 4B ++ SUITE_SELECTOR pairwise_key_cipher_suites[WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT]; ++ SUITE_SELECTOR auth_key_mgt_suites[WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT]; ++ ++ u16 pairwise_key_cipher_suite_count; ++ u16 auth_key_mgt_suite_count; ++ ++ u8 pairwise_key_cipher_suite_selected; ++ u8 auth_key_mgt_suite_selected; ++ u8 reserved_8[2]; ++ ++ struct RSN_Capability_Element rsn_capabilities; // 2B ++ u8 reserved_9[2]; ++ ++ //to record the rsn cipher suites for WPA2 ++ #ifdef _WPA2_ ++ u32 pre_auth; //added by WS for distinguish for 05/04/04 ++ SUITE_SELECTOR wpa2_group_cipher; // 4B ++ SUITE_SELECTOR wpa2_pairwise_key_cipher_suites[WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT]; ++ SUITE_SELECTOR wpa2_auth_key_mgt_suites[WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT]; ++ ++ u16 wpa2_pairwise_key_cipher_suite_count; ++ u16 wpa2_auth_key_mgt_suite_count; ++ ++ u8 wpa2_pairwise_key_cipher_suite_selected; ++ u8 wpa2_auth_key_mgt_suite_selected; ++ u8 reserved_10[2]; ++ ++ struct RSN_Capability_Element wpa2_rsn_capabilities; // 2B ++ u8 reserved_11[2]; ++ #endif //endif _WPA2_ ++ ++ //For Replay protection ++// u8 PairwiseTSC[6]; ++// u8 GroupTSC[6]; ++ ++ ////For up-to-date ++ u32 ScanTimeStamp; //for the decision whether the station/AP(may exist at ++ //different channels) has left. It must be detected by ++ //scanning. Local device may connected or disconnected. ++ u32 BssTimeStamp; //Only for the decision whether the station/AP(exist in ++ //the same channel, and no scanning) if local device has ++ //connected successfully. ++ ++ // 20061108 Add for storing WPS_IE. [E id][Length][OUI][Data] ++ u8 WPS_IE_Data[MAX_IE_APPEND_SIZE]; ++ u16 WPS_IE_length; ++ u16 WPS_IE_length_tmp; // For verify there is an WPS_IE in Beacon or probe response ++ ++} WB_BSSDESCRIPTION, *PWB_BSSDESCRIPTION; ++ ++#define wBSSConnectedSTA(Adapter) \ ++ ((u16)(Adapter)->sLocalPara.wConnectedSTAindex) ++ ++#define psBSS(i) (&(Adapter->asBSSDescriptElement[(i)])) ++ ++ +diff --git a/drivers/staging/winbond/ds_tkip.h b/drivers/staging/winbond/ds_tkip.h +new file mode 100644 +index 0000000..29e5055 +--- /dev/null ++++ b/drivers/staging/winbond/ds_tkip.h +@@ -0,0 +1,33 @@ ++// Rotation functions on 32 bit values ++#define ROL32( A, n ) \ ++ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) ++ ++#define ROR32( A, n ) ROL32( (A), 32-(n) ) ++ ++ ++typedef struct tkip ++{ ++ u32 K0, K1; // Key ++ union ++ { ++ struct // Current state ++ { ++ u32 L; ++ u32 R; ++ }; ++ u8 LR[8]; ++ }; ++ union ++ { ++ u32 M; // Message accumulator (single word) ++ u8 Mb[4]; ++ }; ++ s32 bytes_in_M; // # bytes in M ++} tkip_t; ++ ++//void _append_data( PUCHAR pData, u16 size, tkip_t *p ); ++void Mds_MicGet( void* Adapter, void* pRxLayer1, PUCHAR pKey, PUCHAR pMic ); ++void Mds_MicFill( void* Adapter, void* pDes, PUCHAR XmitBufAddress ); ++ ++ ++ +diff --git a/drivers/staging/winbond/gl_80211.h b/drivers/staging/winbond/gl_80211.h +new file mode 100644 +index 0000000..1806d81 +--- /dev/null ++++ b/drivers/staging/winbond/gl_80211.h +@@ -0,0 +1,125 @@ ++ ++#ifndef __GL_80211_H__ ++#define __GL_80211_H__ ++ ++/****************** CONSTANT AND MACRO SECTION ******************************/ ++ ++/* BSS Type */ ++enum { ++ WLAN_BSSTYPE_INFRASTRUCTURE = 0, ++ WLAN_BSSTYPE_INDEPENDENT, ++ WLAN_BSSTYPE_ANY_BSS, ++}; ++ ++ ++ ++/* Preamble_Type, see */ ++typedef enum preamble_type { ++ WLAN_PREAMBLE_TYPE_SHORT, ++ WLAN_PREAMBLE_TYPE_LONG, ++} preamble_type_e; ++ ++ ++/* Slot_Time_Type, see */ ++typedef enum slot_time_type { ++ WLAN_SLOT_TIME_TYPE_LONG, ++ WLAN_SLOT_TIME_TYPE_SHORT, ++} slot_time_type_e; ++ ++/*--------------------------------------------------------------------------*/ ++/* Encryption Mode */ ++typedef enum { ++ WEP_DISABLE = 0, ++ WEP_64, ++ WEP_128, ++ ++ ENCRYPT_DISABLE, ++ ENCRYPT_WEP, ++ ENCRYPT_WEP_NOKEY, ++ ENCRYPT_TKIP, ++ ENCRYPT_TKIP_NOKEY, ++ ENCRYPT_CCMP, ++ ENCRYPT_CCMP_NOKEY, ++} encryption_mode_e; ++ ++typedef enum _WLAN_RADIO { ++ WLAN_RADIO_ON, ++ WLAN_RADIO_OFF, ++ WLAN_RADIO_MAX, // not a real type, defined as an upper bound ++} WLAN_RADIO; ++ ++typedef struct _WLAN_RADIO_STATUS { ++ WLAN_RADIO HWStatus; ++ WLAN_RADIO SWStatus; ++} WLAN_RADIO_STATUS; ++ ++//---------------------------------------------------------------------------- ++// 20041021 1.1.81.1000 ybjiang ++// add for radio notification ++typedef ++void (*RADIO_NOTIFICATION_HANDLER)( ++ void *Data, ++ void *RadioStatusBuffer, ++ u32 RadioStatusBufferLen ++ ); ++ ++typedef struct _WLAN_RADIO_NOTIFICATION ++{ ++ RADIO_NOTIFICATION_HANDLER RadioChangeHandler; ++ void *Data; ++} WLAN_RADIO_NOTIFICATION; ++ ++//---------------------------------------------------------------------------- ++// 20041102 1.1.91.1000 ybjiang ++// add for OID_802_11_CUST_REGION_CAPABILITIES and OID_802_11_OID_REGION ++typedef enum _WLAN_REGION_CODE ++{ ++ WLAN_REGION_UNKNOWN, ++ WLAN_REGION_EUROPE, ++ WLAN_REGION_JAPAN, ++ WLAN_REGION_USA, ++ WLAN_REGION_FRANCE, ++ WLAN_REGION_SPAIN, ++ WLAN_REGION_ISRAEL, ++ WLAN_REGION_MAX, // not a real type, defined as an upper bound ++} WLAN_REGION_CODE; ++ ++#define REGION_NAME_MAX_LENGTH 256 ++ ++typedef struct _WLAN_REGION_CHANNELS ++{ ++ u32 Length; ++ u32 NameLength; ++ u8 Name[REGION_NAME_MAX_LENGTH]; ++ WLAN_REGION_CODE Code; ++ u32 Frequency[1]; ++} WLAN_REGION_CHANNELS; ++ ++typedef struct _WLAN_REGION_CAPABILITIES ++{ ++ u32 NumberOfItems; ++ WLAN_REGION_CHANNELS Region[1]; ++} WLAN_REGION_CAPABILITIES; ++ ++typedef struct _region_name_map { ++ WLAN_REGION_CODE region; ++ u8 *name; ++ u32 *channels; ++} region_name_map; ++ ++/*--------------------------------------------------------------------------*/ ++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] ++#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X" ++ ++// TODO: 0627 kevin ++#define MIC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7] ++#define MICSTR "%02X %02X %02X %02X %02X %02X %02X %02X" ++ ++#define MICKEY2STR(a) MIC2STR(a) ++#define MICKEYSTR MICSTR ++ ++ ++#endif /* __GL_80211_H__ */ ++/*** end of file ***/ ++ ++ +diff --git a/drivers/staging/winbond/ioctls.h b/drivers/staging/winbond/ioctls.h +new file mode 100644 +index 0000000..e8b35dc +--- /dev/null ++++ b/drivers/staging/winbond/ioctls.h +@@ -0,0 +1,678 @@ ++//============================================================================ ++// IOCTLS.H - ++// ++// Description: ++// Define the IOCTL codes. ++// ++// Revision history: ++// -------------------------------------------------------------------------- ++// ++// Copyright (c) 2002-2004 Winbond Electronics Corp. All rights reserved. ++//============================================================================= ++ ++#ifndef _IOCTLS_H ++#define _IOCTLS_H ++ ++// PD43 Keep it - Used with the Win33 application ++// #include ++ ++//======================================================== ++// 20040108 ADD the follow for test ++//======================================================== ++#define INFORMATION_LENGTH sizeof(unsigned int) ++ ++#define WB32_IOCTL_INDEX 0x0900 //­×§ďĽHŤKŹŰŽe// ++ ++#define Wb32_RegisterRead CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 0, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_RegisterWrite CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 1, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_SendPacket CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 2, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_QuerySendResult CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 3, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_SetFragmentThreshold CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 4, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_SetLinkStatus CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 5, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_SetBulkIn CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 6, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb32_LoopbackTest CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 7, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_EEPromRead CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 8, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_EEPromWrite CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 9, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_FlashReadData CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 10, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_FlashWrite CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 11, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_FlashWriteBurst CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 12, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_TxBurstStart CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 13, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_TxBurstStop CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 14, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define Wb35_TxBurstStatus CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB32_IOCTL_INDEX + 15, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// For IOCTL interface ++//================================================ ++#define LINKNAME_STRING "\\DosDevices\\W35UND" ++#define NTDEVICE_STRING "\\Device\\W35UND" ++#define APPLICATION_LINK "\\\\.\\W35UND" ++ ++#define WB_IOCTL_INDEX 0x0800 ++#define WB_IOCTL_TS_INDEX WB_IOCTL_INDEX + 60 ++#define WB_IOCTL_DUT_INDEX WB_IOCTL_TS_INDEX + 40 ++ ++//============================================================================= ++// IOCTLS defined for DUT (Device Under Test) ++ ++// IOCTL_WB_802_11_DUT_MAC_ADDRESS ++// Query: Return the dot11StationID ++// Set : Set the dot11StationID. Demo only. ++// ++#define IOCTL_WB_802_11_DUT_MAC_ADDRESS CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 1, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_BSS_DESCRIPTION ++// Query: Return the info. of the current connected BSS. ++// Set : None. ++// ++#define IOCTL_WB_802_11_DUT_BSS_DESCRIPTION CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 2, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_TX_RATE ++// Query: Return the current transmission rate. ++// Set : Set the transmission rate of the Tx packets. ++// ++#define IOCTL_WB_802_11_DUT_TX_RATE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 3, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_CURRENT_STA_STATE ++// Query: Return the current STA state. (WB_STASTATE type) ++// Set : None. ++// ++#define IOCTL_WB_802_11_DUT_CURRENT_STA_STATE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 4, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++/////////// 10/31/02' Added ///////////////////// ++ ++// IOCTL_WB_802_11_DUT_START_IBSS_REQUEST ++// Query: None. ++// Set : Start a new IBSS ++// ++#define IOCTL_WB_802_11_DUT_START_IBSS_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 5, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_JOIN_REQUEST ++// Query: None. ++// Set : Synchronize with the selected BSS ++// ++#define IOCTL_WB_802_11_DUT_JOIN_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 6, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_AUTHEN_REQUEST ++// Query: None. ++// Set : Authenticate with the BSS ++// ++#define IOCTL_WB_802_11_DUT_AUTHEN_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 7, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_DEAUTHEN_REQUEST ++// Query: None. ++// Set : DeAuthenticate withe the BSS ++// ++#define IOCTL_WB_802_11_DUT_DEAUTHEN_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 8, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_ASSOC_REQUEST ++// Query: None. ++// Set : Associate withe the BSS ++// ++#define IOCTL_WB_802_11_DUT_ASSOC_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 9, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_REASSOC_REQUEST ++// Query: None. ++// Set : ReAssociate withe the BSS ++// ++#define IOCTL_WB_802_11_DUT_REASSOC_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 10, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++ ++// IOCTL_WB_802_11_DUT_DISASSOC_REQUEST ++// Query: None. ++// Set : DisAssociate withe the BSS ++// ++#define IOCTL_WB_802_11_DUT_DISASSOC_REQUEST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 11, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_FRAG_THRESHOLD ++// Query: Return the dot11FragmentThreshold ++// Set : Set the dot11FragmentThreshold ++// ++#define IOCTL_WB_802_11_DUT_FRAG_THRESHOLD CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 12, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_RTS_THRESHOLD ++// Query: Return the dot11RTSThreshold ++// Set : Set the dot11RTSThresold ++// ++#define IOCTL_WB_802_11_DUT_RTS_THRESHOLD CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 13, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_WEP_KEYMODE ++// Query: Get the WEP key mode. ++// Set : Set the WEP key mode: disable/64 bits/128 bits ++// ++#define IOCTL_WB_802_11_DUT_WEP_KEYMODE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 14, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_WEP_KEYVALUE ++// Query: None. ++// Set : fill in the WEP key value ++// ++#define IOCTL_WB_802_11_DUT_WEP_KEYVALUE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 15, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_RESET ++// Query: None. ++// Set : Reset S/W and H/W ++// ++#define IOCTL_WB_802_11_DUT_RESET CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 16, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_POWER_SAVE ++// Query: None. ++// Set : Set Power Save Mode ++// ++#define IOCTL_WB_802_11_DUT_POWER_SAVE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 17, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_BSSID_LIST_SCAN ++// Query: None. ++// Set : ++// ++#define IOCTL_WB_802_11_DUT_BSSID_LIST_SCAN CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 18, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_BSSID_LIST ++// Query: Return the BSS info of BSSs in the last scanning process ++// Set : None. ++// ++#define IOCTL_WB_802_11_DUT_BSSID_LIST CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 19, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_STATISTICS ++// Query: Return the statistics of Tx/Rx. ++// Set : None. ++// ++#define IOCTL_WB_802_11_DUT_STATISTICS CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 20, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_ACCEPT_BEACON ++// Query: Return the current mode to accept beacon or not. ++// Set : Enable or disable allowing the HW-MAC to pass the beacon to the SW-MAC ++// Arguments: unsigned char ++// ++#define IOCTL_WB_802_11_DUT_ACCEPT_BEACON CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 21, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_ROAMING ++// Query: Return the roaming function status ++// Set : Enable/Disable the roaming function. ++#define IOCTL_WB_802_11_DUT_ROAMING CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 22, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_DTO ++// Query: Return the DTO(Data Throughput Optimization) ++// function status (TRUE or FALSE) ++// Set : Enable/Disable the DTO function. ++// ++#define IOCTL_WB_802_11_DUT_DTO CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 23, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_ANTENNA_DIVERSITY ++// Query: Return the antenna diversity status. (TRUE/ON or FALSE/OFF) ++// Set : Enable/Disable the antenna diversity. ++// ++#define IOCTL_WB_802_11_DUT_ANTENNA_DIVERSITY CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 24, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++//-------------- new added for a+b+g --------------------- ++// IOCTL_WB_802_11_DUT_MAC_OPERATION_MODE ++// Query: Return the MAC operation mode. (MODE_802_11_BG, MODE_802_11_A, ++// MODE_802_11_ABG, MODE_802_11_BG_IBSS) ++// Set : Set the MAC operation mode. ++// ++#define IOCTL_WB_802_11_DUT_MAC_OPERATION_MODE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 25, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_TX_RATE_REDEFINED ++// Query: Return the current tx rate which follows the definition in spec. (for ++// example, 5.5M => 0x0b) ++// Set : None ++// ++#define IOCTL_WB_802_11_DUT_TX_RATE_REDEFINED CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 26, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_PREAMBLE_MODE ++// Query: Return the preamble mode. (auto or long) ++// Set : Set the preamble mode. ++// ++#define IOCTL_WB_802_11_DUT_PREAMBLE_MODE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 27, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_SLOT_TIME_MODE ++// Query: Return the slot time mode. (auto or long) ++// Set : Set the slot time mode. ++// ++#define IOCTL_WB_802_11_DUT_SLOT_TIME_MODE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 28, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++//------------------------------------------------------------------ ++ ++// IOCTL_WB_802_11_DUT_ADVANCE_STATUS ++// Query: ++// Set : NONE ++// ++#define IOCTL_WB_802_11_DUT_ADVANCE_STATUS CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 29, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_TX_RATE_MODE ++// Query: Return the tx rate mode. (RATE_AUTO, RATE_1M, .., RATE_54M, RATE_MAX) ++// Set : Set the tx rate mode. (RATE_AUTO, RATE_1M, .., RATE_54M, RATE_MAX) ++// ++#define IOCTL_WB_802_11_DUT_TX_RATE_MODE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 30, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_DTO_PARA ++// Query: Return the DTO parameters ++// Set : Set the DTO parameters ++// ++#define IOCTL_WB_802_11_DUT_DTO_PARA CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 31, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_EVENT_LOG ++// Query: Return event log ++// Set : Reset event log ++// ++#define IOCTL_WB_802_11_DUT_EVENT_LOG CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 32, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_CWMIN ++// Query: NONE(It will be obtained by IOCTL_WB_802_11_DUT_ADVANCE_STATUS) ++// Set : Set CWMin value ++// ++#define IOCTL_WB_802_11_DUT_CWMIN CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 33, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_DUT_CWMAX ++// Query: NONE(It will be obtained by IOCTL_WB_802_11_DUT_ADVANCE_STATUS) ++// Set : Set CWMax value ++// ++#define IOCTL_WB_802_11_DUT_CWMAX CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_DUT_INDEX + 34, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++ ++//========================================================== ++// IOCTLs for Testing ++ ++// IOCTL_WB_802_11_TS_SET_CXX_REG ++// Query: None ++// Set : Write the value to one of Cxx register. ++// ++#define IOCTL_WB_802_11_TS_SET_CXX_REG CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 0, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_TS_GET_CXX_REG ++// Query: Return the value of the Cxx register. ++// Set : Write the reg no. (0x00, 0x04, 0x08 etc) ++// ++#define IOCTL_WB_802_11_TS_GET_CXX_REG CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 1, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_TS_SET_DXX_REG ++// Query: None ++// Set : Write the value to one of Dxx register. ++// ++#define IOCTL_WB_802_11_TS_SET_DXX_REG CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 2, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// IOCTL_WB_802_11_TS_GET_DXX_REG ++// Query: Return the value of the Dxx register. ++// Set : Write the reg no. (0x00, 0x04, 0x08 etc) ++// ++#define IOCTL_WB_802_11_TS_GET_DXX_REG CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 3, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++//============================================================ ++// [TS] ++ ++#define IOCTL_WB_802_11_TS_TX_RATE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 4, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_CURRENT_CHANNEL CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 5, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_ENABLE_SEQNO CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 6, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_ENALBE_ACKEDPACKET CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 7, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_INHIBIT_CRC CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 8, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_RESET_RCV_COUNTER CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 9, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_SET_TX_TRIGGER CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 10, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_FAILED_TX_COUNT CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 11, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// [TS1] ++#define IOCTL_WB_802_11_TS_TX_POWER CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 12, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_MODE_ENABLE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 13, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_MODE_DISABLE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 14, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_ANTENNA CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 15, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_ADAPTER_INFO CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 16, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_MAC_ADDRESS CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 17, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_BSSID CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 18, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_RF_PARAMETER CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 19, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_FILTER CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 20, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_CALIBRATION CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 21, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_BSS_MODE CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 22, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_SET_SSID CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 23, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_IBSS_CHANNEL CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 24, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++// set/query the slot time value(short or long slot time) ++#define IOCTL_WB_802_11_TS_SLOT_TIME CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 25, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_SLOT_TIME CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 25, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#define IOCTL_WB_802_11_TS_RX_STATISTICS CTL_CODE( \ ++ FILE_DEVICE_UNKNOWN, \ ++ WB_IOCTL_TS_INDEX + 26, \ ++ METHOD_BUFFERED, \ ++ FILE_ANY_ACCESS) ++ ++#endif // #ifndef _IOCTLS_H ++ ++ +diff --git a/drivers/staging/winbond/linux/common.h b/drivers/staging/winbond/linux/common.h +new file mode 100644 +index 0000000..6b00bad +--- /dev/null ++++ b/drivers/staging/winbond/linux/common.h +@@ -0,0 +1,143 @@ ++// ++// common.h ++// ++// This file contains the OS dependant definition and function. ++// Every OS has this file individual. ++// ++ ++#define DebugUsbdStatusInformation( _A ) ++ ++#ifndef COMMON_DEF ++#define COMMON_DEF ++ ++#include ++#include ++#include //need for kernel alert ++#include ++#include ++#include ++#include //memory allocate ++#include ++#include ++#include ++#include //need for init and exit modules marco ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++//#define DEBUG_ENABLED 1 ++ ++ ++ ++//=============================================================== ++// Common type definition ++//=============================================================== ++ ++typedef u8* PUCHAR; ++typedef s8* PCHAR; ++typedef u8* PBOOLEAN; ++typedef u16* PUSHORT; ++typedef u32* PULONG; ++typedef s16* PSHORT; ++ ++ ++//=========================================== ++#define IGNORE 2 ++#define SUCCESS 1 ++#define FAILURE 0 ++ ++ ++#ifndef true ++#define true 1 ++#endif ++ ++#ifndef false ++#define false 0 ++#endif ++ ++// PD43 20021108 ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#define STATUS_MEDIA_CONNECT 1 ++#define STATUS_MEDIA_DISCONNECT 0 ++ ++#ifndef BIT ++#define BIT(x) (1 << (x)) ++#endif ++ ++typedef struct urb * PURB; ++ ++ ++ ++//================================================================================================== ++// Common function definition ++//================================================================================================== ++#ifndef abs ++#define abs(_T) ((_T) < 0 ? -_T : _T) ++#endif ++#define DEBUG_ENABLED ++#define ETH_LENGTH_OF_ADDRESS 6 ++#ifdef DEBUG_ENABLED ++#define WBDEBUG( _M ) printk _M ++#else ++#define WBDEBUG( _M ) 0 ++#endif ++ ++#define OS_DISCONNECTED 0 ++#define OS_CONNECTED 1 ++ ++ ++#define OS_EVENT_INDICATE( _A, _B, _F ) ++#define OS_PMKID_STATUS_EVENT( _A ) ++ ++ ++/* Uff, no, longs are not atomic on all architectures Linux ++ * supports. This should really use atomic_t */ ++ ++#define OS_ATOMIC u32 ++#define OS_ATOMIC_READ( _A, _V ) _V ++#define OS_ATOMIC_INC( _A, _V ) EncapAtomicInc( _A, (void*)_V ) ++#define OS_ATOMIC_DEC( _A, _V ) EncapAtomicDec( _A, (void*)_V ) ++#define OS_MEMORY_CLEAR( _A, _S ) memset( (PUCHAR)_A,0,_S) ++#define OS_MEMORY_COMPARE( _A, _B, _S ) (memcmp(_A,_B,_S)? 0 : 1) // Definition is reverse with Ndis 1: the same 0: different ++ ++ ++#define OS_SPIN_LOCK spinlock_t ++#define OS_SPIN_LOCK_ALLOCATE( _S ) spin_lock_init( _S ); ++#define OS_SPIN_LOCK_FREE( _S ) ++#define OS_SPIN_LOCK_ACQUIRED( _S ) spin_lock_irq( _S ) ++#define OS_SPIN_LOCK_RELEASED( _S ) spin_unlock_irq( _S ); ++ ++#define OS_TIMER struct timer_list ++#define OS_TIMER_INITIAL( _T, _F, _P ) \ ++{ \ ++ init_timer( _T ); \ ++ (_T)->function = (void *)_F##_1a; \ ++ (_T)->data = (unsigned long)_P; \ ++} ++ ++// _S : Millisecond ++// 20060420 At least 1 large than jiffies ++#define OS_TIMER_SET( _T, _S ) \ ++{ \ ++ (_T)->expires = jiffies + ((_S*HZ+999)/1000);\ ++ add_timer( _T ); \ ++} ++#define OS_TIMER_CANCEL( _T, _B ) del_timer_sync( _T ) ++#define OS_TIMER_GET_SYS_TIME( _T ) (*_T=jiffies) ++ ++ ++#endif // COMMON_DEF ++ +diff --git a/drivers/staging/winbond/linux/sysdef.h b/drivers/staging/winbond/linux/sysdef.h +new file mode 100644 +index 0000000..d46d63e +--- /dev/null ++++ b/drivers/staging/winbond/linux/sysdef.h +@@ -0,0 +1,73 @@ ++ ++ ++// ++// Winbond WLAN System Configuration defines ++// ++ ++//===================================================================== ++// Current directory is Linux ++// The definition WB_LINUX is a keyword for this OS ++//===================================================================== ++#ifndef SYS_DEF_H ++#define SYS_DEF_H ++#define WB_LINUX ++#define WB_LINUX_WPA_PSK ++ ++ ++//#define _IBSS_BEACON_SEQ_STICK_ ++#define _USE_FALLBACK_RATE_ ++//#define ANTDIV_DEFAULT_ON ++ ++#define _WPA2_ // 20061122 It's needed for current Linux driver ++ ++ ++#ifndef _WPA_PSK_DEBUG ++#undef _WPA_PSK_DEBUG ++#endif ++ ++// debug print options, mark what debug you don't need ++ ++#ifdef FULL_DEBUG ++#define _PE_STATE_DUMP_ ++#define _PE_TX_DUMP_ ++#define _PE_RX_DUMP_ ++#define _PE_OID_DUMP_ ++#define _PE_DTO_DUMP_ ++#define _PE_REG_DUMP_ ++#define _PE_USB_INI_DUMP_ ++#endif ++ ++ ++ ++#include "common.h" // Individual file depends on OS ++ ++#include "../wb35_ver.h" ++#include "../mac_structures.h" ++#include "../ds_tkip.h" ++#include "../localpara.h" ++#include "../sme_s.h" ++#include "../scan_s.h" ++#include "../mds_s.h" ++#include "../mlme_s.h" ++#include "../bssdscpt.h" ++#include "../sme_api.h" ++#include "../gl_80211.h" ++#include "../mto.h" ++#include "../wblinux_s.h" ++#include "../wbhal_s.h" ++ ++ ++#include "../adapter.h" ++ ++#include "../mlme_mib.h" ++#include "../mds_f.h" ++#include "../bss_f.h" ++#include "../mlmetxrx_f.h" ++#include "../mto_f.h" ++#include "../wbhal_f.h" ++#include "../wblinux_f.h" ++// Kernel Timer resolution, NDIS is 10ms, 10000us ++#define MIN_TIMEOUT_VAL (10) //ms ++ ++ ++#endif +diff --git a/drivers/staging/winbond/linux/wb35reg.c b/drivers/staging/winbond/linux/wb35reg.c +new file mode 100644 +index 0000000..2c0b454 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35reg.c +@@ -0,0 +1,747 @@ ++#include "sysdef.h" ++ ++extern void phy_calibration_winbond(hw_data_t *phw_data, u32 frequency); ++ ++// TRUE : read command process successfully ++// FALSE : register not support ++// RegisterNo : start base ++// pRegisterData : data point ++// NumberOfData : number of register data ++// Flag : AUTO_INCREMENT - RegisterNo will auto increment 4 ++// NO_INCREMENT - Function will write data into the same register ++unsigned char ++Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ PURB pUrb = NULL; ++ PREG_QUEUE pRegQueue = NULL; ++ u16 UrbSize; ++ struct usb_ctrlrequest *dr; ++ u16 i, DataSize = NumberOfData*4; ++ ++ // Module shutdown ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ ++ // Trying to use burst write function if use new hardware ++ UrbSize = sizeof(REG_QUEUE) + DataSize + sizeof(struct usb_ctrlrequest); ++ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize ); ++ pUrb = wb_usb_alloc_urb(0); ++ if( pUrb && pRegQueue ) { ++ pRegQueue->DIRECT = 2;// burst write register ++ pRegQueue->INDEX = RegisterNo; ++ pRegQueue->pBuffer = (PULONG)((PUCHAR)pRegQueue + sizeof(REG_QUEUE)); ++ memcpy( pRegQueue->pBuffer, pRegisterData, DataSize ); ++ //the function for reversing register data from little endian to big endian ++ for( i=0; ipBuffer[i] = cpu_to_le32( pRegQueue->pBuffer[i] ); ++ ++ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE) + DataSize); ++ dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE; ++ dr->bRequest = 0x04; // USB or vendor-defined request code, burst mode ++ dr->wValue = cpu_to_le16( Flag ); // 0: Register number auto-increment, 1: No auto increment ++ dr->wIndex = cpu_to_le16( RegisterNo ); ++ dr->wLength = cpu_to_le16( DataSize ); ++ pRegQueue->Next = NULL; ++ pRegQueue->pUsbReq = dr; ++ pRegQueue->pUrb = pUrb; ++ ++ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock ); ++ if (pWb35Reg->pRegFirst == NULL) ++ pWb35Reg->pRegFirst = pRegQueue; ++ else ++ pWb35Reg->pRegLast->Next = pRegQueue; ++ pWb35Reg->pRegLast = pRegQueue; ++ ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ // Start EP0VM ++ Wb35Reg_EP0VM_start(pHwData); ++ ++ return TRUE; ++ } else { ++ if (pUrb) ++ usb_free_urb(pUrb); ++ if (pRegQueue) ++ kfree(pRegQueue); ++ return FALSE; ++ } ++ return FALSE; ++} ++ ++void ++Wb35Reg_Update(phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ switch (RegisterNo) { ++ case 0x3b0: pWb35Reg->U1B0 = RegisterValue; break; ++ case 0x3bc: pWb35Reg->U1BC_LEDConfigure = RegisterValue; break; ++ case 0x400: pWb35Reg->D00_DmaControl = RegisterValue; break; ++ case 0x800: pWb35Reg->M00_MacControl = RegisterValue; break; ++ case 0x804: pWb35Reg->M04_MulticastAddress1 = RegisterValue; break; ++ case 0x808: pWb35Reg->M08_MulticastAddress2 = RegisterValue; break; ++ case 0x824: pWb35Reg->M24_MacControl = RegisterValue; break; ++ case 0x828: pWb35Reg->M28_MacControl = RegisterValue; break; ++ case 0x82c: pWb35Reg->M2C_MacControl = RegisterValue; break; ++ case 0x838: pWb35Reg->M38_MacControl = RegisterValue; break; ++ case 0x840: pWb35Reg->M40_MacControl = RegisterValue; break; ++ case 0x844: pWb35Reg->M44_MacControl = RegisterValue; break; ++ case 0x848: pWb35Reg->M48_MacControl = RegisterValue; break; ++ case 0x84c: pWb35Reg->M4C_MacStatus = RegisterValue; break; ++ case 0x860: pWb35Reg->M60_MacControl = RegisterValue; break; ++ case 0x868: pWb35Reg->M68_MacControl = RegisterValue; break; ++ case 0x870: pWb35Reg->M70_MacControl = RegisterValue; break; ++ case 0x874: pWb35Reg->M74_MacControl = RegisterValue; break; ++ case 0x878: pWb35Reg->M78_ERPInformation = RegisterValue; break; ++ case 0x87C: pWb35Reg->M7C_MacControl = RegisterValue; break; ++ case 0x880: pWb35Reg->M80_MacControl = RegisterValue; break; ++ case 0x884: pWb35Reg->M84_MacControl = RegisterValue; break; ++ case 0x888: pWb35Reg->M88_MacControl = RegisterValue; break; ++ case 0x898: pWb35Reg->M98_MacControl = RegisterValue; break; ++ case 0x100c: pWb35Reg->BB0C = RegisterValue; break; ++ case 0x102c: pWb35Reg->BB2C = RegisterValue; break; ++ case 0x1030: pWb35Reg->BB30 = RegisterValue; break; ++ case 0x103c: pWb35Reg->BB3C = RegisterValue; break; ++ case 0x1048: pWb35Reg->BB48 = RegisterValue; break; ++ case 0x104c: pWb35Reg->BB4C = RegisterValue; break; ++ case 0x1050: pWb35Reg->BB50 = RegisterValue; break; ++ case 0x1054: pWb35Reg->BB54 = RegisterValue; break; ++ case 0x1058: pWb35Reg->BB58 = RegisterValue; break; ++ case 0x105c: pWb35Reg->BB5C = RegisterValue; break; ++ case 0x1060: pWb35Reg->BB60 = RegisterValue; break; ++ } ++} ++ ++// TRUE : read command process successfully ++// FALSE : register not support ++unsigned char ++Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ int ret = -1; ++ ++ // Module shutdown ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ ++ RegisterValue = cpu_to_le32(RegisterValue); ++ ++ // update the register by send usb message------------------------------------ ++ pWb35Reg->SyncIoPause = 1; ++ ++ // 20060717.5 Wait until EP0VM stop ++ while (pWb35Reg->EP0vm_state != VM_STOP) ++ OS_SLEEP(10000); ++ ++ // Sync IoCallDriver ++ pWb35Reg->EP0vm_state = VM_RUNNING; ++ ret = usb_control_msg( pHwData->WbUsb.udev, ++ usb_sndctrlpipe( pHwData->WbUsb.udev, 0 ), ++ 0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, ++ 0x0,RegisterNo, &RegisterValue, 4, HZ*100 ); ++ pWb35Reg->EP0vm_state = VM_STOP; ++ pWb35Reg->SyncIoPause = 0; ++ ++ Wb35Reg_EP0VM_start(pHwData); ++ ++ if (ret < 0) { ++ #ifdef _PE_REG_DUMP_ ++ WBDEBUG(("EP0 Write register usb message sending error\n")); ++ #endif ++ ++ pHwData->SurpriseRemove = 1; // 20060704.2 ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++// TRUE : read command process successfully ++// FALSE : register not support ++unsigned char ++Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ struct usb_ctrlrequest *dr; ++ PURB pUrb = NULL; ++ PREG_QUEUE pRegQueue = NULL; ++ u16 UrbSize; ++ ++ ++ // Module shutdown ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ ++ // update the register by send urb request------------------------------------ ++ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest); ++ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize ); ++ pUrb = wb_usb_alloc_urb(0); ++ if (pUrb && pRegQueue) { ++ pRegQueue->DIRECT = 1;// burst write register ++ pRegQueue->INDEX = RegisterNo; ++ pRegQueue->VALUE = cpu_to_le32(RegisterValue); ++ pRegQueue->RESERVED_VALID = FALSE; ++ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE)); ++ dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE; ++ dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode ++ dr->wValue = cpu_to_le16(0x0); ++ dr->wIndex = cpu_to_le16(RegisterNo); ++ dr->wLength = cpu_to_le16(4); ++ ++ // Enter the sending queue ++ pRegQueue->Next = NULL; ++ pRegQueue->pUsbReq = dr; ++ pRegQueue->pUrb = pUrb; ++ ++ OS_SPIN_LOCK_ACQUIRED(&pWb35Reg->EP0VM_spin_lock ); ++ if (pWb35Reg->pRegFirst == NULL) ++ pWb35Reg->pRegFirst = pRegQueue; ++ else ++ pWb35Reg->pRegLast->Next = pRegQueue; ++ pWb35Reg->pRegLast = pRegQueue; ++ ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ // Start EP0VM ++ Wb35Reg_EP0VM_start(pHwData); ++ ++ return TRUE; ++ } else { ++ if (pUrb) ++ usb_free_urb(pUrb); ++ kfree(pRegQueue); ++ return FALSE; ++ } ++} ++ ++//This command will be executed with a user defined value. When it completes, ++//this value is useful. For example, hal_set_current_channel will use it. ++// TRUE : read command process successfully ++// FALSE : register not support ++unsigned char ++Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue, ++ PCHAR pValue, s8 Len) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ struct usb_ctrlrequest *dr; ++ PURB pUrb = NULL; ++ PREG_QUEUE pRegQueue = NULL; ++ u16 UrbSize; ++ ++ // Module shutdown ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ ++ // update the register by send urb request------------------------------------ ++ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest); ++ OS_MEMORY_ALLOC((void* *) &pRegQueue, UrbSize ); ++ pUrb = wb_usb_alloc_urb(0); ++ if (pUrb && pRegQueue) { ++ pRegQueue->DIRECT = 1;// burst write register ++ pRegQueue->INDEX = RegisterNo; ++ pRegQueue->VALUE = cpu_to_le32(RegisterValue); ++ //NOTE : Users must guarantee the size of value will not exceed the buffer size. ++ memcpy(pRegQueue->RESERVED, pValue, Len); ++ pRegQueue->RESERVED_VALID = TRUE; ++ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE)); ++ dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE; ++ dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode ++ dr->wValue = cpu_to_le16(0x0); ++ dr->wIndex = cpu_to_le16(RegisterNo); ++ dr->wLength = cpu_to_le16(4); ++ ++ // Enter the sending queue ++ pRegQueue->Next = NULL; ++ pRegQueue->pUsbReq = dr; ++ pRegQueue->pUrb = pUrb; ++ OS_SPIN_LOCK_ACQUIRED (&pWb35Reg->EP0VM_spin_lock ); ++ if( pWb35Reg->pRegFirst == NULL ) ++ pWb35Reg->pRegFirst = pRegQueue; ++ else ++ pWb35Reg->pRegLast->Next = pRegQueue; ++ pWb35Reg->pRegLast = pRegQueue; ++ ++ OS_SPIN_LOCK_RELEASED ( &pWb35Reg->EP0VM_spin_lock ); ++ ++ // Start EP0VM ++ Wb35Reg_EP0VM_start(pHwData); ++ return TRUE; ++ } else { ++ if (pUrb) ++ usb_free_urb(pUrb); ++ kfree(pRegQueue); ++ return FALSE; ++ } ++} ++ ++// TRUE : read command process successfully ++// FALSE : register not support ++// pRegisterValue : It must be a resident buffer due to asynchronous read register. ++unsigned char ++Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ PULONG pltmp = pRegisterValue; ++ int ret = -1; ++ ++ // Module shutdown ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ ++ // Read the register by send usb message------------------------------------ ++ ++ pWb35Reg->SyncIoPause = 1; ++ ++ // 20060717.5 Wait until EP0VM stop ++ while (pWb35Reg->EP0vm_state != VM_STOP) ++ OS_SLEEP(10000); ++ ++ pWb35Reg->EP0vm_state = VM_RUNNING; ++ ret = usb_control_msg( pHwData->WbUsb.udev, ++ usb_rcvctrlpipe(pHwData->WbUsb.udev, 0), ++ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, ++ 0x0, RegisterNo, pltmp, 4, HZ*100 ); ++ ++ *pRegisterValue = cpu_to_le32(*pltmp); ++ ++ pWb35Reg->EP0vm_state = VM_STOP; ++ ++ Wb35Reg_Update( pHwData, RegisterNo, *pRegisterValue ); ++ pWb35Reg->SyncIoPause = 0; ++ ++ Wb35Reg_EP0VM_start( pHwData ); ++ ++ if (ret < 0) { ++ #ifdef _PE_REG_DUMP_ ++ WBDEBUG(("EP0 Read register usb message sending error\n")); ++ #endif ++ ++ pHwData->SurpriseRemove = 1; // 20060704.2 ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++// TRUE : read command process successfully ++// FALSE : register not support ++// pRegisterValue : It must be a resident buffer due to asynchronous read register. ++unsigned char ++Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ struct usb_ctrlrequest * dr; ++ PURB pUrb; ++ PREG_QUEUE pRegQueue; ++ u16 UrbSize; ++ ++ // Module shutdown ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ ++ // update the variable by send Urb to read register ------------------------------------ ++ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest); ++ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize ); ++ pUrb = wb_usb_alloc_urb(0); ++ if( pUrb && pRegQueue ) ++ { ++ pRegQueue->DIRECT = 0;// read register ++ pRegQueue->INDEX = RegisterNo; ++ pRegQueue->pBuffer = pRegisterValue; ++ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE)); ++ dr->bRequestType = USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN; ++ dr->bRequest = 0x01; // USB or vendor-defined request code, burst mode ++ dr->wValue = cpu_to_le16(0x0); ++ dr->wIndex = cpu_to_le16 (RegisterNo); ++ dr->wLength = cpu_to_le16 (4); ++ ++ // Enter the sending queue ++ pRegQueue->Next = NULL; ++ pRegQueue->pUsbReq = dr; ++ pRegQueue->pUrb = pUrb; ++ OS_SPIN_LOCK_ACQUIRED ( &pWb35Reg->EP0VM_spin_lock ); ++ if( pWb35Reg->pRegFirst == NULL ) ++ pWb35Reg->pRegFirst = pRegQueue; ++ else ++ pWb35Reg->pRegLast->Next = pRegQueue; ++ pWb35Reg->pRegLast = pRegQueue; ++ ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ // Start EP0VM ++ Wb35Reg_EP0VM_start( pHwData ); ++ ++ return TRUE; ++ } else { ++ if (pUrb) ++ usb_free_urb( pUrb ); ++ kfree(pRegQueue); ++ return FALSE; ++ } ++} ++ ++ ++void ++Wb35Reg_EP0VM_start( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Reg->RegFireCount) == 1) { ++ pWb35Reg->EP0vm_state = VM_RUNNING; ++ Wb35Reg_EP0VM(pHwData); ++ } else ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount ); ++} ++ ++void ++Wb35Reg_EP0VM(phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ PURB pUrb; ++ struct usb_ctrlrequest *dr; ++ PULONG pBuffer; ++ int ret = -1; ++ PREG_QUEUE pRegQueue; ++ ++ ++ if (pWb35Reg->SyncIoPause) ++ goto cleanup; ++ ++ if (pHwData->SurpriseRemove) ++ goto cleanup; ++ ++ // Get the register data and send to USB through Irp ++ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock ); ++ pRegQueue = pWb35Reg->pRegFirst; ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ if (!pRegQueue) ++ goto cleanup; ++ ++ // Get an Urb, send it ++ pUrb = (PURB)pRegQueue->pUrb; ++ ++ dr = pRegQueue->pUsbReq; ++ pUrb = pRegQueue->pUrb; ++ pBuffer = pRegQueue->pBuffer; ++ if (pRegQueue->DIRECT == 1) // output ++ pBuffer = &pRegQueue->VALUE; ++ ++ usb_fill_control_urb( pUrb, pHwData->WbUsb.udev, ++ REG_DIRECTION(pHwData->WbUsb.udev,pRegQueue), ++ (PUCHAR)dr,pBuffer,cpu_to_le16(dr->wLength), ++ Wb35Reg_EP0VM_complete, (void*)pHwData); ++ ++ pWb35Reg->EP0vm_state = VM_RUNNING; ++ ++ ret = wb_usb_submit_urb( pUrb ); ++ ++ if (ret < 0) { ++#ifdef _PE_REG_DUMP_ ++ WBDEBUG(("EP0 Irp sending error\n")); ++#endif ++ goto cleanup; ++ } ++ ++ return; ++ ++ cleanup: ++ pWb35Reg->EP0vm_state = VM_STOP; ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount ); ++} ++ ++ ++void ++Wb35Reg_EP0VM_complete(PURB pUrb) ++{ ++ phw_data_t pHwData = (phw_data_t)pUrb->context; ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ PREG_QUEUE pRegQueue; ++ ++ ++ // Variable setting ++ pWb35Reg->EP0vm_state = VM_COMPLETED; ++ pWb35Reg->EP0VM_status = pUrb->status; ++ ++ if (pHwData->SurpriseRemove) { // Let WbWlanHalt to handle surprise remove ++ pWb35Reg->EP0vm_state = VM_STOP; ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount ); ++ } else { ++ // Complete to send, remove the URB from the first ++ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock ); ++ pRegQueue = pWb35Reg->pRegFirst; ++ if (pRegQueue == pWb35Reg->pRegLast) ++ pWb35Reg->pRegLast = NULL; ++ pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next; ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ if (pWb35Reg->EP0VM_status) { ++#ifdef _PE_REG_DUMP_ ++ WBDEBUG(("EP0 IoCompleteRoutine return error\n")); ++ DebugUsbdStatusInformation( pWb35Reg->EP0VM_status ); ++#endif ++ pWb35Reg->EP0vm_state = VM_STOP; ++ pHwData->SurpriseRemove = 1; ++ } else { ++ // Success. Update the result ++ ++ // Start the next send ++ Wb35Reg_EP0VM(pHwData); ++ } ++ ++ kfree(pRegQueue); ++ } ++ ++ usb_free_urb(pUrb); ++} ++ ++ ++void ++Wb35Reg_destroy(phw_data_t pHwData) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ PURB pUrb; ++ PREG_QUEUE pRegQueue; ++ ++ ++ Uxx_power_off_procedure(pHwData); ++ ++ // Wait for Reg operation completed ++ do { ++ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a ++ } while (pWb35Reg->EP0vm_state != VM_STOP); ++ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b ++ ++ // Release all the data in RegQueue ++ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock ); ++ pRegQueue = pWb35Reg->pRegFirst; ++ while (pRegQueue) { ++ if (pRegQueue == pWb35Reg->pRegLast) ++ pWb35Reg->pRegLast = NULL; ++ pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next; ++ ++ pUrb = pRegQueue->pUrb; ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ if (pUrb) { ++ usb_free_urb(pUrb); ++ kfree(pRegQueue); ++ } else { ++ #ifdef _PE_REG_DUMP_ ++ WBDEBUG(("EP0 queue release error\n")); ++ #endif ++ } ++ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ pRegQueue = pWb35Reg->pRegFirst; ++ } ++ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock ); ++ ++ // Free resource ++ OS_SPIN_LOCK_FREE( &pWb35Reg->EP0VM_spin_lock ); ++} ++ ++//==================================================================================== ++// The function can be run in passive-level only. ++//==================================================================================== ++unsigned char Wb35Reg_initial(phw_data_t pHwData) ++{ ++ PWB35REG pWb35Reg=&pHwData->Wb35Reg; ++ u32 ltmp; ++ u32 SoftwareSet, VCO_trim, TxVga, Region_ScanInterval; ++ ++ // Spin lock is acquired for read and write IRP command ++ OS_SPIN_LOCK_ALLOCATE( &pWb35Reg->EP0VM_spin_lock ); ++ ++ // Getting RF module type from EEPROM ------------------------------------ ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x080d0000 ); // Start EEPROM access + Read + address(0x0d) ++ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp ); ++ ++ //Update RF module type and determine the PHY type by inf or EEPROM ++ pWb35Reg->EEPROMPhyType = (u8)( ltmp & 0xff ); ++ // 0 V MAX2825, 1 V MAX2827, 2 V MAX2828, 3 V MAX2829 ++ // 16V AL2230, 17 - AL7230, 18 - AL2230S ++ // 32 Reserved ++ // 33 - W89RF242(TxVGA 0~19), 34 - W89RF242(TxVGA 0~34) ++ if (pWb35Reg->EEPROMPhyType != RF_DECIDE_BY_INF) { ++ if( (pWb35Reg->EEPROMPhyType == RF_MAXIM_2825) || ++ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2827) || ++ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2828) || ++ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2829) || ++ (pWb35Reg->EEPROMPhyType == RF_MAXIM_V1) || ++ (pWb35Reg->EEPROMPhyType == RF_AIROHA_2230) || ++ (pWb35Reg->EEPROMPhyType == RF_AIROHA_2230S) || ++ (pWb35Reg->EEPROMPhyType == RF_AIROHA_7230) || ++ (pWb35Reg->EEPROMPhyType == RF_WB_242) || ++ (pWb35Reg->EEPROMPhyType == RF_WB_242_1)) ++ pHwData->phy_type = pWb35Reg->EEPROMPhyType; ++ } ++ ++ // Power On procedure running. The relative parameter will be set according to phy_type ++ Uxx_power_on_procedure( pHwData ); ++ ++ // Reading MAC address ++ Uxx_ReadEthernetAddress( pHwData ); ++ ++ // Read VCO trim for RF parameter ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08200000 ); ++ Wb35Reg_ReadSync( pHwData, 0x03b4, &VCO_trim ); ++ ++ // Read Antenna On/Off of software flag ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08210000 ); ++ Wb35Reg_ReadSync( pHwData, 0x03b4, &SoftwareSet ); ++ ++ // Read TXVGA ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08100000 ); ++ Wb35Reg_ReadSync( pHwData, 0x03b4, &TxVga ); ++ ++ // Get Scan interval setting from EEPROM offset 0x1c ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x081d0000 ); ++ Wb35Reg_ReadSync( pHwData, 0x03b4, &Region_ScanInterval ); ++ ++ // Update Ethernet address ++ memcpy( pHwData->CurrentMacAddress, pHwData->PermanentMacAddress, ETH_LENGTH_OF_ADDRESS ); ++ ++ // Update software variable ++ pHwData->SoftwareSet = (u16)(SoftwareSet & 0xffff); ++ TxVga &= 0x000000ff; ++ pHwData->PowerIndexFromEEPROM = (u8)TxVga; ++ pHwData->VCO_trim = (u8)VCO_trim & 0xff; ++ if (pHwData->VCO_trim == 0xff) ++ pHwData->VCO_trim = 0x28; ++ ++ pWb35Reg->EEPROMRegion = (u8)(Region_ScanInterval>>8); // 20060720 ++ if( pWb35Reg->EEPROMRegion<1 || pWb35Reg->EEPROMRegion>6 ) ++ pWb35Reg->EEPROMRegion = REGION_AUTO; ++ ++ //For Get Tx VGA from EEPROM 20060315.5 move here ++ GetTxVgaFromEEPROM( pHwData ); ++ ++ // Set Scan Interval ++ pHwData->Scan_Interval = (u8)(Region_ScanInterval & 0xff) * 10; ++ if ((pHwData->Scan_Interval == 2550) || (pHwData->Scan_Interval < 10)) // Is default setting 0xff * 10 ++ pHwData->Scan_Interval = SCAN_MAX_CHNL_TIME; ++ ++ // Initial register ++ RFSynthesizer_initial(pHwData); ++ ++ BBProcessor_initial(pHwData); // Async write, must wait until complete ++ ++ Wb35Reg_phy_calibration(pHwData); ++ ++ Mxx_initial(pHwData); ++ Dxx_initial(pHwData); ++ ++ if (pHwData->SurpriseRemove) ++ return FALSE; ++ else ++ return TRUE; // Initial fail ++} ++ ++//=================================================================================== ++// CardComputeCrc -- ++// ++// Description: ++// Runs the AUTODIN II CRC algorithm on buffer Buffer of length, Length. ++// ++// Arguments: ++// Buffer - the input buffer ++// Length - the length of Buffer ++// ++// Return Value: ++// The 32-bit CRC value. ++// ++// Note: ++// This is adapted from the comments in the assembly language ++// version in _GENREQ.ASM of the DWB NE1000/2000 driver. ++//================================================================================== ++u32 ++CardComputeCrc(PUCHAR Buffer, u32 Length) ++{ ++ u32 Crc, Carry; ++ u32 i, j; ++ u8 CurByte; ++ ++ Crc = 0xffffffff; ++ ++ for (i = 0; i < Length; i++) { ++ ++ CurByte = Buffer[i]; ++ ++ for (j = 0; j < 8; j++) { ++ ++ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01); ++ Crc <<= 1; ++ CurByte >>= 1; ++ ++ if (Carry) { ++ Crc =(Crc ^ 0x04c11db6) | Carry; ++ } ++ } ++ } ++ ++ return Crc; ++} ++ ++ ++//================================================================== ++// BitReverse -- ++// Reverse the bits in the input argument, dwData, which is ++// regarded as a string of bits with the length, DataLength. ++// ++// Arguments: ++// dwData : ++// DataLength : ++// ++// Return: ++// The converted value. ++//================================================================== ++u32 BitReverse( u32 dwData, u32 DataLength) ++{ ++ u32 HalfLength, i, j; ++ u32 BitA, BitB; ++ ++ if ( DataLength <= 0) return 0; // No conversion is done. ++ dwData = dwData & (0xffffffff >> (32 - DataLength)); ++ ++ HalfLength = DataLength / 2; ++ for ( i = 0, j = DataLength-1 ; i < HalfLength; i++, j--) ++ { ++ BitA = GetBit( dwData, i); ++ BitB = GetBit( dwData, j); ++ if (BitA && !BitB) { ++ dwData = ClearBit( dwData, i); ++ dwData = SetBit( dwData, j); ++ } else if (!BitA && BitB) { ++ dwData = SetBit( dwData, i); ++ dwData = ClearBit( dwData, j); ++ } else ++ { ++ // Do nothing since these two bits are of the save values. ++ } ++ } ++ ++ return dwData; ++} ++ ++void Wb35Reg_phy_calibration( phw_data_t pHwData ) ++{ ++ u32 BB3c, BB54; ++ ++ if ((pHwData->phy_type == RF_WB_242) || ++ (pHwData->phy_type == RF_WB_242_1)) { ++ phy_calibration_winbond ( pHwData, 2412 ); // Sync operation ++ Wb35Reg_ReadSync( pHwData, 0x103c, &BB3c ); ++ Wb35Reg_ReadSync( pHwData, 0x1054, &BB54 ); ++ ++ pHwData->BB3c_cal = BB3c; ++ pHwData->BB54_cal = BB54; ++ ++ RFSynthesizer_initial(pHwData); ++ BBProcessor_initial(pHwData); // Async operation ++ ++ Wb35Reg_WriteSync( pHwData, 0x103c, BB3c ); ++ Wb35Reg_WriteSync( pHwData, 0x1054, BB54 ); ++ } ++} ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35reg_f.h b/drivers/staging/winbond/linux/wb35reg_f.h +new file mode 100644 +index 0000000..38e2906 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35reg_f.h +@@ -0,0 +1,56 @@ ++//==================================== ++// Interface function declare ++//==================================== ++unsigned char Wb35Reg_initial( phw_data_t pHwData ); ++void Uxx_power_on_procedure( phw_data_t pHwData ); ++void Uxx_power_off_procedure( phw_data_t pHwData ); ++void Uxx_ReadEthernetAddress( phw_data_t pHwData ); ++void Dxx_initial( phw_data_t pHwData ); ++void Mxx_initial( phw_data_t pHwData ); ++void RFSynthesizer_initial( phw_data_t pHwData ); ++//void RFSynthesizer_SwitchingChannel( phw_data_t pHwData, s8 Channel ); ++void RFSynthesizer_SwitchingChannel( phw_data_t pHwData, ChanInfo Channel ); ++void BBProcessor_initial( phw_data_t pHwData ); ++void BBProcessor_RateChanging( phw_data_t pHwData, u8 rate ); // 20060613.1 ++//void RF_RateChanging( phw_data_t pHwData, u8 rate ); // 20060626.5.c Add ++u8 RFSynthesizer_SetPowerIndex( phw_data_t pHwData, u8 PowerIndex ); ++u8 RFSynthesizer_SetMaxim2828_24Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetMaxim2828_50Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetMaxim2827_24Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetMaxim2827_50Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetMaxim2825Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetAiroha2230Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetAiroha7230Power( phw_data_t, u8 index ); ++u8 RFSynthesizer_SetWinbond242Power( phw_data_t, u8 index ); ++void GetTxVgaFromEEPROM( phw_data_t pHwData ); ++void EEPROMTxVgaAdjust( phw_data_t pHwData ); // 20060619.5 Add ++ ++#define RFWriteControlData( _A, _V ) Wb35Reg_Write( _A, 0x0864, _V ) ++ ++void Wb35Reg_destroy( phw_data_t pHwData ); ++ ++unsigned char Wb35Reg_Read( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue ); ++unsigned char Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue ); ++unsigned char Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue ); ++unsigned char Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue ); ++unsigned char Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, ++ u16 RegisterNo, ++ u32 RegisterValue, ++ PCHAR pValue, ++ s8 Len); ++unsigned char Wb35Reg_BurstWrite( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag ); ++ ++void Wb35Reg_EP0VM( phw_data_t pHwData ); ++void Wb35Reg_EP0VM_start( phw_data_t pHwData ); ++void Wb35Reg_EP0VM_complete( PURB pUrb ); ++ ++u32 BitReverse( u32 dwData, u32 DataLength); ++ ++void CardGetMulticastBit( u8 Address[MAC_ADDR_LENGTH], u8 *Byte, u8 *Value ); ++u32 CardComputeCrc( PUCHAR Buffer, u32 Length ); ++ ++void Wb35Reg_phy_calibration( phw_data_t pHwData ); ++void Wb35Reg_Update( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue ); ++unsigned char adjust_TXVGA_for_iq_mag( phw_data_t pHwData ); ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35reg_s.h b/drivers/staging/winbond/linux/wb35reg_s.h +new file mode 100644 +index 0000000..a7595b1 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35reg_s.h +@@ -0,0 +1,170 @@ ++//======================================================================================= ++/* ++ HAL setting function ++ ++ ======================================== ++ |Uxx| |Dxx| |Mxx| |BB| |RF| ++ ======================================== ++ | | ++ Wb35Reg_Read Wb35Reg_Write ++ ++ ---------------------------------------- ++ WbUsb_CallUSBDASync supplied By WbUsb module ++*/ ++//======================================================================================= ++ ++#define GetBit( dwData, i) ( dwData & (0x00000001 << i)) ++#define SetBit( dwData, i) ( dwData | (0x00000001 << i)) ++#define ClearBit( dwData, i) ( dwData & ~(0x00000001 << i)) ++ ++#define IGNORE_INCREMENT 0 ++#define AUTO_INCREMENT 0 ++#define NO_INCREMENT 1 ++#define REG_DIRECTION(_x,_y) ((_y)->DIRECT ==0 ? usb_rcvctrlpipe(_x,0) : usb_sndctrlpipe(_x,0)) ++#define REG_BUF_SIZE(_x) ((_x)->bRequest== 0x04 ? cpu_to_le16((_x)->wLength) : 4) ++ ++// 20060613.2 Add the follow definition ++#define BB48_DEFAULT_AL2230_11B 0x0033447c ++#define BB4C_DEFAULT_AL2230_11B 0x0A00FEFF ++#define BB48_DEFAULT_AL2230_11G 0x00332C1B ++#define BB4C_DEFAULT_AL2230_11G 0x0A00FEFF ++ ++ ++#define BB48_DEFAULT_WB242_11B 0x00292315 //backoff 2dB ++#define BB4C_DEFAULT_WB242_11B 0x0800FEFF //backoff 2dB ++//#define BB48_DEFAULT_WB242_11B 0x00201B11 //backoff 4dB ++//#define BB4C_DEFAULT_WB242_11B 0x0600FF00 //backoff 4dB ++#define BB48_DEFAULT_WB242_11G 0x00453B24 ++#define BB4C_DEFAULT_WB242_11G 0x0E00FEFF ++ ++//==================================== ++// Default setting for Mxx ++//==================================== ++#define DEFAULT_CWMIN 31 //(M2C) CWmin. Its value is in the range 0-31. ++#define DEFAULT_CWMAX 1023 //(M2C) CWmax. Its value is in the range 0-1023. ++#define DEFAULT_AID 1 //(M34) AID. Its value is in the range 1-2007. ++ ++#ifdef _USE_FALLBACK_RATE_ ++#define DEFAULT_RATE_RETRY_LIMIT 2 //(M38) as named ++#else ++#define DEFAULT_RATE_RETRY_LIMIT 7 //(M38) as named ++#endif ++ ++#define DEFAULT_LONG_RETRY_LIMIT 7 //(M38) LongRetryLimit. Its value is in the range 0-15. ++#define DEFAULT_SHORT_RETRY_LIMIT 7 //(M38) ShortRetryLimit. Its value is in the range 0-15. ++#define DEFAULT_PIFST 25 //(M3C) PIFS Time. Its value is in the range 0-65535. ++#define DEFAULT_EIFST 354 //(M3C) EIFS Time. Its value is in the range 0-1048575. ++#define DEFAULT_DIFST 45 //(M3C) DIFS Time. Its value is in the range 0-65535. ++#define DEFAULT_SIFST 5 //(M3C) SIFS Time. Its value is in the range 0-65535. ++#define DEFAULT_OSIFST 10 //(M3C) Original SIFS Time. Its value is in the range 0-15. ++#define DEFAULT_ATIMWD 0 //(M40) ATIM Window. Its value is in the range 0-65535. ++#define DEFAULT_SLOT_TIME 20 //(M40) ($) SlotTime. Its value is in the range 0-255. ++#define DEFAULT_MAX_TX_MSDU_LIFE_TIME 512 //(M44) MaxTxMSDULifeTime. Its value is in the range 0-4294967295. ++#define DEFAULT_BEACON_INTERVAL 500 //(M48) Beacon Interval. Its value is in the range 0-65535. ++#define DEFAULT_PROBE_DELAY_TIME 200 //(M48) Probe Delay Time. Its value is in the range 0-65535. ++#define DEFAULT_PROTOCOL_VERSION 0 //(M4C) ++#define DEFAULT_MAC_POWER_STATE 2 //(M4C) 2: MAC at power active ++#define DEFAULT_DTIM_ALERT_TIME 0 ++ ++ ++typedef struct _REG_QUEUE ++{ ++ struct urb *pUrb; ++ void* pUsbReq; ++ void* Next; ++ union ++ { ++ u32 VALUE; ++ PULONG pBuffer; ++ }; ++ u8 RESERVED[4];// space reserved for communication ++ ++ u16 INDEX; // For storing the register index ++ u8 RESERVED_VALID; //Indicate whether the RESERVED space is valid at this command. ++ u8 DIRECT; // 0:In 1:Out ++ ++} REG_QUEUE, *PREG_QUEUE; ++ ++//==================================== ++// Internal variable for module ++//==================================== ++#define MAX_SQ3_FILTER_SIZE 5 ++typedef struct _WB35REG ++{ ++ //============================ ++ // Register Bank backup ++ //============================ ++ u32 U1B0; //bit16 record the h/w radio on/off status ++ u32 U1BC_LEDConfigure; ++ u32 D00_DmaControl; ++ u32 M00_MacControl; ++ union { ++ struct { ++ u32 M04_MulticastAddress1; ++ u32 M08_MulticastAddress2; ++ }; ++ u8 Multicast[8]; // contents of card multicast registers ++ }; ++ ++ u32 M24_MacControl; ++ u32 M28_MacControl; ++ u32 M2C_MacControl; ++ u32 M38_MacControl; ++ u32 M3C_MacControl; // 20060214 backup only ++ u32 M40_MacControl; ++ u32 M44_MacControl; // 20060214 backup only ++ u32 M48_MacControl; // 20060214 backup only ++ u32 M4C_MacStatus; ++ u32 M60_MacControl; // 20060214 backup only ++ u32 M68_MacControl; // 20060214 backup only ++ u32 M70_MacControl; // 20060214 backup only ++ u32 M74_MacControl; // 20060214 backup only ++ u32 M78_ERPInformation;//930206.2.b ++ u32 M7C_MacControl; // 20060214 backup only ++ u32 M80_MacControl; // 20060214 backup only ++ u32 M84_MacControl; // 20060214 backup only ++ u32 M88_MacControl; // 20060214 backup only ++ u32 M98_MacControl; // 20060214 backup only ++ ++ //[20040722 WK] ++ //Baseband register ++ u32 BB0C; // Used for LNA calculation ++ u32 BB2C; // ++ u32 BB30; //11b acquisition control register ++ u32 BB3C; ++ u32 BB48; // 20051221.1.a 20060613.1 Fix OBW issue of 11b/11g rate ++ u32 BB4C; // 20060613.1 Fix OBW issue of 11b/11g rate ++ u32 BB50; //mode control register ++ u32 BB54; ++ u32 BB58; //IQ_ALPHA ++ u32 BB5C; // For test ++ u32 BB60; // for WTO read value ++ ++ //------------------- ++ // VM ++ //------------------- ++ OS_SPIN_LOCK EP0VM_spin_lock; // 4B ++ u32 EP0VM_status;//$$ ++ PREG_QUEUE pRegFirst; ++ PREG_QUEUE pRegLast; ++ OS_ATOMIC RegFireCount; ++ ++ // Hardware status ++ u8 EP0vm_state; ++ u8 mac_power_save; ++ u8 EEPROMPhyType; // 0 ~ 15 for Maxim (0 ĄV MAX2825, 1 ĄV MAX2827, 2 ĄV MAX2828, 3 ĄV MAX2829), ++ // 16 ~ 31 for Airoha (16 ĄV AL2230, 11 - AL7230) ++ // 32 ~ Reserved ++ // 33 ~ 47 For WB242 ( 33 - WB242, 34 - WB242 with new Txvga 0.5 db step) ++ // 48 ~ 255 ARE RESERVED. ++ u8 EEPROMRegion; //Region setting in EEPROM ++ ++ u32 SyncIoPause; // If user use the Sync Io to access Hw, then pause the async access ++ ++ u8 LNAValue[4]; //Table for speed up running ++ u32 SQ3_filter[MAX_SQ3_FILTER_SIZE]; ++ u32 SQ3_index; ++ ++} WB35REG, *PWB35REG; ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35rx.c b/drivers/staging/winbond/linux/wb35rx.c +new file mode 100644 +index 0000000..26157eb +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35rx.c +@@ -0,0 +1,337 @@ ++//============================================================================ ++// Copyright (c) 1996-2002 Winbond Electronic Corporation ++// ++// Module Name: ++// Wb35Rx.c ++// ++// Abstract: ++// Processing the Rx message from down layer ++// ++//============================================================================ ++#include "sysdef.h" ++ ++ ++void Wb35Rx_start(phw_data_t pHwData) ++{ ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ ++ // Allow only one thread to run into the Wb35Rx() function ++ if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Rx->RxFireCounter) == 1) { ++ pWb35Rx->EP3vm_state = VM_RUNNING; ++ Wb35Rx(pHwData); ++ } else ++ OS_ATOMIC_DEC(pHwData->Adapter, &pWb35Rx->RxFireCounter); ++} ++ ++// This function cannot reentrain ++void Wb35Rx( phw_data_t pHwData ) ++{ ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ PUCHAR pRxBufferAddress; ++ PURB pUrb = (PURB)pWb35Rx->RxUrb; ++ int retv; ++ u32 RxBufferId; ++ ++ // ++ // Issuing URB ++ // ++ do { ++ if (pHwData->SurpriseRemove || pHwData->HwStop) ++ break; ++ ++ if (pWb35Rx->rx_halt) ++ break; ++ ++ // Get RxBuffer's ID ++ RxBufferId = pWb35Rx->RxBufferId; ++ if (!pWb35Rx->RxOwner[RxBufferId]) { ++ // It's impossible to run here. ++ #ifdef _PE_RX_DUMP_ ++ WBDEBUG(("Rx driver fifo unavailable\n")); ++ #endif ++ break; ++ } ++ ++ // Update buffer point, then start to bulkin the data from USB ++ pWb35Rx->RxBufferId++; ++ pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER; ++ ++ pWb35Rx->CurrentRxBufferId = RxBufferId; ++ ++ if (1 != OS_MEMORY_ALLOC((void* *)&pWb35Rx->pDRx, MAX_USB_RX_BUFFER)) { ++ printk("w35und: Rx memory alloc failed\n"); ++ break; ++ } ++ pRxBufferAddress = pWb35Rx->pDRx; ++ ++ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev, ++ usb_rcvbulkpipe(pHwData->WbUsb.udev, 3), ++ pRxBufferAddress, MAX_USB_RX_BUFFER, ++ Wb35Rx_Complete, pHwData); ++ ++ pWb35Rx->EP3vm_state = VM_RUNNING; ++ ++ retv = wb_usb_submit_urb(pUrb); ++ ++ if (retv != 0) { ++ printk("Rx URB sending error\n"); ++ break; ++ } ++ return; ++ } while(FALSE); ++ ++ // VM stop ++ pWb35Rx->EP3vm_state = VM_STOP; ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter ); ++} ++ ++void Wb35Rx_Complete(PURB pUrb) ++{ ++ phw_data_t pHwData = pUrb->context; ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ PUCHAR pRxBufferAddress; ++ u32 SizeCheck; ++ u16 BulkLength; ++ u32 RxBufferId; ++ R00_DESCRIPTOR R00; ++ ++ // Variable setting ++ pWb35Rx->EP3vm_state = VM_COMPLETED; ++ pWb35Rx->EP3VM_status = pUrb->status;//Store the last result of Irp ++ ++ do { ++ RxBufferId = pWb35Rx->CurrentRxBufferId; ++ ++ pRxBufferAddress = pWb35Rx->pDRx; ++ BulkLength = (u16)pUrb->actual_length; ++ ++ // The IRP is completed ++ pWb35Rx->EP3vm_state = VM_COMPLETED; ++ ++ if (pHwData->SurpriseRemove || pHwData->HwStop) // Must be here, or RxBufferId is invalid ++ break; ++ ++ if (pWb35Rx->rx_halt) ++ break; ++ ++ // Start to process the data only in successful condition ++ pWb35Rx->RxOwner[ RxBufferId ] = 0; // Set the owner to driver ++ R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress); ++ ++ // The URB is completed, check the result ++ if (pWb35Rx->EP3VM_status != 0) { ++ #ifdef _PE_USB_STATE_DUMP_ ++ WBDEBUG(("EP3 IoCompleteRoutine return error\n")); ++ DebugUsbdStatusInformation( pWb35Rx->EP3VM_status ); ++ #endif ++ pWb35Rx->EP3vm_state = VM_STOP; ++ break; ++ } ++ ++ // 20060220 For recovering. check if operating in single USB mode ++ if (!HAL_USB_MODE_BURST(pHwData)) { ++ SizeCheck = R00.R00_receive_byte_count; //20060926 anson's endian ++ if ((SizeCheck & 0x03) > 0) ++ SizeCheck -= 4; ++ SizeCheck = (SizeCheck + 3) & ~0x03; ++ SizeCheck += 12; // 8 + 4 badbeef ++ if ((BulkLength > 1600) || ++ (SizeCheck > 1600) || ++ (BulkLength != SizeCheck) || ++ (BulkLength == 0)) { // Add for fail Urb ++ pWb35Rx->EP3vm_state = VM_STOP; ++ pWb35Rx->Ep3ErrorCount2++; ++ } ++ } ++ ++ // Indicating the receiving data ++ pWb35Rx->ByteReceived += BulkLength; ++ pWb35Rx->RxBufferSize[ RxBufferId ] = BulkLength; ++ ++ if (!pWb35Rx->RxOwner[ RxBufferId ]) ++ Wb35Rx_indicate(pHwData); ++ ++ kfree(pWb35Rx->pDRx); ++ // Do the next receive ++ Wb35Rx(pHwData); ++ return; ++ ++ } while(FALSE); ++ ++ pWb35Rx->RxOwner[ RxBufferId ] = 1; // Set the owner to hardware ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter ); ++ pWb35Rx->EP3vm_state = VM_STOP; ++} ++ ++//===================================================================================== ++unsigned char Wb35Rx_initial(phw_data_t pHwData) ++{ ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ ++ // Initial the Buffer Queue ++ Wb35Rx_reset_descriptor( pHwData ); ++ ++ pWb35Rx->RxUrb = wb_usb_alloc_urb(0); ++ return (!!pWb35Rx->RxUrb); ++} ++ ++void Wb35Rx_stop(phw_data_t pHwData) ++{ ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ ++ // Canceling the Irp if already sends it out. ++ if (pWb35Rx->EP3vm_state == VM_RUNNING) { ++ usb_unlink_urb( pWb35Rx->RxUrb ); // Only use unlink, let Wb35Rx_destroy to free them ++ #ifdef _PE_RX_DUMP_ ++ WBDEBUG(("EP3 Rx stop\n")); ++ #endif ++ } ++} ++ ++// Needs process context ++void Wb35Rx_destroy(phw_data_t pHwData) ++{ ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ ++ do { ++ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a ++ } while (pWb35Rx->EP3vm_state != VM_STOP); ++ OS_SLEEP(10000); // Delay for waiting function exit 940623.1.b ++ ++ if (pWb35Rx->RxUrb) ++ usb_free_urb( pWb35Rx->RxUrb ); ++ #ifdef _PE_RX_DUMP_ ++ WBDEBUG(("Wb35Rx_destroy OK\n")); ++ #endif ++} ++ ++void Wb35Rx_reset_descriptor( phw_data_t pHwData ) ++{ ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ u32 i; ++ ++ pWb35Rx->ByteReceived = 0; ++ pWb35Rx->RxProcessIndex = 0; ++ pWb35Rx->RxBufferId = 0; ++ pWb35Rx->EP3vm_state = VM_STOP; ++ pWb35Rx->rx_halt = 0; ++ ++ // Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable. ++ for( i=0; iRxOwner[i] = 1; ++} ++ ++void Wb35Rx_adjust(PDESCRIPTOR pRxDes) ++{ ++ PULONG pRxBufferAddress; ++ u32 DecryptionMethod; ++ u32 i; ++ u16 BufferSize; ++ ++ DecryptionMethod = pRxDes->R01.R01_decryption_method; ++ pRxBufferAddress = pRxDes->buffer_address[0]; ++ BufferSize = pRxDes->buffer_size[0]; ++ ++ // Adjust the last part of data. Only data left ++ BufferSize -= 4; // For CRC-32 ++ if (DecryptionMethod) ++ BufferSize -= 4; ++ if (DecryptionMethod == 3) // For CCMP ++ BufferSize -= 4; ++ ++ // Adjust the IV field which after 802.11 header and ICV field. ++ if (DecryptionMethod == 1) // For WEP ++ { ++ for( i=6; i>0; i-- ) ++ pRxBufferAddress[i] = pRxBufferAddress[i-1]; ++ pRxDes->buffer_address[0] = pRxBufferAddress + 1; ++ BufferSize -= 4; // 4 byte for IV ++ } ++ else if( DecryptionMethod ) // For TKIP and CCMP ++ { ++ for (i=7; i>1; i--) ++ pRxBufferAddress[i] = pRxBufferAddress[i-2]; ++ pRxDes->buffer_address[0] = pRxBufferAddress + 2;//Update the descriptor, shift 8 byte ++ BufferSize -= 8; // 8 byte for IV + ICV ++ } ++ pRxDes->buffer_size[0] = BufferSize; ++} ++ ++extern void packet_came(char *pRxBufferAddress, int PacketSize); ++ ++ ++u16 Wb35Rx_indicate(phw_data_t pHwData) ++{ ++ DESCRIPTOR RxDes; ++ PWB35RX pWb35Rx = &pHwData->Wb35Rx; ++ PUCHAR pRxBufferAddress; ++ u16 PacketSize; ++ u16 stmp, BufferSize, stmp2 = 0; ++ u32 RxBufferId; ++ ++ // Only one thread be allowed to run into the following ++ do { ++ RxBufferId = pWb35Rx->RxProcessIndex; ++ if (pWb35Rx->RxOwner[ RxBufferId ]) //Owner by VM ++ break; ++ ++ pWb35Rx->RxProcessIndex++; ++ pWb35Rx->RxProcessIndex %= MAX_USB_RX_BUFFER_NUMBER; ++ ++ pRxBufferAddress = pWb35Rx->pDRx; ++ BufferSize = pWb35Rx->RxBufferSize[ RxBufferId ]; ++ ++ // Parse the bulkin buffer ++ while (BufferSize >= 4) { ++ if ((cpu_to_le32(*(PULONG)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) //Is ending? 921002.9.a ++ break; ++ ++ // Get the R00 R01 first ++ RxDes.R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress); ++ PacketSize = (u16)RxDes.R00.R00_receive_byte_count; ++ RxDes.R01.value = le32_to_cpu(*((PULONG)(pRxBufferAddress+4))); ++ // For new DMA 4k ++ if ((PacketSize & 0x03) > 0) ++ PacketSize -= 4; ++ ++ // Basic check for Rx length. Is length valid? ++ if (PacketSize > MAX_PACKET_SIZE) { ++ #ifdef _PE_RX_DUMP_ ++ WBDEBUG(("Serious ERROR : Rx data size too long, size =%d\n", PacketSize)); ++ #endif ++ ++ pWb35Rx->EP3vm_state = VM_STOP; ++ pWb35Rx->Ep3ErrorCount2++; ++ break; ++ } ++ ++ // Start to process Rx buffer ++// RxDes.Descriptor_ID = RxBufferId; // Due to synchronous indicate, the field doesn't necessary to use. ++ BufferSize -= 8; //subtract 8 byte for 35's USB header length ++ pRxBufferAddress += 8; ++ ++ RxDes.buffer_address[0] = pRxBufferAddress; ++ RxDes.buffer_size[0] = PacketSize; ++ RxDes.buffer_number = 1; ++ RxDes.buffer_start_index = 0; ++ RxDes.buffer_total_size = RxDes.buffer_size[0]; ++ Wb35Rx_adjust(&RxDes); ++ ++ packet_came(pRxBufferAddress, PacketSize); ++ ++ // Move RxBuffer point to the next ++ stmp = PacketSize + 3; ++ stmp &= ~0x03; // 4n alignment ++ pRxBufferAddress += stmp; ++ BufferSize -= stmp; ++ stmp2 += stmp; ++ } ++ ++ // Reclaim resource ++ pWb35Rx->RxOwner[ RxBufferId ] = 1; ++ } while(TRUE); ++ ++ return stmp2; ++} ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35rx_f.h b/drivers/staging/winbond/linux/wb35rx_f.h +new file mode 100644 +index 0000000..daa3e73 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35rx_f.h +@@ -0,0 +1,17 @@ ++//==================================== ++// Interface function declare ++//==================================== ++void Wb35Rx_reset_descriptor( phw_data_t pHwData ); ++unsigned char Wb35Rx_initial( phw_data_t pHwData ); ++void Wb35Rx_destroy( phw_data_t pHwData ); ++void Wb35Rx_stop( phw_data_t pHwData ); ++u16 Wb35Rx_indicate( phw_data_t pHwData ); ++void Wb35Rx_adjust( PDESCRIPTOR pRxDes ); ++void Wb35Rx_start( phw_data_t pHwData ); ++ ++void Wb35Rx( phw_data_t pHwData ); ++void Wb35Rx_Complete( PURB pUrb ); ++ ++ ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35rx_s.h b/drivers/staging/winbond/linux/wb35rx_s.h +new file mode 100644 +index 0000000..53b831f +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35rx_s.h +@@ -0,0 +1,48 @@ ++//============================================================================ ++// wb35rx.h -- ++//============================================================================ ++ ++// Definition for this module used ++#define MAX_USB_RX_BUFFER 4096 // This parameter must be 4096 931130.4.f ++ ++#define MAX_USB_RX_BUFFER_NUMBER ETHERNET_RX_DESCRIPTORS // Maximum 254, 255 is RESERVED ID ++#define RX_INTERFACE 0 // Interface 1 ++#define RX_PIPE 2 // Pipe 3 ++#define MAX_PACKET_SIZE 1600 //1568 // 8 + 1532 + 4 + 24(IV EIV MIC ICV CRC) for check DMA data 931130.4.g ++#define RX_END_TAG 0x0badbeef ++ ++ ++//==================================== ++// Internal variable for module ++//==================================== ++typedef struct _WB35RX ++{ ++ u32 ByteReceived;// For calculating throughput of BulkIn ++ OS_ATOMIC RxFireCounter;// Does Wb35Rx module fire? ++ ++ u8 RxBuffer[ MAX_USB_RX_BUFFER_NUMBER ][ ((MAX_USB_RX_BUFFER+3) & ~0x03 ) ]; ++ u16 RxBufferSize[ ((MAX_USB_RX_BUFFER_NUMBER+1) & ~0x01) ]; ++ u8 RxOwner[ ((MAX_USB_RX_BUFFER_NUMBER+3) & ~0x03 ) ];//Ownership of buffer 0: SW 1:HW ++ ++ u32 RxProcessIndex;//The next index to process ++ u32 RxBufferId; ++ u32 EP3vm_state; ++ ++ u32 rx_halt; // For VM stopping ++ ++ u16 MoreDataSize; ++ u16 PacketSize; ++ ++ u32 CurrentRxBufferId; // For complete routine usage ++ u32 Rx3UrbCancel; ++ ++ u32 LastR1; // For RSSI reporting ++ struct urb * RxUrb; ++ u32 Ep3ErrorCount2; // 20060625.1 Usbd for Rx DMA error count ++ ++ int EP3VM_status; ++ PUCHAR pDRx; ++ ++} WB35RX, *PWB35RX; ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35tx.c b/drivers/staging/winbond/linux/wb35tx.c +new file mode 100644 +index 0000000..cf19c3b +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35tx.c +@@ -0,0 +1,313 @@ ++//============================================================================ ++// Copyright (c) 1996-2002 Winbond Electronic Corporation ++// ++// Module Name: ++// Wb35Tx.c ++// ++// Abstract: ++// Processing the Tx message and put into down layer ++// ++//============================================================================ ++#include "sysdef.h" ++ ++ ++unsigned char ++Wb35Tx_get_tx_buffer(phw_data_t pHwData, PUCHAR *pBuffer ) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ *pBuffer = pWb35Tx->TxBuffer[0]; ++ return TRUE; ++} ++ ++void Wb35Tx_start(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ // Allow only one thread to run into function ++ if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Tx->TxFireCounter) == 1) { ++ pWb35Tx->EP4vm_state = VM_RUNNING; ++ Wb35Tx(pHwData); ++ } else ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter ); ++} ++ ++ ++void Wb35Tx(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ PADAPTER Adapter = pHwData->Adapter; ++ PUCHAR pTxBufferAddress; ++ PMDS pMds = &Adapter->Mds; ++ struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb; ++ int retv; ++ u32 SendIndex; ++ ++ ++ if (pHwData->SurpriseRemove || pHwData->HwStop) ++ goto cleanup; ++ ++ if (pWb35Tx->tx_halt) ++ goto cleanup; ++ ++ // Ownership checking ++ SendIndex = pWb35Tx->TxSendIndex; ++ if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately ++ goto cleanup; ++ ++ pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex]; ++ // ++ // Issuing URB ++ // ++ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev, ++ usb_sndbulkpipe(pHwData->WbUsb.udev, 4), ++ pTxBufferAddress, pMds->TxBufferSize[ SendIndex ], ++ Wb35Tx_complete, pHwData); ++ ++ pWb35Tx->EP4vm_state = VM_RUNNING; ++ retv = wb_usb_submit_urb( pUrb ); ++ if (retv<0) { ++ printk("EP4 Tx Irp sending error\n"); ++ goto cleanup; ++ } ++ ++ // Check if driver needs issue Irp for EP2 ++ pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex]; ++ if (pWb35Tx->TxFillCount > 12) ++ Wb35Tx_EP2VM_start( pHwData ); ++ ++ pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex]; ++ return; ++ ++ cleanup: ++ pWb35Tx->EP4vm_state = VM_STOP; ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter ); ++} ++ ++ ++void Wb35Tx_complete(struct urb * pUrb) ++{ ++ phw_data_t pHwData = pUrb->context; ++ PADAPTER Adapter = (PADAPTER)pHwData->Adapter; ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ PMDS pMds = &Adapter->Mds; ++ ++ printk("wb35: tx complete\n"); ++ // Variable setting ++ pWb35Tx->EP4vm_state = VM_COMPLETED; ++ pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp ++ pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always. ++ pWb35Tx->TxSendIndex++; ++ pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER; ++ ++ do { ++ if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove ++ break; ++ ++ if (pWb35Tx->tx_halt) ++ break; ++ ++ // The URB is completed, check the result ++ if (pWb35Tx->EP4VM_status != 0) { ++ printk("URB submission failed\n"); ++ pWb35Tx->EP4vm_state = VM_STOP; ++ break; // Exit while(FALSE); ++ } ++ ++ Mds_Tx(Adapter); ++ Wb35Tx(pHwData); ++ return; ++ } while(FALSE); ++ ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter ); ++ pWb35Tx->EP4vm_state = VM_STOP; ++} ++ ++void Wb35Tx_reset_descriptor( phw_data_t pHwData ) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ pWb35Tx->TxSendIndex = 0; ++ pWb35Tx->tx_halt = 0; ++} ++ ++unsigned char Wb35Tx_initial(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ pWb35Tx->Tx4Urb = wb_usb_alloc_urb(0); ++ if (!pWb35Tx->Tx4Urb) ++ return FALSE; ++ ++ pWb35Tx->Tx2Urb = wb_usb_alloc_urb(0); ++ if (!pWb35Tx->Tx2Urb) ++ { ++ usb_free_urb( pWb35Tx->Tx4Urb ); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++//====================================================== ++void Wb35Tx_stop(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ // Trying to canceling the Trp of EP2 ++ if (pWb35Tx->EP2vm_state == VM_RUNNING) ++ usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them ++ #ifdef _PE_TX_DUMP_ ++ WBDEBUG(("EP2 Tx stop\n")); ++ #endif ++ ++ // Trying to canceling the Irp of EP4 ++ if (pWb35Tx->EP4vm_state == VM_RUNNING) ++ usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them ++ #ifdef _PE_TX_DUMP_ ++ WBDEBUG(("EP4 Tx stop\n")); ++ #endif ++} ++ ++//====================================================== ++void Wb35Tx_destroy(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ // Wait for VM stop ++ do { ++ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a ++ } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) ); ++ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b ++ ++ if (pWb35Tx->Tx4Urb) ++ usb_free_urb( pWb35Tx->Tx4Urb ); ++ ++ if (pWb35Tx->Tx2Urb) ++ usb_free_urb( pWb35Tx->Tx2Urb ); ++ ++ #ifdef _PE_TX_DUMP_ ++ WBDEBUG(("Wb35Tx_destroy OK\n")); ++ #endif ++} ++ ++void Wb35Tx_CurrentTime(phw_data_t pHwData, u32 TimeCount) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ unsigned char Trigger = FALSE; ++ ++ if (pWb35Tx->TxTimer > TimeCount) ++ Trigger = TRUE; ++ else if (TimeCount > (pWb35Tx->TxTimer+500)) ++ Trigger = TRUE; ++ ++ if (Trigger) { ++ pWb35Tx->TxTimer = TimeCount; ++ Wb35Tx_EP2VM_start( pHwData ); ++ } ++} ++ ++void Wb35Tx_EP2VM_start(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ ++ // Allow only one thread to run into function ++ if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Tx->TxResultCount ) == 1) { ++ pWb35Tx->EP2vm_state = VM_RUNNING; ++ Wb35Tx_EP2VM( pHwData ); ++ } ++ else ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount ); ++} ++ ++ ++void Wb35Tx_EP2VM(phw_data_t pHwData) ++{ ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb; ++ PULONG pltmp = (PULONG)pWb35Tx->EP2_buf; ++ int retv; ++ ++ do { ++ if (pHwData->SurpriseRemove || pHwData->HwStop) ++ break; ++ ++ if (pWb35Tx->tx_halt) ++ break; ++ ++ // ++ // Issuing URB ++ // ++ usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2), ++ pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32); ++ ++ pWb35Tx->EP2vm_state = VM_RUNNING; ++ retv = wb_usb_submit_urb( pUrb ); ++ ++ if(retv < 0) { ++ #ifdef _PE_TX_DUMP_ ++ WBDEBUG(("EP2 Tx Irp sending error\n")); ++ #endif ++ break; ++ } ++ ++ return; ++ ++ } while(FALSE); ++ ++ pWb35Tx->EP2vm_state = VM_STOP; ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount ); ++} ++ ++ ++void Wb35Tx_EP2VM_complete(struct urb * pUrb) ++{ ++ phw_data_t pHwData = pUrb->context; ++ T02_DESCRIPTOR T02, TSTATUS; ++ PADAPTER Adapter = (PADAPTER)pHwData->Adapter; ++ PWB35TX pWb35Tx = &pHwData->Wb35Tx; ++ PULONG pltmp = (PULONG)pWb35Tx->EP2_buf; ++ u32 i; ++ u16 InterruptInLength; ++ ++ ++ // Variable setting ++ pWb35Tx->EP2vm_state = VM_COMPLETED; ++ pWb35Tx->EP2VM_status = pUrb->status; ++ ++ do { ++ // For Linux 2.4. Interrupt will always trigger ++ if( pHwData->SurpriseRemove || pHwData->HwStop ) // Let WbWlanHalt to handle surprise remove ++ break; ++ ++ if( pWb35Tx->tx_halt ) ++ break; ++ ++ //The Urb is completed, check the result ++ if (pWb35Tx->EP2VM_status != 0) { ++ WBDEBUG(("EP2 IoCompleteRoutine return error\n")); ++ pWb35Tx->EP2vm_state= VM_STOP; ++ break; // Exit while(FALSE); ++ } ++ ++ // Update the Tx result ++ InterruptInLength = pUrb->actual_length; ++ // Modify for minimum memory access and DWORD alignment. ++ T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0] ++ InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable ++ InterruptInLength >>= 2; // InterruptInLength/4 ++ for (i=1; i<=InterruptInLength; i++) { ++ T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24); ++ ++ TSTATUS.value = T02.value; //20061009 anson's endian ++ Mds_SendComplete( Adapter, &TSTATUS ); ++ T02.value = cpu_to_le32(pltmp[i]) >> 8; ++ } ++ ++ return; ++ } while(FALSE); ++ ++ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount ); ++ pWb35Tx->EP2vm_state = VM_STOP; ++} ++ +diff --git a/drivers/staging/winbond/linux/wb35tx_f.h b/drivers/staging/winbond/linux/wb35tx_f.h +new file mode 100644 +index 0000000..7705a84 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35tx_f.h +@@ -0,0 +1,20 @@ ++//==================================== ++// Interface function declare ++//==================================== ++unsigned char Wb35Tx_initial( phw_data_t pHwData ); ++void Wb35Tx_destroy( phw_data_t pHwData ); ++unsigned char Wb35Tx_get_tx_buffer( phw_data_t pHwData, PUCHAR *pBuffer ); ++ ++void Wb35Tx_EP2VM( phw_data_t pHwData ); ++void Wb35Tx_EP2VM_start( phw_data_t pHwData ); ++void Wb35Tx_EP2VM_complete( PURB purb ); ++ ++void Wb35Tx_start( phw_data_t pHwData ); ++void Wb35Tx_stop( phw_data_t pHwData ); ++void Wb35Tx( phw_data_t pHwData ); ++void Wb35Tx_complete( PURB purb ); ++void Wb35Tx_reset_descriptor( phw_data_t pHwData ); ++ ++void Wb35Tx_CurrentTime( phw_data_t pHwData, u32 TimeCount ); ++ ++ +diff --git a/drivers/staging/winbond/linux/wb35tx_s.h b/drivers/staging/winbond/linux/wb35tx_s.h +new file mode 100644 +index 0000000..ac43257 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wb35tx_s.h +@@ -0,0 +1,47 @@ ++//==================================== ++// IS89C35 Tx related definition ++//==================================== ++#define TX_INTERFACE 0 // Interface 1 ++#define TX_PIPE 3 // endpoint 4 ++#define TX_INTERRUPT 1 // endpoint 2 ++#define MAX_INTERRUPT_LENGTH 64 // It must be 64 for EP2 hardware ++ ++ ++ ++//==================================== ++// Internal variable for module ++//==================================== ++ ++ ++typedef struct _WB35TX ++{ ++ // For Tx buffer ++ u8 TxBuffer[ MAX_USB_TX_BUFFER_NUMBER ][ MAX_USB_TX_BUFFER ]; ++ ++ // For Interrupt pipe ++ u8 EP2_buf[MAX_INTERRUPT_LENGTH]; ++ ++ OS_ATOMIC TxResultCount;// For thread control of EP2 931130.4.m ++ OS_ATOMIC TxFireCounter;// For thread control of EP4 931130.4.n ++ u32 ByteTransfer; ++ ++ u32 TxSendIndex;// The next index of Mds array to be sent ++ u32 EP2vm_state; // for EP2vm state ++ u32 EP4vm_state; // for EP4vm state ++ u32 tx_halt; // Stopping VM ++ ++ struct urb * Tx4Urb; ++ struct urb * Tx2Urb; ++ ++ int EP2VM_status; ++ int EP4VM_status; ++ ++ u32 TxFillCount; // 20060928 ++ u32 TxTimer; // 20060928 Add if sending packet not great than 13 ++ ++} WB35TX, *PWB35TX; ++ ++ ++ ++ ++ +diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c +new file mode 100644 +index 0000000..cbad5fb +--- /dev/null ++++ b/drivers/staging/winbond/linux/wbusb.c +@@ -0,0 +1,404 @@ ++/* ++ * Copyright 2008 Pavel Machek ++ * ++ * Distribute under GPLv2. ++ */ ++#include "sysdef.h" ++#include ++ ++ ++MODULE_AUTHOR( DRIVER_AUTHOR ); ++MODULE_DESCRIPTION( DRIVER_DESC ); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("0.1"); ++ ++ ++//============================================================ ++// vendor ID and product ID can into here for others ++//============================================================ ++static struct usb_device_id Id_Table[] = ++{ ++ {USB_DEVICE( 0x0416, 0x0035 )}, ++ {USB_DEVICE( 0x18E8, 0x6201 )}, ++ {USB_DEVICE( 0x18E8, 0x6206 )}, ++ {USB_DEVICE( 0x18E8, 0x6217 )}, ++ {USB_DEVICE( 0x18E8, 0x6230 )}, ++ {USB_DEVICE( 0x18E8, 0x6233 )}, ++ {USB_DEVICE( 0x1131, 0x2035 )}, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(usb, Id_Table); ++ ++static struct usb_driver wb35_driver = { ++ .name = "w35und", ++ .probe = wb35_probe, ++ .disconnect = wb35_disconnect, ++ .id_table = Id_Table, ++}; ++ ++static const struct ieee80211_rate wbsoft_rates[] = { ++ { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, ++}; ++ ++static const struct ieee80211_channel wbsoft_channels[] = { ++ { .center_freq = 2412}, ++}; ++ ++int wbsoft_enabled; ++struct ieee80211_hw *my_dev; ++PADAPTER my_adapter; ++ ++static int wbsoft_add_interface(struct ieee80211_hw *dev, ++ struct ieee80211_if_init_conf *conf) ++{ ++ printk("wbsoft_add interface called\n"); ++ return 0; ++} ++ ++static void wbsoft_remove_interface(struct ieee80211_hw *dev, ++ struct ieee80211_if_init_conf *conf) ++{ ++ printk("wbsoft_remove interface called\n"); ++} ++ ++static int wbsoft_nop(void) ++{ ++ printk("wbsoft_nop called\n"); ++ return 0; ++} ++ ++static void wbsoft_configure_filter(struct ieee80211_hw *dev, ++ unsigned int changed_flags, ++ unsigned int *total_flags, ++ int mc_count, struct dev_mc_list *mclist) ++{ ++ unsigned int bit_nr, new_flags; ++ u32 mc_filter[2]; ++ int i; ++ ++ new_flags = 0; ++ ++ if (*total_flags & FIF_PROMISC_IN_BSS) { ++ new_flags |= FIF_PROMISC_IN_BSS; ++ mc_filter[1] = mc_filter[0] = ~0; ++ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { ++ new_flags |= FIF_ALLMULTI; ++ mc_filter[1] = mc_filter[0] = ~0; ++ } else { ++ mc_filter[1] = mc_filter[0] = 0; ++ for (i = 0; i < mc_count; i++) { ++ if (!mclist) ++ break; ++ printk("Should call ether_crc here\n"); ++ //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; ++ bit_nr = 0; ++ ++ bit_nr &= 0x3F; ++ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); ++ mclist = mclist->next; ++ } ++ } ++ ++ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; ++ ++ *total_flags = new_flags; ++} ++ ++static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb, ++ struct ieee80211_tx_control *control) ++{ ++ char *buffer = kmalloc(skb->len, GFP_ATOMIC); ++ printk("Sending frame %d bytes\n", skb->len); ++ memcpy(buffer, skb->data, skb->len); ++ if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT)) ++ printk("frame sent ok (%d bytes)?\n", skb->len); ++ return NETDEV_TX_OK; ++} ++ ++ ++static int wbsoft_start(struct ieee80211_hw *dev) ++{ ++ wbsoft_enabled = 1; ++ printk("wbsoft_start called\n"); ++ return 0; ++} ++ ++static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) ++{ ++ ChanInfo ch; ++ printk("wbsoft_config called\n"); ++ ++ ch.band = 1; ++ ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ ++ ++ ++ hal_set_current_channel(&my_adapter->sHwData, ch); ++ hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int); ++// hal_set_cap_info(&my_adapter->sHwData, ?? ); ++// hal_set_ssid(phw_data_t pHwData, PUCHAR pssid, u8 ssid_len); ?? ++ hal_set_accept_broadcast(&my_adapter->sHwData, 1); ++ hal_set_accept_promiscuous(&my_adapter->sHwData, 1); ++ hal_set_accept_multicast(&my_adapter->sHwData, 1); ++ hal_set_accept_beacon(&my_adapter->sHwData, 1); ++ hal_set_radio_mode(&my_adapter->sHwData, 0); ++ //hal_set_antenna_number( phw_data_t pHwData, u8 number ) ++ //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex) ++ ++ ++// hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? ++ ++//void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates, ++// u8 length, unsigned char basic_rate_set) ++ ++ return 0; ++} ++ ++static int wbsoft_config_interface(struct ieee80211_hw *dev, ++ struct ieee80211_vif *vif, ++ struct ieee80211_if_conf *conf) ++{ ++ printk("wbsoft_config_interface called\n"); ++ return 0; ++} ++ ++static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) ++{ ++ printk("wbsoft_get_tsf called\n"); ++ return 0; ++} ++ ++static const struct ieee80211_ops wbsoft_ops = { ++ .tx = wbsoft_tx, ++ .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */ ++ .stop = wbsoft_nop, ++ .add_interface = wbsoft_add_interface, ++ .remove_interface = wbsoft_remove_interface, ++ .config = wbsoft_config, ++ .config_interface = wbsoft_config_interface, ++ .configure_filter = wbsoft_configure_filter, ++ .get_stats = wbsoft_nop, ++ .get_tx_stats = wbsoft_nop, ++ .get_tsf = wbsoft_get_tsf, ++// conf_tx: hal_set_cwmin()/hal_set_cwmax; ++}; ++ ++struct wbsoft_priv { ++}; ++ ++ ++int __init wb35_init(void) ++{ ++ printk("[w35und]driver init\n"); ++ return usb_register(&wb35_driver); ++} ++ ++void __exit wb35_exit(void) ++{ ++ printk("[w35und]driver exit\n"); ++ usb_deregister( &wb35_driver ); ++} ++ ++module_init(wb35_init); ++module_exit(wb35_exit); ++ ++// Usb kernel subsystem will call this function when a new device is plugged into. ++int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) ++{ ++ PADAPTER Adapter; ++ PWBLINUX pWbLinux; ++ PWBUSB pWbUsb; ++ struct usb_host_interface *interface; ++ struct usb_endpoint_descriptor *endpoint; ++ int i, ret = -1; ++ u32 ltmp; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ ++ usb_get_dev(udev); ++ ++ printk("[w35und]wb35_probe ->\n"); ++ ++ do { ++ for (i=0; i<(sizeof(Id_Table)/sizeof(struct usb_device_id)); i++ ) { ++ if ((udev->descriptor.idVendor == Id_Table[i].idVendor) && ++ (udev->descriptor.idProduct == Id_Table[i].idProduct)) { ++ printk("[w35und]Found supported hardware\n"); ++ break; ++ } ++ } ++ if ((i == (sizeof(Id_Table)/sizeof(struct usb_device_id)))) { ++ #ifdef _PE_USB_INI_DUMP_ ++ WBDEBUG(("[w35und] This is not the one we are interested about\n")); ++ #endif ++ return -ENODEV; ++ } ++ ++ // 20060630.2 Check the device if it already be opened ++ ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), ++ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, ++ 0x0, 0x400, <mp, 4, HZ*100 ); ++ if( ret < 0 ) ++ break; ++ ++ ltmp = cpu_to_le32(ltmp); ++ if (ltmp) // Is already initialized? ++ break; ++ ++ ++ Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL); ++ ++ my_adapter = Adapter; ++ pWbLinux = &Adapter->WbLinux; ++ pWbUsb = &Adapter->sHwData.WbUsb; ++ pWbUsb->udev = udev; ++ ++ interface = intf->cur_altsetting; ++ endpoint = &interface->endpoint[0].desc; ++ ++ if (endpoint[2].wMaxPacketSize == 512) { ++ printk("[w35und] Working on USB 2.0\n"); ++ pWbUsb->IsUsb20 = 1; ++ } ++ ++ if (!WbWLanInitialize(Adapter)) { ++ printk("[w35und]WbWLanInitialize fail\n"); ++ break; ++ } ++ ++ { ++ struct wbsoft_priv *priv; ++ struct ieee80211_hw *dev; ++ int res; ++ ++ dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); ++ ++ if (!dev) { ++ printk("w35und: ieee80211 alloc failed\n" ); ++ BUG(); ++ } ++ ++ my_dev = dev; ++ ++ SET_IEEE80211_DEV(dev, &udev->dev); ++ { ++ phw_data_t pHwData = &Adapter->sHwData; ++ unsigned char dev_addr[MAX_ADDR_LEN]; ++ hal_get_permanent_address(pHwData, dev_addr); ++ SET_IEEE80211_PERM_ADDR(dev, dev_addr); ++ } ++ ++ ++ dev->extra_tx_headroom = 12; /* FIXME */ ++ dev->flags = 0; ++ ++ dev->channel_change_time = 1000; ++// dev->max_rssi = 100; ++ ++ dev->queues = 1; ++ ++ static struct ieee80211_supported_band band; ++ ++ band.channels = wbsoft_channels; ++ band.n_channels = ARRAY_SIZE(wbsoft_channels); ++ band.bitrates = wbsoft_rates; ++ band.n_bitrates = ARRAY_SIZE(wbsoft_rates); ++ ++ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band; ++#if 0 ++ wbsoft_modes[0].num_channels = 1; ++ wbsoft_modes[0].channels = wbsoft_channels; ++ wbsoft_modes[0].mode = MODE_IEEE80211B; ++ wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates); ++ wbsoft_modes[0].rates = wbsoft_rates; ++ ++ res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]); ++ BUG_ON(res); ++#endif ++ ++ res = ieee80211_register_hw(dev); ++ BUG_ON(res); ++ } ++ ++ usb_set_intfdata( intf, Adapter ); ++ ++ printk("[w35und] _probe OK\n"); ++ return 0; ++ ++ } while(FALSE); ++ ++ return -ENOMEM; ++} ++ ++void packet_came(char *pRxBufferAddress, int PacketSize) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_rx_status rx_status = {0}; ++ ++ if (!wbsoft_enabled) ++ return; ++ ++ skb = dev_alloc_skb(PacketSize); ++ if (!skb) { ++ printk("Not enough memory for packet, FIXME\n"); ++ return; ++ } ++ ++ memcpy(skb_put(skb, PacketSize), ++ pRxBufferAddress, ++ PacketSize); ++ ++/* ++ rx_status.rate = 10; ++ rx_status.channel = 1; ++ rx_status.freq = 12345; ++ rx_status.phymode = MODE_IEEE80211B; ++*/ ++ ++ ieee80211_rx_irqsafe(my_dev, skb, &rx_status); ++} ++ ++unsigned char ++WbUsb_initial(phw_data_t pHwData) ++{ ++ return 1; ++} ++ ++ ++void ++WbUsb_destroy(phw_data_t pHwData) ++{ ++} ++ ++int wb35_open(struct net_device *netdev) ++{ ++ PADAPTER Adapter = (PADAPTER)netdev->priv; ++ phw_data_t pHwData = &Adapter->sHwData; ++ ++ netif_start_queue(netdev); ++ ++ //TODO : put here temporarily ++ hal_set_accept_broadcast(pHwData, 1); // open accept broadcast ++ ++ return 0; ++} ++ ++int wb35_close(struct net_device *netdev) ++{ ++ netif_stop_queue(netdev); ++ return 0; ++} ++ ++void wb35_disconnect(struct usb_interface *intf) ++{ ++ PWBLINUX pWbLinux; ++ PADAPTER Adapter = usb_get_intfdata(intf); ++ usb_set_intfdata(intf, NULL); ++ ++ pWbLinux = &Adapter->WbLinux; ++ ++ // Card remove ++ WbWlanHalt(Adapter); ++ ++} ++ ++ +diff --git a/drivers/staging/winbond/linux/wbusb_f.h b/drivers/staging/winbond/linux/wbusb_f.h +new file mode 100644 +index 0000000..cae29e1 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wbusb_f.h +@@ -0,0 +1,34 @@ ++//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// Copyright (c) 1996-2004 Winbond Electronic Corporation ++// ++// Module Name: ++// wbusb_f.h ++// ++// Abstract: ++// Linux driver. ++// ++// Author: ++// ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++int wb35_open(struct net_device *netdev); ++int wb35_close(struct net_device *netdev); ++unsigned char WbUsb_initial(phw_data_t pHwData); ++void WbUsb_destroy(phw_data_t pHwData); ++unsigned char WbWLanInitialize(PADAPTER Adapter); ++#define WbUsb_Stop( _A ) ++ ++int wb35_probe(struct usb_interface *intf,const struct usb_device_id *id_table); ++void wb35_disconnect(struct usb_interface *intf); ++ ++ ++#define wb_usb_submit_urb(_A) usb_submit_urb(_A, GFP_ATOMIC) ++#define wb_usb_alloc_urb(_A) usb_alloc_urb(_A, GFP_ATOMIC) ++ ++#define WbUsb_CheckForHang( _P ) ++#define WbUsb_DetectStart( _P, _I ) ++ ++ ++ ++ ++ +diff --git a/drivers/staging/winbond/linux/wbusb_s.h b/drivers/staging/winbond/linux/wbusb_s.h +new file mode 100644 +index 0000000..d5c1d53 +--- /dev/null ++++ b/drivers/staging/winbond/linux/wbusb_s.h +@@ -0,0 +1,42 @@ ++//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// Copyright (c) 1996-2004 Winbond Electronic Corporation ++// ++// Module Name: ++// wbusb_s.h ++// ++// Abstract: ++// Linux driver. ++// ++// Author: ++// ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++#define OS_SLEEP( _MT ) { set_current_state(TASK_INTERRUPTIBLE); \ ++ schedule_timeout( _MT*HZ/1000000 ); } ++ ++ ++//--------------------------------------------------------------------------- ++// RW_CONTEXT -- ++// ++// Used to track driver-generated io irps ++//--------------------------------------------------------------------------- ++typedef struct _RW_CONTEXT ++{ ++ void* pHwData; ++ PURB pUrb; ++ void* pCallBackFunctionParameter; ++} RW_CONTEXT, *PRW_CONTEXT; ++ ++ ++ ++ ++#define DRIVER_AUTHOR "Original by: Jeff Lee Adapted to 2.6.x by Costantino Leandro (Rxart Desktop) " ++#define DRIVER_DESC "IS89C35 802.11bg WLAN USB Driver" ++ ++ ++ ++typedef struct _WBUSB { ++ u32 IsUsb20; ++ struct usb_device *udev; ++ u32 DetectCount; ++} WBUSB, *PWBUSB; +diff --git a/drivers/staging/winbond/localpara.h b/drivers/staging/winbond/localpara.h +new file mode 100644 +index 0000000..268cf91 +--- /dev/null ++++ b/drivers/staging/winbond/localpara.h +@@ -0,0 +1,275 @@ ++//============================================================= ++// LocalPara.h - ++//============================================================= ++//Define the local ability ++ ++#define LOCAL_DEFAULT_BEACON_PERIOD 100 //ms ++#define LOCAL_DEFAULT_ATIM_WINDOW 0 ++#define LOCAL_DEFAULT_ERP_CAPABILITY 0x0431 //0x0001: ESS ++ //0x0010: Privacy ++ //0x0020: short preamble ++ //0x0400: short slot time ++#define LOCAL_DEFAULT_LISTEN_INTERVAL 5 ++ ++//#define LOCAL_DEFAULT_24_CHANNEL_NUM 11 // channel 1..11 ++#define LOCAL_DEFAULT_24_CHANNEL_NUM 13 // channel 1..13 ++#define LOCAL_DEFAULT_5_CHANNEL_NUM 8 // channel 36..64 ++ ++#define LOCAL_USA_24_CHANNEL_NUM 11 ++#define LOCAL_USA_5_CHANNEL_NUM 12 ++#define LOCAL_EUROPE_24_CHANNEL_NUM 13 ++#define LOCAL_EUROPE_5_CHANNEL_NUM 19 ++#define LOCAL_JAPAN_24_CHANNEL_NUM 14 ++#define LOCAL_JAPAN_5_CHANNEL_NUM 11 ++#define LOCAL_UNKNOWN_24_CHANNEL_NUM 14 ++#define LOCAL_UNKNOWN_5_CHANNEL_NUM 34 //not include 165 ++ ++ ++#define psLOCAL (&(Adapter->sLocalPara)) ++ ++#define MODE_802_11_BG 0 ++#define MODE_802_11_A 1 ++#define MODE_802_11_ABG 2 ++#define MODE_802_11_BG_IBSS 3 ++#define MODE_802_11_B 4 ++#define MODE_AUTO 255 ++ ++#define BAND_TYPE_DSSS 0 ++#define BAND_TYPE_OFDM_24 1 ++#define BAND_TYPE_OFDM_5 2 ++ ++//refer Bitmap2RateValue table ++#define LOCAL_ALL_SUPPORTED_RATES_BITMAP 0x130c1a66 //the bitmap value of all the H/W supported rates ++ //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define LOCAL_OFDM_SUPPORTED_RATES_BITMAP 0x130c1240 //the bitmap value of all the H/W supported rates ++ //except to non-OFDM rates ++ //6, 9, 12, 18, 24, 36, 48, 54 ++ ++#define LOCAL_11B_SUPPORTED_RATE_BITMAP 0x826 ++#define LOCAL_11B_BASIC_RATE_BITMAP 0x826 ++#define LOCAL_11B_OPERATION_RATE_BITMAP 0x826 ++#define LOCAL_11G_BASIC_RATE_BITMAP 0x826 //1, 2, 5.5, 11 ++#define LOCAL_11G_OPERATION_RATE_BITMAP 0x130c1240 //6, 9, 12, 18, 24, 36, 48, 54 ++#define LOCAL_11A_BASIC_RATE_BITMAP 0x01001040 //6, 12, 24 ++#define LOCAL_11A_OPERATION_RATE_BITMAP 0x120c0200 //9, 18, 36, 48, 54 ++ ++ ++ ++#define PWR_ACTIVE 0 ++#define PWR_SAVE 1 ++#define PWR_TX_IDLE_CYCLE 6 ++ ++//bPreambleMode and bSlotTimeMode ++#define AUTO_MODE 0 ++#define LONG_MODE 1 ++ ++//Region definition ++#define REGION_AUTO 0xff ++#define REGION_UNKNOWN 0 ++#define REGION_EUROPE 1 //ETSI ++#define REGION_JAPAN 2 //MKK ++#define REGION_USA 3 //FCC ++#define REGION_FRANCE 4 //FRANCE ++#define REGION_SPAIN 5 //SPAIN ++#define REGION_ISRAEL 6 //ISRAEL ++//#define REGION_CANADA 7 //IC ++ ++#define MAX_BSS_DESCRIPT_ELEMENT 32 ++#define MAX_PMKID_CandidateList 16 ++ ++//High byte : Event number, low byte : reason ++//Event definition ++//-- SME/MLME event ++#define EVENT_RCV_DEAUTH 0x0100 ++#define EVENT_JOIN_FAIL 0x0200 ++#define EVENT_AUTH_FAIL 0x0300 ++#define EVENT_ASSOC_FAIL 0x0400 ++#define EVENT_LOST_SIGNAL 0x0500 ++#define EVENT_BSS_DESCRIPT_LACK 0x0600 ++#define EVENT_COUNTERMEASURE 0x0700 ++#define EVENT_JOIN_FILTER 0x0800 ++//-- TX/RX event ++#define EVENT_RX_BUFF_UNAVAILABLE 0x4100 ++ ++#define EVENT_CONNECT 0x8100 ++#define EVENT_DISCONNECT 0x8200 ++#define EVENT_SCAN_REQ 0x8300 ++ ++//Reason of Event ++#define EVENT_REASON_FILTER_BASIC_RATE 0x0001 ++#define EVENT_REASON_FILTER_PRIVACY 0x0002 ++#define EVENT_REASON_FILTER_AUTH_MODE 0x0003 ++#define EVENT_REASON_TIMEOUT 0x00ff ++ ++// 20061108 WPS IE buffer ++#define MAX_IE_APPEND_SIZE 256 + 4 // Due to [E id][Length][OUI][Data] may 257 bytes ++ ++typedef struct _EVENTLOG ++{ ++ u16 Count; //Total count from start ++ u16 index; //Buffer index, 0 ~ 63 ++ u32 EventValue[64]; //BYTE 3~2 : count, BYTE 1 : Event, BYTE 0 : reason ++} Event_Log, *pEvent_Log; ++ ++typedef struct _ChanInfo ++{ ++ u8 band; ++ u8 ChanNo; ++} ChanInfo, *pChanInfo; ++ ++typedef struct _CHAN_LIST ++{ ++ u16 Count; ++ ChanInfo Channel[50]; // 100B ++} CHAN_LIST, *psCHAN_LIST; ++ ++typedef struct _RadioOff ++{ ++ u8 boHwRadioOff; ++ u8 boSwRadioOff; ++} RadioOff, *psRadioOff; ++ ++//=========================================================================== ++typedef struct LOCAL_PARA ++{ ++ u8 PermanentAddress[ MAC_ADDR_LENGTH + 2 ]; // read from EPROM, manufacture set for each NetCard ++ u8 ThisMacAddress[ MAC_ADDR_LENGTH + 2 ]; // the driver will use actually. ++ ++ u32 MTUsize; // Ind to Uplayer, Max transmission unit size ++ ++ u8 region_INF; //region setting from INF ++ u8 region; //real region setting of the device ++ u8 Reserved_1[2]; ++ ++ //// power-save variables ++ u8 iPowerSaveMode; // 0 indicates it is on, 1 indicates it is off ++ u8 ShutDowned; ++ u8 ATIMmode; ++ u8 ExcludeUnencrypted; ++ ++ u16 CheckCountForPS; //Unit ime count for the decision to enter PS mode ++ u8 boHasTxActivity; //tx activity has occurred ++ u8 boMacPsValid; //Power save mode obtained from H/W is valid or not ++ ++ //// Rate ++ u8 TxRateMode; // Initial, input from Registry, may be updated by GUI ++ //Tx Rate Mode: auto(DTO on), max, 1M, 2M, .. ++ u8 CurrentTxRate; // The current Tx rate ++ u8 CurrentTxRateForMng; // The current Tx rate for management frames ++ // It will be decided before connection succeeds. ++ u8 CurrentTxFallbackRate; ++ ++ //for Rate handler ++ u8 BRateSet[32]; //basic rate set ++ u8 SRateSet[32]; //support rate set ++ ++ u8 NumOfBRate; ++ u8 NumOfSRate; ++ u8 NumOfDsssRateInSRate; //number of DSSS rates in supported rate set ++ u8 reserved1; ++ ++ u32 dwBasicRateBitmap; //bit map of basic rates ++ u32 dwSupportRateBitmap; //bit map of all support rates including ++ //basic and operational rates ++ ++ ////For SME/MLME handler ++ u16 wOldSTAindex; // valid when boHandover=TRUE, store old connected STA index ++ u16 wConnectedSTAindex; // Index of peerly connected AP or IBSS in ++ // the descriptionset. ++ u16 Association_ID; // The Association ID in the (Re)Association ++ // Response frame. ++ u16 ListenInterval; // The listen interval when SME invoking MLME_ ++ // (Re)Associate_Request(). ++ ++ RadioOff RadioOffStatus; ++ u8 Reserved0[2]; ++ ++ u8 boMsRadioOff; // Ndis demands to be true when set Disassoc. OID and be false when set SSID OID. ++ u8 boAntennaDiversity; //TRUE/ON or FALSE/OFF ++ u8 bAntennaNo; //which antenna ++ u8 bConnectFlag; //the connect status flag for roaming task ++ ++ u8 RoamStatus; ++ u8 reserved7[3]; ++ ++ ChanInfo CurrentChan; //Current channel no. and channel band. It may be changed by scanning. ++ u8 boHandover; // Roaming, Hnadover to other AP. ++ u8 boCCAbusy; ++ ++ u16 CWMax; // It may not be the real value that H/W used ++ u8 CWMin; // 255: set according to 802.11 spec. ++ u8 reserved2; ++ ++ //11G: ++ u8 bMacOperationMode; // operation in 802.11b or 802.11g ++ u8 bSlotTimeMode; //AUTO, s32 ++ u8 bPreambleMode; //AUTO, s32 ++ u8 boNonERPpresent; ++ ++ u8 boProtectMechanism; // H/W will take the necessary action based on this variable ++ u8 boShortPreamble; // H/W will take the necessary action based on this variable ++ u8 boShortSlotTime; // H/W will take the necessary action based on this variable ++ u8 reserved_3; ++ ++ u32 RSN_IE_Bitmap; //added by WS ++ u32 RSN_OUI_Type; //added by WS ++ ++ //For the BSSID ++ u8 HwBssid[MAC_ADDR_LENGTH + 2]; ++ u32 HwBssidValid; ++ ++ //For scan list ++ u8 BssListCount; //Total count of valid descriptor indexes ++ u8 boReceiveUncorrectInfo; //important settings in beacon/probe resp. have been changed ++ u8 NoOfJoinerInIbss; ++ u8 reserved_4; ++ ++ u8 BssListIndex[ (MAX_BSS_DESCRIPT_ELEMENT+3) & ~0x03 ]; //Store the valid descriptor indexes obtained from scannings ++ u8 JoinerInIbss[ (MAX_BSS_DESCRIPT_ELEMENT+3) & ~0x03 ]; //save the BssDescriptor index in this ++ //IBSS. The index 0 is local descriptor ++ //(psLOCAL->wConnectedSTAindex). ++ //If CONNECTED : NoOfJoinerInIbss >=2 ++ // else : NoOfJoinerInIbss <=1 ++ ++ //// General Statistics, count at Rx_handler or Tx_callback interrupt handler ++ u64 GS_XMIT_OK; // Good Frames Transmitted ++ u64 GS_RCV_OK; // Good Frames Received ++ u32 GS_RCV_ERROR; // Frames received with crc error ++ u32 GS_XMIT_ERROR; // Bad Frames Transmitted ++ u32 GS_RCV_NO_BUFFER; // Receive Buffer underrun ++ u32 GS_XMIT_ONE_COLLISION; // one collision ++ u32 GS_XMIT_MORE_COLLISIONS;// more collisions ++ ++ //================================================================ ++ // Statistics (no matter whether it had done successfully) -wkchen ++ //================================================================ ++ u32 _NumRxMSDU; ++ u32 _NumTxMSDU; ++ u32 _dot11WEPExcludedCount; ++ u32 _dot11WEPUndecryptableCount; ++ u32 _dot11FrameDuplicateCount; ++ ++ ChanInfo IbssChanSetting; // 2B. Start IBSS Channel setting by registry or WWU. ++ u8 reserved_5[2]; //It may not be used after considering RF type, ++ //region and modulation type. ++ ++ CHAN_LIST sSupportChanList; // 86B. It will be obtained according to RF type and region ++ u8 reserved_6[2]; //two variables are for wep key error detection added by ws 02/02/04 ++ ++ u32 bWepKeyError; ++ u32 bToSelfPacketReceived; ++ u32 WepKeyDetectTimerCount; ++ ++ Event_Log EventLog; ++ ++ u16 SignalLostTh; ++ u16 SignalRoamTh; ++ ++ // 20061108 WPS IE Append ++ u8 IE_Append_data[MAX_IE_APPEND_SIZE]; ++ u16 IE_Append_size; ++ u16 reserved_7; ++ ++} WB_LOCALDESCRIPT, *PWB_LOCALDESCRIPT; ++ ++ +diff --git a/drivers/staging/winbond/mac_structures.h b/drivers/staging/winbond/mac_structures.h +new file mode 100644 +index 0000000..031d2cb +--- /dev/null ++++ b/drivers/staging/winbond/mac_structures.h +@@ -0,0 +1,670 @@ ++//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// MAC_Structures.h ++// ++// This file contains the definitions and data structures used by SW-MAC. ++// ++// Revision Histoy ++//================= ++// 0.1 2002 UN00 ++// 0.2 20021004 PD43 CCLiu6 ++// 20021018 PD43 CCLiu6 ++// Add enum_TxRate type ++// Modify enum_STAState type ++// 0.3 20021023 PE23 CYLiu update MAC session struct ++// 20021108 ++// 20021122 PD43 Austin ++// Deleted some unused. ++// 20021129 PD43 Austin ++// 20030617 increase the 802.11g definition ++//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++#ifndef _MAC_Structures_H_ ++#define _MAC_Structures_H_ ++ ++ ++//========================================================= ++// Some miscellaneous definitions ++//----- ++#define MAX_CHANNELS 30 ++#define MAC_ADDR_LENGTH 6 ++#define MAX_WEP_KEY_SIZE 16 // 128 bits ++#define MAX_802_11_FRAGMENT_NUMBER 10 // By spec ++ ++//======================================================== ++// 802.11 Frame define ++//----- ++#define MASK_PROTOCOL_VERSION_TYPE 0x0F ++#define MASK_FRAGMENT_NUMBER 0x000F ++#define SEQUENCE_NUMBER_SHIFT 4 ++#define DIFFER_11_TO_3 18 ++#define DOT_11_MAC_HEADER_SIZE 24 ++#define DOT_11_SNAP_SIZE 6 ++#define DOT_11_DURATION_OFFSET 2 ++#define DOT_11_SEQUENCE_OFFSET 22 //Sequence control offset ++#define DOT_11_TYPE_OFFSET 30 //The start offset of 802.11 Frame// ++#define DOT_11_DATA_OFFSET 24 ++#define DOT_11_DA_OFFSET 4 ++#define DOT_3_TYPE_ARP 0x80F3 ++#define DOT_3_TYPE_IPX 0x8137 ++#define DOT_3_TYPE_OFFSET 12 ++ ++ ++#define ETHERNET_HEADER_SIZE 14 ++#define MAX_ETHERNET_PACKET_SIZE 1514 ++ ++ ++//----- management : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) ++#define MAC_SUBTYPE_MNGMNT_ASSOC_REQUEST 0x00 ++#define MAC_SUBTYPE_MNGMNT_ASSOC_RESPONSE 0x10 ++#define MAC_SUBTYPE_MNGMNT_REASSOC_REQUEST 0x20 ++#define MAC_SUBTYPE_MNGMNT_REASSOC_RESPONSE 0x30 ++#define MAC_SUBTYPE_MNGMNT_PROBE_REQUEST 0x40 ++#define MAC_SUBTYPE_MNGMNT_PROBE_RESPONSE 0x50 ++#define MAC_SUBTYPE_MNGMNT_BEACON 0x80 ++#define MAC_SUBTYPE_MNGMNT_ATIM 0x90 ++#define MAC_SUBTYPE_MNGMNT_DISASSOCIATION 0xA0 ++#define MAC_SUBTYPE_MNGMNT_AUTHENTICATION 0xB0 ++#define MAC_SUBTYPE_MNGMNT_DEAUTHENTICATION 0xC0 ++ ++//----- control : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) ++#define MAC_SUBTYPE_CONTROL_PSPOLL 0xA4 ++#define MAC_SUBTYPE_CONTROL_RTS 0xB4 ++#define MAC_SUBTYPE_CONTROL_CTS 0xC4 ++#define MAC_SUBTYPE_CONTROL_ACK 0xD4 ++#define MAC_SUBTYPE_CONTROL_CFEND 0xE4 ++#define MAC_SUBTYPE_CONTROL_CFEND_CFACK 0xF4 ++ ++//----- data : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7) ++#define MAC_SUBTYPE_DATA 0x08 ++#define MAC_SUBTYPE_DATA_CFACK 0x18 ++#define MAC_SUBTYPE_DATA_CFPOLL 0x28 ++#define MAC_SUBTYPE_DATA_CFACK_CFPOLL 0x38 ++#define MAC_SUBTYPE_DATA_NULL 0x48 ++#define MAC_SUBTYPE_DATA_CFACK_NULL 0x58 ++#define MAC_SUBTYPE_DATA_CFPOLL_NULL 0x68 ++#define MAC_SUBTYPE_DATA_CFACK_CFPOLL_NULL 0x78 ++ ++//----- Frame Type of Bits (2, 3) ++#define MAC_TYPE_MANAGEMENT 0x00 ++#define MAC_TYPE_CONTROL 0x04 ++#define MAC_TYPE_DATA 0x08 ++ ++//----- definitions for Management Frame Element ID (1 BYTE) ++#define ELEMENT_ID_SSID 0 ++#define ELEMENT_ID_SUPPORTED_RATES 1 ++#define ELEMENT_ID_FH_PARAMETER_SET 2 ++#define ELEMENT_ID_DS_PARAMETER_SET 3 ++#define ELEMENT_ID_CF_PARAMETER_SET 4 ++#define ELEMENT_ID_TIM 5 ++#define ELEMENT_ID_IBSS_PARAMETER_SET 6 ++// 7~15 reserverd ++#define ELEMENT_ID_CHALLENGE_TEXT 16 ++// 17~31 reserved for challenge text extension ++// 32~255 reserved ++//-- 11G -- ++#define ELEMENT_ID_ERP_INFORMATION 42 ++#define ELEMENT_ID_EXTENDED_SUPPORTED_RATES 50 ++ ++//-- WPA -- ++ ++#define ELEMENT_ID_RSN_WPA 221 ++#ifdef _WPA2_ ++#define ELEMENT_ID_RSN_WPA2 48 ++#endif //endif WPA2 ++ ++#define WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT ((u16) 6) ++#define WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT ((u16) 2) ++ ++#ifdef WB_LINUX ++#define UNALIGNED ++#endif ++ ++//======================================================== ++typedef enum enum_PowerManagementMode ++{ ++ ACTIVE = 0, ++ POWER_SAVE ++} WB_PM_Mode, *PWB_PM_MODE; ++ ++//=================================================================== ++// Reason Code (Table 18): indicate the reason of DisAssoc, DeAuthen ++// length of ReasonCode is 2 Octs. ++//=================================================================== ++#define REASON_REASERED 0 ++#define REASON_UNSPECIDIED 1 ++#define REASON_PREAUTH_INVALID 2 ++#define DEAUTH_REASON_LEFT_BSS 3 ++#define DISASS_REASON_AP_INACTIVE 4 ++#define DISASS_REASON_AP_BUSY 5 ++#define REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define REASON_CLASS3_FRAME_FROM_NONASSO_STA 7 ++#define DISASS_REASON_LEFT_BSS 8 ++#define REASON_NOT_AUTH_YET 9 ++//802.11i define ++#define REASON_INVALID_IE 13 ++#define REASON_MIC_ERROR 14 ++#define REASON_4WAY_HANDSHAKE_TIMEOUT 15 ++#define REASON_GROUPKEY_UPDATE_TIMEOUT 16 ++#define REASON_IE_DIFF_4WAY_ASSOC 17 ++#define REASON_INVALID_MULTICAST_CIPHER 18 ++#define REASON_INVALID_UNICAST_CIPHER 19 ++#define REASON_INVALID_AKMP 20 ++#define REASON_UNSUPPORTED_RSNIE_VERSION 21 ++#define REASON_INVALID_RSNIE_CAPABILITY 22 ++#define REASON_802_1X_AUTH_FAIL 23 ++#define REASON_CIPHER_REJECT_PER_SEC_POLICY 14 ++ ++/* ++//=========================================================== ++// enum_MMPDUResultCode -- ++// Status code (2 Octs) in the MMPDU's frame body. Table.19 ++// ++//=========================================================== ++enum enum_MMPDUResultCode ++{ ++// SUCCESS = 0, // Redefined ++ UNSPECIFIED_FAILURE = 1, ++ ++ // 2 - 9 Reserved ++ ++ NOT_SUPPROT_CAPABILITIES = 10, ++ ++ //REASSOCIATION_DENIED ++ // ++ REASSOC_DENIED_UNABLE_CFM_ASSOC_EXIST = 11, ++ ++ //ASSOCIATION_DENIED_NOT_IN_STANDARD ++ // ++ ASSOC_DENIED_REASON_NOT_IN_STANDARD = 12, ++ PEER_NOT_SUPPORT_AUTH_ALGORITHM = 13, ++ AUTH_SEQNUM_OUT_OF_EXPECT = 14, ++ AUTH_REJECT_REASON_CHALLENGE_FAIL = 15, ++ AUTH_REJECT_REASON_WAIT_TIMEOUT = 16, ++ ASSOC_DENIED_REASON_AP_BUSY = 17, ++ ASSOC_DENIED_REASON_NOT_SUPPORT_BASIC_RATE = 18 ++} WB_MMPDURESULTCODE, *PWB_MMPDURESULTCODE; ++*/ ++ ++//=========================================================== ++// enum_TxRate -- ++// Define the transmission constants based on W89C32 MAC ++// target specification. ++//=========================================================== ++typedef enum enum_TxRate ++{ ++ TXRATE_1M = 0, ++ TXRATE_2MLONG = 2, ++ TXRATE_2MSHORT = 3, ++ TXRATE_55MLONG = 4, ++ TXRATE_55MSHORT = 5, ++ TXRATE_11MLONG = 6, ++ TXRATE_11MSHORT = 7, ++ TXRATE_AUTO = 255 // PD43 20021108 ++} WB_TXRATE, *PWB_TXRATE; ++ ++ ++#define RATE_BITMAP_1M 1 ++#define RATE_BITMAP_2M 2 ++#define RATE_BITMAP_5dot5M 5 ++#define RATE_BITMAP_6M 6 ++#define RATE_BITMAP_9M 9 ++#define RATE_BITMAP_11M 11 ++#define RATE_BITMAP_12M 12 ++#define RATE_BITMAP_18M 18 ++#define RATE_BITMAP_22M 22 ++#define RATE_BITMAP_24M 24 ++#define RATE_BITMAP_33M 17 ++#define RATE_BITMAP_36M 19 ++#define RATE_BITMAP_48M 25 ++#define RATE_BITMAP_54M 28 ++ ++#define RATE_AUTO 0 ++#define RATE_1M 2 ++#define RATE_2M 4 ++#define RATE_5dot5M 11 ++#define RATE_6M 12 ++#define RATE_9M 18 ++#define RATE_11M 22 ++#define RATE_12M 24 ++#define RATE_18M 36 ++#define RATE_22M 44 ++#define RATE_24M 48 ++#define RATE_33M 66 ++#define RATE_36M 72 ++#define RATE_48M 96 ++#define RATE_54M 108 ++#define RATE_MAX 255 ++ ++//CAPABILITY ++#define CAPABILITY_ESS_BIT 0x0001 ++#define CAPABILITY_IBSS_BIT 0x0002 ++#define CAPABILITY_CF_POLL_BIT 0x0004 ++#define CAPABILITY_CF_POLL_REQ_BIT 0x0008 ++#define CAPABILITY_PRIVACY_BIT 0x0010 ++#define CAPABILITY_SHORT_PREAMBLE_BIT 0x0020 ++#define CAPABILITY_PBCC_BIT 0x0040 ++#define CAPABILITY_CHAN_AGILITY_BIT 0x0080 ++#define CAPABILITY_SHORT_SLOT_TIME_BIT 0x0400 ++#define CAPABILITY_DSSS_OFDM_BIT 0x2000 ++ ++ ++struct Capability_Information_Element ++{ ++ union ++ { ++ u16 __attribute__ ((packed)) wValue; ++ #ifdef _BIG_ENDIAN_ //20060926 add by anson's endian ++ struct _Capability ++ { ++ //-- 11G -- ++ u8 Reserved3 : 2; ++ u8 DSSS_OFDM : 1; ++ u8 Reserved2 : 2; ++ u8 Short_Slot_Time : 1; ++ u8 Reserved1 : 2; ++ u8 Channel_Agility : 1; ++ u8 PBCC : 1; ++ u8 ShortPreamble : 1; ++ u8 CF_Privacy : 1; ++ u8 CF_Poll_Request : 1; ++ u8 CF_Pollable : 1; ++ u8 IBSS : 1; ++ u8 ESS : 1; ++ } __attribute__ ((packed)) Capability; ++ #else ++ struct _Capability ++ { ++ u8 ESS : 1; ++ u8 IBSS : 1; ++ u8 CF_Pollable : 1; ++ u8 CF_Poll_Request : 1; ++ u8 CF_Privacy : 1; ++ u8 ShortPreamble : 1; ++ u8 PBCC : 1; ++ u8 Channel_Agility : 1; ++ u8 Reserved1 : 2; ++ //-- 11G -- ++ u8 Short_Slot_Time : 1; ++ u8 Reserved2 : 2; ++ u8 DSSS_OFDM : 1; ++ u8 Reserved3 : 2; ++ } __attribute__ ((packed)) Capability; ++ #endif ++ }__attribute__ ((packed)) ; ++}__attribute__ ((packed)); ++ ++struct FH_Parameter_Set_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 Dwell_Time[2]; ++ u8 Hop_Set; ++ u8 Hop_Pattern; ++ u8 Hop_Index; ++}; ++ ++struct DS_Parameter_Set_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 Current_Channel; ++}; ++ ++struct Supported_Rates_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 SupportedRates[8]; ++}__attribute__ ((packed)); ++ ++struct SSID_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 SSID[32]; ++}__attribute__ ((packed)) ; ++ ++struct CF_Parameter_Set_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 CFP_Count; ++ u8 CFP_Period; ++ u8 CFP_MaxDuration[2]; // in Time Units ++ u8 CFP_DurRemaining[2]; // in time units ++}; ++ ++struct TIM_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 DTIM_Count; ++ u8 DTIM_Period; ++ u8 Bitmap_Control; ++ u8 Partial_Virtual_Bitmap[251]; ++}; ++ ++struct IBSS_Parameter_Set_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 ATIM_Window[2]; ++}; ++ ++struct Challenge_Text_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 Challenge_Text[253]; ++}; ++ ++struct PHY_Parameter_Set_Element ++{ ++// int aSlotTime; ++// int aSifsTime; ++ s32 aCCATime; ++ s32 aRxTxTurnaroundTime; ++ s32 aTxPLCPDelay; ++ s32 RxPLCPDelay; ++ s32 aRxTxSwitchTime; ++ s32 aTxRampOntime; ++ s32 aTxRampOffTime; ++ s32 aTxRFDelay; ++ s32 aRxRFDelay; ++ s32 aAirPropagationTime; ++ s32 aMACProcessingDelay; ++ s32 aPreambleLength; ++ s32 aPLCPHeaderLength; ++ s32 aMPDUDurationFactor; ++ s32 aMPDUMaxLength; ++// int aCWmin; ++// int aCWmax; ++}; ++ ++//-- 11G -- ++struct ERP_Information_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ #ifdef _BIG_ENDIAN_ //20060926 add by anson's endian ++ u8 Reserved:5; //20060926 add by anson ++ u8 Barker_Preamble_Mode:1; ++ u8 Use_Protection:1; ++ u8 NonERP_Present:1; ++ #else ++ u8 NonERP_Present:1; ++ u8 Use_Protection:1; ++ u8 Barker_Preamble_Mode:1; ++ u8 Reserved:5; ++ #endif ++}; ++ ++struct Extended_Supported_Rates_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u8 ExtendedSupportedRates[255]; ++}__attribute__ ((packed)); ++ ++//WPA(802.11i draft 3.0) ++#define VERSION_WPA 1 ++#ifdef _WPA2_ ++#define VERSION_WPA2 1 ++#endif //end def _WPA2_ ++#define OUI_WPA 0x00F25000 //WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type ++#ifdef _WPA2_ ++#define OUI_WPA2 0x00AC0F00 // for wpa2 change to 0x00ACOF04 by Ws 26/04/04 ++#endif //end def _WPA2_ ++ ++#define OUI_WPA_ADDITIONAL 0x01 ++#define WLAN_MIN_RSN_WPA_LENGTH 6 //added by ws 09/10/04 ++#ifdef _WPA2_ ++#define WLAN_MIN_RSN_WPA2_LENGTH 2 // Fix to 2 09/14/05 ++#endif //end def _WPA2_ ++ ++#define oui_wpa (u32)(OUI_WPA|OUI_WPA_ADDITIONAL) ++ ++#define WPA_OUI_BIG ((u32) 0x01F25000)//added by ws 09/23/04 ++#define WPA_OUI_LITTLE ((u32) 0x01F25001)//added by ws 09/23/04 ++ ++#define WPA_WPS_OUI cpu_to_le32(0x04F25000) // 20061108 For WPS. It's little endian. Big endian is 0x0050F204 ++ ++//-----WPA2----- ++#ifdef _WPA2_ ++#define WPA2_OUI_BIG ((u32)0x01AC0F00) ++#define WPA2_OUI_LITTLE ((u32)0x01AC0F01) ++#endif //end def _WPA2_ ++ ++//Authentication suite ++#define OUI_AUTH_WPA_NONE 0x00 //for WPA_NONE ++#define OUI_AUTH_8021X 0x01 ++#define OUI_AUTH_PSK 0x02 ++//Cipher suite ++#define OUI_CIPHER_GROUP_KEY 0x00 //added by ws 05/21/04 ++#define OUI_CIPHER_WEP_40 0x01 ++#define OUI_CIPHER_TKIP 0x02 ++#define OUI_CIPHER_CCMP 0x04 ++#define OUI_CIPHER_WEP_104 0x05 ++ ++typedef struct _SUITE_SELECTOR_ ++{ ++ union ++ { ++ u8 Value[4]; ++ struct _SUIT_ ++ { ++ u8 OUI[3]; ++ u8 Type; ++ }SuitSelector; ++ }; ++}SUITE_SELECTOR; ++ ++//-- WPA -- ++struct RSN_Information_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ UNALIGNED SUITE_SELECTOR OuiWPAAdditional;//WPA version 2.0 additional field, and should be 00:50:F2:01 ++ u16 Version; ++ SUITE_SELECTOR GroupKeySuite; ++ u16 PairwiseKeySuiteCount; ++ SUITE_SELECTOR PairwiseKeySuite[1]; ++}__attribute__ ((packed)); ++struct RSN_Auth_Sub_Information_Element ++{ ++ u16 AuthKeyMngtSuiteCount; ++ SUITE_SELECTOR AuthKeyMngtSuite[1]; ++}__attribute__ ((packed)); ++ ++//-- WPA2 -- ++struct RSN_Capability_Element ++{ ++ union ++ { ++ u16 __attribute__ ((packed)) wValue; ++ #ifdef _BIG_ENDIAN_ //20060927 add by anson's endian ++ struct _RSN_Capability ++ { ++ u16 __attribute__ ((packed)) Reserved2 : 8; // 20051201 ++ u16 __attribute__ ((packed)) Reserved1 : 2; ++ u16 __attribute__ ((packed)) GTK_Replay_Counter : 2; ++ u16 __attribute__ ((packed)) PTK_Replay_Counter : 2; ++ u16 __attribute__ ((packed)) No_Pairwise : 1; ++ u16 __attribute__ ((packed)) Pre_Auth : 1; ++ }__attribute__ ((packed)) RSN_Capability; ++ #else ++ struct _RSN_Capability ++ { ++ u16 __attribute__ ((packed)) Pre_Auth : 1; ++ u16 __attribute__ ((packed)) No_Pairwise : 1; ++ u16 __attribute__ ((packed)) PTK_Replay_Counter : 2; ++ u16 __attribute__ ((packed)) GTK_Replay_Counter : 2; ++ u16 __attribute__ ((packed)) Reserved1 : 2; ++ u16 __attribute__ ((packed)) Reserved2 : 8; // 20051201 ++ }__attribute__ ((packed)) RSN_Capability; ++ #endif ++ ++ }__attribute__ ((packed)) ; ++}__attribute__ ((packed)) ; ++ ++#ifdef _WPA2_ ++typedef struct _PMKID ++{ ++ u8 pValue[16]; ++}PMKID; ++ ++struct WPA2_RSN_Information_Element ++{ ++ u8 Element_ID; ++ u8 Length; ++ u16 Version; ++ SUITE_SELECTOR GroupKeySuite; ++ u16 PairwiseKeySuiteCount; ++ SUITE_SELECTOR PairwiseKeySuite[1]; ++ ++}__attribute__ ((packed)); ++ ++struct WPA2_RSN_Auth_Sub_Information_Element ++{ ++ u16 AuthKeyMngtSuiteCount; ++ SUITE_SELECTOR AuthKeyMngtSuite[1]; ++}__attribute__ ((packed)); ++ ++ ++struct PMKID_Information_Element ++{ ++ u16 PMKID_Count; ++ PMKID pmkid [16] ; ++}__attribute__ ((packed)); ++ ++#endif //enddef _WPA2_ ++//============================================================ ++// MAC Frame structure (different type) and subfield structure ++//============================================================ ++struct MAC_frame_control ++{ ++ u8 mac_frame_info; // a combination of the [Protocol Version, Control Type, Control Subtype] ++ #ifdef _BIG_ENDIAN_ //20060927 add by anson's endian ++ u8 order:1; ++ u8 WEP:1; ++ u8 more_data:1; ++ u8 pwr_mgt:1; ++ u8 retry:1; ++ u8 more_frag:1; ++ u8 from_ds:1; ++ u8 to_ds:1; ++ #else ++ u8 to_ds:1; ++ u8 from_ds:1; ++ u8 more_frag:1; ++ u8 retry:1; ++ u8 pwr_mgt:1; ++ u8 more_data:1; ++ u8 WEP:1; ++ u8 order:1; ++ #endif ++} __attribute__ ((packed)); ++ ++struct Management_Frame { ++ struct MAC_frame_control frame_control; // 2B, ToDS,FromDS,MoreFrag,MoreData,Order=0 ++ u16 duration; ++ u8 DA[MAC_ADDR_LENGTH]; // Addr1 ++ u8 SA[MAC_ADDR_LENGTH]; // Addr2 ++ u8 BSSID[MAC_ADDR_LENGTH]; // Addr3 ++ u16 Sequence_Control; ++ // Management Frame Body <= 325 bytes ++ // FCS 4 bytes ++}__attribute__ ((packed)); ++ ++// SW-MAC don't Tx/Rx Control-Frame, HW-MAC do it. ++struct Control_Frame { ++ struct MAC_frame_control frame_control; // ToDS,FromDS,MoreFrag,Retry,MoreData,WEP,Order=0 ++ u16 duration; ++ u8 RA[MAC_ADDR_LENGTH]; ++ u8 TA[MAC_ADDR_LENGTH]; ++ u16 FCS; ++}__attribute__ ((packed)); ++ ++struct Data_Frame { ++ struct MAC_frame_control frame_control; ++ u16 duration; ++ u8 Addr1[MAC_ADDR_LENGTH]; ++ u8 Addr2[MAC_ADDR_LENGTH]; ++ u8 Addr3[MAC_ADDR_LENGTH]; ++ u16 Sequence_Control; ++ u8 Addr4[MAC_ADDR_LENGTH]; // only exist when ToDS=FromDS=1 ++ // Data Frame Body <= 2312 ++ // FCS ++}__attribute__ ((packed)); ++ ++struct Disassociation_Frame_Body ++{ ++ u16 reasonCode; ++}__attribute__ ((packed)); ++ ++struct Association_Request_Frame_Body ++{ ++ u16 capability_information; ++ u16 listenInterval; ++ u8 Current_AP_Address[MAC_ADDR_LENGTH];//for reassociation only ++ // SSID (2+32 bytes) ++ // Supported_Rates (2+8 bytes) ++}__attribute__ ((packed)); ++ ++struct Association_Response_Frame_Body ++{ ++ u16 capability_information; ++ u16 statusCode; ++ u16 Association_ID; ++ struct Supported_Rates_Element supportedRates; ++}__attribute__ ((packed)); ++ ++/*struct Reassociation_Request_Frame_Body ++{ ++ u16 capability_information; ++ u16 listenInterval; ++ u8 Current_AP_Address[MAC_ADDR_LENGTH]; ++ // SSID (2+32 bytes) ++ // Supported_Rates (2+8 bytes) ++};*/ ++// eliminated by WS 07/22/04 comboined with associateion request frame. ++ ++struct Reassociation_Response_Frame_Body ++{ ++ u16 capability_information; ++ u16 statusCode; ++ u16 Association_ID; ++ struct Supported_Rates_Element supportedRates; ++}__attribute__ ((packed)); ++ ++struct Deauthentication_Frame_Body ++{ ++ u16 reasonCode; ++}__attribute__ ((packed)); ++ ++ ++struct Probe_Response_Frame_Body ++{ ++ u16 Timestamp; ++ u16 Beacon_Interval; ++ u16 Capability_Information; ++ // SSID ++ // Supported_Rates ++ // PHY parameter Set (DS Parameters) ++ // CF parameter Set ++ // IBSS parameter Set ++}__attribute__ ((packed)); ++ ++struct Authentication_Frame_Body ++{ ++ u16 algorithmNumber; ++ u16 sequenceNumber; ++ u16 statusCode; ++ // NB: don't include ChallengeText in this structure ++ // struct Challenge_Text_Element sChallengeTextElement; // wkchen added ++}__attribute__ ((packed)); ++ ++ ++#endif // _MAC_Structure_H_ ++ ++ +diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c +new file mode 100644 +index 0000000..8ce6389 +--- /dev/null ++++ b/drivers/staging/winbond/mds.c +@@ -0,0 +1,630 @@ ++#include "os_common.h" ++ ++void ++Mds_reset_descriptor(PADAPTER Adapter) ++{ ++ PMDS pMds = &Adapter->Mds; ++ ++ pMds->TxPause = 0; ++ pMds->TxThreadCount = 0; ++ pMds->TxFillIndex = 0; ++ pMds->TxDesIndex = 0; ++ pMds->ScanTxPause = 0; ++ memset(pMds->TxOwner, 0, ((MAX_USB_TX_BUFFER_NUMBER + 3) & ~0x03)); ++} ++ ++unsigned char ++Mds_initial(PADAPTER Adapter) ++{ ++ PMDS pMds = &Adapter->Mds; ++ ++ pMds->TxPause = FALSE; ++ pMds->TxRTSThreshold = DEFAULT_RTSThreshold; ++ pMds->TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; ++ ++ vRxTimerInit(Adapter);//for WPA countermeasure ++ ++ return hal_get_tx_buffer( &Adapter->sHwData, &pMds->pTxBuffer ); ++} ++ ++void ++Mds_Destroy(PADAPTER Adapter) ++{ ++ vRxTimerStop(Adapter); ++} ++ ++void ++Mds_Tx(PADAPTER Adapter) ++{ ++ phw_data_t pHwData = &Adapter->sHwData; ++ PMDS pMds = &Adapter->Mds; ++ DESCRIPTOR TxDes; ++ PDESCRIPTOR pTxDes = &TxDes; ++ PUCHAR XmitBufAddress; ++ u16 XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold; ++ u8 FillIndex, TxDesIndex, FragmentCount, FillCount; ++ unsigned char BufferFilled = FALSE, MICAdd = 0; ++ ++ ++ if (pMds->TxPause) ++ return; ++ if (!hal_driver_init_OK(pHwData)) ++ return; ++ ++ //Only one thread can be run here ++ if (!OS_ATOMIC_INC( Adapter, &pMds->TxThreadCount) == 1) ++ goto cleanup; ++ ++ // Start to fill the data ++ do { ++ FillIndex = pMds->TxFillIndex; ++ if (pMds->TxOwner[FillIndex]) { // Is owned by software 0:Yes 1:No ++#ifdef _PE_TX_DUMP_ ++ WBDEBUG(("[Mds_Tx] Tx Owner is H/W.\n")); ++#endif ++ break; ++ } ++ ++ XmitBufAddress = pMds->pTxBuffer + (MAX_USB_TX_BUFFER * FillIndex); //Get buffer ++ XmitBufSize = 0; ++ FillCount = 0; ++ do { ++ PacketSize = Adapter->sMlmeFrame.len; ++ if (!PacketSize) ++ break; ++ ++ //For Check the buffer resource ++ FragmentThreshold = CURRENT_FRAGMENT_THRESHOLD; ++ //931130.5.b ++ FragmentCount = PacketSize/FragmentThreshold + 1; ++ stmp = PacketSize + FragmentCount*32 + 8;//931130.5.c 8:MIC ++ if ((XmitBufSize + stmp) >= MAX_USB_TX_BUFFER) { ++ printk("[Mds_Tx] Excess max tx buffer.\n"); ++ break; // buffer is not enough ++ } ++ ++ ++ // ++ // Start transmitting ++ // ++ BufferFilled = TRUE; ++ ++ /* Leaves first u8 intact */ ++ memset((PUCHAR)pTxDes + 1, 0, sizeof(DESCRIPTOR) - 1); ++ ++ TxDesIndex = pMds->TxDesIndex;//Get the current ID ++ pTxDes->Descriptor_ID = TxDesIndex; ++ pMds->TxDesFrom[ TxDesIndex ] = 2;//Storing the information of source comming from ++ pMds->TxDesIndex++; ++ pMds->TxDesIndex %= MAX_USB_TX_DESCRIPTOR; ++ ++ MLME_GetNextPacket( Adapter, pTxDes ); ++ ++ // Copy header. 8byte USB + 24byte 802.11Hdr. Set TxRate, Preamble type ++ Mds_HeaderCopy( Adapter, pTxDes, XmitBufAddress ); ++ ++ // For speed up Key setting ++ if (pTxDes->EapFix) { ++#ifdef _PE_TX_DUMP_ ++ WBDEBUG(("35: EPA 4th frame detected. Size = %d\n", PacketSize)); ++#endif ++ pHwData->IsKeyPreSet = 1; ++ } ++ ++ // Copy (fragment) frame body, and set USB, 802.11 hdr flag ++ CurrentSize = Mds_BodyCopy(Adapter, pTxDes, XmitBufAddress); ++ ++ // Set RTS/CTS and Normal duration field into buffer ++ Mds_DurationSet(Adapter, pTxDes, XmitBufAddress); ++ ++ // ++ // Calculation MIC from buffer which maybe fragment, then fill into temporary address 8 byte ++ // 931130.5.e ++ if (MICAdd) ++ Mds_MicFill( Adapter, pTxDes, XmitBufAddress ); ++ ++ //Shift to the next address ++ XmitBufSize += CurrentSize; ++ XmitBufAddress += CurrentSize; ++ ++#ifdef _IBSS_BEACON_SEQ_STICK_ ++ if ((XmitBufAddress[ DOT_11_DA_OFFSET+8 ] & 0xfc) != MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) // +8 for USB hdr ++#endif ++ pMds->TxToggle = TRUE; ++ ++ // Get packet to transmit completed, 1:TESTSTA 2:MLME 3: Ndis data ++ MLME_SendComplete(Adapter, 0, TRUE); ++ ++ // Software TSC count 20060214 ++ pMds->TxTsc++; ++ if (pMds->TxTsc == 0) ++ pMds->TxTsc_2++; ++ ++ FillCount++; // 20060928 ++ } while (HAL_USB_MODE_BURST(pHwData)); // End of multiple MSDU copy loop. FALSE = single TRUE = multiple sending ++ ++ // Move to the next one, if necessary ++ if (BufferFilled) { ++ // size setting ++ pMds->TxBufferSize[ FillIndex ] = XmitBufSize; ++ ++ // 20060928 set Tx count ++ pMds->TxCountInBuffer[FillIndex] = FillCount; ++ ++ // Set owner flag ++ pMds->TxOwner[FillIndex] = 1; ++ ++ pMds->TxFillIndex++; ++ pMds->TxFillIndex %= MAX_USB_TX_BUFFER_NUMBER; ++ BufferFilled = FALSE; ++ } else ++ break; ++ ++ if (!PacketSize) // No more pk for transmitting ++ break; ++ ++ } while(TRUE); ++ ++ // ++ // Start to send by lower module ++ // ++ if (!pHwData->IsKeyPreSet) ++ Wb35Tx_start(pHwData); ++ ++ cleanup: ++ OS_ATOMIC_DEC( Adapter, &pMds->TxThreadCount ); ++} ++ ++void ++Mds_SendComplete(PADAPTER Adapter, PT02_DESCRIPTOR pT02) ++{ ++ PMDS pMds = &Adapter->Mds; ++ phw_data_t pHwData = &Adapter->sHwData; ++ u8 PacketId = (u8)pT02->T02_Tx_PktID; ++ unsigned char SendOK = TRUE; ++ u8 RetryCount, TxRate; ++ ++ if (pT02->T02_IgnoreResult) // Don't care the result ++ return; ++ if (pT02->T02_IsLastMpdu) { ++ //TODO: DTO -- get the retry count and fragment count ++ // Tx rate ++ TxRate = pMds->TxRate[ PacketId ][ 0 ]; ++ RetryCount = (u8)pT02->T02_MPDU_Cnt; ++ if (pT02->value & FLAG_ERROR_TX_MASK) { ++ SendOK = FALSE; ++ ++ if (pT02->T02_transmit_abort || pT02->T02_out_of_MaxTxMSDULiftTime) { ++ //retry error ++ pHwData->dto_tx_retry_count += (RetryCount+1); ++ //[for tx debug] ++ if (RetryCount<7) ++ pHwData->tx_retry_count[RetryCount] += RetryCount; ++ else ++ pHwData->tx_retry_count[7] += RetryCount; ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("dto_tx_retry_count =%d\n", pHwData->dto_tx_retry_count)); ++ #endif ++ MTO_SetTxCount(Adapter, TxRate, RetryCount); ++ } ++ pHwData->dto_tx_frag_count += (RetryCount+1); ++ ++ //[for tx debug] ++ if (pT02->T02_transmit_abort_due_to_TBTT) ++ pHwData->tx_TBTT_start_count++; ++ if (pT02->T02_transmit_without_encryption_due_to_wep_on_false) ++ pHwData->tx_WepOn_false_count++; ++ if (pT02->T02_discard_due_to_null_wep_key) ++ pHwData->tx_Null_key_count++; ++ } else { ++ if (pT02->T02_effective_transmission_rate) ++ pHwData->tx_ETR_count++; ++ MTO_SetTxCount(Adapter, TxRate, RetryCount); ++ } ++ ++ // Clear send result buffer ++ pMds->TxResult[ PacketId ] = 0; ++ } else ++ pMds->TxResult[ PacketId ] |= ((u16)(pT02->value & 0x0ffff)); ++} ++ ++void ++Mds_HeaderCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer) ++{ ++ PMDS pMds = &Adapter->Mds; ++ PUCHAR src_buffer = pDes->buffer_address[0];//931130.5.g ++ PT00_DESCRIPTOR pT00; ++ PT01_DESCRIPTOR pT01; ++ u16 stmp; ++ u8 i, ctmp1, ctmp2, ctmpf; ++ u16 FragmentThreshold = CURRENT_FRAGMENT_THRESHOLD; ++ ++ ++ stmp = pDes->buffer_total_size; ++ // ++ // Set USB header 8 byte ++ // ++ pT00 = (PT00_DESCRIPTOR)TargetBuffer; ++ TargetBuffer += 4; ++ pT01 = (PT01_DESCRIPTOR)TargetBuffer; ++ TargetBuffer += 4; ++ ++ pT00->value = 0;// Clear ++ pT01->value = 0;// Clear ++ ++ pT00->T00_tx_packet_id = pDes->Descriptor_ID;// Set packet ID ++ pT00->T00_header_length = 24;// Set header length ++ pT01->T01_retry_abort_ebable = 1;//921013 931130.5.h ++ ++ // Key ID setup ++ pT01->T01_wep_id = 0; ++ ++ FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; //Do not fragment ++ // Copy full data, the 1'st buffer contain all the data 931130.5.j ++ memcpy( TargetBuffer, src_buffer, DOT_11_MAC_HEADER_SIZE );// Copy header ++ pDes->buffer_address[0] = src_buffer + DOT_11_MAC_HEADER_SIZE; ++ pDes->buffer_total_size -= DOT_11_MAC_HEADER_SIZE; ++ pDes->buffer_size[0] = pDes->buffer_total_size; ++ ++ // Set fragment threshold ++ FragmentThreshold -= (DOT_11_MAC_HEADER_SIZE + 4); ++ pDes->FragmentThreshold = FragmentThreshold; ++ ++ // Set more frag bit ++ TargetBuffer[1] |= 0x04;// Set more frag bit ++ ++ // ++ // Set tx rate ++ // ++ stmp = *(PUSHORT)(TargetBuffer+30); // 2n alignment address ++ ++ //Use basic rate ++ ctmp1 = ctmpf = CURRENT_TX_RATE_FOR_MNG; ++ ++ pDes->TxRate = ctmp1; ++ #ifdef _PE_TX_DUMP_ ++ WBDEBUG(("Tx rate =%x\n", ctmp1)); ++ #endif ++ ++ pT01->T01_modulation_type = (ctmp1%3) ? 0 : 1; ++ ++ for( i=0; i<2; i++ ) { ++ if( i == 1 ) ++ ctmp1 = ctmpf; ++ ++ pMds->TxRate[pDes->Descriptor_ID][i] = ctmp1; // backup the ta rate and fall back rate ++ ++ if( ctmp1 == 108) ctmp2 = 7; ++ else if( ctmp1 == 96 ) ctmp2 = 6; // Rate convert for USB ++ else if( ctmp1 == 72 ) ctmp2 = 5; ++ else if( ctmp1 == 48 ) ctmp2 = 4; ++ else if( ctmp1 == 36 ) ctmp2 = 3; ++ else if( ctmp1 == 24 ) ctmp2 = 2; ++ else if( ctmp1 == 18 ) ctmp2 = 1; ++ else if( ctmp1 == 12 ) ctmp2 = 0; ++ else if( ctmp1 == 22 ) ctmp2 = 3; ++ else if( ctmp1 == 11 ) ctmp2 = 2; ++ else if( ctmp1 == 4 ) ctmp2 = 1; ++ else ctmp2 = 0; // if( ctmp1 == 2 ) or default ++ ++ if( i == 0 ) ++ pT01->T01_transmit_rate = ctmp2; ++ else ++ pT01->T01_fall_back_rate = ctmp2; ++ } ++ ++ // ++ // Set preamble type ++ // ++ if ((pT01->T01_modulation_type == 0) && (pT01->T01_transmit_rate == 0)) // RATE_1M ++ pDes->PreambleMode = WLAN_PREAMBLE_TYPE_LONG; ++ else ++ pDes->PreambleMode = CURRENT_PREAMBLE_MODE; ++ pT01->T01_plcp_header_length = pDes->PreambleMode; // Set preamble ++ ++} ++ ++// The function return the 4n size of usb pk ++u16 ++Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer) ++{ ++ PT00_DESCRIPTOR pT00; ++ PMDS pMds = &Adapter->Mds; ++ PUCHAR buffer, src_buffer, pctmp; ++ u16 Size = 0; ++ u16 SizeLeft, CopySize, CopyLeft, stmp; ++ u8 buf_index, FragmentCount = 0; ++ ++ ++ // Copy fragment body ++ buffer = TargetBuffer; // shift 8B usb + 24B 802.11 ++ SizeLeft = pDes->buffer_total_size; ++ buf_index = pDes->buffer_start_index; ++ ++ pT00 = (PT00_DESCRIPTOR)buffer; ++ while (SizeLeft) { ++ pT00 = (PT00_DESCRIPTOR)buffer; ++ CopySize = SizeLeft; ++ if (SizeLeft > pDes->FragmentThreshold) { ++ CopySize = pDes->FragmentThreshold; ++ pT00->T00_frame_length = 24 + CopySize;//Set USB length ++ } else ++ pT00->T00_frame_length = 24 + SizeLeft;//Set USB length ++ ++ SizeLeft -= CopySize; ++ ++ // 1 Byte operation ++ pctmp = (PUCHAR)( buffer + 8 + DOT_11_SEQUENCE_OFFSET ); ++ *pctmp &= 0xf0; ++ *pctmp |= FragmentCount;//931130.5.m ++ if( !FragmentCount ) ++ pT00->T00_first_mpdu = 1; ++ ++ buffer += 32; // 8B usb + 24B 802.11 header ++ Size += 32; ++ ++ // Copy into buffer ++ stmp = CopySize + 3; ++ stmp &= ~0x03;//4n Alignment ++ Size += stmp;// Current 4n offset of mpdu ++ ++ while (CopySize) { ++ // Copy body ++ src_buffer = pDes->buffer_address[buf_index]; ++ CopyLeft = CopySize; ++ if (CopySize >= pDes->buffer_size[buf_index]) { ++ CopyLeft = pDes->buffer_size[buf_index]; ++ ++ // Get the next buffer of descriptor ++ buf_index++; ++ buf_index %= MAX_DESCRIPTOR_BUFFER_INDEX; ++ } else { ++ PUCHAR pctmp = pDes->buffer_address[buf_index]; ++ pctmp += CopySize; ++ pDes->buffer_address[buf_index] = pctmp; ++ pDes->buffer_size[buf_index] -= CopySize; ++ } ++ ++ memcpy(buffer, src_buffer, CopyLeft); ++ buffer += CopyLeft; ++ CopySize -= CopyLeft; ++ } ++ ++ // 931130.5.n ++ if (pMds->MicAdd) { ++ if (!SizeLeft) { ++ pMds->MicWriteAddress[ pMds->MicWriteIndex ] = buffer - pMds->MicAdd; ++ pMds->MicWriteSize[ pMds->MicWriteIndex ] = pMds->MicAdd; ++ pMds->MicAdd = 0; ++ } ++ else if( SizeLeft < 8 ) //931130.5.p ++ { ++ pMds->MicAdd = SizeLeft; ++ pMds->MicWriteAddress[ pMds->MicWriteIndex ] = buffer - ( 8 - SizeLeft ); ++ pMds->MicWriteSize[ pMds->MicWriteIndex ] = 8 - SizeLeft; ++ pMds->MicWriteIndex++; ++ } ++ } ++ ++ // Does it need to generate the new header for next mpdu? ++ if (SizeLeft) { ++ buffer = TargetBuffer + Size; // Get the next 4n start address ++ memcpy( buffer, TargetBuffer, 32 );//Copy 8B USB +24B 802.11 ++ pT00 = (PT00_DESCRIPTOR)buffer; ++ pT00->T00_first_mpdu = 0; ++ } ++ ++ FragmentCount++; ++ } ++ ++ pT00->T00_last_mpdu = 1; ++ pT00->T00_IsLastMpdu = 1; ++ buffer = (PUCHAR)pT00 + 8; // +8 for USB hdr ++ buffer[1] &= ~0x04; // Clear more frag bit of 802.11 frame control ++ pDes->FragmentCount = FragmentCount; // Update the correct fragment number ++ return Size; ++} ++ ++ ++void ++Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR buffer ) ++{ ++ PT00_DESCRIPTOR pT00; ++ PT01_DESCRIPTOR pT01; ++ u16 Duration, NextBodyLen, OffsetSize; ++ u8 Rate, i; ++ unsigned char CTS_on = FALSE, RTS_on = FALSE; ++ PT00_DESCRIPTOR pNextT00; ++ u16 BodyLen; ++ unsigned char boGroupAddr = FALSE; ++ ++ ++ OffsetSize = pDes->FragmentThreshold + 32 + 3; ++ OffsetSize &= ~0x03; ++ Rate = pDes->TxRate >> 1; ++ if (!Rate) ++ Rate = 1; ++ ++ pT00 = (PT00_DESCRIPTOR)buffer; ++ pT01 = (PT01_DESCRIPTOR)(buffer+4); ++ pNextT00 = (PT00_DESCRIPTOR)(buffer+OffsetSize); ++ ++ if( buffer[ DOT_11_DA_OFFSET+8 ] & 0x1 ) // +8 for USB hdr ++ boGroupAddr = TRUE; ++ ++ //======================================== ++ // Set RTS/CTS mechanism ++ //======================================== ++ if (!boGroupAddr) ++ { ++ //NOTE : If the protection mode is enabled and the MSDU will be fragmented, ++ // the tx rates of MPDUs will all be DSSS rates. So it will not use ++ // CTS-to-self in this case. CTS-To-self will only be used when without ++ // fragmentation. -- 20050112 ++ BodyLen = (u16)pT00->T00_frame_length; //include 802.11 header ++ BodyLen += 4; //CRC ++ ++ if( BodyLen >= CURRENT_RTS_THRESHOLD ) ++ RTS_on = TRUE; // Using RTS ++ else ++ { ++ if( pT01->T01_modulation_type ) // Is using OFDM ++ { ++ if( CURRENT_PROTECT_MECHANISM ) // Is using protect ++ CTS_on = TRUE; // Using CTS ++ } ++ } ++ } ++ ++ if( RTS_on || CTS_on ) ++ { ++ if( pT01->T01_modulation_type) // Is using OFDM ++ { ++ //CTS duration ++ // 2 SIFS + DATA transmit time + 1 ACK ++ // ACK Rate : 24 Mega bps ++ // ACK frame length = 14 bytes ++ Duration = 2*DEFAULT_SIFSTIME + ++ 2*PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION + ++ ((BodyLen*8 + 22 + Rate*4 - 1)/(Rate*4))*Tsym + ++ ((112 + 22 + 95)/96)*Tsym; ++ } ++ else //DSSS ++ { ++ //CTS duration ++ // 2 SIFS + DATA transmit time + 1 ACK ++ // Rate : ?? Mega bps ++ // ACK frame length = 14 bytes ++ if( pT01->T01_plcp_header_length ) //long preamble ++ Duration = LONG_PREAMBLE_PLUS_PLCPHEADER_TIME*2; ++ else ++ Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME*2; ++ ++ Duration += ( ((BodyLen + 14)*8 + Rate-1) / Rate + ++ DEFAULT_SIFSTIME*2 ); ++ } ++ ++ if( RTS_on ) ++ { ++ if( pT01->T01_modulation_type ) // Is using OFDM ++ { ++ //CTS + 1 SIFS + CTS duration ++ //CTS Rate : 24 Mega bps ++ //CTS frame length = 14 bytes ++ Duration += (DEFAULT_SIFSTIME + ++ PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION + ++ ((112 + 22 + 95)/96)*Tsym); ++ } ++ else ++ { ++ //CTS + 1 SIFS + CTS duration ++ //CTS Rate : ?? Mega bps ++ //CTS frame length = 14 bytes ++ if( pT01->T01_plcp_header_length ) //long preamble ++ Duration += LONG_PREAMBLE_PLUS_PLCPHEADER_TIME; ++ else ++ Duration += SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME; ++ ++ Duration += ( ((112 + Rate-1) / Rate) + DEFAULT_SIFSTIME ); ++ } ++ } ++ ++ // Set the value into USB descriptor ++ pT01->T01_add_rts = RTS_on ? 1 : 0; ++ pT01->T01_add_cts = CTS_on ? 1 : 0; ++ pT01->T01_rts_cts_duration = Duration; ++ } ++ ++ //===================================== ++ // Fill the more fragment descriptor ++ //===================================== ++ if( boGroupAddr ) ++ Duration = 0; ++ else ++ { ++ for( i=pDes->FragmentCount-1; i>0; i-- ) ++ { ++ NextBodyLen = (u16)pNextT00->T00_frame_length; ++ NextBodyLen += 4; //CRC ++ ++ if( pT01->T01_modulation_type ) ++ { ++ //OFDM ++ // data transmit time + 3 SIFS + 2 ACK ++ // Rate : ??Mega bps ++ // ACK frame length = 14 bytes, tx rate = 24M ++ Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION * 3; ++ Duration += (((NextBodyLen*8 + 22 + Rate*4 - 1)/(Rate*4)) * Tsym + ++ (((2*14)*8 + 22 + 95)/96)*Tsym + ++ DEFAULT_SIFSTIME*3); ++ } ++ else ++ { ++ //DSSS ++ // data transmit time + 2 ACK + 3 SIFS ++ // Rate : ??Mega bps ++ // ACK frame length = 14 bytes ++ //TODO : ++ if( pT01->T01_plcp_header_length ) //long preamble ++ Duration = LONG_PREAMBLE_PLUS_PLCPHEADER_TIME*3; ++ else ++ Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME*3; ++ ++ Duration += ( ((NextBodyLen + (2*14))*8 + Rate-1) / Rate + ++ DEFAULT_SIFSTIME*3 ); ++ } ++ ++ ((PUSHORT)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration ++ ++ //----20061009 add by anson's endian ++ pNextT00->value = cpu_to_le32(pNextT00->value); ++ pT01->value = cpu_to_le32( pT01->value ); ++ //----end 20061009 add by anson's endian ++ ++ buffer += OffsetSize; ++ pT01 = (PT01_DESCRIPTOR)(buffer+4); ++ if (i != 1) //The last fragment will not have the next fragment ++ pNextT00 = (PT00_DESCRIPTOR)(buffer+OffsetSize); ++ } ++ ++ //===================================== ++ // Fill the last fragment descriptor ++ //===================================== ++ if( pT01->T01_modulation_type ) ++ { ++ //OFDM ++ // 1 SIFS + 1 ACK ++ // Rate : 24 Mega bps ++ // ACK frame length = 14 bytes ++ Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION; ++ //The Tx rate of ACK use 24M ++ Duration += (((112 + 22 + 95)/96)*Tsym + DEFAULT_SIFSTIME ); ++ } ++ else ++ { ++ // DSSS ++ // 1 ACK + 1 SIFS ++ // Rate : ?? Mega bps ++ // ACK frame length = 14 bytes(112 bits) ++ if( pT01->T01_plcp_header_length ) //long preamble ++ Duration = LONG_PREAMBLE_PLUS_PLCPHEADER_TIME; ++ else ++ Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME; ++ ++ Duration += ( (112 + Rate-1)/Rate + DEFAULT_SIFSTIME ); ++ } ++ } ++ ++ ((PUSHORT)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration ++ pT00->value = cpu_to_le32(pT00->value); ++ pT01->value = cpu_to_le32(pT01->value); ++ //--end 20061009 add ++ ++} ++ ++void MDS_EthernetPacketReceive( PADAPTER Adapter, PRXLAYER1 pRxLayer1 ) ++{ ++ OS_RECEIVE_PACKET_INDICATE( Adapter, pRxLayer1 ); ++} ++ ++ +diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h +new file mode 100644 +index 0000000..651188b +--- /dev/null ++++ b/drivers/staging/winbond/mds_f.h +@@ -0,0 +1,33 @@ ++unsigned char Mds_initial( PADAPTER Adapter ); ++void Mds_Destroy( PADAPTER Adapter ); ++void Mds_Tx( PADAPTER Adapter ); ++void Mds_HeaderCopy( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer ); ++u16 Mds_BodyCopy( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer ); ++void Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer ); ++void Mds_SendComplete( PADAPTER Adapter, PT02_DESCRIPTOR pT02 ); ++void Mds_MpduProcess( PADAPTER Adapter, PDESCRIPTOR pRxDes ); ++void Mds_reset_descriptor( PADAPTER Adapter ); ++extern void DataDmp(u8 *pdata, u32 len, u32 offset); ++ ++ ++void vRxTimerInit(PWB32_ADAPTER Adapter); ++void vRxTimerStart(PWB32_ADAPTER Adapter, int timeout_value); ++void RxTimerHandler_1a( PADAPTER Adapter); ++void vRxTimerStop(PWB32_ADAPTER Adapter); ++void RxTimerHandler( void* SystemSpecific1, ++ PWB32_ADAPTER Adapter, ++ void* SystemSpecific2, ++ void* SystemSpecific3); ++ ++ ++// For Asynchronous indicating. The routine collocates with USB. ++void Mds_MsduProcess( PWB32_ADAPTER Adapter, PRXLAYER1 pRxLayer1, u8 SlotIndex); ++ ++// For data frame sending 20060802 ++u16 MDS_GetPacketSize( PADAPTER Adapter ); ++void MDS_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes ); ++void MDS_GetNextPacketComplete( PADAPTER Adapter, PDESCRIPTOR pDes ); ++void MDS_SendResult( PADAPTER Adapter, u8 PacketId, unsigned char SendOK ); ++void MDS_EthernetPacketReceive( PADAPTER Adapter, PRXLAYER1 pRxLayer1 ); ++ ++ +diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h +new file mode 100644 +index 0000000..4738279 +--- /dev/null ++++ b/drivers/staging/winbond/mds_s.h +@@ -0,0 +1,183 @@ ++//////////////////////////////////////////////////////////////////////////////////////////////////////// ++#define MAX_USB_TX_DESCRIPTOR 15 // IS89C35 ability ++#define MAX_USB_TX_BUFFER_NUMBER 4 // Virtual pre-buffer number of MAX_USB_TX_BUFFER ++#define MAX_USB_TX_BUFFER 4096 // IS89C35 ability 4n alignment is required for hardware ++ ++#define MDS_EVENT_INDICATE( _A, _B, _F ) OS_EVENT_INDICATE( _A, _B, _F ) ++#define AUTH_REQUEST_PAIRWISE_ERROR 0 // _F flag setting ++#define AUTH_REQUEST_GROUP_ERROR 1 // _F flag setting ++ ++// For variable setting ++#define CURRENT_BSS_TYPE psBSS(psLOCAL->wConnectedSTAindex)->bBssType ++#define CURRENT_WEP_MODE psSME->_dot11PrivacyInvoked ++#define CURRENT_BSSID psBSS(psLOCAL->wConnectedSTAindex)->abBssID ++#define CURRENT_DESIRED_WPA_ENABLE ((psSME->bDesiredAuthMode==WPA_AUTH)||(psSME->bDesiredAuthMode==WPAPSK_AUTH)) ++#ifdef _WPA2_ ++#define CURRENT_DESIRED_WPA2_ENABLE ((psSME->bDesiredAuthMode==WPA2_AUTH)||(psSME->bDesiredAuthMode==WPA2PSK_AUTH)) ++#endif //end def _WPA2_ ++#define CURRENT_PAIRWISE_KEY_OK psSME->pairwise_key_ok ++//[20040712 WS] ++#define CURRENT_GROUP_KEY_OK psSME->group_key_ok ++#define CURRENT_PAIRWISE_KEY psSME->tx_mic_key ++#define CURRENT_GROUP_KEY psSME->group_tx_mic_key ++#define CURRENT_ENCRYPT_STATUS psSME->encrypt_status ++#define CURRENT_WEP_ID Adapter->sSmePara._dot11WEPDefaultKeyID ++#define CURRENT_CONTROL_PORT_BLOCK ( psSME->wpa_ok!=1 || (Adapter->Mds.boCounterMeasureBlock==1 && (CURRENT_ENCRYPT_STATUS==ENCRYPT_TKIP)) ) ++#define CURRENT_FRAGMENT_THRESHOLD (Adapter->Mds.TxFragmentThreshold & ~0x1) ++#define CURRENT_PREAMBLE_MODE psLOCAL->boShortPreamble?WLAN_PREAMBLE_TYPE_SHORT:WLAN_PREAMBLE_TYPE_LONG ++#define CURRENT_LINK_ON OS_LINK_STATUS ++#define CURRENT_TX_RATE Adapter->sLocalPara.CurrentTxRate ++#define CURRENT_FALL_BACK_TX_RATE Adapter->sLocalPara.CurrentTxFallbackRate ++#define CURRENT_TX_RATE_FOR_MNG Adapter->sLocalPara.CurrentTxRateForMng ++#define CURRENT_PROTECT_MECHANISM psLOCAL->boProtectMechanism ++#define CURRENT_RTS_THRESHOLD Adapter->Mds.TxRTSThreshold ++ ++#define MIB_GS_XMIT_OK_INC Adapter->sLocalPara.GS_XMIT_OK++ ++#define MIB_GS_RCV_OK_INC Adapter->sLocalPara.GS_RCV_OK++ ++#define MIB_GS_XMIT_ERROR_INC Adapter->sLocalPara.GS_XMIT_ERROR ++ ++//---------- TX ----------------------------------- ++#define ETHERNET_TX_DESCRIPTORS MAX_USB_TX_BUFFER_NUMBER ++ ++//---------- RX ------------------------------------ ++#define ETHERNET_RX_DESCRIPTORS 8 //It's not necessary to allocate more than 2 in sync indicate ++ ++//================================================================ ++// Configration default value ++//================================================================ ++#define DEFAULT_MULTICASTLISTMAX 32 // standard ++#define DEFAULT_TX_BURSTLENGTH 3 // 32 Longwords ++#define DEFAULT_RX_BURSTLENGTH 3 // 32 Longwords ++#define DEFAULT_TX_THRESHOLD 0 // Full Packet ++#define DEFAULT_RX_THRESHOLD 0 // Full Packet ++#define DEFAULT_MAXTXRATE 6 // 11 Mbps (Long) ++#define DEFAULT_CHANNEL 3 // Chennel 3 ++#define DEFAULT_RTSThreshold 2347 // Disable RTS ++//#define DEFAULT_PME 1 // Enable ++#define DEFAULT_PME 0 // Disable ++#define DEFAULT_SIFSTIME 10 ++#define DEFAULT_ACKTIME_1ML 304 // 148+44+112 911220 by LCC ++#define DEFAULT_ACKTIME_2ML 248 // 148+44+56 911220 by LCC ++#define DEFAULT_FRAGMENT_THRESHOLD 2346 // No fragment ++#define DEFAULT_PREAMBLE_LENGTH 72 ++#define DEFAULT_PLCPHEADERTIME_LENGTH 24 ++ ++/*------------------------------------------------------------------------ ++ 0.96 sec since time unit of the R03 for the current, W89C32 is about 60ns ++ instead of 960 ns. This shall be fixed in the future W89C32 ++ -------------------------------------------------------------------------*/ ++#define DEFAULT_MAX_RECEIVE_TIME 16440000 ++ ++#define RX_BUF_SIZE 2352 // 600 // For 301 must be multiple of 8 ++#define MAX_RX_DESCRIPTORS 18 // Rx Layer 2 ++#define MAX_BUFFER_QUEUE 8 // The value is always equal 8 due to NDIS_PACKET's MiniportReserved field size ++ ++ ++// For brand-new rx system ++#define MDS_ID_IGNORE ETHERNET_RX_DESCRIPTORS ++ ++// For Tx Packet status classify ++#define PACKET_FREE_TO_USE 0 ++#define PACKET_COME_FROM_NDIS 0x08 ++#define PACKET_COME_FROM_MLME 0x80 ++#define PACKET_SEND_COMPLETE 0xff ++ ++typedef struct _MDS ++{ ++ // For Tx usage ++ u8 TxOwner[ ((MAX_USB_TX_BUFFER_NUMBER + 3) & ~0x03) ]; ++ PUCHAR pTxBuffer; ++ u16 TxBufferSize[ ((MAX_USB_TX_BUFFER_NUMBER + 1) & ~0x01) ]; ++ u8 TxDesFrom[ ((MAX_USB_TX_DESCRIPTOR + 3) & ~0x03) ];//931130.4.u // 1: MLME 2: NDIS control 3: NDIS data ++ u8 TxCountInBuffer[ ((MAX_USB_TX_DESCRIPTOR + 3) & ~0x03) ]; // 20060928 ++ ++ u8 TxFillIndex;//the next index of TxBuffer can be used ++ u8 TxDesIndex;//The next index of TxDes can be used ++ u8 ScanTxPause; //data Tx pause because the scanning is progressing, but probe request Tx won't. ++ u8 TxPause;//For pause the Mds_Tx modult ++ ++ OS_ATOMIC TxThreadCount;//For thread counting 931130.4.v ++//950301 delete due to HW ++// OS_ATOMIC TxConcurrentCount;//931130.4.w ++ ++ u16 TxResult[ ((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01) ];//Collect the sending result of Mpdu ++ ++ u8 MicRedundant[8]; // For tmp use ++ PUCHAR MicWriteAddress[2]; //The start address to fill the Mic, use 2 point due to Mic maybe fragment ++ ++ u16 MicWriteSize[2]; //931130.4.x ++ ++ u16 MicAdd; // If want to add the Mic, this variable equal to 8 ++ u16 MicWriteIndex;//The number of MicWriteAddress 931130.4.y ++ ++ u8 TxRate[ ((MAX_USB_TX_DESCRIPTOR+1)&~0x01) ][2]; // [0] current tx rate, [1] fall back rate ++ u8 TxInfo[ ((MAX_USB_TX_DESCRIPTOR+1)&~0x01) ]; //Store information for callback function ++ ++ //WKCHEN added for scanning mechanism ++ u8 TxToggle; //It is TRUE if there are tx activities in some time interval ++ u8 Reserved_[3]; ++ ++ //---------- for Tx Parameter ++ u16 TxFragmentThreshold; // For frame body only ++ u16 TxRTSThreshold; ++ ++ u32 MaxReceiveTime;//911220.3 Add ++ ++ // depend on OS, ++ u32 MulticastListNo; ++ u32 PacketFilter; // Setting by NDIS, the current packet filter in use. ++ u8 MulticastAddressesArray[DEFAULT_MULTICASTLISTMAX][MAC_ADDR_LENGTH]; ++ ++ //COUNTERMEASURE ++ u8 bMICfailCount; ++ u8 boCounterMeasureBlock; ++ u8 reserved_4[2]; ++ ++ //NDIS_MINIPORT_TIMER nTimer; ++ OS_TIMER nTimer; ++ ++ u32 TxTsc; // 20060214 ++ u32 TxTsc_2; // 20060214 ++ ++} MDS, *PMDS; ++ ++ ++typedef struct _RxBuffer ++{ ++ PUCHAR pBufferAddress; // Pointer the received data buffer. ++ u16 BufferSize; ++ u8 RESERVED; ++ u8 BufferIndex;// Only 1 byte ++} RXBUFFER, *PRXBUFFER; ++ ++// ++// Reveive Layer 1 Format. ++//---------------------------- ++typedef struct _RXLAYER1 ++{ ++ u16 SequenceNumber; // The sequence number of the last received packet. ++ u16 BufferTotalSize; ++ ++ u32 InUsed; ++ u32 DecryptionMethod; // The desired defragment number of the next incoming packet. ++ ++ u8 DeFragmentNumber; ++ u8 FrameType; ++ u8 TypeEncapsulated; ++ u8 BufferNumber; ++ ++ u32 FirstFrameArrivedTime; ++ ++ RXBUFFER BufferQueue[ MAX_BUFFER_QUEUE ]; ++ ++ u8 LastFrameType; // 20061004 for fix intel 3945 's bug ++ u8 RESERVED[3]; //@@ anson ++ ++ ///////////////////////////////////////////////////////////////////////////////////////////// ++ // For brand-new Rx system ++ u8 ReservedBuffer[ 2400 ];//If Buffer ID is reserved one, it must copy the data into this area ++ PUCHAR ReservedBufferPoint;// Point to the next availabe address of reserved buffer ++ ++}RXLAYER1, * PRXLAYER1; ++ ++ +diff --git a/drivers/staging/winbond/mlme_mib.h b/drivers/staging/winbond/mlme_mib.h +new file mode 100644 +index 0000000..8975973 +--- /dev/null ++++ b/drivers/staging/winbond/mlme_mib.h +@@ -0,0 +1,84 @@ ++//============================================================================ ++// MLMEMIB.H - ++// ++// Description: ++// Get and Set some of MLME MIB attributes. ++// ++// Revision history: ++// -------------------------------------------------------------------------- ++// 20030117 PD43 Austin Liu ++// Initial release ++// ++// Copyright (c) 2003 Winbond Electronics Corp. All rights reserved. ++//============================================================================ ++ ++#ifndef _MLME_MIB_H ++#define _MLME_MIB_H ++ ++//============================================================================ ++// MLMESetExcludeUnencrypted -- ++// ++// Description: ++// Set the dot11ExcludeUnencrypted value. ++// ++// Arguments: ++// Adapter - The pointer to the miniport adapter context. ++// ExUnencrypted - unsigned char type. The value to be set. ++// ++// Return values: ++// None. ++//============================================================================ ++#define MLMESetExcludeUnencrypted(Adapter, ExUnencrypted) \ ++{ \ ++ (Adapter)->sLocalPara.ExcludeUnencrypted = ExUnencrypted; \ ++} ++ ++//============================================================================ ++// MLMEGetExcludeUnencrypted -- ++// ++// Description: ++// Get the dot11ExcludeUnencrypted value. ++// ++// Arguments: ++// Adapter - The pointer to the miniport adapter context. ++// ++// Return values: ++// unsigned char type. The current dot11ExcludeUnencrypted value. ++//============================================================================ ++#define MLMEGetExcludeUnencrypted(Adapter) ((unsigned char) (Adapter)->sLocalPara.ExcludeUnencrypted) ++ ++//============================================================================ ++// MLMESetMaxReceiveLifeTime -- ++// ++// Description: ++// Set the dot11MaxReceiveLifeTime value. ++// ++// Arguments: ++// Adapter - The pointer to the miniport adapter context. ++// ReceiveLifeTime- u32 type. The value to be set. ++// ++// Return values: ++// None. ++//============================================================================ ++#define MLMESetMaxReceiveLifeTime(Adapter, ReceiveLifeTime) \ ++{ \ ++ (Adapter)->Mds.MaxReceiveTime = ReceiveLifeTime; \ ++} ++ ++//============================================================================ ++// MLMESetMaxReceiveLifeTime -- ++// ++// Description: ++// Get the dot11MaxReceiveLifeTime value. ++// ++// Arguments: ++// Adapter - The pointer to the miniport adapter context. ++// ++// Return values: ++// u32 type. The current dot11MaxReceiveLifeTime value. ++//============================================================================ ++#define MLMEGetMaxReceiveLifeTime(Adapter) ((u32) (Adapter)->Mds.MaxReceiveTime) ++ ++#endif ++ ++ +diff --git a/drivers/staging/winbond/mlme_s.h b/drivers/staging/winbond/mlme_s.h +new file mode 100644 +index 0000000..58094f6 +--- /dev/null ++++ b/drivers/staging/winbond/mlme_s.h +@@ -0,0 +1,195 @@ ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// Mlme.h ++// Define the related definitions of MLME module ++// history -- 01/14/03' created ++// ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++#define AUTH_REJECT_REASON_CHALLENGE_FAIL 1 ++ ++//====== the state of MLME module ++#define INACTIVE 0x0 ++#define IDLE_SCAN 0x1 ++ ++//====== the state of MLME/ESS module ++#define STATE_1 0x2 ++#define AUTH_REQ 0x3 ++#define AUTH_WEP 0x4 ++#define STATE_2 0x5 ++#define ASSOC_REQ 0x6 ++#define STATE_3 0x7 ++ ++//====== the state of MLME/IBSS module ++#define IBSS_JOIN_SYNC 0x8 ++#define IBSS_AUTH_REQ 0x9 ++#define IBSS_AUTH_CHANLGE 0xa ++#define IBSS_AUTH_WEP 0xb ++#define IBSS_AUTH_IND 0xc ++#define IBSS_STATE_2 0xd ++ ++ ++ ++//========================================= ++//depend on D5C(MAC timing control 03 register): MaxTxMSDULifeTime default 0x80000us ++#define AUTH_FAIL_TIMEOUT 550 ++#define ASSOC_FAIL_TIMEOUT 550 ++#define REASSOC_FAIL_TIMEOUT 550 ++ ++ ++ ++// ++// MLME task global CONSTANTS, STRUCTURE, variables ++// ++ ++ ++///////////////////////////////////////////////////////////// ++// enum_ResultCode -- ++// Result code returned from MLME to SME. ++// ++///////////////////////////////////////////////////////////// ++// PD43 20030829 Modifiled ++//#define SUCCESS 0 ++#define MLME_SUCCESS 0 //follow spec. ++#define INVALID_PARAMETERS 1 //Not following spec. ++#define NOT_SUPPPORTED 2 ++#define TIMEOUT 3 ++#define TOO_MANY_SIMULTANEOUS_REQUESTS 4 ++#define REFUSED 5 ++#define BSS_ALREADY_STARTED_OR_JOINED 6 ++#define TRANSMIT_FRAME_FAIL 7 ++#define NO_BSS_FOUND 8 ++#define RETRY 9 ++#define GIVE_UP 10 ++ ++ ++#define OPEN_AUTH 0 ++#define SHARE_AUTH 1 ++#define ANY_AUTH 2 ++#define WPA_AUTH 3 //for WPA ++#define WPAPSK_AUTH 4 ++#define WPANONE_AUTH 5 ++///////////////////////////////////////////// added by ws 04/19/04 ++#ifdef _WPA2_ ++#define WPA2_AUTH 6//for WPA2 ++#define WPA2PSK_AUTH 7 ++#endif //end def _WPA2_ ++ ++////////////////////////////////////////////////////////////////// ++//define the msg type of MLME module ++////////////////////////////////////////////////////////////////// ++//-------------------------------------------------------- ++//from SME ++ ++#define MLMEMSG_AUTH_REQ 0x0b ++#define MLMEMSG_DEAUTH_REQ 0x0c ++#define MLMEMSG_ASSOC_REQ 0x0d ++#define MLMEMSG_REASSOC_REQ 0x0e ++#define MLMEMSG_DISASSOC_REQ 0x0f ++#define MLMEMSG_START_IBSS_REQ 0x10 ++#define MLMEMSG_IBSS_NET_CFM 0x11 ++ ++//from RX : ++#define MLMEMSG_RCV_MLMEFRAME 0x20 ++#define MLMEMSG_RCV_ASSOCRSP 0x22 ++#define MLMEMSG_RCV_REASSOCRSP 0x24 ++#define MLMEMSG_RCV_DISASSOC 0x2b ++#define MLMEMSG_RCV_AUTH 0x2c ++#define MLMEMSG_RCV_DEAUTH 0x2d ++ ++ ++//from TX callback ++#define MLMEMSG_TX_CALLBACK 0x40 ++#define MLMEMSG_ASSOCREQ_CALLBACK 0x41 ++#define MLMEMSG_REASSOCREQ_CALLBACK 0x43 ++#define MLMEMSG_DISASSOC_CALLBACK 0x4a ++#define MLMEMSG_AUTH_CALLBACK 0x4c ++#define MLMEMSG_DEAUTH_CALLBACK 0x4d ++ ++//#define MLMEMSG_JOIN_FAIL 4 ++//#define MLMEMSG_AUTHEN_FAIL 18 ++#define MLMEMSG_TIMEOUT 0x50 ++ ++/////////////////////////////////////////////////////////////////////////// ++//Global data structures ++#define MAX_NUM_TX_MMPDU 2 ++#define MAX_MMPDU_SIZE 1512 ++#define MAX_NUM_RX_MMPDU 6 ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++//MACRO ++#define boMLME_InactiveState(_AA_) (_AA_->wState==INACTIVE) ++#define boMLME_IdleScanState(_BB_) (_BB_->wState==IDLE_SCAN) ++#define boMLME_FoundSTAinfo(_CC_) (_CC_->wState>=IDLE_SCAN) ++ ++typedef struct _MLME_FRAME ++{ ++ //NDIS_PACKET MLME_Packet; ++ PCHAR pMMPDU; ++ u16 len; ++ u8 DataType; ++ u8 IsInUsed; ++ ++ OS_SPIN_LOCK MLMESpinLock; ++ ++ u8 TxMMPDU[MAX_NUM_TX_MMPDU][MAX_MMPDU_SIZE]; ++ u8 TxMMPDUInUse[ (MAX_NUM_TX_MMPDU+3) & ~0x03 ]; ++ ++ u16 wNumTxMMPDU; ++ u16 wNumTxMMPDUDiscarded; ++ ++ u8 RxMMPDU[MAX_NUM_RX_MMPDU][MAX_MMPDU_SIZE]; ++ u8 SaveRxBufSlotInUse[ (MAX_NUM_RX_MMPDU+3) & ~0x03 ]; ++ ++ u16 wNumRxMMPDU; ++ u16 wNumRxMMPDUDiscarded; ++ ++ u16 wNumRxMMPDUInMLME; // Number of the Rx MMPDU ++ u16 reserved_1; // in MLME. ++ // excluding the discarded ++} MLME_FRAME, *psMLME_FRAME; ++ ++typedef struct _AUTHREQ { ++ ++ u8 peerMACaddr[MAC_ADDR_LENGTH]; ++ u16 wAuthAlgorithm; ++ ++} MLME_AUTHREQ_PARA, *psMLME_AUTHREQ_PARA; ++ ++struct _Reason_Code { ++ ++ u8 peerMACaddr[MAC_ADDR_LENGTH]; ++ u16 wReasonCode; ++}; ++typedef struct _Reason_Code MLME_DEAUTHREQ_PARA, *psMLME_DEAUTHREQ_PARA; ++typedef struct _Reason_Code MLME_DISASSOCREQ_PARA, *psMLME_DISASSOCREQ_PARA; ++ ++typedef struct _ASSOCREQ { ++ u8 PeerSTAAddr[MAC_ADDR_LENGTH]; ++ u16 CapabilityInfo; ++ u16 ListenInterval; ++ ++}__attribute__ ((packed)) MLME_ASSOCREQ_PARA, *psMLME_ASSOCREQ_PARA; ++ ++typedef struct _REASSOCREQ { ++ u8 NewAPAddr[MAC_ADDR_LENGTH]; ++ u16 CapabilityInfo; ++ u16 ListenInterval; ++ ++}__attribute__ ((packed)) MLME_REASSOCREQ_PARA, *psMLME_REASSOCREQ_PARA; ++ ++typedef struct _MLMECALLBACK { ++ ++ u8 *psFramePtr; ++ u8 bResult; ++ ++} MLME_TXCALLBACK, *psMLME_TXCALLBACK; ++ ++typedef struct _RXDATA ++{ ++ s32 FrameLength; ++ u8 __attribute__ ((packed)) *pbFramePtr; ++ ++}__attribute__ ((packed)) RXDATA, *psRXDATA; ++ ++ +diff --git a/drivers/staging/winbond/mlmetxrx.c b/drivers/staging/winbond/mlmetxrx.c +new file mode 100644 +index 0000000..46b091e +--- /dev/null ++++ b/drivers/staging/winbond/mlmetxrx.c +@@ -0,0 +1,150 @@ ++//============================================================================ ++// Module Name: ++// MLMETxRx.C ++// ++// Description: ++// The interface between MDS (MAC Data Service) and MLME. ++// ++// Revision History: ++// -------------------------------------------------------------------------- ++// 200209 UN20 Jennifer Xu ++// Initial Release ++// 20021108 PD43 Austin Liu ++// 20030117 PD43 Austin Liu ++// Deleted MLMEReturnPacket and MLMEProcThread() ++// ++// Copyright (c) 1996-2002 Winbond Electronics Corp. All Rights Reserved. ++//============================================================================ ++#include "os_common.h" ++ ++void MLMEResetTxRx(PWB32_ADAPTER Adapter) ++{ ++ s32 i; ++ ++ // Reset the interface between MDS and MLME ++ for (i = 0; i < MAX_NUM_TX_MMPDU; i++) ++ Adapter->sMlmeFrame.TxMMPDUInUse[i] = FALSE; ++ for (i = 0; i < MAX_NUM_RX_MMPDU; i++) ++ Adapter->sMlmeFrame.SaveRxBufSlotInUse[i] = FALSE; ++ ++ Adapter->sMlmeFrame.wNumRxMMPDUInMLME = 0; ++ Adapter->sMlmeFrame.wNumRxMMPDUDiscarded = 0; ++ Adapter->sMlmeFrame.wNumRxMMPDU = 0; ++ Adapter->sMlmeFrame.wNumTxMMPDUDiscarded = 0; ++ Adapter->sMlmeFrame.wNumTxMMPDU = 0; ++ Adapter->sLocalPara.boCCAbusy = FALSE; ++ Adapter->sLocalPara.iPowerSaveMode = PWR_ACTIVE; // Power active ++} ++ ++//============================================================================= ++// Function: ++// MLMEGetMMPDUBuffer() ++// ++// Description: ++// Return the pointer to an available data buffer with ++// the size MAX_MMPDU_SIZE for a MMPDU. ++// ++// Arguments: ++// Adapter - pointer to the miniport adapter context. ++// ++// Return value: ++// NULL : No available data buffer available ++// Otherwise: Pointer to the data buffer ++//============================================================================= ++ ++/* FIXME: Should this just be replaced with kmalloc() and kfree()? */ ++u8 *MLMEGetMMPDUBuffer(PWB32_ADAPTER Adapter) ++{ ++ s32 i; ++ u8 *returnVal; ++ ++ for (i = 0; i< MAX_NUM_TX_MMPDU; i++) { ++ if (Adapter->sMlmeFrame.TxMMPDUInUse[i] == FALSE) ++ break; ++ } ++ if (i >= MAX_NUM_TX_MMPDU) return NULL; ++ ++ returnVal = (u8 *)&(Adapter->sMlmeFrame.TxMMPDU[i]); ++ Adapter->sMlmeFrame.TxMMPDUInUse[i] = TRUE; ++ ++ return returnVal; ++} ++ ++//============================================================================= ++u8 MLMESendFrame(PWB32_ADAPTER Adapter, u8 *pMMPDU, u16 len, u8 DataType) ++/* DataType : FRAME_TYPE_802_11_MANAGEMENT, FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE, ++ FRAME_TYPE_802_11_DATA */ ++{ ++ if (Adapter->sMlmeFrame.IsInUsed != PACKET_FREE_TO_USE) { ++ Adapter->sMlmeFrame.wNumTxMMPDUDiscarded++; ++ return FALSE; ++ } ++ Adapter->sMlmeFrame.IsInUsed = PACKET_COME_FROM_MLME; ++ ++ // Keep information for sending ++ Adapter->sMlmeFrame.pMMPDU = pMMPDU; ++ Adapter->sMlmeFrame.DataType = DataType; ++ // len must be the last setting due to QUERY_SIZE_SECOND of Mds ++ Adapter->sMlmeFrame.len = len; ++ Adapter->sMlmeFrame.wNumTxMMPDU++; ++ ++ // H/W will enter power save by set the register. S/W don't send null frame ++ //with PWRMgt bit enbled to enter power save now. ++ ++ // Transmit NDIS packet ++ Mds_Tx(Adapter); ++ return TRUE; ++} ++ ++void ++MLME_GetNextPacket(PADAPTER Adapter, PDESCRIPTOR pDes) ++{ ++#define DESCRIPTOR_ADD_BUFFER( _D, _A, _S ) \ ++{\ ++ _D->InternalUsed = _D->buffer_start_index + _D->buffer_number; \ ++ _D->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX; \ ++ _D->buffer_address[ _D->InternalUsed ] = _A; \ ++ _D->buffer_size[ _D->InternalUsed ] = _S; \ ++ _D->buffer_total_size += _S; \ ++ _D->buffer_number++;\ ++} ++ ++ DESCRIPTOR_ADD_BUFFER( pDes, Adapter->sMlmeFrame.pMMPDU, Adapter->sMlmeFrame.len ); ++ pDes->Type = Adapter->sMlmeFrame.DataType; ++} ++ ++void MLMEfreeMMPDUBuffer(PWB32_ADAPTER Adapter, PCHAR pData) ++{ ++ int i; ++ ++ // Reclaim the data buffer ++ for (i = 0; i < MAX_NUM_TX_MMPDU; i++) { ++ if (pData == (PCHAR)&(Adapter->sMlmeFrame.TxMMPDU[i])) ++ break; ++ } ++ if (Adapter->sMlmeFrame.TxMMPDUInUse[i]) ++ Adapter->sMlmeFrame.TxMMPDUInUse[i] = FALSE; ++ else { ++ // Something wrong ++ // PD43 Add debug code here??? ++ } ++} ++ ++void ++MLME_SendComplete(PADAPTER Adapter, u8 PacketID, unsigned char SendOK) ++{ ++ MLME_TXCALLBACK TxCallback; ++ ++ // Reclaim the data buffer ++ Adapter->sMlmeFrame.len = 0; ++ MLMEfreeMMPDUBuffer( Adapter, Adapter->sMlmeFrame.pMMPDU ); ++ ++ ++ TxCallback.bResult = MLME_SUCCESS; ++ ++ // Return resource ++ Adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE; ++} ++ ++ ++ +diff --git a/drivers/staging/winbond/mlmetxrx_f.h b/drivers/staging/winbond/mlmetxrx_f.h +new file mode 100644 +index 0000000..d74e225 +--- /dev/null ++++ b/drivers/staging/winbond/mlmetxrx_f.h +@@ -0,0 +1,52 @@ ++//================================================================ ++// MLMETxRx.H -- ++// ++// Functions defined in MLMETxRx.c. ++// ++// Copyright (c) 2002 Winbond Electrics Corp. All Rights Reserved. ++//================================================================ ++#ifndef _MLMETXRX_H ++#define _MLMETXRX_H ++ ++void ++MLMEProcThread( ++ PWB32_ADAPTER Adapter ++ ); ++ ++void MLMEResetTxRx( PWB32_ADAPTER Adapter); ++ ++u8 * ++MLMEGetMMPDUBuffer( ++ PWB32_ADAPTER Adapter ++ ); ++ ++void MLMEfreeMMPDUBuffer( PWB32_ADAPTER Adapter, PCHAR pData); ++ ++void MLME_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes ); ++u8 MLMESendFrame( PWB32_ADAPTER Adapter, ++ u8 *pMMPDU, ++ u16 len, ++ u8 DataType); ++ ++void ++MLME_SendComplete( PWB32_ADAPTER Adapter, u8 PacketID, unsigned char SendOK ); ++ ++void ++MLMERcvFrame( ++ PWB32_ADAPTER Adapter, ++ PRXBUFFER pRxBufferArray, ++ u8 NumOfBuffer, ++ u8 ReturnSlotIndex ++ ); ++ ++void ++MLMEReturnPacket( ++ PWB32_ADAPTER Adapter, ++ PUCHAR pRxBufer ++ ); ++#ifdef _IBSS_BEACON_SEQ_STICK_ ++s8 SendBCNullData(PWB32_ADAPTER Adapter, u16 wIdx); ++#endif ++ ++#endif ++ +diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c +new file mode 100644 +index 0000000..2ef60e5 +--- /dev/null ++++ b/drivers/staging/winbond/mto.c +@@ -0,0 +1,1229 @@ ++//============================================================================ ++// MTO.C - ++// ++// Description: ++// MAC Throughput Optimization for W89C33 802.11g WLAN STA. ++// ++// The following MIB attributes or internal variables will be affected ++// while the MTO is being executed: ++// dot11FragmentationThreshold, ++// dot11RTSThreshold, ++// transmission rate and PLCP preamble type, ++// CCA mode, ++// antenna diversity. ++// ++// Revision history: ++// -------------------------------------------------------------------------- ++// 20031227 UN20 Pete Chao ++// First draft ++// 20031229 Turbo copy from PD43 ++// 20040210 Kevin revised ++// Copyright (c) 2003 Winbond Electronics Corp. All rights reserved. ++//============================================================================ ++ ++// LA20040210_DTO kevin ++#include "os_common.h" ++ ++// Declare SQ3 to rate and fragmentation threshold table ++// Declare fragmentation thresholds table ++#define MTO_MAX_SQ3_LEVELS 14 ++#define MTO_MAX_FRAG_TH_LEVELS 5 ++#define MTO_MAX_DATA_RATE_LEVELS 12 ++ ++u16 MTO_Frag_Th_Tbl[MTO_MAX_FRAG_TH_LEVELS] = ++{ ++ 256, 384, 512, 768, 1536 ++}; ++ ++u8 MTO_SQ3_Level[MTO_MAX_SQ3_LEVELS] = ++{ ++ 0, 26, 30, 32, 34, 35, 37, 42, 44, 46, 54, 62, 78, 81 ++}; ++u8 MTO_SQ3toRate[MTO_MAX_SQ3_LEVELS] = ++{ ++ 0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ++}; ++u8 MTO_SQ3toFrag[MTO_MAX_SQ3_LEVELS] = ++{ ++ 0, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4 ++}; ++ ++// One Exchange Time table ++// ++u16 MTO_One_Exchange_Time_Tbl_l[MTO_MAX_FRAG_TH_LEVELS][MTO_MAX_DATA_RATE_LEVELS] = ++{ ++ { 2554, 1474, 822, 0, 0, 636, 0, 0, 0, 0, 0, 0}, ++ { 3578, 1986, 1009, 0, 0, 729, 0, 0, 0, 0, 0, 0}, ++ { 4602, 2498, 1195, 0, 0, 822, 0, 0, 0, 0, 0, 0}, ++ { 6650, 3522, 1567, 0, 0, 1009, 0, 0, 0, 0, 0, 0}, ++ {12794, 6594, 2684, 0, 0, 1567, 0, 0, 0, 0, 0, 0} ++}; ++ ++u16 MTO_One_Exchange_Time_Tbl_s[MTO_MAX_FRAG_TH_LEVELS][MTO_MAX_DATA_RATE_LEVELS] = ++{ ++ { 0, 1282, 630, 404, 288, 444, 232, 172, 144, 116, 100, 96}, ++ { 0, 1794, 817, 572, 400, 537, 316, 228, 188, 144, 124, 116}, ++ { 0, 2306, 1003, 744, 516, 630, 400, 288, 228, 172, 144, 136}, ++ { 0, 3330, 1375, 1084, 744, 817, 572, 400, 316, 228, 188, 172}, ++ { 0, 6402, 2492, 2108, 1424, 1375, 1084, 740, 572, 400, 316, 284} ++}; ++ ++#define MTO_ONE_EXCHANGE_TIME(preamble_type, frag_th_lvl, data_rate_lvl) \ ++ (preamble_type) ? MTO_One_Exchange_Time_Tbl_s[frag_th_lvl][data_rate_lvl] : \ ++ MTO_One_Exchange_Time_Tbl_l[frag_th_lvl][data_rate_lvl] ++ ++// Declare data rate table ++//The following table will be changed at anytime if the opration rate supported by AP don't ++//match the table ++u8 MTO_Data_Rate_Tbl[MTO_MAX_DATA_RATE_LEVELS] = ++{ ++ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 ++}; ++ ++//The Stardard_Data_Rate_Tbl and Level2PerTbl table is used to indirectly retreive PER ++//information from Rate_PER_TBL ++//The default settings is AP can support full rate set. ++static u8 Stardard_Data_Rate_Tbl[MTO_MAX_DATA_RATE_LEVELS] = ++{ ++ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 ++}; ++static u8 Level2PerTbl[MTO_MAX_DATA_RATE_LEVELS] = ++{ ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ++}; ++//How many kind of tx rate can be supported by AP ++//DTO will change Rate between MTO_Data_Rate_Tbl[0] and MTO_Data_Rate_Tbl[MTO_DataRateAvailableLevel-1] ++static u8 MTO_DataRateAvailableLevel = MTO_MAX_DATA_RATE_LEVELS; ++//Smoothed PER table for each different RATE based on packet length of 1514 ++static int Rate_PER_TBL[91][MTO_MAX_DATA_RATE_LEVELS] = { ++// 1M 2M 5.5M 11M 6M 9M 12M 18M 24M 36M 48M 54M ++/* 0% */{ 93, 177, 420, 538, 690, 774, 1001, 1401, 1768, 2358, 2838, 3039}, ++/* 1% */{ 92, 176, 416, 533, 683, 767, 992, 1389, 1752, 2336, 2811, 3010}, ++/* 2% */{ 91, 174, 412, 528, 675, 760, 983, 1376, 1735, 2313, 2783, 2979}, ++/* 3% */{ 90, 172, 407, 523, 667, 753, 973, 1363, 1719, 2290, 2755, 2948}, ++/* 4% */{ 90, 170, 403, 518, 659, 746, 964, 1350, 1701, 2266, 2726, 2916}, ++/* 5% */{ 89, 169, 398, 512, 651, 738, 954, 1336, 1684, 2242, 2696, 2884}, ++/* 6% */{ 88, 167, 394, 507, 643, 731, 944, 1322, 1666, 2217, 2665, 2851}, ++/* 7% */{ 87, 165, 389, 502, 635, 723, 935, 1308, 1648, 2192, 2634, 2817}, ++/* 8% */{ 86, 163, 384, 497, 626, 716, 924, 1294, 1629, 2166, 2602, 2782}, ++/* 9% */{ 85, 161, 380, 491, 618, 708, 914, 1279, 1611, 2140, 2570, 2747}, ++/* 10% */{ 84, 160, 375, 486, 609, 700, 904, 1265, 1591, 2113, 2537, 2711}, ++/* 11% */{ 83, 158, 370, 480, 600, 692, 894, 1250, 1572, 2086, 2503, 2675}, ++/* 12% */{ 82, 156, 365, 475, 592, 684, 883, 1234, 1552, 2059, 2469, 2638}, ++/* 13% */{ 81, 154, 360, 469, 583, 676, 872, 1219, 1532, 2031, 2435, 2600}, ++/* 14% */{ 80, 152, 355, 464, 574, 668, 862, 1204, 1512, 2003, 2400, 2562}, ++/* 15% */{ 79, 150, 350, 458, 565, 660, 851, 1188, 1492, 1974, 2365, 2524}, ++/* 16% */{ 78, 148, 345, 453, 556, 652, 840, 1172, 1471, 1945, 2329, 2485}, ++/* 17% */{ 77, 146, 340, 447, 547, 643, 829, 1156, 1450, 1916, 2293, 2446}, ++/* 18% */{ 76, 144, 335, 441, 538, 635, 818, 1140, 1429, 1887, 2256, 2406}, ++/* 19% */{ 75, 143, 330, 436, 529, 627, 807, 1124, 1408, 1857, 2219, 2366}, ++/* 20% */{ 74, 141, 325, 430, 520, 618, 795, 1107, 1386, 1827, 2182, 2326}, ++/* 21% */{ 73, 139, 320, 424, 510, 610, 784, 1091, 1365, 1797, 2145, 2285}, ++/* 22% */{ 72, 137, 314, 418, 501, 601, 772, 1074, 1343, 1766, 2107, 2244}, ++/* 23% */{ 71, 135, 309, 412, 492, 592, 761, 1057, 1321, 1736, 2069, 2203}, ++/* 24% */{ 70, 133, 304, 407, 482, 584, 749, 1040, 1299, 1705, 2031, 2161}, ++/* 25% */{ 69, 131, 299, 401, 473, 575, 738, 1023, 1277, 1674, 1992, 2120}, ++/* 26% */{ 68, 129, 293, 395, 464, 566, 726, 1006, 1254, 1642, 1953, 2078}, ++/* 27% */{ 67, 127, 288, 389, 454, 557, 714, 989, 1232, 1611, 1915, 2035}, ++/* 28% */{ 66, 125, 283, 383, 445, 549, 703, 972, 1209, 1579, 1876, 1993}, ++/* 29% */{ 65, 123, 278, 377, 436, 540, 691, 955, 1187, 1548, 1836, 1951}, ++/* 30% */{ 64, 121, 272, 371, 426, 531, 679, 937, 1164, 1516, 1797, 1908}, ++/* 31% */{ 63, 119, 267, 365, 417, 522, 667, 920, 1141, 1484, 1758, 1866}, ++/* 32% */{ 62, 117, 262, 359, 407, 513, 655, 902, 1118, 1453, 1719, 1823}, ++/* 33% */{ 61, 115, 256, 353, 398, 504, 643, 885, 1095, 1421, 1679, 1781}, ++/* 34% */{ 60, 113, 251, 347, 389, 495, 631, 867, 1072, 1389, 1640, 1738}, ++/* 35% */{ 59, 111, 246, 341, 379, 486, 619, 850, 1049, 1357, 1600, 1695}, ++/* 36% */{ 58, 108, 240, 335, 370, 477, 607, 832, 1027, 1325, 1561, 1653}, ++/* 37% */{ 57, 106, 235, 329, 361, 468, 595, 815, 1004, 1293, 1522, 1610}, ++/* 38% */{ 56, 104, 230, 323, 351, 459, 584, 797, 981, 1261, 1483, 1568}, ++/* 39% */{ 55, 102, 224, 317, 342, 450, 572, 780, 958, 1230, 1443, 1526}, ++/* 40% */{ 54, 100, 219, 311, 333, 441, 560, 762, 935, 1198, 1404, 1484}, ++/* 41% */{ 53, 98, 214, 305, 324, 432, 548, 744, 912, 1166, 1366, 1442}, ++/* 42% */{ 52, 96, 209, 299, 315, 423, 536, 727, 889, 1135, 1327, 1400}, ++/* 43% */{ 51, 94, 203, 293, 306, 414, 524, 709, 866, 1104, 1289, 1358}, ++/* 44% */{ 50, 92, 198, 287, 297, 405, 512, 692, 844, 1072, 1250, 1317}, ++/* 45% */{ 49, 90, 193, 281, 288, 396, 500, 675, 821, 1041, 1212, 1276}, ++/* 46% */{ 48, 88, 188, 275, 279, 387, 488, 657, 799, 1011, 1174, 1236}, ++/* 47% */{ 47, 86, 183, 269, 271, 378, 476, 640, 777, 980, 1137, 1195}, ++/* 48% */{ 46, 84, 178, 262, 262, 369, 464, 623, 754, 949, 1100, 1155}, ++/* 49% */{ 45, 82, 173, 256, 254, 360, 452, 606, 732, 919, 1063, 1116}, ++/* 50% */{ 44, 80, 168, 251, 245, 351, 441, 589, 710, 889, 1026, 1076}, ++/* 51% */{ 43, 78, 163, 245, 237, 342, 429, 572, 689, 860, 990, 1038}, ++/* 52% */{ 42, 76, 158, 239, 228, 333, 417, 555, 667, 830, 955, 999}, ++/* 53% */{ 41, 74, 153, 233, 220, 324, 406, 538, 645, 801, 919, 961}, ++/* 54% */{ 40, 72, 148, 227, 212, 315, 394, 522, 624, 773, 884, 924}, ++/* 55% */{ 39, 70, 143, 221, 204, 307, 383, 505, 603, 744, 850, 887}, ++/* 56% */{ 38, 68, 138, 215, 196, 298, 371, 489, 582, 716, 816, 851}, ++/* 57% */{ 37, 67, 134, 209, 189, 289, 360, 473, 562, 688, 783, 815}, ++/* 58% */{ 36, 65, 129, 203, 181, 281, 349, 457, 541, 661, 750, 780}, ++/* 59% */{ 35, 63, 124, 197, 174, 272, 338, 441, 521, 634, 717, 745}, ++/* 60% */{ 34, 61, 120, 192, 166, 264, 327, 425, 501, 608, 686, 712}, ++/* 61% */{ 33, 59, 115, 186, 159, 255, 316, 409, 482, 582, 655, 678}, ++/* 62% */{ 32, 57, 111, 180, 152, 247, 305, 394, 462, 556, 624, 646}, ++/* 63% */{ 31, 55, 107, 174, 145, 238, 294, 379, 443, 531, 594, 614}, ++/* 64% */{ 30, 53, 102, 169, 138, 230, 283, 364, 425, 506, 565, 583}, ++/* 65% */{ 29, 52, 98, 163, 132, 222, 273, 349, 406, 482, 536, 553}, ++/* 66% */{ 28, 50, 94, 158, 125, 214, 262, 334, 388, 459, 508, 523}, ++/* 67% */{ 27, 48, 90, 152, 119, 206, 252, 320, 370, 436, 481, 495}, ++/* 68% */{ 26, 46, 86, 147, 113, 198, 242, 306, 353, 413, 455, 467}, ++/* 69% */{ 26, 44, 82, 141, 107, 190, 231, 292, 336, 391, 429, 440}, ++/* 70% */{ 25, 43, 78, 136, 101, 182, 221, 278, 319, 370, 405, 414}, ++/* 71% */{ 24, 41, 74, 130, 95, 174, 212, 265, 303, 350, 381, 389}, ++/* 72% */{ 23, 39, 71, 125, 90, 167, 202, 252, 287, 329, 358, 365}, ++/* 73% */{ 22, 37, 67, 119, 85, 159, 192, 239, 271, 310, 335, 342}, ++/* 74% */{ 21, 36, 63, 114, 80, 151, 183, 226, 256, 291, 314, 320}, ++/* 75% */{ 20, 34, 60, 109, 75, 144, 174, 214, 241, 273, 294, 298}, ++/* 76% */{ 19, 32, 57, 104, 70, 137, 164, 202, 227, 256, 274, 278}, ++/* 77% */{ 18, 31, 53, 99, 66, 130, 155, 190, 213, 239, 256, 259}, ++/* 78% */{ 17, 29, 50, 94, 62, 122, 146, 178, 200, 223, 238, 241}, ++/* 79% */{ 16, 28, 47, 89, 58, 115, 138, 167, 187, 208, 222, 225}, ++/* 80% */{ 16, 26, 44, 84, 54, 109, 129, 156, 175, 194, 206, 209}, ++/* 81% */{ 15, 24, 41, 79, 50, 102, 121, 146, 163, 180, 192, 194}, ++/* 82% */{ 14, 23, 39, 74, 47, 95, 113, 136, 151, 167, 178, 181}, ++/* 83% */{ 13, 21, 36, 69, 44, 89, 105, 126, 140, 155, 166, 169}, ++/* 84% */{ 12, 20, 33, 64, 41, 82, 97, 116, 130, 144, 155, 158}, ++/* 85% */{ 11, 19, 31, 60, 39, 76, 89, 107, 120, 134, 145, 149}, ++/* 86% */{ 11, 17, 29, 55, 36, 70, 82, 98, 110, 125, 136, 140}, ++/* 87% */{ 10, 16, 26, 51, 34, 64, 75, 90, 102, 116, 128, 133}, ++/* 88% */{ 9, 14, 24, 46, 32, 58, 68, 81, 93, 108, 121, 128}, ++/* 89% */{ 8, 13, 22, 42, 31, 52, 61, 74, 86, 102, 116, 124}, ++/* 90% */{ 7, 12, 21, 37, 29, 46, 54, 66, 79, 96, 112, 121} ++}; ++ ++#define RSSIBUF_NUM 10 ++#define RSSI2RATE_SIZE 9 ++ ++static TXRETRY_REC TxRateRec={MTO_MAX_DATA_RATE_LEVELS - 1, 0}; //new record=>TxRateRec ++static int TxRetryRate; ++//static int SQ3, BSS_PK_CNT, NIDLESLOT, SLOT_CNT, INTERF_CNT, GAP_CNT, DS_EVM; ++static s32 RSSIBuf[RSSIBUF_NUM]={-70, -70, -70, -70, -70, -70, -70, -70, -70, -70}; ++static s32 RSSISmoothed=-700; ++static int RSSIBufIndex=0; ++static u8 max_rssi_rate; ++static int rate_tbl[13] = {0,1,2,5,11,6,9,12,18,24,36,48,54}; ++//[WKCHEN]static core_data_t *pMTOcore_data=NULL; ++ ++static int TotalTxPkt = 0; ++static int TotalTxPktRetry = 0; ++static int TxPktPerAnt[3] = {0,0,0}; ++static int RXRSSIANT[3] ={-70,-70,-70}; ++static int TxPktRetryPerAnt[3] = {0,0,0}; ++//static int TxDominateFlag=FALSE; ++static u8 old_antenna[4]={1 ,0 ,1 ,0}; ++static int retryrate_rec[MTO_MAX_DATA_RATE_LEVELS];//this record the retry rate at different data rate ++ ++static int PeriodTotalTxPkt = 0; ++static int PeriodTotalTxPktRetry = 0; ++ ++typedef struct ++{ ++ s32 RSSI; ++ u8 TxRate; ++}RSSI2RATE; ++ ++static RSSI2RATE RSSI2RateTbl[RSSI2RATE_SIZE] = ++{ ++ {-740, 108}, // 54M ++ {-760, 96}, // 48M ++ {-820, 72}, // 36M ++ {-850, 48}, // 24M ++ {-870, 36}, // 18M ++ {-890, 24}, // 12M ++ {-900, 12}, // 6M ++ {-920, 11}, // 5.5M ++ {-950, 4}, // 2M ++}; ++static u8 untogglecount; ++static u8 last_rate_ant; //this is used for antenna backoff-hh ++ ++u8 boSparseTxTraffic = FALSE; ++ ++void MTO_Init(MTO_FUNC_INPUT); ++void AntennaToggleInitiator(MTO_FUNC_INPUT); ++void AntennaToggleState(MTO_FUNC_INPUT); ++void TxPwrControl(MTO_FUNC_INPUT); ++void GetFreshAntennaData(MTO_FUNC_INPUT); ++void TxRateReductionCtrl(MTO_FUNC_INPUT); ++/** 1.1.31.1000 Turbo modify */ ++//void MTO_SetDTORateRange(int type); ++void MTO_SetDTORateRange(MTO_FUNC_INPUT, u8 *pRateArray, u8 ArraySize); ++void MTO_SetTxCount(MTO_FUNC_INPUT, u8 t0, u8 index); ++void MTO_TxFailed(MTO_FUNC_INPUT); ++void SmoothRSSI(s32 new_rssi); ++void hal_get_dto_para(MTO_FUNC_INPUT, char *buffer); ++u8 CalcNewRate(MTO_FUNC_INPUT, u8 old_rate, u32 retry_cnt, u32 tx_frag_cnt); ++u8 GetMaxRateLevelFromRSSI(void); ++u8 MTO_GetTxFallbackRate(MTO_FUNC_INPUT); ++int Divide(int a, int b); ++void multiagc(MTO_FUNC_INPUT, u8 high_gain_mode); ++ ++//=========================================================================== ++// MTO_Init -- ++// ++// Description: ++// Set DTO Tx Rate Scope because different AP could have different Rate set. ++// After our staion join with AP, LM core will call this function to initialize ++// Tx Rate table. ++// ++// Arguments: ++// pRateArray - The pointer to the Tx Rate Array by the following order ++// - 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 ++// - DTO won't check whether rate order is invalid or not ++// ArraySize - The array size to indicate how many tx rate we can choose ++// ++// sample code: ++// { ++// u8 RateArray[4] = {2, 4, 11, 22}; ++// MTO_SetDTORateRange(RateArray, 4); ++// } ++// ++// Return Value: ++// None ++//============================================================================ ++void MTO_SetDTORateRange(MTO_FUNC_INPUT,u8 *pRateArray, u8 ArraySize) ++{ ++ u8 i, j=0; ++ ++ for(i=0;i0;i--) ++ { ++ if(pRateArray[i-1] <= 11) ++ break; ++ pRateArray[i] = pRateArray[i-1]; ++ } ++ pRateArray[i] = 22; ++ MTO_OFDM_RATE_LEVEL() = i; ++ } ++ else ++ { ++ for(i=0; i= 12) ++ break; ++ } ++ MTO_OFDM_RATE_LEVEL() = i; ++ } ++ ++ for(i=0;i MTO_Init()\n")); ++ //[WKCHEN]pMTOcore_data = pcore_data; ++// 20040510 Turbo add for global variable ++ MTO_TMR_CNT() = 0; ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE; ++ MTO_TX_RATE_REDUCTION_STATE() = RATE_CHGSTATE_IDLE; ++ MTO_BACKOFF_TMR() = 0; ++ MTO_LAST_RATE() = 11; ++ MTO_CO_EFFICENT() = 0; ++ ++ //MTO_TH_FIXANT() = MTO_DEFAULT_TH_FIXANT; ++ MTO_TH_CNT() = MTO_DEFAULT_TH_CNT; ++ MTO_TH_SQ3() = MTO_DEFAULT_TH_SQ3; ++ MTO_TH_IDLE_SLOT() = MTO_DEFAULT_TH_IDLE_SLOT; ++ MTO_TH_PR_INTERF() = MTO_DEFAULT_TH_PR_INTERF; ++ ++ MTO_TMR_AGING() = MTO_DEFAULT_TMR_AGING; ++ MTO_TMR_PERIODIC() = MTO_DEFAULT_TMR_PERIODIC; ++ ++ //[WKCHEN]MTO_CCA_MODE_SETUP()= (u8) hal_get_cca_mode(MTO_HAL()); ++ //[WKCHEN]MTO_CCA_MODE() = MTO_CCA_MODE_SETUP(); ++ ++ //MTO_PREAMBLE_TYPE() = MTO_PREAMBLE_LONG; ++ MTO_PREAMBLE_TYPE() = MTO_PREAMBLE_SHORT; // for test ++ ++ MTO_ANT_SEL() = hal_get_antenna_number(MTO_HAL()); ++ MTO_ANT_MAC() = MTO_ANT_SEL(); ++ MTO_CNT_ANT(0) = 0; ++ MTO_CNT_ANT(1) = 0; ++ MTO_SQ_ANT(0) = 0; ++ MTO_SQ_ANT(1) = 0; ++ MTO_ANT_DIVERSITY() = MTO_ANTENNA_DIVERSITY_ON; ++ //CardSet_AntennaDiversity(Adapter, MTO_ANT_DIVERSITY()); ++ //PLMESetAntennaDiversity( Adapter, MTO_ANT_DIVERSITY()); ++ ++ MTO_AGING_TIMEOUT() = 0;//MTO_TMR_AGING() / MTO_TMR_PERIODIC(); ++ ++ // The following parameters should be initialized to the values set by user ++ // ++ //MTO_RATE_LEVEL() = 10; ++ MTO_RATE_LEVEL() = 0; ++ MTO_FALLBACK_RATE_LEVEL() = MTO_RATE_LEVEL(); ++ MTO_FRAG_TH_LEVEL() = 4; ++ /** 1.1.23.1000 Turbo modify from -1 to +1 ++ MTO_RTS_THRESHOLD() = MTO_FRAG_TH() - 1; ++ MTO_RTS_THRESHOLD_SETUP() = MTO_FRAG_TH() - 1; ++ */ ++ MTO_RTS_THRESHOLD() = MTO_FRAG_TH() + 1; ++ MTO_RTS_THRESHOLD_SETUP() = MTO_FRAG_TH() + 1; ++ // 1.1.23.1000 Turbo add for mto change preamble from 0 to 1 ++ MTO_RATE_CHANGE_ENABLE() = 1; ++ MTO_FRAG_CHANGE_ENABLE() = 0; // 1.1.29.1000 Turbo add don't support frag ++ //The default valud of ANTDIV_DEFAULT_ON will be decided by EEPROM ++ //#ifdef ANTDIV_DEFAULT_ON ++ //MTO_ANT_DIVERSITY_ENABLE() = 1; ++ //#else ++ //MTO_ANT_DIVERSITY_ENABLE() = 0; ++ //#endif ++ MTO_POWER_CHANGE_ENABLE() = 1; ++ MTO_PREAMBLE_CHANGE_ENABLE()= 1; ++ MTO_RTS_CHANGE_ENABLE() = 0; // 1.1.29.1000 Turbo add don't support frag ++ // 20040512 Turbo add ++ //old_antenna[0] = 1; ++ //old_antenna[1] = 0; ++ //old_antenna[2] = 1; ++ //old_antenna[3] = 0; ++ for (i=0;iphy_type) ++ { ++ case RF_AIROHA_2230: ++ case RF_AIROHA_2230S: // 20060420 Add this ++ MTOPARA_TXPOWER_INDEX() = 46; // MAX-8 // @@ Only for AL 2230 ++ break; ++ case RF_AIROHA_7230: ++ MTOPARA_TXPOWER_INDEX() = 49; ++ break; ++ case RF_WB_242: ++ MTOPARA_TXPOWER_INDEX() = 10; ++ break; ++ case RF_WB_242_1: ++ MTOPARA_TXPOWER_INDEX() = 24; // ->10 20060316.1 modify ++ break; ++ } ++ } ++ else //follow the setting from EEPROM ++ MTOPARA_TXPOWER_INDEX() = MTO_TXPOWER_FROM_EEPROM; ++ hal_set_rf_power(MTO_HAL(), (u8)MTOPARA_TXPOWER_INDEX()); ++ //------------------------------------------------ ++ ++ // For RSSI turning 20060808.4 Cancel load from EEPROM ++ MTO_DATA().RSSI_high = -41; ++ MTO_DATA().RSSI_low = -60; ++} ++ ++//---------------------------------------------------------------------------// ++static u32 DTO_Rx_Info[13][3]; ++static u32 DTO_RxCRCFail_Info[13][3]; ++static u32 AntennaToggleBkoffTimer=5; ++typedef struct{ ++ int RxRate; ++ int RxRatePkts; ++ int index; ++}RXRATE_ANT; ++RXRATE_ANT RxRatePeakAnt[3]; ++ ++#define ANT0 0 ++#define ANT1 1 ++#define OLD_ANT 2 ++ ++void SearchPeakRxRate(int index) ++{ ++ int i; ++ RxRatePeakAnt[index].RxRatePkts=0; ++ //Find out the best rx rate which is used on different antenna ++ for(i=1;i<13;i++) ++ { ++ if(DTO_Rx_Info[i][index] > (u32) RxRatePeakAnt[index].RxRatePkts) ++ { ++ RxRatePeakAnt[index].RxRatePkts = DTO_Rx_Info[i][index]; ++ RxRatePeakAnt[index].RxRate = rate_tbl[i]; ++ RxRatePeakAnt[index].index = i; ++ } ++ } ++} ++ ++void ResetDTO_RxInfo(int index, MTO_FUNC_INPUT) ++{ ++ int i; ++ ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("ResetDTOrx\n")); ++ #endif ++ ++ for(i=0;i<13;i++) ++ DTO_Rx_Info[i][index] = MTO_HAL()->rx_ok_count[i]; ++ ++ for(i=0;i<13;i++) ++ DTO_RxCRCFail_Info[i][index] = MTO_HAL()->rx_err_count[i]; ++ ++ TotalTxPkt = 0; ++ TotalTxPktRetry = 0; ++} ++ ++void GetDTO_RxInfo(int index, MTO_FUNC_INPUT) ++{ ++ int i; ++ ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("GetDTOrx\n")); ++ #endif ++ ++ //PDEBUG(("[MTO]:DTO_Rx_Info[%d]=%d, rx_ok_count=%d\n", index, DTO_Rx_Info[0][index], phw_data->rx_ok_count[0])); ++ for(i=0;i<13;i++) ++ DTO_Rx_Info[i][index] = abs(MTO_HAL()->rx_ok_count[i] - DTO_Rx_Info[i][index]); ++ if(DTO_Rx_Info[0][index]==0) DTO_Rx_Info[0][index] = 1; ++ ++ for(i=0;i<13;i++) ++ DTO_RxCRCFail_Info[i][index] = MTO_HAL()->rx_err_count[i] - DTO_RxCRCFail_Info[i][index]; ++ ++ TxPktPerAnt[index] = TotalTxPkt; ++ TxPktRetryPerAnt[index] = TotalTxPktRetry; ++ TotalTxPkt = 0; ++ TotalTxPktRetry = 0; ++} ++ ++void OutputDebugInfo(int index1, int index2) ++{ ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:Total Rx (%d)\t\t(%d) \n ", DTO_Rx_Info[0][index1], DTO_Rx_Info[0][index2])); ++ WBDEBUG(("[HHDTO]:RECEIVE RSSI: (%d)\t\t(%d) \n ", RXRSSIANT[index1], RXRSSIANT[index2])); ++ WBDEBUG(("[HHDTO]:TX packet correct rate: (%d)%%\t\t(%d)%% \n ",Divide(TxPktPerAnt[index1]*100,TxPktRetryPerAnt[index1]), Divide(TxPktPerAnt[index2]*100,TxPktRetryPerAnt[index2]))); ++ #endif ++ { ++ int tmp1, tmp2; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:Total Tx (%d)\t\t(%d) \n ", TxPktPerAnt[index1], TxPktPerAnt[index2])); ++ WBDEBUG(("[HHDTO]:Total Tx retry (%d)\t\t(%d) \n ", TxPktRetryPerAnt[index1], TxPktRetryPerAnt[index2])); ++ #endif ++ tmp1 = TxPktPerAnt[index1] + DTO_Rx_Info[0][index1]; ++ tmp2 = TxPktPerAnt[index2] + DTO_Rx_Info[0][index2]; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:Total Tx+RX (%d)\t\t(%d) \n ", tmp1, tmp2)); ++ #endif ++ } ++} ++ ++unsigned char TxDominate(int index) ++{ ++ int tmp; ++ ++ tmp = TxPktPerAnt[index] + DTO_Rx_Info[0][index]; ++ ++ if(Divide(TxPktPerAnt[index]*100, tmp) > 40) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++unsigned char CmpTxRetryRate(int index1, int index2) ++{ ++ int tx_retry_rate1, tx_retry_rate2; ++ tx_retry_rate1 = Divide((TxPktRetryPerAnt[index1] - TxPktPerAnt[index1])*100, TxPktRetryPerAnt[index1]); ++ tx_retry_rate2 = Divide((TxPktRetryPerAnt[index2] - TxPktPerAnt[index2])*100, TxPktRetryPerAnt[index2]); ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[MTO]:TxRetry Ant0: (%d%%) Ant1: (%d%%) \n ", tx_retry_rate1, tx_retry_rate2)); ++ #endif ++ ++ if(tx_retry_rate1 > tx_retry_rate2) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++void GetFreshAntennaData(MTO_FUNC_INPUT) ++{ ++ u8 x; ++ ++ x = hal_get_antenna_number(MTO_HAL()); ++ //hal_get_bss_pk_cnt(MTO_HAL()); ++ //hal_get_est_sq3(MTO_HAL(), 1); ++ old_antenna[0] = x; ++ //if this is the function for timer ++ ResetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA); ++ if(AntennaToggleBkoffTimer) ++ AntennaToggleBkoffTimer--; ++ if (abs(last_rate_ant-MTO_RATE_LEVEL())>1) //backoff timer reset ++ AntennaToggleBkoffTimer=0; ++ ++ if (MTO_ANT_DIVERSITY() != MTO_ANTENNA_DIVERSITY_ON || ++ MTO_ANT_DIVERSITY_ENABLE() != 1) ++ AntennaToggleBkoffTimer=1; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:**last data rate=%d,now data rate=%d**antenna toggle timer=%d",last_rate_ant,MTO_RATE_LEVEL(),AntennaToggleBkoffTimer)); ++ #endif ++ last_rate_ant=MTO_RATE_LEVEL(); ++ if(AntennaToggleBkoffTimer==0) ++ { ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_WAIT0; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:===state is starting==for antenna toggle===")); ++ #endif ++ } ++ else ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE; ++ ++ if ((MTO_BACKOFF_TMR()!=0)&&(MTO_RATE_LEVEL()>MTO_DataRateAvailableLevel - 3)) ++ { ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:===the data rate is %d (good)and will not toogle ===",MTO_DATA_RATE()>>1)); ++ #endif ++ } ++ ++ ++} ++ ++int WB_PCR[2]; //packet correct rate ++ ++void AntennaToggleState(MTO_FUNC_INPUT) ++{ ++ int decideantflag = 0; ++ u8 x; ++ s32 rssi; ++ ++ if(MTO_ANT_DIVERSITY_ENABLE() != 1) ++ return; ++ x = hal_get_antenna_number(MTO_HAL()); ++ switch(MTO_TOGGLE_STATE()) ++ { ++ ++ //Missing..... ++ case TOGGLE_STATE_IDLE: ++ case TOGGLE_STATE_BKOFF: ++ break;; ++ ++ case TOGGLE_STATE_WAIT0://======== ++ GetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA); ++ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi); ++ RXRSSIANT[x] = rssi; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO] **wait0==== Collecting Ant%d--rssi=%d\n", x,RXRSSIANT[x])); ++ #endif ++ ++ //change antenna and reset the data at changed antenna ++ x = (~x) & 0x01; ++ MTO_ANT_SEL() = x; ++ hal_set_antenna_number(MTO_HAL(), MTO_ANT_SEL()); ++ LOCAL_ANTENNA_NO() = x; ++ ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_WAIT1;//go to wait1 ++ ResetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA); ++ break; ++ case TOGGLE_STATE_WAIT1://=====wait1 ++ //MTO_CNT_ANT(x) = hal_get_bss_pk_cnt(MTO_HAL()); ++ //RXRSSIANT[x] = hal_get_rssi(MTO_HAL()); ++ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi); ++ RXRSSIANT[x] = rssi; ++ GetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA); ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO] **wait1==== Collecting Ant%d--rssi=%d\n", x,RXRSSIANT[x])); ++ #endif ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_MAKEDESISION; ++ break; ++ case TOGGLE_STATE_MAKEDESISION: ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:Ant--0-----------------1---\n")); ++ OutputDebugInfo(ANT0,ANT1); ++ #endif ++ //PDEBUG(("[HHDTO] **decision====\n ")); ++ ++ //=====following is the decision produrce ++ // ++ // first: compare the rssi if difference >10 ++ // select the larger one ++ // ,others go to second ++ // second: comapre the tx+rx packet count if difference >100 ++ // use larger total packets antenna ++ // third::compare the tx PER if packets>20 ++ // if difference >5% using the bigger one ++ // ++ // fourth:compare the RX PER if packets>20 ++ // if PER difference <5% ++ // using old antenna ++ // ++ // ++ if (abs(RXRSSIANT[ANT0]-RXRSSIANT[ANT1]) > MTOPARA_RSSI_TH_FOR_ANTDIV())//====rssi_th ++ { ++ if (RXRSSIANT[ANT0]>RXRSSIANT[ANT1]) ++ { ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT0; ++ } ++ else ++ { ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT1; ++ } ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("Select antenna by RSSI\n")); ++ #endif ++ } ++ else if (abs(TxPktPerAnt[ANT0] + DTO_Rx_Info[0][ANT0]-TxPktPerAnt[ANT1]-DTO_Rx_Info[0][ANT1])<50)//=====total packet_th ++ { ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("Total tx/rx is close\n")); ++ #endif ++ if (TxDominate(ANT0) && TxDominate(ANT1)) ++ { ++ if ((TxPktPerAnt[ANT0]>10) && (TxPktPerAnt[ANT1]>10))//====tx packet_th ++ { ++ WB_PCR[ANT0]=Divide(TxPktPerAnt[ANT0]*100,TxPktRetryPerAnt[ANT0]); ++ WB_PCR[ANT1]=Divide(TxPktPerAnt[ANT1]*100,TxPktRetryPerAnt[ANT1]); ++ if (abs(WB_PCR[ANT0]-WB_PCR[ANT1])>5)// tx PER_th ++ { ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("Decide by Tx correct rate\n")); ++ #endif ++ if (WB_PCR[ANT0]>WB_PCR[ANT1]) ++ { ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT0; ++ } ++ else ++ { ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT1; ++ } ++ } ++ else ++ { ++ decideantflag=0; ++ untogglecount++; ++ MTO_ANT_MAC() = old_antenna[0]; ++ } ++ } ++ else ++ { ++ decideantflag=0; ++ MTO_ANT_MAC() = old_antenna[0]; ++ } ++ } ++ else if ((DTO_Rx_Info[0][ANT0]>10)&&(DTO_Rx_Info[0][ANT1]>10))//rx packet th ++ { ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("Decide by Rx\n")); ++ #endif ++ if (abs(DTO_Rx_Info[0][ANT0] - DTO_Rx_Info[0][ANT1])>50) ++ { ++ if (DTO_Rx_Info[0][ANT0] > DTO_Rx_Info[0][ANT1]) ++ { ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT0; ++ } ++ else ++ { ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT1; ++ } ++ } ++ else ++ { ++ decideantflag=0; ++ untogglecount++; ++ MTO_ANT_MAC() = old_antenna[0]; ++ } ++ } ++ else ++ { ++ decideantflag=0; ++ MTO_ANT_MAC() = old_antenna[0]; ++ } ++ } ++ else if ((TxPktPerAnt[ANT0]+DTO_Rx_Info[0][ANT0])>(TxPktPerAnt[ANT1]+DTO_Rx_Info[0][ANT1]))//use more packekts ++ { ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("decide by total tx/rx : ANT 0\n")); ++ #endif ++ ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT0; ++ } ++ else ++ { ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("decide by total tx/rx : ANT 1\n")); ++ #endif ++ decideantflag=1; ++ MTO_ANT_MAC() = ANT1; ++ ++ } ++ //this is force ant toggle ++ if (decideantflag==1) ++ untogglecount=0; ++ ++ untogglecount=untogglecount%4; ++ if (untogglecount==3) //change antenna ++ MTO_ANT_MAC() = ((~old_antenna[0]) & 0x1); ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:==================untoggle-count=%d",untogglecount)); ++ #endif ++ ++ ++ ++ ++ //PDEBUG(("[HHDTO] **********************************DTO ENABLE=%d",MTO_ANT_DIVERSITY_ENABLE())); ++ if(MTO_ANT_DIVERSITY_ENABLE() == 1) ++ { ++ MTO_ANT_SEL() = MTO_ANT_MAC(); ++ hal_set_antenna_number(MTO_HAL(), MTO_ANT_SEL()); ++ LOCAL_ANTENNA_NO() = MTO_ANT_SEL(); ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO] ==decision==*******antflag=%d******************selected antenna=%d\n",decideantflag,MTO_ANT_SEL())); ++ #endif ++ } ++ if (decideantflag) ++ { ++ old_antenna[3]=old_antenna[2];//store antenna info ++ old_antenna[2]=old_antenna[1]; ++ old_antenna[1]=old_antenna[0]; ++ old_antenna[0]= MTO_ANT_MAC(); ++ } ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:**old antenna=[%d][%d][%d][%d]\n",old_antenna[0],old_antenna[1],old_antenna[2],old_antenna[3])); ++ #endif ++ if (old_antenna[0]!=old_antenna[1]) ++ AntennaToggleBkoffTimer=0; ++ else if (old_antenna[1]!=old_antenna[2]) ++ AntennaToggleBkoffTimer=1; ++ else if (old_antenna[2]!=old_antenna[3]) ++ AntennaToggleBkoffTimer=2; ++ else ++ AntennaToggleBkoffTimer=4; ++ ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTO]:**back off timer=%d",AntennaToggleBkoffTimer)); ++ #endif ++ ++ ResetDTO_RxInfo(MTO_ANT_MAC(), MTO_FUNC_INPUT_DATA); ++ if (AntennaToggleBkoffTimer==0 && decideantflag) ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_WAIT0; ++ else ++ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE; ++ break; ++ } ++ ++} ++ ++void multiagc(MTO_FUNC_INPUT, u8 high_gain_mode ) ++{ ++ s32 rssi; ++ hw_data_t *pHwData = MTO_HAL(); ++ ++ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi); ++ ++ if( (RF_WB_242 == pHwData->phy_type) || ++ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add ++ { ++ if (high_gain_mode==1) ++ { ++ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f52230); ++ //hw_set_dxx_reg(phw_data, 0x20, 0x06C43440); ++ Wb35Reg_Write( pHwData, 0x100C, 0xF2F32232 ); // 940916 0xf8f52230 ); ++ Wb35Reg_Write( pHwData, 0x1020, 0x04cb3440 ); // 940915 0x06C43440 ++ } ++ else if (high_gain_mode==0) ++ { ++ //hw_set_dxx_reg(phw_data, 0x0C, 0xEEEE000D); ++ //hw_set_dxx_reg(phw_data, 0x20, 0x06c41440); ++ Wb35Reg_Write( pHwData, 0x100C, 0xEEEE000D ); ++ Wb35Reg_Write( pHwData, 0x1020, 0x04cb1440 ); // 940915 0x06c41440 ++ } ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[HHDTOAGC] **rssi=%d, high gain mode=%d", rssi, high_gain_mode)); ++ #endif ++ } ++} ++ ++void TxPwrControl(MTO_FUNC_INPUT) ++{ ++ s32 rssi; ++ hw_data_t *pHwData = MTO_HAL(); ++ ++ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi); ++ if( (RF_WB_242 == pHwData->phy_type) || ++ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add ++ { ++ static u8 high_gain_mode; //this is for winbond RF switch LNA ++ //using different register setting ++ ++ if (high_gain_mode==1) ++ { ++ if( rssi > MTO_DATA().RSSI_high ) ++ { ++ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f52230); ++ //hw_set_dxx_reg(phw_data, 0x20, 0x05541640); ++ high_gain_mode=0; ++ } ++ else ++ { ++ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f51830); ++ //hw_set_dxx_reg(phw_data, 0x20, 0x05543E40); ++ high_gain_mode=1; ++ } ++ } ++ else //if (high_gain_mode==0) ++ { ++ if( rssi < MTO_DATA().RSSI_low ) ++ { ++ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f51830); ++ //hw_set_dxx_reg(phw_data, 0x20, 0x05543E40); ++ high_gain_mode=1; ++ } ++ else ++ { ++ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f52230); ++ //hw_set_dxx_reg(phw_data, 0x20, 0x05541640); ++ high_gain_mode=0; ++ } ++ } ++ ++ // Always high gain 20051014. Using the initial value only. ++ multiagc(MTO_FUNC_INPUT_DATA, high_gain_mode); ++ } ++} ++ ++ ++u8 CalcNewRate(MTO_FUNC_INPUT, u8 old_rate, u32 retry_cnt, u32 tx_frag_cnt) ++{ ++ int i; ++ u8 new_rate; ++ u32 retry_rate; ++ int TxThrouput1, TxThrouput2, TxThrouput3, BestThroupht; ++ ++ if(tx_frag_cnt < MTOPARA_TXCOUNT_TH_FOR_CALC_RATE()) //too few packets transmit ++ { ++ return 0xff; ++ } ++ retry_rate = Divide(retry_cnt * 100, tx_frag_cnt); ++ ++ if(retry_rate > 90) retry_rate = 90; //always truncate to 90% due to lookup table size ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("##### Current level =%d, Retry count =%d, Frag count =%d\n", ++ old_rate, retry_cnt, tx_frag_cnt)); ++ WBDEBUG(("*##* Retry rate =%d, throughput =%d\n", ++ retry_rate, Rate_PER_TBL[retry_rate][old_rate])); ++ WBDEBUG(("TxRateRec.tx_rate =%d, Retry rate = %d, throughput = %d\n", ++ TxRateRec.tx_rate, TxRateRec.tx_retry_rate, ++ Rate_PER_TBL[TxRateRec.tx_retry_rate][Level2PerTbl[TxRateRec.tx_rate]])); ++ WBDEBUG(("old_rate-1 =%d, Retry rate = %d, throughput = %d\n", ++ old_rate-1, retryrate_rec[old_rate-1], ++ Rate_PER_TBL[retryrate_rec[old_rate-1]][old_rate-1])); ++ WBDEBUG(("old_rate+1 =%d, Retry rate = %d, throughput = %d\n", ++ old_rate+1, retryrate_rec[old_rate+1], ++ Rate_PER_TBL[retryrate_rec[old_rate+1]][old_rate+1])); ++ #endif ++ ++ //following is for record the retry rate at the different data rate ++ if (abs(retry_rate-retryrate_rec[old_rate])<50)//---the per TH ++ retryrate_rec[old_rate] = retry_rate; //update retry rate ++ else ++ { ++ for (i=0;i old_rate) //Decrease Tx Rate ++ { ++ TxThrouput1 = Rate_PER_TBL[TxRateRec.tx_retry_rate][Level2PerTbl[TxRateRec.tx_rate]]; ++ TxThrouput2 = Rate_PER_TBL[retry_rate][Level2PerTbl[old_rate]]; ++ if(TxThrouput1 > TxThrouput2) ++ { ++ new_rate = TxRateRec.tx_rate; ++ BestThroupht = TxThrouput1; ++ } ++ else ++ { ++ new_rate = old_rate; ++ BestThroupht = TxThrouput2; ++ } ++ if((old_rate > 0) &&(retry_rate>MTOPARA_TXRATE_DEC_TH())) //Min Rate ++ { ++ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate-1]][Level2PerTbl[old_rate-1]]; ++ if(BestThroupht < TxThrouput3) ++ { ++ new_rate = old_rate - 1; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("--------\n")); ++ #endif ++ BestThroupht = TxThrouput3; ++ } ++ } ++ } ++ else if(TxRateRec.tx_rate < old_rate) //Increase Tx Rate ++ { ++ TxThrouput1 = Rate_PER_TBL[TxRateRec.tx_retry_rate][Level2PerTbl[TxRateRec.tx_rate]]; ++ TxThrouput2 = Rate_PER_TBL[retry_rate][Level2PerTbl[old_rate]]; ++ if(TxThrouput1 > TxThrouput2) ++ { ++ new_rate = TxRateRec.tx_rate; ++ BestThroupht = TxThrouput1; ++ } ++ else ++ { ++ new_rate = old_rate; ++ BestThroupht = TxThrouput2; ++ } ++ if ((old_rate < MTO_DataRateAvailableLevel - 1)&&(retry_rate MTOPARA_TXRETRYRATE_REDUCE()) ++ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]-MTOPARA_TXRETRYRATE_REDUCE()][Level2PerTbl[old_rate+1]]; ++ else ++ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]][Level2PerTbl[old_rate+1]]; ++ if(BestThroupht < TxThrouput3) ++ { ++ new_rate = old_rate + 1; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("++++++++++\n")); ++ #endif ++ BestThroupht = TxThrouput3; ++ } ++ } ++ } ++ else //Tx Rate no change ++ { ++ TxThrouput2 = Rate_PER_TBL[retry_rate][Level2PerTbl[old_rate]]; ++ new_rate = old_rate; ++ BestThroupht = TxThrouput2; ++ ++ if (retry_rate MTOPARA_TXRETRYRATE_REDUCE()) ++ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]-MTOPARA_TXRETRYRATE_REDUCE()][Level2PerTbl[old_rate+1]]; ++ else ++ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]][Level2PerTbl[old_rate+1]]; ++ if(BestThroupht < TxThrouput3) ++ { ++ new_rate = old_rate + 1; ++ BestThroupht = TxThrouput3; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("=++++++++++\n")); ++ #endif ++ } ++ } ++ } ++ else ++ if(old_rate > 0) //Min Rate ++ { ++ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate-1]][Level2PerTbl[old_rate-1]]; ++ if(BestThroupht < TxThrouput3) ++ { ++ new_rate = old_rate - 1; ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("=--------\n")); ++ #endif ++ BestThroupht = TxThrouput3; ++ } ++ } ++ } ++ ++ if (!LOCAL_IS_IBSS_MODE()) ++ { ++ max_rssi_rate = GetMaxRateLevelFromRSSI(); ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[MTO]:RSSI2Rate=%d\n", MTO_Data_Rate_Tbl[max_rssi_rate])); ++ #endif ++ if(new_rate > max_rssi_rate) ++ new_rate = max_rssi_rate; ++ } ++ ++ //save new rate; ++ TxRateRec.tx_rate = old_rate; ++ TxRateRec.tx_retry_rate = (u8) retry_rate; ++ TxRetryRate = retry_rate; ++ return new_rate; ++} ++ ++void SmoothRSSI(s32 new_rssi) ++{ ++ RSSISmoothed = RSSISmoothed + new_rssi - RSSIBuf[RSSIBufIndex]; ++ RSSIBuf[RSSIBufIndex] = new_rssi; ++ RSSIBufIndex = (RSSIBufIndex + 1) % 10; ++} ++ ++u8 GetMaxRateLevelFromRSSI(void) ++{ ++ u8 i; ++ u8 TxRate; ++ ++ for(i=0;i RSSI2RateTbl[i].RSSI) ++ break; ++ } ++ #ifdef _PE_DTO_DUMP_ ++ WBDEBUG(("[MTO]:RSSI=%d\n", Divide(RSSISmoothed, 10))); ++ #endif ++ if(i < RSSI2RATE_SIZE) ++ TxRate = RSSI2RateTbl[i].TxRate; ++ else ++ TxRate = 2; //divided by 2 = 1Mbps ++ ++ for(i=MTO_DataRateAvailableLevel-1;i>0;i--) ++ { ++ if(TxRate >=MTO_Data_Rate_Tbl[i]) ++ break; ++ } ++ return i; ++} ++ ++//=========================================================================== ++// Description: ++// If we enable DTO, we will ignore the tx count with different tx rate from ++// DTO rate. This is because when we adjust DTO tx rate, there could be some ++// packets in the tx queue with previous tx rate ++void MTO_SetTxCount(MTO_FUNC_INPUT, u8 tx_rate, u8 index) ++{ ++ MTO_TXFLOWCOUNT()++; ++ if ((MTO_ENABLE==1) && (MTO_RATE_CHANGE_ENABLE()==1)) ++ { ++ if(tx_rate == MTO_DATA_RATE()) ++ { ++ if (index == 0) ++ { ++ if (boSparseTxTraffic) ++ MTO_HAL()->dto_tx_frag_count += MTOPARA_PERIODIC_CHECK_CYCLE(); ++ else ++ MTO_HAL()->dto_tx_frag_count += 1; ++ } ++ else ++ { ++ if (index<8) ++ { ++ MTO_HAL()->dto_tx_retry_count += index; ++ MTO_HAL()->dto_tx_frag_count += (index+1); ++ } ++ else ++ { ++ MTO_HAL()->dto_tx_retry_count += 7; ++ MTO_HAL()->dto_tx_frag_count += 7; ++ } ++ } ++ } ++ else if(MTO_DATA_RATE()>48 && tx_rate ==48) ++ {//ALFRED ++ if (index<3) //for reduciing data rate scheme , ++ //do not calcu different data rate ++ //3 is the reducing data rate at retry ++ { ++ MTO_HAL()->dto_tx_retry_count += index; ++ MTO_HAL()->dto_tx_frag_count += (index+1); ++ } ++ else ++ { ++ MTO_HAL()->dto_tx_retry_count += 3; ++ MTO_HAL()->dto_tx_frag_count += 3; ++ } ++ ++ } ++ } ++ else ++ { ++ MTO_HAL()->dto_tx_retry_count += index; ++ MTO_HAL()->dto_tx_frag_count += (index+1); ++ } ++ TotalTxPkt ++; ++ TotalTxPktRetry += (index+1); ++ ++ PeriodTotalTxPkt ++; ++ PeriodTotalTxPktRetry += (index+1); ++} ++ ++u8 MTO_GetTxFallbackRate(MTO_FUNC_INPUT) ++{ ++ return MTO_DATA_FALLBACK_RATE(); ++} ++ ++ ++//=========================================================================== ++// MTO_TxFailed -- ++// ++// Description: ++// Failure of transmitting a packet indicates that certain MTO parmeters ++// may need to be adjusted. This function is called when NIC just failed ++// to transmit a packet or when MSDULifeTime expired. ++// ++// Arguments: ++// Adapter - The pointer to the Miniport Adapter Context ++// ++// Return Value: ++// None ++//============================================================================ ++void MTO_TxFailed(MTO_FUNC_INPUT) ++{ ++ return; ++} ++ ++int Divide(int a, int b) ++{ ++ if (b==0) b=1; ++ return a/b; ++} ++ ++ +diff --git a/drivers/staging/winbond/mto.h b/drivers/staging/winbond/mto.h +new file mode 100644 +index 0000000..f47936f +--- /dev/null ++++ b/drivers/staging/winbond/mto.h +@@ -0,0 +1,265 @@ ++//================================================================== ++// MTO.H ++// ++// Revision history ++//================================= ++// 20030110 UN20 Pete Chao ++// Initial Release ++// ++// Copyright (c) 2003 Winbond Electronics Corp. All rights reserved. ++//================================================================== ++#ifndef __MTO_H__ ++#define __MTO_H__ ++ ++#define MTO_DEFAULT_TH_CNT 5 ++#define MTO_DEFAULT_TH_SQ3 112 //OLD IS 13 reference JohnXu ++#define MTO_DEFAULT_TH_IDLE_SLOT 15 ++#define MTO_DEFAULT_TH_PR_INTERF 30 ++#define MTO_DEFAULT_TMR_AGING 25 // unit: slot time 10 reference JohnXu ++#define MTO_DEFAULT_TMR_PERIODIC 5 // unit: slot time ++ ++#define MTO_ANTENNA_DIVERSITY_OFF 0 ++#define MTO_ANTENNA_DIVERSITY_ON 1 ++ ++// LA20040210_DTO kevin ++//#define MTO_PREAMBLE_LONG 0 ++//#define MTO_PREAMBLE_SHORT 1 ++#define MTO_PREAMBLE_LONG WLAN_PREAMBLE_TYPE_LONG ++#define MTO_PREAMBLE_SHORT WLAN_PREAMBLE_TYPE_SHORT ++ ++typedef enum { ++ TOGGLE_STATE_IDLE = 0, ++ TOGGLE_STATE_WAIT0 = 1, ++ TOGGLE_STATE_WAIT1 = 2, ++ TOGGLE_STATE_MAKEDESISION = 3, ++ TOGGLE_STATE_BKOFF = 4 ++} TOGGLE_STATE; ++ ++typedef enum { ++ RATE_CHGSTATE_IDLE = 0, ++ RATE_CHGSTATE_CALCULATE = 1, ++ RATE_CHGSTATE_BACKOFF = 2 ++} TX_RATE_REDUCTION_STATE; ++ ++//============================================================================ ++// struct _MTOParameters -- ++// ++// Defines the parameters used in the MAC Throughput Optimization algorithm ++//============================================================================ ++typedef struct _MTO_PARAMETERS ++{ ++ u8 Th_Fixant; ++ u8 Th_Cnt; ++ u8 Th_SQ3; ++ u8 Th_IdleSlot; ++ ++ u16 Tmr_Aging; ++ u8 Th_PrInterf; ++ u8 Tmr_Periodic; ++ ++ //--------- wkchen added ------------- ++ u32 TxFlowCount; //to judge what kind the tx flow(sparse or busy) is ++ //------------------------------------------------ ++ ++ //--------- DTO threshold parameters ------------- ++ u16 DTO_PeriodicCheckCycle; ++ u16 DTO_RssiThForAntDiv; ++ ++ u16 DTO_TxCountThForCalcNewRate; ++ u16 DTO_TxRateIncTh; ++ ++ u16 DTO_TxRateDecTh; ++ u16 DTO_TxRateEqTh; ++ ++ u16 DTO_TxRateBackOff; ++ u16 DTO_TxRetryRateReduce; ++ ++ u16 DTO_TxPowerIndex; //0 ~ 31 ++ u16 reserved_1; ++ //------------------------------------------------ ++ ++ u8 PowerChangeEnable; ++ u8 AntDiversityEnable; ++ u8 Ant_mac; ++ u8 Ant_div; ++ ++ u8 CCA_Mode; ++ u8 CCA_Mode_Setup; ++ u8 Preamble_Type; ++ u8 PreambleChangeEnable; ++ ++ u8 DataRateLevel; ++ u8 DataRateChangeEnable; ++ u8 FragThresholdLevel; ++ u8 FragThresholdChangeEnable; ++ ++ u16 RTSThreshold; ++ u16 RTSThreshold_Setup; ++ ++ u32 AvgIdleSlot; ++ u32 Pr_Interf; ++ u32 AvgGapBtwnInterf; ++ ++ u8 RTSChangeEnable; ++ u8 Ant_sel; ++ u8 aging_timeout; ++ u8 reserved_2; ++ ++ u32 Cnt_Ant[2]; ++ u32 SQ_Ant[2]; ++ ++// 20040510 remove from globe vairable ++ u32 TmrCnt; ++ u32 BackoffTmr; ++ TOGGLE_STATE ToggleState; ++ TX_RATE_REDUCTION_STATE TxRateReductionState; ++ ++ u8 Last_Rate; ++ u8 Co_efficent; ++ u8 FallbackRateLevel; ++ u8 OfdmRateLevel; ++ ++ u8 RatePolicy; ++ u8 reserved_3[3]; ++ ++ // For RSSI turning ++ s32 RSSI_high; ++ s32 RSSI_low; ++ ++} MTO_PARAMETERS, *PMTO_PARAMETERS; ++ ++ ++#define MTO_FUNC_INPUT PWB32_ADAPTER Adapter ++#define MTO_FUNC_INPUT_DATA Adapter ++#define MTO_DATA() (Adapter->sMtoPara) ++#define MTO_HAL() (&Adapter->sHwData) ++#define MTO_SET_PREAMBLE_TYPE(x) // 20040511 Turbo mark LM_PREAMBLE_TYPE(&pcore_data->lm_data) = (x) ++#define MTO_ENABLE (Adapter->sLocalPara.TxRateMode == RATE_AUTO) ++#define MTO_TXPOWER_FROM_EEPROM (Adapter->sHwData.PowerIndexFromEEPROM) ++#define LOCAL_ANTENNA_NO() (Adapter->sLocalPara.bAntennaNo) ++#define LOCAL_IS_CONNECTED() (Adapter->sLocalPara.wConnectedSTAindex != 0) ++#define LOCAL_IS_IBSS_MODE() (Adapter->asBSSDescriptElement[Adapter->sLocalPara.wConnectedSTAindex].bBssType == IBSS_NET) ++#define MTO_INITTXRATE_MODE (Adapter->sHwData.SoftwareSet&0x2) //bit 1 ++// 20040510 Turbo add ++#define MTO_TMR_CNT() MTO_DATA().TmrCnt ++#define MTO_TOGGLE_STATE() MTO_DATA().ToggleState ++#define MTO_TX_RATE_REDUCTION_STATE() MTO_DATA().TxRateReductionState ++#define MTO_BACKOFF_TMR() MTO_DATA().BackoffTmr ++#define MTO_LAST_RATE() MTO_DATA().Last_Rate ++#define MTO_CO_EFFICENT() MTO_DATA().Co_efficent ++ ++#define MTO_TH_CNT() MTO_DATA().Th_Cnt ++#define MTO_TH_SQ3() MTO_DATA().Th_SQ3 ++#define MTO_TH_IDLE_SLOT() MTO_DATA().Th_IdleSlot ++#define MTO_TH_PR_INTERF() MTO_DATA().Th_PrInterf ++ ++#define MTO_TMR_AGING() MTO_DATA().Tmr_Aging ++#define MTO_TMR_PERIODIC() MTO_DATA().Tmr_Periodic ++ ++#define MTO_POWER_CHANGE_ENABLE() MTO_DATA().PowerChangeEnable ++#define MTO_ANT_DIVERSITY_ENABLE() Adapter->sLocalPara.boAntennaDiversity ++#define MTO_ANT_MAC() MTO_DATA().Ant_mac ++#define MTO_ANT_DIVERSITY() MTO_DATA().Ant_div ++#define MTO_CCA_MODE() MTO_DATA().CCA_Mode ++#define MTO_CCA_MODE_SETUP() MTO_DATA().CCA_Mode_Setup ++#define MTO_PREAMBLE_TYPE() MTO_DATA().Preamble_Type ++#define MTO_PREAMBLE_CHANGE_ENABLE() MTO_DATA().PreambleChangeEnable ++ ++#define MTO_RATE_LEVEL() MTO_DATA().DataRateLevel ++#define MTO_FALLBACK_RATE_LEVEL() MTO_DATA().FallbackRateLevel ++#define MTO_OFDM_RATE_LEVEL() MTO_DATA().OfdmRateLevel ++#define MTO_RATE_CHANGE_ENABLE() MTO_DATA().DataRateChangeEnable ++#define MTO_FRAG_TH_LEVEL() MTO_DATA().FragThresholdLevel ++#define MTO_FRAG_CHANGE_ENABLE() MTO_DATA().FragThresholdChangeEnable ++#define MTO_RTS_THRESHOLD() MTO_DATA().RTSThreshold ++#define MTO_RTS_CHANGE_ENABLE() MTO_DATA().RTSChangeEnable ++#define MTO_RTS_THRESHOLD_SETUP() MTO_DATA().RTSThreshold_Setup ++ ++#define MTO_AVG_IDLE_SLOT() MTO_DATA().AvgIdleSlot ++#define MTO_PR_INTERF() MTO_DATA().Pr_Interf ++#define MTO_AVG_GAP_BTWN_INTERF() MTO_DATA().AvgGapBtwnInterf ++ ++#define MTO_ANT_SEL() MTO_DATA().Ant_sel ++#define MTO_CNT_ANT(x) MTO_DATA().Cnt_Ant[(x)] ++#define MTO_SQ_ANT(x) MTO_DATA().SQ_Ant[(x)] ++#define MTO_AGING_TIMEOUT() MTO_DATA().aging_timeout ++ ++ ++#define MTO_TXFLOWCOUNT() MTO_DATA().TxFlowCount ++//--------- DTO threshold parameters ------------- ++#define MTOPARA_PERIODIC_CHECK_CYCLE() MTO_DATA().DTO_PeriodicCheckCycle ++#define MTOPARA_RSSI_TH_FOR_ANTDIV() MTO_DATA().DTO_RssiThForAntDiv ++#define MTOPARA_TXCOUNT_TH_FOR_CALC_RATE() MTO_DATA().DTO_TxCountThForCalcNewRate ++#define MTOPARA_TXRATE_INC_TH() MTO_DATA().DTO_TxRateIncTh ++#define MTOPARA_TXRATE_DEC_TH() MTO_DATA().DTO_TxRateDecTh ++#define MTOPARA_TXRATE_EQ_TH() MTO_DATA().DTO_TxRateEqTh ++#define MTOPARA_TXRATE_BACKOFF() MTO_DATA().DTO_TxRateBackOff ++#define MTOPARA_TXRETRYRATE_REDUCE() MTO_DATA().DTO_TxRetryRateReduce ++#define MTOPARA_TXPOWER_INDEX() MTO_DATA().DTO_TxPowerIndex ++//------------------------------------------------ ++ ++ ++extern u8 MTO_Data_Rate_Tbl[]; ++extern u16 MTO_Frag_Th_Tbl[]; ++ ++#define MTO_DATA_RATE() MTO_Data_Rate_Tbl[MTO_RATE_LEVEL()] ++#define MTO_DATA_FALLBACK_RATE() MTO_Data_Rate_Tbl[MTO_FALLBACK_RATE_LEVEL()] //next level ++#define MTO_FRAG_TH() MTO_Frag_Th_Tbl[MTO_FRAG_TH_LEVEL()] ++ ++typedef struct { ++ u8 tx_rate; ++ u8 tx_retry_rate; ++} TXRETRY_REC; ++ ++typedef struct _STATISTICS_INFO { ++ u32 Rate54M; ++ u32 Rate48M; ++ u32 Rate36M; ++ u32 Rate24M; ++ u32 Rate18M; ++ u32 Rate12M; ++ u32 Rate9M; ++ u32 Rate6M; ++ u32 Rate11MS; ++ u32 Rate11ML; ++ u32 Rate55MS; ++ u32 Rate55ML; ++ u32 Rate2MS; ++ u32 Rate2ML; ++ u32 Rate1M; ++ u32 Rate54MOK; ++ u32 Rate48MOK; ++ u32 Rate36MOK; ++ u32 Rate24MOK; ++ u32 Rate18MOK; ++ u32 Rate12MOK; ++ u32 Rate9MOK; ++ u32 Rate6MOK; ++ u32 Rate11MSOK; ++ u32 Rate11MLOK; ++ u32 Rate55MSOK; ++ u32 Rate55MLOK; ++ u32 Rate2MSOK; ++ u32 Rate2MLOK; ++ u32 Rate1MOK; ++ u32 SQ3; ++ s32 RSSIAVG; ++ s32 RSSIMAX; ++ s32 TXRATE; ++ s32 TxRetryRate; ++ s32 BSS_PK_CNT; ++ s32 NIDLESLOT; ++ s32 SLOT_CNT; ++ s32 INTERF_CNT; ++ s32 GAP_CNT; ++ s32 DS_EVM; ++ s32 RcvBeaconNum; ++ s32 RXRATE; ++ s32 RxBytes; ++ s32 TxBytes; ++ s32 Antenna; ++} STATISTICS_INFO, *PSTATISTICS_INFO; ++ ++#endif //__MTO_H__ ++ ++ +diff --git a/drivers/staging/winbond/mto_f.h b/drivers/staging/winbond/mto_f.h +new file mode 100644 +index 0000000..30b3df2 +--- /dev/null ++++ b/drivers/staging/winbond/mto_f.h +@@ -0,0 +1,7 @@ ++extern void MTO_Init(PWB32_ADAPTER); ++extern void MTO_PeriodicTimerExpired(PWB32_ADAPTER); ++extern void MTO_SetDTORateRange(PWB32_ADAPTER, u8 *, u8); ++extern u8 MTO_GetTxRate(MTO_FUNC_INPUT, u32 fpdu_len); ++extern u8 MTO_GetTxFallbackRate(MTO_FUNC_INPUT); ++extern void MTO_SetTxCount(MTO_FUNC_INPUT, u8 t0, u8 index); ++ +diff --git a/drivers/staging/winbond/os_common.h b/drivers/staging/winbond/os_common.h +new file mode 100644 +index 0000000..e24ff41 +--- /dev/null ++++ b/drivers/staging/winbond/os_common.h +@@ -0,0 +1,2 @@ ++#include "linux/sysdef.h" ++ +diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c +new file mode 100644 +index 0000000..272a650 +--- /dev/null ++++ b/drivers/staging/winbond/phy_calibration.c +@@ -0,0 +1,1759 @@ ++/* ++ * phy_302_calibration.c ++ * ++ * Copyright (C) 2002, 2005 Winbond Electronics Corp. ++ * ++ * modification history ++ * --------------------------------------------------------------------------- ++ * 0.01.001, 2003-04-16, Kevin created ++ * ++ */ ++ ++/****************** INCLUDE FILES SECTION ***********************************/ ++#include "os_common.h" ++#include "phy_calibration.h" ++ ++ ++/****************** DEBUG CONSTANT AND MACRO SECTION ************************/ ++ ++/****************** LOCAL CONSTANT AND MACRO SECTION ************************/ ++#define LOOP_TIMES 20 ++#define US 1000//MICROSECOND ++ ++#define AG_CONST 0.6072529350 ++#define FIXED(X) ((s32)((X) * 32768.0)) ++#define DEG2RAD(X) 0.017453 * (X) ++ ++/****************** LOCAL TYPE DEFINITION SECTION ***************************/ ++typedef s32 fixed; /* 16.16 fixed-point */ ++ ++static const fixed Angles[]= ++{ ++ FIXED(DEG2RAD(45.0)), FIXED(DEG2RAD(26.565)), FIXED(DEG2RAD(14.0362)), ++ FIXED(DEG2RAD(7.12502)), FIXED(DEG2RAD(3.57633)), FIXED(DEG2RAD(1.78991)), ++ FIXED(DEG2RAD(0.895174)),FIXED(DEG2RAD(0.447614)),FIXED(DEG2RAD(0.223811)), ++ FIXED(DEG2RAD(0.111906)),FIXED(DEG2RAD(0.055953)),FIXED(DEG2RAD(0.027977)) ++}; ++ ++/****************** LOCAL FUNCTION DECLARATION SECTION **********************/ ++//void _phy_rf_write_delay(hw_data_t *phw_data); ++//void phy_init_rf(hw_data_t *phw_data); ++ ++/****************** FUNCTION DEFINITION SECTION *****************************/ ++ ++s32 _s13_to_s32(u32 data) ++{ ++ u32 val; ++ ++ val = (data & 0x0FFF); ++ ++ if ((data & BIT(12)) != 0) ++ { ++ val |= 0xFFFFF000; ++ } ++ ++ return ((s32) val); ++} ++ ++u32 _s32_to_s13(s32 data) ++{ ++ u32 val; ++ ++ if (data > 4095) ++ { ++ data = 4095; ++ } ++ else if (data < -4096) ++ { ++ data = -4096; ++ } ++ ++ val = data & 0x1FFF; ++ ++ return val; ++} ++ ++/****************************************************************************/ ++s32 _s4_to_s32(u32 data) ++{ ++ s32 val; ++ ++ val = (data & 0x0007); ++ ++ if ((data & BIT(3)) != 0) ++ { ++ val |= 0xFFFFFFF8; ++ } ++ ++ return val; ++} ++ ++u32 _s32_to_s4(s32 data) ++{ ++ u32 val; ++ ++ if (data > 7) ++ { ++ data = 7; ++ } ++ else if (data < -8) ++ { ++ data = -8; ++ } ++ ++ val = data & 0x000F; ++ ++ return val; ++} ++ ++/****************************************************************************/ ++s32 _s5_to_s32(u32 data) ++{ ++ s32 val; ++ ++ val = (data & 0x000F); ++ ++ if ((data & BIT(4)) != 0) ++ { ++ val |= 0xFFFFFFF0; ++ } ++ ++ return val; ++} ++ ++u32 _s32_to_s5(s32 data) ++{ ++ u32 val; ++ ++ if (data > 15) ++ { ++ data = 15; ++ } ++ else if (data < -16) ++ { ++ data = -16; ++ } ++ ++ val = data & 0x001F; ++ ++ return val; ++} ++ ++/****************************************************************************/ ++s32 _s6_to_s32(u32 data) ++{ ++ s32 val; ++ ++ val = (data & 0x001F); ++ ++ if ((data & BIT(5)) != 0) ++ { ++ val |= 0xFFFFFFE0; ++ } ++ ++ return val; ++} ++ ++u32 _s32_to_s6(s32 data) ++{ ++ u32 val; ++ ++ if (data > 31) ++ { ++ data = 31; ++ } ++ else if (data < -32) ++ { ++ data = -32; ++ } ++ ++ val = data & 0x003F; ++ ++ return val; ++} ++ ++/****************************************************************************/ ++s32 _s9_to_s32(u32 data) ++{ ++ s32 val; ++ ++ val = data & 0x00FF; ++ ++ if ((data & BIT(8)) != 0) ++ { ++ val |= 0xFFFFFF00; ++ } ++ ++ return val; ++} ++ ++u32 _s32_to_s9(s32 data) ++{ ++ u32 val; ++ ++ if (data > 255) ++ { ++ data = 255; ++ } ++ else if (data < -256) ++ { ++ data = -256; ++ } ++ ++ val = data & 0x01FF; ++ ++ return val; ++} ++ ++/****************************************************************************/ ++s32 _floor(s32 n) ++{ ++ if (n > 0) ++ { ++ n += 5; ++ } ++ else ++ { ++ n -= 5; ++ } ++ ++ return (n/10); ++} ++ ++/****************************************************************************/ ++// The following code is sqare-root function. ++// sqsum is the input and the output is sq_rt; ++// The maximum of sqsum = 2^27 -1; ++u32 _sqrt(u32 sqsum) ++{ ++ u32 sq_rt; ++ ++ int g0, g1, g2, g3, g4; ++ int seed; ++ int next; ++ int step; ++ ++ g4 = sqsum / 100000000; ++ g3 = (sqsum - g4*100000000) /1000000; ++ g2 = (sqsum - g4*100000000 - g3*1000000) /10000; ++ g1 = (sqsum - g4*100000000 - g3*1000000 - g2*10000) /100; ++ g0 = (sqsum - g4*100000000 - g3*1000000 - g2*10000 - g1*100); ++ ++ next = g4; ++ step = 0; ++ seed = 0; ++ while (((seed+1)*(step+1)) <= next) ++ { ++ step++; ++ seed++; ++ } ++ ++ sq_rt = seed * 10000; ++ next = (next-(seed*step))*100 + g3; ++ ++ step = 0; ++ seed = 2 * seed * 10; ++ while (((seed+1)*(step+1)) <= next) ++ { ++ step++; ++ seed++; ++ } ++ ++ sq_rt = sq_rt + step * 1000; ++ next = (next - seed * step) * 100 + g2; ++ seed = (seed + step) * 10; ++ step = 0; ++ while (((seed+1)*(step+1)) <= next) ++ { ++ step++; ++ seed++; ++ } ++ ++ sq_rt = sq_rt + step * 100; ++ next = (next - seed * step) * 100 + g1; ++ seed = (seed + step) * 10; ++ step = 0; ++ ++ while (((seed+1)*(step+1)) <= next) ++ { ++ step++; ++ seed++; ++ } ++ ++ sq_rt = sq_rt + step * 10; ++ next = (next - seed* step) * 100 + g0; ++ seed = (seed + step) * 10; ++ step = 0; ++ ++ while (((seed+1)*(step+1)) <= next) ++ { ++ step++; ++ seed++; ++ } ++ ++ sq_rt = sq_rt + step; ++ ++ return sq_rt; ++} ++ ++/****************************************************************************/ ++void _sin_cos(s32 angle, s32 *sin, s32 *cos) ++{ ++ fixed X, Y, TargetAngle, CurrAngle; ++ unsigned Step; ++ ++ X=FIXED(AG_CONST); // AG_CONST * cos(0) ++ Y=0; // AG_CONST * sin(0) ++ TargetAngle=abs(angle); ++ CurrAngle=0; ++ ++ for (Step=0; Step < 12; Step++) ++ { ++ fixed NewX; ++ ++ if(TargetAngle > CurrAngle) ++ { ++ NewX=X - (Y >> Step); ++ Y=(X >> Step) + Y; ++ X=NewX; ++ CurrAngle += Angles[Step]; ++ } ++ else ++ { ++ NewX=X + (Y >> Step); ++ Y=-(X >> Step) + Y; ++ X=NewX; ++ CurrAngle -= Angles[Step]; ++ } ++ } ++ ++ if (angle > 0) ++ { ++ *cos = X; ++ *sin = Y; ++ } ++ else ++ { ++ *cos = X; ++ *sin = -Y; ++ } ++} ++ ++ ++void _reset_rx_cal(hw_data_t *phw_data) ++{ ++ u32 val; ++ ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ val &= 0xFFFF0000; ++ } ++ else // 2nd-cut ++ { ++ val &= 0x000003FF; ++ } ++ ++ hw_set_dxx_reg(phw_data, 0x54, val); ++} ++ ++ ++// ************for winbond calibration********* ++// ++ ++// ++// ++// ********************************************* ++void _rxadc_dc_offset_cancellation_winbond(hw_data_t *phw_data, u32 frequency) ++{ ++ u32 reg_agc_ctrl3; ++ u32 reg_a_acq_ctrl; ++ u32 reg_b_acq_ctrl; ++ u32 val; ++ ++ PHY_DEBUG(("[CAL] -> [1]_rxadc_dc_offset_cancellation()\n")); ++ phy_init_rf(phw_data); ++ ++ // set calibration channel ++ if( (RF_WB_242 == phw_data->phy_type) || ++ (RF_WB_242_1 == phw_data->phy_type) ) // 20060619.5 Add ++ { ++ if ((frequency >= 2412) && (frequency <= 2484)) ++ { ++ // w89rf242 change frequency to 2390Mhz ++ PHY_DEBUG(("[CAL] W89RF242/11G/Channel=2390Mhz\n")); ++ phy_set_rf_data(phw_data, 3, (3<<24)|0x025586); ++ ++ } ++ } ++ else ++ { ++ ++ } ++ ++ // reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel ++ hw_get_dxx_reg(phw_data, 0x5C, &val); ++ val &= ~(0x03FF); ++ hw_set_dxx_reg(phw_data, 0x5C, val); ++ ++ // reset the TX and RX IQ calibration data ++ hw_set_dxx_reg(phw_data, 0x3C, 0); ++ hw_set_dxx_reg(phw_data, 0x54, 0); ++ ++ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed ++ ++ // a. Disable AGC ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3); ++ reg_agc_ctrl3 &= ~BIT(2); ++ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX); ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3); ++ ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val); ++ val |= MASK_AGC_FIX_GAIN; ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val); ++ ++ // b. Turn off BB RX ++ hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, ®_a_acq_ctrl); ++ reg_a_acq_ctrl |= MASK_AMER_OFF_REG; ++ hw_set_dxx_reg(phw_data, REG_A_ACQ_CTRL, reg_a_acq_ctrl); ++ ++ hw_get_dxx_reg(phw_data, REG_B_ACQ_CTRL, ®_b_acq_ctrl); ++ reg_b_acq_ctrl |= MASK_BMER_OFF_REG; ++ hw_set_dxx_reg(phw_data, REG_B_ACQ_CTRL, reg_b_acq_ctrl); ++ ++ // c. Make sure MAC is in receiving mode ++ // d. Turn ON ADC calibration ++ // - ADC calibrator is triggered by this signal rising from 0 to 1 ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); ++ val &= ~MASK_ADC_DC_CAL_STR; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val); ++ ++ val |= MASK_ADC_DC_CAL_STR; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val); ++ pa_stall_execution(US); // *MUST* wait for a while ++ ++ // e. The result are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]" ++#ifdef _DEBUG ++ hw_get_dxx_reg(phw_data, REG_OFFSET_READ, &val); ++ PHY_DEBUG(("[CAL] REG_OFFSET_READ = 0x%08X\n", val)); ++ ++ PHY_DEBUG(("[CAL] ** adc_dc_cal_i = %d (0x%04X)\n", ++ _s9_to_s32(val&0x000001FF), val&0x000001FF)); ++ PHY_DEBUG(("[CAL] ** adc_dc_cal_q = %d (0x%04X)\n", ++ _s9_to_s32((val&0x0003FE00)>>9), (val&0x0003FE00)>>9)); ++#endif ++ ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); ++ val &= ~MASK_ADC_DC_CAL_STR; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val); ++ ++ // f. Turn on BB RX ++ //hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, ®_a_acq_ctrl); ++ reg_a_acq_ctrl &= ~MASK_AMER_OFF_REG; ++ hw_set_dxx_reg(phw_data, REG_A_ACQ_CTRL, reg_a_acq_ctrl); ++ ++ //hw_get_dxx_reg(phw_data, REG_B_ACQ_CTRL, ®_b_acq_ctrl); ++ reg_b_acq_ctrl &= ~MASK_BMER_OFF_REG; ++ hw_set_dxx_reg(phw_data, REG_B_ACQ_CTRL, reg_b_acq_ctrl); ++ ++ // g. Enable AGC ++ //hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val); ++ reg_agc_ctrl3 |= BIT(2); ++ reg_agc_ctrl3 &= ~(MASK_LNA_FIX_GAIN|MASK_AGC_FIX); ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3); ++} ++ ++//////////////////////////////////////////////////////// ++void _txidac_dc_offset_cancellation_winbond(hw_data_t *phw_data) ++{ ++ u32 reg_agc_ctrl3; ++ u32 reg_mode_ctrl; ++ u32 reg_dc_cancel; ++ s32 iqcal_image_i; ++ s32 iqcal_image_q; ++ u32 sqsum; ++ s32 mag_0; ++ s32 mag_1; ++ s32 fix_cancel_dc_i = 0; ++ u32 val; ++ int loop; ++ ++ PHY_DEBUG(("[CAL] -> [2]_txidac_dc_offset_cancellation()\n")); ++ ++ // a. Set to "TX calibration mode" ++ ++ //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits ++ phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2); ++ //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit ++ phy_set_rf_data(phw_data, 11, (11<<24)|0x1901D6); ++ //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized ++ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C48A); ++ //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized ++ phy_set_rf_data(phw_data, 6, (6<<24)|0x06890C); ++ //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode ++ phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0); ++ ++ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed ++ ++ // a. Disable AGC ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3); ++ reg_agc_ctrl3 &= ~BIT(2); ++ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX); ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3); ++ ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val); ++ val |= MASK_AGC_FIX_GAIN; ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val); ++ ++ // b. set iqcal_mode[1:0] to 0x2 and set iqcal_tone[3:2] to 0 ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ ++ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl)); ++ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); ++ ++ // mode=2, tone=0 ++ //reg_mode_ctrl |= (MASK_CALIB_START|2); ++ ++ // mode=2, tone=1 ++ //reg_mode_ctrl |= (MASK_CALIB_START|2|(1<<2)); ++ ++ // mode=2, tone=2 ++ reg_mode_ctrl |= (MASK_CALIB_START|2|(2<<2)); ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++ ++ hw_get_dxx_reg(phw_data, 0x5C, ®_dc_cancel); ++ PHY_DEBUG(("[CAL] DC_CANCEL (read) = 0x%08X\n", reg_dc_cancel)); ++ ++ for (loop = 0; loop < LOOP_TIMES; loop++) ++ { ++ PHY_DEBUG(("[CAL] [%d.] ==================================\n", loop)); ++ ++ // c. ++ // reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel ++ reg_dc_cancel &= ~(0x03FF); ++ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel)); ++ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel); ++ pa_stall_execution(US); ++ ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val)); ++ ++ iqcal_image_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q; ++ mag_0 = (s32) _sqrt(sqsum); ++ PHY_DEBUG(("[CAL] mag_0=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n", ++ mag_0, iqcal_image_i, iqcal_image_q)); ++ ++ // d. ++ reg_dc_cancel |= (1 << CANCEL_DC_I_SHIFT); ++ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel)); ++ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel); ++ pa_stall_execution(US); ++ ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val)); ++ ++ iqcal_image_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q; ++ mag_1 = (s32) _sqrt(sqsum); ++ PHY_DEBUG(("[CAL] mag_1=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n", ++ mag_1, iqcal_image_i, iqcal_image_q)); ++ ++ // e. Calculate the correct DC offset cancellation value for I ++ if (mag_0 != mag_1) ++ { ++ fix_cancel_dc_i = (mag_0*10000) / (mag_0*10000 - mag_1*10000); ++ } ++ else ++ { ++ if (mag_0 == mag_1) ++ { ++ PHY_DEBUG(("[CAL] ***** mag_0 = mag_1 !!\n")); ++ } ++ ++ fix_cancel_dc_i = 0; ++ } ++ ++ PHY_DEBUG(("[CAL] ** fix_cancel_dc_i = %d (0x%04X)\n", ++ fix_cancel_dc_i, _s32_to_s5(fix_cancel_dc_i))); ++ ++ if ((abs(mag_1-mag_0)*6) > mag_0) ++ { ++ break; ++ } ++ } ++ ++ if ( loop >= 19 ) ++ fix_cancel_dc_i = 0; ++ ++ reg_dc_cancel &= ~(0x03FF); ++ reg_dc_cancel |= (_s32_to_s5(fix_cancel_dc_i) << CANCEL_DC_I_SHIFT); ++ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel); ++ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel)); ++ ++ // g. ++ reg_mode_ctrl &= ~MASK_CALIB_START; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++} ++ ++/////////////////////////////////////////////////////// ++void _txqdac_dc_offset_cacellation_winbond(hw_data_t *phw_data) ++{ ++ u32 reg_agc_ctrl3; ++ u32 reg_mode_ctrl; ++ u32 reg_dc_cancel; ++ s32 iqcal_image_i; ++ s32 iqcal_image_q; ++ u32 sqsum; ++ s32 mag_0; ++ s32 mag_1; ++ s32 fix_cancel_dc_q = 0; ++ u32 val; ++ int loop; ++ ++ PHY_DEBUG(("[CAL] -> [3]_txqdac_dc_offset_cacellation()\n")); ++ //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits ++ phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2); ++ //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit ++ phy_set_rf_data(phw_data, 11, (11<<24)|0x1901D6); ++ //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized ++ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C48A); ++ //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized ++ phy_set_rf_data(phw_data, 6, (6<<24)|0x06890C); ++ //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode ++ phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0); ++ ++ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed ++ ++ // a. Disable AGC ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3); ++ reg_agc_ctrl3 &= ~BIT(2); ++ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX); ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3); ++ ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val); ++ val |= MASK_AGC_FIX_GAIN; ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val); ++ ++ // a. set iqcal_mode[1:0] to 0x3 and set iqcal_tone[3:2] to 0 ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl)); ++ ++ //reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); ++ reg_mode_ctrl &= ~(MASK_IQCAL_MODE); ++ reg_mode_ctrl |= (MASK_CALIB_START|3); ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++ ++ hw_get_dxx_reg(phw_data, 0x5C, ®_dc_cancel); ++ PHY_DEBUG(("[CAL] DC_CANCEL (read) = 0x%08X\n", reg_dc_cancel)); ++ ++ for (loop = 0; loop < LOOP_TIMES; loop++) ++ { ++ PHY_DEBUG(("[CAL] [%d.] ==================================\n", loop)); ++ ++ // b. ++ // reset cancel_dc_q[4:0] in register DC_Cancel ++ reg_dc_cancel &= ~(0x001F); ++ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel)); ++ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel); ++ pa_stall_execution(US); ++ ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val)); ++ pa_stall_execution(US); ++ ++ iqcal_image_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q; ++ mag_0 = _sqrt(sqsum); ++ PHY_DEBUG(("[CAL] mag_0=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n", ++ mag_0, iqcal_image_i, iqcal_image_q)); ++ ++ // c. ++ reg_dc_cancel |= (1 << CANCEL_DC_Q_SHIFT); ++ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel)); ++ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel); ++ pa_stall_execution(US); ++ ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val)); ++ pa_stall_execution(US); ++ ++ iqcal_image_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q; ++ mag_1 = _sqrt(sqsum); ++ PHY_DEBUG(("[CAL] mag_1=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n", ++ mag_1, iqcal_image_i, iqcal_image_q)); ++ ++ // d. Calculate the correct DC offset cancellation value for I ++ if (mag_0 != mag_1) ++ { ++ fix_cancel_dc_q = (mag_0*10000) / (mag_0*10000 - mag_1*10000); ++ } ++ else ++ { ++ if (mag_0 == mag_1) ++ { ++ PHY_DEBUG(("[CAL] ***** mag_0 = mag_1 !!\n")); ++ } ++ ++ fix_cancel_dc_q = 0; ++ } ++ ++ PHY_DEBUG(("[CAL] ** fix_cancel_dc_q = %d (0x%04X)\n", ++ fix_cancel_dc_q, _s32_to_s5(fix_cancel_dc_q))); ++ ++ if ((abs(mag_1-mag_0)*6) > mag_0) ++ { ++ break; ++ } ++ } ++ ++ if ( loop >= 19 ) ++ fix_cancel_dc_q = 0; ++ ++ reg_dc_cancel &= ~(0x001F); ++ reg_dc_cancel |= (_s32_to_s5(fix_cancel_dc_q) << CANCEL_DC_Q_SHIFT); ++ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel); ++ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel)); ++ ++ ++ // f. ++ reg_mode_ctrl &= ~MASK_CALIB_START; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++} ++ ++//20060612.1.a 20060718.1 Modify ++u8 _tx_iq_calibration_loop_winbond(hw_data_t *phw_data, ++ s32 a_2_threshold, ++ s32 b_2_threshold) ++{ ++ u32 reg_mode_ctrl; ++ s32 iq_mag_0_tx; ++ s32 iqcal_tone_i0; ++ s32 iqcal_tone_q0; ++ s32 iqcal_tone_i; ++ s32 iqcal_tone_q; ++ u32 sqsum; ++ s32 rot_i_b; ++ s32 rot_q_b; ++ s32 tx_cal_flt_b[4]; ++ s32 tx_cal[4]; ++ s32 tx_cal_reg[4]; ++ s32 a_2, b_2; ++ s32 sin_b, sin_2b; ++ s32 cos_b, cos_2b; ++ s32 divisor; ++ s32 temp1, temp2; ++ u32 val; ++ u16 loop; ++ s32 iqcal_tone_i_avg,iqcal_tone_q_avg; ++ u8 verify_count; ++ int capture_time; ++ ++ PHY_DEBUG(("[CAL] -> _tx_iq_calibration_loop()\n")); ++ PHY_DEBUG(("[CAL] ** a_2_threshold = %d\n", a_2_threshold)); ++ PHY_DEBUG(("[CAL] ** b_2_threshold = %d\n", b_2_threshold)); ++ ++ verify_count = 0; ++ ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl)); ++ ++ loop = LOOP_TIMES; ++ ++ while (loop > 0) ++ { ++ PHY_DEBUG(("[CAL] [%d.] <_tx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1))); ++ ++ iqcal_tone_i_avg=0; ++ iqcal_tone_q_avg=0; ++ if( !hw_set_dxx_reg(phw_data, 0x3C, 0x00) ) // 20060718.1 modify ++ return 0; ++ for(capture_time=0;capture_time<10;capture_time++) ++ { ++ // a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to ++ // enable "IQ alibration Mode II" ++ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); ++ reg_mode_ctrl &= ~MASK_IQCAL_MODE; ++ reg_mode_ctrl |= (MASK_CALIB_START|0x02); ++ reg_mode_ctrl |= (MASK_CALIB_START|0x02|2<<2); ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++ ++ // b. ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val)); ++ pa_stall_execution(US); ++ ++ iqcal_tone_i0 = _s13_to_s32(val & 0x00001FFF); ++ iqcal_tone_q0 = _s13_to_s32((val & 0x03FFE000) >> 13); ++ PHY_DEBUG(("[CAL] ** iqcal_tone_i0=%d, iqcal_tone_q0=%d\n", ++ iqcal_tone_i0, iqcal_tone_q0)); ++ ++ sqsum = iqcal_tone_i0*iqcal_tone_i0 + ++ iqcal_tone_q0*iqcal_tone_q0; ++ iq_mag_0_tx = (s32) _sqrt(sqsum); ++ PHY_DEBUG(("[CAL] ** iq_mag_0_tx=%d\n", iq_mag_0_tx)); ++ ++ // c. Set "calib_start" to 0x0 ++ reg_mode_ctrl &= ~MASK_CALIB_START; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++ ++ // d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to ++ // enable "IQ alibration Mode II" ++ //hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ reg_mode_ctrl &= ~MASK_IQCAL_MODE; ++ reg_mode_ctrl |= (MASK_CALIB_START|0x03); ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++ ++ // e. ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val)); ++ pa_stall_execution(US); ++ ++ iqcal_tone_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_tone_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ PHY_DEBUG(("[CAL] ** iqcal_tone_i = %d, iqcal_tone_q = %d\n", ++ iqcal_tone_i, iqcal_tone_q)); ++ if( capture_time == 0) ++ { ++ continue; ++ } ++ else ++ { ++ iqcal_tone_i_avg=( iqcal_tone_i_avg*(capture_time-1) +iqcal_tone_i)/capture_time; ++ iqcal_tone_q_avg=( iqcal_tone_q_avg*(capture_time-1) +iqcal_tone_q)/capture_time; ++ } ++ } ++ ++ iqcal_tone_i = iqcal_tone_i_avg; ++ iqcal_tone_q = iqcal_tone_q_avg; ++ ++ ++ rot_i_b = (iqcal_tone_i * iqcal_tone_i0 + ++ iqcal_tone_q * iqcal_tone_q0) / 1024; ++ rot_q_b = (iqcal_tone_i * iqcal_tone_q0 * (-1) + ++ iqcal_tone_q * iqcal_tone_i0) / 1024; ++ PHY_DEBUG(("[CAL] ** rot_i_b = %d, rot_q_b = %d\n", ++ rot_i_b, rot_q_b)); ++ ++ // f. ++ divisor = ((iq_mag_0_tx * iq_mag_0_tx * 2)/1024 - rot_i_b) * 2; ++ ++ if (divisor == 0) ++ { ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> ERROR *******\n")); ++ PHY_DEBUG(("[CAL] ** divisor=0 to calculate EPS and THETA !!\n")); ++ PHY_DEBUG(("[CAL] ******************************************\n")); ++ break; ++ } ++ ++ a_2 = (rot_i_b * 32768) / divisor; ++ b_2 = (rot_q_b * (-32768)) / divisor; ++ PHY_DEBUG(("[CAL] ***** EPSILON/2 = %d\n", a_2)); ++ PHY_DEBUG(("[CAL] ***** THETA/2 = %d\n", b_2)); ++ ++ phw_data->iq_rsdl_gain_tx_d2 = a_2; ++ phw_data->iq_rsdl_phase_tx_d2 = b_2; ++ ++ //if ((abs(a_2) < 150) && (abs(b_2) < 100)) ++ //if ((abs(a_2) < 200) && (abs(b_2) < 200)) ++ if ((abs(a_2) < a_2_threshold) && (abs(b_2) < b_2_threshold)) ++ { ++ verify_count++; ++ ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n")); ++ PHY_DEBUG(("[CAL] ** VERIFY OK # %d !!\n", verify_count)); ++ PHY_DEBUG(("[CAL] ******************************************\n")); ++ ++ if (verify_count > 2) ++ { ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n")); ++ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION (EPS,THETA) OK !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ return 0; ++ } ++ ++ continue; ++ } ++ else ++ { ++ verify_count = 0; ++ } ++ ++ _sin_cos(b_2, &sin_b, &cos_b); ++ _sin_cos(b_2*2, &sin_2b, &cos_2b); ++ PHY_DEBUG(("[CAL] ** sin(b/2)=%d, cos(b/2)=%d\n", sin_b, cos_b)); ++ PHY_DEBUG(("[CAL] ** sin(b)=%d, cos(b)=%d\n", sin_2b, cos_2b)); ++ ++ if (cos_2b == 0) ++ { ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> ERROR *******\n")); ++ PHY_DEBUG(("[CAL] ** cos(b)=0 !!\n")); ++ PHY_DEBUG(("[CAL] ******************************************\n")); ++ break; ++ } ++ ++ // 1280 * 32768 = 41943040 ++ temp1 = (41943040/cos_2b)*cos_b; ++ ++ //temp2 = (41943040/cos_2b)*sin_b*(-1); ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ temp2 = (41943040/cos_2b)*sin_b*(-1); ++ } ++ else // 2nd-cut ++ { ++ temp2 = (41943040*4/cos_2b)*sin_b*(-1); ++ } ++ ++ tx_cal_flt_b[0] = _floor(temp1/(32768+a_2)); ++ tx_cal_flt_b[1] = _floor(temp2/(32768+a_2)); ++ tx_cal_flt_b[2] = _floor(temp2/(32768-a_2)); ++ tx_cal_flt_b[3] = _floor(temp1/(32768-a_2)); ++ PHY_DEBUG(("[CAL] ** tx_cal_flt_b[0] = %d\n", tx_cal_flt_b[0])); ++ PHY_DEBUG(("[CAL] tx_cal_flt_b[1] = %d\n", tx_cal_flt_b[1])); ++ PHY_DEBUG(("[CAL] tx_cal_flt_b[2] = %d\n", tx_cal_flt_b[2])); ++ PHY_DEBUG(("[CAL] tx_cal_flt_b[3] = %d\n", tx_cal_flt_b[3])); ++ ++ tx_cal[2] = tx_cal_flt_b[2]; ++ tx_cal[2] = tx_cal[2] +3; ++ tx_cal[1] = tx_cal[2]; ++ tx_cal[3] = tx_cal_flt_b[3] - 128; ++ tx_cal[0] = -tx_cal[3]+1; ++ ++ PHY_DEBUG(("[CAL] tx_cal[0] = %d\n", tx_cal[0])); ++ PHY_DEBUG(("[CAL] tx_cal[1] = %d\n", tx_cal[1])); ++ PHY_DEBUG(("[CAL] tx_cal[2] = %d\n", tx_cal[2])); ++ PHY_DEBUG(("[CAL] tx_cal[3] = %d\n", tx_cal[3])); ++ ++ //if ((tx_cal[0] == 0) && (tx_cal[1] == 0) && ++ // (tx_cal[2] == 0) && (tx_cal[3] == 0)) ++ //{ ++ // PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n")); ++ // PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION COMPLETE !!\n")); ++ // PHY_DEBUG(("[CAL] ******************************************\n")); ++ // return 0; ++ //} ++ ++ // g. ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val)); ++ tx_cal_reg[0] = _s4_to_s32((val & 0xF0000000) >> 28); ++ tx_cal_reg[1] = _s4_to_s32((val & 0x0F000000) >> 24); ++ tx_cal_reg[2] = _s4_to_s32((val & 0x00F00000) >> 20); ++ tx_cal_reg[3] = _s4_to_s32((val & 0x000F0000) >> 16); ++ } ++ else // 2nd-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x3C, &val); ++ PHY_DEBUG(("[CAL] ** 0x3C = 0x%08X\n", val)); ++ tx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27); ++ tx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21); ++ tx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15); ++ tx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10); ++ ++ } ++ ++ PHY_DEBUG(("[CAL] ** tx_cal_reg[0] = %d\n", tx_cal_reg[0])); ++ PHY_DEBUG(("[CAL] tx_cal_reg[1] = %d\n", tx_cal_reg[1])); ++ PHY_DEBUG(("[CAL] tx_cal_reg[2] = %d\n", tx_cal_reg[2])); ++ PHY_DEBUG(("[CAL] tx_cal_reg[3] = %d\n", tx_cal_reg[3])); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ if (((tx_cal_reg[0]==7) || (tx_cal_reg[0]==(-8))) && ++ ((tx_cal_reg[3]==7) || (tx_cal_reg[3]==(-8)))) ++ { ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n")); ++ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION SATUATION !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ break; ++ } ++ } ++ else // 2nd-cut ++ { ++ if (((tx_cal_reg[0]==31) || (tx_cal_reg[0]==(-32))) && ++ ((tx_cal_reg[3]==31) || (tx_cal_reg[3]==(-32)))) ++ { ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n")); ++ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION SATUATION !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ break; ++ } ++ } ++ ++ tx_cal[0] = tx_cal[0] + tx_cal_reg[0]; ++ tx_cal[1] = tx_cal[1] + tx_cal_reg[1]; ++ tx_cal[2] = tx_cal[2] + tx_cal_reg[2]; ++ tx_cal[3] = tx_cal[3] + tx_cal_reg[3]; ++ PHY_DEBUG(("[CAL] ** apply tx_cal[0] = %d\n", tx_cal[0])); ++ PHY_DEBUG(("[CAL] apply tx_cal[1] = %d\n", tx_cal[1])); ++ PHY_DEBUG(("[CAL] apply tx_cal[2] = %d\n", tx_cal[2])); ++ PHY_DEBUG(("[CAL] apply tx_cal[3] = %d\n", tx_cal[3])); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ val &= 0x0000FFFF; ++ val |= ((_s32_to_s4(tx_cal[0]) << 28)| ++ (_s32_to_s4(tx_cal[1]) << 24)| ++ (_s32_to_s4(tx_cal[2]) << 20)| ++ (_s32_to_s4(tx_cal[3]) << 16)); ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ PHY_DEBUG(("[CAL] ** CALIB_DATA = 0x%08X\n", val)); ++ return 0; ++ } ++ else // 2nd-cut ++ { ++ val &= 0x000003FF; ++ val |= ((_s32_to_s5(tx_cal[0]) << 27)| ++ (_s32_to_s6(tx_cal[1]) << 21)| ++ (_s32_to_s6(tx_cal[2]) << 15)| ++ (_s32_to_s5(tx_cal[3]) << 10)); ++ hw_set_dxx_reg(phw_data, 0x3C, val); ++ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION = 0x%08X\n", val)); ++ return 0; ++ } ++ ++ // i. Set "calib_start" to 0x0 ++ reg_mode_ctrl &= ~MASK_CALIB_START; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ ++ loop--; ++ } ++ ++ return 1; ++} ++ ++void _tx_iq_calibration_winbond(hw_data_t *phw_data) ++{ ++ u32 reg_agc_ctrl3; ++#ifdef _DEBUG ++ s32 tx_cal_reg[4]; ++ ++#endif ++ u32 reg_mode_ctrl; ++ u32 val; ++ u8 result; ++ ++ PHY_DEBUG(("[CAL] -> [4]_tx_iq_calibration()\n")); ++ ++ //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits ++ phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2); ++ //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit ++ phy_set_rf_data(phw_data, 11, (11<<24)|0x19BDD6); // 20060612.1.a 0x1905D6); ++ //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized ++ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C60A); //0x24C60A (high temperature) ++ //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized ++ phy_set_rf_data(phw_data, 6, (6<<24)|0x34880C); // 20060612.1.a 0x06890C); ++ //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode ++ phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0); ++ //; [BB-chip]: Calibration (6f).Send test pattern ++ //; [BB-chip]: Calibration (6g). Search RXGCL optimal value ++ //; [BB-chip]: Calibration (6h). Caculate TX-path IQ imbalance and setting TX path IQ compensation table ++ //phy_set_rf_data(phw_data, 3, (3<<24)|0x025586); ++ ++ OS_SLEEP(30000); // 20060612.1.a 30ms delay. Add the follow 2 lines ++ //To adjust TXVGA to fit iq_mag_0 range from 1250 ~ 1750 ++ adjust_TXVGA_for_iq_mag( phw_data ); ++ ++ // a. Disable AGC ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3); ++ reg_agc_ctrl3 &= ~BIT(2); ++ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX); ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3); ++ ++ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val); ++ val |= MASK_AGC_FIX_GAIN; ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val); ++ ++ result = _tx_iq_calibration_loop_winbond(phw_data, 150, 100); ++ ++ if (result > 0) ++ { ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ val &= 0x0000FFFF; ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ } ++ else // 2nd-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x3C, &val); ++ val &= 0x000003FF; ++ hw_set_dxx_reg(phw_data, 0x3C, val); ++ } ++ ++ result = _tx_iq_calibration_loop_winbond(phw_data, 300, 200); ++ ++ if (result > 0) ++ { ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ val &= 0x0000FFFF; ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ } ++ else // 2nd-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x3C, &val); ++ val &= 0x000003FF; ++ hw_set_dxx_reg(phw_data, 0x3C, val); ++ } ++ ++ result = _tx_iq_calibration_loop_winbond(phw_data, 500, 400); ++ if (result > 0) ++ { ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ val &= 0x0000FFFF; ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ } ++ else // 2nd-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x3C, &val); ++ val &= 0x000003FF; ++ hw_set_dxx_reg(phw_data, 0x3C, val); ++ } ++ ++ ++ result = _tx_iq_calibration_loop_winbond(phw_data, 700, 500); ++ ++ if (result > 0) ++ { ++ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration> **************\n")); ++ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION FAILURE !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ val &= 0x0000FFFF; ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ } ++ else // 2nd-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x3C, &val); ++ val &= 0x000003FF; ++ hw_set_dxx_reg(phw_data, 0x3C, val); ++ } ++ } ++ } ++ } ++ } ++ ++ // i. Set "calib_start" to 0x0 ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ reg_mode_ctrl &= ~MASK_CALIB_START; ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ ++ // g. Enable AGC ++ //hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val); ++ reg_agc_ctrl3 |= BIT(2); ++ reg_agc_ctrl3 &= ~(MASK_LNA_FIX_GAIN|MASK_AGC_FIX); ++ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3); ++ ++#ifdef _DEBUG ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val)); ++ tx_cal_reg[0] = _s4_to_s32((val & 0xF0000000) >> 28); ++ tx_cal_reg[1] = _s4_to_s32((val & 0x0F000000) >> 24); ++ tx_cal_reg[2] = _s4_to_s32((val & 0x00F00000) >> 20); ++ tx_cal_reg[3] = _s4_to_s32((val & 0x000F0000) >> 16); ++ } ++ else // 2nd-cut ++ { ++ hw_get_dxx_reg(phw_data, 0x3C, &val); ++ PHY_DEBUG(("[CAL] ** 0x3C = 0x%08X\n", val)); ++ tx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27); ++ tx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21); ++ tx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15); ++ tx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10); ++ ++ } ++ ++ PHY_DEBUG(("[CAL] ** tx_cal_reg[0] = %d\n", tx_cal_reg[0])); ++ PHY_DEBUG(("[CAL] tx_cal_reg[1] = %d\n", tx_cal_reg[1])); ++ PHY_DEBUG(("[CAL] tx_cal_reg[2] = %d\n", tx_cal_reg[2])); ++ PHY_DEBUG(("[CAL] tx_cal_reg[3] = %d\n", tx_cal_reg[3])); ++#endif ++ ++ ++ // for test - BEN ++ // RF Control Override ++} ++ ++///////////////////////////////////////////////////////////////////////////////////////// ++u8 _rx_iq_calibration_loop_winbond(hw_data_t *phw_data, u16 factor, u32 frequency) ++{ ++ u32 reg_mode_ctrl; ++ s32 iqcal_tone_i; ++ s32 iqcal_tone_q; ++ s32 iqcal_image_i; ++ s32 iqcal_image_q; ++ s32 rot_tone_i_b; ++ s32 rot_tone_q_b; ++ s32 rot_image_i_b; ++ s32 rot_image_q_b; ++ s32 rx_cal_flt_b[4]; ++ s32 rx_cal[4]; ++ s32 rx_cal_reg[4]; ++ s32 a_2, b_2; ++ s32 sin_b, sin_2b; ++ s32 cos_b, cos_2b; ++ s32 temp1, temp2; ++ u32 val; ++ u16 loop; ++ ++ u32 pwr_tone; ++ u32 pwr_image; ++ u8 verify_count; ++ ++ s32 iqcal_tone_i_avg,iqcal_tone_q_avg; ++ s32 iqcal_image_i_avg,iqcal_image_q_avg; ++ u16 capture_time; ++ ++ PHY_DEBUG(("[CAL] -> [5]_rx_iq_calibration_loop()\n")); ++ PHY_DEBUG(("[CAL] ** factor = %d\n", factor)); ++ ++ ++// RF Control Override ++ hw_get_cxx_reg(phw_data, 0x80, &val); ++ val |= BIT(19); ++ hw_set_cxx_reg(phw_data, 0x80, val); ++ ++// RF_Ctrl ++ hw_get_cxx_reg(phw_data, 0xE4, &val); ++ val |= BIT(0); ++ hw_set_cxx_reg(phw_data, 0xE4, val); ++ PHY_DEBUG(("[CAL] ** RF_CTRL(0xE4) = 0x%08X", val)); ++ ++ hw_set_dxx_reg(phw_data, 0x58, 0x44444444); // IQ_Alpha ++ ++ // b. ++ ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl)); ++ ++ verify_count = 0; ++ ++ //for (loop = 0; loop < 1; loop++) ++ //for (loop = 0; loop < LOOP_TIMES; loop++) ++ loop = LOOP_TIMES; ++ while (loop > 0) ++ { ++ PHY_DEBUG(("[CAL] [%d.] <_rx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1))); ++ iqcal_tone_i_avg=0; ++ iqcal_tone_q_avg=0; ++ iqcal_image_i_avg=0; ++ iqcal_image_q_avg=0; ++ capture_time=0; ++ ++ for(capture_time=0; capture_time<10; capture_time++) ++ { ++ // i. Set "calib_start" to 0x0 ++ reg_mode_ctrl &= ~MASK_CALIB_START; ++ if( !hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl) )//20060718.1 modify ++ return 0; ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); ++ ++ reg_mode_ctrl &= ~MASK_IQCAL_MODE; ++ reg_mode_ctrl |= (MASK_CALIB_START|0x1); ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ pa_stall_execution(US); //Should be read out after 450us ++ ++ // c. ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val)); ++ ++ iqcal_tone_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_tone_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ PHY_DEBUG(("[CAL] ** iqcal_tone_i = %d, iqcal_tone_q = %d\n", ++ iqcal_tone_i, iqcal_tone_q)); ++ ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val); ++ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val)); ++ ++ iqcal_image_i = _s13_to_s32(val & 0x00001FFF); ++ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13); ++ PHY_DEBUG(("[CAL] ** iqcal_image_i = %d, iqcal_image_q = %d\n", ++ iqcal_image_i, iqcal_image_q)); ++ if( capture_time == 0) ++ { ++ continue; ++ } ++ else ++ { ++ iqcal_image_i_avg=( iqcal_image_i_avg*(capture_time-1) +iqcal_image_i)/capture_time; ++ iqcal_image_q_avg=( iqcal_image_q_avg*(capture_time-1) +iqcal_image_q)/capture_time; ++ iqcal_tone_i_avg=( iqcal_tone_i_avg*(capture_time-1) +iqcal_tone_i)/capture_time; ++ iqcal_tone_q_avg=( iqcal_tone_q_avg*(capture_time-1) +iqcal_tone_q)/capture_time; ++ } ++ } ++ ++ ++ iqcal_image_i = iqcal_image_i_avg; ++ iqcal_image_q = iqcal_image_q_avg; ++ iqcal_tone_i = iqcal_tone_i_avg; ++ iqcal_tone_q = iqcal_tone_q_avg; ++ ++ // d. ++ rot_tone_i_b = (iqcal_tone_i * iqcal_tone_i + ++ iqcal_tone_q * iqcal_tone_q) / 1024; ++ rot_tone_q_b = (iqcal_tone_i * iqcal_tone_q * (-1) + ++ iqcal_tone_q * iqcal_tone_i) / 1024; ++ rot_image_i_b = (iqcal_image_i * iqcal_tone_i - ++ iqcal_image_q * iqcal_tone_q) / 1024; ++ rot_image_q_b = (iqcal_image_i * iqcal_tone_q + ++ iqcal_image_q * iqcal_tone_i) / 1024; ++ ++ PHY_DEBUG(("[CAL] ** rot_tone_i_b = %d\n", rot_tone_i_b)); ++ PHY_DEBUG(("[CAL] ** rot_tone_q_b = %d\n", rot_tone_q_b)); ++ PHY_DEBUG(("[CAL] ** rot_image_i_b = %d\n", rot_image_i_b)); ++ PHY_DEBUG(("[CAL] ** rot_image_q_b = %d\n", rot_image_q_b)); ++ ++ // f. ++ if (rot_tone_i_b == 0) ++ { ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> ERROR *******\n")); ++ PHY_DEBUG(("[CAL] ** rot_tone_i_b=0 to calculate EPS and THETA !!\n")); ++ PHY_DEBUG(("[CAL] ******************************************\n")); ++ break; ++ } ++ ++ a_2 = (rot_image_i_b * 32768) / rot_tone_i_b - ++ phw_data->iq_rsdl_gain_tx_d2; ++ b_2 = (rot_image_q_b * 32768) / rot_tone_i_b - ++ phw_data->iq_rsdl_phase_tx_d2; ++ ++ PHY_DEBUG(("[CAL] ** iq_rsdl_gain_tx_d2 = %d\n", phw_data->iq_rsdl_gain_tx_d2)); ++ PHY_DEBUG(("[CAL] ** iq_rsdl_phase_tx_d2= %d\n", phw_data->iq_rsdl_phase_tx_d2)); ++ PHY_DEBUG(("[CAL] ***** EPSILON/2 = %d\n", a_2)); ++ PHY_DEBUG(("[CAL] ***** THETA/2 = %d\n", b_2)); ++ ++ _sin_cos(b_2, &sin_b, &cos_b); ++ _sin_cos(b_2*2, &sin_2b, &cos_2b); ++ PHY_DEBUG(("[CAL] ** sin(b/2)=%d, cos(b/2)=%d\n", sin_b, cos_b)); ++ PHY_DEBUG(("[CAL] ** sin(b)=%d, cos(b)=%d\n", sin_2b, cos_2b)); ++ ++ if (cos_2b == 0) ++ { ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> ERROR *******\n")); ++ PHY_DEBUG(("[CAL] ** cos(b)=0 !!\n")); ++ PHY_DEBUG(("[CAL] ******************************************\n")); ++ break; ++ } ++ ++ // 1280 * 32768 = 41943040 ++ temp1 = (41943040/cos_2b)*cos_b; ++ ++ //temp2 = (41943040/cos_2b)*sin_b*(-1); ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ temp2 = (41943040/cos_2b)*sin_b*(-1); ++ } ++ else // 2nd-cut ++ { ++ temp2 = (41943040*4/cos_2b)*sin_b*(-1); ++ } ++ ++ rx_cal_flt_b[0] = _floor(temp1/(32768+a_2)); ++ rx_cal_flt_b[1] = _floor(temp2/(32768-a_2)); ++ rx_cal_flt_b[2] = _floor(temp2/(32768+a_2)); ++ rx_cal_flt_b[3] = _floor(temp1/(32768-a_2)); ++ ++ PHY_DEBUG(("[CAL] ** rx_cal_flt_b[0] = %d\n", rx_cal_flt_b[0])); ++ PHY_DEBUG(("[CAL] rx_cal_flt_b[1] = %d\n", rx_cal_flt_b[1])); ++ PHY_DEBUG(("[CAL] rx_cal_flt_b[2] = %d\n", rx_cal_flt_b[2])); ++ PHY_DEBUG(("[CAL] rx_cal_flt_b[3] = %d\n", rx_cal_flt_b[3])); ++ ++ rx_cal[0] = rx_cal_flt_b[0] - 128; ++ rx_cal[1] = rx_cal_flt_b[1]; ++ rx_cal[2] = rx_cal_flt_b[2]; ++ rx_cal[3] = rx_cal_flt_b[3] - 128; ++ PHY_DEBUG(("[CAL] ** rx_cal[0] = %d\n", rx_cal[0])); ++ PHY_DEBUG(("[CAL] rx_cal[1] = %d\n", rx_cal[1])); ++ PHY_DEBUG(("[CAL] rx_cal[2] = %d\n", rx_cal[2])); ++ PHY_DEBUG(("[CAL] rx_cal[3] = %d\n", rx_cal[3])); ++ ++ // e. ++ pwr_tone = (iqcal_tone_i*iqcal_tone_i + iqcal_tone_q*iqcal_tone_q); ++ pwr_image = (iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q)*factor; ++ ++ PHY_DEBUG(("[CAL] ** pwr_tone = %d\n", pwr_tone)); ++ PHY_DEBUG(("[CAL] ** pwr_image = %d\n", pwr_image)); ++ ++ if (pwr_tone > pwr_image) ++ { ++ verify_count++; ++ ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *************\n")); ++ PHY_DEBUG(("[CAL] ** VERIFY OK # %d !!\n", verify_count)); ++ PHY_DEBUG(("[CAL] ******************************************\n")); ++ ++ if (verify_count > 2) ++ { ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n")); ++ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION OK !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ return 0; ++ } ++ ++ continue; ++ } ++ // g. ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val)); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ rx_cal_reg[0] = _s4_to_s32((val & 0x0000F000) >> 12); ++ rx_cal_reg[1] = _s4_to_s32((val & 0x00000F00) >> 8); ++ rx_cal_reg[2] = _s4_to_s32((val & 0x000000F0) >> 4); ++ rx_cal_reg[3] = _s4_to_s32((val & 0x0000000F)); ++ } ++ else // 2nd-cut ++ { ++ rx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27); ++ rx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21); ++ rx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15); ++ rx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10); ++ } ++ ++ PHY_DEBUG(("[CAL] ** rx_cal_reg[0] = %d\n", rx_cal_reg[0])); ++ PHY_DEBUG(("[CAL] rx_cal_reg[1] = %d\n", rx_cal_reg[1])); ++ PHY_DEBUG(("[CAL] rx_cal_reg[2] = %d\n", rx_cal_reg[2])); ++ PHY_DEBUG(("[CAL] rx_cal_reg[3] = %d\n", rx_cal_reg[3])); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ if (((rx_cal_reg[0]==7) || (rx_cal_reg[0]==(-8))) && ++ ((rx_cal_reg[3]==7) || (rx_cal_reg[3]==(-8)))) ++ { ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n")); ++ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION SATUATION !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ break; ++ } ++ } ++ else // 2nd-cut ++ { ++ if (((rx_cal_reg[0]==31) || (rx_cal_reg[0]==(-32))) && ++ ((rx_cal_reg[3]==31) || (rx_cal_reg[3]==(-32)))) ++ { ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n")); ++ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION SATUATION !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ break; ++ } ++ } ++ ++ rx_cal[0] = rx_cal[0] + rx_cal_reg[0]; ++ rx_cal[1] = rx_cal[1] + rx_cal_reg[1]; ++ rx_cal[2] = rx_cal[2] + rx_cal_reg[2]; ++ rx_cal[3] = rx_cal[3] + rx_cal_reg[3]; ++ PHY_DEBUG(("[CAL] ** apply rx_cal[0] = %d\n", rx_cal[0])); ++ PHY_DEBUG(("[CAL] apply rx_cal[1] = %d\n", rx_cal[1])); ++ PHY_DEBUG(("[CAL] apply rx_cal[2] = %d\n", rx_cal[2])); ++ PHY_DEBUG(("[CAL] apply rx_cal[3] = %d\n", rx_cal[3])); ++ ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ val &= 0x0000FFFF; ++ val |= ((_s32_to_s4(rx_cal[0]) << 12)| ++ (_s32_to_s4(rx_cal[1]) << 8)| ++ (_s32_to_s4(rx_cal[2]) << 4)| ++ (_s32_to_s4(rx_cal[3]))); ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ } ++ else // 2nd-cut ++ { ++ val &= 0x000003FF; ++ val |= ((_s32_to_s5(rx_cal[0]) << 27)| ++ (_s32_to_s6(rx_cal[1]) << 21)| ++ (_s32_to_s6(rx_cal[2]) << 15)| ++ (_s32_to_s5(rx_cal[3]) << 10)); ++ hw_set_dxx_reg(phw_data, 0x54, val); ++ ++ if( loop == 3 ) ++ return 0; ++ } ++ PHY_DEBUG(("[CAL] ** CALIB_DATA = 0x%08X\n", val)); ++ ++ loop--; ++ } ++ ++ return 1; ++} ++ ++////////////////////////////////////////////////////////// ++ ++////////////////////////////////////////////////////////////////////////// ++void _rx_iq_calibration_winbond(hw_data_t *phw_data, u32 frequency) ++{ ++// figo 20050523 marked thsi flag for can't compile for relesase ++#ifdef _DEBUG ++ s32 rx_cal_reg[4]; ++ u32 val; ++#endif ++ ++ u8 result; ++ ++ PHY_DEBUG(("[CAL] -> [5]_rx_iq_calibration()\n")); ++// a. Set RFIC to "RX calibration mode" ++ //; ----- Calibration (7). RX path IQ imbalance calibration loop ++ // 0x01 0xFFBFC2 ; 3FEFF ; Calibration (7a). enable RX IQ calibration loop circuits ++ phy_set_rf_data(phw_data, 1, (1<<24)|0xEFBFC2); ++ // 0x0B 0x1A01D6 ; 06817 ; Calibration (7b). enable RX I/Q cal loop SW1 circuit ++ phy_set_rf_data(phw_data, 11, (11<<24)|0x1A05D6); ++ //0x05 0x24848A ; 09212 ; Calibration (7c). setting TX-VGA gain (TXGCH) to 2 --> to be optimized ++ phy_set_rf_data(phw_data, 5, (5<<24)| phw_data->txvga_setting_for_cal); ++ //0x06 0x06840C ; 01A10 ; Calibration (7d). RXGCH=00; RXGCL=010 000 (RXVGA) --> to be optimized ++ phy_set_rf_data(phw_data, 6, (6<<24)|0x06834C); ++ //0x00 0xFFF1C0 ; 3F7C7 ; Calibration (7e). turn on IQ imbalance/Test mode ++ phy_set_rf_data(phw_data, 0, (0<<24)|0xFFF1C0); ++ ++ // ; [BB-chip]: Calibration (7f). Send test pattern ++ // ; [BB-chip]: Calibration (7g). Search RXGCL optimal value ++ // ; [BB-chip]: Calibration (7h). Caculate RX-path IQ imbalance and setting RX path IQ compensation table ++ ++ result = _rx_iq_calibration_loop_winbond(phw_data, 12589, frequency); ++ ++ if (result > 0) ++ { ++ _reset_rx_cal(phw_data); ++ result = _rx_iq_calibration_loop_winbond(phw_data, 7943, frequency); ++ ++ if (result > 0) ++ { ++ _reset_rx_cal(phw_data); ++ result = _rx_iq_calibration_loop_winbond(phw_data, 5011, frequency); ++ ++ if (result > 0) ++ { ++ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration> **************\n")); ++ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION FAILURE !!\n")); ++ PHY_DEBUG(("[CAL] **************************************\n")); ++ _reset_rx_cal(phw_data); ++ } ++ } ++ } ++ ++#ifdef _DEBUG ++ hw_get_dxx_reg(phw_data, 0x54, &val); ++ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val)); ++ ++ if (phw_data->revision == 0x2002) // 1st-cut ++ { ++ rx_cal_reg[0] = _s4_to_s32((val & 0x0000F000) >> 12); ++ rx_cal_reg[1] = _s4_to_s32((val & 0x00000F00) >> 8); ++ rx_cal_reg[2] = _s4_to_s32((val & 0x000000F0) >> 4); ++ rx_cal_reg[3] = _s4_to_s32((val & 0x0000000F)); ++ } ++ else // 2nd-cut ++ { ++ rx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27); ++ rx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21); ++ rx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15); ++ rx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10); ++ } ++ ++ PHY_DEBUG(("[CAL] ** rx_cal_reg[0] = %d\n", rx_cal_reg[0])); ++ PHY_DEBUG(("[CAL] rx_cal_reg[1] = %d\n", rx_cal_reg[1])); ++ PHY_DEBUG(("[CAL] rx_cal_reg[2] = %d\n", rx_cal_reg[2])); ++ PHY_DEBUG(("[CAL] rx_cal_reg[3] = %d\n", rx_cal_reg[3])); ++#endif ++ ++} ++ ++//////////////////////////////////////////////////////////////////////// ++void phy_calibration_winbond(hw_data_t *phw_data, u32 frequency) ++{ ++ u32 reg_mode_ctrl; ++ u32 iq_alpha; ++ ++ PHY_DEBUG(("[CAL] -> phy_calibration_winbond()\n")); ++ ++ // 20040701 1.1.25.1000 kevin ++ hw_get_cxx_reg(phw_data, 0x80, &mac_ctrl); ++ hw_get_cxx_reg(phw_data, 0xE4, &rf_ctrl); ++ hw_get_dxx_reg(phw_data, 0x58, &iq_alpha); ++ ++ ++ ++ _rxadc_dc_offset_cancellation_winbond(phw_data, frequency); ++ //_txidac_dc_offset_cancellation_winbond(phw_data); ++ //_txqdac_dc_offset_cacellation_winbond(phw_data); ++ ++ _tx_iq_calibration_winbond(phw_data); ++ _rx_iq_calibration_winbond(phw_data, frequency); ++ ++ //------------------------------------------------------------------------ ++ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); ++ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE|MASK_CALIB_START); // set when finish ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ ++ // i. Set RFIC to "Normal mode" ++ hw_set_cxx_reg(phw_data, 0x80, mac_ctrl); ++ hw_set_cxx_reg(phw_data, 0xE4, rf_ctrl); ++ hw_set_dxx_reg(phw_data, 0x58, iq_alpha); ++ ++ ++ //------------------------------------------------------------------------ ++ phy_init_rf(phw_data); ++ ++} ++ ++//=========================== ++void phy_set_rf_data( phw_data_t pHwData, u32 index, u32 value ) ++{ ++ u32 ltmp=0; ++ ++ switch( pHwData->phy_type ) ++ { ++ case RF_MAXIM_2825: ++ case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331) ++ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 ); ++ break; ++ ++ case RF_MAXIM_2827: ++ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 ); ++ break; ++ ++ case RF_MAXIM_2828: ++ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 ); ++ break; ++ ++ case RF_MAXIM_2829: ++ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 ); ++ break; ++ ++ case RF_AIROHA_2230: ++ case RF_AIROHA_2230S: // 20060420 Add this ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( value, 20 ); ++ break; ++ ++ case RF_AIROHA_7230: ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | (value&0xffffff); ++ break; ++ ++ case RF_WB_242: ++ case RF_WB_242_1: // 20060619.5 Add ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( value, 24 ); ++ break; ++ } ++ ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++} ++ ++// 20060717 modify as Bruce's mail ++unsigned char adjust_TXVGA_for_iq_mag(hw_data_t *phw_data) ++{ ++ int init_txvga = 0; ++ u32 reg_mode_ctrl; ++ u32 val; ++ s32 iqcal_tone_i0; ++ s32 iqcal_tone_q0; ++ u32 sqsum; ++ s32 iq_mag_0_tx; ++ u8 reg_state; ++ int current_txvga; ++ ++ ++ reg_state = 0; ++ for( init_txvga=0; init_txvga<10; init_txvga++) ++ { ++ current_txvga = ( 0x24C40A|(init_txvga<<6) ); ++ phy_set_rf_data(phw_data, 5, ((5<<24)|current_txvga) ); ++ phw_data->txvga_setting_for_cal = current_txvga; ++ ++ //pa_stall_execution(30000);//Sleep(30); ++ OS_SLEEP(30000); // 20060612.1.a ++ ++ if( !hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl) ) // 20060718.1 modify ++ return FALSE; ++ ++ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl)); ++ ++ // a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to ++ // enable "IQ alibration Mode II" ++ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); ++ reg_mode_ctrl &= ~MASK_IQCAL_MODE; ++ reg_mode_ctrl |= (MASK_CALIB_START|0x02); ++ reg_mode_ctrl |= (MASK_CALIB_START|0x02|2<<2); ++ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl); ++ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl)); ++ ++ //pa_stall_execution(US); ++ OS_SLEEP(1); // 20060612.1.a ++ ++ //pa_stall_execution(300);//Sleep(30); ++ OS_SLEEP(300); // 20060612.1.a ++ ++ // b. ++ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val); ++ ++ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val)); ++ //pa_stall_execution(US); ++ //pa_stall_execution(300);//Sleep(30); ++ OS_SLEEP(300); // 20060612.1.a ++ ++ iqcal_tone_i0 = _s13_to_s32(val & 0x00001FFF); ++ iqcal_tone_q0 = _s13_to_s32((val & 0x03FFE000) >> 13); ++ PHY_DEBUG(("[CAL] ** iqcal_tone_i0=%d, iqcal_tone_q0=%d\n", ++ iqcal_tone_i0, iqcal_tone_q0)); ++ ++ sqsum = iqcal_tone_i0*iqcal_tone_i0 + iqcal_tone_q0*iqcal_tone_q0; ++ iq_mag_0_tx = (s32) _sqrt(sqsum); ++ PHY_DEBUG(("[CAL] ** auto_adjust_txvga_for_iq_mag_0_tx=%d\n", iq_mag_0_tx)); ++ ++ if( iq_mag_0_tx>=700 && iq_mag_0_tx<=1750 ) ++ break; ++ else if(iq_mag_0_tx > 1750) ++ { ++ init_txvga=-2; ++ continue; ++ } ++ else ++ continue; ++ ++ } ++ ++ if( iq_mag_0_tx>=700 && iq_mag_0_tx<=1750 ) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++ ++ +diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h +new file mode 100644 +index 0000000..b6a65d3 +--- /dev/null ++++ b/drivers/staging/winbond/phy_calibration.h +@@ -0,0 +1,101 @@ ++// 20031229 Turbo add ++#define REG_AGC_CTRL1 0x1000 ++#define REG_AGC_CTRL2 0x1004 ++#define REG_AGC_CTRL3 0x1008 ++#define REG_AGC_CTRL4 0x100C ++#define REG_AGC_CTRL5 0x1010 ++#define REG_AGC_CTRL6 0x1014 ++#define REG_AGC_CTRL7 0x1018 ++#define REG_AGC_CTRL8 0x101C ++#define REG_AGC_CTRL9 0x1020 ++#define REG_AGC_CTRL10 0x1024 ++#define REG_CCA_CTRL 0x1028 ++#define REG_A_ACQ_CTRL 0x102C ++#define REG_B_ACQ_CTRL 0x1030 ++#define REG_A_TXRX_CTRL 0x1034 ++#define REG_B_TXRX_CTRL 0x1038 ++#define REG_A_TX_COEF3 0x103C ++#define REG_A_TX_COEF2 0x1040 ++#define REG_A_TX_COEF1 0x1044 ++#define REG_B_TX_COEF2 0x1048 ++#define REG_B_TX_COEF1 0x104C ++#define REG_MODE_CTRL 0x1050 ++#define REG_CALIB_DATA 0x1054 ++#define REG_IQ_ALPHA 0x1058 ++#define REG_DC_CANCEL 0x105C ++#define REG_WTO_READ 0x1060 ++#define REG_OFFSET_READ 0x1064 ++#define REG_CALIB_READ1 0x1068 ++#define REG_CALIB_READ2 0x106C ++#define REG_A_FREQ_EST 0x1070 ++ ++ ++ ++ ++// 20031101 Turbo add ++#define MASK_AMER_OFF_REG BIT(31) ++ ++#define MASK_BMER_OFF_REG BIT(31) ++ ++#define MASK_LNA_FIX_GAIN (BIT(3)|BIT(4)) ++#define MASK_AGC_FIX BIT(1) ++ ++#define MASK_AGC_FIX_GAIN 0xFF00 ++ ++#define MASK_ADC_DC_CAL_STR BIT(10) ++#define MASK_CALIB_START BIT(4) ++#define MASK_IQCAL_TONE_SEL (BIT(3)|BIT(2)) ++#define MASK_IQCAL_MODE (BIT(1)|BIT(0)) ++ ++#define MASK_TX_CAL_0 0xF0000000 ++#define TX_CAL_0_SHIFT 28 ++#define MASK_TX_CAL_1 0x0F000000 ++#define TX_CAL_1_SHIFT 24 ++#define MASK_TX_CAL_2 0x00F00000 ++#define TX_CAL_2_SHIFT 20 ++#define MASK_TX_CAL_3 0x000F0000 ++#define TX_CAL_3_SHIFT 16 ++#define MASK_RX_CAL_0 0x0000F000 ++#define RX_CAL_0_SHIFT 12 ++#define MASK_RX_CAL_1 0x00000F00 ++#define RX_CAL_1_SHIFT 8 ++#define MASK_RX_CAL_2 0x000000F0 ++#define RX_CAL_2_SHIFT 4 ++#define MASK_RX_CAL_3 0x0000000F ++#define RX_CAL_3_SHIFT 0 ++ ++#define MASK_CANCEL_DC_I 0x3E0 ++#define CANCEL_DC_I_SHIFT 5 ++#define MASK_CANCEL_DC_Q 0x01F ++#define CANCEL_DC_Q_SHIFT 0 ++ ++// LA20040210 kevin ++//#define MASK_ADC_DC_CAL_I(x) (((x)&0x1FE00)>>9) ++//#define MASK_ADC_DC_CAL_Q(x) ((x)&0x1FF) ++#define MASK_ADC_DC_CAL_I(x) (((x)&0x0003FE00)>>9) ++#define MASK_ADC_DC_CAL_Q(x) ((x)&0x000001FF) ++ ++// LA20040210 kevin (Turbo has wrong definition) ++//#define MASK_IQCAL_TONE_I 0x7FFC000 ++//#define SHIFT_IQCAL_TONE_I(x) ((x)>>13) ++//#define MASK_IQCAL_TONE_Q 0x1FFF ++//#define SHIFT_IQCAL_TONE_Q(x) ((x)>>0) ++#define MASK_IQCAL_TONE_I 0x00001FFF ++#define SHIFT_IQCAL_TONE_I(x) ((x)>>0) ++#define MASK_IQCAL_TONE_Q 0x03FFE000 ++#define SHIFT_IQCAL_TONE_Q(x) ((x)>>13) ++ ++// LA20040210 kevin (Turbo has wrong definition) ++//#define MASK_IQCAL_IMAGE_I 0x7FFC000 ++//#define SHIFT_IQCAL_IMAGE_I(x) ((x)>>13) ++//#define MASK_IQCAL_IMAGE_Q 0x1FFF ++//#define SHIFT_IQCAL_IMAGE_Q(x) ((x)>>0) ++ ++//#define MASK_IQCAL_IMAGE_I 0x00001FFF ++//#define SHIFT_IQCAL_IMAGE_I(x) ((x)>>0) ++//#define MASK_IQCAL_IMAGE_Q 0x03FFE000 ++//#define SHIFT_IQCAL_IMAGE_Q(x) ((x)>>13) ++ ++void phy_set_rf_data( phw_data_t pHwData, u32 index, u32 value ); ++#define phy_init_rf( _A ) //RFSynthesizer_initial( _A ) ++ +diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c +new file mode 100644 +index 0000000..b475c7a +--- /dev/null ++++ b/drivers/staging/winbond/reg.c +@@ -0,0 +1,2683 @@ ++#include "os_common.h" ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++// Original Phy.h ++//***************************************************************************** ++ ++/***************************************************************************** ++; For MAXIM2825/6/7 Ver. 331 or more ++; Edited by Tiger, Sep-17-2003 ++; revised by Ben, Sep-18-2003 ++ ++0x00 0x000a2 ++0x01 0x21cc0 ++;0x02 0x13802 ++0x02 0x1383a ++ ++;channe1 01 ; 0x03 0x30142 ; 0x04 0x0b333; ++;channe1 02 ;0x03 0x32141 ;0x04 0x08444; ++;channe1 03 ;0x03 0x32143 ;0x04 0x0aeee; ++;channe1 04 ;0x03 0x32142 ;0x04 0x0b333; ++;channe1 05 ;0x03 0x31141 ;0x04 0x08444; ++;channe1 06 ; ++0x03 0x31143; ++0x04 0x0aeee; ++;channe1 07 ;0x03 0x31142 ;0x04 0x0b333; ++;channe1 08 ;0x03 0x33141 ;0x04 0x08444; ++;channe1 09 ;0x03 0x33143 ;0x04 0x0aeee; ++;channe1 10 ;0x03 0x33142 ;0x04 0x0b333; ++;channe1 11 ;0x03 0x30941 ;0x04 0x08444; ++;channe1 12 ;0x03 0x30943 ;0x04 0x0aeee; ++;channe1 13 ;0x03 0x30942 ;0x04 0x0b333; ++ ++0x05 0x28986 ++0x06 0x18008 ++0x07 0x38400 ++0x08 0x05100; 100 Hz DC ++;0x08 0x05900; 30 KHz DC ++0x09 0x24f08 ++0x0a 0x17e00, 0x17ea0 ++0x0b 0x37d80 ++0x0c 0x0c900 // 0x0ca00 (lager power 9db than 0x0c000), 0x0c000 ++*****************************************************************************/ ++// MAX2825 (pure b/g) ++u32 max2825_rf_data[] = ++{ ++ (0x00<<18)|0x000a2, ++ (0x01<<18)|0x21cc0, ++ (0x02<<18)|0x13806, ++ (0x03<<18)|0x30142, ++ (0x04<<18)|0x0b333, ++ (0x05<<18)|0x289A6, ++ (0x06<<18)|0x18008, ++ (0x07<<18)|0x38000, ++ (0x08<<18)|0x05100, ++ (0x09<<18)|0x24f08, ++ (0x0A<<18)|0x14000, ++ (0x0B<<18)|0x37d80, ++ (0x0C<<18)|0x0c100 // 11a: 0x0c300, 11g: 0x0c100 ++}; ++ ++u32 max2825_channel_data_24[][3] = ++{ ++ {(0x03<<18)|0x30142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 01 ++ {(0x03<<18)|0x32141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 02 ++ {(0x03<<18)|0x32143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 03 ++ {(0x03<<18)|0x32142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 04 ++ {(0x03<<18)|0x31141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 05 ++ {(0x03<<18)|0x31143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 06 ++ {(0x03<<18)|0x31142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 07 ++ {(0x03<<18)|0x33141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 08 ++ {(0x03<<18)|0x33143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 09 ++ {(0x03<<18)|0x33142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 10 ++ {(0x03<<18)|0x30941, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 11 ++ {(0x03<<18)|0x30943, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 12 ++ {(0x03<<18)|0x30942, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 13 ++ {(0x03<<18)|0x32941, (0x04<<18)|0x09999, (0x05<<18)|0x289A6} // 14 (2484MHz) hhmodify ++}; ++ ++u32 max2825_power_data_24[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100}; ++ ++/****************************************************************************/ ++// MAX2827 (a/b/g) ++u32 max2827_rf_data[] = ++{ ++ (0x00<<18)|0x000a2, ++ (0x01<<18)|0x21cc0, ++ (0x02<<18)|0x13806, ++ (0x03<<18)|0x30142, ++ (0x04<<18)|0x0b333, ++ (0x05<<18)|0x289A6, ++ (0x06<<18)|0x18008, ++ (0x07<<18)|0x38000, ++ (0x08<<18)|0x05100, ++ (0x09<<18)|0x24f08, ++ (0x0A<<18)|0x14000, ++ (0x0B<<18)|0x37d80, ++ (0x0C<<18)|0x0c100 // 11a: 0x0c300, 11g: 0x0c100 ++}; ++ ++u32 max2827_channel_data_24[][3] = ++{ ++ {(0x03<<18)|0x30142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 01 ++ {(0x03<<18)|0x32141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 02 ++ {(0x03<<18)|0x32143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 03 ++ {(0x03<<18)|0x32142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 04 ++ {(0x03<<18)|0x31141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 05 ++ {(0x03<<18)|0x31143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 06 ++ {(0x03<<18)|0x31142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 07 ++ {(0x03<<18)|0x33141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 08 ++ {(0x03<<18)|0x33143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 09 ++ {(0x03<<18)|0x33142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 10 ++ {(0x03<<18)|0x30941, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 11 ++ {(0x03<<18)|0x30943, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 12 ++ {(0x03<<18)|0x30942, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 13 ++ {(0x03<<18)|0x32941, (0x04<<18)|0x09999, (0x05<<18)|0x289A6} // 14 (2484MHz) hhmodify ++}; ++ ++u32 max2827_channel_data_50[][3] = ++{ ++ {(0x03<<18)|0x33cc3, (0x04<<18)|0x08ccc, (0x05<<18)|0x2A9A6}, // channel 36 ++ {(0x03<<18)|0x302c0, (0x04<<18)|0x08000, (0x05<<18)|0x2A9A6}, // channel 40 ++ {(0x03<<18)|0x302c2, (0x04<<18)|0x0b333, (0x05<<18)|0x2A9A6}, // channel 44 ++ {(0x03<<18)|0x322c1, (0x04<<18)|0x09999, (0x05<<18)|0x2A9A6}, // channel 48 ++ {(0x03<<18)|0x312c1, (0x04<<18)|0x0a666, (0x05<<18)|0x2A9A6}, // channel 52 ++ {(0x03<<18)|0x332c3, (0x04<<18)|0x08ccc, (0x05<<18)|0x2A9A6}, // channel 56 ++ {(0x03<<18)|0x30ac0, (0x04<<18)|0x08000, (0x05<<18)|0x2A9A6}, // channel 60 ++ {(0x03<<18)|0x30ac2, (0x04<<18)|0x0b333, (0x05<<18)|0x2A9A6} // channel 64 ++}; ++ ++u32 max2827_power_data_24[] = {(0x0C<<18)|0x0C000, (0x0C<<18)|0x0D600, (0x0C<<18)|0x0C100}; ++u32 max2827_power_data_50[] = {(0x0C<<18)|0x0C400, (0x0C<<18)|0x0D500, (0x0C<<18)|0x0C300}; ++ ++/****************************************************************************/ ++// MAX2828 (a/b/g) ++u32 max2828_rf_data[] = ++{ ++ (0x00<<18)|0x000a2, ++ (0x01<<18)|0x21cc0, ++ (0x02<<18)|0x13806, ++ (0x03<<18)|0x30142, ++ (0x04<<18)|0x0b333, ++ (0x05<<18)|0x289A6, ++ (0x06<<18)|0x18008, ++ (0x07<<18)|0x38000, ++ (0x08<<18)|0x05100, ++ (0x09<<18)|0x24f08, ++ (0x0A<<18)|0x14000, ++ (0x0B<<18)|0x37d80, ++ (0x0C<<18)|0x0c100 // 11a: 0x0c300, 11g: 0x0c100 ++}; ++ ++u32 max2828_channel_data_24[][3] = ++{ ++ {(0x03<<18)|0x30142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 01 ++ {(0x03<<18)|0x32141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 02 ++ {(0x03<<18)|0x32143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 03 ++ {(0x03<<18)|0x32142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 04 ++ {(0x03<<18)|0x31141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 05 ++ {(0x03<<18)|0x31143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 06 ++ {(0x03<<18)|0x31142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 07 ++ {(0x03<<18)|0x33141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 08 ++ {(0x03<<18)|0x33143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 09 ++ {(0x03<<18)|0x33142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 10 ++ {(0x03<<18)|0x30941, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 11 ++ {(0x03<<18)|0x30943, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 12 ++ {(0x03<<18)|0x30942, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 13 ++ {(0x03<<18)|0x32941, (0x04<<18)|0x09999, (0x05<<18)|0x289A6} // 14 (2484MHz) hhmodify ++}; ++ ++u32 max2828_channel_data_50[][3] = ++{ ++ {(0x03<<18)|0x33cc3, (0x04<<18)|0x08ccc, (0x05<<18)|0x289A6}, // channel 36 ++ {(0x03<<18)|0x302c0, (0x04<<18)|0x08000, (0x05<<18)|0x289A6}, // channel 40 ++ {(0x03<<18)|0x302c2, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channel 44 ++ {(0x03<<18)|0x322c1, (0x04<<18)|0x09999, (0x05<<18)|0x289A6}, // channel 48 ++ {(0x03<<18)|0x312c1, (0x04<<18)|0x0a666, (0x05<<18)|0x289A6}, // channel 52 ++ {(0x03<<18)|0x332c3, (0x04<<18)|0x08ccc, (0x05<<18)|0x289A6}, // channel 56 ++ {(0x03<<18)|0x30ac0, (0x04<<18)|0x08000, (0x05<<18)|0x289A6}, // channel 60 ++ {(0x03<<18)|0x30ac2, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6} // channel 64 ++}; ++ ++u32 max2828_power_data_24[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100}; ++u32 max2828_power_data_50[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100}; ++ ++/****************************************************************************/ ++// LA20040728 kevin ++// MAX2829 (a/b/g) ++u32 max2829_rf_data[] = ++{ ++ (0x00<<18)|0x000a2, ++ (0x01<<18)|0x23520, ++ (0x02<<18)|0x13802, ++ (0x03<<18)|0x30142, ++ (0x04<<18)|0x0b333, ++ (0x05<<18)|0x28906, ++ (0x06<<18)|0x18008, ++ (0x07<<18)|0x3B500, ++ (0x08<<18)|0x05100, ++ (0x09<<18)|0x24f08, ++ (0x0A<<18)|0x14000, ++ (0x0B<<18)|0x37d80, ++ (0x0C<<18)|0x0F300 //TXVGA=51, (MAX-6 dB) ++}; ++ ++u32 max2829_channel_data_24[][3] = ++{ ++ {(3<<18)|0x30142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 01 (2412MHz) ++ {(3<<18)|0x32141, (4<<18)|0x08444, (5<<18)|0x289C6}, // 02 (2417MHz) ++ {(3<<18)|0x32143, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 03 (2422MHz) ++ {(3<<18)|0x32142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 04 (2427MHz) ++ {(3<<18)|0x31141, (4<<18)|0x08444, (5<<18)|0x289C6}, // 05 (2432MHz) ++ {(3<<18)|0x31143, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 06 (2437MHz) ++ {(3<<18)|0x31142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 07 (2442MHz) ++ {(3<<18)|0x33141, (4<<18)|0x08444, (5<<18)|0x289C6}, // 08 (2447MHz) ++ {(3<<18)|0x33143, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 09 (2452MHz) ++ {(3<<18)|0x33142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 10 (2457MHz) ++ {(3<<18)|0x30941, (4<<18)|0x08444, (5<<18)|0x289C6}, // 11 (2462MHz) ++ {(3<<18)|0x30943, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 12 (2467MHz) ++ {(3<<18)|0x30942, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 13 (2472MHz) ++ {(3<<18)|0x32941, (4<<18)|0x09999, (5<<18)|0x289C6}, // 14 (2484MHz) hh-modify ++}; ++ ++u32 max2829_channel_data_50[][4] = ++{ ++ {36, (3<<18)|0x33cc3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 36 (5.180GHz) ++ {40, (3<<18)|0x302c0, (4<<18)|0x08000, (5<<18)|0x2A946}, // 40 (5.200GHz) ++ {44, (3<<18)|0x302c2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 44 (5.220GHz) ++ {48, (3<<18)|0x322c1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 48 (5.240GHz) ++ {52, (3<<18)|0x312c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 52 (5.260GHz) ++ {56, (3<<18)|0x332c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 56 (5.280GHz) ++ {60, (3<<18)|0x30ac0, (4<<18)|0x08000, (5<<18)|0x2A946}, // 60 (5.300GHz) ++ {64, (3<<18)|0x30ac2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 64 (5.320GHz) ++ ++ {100, (3<<18)|0x30ec0, (4<<18)|0x08000, (5<<18)|0x2A9C6}, // 100 (5.500GHz) ++ {104, (3<<18)|0x30ec2, (4<<18)|0x0b333, (5<<18)|0x2A9C6}, // 104 (5.520GHz) ++ {108, (3<<18)|0x32ec1, (4<<18)|0x09999, (5<<18)|0x2A9C6}, // 108 (5.540GHz) ++ {112, (3<<18)|0x31ec1, (4<<18)|0x0a666, (5<<18)|0x2A9C6}, // 112 (5.560GHz) ++ {116, (3<<18)|0x33ec3, (4<<18)|0x08ccc, (5<<18)|0x2A9C6}, // 116 (5.580GHz) ++ {120, (3<<18)|0x301c0, (4<<18)|0x08000, (5<<18)|0x2A9C6}, // 120 (5.600GHz) ++ {124, (3<<18)|0x301c2, (4<<18)|0x0b333, (5<<18)|0x2A9C6}, // 124 (5.620GHz) ++ {128, (3<<18)|0x321c1, (4<<18)|0x09999, (5<<18)|0x2A9C6}, // 128 (5.640GHz) ++ {132, (3<<18)|0x311c1, (4<<18)|0x0a666, (5<<18)|0x2A9C6}, // 132 (5.660GHz) ++ {136, (3<<18)|0x331c3, (4<<18)|0x08ccc, (5<<18)|0x2A9C6}, // 136 (5.680GHz) ++ {140, (3<<18)|0x309c0, (4<<18)|0x08000, (5<<18)|0x2A9C6}, // 140 (5.700GHz) ++ ++ {149, (3<<18)|0x329c2, (4<<18)|0x0b333, (5<<18)|0x2A9C6}, // 149 (5.745GHz) ++ {153, (3<<18)|0x319c1, (4<<18)|0x09999, (5<<18)|0x2A9C6}, // 153 (5.765GHz) ++ {157, (3<<18)|0x339c1, (4<<18)|0x0a666, (5<<18)|0x2A9C6}, // 157 (5.785GHz) ++ {161, (3<<18)|0x305c3, (4<<18)|0x08ccc, (5<<18)|0x2A9C6}, // 161 (5.805GHz) ++ ++ // Japan ++ { 184, (3<<18)|0x308c2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 184 (4.920GHz) ++ { 188, (3<<18)|0x328c1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 188 (4.940GHz) ++ { 192, (3<<18)|0x318c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 192 (4.960GHz) ++ { 196, (3<<18)|0x338c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 196 (4.980GHz) ++ { 8, (3<<18)|0x324c1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 8 (5.040GHz) ++ { 12, (3<<18)|0x314c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 12 (5.060GHz) ++ { 16, (3<<18)|0x334c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 16 (5.080GHz) ++ { 34, (3<<18)|0x31cc2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 34 (5.170GHz) ++ { 38, (3<<18)|0x33cc1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 38 (5.190GHz) ++ { 42, (3<<18)|0x302c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 42 (5.210GHz) ++ { 46, (3<<18)|0x322c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 46 (5.230GHz) ++}; ++ ++/***************************************************************************** ++; For MAXIM2825/6/7 Ver. 317 or less ++; Edited by Tiger, Sep-17-2003 for 2.4Ghz channels ++; Updated by Tiger, Sep-22-2003 for 5.0Ghz channels ++; Corrected by Tiger, Sep-23-2003, for 0x03 and 0x04 of 5.0Ghz channels ++ ++0x00 0x00080 ++0x01 0x214c0 ++0x02 0x13802 ++ ++;2.4GHz Channels ++;channe1 01 (2.412GHz); 0x03 0x30143 ;0x04 0x0accc ++;channe1 02 (2.417GHz); 0x03 0x32140 ;0x04 0x09111 ++;channe1 03 (2.422GHz); 0x03 0x32142 ;0x04 0x0bbbb ++;channe1 04 (2.427GHz); 0x03 0x32143 ;0x04 0x0accc ++;channe1 05 (2.432GHz); 0x03 0x31140 ;0x04 0x09111 ++;channe1 06 (2.437GHz); 0x03 0x31142 ;0x04 0x0bbbb ++;channe1 07 (2.442GHz); 0x03 0x31143 ;0x04 0x0accc ++;channe1 08 (2.447GHz); 0x03 0x33140 ;0x04 0x09111 ++;channe1 09 (2.452GHz); 0x03 0x33142 ;0x04 0x0bbbb ++;channe1 10 (2.457GHz); 0x03 0x33143 ;0x04 0x0accc ++;channe1 11 (2.462GHz); 0x03 0x30940 ;0x04 0x09111 ++;channe1 12 (2.467GHz); 0x03 0x30942 ;0x04 0x0bbbb ++;channe1 13 (2.472GHz); 0x03 0x30943 ;0x04 0x0accc ++ ++;5.0Ghz Channels ++;channel 36 (5.180GHz); 0x03 0x33cc0 ;0x04 0x0b333 ++;channel 40 (5.200GHz); 0x03 0x302c0 ;0x04 0x08000 ++;channel 44 (5.220GHz); 0x03 0x302c2 ;0x04 0x0b333 ++;channel 48 (5.240GHz); 0x03 0x322c1 ;0x04 0x09999 ++;channel 52 (5.260GHz); 0x03 0x312c1 ;0x04 0x0a666 ++;channel 56 (5.280GHz); 0x03 0x332c3 ;0x04 0x08ccc ++;channel 60 (5.300GHz); 0x03 0x30ac0 ;0x04 0x08000 ++;channel 64 (5.320GHz); 0x03 0x30ac2 ;0x04 0x08333 ++ ++;2.4GHz band ;0x05 0x28986; ++;5.0GHz band ++0x05 0x2a986 ++ ++0x06 0x18008 ++0x07 0x38400 ++0x08 0x05108 ++0x09 0x27ff8 ++0x0a 0x14000 ++0x0b 0x37f99 ++0x0c 0x0c000 ++*****************************************************************************/ ++u32 maxim_317_rf_data[] = ++{ ++ (0x00<<18)|0x000a2, ++ (0x01<<18)|0x214c0, ++ (0x02<<18)|0x13802, ++ (0x03<<18)|0x30143, ++ (0x04<<18)|0x0accc, ++ (0x05<<18)|0x28986, ++ (0x06<<18)|0x18008, ++ (0x07<<18)|0x38400, ++ (0x08<<18)|0x05108, ++ (0x09<<18)|0x27ff8, ++ (0x0A<<18)|0x14000, ++ (0x0B<<18)|0x37f99, ++ (0x0C<<18)|0x0c000 ++}; ++ ++u32 maxim_317_channel_data_24[][3] = ++{ ++ {(0x03<<18)|0x30143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 01 ++ {(0x03<<18)|0x32140, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 02 ++ {(0x03<<18)|0x32142, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 03 ++ {(0x03<<18)|0x32143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 04 ++ {(0x03<<18)|0x31140, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 05 ++ {(0x03<<18)|0x31142, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 06 ++ {(0x03<<18)|0x31143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 07 ++ {(0x03<<18)|0x33140, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 08 ++ {(0x03<<18)|0x33142, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 09 ++ {(0x03<<18)|0x33143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 10 ++ {(0x03<<18)|0x30940, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 11 ++ {(0x03<<18)|0x30942, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 12 ++ {(0x03<<18)|0x30943, (0x04<<18)|0x0accc, (0x05<<18)|0x28986} // channe1 13 ++}; ++ ++u32 maxim_317_channel_data_50[][3] = ++{ ++ {(0x03<<18)|0x33cc0, (0x04<<18)|0x0b333, (0x05<<18)|0x2a986}, // channel 36 ++ {(0x03<<18)|0x302c0, (0x04<<18)|0x08000, (0x05<<18)|0x2a986}, // channel 40 ++ {(0x03<<18)|0x302c3, (0x04<<18)|0x0accc, (0x05<<18)|0x2a986}, // channel 44 ++ {(0x03<<18)|0x322c1, (0x04<<18)|0x09666, (0x05<<18)|0x2a986}, // channel 48 ++ {(0x03<<18)|0x312c2, (0x04<<18)|0x09999, (0x05<<18)|0x2a986}, // channel 52 ++ {(0x03<<18)|0x332c0, (0x04<<18)|0x0b333, (0x05<<18)|0x2a99e}, // channel 56 ++ {(0x03<<18)|0x30ac0, (0x04<<18)|0x08000, (0x05<<18)|0x2a99e}, // channel 60 ++ {(0x03<<18)|0x30ac3, (0x04<<18)|0x0accc, (0x05<<18)|0x2a99e} // channel 64 ++}; ++ ++u32 maxim_317_power_data_24[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100}; ++u32 maxim_317_power_data_50[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100}; ++ ++/***************************************************************************** ++;;AL2230 MP (Mass Production Version) ++;;RF Registers Setting for Airoha AL2230 silicon after June 1st, 2004 ++;;Updated by Tiger Huang (June 1st, 2004) ++;;20-bit length and LSB first ++ ++;;Ch01 (2412MHz) ;0x00 0x09EFC ;0x01 0x8CCCC; ++;;Ch02 (2417MHz) ;0x00 0x09EFC ;0x01 0x8CCCD; ++;;Ch03 (2422MHz) ;0x00 0x09E7C ;0x01 0x8CCCC; ++;;Ch04 (2427MHz) ;0x00 0x09E7C ;0x01 0x8CCCD; ++;;Ch05 (2432MHz) ;0x00 0x05EFC ;0x01 0x8CCCC; ++;;Ch06 (2437MHz) ;0x00 0x05EFC ;0x01 0x8CCCD; ++;;Ch07 (2442MHz) ;0x00 0x05E7C ;0x01 0x8CCCC; ++;;Ch08 (2447MHz) ;0x00 0x05E7C ;0x01 0x8CCCD; ++;;Ch09 (2452MHz) ;0x00 0x0DEFC ;0x01 0x8CCCC; ++;;Ch10 (2457MHz) ;0x00 0x0DEFC ;0x01 0x8CCCD; ++;;Ch11 (2462MHz) ;0x00 0x0DE7C ;0x01 0x8CCCC; ++;;Ch12 (2467MHz) ;0x00 0x0DE7C ;0x01 0x8CCCD; ++;;Ch13 (2472MHz) ;0x00 0x03EFC ;0x01 0x8CCCC; ++;;Ch14 (2484Mhz) ;0x00 0x03E7C ;0x01 0x86666; ++ ++0x02 0x401D8; RXDCOC BW 100Hz for RXHP low ++;;0x02 0x481DC; RXDCOC BW 30Khz for RXHP low ++ ++0x03 0xCFFF0 ++0x04 0x23800 ++0x05 0xA3B72 ++0x06 0x6DA01 ++0x07 0xE1688 ++0x08 0x11600 ++0x09 0x99E02 ++0x0A 0x5DDB0 ++0x0B 0xD9900 ++0x0C 0x3FFBD ++0x0D 0xB0000 ++0x0F 0xF00A0 ++ ++;RF Calibration for Airoha AL2230 ++;Edit by Ben Chang (01/30/04) ++;Updated by Tiger Huang (03/03/04) ++0x0f 0xf00a0 ; Initial Setting ++0x0f 0xf00b0 ; Activate TX DCC ++0x0f 0xf02a0 ; Activate Phase Calibration ++0x0f 0xf00e0 ; Activate Filter RC Calibration ++0x0f 0xf00a0 ; Restore Initial Setting ++*****************************************************************************/ ++ ++u32 al2230_rf_data[] = ++{ ++ (0x00<<20)|0x09EFC, ++ (0x01<<20)|0x8CCCC, ++ (0x02<<20)|0x40058,// 20060627 Anson 0x401D8, ++ (0x03<<20)|0xCFFF0, ++ (0x04<<20)|0x24100,// 20060627 Anson 0x23800, ++ (0x05<<20)|0xA3B2F,// 20060627 Anson 0xA3B72 ++ (0x06<<20)|0x6DA01, ++ (0x07<<20)|0xE3628,// 20060627 Anson 0xE1688, ++ (0x08<<20)|0x11600, ++ (0x09<<20)|0x9DC02,// 20060627 Anosn 0x97602,//0x99E02, //0x9AE02 ++ (0x0A<<20)|0x5ddb0, // 941206 For QCOM interference 0x588b0,//0x5DDB0, 940601 adj 0x5aa30 for bluetooth ++ (0x0B<<20)|0xD9900, ++ (0x0C<<20)|0x3FFBD, ++ (0x0D<<20)|0xB0000, ++ (0x0F<<20)|0xF01A0 // 20060627 Anson 0xF00A0 ++}; ++ ++u32 al2230s_rf_data[] = ++{ ++ (0x00<<20)|0x09EFC, ++ (0x01<<20)|0x8CCCC, ++ (0x02<<20)|0x40058,// 20060419 0x401D8, ++ (0x03<<20)|0xCFFF0, ++ (0x04<<20)|0x24100,// 20060419 0x23800, ++ (0x05<<20)|0xA3B2F,// 20060419 0xA3B72, ++ (0x06<<20)|0x6DA01, ++ (0x07<<20)|0xE3628,// 20060419 0xE1688, ++ (0x08<<20)|0x11600, ++ (0x09<<20)|0x9DC02,// 20060419 0x97602,//0x99E02, //0x9AE02 ++ (0x0A<<20)|0x5DDB0,// 941206 For QCOM interference 0x588b0,//0x5DDB0, 940601 adj 0x5aa30 for bluetooth ++ (0x0B<<20)|0xD9900, ++ (0x0C<<20)|0x3FFBD, ++ (0x0D<<20)|0xB0000, ++ (0x0F<<20)|0xF01A0 // 20060419 0xF00A0 ++}; ++ ++u32 al2230_channel_data_24[][2] = ++{ ++ {(0x00<<20)|0x09EFC, (0x01<<20)|0x8CCCC}, // channe1 01 ++ {(0x00<<20)|0x09EFC, (0x01<<20)|0x8CCCD}, // channe1 02 ++ {(0x00<<20)|0x09E7C, (0x01<<20)|0x8CCCC}, // channe1 03 ++ {(0x00<<20)|0x09E7C, (0x01<<20)|0x8CCCD}, // channe1 04 ++ {(0x00<<20)|0x05EFC, (0x01<<20)|0x8CCCC}, // channe1 05 ++ {(0x00<<20)|0x05EFC, (0x01<<20)|0x8CCCD}, // channe1 06 ++ {(0x00<<20)|0x05E7C, (0x01<<20)|0x8CCCC}, // channe1 07 ++ {(0x00<<20)|0x05E7C, (0x01<<20)|0x8CCCD}, // channe1 08 ++ {(0x00<<20)|0x0DEFC, (0x01<<20)|0x8CCCC}, // channe1 09 ++ {(0x00<<20)|0x0DEFC, (0x01<<20)|0x8CCCD}, // channe1 10 ++ {(0x00<<20)|0x0DE7C, (0x01<<20)|0x8CCCC}, // channe1 11 ++ {(0x00<<20)|0x0DE7C, (0x01<<20)|0x8CCCD}, // channe1 12 ++ {(0x00<<20)|0x03EFC, (0x01<<20)|0x8CCCC}, // channe1 13 ++ {(0x00<<20)|0x03E7C, (0x01<<20)|0x86666} // channe1 14 ++}; ++ ++// Current setting. u32 airoha_power_data_24[] = {(0x09<<20)|0x90202, (0x09<<20)|0x96602, (0x09<<20)|0x97602}; ++#define AIROHA_TXVGA_LOW_INDEX 31 // Index for 0x90202 ++#define AIROHA_TXVGA_MIDDLE_INDEX 12 // Index for 0x96602 ++#define AIROHA_TXVGA_HIGH_INDEX 8 // Index for 0x97602 1.0.24.0 1.0.28.0 ++/* ++u32 airoha_power_data_24[] = ++{ ++ 0x9FE02, // Max - 0 dB ++ 0x9BE02, // Max - 1 dB ++ 0x9DE02, // Max - 2 dB ++ 0x99E02, // Max - 3 dB ++ 0x9EE02, // Max - 4 dB ++ 0x9AE02, // Max - 5 dB ++ 0x9CE02, // Max - 6 dB ++ 0x98E02, // Max - 7 dB ++ 0x97602, // Max - 8 dB ++ 0x93602, // Max - 9 dB ++ 0x95602, // Max - 10 dB ++ 0x91602, // Max - 11 dB ++ 0x96602, // Max - 12 dB ++ 0x92602, // Max - 13 dB ++ 0x94602, // Max - 14 dB ++ 0x90602, // Max - 15 dB ++ 0x97A02, // Max - 16 dB ++ 0x93A02, // Max - 17 dB ++ 0x95A02, // Max - 18 dB ++ 0x91A02, // Max - 19 dB ++ 0x96A02, // Max - 20 dB ++ 0x92A02, // Max - 21 dB ++ 0x94A02, // Max - 22 dB ++ 0x90A02, // Max - 23 dB ++ 0x97202, // Max - 24 dB ++ 0x93202, // Max - 25 dB ++ 0x95202, // Max - 26 dB ++ 0x91202, // Max - 27 dB ++ 0x96202, // Max - 28 dB ++ 0x92202, // Max - 29 dB ++ 0x94202, // Max - 30 dB ++ 0x90202 // Max - 31 dB ++}; ++*/ ++ ++// 20040927 1.1.69.1000 ybjiang ++// from John ++u32 al2230_txvga_data[][2] = ++{ ++ //value , index ++ {0x090202, 0}, ++ {0x094202, 2}, ++ {0x092202, 4}, ++ {0x096202, 6}, ++ {0x091202, 8}, ++ {0x095202, 10}, ++ {0x093202, 12}, ++ {0x097202, 14}, ++ {0x090A02, 16}, ++ {0x094A02, 18}, ++ {0x092A02, 20}, ++ {0x096A02, 22}, ++ {0x091A02, 24}, ++ {0x095A02, 26}, ++ {0x093A02, 28}, ++ {0x097A02, 30}, ++ {0x090602, 32}, ++ {0x094602, 34}, ++ {0x092602, 36}, ++ {0x096602, 38}, ++ {0x091602, 40}, ++ {0x095602, 42}, ++ {0x093602, 44}, ++ {0x097602, 46}, ++ {0x090E02, 48}, ++ {0x098E02, 49}, ++ {0x094E02, 50}, ++ {0x09CE02, 51}, ++ {0x092E02, 52}, ++ {0x09AE02, 53}, ++ {0x096E02, 54}, ++ {0x09EE02, 55}, ++ {0x091E02, 56}, ++ {0x099E02, 57}, ++ {0x095E02, 58}, ++ {0x09DE02, 59}, ++ {0x093E02, 60}, ++ {0x09BE02, 61}, ++ {0x097E02, 62}, ++ {0x09FE02, 63} ++}; ++ ++//-------------------------------- ++// For Airoha AL7230, 2.4Ghz band ++// Edit by Tiger, (March, 9, 2005) ++// 24bit, MSB first ++ ++//channel independent registers: ++u32 al7230_rf_data_24[] = ++{ ++ (0x00<<24)|0x003790, ++ (0x01<<24)|0x133331, ++ (0x02<<24)|0x841FF2, ++ (0x03<<24)|0x3FDFA3, ++ (0x04<<24)|0x7FD784, ++ (0x05<<24)|0x802B55, ++ (0x06<<24)|0x56AF36, ++ (0x07<<24)|0xCE0207, ++ (0x08<<24)|0x6EBC08, ++ (0x09<<24)|0x221BB9, ++ (0x0A<<24)|0xE0000A, ++ (0x0B<<24)|0x08071B, ++ (0x0C<<24)|0x000A3C, ++ (0x0D<<24)|0xFFFFFD, ++ (0x0E<<24)|0x00000E, ++ (0x0F<<24)|0x1ABA8F ++}; ++ ++u32 al7230_channel_data_24[][2] = ++{ ++ {(0x00<<24)|0x003790, (0x01<<24)|0x133331}, // channe1 01 ++ {(0x00<<24)|0x003790, (0x01<<24)|0x1B3331}, // channe1 02 ++ {(0x00<<24)|0x003790, (0x01<<24)|0x033331}, // channe1 03 ++ {(0x00<<24)|0x003790, (0x01<<24)|0x0B3331}, // channe1 04 ++ {(0x00<<24)|0x0037A0, (0x01<<24)|0x133331}, // channe1 05 ++ {(0x00<<24)|0x0037A0, (0x01<<24)|0x1B3331}, // channe1 06 ++ {(0x00<<24)|0x0037A0, (0x01<<24)|0x033331}, // channe1 07 ++ {(0x00<<24)|0x0037A0, (0x01<<24)|0x0B3331}, // channe1 08 ++ {(0x00<<24)|0x0037B0, (0x01<<24)|0x133331}, // channe1 09 ++ {(0x00<<24)|0x0037B0, (0x01<<24)|0x1B3331}, // channe1 10 ++ {(0x00<<24)|0x0037B0, (0x01<<24)|0x033331}, // channe1 11 ++ {(0x00<<24)|0x0037B0, (0x01<<24)|0x0B3331}, // channe1 12 ++ {(0x00<<24)|0x0037C0, (0x01<<24)|0x133331}, // channe1 13 ++ {(0x00<<24)|0x0037C0, (0x01<<24)|0x066661} // channel 14 ++}; ++ ++//channel independent registers: ++u32 al7230_rf_data_50[] = ++{ ++ (0x00<<24)|0x0FF520, ++ (0x01<<24)|0x000001, ++ (0x02<<24)|0x451FE2, ++ (0x03<<24)|0x5FDFA3, ++ (0x04<<24)|0x6FD784, ++ (0x05<<24)|0x853F55, ++ (0x06<<24)|0x56AF36, ++ (0x07<<24)|0xCE0207, ++ (0x08<<24)|0x6EBC08, ++ (0x09<<24)|0x221BB9, ++ (0x0A<<24)|0xE0600A, ++ (0x0B<<24)|0x08044B, ++ (0x0C<<24)|0x00143C, ++ (0x0D<<24)|0xFFFFFD, ++ (0x0E<<24)|0x00000E, ++ (0x0F<<24)|0x12BACF //5Ghz default state ++}; ++ ++u32 al7230_channel_data_5[][4] = ++{ ++ //channel dependent registers: 0x00, 0x01 and 0x04 ++ //11J =========== ++ {184, (0x00<<24)|0x0FF520, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 184 ++ {188, (0x00<<24)|0x0FF520, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 188 ++ {192, (0x00<<24)|0x0FF530, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 192 ++ {196, (0x00<<24)|0x0FF530, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 196 ++ {8, (0x00<<24)|0x0FF540, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 008 ++ {12, (0x00<<24)|0x0FF540, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 012 ++ {16, (0x00<<24)|0x0FF550, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 016 ++ {34, (0x00<<24)|0x0FF560, (0x01<<24)|0x055551, (0x04<<24)|0x77F784}, // channel 034 ++ {38, (0x00<<24)|0x0FF570, (0x01<<24)|0x100001, (0x04<<24)|0x77F784}, // channel 038 ++ {42, (0x00<<24)|0x0FF570, (0x01<<24)|0x1AAAA1, (0x04<<24)|0x77F784}, // channel 042 ++ {46, (0x00<<24)|0x0FF570, (0x01<<24)|0x055551, (0x04<<24)|0x77F784}, // channel 046 ++ //11 A/H ========= ++ {36, (0x00<<24)|0x0FF560, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 036 ++ {40, (0x00<<24)|0x0FF570, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 040 ++ {44, (0x00<<24)|0x0FF570, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 044 ++ {48, (0x00<<24)|0x0FF570, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 048 ++ {52, (0x00<<24)|0x0FF580, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 052 ++ {56, (0x00<<24)|0x0FF580, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 056 ++ {60, (0x00<<24)|0x0FF580, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 060 ++ {64, (0x00<<24)|0x0FF590, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 064 ++ {100, (0x00<<24)|0x0FF5C0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 100 ++ {104, (0x00<<24)|0x0FF5C0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 104 ++ {108, (0x00<<24)|0x0FF5C0, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 108 ++ {112, (0x00<<24)|0x0FF5D0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 112 ++ {116, (0x00<<24)|0x0FF5D0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 116 ++ {120, (0x00<<24)|0x0FF5D0, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 120 ++ {124, (0x00<<24)|0x0FF5E0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 124 ++ {128, (0x00<<24)|0x0FF5E0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 128 ++ {132, (0x00<<24)|0x0FF5E0, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 132 ++ {136, (0x00<<24)|0x0FF5F0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 136 ++ {140, (0x00<<24)|0x0FF5F0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 140 ++ {149, (0x00<<24)|0x0FF600, (0x01<<24)|0x180001, (0x04<<24)|0x77F784}, // channel 149 ++ {153, (0x00<<24)|0x0FF600, (0x01<<24)|0x02AAA1, (0x04<<24)|0x77F784}, // channel 153 ++ {157, (0x00<<24)|0x0FF600, (0x01<<24)|0x0D5551, (0x04<<24)|0x77F784}, // channel 157 ++ {161, (0x00<<24)|0x0FF610, (0x01<<24)|0x180001, (0x04<<24)|0x77F784}, // channel 161 ++ {165, (0x00<<24)|0x0FF610, (0x01<<24)|0x02AAA1, (0x04<<24)|0x77F784} // channel 165 ++}; ++ ++//; RF Calibration <=== Register 0x0F ++//0x0F 0x1ABA8F; start from 2.4Ghz default state ++//0x0F 0x9ABA8F; TXDC compensation ++//0x0F 0x3ABA8F; RXFIL adjustment ++//0x0F 0x1ABA8F; restore 2.4Ghz default state ++ ++//;TXVGA Mapping Table <=== Register 0x0B ++u32 al7230_txvga_data[][2] = ++{ ++ {0x08040B, 0}, //TXVGA=0; ++ {0x08041B, 1}, //TXVGA=1; ++ {0x08042B, 2}, //TXVGA=2; ++ {0x08043B, 3}, //TXVGA=3; ++ {0x08044B, 4}, //TXVGA=4; ++ {0x08045B, 5}, //TXVGA=5; ++ {0x08046B, 6}, //TXVGA=6; ++ {0x08047B, 7}, //TXVGA=7; ++ {0x08048B, 8}, //TXVGA=8; ++ {0x08049B, 9}, //TXVGA=9; ++ {0x0804AB, 10}, //TXVGA=10; ++ {0x0804BB, 11}, //TXVGA=11; ++ {0x0804CB, 12}, //TXVGA=12; ++ {0x0804DB, 13}, //TXVGA=13; ++ {0x0804EB, 14}, //TXVGA=14; ++ {0x0804FB, 15}, //TXVGA=15; ++ {0x08050B, 16}, //TXVGA=16; ++ {0x08051B, 17}, //TXVGA=17; ++ {0x08052B, 18}, //TXVGA=18; ++ {0x08053B, 19}, //TXVGA=19; ++ {0x08054B, 20}, //TXVGA=20; ++ {0x08055B, 21}, //TXVGA=21; ++ {0x08056B, 22}, //TXVGA=22; ++ {0x08057B, 23}, //TXVGA=23; ++ {0x08058B, 24}, //TXVGA=24; ++ {0x08059B, 25}, //TXVGA=25; ++ {0x0805AB, 26}, //TXVGA=26; ++ {0x0805BB, 27}, //TXVGA=27; ++ {0x0805CB, 28}, //TXVGA=28; ++ {0x0805DB, 29}, //TXVGA=29; ++ {0x0805EB, 30}, //TXVGA=30; ++ {0x0805FB, 31}, //TXVGA=31; ++ {0x08060B, 32}, //TXVGA=32; ++ {0x08061B, 33}, //TXVGA=33; ++ {0x08062B, 34}, //TXVGA=34; ++ {0x08063B, 35}, //TXVGA=35; ++ {0x08064B, 36}, //TXVGA=36; ++ {0x08065B, 37}, //TXVGA=37; ++ {0x08066B, 38}, //TXVGA=38; ++ {0x08067B, 39}, //TXVGA=39; ++ {0x08068B, 40}, //TXVGA=40; ++ {0x08069B, 41}, //TXVGA=41; ++ {0x0806AB, 42}, //TXVGA=42; ++ {0x0806BB, 43}, //TXVGA=43; ++ {0x0806CB, 44}, //TXVGA=44; ++ {0x0806DB, 45}, //TXVGA=45; ++ {0x0806EB, 46}, //TXVGA=46; ++ {0x0806FB, 47}, //TXVGA=47; ++ {0x08070B, 48}, //TXVGA=48; ++ {0x08071B, 49}, //TXVGA=49; ++ {0x08072B, 50}, //TXVGA=50; ++ {0x08073B, 51}, //TXVGA=51; ++ {0x08074B, 52}, //TXVGA=52; ++ {0x08075B, 53}, //TXVGA=53; ++ {0x08076B, 54}, //TXVGA=54; ++ {0x08077B, 55}, //TXVGA=55; ++ {0x08078B, 56}, //TXVGA=56; ++ {0x08079B, 57}, //TXVGA=57; ++ {0x0807AB, 58}, //TXVGA=58; ++ {0x0807BB, 59}, //TXVGA=59; ++ {0x0807CB, 60}, //TXVGA=60; ++ {0x0807DB, 61}, //TXVGA=61; ++ {0x0807EB, 62}, //TXVGA=62; ++ {0x0807FB, 63}, //TXVGA=63; ++}; ++//-------------------------------- ++ ++ ++//; W89RF242 RFIC SPI programming initial data ++//; Winbond WLAN 11g RFIC BB-SPI register -- version FA5976A rev 1.3b ++//; Update Date: Ocotber 3, 2005 by PP10 Hsiang-Te Ho ++//; ++//; Version 1.3b revision items: (Oct. 1, 2005 by HTHo) for FA5976A ++u32 w89rf242_rf_data[] = ++{ ++ (0x00<<24)|0xF86100, // 20060721 0xF86100, //; 3E184; MODA (0x00) -- Normal mode ; calibration off ++ (0x01<<24)|0xEFFFC2, //; 3BFFF; MODB (0x01) -- turn off RSSI, and other circuits are turned on ++ (0x02<<24)|0x102504, //; 04094; FSET (0x02) -- default 20MHz crystal ; Icmp=1.5mA ++ (0x03<<24)|0x026286, //; 0098A; FCHN (0x03) -- default CH7, 2442MHz ++ (0x04<<24)|0x000208, // 20060612.1.a 0x0002C8, // 20050818 // 20050816 0x000388 ++ //; 02008; FCAL (0x04) -- XTAL Freq Trim=001000 (socket board#1); FA5976AYG_v1.3C ++ (0x05<<24)|0x24C60A, // 20060612.1.a 0x24C58A, // 941003 0x24C48A, // 20050818.2 0x24848A, // 20050818 // 20050816 0x24C48A ++ //; 09316; GANA (0x05) -- TX VGA default (TXVGA=0x18(12)) & TXGPK=110 ; FA5976A_1.3D ++ (0x06<<24)|0x3432CC, // 941003 0x26C34C, // 20050818 0x06B40C ++ //; 0D0CB; GANB (0x06) -- RXDC(DC offset) on; LNA=11; RXVGA=001011(11) ; RXFLSW=11(010001); RXGPK=00; RXGCF=00; -50dBm input ++ (0x07<<24)|0x0C68CE, // 20050818.2 0x0C66CE, // 20050818 // 20050816 0x0C68CE ++ //; 031A3; FILT (0x07) -- TX/RX filter with auto-tuning; TFLBW=011; RFLBW=100 ++ (0x08<<24)|0x100010, //; 04000; TCAL (0x08) -- //for LO ++ (0x09<<24)|0x004012, // 20060612.1.a 0x6E4012, // 0x004012, ++ //; 1B900; RCALA (0x09) -- FASTS=11; HPDE=01 (100nsec); SEHP=1 (select B0 pin=RXHP); RXHP=1 (Turn on RXHP function)(FA5976A_1.3C) ++ (0x0A<<24)|0x704014, //; 1C100; RCALB (0x0A) ++ (0x0B<<24)|0x18BDD6, // 941003 0x1805D6, // 20050818.2 0x1801D6, // 20050818 // 20050816 0x1805D6 ++ //; 062F7; IQCAL (0x0B) -- Turn on LO phase tuner=0111 & RX-LO phase = 0111; FA5976A_1.3B (2005/09/29) ++ (0x0C<<24)|0x575558, // 20050818.2 0x555558, // 20050818 // 20050816 0x575558 ++ //; 15D55 ; IBSA (0x0C) -- IFPre =11 ; TC5376A_v1.3A for corner ++ (0x0D<<24)|0x55545A, // 20060612.1.a 0x55555A, ++ //; 15555 ; IBSB (0x0D) ++ (0x0E<<24)|0x5557DC, // 20060612.1.a 0x55555C, // 941003 0x5557DC, ++ //; 1555F ; IBSC (0x0E) -- IRLNA & IRLNB (PTAT & Const current)=01/01; FA5976B_1.3F (2005/11/25) ++ (0x10<<24)|0x000C20, // 941003 0x000020, // 20050818 ++ //; 00030 ; TMODA (0x10) -- LNA_gain_step=0011 ; LNA=15/16dB ++ (0x11<<24)|0x0C0022, // 941003 0x030022 // 20050818.2 0x030022 // 20050818 // 20050816 0x0C0022 ++ //; 03000 ; TMODB (0x11) -- Turn ON RX-Q path Test Switch; To improve IQ path group delay (FA5976A_1.3C) ++ (0x12<<24)|0x000024 // 20060612.1.a 0x001824 // 941003 add ++ //; TMODC (0x12) -- Turn OFF Tempearure sensor ++}; ++ ++u32 w89rf242_channel_data_24[][2] = ++{ ++ {(0x03<<24)|0x025B06, (0x04<<24)|0x080408}, // channe1 01 ++ {(0x03<<24)|0x025C46, (0x04<<24)|0x080408}, // channe1 02 ++ {(0x03<<24)|0x025D86, (0x04<<24)|0x080408}, // channe1 03 ++ {(0x03<<24)|0x025EC6, (0x04<<24)|0x080408}, // channe1 04 ++ {(0x03<<24)|0x026006, (0x04<<24)|0x080408}, // channe1 05 ++ {(0x03<<24)|0x026146, (0x04<<24)|0x080408}, // channe1 06 ++ {(0x03<<24)|0x026286, (0x04<<24)|0x080408}, // channe1 07 ++ {(0x03<<24)|0x0263C6, (0x04<<24)|0x080408}, // channe1 08 ++ {(0x03<<24)|0x026506, (0x04<<24)|0x080408}, // channe1 09 ++ {(0x03<<24)|0x026646, (0x04<<24)|0x080408}, // channe1 10 ++ {(0x03<<24)|0x026786, (0x04<<24)|0x080408}, // channe1 11 ++ {(0x03<<24)|0x0268C6, (0x04<<24)|0x080408}, // channe1 12 ++ {(0x03<<24)|0x026A06, (0x04<<24)|0x080408}, // channe1 13 ++ {(0x03<<24)|0x026D06, (0x04<<24)|0x080408} // channe1 14 ++}; ++ ++u32 w89rf242_power_data_24[] = {(0x05<<24)|0x24C48A, (0x05<<24)|0x24C48A, (0x05<<24)|0x24C48A}; ++ ++// 20060315.6 Enlarge for new scale ++// 20060316.6 20060619.2.a add mapping array ++u32 w89rf242_txvga_old_mapping[][2] = ++{ ++ {0, 0} , // New <-> Old ++ {1, 1} , ++ {2, 2} , ++ {3, 3} , ++ {4, 4} , ++ {6, 5} , ++ {8, 6 }, ++ {10, 7 }, ++ {12, 8 }, ++ {14, 9 }, ++ {16, 10}, ++ {18, 11}, ++ {20, 12}, ++ {22, 13}, ++ {24, 14}, ++ {26, 15}, ++ {28, 16}, ++ {30, 17}, ++ {32, 18}, ++ {34, 19}, ++ ++ ++}; ++ ++// 20060619.3 modify from Bruce's mail ++u32 w89rf242_txvga_data[][5] = ++{ ++ //low gain mode ++ { (0x05<<24)|0x24C00A, 0, 0x00292315, 0x0800FEFF, 0x52523131 },// ; min gain ++ { (0x05<<24)|0x24C80A, 1, 0x00292315, 0x0800FEFF, 0x52523131 }, ++ { (0x05<<24)|0x24C04A, 2, 0x00292315, 0x0800FEFF, 0x52523131 },// (default) +14dBm (ANT) ++ { (0x05<<24)|0x24C84A, 3, 0x00292315, 0x0800FEFF, 0x52523131 }, ++ ++ //TXVGA=0x10 ++ { (0x05<<24)|0x24C40A, 4, 0x00292315, 0x0800FEFF, 0x60603838 }, ++ { (0x05<<24)|0x24C40A, 5, 0x00262114, 0x0700FEFF, 0x65653B3B }, ++ ++ //TXVGA=0x11 ++ { (0x05<<24)|0x24C44A, 6, 0x00241F13, 0x0700FFFF, 0x58583333 }, ++ { (0x05<<24)|0x24C44A, 7, 0x00292315, 0x0800FEFF, 0x5E5E3737 }, ++ ++ //TXVGA=0x12 ++ { (0x05<<24)|0x24C48A, 8, 0x00262114, 0x0700FEFF, 0x53533030 }, ++ { (0x05<<24)|0x24C48A, 9, 0x00241F13, 0x0700FFFF, 0x59593434 }, ++ ++ //TXVGA=0x13 ++ { (0x05<<24)|0x24C4CA, 10, 0x00292315, 0x0800FEFF, 0x52523030 }, ++ { (0x05<<24)|0x24C4CA, 11, 0x00262114, 0x0700FEFF, 0x56563232 }, ++ ++ //TXVGA=0x14 ++ { (0x05<<24)|0x24C50A, 12, 0x00292315, 0x0800FEFF, 0x54543131 }, ++ { (0x05<<24)|0x24C50A, 13, 0x00262114, 0x0700FEFF, 0x58583434 }, ++ ++ //TXVGA=0x15 ++ { (0x05<<24)|0x24C54A, 14, 0x00292315, 0x0800FEFF, 0x54543131 }, ++ { (0x05<<24)|0x24C54A, 15, 0x00262114, 0x0700FEFF, 0x59593434 }, ++ ++ //TXVGA=0x16 ++ { (0x05<<24)|0x24C58A, 16, 0x00292315, 0x0800FEFF, 0x55553131 }, ++ { (0x05<<24)|0x24C58A, 17, 0x00292315, 0x0800FEFF, 0x5B5B3535 }, ++ ++ //TXVGA=0x17 ++ { (0x05<<24)|0x24C5CA, 18, 0x00262114, 0x0700FEFF, 0x51512F2F }, ++ { (0x05<<24)|0x24C5CA, 19, 0x00241F13, 0x0700FFFF, 0x55553131 }, ++ ++ //TXVGA=0x18 ++ { (0x05<<24)|0x24C60A, 20, 0x00292315, 0x0800FEFF, 0x4F4F2E2E }, ++ { (0x05<<24)|0x24C60A, 21, 0x00262114, 0x0700FEFF, 0x53533030 }, ++ ++ //TXVGA=0x19 ++ { (0x05<<24)|0x24C64A, 22, 0x00292315, 0x0800FEFF, 0x4E4E2D2D }, ++ { (0x05<<24)|0x24C64A, 23, 0x00262114, 0x0700FEFF, 0x53533030 }, ++ ++ //TXVGA=0x1A ++ { (0x05<<24)|0x24C68A, 24, 0x00292315, 0x0800FEFF, 0x50502E2E }, ++ { (0x05<<24)|0x24C68A, 25, 0x00262114, 0x0700FEFF, 0x55553131 }, ++ ++ //TXVGA=0x1B ++ { (0x05<<24)|0x24C6CA, 26, 0x00262114, 0x0700FEFF, 0x53533030 }, ++ { (0x05<<24)|0x24C6CA, 27, 0x00292315, 0x0800FEFF, 0x5A5A3434 }, ++ ++ //TXVGA=0x1C ++ { (0x05<<24)|0x24C70A, 28, 0x00292315, 0x0800FEFF, 0x55553131 }, ++ { (0x05<<24)|0x24C70A, 29, 0x00292315, 0x0800FEFF, 0x5D5D3636 }, ++ ++ //TXVGA=0x1D ++ { (0x05<<24)|0x24C74A, 30, 0x00292315, 0x0800FEFF, 0x5F5F3737 }, ++ { (0x05<<24)|0x24C74A, 31, 0x00262114, 0x0700FEFF, 0x65653B3B }, ++ ++ //TXVGA=0x1E ++ { (0x05<<24)|0x24C78A, 32, 0x00292315, 0x0800FEFF, 0x66663B3B }, ++ { (0x05<<24)|0x24C78A, 33, 0x00262114, 0x0700FEFF, 0x70704141 }, ++ ++ //TXVGA=0x1F ++ { (0x05<<24)|0x24C7CA, 34, 0x00292315, 0x0800FEFF, 0x72724242 } ++}; ++ ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++/////////////////////////////////////////////////////////////////////////////////////////////////// ++ ++ ++ ++//============================================================================================================= ++// Uxx_ReadEthernetAddress -- ++// ++// Routine Description: ++// Reads in the Ethernet address from the IC. ++// ++// Arguments: ++// pHwData - The pHwData structure ++// ++// Return Value: ++// ++// The address is stored in EthernetIDAddr. ++//============================================================================================================= ++void ++Uxx_ReadEthernetAddress( phw_data_t pHwData ) ++{ ++ u32 ltmp; ++ ++ // Reading Ethernet address from EEPROM and set into hardware due to MAC address maybe change. ++ // Only unplug and plug again can make hardware read EEPROM again. 20060727 ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08000000 ); // Start EEPROM access + Read + address(0x0d) ++ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp ); ++ *(PUSHORT)pHwData->PermanentMacAddress = cpu_to_le16((u16)ltmp); //20060926 anson's endian ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08010000 ); // Start EEPROM access + Read + address(0x0d) ++ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp ); ++ *(PUSHORT)(pHwData->PermanentMacAddress + 2) = cpu_to_le16((u16)ltmp); //20060926 anson's endian ++ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08020000 ); // Start EEPROM access + Read + address(0x0d) ++ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp ); ++ *(PUSHORT)(pHwData->PermanentMacAddress + 4) = cpu_to_le16((u16)ltmp); //20060926 anson's endian ++ *(PUSHORT)(pHwData->PermanentMacAddress + 6) = 0; ++ Wb35Reg_WriteSync( pHwData, 0x03e8, cpu_to_le32(*(PULONG)pHwData->PermanentMacAddress) ); //20060926 anson's endian ++ Wb35Reg_WriteSync( pHwData, 0x03ec, cpu_to_le32(*(PULONG)(pHwData->PermanentMacAddress+4)) ); //20060926 anson's endian ++} ++ ++ ++//=============================================================================================================== ++// CardGetMulticastBit -- ++// Description: ++// For a given multicast address, returns the byte and bit in the card multicast registers that it hashes to. ++// Calls CardComputeCrc() to determine the CRC value. ++// Arguments: ++// Address - the address ++// Byte - the byte that it hashes to ++// Value - will have a 1 in the relevant bit ++// Return Value: ++// None. ++//============================================================================================================== ++void CardGetMulticastBit( u8 Address[ETH_LENGTH_OF_ADDRESS], ++ u8 *Byte, u8 *Value ) ++{ ++ u32 Crc; ++ u32 BitNumber; ++ ++ // First compute the CRC. ++ Crc = CardComputeCrc(Address, ETH_LENGTH_OF_ADDRESS); ++ ++ // The computed CRC is bit0~31 from left to right ++ //At first we should do right shift 25bits, and read 7bits by using '&', 2^7=128 ++ BitNumber = (u32) ((Crc >> 26) & 0x3f); ++ ++ *Byte = (u8) (BitNumber >> 3);// 900514 original (BitNumber / 8) ++ *Value = (u8) ((u8)1 << (BitNumber % 8)); ++} ++ ++void Uxx_power_on_procedure( phw_data_t pHwData ) ++{ ++ u32 ltmp, loop; ++ ++ if( pHwData->phy_type <= RF_MAXIM_V1 ) ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xffffff38 ); ++ else ++ { ++ Wb35Reg_WriteSync( pHwData, 0x03f4, 0xFF5807FF );// 20060721 For NEW IC 0xFF5807FF ++ ++ // 20060511.1 Fix the following 4 steps for Rx of RF 2230 initial fail ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0x80 );// regulator on only ++ OS_SLEEP(10000); // Modify 20051221.1.b ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xb8 );// REG_ON RF_RSTN on, and ++ OS_SLEEP(10000); // Modify 20051221.1.b ++ ++ ltmp = 0x4968; ++ if( (pHwData->phy_type == RF_WB_242) || ++ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add ++ ltmp = 0x4468; ++ Wb35Reg_WriteSync( pHwData, 0x03d0, ltmp ); ++ ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xa0 );// PLL_PD REF_PD set to 0 ++ ++ OS_SLEEP(20000); // Modify 20051221.1.b ++ Wb35Reg_ReadSync( pHwData, 0x03d0, <mp ); ++ loop = 500; // Wait for 5 second 20061101 ++ while( !(ltmp & 0x20) && loop-- ) ++ { ++ OS_SLEEP(10000); // Modify 20051221.1.b ++ if( !Wb35Reg_ReadSync( pHwData, 0x03d0, <mp ) ) ++ break; ++ } ++ ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xe0 );// MLK_EN ++ } ++ ++ Wb35Reg_WriteSync( pHwData, 0x03b0, 1 );// Reset hardware first ++ OS_SLEEP(10000); // Add this 20051221.1.b ++ ++ // Set burst write delay ++ Wb35Reg_WriteSync( pHwData, 0x03f8, 0x7ff ); ++} ++ ++void Set_ChanIndep_RfData_al7230_24( phw_data_t pHwData, u32 *pltmp ,char number) ++{ ++ u8 i; ++ ++ for( i=0; iphy_para[i] = al7230_rf_data_24[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_rf_data_24[i]&0xffffff); ++ } ++} ++ ++void Set_ChanIndep_RfData_al7230_50( phw_data_t pHwData, u32 *pltmp, char number) ++{ ++ u8 i; ++ ++ for( i=0; iphy_para[i] = al7230_rf_data_50[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_rf_data_50[i]&0xffffff); ++ } ++} ++ ++ ++//============================================================================================================= ++// RFSynthesizer_initial -- ++//============================================================================================================= ++void ++RFSynthesizer_initial(phw_data_t pHwData) ++{ ++ u32 altmp[32]; ++ PULONG pltmp = altmp; ++ u32 ltmp; ++ u8 number=0x00; // The number of register vale ++ u8 i; ++ ++ // ++ // bit[31] SPI Enable. ++ // 1=perform synthesizer program operation. This bit will ++ // cleared automatically after the operation is completed. ++ // bit[30] SPI R/W Control ++ // 0=write, 1=read ++ // bit[29:24] SPI Data Format Length ++ // bit[17:4 ] RF Data bits. ++ // bit[3 :0 ] RF address. ++ switch( pHwData->phy_type ) ++ { ++ case RF_MAXIM_2825: ++ case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331) ++ number = sizeof(max2825_rf_data)/sizeof(max2825_rf_data[0]); ++ for( i=0; iphy_para[i] = max2825_rf_data[i];// Backup Rf parameter ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2825_rf_data[i], 18); ++ } ++ break; ++ ++ case RF_MAXIM_2827: ++ number = sizeof(max2827_rf_data)/sizeof(max2827_rf_data[0]); ++ for( i=0; iphy_para[i] = max2827_rf_data[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_rf_data[i], 18); ++ } ++ break; ++ ++ case RF_MAXIM_2828: ++ number = sizeof(max2828_rf_data)/sizeof(max2828_rf_data[0]); ++ for( i=0; iphy_para[i] = max2828_rf_data[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_rf_data[i], 18); ++ } ++ break; ++ ++ case RF_MAXIM_2829: ++ number = sizeof(max2829_rf_data)/sizeof(max2829_rf_data[0]); ++ for( i=0; iphy_para[i] = max2829_rf_data[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2829_rf_data[i], 18); ++ } ++ break; ++ ++ case RF_AIROHA_2230: ++ number = sizeof(al2230_rf_data)/sizeof(al2230_rf_data[0]); ++ for( i=0; iphy_para[i] = al2230_rf_data[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_rf_data[i], 20); ++ } ++ break; ++ ++ case RF_AIROHA_2230S: ++ number = sizeof(al2230s_rf_data)/sizeof(al2230s_rf_data[0]); ++ for( i=0; iphy_para[i] = al2230s_rf_data[i]; ++ pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230s_rf_data[i], 20); ++ } ++ break; ++ ++ case RF_AIROHA_7230: ++ ++ //Start to fill RF parameters, PLL_ON should be pulled low. ++ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000000 ); ++#ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("* PLL_ON low\n")); ++#endif ++ ++ number = sizeof(al7230_rf_data_24)/sizeof(al7230_rf_data_24[0]); ++ Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number); ++ break; ++ ++ case RF_WB_242: ++ case RF_WB_242_1: // 20060619.5 Add ++ number = sizeof(w89rf242_rf_data)/sizeof(w89rf242_rf_data[0]); ++ for( i=0; iVCO_trim<<4; ++ } ++ ++ pHwData->phy_para[i] = ltmp; ++ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( ltmp, 24); ++ } ++ break; ++ } ++ ++ pHwData->phy_number = number; ++ ++ // The 16 is the maximum capability of hardware. Here use 12 ++ if( number > 12 ) { ++ //Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 12, NO_INCREMENT ); ++ for( i=0; i<12; i++ ) // For Al2230 ++ Wb35Reg_WriteSync( pHwData, 0x0864, pltmp[i] ); ++ ++ pltmp += 12; ++ number -= 12; ++ } ++ ++ // Write to register. number must less and equal than 16 ++ for( i=0; iCalOneTime ) ++ return; ++ pHwData->CalOneTime = 1; ++ ++ switch( pHwData->phy_type ) ++ { ++ case RF_AIROHA_2230: ++ ++ // 20060511.1 --- Modifying the follow step for Rx issue----------------- ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x07<<20)|0xE168E, 20); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(10000); ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_rf_data[7], 20); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(10000); ++ ++ case RF_AIROHA_2230S: // 20060420 Add this ++ ++ // 20060511.1 --- Modifying the follow step for Rx issue----------------- ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0x80 );// regulator on only ++ OS_SLEEP(10000); // Modify 20051221.1.b ++ ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xa0 );// PLL_PD REF_PD set to 0 ++ OS_SLEEP(10000); // Modify 20051221.1.b ++ ++ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xe0 );// MLK_EN ++ Wb35Reg_WriteSync( pHwData, 0x03b0, 1 );// Reset hardware first ++ OS_SLEEP(10000); // Add this 20051221.1.b ++ //------------------------------------------------------------------------ ++ ++ // The follow code doesn't use the burst-write mode ++ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01A0); //Raise Initial Setting ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01A0, 20); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ ltmp = pHwData->Wb35Reg.BB5C & 0xfffff000; ++ Wb35Reg_WriteSync( pHwData, 0x105c, ltmp ); ++ pHwData->Wb35Reg.BB50 |= 0x13;//(MASK_IQCAL_MODE|MASK_CALIB_START);//20060315.1 modify ++ Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50); ++ OS_SLEEP(5000); ++ ++ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01B0); //Activate Filter Cal. ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01B0, 20); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(5000); ++ ++ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01e0); //Activate TX DCC ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01E0, 20); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(5000); ++ ++ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01A0); //Resotre Initial Setting ++ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01A0, 20); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++// //Force TXI(Q)P(N) to normal control ++ Wb35Reg_WriteSync( pHwData, 0x105c, pHwData->Wb35Reg.BB5C ); ++ pHwData->Wb35Reg.BB50 &= ~0x13;//(MASK_IQCAL_MODE|MASK_CALIB_START); ++ Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50); ++ break; ++ ++ case RF_AIROHA_7230: ++ ++ //RF parameters have filled completely, PLL_ON should be ++ //pulled high ++ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000080 ); ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("* PLL_ON high\n")); ++ #endif ++ ++ //2.4GHz ++ //ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x1ABA8F; ++ //Wb35Reg_WriteSync pHwData, 0x0864, ltmp ); ++ //OS_SLEEP(1000); // Sleep 1 ms ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F; ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(5000); ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x3ABA8F; ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(5000); ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x1ABA8F; ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(5000); ++ ++ //5GHz ++ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000000 ); ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("* PLL_ON low\n")); ++ #endif ++ ++ number = sizeof(al7230_rf_data_50)/sizeof(al7230_rf_data_50[0]); ++ Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number); ++ // Write to register. number must less and equal than 16 ++ for( i=0; iWb35Reg.BB5C & 0xfffff000; ++ Wb35Reg_WriteSync( pHwData, 0x105c, ltmp ); ++ Wb35Reg_WriteSync( pHwData, 0x1058, 0 ); ++ pHwData->Wb35Reg.BB50 |= 0x3;//(MASK_IQCAL_MODE|MASK_CALIB_START);//20060630 ++ Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50); ++ ++ //----- Calibration (1). VCO frequency calibration ++ //Calibration (1a.0). Synthesizer reset (HTHo corrected 2005/05/10) ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x0F<<24) | 0x00101E, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP( 5000 ); // Sleep 5ms ++ //Calibration (1a). VCO frequency calibration mode ; waiting 2msec VCO calibration time ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFE69c0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP( 2000 ); // Sleep 2ms ++ ++ //----- Calibration (2). TX baseband Gm-C filter auto-tuning ++ //Calibration (2a). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xF8EBC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (2b.0). TX filter auto-tuning BW: TFLBW=101 (TC5376A default) ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x07<<24) | 0x0C68CE, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (2b). send TX reset signal (HTHo corrected May 10, 2005) ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x0F<<24) | 0x00201E, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (2c). turn-on TX Gm-C filter auto-tuning ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFCEBC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP( 150 ); // Sleep 150 us ++ //turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xF8EBC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //----- Calibration (3). RX baseband Gm-C filter auto-tuning ++ //Calibration (3a). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (3b.0). RX filter auto-tuning BW: RFLBW=100 (TC5376A+corner default; July 26, 2005) ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x07<<24) | 0x0C68CE, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (3b). send RX reset signal (HTHo corrected May 10, 2005) ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x0F<<24) | 0x00401E, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (3c). turn-on RX Gm-C filter auto-tuning ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFEEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP( 150 ); // Sleep 150 us ++ //Calibration (3e). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //----- Calibration (4). TX LO leakage calibration ++ //Calibration (4a). TX LO leakage calibration ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFD6BC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP( 150 ); // Sleep 150 us ++ ++ //----- Calibration (5). RX DC offset calibration ++ //Calibration (5a). turn off ENCAL signal and set to RX SW DC caliration mode ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (5b). turn off AGC servo-loop & RSSI ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x01<<24) | 0xEBFFC2, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //; for LNA=11 -------- ++ //Calibration (5c-h). RX DC offset current bias ON; & LNA=11; RXVGA=111111 ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x343FCC, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(2000); // Sleep 2ms ++ //Calibration (5f). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //; for LNA=10 -------- ++ //Calibration (5c-m). RX DC offset current bias ON; & LNA=10; RXVGA=111111 ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x342FCC, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(2000); // Sleep 2ms ++ //Calibration (5f). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //; for LNA=01 -------- ++ //Calibration (5c-m). RX DC offset current bias ON; & LNA=01; RXVGA=111111 ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x341FCC, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(2000); // Sleep 2ms ++ //Calibration (5f). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //; for LNA=00 -------- ++ //Calibration (5c-l). RX DC offset current bias ON; & LNA=00; RXVGA=111111 ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x340FCC, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(2000); // Sleep 2ms ++ //Calibration (5f). turn off ENCAL signal ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ //Calibration (5g). turn on AGC servo-loop ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x01<<24) | 0xEFFFC2, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ ++ //; ----- Calibration (7). Switch RF chip to normal mode ++ //0x00 0xF86100 ; 3E184 ; Switch RF chip to normal mode ++// OS_SLEEP(10000); // @@ 20060721 ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xF86100, 24); ++ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp ); ++ OS_SLEEP(5000); // Sleep 5 ms ++ ++// //write back ++// Wb35Reg_WriteSync( pHwData, 0x105c, pHwData->Wb35Reg.BB5C ); ++// pHwData->Wb35Reg.BB50 &= ~0x13;//(MASK_IQCAL_MODE|MASK_CALIB_START); // 20060315.1 fix ++// Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50); ++// OS_SLEEP(1000); // Sleep 1 ms ++ break; ++ } ++} ++ ++void BBProcessor_AL7230_2400( phw_data_t pHwData) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 pltmp[12]; ++ ++ pltmp[0] = 0x16A8337A; // 0x16a5215f; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9AFF9AA6; // 0x9aff9ca6; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55D00A04; // 0x55d00a04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xFFF72031; // 0xFfFf2138; // 0x100c AGC_Ctrl4 ++ pWb35Reg->BB0C = 0xFFF72031; ++ pltmp[4] = 0x0FacDCC5; // 0x1010 AGC_Ctrl5 // 20050927 0x0FacDCB7 ++ pltmp[5] = 0x00CAA333; // 0x00eaa333; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0xF2211111; // 0x11111111; // 0x1018 AGC_Ctrl7 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x06443440; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0xA8002A79; // 0xa9002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0x40000528; // 20050927 0x40000228 ++ pltmp[11] = 0x232D7F30; // 0x23457f30;// 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2C = 0x232D7F30; ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002c54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002c54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = 0x00332C1B; // 0x00453B24; // 0x1048 11b TX RC filter ++ pltmp[7] = 0x0A00FEFF; // 0x0E00FEFF; // 0x104c 11b TX RC filter ++ pltmp[8] = 0x2B106208; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x2B106208; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x52524242; // 0x64645252; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x52524242; ++ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++} ++ ++void BBProcessor_AL7230_5000( phw_data_t pHwData) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 pltmp[12]; ++ ++ pltmp[0] = 0x16AA6678; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9AFFA0B2; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55D00A04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xEFFF233E; // 0x100c AGC_Ctrl4 ++ pWb35Reg->BB0C = 0xEFFF233E; ++ pltmp[4] = 0x0FacDCC5; // 0x1010 AGC_Ctrl5 // 20050927 0x0FacDCB7 ++ pltmp[5] = 0x00CAA333; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0xF2432111; // 0x1018 AGC_Ctrl7 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x05C43440; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0x40000528; // 20050927 0x40000228 ++ pltmp[11] = 0x232FDF30;// 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2C = 0x232FDF30; ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x80002C7C; // 0x1030 B_ACQ_Ctrl ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = 0x00332C1B; // 0x1048 11b TX RC filter ++ pltmp[7] = 0x0A00FEFF; // 0x104c 11b TX RC filter ++ pltmp[8] = 0x2B107208; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x2B107208; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x52524242; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x52524242; ++ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++} ++ ++//============================================================================================================= ++// BBProcessorPowerupInit -- ++// ++// Description: ++// Initialize the Baseband processor. ++// ++// Arguments: ++// pHwData - Handle of the USB Device. ++// ++// Return values: ++// None. ++//============================================================================================================= ++void ++BBProcessor_initial( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 i, pltmp[12]; ++ ++ switch( pHwData->phy_type ) ++ { ++ case RF_MAXIM_V1: // Initializng the Winbond 2nd BB(with Phy board (v1) + Maxim 331) ++ ++ pltmp[0] = 0x16F47E77; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9AFFAEA4; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55D00A04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xEFFF1A34; // 0x100c AGC_Ctrl4 ++ pWb35Reg->BB0C = 0xEFFF1A34; ++ pltmp[4] = 0x0FABE0B7; // 0x1010 AGC_Ctrl5 ++ pltmp[5] = 0x00CAA332; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0xF6632111; // 0x1018 AGC_Ctrl7 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04CC3640; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = (pHwData->phy_type==3) ? 0x40000a28 : 0x40000228; // 0x1028 MAXIM_331(b31=0) + WBRF_V1(b11=1) : MAXIM_331(b31=0) + WBRF_V2(b11=0) ++ pltmp[11] = 0x232FDF30; // 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2C = 0x232FDF30; //Modify for 33's 1.0.95.xxx version, antenna 1 ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B6C8769; // 0x1038 B_TXRX_Ctrl ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = 0x00453B24; // 0x1048 11b TX RC filter ++ pltmp[7] = 0x0E00FEFF; // 0x104c 11b TX RC filter ++ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106208; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x64646464; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x64646464; ++ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ ++ //------------------------------------------------------------------ ++ //[20040722 WK] ++ //Only for baseband version 2 ++// case RF_MAXIM_317: ++ case RF_MAXIM_2825: ++ case RF_MAXIM_2827: ++ case RF_MAXIM_2828: ++ ++ pltmp[0] = 0x16b47e77; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9affaea4; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xefff1a34; // 0x100c AGC_Ctrl4 ++ pWb35Reg->BB0C = 0xefff1a34; ++ pltmp[4] = 0x0fabe0b7; // 0x1010 AGC_Ctrl5 ++ pltmp[5] = 0x00caa332; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0xf6632111; // 0x1018 AGC_Ctrl7 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04CC3640; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0x40000528; // 0x40000128; Modify for 33's 1.0.95 ++ pltmp[11] = 0x232fdf30; // 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2C = 0x232fdf30; //Modify for 33's 1.0.95.xxx version, antenna 1 ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B6C8769; // 0x1038 B_TXRX_Ctrl ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = 0x00453B24; // 0x1048 11b TX RC filter ++ pltmp[7] = 0x0D00FDFF; // 0x104c 11b TX RC filter ++ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106208; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x64646464; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x64646464; ++ pltmp[11] = 0xAA28C000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ ++ case RF_MAXIM_2829: ++ ++ pltmp[0] = 0x16b47e77; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9affaea4; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xf4ff1632; // 0xefff1a34; // 0x100c AGC_Ctrl4 Modify for 33's 1.0.95 ++ pWb35Reg->BB0C = 0xf4ff1632; // 0xefff1a34; Modify for 33's 1.0.95 ++ pltmp[4] = 0x0fabe0b7; // 0x1010 AGC_Ctrl5 ++ pltmp[5] = 0x00caa332; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0xf8632112; // 0xf6632111; // 0x1018 AGC_Ctrl7 Modify for 33's 1.0.95 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04CC3640; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0x40000528; // 0x40000128; modify for 33's 1.0.95 ++ pltmp[11] = 0x232fdf30; // 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2C = 0x232fdf30; //Modify for 33's 1.0.95.xxx version, antenna 1 ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5b2c8769; // 0x5B6C8769; // 0x1038 B_TXRX_Ctrl Modify for 33's 1.0.95 ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = 0x002c2617; // 0x00453B24; // 0x1048 11b TX RC filter Modify for 33's 1.0.95 ++ pltmp[7] = 0x0800feff; // 0x0D00FDFF; // 0x104c 11b TX RC filter Modify for 33's 1.0.95 ++ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106208; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x64644a4a; // 0x64646464; // 0x1058 IQ_Alpha Modify for 33's 1.0.95 ++ pWb35Reg->BB58 = 0x64646464; ++ pltmp[11] = 0xAA28C000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ ++ case RF_AIROHA_2230: ++ ++ pltmp[0] = 0X16764A77; // 0x1000 AGC_Ctrl1 //0x16765A77 ++ pltmp[1] = 0x9affafb2; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xFFFd203c; // 0xFFFb203a; // 0x100c AGC_Ctrl4 Modify for 33's 1.0.95.xxx version ++ pWb35Reg->BB0C = 0xFFFd203c; ++ pltmp[4] = 0X0FBFDCc5; // 0X0FBFDCA0; // 0x1010 AGC_Ctrl5 //0x0FB2E0B7 Modify for 33's 1.0.95.xxx version ++ pltmp[5] = 0x00caa332; // 0x00caa333; // 0x1014 AGC_Ctrl6 Modify for 33's 1.0.95.xxx version ++ pltmp[6] = 0XF6632111; // 0XF1632112; // 0x1018 AGC_Ctrl7 //0xf6632112 Modify for 33's 1.0.95.xxx version ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04C43640; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0X40000528; //0x40000228 ++ pltmp[11] = 0x232dfF30; // 0x232A9F30; // 0x102c A_ACQ_Ctrl //0x232a9730 ++ pWb35Reg->BB2C = 0x232dfF30; //Modify for 33's 1.0.95.xxx version, antenna 1 ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl //0x5B6C8769 ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = BB48_DEFAULT_AL2230_11G; // 0x1048 11b TX RC filter 20060613.2 ++ pWb35Reg->BB48 = BB48_DEFAULT_AL2230_11G; // 20051221 ch14 20060613.2 ++ pltmp[7] = BB4C_DEFAULT_AL2230_11G; // 0x104c 11b TX RC filter 20060613.2 ++ pWb35Reg->BB4C = BB4C_DEFAULT_AL2230_11G; // 20060613.1 20060613.2 ++ pltmp[8] = 0x27106200; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106200; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x52524242; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x52524242; ++ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ ++ case RF_AIROHA_2230S: // 20060420 Add this ++ ++ pltmp[0] = 0X16764A77; // 0x1000 AGC_Ctrl1 //0x16765A77 ++ pltmp[1] = 0x9affafb2; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xFFFd203c; // 0xFFFb203a; // 0x100c AGC_Ctrl4 Modify for 33's 1.0.95.xxx version ++ pWb35Reg->BB0C = 0xFFFd203c; ++ pltmp[4] = 0X0FBFDCc5; // 0X0FBFDCA0; // 0x1010 AGC_Ctrl5 //0x0FB2E0B7 Modify for 33's 1.0.95.xxx version ++ pltmp[5] = 0x00caa332; // 0x00caa333; // 0x1014 AGC_Ctrl6 Modify for 33's 1.0.95.xxx version ++ pltmp[6] = 0XF6632111; // 0XF1632112; // 0x1018 AGC_Ctrl7 //0xf6632112 Modify for 33's 1.0.95.xxx version ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04C43640; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0X40000528; //0x40000228 ++ pltmp[11] = 0x232dfF30; // 0x232A9F30; // 0x102c A_ACQ_Ctrl //0x232a9730 ++ pWb35Reg->BB2C = 0x232dfF30; //Modify for 33's 1.0.95.xxx version, antenna 1 ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl //0x5B6C8769 ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = BB48_DEFAULT_AL2230_11G; // 0x1048 11b TX RC filter 20060613.2 ++ pWb35Reg->BB48 = BB48_DEFAULT_AL2230_11G; // 20051221 ch14 20060613.2 ++ pltmp[7] = BB4C_DEFAULT_AL2230_11G; // 0x104c 11b TX RC filter 20060613.2 ++ pWb35Reg->BB4C = BB4C_DEFAULT_AL2230_11G; // 20060613.1 ++ pltmp[8] = 0x27106200; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106200; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x52523232; // 20060419 0x52524242; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x52523232; // 20060419 0x52524242; ++ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ ++ case RF_AIROHA_7230: ++/* ++ pltmp[0] = 0x16a84a77; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9affafb2; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xFFFb203a; // 0x100c AGC_Ctrl4 ++ pWb35Reg->BB0c = 0xFFFb203a; ++ pltmp[4] = 0x0FBFDCB7; // 0x1010 AGC_Ctrl5 ++ pltmp[5] = 0x00caa333; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0xf6632112; // 0x1018 AGC_Ctrl7 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04C43640; // 0x1020 AGC_Ctrl9 ++ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0x40000228; ++ pltmp[11] = 0x232A9F30;// 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2c = 0x232A9F30; ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl ++ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3c = 0x00000000; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = 0x00453B24; // 0x1048 11b TX RC filter ++ pltmp[7] = 0x0E00FEFF; // 0x104c 11b TX RC filter ++ pltmp[8] = 0x27106200; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106200; ++ pltmp[9] = 0; // 0x1054 ++ pWb35Reg->BB54 = 0x00000000; ++ pltmp[10] = 0x64645252; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x64645252; ++ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++*/ ++ BBProcessor_AL7230_2400( pHwData ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ ++ case RF_WB_242: ++ case RF_WB_242_1: // 20060619.5 Add ++ ++ pltmp[0] = 0x16A8525D; // 0x1000 AGC_Ctrl1 ++ pltmp[1] = 0x9AFF9ABA; // 0x1004 AGC_Ctrl2 ++ pltmp[2] = 0x55D00A04; // 0x1008 AGC_Ctrl3 ++ pltmp[3] = 0xEEE91C32; // 0x100c AGC_Ctrl4 ++ pWb35Reg->BB0C = 0xEEE91C32; ++ pltmp[4] = 0x0FACDCC5; // 0x1010 AGC_Ctrl5 ++ pltmp[5] = 0x000AA344; // 0x1014 AGC_Ctrl6 ++ pltmp[6] = 0x22222221; // 0x1018 AGC_Ctrl7 ++ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8 ++ pltmp[8] = 0x04CC3440; // 20051018 0x03CB3440; // 0x1020 AGC_Ctrl9 20051014 0x03C33440 ++ pltmp[9] = 0xA9002A79; // 0x1024 AGC_Ctrl10 ++ pltmp[10] = 0x40000528; // 0x1028 ++ pltmp[11] = 0x23457F30; // 0x102c A_ACQ_Ctrl ++ pWb35Reg->BB2C = 0x23457F30; ++ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT ); ++ ++ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl ++ pWb35Reg->BB30 = 0x00002C54; ++ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl ++ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl ++ pltmp[3] = pHwData->BB3c_cal; // 0x103c 11a TX LS filter ++ pWb35Reg->BB3C = pHwData->BB3c_cal; ++ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter ++ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter ++ pltmp[6] = BB48_DEFAULT_WB242_11G; // 0x1048 11b TX RC filter 20060613.2 ++ pWb35Reg->BB48 = BB48_DEFAULT_WB242_11G; // 20060613.1 20060613.2 ++ pltmp[7] = BB4C_DEFAULT_WB242_11G; // 0x104c 11b TX RC filter 20060613.2 ++ pWb35Reg->BB4C = BB4C_DEFAULT_WB242_11G; // 20060613.1 20060613.2 ++ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl ++ pWb35Reg->BB50 = 0x27106208; ++ pltmp[9] = pHwData->BB54_cal; // 0x1054 ++ pWb35Reg->BB54 = pHwData->BB54_cal; ++ pltmp[10] = 0x52523131; // 0x1058 IQ_Alpha ++ pWb35Reg->BB58 = 0x52523131; ++ pltmp[11] = 0xAA0AC000; // 20060825 0xAA2AC000; // 0x105c DC_Cancel ++ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT ); ++ ++ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 ); ++ break; ++ } ++ ++ // Fill the LNA table ++ pWb35Reg->LNAValue[0] = (u8)(pWb35Reg->BB0C & 0xff); ++ pWb35Reg->LNAValue[1] = 0; ++ pWb35Reg->LNAValue[2] = (u8)((pWb35Reg->BB0C & 0xff00)>>8); ++ pWb35Reg->LNAValue[3] = 0; ++ ++ // Fill SQ3 table ++ for( i=0; iSQ3_filter[i] = 0x2f; // half of Bit 0 ~ 6 ++} ++ ++void set_tx_power_per_channel_max2829( phw_data_t pHwData, ChanInfo Channel) ++{ ++ RFSynthesizer_SetPowerIndex( pHwData, 100 ); // 20060620.1 Modify ++} ++ ++void set_tx_power_per_channel_al2230( phw_data_t pHwData, ChanInfo Channel ) ++{ ++ u8 index = 100; ++ ++ if (pHwData->TxVgaFor24[Channel.ChanNo - 1] != 0xff) // 20060620.1 Add ++ index = pHwData->TxVgaFor24[Channel.ChanNo - 1]; ++ ++ RFSynthesizer_SetPowerIndex( pHwData, index ); ++} ++ ++void set_tx_power_per_channel_al7230( phw_data_t pHwData, ChanInfo Channel) ++{ ++ u8 i, index = 100; ++ ++ switch ( Channel.band ) ++ { ++ case BAND_TYPE_DSSS: ++ case BAND_TYPE_OFDM_24: ++ { ++ if (pHwData->TxVgaFor24[Channel.ChanNo - 1] != 0xff) ++ index = pHwData->TxVgaFor24[Channel.ChanNo - 1]; ++ } ++ break; ++ case BAND_TYPE_OFDM_5: ++ { ++ for (i =0; i<35; i++) ++ { ++ if (Channel.ChanNo == pHwData->TxVgaFor50[i].ChanNo) ++ { ++ if (pHwData->TxVgaFor50[i].TxVgaValue != 0xff) ++ index = pHwData->TxVgaFor50[i].TxVgaValue; ++ break; ++ } ++ } ++ } ++ break; ++ } ++ RFSynthesizer_SetPowerIndex( pHwData, index ); ++} ++ ++void set_tx_power_per_channel_wb242( phw_data_t pHwData, ChanInfo Channel) ++{ ++ u8 index = 100; ++ ++ switch ( Channel.band ) ++ { ++ case BAND_TYPE_DSSS: ++ case BAND_TYPE_OFDM_24: ++ { ++ if (pHwData->TxVgaFor24[Channel.ChanNo - 1] != 0xff) ++ index = pHwData->TxVgaFor24[Channel.ChanNo - 1]; ++ } ++ break; ++ case BAND_TYPE_OFDM_5: ++ break; ++ } ++ RFSynthesizer_SetPowerIndex( pHwData, index ); ++} ++ ++//============================================================================================================= ++// RFSynthesizer_SwitchingChannel -- ++// ++// Description: ++// Swithch the RF channel. ++// ++// Arguments: ++// pHwData - Handle of the USB Device. ++// Channel - The channel no. ++// ++// Return values: ++// None. ++//============================================================================================================= ++void ++RFSynthesizer_SwitchingChannel( phw_data_t pHwData, ChanInfo Channel ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 pltmp[16]; // The 16 is the maximum capability of hardware ++ u32 count, ltmp; ++ u8 i, j, number; ++ u8 ChnlTmp; ++ ++ switch( pHwData->phy_type ) ++ { ++ case RF_MAXIM_2825: ++ case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331) ++ ++ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 13 ++ { ++ for( i=0; i<3; i++ ) ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2825_channel_data_24[Channel.ChanNo-1][i], 18); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT ); ++ } ++ RFSynthesizer_SetPowerIndex( pHwData, 100 ); ++ break; ++ ++ case RF_MAXIM_2827: ++ ++ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 13 ++ { ++ for( i=0; i<3; i++ ) ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_channel_data_24[Channel.ChanNo-1][i], 18); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT ); ++ } ++ else if( Channel.band == BAND_TYPE_OFDM_5 ) // channel 36 ~ 64 ++ { ++ ChnlTmp = (Channel.ChanNo - 36) / 4; ++ for( i=0; i<3; i++ ) ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_channel_data_50[ChnlTmp][i], 18); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT ); ++ } ++ RFSynthesizer_SetPowerIndex( pHwData, 100 ); ++ break; ++ ++ case RF_MAXIM_2828: ++ ++ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 13 ++ { ++ for( i=0; i<3; i++ ) ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_channel_data_24[Channel.ChanNo-1][i], 18); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT ); ++ } ++ else if( Channel.band == BAND_TYPE_OFDM_5 ) // channel 36 ~ 64 ++ { ++ ChnlTmp = (Channel.ChanNo - 36) / 4; ++ for ( i = 0; i < 3; i++) ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_channel_data_50[ChnlTmp][i], 18); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT ); ++ } ++ RFSynthesizer_SetPowerIndex( pHwData, 100 ); ++ break; ++ ++ case RF_MAXIM_2829: ++ ++ if( Channel.band <= BAND_TYPE_OFDM_24) ++ { ++ for( i=0; i<3; i++ ) ++ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2829_channel_data_24[Channel.ChanNo-1][i], 18); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT ); ++ } ++ else if( Channel.band == BAND_TYPE_OFDM_5 ) ++ { ++ count = sizeof(max2829_channel_data_50) / sizeof(max2829_channel_data_50[0]); ++ ++ for( i=0; iband) ++ { ++ if (Channel.band <= BAND_TYPE_OFDM_24) ++ { ++ //Update BB register ++ BBProcessor_AL7230_2400(pHwData); ++ ++ number = sizeof(al7230_rf_data_24)/sizeof(al7230_rf_data_24[0]); ++ Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number); ++ } ++ else ++ { ++ //Update BB register ++ BBProcessor_AL7230_5000(pHwData); ++ ++ number = sizeof(al7230_rf_data_50)/sizeof(al7230_rf_data_50[0]); ++ Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number); ++ } ++ ++ // Write to register. number must less and equal than 16 ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, number, NO_INCREMENT ); ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("Band changed\n")); ++ #endif ++ } ++ ++ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 14 ++ { ++ for( i=0; i<2; i++ ) ++ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_channel_data_24[Channel.ChanNo-1][i]&0xffffff); ++ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 2, NO_INCREMENT ); ++ } ++ else if( Channel.band == BAND_TYPE_OFDM_5 ) ++ { ++ //Update Reg12 ++ if ((Channel.ChanNo > 64) && (Channel.ChanNo <= 165)) ++ { ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x00143c; ++ Wb35Reg_Write( pHwData, 0x0864, ltmp ); ++ } ++ else //reg12 = 0x00147c at Channel 4920 ~ 5320 ++ { ++ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x00147c; ++ Wb35Reg_Write( pHwData, 0x0864, ltmp ); ++ } ++ ++ count = sizeof(al7230_channel_data_5) / sizeof(al7230_channel_data_5[0]); ++ ++ for (i=0; iBB50 &= ~(BIT(11)|BIT(12)); ++ Wb35Reg_Write( pHwData, 0x1050, pWb35Reg->BB50 ); // MODE_Ctrl ++ // MAC: select 2.4 GHz, bit[5]=0 ++ pWb35Reg->M78_ERPInformation &= ~BIT(5); ++ Wb35Reg_Write( pHwData, 0x0878, pWb35Reg->M78_ERPInformation ); ++ // enable 11b Baseband ++ pWb35Reg->BB30 &= ~BIT(31); ++ Wb35Reg_Write( pHwData, 0x1030, pWb35Reg->BB30 ); ++ } ++ else if( (Channel.band == BAND_TYPE_OFDM_5) ) ++ { ++ // BB: select 5 GHz ++ pWb35Reg->BB50 &= ~(BIT(11)|BIT(12)); ++ if (Channel.ChanNo <=64 ) ++ pWb35Reg->BB50 |= BIT(12); // 10-5.25GHz ++ else if ((Channel.ChanNo >= 100) && (Channel.ChanNo <= 124)) ++ pWb35Reg->BB50 |= BIT(11); // 01-5.48GHz ++ else if ((Channel.ChanNo >=128) && (Channel.ChanNo <= 161)) ++ pWb35Reg->BB50 |= (BIT(12)|BIT(11)); // 11-5.775GHz ++ else //Chan 184 ~ 196 will use bit[12-11] = 10 in version sh-src-1.2.25 ++ pWb35Reg->BB50 |= BIT(12); ++ Wb35Reg_Write( pHwData, 0x1050, pWb35Reg->BB50 ); // MODE_Ctrl ++ ++ //(1) M78 should alway use 2.4G setting when using RF_AIROHA_7230 ++ //(2) BB30 has been updated previously. ++ if (pHwData->phy_type != RF_AIROHA_7230) ++ { ++ // MAC: select 5 GHz, bit[5]=1 ++ pWb35Reg->M78_ERPInformation |= BIT(5); ++ Wb35Reg_Write( pHwData, 0x0878, pWb35Reg->M78_ERPInformation ); ++ ++ // disable 11b Baseband ++ pWb35Reg->BB30 |= BIT(31); ++ Wb35Reg_Write( pHwData, 0x1030, pWb35Reg->BB30 ); ++ } ++ } ++} ++ ++//Set the tx power directly from DUT GUI, not from the EEPROM. Return the current setting ++u8 RFSynthesizer_SetPowerIndex( phw_data_t pHwData, u8 PowerIndex ) ++{ ++ u32 Band = pHwData->band; ++ u8 index=0; ++ ++ if( pHwData->power_index == PowerIndex ) // 20060620.1 Add ++ return PowerIndex; ++ ++ if (RF_MAXIM_2825 == pHwData->phy_type) ++ { ++ // Channel 1 - 13 ++ index = RFSynthesizer_SetMaxim2825Power( pHwData, PowerIndex ); ++ } ++ else if (RF_MAXIM_2827 == pHwData->phy_type) ++ { ++ if( Band <= BAND_TYPE_OFDM_24 ) // Channel 1 - 13 ++ index = RFSynthesizer_SetMaxim2827_24Power( pHwData, PowerIndex ); ++ else// if( Band == BAND_TYPE_OFDM_5 ) // Channel 36 - 64 ++ index = RFSynthesizer_SetMaxim2827_50Power( pHwData, PowerIndex ); ++ } ++ else if (RF_MAXIM_2828 == pHwData->phy_type) ++ { ++ if( Band <= BAND_TYPE_OFDM_24 ) // Channel 1 - 13 ++ index = RFSynthesizer_SetMaxim2828_24Power( pHwData, PowerIndex ); ++ else// if( Band == BAND_TYPE_OFDM_5 ) // Channel 36 - 64 ++ index = RFSynthesizer_SetMaxim2828_50Power( pHwData, PowerIndex ); ++ } ++ else if( RF_AIROHA_2230 == pHwData->phy_type ) ++ { ++ //Power index: 0 ~ 63 // Channel 1 - 14 ++ index = RFSynthesizer_SetAiroha2230Power( pHwData, PowerIndex ); ++ index = (u8)al2230_txvga_data[index][1]; ++ } ++ else if( RF_AIROHA_2230S == pHwData->phy_type ) // 20060420 Add this ++ { ++ //Power index: 0 ~ 63 // Channel 1 - 14 ++ index = RFSynthesizer_SetAiroha2230Power( pHwData, PowerIndex ); ++ index = (u8)al2230_txvga_data[index][1]; ++ } ++ else if( RF_AIROHA_7230 == pHwData->phy_type ) ++ { ++ //Power index: 0 ~ 63 ++ index = RFSynthesizer_SetAiroha7230Power( pHwData, PowerIndex ); ++ index = (u8)al7230_txvga_data[index][1]; ++ } ++ else if( (RF_WB_242 == pHwData->phy_type) || ++ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add ++ { ++ //Power index: 0 ~ 19 for original. New range is 0 ~ 33 ++ index = RFSynthesizer_SetWinbond242Power( pHwData, PowerIndex ); ++ index = (u8)w89rf242_txvga_data[index][1]; ++ } ++ ++ pHwData->power_index = index; // Backup current ++ return index; ++} ++ ++//-- Sub function ++u8 RFSynthesizer_SetMaxim2828_24Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ if( index > 1 ) index = 1; ++ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_power_data_24[index], 18); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return index; ++} ++//-- ++u8 RFSynthesizer_SetMaxim2828_50Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ if( index > 1 ) index = 1; ++ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_power_data_50[index], 18); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return index; ++} ++//-- ++u8 RFSynthesizer_SetMaxim2827_24Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ if( index > 1 ) index = 1; ++ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_power_data_24[index], 18); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return index; ++} ++//-- ++u8 RFSynthesizer_SetMaxim2827_50Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ if( index > 1 ) index = 1; ++ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_power_data_50[index], 18); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return index; ++} ++//-- ++u8 RFSynthesizer_SetMaxim2825Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ if( index > 1 ) index = 1; ++ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2825_power_data_24[index], 18); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return index; ++} ++//-- ++u8 RFSynthesizer_SetAiroha2230Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ u8 i,count; ++ ++ count = sizeof(al2230_txvga_data) / sizeof(al2230_txvga_data[0]); ++ for (i=0; i= index) ++ break; ++ } ++ if (i == count) ++ i--; ++ ++ PowerData = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_txvga_data[i][0], 20); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return i; ++} ++//-- ++u8 RFSynthesizer_SetAiroha7230Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ u8 i,count; ++ ++ //PowerData = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( airoha_power_data_24[index], 20); ++ count = sizeof(al7230_txvga_data) / sizeof(al7230_txvga_data[0]); ++ for (i=0; i= index) ++ break; ++ } ++ if (i == count) ++ i--; ++ PowerData = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_txvga_data[i][0]&0xffffff); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return i; ++} ++ ++u8 RFSynthesizer_SetWinbond242Power( phw_data_t pHwData, u8 index ) ++{ ++ u32 PowerData; ++ u8 i,count; ++ ++ count = sizeof(w89rf242_txvga_data) / sizeof(w89rf242_txvga_data[0]); ++ for (i=0; i= index) ++ break; ++ } ++ if (i == count) ++ i--; ++ ++ // Set TxVga into RF ++ PowerData = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( w89rf242_txvga_data[i][0], 24); ++ Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ ++ // Update BB48 BB4C BB58 for high precision txvga ++ Wb35Reg_Write( pHwData, 0x1048, w89rf242_txvga_data[i][2] ); ++ Wb35Reg_Write( pHwData, 0x104c, w89rf242_txvga_data[i][3] ); ++ Wb35Reg_Write( pHwData, 0x1058, w89rf242_txvga_data[i][4] ); ++ ++// Rf vga 0 ~ 3 for temperature compensate. It will affect the scan Bss. ++// The i value equals to 8 or 7 usually. So It's not necessary to setup this RF register. ++// if( i <= 3 ) ++// PowerData = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( 0x000024, 24 ); ++// else ++// PowerData = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( 0x001824, 24 ); ++// Wb35Reg_Write( pHwData, 0x0864, PowerData ); ++ return i; ++} ++ ++//=========================================================================================================== ++// Dxx_initial -- ++// Mxx_initial -- ++ // ++// Routine Description: ++// Initial the hardware setting and module variable ++ // ++//=========================================================================================================== ++void Dxx_initial( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ // Old IC:Single mode only. ++ // New IC: operation decide by Software set bit[4]. 1:multiple 0: single ++ pWb35Reg->D00_DmaControl = 0xc0000004; //Txon, Rxon, multiple Rx for new 4k DMA ++ //Txon, Rxon, single Rx for old 8k ASIC ++ if( !HAL_USB_MODE_BURST( pHwData ) ) ++ pWb35Reg->D00_DmaControl = 0xc0000000;//Txon, Rxon, single Rx for new 4k DMA ++ ++ Wb35Reg_WriteSync( pHwData, 0x0400, pWb35Reg->D00_DmaControl ); ++} ++ ++void Mxx_initial( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 tmp; ++ u32 pltmp[11]; ++ u16 i; ++ ++ ++ //====================================================== ++ // Initial Mxx register ++ //====================================================== ++ ++ // M00 bit set ++#ifdef _IBSS_BEACON_SEQ_STICK_ ++ pWb35Reg->M00_MacControl = 0; // Solve beacon sequence number stop by software ++#else ++ pWb35Reg->M00_MacControl = 0x80000000; // Solve beacon sequence number stop by hardware ++#endif ++ ++ // M24 disable enter power save, BB RxOn and enable NAV attack ++ pWb35Reg->M24_MacControl = 0x08040042; ++ pltmp[0] = pWb35Reg->M24_MacControl; ++ ++ pltmp[1] = 0; // Skip M28, because no initialize value is required. ++ ++ // M2C CWmin and CWmax setting ++ pHwData->cwmin = DEFAULT_CWMIN; ++ pHwData->cwmax = DEFAULT_CWMAX; ++ pWb35Reg->M2C_MacControl = DEFAULT_CWMIN << 10; ++ pWb35Reg->M2C_MacControl |= DEFAULT_CWMAX; ++ pltmp[2] = pWb35Reg->M2C_MacControl; ++ ++ // M30 BSSID ++ pltmp[3] = *(PULONG)pHwData->bssid; ++ ++ // M34 ++ pHwData->AID = DEFAULT_AID; ++ tmp = *(PUSHORT)(pHwData->bssid+4); ++ tmp |= DEFAULT_AID << 16; ++ pltmp[4] = tmp; ++ ++ // M38 ++ pWb35Reg->M38_MacControl = (DEFAULT_RATE_RETRY_LIMIT<<8) | (DEFAULT_LONG_RETRY_LIMIT << 4) | DEFAULT_SHORT_RETRY_LIMIT; ++ pltmp[5] = pWb35Reg->M38_MacControl; ++ ++ // M3C ++ tmp = (DEFAULT_PIFST << 26) | (DEFAULT_EIFST << 16) | (DEFAULT_DIFST << 8) | (DEFAULT_SIFST << 4) | DEFAULT_OSIFST ; ++ pWb35Reg->M3C_MacControl = tmp; ++ pltmp[6] = tmp; ++ ++ // M40 ++ pHwData->slot_time_select = DEFAULT_SLOT_TIME; ++ tmp = (DEFAULT_ATIMWD << 16) | DEFAULT_SLOT_TIME; ++ pWb35Reg->M40_MacControl = tmp; ++ pltmp[7] = tmp; ++ ++ // M44 ++ tmp = DEFAULT_MAX_TX_MSDU_LIFE_TIME << 10; // *1024 ++ pWb35Reg->M44_MacControl = tmp; ++ pltmp[8] = tmp; ++ ++ // M48 ++ pHwData->BeaconPeriod = DEFAULT_BEACON_INTERVAL; ++ pHwData->ProbeDelay = DEFAULT_PROBE_DELAY_TIME; ++ tmp = (DEFAULT_BEACON_INTERVAL << 16) | DEFAULT_PROBE_DELAY_TIME; ++ pWb35Reg->M48_MacControl = tmp; ++ pltmp[9] = tmp; ++ ++ //M4C ++ pWb35Reg->M4C_MacStatus = (DEFAULT_PROTOCOL_VERSION << 30) | (DEFAULT_MAC_POWER_STATE << 28) | (DEFAULT_DTIM_ALERT_TIME << 24); ++ pltmp[10] = pWb35Reg->M4C_MacStatus; ++ ++ // Burst write ++ //Wb35Reg_BurstWrite( pHwData, 0x0824, pltmp, 11, AUTO_INCREMENT ); ++ for( i=0; i<11; i++ ) ++ Wb35Reg_WriteSync( pHwData, 0x0824 + i*4, pltmp[i] ); ++ ++ // M60 ++ Wb35Reg_WriteSync( pHwData, 0x0860, 0x12481248 ); ++ pWb35Reg->M60_MacControl = 0x12481248; ++ ++ // M68 ++ Wb35Reg_WriteSync( pHwData, 0x0868, 0x00050900 ); // 20051018 0x000F0F00 ); // 940930 0x00131300 ++ pWb35Reg->M68_MacControl = 0x00050900; ++ ++ // M98 ++ Wb35Reg_WriteSync( pHwData, 0x0898, 0xffff8888 ); ++ pWb35Reg->M98_MacControl = 0xffff8888; ++} ++ ++ ++void Uxx_power_off_procedure( phw_data_t pHwData ) ++{ ++ // SW, PMU reset and turn off clock ++ Wb35Reg_WriteSync( pHwData, 0x03b0, 3 ); ++ Wb35Reg_WriteSync( pHwData, 0x03f0, 0xf9 ); ++} ++ ++//Decide the TxVga of every channel ++void GetTxVgaFromEEPROM( phw_data_t pHwData ) ++{ ++ u32 i, j, ltmp; ++ u16 Value[MAX_TXVGA_EEPROM]; ++ PUCHAR pctmp; ++ u8 ctmp=0; ++ ++ // Get the entire TxVga setting in EEPROM ++ for( i=0; iphy_type == RF_WB_242 ) ++ { ++ for( i=0; i<4; i++ ) // Only 2412 2437 2462 2484 case must be modified ++ { ++ for( j=0; j<(sizeof(w89rf242_txvga_old_mapping)/sizeof(w89rf242_txvga_old_mapping[0])); j++ ) ++ { ++ if( pctmp[i] < (u8)w89rf242_txvga_old_mapping[j][1] ) ++ { ++ pctmp[i] = (u8)w89rf242_txvga_old_mapping[j][0]; ++ break; ++ } ++ } ++ ++ if( j == (sizeof(w89rf242_txvga_old_mapping)/sizeof(w89rf242_txvga_old_mapping[0])) ) ++ pctmp[i] = (u8)w89rf242_txvga_old_mapping[j-1][0]; ++ } ++ } ++ ++ // 20060621 Add ++ memcpy( pHwData->TxVgaSettingInEEPROM, pctmp, MAX_TXVGA_EEPROM*2 ); //MAX_TXVGA_EEPROM is u16 count ++ EEPROMTxVgaAdjust( pHwData ); ++} ++ ++// This function will affect the TxVga parameter in HAL. If hal_set_current_channel ++// or RFSynthesizer_SetPowerIndex be called, new TxVga will take effect. ++// TxVgaSettingInEEPROM of sHwData is an u8 array point to EEPROM contain for IS89C35 ++// This function will use default TxVgaSettingInEEPROM data to calculate new TxVga. ++void EEPROMTxVgaAdjust( phw_data_t pHwData ) // 20060619.5 Add ++{ ++ PUCHAR pTxVga = pHwData->TxVgaSettingInEEPROM; ++ s16 i, stmp; ++ ++ //-- 2.4G -- 20060704.2 Request from Tiger ++ //channel 1 ~ 5 ++ stmp = pTxVga[1] - pTxVga[0]; ++ for( i=0; i<5; i++ ) ++ pHwData->TxVgaFor24[i] = pTxVga[0] + stmp*i/4; ++ //channel 6 ~ 10 ++ stmp = pTxVga[2] - pTxVga[1]; ++ for( i=5; i<10; i++ ) ++ pHwData->TxVgaFor24[i] = pTxVga[1] + stmp*(i-5)/4; ++ //channel 11 ~ 13 ++ stmp = pTxVga[3] - pTxVga[2]; ++ for( i=10; i<13; i++ ) ++ pHwData->TxVgaFor24[i] = pTxVga[2] + stmp*(i-10)/2; ++ //channel 14 ++ pHwData->TxVgaFor24[13] = pTxVga[3]; ++ ++ //-- 5G -- ++ if( pHwData->phy_type == RF_AIROHA_7230 ) ++ { ++ //channel 184 ++ pHwData->TxVgaFor50[0].ChanNo = 184; ++ pHwData->TxVgaFor50[0].TxVgaValue = pTxVga[4]; ++ //channel 196 ++ pHwData->TxVgaFor50[3].ChanNo = 196; ++ pHwData->TxVgaFor50[3].TxVgaValue = pTxVga[5]; ++ //interpolate ++ pHwData->TxVgaFor50[1].ChanNo = 188; ++ pHwData->TxVgaFor50[2].ChanNo = 192; ++ stmp = pTxVga[5] - pTxVga[4]; ++ pHwData->TxVgaFor50[2].TxVgaValue = pTxVga[5] - stmp/3; ++ pHwData->TxVgaFor50[1].TxVgaValue = pTxVga[5] - stmp*2/3; ++ ++ //channel 16 ++ pHwData->TxVgaFor50[6].ChanNo = 16; ++ pHwData->TxVgaFor50[6].TxVgaValue = pTxVga[6]; ++ pHwData->TxVgaFor50[4].ChanNo = 8; ++ pHwData->TxVgaFor50[4].TxVgaValue = pTxVga[6]; ++ pHwData->TxVgaFor50[5].ChanNo = 12; ++ pHwData->TxVgaFor50[5].TxVgaValue = pTxVga[6]; ++ ++ //channel 36 ++ pHwData->TxVgaFor50[8].ChanNo = 36; ++ pHwData->TxVgaFor50[8].TxVgaValue = pTxVga[7]; ++ pHwData->TxVgaFor50[7].ChanNo = 34; ++ pHwData->TxVgaFor50[7].TxVgaValue = pTxVga[7]; ++ pHwData->TxVgaFor50[9].ChanNo = 38; ++ pHwData->TxVgaFor50[9].TxVgaValue = pTxVga[7]; ++ ++ //channel 40 ++ pHwData->TxVgaFor50[10].ChanNo = 40; ++ pHwData->TxVgaFor50[10].TxVgaValue = pTxVga[8]; ++ //channel 48 ++ pHwData->TxVgaFor50[14].ChanNo = 48; ++ pHwData->TxVgaFor50[14].TxVgaValue = pTxVga[9]; ++ //interpolate ++ pHwData->TxVgaFor50[11].ChanNo = 42; ++ pHwData->TxVgaFor50[12].ChanNo = 44; ++ pHwData->TxVgaFor50[13].ChanNo = 46; ++ stmp = pTxVga[9] - pTxVga[8]; ++ pHwData->TxVgaFor50[13].TxVgaValue = pTxVga[9] - stmp/4; ++ pHwData->TxVgaFor50[12].TxVgaValue = pTxVga[9] - stmp*2/4; ++ pHwData->TxVgaFor50[11].TxVgaValue = pTxVga[9] - stmp*3/4; ++ ++ //channel 52 ++ pHwData->TxVgaFor50[15].ChanNo = 52; ++ pHwData->TxVgaFor50[15].TxVgaValue = pTxVga[10]; ++ //channel 64 ++ pHwData->TxVgaFor50[18].ChanNo = 64; ++ pHwData->TxVgaFor50[18].TxVgaValue = pTxVga[11]; ++ //interpolate ++ pHwData->TxVgaFor50[16].ChanNo = 56; ++ pHwData->TxVgaFor50[17].ChanNo = 60; ++ stmp = pTxVga[11] - pTxVga[10]; ++ pHwData->TxVgaFor50[17].TxVgaValue = pTxVga[11] - stmp/3; ++ pHwData->TxVgaFor50[16].TxVgaValue = pTxVga[11] - stmp*2/3; ++ ++ //channel 100 ++ pHwData->TxVgaFor50[19].ChanNo = 100; ++ pHwData->TxVgaFor50[19].TxVgaValue = pTxVga[12]; ++ //channel 112 ++ pHwData->TxVgaFor50[22].ChanNo = 112; ++ pHwData->TxVgaFor50[22].TxVgaValue = pTxVga[13]; ++ //interpolate ++ pHwData->TxVgaFor50[20].ChanNo = 104; ++ pHwData->TxVgaFor50[21].ChanNo = 108; ++ stmp = pTxVga[13] - pTxVga[12]; ++ pHwData->TxVgaFor50[21].TxVgaValue = pTxVga[13] - stmp/3; ++ pHwData->TxVgaFor50[20].TxVgaValue = pTxVga[13] - stmp*2/3; ++ ++ //channel 128 ++ pHwData->TxVgaFor50[26].ChanNo = 128; ++ pHwData->TxVgaFor50[26].TxVgaValue = pTxVga[14]; ++ //interpolate ++ pHwData->TxVgaFor50[23].ChanNo = 116; ++ pHwData->TxVgaFor50[24].ChanNo = 120; ++ pHwData->TxVgaFor50[25].ChanNo = 124; ++ stmp = pTxVga[14] - pTxVga[13]; ++ pHwData->TxVgaFor50[25].TxVgaValue = pTxVga[14] - stmp/4; ++ pHwData->TxVgaFor50[24].TxVgaValue = pTxVga[14] - stmp*2/4; ++ pHwData->TxVgaFor50[23].TxVgaValue = pTxVga[14] - stmp*3/4; ++ ++ //channel 140 ++ pHwData->TxVgaFor50[29].ChanNo = 140; ++ pHwData->TxVgaFor50[29].TxVgaValue = pTxVga[15]; ++ //interpolate ++ pHwData->TxVgaFor50[27].ChanNo = 132; ++ pHwData->TxVgaFor50[28].ChanNo = 136; ++ stmp = pTxVga[15] - pTxVga[14]; ++ pHwData->TxVgaFor50[28].TxVgaValue = pTxVga[15] - stmp/3; ++ pHwData->TxVgaFor50[27].TxVgaValue = pTxVga[15] - stmp*2/3; ++ ++ //channel 149 ++ pHwData->TxVgaFor50[30].ChanNo = 149; ++ pHwData->TxVgaFor50[30].TxVgaValue = pTxVga[16]; ++ //channel 165 ++ pHwData->TxVgaFor50[34].ChanNo = 165; ++ pHwData->TxVgaFor50[34].TxVgaValue = pTxVga[17]; ++ //interpolate ++ pHwData->TxVgaFor50[31].ChanNo = 153; ++ pHwData->TxVgaFor50[32].ChanNo = 157; ++ pHwData->TxVgaFor50[33].ChanNo = 161; ++ stmp = pTxVga[17] - pTxVga[16]; ++ pHwData->TxVgaFor50[33].TxVgaValue = pTxVga[17] - stmp/4; ++ pHwData->TxVgaFor50[32].TxVgaValue = pTxVga[17] - stmp*2/4; ++ pHwData->TxVgaFor50[31].TxVgaValue = pTxVga[17] - stmp*3/4; ++ } ++ ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG((" TxVgaFor24 : \n")); ++ DataDmp((u8 *)pHwData->TxVgaFor24, 14 ,0); ++ WBDEBUG((" TxVgaFor50 : \n")); ++ DataDmp((u8 *)pHwData->TxVgaFor50, 70 ,0); ++ #endif ++} ++ ++void BBProcessor_RateChanging( phw_data_t pHwData, u8 rate ) // 20060613.1 ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ unsigned char Is11bRate; ++ ++ Is11bRate = (rate % 6) ? 1 : 0; ++ switch( pHwData->phy_type ) ++ { ++ case RF_AIROHA_2230: ++ case RF_AIROHA_2230S: // 20060420 Add this ++ if( Is11bRate ) ++ { ++ if( (pWb35Reg->BB48 != BB48_DEFAULT_AL2230_11B) && ++ (pWb35Reg->BB4C != BB4C_DEFAULT_AL2230_11B) ) ++ { ++ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_AL2230_11B ); ++ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_AL2230_11B ); ++ } ++ } ++ else ++ { ++ if( (pWb35Reg->BB48 != BB48_DEFAULT_AL2230_11G) && ++ (pWb35Reg->BB4C != BB4C_DEFAULT_AL2230_11G) ) ++ { ++ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_AL2230_11G ); ++ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_AL2230_11G ); ++ } ++ } ++ break; ++ ++ case RF_WB_242: // 20060623 The fix only for old TxVGA setting ++ if( Is11bRate ) ++ { ++ if( (pWb35Reg->BB48 != BB48_DEFAULT_WB242_11B) && ++ (pWb35Reg->BB4C != BB4C_DEFAULT_WB242_11B) ) ++ { ++ pWb35Reg->BB48 = BB48_DEFAULT_WB242_11B; ++ pWb35Reg->BB4C = BB4C_DEFAULT_WB242_11B; ++ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_WB242_11B ); ++ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_WB242_11B ); ++ } ++ } ++ else ++ { ++ if( (pWb35Reg->BB48 != BB48_DEFAULT_WB242_11G) && ++ (pWb35Reg->BB4C != BB4C_DEFAULT_WB242_11G) ) ++ { ++ pWb35Reg->BB48 = BB48_DEFAULT_WB242_11G; ++ pWb35Reg->BB4C = BB4C_DEFAULT_WB242_11G; ++ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_WB242_11G ); ++ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_WB242_11G ); ++ } ++ } ++ break; ++ } ++} ++ ++ ++ ++ ++ ++ ++ +diff --git a/drivers/staging/winbond/rxisr.c b/drivers/staging/winbond/rxisr.c +new file mode 100644 +index 0000000..18e942c +--- /dev/null ++++ b/drivers/staging/winbond/rxisr.c +@@ -0,0 +1,30 @@ ++#include "os_common.h" ++ ++void vRxTimerInit(PWB32_ADAPTER Adapter) ++{ ++ OS_TIMER_INITIAL(&(Adapter->Mds.nTimer), (void*) RxTimerHandler, (void*) Adapter); ++} ++ ++void vRxTimerStart(PWB32_ADAPTER Adapter, int timeout_value) ++{ ++ if (timeout_valueMds.nTimer), timeout_value ); ++} ++ ++void vRxTimerStop(PWB32_ADAPTER Adapter) ++{ ++ OS_TIMER_CANCEL( &(Adapter->Mds.nTimer), 0 ); ++} ++ ++void RxTimerHandler_1a( PADAPTER Adapter) ++{ ++ RxTimerHandler(NULL, Adapter, NULL, NULL); ++} ++ ++void RxTimerHandler(void* SystemSpecific1, PWB32_ADAPTER Adapter, ++ void* SystemSpecific2, void* SystemSpecific3) ++{ ++ WARN_ON(1); ++} +diff --git a/drivers/staging/winbond/scan_s.h b/drivers/staging/winbond/scan_s.h +new file mode 100644 +index 0000000..1d1b0c4 +--- /dev/null ++++ b/drivers/staging/winbond/scan_s.h +@@ -0,0 +1,115 @@ ++// ++// SCAN task global CONSTANTS, STRUCTURES, variables ++// ++ ++////////////////////////////////////////////////////////////////////////// ++//define the msg type of SCAN module ++#define SCANMSG_SCAN_REQ 0x01 ++#define SCANMSG_BEACON 0x02 ++#define SCANMSG_PROBE_RESPONSE 0x03 ++#define SCANMSG_TIMEOUT 0x04 ++#define SCANMSG_TXPROBE_FAIL 0x05 ++#define SCANMSG_ENABLE_BGSCAN 0x06 ++#define SCANMSG_STOP_SCAN 0x07 ++ ++// BSS Type =>conform to ++// IBSS : ToDS/FromDS = 00 ++// Infrastructure : ToDS/FromDS = 01 ++#define IBSS_NET 0 ++#define ESS_NET 1 ++#define ANYBSS_NET 2 ++ ++// Scan Type ++#define ACTIVE_SCAN 0 ++#define PASSIVE_SCAN 1 ++ ++/////////////////////////////////////////////////////////////////////////// ++//Global data structures, Initial Scan & Background Scan ++typedef struct _SCAN_REQ_PARA //mandatory parameters for SCAN request ++{ ++ u32 ScanType; //passive/active scan ++ ++ CHAN_LIST sChannelList; // 86B ++ u8 reserved_1[2]; ++ ++ struct SSID_Element sSSID; // 34B. scan only for this SSID ++ u8 reserved_2[2]; ++ ++} SCAN_REQ_PARA, *psSCAN_REQ_PARA; ++ ++typedef struct _SCAN_PARAMETERS ++{ ++ u16 wState; ++ u16 iCurrentChannelIndex; ++ ++ SCAN_REQ_PARA sScanReq; ++ ++ u8 BSSID[MAC_ADDR_LENGTH + 2]; //scan only for this BSSID ++ ++ u32 BssType; //scan only for this BSS type ++ ++ //struct SSID_Element sSSID; //scan only for this SSID ++ u16 ProbeDelay; ++ u16 MinChannelTime; ++ ++ u16 MaxChannelTime; ++ u16 reserved_1; ++ ++ s32 iBgScanPeriod; // XP: 5 sec ++ ++ u8 boBgScan; // Wb: enable BG scan, For XP, this value must be FALSE ++ u8 boFastScan; // Wb: reserved ++ u8 boCCAbusy; // Wb: HWMAC CCA busy status ++ u8 reserved_2; ++ ++ //NDIS_MINIPORT_TIMER nTimer; ++ OS_TIMER nTimer; ++ ++ u32 ScanTimeStamp; //Increase 1 per background scan(1 minute) ++ u32 BssTimeStamp; //Increase 1 per connect status check ++ u32 RxNumPerAntenna[2]; // ++ ++ u8 AntennaToggle; // ++ u8 boInTimerHandler; ++ u8 boTimerActive; // Wb: reserved ++ u8 boSave; ++ ++ u32 BScanEnable; // Background scan enable. Default is On ++ ++} SCAN_PARAMETERS, *psSCAN_PARAMETERS; ++ ++// Encapsulate 'Adapter' data structure ++#define psSCAN (&(Adapter->sScanPara)) ++#define psSCANREQ (&(Adapter->sScanPara.sScanReq)) ++ ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// scan.h ++// Define the related definitions of scan module ++// history -- 01/14/03' created ++// ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++//Define the state of scan module ++#define SCAN_INACTIVE 0 ++#define WAIT_PROBE_DELAY 1 ++#define WAIT_RESPONSE_MIN 2 ++#define WAIT_RESPONSE_MAX_ACTIVE 3 ++#define WAIT_BEACON_MAX_PASSIVE 4 ++#define SCAN_COMPLETE 5 ++#define BG_SCAN 6 ++#define BG_SCANNING 7 ++ ++ ++// The value will load from EEPROM ++// If 0xff is set in EEPOM, the driver will use SCAN_MAX_CHNL_TIME instead. ++// The definition is in WbHal.h ++// #define SCAN_MAX_CHNL_TIME (50) ++ ++ ++ ++// static functions ++ ++//static void ScanTimerHandler(PWB32_ADAPTER Adapter); ++//static void vScanTimerStart(PWB32_ADAPTER Adapter, int timeout_value); ++//static void vScanTimerStop(PWB32_ADAPTER Adapter); ++ +diff --git a/drivers/staging/winbond/sme_api.c b/drivers/staging/winbond/sme_api.c +new file mode 100644 +index 0000000..40e93b7 +--- /dev/null ++++ b/drivers/staging/winbond/sme_api.c +@@ -0,0 +1,13 @@ ++//------------------------------------------------------------------------------------ ++// sme_api.c ++// ++// Copyright(C) 2002 Winbond Electronics Corp. ++// ++// ++//------------------------------------------------------------------------------------ ++#include "os_common.h" ++ ++s8 sme_get_rssi(void *pcore_data, s32 *prssi) ++{ ++ BUG(); ++} +diff --git a/drivers/staging/winbond/sme_api.h b/drivers/staging/winbond/sme_api.h +new file mode 100644 +index 0000000..016b225 +--- /dev/null ++++ b/drivers/staging/winbond/sme_api.h +@@ -0,0 +1,265 @@ ++/* ++ * sme_api.h ++ * ++ * Copyright(C) 2002 Winbond Electronics Corp. ++ * ++ * modification history ++ * --------------------------------------------------------------------------- ++ * 1.00.001, 2003-04-21, Kevin created ++ * 1.00.002, 2003-05-14, PD43 & PE20 modified ++ * ++ */ ++ ++#ifndef __SME_API_H__ ++#define __SME_API_H__ ++ ++/****************** INCLUDE FILES SECTION ***********************************/ ++//#include "GL\gl_core.h" ++ ++/****************** CONSTANT AND MACRO SECTION ******************************/ ++#define _INLINE __inline ++ ++#define MEDIA_STATE_DISCONNECTED 0 ++#define MEDIA_STATE_CONNECTED 1 ++ ++//ARRAY CHECK ++#define MAX_POWER_TO_DB 32 ++ ++/****************** TYPE DEFINITION SECTION *********************************/ ++ ++/****************** EXPORTED FUNCTION DECLARATION SECTION *******************/ ++ ++// OID_802_11_BSSID ++s8 sme_get_bssid(void *pcore_data, u8 *pbssid); ++s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid);//Not use ++s8 sme_set_desired_bssid(void *pcore_data, u8 *pbssid); ++ ++// OID_802_11_SSID ++s8 sme_get_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len); ++s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);// Not use ++s8 sme_set_desired_ssid(void *pcore_data, u8 *pssid, u8 ssid_len); ++ ++// OID_802_11_INFRASTRUCTURE_MODE ++s8 sme_get_bss_type(void *pcore_data, u8 *pbss_type); ++s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type);//Not use ++s8 sme_set_desired_bss_type(void *pcore_data, u8 bss_type); ++ ++// OID_802_11_FRAGMENTATION_THRESHOLD ++s8 sme_get_fragment_threshold(void *pcore_data, u32 *pthreshold); ++s8 sme_set_fragment_threshold(void *pcore_data, u32 threshold); ++ ++// OID_802_11_RTS_THRESHOLD ++s8 sme_get_rts_threshold(void *pcore_data, u32 *pthreshold); ++s8 sme_set_rts_threshold(void *pcore_data, u32 threshold); ++ ++// OID_802_11_RSSI ++s8 sme_get_rssi(void *pcore_data, s32 *prssi); ++ ++// OID_802_11_CONFIGURATION ++s8 sme_get_beacon_period(void *pcore_data, u16 *pbeacon_period); ++s8 sme_set_beacon_period(void *pcore_data, u16 beacon_period); ++ ++s8 sme_get_atim_window(void *pcore_data, u16 *patim_window); ++s8 sme_set_atim_window(void *pcore_data, u16 atim_window); ++ ++s8 sme_get_current_channel(void *pcore_data, u8 *pcurrent_channel); ++s8 sme_get_current_band(void *pcore_data, u8 *pcurrent_band); ++s8 sme_set_current_channel(void *pcore_data, u8 current_channel); ++ ++// OID_802_11_BSSID_LIST ++s8 sme_get_scan_bss_count(void *pcore_data, u8 *pcount); ++s8 sme_get_scan_bss(void *pcore_data, u8 index, void **ppbss); ++ ++s8 sme_get_connected_bss(void *pcore_data, void **ppbss_now); ++ ++// OID_802_11_AUTHENTICATION_MODE ++s8 sme_get_auth_mode(void *pcore_data, u8 *pauth_mode); ++s8 sme_set_auth_mode(void *pcore_data, u8 auth_mode); ++ ++// OID_802_11_WEP_STATUS / OID_802_11_ENCRYPTION_STATUS ++s8 sme_get_wep_mode(void *pcore_data, u8 *pwep_mode); ++s8 sme_set_wep_mode(void *pcore_data, u8 wep_mode); ++//s8 sme_get_encryption_status(void *pcore_data, u8 *pstatus); ++//s8 sme_set_encryption_status(void *pcore_data, u8 status); ++ ++// ??????????????????????????????????????? ++ ++// OID_GEN_VENDOR_ID ++// OID_802_3_PERMANENT_ADDRESS ++s8 sme_get_permanent_mac_addr(void *pcore_data, u8 *pmac_addr); ++ ++// OID_802_3_CURRENT_ADDRESS ++s8 sme_get_current_mac_addr(void *pcore_data, u8 *pmac_addr); ++ ++// OID_802_11_NETWORK_TYPE_IN_USE ++s8 sme_get_network_type_in_use(void *pcore_data, u8 *ptype); ++s8 sme_set_network_type_in_use(void *pcore_data, u8 type); ++ ++// OID_802_11_SUPPORTED_RATES ++s8 sme_get_supported_rate(void *pcore_data, u8 *prates); ++ ++// OID_802_11_ADD_WEP ++//12/29/03' wkchen ++s8 sme_set_add_wep(void *pcore_data, u32 key_index, u32 key_len, ++ u8 *Address, u8 *key); ++ ++// OID_802_11_REMOVE_WEP ++s8 sme_set_remove_wep(void *pcre_data, u32 key_index); ++ ++// OID_802_11_DISASSOCIATE ++s8 sme_set_disassociate(void *pcore_data); ++ ++// OID_802_11_POWER_MODE ++s8 sme_get_power_mode(void *pcore_data, u8 *pmode); ++s8 sme_set_power_mode(void *pcore_data, u8 mode); ++ ++// OID_802_11_BSSID_LIST_SCAN ++s8 sme_set_bssid_list_scan(void *pcore_data, void *pscan_para); ++ ++// OID_802_11_RELOAD_DEFAULTS ++s8 sme_set_reload_defaults(void *pcore_data, u8 reload_type); ++ ++ ++// The following SME API functions are used for WPA ++// ++// Mandatory OIDs for WPA ++// ++ ++// OID_802_11_ADD_KEY ++//s8 sme_set_add_key(void *pcore_data, NDIS_802_11_KEY *pkey); ++ ++// OID_802_11_REMOVE_KEY ++//s8 sme_set_remove_key(void *pcore_data, NDIS_802_11_REMOVE_KEY *pkey); ++ ++// OID_802_11_ASSOCIATION_INFORMATION ++//s8 sme_set_association_information(void *pcore_data, ++// NDIS_802_11_ASSOCIATION_INFORMATION *pinfo); ++ ++// OID_802_11_TEST ++//s8 sme_set_test(void *pcore_data, NDIS_802_11_TEST *ptest_data); ++ ++//--------------------------------------------------------------------------// ++/* ++// The left OIDs ++ ++// OID_802_11_NETWORK_TYPES_SUPPORTED ++// OID_802_11_TX_POWER_LEVEL ++// OID_802_11_RSSI_TRIGGER ++// OID_802_11_NUMBER_OF_ANTENNAS ++// OID_802_11_RX_ANTENNA_SELECTED ++// OID_802_11_TX_ANTENNA_SELECTED ++// OID_802_11_STATISTICS ++// OID_802_11_DESIRED_RATES ++// OID_802_11_PRIVACY_FILTER ++ ++*/ ++ ++/*------------------------- none-standard ----------------------------------*/ ++s8 sme_get_connect_status(void *pcore_data, u8 *pstatus); ++ ++/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ ++//s8 sme_get_scan_type(void *pcore_data, u8 *pscan_type); ++//s8 sme_set_scan_type(void *pcore_data, u8 scan_type); ++ ++//s8 sme_get_scan_channel_list(void *pcore_data, u8 *pscan_type); ++//s8 sme_set_scan_channel_list(void *pcore_data, u8 scan_type); ++ ++ ++void sme_get_encryption_status(void *pcore_data, u8 *EncryptStatus); ++void sme_set_encryption_status(void *pcore_data, u8 EncryptStatus); ++s8 sme_add_key(void *pcore_data, ++ u32 key_index, ++ u8 key_len, ++ u8 key_type, ++ u8 *key_bssid, ++ //u8 *key_rsc, ++ u8 *ptx_tsc, ++ u8 *prx_tsc, ++ u8 *key_material); ++void sme_remove_default_key(void *pcore_data, int index); ++void sme_remove_mapping_key(void *pcore_data, u8 *pmac_addr); ++void sme_clear_all_mapping_key(void *pcore_data); ++void sme_clear_all_default_key(void *pcore_data); ++ ++ ++ ++s8 sme_set_preamble_mode(void *pcore_data, u8 mode); ++s8 sme_get_preamble_mode(void *pcore_data, u8 *mode); ++s8 sme_get_preamble_type(void *pcore_data, u8 *type); ++s8 sme_set_slottime_mode(void *pcore_data, u8 mode); ++s8 sme_get_slottime_mode(void *pcore_data, u8 *mode); ++s8 sme_get_slottime_type(void *pcore_data, u8 *type); ++s8 sme_set_txrate_policy(void *pcore_data, u8 policy); ++s8 sme_get_txrate_policy(void *pcore_data, u8 *policy); ++s8 sme_get_cwmin_value(void *pcore_data, u8 *cwmin); ++s8 sme_get_cwmax_value(void *pcore_data, u16 *cwmax); ++s8 sme_get_ms_radio_mode(void *pcore_data, u8 * pMsRadioOff); ++s8 sme_set_ms_radio_mode(void *pcore_data, u8 boMsRadioOff); ++s8 sme_get_radio_mode(void *pcore_data, psRadioOff pRadioOffData); ++s8 sme_set_radio_mode(void *pcore_data, RadioOff RadioOffData); ++ ++void sme_get_tx_power_level(void *pcore_data, u32 *TxPower); ++u8 sme_set_tx_power_level(void *pcore_data, u32 TxPower); ++void sme_get_antenna_count(void *pcore_data, u32 *AntennaCount); ++void sme_get_rx_antenna(void *pcore_data, u32 *RxAntenna); ++u8 sme_set_rx_antenna(void *pcore_data, u32 RxAntenna); ++void sme_get_tx_antenna(void *pcore_data, u32 *TxAntenna); ++s8 sme_set_tx_antenna(void *pcore_data, u32 TxAntenna); ++s8 sme_set_IBSS_chan(void *pcore_data, ChanInfo chan); ++ ++//20061108 WPS ++s8 sme_set_IE_append(void *pcore_data, PUCHAR buffer, u16 buf_len); ++ ++ ++ ++ ++//================== Local functions ====================== ++//#ifdef _HSINCHU ++//void drv_translate_rssi(); // HW RSSI bit -> NDIS RSSI representation ++//void drv_translate_bss_description(); // Local bss desc -> NDIS bss desc ++//void drv_translate_channel(u8 NetworkType, u8 ChannelNumber, u32 *freq); // channel number -> channel /freq. ++//#endif _HSINCHU ++// ++static const u32 PowerDbToMw[] = ++{ ++ 56, //mW, MAX - 0, 17.5 dbm ++ 40, //mW, MAX - 1, 16.0 dbm ++ 30, //mW, MAX - 2, 14.8 dbm ++ 20, //mW, MAX - 3, 13.0 dbm ++ 15, //mW, MAX - 4, 11.8 dbm ++ 12, //mW, MAX - 5, 10.6 dbm ++ 9, //mW, MAX - 6, 9.4 dbm ++ 7, //mW, MAX - 7, 8.3 dbm ++ 5, //mW, MAX - 8, 6.4 dbm ++ 4, //mW, MAX - 9, 5.3 dbm ++ 3, //mW, MAX - 10, 4.0 dbm ++ 2, //mW, MAX - 11, ? dbm ++ 2, //mW, MAX - 12, ? dbm ++ 2, //mW, MAX - 13, ? dbm ++ 2, //mW, MAX - 14, ? dbm ++ 2, //mW, MAX - 15, ? dbm ++ 2, //mW, MAX - 16, ? dbm ++ 2, //mW, MAX - 17, ? dbm ++ 2, //mW, MAX - 18, ? dbm ++ 1, //mW, MAX - 19, ? dbm ++ 1, //mW, MAX - 20, ? dbm ++ 1, //mW, MAX - 21, ? dbm ++ 1, //mW, MAX - 22, ? dbm ++ 1, //mW, MAX - 23, ? dbm ++ 1, //mW, MAX - 24, ? dbm ++ 1, //mW, MAX - 25, ? dbm ++ 1, //mW, MAX - 26, ? dbm ++ 1, //mW, MAX - 27, ? dbm ++ 1, //mW, MAX - 28, ? dbm ++ 1, //mW, MAX - 29, ? dbm ++ 1, //mW, MAX - 30, ? dbm ++ 1 //mW, MAX - 31, ? dbm ++}; ++ ++ ++ ++ ++ ++#endif /* __SME_API_H__ */ ++ ++ +diff --git a/drivers/staging/winbond/sme_s.h b/drivers/staging/winbond/sme_s.h +new file mode 100644 +index 0000000..dfd2fbc +--- /dev/null ++++ b/drivers/staging/winbond/sme_s.h +@@ -0,0 +1,228 @@ ++// ++// SME_S.H - ++// SME task global CONSTANTS, STRUCTURES, variables ++// ++ ++////////////////////////////////////////////////////////////////////////// ++//define the msg type of SME module ++// 0x00~0x1F : MSG from GUI dispatch ++// 0x20~0x3F : MSG from MLME ++// 0x40~0x5F : MSG from SCAN ++// 0x60~0x6F : MSG from TX/RX ++// 0x70~0x7F : MSG from ROAMING ++// 0x80~0x8F : MSG from ISR ++// 0x90 : MSG TimeOut ++ ++// from GUI ++#define SMEMSG_SCAN_REQ 0x01 ++//#define SMEMSG_PASSIVE_SCAN_REQ 0x02 ++#define SMEMSG_JOIN_REQ 0x03 ++#define SMEMSG_START_IBSS 0x04 ++#define SMEMSG_DISCONNECT_REQ 0x05 ++#define SMEMSG_AUTHEN_REQ 0x06 ++#define SMEMSG_DEAUTHEN_REQ 0x07 ++#define SMEMSG_ASSOC_REQ 0x08 ++#define SMEMSG_REASSOC_REQ 0x09 ++#define SMEMSG_DISASSOC_REQ 0x0a ++#define SMEMSG_POWERSAVE_REQ 0x0b ++ ++ ++// from MLME ++#define SMEMSG_AUTHEN_CFM 0x21 ++#define SMEMSG_AUTHEN_IND 0x22 ++#define SMEMSG_ASSOC_CFM 0x23 ++#define SMEMSG_DEAUTHEN_IND 0x24 ++#define SMEMSG_DISASSOC_IND 0x25 ++// from SCAN ++#define SMEMSG_SCAN_CFM 0x41 ++#define SMEMSG_START_IBSS_CFM 0x42 ++// from MTO, function call to set SME parameters ++ ++// 0x60~0x6F : MSG from TX/RX ++//#define SMEMSG_IBSS_JOIN_UPDATE_BSSID 0x61 ++#define SMEMSG_COUNTERMEASURE_MICFAIL_TIMEOUT 0x62 ++#define SMEMSG_COUNTERMEASURE_BLOCK_TIMEOUT 0x63 ++// from ROAMING ++#define SMEMSG_HANDOVER_JOIN_REQ 0x71 ++#define SMEMSG_END_ROAMING 0x72 ++#define SMEMSG_SCAN_JOIN_REQ 0x73 ++// from ISR ++#define SMEMSG_TSF_SYNC_IND 0x81 ++// from TimeOut ++#define SMEMSG_TIMEOUT 0x91 ++ ++ ++ ++#define MAX_PMKID_Accunt 16 ++//@added by ws 04/22/05 ++#define Cipher_Disabled 0 ++#define Cipher_Wep 1 ++#define Cipher_Tkip 2 ++#define Cipher_Ccmp 4 ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++//Constants ++ ++/////////////////////////////////////////////////////////////////////////// ++//Global data structures ++ ++#define NUMOFWEPENTRIES 64 ++ ++typedef enum _WEPKeyMode ++{ ++ WEPKEY_DISABLED = 0, ++ WEPKEY_64 = 1, ++ WEPKEY_128 = 2 ++ ++} WEPKEYMODE, *pWEPKEYMODE; ++ ++#ifdef _WPA2_ ++ ++typedef struct _BSSInfo ++{ ++ u8 PreAuthBssID[6]; ++ PMKID pmkid_value; ++}BSSID_Info; ++ ++typedef struct _PMKID_Table //added by ws 05/05/04 ++{ ++ u32 Length; ++ u32 BSSIDInfoCount; ++ BSSID_Info BSSIDInfo[16]; ++ ++} PMKID_Table; ++ ++#endif //end def _WPA2_ ++ ++#define MAX_BASIC_RATE_SET 15 ++#define MAX_OPT_RATE_SET MAX_BASIC_RATE_SET ++ ++ ++typedef struct _SME_PARAMETERS ++{ ++ u16 wState; ++ u8 boDUTmode; ++ u8 bDesiredPowerSave; ++ ++ // SME timer and timeout value ++ //NDIS_MINIPORT_TIMER nTimer; ++ OS_TIMER nTimer; ++ ++ u8 boInTimerHandler; ++ u8 boAuthRetryActive; ++ u8 reserved_0[2]; ++ ++ u32 AuthenRetryTimerVal; // NOTE: Assoc don't fail timeout ++ u32 JoinFailTimerVal; // 10*Beacon-Interval ++ ++ //Rates ++ u8 BSSBasicRateSet[(MAX_BASIC_RATE_SET + 3) & ~0x03 ]; // BSS basic rate set ++ u8 OperationalRateSet[(MAX_OPT_RATE_SET + 3) & ~0x03 ]; // Operational rate set ++ ++ u8 NumOfBSSBasicRate; ++ u8 NumOfOperationalRate; ++ u8 reserved_1[2]; ++ ++ u32 BasicRateBitmap; ++ u32 OpRateBitmap; ++ ++ // System parameters Set by GUI ++ //-------------------- start IBSS parameter ---------------------------// ++ u32 boStartIBSS; //Start IBSS toggle ++ ++ u16 wBeaconPeriod; ++ u16 wATIM_Window; ++ ++ ChanInfo IbssChan; // 2B //channel setting when start IBSS ++ u8 reserved_2[2]; ++ ++ // Join related ++ u16 wDesiredJoinBSS; // BSS index which desire to join ++ u8 boJoinReq; //Join request toggle ++ u8 bDesiredBSSType; //for Join request ++ ++ u16 wCapabilityInfo; // Used when invoking the MLME_Associate_request(). ++ u16 wNonERPcapabilityInfo; ++ ++ struct SSID_Element sDesiredSSID; // 34 B ++ u8 reserved_3[2]; ++ ++ u8 abDesiredBSSID[MAC_ADDR_LENGTH + 2]; ++ ++ u8 bJoinScanCount; // the time of scan-join action need to do ++ u8 bDesiredAuthMode; // AUTH_OPEN_SYSTEM or AUTH_SHARED_KEY ++ u8 reserved_4[2]; ++ ++ // Encryption parameters ++ u8 _dot11PrivacyInvoked; ++ u8 _dot11PrivacyOptionImplemented; ++ u8 reserved_5[2]; ++ ++ //@ ws added ++ u8 DesiredEncrypt; ++ u8 encrypt_status; //ENCRYPT_DISABLE, ENCRYPT_WEP, ENCRYPT_WEP_NOKEY, ENCRYPT_TKIP, ... ++ u8 key_length; ++ u8 pairwise_key_ok; ++ ++ u8 group_key_ok; ++ u8 wpa_ok; // indicate the control port of 802.1x is open or close ++ u8 pairwise_key_type; ++ u8 group_key_type; ++ ++ u32 _dot11WEPDefaultKeyID; ++ ++ u8 tx_mic_key[8]; // TODO: 0627 kevin-TKIP ++ u8 rx_mic_key[8]; // TODO: 0627 kevin-TKIP ++ u8 group_tx_mic_key[8]; ++ u8 group_rx_mic_key[8]; ++ ++// #ifdef _WPA_ ++ u8 AssocReqVarIE[200]; ++ u8 AssocRespVarIE[200]; ++ ++ u16 AssocReqVarLen; ++ u16 AssocRespVarLen; ++ u8 boReassoc; //use assoc. or reassoc. ++ u8 reserved_6[3]; ++ u16 AssocRespCapability; ++ u16 AssocRespStatus; ++// #endif ++ ++ #ifdef _WPA2_ ++ u8 PmkIdTable[256]; ++ u32 PmkidTableIndex; ++ #endif //end def _WPA2_ ++ ++} SME_PARAMETERS, *PSME_PARAMETERS; ++ ++#define psSME (&(Adapter->sSmePara)) ++ ++#define wSMEGetCurrentSTAState(Adapter) ((u16)(Adapter)->sSmePara.wState) ++ ++ ++ ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++// SmeModule.h ++// Define the related definitions of SME module ++// history -- 01/14/03' created ++// ++//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++//Define the state of SME module ++#define DISABLED 0 ++#define INIT_SCAN 1 ++#define SCAN_READY 2 ++#define START_IBSS 3 ++#define JOIN_PENDING 4 ++#define JOIN_CFM 5 ++#define AUTHENTICATE_PENDING 6 ++#define AUTHENTICATED 7 ++#define CONNECTED 8 ++//#define EAP_STARTING 9 ++//#define EAPOL_AUTHEN_PENDING 10 ++//#define SECURE_CONNECTED 11 ++ ++ ++// Static function ++ +diff --git a/drivers/staging/winbond/wb35_ver.h b/drivers/staging/winbond/wb35_ver.h +new file mode 100644 +index 0000000..2433bc0 +--- /dev/null ++++ b/drivers/staging/winbond/wb35_ver.h +@@ -0,0 +1,30 @@ ++// ++// Only define one of follow ++// ++ ++#ifdef WB_WIN ++ #define VER_FILEVERSION 1,00,47,00 ++ #define VER_FILEVERSION_STR "1.00.47.00" ++ #define WB32_DRIVER_MAJOR_VERSION 0x0100 ++ #define WB32_DRIVER_MINOR_VERSION 0x4700 ++#endif ++ ++#ifdef WB_CE ++ #define VER_FILEVERSION 2,00,47,00 ++ #define VER_FILEVERSION_STR "2.00.47.00" ++ #define WB32_DRIVER_MAJOR_VERSION 0x0200 ++ #define WB32_DRIVER_MINOR_VERSION 0x4700 ++#endif ++ ++#ifdef WB_LINUX ++ #define VER_FILEVERSION 3,00,47,00 ++ #define VER_FILEVERSION_STR "3.00.47.00" ++ #define WB32_DRIVER_MAJOR_VERSION 0x0300 ++ #define WB32_DRIVER_MINOR_VERSION 0x4700 ++#endif ++ ++ ++ ++ ++ ++ +diff --git a/drivers/staging/winbond/wbhal.c b/drivers/staging/winbond/wbhal.c +new file mode 100644 +index 0000000..daf4422 +--- /dev/null ++++ b/drivers/staging/winbond/wbhal.c +@@ -0,0 +1,878 @@ ++#include "os_common.h" ++ ++void hal_get_ethernet_address( phw_data_t pHwData, PUCHAR current_address ) ++{ ++ if( pHwData->SurpriseRemove ) return; ++ ++ memcpy( current_address, pHwData->CurrentMacAddress, ETH_LENGTH_OF_ADDRESS ); ++} ++ ++void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address ) ++{ ++ u32 ltmp[2]; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ memcpy( pHwData->CurrentMacAddress, current_address, ETH_LENGTH_OF_ADDRESS ); ++ ++ ltmp[0]= cpu_to_le32( *(PULONG)pHwData->CurrentMacAddress ); ++ ltmp[1]= cpu_to_le32( *(PULONG)(pHwData->CurrentMacAddress + 4) ) & 0xffff; ++ ++ Wb35Reg_BurstWrite( pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT ); ++} ++ ++void hal_get_permanent_address( phw_data_t pHwData, PUCHAR pethernet_address ) ++{ ++ if( pHwData->SurpriseRemove ) return; ++ ++ memcpy( pethernet_address, pHwData->PermanentMacAddress, 6 ); ++} ++ ++u8 hal_init_hardware(phw_data_t pHwData, PWB32_ADAPTER Adapter) ++{ ++ u16 SoftwareSet; ++ pHwData->Adapter = Adapter; ++ ++ // Initial the variable ++ pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME; // Setting Rx maximum MSDU life time ++ pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; // Setting default fragment threshold ++ ++ if (WbUsb_initial(pHwData)) { ++ pHwData->InitialResource = 1; ++ if( Wb35Reg_initial(pHwData)) { ++ pHwData->InitialResource = 2; ++ if (Wb35Tx_initial(pHwData)) { ++ pHwData->InitialResource = 3; ++ if (Wb35Rx_initial(pHwData)) { ++ pHwData->InitialResource = 4; ++ OS_TIMER_INITIAL( &pHwData->LEDTimer, hal_led_control, pHwData ); ++ OS_TIMER_SET( &pHwData->LEDTimer, 1000 ); // 20060623 ++ ++ // ++ // For restrict to vendor's hardware ++ // ++ SoftwareSet = hal_software_set( pHwData ); ++ ++ #ifdef Vendor2 ++ // Try to make sure the EEPROM contain ++ SoftwareSet >>= 8; ++ if( SoftwareSet != 0x82 ) ++ return FALSE; ++ #endif ++ ++ Wb35Rx_start( pHwData ); ++ Wb35Tx_EP2VM_start( pHwData ); ++ ++ return TRUE; ++ } ++ } ++ } ++ } ++ ++ pHwData->SurpriseRemove = 1; ++ return FALSE; ++} ++ ++ ++void hal_halt(phw_data_t pHwData, void *ppa_data) ++{ ++ switch( pHwData->InitialResource ) ++ { ++ case 4: ++ case 3: OS_TIMER_CANCEL( &pHwData->LEDTimer, &cancel ); ++ OS_SLEEP(100000); // Wait for Timer DPC exit 940623.2 ++ Wb35Rx_destroy( pHwData ); // Release the Rx ++ case 2: Wb35Tx_destroy( pHwData ); // Release the Tx ++ case 1: Wb35Reg_destroy( pHwData ); // Release the Wb35 Regisster resources ++ WbUsb_destroy( pHwData );// Release the WbUsb ++ } ++} ++ ++//--------------------------------------------------------------------------------------------------- ++void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates, ++ u8 length, unsigned char basic_rate_set) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 tmp, tmp1; ++ u8 Rate[12]={ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; ++ u8 SupportedRate[16]; ++ u8 i, j, k, Count1, Count2, Byte; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ if (basic_rate_set) { ++ pWb35Reg->M28_MacControl &= ~0x000fff00; ++ tmp1 = 0x00000100; ++ } else { ++ pWb35Reg->M28_MacControl &= ~0xfff00000; ++ tmp1 = 0x00100000; ++ } ++ ++ tmp = 0; ++ for (i=0; iM28_MacControl |= tmp; ++ Wb35Reg_Write( pHwData, 0x0828, pWb35Reg->M28_MacControl ); ++ ++ // 930206.2.c M78 setting ++ j = k = Count1 = Count2 = 0; ++ memset( SupportedRate, 0, 16 ); ++ tmp = 0x00100000; ++ tmp1 = 0x00000100; ++ for (i=0; i<12; i++) { // Get the supported rate ++ if (tmp & pWb35Reg->M28_MacControl) { ++ SupportedRate[j] = Rate[i]; ++ ++ if (tmp1 & pWb35Reg->M28_MacControl) ++ SupportedRate[j] |= 0x80; ++ ++ if (k) ++ Count2++; ++ else ++ Count1++; ++ ++ j++; ++ } ++ ++ if (i==4 && k==0) { ++ if( !(pWb35Reg->M28_MacControl & 0x000ff000) ) // if basic rate in 11g domain) ++ { ++ k = 1; ++ j = 8; ++ } ++ } ++ ++ tmp <<= 1; ++ tmp1 <<= 1; ++ } ++ ++ // Fill data into support rate until buffer full ++ //---20060926 add by anson's endian ++ for (i=0; i<4; i++) ++ *(PULONG)(SupportedRate+(i<<2)) = cpu_to_le32( *(PULONG)(SupportedRate+(i<<2)) ); ++ //--- end 20060926 add by anson's endian ++ Wb35Reg_BurstWrite( pHwData,0x087c, (PULONG)SupportedRate, 4, AUTO_INCREMENT ); ++ pWb35Reg->M7C_MacControl = ((PULONG)SupportedRate)[0]; ++ pWb35Reg->M80_MacControl = ((PULONG)SupportedRate)[1]; ++ pWb35Reg->M84_MacControl = ((PULONG)SupportedRate)[2]; ++ pWb35Reg->M88_MacControl = ((PULONG)SupportedRate)[3]; ++ ++ // Fill length ++ tmp = Count1<<28 | Count2<<24; ++ pWb35Reg->M78_ERPInformation &= ~0xff000000; ++ pWb35Reg->M78_ERPInformation |= tmp; ++ Wb35Reg_Write( pHwData, 0x0878, pWb35Reg->M78_ERPInformation ); ++} ++ ++ ++//--------------------------------------------------------------------------------------------------- ++void hal_set_beacon_period( phw_data_t pHwData, u16 beacon_period ) ++{ ++ u32 tmp; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ pHwData->BeaconPeriod = beacon_period; ++ tmp = pHwData->BeaconPeriod << 16; ++ tmp |= pHwData->ProbeDelay; ++ Wb35Reg_Write( pHwData, 0x0848, tmp ); ++} ++ ++ ++void hal_set_current_channel_ex( phw_data_t pHwData, ChanInfo channel ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) ++ return; ++ ++ printk("Going to channel: %d/%d\n", channel.band, channel.ChanNo); ++ ++ RFSynthesizer_SwitchingChannel( pHwData, channel );// Switch channel ++ pHwData->Channel = channel.ChanNo; ++ pHwData->band = channel.band; ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("Set channel is %d, band =%d\n", pHwData->Channel, pHwData->band)); ++ #endif ++ pWb35Reg->M28_MacControl &= ~0xff; // Clean channel information field ++ pWb35Reg->M28_MacControl |= channel.ChanNo; ++ Wb35Reg_WriteWithCallbackValue( pHwData, 0x0828, pWb35Reg->M28_MacControl, ++ (PCHAR)&channel, sizeof(ChanInfo)); ++} ++//--------------------------------------------------------------------------------------------------- ++void hal_set_current_channel( phw_data_t pHwData, ChanInfo channel ) ++{ ++ hal_set_current_channel_ex( pHwData, channel ); ++} ++//--------------------------------------------------------------------------------------------------- ++void hal_get_current_channel( phw_data_t pHwData, ChanInfo *channel ) ++{ ++ channel->ChanNo = pHwData->Channel; ++ channel->band = pHwData->band; ++} ++//--------------------------------------------------------------------------------------------------- ++void hal_set_accept_broadcast( phw_data_t pHwData, u8 enable ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ pWb35Reg->M00_MacControl &= ~0x02000000;//The HW value ++ ++ if (enable) ++ pWb35Reg->M00_MacControl |= 0x02000000;//The HW value ++ ++ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl ); ++} ++ ++//for wep key error detection, we need to accept broadcast packets to be received temporary. ++void hal_set_accept_promiscuous( phw_data_t pHwData, u8 enable) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if (pHwData->SurpriseRemove) return; ++ if (enable) { ++ pWb35Reg->M00_MacControl |= 0x00400000; ++ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl ); ++ } else { ++ pWb35Reg->M00_MacControl&=~0x00400000; ++ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl ); ++ } ++} ++ ++void hal_set_accept_multicast( phw_data_t pHwData, u8 enable ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ pWb35Reg->M00_MacControl &= ~0x01000000;//The HW value ++ if (enable) pWb35Reg->M00_MacControl |= 0x01000000;//The HW value ++ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl ); ++} ++ ++void hal_set_accept_beacon( phw_data_t pHwData, u8 enable ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ // 20040108 debug ++ if( !enable )//Due to SME and MLME are not suitable for 35 ++ return; ++ ++ pWb35Reg->M00_MacControl &= ~0x04000000;//The HW value ++ if( enable ) ++ pWb35Reg->M00_MacControl |= 0x04000000;//The HW value ++ ++ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl ); ++} ++//--------------------------------------------------------------------------------------------------- ++void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u8 Byte, Bit; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ //Erases and refills the card multicast registers. Used when an address ++ // has been deleted and all bits must be recomputed. ++ pWb35Reg->M04_MulticastAddress1 = 0; ++ pWb35Reg->M08_MulticastAddress2 = 0; ++ ++ while( number ) ++ { ++ number--; ++ CardGetMulticastBit( (address+(number*ETH_LENGTH_OF_ADDRESS)), &Byte, &Bit); ++ pWb35Reg->Multicast[Byte] |= Bit; ++ } ++ ++ // Updating register ++ Wb35Reg_BurstWrite( pHwData, 0x0804, (PULONG)pWb35Reg->Multicast, 2, AUTO_INCREMENT ); ++} ++//--------------------------------------------------------------------------------------------------- ++u8 hal_get_accept_beacon( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return 0; ++ ++ if( pWb35Reg->M00_MacControl & 0x04000000 ) ++ return 1; ++ else ++ return 0; ++} ++ ++unsigned char hal_reset_hardware( phw_data_t pHwData, void* ppa ) ++{ ++ // Not implement yet ++ return TRUE; ++} ++ ++void hal_stop( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ pHwData->Wb35Rx.rx_halt = 1; ++ Wb35Rx_stop( pHwData ); ++ ++ pHwData->Wb35Tx.tx_halt = 1; ++ Wb35Tx_stop( pHwData ); ++ ++ pWb35Reg->D00_DmaControl &= ~0xc0000000;//Tx Off, Rx Off ++ Wb35Reg_Write( pHwData, 0x0400, pWb35Reg->D00_DmaControl ); ++ ++ WbUsb_Stop( pHwData ); // 20051230 Add.4 ++} ++ ++unsigned char hal_idle(phw_data_t pHwData) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ PWBUSB pWbUsb = &pHwData->WbUsb; ++ ++ if( !pHwData->SurpriseRemove && ( pWbUsb->DetectCount || pWb35Reg->EP0vm_state!=VM_STOP ) ) ++ return FALSE; ++ ++ return TRUE; ++} ++//--------------------------------------------------------------------------------------------------- ++void hal_set_cwmin( phw_data_t pHwData, u8 cwin_min ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ pHwData->cwmin = cwin_min; ++ pWb35Reg->M2C_MacControl &= ~0x7c00; //bit 10 ~ 14 ++ pWb35Reg->M2C_MacControl |= (pHwData->cwmin<<10); ++ Wb35Reg_Write( pHwData, 0x082c, pWb35Reg->M2C_MacControl ); ++} ++ ++s32 hal_get_rssi( phw_data_t pHwData, u32 *HalRssiArry, u8 Count ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ R01_DESCRIPTOR r01; ++ s32 ltmp = 0, tmp; ++ u8 i; ++ ++ if( pHwData->SurpriseRemove ) return -200; ++ if( Count > MAX_ACC_RSSI_COUNT ) // Because the TS may use this funtion ++ Count = MAX_ACC_RSSI_COUNT; ++ ++ // RSSI = C1 + C2 * (agc_state[7:0] + offset_map(lna_state[1:0])) ++ // C1 = -195, C2 = 0.66 = 85/128 ++ for (i=0; iLNAValue[r01.R01_LNA_state]) * 85 ) >>7 ) - 195; ++ ltmp += tmp; ++ } ++ ltmp /= Count; ++ if( pHwData->phy_type == RF_AIROHA_2230 ) ltmp -= 5; // 10; ++ if( pHwData->phy_type == RF_AIROHA_2230S ) ltmp -= 5; // 10; 20060420 Add this ++ ++ //if( ltmp < -200 ) ltmp = -200; ++ if( ltmp < -110 ) ltmp = -110;// 1.0.24.0 For NJRC ++ ++ return ltmp; ++} ++//---------------------------------------------------------------------------------------------------- ++s32 hal_get_rssi_bss( phw_data_t pHwData, u16 idx, u8 Count ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ R01_DESCRIPTOR r01; ++ s32 ltmp = 0, tmp; ++ u8 i, j; ++ PADAPTER Adapter = pHwData->Adapter; ++// u32 *HalRssiArry = psBSS(idx)->HalRssi; ++ ++ if( pHwData->SurpriseRemove ) return -200; ++ if( Count > MAX_ACC_RSSI_COUNT ) // Because the TS may use this funtion ++ Count = MAX_ACC_RSSI_COUNT; ++ ++ // RSSI = C1 + C2 * (agc_state[7:0] + offset_map(lna_state[1:0])) ++ // C1 = -195, C2 = 0.66 = 85/128 ++#if 0 ++ for (i=0; iLNAValue[r01.R01_LNA_state]) * 85 ) >>7 ) - 195; ++ ltmp += tmp; ++ } ++#else ++ if (psBSS(idx)->HalRssiIndex == 0) ++ psBSS(idx)->HalRssiIndex = MAX_ACC_RSSI_COUNT; ++ j = (u8)psBSS(idx)->HalRssiIndex-1; ++ ++ for (i=0; iHalRssi[j]; ++ tmp = ((( r01.R01_AGC_state + pWb35Reg->LNAValue[r01.R01_LNA_state]) * 85 ) >>7 ) - 195; ++ ltmp += tmp; ++ if (j == 0) ++ { ++ j = MAX_ACC_RSSI_COUNT; ++ } ++ j--; ++ } ++#endif ++ ltmp /= Count; ++ if( pHwData->phy_type == RF_AIROHA_2230 ) ltmp -= 5; // 10; ++ if( pHwData->phy_type == RF_AIROHA_2230S ) ltmp -= 5; // 10; 20060420 Add this ++ ++ //if( ltmp < -200 ) ltmp = -200; ++ if( ltmp < -110 ) ltmp = -110;// 1.0.24.0 For NJRC ++ ++ return ltmp; ++} ++ ++//--------------------------------------------------------------------------- ++void hal_led_control_1a( phw_data_t pHwData ) ++{ ++ hal_led_control( NULL, pHwData, NULL, NULL ); ++} ++ ++void hal_led_control( void* S1, phw_data_t pHwData, void* S3, void* S4 ) ++{ ++ PADAPTER Adapter = pHwData->Adapter; ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT; ++ u8 LEDgray[20] = { 0,3,4,6,8,10,11,12,13,14,15,14,13,12,11,10,8,6,4,2 }; ++ u8 LEDgray2[30] = { 7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,15,14,13,12,11,10,9,8 }; ++ u32 TimeInterval = 500, ltmp, ltmp2; ++ ltmp=0; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ if( pHwData->LED_control ) { ++ ltmp2 = pHwData->LED_control & 0xff; ++ if( ltmp2 == 5 ) // 5 is WPS mode ++ { ++ TimeInterval = 100; ++ ltmp2 = (pHwData->LED_control>>8) & 0xff; ++ switch( ltmp2 ) ++ { ++ case 1: // [0.2 On][0.1 Off]... ++ pHwData->LED_Blinking %= 3; ++ ltmp = 0x1010; // Led 1 & 0 Green and Red ++ if( pHwData->LED_Blinking == 2 ) // Turn off ++ ltmp = 0; ++ break; ++ case 2: // [0.1 On][0.1 Off]... ++ pHwData->LED_Blinking %= 2; ++ ltmp = 0x0010; // Led 0 red color ++ if( pHwData->LED_Blinking ) // Turn off ++ ltmp = 0; ++ break; ++ case 3: // [0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.5 Off]... ++ pHwData->LED_Blinking %= 15; ++ ltmp = 0x0010; // Led 0 red color ++ if( (pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking%2) ) // Turn off 0.6 sec ++ ltmp = 0; ++ break; ++ case 4: // [300 On][ off ] ++ ltmp = 0x1000; // Led 1 Green color ++ if( pHwData->LED_Blinking >= 3000 ) ++ ltmp = 0; // led maybe on after 300sec * 32bit counter overlap. ++ break; ++ } ++ pHwData->LED_Blinking++; ++ ++ pWb35Reg->U1BC_LEDConfigure = ltmp; ++ if( LEDSet != 7 ) // Only 111 mode has 2 LEDs on PCB. ++ { ++ pWb35Reg->U1BC_LEDConfigure |= (ltmp &0xff)<<8; // Copy LED result to each LED control register ++ pWb35Reg->U1BC_LEDConfigure |= (ltmp &0xff00)>>8; ++ } ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); ++ } ++ } ++ else if( pHwData->CurrentRadioSw || pHwData->CurrentRadioHw ) // If radio off ++ { ++ if( pWb35Reg->U1BC_LEDConfigure & 0x1010 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x1010; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); ++ } ++ } ++ else ++ { ++ switch( LEDSet ) ++ { ++ case 4: // [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing ++ if( !pHwData->LED_LinkOn ) // Blink only if not Link On ++ { ++ // Blinking if scanning is on progress ++ if( pHwData->LED_Scanning ) ++ { ++ if( pHwData->LED_Blinking == 0 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 On ++ pHwData->LED_Blinking = 1; ++ TimeInterval = 300; ++ } ++ else ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off ++ pHwData->LED_Blinking = 0; ++ TimeInterval = 300; ++ } ++ } ++ else ++ { ++ //Turn Off LED_0 ++ if( pWb35Reg->U1BC_LEDConfigure & 0x10 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off ++ } ++ } ++ } ++ else ++ { ++ // Turn On LED_0 ++ if( (pWb35Reg->U1BC_LEDConfigure & 0x10) == 0 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off ++ } ++ } ++ break; ++ ++ case 6: // [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing ++ if( !pHwData->LED_LinkOn ) // Blink only if not Link On ++ { ++ // Blinking if scanning is on progress ++ if( pHwData->LED_Scanning ) ++ { ++ if( pHwData->LED_Blinking == 0 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0xf; ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 On ++ pHwData->LED_Blinking = 1; ++ TimeInterval = 300; ++ } ++ else ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x1f; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off ++ pHwData->LED_Blinking = 0; ++ TimeInterval = 300; ++ } ++ } ++ else ++ { ++ // 20060901 Gray blinking if in disconnect state and not scanning ++ ltmp = pWb35Reg->U1BC_LEDConfigure; ++ pWb35Reg->U1BC_LEDConfigure &= ~0x1f; ++ if( LEDgray2[(pHwData->LED_Blinking%30)] ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ pWb35Reg->U1BC_LEDConfigure |= LEDgray2[ (pHwData->LED_Blinking%30) ]; ++ } ++ pHwData->LED_Blinking++; ++ if( pWb35Reg->U1BC_LEDConfigure != ltmp ) ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off ++ TimeInterval = 100; ++ } ++ } ++ else ++ { ++ // Turn On LED_0 ++ if( (pWb35Reg->U1BC_LEDConfigure & 0x10) == 0 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off ++ } ++ } ++ break; ++ ++ case 5: // [101] Only 1 Led be placed on PCB and use LED_1 for showing ++ if( !pHwData->LED_LinkOn ) // Blink only if not Link On ++ { ++ // Blinking if scanning is on progress ++ if( pHwData->LED_Scanning ) ++ { ++ if( pHwData->LED_Blinking == 0 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x1000; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 On ++ pHwData->LED_Blinking = 1; ++ TimeInterval = 300; ++ } ++ else ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x1000; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 Off ++ pHwData->LED_Blinking = 0; ++ TimeInterval = 300; ++ } ++ } ++ else ++ { ++ //Turn Off LED_1 ++ if( pWb35Reg->U1BC_LEDConfigure & 0x1000 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x1000; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 Off ++ } ++ } ++ } ++ else ++ { ++ // Is transmitting/receiving ?? ++ if( (OS_CURRENT_RX_BYTE( Adapter ) != pHwData->RxByteCountLast ) || ++ (OS_CURRENT_TX_BYTE( Adapter ) != pHwData->TxByteCountLast ) ) ++ { ++ if( (pWb35Reg->U1BC_LEDConfigure & 0x3000) != 0x3000 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x3000; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 On ++ } ++ ++ // Update variable ++ pHwData->RxByteCountLast = OS_CURRENT_RX_BYTE( Adapter ); ++ pHwData->TxByteCountLast = OS_CURRENT_TX_BYTE( Adapter ); ++ TimeInterval = 200; ++ } ++ else ++ { ++ // Turn On LED_1 and blinking if transmitting/receiving ++ if( (pWb35Reg->U1BC_LEDConfigure & 0x3000) != 0x1000 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x3000; ++ pWb35Reg->U1BC_LEDConfigure |= 0x1000; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 On ++ } ++ } ++ } ++ break; ++ ++ default: // Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active ++ if( (pWb35Reg->U1BC_LEDConfigure & 0x3000) != 0x3000 ) ++ { ++ pWb35Reg->U1BC_LEDConfigure |= 0x3000;// LED_1 is always on and event enable ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); ++ } ++ ++ if( pHwData->LED_Blinking ) ++ { ++ // Gray blinking ++ pWb35Reg->U1BC_LEDConfigure &= ~0x0f; ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ pWb35Reg->U1BC_LEDConfigure |= LEDgray[ (pHwData->LED_Blinking-1)%20 ]; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); ++ ++ pHwData->LED_Blinking += 2; ++ if( pHwData->LED_Blinking < 40 ) ++ TimeInterval = 100; ++ else ++ { ++ pHwData->LED_Blinking = 0; // Stop blinking ++ pWb35Reg->U1BC_LEDConfigure &= ~0x0f; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); ++ } ++ break; ++ } ++ ++ if( pHwData->LED_LinkOn ) ++ { ++ if( !(pWb35Reg->U1BC_LEDConfigure & 0x10) ) // Check the LED_0 ++ { ++ //Try to turn ON LED_0 after gray blinking ++ pWb35Reg->U1BC_LEDConfigure |= 0x10; ++ pHwData->LED_Blinking = 1; //Start blinking ++ TimeInterval = 50; ++ } ++ } ++ else ++ { ++ if( pWb35Reg->U1BC_LEDConfigure & 0x10 ) // Check the LED_0 ++ { ++ pWb35Reg->U1BC_LEDConfigure &= ~0x10; ++ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); ++ } ++ } ++ break; ++ } ++ ++ //20060828.1 Active send null packet to avoid AP disconnect ++ if( pHwData->LED_LinkOn ) ++ { ++ pHwData->NullPacketCount += TimeInterval; ++ if( pHwData->NullPacketCount >= DEFAULT_NULL_PACKET_COUNT ) ++ { ++ pHwData->NullPacketCount = 0; ++ } ++ } ++ } ++ ++ pHwData->time_count += TimeInterval; ++ Wb35Tx_CurrentTime( pHwData, pHwData->time_count ); // 20060928 add ++ OS_TIMER_SET( &pHwData->LEDTimer, TimeInterval ); // 20060623.1 ++} ++ ++ ++void hal_set_phy_type( phw_data_t pHwData, u8 PhyType ) ++{ ++ pHwData->phy_type = PhyType; ++} ++ ++void hal_get_phy_type( phw_data_t pHwData, u8 *PhyType ) ++{ ++ *PhyType = pHwData->phy_type; ++} ++ ++void hal_reset_counter( phw_data_t pHwData ) ++{ ++ pHwData->dto_tx_retry_count = 0; ++ pHwData->dto_tx_frag_count = 0; ++ memset( pHwData->tx_retry_count, 0, 8); ++} ++ ++void hal_set_radio_mode( phw_data_t pHwData, unsigned char radio_off) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return; ++ ++ if (radio_off) //disable Baseband receive off ++ { ++ pHwData->CurrentRadioSw = 1; // off ++ pWb35Reg->M24_MacControl &= 0xffffffbf; ++ } ++ else ++ { ++ pHwData->CurrentRadioSw = 0; // on ++ pWb35Reg->M24_MacControl |= 0x00000040; ++ } ++ Wb35Reg_Write( pHwData, 0x0824, pWb35Reg->M24_MacControl ); ++} ++ ++u8 hal_get_antenna_number( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if ((pWb35Reg->BB2C & BIT(11)) == 0) ++ return 0; ++ else ++ return 1; ++} ++ ++void hal_set_antenna_number( phw_data_t pHwData, u8 number ) ++{ ++ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if (number == 1) { ++ pWb35Reg->BB2C |= BIT(11); ++ } else { ++ pWb35Reg->BB2C &= ~BIT(11); ++ } ++ Wb35Reg_Write( pHwData, 0x102c, pWb35Reg->BB2C ); ++#ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("Current antenna number : %d\n", number)); ++#endif ++} ++ ++//---------------------------------------------------------------------------------------------------- ++//0 : radio on; 1: radio off ++u8 hal_get_hw_radio_off( phw_data_t pHwData ) ++{ ++ PWB35REG pWb35Reg = &pHwData->Wb35Reg; ++ ++ if( pHwData->SurpriseRemove ) return 1; ++ ++ //read the bit16 of register U1B0 ++ Wb35Reg_Read( pHwData, 0x3b0, &pWb35Reg->U1B0 ); ++ if ((pWb35Reg->U1B0 & 0x00010000)) { ++ pHwData->CurrentRadioHw = 1; ++ return 1; ++ } else { ++ pHwData->CurrentRadioHw = 0; ++ return 0; ++ } ++} ++ ++unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, PULONG pValue ) ++{ ++ if( number < 0x1000 ) ++ number += 0x1000; ++ return Wb35Reg_ReadSync( pHwData, number, pValue ); ++} ++ ++unsigned char hal_set_dxx_reg( phw_data_t pHwData, u16 number, u32 value ) ++{ ++ unsigned char ret; ++ ++ if( number < 0x1000 ) ++ number += 0x1000; ++ ret = Wb35Reg_WriteSync( pHwData, number, value ); ++ return ret; ++} ++ ++void hal_scan_status_indicate(phw_data_t pHwData, unsigned char IsOnProgress) ++{ ++ if( pHwData->SurpriseRemove ) return; ++ pHwData->LED_Scanning = IsOnProgress ? 1 : 0; ++} ++ ++void hal_system_power_change(phw_data_t pHwData, u32 PowerState) ++{ ++ if( PowerState != 0 ) ++ { ++ pHwData->SurpriseRemove = 1; ++ if( pHwData->WbUsb.IsUsb20 ) ++ hal_stop( pHwData ); ++ } ++ else ++ { ++ if( !pHwData->WbUsb.IsUsb20 ) ++ hal_stop( pHwData ); ++ } ++} ++ ++void hal_surprise_remove( phw_data_t pHwData ) ++{ ++ PADAPTER Adapter = pHwData->Adapter; ++ if (OS_ATOMIC_INC( Adapter, &pHwData->SurpriseRemoveCount ) == 1) { ++ #ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("Calling hal_surprise_remove\n")); ++ #endif ++ OS_STOP( Adapter ); ++ } ++} ++ ++void hal_rate_change( phw_data_t pHwData ) // Notify the HAL rate is changing 20060613.1 ++{ ++ PADAPTER Adapter = pHwData->Adapter; ++ u8 rate = CURRENT_TX_RATE; ++ ++ BBProcessor_RateChanging( pHwData, rate ); ++} ++ ++void hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex) ++{ ++ RFSynthesizer_SetPowerIndex( pHwData, PowerIndex ); ++} ++ ++unsigned char hal_set_LED(phw_data_t pHwData, u32 Mode) // 20061108 for WPS led control ++{ ++ pHwData->LED_Blinking = 0; ++ pHwData->LED_control = Mode; ++ OS_TIMER_SET( &pHwData->LEDTimer, 10 ); // 20060623 ++ return TRUE; ++} ++ +diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h +new file mode 100644 +index 0000000..fe25f97 +--- /dev/null ++++ b/drivers/staging/winbond/wbhal_f.h +@@ -0,0 +1,122 @@ ++//===================================================================== ++// Device related include ++//===================================================================== ++#ifdef WB_LINUX ++ #include "linux/wbusb_f.h" ++ #include "linux/wb35reg_f.h" ++ #include "linux/wb35tx_f.h" ++ #include "linux/wb35rx_f.h" ++#else ++ #include "wbusb_f.h" ++ #include "wb35reg_f.h" ++ #include "wb35tx_f.h" ++ #include "wb35rx_f.h" ++#endif ++ ++//==================================================================================== ++// Function declaration ++//==================================================================================== ++void hal_remove_mapping_key( phw_data_t pHwData, PUCHAR pmac_addr ); ++void hal_remove_default_key( phw_data_t pHwData, u32 index ); ++unsigned char hal_set_mapping_key( phw_data_t Adapter, PUCHAR pmac_addr, u8 null_key, u8 wep_on, PUCHAR ptx_tsc, PUCHAR prx_tsc, u8 key_type, u8 key_len, PUCHAR pkey_data ); ++unsigned char hal_set_default_key( phw_data_t Adapter, u8 index, u8 null_key, u8 wep_on, PUCHAR ptx_tsc, PUCHAR prx_tsc, u8 key_type, u8 key_len, PUCHAR pkey_data ); ++void hal_clear_all_default_key( phw_data_t pHwData ); ++void hal_clear_all_group_key( phw_data_t pHwData ); ++void hal_clear_all_mapping_key( phw_data_t pHwData ); ++void hal_clear_all_key( phw_data_t pHwData ); ++void hal_get_ethernet_address( phw_data_t pHwData, PUCHAR current_address ); ++void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address ); ++void hal_get_permanent_address( phw_data_t pHwData, PUCHAR pethernet_address ); ++unsigned char hal_init_hardware( phw_data_t pHwData, PADAPTER Adapter ); ++void hal_set_power_save_mode( phw_data_t pHwData, unsigned char power_save, unsigned char wakeup, unsigned char dtim ); ++void hal_get_power_save_mode( phw_data_t pHwData, PBOOLEAN pin_pwr_save ); ++void hal_set_slot_time( phw_data_t pHwData, u8 type ); ++#define hal_set_atim_window( _A, _ATM ) ++void hal_set_rates( phw_data_t pHwData, PUCHAR pbss_rates, u8 length, unsigned char basic_rate_set ); ++#define hal_set_basic_rates( _A, _R, _L ) hal_set_rates( _A, _R, _L, TRUE ) ++#define hal_set_op_rates( _A, _R, _L ) hal_set_rates( _A, _R, _L, FALSE ) ++void hal_start_bss( phw_data_t pHwData, u8 mac_op_mode ); ++void hal_join_request( phw_data_t pHwData, u8 bss_type ); // 0:BSS STA 1:IBSS STA// ++void hal_stop_sync_bss( phw_data_t pHwData ); ++void hal_resume_sync_bss( phw_data_t pHwData); ++void hal_set_aid( phw_data_t pHwData, u16 aid ); ++void hal_set_bssid( phw_data_t pHwData, PUCHAR pbssid ); ++void hal_get_bssid( phw_data_t pHwData, PUCHAR pbssid ); ++void hal_set_beacon_period( phw_data_t pHwData, u16 beacon_period ); ++void hal_set_listen_interval( phw_data_t pHwData, u16 listen_interval ); ++void hal_set_cap_info( phw_data_t pHwData, u16 capability_info ); ++void hal_set_ssid( phw_data_t pHwData, PUCHAR pssid, u8 ssid_len ); ++void hal_set_current_channel( phw_data_t pHwData, ChanInfo channel ); ++void hal_set_current_channel_ex( phw_data_t pHwData, ChanInfo channel ); ++void hal_get_current_channel( phw_data_t pHwData, ChanInfo *channel ); ++void hal_set_accept_broadcast( phw_data_t pHwData, u8 enable ); ++void hal_set_accept_multicast( phw_data_t pHwData, u8 enable ); ++void hal_set_accept_beacon( phw_data_t pHwData, u8 enable ); ++void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number ); ++u8 hal_get_accept_beacon( phw_data_t pHwData ); ++void hal_stop( phw_data_t pHwData ); ++void hal_halt( phw_data_t pHwData, void *ppa_data ); ++void hal_start_tx0( phw_data_t pHwData ); ++void hal_set_phy_type( phw_data_t pHwData, u8 PhyType ); ++void hal_get_phy_type( phw_data_t pHwData, u8 *PhyType ); ++unsigned char hal_reset_hardware( phw_data_t pHwData, void* ppa ); ++void hal_set_cwmin( phw_data_t pHwData, u8 cwin_min ); ++#define hal_get_cwmin( _A ) ( (_A)->cwmin ) ++void hal_set_cwmax( phw_data_t pHwData, u16 cwin_max ); ++#define hal_get_cwmax( _A ) ( (_A)->cwmax ) ++void hal_set_rsn_wpa( phw_data_t pHwData, u32 * RSN_IE_Bitmap , u32 * RSN_OUI_type , unsigned char bDesiredAuthMode); ++//s32 hal_get_rssi( phw_data_t pHwData, u32 HalRssi ); ++s32 hal_get_rssi( phw_data_t pHwData, u32 *HalRssiArry, u8 Count ); ++s32 hal_get_rssi_bss( phw_data_t pHwData, u16 idx, u8 Count ); ++void hal_set_connect_info( phw_data_t pHwData, unsigned char boConnect ); ++u8 hal_get_est_sq3( phw_data_t pHwData, u8 Count ); ++void hal_led_control_1a( phw_data_t pHwData ); ++void hal_led_control( void* S1, phw_data_t pHwData, void* S3, void* S4 ); ++void hal_set_rf_power( phw_data_t pHwData, u8 PowerIndex ); // 20060621 Modify ++void hal_reset_counter( phw_data_t pHwData ); ++void hal_set_radio_mode( phw_data_t pHwData, unsigned char boValue); ++void hal_descriptor_indicate( phw_data_t pHwData, PDESCRIPTOR pDes ); ++u8 hal_get_antenna_number( phw_data_t pHwData ); ++void hal_set_antenna_number( phw_data_t pHwData, u8 number ); ++u32 hal_get_bss_pk_cnt( phw_data_t pHwData ); ++#define hal_get_region_from_EEPROM( _A ) ( (_A)->Wb35Reg.EEPROMRegion ) ++void hal_set_accept_promiscuous ( phw_data_t pHwData, u8 enable); ++#define hal_get_tx_buffer( _A, _B ) Wb35Tx_get_tx_buffer( _A, _B ) ++u8 hal_get_hw_radio_off ( phw_data_t pHwData ); ++#define hal_software_set( _A ) (_A->SoftwareSet) ++#define hal_driver_init_OK( _A ) (_A->IsInitOK) ++#define hal_rssi_boundary_high( _A ) (_A->RSSI_high) ++#define hal_rssi_boundary_low( _A ) (_A->RSSI_low) ++#define hal_scan_interval( _A ) (_A->Scan_Interval) ++void hal_scan_status_indicate( phw_data_t pHwData, u8 status); // 0: complete, 1: in progress ++void hal_system_power_change( phw_data_t pHwData, u32 PowerState ); // 20051230 -=D0 1=D1 .. ++void hal_surprise_remove( phw_data_t pHwData ); ++ ++#define PHY_DEBUG( msg, args... ) ++ ++ ++ ++void hal_rate_change( phw_data_t pHwData ); // Notify the HAL rate is changing 20060613.1 ++unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, PULONG pValue ); ++unsigned char hal_set_dxx_reg( phw_data_t pHwData, u16 number, u32 value ); ++#define hal_get_time_count( _P ) (_P->time_count/10) // return 100ms count ++#define hal_detect_error( _P ) (_P->WbUsb.DetectCount) ++unsigned char hal_set_LED( phw_data_t pHwData, u32 Mode ); // 20061108 for WPS led control ++ ++//------------------------------------------------------------------------- ++// The follow function is unused for IS89C35 ++//------------------------------------------------------------------------- ++#define hal_disable_interrupt(_A) ++#define hal_enable_interrupt(_A) ++#define hal_get_interrupt_type( _A) ++#define hal_get_clear_interrupt(_A) ++#define hal_ibss_disconnect(_A) hal_stop_sync_bss(_A) ++#define hal_join_request_stop(_A) ++unsigned char hal_idle( phw_data_t pHwData ); ++#define pa_stall_execution( _A ) //OS_SLEEP( 1 ) ++#define hw_get_cxx_reg( _A, _B, _C ) ++#define hw_set_cxx_reg( _A, _B, _C ) ++#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (PULONG)_C ) ++#define hw_set_dxx_reg( _A, _B, _C ) hal_set_dxx_reg( _A, _B, (u32)_C ) ++ ++ +diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal_s.h +new file mode 100644 +index 0000000..5b862ff +--- /dev/null ++++ b/drivers/staging/winbond/wbhal_s.h +@@ -0,0 +1,615 @@ ++//[20040722 WK] ++#define HAL_LED_SET_MASK 0x001c //20060901 Extend ++#define HAL_LED_SET_SHIFT 2 ++ ++//supported RF type ++#define RF_MAXIM_2825 0 ++#define RF_MAXIM_2827 1 ++#define RF_MAXIM_2828 2 ++#define RF_MAXIM_2829 3 ++#define RF_MAXIM_V1 15 ++#define RF_AIROHA_2230 16 ++#define RF_AIROHA_7230 17 ++#define RF_AIROHA_2230S 18 // 20060420 Add this ++// #define RF_RFMD_2959 32 // 20060626 Remove all about RFMD ++#define RF_WB_242 33 ++#define RF_WB_242_1 34 // 20060619.5 Add ++#define RF_DECIDE_BY_INF 255 ++ ++//---------------------------------------------------------------- ++// The follow define connect to upper layer ++// User must modify for connection between HAL and upper layer ++//---------------------------------------------------------------- ++ ++ ++ ++ ++///////////////////////////////////////////////////////////////////////////////////////////////////// ++//================================================================================================ ++// Common define ++//================================================================================================ ++#define HAL_USB_MODE_BURST( _H ) (_H->SoftwareSet & 0x20 ) // Bit 5 20060901 Modify ++ ++// Scan interval ++#define SCAN_MAX_CHNL_TIME (50) ++ ++// For TxL2 Frame typr recognise ++#define FRAME_TYPE_802_3_DATA 0 ++#define FRAME_TYPE_802_11_MANAGEMENT 1 ++#define FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE 2 ++#define FRAME_TYPE_802_11_CONTROL 3 ++#define FRAME_TYPE_802_11_DATA 4 ++#define FRAME_TYPE_PROMISCUOUS 5 ++ ++// The follow definition is used for convert the frame-------------------- ++#define DOT_11_SEQUENCE_OFFSET 22 //Sequence control offset ++#define DOT_3_TYPE_OFFSET 12 ++#define DOT_11_MAC_HEADER_SIZE 24 ++#define DOT_11_SNAP_SIZE 6 ++#define DOT_11_TYPE_OFFSET 30 //The start offset of 802.11 Frame. Type encapsulatuin. ++#define DEFAULT_SIFSTIME 10 ++#define DEFAULT_FRAGMENT_THRESHOLD 2346 // No fragment ++#define DEFAULT_MSDU_LIFE_TIME 0xffff ++ ++#define LONG_PREAMBLE_PLUS_PLCPHEADER_TIME (144+48) ++#define SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME (72+24) ++#define PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION (16+4+6) ++#define Tsym 4 ++ ++// Frame Type of Bits (2, 3)--------------------------------------------- ++#define MAC_TYPE_MANAGEMENT 0x00 ++#define MAC_TYPE_CONTROL 0x04 ++#define MAC_TYPE_DATA 0x08 ++#define MASK_FRAGMENT_NUMBER 0x000F ++#define SEQUENCE_NUMBER_SHIFT 4 ++ ++#define HAL_WOL_TYPE_WAKEUP_FRAME 0x01 ++#define HAL_WOL_TYPE_MAGIC_PACKET 0x02 ++ ++// 20040106 ADDED ++#define HAL_KEYTYPE_WEP40 0 ++#define HAL_KEYTYPE_WEP104 1 ++#define HAL_KEYTYPE_TKIP 2 // 128 bit key ++#define HAL_KEYTYPE_AES_CCMP 3 // 128 bit key ++ ++// For VM state ++enum { ++ VM_STOP = 0, ++ VM_RUNNING, ++ VM_COMPLETED ++}; ++ ++// Be used for 802.11 mac header ++typedef struct _MAC_FRAME_CONTROL { ++ u8 mac_frame_info; // this is a combination of the protovl version, type and subtype ++ u8 to_ds:1; ++ u8 from_ds:1; ++ u8 more_frag:1; ++ u8 retry:1; ++ u8 pwr_mgt:1; ++ u8 more_data:1; ++ u8 WEP:1; ++ u8 order:1; ++} MAC_FRAME_CONTROL, *PMAC_FRAME_CONTROL; ++ ++//----------------------------------------------------- ++// Normal Key table format ++//----------------------------------------------------- ++// The order of KEY index is MAPPING_KEY_START_INDEX > GROUP_KEY_START_INDEX ++#define MAX_KEY_TABLE 24 // 24 entry for storing key data ++#define GROUP_KEY_START_INDEX 4 ++#define MAPPING_KEY_START_INDEX 8 ++typedef struct _KEY_TABLE ++{ ++ u32 DW0_Valid:1; ++ u32 DW0_NullKey:1; ++ u32 DW0_Security_Mode:2;//0:WEP 40 bit 1:WEP 104 bit 2:TKIP 128 bit 3:CCMP 128 bit ++ u32 DW0_WEPON:1; ++ u32 DW0_RESERVED:11; ++ u32 DW0_Address1:16; ++ ++ u32 DW1_Address2; ++ ++ u32 DW2_RxSequenceCount1; ++ ++ u32 DW3_RxSequenceCount2:16; ++ u32 DW3_RESERVED:16; ++ ++ u32 DW4_TxSequenceCount1; ++ ++ u32 DW5_TxSequenceCount2:16; ++ u32 DW5_RESERVED:16; ++ ++} KEY_TABLE, *PKEY_TABLE; ++ ++//-------------------------------------------------------- ++// Descriptor ++//-------------------------------------------------------- ++#define MAX_DESCRIPTOR_BUFFER_INDEX 8 // Have to multiple of 2 ++//#define FLAG_ERROR_TX_MASK cpu_to_le32(0x000000bf) //20061009 marked by anson's endian ++#define FLAG_ERROR_TX_MASK 0x000000bf //20061009 anson's endian ++//#define FLAG_ERROR_RX_MASK 0x00000c3f ++//#define FLAG_ERROR_RX_MASK cpu_to_le32(0x0000083f) //20061009 marked by anson's endian ++ //Don't care replay error, ++ //it is handled by S/W ++#define FLAG_ERROR_RX_MASK 0x0000083f //20060926 anson's endian ++ ++#define FLAG_BAND_RX_MASK 0x10000000 //Bit 28 ++ ++typedef struct _R00_DESCRIPTOR ++{ ++ union ++ { ++ u32 value; ++ #ifdef _BIG_ENDIAN_ //20060926 anson's endian ++ struct ++ { ++ u32 R00_packet_or_buffer_status:1; ++ u32 R00_packet_in_fifo:1; ++ u32 R00_RESERVED:2; ++ u32 R00_receive_byte_count:12; ++ u32 R00_receive_time_index:16; ++ }; ++ #else ++ struct ++ { ++ u32 R00_receive_time_index:16; ++ u32 R00_receive_byte_count:12; ++ u32 R00_RESERVED:2; ++ u32 R00_packet_in_fifo:1; ++ u32 R00_packet_or_buffer_status:1; ++ }; ++ #endif ++ }; ++} R00_DESCRIPTOR, *PR00_DESCRIPTOR; ++ ++typedef struct _T00_DESCRIPTOR ++{ ++ union ++ { ++ u32 value; ++ #ifdef _BIG_ENDIAN_ //20061009 anson's endian ++ struct ++ { ++ u32 T00_first_mpdu:1; // for hardware use ++ u32 T00_last_mpdu:1; // for hardware use ++ u32 T00_IsLastMpdu:1;// 0: not 1:Yes for software used ++ u32 T00_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS ++ u32 T00_RESERVED_ID:2;//3 bit ID reserved ++ u32 T00_tx_packet_id:4;//930519.4.e 930810.3.c ++ u32 T00_RESERVED:4; ++ u32 T00_header_length:6; ++ u32 T00_frame_length:12; ++ }; ++ #else ++ struct ++ { ++ u32 T00_frame_length:12; ++ u32 T00_header_length:6; ++ u32 T00_RESERVED:4; ++ u32 T00_tx_packet_id:4;//930519.4.e 930810.3.c ++ u32 T00_RESERVED_ID:2;//3 bit ID reserved ++ u32 T00_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS ++ u32 T00_IsLastMpdu:1;// 0: not 1:Yes for software used ++ u32 T00_last_mpdu:1; // for hardware use ++ u32 T00_first_mpdu:1; // for hardware use ++ }; ++ #endif ++ }; ++} T00_DESCRIPTOR, *PT00_DESCRIPTOR; ++ ++typedef struct _R01_DESCRIPTOR ++{ ++ union ++ { ++ u32 value; ++ #ifdef _BIG_ENDIAN_ //20060926 add by anson's endian ++ struct ++ { ++ u32 R01_RESERVED:3; ++ u32 R01_mod_type:1; ++ u32 R01_pre_type:1; ++ u32 R01_data_rate:3; ++ u32 R01_AGC_state:8; ++ u32 R01_LNA_state:2; ++ u32 R01_decryption_method:2; ++ u32 R01_mic_error:1; ++ u32 R01_replay:1; ++ u32 R01_broadcast_frame:1; ++ u32 R01_multicast_frame:1; ++ u32 R01_directed_frame:1; ++ u32 R01_receive_frame_antenna_selection:1; ++ u32 R01_frame_receive_during_atim_window:1; ++ u32 R01_protocol_version_error:1; ++ u32 R01_authentication_frame_icv_error:1; ++ u32 R01_null_key_to_authentication_frame:1; ++ u32 R01_icv_error:1; ++ u32 R01_crc_error:1; ++ }; ++ #else ++ struct ++ { ++ u32 R01_crc_error:1; ++ u32 R01_icv_error:1; ++ u32 R01_null_key_to_authentication_frame:1; ++ u32 R01_authentication_frame_icv_error:1; ++ u32 R01_protocol_version_error:1; ++ u32 R01_frame_receive_during_atim_window:1; ++ u32 R01_receive_frame_antenna_selection:1; ++ u32 R01_directed_frame:1; ++ u32 R01_multicast_frame:1; ++ u32 R01_broadcast_frame:1; ++ u32 R01_replay:1; ++ u32 R01_mic_error:1; ++ u32 R01_decryption_method:2; ++ u32 R01_LNA_state:2; ++ u32 R01_AGC_state:8; ++ u32 R01_data_rate:3; ++ u32 R01_pre_type:1; ++ u32 R01_mod_type:1; ++ u32 R01_RESERVED:3; ++ }; ++ #endif ++ }; ++} R01_DESCRIPTOR, *PR01_DESCRIPTOR; ++ ++typedef struct _T01_DESCRIPTOR ++{ ++ union ++ { ++ u32 value; ++ #ifdef _BIG_ENDIAN_ //20061009 anson's endian ++ struct ++ { ++ u32 T01_rts_cts_duration:16; ++ u32 T01_fall_back_rate:3; ++ u32 T01_add_rts:1; ++ u32 T01_add_cts:1; ++ u32 T01_modulation_type:1; ++ u32 T01_plcp_header_length:1; ++ u32 T01_transmit_rate:3; ++ u32 T01_wep_id:2; ++ u32 T01_add_challenge_text:1; ++ u32 T01_inhibit_crc:1; ++ u32 T01_loop_back_wep_mode:1; ++ u32 T01_retry_abort_ebable:1; ++ }; ++ #else ++ struct ++ { ++ u32 T01_retry_abort_ebable:1; ++ u32 T01_loop_back_wep_mode:1; ++ u32 T01_inhibit_crc:1; ++ u32 T01_add_challenge_text:1; ++ u32 T01_wep_id:2; ++ u32 T01_transmit_rate:3; ++ u32 T01_plcp_header_length:1; ++ u32 T01_modulation_type:1; ++ u32 T01_add_cts:1; ++ u32 T01_add_rts:1; ++ u32 T01_fall_back_rate:3; ++ u32 T01_rts_cts_duration:16; ++ }; ++ #endif ++ }; ++} T01_DESCRIPTOR, *PT01_DESCRIPTOR; ++ ++typedef struct _T02_DESCRIPTOR ++{ ++ union ++ { ++ u32 value; ++ #ifdef _BIG_ENDIAN_ //20061009 add by anson's endian ++ struct ++ { ++ u32 T02_IsLastMpdu:1;// The same mechanism with T00 setting ++ u32 T02_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS ++ u32 T02_RESERVED_ID:2;// The same mechanism with T00 setting ++ u32 T02_Tx_PktID:4; ++ u32 T02_MPDU_Cnt:4; ++ u32 T02_RTS_Cnt:4; ++ u32 T02_RESERVED:7; ++ u32 T02_transmit_complete:1; ++ u32 T02_transmit_abort_due_to_TBTT:1; ++ u32 T02_effective_transmission_rate:1; ++ u32 T02_transmit_without_encryption_due_to_wep_on_false:1; ++ u32 T02_discard_due_to_null_wep_key:1; ++ u32 T02_RESERVED_1:1; ++ u32 T02_out_of_MaxTxMSDULiftTime:1; ++ u32 T02_transmit_abort:1; ++ u32 T02_transmit_fail:1; ++ }; ++ #else ++ struct ++ { ++ u32 T02_transmit_fail:1; ++ u32 T02_transmit_abort:1; ++ u32 T02_out_of_MaxTxMSDULiftTime:1; ++ u32 T02_RESERVED_1:1; ++ u32 T02_discard_due_to_null_wep_key:1; ++ u32 T02_transmit_without_encryption_due_to_wep_on_false:1; ++ u32 T02_effective_transmission_rate:1; ++ u32 T02_transmit_abort_due_to_TBTT:1; ++ u32 T02_transmit_complete:1; ++ u32 T02_RESERVED:7; ++ u32 T02_RTS_Cnt:4; ++ u32 T02_MPDU_Cnt:4; ++ u32 T02_Tx_PktID:4; ++ u32 T02_RESERVED_ID:2;// The same mechanism with T00 setting ++ u32 T02_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS ++ u32 T02_IsLastMpdu:1;// The same mechanism with T00 setting ++ }; ++ #endif ++ }; ++} T02_DESCRIPTOR, *PT02_DESCRIPTOR; ++ ++typedef struct _DESCRIPTOR { // Skip length = 8 DWORD ++ // ID for descriptor ---, The field doesn't be cleard in the operation of Descriptor definition ++ u8 Descriptor_ID; ++ //----------------------The above region doesn't be cleared by DESCRIPTOR_RESET------ ++ u8 RESERVED[3]; ++ ++ u16 FragmentThreshold; ++ u8 InternalUsed;//Only can be used by operation of descriptor definition ++ u8 Type;// 0: 802.3 1:802.11 data frame 2:802.11 management frame ++ ++ u8 PreambleMode;// 0: short 1:long ++ u8 TxRate; ++ u8 FragmentCount; ++ u8 EapFix; // For speed up key install ++ ++ // For R00 and T00 ---------------------------------------------- ++ union ++ { ++ R00_DESCRIPTOR R00; ++ T00_DESCRIPTOR T00; ++ }; ++ ++ // For R01 and T01 ---------------------------------------------- ++ union ++ { ++ R01_DESCRIPTOR R01; ++ T01_DESCRIPTOR T01; ++ }; ++ ++ // For R02 and T02 ---------------------------------------------- ++ union ++ { ++ u32 R02; ++ T02_DESCRIPTOR T02; ++ }; ++ ++ // For R03 and T03 ---------------------------------------------- ++ // For software used ++ union ++ { ++ u32 R03; ++ u32 T03; ++ struct ++ { ++ u8 buffer_number; ++ u8 buffer_start_index; ++ u16 buffer_total_size; ++ }; ++ }; ++ ++ // For storing the buffer ++ u16 buffer_size[ MAX_DESCRIPTOR_BUFFER_INDEX ]; ++ void* buffer_address[ MAX_DESCRIPTOR_BUFFER_INDEX ];//931130.4.q ++ ++} DESCRIPTOR, *PDESCRIPTOR; ++ ++ ++#define DEFAULT_NULL_PACKET_COUNT 180000 //20060828.1 Add. 180 seconds ++ ++#define MAX_TXVGA_EEPROM 9 //How many word(u16) of EEPROM will be used for TxVGA ++#define MAX_RF_PARAMETER 32 ++ ++typedef struct _TXVGA_FOR_50 { ++ u8 ChanNo; ++ u8 TxVgaValue; ++} TXVGA_FOR_50; ++ ++ ++//===================================================================== ++// Device related include ++//===================================================================== ++ ++#include "linux/wbusb_s.h" ++#include "linux/wb35reg_s.h" ++#include "linux/wb35tx_s.h" ++#include "linux/wb35rx_s.h" ++ ++ ++// For Hal using ================================================================== ++typedef struct _HW_DATA_T ++{ ++ // For compatible with 33 ++ u32 revision; ++ u32 BB3c_cal; // The value for Tx calibration comes from EEPROM ++ u32 BB54_cal; // The value for Rx calibration comes from EEPROM ++ ++ ++ // For surprise remove ++ u32 SurpriseRemove; // 0: Normal 1: Surprise remove ++ u8 InitialResource; ++ u8 IsKeyPreSet; ++ u8 CalOneTime; // 20060630.1 ++ ++ u8 VCO_trim; ++ ++ // For Fix 1'st DMA bug ++ u32 FragCount; ++ u32 DMAFix; //V1_DMA_FIX The variable can be removed if driver want to save mem space for V2. ++ ++ //======================================================================================= ++ // For USB driver, hal need more variables. Due to ++ // 1. NDIS-WDM operation ++ // 2. The SME, MLME and OLD MDS need Adapter structure, but the driver under HAL doesn't ++ // have that parameter when receiving and indicating packet. ++ // The MDS must input the Adapter pointer as the second parameter of hal_init_hardware. ++ // The function usage is different than PCI driver. ++ //======================================================================================= ++ void* Adapter; ++ ++ //=============================================== ++ // Definition for MAC address ++ //=============================================== ++ u8 PermanentMacAddress[ETH_LENGTH_OF_ADDRESS + 2]; // The Enthernet addr that are stored in EEPROM. + 2 to 8-byte alignment ++ u8 CurrentMacAddress[ETH_LENGTH_OF_ADDRESS + 2]; // The Enthernet addr that are in used. + 2 to 8-byte alignment ++ ++ //===================================================================== ++ // Definition for 802.11 ++ //===================================================================== ++ PUCHAR bssid_pointer; // Used by hal_get_bssid for return value ++ u8 bssid[8];// Only 6 byte will be used. 8 byte is required for read buffer ++ u8 ssid[32];// maximum ssid length is 32 byte ++ ++ u16 AID; ++ u8 ssid_length; ++ u8 Channel; ++ ++ u16 ListenInterval; ++ u16 CapabilityInformation; ++ ++ u16 BeaconPeriod; ++ u16 ProbeDelay; ++ ++ u8 bss_type;// 0: IBSS_NET or 1:ESS_NET ++ u8 preamble;// 0: short preamble, 1: long preamble ++ u8 slot_time_select;// 9 or 20 value ++ u8 phy_type;// Phy select ++ ++ u32 phy_para[MAX_RF_PARAMETER]; ++ u32 phy_number; ++ ++ u32 CurrentRadioSw; // 20060320.2 0:On 1:Off ++ u32 CurrentRadioHw; // 20060825 0:On 1:Off ++ ++ PUCHAR power_save_point; // Used by hal_get_power_save_mode for return value ++ u8 cwmin; ++ u8 desired_power_save; ++ u8 dtim;// Is running dtim ++ u8 mapping_key_replace_index;//In Key table, the next index be replaced 931130.4.r ++ ++ u16 MaxReceiveLifeTime; ++ u16 FragmentThreshold; ++ u16 FragmentThreshold_tmp; ++ u16 cwmax; ++ ++ u8 Key_slot[MAX_KEY_TABLE][8]; //Ownership record for key slot. For Alignment ++ u32 Key_content[MAX_KEY_TABLE][12]; // 10DW for each entry + 2 for burst command( Off and On valid bit) ++ u8 CurrentDefaultKeyIndex; ++ u32 CurrentDefaultKeyLength; ++ ++ //======================================================================== ++ // Variable for each module ++ //======================================================================== ++ WBUSB WbUsb; // Need WbUsb.h ++ WB35REG Wb35Reg; // Need Wb35Reg.h ++ WB35TX Wb35Tx; // Need Wb35Tx.h ++ WB35RX Wb35Rx; // Need Wb35Rx.h ++ ++ OS_TIMER LEDTimer;// For LED ++ ++ u32 LEDpoint;// For LED ++ ++ u32 dto_tx_retry_count; // LA20040210_DTO kevin ++ u32 dto_tx_frag_count; // LA20040210_DTO kevin ++ u32 rx_ok_count[13]; // index=0: total rx ok ++ //u32 rx_ok_bytes[13]; // index=0, total rx ok bytes ++ u32 rx_err_count[13]; // index=0: total rx err ++ ++ //for Tx debug ++ u32 tx_TBTT_start_count; ++ u32 tx_ETR_count; ++ u32 tx_WepOn_false_count; ++ u32 tx_Null_key_count; ++ u32 tx_retry_count[8]; ++ ++ u8 PowerIndexFromEEPROM; // For 2412MHz ++ u8 power_index; ++ u8 IsWaitJoinComplete; // TRUE: set join request ++ u8 band; ++ ++ u16 SoftwareSet; ++ u16 Reserved_s; ++ ++ u32 IsInitOK; // 0: Driver starting 1: Driver init OK ++ ++ // For Phy calibration ++ s32 iq_rsdl_gain_tx_d2; ++ s32 iq_rsdl_phase_tx_d2; ++ u32 txvga_setting_for_cal; // 20060703.1 Add ++ ++ u8 TxVgaSettingInEEPROM[ (((MAX_TXVGA_EEPROM*2)+3) & ~0x03) ]; // 20060621 For backup EEPROM value ++ u8 TxVgaFor24[16]; // Max is 14, 2 for alignment ++ TXVGA_FOR_50 TxVgaFor50[36]; // 35 channels in 5G. 35x2 = 70 byte. 2 for alignments ++ ++ u16 Scan_Interval; ++ u16 RESERVED6; ++ ++ // LED control ++ u32 LED_control; ++ // LED_control 4 byte: Gray_Led_1[3] Gray_Led_0[2] Led[1] Led[0] ++ // Gray_Led ++ // For Led gray setting ++ // Led ++ // 0: normal control, LED behavior will decide by EEPROM setting ++ // 1: Turn off specific LED ++ // 2: Always on specific LED ++ // 3: slow blinking specific LED ++ // 4: fast blinking specific LED ++ // 5: WPS led control is set. Led0 is Red, Led1 id Green ++ // Led[1] is parameter for WPS LED mode ++ // // 1:InProgress 2: Error 3: Session overlap 4: Success 20061108 control ++ ++ u32 LED_LinkOn; //Turn LED on control ++ u32 LED_Scanning; // Let LED in scan process control ++ u32 LED_Blinking; // Temp variable for shining ++ u32 RxByteCountLast; ++ u32 TxByteCountLast; ++ ++ s32 SurpriseRemoveCount; ++ ++ // For global timer ++ u32 time_count;//TICK_TIME_100ms 1 = 100ms ++ ++ // For error recover ++ u32 HwStop; ++ ++ // 20060828.1 for avoid AP disconnect ++ u32 NullPacketCount; ++ ++} hw_data_t, *phw_data_t; ++ ++// The mapping of Rx and Tx descriptor field ++typedef struct _HAL_RATE ++{ ++ // DSSS ++ u32 RESERVED_0; ++ u32 NumRate2MS; ++ u32 NumRate55MS; ++ u32 NumRate11MS; ++ ++ u32 RESERVED_1[4]; ++ ++ u32 NumRate1M; ++ u32 NumRate2ML; ++ u32 NumRate55ML; ++ u32 NumRate11ML; ++ ++ u32 RESERVED_2[4]; ++ ++ // OFDM ++ u32 NumRate6M; ++ u32 NumRate9M; ++ u32 NumRate12M; ++ u32 NumRate18M; ++ u32 NumRate24M; ++ u32 NumRate36M; ++ u32 NumRate48M; ++ u32 NumRate54M; ++} HAL_RATE, *PHAL_RATE; ++ ++ +diff --git a/drivers/staging/winbond/wblinux.c b/drivers/staging/winbond/wblinux.c +new file mode 100644 +index 0000000..2eade5a +--- /dev/null ++++ b/drivers/staging/winbond/wblinux.c +@@ -0,0 +1,277 @@ ++//============================================================================ ++// Copyright (c) 1996-2005 Winbond Electronic Corporation ++// ++// Module Name: ++// wblinux.c ++// ++// Abstract: ++// Linux releated routines ++// ++//============================================================================ ++#include "os_common.h" ++ ++u32 ++WBLINUX_MemoryAlloc(void* *VirtualAddress, u32 Length) ++{ ++ *VirtualAddress = kzalloc( Length, GFP_ATOMIC ); //GFP_KERNEL is not suitable ++ ++ if (*VirtualAddress == NULL) ++ return 0; ++ return 1; ++} ++ ++s32 ++EncapAtomicInc(PADAPTER Adapter, void* pAtomic) ++{ ++ PWBLINUX pWbLinux = &Adapter->WbLinux; ++ u32 ltmp; ++ PULONG pltmp = (PULONG)pAtomic; ++ OS_SPIN_LOCK_ACQUIRED( &pWbLinux->AtomicSpinLock ); ++ (*pltmp)++; ++ ltmp = (*pltmp); ++ OS_SPIN_LOCK_RELEASED( &pWbLinux->AtomicSpinLock ); ++ return ltmp; ++} ++ ++s32 ++EncapAtomicDec(PADAPTER Adapter, void* pAtomic) ++{ ++ PWBLINUX pWbLinux = &Adapter->WbLinux; ++ u32 ltmp; ++ PULONG pltmp = (PULONG)pAtomic; ++ OS_SPIN_LOCK_ACQUIRED( &pWbLinux->AtomicSpinLock ); ++ (*pltmp)--; ++ ltmp = (*pltmp); ++ OS_SPIN_LOCK_RELEASED( &pWbLinux->AtomicSpinLock ); ++ return ltmp; ++} ++ ++unsigned char ++WBLINUX_Initial(PADAPTER Adapter) ++{ ++ PWBLINUX pWbLinux = &Adapter->WbLinux; ++ ++ OS_SPIN_LOCK_ALLOCATE( &pWbLinux->SpinLock ); ++ OS_SPIN_LOCK_ALLOCATE( &pWbLinux->AtomicSpinLock ); ++ return TRUE; ++} ++ ++void ++WBLinux_ReceivePacket(PADAPTER Adapter, PRXLAYER1 pRxLayer1) ++{ ++ BUG(); ++} ++ ++ ++void ++WBLINUX_GetNextPacket(PADAPTER Adapter, PDESCRIPTOR pDes) ++{ ++ BUG(); ++} ++ ++void ++WBLINUX_GetNextPacketCompleted(PADAPTER Adapter, PDESCRIPTOR pDes) ++{ ++ BUG(); ++} ++ ++void ++WBLINUX_Destroy(PADAPTER Adapter) ++{ ++ WBLINUX_stop( Adapter ); ++ OS_SPIN_LOCK_FREE( &pWbNdis->SpinLock ); ++#ifdef _PE_USB_INI_DUMP_ ++ WBDEBUG(("[w35und] unregister_netdev!\n")); ++#endif ++} ++ ++void ++WBLINUX_stop( PADAPTER Adapter ) ++{ ++ PWBLINUX pWbLinux = &Adapter->WbLinux; ++ struct sk_buff *pSkb; ++ ++ if (OS_ATOMIC_INC( Adapter, &pWbLinux->ThreadCount ) == 1) { ++ // Shutdown module immediately ++ pWbLinux->shutdown = 1; ++ ++ while (pWbLinux->skb_array[ pWbLinux->skb_GetIndex ]) { ++ // Trying to free the un-sending packet ++ pSkb = pWbLinux->skb_array[ pWbLinux->skb_GetIndex ]; ++ pWbLinux->skb_array[ pWbLinux->skb_GetIndex ] = NULL; ++ if( in_irq() ) ++ dev_kfree_skb_irq( pSkb ); ++ else ++ dev_kfree_skb( pSkb ); ++ ++ pWbLinux->skb_GetIndex++; ++ pWbLinux->skb_GetIndex %= WBLINUX_PACKET_ARRAY_SIZE; ++ } ++ ++#ifdef _PE_STATE_DUMP_ ++ WBDEBUG(( "[w35und] SKB_RELEASE OK\n" )); ++#endif ++ } ++ ++ OS_ATOMIC_DEC( Adapter, &pWbLinux->ThreadCount ); ++} ++ ++void ++WbWlanHalt( PADAPTER Adapter ) ++{ ++ //--------------------- ++ Adapter->sLocalPara.ShutDowned = TRUE; ++ ++ Mds_Destroy( Adapter ); ++ ++ // Turn off Rx and Tx hardware ability ++ hal_stop( &Adapter->sHwData ); ++#ifdef _PE_USB_INI_DUMP_ ++ WBDEBUG(("[w35und] Hal_stop O.K.\n")); ++#endif ++ OS_SLEEP(100000);// Waiting Irp completed ++ ++ // Destroy the NDIS module ++ WBLINUX_Destroy( Adapter ); ++ ++ // Halt the HAL ++ hal_halt(&Adapter->sHwData, NULL); ++} ++ ++unsigned char ++WbWLanInitialize(PADAPTER Adapter) ++{ ++ phw_data_t pHwData; ++ PUCHAR pMacAddr, pMacAddr2; ++ u32 InitStep = 0; ++ u8 EEPROM_region; ++ u8 HwRadioOff; ++ ++ do { ++ // ++ // Setting default value for Linux ++ // ++ Adapter->sLocalPara.region_INF = REGION_AUTO; ++ Adapter->sLocalPara.TxRateMode = RATE_AUTO; ++ psLOCAL->bMacOperationMode = MODE_802_11_BG; // B/G mode ++ Adapter->Mds.TxRTSThreshold = DEFAULT_RTSThreshold; ++ Adapter->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; ++ hal_set_phy_type( &Adapter->sHwData, RF_WB_242_1 ); ++ Adapter->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE; ++ psLOCAL->bPreambleMode = AUTO_MODE; ++ Adapter->sLocalPara.RadioOffStatus.boSwRadioOff = FALSE; ++ pHwData = &Adapter->sHwData; ++ hal_set_phy_type( pHwData, RF_DECIDE_BY_INF ); ++ ++ // ++ // Initial each module and variable ++ // ++ if (!WBLINUX_Initial(Adapter)) { ++#ifdef _PE_USB_INI_DUMP_ ++ WBDEBUG(("[w35und]WBNDIS initialization failed\n")); ++#endif ++ break; ++ } ++ ++ // Initial Software variable ++ Adapter->sLocalPara.ShutDowned = FALSE; ++ ++ //added by ws for wep key error detection ++ Adapter->sLocalPara.bWepKeyError= FALSE; ++ Adapter->sLocalPara.bToSelfPacketReceived = FALSE; ++ Adapter->sLocalPara.WepKeyDetectTimerCount= 2 * 100; /// 2 seconds ++ ++ // Initial USB hal ++ InitStep = 1; ++ pHwData = &Adapter->sHwData; ++ if (!hal_init_hardware(pHwData, Adapter)) ++ break; ++ ++ EEPROM_region = hal_get_region_from_EEPROM( pHwData ); ++ if (EEPROM_region != REGION_AUTO) ++ psLOCAL->region = EEPROM_region; ++ else { ++ if (psLOCAL->region_INF != REGION_AUTO) ++ psLOCAL->region = psLOCAL->region_INF; ++ else ++ psLOCAL->region = REGION_USA; //default setting ++ } ++ ++ // Get Software setting flag from hal ++ Adapter->sLocalPara.boAntennaDiversity = FALSE; ++ if (hal_software_set(pHwData) & 0x00000001) ++ Adapter->sLocalPara.boAntennaDiversity = TRUE; ++ ++ // ++ // For TS module ++ // ++ InitStep = 2; ++ ++ // For MDS module ++ InitStep = 3; ++ Mds_initial(Adapter); ++ ++ //======================================= ++ // Initialize the SME, SCAN, MLME, ROAM ++ //======================================= ++ InitStep = 4; ++ InitStep = 5; ++ InitStep = 6; ++ ++ // If no user-defined address in the registry, use the addresss "burned" on the NIC instead. ++ pMacAddr = Adapter->sLocalPara.ThisMacAddress; ++ pMacAddr2 = Adapter->sLocalPara.PermanentAddress; ++ hal_get_permanent_address( pHwData, Adapter->sLocalPara.PermanentAddress );// Reading ethernet address from EEPROM ++ if (OS_MEMORY_COMPARE(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH )) // Is equal ++ { ++ memcpy( pMacAddr, pMacAddr2, MAC_ADDR_LENGTH ); ++ } else { ++ // Set the user define MAC address ++ hal_set_ethernet_address( pHwData, Adapter->sLocalPara.ThisMacAddress ); ++ } ++ ++ //get current antenna ++ psLOCAL->bAntennaNo = hal_get_antenna_number(pHwData); ++#ifdef _PE_STATE_DUMP_ ++ WBDEBUG(("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo)); ++#endif ++ hal_get_hw_radio_off( pHwData ); ++ ++ // Waiting for HAL setting OK ++ while (!hal_idle(pHwData)) ++ OS_SLEEP(10000); ++ ++ MTO_Init(Adapter); ++ ++ HwRadioOff = hal_get_hw_radio_off( pHwData ); ++ psLOCAL->RadioOffStatus.boHwRadioOff = !!HwRadioOff; ++ ++ hal_set_radio_mode( pHwData, (unsigned char)(psLOCAL->RadioOffStatus.boSwRadioOff || psLOCAL->RadioOffStatus.boHwRadioOff) ); ++ ++ hal_driver_init_OK(pHwData) = 1; // Notify hal that the driver is ready now. ++ //set a tx power for reference..... ++// sme_set_tx_power_level(Adapter, 12); FIXME? ++ return TRUE; ++ } ++ while(FALSE); ++ ++ switch (InitStep) { ++ case 5: ++ case 4: ++ case 3: Mds_Destroy( Adapter ); ++ case 2: ++ case 1: WBLINUX_Destroy( Adapter ); ++ hal_halt( pHwData, NULL ); ++ case 0: break; ++ } ++ ++ return FALSE; ++} ++ ++void WBLINUX_ConnectStatus(PADAPTER Adapter, u32 flag) ++{ ++ PWBLINUX pWbLinux = &Adapter->WbLinux; ++ ++ pWbLinux->LinkStatus = flag; // OS_DISCONNECTED or OS_CONNECTED ++} ++ +diff --git a/drivers/staging/winbond/wblinux_f.h b/drivers/staging/winbond/wblinux_f.h +new file mode 100644 +index 0000000..68240c5 +--- /dev/null ++++ b/drivers/staging/winbond/wblinux_f.h +@@ -0,0 +1,23 @@ ++//========================================================================= ++// Copyright (c) 1996-2004 Winbond Electronic Corporation ++// ++// wblinux_f.h ++// ++u32 WBLINUX_MemoryAlloc( void* *VirtualAddress, u32 Length ); ++s32 EncapAtomicInc( PADAPTER Adapter, void* pAtomic ); ++s32 EncapAtomicDec( PADAPTER Adapter, void* pAtomic ); ++void WBLinux_ReceivePacket( PADAPTER Adapter, PRXLAYER1 pRxLayer1 ); ++unsigned char WBLINUX_Initial( PADAPTER Adapter ); ++int wb35_start_xmit(struct sk_buff *skb, struct net_device *netdev ); ++void WBLINUX_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes ); ++void WBLINUX_GetNextPacketCompleted( PADAPTER Adapter, PDESCRIPTOR pDes ); ++void WBLINUX_stop( PADAPTER Adapter ); ++void WBLINUX_Destroy( PADAPTER Adapter ); ++void wb35_set_multicast( struct net_device *netdev ); ++struct net_device_stats * wb35_netdev_stats( struct net_device *netdev ); ++void WBLINUX_stop( PADAPTER Adapter ); ++void WbWlanHalt( PADAPTER Adapter ); ++void WBLINUX_ConnectStatus( PADAPTER Adapter, u32 flag ); ++ ++ ++ +diff --git a/drivers/staging/winbond/wblinux_s.h b/drivers/staging/winbond/wblinux_s.h +new file mode 100644 +index 0000000..97e9167 +--- /dev/null ++++ b/drivers/staging/winbond/wblinux_s.h +@@ -0,0 +1,45 @@ ++//============================================================ ++// wblinux_s.h ++// ++#define OS_MEMORY_ALLOC( _V, _S ) WBLINUX_MemoryAlloc( _V, _S ) ++#define OS_LINK_STATUS (Adapter->WbLinux.LinkStatus == OS_CONNECTED) ++#define OS_SET_SHUTDOWN( _A ) _A->WbLinux.shutdown=1 ++#define OS_SET_RESUME( _A ) _A->WbLinux.shutdown=0 ++#define OS_CONNECT_STATUS_INDICATE( _A, _F ) WBLINUX_ConnectStatus( _A, _F ) ++#define OS_DISCONNECTED 0 ++#define OS_CONNECTED 1 ++#define OS_STOP( _A ) WBLINUX_stop( _A ) ++ ++#define OS_CURRENT_RX_BYTE( _A ) _A->WbLinux.RxByteCount ++#define OS_CURRENT_TX_BYTE( _A ) _A->WbLinux.TxByteCount ++#define OS_EVENT_INDICATE( _A, _B, _F ) ++#define OS_PMKID_STATUS_EVENT( _A ) ++#define OS_RECEIVE_PACKET_INDICATE( _A, _D ) WBLinux_ReceivePacket( _A, _D ) ++#define OS_RECEIVE_802_1X_PACKET_INDICATE( _A, _D ) EAP_ReceivePacket( _A, _D ) ++#define OS_GET_PACKET( _A, _D ) WBLINUX_GetNextPacket( _A, _D ) ++#define OS_GET_PACKET_COMPLETE( _A, _D ) WBLINUX_GetNextPacketCompleted( _A, _D ) ++#define OS_SEND_RESULT( _A, _ID, _R ) ++ ++#define WBLINUX_PACKET_ARRAY_SIZE (ETHERNET_TX_DESCRIPTORS*4) ++ ++typedef struct _WBLINUX ++{ ++ OS_SPIN_LOCK AtomicSpinLock; ++ OS_SPIN_LOCK SpinLock; ++ u32 shutdown; ++ ++ OS_ATOMIC ThreadCount; ++ ++ u32 LinkStatus; // OS_DISCONNECTED or OS_CONNECTED ++ ++ u32 RxByteCount; ++ u32 TxByteCount; ++ ++ struct sk_buff *skb_array[ WBLINUX_PACKET_ARRAY_SIZE ]; ++ struct sk_buff *packet_return; ++ s32 skb_SetIndex; ++ s32 skb_GetIndex; ++ s32 netif_state_stop; // 1: stop 0: normal ++} WBLINUX, *PWBLINUX; ++ ++ +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0015-Staging-add-wlan-ng-prism2-usb-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0015-Staging-add-wlan-ng-prism2-usb-driver.patch new file mode 100644 index 000000000..3e8695d34 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0015-Staging-add-wlan-ng-prism2-usb-driver.patch @@ -0,0 +1,21126 @@ +From 00b3ed1685089ff52169a715de11106ed37df087 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 2 Oct 2008 11:29:28 -0700 +Subject: [PATCH 15/23] Staging: add wlan-ng prism2 usb driver +Patch-mainline: 2.6.28 + +This adds the wlan-ng prism2 USB driver to the drivers/staging tree. + +The code was originally written by the linux-wlan-ng team, patched by +some Novell engineers to properly work on newer kernels, and then hacked +into place in order to get it to build properly in a single subdirectory +within the kernel tree by me. + +It supports a wide range of older USB prism2 devices, and contains a +80211 stack to support this single driver. + +Cc: Christian Zoz +Cc: Andreas Gruenbacher +Cc: linux-wireless +Cc: John Linville +Cc: Helmut Schaa +Cc: linux-wlan-ng +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/wlan-ng/Kconfig | 10 + drivers/staging/wlan-ng/Makefile | 8 + drivers/staging/wlan-ng/README | 7 + drivers/staging/wlan-ng/hfa384x.h | 2792 +++++++++++++++++ + drivers/staging/wlan-ng/hfa384x_usb.c | 4690 +++++++++++++++++++++++++++++ + drivers/staging/wlan-ng/p80211conv.c | 686 ++++ + drivers/staging/wlan-ng/p80211conv.h | 186 + + drivers/staging/wlan-ng/p80211hdr.h | 299 + + drivers/staging/wlan-ng/p80211ioctl.h | 123 + drivers/staging/wlan-ng/p80211meta.h | 169 + + drivers/staging/wlan-ng/p80211metadef.h | 757 ++++ + drivers/staging/wlan-ng/p80211metamib.h | 105 + drivers/staging/wlan-ng/p80211metamsg.h | 105 + drivers/staging/wlan-ng/p80211metastruct.h | 285 + + drivers/staging/wlan-ng/p80211mgmt.h | 575 +++ + drivers/staging/wlan-ng/p80211msg.h | 102 + drivers/staging/wlan-ng/p80211netdev.c | 1209 +++++++ + drivers/staging/wlan-ng/p80211netdev.h | 254 + + drivers/staging/wlan-ng/p80211req.c | 300 + + drivers/staging/wlan-ng/p80211req.h | 68 + drivers/staging/wlan-ng/p80211types.h | 675 ++++ + drivers/staging/wlan-ng/p80211wep.c | 315 + + drivers/staging/wlan-ng/p80211wext.c | 1826 +++++++++++ + drivers/staging/wlan-ng/prism2mgmt.c | 1363 ++++++++ + drivers/staging/wlan-ng/prism2mgmt.h | 155 + drivers/staging/wlan-ng/prism2mib.c | 1135 +++++++ + drivers/staging/wlan-ng/prism2sta.c | 2212 +++++++++++++ + drivers/staging/wlan-ng/prism2usb.c | 302 + + drivers/staging/wlan-ng/version.h | 56 + drivers/staging/wlan-ng/wlan_compat.h | 193 + + 32 files changed, 20965 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -37,4 +37,6 @@ source "drivers/staging/usbip/Kconfig" + + source "drivers/staging/winbond/Kconfig" + ++source "drivers/staging/wlan-ng/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_ME4000) += me4000/ + obj-$(CONFIG_VIDEO_GO7007) += go7007/ + obj-$(CONFIG_USB_IP_COMMON) += usbip/ + obj-$(CONFIG_W35UND) += winbond/ ++obj-$(CONFIG_PRISM2_USB) += wlan-ng/ +--- /dev/null ++++ b/drivers/staging/wlan-ng/hfa384x.h +@@ -0,0 +1,2792 @@ ++/* hfa384x.h ++* ++* Defines the constants and data structures for the hfa384x ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* [Implementation and usage notes] ++* ++* [References] ++* CW10 Programmer's Manual v1.5 ++* IEEE 802.11 D10.0 ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _HFA384x_H ++#define _HFA384x_H ++ ++/*=============================================================*/ ++#define HFA384x_FIRMWARE_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++ ++#define HFA384x_LEVEL_TO_dBm(v) (0x100 + (v) * 100 / 255 - 100) ++ ++/*------ Constants --------------------------------------------*/ ++/*--- Mins & Maxs -----------------------------------*/ ++#define HFA384x_CMD_ALLOC_LEN_MIN ((u16)4) ++#define HFA384x_CMD_ALLOC_LEN_MAX ((u16)2400) ++#define HFA384x_BAP_DATALEN_MAX ((u16)4096) ++#define HFA384x_BAP_OFFSET_MAX ((u16)4096) ++#define HFA384x_PORTID_MAX ((u16)7) ++#define HFA384x_NUMPORTS_MAX ((u16)(HFA384x_PORTID_MAX+1)) ++#define HFA384x_PDR_LEN_MAX ((u16)512) /* in bytes, from EK */ ++#define HFA384x_PDA_RECS_MAX ((u16)200) /* a guess */ ++#define HFA384x_PDA_LEN_MAX ((u16)1024) /* in bytes, from EK */ ++#define HFA384x_SCANRESULT_MAX ((u16)31) ++#define HFA384x_HSCANRESULT_MAX ((u16)31) ++#define HFA384x_CHINFORESULT_MAX ((u16)16) ++#define HFA384x_DRVR_FIDSTACKLEN_MAX (10) ++#define HFA384x_DRVR_TXBUF_MAX (sizeof(hfa384x_tx_frame_t) + \ ++ WLAN_DATA_MAXLEN - \ ++ WLAN_WEP_IV_LEN - \ ++ WLAN_WEP_ICV_LEN + 2) ++#define HFA384x_DRVR_MAGIC (0x4a2d) ++#define HFA384x_INFODATA_MAXLEN (sizeof(hfa384x_infodata_t)) ++#define HFA384x_INFOFRM_MAXLEN (sizeof(hfa384x_InfFrame_t)) ++#define HFA384x_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */ ++#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN ++#define HFA384x_USB_RWMEM_MAXLEN 2048 ++ ++/*--- Support Constants -----------------------------*/ ++#define HFA384x_BAP_PROC ((u16)0) ++#define HFA384x_BAP_int ((u16)1) ++#define HFA384x_PORTTYPE_IBSS ((u16)0) ++#define HFA384x_PORTTYPE_BSS ((u16)1) ++#define HFA384x_PORTTYPE_WDS ((u16)2) ++#define HFA384x_PORTTYPE_PSUEDOIBSS ((u16)3) ++#define HFA384x_PORTTYPE_HOSTAP ((u16)6) ++#define HFA384x_WEPFLAGS_PRIVINVOKED ((u16)BIT0) ++#define HFA384x_WEPFLAGS_EXCLUDE ((u16)BIT1) ++#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT ((u16)BIT4) ++#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT ((u16)BIT7) ++#define HFA384x_WEPFLAGS_DISALLOW_MIXED ((u16)BIT11) ++#define HFA384x_WEPFLAGS_IV_intERVAL1 ((u16)0) ++#define HFA384x_WEPFLAGS_IV_intERVAL10 ((u16)BIT5) ++#define HFA384x_WEPFLAGS_IV_intERVAL50 ((u16)BIT6) ++#define HFA384x_WEPFLAGS_IV_intERVAL100 ((u16)(BIT5 | BIT6)) ++#define HFA384x_WEPFLAGS_FIRMWARE_WPA ((u16)BIT8) ++#define HFA384x_WEPFLAGS_HOST_MIC ((u16)BIT9) ++#define HFA384x_ROAMMODE_FWSCAN_FWROAM ((u16)1) ++#define HFA384x_ROAMMODE_FWSCAN_HOSTROAM ((u16)2) ++#define HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM ((u16)3) ++#define HFA384x_PORTSTATUS_DISABLED ((u16)1) ++#define HFA384x_PORTSTATUS_INITSRCH ((u16)2) ++#define HFA384x_PORTSTATUS_CONN_IBSS ((u16)3) ++#define HFA384x_PORTSTATUS_CONN_ESS ((u16)4) ++#define HFA384x_PORTSTATUS_OOR_ESS ((u16)5) ++#define HFA384x_PORTSTATUS_CONN_WDS ((u16)6) ++#define HFA384x_PORTSTATUS_HOSTAP ((u16)8) ++#define HFA384x_RATEBIT_1 ((u16)1) ++#define HFA384x_RATEBIT_2 ((u16)2) ++#define HFA384x_RATEBIT_5dot5 ((u16)4) ++#define HFA384x_RATEBIT_11 ((u16)8) ++ ++/*--- Just some symbolic names for legibility -------*/ ++#define HFA384x_TXCMD_NORECL ((u16)0) ++#define HFA384x_TXCMD_RECL ((u16)1) ++ ++/*--- MAC Internal memory constants and macros ------*/ ++/* masks and macros used to manipulate MAC internal memory addresses. */ ++/* MAC internal memory addresses are 23 bit quantities. The MAC uses ++ * a paged address space where the upper 16 bits are the page number ++ * and the lower 7 bits are the offset. There are various Host API ++ * elements that require two 16-bit quantities to specify a MAC ++ * internal memory address. Unfortunately, some of the API's use a ++ * page/offset format where the offset value is JUST the lower seven ++ * bits and the page is the remaining 16 bits. Some of the API's ++ * assume that the 23 bit address has been split at the 16th bit. We ++ * refer to these two formats as AUX format and CMD format. The ++ * macros below help handle some of this. ++ */ ++ ++/* Handy constant */ ++#define HFA384x_ADDR_AUX_OFF_MAX ((u16)0x007f) ++ ++/* Mask bits for discarding unwanted pieces in a flat address */ ++#define HFA384x_ADDR_FLAT_AUX_PAGE_MASK (0x007fff80) ++#define HFA384x_ADDR_FLAT_AUX_OFF_MASK (0x0000007f) ++#define HFA384x_ADDR_FLAT_CMD_PAGE_MASK (0xffff0000) ++#define HFA384x_ADDR_FLAT_CMD_OFF_MASK (0x0000ffff) ++ ++/* Mask bits for discarding unwanted pieces in AUX format 16-bit address parts */ ++#define HFA384x_ADDR_AUX_PAGE_MASK (0xffff) ++#define HFA384x_ADDR_AUX_OFF_MASK (0x007f) ++ ++/* Mask bits for discarding unwanted pieces in CMD format 16-bit address parts */ ++#define HFA384x_ADDR_CMD_PAGE_MASK (0x007f) ++#define HFA384x_ADDR_CMD_OFF_MASK (0xffff) ++ ++/* Make a 32-bit flat address from AUX format 16-bit page and offset */ ++#define HFA384x_ADDR_AUX_MKFLAT(p,o) \ ++ (((u32)(((u16)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) <<7) | \ ++ ((u32)(((u16)(o))&HFA384x_ADDR_AUX_OFF_MASK)) ++ ++/* Make a 32-bit flat address from CMD format 16-bit page and offset */ ++#define HFA384x_ADDR_CMD_MKFLAT(p,o) \ ++ (((u32)(((u16)(p))&HFA384x_ADDR_CMD_PAGE_MASK)) <<16) | \ ++ ((u32)(((u16)(o))&HFA384x_ADDR_CMD_OFF_MASK)) ++ ++/* Make AUX format offset and page from a 32-bit flat address */ ++#define HFA384x_ADDR_AUX_MKPAGE(f) \ ++ ((u16)((((u32)(f))&HFA384x_ADDR_FLAT_AUX_PAGE_MASK)>>7)) ++#define HFA384x_ADDR_AUX_MKOFF(f) \ ++ ((u16)(((u32)(f))&HFA384x_ADDR_FLAT_AUX_OFF_MASK)) ++ ++/* Make CMD format offset and page from a 32-bit flat address */ ++#define HFA384x_ADDR_CMD_MKPAGE(f) \ ++ ((u16)((((u32)(f))&HFA384x_ADDR_FLAT_CMD_PAGE_MASK)>>16)) ++#define HFA384x_ADDR_CMD_MKOFF(f) \ ++ ((u16)(((u32)(f))&HFA384x_ADDR_FLAT_CMD_OFF_MASK)) ++ ++/*--- Aux register masks/tests ----------------------*/ ++/* Some of the upper bits of the AUX offset register are used to */ ++/* select address space. */ ++#define HFA384x_AUX_CTL_EXTDS (0x00) ++#define HFA384x_AUX_CTL_NV (0x01) ++#define HFA384x_AUX_CTL_PHY (0x02) ++#define HFA384x_AUX_CTL_ICSRAM (0x03) ++ ++/* Make AUX register offset and page values from a flat address */ ++#define HFA384x_AUX_MKOFF(f, c) \ ++ (HFA384x_ADDR_AUX_MKOFF(f) | (((u16)(c))<<12)) ++#define HFA384x_AUX_MKPAGE(f) HFA384x_ADDR_AUX_MKPAGE(f) ++ ++ ++/*--- Controller Memory addresses -------------------*/ ++#define HFA3842_PDA_BASE (0x007f0000UL) ++#define HFA3841_PDA_BASE (0x003f0000UL) ++#define HFA3841_PDA_BOGUS_BASE (0x00390000UL) ++ ++/*--- Driver Download states -----------------------*/ ++#define HFA384x_DLSTATE_DISABLED 0 ++#define HFA384x_DLSTATE_RAMENABLED 1 ++#define HFA384x_DLSTATE_FLASHENABLED 2 ++#define HFA384x_DLSTATE_FLASHWRITTEN 3 ++#define HFA384x_DLSTATE_FLASHWRITEPENDING 4 ++#define HFA384x_DLSTATE_GENESIS 5 ++ ++#define HFA384x_CMD_OFF (0x00) ++#define HFA384x_PARAM0_OFF (0x04) ++#define HFA384x_PARAM1_OFF (0x08) ++#define HFA384x_PARAM2_OFF (0x0c) ++#define HFA384x_STATUS_OFF (0x10) ++#define HFA384x_RESP0_OFF (0x14) ++#define HFA384x_RESP1_OFF (0x18) ++#define HFA384x_RESP2_OFF (0x1c) ++#define HFA384x_INFOFID_OFF (0x20) ++#define HFA384x_RXFID_OFF (0x40) ++#define HFA384x_ALLOCFID_OFF (0x44) ++#define HFA384x_TXCOMPLFID_OFF (0x48) ++#define HFA384x_SELECT0_OFF (0x30) ++#define HFA384x_OFFSET0_OFF (0x38) ++#define HFA384x_DATA0_OFF (0x6c) ++#define HFA384x_SELECT1_OFF (0x34) ++#define HFA384x_OFFSET1_OFF (0x3c) ++#define HFA384x_DATA1_OFF (0x70) ++#define HFA384x_EVSTAT_OFF (0x60) ++#define HFA384x_intEN_OFF (0x64) ++#define HFA384x_EVACK_OFF (0x68) ++#define HFA384x_CONTROL_OFF (0x28) ++#define HFA384x_SWSUPPORT0_OFF (0x50) ++#define HFA384x_SWSUPPORT1_OFF (0x54) ++#define HFA384x_SWSUPPORT2_OFF (0x58) ++#define HFA384x_AUXPAGE_OFF (0x74) ++#define HFA384x_AUXOFFSET_OFF (0x78) ++#define HFA384x_AUXDATA_OFF (0x7c) ++#define HFA384x_PCICOR_OFF (0x4c) ++#define HFA384x_PCIHCR_OFF (0x5c) ++#define HFA384x_PCI_M0_ADDRH_OFF (0x80) ++#define HFA384x_PCI_M0_ADDRL_OFF (0x84) ++#define HFA384x_PCI_M0_LEN_OFF (0x88) ++#define HFA384x_PCI_M0_CTL_OFF (0x8c) ++#define HFA384x_PCI_STATUS_OFF (0x98) ++#define HFA384x_PCI_M1_ADDRH_OFF (0xa0) ++#define HFA384x_PCI_M1_ADDRL_OFF (0xa4) ++#define HFA384x_PCI_M1_LEN_OFF (0xa8) ++#define HFA384x_PCI_M1_CTL_OFF (0xac) ++ ++/*--- Register Field Masks --------------------------*/ ++#define HFA384x_CMD_BUSY ((u16)BIT15) ++#define HFA384x_CMD_AINFO ((u16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) ++#define HFA384x_CMD_MACPORT ((u16)(BIT10 | BIT9 | BIT8)) ++#define HFA384x_CMD_RECL ((u16)BIT8) ++#define HFA384x_CMD_WRITE ((u16)BIT8) ++#define HFA384x_CMD_PROGMODE ((u16)(BIT9 | BIT8)) ++#define HFA384x_CMD_CMDCODE ((u16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) ++ ++#define HFA384x_STATUS_RESULT ((u16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) ++#define HFA384x_STATUS_CMDCODE ((u16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) ++ ++#define HFA384x_OFFSET_BUSY ((u16)BIT15) ++#define HFA384x_OFFSET_ERR ((u16)BIT14) ++#define HFA384x_OFFSET_DATAOFF ((u16)(BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1)) ++ ++#define HFA384x_EVSTAT_TICK ((u16)BIT15) ++#define HFA384x_EVSTAT_WTERR ((u16)BIT14) ++#define HFA384x_EVSTAT_INFDROP ((u16)BIT13) ++#define HFA384x_EVSTAT_INFO ((u16)BIT7) ++#define HFA384x_EVSTAT_DTIM ((u16)BIT5) ++#define HFA384x_EVSTAT_CMD ((u16)BIT4) ++#define HFA384x_EVSTAT_ALLOC ((u16)BIT3) ++#define HFA384x_EVSTAT_TXEXC ((u16)BIT2) ++#define HFA384x_EVSTAT_TX ((u16)BIT1) ++#define HFA384x_EVSTAT_RX ((u16)BIT0) ++ ++#define HFA384x_int_BAP_OP (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC) ++ ++#define HFA384x_int_NORMAL (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC|HFA384x_EVSTAT_INFDROP|HFA384x_EVSTAT_ALLOC|HFA384x_EVSTAT_DTIM) ++ ++#define HFA384x_intEN_TICK ((u16)BIT15) ++#define HFA384x_intEN_WTERR ((u16)BIT14) ++#define HFA384x_intEN_INFDROP ((u16)BIT13) ++#define HFA384x_intEN_INFO ((u16)BIT7) ++#define HFA384x_intEN_DTIM ((u16)BIT5) ++#define HFA384x_intEN_CMD ((u16)BIT4) ++#define HFA384x_intEN_ALLOC ((u16)BIT3) ++#define HFA384x_intEN_TXEXC ((u16)BIT2) ++#define HFA384x_intEN_TX ((u16)BIT1) ++#define HFA384x_intEN_RX ((u16)BIT0) ++ ++#define HFA384x_EVACK_TICK ((u16)BIT15) ++#define HFA384x_EVACK_WTERR ((u16)BIT14) ++#define HFA384x_EVACK_INFDROP ((u16)BIT13) ++#define HFA384x_EVACK_INFO ((u16)BIT7) ++#define HFA384x_EVACK_DTIM ((u16)BIT5) ++#define HFA384x_EVACK_CMD ((u16)BIT4) ++#define HFA384x_EVACK_ALLOC ((u16)BIT3) ++#define HFA384x_EVACK_TXEXC ((u16)BIT2) ++#define HFA384x_EVACK_TX ((u16)BIT1) ++#define HFA384x_EVACK_RX ((u16)BIT0) ++ ++#define HFA384x_CONTROL_AUXEN ((u16)(BIT15 | BIT14)) ++ ++ ++/*--- Command Code Constants --------------------------*/ ++/*--- Controller Commands --------------------------*/ ++#define HFA384x_CMDCODE_INIT ((u16)0x00) ++#define HFA384x_CMDCODE_ENABLE ((u16)0x01) ++#define HFA384x_CMDCODE_DISABLE ((u16)0x02) ++#define HFA384x_CMDCODE_DIAG ((u16)0x03) ++ ++/*--- Buffer Mgmt Commands --------------------------*/ ++#define HFA384x_CMDCODE_ALLOC ((u16)0x0A) ++#define HFA384x_CMDCODE_TX ((u16)0x0B) ++#define HFA384x_CMDCODE_CLRPRST ((u16)0x12) ++ ++/*--- Regulate Commands --------------------------*/ ++#define HFA384x_CMDCODE_NOTIFY ((u16)0x10) ++#define HFA384x_CMDCODE_INQ ((u16)0x11) ++ ++/*--- Configure Commands --------------------------*/ ++#define HFA384x_CMDCODE_ACCESS ((u16)0x21) ++#define HFA384x_CMDCODE_DOWNLD ((u16)0x22) ++ ++/*--- Debugging Commands -----------------------------*/ ++#define HFA384x_CMDCODE_MONITOR ((u16)(0x38)) ++#define HFA384x_MONITOR_ENABLE ((u16)(0x0b)) ++#define HFA384x_MONITOR_DISABLE ((u16)(0x0f)) ++ ++/*--- Result Codes --------------------------*/ ++#define HFA384x_SUCCESS ((u16)(0x00)) ++#define HFA384x_CARD_FAIL ((u16)(0x01)) ++#define HFA384x_NO_BUFF ((u16)(0x05)) ++#define HFA384x_CMD_ERR ((u16)(0x7F)) ++ ++/*--- Programming Modes -------------------------- ++ MODE 0: Disable programming ++ MODE 1: Enable volatile memory programming ++ MODE 2: Enable non-volatile memory programming ++ MODE 3: Program non-volatile memory section ++--------------------------------------------------*/ ++#define HFA384x_PROGMODE_DISABLE ((u16)0x00) ++#define HFA384x_PROGMODE_RAM ((u16)0x01) ++#define HFA384x_PROGMODE_NV ((u16)0x02) ++#define HFA384x_PROGMODE_NVWRITE ((u16)0x03) ++ ++/*--- AUX register enable --------------------------*/ ++#define HFA384x_AUXPW0 ((u16)0xfe01) ++#define HFA384x_AUXPW1 ((u16)0xdc23) ++#define HFA384x_AUXPW2 ((u16)0xba45) ++ ++#define HFA384x_CONTROL_AUX_ISDISABLED ((u16)0x0000) ++#define HFA384x_CONTROL_AUX_ISENABLED ((u16)0xc000) ++#define HFA384x_CONTROL_AUX_DOENABLE ((u16)0x8000) ++#define HFA384x_CONTROL_AUX_DODISABLE ((u16)0x4000) ++ ++/*--- Record ID Constants --------------------------*/ ++/*-------------------------------------------------------------------- ++Configuration RIDs: Network Parameters, Static Configuration Entities ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_CNFPORTTYPE ((u16)0xFC00) ++#define HFA384x_RID_CNFOWNMACADDR ((u16)0xFC01) ++#define HFA384x_RID_CNFDESIREDSSID ((u16)0xFC02) ++#define HFA384x_RID_CNFOWNCHANNEL ((u16)0xFC03) ++#define HFA384x_RID_CNFOWNSSID ((u16)0xFC04) ++#define HFA384x_RID_CNFOWNATIMWIN ((u16)0xFC05) ++#define HFA384x_RID_CNFSYSSCALE ((u16)0xFC06) ++#define HFA384x_RID_CNFMAXDATALEN ((u16)0xFC07) ++#define HFA384x_RID_CNFWDSADDR ((u16)0xFC08) ++#define HFA384x_RID_CNFPMENABLED ((u16)0xFC09) ++#define HFA384x_RID_CNFPMEPS ((u16)0xFC0A) ++#define HFA384x_RID_CNFMULTICASTRX ((u16)0xFC0B) ++#define HFA384x_RID_CNFMAXSLEEPDUR ((u16)0xFC0C) ++#define HFA384x_RID_CNFPMHOLDDUR ((u16)0xFC0D) ++#define HFA384x_RID_CNFOWNNAME ((u16)0xFC0E) ++#define HFA384x_RID_CNFOWNDTIMPER ((u16)0xFC10) ++#define HFA384x_RID_CNFWDSADDR1 ((u16)0xFC11) ++#define HFA384x_RID_CNFWDSADDR2 ((u16)0xFC12) ++#define HFA384x_RID_CNFWDSADDR3 ((u16)0xFC13) ++#define HFA384x_RID_CNFWDSADDR4 ((u16)0xFC14) ++#define HFA384x_RID_CNFWDSADDR5 ((u16)0xFC15) ++#define HFA384x_RID_CNFWDSADDR6 ((u16)0xFC16) ++#define HFA384x_RID_CNFMCASTPMBUFF ((u16)0xFC17) ++ ++/*-------------------------------------------------------------------- ++Configuration RID lengths: Network Params, Static Config Entities ++ This is the length of JUST the DATA part of the RID (does not ++ include the len or code fields) ++--------------------------------------------------------------------*/ ++/* TODO: fill in the rest of these */ ++#define HFA384x_RID_CNFPORTTYPE_LEN ((u16)2) ++#define HFA384x_RID_CNFOWNMACADDR_LEN ((u16)6) ++#define HFA384x_RID_CNFDESIREDSSID_LEN ((u16)34) ++#define HFA384x_RID_CNFOWNCHANNEL_LEN ((u16)2) ++#define HFA384x_RID_CNFOWNSSID_LEN ((u16)34) ++#define HFA384x_RID_CNFOWNATIMWIN_LEN ((u16)2) ++#define HFA384x_RID_CNFSYSSCALE_LEN ((u16)0) ++#define HFA384x_RID_CNFMAXDATALEN_LEN ((u16)0) ++#define HFA384x_RID_CNFWDSADDR_LEN ((u16)6) ++#define HFA384x_RID_CNFPMENABLED_LEN ((u16)0) ++#define HFA384x_RID_CNFPMEPS_LEN ((u16)0) ++#define HFA384x_RID_CNFMULTICASTRX_LEN ((u16)0) ++#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((u16)0) ++#define HFA384x_RID_CNFPMHOLDDUR_LEN ((u16)0) ++#define HFA384x_RID_CNFOWNNAME_LEN ((u16)34) ++#define HFA384x_RID_CNFOWNDTIMPER_LEN ((u16)0) ++#define HFA384x_RID_CNFWDSADDR1_LEN ((u16)6) ++#define HFA384x_RID_CNFWDSADDR2_LEN ((u16)6) ++#define HFA384x_RID_CNFWDSADDR3_LEN ((u16)6) ++#define HFA384x_RID_CNFWDSADDR4_LEN ((u16)6) ++#define HFA384x_RID_CNFWDSADDR5_LEN ((u16)6) ++#define HFA384x_RID_CNFWDSADDR6_LEN ((u16)6) ++#define HFA384x_RID_CNFMCASTPMBUFF_LEN ((u16)0) ++#define HFA384x_RID_CNFAUTHENTICATION_LEN ((u16)sizeof(u16)) ++#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((u16)0) ++ ++/*-------------------------------------------------------------------- ++Configuration RIDs: Network Parameters, Dynamic Configuration Entities ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_GROUPADDR ((u16)0xFC80) ++#define HFA384x_RID_CREATEIBSS ((u16)0xFC81) ++#define HFA384x_RID_FRAGTHRESH ((u16)0xFC82) ++#define HFA384x_RID_RTSTHRESH ((u16)0xFC83) ++#define HFA384x_RID_TXRATECNTL ((u16)0xFC84) ++#define HFA384x_RID_PROMISCMODE ((u16)0xFC85) ++#define HFA384x_RID_FRAGTHRESH0 ((u16)0xFC90) ++#define HFA384x_RID_FRAGTHRESH1 ((u16)0xFC91) ++#define HFA384x_RID_FRAGTHRESH2 ((u16)0xFC92) ++#define HFA384x_RID_FRAGTHRESH3 ((u16)0xFC93) ++#define HFA384x_RID_FRAGTHRESH4 ((u16)0xFC94) ++#define HFA384x_RID_FRAGTHRESH5 ((u16)0xFC95) ++#define HFA384x_RID_FRAGTHRESH6 ((u16)0xFC96) ++#define HFA384x_RID_RTSTHRESH0 ((u16)0xFC97) ++#define HFA384x_RID_RTSTHRESH1 ((u16)0xFC98) ++#define HFA384x_RID_RTSTHRESH2 ((u16)0xFC99) ++#define HFA384x_RID_RTSTHRESH3 ((u16)0xFC9A) ++#define HFA384x_RID_RTSTHRESH4 ((u16)0xFC9B) ++#define HFA384x_RID_RTSTHRESH5 ((u16)0xFC9C) ++#define HFA384x_RID_RTSTHRESH6 ((u16)0xFC9D) ++#define HFA384x_RID_TXRATECNTL0 ((u16)0xFC9E) ++#define HFA384x_RID_TXRATECNTL1 ((u16)0xFC9F) ++#define HFA384x_RID_TXRATECNTL2 ((u16)0xFCA0) ++#define HFA384x_RID_TXRATECNTL3 ((u16)0xFCA1) ++#define HFA384x_RID_TXRATECNTL4 ((u16)0xFCA2) ++#define HFA384x_RID_TXRATECNTL5 ((u16)0xFCA3) ++#define HFA384x_RID_TXRATECNTL6 ((u16)0xFCA4) ++ ++/*-------------------------------------------------------------------- ++Configuration RID Lengths: Network Param, Dynamic Config Entities ++ This is the length of JUST the DATA part of the RID (does not ++ include the len or code fields) ++--------------------------------------------------------------------*/ ++/* TODO: fill in the rest of these */ ++#define HFA384x_RID_GROUPADDR_LEN ((u16)16 * WLAN_ADDR_LEN) ++#define HFA384x_RID_CREATEIBSS_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL_LEN ((u16)4) ++#define HFA384x_RID_PROMISCMODE_LEN ((u16)2) ++#define HFA384x_RID_FRAGTHRESH0_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH1_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH2_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH3_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH4_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH5_LEN ((u16)0) ++#define HFA384x_RID_FRAGTHRESH6_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH0_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH1_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH2_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH3_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH4_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH5_LEN ((u16)0) ++#define HFA384x_RID_RTSTHRESH6_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL0_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL1_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL2_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL3_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL4_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL5_LEN ((u16)0) ++#define HFA384x_RID_TXRATECNTL6_LEN ((u16)0) ++ ++/*-------------------------------------------------------------------- ++Configuration RIDs: Behavior Parameters ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_ITICKTIME ((u16)0xFCE0) ++ ++/*-------------------------------------------------------------------- ++Configuration RID Lengths: Behavior Parameters ++ This is the length of JUST the DATA part of the RID (does not ++ include the len or code fields) ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_ITICKTIME_LEN ((u16)2) ++ ++/*---------------------------------------------------------------------- ++Information RIDs: NIC Information ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_MAXLOADTIME ((u16)0xFD00) ++#define HFA384x_RID_DOWNLOADBUFFER ((u16)0xFD01) ++#define HFA384x_RID_PRIIDENTITY ((u16)0xFD02) ++#define HFA384x_RID_PRISUPRANGE ((u16)0xFD03) ++#define HFA384x_RID_PRI_CFIACTRANGES ((u16)0xFD04) ++#define HFA384x_RID_NICSERIALNUMBER ((u16)0xFD0A) ++#define HFA384x_RID_NICIDENTITY ((u16)0xFD0B) ++#define HFA384x_RID_MFISUPRANGE ((u16)0xFD0C) ++#define HFA384x_RID_CFISUPRANGE ((u16)0xFD0D) ++#define HFA384x_RID_CHANNELLIST ((u16)0xFD10) ++#define HFA384x_RID_REGULATORYDOMAINS ((u16)0xFD11) ++#define HFA384x_RID_TEMPTYPE ((u16)0xFD12) ++#define HFA384x_RID_CIS ((u16)0xFD13) ++#define HFA384x_RID_STAIDENTITY ((u16)0xFD20) ++#define HFA384x_RID_STASUPRANGE ((u16)0xFD21) ++#define HFA384x_RID_STA_MFIACTRANGES ((u16)0xFD22) ++#define HFA384x_RID_STA_CFIACTRANGES ((u16)0xFD23) ++#define HFA384x_RID_BUILDSEQ ((u16)0xFFFE) ++#define HFA384x_RID_FWID ((u16)0xFFFF) ++ ++/*---------------------------------------------------------------------- ++Information RID Lengths: NIC Information ++ This is the length of JUST the DATA part of the RID (does not ++ include the len or code fields) ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_MAXLOADTIME_LEN ((u16)0) ++#define HFA384x_RID_DOWNLOADBUFFER_LEN ((u16)sizeof(hfa384x_downloadbuffer_t)) ++#define HFA384x_RID_PRIIDENTITY_LEN ((u16)8) ++#define HFA384x_RID_PRISUPRANGE_LEN ((u16)10) ++#define HFA384x_RID_CFIACTRANGES_LEN ((u16)10) ++#define HFA384x_RID_NICSERIALNUMBER_LEN ((u16)12) ++#define HFA384x_RID_NICIDENTITY_LEN ((u16)8) ++#define HFA384x_RID_MFISUPRANGE_LEN ((u16)10) ++#define HFA384x_RID_CFISUPRANGE_LEN ((u16)10) ++#define HFA384x_RID_CHANNELLIST_LEN ((u16)0) ++#define HFA384x_RID_REGULATORYDOMAINS_LEN ((u16)12) ++#define HFA384x_RID_TEMPTYPE_LEN ((u16)0) ++#define HFA384x_RID_CIS_LEN ((u16)480) ++#define HFA384x_RID_STAIDENTITY_LEN ((u16)8) ++#define HFA384x_RID_STASUPRANGE_LEN ((u16)10) ++#define HFA384x_RID_MFIACTRANGES_LEN ((u16)10) ++#define HFA384x_RID_CFIACTRANGES2_LEN ((u16)10) ++#define HFA384x_RID_BUILDSEQ_LEN ((u16)sizeof(hfa384x_BuildSeq_t)) ++#define HFA384x_RID_FWID_LEN ((u16)sizeof(hfa384x_FWID_t)) ++ ++/*-------------------------------------------------------------------- ++Information RIDs: MAC Information ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_PORTSTATUS ((u16)0xFD40) ++#define HFA384x_RID_CURRENTSSID ((u16)0xFD41) ++#define HFA384x_RID_CURRENTBSSID ((u16)0xFD42) ++#define HFA384x_RID_COMMSQUALITY ((u16)0xFD43) ++#define HFA384x_RID_CURRENTTXRATE ((u16)0xFD44) ++#define HFA384x_RID_CURRENTBCNint ((u16)0xFD45) ++#define HFA384x_RID_CURRENTSCALETHRESH ((u16)0xFD46) ++#define HFA384x_RID_PROTOCOLRSPTIME ((u16)0xFD47) ++#define HFA384x_RID_SHORTRETRYLIMIT ((u16)0xFD48) ++#define HFA384x_RID_LONGRETRYLIMIT ((u16)0xFD49) ++#define HFA384x_RID_MAXTXLIFETIME ((u16)0xFD4A) ++#define HFA384x_RID_MAXRXLIFETIME ((u16)0xFD4B) ++#define HFA384x_RID_CFPOLLABLE ((u16)0xFD4C) ++#define HFA384x_RID_AUTHALGORITHMS ((u16)0xFD4D) ++#define HFA384x_RID_PRIVACYOPTIMP ((u16)0xFD4F) ++#define HFA384x_RID_DBMCOMMSQUALITY ((u16)0xFD51) ++#define HFA384x_RID_CURRENTTXRATE1 ((u16)0xFD80) ++#define HFA384x_RID_CURRENTTXRATE2 ((u16)0xFD81) ++#define HFA384x_RID_CURRENTTXRATE3 ((u16)0xFD82) ++#define HFA384x_RID_CURRENTTXRATE4 ((u16)0xFD83) ++#define HFA384x_RID_CURRENTTXRATE5 ((u16)0xFD84) ++#define HFA384x_RID_CURRENTTXRATE6 ((u16)0xFD85) ++#define HFA384x_RID_OWNMACADDRESS ((u16)0xFD86) ++// #define HFA384x_RID_PCFINFO ((u16)0xFD87) ++#define HFA384x_RID_SCANRESULTS ((u16)0xFD88) // NEW ++#define HFA384x_RID_HOSTSCANRESULTS ((u16)0xFD89) // NEW ++#define HFA384x_RID_AUTHENTICATIONUSED ((u16)0xFD8A) // NEW ++#define HFA384x_RID_ASSOCIATEFAILURE ((u16)0xFD8D) // 1.8.0 ++ ++/*-------------------------------------------------------------------- ++Information RID Lengths: MAC Information ++ This is the length of JUST the DATA part of the RID (does not ++ include the len or code fields) ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_PORTSTATUS_LEN ((u16)0) ++#define HFA384x_RID_CURRENTSSID_LEN ((u16)34) ++#define HFA384x_RID_CURRENTBSSID_LEN ((u16)WLAN_BSSID_LEN) ++#define HFA384x_RID_COMMSQUALITY_LEN ((u16)sizeof(hfa384x_commsquality_t)) ++#define HFA384x_RID_DBMCOMMSQUALITY_LEN ((u16)sizeof(hfa384x_dbmcommsquality_t)) ++#define HFA384x_RID_CURRENTTXRATE_LEN ((u16)0) ++#define HFA384x_RID_CURRENTBCNint_LEN ((u16)0) ++#define HFA384x_RID_STACURSCALETHRESH_LEN ((u16)12) ++#define HFA384x_RID_APCURSCALETHRESH_LEN ((u16)6) ++#define HFA384x_RID_PROTOCOLRSPTIME_LEN ((u16)0) ++#define HFA384x_RID_SHORTRETRYLIMIT_LEN ((u16)0) ++#define HFA384x_RID_LONGRETRYLIMIT_LEN ((u16)0) ++#define HFA384x_RID_MAXTXLIFETIME_LEN ((u16)0) ++#define HFA384x_RID_MAXRXLIFETIME_LEN ((u16)0) ++#define HFA384x_RID_CFPOLLABLE_LEN ((u16)0) ++#define HFA384x_RID_AUTHALGORITHMS_LEN ((u16)4) ++#define HFA384x_RID_PRIVACYOPTIMP_LEN ((u16)0) ++#define HFA384x_RID_CURRENTTXRATE1_LEN ((u16)0) ++#define HFA384x_RID_CURRENTTXRATE2_LEN ((u16)0) ++#define HFA384x_RID_CURRENTTXRATE3_LEN ((u16)0) ++#define HFA384x_RID_CURRENTTXRATE4_LEN ((u16)0) ++#define HFA384x_RID_CURRENTTXRATE5_LEN ((u16)0) ++#define HFA384x_RID_CURRENTTXRATE6_LEN ((u16)0) ++#define HFA384x_RID_OWNMACADDRESS_LEN ((u16)6) ++#define HFA384x_RID_PCFINFO_LEN ((u16)6) ++#define HFA384x_RID_CNFAPPCFINFO_LEN ((u16)sizeof(hfa384x_PCFInfo_data_t)) ++#define HFA384x_RID_SCANREQUEST_LEN ((u16)sizeof(hfa384x_ScanRequest_data_t)) ++#define HFA384x_RID_JOINREQUEST_LEN ((u16)sizeof(hfa384x_JoinRequest_data_t)) ++#define HFA384x_RID_AUTHENTICATESTA_LEN ((u16)sizeof(hfa384x_authenticateStation_data_t)) ++#define HFA384x_RID_CHANNELINFOREQUEST_LEN ((u16)sizeof(hfa384x_ChannelInfoRequest_data_t)) ++/*-------------------------------------------------------------------- ++Information RIDs: Modem Information ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_PHYTYPE ((u16)0xFDC0) ++#define HFA384x_RID_CURRENTCHANNEL ((u16)0xFDC1) ++#define HFA384x_RID_CURRENTPOWERSTATE ((u16)0xFDC2) ++#define HFA384x_RID_CCAMODE ((u16)0xFDC3) ++#define HFA384x_RID_SUPPORTEDDATARATES ((u16)0xFDC6) ++#define HFA384x_RID_LFOSTATUS ((u16)0xFDC7) // 1.7.1 ++ ++/*-------------------------------------------------------------------- ++Information RID Lengths: Modem Information ++ This is the length of JUST the DATA part of the RID (does not ++ include the len or code fields) ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_PHYTYPE_LEN ((u16)0) ++#define HFA384x_RID_CURRENTCHANNEL_LEN ((u16)0) ++#define HFA384x_RID_CURRENTPOWERSTATE_LEN ((u16)0) ++#define HFA384x_RID_CCAMODE_LEN ((u16)0) ++#define HFA384x_RID_SUPPORTEDDATARATES_LEN ((u16)10) ++ ++/*-------------------------------------------------------------------- ++API ENHANCEMENTS (NOT ALREADY IMPLEMENTED) ++--------------------------------------------------------------------*/ ++#define HFA384x_RID_CNFWEPDEFAULTKEYID ((u16)0xFC23) ++#define HFA384x_RID_CNFWEPDEFAULTKEY0 ((u16)0xFC24) ++#define HFA384x_RID_CNFWEPDEFAULTKEY1 ((u16)0xFC25) ++#define HFA384x_RID_CNFWEPDEFAULTKEY2 ((u16)0xFC26) ++#define HFA384x_RID_CNFWEPDEFAULTKEY3 ((u16)0xFC27) ++#define HFA384x_RID_CNFWEPFLAGS ((u16)0xFC28) ++#define HFA384x_RID_CNFWEPKEYMAPTABLE ((u16)0xFC29) ++#define HFA384x_RID_CNFAUTHENTICATION ((u16)0xFC2A) ++#define HFA384x_RID_CNFMAXASSOCSTATIONS ((u16)0xFC2B) ++#define HFA384x_RID_CNFTXCONTROL ((u16)0xFC2C) ++#define HFA384x_RID_CNFROAMINGMODE ((u16)0xFC2D) ++#define HFA384x_RID_CNFHOSTAUTHASSOC ((u16)0xFC2E) ++#define HFA384x_RID_CNFRCVCRCERROR ((u16)0xFC30) ++// #define HFA384x_RID_CNFMMLIFE ((u16)0xFC31) ++#define HFA384x_RID_CNFALTRETRYCNT ((u16)0xFC32) ++#define HFA384x_RID_CNFAPBCNint ((u16)0xFC33) ++#define HFA384x_RID_CNFAPPCFINFO ((u16)0xFC34) ++#define HFA384x_RID_CNFSTAPCFINFO ((u16)0xFC35) ++#define HFA384x_RID_CNFPRIORITYQUSAGE ((u16)0xFC37) ++#define HFA384x_RID_CNFTIMCTRL ((u16)0xFC40) ++#define HFA384x_RID_CNFTHIRTY2TALLY ((u16)0xFC42) ++#define HFA384x_RID_CNFENHSECURITY ((u16)0xFC43) ++#define HFA384x_RID_CNFDBMADJUST ((u16)0xFC46) // NEW ++#define HFA384x_RID_CNFWPADATA ((u16)0xFC48) // 1.7.0 ++#define HFA384x_RID_CNFPROPOGATIONDELAY ((u16)0xFC49) // 1.7.6 ++#define HFA384x_RID_CNFSHORTPREAMBLE ((u16)0xFCB0) ++#define HFA384x_RID_CNFEXCLONGPREAMBLE ((u16)0xFCB1) ++#define HFA384x_RID_CNFAUTHRSPTIMEOUT ((u16)0xFCB2) ++#define HFA384x_RID_CNFBASICRATES ((u16)0xFCB3) ++#define HFA384x_RID_CNFSUPPRATES ((u16)0xFCB4) ++#define HFA384x_RID_CNFFALLBACKCTRL ((u16)0xFCB5) // NEW ++#define HFA384x_RID_WEPKEYSTATUS ((u16)0xFCB6) // NEW ++#define HFA384x_RID_WEPKEYMAPINDEX ((u16)0xFCB7) // NEW ++#define HFA384x_RID_BROADCASTKEYID ((u16)0xFCB8) // NEW ++#define HFA384x_RID_ENTSECFLAGEYID ((u16)0xFCB9) // NEW ++#define HFA384x_RID_CNFPASSIVESCANCTRL ((u16)0xFCBA) // NEW STA ++#define HFA384x_RID_CNFWPAHANDLING ((u16)0xFCBB) // 1.7.0 ++#define HFA384x_RID_MDCCONTROL ((u16)0xFCBC) // 1.7.0/1.4.0 ++#define HFA384x_RID_MDCCOUNTRY ((u16)0xFCBD) // 1.7.0/1.4.0 ++#define HFA384x_RID_TXPOWERMAX ((u16)0xFCBE) // 1.7.0/1.4.0 ++#define HFA384x_RID_CNFLFOENBLED ((u16)0xFCBF) // 1.6.3 ++#define HFA384x_RID_CAPINFO ((u16)0xFCC0) // 1.7.0/1.3.7 ++#define HFA384x_RID_LISTENintERVAL ((u16)0xFCC1) // 1.7.0/1.3.7 ++#define HFA384x_RID_DIVERSITYENABLED ((u16)0xFCC2) // 1.7.0/1.3.7 ++#define HFA384x_RID_LED_CONTROL ((u16)0xFCC4) // 1.7.6 ++#define HFA384x_RID_HFO_DELAY ((u16)0xFCC5) // 1.7.6 ++#define HFA384x_RID_DISSALOWEDBSSID ((u16)0xFCC6) // 1.8.0 ++#define HFA384x_RID_SCANREQUEST ((u16)0xFCE1) ++#define HFA384x_RID_JOINREQUEST ((u16)0xFCE2) ++#define HFA384x_RID_AUTHENTICATESTA ((u16)0xFCE3) ++#define HFA384x_RID_CHANNELINFOREQUEST ((u16)0xFCE4) ++#define HFA384x_RID_HOSTSCAN ((u16)0xFCE5) // NEW STA ++#define HFA384x_RID_ASSOCIATESTA ((u16)0xFCE6) ++ ++#define HFA384x_RID_CNFWEPDEFAULTKEY_LEN ((u16)6) ++#define HFA384x_RID_CNFWEP128DEFAULTKEY_LEN ((u16)14) ++#define HFA384x_RID_CNFPRIOQUSAGE_LEN ((u16)4) ++/*-------------------------------------------------------------------- ++PD Record codes ++--------------------------------------------------------------------*/ ++#define HFA384x_PDR_PCB_PARTNUM ((u16)0x0001) ++#define HFA384x_PDR_PDAVER ((u16)0x0002) ++#define HFA384x_PDR_NIC_SERIAL ((u16)0x0003) ++#define HFA384x_PDR_MKK_MEASUREMENTS ((u16)0x0004) ++#define HFA384x_PDR_NIC_RAMSIZE ((u16)0x0005) ++#define HFA384x_PDR_MFISUPRANGE ((u16)0x0006) ++#define HFA384x_PDR_CFISUPRANGE ((u16)0x0007) ++#define HFA384x_PDR_NICID ((u16)0x0008) ++//#define HFA384x_PDR_REFDAC_MEASUREMENTS ((u16)0x0010) ++//#define HFA384x_PDR_VGDAC_MEASUREMENTS ((u16)0x0020) ++//#define HFA384x_PDR_LEVEL_COMP_MEASUREMENTS ((u16)0x0030) ++//#define HFA384x_PDR_MODEM_TRIMDAC_MEASUREMENTS ((u16)0x0040) ++//#define HFA384x_PDR_COREGA_HACK ((u16)0x00ff) ++#define HFA384x_PDR_MAC_ADDRESS ((u16)0x0101) ++//#define HFA384x_PDR_MKK_CALLNAME ((u16)0x0102) ++#define HFA384x_PDR_REGDOMAIN ((u16)0x0103) ++#define HFA384x_PDR_ALLOWED_CHANNEL ((u16)0x0104) ++#define HFA384x_PDR_DEFAULT_CHANNEL ((u16)0x0105) ++//#define HFA384x_PDR_PRIVACY_OPTION ((u16)0x0106) ++#define HFA384x_PDR_TEMPTYPE ((u16)0x0107) ++//#define HFA384x_PDR_REFDAC_SETUP ((u16)0x0110) ++//#define HFA384x_PDR_VGDAC_SETUP ((u16)0x0120) ++//#define HFA384x_PDR_LEVEL_COMP_SETUP ((u16)0x0130) ++//#define HFA384x_PDR_TRIMDAC_SETUP ((u16)0x0140) ++#define HFA384x_PDR_IFR_SETTING ((u16)0x0200) ++#define HFA384x_PDR_RFR_SETTING ((u16)0x0201) ++#define HFA384x_PDR_HFA3861_BASELINE ((u16)0x0202) ++#define HFA384x_PDR_HFA3861_SHADOW ((u16)0x0203) ++#define HFA384x_PDR_HFA3861_IFRF ((u16)0x0204) ++#define HFA384x_PDR_HFA3861_CHCALSP ((u16)0x0300) ++#define HFA384x_PDR_HFA3861_CHCALI ((u16)0x0301) ++#define HFA384x_PDR_MAX_TX_POWER ((u16)0x0302) ++#define HFA384x_PDR_MASTER_CHAN_LIST ((u16)0x0303) ++#define HFA384x_PDR_3842_NIC_CONFIG ((u16)0x0400) ++#define HFA384x_PDR_USB_ID ((u16)0x0401) ++#define HFA384x_PDR_PCI_ID ((u16)0x0402) ++#define HFA384x_PDR_PCI_IFCONF ((u16)0x0403) ++#define HFA384x_PDR_PCI_PMCONF ((u16)0x0404) ++#define HFA384x_PDR_RFENRGY ((u16)0x0406) ++#define HFA384x_PDR_USB_POWER_TYPE ((u16)0x0407) ++//#define HFA384x_PDR_UNKNOWN408 ((u16)0x0408) ++#define HFA384x_PDR_USB_MAX_POWER ((u16)0x0409) ++#define HFA384x_PDR_USB_MANUFACTURER ((u16)0x0410) ++#define HFA384x_PDR_USB_PRODUCT ((u16)0x0411) ++#define HFA384x_PDR_ANT_DIVERSITY ((u16)0x0412) ++#define HFA384x_PDR_HFO_DELAY ((u16)0x0413) ++#define HFA384x_PDR_SCALE_THRESH ((u16)0x0414) ++ ++#define HFA384x_PDR_HFA3861_MANF_TESTSP ((u16)0x0900) ++#define HFA384x_PDR_HFA3861_MANF_TESTI ((u16)0x0901) ++#define HFA384x_PDR_END_OF_PDA ((u16)0x0000) ++ ++ ++/*=============================================================*/ ++/*------ Macros -----------------------------------------------*/ ++ ++/*--- Register ID macros ------------------------*/ ++ ++#define HFA384x_CMD HFA384x_CMD_OFF ++#define HFA384x_PARAM0 HFA384x_PARAM0_OFF ++#define HFA384x_PARAM1 HFA384x_PARAM1_OFF ++#define HFA384x_PARAM2 HFA384x_PARAM2_OFF ++#define HFA384x_STATUS HFA384x_STATUS_OFF ++#define HFA384x_RESP0 HFA384x_RESP0_OFF ++#define HFA384x_RESP1 HFA384x_RESP1_OFF ++#define HFA384x_RESP2 HFA384x_RESP2_OFF ++#define HFA384x_INFOFID HFA384x_INFOFID_OFF ++#define HFA384x_RXFID HFA384x_RXFID_OFF ++#define HFA384x_ALLOCFID HFA384x_ALLOCFID_OFF ++#define HFA384x_TXCOMPLFID HFA384x_TXCOMPLFID_OFF ++#define HFA384x_SELECT0 HFA384x_SELECT0_OFF ++#define HFA384x_OFFSET0 HFA384x_OFFSET0_OFF ++#define HFA384x_DATA0 HFA384x_DATA0_OFF ++#define HFA384x_SELECT1 HFA384x_SELECT1_OFF ++#define HFA384x_OFFSET1 HFA384x_OFFSET1_OFF ++#define HFA384x_DATA1 HFA384x_DATA1_OFF ++#define HFA384x_EVSTAT HFA384x_EVSTAT_OFF ++#define HFA384x_intEN HFA384x_INTEN_OFF ++#define HFA384x_EVACK HFA384x_EVACK_OFF ++#define HFA384x_CONTROL HFA384x_CONTROL_OFF ++#define HFA384x_SWSUPPORT0 HFA384x_SWSUPPORT0_OFF ++#define HFA384x_SWSUPPORT1 HFA384x_SWSUPPORT1_OFF ++#define HFA384x_SWSUPPORT2 HFA384x_SWSUPPORT2_OFF ++#define HFA384x_AUXPAGE HFA384x_AUXPAGE_OFF ++#define HFA384x_AUXOFFSET HFA384x_AUXOFFSET_OFF ++#define HFA384x_AUXDATA HFA384x_AUXDATA_OFF ++#define HFA384x_PCICOR HFA384x_PCICOR_OFF ++#define HFA384x_PCIHCR HFA384x_PCIHCR_OFF ++ ++ ++/*--- Register Test/Get/Set Field macros ------------------------*/ ++ ++#define HFA384x_CMD_ISBUSY(value) ((u16)(((u16)value) & HFA384x_CMD_BUSY)) ++#define HFA384x_CMD_AINFO_GET(value) ((u16)(((u16)(value) & HFA384x_CMD_AINFO) >> 8)) ++#define HFA384x_CMD_AINFO_SET(value) ((u16)((u16)(value) << 8)) ++#define HFA384x_CMD_MACPORT_GET(value) ((u16)(HFA384x_CMD_AINFO_GET((u16)(value) & HFA384x_CMD_MACPORT))) ++#define HFA384x_CMD_MACPORT_SET(value) ((u16)HFA384x_CMD_AINFO_SET(value)) ++#define HFA384x_CMD_ISRECL(value) ((u16)(HFA384x_CMD_AINFO_GET((u16)(value) & HFA384x_CMD_RECL))) ++#define HFA384x_CMD_RECL_SET(value) ((u16)HFA384x_CMD_AINFO_SET(value)) ++#define HFA384x_CMD_QOS_GET(value) ((u16)((((u16)(value))&((u16)0x3000)) >> 12)) ++#define HFA384x_CMD_QOS_SET(value) ((u16)((((u16)(value)) << 12) & 0x3000)) ++#define HFA384x_CMD_ISWRITE(value) ((u16)(HFA384x_CMD_AINFO_GET((u16)(value) & HFA384x_CMD_WRITE))) ++#define HFA384x_CMD_WRITE_SET(value) ((u16)HFA384x_CMD_AINFO_SET((u16)value)) ++#define HFA384x_CMD_PROGMODE_GET(value) ((u16)(HFA384x_CMD_AINFO_GET((u16)(value) & HFA384x_CMD_PROGMODE))) ++#define HFA384x_CMD_PROGMODE_SET(value) ((u16)HFA384x_CMD_AINFO_SET((u16)value)) ++#define HFA384x_CMD_CMDCODE_GET(value) ((u16)(((u16)(value)) & HFA384x_CMD_CMDCODE)) ++#define HFA384x_CMD_CMDCODE_SET(value) ((u16)(value)) ++ ++#define HFA384x_STATUS_RESULT_GET(value) ((u16)((((u16)(value)) & HFA384x_STATUS_RESULT) >> 8)) ++#define HFA384x_STATUS_RESULT_SET(value) (((u16)(value)) << 8) ++#define HFA384x_STATUS_CMDCODE_GET(value) (((u16)(value)) & HFA384x_STATUS_CMDCODE) ++#define HFA384x_STATUS_CMDCODE_SET(value) ((u16)(value)) ++ ++#define HFA384x_OFFSET_ISBUSY(value) ((u16)(((u16)(value)) & HFA384x_OFFSET_BUSY)) ++#define HFA384x_OFFSET_ISERR(value) ((u16)(((u16)(value)) & HFA384x_OFFSET_ERR)) ++#define HFA384x_OFFSET_DATAOFF_GET(value) ((u16)(((u16)(value)) & HFA384x_OFFSET_DATAOFF)) ++#define HFA384x_OFFSET_DATAOFF_SET(value) ((u16)(value)) ++ ++#define HFA384x_EVSTAT_ISTICK(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_TICK)) ++#define HFA384x_EVSTAT_ISWTERR(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_WTERR)) ++#define HFA384x_EVSTAT_ISINFDROP(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_INFDROP)) ++#define HFA384x_EVSTAT_ISINFO(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_INFO)) ++#define HFA384x_EVSTAT_ISDTIM(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_DTIM)) ++#define HFA384x_EVSTAT_ISCMD(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_CMD)) ++#define HFA384x_EVSTAT_ISALLOC(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_ALLOC)) ++#define HFA384x_EVSTAT_ISTXEXC(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_TXEXC)) ++#define HFA384x_EVSTAT_ISTX(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_TX)) ++#define HFA384x_EVSTAT_ISRX(value) ((u16)(((u16)(value)) & HFA384x_EVSTAT_RX)) ++ ++#define HFA384x_EVSTAT_ISBAP_OP(value) ((u16)(((u16)(value)) & HFA384x_int_BAP_OP)) ++ ++#define HFA384x_intEN_ISTICK(value) ((u16)(((u16)(value)) & HFA384x_INTEN_TICK)) ++#define HFA384x_intEN_TICK_SET(value) ((u16)(((u16)(value)) << 15)) ++#define HFA384x_intEN_ISWTERR(value) ((u16)(((u16)(value)) & HFA384x_INTEN_WTERR)) ++#define HFA384x_intEN_WTERR_SET(value) ((u16)(((u16)(value)) << 14)) ++#define HFA384x_intEN_ISINFDROP(value) ((u16)(((u16)(value)) & HFA384x_INTEN_INFDROP)) ++#define HFA384x_intEN_INFDROP_SET(value) ((u16)(((u16)(value)) << 13)) ++#define HFA384x_intEN_ISINFO(value) ((u16)(((u16)(value)) & HFA384x_INTEN_INFO)) ++#define HFA384x_intEN_INFO_SET(value) ((u16)(((u16)(value)) << 7)) ++#define HFA384x_intEN_ISDTIM(value) ((u16)(((u16)(value)) & HFA384x_INTEN_DTIM)) ++#define HFA384x_intEN_DTIM_SET(value) ((u16)(((u16)(value)) << 5)) ++#define HFA384x_intEN_ISCMD(value) ((u16)(((u16)(value)) & HFA384x_INTEN_CMD)) ++#define HFA384x_intEN_CMD_SET(value) ((u16)(((u16)(value)) << 4)) ++#define HFA384x_intEN_ISALLOC(value) ((u16)(((u16)(value)) & HFA384x_INTEN_ALLOC)) ++#define HFA384x_intEN_ALLOC_SET(value) ((u16)(((u16)(value)) << 3)) ++#define HFA384x_intEN_ISTXEXC(value) ((u16)(((u16)(value)) & HFA384x_INTEN_TXEXC)) ++#define HFA384x_intEN_TXEXC_SET(value) ((u16)(((u16)(value)) << 2)) ++#define HFA384x_intEN_ISTX(value) ((u16)(((u16)(value)) & HFA384x_INTEN_TX)) ++#define HFA384x_intEN_TX_SET(value) ((u16)(((u16)(value)) << 1)) ++#define HFA384x_intEN_ISRX(value) ((u16)(((u16)(value)) & HFA384x_INTEN_RX)) ++#define HFA384x_intEN_RX_SET(value) ((u16)(((u16)(value)) << 0)) ++ ++#define HFA384x_EVACK_ISTICK(value) ((u16)(((u16)(value)) & HFA384x_EVACK_TICK)) ++#define HFA384x_EVACK_TICK_SET(value) ((u16)(((u16)(value)) << 15)) ++#define HFA384x_EVACK_ISWTERR(value) ((u16)(((u16)(value)) & HFA384x_EVACK_WTERR)) ++#define HFA384x_EVACK_WTERR_SET(value) ((u16)(((u16)(value)) << 14)) ++#define HFA384x_EVACK_ISINFDROP(value) ((u16)(((u16)(value)) & HFA384x_EVACK_INFDROP)) ++#define HFA384x_EVACK_INFDROP_SET(value) ((u16)(((u16)(value)) << 13)) ++#define HFA384x_EVACK_ISINFO(value) ((u16)(((u16)(value)) & HFA384x_EVACK_INFO)) ++#define HFA384x_EVACK_INFO_SET(value) ((u16)(((u16)(value)) << 7)) ++#define HFA384x_EVACK_ISDTIM(value) ((u16)(((u16)(value)) & HFA384x_EVACK_DTIM)) ++#define HFA384x_EVACK_DTIM_SET(value) ((u16)(((u16)(value)) << 5)) ++#define HFA384x_EVACK_ISCMD(value) ((u16)(((u16)(value)) & HFA384x_EVACK_CMD)) ++#define HFA384x_EVACK_CMD_SET(value) ((u16)(((u16)(value)) << 4)) ++#define HFA384x_EVACK_ISALLOC(value) ((u16)(((u16)(value)) & HFA384x_EVACK_ALLOC)) ++#define HFA384x_EVACK_ALLOC_SET(value) ((u16)(((u16)(value)) << 3)) ++#define HFA384x_EVACK_ISTXEXC(value) ((u16)(((u16)(value)) & HFA384x_EVACK_TXEXC)) ++#define HFA384x_EVACK_TXEXC_SET(value) ((u16)(((u16)(value)) << 2)) ++#define HFA384x_EVACK_ISTX(value) ((u16)(((u16)(value)) & HFA384x_EVACK_TX)) ++#define HFA384x_EVACK_TX_SET(value) ((u16)(((u16)(value)) << 1)) ++#define HFA384x_EVACK_ISRX(value) ((u16)(((u16)(value)) & HFA384x_EVACK_RX)) ++#define HFA384x_EVACK_RX_SET(value) ((u16)(((u16)(value)) << 0)) ++ ++#define HFA384x_CONTROL_AUXEN_SET(value) ((u16)(((u16)(value)) << 14)) ++#define HFA384x_CONTROL_AUXEN_GET(value) ((u16)(((u16)(value)) >> 14)) ++ ++/* Byte Order */ ++#ifdef __KERNEL__ ++#define hfa384x2host_16(n) (__le16_to_cpu((u16)(n))) ++#define hfa384x2host_32(n) (__le32_to_cpu((u32)(n))) ++#define host2hfa384x_16(n) (__cpu_to_le16((u16)(n))) ++#define host2hfa384x_32(n) (__cpu_to_le32((u32)(n))) ++#endif ++ ++/* Host Maintained State Info */ ++#define HFA384x_STATE_PREINIT 0 ++#define HFA384x_STATE_INIT 1 ++#define HFA384x_STATE_RUNNING 2 ++ ++/*=============================================================*/ ++/*------ Types and their related constants --------------------*/ ++ ++#define HFA384x_HOSTAUTHASSOC_HOSTAUTH BIT0 ++#define HFA384x_HOSTAUTHASSOC_HOSTASSOC BIT1 ++ ++#define HFA384x_WHAHANDLING_DISABLED 0 ++#define HFA384x_WHAHANDLING_PASSTHROUGH BIT1 ++ ++/*-------------------------------------------------------------*/ ++/* Commonly used basic types */ ++typedef struct hfa384x_bytestr ++{ ++ u16 len; ++ u8 data[0]; ++} __WLAN_ATTRIB_PACK__ hfa384x_bytestr_t; ++ ++typedef struct hfa384x_bytestr32 ++{ ++ u16 len; ++ u8 data[32]; ++} __WLAN_ATTRIB_PACK__ hfa384x_bytestr32_t; ++ ++/*-------------------------------------------------------------------- ++Configuration Record Structures: ++ Network Parameters, Static Configuration Entities ++--------------------------------------------------------------------*/ ++/* Prototype structure: all configuration record structures start with ++these members */ ++ ++typedef struct hfa384x_record ++{ ++ u16 reclen; ++ u16 rid; ++} __WLAN_ATTRIB_PACK__ hfa384x_rec_t; ++ ++typedef struct hfa384x_record16 ++{ ++ u16 reclen; ++ u16 rid; ++ u16 val; ++} __WLAN_ATTRIB_PACK__ hfa384x_rec16_t; ++ ++typedef struct hfa384x_record32 ++{ ++ u16 reclen; ++ u16 rid; ++ u32 val; ++} __WLAN_ATTRIB_PACK__ hfa384x_rec32; ++ ++/*-- Hardware/Firmware Component Information ----------*/ ++typedef struct hfa384x_compident ++{ ++ u16 id; ++ u16 variant; ++ u16 major; ++ u16 minor; ++} __WLAN_ATTRIB_PACK__ hfa384x_compident_t; ++ ++typedef struct hfa384x_caplevel ++{ ++ u16 role; ++ u16 id; ++ u16 variant; ++ u16 bottom; ++ u16 top; ++} __WLAN_ATTRIB_PACK__ hfa384x_caplevel_t; ++ ++/*-- Configuration Record: cnfPortType --*/ ++typedef struct hfa384x_cnfPortType ++{ ++ u16 cnfPortType; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfPortType_t; ++ ++/*-- Configuration Record: cnfOwnMACAddress --*/ ++typedef struct hfa384x_cnfOwnMACAddress ++{ ++ u8 cnfOwnMACAddress[6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnMACAddress_t; ++ ++/*-- Configuration Record: cnfDesiredSSID --*/ ++typedef struct hfa384x_cnfDesiredSSID ++{ ++ u8 cnfDesiredSSID[34]; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfDesiredSSID_t; ++ ++/*-- Configuration Record: cnfOwnChannel --*/ ++typedef struct hfa384x_cnfOwnChannel ++{ ++ u16 cnfOwnChannel; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnChannel_t; ++ ++/*-- Configuration Record: cnfOwnSSID --*/ ++typedef struct hfa384x_cnfOwnSSID ++{ ++ u8 cnfOwnSSID[34]; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnSSID_t; ++ ++/*-- Configuration Record: cnfOwnATIMWindow --*/ ++typedef struct hfa384x_cnfOwnATIMWindow ++{ ++ u16 cnfOwnATIMWindow; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnATIMWindow_t; ++ ++/*-- Configuration Record: cnfSystemScale --*/ ++typedef struct hfa384x_cnfSystemScale ++{ ++ u16 cnfSystemScale; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfSystemScale_t; ++ ++/*-- Configuration Record: cnfMaxDataLength --*/ ++typedef struct hfa384x_cnfMaxDataLength ++{ ++ u16 cnfMaxDataLength; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxDataLength_t; ++ ++/*-- Configuration Record: cnfWDSAddress --*/ ++typedef struct hfa384x_cnfWDSAddress ++{ ++ u8 cnfWDSAddress[6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddress_t; ++ ++/*-- Configuration Record: cnfPMEnabled --*/ ++typedef struct hfa384x_cnfPMEnabled ++{ ++ u16 cnfPMEnabled; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEnabled_t; ++ ++/*-- Configuration Record: cnfPMEPS --*/ ++typedef struct hfa384x_cnfPMEPS ++{ ++ u16 cnfPMEPS; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEPS_t; ++ ++/*-- Configuration Record: cnfMulticastReceive --*/ ++typedef struct hfa384x_cnfMulticastReceive ++{ ++ u16 cnfMulticastReceive; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastReceive_t; ++ ++/*-- Configuration Record: cnfAuthentication --*/ ++#define HFA384x_CNFAUTHENTICATION_OPENSYSTEM 0x0001 ++#define HFA384x_CNFAUTHENTICATION_SHAREDKEY 0x0002 ++#define HFA384x_CNFAUTHENTICATION_LEAP 0x0004 ++ ++/*-- Configuration Record: cnfMaxSleepDuration --*/ ++typedef struct hfa384x_cnfMaxSleepDuration ++{ ++ u16 cnfMaxSleepDuration; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxSleepDuration_t; ++ ++/*-- Configuration Record: cnfPMHoldoverDuration --*/ ++typedef struct hfa384x_cnfPMHoldoverDuration ++{ ++ u16 cnfPMHoldoverDuration; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfPMHoldoverDuration_t; ++ ++/*-- Configuration Record: cnfOwnName --*/ ++typedef struct hfa384x_cnfOwnName ++{ ++ u8 cnfOwnName[34]; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnName_t; ++ ++/*-- Configuration Record: cnfOwnDTIMPeriod --*/ ++typedef struct hfa384x_cnfOwnDTIMPeriod ++{ ++ u16 cnfOwnDTIMPeriod; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnDTIMPeriod_t; ++ ++/*-- Configuration Record: cnfWDSAddress --*/ ++typedef struct hfa384x_cnfWDSAddressN ++{ ++ u8 cnfWDSAddress[6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddressN_t; ++ ++/*-- Configuration Record: cnfMulticastPMBuffering --*/ ++typedef struct hfa384x_cnfMulticastPMBuffering ++{ ++ u16 cnfMulticastPMBuffering; ++} __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastPMBuffering_t; ++ ++/*-------------------------------------------------------------------- ++Configuration Record Structures: ++ Network Parameters, Dynamic Configuration Entities ++--------------------------------------------------------------------*/ ++ ++/*-- Configuration Record: GroupAddresses --*/ ++typedef struct hfa384x_GroupAddresses ++{ ++ u8 MACAddress[16][6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_GroupAddresses_t; ++ ++/*-- Configuration Record: CreateIBSS --*/ ++typedef struct hfa384x_CreateIBSS ++{ ++ u16 CreateIBSS; ++} __WLAN_ATTRIB_PACK__ hfa384x_CreateIBSS_t; ++ ++#define HFA384x_CREATEIBSS_JOINCREATEIBSS 0 ++#define HFA384x_CREATEIBSS_JOINESS_JOINCREATEIBSS 1 ++#define HFA384x_CREATEIBSS_JOINIBSS 2 ++#define HFA384x_CREATEIBSS_JOINESS_JOINIBSS 3 ++ ++/*-- Configuration Record: FragmentationThreshold --*/ ++typedef struct hfa384x_FragmentationThreshold ++{ ++ u16 FragmentationThreshold; ++} __WLAN_ATTRIB_PACK__ hfa384x_FragmentationThreshold_t; ++ ++/*-- Configuration Record: RTSThreshold --*/ ++typedef struct hfa384x_RTSThreshold ++{ ++ u16 RTSThreshold; ++} __WLAN_ATTRIB_PACK__ hfa384x_RTSThreshold_t; ++ ++/*-- Configuration Record: TxRateControl --*/ ++typedef struct hfa384x_TxRateControl ++{ ++ u16 TxRateControl; ++} __WLAN_ATTRIB_PACK__ hfa384x_TxRateControl_t; ++ ++/*-- Configuration Record: PromiscuousMode --*/ ++typedef struct hfa384x_PromiscuousMode ++{ ++ u16 PromiscuousMode; ++} __WLAN_ATTRIB_PACK__ hfa384x_PromiscuousMode_t; ++ ++/*-- Configuration Record: ScanRequest (data portion only) --*/ ++typedef struct hfa384x_ScanRequest_data ++{ ++ u16 channelList; ++ u16 txRate; ++} __WLAN_ATTRIB_PACK__ hfa384x_ScanRequest_data_t; ++ ++/*-- Configuration Record: HostScanRequest (data portion only) --*/ ++typedef struct hfa384x_HostScanRequest_data ++{ ++ u16 channelList; ++ u16 txRate; ++ hfa384x_bytestr32_t ssid; ++} __WLAN_ATTRIB_PACK__ hfa384x_HostScanRequest_data_t; ++ ++/*-- Configuration Record: JoinRequest (data portion only) --*/ ++typedef struct hfa384x_JoinRequest_data ++{ ++ u8 bssid[WLAN_BSSID_LEN]; ++ u16 channel; ++} __WLAN_ATTRIB_PACK__ hfa384x_JoinRequest_data_t; ++ ++/*-- Configuration Record: authenticateStation (data portion only) --*/ ++typedef struct hfa384x_authenticateStation_data ++{ ++ u8 address[WLAN_ADDR_LEN]; ++ u16 status; ++ u16 algorithm; ++} __WLAN_ATTRIB_PACK__ hfa384x_authenticateStation_data_t; ++ ++/*-- Configuration Record: associateStation (data portion only) --*/ ++typedef struct hfa384x_associateStation_data ++{ ++ u8 address[WLAN_ADDR_LEN]; ++ u16 status; ++ u16 type; ++} __WLAN_ATTRIB_PACK__ hfa384x_associateStation_data_t; ++ ++/*-- Configuration Record: ChannelInfoRequest (data portion only) --*/ ++typedef struct hfa384x_ChannelInfoRequest_data ++{ ++ u16 channelList; ++ u16 channelDwellTime; ++} __WLAN_ATTRIB_PACK__ hfa384x_ChannelInfoRequest_data_t; ++ ++/*-- Configuration Record: WEPKeyMapping (data portion only) --*/ ++typedef struct hfa384x_WEPKeyMapping ++{ ++ u8 address[WLAN_ADDR_LEN]; ++ u16 key_index; ++ u8 key[16]; ++ u8 mic_transmit_key[4]; ++ u8 mic_receive_key[4]; ++} __WLAN_ATTRIB_PACK__ hfa384x_WEPKeyMapping_t; ++ ++/*-- Configuration Record: WPAData (data portion only) --*/ ++typedef struct hfa384x_WPAData ++{ ++ u16 datalen; ++ u8 data[0]; // max 80 ++} __WLAN_ATTRIB_PACK__ hfa384x_WPAData_t; ++ ++/*-------------------------------------------------------------------- ++Configuration Record Structures: Behavior Parameters ++--------------------------------------------------------------------*/ ++ ++/*-- Configuration Record: TickTime --*/ ++typedef struct hfa384x_TickTime ++{ ++ u16 TickTime; ++} __WLAN_ATTRIB_PACK__ hfa384x_TickTime_t; ++ ++/*-------------------------------------------------------------------- ++Information Record Structures: NIC Information ++--------------------------------------------------------------------*/ ++ ++/*-- Information Record: MaxLoadTime --*/ ++typedef struct hfa384x_MaxLoadTime ++{ ++ u16 MaxLoadTime; ++} __WLAN_ATTRIB_PACK__ hfa384x_MaxLoadTime_t; ++ ++/*-- Information Record: DownLoadBuffer --*/ ++/* NOTE: The page and offset are in AUX format */ ++typedef struct hfa384x_downloadbuffer ++{ ++ u16 page; ++ u16 offset; ++ u16 len; ++} __WLAN_ATTRIB_PACK__ hfa384x_downloadbuffer_t; ++ ++/*-- Information Record: PRIIdentity --*/ ++typedef struct hfa384x_PRIIdentity ++{ ++ u16 PRICompID; ++ u16 PRIVariant; ++ u16 PRIMajorVersion; ++ u16 PRIMinorVersion; ++} __WLAN_ATTRIB_PACK__ hfa384x_PRIIdentity_t; ++ ++/*-- Information Record: PRISupRange --*/ ++typedef struct hfa384x_PRISupRange ++{ ++ u16 PRIRole; ++ u16 PRIID; ++ u16 PRIVariant; ++ u16 PRIBottom; ++ u16 PRITop; ++} __WLAN_ATTRIB_PACK__ hfa384x_PRISupRange_t; ++ ++/*-- Information Record: CFIActRanges --*/ ++typedef struct hfa384x_CFIActRanges ++{ ++ u16 CFIRole; ++ u16 CFIID; ++ u16 CFIVariant; ++ u16 CFIBottom; ++ u16 CFITop; ++} __WLAN_ATTRIB_PACK__ hfa384x_CFIActRanges_t; ++ ++/*-- Information Record: NICSerialNumber --*/ ++typedef struct hfa384x_NICSerialNumber ++{ ++ u8 NICSerialNumber[12]; ++} __WLAN_ATTRIB_PACK__ hfa384x_NICSerialNumber_t; ++ ++/*-- Information Record: NICIdentity --*/ ++typedef struct hfa384x_NICIdentity ++{ ++ u16 NICCompID; ++ u16 NICVariant; ++ u16 NICMajorVersion; ++ u16 NICMinorVersion; ++} __WLAN_ATTRIB_PACK__ hfa384x_NICIdentity_t; ++ ++/*-- Information Record: MFISupRange --*/ ++typedef struct hfa384x_MFISupRange ++{ ++ u16 MFIRole; ++ u16 MFIID; ++ u16 MFIVariant; ++ u16 MFIBottom; ++ u16 MFITop; ++} __WLAN_ATTRIB_PACK__ hfa384x_MFISupRange_t; ++ ++/*-- Information Record: CFISupRange --*/ ++typedef struct hfa384x_CFISupRange ++{ ++ u16 CFIRole; ++ u16 CFIID; ++ u16 CFIVariant; ++ u16 CFIBottom; ++ u16 CFITop; ++} __WLAN_ATTRIB_PACK__ hfa384x_CFISupRange_t; ++ ++/*-- Information Record: BUILDSEQ:BuildSeq --*/ ++typedef struct hfa384x_BuildSeq { ++ u16 primary; ++ u16 secondary; ++} __WLAN_ATTRIB_PACK__ hfa384x_BuildSeq_t; ++ ++/*-- Information Record: FWID --*/ ++#define HFA384x_FWID_LEN 14 ++typedef struct hfa384x_FWID { ++ u8 primary[HFA384x_FWID_LEN]; ++ u8 secondary[HFA384x_FWID_LEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_FWID_t; ++ ++/*-- Information Record: ChannelList --*/ ++typedef struct hfa384x_ChannelList ++{ ++ u16 ChannelList; ++} __WLAN_ATTRIB_PACK__ hfa384x_ChannelList_t; ++ ++/*-- Information Record: RegulatoryDomains --*/ ++typedef struct hfa384x_RegulatoryDomains ++{ ++ u8 RegulatoryDomains[12]; ++} __WLAN_ATTRIB_PACK__ hfa384x_RegulatoryDomains_t; ++ ++/*-- Information Record: TempType --*/ ++typedef struct hfa384x_TempType ++{ ++ u16 TempType; ++} __WLAN_ATTRIB_PACK__ hfa384x_TempType_t; ++ ++/*-- Information Record: CIS --*/ ++typedef struct hfa384x_CIS ++{ ++ u8 CIS[480]; ++} __WLAN_ATTRIB_PACK__ hfa384x_CIS_t; ++ ++/*-- Information Record: STAIdentity --*/ ++typedef struct hfa384x_STAIdentity ++{ ++ u16 STACompID; ++ u16 STAVariant; ++ u16 STAMajorVersion; ++ u16 STAMinorVersion; ++} __WLAN_ATTRIB_PACK__ hfa384x_STAIdentity_t; ++ ++/*-- Information Record: STASupRange --*/ ++typedef struct hfa384x_STASupRange ++{ ++ u16 STARole; ++ u16 STAID; ++ u16 STAVariant; ++ u16 STABottom; ++ u16 STATop; ++} __WLAN_ATTRIB_PACK__ hfa384x_STASupRange_t; ++ ++/*-- Information Record: MFIActRanges --*/ ++typedef struct hfa384x_MFIActRanges ++{ ++ u16 MFIRole; ++ u16 MFIID; ++ u16 MFIVariant; ++ u16 MFIBottom; ++ u16 MFITop; ++} __WLAN_ATTRIB_PACK__ hfa384x_MFIActRanges_t; ++ ++/*-------------------------------------------------------------------- ++Information Record Structures: NIC Information ++--------------------------------------------------------------------*/ ++ ++/*-- Information Record: PortStatus --*/ ++typedef struct hfa384x_PortStatus ++{ ++ u16 PortStatus; ++} __WLAN_ATTRIB_PACK__ hfa384x_PortStatus_t; ++ ++#define HFA384x_PSTATUS_DISABLED ((u16)1) ++#define HFA384x_PSTATUS_SEARCHING ((u16)2) ++#define HFA384x_PSTATUS_CONN_IBSS ((u16)3) ++#define HFA384x_PSTATUS_CONN_ESS ((u16)4) ++#define HFA384x_PSTATUS_OUTOFRANGE ((u16)5) ++#define HFA384x_PSTATUS_CONN_WDS ((u16)6) ++ ++/*-- Information Record: CurrentSSID --*/ ++typedef struct hfa384x_CurrentSSID ++{ ++ u8 CurrentSSID[34]; ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentSSID_t; ++ ++/*-- Information Record: CurrentBSSID --*/ ++typedef struct hfa384x_CurrentBSSID ++{ ++ u8 CurrentBSSID[6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentBSSID_t; ++ ++/*-- Information Record: commsquality --*/ ++typedef struct hfa384x_commsquality ++{ ++ u16 CQ_currBSS; ++ u16 ASL_currBSS; ++ u16 ANL_currFC; ++} __WLAN_ATTRIB_PACK__ hfa384x_commsquality_t; ++ ++/*-- Information Record: dmbcommsquality --*/ ++typedef struct hfa384x_dbmcommsquality ++{ ++ u16 CQdbm_currBSS; ++ u16 ASLdbm_currBSS; ++ u16 ANLdbm_currFC; ++} __WLAN_ATTRIB_PACK__ hfa384x_dbmcommsquality_t; ++ ++/*-- Information Record: CurrentTxRate --*/ ++typedef struct hfa384x_CurrentTxRate ++{ ++ u16 CurrentTxRate; ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentTxRate_t; ++ ++/*-- Information Record: CurrentBeaconInterval --*/ ++typedef struct hfa384x_CurrentBeaconInterval ++{ ++ u16 CurrentBeaconInterval; ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentBeaconInterval_t; ++ ++/*-- Information Record: CurrentScaleThresholds --*/ ++typedef struct hfa384x_CurrentScaleThresholds ++{ ++ u16 EnergyDetectThreshold; ++ u16 CarrierDetectThreshold; ++ u16 DeferDetectThreshold; ++ u16 CellSearchThreshold; /* Stations only */ ++ u16 DeadSpotThreshold; /* Stations only */ ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentScaleThresholds_t; ++ ++/*-- Information Record: ProtocolRspTime --*/ ++typedef struct hfa384x_ProtocolRspTime ++{ ++ u16 ProtocolRspTime; ++} __WLAN_ATTRIB_PACK__ hfa384x_ProtocolRspTime_t; ++ ++/*-- Information Record: ShortRetryLimit --*/ ++typedef struct hfa384x_ShortRetryLimit ++{ ++ u16 ShortRetryLimit; ++} __WLAN_ATTRIB_PACK__ hfa384x_ShortRetryLimit_t; ++ ++/*-- Information Record: LongRetryLimit --*/ ++typedef struct hfa384x_LongRetryLimit ++{ ++ u16 LongRetryLimit; ++} __WLAN_ATTRIB_PACK__ hfa384x_LongRetryLimit_t; ++ ++/*-- Information Record: MaxTransmitLifetime --*/ ++typedef struct hfa384x_MaxTransmitLifetime ++{ ++ u16 MaxTransmitLifetime; ++} __WLAN_ATTRIB_PACK__ hfa384x_MaxTransmitLifetime_t; ++ ++/*-- Information Record: MaxReceiveLifetime --*/ ++typedef struct hfa384x_MaxReceiveLifetime ++{ ++ u16 MaxReceiveLifetime; ++} __WLAN_ATTRIB_PACK__ hfa384x_MaxReceiveLifetime_t; ++ ++/*-- Information Record: CFPollable --*/ ++typedef struct hfa384x_CFPollable ++{ ++ u16 CFPollable; ++} __WLAN_ATTRIB_PACK__ hfa384x_CFPollable_t; ++ ++/*-- Information Record: AuthenticationAlgorithms --*/ ++typedef struct hfa384x_AuthenticationAlgorithms ++{ ++ u16 AuthenticationType; ++ u16 TypeEnabled; ++} __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_t; ++ ++/*-- Information Record: AuthenticationAlgorithms ++(data only --*/ ++typedef struct hfa384x_AuthenticationAlgorithms_data ++{ ++ u16 AuthenticationType; ++ u16 TypeEnabled; ++} __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_data_t; ++ ++/*-- Information Record: PrivacyOptionImplemented --*/ ++typedef struct hfa384x_PrivacyOptionImplemented ++{ ++ u16 PrivacyOptionImplemented; ++} __WLAN_ATTRIB_PACK__ hfa384x_PrivacyOptionImplemented_t; ++ ++/*-- Information Record: OwnMACAddress --*/ ++typedef struct hfa384x_OwnMACAddress ++{ ++ u8 OwnMACAddress[6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_OwnMACAddress_t; ++ ++/*-- Information Record: PCFInfo --*/ ++typedef struct hfa384x_PCFInfo ++{ ++ u16 MediumOccupancyLimit; ++ u16 CFPPeriod; ++ u16 CFPMaxDuration; ++ u16 CFPFlags; ++} __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_t; ++ ++/*-- Information Record: PCFInfo (data portion only) --*/ ++typedef struct hfa384x_PCFInfo_data ++{ ++ u16 MediumOccupancyLimit; ++ u16 CFPPeriod; ++ u16 CFPMaxDuration; ++ u16 CFPFlags; ++} __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_data_t; ++ ++/*-------------------------------------------------------------------- ++Information Record Structures: Modem Information Records ++--------------------------------------------------------------------*/ ++ ++/*-- Information Record: PHYType --*/ ++typedef struct hfa384x_PHYType ++{ ++ u16 PHYType; ++} __WLAN_ATTRIB_PACK__ hfa384x_PHYType_t; ++ ++/*-- Information Record: CurrentChannel --*/ ++typedef struct hfa384x_CurrentChannel ++{ ++ u16 CurrentChannel; ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentChannel_t; ++ ++/*-- Information Record: CurrentPowerState --*/ ++typedef struct hfa384x_CurrentPowerState ++{ ++ u16 CurrentPowerState; ++} __WLAN_ATTRIB_PACK__ hfa384x_CurrentPowerState_t; ++ ++/*-- Information Record: CCAMode --*/ ++typedef struct hfa384x_CCAMode ++{ ++ u16 CCAMode; ++} __WLAN_ATTRIB_PACK__ hfa384x_CCAMode_t; ++ ++/*-- Information Record: SupportedDataRates --*/ ++typedef struct hfa384x_SupportedDataRates ++{ ++ u8 SupportedDataRates[10]; ++} __WLAN_ATTRIB_PACK__ hfa384x_SupportedDataRates_t; ++ ++/*-- Information Record: LFOStatus --*/ ++typedef struct hfa384x_LFOStatus ++{ ++ u16 TestResults; ++ u16 LFOResult; ++ u16 VRHFOResult; ++} __WLAN_ATTRIB_PACK__ hfa384x_LFOStatus_t; ++ ++#define HFA384x_TESTRESULT_ALLPASSED BIT0 ++#define HFA384x_TESTRESULT_LFO_FAIL BIT1 ++#define HFA384x_TESTRESULT_VR_HF0_FAIL BIT2 ++#define HFA384x_HOST_FIRM_COORDINATE BIT7 ++#define HFA384x_TESTRESULT_COORDINATE BIT15 ++ ++/*-- Information Record: LEDControl --*/ ++typedef struct hfa384x_LEDControl ++{ ++ u16 searching_on; ++ u16 searching_off; ++ u16 assoc_on; ++ u16 assoc_off; ++ u16 activity; ++} __WLAN_ATTRIB_PACK__ hfa384x_LEDControl_t; ++ ++/*-------------------------------------------------------------------- ++ FRAME DESCRIPTORS AND FRAME STRUCTURES ++ ++FRAME DESCRIPTORS: Offsets ++ ++---------------------------------------------------------------------- ++Control Info (offset 44-51) ++--------------------------------------------------------------------*/ ++#define HFA384x_FD_STATUS_OFF ((u16)0x44) ++#define HFA384x_FD_TIME_OFF ((u16)0x46) ++#define HFA384x_FD_SWSUPPORT_OFF ((u16)0x4A) ++#define HFA384x_FD_SILENCE_OFF ((u16)0x4A) ++#define HFA384x_FD_SIGNAL_OFF ((u16)0x4B) ++#define HFA384x_FD_RATE_OFF ((u16)0x4C) ++#define HFA384x_FD_RXFLOW_OFF ((u16)0x4D) ++#define HFA384x_FD_RESERVED_OFF ((u16)0x4E) ++#define HFA384x_FD_TXCONTROL_OFF ((u16)0x50) ++/*-------------------------------------------------------------------- ++802.11 Header (offset 52-6B) ++--------------------------------------------------------------------*/ ++#define HFA384x_FD_FRAMECONTROL_OFF ((u16)0x52) ++#define HFA384x_FD_DURATIONID_OFF ((u16)0x54) ++#define HFA384x_FD_ADDRESS1_OFF ((u16)0x56) ++#define HFA384x_FD_ADDRESS2_OFF ((u16)0x5C) ++#define HFA384x_FD_ADDRESS3_OFF ((u16)0x62) ++#define HFA384x_FD_SEQCONTROL_OFF ((u16)0x68) ++#define HFA384x_FD_ADDRESS4_OFF ((u16)0x6A) ++#define HFA384x_FD_DATALEN_OFF ((u16)0x70) ++/*-------------------------------------------------------------------- ++802.3 Header (offset 72-7F) ++--------------------------------------------------------------------*/ ++#define HFA384x_FD_DESTADDRESS_OFF ((u16)0x72) ++#define HFA384x_FD_SRCADDRESS_OFF ((u16)0x78) ++#define HFA384x_FD_DATALENGTH_OFF ((u16)0x7E) ++ ++/*-------------------------------------------------------------------- ++FRAME STRUCTURES: Communication Frames ++---------------------------------------------------------------------- ++Communication Frames: Transmit Frames ++--------------------------------------------------------------------*/ ++/*-- Communication Frame: Transmit Frame Structure --*/ ++typedef struct hfa384x_tx_frame ++{ ++ u16 status; ++ u16 reserved1; ++ u16 reserved2; ++ u32 sw_support; ++ u8 tx_retrycount; ++ u8 tx_rate; ++ u16 tx_control; ++ ++ /*-- 802.11 Header Information --*/ ++ ++ u16 frame_control; ++ u16 duration_id; ++ u8 address1[6]; ++ u8 address2[6]; ++ u8 address3[6]; ++ u16 sequence_control; ++ u8 address4[6]; ++ u16 data_len; /* little endian format */ ++ ++ /*-- 802.3 Header Information --*/ ++ ++ u8 dest_addr[6]; ++ u8 src_addr[6]; ++ u16 data_length; /* big endian format */ ++} __WLAN_ATTRIB_PACK__ hfa384x_tx_frame_t; ++/*-------------------------------------------------------------------- ++Communication Frames: Field Masks for Transmit Frames ++--------------------------------------------------------------------*/ ++/*-- Status Field --*/ ++#define HFA384x_TXSTATUS_ACKERR ((u16)BIT5) ++#define HFA384x_TXSTATUS_FORMERR ((u16)BIT3) ++#define HFA384x_TXSTATUS_DISCON ((u16)BIT2) ++#define HFA384x_TXSTATUS_AGEDERR ((u16)BIT1) ++#define HFA384x_TXSTATUS_RETRYERR ((u16)BIT0) ++/*-- Transmit Control Field --*/ ++#define HFA384x_TX_CFPOLL ((u16)BIT12) ++#define HFA384x_TX_PRST ((u16)BIT11) ++#define HFA384x_TX_MACPORT ((u16)(BIT10 | BIT9 | BIT8)) ++#define HFA384x_TX_NOENCRYPT ((u16)BIT7) ++#define HFA384x_TX_RETRYSTRAT ((u16)(BIT6 | BIT5)) ++#define HFA384x_TX_STRUCTYPE ((u16)(BIT4 | BIT3)) ++#define HFA384x_TX_TXEX ((u16)BIT2) ++#define HFA384x_TX_TXOK ((u16)BIT1) ++/*-------------------------------------------------------------------- ++Communication Frames: Test/Get/Set Field Values for Transmit Frames ++--------------------------------------------------------------------*/ ++/*-- Status Field --*/ ++#define HFA384x_TXSTATUS_ISERROR(v) \ ++ (((u16)(v))&\ ++ (HFA384x_TXSTATUS_ACKERR|HFA384x_TXSTATUS_FORMERR|\ ++ HFA384x_TXSTATUS_DISCON|HFA384x_TXSTATUS_AGEDERR|\ ++ HFA384x_TXSTATUS_RETRYERR)) ++ ++#define HFA384x_TXSTATUS_ISACKERR(v) ((u16)(((u16)(v)) & HFA384x_TXSTATUS_ACKERR)) ++#define HFA384x_TXSTATUS_ISFORMERR(v) ((u16)(((u16)(v)) & HFA384x_TXSTATUS_FORMERR)) ++#define HFA384x_TXSTATUS_ISDISCON(v) ((u16)(((u16)(v)) & HFA384x_TXSTATUS_DISCON)) ++#define HFA384x_TXSTATUS_ISAGEDERR(v) ((u16)(((u16)(v)) & HFA384x_TXSTATUS_AGEDERR)) ++#define HFA384x_TXSTATUS_ISRETRYERR(v) ((u16)(((u16)(v)) & HFA384x_TXSTATUS_RETRYERR)) ++ ++#define HFA384x_TX_GET(v,m,s) ((((u16)(v))&((u16)(m)))>>((u16)(s))) ++#define HFA384x_TX_SET(v,m,s) ((((u16)(v))<<((u16)(s)))&((u16)(m))) ++ ++#define HFA384x_TX_CFPOLL_GET(v) HFA384x_TX_GET(v, HFA384x_TX_CFPOLL,12) ++#define HFA384x_TX_CFPOLL_SET(v) HFA384x_TX_SET(v, HFA384x_TX_CFPOLL,12) ++#define HFA384x_TX_PRST_GET(v) HFA384x_TX_GET(v, HFA384x_TX_PRST,11) ++#define HFA384x_TX_PRST_SET(v) HFA384x_TX_SET(v, HFA384x_TX_PRST,11) ++#define HFA384x_TX_MACPORT_GET(v) HFA384x_TX_GET(v, HFA384x_TX_MACPORT, 8) ++#define HFA384x_TX_MACPORT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_MACPORT, 8) ++#define HFA384x_TX_NOENCRYPT_GET(v) HFA384x_TX_GET(v, HFA384x_TX_NOENCRYPT, 7) ++#define HFA384x_TX_NOENCRYPT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_NOENCRYPT, 7) ++#define HFA384x_TX_RETRYSTRAT_GET(v) HFA384x_TX_GET(v, HFA384x_TX_RETRYSTRAT, 5) ++#define HFA384x_TX_RETRYSTRAT_SET(v) HFA384x_TX_SET(v, HFA384x_TX_RETRYSTRAT, 5) ++#define HFA384x_TX_STRUCTYPE_GET(v) HFA384x_TX_GET(v, HFA384x_TX_STRUCTYPE, 3) ++#define HFA384x_TX_STRUCTYPE_SET(v) HFA384x_TX_SET(v, HFA384x_TX_STRUCTYPE, 3) ++#define HFA384x_TX_TXEX_GET(v) HFA384x_TX_GET(v, HFA384x_TX_TXEX, 2) ++#define HFA384x_TX_TXEX_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXEX, 2) ++#define HFA384x_TX_TXOK_GET(v) HFA384x_TX_GET(v, HFA384x_TX_TXOK, 1) ++#define HFA384x_TX_TXOK_SET(v) HFA384x_TX_SET(v, HFA384x_TX_TXOK, 1) ++/*-------------------------------------------------------------------- ++Communication Frames: Receive Frames ++--------------------------------------------------------------------*/ ++/*-- Communication Frame: Receive Frame Structure --*/ ++typedef struct hfa384x_rx_frame ++{ ++ /*-- MAC rx descriptor (hfa384x byte order) --*/ ++ u16 status; ++ u32 time; ++ u8 silence; ++ u8 signal; ++ u8 rate; ++ u8 rx_flow; ++ u16 reserved1; ++ u16 reserved2; ++ ++ /*-- 802.11 Header Information (802.11 byte order) --*/ ++ u16 frame_control; ++ u16 duration_id; ++ u8 address1[6]; ++ u8 address2[6]; ++ u8 address3[6]; ++ u16 sequence_control; ++ u8 address4[6]; ++ u16 data_len; /* hfa384x (little endian) format */ ++ ++ /*-- 802.3 Header Information --*/ ++ u8 dest_addr[6]; ++ u8 src_addr[6]; ++ u16 data_length; /* IEEE? (big endian) format */ ++} __WLAN_ATTRIB_PACK__ hfa384x_rx_frame_t; ++/*-------------------------------------------------------------------- ++Communication Frames: Field Masks for Receive Frames ++--------------------------------------------------------------------*/ ++/*-- Offsets --------*/ ++#define HFA384x_RX_DATA_LEN_OFF ((u16)44) ++#define HFA384x_RX_80211HDR_OFF ((u16)14) ++#define HFA384x_RX_DATA_OFF ((u16)60) ++ ++/*-- Status Fields --*/ ++#define HFA384x_RXSTATUS_MSGTYPE ((u16)(BIT15 | BIT14 | BIT13)) ++#define HFA384x_RXSTATUS_MACPORT ((u16)(BIT10 | BIT9 | BIT8)) ++#define HFA384x_RXSTATUS_UNDECR ((u16)BIT1) ++#define HFA384x_RXSTATUS_FCSERR ((u16)BIT0) ++/*-------------------------------------------------------------------- ++Communication Frames: Test/Get/Set Field Values for Receive Frames ++--------------------------------------------------------------------*/ ++#define HFA384x_RXSTATUS_MSGTYPE_GET(value) ((u16)((((u16)(value)) & HFA384x_RXSTATUS_MSGTYPE) >> 13)) ++#define HFA384x_RXSTATUS_MSGTYPE_SET(value) ((u16)(((u16)(value)) << 13)) ++#define HFA384x_RXSTATUS_MACPORT_GET(value) ((u16)((((u16)(value)) & HFA384x_RXSTATUS_MACPORT) >> 8)) ++#define HFA384x_RXSTATUS_MACPORT_SET(value) ((u16)(((u16)(value)) << 8)) ++#define HFA384x_RXSTATUS_ISUNDECR(value) ((u16)(((u16)(value)) & HFA384x_RXSTATUS_UNDECR)) ++#define HFA384x_RXSTATUS_ISFCSERR(value) ((u16)(((u16)(value)) & HFA384x_RXSTATUS_FCSERR)) ++/*-------------------------------------------------------------------- ++ FRAME STRUCTURES: Information Types and Information Frame Structures ++---------------------------------------------------------------------- ++Information Types ++--------------------------------------------------------------------*/ ++#define HFA384x_IT_HANDOVERADDR ((u16)0xF000UL) ++#define HFA384x_IT_HANDOVERDEAUTHADDRESS ((u16)0xF001UL)//AP 1.3.7 ++#define HFA384x_IT_COMMTALLIES ((u16)0xF100UL) ++#define HFA384x_IT_SCANRESULTS ((u16)0xF101UL) ++#define HFA384x_IT_CHINFORESULTS ((u16)0xF102UL) ++#define HFA384x_IT_HOSTSCANRESULTS ((u16)0xF103UL) ++#define HFA384x_IT_LINKSTATUS ((u16)0xF200UL) ++#define HFA384x_IT_ASSOCSTATUS ((u16)0xF201UL) ++#define HFA384x_IT_AUTHREQ ((u16)0xF202UL) ++#define HFA384x_IT_PSUSERCNT ((u16)0xF203UL) ++#define HFA384x_IT_KEYIDCHANGED ((u16)0xF204UL) ++#define HFA384x_IT_ASSOCREQ ((u16)0xF205UL) ++#define HFA384x_IT_MICFAILURE ((u16)0xF206UL) ++ ++/*-------------------------------------------------------------------- ++Information Frames Structures ++---------------------------------------------------------------------- ++Information Frames: Notification Frame Structures ++--------------------------------------------------------------------*/ ++/*-- Notification Frame,MAC Mgmt: Handover Address --*/ ++typedef struct hfa384x_HandoverAddr ++{ ++ u16 framelen; ++ u16 infotype; ++ u8 handover_addr[WLAN_BSSID_LEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_HandoverAddr_t; ++ ++/*-- Inquiry Frame, Diagnose: Communication Tallies --*/ ++typedef struct hfa384x_CommTallies16 ++{ ++ u16 txunicastframes; ++ u16 txmulticastframes; ++ u16 txfragments; ++ u16 txunicastoctets; ++ u16 txmulticastoctets; ++ u16 txdeferredtrans; ++ u16 txsingleretryframes; ++ u16 txmultipleretryframes; ++ u16 txretrylimitexceeded; ++ u16 txdiscards; ++ u16 rxunicastframes; ++ u16 rxmulticastframes; ++ u16 rxfragments; ++ u16 rxunicastoctets; ++ u16 rxmulticastoctets; ++ u16 rxfcserrors; ++ u16 rxdiscardsnobuffer; ++ u16 txdiscardswrongsa; ++ u16 rxdiscardswepundecr; ++ u16 rxmsginmsgfrag; ++ u16 rxmsginbadmsgfrag; ++} __WLAN_ATTRIB_PACK__ hfa384x_CommTallies16_t; ++ ++typedef struct hfa384x_CommTallies32 ++{ ++ u32 txunicastframes; ++ u32 txmulticastframes; ++ u32 txfragments; ++ u32 txunicastoctets; ++ u32 txmulticastoctets; ++ u32 txdeferredtrans; ++ u32 txsingleretryframes; ++ u32 txmultipleretryframes; ++ u32 txretrylimitexceeded; ++ u32 txdiscards; ++ u32 rxunicastframes; ++ u32 rxmulticastframes; ++ u32 rxfragments; ++ u32 rxunicastoctets; ++ u32 rxmulticastoctets; ++ u32 rxfcserrors; ++ u32 rxdiscardsnobuffer; ++ u32 txdiscardswrongsa; ++ u32 rxdiscardswepundecr; ++ u32 rxmsginmsgfrag; ++ u32 rxmsginbadmsgfrag; ++} __WLAN_ATTRIB_PACK__ hfa384x_CommTallies32_t; ++ ++/*-- Inquiry Frame, Diagnose: Scan Results & Subfields--*/ ++typedef struct hfa384x_ScanResultSub ++{ ++ u16 chid; ++ u16 anl; ++ u16 sl; ++ u8 bssid[WLAN_BSSID_LEN]; ++ u16 bcnint; ++ u16 capinfo; ++ hfa384x_bytestr32_t ssid; ++ u8 supprates[10]; /* 802.11 info element */ ++ u16 proberesp_rate; ++} __WLAN_ATTRIB_PACK__ hfa384x_ScanResultSub_t; ++ ++typedef struct hfa384x_ScanResult ++{ ++ u16 rsvd; ++ u16 scanreason; ++ hfa384x_ScanResultSub_t ++ result[HFA384x_SCANRESULT_MAX]; ++} __WLAN_ATTRIB_PACK__ hfa384x_ScanResult_t; ++ ++/*-- Inquiry Frame, Diagnose: ChInfo Results & Subfields--*/ ++typedef struct hfa384x_ChInfoResultSub ++{ ++ u16 chid; ++ u16 anl; ++ u16 pnl; ++ u16 active; ++} __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResultSub_t; ++ ++#define HFA384x_CHINFORESULT_BSSACTIVE BIT0 ++#define HFA384x_CHINFORESULT_PCFACTIVE BIT1 ++ ++typedef struct hfa384x_ChInfoResult ++{ ++ u16 scanchannels; ++ hfa384x_ChInfoResultSub_t ++ result[HFA384x_CHINFORESULT_MAX]; ++} __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResult_t; ++ ++/*-- Inquiry Frame, Diagnose: Host Scan Results & Subfields--*/ ++typedef struct hfa384x_HScanResultSub ++{ ++ u16 chid; ++ u16 anl; ++ u16 sl; ++ u8 bssid[WLAN_BSSID_LEN]; ++ u16 bcnint; ++ u16 capinfo; ++ hfa384x_bytestr32_t ssid; ++ u8 supprates[10]; /* 802.11 info element */ ++ u16 proberesp_rate; ++ u16 atim; ++} __WLAN_ATTRIB_PACK__ hfa384x_HScanResultSub_t; ++ ++typedef struct hfa384x_HScanResult ++{ ++ u16 nresult; ++ u16 rsvd; ++ hfa384x_HScanResultSub_t ++ result[HFA384x_HSCANRESULT_MAX]; ++} __WLAN_ATTRIB_PACK__ hfa384x_HScanResult_t; ++ ++/*-- Unsolicited Frame, MAC Mgmt: LinkStatus --*/ ++ ++#define HFA384x_LINK_NOTCONNECTED ((u16)0) ++#define HFA384x_LINK_CONNECTED ((u16)1) ++#define HFA384x_LINK_DISCONNECTED ((u16)2) ++#define HFA384x_LINK_AP_CHANGE ((u16)3) ++#define HFA384x_LINK_AP_OUTOFRANGE ((u16)4) ++#define HFA384x_LINK_AP_INRANGE ((u16)5) ++#define HFA384x_LINK_ASSOCFAIL ((u16)6) ++ ++typedef struct hfa384x_LinkStatus ++{ ++ u16 linkstatus; ++} __WLAN_ATTRIB_PACK__ hfa384x_LinkStatus_t; ++ ++ ++/*-- Unsolicited Frame, MAC Mgmt: AssociationStatus (--*/ ++ ++#define HFA384x_ASSOCSTATUS_STAASSOC ((u16)1) ++#define HFA384x_ASSOCSTATUS_REASSOC ((u16)2) ++#define HFA384x_ASSOCSTATUS_DISASSOC ((u16)3) ++#define HFA384x_ASSOCSTATUS_ASSOCFAIL ((u16)4) ++#define HFA384x_ASSOCSTATUS_AUTHFAIL ((u16)5) ++ ++typedef struct hfa384x_AssocStatus ++{ ++ u16 assocstatus; ++ u8 sta_addr[WLAN_ADDR_LEN]; ++ /* old_ap_addr is only valid if assocstatus == 2 */ ++ u8 old_ap_addr[WLAN_ADDR_LEN]; ++ u16 reason; ++ u16 reserved; ++} __WLAN_ATTRIB_PACK__ hfa384x_AssocStatus_t; ++ ++/*-- Unsolicited Frame, MAC Mgmt: AuthRequest (AP Only) --*/ ++ ++typedef struct hfa384x_AuthRequest ++{ ++ u8 sta_addr[WLAN_ADDR_LEN]; ++ u16 algorithm; ++} __WLAN_ATTRIB_PACK__ hfa384x_AuthReq_t; ++ ++/*-- Unsolicited Frame, MAC Mgmt: AssocRequest (AP Only) --*/ ++ ++typedef struct hfa384x_AssocRequest ++{ ++ u8 sta_addr[WLAN_ADDR_LEN]; ++ u16 type; ++ u8 wpa_data[80]; ++} __WLAN_ATTRIB_PACK__ hfa384x_AssocReq_t; ++ ++ ++#define HFA384x_ASSOCREQ_TYPE_ASSOC 0 ++#define HFA384x_ASSOCREQ_TYPE_REASSOC 1 ++ ++/*-- Unsolicited Frame, MAC Mgmt: MIC Failure (AP Only) --*/ ++ ++typedef struct hfa384x_MicFailure ++{ ++ u8 sender[WLAN_ADDR_LEN]; ++ u8 dest[WLAN_ADDR_LEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_MicFailure_t; ++ ++/*-- Unsolicited Frame, MAC Mgmt: PSUserCount (AP Only) --*/ ++ ++typedef struct hfa384x_PSUserCount ++{ ++ u16 usercnt; ++} __WLAN_ATTRIB_PACK__ hfa384x_PSUserCount_t; ++ ++typedef struct hfa384x_KeyIDChanged ++{ ++ u8 sta_addr[WLAN_ADDR_LEN]; ++ u16 keyid; ++} __WLAN_ATTRIB_PACK__ hfa384x_KeyIDChanged_t; ++ ++/*-- Collection of all Inf frames ---------------*/ ++typedef union hfa384x_infodata { ++ hfa384x_CommTallies16_t commtallies16; ++ hfa384x_CommTallies32_t commtallies32; ++ hfa384x_ScanResult_t scanresult; ++ hfa384x_ChInfoResult_t chinforesult; ++ hfa384x_HScanResult_t hscanresult; ++ hfa384x_LinkStatus_t linkstatus; ++ hfa384x_AssocStatus_t assocstatus; ++ hfa384x_AuthReq_t authreq; ++ hfa384x_PSUserCount_t psusercnt; ++ hfa384x_KeyIDChanged_t keyidchanged; ++} __WLAN_ATTRIB_PACK__ hfa384x_infodata_t; ++ ++typedef struct hfa384x_InfFrame ++{ ++ u16 framelen; ++ u16 infotype; ++ hfa384x_infodata_t info; ++} __WLAN_ATTRIB_PACK__ hfa384x_InfFrame_t; ++ ++/*-------------------------------------------------------------------- ++USB Packet structures and constants. ++--------------------------------------------------------------------*/ ++ ++/* Should be sent to the ctrlout endpoint */ ++#define HFA384x_USB_ENBULKIN 6 ++ ++/* Should be sent to the bulkout endpoint */ ++#define HFA384x_USB_TXFRM 0 ++#define HFA384x_USB_CMDREQ 1 ++#define HFA384x_USB_WRIDREQ 2 ++#define HFA384x_USB_RRIDREQ 3 ++#define HFA384x_USB_WMEMREQ 4 ++#define HFA384x_USB_RMEMREQ 5 ++ ++/* Received from the bulkin endpoint */ ++#define HFA384x_USB_ISFRM(a) (!((a) & 0x8000)) ++#define HFA384x_USB_ISTXFRM(a) (((a) & 0x9000) == 0x1000) ++#define HFA384x_USB_ISRXFRM(a) (!((a) & 0x9000)) ++#define HFA384x_USB_INFOFRM 0x8000 ++#define HFA384x_USB_CMDRESP 0x8001 ++#define HFA384x_USB_WRIDRESP 0x8002 ++#define HFA384x_USB_RRIDRESP 0x8003 ++#define HFA384x_USB_WMEMRESP 0x8004 ++#define HFA384x_USB_RMEMRESP 0x8005 ++#define HFA384x_USB_BUFAVAIL 0x8006 ++#define HFA384x_USB_ERROR 0x8007 ++ ++/*------------------------------------*/ ++/* Request (bulk OUT) packet contents */ ++ ++typedef struct hfa384x_usb_txfrm { ++ hfa384x_tx_frame_t desc; ++ u8 data[WLAN_DATA_MAXLEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_txfrm_t; ++ ++typedef struct hfa384x_usb_cmdreq { ++ u16 type; ++ u16 cmd; ++ u16 parm0; ++ u16 parm1; ++ u16 parm2; ++ u8 pad[54]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdreq_t; ++ ++typedef struct hfa384x_usb_wridreq { ++ u16 type; ++ u16 frmlen; ++ u16 rid; ++ u8 data[HFA384x_RIDDATA_MAXLEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_wridreq_t; ++ ++typedef struct hfa384x_usb_rridreq { ++ u16 type; ++ u16 frmlen; ++ u16 rid; ++ u8 pad[58]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_rridreq_t; ++ ++typedef struct hfa384x_usb_wmemreq { ++ u16 type; ++ u16 frmlen; ++ u16 offset; ++ u16 page; ++ u8 data[HFA384x_USB_RWMEM_MAXLEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_wmemreq_t; ++ ++typedef struct hfa384x_usb_rmemreq { ++ u16 type; ++ u16 frmlen; ++ u16 offset; ++ u16 page; ++ u8 pad[56]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemreq_t; ++ ++/*------------------------------------*/ ++/* Response (bulk IN) packet contents */ ++ ++typedef struct hfa384x_usb_rxfrm { ++ hfa384x_rx_frame_t desc; ++ u8 data[WLAN_DATA_MAXLEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_rxfrm_t; ++ ++typedef struct hfa384x_usb_infofrm { ++ u16 type; ++ hfa384x_InfFrame_t info; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_infofrm_t; ++ ++typedef struct hfa384x_usb_statusresp { ++ u16 type; ++ u16 status; ++ u16 resp0; ++ u16 resp1; ++ u16 resp2; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdresp_t; ++ ++typedef hfa384x_usb_cmdresp_t hfa384x_usb_wridresp_t; ++ ++typedef struct hfa384x_usb_rridresp { ++ u16 type; ++ u16 frmlen; ++ u16 rid; ++ u8 data[HFA384x_RIDDATA_MAXLEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_rridresp_t; ++ ++typedef hfa384x_usb_cmdresp_t hfa384x_usb_wmemresp_t; ++ ++typedef struct hfa384x_usb_rmemresp { ++ u16 type; ++ u16 frmlen; ++ u8 data[HFA384x_USB_RWMEM_MAXLEN]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemresp_t; ++ ++typedef struct hfa384x_usb_bufavail { ++ u16 type; ++ u16 frmlen; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_bufavail_t; ++ ++typedef struct hfa384x_usb_error { ++ u16 type; ++ u16 errortype; ++} __WLAN_ATTRIB_PACK__ hfa384x_usb_error_t; ++ ++/*----------------------------------------------------------*/ ++/* Unions for packaging all the known packet types together */ ++ ++typedef union hfa384x_usbout { ++ u16 type; ++ hfa384x_usb_txfrm_t txfrm; ++ hfa384x_usb_cmdreq_t cmdreq; ++ hfa384x_usb_wridreq_t wridreq; ++ hfa384x_usb_rridreq_t rridreq; ++ hfa384x_usb_wmemreq_t wmemreq; ++ hfa384x_usb_rmemreq_t rmemreq; ++} __WLAN_ATTRIB_PACK__ hfa384x_usbout_t; ++ ++typedef union hfa384x_usbin { ++ u16 type; ++ hfa384x_usb_rxfrm_t rxfrm; ++ hfa384x_usb_txfrm_t txfrm; ++ hfa384x_usb_infofrm_t infofrm; ++ hfa384x_usb_cmdresp_t cmdresp; ++ hfa384x_usb_wridresp_t wridresp; ++ hfa384x_usb_rridresp_t rridresp; ++ hfa384x_usb_wmemresp_t wmemresp; ++ hfa384x_usb_rmemresp_t rmemresp; ++ hfa384x_usb_bufavail_t bufavail; ++ hfa384x_usb_error_t usberror; ++ u8 boguspad[3000]; ++} __WLAN_ATTRIB_PACK__ hfa384x_usbin_t; ++ ++/*-------------------------------------------------------------------- ++PD record structures. ++--------------------------------------------------------------------*/ ++ ++typedef struct hfa384x_pdr_pcb_partnum ++{ ++ u8 num[8]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_partnum_t; ++ ++typedef struct hfa384x_pdr_pcb_tracenum ++{ ++ u8 num[8]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_tracenum_t; ++ ++typedef struct hfa384x_pdr_nic_serial ++{ ++ u8 num[12]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_serial_t; ++ ++typedef struct hfa384x_pdr_mkk_measurements ++{ ++ double carrier_freq; ++ double occupied_band; ++ double power_density; ++ double tx_spur_f1; ++ double tx_spur_f2; ++ double tx_spur_f3; ++ double tx_spur_f4; ++ double tx_spur_l1; ++ double tx_spur_l2; ++ double tx_spur_l3; ++ double tx_spur_l4; ++ double rx_spur_f1; ++ double rx_spur_f2; ++ double rx_spur_l1; ++ double rx_spur_l2; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_measurements_t; ++ ++typedef struct hfa384x_pdr_nic_ramsize ++{ ++ u8 size[12]; /* units of KB */ ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_ramsize_t; ++ ++typedef struct hfa384x_pdr_mfisuprange ++{ ++ u16 id; ++ u16 variant; ++ u16 bottom; ++ u16 top; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mfisuprange_t; ++ ++typedef struct hfa384x_pdr_cfisuprange ++{ ++ u16 id; ++ u16 variant; ++ u16 bottom; ++ u16 top; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_cfisuprange_t; ++ ++typedef struct hfa384x_pdr_nicid ++{ ++ u16 id; ++ u16 variant; ++ u16 major; ++ u16 minor; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nicid_t; ++ ++ ++typedef struct hfa384x_pdr_refdac_measurements ++{ ++ u16 value[0]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_measurements_t; ++ ++typedef struct hfa384x_pdr_vgdac_measurements ++{ ++ u16 value[0]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_measurements_t; ++ ++typedef struct hfa384x_pdr_level_comp_measurements ++{ ++ u16 value[0]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_compc_measurements_t; ++ ++typedef struct hfa384x_pdr_mac_address ++{ ++ u8 addr[6]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mac_address_t; ++ ++typedef struct hfa384x_pdr_mkk_callname ++{ ++ u8 callname[8]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_callname_t; ++ ++typedef struct hfa384x_pdr_regdomain ++{ ++ u16 numdomains; ++ u16 domain[5]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_regdomain_t; ++ ++typedef struct hfa384x_pdr_allowed_channel ++{ ++ u16 ch_bitmap; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_allowed_channel_t; ++ ++typedef struct hfa384x_pdr_default_channel ++{ ++ u16 channel; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_default_channel_t; ++ ++typedef struct hfa384x_pdr_privacy_option ++{ ++ u16 available; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_privacy_option_t; ++ ++typedef struct hfa384x_pdr_temptype ++{ ++ u16 type; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_temptype_t; ++ ++typedef struct hfa384x_pdr_refdac_setup ++{ ++ u16 ch_value[14]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_setup_t; ++ ++typedef struct hfa384x_pdr_vgdac_setup ++{ ++ u16 ch_value[14]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_setup_t; ++ ++typedef struct hfa384x_pdr_level_comp_setup ++{ ++ u16 ch_value[14]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_comp_setup_t; ++ ++typedef struct hfa384x_pdr_trimdac_setup ++{ ++ u16 trimidac; ++ u16 trimqdac; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_trimdac_setup_t; ++ ++typedef struct hfa384x_pdr_ifr_setting ++{ ++ u16 value[3]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_ifr_setting_t; ++ ++typedef struct hfa384x_pdr_rfr_setting ++{ ++ u16 value[3]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_rfr_setting_t; ++ ++typedef struct hfa384x_pdr_hfa3861_baseline ++{ ++ u16 value[50]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_baseline_t; ++ ++typedef struct hfa384x_pdr_hfa3861_shadow ++{ ++ u32 value[32]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_shadow_t; ++ ++typedef struct hfa384x_pdr_hfa3861_ifrf ++{ ++ u32 value[20]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_ifrf_t; ++ ++typedef struct hfa384x_pdr_hfa3861_chcalsp ++{ ++ u16 value[14]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcalsp_t; ++ ++typedef struct hfa384x_pdr_hfa3861_chcali ++{ ++ u16 value[17]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcali_t; ++ ++typedef struct hfa384x_pdr_hfa3861_nic_config ++{ ++ u16 config_bitmap; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_config_t; ++ ++typedef struct hfa384x_pdr_hfo_delay ++{ ++ u8 hfo_delay; ++} __WLAN_ATTRIB_PACK__ hfa384x_hfo_delay_t; ++ ++typedef struct hfa384x_pdr_hfa3861_manf_testsp ++{ ++ u16 value[30]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testsp_t; ++ ++typedef struct hfa384x_pdr_hfa3861_manf_testi ++{ ++ u16 value[30]; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testi_t; ++ ++typedef struct hfa384x_end_of_pda ++{ ++ u16 crc; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdr_end_of_pda_t; ++ ++typedef struct hfa384x_pdrec ++{ ++ u16 len; /* in words */ ++ u16 code; ++ union pdr { ++ hfa384x_pdr_pcb_partnum_t pcb_partnum; ++ hfa384x_pdr_pcb_tracenum_t pcb_tracenum; ++ hfa384x_pdr_nic_serial_t nic_serial; ++ hfa384x_pdr_mkk_measurements_t mkk_measurements; ++ hfa384x_pdr_nic_ramsize_t nic_ramsize; ++ hfa384x_pdr_mfisuprange_t mfisuprange; ++ hfa384x_pdr_cfisuprange_t cfisuprange; ++ hfa384x_pdr_nicid_t nicid; ++ hfa384x_pdr_refdac_measurements_t refdac_measurements; ++ hfa384x_pdr_vgdac_measurements_t vgdac_measurements; ++ hfa384x_pdr_level_compc_measurements_t level_compc_measurements; ++ hfa384x_pdr_mac_address_t mac_address; ++ hfa384x_pdr_mkk_callname_t mkk_callname; ++ hfa384x_pdr_regdomain_t regdomain; ++ hfa384x_pdr_allowed_channel_t allowed_channel; ++ hfa384x_pdr_default_channel_t default_channel; ++ hfa384x_pdr_privacy_option_t privacy_option; ++ hfa384x_pdr_temptype_t temptype; ++ hfa384x_pdr_refdac_setup_t refdac_setup; ++ hfa384x_pdr_vgdac_setup_t vgdac_setup; ++ hfa384x_pdr_level_comp_setup_t level_comp_setup; ++ hfa384x_pdr_trimdac_setup_t trimdac_setup; ++ hfa384x_pdr_ifr_setting_t ifr_setting; ++ hfa384x_pdr_rfr_setting_t rfr_setting; ++ hfa384x_pdr_hfa3861_baseline_t hfa3861_baseline; ++ hfa384x_pdr_hfa3861_shadow_t hfa3861_shadow; ++ hfa384x_pdr_hfa3861_ifrf_t hfa3861_ifrf; ++ hfa384x_pdr_hfa3861_chcalsp_t hfa3861_chcalsp; ++ hfa384x_pdr_hfa3861_chcali_t hfa3861_chcali; ++ hfa384x_pdr_nic_config_t nic_config; ++ hfa384x_hfo_delay_t hfo_delay; ++ hfa384x_pdr_hfa3861_manf_testsp_t hfa3861_manf_testsp; ++ hfa384x_pdr_hfa3861_manf_testi_t hfa3861_manf_testi; ++ hfa384x_pdr_end_of_pda_t end_of_pda; ++ ++ } data; ++} __WLAN_ATTRIB_PACK__ hfa384x_pdrec_t; ++ ++ ++#ifdef __KERNEL__ ++/*-------------------------------------------------------------------- ++--- MAC state structure, argument to all functions -- ++--- Also, a collection of support types -- ++--------------------------------------------------------------------*/ ++typedef struct hfa384x_statusresult ++{ ++ u16 status; ++ u16 resp0; ++ u16 resp1; ++ u16 resp2; ++} hfa384x_cmdresult_t; ++ ++/* USB Control Exchange (CTLX): ++ * A queue of the structure below is maintained for all of the ++ * Request/Response type USB packets supported by Prism2. ++ */ ++/* The following hfa384x_* structures are arguments to ++ * the usercb() for the different CTLX types. ++ */ ++typedef hfa384x_cmdresult_t hfa384x_wridresult_t; ++typedef hfa384x_cmdresult_t hfa384x_wmemresult_t; ++ ++typedef struct hfa384x_rridresult ++{ ++ u16 rid; ++ const void *riddata; ++ unsigned int riddata_len; ++} hfa384x_rridresult_t; ++ ++enum ctlx_state { ++ CTLX_START = 0, /* Start state, not queued */ ++ ++ CTLX_COMPLETE, /* CTLX successfully completed */ ++ CTLX_REQ_FAILED, /* OUT URB completed w/ error */ ++ ++ CTLX_PENDING, /* Queued, data valid */ ++ CTLX_REQ_SUBMITTED, /* OUT URB submitted */ ++ CTLX_REQ_COMPLETE, /* OUT URB complete */ ++ CTLX_RESP_COMPLETE /* IN URB received */ ++}; ++typedef enum ctlx_state CTLX_STATE; ++ ++struct hfa384x_usbctlx; ++struct hfa384x; ++ ++typedef void (*ctlx_cmdcb_t)( struct hfa384x*, const struct hfa384x_usbctlx* ); ++ ++typedef void (*ctlx_usercb_t)( ++ struct hfa384x *hw, ++ void *ctlxresult, ++ void *usercb_data); ++ ++typedef struct hfa384x_usbctlx ++{ ++ struct list_head list; ++ ++ size_t outbufsize; ++ hfa384x_usbout_t outbuf; /* pkt buf for OUT */ ++ hfa384x_usbin_t inbuf; /* pkt buf for IN(a copy) */ ++ ++ CTLX_STATE state; /* Tracks running state */ ++ ++ struct completion done; ++ volatile int reapable; /* Food for the reaper task */ ++ ++ ctlx_cmdcb_t cmdcb; /* Async command callback */ ++ ctlx_usercb_t usercb; /* Async user callback, */ ++ void *usercb_data; /* at CTLX completion */ ++ ++ int variant; /* Identifies cmd variant */ ++} hfa384x_usbctlx_t; ++ ++typedef struct hfa384x_usbctlxq ++{ ++ spinlock_t lock; ++ struct list_head pending; ++ struct list_head active; ++ struct list_head completing; ++ struct list_head reapable; ++} hfa384x_usbctlxq_t; ++ ++typedef struct hfa484x_metacmd ++{ ++ u16 cmd; ++ ++ u16 parm0; ++ u16 parm1; ++ u16 parm2; ++ ++ hfa384x_cmdresult_t result; ++} hfa384x_metacmd_t; ++ ++#define MAX_PRISM2_GRP_ADDR 16 ++#define MAX_GRP_ADDR 32 ++#define WLAN_COMMENT_MAX 80 /* Max. length of user comment string. */ ++ ++#define MM_SAT_PCF (BIT14) ++#define MM_GCSD_PCF (BIT15) ++#define MM_GCSD_PCF_EB (BIT14 | BIT15) ++ ++#define WLAN_STATE_STOPPED 0 /* Network is not active. */ ++#define WLAN_STATE_STARTED 1 /* Network has been started. */ ++ ++#define WLAN_AUTH_MAX 60 /* Max. # of authenticated stations. */ ++#define WLAN_ACCESS_MAX 60 /* Max. # of stations in an access list. */ ++#define WLAN_ACCESS_NONE 0 /* No stations may be authenticated. */ ++#define WLAN_ACCESS_ALL 1 /* All stations may be authenticated. */ ++#define WLAN_ACCESS_ALLOW 2 /* Authenticate only "allowed" stations. */ ++#define WLAN_ACCESS_DENY 3 /* Do not authenticate "denied" stations. */ ++ ++/* XXX These are going away ASAP */ ++typedef struct prism2sta_authlist ++{ ++ unsigned int cnt; ++ u8 addr[WLAN_AUTH_MAX][WLAN_ADDR_LEN]; ++ u8 assoc[WLAN_AUTH_MAX]; ++} prism2sta_authlist_t; ++ ++typedef struct prism2sta_accesslist ++{ ++ unsigned int modify; ++ unsigned int cnt; ++ u8 addr[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; ++ unsigned int cnt1; ++ u8 addr1[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; ++} prism2sta_accesslist_t; ++ ++typedef struct hfa384x ++{ ++ /* USB support data */ ++ struct usb_device *usb; ++ struct urb rx_urb; ++ struct sk_buff *rx_urb_skb; ++ struct urb tx_urb; ++ struct urb ctlx_urb; ++ hfa384x_usbout_t txbuff; ++ hfa384x_usbctlxq_t ctlxq; ++ struct timer_list reqtimer; ++ struct timer_list resptimer; ++ ++ struct timer_list throttle; ++ ++ struct tasklet_struct reaper_bh; ++ struct tasklet_struct completion_bh; ++ ++ struct work_struct usb_work; ++ ++ unsigned long usb_flags; ++#define THROTTLE_RX 0 ++#define THROTTLE_TX 1 ++#define WORK_RX_HALT 2 ++#define WORK_TX_HALT 3 ++#define WORK_RX_RESUME 4 ++#define WORK_TX_RESUME 5 ++ ++ unsigned short req_timer_done:1; ++ unsigned short resp_timer_done:1; ++ ++ int endp_in; ++ int endp_out; ++ ++ int sniff_fcs; ++ int sniff_channel; ++ int sniff_truncate; ++ int sniffhdr; ++ ++ wait_queue_head_t cmdq; /* wait queue itself */ ++ ++ /* Controller state */ ++ u32 state; ++ u32 isap; ++ u8 port_enabled[HFA384x_NUMPORTS_MAX]; ++ ++ /* Download support */ ++ unsigned int dlstate; ++ hfa384x_downloadbuffer_t bufinfo; ++ u16 dltimeout; ++ ++ int scanflag; /* to signal scan comlete */ ++ int join_ap; /* are we joined to a specific ap */ ++ int join_retries; /* number of join retries till we fail */ ++ hfa384x_JoinRequest_data_t joinreq; /* join request saved data */ ++ ++ wlandevice_t *wlandev; ++ /* Timer to allow for the deferred processing of linkstatus messages */ ++ struct work_struct link_bh; ++ ++ struct work_struct commsqual_bh; ++ hfa384x_commsquality_t qual; ++ struct timer_list commsqual_timer; ++ ++ u16 link_status; ++ u16 link_status_new; ++ struct sk_buff_head authq; ++ ++ /* And here we have stuff that used to be in priv */ ++ ++ /* State variables */ ++ unsigned int presniff_port_type; ++ u16 presniff_wepflags; ++ u32 dot11_desired_bss_type; ++ ++ int dbmadjust; ++ ++ /* Group Addresses - right now, there are up to a total ++ of MAX_GRP_ADDR group addresses */ ++ u8 dot11_grp_addr[MAX_GRP_ADDR][WLAN_ADDR_LEN]; ++ unsigned int dot11_grpcnt; ++ ++ /* Component Identities */ ++ hfa384x_compident_t ident_nic; ++ hfa384x_compident_t ident_pri_fw; ++ hfa384x_compident_t ident_sta_fw; ++ hfa384x_compident_t ident_ap_fw; ++ u16 mm_mods; ++ ++ /* Supplier compatibility ranges */ ++ hfa384x_caplevel_t cap_sup_mfi; ++ hfa384x_caplevel_t cap_sup_cfi; ++ hfa384x_caplevel_t cap_sup_pri; ++ hfa384x_caplevel_t cap_sup_sta; ++ hfa384x_caplevel_t cap_sup_ap; ++ ++ /* Actor compatibility ranges */ ++ hfa384x_caplevel_t cap_act_pri_cfi; /* pri f/w to controller interface */ ++ hfa384x_caplevel_t cap_act_sta_cfi; /* sta f/w to controller interface */ ++ hfa384x_caplevel_t cap_act_sta_mfi; /* sta f/w to modem interface */ ++ hfa384x_caplevel_t cap_act_ap_cfi; /* ap f/w to controller interface */ ++ hfa384x_caplevel_t cap_act_ap_mfi; /* ap f/w to modem interface */ ++ ++ u32 psusercount; /* Power save user count. */ ++ hfa384x_CommTallies32_t tallies; /* Communication tallies. */ ++ u8 comment[WLAN_COMMENT_MAX+1]; /* User comment */ ++ ++ /* Channel Info request results (AP only) */ ++ struct { ++ atomic_t done; ++ u8 count; ++ hfa384x_ChInfoResult_t results; ++ } channel_info; ++ ++ hfa384x_InfFrame_t *scanresults; ++ ++ ++ prism2sta_authlist_t authlist; /* Authenticated station list. */ ++ unsigned int accessmode; /* Access mode. */ ++ prism2sta_accesslist_t allow; /* Allowed station list. */ ++ prism2sta_accesslist_t deny; /* Denied station list. */ ++ ++} hfa384x_t; ++ ++/*=============================================================*/ ++/*--- Function Declarations -----------------------------------*/ ++/*=============================================================*/ ++void ++hfa384x_create( ++ hfa384x_t *hw, ++ struct usb_device *usb); ++ ++void hfa384x_destroy(hfa384x_t *hw); ++ ++int ++hfa384x_corereset( hfa384x_t *hw, int holdtime, int settletime, int genesis); ++int ++hfa384x_drvr_chinforesults( hfa384x_t *hw); ++int ++hfa384x_drvr_commtallies( hfa384x_t *hw); ++int ++hfa384x_drvr_disable(hfa384x_t *hw, u16 macport); ++int ++hfa384x_drvr_enable(hfa384x_t *hw, u16 macport); ++int ++hfa384x_drvr_flashdl_enable(hfa384x_t *hw); ++int ++hfa384x_drvr_flashdl_disable(hfa384x_t *hw); ++int ++hfa384x_drvr_flashdl_write(hfa384x_t *hw, u32 daddr, void* buf, u32 len); ++int ++hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len); ++int ++hfa384x_drvr_handover( hfa384x_t *hw, u8 *addr); ++int ++hfa384x_drvr_hostscanresults( hfa384x_t *hw); ++int ++hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd); ++int ++hfa384x_drvr_mmi_read(hfa384x_t *hw, u32 address, u32 *result); ++int ++hfa384x_drvr_mmi_write(hfa384x_t *hw, u32 address, u32 data); ++int ++hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr); ++int ++hfa384x_drvr_ramdl_disable(hfa384x_t *hw); ++int ++hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void* buf, u32 len); ++int ++hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len); ++int ++hfa384x_drvr_scanresults( hfa384x_t *hw); ++ ++int ++hfa384x_drvr_setconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len); ++ ++static inline int ++hfa384x_drvr_getconfig16(hfa384x_t *hw, u16 rid, void *val) ++{ ++ int result = 0; ++ result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(u16)); ++ if ( result == 0 ) { ++ *((u16*)val) = hfa384x2host_16(*((u16*)val)); ++ } ++ return result; ++} ++ ++static inline int ++hfa384x_drvr_getconfig32(hfa384x_t *hw, u16 rid, void *val) ++{ ++ int result = 0; ++ ++ result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(u32)); ++ if ( result == 0 ) { ++ *((u32*)val) = hfa384x2host_32(*((u32*)val)); ++ } ++ ++ return result; ++} ++ ++static inline int ++hfa384x_drvr_setconfig16(hfa384x_t *hw, u16 rid, u16 val) ++{ ++ u16 value = host2hfa384x_16(val); ++ return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); ++} ++ ++static inline int ++hfa384x_drvr_setconfig32(hfa384x_t *hw, u16 rid, u32 val) ++{ ++ u32 value = host2hfa384x_32(val); ++ return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); ++} ++ ++int ++hfa384x_drvr_getconfig_async(hfa384x_t *hw, ++ u16 rid, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++int ++hfa384x_drvr_setconfig_async(hfa384x_t *hw, ++ u16 rid, ++ void *buf, ++ u16 len, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++static inline int ++hfa384x_drvr_setconfig16_async(hfa384x_t *hw, u16 rid, u16 val) ++{ ++ u16 value = host2hfa384x_16(val); ++ return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), ++ NULL , NULL); ++} ++ ++static inline int ++hfa384x_drvr_setconfig32_async(hfa384x_t *hw, u16 rid, u32 val) ++{ ++ u32 value = host2hfa384x_32(val); ++ return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), ++ NULL , NULL); ++} ++ ++ ++int ++hfa384x_drvr_start(hfa384x_t *hw); ++int ++hfa384x_drvr_stop(hfa384x_t *hw); ++int ++hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); ++void ++hfa384x_tx_timeout(wlandevice_t *wlandev); ++ ++int ++hfa384x_cmd_initialize(hfa384x_t *hw); ++int ++hfa384x_cmd_enable(hfa384x_t *hw, u16 macport); ++int ++hfa384x_cmd_disable(hfa384x_t *hw, u16 macport); ++int ++hfa384x_cmd_diagnose(hfa384x_t *hw); ++int ++hfa384x_cmd_allocate(hfa384x_t *hw, u16 len); ++int ++hfa384x_cmd_transmit(hfa384x_t *hw, u16 reclaim, u16 qos, u16 fid); ++int ++hfa384x_cmd_clearpersist(hfa384x_t *hw, u16 fid); ++int ++hfa384x_cmd_access(hfa384x_t *hw, u16 write, u16 rid, void *buf, u16 len); ++int ++hfa384x_cmd_monitor(hfa384x_t *hw, u16 enable); ++int ++hfa384x_cmd_download( ++ hfa384x_t *hw, ++ u16 mode, ++ u16 lowaddr, ++ u16 highaddr, ++ u16 codelen); ++int ++hfa384x_cmd_aux_enable(hfa384x_t *hw, int force); ++int ++hfa384x_cmd_aux_disable(hfa384x_t *hw); ++int ++hfa384x_copy_from_bap( ++ hfa384x_t *hw, ++ u16 bap, ++ u16 id, ++ u16 offset, ++ void *buf, ++ unsigned int len); ++int ++hfa384x_copy_to_bap( ++ hfa384x_t *hw, ++ u16 bap, ++ u16 id, ++ u16 offset, ++ void *buf, ++ unsigned int len); ++void ++hfa384x_copy_from_aux( ++ hfa384x_t *hw, ++ u32 cardaddr, ++ u32 auxctl, ++ void *buf, ++ unsigned int len); ++void ++hfa384x_copy_to_aux( ++ hfa384x_t *hw, ++ u32 cardaddr, ++ u32 auxctl, ++ void *buf, ++ unsigned int len); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _HFA384x_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/hfa384x_usb.c +@@ -0,0 +1,4690 @@ ++/* src/prism2/driver/hfa384x_usb.c ++* ++* Functions that talk to the USB variantof the Intersil hfa384x MAC ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file implements functions that correspond to the prism2/hfa384x ++* 802.11 MAC hardware and firmware host interface. ++* ++* The functions can be considered to represent several levels of ++* abstraction. The lowest level functions are simply C-callable wrappers ++* around the register accesses. The next higher level represents C-callable ++* prism2 API functions that match the Intersil documentation as closely ++* as is reasonable. The next higher layer implements common sequences ++* of invokations of the API layer (e.g. write to bap, followed by cmd). ++* ++* Common sequences: ++* hfa384x_drvr_xxx Highest level abstractions provided by the ++* hfa384x code. They are driver defined wrappers ++* for common sequences. These functions generally ++* use the services of the lower levels. ++* ++* hfa384x_drvr_xxxconfig An example of the drvr level abstraction. These ++* functions are wrappers for the RID get/set ++* sequence. They call copy_[to|from]_bap() and ++* cmd_access(). These functions operate on the ++* RIDs and buffers without validation. The caller ++* is responsible for that. ++* ++* API wrapper functions: ++* hfa384x_cmd_xxx functions that provide access to the f/w commands. ++* The function arguments correspond to each command ++* argument, even command arguments that get packed ++* into single registers. These functions _just_ ++* issue the command by setting the cmd/parm regs ++* & reading the status/resp regs. Additional ++* activities required to fully use a command ++* (read/write from/to bap, get/set int status etc.) ++* are implemented separately. Think of these as ++* C-callable prism2 commands. ++* ++* Lowest Layer Functions: ++* hfa384x_docmd_xxx These functions implement the sequence required ++* to issue any prism2 command. Primarily used by the ++* hfa384x_cmd_xxx functions. ++* ++* hfa384x_bap_xxx BAP read/write access functions. ++* Note: we usually use BAP0 for non-interrupt context ++* and BAP1 for interrupt context. ++* ++* hfa384x_dl_xxx download related functions. ++* ++* Driver State Issues: ++* Note that there are two pairs of functions that manage the ++* 'initialized' and 'running' states of the hw/MAC combo. The four ++* functions are create(), destroy(), start(), and stop(). create() ++* sets up the data structures required to support the hfa384x_* ++* functions and destroy() cleans them up. The start() function gets ++* the actual hardware running and enables the interrupts. The stop() ++* function shuts the hardware down. The sequence should be: ++* create() ++* start() ++* . ++* . Do interesting things w/ the hardware ++* . ++* stop() ++* destroy() ++* ++* Note that destroy() can be called without calling stop() first. ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++#define WLAN_DBVAR prism2_debug ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wlan_compat.h" ++ ++#define SUBMIT_URB(u,f) usb_submit_urb(u,f) ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211mgmt.h" ++#include "p80211conv.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211req.h" ++#include "p80211metadef.h" ++#include "p80211metastruct.h" ++#include "hfa384x.h" ++#include "prism2mgmt.h" ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++enum cmd_mode ++{ ++ DOWAIT = 0, ++ DOASYNC ++}; ++typedef enum cmd_mode CMD_MODE; ++ ++#define THROTTLE_JIFFIES (HZ/8) ++ ++/*================================================================*/ ++/* Local Macros */ ++ ++#define ROUNDUP64(a) (((a)+63)&~63) ++ ++/*================================================================*/ ++/* Local Types */ ++ ++/*================================================================*/ ++/* Local Static Definitions */ ++extern int prism2_debug; ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++#ifdef DEBUG_USB ++static void ++dbprint_urb(struct urb* urb); ++#endif ++ ++static void ++hfa384x_int_rxmonitor( ++ wlandevice_t *wlandev, ++ hfa384x_usb_rxfrm_t *rxfrm); ++ ++static void ++hfa384x_usb_defer(struct work_struct *data); ++ ++static int ++submit_rx_urb(hfa384x_t *hw, gfp_t flags); ++ ++static int ++submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t flags); ++ ++/*---------------------------------------------------*/ ++/* Callbacks */ ++static void ++hfa384x_usbout_callback(struct urb *urb); ++static void ++hfa384x_ctlxout_callback(struct urb *urb); ++static void ++hfa384x_usbin_callback(struct urb *urb); ++ ++static void ++hfa384x_usbin_txcompl(wlandevice_t *wlandev, hfa384x_usbin_t *usbin); ++ ++static void ++hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb); ++ ++static void ++hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin); ++ ++static void ++hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout); ++ ++static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, ++ int urb_status); ++ ++/*---------------------------------------------------*/ ++/* Functions to support the prism2 usb command queue */ ++ ++static void ++hfa384x_usbctlxq_run(hfa384x_t *hw); ++ ++static void ++hfa384x_usbctlx_reqtimerfn(unsigned long data); ++ ++static void ++hfa384x_usbctlx_resptimerfn(unsigned long data); ++ ++static void ++hfa384x_usb_throttlefn(unsigned long data); ++ ++static void ++hfa384x_usbctlx_completion_task(unsigned long data); ++ ++static void ++hfa384x_usbctlx_reaper_task(unsigned long data); ++ ++static int ++hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); ++ ++static void ++unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); ++ ++struct usbctlx_completor ++{ ++ int (*complete)(struct usbctlx_completor*); ++}; ++typedef struct usbctlx_completor usbctlx_completor_t; ++ ++static int ++hfa384x_usbctlx_complete_sync(hfa384x_t *hw, ++ hfa384x_usbctlx_t *ctlx, ++ usbctlx_completor_t *completor); ++ ++static int ++unlocked_usbctlx_cancel_async(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx); ++ ++static void ++hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx); ++ ++static void ++hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx); ++ ++static int ++usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, ++ hfa384x_cmdresult_t *result); ++ ++static void ++usbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, ++ hfa384x_rridresult_t *result); ++ ++/*---------------------------------------------------*/ ++/* Low level req/resp CTLX formatters and submitters */ ++static int ++hfa384x_docmd( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ hfa384x_metacmd_t *cmd, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++static int ++hfa384x_dorrid( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 rid, ++ void *riddata, ++ unsigned int riddatalen, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++static int ++hfa384x_dowrid( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 rid, ++ void *riddata, ++ unsigned int riddatalen, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++static int ++hfa384x_dormem( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 page, ++ u16 offset, ++ void *data, ++ unsigned int len, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++static int ++hfa384x_dowmem( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 page, ++ u16 offset, ++ void *data, ++ unsigned int len, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data); ++ ++static int ++hfa384x_isgood_pdrcode(u16 pdrcode); ++ ++/*================================================================*/ ++/* Function Definitions */ ++static inline const char* ctlxstr(CTLX_STATE s) ++{ ++ static const char* ctlx_str[] = { ++ "Initial state", ++ "Complete", ++ "Request failed", ++ "Request pending", ++ "Request packet submitted", ++ "Request packet completed", ++ "Response packet completed" ++ }; ++ ++ return ctlx_str[s]; ++}; ++ ++ ++static inline hfa384x_usbctlx_t* ++get_active_ctlx(hfa384x_t *hw) ++{ ++ return list_entry(hw->ctlxq.active.next, hfa384x_usbctlx_t, list); ++} ++ ++ ++#ifdef DEBUG_USB ++void ++dbprint_urb(struct urb* urb) ++{ ++ WLAN_LOG_DEBUG(3,"urb->pipe=0x%08x\n", urb->pipe); ++ WLAN_LOG_DEBUG(3,"urb->status=0x%08x\n", urb->status); ++ WLAN_LOG_DEBUG(3,"urb->transfer_flags=0x%08x\n", urb->transfer_flags); ++ WLAN_LOG_DEBUG(3,"urb->transfer_buffer=0x%08x\n", (unsigned int)urb->transfer_buffer); ++ WLAN_LOG_DEBUG(3,"urb->transfer_buffer_length=0x%08x\n", urb->transfer_buffer_length); ++ WLAN_LOG_DEBUG(3,"urb->actual_length=0x%08x\n", urb->actual_length); ++ WLAN_LOG_DEBUG(3,"urb->bandwidth=0x%08x\n", urb->bandwidth); ++ WLAN_LOG_DEBUG(3,"urb->setup_packet(ctl)=0x%08x\n", (unsigned int)urb->setup_packet); ++ WLAN_LOG_DEBUG(3,"urb->start_frame(iso/irq)=0x%08x\n", urb->start_frame); ++ WLAN_LOG_DEBUG(3,"urb->interval(irq)=0x%08x\n", urb->interval); ++ WLAN_LOG_DEBUG(3,"urb->error_count(iso)=0x%08x\n", urb->error_count); ++ WLAN_LOG_DEBUG(3,"urb->timeout=0x%08x\n", urb->timeout); ++ WLAN_LOG_DEBUG(3,"urb->context=0x%08x\n", (unsigned int)urb->context); ++ WLAN_LOG_DEBUG(3,"urb->complete=0x%08x\n", (unsigned int)urb->complete); ++} ++#endif ++ ++ ++/*---------------------------------------------------------------- ++* submit_rx_urb ++* ++* Listen for input data on the BULK-IN pipe. If the pipe has ++* stalled then schedule it to be reset. ++* ++* Arguments: ++* hw device struct ++* memflags memory allocation flags ++* ++* Returns: ++* error code from submission ++* ++* Call context: ++* Any ++----------------------------------------------------------------*/ ++static int ++submit_rx_urb(hfa384x_t *hw, gfp_t memflags) ++{ ++ struct sk_buff *skb; ++ int result; ++ ++ DBFENTER; ++ ++ skb = dev_alloc_skb(sizeof(hfa384x_usbin_t)); ++ if (skb == NULL) { ++ result = -ENOMEM; ++ goto done; ++ } ++ ++ /* Post the IN urb */ ++ usb_fill_bulk_urb(&hw->rx_urb, hw->usb, ++ hw->endp_in, ++ skb->data, sizeof(hfa384x_usbin_t), ++ hfa384x_usbin_callback, hw->wlandev); ++ ++ hw->rx_urb_skb = skb; ++ ++ result = -ENOLINK; ++ if ( !hw->wlandev->hwremoved && !test_bit(WORK_RX_HALT, &hw->usb_flags)) { ++ result = SUBMIT_URB(&hw->rx_urb, memflags); ++ ++ /* Check whether we need to reset the RX pipe */ ++ if (result == -EPIPE) { ++ WLAN_LOG_WARNING("%s rx pipe stalled: requesting reset\n", ++ hw->wlandev->netdev->name); ++ if ( !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) ++ schedule_work(&hw->usb_work); ++ } ++ } ++ ++ /* Don't leak memory if anything should go wrong */ ++ if (result != 0) { ++ dev_kfree_skb(skb); ++ hw->rx_urb_skb = NULL; ++ } ++ ++ done: ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* submit_tx_urb ++* ++* Prepares and submits the URB of transmitted data. If the ++* submission fails then it will schedule the output pipe to ++* be reset. ++* ++* Arguments: ++* hw device struct ++* tx_urb URB of data for tranmission ++* memflags memory allocation flags ++* ++* Returns: ++* error code from submission ++* ++* Call context: ++* Any ++----------------------------------------------------------------*/ ++static int ++submit_tx_urb(hfa384x_t *hw, struct urb *tx_urb, gfp_t memflags) ++{ ++ struct net_device *netdev = hw->wlandev->netdev; ++ int result; ++ ++ DBFENTER; ++ ++ result = -ENOLINK; ++ if ( netif_running(netdev) ) { ++ ++ if ( !hw->wlandev->hwremoved && !test_bit(WORK_TX_HALT, &hw->usb_flags) ) { ++ result = SUBMIT_URB(tx_urb, memflags); ++ ++ /* Test whether we need to reset the TX pipe */ ++ if (result == -EPIPE) { ++ WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", ++ netdev->name); ++ set_bit(WORK_TX_HALT, &hw->usb_flags); ++ schedule_work(&hw->usb_work); ++ } else if (result == 0) { ++ netif_stop_queue(netdev); ++ } ++ } ++ } ++ ++ DBFEXIT; ++ ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* hfa394x_usb_defer ++* ++* There are some things that the USB stack cannot do while ++* in interrupt context, so we arrange this function to run ++* in process context. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* nothing ++* ++* Call context: ++* process (by design) ++----------------------------------------------------------------*/ ++static void ++hfa384x_usb_defer(struct work_struct *data) ++{ ++ hfa384x_t *hw = container_of(data, struct hfa384x, usb_work); ++ struct net_device *netdev = hw->wlandev->netdev; ++ ++ DBFENTER; ++ ++ /* Don't bother trying to reset anything if the plug ++ * has been pulled ... ++ */ ++ if ( hw->wlandev->hwremoved ) { ++ DBFEXIT; ++ return; ++ } ++ ++ /* Reception has stopped: try to reset the input pipe */ ++ if (test_bit(WORK_RX_HALT, &hw->usb_flags)) { ++ int ret; ++ ++ usb_kill_urb(&hw->rx_urb); /* Cannot be holding spinlock! */ ++ ++ ret = usb_clear_halt(hw->usb, hw->endp_in); ++ if (ret != 0) { ++ printk(KERN_ERR ++ "Failed to clear rx pipe for %s: err=%d\n", ++ netdev->name, ret); ++ } else { ++ printk(KERN_INFO "%s rx pipe reset complete.\n", ++ netdev->name); ++ clear_bit(WORK_RX_HALT, &hw->usb_flags); ++ set_bit(WORK_RX_RESUME, &hw->usb_flags); ++ } ++ } ++ ++ /* Resume receiving data back from the device. */ ++ if ( test_bit(WORK_RX_RESUME, &hw->usb_flags) ) { ++ int ret; ++ ++ ret = submit_rx_urb(hw, GFP_KERNEL); ++ if (ret != 0) { ++ printk(KERN_ERR ++ "Failed to resume %s rx pipe.\n", netdev->name); ++ } else { ++ clear_bit(WORK_RX_RESUME, &hw->usb_flags); ++ } ++ } ++ ++ /* Transmission has stopped: try to reset the output pipe */ ++ if (test_bit(WORK_TX_HALT, &hw->usb_flags)) { ++ int ret; ++ ++ usb_kill_urb(&hw->tx_urb); ++ ret = usb_clear_halt(hw->usb, hw->endp_out); ++ if (ret != 0) { ++ printk(KERN_ERR ++ "Failed to clear tx pipe for %s: err=%d\n", ++ netdev->name, ret); ++ } else { ++ printk(KERN_INFO "%s tx pipe reset complete.\n", ++ netdev->name); ++ clear_bit(WORK_TX_HALT, &hw->usb_flags); ++ set_bit(WORK_TX_RESUME, &hw->usb_flags); ++ ++ /* Stopping the BULK-OUT pipe also blocked ++ * us from sending any more CTLX URBs, so ++ * we need to re-run our queue ... ++ */ ++ hfa384x_usbctlxq_run(hw); ++ } ++ } ++ ++ /* Resume transmitting. */ ++ if ( test_and_clear_bit(WORK_TX_RESUME, &hw->usb_flags) ) { ++ netif_wake_queue(hw->wlandev->netdev); ++ } ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_create ++* ++* Sets up the hfa384x_t data structure for use. Note this ++* does _not_ intialize the actual hardware, just the data structures ++* we use to keep track of its state. ++* ++* Arguments: ++* hw device structure ++* irq device irq number ++* iobase i/o base address for register access ++* membase memory base address for register access ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++void ++hfa384x_create( hfa384x_t *hw, struct usb_device *usb) ++{ ++ DBFENTER; ++ ++ memset(hw, 0, sizeof(hfa384x_t)); ++ hw->usb = usb; ++ ++ /* set up the endpoints */ ++ hw->endp_in = usb_rcvbulkpipe(usb, 1); ++ hw->endp_out = usb_sndbulkpipe(usb, 2); ++ ++ /* Set up the waitq */ ++ init_waitqueue_head(&hw->cmdq); ++ ++ /* Initialize the command queue */ ++ spin_lock_init(&hw->ctlxq.lock); ++ INIT_LIST_HEAD(&hw->ctlxq.pending); ++ INIT_LIST_HEAD(&hw->ctlxq.active); ++ INIT_LIST_HEAD(&hw->ctlxq.completing); ++ INIT_LIST_HEAD(&hw->ctlxq.reapable); ++ ++ /* Initialize the authentication queue */ ++ skb_queue_head_init(&hw->authq); ++ ++ tasklet_init(&hw->reaper_bh, ++ hfa384x_usbctlx_reaper_task, ++ (unsigned long)hw); ++ tasklet_init(&hw->completion_bh, ++ hfa384x_usbctlx_completion_task, ++ (unsigned long)hw); ++ INIT_WORK(&hw->link_bh, prism2sta_processing_defer); ++ INIT_WORK(&hw->usb_work, hfa384x_usb_defer); ++ ++ init_timer(&hw->throttle); ++ hw->throttle.function = hfa384x_usb_throttlefn; ++ hw->throttle.data = (unsigned long)hw; ++ ++ init_timer(&hw->resptimer); ++ hw->resptimer.function = hfa384x_usbctlx_resptimerfn; ++ hw->resptimer.data = (unsigned long)hw; ++ ++ init_timer(&hw->reqtimer); ++ hw->reqtimer.function = hfa384x_usbctlx_reqtimerfn; ++ hw->reqtimer.data = (unsigned long)hw; ++ ++ usb_init_urb(&hw->rx_urb); ++ usb_init_urb(&hw->tx_urb); ++ usb_init_urb(&hw->ctlx_urb); ++ ++ hw->link_status = HFA384x_LINK_NOTCONNECTED; ++ hw->state = HFA384x_STATE_INIT; ++ ++ INIT_WORK(&hw->commsqual_bh, prism2sta_commsqual_defer); ++ init_timer(&hw->commsqual_timer); ++ hw->commsqual_timer.data = (unsigned long) hw; ++ hw->commsqual_timer.function = prism2sta_commsqual_timer; ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_destroy ++* ++* Partner to hfa384x_create(). This function cleans up the hw ++* structure so that it can be freed by the caller using a simple ++* kfree. Currently, this function is just a placeholder. If, at some ++* point in the future, an hw in the 'shutdown' state requires a 'deep' ++* kfree, this is where it should be done. Note that if this function ++* is called on a _running_ hw structure, the drvr_stop() function is ++* called. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* nothing, this function is not allowed to fail. ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++void ++hfa384x_destroy( hfa384x_t *hw) ++{ ++ struct sk_buff *skb; ++ ++ DBFENTER; ++ ++ if ( hw->state == HFA384x_STATE_RUNNING ) { ++ hfa384x_drvr_stop(hw); ++ } ++ hw->state = HFA384x_STATE_PREINIT; ++ ++ if (hw->scanresults) { ++ kfree(hw->scanresults); ++ hw->scanresults = NULL; ++ } ++ ++ /* Now to clean out the auth queue */ ++ while ( (skb = skb_dequeue(&hw->authq)) ) { ++ dev_kfree_skb(skb); ++ } ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++ */ ++static hfa384x_usbctlx_t* usbctlx_alloc(void) ++{ ++ hfa384x_usbctlx_t *ctlx; ++ ++ ctlx = kmalloc(sizeof(*ctlx), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++ if (ctlx != NULL) ++ { ++ memset(ctlx, 0, sizeof(*ctlx)); ++ init_completion(&ctlx->done); ++ } ++ ++ return ctlx; ++} ++ ++ ++/*---------------------------------------------------------------- ++ * ++----------------------------------------------------------------*/ ++static int ++usbctlx_get_status(const hfa384x_usb_cmdresp_t *cmdresp, ++ hfa384x_cmdresult_t *result) ++{ ++ DBFENTER; ++ ++ result->status = hfa384x2host_16(cmdresp->status); ++ result->resp0 = hfa384x2host_16(cmdresp->resp0); ++ result->resp1 = hfa384x2host_16(cmdresp->resp1); ++ result->resp2 = hfa384x2host_16(cmdresp->resp2); ++ ++ WLAN_LOG_DEBUG(4, "cmdresult:status=0x%04x " ++ "resp0=0x%04x resp1=0x%04x resp2=0x%04x\n", ++ result->status, ++ result->resp0, ++ result->resp1, ++ result->resp2); ++ ++ DBFEXIT; ++ return (result->status & HFA384x_STATUS_RESULT); ++} ++ ++static void ++usbctlx_get_rridresult(const hfa384x_usb_rridresp_t *rridresp, ++ hfa384x_rridresult_t *result) ++{ ++ DBFENTER; ++ ++ result->rid = hfa384x2host_16(rridresp->rid); ++ result->riddata = rridresp->data; ++ result->riddata_len = ((hfa384x2host_16(rridresp->frmlen) - 1) * 2); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* Completor object: ++* This completor must be passed to hfa384x_usbctlx_complete_sync() ++* when processing a CTLX that returns a hfa384x_cmdresult_t structure. ++----------------------------------------------------------------*/ ++struct usbctlx_cmd_completor ++{ ++ usbctlx_completor_t head; ++ ++ const hfa384x_usb_cmdresp_t *cmdresp; ++ hfa384x_cmdresult_t *result; ++}; ++typedef struct usbctlx_cmd_completor usbctlx_cmd_completor_t; ++ ++static int usbctlx_cmd_completor_fn(usbctlx_completor_t *head) ++{ ++ usbctlx_cmd_completor_t *complete = (usbctlx_cmd_completor_t*)head; ++ return usbctlx_get_status(complete->cmdresp, complete->result); ++} ++ ++static inline usbctlx_completor_t* ++init_cmd_completor(usbctlx_cmd_completor_t *completor, ++ const hfa384x_usb_cmdresp_t *cmdresp, ++ hfa384x_cmdresult_t *result) ++{ ++ completor->head.complete = usbctlx_cmd_completor_fn; ++ completor->cmdresp = cmdresp; ++ completor->result = result; ++ return &(completor->head); ++} ++ ++/*---------------------------------------------------------------- ++* Completor object: ++* This completor must be passed to hfa384x_usbctlx_complete_sync() ++* when processing a CTLX that reads a RID. ++----------------------------------------------------------------*/ ++struct usbctlx_rrid_completor ++{ ++ usbctlx_completor_t head; ++ ++ const hfa384x_usb_rridresp_t *rridresp; ++ void *riddata; ++ unsigned int riddatalen; ++}; ++typedef struct usbctlx_rrid_completor usbctlx_rrid_completor_t; ++ ++static int usbctlx_rrid_completor_fn(usbctlx_completor_t *head) ++{ ++ usbctlx_rrid_completor_t *complete = (usbctlx_rrid_completor_t*)head; ++ hfa384x_rridresult_t rridresult; ++ ++ usbctlx_get_rridresult(complete->rridresp, &rridresult); ++ ++ /* Validate the length, note body len calculation in bytes */ ++ if ( rridresult.riddata_len != complete->riddatalen ) { ++ WLAN_LOG_WARNING( ++ "RID len mismatch, rid=0x%04x hlen=%d fwlen=%d\n", ++ rridresult.rid, ++ complete->riddatalen, ++ rridresult.riddata_len); ++ return -ENODATA; ++ } ++ ++ memcpy(complete->riddata, ++ rridresult.riddata, ++ complete->riddatalen); ++ return 0; ++} ++ ++static inline usbctlx_completor_t* ++init_rrid_completor(usbctlx_rrid_completor_t *completor, ++ const hfa384x_usb_rridresp_t *rridresp, ++ void *riddata, ++ unsigned int riddatalen) ++{ ++ completor->head.complete = usbctlx_rrid_completor_fn; ++ completor->rridresp = rridresp; ++ completor->riddata = riddata; ++ completor->riddatalen = riddatalen; ++ return &(completor->head); ++} ++ ++/*---------------------------------------------------------------- ++* Completor object: ++* Interprets the results of a synchronous RID-write ++----------------------------------------------------------------*/ ++typedef usbctlx_cmd_completor_t usbctlx_wrid_completor_t; ++#define init_wrid_completor init_cmd_completor ++ ++/*---------------------------------------------------------------- ++* Completor object: ++* Interprets the results of a synchronous memory-write ++----------------------------------------------------------------*/ ++typedef usbctlx_cmd_completor_t usbctlx_wmem_completor_t; ++#define init_wmem_completor init_cmd_completor ++ ++/*---------------------------------------------------------------- ++* Completor object: ++* Interprets the results of a synchronous memory-read ++----------------------------------------------------------------*/ ++struct usbctlx_rmem_completor ++{ ++ usbctlx_completor_t head; ++ ++ const hfa384x_usb_rmemresp_t *rmemresp; ++ void *data; ++ unsigned int len; ++}; ++typedef struct usbctlx_rmem_completor usbctlx_rmem_completor_t; ++ ++static int usbctlx_rmem_completor_fn(usbctlx_completor_t *head) ++{ ++ usbctlx_rmem_completor_t *complete = (usbctlx_rmem_completor_t*)head; ++ ++ WLAN_LOG_DEBUG(4,"rmemresp:len=%d\n", complete->rmemresp->frmlen); ++ memcpy(complete->data, complete->rmemresp->data, complete->len); ++ return 0; ++} ++ ++static inline usbctlx_completor_t* ++init_rmem_completor(usbctlx_rmem_completor_t *completor, ++ hfa384x_usb_rmemresp_t *rmemresp, ++ void *data, ++ unsigned int len) ++{ ++ completor->head.complete = usbctlx_rmem_completor_fn; ++ completor->rmemresp = rmemresp; ++ completor->data = data; ++ completor->len = len; ++ return &(completor->head); ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_cb_status ++* ++* Ctlx_complete handler for async CMD type control exchanges. ++* mark the hw struct as such. ++* ++* Note: If the handling is changed here, it should probably be ++* changed in docmd as well. ++* ++* Arguments: ++* hw hw struct ++* ctlx completed CTLX ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void ++hfa384x_cb_status(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) ++{ ++ DBFENTER; ++ ++ if ( ctlx->usercb != NULL ) { ++ hfa384x_cmdresult_t cmdresult; ++ ++ if (ctlx->state != CTLX_COMPLETE) { ++ memset(&cmdresult, 0, sizeof(cmdresult)); ++ cmdresult.status = HFA384x_STATUS_RESULT_SET(HFA384x_CMD_ERR); ++ } else { ++ usbctlx_get_status(&ctlx->inbuf.cmdresp, &cmdresult); ++ } ++ ++ ctlx->usercb(hw, &cmdresult, ctlx->usercb_data); ++ } ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_cb_rrid ++* ++* CTLX completion handler for async RRID type control exchanges. ++* ++* Note: If the handling is changed here, it should probably be ++* changed in dorrid as well. ++* ++* Arguments: ++* hw hw struct ++* ctlx completed CTLX ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void ++hfa384x_cb_rrid(hfa384x_t *hw, const hfa384x_usbctlx_t *ctlx) ++{ ++ DBFENTER; ++ ++ if ( ctlx->usercb != NULL ) { ++ hfa384x_rridresult_t rridresult; ++ ++ if (ctlx->state != CTLX_COMPLETE) { ++ memset(&rridresult, 0, sizeof(rridresult)); ++ rridresult.rid = hfa384x2host_16(ctlx->outbuf.rridreq.rid); ++ } else { ++ usbctlx_get_rridresult(&ctlx->inbuf.rridresp, &rridresult); ++ } ++ ++ ctlx->usercb(hw, &rridresult, ctlx->usercb_data); ++ } ++ ++ DBFEXIT; ++} ++ ++static inline int ++hfa384x_docmd_wait(hfa384x_t *hw, hfa384x_metacmd_t *cmd) ++{ ++ return hfa384x_docmd(hw, DOWAIT, cmd, NULL, NULL, NULL); ++} ++ ++static inline int ++hfa384x_docmd_async(hfa384x_t *hw, ++ hfa384x_metacmd_t *cmd, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_docmd(hw, DOASYNC, cmd, ++ cmdcb, usercb, usercb_data); ++} ++ ++static inline int ++hfa384x_dorrid_wait(hfa384x_t *hw, u16 rid, void *riddata, unsigned int riddatalen) ++{ ++ return hfa384x_dorrid(hw, DOWAIT, ++ rid, riddata, riddatalen, ++ NULL, NULL, NULL); ++} ++ ++static inline int ++hfa384x_dorrid_async(hfa384x_t *hw, ++ u16 rid, void *riddata, unsigned int riddatalen, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_dorrid(hw, DOASYNC, ++ rid, riddata, riddatalen, ++ cmdcb, usercb, usercb_data); ++} ++ ++static inline int ++hfa384x_dowrid_wait(hfa384x_t *hw, u16 rid, void *riddata, unsigned int riddatalen) ++{ ++ return hfa384x_dowrid(hw, DOWAIT, ++ rid, riddata, riddatalen, ++ NULL, NULL, NULL); ++} ++ ++static inline int ++hfa384x_dowrid_async(hfa384x_t *hw, ++ u16 rid, void *riddata, unsigned int riddatalen, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_dowrid(hw, DOASYNC, ++ rid, riddata, riddatalen, ++ cmdcb, usercb, usercb_data); ++} ++ ++static inline int ++hfa384x_dormem_wait(hfa384x_t *hw, ++ u16 page, u16 offset, void *data, unsigned int len) ++{ ++ return hfa384x_dormem(hw, DOWAIT, ++ page, offset, data, len, ++ NULL, NULL, NULL); ++} ++ ++static inline int ++hfa384x_dormem_async(hfa384x_t *hw, ++ u16 page, u16 offset, void *data, unsigned int len, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_dormem(hw, DOASYNC, ++ page, offset, data, len, ++ cmdcb, usercb, usercb_data); ++} ++ ++static inline int ++hfa384x_dowmem_wait( ++ hfa384x_t *hw, ++ u16 page, ++ u16 offset, ++ void *data, ++ unsigned int len) ++{ ++ return hfa384x_dowmem(hw, DOWAIT, ++ page, offset, data, len, ++ NULL, NULL, NULL); ++} ++ ++static inline int ++hfa384x_dowmem_async( ++ hfa384x_t *hw, ++ u16 page, ++ u16 offset, ++ void *data, ++ unsigned int len, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_dowmem(hw, DOASYNC, ++ page, offset, data, len, ++ cmdcb, usercb, usercb_data); ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_cmd_initialize ++* ++* Issues the initialize command and sets the hw->state based ++* on the result. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int ++hfa384x_cmd_initialize(hfa384x_t *hw) ++{ ++ int result = 0; ++ int i; ++ hfa384x_metacmd_t cmd; ++ ++ DBFENTER; ++ ++ ++ cmd.cmd = HFA384x_CMDCODE_INIT; ++ cmd.parm0 = 0; ++ cmd.parm1 = 0; ++ cmd.parm2 = 0; ++ ++ result = hfa384x_docmd_wait(hw, &cmd); ++ ++ ++ WLAN_LOG_DEBUG(3,"cmdresp.init: " ++ "status=0x%04x, resp0=0x%04x, " ++ "resp1=0x%04x, resp2=0x%04x\n", ++ cmd.result.status, ++ cmd.result.resp0, ++ cmd.result.resp1, ++ cmd.result.resp2); ++ if ( result == 0 ) { ++ for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) { ++ hw->port_enabled[i] = 0; ++ } ++ } ++ ++ hw->link_status = HFA384x_LINK_NOTCONNECTED; ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_cmd_disable ++* ++* Issues the disable command to stop communications on one of ++* the MACs 'ports'. ++* ++* Arguments: ++* hw device structure ++* macport MAC port number (host order) ++* ++* Returns: ++* 0 success ++* >0 f/w reported failure - f/w status code ++* <0 driver reported error (timeout|bad arg) ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_cmd_disable(hfa384x_t *hw, u16 macport) ++{ ++ int result = 0; ++ hfa384x_metacmd_t cmd; ++ ++ DBFENTER; ++ ++ cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DISABLE) | ++ HFA384x_CMD_MACPORT_SET(macport); ++ cmd.parm0 = 0; ++ cmd.parm1 = 0; ++ cmd.parm2 = 0; ++ ++ result = hfa384x_docmd_wait(hw, &cmd); ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_cmd_enable ++* ++* Issues the enable command to enable communications on one of ++* the MACs 'ports'. ++* ++* Arguments: ++* hw device structure ++* macport MAC port number ++* ++* Returns: ++* 0 success ++* >0 f/w reported failure - f/w status code ++* <0 driver reported error (timeout|bad arg) ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_cmd_enable(hfa384x_t *hw, u16 macport) ++{ ++ int result = 0; ++ hfa384x_metacmd_t cmd; ++ ++ DBFENTER; ++ ++ cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | ++ HFA384x_CMD_MACPORT_SET(macport); ++ cmd.parm0 = 0; ++ cmd.parm1 = 0; ++ cmd.parm2 = 0; ++ ++ result = hfa384x_docmd_wait(hw, &cmd); ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_cmd_monitor ++* ++* Enables the 'monitor mode' of the MAC. Here's the description of ++* monitor mode that I've received thus far: ++* ++* "The "monitor mode" of operation is that the MAC passes all ++* frames for which the PLCP checks are correct. All received ++* MPDUs are passed to the host with MAC Port = 7, with a ++* receive status of good, FCS error, or undecryptable. Passing ++* certain MPDUs is a violation of the 802.11 standard, but useful ++* for a debugging tool." Normal communication is not possible ++* while monitor mode is enabled. ++* ++* Arguments: ++* hw device structure ++* enable a code (0x0b|0x0f) that enables/disables ++* monitor mode. (host order) ++* ++* Returns: ++* 0 success ++* >0 f/w reported failure - f/w status code ++* <0 driver reported error (timeout|bad arg) ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_cmd_monitor(hfa384x_t *hw, u16 enable) ++{ ++ int result = 0; ++ hfa384x_metacmd_t cmd; ++ ++ DBFENTER; ++ ++ cmd.cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_MONITOR) | ++ HFA384x_CMD_AINFO_SET(enable); ++ cmd.parm0 = 0; ++ cmd.parm1 = 0; ++ cmd.parm2 = 0; ++ ++ result = hfa384x_docmd_wait(hw, &cmd); ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_cmd_download ++* ++* Sets the controls for the MAC controller code/data download ++* process. The arguments set the mode and address associated ++* with a download. Note that the aux registers should be enabled ++* prior to setting one of the download enable modes. ++* ++* Arguments: ++* hw device structure ++* mode 0 - Disable programming and begin code exec ++* 1 - Enable volatile mem programming ++* 2 - Enable non-volatile mem programming ++* 3 - Program non-volatile section from NV download ++* buffer. ++* (host order) ++* lowaddr ++* highaddr For mode 1, sets the high & low order bits of ++* the "destination address". This address will be ++* the execution start address when download is ++* subsequently disabled. ++* For mode 2, sets the high & low order bits of ++* the destination in NV ram. ++* For modes 0 & 3, should be zero. (host order) ++* NOTE: these are CMD format. ++* codelen Length of the data to write in mode 2, ++* zero otherwise. (host order) ++* ++* Returns: ++* 0 success ++* >0 f/w reported failure - f/w status code ++* <0 driver reported error (timeout|bad arg) ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_cmd_download(hfa384x_t *hw, u16 mode, u16 lowaddr, ++ u16 highaddr, u16 codelen) ++{ ++ int result = 0; ++ hfa384x_metacmd_t cmd; ++ ++ DBFENTER; ++ WLAN_LOG_DEBUG(5, ++ "mode=%d, lowaddr=0x%04x, highaddr=0x%04x, codelen=%d\n", ++ mode, lowaddr, highaddr, codelen); ++ ++ cmd.cmd = (HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_DOWNLD) | ++ HFA384x_CMD_PROGMODE_SET(mode)); ++ ++ cmd.parm0 = lowaddr; ++ cmd.parm1 = highaddr; ++ cmd.parm2 = codelen; ++ ++ result = hfa384x_docmd_wait(hw, &cmd); ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_copy_from_aux ++* ++* Copies a collection of bytes from the controller memory. The ++* Auxiliary port MUST be enabled prior to calling this function. ++* We _might_ be in a download state. ++* ++* Arguments: ++* hw device structure ++* cardaddr address in hfa384x data space to read ++* auxctl address space select ++* buf ptr to destination host buffer ++* len length of data to transfer (in bytes) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* buf contains the data copied ++* ++* Call context: ++* process ++* interrupt ++----------------------------------------------------------------*/ ++void ++hfa384x_copy_from_aux( ++ hfa384x_t *hw, u32 cardaddr, u32 auxctl, void *buf, unsigned int len) ++{ ++ DBFENTER; ++ WLAN_LOG_ERROR("not used in USB.\n"); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_copy_to_aux ++* ++* Copies a collection of bytes to the controller memory. The ++* Auxiliary port MUST be enabled prior to calling this function. ++* We _might_ be in a download state. ++* ++* Arguments: ++* hw device structure ++* cardaddr address in hfa384x data space to read ++* auxctl address space select ++* buf ptr to destination host buffer ++* len length of data to transfer (in bytes) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* Controller memory now contains a copy of buf ++* ++* Call context: ++* process ++* interrupt ++----------------------------------------------------------------*/ ++void ++hfa384x_copy_to_aux( ++ hfa384x_t *hw, u32 cardaddr, u32 auxctl, void *buf, unsigned int len) ++{ ++ DBFENTER; ++ WLAN_LOG_ERROR("not used in USB.\n"); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_corereset ++* ++* Perform a reset of the hfa38xx MAC core. We assume that the hw ++* structure is in its "created" state. That is, it is initialized ++* with proper values. Note that if a reset is done after the ++* device has been active for awhile, the caller might have to clean ++* up some leftover cruft in the hw structure. ++* ++* Arguments: ++* hw device structure ++* holdtime how long (in ms) to hold the reset ++* settletime how long (in ms) to wait after releasing ++* the reset ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) ++{ ++ int result = 0; ++ ++ DBFENTER; ++ ++ result=usb_reset_device(hw->usb); ++ if(result<0) { ++ WLAN_LOG_ERROR("usb_reset_device() failed, result=%d.\n",result); ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlx_complete_sync ++* ++* Waits for a synchronous CTLX object to complete, ++* and then handles the response. ++* ++* Arguments: ++* hw device structure ++* ctlx CTLX ptr ++* completor functor object to decide what to ++* do with the CTLX's result. ++* ++* Returns: ++* 0 Success ++* -ERESTARTSYS Interrupted by a signal ++* -EIO CTLX failed ++* -ENODEV Adapter was unplugged ++* ??? Result from completor ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++static int hfa384x_usbctlx_complete_sync(hfa384x_t *hw, ++ hfa384x_usbctlx_t *ctlx, ++ usbctlx_completor_t *completor) ++{ ++ unsigned long flags; ++ int result; ++ ++ DBFENTER; ++ ++ result = wait_for_completion_interruptible(&ctlx->done); ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* ++ * We can only handle the CTLX if the USB disconnect ++ * function has not run yet ... ++ */ ++ cleanup: ++ if ( hw->wlandev->hwremoved ) ++ { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ result = -ENODEV; ++ } ++ else if ( result != 0 ) ++ { ++ int runqueue = 0; ++ ++ /* ++ * We were probably interrupted, so delete ++ * this CTLX asynchronously, kill the timers ++ * and the URB, and then start the next ++ * pending CTLX. ++ * ++ * NOTE: We can only delete the timers and ++ * the URB if this CTLX is active. ++ */ ++ if (ctlx == get_active_ctlx(hw)) ++ { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ del_singleshot_timer_sync(&hw->reqtimer); ++ del_singleshot_timer_sync(&hw->resptimer); ++ hw->req_timer_done = 1; ++ hw->resp_timer_done = 1; ++ usb_kill_urb(&hw->ctlx_urb); ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ runqueue = 1; ++ ++ /* ++ * This scenario is so unlikely that I'm ++ * happy with a grubby "goto" solution ... ++ */ ++ if ( hw->wlandev->hwremoved ) ++ goto cleanup; ++ } ++ ++ /* ++ * The completion task will send this CTLX ++ * to the reaper the next time it runs. We ++ * are no longer in a hurry. ++ */ ++ ctlx->reapable = 1; ++ ctlx->state = CTLX_REQ_FAILED; ++ list_move_tail(&ctlx->list, &hw->ctlxq.completing); ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ if (runqueue) ++ hfa384x_usbctlxq_run(hw); ++ } else { ++ if (ctlx->state == CTLX_COMPLETE) { ++ result = completor->complete(completor); ++ } else { ++ WLAN_LOG_WARNING("CTLX[%d] error: state(%s)\n", ++ hfa384x2host_16(ctlx->outbuf.type), ++ ctlxstr(ctlx->state)); ++ result = -EIO; ++ } ++ ++ list_del(&ctlx->list); ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ kfree(ctlx); ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_docmd ++* ++* Constructs a command CTLX and submits it. ++* ++* NOTE: Any changes to the 'post-submit' code in this function ++* need to be carried over to hfa384x_cbcmd() since the handling ++* is virtually identical. ++* ++* Arguments: ++* hw device structure ++* mode DOWAIT or DOASYNC ++* cmd cmd structure. Includes all arguments and result ++* data points. All in host order. in host order ++* cmdcb command-specific callback ++* usercb user callback for async calls, NULL for DOWAIT calls ++* usercb_data user supplied data pointer for async calls, NULL ++* for DOASYNC calls ++* ++* Returns: ++* 0 success ++* -EIO CTLX failure ++* -ERESTARTSYS Awakened on signal ++* >0 command indicated error, Status and Resp0-2 are ++* in hw structure. ++* ++* Side effects: ++* ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++static int ++hfa384x_docmd( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ hfa384x_metacmd_t *cmd, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ int result; ++ hfa384x_usbctlx_t *ctlx; ++ ++ DBFENTER; ++ ctlx = usbctlx_alloc(); ++ if ( ctlx == NULL ) { ++ result = -ENOMEM; ++ goto done; ++ } ++ ++ /* Initialize the command */ ++ ctlx->outbuf.cmdreq.type = host2hfa384x_16(HFA384x_USB_CMDREQ); ++ ctlx->outbuf.cmdreq.cmd = host2hfa384x_16(cmd->cmd); ++ ctlx->outbuf.cmdreq.parm0 = host2hfa384x_16(cmd->parm0); ++ ctlx->outbuf.cmdreq.parm1 = host2hfa384x_16(cmd->parm1); ++ ctlx->outbuf.cmdreq.parm2 = host2hfa384x_16(cmd->parm2); ++ ++ ctlx->outbufsize = sizeof(ctlx->outbuf.cmdreq); ++ ++ WLAN_LOG_DEBUG(4, "cmdreq: cmd=0x%04x " ++ "parm0=0x%04x parm1=0x%04x parm2=0x%04x\n", ++ cmd->cmd, ++ cmd->parm0, ++ cmd->parm1, ++ cmd->parm2); ++ ++ ctlx->reapable = mode; ++ ctlx->cmdcb = cmdcb; ++ ctlx->usercb = usercb; ++ ctlx->usercb_data = usercb_data; ++ ++ result = hfa384x_usbctlx_submit(hw, ctlx); ++ if (result != 0) { ++ kfree(ctlx); ++ } else if (mode == DOWAIT) { ++ usbctlx_cmd_completor_t completor; ++ ++ result = hfa384x_usbctlx_complete_sync( ++ hw, ctlx, init_cmd_completor(&completor, ++ &ctlx->inbuf.cmdresp, ++ &cmd->result) ); ++ } ++ ++done: ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_dorrid ++* ++* Constructs a read rid CTLX and issues it. ++* ++* NOTE: Any changes to the 'post-submit' code in this function ++* need to be carried over to hfa384x_cbrrid() since the handling ++* is virtually identical. ++* ++* Arguments: ++* hw device structure ++* mode DOWAIT or DOASYNC ++* rid Read RID number (host order) ++* riddata Caller supplied buffer that MAC formatted RID.data ++* record will be written to for DOWAIT calls. Should ++* be NULL for DOASYNC calls. ++* riddatalen Buffer length for DOWAIT calls. Zero for DOASYNC calls. ++* cmdcb command callback for async calls, NULL for DOWAIT calls ++* usercb user callback for async calls, NULL for DOWAIT calls ++* usercb_data user supplied data pointer for async calls, NULL ++* for DOWAIT calls ++* ++* Returns: ++* 0 success ++* -EIO CTLX failure ++* -ERESTARTSYS Awakened on signal ++* -ENODATA riddatalen != macdatalen ++* >0 command indicated error, Status and Resp0-2 are ++* in hw structure. ++* ++* Side effects: ++* ++* Call context: ++* interrupt (DOASYNC) ++* process (DOWAIT or DOASYNC) ++----------------------------------------------------------------*/ ++static int ++hfa384x_dorrid( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 rid, ++ void *riddata, ++ unsigned int riddatalen, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ int result; ++ hfa384x_usbctlx_t *ctlx; ++ ++ DBFENTER; ++ ctlx = usbctlx_alloc(); ++ if ( ctlx == NULL ) { ++ result = -ENOMEM; ++ goto done; ++ } ++ ++ /* Initialize the command */ ++ ctlx->outbuf.rridreq.type = host2hfa384x_16(HFA384x_USB_RRIDREQ); ++ ctlx->outbuf.rridreq.frmlen = ++ host2hfa384x_16(sizeof(ctlx->outbuf.rridreq.rid)); ++ ctlx->outbuf.rridreq.rid = host2hfa384x_16(rid); ++ ++ ctlx->outbufsize = sizeof(ctlx->outbuf.rridreq); ++ ++ ctlx->reapable = mode; ++ ctlx->cmdcb = cmdcb; ++ ctlx->usercb = usercb; ++ ctlx->usercb_data = usercb_data; ++ ++ /* Submit the CTLX */ ++ result = hfa384x_usbctlx_submit(hw, ctlx); ++ if (result != 0) { ++ kfree(ctlx); ++ } else if (mode == DOWAIT) { ++ usbctlx_rrid_completor_t completor; ++ ++ result = hfa384x_usbctlx_complete_sync( ++ hw, ctlx, init_rrid_completor(&completor, ++ &ctlx->inbuf.rridresp, ++ riddata, ++ riddatalen) ); ++ } ++ ++done: ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_dowrid ++* ++* Constructs a write rid CTLX and issues it. ++* ++* NOTE: Any changes to the 'post-submit' code in this function ++* need to be carried over to hfa384x_cbwrid() since the handling ++* is virtually identical. ++* ++* Arguments: ++* hw device structure ++* CMD_MODE DOWAIT or DOASYNC ++* rid RID code ++* riddata Data portion of RID formatted for MAC ++* riddatalen Length of the data portion in bytes ++* cmdcb command callback for async calls, NULL for DOWAIT calls ++* usercb user callback for async calls, NULL for DOWAIT calls ++* usercb_data user supplied data pointer for async calls ++* ++* Returns: ++* 0 success ++* -ETIMEDOUT timed out waiting for register ready or ++* command completion ++* >0 command indicated error, Status and Resp0-2 are ++* in hw structure. ++* ++* Side effects: ++* ++* Call context: ++* interrupt (DOASYNC) ++* process (DOWAIT or DOASYNC) ++----------------------------------------------------------------*/ ++static int ++hfa384x_dowrid( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 rid, ++ void *riddata, ++ unsigned int riddatalen, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ int result; ++ hfa384x_usbctlx_t *ctlx; ++ ++ DBFENTER; ++ ctlx = usbctlx_alloc(); ++ if ( ctlx == NULL ) { ++ result = -ENOMEM; ++ goto done; ++ } ++ ++ /* Initialize the command */ ++ ctlx->outbuf.wridreq.type = host2hfa384x_16(HFA384x_USB_WRIDREQ); ++ ctlx->outbuf.wridreq.frmlen = host2hfa384x_16( ++ (sizeof(ctlx->outbuf.wridreq.rid) + ++ riddatalen + 1) / 2); ++ ctlx->outbuf.wridreq.rid = host2hfa384x_16(rid); ++ memcpy(ctlx->outbuf.wridreq.data, riddata, riddatalen); ++ ++ ctlx->outbufsize = sizeof(ctlx->outbuf.wridreq.type) + ++ sizeof(ctlx->outbuf.wridreq.frmlen) + ++ sizeof(ctlx->outbuf.wridreq.rid) + ++ riddatalen; ++ ++ ctlx->reapable = mode; ++ ctlx->cmdcb = cmdcb; ++ ctlx->usercb = usercb; ++ ctlx->usercb_data = usercb_data; ++ ++ /* Submit the CTLX */ ++ result = hfa384x_usbctlx_submit(hw, ctlx); ++ if (result != 0) { ++ kfree(ctlx); ++ } else if (mode == DOWAIT) { ++ usbctlx_wrid_completor_t completor; ++ hfa384x_cmdresult_t wridresult; ++ ++ result = hfa384x_usbctlx_complete_sync( ++ hw, ++ ctlx, ++ init_wrid_completor(&completor, ++ &ctlx->inbuf.wridresp, ++ &wridresult) ); ++ } ++ ++done: ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_dormem ++* ++* Constructs a readmem CTLX and issues it. ++* ++* NOTE: Any changes to the 'post-submit' code in this function ++* need to be carried over to hfa384x_cbrmem() since the handling ++* is virtually identical. ++* ++* Arguments: ++* hw device structure ++* mode DOWAIT or DOASYNC ++* page MAC address space page (CMD format) ++* offset MAC address space offset ++* data Ptr to data buffer to receive read ++* len Length of the data to read (max == 2048) ++* cmdcb command callback for async calls, NULL for DOWAIT calls ++* usercb user callback for async calls, NULL for DOWAIT calls ++* usercb_data user supplied data pointer for async calls ++* ++* Returns: ++* 0 success ++* -ETIMEDOUT timed out waiting for register ready or ++* command completion ++* >0 command indicated error, Status and Resp0-2 are ++* in hw structure. ++* ++* Side effects: ++* ++* Call context: ++* interrupt (DOASYNC) ++* process (DOWAIT or DOASYNC) ++----------------------------------------------------------------*/ ++static int ++hfa384x_dormem( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 page, ++ u16 offset, ++ void *data, ++ unsigned int len, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ int result; ++ hfa384x_usbctlx_t *ctlx; ++ ++ DBFENTER; ++ ctlx = usbctlx_alloc(); ++ if ( ctlx == NULL ) { ++ result = -ENOMEM; ++ goto done; ++ } ++ ++ /* Initialize the command */ ++ ctlx->outbuf.rmemreq.type = host2hfa384x_16(HFA384x_USB_RMEMREQ); ++ ctlx->outbuf.rmemreq.frmlen = host2hfa384x_16( ++ sizeof(ctlx->outbuf.rmemreq.offset) + ++ sizeof(ctlx->outbuf.rmemreq.page) + ++ len); ++ ctlx->outbuf.rmemreq.offset = host2hfa384x_16(offset); ++ ctlx->outbuf.rmemreq.page = host2hfa384x_16(page); ++ ++ ctlx->outbufsize = sizeof(ctlx->outbuf.rmemreq); ++ ++ WLAN_LOG_DEBUG(4, ++ "type=0x%04x frmlen=%d offset=0x%04x page=0x%04x\n", ++ ctlx->outbuf.rmemreq.type, ++ ctlx->outbuf.rmemreq.frmlen, ++ ctlx->outbuf.rmemreq.offset, ++ ctlx->outbuf.rmemreq.page); ++ ++ WLAN_LOG_DEBUG(4,"pktsize=%zd\n", ++ ROUNDUP64(sizeof(ctlx->outbuf.rmemreq))); ++ ++ ctlx->reapable = mode; ++ ctlx->cmdcb = cmdcb; ++ ctlx->usercb = usercb; ++ ctlx->usercb_data = usercb_data; ++ ++ result = hfa384x_usbctlx_submit(hw, ctlx); ++ if (result != 0) { ++ kfree(ctlx); ++ } else if ( mode == DOWAIT ) { ++ usbctlx_rmem_completor_t completor; ++ ++ result = hfa384x_usbctlx_complete_sync( ++ hw, ctlx, init_rmem_completor(&completor, ++ &ctlx->inbuf.rmemresp, ++ data, ++ len) ); ++ } ++ ++done: ++ DBFEXIT; ++ return result; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_dowmem ++* ++* Constructs a writemem CTLX and issues it. ++* ++* NOTE: Any changes to the 'post-submit' code in this function ++* need to be carried over to hfa384x_cbwmem() since the handling ++* is virtually identical. ++* ++* Arguments: ++* hw device structure ++* mode DOWAIT or DOASYNC ++* page MAC address space page (CMD format) ++* offset MAC address space offset ++* data Ptr to data buffer containing write data ++* len Length of the data to read (max == 2048) ++* cmdcb command callback for async calls, NULL for DOWAIT calls ++* usercb user callback for async calls, NULL for DOWAIT calls ++* usercb_data user supplied data pointer for async calls. ++* ++* Returns: ++* 0 success ++* -ETIMEDOUT timed out waiting for register ready or ++* command completion ++* >0 command indicated error, Status and Resp0-2 are ++* in hw structure. ++* ++* Side effects: ++* ++* Call context: ++* interrupt (DOWAIT) ++* process (DOWAIT or DOASYNC) ++----------------------------------------------------------------*/ ++static int ++hfa384x_dowmem( ++ hfa384x_t *hw, ++ CMD_MODE mode, ++ u16 page, ++ u16 offset, ++ void *data, ++ unsigned int len, ++ ctlx_cmdcb_t cmdcb, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ int result; ++ hfa384x_usbctlx_t *ctlx; ++ ++ DBFENTER; ++ WLAN_LOG_DEBUG(5, "page=0x%04x offset=0x%04x len=%d\n", ++ page,offset,len); ++ ++ ctlx = usbctlx_alloc(); ++ if ( ctlx == NULL ) { ++ result = -ENOMEM; ++ goto done; ++ } ++ ++ /* Initialize the command */ ++ ctlx->outbuf.wmemreq.type = host2hfa384x_16(HFA384x_USB_WMEMREQ); ++ ctlx->outbuf.wmemreq.frmlen = host2hfa384x_16( ++ sizeof(ctlx->outbuf.wmemreq.offset) + ++ sizeof(ctlx->outbuf.wmemreq.page) + ++ len); ++ ctlx->outbuf.wmemreq.offset = host2hfa384x_16(offset); ++ ctlx->outbuf.wmemreq.page = host2hfa384x_16(page); ++ memcpy(ctlx->outbuf.wmemreq.data, data, len); ++ ++ ctlx->outbufsize = sizeof(ctlx->outbuf.wmemreq.type) + ++ sizeof(ctlx->outbuf.wmemreq.frmlen) + ++ sizeof(ctlx->outbuf.wmemreq.offset) + ++ sizeof(ctlx->outbuf.wmemreq.page) + ++ len; ++ ++ ctlx->reapable = mode; ++ ctlx->cmdcb = cmdcb; ++ ctlx->usercb = usercb; ++ ctlx->usercb_data = usercb_data; ++ ++ result = hfa384x_usbctlx_submit(hw, ctlx); ++ if (result != 0) { ++ kfree(ctlx); ++ } else if ( mode == DOWAIT ) { ++ usbctlx_wmem_completor_t completor; ++ hfa384x_cmdresult_t wmemresult; ++ ++ result = hfa384x_usbctlx_complete_sync( ++ hw, ++ ctlx, ++ init_wmem_completor(&completor, ++ &ctlx->inbuf.wmemresp, ++ &wmemresult) ); ++ } ++ ++done: ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_commtallies ++* ++* Send a commtallies inquiry to the MAC. Note that this is an async ++* call that will result in an info frame arriving sometime later. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* zero success. ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_commtallies( hfa384x_t *hw ) ++{ ++ hfa384x_metacmd_t cmd; ++ ++ DBFENTER; ++ ++ cmd.cmd = HFA384x_CMDCODE_INQ; ++ cmd.parm0 = HFA384x_IT_COMMTALLIES; ++ cmd.parm1 = 0; ++ cmd.parm2 = 0; ++ ++ hfa384x_docmd_async(hw, &cmd, NULL, NULL, NULL); ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_disable ++* ++* Issues the disable command to stop communications on one of ++* the MACs 'ports'. Only macport 0 is valid for stations. ++* APs may also disable macports 1-6. Only ports that have been ++* previously enabled may be disabled. ++* ++* Arguments: ++* hw device structure ++* macport MAC port number (host order) ++* ++* Returns: ++* 0 success ++* >0 f/w reported failure - f/w status code ++* <0 driver reported error (timeout|bad arg) ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_disable(hfa384x_t *hw, u16 macport) ++{ ++ int result = 0; ++ ++ DBFENTER; ++ if ((!hw->isap && macport != 0) || ++ (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || ++ !(hw->port_enabled[macport]) ){ ++ result = -EINVAL; ++ } else { ++ result = hfa384x_cmd_disable(hw, macport); ++ if ( result == 0 ) { ++ hw->port_enabled[macport] = 0; ++ } ++ } ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_enable ++* ++* Issues the enable command to enable communications on one of ++* the MACs 'ports'. Only macport 0 is valid for stations. ++* APs may also enable macports 1-6. Only ports that are currently ++* disabled may be enabled. ++* ++* Arguments: ++* hw device structure ++* macport MAC port number ++* ++* Returns: ++* 0 success ++* >0 f/w reported failure - f/w status code ++* <0 driver reported error (timeout|bad arg) ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_enable(hfa384x_t *hw, u16 macport) ++{ ++ int result = 0; ++ ++ DBFENTER; ++ if ((!hw->isap && macport != 0) || ++ (hw->isap && !(macport <= HFA384x_PORTID_MAX)) || ++ (hw->port_enabled[macport]) ){ ++ result = -EINVAL; ++ } else { ++ result = hfa384x_cmd_enable(hw, macport); ++ if ( result == 0 ) { ++ hw->port_enabled[macport] = 1; ++ } ++ } ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_flashdl_enable ++* ++* Begins the flash download state. Checks to see that we're not ++* already in a download state and that a port isn't enabled. ++* Sets the download state and retrieves the flash download ++* buffer location, buffer size, and timeout length. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_flashdl_enable(hfa384x_t *hw) ++{ ++ int result = 0; ++ int i; ++ ++ DBFENTER; ++ /* Check that a port isn't active */ ++ for ( i = 0; i < HFA384x_PORTID_MAX; i++) { ++ if ( hw->port_enabled[i] ) { ++ WLAN_LOG_DEBUG(1,"called when port enabled.\n"); ++ return -EINVAL; ++ } ++ } ++ ++ /* Check that we're not already in a download state */ ++ if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) { ++ return -EINVAL; ++ } ++ ++ /* Retrieve the buffer loc&size and timeout */ ++ if ( (result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DOWNLOADBUFFER, ++ &(hw->bufinfo), sizeof(hw->bufinfo))) ) { ++ return result; ++ } ++ hw->bufinfo.page = hfa384x2host_16(hw->bufinfo.page); ++ hw->bufinfo.offset = hfa384x2host_16(hw->bufinfo.offset); ++ hw->bufinfo.len = hfa384x2host_16(hw->bufinfo.len); ++ if ( (result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_MAXLOADTIME, ++ &(hw->dltimeout))) ) { ++ return result; ++ } ++ hw->dltimeout = hfa384x2host_16(hw->dltimeout); ++ ++ WLAN_LOG_DEBUG(1,"flashdl_enable\n"); ++ ++ hw->dlstate = HFA384x_DLSTATE_FLASHENABLED; ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_flashdl_disable ++* ++* Ends the flash download state. Note that this will cause the MAC ++* firmware to restart. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_flashdl_disable(hfa384x_t *hw) ++{ ++ DBFENTER; ++ /* Check that we're already in the download state */ ++ if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) { ++ return -EINVAL; ++ } ++ ++ WLAN_LOG_DEBUG(1,"flashdl_enable\n"); ++ ++ /* There isn't much we can do at this point, so I don't */ ++ /* bother w/ the return value */ ++ hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0); ++ hw->dlstate = HFA384x_DLSTATE_DISABLED; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_flashdl_write ++* ++* Performs a FLASH download of a chunk of data. First checks to see ++* that we're in the FLASH download state, then sets the download ++* mode, uses the aux functions to 1) copy the data to the flash ++* buffer, 2) sets the download 'write flash' mode, 3) readback and ++* compare. Lather rinse, repeat as many times an necessary to get ++* all the given data into flash. ++* When all data has been written using this function (possibly ++* repeatedly), call drvr_flashdl_disable() to end the download state ++* and restart the MAC. ++* ++* Arguments: ++* hw device structure ++* daddr Card address to write to. (host order) ++* buf Ptr to data to write. ++* len Length of data (host order). ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int ++hfa384x_drvr_flashdl_write( ++ hfa384x_t *hw, ++ u32 daddr, ++ void *buf, ++ u32 len) ++{ ++ int result = 0; ++ u32 dlbufaddr; ++ int nburns; ++ u32 burnlen; ++ u32 burndaddr; ++ u16 burnlo; ++ u16 burnhi; ++ int nwrites; ++ u8 *writebuf; ++ u16 writepage; ++ u16 writeoffset; ++ u32 writelen; ++ int i; ++ int j; ++ ++ DBFENTER; ++ WLAN_LOG_DEBUG(5,"daddr=0x%08x len=%d\n", daddr, len); ++ ++ /* Check that we're in the flash download state */ ++ if ( hw->dlstate != HFA384x_DLSTATE_FLASHENABLED ) { ++ return -EINVAL; ++ } ++ ++ WLAN_LOG_INFO("Download %d bytes to flash @0x%06x\n", len, daddr); ++ ++ /* Convert to flat address for arithmetic */ ++ /* NOTE: dlbuffer RID stores the address in AUX format */ ++ dlbufaddr = HFA384x_ADDR_AUX_MKFLAT( ++ hw->bufinfo.page, hw->bufinfo.offset); ++ WLAN_LOG_DEBUG(5, ++ "dlbuf.page=0x%04x dlbuf.offset=0x%04x dlbufaddr=0x%08x\n", ++ hw->bufinfo.page, hw->bufinfo.offset, dlbufaddr); ++ ++#if 0 ++WLAN_LOG_WARNING("dlbuf@0x%06lx len=%d to=%d\n", dlbufaddr, hw->bufinfo.len, hw->dltimeout); ++#endif ++ /* Calculations to determine how many fills of the dlbuffer to do ++ * and how many USB wmemreq's to do for each fill. At this point ++ * in time, the dlbuffer size and the wmemreq size are the same. ++ * Therefore, nwrites should always be 1. The extra complexity ++ * here is a hedge against future changes. ++ */ ++ ++ /* Figure out how many times to do the flash programming */ ++ nburns = len / hw->bufinfo.len; ++ nburns += (len % hw->bufinfo.len) ? 1 : 0; ++ ++ /* For each flash program cycle, how many USB wmemreq's are needed? */ ++ nwrites = hw->bufinfo.len / HFA384x_USB_RWMEM_MAXLEN; ++ nwrites += (hw->bufinfo.len % HFA384x_USB_RWMEM_MAXLEN) ? 1 : 0; ++ ++ /* For each burn */ ++ for ( i = 0; i < nburns; i++) { ++ /* Get the dest address and len */ ++ burnlen = (len - (hw->bufinfo.len * i)) > hw->bufinfo.len ? ++ hw->bufinfo.len : ++ (len - (hw->bufinfo.len * i)); ++ burndaddr = daddr + (hw->bufinfo.len * i); ++ burnlo = HFA384x_ADDR_CMD_MKOFF(burndaddr); ++ burnhi = HFA384x_ADDR_CMD_MKPAGE(burndaddr); ++ ++ WLAN_LOG_INFO("Writing %d bytes to flash @0x%06x\n", ++ burnlen, burndaddr); ++ ++ /* Set the download mode */ ++ result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_NV, ++ burnlo, burnhi, burnlen); ++ if ( result ) { ++ WLAN_LOG_ERROR("download(NV,lo=%x,hi=%x,len=%x) " ++ "cmd failed, result=%d. Aborting d/l\n", ++ burnlo, burnhi, burnlen, result); ++ goto exit_proc; ++ } ++ ++ /* copy the data to the flash download buffer */ ++ for ( j=0; j < nwrites; j++) { ++ writebuf = buf + ++ (i*hw->bufinfo.len) + ++ (j*HFA384x_USB_RWMEM_MAXLEN); ++ ++ writepage = HFA384x_ADDR_CMD_MKPAGE( ++ dlbufaddr + ++ (j*HFA384x_USB_RWMEM_MAXLEN)); ++ writeoffset = HFA384x_ADDR_CMD_MKOFF( ++ dlbufaddr + ++ (j*HFA384x_USB_RWMEM_MAXLEN)); ++ ++ writelen = burnlen-(j*HFA384x_USB_RWMEM_MAXLEN); ++ writelen = writelen > HFA384x_USB_RWMEM_MAXLEN ? ++ HFA384x_USB_RWMEM_MAXLEN : ++ writelen; ++ ++ result = hfa384x_dowmem_wait( hw, ++ writepage, ++ writeoffset, ++ writebuf, ++ writelen ); ++#if 0 ++ ++Comment out for debugging, assume the write was successful. ++ if (result) { ++ WLAN_LOG_ERROR( ++ "Write to dl buffer failed, " ++ "result=0x%04x. Aborting.\n", ++ result); ++ goto exit_proc; ++ } ++#endif ++ ++ } ++ ++ /* set the download 'write flash' mode */ ++ result = hfa384x_cmd_download(hw, ++ HFA384x_PROGMODE_NVWRITE, ++ 0,0,0); ++ if ( result ) { ++ WLAN_LOG_ERROR( ++ "download(NVWRITE,lo=%x,hi=%x,len=%x) " ++ "cmd failed, result=%d. Aborting d/l\n", ++ burnlo, burnhi, burnlen, result); ++ goto exit_proc; ++ } ++ ++ /* TODO: We really should do a readback and compare. */ ++ } ++ ++exit_proc: ++ ++ /* Leave the firmware in the 'post-prog' mode. flashdl_disable will */ ++ /* actually disable programming mode. Remember, that will cause the */ ++ /* the firmware to effectively reset itself. */ ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_getconfig ++* ++* Performs the sequence necessary to read a config/info item. ++* ++* Arguments: ++* hw device structure ++* rid config/info record id (host order) ++* buf host side record buffer. Upon return it will ++* contain the body portion of the record (minus the ++* RID and len). ++* len buffer length (in bytes, should match record length) ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* -ENODATA length mismatch between argument and retrieved ++* record. ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) ++{ ++ int result; ++ DBFENTER; ++ ++ result = hfa384x_dorrid_wait(hw, rid, buf, len); ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++ * hfa384x_drvr_getconfig_async ++ * ++ * Performs the sequence necessary to perform an async read of ++ * of a config/info item. ++ * ++ * Arguments: ++ * hw device structure ++ * rid config/info record id (host order) ++ * buf host side record buffer. Upon return it will ++ * contain the body portion of the record (minus the ++ * RID and len). ++ * len buffer length (in bytes, should match record length) ++ * cbfn caller supplied callback, called when the command ++ * is done (successful or not). ++ * cbfndata pointer to some caller supplied data that will be ++ * passed in as an argument to the cbfn. ++ * ++ * Returns: ++ * nothing the cbfn gets a status argument identifying if ++ * any errors occur. ++ * Side effects: ++ * Queues an hfa384x_usbcmd_t for subsequent execution. ++ * ++ * Call context: ++ * Any ++ ----------------------------------------------------------------*/ ++int ++hfa384x_drvr_getconfig_async( ++ hfa384x_t *hw, ++ u16 rid, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_dorrid_async(hw, rid, NULL, 0, ++ hfa384x_cb_rrid, usercb, usercb_data); ++} ++ ++/*---------------------------------------------------------------- ++ * hfa384x_drvr_setconfig_async ++ * ++ * Performs the sequence necessary to write a config/info item. ++ * ++ * Arguments: ++ * hw device structure ++ * rid config/info record id (in host order) ++ * buf host side record buffer ++ * len buffer length (in bytes) ++ * usercb completion callback ++ * usercb_data completion callback argument ++ * ++ * Returns: ++ * 0 success ++ * >0 f/w reported error - f/w status code ++ * <0 driver reported error ++ * ++ * Side effects: ++ * ++ * Call context: ++ * process ++ ----------------------------------------------------------------*/ ++int ++hfa384x_drvr_setconfig_async( ++ hfa384x_t *hw, ++ u16 rid, ++ void *buf, ++ u16 len, ++ ctlx_usercb_t usercb, ++ void *usercb_data) ++{ ++ return hfa384x_dowrid_async(hw, rid, buf, len, ++ hfa384x_cb_status, usercb, usercb_data); ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_handover ++* ++* Sends a handover notification to the MAC. ++* ++* Arguments: ++* hw device structure ++* addr address of station that's left ++* ++* Returns: ++* zero success. ++* -ERESTARTSYS received signal while waiting for semaphore. ++* -EIO failed to write to bap, or failed in cmd. ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_handover( hfa384x_t *hw, u8 *addr) ++{ ++ DBFENTER; ++ WLAN_LOG_ERROR("Not currently supported in USB!\n"); ++ DBFEXIT; ++ return -EIO; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_low_level ++* ++* Write test commands to the card. Some test commands don't make ++* sense without prior set-up. For example, continous TX isn't very ++* useful until you set the channel. That functionality should be ++* ++* Side effects: ++* ++* Call context: ++* process thread ++* -----------------------------------------------------------------*/ ++int hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd) ++{ ++ int result; ++ DBFENTER; ++ ++ /* Do i need a host2hfa... conversion ? */ ++ ++ result = hfa384x_docmd_wait(hw, cmd); ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_ramdl_disable ++* ++* Ends the ram download state. ++* ++* Arguments: ++* hw device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int ++hfa384x_drvr_ramdl_disable(hfa384x_t *hw) ++{ ++ DBFENTER; ++ /* Check that we're already in the download state */ ++ if ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) { ++ return -EINVAL; ++ } ++ ++ WLAN_LOG_DEBUG(3,"ramdl_disable()\n"); ++ ++ /* There isn't much we can do at this point, so I don't */ ++ /* bother w/ the return value */ ++ hfa384x_cmd_download(hw, HFA384x_PROGMODE_DISABLE, 0, 0 , 0); ++ hw->dlstate = HFA384x_DLSTATE_DISABLED; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_ramdl_enable ++* ++* Begins the ram download state. Checks to see that we're not ++* already in a download state and that a port isn't enabled. ++* Sets the download state and calls cmd_download with the ++* ENABLE_VOLATILE subcommand and the exeaddr argument. ++* ++* Arguments: ++* hw device structure ++* exeaddr the card execution address that will be ++* jumped to when ramdl_disable() is called ++* (host order). ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int ++hfa384x_drvr_ramdl_enable(hfa384x_t *hw, u32 exeaddr) ++{ ++ int result = 0; ++ u16 lowaddr; ++ u16 hiaddr; ++ int i; ++ DBFENTER; ++ /* Check that a port isn't active */ ++ for ( i = 0; i < HFA384x_PORTID_MAX; i++) { ++ if ( hw->port_enabled[i] ) { ++ WLAN_LOG_ERROR( ++ "Can't download with a macport enabled.\n"); ++ return -EINVAL; ++ } ++ } ++ ++ /* Check that we're not already in a download state */ ++ if ( hw->dlstate != HFA384x_DLSTATE_DISABLED ) { ++ WLAN_LOG_ERROR( ++ "Download state not disabled.\n"); ++ return -EINVAL; ++ } ++ ++ WLAN_LOG_DEBUG(3,"ramdl_enable, exeaddr=0x%08x\n", exeaddr); ++ ++ /* Call the download(1,addr) function */ ++ lowaddr = HFA384x_ADDR_CMD_MKOFF(exeaddr); ++ hiaddr = HFA384x_ADDR_CMD_MKPAGE(exeaddr); ++ ++ result = hfa384x_cmd_download(hw, HFA384x_PROGMODE_RAM, ++ lowaddr, hiaddr, 0); ++ ++ if ( result == 0) { ++ /* Set the download state */ ++ hw->dlstate = HFA384x_DLSTATE_RAMENABLED; ++ } else { ++ WLAN_LOG_DEBUG(1, ++ "cmd_download(0x%04x, 0x%04x) failed, result=%d.\n", ++ lowaddr, ++ hiaddr, ++ result); ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_ramdl_write ++* ++* Performs a RAM download of a chunk of data. First checks to see ++* that we're in the RAM download state, then uses the [read|write]mem USB ++* commands to 1) copy the data, 2) readback and compare. The download ++* state is unaffected. When all data has been written using ++* this function, call drvr_ramdl_disable() to end the download state ++* and restart the MAC. ++* ++* Arguments: ++* hw device structure ++* daddr Card address to write to. (host order) ++* buf Ptr to data to write. ++* len Length of data (host order). ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int ++hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void* buf, u32 len) ++{ ++ int result = 0; ++ int nwrites; ++ u8 *data = buf; ++ int i; ++ u32 curraddr; ++ u16 currpage; ++ u16 curroffset; ++ u16 currlen; ++ DBFENTER; ++ /* Check that we're in the ram download state */ ++ if ( hw->dlstate != HFA384x_DLSTATE_RAMENABLED ) { ++ return -EINVAL; ++ } ++ ++ WLAN_LOG_INFO("Writing %d bytes to ram @0x%06x\n", len, daddr); ++ ++ /* How many dowmem calls? */ ++ nwrites = len / HFA384x_USB_RWMEM_MAXLEN; ++ nwrites += len % HFA384x_USB_RWMEM_MAXLEN ? 1 : 0; ++ ++ /* Do blocking wmem's */ ++ for(i=0; i < nwrites; i++) { ++ /* make address args */ ++ curraddr = daddr + (i * HFA384x_USB_RWMEM_MAXLEN); ++ currpage = HFA384x_ADDR_CMD_MKPAGE(curraddr); ++ curroffset = HFA384x_ADDR_CMD_MKOFF(curraddr); ++ currlen = len - (i * HFA384x_USB_RWMEM_MAXLEN); ++ if ( currlen > HFA384x_USB_RWMEM_MAXLEN) { ++ currlen = HFA384x_USB_RWMEM_MAXLEN; ++ } ++ ++ /* Do blocking ctlx */ ++ result = hfa384x_dowmem_wait( hw, ++ currpage, ++ curroffset, ++ data + (i*HFA384x_USB_RWMEM_MAXLEN), ++ currlen ); ++ ++ if (result) break; ++ ++ /* TODO: We really should have a readback. */ ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_readpda ++* ++* Performs the sequence to read the PDA space. Note there is no ++* drvr_writepda() function. Writing a PDA is ++* generally implemented by a calling component via calls to ++* cmd_download and writing to the flash download buffer via the ++* aux regs. ++* ++* Arguments: ++* hw device structure ++* buf buffer to store PDA in ++* len buffer length ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* -ETIMEOUT timout waiting for the cmd regs to become ++* available, or waiting for the control reg ++* to indicate the Aux port is enabled. ++* -ENODATA the buffer does NOT contain a valid PDA. ++* Either the card PDA is bad, or the auxdata ++* reads are giving us garbage. ++ ++* ++* Side effects: ++* ++* Call context: ++* process or non-card interrupt. ++----------------------------------------------------------------*/ ++int hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len) ++{ ++ int result = 0; ++ u16 *pda = buf; ++ int pdaok = 0; ++ int morepdrs = 1; ++ int currpdr = 0; /* word offset of the current pdr */ ++ size_t i; ++ u16 pdrlen; /* pdr length in bytes, host order */ ++ u16 pdrcode; /* pdr code, host order */ ++ u16 currpage; ++ u16 curroffset; ++ struct pdaloc { ++ u32 cardaddr; ++ u16 auxctl; ++ } pdaloc[] = ++ { ++ { HFA3842_PDA_BASE, 0}, ++ { HFA3841_PDA_BASE, 0}, ++ { HFA3841_PDA_BOGUS_BASE, 0} ++ }; ++ ++ DBFENTER; ++ ++ /* Read the pda from each known address. */ ++ for ( i = 0; i < ARRAY_SIZE(pdaloc); i++) { ++ /* Make address */ ++ currpage = HFA384x_ADDR_CMD_MKPAGE(pdaloc[i].cardaddr); ++ curroffset = HFA384x_ADDR_CMD_MKOFF(pdaloc[i].cardaddr); ++ ++ result = hfa384x_dormem_wait(hw, ++ currpage, ++ curroffset, ++ buf, ++ len); /* units of bytes */ ++ ++ if (result) { ++ WLAN_LOG_WARNING( ++ "Read from index %zd failed, continuing\n", ++ i ); ++ continue; ++ } ++ ++ /* Test for garbage */ ++ pdaok = 1; /* initially assume good */ ++ morepdrs = 1; ++ while ( pdaok && morepdrs ) { ++ pdrlen = hfa384x2host_16(pda[currpdr]) * 2; ++ pdrcode = hfa384x2host_16(pda[currpdr+1]); ++ /* Test the record length */ ++ if ( pdrlen > HFA384x_PDR_LEN_MAX || pdrlen == 0) { ++ WLAN_LOG_ERROR("pdrlen invalid=%d\n", ++ pdrlen); ++ pdaok = 0; ++ break; ++ } ++ /* Test the code */ ++ if ( !hfa384x_isgood_pdrcode(pdrcode) ) { ++ WLAN_LOG_ERROR("pdrcode invalid=%d\n", ++ pdrcode); ++ pdaok = 0; ++ break; ++ } ++ /* Test for completion */ ++ if ( pdrcode == HFA384x_PDR_END_OF_PDA) { ++ morepdrs = 0; ++ } ++ ++ /* Move to the next pdr (if necessary) */ ++ if ( morepdrs ) { ++ /* note the access to pda[], need words here */ ++ currpdr += hfa384x2host_16(pda[currpdr]) + 1; ++ } ++ } ++ if ( pdaok ) { ++ WLAN_LOG_INFO( ++ "PDA Read from 0x%08x in %s space.\n", ++ pdaloc[i].cardaddr, ++ pdaloc[i].auxctl == 0 ? "EXTDS" : ++ pdaloc[i].auxctl == 1 ? "NV" : ++ pdaloc[i].auxctl == 2 ? "PHY" : ++ pdaloc[i].auxctl == 3 ? "ICSRAM" : ++ ""); ++ break; ++ } ++ } ++ result = pdaok ? 0 : -ENODATA; ++ ++ if ( result ) { ++ WLAN_LOG_DEBUG(3,"Failure: pda is not okay\n"); ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_setconfig ++* ++* Performs the sequence necessary to write a config/info item. ++* ++* Arguments: ++* hw device structure ++* rid config/info record id (in host order) ++* buf host side record buffer ++* len buffer length (in bytes) ++* ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int hfa384x_drvr_setconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) ++{ ++ return hfa384x_dowrid_wait(hw, rid, buf, len); ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_start ++* ++* Issues the MAC initialize command, sets up some data structures, ++* and enables the interrupts. After this function completes, the ++* low-level stuff should be ready for any/all commands. ++* ++* Arguments: ++* hw device structure ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++ ++int hfa384x_drvr_start(hfa384x_t *hw) ++{ ++ int result, result1, result2; ++ u16 status; ++ DBFENTER; ++ ++ might_sleep(); ++ ++ /* Clear endpoint stalls - but only do this if the endpoint ++ * is showing a stall status. Some prism2 cards seem to behave ++ * badly if a clear_halt is called when the endpoint is already ++ * ok ++ */ ++ result = usb_get_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_in, &status); ++ if (result < 0) { ++ WLAN_LOG_ERROR( ++ "Cannot get bulk in endpoint status.\n"); ++ goto done; ++ } ++ if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_in)) { ++ WLAN_LOG_ERROR( ++ "Failed to reset bulk in endpoint.\n"); ++ } ++ ++ result = usb_get_status(hw->usb, USB_RECIP_ENDPOINT, hw->endp_out, &status); ++ if (result < 0) { ++ WLAN_LOG_ERROR( ++ "Cannot get bulk out endpoint status.\n"); ++ goto done; ++ } ++ if ((status == 1) && usb_clear_halt(hw->usb, hw->endp_out)) { ++ WLAN_LOG_ERROR( ++ "Failed to reset bulk out endpoint.\n"); ++ } ++ ++ /* Synchronous unlink, in case we're trying to restart the driver */ ++ usb_kill_urb(&hw->rx_urb); ++ ++ /* Post the IN urb */ ++ result = submit_rx_urb(hw, GFP_KERNEL); ++ if (result != 0) { ++ WLAN_LOG_ERROR( ++ "Fatal, failed to submit RX URB, result=%d\n", ++ result); ++ goto done; ++ } ++ ++ /* Call initialize twice, with a 1 second sleep in between. ++ * This is a nasty work-around since many prism2 cards seem to ++ * need time to settle after an init from cold. The second ++ * call to initialize in theory is not necessary - but we call ++ * it anyway as a double insurance policy: ++ * 1) If the first init should fail, the second may well succeed ++ * and the card can still be used ++ * 2) It helps ensures all is well with the card after the first ++ * init and settle time. ++ */ ++ result1 = hfa384x_cmd_initialize(hw); ++ msleep(1000); ++ result = result2 = hfa384x_cmd_initialize(hw); ++ if (result1 != 0) { ++ if (result2 != 0) { ++ WLAN_LOG_ERROR( ++ "cmd_initialize() failed on two attempts, results %d and %d\n", ++ result1, result2); ++ usb_kill_urb(&hw->rx_urb); ++ goto done; ++ } else { ++ WLAN_LOG_DEBUG(0, "First cmd_initialize() failed (result %d),\n", ++ result1); ++ WLAN_LOG_DEBUG(0, "but second attempt succeeded. All should be ok\n"); ++ } ++ } else if (result2 != 0) { ++ WLAN_LOG_WARNING( ++ "First cmd_initialize() succeeded, but second attempt failed (result=%d)\n", ++ result2); ++ WLAN_LOG_WARNING("Most likely the card will be functional\n"); ++ goto done; ++ } ++ ++ hw->state = HFA384x_STATE_RUNNING; ++ ++done: ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_stop ++* ++* Shuts down the MAC to the point where it is safe to unload the ++* driver. Any subsystem that may be holding a data or function ++* ptr into the driver must be cleared/deinitialized. ++* ++* Arguments: ++* hw device structure ++* Returns: ++* 0 success ++* >0 f/w reported error - f/w status code ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++int ++hfa384x_drvr_stop(hfa384x_t *hw) ++{ ++ int result = 0; ++ int i; ++ DBFENTER; ++ ++ might_sleep(); ++ ++ /* There's no need for spinlocks here. The USB "disconnect" ++ * function sets this "removed" flag and then calls us. ++ */ ++ if ( !hw->wlandev->hwremoved ) { ++ /* Call initialize to leave the MAC in its 'reset' state */ ++ hfa384x_cmd_initialize(hw); ++ ++ /* Cancel the rxurb */ ++ usb_kill_urb(&hw->rx_urb); ++ } ++ ++ hw->link_status = HFA384x_LINK_NOTCONNECTED; ++ hw->state = HFA384x_STATE_INIT; ++ ++ del_timer_sync(&hw->commsqual_timer); ++ ++ /* Clear all the port status */ ++ for ( i = 0; i < HFA384x_NUMPORTS_MAX; i++) { ++ hw->port_enabled[i] = 0; ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_drvr_txframe ++* ++* Takes a frame from prism2sta and queues it for transmission. ++* ++* Arguments: ++* hw device structure ++* skb packet buffer struct. Contains an 802.11 ++* data frame. ++* p80211_hdr points to the 802.11 header for the packet. ++* Returns: ++* 0 Success and more buffs available ++* 1 Success but no more buffs ++* 2 Allocation failure ++* 4 Buffer full or queue busy ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++int hfa384x_drvr_txframe(hfa384x_t *hw, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep) ++ ++{ ++ int usbpktlen = sizeof(hfa384x_tx_frame_t); ++ int result; ++ int ret; ++ char *ptr; ++ ++ DBFENTER; ++ ++ if (hw->tx_urb.status == -EINPROGRESS) { ++ WLAN_LOG_WARNING("TX URB already in use\n"); ++ result = 3; ++ goto exit; ++ } ++ ++ /* Build Tx frame structure */ ++ /* Set up the control field */ ++ memset(&hw->txbuff.txfrm.desc, 0, sizeof(hw->txbuff.txfrm.desc)); ++ ++ /* Setup the usb type field */ ++ hw->txbuff.type = host2hfa384x_16(HFA384x_USB_TXFRM); ++ ++ /* Set up the sw_support field to identify this frame */ ++ hw->txbuff.txfrm.desc.sw_support = 0x0123; ++ ++/* Tx complete and Tx exception disable per dleach. Might be causing ++ * buf depletion ++ */ ++//#define DOEXC SLP -- doboth breaks horribly under load, doexc less so. ++#if defined(DOBOTH) ++ hw->txbuff.txfrm.desc.tx_control = ++ HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | ++ HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1); ++#elif defined(DOEXC) ++ hw->txbuff.txfrm.desc.tx_control = ++ HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | ++ HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(0); ++#else ++ hw->txbuff.txfrm.desc.tx_control = ++ HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | ++ HFA384x_TX_TXEX_SET(0) | HFA384x_TX_TXOK_SET(0); ++#endif ++ hw->txbuff.txfrm.desc.tx_control = ++ host2hfa384x_16(hw->txbuff.txfrm.desc.tx_control); ++ ++ /* copy the header over to the txdesc */ ++ memcpy(&(hw->txbuff.txfrm.desc.frame_control), p80211_hdr, sizeof(p80211_hdr_t)); ++ ++ /* if we're using host WEP, increase size by IV+ICV */ ++ if (p80211_wep->data) { ++ hw->txbuff.txfrm.desc.data_len = host2hfa384x_16(skb->len+8); ++ // hw->txbuff.txfrm.desc.tx_control |= HFA384x_TX_NOENCRYPT_SET(1); ++ usbpktlen+=8; ++ } else { ++ hw->txbuff.txfrm.desc.data_len = host2hfa384x_16(skb->len); ++ } ++ ++ usbpktlen += skb->len; ++ ++ /* copy over the WEP IV if we are using host WEP */ ++ ptr = hw->txbuff.txfrm.data; ++ if (p80211_wep->data) { ++ memcpy(ptr, p80211_wep->iv, sizeof(p80211_wep->iv)); ++ ptr+= sizeof(p80211_wep->iv); ++ memcpy(ptr, p80211_wep->data, skb->len); ++ } else { ++ memcpy(ptr, skb->data, skb->len); ++ } ++ /* copy over the packet data */ ++ ptr+= skb->len; ++ ++ /* copy over the WEP ICV if we are using host WEP */ ++ if (p80211_wep->data) { ++ memcpy(ptr, p80211_wep->icv, sizeof(p80211_wep->icv)); ++ } ++ ++ /* Send the USB packet */ ++ usb_fill_bulk_urb( &(hw->tx_urb), hw->usb, ++ hw->endp_out, ++ &(hw->txbuff), ROUNDUP64(usbpktlen), ++ hfa384x_usbout_callback, hw->wlandev ); ++ hw->tx_urb.transfer_flags |= USB_QUEUE_BULK; ++ ++ result = 1; ++ ret = submit_tx_urb(hw, &hw->tx_urb, GFP_ATOMIC); ++ if ( ret != 0 ) { ++ WLAN_LOG_ERROR( ++ "submit_tx_urb() failed, error=%d\n", ret); ++ result = 3; ++ } ++ ++ exit: ++ DBFEXIT; ++ return result; ++} ++ ++void hfa384x_tx_timeout(wlandevice_t *wlandev) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ unsigned long flags; ++ ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ if ( !hw->wlandev->hwremoved && ++ /* Note the bitwise OR, not the logical OR. */ ++ ( !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) | ++ !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) ) ++ { ++ schedule_work(&hw->usb_work); ++ } ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlx_reaper_task ++* ++* Tasklet to delete dead CTLX objects ++* ++* Arguments: ++* data ptr to a hfa384x_t ++* ++* Returns: ++* ++* Call context: ++* Interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbctlx_reaper_task(unsigned long data) ++{ ++ hfa384x_t *hw = (hfa384x_t*)data; ++ struct list_head *entry; ++ struct list_head *temp; ++ unsigned long flags; ++ ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* This list is guaranteed to be empty if someone ++ * has unplugged the adapter. ++ */ ++ list_for_each_safe(entry, temp, &hw->ctlxq.reapable) { ++ hfa384x_usbctlx_t *ctlx; ++ ++ ctlx = list_entry(entry, hfa384x_usbctlx_t, list); ++ list_del(&ctlx->list); ++ kfree(ctlx); ++ } ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlx_completion_task ++* ++* Tasklet to call completion handlers for returned CTLXs ++* ++* Arguments: ++* data ptr to hfa384x_t ++* ++* Returns: ++* Nothing ++* ++* Call context: ++* Interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbctlx_completion_task(unsigned long data) ++{ ++ hfa384x_t *hw = (hfa384x_t*)data; ++ struct list_head *entry; ++ struct list_head *temp; ++ unsigned long flags; ++ ++ int reap = 0; ++ ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* This list is guaranteed to be empty if someone ++ * has unplugged the adapter ... ++ */ ++ list_for_each_safe(entry, temp, &hw->ctlxq.completing) { ++ hfa384x_usbctlx_t *ctlx; ++ ++ ctlx = list_entry(entry, hfa384x_usbctlx_t, list); ++ ++ /* Call the completion function that this ++ * command was assigned, assuming it has one. ++ */ ++ if ( ctlx->cmdcb != NULL ) { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ctlx->cmdcb(hw, ctlx); ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* Make sure we don't try and complete ++ * this CTLX more than once! ++ */ ++ ctlx->cmdcb = NULL; ++ ++ /* Did someone yank the adapter out ++ * while our list was (briefly) unlocked? ++ */ ++ if ( hw->wlandev->hwremoved ) ++ { ++ reap = 0; ++ break; ++ } ++ } ++ ++ /* ++ * "Reapable" CTLXs are ones which don't have any ++ * threads waiting for them to die. Hence they must ++ * be delivered to The Reaper! ++ */ ++ if ( ctlx->reapable ) { ++ /* Move the CTLX off the "completing" list (hopefully) ++ * on to the "reapable" list where the reaper task ++ * can find it. And "reapable" means that this CTLX ++ * isn't sitting on a wait-queue somewhere. ++ */ ++ list_move_tail(&ctlx->list, &hw->ctlxq.reapable); ++ reap = 1; ++ } ++ ++ complete(&ctlx->done); ++ } ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ if (reap) ++ tasklet_schedule(&hw->reaper_bh); ++ ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* unlocked_usbctlx_cancel_async ++* ++* Mark the CTLX dead asynchronously, and ensure that the ++* next command on the queue is run afterwards. ++* ++* Arguments: ++* hw ptr to the hfa384x_t structure ++* ctlx ptr to a CTLX structure ++* ++* Returns: ++* 0 the CTLX's URB is inactive ++* -EINPROGRESS the URB is currently being unlinked ++* ++* Call context: ++* Either process or interrupt, but presumably interrupt ++----------------------------------------------------------------*/ ++static int unlocked_usbctlx_cancel_async(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) ++{ ++ int ret; ++ ++ DBFENTER; ++ ++ /* ++ * Try to delete the URB containing our request packet. ++ * If we succeed, then its completion handler will be ++ * called with a status of -ECONNRESET. ++ */ ++ hw->ctlx_urb.transfer_flags |= URB_ASYNC_UNLINK; ++ ret = usb_unlink_urb(&hw->ctlx_urb); ++ ++ if (ret != -EINPROGRESS) { ++ /* ++ * The OUT URB had either already completed ++ * or was still in the pending queue, so the ++ * URB's completion function will not be called. ++ * We will have to complete the CTLX ourselves. ++ */ ++ ctlx->state = CTLX_REQ_FAILED; ++ unlocked_usbctlx_complete(hw, ctlx); ++ ret = 0; ++ } ++ ++ DBFEXIT; ++ ++ return ret; ++} ++ ++/*---------------------------------------------------------------- ++* unlocked_usbctlx_complete ++* ++* A CTLX has completed. It may have been successful, it may not ++* have been. At this point, the CTLX should be quiescent. The URBs ++* aren't active and the timers should have been stopped. ++* ++* The CTLX is migrated to the "completing" queue, and the completing ++* tasklet is scheduled. ++* ++* Arguments: ++* hw ptr to a hfa384x_t structure ++* ctlx ptr to a ctlx structure ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* Either, assume interrupt ++----------------------------------------------------------------*/ ++static void unlocked_usbctlx_complete(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) ++{ ++ DBFENTER; ++ ++ /* Timers have been stopped, and ctlx should be in ++ * a terminal state. Retire it from the "active" ++ * queue. ++ */ ++ list_move_tail(&ctlx->list, &hw->ctlxq.completing); ++ tasklet_schedule(&hw->completion_bh); ++ ++ switch (ctlx->state) { ++ case CTLX_COMPLETE: ++ case CTLX_REQ_FAILED: ++ /* This are the correct terminating states. */ ++ break; ++ ++ default: ++ WLAN_LOG_ERROR("CTLX[%d] not in a terminating state(%s)\n", ++ hfa384x2host_16(ctlx->outbuf.type), ++ ctlxstr(ctlx->state)); ++ break; ++ } /* switch */ ++ ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlxq_run ++* ++* Checks to see if the head item is running. If not, starts it. ++* ++* Arguments: ++* hw ptr to hfa384x_t ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* any ++----------------------------------------------------------------*/ ++static void ++hfa384x_usbctlxq_run(hfa384x_t *hw) ++{ ++ unsigned long flags; ++ DBFENTER; ++ ++ /* acquire lock */ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* Only one active CTLX at any one time, because there's no ++ * other (reliable) way to match the response URB to the ++ * correct CTLX. ++ * ++ * Don't touch any of these CTLXs if the hardware ++ * has been removed or the USB subsystem is stalled. ++ */ ++ if ( !list_empty(&hw->ctlxq.active) || ++ test_bit(WORK_TX_HALT, &hw->usb_flags) || ++ hw->wlandev->hwremoved ) ++ goto unlock; ++ ++ while ( !list_empty(&hw->ctlxq.pending) ) { ++ hfa384x_usbctlx_t *head; ++ int result; ++ ++ /* This is the first pending command */ ++ head = list_entry(hw->ctlxq.pending.next, ++ hfa384x_usbctlx_t, ++ list); ++ ++ /* We need to split this off to avoid a race condition */ ++ list_move_tail(&head->list, &hw->ctlxq.active); ++ ++ /* Fill the out packet */ ++ usb_fill_bulk_urb( &(hw->ctlx_urb), hw->usb, ++ hw->endp_out, ++ &(head->outbuf), ROUNDUP64(head->outbufsize), ++ hfa384x_ctlxout_callback, hw); ++ hw->ctlx_urb.transfer_flags |= USB_QUEUE_BULK; ++ ++ /* Now submit the URB and update the CTLX's state ++ */ ++ if ((result = SUBMIT_URB(&hw->ctlx_urb, GFP_ATOMIC)) == 0) { ++ /* This CTLX is now running on the active queue */ ++ head->state = CTLX_REQ_SUBMITTED; ++ ++ /* Start the OUT wait timer */ ++ hw->req_timer_done = 0; ++ hw->reqtimer.expires = jiffies + HZ; ++ add_timer(&hw->reqtimer); ++ ++ /* Start the IN wait timer */ ++ hw->resp_timer_done = 0; ++ hw->resptimer.expires = jiffies + 2*HZ; ++ add_timer(&hw->resptimer); ++ ++ break; ++ } ++ ++ if (result == -EPIPE) { ++ /* The OUT pipe needs resetting, so put ++ * this CTLX back in the "pending" queue ++ * and schedule a reset ... ++ */ ++ WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", ++ hw->wlandev->netdev->name); ++ list_move(&head->list, &hw->ctlxq.pending); ++ set_bit(WORK_TX_HALT, &hw->usb_flags); ++ schedule_work(&hw->usb_work); ++ break; ++ } ++ ++ if (result == -ESHUTDOWN) { ++ WLAN_LOG_WARNING("%s urb shutdown!\n", ++ hw->wlandev->netdev->name); ++ break; ++ } ++ ++ WLAN_LOG_ERROR("Failed to submit CTLX[%d]: error=%d\n", ++ hfa384x2host_16(head->outbuf.type), result); ++ unlocked_usbctlx_complete(hw, head); ++ } /* while */ ++ ++ unlock: ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbin_callback ++* ++* Callback for URBs on the BULKIN endpoint. ++* ++* Arguments: ++* urb ptr to the completed urb ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbin_callback(struct urb *urb) ++{ ++ wlandevice_t *wlandev = urb->context; ++ hfa384x_t *hw; ++ hfa384x_usbin_t *usbin = (hfa384x_usbin_t *) urb->transfer_buffer; ++ struct sk_buff *skb = NULL; ++ int result; ++ int urb_status; ++ u16 type; ++ ++ enum USBIN_ACTION { ++ HANDLE, ++ RESUBMIT, ++ ABORT ++ } action; ++ ++ DBFENTER; ++ ++ if ( !wlandev || ++ !wlandev->netdev || ++ wlandev->hwremoved ) ++ goto exit; ++ ++ hw = wlandev->priv; ++ if (!hw) ++ goto exit; ++ ++ skb = hw->rx_urb_skb; ++ if (!skb || (skb->data != urb->transfer_buffer)) { ++ BUG(); ++ } ++ hw->rx_urb_skb = NULL; ++ ++ /* Check for error conditions within the URB */ ++ switch (urb->status) { ++ case 0: ++ action = HANDLE; ++ ++ /* Check for short packet */ ++ if ( urb->actual_length == 0 ) { ++ ++(wlandev->linux_stats.rx_errors); ++ ++(wlandev->linux_stats.rx_length_errors); ++ action = RESUBMIT; ++ } ++ break; ++ ++ case -EPIPE: ++ WLAN_LOG_WARNING("%s rx pipe stalled: requesting reset\n", ++ wlandev->netdev->name); ++ if ( !test_and_set_bit(WORK_RX_HALT, &hw->usb_flags) ) ++ schedule_work(&hw->usb_work); ++ ++(wlandev->linux_stats.rx_errors); ++ action = ABORT; ++ break; ++ ++ case -EILSEQ: ++ case -ETIMEDOUT: ++ case -EPROTO: ++ if ( !test_and_set_bit(THROTTLE_RX, &hw->usb_flags) && ++ !timer_pending(&hw->throttle) ) { ++ mod_timer(&hw->throttle, jiffies + THROTTLE_JIFFIES); ++ } ++ ++(wlandev->linux_stats.rx_errors); ++ action = ABORT; ++ break; ++ ++ case -EOVERFLOW: ++ ++(wlandev->linux_stats.rx_over_errors); ++ action = RESUBMIT; ++ break; ++ ++ case -ENODEV: ++ case -ESHUTDOWN: ++ WLAN_LOG_DEBUG(3,"status=%d, device removed.\n", urb->status); ++ action = ABORT; ++ break; ++ ++ case -ENOENT: ++ case -ECONNRESET: ++ WLAN_LOG_DEBUG(3,"status=%d, urb explicitly unlinked.\n", urb->status); ++ action = ABORT; ++ break; ++ ++ default: ++ WLAN_LOG_DEBUG(3,"urb status=%d, transfer flags=0x%x\n", ++ urb->status, urb->transfer_flags); ++ ++(wlandev->linux_stats.rx_errors); ++ action = RESUBMIT; ++ break; ++ } ++ ++ urb_status = urb->status; ++ ++ if (action != ABORT) { ++ /* Repost the RX URB */ ++ result = submit_rx_urb(hw, GFP_ATOMIC); ++ ++ if (result != 0) { ++ WLAN_LOG_ERROR( ++ "Fatal, failed to resubmit rx_urb. error=%d\n", ++ result); ++ } ++ } ++ ++ /* Handle any USB-IN packet */ ++ /* Note: the check of the sw_support field, the type field doesn't ++ * have bit 12 set like the docs suggest. ++ */ ++ type = hfa384x2host_16(usbin->type); ++ if (HFA384x_USB_ISRXFRM(type)) { ++ if (action == HANDLE) { ++ if (usbin->txfrm.desc.sw_support == 0x0123) { ++ hfa384x_usbin_txcompl(wlandev, usbin); ++ } else { ++ skb_put(skb, sizeof(*usbin)); ++ hfa384x_usbin_rx(wlandev, skb); ++ skb = NULL; ++ } ++ } ++ goto exit; ++ } ++ if (HFA384x_USB_ISTXFRM(type)) { ++ if (action == HANDLE) ++ hfa384x_usbin_txcompl(wlandev, usbin); ++ goto exit; ++ } ++ switch (type) { ++ case HFA384x_USB_INFOFRM: ++ if (action == ABORT) ++ goto exit; ++ if (action == HANDLE) ++ hfa384x_usbin_info(wlandev, usbin); ++ break; ++ ++ case HFA384x_USB_CMDRESP: ++ case HFA384x_USB_WRIDRESP: ++ case HFA384x_USB_RRIDRESP: ++ case HFA384x_USB_WMEMRESP: ++ case HFA384x_USB_RMEMRESP: ++ /* ALWAYS, ALWAYS, ALWAYS handle this CTLX!!!! */ ++ hfa384x_usbin_ctlx(hw, usbin, urb_status); ++ break; ++ ++ case HFA384x_USB_BUFAVAIL: ++ WLAN_LOG_DEBUG(3,"Received BUFAVAIL packet, frmlen=%d\n", ++ usbin->bufavail.frmlen); ++ break; ++ ++ case HFA384x_USB_ERROR: ++ WLAN_LOG_DEBUG(3,"Received USB_ERROR packet, errortype=%d\n", ++ usbin->usberror.errortype); ++ break; ++ ++ default: ++ WLAN_LOG_DEBUG(3,"Unrecognized USBIN packet, type=%x, status=%d\n", ++ usbin->type, urb_status); ++ break; ++ } /* switch */ ++ ++exit: ++ ++ if (skb) ++ dev_kfree_skb(skb); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbin_ctlx ++* ++* We've received a URB containing a Prism2 "response" message. ++* This message needs to be matched up with a CTLX on the active ++* queue and our state updated accordingly. ++* ++* Arguments: ++* hw ptr to hfa384x_t ++* usbin ptr to USB IN packet ++* urb_status status of this Bulk-In URB ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbin_ctlx(hfa384x_t *hw, hfa384x_usbin_t *usbin, ++ int urb_status) ++{ ++ hfa384x_usbctlx_t *ctlx; ++ int run_queue = 0; ++ unsigned long flags; ++ ++ DBFENTER; ++ ++retry: ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* There can be only one CTLX on the active queue ++ * at any one time, and this is the CTLX that the ++ * timers are waiting for. ++ */ ++ if ( list_empty(&hw->ctlxq.active) ) { ++ goto unlock; ++ } ++ ++ /* Remove the "response timeout". It's possible that ++ * we are already too late, and that the timeout is ++ * already running. And that's just too bad for us, ++ * because we could lose our CTLX from the active ++ * queue here ... ++ */ ++ if (del_timer(&hw->resptimer) == 0) { ++ if (hw->resp_timer_done == 0) { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ goto retry; ++ } ++ } ++ else { ++ hw->resp_timer_done = 1; ++ } ++ ++ ctlx = get_active_ctlx(hw); ++ ++ if (urb_status != 0) { ++ /* ++ * Bad CTLX, so get rid of it. But we only ++ * remove it from the active queue if we're no ++ * longer expecting the OUT URB to complete. ++ */ ++ if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) ++ run_queue = 1; ++ } else { ++ const u16 intype = (usbin->type&~host2hfa384x_16(0x8000)); ++ ++ /* ++ * Check that our message is what we're expecting ... ++ */ ++ if (ctlx->outbuf.type != intype) { ++ WLAN_LOG_WARNING("Expected IN[%d], received IN[%d] - ignored.\n", ++ hfa384x2host_16(ctlx->outbuf.type), ++ hfa384x2host_16(intype)); ++ goto unlock; ++ } ++ ++ /* This URB has succeeded, so grab the data ... */ ++ memcpy(&ctlx->inbuf, usbin, sizeof(ctlx->inbuf)); ++ ++ switch (ctlx->state) { ++ case CTLX_REQ_SUBMITTED: ++ /* ++ * We have received our response URB before ++ * our request has been acknowledged. Odd, ++ * but our OUT URB is still alive... ++ */ ++ WLAN_LOG_DEBUG(0, "Causality violation: please reboot Universe, or email linux-wlan-devel@lists.linux-wlan.com\n"); ++ ctlx->state = CTLX_RESP_COMPLETE; ++ break; ++ ++ case CTLX_REQ_COMPLETE: ++ /* ++ * This is the usual path: our request ++ * has already been acknowledged, and ++ * now we have received the reply too. ++ */ ++ ctlx->state = CTLX_COMPLETE; ++ unlocked_usbctlx_complete(hw, ctlx); ++ run_queue = 1; ++ break; ++ ++ default: ++ /* ++ * Throw this CTLX away ... ++ */ ++ WLAN_LOG_ERROR("Matched IN URB, CTLX[%d] in invalid state(%s)." ++ " Discarded.\n", ++ hfa384x2host_16(ctlx->outbuf.type), ++ ctlxstr(ctlx->state)); ++ if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) ++ run_queue = 1; ++ break; ++ } /* switch */ ++ } ++ ++unlock: ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ if (run_queue) ++ hfa384x_usbctlxq_run(hw); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbin_txcompl ++* ++* At this point we have the results of a previous transmit. ++* ++* Arguments: ++* wlandev wlan device ++* usbin ptr to the usb transfer buffer ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbin_txcompl(wlandevice_t *wlandev, hfa384x_usbin_t *usbin) ++{ ++ u16 status; ++ DBFENTER; ++ ++ status = hfa384x2host_16(usbin->type); /* yeah I know it says type...*/ ++ ++ /* Was there an error? */ ++ if (HFA384x_TXSTATUS_ISERROR(status)) { ++ prism2sta_ev_txexc(wlandev, status); ++ } else { ++ prism2sta_ev_tx(wlandev, status); ++ } ++ // prism2sta_ev_alloc(wlandev); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbin_rx ++* ++* At this point we have a successful received a rx frame packet. ++* ++* Arguments: ++* wlandev wlan device ++* usbin ptr to the usb transfer buffer ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbin_rx(wlandevice_t *wlandev, struct sk_buff *skb) ++{ ++ hfa384x_usbin_t *usbin = (hfa384x_usbin_t *) skb->data; ++ hfa384x_t *hw = wlandev->priv; ++ int hdrlen; ++ p80211_rxmeta_t *rxmeta; ++ u16 data_len; ++ u16 fc; ++ ++ DBFENTER; ++ ++ /* Byte order convert once up front. */ ++ usbin->rxfrm.desc.status = ++ hfa384x2host_16(usbin->rxfrm.desc.status); ++ usbin->rxfrm.desc.time = ++ hfa384x2host_32(usbin->rxfrm.desc.time); ++ ++ /* Now handle frame based on port# */ ++ switch( HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status) ) ++ { ++ case 0: ++ fc = ieee2host16(usbin->rxfrm.desc.frame_control); ++ ++ /* If exclude and we receive an unencrypted, drop it */ ++ if ( (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) && ++ !WLAN_GET_FC_ISWEP(fc)){ ++ goto done; ++ } ++ ++ data_len = hfa384x2host_16(usbin->rxfrm.desc.data_len); ++ ++ /* How much header data do we have? */ ++ hdrlen = p80211_headerlen(fc); ++ ++ /* Pull off the descriptor */ ++ skb_pull(skb, sizeof(hfa384x_rx_frame_t)); ++ ++ /* Now shunt the header block up against the data block ++ * with an "overlapping" copy ++ */ ++ memmove(skb_push(skb, hdrlen), ++ &usbin->rxfrm.desc.frame_control, ++ hdrlen); ++ ++ skb->dev = wlandev->netdev; ++ skb->dev->last_rx = jiffies; ++ ++ /* And set the frame length properly */ ++ skb_trim(skb, data_len + hdrlen); ++ ++ /* The prism2 series does not return the CRC */ ++ memset(skb_put(skb, WLAN_CRC_LEN), 0xff, WLAN_CRC_LEN); ++ ++ skb_reset_mac_header(skb); ++ ++ /* Attach the rxmeta, set some stuff */ ++ p80211skb_rxmeta_attach(wlandev, skb); ++ rxmeta = P80211SKB_RXMETA(skb); ++ rxmeta->mactime = usbin->rxfrm.desc.time; ++ rxmeta->rxrate = usbin->rxfrm.desc.rate; ++ rxmeta->signal = usbin->rxfrm.desc.signal - hw->dbmadjust; ++ rxmeta->noise = usbin->rxfrm.desc.silence - hw->dbmadjust; ++ ++ prism2sta_ev_rx(wlandev, skb); ++ ++ break; ++ ++ case 7: ++ if ( ! HFA384x_RXSTATUS_ISFCSERR(usbin->rxfrm.desc.status) ) { ++ /* Copy to wlansnif skb */ ++ hfa384x_int_rxmonitor( wlandev, &usbin->rxfrm); ++ dev_kfree_skb(skb); ++ } else { ++ WLAN_LOG_DEBUG(3,"Received monitor frame: FCSerr set\n"); ++ } ++ break; ++ ++ default: ++ WLAN_LOG_WARNING("Received frame on unsupported port=%d\n", ++ HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status) ); ++ goto done; ++ break; ++ } ++ ++done: ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_int_rxmonitor ++* ++* Helper function for int_rx. Handles monitor frames. ++* Note that this function allocates space for the FCS and sets it ++* to 0xffffffff. The hfa384x doesn't give us the FCS value but the ++* higher layers expect it. 0xffffffff is used as a flag to indicate ++* the FCS is bogus. ++* ++* Arguments: ++* wlandev wlan device structure ++* rxfrm rx descriptor read from card in int_rx ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* Allocates an skb and passes it up via the PF_PACKET interface. ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_int_rxmonitor( wlandevice_t *wlandev, hfa384x_usb_rxfrm_t *rxfrm) ++{ ++ hfa384x_rx_frame_t *rxdesc = &(rxfrm->desc); ++ unsigned int hdrlen = 0; ++ unsigned int datalen = 0; ++ unsigned int skblen = 0; ++ u8 *datap; ++ u16 fc; ++ struct sk_buff *skb; ++ hfa384x_t *hw = wlandev->priv; ++ ++ ++ DBFENTER; ++ /* Don't forget the status, time, and data_len fields are in host order */ ++ /* Figure out how big the frame is */ ++ fc = ieee2host16(rxdesc->frame_control); ++ hdrlen = p80211_headerlen(fc); ++ datalen = hfa384x2host_16(rxdesc->data_len); ++ ++ /* Allocate an ind message+framesize skb */ ++ skblen = sizeof(p80211_caphdr_t) + ++ hdrlen + datalen + WLAN_CRC_LEN; ++ ++ /* sanity check the length */ ++ if ( skblen > ++ (sizeof(p80211_caphdr_t) + ++ WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) { ++ WLAN_LOG_DEBUG(1, "overlen frm: len=%zd\n", ++ skblen - sizeof(p80211_caphdr_t)); ++ } ++ ++ if ( (skb = dev_alloc_skb(skblen)) == NULL ) { ++ WLAN_LOG_ERROR("alloc_skb failed trying to allocate %d bytes\n", skblen); ++ return; ++ } ++ ++ /* only prepend the prism header if in the right mode */ ++ if ((wlandev->netdev->type == ARPHRD_IEEE80211_PRISM) && ++ (hw->sniffhdr != 0)) { ++ p80211_caphdr_t *caphdr; ++ /* The NEW header format! */ ++ datap = skb_put(skb, sizeof(p80211_caphdr_t)); ++ caphdr = (p80211_caphdr_t*) datap; ++ ++ caphdr->version = htonl(P80211CAPTURE_VERSION); ++ caphdr->length = htonl(sizeof(p80211_caphdr_t)); ++ caphdr->mactime = __cpu_to_be64(rxdesc->time) * 1000; ++ caphdr->hosttime = __cpu_to_be64(jiffies); ++ caphdr->phytype = htonl(4); /* dss_dot11_b */ ++ caphdr->channel = htonl(hw->sniff_channel); ++ caphdr->datarate = htonl(rxdesc->rate); ++ caphdr->antenna = htonl(0); /* unknown */ ++ caphdr->priority = htonl(0); /* unknown */ ++ caphdr->ssi_type = htonl(3); /* rssi_raw */ ++ caphdr->ssi_signal = htonl(rxdesc->signal); ++ caphdr->ssi_noise = htonl(rxdesc->silence); ++ caphdr->preamble = htonl(0); /* unknown */ ++ caphdr->encoding = htonl(1); /* cck */ ++ } ++ ++ /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */ ++ datap = skb_put(skb, hdrlen); ++ memcpy( datap, &(rxdesc->frame_control), hdrlen); ++ ++ /* If any, copy the data from the card to the skb */ ++ if ( datalen > 0 ) ++ { ++ datap = skb_put(skb, datalen); ++ memcpy(datap, rxfrm->data, datalen); ++ ++ /* check for unencrypted stuff if WEP bit set. */ ++ if (*(datap - hdrlen + 1) & 0x40) // wep set ++ if ((*(datap) == 0xaa) && (*(datap+1) == 0xaa)) ++ *(datap - hdrlen + 1) &= 0xbf; // clear wep; it's the 802.2 header! ++ } ++ ++ if (hw->sniff_fcs) { ++ /* Set the FCS */ ++ datap = skb_put(skb, WLAN_CRC_LEN); ++ memset( datap, 0xff, WLAN_CRC_LEN); ++ } ++ ++ /* pass it back up */ ++ prism2sta_ev_rx(wlandev, skb); ++ ++ DBFEXIT; ++ return; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbin_info ++* ++* At this point we have a successful received a Prism2 info frame. ++* ++* Arguments: ++* wlandev wlan device ++* usbin ptr to the usb transfer buffer ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbin_info(wlandevice_t *wlandev, hfa384x_usbin_t *usbin) ++{ ++ DBFENTER; ++ ++ usbin->infofrm.info.framelen = hfa384x2host_16(usbin->infofrm.info.framelen); ++ prism2sta_ev_info(wlandev, &usbin->infofrm.info); ++ ++ DBFEXIT; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbout_callback ++* ++* Callback for URBs on the BULKOUT endpoint. ++* ++* Arguments: ++* urb ptr to the completed urb ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbout_callback(struct urb *urb) ++{ ++ wlandevice_t *wlandev = urb->context; ++ hfa384x_usbout_t *usbout = urb->transfer_buffer; ++ DBFENTER; ++ ++#ifdef DEBUG_USB ++ dbprint_urb(urb); ++#endif ++ ++ if ( wlandev && ++ wlandev->netdev ) { ++ ++ switch(urb->status) { ++ case 0: ++ hfa384x_usbout_tx(wlandev, usbout); ++ break; ++ ++ case -EPIPE: ++ { ++ hfa384x_t *hw = wlandev->priv; ++ WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", ++ wlandev->netdev->name); ++ if ( !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) ) ++ schedule_work(&hw->usb_work); ++ ++(wlandev->linux_stats.tx_errors); ++ break; ++ } ++ ++ case -EPROTO: ++ case -ETIMEDOUT: ++ case -EILSEQ: ++ { ++ hfa384x_t *hw = wlandev->priv; ++ ++ if ( !test_and_set_bit(THROTTLE_TX, &hw->usb_flags) ++ && !timer_pending(&hw->throttle) ) { ++ mod_timer(&hw->throttle, ++ jiffies + THROTTLE_JIFFIES); ++ } ++ ++(wlandev->linux_stats.tx_errors); ++ netif_stop_queue(wlandev->netdev); ++ break; ++ } ++ ++ case -ENOENT: ++ case -ESHUTDOWN: ++ /* Ignorable errors */ ++ break; ++ ++ default: ++ WLAN_LOG_INFO("unknown urb->status=%d\n", urb->status); ++ ++(wlandev->linux_stats.tx_errors); ++ break; ++ } /* switch */ ++ } ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_ctlxout_callback ++* ++* Callback for control data on the BULKOUT endpoint. ++* ++* Arguments: ++* urb ptr to the completed urb ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_ctlxout_callback(struct urb *urb) ++{ ++ hfa384x_t *hw = urb->context; ++ int delete_resptimer = 0; ++ int timer_ok = 1; ++ int run_queue = 0; ++ hfa384x_usbctlx_t *ctlx; ++ unsigned long flags; ++ ++ DBFENTER; ++ ++ WLAN_LOG_DEBUG(3,"urb->status=%d\n", urb->status); ++#ifdef DEBUG_USB ++ dbprint_urb(urb); ++#endif ++ if ( (urb->status == -ESHUTDOWN) || ++ (urb->status == -ENODEV) || ++ (hw == NULL) ) ++ goto done; ++ ++retry: ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* ++ * Only one CTLX at a time on the "active" list, and ++ * none at all if we are unplugged. However, we can ++ * rely on the disconnect function to clean everything ++ * up if someone unplugged the adapter. ++ */ ++ if ( list_empty(&hw->ctlxq.active) ) { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ goto done; ++ } ++ ++ /* ++ * Having something on the "active" queue means ++ * that we have timers to worry about ... ++ */ ++ if (del_timer(&hw->reqtimer) == 0) { ++ if (hw->req_timer_done == 0) { ++ /* ++ * This timer was actually running while we ++ * were trying to delete it. Let it terminate ++ * gracefully instead. ++ */ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ goto retry; ++ } ++ } ++ else { ++ hw->req_timer_done = 1; ++ } ++ ++ ctlx = get_active_ctlx(hw); ++ ++ if ( urb->status == 0 ) { ++ /* Request portion of a CTLX is successful */ ++ switch ( ctlx->state ) { ++ case CTLX_REQ_SUBMITTED: ++ /* This OUT-ACK received before IN */ ++ ctlx->state = CTLX_REQ_COMPLETE; ++ break; ++ ++ case CTLX_RESP_COMPLETE: ++ /* IN already received before this OUT-ACK, ++ * so this command must now be complete. ++ */ ++ ctlx->state = CTLX_COMPLETE; ++ unlocked_usbctlx_complete(hw, ctlx); ++ run_queue = 1; ++ break; ++ ++ default: ++ /* This is NOT a valid CTLX "success" state! */ ++ WLAN_LOG_ERROR( ++ "Illegal CTLX[%d] success state(%s, %d) in OUT URB\n", ++ hfa384x2host_16(ctlx->outbuf.type), ++ ctlxstr(ctlx->state), urb->status); ++ break; ++ } /* switch */ ++ } else { ++ /* If the pipe has stalled then we need to reset it */ ++ if ( (urb->status == -EPIPE) && ++ !test_and_set_bit(WORK_TX_HALT, &hw->usb_flags) ) { ++ WLAN_LOG_WARNING("%s tx pipe stalled: requesting reset\n", ++ hw->wlandev->netdev->name); ++ schedule_work(&hw->usb_work); ++ } ++ ++ /* If someone cancels the OUT URB then its status ++ * should be either -ECONNRESET or -ENOENT. ++ */ ++ ctlx->state = CTLX_REQ_FAILED; ++ unlocked_usbctlx_complete(hw, ctlx); ++ delete_resptimer = 1; ++ run_queue = 1; ++ } ++ ++ delresp: ++ if (delete_resptimer) { ++ if ((timer_ok = del_timer(&hw->resptimer)) != 0) { ++ hw->resp_timer_done = 1; ++ } ++ } ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ if ( !timer_ok && (hw->resp_timer_done == 0) ) { ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ goto delresp; ++ } ++ ++ if (run_queue) ++ hfa384x_usbctlxq_run(hw); ++ ++ done: ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlx_reqtimerfn ++* ++* Timer response function for CTLX request timeouts. If this ++* function is called, it means that the callback for the OUT ++* URB containing a Prism2.x XXX_Request was never called. ++* ++* Arguments: ++* data a ptr to the hfa384x_t ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void ++hfa384x_usbctlx_reqtimerfn(unsigned long data) ++{ ++ hfa384x_t *hw = (hfa384x_t*)data; ++ unsigned long flags; ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ hw->req_timer_done = 1; ++ ++ /* Removing the hardware automatically empties ++ * the active list ... ++ */ ++ if ( !list_empty(&hw->ctlxq.active) ) ++ { ++ /* ++ * We must ensure that our URB is removed from ++ * the system, if it hasn't already expired. ++ */ ++ hw->ctlx_urb.transfer_flags |= URB_ASYNC_UNLINK; ++ if (usb_unlink_urb(&hw->ctlx_urb) == -EINPROGRESS) ++ { ++ hfa384x_usbctlx_t *ctlx = get_active_ctlx(hw); ++ ++ ctlx->state = CTLX_REQ_FAILED; ++ ++ /* This URB was active, but has now been ++ * cancelled. It will now have a status of ++ * -ECONNRESET in the callback function. ++ * ++ * We are cancelling this CTLX, so we're ++ * not going to need to wait for a response. ++ * The URB's callback function will check ++ * that this timer is truly dead. ++ */ ++ if (del_timer(&hw->resptimer) != 0) ++ hw->resp_timer_done = 1; ++ } ++ } ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlx_resptimerfn ++* ++* Timer response function for CTLX response timeouts. If this ++* function is called, it means that the callback for the IN ++* URB containing a Prism2.x XXX_Response was never called. ++* ++* Arguments: ++* data a ptr to the hfa384x_t ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void ++hfa384x_usbctlx_resptimerfn(unsigned long data) ++{ ++ hfa384x_t *hw = (hfa384x_t*)data; ++ unsigned long flags; ++ ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ hw->resp_timer_done = 1; ++ ++ /* The active list will be empty if the ++ * adapter has been unplugged ... ++ */ ++ if ( !list_empty(&hw->ctlxq.active) ) ++ { ++ hfa384x_usbctlx_t *ctlx = get_active_ctlx(hw); ++ ++ if ( unlocked_usbctlx_cancel_async(hw, ctlx) == 0 ) ++ { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ hfa384x_usbctlxq_run(hw); ++ goto done; ++ } ++ } ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ done: ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_usb_throttlefn ++* ++* ++* Arguments: ++* data ptr to hw ++* ++* Returns: ++* Nothing ++* ++* Side effects: ++* ++* Call context: ++* Interrupt ++----------------------------------------------------------------*/ ++static void ++hfa384x_usb_throttlefn(unsigned long data) ++{ ++ hfa384x_t *hw = (hfa384x_t*)data; ++ unsigned long flags; ++ ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ /* ++ * We need to check BOTH the RX and the TX throttle controls, ++ * so we use the bitwise OR instead of the logical OR. ++ */ ++ WLAN_LOG_DEBUG(3, "flags=0x%lx\n", hw->usb_flags); ++ if ( !hw->wlandev->hwremoved && ++ ( ++ (test_and_clear_bit(THROTTLE_RX, &hw->usb_flags) && ++ !test_and_set_bit(WORK_RX_RESUME, &hw->usb_flags)) ++ | ++ (test_and_clear_bit(THROTTLE_TX, &hw->usb_flags) && ++ !test_and_set_bit(WORK_TX_RESUME, &hw->usb_flags)) ++ ) ) ++ { ++ schedule_work(&hw->usb_work); ++ } ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbctlx_submit ++* ++* Called from the doxxx functions to submit a CTLX to the queue ++* ++* Arguments: ++* hw ptr to the hw struct ++* ctlx ctlx structure to enqueue ++* ++* Returns: ++* -ENODEV if the adapter is unplugged ++* 0 ++* ++* Side effects: ++* ++* Call context: ++* process or interrupt ++----------------------------------------------------------------*/ ++static int ++hfa384x_usbctlx_submit( ++ hfa384x_t *hw, ++ hfa384x_usbctlx_t *ctlx) ++{ ++ unsigned long flags; ++ int ret; ++ ++ DBFENTER; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ if (hw->wlandev->hwremoved) { ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ret = -ENODEV; ++ } else { ++ ctlx->state = CTLX_PENDING; ++ list_add_tail(&ctlx->list, &hw->ctlxq.pending); ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ hfa384x_usbctlxq_run(hw); ++ ret = 0; ++ } ++ ++ DBFEXIT; ++ return ret; ++} ++ ++ ++/*---------------------------------------------------------------- ++* hfa384x_usbout_tx ++* ++* At this point we have finished a send of a frame. Mark the URB ++* as available and call ev_alloc to notify higher layers we're ++* ready for more. ++* ++* Arguments: ++* wlandev wlan device ++* usbout ptr to the usb transfer buffer ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void hfa384x_usbout_tx(wlandevice_t *wlandev, hfa384x_usbout_t *usbout) ++{ ++ DBFENTER; ++ ++ prism2sta_ev_alloc(wlandev); ++ ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* hfa384x_isgood_pdrcore ++* ++* Quick check of PDR codes. ++* ++* Arguments: ++* pdrcode PDR code number (host order) ++* ++* Returns: ++* zero not good. ++* one is good. ++* ++* Side effects: ++* ++* Call context: ++----------------------------------------------------------------*/ ++static int ++hfa384x_isgood_pdrcode(u16 pdrcode) ++{ ++ switch(pdrcode) { ++ case HFA384x_PDR_END_OF_PDA: ++ case HFA384x_PDR_PCB_PARTNUM: ++ case HFA384x_PDR_PDAVER: ++ case HFA384x_PDR_NIC_SERIAL: ++ case HFA384x_PDR_MKK_MEASUREMENTS: ++ case HFA384x_PDR_NIC_RAMSIZE: ++ case HFA384x_PDR_MFISUPRANGE: ++ case HFA384x_PDR_CFISUPRANGE: ++ case HFA384x_PDR_NICID: ++ case HFA384x_PDR_MAC_ADDRESS: ++ case HFA384x_PDR_REGDOMAIN: ++ case HFA384x_PDR_ALLOWED_CHANNEL: ++ case HFA384x_PDR_DEFAULT_CHANNEL: ++ case HFA384x_PDR_TEMPTYPE: ++ case HFA384x_PDR_IFR_SETTING: ++ case HFA384x_PDR_RFR_SETTING: ++ case HFA384x_PDR_HFA3861_BASELINE: ++ case HFA384x_PDR_HFA3861_SHADOW: ++ case HFA384x_PDR_HFA3861_IFRF: ++ case HFA384x_PDR_HFA3861_CHCALSP: ++ case HFA384x_PDR_HFA3861_CHCALI: ++ case HFA384x_PDR_3842_NIC_CONFIG: ++ case HFA384x_PDR_USB_ID: ++ case HFA384x_PDR_PCI_ID: ++ case HFA384x_PDR_PCI_IFCONF: ++ case HFA384x_PDR_PCI_PMCONF: ++ case HFA384x_PDR_RFENRGY: ++ case HFA384x_PDR_HFA3861_MANF_TESTSP: ++ case HFA384x_PDR_HFA3861_MANF_TESTI: ++ /* code is OK */ ++ return 1; ++ break; ++ default: ++ if ( pdrcode < 0x1000 ) { ++ /* code is OK, but we don't know exactly what it is */ ++ WLAN_LOG_DEBUG(3, ++ "Encountered unknown PDR#=0x%04x, " ++ "assuming it's ok.\n", ++ pdrcode); ++ return 1; ++ } else { ++ /* bad code */ ++ WLAN_LOG_DEBUG(3, ++ "Encountered unknown PDR#=0x%04x, " ++ "(>=0x1000), assuming it's bad.\n", ++ pdrcode); ++ return 0; ++ } ++ break; ++ } ++ return 0; /* avoid compiler warnings */ ++} ++ +--- /dev/null ++++ b/drivers/staging/wlan-ng/Kconfig +@@ -0,0 +1,10 @@ ++config PRISM2_USB ++ tristate "Prism2.5/3 USB driver" ++ depends on WLAN_80211 && USB && WIRELESS_EXT ++ default n ++ ---help--- ++ This is the wlan-ng prism 2.5/3 USB driver for a wide range of ++ old USB wireless devices. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called prism2_usb. +--- /dev/null ++++ b/drivers/staging/wlan-ng/Makefile +@@ -0,0 +1,8 @@ ++obj-$(CONFIG_PRISM2_USB) += prism2_usb.o ++ ++prism2_usb-objs := prism2usb.o \ ++ p80211conv.o \ ++ p80211req.o \ ++ p80211wep.o \ ++ p80211wext.o \ ++ p80211netdev.o +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211conv.c +@@ -0,0 +1,686 @@ ++/* src/p80211/p80211conv.c ++* ++* Ether/802.11 conversions and packet buffer routines ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file defines the functions that perform Ethernet to/from ++* 802.11 frame conversions. ++* ++* -------------------------------------------------------------------- ++*/ ++/*================================================================*/ ++/* System Includes */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "wlan_compat.h" ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211conv.h" ++#include "p80211mgmt.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211ioctl.h" ++#include "p80211req.h" ++ ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++/*================================================================*/ ++/* Local Macros */ ++ ++ ++/*================================================================*/ ++/* Local Types */ ++ ++ ++/*================================================================*/ ++/* Local Static Definitions */ ++ ++static u8 oui_rfc1042[] = {0x00, 0x00, 0x00}; ++static u8 oui_8021h[] = {0x00, 0x00, 0xf8}; ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++ ++/*================================================================*/ ++/* Function Definitions */ ++ ++/*---------------------------------------------------------------- ++* p80211pb_ether_to_80211 ++* ++* Uses the contents of the ether frame and the etherconv setting ++* to build the elements of the 802.11 frame. ++* ++* We don't actually set ++* up the frame header here. That's the MAC's job. We're only handling ++* conversion of DIXII or 802.3+LLC frames to something that works ++* with 802.11. ++* ++* Note -- 802.11 header is NOT part of the skb. Likewise, the 802.11 ++* FCS is also not present and will need to be added elsewhere. ++* ++* Arguments: ++* ethconv Conversion type to perform ++* skb skbuff containing the ether frame ++* p80211_hdr 802.11 header ++* ++* Returns: ++* 0 on success, non-zero otherwise ++* ++* Call context: ++* May be called in interrupt or non-interrupt context ++----------------------------------------------------------------*/ ++int skb_ether_to_p80211( wlandevice_t *wlandev, u32 ethconv, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep) ++{ ++ ++ u16 fc; ++ u16 proto; ++ wlan_ethhdr_t e_hdr; ++ wlan_llc_t *e_llc; ++ wlan_snap_t *e_snap; ++ int foo; ++ ++ DBFENTER; ++ memcpy(&e_hdr, skb->data, sizeof(e_hdr)); ++ ++ if (skb->len <= 0) { ++ WLAN_LOG_DEBUG(1, "zero-length skb!\n"); ++ return 1; ++ } ++ ++ if ( ethconv == WLAN_ETHCONV_ENCAP ) { /* simplest case */ ++ WLAN_LOG_DEBUG(3, "ENCAP len: %d\n", skb->len); ++ /* here, we don't care what kind of ether frm. Just stick it */ ++ /* in the 80211 payload */ ++ /* which is to say, leave the skb alone. */ ++ } else { ++ /* step 1: classify ether frame, DIX or 802.3? */ ++ proto = ntohs(e_hdr.type); ++ if ( proto <= 1500 ) { ++ WLAN_LOG_DEBUG(3, "802.3 len: %d\n", skb->len); ++ /* codes <= 1500 reserved for 802.3 lengths */ ++ /* it's 802.3, pass ether payload unchanged, */ ++ ++ /* trim off ethernet header */ ++ skb_pull(skb, WLAN_ETHHDR_LEN); ++ ++ /* leave off any PAD octets. */ ++ skb_trim(skb, proto); ++ } else { ++ WLAN_LOG_DEBUG(3, "DIXII len: %d\n", skb->len); ++ /* it's DIXII, time for some conversion */ ++ ++ /* trim off ethernet header */ ++ skb_pull(skb, WLAN_ETHHDR_LEN); ++ ++ /* tack on SNAP */ ++ e_snap = (wlan_snap_t *) skb_push(skb, sizeof(wlan_snap_t)); ++ e_snap->type = htons(proto); ++ if ( ethconv == WLAN_ETHCONV_8021h && p80211_stt_findproto(proto) ) { ++ memcpy( e_snap->oui, oui_8021h, WLAN_IEEE_OUI_LEN); ++ } else { ++ memcpy( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN); ++ } ++ ++ /* tack on llc */ ++ e_llc = (wlan_llc_t *) skb_push(skb, sizeof(wlan_llc_t)); ++ e_llc->dsap = 0xAA; /* SNAP, see IEEE 802 */ ++ e_llc->ssap = 0xAA; ++ e_llc->ctl = 0x03; ++ ++ } ++ } ++ ++ /* Set up the 802.11 header */ ++ /* It's a data frame */ ++ fc = host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) | ++ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY)); ++ ++ switch ( wlandev->macmode ) { ++ case WLAN_MACMODE_IBSS_STA: ++ memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, WLAN_ADDR_LEN); ++ memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, WLAN_ADDR_LEN); ++ memcpy(p80211_hdr->a3.a3, wlandev->bssid, WLAN_ADDR_LEN); ++ break; ++ case WLAN_MACMODE_ESS_STA: ++ fc |= host2ieee16(WLAN_SET_FC_TODS(1)); ++ memcpy(p80211_hdr->a3.a1, wlandev->bssid, WLAN_ADDR_LEN); ++ memcpy(p80211_hdr->a3.a2, wlandev->netdev->dev_addr, WLAN_ADDR_LEN); ++ memcpy(p80211_hdr->a3.a3, &e_hdr.daddr, WLAN_ADDR_LEN); ++ break; ++ case WLAN_MACMODE_ESS_AP: ++ fc |= host2ieee16(WLAN_SET_FC_FROMDS(1)); ++ memcpy(p80211_hdr->a3.a1, &e_hdr.daddr, WLAN_ADDR_LEN); ++ memcpy(p80211_hdr->a3.a2, wlandev->bssid, WLAN_ADDR_LEN); ++ memcpy(p80211_hdr->a3.a3, &e_hdr.saddr, WLAN_ADDR_LEN); ++ break; ++ default: ++ WLAN_LOG_ERROR("Error: Converting eth to wlan in unknown mode.\n"); ++ return 1; ++ break; ++ } ++ ++ p80211_wep->data = NULL; ++ ++ if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && (wlandev->hostwep & HOSTWEP_ENCRYPT)) { ++ // XXXX need to pick keynum other than default? ++ ++#if 1 ++ p80211_wep->data = kmalloc(skb->len, GFP_ATOMIC); ++#else ++ p80211_wep->data = skb->data; ++#endif ++ ++ if ((foo = wep_encrypt(wlandev, skb->data, p80211_wep->data, ++ skb->len, ++ (wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK), ++ p80211_wep->iv, p80211_wep->icv))) { ++ WLAN_LOG_WARNING("Host en-WEP failed, dropping frame (%d).\n", foo); ++ return 2; ++ } ++ fc |= host2ieee16(WLAN_SET_FC_ISWEP(1)); ++ } ++ ++ ++ // skb->nh.raw = skb->data; ++ ++ p80211_hdr->a3.fc = fc; ++ p80211_hdr->a3.dur = 0; ++ p80211_hdr->a3.seq = 0; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++/* jkriegl: from orinoco, modified */ ++static void orinoco_spy_gather(wlandevice_t *wlandev, char *mac, ++ p80211_rxmeta_t *rxmeta) ++{ ++ int i; ++ ++ /* Gather wireless spy statistics: for each packet, compare the ++ * source address with out list, and if match, get the stats... */ ++ ++ for (i = 0; i < wlandev->spy_number; i++) { ++ ++ if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) { ++ memcpy(wlandev->spy_address[i], mac, ETH_ALEN); ++ wlandev->spy_stat[i].level = rxmeta->signal; ++ wlandev->spy_stat[i].noise = rxmeta->noise; ++ wlandev->spy_stat[i].qual = (rxmeta->signal > rxmeta->noise) ? \ ++ (rxmeta->signal - rxmeta->noise) : 0; ++ wlandev->spy_stat[i].updated = 0x7; ++ } ++ } ++} ++ ++/*---------------------------------------------------------------- ++* p80211pb_80211_to_ether ++* ++* Uses the contents of a received 802.11 frame and the etherconv ++* setting to build an ether frame. ++* ++* This function extracts the src and dest address from the 802.11 ++* frame to use in the construction of the eth frame. ++* ++* Arguments: ++* ethconv Conversion type to perform ++* skb Packet buffer containing the 802.11 frame ++* ++* Returns: ++* 0 on success, non-zero otherwise ++* ++* Call context: ++* May be called in interrupt or non-interrupt context ++----------------------------------------------------------------*/ ++int skb_p80211_to_ether( wlandevice_t *wlandev, u32 ethconv, struct sk_buff *skb) ++{ ++ netdevice_t *netdev = wlandev->netdev; ++ u16 fc; ++ unsigned int payload_length; ++ unsigned int payload_offset; ++ u8 daddr[WLAN_ETHADDR_LEN]; ++ u8 saddr[WLAN_ETHADDR_LEN]; ++ p80211_hdr_t *w_hdr; ++ wlan_ethhdr_t *e_hdr; ++ wlan_llc_t *e_llc; ++ wlan_snap_t *e_snap; ++ ++ int foo; ++ ++ DBFENTER; ++ ++ payload_length = skb->len - WLAN_HDR_A3_LEN - WLAN_CRC_LEN; ++ payload_offset = WLAN_HDR_A3_LEN; ++ ++ w_hdr = (p80211_hdr_t *) skb->data; ++ ++ /* setup some vars for convenience */ ++ fc = ieee2host16(w_hdr->a3.fc); ++ if ( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 0) ) { ++ memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); ++ memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); ++ } else if( (WLAN_GET_FC_TODS(fc) == 0) && (WLAN_GET_FC_FROMDS(fc) == 1) ) { ++ memcpy(daddr, w_hdr->a3.a1, WLAN_ETHADDR_LEN); ++ memcpy(saddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); ++ } else if( (WLAN_GET_FC_TODS(fc) == 1) && (WLAN_GET_FC_FROMDS(fc) == 0) ) { ++ memcpy(daddr, w_hdr->a3.a3, WLAN_ETHADDR_LEN); ++ memcpy(saddr, w_hdr->a3.a2, WLAN_ETHADDR_LEN); ++ } else { ++ payload_offset = WLAN_HDR_A4_LEN; ++ if (payload_length < WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN) { ++ WLAN_LOG_ERROR("A4 frame too short!\n"); ++ return 1; ++ } ++ payload_length -= (WLAN_HDR_A4_LEN - WLAN_HDR_A3_LEN); ++ memcpy(daddr, w_hdr->a4.a3, WLAN_ETHADDR_LEN); ++ memcpy(saddr, w_hdr->a4.a4, WLAN_ETHADDR_LEN); ++ } ++ ++ /* perform de-wep if necessary.. */ ++ if ((wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) && WLAN_GET_FC_ISWEP(fc) && (wlandev->hostwep & HOSTWEP_DECRYPT)) { ++ if (payload_length <= 8) { ++ WLAN_LOG_ERROR("WEP frame too short (%u).\n", ++ skb->len); ++ return 1; ++ } ++ if ((foo = wep_decrypt(wlandev, skb->data + payload_offset + 4, ++ payload_length - 8, -1, ++ skb->data + payload_offset, ++ skb->data + payload_offset + payload_length - 4))) { ++ /* de-wep failed, drop skb. */ ++ WLAN_LOG_DEBUG(1, "Host de-WEP failed, dropping frame (%d).\n", foo); ++ wlandev->rx.decrypt_err++; ++ return 2; ++ } ++ ++ /* subtract the IV+ICV length off the payload */ ++ payload_length -= 8; ++ /* chop off the IV */ ++ skb_pull(skb, 4); ++ /* chop off the ICV. */ ++ skb_trim(skb, skb->len - 4); ++ ++ wlandev->rx.decrypt++; ++ } ++ ++ e_hdr = (wlan_ethhdr_t *) (skb->data + payload_offset); ++ ++ e_llc = (wlan_llc_t *) (skb->data + payload_offset); ++ e_snap = (wlan_snap_t *) (skb->data + payload_offset + sizeof(wlan_llc_t)); ++ ++ /* Test for the various encodings */ ++ if ( (payload_length >= sizeof(wlan_ethhdr_t)) && ++ ( e_llc->dsap != 0xaa || e_llc->ssap != 0xaa ) && ++ ((memcmp(daddr, e_hdr->daddr, WLAN_ETHADDR_LEN) == 0) || ++ (memcmp(saddr, e_hdr->saddr, WLAN_ETHADDR_LEN) == 0))) { ++ WLAN_LOG_DEBUG(3, "802.3 ENCAP len: %d\n", payload_length); ++ /* 802.3 Encapsulated */ ++ /* Test for an overlength frame */ ++ if ( payload_length > (netdev->mtu + WLAN_ETHHDR_LEN)) { ++ /* A bogus length ethfrm has been encap'd. */ ++ /* Is someone trying an oflow attack? */ ++ WLAN_LOG_ERROR("ENCAP frame too large (%d > %d)\n", ++ payload_length, netdev->mtu + WLAN_ETHHDR_LEN); ++ return 1; ++ } ++ ++ /* Chop off the 802.11 header. it's already sane. */ ++ skb_pull(skb, payload_offset); ++ /* chop off the 802.11 CRC */ ++ skb_trim(skb, skb->len - WLAN_CRC_LEN); ++ ++ } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) && ++ (e_llc->dsap == 0xaa) && ++ (e_llc->ssap == 0xaa) && ++ (e_llc->ctl == 0x03) && ++ (((memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)==0) && ++ (ethconv == WLAN_ETHCONV_8021h) && ++ (p80211_stt_findproto(ieee2host16(e_snap->type)))) || ++ (memcmp( e_snap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)!=0))) ++ { ++ WLAN_LOG_DEBUG(3, "SNAP+RFC1042 len: %d\n", payload_length); ++ /* it's a SNAP + RFC1042 frame && protocol is in STT */ ++ /* build 802.3 + RFC1042 */ ++ ++ /* Test for an overlength frame */ ++ if ( payload_length > netdev->mtu ) { ++ /* A bogus length ethfrm has been sent. */ ++ /* Is someone trying an oflow attack? */ ++ WLAN_LOG_ERROR("SNAP frame too large (%d > %d)\n", ++ payload_length, netdev->mtu); ++ return 1; ++ } ++ ++ /* chop 802.11 header from skb. */ ++ skb_pull(skb, payload_offset); ++ ++ /* create 802.3 header at beginning of skb. */ ++ e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN); ++ memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); ++ memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); ++ e_hdr->type = htons(payload_length); ++ ++ /* chop off the 802.11 CRC */ ++ skb_trim(skb, skb->len - WLAN_CRC_LEN); ++ ++ } else if ((payload_length >= sizeof(wlan_llc_t) + sizeof(wlan_snap_t)) && ++ (e_llc->dsap == 0xaa) && ++ (e_llc->ssap == 0xaa) && ++ (e_llc->ctl == 0x03) ) { ++ WLAN_LOG_DEBUG(3, "802.1h/RFC1042 len: %d\n", payload_length); ++ /* it's an 802.1h frame || (an RFC1042 && protocol is not in STT) */ ++ /* build a DIXII + RFC894 */ ++ ++ /* Test for an overlength frame */ ++ if ((payload_length - sizeof(wlan_llc_t) - sizeof(wlan_snap_t)) ++ > netdev->mtu) { ++ /* A bogus length ethfrm has been sent. */ ++ /* Is someone trying an oflow attack? */ ++ WLAN_LOG_ERROR("DIXII frame too large (%ld > %d)\n", ++ (long int) (payload_length - sizeof(wlan_llc_t) - ++ sizeof(wlan_snap_t)), ++ netdev->mtu); ++ return 1; ++ } ++ ++ /* chop 802.11 header from skb. */ ++ skb_pull(skb, payload_offset); ++ ++ /* chop llc header from skb. */ ++ skb_pull(skb, sizeof(wlan_llc_t)); ++ ++ /* chop snap header from skb. */ ++ skb_pull(skb, sizeof(wlan_snap_t)); ++ ++ /* create 802.3 header at beginning of skb. */ ++ e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN); ++ e_hdr->type = e_snap->type; ++ memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); ++ memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); ++ ++ /* chop off the 802.11 CRC */ ++ skb_trim(skb, skb->len - WLAN_CRC_LEN); ++ } else { ++ WLAN_LOG_DEBUG(3, "NON-ENCAP len: %d\n", payload_length); ++ /* any NON-ENCAP */ ++ /* it's a generic 80211+LLC or IPX 'Raw 802.3' */ ++ /* build an 802.3 frame */ ++ /* allocate space and setup hostbuf */ ++ ++ /* Test for an overlength frame */ ++ if ( payload_length > netdev->mtu ) { ++ /* A bogus length ethfrm has been sent. */ ++ /* Is someone trying an oflow attack? */ ++ WLAN_LOG_ERROR("OTHER frame too large (%d > %d)\n", ++ payload_length, ++ netdev->mtu); ++ return 1; ++ } ++ ++ /* Chop off the 802.11 header. */ ++ skb_pull(skb, payload_offset); ++ ++ /* create 802.3 header at beginning of skb. */ ++ e_hdr = (wlan_ethhdr_t *) skb_push(skb, WLAN_ETHHDR_LEN); ++ memcpy(e_hdr->daddr, daddr, WLAN_ETHADDR_LEN); ++ memcpy(e_hdr->saddr, saddr, WLAN_ETHADDR_LEN); ++ e_hdr->type = htons(payload_length); ++ ++ /* chop off the 802.11 CRC */ ++ skb_trim(skb, skb->len - WLAN_CRC_LEN); ++ ++ } ++ ++ /* ++ * Note that eth_type_trans() expects an skb w/ skb->data pointing ++ * at the MAC header, it then sets the following skb members: ++ * skb->mac_header, ++ * skb->data, and ++ * skb->pkt_type. ++ * It then _returns_ the value that _we're_ supposed to stuff in ++ * skb->protocol. This is nuts. ++ */ ++ skb->protocol = eth_type_trans(skb, netdev); ++ ++ /* jkriegl: process signal and noise as set in hfa384x_int_rx() */ ++ /* jkriegl: only process signal/noise if requested by iwspy */ ++ if (wlandev->spy_number) ++ orinoco_spy_gather(wlandev, eth_hdr(skb)->h_source, P80211SKB_RXMETA(skb)); ++ ++ /* Free the metadata */ ++ p80211skb_rxmeta_detach(skb); ++ ++ DBFEXIT; ++ return 0; ++} ++ ++/*---------------------------------------------------------------- ++* p80211_stt_findproto ++* ++* Searches the 802.1h Selective Translation Table for a given ++* protocol. ++* ++* Arguments: ++* proto protocl number (in host order) to search for. ++* ++* Returns: ++* 1 - if the table is empty or a match is found. ++* 0 - if the table is non-empty and a match is not found. ++* ++* Call context: ++* May be called in interrupt or non-interrupt context ++----------------------------------------------------------------*/ ++int p80211_stt_findproto(u16 proto) ++{ ++ /* Always return found for now. This is the behavior used by the */ ++ /* Zoom Win95 driver when 802.1h mode is selected */ ++ /* TODO: If necessary, add an actual search we'll probably ++ need this to match the CMAC's way of doing things. ++ Need to do some testing to confirm. ++ */ ++ ++ if (proto == 0x80f3) /* APPLETALK */ ++ return 1; ++ ++ return 0; ++} ++ ++/*---------------------------------------------------------------- ++* p80211skb_rxmeta_detach ++* ++* Disconnects the frmmeta and rxmeta from an skb. ++* ++* Arguments: ++* wlandev The wlandev this skb belongs to. ++* skb The skb we're attaching to. ++* ++* Returns: ++* 0 on success, non-zero otherwise ++* ++* Call context: ++* May be called in interrupt or non-interrupt context ++----------------------------------------------------------------*/ ++void ++p80211skb_rxmeta_detach(struct sk_buff *skb) ++{ ++ p80211_rxmeta_t *rxmeta; ++ p80211_frmmeta_t *frmmeta; ++ ++ DBFENTER; ++ /* Sanity checks */ ++ if ( skb==NULL ) { /* bad skb */ ++ WLAN_LOG_DEBUG(1, "Called w/ null skb.\n"); ++ goto exit; ++ } ++ frmmeta = P80211SKB_FRMMETA(skb); ++ if ( frmmeta == NULL ) { /* no magic */ ++ WLAN_LOG_DEBUG(1, "Called w/ bad frmmeta magic.\n"); ++ goto exit; ++ } ++ rxmeta = frmmeta->rx; ++ if ( rxmeta == NULL ) { /* bad meta ptr */ ++ WLAN_LOG_DEBUG(1, "Called w/ bad rxmeta ptr.\n"); ++ goto exit; ++ } ++ ++ /* Free rxmeta */ ++ kfree(rxmeta); ++ ++ /* Clear skb->cb */ ++ memset(skb->cb, 0, sizeof(skb->cb)); ++exit: ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* p80211skb_rxmeta_attach ++* ++* Allocates a p80211rxmeta structure, initializes it, and attaches ++* it to an skb. ++* ++* Arguments: ++* wlandev The wlandev this skb belongs to. ++* skb The skb we're attaching to. ++* ++* Returns: ++* 0 on success, non-zero otherwise ++* ++* Call context: ++* May be called in interrupt or non-interrupt context ++----------------------------------------------------------------*/ ++int ++p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb) ++{ ++ int result = 0; ++ p80211_rxmeta_t *rxmeta; ++ p80211_frmmeta_t *frmmeta; ++ ++ DBFENTER; ++ ++ /* If these already have metadata, we error out! */ ++ if (P80211SKB_RXMETA(skb) != NULL) { ++ WLAN_LOG_ERROR("%s: RXmeta already attached!\n", ++ wlandev->name); ++ result = 0; ++ goto exit; ++ } ++ ++ /* Allocate the rxmeta */ ++ rxmeta = kmalloc(sizeof(p80211_rxmeta_t), GFP_ATOMIC); ++ ++ if ( rxmeta == NULL ) { ++ WLAN_LOG_ERROR("%s: Failed to allocate rxmeta.\n", ++ wlandev->name); ++ result = 1; ++ goto exit; ++ } ++ ++ /* Initialize the rxmeta */ ++ memset(rxmeta, 0, sizeof(p80211_rxmeta_t)); ++ rxmeta->wlandev = wlandev; ++ rxmeta->hosttime = jiffies; ++ ++ /* Overlay a frmmeta_t onto skb->cb */ ++ memset(skb->cb, 0, sizeof(p80211_frmmeta_t)); ++ frmmeta = (p80211_frmmeta_t*)(skb->cb); ++ frmmeta->magic = P80211_FRMMETA_MAGIC; ++ frmmeta->rx = rxmeta; ++exit: ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* p80211skb_free ++* ++* Frees an entire p80211skb by checking and freeing the meta struct ++* and then freeing the skb. ++* ++* Arguments: ++* wlandev The wlandev this skb belongs to. ++* skb The skb we're attaching to. ++* ++* Returns: ++* 0 on success, non-zero otherwise ++* ++* Call context: ++* May be called in interrupt or non-interrupt context ++----------------------------------------------------------------*/ ++void ++p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb) ++{ ++ p80211_frmmeta_t *meta; ++ DBFENTER; ++ meta = P80211SKB_FRMMETA(skb); ++ if ( meta && meta->rx) { ++ p80211skb_rxmeta_detach(skb); ++ } else { ++ WLAN_LOG_ERROR("Freeing an skb (%p) w/ no frmmeta.\n", skb); ++ } ++ ++ dev_kfree_skb(skb); ++ DBFEXIT; ++ return; ++} +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211conv.h +@@ -0,0 +1,186 @@ ++/* p80211conv.h ++* ++* Ether/802.11 conversions and packet buffer routines ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares the functions, types and macros that perform ++* Ethernet to/from 802.11 frame conversions. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _LINUX_P80211CONV_H ++#define _LINUX_P80211CONV_H ++ ++/*================================================================*/ ++/* Constants */ ++ ++#define WLAN_ETHADDR_LEN 6 ++#define WLAN_IEEE_OUI_LEN 3 ++ ++#define WLAN_ETHCONV_ENCAP 1 ++#define WLAN_ETHCONV_RFC1042 2 ++#define WLAN_ETHCONV_8021h 3 ++ ++#define WLAN_MIN_ETHFRM_LEN 60 ++#define WLAN_MAX_ETHFRM_LEN 1514 ++#define WLAN_ETHHDR_LEN 14 ++ ++#define P80211CAPTURE_VERSION 0x80211001 ++ ++/*================================================================*/ ++/* Macros */ ++ ++#define P80211_FRMMETA_MAGIC 0x802110 ++ ++#define P80211SKB_FRMMETA(s) \ ++ (((((p80211_frmmeta_t*)((s)->cb))->magic)==P80211_FRMMETA_MAGIC) ? \ ++ ((p80211_frmmeta_t*)((s)->cb)) : \ ++ (NULL)) ++ ++#define P80211SKB_RXMETA(s) \ ++ (P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((p80211_rxmeta_t*)(NULL))) ++ ++typedef struct p80211_rxmeta ++{ ++ struct wlandevice *wlandev; ++ ++ u64 mactime; /* Hi-rez MAC-supplied time value */ ++ u64 hosttime; /* Best-rez host supplied time value */ ++ ++ unsigned int rxrate; /* Receive data rate in 100kbps */ ++ unsigned int priority; /* 0-15, 0=contention, 6=CF */ ++ int signal; /* An SSI, see p80211netdev.h */ ++ int noise; /* An SSI, see p80211netdev.h */ ++ unsigned int channel; /* Receive channel (mostly for snifs) */ ++ unsigned int preamble; /* P80211ENUM_preambletype_* */ ++ unsigned int encoding; /* P80211ENUM_encoding_* */ ++ ++} p80211_rxmeta_t; ++ ++typedef struct p80211_frmmeta ++{ ++ unsigned int magic; ++ p80211_rxmeta_t *rx; ++} p80211_frmmeta_t; ++ ++void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb); ++int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb); ++void p80211skb_rxmeta_detach(struct sk_buff *skb); ++ ++/*================================================================*/ ++/* Types */ ++ ++/* ++ * Frame capture header. (See doc/capturefrm.txt) ++ */ ++typedef struct p80211_caphdr ++{ ++ u32 version; ++ u32 length; ++ u64 mactime; ++ u64 hosttime; ++ u32 phytype; ++ u32 channel; ++ u32 datarate; ++ u32 antenna; ++ u32 priority; ++ u32 ssi_type; ++ s32 ssi_signal; ++ s32 ssi_noise; ++ u32 preamble; ++ u32 encoding; ++} p80211_caphdr_t; ++ ++/* buffer free method pointer type */ ++typedef void (* freebuf_method_t)(void *buf, int size); ++ ++typedef struct p80211_metawep { ++ void *data; ++ u8 iv[4]; ++ u8 icv[4]; ++} p80211_metawep_t; ++ ++/* local ether header type */ ++typedef struct wlan_ethhdr ++{ ++ u8 daddr[WLAN_ETHADDR_LEN]; ++ u8 saddr[WLAN_ETHADDR_LEN]; ++ u16 type; ++} __WLAN_ATTRIB_PACK__ wlan_ethhdr_t; ++ ++/* local llc header type */ ++typedef struct wlan_llc ++{ ++ u8 dsap; ++ u8 ssap; ++ u8 ctl; ++} __WLAN_ATTRIB_PACK__ wlan_llc_t; ++ ++/* local snap header type */ ++typedef struct wlan_snap ++{ ++ u8 oui[WLAN_IEEE_OUI_LEN]; ++ u16 type; ++} __WLAN_ATTRIB_PACK__ wlan_snap_t; ++ ++/* Circular include trick */ ++struct wlandevice; ++ ++/*================================================================*/ ++/* Externs */ ++ ++/*================================================================*/ ++/*Function Declarations */ ++ ++int skb_p80211_to_ether( struct wlandevice *wlandev, u32 ethconv, ++ struct sk_buff *skb); ++int skb_ether_to_p80211( struct wlandevice *wlandev, u32 ethconv, ++ struct sk_buff *skb, p80211_hdr_t *p80211_hdr, ++ p80211_metawep_t *p80211_wep ); ++ ++int p80211_stt_findproto(u16 proto); ++int p80211_stt_addproto(u16 proto); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211hdr.h +@@ -0,0 +1,299 @@ ++/* p80211hdr.h ++* ++* Macros, types, and functions for handling 802.11 MAC headers ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares the constants and types used in the interface ++* between a wlan driver and the user mode utilities. ++* ++* Note: ++* - Constant values are always in HOST byte order. To assign ++* values to multi-byte fields they _must_ be converted to ++* ieee byte order. To retrieve multi-byte values from incoming ++* frames, they must be converted to host order. ++* ++* All functions declared here are implemented in p80211.c ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211HDR_H ++#define _P80211HDR_H ++ ++/*================================================================*/ ++/* System Includes */ ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*--- Sizes -----------------------------------------------*/ ++#define WLAN_ADDR_LEN 6 ++#define WLAN_CRC_LEN 4 ++#define WLAN_BSSID_LEN 6 ++#define WLAN_BSS_TS_LEN 8 ++#define WLAN_HDR_A3_LEN 24 ++#define WLAN_HDR_A4_LEN 30 ++#define WLAN_SSID_MAXLEN 32 ++#define WLAN_DATA_MAXLEN 2312 ++#define WLAN_A3FR_MAXLEN (WLAN_HDR_A3_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ++#define WLAN_A4FR_MAXLEN (WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ++#define WLAN_BEACON_FR_MAXLEN (WLAN_HDR_A3_LEN + 334) ++#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_A3_LEN + 0) ++#define WLAN_DISASSOC_FR_MAXLEN (WLAN_HDR_A3_LEN + 2) ++#define WLAN_ASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 48) ++#define WLAN_ASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16) ++#define WLAN_REASSOCREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 54) ++#define WLAN_REASSOCRESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 16) ++#define WLAN_PROBEREQ_FR_MAXLEN (WLAN_HDR_A3_LEN + 44) ++#define WLAN_PROBERESP_FR_MAXLEN (WLAN_HDR_A3_LEN + 78) ++#define WLAN_AUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 261) ++#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_A3_LEN + 2) ++#define WLAN_WEP_NKEYS 4 ++#define WLAN_WEP_MAXKEYLEN 13 ++#define WLAN_CHALLENGE_IE_LEN 130 ++#define WLAN_CHALLENGE_LEN 128 ++#define WLAN_WEP_IV_LEN 4 ++#define WLAN_WEP_ICV_LEN 4 ++ ++/*--- Frame Control Field -------------------------------------*/ ++/* Frame Types */ ++#define WLAN_FTYPE_MGMT 0x00 ++#define WLAN_FTYPE_CTL 0x01 ++#define WLAN_FTYPE_DATA 0x02 ++ ++/* Frame subtypes */ ++/* Management */ ++#define WLAN_FSTYPE_ASSOCREQ 0x00 ++#define WLAN_FSTYPE_ASSOCRESP 0x01 ++#define WLAN_FSTYPE_REASSOCREQ 0x02 ++#define WLAN_FSTYPE_REASSOCRESP 0x03 ++#define WLAN_FSTYPE_PROBEREQ 0x04 ++#define WLAN_FSTYPE_PROBERESP 0x05 ++#define WLAN_FSTYPE_BEACON 0x08 ++#define WLAN_FSTYPE_ATIM 0x09 ++#define WLAN_FSTYPE_DISASSOC 0x0a ++#define WLAN_FSTYPE_AUTHEN 0x0b ++#define WLAN_FSTYPE_DEAUTHEN 0x0c ++ ++/* Control */ ++#define WLAN_FSTYPE_BLOCKACKREQ 0x8 ++#define WLAN_FSTYPE_BLOCKACK 0x9 ++#define WLAN_FSTYPE_PSPOLL 0x0a ++#define WLAN_FSTYPE_RTS 0x0b ++#define WLAN_FSTYPE_CTS 0x0c ++#define WLAN_FSTYPE_ACK 0x0d ++#define WLAN_FSTYPE_CFEND 0x0e ++#define WLAN_FSTYPE_CFENDCFACK 0x0f ++ ++/* Data */ ++#define WLAN_FSTYPE_DATAONLY 0x00 ++#define WLAN_FSTYPE_DATA_CFACK 0x01 ++#define WLAN_FSTYPE_DATA_CFPOLL 0x02 ++#define WLAN_FSTYPE_DATA_CFACK_CFPOLL 0x03 ++#define WLAN_FSTYPE_NULL 0x04 ++#define WLAN_FSTYPE_CFACK 0x05 ++#define WLAN_FSTYPE_CFPOLL 0x06 ++#define WLAN_FSTYPE_CFACK_CFPOLL 0x07 ++ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*--- FC Macros ----------------------------------------------*/ ++/* Macros to get/set the bitfields of the Frame Control Field */ ++/* GET_FC_??? - takes the host byte-order value of an FC */ ++/* and retrieves the value of one of the */ ++/* bitfields and moves that value so its lsb is */ ++/* in bit 0. */ ++/* SET_FC_??? - takes a host order value for one of the FC */ ++/* bitfields and moves it to the proper bit */ ++/* location for ORing into a host order FC. */ ++/* To send the FC produced from SET_FC_???, */ ++/* one must put the bytes in IEEE order. */ ++/* e.g. */ ++/* printf("the frame subtype is %x", */ ++/* GET_FC_FTYPE( ieee2host( rx.fc ))) */ ++/* */ ++/* tx.fc = host2ieee( SET_FC_FTYPE(WLAN_FTYP_CTL) | */ ++/* SET_FC_FSTYPE(WLAN_FSTYPE_RTS) ); */ ++/*------------------------------------------------------------*/ ++ ++#define WLAN_GET_FC_PVER(n) (((u16)(n)) & (BIT0 | BIT1)) ++#define WLAN_GET_FC_FTYPE(n) ((((u16)(n)) & (BIT2 | BIT3)) >> 2) ++#define WLAN_GET_FC_FSTYPE(n) ((((u16)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4) ++#define WLAN_GET_FC_TODS(n) ((((u16)(n)) & (BIT8)) >> 8) ++#define WLAN_GET_FC_FROMDS(n) ((((u16)(n)) & (BIT9)) >> 9) ++#define WLAN_GET_FC_MOREFRAG(n) ((((u16)(n)) & (BIT10)) >> 10) ++#define WLAN_GET_FC_RETRY(n) ((((u16)(n)) & (BIT11)) >> 11) ++#define WLAN_GET_FC_PWRMGT(n) ((((u16)(n)) & (BIT12)) >> 12) ++#define WLAN_GET_FC_MOREDATA(n) ((((u16)(n)) & (BIT13)) >> 13) ++#define WLAN_GET_FC_ISWEP(n) ((((u16)(n)) & (BIT14)) >> 14) ++#define WLAN_GET_FC_ORDER(n) ((((u16)(n)) & (BIT15)) >> 15) ++ ++#define WLAN_SET_FC_PVER(n) ((u16)(n)) ++#define WLAN_SET_FC_FTYPE(n) (((u16)(n)) << 2) ++#define WLAN_SET_FC_FSTYPE(n) (((u16)(n)) << 4) ++#define WLAN_SET_FC_TODS(n) (((u16)(n)) << 8) ++#define WLAN_SET_FC_FROMDS(n) (((u16)(n)) << 9) ++#define WLAN_SET_FC_MOREFRAG(n) (((u16)(n)) << 10) ++#define WLAN_SET_FC_RETRY(n) (((u16)(n)) << 11) ++#define WLAN_SET_FC_PWRMGT(n) (((u16)(n)) << 12) ++#define WLAN_SET_FC_MOREDATA(n) (((u16)(n)) << 13) ++#define WLAN_SET_FC_ISWEP(n) (((u16)(n)) << 14) ++#define WLAN_SET_FC_ORDER(n) (((u16)(n)) << 15) ++ ++/*--- Duration Macros ----------------------------------------*/ ++/* Macros to get/set the bitfields of the Duration Field */ ++/* - the duration value is only valid when bit15 is zero */ ++/* - the firmware handles these values, so I'm not going */ ++/* these macros right now. */ ++/*------------------------------------------------------------*/ ++ ++/*--- Sequence Control Macros -------------------------------*/ ++/* Macros to get/set the bitfields of the Sequence Control */ ++/* Field. */ ++/*------------------------------------------------------------*/ ++#define WLAN_GET_SEQ_FRGNUM(n) (((u16)(n)) & (BIT0|BIT1|BIT2|BIT3)) ++#define WLAN_GET_SEQ_SEQNUM(n) ((((u16)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) ++ ++/*--- Data ptr macro -----------------------------------------*/ ++/* Creates a u8* to the data portion of a frame */ ++/* Assumes you're passing in a ptr to the beginning of the hdr*/ ++/*------------------------------------------------------------*/ ++#define WLAN_HDR_A3_DATAP(p) (((u8*)(p)) + WLAN_HDR_A3_LEN) ++#define WLAN_HDR_A4_DATAP(p) (((u8*)(p)) + WLAN_HDR_A4_LEN) ++ ++#define DOT11_RATE5_ISBASIC_GET(r) (((u8)(r)) & BIT7) ++ ++/*================================================================*/ ++/* Types */ ++ ++/* BSS Timestamp */ ++typedef u8 wlan_bss_ts_t[WLAN_BSS_TS_LEN]; ++ ++/* Generic 802.11 Header types */ ++ ++typedef struct p80211_hdr_a3 ++{ ++ u16 fc; ++ u16 dur; ++ u8 a1[WLAN_ADDR_LEN]; ++ u8 a2[WLAN_ADDR_LEN]; ++ u8 a3[WLAN_ADDR_LEN]; ++ u16 seq; ++} __WLAN_ATTRIB_PACK__ p80211_hdr_a3_t; ++ ++typedef struct p80211_hdr_a4 ++{ ++ u16 fc; ++ u16 dur; ++ u8 a1[WLAN_ADDR_LEN]; ++ u8 a2[WLAN_ADDR_LEN]; ++ u8 a3[WLAN_ADDR_LEN]; ++ u16 seq; ++ u8 a4[WLAN_ADDR_LEN]; ++} __WLAN_ATTRIB_PACK__ p80211_hdr_a4_t; ++ ++typedef union p80211_hdr ++{ ++ p80211_hdr_a3_t a3; ++ p80211_hdr_a4_t a4; ++} __WLAN_ATTRIB_PACK__ p80211_hdr_t; ++ ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++/* Frame and header lenght macros */ ++ ++#define WLAN_CTL_FRAMELEN(fstype) (\ ++ (fstype) == WLAN_FSTYPE_BLOCKACKREQ ? 24 : \ ++ (fstype) == WLAN_FSTYPE_BLOCKACK ? 152 : \ ++ (fstype) == WLAN_FSTYPE_PSPOLL ? 20 : \ ++ (fstype) == WLAN_FSTYPE_RTS ? 20 : \ ++ (fstype) == WLAN_FSTYPE_CTS ? 14 : \ ++ (fstype) == WLAN_FSTYPE_ACK ? 14 : \ ++ (fstype) == WLAN_FSTYPE_CFEND ? 20 : \ ++ (fstype) == WLAN_FSTYPE_CFENDCFACK ? 20 : 4) ++ ++#define WLAN_FCS_LEN 4 ++ ++/* ftcl in HOST order */ ++inline static u16 p80211_headerlen(u16 fctl) ++{ ++ u16 hdrlen = 0; ++ ++ switch ( WLAN_GET_FC_FTYPE(fctl) ) { ++ case WLAN_FTYPE_MGMT: ++ hdrlen = WLAN_HDR_A3_LEN; ++ break; ++ case WLAN_FTYPE_DATA: ++ hdrlen = WLAN_HDR_A3_LEN; ++ if ( WLAN_GET_FC_TODS(fctl) && WLAN_GET_FC_FROMDS(fctl) ) { ++ hdrlen += WLAN_ADDR_LEN; ++ } ++ break; ++ case WLAN_FTYPE_CTL: ++ hdrlen = WLAN_CTL_FRAMELEN(WLAN_GET_FC_FSTYPE(fctl)) - ++ WLAN_FCS_LEN; ++ break; ++ default: ++ hdrlen = WLAN_HDR_A3_LEN; ++ } ++ ++ return hdrlen; ++} ++ ++#endif /* _P80211HDR_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211ioctl.h +@@ -0,0 +1,123 @@ ++/* p80211ioctl.h ++* ++* Declares constants and types for the p80211 ioctls ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* While this file is called 'ioctl' is purpose goes a little beyond ++* that. This file defines the types and contants used to implement ++* the p80211 request/confirm/indicate interfaces on Linux. The ++* request/confirm interface is, in fact, normally implemented as an ++* ioctl. The indicate interface on the other hand, is implemented ++* using the Linux 'netlink' interface. ++* ++* The reason I say that request/confirm is 'normally' implemented ++* via ioctl is that we're reserving the right to be able to send ++* request commands via the netlink interface. This will be necessary ++* if we ever need to send request messages when there aren't any ++* wlan network devices present (i.e. sending a message that only p80211 ++* cares about. ++* -------------------------------------------------------------------- ++*/ ++ ++ ++#ifndef _P80211IOCTL_H ++#define _P80211IOCTL_H ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*----------------------------------------------------------------*/ ++/* p80211 ioctl "request" codes. See argument 2 of ioctl(2). */ ++ ++#define P80211_IFTEST (SIOCDEVPRIVATE + 0) ++#define P80211_IFREQ (SIOCDEVPRIVATE + 1) ++ ++/*----------------------------------------------------------------*/ ++/* Magic number, a quick test to see we're getting the desired struct */ ++ ++#define P80211_IOCTL_MAGIC (0x4a2d464dUL) ++ ++/*----------------------------------------------------------------*/ ++/* Netlink protocol numbers for the indication interface */ ++ ++#define P80211_NL_SOCK_IND NETLINK_USERSOCK ++ ++/*----------------------------------------------------------------*/ ++/* Netlink multicast bits for different types of messages */ ++ ++#define P80211_NL_MCAST_GRP_MLME BIT0 /* Local station messages */ ++#define P80211_NL_MCAST_GRP_SNIFF BIT1 /* Sniffer messages */ ++#define P80211_NL_MCAST_GRP_DIST BIT2 /* Distribution system messages */ ++ ++/*================================================================*/ ++/* Macros */ ++ ++ ++/*================================================================*/ ++/* Types */ ++ ++/*----------------------------------------------------------------*/ ++/* A ptr to the following structure type is passed as the third */ ++/* argument to the ioctl system call when issuing a request to */ ++/* the p80211 module. */ ++ ++typedef struct p80211ioctl_req ++{ ++ char name[WLAN_DEVNAMELEN_MAX]; ++ caddr_t data; ++ u32 magic; ++ u16 len; ++ u32 result; ++} __WLAN_ATTRIB_PACK__ p80211ioctl_req_t; ++ ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++ ++#endif /* _P80211IOCTL_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211metadef.h +@@ -0,0 +1,757 @@ ++/* This file is GENERATED AUTOMATICALLY. DO NOT EDIT OR MODIFY. ++* -------------------------------------------------------------------- ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211MKMETADEF_H ++#define _P80211MKMETADEF_H ++ ++ ++#define DIDmsg_cat_dot11req \ ++ P80211DID_MKSECTION(1) ++#define DIDmsg_dot11req_mibget \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(1)) ++#define DIDmsg_dot11req_mibget_mibattribute \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11req_mibget_resultcode \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11req_mibset \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(2)) ++#define DIDmsg_dot11req_mibset_mibattribute \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11req_mibset_resultcode \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11req_scan \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4)) ++#define DIDmsg_dot11req_scan_bsstype \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11req_scan_bssid \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11req_scan_ssid \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_dot11req_scan_scantype \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmsg_dot11req_scan_probedelay \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(5) | 0x00000000) ++#define DIDmsg_dot11req_scan_channellist \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(6) | 0x00000000) ++#define DIDmsg_dot11req_scan_minchanneltime \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(7) | 0x00000000) ++#define DIDmsg_dot11req_scan_maxchanneltime \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(8) | 0x00000000) ++#define DIDmsg_dot11req_scan_resultcode \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(9) | 0x00000000) ++#define DIDmsg_dot11req_scan_numbss \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(10) | 0x00000000) ++#define DIDmsg_dot11req_scan_append \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(11) | 0x00000000) ++#define DIDmsg_dot11req_scan_results \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5)) ++#define DIDmsg_dot11req_scan_results_bssindex \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_resultcode \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_signal \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_noise \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_bssid \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(5) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_ssid \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(6) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_bsstype \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(7) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_beaconperiod \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(8) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_dtimperiod \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(9) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_timestamp \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(10) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_localtime \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(11) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_fhdwelltime \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(12) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_fhhopset \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(13) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_fhhoppattern \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(14) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_fhhopindex \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(15) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_dschannel \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(16) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_cfpcount \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(17) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_cfpperiod \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(18) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_cfpmaxduration \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(19) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_cfpdurremaining \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(20) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_ibssatimwindow \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(21) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_cfpollable \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(22) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_cfpollreq \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(23) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_privacy \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(24) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate1 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(25) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate2 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(26) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate3 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(27) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate4 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(28) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate5 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(29) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate6 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(30) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate7 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(31) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_basicrate8 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(32) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate1 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(33) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate2 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(34) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate3 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(35) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate4 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(36) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate5 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(37) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate6 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(38) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate7 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(39) | 0x00000000) ++#define DIDmsg_dot11req_scan_results_supprate8 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(40) | 0x00000000) ++#define DIDmsg_dot11req_start \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13)) ++#define DIDmsg_dot11req_start_ssid \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11req_start_bsstype \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11req_start_beaconperiod \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_dot11req_start_dtimperiod \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmsg_dot11req_start_cfpperiod \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(5) | 0x00000000) ++#define DIDmsg_dot11req_start_cfpmaxduration \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(6) | 0x00000000) ++#define DIDmsg_dot11req_start_fhdwelltime \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(7) | 0x00000000) ++#define DIDmsg_dot11req_start_fhhopset \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(8) | 0x00000000) ++#define DIDmsg_dot11req_start_fhhoppattern \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(9) | 0x00000000) ++#define DIDmsg_dot11req_start_dschannel \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(10) | 0x00000000) ++#define DIDmsg_dot11req_start_ibssatimwindow \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(11) | 0x00000000) ++#define DIDmsg_dot11req_start_probedelay \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(12) | 0x00000000) ++#define DIDmsg_dot11req_start_cfpollable \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(13) | 0x00000000) ++#define DIDmsg_dot11req_start_cfpollreq \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(14) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate1 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(15) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate2 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(16) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate3 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(17) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate4 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(18) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate5 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(19) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate6 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(20) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate7 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(21) | 0x00000000) ++#define DIDmsg_dot11req_start_basicrate8 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(22) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate1 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(23) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate2 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(24) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate3 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(25) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate4 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(26) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate5 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(27) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate6 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(28) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate7 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(29) | 0x00000000) ++#define DIDmsg_dot11req_start_operationalrate8 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(30) | 0x00000000) ++#define DIDmsg_dot11req_start_resultcode \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(31) | 0x00000000) ++#define DIDmsg_cat_dot11ind \ ++ P80211DID_MKSECTION(2) ++#define DIDmsg_dot11ind_authenticate \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1)) ++#define DIDmsg_dot11ind_authenticate_peerstaaddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11ind_authenticate_authenticationtype \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11ind_deauthenticate \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(2)) ++#define DIDmsg_dot11ind_deauthenticate_peerstaaddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11ind_deauthenticate_reasoncode \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11ind_associate \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(3)) ++#define DIDmsg_dot11ind_associate_peerstaaddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(3) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11ind_associate_aid \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(3) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11ind_reassociate \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(4)) ++#define DIDmsg_dot11ind_reassociate_peerstaaddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11ind_reassociate_aid \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_dot11ind_reassociate_oldapaddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_dot11ind_disassociate \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(5)) ++#define DIDmsg_dot11ind_disassociate_peerstaaddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_dot11ind_disassociate_reasoncode \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_cat_lnxreq \ ++ P80211DID_MKSECTION(3) ++#define DIDmsg_lnxreq_ifstate \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(1)) ++#define DIDmsg_lnxreq_ifstate_ifstate \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_lnxreq_ifstate_resultcode \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2)) ++#define DIDmsg_lnxreq_wlansniff_enable \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_channel \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_prismheader \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_wlanheader \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_keepwepflags \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(5) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_stripfcs \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(6) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_packet_trunc \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(7) | 0x00000000) ++#define DIDmsg_lnxreq_wlansniff_resultcode \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(8) | 0x00000000) ++#define DIDmsg_lnxreq_hostwep \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(3)) ++#define DIDmsg_lnxreq_hostwep_resultcode \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(3) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_lnxreq_hostwep_decrypt \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(3) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_lnxreq_hostwep_encrypt \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(3) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_lnxreq_commsquality \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(4)) ++#define DIDmsg_lnxreq_commsquality_resultcode \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_lnxreq_commsquality_dbm \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_lnxreq_commsquality_link \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_lnxreq_commsquality_level \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmsg_lnxreq_commsquality_noise \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(5) | 0x00000000) ++#define DIDmsg_lnxreq_autojoin \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(5)) ++#define DIDmsg_lnxreq_autojoin_ssid \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_lnxreq_autojoin_authtype \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_lnxreq_autojoin_resultcode \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_cat_p2req \ ++ P80211DID_MKSECTION(5) ++#define DIDmsg_p2req_readpda \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(2)) ++#define DIDmsg_p2req_readpda_pda \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_p2req_readpda_resultcode \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_p2req_ramdl_state \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(11)) ++#define DIDmsg_p2req_ramdl_state_enable \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(11) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_p2req_ramdl_state_exeaddr \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(11) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_p2req_ramdl_state_resultcode \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(11) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_p2req_ramdl_write \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(12)) ++#define DIDmsg_p2req_ramdl_write_addr \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(12) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_p2req_ramdl_write_len \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(12) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_p2req_ramdl_write_data \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(12) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_p2req_ramdl_write_resultcode \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(12) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmsg_p2req_flashdl_state \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(13)) ++#define DIDmsg_p2req_flashdl_state_enable \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_p2req_flashdl_state_resultcode \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(13) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_p2req_flashdl_write \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(14)) ++#define DIDmsg_p2req_flashdl_write_addr \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(14) | \ ++ P80211DID_MKITEM(1) | 0x00000000) ++#define DIDmsg_p2req_flashdl_write_len \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(14) | \ ++ P80211DID_MKITEM(2) | 0x00000000) ++#define DIDmsg_p2req_flashdl_write_data \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(14) | \ ++ P80211DID_MKITEM(3) | 0x00000000) ++#define DIDmsg_p2req_flashdl_write_resultcode \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(14) | \ ++ P80211DID_MKITEM(4) | 0x00000000) ++#define DIDmib_cat_dot11smt \ ++ P80211DID_MKSECTION(1) ++#define DIDmib_dot11smt_dot11WEPDefaultKeysTable \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4)) ++#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(1) | 0x0c000000) ++#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(2) | 0x0c000000) ++#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(3) | 0x0c000000) ++#define DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3 \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(4) | \ ++ P80211DID_MKITEM(4) | 0x0c000000) ++#define DIDmib_dot11smt_dot11PrivacyTable \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(6)) ++#define DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(6) | \ ++ P80211DID_MKITEM(1) | 0x18000000) ++#define DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(6) | \ ++ P80211DID_MKITEM(2) | 0x18000000) ++#define DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted \ ++ (P80211DID_MKSECTION(1) | \ ++ P80211DID_MKGROUP(6) | \ ++ P80211DID_MKITEM(4) | 0x18000000) ++#define DIDmib_cat_dot11mac \ ++ P80211DID_MKSECTION(2) ++#define DIDmib_dot11mac_dot11OperationTable \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1)) ++#define DIDmib_dot11mac_dot11OperationTable_dot11MACAddress \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(1) | 0x18000000) ++#define DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(2) | 0x18000000) ++#define DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(3) | 0x10000000) ++#define DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(4) | 0x10000000) ++#define DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(5) | 0x18000000) ++#define DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime \ ++ (P80211DID_MKSECTION(2) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(6) | 0x10000000) ++#define DIDmib_cat_dot11phy \ ++ P80211DID_MKSECTION(3) ++#define DIDmib_dot11phy_dot11PhyOperationTable \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(1)) ++#define DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(3) | \ ++ P80211DID_MKITEM(10) | 0x18000000) ++#define DIDmib_dot11phy_dot11PhyDSSSTable \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(5)) ++#define DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel \ ++ (P80211DID_MKSECTION(3) | \ ++ P80211DID_MKGROUP(5) | \ ++ P80211DID_MKITEM(1) | 0x10000000) ++#define DIDmib_cat_lnx \ ++ P80211DID_MKSECTION(4) ++#define DIDmib_lnx_lnxConfigTable \ ++ (P80211DID_MKSECTION(4) | \ ++ P80211DID_MKGROUP(1)) ++#define DIDmib_lnx_lnxConfigTable_lnxRSNAIE \ ++ (P80211DID_MKSECTION(4) | \ ++ P80211DID_MKGROUP(1) | \ ++ P80211DID_MKITEM(1) | 0x18000000) ++#define DIDmib_cat_p2 \ ++ P80211DID_MKSECTION(5) ++#define DIDmib_p2_p2Static \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(2)) ++#define DIDmib_p2_p2Static_p2CnfPortType \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(2) | \ ++ P80211DID_MKITEM(1) | 0x18000000) ++#define DIDmib_p2_p2MAC \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(6)) ++#define DIDmib_p2_p2MAC_p2CurrentTxRate \ ++ (P80211DID_MKSECTION(5) | \ ++ P80211DID_MKGROUP(6) | \ ++ P80211DID_MKITEM(12) | 0x10000000) ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211meta.h +@@ -0,0 +1,169 @@ ++/* p80211meta.h ++* ++* Macros, constants, types, and funcs for p80211 metadata ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares some of the constants and types used in various ++* parts of the linux-wlan system. ++* ++* Notes: ++* - Constant values are always in HOST byte order. ++* ++* All functions and statics declared here are implemented in p80211types.c ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211META_H ++#define _P80211META_H ++ ++/*================================================================*/ ++/* System Includes */ ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*----------------------------------------------------------------*/ ++/* The following macros are used to ensure consistent naming */ ++/* conventions for all the different metadata lists. */ ++ ++#define MKREQMETANAME(name) p80211meta_ ## req ## _ ## name ++#define MKINDMETANAME(name) p80211meta_ ## ind ## _ ## name ++#define MKMIBMETANAME(name) p80211meta_ ## mib ## _ ## name ++#define MKGRPMETANAME(name) p80211meta_ ## grp ## _ ## name ++ ++#define MKREQMETASIZE(name) p80211meta_ ## req ## _ ## name ## _ ## size ++#define MKINDMETASIZE(name) p80211meta_ ## ind ## _ ## name ## _ ## size ++#define MKMIBMETASIZE(name) p80211meta_ ## mib ## _ ## name ## _ ## size ++#define MKGRPMETASIZE(name) p80211meta_ ## grp ## _ ## name ## _ ## size ++ ++#define GETMETASIZE(aptr) (**((u32**)(aptr))) ++ ++/*----------------------------------------------------------------*/ ++/* The following ifdef depends on the following defines: */ ++/* P80211_NOINCLUDESTRINGS - if defined, all metadata name fields */ ++/* are empty strings */ ++ ++#ifdef P80211_NOINCLUDESTRINGS ++ #define MKITEMNAME(s) ("") ++#else ++ #define MKITEMNAME(s) (s) ++#endif ++ ++/*================================================================*/ ++/* Types */ ++ ++/*----------------------------------------------------------------*/ ++/* The following structure types are used for the metadata */ ++/* representation of category list metadata, group list metadata, */ ++/* and data item metadata for both Mib and Messages. */ ++ ++typedef struct p80211meta ++{ ++ char *name; /* data item name */ ++ u32 did; /* partial did */ ++ u32 flags; /* set of various flag bits */ ++ u32 min; /* min value of a BOUNDEDint */ ++ u32 max; /* max value of a BOUNDEDint */ ++ ++ u32 maxlen; /* maxlen of a OCTETSTR or DISPLAYSTR */ ++ u32 minlen; /* minlen of a OCTETSTR or DISPLAYSTR */ ++ p80211enum_t *enumptr; /* ptr to the enum type for ENUMint */ ++ p80211_totext_t totextptr; /* ptr to totext conversion function */ ++ p80211_fromtext_t fromtextptr; /* ptr to totext conversion function */ ++ p80211_valid_t validfunptr; /* ptr to totext conversion function */ ++} p80211meta_t; ++ ++typedef struct grplistitem ++{ ++ char *name; ++ p80211meta_t *itemlist; ++} grplistitem_t; ++ ++typedef struct catlistitem ++{ ++ char *name; ++ grplistitem_t *grplist; ++} catlistitem_t; ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++u32 p80211_text2did(catlistitem_t *catlist, char *catname, char *grpname, char *itemname); ++u32 p80211_text2catdid(catlistitem_t *list, char *name ); ++u32 p80211_text2grpdid(grplistitem_t *list, char *name ); ++u32 p80211_text2itemdid(p80211meta_t *list, char *name ); ++u32 p80211_isvalid_did( catlistitem_t *catlist, u32 did ); ++u32 p80211_isvalid_catdid( catlistitem_t *catlist, u32 did ); ++u32 p80211_isvalid_grpdid( catlistitem_t *catlist, u32 did ); ++u32 p80211_isvalid_itemdid( catlistitem_t *catlist, u32 did ); ++catlistitem_t *p80211_did2cat( catlistitem_t *catlist, u32 did ); ++grplistitem_t *p80211_did2grp( catlistitem_t *catlist, u32 did ); ++p80211meta_t *p80211_did2item( catlistitem_t *catlist, u32 did ); ++u32 p80211item_maxdatalen( struct catlistitem *metalist, u32 did ); ++u32 p80211_metaname2did(struct catlistitem *metalist, char *itemname); ++u32 p80211item_getoffset( struct catlistitem *metalist, u32 did ); ++int p80211item_gettype(p80211meta_t *meta); ++ ++#endif /* _P80211META_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211metamib.h +@@ -0,0 +1,105 @@ ++/* p80211metamib.h ++* ++* Macros, const, types, and funcs for p80211 mib metadata ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares some of the constants and types used in various ++* parts of the linux-wlan system. ++* ++* Notes: ++* - Constant values are always in HOST byte order. ++* ++* All functions and statics declared here are implemented in p80211types.c ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211METAMIB_H ++#define _P80211METAMIB_H ++ ++/*================================================================*/ ++/* System Includes */ ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Types */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* The following is the external declaration for the mib */ ++/* category metadata list */ ++ ++extern catlistitem_t mib_catlist[]; ++extern u32 mib_catlist_size; ++ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++#endif /* _P80211METAMIB_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211metamsg.h +@@ -0,0 +1,105 @@ ++/* p80211metamsg.h ++* ++* Macros, const, types, and funcs for p80211 msg metadata ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares some of the constants and types used in various ++* parts of the linux-wlan system. ++* ++* Notes: ++* - Constant values are always in HOST byte order. ++* ++* All functions and statics declared here are implemented in p80211types.c ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211METAMSG_H ++#define _P80211METAMSG_H ++ ++/*================================================================*/ ++/* System Includes */ ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Types */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* The following is the external declaration for the message */ ++/* category metadata list */ ++ ++extern catlistitem_t msg_catlist[]; ++extern u32 msg_catlist_size; ++ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* */ ++ ++#endif /* _P80211METAMSG_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211metastruct.h +@@ -0,0 +1,285 @@ ++/* This file is GENERATED AUTOMATICALLY. DO NOT EDIT OR MODIFY. ++* -------------------------------------------------------------------- ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211MKMETASTRUCT_H ++#define _P80211MKMETASTRUCT_H ++ ++ ++typedef struct p80211msg_dot11req_mibget ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_unk392_t mibattribute ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_mibget_t; ++ ++typedef struct p80211msg_dot11req_mibset ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_unk392_t mibattribute ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_mibset_t; ++ ++typedef struct p80211msg_dot11req_scan ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t bsstype ; ++ p80211item_pstr6_t bssid ; ++ u8 pad_0C[1] ; ++ p80211item_pstr32_t ssid ; ++ u8 pad_1D[3] ; ++ p80211item_uint32_t scantype ; ++ p80211item_uint32_t probedelay ; ++ p80211item_pstr14_t channellist ; ++ u8 pad_2C[1] ; ++ p80211item_uint32_t minchanneltime ; ++ p80211item_uint32_t maxchanneltime ; ++ p80211item_uint32_t resultcode ; ++ p80211item_uint32_t numbss ; ++ p80211item_uint32_t append ; ++} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_scan_t; ++ ++typedef struct p80211msg_dot11req_scan_results ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t bssindex ; ++ p80211item_uint32_t resultcode ; ++ p80211item_uint32_t signal ; ++ p80211item_uint32_t noise ; ++ p80211item_pstr6_t bssid ; ++ u8 pad_3C[1] ; ++ p80211item_pstr32_t ssid ; ++ u8 pad_4D[3] ; ++ p80211item_uint32_t bsstype ; ++ p80211item_uint32_t beaconperiod ; ++ p80211item_uint32_t dtimperiod ; ++ p80211item_uint32_t timestamp ; ++ p80211item_uint32_t localtime ; ++ p80211item_uint32_t fhdwelltime ; ++ p80211item_uint32_t fhhopset ; ++ p80211item_uint32_t fhhoppattern ; ++ p80211item_uint32_t fhhopindex ; ++ p80211item_uint32_t dschannel ; ++ p80211item_uint32_t cfpcount ; ++ p80211item_uint32_t cfpperiod ; ++ p80211item_uint32_t cfpmaxduration ; ++ p80211item_uint32_t cfpdurremaining ; ++ p80211item_uint32_t ibssatimwindow ; ++ p80211item_uint32_t cfpollable ; ++ p80211item_uint32_t cfpollreq ; ++ p80211item_uint32_t privacy ; ++ p80211item_uint32_t basicrate1 ; ++ p80211item_uint32_t basicrate2 ; ++ p80211item_uint32_t basicrate3 ; ++ p80211item_uint32_t basicrate4 ; ++ p80211item_uint32_t basicrate5 ; ++ p80211item_uint32_t basicrate6 ; ++ p80211item_uint32_t basicrate7 ; ++ p80211item_uint32_t basicrate8 ; ++ p80211item_uint32_t supprate1 ; ++ p80211item_uint32_t supprate2 ; ++ p80211item_uint32_t supprate3 ; ++ p80211item_uint32_t supprate4 ; ++ p80211item_uint32_t supprate5 ; ++ p80211item_uint32_t supprate6 ; ++ p80211item_uint32_t supprate7 ; ++ p80211item_uint32_t supprate8 ; ++} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_scan_results_t; ++ ++typedef struct p80211msg_dot11req_start ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_pstr32_t ssid ; ++ u8 pad_12D[3] ; ++ p80211item_uint32_t bsstype ; ++ p80211item_uint32_t beaconperiod ; ++ p80211item_uint32_t dtimperiod ; ++ p80211item_uint32_t cfpperiod ; ++ p80211item_uint32_t cfpmaxduration ; ++ p80211item_uint32_t fhdwelltime ; ++ p80211item_uint32_t fhhopset ; ++ p80211item_uint32_t fhhoppattern ; ++ p80211item_uint32_t dschannel ; ++ p80211item_uint32_t ibssatimwindow ; ++ p80211item_uint32_t probedelay ; ++ p80211item_uint32_t cfpollable ; ++ p80211item_uint32_t cfpollreq ; ++ p80211item_uint32_t basicrate1 ; ++ p80211item_uint32_t basicrate2 ; ++ p80211item_uint32_t basicrate3 ; ++ p80211item_uint32_t basicrate4 ; ++ p80211item_uint32_t basicrate5 ; ++ p80211item_uint32_t basicrate6 ; ++ p80211item_uint32_t basicrate7 ; ++ p80211item_uint32_t basicrate8 ; ++ p80211item_uint32_t operationalrate1 ; ++ p80211item_uint32_t operationalrate2 ; ++ p80211item_uint32_t operationalrate3 ; ++ p80211item_uint32_t operationalrate4 ; ++ p80211item_uint32_t operationalrate5 ; ++ p80211item_uint32_t operationalrate6 ; ++ p80211item_uint32_t operationalrate7 ; ++ p80211item_uint32_t operationalrate8 ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_dot11req_start_t; ++ ++typedef struct p80211msg_lnxreq_ifstate ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t ifstate ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_ifstate_t; ++ ++typedef struct p80211msg_lnxreq_wlansniff ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t enable ; ++ p80211item_uint32_t channel ; ++ p80211item_uint32_t prismheader ; ++ p80211item_uint32_t wlanheader ; ++ p80211item_uint32_t keepwepflags ; ++ p80211item_uint32_t stripfcs ; ++ p80211item_uint32_t packet_trunc ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_wlansniff_t; ++ ++typedef struct p80211msg_lnxreq_hostwep ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t resultcode ; ++ p80211item_uint32_t decrypt ; ++ p80211item_uint32_t encrypt ; ++} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_hostwep_t; ++ ++typedef struct p80211msg_lnxreq_commsquality ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t resultcode ; ++ p80211item_uint32_t dbm ; ++ p80211item_uint32_t link ; ++ p80211item_uint32_t level ; ++ p80211item_uint32_t noise ; ++} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_commsquality_t; ++ ++typedef struct p80211msg_lnxreq_autojoin ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_pstr32_t ssid ; ++ u8 pad_19D[3] ; ++ p80211item_uint32_t authtype ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_lnxreq_autojoin_t; ++ ++typedef struct p80211msg_p2req_readpda ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_unk1024_t pda ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_p2req_readpda_t; ++ ++typedef struct p80211msg_p2req_ramdl_state ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t enable ; ++ p80211item_uint32_t exeaddr ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_p2req_ramdl_state_t; ++ ++typedef struct p80211msg_p2req_ramdl_write ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t addr ; ++ p80211item_uint32_t len ; ++ p80211item_unk4096_t data ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_p2req_ramdl_write_t; ++ ++typedef struct p80211msg_p2req_flashdl_state ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t enable ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_p2req_flashdl_state_t; ++ ++typedef struct p80211msg_p2req_flashdl_write ++{ ++ u32 msgcode ; ++ u32 msglen ; ++ u8 devname[WLAN_DEVNAMELEN_MAX] ; ++ p80211item_uint32_t addr ; ++ p80211item_uint32_t len ; ++ p80211item_unk4096_t data ; ++ p80211item_uint32_t resultcode ; ++} __WLAN_ATTRIB_PACK__ p80211msg_p2req_flashdl_write_t; ++ ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211mgmt.h +@@ -0,0 +1,575 @@ ++/* p80211mgmt.h ++* ++* Macros, types, and functions to handle 802.11 mgmt frames ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares the constants and types used in the interface ++* between a wlan driver and the user mode utilities. ++* ++* Notes: ++* - Constant values are always in HOST byte order. To assign ++* values to multi-byte fields they _must_ be converted to ++* ieee byte order. To retrieve multi-byte values from incoming ++* frames, they must be converted to host order. ++* ++* - The len member of the frame structure does NOT!!! include ++* the MAC CRC. Therefore, the len field on rx'd frames should ++* have 4 subtracted from it. ++* ++* All functions declared here are implemented in p80211.c ++* ++* The types, macros, and functions defined here are primarily ++* used for encoding and decoding management frames. They are ++* designed to follow these patterns of use: ++* ++* DECODE: ++* 1) a frame of length len is received into buffer b ++* 2) using the hdr structure and macros, we determine the type ++* 3) an appropriate mgmt frame structure, mf, is allocated and zeroed ++* 4) mf.hdr = b ++* mf.buf = b ++* mf.len = len ++* 5) call mgmt_decode( mf ) ++* 6) the frame field pointers in mf are now set. Note that any ++* multi-byte frame field values accessed using the frame field ++* pointers are in ieee byte order and will have to be converted ++* to host order. ++* ++* ENCODE: ++* 1) Library client allocates buffer space for maximum length ++* frame of the desired type ++* 2) Library client allocates a mgmt frame structure, called mf, ++* of the desired type ++* 3) Set the following: ++* mf.type = ++* mf.buf = ++* 4) call mgmt_encode( mf ) ++* 5) all of the fixed field pointers and fixed length information element ++* pointers in mf are now set to their respective locations in the ++* allocated space (fortunately, all variable length information elements ++* fall at the end of their respective frames). ++* 5a) The length field is set to include the last of the fixed and fixed ++* length fields. It may have to be updated for optional or variable ++* length information elements. ++* 6) Optional and variable length information elements are special cases ++* and must be handled individually by the client code. ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211MGMT_H ++#define _P80211MGMT_H ++ ++/*================================================================*/ ++/* System Includes */ ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++#ifndef _P80211HDR_H ++#include "p80211hdr.h" ++#endif ++ ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*-- Information Element IDs --------------------*/ ++#define WLAN_EID_SSID 0 ++#define WLAN_EID_SUPP_RATES 1 ++#define WLAN_EID_FH_PARMS 2 ++#define WLAN_EID_DS_PARMS 3 ++#define WLAN_EID_CF_PARMS 4 ++#define WLAN_EID_TIM 5 ++#define WLAN_EID_IBSS_PARMS 6 ++/*-- values 7-15 reserved --*/ ++#define WLAN_EID_CHALLENGE 16 ++/*-- values 17-31 reserved for challenge text extension --*/ ++/*-- values 32-255 reserved --*/ ++ ++/*-- Reason Codes -------------------------------*/ ++#define WLAN_MGMT_REASON_RSVD 0 ++#define WLAN_MGMT_REASON_UNSPEC 1 ++#define WLAN_MGMT_REASON_PRIOR_AUTH_INVALID 2 ++#define WLAN_MGMT_REASON_DEAUTH_LEAVING 3 ++#define WLAN_MGMT_REASON_DISASSOC_INACTIVE 4 ++#define WLAN_MGMT_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_MGMT_REASON_CLASS2_NONAUTH 6 ++#define WLAN_MGMT_REASON_CLASS3_NONASSOC 7 ++#define WLAN_MGMT_REASON_DISASSOC_STA_HASLEFT 8 ++#define WLAN_MGMT_REASON_CANT_ASSOC_NONAUTH 9 ++ ++/*-- Status Codes -------------------------------*/ ++#define WLAN_MGMT_STATUS_SUCCESS 0 ++#define WLAN_MGMT_STATUS_UNSPEC_FAILURE 1 ++#define WLAN_MGMT_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_MGMT_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG 13 ++#define WLAN_MGMT_STATUS_RX_AUTH_NOSEQ 14 ++#define WLAN_MGMT_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_MGMT_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY 17 ++#define WLAN_MGMT_STATUS_ASSOC_DENIED_RATES 18 ++ /* p80211b additions */ ++#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_MGMT_STATUS_ASSOC_DENIED_NOAGILITY 21 ++ ++ ++ ++/*-- Auth Algorithm Field ---------------------------*/ ++#define WLAN_AUTH_ALG_OPENSYSTEM 0 ++#define WLAN_AUTH_ALG_SHAREDKEY 1 ++ ++/*-- Management Frame Field Offsets -------------*/ ++/* Note: Not all fields are listed because of variable lengths, */ ++/* see the code in p80211.c to see how we search for fields */ ++/* Note: These offsets are from the start of the frame data */ ++ ++#define WLAN_BEACON_OFF_TS 0 ++#define WLAN_BEACON_OFF_BCN_int 8 ++#define WLAN_BEACON_OFF_CAPINFO 10 ++#define WLAN_BEACON_OFF_SSID 12 ++ ++#define WLAN_DISASSOC_OFF_REASON 0 ++ ++#define WLAN_ASSOCREQ_OFF_CAP_INFO 0 ++#define WLAN_ASSOCREQ_OFF_LISTEN_int 2 ++#define WLAN_ASSOCREQ_OFF_SSID 4 ++ ++#define WLAN_ASSOCRESP_OFF_CAP_INFO 0 ++#define WLAN_ASSOCRESP_OFF_STATUS 2 ++#define WLAN_ASSOCRESP_OFF_AID 4 ++#define WLAN_ASSOCRESP_OFF_SUPP_RATES 6 ++ ++#define WLAN_REASSOCREQ_OFF_CAP_INFO 0 ++#define WLAN_REASSOCREQ_OFF_LISTEN_int 2 ++#define WLAN_REASSOCREQ_OFF_CURR_AP 4 ++#define WLAN_REASSOCREQ_OFF_SSID 10 ++ ++#define WLAN_REASSOCRESP_OFF_CAP_INFO 0 ++#define WLAN_REASSOCRESP_OFF_STATUS 2 ++#define WLAN_REASSOCRESP_OFF_AID 4 ++#define WLAN_REASSOCRESP_OFF_SUPP_RATES 6 ++ ++#define WLAN_PROBEREQ_OFF_SSID 0 ++ ++#define WLAN_PROBERESP_OFF_TS 0 ++#define WLAN_PROBERESP_OFF_BCN_int 8 ++#define WLAN_PROBERESP_OFF_CAP_INFO 10 ++#define WLAN_PROBERESP_OFF_SSID 12 ++ ++#define WLAN_AUTHEN_OFF_AUTH_ALG 0 ++#define WLAN_AUTHEN_OFF_AUTH_SEQ 2 ++#define WLAN_AUTHEN_OFF_STATUS 4 ++#define WLAN_AUTHEN_OFF_CHALLENGE 6 ++ ++#define WLAN_DEAUTHEN_OFF_REASON 0 ++ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*-- Capability Field ---------------------------*/ ++#define WLAN_GET_MGMT_CAP_INFO_ESS(n) ((n) & BIT0) ++#define WLAN_GET_MGMT_CAP_INFO_IBSS(n) (((n) & BIT1) >> 1) ++#define WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(n) (((n) & BIT2) >> 2) ++#define WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(n) (((n) & BIT3) >> 3) ++#define WLAN_GET_MGMT_CAP_INFO_PRIVACY(n) (((n) & BIT4) >> 4) ++ /* p80211b additions */ ++#define WLAN_GET_MGMT_CAP_INFO_SHORT(n) (((n) & BIT5) >> 5) ++#define WLAN_GET_MGMT_CAP_INFO_PBCC(n) (((n) & BIT6) >> 6) ++#define WLAN_GET_MGMT_CAP_INFO_AGILITY(n) (((n) & BIT7) >> 7) ++ ++#define WLAN_SET_MGMT_CAP_INFO_ESS(n) (n) ++#define WLAN_SET_MGMT_CAP_INFO_IBSS(n) ((n) << 1) ++#define WLAN_SET_MGMT_CAP_INFO_CFPOLLABLE(n) ((n) << 2) ++#define WLAN_SET_MGMT_CAP_INFO_CFPOLLREQ(n) ((n) << 3) ++#define WLAN_SET_MGMT_CAP_INFO_PRIVACY(n) ((n) << 4) ++ /* p80211b additions */ ++#define WLAN_SET_MGMT_CAP_INFO_SHORT(n) ((n) << 5) ++#define WLAN_SET_MGMT_CAP_INFO_PBCC(n) ((n) << 6) ++#define WLAN_SET_MGMT_CAP_INFO_AGILITY(n) ((n) << 7) ++ ++ ++/*================================================================*/ ++/* Types */ ++ ++/*-- Information Element Types --------------------*/ ++/* prototype structure, all IEs start with these members */ ++ ++typedef struct wlan_ie ++{ ++ u8 eid; ++ u8 len; ++} __WLAN_ATTRIB_PACK__ wlan_ie_t; ++ ++/*-- Service Set Identity (SSID) -----------------*/ ++typedef struct wlan_ie_ssid ++{ ++ u8 eid; ++ u8 len; ++ u8 ssid[1]; /* may be zero, ptrs may overlap */ ++} __WLAN_ATTRIB_PACK__ wlan_ie_ssid_t; ++ ++/*-- Supported Rates -----------------------------*/ ++typedef struct wlan_ie_supp_rates ++{ ++ u8 eid; ++ u8 len; ++ u8 rates[1]; /* had better be at LEAST one! */ ++} __WLAN_ATTRIB_PACK__ wlan_ie_supp_rates_t; ++ ++/*-- FH Parameter Set ----------------------------*/ ++typedef struct wlan_ie_fh_parms ++{ ++ u8 eid; ++ u8 len; ++ u16 dwell; ++ u8 hopset; ++ u8 hoppattern; ++ u8 hopindex; ++} __WLAN_ATTRIB_PACK__ wlan_ie_fh_parms_t; ++ ++/*-- DS Parameter Set ----------------------------*/ ++typedef struct wlan_ie_ds_parms ++{ ++ u8 eid; ++ u8 len; ++ u8 curr_ch; ++} __WLAN_ATTRIB_PACK__ wlan_ie_ds_parms_t; ++ ++/*-- CF Parameter Set ----------------------------*/ ++ ++typedef struct wlan_ie_cf_parms ++{ ++ u8 eid; ++ u8 len; ++ u8 cfp_cnt; ++ u8 cfp_period; ++ u16 cfp_maxdur; ++ u16 cfp_durremaining; ++} __WLAN_ATTRIB_PACK__ wlan_ie_cf_parms_t; ++ ++/*-- TIM ------------------------------------------*/ ++typedef struct wlan_ie_tim ++{ ++ u8 eid; ++ u8 len; ++ u8 dtim_cnt; ++ u8 dtim_period; ++ u8 bitmap_ctl; ++ u8 virt_bm[1]; ++} __WLAN_ATTRIB_PACK__ wlan_ie_tim_t; ++ ++/*-- IBSS Parameter Set ---------------------------*/ ++typedef struct wlan_ie_ibss_parms ++{ ++ u8 eid; ++ u8 len; ++ u16 atim_win; ++} __WLAN_ATTRIB_PACK__ wlan_ie_ibss_parms_t; ++ ++/*-- Challenge Text ------------------------------*/ ++typedef struct wlan_ie_challenge ++{ ++ u8 eid; ++ u8 len; ++ u8 challenge[1]; ++} __WLAN_ATTRIB_PACK__ wlan_ie_challenge_t; ++ ++/*-------------------------------------------------*/ ++/* Frame Types */ ++ ++/* prototype structure, all mgmt frame types will start with these members */ ++typedef struct wlan_fr_mgmt ++{ ++ u16 type; ++ u16 len; /* DOES NOT include CRC !!!!*/ ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ /*-- info elements ----------*/ ++} wlan_fr_mgmt_t; ++ ++/*-- Beacon ---------------------------------------*/ ++typedef struct wlan_fr_beacon ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u64 *ts; ++ u16 *bcn_int; ++ u16 *cap_info; ++ /*-- info elements ----------*/ ++ wlan_ie_ssid_t *ssid; ++ wlan_ie_supp_rates_t *supp_rates; ++ wlan_ie_fh_parms_t *fh_parms; ++ wlan_ie_ds_parms_t *ds_parms; ++ wlan_ie_cf_parms_t *cf_parms; ++ wlan_ie_ibss_parms_t *ibss_parms; ++ wlan_ie_tim_t *tim; ++ ++} wlan_fr_beacon_t; ++ ++ ++/*-- IBSS ATIM ------------------------------------*/ ++typedef struct wlan_fr_ibssatim ++{ ++ u16 type; ++ u16 len; ++ u8* buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ ++ /*-- fixed fields -----------*/ ++ /*-- info elements ----------*/ ++ ++ /* this frame type has a null body */ ++ ++} wlan_fr_ibssatim_t; ++ ++/*-- Disassociation -------------------------------*/ ++typedef struct wlan_fr_disassoc ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *reason; ++ ++ /*-- info elements ----------*/ ++ ++} wlan_fr_disassoc_t; ++ ++/*-- Association Request --------------------------*/ ++typedef struct wlan_fr_assocreq ++{ ++ u16 type; ++ u16 len; ++ u8* buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *cap_info; ++ u16 *listen_int; ++ /*-- info elements ----------*/ ++ wlan_ie_ssid_t *ssid; ++ wlan_ie_supp_rates_t *supp_rates; ++ ++} wlan_fr_assocreq_t; ++ ++/*-- Association Response -------------------------*/ ++typedef struct wlan_fr_assocresp ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *cap_info; ++ u16 *status; ++ u16 *aid; ++ /*-- info elements ----------*/ ++ wlan_ie_supp_rates_t *supp_rates; ++ ++} wlan_fr_assocresp_t; ++ ++/*-- Reassociation Request ------------------------*/ ++typedef struct wlan_fr_reassocreq ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *cap_info; ++ u16 *listen_int; ++ u8 *curr_ap; ++ /*-- info elements ----------*/ ++ wlan_ie_ssid_t *ssid; ++ wlan_ie_supp_rates_t *supp_rates; ++ ++} wlan_fr_reassocreq_t; ++ ++/*-- Reassociation Response -----------------------*/ ++typedef struct wlan_fr_reassocresp ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *cap_info; ++ u16 *status; ++ u16 *aid; ++ /*-- info elements ----------*/ ++ wlan_ie_supp_rates_t *supp_rates; ++ ++} wlan_fr_reassocresp_t; ++ ++/*-- Probe Request --------------------------------*/ ++typedef struct wlan_fr_probereq ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ /*-- info elements ----------*/ ++ wlan_ie_ssid_t *ssid; ++ wlan_ie_supp_rates_t *supp_rates; ++ ++} wlan_fr_probereq_t; ++ ++/*-- Probe Response -------------------------------*/ ++typedef struct wlan_fr_proberesp ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u64 *ts; ++ u16 *bcn_int; ++ u16 *cap_info; ++ /*-- info elements ----------*/ ++ wlan_ie_ssid_t *ssid; ++ wlan_ie_supp_rates_t *supp_rates; ++ wlan_ie_fh_parms_t *fh_parms; ++ wlan_ie_ds_parms_t *ds_parms; ++ wlan_ie_cf_parms_t *cf_parms; ++ wlan_ie_ibss_parms_t *ibss_parms; ++} wlan_fr_proberesp_t; ++ ++/*-- Authentication -------------------------------*/ ++typedef struct wlan_fr_authen ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *auth_alg; ++ u16 *auth_seq; ++ u16 *status; ++ /*-- info elements ----------*/ ++ wlan_ie_challenge_t *challenge; ++ ++} wlan_fr_authen_t; ++ ++/*-- Deauthenication -----------------------------*/ ++typedef struct wlan_fr_deauthen ++{ ++ u16 type; ++ u16 len; ++ u8 *buf; ++ p80211_hdr_t *hdr; ++ /* used for target specific data, skb in Linux */ ++ void *priv; ++ /*-- fixed fields -----------*/ ++ u16 *reason; ++ ++ /*-- info elements ----------*/ ++ ++} wlan_fr_deauthen_t; ++ ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++void wlan_mgmt_encode_beacon( wlan_fr_beacon_t *f ); ++void wlan_mgmt_decode_beacon( wlan_fr_beacon_t *f ); ++void wlan_mgmt_encode_disassoc( wlan_fr_disassoc_t *f ); ++void wlan_mgmt_decode_disassoc( wlan_fr_disassoc_t *f ); ++void wlan_mgmt_encode_assocreq( wlan_fr_assocreq_t *f ); ++void wlan_mgmt_decode_assocreq( wlan_fr_assocreq_t *f ); ++void wlan_mgmt_encode_assocresp( wlan_fr_assocresp_t *f ); ++void wlan_mgmt_decode_assocresp( wlan_fr_assocresp_t *f ); ++void wlan_mgmt_encode_reassocreq( wlan_fr_reassocreq_t *f ); ++void wlan_mgmt_decode_reassocreq( wlan_fr_reassocreq_t *f ); ++void wlan_mgmt_encode_reassocresp( wlan_fr_reassocresp_t *f ); ++void wlan_mgmt_decode_reassocresp( wlan_fr_reassocresp_t *f ); ++void wlan_mgmt_encode_probereq( wlan_fr_probereq_t *f ); ++void wlan_mgmt_decode_probereq( wlan_fr_probereq_t *f ); ++void wlan_mgmt_encode_proberesp( wlan_fr_proberesp_t *f ); ++void wlan_mgmt_decode_proberesp( wlan_fr_proberesp_t *f ); ++void wlan_mgmt_encode_authen( wlan_fr_authen_t *f ); ++void wlan_mgmt_decode_authen( wlan_fr_authen_t *f ); ++void wlan_mgmt_encode_deauthen( wlan_fr_deauthen_t *f ); ++void wlan_mgmt_decode_deauthen( wlan_fr_deauthen_t *f ); ++ ++ ++#endif /* _P80211MGMT_H */ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211msg.h +@@ -0,0 +1,102 @@ ++/* p80211msg.h ++* ++* Macros, constants, types, and funcs for req and ind messages ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211MSG_H ++#define _P80211MSG_H ++ ++/*================================================================*/ ++/* System Includes */ ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++/*================================================================*/ ++/* Constants */ ++ ++#define MSG_BUFF_LEN 4000 ++#define WLAN_DEVNAMELEN_MAX 16 ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*================================================================*/ ++/* Types */ ++ ++/*--------------------------------------------------------------------*/ ++/*----- Message Structure Types --------------------------------------*/ ++ ++/*--------------------------------------------------------------------*/ ++/* Prototype msg type */ ++ ++typedef struct p80211msg ++{ ++ u32 msgcode; ++ u32 msglen; ++ u8 devname[WLAN_DEVNAMELEN_MAX]; ++} __WLAN_ATTRIB_PACK__ p80211msg_t; ++ ++typedef struct p80211msgd ++{ ++ u32 msgcode; ++ u32 msglen; ++ u8 devname[WLAN_DEVNAMELEN_MAX]; ++ u8 args[0]; ++} __WLAN_ATTRIB_PACK__ p80211msgd_t; ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++#endif /* _P80211MSG_H */ ++ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211netdev.c +@@ -0,0 +1,1209 @@ ++/* src/p80211/p80211knetdev.c ++* ++* Linux Kernel net device interface ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* The functions required for a Linux network device are defined here. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++ ++/*================================================================*/ ++/* System Includes */ ++ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#ifdef SIOCETHTOOL ++#include ++#endif ++ ++#include ++#include ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "wlan_compat.h" ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211conv.h" ++#include "p80211mgmt.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211ioctl.h" ++#include "p80211req.h" ++#include "p80211metastruct.h" ++#include "p80211metadef.h" ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++/*================================================================*/ ++/* Local Macros */ ++ ++ ++/*================================================================*/ ++/* Local Types */ ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++/* Support functions */ ++static void p80211netdev_rx_bh(unsigned long arg); ++ ++/* netdevice method functions */ ++static int p80211knetdev_init( netdevice_t *netdev); ++static struct net_device_stats* p80211knetdev_get_stats(netdevice_t *netdev); ++static int p80211knetdev_open( netdevice_t *netdev); ++static int p80211knetdev_stop( netdevice_t *netdev ); ++static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev); ++static void p80211knetdev_set_multicast_list(netdevice_t *dev); ++static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); ++static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr); ++static void p80211knetdev_tx_timeout(netdevice_t *netdev); ++static int p80211_rx_typedrop( wlandevice_t *wlandev, u16 fc); ++ ++int wlan_watchdog = 5000; ++module_param(wlan_watchdog, int, 0644); ++MODULE_PARM_DESC(wlan_watchdog, "transmit timeout in milliseconds"); ++ ++int wlan_wext_write = 1; ++module_param(wlan_wext_write, int, 0644); ++MODULE_PARM_DESC(wlan_wext_write, "enable write wireless extensions"); ++ ++#ifdef WLAN_INCLUDE_DEBUG ++int wlan_debug=0; ++module_param(wlan_debug, int, 0644); ++MODULE_PARM_DESC(wlan_debug, "p80211 debug level"); ++#endif ++ ++/*================================================================*/ ++/* Function Definitions */ ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_init ++* ++* Init method for a Linux netdevice. Called in response to ++* register_netdev. ++* ++* Arguments: ++* none ++* ++* Returns: ++* nothing ++----------------------------------------------------------------*/ ++static int p80211knetdev_init( netdevice_t *netdev) ++{ ++ DBFENTER; ++ /* Called in response to register_netdev */ ++ /* This is usually the probe function, but the probe has */ ++ /* already been done by the MSD and the create_kdev */ ++ /* function. All we do here is return success */ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_get_stats ++* ++* Statistics retrieval for linux netdevices. Here we're reporting ++* the Linux i/f level statistics. Hence, for the primary numbers, ++* we don't want to report the numbers from the MIB. Eventually, ++* it might be useful to collect some of the error counters though. ++* ++* Arguments: ++* netdev Linux netdevice ++* ++* Returns: ++* the address of the statistics structure ++----------------------------------------------------------------*/ ++static struct net_device_stats* ++p80211knetdev_get_stats(netdevice_t *netdev) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; ++ DBFENTER; ++ ++ /* TODO: review the MIB stats for items that correspond to ++ linux stats */ ++ ++ DBFEXIT; ++ return &(wlandev->linux_stats); ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_open ++* ++* Linux netdevice open method. Following a successful call here, ++* the device is supposed to be ready for tx and rx. In our ++* situation that may not be entirely true due to the state of the ++* MAC below. ++* ++* Arguments: ++* netdev Linux network device structure ++* ++* Returns: ++* zero on success, non-zero otherwise ++----------------------------------------------------------------*/ ++static int p80211knetdev_open( netdevice_t *netdev ) ++{ ++ int result = 0; /* success */ ++ wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); ++ ++ DBFENTER; ++ ++ /* Check to make sure the MSD is running */ ++ if ( wlandev->msdstate != WLAN_MSD_RUNNING ) { ++ return -ENODEV; ++ } ++ ++ /* Tell the MSD to open */ ++ if ( wlandev->open != NULL) { ++ result = wlandev->open(wlandev); ++ if ( result == 0 ) { ++ netif_start_queue(wlandev->netdev); ++ wlandev->state = WLAN_DEVICE_OPEN; ++ } ++ } else { ++ result = -EAGAIN; ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_stop ++* ++* Linux netdevice stop (close) method. Following this call, ++* no frames should go up or down through this interface. ++* ++* Arguments: ++* netdev Linux network device structure ++* ++* Returns: ++* zero on success, non-zero otherwise ++----------------------------------------------------------------*/ ++static int p80211knetdev_stop( netdevice_t *netdev ) ++{ ++ int result = 0; ++ wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); ++ ++ DBFENTER; ++ ++ if ( wlandev->close != NULL ) { ++ result = wlandev->close(wlandev); ++ } ++ ++ netif_stop_queue(wlandev->netdev); ++ wlandev->state = WLAN_DEVICE_CLOSED; ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* p80211netdev_rx ++* ++* Frame receive function called by the mac specific driver. ++* ++* Arguments: ++* wlandev WLAN network device structure ++* skb skbuff containing a full 802.11 frame. ++* Returns: ++* nothing ++* Side effects: ++* ++----------------------------------------------------------------*/ ++void ++p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb ) ++{ ++ DBFENTER; ++ ++ /* Enqueue for post-irq processing */ ++ skb_queue_tail(&wlandev->nsd_rxq, skb); ++ ++ tasklet_schedule(&wlandev->rx_bh); ++ ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* p80211netdev_rx_bh ++* ++* Deferred processing of all received frames. ++* ++* Arguments: ++* wlandev WLAN network device structure ++* skb skbuff containing a full 802.11 frame. ++* Returns: ++* nothing ++* Side effects: ++* ++----------------------------------------------------------------*/ ++static void p80211netdev_rx_bh(unsigned long arg) ++{ ++ wlandevice_t *wlandev = (wlandevice_t *) arg; ++ struct sk_buff *skb = NULL; ++ netdevice_t *dev = wlandev->netdev; ++ p80211_hdr_a3_t *hdr; ++ u16 fc; ++ ++ DBFENTER; ++ ++ /* Let's empty our our queue */ ++ while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) { ++ if (wlandev->state == WLAN_DEVICE_OPEN) { ++ ++ if (dev->type != ARPHRD_ETHER) { ++ /* RAW frame; we shouldn't convert it */ ++ // XXX Append the Prism Header here instead. ++ ++ /* set up various data fields */ ++ skb->dev = dev; ++ skb_reset_mac_header(skb); ++ skb->ip_summed = CHECKSUM_NONE; ++ skb->pkt_type = PACKET_OTHERHOST; ++ skb->protocol = htons(ETH_P_80211_RAW); ++ dev->last_rx = jiffies; ++ ++ wlandev->linux_stats.rx_packets++; ++ wlandev->linux_stats.rx_bytes += skb->len; ++ netif_rx_ni(skb); ++ continue; ++ } else { ++ hdr = (p80211_hdr_a3_t *)skb->data; ++ fc = ieee2host16(hdr->fc); ++ if (p80211_rx_typedrop(wlandev, fc)) { ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ /* perform mcast filtering */ ++ if (wlandev->netdev->flags & IFF_ALLMULTI) { ++ /* allow my local address through */ ++ if (memcmp(hdr->a1, wlandev->netdev->dev_addr, WLAN_ADDR_LEN) != 0) { ++ /* but reject anything else that isn't multicast */ ++ if (!(hdr->a1[0] & 0x01)) { ++ dev_kfree_skb(skb); ++ continue; ++ } ++ } ++ } ++ ++ if ( skb_p80211_to_ether(wlandev, wlandev->ethconv, skb) == 0 ) { ++ skb->dev->last_rx = jiffies; ++ wlandev->linux_stats.rx_packets++; ++ wlandev->linux_stats.rx_bytes += skb->len; ++ netif_rx_ni(skb); ++ continue; ++ } ++ WLAN_LOG_DEBUG(1, "p80211_to_ether failed.\n"); ++ } ++ } ++ dev_kfree_skb(skb); ++ } ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_hard_start_xmit ++* ++* Linux netdevice method for transmitting a frame. ++* ++* Arguments: ++* skb Linux sk_buff containing the frame. ++* netdev Linux netdevice. ++* ++* Side effects: ++* If the lower layers report that buffers are full. netdev->tbusy ++* will be set to prevent higher layers from sending more traffic. ++* ++* Note: If this function returns non-zero, higher layers retain ++* ownership of the skb. ++* ++* Returns: ++* zero on success, non-zero on failure. ++----------------------------------------------------------------*/ ++static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev) ++{ ++ int result = 0; ++ int txresult = -1; ++ wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; ++ p80211_hdr_t p80211_hdr; ++ p80211_metawep_t p80211_wep; ++ ++ DBFENTER; ++ ++ if (skb == NULL) { ++ return 0; ++ } ++ ++ if (wlandev->state != WLAN_DEVICE_OPEN) { ++ result = 1; ++ goto failed; ++ } ++ ++ memset(&p80211_hdr, 0, sizeof(p80211_hdr_t)); ++ memset(&p80211_wep, 0, sizeof(p80211_metawep_t)); ++ ++ if ( netif_queue_stopped(netdev) ) { ++ WLAN_LOG_DEBUG(1, "called when queue stopped.\n"); ++ result = 1; ++ goto failed; ++ } ++ ++ netif_stop_queue(netdev); ++ ++ /* Check to see that a valid mode is set */ ++ switch( wlandev->macmode ) { ++ case WLAN_MACMODE_IBSS_STA: ++ case WLAN_MACMODE_ESS_STA: ++ case WLAN_MACMODE_ESS_AP: ++ break; ++ default: ++ /* Mode isn't set yet, just drop the frame ++ * and return success . ++ * TODO: we need a saner way to handle this ++ */ ++ if(skb->protocol != ETH_P_80211_RAW) { ++ netif_start_queue(wlandev->netdev); ++ WLAN_LOG_NOTICE( ++ "Tx attempt prior to association, frame dropped.\n"); ++ wlandev->linux_stats.tx_dropped++; ++ result = 0; ++ goto failed; ++ } ++ break; ++ } ++ ++ /* Check for raw transmits */ ++ if(skb->protocol == ETH_P_80211_RAW) { ++ if (!capable(CAP_NET_ADMIN)) { ++ result = 1; ++ goto failed; ++ } ++ /* move the header over */ ++ memcpy(&p80211_hdr, skb->data, sizeof(p80211_hdr_t)); ++ skb_pull(skb, sizeof(p80211_hdr_t)); ++ } else { ++ if ( skb_ether_to_p80211(wlandev, wlandev->ethconv, skb, &p80211_hdr, &p80211_wep) != 0 ) { ++ /* convert failed */ ++ WLAN_LOG_DEBUG(1, "ether_to_80211(%d) failed.\n", ++ wlandev->ethconv); ++ result = 1; ++ goto failed; ++ } ++ } ++ if ( wlandev->txframe == NULL ) { ++ result = 1; ++ goto failed; ++ } ++ ++ netdev->trans_start = jiffies; ++ ++ wlandev->linux_stats.tx_packets++; ++ /* count only the packet payload */ ++ wlandev->linux_stats.tx_bytes += skb->len; ++ ++ txresult = wlandev->txframe(wlandev, skb, &p80211_hdr, &p80211_wep); ++ ++ if ( txresult == 0) { ++ /* success and more buf */ ++ /* avail, re: hw_txdata */ ++ netif_wake_queue(wlandev->netdev); ++ result = 0; ++ } else if ( txresult == 1 ) { ++ /* success, no more avail */ ++ WLAN_LOG_DEBUG(3, "txframe success, no more bufs\n"); ++ /* netdev->tbusy = 1; don't set here, irqhdlr */ ++ /* may have already cleared it */ ++ result = 0; ++ } else if ( txresult == 2 ) { ++ /* alloc failure, drop frame */ ++ WLAN_LOG_DEBUG(3, "txframe returned alloc_fail\n"); ++ result = 1; ++ } else { ++ /* buffer full or queue busy, drop frame. */ ++ WLAN_LOG_DEBUG(3, "txframe returned full or busy\n"); ++ result = 1; ++ } ++ ++ failed: ++ /* Free up the WEP buffer if it's not the same as the skb */ ++ if ((p80211_wep.data) && (p80211_wep.data != skb->data)) ++ kfree(p80211_wep.data); ++ ++ /* we always free the skb here, never in a lower level. */ ++ if (!result) ++ dev_kfree_skb(skb); ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_set_multicast_list ++* ++* Called from higher lavers whenever there's a need to set/clear ++* promiscuous mode or rewrite the multicast list. ++* ++* Arguments: ++* none ++* ++* Returns: ++* nothing ++----------------------------------------------------------------*/ ++static void p80211knetdev_set_multicast_list(netdevice_t *dev) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ ++ DBFENTER; ++ ++ /* TODO: real multicast support as well */ ++ ++ if (wlandev->set_multicast_list) ++ wlandev->set_multicast_list(wlandev, dev); ++ ++ DBFEXIT; ++} ++ ++#ifdef SIOCETHTOOL ++ ++static int p80211netdev_ethtool(wlandevice_t *wlandev, void __user *useraddr) ++{ ++ u32 ethcmd; ++ struct ethtool_drvinfo info; ++ struct ethtool_value edata; ++ ++ memset(&info, 0, sizeof(info)); ++ memset(&edata, 0, sizeof(edata)); ++ ++ if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) ++ return -EFAULT; ++ ++ switch (ethcmd) { ++ case ETHTOOL_GDRVINFO: ++ info.cmd = ethcmd; ++ snprintf(info.driver, sizeof(info.driver), "p80211_%s", ++ wlandev->nsdname); ++ snprintf(info.version, sizeof(info.version), "%s", ++ WLAN_RELEASE); ++ ++ // info.fw_version ++ // info.bus_info ++ ++ if (copy_to_user(useraddr, &info, sizeof(info))) ++ return -EFAULT; ++ return 0; ++#ifdef ETHTOOL_GLINK ++ case ETHTOOL_GLINK: ++ edata.cmd = ethcmd; ++ ++ if (wlandev->linkstatus && ++ (wlandev->macmode != WLAN_MACMODE_NONE)) { ++ edata.data = 1; ++ } else { ++ edata.data = 0; ++ } ++ ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++#endif ++ ++ return -EOPNOTSUPP; ++} ++ ++#endif ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_do_ioctl ++* ++* Handle an ioctl call on one of our devices. Everything Linux ++* ioctl specific is done here. Then we pass the contents of the ++* ifr->data to the request message handler. ++* ++* Arguments: ++* dev Linux kernel netdevice ++* ifr Our private ioctl request structure, typed for the ++* generic struct ifreq so we can use ptr to func ++* w/o cast. ++* ++* Returns: ++* zero on success, a negative errno on failure. Possible values: ++* -ENETDOWN Device isn't up. ++* -EBUSY cmd already in progress ++* -ETIME p80211 cmd timed out (MSD may have its own timers) ++* -EFAULT memory fault copying msg from user buffer ++* -ENOMEM unable to allocate kernel msg buffer ++* -ENOSYS bad magic, it the cmd really for us? ++* -EintR sleeping on cmd, awakened by signal, cmd cancelled. ++* ++* Call Context: ++* Process thread (ioctl caller). TODO: SMP support may require ++* locks. ++----------------------------------------------------------------*/ ++static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) ++{ ++ int result = 0; ++ p80211ioctl_req_t *req = (p80211ioctl_req_t*)ifr; ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ u8 *msgbuf; ++ DBFENTER; ++ ++ WLAN_LOG_DEBUG(2, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len); ++ ++#ifdef SIOCETHTOOL ++ if (cmd == SIOCETHTOOL) { ++ result = p80211netdev_ethtool(wlandev, (void __user *) ifr->ifr_data); ++ goto bail; ++ } ++#endif ++ ++ /* Test the magic, assume ifr is good if it's there */ ++ if ( req->magic != P80211_IOCTL_MAGIC ) { ++ result = -ENOSYS; ++ goto bail; ++ } ++ ++ if ( cmd == P80211_IFTEST ) { ++ result = 0; ++ goto bail; ++ } else if ( cmd != P80211_IFREQ ) { ++ result = -ENOSYS; ++ goto bail; ++ } ++ ++ /* Allocate a buf of size req->len */ ++ if ((msgbuf = kmalloc( req->len, GFP_KERNEL))) { ++ if ( copy_from_user( msgbuf, (void __user *) req->data, req->len) ) { ++ result = -EFAULT; ++ } else { ++ result = p80211req_dorequest( wlandev, msgbuf); ++ } ++ ++ if ( result == 0 ) { ++ if ( copy_to_user( (void __user *) req->data, msgbuf, req->len)) { ++ result = -EFAULT; ++ } ++ } ++ kfree(msgbuf); ++ } else { ++ result = -ENOMEM; ++ } ++bail: ++ DBFEXIT; ++ ++ return result; /* If allocate,copyfrom or copyto fails, return errno */ ++} ++ ++/*---------------------------------------------------------------- ++* p80211knetdev_set_mac_address ++* ++* Handles the ioctl for changing the MACAddress of a netdevice ++* ++* references: linux/netdevice.h and drivers/net/net_init.c ++* ++* NOTE: [MSM] We only prevent address changes when the netdev is ++* up. We don't control anything based on dot11 state. If the ++* address is changed on a STA that's currently associated, you ++* will probably lose the ability to send and receive data frames. ++* Just be aware. Therefore, this should usually only be done ++* prior to scan/join/auth/assoc. ++* ++* Arguments: ++* dev netdevice struct ++* addr the new MACAddress (a struct) ++* ++* Returns: ++* zero on success, a negative errno on failure. Possible values: ++* -EBUSY device is bussy (cmd not possible) ++* -and errors returned by: p80211req_dorequest(..) ++* ++* by: Collin R. Mulliner ++----------------------------------------------------------------*/ ++static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) ++{ ++ struct sockaddr *new_addr = addr; ++ p80211msg_dot11req_mibset_t dot11req; ++ p80211item_unk392_t *mibattr; ++ p80211item_pstr6_t *macaddr; ++ p80211item_uint32_t *resultcode; ++ int result = 0; ++ ++ DBFENTER; ++ /* If we're running, we don't allow MAC address changes */ ++ if (netif_running(dev)) { ++ return -EBUSY; ++ } ++ ++ /* Set up some convenience pointers. */ ++ mibattr = &dot11req.mibattribute; ++ macaddr = (p80211item_pstr6_t*)&mibattr->data; ++ resultcode = &dot11req.resultcode; ++ ++ /* Set up a dot11req_mibset */ ++ memset(&dot11req, 0, sizeof(p80211msg_dot11req_mibset_t)); ++ dot11req.msgcode = DIDmsg_dot11req_mibset; ++ dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t); ++ memcpy(dot11req.devname, ++ ((wlandevice_t*)(dev->priv))->name, ++ WLAN_DEVNAMELEN_MAX - 1); ++ ++ /* Set up the mibattribute argument */ ++ mibattr->did = DIDmsg_dot11req_mibset_mibattribute; ++ mibattr->status = P80211ENUM_msgitem_status_data_ok; ++ mibattr->len = sizeof(mibattr->data); ++ ++ macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress; ++ macaddr->status = P80211ENUM_msgitem_status_data_ok; ++ macaddr->len = sizeof(macaddr->data); ++ macaddr->data.len = WLAN_ADDR_LEN; ++ memcpy(&macaddr->data.data, new_addr->sa_data, WLAN_ADDR_LEN); ++ ++ /* Set up the resultcode argument */ ++ resultcode->did = DIDmsg_dot11req_mibset_resultcode; ++ resultcode->status = P80211ENUM_msgitem_status_no_value; ++ resultcode->len = sizeof(resultcode->data); ++ resultcode->data = 0; ++ ++ /* now fire the request */ ++ result = p80211req_dorequest(dev->priv, (u8*)&dot11req); ++ ++ /* If the request wasn't successful, report an error and don't ++ * change the netdev address ++ */ ++ if ( result != 0 || resultcode->data != P80211ENUM_resultcode_success) { ++ WLAN_LOG_ERROR( ++ "Low-level driver failed dot11req_mibset(dot11MACAddress).\n"); ++ result = -EADDRNOTAVAIL; ++ } else { ++ /* everything's ok, change the addr in netdev */ ++ memcpy(dev->dev_addr, new_addr->sa_data, dev->addr_len); ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++static int wlan_change_mtu(netdevice_t *dev, int new_mtu) ++{ ++ DBFENTER; ++ // 2312 is max 802.11 payload, 20 is overhead, (ether + llc +snap) ++ // and another 8 for wep. ++ if ( (new_mtu < 68) || (new_mtu > (2312 - 20 - 8))) ++ return -EINVAL; ++ ++ dev->mtu = new_mtu; ++ ++ DBFEXIT; ++ ++ return 0; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* wlan_setup ++* ++* Roughly matches the functionality of ether_setup. Here ++* we set up any members of the wlandevice structure that are common ++* to all devices. Additionally, we allocate a linux 'struct device' ++* and perform the same setup as ether_setup. ++* ++* Note: It's important that the caller have setup the wlandev->name ++* ptr prior to calling this function. ++* ++* Arguments: ++* wlandev ptr to the wlandev structure for the ++* interface. ++* Returns: ++* zero on success, non-zero otherwise. ++* Call Context: ++* Should be process thread. We'll assume it might be ++* interrupt though. When we add support for statically ++* compiled drivers, this function will be called in the ++* context of the kernel startup code. ++----------------------------------------------------------------*/ ++int wlan_setup(wlandevice_t *wlandev) ++{ ++ int result = 0; ++ netdevice_t *dev; ++ ++ DBFENTER; ++ ++ /* Set up the wlandev */ ++ wlandev->state = WLAN_DEVICE_CLOSED; ++ wlandev->ethconv = WLAN_ETHCONV_8021h; ++ wlandev->macmode = WLAN_MACMODE_NONE; ++ ++ /* Set up the rx queue */ ++ skb_queue_head_init(&wlandev->nsd_rxq); ++ tasklet_init(&wlandev->rx_bh, ++ p80211netdev_rx_bh, ++ (unsigned long)wlandev); ++ ++ /* Allocate and initialize the struct device */ ++ dev = alloc_netdev(0,"wlan%d",ether_setup); ++ if ( dev == NULL ) { ++ WLAN_LOG_ERROR("Failed to alloc netdev.\n"); ++ result = 1; ++ } else { ++ wlandev->netdev = dev; ++ dev->priv = wlandev; ++ dev->hard_start_xmit = p80211knetdev_hard_start_xmit; ++ dev->get_stats = p80211knetdev_get_stats; ++#ifdef HAVE_PRIVATE_IOCTL ++ dev->do_ioctl = p80211knetdev_do_ioctl; ++#endif ++#ifdef HAVE_MULTICAST ++ dev->set_multicast_list = p80211knetdev_set_multicast_list; ++#endif ++ dev->init = p80211knetdev_init; ++ dev->open = p80211knetdev_open; ++ dev->stop = p80211knetdev_stop; ++ ++#if (WIRELESS_EXT < 21) ++ dev->get_wireless_stats = p80211wext_get_wireless_stats; ++#endif ++ dev->wireless_handlers = &p80211wext_handler_def; ++ ++ netif_stop_queue(dev); ++#ifdef HAVE_CHANGE_MTU ++ dev->change_mtu = wlan_change_mtu; ++#endif ++#ifdef HAVE_SET_MAC_ADDR ++ dev->set_mac_address = p80211knetdev_set_mac_address; ++#endif ++#ifdef HAVE_TX_TIMEOUT ++ dev->tx_timeout = &p80211knetdev_tx_timeout; ++ dev->watchdog_timeo = (wlan_watchdog * HZ) / 1000; ++#endif ++ netif_carrier_off(dev); ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* wlan_unsetup ++* ++* This function is paired with the wlan_setup routine. It should ++* be called after unregister_wlandev. Basically, all it does is ++* free the 'struct device' that's associated with the wlandev. ++* We do it here because the 'struct device' isn't allocated ++* explicitly in the driver code, it's done in wlan_setup. To ++* do the free in the driver might seem like 'magic'. ++* ++* Arguments: ++* wlandev ptr to the wlandev structure for the ++* interface. ++* Returns: ++* zero on success, non-zero otherwise. ++* Call Context: ++* Should be process thread. We'll assume it might be ++* interrupt though. When we add support for statically ++* compiled drivers, this function will be called in the ++* context of the kernel startup code. ++----------------------------------------------------------------*/ ++int wlan_unsetup(wlandevice_t *wlandev) ++{ ++ int result = 0; ++ ++ DBFENTER; ++ ++ tasklet_kill(&wlandev->rx_bh); ++ ++ if (wlandev->netdev == NULL ) { ++ WLAN_LOG_ERROR("called without wlandev->netdev set.\n"); ++ result = 1; ++ } else { ++ free_netdev(wlandev->netdev); ++ wlandev->netdev = NULL; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* register_wlandev ++* ++* Roughly matches the functionality of register_netdev. This function ++* is called after the driver has successfully probed and set up the ++* resources for the device. It's now ready to become a named device ++* in the Linux system. ++* ++* First we allocate a name for the device (if not already set), then ++* we call the Linux function register_netdevice. ++* ++* Arguments: ++* wlandev ptr to the wlandev structure for the ++* interface. ++* Returns: ++* zero on success, non-zero otherwise. ++* Call Context: ++* Can be either interrupt or not. ++----------------------------------------------------------------*/ ++int register_wlandev(wlandevice_t *wlandev) ++{ ++ int i = 0; ++ ++ DBFENTER; ++ ++ i = register_netdev(wlandev->netdev); ++ if (i) ++ return i; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* unregister_wlandev ++* ++* Roughly matches the functionality of unregister_netdev. This ++* function is called to remove a named device from the system. ++* ++* First we tell linux that the device should no longer exist. ++* Then we remove it from the list of known wlan devices. ++* ++* Arguments: ++* wlandev ptr to the wlandev structure for the ++* interface. ++* Returns: ++* zero on success, non-zero otherwise. ++* Call Context: ++* Can be either interrupt or not. ++----------------------------------------------------------------*/ ++int unregister_wlandev(wlandevice_t *wlandev) ++{ ++ struct sk_buff *skb; ++ ++ DBFENTER; ++ ++ unregister_netdev(wlandev->netdev); ++ ++ /* Now to clean out the rx queue */ ++ while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) { ++ dev_kfree_skb(skb); ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211netdev_hwremoved ++* ++* Hardware removed notification. This function should be called ++* immediately after an MSD has detected that the underlying hardware ++* has been yanked out from under us. The primary things we need ++* to do are: ++* - Mark the wlandev ++* - Prevent any further traffic from the knetdev i/f ++* - Prevent any further requests from mgmt i/f ++* - If there are any waitq'd mgmt requests or mgmt-frame exchanges, ++* shut them down. ++* - Call the MSD hwremoved function. ++* ++* The remainder of the cleanup will be handled by unregister(). ++* Our primary goal here is to prevent as much tickling of the MSD ++* as possible since the MSD is already in a 'wounded' state. ++* ++* TODO: As new features are added, this function should be ++* updated. ++* ++* Arguments: ++* wlandev WLAN network device structure ++* Returns: ++* nothing ++* Side effects: ++* ++* Call context: ++* Usually interrupt. ++----------------------------------------------------------------*/ ++void p80211netdev_hwremoved(wlandevice_t *wlandev) ++{ ++ DBFENTER; ++ wlandev->hwremoved = 1; ++ if ( wlandev->state == WLAN_DEVICE_OPEN) { ++ netif_stop_queue(wlandev->netdev); ++ } ++ ++ netif_device_detach(wlandev->netdev); ++ ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* p80211_rx_typedrop ++* ++* Classifies the frame, increments the appropriate counter, and ++* returns 0|1|2 indicating whether the driver should handle, ignore, or ++* drop the frame ++* ++* Arguments: ++* wlandev wlan device structure ++* fc frame control field ++* ++* Returns: ++* zero if the frame should be handled by the driver, ++* one if the frame should be ignored ++* anything else means we drop it. ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static int p80211_rx_typedrop( wlandevice_t *wlandev, u16 fc) ++{ ++ u16 ftype; ++ u16 fstype; ++ int drop = 0; ++ /* Classify frame, increment counter */ ++ ftype = WLAN_GET_FC_FTYPE(fc); ++ fstype = WLAN_GET_FC_FSTYPE(fc); ++#if 0 ++ WLAN_LOG_DEBUG(4, ++ "rx_typedrop : ftype=%d fstype=%d.\n", ftype, fstype); ++#endif ++ switch ( ftype ) { ++ case WLAN_FTYPE_MGMT: ++ if ((wlandev->netdev->flags & IFF_PROMISC) || ++ (wlandev->netdev->flags & IFF_ALLMULTI)) { ++ drop = 1; ++ break; ++ } ++ WLAN_LOG_DEBUG(3, "rx'd mgmt:\n"); ++ wlandev->rx.mgmt++; ++ switch( fstype ) { ++ case WLAN_FSTYPE_ASSOCREQ: ++ /* printk("assocreq"); */ ++ wlandev->rx.assocreq++; ++ break; ++ case WLAN_FSTYPE_ASSOCRESP: ++ /* printk("assocresp"); */ ++ wlandev->rx.assocresp++; ++ break; ++ case WLAN_FSTYPE_REASSOCREQ: ++ /* printk("reassocreq"); */ ++ wlandev->rx.reassocreq++; ++ break; ++ case WLAN_FSTYPE_REASSOCRESP: ++ /* printk("reassocresp"); */ ++ wlandev->rx.reassocresp++; ++ break; ++ case WLAN_FSTYPE_PROBEREQ: ++ /* printk("probereq"); */ ++ wlandev->rx.probereq++; ++ break; ++ case WLAN_FSTYPE_PROBERESP: ++ /* printk("proberesp"); */ ++ wlandev->rx.proberesp++; ++ break; ++ case WLAN_FSTYPE_BEACON: ++ /* printk("beacon"); */ ++ wlandev->rx.beacon++; ++ break; ++ case WLAN_FSTYPE_ATIM: ++ /* printk("atim"); */ ++ wlandev->rx.atim++; ++ break; ++ case WLAN_FSTYPE_DISASSOC: ++ /* printk("disassoc"); */ ++ wlandev->rx.disassoc++; ++ break; ++ case WLAN_FSTYPE_AUTHEN: ++ /* printk("authen"); */ ++ wlandev->rx.authen++; ++ break; ++ case WLAN_FSTYPE_DEAUTHEN: ++ /* printk("deauthen"); */ ++ wlandev->rx.deauthen++; ++ break; ++ default: ++ /* printk("unknown"); */ ++ wlandev->rx.mgmt_unknown++; ++ break; ++ } ++ /* printk("\n"); */ ++ drop = 2; ++ break; ++ ++ case WLAN_FTYPE_CTL: ++ if ((wlandev->netdev->flags & IFF_PROMISC) || ++ (wlandev->netdev->flags & IFF_ALLMULTI)) { ++ drop = 1; ++ break; ++ } ++ WLAN_LOG_DEBUG(3, "rx'd ctl:\n"); ++ wlandev->rx.ctl++; ++ switch( fstype ) { ++ case WLAN_FSTYPE_PSPOLL: ++ /* printk("pspoll"); */ ++ wlandev->rx.pspoll++; ++ break; ++ case WLAN_FSTYPE_RTS: ++ /* printk("rts"); */ ++ wlandev->rx.rts++; ++ break; ++ case WLAN_FSTYPE_CTS: ++ /* printk("cts"); */ ++ wlandev->rx.cts++; ++ break; ++ case WLAN_FSTYPE_ACK: ++ /* printk("ack"); */ ++ wlandev->rx.ack++; ++ break; ++ case WLAN_FSTYPE_CFEND: ++ /* printk("cfend"); */ ++ wlandev->rx.cfend++; ++ break; ++ case WLAN_FSTYPE_CFENDCFACK: ++ /* printk("cfendcfack"); */ ++ wlandev->rx.cfendcfack++; ++ break; ++ default: ++ /* printk("unknown"); */ ++ wlandev->rx.ctl_unknown++; ++ break; ++ } ++ /* printk("\n"); */ ++ drop = 2; ++ break; ++ ++ case WLAN_FTYPE_DATA: ++ wlandev->rx.data++; ++ switch( fstype ) { ++ case WLAN_FSTYPE_DATAONLY: ++ wlandev->rx.dataonly++; ++ break; ++ case WLAN_FSTYPE_DATA_CFACK: ++ wlandev->rx.data_cfack++; ++ break; ++ case WLAN_FSTYPE_DATA_CFPOLL: ++ wlandev->rx.data_cfpoll++; ++ break; ++ case WLAN_FSTYPE_DATA_CFACK_CFPOLL: ++ wlandev->rx.data__cfack_cfpoll++; ++ break; ++ case WLAN_FSTYPE_NULL: ++ WLAN_LOG_DEBUG(3, "rx'd data:null\n"); ++ wlandev->rx.null++; ++ break; ++ case WLAN_FSTYPE_CFACK: ++ WLAN_LOG_DEBUG(3, "rx'd data:cfack\n"); ++ wlandev->rx.cfack++; ++ break; ++ case WLAN_FSTYPE_CFPOLL: ++ WLAN_LOG_DEBUG(3, "rx'd data:cfpoll\n"); ++ wlandev->rx.cfpoll++; ++ break; ++ case WLAN_FSTYPE_CFACK_CFPOLL: ++ WLAN_LOG_DEBUG(3, "rx'd data:cfack_cfpoll\n"); ++ wlandev->rx.cfack_cfpoll++; ++ break; ++ default: ++ /* printk("unknown"); */ ++ wlandev->rx.data_unknown++; ++ break; ++ } ++ ++ break; ++ } ++ return drop; ++} ++ ++static void p80211knetdev_tx_timeout( netdevice_t *netdev) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; ++ DBFENTER; ++ ++ if (wlandev->tx_timeout) { ++ wlandev->tx_timeout(wlandev); ++ } else { ++ WLAN_LOG_WARNING("Implement tx_timeout for %s\n", ++ wlandev->nsdname); ++ netif_wake_queue(wlandev->netdev); ++ } ++ ++ DBFEXIT; ++} +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211netdev.h +@@ -0,0 +1,254 @@ ++/* p80211netdev.h ++* ++* WLAN net device structure and functions ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares the structure type that represents each wlan ++* interface. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _LINUX_P80211NETDEV_H ++#define _LINUX_P80211NETDEV_H ++ ++#include ++#include ++ ++/*================================================================*/ ++/* Constants */ ++ ++#define WLAN_DEVICE_CLOSED 0 ++#define WLAN_DEVICE_OPEN 1 ++ ++#define WLAN_MACMODE_NONE 0 ++#define WLAN_MACMODE_IBSS_STA 1 ++#define WLAN_MACMODE_ESS_STA 2 ++#define WLAN_MACMODE_ESS_AP 3 ++ ++/* MSD States */ ++#define WLAN_MSD_START -1 ++#define WLAN_MSD_DRIVERLOADED 0 ++#define WLAN_MSD_HWPRESENT_PENDING 1 ++#define WLAN_MSD_HWFAIL 2 ++#define WLAN_MSD_HWPRESENT 3 ++#define WLAN_MSD_FWLOAD_PENDING 4 ++#define WLAN_MSD_FWLOAD 5 ++#define WLAN_MSD_RUNNING_PENDING 6 ++#define WLAN_MSD_RUNNING 7 ++ ++#ifndef ETH_P_ECONET ++#define ETH_P_ECONET 0x0018 /* needed for 2.2.x kernels */ ++#endif ++ ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++ ++#ifndef ARPHRD_IEEE80211 ++#define ARPHRD_IEEE80211 801 /* kernel 2.4.6 */ ++#endif ++ ++#ifndef ARPHRD_IEEE80211_PRISM /* kernel 2.4.18 */ ++#define ARPHRD_IEEE80211_PRISM 802 ++#endif ++ ++/*--- NSD Capabilities Flags ------------------------------*/ ++#define P80211_NSDCAP_HARDWAREWEP 0x01 /* hardware wep engine */ ++#define P80211_NSDCAP_TIEDWEP 0x02 /* can't decouple en/de */ ++#define P80211_NSDCAP_NOHOSTWEP 0x04 /* must use hardware wep */ ++#define P80211_NSDCAP_PBCC 0x08 /* hardware supports PBCC */ ++#define P80211_NSDCAP_SHORT_PREAMBLE 0x10 /* hardware supports */ ++#define P80211_NSDCAP_AGILITY 0x20 /* hardware supports */ ++#define P80211_NSDCAP_AP_RETRANSMIT 0x40 /* nsd handles retransmits */ ++#define P80211_NSDCAP_HWFRAGMENT 0x80 /* nsd handles frag/defrag */ ++#define P80211_NSDCAP_AUTOJOIN 0x100 /* nsd does autojoin */ ++#define P80211_NSDCAP_NOSCAN 0x200 /* nsd can scan */ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*================================================================*/ ++/* Types */ ++ ++/* Received frame statistics */ ++typedef struct p80211_frmrx_t ++{ ++ u32 mgmt; ++ u32 assocreq; ++ u32 assocresp; ++ u32 reassocreq; ++ u32 reassocresp; ++ u32 probereq; ++ u32 proberesp; ++ u32 beacon; ++ u32 atim; ++ u32 disassoc; ++ u32 authen; ++ u32 deauthen; ++ u32 mgmt_unknown; ++ u32 ctl; ++ u32 pspoll; ++ u32 rts; ++ u32 cts; ++ u32 ack; ++ u32 cfend; ++ u32 cfendcfack; ++ u32 ctl_unknown; ++ u32 data; ++ u32 dataonly; ++ u32 data_cfack; ++ u32 data_cfpoll; ++ u32 data__cfack_cfpoll; ++ u32 null; ++ u32 cfack; ++ u32 cfpoll; ++ u32 cfack_cfpoll; ++ u32 data_unknown; ++ u32 decrypt; ++ u32 decrypt_err; ++} p80211_frmrx_t; ++ ++/* called by /proc/net/wireless */ ++struct iw_statistics* p80211wext_get_wireless_stats(netdevice_t *dev); ++/* wireless extensions' ioctls */ ++int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd); ++extern struct iw_handler_def p80211wext_handler_def; ++int p80211wext_event_associated(struct wlandevice *wlandev, int assoc); ++ ++/* WEP stuff */ ++#define NUM_WEPKEYS 4 ++#define MAX_KEYLEN 32 ++ ++#define HOSTWEP_DEFAULTKEY_MASK (BIT1|BIT0) ++#define HOSTWEP_DECRYPT BIT4 ++#define HOSTWEP_ENCRYPT BIT5 ++#define HOSTWEP_PRIVACYINVOKED BIT6 ++#define HOSTWEP_EXCLUDEUNENCRYPTED BIT7 ++ ++extern int wlan_watchdog; ++extern int wlan_wext_write; ++ ++/* WLAN device type */ ++typedef struct wlandevice ++{ ++ struct wlandevice *next; /* link for list of devices */ ++ void *priv; /* private data for MSD */ ++ ++ /* Subsystem State */ ++ char name[WLAN_DEVNAMELEN_MAX]; /* Dev name, from register_wlandev()*/ ++ char *nsdname; ++ ++ u32 state; /* Device I/F state (open/closed) */ ++ u32 msdstate; /* state of underlying driver */ ++ u32 hwremoved; /* Has the hw been yanked out? */ ++ ++ /* Hardware config */ ++ unsigned int irq; ++ unsigned int iobase; ++ unsigned int membase; ++ u32 nsdcaps; /* NSD Capabilities flags */ ++ ++ /* Config vars */ ++ unsigned int ethconv; ++ ++ /* device methods (init by MSD, used by p80211 */ ++ int (*open)(struct wlandevice *wlandev); ++ int (*close)(struct wlandevice *wlandev); ++ void (*reset)(struct wlandevice *wlandev ); ++ int (*txframe)(struct wlandevice *wlandev, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); ++ int (*mlmerequest)(struct wlandevice *wlandev, p80211msg_t *msg); ++ int (*set_multicast_list)(struct wlandevice *wlandev, ++ netdevice_t *dev); ++ void (*tx_timeout)(struct wlandevice *wlandev); ++ ++ /* 802.11 State */ ++ u8 bssid[WLAN_BSSID_LEN]; ++ p80211pstr32_t ssid; ++ u32 macmode; ++ int linkstatus; ++ ++ /* WEP State */ ++ u8 wep_keys[NUM_WEPKEYS][MAX_KEYLEN]; ++ u8 wep_keylens[NUM_WEPKEYS]; ++ int hostwep; ++ ++ /* Request/Confirm i/f state (used by p80211) */ ++ unsigned long request_pending; /* flag, access atomically */ ++ ++ /* netlink socket */ ++ /* queue for indications waiting for cmd completion */ ++ /* Linux netdevice and support */ ++ netdevice_t *netdev; /* ptr to linux netdevice */ ++ struct net_device_stats linux_stats; ++ ++ /* Rx bottom half */ ++ struct tasklet_struct rx_bh; ++ ++ struct sk_buff_head nsd_rxq; ++ ++ /* 802.11 device statistics */ ++ struct p80211_frmrx_t rx; ++ ++ struct iw_statistics wstats; ++ ++ /* jkriegl: iwspy fields */ ++ u8 spy_number; ++ char spy_address[IW_MAX_SPY][ETH_ALEN]; ++ struct iw_quality spy_stat[IW_MAX_SPY]; ++} wlandevice_t; ++ ++/* WEP stuff */ ++int wep_change_key(wlandevice_t *wlandev, int keynum, u8* key, int keylen); ++int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *iv, u8 *icv); ++int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv); ++ ++void p80211netdev_startup(void); ++void p80211netdev_shutdown(void); ++int wlan_setup(wlandevice_t *wlandev); ++int wlan_unsetup(wlandevice_t *wlandev); ++int register_wlandev(wlandevice_t *wlandev); ++int unregister_wlandev(wlandevice_t *wlandev); ++void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb); ++void p80211netdev_hwremoved(wlandevice_t *wlandev); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211req.c +@@ -0,0 +1,300 @@ ++/* src/p80211/p80211req.c ++* ++* Request/Indication/MacMgmt interface handling functions ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file contains the functions, types, and macros to support the ++* MLME request interface that's implemented via the device ioctls. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wlan_compat.h" ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211mgmt.h" ++#include "p80211conv.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211ioctl.h" ++#include "p80211metadef.h" ++#include "p80211metastruct.h" ++#include "p80211req.h" ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++/* Maximum amount of time we'll wait for a request to complete */ ++#define P80211REQ_MAXTIME 3*HZ /* 3 seconds */ ++ ++/*================================================================*/ ++/* Local Macros */ ++ ++/*================================================================*/ ++/* Local Types */ ++ ++/*================================================================*/ ++/* Local Static Definitions */ ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++static void p80211req_handlemsg( wlandevice_t *wlandev, p80211msg_t *msg); ++static int p80211req_mibset_mibget(wlandevice_t *wlandev, p80211msg_dot11req_mibget_t *mib_msg, int isget); ++ ++/*================================================================*/ ++/* Function Definitions */ ++ ++ ++/*---------------------------------------------------------------- ++* p80211req_dorequest ++* ++* Handles an MLME reqest/confirm message. ++* ++* Arguments: ++* wlandev WLAN device struct ++* msgbuf Buffer containing a request message ++* ++* Returns: ++* 0 on success, an errno otherwise ++* ++* Call context: ++* Potentially blocks the caller, so it's a good idea to ++* not call this function from an interrupt context. ++----------------------------------------------------------------*/ ++int p80211req_dorequest( wlandevice_t *wlandev, u8 *msgbuf) ++{ ++ int result = 0; ++ p80211msg_t *msg = (p80211msg_t*)msgbuf; ++ ++ DBFENTER; ++ ++ /* Check to make sure the MSD is running */ ++ if ( ++ !((wlandev->msdstate == WLAN_MSD_HWPRESENT && ++ msg->msgcode == DIDmsg_lnxreq_ifstate) || ++ wlandev->msdstate == WLAN_MSD_RUNNING || ++ wlandev->msdstate == WLAN_MSD_FWLOAD) ) { ++ return -ENODEV; ++ } ++ ++ /* Check Permissions */ ++ if (!capable(CAP_NET_ADMIN) && ++ (msg->msgcode != DIDmsg_dot11req_mibget)) { ++ WLAN_LOG_ERROR("%s: only dot11req_mibget allowed for non-root.\n", wlandev->name); ++ return -EPERM; ++ } ++ ++ /* Check for busy status */ ++ if ( test_and_set_bit(1, &(wlandev->request_pending))) { ++ return -EBUSY; ++ } ++ ++ /* Allow p80211 to look at msg and handle if desired. */ ++ /* So far, all p80211 msgs are immediate, no waitq/timer necessary */ ++ /* This may change. */ ++ p80211req_handlemsg(wlandev, msg); ++ ++ /* Pass it down to wlandev via wlandev->mlmerequest */ ++ if ( wlandev->mlmerequest != NULL ) ++ wlandev->mlmerequest(wlandev, msg); ++ ++ clear_bit( 1, &(wlandev->request_pending)); ++ DBFEXIT; ++ return result; /* if result==0, msg->status still may contain an err */ ++} ++ ++/*---------------------------------------------------------------- ++* p80211req_handlemsg ++* ++* p80211 message handler. Primarily looks for messages that ++* belong to p80211 and then dispatches the appropriate response. ++* TODO: we don't do anything yet. Once the linuxMIB is better ++* defined we'll need a get/set handler. ++* ++* Arguments: ++* wlandev WLAN device struct ++* msg message structure ++* ++* Returns: ++* nothing (any results are set in the status field of the msg) ++* ++* Call context: ++* Process thread ++----------------------------------------------------------------*/ ++static void p80211req_handlemsg( wlandevice_t *wlandev, p80211msg_t *msg) ++{ ++ DBFENTER; ++ ++ switch (msg->msgcode) { ++ ++ case DIDmsg_lnxreq_hostwep: { ++ p80211msg_lnxreq_hostwep_t *req = (p80211msg_lnxreq_hostwep_t*) msg; ++ wlandev->hostwep &= ~(HOSTWEP_DECRYPT|HOSTWEP_ENCRYPT); ++ if (req->decrypt.data == P80211ENUM_truth_true) ++ wlandev->hostwep |= HOSTWEP_DECRYPT; ++ if (req->encrypt.data == P80211ENUM_truth_true) ++ wlandev->hostwep |= HOSTWEP_ENCRYPT; ++ ++ break; ++ } ++ case DIDmsg_dot11req_mibget: ++ case DIDmsg_dot11req_mibset: { ++ int isget = (msg->msgcode == DIDmsg_dot11req_mibget); ++ p80211msg_dot11req_mibget_t *mib_msg = (p80211msg_dot11req_mibget_t *) msg; ++ p80211req_mibset_mibget (wlandev, mib_msg, isget); ++ } ++ default: ++ // XXX do nothing! ++ ; ++ } /* switch msg->msgcode */ ++ ++ DBFEXIT; ++ ++ return; ++} ++ ++static int p80211req_mibset_mibget(wlandevice_t *wlandev, ++ p80211msg_dot11req_mibget_t *mib_msg, ++ int isget) ++{ ++ p80211itemd_t *mibitem = (p80211itemd_t *) mib_msg->mibattribute.data; ++ p80211pstrd_t *pstr = (p80211pstrd_t*) mibitem->data; ++ u8 *key = mibitem->data + sizeof(p80211pstrd_t); ++ ++ DBFENTER; ++ ++ switch (mibitem->did) { ++ case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0: { ++ if (!isget) ++ wep_change_key(wlandev, 0, key, pstr->len); ++ break; ++ } ++ case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1: { ++ if (!isget) ++ wep_change_key(wlandev, 1, key, pstr->len); ++ break; ++ } ++ case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2: { ++ if (!isget) ++ wep_change_key(wlandev, 2, key, pstr->len); ++ break; ++ } ++ case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3: { ++ if (!isget) ++ wep_change_key(wlandev, 3, key, pstr->len); ++ break; ++ } ++ case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID: { ++ u32 *data = (u32 *) mibitem->data; ++ ++ if (isget) { ++ *data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; ++ } else { ++ wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK); ++ ++ wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK); ++ } ++ break; ++ } ++ case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked: { ++ u32 *data = (u32 *) mibitem->data; ++ ++ if (isget) { ++ if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) ++ *data = P80211ENUM_truth_true; ++ else ++ *data = P80211ENUM_truth_false; ++ } else { ++ wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED); ++ if (*data == P80211ENUM_truth_true) ++ wlandev->hostwep |= HOSTWEP_PRIVACYINVOKED; ++ } ++ break; ++ } ++ case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted: { ++ u32 *data = (u32 *) mibitem->data; ++ ++ if (isget) { ++ if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) ++ *data = P80211ENUM_truth_true; ++ else ++ *data = P80211ENUM_truth_false; ++ } else { ++ wlandev->hostwep &= ~(HOSTWEP_EXCLUDEUNENCRYPTED); ++ if (*data == P80211ENUM_truth_true) ++ wlandev->hostwep |= HOSTWEP_EXCLUDEUNENCRYPTED; ++ } ++ break; ++ } ++ default: ++ // XXXX do nothing! ++ ; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211req.h +@@ -0,0 +1,68 @@ ++/* p80211req.h ++* ++* Request handling functions ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _LINUX_P80211REQ_H ++#define _LINUX_P80211REQ_H ++ ++/*================================================================*/ ++/* Constants */ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*================================================================*/ ++/* Types */ ++ ++/*================================================================*/ ++/* Externs */ ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++int p80211req_dorequest(wlandevice_t *wlandev, u8 *msgbuf); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211types.h +@@ -0,0 +1,675 @@ ++/* p80211types.h ++* ++* Macros, constants, types, and funcs for p80211 data types ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file declares some of the constants and types used in various ++* parts of the linux-wlan system. ++* ++* Notes: ++* - Constant values are always in HOST byte order. ++* ++* All functions and statics declared here are implemented in p80211types.c ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _P80211TYPES_H ++#define _P80211TYPES_H ++ ++/*================================================================*/ ++/* System Includes */ ++/*================================================================*/ ++ ++/*================================================================*/ ++/* Project Includes */ ++/*================================================================*/ ++ ++#ifndef _WLAN_COMPAT_H ++#include "wlan_compat.h" ++#endif ++ ++/*================================================================*/ ++/* Constants */ ++/*================================================================*/ ++ ++/*----------------------------------------------------------------*/ ++/* p80211 data type codes used for MIB items and message */ ++/* arguments. The various metadata structures provide additional */ ++/* information about these types. */ ++ ++#define P80211_TYPE_OCTETSTR 1 /* pascal array of bytes */ ++#define P80211_TYPE_DISPLAYSTR 2 /* pascal array of bytes containing ascii */ ++#define P80211_TYPE_int 4 /* u32 min and max limited by 32 bits */ ++#define P80211_TYPE_ENUMint 5 /* u32 holding a numeric ++ code that can be mapped ++ to a textual name */ ++#define P80211_TYPE_UNKDATA 6 /* Data item containing an ++ unknown data type */ ++#define P80211_TYPE_intARRAY 7 /* Array of 32-bit integers. */ ++#define P80211_TYPE_BITARRAY 8 /* Array of bits. */ ++#define P80211_TYPE_MACARRAY 9 /* Array of MAC addresses. */ ++ ++/*----------------------------------------------------------------*/ ++/* The following constants are indexes into the Mib Category List */ ++/* and the Message Category List */ ++ ++/* Mib Category List */ ++#define P80211_MIB_CAT_DOT11SMT 1 ++#define P80211_MIB_CAT_DOT11MAC 2 ++#define P80211_MIB_CAT_DOT11PHY 3 ++ ++#define P80211SEC_DOT11SMT P80211_MIB_CAT_DOT11SMT ++#define P80211SEC_DOT11MAC P80211_MIB_CAT_DOT11MAC ++#define P80211SEC_DOT11PHY P80211_MIB_CAT_DOT11PHY ++ ++/* Message Category List */ ++#define P80211_MSG_CAT_DOT11REQ 1 ++#define P80211_MSG_CAT_DOT11IND 2 ++/* #define P80211_MSG_CAT_DOT11CFM 3 (doesn't exist at this time) */ ++ ++#define P80211SEC_DOT11REQ P80211_MSG_CAT_DOT11REQ ++#define P80211SEC_DOT11IND P80211_MSG_CAT_DOT11IND ++/* #define P80211SEC_DOT11CFM P80211_MSG_CAT_DOT11CFM (doesn't exist at this time */ ++ ++ ++ ++/*----------------------------------------------------------------*/ ++/* p80211 DID field codes that represent access type and */ ++/* is_table status. */ ++ ++#define P80211DID_ACCESS_READ 0x10000000 ++#define P80211DID_ACCESS_WRITE 0x08000000 ++#define P80211DID_WRITEONLY 0x00000001 ++#define P80211DID_READONLY 0x00000002 ++#define P80211DID_READWRITE 0x00000003 ++#define P80211DID_ISTABLE_FALSE 0 ++#define P80211DID_ISTABLE_TRUE 1 ++ ++/*----------------------------------------------------------------*/ ++/* p80211 enumeration constants. The value to text mappings for */ ++/* these is in p80211types.c. These defines were generated */ ++/* from the mappings. */ ++ ++/* error codes for lookups */ ++#define P80211ENUM_BAD 0xffffffffUL ++#define P80211ENUM_BADSTR "P80211ENUM_BAD" ++ ++#define P80211ENUM_truth_false 0 ++#define P80211ENUM_truth_true 1 ++#define P80211ENUM_ifstate_disable 0 ++#define P80211ENUM_ifstate_fwload 1 ++#define P80211ENUM_ifstate_enable 2 ++#define P80211ENUM_powermgmt_active 1 ++#define P80211ENUM_powermgmt_powersave 2 ++#define P80211ENUM_bsstype_infrastructure 1 ++#define P80211ENUM_bsstype_independent 2 ++#define P80211ENUM_bsstype_any 3 ++#define P80211ENUM_authalg_opensystem 1 ++#define P80211ENUM_authalg_sharedkey 2 ++#define P80211ENUM_phytype_fhss 1 ++#define P80211ENUM_phytype_dsss 2 ++#define P80211ENUM_phytype_irbaseband 3 ++#define P80211ENUM_temptype_commercial 1 ++#define P80211ENUM_temptype_industrial 2 ++#define P80211ENUM_regdomain_fcc 16 ++#define P80211ENUM_regdomain_doc 32 ++#define P80211ENUM_regdomain_etsi 48 ++#define P80211ENUM_regdomain_spain 49 ++#define P80211ENUM_regdomain_france 50 ++#define P80211ENUM_regdomain_mkk 64 ++#define P80211ENUM_ccamode_edonly 1 ++#define P80211ENUM_ccamode_csonly 2 ++#define P80211ENUM_ccamode_edandcs 4 ++#define P80211ENUM_ccamode_cswithtimer 8 ++#define P80211ENUM_ccamode_hrcsanded 16 ++#define P80211ENUM_diversity_fixedlist 1 ++#define P80211ENUM_diversity_notsupported 2 ++#define P80211ENUM_diversity_dynamic 3 ++#define P80211ENUM_scantype_active 1 ++#define P80211ENUM_scantype_passive 2 ++#define P80211ENUM_scantype_both 3 ++#define P80211ENUM_resultcode_success 1 ++#define P80211ENUM_resultcode_invalid_parameters 2 ++#define P80211ENUM_resultcode_not_supported 3 ++#define P80211ENUM_resultcode_timeout 4 ++#define P80211ENUM_resultcode_too_many_req 5 ++#define P80211ENUM_resultcode_refused 6 ++#define P80211ENUM_resultcode_bss_already 7 ++#define P80211ENUM_resultcode_invalid_access 8 ++#define P80211ENUM_resultcode_invalid_mibattribute 9 ++#define P80211ENUM_resultcode_cant_set_readonly_mib 10 ++#define P80211ENUM_resultcode_implementation_failure 11 ++#define P80211ENUM_resultcode_cant_get_writeonly_mib 12 ++#define P80211ENUM_reason_unspec_reason 1 ++#define P80211ENUM_reason_auth_not_valid 2 ++#define P80211ENUM_reason_deauth_lv_ss 3 ++#define P80211ENUM_reason_inactivity 4 ++#define P80211ENUM_reason_ap_overload 5 ++#define P80211ENUM_reason_class23_err 6 ++#define P80211ENUM_reason_class3_err 7 ++#define P80211ENUM_reason_disas_lv_ss 8 ++#define P80211ENUM_reason_asoc_not_auth 9 ++#define P80211ENUM_status_successful 0 ++#define P80211ENUM_status_unspec_failure 1 ++#define P80211ENUM_status_unsup_cap 10 ++#define P80211ENUM_status_reasoc_no_asoc 11 ++#define P80211ENUM_status_fail_other 12 ++#define P80211ENUM_status_unspt_alg 13 ++#define P80211ENUM_status_auth_seq_fail 14 ++#define P80211ENUM_status_chlng_fail 15 ++#define P80211ENUM_status_auth_timeout 16 ++#define P80211ENUM_status_ap_full 17 ++#define P80211ENUM_status_unsup_rate 18 ++#define P80211ENUM_status_unsup_shortpreamble 19 ++#define P80211ENUM_status_unsup_pbcc 20 ++#define P80211ENUM_status_unsup_agility 21 ++#define P80211ENUM_msgitem_status_data_ok 0 ++#define P80211ENUM_msgitem_status_no_value 1 ++#define P80211ENUM_msgitem_status_invalid_itemname 2 ++#define P80211ENUM_msgitem_status_invalid_itemdata 3 ++#define P80211ENUM_msgitem_status_missing_itemdata 4 ++#define P80211ENUM_msgitem_status_incomplete_itemdata 5 ++#define P80211ENUM_msgitem_status_invalid_msg_did 6 ++#define P80211ENUM_msgitem_status_invalid_mib_did 7 ++#define P80211ENUM_msgitem_status_missing_conv_func 8 ++#define P80211ENUM_msgitem_status_string_too_long 9 ++#define P80211ENUM_msgitem_status_data_out_of_range 10 ++#define P80211ENUM_msgitem_status_string_too_short 11 ++#define P80211ENUM_msgitem_status_missing_valid_func 12 ++#define P80211ENUM_msgitem_status_unknown 13 ++#define P80211ENUM_msgitem_status_invalid_did 14 ++#define P80211ENUM_msgitem_status_missing_print_func 15 ++ ++#define P80211ENUM_lnxroam_reason_unknown 0 ++#define P80211ENUM_lnxroam_reason_beacon 1 ++#define P80211ENUM_lnxroam_reason_signal 2 ++#define P80211ENUM_lnxroam_reason_txretry 3 ++#define P80211ENUM_lnxroam_reason_notjoined 4 ++ ++#define P80211ENUM_p2preamble_long 0 ++#define P80211ENUM_p2preamble_short 2 ++#define P80211ENUM_p2preamble_mixed 3 ++ ++/*----------------------------------------------------------------*/ ++/* p80211 max length constants for the different pascal strings. */ ++ ++#define MAXLEN_PSTR6 (6) /* pascal array of 6 bytes */ ++#define MAXLEN_PSTR14 (14) /* pascal array of 14 bytes */ ++#define MAXLEN_PSTR32 (32) /* pascal array of 32 bytes */ ++#define MAXLEN_PSTR255 (255) /* pascal array of 255 bytes */ ++#define MAXLEN_MIBATTRIBUTE (392) /* maximum mibattribute */ ++ /* where the size of the DATA itself */ ++ /* is a DID-LEN-DATA triple */ ++ /* with a max size of 4+4+384 */ ++ ++#define P80211_SET_int(item, value) do { \ ++ (item).data = (value); \ ++ (item).status = P80211ENUM_msgitem_status_data_ok; \ ++ } while(0) ++/*----------------------------------------------------------------*/ ++/* string constants */ ++ ++#define NOT_SET "NOT_SET" ++#define NOT_SUPPORTED "NOT_SUPPORTED" ++#define UNKNOWN_DATA "UNKNOWN_DATA" ++ ++ ++/*--------------------------------------------------------------------*/ ++/* Metadata flags */ ++ ++/* MSM: Do these belong in p80211meta.h? I'm not sure. */ ++ ++#define ISREQUIRED (0x80000000UL) ++#define ISREQUEST (0x40000000UL) ++#define ISCONFIRM (0x20000000UL) ++ ++ ++/*================================================================*/ ++/* Macros */ ++ ++/*--------------------------------------------------------------------*/ ++/* The following macros are used to manipulate the 'flags' field in */ ++/* the metadata. These are only used when the metadata is for */ ++/* command arguments to determine if the data item is required, and */ ++/* whether the metadata item is for a request command, confirm */ ++/* command or both. */ ++/*--------------------------------------------------------------------*/ ++/* MSM: Do these belong in p80211meta.h? I'm not sure */ ++ ++#define P80211ITEM_SETFLAGS(q, r, c) ( q | r | c ) ++ ++#define P80211ITEM_ISREQUIRED(flags) (((u32)(flags & ISREQUIRED)) >> 31 ) ++#define P80211ITEM_ISREQUEST(flags) (((u32)(flags & ISREQUEST)) >> 30 ) ++#define P80211ITEM_ISCONFIRM(flags) (((u32)(flags & ISCONFIRM)) >> 29 ) ++ ++/*----------------------------------------------------------------*/ ++/* The following macro creates a name for an enum */ ++ ++#define MKENUMNAME(name) p80211enum_ ## name ++ ++/*---------------------------------------------------------------- ++* The following constants and macros are used to construct and ++* deconstruct the Data ID codes. The coding is as follows: ++* ++* ...rwtnnnnnnnniiiiiiggggggssssss s - Section ++* g - Group ++* i - Item ++* n - Index ++* t - Table flag ++* w - Write flag ++* r - Read flag ++* . - Unused ++*/ ++ ++#define P80211DID_INVALID 0xffffffffUL ++#define P80211DID_VALID 0x00000000UL ++ ++#define P80211DID_LSB_SECTION (0) ++#define P80211DID_LSB_GROUP (6) ++#define P80211DID_LSB_ITEM (12) ++#define P80211DID_LSB_INDEX (18) ++#define P80211DID_LSB_ISTABLE (26) ++#define P80211DID_LSB_ACCESS (27) ++ ++#define P80211DID_MASK_SECTION (0x0000003fUL) ++#define P80211DID_MASK_GROUP (0x0000003fUL) ++#define P80211DID_MASK_ITEM (0x0000003fUL) ++#define P80211DID_MASK_INDEX (0x000000ffUL) ++#define P80211DID_MASK_ISTABLE (0x00000001UL) ++#define P80211DID_MASK_ACCESS (0x00000003UL) ++ ++ ++#define P80211DID_MK(a,m,l) ((((u32)(a)) & (m)) << (l)) ++ ++#define P80211DID_MKSECTION(a) P80211DID_MK(a, \ ++ P80211DID_MASK_SECTION, \ ++ P80211DID_LSB_SECTION ) ++#define P80211DID_MKGROUP(a) P80211DID_MK(a, \ ++ P80211DID_MASK_GROUP, \ ++ P80211DID_LSB_GROUP ) ++#define P80211DID_MKITEM(a) P80211DID_MK(a, \ ++ P80211DID_MASK_ITEM, \ ++ P80211DID_LSB_ITEM ) ++#define P80211DID_MKINDEX(a) P80211DID_MK(a, \ ++ P80211DID_MASK_INDEX, \ ++ P80211DID_LSB_INDEX ) ++#define P80211DID_MKISTABLE(a) P80211DID_MK(a, \ ++ P80211DID_MASK_ISTABLE, \ ++ P80211DID_LSB_ISTABLE ) ++ ++ ++#define P80211DID_MKID(s,g,i,n,t,a) (P80211DID_MKSECTION(s) | \ ++ P80211DID_MKGROUP(g) | \ ++ P80211DID_MKITEM(i) | \ ++ P80211DID_MKINDEX(n) | \ ++ P80211DID_MKISTABLE(t) | \ ++ (a) ) ++ ++ ++#define P80211DID_GET(a,m,l) ((((u32)(a)) >> (l)) & (m)) ++ ++#define P80211DID_SECTION(a) P80211DID_GET(a, \ ++ P80211DID_MASK_SECTION, \ ++ P80211DID_LSB_SECTION) ++#define P80211DID_GROUP(a) P80211DID_GET(a, \ ++ P80211DID_MASK_GROUP, \ ++ P80211DID_LSB_GROUP) ++#define P80211DID_ITEM(a) P80211DID_GET(a, \ ++ P80211DID_MASK_ITEM, \ ++ P80211DID_LSB_ITEM) ++#define P80211DID_INDEX(a) P80211DID_GET(a, \ ++ P80211DID_MASK_INDEX, \ ++ P80211DID_LSB_INDEX) ++#define P80211DID_ISTABLE(a) P80211DID_GET(a, \ ++ P80211DID_MASK_ISTABLE, \ ++ P80211DID_LSB_ISTABLE) ++#define P80211DID_ACCESS(a) P80211DID_GET(a, \ ++ P80211DID_MASK_ACCESS, \ ++ P80211DID_LSB_ACCESS) ++ ++/*================================================================*/ ++/* Types */ ++ ++/*----------------------------------------------------------------*/ ++/* The following structure types are used for the represenation */ ++/* of ENUMint type metadata. */ ++ ++typedef struct p80211enumpair ++{ ++ u32 val; ++ char *name; ++} p80211enumpair_t; ++ ++typedef struct p80211enum ++{ ++ int nitems; ++ p80211enumpair_t *list; ++} p80211enum_t; ++ ++/*----------------------------------------------------------------*/ ++/* The following structure types are used to store data items in */ ++/* messages. */ ++ ++/* Template pascal string */ ++typedef struct p80211pstr ++{ ++ u8 len; ++} __WLAN_ATTRIB_PACK__ p80211pstr_t; ++ ++typedef struct p80211pstrd ++{ ++ u8 len; ++ u8 data[0]; ++} __WLAN_ATTRIB_PACK__ p80211pstrd_t; ++ ++/* Maximum pascal string */ ++typedef struct p80211pstr255 ++{ ++ u8 len; ++ u8 data[MAXLEN_PSTR255]; ++} __WLAN_ATTRIB_PACK__ p80211pstr255_t; ++ ++/* pascal string for macaddress and bssid */ ++typedef struct p80211pstr6 ++{ ++ u8 len; ++ u8 data[MAXLEN_PSTR6]; ++} __WLAN_ATTRIB_PACK__ p80211pstr6_t; ++ ++/* pascal string for channel list */ ++typedef struct p80211pstr14 ++{ ++ u8 len; ++ u8 data[MAXLEN_PSTR14]; ++} __WLAN_ATTRIB_PACK__ p80211pstr14_t; ++ ++/* pascal string for ssid */ ++typedef struct p80211pstr32 ++{ ++ u8 len; ++ u8 data[MAXLEN_PSTR32]; ++} __WLAN_ATTRIB_PACK__ p80211pstr32_t; ++ ++/* MAC address array */ ++typedef struct p80211macarray ++{ ++ u32 cnt; ++ u8 data[1][MAXLEN_PSTR6]; ++} __WLAN_ATTRIB_PACK__ p80211macarray_t; ++ ++/* prototype template */ ++typedef struct p80211item ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++} __WLAN_ATTRIB_PACK__ p80211item_t; ++ ++/* prototype template w/ data item */ ++typedef struct p80211itemd ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ u8 data[0]; ++} __WLAN_ATTRIB_PACK__ p80211itemd_t; ++ ++/* message data item for int, BOUNDEDINT, ENUMINT */ ++typedef struct p80211item_uint32 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ u32 data; ++} __WLAN_ATTRIB_PACK__ p80211item_uint32_t; ++ ++/* message data item for OCTETSTR, DISPLAYSTR */ ++typedef struct p80211item_pstr6 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ p80211pstr6_t data; ++} __WLAN_ATTRIB_PACK__ p80211item_pstr6_t; ++ ++/* message data item for OCTETSTR, DISPLAYSTR */ ++typedef struct p80211item_pstr14 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ p80211pstr14_t data; ++} __WLAN_ATTRIB_PACK__ p80211item_pstr14_t; ++ ++/* message data item for OCTETSTR, DISPLAYSTR */ ++typedef struct p80211item_pstr32 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ p80211pstr32_t data; ++} __WLAN_ATTRIB_PACK__ p80211item_pstr32_t; ++ ++/* message data item for OCTETSTR, DISPLAYSTR */ ++typedef struct p80211item_pstr255 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ p80211pstr255_t data; ++} __WLAN_ATTRIB_PACK__ p80211item_pstr255_t; ++ ++/* message data item for UNK 392, namely mib items */ ++typedef struct p80211item_unk392 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ u8 data[MAXLEN_MIBATTRIBUTE]; ++} __WLAN_ATTRIB_PACK__ p80211item_unk392_t; ++ ++/* message data item for UNK 1025, namely p2 pdas */ ++typedef struct p80211item_unk1024 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ u8 data[1024]; ++} __WLAN_ATTRIB_PACK__ p80211item_unk1024_t; ++ ++/* message data item for UNK 4096, namely p2 download chunks */ ++typedef struct p80211item_unk4096 ++{ ++ u32 did; ++ u16 status; ++ u16 len; ++ u8 data[4096]; ++} __WLAN_ATTRIB_PACK__ p80211item_unk4096_t; ++ ++struct catlistitem; ++ ++/*----------------------------------------------------------------*/ ++/* The following structure type is used to represent all of the */ ++/* metadata items. Some components may choose to use more, */ ++/* less or different metadata items. */ ++ ++typedef void (*p80211_totext_t)( struct catlistitem *, u32 did, u8* itembuf, char *textbuf); ++typedef void (*p80211_fromtext_t)( struct catlistitem *, u32 did, u8* itembuf, char *textbuf); ++typedef u32 (*p80211_valid_t)( struct catlistitem *, u32 did, u8* itembuf); ++ ++ ++/*================================================================*/ ++/* Extern Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* Enumeration Lists */ ++/* The following are the external declarations */ ++/* for all enumerations */ ++ ++extern p80211enum_t MKENUMNAME(truth); ++extern p80211enum_t MKENUMNAME(ifstate); ++extern p80211enum_t MKENUMNAME(powermgmt); ++extern p80211enum_t MKENUMNAME(bsstype); ++extern p80211enum_t MKENUMNAME(authalg); ++extern p80211enum_t MKENUMNAME(phytype); ++extern p80211enum_t MKENUMNAME(temptype); ++extern p80211enum_t MKENUMNAME(regdomain); ++extern p80211enum_t MKENUMNAME(ccamode); ++extern p80211enum_t MKENUMNAME(diversity); ++extern p80211enum_t MKENUMNAME(scantype); ++extern p80211enum_t MKENUMNAME(resultcode); ++extern p80211enum_t MKENUMNAME(reason); ++extern p80211enum_t MKENUMNAME(status); ++extern p80211enum_t MKENUMNAME(msgcode); ++extern p80211enum_t MKENUMNAME(msgitem_status); ++ ++extern p80211enum_t MKENUMNAME(lnxroam_reason); ++ ++extern p80211enum_t MKENUMNAME(p2preamble); ++ ++/*================================================================*/ ++/* Function Declarations */ ++ ++/*----------------------------------------------------------------*/ ++/* The following declare some utility functions for use with the */ ++/* p80211enum_t type. */ ++ ++u32 p80211enum_text2int(p80211enum_t *ep, char *text); ++u32 p80211enum_int2text(p80211enum_t *ep, u32 val, char *text); ++void p80211_error2text(int err_code, char *err_str); ++ ++/*----------------------------------------------------------------*/ ++/* The following declare some utility functions for use with the */ ++/* p80211item_t and p80211meta_t types. */ ++ ++/*----------------------------------------------------------------*/ ++/* The following declare functions that perform validation and */ ++/* text to binary conversions based on the metadata for interface */ ++/* and MIB data items. */ ++/*----------------------------------------------------------------*/ ++ ++/*-- DISPLAYSTR ------------------------------------------------------*/ ++/* pstr ==> cstr */ ++void p80211_totext_displaystr( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* cstr ==> pstr */ ++void p80211_fromtext_displaystr( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of a displaystr binary value */ ++u32 p80211_isvalid_displaystr( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- OCTETSTR --------------------------------------------------------*/ ++/* pstr ==> "xx:xx:...." */ ++void p80211_totext_octetstr( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* "xx:xx:...." ==> pstr */ ++void p80211_fromtext_octetstr( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of an octetstr binary value */ ++u32 p80211_isvalid_octetstr( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- int -------------------------------------------------------------*/ ++/* u32 ==> %d */ ++void p80211_totext_int( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* %d ==> u32 */ ++void p80211_fromtext_int( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of an int's binary value (always successful) */ ++u32 p80211_isvalid_int( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- ENUMint ---------------------------------------------------------*/ ++/* u32 ==> */ ++void p80211_totext_enumint( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* ==> u32 */ ++void p80211_fromtext_enumint( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of an enum's binary value */ ++u32 p80211_isvalid_enumint( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- intARRAY --------------------------------------------------------*/ ++/* u32[] => %d,%d,%d,... */ ++void p80211_totext_intarray( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* %d,%d,%d,... ==> u32[] */ ++void p80211_fromtext_intarray( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of an integer array's value */ ++u32 p80211_isvalid_intarray( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- BITARRAY --------------------------------------------------------*/ ++/* u32 ==> %d,%d,%d,... */ ++void p80211_totext_bitarray( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* %d,%d,%d,... ==> u32 */ ++void p80211_fromtext_bitarray( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of a bit array's value */ ++u32 p80211_isvalid_bitarray( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- MACARRAY --------------------------------------------------------*/ ++void p80211_totext_macarray( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++void p80211_fromtext_macarray( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of a MAC address array's value */ ++u32 p80211_isvalid_macarray( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++/*-- MIBATTRIUBTE ------------------------------------------------------*/ ++/* ==> */ ++void p80211_totext_getmibattribute( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++void p80211_totext_setmibattribute( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++ ++/* ==> */ ++void p80211_fromtext_getmibattribute( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++void p80211_fromtext_setmibattribute( struct catlistitem *metalist, u32 did, u8 *itembuf, char *textbuf ); ++ ++/* function that checks validity of a mibitem's binary value */ ++u32 p80211_isvalid_getmibattribute( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++u32 p80211_isvalid_setmibattribute( struct catlistitem *metalist, u32 did, u8 *itembuf ); ++ ++#endif /* _P80211TYPES_H */ ++ +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211wep.c +@@ -0,0 +1,315 @@ ++/* src/p80211/p80211wep.c ++* ++* WEP encode/decode for P80211. ++* ++* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "wlan_compat.h" ++ ++// #define WEP_DEBUG ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211hdr.h" ++#include "p80211types.h" ++#include "p80211msg.h" ++#include "p80211conv.h" ++#include "p80211netdev.h" ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++#define SSWAP(a,b) {u8 tmp = s[a]; s[a] = s[b]; s[b] = tmp;} ++#define WEP_KEY(x) (((x) & 0xC0) >> 6) ++ ++/*================================================================*/ ++/* Local Macros */ ++ ++ ++/*================================================================*/ ++/* Local Types */ ++ ++ ++/*================================================================*/ ++/* Local Static Definitions */ ++ ++static const u32 wep_crc32_table[256] = { ++ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, ++ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, ++ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, ++ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, ++ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, ++ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, ++ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, ++ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, ++ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, ++ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, ++ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, ++ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, ++ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, ++ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, ++ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, ++ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, ++ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, ++ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, ++ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, ++ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, ++ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, ++ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, ++ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, ++ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, ++ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, ++ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, ++ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, ++ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, ++ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, ++ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, ++ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, ++ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, ++ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, ++ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, ++ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, ++ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, ++ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, ++ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, ++ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, ++ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, ++ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, ++ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, ++ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, ++ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, ++ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, ++ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, ++ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, ++ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, ++ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, ++ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, ++ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, ++ 0x2d02ef8dL ++}; ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++/*================================================================*/ ++/* Function Definitions */ ++ ++/* keylen in bytes! */ ++ ++int wep_change_key(wlandevice_t *wlandev, int keynum, u8* key, int keylen) ++{ ++ if (keylen < 0) return -1; ++ if (keylen >= MAX_KEYLEN) return -1; ++ if (key == NULL) return -1; ++ if (keynum < 0) return -1; ++ if (keynum >= NUM_WEPKEYS) return -1; ++ ++ ++#ifdef WEP_DEBUG ++ printk(KERN_DEBUG "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); ++#endif ++ ++ wlandev->wep_keylens[keynum] = keylen; ++ memcpy(wlandev->wep_keys[keynum], key, keylen); ++ ++ return 0; ++} ++ ++/* ++ 4-byte IV at start of buffer, 4-byte ICV at end of buffer. ++ if successful, buf start is payload begin, length -= 8; ++ */ ++int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, u8 *iv, u8 *icv) ++{ ++ u32 i, j, k, crc, keylen; ++ u8 s[256], key[64], c_crc[4]; ++ u8 keyidx; ++ ++ /* Needs to be at least 8 bytes of payload */ ++ if (len <= 0) return -1; ++ ++ /* initialize the first bytes of the key from the IV */ ++ key[0] = iv[0]; ++ key[1] = iv[1]; ++ key[2] = iv[2]; ++ keyidx = WEP_KEY(iv[3]); ++ ++ if (key_override >= 0) ++ keyidx = key_override; ++ ++ if (keyidx >= NUM_WEPKEYS) return -2; ++ ++ keylen = wlandev->wep_keylens[keyidx]; ++ ++ if (keylen == 0) return -3; ++ ++ /* copy the rest of the key over from the designated key */ ++ memcpy(key+3, wlandev->wep_keys[keyidx], keylen); ++ ++ keylen+=3; /* add in IV bytes */ ++ ++#ifdef WEP_DEBUG ++ printk(KERN_DEBUG "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], key[6], key[7]); ++#endif ++ ++ /* set up the RC4 state */ ++ for (i = 0; i < 256; i++) ++ s[i] = i; ++ j = 0; ++ for (i = 0; i < 256; i++) { ++ j = (j + s[i] + key[i % keylen]) & 0xff; ++ SSWAP(i,j); ++ } ++ ++ /* Apply the RC4 to the data, update the CRC32 */ ++ crc = ~0; ++ i = j = 0; ++ for (k = 0; k < len; k++) { ++ i = (i+1) & 0xff; ++ j = (j+s[i]) & 0xff; ++ SSWAP(i,j); ++ buf[k] ^= s[(s[i] + s[j]) & 0xff]; ++ crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); ++ } ++ crc = ~crc; ++ ++ /* now let's check the crc */ ++ c_crc[0] = crc; ++ c_crc[1] = crc >> 8; ++ c_crc[2] = crc >> 16; ++ c_crc[3] = crc >> 24; ++ ++ for (k = 0; k < 4; k++) { ++ i = (i + 1) & 0xff; ++ j = (j+s[i]) & 0xff; ++ SSWAP(i,j); ++ if ((c_crc[k] ^ s[(s[i] + s[j]) & 0xff]) != icv[k]) ++ return -(4 | (k << 4)) ; /* ICV mismatch */ ++ } ++ ++ return 0; ++} ++ ++/* encrypts in-place. */ ++int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv) ++{ ++ u32 i, j, k, crc, keylen; ++ u8 s[256], key[64]; ++ ++ /* no point in WEPping an empty frame */ ++ if (len <= 0) return -1; ++ ++ /* we need to have a real key.. */ ++ if (keynum >= NUM_WEPKEYS) return -2; ++ keylen = wlandev->wep_keylens[keynum]; ++ if (keylen <= 0) return -3; ++ ++ /* use a random IV. And skip known weak ones. */ ++ get_random_bytes(iv, 3); ++ while ((iv[1] == 0xff) && (iv[0] >= 3) && (iv[0] < keylen)) ++ get_random_bytes(iv, 3); ++ ++ iv[3] = (keynum & 0x03) << 6; ++ ++ key[0] = iv[0]; ++ key[1] = iv[1]; ++ key[2] = iv[2]; ++ ++ /* copy the rest of the key over from the designated key */ ++ memcpy(key+3, wlandev->wep_keys[keynum], keylen); ++ ++ keylen+=3; /* add in IV bytes */ ++ ++#ifdef WEP_DEBUG ++ printk(KERN_DEBUG "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len, iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); ++#endif ++ ++ /* set up the RC4 state */ ++ for (i = 0; i < 256; i++) ++ s[i] = i; ++ j = 0; ++ for (i = 0; i < 256; i++) { ++ j = (j + s[i] + key[i % keylen]) & 0xff; ++ SSWAP(i,j); ++ } ++ ++ /* Update CRC32 then apply RC4 to the data */ ++ crc = ~0; ++ i = j = 0; ++ for (k = 0; k < len; k++) { ++ crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); ++ i = (i+1) & 0xff; ++ j = (j+s[i]) & 0xff; ++ SSWAP(i,j); ++ dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff]; ++ } ++ crc = ~crc; ++ ++ /* now let's encrypt the crc */ ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++ for (k = 0; k < 4; k++) { ++ i = (i + 1) & 0xff; ++ j = (j+s[i]) & 0xff; ++ SSWAP(i,j); ++ icv[k] ^= s[(s[i] + s[j]) & 0xff]; ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/staging/wlan-ng/p80211wext.c +@@ -0,0 +1,1826 @@ ++/* src/p80211/p80211wext.c ++* ++* Glue code to make linux-wlan-ng a happy wireless extension camper. ++* ++* original author: Reyk Floeter ++* Completely re-written by Solomon Peachy ++* ++* Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "wlan_compat.h" ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211conv.h" ++#include "p80211mgmt.h" ++#include "p80211msg.h" ++#include "p80211metastruct.h" ++#include "p80211metadef.h" ++#include "p80211netdev.h" ++#include "p80211ioctl.h" ++#include "p80211req.h" ++ ++static int p80211wext_giwrate(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra); ++static int p80211wext_giwessid(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid); ++ ++static u8 p80211_mhz_to_channel(u16 mhz) ++{ ++ if (mhz >= 5000) { ++ return ((mhz - 5000) / 5); ++ } ++ ++ if (mhz == 2482) ++ return 14; ++ ++ if (mhz >= 2407) { ++ return ((mhz - 2407) / 5); ++ } ++ ++ return 0; ++} ++ ++static u16 p80211_channel_to_mhz(u8 ch, int dot11a) ++{ ++ ++ if (ch == 0) ++ return 0; ++ if (ch > 200) ++ return 0; ++ ++ /* 5G */ ++ ++ if (dot11a) { ++ return (5000 + (5 * ch)); ++ } ++ ++ /* 2.4G */ ++ ++ if (ch == 14) ++ return 2484; ++ ++ if ((ch < 14) && (ch > 0)) { ++ return (2407 + (5 * ch)); ++ } ++ ++ return 0; ++} ++ ++/* taken from orinoco.c ;-) */ ++static const long p80211wext_channel_freq[] = { ++ 2412, 2417, 2422, 2427, 2432, 2437, 2442, ++ 2447, 2452, 2457, 2462, 2467, 2472, 2484 ++}; ++#define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq) ++ ++/* steal a spare bit to store the shared/opensystems state. should default to open if not set */ ++#define HOSTWEP_SHAREDKEY BIT3 ++ ++ ++/** function declarations =============== */ ++ ++static int qual_as_percent(int snr ) { ++ if ( snr <= 0 ) ++ return 0; ++ if ( snr <= 40 ) ++ return snr*5/2; ++ return 100; ++} ++ ++ ++ ++ ++static int p80211wext_dorequest(wlandevice_t *wlandev, u32 did, u32 data) ++{ ++ p80211msg_dot11req_mibset_t msg; ++ p80211item_uint32_t mibitem; ++ int result; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ mibitem.did = did; ++ mibitem.data = data; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ DBFEXIT; ++ return result; ++} ++ ++static int p80211wext_autojoin(wlandevice_t *wlandev) ++{ ++ p80211msg_lnxreq_autojoin_t msg; ++ struct iw_point data; ++ char ssid[IW_ESSID_MAX_SIZE]; ++ ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ /* Get ESSID */ ++ result = p80211wext_giwessid(wlandev->netdev, NULL, &data, ssid); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if ( wlandev->hostwep & HOSTWEP_SHAREDKEY ) ++ msg.authtype.data = P80211ENUM_authalg_sharedkey; ++ else ++ msg.authtype.data = P80211ENUM_authalg_opensystem; ++ ++ msg.msgcode = DIDmsg_lnxreq_autojoin; ++ ++ /* Trim the last '\0' to fit the SSID format */ ++ ++ if (data.length && ssid[data.length-1] == '\0') { ++ data.length = data.length - 1; ++ } ++ ++ memcpy(msg.ssid.data.data, ssid, data.length); ++ msg.ssid.data.len = data.length; ++ ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++exit: ++ ++ DBFEXIT; ++ return err; ++ ++} ++ ++/* called by /proc/net/wireless */ ++struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev) ++{ ++ p80211msg_lnxreq_commsquality_t quality; ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ struct iw_statistics* wstats = &wlandev->wstats; ++ int retval; ++ ++ DBFENTER; ++ /* Check */ ++ if ( (wlandev == NULL) || (wlandev->msdstate != WLAN_MSD_RUNNING) ) ++ return NULL; ++ ++ /* XXX Only valid in station mode */ ++ wstats->status = 0; ++ ++ /* build request message */ ++ quality.msgcode = DIDmsg_lnxreq_commsquality; ++ quality.dbm.data = P80211ENUM_truth_true; ++ quality.dbm.status = P80211ENUM_msgitem_status_data_ok; ++ ++ /* send message to nsd */ ++ if ( wlandev->mlmerequest == NULL ) ++ return NULL; ++ ++ retval = wlandev->mlmerequest(wlandev, (p80211msg_t*) &quality); ++ ++ wstats->qual.qual = qual_as_percent(quality.link.data); /* overall link quality */ ++ wstats->qual.level = quality.level.data; /* instant signal level */ ++ wstats->qual.noise = quality.noise.data; /* instant noise level */ ++ ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++ wstats->discard.code = wlandev->rx.decrypt_err; ++ wstats->discard.nwid = 0; ++ wstats->discard.misc = 0; ++ ++ wstats->discard.fragment = 0; // incomplete fragments ++ wstats->discard.retries = 0; // tx retries. ++ wstats->miss.beacon = 0; ++ ++ DBFEXIT; ++ ++ return wstats; ++} ++ ++static int p80211wext_giwname(netdevice_t *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ struct iw_param rate; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ result = p80211wext_giwrate(dev, NULL, &rate, NULL); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ switch (rate.value) { ++ case 1000000: ++ case 2000000: ++ strcpy(name, "IEEE 802.11-DS"); ++ break; ++ case 5500000: ++ case 11000000: ++ strcpy(name, "IEEE 802.11-b"); ++ break; ++ } ++exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_giwfreq(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ if (mibitem.data > NUM_CHANNELS) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ /* convert into frequency instead of a channel */ ++ freq->e = 1; ++ freq->m = p80211_channel_to_mhz(mibitem.data, 0) * 100000; ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_siwfreq(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ mibitem.did = DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel; ++ mibitem.status = P80211ENUM_msgitem_status_data_ok; ++ ++ if ( (freq->e == 0) && (freq->m <= 1000) ) ++ mibitem.data = freq->m; ++ else ++ mibitem.data = p80211_mhz_to_channel(freq->m); ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_giwmode(netdevice_t *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ ++ DBFENTER; ++ ++ switch (wlandev->macmode) { ++ case WLAN_MACMODE_IBSS_STA: ++ *mode = IW_MODE_ADHOC; ++ break; ++ case WLAN_MACMODE_ESS_STA: ++ *mode = IW_MODE_INFRA; ++ break; ++ case WLAN_MACMODE_ESS_AP: ++ *mode = IW_MODE_MASTER; ++ break; ++ default: ++ /* Not set yet. */ ++ *mode = IW_MODE_AUTO; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++static int p80211wext_siwmode(netdevice_t *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA && ++ *mode != IW_MODE_MASTER) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ /* Operation mode is the same with current mode */ ++ if (*mode == wlandev->macmode) ++ goto exit; ++ ++ switch (*mode) { ++ case IW_MODE_ADHOC: ++ wlandev->macmode = WLAN_MACMODE_IBSS_STA; ++ break; ++ case IW_MODE_INFRA: ++ wlandev->macmode = WLAN_MACMODE_ESS_STA; ++ break; ++ case IW_MODE_MASTER: ++ wlandev->macmode = WLAN_MACMODE_ESS_AP; ++ break; ++ default: ++ /* Not set yet. */ ++ WLAN_LOG_INFO("Operation mode: %d not support\n", *mode); ++ return -EOPNOTSUPP; ++ } ++ ++ /* Set Operation mode to the PORT TYPE RID */ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ mibitem.did = DIDmib_p2_p2Static_p2CnfPortType; ++ mibitem.data = (*mode == IW_MODE_ADHOC) ? 0 : 1; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) ++ err = -EFAULT; ++ ++ exit: ++ DBFEXIT; ++ ++ return err; ++} ++ ++ ++static int p80211wext_giwrange(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *) extra; ++ int i, val; ++ ++ DBFENTER; ++ ++ // for backward compatability set size & zero everything we don't understand ++ data->length = sizeof(*range); ++ memset(range,0,sizeof(*range)); ++ ++ range->txpower_capa = IW_TXPOW_DBM; ++ // XXX what about min/max_pmp, min/max_pmt, etc. ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 13; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | //mode/freq/ssid ++ IW_EVENT_CAPA_MASK(SIOCGIWAP) | ++ IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); ++ range->event_capa[1] = IW_EVENT_CAPA_K_1; //encode ++ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL) | ++ IW_EVENT_CAPA_MASK(IWEVCUSTOM) ); ++ ++ range->num_channels = NUM_CHANNELS; ++ ++ /* XXX need to filter against the regulatory domain &| active set */ ++ val = 0; ++ for (i = 0; i < NUM_CHANNELS ; i++) { ++ range->freq[val].i = i + 1; ++ range->freq[val].m = p80211wext_channel_freq[i] * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } ++ ++ range->num_frequency = val; ++ ++ /* Max of /proc/net/wireless */ ++ range->max_qual.qual = 100; ++ range->max_qual.level = 0; ++ range->max_qual.noise = 0; ++ range->sensitivity = 3; ++ // XXX these need to be nsd-specific! ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++ range->max_encoding_tokens = NUM_WEPKEYS; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ // XXX what about num_bitrates/throughput? ++ range->num_bitrates = 0; ++ ++ /* estimated max throughput */ ++ // XXX need to cap it if we're running at ~2Mbps.. ++ range->throughput = 5500000; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++static int p80211wext_giwap(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ ++ DBFENTER; ++ ++ memcpy(ap_addr->sa_data, wlandev->bssid, WLAN_BSSID_LEN); ++ ap_addr->sa_family = ARPHRD_ETHER; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++static int p80211wext_giwencode(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ int err = 0; ++ int i; ++ ++ DBFENTER; ++ ++ i = (erq->flags & IW_ENCODE_INDEX) - 1; ++ erq->flags = 0; ++ ++ if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) ++ erq->flags |= IW_ENCODE_ENABLED; ++ else ++ erq->flags |= IW_ENCODE_DISABLED; ++ ++ if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ else ++ erq->flags |= IW_ENCODE_OPEN; ++ ++ i = (erq->flags & IW_ENCODE_INDEX) - 1; ++ ++ if (i == -1) ++ i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; ++ ++ if ((i < 0) || (i >= NUM_WEPKEYS)) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ erq->flags |= i + 1; ++ ++ /* copy the key from the driver cache as the keys are read-only MIBs */ ++ erq->length = wlandev->wep_keylens[i]; ++ memcpy(key, wlandev->wep_keys[i], erq->length); ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_siwencode(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211msg_dot11req_mibset_t msg; ++ p80211item_pstr32_t pstr; ++ ++ int err = 0; ++ int result = 0; ++ int i; ++ ++ DBFENTER; ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ /* Check the Key index first. */ ++ if((i = (erq->flags & IW_ENCODE_INDEX))) { ++ ++ if ((i < 1) || (i > NUM_WEPKEYS)) { ++ err = -EINVAL; ++ goto exit; ++ } ++ else ++ i--; ++ ++ /* Set current key number only if no keys are given */ ++ if (erq->flags & IW_ENCODE_NOKEY) { ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, i); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ ++ } else { ++ // Use defaultkey if no Key Index ++ i = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; ++ } ++ ++ /* Check if there is no key information in the iwconfig request */ ++ if((erq->flags & IW_ENCODE_NOKEY) == 0 ) { ++ ++ /*------------------------------------------------------------ ++ * If there is WEP Key for setting, check the Key Information ++ * and then set it to the firmware. ++ -------------------------------------------------------------*/ ++ ++ if (erq->length > 0) { ++ ++ /* copy the key from the driver cache as the keys are read-only MIBs */ ++ wlandev->wep_keylens[i] = erq->length; ++ memcpy(wlandev->wep_keys[i], key, erq->length); ++ ++ /* Prepare data struture for p80211req_dorequest. */ ++ memcpy(pstr.data.data, key, erq->length); ++ pstr.data.len = erq->length; ++ ++ switch(i) ++ { ++ case 0: ++ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; ++ break; ++ ++ case 1: ++ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; ++ break; ++ ++ case 2: ++ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; ++ break; ++ ++ case 3: ++ pstr.did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; ++ break; ++ ++ default: ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ memcpy(&msg.mibattribute.data, &pstr, sizeof(pstr)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ ++ } ++ ++ /* Check the PrivacyInvoked flag */ ++ if (erq->flags & IW_ENCODE_DISABLED) { ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false); ++ } else { ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true); ++ } ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ /* The security mode may be open or restricted, and its meaning ++ depends on the card used. With most cards, in open mode no ++ authentication is used and the card may also accept non- ++ encrypted sessions, whereas in restricted mode only encrypted ++ sessions are accepted and the card will use authentication if ++ available. ++ */ ++ if (erq->flags & IW_ENCODE_RESTRICTED) { ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true); ++ } ++ else if (erq->flags & IW_ENCODE_OPEN) { ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false); ++ } ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ exit: ++ ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_giwessid(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ ++ DBFENTER; ++ ++ if (wlandev->ssid.len) { ++ data->length = wlandev->ssid.len; ++ data->flags = 1; ++ memcpy(essid, wlandev->ssid.data, data->length); ++ essid[data->length] = 0; ++#if (WIRELESS_EXT < 21) ++ data->length++; ++#endif ++ } else { ++ memset(essid, 0, sizeof(wlandev->ssid.data)); ++ data->length = 0; ++ data->flags = 0; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++static int p80211wext_siwessid(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211msg_lnxreq_autojoin_t msg; ++ ++ int result; ++ int err = 0; ++ int length = data->length; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ ++ if ( wlandev->hostwep & HOSTWEP_SHAREDKEY ) ++ msg.authtype.data = P80211ENUM_authalg_sharedkey; ++ else ++ msg.authtype.data = P80211ENUM_authalg_opensystem; ++ ++ msg.msgcode = DIDmsg_lnxreq_autojoin; ++ ++#if (WIRELESS_EXT < 21) ++ if (length) length--; ++#endif ++ ++ /* Trim the last '\0' to fit the SSID format */ ++ ++ if (length && essid[length-1] == '\0') { ++ length--; ++ } ++ ++ memcpy(msg.ssid.data.data, essid, length); ++ msg.ssid.data.len = length; ++ ++ WLAN_LOG_DEBUG(1,"autojoin_ssid for %s \n",essid); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ WLAN_LOG_DEBUG(1,"autojoin_ssid %d\n",result); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++ ++static int p80211wext_siwcommit(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ /* Auto Join */ ++ err = p80211wext_autojoin(wlandev); ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++ ++static int p80211wext_giwrate(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_p2_p2MAC_p2CurrentTxRate; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ rrq->fixed = 0; /* can it change? */ ++ rrq->disabled = 0; ++ rrq->value = 0; ++ ++#define HFA384x_RATEBIT_1 ((u16)1) ++#define HFA384x_RATEBIT_2 ((u16)2) ++#define HFA384x_RATEBIT_5dot5 ((u16)4) ++#define HFA384x_RATEBIT_11 ((u16)8) ++ ++ switch (mibitem.data) { ++ case HFA384x_RATEBIT_1: ++ rrq->value = 1000000; ++ break; ++ case HFA384x_RATEBIT_2: ++ rrq->value = 2000000; ++ break; ++ case HFA384x_RATEBIT_5dot5: ++ rrq->value = 5500000; ++ break; ++ case HFA384x_RATEBIT_11: ++ rrq->value = 11000000; ++ break; ++ default: ++ err = -EINVAL; ++ } ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_giwrts(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ rts->value = mibitem.data; ++ rts->disabled = (rts->value == 2347); ++ rts->fixed = 1; ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++ ++static int p80211wext_siwrts(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold; ++ if (rts->disabled) ++ mibitem.data = 2347; ++ else ++ mibitem.data = rts->value; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_giwfrag(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ frag->value = mibitem.data; ++ frag->disabled = (frag->value == 2346); ++ frag->fixed = 1; ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_siwfrag(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold; ++ ++ if (frag->disabled) ++ mibitem.data = 2346; ++ else ++ mibitem.data = frag->value; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++#ifndef IW_RETRY_LONG ++#define IW_RETRY_LONG IW_RETRY_MAX ++#endif ++ ++#ifndef IW_RETRY_SHORT ++#define IW_RETRY_SHORT IW_RETRY_MIN ++#endif ++ ++static int p80211wext_giwretry(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ u16 shortretry, longretry, lifetime; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ shortretry = mibitem.data; ++ ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ longretry = mibitem.data; ++ ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ lifetime = mibitem.data; ++ ++ rrq->disabled = 0; ++ ++ if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { ++ rrq->flags = IW_RETRY_LIFETIME; ++ rrq->value = lifetime * 1024; ++ } else { ++ if (rrq->flags & IW_RETRY_LONG) { ++ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; ++ rrq->value = longretry; ++ } else { ++ rrq->flags = IW_RETRY_LIMIT; ++ rrq->value = shortretry; ++ if (shortretry != longretry) ++ rrq->flags |= IW_RETRY_SHORT; ++ } ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++ ++} ++ ++static int p80211wext_siwretry(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ if (rrq->disabled) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ ++ if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime; ++ mibitem.data = rrq->value /= 1024; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } else { ++ if (rrq->flags & IW_RETRY_LONG) { ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit; ++ mibitem.data = rrq->value; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ ++ if (rrq->flags & IW_RETRY_SHORT) { ++ mibitem.did = DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit; ++ mibitem.data = rrq->value; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ } ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++ ++} ++ ++static int p80211wext_siwtxpow(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ if (!wlan_wext_write) { ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; ++ if (rrq->fixed == 0) ++ mibitem.data = 30; ++ else ++ mibitem.data = rrq->value; ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_giwtxpow(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211item_uint32_t mibitem; ++ p80211msg_dot11req_mibset_t msg; ++ int result; ++ int err = 0; ++ ++ DBFENTER; ++ ++ msg.msgcode = DIDmsg_dot11req_mibget; ++ mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel; ++ ++ memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem)); ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ ++ if (result) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ memcpy(&mibitem, &msg.mibattribute.data, sizeof(mibitem)); ++ ++ // XXX handle OFF by setting disabled = 1; ++ ++ rrq->flags = 0; // IW_TXPOW_DBM; ++ rrq->disabled = 0; ++ rrq->fixed = 0; ++ rrq->value = mibitem.data; ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++static int p80211wext_siwspy(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *srq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ struct sockaddr address[IW_MAX_SPY]; ++ int number = srq->length; ++ int i; ++ ++ DBFENTER; ++ ++ /* Copy the data from the input buffer */ ++ memcpy(address, extra, sizeof(struct sockaddr)*number); ++ ++ wlandev->spy_number = 0; ++ ++ if (number > 0) { ++ ++ /* extract the addresses */ ++ for (i = 0; i < number; i++) { ++ ++ memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN); ++ } ++ ++ /* reset stats */ ++ memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY); ++ ++ /* set number of addresses */ ++ wlandev->spy_number = number; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++/* jkriegl: from orinoco, modified */ ++static int p80211wext_giwspy(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *srq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ ++ struct sockaddr address[IW_MAX_SPY]; ++ struct iw_quality spy_stat[IW_MAX_SPY]; ++ int number; ++ int i; ++ ++ DBFENTER; ++ ++ number = wlandev->spy_number; ++ ++ if (number > 0) { ++ ++ /* populate address and spy struct's */ ++ for (i = 0; i < number; i++) { ++ memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN); ++ address[i].sa_family = AF_UNIX; ++ memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality)); ++ } ++ ++ /* reset update flag */ ++ for (i=0; i < number; i++) ++ wlandev->spy_stat[i].updated = 0; ++ } ++ ++ /* push stuff to user space */ ++ srq->length = number; ++ memcpy(extra, address, sizeof(struct sockaddr)*number); ++ memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number); ++ ++ DBFEXIT; ++ return 0; ++} ++ ++static int prism2_result2err (int prism2_result) ++{ ++ int err = 0; ++ ++ switch (prism2_result) { ++ case P80211ENUM_resultcode_invalid_parameters: ++ err = -EINVAL; ++ break; ++ case P80211ENUM_resultcode_implementation_failure: ++ err = -EIO; ++ break; ++ case P80211ENUM_resultcode_not_supported: ++ err = -EOPNOTSUPP; ++ break; ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++static int p80211wext_siwscan(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *srq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211msg_dot11req_scan_t msg; ++ int result; ++ int err = 0; ++ int i = 0; ++ ++ DBFENTER; ++ ++ if (wlandev->macmode == WLAN_MACMODE_ESS_AP) { ++ WLAN_LOG_ERROR("Can't scan in AP mode\n"); ++ err = (-EOPNOTSUPP); ++ goto exit; ++ } ++ ++ memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t)); ++ msg.msgcode = DIDmsg_dot11req_scan; ++ msg.bsstype.data = P80211ENUM_bsstype_any; ++ ++ memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t)); ++ msg.bssid.data.len = 6; ++ ++ msg.scantype.data = P80211ENUM_scantype_active; ++ msg.probedelay.data = 0; ++ ++ for (i = 1; i <= 14; i++) ++ msg.channellist.data.data[i-1] = i; ++ msg.channellist.data.len = 14; ++ ++ msg.maxchanneltime.data = 250; ++ msg.minchanneltime.data = 200; ++ ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ if (result) ++ err = prism2_result2err (msg.resultcode.data); ++ ++ exit: ++ DBFEXIT; ++ return err; ++} ++ ++ ++/* Helper to translate scan into Wireless Extensions scan results. ++ * Inspired by the prism54 code, which was in turn inspired by the ++ * airo driver code. ++ */ ++static char * ++wext_translate_bss(struct iw_request_info *info, char *current_ev, ++ char *end_buf, p80211msg_dot11req_scan_results_t *bss) ++{ ++ struct iw_event iwe; /* Temporary buffer */ ++ ++ /* The first entry must be the MAC address */ ++ memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN); ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ iwe.cmd = SIOCGIWAP; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); ++ ++ /* The following entries will be displayed in the same order we give them */ ++ ++ /* The ESSID. */ ++ if (bss->ssid.data.len > 0) { ++ char essid[IW_ESSID_MAX_SIZE + 1]; ++ int size; ++ ++ size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len); ++ memset(&essid, 0, sizeof (essid)); ++ memcpy(&essid, bss->ssid.data.data, size); ++ WLAN_LOG_DEBUG(1, " essid size = %d\n", size); ++ iwe.u.data.length = size; ++ iwe.u.data.flags = 1; ++ iwe.cmd = SIOCGIWESSID; ++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, &essid[0]); ++ WLAN_LOG_DEBUG(1, " essid size OK.\n"); ++ } ++ ++ switch (bss->bsstype.data) { ++ case P80211ENUM_bsstype_infrastructure: ++ iwe.u.mode = IW_MODE_MASTER; ++ break; ++ ++ case P80211ENUM_bsstype_independent: ++ iwe.u.mode = IW_MODE_ADHOC; ++ break; ++ ++ default: ++ iwe.u.mode = 0; ++ break; ++ } ++ iwe.cmd = SIOCGIWMODE; ++ if (iwe.u.mode) ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ ++ /* Encryption capability */ ++ if (bss->privacy.data == P80211ENUM_truth_true) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ iwe.cmd = SIOCGIWENCODE; ++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, NULL); ++ ++ /* Add frequency. (short) bss->channel is the frequency in MHz */ ++ iwe.u.freq.m = bss->dschannel.data; ++ iwe.u.freq.e = 0; ++ iwe.cmd = SIOCGIWFREQ; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Add quality statistics */ ++ iwe.u.qual.level = bss->signal.data; ++ iwe.u.qual.noise = bss->noise.data; ++ /* do a simple SNR for quality */ ++ iwe.u.qual.qual = qual_as_percent(bss->signal.data - bss->noise.data); ++ iwe.cmd = IWEVQUAL; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ ++ return current_ev; ++} ++ ++ ++static int p80211wext_giwscan(netdevice_t *dev, ++ struct iw_request_info *info, ++ struct iw_point *srq, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ p80211msg_dot11req_scan_results_t msg; ++ int result = 0; ++ int err = 0; ++ int i = 0; ++ int scan_good = 0; ++ char *current_ev = extra; ++ ++ DBFENTER; ++ ++ /* Since wireless tools doesn't really have a way of passing how ++ * many scan results results there were back here, keep grabbing them ++ * until we fail. ++ */ ++ do { ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgcode = DIDmsg_dot11req_scan_results; ++ msg.bssindex.data = i; ++ ++ result = p80211req_dorequest(wlandev, (u8*)&msg); ++ if ((result != 0) || ++ (msg.resultcode.data != P80211ENUM_resultcode_success)) { ++ break; ++ } ++ ++ current_ev = wext_translate_bss(info, current_ev, extra + IW_SCAN_MAX_DATA, &msg); ++ scan_good = 1; ++ i++; ++ } while (i < IW_MAX_AP); ++ ++ srq->length = (current_ev - extra); ++ srq->flags = 0; /* todo */ ++ ++ if (result && !scan_good) ++ err = prism2_result2err (msg.resultcode.data); ++ ++ DBFEXIT; ++ return err; ++} ++ ++/*****************************************************/ ++//extra wireless extensions stuff to support NetworkManager (I hope) ++ ++/* SIOCSIWENCODEEXT */ ++static int p80211wext_set_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ p80211msg_dot11req_mibset_t msg; ++ p80211item_pstr32_t *pstr; ++ ++ int result = 0; ++ struct iw_point *encoding = &wrqu->encoding; ++ int idx = encoding->flags & IW_ENCODE_INDEX; ++ ++ WLAN_LOG_DEBUG(1,"set_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len); ++ ++ ++ if ( ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY ) { ++ // set default key ? I'm not sure if this the the correct thing to do here ++ ++ if ( idx ) { ++ if (idx < 1 || idx > NUM_WEPKEYS) { ++ return -EINVAL; ++ } else ++ idx--; ++ } ++ WLAN_LOG_DEBUG(1,"setting default key (%d)\n",idx); ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, idx); ++ if ( result ) ++ return -EFAULT; ++ } ++ ++ ++ if ( ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY ) { ++ if (!(ext->alg & IW_ENCODE_ALG_WEP)) { ++ WLAN_LOG_DEBUG(1,"asked to set a non wep key :("); ++ return -EINVAL; ++ } ++ if (idx) { ++ if (idx <1 || idx > NUM_WEPKEYS) ++ return -EINVAL; ++ else ++ idx--; ++ } ++ WLAN_LOG_DEBUG(1,"Set WEP key (%d)\n",idx); ++ wlandev->wep_keylens[idx] = ext->key_len; ++ memcpy(wlandev->wep_keys[idx], ext->key, ext->key_len); ++ ++ memset( &msg,0,sizeof(msg)); ++ pstr = (p80211item_pstr32_t*)&msg.mibattribute.data; ++ memcpy(pstr->data.data, ext->key,ext->key_len); ++ pstr->data.len = ext->key_len; ++ switch (idx) { ++ case 0: ++ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0; ++ break; ++ case 1: ++ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1; ++ break; ++ case 2: ++ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2; ++ break; ++ case 3: ++ pstr->did = DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3; ++ break; ++ default: ++ break; ++ } ++ msg.msgcode = DIDmsg_dot11req_mibset; ++ result = p80211req_dorequest(wlandev,(u8*)&msg); ++ WLAN_LOG_DEBUG(1,"result (%d)\n",result); ++ } ++ return result; ++} ++ ++/* SIOCGIWENCODEEXT */ ++static int p80211wext_get_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ ++ struct iw_point *encoding = &wrqu->encoding; ++ int result = 0; ++ int max_len; ++ int idx; ++ ++ DBFENTER; ++ ++ WLAN_LOG_DEBUG(1,"get_encode_ext flags[%d] alg[%d] keylen[%d]\n",ext->ext_flags,(int)ext->alg,(int)ext->key_len); ++ ++ ++ max_len = encoding->length - sizeof(*ext); ++ if ( max_len <= 0) { ++ WLAN_LOG_DEBUG(1,"get_encodeext max_len [%d] invalid\n",max_len); ++ result = -EINVAL; ++ goto exit; ++ } ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ ++ WLAN_LOG_DEBUG(1,"get_encode_ext index [%d]\n",idx); ++ ++ if (idx) { ++ if (idx < 1 || idx > NUM_WEPKEYS ) { ++ WLAN_LOG_DEBUG(1,"get_encode_ext invalid key index [%d]\n",idx); ++ result = -EINVAL; ++ goto exit; ++ } ++ idx--; ++ } else { ++ /* default key ? not sure what to do */ ++ /* will just use key[0] for now ! FIX ME */ ++ } ++ ++ encoding->flags = idx + 1; ++ memset(ext,0,sizeof(*ext)); ++ ++ ext->alg = IW_ENCODE_ALG_WEP; ++ ext->key_len = wlandev->wep_keylens[idx]; ++ memcpy( ext->key, wlandev->wep_keys[idx] , ext->key_len ); ++ ++ encoding->flags |= IW_ENCODE_ENABLED; ++exit: ++ DBFEXIT; ++ ++ return result; ++} ++ ++ ++/* SIOCSIWAUTH */ ++static int p80211_wext_set_iwauth (struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ struct iw_param *param = &wrqu->param; ++ int result =0; ++ ++ WLAN_LOG_DEBUG(1,"set_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX ); ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ WLAN_LOG_DEBUG(1,"drop_unencrypted %d\n",param->value); ++ if (param->value) ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_true); ++ else ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, P80211ENUM_truth_false); ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ WLAN_LOG_DEBUG(1,"privacy invoked %d\n",param->value); ++ if ( param->value) ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_true); ++ else ++ result = p80211wext_dorequest(wlandev, DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, P80211ENUM_truth_false); ++ ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ if ( param->value & IW_AUTH_ALG_OPEN_SYSTEM ) { ++ WLAN_LOG_DEBUG(1,"set open_system\n"); ++ wlandev->hostwep &= ~HOSTWEP_SHAREDKEY; ++ } else if ( param->value & IW_AUTH_ALG_SHARED_KEY) { ++ WLAN_LOG_DEBUG(1,"set shared key\n"); ++ wlandev->hostwep |= HOSTWEP_SHAREDKEY; ++ } else { ++ /* don't know what to do know :( */ ++ WLAN_LOG_DEBUG(1,"unknown AUTH_ALG (%d)\n",param->value); ++ result = -EINVAL; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ ++ return result; ++} ++ ++/* SIOCSIWAUTH */ ++static int p80211_wext_get_iwauth (struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wlandevice_t *wlandev = (wlandevice_t*)dev->priv; ++ struct iw_param *param = &wrqu->param; ++ int result =0; ++ ++ WLAN_LOG_DEBUG(1,"get_iwauth flags[%d]\n",(int)param->flags & IW_AUTH_INDEX ); ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ param->value = wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED?1:0; ++ break; ++ ++ case IW_AUTH_PRIVACY_INVOKED: ++ param->value = wlandev->hostwep & HOSTWEP_PRIVACYINVOKED?1:0; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ param->value = wlandev->hostwep & HOSTWEP_SHAREDKEY?IW_AUTH_ALG_SHARED_KEY:IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ ++ ++ default: ++ break; ++ } ++ ++ ++ ++ return result; ++} ++ ++static iw_handler p80211wext_handlers[] = { ++ (iw_handler) p80211wext_siwcommit, /* SIOCSIWCOMMIT */ ++ (iw_handler) p80211wext_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) p80211wext_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) p80211wext_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) p80211wext_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) p80211wext_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL, /* not used */ /* SIOCSIWRANGE */ ++ (iw_handler) p80211wext_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL, /* not used */ /* SIOCSIWPRIV */ ++ (iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */ ++ (iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */ ++ (iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */ ++ (iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */ ++ (iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* SIOCSIWAP */ ++ (iw_handler) p80211wext_giwap, /* SIOCGIWAP */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* SIOCGIWAPLIST */ ++ (iw_handler) p80211wext_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) p80211wext_giwscan, /* SIOCGIWSCAN */ ++ (iw_handler) p80211wext_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) p80211wext_giwessid, /* SIOCGIWESSID */ ++ (iw_handler) NULL, /* SIOCSIWNICKN */ ++ (iw_handler) p80211wext_giwessid, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* SIOCSIWRATE */ ++ (iw_handler) p80211wext_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) p80211wext_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) p80211wext_siwtxpow, /* SIOCSIWTXPOW */ ++ (iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */ ++ (iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */ ++ (iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */ ++ (iw_handler) p80211wext_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) p80211wext_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) NULL, /* SIOCSIWPOWER */ ++ (iw_handler) NULL, /* SIOCGIWPOWER */ ++/* WPA operations */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* SIOCSIWGENIE set generic IE */ ++ (iw_handler) NULL, /* SIOCGIWGENIE get generic IE */ ++ (iw_handler) p80211_wext_set_iwauth, /* SIOCSIWAUTH set authentication mode params */ ++ (iw_handler) p80211_wext_get_iwauth, /* SIOCGIWAUTH get authentication mode params */ ++ ++ (iw_handler) p80211wext_set_encodeext, /* SIOCSIWENCODEEXT set encoding token & mode */ ++ (iw_handler) p80211wext_get_encodeext, /* SIOCGIWENCODEEXT get encoding token & mode */ ++ (iw_handler) NULL, /* SIOCSIWPMKSA PMKSA cache operation */ ++}; ++ ++struct iw_handler_def p80211wext_handler_def = { ++ .num_standard = ARRAY_SIZE(p80211wext_handlers), ++ .num_private = 0, ++ .num_private_args = 0, ++ .standard = p80211wext_handlers, ++ .private = NULL, ++ .private_args = NULL, ++ .get_wireless_stats = p80211wext_get_wireless_stats ++}; ++ ++int p80211wext_event_associated(wlandevice_t *wlandev, int assoc) ++{ ++ union iwreq_data data; ++ ++ DBFENTER; ++ ++ /* Send the association state first */ ++ data.ap_addr.sa_family = ARPHRD_ETHER; ++ if (assoc) { ++ memcpy(data.ap_addr.sa_data, wlandev->bssid, WLAN_ADDR_LEN); ++ } else { ++ memset(data.ap_addr.sa_data, 0, WLAN_ADDR_LEN); ++ } ++ ++ if (wlan_wext_write) ++ wireless_send_event(wlandev->netdev, SIOCGIWAP, &data, NULL); ++ ++ if (!assoc) goto done; ++ ++ // XXX send association data, like IEs, etc etc. ++ ++ done: ++ DBFEXIT; ++ return 0; ++} ++ ++ ++ ++ +--- /dev/null ++++ b/drivers/staging/wlan-ng/prism2mgmt.c +@@ -0,0 +1,1363 @@ ++/* src/prism2/driver/prism2mgmt.c ++* ++* Management request handler functions. ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* The functions in this file handle management requests sent from ++* user mode. ++* ++* Most of these functions have two separate blocks of code that are ++* conditional on whether this is a station or an AP. This is used ++* to separate out the STA and AP responses to these management primitives. ++* It's a choice (good, bad, indifferent?) to have the code in the same ++* place so it's clear that the same primitive is implemented in both ++* cases but has different behavior. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++#define WLAN_DBVAR prism2_debug ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "wlan_compat.h" ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211mgmt.h" ++#include "p80211conv.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211metadef.h" ++#include "p80211metastruct.h" ++#include "hfa384x.h" ++#include "prism2mgmt.h" ++ ++/* Converts 802.11 format rate specifications to prism2 */ ++#define p80211rate_to_p2bit(n) ((((n)&~BIT7) == 2) ? BIT0 : \ ++ (((n)&~BIT7) == 4) ? BIT1 : \ ++ (((n)&~BIT7) == 11) ? BIT2 : \ ++ (((n)&~BIT7) == 22) ? BIT3 : 0) ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_scan ++* ++* Initiate a scan for BSSs. ++* ++* This function corresponds to MLME-scan.request and part of ++* MLME-scan.confirm. As far as I can tell in the standard, there ++* are no restrictions on when a scan.request may be issued. We have ++* to handle in whatever state the driver/MAC happen to be. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp) ++{ ++ int result = 0; ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_dot11req_scan_t *msg = msgp; ++ u16 roamingmode, word; ++ int i, timeout; ++ int istmpenable = 0; ++ ++ hfa384x_HostScanRequest_data_t scanreq; ++ ++ DBFENTER; ++ ++ /* gatekeeper check */ ++ if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, ++ hw->ident_sta_fw.variant) < ++ HFA384x_FIRMWARE_VERSION(1,3,2)) { ++ WLAN_LOG_ERROR("HostScan not supported with current firmware (<1.3.2).\n"); ++ result = 1; ++ msg->resultcode.data = P80211ENUM_resultcode_not_supported; ++ goto exit; ++ } ++ ++ memset(&scanreq, 0, sizeof(scanreq)); ++ ++ /* save current roaming mode */ ++ result = hfa384x_drvr_getconfig16(hw, ++ HFA384x_RID_CNFROAMINGMODE, &roamingmode); ++ if ( result ) { ++ WLAN_LOG_ERROR("getconfig(ROAMMODE) failed. result=%d\n", ++ result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ ++ /* drop into mode 3 for the scan */ ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFROAMINGMODE, ++ HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); ++ if ( result ) { ++ WLAN_LOG_ERROR("setconfig(ROAMINGMODE) failed. result=%d\n", ++ result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ ++ /* active or passive? */ ++ if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, ++ hw->ident_sta_fw.variant) > ++ HFA384x_FIRMWARE_VERSION(1,5,0)) { ++ if (msg->scantype.data != P80211ENUM_scantype_active) { ++ word = host2hfa384x_16(msg->maxchanneltime.data); ++ } else { ++ word = 0; ++ } ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL, word); ++ if ( result ) { ++ WLAN_LOG_WARNING("Passive scan not supported with " ++ "current firmware. (<1.5.1)\n"); ++ } ++ } ++ ++ /* set up the txrate to be 2MBPS. Should be fastest basicrate... */ ++ word = HFA384x_RATEBIT_2; ++ scanreq.txRate = host2hfa384x_16(word); ++ ++ /* set up the channel list */ ++ word = 0; ++ for (i = 0; i < msg->channellist.data.len; i++) { ++ u8 channel = msg->channellist.data.data[i]; ++ if (channel > 14) continue; ++ /* channel 1 is BIT0 ... channel 14 is BIT13 */ ++ word |= (1 << (channel-1)); ++ } ++ scanreq.channelList = host2hfa384x_16(word); ++ ++ /* set up the ssid, if present. */ ++ scanreq.ssid.len = host2hfa384x_16(msg->ssid.data.len); ++ memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len); ++ ++ /* Enable the MAC port if it's not already enabled */ ++ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word); ++ if ( result ) { ++ WLAN_LOG_ERROR("getconfig(PORTSTATUS) failed. " ++ "result=%d\n", result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ if (word == HFA384x_PORTSTATUS_DISABLED) { ++ u16 wordbuf[17]; ++ ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFROAMINGMODE, ++ HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM); ++ if ( result ) { ++ WLAN_LOG_ERROR("setconfig(ROAMINGMODE) failed. result=%d\n", result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ /* Construct a bogus SSID and assign it to OwnSSID and ++ * DesiredSSID ++ */ ++ wordbuf[0] = host2hfa384x_16(WLAN_SSID_MAXLEN); ++ get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN); ++ result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID, ++ wordbuf, HFA384x_RID_CNFOWNSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set OwnSSID.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID, ++ wordbuf, HFA384x_RID_CNFDESIREDSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set DesiredSSID.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ /* bsstype */ ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFPORTTYPE, ++ HFA384x_PORTTYPE_IBSS); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set CNFPORTTYPE.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ /* ibss options */ ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CREATEIBSS, ++ HFA384x_CREATEIBSS_JOINCREATEIBSS); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set CREATEIBSS.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ result = hfa384x_drvr_enable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_ERROR("drvr_enable(0) failed. " ++ "result=%d\n", result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ istmpenable = 1; ++ } ++ ++ /* Figure out our timeout first Kus, then HZ */ ++ timeout = msg->channellist.data.len * msg->maxchanneltime.data; ++ timeout = (timeout * HZ)/1000; ++ ++ /* Issue the scan request */ ++ hw->scanflag = 0; ++ ++ WLAN_HEX_DUMP(5,"hscanreq", &scanreq, sizeof(scanreq)); ++ ++ result = hfa384x_drvr_setconfig( hw, ++ HFA384x_RID_HOSTSCAN, &scanreq, ++ sizeof(hfa384x_HostScanRequest_data_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("setconfig(SCANREQUEST) failed. result=%d\n", ++ result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ ++ /* sleep until info frame arrives */ ++ wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout); ++ ++ msg->numbss.status = P80211ENUM_msgitem_status_data_ok; ++ if (hw->scanflag == -1) ++ hw->scanflag = 0; ++ ++ msg->numbss.data = hw->scanflag; ++ ++ hw->scanflag = 0; ++ ++ /* Disable port if we temporarily enabled it. */ ++ if (istmpenable) { ++ result = hfa384x_drvr_disable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_ERROR("drvr_disable(0) failed. " ++ "result=%d\n", result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ } ++ ++ /* restore original roaming mode */ ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE, ++ roamingmode); ++ if ( result ) { ++ WLAN_LOG_ERROR("setconfig(ROAMMODE) failed. result=%d\n", ++ result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ goto exit; ++ } ++ ++ result = 0; ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ ++ exit: ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_scan_results ++* ++* Retrieve the BSS description for one of the BSSs identified in ++* a scan. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) ++{ ++ int result = 0; ++ p80211msg_dot11req_scan_results_t *req; ++ hfa384x_t *hw = wlandev->priv; ++ hfa384x_HScanResultSub_t *item = NULL; ++ ++ int count; ++ ++ DBFENTER; ++ ++ req = (p80211msg_dot11req_scan_results_t *) msgp; ++ ++ req->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ ++ if (! hw->scanresults) { ++ WLAN_LOG_ERROR("dot11req_scan_results can only be used after a successful dot11req_scan.\n"); ++ result = 2; ++ req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; ++ goto exit; ++ } ++ ++ count = (hw->scanresults->framelen - 3) / 32; ++ if (count > 32) count = 32; ++ ++ if (req->bssindex.data >= count) { ++ WLAN_LOG_DEBUG(0, "requested index (%d) out of range (%d)\n", ++ req->bssindex.data, count); ++ result = 2; ++ req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; ++ goto exit; ++ } ++ ++ item = &(hw->scanresults->info.hscanresult.result[req->bssindex.data]); ++ /* signal and noise */ ++ req->signal.status = P80211ENUM_msgitem_status_data_ok; ++ req->noise.status = P80211ENUM_msgitem_status_data_ok; ++ req->signal.data = hfa384x2host_16(item->sl); ++ req->noise.data = hfa384x2host_16(item->anl); ++ ++ /* BSSID */ ++ req->bssid.status = P80211ENUM_msgitem_status_data_ok; ++ req->bssid.data.len = WLAN_BSSID_LEN; ++ memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN); ++ ++ /* SSID */ ++ req->ssid.status = P80211ENUM_msgitem_status_data_ok; ++ req->ssid.data.len = hfa384x2host_16(item->ssid.len); ++ memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); ++ ++ /* supported rates */ ++ for (count = 0; count < 10 ; count++) ++ if (item->supprates[count] == 0) ++ break; ++ ++#define REQBASICRATE(N) \ ++ if ((count >= N) && DOT11_RATE5_ISBASIC_GET(item->supprates[(N)-1])) { \ ++ req->basicrate ## N .data = item->supprates[(N)-1]; \ ++ req->basicrate ## N .status = P80211ENUM_msgitem_status_data_ok; \ ++ } ++ ++ REQBASICRATE(1); ++ REQBASICRATE(2); ++ REQBASICRATE(3); ++ REQBASICRATE(4); ++ REQBASICRATE(5); ++ REQBASICRATE(6); ++ REQBASICRATE(7); ++ REQBASICRATE(8); ++ ++#define REQSUPPRATE(N) \ ++ if (count >= N) { \ ++ req->supprate ## N .data = item->supprates[(N)-1]; \ ++ req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \ ++ } ++ ++ REQSUPPRATE(1); ++ REQSUPPRATE(2); ++ REQSUPPRATE(3); ++ REQSUPPRATE(4); ++ REQSUPPRATE(5); ++ REQSUPPRATE(6); ++ REQSUPPRATE(7); ++ REQSUPPRATE(8); ++ ++ /* beacon period */ ++ req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok; ++ req->beaconperiod.data = hfa384x2host_16(item->bcnint); ++ ++ /* timestamps */ ++ req->timestamp.status = P80211ENUM_msgitem_status_data_ok; ++ req->timestamp.data = jiffies; ++ req->localtime.status = P80211ENUM_msgitem_status_data_ok; ++ req->localtime.data = jiffies; ++ ++ /* atim window */ ++ req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok; ++ req->ibssatimwindow.data = hfa384x2host_16(item->atim); ++ ++ /* Channel */ ++ req->dschannel.status = P80211ENUM_msgitem_status_data_ok; ++ req->dschannel.data = hfa384x2host_16(item->chid); ++ ++ /* capinfo bits */ ++ count = hfa384x2host_16(item->capinfo); ++ ++ /* privacy flag */ ++ req->privacy.status = P80211ENUM_msgitem_status_data_ok; ++ req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count); ++ ++ /* cfpollable */ ++ req->cfpollable.status = P80211ENUM_msgitem_status_data_ok; ++ req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count); ++ ++ /* cfpollreq */ ++ req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok; ++ req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count); ++ ++ /* bsstype */ ++ req->bsstype.status = P80211ENUM_msgitem_status_data_ok; ++ req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ? ++ P80211ENUM_bsstype_infrastructure : ++ P80211ENUM_bsstype_independent; ++ ++ // item->proberesp_rate ++/* ++ req->fhdwelltime ++ req->fhhopset ++ req->fhhoppattern ++ req->fhhopindex ++ req->cfpdurremaining ++*/ ++ ++ result = 0; ++ req->resultcode.data = P80211ENUM_resultcode_success; ++ ++ exit: ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_start ++* ++* Start a BSS. Any station can do this for IBSS, only AP for ESS. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++int prism2mgmt_start(wlandevice_t *wlandev, void *msgp) ++{ ++ int result = 0; ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_dot11req_start_t *msg = msgp; ++ ++ p80211pstrd_t *pstr; ++ u8 bytebuf[80]; ++ hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*)bytebuf; ++ u16 word; ++ DBFENTER; ++ ++ wlandev->macmode = WLAN_MACMODE_NONE; ++ ++ /* Set the SSID */ ++ memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); ++ ++ /*** ADHOC IBSS ***/ ++ /* see if current f/w is less than 8c3 */ ++ if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, ++ hw->ident_sta_fw.variant) < ++ HFA384x_FIRMWARE_VERSION(0,8,3)) { ++ /* Ad-Hoc not quite supported on Prism2 */ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ msg->resultcode.data = P80211ENUM_resultcode_not_supported; ++ goto done; ++ } ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ ++ /*** STATION ***/ ++ /* Set the REQUIRED config items */ ++ /* SSID */ ++ pstr = (p80211pstrd_t*)&(msg->ssid.data); ++ prism2mgmt_pstr2bytestr(p2bytestr, pstr); ++ result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID, ++ bytebuf, HFA384x_RID_CNFOWNSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set CnfOwnSSID\n"); ++ goto failed; ++ } ++ result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID, ++ bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set CnfDesiredSSID\n"); ++ goto failed; ++ } ++ ++ /* bsstype - we use the default in the ap firmware */ ++ /* IBSS port */ ++ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0); ++ ++ /* beacon period */ ++ word = msg->beaconperiod.data; ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNint, word); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set beacon period=%d.\n", word); ++ goto failed; ++ } ++ ++ /* dschannel */ ++ word = msg->dschannel.data; ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set channel=%d.\n", word); ++ goto failed; ++ } ++ /* Basic rates */ ++ word = p80211rate_to_p2bit(msg->basicrate1.data); ++ if ( msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate2.data); ++ } ++ if ( msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate3.data); ++ } ++ if ( msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate4.data); ++ } ++ if ( msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate5.data); ++ } ++ if ( msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate6.data); ++ } ++ if ( msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate7.data); ++ } ++ if ( msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->basicrate8.data); ++ } ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set basicrates=%d.\n", word); ++ goto failed; ++ } ++ ++ /* Operational rates (supprates and txratecontrol) */ ++ word = p80211rate_to_p2bit(msg->operationalrate1.data); ++ if ( msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate2.data); ++ } ++ if ( msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate3.data); ++ } ++ if ( msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate4.data); ++ } ++ if ( msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate5.data); ++ } ++ if ( msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate6.data); ++ } ++ if ( msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate7.data); ++ } ++ if ( msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok ) { ++ word |= p80211rate_to_p2bit(msg->operationalrate8.data); ++ } ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set supprates=%d.\n", word); ++ goto failed; ++ } ++ ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to set txrates=%d.\n", word); ++ goto failed; ++ } ++ ++ /* Set the macmode so the frame setup code knows what to do */ ++ if ( msg->bsstype.data == P80211ENUM_bsstype_independent ) { ++ wlandev->macmode = WLAN_MACMODE_IBSS_STA; ++ /* lets extend the data length a bit */ ++ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304); ++ } ++ ++ /* Enable the Port */ ++ result = hfa384x_drvr_enable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result); ++ goto failed; ++ } ++ ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ ++ goto done; ++failed: ++ WLAN_LOG_DEBUG(1, "Failed to set a config option, result=%d\n", result); ++ msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; ++ ++done: ++ result = 0; ++ ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_readpda ++* ++* Collect the PDA data and put it in the message. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++----------------------------------------------------------------*/ ++int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_p2req_readpda_t *msg = msgp; ++ int result; ++ DBFENTER; ++ ++ /* We only support collecting the PDA when in the FWLOAD ++ * state. ++ */ ++ if (wlandev->msdstate != WLAN_MSD_FWLOAD) { ++ WLAN_LOG_ERROR( ++ "PDA may only be read " ++ "in the fwload state.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ } else { ++ /* Call drvr_readpda(), it handles the auxport enable ++ * and validating the returned PDA. ++ */ ++ result = hfa384x_drvr_readpda( ++ hw, ++ msg->pda.data, ++ HFA384x_PDA_LEN_MAX); ++ if (result) { ++ WLAN_LOG_ERROR( ++ "hfa384x_drvr_readpda() failed, " ++ "result=%d\n", ++ result); ++ ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ msg->resultcode.status = ++ P80211ENUM_msgitem_status_data_ok; ++ DBFEXIT; ++ return 0; ++ } ++ msg->pda.status = P80211ENUM_msgitem_status_data_ok; ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_ramdl_state ++* ++* Establishes the beginning/end of a card RAM download session. ++* ++* It is expected that the ramdl_write() function will be called ++* one or more times between the 'enable' and 'disable' calls to ++* this function. ++* ++* Note: This function should not be called when a mac comm port ++* is active. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++----------------------------------------------------------------*/ ++int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_p2req_ramdl_state_t *msg = msgp; ++ DBFENTER; ++ ++ if (wlandev->msdstate != WLAN_MSD_FWLOAD) { ++ WLAN_LOG_ERROR( ++ "ramdl_state(): may only be called " ++ "in the fwload state.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ DBFEXIT; ++ return 0; ++ } ++ ++ /* ++ ** Note: Interrupts are locked out if this is an AP and are NOT ++ ** locked out if this is a station. ++ */ ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ if ( msg->enable.data == P80211ENUM_truth_true ) { ++ if ( hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data) ) { ++ msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; ++ } else { ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ } ++ } else { ++ hfa384x_drvr_ramdl_disable(hw); ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_ramdl_write ++* ++* Writes a buffer to the card RAM using the download state. This ++* is for writing code to card RAM. To just read or write raw data ++* use the aux functions. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++----------------------------------------------------------------*/ ++int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_p2req_ramdl_write_t *msg = msgp; ++ u32 addr; ++ u32 len; ++ u8 *buf; ++ DBFENTER; ++ ++ if (wlandev->msdstate != WLAN_MSD_FWLOAD) { ++ WLAN_LOG_ERROR( ++ "ramdl_write(): may only be called " ++ "in the fwload state.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ DBFEXIT; ++ return 0; ++ } ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ /* first validate the length */ ++ if ( msg->len.data > sizeof(msg->data.data) ) { ++ msg->resultcode.status = P80211ENUM_resultcode_invalid_parameters; ++ return 0; ++ } ++ /* call the hfa384x function to do the write */ ++ addr = msg->addr.data; ++ len = msg->len.data; ++ buf = msg->data.data; ++ if ( hfa384x_drvr_ramdl_write(hw, addr, buf, len) ) { ++ msg->resultcode.data = P80211ENUM_resultcode_refused; ++ ++ } ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_flashdl_state ++* ++* Establishes the beginning/end of a card Flash download session. ++* ++* It is expected that the flashdl_write() function will be called ++* one or more times between the 'enable' and 'disable' calls to ++* this function. ++* ++* Note: This function should not be called when a mac comm port ++* is active. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++----------------------------------------------------------------*/ ++int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp) ++{ ++ int result = 0; ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_p2req_flashdl_state_t *msg = msgp; ++ DBFENTER; ++ ++ if (wlandev->msdstate != WLAN_MSD_FWLOAD) { ++ WLAN_LOG_ERROR( ++ "flashdl_state(): may only be called " ++ "in the fwload state.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ DBFEXIT; ++ return 0; ++ } ++ ++ /* ++ ** Note: Interrupts are locked out if this is an AP and are NOT ++ ** locked out if this is a station. ++ */ ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ if ( msg->enable.data == P80211ENUM_truth_true ) { ++ if ( hfa384x_drvr_flashdl_enable(hw) ) { ++ msg->resultcode.data = P80211ENUM_resultcode_implementation_failure; ++ } else { ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ } ++ } else { ++ hfa384x_drvr_flashdl_disable(hw); ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ /* NOTE: At this point, the MAC is in the post-reset ++ * state and the driver is in the fwload state. ++ * We need to get the MAC back into the fwload ++ * state. To do this, we set the nsdstate to HWPRESENT ++ * and then call the ifstate function to redo everything ++ * that got us into the fwload state. ++ */ ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload); ++ if (result != P80211ENUM_resultcode_success) { ++ WLAN_LOG_ERROR("prism2sta_ifstate(fwload) failed," ++ "P80211ENUM_resultcode=%d\n", result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ result = -1; ++ } ++ } ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_flashdl_write ++* ++* ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++----------------------------------------------------------------*/ ++int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ p80211msg_p2req_flashdl_write_t *msg = msgp; ++ u32 addr; ++ u32 len; ++ u8 *buf; ++ DBFENTER; ++ ++ if (wlandev->msdstate != WLAN_MSD_FWLOAD) { ++ WLAN_LOG_ERROR( ++ "flashdl_write(): may only be called " ++ "in the fwload state.\n"); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ DBFEXIT; ++ return 0; ++ } ++ ++ /* ++ ** Note: Interrupts are locked out if this is an AP and are NOT ++ ** locked out if this is a station. ++ */ ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ /* first validate the length */ ++ if ( msg->len.data > sizeof(msg->data.data) ) { ++ msg->resultcode.status = ++ P80211ENUM_resultcode_invalid_parameters; ++ return 0; ++ } ++ /* call the hfa384x function to do the write */ ++ addr = msg->addr.data; ++ len = msg->len.data; ++ buf = msg->data.data; ++ if ( hfa384x_drvr_flashdl_write(hw, addr, buf, len) ) { ++ msg->resultcode.data = P80211ENUM_resultcode_refused; ++ ++ } ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ ++ DBFEXIT; ++ return 0; ++} ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_autojoin ++* ++* Associate with an ESS. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ int result = 0; ++ u16 reg; ++ u16 port_type; ++ p80211msg_lnxreq_autojoin_t *msg = msgp; ++ p80211pstrd_t *pstr; ++ u8 bytebuf[256]; ++ hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*)bytebuf; ++ DBFENTER; ++ ++ wlandev->macmode = WLAN_MACMODE_NONE; ++ ++ /* Set the SSID */ ++ memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); ++ ++ /* Disable the Port */ ++ hfa384x_drvr_disable(hw, 0); ++ ++ /*** STATION ***/ ++ /* Set the TxRates */ ++ hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, 0x000f); ++ ++ /* Set the auth type */ ++ if ( msg->authtype.data == P80211ENUM_authalg_sharedkey ) { ++ reg = HFA384x_CNFAUTHENTICATION_SHAREDKEY; ++ } else { ++ reg = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; ++ } ++ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, reg); ++ ++ /* Set the ssid */ ++ memset(bytebuf, 0, 256); ++ pstr = (p80211pstrd_t*)&(msg->ssid.data); ++ prism2mgmt_pstr2bytestr(p2bytestr, pstr); ++ result = hfa384x_drvr_setconfig( ++ hw, HFA384x_RID_CNFDESIREDSSID, ++ bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN); ++#if 0 ++ /* we can use the new-fangled auto-unknown mode if the firmware ++ is 1.3.3 or newer */ ++ if (HFA384x_FIRMARE_VERSION(hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, ++ hw->ident_sta_fw.variant) >= ++ HFA384x_FIRMWARE_VERSION(1,3,3)) { ++ /* Set up the IBSS options */ ++ reg = HFA384x_CREATEIBSS_JOINESS_JOINCREATEIBSS; ++ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CREATEIBSS, reg); ++ ++ /* Set the PortType */ ++ port_type = HFA384x_PORTTYPE_IBSS; ++ } else { ++ port_type = HFA384x_PORTTYPE_BSS; ++ } ++#else ++ port_type = HFA384x_PORTTYPE_BSS; ++#endif ++ /* Set the PortType */ ++ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, port_type); ++ ++ /* Enable the Port */ ++ hfa384x_drvr_enable(hw, 0); ++ ++ /* Set the resultcode */ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_wlansniff ++* ++* Start or stop sniffing. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) ++{ ++ int result = 0; ++ p80211msg_lnxreq_wlansniff_t *msg = msgp; ++ ++ hfa384x_t *hw = wlandev->priv; ++ u16 word; ++ ++ DBFENTER; ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ switch (msg->enable.data) ++ { ++ case P80211ENUM_truth_false: ++ /* Confirm that we're in monitor mode */ ++ if ( wlandev->netdev->type == ARPHRD_ETHER ) { ++ msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; ++ result = 0; ++ goto exit; ++ } ++ /* Disable monitor mode */ ++ result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to disable monitor mode, result=%d\n", ++ result); ++ goto failed; ++ } ++ /* Disable port 0 */ ++ result = hfa384x_drvr_disable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to disable port 0 after sniffing, result=%d\n", ++ result); ++ goto failed; ++ } ++ /* Clear the driver state */ ++ wlandev->netdev->type = ARPHRD_ETHER; ++ ++ /* Restore the wepflags */ ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFWEPFLAGS, ++ hw->presniff_wepflags); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to restore wepflags=0x%04x, result=%d\n", ++ hw->presniff_wepflags, ++ result); ++ goto failed; ++ } ++ ++ /* Set the port to its prior type and enable (if necessary) */ ++ if (hw->presniff_port_type != 0 ) { ++ word = hw->presniff_port_type; ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFPORTTYPE, word); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to restore porttype, result=%d\n", ++ result); ++ goto failed; ++ } ++ ++ /* Enable the port */ ++ result = hfa384x_drvr_enable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, "failed to enable port to presniff setting, result=%d\n", result); ++ goto failed; ++ } ++ } else { ++ result = hfa384x_drvr_disable(hw, 0); ++ ++ } ++ ++ WLAN_LOG_INFO("monitor mode disabled\n"); ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ result = 0; ++ goto exit; ++ break; ++ case P80211ENUM_truth_true: ++ /* Disable the port (if enabled), only check Port 0 */ ++ if ( hw->port_enabled[0]) { ++ if (wlandev->netdev->type == ARPHRD_ETHER) { ++ /* Save macport 0 state */ ++ result = hfa384x_drvr_getconfig16(hw, ++ HFA384x_RID_CNFPORTTYPE, ++ &(hw->presniff_port_type)); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1,"failed to read porttype, result=%d\n", result); ++ goto failed; ++ } ++ /* Save the wepflags state */ ++ result = hfa384x_drvr_getconfig16(hw, ++ HFA384x_RID_CNFWEPFLAGS, ++ &(hw->presniff_wepflags)); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1,"failed to read wepflags, result=%d\n", result); ++ goto failed; ++ } ++ hfa384x_drvr_stop(hw); ++ result = hfa384x_drvr_start(hw); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to restart the card for sniffing, result=%d\n", ++ result); ++ goto failed; ++ } ++ } else { ++ /* Disable the port */ ++ result = hfa384x_drvr_disable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to enable port for sniffing, result=%d\n", ++ result); ++ goto failed; ++ } ++ } ++ } else { ++ hw->presniff_port_type = 0; ++ } ++ ++ /* Set the channel we wish to sniff */ ++ word = msg->channel.data; ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFOWNCHANNEL, word); ++ hw->sniff_channel=word; ++ ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to set channel %d, result=%d\n", ++ word, ++ result); ++ goto failed; ++ } ++ ++ /* Now if we're already sniffing, we can skip the rest */ ++ if (wlandev->netdev->type != ARPHRD_ETHER) { ++ /* Set the port type to pIbss */ ++ word = HFA384x_PORTTYPE_PSUEDOIBSS; ++ result = hfa384x_drvr_setconfig16(hw, ++ HFA384x_RID_CNFPORTTYPE, word); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to set porttype %d, result=%d\n", ++ word, ++ result); ++ goto failed; ++ } ++ if ((msg->keepwepflags.status == P80211ENUM_msgitem_status_data_ok) && (msg->keepwepflags.data != P80211ENUM_truth_true)) { ++ /* Set the wepflags for no decryption */ ++ word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | ++ HFA384x_WEPFLAGS_DISABLE_RXCRYPT; ++ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFWEPFLAGS, word); ++ } ++ ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to set wepflags=0x%04x, result=%d\n", ++ word, ++ result); ++ goto failed; ++ } ++ } ++ ++ /* Do we want to strip the FCS in monitor mode? */ ++ if ((msg->stripfcs.status == P80211ENUM_msgitem_status_data_ok) && (msg->stripfcs.data == P80211ENUM_truth_true)) { ++ hw->sniff_fcs = 0; ++ } else { ++ hw->sniff_fcs = 1; ++ } ++ ++ /* Do we want to truncate the packets? */ ++ if (msg->packet_trunc.status == P80211ENUM_msgitem_status_data_ok) { ++ hw->sniff_truncate = msg->packet_trunc.data; ++ } else { ++ hw->sniff_truncate = 0; ++ } ++ ++ /* Enable the port */ ++ result = hfa384x_drvr_enable(hw, 0); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to enable port for sniffing, result=%d\n", ++ result); ++ goto failed; ++ } ++ /* Enable monitor mode */ ++ result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "failed to enable monitor mode, result=%d\n", ++ result); ++ goto failed; ++ } ++ ++ if (wlandev->netdev->type == ARPHRD_ETHER) { ++ WLAN_LOG_INFO("monitor mode enabled\n"); ++ } ++ ++ /* Set the driver state */ ++ /* Do we want the prism2 header? */ ++ if ((msg->prismheader.status == P80211ENUM_msgitem_status_data_ok) && (msg->prismheader.data == P80211ENUM_truth_true)) { ++ hw->sniffhdr = 0; ++ wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; ++ } else if ((msg->wlanheader.status == P80211ENUM_msgitem_status_data_ok) && (msg->wlanheader.data == P80211ENUM_truth_true)) { ++ hw->sniffhdr = 1; ++ wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; ++ } else { ++ wlandev->netdev->type = ARPHRD_IEEE80211; ++ } ++ ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ result = 0; ++ goto exit; ++ break; ++ default: ++ msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; ++ result = 0; ++ goto exit; ++ break; ++ } ++ ++failed: ++ msg->resultcode.data = P80211ENUM_resultcode_refused; ++ result = 0; ++exit: ++ ++ DBFEXIT; ++ return result; ++} +--- /dev/null ++++ b/drivers/staging/wlan-ng/prism2mgmt.h +@@ -0,0 +1,155 @@ ++/* prism2mgmt.h ++* ++* Declares the mgmt command handler functions ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file contains the constants and data structures for interaction ++* with the hfa384x Wireless LAN (WLAN) Media Access Contoller (MAC). ++* The hfa384x is a portion of the Harris PRISM(tm) WLAN chipset. ++* ++* [Implementation and usage notes] ++* ++* [References] ++* CW10 Programmer's Manual v1.5 ++* IEEE 802.11 D10.0 ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _PRISM2MGMT_H ++#define _PRISM2MGMT_H ++ ++ ++/*=============================================================*/ ++/*------ Constants --------------------------------------------*/ ++ ++/*=============================================================*/ ++/*------ Macros -----------------------------------------------*/ ++ ++/*=============================================================*/ ++/*------ Types and their related constants --------------------*/ ++ ++/*=============================================================*/ ++/*------ Static variable externs ------------------------------*/ ++ ++extern int prism2_debug; ++extern int prism2_reset_holdtime; ++extern int prism2_reset_settletime; ++/*=============================================================*/ ++/*--- Function Declarations -----------------------------------*/ ++/*=============================================================*/ ++ ++u32 ++prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate); ++ ++void ++prism2sta_ev_dtim(wlandevice_t *wlandev); ++void ++prism2sta_ev_infdrop(wlandevice_t *wlandev); ++void ++prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++void ++prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status); ++void ++prism2sta_ev_tx(wlandevice_t *wlandev, u16 status); ++void ++prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb); ++void ++prism2sta_ev_alloc(wlandevice_t *wlandev); ++ ++int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_start(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_ramdl_write(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp); ++int prism2mgmt_autojoin(wlandevice_t *wlandev, void *msgp); ++ ++/*--------------------------------------------------------------- ++* conversion functions going between wlan message data types and ++* Prism2 data types ++---------------------------------------------------------------*/ ++/* byte area conversion functions*/ ++void prism2mgmt_pstr2bytearea(u8 *bytearea, p80211pstrd_t *pstr); ++void prism2mgmt_bytearea2pstr(u8 *bytearea, p80211pstrd_t *pstr, int len); ++ ++/* byte string conversion functions*/ ++void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr); ++void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr); ++ ++/* integer conversion functions */ ++void prism2mgmt_prism2int2p80211int(u16 *prism2int, u32 *wlanint); ++void prism2mgmt_p80211int2prism2int(u16 *prism2int, u32 *wlanint); ++ ++/* enumerated integer conversion functions */ ++void prism2mgmt_prism2enum2p80211enum(u16 *prism2enum, u32 *wlanenum, u16 rid); ++void prism2mgmt_p80211enum2prism2enum(u16 *prism2enum, u32 *wlanenum, u16 rid); ++ ++/* functions to convert a bit area to/from an Operational Rate Set */ ++void prism2mgmt_get_oprateset(u16 *rate, p80211pstrd_t *pstr); ++void prism2mgmt_set_oprateset(u16 *rate, p80211pstrd_t *pstr); ++ ++/* functions to convert Group Addresses */ ++void prism2mgmt_get_grpaddr(u32 did, ++ p80211pstrd_t *pstr, hfa384x_t *priv ); ++int prism2mgmt_set_grpaddr(u32 did, ++ u8 *prism2buf, p80211pstrd_t *pstr, hfa384x_t *priv ); ++int prism2mgmt_get_grpaddr_index( u32 did ); ++ ++void prism2sta_processing_defer(struct work_struct *data); ++ ++void prism2sta_commsqual_defer(struct work_struct *data); ++void prism2sta_commsqual_timer(unsigned long data); ++ ++/*=============================================================*/ ++/*--- Inline Function Definitions (if supported) --------------*/ ++/*=============================================================*/ ++ ++ ++ ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/prism2mib.c +@@ -0,0 +1,1135 @@ ++/* src/prism2/driver/prism2mib.c ++* ++* Management request for mibset/mibget ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* The functions in this file handle the mibset/mibget management ++* functions. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++#define WLAN_DBVAR prism2_debug ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211mgmt.h" ++#include "p80211conv.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211metadef.h" ++#include "p80211metastruct.h" ++#include "hfa384x.h" ++#include "prism2mgmt.h" ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++#define MIB_TMP_MAXLEN 200 /* Max length of RID record (in bytes). */ ++ ++/*================================================================*/ ++/* Local Types */ ++ ++#define F_STA 0x1 /* MIB is supported on stations. */ ++#define F_READ 0x2 /* MIB may be read. */ ++#define F_WRITE 0x4 /* MIB may be written. */ ++ ++typedef struct mibrec ++{ ++ u32 did; ++ u16 flag; ++ u16 parm1; ++ u16 parm2; ++ u16 parm3; ++ int (*func)(struct mibrec *mib, ++ int isget, ++ wlandevice_t *wlandev, ++ hfa384x_t *hw, ++ p80211msg_dot11req_mibset_t *msg, ++ void *data); ++} mibrec_t; ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++static int prism2mib_bytearea2pstr( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_uint32( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_flag( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_wepdefaultkey( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_privacyinvoked( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_excludeunencrypted( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_fragmentationthreshold( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++static int prism2mib_priv( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data); ++ ++/*================================================================*/ ++/* Local Static Definitions */ ++ ++static mibrec_t mibtab[] = { ++ ++ /* dot11smt MIB's */ ++ { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0, ++ F_STA | F_WRITE, ++ HFA384x_RID_CNFWEPDEFAULTKEY0, 0, 0, ++ prism2mib_wepdefaultkey }, ++ { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1, ++ F_STA | F_WRITE, ++ HFA384x_RID_CNFWEPDEFAULTKEY1, 0, 0, ++ prism2mib_wepdefaultkey }, ++ { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2, ++ F_STA | F_WRITE, ++ HFA384x_RID_CNFWEPDEFAULTKEY2, 0, 0, ++ prism2mib_wepdefaultkey }, ++ { DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3, ++ F_STA | F_WRITE, ++ HFA384x_RID_CNFWEPDEFAULTKEY3, 0, 0, ++ prism2mib_wepdefaultkey }, ++ { DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_PRIVINVOKED, 0, ++ prism2mib_privacyinvoked }, ++ { DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_CNFWEPDEFAULTKEYID, 0, 0, ++ prism2mib_uint32 }, ++ { DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_CNFWEPFLAGS, HFA384x_WEPFLAGS_EXCLUDE, 0, ++ prism2mib_excludeunencrypted }, ++ ++ /* dot11mac MIB's */ ++ ++ { DIDmib_dot11mac_dot11OperationTable_dot11MACAddress, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_CNFOWNMACADDR, HFA384x_RID_CNFOWNMACADDR_LEN, 0, ++ prism2mib_bytearea2pstr }, ++ { DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_RTSTHRESH, 0, 0, ++ prism2mib_uint32 }, ++ { DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit, ++ F_STA | F_READ, ++ HFA384x_RID_SHORTRETRYLIMIT, 0, 0, ++ prism2mib_uint32 }, ++ { DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit, ++ F_STA | F_READ, ++ HFA384x_RID_LONGRETRYLIMIT, 0, 0, ++ prism2mib_uint32 }, ++ { DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_FRAGTHRESH, 0, 0, ++ prism2mib_fragmentationthreshold }, ++ { DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime, ++ F_STA | F_READ, ++ HFA384x_RID_MAXTXLIFETIME, 0, 0, ++ prism2mib_uint32 }, ++ ++ /* dot11phy MIB's */ ++ ++ { DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel, ++ F_STA | F_READ, ++ HFA384x_RID_CURRENTCHANNEL, 0, 0, ++ prism2mib_uint32 }, ++ { DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_TXPOWERMAX, 0, 0, ++ prism2mib_uint32 }, ++ ++ /* p2Static MIB's */ ++ ++ { DIDmib_p2_p2Static_p2CnfPortType, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_CNFPORTTYPE, 0, 0, ++ prism2mib_uint32 }, ++ ++ /* p2MAC MIB's */ ++ ++ { DIDmib_p2_p2MAC_p2CurrentTxRate, ++ F_STA | F_READ, ++ HFA384x_RID_CURRENTTXRATE, 0, 0, ++ prism2mib_uint32 }, ++ ++ /* And finally, lnx mibs */ ++ { DIDmib_lnx_lnxConfigTable_lnxRSNAIE, ++ F_STA | F_READ | F_WRITE, ++ HFA384x_RID_CNFWPADATA, 0, 0, ++ prism2mib_priv }, ++ { 0, 0, 0, 0, 0, NULL}}; ++ ++/*================================================================*/ ++/* Function Definitions */ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_mibset_mibget ++* ++* Set the value of a mib item. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* 0 success and done ++* <0 success, but we're waiting for something to finish. ++* >0 an error occurred while handling the message. ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++ ++int prism2mgmt_mibset_mibget(wlandevice_t *wlandev, void *msgp) ++{ ++ hfa384x_t *hw = wlandev->priv; ++ int result, isget; ++ mibrec_t *mib; ++ ++ u16 which; ++ ++ p80211msg_dot11req_mibset_t *msg = msgp; ++ p80211itemd_t *mibitem; ++ ++ DBFENTER; ++ ++ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; ++ msg->resultcode.data = P80211ENUM_resultcode_success; ++ ++ /* ++ ** Determine if this is an Access Point or a station. ++ */ ++ ++ which = F_STA; ++ ++ /* ++ ** Find the MIB in the MIB table. Note that a MIB may be in the ++ ** table twice...once for an AP and once for a station. Make sure ++ ** to get the correct one. Note that DID=0 marks the end of the ++ ** MIB table. ++ */ ++ ++ mibitem = (p80211itemd_t *) msg->mibattribute.data; ++ ++ for (mib = mibtab; mib->did != 0; mib++) ++ if (mib->did == mibitem->did && (mib->flag & which)) ++ break; ++ ++ if (mib->did == 0) { ++ msg->resultcode.data = P80211ENUM_resultcode_not_supported; ++ goto done; ++ } ++ ++ /* ++ ** Determine if this is a "mibget" or a "mibset". If this is a ++ ** "mibget", then make sure that the MIB may be read. Otherwise, ++ ** this is a "mibset" so make make sure that the MIB may be written. ++ */ ++ ++ isget = (msg->msgcode == DIDmsg_dot11req_mibget); ++ ++ if (isget) { ++ if (!(mib->flag & F_READ)) { ++ msg->resultcode.data = ++ P80211ENUM_resultcode_cant_get_writeonly_mib; ++ goto done; ++ } ++ } else { ++ if (!(mib->flag & F_WRITE)) { ++ msg->resultcode.data = ++ P80211ENUM_resultcode_cant_set_readonly_mib; ++ goto done; ++ } ++ } ++ ++ /* ++ ** Execute the MIB function. If things worked okay, then make ++ ** sure that the MIB function also worked okay. If so, and this ++ ** is a "mibget", then the status value must be set for both the ++ ** "mibattribute" parameter and the mib item within the data ++ ** portion of the "mibattribute". ++ */ ++ ++ result = mib->func(mib, isget, wlandev, hw, msg, ++ (void *) mibitem->data); ++ ++ if (msg->resultcode.data == P80211ENUM_resultcode_success) { ++ if (result != 0) { ++ WLAN_LOG_DEBUG(1, "get/set failure, result=%d\n", ++ result); ++ msg->resultcode.data = ++ P80211ENUM_resultcode_implementation_failure; ++ } else { ++ if (isget) { ++ msg->mibattribute.status = ++ P80211ENUM_msgitem_status_data_ok; ++ mibitem->status = ++ P80211ENUM_msgitem_status_data_ok; ++ } ++ } ++ } ++ ++done: ++ DBFEXIT; ++ ++ return(0); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_bytearea2pstr ++* ++* Get/set pstr data to/from a byte area. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Number of bytes of RID data. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_bytearea2pstr( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ p80211pstrd_t *pstr = (p80211pstrd_t*) data; ++ u8 bytebuf[MIB_TMP_MAXLEN]; ++ ++ DBFENTER; ++ ++ if (isget) { ++ result = hfa384x_drvr_getconfig(hw, mib->parm1, bytebuf, mib->parm2); ++ prism2mgmt_bytearea2pstr(bytebuf, pstr, mib->parm2); ++ } else { ++ memset(bytebuf, 0, mib->parm2); ++ prism2mgmt_pstr2bytearea(bytebuf, pstr); ++ result = hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, mib->parm2); ++ } ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_uint32 ++* ++* Get/set uint32 data. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Not used. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_uint32( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ u32 *uint32 = (u32*) data; ++ u8 bytebuf[MIB_TMP_MAXLEN]; ++ u16 *wordbuf = (u16*) bytebuf; ++ ++ DBFENTER; ++ ++ if (isget) { ++ result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); ++ *uint32 = *wordbuf; ++ /* [MSM] Removed, getconfig16 returns the value in host order. ++ * prism2mgmt_prism2int2p80211int(wordbuf, uint32); ++ */ ++ } else { ++ /* [MSM] Removed, setconfig16 expects host order. ++ * prism2mgmt_p80211int2prism2int(wordbuf, uint32); ++ */ ++ *wordbuf = *uint32; ++ result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); ++ } ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_flag ++* ++* Get/set a flag. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Bit to get/set. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_flag( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ u32 *uint32 = (u32*) data; ++ u8 bytebuf[MIB_TMP_MAXLEN]; ++ u16 *wordbuf = (u16*) bytebuf; ++ u32 flags; ++ ++ DBFENTER; ++ ++ result = hfa384x_drvr_getconfig16(hw, mib->parm1, wordbuf); ++ if (result == 0) { ++ /* [MSM] Removed, getconfig16 returns the value in host order. ++ * prism2mgmt_prism2int2p80211int(wordbuf, &flags); ++ */ ++ flags = *wordbuf; ++ if (isget) { ++ *uint32 = (flags & mib->parm2) ? ++ P80211ENUM_truth_true : P80211ENUM_truth_false; ++ } else { ++ if ((*uint32) == P80211ENUM_truth_true) ++ flags |= mib->parm2; ++ else ++ flags &= ~mib->parm2; ++ /* [MSM] Removed, setconfig16 expects host order. ++ * prism2mgmt_p80211int2prism2int(wordbuf, &flags); ++ */ ++ *wordbuf = flags; ++ result = hfa384x_drvr_setconfig16(hw, mib->parm1, *wordbuf); ++ } ++ } ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_wepdefaultkey ++* ++* Get/set WEP default keys. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Number of bytes of RID data. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_wepdefaultkey( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ p80211pstrd_t *pstr = (p80211pstrd_t*) data; ++ u8 bytebuf[MIB_TMP_MAXLEN]; ++ u16 len; ++ ++ DBFENTER; ++ ++ if (isget) { ++ result = 0; /* Should never happen. */ ++ } else { ++ len = (pstr->len > 5) ? HFA384x_RID_CNFWEP128DEFAULTKEY_LEN : ++ HFA384x_RID_CNFWEPDEFAULTKEY_LEN; ++ memset(bytebuf, 0, len); ++ prism2mgmt_pstr2bytearea(bytebuf, pstr); ++ result = hfa384x_drvr_setconfig(hw, mib->parm1, bytebuf, len); ++ } ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_privacyinvoked ++* ++* Get/set the dot11PrivacyInvoked value. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Bit value for PrivacyInvoked flag. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_privacyinvoked( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ ++ DBFENTER; ++ ++ if (wlandev->hostwep & HOSTWEP_DECRYPT) { ++ if (wlandev->hostwep & HOSTWEP_DECRYPT) ++ mib->parm2 |= HFA384x_WEPFLAGS_DISABLE_RXCRYPT; ++ if (wlandev->hostwep & HOSTWEP_ENCRYPT) ++ mib->parm2 |= HFA384x_WEPFLAGS_DISABLE_TXCRYPT; ++ } ++ ++ result = prism2mib_flag(mib, isget, wlandev, hw, msg, data); ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_excludeunencrypted ++* ++* Get/set the dot11ExcludeUnencrypted value. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Bit value for ExcludeUnencrypted flag. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_excludeunencrypted( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ ++ DBFENTER; ++ ++ result = prism2mib_flag(mib, isget, wlandev, hw, msg, data); ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_fragmentationthreshold ++* ++* Get/set the fragmentation threshold. ++* ++* MIB record parameters: ++* parm1 Prism2 RID value. ++* parm2 Not used. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_fragmentationthreshold( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ int result; ++ u32 *uint32 = (u32*) data; ++ ++ DBFENTER; ++ ++ if (!isget) ++ if ((*uint32) % 2) { ++ WLAN_LOG_WARNING("Attempt to set odd number " ++ "FragmentationThreshold\n"); ++ msg->resultcode.data = P80211ENUM_resultcode_not_supported; ++ return(0); ++ } ++ ++ result = prism2mib_uint32(mib, isget, wlandev, hw, msg, data); ++ ++ DBFEXIT; ++ return(result); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mib_priv ++* ++* Get/set values in the "priv" data structure. ++* ++* MIB record parameters: ++* parm1 Not used. ++* parm2 Not used. ++* parm3 Not used. ++* ++* Arguments: ++* mib MIB record. ++* isget MIBGET/MIBSET flag. ++* wlandev wlan device structure. ++* priv "priv" structure. ++* hw "hw" structure. ++* msg Message structure. ++* data Data buffer. ++* ++* Returns: ++* 0 - Success. ++* ~0 - Error. ++* ++----------------------------------------------------------------*/ ++ ++static int prism2mib_priv( ++mibrec_t *mib, ++int isget, ++wlandevice_t *wlandev, ++hfa384x_t *hw, ++p80211msg_dot11req_mibset_t *msg, ++void *data) ++{ ++ p80211pstrd_t *pstr = (p80211pstrd_t*) data; ++ ++ int result; ++ ++ DBFENTER; ++ ++ switch (mib->did) { ++ case DIDmib_lnx_lnxConfigTable_lnxRSNAIE: { ++ hfa384x_WPAData_t wpa; ++ if (isget) { ++ hfa384x_drvr_getconfig( hw, HFA384x_RID_CNFWPADATA, ++ (u8 *) &wpa, sizeof(wpa)); ++ pstr->len = hfa384x2host_16(wpa.datalen); ++ memcpy(pstr->data, wpa.data, pstr->len); ++ } else { ++ wpa.datalen = host2hfa384x_16(pstr->len); ++ memcpy(wpa.data, pstr->data, pstr->len); ++ ++ result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFWPADATA, ++ (u8 *) &wpa, sizeof(wpa)); ++ } ++ break; ++ } ++ default: ++ WLAN_LOG_ERROR("Unhandled DID 0x%08x\n", mib->did); ++ } ++ ++ DBFEXIT; ++ return(0); ++} ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_pstr2bytestr ++* ++* Convert the pstr data in the WLAN message structure into an hfa384x ++* byte string format. ++* ++* Arguments: ++* bytestr hfa384x byte string data type ++* pstr wlan message data ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++ ++void prism2mgmt_pstr2bytestr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) ++{ ++ DBFENTER; ++ ++ bytestr->len = host2hfa384x_16((u16)(pstr->len)); ++ memcpy(bytestr->data, pstr->data, pstr->len); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_pstr2bytearea ++* ++* Convert the pstr data in the WLAN message structure into an hfa384x ++* byte area format. ++* ++* Arguments: ++* bytearea hfa384x byte area data type ++* pstr wlan message data ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++ ++void prism2mgmt_pstr2bytearea(u8 *bytearea, p80211pstrd_t *pstr) ++{ ++ DBFENTER; ++ ++ memcpy(bytearea, pstr->data, pstr->len); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_bytestr2pstr ++* ++* Convert the data in an hfa384x byte string format into a ++* pstr in the WLAN message. ++* ++* Arguments: ++* bytestr hfa384x byte string data type ++* msg wlan message ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++ ++void prism2mgmt_bytestr2pstr(hfa384x_bytestr_t *bytestr, p80211pstrd_t *pstr) ++{ ++ DBFENTER; ++ ++ pstr->len = (u8)(hfa384x2host_16((u16)(bytestr->len))); ++ memcpy(pstr->data, bytestr->data, pstr->len); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_bytearea2pstr ++* ++* Convert the data in an hfa384x byte area format into a pstr ++* in the WLAN message. ++* ++* Arguments: ++* bytearea hfa384x byte area data type ++* msg wlan message ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++ ++void prism2mgmt_bytearea2pstr(u8 *bytearea, p80211pstrd_t *pstr, int len) ++{ ++ DBFENTER; ++ ++ pstr->len = (u8)len; ++ memcpy(pstr->data, bytearea, len); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_prism2int2p80211int ++* ++* Convert an hfa384x integer into a wlan integer ++* ++* Arguments: ++* prism2enum pointer to hfa384x integer ++* wlanenum pointer to p80211 integer ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++ ++void prism2mgmt_prism2int2p80211int(u16 *prism2int, u32 *wlanint) ++{ ++ DBFENTER; ++ ++ *wlanint = (u32)hfa384x2host_16(*prism2int); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_p80211int2prism2int ++* ++* Convert a wlan integer into an hfa384x integer ++* ++* Arguments: ++* prism2enum pointer to hfa384x integer ++* wlanenum pointer to p80211 integer ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++ ++void prism2mgmt_p80211int2prism2int(u16 *prism2int, u32 *wlanint) ++{ ++ DBFENTER; ++ ++ *prism2int = host2hfa384x_16((u16)(*wlanint)); ++ DBFEXIT; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_prism2enum2p80211enum ++* ++* Convert the hfa384x enumerated int into a p80211 enumerated int ++* ++* Arguments: ++* prism2enum pointer to hfa384x integer ++* wlanenum pointer to p80211 integer ++* rid hfa384x record id ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++void prism2mgmt_prism2enum2p80211enum(u16 *prism2enum, u32 *wlanenum, u16 rid) ++{ ++ DBFENTER; ++ ++ /* At the moment, the need for this functionality hasn't ++ presented itself. All the wlan enumerated values are ++ a 1-to-1 match against the Prism2 enumerated values*/ ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_p80211enum2prism2enum ++* ++* Convert the p80211 enumerated int into an hfa384x enumerated int ++* ++* Arguments: ++* prism2enum pointer to hfa384x integer ++* wlanenum pointer to p80211 integer ++* rid hfa384x record id ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++void prism2mgmt_p80211enum2prism2enum(u16 *prism2enum, u32 *wlanenum, u16 rid) ++{ ++ DBFENTER; ++ ++ /* At the moment, the need for this functionality hasn't ++ presented itself. All the wlan enumerated values are ++ a 1-to-1 match against the Prism2 enumerated values*/ ++ DBFEXIT; ++ return; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_get_oprateset ++* ++* Convert the hfa384x bit area into a wlan octet string. ++* ++* Arguments: ++* rate Prism2 bit area ++* pstr wlan octet string ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++void prism2mgmt_get_oprateset(u16 *rate, p80211pstrd_t *pstr) ++{ ++ u8 len; ++ u8 *datarate; ++ ++ DBFENTER; ++ ++ len = 0; ++ datarate = pstr->data; ++ ++ /* 1 Mbps */ ++ if ( BIT0 & (*rate) ) { ++ len += (u8)1; ++ *datarate = (u8)2; ++ datarate++; ++ } ++ ++ /* 2 Mbps */ ++ if ( BIT1 & (*rate) ) { ++ len += (u8)1; ++ *datarate = (u8)4; ++ datarate++; ++ } ++ ++ /* 5.5 Mbps */ ++ if ( BIT2 & (*rate) ) { ++ len += (u8)1; ++ *datarate = (u8)11; ++ datarate++; ++ } ++ ++ /* 11 Mbps */ ++ if ( BIT3 & (*rate) ) { ++ len += (u8)1; ++ *datarate = (u8)22; ++ datarate++; ++ } ++ ++ pstr->len = len; ++ ++ DBFEXIT; ++ return; ++} ++ ++ ++ ++/*---------------------------------------------------------------- ++* prism2mgmt_set_oprateset ++* ++* Convert the wlan octet string into an hfa384x bit area. ++* ++* Arguments: ++* rate Prism2 bit area ++* pstr wlan octet string ++* ++* Returns: ++* Nothing ++* ++----------------------------------------------------------------*/ ++void prism2mgmt_set_oprateset(u16 *rate, p80211pstrd_t *pstr) ++{ ++ u8 *datarate; ++ int i; ++ ++ DBFENTER; ++ ++ *rate = 0; ++ ++ datarate = pstr->data; ++ ++ for ( i=0; i < pstr->len; i++, datarate++ ) { ++ switch (*datarate) { ++ case 2: /* 1 Mbps */ ++ *rate |= BIT0; ++ break; ++ case 4: /* 2 Mbps */ ++ *rate |= BIT1; ++ break; ++ case 11: /* 5.5 Mbps */ ++ *rate |= BIT2; ++ break; ++ case 22: /* 11 Mbps */ ++ *rate |= BIT3; ++ break; ++ default: ++ WLAN_LOG_DEBUG(1, "Unrecoginzed Rate of %d\n", ++ *datarate); ++ break; ++ } ++ } ++ ++ DBFEXIT; ++ return; ++} +--- /dev/null ++++ b/drivers/staging/wlan-ng/prism2sta.c +@@ -0,0 +1,2212 @@ ++/* src/prism2/driver/prism2sta.c ++* ++* Implements the station functionality for prism2 ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++* ++* This file implements the module and linux pcmcia routines for the ++* prism2 driver. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++/*================================================================*/ ++/* System Includes */ ++#define WLAN_DBVAR prism2_debug ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "wlan_compat.h" ++ ++/*================================================================*/ ++/* Project Includes */ ++ ++#include "p80211types.h" ++#include "p80211hdr.h" ++#include "p80211mgmt.h" ++#include "p80211conv.h" ++#include "p80211msg.h" ++#include "p80211netdev.h" ++#include "p80211req.h" ++#include "p80211metadef.h" ++#include "p80211metastruct.h" ++#include "hfa384x.h" ++#include "prism2mgmt.h" ++ ++/*================================================================*/ ++/* Local Constants */ ++ ++/*================================================================*/ ++/* Local Macros */ ++ ++/*================================================================*/ ++/* Local Types */ ++ ++/*================================================================*/ ++/* Local Static Definitions */ ++ ++static char *dev_info = "prism2_usb"; ++ ++static wlandevice_t *create_wlan(void); ++ ++/*----------------------------------------------------------------*/ ++/* --Module Parameters */ ++ ++int prism2_reset_holdtime=30; /* Reset hold time in ms */ ++int prism2_reset_settletime=100; /* Reset settle time in ms */ ++ ++static int prism2_doreset=0; /* Do a reset at init? */ ++ ++#ifdef WLAN_INCLUDE_DEBUG ++int prism2_debug=0; ++module_param( prism2_debug, int, 0644); ++MODULE_PARM_DESC(prism2_debug, "prism2 debugging"); ++#endif ++ ++module_param( prism2_doreset, int, 0644); ++MODULE_PARM_DESC(prism2_doreset, "Issue a reset on initialization"); ++ ++module_param( prism2_reset_holdtime, int, 0644); ++MODULE_PARM_DESC( prism2_reset_holdtime, "reset hold time in ms"); ++module_param( prism2_reset_settletime, int, 0644); ++MODULE_PARM_DESC( prism2_reset_settletime, "reset settle time in ms"); ++ ++MODULE_LICENSE("Dual MPL/GPL"); ++ ++/*================================================================*/ ++/* Local Function Declarations */ ++ ++static int prism2sta_open(wlandevice_t *wlandev); ++static int prism2sta_close(wlandevice_t *wlandev); ++static void prism2sta_reset(wlandevice_t *wlandev ); ++static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep); ++static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg); ++static int prism2sta_getcardinfo(wlandevice_t *wlandev); ++static int prism2sta_globalsetup(wlandevice_t *wlandev); ++static int prism2sta_setmulticast(wlandevice_t *wlandev, ++ netdevice_t *dev); ++ ++static void prism2sta_inf_handover( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_tallies( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_hostscanresults( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_scanresults( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_chinforesults( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_linkstatus( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_assocstatus( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_authreq( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_authreq_defer( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++static void prism2sta_inf_psusercnt( ++ wlandevice_t *wlandev, hfa384x_InfFrame_t *inf); ++ ++/*================================================================*/ ++/* Function Definitions */ ++ ++/*---------------------------------------------------------------- ++* dmpmem ++* ++* Debug utility function to dump memory to the kernel debug log. ++* ++* Arguments: ++* buf ptr data we want dumped ++* len length of data ++* ++* Returns: ++* nothing ++* Side effects: ++* ++* Call context: ++* process thread ++* interrupt ++----------------------------------------------------------------*/ ++inline void dmpmem(void *buf, int n) ++{ ++ int c; ++ for ( c= 0; c < n; c++) { ++ if ( (c % 16) == 0 ) printk(KERN_DEBUG"dmp[%d]: ", c); ++ printk("%02x ", ((u8*)buf)[c]); ++ if ( (c % 16) == 15 ) printk("\n"); ++ } ++ if ( (c % 16) != 0 ) printk("\n"); ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_open ++* ++* WLAN device open method. Called from p80211netdev when kernel ++* device open (start) method is called in response to the ++* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP ++* from clear to set. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process thread ++----------------------------------------------------------------*/ ++static int prism2sta_open(wlandevice_t *wlandev) ++{ ++ DBFENTER; ++ ++ /* We don't currently have to do anything else. ++ * The setup of the MAC should be subsequently completed via ++ * the mlme commands. ++ * Higher layers know we're ready from dev->start==1 and ++ * dev->tbusy==0. Our rx path knows to pass up received/ ++ * frames because of dev->flags&IFF_UP is true. ++ */ ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_close ++* ++* WLAN device close method. Called from p80211netdev when kernel ++* device close method is called in response to the ++* SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP ++* from set to clear. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process thread ++----------------------------------------------------------------*/ ++static int prism2sta_close(wlandevice_t *wlandev) ++{ ++ DBFENTER; ++ ++ /* We don't currently have to do anything else. ++ * Higher layers know we're not ready from dev->start==0 and ++ * dev->tbusy==1. Our rx path knows to not pass up received ++ * frames because of dev->flags&IFF_UP is false. ++ */ ++ ++ DBFEXIT; ++ return 0; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_reset ++* ++* Not currently implented. ++* ++* Arguments: ++* wlandev wlan device structure ++* none ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* process thread ++----------------------------------------------------------------*/ ++static void prism2sta_reset(wlandevice_t *wlandev ) ++{ ++ DBFENTER; ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_txframe ++* ++* Takes a frame from p80211 and queues it for transmission. ++* ++* Arguments: ++* wlandev wlan device structure ++* pb packet buffer struct. Contains an 802.11 ++* data frame. ++* p80211_hdr points to the 802.11 header for the packet. ++* Returns: ++* 0 Success and more buffs available ++* 1 Success but no more buffs ++* 2 Allocation failure ++* 4 Buffer full or queue busy ++* ++* Side effects: ++* ++* Call context: ++* process thread ++----------------------------------------------------------------*/ ++static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, ++ p80211_hdr_t *p80211_hdr, ++ p80211_metawep_t *p80211_wep) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ int result; ++ DBFENTER; ++ ++ /* If necessary, set the 802.11 WEP bit */ ++ if ((wlandev->hostwep & (HOSTWEP_PRIVACYINVOKED | HOSTWEP_ENCRYPT)) == HOSTWEP_PRIVACYINVOKED) { ++ p80211_hdr->a3.fc |= host2ieee16(WLAN_SET_FC_ISWEP(1)); ++ } ++ ++ result = hfa384x_drvr_txframe(hw, skb, p80211_hdr, p80211_wep); ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_mlmerequest ++* ++* wlan command message handler. All we do here is pass the message ++* over to the prism2sta_mgmt_handler. ++* ++* Arguments: ++* wlandev wlan device structure ++* msg wlan command message ++* Returns: ++* 0 success ++* <0 successful acceptance of message, but we're ++* waiting for an async process to finish before ++* we're done with the msg. When the asynch ++* process is done, we'll call the p80211 ++* function p80211req_confirm() . ++* >0 An error occurred while we were handling ++* the message. ++* ++* Side effects: ++* ++* Call context: ++* process thread ++----------------------------------------------------------------*/ ++static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ ++ int result = 0; ++ DBFENTER; ++ ++ switch( msg->msgcode ) ++ { ++ case DIDmsg_dot11req_mibget : ++ WLAN_LOG_DEBUG(2,"Received mibget request\n"); ++ result = prism2mgmt_mibset_mibget(wlandev, msg); ++ break; ++ case DIDmsg_dot11req_mibset : ++ WLAN_LOG_DEBUG(2,"Received mibset request\n"); ++ result = prism2mgmt_mibset_mibget(wlandev, msg); ++ break; ++ case DIDmsg_dot11req_scan : ++ WLAN_LOG_DEBUG(2,"Received scan request\n"); ++ result = prism2mgmt_scan(wlandev, msg); ++ break; ++ case DIDmsg_dot11req_scan_results : ++ WLAN_LOG_DEBUG(2,"Received scan_results request\n"); ++ result = prism2mgmt_scan_results(wlandev, msg); ++ break; ++ case DIDmsg_dot11req_start : ++ WLAN_LOG_DEBUG(2,"Received mlme start request\n"); ++ result = prism2mgmt_start(wlandev, msg); ++ break; ++ /* ++ * Prism2 specific messages ++ */ ++ case DIDmsg_p2req_readpda : ++ WLAN_LOG_DEBUG(2,"Received mlme readpda request\n"); ++ result = prism2mgmt_readpda(wlandev, msg); ++ break; ++ case DIDmsg_p2req_ramdl_state : ++ WLAN_LOG_DEBUG(2,"Received mlme ramdl_state request\n"); ++ result = prism2mgmt_ramdl_state(wlandev, msg); ++ break; ++ case DIDmsg_p2req_ramdl_write : ++ WLAN_LOG_DEBUG(2,"Received mlme ramdl_write request\n"); ++ result = prism2mgmt_ramdl_write(wlandev, msg); ++ break; ++ case DIDmsg_p2req_flashdl_state : ++ WLAN_LOG_DEBUG(2,"Received mlme flashdl_state request\n"); ++ result = prism2mgmt_flashdl_state(wlandev, msg); ++ break; ++ case DIDmsg_p2req_flashdl_write : ++ WLAN_LOG_DEBUG(2,"Received mlme flashdl_write request\n"); ++ result = prism2mgmt_flashdl_write(wlandev, msg); ++ break; ++ /* ++ * Linux specific messages ++ */ ++ case DIDmsg_lnxreq_hostwep : ++ break; // ignore me. ++ case DIDmsg_lnxreq_ifstate : ++ { ++ p80211msg_lnxreq_ifstate_t *ifstatemsg; ++ WLAN_LOG_DEBUG(2,"Received mlme ifstate request\n"); ++ ifstatemsg = (p80211msg_lnxreq_ifstate_t*)msg; ++ result = prism2sta_ifstate(wlandev, ifstatemsg->ifstate.data); ++ ifstatemsg->resultcode.status = ++ P80211ENUM_msgitem_status_data_ok; ++ ifstatemsg->resultcode.data = result; ++ result = 0; ++ } ++ break; ++ case DIDmsg_lnxreq_wlansniff : ++ WLAN_LOG_DEBUG(2,"Received mlme wlansniff request\n"); ++ result = prism2mgmt_wlansniff(wlandev, msg); ++ break; ++ case DIDmsg_lnxreq_autojoin : ++ WLAN_LOG_DEBUG(2,"Received mlme autojoin request\n"); ++ result = prism2mgmt_autojoin(wlandev, msg); ++ break; ++ case DIDmsg_lnxreq_commsquality: { ++ p80211msg_lnxreq_commsquality_t *qualmsg; ++ ++ WLAN_LOG_DEBUG(2,"Received commsquality request\n"); ++ ++ qualmsg = (p80211msg_lnxreq_commsquality_t*) msg; ++ ++ qualmsg->link.status = P80211ENUM_msgitem_status_data_ok; ++ qualmsg->level.status = P80211ENUM_msgitem_status_data_ok; ++ qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok; ++ ++ ++ qualmsg->link.data = hfa384x2host_16(hw->qual.CQ_currBSS); ++ qualmsg->level.data = hfa384x2host_16(hw->qual.ASL_currBSS); ++ qualmsg->noise.data = hfa384x2host_16(hw->qual.ANL_currFC); ++ ++ break; ++ } ++ default: ++ WLAN_LOG_WARNING("Unknown mgmt request message 0x%08x", msg->msgcode); ++ break; ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_ifstate ++* ++* Interface state. This is the primary WLAN interface enable/disable ++* handler. Following the driver/load/deviceprobe sequence, this ++* function must be called with a state of "enable" before any other ++* commands will be accepted. ++* ++* Arguments: ++* wlandev wlan device structure ++* msgp ptr to msg buffer ++* ++* Returns: ++* A p80211 message resultcode value. ++* ++* Side effects: ++* ++* Call context: ++* process thread (usually) ++* interrupt ++----------------------------------------------------------------*/ ++u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ u32 result; ++ DBFENTER; ++ ++ result = P80211ENUM_resultcode_implementation_failure; ++ ++ WLAN_LOG_DEBUG(2, "Current MSD state(%d), requesting(%d)\n", ++ wlandev->msdstate, ifstate); ++ switch (ifstate) ++ { ++ case P80211ENUM_ifstate_fwload: ++ switch (wlandev->msdstate) { ++ case WLAN_MSD_HWPRESENT: ++ wlandev->msdstate = WLAN_MSD_FWLOAD_PENDING; ++ /* ++ * Initialize the device+driver sufficiently ++ * for firmware loading. ++ */ ++ if ((result=hfa384x_drvr_start(hw))) { ++ WLAN_LOG_ERROR( ++ "hfa384x_drvr_start() failed," ++ "result=%d\n", (int)result); ++ result = ++ P80211ENUM_resultcode_implementation_failure; ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ break; ++ } ++ wlandev->msdstate = WLAN_MSD_FWLOAD; ++ result = P80211ENUM_resultcode_success; ++ break; ++ case WLAN_MSD_FWLOAD: ++ hfa384x_cmd_initialize(hw); ++ result = P80211ENUM_resultcode_success; ++ break; ++ case WLAN_MSD_RUNNING: ++ WLAN_LOG_WARNING( ++ "Cannot enter fwload state from enable state," ++ "you must disable first.\n"); ++ result = P80211ENUM_resultcode_invalid_parameters; ++ break; ++ case WLAN_MSD_HWFAIL: ++ default: ++ /* probe() had a problem or the msdstate contains ++ * an unrecognized value, there's nothing we can do. ++ */ ++ result = P80211ENUM_resultcode_implementation_failure; ++ break; ++ } ++ break; ++ case P80211ENUM_ifstate_enable: ++ switch (wlandev->msdstate) { ++ case WLAN_MSD_HWPRESENT: ++ case WLAN_MSD_FWLOAD: ++ wlandev->msdstate = WLAN_MSD_RUNNING_PENDING; ++ /* Initialize the device+driver for full ++ * operation. Note that this might me an FWLOAD to ++ * to RUNNING transition so we must not do a chip ++ * or board level reset. Note that on failure, ++ * the MSD state is set to HWPRESENT because we ++ * can't make any assumptions about the state ++ * of the hardware or a previous firmware load. ++ */ ++ if ((result=hfa384x_drvr_start(hw))) { ++ WLAN_LOG_ERROR( ++ "hfa384x_drvr_start() failed," ++ "result=%d\n", (int)result); ++ result = ++ P80211ENUM_resultcode_implementation_failure; ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ break; ++ } ++ ++ if ((result=prism2sta_getcardinfo(wlandev))) { ++ WLAN_LOG_ERROR( ++ "prism2sta_getcardinfo() failed," ++ "result=%d\n", (int)result); ++ result = ++ P80211ENUM_resultcode_implementation_failure; ++ hfa384x_drvr_stop(hw); ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ break; ++ } ++ if ((result=prism2sta_globalsetup(wlandev))) { ++ WLAN_LOG_ERROR( ++ "prism2sta_globalsetup() failed," ++ "result=%d\n", (int)result); ++ result = ++ P80211ENUM_resultcode_implementation_failure; ++ hfa384x_drvr_stop(hw); ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ break; ++ } ++ wlandev->msdstate = WLAN_MSD_RUNNING; ++ hw->join_ap = 0; ++ hw->join_retries = 60; ++ result = P80211ENUM_resultcode_success; ++ break; ++ case WLAN_MSD_RUNNING: ++ /* Do nothing, we're already in this state.*/ ++ result = P80211ENUM_resultcode_success; ++ break; ++ case WLAN_MSD_HWFAIL: ++ default: ++ /* probe() had a problem or the msdstate contains ++ * an unrecognized value, there's nothing we can do. ++ */ ++ result = P80211ENUM_resultcode_implementation_failure; ++ break; ++ } ++ break; ++ case P80211ENUM_ifstate_disable: ++ switch (wlandev->msdstate) { ++ case WLAN_MSD_HWPRESENT: ++ /* Do nothing, we're already in this state.*/ ++ result = P80211ENUM_resultcode_success; ++ break; ++ case WLAN_MSD_FWLOAD: ++ case WLAN_MSD_RUNNING: ++ wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING; ++ /* ++ * TODO: Shut down the MAC completely. Here a chip ++ * or board level reset is probably called for. ++ * After a "disable" _all_ results are lost, even ++ * those from a fwload. ++ */ ++ if (!wlandev->hwremoved) ++ netif_carrier_off(wlandev->netdev); ++ ++ hfa384x_drvr_stop(hw); ++ ++ wlandev->macmode = WLAN_MACMODE_NONE; ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ result = P80211ENUM_resultcode_success; ++ break; ++ case WLAN_MSD_HWFAIL: ++ default: ++ /* probe() had a problem or the msdstate contains ++ * an unrecognized value, there's nothing we can do. ++ */ ++ result = P80211ENUM_resultcode_implementation_failure; ++ break; ++ } ++ break; ++ default: ++ result = P80211ENUM_resultcode_invalid_parameters; ++ break; ++ } ++ ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_getcardinfo ++* ++* Collect the NICID, firmware version and any other identifiers ++* we'd like to have in host-side data structures. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* Either. ++----------------------------------------------------------------*/ ++static int prism2sta_getcardinfo(wlandevice_t *wlandev) ++{ ++ int result = 0; ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ u16 temp; ++ u8 snum[HFA384x_RID_NICSERIALNUMBER_LEN]; ++ char pstr[(HFA384x_RID_NICSERIALNUMBER_LEN * 4) + 1]; ++ ++ DBFENTER; ++ ++ /* Collect version and compatibility info */ ++ /* Some are critical, some are not */ ++ /* NIC identity */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICIDENTITY, ++ &hw->ident_nic, sizeof(hfa384x_compident_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve NICIDENTITY\n"); ++ goto failed; ++ } ++ ++ /* get all the nic id fields in host byte order */ ++ hw->ident_nic.id = hfa384x2host_16(hw->ident_nic.id); ++ hw->ident_nic.variant = hfa384x2host_16(hw->ident_nic.variant); ++ hw->ident_nic.major = hfa384x2host_16(hw->ident_nic.major); ++ hw->ident_nic.minor = hfa384x2host_16(hw->ident_nic.minor); ++ ++ WLAN_LOG_INFO( "ident: nic h/w: id=0x%02x %d.%d.%d\n", ++ hw->ident_nic.id, hw->ident_nic.major, ++ hw->ident_nic.minor, hw->ident_nic.variant); ++ ++ /* Primary f/w identity */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRIIDENTITY, ++ &hw->ident_pri_fw, sizeof(hfa384x_compident_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve PRIIDENTITY\n"); ++ goto failed; ++ } ++ ++ /* get all the private fw id fields in host byte order */ ++ hw->ident_pri_fw.id = hfa384x2host_16(hw->ident_pri_fw.id); ++ hw->ident_pri_fw.variant = hfa384x2host_16(hw->ident_pri_fw.variant); ++ hw->ident_pri_fw.major = hfa384x2host_16(hw->ident_pri_fw.major); ++ hw->ident_pri_fw.minor = hfa384x2host_16(hw->ident_pri_fw.minor); ++ ++ WLAN_LOG_INFO( "ident: pri f/w: id=0x%02x %d.%d.%d\n", ++ hw->ident_pri_fw.id, hw->ident_pri_fw.major, ++ hw->ident_pri_fw.minor, hw->ident_pri_fw.variant); ++ ++ /* Station (Secondary?) f/w identity */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STAIDENTITY, ++ &hw->ident_sta_fw, sizeof(hfa384x_compident_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve STAIDENTITY\n"); ++ goto failed; ++ } ++ ++ if (hw->ident_nic.id < 0x8000) { ++ WLAN_LOG_ERROR("FATAL: Card is not an Intersil Prism2/2.5/3\n"); ++ result = -1; ++ goto failed; ++ } ++ ++ /* get all the station fw id fields in host byte order */ ++ hw->ident_sta_fw.id = hfa384x2host_16(hw->ident_sta_fw.id); ++ hw->ident_sta_fw.variant = hfa384x2host_16(hw->ident_sta_fw.variant); ++ hw->ident_sta_fw.major = hfa384x2host_16(hw->ident_sta_fw.major); ++ hw->ident_sta_fw.minor = hfa384x2host_16(hw->ident_sta_fw.minor); ++ ++ /* strip out the 'special' variant bits */ ++ hw->mm_mods = hw->ident_sta_fw.variant & (BIT14 | BIT15); ++ hw->ident_sta_fw.variant &= ~((u16)(BIT14 | BIT15)); ++ ++ if ( hw->ident_sta_fw.id == 0x1f ) { ++ WLAN_LOG_INFO( ++ "ident: sta f/w: id=0x%02x %d.%d.%d\n", ++ hw->ident_sta_fw.id, hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); ++ } else { ++ WLAN_LOG_INFO( ++ "ident: ap f/w: id=0x%02x %d.%d.%d\n", ++ hw->ident_sta_fw.id, hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, hw->ident_sta_fw.variant); ++ WLAN_LOG_ERROR("Unsupported Tertiary AP firmeare loaded!\n"); ++ goto failed; ++ } ++ ++ /* Compatibility range, Modem supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_MFISUPRANGE, ++ &hw->cap_sup_mfi, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve MFISUPRANGE\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, modem interface supplier ++ fields in byte order */ ++ hw->cap_sup_mfi.role = hfa384x2host_16(hw->cap_sup_mfi.role); ++ hw->cap_sup_mfi.id = hfa384x2host_16(hw->cap_sup_mfi.id); ++ hw->cap_sup_mfi.variant = hfa384x2host_16(hw->cap_sup_mfi.variant); ++ hw->cap_sup_mfi.bottom = hfa384x2host_16(hw->cap_sup_mfi.bottom); ++ hw->cap_sup_mfi.top = hfa384x2host_16(hw->cap_sup_mfi.top); ++ ++ WLAN_LOG_INFO( ++ "MFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_sup_mfi.role, hw->cap_sup_mfi.id, ++ hw->cap_sup_mfi.variant, hw->cap_sup_mfi.bottom, ++ hw->cap_sup_mfi.top); ++ ++ /* Compatibility range, Controller supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CFISUPRANGE, ++ &hw->cap_sup_cfi, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve CFISUPRANGE\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, controller interface supplier ++ fields in byte order */ ++ hw->cap_sup_cfi.role = hfa384x2host_16(hw->cap_sup_cfi.role); ++ hw->cap_sup_cfi.id = hfa384x2host_16(hw->cap_sup_cfi.id); ++ hw->cap_sup_cfi.variant = hfa384x2host_16(hw->cap_sup_cfi.variant); ++ hw->cap_sup_cfi.bottom = hfa384x2host_16(hw->cap_sup_cfi.bottom); ++ hw->cap_sup_cfi.top = hfa384x2host_16(hw->cap_sup_cfi.top); ++ ++ WLAN_LOG_INFO( ++ "CFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_sup_cfi.role, hw->cap_sup_cfi.id, ++ hw->cap_sup_cfi.variant, hw->cap_sup_cfi.bottom, ++ hw->cap_sup_cfi.top); ++ ++ /* Compatibility range, Primary f/w supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRISUPRANGE, ++ &hw->cap_sup_pri, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve PRISUPRANGE\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, primary firmware supplier ++ fields in byte order */ ++ hw->cap_sup_pri.role = hfa384x2host_16(hw->cap_sup_pri.role); ++ hw->cap_sup_pri.id = hfa384x2host_16(hw->cap_sup_pri.id); ++ hw->cap_sup_pri.variant = hfa384x2host_16(hw->cap_sup_pri.variant); ++ hw->cap_sup_pri.bottom = hfa384x2host_16(hw->cap_sup_pri.bottom); ++ hw->cap_sup_pri.top = hfa384x2host_16(hw->cap_sup_pri.top); ++ ++ WLAN_LOG_INFO( ++ "PRI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_sup_pri.role, hw->cap_sup_pri.id, ++ hw->cap_sup_pri.variant, hw->cap_sup_pri.bottom, ++ hw->cap_sup_pri.top); ++ ++ /* Compatibility range, Station f/w supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STASUPRANGE, ++ &hw->cap_sup_sta, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve STASUPRANGE\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, station firmware supplier ++ fields in byte order */ ++ hw->cap_sup_sta.role = hfa384x2host_16(hw->cap_sup_sta.role); ++ hw->cap_sup_sta.id = hfa384x2host_16(hw->cap_sup_sta.id); ++ hw->cap_sup_sta.variant = hfa384x2host_16(hw->cap_sup_sta.variant); ++ hw->cap_sup_sta.bottom = hfa384x2host_16(hw->cap_sup_sta.bottom); ++ hw->cap_sup_sta.top = hfa384x2host_16(hw->cap_sup_sta.top); ++ ++ if ( hw->cap_sup_sta.id == 0x04 ) { ++ WLAN_LOG_INFO( ++ "STA:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_sup_sta.role, hw->cap_sup_sta.id, ++ hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom, ++ hw->cap_sup_sta.top); ++ } else { ++ WLAN_LOG_INFO( ++ "AP:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_sup_sta.role, hw->cap_sup_sta.id, ++ hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom, ++ hw->cap_sup_sta.top); ++ } ++ ++ /* Compatibility range, primary f/w actor, CFI supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRI_CFIACTRANGES, ++ &hw->cap_act_pri_cfi, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve PRI_CFIACTRANGES\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, primary f/w actor, CFI supplier ++ fields in byte order */ ++ hw->cap_act_pri_cfi.role = hfa384x2host_16(hw->cap_act_pri_cfi.role); ++ hw->cap_act_pri_cfi.id = hfa384x2host_16(hw->cap_act_pri_cfi.id); ++ hw->cap_act_pri_cfi.variant = hfa384x2host_16(hw->cap_act_pri_cfi.variant); ++ hw->cap_act_pri_cfi.bottom = hfa384x2host_16(hw->cap_act_pri_cfi.bottom); ++ hw->cap_act_pri_cfi.top = hfa384x2host_16(hw->cap_act_pri_cfi.top); ++ ++ WLAN_LOG_INFO( ++ "PRI-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_act_pri_cfi.role, hw->cap_act_pri_cfi.id, ++ hw->cap_act_pri_cfi.variant, hw->cap_act_pri_cfi.bottom, ++ hw->cap_act_pri_cfi.top); ++ ++ /* Compatibility range, sta f/w actor, CFI supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_CFIACTRANGES, ++ &hw->cap_act_sta_cfi, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve STA_CFIACTRANGES\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, station f/w actor, CFI supplier ++ fields in byte order */ ++ hw->cap_act_sta_cfi.role = hfa384x2host_16(hw->cap_act_sta_cfi.role); ++ hw->cap_act_sta_cfi.id = hfa384x2host_16(hw->cap_act_sta_cfi.id); ++ hw->cap_act_sta_cfi.variant = hfa384x2host_16(hw->cap_act_sta_cfi.variant); ++ hw->cap_act_sta_cfi.bottom = hfa384x2host_16(hw->cap_act_sta_cfi.bottom); ++ hw->cap_act_sta_cfi.top = hfa384x2host_16(hw->cap_act_sta_cfi.top); ++ ++ WLAN_LOG_INFO( ++ "STA-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_act_sta_cfi.role, hw->cap_act_sta_cfi.id, ++ hw->cap_act_sta_cfi.variant, hw->cap_act_sta_cfi.bottom, ++ hw->cap_act_sta_cfi.top); ++ ++ /* Compatibility range, sta f/w actor, MFI supplier */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_MFIACTRANGES, ++ &hw->cap_act_sta_mfi, sizeof(hfa384x_caplevel_t)); ++ if ( result ) { ++ WLAN_LOG_ERROR("Failed to retrieve STA_MFIACTRANGES\n"); ++ goto failed; ++ } ++ ++ /* get all the Compatibility range, station f/w actor, MFI supplier ++ fields in byte order */ ++ hw->cap_act_sta_mfi.role = hfa384x2host_16(hw->cap_act_sta_mfi.role); ++ hw->cap_act_sta_mfi.id = hfa384x2host_16(hw->cap_act_sta_mfi.id); ++ hw->cap_act_sta_mfi.variant = hfa384x2host_16(hw->cap_act_sta_mfi.variant); ++ hw->cap_act_sta_mfi.bottom = hfa384x2host_16(hw->cap_act_sta_mfi.bottom); ++ hw->cap_act_sta_mfi.top = hfa384x2host_16(hw->cap_act_sta_mfi.top); ++ ++ WLAN_LOG_INFO( ++ "STA-MFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n", ++ hw->cap_act_sta_mfi.role, hw->cap_act_sta_mfi.id, ++ hw->cap_act_sta_mfi.variant, hw->cap_act_sta_mfi.bottom, ++ hw->cap_act_sta_mfi.top); ++ ++ /* Serial Number */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER, ++ snum, HFA384x_RID_NICSERIALNUMBER_LEN); ++ if ( !result ) { ++ wlan_mkprintstr(snum, HFA384x_RID_NICSERIALNUMBER_LEN, ++ pstr, sizeof(pstr)); ++ WLAN_LOG_INFO("Prism2 card SN: %s\n", pstr); ++ } else { ++ WLAN_LOG_ERROR("Failed to retrieve Prism2 Card SN\n"); ++ goto failed; ++ } ++ ++ /* Collect the MAC address */ ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFOWNMACADDR, ++ wlandev->netdev->dev_addr, WLAN_ADDR_LEN); ++ if ( result != 0 ) { ++ WLAN_LOG_ERROR("Failed to retrieve mac address\n"); ++ goto failed; ++ } ++ ++ /* short preamble is always implemented */ ++ wlandev->nsdcaps |= P80211_NSDCAP_SHORT_PREAMBLE; ++ ++ /* find out if hardware wep is implemented */ ++ hfa384x_drvr_getconfig16(hw, HFA384x_RID_PRIVACYOPTIMP, &temp); ++ if (temp) ++ wlandev->nsdcaps |= P80211_NSDCAP_HARDWAREWEP; ++ ++ /* get the dBm Scaling constant */ ++ hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFDBMADJUST, &temp); ++ hw->dbmadjust = temp; ++ ++ /* Only enable scan by default on newer firmware */ ++ if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, ++ hw->ident_sta_fw.minor, ++ hw->ident_sta_fw.variant) < ++ HFA384x_FIRMWARE_VERSION(1,5,5)) { ++ wlandev->nsdcaps |= P80211_NSDCAP_NOSCAN; ++ } ++ ++ /* TODO: Set any internally managed config items */ ++ ++ goto done; ++failed: ++ WLAN_LOG_ERROR("Failed, result=%d\n", result); ++done: ++ DBFEXIT; ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_globalsetup ++* ++* Set any global RIDs that we want to set at device activation. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* 0 success ++* >0 f/w reported error ++* <0 driver reported error ++* ++* Side effects: ++* ++* Call context: ++* process thread ++----------------------------------------------------------------*/ ++static int prism2sta_globalsetup(wlandevice_t *wlandev) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ ++ /* Set the maximum frame size */ ++ return hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, ++ WLAN_DATA_MAXLEN); ++} ++ ++static int prism2sta_setmulticast(wlandevice_t *wlandev, netdevice_t *dev) ++{ ++ int result = 0; ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ ++ u16 promisc; ++ ++ DBFENTER; ++ ++ /* If we're not ready, what's the point? */ ++ if ( hw->state != HFA384x_STATE_RUNNING ) ++ goto exit; ++ ++ if ( (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0 ) ++ promisc = P80211ENUM_truth_true; ++ else ++ promisc = P80211ENUM_truth_false; ++ ++ result = hfa384x_drvr_setconfig16_async(hw, HFA384x_RID_PROMISCMODE, promisc); ++ ++ /* XXX TODO: configure the multicast list */ ++ // CLEAR_HW_MULTICAST_LIST ++ // struct dev_mc_list element = dev->mc_list; ++ // while (element != null) { ++ // HW_ADD_MULTICAST_ADDR(element->dmi_addr, dmi_addrlen) ++ // element = element->next; ++ // } ++ ++ exit: ++ DBFEXIT; ++ return result; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_handover ++* ++* Handles the receipt of a Handover info frame. Should only be present ++* in APs only. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_handover(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) ++{ ++ DBFENTER; ++ WLAN_LOG_DEBUG(2,"received infoframe:HANDOVER (unhandled)\n"); ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_tallies ++* ++* Handles the receipt of a CommTallies info frame. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_tallies(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ u16 *src16; ++ u32 *dst; ++ u32 *src32; ++ int i; ++ int cnt; ++ ++ DBFENTER; ++ ++ /* ++ ** Determine if these are 16-bit or 32-bit tallies, based on the ++ ** record length of the info record. ++ */ ++ ++ cnt = sizeof(hfa384x_CommTallies32_t) / sizeof(u32); ++ if (inf->framelen > 22) { ++ dst = (u32 *) &hw->tallies; ++ src32 = (u32 *) &inf->info.commtallies32; ++ for (i = 0; i < cnt; i++, dst++, src32++) ++ *dst += hfa384x2host_32(*src32); ++ } else { ++ dst = (u32 *) &hw->tallies; ++ src16 = (u16 *) &inf->info.commtallies16; ++ for (i = 0; i < cnt; i++, dst++, src16++) ++ *dst += hfa384x2host_16(*src16); ++ } ++ ++ DBFEXIT; ++ ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_scanresults ++* ++* Handles the receipt of a Scan Results info frame. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_scanresults(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ int nbss; ++ hfa384x_ScanResult_t *sr = &(inf->info.scanresult); ++ int i; ++ hfa384x_JoinRequest_data_t joinreq; ++ int result; ++ DBFENTER; ++ ++ /* Get the number of results, first in bytes, then in results */ ++ nbss = (inf->framelen * sizeof(u16)) - ++ sizeof(inf->infotype) - ++ sizeof(inf->info.scanresult.scanreason); ++ nbss /= sizeof(hfa384x_ScanResultSub_t); ++ ++ /* Print em */ ++ WLAN_LOG_DEBUG(1,"rx scanresults, reason=%d, nbss=%d:\n", ++ inf->info.scanresult.scanreason, nbss); ++ for ( i = 0; i < nbss; i++) { ++ WLAN_LOG_DEBUG(1, "chid=%d anl=%d sl=%d bcnint=%d\n", ++ sr->result[i].chid, ++ sr->result[i].anl, ++ sr->result[i].sl, ++ sr->result[i].bcnint); ++ WLAN_LOG_DEBUG(1, " capinfo=0x%04x proberesp_rate=%d\n", ++ sr->result[i].capinfo, ++ sr->result[i].proberesp_rate); ++ } ++ /* issue a join request */ ++ joinreq.channel = sr->result[0].chid; ++ memcpy( joinreq.bssid, sr->result[0].bssid, WLAN_BSSID_LEN); ++ result = hfa384x_drvr_setconfig( hw, ++ HFA384x_RID_JOINREQUEST, ++ &joinreq, HFA384x_RID_JOINREQUEST_LEN); ++ if (result) { ++ WLAN_LOG_ERROR("setconfig(joinreq) failed, result=%d\n", result); ++ } ++ ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_hostscanresults ++* ++* Handles the receipt of a Scan Results info frame. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_hostscanresults(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ int nbss; ++ DBFENTER; ++ ++ nbss = (inf->framelen - 3) / 32; ++ WLAN_LOG_DEBUG(1, "Received %d hostscan results\n", nbss); ++ ++ if (nbss > 32) ++ nbss = 32; ++ ++ if (hw->scanresults) ++ kfree(hw->scanresults); ++ ++ hw->scanresults = kmalloc(sizeof(hfa384x_InfFrame_t), GFP_ATOMIC); ++ memcpy(hw->scanresults, inf, sizeof(hfa384x_InfFrame_t)); ++ ++ if (nbss == 0) ++ nbss = -1; ++ ++ /* Notify/wake the sleeping caller. */ ++ hw->scanflag = nbss; ++ wake_up_interruptible(&hw->cmdq); ++ ++ DBFEXIT; ++}; ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_chinforesults ++* ++* Handles the receipt of a Channel Info Results info frame. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_chinforesults(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ unsigned int i, n; ++ ++ DBFENTER; ++ hw->channel_info.results.scanchannels = ++ hfa384x2host_16(inf->info.chinforesult.scanchannels); ++#if 0 ++ memcpy(&inf->info.chinforesult, &hw->channel_info.results, sizeof(hfa384x_ChInfoResult_t)); ++#endif ++ ++ for (i=0, n=0; ichannel_info.results.scanchannels & (1<info.chinforesult.result[n].chid)-1; ++ hfa384x_ChInfoResultSub_t *chinforesult=&hw->channel_info.results.result[channel]; ++ chinforesult->chid = channel; ++ chinforesult->anl = hfa384x2host_16(inf->info.chinforesult.result[n].anl); ++ chinforesult->pnl = hfa384x2host_16(inf->info.chinforesult.result[n].pnl); ++ chinforesult->active = hfa384x2host_16(inf->info.chinforesult.result[n].active); ++ WLAN_LOG_DEBUG(2, "chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n", ++ channel+1, ++ chinforesult->active & ++ HFA384x_CHINFORESULT_BSSACTIVE ? "signal" : "noise", ++ chinforesult->anl, chinforesult->pnl, ++ chinforesult->active & HFA384x_CHINFORESULT_PCFACTIVE ? 1 : 0 ++ ); ++ n++; ++ } ++ } ++ atomic_set(&hw->channel_info.done, 2); ++ ++ hw->channel_info.count = n; ++ DBFEXIT; ++ return; ++} ++ ++void prism2sta_processing_defer(struct work_struct *data) ++{ ++ hfa384x_t *hw = container_of(data, struct hfa384x, link_bh); ++ wlandevice_t *wlandev = hw->wlandev; ++ hfa384x_bytestr32_t ssid; ++ int result; ++ ++ DBFENTER; ++ /* First let's process the auth frames */ ++ { ++ struct sk_buff *skb; ++ hfa384x_InfFrame_t *inf; ++ ++ while ( (skb = skb_dequeue(&hw->authq)) ) { ++ inf = (hfa384x_InfFrame_t *) skb->data; ++ prism2sta_inf_authreq_defer(wlandev, inf); ++ } ++ ++ } ++ ++ /* Now let's handle the linkstatus stuff */ ++ if (hw->link_status == hw->link_status_new) ++ goto failed; ++ ++ hw->link_status = hw->link_status_new; ++ ++ switch(hw->link_status) { ++ case HFA384x_LINK_NOTCONNECTED: ++ /* I'm currently assuming that this is the initial link ++ * state. It should only be possible immediately ++ * following an Enable command. ++ * Response: ++ * Block Transmits, Ignore receives of data frames ++ */ ++ netif_carrier_off(wlandev->netdev); ++ ++ WLAN_LOG_INFO("linkstatus=NOTCONNECTED (unhandled)\n"); ++ break; ++ ++ case HFA384x_LINK_CONNECTED: ++ /* This one indicates a successful scan/join/auth/assoc. ++ * When we have the full MLME complement, this event will ++ * signify successful completion of both mlme_authenticate ++ * and mlme_associate. State management will get a little ++ * ugly here. ++ * Response: ++ * Indicate authentication and/or association ++ * Enable Transmits, Receives and pass up data frames ++ */ ++ ++ netif_carrier_on(wlandev->netdev); ++ ++ /* If we are joining a specific AP, set our state and reset retries */ ++ if(hw->join_ap == 1) ++ hw->join_ap = 2; ++ hw->join_retries = 60; ++ ++ /* Don't call this in monitor mode */ ++ if ( wlandev->netdev->type == ARPHRD_ETHER ) { ++ u16 portstatus; ++ ++ WLAN_LOG_INFO("linkstatus=CONNECTED\n"); ++ ++ /* For non-usb devices, we can use the sync versions */ ++ /* Collect the BSSID, and set state to allow tx */ ++ ++ result = hfa384x_drvr_getconfig(hw, ++ HFA384x_RID_CURRENTBSSID, ++ wlandev->bssid, WLAN_BSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_CURRENTBSSID, result); ++ goto failed; ++ } ++ ++ result = hfa384x_drvr_getconfig(hw, ++ HFA384x_RID_CURRENTSSID, ++ &ssid, sizeof(ssid)); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_CURRENTSSID, result); ++ goto failed; ++ } ++ prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, ++ (p80211pstrd_t *) &wlandev->ssid); ++ ++ /* Collect the port status */ ++ result = hfa384x_drvr_getconfig16(hw, ++ HFA384x_RID_PORTSTATUS, &portstatus); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_PORTSTATUS, result); ++ goto failed; ++ } ++ wlandev->macmode = ++ (portstatus == HFA384x_PSTATUS_CONN_IBSS) ? ++ WLAN_MACMODE_IBSS_STA : WLAN_MACMODE_ESS_STA; ++ ++ /* Get the ball rolling on the comms quality stuff */ ++ prism2sta_commsqual_defer(&hw->commsqual_bh); ++ } ++ break; ++ ++ case HFA384x_LINK_DISCONNECTED: ++ /* This one indicates that our association is gone. We've ++ * lost connection with the AP and/or been disassociated. ++ * This indicates that the MAC has completely cleared it's ++ * associated state. We * should send a deauth indication ++ * (implying disassoc) up * to the MLME. ++ * Response: ++ * Indicate Deauthentication ++ * Block Transmits, Ignore receives of data frames ++ */ ++ if(hw->join_ap == 2) ++ { ++ hfa384x_JoinRequest_data_t joinreq; ++ joinreq = hw->joinreq; ++ /* Send the join request */ ++ hfa384x_drvr_setconfig( hw, ++ HFA384x_RID_JOINREQUEST, ++ &joinreq, HFA384x_RID_JOINREQUEST_LEN); ++ WLAN_LOG_INFO("linkstatus=DISCONNECTED (re-submitting join)\n"); ++ } else { ++ if (wlandev->netdev->type == ARPHRD_ETHER) ++ WLAN_LOG_INFO("linkstatus=DISCONNECTED (unhandled)\n"); ++ } ++ wlandev->macmode = WLAN_MACMODE_NONE; ++ ++ netif_carrier_off(wlandev->netdev); ++ ++ break; ++ ++ case HFA384x_LINK_AP_CHANGE: ++ /* This one indicates that the MAC has decided to and ++ * successfully completed a change to another AP. We ++ * should probably implement a reassociation indication ++ * in response to this one. I'm thinking that the the ++ * p80211 layer needs to be notified in case of ++ * buffering/queueing issues. User mode also needs to be ++ * notified so that any BSS dependent elements can be ++ * updated. ++ * associated state. We * should send a deauth indication ++ * (implying disassoc) up * to the MLME. ++ * Response: ++ * Indicate Reassociation ++ * Enable Transmits, Receives and pass up data frames ++ */ ++ WLAN_LOG_INFO("linkstatus=AP_CHANGE\n"); ++ ++ result = hfa384x_drvr_getconfig(hw, ++ HFA384x_RID_CURRENTBSSID, ++ wlandev->bssid, WLAN_BSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_CURRENTBSSID, result); ++ goto failed; ++ } ++ ++ result = hfa384x_drvr_getconfig(hw, ++ HFA384x_RID_CURRENTSSID, ++ &ssid, sizeof(ssid)); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_CURRENTSSID, result); ++ goto failed; ++ } ++ prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, ++ (p80211pstrd_t *) &wlandev->ssid); ++ ++ ++ hw->link_status = HFA384x_LINK_CONNECTED; ++ netif_carrier_on(wlandev->netdev); ++ ++ break; ++ ++ case HFA384x_LINK_AP_OUTOFRANGE: ++ /* This one indicates that the MAC has decided that the ++ * AP is out of range, but hasn't found a better candidate ++ * so the MAC maintains its "associated" state in case ++ * we get back in range. We should block transmits and ++ * receives in this state. Do we need an indication here? ++ * Probably not since a polling user-mode element would ++ * get this status from from p2PortStatus(FD40). What about ++ * p80211? ++ * Response: ++ * Block Transmits, Ignore receives of data frames ++ */ ++ WLAN_LOG_INFO("linkstatus=AP_OUTOFRANGE (unhandled)\n"); ++ ++ netif_carrier_off(wlandev->netdev); ++ ++ break; ++ ++ case HFA384x_LINK_AP_INRANGE: ++ /* This one indicates that the MAC has decided that the ++ * AP is back in range. We continue working with our ++ * existing association. ++ * Response: ++ * Enable Transmits, Receives and pass up data frames ++ */ ++ WLAN_LOG_INFO("linkstatus=AP_INRANGE\n"); ++ ++ hw->link_status = HFA384x_LINK_CONNECTED; ++ netif_carrier_on(wlandev->netdev); ++ ++ break; ++ ++ case HFA384x_LINK_ASSOCFAIL: ++ /* This one is actually a peer to CONNECTED. We've ++ * requested a join for a given SSID and optionally BSSID. ++ * We can use this one to indicate authentication and ++ * association failures. The trick is going to be ++ * 1) identifying the failure, and 2) state management. ++ * Response: ++ * Disable Transmits, Ignore receives of data frames ++ */ ++ if(hw->join_ap && --hw->join_retries > 0) ++ { ++ hfa384x_JoinRequest_data_t joinreq; ++ joinreq = hw->joinreq; ++ /* Send the join request */ ++ hfa384x_drvr_setconfig( hw, ++ HFA384x_RID_JOINREQUEST, ++ &joinreq, HFA384x_RID_JOINREQUEST_LEN); ++ WLAN_LOG_INFO("linkstatus=ASSOCFAIL (re-submitting join)\n"); ++ } else { ++ WLAN_LOG_INFO("linkstatus=ASSOCFAIL (unhandled)\n"); ++ } ++ ++ netif_carrier_off(wlandev->netdev); ++ ++ break; ++ ++ default: ++ /* This is bad, IO port problems? */ ++ WLAN_LOG_WARNING( ++ "unknown linkstatus=0x%02x\n", hw->link_status); ++ goto failed; ++ break; ++ } ++ ++ wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED); ++#ifdef WIRELESS_EXT ++ p80211wext_event_associated(wlandev, wlandev->linkstatus); ++#endif ++ ++ failed: ++ DBFEXIT; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_linkstatus ++* ++* Handles the receipt of a Link Status info frame. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_linkstatus(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ ++ DBFENTER; ++ ++ hw->link_status_new = hfa384x2host_16(inf->info.linkstatus.linkstatus); ++ ++ schedule_work(&hw->link_bh); ++ ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_assocstatus ++* ++* Handles the receipt of an Association Status info frame. Should ++* be present in APs only. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_assocstatus(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ hfa384x_AssocStatus_t rec; ++ int i; ++ ++ DBFENTER; ++ ++ memcpy(&rec, &inf->info.assocstatus, sizeof(rec)); ++ rec.assocstatus = hfa384x2host_16(rec.assocstatus); ++ rec.reason = hfa384x2host_16(rec.reason); ++ ++ /* ++ ** Find the address in the list of authenticated stations. If it wasn't ++ ** found, then this address has not been previously authenticated and ++ ** something weird has happened if this is anything other than an ++ ** "authentication failed" message. If the address was found, then ++ ** set the "associated" flag for that station, based on whether the ++ ** station is associating or losing its association. Something weird ++ ** has also happened if we find the address in the list of authenticated ++ ** stations but we are getting an "authentication failed" message. ++ */ ++ ++ for (i = 0; i < hw->authlist.cnt; i++) ++ if (memcmp(rec.sta_addr, hw->authlist.addr[i], WLAN_ADDR_LEN) == 0) ++ break; ++ ++ if (i >= hw->authlist.cnt) { ++ if (rec.assocstatus != HFA384x_ASSOCSTATUS_AUTHFAIL) ++ WLAN_LOG_WARNING("assocstatus info frame received for non-authenticated station.\n"); ++ } else { ++ hw->authlist.assoc[i] = ++ (rec.assocstatus == HFA384x_ASSOCSTATUS_STAASSOC || ++ rec.assocstatus == HFA384x_ASSOCSTATUS_REASSOC); ++ ++ if (rec.assocstatus == HFA384x_ASSOCSTATUS_AUTHFAIL) ++ WLAN_LOG_WARNING("authfail assocstatus info frame received for authenticated station.\n"); ++ } ++ ++ DBFEXIT; ++ ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_authreq ++* ++* Handles the receipt of an Authentication Request info frame. Should ++* be present in APs only. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++* ++----------------------------------------------------------------*/ ++static void prism2sta_inf_authreq(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ struct sk_buff *skb; ++ ++ DBFENTER; ++ ++ skb = dev_alloc_skb(sizeof(*inf)); ++ if (skb) { ++ skb_put(skb, sizeof(*inf)); ++ memcpy(skb->data, inf, sizeof(*inf)); ++ skb_queue_tail(&hw->authq, skb); ++ schedule_work(&hw->link_bh); ++ } ++ ++ DBFEXIT; ++} ++ ++static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ hfa384x_authenticateStation_data_t rec; ++ ++ int i, added, result, cnt; ++ u8 *addr; ++ ++ DBFENTER; ++ ++ /* ++ ** Build the AuthenticateStation record. Initialize it for denying ++ ** authentication. ++ */ ++ ++ memcpy(rec.address, inf->info.authreq.sta_addr, WLAN_ADDR_LEN); ++ rec.status = P80211ENUM_status_unspec_failure; ++ ++ /* ++ ** Authenticate based on the access mode. ++ */ ++ ++ switch (hw->accessmode) { ++ case WLAN_ACCESS_NONE: ++ ++ /* ++ ** Deny all new authentications. However, if a station ++ ** is ALREADY authenticated, then accept it. ++ */ ++ ++ for (i = 0; i < hw->authlist.cnt; i++) ++ if (memcmp(rec.address, hw->authlist.addr[i], ++ WLAN_ADDR_LEN) == 0) { ++ rec.status = P80211ENUM_status_successful; ++ break; ++ } ++ ++ break; ++ ++ case WLAN_ACCESS_ALL: ++ ++ /* ++ ** Allow all authentications. ++ */ ++ ++ rec.status = P80211ENUM_status_successful; ++ break; ++ ++ case WLAN_ACCESS_ALLOW: ++ ++ /* ++ ** Only allow the authentication if the MAC address ++ ** is in the list of allowed addresses. ++ ** ++ ** Since this is the interrupt handler, we may be here ++ ** while the access list is in the middle of being ++ ** updated. Choose the list which is currently okay. ++ ** See "prism2mib_priv_accessallow()" for details. ++ */ ++ ++ if (hw->allow.modify == 0) { ++ cnt = hw->allow.cnt; ++ addr = hw->allow.addr[0]; ++ } else { ++ cnt = hw->allow.cnt1; ++ addr = hw->allow.addr1[0]; ++ } ++ ++ for (i = 0; i < cnt; i++, addr += WLAN_ADDR_LEN) ++ if (memcmp(rec.address, addr, WLAN_ADDR_LEN) == 0) { ++ rec.status = P80211ENUM_status_successful; ++ break; ++ } ++ ++ break; ++ ++ case WLAN_ACCESS_DENY: ++ ++ /* ++ ** Allow the authentication UNLESS the MAC address is ++ ** in the list of denied addresses. ++ ** ++ ** Since this is the interrupt handler, we may be here ++ ** while the access list is in the middle of being ++ ** updated. Choose the list which is currently okay. ++ ** See "prism2mib_priv_accessdeny()" for details. ++ */ ++ ++ if (hw->deny.modify == 0) { ++ cnt = hw->deny.cnt; ++ addr = hw->deny.addr[0]; ++ } else { ++ cnt = hw->deny.cnt1; ++ addr = hw->deny.addr1[0]; ++ } ++ ++ rec.status = P80211ENUM_status_successful; ++ ++ for (i = 0; i < cnt; i++, addr += WLAN_ADDR_LEN) ++ if (memcmp(rec.address, addr, WLAN_ADDR_LEN) == 0) { ++ rec.status = P80211ENUM_status_unspec_failure; ++ break; ++ } ++ ++ break; ++ } ++ ++ /* ++ ** If the authentication is okay, then add the MAC address to the list ++ ** of authenticated stations. Don't add the address if it is already in ++ ** the list. (802.11b does not seem to disallow a station from issuing ++ ** an authentication request when the station is already authenticated. ++ ** Does this sort of thing ever happen? We might as well do the check ++ ** just in case.) ++ */ ++ ++ added = 0; ++ ++ if (rec.status == P80211ENUM_status_successful) { ++ for (i = 0; i < hw->authlist.cnt; i++) ++ if (memcmp(rec.address, hw->authlist.addr[i], WLAN_ADDR_LEN) == 0) ++ break; ++ ++ if (i >= hw->authlist.cnt) { ++ if (hw->authlist.cnt >= WLAN_AUTH_MAX) { ++ rec.status = P80211ENUM_status_ap_full; ++ } else { ++ memcpy(hw->authlist.addr[hw->authlist.cnt], ++ rec.address, WLAN_ADDR_LEN); ++ hw->authlist.cnt++; ++ added = 1; ++ } ++ } ++ } ++ ++ /* ++ ** Send back the results of the authentication. If this doesn't work, ++ ** then make sure to remove the address from the authenticated list if ++ ** it was added. ++ */ ++ ++ rec.status = host2hfa384x_16(rec.status); ++ rec.algorithm = inf->info.authreq.algorithm; ++ ++ result = hfa384x_drvr_setconfig(hw, HFA384x_RID_AUTHENTICATESTA, ++ &rec, sizeof(rec)); ++ if (result) { ++ if (added) hw->authlist.cnt--; ++ WLAN_LOG_ERROR("setconfig(authenticatestation) failed, result=%d\n", result); ++ } ++ ++ DBFEXIT; ++ ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_inf_psusercnt ++* ++* Handles the receipt of a PowerSaveUserCount info frame. Should ++* be present in APs only. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to info frame (contents in hfa384x order) ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, ++ hfa384x_InfFrame_t *inf) ++{ ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++ ++ DBFENTER; ++ ++ hw->psusercount = hfa384x2host_16(inf->info.psusercnt.usercnt); ++ ++ DBFEXIT; ++ ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_dtim ++* ++* Handles the DTIM early warning event. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_dtim(wlandevice_t *wlandev) ++{ ++#if 0 ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++#endif ++ DBFENTER; ++ WLAN_LOG_DEBUG(3, "DTIM event, currently unhandled.\n"); ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_infdrop ++* ++* Handles the InfDrop event. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_infdrop(wlandevice_t *wlandev) ++{ ++#if 0 ++ hfa384x_t *hw = (hfa384x_t *)wlandev->priv; ++#endif ++ DBFENTER; ++ WLAN_LOG_DEBUG(3, "Info frame dropped due to card mem low.\n"); ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_info ++* ++* Handles the Info event. ++* ++* Arguments: ++* wlandev wlan device structure ++* inf ptr to a generic info frame ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) ++{ ++ DBFENTER; ++ inf->infotype = hfa384x2host_16(inf->infotype); ++ /* Dispatch */ ++ switch ( inf->infotype ) { ++ case HFA384x_IT_HANDOVERADDR: ++ prism2sta_inf_handover(wlandev, inf); ++ break; ++ case HFA384x_IT_COMMTALLIES: ++ prism2sta_inf_tallies(wlandev, inf); ++ break; ++ case HFA384x_IT_HOSTSCANRESULTS: ++ prism2sta_inf_hostscanresults(wlandev, inf); ++ break; ++ case HFA384x_IT_SCANRESULTS: ++ prism2sta_inf_scanresults(wlandev, inf); ++ break; ++ case HFA384x_IT_CHINFORESULTS: ++ prism2sta_inf_chinforesults(wlandev, inf); ++ break; ++ case HFA384x_IT_LINKSTATUS: ++ prism2sta_inf_linkstatus(wlandev, inf); ++ break; ++ case HFA384x_IT_ASSOCSTATUS: ++ prism2sta_inf_assocstatus(wlandev, inf); ++ break; ++ case HFA384x_IT_AUTHREQ: ++ prism2sta_inf_authreq(wlandev, inf); ++ break; ++ case HFA384x_IT_PSUSERCNT: ++ prism2sta_inf_psusercnt(wlandev, inf); ++ break; ++ case HFA384x_IT_KEYIDCHANGED: ++ WLAN_LOG_WARNING("Unhandled IT_KEYIDCHANGED\n"); ++ break; ++ case HFA384x_IT_ASSOCREQ: ++ WLAN_LOG_WARNING("Unhandled IT_ASSOCREQ\n"); ++ break; ++ case HFA384x_IT_MICFAILURE: ++ WLAN_LOG_WARNING("Unhandled IT_MICFAILURE\n"); ++ break; ++ default: ++ WLAN_LOG_WARNING( ++ "Unknown info type=0x%02x\n", inf->infotype); ++ break; ++ } ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_txexc ++* ++* Handles the TxExc event. A Transmit Exception event indicates ++* that the MAC's TX process was unsuccessful - so the packet did ++* not get transmitted. ++* ++* Arguments: ++* wlandev wlan device structure ++* status tx frame status word ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status) ++{ ++ DBFENTER; ++ ++ WLAN_LOG_DEBUG(3, "TxExc status=0x%x.\n", status); ++ ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_tx ++* ++* Handles the Tx event. ++* ++* Arguments: ++* wlandev wlan device structure ++* status tx frame status word ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status) ++{ ++ DBFENTER; ++ WLAN_LOG_DEBUG(4, "Tx Complete, status=0x%04x\n", status); ++ /* update linux network stats */ ++ wlandev->linux_stats.tx_packets++; ++ DBFEXIT; ++ return; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_rx ++* ++* Handles the Rx event. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb) ++{ ++ DBFENTER; ++ ++ p80211netdev_rx(wlandev, skb); ++ ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* prism2sta_ev_alloc ++* ++* Handles the Alloc event. ++* ++* Arguments: ++* wlandev wlan device structure ++* ++* Returns: ++* nothing ++* ++* Side effects: ++* ++* Call context: ++* interrupt ++----------------------------------------------------------------*/ ++void prism2sta_ev_alloc(wlandevice_t *wlandev) ++{ ++ DBFENTER; ++ ++ netif_wake_queue(wlandev->netdev); ++ ++ DBFEXIT; ++ return; ++} ++ ++/*---------------------------------------------------------------- ++* create_wlan ++* ++* Called at module init time. This creates the wlandevice_t structure ++* and initializes it with relevant bits. ++* ++* Arguments: ++* none ++* ++* Returns: ++* the created wlandevice_t structure. ++* ++* Side effects: ++* also allocates the priv/hw structures. ++* ++* Call context: ++* process thread ++* ++----------------------------------------------------------------*/ ++static wlandevice_t *create_wlan(void) ++{ ++ wlandevice_t *wlandev = NULL; ++ hfa384x_t *hw = NULL; ++ ++ /* Alloc our structures */ ++ wlandev = kmalloc(sizeof(wlandevice_t), GFP_KERNEL); ++ hw = kmalloc(sizeof(hfa384x_t), GFP_KERNEL); ++ ++ if (!wlandev || !hw) { ++ WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); ++ if (wlandev) kfree(wlandev); ++ if (hw) kfree(hw); ++ return NULL; ++ } ++ ++ /* Clear all the structs */ ++ memset(wlandev, 0, sizeof(wlandevice_t)); ++ memset(hw, 0, sizeof(hfa384x_t)); ++ ++ /* Initialize the network device object. */ ++ wlandev->nsdname = dev_info; ++ wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING; ++ wlandev->priv = hw; ++ wlandev->open = prism2sta_open; ++ wlandev->close = prism2sta_close; ++ wlandev->reset = prism2sta_reset; ++ wlandev->txframe = prism2sta_txframe; ++ wlandev->mlmerequest = prism2sta_mlmerequest; ++ wlandev->set_multicast_list = prism2sta_setmulticast; ++ wlandev->tx_timeout = hfa384x_tx_timeout; ++ ++ wlandev->nsdcaps = P80211_NSDCAP_HWFRAGMENT | ++ P80211_NSDCAP_AUTOJOIN; ++ ++ /* Initialize the device private data stucture. */ ++ hw->dot11_desired_bss_type = 1; ++ ++ return wlandev; ++} ++ ++void prism2sta_commsqual_defer(struct work_struct *data) ++{ ++ hfa384x_t *hw = container_of(data, struct hfa384x, commsqual_bh); ++ wlandevice_t *wlandev = hw->wlandev; ++ hfa384x_bytestr32_t ssid; ++ int result = 0; ++ ++ DBFENTER; ++ ++ if (hw->wlandev->hwremoved) ++ goto done; ++ ++ /* we don't care if we're in AP mode */ ++ if ((wlandev->macmode == WLAN_MACMODE_NONE) || ++ (wlandev->macmode == WLAN_MACMODE_ESS_AP)) { ++ goto done; ++ } ++ ++ /* It only makes sense to poll these in non-IBSS */ ++ if (wlandev->macmode != WLAN_MACMODE_IBSS_STA) { ++ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DBMCOMMSQUALITY, ++ &hw->qual, ++ HFA384x_RID_DBMCOMMSQUALITY_LEN); ++ ++ if (result) { ++ WLAN_LOG_ERROR("error fetching commsqual\n"); ++ goto done; ++ } ++ ++ // qual.CQ_currBSS; // link ++ // ASL_currBSS; // level ++ // qual.ANL_currFC; // noise ++ ++ WLAN_LOG_DEBUG(3, "commsqual %d %d %d\n", ++ hfa384x2host_16(hw->qual.CQ_currBSS), ++ hfa384x2host_16(hw->qual.ASL_currBSS), ++ hfa384x2host_16(hw->qual.ANL_currFC)); ++ } ++ ++ /* Lastly, we need to make sure the BSSID didn't change on us */ ++ result = hfa384x_drvr_getconfig(hw, ++ HFA384x_RID_CURRENTBSSID, ++ wlandev->bssid, WLAN_BSSID_LEN); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_CURRENTBSSID, result); ++ goto done; ++ } ++ ++ result = hfa384x_drvr_getconfig(hw, ++ HFA384x_RID_CURRENTSSID, ++ &ssid, sizeof(ssid)); ++ if ( result ) { ++ WLAN_LOG_DEBUG(1, ++ "getconfig(0x%02x) failed, result = %d\n", ++ HFA384x_RID_CURRENTSSID, result); ++ goto done; ++ } ++ prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid, ++ (p80211pstrd_t *) &wlandev->ssid); ++ ++ ++ /* Reschedule timer */ ++ mod_timer(&hw->commsqual_timer, jiffies + HZ); ++ ++ done: ++ DBFEXIT; ++} ++ ++void prism2sta_commsqual_timer(unsigned long data) ++{ ++ hfa384x_t *hw = (hfa384x_t *) data; ++ ++ DBFENTER; ++ ++ schedule_work(&hw->commsqual_bh); ++ ++ DBFEXIT; ++} +--- /dev/null ++++ b/drivers/staging/wlan-ng/prism2usb.c +@@ -0,0 +1,302 @@ ++#include "hfa384x_usb.c" ++#include "prism2mgmt.c" ++#include "prism2mib.c" ++#include "prism2sta.c" ++ ++#define PRISM_USB_DEVICE(vid, pid, name) \ ++ USB_DEVICE(vid, pid), \ ++ .driver_info = (unsigned long) name ++ ++static struct usb_device_id usb_prism_tbl[] = { ++ {PRISM_USB_DEVICE(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS")}, ++ {PRISM_USB_DEVICE(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11")}, ++ {PRISM_USB_DEVICE(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x067c, 0x1022, "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x049f, 0x0033, "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter")}, ++ {PRISM_USB_DEVICE(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter")}, ++ {PRISM_USB_DEVICE(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0967, 0x0204, "Acer Warplink USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated")}, ++ {PRISM_USB_DEVICE(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter")}, ++ {PRISM_USB_DEVICE(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x0846, 0x4110, "NetGear MA111")}, ++ {PRISM_USB_DEVICE(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter")}, ++// {PRISM_USB_DEVICE(0x0ace, 0x1201, "ZyDAS ZD1201 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x2821, 0x3300, "ASUS-WL140 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x2001, 0x3700, "DWL-122 Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter")}, ++ {PRISM_USB_DEVICE(0x50c2, 0x4013, "Averatec USB WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter")}, ++ {PRISM_USB_DEVICE(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x2821, 0x3300, "Hawking HighDB USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter")}, ++ {PRISM_USB_DEVICE(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter")}, ++ {PRISM_USB_DEVICE(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0bb2, 0x0302, "Ambit Microsystems Corp.")}, ++ {PRISM_USB_DEVICE(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter")}, ++ {PRISM_USB_DEVICE(0x0543, 0x0f01, "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)")}, ++ { /* terminator */ } ++}; ++ ++MODULE_DEVICE_TABLE(usb, usb_prism_tbl); ++ ++/*---------------------------------------------------------------- ++* prism2sta_probe_usb ++* ++* Probe routine called by the USB subsystem. ++* ++* Arguments: ++* dev ptr to the usb_device struct ++* ifnum interface number being offered ++* ++* Returns: ++* NULL - we're not claiming the device+interface ++* non-NULL - we are claiming the device+interface and ++* this is a ptr to the data we want back ++* when disconnect is called. ++* ++* Side effects: ++* ++* Call context: ++* I'm not sure, assume it's interrupt. ++* ++----------------------------------------------------------------*/ ++static int prism2sta_probe_usb( ++ struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *dev; ++ ++ wlandevice_t *wlandev = NULL; ++ hfa384x_t *hw = NULL; ++ int result = 0; ++ ++ DBFENTER; ++ ++ dev = interface_to_usbdev(interface); ++ ++ if ((wlandev = create_wlan()) == NULL) { ++ WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); ++ result = -EIO; ++ goto failed; ++ } ++ hw = wlandev->priv; ++ ++ if ( wlan_setup(wlandev) != 0 ) { ++ WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info); ++ result = -EIO; ++ goto failed; ++ } ++ ++ /* Initialize the hw data */ ++ hfa384x_create(hw, dev); ++ hw->wlandev = wlandev; ++ ++ /* Register the wlandev, this gets us a name and registers the ++ * linux netdevice. ++ */ ++ SET_NETDEV_DEV(wlandev->netdev, &(interface->dev)); ++ ++ /* Do a chip-level reset on the MAC */ ++ if (prism2_doreset) { ++ result = hfa384x_corereset(hw, ++ prism2_reset_holdtime, ++ prism2_reset_settletime, 0); ++ if (result != 0) { ++ unregister_wlandev(wlandev); ++ hfa384x_destroy(hw); ++ result = -EIO; ++ WLAN_LOG_ERROR( ++ "%s: hfa384x_corereset() failed.\n", ++ dev_info); ++ goto failed; ++ } ++ } ++ ++ usb_get_dev(dev); ++ ++ wlandev->msdstate = WLAN_MSD_HWPRESENT; ++ ++ if ( register_wlandev(wlandev) != 0 ) { ++ WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info); ++ result = -EIO; ++ goto failed; ++ } ++ ++/* enable the card */ ++ prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable); ++ ++ goto done; ++ ++ failed: ++ if (wlandev) kfree(wlandev); ++ if (hw) kfree(hw); ++ wlandev = NULL; ++ ++ done: ++ DBFEXIT; ++ ++ usb_set_intfdata(interface, wlandev); ++ return result; ++} ++ ++ ++/*---------------------------------------------------------------- ++* prism2sta_disconnect_usb ++* ++* Called when a device previously claimed by probe is removed ++* from the USB. ++* ++* Arguments: ++* dev ptr to the usb_device struct ++* ptr ptr returned by probe() when the device ++* was claimed. ++* ++* Returns: ++* Nothing ++* ++* Side effects: ++* ++* Call context: ++* process ++----------------------------------------------------------------*/ ++static void ++prism2sta_disconnect_usb(struct usb_interface *interface) ++{ ++ wlandevice_t *wlandev; ++ ++ DBFENTER; ++ ++ wlandev = (wlandevice_t *) usb_get_intfdata(interface); ++ ++ if ( wlandev != NULL ) { ++ LIST_HEAD(cleanlist); ++ struct list_head *entry; ++ struct list_head *temp; ++ unsigned long flags; ++ ++ hfa384x_t *hw = wlandev->priv; ++ ++ if (!hw) ++ goto exit; ++ ++ spin_lock_irqsave(&hw->ctlxq.lock, flags); ++ ++ p80211netdev_hwremoved(wlandev); ++ list_splice_init(&hw->ctlxq.reapable, &cleanlist); ++ list_splice_init(&hw->ctlxq.completing, &cleanlist); ++ list_splice_init(&hw->ctlxq.pending, &cleanlist); ++ list_splice_init(&hw->ctlxq.active, &cleanlist); ++ ++ spin_unlock_irqrestore(&hw->ctlxq.lock, flags); ++ ++ /* There's no hardware to shutdown, but the driver ++ * might have some tasks or tasklets that must be ++ * stopped before we can tear everything down. ++ */ ++ prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); ++ ++ del_singleshot_timer_sync(&hw->throttle); ++ del_singleshot_timer_sync(&hw->reqtimer); ++ del_singleshot_timer_sync(&hw->resptimer); ++ ++ /* Unlink all the URBs. This "removes the wheels" ++ * from the entire CTLX handling mechanism. ++ */ ++ usb_kill_urb(&hw->rx_urb); ++ usb_kill_urb(&hw->tx_urb); ++ usb_kill_urb(&hw->ctlx_urb); ++ ++ tasklet_kill(&hw->completion_bh); ++ tasklet_kill(&hw->reaper_bh); ++ ++ flush_scheduled_work(); ++ ++ /* Now we complete any outstanding commands ++ * and tell everyone who is waiting for their ++ * responses that we have shut down. ++ */ ++ list_for_each(entry, &cleanlist) { ++ hfa384x_usbctlx_t *ctlx; ++ ++ ctlx = list_entry(entry, hfa384x_usbctlx_t, list); ++ complete(&ctlx->done); ++ } ++ ++ /* Give any outstanding synchronous commands ++ * a chance to complete. All they need to do ++ * is "wake up", so that's easy. ++ * (I'd like a better way to do this, really.) ++ */ ++ msleep(100); ++ ++ /* Now delete the CTLXs, because no-one else can now. */ ++ list_for_each_safe(entry, temp, &cleanlist) { ++ hfa384x_usbctlx_t *ctlx; ++ ++ ctlx = list_entry(entry, hfa384x_usbctlx_t, list); ++ kfree(ctlx); ++ } ++ ++ /* Unhook the wlandev */ ++ unregister_wlandev(wlandev); ++ wlan_unsetup(wlandev); ++ ++ usb_put_dev(hw->usb); ++ ++ hfa384x_destroy(hw); ++ kfree(hw); ++ ++ kfree(wlandev); ++ } ++ ++ exit: ++ ++ usb_set_intfdata(interface, NULL); ++ DBFEXIT; ++} ++ ++ ++static struct usb_driver prism2_usb_driver = { ++ .name = "prism2_usb", ++ .probe = prism2sta_probe_usb, ++ .disconnect = prism2sta_disconnect_usb, ++ .id_table = usb_prism_tbl, ++ /* fops, minor? */ ++}; ++ ++static int __init prism2usb_init(void) ++{ ++ DBFENTER; ++ ++ /* This call will result in calls to prism2sta_probe_usb. */ ++ return usb_register(&prism2_usb_driver); ++ ++ DBFEXIT; ++}; ++ ++static void __exit prism2usb_cleanup(void) ++{ ++ DBFENTER; ++ ++ usb_deregister(&prism2_usb_driver); ++ ++ DBFEXIT; ++}; ++ ++module_init(prism2usb_init); ++module_exit(prism2usb_cleanup); +--- /dev/null ++++ b/drivers/staging/wlan-ng/README +@@ -0,0 +1,7 @@ ++TODO: ++ - checkpatch.pl cleanups ++ - sparse warnings ++ - Lindent cleanups ++ - move to use the in-kernel wireless stack ++ ++Please send all patches to Greg Kroah-Hartman +--- /dev/null ++++ b/drivers/staging/wlan-ng/version.h +@@ -0,0 +1,56 @@ ++/* src/include/wlan/version.h ++* ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++#ifndef _WLAN_VERSION_H ++#define _WLAN_VERSION_H ++#ifndef KERNEL_VERSION ++#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++#endif ++ ++#define WLAN_RELEASE "0.2.8" ++#define WLAN_RELEASE_CODE 0x000208 ++#define WLAN_BUILD_DATE "Thu Oct 2 11:04:42 PDT 2008" ++ ++#endif +--- /dev/null ++++ b/drivers/staging/wlan-ng/wlan_compat.h +@@ -0,0 +1,193 @@ ++/* wlan_compat.h ++* ++* Types and macros to aid in portability ++* ++* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. ++* -------------------------------------------------------------------- ++* ++* linux-wlan ++* ++* The contents of this file are subject to the Mozilla Public ++* License Version 1.1 (the "License"); you may not use this file ++* except in compliance with the License. You may obtain a copy of ++* the License at http://www.mozilla.org/MPL/ ++* ++* Software distributed under the License is distributed on an "AS ++* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++* implied. See the License for the specific language governing ++* rights and limitations under the License. ++* ++* Alternatively, the contents of this file may be used under the ++* terms of the GNU Public License version 2 (the "GPL"), in which ++* case the provisions of the GPL are applicable instead of the ++* above. If you wish to allow the use of your version of this file ++* only under the terms of the GPL and not to allow others to use ++* your version of this file under the MPL, indicate your decision ++* by deleting the provisions above and replace them with the notice ++* and other provisions required by the GPL. If you do not delete ++* the provisions above, a recipient may use your version of this ++* file under either the MPL or the GPL. ++* ++* -------------------------------------------------------------------- ++* ++* Inquiries regarding the linux-wlan Open Source project can be ++* made directly to: ++* ++* AbsoluteValue Systems Inc. ++* info@linux-wlan.com ++* http://www.linux-wlan.com ++* ++* -------------------------------------------------------------------- ++* ++* Portions of the development of this software were funded by ++* Intersil Corporation as part of PRISM(R) chipset product development. ++* ++* -------------------------------------------------------------------- ++*/ ++ ++#ifndef _WLAN_COMPAT_H ++#define _WLAN_COMPAT_H ++ ++/*=============================================================*/ ++/*------ Bit settings -----------------------------------------*/ ++/*=============================================================*/ ++ ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++ ++/*=============================================================*/ ++/*------ Compiler Portability Macros --------------------------*/ ++/*=============================================================*/ ++#define __WLAN_ATTRIB_PACK__ __attribute__ ((packed)) ++ ++/*=============================================================*/ ++/*------ OS Portability Macros --------------------------------*/ ++/*=============================================================*/ ++ ++#ifndef WLAN_DBVAR ++#define WLAN_DBVAR wlan_debug ++#endif ++ ++#define WLAN_RELEASE "0.3.0-lkml" ++ ++#include ++ ++#define WLAN_LOG_ERROR(x,args...) printk(KERN_ERR "%s: " x , __func__ , ##args); ++ ++#define WLAN_LOG_WARNING(x,args...) printk(KERN_WARNING "%s: " x , __func__ , ##args); ++ ++#define WLAN_LOG_NOTICE(x,args...) printk(KERN_NOTICE "%s: " x , __func__ , ##args); ++ ++#define WLAN_LOG_INFO(args... ) printk(KERN_INFO args) ++ ++#if defined(WLAN_INCLUDE_DEBUG) ++ #define WLAN_HEX_DUMP( l, x, p, n) if( WLAN_DBVAR >= (l) ){ \ ++ int __i__; \ ++ printk(KERN_DEBUG x ":"); \ ++ for( __i__=0; __i__ < (n); __i__++) \ ++ printk( " %02x", ((u8*)(p))[__i__]); \ ++ printk("\n"); } ++ #define DBFENTER { if ( WLAN_DBVAR >= 5 ){ WLAN_LOG_DEBUG(3,"---->\n"); } } ++ #define DBFEXIT { if ( WLAN_DBVAR >= 5 ){ WLAN_LOG_DEBUG(3,"<----\n"); } } ++ ++ #define WLAN_LOG_DEBUG(l,x,args...) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s(%lu): " x , __func__, (preempt_count() & PREEMPT_MASK), ##args ); ++#else ++ #define WLAN_HEX_DUMP( l, s, p, n) ++ #define DBFENTER ++ #define DBFEXIT ++ ++ #define WLAN_LOG_DEBUG(l, s, args...) ++#endif ++ ++#undef netdevice_t ++typedef struct net_device netdevice_t; ++ ++#define URB_ASYNC_UNLINK 0 ++#define USB_QUEUE_BULK 0 ++ ++/*=============================================================*/ ++/*------ Hardware Portability Macros --------------------------*/ ++/*=============================================================*/ ++ ++#define ieee2host16(n) __le16_to_cpu(n) ++#define ieee2host32(n) __le32_to_cpu(n) ++#define host2ieee16(n) __cpu_to_le16(n) ++#define host2ieee32(n) __cpu_to_le32(n) ++ ++/*=============================================================*/ ++/*--- General Macros ------------------------------------------*/ ++/*=============================================================*/ ++ ++#define wlan_max(a, b) (((a) > (b)) ? (a) : (b)) ++#define wlan_min(a, b) (((a) < (b)) ? (a) : (b)) ++ ++#define wlan_isprint(c) (((c) > (0x19)) && ((c) < (0x7f))) ++ ++#define wlan_hexchar(x) (((x) < 0x0a) ? ('0' + (x)) : ('a' + ((x) - 0x0a))) ++ ++/* Create a string of printable chars from something that might not be */ ++/* It's recommended that the str be 4*len + 1 bytes long */ ++#define wlan_mkprintstr(buf, buflen, str, strlen) \ ++{ \ ++ int i = 0; \ ++ int j = 0; \ ++ memset(str, 0, (strlen)); \ ++ for (i = 0; i < (buflen); i++) { \ ++ if ( wlan_isprint((buf)[i]) ) { \ ++ (str)[j] = (buf)[i]; \ ++ j++; \ ++ } else { \ ++ (str)[j] = '\\'; \ ++ (str)[j+1] = 'x'; \ ++ (str)[j+2] = wlan_hexchar(((buf)[i] & 0xf0) >> 4); \ ++ (str)[j+3] = wlan_hexchar(((buf)[i] & 0x0f)); \ ++ j += 4; \ ++ } \ ++ } \ ++} ++ ++/*=============================================================*/ ++/*--- Variables -----------------------------------------------*/ ++/*=============================================================*/ ++ ++#ifdef WLAN_INCLUDE_DEBUG ++extern int wlan_debug; ++#endif ++ ++extern int wlan_ethconv; /* What's the default ethconv? */ ++ ++/*=============================================================*/ ++/*--- Functions -----------------------------------------------*/ ++/*=============================================================*/ ++#endif /* _WLAN_COMPAT_H */ ++ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0016-Staging-add-echo-cancelation-module.patch b/src/patches/suse-2.6.27.31/patches.drivers/0016-Staging-add-echo-cancelation-module.patch new file mode 100644 index 000000000..5088aca08 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0016-Staging-add-echo-cancelation-module.patch @@ -0,0 +1,1886 @@ +From 10602db812fa270fc923f5e48fb47202288828f3 Mon Sep 17 00:00:00 2001 +From: David Rowe +Date: Mon, 6 Oct 2008 21:41:46 -0700 +Subject: [PATCH 16/23] Staging: add echo cancelation module +Patch-mainline: 2.6.28 + +This is used by mISDN and Zaptel drivers. + +From: Steve Underwood +From: David Rowe +Cc: Tzafrir Cohen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/echo/Kconfig | 9 + + drivers/staging/echo/Makefile | 1 + + drivers/staging/echo/TODO | 10 + + drivers/staging/echo/bit_operations.h | 253 +++++++++++++ + drivers/staging/echo/echo.c | 632 +++++++++++++++++++++++++++++++++ + drivers/staging/echo/echo.h | 220 ++++++++++++ + drivers/staging/echo/fir.h | 369 +++++++++++++++++++ + drivers/staging/echo/mmx.h | 288 +++++++++++++++ + 10 files changed, 1785 insertions(+), 0 deletions(-) + create mode 100644 drivers/staging/echo/Kconfig + create mode 100644 drivers/staging/echo/Makefile + create mode 100644 drivers/staging/echo/TODO + create mode 100644 drivers/staging/echo/bit_operations.h + create mode 100644 drivers/staging/echo/echo.c + create mode 100644 drivers/staging/echo/echo.h + create mode 100644 drivers/staging/echo/fir.h + create mode 100644 drivers/staging/echo/mmx.h + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 762b471..25338b7 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -39,4 +39,6 @@ source "drivers/staging/winbond/Kconfig" + + source "drivers/staging/wlan-ng/Kconfig" + ++source "drivers/staging/echo/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 5741984..93decb8 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_VIDEO_GO7007) += go7007/ + obj-$(CONFIG_USB_IP_COMMON) += usbip/ + obj-$(CONFIG_W35UND) += winbond/ + obj-$(CONFIG_PRISM2_USB) += wlan-ng/ ++obj-$(CONFIG_ECHO) += echo/ +diff --git a/drivers/staging/echo/Kconfig b/drivers/staging/echo/Kconfig +new file mode 100644 +index 0000000..f1d41ea +--- /dev/null ++++ b/drivers/staging/echo/Kconfig +@@ -0,0 +1,9 @@ ++config ECHO ++ tristate "Line Echo Canceller support" ++ default n ++ ---help--- ++ This driver provides line echo cancelling support for mISDN and ++ Zaptel drivers. ++ ++ To compile this driver as a module, choose M here. The module ++ will be called echo. +diff --git a/drivers/staging/echo/Makefile b/drivers/staging/echo/Makefile +new file mode 100644 +index 0000000..7d4caac +--- /dev/null ++++ b/drivers/staging/echo/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_ECHO) += echo.o +diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO +new file mode 100644 +index 0000000..1ca09af +--- /dev/null ++++ b/drivers/staging/echo/TODO +@@ -0,0 +1,10 @@ ++TODO: ++ - checkpatch.pl cleanups ++ - Lindent ++ - typedef removals ++ - handle bit_operations.h (merge in or make part of common code?) ++ - remove proc interface, only use echo.h interface (proc interface is ++ racy and not correct.) ++ ++Please send patches to Greg Kroah-Hartman and Cc: Steve ++Underwood and David Rowe +diff --git a/drivers/staging/echo/bit_operations.h b/drivers/staging/echo/bit_operations.h +new file mode 100644 +index 0000000..b32f4bf +--- /dev/null ++++ b/drivers/staging/echo/bit_operations.h +@@ -0,0 +1,253 @@ ++/* ++ * SpanDSP - a series of DSP components for telephony ++ * ++ * bit_operations.h - Various bit level operations, such as bit reversal ++ * ++ * Written by Steve Underwood ++ * ++ * Copyright (C) 2006 Steve Underwood ++ * ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2, as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * $Id: bit_operations.h,v 1.11 2006/11/28 15:37:03 steveu Exp $ ++ */ ++ ++/*! \file */ ++ ++#if !defined(_BIT_OPERATIONS_H_) ++#define _BIT_OPERATIONS_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#if defined(__i386__) || defined(__x86_64__) ++/*! \brief Find the bit position of the highest set bit in a word ++ \param bits The word to be searched ++ \return The bit number of the highest set bit, or -1 if the word is zero. */ ++static __inline__ int top_bit(unsigned int bits) ++{ ++ int res; ++ ++ __asm__ (" xorl %[res],%[res];\n" ++ " decl %[res];\n" ++ " bsrl %[bits],%[res]\n" ++ : [res] "=&r" (res) ++ : [bits] "rm" (bits)); ++ return res; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/*! \brief Find the bit position of the lowest set bit in a word ++ \param bits The word to be searched ++ \return The bit number of the lowest set bit, or -1 if the word is zero. */ ++static __inline__ int bottom_bit(unsigned int bits) ++{ ++ int res; ++ ++ __asm__ (" xorl %[res],%[res];\n" ++ " decl %[res];\n" ++ " bsfl %[bits],%[res]\n" ++ : [res] "=&r" (res) ++ : [bits] "rm" (bits)); ++ return res; ++} ++/*- End of function --------------------------------------------------------*/ ++#else ++static __inline__ int top_bit(unsigned int bits) ++{ ++ int i; ++ ++ if (bits == 0) ++ return -1; ++ i = 0; ++ if (bits & 0xFFFF0000) ++ { ++ bits &= 0xFFFF0000; ++ i += 16; ++ } ++ if (bits & 0xFF00FF00) ++ { ++ bits &= 0xFF00FF00; ++ i += 8; ++ } ++ if (bits & 0xF0F0F0F0) ++ { ++ bits &= 0xF0F0F0F0; ++ i += 4; ++ } ++ if (bits & 0xCCCCCCCC) ++ { ++ bits &= 0xCCCCCCCC; ++ i += 2; ++ } ++ if (bits & 0xAAAAAAAA) ++ { ++ bits &= 0xAAAAAAAA; ++ i += 1; ++ } ++ return i; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ int bottom_bit(unsigned int bits) ++{ ++ int i; ++ ++ if (bits == 0) ++ return -1; ++ i = 32; ++ if (bits & 0x0000FFFF) ++ { ++ bits &= 0x0000FFFF; ++ i -= 16; ++ } ++ if (bits & 0x00FF00FF) ++ { ++ bits &= 0x00FF00FF; ++ i -= 8; ++ } ++ if (bits & 0x0F0F0F0F) ++ { ++ bits &= 0x0F0F0F0F; ++ i -= 4; ++ } ++ if (bits & 0x33333333) ++ { ++ bits &= 0x33333333; ++ i -= 2; ++ } ++ if (bits & 0x55555555) ++ { ++ bits &= 0x55555555; ++ i -= 1; ++ } ++ return i; ++} ++/*- End of function --------------------------------------------------------*/ ++#endif ++ ++/*! \brief Bit reverse a byte. ++ \param data The byte to be reversed. ++ \return The bit reversed version of data. */ ++static __inline__ uint8_t bit_reverse8(uint8_t x) ++{ ++#if defined(__i386__) || defined(__x86_64__) ++ /* If multiply is fast */ ++ return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16; ++#else ++ /* If multiply is slow, but we have a barrel shifter */ ++ x = (x >> 4) | (x << 4); ++ x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2); ++ return ((x & 0xAA) >> 1) | ((x & 0x55) << 1); ++#endif ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/*! \brief Bit reverse a 16 bit word. ++ \param data The word to be reversed. ++ \return The bit reversed version of data. */ ++uint16_t bit_reverse16(uint16_t data); ++ ++/*! \brief Bit reverse a 32 bit word. ++ \param data The word to be reversed. ++ \return The bit reversed version of data. */ ++uint32_t bit_reverse32(uint32_t data); ++ ++/*! \brief Bit reverse each of the four bytes in a 32 bit word. ++ \param data The word to be reversed. ++ \return The bit reversed version of data. */ ++uint32_t bit_reverse_4bytes(uint32_t data); ++ ++/*! \brief Find the number of set bits in a 32 bit word. ++ \param x The word to be searched. ++ \return The number of set bits. */ ++int one_bits32(uint32_t x); ++ ++/*! \brief Create a mask as wide as the number in a 32 bit word. ++ \param x The word to be searched. ++ \return The mask. */ ++uint32_t make_mask32(uint32_t x); ++ ++/*! \brief Create a mask as wide as the number in a 16 bit word. ++ \param x The word to be searched. ++ \return The mask. */ ++uint16_t make_mask16(uint16_t x); ++ ++/*! \brief Find the least significant one in a word, and return a word ++ with just that bit set. ++ \param x The word to be searched. ++ \return The word with the single set bit. */ ++static __inline__ uint32_t least_significant_one32(uint32_t x) ++{ ++ return (x & (-(int32_t) x)); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/*! \brief Find the most significant one in a word, and return a word ++ with just that bit set. ++ \param x The word to be searched. ++ \return The word with the single set bit. */ ++static __inline__ uint32_t most_significant_one32(uint32_t x) ++{ ++#if defined(__i386__) || defined(__x86_64__) ++ return 1 << top_bit(x); ++#else ++ x = make_mask32(x); ++ return (x ^ (x >> 1)); ++#endif ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/*! \brief Find the parity of a byte. ++ \param x The byte to be checked. ++ \return 1 for odd, or 0 for even. */ ++static __inline__ int parity8(uint8_t x) ++{ ++ x = (x ^ (x >> 4)) & 0x0F; ++ return (0x6996 >> x) & 1; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/*! \brief Find the parity of a 16 bit word. ++ \param x The word to be checked. ++ \return 1 for odd, or 0 for even. */ ++static __inline__ int parity16(uint16_t x) ++{ ++ x ^= (x >> 8); ++ x = (x ^ (x >> 4)) & 0x0F; ++ return (0x6996 >> x) & 1; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/*! \brief Find the parity of a 32 bit word. ++ \param x The word to be checked. ++ \return 1 for odd, or 0 for even. */ ++static __inline__ int parity32(uint32_t x) ++{ ++ x ^= (x >> 16); ++ x ^= (x >> 8); ++ x = (x ^ (x >> 4)) & 0x0F; ++ return (0x6996 >> x) & 1; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif ++/*- End of file ------------------------------------------------------------*/ +diff --git a/drivers/staging/echo/echo.c b/drivers/staging/echo/echo.c +new file mode 100644 +index 0000000..4a281b1 +--- /dev/null ++++ b/drivers/staging/echo/echo.c +@@ -0,0 +1,632 @@ ++/* ++ * SpanDSP - a series of DSP components for telephony ++ * ++ * echo.c - A line echo canceller. This code is being developed ++ * against and partially complies with G168. ++ * ++ * Written by Steve Underwood ++ * and David Rowe ++ * ++ * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe ++ * ++ * Based on a bit from here, a bit from there, eye of toad, ear of ++ * bat, 15 years of failed attempts by David and a few fried brain ++ * cells. ++ * ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2, as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * $Id: echo.c,v 1.20 2006/12/01 18:00:48 steveu Exp $ ++ */ ++ ++/*! \file */ ++ ++/* Implementation Notes ++ David Rowe ++ April 2007 ++ ++ This code started life as Steve's NLMS algorithm with a tap ++ rotation algorithm to handle divergence during double talk. I ++ added a Geigel Double Talk Detector (DTD) [2] and performed some ++ G168 tests. However I had trouble meeting the G168 requirements, ++ especially for double talk - there were always cases where my DTD ++ failed, for example where near end speech was under the 6dB ++ threshold required for declaring double talk. ++ ++ So I tried a two path algorithm [1], which has so far given better ++ results. The original tap rotation/Geigel algorithm is available ++ in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit. ++ It's probably possible to make it work if some one wants to put some ++ serious work into it. ++ ++ At present no special treatment is provided for tones, which ++ generally cause NLMS algorithms to diverge. Initial runs of a ++ subset of the G168 tests for tones (e.g ./echo_test 6) show the ++ current algorithm is passing OK, which is kind of surprising. The ++ full set of tests needs to be performed to confirm this result. ++ ++ One other interesting change is that I have managed to get the NLMS ++ code to work with 16 bit coefficients, rather than the original 32 ++ bit coefficents. This reduces the MIPs and storage required. ++ I evaulated the 16 bit port using g168_tests.sh and listening tests ++ on 4 real-world samples. ++ ++ I also attempted the implementation of a block based NLMS update ++ [2] but although this passes g168_tests.sh it didn't converge well ++ on the real-world samples. I have no idea why, perhaps a scaling ++ problem. The block based code is also available in SVN ++ http://svn.rowetel.com/software/oslec/tags/before_16bit. If this ++ code can be debugged, it will lead to further reduction in MIPS, as ++ the block update code maps nicely onto DSP instruction sets (it's a ++ dot product) compared to the current sample-by-sample update. ++ ++ Steve also has some nice notes on echo cancellers in echo.h ++ ++ ++ References: ++ ++ [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo ++ Path Models", IEEE Transactions on communications, COM-25, ++ No. 6, June ++ 1977. ++ http://www.rowetel.com/images/echo/dual_path_paper.pdf ++ ++ [2] The classic, very useful paper that tells you how to ++ actually build a real world echo canceller: ++ Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice ++ Echo Canceller with a TMS320020, ++ http://www.rowetel.com/images/echo/spra129.pdf ++ ++ [3] I have written a series of blog posts on this work, here is ++ Part 1: http://www.rowetel.com/blog/?p=18 ++ ++ [4] The source code http://svn.rowetel.com/software/oslec/ ++ ++ [5] A nice reference on LMS filters: ++ http://en.wikipedia.org/wiki/Least_mean_squares_filter ++ ++ Credits: ++ ++ Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan ++ Muthukrishnan for their suggestions and email discussions. Thanks ++ also to those people who collected echo samples for me such as ++ Mark, Pawel, and Pavel. ++*/ ++ ++#include /* We're doing kernel work */ ++#include ++#include ++#include ++#define malloc(a) kmalloc((a), GFP_KERNEL) ++#define free(a) kfree(a) ++ ++#include "bit_operations.h" ++#include "echo.h" ++ ++#define MIN_TX_POWER_FOR_ADAPTION 64 ++#define MIN_RX_POWER_FOR_ADAPTION 64 ++#define DTD_HANGOVER 600 /* 600 samples, or 75ms */ ++#define DC_LOG2BETA 3 /* log2() of DC filter Beta */ ++ ++/*-----------------------------------------------------------------------*\ ++ FUNCTIONS ++\*-----------------------------------------------------------------------*/ ++ ++/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */ ++ ++ ++#ifdef __BLACKFIN_ASM__ ++static void __inline__ lms_adapt_bg(echo_can_state_t *ec, int clean, int shift) ++{ ++ int i, j; ++ int offset1; ++ int offset2; ++ int factor; ++ int exp; ++ int16_t *phist; ++ int n; ++ ++ if (shift > 0) ++ factor = clean << shift; ++ else ++ factor = clean >> -shift; ++ ++ /* Update the FIR taps */ ++ ++ offset2 = ec->curr_pos; ++ offset1 = ec->taps - offset2; ++ phist = &ec->fir_state_bg.history[offset2]; ++ ++ /* st: and en: help us locate the assembler in echo.s */ ++ ++ //asm("st:"); ++ n = ec->taps; ++ for (i = 0, j = offset2; i < n; i++, j++) ++ { ++ exp = *phist++ * factor; ++ ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15); ++ } ++ //asm("en:"); ++ ++ /* Note the asm for the inner loop above generated by Blackfin gcc ++ 4.1.1 is pretty good (note even parallel instructions used): ++ ++ R0 = W [P0++] (X); ++ R0 *= R2; ++ R0 = R0 + R3 (NS) || ++ R1 = W [P1] (X) || ++ nop; ++ R0 >>>= 15; ++ R0 = R0 + R1; ++ W [P1++] = R0; ++ ++ A block based update algorithm would be much faster but the ++ above can't be improved on much. Every instruction saved in ++ the loop above is 2 MIPs/ch! The for loop above is where the ++ Blackfin spends most of it's time - about 17 MIPs/ch measured ++ with speedtest.c with 256 taps (32ms). Write-back and ++ Write-through cache gave about the same performance. ++ */ ++} ++ ++/* ++ IDEAS for further optimisation of lms_adapt_bg(): ++ ++ 1/ The rounding is quite costly. Could we keep as 32 bit coeffs ++ then make filter pluck the MS 16-bits of the coeffs when filtering? ++ However this would lower potential optimisation of filter, as I ++ think the dual-MAC architecture requires packed 16 bit coeffs. ++ ++ 2/ Block based update would be more efficient, as per comments above, ++ could use dual MAC architecture. ++ ++ 3/ Look for same sample Blackfin LMS code, see if we can get dual-MAC ++ packing. ++ ++ 4/ Execute the whole e/c in a block of say 20ms rather than sample ++ by sample. Processing a few samples every ms is inefficient. ++*/ ++ ++#else ++static __inline__ void lms_adapt_bg(echo_can_state_t *ec, int clean, int shift) ++{ ++ int i; ++ ++ int offset1; ++ int offset2; ++ int factor; ++ int exp; ++ ++ if (shift > 0) ++ factor = clean << shift; ++ else ++ factor = clean >> -shift; ++ ++ /* Update the FIR taps */ ++ ++ offset2 = ec->curr_pos; ++ offset1 = ec->taps - offset2; ++ ++ for (i = ec->taps - 1; i >= offset1; i--) ++ { ++ exp = (ec->fir_state_bg.history[i - offset1]*factor); ++ ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15); ++ } ++ for ( ; i >= 0; i--) ++ { ++ exp = (ec->fir_state_bg.history[i + offset2]*factor); ++ ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15); ++ } ++} ++#endif ++ ++/*- End of function --------------------------------------------------------*/ ++ ++echo_can_state_t *echo_can_create(int len, int adaption_mode) ++{ ++ echo_can_state_t *ec; ++ int i; ++ int j; ++ ++ ec = kmalloc(sizeof(*ec), GFP_KERNEL); ++ if (ec == NULL) ++ return NULL; ++ memset(ec, 0, sizeof(*ec)); ++ ++ ec->taps = len; ++ ec->log2taps = top_bit(len); ++ ec->curr_pos = ec->taps - 1; ++ ++ for (i = 0; i < 2; i++) ++ { ++ if ((ec->fir_taps16[i] = (int16_t *) malloc((ec->taps)*sizeof(int16_t))) == NULL) ++ { ++ for (j = 0; j < i; j++) ++ kfree(ec->fir_taps16[j]); ++ kfree(ec); ++ return NULL; ++ } ++ memset(ec->fir_taps16[i], 0, (ec->taps)*sizeof(int16_t)); ++ } ++ ++ fir16_create(&ec->fir_state, ++ ec->fir_taps16[0], ++ ec->taps); ++ fir16_create(&ec->fir_state_bg, ++ ec->fir_taps16[1], ++ ec->taps); ++ ++ for(i=0; i<5; i++) { ++ ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0; ++ } ++ ++ ec->cng_level = 1000; ++ echo_can_adaption_mode(ec, adaption_mode); ++ ++ ec->snapshot = (int16_t*)malloc(ec->taps*sizeof(int16_t)); ++ memset(ec->snapshot, 0, sizeof(int16_t)*ec->taps); ++ ++ ec->cond_met = 0; ++ ec->Pstates = 0; ++ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0; ++ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0; ++ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0; ++ ec->Lbgn = ec->Lbgn_acc = 0; ++ ec->Lbgn_upper = 200; ++ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13; ++ ++ return ec; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++void echo_can_free(echo_can_state_t *ec) ++{ ++ int i; ++ ++ fir16_free(&ec->fir_state); ++ fir16_free(&ec->fir_state_bg); ++ for (i = 0; i < 2; i++) ++ kfree(ec->fir_taps16[i]); ++ kfree(ec->snapshot); ++ kfree(ec); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode) ++{ ++ ec->adaption_mode = adaption_mode; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++void echo_can_flush(echo_can_state_t *ec) ++{ ++ int i; ++ ++ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0; ++ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0; ++ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0; ++ ++ ec->Lbgn = ec->Lbgn_acc = 0; ++ ec->Lbgn_upper = 200; ++ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13; ++ ++ ec->nonupdate_dwell = 0; ++ ++ fir16_flush(&ec->fir_state); ++ fir16_flush(&ec->fir_state_bg); ++ ec->fir_state.curr_pos = ec->taps - 1; ++ ec->fir_state_bg.curr_pos = ec->taps - 1; ++ for (i = 0; i < 2; i++) ++ memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t)); ++ ++ ec->curr_pos = ec->taps - 1; ++ ec->Pstates = 0; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++void echo_can_snapshot(echo_can_state_t *ec) { ++ memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps*sizeof(int16_t)); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++/* Dual Path Echo Canceller ------------------------------------------------*/ ++ ++int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx) ++{ ++ int32_t echo_value; ++ int clean_bg; ++ int tmp, tmp1; ++ ++ /* Input scaling was found be required to prevent problems when tx ++ starts clipping. Another possible way to handle this would be the ++ filter coefficent scaling. */ ++ ++ ec->tx = tx; ec->rx = rx; ++ tx >>=1; ++ rx >>=1; ++ ++ /* ++ Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required ++ otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta) ++ only real axis. Some chip sets (like Si labs) don't need ++ this, but something like a $10 X100P card does. Any DC really slows ++ down convergence. ++ ++ Note: removes some low frequency from the signal, this reduces ++ the speech quality when listening to samples through headphones ++ but may not be obvious through a telephone handset. ++ ++ Note that the 3dB frequency in radians is approx Beta, e.g. for ++ Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz. ++ */ ++ ++ if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) { ++ tmp = rx << 15; ++#if 1 ++ /* Make sure the gain of the HPF is 1.0. This can still saturate a little under ++ impulse conditions, and it might roll to 32768 and need clipping on sustained peak ++ level signals. However, the scale of such clipping is small, and the error due to ++ any saturation should not markedly affect the downstream processing. */ ++ tmp -= (tmp >> 4); ++#endif ++ ec->rx_1 += -(ec->rx_1>>DC_LOG2BETA) + tmp - ec->rx_2; ++ ++ /* hard limit filter to prevent clipping. Note that at this stage ++ rx should be limited to +/- 16383 due to right shift above */ ++ tmp1 = ec->rx_1 >> 15; ++ if (tmp1 > 16383) tmp1 = 16383; ++ if (tmp1 < -16383) tmp1 = -16383; ++ rx = tmp1; ++ ec->rx_2 = tmp; ++ } ++ ++ /* Block average of power in the filter states. Used for ++ adaption power calculation. */ ++ ++ { ++ int new, old; ++ ++ /* efficient "out with the old and in with the new" algorithm so ++ we don't have to recalculate over the whole block of ++ samples. */ ++ new = (int)tx * (int)tx; ++ old = (int)ec->fir_state.history[ec->fir_state.curr_pos] * ++ (int)ec->fir_state.history[ec->fir_state.curr_pos]; ++ ec->Pstates += ((new - old) + (1<log2taps)) >> ec->log2taps; ++ if (ec->Pstates < 0) ec->Pstates = 0; ++ } ++ ++ /* Calculate short term average levels using simple single pole IIRs */ ++ ++ ec->Ltxacc += abs(tx) - ec->Ltx; ++ ec->Ltx = (ec->Ltxacc + (1<<4)) >> 5; ++ ec->Lrxacc += abs(rx) - ec->Lrx; ++ ec->Lrx = (ec->Lrxacc + (1<<4)) >> 5; ++ ++ /* Foreground filter ---------------------------------------------------*/ ++ ++ ec->fir_state.coeffs = ec->fir_taps16[0]; ++ echo_value = fir16(&ec->fir_state, tx); ++ ec->clean = rx - echo_value; ++ ec->Lcleanacc += abs(ec->clean) - ec->Lclean; ++ ec->Lclean = (ec->Lcleanacc + (1<<4)) >> 5; ++ ++ /* Background filter ---------------------------------------------------*/ ++ ++ echo_value = fir16(&ec->fir_state_bg, tx); ++ clean_bg = rx - echo_value; ++ ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg; ++ ec->Lclean_bg = (ec->Lclean_bgacc + (1<<4)) >> 5; ++ ++ /* Background Filter adaption -----------------------------------------*/ ++ ++ /* Almost always adap bg filter, just simple DT and energy ++ detection to minimise adaption in cases of strong double talk. ++ However this is not critical for the dual path algorithm. ++ */ ++ ec->factor = 0; ++ ec->shift = 0; ++ if ((ec->nonupdate_dwell == 0)) { ++ int P, logP, shift; ++ ++ /* Determine: ++ ++ f = Beta * clean_bg_rx/P ------ (1) ++ ++ where P is the total power in the filter states. ++ ++ The Boffins have shown that if we obey (1) we converge ++ quickly and avoid instability. ++ ++ The correct factor f must be in Q30, as this is the fixed ++ point format required by the lms_adapt_bg() function, ++ therefore the scaled version of (1) is: ++ ++ (2^30) * f = (2^30) * Beta * clean_bg_rx/P ++ factor = (2^30) * Beta * clean_bg_rx/P ----- (2) ++ ++ We have chosen Beta = 0.25 by experiment, so: ++ ++ factor = (2^30) * (2^-2) * clean_bg_rx/P ++ ++ (30 - 2 - log2(P)) ++ factor = clean_bg_rx 2 ----- (3) ++ ++ To avoid a divide we approximate log2(P) as top_bit(P), ++ which returns the position of the highest non-zero bit in ++ P. This approximation introduces an error as large as a ++ factor of 2, but the algorithm seems to handle it OK. ++ ++ Come to think of it a divide may not be a big deal on a ++ modern DSP, so its probably worth checking out the cycles ++ for a divide versus a top_bit() implementation. ++ */ ++ ++ P = MIN_TX_POWER_FOR_ADAPTION + ec->Pstates; ++ logP = top_bit(P) + ec->log2taps; ++ shift = 30 - 2 - logP; ++ ec->shift = shift; ++ ++ lms_adapt_bg(ec, clean_bg, shift); ++ } ++ ++ /* very simple DTD to make sure we dont try and adapt with strong ++ near end speech */ ++ ++ ec->adapt = 0; ++ if ((ec->Lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->Lrx > ec->Ltx)) ++ ec->nonupdate_dwell = DTD_HANGOVER; ++ if (ec->nonupdate_dwell) ++ ec->nonupdate_dwell--; ++ ++ /* Transfer logic ------------------------------------------------------*/ ++ ++ /* These conditions are from the dual path paper [1], I messed with ++ them a bit to improve performance. */ ++ ++ if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && ++ (ec->nonupdate_dwell == 0) && ++ (8*ec->Lclean_bg < 7*ec->Lclean) /* (ec->Lclean_bg < 0.875*ec->Lclean) */ && ++ (8*ec->Lclean_bg < ec->Ltx) /* (ec->Lclean_bg < 0.125*ec->Ltx) */ ) ++ { ++ if (ec->cond_met == 6) { ++ /* BG filter has had better results for 6 consecutive samples */ ++ ec->adapt = 1; ++ memcpy(ec->fir_taps16[0], ec->fir_taps16[1], ec->taps*sizeof(int16_t)); ++ } ++ else ++ ec->cond_met++; ++ } ++ else ++ ec->cond_met = 0; ++ ++ /* Non-Linear Processing ---------------------------------------------------*/ ++ ++ ec->clean_nlp = ec->clean; ++ if (ec->adaption_mode & ECHO_CAN_USE_NLP) ++ { ++ /* Non-linear processor - a fancy way to say "zap small signals, to avoid ++ residual echo due to (uLaw/ALaw) non-linearity in the channel.". */ ++ ++ if ((16*ec->Lclean < ec->Ltx)) ++ { ++ /* Our e/c has improved echo by at least 24 dB (each factor of 2 is 6dB, ++ so 2*2*2*2=16 is the same as 6+6+6+6=24dB) */ ++ if (ec->adaption_mode & ECHO_CAN_USE_CNG) ++ { ++ ec->cng_level = ec->Lbgn; ++ ++ /* Very elementary comfort noise generation. Just random ++ numbers rolled off very vaguely Hoth-like. DR: This ++ noise doesn't sound quite right to me - I suspect there ++ are some overlfow issues in the filtering as it's too ++ "crackly". TODO: debug this, maybe just play noise at ++ high level or look at spectrum. ++ */ ++ ++ ec->cng_rndnum = 1664525U*ec->cng_rndnum + 1013904223U; ++ ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5*ec->cng_filter) >> 3; ++ ec->clean_nlp = (ec->cng_filter*ec->cng_level*8) >> 14; ++ ++ } ++ else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) ++ { ++ /* This sounds much better than CNG */ ++ if (ec->clean_nlp > ec->Lbgn) ++ ec->clean_nlp = ec->Lbgn; ++ if (ec->clean_nlp < -ec->Lbgn) ++ ec->clean_nlp = -ec->Lbgn; ++ } ++ else ++ { ++ /* just mute the residual, doesn't sound very good, used mainly ++ in G168 tests */ ++ ec->clean_nlp = 0; ++ } ++ } ++ else { ++ /* Background noise estimator. I tried a few algorithms ++ here without much luck. This very simple one seems to ++ work best, we just average the level using a slow (1 sec ++ time const) filter if the current level is less than a ++ (experimentally derived) constant. This means we dont ++ include high level signals like near end speech. When ++ combined with CNG or especially CLIP seems to work OK. ++ */ ++ if (ec->Lclean < 40) { ++ ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn; ++ ec->Lbgn = (ec->Lbgn_acc + (1<<11)) >> 12; ++ } ++ } ++ } ++ ++ /* Roll around the taps buffer */ ++ if (ec->curr_pos <= 0) ++ ec->curr_pos = ec->taps; ++ ec->curr_pos--; ++ ++ if (ec->adaption_mode & ECHO_CAN_DISABLE) ++ ec->clean_nlp = rx; ++ ++ /* Output scaled back up again to match input scaling */ ++ ++ return (int16_t) ec->clean_nlp << 1; ++} ++ ++/*- End of function --------------------------------------------------------*/ ++ ++/* This function is seperated from the echo canceller is it is usually called ++ as part of the tx process. See rx HP (DC blocking) filter above, it's ++ the same design. ++ ++ Some soft phones send speech signals with a lot of low frequency ++ energy, e.g. down to 20Hz. This can make the hybrid non-linear ++ which causes the echo canceller to fall over. This filter can help ++ by removing any low frequency before it gets to the tx port of the ++ hybrid. ++ ++ It can also help by removing and DC in the tx signal. DC is bad ++ for LMS algorithms. ++ ++ This is one of the classic DC removal filters, adjusted to provide sufficient ++ bass rolloff to meet the above requirement to protect hybrids from things that ++ upset them. The difference between successive samples produces a lousy HPF, and ++ then a suitably placed pole flattens things out. The final result is a nicely ++ rolled off bass end. The filtering is implemented with extended fractional ++ precision, which noise shapes things, giving very clean DC removal. ++*/ ++ ++int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx) { ++ int tmp, tmp1; ++ ++ if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) { ++ tmp = tx << 15; ++#if 1 ++ /* Make sure the gain of the HPF is 1.0. The first can still saturate a little under ++ impulse conditions, and it might roll to 32768 and need clipping on sustained peak ++ level signals. However, the scale of such clipping is small, and the error due to ++ any saturation should not markedly affect the downstream processing. */ ++ tmp -= (tmp >> 4); ++#endif ++ ec->tx_1 += -(ec->tx_1>>DC_LOG2BETA) + tmp - ec->tx_2; ++ tmp1 = ec->tx_1 >> 15; ++ if (tmp1 > 32767) tmp1 = 32767; ++ if (tmp1 < -32767) tmp1 = -32767; ++ tx = tmp1; ++ ec->tx_2 = tmp; ++ } ++ ++ return tx; ++} +diff --git a/drivers/staging/echo/echo.h b/drivers/staging/echo/echo.h +new file mode 100644 +index 0000000..7a91b43 +--- /dev/null ++++ b/drivers/staging/echo/echo.h +@@ -0,0 +1,220 @@ ++/* ++ * SpanDSP - a series of DSP components for telephony ++ * ++ * echo.c - A line echo canceller. This code is being developed ++ * against and partially complies with G168. ++ * ++ * Written by Steve Underwood ++ * and David Rowe ++ * ++ * Copyright (C) 2001 Steve Underwood and 2007 David Rowe ++ * ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2, as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * $Id: echo.h,v 1.9 2006/10/24 13:45:28 steveu Exp $ ++ */ ++ ++#ifndef __ECHO_H ++#define __ECHO_H ++ ++/*! \page echo_can_page Line echo cancellation for voice ++ ++\section echo_can_page_sec_1 What does it do? ++This module aims to provide G.168-2002 compliant echo cancellation, to remove ++electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. ++ ++\section echo_can_page_sec_2 How does it work? ++The heart of the echo cancellor is FIR filter. This is adapted to match the ++echo impulse response of the telephone line. It must be long enough to ++adequately cover the duration of that impulse response. The signal transmitted ++to the telephone line is passed through the FIR filter. Once the FIR is ++properly adapted, the resulting output is an estimate of the echo signal ++received from the line. This is subtracted from the received signal. The result ++is an estimate of the signal which originated at the far end of the line, free ++from echos of our own transmitted signal. ++ ++The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and ++was introduced in 1960. It is the commonest form of filter adaption used in ++things like modem line equalisers and line echo cancellers. There it works very ++well. However, it only works well for signals of constant amplitude. It works ++very poorly for things like speech echo cancellation, where the signal level ++varies widely. This is quite easy to fix. If the signal level is normalised - ++similar to applying AGC - LMS can work as well for a signal of varying ++amplitude as it does for a modem signal. This normalised least mean squares ++(NLMS) algorithm is the commonest one used for speech echo cancellation. Many ++other algorithms exist - e.g. RLS (essentially the same as Kalman filtering), ++FAP, etc. Some perform significantly better than NLMS. However, factors such ++as computational complexity and patents favour the use of NLMS. ++ ++A simple refinement to NLMS can improve its performance with speech. NLMS tends ++to adapt best to the strongest parts of a signal. If the signal is white noise, ++the NLMS algorithm works very well. However, speech has more low frequency than ++high frequency content. Pre-whitening (i.e. filtering the signal to flatten its ++spectrum) the echo signal improves the adapt rate for speech, and ensures the ++final residual signal is not heavily biased towards high frequencies. A very ++low complexity filter is adequate for this, so pre-whitening adds little to the ++compute requirements of the echo canceller. ++ ++An FIR filter adapted using pre-whitened NLMS performs well, provided certain ++conditions are met: ++ ++ - The transmitted signal has poor self-correlation. ++ - There is no signal being generated within the environment being ++ cancelled. ++ ++The difficulty is that neither of these can be guaranteed. ++ ++If the adaption is performed while transmitting noise (or something fairly ++noise like, such as voice) the adaption works very well. If the adaption is ++performed while transmitting something highly correlative (typically narrow ++band energy such as signalling tones or DTMF), the adaption can go seriously ++wrong. The reason is there is only one solution for the adaption on a near ++random signal - the impulse response of the line. For a repetitive signal, ++there are any number of solutions which converge the adaption, and nothing ++guides the adaption to choose the generalised one. Allowing an untrained ++canceller to converge on this kind of narrowband energy probably a good thing, ++since at least it cancels the tones. Allowing a well converged canceller to ++continue converging on such energy is just a way to ruin its generalised ++adaption. A narrowband detector is needed, so adapation can be suspended at ++appropriate times. ++ ++The adaption process is based on trying to eliminate the received signal. When ++there is any signal from within the environment being cancelled it may upset ++the adaption process. Similarly, if the signal we are transmitting is small, ++noise may dominate and disturb the adaption process. If we can ensure that the ++adaption is only performed when we are transmitting a significant signal level, ++and the environment is not, things will be OK. Clearly, it is easy to tell when ++we are sending a significant signal. Telling, if the environment is generating ++a significant signal, and doing it with sufficient speed that the adaption will ++not have diverged too much more we stop it, is a little harder. ++ ++The key problem in detecting when the environment is sourcing significant ++energy is that we must do this very quickly. Given a reasonably long sample of ++the received signal, there are a number of strategies which may be used to ++assess whether that signal contains a strong far end component. However, by the ++time that assessment is complete the far end signal will have already caused ++major mis-convergence in the adaption process. An assessment algorithm is ++needed which produces a fairly accurate result from a very short burst of far ++end energy. ++ ++\section echo_can_page_sec_3 How do I use it? ++The echo cancellor processes both the transmit and receive streams sample by ++sample. The processing function is not declared inline. Unfortunately, ++cancellation requires many operations per sample, so the call overhead is only ++a minor burden. ++*/ ++ ++#include "fir.h" ++ ++/* Mask bits for the adaption mode */ ++#define ECHO_CAN_USE_ADAPTION 0x01 ++#define ECHO_CAN_USE_NLP 0x02 ++#define ECHO_CAN_USE_CNG 0x04 ++#define ECHO_CAN_USE_CLIP 0x08 ++#define ECHO_CAN_USE_TX_HPF 0x10 ++#define ECHO_CAN_USE_RX_HPF 0x20 ++#define ECHO_CAN_DISABLE 0x40 ++ ++/*! ++ G.168 echo canceller descriptor. This defines the working state for a line ++ echo canceller. ++*/ ++typedef struct ++{ ++ int16_t tx,rx; ++ int16_t clean; ++ int16_t clean_nlp; ++ ++ int nonupdate_dwell; ++ int curr_pos; ++ int taps; ++ int log2taps; ++ int adaption_mode; ++ ++ int cond_met; ++ int32_t Pstates; ++ int16_t adapt; ++ int32_t factor; ++ int16_t shift; ++ ++ /* Average levels and averaging filter states */ ++ int Ltxacc, Lrxacc, Lcleanacc, Lclean_bgacc; ++ int Ltx, Lrx; ++ int Lclean; ++ int Lclean_bg; ++ int Lbgn, Lbgn_acc, Lbgn_upper, Lbgn_upper_acc; ++ ++ /* foreground and background filter states */ ++ fir16_state_t fir_state; ++ fir16_state_t fir_state_bg; ++ int16_t *fir_taps16[2]; ++ ++ /* DC blocking filter states */ ++ int tx_1, tx_2, rx_1, rx_2; ++ ++ /* optional High Pass Filter states */ ++ int32_t xvtx[5], yvtx[5]; ++ int32_t xvrx[5], yvrx[5]; ++ ++ /* Parameters for the optional Hoth noise generator */ ++ int cng_level; ++ int cng_rndnum; ++ int cng_filter; ++ ++ /* snapshot sample of coeffs used for development */ ++ int16_t *snapshot; ++} echo_can_state_t; ++ ++/*! Create a voice echo canceller context. ++ \param len The length of the canceller, in samples. ++ \return The new canceller context, or NULL if the canceller could not be created. ++*/ ++echo_can_state_t *echo_can_create(int len, int adaption_mode); ++ ++/*! Free a voice echo canceller context. ++ \param ec The echo canceller context. ++*/ ++void echo_can_free(echo_can_state_t *ec); ++ ++/*! Flush (reinitialise) a voice echo canceller context. ++ \param ec The echo canceller context. ++*/ ++void echo_can_flush(echo_can_state_t *ec); ++ ++/*! Set the adaption mode of a voice echo canceller context. ++ \param ec The echo canceller context. ++ \param adapt The mode. ++*/ ++void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode); ++ ++void echo_can_snapshot(echo_can_state_t *ec); ++ ++/*! Process a sample through a voice echo canceller. ++ \param ec The echo canceller context. ++ \param tx The transmitted audio sample. ++ \param rx The received audio sample. ++ \return The clean (echo cancelled) received sample. ++*/ ++int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx); ++ ++/*! Process to high pass filter the tx signal. ++ \param ec The echo canceller context. ++ \param tx The transmitted auio sample. ++ \return The HP filtered transmit sample, send this to your D/A. ++*/ ++int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx); ++ ++#endif /* __ECHO_H */ +diff --git a/drivers/staging/echo/fir.h b/drivers/staging/echo/fir.h +new file mode 100644 +index 0000000..e1bfc49 +--- /dev/null ++++ b/drivers/staging/echo/fir.h +@@ -0,0 +1,369 @@ ++/* ++ * SpanDSP - a series of DSP components for telephony ++ * ++ * fir.h - General telephony FIR routines ++ * ++ * Written by Steve Underwood ++ * ++ * Copyright (C) 2002 Steve Underwood ++ * ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2, as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * $Id: fir.h,v 1.8 2006/10/24 13:45:28 steveu Exp $ ++ */ ++ ++/*! \page fir_page FIR filtering ++\section fir_page_sec_1 What does it do? ++???. ++ ++\section fir_page_sec_2 How does it work? ++???. ++*/ ++ ++#if !defined(_FIR_H_) ++#define _FIR_H_ ++ ++/* ++ Blackfin NOTES & IDEAS: ++ ++ A simple dot product function is used to implement the filter. This performs ++ just one MAC/cycle which is inefficient but was easy to implement as a first ++ pass. The current Blackfin code also uses an unrolled form of the filter ++ history to avoid 0 length hardware loop issues. This is wasteful of ++ memory. ++ ++ Ideas for improvement: ++ ++ 1/ Rewrite filter for dual MAC inner loop. The issue here is handling ++ history sample offsets that are 16 bit aligned - the dual MAC needs ++ 32 bit aligmnent. There are some good examples in libbfdsp. ++ ++ 2/ Use the hardware circular buffer facility tohalve memory usage. ++ ++ 3/ Consider using internal memory. ++ ++ Using less memory might also improve speed as cache misses will be ++ reduced. A drop in MIPs and memory approaching 50% should be ++ possible. ++ ++ The foreground and background filters currenlty use a total of ++ about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo ++ can. ++*/ ++ ++#if defined(USE_MMX) || defined(USE_SSE2) ++#include "mmx.h" ++#endif ++ ++/*! ++ 16 bit integer FIR descriptor. This defines the working state for a single ++ instance of an FIR filter using 16 bit integer coefficients. ++*/ ++typedef struct ++{ ++ int taps; ++ int curr_pos; ++ const int16_t *coeffs; ++ int16_t *history; ++} fir16_state_t; ++ ++/*! ++ 32 bit integer FIR descriptor. This defines the working state for a single ++ instance of an FIR filter using 32 bit integer coefficients, and filtering ++ 16 bit integer data. ++*/ ++typedef struct ++{ ++ int taps; ++ int curr_pos; ++ const int32_t *coeffs; ++ int16_t *history; ++} fir32_state_t; ++ ++/*! ++ Floating point FIR descriptor. This defines the working state for a single ++ instance of an FIR filter using floating point coefficients and data. ++*/ ++typedef struct ++{ ++ int taps; ++ int curr_pos; ++ const float *coeffs; ++ float *history; ++} fir_float_state_t; ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++static __inline__ const int16_t *fir16_create(fir16_state_t *fir, ++ const int16_t *coeffs, ++ int taps) ++{ ++ fir->taps = taps; ++ fir->curr_pos = taps - 1; ++ fir->coeffs = coeffs; ++#if defined(USE_MMX) || defined(USE_SSE2) || defined(__BLACKFIN_ASM__) ++ if ((fir->history = malloc(2*taps*sizeof(int16_t)))) ++ memset(fir->history, 0, 2*taps*sizeof(int16_t)); ++#else ++ if ((fir->history = (int16_t *) malloc(taps*sizeof(int16_t)))) ++ memset(fir->history, 0, taps*sizeof(int16_t)); ++#endif ++ return fir->history; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ void fir16_flush(fir16_state_t *fir) ++{ ++#if defined(USE_MMX) || defined(USE_SSE2) || defined(__BLACKFIN_ASM__) ++ memset(fir->history, 0, 2*fir->taps*sizeof(int16_t)); ++#else ++ memset(fir->history, 0, fir->taps*sizeof(int16_t)); ++#endif ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ void fir16_free(fir16_state_t *fir) ++{ ++ free(fir->history); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++#ifdef __BLACKFIN_ASM__ ++static inline int32_t dot_asm(short *x, short *y, int len) ++{ ++ int dot; ++ ++ len--; ++ ++ __asm__ ++ ( ++ "I0 = %1;\n\t" ++ "I1 = %2;\n\t" ++ "A0 = 0;\n\t" ++ "R0.L = W[I0++] || R1.L = W[I1++];\n\t" ++ "LOOP dot%= LC0 = %3;\n\t" ++ "LOOP_BEGIN dot%=;\n\t" ++ "A0 += R0.L * R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t" ++ "LOOP_END dot%=;\n\t" ++ "A0 += R0.L*R1.L (IS);\n\t" ++ "R0 = A0;\n\t" ++ "%0 = R0;\n\t" ++ : "=&d" (dot) ++ : "a" (x), "a" (y), "a" (len) ++ : "I0", "I1", "A1", "A0", "R0", "R1" ++ ); ++ ++ return dot; ++} ++#endif ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ int16_t fir16(fir16_state_t *fir, int16_t sample) ++{ ++ int32_t y; ++#if defined(USE_MMX) ++ int i; ++ mmx_t *mmx_coeffs; ++ mmx_t *mmx_hist; ++ ++ fir->history[fir->curr_pos] = sample; ++ fir->history[fir->curr_pos + fir->taps] = sample; ++ ++ mmx_coeffs = (mmx_t *) fir->coeffs; ++ mmx_hist = (mmx_t *) &fir->history[fir->curr_pos]; ++ i = fir->taps; ++ pxor_r2r(mm4, mm4); ++ /* 8 samples per iteration, so the filter must be a multiple of 8 long. */ ++ while (i > 0) ++ { ++ movq_m2r(mmx_coeffs[0], mm0); ++ movq_m2r(mmx_coeffs[1], mm2); ++ movq_m2r(mmx_hist[0], mm1); ++ movq_m2r(mmx_hist[1], mm3); ++ mmx_coeffs += 2; ++ mmx_hist += 2; ++ pmaddwd_r2r(mm1, mm0); ++ pmaddwd_r2r(mm3, mm2); ++ paddd_r2r(mm0, mm4); ++ paddd_r2r(mm2, mm4); ++ i -= 8; ++ } ++ movq_r2r(mm4, mm0); ++ psrlq_i2r(32, mm0); ++ paddd_r2r(mm0, mm4); ++ movd_r2m(mm4, y); ++ emms(); ++#elif defined(USE_SSE2) ++ int i; ++ xmm_t *xmm_coeffs; ++ xmm_t *xmm_hist; ++ ++ fir->history[fir->curr_pos] = sample; ++ fir->history[fir->curr_pos + fir->taps] = sample; ++ ++ xmm_coeffs = (xmm_t *) fir->coeffs; ++ xmm_hist = (xmm_t *) &fir->history[fir->curr_pos]; ++ i = fir->taps; ++ pxor_r2r(xmm4, xmm4); ++ /* 16 samples per iteration, so the filter must be a multiple of 16 long. */ ++ while (i > 0) ++ { ++ movdqu_m2r(xmm_coeffs[0], xmm0); ++ movdqu_m2r(xmm_coeffs[1], xmm2); ++ movdqu_m2r(xmm_hist[0], xmm1); ++ movdqu_m2r(xmm_hist[1], xmm3); ++ xmm_coeffs += 2; ++ xmm_hist += 2; ++ pmaddwd_r2r(xmm1, xmm0); ++ pmaddwd_r2r(xmm3, xmm2); ++ paddd_r2r(xmm0, xmm4); ++ paddd_r2r(xmm2, xmm4); ++ i -= 16; ++ } ++ movdqa_r2r(xmm4, xmm0); ++ psrldq_i2r(8, xmm0); ++ paddd_r2r(xmm0, xmm4); ++ movdqa_r2r(xmm4, xmm0); ++ psrldq_i2r(4, xmm0); ++ paddd_r2r(xmm0, xmm4); ++ movd_r2m(xmm4, y); ++#elif defined(__BLACKFIN_ASM__) ++ fir->history[fir->curr_pos] = sample; ++ fir->history[fir->curr_pos + fir->taps] = sample; ++ y = dot_asm((int16_t*)fir->coeffs, &fir->history[fir->curr_pos], fir->taps); ++#else ++ int i; ++ int offset1; ++ int offset2; ++ ++ fir->history[fir->curr_pos] = sample; ++ ++ offset2 = fir->curr_pos; ++ offset1 = fir->taps - offset2; ++ y = 0; ++ for (i = fir->taps - 1; i >= offset1; i--) ++ y += fir->coeffs[i]*fir->history[i - offset1]; ++ for ( ; i >= 0; i--) ++ y += fir->coeffs[i]*fir->history[i + offset2]; ++#endif ++ if (fir->curr_pos <= 0) ++ fir->curr_pos = fir->taps; ++ fir->curr_pos--; ++ return (int16_t) (y >> 15); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ const int16_t *fir32_create(fir32_state_t *fir, ++ const int32_t *coeffs, ++ int taps) ++{ ++ fir->taps = taps; ++ fir->curr_pos = taps - 1; ++ fir->coeffs = coeffs; ++ fir->history = (int16_t *) malloc(taps*sizeof(int16_t)); ++ if (fir->history) ++ memset(fir->history, '\0', taps*sizeof(int16_t)); ++ return fir->history; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ void fir32_flush(fir32_state_t *fir) ++{ ++ memset(fir->history, 0, fir->taps*sizeof(int16_t)); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ void fir32_free(fir32_state_t *fir) ++{ ++ free(fir->history); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ int16_t fir32(fir32_state_t *fir, int16_t sample) ++{ ++ int i; ++ int32_t y; ++ int offset1; ++ int offset2; ++ ++ fir->history[fir->curr_pos] = sample; ++ offset2 = fir->curr_pos; ++ offset1 = fir->taps - offset2; ++ y = 0; ++ for (i = fir->taps - 1; i >= offset1; i--) ++ y += fir->coeffs[i]*fir->history[i - offset1]; ++ for ( ; i >= 0; i--) ++ y += fir->coeffs[i]*fir->history[i + offset2]; ++ if (fir->curr_pos <= 0) ++ fir->curr_pos = fir->taps; ++ fir->curr_pos--; ++ return (int16_t) (y >> 15); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++#ifndef __KERNEL__ ++static __inline__ const float *fir_float_create(fir_float_state_t *fir, ++ const float *coeffs, ++ int taps) ++{ ++ fir->taps = taps; ++ fir->curr_pos = taps - 1; ++ fir->coeffs = coeffs; ++ fir->history = (float *) malloc(taps*sizeof(float)); ++ if (fir->history) ++ memset(fir->history, '\0', taps*sizeof(float)); ++ return fir->history; ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ void fir_float_free(fir_float_state_t *fir) ++{ ++ free(fir->history); ++} ++/*- End of function --------------------------------------------------------*/ ++ ++static __inline__ int16_t fir_float(fir_float_state_t *fir, int16_t sample) ++{ ++ int i; ++ float y; ++ int offset1; ++ int offset2; ++ ++ fir->history[fir->curr_pos] = sample; ++ ++ offset2 = fir->curr_pos; ++ offset1 = fir->taps - offset2; ++ y = 0; ++ for (i = fir->taps - 1; i >= offset1; i--) ++ y += fir->coeffs[i]*fir->history[i - offset1]; ++ for ( ; i >= 0; i--) ++ y += fir->coeffs[i]*fir->history[i + offset2]; ++ if (fir->curr_pos <= 0) ++ fir->curr_pos = fir->taps; ++ fir->curr_pos--; ++ return (int16_t) y; ++} ++/*- End of function --------------------------------------------------------*/ ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif ++/*- End of file ------------------------------------------------------------*/ +diff --git a/drivers/staging/echo/mmx.h b/drivers/staging/echo/mmx.h +new file mode 100644 +index 0000000..b5a3964 +--- /dev/null ++++ b/drivers/staging/echo/mmx.h +@@ -0,0 +1,288 @@ ++/* ++ * mmx.h ++ * Copyright (C) 1997-2001 H. Dietz and R. Fisher ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#ifndef AVCODEC_I386MMX_H ++#define AVCODEC_I386MMX_H ++ ++/* ++ * The type of an value that fits in an MMX register (note that long ++ * long constant values MUST be suffixed by LL and unsigned long long ++ * values by ULL, lest they be truncated by the compiler) ++ */ ++ ++typedef union { ++ long long q; /* Quadword (64-bit) value */ ++ unsigned long long uq; /* Unsigned Quadword */ ++ int d[2]; /* 2 Doubleword (32-bit) values */ ++ unsigned int ud[2]; /* 2 Unsigned Doubleword */ ++ short w[4]; /* 4 Word (16-bit) values */ ++ unsigned short uw[4]; /* 4 Unsigned Word */ ++ char b[8]; /* 8 Byte (8-bit) values */ ++ unsigned char ub[8]; /* 8 Unsigned Byte */ ++ float s[2]; /* Single-precision (32-bit) value */ ++} mmx_t; /* On an 8-byte (64-bit) boundary */ ++ ++/* SSE registers */ ++typedef union { ++ char b[16]; ++} xmm_t; ++ ++ ++#define mmx_i2r(op,imm,reg) \ ++ __asm__ __volatile__ (#op " %0, %%" #reg \ ++ : /* nothing */ \ ++ : "i" (imm) ) ++ ++#define mmx_m2r(op,mem,reg) \ ++ __asm__ __volatile__ (#op " %0, %%" #reg \ ++ : /* nothing */ \ ++ : "m" (mem)) ++ ++#define mmx_r2m(op,reg,mem) \ ++ __asm__ __volatile__ (#op " %%" #reg ", %0" \ ++ : "=m" (mem) \ ++ : /* nothing */ ) ++ ++#define mmx_r2r(op,regs,regd) \ ++ __asm__ __volatile__ (#op " %" #regs ", %" #regd) ++ ++ ++#define emms() __asm__ __volatile__ ("emms") ++ ++#define movd_m2r(var,reg) mmx_m2r (movd, var, reg) ++#define movd_r2m(reg,var) mmx_r2m (movd, reg, var) ++#define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd) ++ ++#define movq_m2r(var,reg) mmx_m2r (movq, var, reg) ++#define movq_r2m(reg,var) mmx_r2m (movq, reg, var) ++#define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd) ++ ++#define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg) ++#define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd) ++#define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg) ++#define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd) ++ ++#define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg) ++#define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd) ++ ++#define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg) ++#define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd) ++#define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg) ++#define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd) ++#define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg) ++#define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd) ++ ++#define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg) ++#define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd) ++#define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg) ++#define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd) ++ ++#define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg) ++#define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd) ++#define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg) ++#define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd) ++ ++#define pand_m2r(var,reg) mmx_m2r (pand, var, reg) ++#define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd) ++ ++#define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg) ++#define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd) ++ ++#define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg) ++#define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd) ++#define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg) ++#define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd) ++#define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg) ++#define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd) ++ ++#define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg) ++#define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd) ++#define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg) ++#define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd) ++#define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg) ++#define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd) ++ ++#define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg) ++#define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd) ++ ++#define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg) ++#define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd) ++ ++#define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg) ++#define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd) ++ ++#define por_m2r(var,reg) mmx_m2r (por, var, reg) ++#define por_r2r(regs,regd) mmx_r2r (por, regs, regd) ++ ++#define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg) ++#define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg) ++#define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd) ++#define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg) ++#define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg) ++#define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd) ++#define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg) ++#define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg) ++#define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd) ++ ++#define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg) ++#define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg) ++#define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd) ++#define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg) ++#define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg) ++#define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd) ++ ++#define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg) ++#define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg) ++#define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd) ++#define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg) ++#define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg) ++#define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd) ++#define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg) ++#define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg) ++#define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd) ++ ++#define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg) ++#define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd) ++#define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg) ++#define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd) ++#define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg) ++#define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd) ++ ++#define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg) ++#define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd) ++#define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg) ++#define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd) ++ ++#define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg) ++#define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd) ++#define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg) ++#define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd) ++ ++#define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg) ++#define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd) ++#define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg) ++#define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd) ++#define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg) ++#define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd) ++ ++#define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg) ++#define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd) ++#define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg) ++#define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd) ++#define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg) ++#define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd) ++ ++#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg) ++#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd) ++ ++ ++/* 3DNOW extensions */ ++ ++#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg) ++#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd) ++ ++ ++/* AMD MMX extensions - also available in intel SSE */ ++ ++ ++#define mmx_m2ri(op,mem,reg,imm) \ ++ __asm__ __volatile__ (#op " %1, %0, %%" #reg \ ++ : /* nothing */ \ ++ : "m" (mem), "i" (imm)) ++#define mmx_r2ri(op,regs,regd,imm) \ ++ __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \ ++ : /* nothing */ \ ++ : "i" (imm) ) ++ ++#define mmx_fetch(mem,hint) \ ++ __asm__ __volatile__ ("prefetch" #hint " %0" \ ++ : /* nothing */ \ ++ : "m" (mem)) ++ ++ ++#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg) ++ ++#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var) ++ ++#define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg) ++#define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd) ++#define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg) ++#define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd) ++ ++#define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm) ++ ++#define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm) ++ ++#define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg) ++#define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd) ++ ++#define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg) ++#define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd) ++ ++#define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg) ++#define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd) ++ ++#define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg) ++#define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd) ++ ++#define pmovmskb(mmreg,reg) \ ++ __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) ++ ++#define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg) ++#define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd) ++ ++#define prefetcht0(mem) mmx_fetch (mem, t0) ++#define prefetcht1(mem) mmx_fetch (mem, t1) ++#define prefetcht2(mem) mmx_fetch (mem, t2) ++#define prefetchnta(mem) mmx_fetch (mem, nta) ++ ++#define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg) ++#define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd) ++ ++#define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm) ++#define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm) ++ ++#define sfence() __asm__ __volatile__ ("sfence\n\t") ++ ++/* SSE2 */ ++#define pshufhw_m2r(var,reg,imm) mmx_m2ri(pshufhw, var, reg, imm) ++#define pshufhw_r2r(regs,regd,imm) mmx_r2ri(pshufhw, regs, regd, imm) ++#define pshuflw_m2r(var,reg,imm) mmx_m2ri(pshuflw, var, reg, imm) ++#define pshuflw_r2r(regs,regd,imm) mmx_r2ri(pshuflw, regs, regd, imm) ++ ++#define pshufd_r2r(regs,regd,imm) mmx_r2ri(pshufd, regs, regd, imm) ++ ++#define movdqa_m2r(var,reg) mmx_m2r (movdqa, var, reg) ++#define movdqa_r2m(reg,var) mmx_r2m (movdqa, reg, var) ++#define movdqa_r2r(regs,regd) mmx_r2r (movdqa, regs, regd) ++#define movdqu_m2r(var,reg) mmx_m2r (movdqu, var, reg) ++#define movdqu_r2m(reg,var) mmx_r2m (movdqu, reg, var) ++#define movdqu_r2r(regs,regd) mmx_r2r (movdqu, regs, regd) ++ ++#define pmullw_r2m(reg,var) mmx_r2m (pmullw, reg, var) ++ ++#define pslldq_i2r(imm,reg) mmx_i2r (pslldq, imm, reg) ++#define psrldq_i2r(imm,reg) mmx_i2r (psrldq, imm, reg) ++ ++#define punpcklqdq_r2r(regs,regd) mmx_r2r (punpcklqdq, regs, regd) ++#define punpckhqdq_r2r(regs,regd) mmx_r2r (punpckhqdq, regs, regd) ++ ++ ++#endif /* AVCODEC_I386MMX_H */ +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0017-Staging-Fix-gcc-warnings-in-sxg.patch b/src/patches/suse-2.6.27.31/patches.drivers/0017-Staging-Fix-gcc-warnings-in-sxg.patch new file mode 100644 index 000000000..96b499b6a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0017-Staging-Fix-gcc-warnings-in-sxg.patch @@ -0,0 +1,60 @@ +From d63d692a44c918723895f792ffd17eab7bcfb8ef Mon Sep 17 00:00:00 2001 +From: J.R. Mauro +Date: Fri, 3 Oct 2008 12:21:49 -0400 +Subject: [PATCH 17/23] Staging: Fix gcc warnings in sxg +Patch-mainline: 2.6.28 + +Fix for compiler warning about format specifier in prints in +drivers/staging/sxg/sxg.c +Prints were using %x to print unsigned long data. + + +Signed-off-by: J.R. Mauro +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/sxg/sxg.c | 8 ++++---- + 1 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c +index a91c9f3..0117d51 100644 +--- a/drivers/staging/sxg/sxg.c ++++ b/drivers/staging/sxg/sxg.c +@@ -453,7 +453,7 @@ static int sxg_allocate_resources(p_adapter_t adapter) + // fails. If we hit a minimum, fail. + + for (;;) { +- DBG_ERROR("%s Allocate XmtRings size[%x]\n", __FUNCTION__, ++ DBG_ERROR("%s Allocate XmtRings size[%lx]\n", __FUNCTION__, + (sizeof(SXG_XMT_RING) * 1)); + + // Start with big items first - receive and transmit rings. At the moment +@@ -470,7 +470,7 @@ static int sxg_allocate_resources(p_adapter_t adapter) + } + memset(adapter->XmtRings, 0, sizeof(SXG_XMT_RING) * 1); + +- DBG_ERROR("%s Allocate RcvRings size[%x]\n", __FUNCTION__, ++ DBG_ERROR("%s Allocate RcvRings size[%lx]\n", __FUNCTION__, + (sizeof(SXG_RCV_RING) * 1)); + adapter->RcvRings = + pci_alloc_consistent(adapter->pcidev, +@@ -531,7 +531,7 @@ static int sxg_allocate_resources(p_adapter_t adapter) + return (STATUS_RESOURCES); + } + +- DBG_ERROR("%s Allocate EventRings size[%x]\n", __FUNCTION__, ++ DBG_ERROR("%s Allocate EventRings size[%lx]\n", __FUNCTION__, + (sizeof(SXG_EVENT_RING) * RssIds)); + + // Allocate event queues. +@@ -562,7 +562,7 @@ static int sxg_allocate_resources(p_adapter_t adapter) + } + memset(adapter->Isr, 0, sizeof(u32) * IsrCount); + +- DBG_ERROR("%s Allocate shared XMT ring zero index location size[%x]\n", ++ DBG_ERROR("%s Allocate shared XMT ring zero index location size[%lx]\n", + __FUNCTION__, sizeof(u32)); + + // Allocate shared XMT ring zero index location +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0018-Staging-go7007-v4l-fixes.patch b/src/patches/suse-2.6.27.31/patches.drivers/0018-Staging-go7007-v4l-fixes.patch new file mode 100644 index 000000000..9c4e29c4c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0018-Staging-go7007-v4l-fixes.patch @@ -0,0 +1,413 @@ +From df20d69ec968b33526461457c219ad4ba8ba8ac8 Mon Sep 17 00:00:00 2001 +From: Ross Cohen +Date: Mon, 29 Sep 2008 22:36:24 -0400 +Subject: [PATCH 18/23] Staging: go7007 v4l fixes +Patch-mainline: 2.6.28 + +Fix up some of the v4l issues that were recently changed to make the +go7007 driver a bit cleaner. + + +From: Ross Cohen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/go7007/go7007-driver.c | 2 +- + drivers/staging/go7007/go7007-v4l2.c | 12 ++++-------- + drivers/staging/go7007/snd-go7007.c | 4 ++-- + drivers/staging/go7007/wis-ov7640.c | 3 +-- + drivers/staging/go7007/wis-saa7113.c | 25 ++++++++++--------------- + drivers/staging/go7007/wis-saa7115.c | 29 ++++++++++++++--------------- + drivers/staging/go7007/wis-sony-tuner.c | 3 ++- + drivers/staging/go7007/wis-tw2804.c | 29 ++++++++++++++--------------- + drivers/staging/go7007/wis-tw9903.c | 21 ++++++++++----------- + drivers/staging/go7007/wis-uda1342.c | 2 +- + 10 files changed, 59 insertions(+), 71 deletions(-) + +diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c +index 5a336ff..81ae4b0 100644 +--- a/drivers/staging/go7007/go7007-driver.c ++++ b/drivers/staging/go7007/go7007-driver.c +@@ -31,7 +31,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c +index d54d019..94e1141 100644 +--- a/drivers/staging/go7007/go7007-v4l2.c ++++ b/drivers/staging/go7007/go7007-v4l2.c +@@ -26,8 +26,7 @@ + #include + #include + #include +-#include +-#include ++#include + #include + #include + #include +@@ -835,7 +834,6 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file, + case VIDIOC_S_STD: + { + v4l2_std_id *std = arg; +- int norm; + + if (go->streaming) + return -EBUSY; +@@ -856,20 +854,17 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file, + if (*std & V4L2_STD_NTSC) { + go->standard = GO7007_STD_NTSC; + go->sensor_framerate = 30000; +- norm = VIDEO_MODE_NTSC; + } else if (*std & V4L2_STD_PAL) { + go->standard = GO7007_STD_PAL; + go->sensor_framerate = 25025; +- norm = VIDEO_MODE_PAL; + } else if (*std & V4L2_STD_SECAM) { + go->standard = GO7007_STD_PAL; + go->sensor_framerate = 25025; +- norm = VIDEO_MODE_SECAM; + } else + return -EINVAL; + if (go->i2c_adapter_online) + i2c_clients_command(&go->i2c_adapter, +- DECODER_SET_NORM, &norm); ++ VIDIOC_S_STD, std); + set_capture_size(go, NULL, 0); + return 0; + } +@@ -933,7 +928,7 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file, + return -EBUSY; + go->input = *input; + if (go->i2c_adapter_online) { +- i2c_clients_command(&go->i2c_adapter, DECODER_SET_INPUT, ++ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT, + &go->board_info->inputs[*input].video_input); + i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO, + &go->board_info->inputs[*input].audio_input); +@@ -1459,6 +1454,7 @@ static struct file_operations go7007_fops = { + + static struct video_device go7007_template = { + .name = "go7007", ++ .vfl_type = VID_TYPE_CAPTURE, + .fops = &go7007_fops, + .minor = -1, + .release = go7007_vfl_release, +diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c +index f5cac08..382740c 100644 +--- a/drivers/staging/go7007/snd-go7007.c ++++ b/drivers/staging/go7007/snd-go7007.c +@@ -44,8 +44,8 @@ module_param_array(index, int, NULL, 0444); + module_param_array(id, charp, NULL, 0444); + module_param_array(enable, bool, NULL, 0444); + MODULE_PARM_DESC(index, "Index value for the go7007 audio driver"); +-MODULE_PARM_DESC(index, "ID string for the go7007 audio driver"); +-MODULE_PARM_DESC(index, "Enable for the go7007 audio driver"); ++MODULE_PARM_DESC(id, "ID string for the go7007 audio driver"); ++MODULE_PARM_DESC(enable, "Enable for the go7007 audio driver"); + + struct go7007_snd { + struct snd_card *card; +diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c +index 815615a..f5f11e9 100644 +--- a/drivers/staging/go7007/wis-ov7640.c ++++ b/drivers/staging/go7007/wis-ov7640.c +@@ -19,8 +19,7 @@ + #include + #include + #include +-#include +-#include ++#include + + #include "wis-i2c.h" + +diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c +index 4b14ca8..c1aff1b 100644 +--- a/drivers/staging/go7007/wis-saa7113.c ++++ b/drivers/staging/go7007/wis-saa7113.c +@@ -19,8 +19,7 @@ + #include + #include + #include +-#include +-#include ++#include + #include + + #include "wis-i2c.h" +@@ -124,7 +123,7 @@ static int wis_saa7113_command(struct i2c_client *client, + struct wis_saa7113 *dec = i2c_get_clientdata(client); + + switch (cmd) { +- case DECODER_SET_INPUT: ++ case VIDIOC_S_INPUT: + { + int *input = arg; + +@@ -133,23 +132,19 @@ static int wis_saa7113_command(struct i2c_client *client, + *input < 6 ? 0x40 : 0x80); + break; + } +- case DECODER_SET_NORM: ++ case VIDIOC_S_STD: + { +- int *input = arg; ++ v4l2_std_id *input = arg; + dec->norm = *input; +- switch (dec->norm) { +- case VIDEO_MODE_PAL: +- write_reg(client, 0x0e, 0x01); +- write_reg(client, 0x10, 0x48); +- break; +- case VIDEO_MODE_NTSC: ++ if (dec->norm & V4L2_STD_NTSC) { + write_reg(client, 0x0e, 0x01); + write_reg(client, 0x10, 0x40); +- break; +- case VIDEO_MODE_SECAM: ++ } else if (dec->norm & V4L2_STD_PAL) { ++ write_reg(client, 0x0e, 0x01); ++ write_reg(client, 0x10, 0x48); ++ } else if (dec->norm * V4L2_STD_SECAM) { + write_reg(client, 0x0e, 0x50); + write_reg(client, 0x10, 0x48); +- break; + } + break; + } +@@ -295,7 +290,7 @@ static int wis_saa7113_detect(struct i2c_adapter *adapter, int addr, int kind) + kfree(client); + return -ENOMEM; + } +- dec->norm = VIDEO_MODE_NTSC; ++ dec->norm = V4L2_STD_NTSC; + dec->brightness = 128; + dec->contrast = 71; + dec->saturation = 64; +diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c +index bd40bf4..5c94c88 100644 +--- a/drivers/staging/go7007/wis-saa7115.c ++++ b/drivers/staging/go7007/wis-saa7115.c +@@ -19,8 +19,7 @@ + #include + #include + #include +-#include +-#include ++#include + #include + + #include "wis-i2c.h" +@@ -204,7 +203,7 @@ static int wis_saa7115_command(struct i2c_client *client, + struct wis_saa7115 *dec = i2c_get_clientdata(client); + + switch (cmd) { +- case DECODER_SET_INPUT: ++ case VIDIOC_S_INPUT: + { + int *input = arg; + +@@ -222,7 +221,7 @@ static int wis_saa7115_command(struct i2c_client *client, + int h_scaling_increment = (704 / h_integer_scaler) * + 1024 / res->width; + /* Fine-grained scaler only */ +- int v_scaling_increment = (dec->norm == VIDEO_MODE_NTSC ? ++ int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ? + 240 : 288) * 1024 / res->height; + u8 regs[] = { + 0x88, 0xc0, +@@ -262,20 +261,20 @@ static int wis_saa7115_command(struct i2c_client *client, + write_regs(client, regs); + break; + } +- case DECODER_SET_NORM: ++ case VIDIOC_S_STD: + { +- int *input = arg; ++ v4l2_std_id *input = arg; + u8 regs[] = { + 0x88, 0xc0, +- 0x98, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16, +- 0x9a, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20, +- 0x9b, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01, +- 0xc8, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16, +- 0xca, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20, +- 0xcb, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01, ++ 0x98, *input & V4L2_STD_NTSC ? 0x12 : 0x16, ++ 0x9a, *input & V4L2_STD_NTSC ? 0xf2 : 0x20, ++ 0x9b, *input & V4L2_STD_NTSC ? 0x00 : 0x01, ++ 0xc8, *input & V4L2_STD_NTSC ? 0x12 : 0x16, ++ 0xca, *input & V4L2_STD_NTSC ? 0xf2 : 0x20, ++ 0xcb, *input & V4L2_STD_NTSC ? 0x00 : 0x01, + 0x88, 0xf0, +- 0x30, *input == VIDEO_MODE_NTSC ? 0x66 : 0x00, +- 0x31, *input == VIDEO_MODE_NTSC ? 0x90 : 0xe0, ++ 0x30, *input & V4L2_STD_NTSC ? 0x66 : 0x00, ++ 0x31, *input & V4L2_STD_NTSC ? 0x90 : 0xe0, + 0, 0, + }; + write_regs(client, regs); +@@ -424,7 +423,7 @@ static int wis_saa7115_detect(struct i2c_adapter *adapter, int addr, int kind) + kfree(client); + return -ENOMEM; + } +- dec->norm = VIDEO_MODE_NTSC; ++ dec->norm = V4L2_STD_NTSC; + dec->brightness = 128; + dec->contrast = 64; + dec->saturation = 64; +diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c +index 82e66d6..5997fb4 100644 +--- a/drivers/staging/go7007/wis-sony-tuner.c ++++ b/drivers/staging/go7007/wis-sony-tuner.c +@@ -19,9 +19,10 @@ + #include + #include + #include +-#include ++#include + #include + #include ++#include + + #include "wis-i2c.h" + +diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c +index 69ed7bf..27fe4d0 100644 +--- a/drivers/staging/go7007/wis-tw2804.c ++++ b/drivers/staging/go7007/wis-tw2804.c +@@ -19,8 +19,7 @@ + #include + #include + #include +-#include +-#include ++#include + #include + + #include "wis-i2c.h" +@@ -159,20 +158,20 @@ static int wis_tw2804_command(struct i2c_client *client, + } + + switch (cmd) { +- case DECODER_SET_NORM: ++ case VIDIOC_S_STD: + { +- int *input = arg; ++ v4l2_std_id *input = arg; + u8 regs[] = { +- 0x01, *input == VIDEO_MODE_NTSC ? 0xc4 : 0x84, +- 0x09, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04, +- 0x0a, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, +- 0x0b, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04, +- 0x0c, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, +- 0x0d, *input == VIDEO_MODE_NTSC ? 0x40 : 0x4a, +- 0x16, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40, +- 0x17, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40, +- 0x20, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f, +- 0x21, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f, ++ 0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84, ++ 0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04, ++ 0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, ++ 0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04, ++ 0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, ++ 0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a, ++ 0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40, ++ 0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40, ++ 0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f, ++ 0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f, + 0xff, 0xff, + }; + write_regs(client, regs, dec->channel); +@@ -322,7 +321,7 @@ static int wis_tw2804_detect(struct i2c_adapter *adapter, int addr, int kind) + return -ENOMEM; + } + dec->channel = -1; +- dec->norm = VIDEO_MODE_NTSC; ++ dec->norm = V4L2_STD_NTSC; + dec->brightness = 128; + dec->contrast = 128; + dec->saturation = 128; +diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c +index 1cdf01a..d8e4196 100644 +--- a/drivers/staging/go7007/wis-tw9903.c ++++ b/drivers/staging/go7007/wis-tw9903.c +@@ -19,8 +19,7 @@ + #include + #include + #include +-#include +-#include ++#include + #include + + #include "wis-i2c.h" +@@ -106,7 +105,7 @@ static int wis_tw9903_command(struct i2c_client *client, + struct wis_tw9903 *dec = i2c_get_clientdata(client); + + switch (cmd) { +- case DECODER_SET_INPUT: ++ case VIDIOC_S_INPUT: + { + int *input = arg; + +@@ -119,7 +118,7 @@ static int wis_tw9903_command(struct i2c_client *client, + struct video_decoder_resolution *res = arg; + /*int hscale = 256 * 720 / res->width;*/ + int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8)); +- int vscale = 256 * (dec->norm == VIDEO_MODE_NTSC ? 240 : 288) ++ int vscale = 256 * (dec->norm & V4L2_STD_NTSC ? 240 : 288) + / res->height; + u8 regs[] = { + 0x0d, vscale & 0xff, +@@ -134,14 +133,14 @@ static int wis_tw9903_command(struct i2c_client *client, + break; + } + #endif +- case DECODER_SET_NORM: ++ case VIDIOC_S_STD: + { +- int *input = arg; ++ v4l2_std_id *input = arg; + u8 regs[] = { +- 0x05, *input == VIDEO_MODE_NTSC ? 0x80 : 0x00, +- 0x07, *input == VIDEO_MODE_NTSC ? 0x02 : 0x12, +- 0x08, *input == VIDEO_MODE_NTSC ? 0x14 : 0x18, +- 0x09, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20, ++ 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00, ++ 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12, ++ 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18, ++ 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, + 0, 0, + }; + write_regs(client, regs); +@@ -297,7 +296,7 @@ static int wis_tw9903_detect(struct i2c_adapter *adapter, int addr, int kind) + kfree(client); + return -ENOMEM; + } +- dec->norm = VIDEO_MODE_NTSC; ++ dec->norm = V4L2_STD_NTSC; + dec->brightness = 0; + dec->contrast = 0x60; + dec->hue = 0; +diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c +index 28c10bf..a0894e3 100644 +--- a/drivers/staging/go7007/wis-uda1342.c ++++ b/drivers/staging/go7007/wis-uda1342.c +@@ -19,7 +19,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0019-Staging-SLICOSS-lots-of-checkpatch-fixes.patch b/src/patches/suse-2.6.27.31/patches.drivers/0019-Staging-SLICOSS-lots-of-checkpatch-fixes.patch new file mode 100644 index 000000000..00a3dba93 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0019-Staging-SLICOSS-lots-of-checkpatch-fixes.patch @@ -0,0 +1,5348 @@ +From e9eff9d6a0d14fa2e85953ce4115d243ff575e78 Mon Sep 17 00:00:00 2001 +From: Lior Dotan +Date: Sat, 4 Oct 2008 07:10:28 +0300 +Subject: [PATCH 19/23] Staging: SLICOSS: lots of checkpatch fixes +Patch-mainline: 2.6.28 + +Major cleanups of checkpatch warnings from the slicoss driver. + +From: Lior Dotan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/slicoss/gbdownload.h | 10 +- + drivers/staging/slicoss/gbrcvucode.h | 7 +- + drivers/staging/slicoss/oasisdbgdownload.h | 10 +- + drivers/staging/slicoss/oasisdownload.h | 10 +- + drivers/staging/slicoss/oasisrcvucode.h | 6 +- + drivers/staging/slicoss/slic.h | 485 +++++----- + drivers/staging/slicoss/slic_os.h | 85 +-- + drivers/staging/slicoss/slicbuild.h | 1 - + drivers/staging/slicoss/slicdbg.h | 3 +- + drivers/staging/slicoss/slicdump.h | 89 +- + drivers/staging/slicoss/slichw.h | 653 +++++++------- + drivers/staging/slicoss/slicinc.h | 262 +++--- + drivers/staging/slicoss/slicoss.c | 1351 +++++++++++++--------------- + 13 files changed, 1353 insertions(+), 1619 deletions(-) + +diff --git a/drivers/staging/slicoss/gbdownload.h b/drivers/staging/slicoss/gbdownload.h +index 0350fb9..794432b 100644 +--- a/drivers/staging/slicoss/gbdownload.h ++++ b/drivers/staging/slicoss/gbdownload.h +@@ -1,14 +1,14 @@ +-#define MOJAVE_UCODE_VERS_STRING "$Revision: 1.2 $" +-#define MOJAVE_UCODE_VERS_DATE "$Date: 2006/03/27 15:12:22 $" ++#define MOJAVE_UCODE_VERS_STRING "1.2" ++#define MOJAVE_UCODE_VERS_DATE "2006/03/27 15:12:22" + #define MOJAVE_UCODE_HOSTIF_ID 3 + +-static LONG MNumSections = 0x2; +-static ULONG MSectionSize[] = ++static s32 MNumSections = 0x2; ++static u32 MSectionSize[] = + { + 0x00008000, 0x00010000, + }; + +-static ULONG MSectionStart[] = ++static u32 MSectionStart[] = + { + 0x00000000, 0x00008000, + }; +diff --git a/drivers/staging/slicoss/gbrcvucode.h b/drivers/staging/slicoss/gbrcvucode.h +index dc00834..4fa5a4c 100644 +--- a/drivers/staging/slicoss/gbrcvucode.h ++++ b/drivers/staging/slicoss/gbrcvucode.h +@@ -1,7 +1,6 @@ + /* + * Copyright (c) 1997-2002 Alacritech, Inc. All rights reserved + * +- * $Id: gbrcvucode.h,v 1.2 2006/03/27 15:12:15 mook Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -32,10 +31,10 @@ + * official policies, either expressed or implied, of Alacritech, Inc. + * + **************************************************************************/ +-#define GB_RCVUCODE_VERS_STRING "$Revision: 1.2 $" +-#define GB_RCVUCODE_VERS_DATE "$Date: 2006/03/27 15:12:15 $" ++#define GB_RCVUCODE_VERS_STRING "1.2" ++#define GB_RCVUCODE_VERS_DATE "2006/03/27 15:12:15" + +-static ULONG GBRcvUCodeLen = 512; ++static u32 GBRcvUCodeLen = 512; + + static u8 GBRcvUCode[2560] = + { +diff --git a/drivers/staging/slicoss/oasisdbgdownload.h b/drivers/staging/slicoss/oasisdbgdownload.h +index cae5d55..519e007 100644 +--- a/drivers/staging/slicoss/oasisdbgdownload.h ++++ b/drivers/staging/slicoss/oasisdbgdownload.h +@@ -1,14 +1,14 @@ +-#define OASIS_UCODE_VERS_STRING "$Revision: 1.2 $" +-#define OASIS_UCODE_VERS_DATE "$Date: 2006/03/27 15:11:22 $" ++#define OASIS_UCODE_VERS_STRING "1.2" ++#define OASIS_UCODE_VERS_DATE "2006/03/27 15:11:22" + #define OASIS_UCODE_HOSTIF_ID 3 + +-static LONG ONumSections = 0x2; +-static ULONG OSectionSize[] = ++static s32 ONumSections = 0x2; ++static u32 OSectionSize[] = + { + 0x00004000, 0x00010000, + }; + +-static ULONG OSectionStart[] = ++static u32 OSectionStart[] = + { + 0x00000000, 0x00008000, + }; +diff --git a/drivers/staging/slicoss/oasisdownload.h b/drivers/staging/slicoss/oasisdownload.h +index 89a440c..6438c23 100644 +--- a/drivers/staging/slicoss/oasisdownload.h ++++ b/drivers/staging/slicoss/oasisdownload.h +@@ -1,13 +1,13 @@ +-#define OASIS_UCODE_VERS_STRING "$Revision: 1.2 $" +-#define OASIS_UCODE_VERS_DATE "$Date: 2006/03/27 15:10:37 $" ++#define OASIS_UCODE_VERS_STRING "1.2" ++#define OASIS_UCODE_VERS_DATE "2006/03/27 15:10:37" + #define OASIS_UCODE_HOSTIF_ID 3 + +-static LONG ONumSections = 0x2; +-static ULONG OSectionSize[] = { ++static s32 ONumSections = 0x2; ++static u32 OSectionSize[] = { + 0x00004000, 0x00010000, + }; + +-static ULONG OSectionStart[] = { ++static u32 OSectionStart[] = { + 0x00000000, 0x00008000, + }; + +diff --git a/drivers/staging/slicoss/oasisrcvucode.h b/drivers/staging/slicoss/oasisrcvucode.h +index ef91632..5b3531f 100644 +--- a/drivers/staging/slicoss/oasisrcvucode.h ++++ b/drivers/staging/slicoss/oasisrcvucode.h +@@ -1,7 +1,7 @@ +-#define OASIS_RCVUCODE_VERS_STRING "$Revision: 1.2 $" +-#define OASIS_RCVUCODE_VERS_DATE "$Date: 2006/03/27 15:10:28 $" ++#define OASIS_RCVUCODE_VERS_STRING "1.2" ++#define OASIS_RCVUCODE_VERS_DATE "2006/03/27 15:10:28" + +-static ULONG OasisRcvUCodeLen = 512; ++static u32 OasisRcvUCodeLen = 512; + + static u8 OasisRcvUCode[2560] = + { +diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h +index 9707e5a..0d5dc24 100644 +--- a/drivers/staging/slicoss/slic.h ++++ b/drivers/staging/slicoss/slic.h +@@ -2,7 +2,6 @@ + * + * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. + * +- * $Id: slic.h,v 1.3 2006/07/14 16:43:02 mook Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -51,14 +50,14 @@ struct slic_spinlock { + #define SLIC_RSPQ_PAGES_GB 10 + #define SLIC_RSPQ_BUFSINPAGE (PAGE_SIZE / SLIC_RSPBUF_SIZE) + +-typedef struct _slic_rspqueue_t { +- ulong32 offset; +- ulong32 pageindex; +- ulong32 num_pages; +- p_slic_rspbuf_t rspbuf; +- pulong32 vaddr[SLIC_RSPQ_PAGES_GB]; ++struct slic_rspqueue { ++ u32 offset; ++ u32 pageindex; ++ u32 num_pages; ++ struct slic_rspbuf *rspbuf; ++ u32 *vaddr[SLIC_RSPQ_PAGES_GB]; + dma_addr_t paddr[SLIC_RSPQ_PAGES_GB]; +-} slic_rspqueue_t, *p_slic_rspqueue_t; ++}; + + #define SLIC_RCVQ_EXPANSION 1 + #define SLIC_RCVQ_ENTRIES (256 * SLIC_RCVQ_EXPANSION) +@@ -68,45 +67,45 @@ typedef struct _slic_rspqueue_t { + #define SLIC_RCVQ_FILLENTRIES (16 * SLIC_RCVQ_EXPANSION) + #define SLIC_RCVQ_FILLTHRESH (SLIC_RCVQ_ENTRIES - SLIC_RCVQ_FILLENTRIES) + +-typedef struct _slic_rcvqueue_t { ++struct slic_rcvqueue { + struct sk_buff *head; + struct sk_buff *tail; +- ulong32 count; +- ulong32 size; +- ulong32 errors; +-} slic_rcvqueue_t, *p_slic_rcvqueue_t; +- +-typedef struct _slic_rcvbuf_info_t { +- ulong32 id; +- ulong32 starttime; +- ulong32 stoptime; +- ulong32 slicworld; +- ulong32 lasttime; +- ulong32 lastid; +-} slic_rcvbuf_info_t, *pslic_rcvbuf_info_t; ++ u32 count; ++ u32 size; ++ u32 errors; ++}; ++ ++struct slic_rcvbuf_info { ++ u32 id; ++ u32 starttime; ++ u32 stoptime; ++ u32 slicworld; ++ u32 lasttime; ++ u32 lastid; ++}; + /* + SLIC Handle structure. Used to restrict handle values to + 32 bits by using an index rather than an address. + Simplifies ucode in 64-bit systems + */ +-typedef struct _slic_handle_word_t { ++struct slic_handle_word { + union { + struct { + ushort index; + ushort bottombits; /* to denote num bufs to card */ + } parts; +- ulong32 whole; ++ u32 whole; + } handle; +-} slic_handle_word_t, *pslic_handle_word_t; ++}; + +-typedef struct _slic_handle_t { +- slic_handle_word_t token; /* token passed between host and card*/ ++struct slic_handle { ++ struct slic_handle_word token; /* token passed between host and card*/ + ushort type; +- pvoid address; /* actual address of the object*/ ++ void *address; /* actual address of the object*/ + ushort offset; +- struct _slic_handle_t *other_handle; +- struct _slic_handle_t *next; +-} slic_handle_t, *pslic_handle_t; ++ struct slic_handle *other_handle; ++ struct slic_handle *next; ++}; + + #define SLIC_HANDLE_FREE 0x0000 + #define SLIC_HANDLE_DATA 0x0001 +@@ -120,19 +119,19 @@ typedef struct _slic_handle_t { + + #define SLIC_HOSTCMD_SIZE 512 + +-typedef struct _slic_hostcmd_t { +- slic_host64_cmd_t cmd64; +- ulong32 type; ++struct slic_hostcmd { ++ struct slic_host64_cmd cmd64; ++ u32 type; + struct sk_buff *skb; +- ulong32 paddrl; +- ulong32 paddrh; +- ulong32 busy; +- ulong32 cmdsize; ++ u32 paddrl; ++ u32 paddrh; ++ u32 busy; ++ u32 cmdsize; + ushort numbufs; +- pslic_handle_t pslic_handle;/* handle associated with command */ +- struct _slic_hostcmd_t *next; +- struct _slic_hostcmd_t *next_all; +-} slic_hostcmd_t, *p_slic_hostcmd_t; ++ struct slic_handle *pslic_handle;/* handle associated with command */ ++ struct slic_hostcmd *next; ++ struct slic_hostcmd *next_all; ++}; + + #define SLIC_CMDQ_CMDSINPAGE (PAGE_SIZE / SLIC_HOSTCMD_SIZE) + #define SLIC_CMD_DUMB 3 +@@ -142,18 +141,18 @@ typedef struct _slic_hostcmd_t { + #define SLIC_CMDQ_MAXPAGES (SLIC_CMDQ_MAXCMDS / SLIC_CMDQ_CMDSINPAGE) + #define SLIC_CMDQ_INITPAGES (SLIC_CMDQ_INITCMDS / SLIC_CMDQ_CMDSINPAGE) + +-typedef struct _slic_cmdqmem_t { +- int pagecnt; +- pulong32 pages[SLIC_CMDQ_MAXPAGES]; +- dma_addr_t dma_pages[SLIC_CMDQ_MAXPAGES]; +-} slic_cmdqmem_t, *p_slic_cmdqmem_t; ++struct slic_cmdqmem { ++ int pagecnt; ++ u32 *pages[SLIC_CMDQ_MAXPAGES]; ++ dma_addr_t dma_pages[SLIC_CMDQ_MAXPAGES]; ++}; + +-typedef struct _slic_cmdqueue_t { +- p_slic_hostcmd_t head; +- p_slic_hostcmd_t tail; +- int count; +- struct slic_spinlock lock; +-} slic_cmdqueue_t, *p_slic_cmdqueue_t; ++struct slic_cmdqueue { ++ struct slic_hostcmd *head; ++ struct slic_hostcmd *tail; ++ int count; ++ struct slic_spinlock lock; ++}; + + #ifdef STATUS_SUCCESS + #undef STATUS_SUCCESS +@@ -181,10 +180,10 @@ just set this at 15K, shouldnt make that much of a diff. + #endif + + +-typedef struct _mcast_address_t { +- uchar address[6]; +- struct _mcast_address_t *next; +-} mcast_address_t, *p_mcast_address_t; ++struct mcast_address { ++ unsigned char address[6]; ++ struct mcast_address *next; ++}; + + #define CARD_DOWN 0x00000000 + #define CARD_UP 0x00000001 +@@ -236,38 +235,37 @@ typedef struct _mcast_address_t { + #define SLIC_ADAPTER_STATE(x) ((x == ADAPT_UP) ? "UP" : "Down") + #define SLIC_CARD_STATE(x) ((x == CARD_UP) ? "UP" : "Down") + +-typedef struct _slic_iface_stats { ++struct slic_iface_stats { + /* + * Stats + */ +- ulong64 xmt_bytes; +- ulong64 xmt_ucast; +- ulong64 xmt_mcast; +- ulong64 xmt_bcast; +- ulong64 xmt_errors; +- ulong64 xmt_discards; +- ulong64 xmit_collisions; +- ulong64 xmit_excess_xmit_collisions; +- ulong64 rcv_bytes; +- ulong64 rcv_ucast; +- ulong64 rcv_mcast; +- ulong64 rcv_bcast; +- ulong64 rcv_errors; +- ulong64 rcv_discards; +-} slic_iface_stats_t, *p_slic_iface_stats_t; +- +-typedef struct _slic_tcp_stats { +- ulong64 xmit_tcp_segs; +- ulong64 xmit_tcp_bytes; +- ulong64 rcv_tcp_segs; +- ulong64 rcv_tcp_bytes; +-} slic_tcp_stats_t, *p_slic_tcp_stats_t; +- +-typedef struct _slicnet_stats { +- slic_tcp_stats_t tcp; +- slic_iface_stats_t iface; +- +-} slicnet_stats_t, *p_slicnet_stats_t; ++ u64 xmt_bytes; ++ u64 xmt_ucast; ++ u64 xmt_mcast; ++ u64 xmt_bcast; ++ u64 xmt_errors; ++ u64 xmt_discards; ++ u64 xmit_collisions; ++ u64 xmit_excess_xmit_collisions; ++ u64 rcv_bytes; ++ u64 rcv_ucast; ++ u64 rcv_mcast; ++ u64 rcv_bcast; ++ u64 rcv_errors; ++ u64 rcv_discards; ++}; ++ ++struct sliccp_stats { ++ u64 xmit_tcp_segs; ++ u64 xmit_tcp_bytes; ++ u64 rcv_tcp_segs; ++ u64 rcv_tcp_bytes; ++}; ++ ++struct slicnet_stats { ++ struct sliccp_stats tcp; ++ struct slic_iface_stats iface; ++}; + + #define SLIC_LOADTIMER_PERIOD 1 + #define SLIC_INTAGG_DEFAULT 200 +@@ -294,13 +292,13 @@ typedef struct _slicnet_stats { + #define SLIC_INTAGG_4GB 100 + #define SLIC_INTAGG_5GB 100 + +-typedef struct _ether_header { +- uchar ether_dhost[6]; +- uchar ether_shost[6]; ++struct ether_header { ++ unsigned char ether_dhost[6]; ++ unsigned char ether_shost[6]; + ushort ether_type; +-} ether_header, *p_ether_header; ++}; + +-typedef struct _sliccard_t { ++struct sliccard { + uint busnumber; + uint slotnumber; + uint state; +@@ -310,114 +308,111 @@ typedef struct _sliccard_t { + uint adapters_allocated; + uint adapters_sleeping; + uint gennumber; +- ulong32 events; +- ulong32 loadlevel_current; +- ulong32 load; ++ u32 events; ++ u32 loadlevel_current; ++ u32 load; + uint reset_in_progress; +- ulong32 pingstatus; +- ulong32 bad_pingstatus; ++ u32 pingstatus; ++ u32 bad_pingstatus; + struct timer_list loadtimer; +- ulong32 loadtimerset; ++ u32 loadtimerset; + uint config_set; +- slic_config_t config; ++ struct slic_config config; + struct dentry *debugfs_dir; + struct dentry *debugfs_cardinfo; +- struct _adapter_t *master; +- struct _adapter_t *adapter[SLIC_MAX_PORTS]; +- struct _sliccard_t *next; +- ulong32 error_interrupts; +- ulong32 error_rmiss_interrupts; +- ulong32 rcv_interrupts; +- ulong32 xmit_interrupts; +- ulong32 num_isrs; +- ulong32 false_interrupts; +- ulong32 max_isr_rcvs; +- ulong32 max_isr_xmits; +- ulong32 rcv_interrupt_yields; +- ulong32 tx_packets; ++ struct adapter *master; ++ struct adapter *adapter[SLIC_MAX_PORTS]; ++ struct sliccard *next; ++ u32 error_interrupts; ++ u32 error_rmiss_interrupts; ++ u32 rcv_interrupts; ++ u32 xmit_interrupts; ++ u32 num_isrs; ++ u32 false_interrupts; ++ u32 max_isr_rcvs; ++ u32 max_isr_xmits; ++ u32 rcv_interrupt_yields; ++ u32 tx_packets; + #if SLIC_DUMP_ENABLED +- ulong32 dumpstatus; /* Result of dump UPR */ +- pvoid cmdbuffer; ++ u32 dumpstatus; /* Result of dump UPR */ ++ void *cmdbuffer; + + ulong cmdbuffer_phys; +- ulong32 cmdbuffer_physl; +- ulong32 cmdbuffer_physh; ++ u32 cmdbuffer_physl; ++ u32 cmdbuffer_physh; + +- ulong32 dump_count; ++ u32 dump_count; + struct task_struct *dump_task_id; +- ulong32 dump_wait_count; ++ u32 dump_wait_count; + uint dumpthread_running; /* has a dump thread been init'd */ + uint dump_requested; /* 0 no, 1 = reqstd 2=curr 3=done */ +- ulong32 dumptime_start; +- ulong32 dumptime_complete; +- ulong32 dumptime_delta; +- pvoid dumpbuffer; ++ u32 dumptime_start; ++ u32 dumptime_complete; ++ u32 dumptime_delta; ++ void *dumpbuffer; + ulong dumpbuffer_phys; +- ulong32 dumpbuffer_physl; +- ulong32 dumpbuffer_physh; ++ u32 dumpbuffer_physl; ++ u32 dumpbuffer_physh; + wait_queue_head_t dump_wq; + struct file *dumphandle; + mm_segment_t dumpfile_fs; + #endif +- ulong32 debug_ix; ++ u32 debug_ix; + ushort reg_type[32]; + ushort reg_offset[32]; +- ulong32 reg_value[32]; +- ulong32 reg_valueh[32]; +-} sliccard_t, *p_sliccard_t; ++ u32 reg_value[32]; ++ u32 reg_valueh[32]; ++}; + + #define NUM_CFG_SPACES 2 + #define NUM_CFG_REGS 64 +-#define NUM_CFG_REG_ULONGS (NUM_CFG_REGS / sizeof(ulong32)) ++#define NUM_CFG_REG_ULONGS (NUM_CFG_REGS / sizeof(u32)) + +-typedef struct _physcard_t { +- struct _adapter_t *adapter[SLIC_MAX_PORTS]; +- struct _physcard_t *next; ++struct physcard { ++ struct adapter *adapter[SLIC_MAX_PORTS]; ++ struct physcard *next; + uint adapters_allocd; + + /* the following is not currently needed +- ulong32 bridge_busnum; +- ulong32 bridge_cfg[NUM_CFG_SPACES][NUM_CFG_REG_ULONGS]; ++ u32 bridge_busnum; ++ u32 bridge_cfg[NUM_CFG_SPACES][NUM_CFG_REG_ULONGS]; + */ +-} physcard_t, *p_physcard_t; ++}; + +-typedef struct _base_driver { ++struct base_driver { + struct slic_spinlock driver_lock; +- ulong32 num_slic_cards; +- ulong32 num_slic_ports; +- ulong32 num_slic_ports_active; +- ulong32 dynamic_intagg; +- p_sliccard_t slic_card; +- p_physcard_t phys_card; ++ u32 num_slic_cards; ++ u32 num_slic_ports; ++ u32 num_slic_ports_active; ++ u32 dynamic_intagg; ++ struct sliccard *slic_card; ++ struct physcard *phys_card; + uint cardnuminuse[SLIC_MAX_CARDS]; +-} base_driver_t, *p_base_driver_t; +- +-extern base_driver_t slic_global; +- +-typedef struct _slic_shmem_t { +- volatile ulong32 isr; +- volatile ulong32 linkstatus; +- volatile slic_stats_t inicstats; +-} slic_shmem_t, *p_slic_shmem_t; +- +-typedef struct _slic_reg_params_t { +- ulong32 linkspeed; +- ulong32 linkduplex; +- ulong32 fail_on_bad_eeprom; +-} slic_reg_params_t, *p_reg_params_t; +- +-typedef struct _slic_upr_t { +- uint adapter; +- ulong32 upr_request; +- ulong32 upr_data; +- ulong32 upr_data_h; +- ulong32 upr_buffer; +- ulong32 upr_buffer_h; +- struct _slic_upr_t *next; +- +-} slic_upr_t, *p_slic_upr_t; +- +-typedef struct _slic_ifevents_ti { ++}; ++ ++struct slic_shmem { ++ volatile u32 isr; ++ volatile u32 linkstatus; ++ volatile struct slic_stats inicstats; ++}; ++ ++struct slic_reg_params { ++ u32 linkspeed; ++ u32 linkduplex; ++ u32 fail_on_bad_eeprom; ++}; ++ ++struct slic_upr { ++ uint adapter; ++ u32 upr_request; ++ u32 upr_data; ++ u32 upr_data_h; ++ u32 upr_buffer; ++ u32 upr_buffer_h; ++ struct slic_upr *next; ++}; ++ ++struct slic_ifevents { + uint oflow802; + uint uflow802; + uint Tprtoflow; +@@ -434,19 +429,19 @@ typedef struct _slic_ifevents_ti { + uint IpCsum; + uint TpCsum; + uint TpHlen; +-} slic_ifevents_t; ++}; + +-typedef struct _adapter_t { +- pvoid ifp; +- p_sliccard_t card; ++struct adapter { ++ void *ifp; ++ struct sliccard *card; + uint port; +- p_physcard_t physcard; ++ struct physcard *physcard; + uint physport; + uint cardindex; + uint card_size; + uint chipid; +- struct net_device *netdev; +- struct net_device *next_netdevice; ++ struct net_device *netdev; ++ struct net_device *next_netdevice; + struct slic_spinlock adapter_lock; + struct slic_spinlock reset_lock; + struct pci_dev *pcidev; +@@ -456,90 +451,90 @@ typedef struct _adapter_t { + ushort vendid; + ushort devid; + ushort subsysid; +- ulong32 irq; ++ u32 irq; + void __iomem *memorybase; +- ulong32 memorylength; +- ulong32 drambase; +- ulong32 dramlength; ++ u32 memorylength; ++ u32 drambase; ++ u32 dramlength; + uint queues_initialized; + uint allocated; + uint activated; +- ulong32 intrregistered; ++ u32 intrregistered; + uint isp_initialized; + uint gennumber; +- ulong32 curaddrupper; +- p_slic_shmem_t pshmem; ++ u32 curaddrupper; ++ struct slic_shmem *pshmem; + dma_addr_t phys_shmem; +- ulong32 isrcopy; +- p_slic_regs_t slic_regs; +- uchar state; +- uchar linkstate; +- uchar linkspeed; +- uchar linkduplex; ++ u32 isrcopy; ++ __iomem struct slic_regs *slic_regs; ++ unsigned char state; ++ unsigned char linkstate; ++ unsigned char linkspeed; ++ unsigned char linkduplex; + uint flags; +- uchar macaddr[6]; +- uchar currmacaddr[6]; +- ulong32 macopts; ++ unsigned char macaddr[6]; ++ unsigned char currmacaddr[6]; ++ u32 macopts; + ushort devflags_prev; +- ulong64 mcastmask; +- p_mcast_address_t mcastaddrs; +- p_slic_upr_t upr_list; ++ u64 mcastmask; ++ struct mcast_address *mcastaddrs; ++ struct slic_upr *upr_list; + uint upr_busy; + struct timer_list pingtimer; +- ulong32 pingtimerset; ++ u32 pingtimerset; + struct timer_list statstimer; +- ulong32 statstimerset; ++ u32 statstimerset; + struct timer_list loadtimer; +- ulong32 loadtimerset; ++ u32 loadtimerset; + struct dentry *debugfs_entry; + struct slic_spinlock upr_lock; + struct slic_spinlock bit64reglock; +- slic_rspqueue_t rspqueue; +- slic_rcvqueue_t rcvqueue; +- slic_cmdqueue_t cmdq_free; +- slic_cmdqueue_t cmdq_done; +- slic_cmdqueue_t cmdq_all; +- slic_cmdqmem_t cmdqmem; ++ struct slic_rspqueue rspqueue; ++ struct slic_rcvqueue rcvqueue; ++ struct slic_cmdqueue cmdq_free; ++ struct slic_cmdqueue cmdq_done; ++ struct slic_cmdqueue cmdq_all; ++ struct slic_cmdqmem cmdqmem; + /* + * SLIC Handles + */ +- slic_handle_t slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/ +- pslic_handle_t pfree_slic_handles; /* Free object handles*/ ++ struct slic_handle slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/ ++ struct slic_handle *pfree_slic_handles; /* Free object handles*/ + struct slic_spinlock handle_lock; /* Object handle list lock*/ + ushort slic_handle_ix; + +- ulong32 xmitq_full; +- ulong32 all_reg_writes; +- ulong32 icr_reg_writes; +- ulong32 isr_reg_writes; +- ulong32 error_interrupts; +- ulong32 error_rmiss_interrupts; +- ulong32 rx_errors; +- ulong32 rcv_drops; +- ulong32 rcv_interrupts; +- ulong32 xmit_interrupts; +- ulong32 linkevent_interrupts; +- ulong32 upr_interrupts; +- ulong32 num_isrs; +- ulong32 false_interrupts; +- ulong32 tx_packets; +- ulong32 xmit_completes; +- ulong32 tx_drops; +- ulong32 rcv_broadcasts; +- ulong32 rcv_multicasts; +- ulong32 rcv_unicasts; +- ulong32 max_isr_rcvs; +- ulong32 max_isr_xmits; +- ulong32 rcv_interrupt_yields; +- ulong32 intagg_period; +- p_inicpm_state_t inicpm_info; +- pvoid pinicpm_info; +- slic_reg_params_t reg_params; +- slic_ifevents_t if_events; +- slic_stats_t inicstats_prev; +- slicnet_stats_t slic_stats; ++ u32 xmitq_full; ++ u32 all_reg_writes; ++ u32 icr_reg_writes; ++ u32 isr_reg_writes; ++ u32 error_interrupts; ++ u32 error_rmiss_interrupts; ++ u32 rx_errors; ++ u32 rcv_drops; ++ u32 rcv_interrupts; ++ u32 xmit_interrupts; ++ u32 linkevent_interrupts; ++ u32 upr_interrupts; ++ u32 num_isrs; ++ u32 false_interrupts; ++ u32 tx_packets; ++ u32 xmit_completes; ++ u32 tx_drops; ++ u32 rcv_broadcasts; ++ u32 rcv_multicasts; ++ u32 rcv_unicasts; ++ u32 max_isr_rcvs; ++ u32 max_isr_xmits; ++ u32 rcv_interrupt_yields; ++ u32 intagg_period; ++ struct inicpm_state *inicpm_info; ++ void *pinicpm_info; ++ struct slic_reg_params reg_params; ++ struct slic_ifevents if_events; ++ struct slic_stats inicstats_prev; ++ struct slicnet_stats slic_stats; + struct net_device_stats stats; +-} adapter_t, *p_adapter_t; ++}; + + #if SLIC_DUMP_ENABLED + #define SLIC_DUMP_REQUESTED 1 +@@ -552,10 +547,10 @@ typedef struct _adapter_t { + * structure is written out to the card's SRAM when the microcode panic's. + * + ****************************************************************************/ +-typedef struct _slic_crash_info { ++struct slic_crash_info { + ushort cpu_id; + ushort crash_pc; +-} slic_crash_info, *p_slic_crash_info; ++}; + + #define CRASH_INFO_OFFSET 0x155C + +@@ -577,20 +572,20 @@ typedef struct _slic_crash_info { + #define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \ + { \ + _Result = TRUE; \ +- if (*(pulong32)(_AddrA) != *(pulong32)(_AddrB)) \ ++ if (*(u32 *)(_AddrA) != *(u32 *)(_AddrB)) \ + _Result = FALSE; \ +- if (*(pushort)(&((_AddrA)[4])) != *(pushort)(&((_AddrB)[4]))) \ ++ if (*(u16 *)(&((_AddrA)[4])) != *(u16 *)(&((_AddrB)[4]))) \ + _Result = FALSE; \ + } + + #if defined(CONFIG_X86_64) || defined(CONFIG_IA64) +-#define SLIC_GET_ADDR_LOW(_addr) (ulong32)((ulong64)(_addr) & \ ++#define SLIC_GET_ADDR_LOW(_addr) (u32)((u64)(_addr) & \ + 0x00000000FFFFFFFF) +-#define SLIC_GET_ADDR_HIGH(_addr) (ulong32)(((ulong64)(_addr) >> 32) & \ ++#define SLIC_GET_ADDR_HIGH(_addr) (u32)(((u64)(_addr) >> 32) & \ + 0x00000000FFFFFFFF) + #else +-#define SLIC_GET_ADDR_LOW(_addr) (ulong32)_addr +-#define SLIC_GET_ADDR_HIGH(_addr) (ulong32)0 ++#define SLIC_GET_ADDR_LOW(_addr) (u32)_addr ++#define SLIC_GET_ADDR_HIGH(_addr) (u32)0 + #endif + + #define FLUSH TRUE +diff --git a/drivers/staging/slicoss/slic_os.h b/drivers/staging/slicoss/slic_os.h +index 2064673..b0d2883 100644 +--- a/drivers/staging/slicoss/slic_os.h ++++ b/drivers/staging/slicoss/slic_os.h +@@ -2,7 +2,6 @@ + * + * Copyright (c)2000-2002 Alacritech, Inc. All rights reserved. + * +- * $Id: slic_os.h,v 1.2 2006/03/27 15:10:15 mook Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -43,87 +42,9 @@ + #ifndef _SLIC_OS_SPECIFIC_H_ + #define _SLIC_OS_SPECIFIC_H_ + +-typedef unsigned char uchar; +-typedef u64 ulong64; +-typedef char *pchar; +-typedef unsigned char *puchar; +-typedef u16 *pushort; +-typedef u32 ulong32; +-typedef u32 *pulong32; +-typedef int *plong32; +-typedef unsigned int *puint; +-typedef void *pvoid; +-typedef unsigned long *pulong; +-typedef unsigned int boolean; +-typedef unsigned int wchar; +-typedef unsigned int *pwchar; +-typedef unsigned char UCHAR; +-typedef u32 ULONG; +-typedef s32 LONG; + #define FALSE (0) + #define TRUE (1) + +-#define SLIC_INIT_SPINLOCK(x) \ +- { \ +- spin_lock_init(&((x).lock)); \ +- } +-#define SLIC_ACQUIRE_SPINLOCK(x) \ +- { \ +- spin_lock(&((x).lock)); \ +- } +- +-#define SLIC_RELEASE_SPINLOCK(x) \ +- { \ +- spin_unlock(&((x).lock)); \ +- } +- +-#define SLIC_ACQUIRE_IRQ_SPINLOCK(x) \ +- { \ +- spin_lock_irqsave(&((x).lock), (x).flags); \ +- } +- +-#define SLIC_RELEASE_IRQ_SPINLOCK(x) \ +- { \ +- spin_unlock_irqrestore(&((x).lock), (x).flags); \ +- } +- +-#define ATK_DEBUG 1 +- +-#if ATK_DEBUG +-#define SLIC_TIMESTAMP(value) { \ +- struct timeval timev; \ +- do_gettimeofday(&timev); \ +- value = timev.tv_sec*1000000 + timev.tv_usec; \ +-} +-#else +-#define SLIC_TIMESTAMP(value) +-#endif +- +-#define SLIC_ALLOCATE_MEM(len, flag) kmalloc(len, flag) +-#define SLIC_DEALLOCATE_MEM(mem) kfree(mem) +-#define SLIC_DEALLOCATE_IRQ_MEM(mem) free(mem) +-#define SLIC_ALLOCATE_PAGE(x) (pulong32)get_free_page(GFP_KERNEL) +-#define SLIC_DEALLOCATE_PAGE(addr) free_page((ulong32)addr) +-#define SLIC_ALLOCATE_PCIMEM(a, sz, physp) \ +- pci_alloc_consistent((a)->pcidev, (sz), &(physp)) +-#define SLIC_DEALLOCATE_PCIMEM(a, sz, vp, pp) \ +- pci_free_consistent((a)->pcidev, (sz), (vp), (pp)) +-#define SLIC_GET_PHYSICAL_ADDRESS(addr) virt_to_bus((addr)) +-#define SLIC_GET_PHYSICAL_ADDRESS_HIGH(addr) 0 +- +-#define SLIC_GET_DMA_ADDRESS_WRITE(a, ptr, sz) \ +- pci_map_single((a)->pcidev, (ptr), (sz), PCI_DMA_TODEVICE) +-#define SLIC_GET_DMA_ADDRESS_READ(a, ptr, sz) \ +- pci_map_single((a)->pcidev, (ptr), (sz), PCI_DMA_FROMDEVICE) +-#define SLIC_UNGET_DMA_ADDRESS_WRITE(a, pa, sz) \ +- pci_unmap_single((a)->pcidev, (pa), (sz), PCI_DMA_TODEVICE) +-#define SLIC_UNGET_DMA_ADDRESS_READ(a, pa, sz) \ +- pci_unmap_single((a)->pcidev, (pa), (sz), PCI_DMA_FROMDEVICE) +- +-#define SLIC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +-#define SLIC_EQUAL_MEMORY(src1, src2, len) (!memcmp(src1, src2, len)) +-#define SLIC_MOVE_MEMORY(dst, src, len) memcpy((dst), (src), (len)) +- + #define SLIC_SECS_TO_JIFFS(x) ((x) * HZ) + #define SLIC_MS_TO_JIFFIES(x) (SLIC_SECS_TO_JIFFS((x)) / 1000) + +@@ -132,7 +53,7 @@ typedef s32 LONG; + { \ + adapter->card->reg_type[adapter->card->debug_ix] = 0; \ + adapter->card->reg_offset[adapter->card->debug_ix] = \ +- ((puchar)(®)) - ((puchar)adapter->slic_regs); \ ++ ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \ + adapter->card->reg_value[adapter->card->debug_ix++] = value; \ + if (adapter->card->debug_ix == 32) \ + adapter->card->debug_ix = 0; \ +@@ -142,7 +63,7 @@ typedef s32 LONG; + { \ + adapter->card->reg_type[adapter->card->debug_ix] = 1; \ + adapter->card->reg_offset[adapter->card->debug_ix] = \ +- ((puchar)(®)) - ((puchar)adapter->slic_regs); \ ++ ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \ + adapter->card->reg_value[adapter->card->debug_ix] = value; \ + adapter->card->reg_valueh[adapter->card->debug_ix++] = valh; \ + if (adapter->card->debug_ix == 32) \ +@@ -156,8 +77,6 @@ typedef s32 LONG; + #define WRITE_REG64(a, reg, value, regh, valh, flush) \ + slic_reg64_write((a), (®), (value), (®h), (valh), (flush)) + #endif +-#define READ_REG(reg, flush) slic_reg32_read((®), (flush)) +-#define READ_REGP16(reg, flush) slic_reg16_read((®), (flush)) + + #endif /* _SLIC_OS_SPECIFIC_H_ */ + +diff --git a/drivers/staging/slicoss/slicbuild.h b/drivers/staging/slicoss/slicbuild.h +index ddf1665..ae05e04 100644 +--- a/drivers/staging/slicoss/slicbuild.h ++++ b/drivers/staging/slicoss/slicbuild.h +@@ -2,7 +2,6 @@ + * + * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. + * +- * $Id: slicbuild.h,v 1.2 2006/03/27 15:10:10 mook Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +diff --git a/drivers/staging/slicoss/slicdbg.h b/drivers/staging/slicoss/slicdbg.h +index c1be56f..c54e44f 100644 +--- a/drivers/staging/slicoss/slicdbg.h ++++ b/drivers/staging/slicoss/slicdbg.h +@@ -2,7 +2,6 @@ + * + * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. + * +- * $Id: slicdbg.h,v 1.2 2006/03/27 15:10:04 mook Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -66,7 +65,7 @@ + #ifdef CONFIG_X86_64 + #define VALID_ADDRESS(p) (1) + #else +-#define VALID_ADDRESS(p) (((ulong32)(p) & 0x80000000) || ((ulong32)(p) == 0)) ++#define VALID_ADDRESS(p) (((u32)(p) & 0x80000000) || ((u32)(p) == 0)) + #endif + #ifndef ASSERT + #define ASSERT(a) \ +diff --git a/drivers/staging/slicoss/slicdump.h b/drivers/staging/slicoss/slicdump.h +index 3c46094..ca0a221 100644 +--- a/drivers/staging/slicoss/slicdump.h ++++ b/drivers/staging/slicoss/slicdump.h +@@ -1,5 +1,4 @@ + /* +- * $Id: slicdump.h,v 1.2 2006/03/27 15:09:57 mook Exp $ + * + * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. + * +@@ -148,32 +147,32 @@ + /* + * Break and Reset Break command structure + */ +-typedef struct _BREAK { +- uchar command; /* Command word defined above */ +- uchar resvd; ++struct BREAK { ++ unsigned char command; /* Command word defined above */ ++ unsigned char resvd; + ushort count; /* Number of executions before break */ +- ulong32 addr; /* Address of break point */ +-} BREAK, *PBREAK; ++ u32 addr; /* Address of break point */ ++}; + + /* + * Dump and Load command structure + */ +-typedef struct _dump_cmd { +- uchar cmd; /* Command word defined above */ +- uchar desc; /* Descriptor values - defined below */ ++struct dump_cmd { ++ unsigned char cmd; /* Command word defined above */ ++ unsigned char desc; /* Descriptor values - defined below */ + ushort count; /* number of 4 byte words to be transferred */ +- ulong32 addr; /* start address of dump or load */ +-} dump_cmd_t, *pdump_cmd_t; ++ u32 addr; /* start address of dump or load */ ++}; + + /* + * Receive or Transmit a frame. + */ +-typedef struct _RCV_OR_XMT_FRAME { +- uchar command; /* Command word defined above */ +- uchar MacId; /* Mac ID of interface - transmit only */ ++struct RCV_OR_XMT_FRAME { ++ unsigned char command; /* Command word defined above */ ++ unsigned char MacId; /* Mac ID of interface - transmit only */ + ushort count; /* Length of frame in bytes */ +- ulong32 pad; /* not used */ +-} RCV_OR_XMT_FRAME, *PRCV_OR_XMT_FRAME; ++ u32 pad; /* not used */ ++}; + + /* + * Values of desc field in DUMP_OR_LOAD structure +@@ -196,12 +195,12 @@ typedef struct _RCV_OR_XMT_FRAME { + /* + * Map command to replace a command in ROM with a command in WCS + */ +-typedef struct _MAP { +- uchar command; /* Command word defined above */ +- uchar not_used[3]; ++struct MAP { ++ unsigned char command; /* Command word defined above */ ++ unsigned char not_used[3]; + ushort map_to; /* Instruction address in WCS */ + ushort map_out; /* Instruction address in ROM */ +-} MAP, *PMAP; ++}; + + /* + * Misc definitions +@@ -221,35 +220,35 @@ typedef struct _MAP { + /* + * Coredump header structure + */ +-typedef struct _CORE_Q { +- ulong32 queueOff; /* Offset of queue */ +- ulong32 queuesize; /* size of queue */ +-} CORE_Q; ++struct CORE_Q { ++ u32 queueOff; /* Offset of queue */ ++ u32 queuesize; /* size of queue */ ++}; + + #define DRIVER_NAME_SIZE 32 + +-typedef struct _sliccore_hdr_t { +- uchar driver_version[DRIVER_NAME_SIZE]; /* Driver version string */ +- ulong32 RcvRegOff; /* Offset of receive registers */ +- ulong32 RcvRegsize; /* size of receive registers */ +- ulong32 XmtRegOff; /* Offset of transmit registers */ +- ulong32 XmtRegsize; /* size of transmit registers */ +- ulong32 FileRegOff; /* Offset of register file */ +- ulong32 FileRegsize; /* size of register file */ +- ulong32 SramOff; /* Offset of Sram */ +- ulong32 Sramsize; /* size of Sram */ +- ulong32 DramOff; /* Offset of Dram */ +- ulong32 Dramsize; /* size of Dram */ ++struct sliccore_hdr { ++ unsigned char driver_version[DRIVER_NAME_SIZE]; /* Driver version string */ ++ u32 RcvRegOff; /* Offset of receive registers */ ++ u32 RcvRegsize; /* size of receive registers */ ++ u32 XmtRegOff; /* Offset of transmit registers */ ++ u32 XmtRegsize; /* size of transmit registers */ ++ u32 FileRegOff; /* Offset of register file */ ++ u32 FileRegsize; /* size of register file */ ++ u32 SramOff; /* Offset of Sram */ ++ u32 Sramsize; /* size of Sram */ ++ u32 DramOff; /* Offset of Dram */ ++ u32 Dramsize; /* size of Dram */ + CORE_Q queues[SLIC_MAX_QUEUE]; /* size and offsets of queues */ +- ulong32 CamAMOff; /* Offset of CAM A contents */ +- ulong32 CamASize; /* Size of Cam A */ +- ulong32 CamBMOff; /* Offset of CAM B contents */ +- ulong32 CamBSize; /* Size of Cam B */ +- ulong32 CamCMOff; /* Offset of CAM C contents */ +- ulong32 CamCSize; /* Size of Cam C */ +- ulong32 CamDMOff; /* Offset of CAM D contents */ +- ulong32 CamDSize; /* Size of Cam D */ +-} sliccore_hdr_t, *p_sliccore_hdr_t; ++ u32 CamAMOff; /* Offset of CAM A contents */ ++ u32 CamASize; /* Size of Cam A */ ++ u32 CamBMOff; /* Offset of CAM B contents */ ++ u32 CamBSize; /* Size of Cam B */ ++ u32 CamCMOff; /* Offset of CAM C contents */ ++ u32 CamCSize; /* Size of Cam C */ ++ u32 CamDMOff; /* Offset of CAM D contents */ ++ u32 CamDSize; /* Size of Cam D */ ++}; + + /* + * definitions needed for our kernel-mode gdb stub. +diff --git a/drivers/staging/slicoss/slichw.h b/drivers/staging/slicoss/slichw.h +index d5765c4..4c5c15d 100644 +--- a/drivers/staging/slicoss/slichw.h ++++ b/drivers/staging/slicoss/slichw.h +@@ -2,7 +2,6 @@ + * + * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. + * +- * $Id: slichw.h,v 1.3 2008/03/17 19:27:26 chris Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -236,110 +235,106 @@ + #define TRUE 1 + #endif + +-typedef struct _slic_rcvbuf_t { +- uchar pad1[6]; ++struct slic_rcvbuf { ++ unsigned char pad1[6]; + ushort pad2; +- ulong32 pad3; +- ulong32 pad4; +- ulong32 buffer; +- ulong32 length; +- ulong32 status; +- ulong32 pad5; ++ u32 pad3; ++ u32 pad4; ++ u32 buffer; ++ u32 length; ++ u32 status; ++ u32 pad5; + ushort pad6; +- uchar data[SLIC_RCVBUF_DATASIZE]; +-} slic_rcvbuf_t, *p_slic_rcvbuf_t; ++ unsigned char data[SLIC_RCVBUF_DATASIZE]; ++}; + +-typedef struct _slic_hddr_wds { ++ struct slic_hddr_wds { + union { + struct { +- ulong32 frame_status; +- ulong32 frame_status_b; +- ulong32 time_stamp; +- ulong32 checksum; ++ u32 frame_status; ++ u32 frame_status_b; ++ u32 time_stamp; ++ u32 checksum; + } hdrs_14port; + struct { +- ulong32 frame_status; ++ u32 frame_status; + ushort ByteCnt; + ushort TpChksum; + ushort CtxHash; + ushort MacHash; +- ulong32 BufLnk; ++ u32 BufLnk; + } hdrs_gbit; + } u0; +-} slic_hddr_wds_t, *p_slic_hddr_wds; ++}; + + #define frame_status14 u0.hdrs_14port.frame_status + #define frame_status_b14 u0.hdrs_14port.frame_status_b + #define frame_statusGB u0.hdrs_gbit.frame_status + +-typedef struct _slic_host64sg_t { +- ulong32 paddrl; +- ulong32 paddrh; +- ulong32 length; +-} slic_host64sg_t, *p_slic_host64sg_t; +- +-typedef struct _slic_host64_cmd_t { +- ulong32 hosthandle; +- ulong32 RSVD; +- uchar command; +- uchar flags; ++struct slic_host64sg { ++ u32 paddrl; ++ u32 paddrh; ++ u32 length; ++}; ++ ++struct slic_host64_cmd { ++ u32 hosthandle; ++ u32 RSVD; ++ unsigned char command; ++ unsigned char flags; + union { + ushort rsv1; + ushort rsv2; + } u0; + union { + struct { +- ulong32 totlen; +- slic_host64sg_t bufs[SLIC_MAX64_BCNT]; ++ u32 totlen; ++ struct slic_host64sg bufs[SLIC_MAX64_BCNT]; + } slic_buffers; + } u; ++}; + +-} slic_host64_cmd_t, *p_slic_host64_cmd_t; ++struct slic_rspbuf { ++ u32 hosthandle; ++ u32 pad0; ++ u32 pad1; ++ u32 status; ++ u32 pad2[4]; + +-typedef struct _slic_rspbuf_t { +- ulong32 hosthandle; +- ulong32 pad0; +- ulong32 pad1; +- ulong32 status; +- ulong32 pad2[4]; ++}; + +-} slic_rspbuf_t, *p_slic_rspbuf_t; ++struct slic_regs { ++ u32 slic_reset; /* Reset Register */ ++ u32 pad0; + +-typedef ulong32 SLIC_REG; +- +- +-typedef struct _slic_regs_t { +- ULONG slic_reset; /* Reset Register */ +- ULONG pad0; +- +- ULONG slic_icr; /* Interrupt Control Register */ +- ULONG pad2; ++ u32 slic_icr; /* Interrupt Control Register */ ++ u32 pad2; + #define SLIC_ICR 0x0008 + +- ULONG slic_isp; /* Interrupt status pointer */ +- ULONG pad1; ++ u32 slic_isp; /* Interrupt status pointer */ ++ u32 pad1; + #define SLIC_ISP 0x0010 + +- ULONG slic_isr; /* Interrupt status */ +- ULONG pad3; ++ u32 slic_isr; /* Interrupt status */ ++ u32 pad3; + #define SLIC_ISR 0x0018 + +- SLIC_REG slic_hbar; /* Header buffer address reg */ +- ULONG pad4; ++ u32 slic_hbar; /* Header buffer address reg */ ++ u32 pad4; + /* 31-8 - phy addr of set of contiguous hdr buffers + 7-0 - number of buffers passed + Buffers are 256 bytes long on 256-byte boundaries. */ + #define SLIC_HBAR 0x0020 + #define SLIC_HBAR_CNT_MSK 0x000000FF + +- SLIC_REG slic_dbar; /* Data buffer handle & address reg */ +- ULONG pad5; ++ u32 slic_dbar; /* Data buffer handle & address reg */ ++ u32 pad5; + + /* 4 sets of registers; Buffers are 2K bytes long 2 per 4K page. */ + #define SLIC_DBAR 0x0028 + #define SLIC_DBAR_SIZE 2048 + +- SLIC_REG slic_cbar; /* Xmt Cmd buf addr regs.*/ ++ u32 slic_cbar; /* Xmt Cmd buf addr regs.*/ + /* 1 per XMT interface + 31-5 - phy addr of host command buffer + 4-0 - length of cmd in multiples of 32 bytes +@@ -348,13 +343,13 @@ typedef struct _slic_regs_t { + #define SLIC_CBAR_LEN_MSK 0x0000001F + #define SLIC_CBAR_ALIGN 0x00000020 + +- SLIC_REG slic_wcs; /* write control store*/ ++ u32 slic_wcs; /* write control store*/ + #define SLIC_WCS 0x0034 + #define SLIC_WCS_START 0x80000000 /*Start the SLIC (Jump to WCS)*/ + #define SLIC_WCS_COMPARE 0x40000000 /* Compare with value in WCS*/ + +- SLIC_REG slic_rbar; /* Response buffer address reg.*/ +- ULONG pad7; ++ u32 slic_rbar; /* Response buffer address reg.*/ ++ u32 pad7; + /*31-8 - phy addr of set of contiguous response buffers + 7-0 - number of buffers passed + Buffers are 32 bytes long on 32-byte boundaries.*/ +@@ -362,166 +357,166 @@ typedef struct _slic_regs_t { + #define SLIC_RBAR_CNT_MSK 0x000000FF + #define SLIC_RBAR_SIZE 32 + +- SLIC_REG slic_stats; /* read statistics (UPR) */ +- ULONG pad8; ++ u32 slic_stats; /* read statistics (UPR) */ ++ u32 pad8; + #define SLIC_RSTAT 0x0040 + +- SLIC_REG slic_rlsr; /* read link status */ +- ULONG pad9; ++ u32 slic_rlsr; /* read link status */ ++ u32 pad9; + #define SLIC_LSTAT 0x0048 + +- SLIC_REG slic_wmcfg; /* Write Mac Config */ +- ULONG pad10; ++ u32 slic_wmcfg; /* Write Mac Config */ ++ u32 pad10; + #define SLIC_WMCFG 0x0050 + +- SLIC_REG slic_wphy; /* Write phy register */ +- ULONG pad11; ++ u32 slic_wphy; /* Write phy register */ ++ u32 pad11; + #define SLIC_WPHY 0x0058 + +- SLIC_REG slic_rcbar; /*Rcv Cmd buf addr reg*/ +- ULONG pad12; ++ u32 slic_rcbar; /*Rcv Cmd buf addr reg*/ ++ u32 pad12; + #define SLIC_RCBAR 0x0060 + +- SLIC_REG slic_rconfig; /* Read SLIC Config*/ +- ULONG pad13; ++ u32 slic_rconfig; /* Read SLIC Config*/ ++ u32 pad13; + #define SLIC_RCONFIG 0x0068 + +- SLIC_REG slic_intagg; /* Interrupt aggregation time*/ +- ULONG pad14; ++ u32 slic_intagg; /* Interrupt aggregation time*/ ++ u32 pad14; + #define SLIC_INTAGG 0x0070 + +- SLIC_REG slic_wxcfg; /* Write XMIT config reg*/ +- ULONG pad16; ++ u32 slic_wxcfg; /* Write XMIT config reg*/ ++ u32 pad16; + #define SLIC_WXCFG 0x0078 + +- SLIC_REG slic_wrcfg; /* Write RCV config reg*/ +- ULONG pad17; ++ u32 slic_wrcfg; /* Write RCV config reg*/ ++ u32 pad17; + #define SLIC_WRCFG 0x0080 + +- SLIC_REG slic_wraddral; /* Write rcv addr a low*/ +- ULONG pad18; ++ u32 slic_wraddral; /* Write rcv addr a low*/ ++ u32 pad18; + #define SLIC_WRADDRAL 0x0088 + +- SLIC_REG slic_wraddrah; /* Write rcv addr a high*/ +- ULONG pad19; ++ u32 slic_wraddrah; /* Write rcv addr a high*/ ++ u32 pad19; + #define SLIC_WRADDRAH 0x0090 + +- SLIC_REG slic_wraddrbl; /* Write rcv addr b low*/ +- ULONG pad20; ++ u32 slic_wraddrbl; /* Write rcv addr b low*/ ++ u32 pad20; + #define SLIC_WRADDRBL 0x0098 + +- SLIC_REG slic_wraddrbh; /* Write rcv addr b high*/ +- ULONG pad21; ++ u32 slic_wraddrbh; /* Write rcv addr b high*/ ++ u32 pad21; + #define SLIC_WRADDRBH 0x00a0 + +- SLIC_REG slic_mcastlow; /* Low bits of mcast mask*/ +- ULONG pad22; ++ u32 slic_mcastlow; /* Low bits of mcast mask*/ ++ u32 pad22; + #define SLIC_MCASTLOW 0x00a8 + +- SLIC_REG slic_mcasthigh; /* High bits of mcast mask*/ +- ULONG pad23; ++ u32 slic_mcasthigh; /* High bits of mcast mask*/ ++ u32 pad23; + #define SLIC_MCASTHIGH 0x00b0 + +- SLIC_REG slic_ping; /* Ping the card*/ +- ULONG pad24; ++ u32 slic_ping; /* Ping the card*/ ++ u32 pad24; + #define SLIC_PING 0x00b8 + +- SLIC_REG slic_dump_cmd; /* Dump command */ +- ULONG pad25; ++ u32 slic_dump_cmd; /* Dump command */ ++ u32 pad25; + #define SLIC_DUMP_CMD 0x00c0 + +- SLIC_REG slic_dump_data; /* Dump data pointer */ +- ULONG pad26; ++ u32 slic_dump_data; /* Dump data pointer */ ++ u32 pad26; + #define SLIC_DUMP_DATA 0x00c8 + +- SLIC_REG slic_pcistatus; /* Read card's pci_status register */ +- ULONG pad27; ++ u32 slic_pcistatus; /* Read card's pci_status register */ ++ u32 pad27; + #define SLIC_PCISTATUS 0x00d0 + +- SLIC_REG slic_wrhostid; /* Write hostid field */ +- ULONG pad28; ++ u32 slic_wrhostid; /* Write hostid field */ ++ u32 pad28; + #define SLIC_WRHOSTID 0x00d8 + #define SLIC_RDHOSTID_1GB 0x1554 + #define SLIC_RDHOSTID_2GB 0x1554 + +- SLIC_REG slic_low_power; /* Put card in a low power state */ +- ULONG pad29; ++ u32 slic_low_power; /* Put card in a low power state */ ++ u32 pad29; + #define SLIC_LOW_POWER 0x00e0 + +- SLIC_REG slic_quiesce; /* force slic into quiescent state ++ u32 slic_quiesce; /* force slic into quiescent state + before soft reset */ +- ULONG pad30; ++ u32 pad30; + #define SLIC_QUIESCE 0x00e8 + +- SLIC_REG slic_reset_iface; /* reset interface queues */ +- ULONG pad31; ++ u32 slic_reset_iface; /* reset interface queues */ ++ u32 pad31; + #define SLIC_RESET_IFACE 0x00f0 + +- SLIC_REG slic_addr_upper; /* Bits 63-32 for host i/f addrs */ +- ULONG pad32; ++ u32 slic_addr_upper; /* Bits 63-32 for host i/f addrs */ ++ u32 pad32; + #define SLIC_ADDR_UPPER 0x00f8 /*Register is only written when it has changed*/ + +- SLIC_REG slic_hbar64; /* 64 bit Header buffer address reg */ +- ULONG pad33; ++ u32 slic_hbar64; /* 64 bit Header buffer address reg */ ++ u32 pad33; + #define SLIC_HBAR64 0x0100 + +- SLIC_REG slic_dbar64; /* 64 bit Data buffer handle & address reg */ +- ULONG pad34; ++ u32 slic_dbar64; /* 64 bit Data buffer handle & address reg */ ++ u32 pad34; + #define SLIC_DBAR64 0x0108 + +- SLIC_REG slic_cbar64; /* 64 bit Xmt Cmd buf addr regs. */ +- ULONG pad35; ++ u32 slic_cbar64; /* 64 bit Xmt Cmd buf addr regs. */ ++ u32 pad35; + #define SLIC_CBAR64 0x0110 + +- SLIC_REG slic_rbar64; /* 64 bit Response buffer address reg.*/ +- ULONG pad36; ++ u32 slic_rbar64; /* 64 bit Response buffer address reg.*/ ++ u32 pad36; + #define SLIC_RBAR64 0x0118 + +- SLIC_REG slic_rcbar64; /* 64 bit Rcv Cmd buf addr reg*/ +- ULONG pad37; ++ u32 slic_rcbar64; /* 64 bit Rcv Cmd buf addr reg*/ ++ u32 pad37; + #define SLIC_RCBAR64 0x0120 + +- SLIC_REG slic_stats64; /*read statistics (64 bit UPR)*/ +- ULONG pad38; ++ u32 slic_stats64; /*read statistics (64 bit UPR)*/ ++ u32 pad38; + #define SLIC_RSTAT64 0x0128 + +- SLIC_REG slic_rcv_wcs; /*Download Gigabit RCV sequencer ucode*/ +- ULONG pad39; ++ u32 slic_rcv_wcs; /*Download Gigabit RCV sequencer ucode*/ ++ u32 pad39; + #define SLIC_RCV_WCS 0x0130 + #define SLIC_RCVWCS_BEGIN 0x40000000 + #define SLIC_RCVWCS_FINISH 0x80000000 + +- SLIC_REG slic_wrvlanid; /* Write VlanId field */ +- ULONG pad40; ++ u32 slic_wrvlanid; /* Write VlanId field */ ++ u32 pad40; + #define SLIC_WRVLANID 0x0138 + +- SLIC_REG slic_read_xf_info; /* Read Transformer info */ +- ULONG pad41; ++ u32 slic_read_xf_info; /* Read Transformer info */ ++ u32 pad41; + #define SLIC_READ_XF_INFO 0x0140 + +- SLIC_REG slic_write_xf_info; /* Write Transformer info */ +- ULONG pad42; ++ u32 slic_write_xf_info; /* Write Transformer info */ ++ u32 pad42; + #define SLIC_WRITE_XF_INFO 0x0148 + +- SLIC_REG RSVD1; /* TOE Only */ +- ULONG pad43; ++ u32 RSVD1; /* TOE Only */ ++ u32 pad43; + +- SLIC_REG RSVD2; /* TOE Only */ +- ULONG pad44; ++ u32 RSVD2; /* TOE Only */ ++ u32 pad44; + +- SLIC_REG RSVD3; /* TOE Only */ +- ULONG pad45; ++ u32 RSVD3; /* TOE Only */ ++ u32 pad45; + +- SLIC_REG RSVD4; /* TOE Only */ +- ULONG pad46; ++ u32 RSVD4; /* TOE Only */ ++ u32 pad46; + +- SLIC_REG slic_ticks_per_sec; /* Write card ticks per second */ +- ULONG pad47; ++ u32 slic_ticks_per_sec; /* Write card ticks per second */ ++ u32 pad47; + #define SLIC_TICKS_PER_SEC 0x0170 + +-} __iomem slic_regs_t, *p_slic_regs_t, SLIC_REGS, *PSLIC_REGS; ++}; + +-typedef enum _UPR_REQUEST { ++enum UPR_REQUEST { + SLIC_UPR_STATS, + SLIC_UPR_RLSR, + SLIC_UPR_WCFG, +@@ -532,103 +527,102 @@ typedef enum _UPR_REQUEST { + SLIC_UPR_PDWN, + SLIC_UPR_PING, + SLIC_UPR_DUMP, +-} UPR_REQUEST; +- +-typedef struct _inicpm_wakepattern { +- ulong32 patternlength; +- uchar pattern[SLIC_PM_PATTERNSIZE]; +- uchar mask[SLIC_PM_PATTERNSIZE]; +-} inicpm_wakepattern_t, *p_inicpm_wakepattern_t; +- +-typedef struct _inicpm_state { +- ulong32 powercaps; +- ulong32 powerstate; +- ulong32 wake_linkstatus; +- ulong32 wake_magicpacket; +- ulong32 wake_framepattern; +- inicpm_wakepattern_t wakepattern[SLIC_PM_MAXPATTERNS]; +-} inicpm_state_t, *p_inicpm_state_t; +- +-typedef struct _slicpm_packet_pattern { +- ulong32 priority; +- ulong32 reserved; +- ulong32 masksize; +- ulong32 patternoffset; +- ulong32 patternsize; +- ulong32 patternflags; +-} slicpm_packet_pattern_t, *p_slicpm_packet_pattern_t; +- +-typedef enum _slicpm_power_state { ++}; ++ ++struct inicpm_wakepattern { ++ u32 patternlength; ++ unsigned char pattern[SLIC_PM_PATTERNSIZE]; ++ unsigned char mask[SLIC_PM_PATTERNSIZE]; ++}; ++ ++struct inicpm_state { ++ u32 powercaps; ++ u32 powerstate; ++ u32 wake_linkstatus; ++ u32 wake_magicpacket; ++ u32 wake_framepattern; ++ struct inicpm_wakepattern wakepattern[SLIC_PM_MAXPATTERNS]; ++}; ++ ++struct slicpm_packet_pattern { ++ u32 priority; ++ u32 reserved; ++ u32 masksize; ++ u32 patternoffset; ++ u32 patternsize; ++ u32 patternflags; ++}; ++ ++enum slicpm_power_state { + slicpm_state_unspecified = 0, + slicpm_state_d0, + slicpm_state_d1, + slicpm_state_d2, + slicpm_state_d3, + slicpm_state_maximum +-} slicpm_state_t, *p_slicpm_state_t; +- +-typedef struct _slicpm_wakeup_capabilities { +- slicpm_state_t min_magic_packet_wakeup; +- slicpm_state_t min_pattern_wakeup; +- slicpm_state_t min_link_change_wakeup; +-} slicpm_wakeup_capabilities_t, *p_slicpm_wakeup_capabilities_t; +- +- +-typedef struct _slic_pnp_capabilities { +- ulong32 flags; +- slicpm_wakeup_capabilities_t wakeup_capabilities; +-} slic_pnp_capabilities_t, *p_slic_pnp_capabilities_t; +- +-typedef struct _xmt_stats_t { +- ulong32 xmit_tcp_bytes; +- ulong32 xmit_tcp_segs; +- ulong32 xmit_bytes; +- ulong32 xmit_collisions; +- ulong32 xmit_unicasts; +- ulong32 xmit_other_error; +- ulong32 xmit_excess_collisions; +-} xmt_stats100_t; +- +-typedef struct _rcv_stats_t { +- ulong32 rcv_tcp_bytes; +- ulong32 rcv_tcp_segs; +- ulong32 rcv_bytes; +- ulong32 rcv_unicasts; +- ulong32 rcv_other_error; +- ulong32 rcv_drops; +-} rcv_stats100_t; +- +-typedef struct _xmt_statsgb_t { +- ulong64 xmit_tcp_bytes; +- ulong64 xmit_tcp_segs; +- ulong64 xmit_bytes; +- ulong64 xmit_collisions; +- ulong64 xmit_unicasts; +- ulong64 xmit_other_error; +- ulong64 xmit_excess_collisions; +-} xmt_statsGB_t; +- +-typedef struct _rcv_statsgb_t { +- ulong64 rcv_tcp_bytes; +- ulong64 rcv_tcp_segs; +- ulong64 rcv_bytes; +- ulong64 rcv_unicasts; +- u64 rcv_other_error; +- ulong64 rcv_drops; +-} rcv_statsGB_t; +- +-typedef struct _slic_stats { ++}; ++ ++struct slicpm_wakeup_capabilities { ++ enum slicpm_power_state min_magic_packet_wakeup; ++ enum slicpm_power_state min_pattern_wakeup; ++ enum slicpm_power_state min_link_change_wakeup; ++}; ++ ++struct slic_pnp_capabilities { ++ u32 flags; ++ struct slicpm_wakeup_capabilities wakeup_capabilities; ++}; ++ ++struct xmt_stats { ++ u32 xmit_tcp_bytes; ++ u32 xmit_tcp_segs; ++ u32 xmit_bytes; ++ u32 xmit_collisions; ++ u32 xmit_unicasts; ++ u32 xmit_other_error; ++ u32 xmit_excess_collisions; ++}; ++ ++struct rcv_stats { ++ u32 rcv_tcp_bytes; ++ u32 rcv_tcp_segs; ++ u32 rcv_bytes; ++ u32 rcv_unicasts; ++ u32 rcv_other_error; ++ u32 rcv_drops; ++}; ++ ++struct xmt_statsgb { ++ u64 xmit_tcp_bytes; ++ u64 xmit_tcp_segs; ++ u64 xmit_bytes; ++ u64 xmit_collisions; ++ u64 xmit_unicasts; ++ u64 xmit_other_error; ++ u64 xmit_excess_collisions; ++}; ++ ++struct rcv_statsgb { ++ u64 rcv_tcp_bytes; ++ u64 rcv_tcp_segs; ++ u64 rcv_bytes; ++ u64 rcv_unicasts; ++ u64 rcv_other_error; ++ u64 rcv_drops; ++}; ++ ++struct slic_stats { + union { + struct { +- xmt_stats100_t xmt100; +- rcv_stats100_t rcv100; ++ struct xmt_stats xmt100; ++ struct rcv_stats rcv100; + } stats_100; + struct { +- xmt_statsGB_t xmtGB; +- rcv_statsGB_t rcvGB; ++ struct xmt_statsgb xmtGB; ++ struct rcv_statsgb rcvGB; + } stats_GB; + } u; +-} slic_stats_t, *p_slic_stats_t; ++}; + + #define xmit_tcp_segs100 u.stats_100.xmt100.xmit_tcp_segs + #define xmit_tcp_bytes100 u.stats_100.xmt100.xmit_tcp_bytes +@@ -658,10 +652,9 @@ typedef struct _slic_stats { + #define rcv_other_error_gb u.stats_GB.rcvGB.rcv_other_error + #define rcv_drops_gb u.stats_GB.rcvGB.rcv_drops + +-typedef struct _slic_config_mac_t { +- uchar macaddrA[6]; +- +-} slic_config_mac_t, *pslic_config_mac_t; ++struct slic_config_mac { ++ unsigned char macaddrA[6]; ++}; + + #define ATK_FRU_FORMAT 0x00 + #define VENDOR1_FRU_FORMAT 0x01 +@@ -670,68 +663,68 @@ typedef struct _slic_config_mac_t { + #define VENDOR4_FRU_FORMAT 0x04 + #define NO_FRU_FORMAT 0xFF + +-typedef struct _atk_fru_t { +- uchar assembly[6]; +- uchar revision[2]; +- uchar serial[14]; +- uchar pad[3]; +-} atk_fru_t, *patk_fru_t; +- +-typedef struct _vendor1_fru_t { +- uchar commodity; +- uchar assembly[4]; +- uchar revision[2]; +- uchar supplier[2]; +- uchar date[2]; +- uchar sequence[3]; +- uchar pad[13]; +-} vendor1_fru_t, *pvendor1_fru_t; +- +-typedef struct _vendor2_fru_t { +- uchar part[8]; +- uchar supplier[5]; +- uchar date[3]; +- uchar sequence[4]; +- uchar pad[7]; +-} vendor2_fru_t, *pvendor2_fru_t; +- +-typedef struct _vendor3_fru_t { +- uchar assembly[6]; +- uchar revision[2]; +- uchar serial[14]; +- uchar pad[3]; +-} vendor3_fru_t, *pvendor3_fru_t; +- +-typedef struct _vendor4_fru_t { +- uchar number[8]; +- uchar part[8]; +- uchar version[8]; +- uchar pad[3]; +-} vendor4_fru_t, *pvendor4_fru_t; +- +-typedef union _oemfru_t { +- vendor1_fru_t vendor1_fru; +- vendor2_fru_t vendor2_fru; +- vendor3_fru_t vendor3_fru; +- vendor4_fru_t vendor4_fru; +-} oemfru_t, *poemfru_t; ++struct atk_fru { ++ unsigned char assembly[6]; ++ unsigned char revision[2]; ++ unsigned char serial[14]; ++ unsigned char pad[3]; ++}; ++ ++struct vendor1_fru { ++ unsigned char commodity; ++ unsigned char assembly[4]; ++ unsigned char revision[2]; ++ unsigned char supplier[2]; ++ unsigned char date[2]; ++ unsigned char sequence[3]; ++ unsigned char pad[13]; ++}; ++ ++struct vendor2_fru { ++ unsigned char part[8]; ++ unsigned char supplier[5]; ++ unsigned char date[3]; ++ unsigned char sequence[4]; ++ unsigned char pad[7]; ++}; ++ ++struct vendor3_fru { ++ unsigned char assembly[6]; ++ unsigned char revision[2]; ++ unsigned char serial[14]; ++ unsigned char pad[3]; ++}; ++ ++struct vendor4_fru { ++ unsigned char number[8]; ++ unsigned char part[8]; ++ unsigned char version[8]; ++ unsigned char pad[3]; ++}; ++ ++union oemfru_t { ++ struct vendor1_fru vendor1_fru; ++ struct vendor2_fru vendor2_fru; ++ struct vendor3_fru vendor3_fru; ++ struct vendor4_fru vendor4_fru; ++}; + + /* + SLIC EEPROM structure for Mojave + */ +-typedef struct _slic_eeprom { ++struct slic_eeprom { + ushort Id; /* 00 EEPROM/FLASH Magic code 'A5A5'*/ + ushort EecodeSize; /* 01 Size of EEPROM Codes (bytes * 4)*/ + ushort FlashSize; /* 02 Flash size */ + ushort EepromSize; /* 03 EEPROM Size */ + ushort VendorId; /* 04 Vendor ID */ + ushort DeviceId; /* 05 Device ID */ +- uchar RevisionId; /* 06 Revision ID */ +- uchar ClassCode[3]; /* 07 Class Code */ +- uchar DbgIntPin; /* 08 Debug Interrupt pin */ +- uchar NetIntPin0; /* Network Interrupt Pin */ +- uchar MinGrant; /* 09 Minimum grant */ +- uchar MaxLat; /* Maximum Latency */ ++ unsigned char RevisionId; /* 06 Revision ID */ ++ unsigned char ClassCode[3]; /* 07 Class Code */ ++ unsigned char DbgIntPin; /* 08 Debug Interrupt pin */ ++ unsigned char NetIntPin0; /* Network Interrupt Pin */ ++ unsigned char MinGrant; /* 09 Minimum grant */ ++ unsigned char MaxLat; /* Maximum Latency */ + ushort PciStatus; /* 10 PCI Status */ + ushort SubSysVId; /* 11 Subsystem Vendor Id */ + ushort SubSysId; /* 12 Subsystem ID */ +@@ -739,58 +732,60 @@ typedef struct _slic_eeprom { + ushort DramRomFn; /* 14 Dram/Rom function */ + ushort DSize2Pci; /* 15 DRAM size to PCI (bytes * 64K) */ + ushort RSize2Pci; /* 16 ROM extension size to PCI (bytes * 4k) */ +- uchar NetIntPin1; /* 17 Network Interface Pin 1 (simba/leone only) */ +- uchar NetIntPin2; /* Network Interface Pin 2 (simba/leone only) */ ++ unsigned char NetIntPin1;/* 17 Network Interface Pin 1 ++ (simba/leone only) */ ++ unsigned char NetIntPin2; /*Network Interface Pin 2 (simba/leone only)*/ + union { +- uchar NetIntPin3;/* 18 Network Interface Pin 3 (simba only) */ +- uchar FreeTime;/* FreeTime setting (leone/mojave only) */ ++ unsigned char NetIntPin3;/*18 Network Interface Pin 3 ++ (simba only)*/ ++ unsigned char FreeTime;/*FreeTime setting (leone/mojave only) */ + } u1; +- uchar TBIctl; /* 10-bit interface control (Mojave only) */ ++ unsigned char TBIctl; /* 10-bit interface control (Mojave only) */ + ushort DramSize; /* 19 DRAM size (bytes * 64k) */ + union { + struct { + /* Mac Interface Specific portions */ +- slic_config_mac_t MacInfo[SLIC_NBR_MACS]; ++ struct slic_config_mac MacInfo[SLIC_NBR_MACS]; + } mac; /* MAC access for all boards */ + struct { + /* use above struct for MAC access */ +- slic_config_mac_t pad[SLIC_NBR_MACS - 1]; ++ struct slic_config_mac pad[SLIC_NBR_MACS - 1]; + ushort DeviceId2; /* Device ID for 2nd + PCI function */ +- uchar IntPin2; /* Interrupt pin for ++ unsigned char IntPin2; /* Interrupt pin for + 2nd PCI function */ +- uchar ClassCode2[3]; /* Class Code for 2nd ++ unsigned char ClassCode2[3]; /* Class Code for 2nd + PCI function */ + } mojave; /* 2nd function access for gigabit board */ + } u2; + ushort CfgByte6; /* Config Byte 6 */ + ushort PMECapab; /* Power Mgment capabilities */ + ushort NwClkCtrls; /* NetworkClockControls */ +- uchar FruFormat; /* Alacritech FRU format type */ +- atk_fru_t AtkFru; /* Alacritech FRU information */ +- uchar OemFruFormat; /* optional OEM FRU format type */ +- oemfru_t OemFru; /* optional OEM FRU information */ +- uchar Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes ++ unsigned char FruFormat; /* Alacritech FRU format type */ ++ struct atk_fru AtkFru; /* Alacritech FRU information */ ++ unsigned char OemFruFormat; /* optional OEM FRU format type */ ++ union oemfru_t OemFru; /* optional OEM FRU information */ ++ unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes + *(if OEM FRU info exists) and two unusable + * bytes at the end */ +-} slic_eeprom_t, *pslic_eeprom_t; ++}; + + /* SLIC EEPROM structure for Oasis */ +-typedef struct _oslic_eeprom_t { ++struct oslic_eeprom { + ushort Id; /* 00 EEPROM/FLASH Magic code 'A5A5' */ + ushort EecodeSize; /* 01 Size of EEPROM Codes (bytes * 4)*/ + ushort FlashConfig0; /* 02 Flash Config for SPI device 0 */ + ushort FlashConfig1; /* 03 Flash Config for SPI device 1 */ + ushort VendorId; /* 04 Vendor ID */ + ushort DeviceId; /* 05 Device ID (function 0) */ +- uchar RevisionId; /* 06 Revision ID */ +- uchar ClassCode[3]; /* 07 Class Code for PCI function 0 */ +- uchar IntPin1; /* 08 Interrupt pin for PCI function 1*/ +- uchar ClassCode2[3]; /* 09 Class Code for PCI function 1 */ +- uchar IntPin2; /* 10 Interrupt pin for PCI function 2*/ +- uchar IntPin0; /* Interrupt pin for PCI function 0*/ +- uchar MinGrant; /* 11 Minimum grant */ +- uchar MaxLat; /* Maximum Latency */ ++ unsigned char RevisionId; /* 06 Revision ID */ ++ unsigned char ClassCode[3]; /* 07 Class Code for PCI function 0 */ ++ unsigned char IntPin1; /* 08 Interrupt pin for PCI function 1*/ ++ unsigned char ClassCode2[3]; /* 09 Class Code for PCI function 1 */ ++ unsigned char IntPin2; /* 10 Interrupt pin for PCI function 2*/ ++ unsigned char IntPin0; /* Interrupt pin for PCI function 0*/ ++ unsigned char MinGrant; /* 11 Minimum grant */ ++ unsigned char MaxLat; /* Maximum Latency */ + ushort SubSysVId; /* 12 Subsystem Vendor Id */ + ushort SubSysId; /* 13 Subsystem ID */ + ushort FlashSize; /* 14 Flash size (bytes / 4K) */ +@@ -801,8 +796,8 @@ typedef struct _oslic_eeprom_t { + ushort DeviceId2; /* 18 Device Id (function 2) */ + ushort CfgByte6; /* 19 Device Status Config Bytes 6-7 */ + ushort PMECapab; /* 20 Power Mgment capabilities */ +- uchar MSICapab; /* 21 MSI capabilities */ +- uchar ClockDivider; /* Clock divider */ ++ unsigned char MSICapab; /* 21 MSI capabilities */ ++ unsigned char ClockDivider; /* Clock divider */ + ushort PciStatusLow; /* 22 PCI Status bits 15:0 */ + ushort PciStatusHigh; /* 23 PCI Status bits 31:16 */ + ushort DramConfigLow; /* 24 DRAM Configuration bits 15:0 */ +@@ -810,18 +805,18 @@ typedef struct _oslic_eeprom_t { + ushort DramSize; /* 26 DRAM size (bytes / 64K) */ + ushort GpioTbiCtl;/* 27 GPIO/TBI controls for functions 1/0 */ + ushort EepromSize; /* 28 EEPROM Size */ +- slic_config_mac_t MacInfo[2]; /* 29 MAC addresses (2 ports) */ +- uchar FruFormat; /* 35 Alacritech FRU format type */ +- atk_fru_t AtkFru; /* Alacritech FRU information */ +- uchar OemFruFormat; /* optional OEM FRU format type */ +- oemfru_t OemFru; /* optional OEM FRU information */ +- uchar Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes ++ struct slic_config_mac MacInfo[2]; /* 29 MAC addresses (2 ports) */ ++ unsigned char FruFormat; /* 35 Alacritech FRU format type */ ++ struct atk_fru AtkFru; /* Alacritech FRU information */ ++ unsigned char OemFruFormat; /* optional OEM FRU format type */ ++ union oemfru_t OemFru; /* optional OEM FRU information */ ++ unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes + * (if OEM FRU info exists) and two unusable + * bytes at the end + */ +-} oslic_eeprom_t, *poslic_eeprom_t; ++}; + +-#define MAX_EECODE_SIZE sizeof(slic_eeprom_t) ++#define MAX_EECODE_SIZE sizeof(struct slic_eeprom) + #define MIN_EECODE_SIZE 0x62 /* code size without optional OEM FRU stuff */ + + /* SLIC CONFIG structure +@@ -830,20 +825,20 @@ typedef struct _oslic_eeprom_t { + board types. It is filled in from the appropriate EEPROM structure + by SlicGetConfigData(). + */ +-typedef struct _slic_config_t { +- boolean EepromValid; /* Valid EEPROM flag (checksum good?) */ ++struct slic_config { ++ bool EepromValid; /* Valid EEPROM flag (checksum good?) */ + ushort DramSize; /* DRAM size (bytes / 64K) */ +- slic_config_mac_t MacInfo[SLIC_NBR_MACS]; /* MAC addresses */ +- uchar FruFormat; /* Alacritech FRU format type */ +- atk_fru_t AtkFru; /* Alacritech FRU information */ +- uchar OemFruFormat; /* optional OEM FRU format type */ +- union { +- vendor1_fru_t vendor1_fru; +- vendor2_fru_t vendor2_fru; +- vendor3_fru_t vendor3_fru; +- vendor4_fru_t vendor4_fru; +- } OemFru; +-} slic_config_t, *pslic_config_t; ++ struct slic_config_mac MacInfo[SLIC_NBR_MACS]; /* MAC addresses */ ++ unsigned char FruFormat; /* Alacritech FRU format type */ ++ struct atk_fru AtkFru; /* Alacritech FRU information */ ++ unsigned char OemFruFormat; /* optional OEM FRU format type */ ++ union { ++ struct vendor1_fru vendor1_fru; ++ struct vendor2_fru vendor2_fru; ++ struct vendor3_fru vendor3_fru; ++ struct vendor4_fru vendor4_fru; ++ } OemFru; ++}; + + #pragma pack() + +diff --git a/drivers/staging/slicoss/slicinc.h b/drivers/staging/slicoss/slicinc.h +index 9910306..610c1ab 100644 +--- a/drivers/staging/slicoss/slicinc.h ++++ b/drivers/staging/slicoss/slicinc.h +@@ -2,7 +2,6 @@ + * + * Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved. + * +- * $Id: slicinc.h,v 1.4 2006/07/14 16:42:56 mook Exp $ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -48,164 +47,135 @@ + #include "slichw.h" + #include "slic.h" + +-int slic_entry_probe(struct pci_dev *pcidev, ++static int slic_entry_probe(struct pci_dev *pcidev, + const struct pci_device_id *ent); +-int slic_init(struct pci_dev *pcidev, +- const struct pci_device_id *pci_tbl_entry, +- long memaddr, +- int chip_idx, +- int acpi_idle_state); +-void slic_entry_remove(struct pci_dev *pcidev); ++static void slic_entry_remove(struct pci_dev *pcidev); + +-void slic_init_driver(void); +-int slic_entry_open(struct net_device *dev); +-int slic_entry_halt(struct net_device *dev); +-int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +-int slic_xmit_start(struct sk_buff *skb, struct net_device *dev); +-void slic_xmit_fail(p_adapter_t adapter, ++static void slic_init_driver(void); ++static int slic_entry_open(struct net_device *dev); ++static int slic_entry_halt(struct net_device *dev); ++static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev); ++static void slic_xmit_fail(struct adapter *adapter, + struct sk_buff *skb, +- pvoid cmd, +- ulong32 skbtype, +- ulong32 status); +-void slic_xmit_timeout(struct net_device *dev); +-void slic_config_pci(struct pci_dev *pcidev); +-struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter); ++ void *cmd, ++ u32 skbtype, ++ u32 status); ++static void slic_xmit_timeout(struct net_device *dev); ++static void slic_config_pci(struct pci_dev *pcidev); ++static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter); + +-inline void slic_reg32_write(void __iomem *reg, ulong32 value, uint flush); +-inline void slic_reg64_write(p_adapter_t adapter, void __iomem *reg, +- ulong32 value, void __iomem *regh, ulong32 paddrh, uint flush); +-inline ulong32 slic_reg32_read(pulong32 reg, uint flush); +-inline ulong32 slic_reg16_read(pulong32 reg, uint flush); ++static inline void slic_reg32_write(void __iomem *reg, u32 value, uint flush); ++static inline void slic_reg64_write(struct adapter *adapter, void __iomem *reg, ++ u32 value, void __iomem *regh, u32 paddrh, uint flush); + + #if SLIC_GET_STATS_ENABLED +-struct net_device_stats *slic_get_stats(struct net_device *dev); ++static struct net_device_stats *slic_get_stats(struct net_device *dev); + #endif + +-int slic_mac_set_address(struct net_device *dev, pvoid ptr); ++static int slic_mac_set_address(struct net_device *dev, void *ptr); ++static void slic_rcv_handler(struct adapter *adapter); ++static void slic_link_event_handler(struct adapter *adapter); ++static void slic_xmit_complete(struct adapter *adapter); ++static void slic_upr_request_complete(struct adapter *adapter, u32 isr); ++static int slic_rspqueue_init(struct adapter *adapter); ++static int slic_rspqueue_reset(struct adapter *adapter); ++static void slic_rspqueue_free(struct adapter *adapter); ++static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter); ++static void slic_cmdqmem_init(struct adapter *adapter); ++static void slic_cmdqmem_free(struct adapter *adapter); ++static u32 *slic_cmdqmem_addpage(struct adapter *adapter); ++static int slic_cmdq_init(struct adapter *adapter); ++static void slic_cmdq_free(struct adapter *adapter); ++static void slic_cmdq_reset(struct adapter *adapter); ++static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page); ++static void slic_cmdq_getdone(struct adapter *adapter); ++static void slic_cmdq_putdone(struct adapter *adapter, ++ struct slic_hostcmd *cmd); ++static void slic_cmdq_putdone_irq(struct adapter *adapter, ++ struct slic_hostcmd *cmd); ++static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter); ++static int slic_rcvqueue_init(struct adapter *adapter); ++static int slic_rcvqueue_reset(struct adapter *adapter); ++static int slic_rcvqueue_fill(struct adapter *adapter); ++static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb); ++static void slic_rcvqueue_free(struct adapter *adapter); ++static void slic_rcv_handle_error(struct adapter *adapter, ++ struct slic_rcvbuf *rcvbuf); ++static void slic_adapter_set_hwaddr(struct adapter *adapter); ++static void slic_card_halt(struct sliccard *card, struct adapter *adapter); ++static int slic_card_init(struct sliccard *card, struct adapter *adapter); ++static void slic_intagg_set(struct adapter *adapter, u32 value); ++static int slic_card_download(struct adapter *adapter); ++static u32 slic_card_locate(struct adapter *adapter); + +-int slicproc_card_read(char *page, char **start, off_t off, int count, +- int *eof, void *data); +-int slicproc_card_write(struct file *file, const char __user *buffer, +- ulong count, void *data); +-void slicproc_card_create(p_sliccard_t card); +-void slicproc_card_destroy(p_sliccard_t card); +-int slicproc_adapter_read(char *page, char **start, off_t off, int count, +- int *eof, void *data); +-int slicproc_adapter_write(struct file *file, const char __user *buffer, +- ulong count, void *data); +-void slicproc_adapter_create(p_adapter_t adapter); +-void slicproc_adapter_destroy(p_adapter_t adapter); +-void slicproc_create(void); +-void slicproc_destroy(void); +- +-void slic_interrupt_process(p_adapter_t adapter, ulong32 isr); +-void slic_rcv_handler(p_adapter_t adapter); +-void slic_upr_handler(p_adapter_t adapter); +-void slic_link_event_handler(p_adapter_t adapter); +-void slic_xmit_complete(p_adapter_t adapter); +-void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr); +-int slic_rspqueue_init(p_adapter_t adapter); +-int slic_rspqueue_reset(p_adapter_t adapter); +-void slic_rspqueue_free(p_adapter_t adapter); +-p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter); +-void slic_cmdqmem_init(p_adapter_t adapter); +-void slic_cmdqmem_free(p_adapter_t adapter); +-pulong32 slic_cmdqmem_addpage(p_adapter_t adapter); +-int slic_cmdq_init(p_adapter_t adapter); +-void slic_cmdq_free(p_adapter_t adapter); +-void slic_cmdq_reset(p_adapter_t adapter); +-void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page); +-void slic_cmdq_getdone(p_adapter_t adapter); +-void slic_cmdq_putdone(p_adapter_t adapter, p_slic_hostcmd_t cmd); +-void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd); +-p_slic_hostcmd_t slic_cmdq_getfree(p_adapter_t adapter); +-int slic_rcvqueue_init(p_adapter_t adapter); +-int slic_rcvqueue_reset(p_adapter_t adapter); +-int slic_rcvqueue_fill(p_adapter_t adapter); +-ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb); +-void slic_rcvqueue_free(p_adapter_t adapter); +-void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf); +-void slic_adapter_set_hwaddr(p_adapter_t adapter); +-void slic_card_halt(p_sliccard_t card, p_adapter_t adapter); +-int slic_card_init(p_sliccard_t card, p_adapter_t adapter); +-void slic_intagg_set(p_adapter_t adapter, ulong32 value); +-int slic_card_download(p_adapter_t adapter); +-ulong32 slic_card_locate(p_adapter_t adapter); +-int slic_card_removeadapter(p_adapter_t adapter); +-void slic_card_remaster(p_adapter_t adapter); +-void slic_card_softreset(p_adapter_t adapter); +-void slic_card_up(p_adapter_t adapter); +-void slic_card_down(p_adapter_t adapter); +- +-void slic_if_stop_queue(p_adapter_t adapter); +-void slic_if_start_queue(p_adapter_t adapter); +-int slic_if_init(p_adapter_t adapter); +-void slic_adapter_close(p_adapter_t adapter); +-int slic_adapter_allocresources(p_adapter_t adapter); +-void slic_adapter_freeresources(p_adapter_t adapter); +-void slic_link_config(p_adapter_t adapter, ulong32 linkspeed, +- ulong32 linkduplex); +-void slic_unmap_mmio_space(p_adapter_t adapter); +-void slic_card_cleanup(p_sliccard_t card); +-void slic_init_cleanup(p_adapter_t adapter); +-void slic_card_reclaim_buffers(p_adapter_t adapter); +-void slic_soft_reset(p_adapter_t adapter); +-void slic_card_reset(p_adapter_t adapter); +-boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame); +-void slic_mac_address_config(p_adapter_t adapter); +-void slic_mac_config(p_adapter_t adapter); +-void slic_mcast_set_mask(p_adapter_t adapter); +-void slic_mac_setmcastaddrs(p_adapter_t adapter); +-int slic_mcast_add_list(p_adapter_t adapter, pchar address); +-uchar slic_mcast_get_mac_hash(pchar macaddr); +-void slic_mcast_set_bit(p_adapter_t adapter, pchar address); +-void slic_config_set(p_adapter_t adapter, boolean linkchange); +-void slic_config_clear(p_adapter_t adapter); +-void slic_config_get(p_adapter_t adapter, ulong32 config, ulong32 configh); +-void slic_timer_get_stats(ulong device); +-void slic_timer_load_check(ulong context); +-void slic_timer_ping(ulong dev); +-void slic_stall_msec(int stall); +-void slic_stall_usec(int stall); +-void slic_assert_fail(void); +-ushort slic_eeprom_cksum(pchar m, int len); ++static void slic_if_stop_queue(struct adapter *adapter); ++static void slic_if_start_queue(struct adapter *adapter); ++static int slic_if_init(struct adapter *adapter); ++static int slic_adapter_allocresources(struct adapter *adapter); ++static void slic_adapter_freeresources(struct adapter *adapter); ++static void slic_link_config(struct adapter *adapter, u32 linkspeed, ++ u32 linkduplex); ++static void slic_unmap_mmio_space(struct adapter *adapter); ++static void slic_card_cleanup(struct sliccard *card); ++static void slic_init_cleanup(struct adapter *adapter); ++static void slic_soft_reset(struct adapter *adapter); ++static void slic_card_reset(struct adapter *adapter); ++static bool slic_mac_filter(struct adapter *adapter, ++ struct ether_header *ether_frame); ++static void slic_mac_address_config(struct adapter *adapter); ++static void slic_mac_config(struct adapter *adapter); ++static void slic_mcast_set_mask(struct adapter *adapter); ++static int slic_mcast_add_list(struct adapter *adapter, char *address); ++static unsigned char slic_mcast_get_mac_hash(char *macaddr); ++static void slic_mcast_set_bit(struct adapter *adapter, char *address); ++static void slic_config_set(struct adapter *adapter, bool linkchange); ++static void slic_config_clear(struct adapter *adapter); ++static void slic_config_get(struct adapter *adapter, u32 config, ++ u32 configh); ++static void slic_timer_get_stats(ulong device); ++static void slic_timer_load_check(ulong context); ++static void slic_timer_ping(ulong dev); ++static void slic_assert_fail(void); ++static ushort slic_eeprom_cksum(char *m, int len); + /* upr */ +-void slic_upr_start(p_adapter_t adapter); +-void slic_link_upr_complete(p_adapter_t adapter, ulong32 Isr); +-int slic_upr_request(p_adapter_t adapter, +- ulong32 upr_request, +- ulong32 upr_data, +- ulong32 upr_data_h, +- ulong32 upr_buffer, +- ulong32 upr_buffer_h); +-int slic_upr_queue_request(p_adapter_t adapter, +- ulong32 upr_request, +- ulong32 upr_data, +- ulong32 upr_data_h, +- ulong32 upr_buffer, +- ulong32 upr_buffer_h); +-void slic_mcast_set_list(struct net_device *dev); +-void slic_mcast_init_crc32(void); ++static void slic_upr_start(struct adapter *adapter); ++static void slic_link_upr_complete(struct adapter *adapter, u32 Isr); ++static int slic_upr_request(struct adapter *adapter, ++ u32 upr_request, ++ u32 upr_data, ++ u32 upr_data_h, ++ u32 upr_buffer, ++ u32 upr_buffer_h); ++static int slic_upr_queue_request(struct adapter *adapter, ++ u32 upr_request, ++ u32 upr_data, ++ u32 upr_data_h, ++ u32 upr_buffer, ++ u32 upr_buffer_h); ++static void slic_mcast_set_list(struct net_device *dev); ++static void slic_mcast_init_crc32(void); + + #if SLIC_DUMP_ENABLED +-int slic_dump_thread(void *context); +-uint slic_init_dump_thread(p_sliccard_t card); +-uchar slic_get_dump_index(pchar path); +-ulong32 slic_dump_card(p_sliccard_t card, boolean resume); +-ulong32 slic_dump_halt(p_sliccard_t card, uchar proc); +-ulong32 slic_dump_reg(p_sliccard_t card, uchar proc); +-ulong32 slic_dump_data(p_sliccard_t card, ulong32 addr, +- ushort count, uchar desc); +-ulong32 slic_dump_queue(p_sliccard_t card, ulong32 buf_phys, +- ulong32 buf_physh, ulong32 queue); +-ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue); +-ulong32 slic_dump_cam(p_sliccard_t card, ulong32 addr, +- ulong32 count, uchar desc); ++static int slic_dump_thread(void *context); ++static uint slic_init_dump_thread(struct sliccard *card); ++static unsigned char slic_get_dump_index(char *path); ++static u32 slic_dump_card(struct sliccard *card, bool resume); ++static u32 slic_dump_halt(struct sliccard *card, unsigned char proc); ++static u32 slic_dump_reg(struct sliccard *card, unsigned char proc); ++static u32 slic_dump_data(struct sliccard *card, u32 addr, ++ ushort count, unsigned char desc); ++static u32 slic_dump_queue(struct sliccard *card, u32 buf_phys, ++ u32 buf_physh, u32 queue); ++static u32 slic_dump_load_queue(struct sliccard *card, u32 data, ++ u32 queue); ++static u32 slic_dump_cam(struct sliccard *card, u32 addr, ++ u32 count, unsigned char desc); + +-ulong32 slic_dump_resume(p_sliccard_t card, uchar proc); +-ulong32 slic_dump_send_cmd(p_sliccard_t card, ulong32 cmd_phys, +- ulong32 cmd_physh, ulong32 buf_phys, +- ulong32 buf_physh); ++static u32 slic_dump_resume(struct sliccard *card, unsigned char proc); ++static u32 slic_dump_send_cmd(struct sliccard *card, u32 cmd_phys, ++ u32 cmd_physh, u32 buf_phys, ++ u32 buf_physh); + + #define create_file(x) STATUS_SUCCESS + #define write_file(w, x, y, z) STATUS_SUCCESS +diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c +index a8c2648..eb61565 100644 +--- a/drivers/staging/slicoss/slicoss.c ++++ b/drivers/staging/slicoss/slicoss.c +@@ -143,7 +143,7 @@ static int slic_debug = 1; + static int debug = -1; + static struct net_device *head_netdevice; + +-base_driver_t slic_global = { {}, 0, 0, 0, 1, NULL, NULL }; ++static struct base_driver slic_global = { {}, 0, 0, 0, 1, NULL, NULL }; + static int intagg_delay = 100; + static u32 dynamic_intagg; + static int errormsg; +@@ -183,44 +183,49 @@ MODULE_DEVICE_TABLE(pci, slic_pci_tbl); + + #define SLIC_GET_SLIC_HANDLE(_adapter, _pslic_handle) \ + { \ +- SLIC_ACQUIRE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++ spin_lock_irqsave(&_adapter->handle_lock.lock, \ ++ _adapter->handle_lock.flags); \ + _pslic_handle = _adapter->pfree_slic_handles; \ + if (_pslic_handle) { \ + ASSERT(_pslic_handle->type == SLIC_HANDLE_FREE); \ + _adapter->pfree_slic_handles = _pslic_handle->next; \ + } \ +- SLIC_RELEASE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++ spin_unlock_irqrestore(&_adapter->handle_lock.lock, \ ++ _adapter->handle_lock.flags); \ + } + + #define SLIC_FREE_SLIC_HANDLE(_adapter, _pslic_handle) \ + { \ + _pslic_handle->type = SLIC_HANDLE_FREE; \ +- SLIC_ACQUIRE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++ spin_lock_irqsave(&_adapter->handle_lock.lock, \ ++ _adapter->handle_lock.flags); \ + _pslic_handle->next = _adapter->pfree_slic_handles; \ + _adapter->pfree_slic_handles = _pslic_handle; \ +- SLIC_RELEASE_IRQ_SPINLOCK(_adapter->handle_lock); \ ++ spin_unlock_irqrestore(&_adapter->handle_lock.lock, \ ++ _adapter->handle_lock.flags); \ + } + + static void slic_debug_init(void); + static void slic_debug_cleanup(void); +-static void slic_debug_adapter_create(p_adapter_t adapter); +-static void slic_debug_adapter_destroy(p_adapter_t adapter); +-static void slic_debug_card_create(p_sliccard_t card); +-static void slic_debug_card_destroy(p_sliccard_t card); ++static void slic_debug_adapter_create(struct adapter *adapter); ++static void slic_debug_adapter_destroy(struct adapter *adapter); ++static void slic_debug_card_create(struct sliccard *card); ++static void slic_debug_card_destroy(struct sliccard *card); + +-inline void slic_reg32_write(void __iomem *reg, ulong32 value, uint flush) ++static inline void slic_reg32_write(void __iomem *reg, u32 value, uint flush) + { + writel(value, reg); + if (flush) + mb(); + } + +-inline void slic_reg64_write(p_adapter_t adapter, ++static inline void slic_reg64_write(struct adapter *adapter, + void __iomem *reg, +- ulong32 value, +- void __iomem *regh, ulong32 paddrh, uint flush) ++ u32 value, ++ void __iomem *regh, u32 paddrh, uint flush) + { +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock); ++ spin_lock_irqsave(&adapter->bit64reglock.lock, ++ adapter->bit64reglock.flags); + if (paddrh != adapter->curaddrupper) { + adapter->curaddrupper = paddrh; + writel(paddrh, regh); +@@ -228,31 +233,22 @@ inline void slic_reg64_write(p_adapter_t adapter, + writel(value, reg); + if (flush) + mb(); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock); ++ spin_unlock_irqrestore(&adapter->bit64reglock.lock, ++ adapter->bit64reglock.flags); + } + +-inline ulong32 slic_reg32_read(u32 __iomem *reg, uint flush) +-{ +- return readl(reg); +-} +- +-inline ulong32 slic_reg16_read(pulong32 reg, uint flush) +-{ +- return (ushort) readw(reg); +-} +- +-void slic_init_driver(void) ++static void slic_init_driver(void) + { + if (slic_first_init) { + DBG_MSG("slicoss: %s slic_first_init set jiffies[%lx]\n", + __func__, jiffies); + slic_first_init = 0; +- SLIC_INIT_SPINLOCK(slic_global.driver_lock); ++ spin_lock_init(&slic_global.driver_lock.lock); + slic_debug_init(); + } + } + +-static void slic_dbg_macaddrs(p_adapter_t adapter) ++static void slic_dbg_macaddrs(struct adapter *adapter) + { + DBG_MSG(" (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + adapter->netdev->name, adapter->currmacaddr[0], +@@ -267,7 +263,8 @@ static void slic_dbg_macaddrs(p_adapter_t adapter) + } + + #ifdef DEBUG_REGISTER_TRACE +-static void slic_dbg_register_trace(p_adapter_t adapter, p_sliccard_t card) ++static void slic_dbg_register_trace(struct adapter *adapter, ++ struct sliccard *card) + { + uint i; + +@@ -287,9 +284,8 @@ static void slic_init_adapter(struct net_device *netdev, + void __iomem *memaddr, int chip_idx) + { + ushort index; +- pslic_handle_t pslic_handle; +- p_adapter_t adapter = (p_adapter_t) netdev_priv(netdev); +- ++ struct slic_handle *pslic_handle; ++ struct adapter *adapter = (struct adapter *)netdev_priv(netdev); + /* + DBG_MSG("slicoss: %s (%s)\n netdev [%p]\n adapter[%p]\n " + "pcidev [%p]\n", __func__, netdev->name, netdev, adapter, pcidev);*/ +@@ -301,7 +297,7 @@ static void slic_init_adapter(struct net_device *netdev, + adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F); + adapter->functionnumber = (pcidev->devfn & 0x7); + adapter->memorylength = pci_resource_len(pcidev, 0); +- adapter->slic_regs = (p_slic_regs_t) memaddr; ++ adapter->slic_regs = (__iomem struct slic_regs *)memaddr; + adapter->irq = pcidev->irq; + /* adapter->netdev = netdev;*/ + adapter->next_netdevice = head_netdevice; +@@ -310,11 +306,11 @@ static void slic_init_adapter(struct net_device *netdev, + adapter->port = 0; /*adapter->functionnumber;*/ + adapter->cardindex = adapter->port; + adapter->memorybase = memaddr; +- SLIC_INIT_SPINLOCK(adapter->upr_lock); +- SLIC_INIT_SPINLOCK(adapter->bit64reglock); +- SLIC_INIT_SPINLOCK(adapter->adapter_lock); +- SLIC_INIT_SPINLOCK(adapter->reset_lock); +- SLIC_INIT_SPINLOCK(adapter->handle_lock); ++ spin_lock_init(&adapter->upr_lock.lock); ++ spin_lock_init(&adapter->bit64reglock.lock); ++ spin_lock_init(&adapter->adapter_lock.lock); ++ spin_lock_init(&adapter->reset_lock.lock); ++ spin_lock_init(&adapter->handle_lock.lock); + + adapter->card_size = 1; + /* +@@ -335,36 +331,36 @@ static void slic_init_adapter(struct net_device *netdev, + /* + DBG_MSG(".........\nix[%d] phandle[%p] pfree[%p] next[%p]\n", + index, pslic_handle, adapter->pfree_slic_handles, pslic_handle->next);*/ +- adapter->pshmem = (p_slic_shmem_t) pci_alloc_consistent(adapter->pcidev, +- sizeof +- (slic_shmem_t), +- &adapter-> +- phys_shmem); ++ adapter->pshmem = (struct slic_shmem *) ++ pci_alloc_consistent(adapter->pcidev, ++ sizeof(struct slic_shmem *), ++ &adapter-> ++ phys_shmem); + /* + DBG_MSG("slicoss: %s (%s)\n pshmem [%p]\n phys_shmem[%p]\n"\ + "slic_regs [%p]\n", __func__, netdev->name, adapter->pshmem, +- (pvoid)adapter->phys_shmem, adapter->slic_regs); ++ (void *)adapter->phys_shmem, adapter->slic_regs); + */ + ASSERT(adapter->pshmem); + +- SLIC_ZERO_MEMORY(adapter->pshmem, sizeof(slic_shmem_t)); ++ memset(adapter->pshmem, 0, sizeof(struct slic_shmem)); + + return; + } + +-int __devinit slic_entry_probe(struct pci_dev *pcidev, ++static int __devinit slic_entry_probe(struct pci_dev *pcidev, + const struct pci_device_id *pci_tbl_entry) + { + static int cards_found; + static int did_version; + int err; + struct net_device *netdev; +- p_adapter_t adapter; ++ struct adapter *adapter; + void __iomem *memmapped_ioaddr = NULL; +- ulong32 status = 0; ++ u32 status = 0; + ulong mmio_start = 0; + ulong mmio_len = 0; +- p_sliccard_t card = NULL; ++ struct sliccard *card = NULL; + + DBG_MSG("slicoss: %s 2.6 VERSION ENTER jiffies[%lx] cpu %d\n", + __func__, jiffies, smp_processor_id()); +@@ -408,7 +404,7 @@ int __devinit slic_entry_probe(struct pci_dev *pcidev, + pci_set_master(pcidev); + + DBG_MSG("call alloc_etherdev\n"); +- netdev = alloc_etherdev(sizeof(adapter_t)); ++ netdev = alloc_etherdev(sizeof(struct adapter)); + if (!netdev) { + err = -ENOMEM; + goto err_out_exit_slic_probe; +@@ -428,7 +424,7 @@ int __devinit slic_entry_probe(struct pci_dev *pcidev, + DBG_MSG("slicoss: call ioremap(mmio_start[%lx], mmio_len[%lx])\n", + mmio_start, mmio_len); + +-/* memmapped_ioaddr = (ulong32)ioremap_nocache(mmio_start, mmio_len);*/ ++/* memmapped_ioaddr = (u32)ioremap_nocache(mmio_start, mmio_len);*/ + memmapped_ioaddr = ioremap(mmio_start, mmio_len); + DBG_MSG("slicoss: %s MEMMAPPED_IOADDR [%p]\n", __func__, + memmapped_ioaddr); +@@ -530,11 +526,11 @@ err_out_exit_slic_probe: + return -ENODEV; + } + +-int slic_entry_open(struct net_device *dev) ++static int slic_entry_open(struct net_device *dev) + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- p_sliccard_t card = adapter->card; +- ulong32 locked = 0; ++ struct adapter *adapter = (struct adapter *) netdev_priv(dev); ++ struct sliccard *card = adapter->card; ++ u32 locked = 0; + int status; + + ASSERT(adapter); +@@ -552,7 +548,8 @@ int slic_entry_open(struct net_device *dev) + + netif_stop_queue(adapter->netdev); + +- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_lock_irqsave(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + locked = 1; + if (!adapter->activated) { + card->adapters_activated++; +@@ -568,7 +565,8 @@ int slic_entry_open(struct net_device *dev) + adapter->activated = 0; + } + if (locked) { +- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_unlock_irqrestore(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + locked = 0; + } + return status; +@@ -583,7 +581,8 @@ int slic_entry_open(struct net_device *dev) + #endif + + if (locked) { +- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_unlock_irqrestore(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + locked = 0; + } + #if SLIC_DUMP_ENABLED +@@ -599,13 +598,13 @@ int slic_entry_open(struct net_device *dev) + return STATUS_SUCCESS; + } + +-void __devexit slic_entry_remove(struct pci_dev *pcidev) ++static void __devexit slic_entry_remove(struct pci_dev *pcidev) + { + struct net_device *dev = pci_get_drvdata(pcidev); +- ulong32 mmio_start = 0; ++ u32 mmio_start = 0; + uint mmio_len = 0; +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- p_sliccard_t card; ++ struct adapter *adapter = (struct adapter *) netdev_priv(dev); ++ struct sliccard *card; + + ASSERT(adapter); + DBG_MSG("slicoss: %s ENTER dev[%p] adapter[%p]\n", __func__, dev, +@@ -635,7 +634,7 @@ void __devexit slic_entry_remove(struct pci_dev *pcidev) + __func__, card->adapters_activated, card->adapters_allocated, + card, adapter); + if (!card->adapters_allocated) { +- p_sliccard_t curr_card = slic_global.slic_card; ++ struct sliccard *curr_card = slic_global.slic_card; + if (curr_card == card) { + slic_global.slic_card = card->next; + } else { +@@ -649,17 +648,18 @@ void __devexit slic_entry_remove(struct pci_dev *pcidev) + slic_card_cleanup(card); + } + DBG_MSG("slicoss: %s deallocate device\n", __func__); +- SLIC_DEALLOCATE_MEM(dev); ++ kfree(dev); + DBG_MSG("slicoss: %s EXIT\n", __func__); + } + +-int slic_entry_halt(struct net_device *dev) ++static int slic_entry_halt(struct net_device *dev) + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- p_sliccard_t card = adapter->card; +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ struct adapter *adapter = (struct adapter *)netdev_priv(dev); ++ struct sliccard *card = adapter->card; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + +- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_lock_irqsave(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + ASSERT(card); + DBG_MSG("slicoss: %s (%s) ENTER\n", __func__, dev->name); + DBG_MSG("slicoss: %s (%s) actvtd[%d] alloc[%d] state[%x] adapt[%p]\n", +@@ -730,11 +730,12 @@ int slic_entry_halt(struct net_device *dev) + + DBG_MSG("slicoss: %s (%s) EXIT\n", __func__, dev->name); + DBG_MSG("slicoss: %s EXIT\n", __func__); +- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_unlock_irqrestore(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + return STATUS_SUCCESS; + } + +-int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + { + ASSERT(rq); + /* +@@ -743,9 +744,10 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + switch (cmd) { + case SIOCSLICSETINTAGG: + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- ulong32 data[7]; +- ulong32 intagg; ++ struct adapter *adapter = (struct adapter *) ++ netdev_priv(dev); ++ u32 data[7]; ++ u32 intagg; + + if (copy_from_user(data, rq->ifr_data, 28)) { + DBG_ERROR +@@ -763,8 +765,9 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + #ifdef SLIC_USER_REQUEST_DUMP_ENABLED + case SIOCSLICDUMPCARD: + { +- p_adapter_t adapter = (p_adapter_t) dev->priv; +- p_sliccard_t card; ++ struct adapter *adapter = (struct adapter *) ++ dev->priv; ++ struct sliccard *card; + + ASSERT(adapter); + ASSERT(adapter->card) +@@ -833,7 +836,8 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + #if SLIC_ETHTOOL_SUPPORT + case SIOCETHTOOL: + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct adapter *adapter = (struct adapter *) ++ netdev_priv(dev); + struct ethtool_cmd data; + struct ethtool_cmd ecmd; + +@@ -892,8 +896,8 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + data.maxrxpkt = 1; + if ((ecmd.speed != data.speed) || + (ecmd.duplex != data.duplex)) { +- ulong32 speed; +- ulong32 duplex; ++ u32 speed; ++ u32 duplex; + + if (ecmd.speed == SPEED_10) { + speed = 0; +@@ -935,10 +939,10 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + #define XMIT_FAIL_ZERO_LENGTH 2 + #define XMIT_FAIL_HOSTCMD_FAIL 3 + +-static void slic_xmit_build_request(p_adapter_t adapter, +- p_slic_hostcmd_t hcmd, struct sk_buff *skb) ++static void slic_xmit_build_request(struct adapter *adapter, ++ struct slic_hostcmd *hcmd, struct sk_buff *skb) + { +- p_slic_host64_cmd_t ihcmd; ++ struct slic_host64_cmd *ihcmd; + ulong phys_addr; + + ihcmd = &hcmd->cmd64; +@@ -946,16 +950,17 @@ static void slic_xmit_build_request(p_adapter_t adapter, + ihcmd->flags = (adapter->port << IHFLG_IFSHFT); + ihcmd->command = IHCMD_XMT_REQ; + ihcmd->u.slic_buffers.totlen = skb->len; +- phys_addr = SLIC_GET_DMA_ADDRESS_WRITE(adapter, skb->data, skb->len); ++ phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); + ihcmd->u.slic_buffers.bufs[0].paddrl = SLIC_GET_ADDR_LOW(phys_addr); + ihcmd->u.slic_buffers.bufs[0].paddrh = SLIC_GET_ADDR_HIGH(phys_addr); + ihcmd->u.slic_buffers.bufs[0].length = skb->len; + #if defined(CONFIG_X86_64) +- hcmd->cmdsize = (ulong32) ((((ulong64)&ihcmd->u.slic_buffers.bufs[1] - +- (ulong64) hcmd) + 31) >> 5); ++ hcmd->cmdsize = (u32) ((((u64)&ihcmd->u.slic_buffers.bufs[1] - ++ (u64) hcmd) + 31) >> 5); + #elif defined(CONFIG_X86) +- hcmd->cmdsize = ((((ulong32) &ihcmd->u.slic_buffers.bufs[1] - +- (ulong32) hcmd) + 31) >> 5); ++ hcmd->cmdsize = ((((u32) &ihcmd->u.slic_buffers.bufs[1] - ++ (u32) hcmd) + 31) >> 5); + #else + Stop Compilation; + #endif +@@ -963,14 +968,14 @@ static void slic_xmit_build_request(p_adapter_t adapter, + + #define NORMAL_ETHFRAME 0 + +-int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) ++static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) + { +- p_sliccard_t card; +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- p_slic_hostcmd_t hcmd = NULL; +- ulong32 status = 0; +- ulong32 skbtype = NORMAL_ETHFRAME; +- pvoid offloadcmd = NULL; ++ struct sliccard *card; ++ struct adapter *adapter = (struct adapter *)netdev_priv(dev); ++ struct slic_hostcmd *hcmd = NULL; ++ u32 status = 0; ++ u32 skbtype = NORMAL_ETHFRAME; ++ void *offloadcmd = NULL; + + card = adapter->card; + ASSERT(card); +@@ -1035,9 +1040,9 @@ xmit_fail: + goto xmit_done; + } + +-void slic_xmit_fail(p_adapter_t adapter, ++static void slic_xmit_fail(struct adapter *adapter, + struct sk_buff *skb, +- pvoid cmd, ulong32 skbtype, ulong32 status) ++ void *cmd, u32 skbtype, u32 status) + { + if (adapter->xmitq_full) + slic_if_stop_queue(adapter); +@@ -1072,31 +1077,10 @@ void slic_xmit_fail(p_adapter_t adapter, + adapter->stats.tx_dropped++; + } + +-void slic_xmit_timeout(struct net_device *dev) +-{ +- p_sliccard_t card; +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- ulong32 i; +- +- ASSERT(adapter); +- card = adapter->card; +- ASSERT(card); +- for (i = 0; i < card->card_size; i++) { +- if (card->adapter[i]) +- slic_if_stop_queue(card->adapter[i]); +- } +- if (!card->reset_in_progress) { +- DBG_ERROR +- ("%s card[%p] state[%x] adapter[%p] port[%d] state[%x]\n", +- __func__, card, card->state, adapter, adapter->port, +- adapter->state); +- slic_card_reset(adapter); +- } +-} +- +-void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf) ++static void slic_rcv_handle_error(struct adapter *adapter, ++ struct slic_rcvbuf *rcvbuf) + { +- p_slic_hddr_wds hdr = (p_slic_hddr_wds) rcvbuf->data; ++ struct slic_hddr_wds *hdr = (struct slic_hddr_wds *)rcvbuf->data; + + if (adapter->devid != SLIC_1GB_DEVICE_ID) { + if (hdr->frame_status14 & VRHSTAT_802OE) +@@ -1141,7 +1125,7 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf) + adapter->if_events.IpHlen++; + } else { + if (hdr->frame_statusGB & VGBSTAT_XPERR) { +- ulong32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT; ++ u32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT; + + if (xerr == VGBSTAT_XCSERR) + adapter->if_events.TpCsum++; +@@ -1151,7 +1135,7 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf) + adapter->if_events.TpHlen++; + } + if (hdr->frame_statusGB & VGBSTAT_NETERR) { +- ulong32 nerr = ++ u32 nerr = + (hdr-> + frame_statusGB >> VGBSTAT_NERRSHFT) & + VGBSTAT_NERRMSK; +@@ -1163,7 +1147,7 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf) + adapter->if_events.IpHlen++; + } + if (hdr->frame_statusGB & VGBSTAT_LNKERR) { +- ulong32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK; ++ u32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK; + + if (lerr == VGBSTAT_LDEARLY) + adapter->if_events.rcvearly++; +@@ -1187,17 +1171,17 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf) + #define TCP_OFFLOAD_FRAME_PUSHFLAG 0x10000000 + #define M_FAST_PATH 0x0040 + +-void slic_rcv_handler(p_adapter_t adapter) ++static void slic_rcv_handler(struct adapter *adapter) + { + struct sk_buff *skb; +- p_slic_rcvbuf_t rcvbuf; +- ulong32 frames = 0; ++ struct slic_rcvbuf *rcvbuf; ++ u32 frames = 0; + + while ((skb = slic_rcvqueue_getnext(adapter))) { +- ulong32 rx_bytes; ++ u32 rx_bytes; + + ASSERT(skb->head); +- rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ rcvbuf = (struct slic_rcvbuf *)skb->head; + adapter->card->events++; + if (rcvbuf->status & IRHDDR_ERR) { + adapter->rx_errors++; +@@ -1206,7 +1190,8 @@ void slic_rcv_handler(p_adapter_t adapter) + continue; + } + +- if (!slic_mac_filter(adapter, (p_ether_header) rcvbuf->data)) { ++ if (!slic_mac_filter(adapter, (struct ether_header *) ++ rcvbuf->data)) { + #if 0 + DBG_MSG + ("slicoss: %s (%s) drop frame due to mac filter\n", +@@ -1239,12 +1224,12 @@ void slic_rcv_handler(p_adapter_t adapter) + adapter->max_isr_rcvs = max(adapter->max_isr_rcvs, frames); + } + +-void slic_xmit_complete(p_adapter_t adapter) ++static void slic_xmit_complete(struct adapter *adapter) + { +- p_slic_hostcmd_t hcmd; +- p_slic_rspbuf_t rspbuf; +- ulong32 frames = 0; +- slic_handle_word_t slic_handle_word; ++ struct slic_hostcmd *hcmd; ++ struct slic_rspbuf *rspbuf; ++ u32 frames = 0; ++ struct slic_handle_word slic_handle_word; + + do { + rspbuf = slic_rspqueue_getnext(adapter); +@@ -1259,10 +1244,10 @@ void slic_xmit_complete(p_adapter_t adapter) + ASSERT(slic_handle_word.handle_index); + ASSERT(slic_handle_word.handle_index <= SLIC_CMDQ_MAXCMDS); + hcmd = +- (p_slic_hostcmd_t) adapter->slic_handles[slic_handle_word. +- handle_index]. +- address; +-/* hcmd = (p_slic_hostcmd_t) rspbuf->hosthandle; */ ++ (struct slic_hostcmd *) ++ adapter->slic_handles[slic_handle_word.handle_index]. ++ address; ++/* hcmd = (struct slic_hostcmd *) rspbuf->hosthandle; */ + ASSERT(hcmd); + ASSERT(hcmd->pslic_handle == + &adapter->slic_handles[slic_handle_word.handle_index]); +@@ -1286,9 +1271,9 @@ void slic_xmit_complete(p_adapter_t adapter) + + static irqreturn_t slic_interrupt(int irq, void *dev_id) + { +- struct net_device *dev = (struct net_device *) dev_id; +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +- ulong32 isr; ++ struct net_device *dev = (struct net_device *)dev_id; ++ struct adapter *adapter = (struct adapter *)netdev_priv(dev); ++ u32 isr; + + if ((adapter->pshmem) && (adapter->pshmem->isr)) { + WRITE_REG(adapter->slic_regs->slic_icr, ICR_INT_MASK, FLUSH); +@@ -1305,7 +1290,7 @@ static irqreturn_t slic_interrupt(int irq, void *dev_id) + int pre_count; + int errors; + +- p_slic_rcvqueue_t rcvq = ++ struct slic_rcvqueue *rcvq = + &adapter->rcvqueue; + + adapter-> +@@ -1400,17 +1385,17 @@ static irqreturn_t slic_interrupt(int irq, void *dev_id) + * will also complete asynchronously. + * + */ +-void slic_link_event_handler(p_adapter_t adapter) ++static void slic_link_event_handler(struct adapter *adapter) + { + int status; +- p_slic_shmem_t pshmem; ++ struct slic_shmem *pshmem; + + if (adapter->state != ADAPT_UP) { + /* Adapter is not operational. Ignore. */ + return; + } + +- pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ pshmem = (struct slic_shmem *)adapter->phys_shmem; + + #if defined(CONFIG_X86_64) + /* +@@ -1425,7 +1410,7 @@ void slic_link_event_handler(p_adapter_t adapter) + 0, 0); + #elif defined(CONFIG_X86) + status = slic_upr_request(adapter, SLIC_UPR_RLSR, +- (ulong32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */ ++ (u32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */ + 0, 0, 0); + #else + Stop compilation; +@@ -1433,7 +1418,7 @@ void slic_link_event_handler(p_adapter_t adapter) + ASSERT((status == STATUS_SUCCESS) || (status == STATUS_PENDING)); + } + +-void slic_init_cleanup(p_adapter_t adapter) ++static void slic_init_cleanup(struct adapter *adapter) + { + DBG_MSG("slicoss: %s ENTER adapter[%p] ", __func__, adapter); + if (adapter->intrregistered) { +@@ -1445,9 +1430,9 @@ void slic_init_cleanup(p_adapter_t adapter) + if (adapter->pshmem) { + DBG_MSG("FREE_SHMEM "); + DBG_MSG("adapter[%p] port %d pshmem[%p] FreeShmem ", +- adapter, adapter->port, (pvoid) adapter->pshmem); ++ adapter, adapter->port, (void *) adapter->pshmem); + pci_free_consistent(adapter->pcidev, +- sizeof(slic_shmem_t), ++ sizeof(struct slic_shmem *), + adapter->pshmem, adapter->phys_shmem); + adapter->pshmem = NULL; + adapter->phys_shmem = (dma_addr_t) NULL; +@@ -1475,9 +1460,9 @@ void slic_init_cleanup(p_adapter_t adapter) + } + + #if SLIC_GET_STATS_ENABLED +-struct net_device_stats *slic_get_stats(struct net_device *dev) ++static struct net_device_stats *slic_get_stats(struct net_device *dev) + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct adapter *adapter = (struct adapter *)netdev_priv(dev); + struct net_device_stats *stats; + + ASSERT(adapter); +@@ -1500,10 +1485,10 @@ struct net_device_stats *slic_get_stats(struct net_device *dev) + * Allocate a mcast_address structure to hold the multicast address. + * Link it in. + */ +-int slic_mcast_add_list(p_adapter_t adapter, pchar address) ++static int slic_mcast_add_list(struct adapter *adapter, char *address) + { +- p_mcast_address_t mcaddr, mlist; +- boolean equaladdr; ++ struct mcast_address *mcaddr, *mlist; ++ bool equaladdr; + + /* Check to see if it already exists */ + mlist = adapter->mcastaddrs; +@@ -1515,7 +1500,7 @@ int slic_mcast_add_list(p_adapter_t adapter, pchar address) + } + + /* Doesn't already exist. Allocate a structure to hold it */ +- mcaddr = SLIC_ALLOCATE_MEM(sizeof(mcast_address_t), GFP_ATOMIC); ++ mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC); + if (mcaddr == NULL) + return 1; + +@@ -1545,10 +1530,10 @@ static u32 slic_crc_init; /* Is table initialized */ + /* + * Contruct the CRC32 table + */ +-void slic_mcast_init_crc32(void) ++static void slic_mcast_init_crc32(void) + { +- ulong32 c; /* CRC shit reg */ +- ulong32 e = 0; /* Poly X-or pattern */ ++ u32 c; /* CRC shit reg */ ++ u32 e = 0; /* Poly X-or pattern */ + int i; /* counter */ + int k; /* byte being shifted into crc */ + +@@ -1568,12 +1553,12 @@ void slic_mcast_init_crc32(void) + /* + * Return the MAC hast as described above. + */ +-uchar slic_mcast_get_mac_hash(pchar macaddr) ++static unsigned char slic_mcast_get_mac_hash(char *macaddr) + { +- ulong32 crc; +- pchar p; ++ u32 crc; ++ char *p; + int i; +- uchar machash = 0; ++ unsigned char machash = 0; + + if (!slic_crc_init) { + slic_mcast_init_crc32(); +@@ -1591,9 +1576,9 @@ uchar slic_mcast_get_mac_hash(pchar macaddr) + return machash; + } + +-void slic_mcast_set_bit(p_adapter_t adapter, pchar address) ++static void slic_mcast_set_bit(struct adapter *adapter, char *address) + { +- uchar crcpoly; ++ unsigned char crcpoly; + + /* Get the CRC polynomial for the mac address */ + crcpoly = slic_mcast_get_mac_hash(address); +@@ -1604,22 +1589,22 @@ void slic_mcast_set_bit(p_adapter_t adapter, pchar address) + crcpoly &= 0x3F; + + /* OR in the new bit into our 64 bit mask. */ +- adapter->mcastmask |= (ulong64) 1 << crcpoly; ++ adapter->mcastmask |= (u64) 1 << crcpoly; + } + +-void slic_mcast_set_list(struct net_device *dev) ++static void slic_mcast_set_list(struct net_device *dev) + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct adapter *adapter = (struct adapter *)netdev_priv(dev); + int status = STATUS_SUCCESS; + int i; +- pchar addresses; ++ char *addresses; + struct dev_mc_list *mc_list = dev->mc_list; + int mc_count = dev->mc_count; + + ASSERT(adapter); + + for (i = 1; i <= mc_count; i++) { +- addresses = (pchar) &mc_list->dmi_addr; ++ addresses = (char *) &mc_list->dmi_addr; + if (mc_list->dmi_addrlen == 6) { + status = slic_mcast_add_list(adapter, addresses); + if (status != STATUS_SUCCESS) +@@ -1657,9 +1642,9 @@ void slic_mcast_set_list(struct net_device *dev) + return; + } + +-void slic_mcast_set_mask(p_adapter_t adapter) ++static void slic_mcast_set_mask(struct adapter *adapter) + { +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + + DBG_MSG("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__, + adapter->netdev->name, (uint) adapter->macopts, +@@ -1687,20 +1672,20 @@ void slic_mcast_set_mask(p_adapter_t adapter) + ((ulong) ((adapter->mcastmask >> 32) & 0xFFFFFFFF))); + + WRITE_REG(slic_regs->slic_mcastlow, +- (ulong32) (adapter->mcastmask & 0xFFFFFFFF), FLUSH); ++ (u32) (adapter->mcastmask & 0xFFFFFFFF), FLUSH); + WRITE_REG(slic_regs->slic_mcasthigh, +- (ulong32) ((adapter->mcastmask >> 32) & 0xFFFFFFFF), ++ (u32) ((adapter->mcastmask >> 32) & 0xFFFFFFFF), + FLUSH); + } + } + +-void slic_timer_ping(ulong dev) ++static void slic_timer_ping(ulong dev) + { +- p_adapter_t adapter; +- p_sliccard_t card; ++ struct adapter *adapter; ++ struct sliccard *card; + + ASSERT(dev); +- adapter = (p_adapter_t) ((struct net_device *) dev)->priv; ++ adapter = (struct adapter *)((struct net_device *) dev)->priv; + ASSERT(adapter); + card = adapter->card; + ASSERT(card); +@@ -1741,12 +1726,12 @@ void slic_timer_ping(ulong dev) + add_timer(&adapter->pingtimer); + } + +-void slic_if_stop_queue(p_adapter_t adapter) ++static void slic_if_stop_queue(struct adapter *adapter) + { + netif_stop_queue(adapter->netdev); + } + +-void slic_if_start_queue(p_adapter_t adapter) ++static void slic_if_start_queue(struct adapter *adapter) + { + netif_start_queue(adapter->netdev); + } +@@ -1757,12 +1742,12 @@ void slic_if_start_queue(p_adapter_t adapter) + * Perform initialization of our slic interface. + * + */ +-int slic_if_init(p_adapter_t adapter) ++static int slic_if_init(struct adapter *adapter) + { +- p_sliccard_t card = adapter->card; ++ struct sliccard *card = adapter->card; + struct net_device *dev = adapter->netdev; +- p_slic_regs_t slic_regs = adapter->slic_regs; +- p_slic_shmem_t pshmem; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; ++ struct slic_shmem *pshmem; + int status = 0; + + ASSERT(card); +@@ -1829,12 +1814,13 @@ int slic_if_init(p_adapter_t adapter) + DBG_MSG("slicoss: %s disable interrupts(slic)\n", __func__); + + WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); +- slic_stall_msec(1); ++ mdelay(1); + + if (!adapter->isp_initialized) { +- pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ pshmem = (struct slic_shmem *)adapter->phys_shmem; + +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock); ++ spin_lock_irqsave(&adapter->bit64reglock.lock, ++ adapter->bit64reglock.flags); + + #if defined(CONFIG_X86_64) + WRITE_REG(slic_regs->slic_addr_upper, +@@ -1842,12 +1828,13 @@ int slic_if_init(p_adapter_t adapter) + WRITE_REG(slic_regs->slic_isp, + SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH); + #elif defined(CONFIG_X86) +- WRITE_REG(slic_regs->slic_addr_upper, (ulong32) 0, DONT_FLUSH); +- WRITE_REG(slic_regs->slic_isp, (ulong32) &pshmem->isr, FLUSH); ++ WRITE_REG(slic_regs->slic_addr_upper, (u32) 0, DONT_FLUSH); ++ WRITE_REG(slic_regs->slic_isp, (u32) &pshmem->isr, FLUSH); + #else + Stop Compilations + #endif +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock); ++ spin_unlock_irqrestore(&adapter->bit64reglock.lock, ++ adapter->bit64reglock.flags); + adapter->isp_initialized = 1; + } + +@@ -1908,7 +1895,7 @@ int slic_if_init(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-void slic_unmap_mmio_space(p_adapter_t adapter) ++static void slic_unmap_mmio_space(struct adapter *adapter) + { + #if LINUX_FREES_ADAPTER_RESOURCES + if (adapter->slic_regs) +@@ -1917,7 +1904,7 @@ void slic_unmap_mmio_space(p_adapter_t adapter) + #endif + } + +-int slic_adapter_allocresources(p_adapter_t adapter) ++static int slic_adapter_allocresources(struct adapter *adapter) + { + if (!adapter->intrregistered) { + int retval; +@@ -1929,14 +1916,16 @@ int slic_adapter_allocresources(p_adapter_t adapter) + (void *)adapter->phys_shmem, adapter->netdev->irq, + NR_IRQS); + +- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_unlock_irqrestore(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + + retval = request_irq(adapter->netdev->irq, + &slic_interrupt, + IRQF_SHARED, + adapter->netdev->name, adapter->netdev); + +- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); ++ spin_lock_irqsave(&slic_global.driver_lock.lock, ++ slic_global.driver_lock.flags); + + if (retval) { + DBG_ERROR("slicoss: request_irq (%s) FAILED [%x]\n", +@@ -1953,7 +1942,7 @@ int slic_adapter_allocresources(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-void slic_config_pci(struct pci_dev *pcidev) ++static void slic_config_pci(struct pci_dev *pcidev) + { + u16 pci_command; + u16 new_command; +@@ -1972,11 +1961,11 @@ void slic_config_pci(struct pci_dev *pcidev) + } + } + +-void slic_adapter_freeresources(p_adapter_t adapter) ++static void slic_adapter_freeresources(struct adapter *adapter) + { + DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); + slic_init_cleanup(adapter); +- SLIC_ZERO_MEMORY(&adapter->stats, sizeof(struct net_device_stats)); ++ memset(&adapter->stats, 0, sizeof(struct net_device_stats)); + adapter->error_interrupts = 0; + adapter->rcv_interrupts = 0; + adapter->xmit_interrupts = 0; +@@ -1996,14 +1985,14 @@ void slic_adapter_freeresources(p_adapter_t adapter) + * Write phy control to configure link duplex/speed + * + */ +-void slic_link_config(p_adapter_t adapter, +- ulong32 linkspeed, ulong32 linkduplex) ++static void slic_link_config(struct adapter *adapter, ++ u32 linkspeed, u32 linkduplex) + { +- ulong32 speed; +- ulong32 duplex; +- ulong32 phy_config; +- ulong32 phy_advreg; +- ulong32 phy_gctlreg; ++ u32 speed; ++ u32 duplex; ++ u32 phy_config; ++ u32 phy_advreg; ++ u32 phy_gctlreg; + + if (adapter->state != ADAPT_UP) { + DBG_MSG +@@ -2052,7 +2041,7 @@ void slic_link_config(p_adapter_t adapter, + phy_config, FLUSH); + /* wait, Marvell says 1 sec, + try to get away with 10 ms */ +- slic_stall_msec(10); ++ mdelay(10); + + /* disable auto-neg, set speed/duplex, + soft reset phy, powerup */ +@@ -2140,7 +2129,7 @@ void slic_link_config(p_adapter_t adapter, + WRITE_REG(adapter->slic_regs->slic_wphy, phy_config, FLUSH); + + /* wait, Marvell says 1 sec, try to get away with 10 ms */ +- slic_stall_msec(10); ++ mdelay(10); + + if (adapter->subsysid != SLIC_1GB_CICADA_SUBSYS_ID) { + /* if a Marvell PHY +@@ -2164,24 +2153,24 @@ void slic_link_config(p_adapter_t adapter, + phy_config); + } + +-void slic_card_cleanup(p_sliccard_t card) ++static void slic_card_cleanup(struct sliccard *card) + { + DBG_MSG("slicoss: %s ENTER\n", __func__); + + #if SLIC_DUMP_ENABLED + if (card->dumpbuffer) { +- SLIC_DEALLOCATE_MEM(card->dumpbuffer); +- card->dumpbuffer = NULL; + card->dumpbuffer_phys = 0; + card->dumpbuffer_physl = 0; + card->dumpbuffer_physh = 0; ++ kfree(card->dumpbuffer); ++ card->dumpbuffer = NULL; + } + if (card->cmdbuffer) { +- SLIC_DEALLOCATE_MEM(card->cmdbuffer); +- card->cmdbuffer = NULL; + card->cmdbuffer_phys = 0; + card->cmdbuffer_physl = 0; + card->cmdbuffer_physh = 0; ++ kfree(card->cmdbuffer); ++ card->cmdbuffer = NULL; + } + #endif + +@@ -2192,24 +2181,24 @@ void slic_card_cleanup(p_sliccard_t card) + + slic_debug_card_destroy(card); + +- SLIC_DEALLOCATE_MEM(card); ++ kfree(card); + DBG_MSG("slicoss: %s EXIT\n", __func__); + } + +-static int slic_card_download_gbrcv(p_adapter_t adapter) ++static int slic_card_download_gbrcv(struct adapter *adapter) + { +- p_slic_regs_t slic_regs = adapter->slic_regs; +- ulong32 codeaddr; +- puchar instruction = NULL; +- ulong32 rcvucodelen = 0; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; ++ u32 codeaddr; ++ unsigned char *instruction = NULL; ++ u32 rcvucodelen = 0; + + switch (adapter->devid) { + case SLIC_2GB_DEVICE_ID: +- instruction = (puchar) &OasisRcvUCode[0]; ++ instruction = (unsigned char *)&OasisRcvUCode[0]; + rcvucodelen = OasisRcvUCodeLen; + break; + case SLIC_1GB_DEVICE_ID: +- instruction = (puchar) &GBRcvUCode[0]; ++ instruction = (unsigned char *)&GBRcvUCode[0]; + rcvucodelen = GBRcvUCodeLen; + break; + default: +@@ -2227,11 +2216,11 @@ static int slic_card_download_gbrcv(p_adapter_t adapter) + + /* write out the instruction data low addr */ + WRITE_REG(slic_regs->slic_rcv_wcs, +- (ulong32) *(pulong32) instruction, FLUSH); ++ (u32) *(u32 *) instruction, FLUSH); + instruction += 4; + + /* write out the instruction data high addr */ +- WRITE_REG(slic_regs->slic_rcv_wcs, (ulong32) *instruction, ++ WRITE_REG(slic_regs->slic_rcv_wcs, (u32) *instruction, + FLUSH); + instruction += 1; + } +@@ -2242,22 +2231,22 @@ static int slic_card_download_gbrcv(p_adapter_t adapter) + return 0; + } + +-int slic_card_download(p_adapter_t adapter) ++static int slic_card_download(struct adapter *adapter) + { +- ulong32 section; ++ u32 section; + int thissectionsize; + int codeaddr; +- p_slic_regs_t slic_regs = adapter->slic_regs; +- ulong32 *instruction = NULL; +- ulong32 *lastinstruct = NULL; +- ulong32 *startinstruct = NULL; +- puchar nextinstruct; +- ulong32 baseaddress; +- ulong32 failure; +- ulong32 i; +- ulong32 numsects = 0; +- ulong32 sectsize[3]; +- ulong32 sectstart[3]; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; ++ u32 *instruction = NULL; ++ u32 *lastinstruct = NULL; ++ u32 *startinstruct = NULL; ++ unsigned char *nextinstruct; ++ u32 baseaddress; ++ u32 failure; ++ u32 i; ++ u32 numsects = 0; ++ u32 sectsize[3]; ++ u32 sectstart[3]; + + /* DBG_MSG ("slicoss: %s (%s) adapter[%p] card[%p] devid[%x] \ + jiffies[%lx] cpu %d\n", __func__, adapter->netdev->name, adapter, +@@ -2292,19 +2281,19 @@ int slic_card_download(p_adapter_t adapter) + for (section = 0; section < numsects; section++) { + switch (adapter->devid) { + case SLIC_2GB_DEVICE_ID: +- instruction = (pulong32) &OasisUCode[section][0]; ++ instruction = (u32 *) &OasisUCode[section][0]; + baseaddress = sectstart[section]; + thissectionsize = sectsize[section] >> 3; + lastinstruct = +- (pulong32) &OasisUCode[section][sectsize[section] - ++ (u32 *) &OasisUCode[section][sectsize[section] - + 8]; + break; + case SLIC_1GB_DEVICE_ID: +- instruction = (pulong32) &MojaveUCode[section][0]; ++ instruction = (u32 *) &MojaveUCode[section][0]; + baseaddress = sectstart[section]; + thissectionsize = sectsize[section] >> 3; + lastinstruct = +- (pulong32) &MojaveUCode[section][sectsize[section] ++ (u32 *) &MojaveUCode[section][sectsize[section] + - 8]; + break; + default: +@@ -2317,21 +2306,21 @@ int slic_card_download(p_adapter_t adapter) + + for (codeaddr = 0; codeaddr < thissectionsize; codeaddr++) { + startinstruct = instruction; +- nextinstruct = ((puchar) instruction) + 8; ++ nextinstruct = ((unsigned char *)instruction) + 8; + /* Write out instruction address */ + WRITE_REG(slic_regs->slic_wcs, baseaddress + codeaddr, + FLUSH); + /* Write out instruction to low addr */ + WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); + #ifdef CONFIG_X86_64 +- instruction = (pulong32) ((puchar) instruction + 4); ++ instruction = (u32 *)((unsigned char *)instruction + 4); + #else + instruction++; + #endif + /* Write out instruction to high addr */ + WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); + #ifdef CONFIG_X86_64 +- instruction = (pulong32) ((puchar) instruction + 4); ++ instruction = (u32 *)((unsigned char *)instruction + 4); + #else + instruction++; + #endif +@@ -2341,10 +2330,10 @@ int slic_card_download(p_adapter_t adapter) + for (section = 0; section < numsects; section++) { + switch (adapter->devid) { + case SLIC_2GB_DEVICE_ID: +- instruction = (pulong32) &OasisUCode[section][0]; ++ instruction = (u32 *)&OasisUCode[section][0]; + break; + case SLIC_1GB_DEVICE_ID: +- instruction = (pulong32) &MojaveUCode[section][0]; ++ instruction = (u32 *)&MojaveUCode[section][0]; + break; + default: + ASSERT(0); +@@ -2367,19 +2356,19 @@ int slic_card_download(p_adapter_t adapter) + /* Write out instruction to low addr */ + WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); + #ifdef CONFIG_X86_64 +- instruction = (pulong32) ((puchar) instruction + 4); ++ instruction = (u32 *)((unsigned char *)instruction + 4); + #else + instruction++; + #endif + /* Write out instruction to high addr */ + WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH); + #ifdef CONFIG_X86_64 +- instruction = (pulong32) ((puchar) instruction + 4); ++ instruction = (u32 *)((unsigned char *)instruction + 4); + #else + instruction++; + #endif + /* Check SRAM location zero. If it is non-zero. Abort.*/ +- failure = READ_REG(slic_regs->slic_reset, 0); ++ failure = readl((u32 __iomem *)&slic_regs->slic_reset); + if (failure) { + DBG_MSG + ("slicoss: %s FAILURE EXIT codeaddr[%x] \ +@@ -2394,12 +2383,12 @@ int slic_card_download(p_adapter_t adapter) + /* DBG_MSG ("slicoss: Compare done\n");*/ + + /* Everything OK, kick off the card */ +- slic_stall_msec(10); ++ mdelay(10); + WRITE_REG(slic_regs->slic_wcs, SLIC_WCS_START, FLUSH); + + /* stall for 20 ms, long enough for ucode to init card + and reach mainloop */ +- slic_stall_msec(20); ++ mdelay(20); + + DBG_MSG("slicoss: %s (%s) EXIT adapter[%p] card[%p]\n", + __func__, adapter->netdev->name, adapter, adapter->card); +@@ -2407,9 +2396,9 @@ int slic_card_download(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-void slic_adapter_set_hwaddr(p_adapter_t adapter) ++static void slic_adapter_set_hwaddr(struct adapter *adapter) + { +- p_sliccard_t card = adapter->card; ++ struct sliccard *card = adapter->card; + + /* DBG_MSG ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", + __func__, card->config_set, adapter->port, adapter->physport, +@@ -2420,7 +2409,7 @@ void slic_adapter_set_hwaddr(p_adapter_t adapter) + if ((adapter->card) && (card->config_set)) { + memcpy(adapter->macaddr, + card->config.MacInfo[adapter->functionnumber].macaddrA, +- sizeof(slic_config_mac_t)); ++ sizeof(struct slic_config_mac)); + /* DBG_MSG ("%s AFTER copying from config.macinfo into currmacaddr\n", + __func__); + slic_dbg_macaddrs(adapter);*/ +@@ -2438,53 +2427,35 @@ void slic_adapter_set_hwaddr(p_adapter_t adapter) + slic_dbg_macaddrs(adapter); */ + } + +-void slic_card_halt(p_sliccard_t card, p_adapter_t adapter) ++static void slic_intagg_set(struct adapter *adapter, u32 value) + { +- p_slic_regs_t slic_regs = adapter->slic_regs; +- +- DBG_MSG("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x]\n", +- __func__, card, adapter, card->state); +- WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); +- adapter->all_reg_writes++; +- adapter->icr_reg_writes++; +- slic_config_clear(adapter); +- WRITE_REG(slic_regs->slic_reset_iface, 0, FLUSH); +- slic_soft_reset(adapter); +- DBG_MSG("slicoss: %s EXIT card[%p] adapter[%p] card->state[%x]\n", +- __func__, card, adapter, card->state); +- return; +- +-} +- +-void slic_intagg_set(p_adapter_t adapter, ulong32 value) +-{ +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + + WRITE_REG(slic_regs->slic_intagg, value, FLUSH); + adapter->card->loadlevel_current = value; + } + +-int slic_card_init(p_sliccard_t card, p_adapter_t adapter) ++static int slic_card_init(struct sliccard *card, struct adapter *adapter) + { +- p_slic_regs_t slic_regs = adapter->slic_regs; +- pslic_eeprom_t peeprom; +- poslic_eeprom_t pOeeprom; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; ++ struct slic_eeprom *peeprom; ++ struct oslic_eeprom *pOeeprom; + dma_addr_t phys_config; +- ulong32 phys_configh; +- ulong32 phys_configl; +- ulong32 i = 0; +- p_slic_shmem_t pshmem; ++ u32 phys_configh; ++ u32 phys_configl; ++ u32 i = 0; ++ struct slic_shmem *pshmem; + int status; + uint macaddrs = card->card_size; + ushort eecodesize; + ushort dramsize; + ushort ee_chksum; + ushort calc_chksum; +- pslic_config_mac_t pmac; +- uchar fruformat; +- uchar oemfruformat; +- patk_fru_t patkfru; +- poemfru_t poemfru; ++ struct slic_config_mac *pmac; ++ unsigned char fruformat; ++ unsigned char oemfruformat; ++ struct atk_fru *patkfru; ++ union oemfru_t *poemfru; + + DBG_MSG + ("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x] \ +@@ -2505,7 +2476,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + + if (!card->config_set) { + peeprom = pci_alloc_consistent(adapter->pcidev, +- sizeof(slic_eeprom_t), ++ sizeof(struct slic_eeprom), + &phys_config); + + phys_configl = SLIC_GET_ADDR_LOW(phys_config); +@@ -2515,8 +2486,9 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + "size [%x]\n peeprom [%p]\n " + "phys_config [%p]\n phys_configl[%x]\n " + "phys_configh[%x]\n", +- __func__, adapter, (ulong32) sizeof(slic_eeprom_t), +- peeprom, (pvoid) phys_config, phys_configl, ++ __func__, adapter, ++ (u32)sizeof(struct slic_eeprom), ++ peeprom, (void *) phys_config, phys_configl, + phys_configh); + if (!peeprom) { + DBG_ERROR +@@ -2526,17 +2498,19 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + (uint) adapter->slotnumber); + return -ENOMEM; + } else { +- SLIC_ZERO_MEMORY(peeprom, sizeof(slic_eeprom_t)); ++ memset(peeprom, 0, sizeof(struct slic_eeprom)); + } + WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH); +- slic_stall_msec(1); +- pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ mdelay(1); ++ pshmem = (struct slic_shmem *)adapter->phys_shmem; + +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock); ++ spin_lock_irqsave(&adapter->bit64reglock.lock, ++ adapter->bit64reglock.flags); + WRITE_REG(slic_regs->slic_addr_upper, 0, DONT_FLUSH); + WRITE_REG(slic_regs->slic_isp, + SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock); ++ spin_unlock_irqrestore(&adapter->bit64reglock.lock, ++ adapter->bit64reglock.flags); + + slic_config_get(adapter, phys_configl, phys_configh); + +@@ -2564,7 +2538,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + FLUSH); + } + } else { +- slic_stall_msec(1); ++ mdelay(1); + i++; + if (i > 5000) { + DBG_ERROR +@@ -2586,7 +2560,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + /* Oasis card */ + case SLIC_2GB_DEVICE_ID: + /* extract EEPROM data and pointers to EEPROM data */ +- pOeeprom = (poslic_eeprom_t) peeprom; ++ pOeeprom = (struct oslic_eeprom *) peeprom; + eecodesize = pOeeprom->EecodeSize; + dramsize = pOeeprom->DramSize; + pmac = pOeeprom->MacInfo; +@@ -2619,12 +2593,12 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + (eecodesize >= MIN_EECODE_SIZE)) { + + ee_chksum = +- *(pushort) ((pchar) peeprom + (eecodesize - 2)); ++ *(u16 *) ((char *) peeprom + (eecodesize - 2)); + /* + calculate the EEPROM checksum + */ + calc_chksum = +- ~slic_eeprom_cksum((pchar) peeprom, ++ ~slic_eeprom_cksum((char *) peeprom, + (eecodesize - 2)); + /* + if the ucdoe chksum flag bit worked, +@@ -2639,24 +2613,25 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + /* copy in the MAC address(es) */ + for (i = 0; i < macaddrs; i++) { + memcpy(&card->config.MacInfo[i], +- &pmac[i], sizeof(slic_config_mac_t)); ++ &pmac[i], sizeof(struct slic_config_mac)); + } + /* DBG_MSG ("%s EEPROM Checksum Good? %d MacAddress\n",__func__, + card->config.EepromValid); */ + + /* copy the Alacritech FRU information */ + card->config.FruFormat = fruformat; +- memcpy(&card->config.AtkFru, patkfru, sizeof(atk_fru_t)); ++ memcpy(&card->config.AtkFru, patkfru, ++ sizeof(struct atk_fru)); + + pci_free_consistent(adapter->pcidev, +- sizeof(slic_eeprom_t), ++ sizeof(struct slic_eeprom), + peeprom, phys_config); + DBG_MSG + ("slicoss: %s adapter%d [%p] size[%x] FREE peeprom[%p] \ + phys_config[%p]\n", + __func__, adapter->port, adapter, +- (ulong32) sizeof(slic_eeprom_t), peeprom, +- (pvoid) phys_config); ++ (u32) sizeof(struct slic_eeprom), peeprom, ++ (void *) phys_config); + + if ((!card->config.EepromValid) && + (adapter->reg_params.fail_on_bad_eeprom)) { +@@ -2698,8 +2673,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + + #if SLIC_DUMP_ENABLED + if (!card->dumpbuffer) { +- card->dumpbuffer = +- SLIC_ALLOCATE_MEM(DUMP_PAGE_SIZE, GFP_ATOMIC); ++ card->dumpbuffer = kmalloc(DUMP_PAGE_SIZE, GFP_ATOMIC); + + ASSERT(card->dumpbuffer); + if (card->dumpbuffer == NULL) +@@ -2709,8 +2683,8 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + * Smear the shared memory structure and then obtain + * the PHYSICAL address of this structure + */ +- SLIC_ZERO_MEMORY(card->dumpbuffer, DUMP_PAGE_SIZE); +- card->dumpbuffer_phys = SLIC_GET_PHYSICAL_ADDRESS(card->dumpbuffer); ++ memset(card->dumpbuffer, 0, DUMP_PAGE_SIZE); ++ card->dumpbuffer_phys = virt_to_bus(card->dumpbuffer); + card->dumpbuffer_physh = SLIC_GET_ADDR_HIGH(card->dumpbuffer_phys); + card->dumpbuffer_physl = SLIC_GET_ADDR_LOW(card->dumpbuffer_phys); + +@@ -2718,8 +2692,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + * Allocate COMMAND BUFFER + */ + if (!card->cmdbuffer) { +- card->cmdbuffer = +- SLIC_ALLOCATE_MEM(sizeof(dump_cmd_t), GFP_ATOMIC); ++ card->cmdbuffer = kmalloc(sizeof(dump_cmd_t), GFP_ATOMIC); + + ASSERT(card->cmdbuffer); + if (card->cmdbuffer == NULL) +@@ -2729,8 +2702,8 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + * Smear the shared memory structure and then obtain + * the PHYSICAL address of this structure + */ +- SLIC_ZERO_MEMORY(card->cmdbuffer, sizeof(dump_cmd_t)); +- card->cmdbuffer_phys = SLIC_GET_PHYSICAL_ADDRESS(card->cmdbuffer); ++ memset(card->cmdbuffer, 0, sizeof(dump_cmd_t)); ++ card->cmdbuffer_phys = virt_to_bus(card->cmdbuffer); + card->cmdbuffer_physh = SLIC_GET_ADDR_HIGH(card->cmdbuffer_phys); + card->cmdbuffer_physl = SLIC_GET_ADDR_LOW(card->cmdbuffer_phys); + #endif +@@ -2746,10 +2719,10 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-ulong32 slic_card_locate(p_adapter_t adapter) ++static u32 slic_card_locate(struct adapter *adapter) + { +- p_sliccard_t card = slic_global.slic_card; +- p_physcard_t physcard = slic_global.phys_card; ++ struct sliccard *card = slic_global.slic_card; ++ struct physcard *physcard = slic_global.phys_card; + ushort card_hostid; + u16 __iomem *hostid_reg; + uint i; +@@ -2777,13 +2750,12 @@ ulong32 slic_card_locate(p_adapter_t adapter) + DBG_MSG("slicoss: %s *hostid_reg[%p] == ", __func__, hostid_reg); + + /* read the 16 bit hostid from SRAM */ +-/* card_hostid = READ_REGP16(hostid_reg, 0);*/ + card_hostid = (ushort) readw(hostid_reg); + DBG_MSG(" card_hostid[%x]\n", card_hostid); + + /* Initialize a new card structure if need be */ + if (card_hostid == SLIC_HOSTID_DEFAULT) { +- card = kzalloc(sizeof(sliccard_t), GFP_KERNEL); ++ card = kzalloc(sizeof(struct sliccard), GFP_KERNEL); + if (card == NULL) + return -ENOMEM; + +@@ -2861,11 +2833,9 @@ ulong32 slic_card_locate(p_adapter_t adapter) + } + if (!physcard) { + /* no structure allocated for this physical card yet */ +- physcard = +- (p_physcard_t) SLIC_ALLOCATE_MEM(sizeof(physcard_t), +- GFP_ATOMIC); ++ physcard = kmalloc(sizeof(struct physcard *), GFP_ATOMIC); + ASSERT(physcard); +- SLIC_ZERO_MEMORY(physcard, sizeof(physcard_t)); ++ memset(physcard, 0, sizeof(struct physcard *)); + + DBG_MSG + ("\n%s Allocate a PHYSICALcard:\n PHYSICAL_Card[%p]\n\ +@@ -2890,130 +2860,27 @@ ulong32 slic_card_locate(p_adapter_t adapter) + return 0; + } + +-void slic_card_remaster(p_adapter_t adapter) +-{ +- p_sliccard_t card = adapter->card; +- int i; +- +- DBG_MSG("slicoss: %s card->master[%p] == adapter[%p]??\n", +- __func__, card->master, adapter); +- if (card->master != adapter) +- return; +- card->master = NULL; +- for (i = 0; i < SLIC_MAX_PORTS; i++) { +- if (card->adapter[i] && (card->adapter[i] != adapter)) { +- card->master = card->adapter[i]; +- DBG_MSG("slicoss: %s NEW MASTER SET card->master[%p]" +- " == card->adapter[%d]\n", __func__, +- card->master, i); +- break; +- } +- } +-} +- +-void slic_soft_reset(p_adapter_t adapter) ++static void slic_soft_reset(struct adapter *adapter) + { + if (adapter->card->state == CARD_UP) { + DBG_MSG("slicoss: %s QUIESCE adapter[%p] card[%p] devid[%x]\n", + __func__, adapter, adapter->card, adapter->devid); + WRITE_REG(adapter->slic_regs->slic_quiesce, 0, FLUSH); +- slic_stall_msec(1); ++ mdelay(1); + } + /* DBG_MSG ("slicoss: %s (%s) adapter[%p] card[%p] devid[%x]\n", + __func__, adapter->netdev->name, adapter, adapter->card, + adapter->devid); */ + + WRITE_REG(adapter->slic_regs->slic_reset, SLIC_RESET_MAGIC, FLUSH); +- slic_stall_msec(1); +-} +- +-void slic_card_reset(p_adapter_t adapter) +-{ +- p_sliccard_t card = adapter->card; +- p_slic_upr_t upr = adapter->upr_list; +- p_slic_upr_t upr_next = NULL; +- ulong32 i; +-#if SLIC_FAILURE_RESET +- ulong32 status = 0; +-#endif +- DBG_MSG +- ("slicoss: %s adapter[%p] port[%d] state[%x] card[%p] state[%x]\n", +- __func__, adapter, adapter->port, adapter->state, card, +- card->state); +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->adapter_lock); +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->reset_lock); +- if (card->state == CARD_DIAG) { +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock); +- return; +- } +- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock); +- card->reset_in_progress = 1; +-#if SLIC_FAILURE_RESET +- if (adapter->state != ADAPT_RESET) { +- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock); +- return; +- } +- +- adapter->state = ADAPT_DOWN; +- adapter->linkstate = LINK_DOWN; +-#endif +- if (adapter->gennumber == card->gennumber) { +- for (i = 0; i < card->card_size; i++) { +- if (card->adapter[i]) { +- if (card->adapter[i] == adapter) +- continue; +- if (card->adapter[i]->state == ADAPT_UP) { +- card->adapter[i]->state = ADAPT_RESET; +- adapter->linkstate = LINK_DOWN; +- } +- } +- } +-#if SLIC_FAILURE_RESET +- slic_soft_reset(adapter); +- card->state = CARD_DOWN; +- card->master = NULL; +- card->adapters_activated = 0; +-#endif +- card->gennumber++; +- } +- adapter->gennumber = card->gennumber; +- adapter->pshmem->isr = 0; +- adapter->isrcopy = 0; +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock); +- for (i = 0; i < card->card_size; i++) { +- if (card->adapter[i]) +- slic_cmdq_reset(card->adapter[i]); +- } +- while (upr) { +- upr_next = upr->next; +- SLIC_DEALLOCATE_MEM(upr); +- upr = upr_next; +- } +- adapter->upr_list = NULL; +- adapter->upr_busy = 0; +-#if SLIC_FAILURE_RESET +- status = slic_if_init(adapter); +- if ((status == 0) && (!card->master)) +- card->master = adapter; +- slic_mcast_set_mask(adapter); +-#endif +- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock); +- DBG_MSG +- ("slicoss: %s EXIT adapter[%p] port[%d] state[%x] card[%p] \ +- state[%x]\n", __func__, adapter, adapter->port, adapter->state, +- card, card->state); +- return; ++ mdelay(1); + } + +-void slic_config_set(p_adapter_t adapter, boolean linkchange) ++static void slic_config_set(struct adapter *adapter, bool linkchange) + { +- ulong32 value; +- ulong32 RcrReset; +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ u32 value; ++ u32 RcrReset; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + + DBG_MSG("slicoss: %s (%s) slic_interface_enable[%p](%d)\n", + __func__, adapter->netdev->name, adapter, +@@ -3075,11 +2942,11 @@ void slic_config_set(p_adapter_t adapter, boolean linkchange) + /* + * Turn off RCV and XMT, power down PHY + */ +-void slic_config_clear(p_adapter_t adapter) ++static void slic_config_clear(struct adapter *adapter) + { +- ulong32 value; +- ulong32 phy_config; +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ u32 value; ++ u32 phy_config; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + + /* Setup xmtcfg */ + value = (GXCR_RESET | /* Always reset */ +@@ -3099,28 +2966,29 @@ void slic_config_clear(p_adapter_t adapter) + WRITE_REG(slic_regs->slic_wphy, phy_config, FLUSH); + } + +-void slic_config_get(p_adapter_t adapter, ulong32 config, ulong32 config_h) ++static void slic_config_get(struct adapter *adapter, u32 config, ++ u32 config_h) + { + int status; + + status = slic_upr_request(adapter, + SLIC_UPR_RCONFIG, +- (ulong32) config, (ulong32) config_h, 0, 0); ++ (u32) config, (u32) config_h, 0, 0); + ASSERT(status == 0); + } + +-void slic_mac_address_config(p_adapter_t adapter) ++static void slic_mac_address_config(struct adapter *adapter) + { +- ulong32 value; +- ulong32 value2; +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ u32 value; ++ u32 value2; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + +- value = *(pulong32) &adapter->currmacaddr[2]; ++ value = *(u32 *) &adapter->currmacaddr[2]; + value = ntohl(value); + WRITE_REG(slic_regs->slic_wraddral, value, FLUSH); + WRITE_REG(slic_regs->slic_wraddrbl, value, FLUSH); + +- value2 = (ulong32) ((adapter->currmacaddr[0] << 8 | ++ value2 = (u32) ((adapter->currmacaddr[0] << 8 | + adapter->currmacaddr[1]) & 0xFFFF); + + WRITE_REG(slic_regs->slic_wraddrah, value2, FLUSH); +@@ -3136,10 +3004,10 @@ void slic_mac_address_config(p_adapter_t adapter) + slic_mcast_set_mask(adapter); + } + +-void slic_mac_config(p_adapter_t adapter) ++static void slic_mac_config(struct adapter *adapter) + { +- ulong32 value; +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ u32 value; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + + /* Setup GMAC gaps */ + if (adapter->linkspeed == LINK_1000MB) { +@@ -3169,12 +3037,13 @@ void slic_mac_config(p_adapter_t adapter) + slic_mac_address_config(adapter); + } + +-boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame) ++static bool slic_mac_filter(struct adapter *adapter, ++ struct ether_header *ether_frame) + { +- ulong32 opts = adapter->macopts; +- pulong32 dhost4 = (pulong32) ðer_frame->ether_dhost[0]; +- pushort dhost2 = (pushort) ðer_frame->ether_dhost[4]; +- boolean equaladdr; ++ u32 opts = adapter->macopts; ++ u32 *dhost4 = (u32 *)ðer_frame->ether_dhost[0]; ++ u16 *dhost2 = (u16 *)ðer_frame->ether_dhost[4]; ++ bool equaladdr; + + if (opts & MAC_PROMISC) { + DBG_MSG("slicoss: %s (%s) PROMISCUOUS. Accept frame\n", +@@ -3198,7 +3067,7 @@ boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame) + return TRUE; + } + if (opts & MAC_MCAST) { +- p_mcast_address_t mcaddr = adapter->mcastaddrs; ++ struct mcast_address *mcaddr = adapter->mcastaddrs; + + while (mcaddr) { + ETHER_EQ_ADDR(mcaddr->address, +@@ -3224,9 +3093,9 @@ boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame) + + } + +-int slic_mac_set_address(struct net_device *dev, pvoid ptr) ++static int slic_mac_set_address(struct net_device *dev, void *ptr) + { +- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); ++ struct adapter *adapter = (struct adapter *)netdev_priv(dev); + struct sockaddr *addr = ptr; + + DBG_MSG("%s ENTER (%s)\n", __func__, adapter->netdev->name); +@@ -3259,21 +3128,21 @@ int slic_mac_set_address(struct net_device *dev, pvoid ptr) + * 50 seconds or whatever STATS_TIMER_INTERVAL is set to. + * + */ +-void slic_timer_get_stats(ulong dev) ++static void slic_timer_get_stats(ulong dev) + { +- p_adapter_t adapter; +- p_sliccard_t card; +- p_slic_shmem_t pshmem; ++ struct adapter *adapter; ++ struct sliccard *card; ++ struct slic_shmem *pshmem; + + ASSERT(dev); +- adapter = (p_adapter_t) ((struct net_device *)dev)->priv; ++ adapter = (struct adapter *)((struct net_device *)dev)->priv; + ASSERT(adapter); + card = adapter->card; + ASSERT(card); + + if ((card->state == CARD_UP) && + (adapter->state == ADAPT_UP) && (adapter->linkstate == LINK_UP)) { +- pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ pshmem = (struct slic_shmem *)adapter->phys_shmem; + #ifdef CONFIG_X86_64 + slic_upr_request(adapter, + SLIC_UPR_STATS, +@@ -3282,7 +3151,7 @@ void slic_timer_get_stats(ulong dev) + #elif defined(CONFIG_X86) + slic_upr_request(adapter, + SLIC_UPR_STATS, +- (ulong32) &pshmem->inicstats, 0, 0, 0); ++ (u32) &pshmem->inicstats, 0, 0, 0); + #else + Stop compilation; + #endif +@@ -3295,12 +3164,12 @@ void slic_timer_get_stats(ulong dev) + add_timer(&adapter->statstimer); + } + +-void slic_timer_load_check(ulong cardaddr) ++static void slic_timer_load_check(ulong cardaddr) + { +- p_sliccard_t card = (p_sliccard_t) cardaddr; +- p_adapter_t adapter = card->master; +- ulong32 load = card->events; +- ulong32 level = 0; ++ struct sliccard *card = (struct sliccard *)cardaddr; ++ struct adapter *adapter = card->master; ++ u32 load = card->events; ++ u32 level = 0; + + if ((adapter) && (adapter->state == ADAPT_UP) && + (card->state == CARD_UP) && (slic_global.dynamic_intagg)) { +@@ -3352,36 +3221,26 @@ void slic_timer_load_check(ulong cardaddr) + add_timer(&card->loadtimer); + } + +-void slic_stall_msec(int stall) +-{ +- mdelay(stall); +-} +- +-void slic_stall_usec(int stall) +-{ +- udelay(stall); +-} +- +-void slic_assert_fail(void) ++static void slic_assert_fail(void) + { +- ulong32 cpuid; +- ulong32 curr_pid; ++ u32 cpuid; ++ u32 curr_pid; + cpuid = smp_processor_id(); + curr_pid = current->pid; + + DBG_ERROR("%s CPU # %d ---- PID # %d\n", __func__, cpuid, curr_pid); + } + +-int slic_upr_queue_request(p_adapter_t adapter, +- ulong32 upr_request, +- ulong32 upr_data, +- ulong32 upr_data_h, +- ulong32 upr_buffer, ulong32 upr_buffer_h) ++static int slic_upr_queue_request(struct adapter *adapter, ++ u32 upr_request, ++ u32 upr_data, ++ u32 upr_data_h, ++ u32 upr_buffer, u32 upr_buffer_h) + { +- p_slic_upr_t upr; +- p_slic_upr_t uprqueue; ++ struct slic_upr *upr; ++ struct slic_upr *uprqueue; + +- upr = SLIC_ALLOCATE_MEM(sizeof(slic_upr_t), GFP_ATOMIC); ++ upr = kmalloc(sizeof(struct slic_upr), GFP_ATOMIC); + if (!upr) { + DBG_MSG("%s COULD NOT ALLOCATE UPR MEM\n", __func__); + +@@ -3406,42 +3265,45 @@ int slic_upr_queue_request(p_adapter_t adapter, + return STATUS_SUCCESS; + } + +-int slic_upr_request(p_adapter_t adapter, +- ulong32 upr_request, +- ulong32 upr_data, +- ulong32 upr_data_h, +- ulong32 upr_buffer, ulong32 upr_buffer_h) ++static int slic_upr_request(struct adapter *adapter, ++ u32 upr_request, ++ u32 upr_data, ++ u32 upr_data_h, ++ u32 upr_buffer, u32 upr_buffer_h) + { + int status; + +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->upr_lock); ++ spin_lock_irqsave(&adapter->upr_lock.lock, adapter->upr_lock.flags); + status = slic_upr_queue_request(adapter, + upr_request, + upr_data, + upr_data_h, upr_buffer, upr_buffer_h); + if (status != STATUS_SUCCESS) { +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ spin_unlock_irqrestore(&adapter->upr_lock.lock, ++ adapter->upr_lock.flags); + return status; + } + slic_upr_start(adapter); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ spin_unlock_irqrestore(&adapter->upr_lock.lock, ++ adapter->upr_lock.flags); + return STATUS_PENDING; + } + +-void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr) ++static void slic_upr_request_complete(struct adapter *adapter, u32 isr) + { +- p_sliccard_t card = adapter->card; +- p_slic_upr_t upr; ++ struct sliccard *card = adapter->card; ++ struct slic_upr *upr; + + /* if (card->dump_requested) { + DBG_MSG("ENTER slic_upr_request_complete Dump in progress ISR[%x]\n", + isr); + } */ +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->upr_lock); ++ spin_lock_irqsave(&adapter->upr_lock.lock, adapter->upr_lock.flags); + upr = adapter->upr_list; + if (!upr) { + ASSERT(0); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ spin_unlock_irqrestore(&adapter->upr_lock.lock, ++ adapter->upr_lock.flags); + return; + } + adapter->upr_list = upr->next; +@@ -3452,11 +3314,11 @@ void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr) + case SLIC_UPR_STATS: + { + #if SLIC_GET_STATS_ENABLED +- p_slic_stats_t slicstats = +- (p_slic_stats_t) &adapter->pshmem->inicstats; +- p_slic_stats_t newstats = slicstats; +- p_slic_stats_t old = &adapter->inicstats_prev; +- p_slicnet_stats_t stst = &adapter->slic_stats; ++ struct slic_stats *slicstats = ++ (struct slic_stats *) &adapter->pshmem->inicstats; ++ struct slic_stats *newstats = slicstats; ++ struct slic_stats *old = &adapter->inicstats_prev; ++ struct slicnet_stats *stst = &adapter->slic_stats; + #endif + if (isr & ISR_UPCERR) { + DBG_ERROR +@@ -3540,7 +3402,7 @@ void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr) + (newstats->rcv_drops_gb - + old->rcv_drops_gb); + } +- memcpy(old, newstats, sizeof(slic_stats_t)); ++ memcpy(old, newstats, sizeof(struct slic_stats)); + #endif + break; + } +@@ -3572,15 +3434,16 @@ void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr) + default: + ASSERT(0); + } +- SLIC_DEALLOCATE_MEM(upr); ++ kfree(upr); + slic_upr_start(adapter); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock); ++ spin_unlock_irqrestore(&adapter->upr_lock.lock, ++ adapter->upr_lock.flags); + } + +-void slic_upr_start(p_adapter_t adapter) ++static void slic_upr_start(struct adapter *adapter) + { +- p_slic_upr_t upr; +- p_slic_regs_t slic_regs = adapter->slic_regs; ++ struct slic_upr *upr; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; + /* + char * ptr1; + char * ptr2; +@@ -3670,21 +3533,21 @@ void slic_upr_start(p_adapter_t adapter) + } + } + +-void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr) ++static void slic_link_upr_complete(struct adapter *adapter, u32 isr) + { +- ulong32 linkstatus = adapter->pshmem->linkstatus; ++ u32 linkstatus = adapter->pshmem->linkstatus; + uint linkup; +- uchar linkspeed; +- uchar linkduplex; ++ unsigned char linkspeed; ++ unsigned char linkduplex; + + DBG_MSG("%s: %s ISR[%x] linkstatus[%x]\n adapter[%p](%d)\n", + __func__, adapter->netdev->name, isr, linkstatus, adapter, + adapter->cardindex); + + if ((isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) { +- p_slic_shmem_t pshmem; ++ struct slic_shmem *pshmem; + +- pshmem = (p_slic_shmem_t) adapter->phys_shmem; ++ pshmem = (struct slic_shmem *)adapter->phys_shmem; + #if defined(CONFIG_X86_64) + slic_upr_queue_request(adapter, + SLIC_UPR_RLSR, +@@ -3694,7 +3557,7 @@ void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr) + #elif defined(CONFIG_X86) + slic_upr_queue_request(adapter, + SLIC_UPR_RLSR, +- (ulong32) &pshmem->linkstatus, ++ (u32) &pshmem->linkstatus, + SLIC_GET_ADDR_HIGH(pshmem), 0, 0); + #else + Stop Compilation; +@@ -3792,16 +3655,16 @@ void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr) + * which prevens us from using the ucode result. + * remove this once ucode is fixed. + */ +-ushort slic_eeprom_cksum(pchar m, int len) ++static ushort slic_eeprom_cksum(char *m, int len) + { + #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) + #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);\ + } + +- pushort w; +- ulong32 sum = 0; +- ulong32 byte_swapped = 0; +- ulong32 w_int; ++ u16 *w; ++ u32 sum = 0; ++ u32 byte_swapped = 0; ++ u32 w_int; + + union { + char c[2]; +@@ -3816,17 +3679,17 @@ ushort slic_eeprom_cksum(pchar m, int len) + l_util.l = 0; + s_util.s = 0; + +- w = (pushort) m; ++ w = (u16 *)m; + #ifdef CONFIG_X86_64 +- w_int = (ulong32) ((ulong) w & 0x00000000FFFFFFFF); ++ w_int = (u32) ((ulong) w & 0x00000000FFFFFFFF); + #else +- w_int = (ulong32) (w); ++ w_int = (u32) (w); + #endif + if ((1 & w_int) && (len > 0)) { + REDUCE; + sum <<= 8; +- s_util.c[0] = *(puchar) w; +- w = (pushort) ((char *)w + 1); ++ s_util.c[0] = *(unsigned char *)w; ++ w = (u16 *)((char *)w + 1); + len--; + byte_swapped = 1; + } +@@ -3849,7 +3712,7 @@ ushort slic_eeprom_cksum(pchar m, int len) + sum += w[13]; + sum += w[14]; + sum += w[15]; +- w = (pushort) ((ulong) w + 16); /* verify */ ++ w = (u16 *)((ulong) w + 16); /* verify */ + } + len += 32; + while ((len -= 8) >= 0) { +@@ -3857,7 +3720,7 @@ ushort slic_eeprom_cksum(pchar m, int len) + sum += w[1]; + sum += w[2]; + sum += w[3]; +- w = (pushort) ((ulong) w + 4); /* verify */ ++ w = (u16 *)((ulong) w + 4); /* verify */ + } + len += 8; + if (len != 0 || byte_swapped != 0) { +@@ -3869,7 +3732,7 @@ ushort slic_eeprom_cksum(pchar m, int len) + sum <<= 8; + byte_swapped = 0; + if (len == -1) { +- s_util.c[1] = *(pchar) w; ++ s_util.c[1] = *(char *) w; + sum += s_util.s; + len = 0; + } else { +@@ -3877,7 +3740,7 @@ ushort slic_eeprom_cksum(pchar m, int len) + } + + } else if (len == -1) { +- s_util.c[0] = *(pchar) w; ++ s_util.c[0] = *(char *) w; + } + + if (len == -1) { +@@ -3889,17 +3752,17 @@ ushort slic_eeprom_cksum(pchar m, int len) + return (ushort) sum; + } + +-int slic_rspqueue_init(p_adapter_t adapter) ++static int slic_rspqueue_init(struct adapter *adapter) + { + int i; +- p_slic_rspqueue_t rspq = &adapter->rspqueue; +- p_slic_regs_t slic_regs = adapter->slic_regs; +- ulong32 paddrh = 0; ++ struct slic_rspqueue *rspq = &adapter->rspqueue; ++ __iomem struct slic_regs *slic_regs = adapter->slic_regs; ++ u32 paddrh = 0; + + DBG_MSG("slicoss: %s (%s) ENTER adapter[%p]\n", __func__, + adapter->netdev->name, adapter); + ASSERT(adapter->state == ADAPT_DOWN); +- SLIC_ZERO_MEMORY(rspq, sizeof(slic_rspqueue_t)); ++ memset(rspq, 0, sizeof(struct slic_rspqueue)); + + rspq->num_pages = SLIC_RSPQ_PAGES_GB; + +@@ -3914,12 +3777,12 @@ int slic_rspqueue_init(p_adapter_t adapter) + return STATUS_FAILURE; + } + #ifndef CONFIG_X86_64 +- ASSERT(((ulong32) rspq->vaddr[i] & 0xFFFFF000) == +- (ulong32) rspq->vaddr[i]); +- ASSERT(((ulong32) rspq->paddr[i] & 0xFFFFF000) == +- (ulong32) rspq->paddr[i]); ++ ASSERT(((u32) rspq->vaddr[i] & 0xFFFFF000) == ++ (u32) rspq->vaddr[i]); ++ ASSERT(((u32) rspq->paddr[i] & 0xFFFFF000) == ++ (u32) rspq->paddr[i]); + #endif +- SLIC_ZERO_MEMORY(rspq->vaddr[i], PAGE_SIZE); ++ memset(rspq->vaddr[i], 0, PAGE_SIZE); + /* DBG_MSG("slicoss: %s UPLOAD RSPBUFF Page pageix[%x] paddr[%p] " + "vaddr[%p]\n", + __func__, i, (void *)rspq->paddr[i], rspq->vaddr[i]); */ +@@ -3938,15 +3801,15 @@ int slic_rspqueue_init(p_adapter_t adapter) + } + rspq->offset = 0; + rspq->pageindex = 0; +- rspq->rspbuf = (p_slic_rspbuf_t) rspq->vaddr[0]; ++ rspq->rspbuf = (struct slic_rspbuf *)rspq->vaddr[0]; + DBG_MSG("slicoss: %s (%s) EXIT adapter[%p]\n", __func__, + adapter->netdev->name, adapter); + return STATUS_SUCCESS; + } + +-int slic_rspqueue_reset(p_adapter_t adapter) ++static int slic_rspqueue_reset(struct adapter *adapter) + { +- p_slic_rspqueue_t rspq = &adapter->rspqueue; ++ struct slic_rspqueue *rspq = &adapter->rspqueue; + + DBG_MSG("slicoss: %s (%s) ENTER adapter[%p]\n", __func__, + adapter->netdev->name, adapter); +@@ -3964,10 +3827,10 @@ int slic_rspqueue_reset(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-void slic_rspqueue_free(p_adapter_t adapter) ++static void slic_rspqueue_free(struct adapter *adapter) + { + int i; +- slic_rspqueue_t *rspq = &adapter->rspqueue; ++ struct slic_rspqueue *rspq = &adapter->rspqueue; + + DBG_MSG("slicoss: %s adapter[%p] port %d rspq[%p] FreeRSPQ\n", + __func__, adapter, adapter->physport, rspq); +@@ -3976,7 +3839,7 @@ void slic_rspqueue_free(p_adapter_t adapter) + DBG_MSG + ("slicoss: pci_free_consistent rspq->vaddr[%p] \ + paddr[%p]\n", +- rspq->vaddr[i], (pvoid) rspq->paddr[i]); ++ rspq->vaddr[i], (void *) rspq->paddr[i]); + pci_free_consistent(adapter->pcidev, PAGE_SIZE, + rspq->vaddr[i], rspq->paddr[i]); + } +@@ -3988,10 +3851,10 @@ void slic_rspqueue_free(p_adapter_t adapter) + rspq->rspbuf = NULL; + } + +-p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter) ++static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter) + { +- p_slic_rspqueue_t rspq = &adapter->rspqueue; +- p_slic_rspbuf_t buf; ++ struct slic_rspqueue *rspq = &adapter->rspqueue; ++ struct slic_rspbuf *buf; + + if (!(rspq->rspbuf->status)) + return NULL; +@@ -4004,8 +3867,8 @@ p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter) + if (++rspq->offset < SLIC_RSPQ_BUFSINPAGE) { + rspq->rspbuf++; + #ifndef CONFIG_X86_64 +- ASSERT(((ulong32) rspq->rspbuf & 0xFFFFFFE0) == +- (ulong32) rspq->rspbuf); ++ ASSERT(((u32) rspq->rspbuf & 0xFFFFFFE0) == ++ (u32) rspq->rspbuf); + #endif + } else { + ASSERT(rspq->offset == SLIC_RSPQ_BUFSINPAGE); +@@ -4016,28 +3879,29 @@ p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter) + adapter->slic_regs->slic_addr_upper, 0, DONT_FLUSH); + rspq->pageindex = (++rspq->pageindex) % rspq->num_pages; + rspq->offset = 0; +- rspq->rspbuf = (p_slic_rspbuf_t) rspq->vaddr[rspq->pageindex]; ++ rspq->rspbuf = (struct slic_rspbuf *) ++ rspq->vaddr[rspq->pageindex]; + #ifndef CONFIG_X86_64 +- ASSERT(((ulong32) rspq->rspbuf & 0xFFFFF000) == +- (ulong32) rspq->rspbuf); ++ ASSERT(((u32) rspq->rspbuf & 0xFFFFF000) == ++ (u32) rspq->rspbuf); + #endif + } + #ifndef CONFIG_X86_64 +- ASSERT(((ulong32) buf & 0xFFFFFFE0) == (ulong32) buf); ++ ASSERT(((u32) buf & 0xFFFFFFE0) == (u32) buf); + #endif + return buf; + } + +-void slic_cmdqmem_init(p_adapter_t adapter) ++static void slic_cmdqmem_init(struct adapter *adapter) + { +- slic_cmdqmem_t *cmdqmem = &adapter->cmdqmem; ++ struct slic_cmdqmem *cmdqmem = &adapter->cmdqmem; + +- SLIC_ZERO_MEMORY(cmdqmem, sizeof(slic_cmdqmem_t)); ++ memset(cmdqmem, 0, sizeof(struct slic_cmdqmem)); + } + +-void slic_cmdqmem_free(p_adapter_t adapter) ++static void slic_cmdqmem_free(struct adapter *adapter) + { +- slic_cmdqmem_t *cmdqmem = &adapter->cmdqmem; ++ struct slic_cmdqmem *cmdqmem = &adapter->cmdqmem; + int i; + + DBG_MSG("slicoss: (%s) adapter[%p] port %d rspq[%p] Free CMDQ Memory\n", +@@ -4045,20 +3909,20 @@ void slic_cmdqmem_free(p_adapter_t adapter) + for (i = 0; i < SLIC_CMDQ_MAXPAGES; i++) { + if (cmdqmem->pages[i]) { + DBG_MSG("slicoss: %s Deallocate page CmdQPage[%p]\n", +- __func__, (pvoid) cmdqmem->pages[i]); ++ __func__, (void *) cmdqmem->pages[i]); + pci_free_consistent(adapter->pcidev, + PAGE_SIZE, +- (pvoid) cmdqmem->pages[i], ++ (void *) cmdqmem->pages[i], + cmdqmem->dma_pages[i]); + } + } +- SLIC_ZERO_MEMORY(cmdqmem, sizeof(slic_cmdqmem_t)); ++ memset(cmdqmem, 0, sizeof(struct slic_cmdqmem)); + } + +-pulong32 slic_cmdqmem_addpage(p_adapter_t adapter) ++static u32 *slic_cmdqmem_addpage(struct adapter *adapter) + { +- p_slic_cmdqmem_t cmdqmem = &adapter->cmdqmem; +- pulong32 pageaddr; ++ struct slic_cmdqmem *cmdqmem = &adapter->cmdqmem; ++ u32 *pageaddr; + + if (cmdqmem->pagecnt >= SLIC_CMDQ_MAXPAGES) + return NULL; +@@ -4068,32 +3932,32 @@ pulong32 slic_cmdqmem_addpage(p_adapter_t adapter) + if (!pageaddr) + return NULL; + #ifndef CONFIG_X86_64 +- ASSERT(((ulong32) pageaddr & 0xFFFFF000) == (ulong32) pageaddr); ++ ASSERT(((u32) pageaddr & 0xFFFFF000) == (u32) pageaddr); + #endif + cmdqmem->pages[cmdqmem->pagecnt] = pageaddr; + cmdqmem->pagecnt++; + return pageaddr; + } + +-int slic_cmdq_init(p_adapter_t adapter) ++static int slic_cmdq_init(struct adapter *adapter) + { + int i; +- pulong32 pageaddr; ++ u32 *pageaddr; + + DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); + ASSERT(adapter->state == ADAPT_DOWN); +- SLIC_ZERO_MEMORY(&adapter->cmdq_all, sizeof(slic_cmdqueue_t)); +- SLIC_ZERO_MEMORY(&adapter->cmdq_free, sizeof(slic_cmdqueue_t)); +- SLIC_ZERO_MEMORY(&adapter->cmdq_done, sizeof(slic_cmdqueue_t)); +- SLIC_INIT_SPINLOCK(adapter->cmdq_all.lock); +- SLIC_INIT_SPINLOCK(adapter->cmdq_free.lock); +- SLIC_INIT_SPINLOCK(adapter->cmdq_done.lock); ++ memset(&adapter->cmdq_all, 0, sizeof(struct slic_cmdqueue)); ++ memset(&adapter->cmdq_free, 0, sizeof(struct slic_cmdqueue)); ++ memset(&adapter->cmdq_done, 0, sizeof(struct slic_cmdqueue)); ++ spin_lock_init(&adapter->cmdq_all.lock.lock); ++ spin_lock_init(&adapter->cmdq_free.lock.lock); ++ spin_lock_init(&adapter->cmdq_done.lock.lock); + slic_cmdqmem_init(adapter); + adapter->slic_handle_ix = 1; + for (i = 0; i < SLIC_CMDQ_INITPAGES; i++) { + pageaddr = slic_cmdqmem_addpage(adapter); + #ifndef CONFIG_X86_64 +- ASSERT(((ulong32) pageaddr & 0xFFFFF000) == (ulong32) pageaddr); ++ ASSERT(((u32) pageaddr & 0xFFFFF000) == (u32) pageaddr); + #endif + if (!pageaddr) { + slic_cmdq_free(adapter); +@@ -4107,9 +3971,9 @@ int slic_cmdq_init(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-void slic_cmdq_free(p_adapter_t adapter) ++static void slic_cmdq_free(struct adapter *adapter) + { +- p_slic_hostcmd_t cmd; ++ struct slic_hostcmd *cmd; + + DBG_MSG("slicoss: %s adapter[%p] port %d FreeCommandsFrom CMDQ\n", + __func__, adapter, adapter->physport); +@@ -4126,21 +3990,23 @@ void slic_cmdq_free(p_adapter_t adapter) + } + cmd = cmd->next_all; + } +- SLIC_ZERO_MEMORY(&adapter->cmdq_all, sizeof(slic_cmdqueue_t)); +- SLIC_ZERO_MEMORY(&adapter->cmdq_free, sizeof(slic_cmdqueue_t)); +- SLIC_ZERO_MEMORY(&adapter->cmdq_done, sizeof(slic_cmdqueue_t)); ++ memset(&adapter->cmdq_all, 0, sizeof(struct slic_cmdqueue)); ++ memset(&adapter->cmdq_free, 0, sizeof(struct slic_cmdqueue)); ++ memset(&adapter->cmdq_done, 0, sizeof(struct slic_cmdqueue)); + slic_cmdqmem_free(adapter); + } + +-void slic_cmdq_reset(p_adapter_t adapter) ++static void slic_cmdq_reset(struct adapter *adapter) + { +- p_slic_hostcmd_t hcmd; ++ struct slic_hostcmd *hcmd; + struct sk_buff *skb; +- ulong32 outstanding; ++ u32 outstanding; + + DBG_MSG("%s ENTER adapter[%p]\n", __func__, adapter); +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->cmdq_free.lock); +- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->cmdq_done.lock); ++ spin_lock_irqsave(&adapter->cmdq_free.lock.lock, ++ adapter->cmdq_free.lock.flags); ++ spin_lock_irqsave(&adapter->cmdq_done.lock.lock, ++ adapter->cmdq_done.lock.flags); + outstanding = adapter->cmdq_all.count - adapter->cmdq_done.count; + outstanding -= adapter->cmdq_free.count; + hcmd = adapter->cmdq_all.head; +@@ -4174,31 +4040,33 @@ void slic_cmdq_reset(p_adapter_t adapter) + DBG_ERROR("%s free_count %d != all count %d\n", __func__, + adapter->cmdq_free.count, adapter->cmdq_all.count); + } +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->cmdq_done.lock); +- SLIC_RELEASE_IRQ_SPINLOCK(adapter->cmdq_free.lock); ++ spin_unlock_irqrestore(&adapter->cmdq_done.lock.lock, ++ adapter->cmdq_done.lock.flags); ++ spin_unlock_irqrestore(&adapter->cmdq_free.lock.lock, ++ adapter->cmdq_free.lock.flags); + DBG_MSG("%s EXIT adapter[%p]\n", __func__, adapter); + } + +-void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page) ++static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page) + { +- p_slic_hostcmd_t cmd; +- p_slic_hostcmd_t prev; +- p_slic_hostcmd_t tail; +- p_slic_cmdqueue_t cmdq; ++ struct slic_hostcmd *cmd; ++ struct slic_hostcmd *prev; ++ struct slic_hostcmd *tail; ++ struct slic_cmdqueue *cmdq; + int cmdcnt; +- pvoid cmdaddr; ++ void *cmdaddr; + ulong phys_addr; +- ulong32 phys_addrl; +- ulong32 phys_addrh; +- pslic_handle_t pslic_handle; ++ u32 phys_addrl; ++ u32 phys_addrh; ++ struct slic_handle *pslic_handle; + + cmdaddr = page; +- cmd = (p_slic_hostcmd_t) cmdaddr; ++ cmd = (struct slic_hostcmd *)cmdaddr; + /* DBG_MSG("CMDQ Page addr[%p] ix[%d] pfree[%p]\n", cmdaddr, slic_handle_ix, + adapter->pfree_slic_handles); */ + cmdcnt = 0; + +- phys_addr = SLIC_GET_PHYSICAL_ADDRESS((void *)page); ++ phys_addr = virt_to_bus((void *)page); + phys_addrl = SLIC_GET_ADDR_LOW(phys_addr); + phys_addrh = SLIC_GET_ADDR_HIGH(phys_addr); + +@@ -4214,7 +4082,7 @@ void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page) + &adapter->slic_handles[pslic_handle->token. + handle_index]); + pslic_handle->type = SLIC_HANDLE_CMD; +- pslic_handle->address = (pvoid) cmd; ++ pslic_handle->address = (void *) cmd; + pslic_handle->offset = (ushort) adapter->slic_handle_ix++; + pslic_handle->other_handle = NULL; + pslic_handle->next = NULL; +@@ -4230,7 +4098,7 @@ void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page) + phys_addrl += SLIC_HOSTCMD_SIZE; + cmdaddr += SLIC_HOSTCMD_SIZE; + +- cmd = (p_slic_hostcmd_t) cmdaddr; ++ cmd = (struct slic_hostcmd *)cmdaddr; + cmdcnt++; + } + +@@ -4240,36 +4108,37 @@ void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page) + ASSERT(VALID_ADDRESS(prev)); + cmdq->head = prev; + cmdq = &adapter->cmdq_free; +- SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock); ++ spin_lock_irqsave(&cmdq->lock.lock, cmdq->lock.flags); + cmdq->count += cmdcnt; /* SLIC_CMDQ_CMDSINPAGE; mooktodo */ + tail->next = cmdq->head; + ASSERT(VALID_ADDRESS(prev)); + cmdq->head = prev; +- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++ spin_unlock_irqrestore(&cmdq->lock.lock, cmdq->lock.flags); + } + +-p_slic_hostcmd_t slic_cmdq_getfree(p_adapter_t adapter) ++static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter) + { +- p_slic_cmdqueue_t cmdq = &adapter->cmdq_free; +- p_slic_hostcmd_t cmd = NULL; ++ struct slic_cmdqueue *cmdq = &adapter->cmdq_free; ++ struct slic_hostcmd *cmd = NULL; + + lock_and_retry: +- SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock); ++ spin_lock_irqsave(&cmdq->lock.lock, cmdq->lock.flags); + retry: + cmd = cmdq->head; + if (cmd) { + cmdq->head = cmd->next; + cmdq->count--; +- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++ spin_unlock_irqrestore(&cmdq->lock.lock, cmdq->lock.flags); + } else { + slic_cmdq_getdone(adapter); + cmd = cmdq->head; + if (cmd) { + goto retry; + } else { +- pulong32 pageaddr; ++ u32 *pageaddr; + +- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); ++ spin_unlock_irqrestore(&cmdq->lock.lock, ++ cmdq->lock.flags); + pageaddr = slic_cmdqmem_addpage(adapter); + if (pageaddr) { + slic_cmdq_addcmdpage(adapter, pageaddr); +@@ -4280,13 +4149,13 @@ retry: + return cmd; + } + +-void slic_cmdq_getdone(p_adapter_t adapter) ++static void slic_cmdq_getdone(struct adapter *adapter) + { +- p_slic_cmdqueue_t done_cmdq = &adapter->cmdq_done; +- p_slic_cmdqueue_t free_cmdq = &adapter->cmdq_free; ++ struct slic_cmdqueue *done_cmdq = &adapter->cmdq_done; ++ struct slic_cmdqueue *free_cmdq = &adapter->cmdq_free; + + ASSERT(free_cmdq->head == NULL); +- SLIC_ACQUIRE_IRQ_SPINLOCK(done_cmdq->lock); ++ spin_lock_irqsave(&done_cmdq->lock.lock, done_cmdq->lock.flags); + ASSERT(VALID_ADDRESS(done_cmdq->head)); + + free_cmdq->head = done_cmdq->head; +@@ -4294,28 +4163,15 @@ void slic_cmdq_getdone(p_adapter_t adapter) + done_cmdq->head = NULL; + done_cmdq->tail = NULL; + done_cmdq->count = 0; +- SLIC_RELEASE_IRQ_SPINLOCK(done_cmdq->lock); ++ spin_unlock_irqrestore(&done_cmdq->lock.lock, done_cmdq->lock.flags); + } + +-void slic_cmdq_putdone(p_adapter_t adapter, p_slic_hostcmd_t cmd) ++static void slic_cmdq_putdone_irq(struct adapter *adapter, ++ struct slic_hostcmd *cmd) + { +- p_slic_cmdqueue_t cmdq = &adapter->cmdq_done; ++ struct slic_cmdqueue *cmdq = &adapter->cmdq_done; + +- SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock); +- cmd->busy = 0; +- ASSERT(VALID_ADDRESS(cmdq->head)); +- cmd->next = cmdq->head; +- ASSERT(VALID_ADDRESS(cmd)); +- cmdq->head = cmd; +- cmdq->count++; +- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock); +-} +- +-void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd) +-{ +- p_slic_cmdqueue_t cmdq = &adapter->cmdq_done; +- +- SLIC_ACQUIRE_SPINLOCK(cmdq->lock); ++ spin_lock(&cmdq->lock.lock); + cmd->busy = 0; + ASSERT(VALID_ADDRESS(cmdq->head)); + cmd->next = cmdq->head; +@@ -4324,13 +4180,13 @@ void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd) + cmdq->count++; + if ((adapter->xmitq_full) && (cmdq->count > 10)) + netif_wake_queue(adapter->netdev); +- SLIC_RELEASE_SPINLOCK(cmdq->lock); ++ spin_unlock(&cmdq->lock.lock); + } + +-int slic_rcvqueue_init(p_adapter_t adapter) ++static int slic_rcvqueue_init(struct adapter *adapter) + { + int i, count; +- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ struct slic_rcvqueue *rcvq = &adapter->rcvqueue; + + DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); + ASSERT(adapter->state == ADAPT_DOWN); +@@ -4353,9 +4209,9 @@ int slic_rcvqueue_init(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-int slic_rcvqueue_reset(p_adapter_t adapter) ++static int slic_rcvqueue_reset(struct adapter *adapter) + { +- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ struct slic_rcvqueue *rcvq = &adapter->rcvqueue; + + DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter); + ASSERT(adapter->state == ADAPT_DOWN); +@@ -4371,9 +4227,9 @@ int slic_rcvqueue_reset(p_adapter_t adapter) + return STATUS_SUCCESS; + } + +-void slic_rcvqueue_free(p_adapter_t adapter) ++static void slic_rcvqueue_free(struct adapter *adapter) + { +- slic_rcvqueue_t *rcvq = &adapter->rcvqueue; ++ struct slic_rcvqueue *rcvq = &adapter->rcvqueue; + struct sk_buff *skb; + + while (rcvq->head) { +@@ -4386,16 +4242,16 @@ void slic_rcvqueue_free(p_adapter_t adapter) + rcvq->count = 0; + } + +-struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter) ++static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter) + { +- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ struct slic_rcvqueue *rcvq = &adapter->rcvqueue; + struct sk_buff *skb; +- p_slic_rcvbuf_t rcvbuf; ++ struct slic_rcvbuf *rcvbuf; + int count; + + if (rcvq->count) { + skb = rcvq->head; +- rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ rcvbuf = (struct slic_rcvbuf *)skb->head; + ASSERT(rcvbuf); + + if (rcvbuf->status & IRHDDR_SVALID) { +@@ -4420,30 +4276,31 @@ struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter) + return skb; + } + +-int slic_rcvqueue_fill(p_adapter_t adapter) ++static int slic_rcvqueue_fill(struct adapter *adapter) + { +- pvoid paddr; +- ulong32 paddrl; +- ulong32 paddrh; +- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; ++ void *paddr; ++ u32 paddrl; ++ u32 paddrh; ++ struct slic_rcvqueue *rcvq = &adapter->rcvqueue; + int i = 0; + + while (i < SLIC_RCVQ_FILLENTRIES) { +- p_slic_rcvbuf_t rcvbuf; ++ struct slic_rcvbuf *rcvbuf; + struct sk_buff *skb; + #ifdef KLUDGE_FOR_4GB_BOUNDARY + retry_rcvqfill: + #endif + skb = alloc_skb(SLIC_RCVQ_RCVBUFSIZE, GFP_ATOMIC); + if (skb) { +- paddr = (void *)SLIC_GET_DMA_ADDRESS_READ(adapter, ++ paddr = (void *)pci_map_single(adapter->pcidev, + skb->data, +- SLIC_RCVQ_RCVBUFSIZE); ++ SLIC_RCVQ_RCVBUFSIZE, ++ PCI_DMA_FROMDEVICE); + paddrl = SLIC_GET_ADDR_LOW(paddr); + paddrh = SLIC_GET_ADDR_HIGH(paddr); + + skb->len = SLIC_RCVBUF_HEADSIZE; +- rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ rcvbuf = (struct slic_rcvbuf *)skb->head; + rcvbuf->status = 0; + skb->next = NULL; + #ifdef KLUDGE_FOR_4GB_BOUNDARY +@@ -4479,13 +4336,13 @@ retry_rcvqfill: + #endif + if (paddrh == 0) { + WRITE_REG(adapter->slic_regs->slic_hbar, +- (ulong32) paddrl, DONT_FLUSH); ++ (u32) paddrl, DONT_FLUSH); + } else { + WRITE_REG64(adapter, + adapter->slic_regs->slic_hbar64, +- (ulong32) paddrl, ++ (u32) paddrl, + adapter->slic_regs->slic_addr_upper, +- (ulong32) paddrh, DONT_FLUSH); ++ (u32) paddrh, DONT_FLUSH); + } + if (rcvq->head) + rcvq->tail->next = skb; +@@ -4505,18 +4362,18 @@ retry_rcvqfill: + return i; + } + +-ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb) ++static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb) + { +- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue; +- pvoid paddr; +- ulong32 paddrl; +- ulong32 paddrh; +- p_slic_rcvbuf_t rcvbuf = (p_slic_rcvbuf_t) skb->head; ++ struct slic_rcvqueue *rcvq = &adapter->rcvqueue; ++ void *paddr; ++ u32 paddrl; ++ u32 paddrh; ++ struct slic_rcvbuf *rcvbuf = (struct slic_rcvbuf *)skb->head; + + ASSERT(skb->len == SLIC_RCVBUF_HEADSIZE); +- paddr = (void *)SLIC_GET_DMA_ADDRESS_READ(adapter, +- skb->head, +- SLIC_RCVQ_RCVBUFSIZE); ++ ++ paddr = (void *)pci_map_single(adapter->pcidev, skb->head, ++ SLIC_RCVQ_RCVBUFSIZE, PCI_DMA_FROMDEVICE); + rcvbuf->status = 0; + skb->next = NULL; + +@@ -4536,7 +4393,7 @@ ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb) + rcvq->count); + } + if (paddrh == 0) { +- WRITE_REG(adapter->slic_regs->slic_hbar, (ulong32) paddrl, ++ WRITE_REG(adapter->slic_regs->slic_hbar, (u32) paddrl, + DONT_FLUSH); + } else { + WRITE_REG64(adapter, +@@ -4558,10 +4415,10 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) + { + #ifdef MOOKTODO + int i; +- p_sliccard_t card = seq->private; ++ struct sliccard *card = seq->private; + pslic_config_t config = &card->config; +- puchar fru = (puchar) (&card->config.atk_fru); +- puchar oemfru = (puchar) (&card->config.OemFru); ++ unsigned char *fru = (unsigned char *)(&card->config.atk_fru); ++ unsigned char *oemfru = (unsigned char *)(&card->config.OemFru); + #endif + + seq_printf(seq, "driver_version : %s", slic_proc_version); +@@ -4600,7 +4457,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) + seq_printf(seq, " IF Init State Duplex/Speed irq\n"); + seq_printf(seq, " -------------------------------\n"); + for (i = 0; i < card->adapters_allocated; i++) { +- p_adapter_t adapter; ++ struct adapter *adapter; + + adapter = card->adapter[i]; + if (adapter) { +@@ -4768,7 +4625,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) + + static int slic_debug_adapter_show(struct seq_file *seq, void *v) + { +- p_adapter_t adapter = seq->private; ++ struct adapter *adapter = seq->private; + + if ((adapter->netdev) && (adapter->netdev->name)) { + seq_printf(seq, "info: interface : %s\n", +@@ -4801,21 +4658,21 @@ static int slic_debug_adapter_show(struct seq_file *seq, void *v) + seq_printf(seq, "rx stats: unicasts : %8.8X\n", + adapter->rcv_unicasts); + seq_printf(seq, "rx stats: errors : %8.8X\n", +- (ulong32) adapter->slic_stats.iface.rcv_errors); ++ (u32) adapter->slic_stats.iface.rcv_errors); + seq_printf(seq, "rx stats: Missed errors : %8.8X\n", +- (ulong32) adapter->slic_stats.iface.rcv_discards); ++ (u32) adapter->slic_stats.iface.rcv_discards); + seq_printf(seq, "rx stats: drops : %8.8X\n", +- (ulong32) adapter->rcv_drops); ++ (u32) adapter->rcv_drops); + seq_printf(seq, "tx stats: packets : %8.8lX\n", + adapter->stats.tx_packets); + seq_printf(seq, "tx stats: bytes : %8.8lX\n", + adapter->stats.tx_bytes); + seq_printf(seq, "tx stats: errors : %8.8X\n", +- (ulong32) adapter->slic_stats.iface.xmt_errors); ++ (u32) adapter->slic_stats.iface.xmt_errors); + seq_printf(seq, "rx stats: multicasts : %8.8lX\n", + adapter->stats.multicast); + seq_printf(seq, "tx stats: collision errors : %8.8X\n", +- (ulong32) adapter->slic_stats.iface.xmit_collisions); ++ (u32) adapter->slic_stats.iface.xmit_collisions); + seq_printf(seq, "perf: Max rcv frames/isr : %8.8X\n", + adapter->max_isr_rcvs); + seq_printf(seq, "perf: Rcv interrupt yields : %8.8X\n", +@@ -4905,11 +4762,11 @@ static const struct file_operations slic_debug_card_fops = { + .release = single_release, + }; + +-static void slic_debug_adapter_create(p_adapter_t adapter) ++static void slic_debug_adapter_create(struct adapter *adapter) + { + struct dentry *d; + char name[7]; +- p_sliccard_t card = adapter->card; ++ struct sliccard *card = adapter->card; + + if (!card->debugfs_dir) + return; +@@ -4924,7 +4781,7 @@ static void slic_debug_adapter_create(p_adapter_t adapter) + adapter->debugfs_entry = d; + } + +-static void slic_debug_adapter_destroy(p_adapter_t adapter) ++static void slic_debug_adapter_destroy(struct adapter *adapter) + { + if (adapter->debugfs_entry) { + debugfs_remove(adapter->debugfs_entry); +@@ -4932,7 +4789,7 @@ static void slic_debug_adapter_destroy(p_adapter_t adapter) + } + } + +-static void slic_debug_card_create(p_sliccard_t card) ++static void slic_debug_card_create(struct sliccard *card) + { + struct dentry *d; + char name[IFNAMSIZ]; +@@ -4955,12 +4812,12 @@ static void slic_debug_card_create(p_sliccard_t card) + } + } + +-static void slic_debug_card_destroy(p_sliccard_t card) ++static void slic_debug_card_destroy(struct sliccard *card) + { + int i; + + for (i = 0; i < card->card_size; i++) { +- p_adapter_t adapter; ++ struct adapter *adapter; + + adapter = card->adapter[i]; + if (adapter) +@@ -5013,17 +4870,17 @@ static void slic_debug_cleanup(void) + + #include + +-pvoid slic_dump_handle; /* thread handle */ ++void *slic_dump_handle; /* thread handle */ + + /* + * These are the only things you should do on a core-file: use only these + * functions to write out all the necessary info. + */ +-static int slic_dump_seek(struct file *SLIChandle, ulong32 file_offset) ++static int slic_dump_seek(struct file *SLIChandle, u32 file_offset) + { + if (SLIChandle->f_pos != file_offset) { + /*DBG_MSG("slic_dump_seek now needed [%x : %x]\n", +- (ulong32)SLIChandle->f_pos, (ulong32)file_offset); */ ++ (u32)SLIChandle->f_pos, (u32)file_offset); */ + if (SLIChandle->f_op->llseek) { + if (SLIChandle->f_op-> + llseek(SLIChandle, file_offset, 0) != file_offset) +@@ -5035,11 +4892,11 @@ static int slic_dump_seek(struct file *SLIChandle, ulong32 file_offset) + return 1; + } + +-static int slic_dump_write(p_sliccard_t card, +- const void *addr, int size, ulong32 file_offset) ++static int slic_dump_write(struct sliccard *card, ++ const void *addr, int size, u32 file_offset) + { + int r = 1; +- ulong32 result = 0; ++ u32 result = 0; + struct file *SLIChandle = card->dumphandle; + + #ifdef HISTORICAL /* legacy */ +@@ -5069,7 +4926,7 @@ static int slic_dump_write(p_sliccard_t card, + return r; + } + +-uint slic_init_dump_thread(p_sliccard_t card) ++static uint slic_init_dump_thread(struct sliccard *card) + { + card->dump_task_id = kthread_run(slic_dump_thread, (void *)card, 0); + +@@ -5082,17 +4939,17 @@ uint slic_init_dump_thread(p_sliccard_t card) + return STATUS_SUCCESS; + } + +-int slic_dump_thread(void *context) ++static int slic_dump_thread(void *context) + { +- p_sliccard_t card = (p_sliccard_t) context; +- p_adapter_t adapter; +- p_adapter_t dump_adapter = NULL; +- ulong32 dump_complete = 0; +- ulong32 delay = SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL); +- p_slic_regs_t pregs; +- ulong32 i; +- p_slic_upr_t upr, uprnext; +- ulong32 dump_card; ++ struct sliccard *card = (struct sliccard *)context; ++ struct adapter *adapter; ++ struct adapter *dump_adapter = NULL; ++ u32 dump_complete = 0; ++ u32 delay = SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL); ++ struct slic_regs *pregs; ++ u32 i; ++ struct slic_upr *upr, *uprnext; ++ u32 dump_card; + + ASSERT(card); + +@@ -5248,19 +5105,20 @@ int slic_dump_thread(void *context) + * now. + */ + if (!card->pingstatus) { +- SLIC_ACQUIRE_IRQ_SPINLOCK +- (adapter->upr_lock); ++ spin_lock_irqsave( ++ &adapter->upr_lock.lock, ++ adapter->upr_lock.flags); + upr = adapter->upr_list; + while (upr) { + uprnext = upr->next; +- SLIC_DEALLOCATE_MEM +- (upr); ++ kfree(upr); + upr = uprnext; + } + adapter->upr_list = 0; + adapter->upr_busy = 0; +- SLIC_RELEASE_IRQ_SPINLOCK +- (adapter->upr_lock); ++ spin_unlock_irqrestore( ++ &adapter->upr_lock.lock, ++ adapter->upr_lock.flags); + } + + slic_dump_card(card, FALSE); +@@ -5340,13 +5198,13 @@ end_thread: + * value is used as our suffix for our dump path. The + * value is incremented and written back to the file + */ +-uchar slic_get_dump_index(pchar path) ++static unsigned char slic_get_dump_index(char *path) + { +- uchar index = 0; ++ unsigned char index = 0; + #ifdef SLIC_DUMP_INDEX_SUPPORT +- ulong32 status; +- pvoid FileHandle; +- ulong32 offset; ++ u32 status; ++ void *FileHandle; ++ u32 offset; + + offset = 0; + +@@ -5356,7 +5214,7 @@ uchar slic_get_dump_index(pchar path) + status = create_file(&FileHandle); + + if (status != STATUS_SUCCESS) +- return (uchar) 0; ++ return (unsigned char) 0; + + status = read_file(FileHandle, &index, 1, &offset); + +@@ -5371,7 +5229,7 @@ uchar slic_get_dump_index(pchar path) + return index; + } + +-struct file *slic_dump_open_file(p_sliccard_t card) ++static struct file *slic_dump_open_file(struct sliccard *card) + { + struct file *SLIChandle = NULL; + struct dentry *dentry = NULL; +@@ -5434,7 +5292,7 @@ end_slicdump: + return NULL; + } + +-void slic_dump_close_file(p_sliccard_t card) ++static void slic_dump_close_file(struct sliccard *card) + { + + /* DBG_MSG("[slicmon] slic_dump_CLOSE_file close SLIChandle[%p]\n", +@@ -5445,19 +5303,19 @@ void slic_dump_close_file(p_sliccard_t card) + set_fs(card->dumpfile_fs); + } + +-ulong32 slic_dump_card(p_sliccard_t card, boolean resume) ++static u32 slic_dump_card(struct sliccard *card, bool resume) + { +- p_adapter_t adapter = card->master; +- ulong32 status; +- ulong32 queue; +- ulong32 len, offset; +- ulong32 sram_size, dram_size, regs; ++ struct adapter *adapter = card->master; ++ u32 status; ++ u32 queue; ++ u32 len, offset; ++ u32 sram_size, dram_size, regs; + sliccore_hdr_t corehdr; +- ulong32 file_offset; +- pchar namestr; +- ulong32 i; +- ulong32 max_queues = 0; +- ulong32 result; ++ u32 file_offset; ++ char *namestr; ++ u32 i; ++ u32 max_queues = 0; ++ u32 result; + + card->dumphandle = slic_dump_open_file(card); + +@@ -5672,12 +5530,12 @@ ulong32 slic_dump_card(p_sliccard_t card, boolean resume) + max_queues = SLIC_MAX_QUEUE; + + for (queue = 0; queue < max_queues; queue++) { +- pulong32 qarray = (pulong32) card->dumpbuffer; +- ulong32 qarray_physl = card->dumpbuffer_physl; +- ulong32 qarray_physh = card->dumpbuffer_physh; +- ulong32 qstart; +- ulong32 qdelta; +- ulong32 qtotal = 0; ++ u32 *qarray = (u32 *) card->dumpbuffer; ++ u32 qarray_physl = card->dumpbuffer_physl; ++ u32 qarray_physh = card->dumpbuffer_physh; ++ u32 qstart; ++ u32 qdelta; ++ u32 qtotal = 0; + + DBG_MSG("[slicmon] Start Dump of QUEUE #0x%x\n", (uint) queue); + +@@ -5823,9 +5681,9 @@ done: + return status; + } + +-ulong32 slic_dump_halt(p_sliccard_t card, uchar proc) ++static u32 slic_dump_halt(struct sliccard *card, unsigned char proc) + { +- puchar cmd = card->cmdbuffer; ++ unsigned char *cmd = card->cmdbuffer; + + *cmd = COMMAND_BYTE(CMD_HALT, 0, proc); + +@@ -5834,9 +5692,9 @@ ulong32 slic_dump_halt(p_sliccard_t card, uchar proc) + card->cmdbuffer_physh, 0, 0); + } + +-ulong32 slic_dump_resume(p_sliccard_t card, uchar proc) ++static u32 slic_dump_resume(struct sliccard *card, unsigned char proc) + { +- puchar cmd = card->cmdbuffer; ++ unsigned char *cmd = card->cmdbuffer; + + *cmd = COMMAND_BYTE(CMD_RUN, 0, proc); + +@@ -5845,7 +5703,7 @@ ulong32 slic_dump_resume(p_sliccard_t card, uchar proc) + card->cmdbuffer_physh, 0, 0); + } + +-ulong32 slic_dump_reg(p_sliccard_t card, uchar proc) ++static u32 slic_dump_reg(struct sliccard *card, unsigned char proc) + { + pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; + +@@ -5861,8 +5719,8 @@ ulong32 slic_dump_reg(p_sliccard_t card, uchar proc) + card->dumpbuffer_physh); + } + +-ulong32 slic_dump_data(p_sliccard_t card, +- ulong32 addr, ushort count, uchar desc) ++static u32 slic_dump_data(struct sliccard *card, ++ u32 addr, ushort count, unsigned char desc) + { + pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; + +@@ -5878,8 +5736,8 @@ ulong32 slic_dump_data(p_sliccard_t card, + card->dumpbuffer_physh); + } + +-ulong32 slic_dump_queue(p_sliccard_t card, +- ulong32 addr, ulong32 buf_physh, ulong32 queue) ++static u32 slic_dump_queue(struct sliccard *card, ++ u32 addr, u32 buf_physh, u32 queue) + { + pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; + +@@ -5894,7 +5752,8 @@ ulong32 slic_dump_queue(p_sliccard_t card, + addr, card->dumpbuffer_physh); + } + +-ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue) ++static u32 slic_dump_load_queue(struct sliccard *card, u32 data, ++ u32 queue) + { + pdump_cmd_t load = (pdump_cmd_t) card->cmdbuffer; + +@@ -5908,8 +5767,8 @@ ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue) + card->cmdbuffer_physh, 0, 0); + } + +-ulong32 slic_dump_cam(p_sliccard_t card, +- ulong32 addr, ulong32 count, uchar desc) ++static u32 slic_dump_cam(struct sliccard *card, ++ u32 addr, u32 count, unsigned char desc) + { + pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; + +@@ -5924,15 +5783,15 @@ ulong32 slic_dump_cam(p_sliccard_t card, + addr, card->dumpbuffer_physh); + } + +-ulong32 slic_dump_send_cmd(p_sliccard_t card, +- ulong32 cmd_physl, +- ulong32 cmd_physh, +- ulong32 buf_physl, ulong32 buf_physh) ++static u32 slic_dump_send_cmd(struct sliccard *card, ++ u32 cmd_physl, ++ u32 cmd_physh, ++ u32 buf_physl, u32 buf_physh) + { + ulong timeout = SLIC_MS_TO_JIFFIES(500); /* 500 msec */ +- ulong32 attempts = 5; +- ulong32 delay = SLIC_MS_TO_JIFFIES(10); /* 10 msec */ +- p_adapter_t adapter = card->master; ++ u32 attempts = 5; ++ u32 delay = SLIC_MS_TO_JIFFIES(10); /* 10 msec */ ++ struct adapter *adapter = card->master; + + ASSERT(adapter); + do { +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0020-Staging-SLICOSS-Fix-warnings-due-to-static-usage.patch b/src/patches/suse-2.6.27.31/patches.drivers/0020-Staging-SLICOSS-Fix-warnings-due-to-static-usage.patch new file mode 100644 index 000000000..8ec2b9fda --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0020-Staging-SLICOSS-Fix-warnings-due-to-static-usage.patch @@ -0,0 +1,85 @@ +From 4578ca0fc2be611ea98618b028ecfbb2415cd990 Mon Sep 17 00:00:00 2001 +From: Lior Dotan +Date: Sun, 5 Oct 2008 15:35:46 +0300 +Subject: [PATCH 20/23] Staging: SLICOSS: Fix warnings due to static usage +Patch-mainline: 2.6.28 + +Fix a few warning messages that crept in due to conversion of all the +functions to static + +Signed-off-by: Lior Dotan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/slicoss/slicinc.h | 6 ------ + drivers/staging/slicoss/slicoss.c | 3 ++- + 2 files changed, 2 insertions(+), 7 deletions(-) + +diff --git a/drivers/staging/slicoss/slicinc.h b/drivers/staging/slicoss/slicinc.h +index 610c1ab..71288c4 100644 +--- a/drivers/staging/slicoss/slicinc.h ++++ b/drivers/staging/slicoss/slicinc.h +@@ -61,7 +61,6 @@ static void slic_xmit_fail(struct adapter *adapter, + void *cmd, + u32 skbtype, + u32 status); +-static void slic_xmit_timeout(struct net_device *dev); + static void slic_config_pci(struct pci_dev *pcidev); + static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter); + +@@ -90,8 +89,6 @@ static void slic_cmdq_free(struct adapter *adapter); + static void slic_cmdq_reset(struct adapter *adapter); + static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page); + static void slic_cmdq_getdone(struct adapter *adapter); +-static void slic_cmdq_putdone(struct adapter *adapter, +- struct slic_hostcmd *cmd); + static void slic_cmdq_putdone_irq(struct adapter *adapter, + struct slic_hostcmd *cmd); + static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter); +@@ -103,7 +100,6 @@ static void slic_rcvqueue_free(struct adapter *adapter); + static void slic_rcv_handle_error(struct adapter *adapter, + struct slic_rcvbuf *rcvbuf); + static void slic_adapter_set_hwaddr(struct adapter *adapter); +-static void slic_card_halt(struct sliccard *card, struct adapter *adapter); + static int slic_card_init(struct sliccard *card, struct adapter *adapter); + static void slic_intagg_set(struct adapter *adapter, u32 value); + static int slic_card_download(struct adapter *adapter); +@@ -120,7 +116,6 @@ static void slic_unmap_mmio_space(struct adapter *adapter); + static void slic_card_cleanup(struct sliccard *card); + static void slic_init_cleanup(struct adapter *adapter); + static void slic_soft_reset(struct adapter *adapter); +-static void slic_card_reset(struct adapter *adapter); + static bool slic_mac_filter(struct adapter *adapter, + struct ether_header *ether_frame); + static void slic_mac_address_config(struct adapter *adapter); +@@ -133,7 +128,6 @@ static void slic_config_set(struct adapter *adapter, bool linkchange); + static void slic_config_clear(struct adapter *adapter); + static void slic_config_get(struct adapter *adapter, u32 config, + u32 configh); +-static void slic_timer_get_stats(ulong device); + static void slic_timer_load_check(ulong context); + static void slic_timer_ping(ulong dev); + static void slic_assert_fail(void); +diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c +index eb61565..f242477 100644 +--- a/drivers/staging/slicoss/slicoss.c ++++ b/drivers/staging/slicoss/slicoss.c +@@ -3128,6 +3128,7 @@ static int slic_mac_set_address(struct net_device *dev, void *ptr) + * 50 seconds or whatever STATS_TIMER_INTERVAL is set to. + * + */ ++#if SLIC_GET_STATS_TIMER_ENABLED + static void slic_timer_get_stats(ulong dev) + { + struct adapter *adapter; +@@ -3163,7 +3164,7 @@ static void slic_timer_get_stats(ulong dev) + SLIC_SECS_TO_JIFFS(STATS_TIMER_INTERVAL); + add_timer(&adapter->statstimer); + } +- ++#endif + static void slic_timer_load_check(ulong cardaddr) + { + struct sliccard *card = (struct sliccard *)cardaddr; +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0021-Staging-SLICOSS-Fix-remaining-type-names.patch b/src/patches/suse-2.6.27.31/patches.drivers/0021-Staging-SLICOSS-Fix-remaining-type-names.patch new file mode 100644 index 000000000..9e3342588 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0021-Staging-SLICOSS-Fix-remaining-type-names.patch @@ -0,0 +1,223 @@ +From 68cf95f3183c7bd60feab3bb774e1e4c7f36fe71 Mon Sep 17 00:00:00 2001 +From: Lior Dotan +Date: Tue, 7 Oct 2008 14:14:04 +0200 +Subject: [PATCH 21/23] Staging: SLICOSS: Fix remaining type names +Patch-mainline: 2.6.28 + +Fix the remaining variables that still had '_t' as a postfix and also +a couple of checkpatch warnings. + +Signed-off-by: Lior Dotan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/slicoss/slic_os.h | 6 ++++-- + drivers/staging/slicoss/slicdump.h | 2 +- + drivers/staging/slicoss/slichw.h | 6 +++--- + drivers/staging/slicoss/slicoss.c | 30 +++++++++++++++--------------- + 4 files changed, 23 insertions(+), 21 deletions(-) + +diff --git a/drivers/staging/slicoss/slic_os.h b/drivers/staging/slicoss/slic_os.h +index b0d2883..46c6784 100644 +--- a/drivers/staging/slicoss/slic_os.h ++++ b/drivers/staging/slicoss/slic_os.h +@@ -53,7 +53,8 @@ + { \ + adapter->card->reg_type[adapter->card->debug_ix] = 0; \ + adapter->card->reg_offset[adapter->card->debug_ix] = \ +- ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \ ++ ((unsigned char *)(®)) - \ ++ ((unsigned char *)adapter->slic_regs); \ + adapter->card->reg_value[adapter->card->debug_ix++] = value; \ + if (adapter->card->debug_ix == 32) \ + adapter->card->debug_ix = 0; \ +@@ -63,7 +64,8 @@ + { \ + adapter->card->reg_type[adapter->card->debug_ix] = 1; \ + adapter->card->reg_offset[adapter->card->debug_ix] = \ +- ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \ ++ ((unsigned char *)(®)) - \ ++ ((unsigned char *)adapter->slic_regs); \ + adapter->card->reg_value[adapter->card->debug_ix] = value; \ + adapter->card->reg_valueh[adapter->card->debug_ix++] = valh; \ + if (adapter->card->debug_ix == 32) \ +diff --git a/drivers/staging/slicoss/slicdump.h b/drivers/staging/slicoss/slicdump.h +index ca0a221..92a9b44 100644 +--- a/drivers/staging/slicoss/slicdump.h ++++ b/drivers/staging/slicoss/slicdump.h +@@ -228,7 +228,7 @@ struct CORE_Q { + #define DRIVER_NAME_SIZE 32 + + struct sliccore_hdr { +- unsigned char driver_version[DRIVER_NAME_SIZE]; /* Driver version string */ ++ unsigned char driver_version[DRIVER_NAME_SIZE]; /* Driver version string */ + u32 RcvRegOff; /* Offset of receive registers */ + u32 RcvRegsize; /* size of receive registers */ + u32 XmtRegOff; /* Offset of transmit registers */ +diff --git a/drivers/staging/slicoss/slichw.h b/drivers/staging/slicoss/slichw.h +index 4c5c15d..d03e90b 100644 +--- a/drivers/staging/slicoss/slichw.h ++++ b/drivers/staging/slicoss/slichw.h +@@ -702,7 +702,7 @@ struct vendor4_fru { + unsigned char pad[3]; + }; + +-union oemfru_t { ++union oemfru { + struct vendor1_fru vendor1_fru; + struct vendor2_fru vendor2_fru; + struct vendor3_fru vendor3_fru; +@@ -764,7 +764,7 @@ struct slic_eeprom { + unsigned char FruFormat; /* Alacritech FRU format type */ + struct atk_fru AtkFru; /* Alacritech FRU information */ + unsigned char OemFruFormat; /* optional OEM FRU format type */ +- union oemfru_t OemFru; /* optional OEM FRU information */ ++ union oemfru OemFru; /* optional OEM FRU information */ + unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes + *(if OEM FRU info exists) and two unusable + * bytes at the end */ +@@ -809,7 +809,7 @@ struct oslic_eeprom { + unsigned char FruFormat; /* 35 Alacritech FRU format type */ + struct atk_fru AtkFru; /* Alacritech FRU information */ + unsigned char OemFruFormat; /* optional OEM FRU format type */ +- union oemfru_t OemFru; /* optional OEM FRU information */ ++ union oemfru OemFru; /* optional OEM FRU information */ + unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes + * (if OEM FRU info exists) and two unusable + * bytes at the end +diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c +index f242477..c129e83 100644 +--- a/drivers/staging/slicoss/slicoss.c ++++ b/drivers/staging/slicoss/slicoss.c +@@ -1015,7 +1015,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev) + + #ifdef DEBUG_DUMP + if (adapter->kill_card) { +- p_slic_host64_cmd_t ihcmd; ++ struct slic_host64_cmd ihcmd; + + ihcmd = &hcmd->cmd64; + +@@ -2455,7 +2455,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter) + unsigned char fruformat; + unsigned char oemfruformat; + struct atk_fru *patkfru; +- union oemfru_t *poemfru; ++ union oemfru *poemfru; + + DBG_MSG + ("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x] \ +@@ -2692,7 +2692,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter) + * Allocate COMMAND BUFFER + */ + if (!card->cmdbuffer) { +- card->cmdbuffer = kmalloc(sizeof(dump_cmd_t), GFP_ATOMIC); ++ card->cmdbuffer = kmalloc(sizeof(struct dump_cmd), GFP_ATOMIC); + + ASSERT(card->cmdbuffer); + if (card->cmdbuffer == NULL) +@@ -2702,7 +2702,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter) + * Smear the shared memory structure and then obtain + * the PHYSICAL address of this structure + */ +- memset(card->cmdbuffer, 0, sizeof(dump_cmd_t)); ++ memset(card->cmdbuffer, 0, sizeof(struct dump_cmd)); + card->cmdbuffer_phys = virt_to_bus(card->cmdbuffer); + card->cmdbuffer_physh = SLIC_GET_ADDR_HIGH(card->cmdbuffer_phys); + card->cmdbuffer_physl = SLIC_GET_ADDR_LOW(card->cmdbuffer_phys); +@@ -4417,7 +4417,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) + #ifdef MOOKTODO + int i; + struct sliccard *card = seq->private; +- pslic_config_t config = &card->config; ++ struct slic_config *config = &card->config; + unsigned char *fru = (unsigned char *)(&card->config.atk_fru); + unsigned char *oemfru = (unsigned char *)(&card->config.OemFru); + #endif +@@ -5311,7 +5311,7 @@ static u32 slic_dump_card(struct sliccard *card, bool resume) + u32 queue; + u32 len, offset; + u32 sram_size, dram_size, regs; +- sliccore_hdr_t corehdr; ++ struct sliccore_hdr corehdr; + u32 file_offset; + char *namestr; + u32 i; +@@ -5344,7 +5344,7 @@ static u32 slic_dump_card(struct sliccard *card, bool resume) + } + corehdr.driver_version[i] = 0; + +- file_offset = sizeof(sliccore_hdr_t); ++ file_offset = sizeof(struct sliccore_hdr); + + /* + * Issue the following debug commands to the SLIC: +@@ -5651,10 +5651,10 @@ done: + */ + file_offset = 0; + DBG_MSG("[slicmon] Write CoreHeader len[%x] offset[%x]\n", +- (uint) sizeof(sliccore_hdr_t), file_offset); ++ (uint) sizeof(struct sliccore_hdr), file_offset); + + result = +- slic_dump_write(card, &corehdr, sizeof(sliccore_hdr_t), ++ slic_dump_write(card, &corehdr, sizeof(struct sliccore_hdr), + file_offset); + DBG_MSG("[slicmon] corehdr xoff[%x] xsz[%x]\n" + " roff[%x] rsz[%x] fileoff[%x] filesz[%x]\n" +@@ -5663,7 +5663,7 @@ done: + corehdr.XmtRegsize, corehdr.RcvRegOff, corehdr.RcvRegsize, + corehdr.FileRegOff, corehdr.FileRegsize, corehdr.SramOff, + corehdr.Sramsize, corehdr.DramOff, corehdr.Dramsize, +- (uint) sizeof(sliccore_hdr_t)); ++ (uint) sizeof(struct sliccore_hdr)); + for (i = 0; i < max_queues; i++) { + DBG_MSG("[slicmon] QUEUE 0x%x offset[%x] size[%x]\n", + (uint) i, corehdr.queues[i].queueOff, +@@ -5706,7 +5706,7 @@ static u32 slic_dump_resume(struct sliccard *card, unsigned char proc) + + static u32 slic_dump_reg(struct sliccard *card, unsigned char proc) + { +- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer; + + dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, proc); + dump->desc = DESC_REG; +@@ -5723,7 +5723,7 @@ static u32 slic_dump_reg(struct sliccard *card, unsigned char proc) + static u32 slic_dump_data(struct sliccard *card, + u32 addr, ushort count, unsigned char desc) + { +- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer; + + dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, PROC_RECEIVE); + dump->desc = desc; +@@ -5740,7 +5740,7 @@ static u32 slic_dump_data(struct sliccard *card, + static u32 slic_dump_queue(struct sliccard *card, + u32 addr, u32 buf_physh, u32 queue) + { +- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer; + + dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, PROC_RECEIVE); + dump->desc = DESC_QUEUE; +@@ -5756,7 +5756,7 @@ static u32 slic_dump_queue(struct sliccard *card, + static u32 slic_dump_load_queue(struct sliccard *card, u32 data, + u32 queue) + { +- pdump_cmd_t load = (pdump_cmd_t) card->cmdbuffer; ++ struct dump_cmd *load = (struct dump_cmd *) card->cmdbuffer; + + load->cmd = COMMAND_BYTE(CMD_LOAD, 0, PROC_RECEIVE); + load->desc = DESC_QUEUE; +@@ -5771,7 +5771,7 @@ static u32 slic_dump_load_queue(struct sliccard *card, u32 data, + static u32 slic_dump_cam(struct sliccard *card, + u32 addr, u32 count, unsigned char desc) + { +- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer; ++ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer; + + dump->cmd = COMMAND_BYTE(CMD_CAM_OPS, 0, PROC_NONE); + dump->desc = desc; +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0022-Staging-SLICOSS-Call-pci_release_regions-at-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/0022-Staging-SLICOSS-Call-pci_release_regions-at-driver.patch new file mode 100644 index 000000000..c40dea5ae --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0022-Staging-SLICOSS-Call-pci_release_regions-at-driver.patch @@ -0,0 +1,38 @@ +From f25fda728dfb5c23d1147279fc6a537451603369 Mon Sep 17 00:00:00 2001 +From: Lior Dotan +Date: Wed, 8 Oct 2008 11:37:37 +0200 +Subject: [PATCH 22/23] Staging: SLICOSS: Call pci_release_regions at driver exit +Patch-mainline: 2.6.28 + +slic_entry_probe() calls pci_request_regions() but there's no matching +pci_release_regions() at driver's exit or if slic_entry_probe() fails. + +Signed-off-by: Lior Dotan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/slicoss/slicoss.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c +index c129e83..b61ac4b 100644 +--- a/drivers/staging/slicoss/slicoss.c ++++ b/drivers/staging/slicoss/slicoss.c +@@ -520,6 +520,7 @@ err_out_free_mmio_region: + release_mem_region(mmio_start, mmio_len); + + err_out_exit_slic_probe: ++ pci_release_regions(pcidev); + DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __func__, jiffies, + smp_processor_id()); + +@@ -649,6 +650,7 @@ static void __devexit slic_entry_remove(struct pci_dev *pcidev) + } + DBG_MSG("slicoss: %s deallocate device\n", __func__); + kfree(dev); ++ pci_release_regions(pcidev); + DBG_MSG("slicoss: %s EXIT\n", __func__); + } + +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/0023-Staging-Lindent-sxg.c.patch b/src/patches/suse-2.6.27.31/patches.drivers/0023-Staging-Lindent-sxg.c.patch new file mode 100644 index 000000000..2f82da1cc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/0023-Staging-Lindent-sxg.c.patch @@ -0,0 +1,484 @@ +From 5c7514e0610249a4e7710eefd801c2b0442eb8ea Mon Sep 17 00:00:00 2001 +From: J.R. Mauro +Date: Sun, 5 Oct 2008 20:38:52 -0400 +Subject: [PATCH 23/23] Staging: Lindent sxg.c +Patch-mainline: 2.6.28 + +Lindent drivers/staging/sxg/sxg.c + +Signed-off by: J.R. Mauro +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/sxg/sxg.c | 146 +++++++++++++++++++++++++-------------------- + 1 files changed, 81 insertions(+), 65 deletions(-) + +diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c +index 0117d51..6ccbee8 100644 +--- a/drivers/staging/sxg/sxg.c ++++ b/drivers/staging/sxg/sxg.c +@@ -80,9 +80,15 @@ + #include "sxgphycode.h" + #include "saharadbgdownload.h" + +-static int sxg_allocate_buffer_memory(p_adapter_t adapter, u32 Size, SXG_BUFFER_TYPE BufferType); +-static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, void * RcvBlock, dma_addr_t PhysicalAddress, u32 Length); +-static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, PSXG_SCATTER_GATHER SxgSgl, dma_addr_t PhysicalAddress, u32 Length); ++static int sxg_allocate_buffer_memory(p_adapter_t adapter, u32 Size, ++ SXG_BUFFER_TYPE BufferType); ++static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, void *RcvBlock, ++ dma_addr_t PhysicalAddress, ++ u32 Length); ++static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, ++ PSXG_SCATTER_GATHER SxgSgl, ++ dma_addr_t PhysicalAddress, ++ u32 Length); + + static void sxg_mcast_init_crc32(void); + +@@ -100,13 +106,13 @@ static void sxg_complete_slow_send(p_adapter_t adapter); + static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event); + static void sxg_process_rcv_error(p_adapter_t adapter, u32 ErrorStatus); + static bool sxg_mac_filter(p_adapter_t adapter, +- p_ether_header EtherHdr, ushort length); ++ p_ether_header EtherHdr, ushort length); + + #if SLIC_GET_STATS_ENABLED + static struct net_device_stats *sxg_get_stats(p_net_device dev); + #endif + +-static int sxg_mac_set_address(p_net_device dev, void * ptr); ++static int sxg_mac_set_address(p_net_device dev, void *ptr); + + static void sxg_adapter_set_hwaddr(p_adapter_t adapter); + +@@ -115,20 +121,19 @@ static void sxg_mcast_set_mask(p_adapter_t adapter); + + static int sxg_initialize_adapter(p_adapter_t adapter); + static void sxg_stock_rcv_buffers(p_adapter_t adapter); +-static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char Index); ++static void sxg_complete_descriptor_blocks(p_adapter_t adapter, ++ unsigned char Index); + static int sxg_initialize_link(p_adapter_t adapter); + static int sxg_phy_init(p_adapter_t adapter); + static void sxg_link_event(p_adapter_t adapter); + static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter); + static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState); + static int sxg_write_mdio_reg(p_adapter_t adapter, +- u32 DevAddr, u32 RegAddr, u32 Value); ++ u32 DevAddr, u32 RegAddr, u32 Value); + static int sxg_read_mdio_reg(p_adapter_t adapter, +- u32 DevAddr, u32 RegAddr, u32 * pValue); ++ u32 DevAddr, u32 RegAddr, u32 *pValue); + static void sxg_mcast_set_list(p_net_device dev); + +- +- + #define XXXTODO 0 + + static unsigned int sxg_first_init = 1; +@@ -164,6 +169,7 @@ static struct pci_device_id sxg_pci_tbl[] __devinitdata = { + {PCI_DEVICE(SXG_VENDOR_ID, SXG_DEVICE_ID)}, + {0,} + }; ++ + MODULE_DEVICE_TABLE(pci, sxg_pci_tbl); + + /*********************************************************************** +@@ -242,7 +248,7 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel) + PSXG_HW_REGS HwRegs = adapter->HwRegs; + u32 Section; + u32 ThisSectionSize; +- u32 * Instruction = NULL; ++ u32 *Instruction = NULL; + u32 BaseAddress, AddressOffset, Address; + // u32 Failure; + u32 ValueRead; +@@ -606,7 +612,7 @@ static void sxg_config_pci(struct pci_dev *pcidev) + PCI_COMMAND_MASTER | // Bus master enable + PCI_COMMAND_INVALIDATE | // Memory write and invalidate + PCI_COMMAND_PARITY | // Parity error response +- PCI_COMMAND_SERR | // System ERR ++ PCI_COMMAND_SERR | // System ERR + PCI_COMMAND_FAST_BACK); // Fast back-to-back + if (pci_command != new_command) { + DBG_ERROR("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n", +@@ -695,17 +701,19 @@ static int sxg_entry_probe(struct pci_dev *pcidev, + mmio_start, mmio_len); + + memmapped_ioaddr = ioremap(mmio_start, mmio_len); +- DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __FUNCTION__, memmapped_ioaddr); ++ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __FUNCTION__, ++ memmapped_ioaddr); + if (!memmapped_ioaddr) { + DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", + __FUNCTION__, mmio_len, mmio_start); + goto err_out_free_mmio_region; + } + +- DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n", ++ DBG_ERROR ++ ("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n", + __func__, memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq); + +- adapter->HwRegs = (void *) memmapped_ioaddr; ++ adapter->HwRegs = (void *)memmapped_ioaddr; + adapter->base_addr = memmapped_ioaddr; + + mmio_start = pci_resource_start(pcidev, 2); +@@ -715,7 +723,8 @@ static int sxg_entry_probe(struct pci_dev *pcidev, + mmio_start, mmio_len); + + memmapped_ioaddr = ioremap(mmio_start, mmio_len); +- DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __func__, memmapped_ioaddr); ++ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __func__, ++ memmapped_ioaddr); + if (!memmapped_ioaddr) { + DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", + __FUNCTION__, mmio_len, mmio_start); +@@ -845,7 +854,6 @@ static int sxg_entry_probe(struct pci_dev *pcidev, + return -ENODEV; + } + +- + /*********************************************************************** + * LINE BASE Interrupt routines.. + ***********************************************************************/ +@@ -957,7 +965,8 @@ static irqreturn_t sxg_isr(int irq, void *dev_id) + PSXG_EVENT_RING EventRing = &adapter->EventRings[i]; + PSXG_EVENT Event = + &EventRing->Ring[adapter->NextEvent[i]]; +- unsigned char Cpu = adapter->RssSystemInfo->RssIdToCpu[i]; ++ unsigned char Cpu = ++ adapter->RssSystemInfo->RssIdToCpu[i]; + if (Event->Status & EVENT_STATUS_VALID) { + adapter->IsrDpcsPending++; + CpuMask |= (1 << Cpu); +@@ -1078,7 +1087,8 @@ static int sxg_process_isr(p_adapter_t adapter, u32 MessageId) + if (Isr & SXG_ISR_DEAD) { + // Set aside the crash info and set the adapter state to RESET + adapter->CrashCpu = +- (unsigned char) ((Isr & SXG_ISR_CPU) >> SXG_ISR_CPU_SHIFT); ++ (unsigned char)((Isr & SXG_ISR_CPU) >> ++ SXG_ISR_CPU_SHIFT); + adapter->CrashLocation = (ushort) (Isr & SXG_ISR_CRASH); + adapter->Dead = TRUE; + DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __FUNCTION__, +@@ -1286,7 +1296,7 @@ static void sxg_complete_slow_send(p_adapter_t adapter) + { + PSXG_XMT_RING XmtRing = &adapter->XmtRings[0]; + PSXG_RING_INFO XmtRingInfo = &adapter->XmtRingZeroInfo; +- u32 * ContextType; ++ u32 *ContextType; + PSXG_CMD XmtCmd; + + // NOTE - This lock is dropped and regrabbed in this loop. +@@ -1380,11 +1390,9 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event) + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvError", + Event, Event->Status, Event->HostHandle, 0); + // XXXTODO - Remove this print later +- DBG_ERROR("SXG: Receive error %x\n", +- *(u32 *) ++ DBG_ERROR("SXG: Receive error %x\n", *(u32 *) + SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)); +- sxg_process_rcv_error(adapter, +- *(u32 *) ++ sxg_process_rcv_error(adapter, *(u32 *) + SXG_RECEIVE_DATA_LOCATION + (RcvDataBufferHdr)); + goto drop; +@@ -1406,8 +1414,7 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event) + // + // Dumb-nic frame. See if it passes our mac filter and update stats + // +- if (!sxg_mac_filter(adapter, +- (p_ether_header) ++ if (!sxg_mac_filter(adapter, (p_ether_header) + SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), + Event->Length)) { + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr", +@@ -1527,7 +1534,8 @@ static void sxg_process_rcv_error(p_adapter_t adapter, u32 ErrorStatus) + * Return Value: + * TRUE if the frame is to be allowed + */ +-static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr, ushort length) ++static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr, ++ ushort length) + { + bool EqualAddr; + +@@ -1600,7 +1608,8 @@ static int sxg_register_interrupt(p_adapter_t adapter) + ("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x] %x\n", + __FUNCTION__, adapter, adapter->netdev->irq, NR_IRQS); + +- spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); ++ spin_unlock_irqrestore(&sxg_global.driver_lock, ++ sxg_global.flags); + + retval = request_irq(adapter->netdev->irq, + &sxg_isr, +@@ -1729,7 +1738,6 @@ static int sxg_entry_open(p_net_device dev) + sxg_global.num_sxg_ports_active++; + adapter->activated = 1; + } +- + // Initialize the adapter + DBG_ERROR("sxg: %s ENTER sxg_initialize_adapter\n", __FUNCTION__); + status = sxg_initialize_adapter(adapter); +@@ -1786,7 +1794,7 @@ static void __devexit sxg_entry_remove(struct pci_dev *pcidev) + release_mem_region(mmio_start, mmio_len); + + DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __FUNCTION__, +- (unsigned int) dev->base_addr); ++ (unsigned int)dev->base_addr); + iounmap((char *)dev->base_addr); + + DBG_ERROR("sxg: %s deallocate device\n", __FUNCTION__); +@@ -1929,7 +1937,7 @@ static int sxg_transmit_packet(p_adapter_t adapter, struct sk_buff *skb) + { + PSCATTER_GATHER_LIST pSgl; + PSXG_SCATTER_GATHER SxgSgl; +- void * SglBuffer; ++ void *SglBuffer; + u32 SglBufferLength; + + // The vast majority of work is done in the shared +@@ -2038,7 +2046,9 @@ static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl) + #endif + // Fill in the command + // Copy out the first SGE to the command and adjust for offset +- phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len, PCI_DMA_TODEVICE); ++ phys_addr = ++ pci_map_single(adapter->pcidev, skb->data, skb->len, ++ PCI_DMA_TODEVICE); + XmtCmd->Buffer.FirstSgeAddress = SXG_GET_ADDR_HIGH(phys_addr); + XmtCmd->Buffer.FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress << 32; + XmtCmd->Buffer.FirstSgeAddress = +@@ -2422,7 +2432,8 @@ static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter) + return (SXG_LINK_DOWN); + } + +-static void sxg_indicate_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState) ++static void sxg_indicate_link_state(p_adapter_t adapter, ++ SXG_LINK_STATE LinkState) + { + if (adapter->LinkState == SXG_LINK_UP) { + DBG_ERROR("%s: LINK now UP, call netif_start_queue\n", +@@ -2487,11 +2498,11 @@ static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState) + * status + */ + static int sxg_write_mdio_reg(p_adapter_t adapter, +- u32 DevAddr, u32 RegAddr, u32 Value) ++ u32 DevAddr, u32 RegAddr, u32 Value) + { + PSXG_HW_REGS HwRegs = adapter->HwRegs; + u32 AddrOp; // Address operation (written to MIIM field reg) +- u32 WriteOp; // Write operation (written to MIIM field reg) ++ u32 WriteOp; // Write operation (written to MIIM field reg) + u32 Cmd; // Command (written to MIIM command reg) + u32 ValueRead; + u32 Timeout; +@@ -2577,7 +2588,7 @@ static int sxg_write_mdio_reg(p_adapter_t adapter, + * status + */ + static int sxg_read_mdio_reg(p_adapter_t adapter, +- u32 DevAddr, u32 RegAddr, u32 * pValue) ++ u32 DevAddr, u32 RegAddr, u32 *pValue) + { + PSXG_HW_REGS HwRegs = adapter->HwRegs; + u32 AddrOp; // Address operation (written to MIIM field reg) +@@ -2698,7 +2709,7 @@ static int sxg_mcast_add_list(p_adapter_t adapter, char *address) + * we must then transpose the value and return bits 30-23. + * + */ +-static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */ ++static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */ + static u32 sxg_crc_init; /* Is table initialized */ + + /* +@@ -2706,7 +2717,7 @@ static u32 sxg_crc_init; /* Is table initialized */ + */ + static void sxg_mcast_init_crc32(void) + { +- u32 c; /* CRC shit reg */ ++ u32 c; /* CRC shit reg */ + u32 e = 0; /* Poly X-or pattern */ + int i; /* counter */ + int k; /* byte being shifted into crc */ +@@ -2783,7 +2794,7 @@ static void sxg_mcast_set_list(p_net_device dev) + ASSERT(adapter); + + for (i = 1; i <= mc_count; i++) { +- addresses = (char *) & mc_list->dmi_addr; ++ addresses = (char *)&mc_list->dmi_addr; + if (mc_list->dmi_addrlen == 6) { + status = sxg_mcast_add_list(adapter, addresses); + if (status != STATUS_SUCCESS) { +@@ -2833,7 +2844,7 @@ static void sxg_mcast_set_mask(p_adapter_t adapter) + PSXG_UCODE_REGS sxg_regs = adapter->UcodeRegs; + + DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __FUNCTION__, +- adapter->netdev->name, (unsigned int) adapter->MacFilter, ++ adapter->netdev->name, (unsigned int)adapter->MacFilter, + adapter->MulticastMask); + + if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) { +@@ -2857,12 +2868,10 @@ static void sxg_mcast_set_mask(p_adapter_t adapter) + ((adapter->MulticastMask >> 32) & 0xFFFFFFFF))); + + WRITE_REG(sxg_regs->McastLow, +- (u32) (adapter->MulticastMask & 0xFFFFFFFF), +- FLUSH); ++ (u32) (adapter->MulticastMask & 0xFFFFFFFF), FLUSH); + WRITE_REG(sxg_regs->McastHigh, + (u32) ((adapter-> +- MulticastMask >> 32) & 0xFFFFFFFF), +- FLUSH); ++ MulticastMask >> 32) & 0xFFFFFFFF), FLUSH); + } + } + +@@ -2991,9 +3000,9 @@ void SxgFreeResources(p_adapter_t adapter) + * None. + */ + static void sxg_allocate_complete(p_adapter_t adapter, +- void *VirtualAddress, +- dma_addr_t PhysicalAddress, +- u32 Length, SXG_BUFFER_TYPE Context) ++ void *VirtualAddress, ++ dma_addr_t PhysicalAddress, ++ u32 Length, SXG_BUFFER_TYPE Context) + { + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocCmp", + adapter, VirtualAddress, Length, Context); +@@ -3008,8 +3017,7 @@ static void sxg_allocate_complete(p_adapter_t adapter, + PhysicalAddress, Length); + break; + case SXG_BUFFER_TYPE_SGL: +- sxg_allocate_sgl_buffer_complete(adapter, +- (PSXG_SCATTER_GATHER) ++ sxg_allocate_sgl_buffer_complete(adapter, (PSXG_SCATTER_GATHER) + VirtualAddress, + PhysicalAddress, Length); + break; +@@ -3031,10 +3039,10 @@ static void sxg_allocate_complete(p_adapter_t adapter, + * int + */ + static int sxg_allocate_buffer_memory(p_adapter_t adapter, +- u32 Size, SXG_BUFFER_TYPE BufferType) ++ u32 Size, SXG_BUFFER_TYPE BufferType) + { + int status; +- void * Buffer; ++ void *Buffer; + dma_addr_t pBuffer; + + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocMem", +@@ -3083,8 +3091,9 @@ static int sxg_allocate_buffer_memory(p_adapter_t adapter, + * + */ + static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, +- void * RcvBlock, +- dma_addr_t PhysicalAddress, u32 Length) ++ void *RcvBlock, ++ dma_addr_t PhysicalAddress, ++ u32 Length) + { + u32 i; + u32 BufferSize = adapter->ReceiveBufferSize; +@@ -3160,9 +3169,10 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, + } + + // Locate the descriptor block and put it on a separate free queue +- RcvDescriptorBlock = (PSXG_RCV_DESCRIPTOR_BLOCK) ((unsigned char *)RcvBlock + +- SXG_RCV_DESCRIPTOR_BLOCK_OFFSET +- (BufferSize)); ++ RcvDescriptorBlock = ++ (PSXG_RCV_DESCRIPTOR_BLOCK) ((unsigned char *)RcvBlock + ++ SXG_RCV_DESCRIPTOR_BLOCK_OFFSET ++ (BufferSize)); + RcvDescriptorBlockHdr = + (PSXG_RCV_DESCRIPTOR_BLOCK_HDR) ((unsigned char *)RcvBlock + + SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET +@@ -3210,8 +3220,9 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, + * + */ + static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, +- PSXG_SCATTER_GATHER SxgSgl, +- dma_addr_t PhysicalAddress, u32 Length) ++ PSXG_SCATTER_GATHER SxgSgl, ++ dma_addr_t PhysicalAddress, ++ u32 Length) + { + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlSglCmp", + adapter, SxgSgl, Length, 0); +@@ -3228,7 +3239,8 @@ static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, + adapter, SxgSgl, Length, 0); + } + +-static unsigned char temp_mac_address[6] = { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 }; ++static unsigned char temp_mac_address[6] = ++ { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 }; + + static void sxg_adapter_set_hwaddr(p_adapter_t adapter) + { +@@ -3255,7 +3267,7 @@ static void sxg_adapter_set_hwaddr(p_adapter_t adapter) + + } + +-static int sxg_mac_set_address(p_net_device dev, void * ptr) ++static int sxg_mac_set_address(p_net_device dev, void *ptr) + { + #if XXXTODO + p_adapter_t adapter = (p_adapter_t) netdev_priv(dev); +@@ -3400,7 +3412,8 @@ static int sxg_initialize_adapter(p_adapter_t adapter) + * status + */ + static int sxg_fill_descriptor_block(p_adapter_t adapter, +- PSXG_RCV_DESCRIPTOR_BLOCK_HDR RcvDescriptorBlockHdr) ++ PSXG_RCV_DESCRIPTOR_BLOCK_HDR ++ RcvDescriptorBlockHdr) + { + u32 i; + PSXG_RING_INFO RcvRingInfo = &adapter->RcvRingZeroInfo; +@@ -3436,7 +3449,8 @@ static int sxg_fill_descriptor_block(p_adapter_t adapter, + ASSERT(RcvDataBufferHdr); + SXG_REINIATIALIZE_PACKET(RcvDataBufferHdr->SxgDumbRcvPacket); + RcvDataBufferHdr->State = SXG_BUFFER_ONCARD; +- RcvDescriptorBlock->Descriptors[i].VirtualAddress = (void *)RcvDataBufferHdr; ++ RcvDescriptorBlock->Descriptors[i].VirtualAddress = ++ (void *)RcvDataBufferHdr; + RcvDescriptorBlock->Descriptors[i].PhysicalAddress = + RcvDataBufferHdr->PhysicalAddress; + } +@@ -3497,7 +3511,9 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter) + RcvDescriptorBlockHdr = NULL; + if (adapter->FreeRcvBlockCount) { + _ple = RemoveHeadList(&adapter->FreeRcvBlocks); +- RcvDescriptorBlockHdr = container_of(_ple, SXG_RCV_DESCRIPTOR_BLOCK_HDR, FreeList); ++ RcvDescriptorBlockHdr = ++ container_of(_ple, SXG_RCV_DESCRIPTOR_BLOCK_HDR, ++ FreeList); + adapter->FreeRcvBlockCount--; + RcvDescriptorBlockHdr->State = SXG_BUFFER_BUSY; + } +@@ -3533,7 +3549,8 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter) + * Return + * None + */ +-static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char Index) ++static void sxg_complete_descriptor_blocks(p_adapter_t adapter, ++ unsigned char Index) + { + PSXG_RCV_RING RingZero = &adapter->RcvRings[0]; + PSXG_RING_INFO RcvRingInfo = &adapter->RcvRingZeroInfo; +@@ -3576,7 +3593,6 @@ static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char In + adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail); + } + +- + static struct pci_driver sxg_driver = { + .name = DRV_NAME, + .id_table = sxg_pci_tbl, +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch b/src/patches/suse-2.6.27.31/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch new file mode 100644 index 000000000..a77a04509 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/Out-of-order-tx-frames-was-causing-several-check-con.patch @@ -0,0 +1,164 @@ +From 9a24511a01552376ad031ac877b62461d58f6a4d Mon Sep 17 00:00:00 2001 +From: Vasu Dev +Date: Thu, 5 Feb 2009 01:32:29 -0800 +References: bnc#473604 +Subject: [PATCH] Out of order tx frames was causing several check condition SCSI status + frames followed by these errors in log. + + [sdp] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE,SUGGEST_OK + [sdp] Sense Key : Aborted Command [current] + [sdp] Add. Sense: Data phase error + +This was causing some test apps to exit due to write failure under heavy +load. + +This was due to a race around adding and removing tx frame skb in +fcoe_pending_queue, Chris Leech helped me to find that brief unlocking +period when pulling skb from fcoe_pending_queue in various contexts +(fcoe_watchdog and fcoe_xmit) and then adding skb back into fcoe_pending_queue +up on a failed fcoe_start_io could change skb/tx frame order in +fcoe_pending_queue. Thanks Chris. + +This patch allows only single context to pull skb from fcoe_pending_queue +at any time to prevent above described ordering issue/race by use of +fcoe_pending_queue_active flag. + +This patch simplified fcoe_watchdog with modified fcoe_check_wait_queue by +use of FCOE_LOW_QUEUE_DEPTH instead previously used several conditionals +to clear and set lp->qfull. + +I think FCOE_MAX_QUEUE_DEPTH with FCOE_LOW_QUEUE_DEPTH will work better +in re/setting lp->qfull and these could be fine tuned for performance. + +Signed-off-by: Vasu Dev +Acked-by: John Jolly +--- + drivers/scsi/fcoe/fcoe_sw.c | 1 + + drivers/scsi/fcoe/libfcoe.c | 45 ++++++++++++++++++++---------------------- + include/scsi/libfcoe.h | 1 + + 3 files changed, 23 insertions(+), 24 deletions(-) + +diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c +index cf83675..da12c93 100644 +--- a/drivers/scsi/fcoe/fcoe_sw.c ++++ b/drivers/scsi/fcoe/fcoe_sw.c +@@ -191,6 +191,7 @@ static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev) + + + skb_queue_head_init(&fc->fcoe_pending_queue); ++ fc->fcoe_pending_queue_active = 0; + + /* setup Source Mac Address */ + memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +index 8bc8078..9f8204b 100644 +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -49,6 +49,7 @@ + static int debug_fcoe; + + #define FCOE_MAX_QUEUE_DEPTH 256 ++#define FCOE_LOW_QUEUE_DEPTH 32 + + /* destination address mode */ + #define FCOE_GW_ADDR_MODE 0x00 +@@ -727,21 +728,12 @@ static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) + **/ + void fcoe_watchdog(ulong vp) + { +- struct fc_lport *lp; + struct fcoe_softc *fc; +- int qfilled = 0; + + read_lock(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { +- lp = fc->lp; +- if (lp) { +- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) +- qfilled = 1; +- if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) { +- if (qfilled) +- lp->qfull = 0; +- } +- } ++ if (fc->lp) ++ fcoe_check_wait_queue(fc->lp); + } + read_unlock(&fcoe_hostlist_lock); + +@@ -757,8 +749,8 @@ void fcoe_watchdog(ulong vp) + * + * This empties the wait_queue, dequeue the head of the wait_queue queue + * and calls fcoe_start_io() for each packet, if all skb have been +- * transmitted, return 0 if a error occurs, then restore wait_queue and +- * try again later. ++ * transmitted, return qlen or -1 if a error occurs, then restore ++ * wait_queue and try again later. + * + * The wait_queue is used when the skb transmit fails. skb will go + * in the wait_queue which will be emptied by the time function OR +@@ -768,33 +760,38 @@ void fcoe_watchdog(ulong vp) + **/ + static int fcoe_check_wait_queue(struct fc_lport *lp) + { +- int rc; + struct sk_buff *skb; + struct fcoe_softc *fc; ++ int rc = -1; + + fc = fcoe_softc(lp); + spin_lock_bh(&fc->fcoe_pending_queue.lock); + +- /* +- * if interface pending queue full then set qfull in lport. +- */ +- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) +- lp->qfull = 1; ++ if (fc->fcoe_pending_queue_active) ++ goto out; ++ fc->fcoe_pending_queue_active = 1; + if (fc->fcoe_pending_queue.qlen) { + while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + rc = fcoe_start_io(skb); +- if (rc) { ++ if (rc) + fcoe_insert_wait_queue_head(lp, skb); +- return rc; +- } + spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ if (rc) ++ break; + } +- if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH) ++ /* ++ * if interface pending queue is below FCOE_LOW_QUEUE_DEPTH ++ * then clear qfull flag. ++ */ ++ if (fc->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH) + lp->qfull = 0; + } ++ fc->fcoe_pending_queue_active = 0; ++ rc = fc->fcoe_pending_queue.qlen; ++out: + spin_unlock_bh(&fc->fcoe_pending_queue.lock); +- return fc->fcoe_pending_queue.qlen; ++ return rc; + } + + /** +diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h +index 89fdbb9..ab09986 100644 +--- a/include/scsi/libfcoe.h ++++ b/include/scsi/libfcoe.h +@@ -46,6 +46,7 @@ struct fcoe_softc { + struct net_device *phys_dev; /* device with ethtool_ops */ + struct packet_type fcoe_packet_type; + struct sk_buff_head fcoe_pending_queue; ++ u8 fcoe_pending_queue_active; + + u8 dest_addr[ETH_ALEN]; + u8 ctl_src_addr[ETH_ALEN]; +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-call-_osc-support-during-root-bridge-discovery.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-call-_osc-support-during-root-bridge-discovery.patch new file mode 100644 index 000000000..c7277e421 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-call-_osc-support-during-root-bridge-discovery.patch @@ -0,0 +1,119 @@ +From 990a7ac5645883a833a11b900bb6f25b65dea65b Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:30:45 -0700 +Subject: ACPI/PCI: call _OSC support during root bridge discovery +Patch-mainline: 2.6.29 +References: bnc#438941 + +Add pci_acpi_osc_support() and call it when a PCI bridge is added. This +allows us to avoid having every individual PCI root bridge driver call +_OSC support for every root bridge in their probe functions, a +significant savings in boot time. + +Signed-off-by: Matthew Wilcox +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/pci_root.c | 9 +++++++++ + drivers/pci/pci-acpi.c | 27 ++++++++++++++++++++------- + include/linux/pci-acpi.h | 1 + + 3 files changed, 30 insertions(+), 7 deletions(-) + +--- a/drivers/acpi/pci_root.c ++++ b/drivers/acpi/pci_root.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -193,6 +194,7 @@ static int __devinit acpi_pci_root_add(s + unsigned long long value = 0; + acpi_handle handle = NULL; + struct acpi_device *child; ++ u32 flags; + + + if (!device) +@@ -210,6 +212,13 @@ static int __devinit acpi_pci_root_add(s + + device->ops.bind = acpi_pci_bind; + ++ /* ++ * All supported architectures that use ACPI have support for ++ * PCI domains, so we indicate this in _OSC support capabilities. ++ */ ++ flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; ++ pci_acpi_osc_support(device->handle, flags); ++ + /* + * Segment + * ------- +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -142,32 +142,45 @@ static acpi_status __acpi_query_osc(u32 + return status; + } + +-static acpi_status acpi_query_osc(acpi_handle handle, +- u32 level, void *context, void **retval) ++/* ++ * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature ++ * @flags: Bitmask of flags to support ++ * ++ * See the ACPI spec for the definition of the flags ++ */ ++int pci_acpi_osc_support(acpi_handle handle, u32 flags) + { + acpi_status status; +- struct acpi_osc_data *osc_data; +- u32 flags = (unsigned long)context; + acpi_handle tmp; ++ struct acpi_osc_data *osc_data; ++ int rc = 0; + + status = acpi_get_handle(handle, "_OSC", &tmp); + if (ACPI_FAILURE(status)) +- return status; ++ return -ENOTTY; + + mutex_lock(&pci_acpi_lock); + osc_data = acpi_get_osc_data(handle); + if (!osc_data) { + printk(KERN_ERR "acpi osc data array is full\n"); +- status = AE_ERROR; ++ rc = -ENOMEM; + goto out; + } + + status = __acpi_query_osc(flags, osc_data); + out: + mutex_unlock(&pci_acpi_lock); +- return status; ++ return rc; ++} ++ ++static acpi_status acpi_query_osc(acpi_handle handle, u32 level, ++ void *context, void **retval) ++{ ++ pci_acpi_osc_support(handle, (unsigned long)context); ++ return AE_OK; + } + ++ + /** + * __pci_osc_support_set - register OS support to Firmware + * @flags: OS support bits +--- a/include/linux/pci-acpi.h ++++ b/include/linux/pci-acpi.h +@@ -51,6 +51,7 @@ + #ifdef CONFIG_ACPI + extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags); + extern acpi_status __pci_osc_support_set(u32 flags, const char *hid); ++int pci_acpi_osc_support(acpi_handle handle, u32 flags); + static inline acpi_status pci_osc_support_set(u32 flags) + { + return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-change-pci_osc_control_set-to-query-control-bits-first.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-change-pci_osc_control_set-to-query-control-bits-first.patch new file mode 100644 index 000000000..241fa19bd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-change-pci_osc_control_set-to-query-control-bits-first.patch @@ -0,0 +1,100 @@ +From 4e39432f4df544d3dfe4fc90a22d87de64d15815 Mon Sep 17 00:00:00 2001 +From: Taku Izumi +Date: Fri, 17 Oct 2008 13:49:46 +0900 +Subject: ACPI/PCI: Change pci_osc_control_set() to query control bits first +Patch-mainline: 2.6.28 +References: bnc#438941 + +Current pci_osc_control_set() evaluates _OSC without query for control +bits, unless __pci_osc_support_set() is called beforehand. But as +strongly recommended in PCI firmware specification, it should query +control bits first. + +This patch changes pci_osc_control_set() to query control bits first +even if __pci_osc_support_set() is not called beforehand. + +Signed-off-by: Kenji Kaneshige +Signed-off-by: Taku Izumi +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/pci-acpi.c | 47 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 31 insertions(+), 16 deletions(-) + +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -120,14 +120,35 @@ out_kfree: + return status; + } + ++static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data) ++{ ++ acpi_status status; ++ u32 support_set; ++ struct acpi_osc_args osc_args; ++ ++ /* do _OSC query for all possible controls */ ++ support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); ++ osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; ++ osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; ++ osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; ++ ++ status = acpi_run_osc(osc_data->handle, &osc_args); ++ if (ACPI_SUCCESS(status)) { ++ osc_data->support_set = support_set; ++ osc_data->query_result = osc_args.query_result; ++ osc_data->is_queried = 1; ++ } ++ ++ return status; ++} ++ + static acpi_status acpi_query_osc(acpi_handle handle, + u32 level, void *context, void **retval) + { + acpi_status status; + struct acpi_osc_data *osc_data; +- u32 flags = (unsigned long)context, support_set; ++ u32 flags = (unsigned long)context; + acpi_handle tmp; +- struct acpi_osc_args osc_args; + + status = acpi_get_handle(handle, "_OSC", &tmp); + if (ACPI_FAILURE(status)) +@@ -141,18 +162,7 @@ static acpi_status acpi_query_osc(acpi_h + goto out; + } + +- /* do _OSC query for all possible controls */ +- support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); +- osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; +- osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; +- osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; +- +- status = acpi_run_osc(handle, &osc_args); +- if (ACPI_SUCCESS(status)) { +- osc_data->support_set = support_set; +- osc_data->query_result = osc_args.query_result; +- osc_data->is_queried = 1; +- } ++ status = __acpi_query_osc(flags, osc_data); + out: + mutex_unlock(&pci_acpi_lock); + return status; +@@ -209,8 +219,13 @@ acpi_status pci_osc_control_set(acpi_han + goto out; + } + +- if (osc_data->is_queried && +- ((osc_data->query_result & ctrlset) != ctrlset)) { ++ if (!osc_data->is_queried) { ++ status = __acpi_query_osc(osc_data->support_set, osc_data); ++ if (ACPI_FAILURE(status)) ++ goto out; ++ } ++ ++ if ((osc_data->query_result & ctrlset) != ctrlset) { + status = AE_SUPPORT; + goto out; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-fix-possible-race-condition-on-_osc-evaluation.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-fix-possible-race-condition-on-_osc-evaluation.patch new file mode 100644 index 000000000..b1e2d54e8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-fix-possible-race-condition-on-_osc-evaluation.patch @@ -0,0 +1,98 @@ +From 9778c14b4ca2c81e437fc2fd2b1f3d676937db27 Mon Sep 17 00:00:00 2001 +From: Taku Izumi +Date: Fri, 17 Oct 2008 13:48:36 +0900 +Subject: ACPI/PCI: Fix possible race condition on _OSC evaluation +Patch-mainline: 2.6.28 +References: bnc#438941 + +Fix possible race condition on _OSC evaluation. + +Current _OSC evaluation code has possible race condition because it +maniputes osc_data linked list or its contents without any lock +mechanism. + +Signed-off-by: Kenji Kaneshige +Signed-off-by: Taku Izumi +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/pci-acpi.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -35,6 +35,8 @@ struct acpi_osc_args { + u32 query_result; + }; + ++static DEFINE_MUTEX(pci_acpi_lock); ++ + static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) + { + struct acpi_osc_data *data; +@@ -131,10 +133,12 @@ static acpi_status acpi_query_osc(acpi_h + if (ACPI_FAILURE(status)) + return status; + ++ mutex_lock(&pci_acpi_lock); + osc_data = acpi_get_osc_data(handle); + if (!osc_data) { + printk(KERN_ERR "acpi osc data array is full\n"); +- return AE_ERROR; ++ status = AE_ERROR; ++ goto out; + } + + /* do _OSC query for all possible controls */ +@@ -149,7 +153,8 @@ static acpi_status acpi_query_osc(acpi_h + osc_data->query_result = osc_args.query_result; + osc_data->is_queried = 1; + } +- ++out: ++ mutex_unlock(&pci_acpi_lock); + return status; + } + +@@ -190,19 +195,25 @@ acpi_status pci_osc_control_set(acpi_han + if (ACPI_FAILURE(status)) + return status; + ++ mutex_lock(&pci_acpi_lock); + osc_data = acpi_get_osc_data(handle); + if (!osc_data) { + printk(KERN_ERR "acpi osc data array is full\n"); +- return AE_ERROR; ++ status = AE_ERROR; ++ goto out; + } + + ctrlset = (flags & OSC_CONTROL_MASKS); +- if (!ctrlset) +- return AE_TYPE; ++ if (!ctrlset) { ++ status = AE_TYPE; ++ goto out; ++ } + + if (osc_data->is_queried && +- ((osc_data->query_result & ctrlset) != ctrlset)) +- return AE_SUPPORT; ++ ((osc_data->query_result & ctrlset) != ctrlset)) { ++ status = AE_SUPPORT; ++ goto out; ++ } + + control_set = osc_data->control_set | ctrlset; + osc_args.capbuf[OSC_QUERY_TYPE] = 0; +@@ -211,7 +222,8 @@ acpi_status pci_osc_control_set(acpi_han + status = acpi_run_osc(handle, &osc_args); + if (ACPI_SUCCESS(status)) + osc_data->control_set = control_set; +- ++out: ++ mutex_unlock(&pci_acpi_lock); + return status; + } + EXPORT_SYMBOL(pci_osc_control_set); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-include-missing-acpi.h-file-in-pci-acpi.h.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-include-missing-acpi.h-file-in-pci-acpi.h.patch new file mode 100644 index 000000000..549dca3a3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-include-missing-acpi.h-file-in-pci-acpi.h.patch @@ -0,0 +1,29 @@ +From 8b62091e20215730be1b94b7cd135a78a3e692ca Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:30:40 -0700 +Subject: ACPI/PCI: include missing acpi.h file in pci-acpi.h. +Patch-mainline: 2.6.29 +References: bnc#438941 + +The pci-acpi.h file will not compile without including linux/acpi.h. + +Signed-off-by: Matthew Wilcox +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + + include/linux/pci-acpi.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/linux/pci-acpi.h ++++ b/include/linux/pci-acpi.h +@@ -8,6 +8,8 @@ + #ifndef _PCI_ACPI_H_ + #define _PCI_ACPI_H_ + ++#include ++ + #define OSC_QUERY_TYPE 0 + #define OSC_SUPPORT_TYPE 1 + #define OSC_CONTROL_TYPE 2 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pci-extended-config-_osc-support-called-when-root-bridge-added.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pci-extended-config-_osc-support-called-when-root-bridge-added.patch new file mode 100644 index 000000000..2fee2d428 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pci-extended-config-_osc-support-called-when-root-bridge-added.patch @@ -0,0 +1,109 @@ +From 0ef5f8f6159e44b4faa997be08d1a3bcbf44ad08 Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:30:50 -0700 +Subject: ACPI/PCI: PCI extended config _OSC support called when root bridge added +Patch-mainline: 2.6.29 +References: bnc#438941 + +The _OSC capability OSC_EXT_PCI_CONFIG_SUPPORT is set when the root +bridge is added with pci_acpi_osc_support() if we can access PCI +extended config space. + +This adds the function pci_ext_cfg_avail which returns true if we can +access PCI extended config space (offset greater than 0xff). It +currently only returns false if arch=x86 and raw_pci_ext_ops is not set +(which might happen if pci=nommcfg is set on the kernel command-line). + +Signed-off-by: Andrew Patterson +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/pci/common.c | 8 ++++++++ + drivers/acpi/pci_root.c | 10 ++++++++-- + drivers/pci/pci.c | 13 +++++++++++++ + include/linux/pci.h | 2 ++ + 4 files changed, 31 insertions(+), 2 deletions(-) + +--- a/arch/x86/pci/common.c ++++ b/arch/x86/pci/common.c +@@ -563,6 +563,14 @@ void pcibios_disable_device (struct pci_ + pcibios_disable_irq(dev); + } + ++int pci_ext_cfg_avail(struct pci_dev *dev) ++{ ++ if (raw_pci_ext_ops) ++ return 1; ++ else ++ return 0; ++} ++ + struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) + { + struct pci_bus *bus = NULL; +--- a/drivers/acpi/pci_root.c ++++ b/drivers/acpi/pci_root.c +@@ -194,7 +194,7 @@ static int __devinit acpi_pci_root_add(s + unsigned long long value = 0; + acpi_handle handle = NULL; + struct acpi_device *child; +- u32 flags; ++ u32 flags, base_flags; + + + if (!device) +@@ -216,7 +216,7 @@ static int __devinit acpi_pci_root_add(s + * All supported architectures that use ACPI have support for + * PCI domains, so we indicate this in _OSC support capabilities. + */ +- flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; ++ flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; + pci_acpi_osc_support(device->handle, flags); + + /* +@@ -344,6 +344,12 @@ static int __devinit acpi_pci_root_add(s + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + ++ /* Indicate support for various _OSC capabilities. */ ++ if (pci_ext_cfg_avail(root->bus->self)) ++ flags |= OSC_EXT_PCI_CONFIG_SUPPORT; ++ if (flags != base_flags) ++ pci_acpi_osc_support(device->handle, flags); ++ + end: + if (result) { + if (!list_empty(&root->node)) +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -1900,6 +1900,19 @@ static void __devinit pci_no_domains(voi + #endif + } + ++/** ++ * pci_ext_cfg_enabled - can we access extended PCI config space? ++ * @dev: The PCI device of the root bridge. ++ * ++ * Returns 1 if we can access PCI extended config space (offsets ++ * greater than 0xff). This is the default implementation. Architecture ++ * implementations can override this. ++ */ ++int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev) ++{ ++ return 1; ++} ++ + static int __devinit pci_init(void) + { + struct pci_dev *dev = NULL; +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1128,5 +1128,7 @@ static inline void pci_mmcfg_early_init( + static inline void pci_mmcfg_late_init(void) { } + #endif + ++int pci_ext_cfg_avail(struct pci_dev *dev); ++ + #endif /* __KERNEL__ */ + #endif /* LINUX_PCI_H */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch new file mode 100644 index 000000000..b746ad5f4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch @@ -0,0 +1,76 @@ +From 07ae95f988a34465bdcb384bfa73c03424fe2312 Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:31:05 -0700 +Subject: ACPI/PCI: PCI MSI _OSC support capabilities called when root bridge added +Patch-mainline: 2.6.29 +References: bnc#438941 + +The _OSC capability OSC_MSI_SUPPORT is set when the root bridge is added +with pci_acpi_osc_support(), so we no longer need to do it in the PCI +MSI driver. Also adds the function pci_msi_enabled, which returns true +if pci=nomsi is not on the kernel command-line. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/pci_root.c | 2 ++ + drivers/pci/msi.c | 11 +++++++++++ + include/linux/pci.h | 7 +++++++ + 3 files changed, 20 insertions(+) + +--- a/drivers/acpi/pci_root.c ++++ b/drivers/acpi/pci_root.c +@@ -350,6 +350,8 @@ static int __devinit acpi_pci_root_add(s + if (pcie_aspm_enabled()) + flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | + OSC_CLOCK_PWR_CAPABILITY_SUPPORT; ++ if (pci_msi_enabled()) ++ flags |= OSC_MSI_SUPPORT; + if (flags != base_flags) + pci_acpi_osc_support(device->handle, flags); + +--- a/drivers/pci/msi.c ++++ b/drivers/pci/msi.c +@@ -757,6 +757,17 @@ void pci_no_msi(void) + pci_msi_enable = 0; + } + ++/** ++ * pci_msi_enabled - is MSI enabled? ++ * ++ * Returns true if MSI has not been disabled by the command-line option ++ * pci=nomsi. ++ **/ ++int pci_msi_enabled(void) ++{ ++ return pci_msi_enable; ++} ++ + void pci_msi_init_pci_dev(struct pci_dev *dev) + { + INIT_LIST_HEAD(&dev->msi_list); +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -767,6 +767,11 @@ static inline void msi_remove_pci_irq_ve + + static inline void pci_restore_msi_state(struct pci_dev *dev) + { } ++ ++static inline int pci_msi_enabled(void) ++{ ++ return 0; ++} + #else + extern int pci_enable_msi(struct pci_dev *dev); + extern void pci_msi_shutdown(struct pci_dev *dev); +@@ -777,6 +782,8 @@ extern void pci_msix_shutdown(struct pci + extern void pci_disable_msix(struct pci_dev *dev); + extern void msi_remove_pci_irq_vectors(struct pci_dev *dev); + extern void pci_restore_msi_state(struct pci_dev *dev); ++extern int pci_msi_enabled(void); ++ + #endif + + #ifndef CONFIG_PCIEASPM diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pcie-aer-_osc-support-capabilities-called-when-root-bridge-added.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pcie-aer-_osc-support-capabilities-called-when-root-bridge-added.patch new file mode 100644 index 000000000..985575ee1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pcie-aer-_osc-support-capabilities-called-when-root-bridge-added.patch @@ -0,0 +1,25 @@ +From eb9188bdb9d65aeead2382ec3dd656a17ec8936d Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:31:00 -0700 +Subject: ACPI/PCI: PCIe AER _OSC support capabilities called when root bridge added +Patch-mainline: 2.6.29 +References: bnc#438941 + +The _OSC capability OSC_EXT_PCI_CONFIG_SUPPORT is set when the root +bridge is added with pci_acpi_osc_support(), so we no longer need to do +it in the PCIe AER driver. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- a/drivers/pci/pcie/aer/aerdrv_acpi.c ++++ b/drivers/pci/pcie/aer/aerdrv_acpi.c +@@ -38,7 +38,6 @@ int aer_osc_setup(struct pcie_device *pciedev) + + handle = acpi_find_root_bridge_handle(pdev); + if (handle) { +- pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); + status = pci_osc_control_set(handle, + OSC_PCI_EXPRESS_AER_CONTROL | + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pcie-aspm-_osc-support-capabilities-called-when-root-bridge-added.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pcie-aspm-_osc-support-capabilities-called-when-root-bridge-added.patch new file mode 100644 index 000000000..ce90cf0ce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-pcie-aspm-_osc-support-capabilities-called-when-root-bridge-added.patch @@ -0,0 +1,90 @@ +From 3e1b16002af29758b6bc9c38939d43838d9335bc Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:30:55 -0700 +Subject: ACPI/PCI: PCIe ASPM _OSC support capabilities called when root bridge added +Patch-mainline: 2.6.29 +References: bnc#438941 + +The _OSC capabilities OSC_ACTIVE_STATE_PWR_SUPPORT and +OSC_CLOCK_PWR_CAPABILITY_SUPPORT are set when the root bridge is added +with pci_acpi_osc_support(), so we no longer need to do it in the ASPM +driver. Also add the function pcie_aspm_enabled, which returns true if +pcie_aspm=off is not on the kernel command-line. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/acpi/pci_root.c | 3 +++ + drivers/pci/pcie/aspm.c | 27 +++++++++------------------ + include/linux/pci.h | 9 +++++++++ + 3 files changed, 21 insertions(+), 18 deletions(-) + +--- a/drivers/acpi/pci_root.c ++++ b/drivers/acpi/pci_root.c +@@ -347,6 +347,9 @@ static int __devinit acpi_pci_root_add(s + /* Indicate support for various _OSC capabilities. */ + if (pci_ext_cfg_avail(root->bus->self)) + flags |= OSC_EXT_PCI_CONFIG_SUPPORT; ++ if (pcie_aspm_enabled()) ++ flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | ++ OSC_CLOCK_PWR_CAPABILITY_SUPPORT; + if (flags != base_flags) + pci_acpi_osc_support(device->handle, flags); + +--- a/drivers/pci/pcie/aspm.c ++++ b/drivers/pci/pcie/aspm.c +@@ -948,24 +948,15 @@ void pcie_no_aspm(void) + aspm_disabled = 1; + } + +-#ifdef CONFIG_ACPI +-#include +-#include +-static void pcie_aspm_platform_init(void) ++/** ++ * pcie_aspm_enabled - is PCIe ASPM enabled? ++ * ++ * Returns true if ASPM has not been disabled by the command-line option ++ * pcie_aspm=off. ++ **/ ++int pcie_aspm_enabled(void) + { +- pcie_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT| +- OSC_CLOCK_PWR_CAPABILITY_SUPPORT); ++ return !aspm_disabled; + } +-#else +-static inline void pcie_aspm_platform_init(void) { } +-#endif ++EXPORT_SYMBOL(pcie_aspm_enabled); + +-static int __init pcie_aspm_init(void) +-{ +- if (aspm_disabled) +- return 0; +- pcie_aspm_platform_init(); +- return 0; +-} +- +-fs_initcall(pcie_aspm_init); +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -779,6 +779,15 @@ extern void msi_remove_pci_irq_vectors(s + extern void pci_restore_msi_state(struct pci_dev *dev); + #endif + ++#ifndef CONFIG_PCIEASPM ++static inline int pcie_aspm_enabled(void) ++{ ++ return 0; ++} ++#else ++extern int pcie_aspm_enabled(void); ++#endif ++ + #ifdef CONFIG_HT_IRQ + /* The functions a driver should call */ + int ht_create_irq(struct pci_dev *dev, int idx); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-remove-obsolete-_osc-capability-support-functions.patch b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-remove-obsolete-_osc-capability-support-functions.patch new file mode 100644 index 000000000..55ab1345a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/acpi-pci-remove-obsolete-_osc-capability-support-functions.patch @@ -0,0 +1,82 @@ +From 23616941914917cf25b94789856b5326b68d8ee8 Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:31:10 -0700 +Subject: ACPI/PCI: remove obsolete _OSC capability support functions +Patch-mainline: 2.6.29 +References: bnc#438941 + +The acpi_query_osc, __pci_osc_support_set, pci_osc_support_set, and +pcie_osc_support_set functions have been obsoleted in favor of setting +these capabilities during root bridge discovery with +pci_acpi_osc_support. There are no longer any callers of these +functions, so remove them. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +--- a/drivers/pci/pci-acpi.c ++++ b/drivers/pci/pci-acpi.c +@@ -173,32 +173,6 @@ out: + return rc; + } + +-static acpi_status acpi_query_osc(acpi_handle handle, u32 level, +- void *context, void **retval) +-{ +- pci_acpi_osc_support(handle, (unsigned long)context); +- return AE_OK; +-} +- +- +-/** +- * __pci_osc_support_set - register OS support to Firmware +- * @flags: OS support bits +- * @hid: hardware ID +- * +- * Update OS support fields and doing a _OSC Query to obtain an update +- * from Firmware on supported control bits. +- **/ +-acpi_status __pci_osc_support_set(u32 flags, const char *hid) +-{ +- if (!(flags & OSC_SUPPORT_MASKS)) +- return AE_TYPE; +- +- acpi_get_devices(hid, acpi_query_osc, +- (void *)(unsigned long)flags, NULL); +- return AE_OK; +-} +- + /** + * pci_osc_control_set - commit requested control to Firmware + * @handle: acpi_handle for the target ACPI object +diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h +index 424f06f..871e096 100644 +--- a/include/linux/pci-acpi.h ++++ b/include/linux/pci-acpi.h +@@ -50,16 +50,7 @@ + + #ifdef CONFIG_ACPI + extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags); +-extern acpi_status __pci_osc_support_set(u32 flags, const char *hid); + int pci_acpi_osc_support(acpi_handle handle, u32 flags); +-static inline acpi_status pci_osc_support_set(u32 flags) +-{ +- return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING); +-} +-static inline acpi_status pcie_osc_support_set(u32 flags) +-{ +- return __pci_osc_support_set(flags, PCI_EXPRESS_ROOT_HID_STRING); +-} + static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) + { + /* Find root host bridge */ +@@ -76,8 +67,6 @@ typedef u32 acpi_status; + #endif + static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) + {return AE_ERROR;} +-static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} +-static inline acpi_status pcie_osc_support_set(u32 flags) {return AE_ERROR;} + static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) + { return NULL; } + #endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/add-via-chrome9-drm-support.patch b/src/patches/suse-2.6.27.31/patches.drivers/add-via-chrome9-drm-support.patch new file mode 100644 index 000000000..d92899b5e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/add-via-chrome9-drm-support.patch @@ -0,0 +1,5166 @@ +From: Bruce Chang +Subject: add Via chrome9 drm support +Patch-mainline: 2.6.29 + +Signed-off-by: Bruce Chang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/Kconfig | 7 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/via_chrome9/Makefile | 8 + drivers/gpu/drm/via_chrome9/via_chrome9_3d_reg.h | 407 ++++++ + drivers/gpu/drm/via_chrome9/via_chrome9_dma.c | 1285 +++++++++++++++++++++ + drivers/gpu/drm/via_chrome9/via_chrome9_dma.h | 69 + + drivers/gpu/drm/via_chrome9/via_chrome9_drm.c | 950 +++++++++++++++ + drivers/gpu/drm/via_chrome9/via_chrome9_drm.h | 443 +++++++ + drivers/gpu/drm/via_chrome9/via_chrome9_drv.c | 224 +++ + drivers/gpu/drm/via_chrome9/via_chrome9_drv.h | 150 ++ + drivers/gpu/drm/via_chrome9/via_chrome9_mm.c | 435 +++++++ + drivers/gpu/drm/via_chrome9/via_chrome9_mm.h | 67 + + drivers/gpu/drm/via_chrome9/via_chrome9_verifier.c | 982 ++++++++++++++++ + drivers/gpu/drm/via_chrome9/via_chrome9_verifier.h | 61 + 14 files changed, 5089 insertions(+) + +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -99,6 +99,13 @@ config DRM_VIA + Choose this option if you have a Via unichrome or compatible video + chipset. If M is selected the module will be called via. + ++config DRM_VIA_CHROME9 ++ tristate "Via chrome9 video cards" ++ depends on DRM ++ help ++ Choose this option if you have a Via chrome9 or compatible video ++ chipset. If M is selected the module will be called via_chrome9. ++ + config DRM_SAVAGE + tristate "Savage video cards" + depends on DRM +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -23,4 +23,5 @@ obj-$(CONFIG_DRM_I915) += i915/ + obj-$(CONFIG_DRM_SIS) += sis/ + obj-$(CONFIG_DRM_SAVAGE)+= savage/ + obj-$(CONFIG_DRM_VIA) +=via/ ++obj-$(CONFIG_DRM_VIA_CHROME9) +=via_chrome9/ + +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/Makefile +@@ -0,0 +1,8 @@ ++# ++# Makefile for the drm device driver. This driver provides support for the ++# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ++ ++ccflags-y := -Iinclude/drm ++via_chrome9-y := via_chrome9_drv.o via_chrome9_drm.o via_chrome9_mm.o via_chrome9_dma.o via_chrome9_verifier.o ++ ++obj-$(CONFIG_DRM_VIA_CHROME9) += via_chrome9.o +\ No newline at end of file +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_3d_reg.h +@@ -0,0 +1,407 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef VIA_CHROME9_3D_REG_H ++#define VIA_CHROME9_3D_REG_H ++#define GetMMIORegister(base, offset) \ ++ (*(__volatile__ unsigned int *)(void *)(((unsigned char *)(base)) + \ ++ (offset))) ++#define SetMMIORegister(base, offset, val) \ ++ (*(__volatile__ unsigned int *)(void *)(((unsigned char *)(base)) + \ ++ (offset)) = (val)) ++ ++#define GetMMIORegisterU8(base, offset) \ ++ (*(__volatile__ unsigned char *)(void *)(((unsigned char *)(base)) + \ ++ (offset))) ++#define SetMMIORegisterU8(base, offset, val) \ ++ (*(__volatile__ unsigned char *)(void *)(((unsigned char *)(base)) + \ ++ (offset)) = (val)) ++ ++#define BCI_SEND(bci, value) (*(bci)++ = (unsigned long)(value)) ++#define BCI_SET_STREAM_REGISTER(bci_base, bci_index, reg_value) \ ++do { \ ++ unsigned long cmd; \ ++ \ ++ cmd = (0x90000000 \ ++ | (1<<16) /* stream processor register */ \ ++ | (bci_index & 0x3FFC)); /* MMIO register address */ \ ++ BCI_SEND(bci_base, cmd); \ ++ BCI_SEND(bci_base, reg_value); \ ++ } while (0) ++ ++/* Command Header Type */ ++ ++#define INV_AGPHeader0 0xFE000000 ++#define INV_AGPHeader1 0xFE010000 ++#define INV_AGPHeader2 0xFE020000 ++#define INV_AGPHeader3 0xFE030000 ++#define INV_AGPHeader4 0xFE040000 ++#define INV_AGPHeader5 0xFE050000 ++#define INV_AGPHeader6 0xFE060000 ++#define INV_AGPHeader7 0xFE070000 ++#define INV_AGPHeader82 0xFE820000 ++#define INV_AGPHeader_MASK 0xFFFF0000 ++#define INV_DUMMY_MASK 0xFF000000 ++ ++/*send pause address of AGP ring command buffer via_chrome9 this IO port*/ ++#define INV_REG_PCIPAUSE 0x294 ++#define INV_REG_PCIPAUSE_ENABLE 0x4 ++ ++#define INV_CMDBUF_THRESHOLD (8) ++#define INV_QW_PAUSE_ALIGN 0x40 ++ ++/* Transmission IO Space*/ ++#define INV_REG_CR_TRANS 0x041C ++#define INV_REG_CR_BEGIN 0x0420 ++#define INV_REG_CR_END 0x0438 ++ ++#define INV_REG_3D_TRANS 0x043C ++#define INV_REG_3D_BEGIN 0x0440 ++#define INV_REG_3D_END 0x06FC ++#define INV_REG_23D_WAIT 0x326C ++/*3D / 2D ID Control (Only For Group A)*/ ++#define INV_REG_2D3D_ID_CTRL 0x060 ++ ++ ++/* Engine Status */ ++ ++#define INV_RB_ENG_STATUS 0x0400 ++#define INV_ENG_BUSY_HQV0 0x00040000 ++#define INV_ENG_BUSY_HQV1 0x00020000 ++#define INV_ENG_BUSY_CR 0x00000010 ++#define INV_ENG_BUSY_MPEG 0x00000008 ++#define INV_ENG_BUSY_VQ 0x00000004 ++#define INV_ENG_BUSY_2D 0x00000002 ++#define INV_ENG_BUSY_3D 0x00001FE1 ++#define INV_ENG_BUSY_ALL \ ++ (INV_ENG_BUSY_2D | INV_ENG_BUSY_3D | INV_ENG_BUSY_CR) ++ ++/* Command Queue Status*/ ++#define INV_RB_VQ_STATUS 0x0448 ++#define INV_VQ_FULL 0x40000000 ++ ++/* AGP command buffer pointer current position*/ ++#define INV_RB_AGPCMD_CURRADDR 0x043C ++ ++/* AGP command buffer status*/ ++#define INV_RB_AGPCMD_STATUS 0x0444 ++#define INV_AGPCMD_InPause 0x80000000 ++ ++/*AGP command buffer pause address*/ ++#define INV_RB_AGPCMD_PAUSEADDR 0x045C ++ ++/*AGP command buffer jump address*/ ++#define INV_RB_AGPCMD_JUMPADDR 0x0460 ++ ++/*AGP command buffer start address*/ ++#define INV_RB_AGPCMD_STARTADDR 0x0464 ++ ++ ++/* Constants */ ++#define NUMBER_OF_EVENT_TAGS 1024 ++#define NUMBER_OF_APERTURES_CLB 16 ++ ++/* Register definition */ ++#define HW_SHADOW_ADDR 0x8520 ++#define HW_GARTTABLE_ADDR 0x8540 ++ ++#define INV_HSWFlag_DBGMASK 0x00000FFF ++#define INV_HSWFlag_ENCODEMASK 0x007FFFF0 ++#define INV_HSWFlag_ADDRSHFT 8 ++#define INV_HSWFlag_DECODEMASK \ ++ (INV_HSWFlag_ENCODEMASK << INV_HSWFlag_ADDRSHFT) ++#define INV_HSWFlag_ADDR_ENCODE(x) 0xCC000000 ++#define INV_HSWFlag_ADDR_DECODE(x) \ ++ (((unsigned int)x & INV_HSWFlag_DECODEMASK) >> INV_HSWFlag_ADDRSHFT) ++ ++ ++#define INV_SubA_HAGPBstL 0x60000000 ++#define INV_SubA_HAGPBstH 0x61000000 ++#define INV_SubA_HAGPBendL 0x62000000 ++#define INV_SubA_HAGPBendH 0x63000000 ++#define INV_SubA_HAGPBpL 0x64000000 ++#define INV_SubA_HAGPBpID 0x65000000 ++#define INV_HAGPBpID_PAUSE 0x00000000 ++#define INV_HAGPBpID_JUMP 0x00000100 ++#define INV_HAGPBpID_STOP 0x00000200 ++ ++#define INV_HAGPBpH_MASK 0x000000FF ++#define INV_HAGPBpH_SHFT 0 ++ ++#define INV_SubA_HAGPBjumpL 0x66000000 ++#define INV_SubA_HAGPBjumpH 0x67000000 ++#define INV_HAGPBjumpH_MASK 0x000000FF ++#define INV_HAGPBjumpH_SHFT 0 ++ ++#define INV_SubA_HFthRCM 0x68000000 ++#define INV_HFthRCM_MASK 0x003F0000 ++#define INV_HFthRCM_SHFT 16 ++#define INV_HFthRCM_8 0x00080000 ++#define INV_HFthRCM_10 0x000A0000 ++#define INV_HFthRCM_18 0x00120000 ++#define INV_HFthRCM_24 0x00180000 ++#define INV_HFthRCM_32 0x00200000 ++ ++#define INV_HAGPBClear 0x00000008 ++ ++#define INV_HRSTTrig_RestoreAGP 0x00000004 ++#define INV_HRSTTrig_RestoreAll 0x00000002 ++#define INV_HAGPBTrig 0x00000001 ++ ++#define INV_ParaSubType_MASK 0xff000000 ++#define INV_ParaType_MASK 0x00ff0000 ++#define INV_ParaOS_MASK 0x0000ff00 ++#define INV_ParaAdr_MASK 0x000000ff ++#define INV_ParaSubType_SHIFT 24 ++#define INV_ParaType_SHIFT 16 ++#define INV_ParaOS_SHIFT 8 ++#define INV_ParaAdr_SHIFT 0 ++ ++#define INV_ParaType_Vdata 0x00000000 ++#define INV_ParaType_Attr 0x00010000 ++#define INV_ParaType_Tex 0x00020000 ++#define INV_ParaType_Pal 0x00030000 ++#define INV_ParaType_FVF 0x00040000 ++#define INV_ParaType_PreCR 0x00100000 ++#define INV_ParaType_CR 0x00110000 ++#define INV_ParaType_Cfg 0x00fe0000 ++#define INV_ParaType_Dummy 0x00300000 ++ ++#define INV_SubType_Tex0 0x00000000 ++#define INV_SubType_Tex1 0x00000001 ++#define INV_SubType_Tex2 0x00000002 ++#define INV_SubType_Tex3 0x00000003 ++#define INV_SubType_Tex4 0x00000004 ++#define INV_SubType_Tex5 0x00000005 ++#define INV_SubType_Tex6 0x00000006 ++#define INV_SubType_Tex7 0x00000007 ++#define INV_SubType_General 0x000000fe ++#define INV_SubType_TexSample 0x00000020 ++ ++#define INV_HWBasL_MASK 0x00FFFFFF ++#define INV_HWBasH_MASK 0xFF000000 ++#define INV_HWBasH_SHFT 24 ++#define INV_HWBasL(x) ((unsigned int)(x) & INV_HWBasL_MASK) ++#define INV_HWBasH(x) ((unsigned int)(x) >> INV_HWBasH_SHFT) ++#define INV_HWBas256(x) ((unsigned int)(x) >> 8) ++#define INV_HWPit32(x) ((unsigned int)(x) >> 5) ++ ++/* Read Back Register Setting */ ++#define INV_SubA_HSetRBGID 0x02000000 ++#define INV_HSetRBGID_CR 0x00000000 ++#define INV_HSetRBGID_FE 0x00000001 ++#define INV_HSetRBGID_PE 0x00000002 ++#define INV_HSetRBGID_RC 0x00000003 ++#define INV_HSetRBGID_PS 0x00000004 ++#define INV_HSetRBGID_XE 0x00000005 ++#define INV_HSetRBGID_BE 0x00000006 ++ ++ ++struct drm_clb_event_tag_info { ++ unsigned int *linear_address; ++ unsigned int *event_tag_linear_address; ++ int usage[NUMBER_OF_EVENT_TAGS]; ++ unsigned int pid[NUMBER_OF_EVENT_TAGS]; ++}; ++ ++static inline int is_agp_header(unsigned int data) ++{ ++ switch (data & INV_AGPHeader_MASK) { ++ case INV_AGPHeader0: ++ case INV_AGPHeader1: ++ case INV_AGPHeader2: ++ case INV_AGPHeader3: ++ case INV_AGPHeader4: ++ case INV_AGPHeader5: ++ case INV_AGPHeader6: ++ case INV_AGPHeader7: ++ return 1; ++ default: ++ return 0; ++ } ++} ++ ++/* Header0: 2D */ ++#define ADDCmdHeader0_INVI(pCmd, dwCount) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader0; \ ++ *(pCmd)++ = (dwCount); \ ++ *(pCmd)++ = 0; \ ++ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ ++} ++ ++/* Header1: 2D */ ++#define ADDCmdHeader1_INVI(pCmd, dwAddr, dwCount) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader1 | (dwAddr); \ ++ *(pCmd)++ = (dwCount); \ ++ *(pCmd)++ = 0; \ ++ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ ++} ++ ++/* Header2: CR/3D */ ++#define ADDCmdHeader2_INVI(pCmd, dwAddr, dwType) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned int)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \ ++ *(pCmd)++ = (dwAddr); \ ++ *(pCmd)++ = (dwType); \ ++ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ ++} ++ ++/* Header2: CR/3D with SW Flag */ ++#define ADDCmdHeader2_SWFlag_INVI(pCmd, dwAddr, dwType, dwSWFlag) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader2 | ((dwAddr)+4); \ ++ *(pCmd)++ = (dwAddr); \ ++ *(pCmd)++ = (dwType); \ ++ *(pCmd)++ = (dwSWFlag); \ ++} ++ ++ ++/* Header3: 3D */ ++#define ADDCmdHeader3_INVI(pCmd, dwType, dwStart, dwCount) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \ ++ *(pCmd)++ = (dwCount); \ ++ *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \ ++ *(pCmd)++ = (unsigned int)INV_HSWFlag_ADDR_ENCODE(pCmd); \ ++} ++ ++/* Header3: 3D with SW Flag */ ++#define ADDCmdHeader3_SWFlag_INVI(pCmd, dwType, dwStart, dwSWFlag, dwCount) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader3 | INV_REG_3D_TRANS; \ ++ *(pCmd)++ = (dwCount); \ ++ *(pCmd)++ = (dwType) | ((dwStart) & 0xFFFF); \ ++ *(pCmd)++ = (dwSWFlag); \ ++} ++ ++/* Header4: DVD */ ++#define ADDCmdHeader4_INVI(pCmd, dwAddr, dwCount, id) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader4 | (dwAddr); \ ++ *(pCmd)++ = (dwCount); \ ++ *(pCmd)++ = (id); \ ++ *(pCmd)++ = 0; \ ++} ++ ++/* Header5: DVD */ ++#define ADDCmdHeader5_INVI(pCmd, dwQWcount, id) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader5; \ ++ *(pCmd)++ = (dwQWcount); \ ++ *(pCmd)++ = (id); \ ++ *(pCmd)++ = 0; \ ++} ++ ++/* Header6: DEBUG */ ++#define ADDCmdHeader6_INVI(pCmd) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader6; \ ++ *(pCmd)++ = 0; \ ++ *(pCmd)++ = 0; \ ++ *(pCmd)++ = 0; \ ++} ++ ++/* Header7: DMA */ ++#define ADDCmdHeader7_INVI(pCmd, dwQWcount, id) \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader7; \ ++ *(pCmd)++ = (dwQWcount); \ ++ *(pCmd)++ = (id); \ ++ *(pCmd)++ = 0; \ ++} ++ ++/* Header82: Branch buffer */ ++#define ADDCmdHeader82_INVI(pCmd, dwAddr, dwType); \ ++{ \ ++ /* 4 unsigned int align, insert NULL Command for padding */ \ ++ while (((unsigned long *)(pCmd)) & 0xF) { \ ++ *(pCmd)++ = 0xCC000000; \ ++ } \ ++ *(pCmd)++ = INV_AGPHeader82 | ((dwAddr)+4); \ ++ *(pCmd)++ = (dwAddr); \ ++ *(pCmd)++ = (dwType); \ ++ *(pCmd)++ = 0xCC000000; \ ++} ++ ++ ++#define ADD2DCmd_INVI(pCmd, dwAddr, dwCmd) \ ++{ \ ++ *(pCmd)++ = (dwAddr); \ ++ *(pCmd)++ = (dwCmd); \ ++} ++ ++#define ADDCmdData_INVI(pCmd, dwCmd) (*(pCmd)++ = (dwCmd)) ++ ++#define ADDCmdDataStream_INVI(pCmdBuf, pCmd, dwCount) \ ++{ \ ++ memcpy((pCmdBuf), (pCmd), ((dwCount)<<2)); \ ++ (pCmdBuf) += (dwCount); \ ++} ++ ++#endif +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_dma.c +@@ -0,0 +1,1285 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++#include "drm.h" ++#include "via_chrome9_drm.h" ++#include "via_chrome9_drv.h" ++#include "via_chrome9_3d_reg.h" ++#include "via_chrome9_dma.h" ++ ++#define NULLCOMMANDNUMBER 256 ++unsigned int NULL_COMMAND_INV[4] = ++ { 0xCC000000, 0xCD000000, 0xCE000000, 0xCF000000 }; ++ ++void ++via_chrome9ke_assert(int a) ++{ ++} ++ ++unsigned int ++ProtectSizeValue(unsigned int size) ++{ ++ unsigned int i; ++ for (i = 0; i < 8; i++) ++ if ((size > (1 << (i + 12))) ++ && (size <= (1 << (i + 13)))) ++ return i + 1; ++ return 0; ++} ++ ++void via_chrome9_dma_init_inv(struct drm_device *dev) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ unsigned int *pGARTTable; ++ unsigned int i, entries, GARTOffset; ++ unsigned char sr6a, sr6b, sr6c, sr6f, sr7b; ++ unsigned int *addrlinear; ++ unsigned int size, alignedoffset; ++ ++ entries = dev_priv->pagetable_map.pagetable_size / ++ sizeof(unsigned int); ++ pGARTTable = dev_priv->pagetable_map.pagetable_handle; ++ ++ GARTOffset = dev_priv->pagetable_map.pagetable_offset; ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c &= (~0x80); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ sr6a = (unsigned char)((GARTOffset & 0xff000) >> 12); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a); ++ ++ sr6b = (unsigned char)((GARTOffset & 0xff00000) >> 20); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c |= ((unsigned char)((GARTOffset >> 28) & 0x01)); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b); ++ sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr7b &= (~0x0f); ++ sr7b |= ProtectSizeValue(dev_priv-> ++ pagetable_map.pagetable_size); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b); ++ ++ for (i = 0; i < entries; i++) ++ writel(0x80000000, pGARTTable+i); ++ ++ /*flush*/ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); ++ do { ++ sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c5); ++ } while (sr6f & 0x80); ++ ++ sr6f |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ if (dev_priv->drm_agp_type != DRM_AGP_DISABLED) { ++ size = lpcmDMAManager->DMASize * sizeof(unsigned int) + ++ dev_priv->agp_size; ++ alignedoffset = 0; ++ entries = (size + PAGE_SIZE - 1) / PAGE_SIZE; ++ addrlinear = ++ (unsigned int *)dev_priv->pcie_vmalloc_nocache; ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = ++ GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c &= (~0x80); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); ++ do { ++ sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c5); ++ } while (sr6f & 0x80); ++ ++ for (i = 0; i < entries; i++) ++ writel(page_to_pfn(vmalloc_to_page( ++ (void *)addrlinear + PAGE_SIZE * i)) & ++ 0x3fffffff, pGARTTable + i + alignedoffset); ++ ++ sr6f |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = ++ GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ } ++ ++ } ++ ++ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) ++ SetAGPDoubleCmd_inv(dev); ++ else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) ++ SetAGPRingCmdRegs_inv(dev); ++ ++ return ; ++} ++ ++static unsigned int ++InitPCIEGART(struct drm_via_chrome9_private *dev_priv) ++{ ++ unsigned int *pGARTTable; ++ unsigned int i, entries, GARTOffset; ++ unsigned char sr6a, sr6b, sr6c, sr6f, sr7b; ++ ++ if (!dev_priv->pagetable_map.pagetable_size) ++ return 0; ++ ++ entries = dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int); ++ ++ pGARTTable = ++ ioremap_nocache(dev_priv->fb_base_address + ++ dev_priv->pagetable_map.pagetable_offset, ++ dev_priv->pagetable_map.pagetable_size); ++ if (pGARTTable) ++ dev_priv->pagetable_map.pagetable_handle = pGARTTable; ++ else ++ return 0; ++ ++ /*set gart table base */ ++ GARTOffset = dev_priv->pagetable_map.pagetable_offset; ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c &= (~0x80); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ sr6a = (unsigned char) ((GARTOffset & 0xff000) >> 12); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6a); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6a); ++ ++ sr6b = (unsigned char) ((GARTOffset & 0xff00000) >> 20); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6b); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6b); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c |= ((unsigned char) ((GARTOffset >> 28) & 0x01)); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x7b); ++ sr7b = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr7b &= (~0x0f); ++ sr7b |= ProtectSizeValue(dev_priv->pagetable_map.pagetable_size); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr7b); ++ ++ for (i = 0; i < entries; i++) ++ writel(0x80000000, pGARTTable + i); ++ /*flush */ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); ++ do { ++ sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ } ++ while (sr6f & 0x80) ++ ; ++ ++ sr6f |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ return 1; ++} ++ ++ ++static unsigned int * ++AllocAndBindPCIEMemory(struct drm_via_chrome9_private *dev_priv, ++ unsigned int size, unsigned int offset) ++{ ++ unsigned int *addrlinear; ++ unsigned int *pGARTTable; ++ unsigned int entries, alignedoffset, i; ++ unsigned char sr6c, sr6f; ++ ++ if (!size) ++ return NULL; ++ ++ entries = (size + PAGE_SIZE - 1) / PAGE_SIZE; ++ alignedoffset = (offset + PAGE_SIZE - 1) / PAGE_SIZE; ++ ++ if ((entries + alignedoffset) > ++ (dev_priv->pagetable_map.pagetable_size / sizeof(unsigned int))) ++ return NULL; ++ ++ addrlinear = ++ __vmalloc(entries * PAGE_SIZE, GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_NOCACHE); ++ ++ if (!addrlinear) ++ return NULL; ++ ++ pGARTTable = dev_priv->pagetable_map.pagetable_handle; ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c &= (~0x80); ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6f); ++ do { ++ sr6f = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ } ++ while (sr6f & 0x80) ++ ; ++ ++ for (i = 0; i < entries; i++) ++ writel(page_to_pfn ++ (vmalloc_to_page((void *) addrlinear + PAGE_SIZE * i)) & ++ 0x3fffffff, pGARTTable + i + alignedoffset); ++ ++ sr6f |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6f); ++ ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ sr6c |= 0x80; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ ++ return addrlinear; ++ ++} ++ ++void ++SetAGPDoubleCmd_inv(struct drm_device *dev) ++{ ++ /* we now don't use double buffer */ ++ return; ++} ++ ++void ++SetAGPRingCmdRegs_inv(struct drm_device *dev) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager; ++ unsigned int AGPBufLinearBase = 0, AGPBufPhysicalBase = 0; ++ unsigned long *pFree; ++ unsigned int dwStart, dwEnd, dwPause, AGPCurrAddr, AGPCurStat, CurrAGP; ++ unsigned int dwReg60, dwReg61, dwReg62, dwReg63, ++ dwReg64, dwReg65, dwJump; ++ ++ lpcmDMAManager->pFree = lpcmDMAManager->pBeg; ++ ++ AGPBufLinearBase = (unsigned int) lpcmDMAManager->addr_linear; ++ AGPBufPhysicalBase = ++ (dev_priv->chip_agp == ++ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + ++ lpcmDMAManager->pPhysical; ++ /*add shadow offset */ ++ ++ CurrAGP = ++ GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); ++ AGPCurStat = ++ GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_STATUS); ++ ++ if (AGPCurStat & INV_AGPCMD_InPause) { ++ AGPCurrAddr = ++ GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ pFree = (unsigned long *) (AGPBufLinearBase + AGPCurrAddr - ++ AGPBufPhysicalBase); ++ ADDCmdHeader2_INVI(pFree, INV_REG_CR_TRANS, INV_ParaType_Dummy); ++ if (dev_priv->chip_sub_index == CHIP_H6S2) ++ do { ++ ADDCmdData_INVI(pFree, 0xCCCCCCC0); ++ ADDCmdData_INVI(pFree, 0xDDD00000); ++ } ++ while ((u32)((unsigned int) pFree) & 0x7f) ++ ; ++ /*for 8*128bit aligned */ ++ else ++ do { ++ ADDCmdData_INVI(pFree, 0xCCCCCCC0); ++ ADDCmdData_INVI(pFree, 0xDDD00000); ++ } ++ while ((u32) ((unsigned int) pFree) & 0x1f) ++ ; ++ /*for 256bit aligned */ ++ dwPause = ++ (u32) (((unsigned int) pFree) - AGPBufLinearBase + ++ AGPBufPhysicalBase - 16); ++ ++ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); ++ dwReg65 = ++ INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | ++ INV_HAGPBpID_STOP; ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ dwReg64); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ dwReg65); ++ ++ while (GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_ENG_STATUS) & INV_ENG_BUSY_ALL) ++ ; ++ } ++ dwStart = ++ (u32) ((unsigned int) lpcmDMAManager->pBeg - AGPBufLinearBase + ++ AGPBufPhysicalBase); ++ dwEnd = (u32) ((unsigned int) lpcmDMAManager->pEnd - AGPBufLinearBase + ++ AGPBufPhysicalBase); ++ ++ lpcmDMAManager->pFree = lpcmDMAManager->pBeg; ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, ++ INV_ParaType_Dummy); ++ do { ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0); ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000); ++ } ++ while ((u32)((unsigned long *) lpcmDMAManager->pFree) & 0x7f) ++ ; ++ } ++ dwJump = 0xFFFFFFF0; ++ dwPause = ++ (u32)(((unsigned int) lpcmDMAManager->pFree) - ++ 16 - AGPBufLinearBase + AGPBufPhysicalBase); ++ ++ DRM_DEBUG("dwStart = %08x, dwEnd = %08x, dwPause = %08x\n", dwStart, ++ dwEnd, dwPause); ++ ++ dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart); ++ dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart); ++ dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd); ++ dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd); ++ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); ++ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; ++ ++ if (dev_priv->chip_sub_index == CHIP_H6S2) ++ dwReg60 |= 0x01; ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump)); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump)); ++ ++ /* Trigger AGP cycle */ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig); ++ ++ /*for debug */ ++ CurrAGP = ++ GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); ++ ++ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; ++} ++ ++/* Do hw intialization and determine whether to use dma or mmio to ++talk with hw */ ++int ++via_chrome9_hw_init(struct drm_device *dev, ++ struct drm_via_chrome9_init *init) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ unsigned retval = 0; ++ unsigned int *pGARTTable, *addrlinear = NULL; ++ int pages; ++ struct drm_clb_event_tag_info *event_tag_info; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL; ++ ++ if (init->chip_agp == CHIP_PCIE) { ++ dev_priv->pagetable_map.pagetable_offset = ++ init->garttable_offset; ++ dev_priv->pagetable_map.pagetable_size = init->garttable_size; ++ dev_priv->agp_size = init->agp_tex_size; ++ /*Henry :prepare for PCIE texture buffer */ ++ } else { ++ dev_priv->pagetable_map.pagetable_offset = 0; ++ dev_priv->pagetable_map.pagetable_size = 0; ++ } ++ ++ dev_priv->dma_manager = ++ kmalloc(sizeof(struct drm_via_chrome9_DMA_manager), GFP_KERNEL); ++ if (!dev_priv->dma_manager) { ++ DRM_ERROR("could not allocate system for dma_manager!\n"); ++ return -ENOMEM; ++ } ++ ++ lpcmDMAManager = ++ (struct drm_via_chrome9_DMA_manager *) dev_priv->dma_manager; ++ ((struct drm_via_chrome9_DMA_manager *) ++ dev_priv->dma_manager)->DMASize = init->DMA_size; ++ ((struct drm_via_chrome9_DMA_manager *) ++ dev_priv->dma_manager)->pPhysical = init->DMA_phys_address; ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000); ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x06000000); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x07100000); ++ } else { ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x02000000); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x03100000); ++ } ++ ++ /* Specify fence command read back ID */ ++ /* Default the read back ID is CR */ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ INV_SubA_HSetRBGID | INV_HSetRBGID_CR); ++ ++ DRM_DEBUG("begin to init\n"); ++ ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ dev_priv->pcie_vmalloc_nocache = 0; ++ if (dev_priv->pagetable_map.pagetable_size) ++ retval = InitPCIEGART(dev_priv); ++ ++ if (retval && dev_priv->drm_agp_type != DRM_AGP_DISABLED) { ++ addrlinear = ++ AllocAndBindPCIEMemory(dev_priv, ++ lpcmDMAManager->DMASize + ++ dev_priv->agp_size, 0); ++ if (addrlinear) { ++ dev_priv->pcie_vmalloc_nocache = (unsigned long) ++ addrlinear; ++ } else { ++ dev_priv->bci_buffer = ++ vmalloc(MAX_BCI_BUFFER_SIZE); ++ dev_priv->drm_agp_type = DRM_AGP_DISABLED; ++ } ++ } else { ++ dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE); ++ dev_priv->drm_agp_type = DRM_AGP_DISABLED; ++ } ++ } else { ++ if (dev_priv->drm_agp_type != DRM_AGP_DISABLED) { ++ pGARTTable = NULL; ++ addrlinear = (unsigned int *) ++ ioremap(dev->agp->base + ++ lpcmDMAManager->pPhysical, ++ lpcmDMAManager->DMASize); ++ dev_priv->bci_buffer = NULL; ++ } else { ++ dev_priv->bci_buffer = vmalloc(MAX_BCI_BUFFER_SIZE); ++ /*Homer, BCI path always use this block of memory8 */ ++ } ++ } ++ ++ /*till here we have known whether support dma or not */ ++ pages = dev->sg->pages; ++ event_tag_info = vmalloc(sizeof(struct drm_clb_event_tag_info)); ++ memset(event_tag_info, 0, sizeof(struct drm_clb_event_tag_info)); ++ if (!event_tag_info) ++ return DRM_ERROR(" event_tag_info allocate error!"); ++ ++ /* aligned to 16k alignment */ ++ event_tag_info->linear_address = ++ (int ++ *) (((unsigned int) dev_priv->shadow_map.shadow_handle + ++ 0x3fff) & 0xffffc000); ++ event_tag_info->event_tag_linear_address = ++ event_tag_info->linear_address + 3; ++ dev_priv->event_tag_info = (void *) event_tag_info; ++ dev_priv->max_apertures = NUMBER_OF_APERTURES_CLB; ++ ++ /* Initialize DMA data structure */ ++ lpcmDMAManager->DMASize /= sizeof(unsigned int); ++ lpcmDMAManager->pBeg = addrlinear; ++ lpcmDMAManager->pFree = lpcmDMAManager->pBeg; ++ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pBeg; ++ lpcmDMAManager->pInUseByHW = lpcmDMAManager->pBeg; ++ lpcmDMAManager->LastIssuedEventTag = (unsigned int) (unsigned long *) ++ lpcmDMAManager->pBeg; ++ lpcmDMAManager->ppInUseByHW = ++ (unsigned int **) ((char *) (dev_priv->mmio->handle) + ++ INV_RB_AGPCMD_CURRADDR); ++ lpcmDMAManager->bDMAAgp = dev_priv->chip_agp; ++ lpcmDMAManager->addr_linear = (unsigned int *) addrlinear; ++ ++ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) { ++ lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize >> 1; ++ lpcmDMAManager->pEnd = ++ lpcmDMAManager->addr_linear + ++ (lpcmDMAManager->DMASize >> 1) - 1; ++ SetAGPDoubleCmd_inv(dev); ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ DRM_INFO("DMA buffer initialized finished. "); ++ DRM_INFO("Use PCIE Double Buffer type!\n"); ++ DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n", ++ lpcmDMAManager->DMASize << 2); ++ } else { ++ DRM_INFO("DMA buffer initialized finished. "); ++ DRM_INFO("Use AGP Double Buffer type!\n"); ++ DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n", ++ lpcmDMAManager->DMASize << 2); ++ } ++ } else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) { ++ lpcmDMAManager->MaxKickoffSize = lpcmDMAManager->DMASize; ++ lpcmDMAManager->pEnd = ++ lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize; ++ SetAGPRingCmdRegs_inv(dev); ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ DRM_INFO("DMA buffer initialized finished. \n"); ++ DRM_INFO("Use PCIE Ring Buffer type!"); ++ DRM_INFO("Total PCIE DMA buffer size = %8d bytes. \n", ++ lpcmDMAManager->DMASize << 2); ++ } else { ++ DRM_INFO("DMA buffer initialized finished. "); ++ DRM_INFO("Use AGP Ring Buffer type!\n"); ++ DRM_INFO("Total AGP DMA buffer size = %8d bytes. \n", ++ lpcmDMAManager->DMASize << 2); ++ } ++ } else if (dev_priv->drm_agp_type == DRM_AGP_DISABLED) { ++ lpcmDMAManager->MaxKickoffSize = 0x0; ++ if (dev_priv->chip_sub_index == CHIP_H6S2) ++ DRM_INFO("PCIE init failed! Use PCI\n"); ++ else ++ DRM_INFO("AGP init failed! Use PCI\n"); ++ } ++ return 0; ++} ++ ++static void ++kickoff_bci_inv(struct drm_device *dev, ++ struct drm_via_chrome9_flush *dma_info) ++{ ++ u32 HdType, dwQWCount, i, dwCount, Addr1, Addr2, SWPointer, ++ SWPointerEnd; ++ unsigned long *pCmdData; ++ int result; ++ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ /*pCmdData = __s3gke_vmalloc(dma_info->cmd_size<<2); */ ++ pCmdData = dev_priv->bci_buffer; ++ ++ if (!pCmdData) ++ return; ++ result = copy_from_user((int *) pCmdData, dma_info->usermode_dma_buf, ++ dma_info->cmd_size << 2); ++ if (result) { ++ DRM_ERROR("In function kickoff_bci_inv,\ ++ copy_from_user is fault. \n"); ++ return ; ++ } ++#if VIA_CHROME9_VERIFY_ENABLE ++ result = via_chrome9_verify_command_stream( ++ (const uint32_t *)pCmdData, dma_info->cmd_size << 2, ++ dev, dev_priv->chip_sub_index == CHIP_H6S2 ? 0 : 1); ++ if (result) { ++ DRM_ERROR("The command has the security issue \n"); ++ return ; ++ } ++#endif ++ SWPointer = 0; ++ SWPointerEnd = (u32) dma_info->cmd_size; ++ while (SWPointer < SWPointerEnd) { ++ HdType = pCmdData[SWPointer] & INV_AGPHeader_MASK; ++ switch (HdType) { ++ case INV_AGPHeader0: ++ case INV_AGPHeader5: ++ dwQWCount = pCmdData[SWPointer + 1]; ++ SWPointer += 4; ++ ++ for (i = 0; i < dwQWCount; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ pCmdData[SWPointer], ++ pCmdData[SWPointer + 1]); ++ SWPointer += 2; ++ } ++ break; ++ ++ case INV_AGPHeader1: ++ dwCount = pCmdData[SWPointer + 1]; ++ Addr1 = 0x0; ++ SWPointer += 4; /* skip 128-bit. */ ++ ++ for (; dwCount > 0; dwCount--, SWPointer++, ++ Addr1 += 4) { ++ SetMMIORegister(dev_priv->hostBlt->handle, ++ Addr1, pCmdData[SWPointer]); ++ } ++ break; ++ ++ case INV_AGPHeader4: ++ dwCount = pCmdData[SWPointer + 1]; ++ Addr1 = pCmdData[SWPointer] & 0x0000FFFF; ++ SWPointer += 4; /* skip 128-bit. */ ++ ++ for (; dwCount > 0; dwCount--, SWPointer++) ++ SetMMIORegister(dev_priv->mmio->handle, Addr1, ++ pCmdData[SWPointer]); ++ break; ++ ++ case INV_AGPHeader2: ++ Addr1 = pCmdData[SWPointer + 1] & 0xFFFF; ++ Addr2 = pCmdData[SWPointer] & 0xFFFF; ++ ++ /* Write first data (either ParaType or whatever) to ++ Addr1 */ ++ SetMMIORegister(dev_priv->mmio->handle, Addr1, ++ pCmdData[SWPointer + 2]); ++ SWPointer += 4; ++ ++ /* The following data are all written to Addr2, ++ until another header is met */ ++ while (!is_agp_header(pCmdData[SWPointer]) ++ && (SWPointer < SWPointerEnd)) { ++ SetMMIORegister(dev_priv->mmio->handle, Addr2, ++ pCmdData[SWPointer]); ++ SWPointer++; ++ } ++ break; ++ ++ case INV_AGPHeader3: ++ Addr1 = pCmdData[SWPointer] & 0xFFFF; ++ Addr2 = Addr1 + 4; ++ dwCount = pCmdData[SWPointer + 1]; ++ ++ /* Write first data (either ParaType or whatever) to ++ Addr1 */ ++ SetMMIORegister(dev_priv->mmio->handle, Addr1, ++ pCmdData[SWPointer + 2]); ++ SWPointer += 4; ++ ++ for (i = 0; i < dwCount; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, Addr2, ++ pCmdData[SWPointer]); ++ SWPointer++; ++ } ++ break; ++ ++ case INV_AGPHeader6: ++ break; ++ ++ case INV_AGPHeader7: ++ break; ++ ++ default: ++ SWPointer += 4; /* Advance to next header */ ++ } ++ ++ SWPointer = (SWPointer + 3) & ~3; ++ } ++} ++ ++void ++kickoff_dma_db_inv(struct drm_device *dev) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ ++ u32 BufferSize = (u32) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg); ++ ++ unsigned int AGPBufLinearBase = ++ (unsigned int) lpcmDMAManager->addr_linear; ++ unsigned int AGPBufPhysicalBase = ++ (unsigned int) dev->agp->base + lpcmDMAManager->pPhysical; ++ /*add shadow offset */ ++ ++ unsigned int dwStart, dwEnd, dwPause; ++ unsigned int dwReg60, dwReg61, dwReg62, dwReg63, dwReg64, dwReg65; ++ unsigned int CR_Status; ++ ++ if (BufferSize == 0) ++ return; ++ ++ /* 256-bit alignment of AGP pause address */ ++ if ((u32) ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) { ++ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, ++ INV_ParaType_Dummy); ++ do { ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC0); ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xDDD00000); ++ } ++ while (((unsigned int) lpcmDMAManager->pFree) & 0x1f) ++ ; ++ } ++ ++ dwStart = ++ (u32) (unsigned long *)lpcmDMAManager->pBeg - ++ AGPBufLinearBase + AGPBufPhysicalBase; ++ dwEnd = (u32) (unsigned long *)lpcmDMAManager->pEnd - ++ AGPBufLinearBase + AGPBufPhysicalBase; ++ dwPause = ++ (u32)(unsigned long *)lpcmDMAManager->pFree - ++ AGPBufLinearBase + AGPBufPhysicalBase - 4; ++ ++ dwReg60 = INV_SubA_HAGPBstL | INV_HWBasL(dwStart); ++ dwReg61 = INV_SubA_HAGPBstH | INV_HWBasH(dwStart); ++ dwReg62 = INV_SubA_HAGPBendL | INV_HWBasL(dwEnd); ++ dwReg63 = INV_SubA_HAGPBendH | INV_HWBasH(dwEnd); ++ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); ++ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_STOP; ++ ++ /* wait CR idle */ ++ CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS); ++ while (CR_Status & INV_ENG_BUSY_CR) ++ CR_Status = ++ GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_ENG_STATUS); ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg60); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg61); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg62); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg63); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); ++ ++ /* Trigger AGP cycle */ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ INV_SubA_HFthRCM | INV_HFthRCM_10 | INV_HAGPBTrig); ++ ++ if (lpcmDMAManager->pBeg == lpcmDMAManager->addr_linear) { ++ /* The second AGP command buffer */ ++ lpcmDMAManager->pBeg = ++ lpcmDMAManager->addr_linear + ++ (lpcmDMAManager->DMASize >> 2); ++ lpcmDMAManager->pEnd = ++ lpcmDMAManager->addr_linear + lpcmDMAManager->DMASize; ++ lpcmDMAManager->pFree = lpcmDMAManager->pBeg; ++ } else { ++ /* The first AGP command buffer */ ++ lpcmDMAManager->pBeg = lpcmDMAManager->addr_linear; ++ lpcmDMAManager->pEnd = ++ lpcmDMAManager->addr_linear + ++ (lpcmDMAManager->DMASize / 2) - 1; ++ lpcmDMAManager->pFree = lpcmDMAManager->pBeg; ++ } ++ CR_Status = GetMMIORegister(dev_priv->mmio->handle, INV_RB_ENG_STATUS); ++} ++ ++ ++void ++kickoff_dma_ring_inv(struct drm_device *dev) ++{ ++ unsigned int dwPause, dwReg64, dwReg65; ++ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ ++ unsigned int AGPBufLinearBase = ++ (unsigned int) lpcmDMAManager->addr_linear; ++ unsigned int AGPBufPhysicalBase = ++ (dev_priv->chip_agp == ++ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + ++ lpcmDMAManager->pPhysical; ++ /*add shadow offset */ ++ ++ /* 256-bit alignment of AGP pause address */ ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ if ((u32) ++ ((unsigned long *) lpcmDMAManager->pFree) & 0x7f) { ++ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, ++ INV_REG_CR_TRANS, ++ INV_ParaType_Dummy); ++ do { ++ ADDCmdData_INVI(lpcmDMAManager->pFree, ++ 0xCCCCCCC0); ++ ADDCmdData_INVI(lpcmDMAManager->pFree, ++ 0xDDD00000); ++ } ++ while ((u32)((unsigned long *) lpcmDMAManager->pFree) & ++ 0x7f) ++ ; ++ } ++ } else { ++ if ((u32) ++ ((unsigned long *) lpcmDMAManager->pFree) & 0x1f) { ++ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, ++ INV_REG_CR_TRANS, ++ INV_ParaType_Dummy); ++ do { ++ ADDCmdData_INVI(lpcmDMAManager->pFree, ++ 0xCCCCCCC0); ++ ADDCmdData_INVI(lpcmDMAManager->pFree, ++ 0xDDD00000); ++ } ++ while ((u32)((unsigned long *) lpcmDMAManager->pFree) & ++ 0x1f) ++ ; ++ } ++ } ++ ++ ++ dwPause = (u32) ((unsigned long *) lpcmDMAManager->pFree) ++ - AGPBufLinearBase + AGPBufPhysicalBase - 16; ++ ++ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); ++ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); ++ ++ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; ++} ++ ++static int ++waitchipidle_inv(struct drm_via_chrome9_private *dev_priv) ++{ ++ unsigned int count = 50000; ++ unsigned int eng_status; ++ unsigned int engine_busy; ++ ++ do { ++ eng_status = ++ GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_ENG_STATUS); ++ engine_busy = eng_status & INV_ENG_BUSY_ALL; ++ count--; ++ } ++ while (engine_busy && count) ++ ; ++ if (count && engine_busy == 0) ++ return 0; ++ return -1; ++} ++ ++void ++get_space_db_inv(struct drm_device *dev, ++ struct cmd_get_space *lpcmGetSpaceData) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ ++ unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize; ++ if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) { ++ DRM_INFO("too big DMA buffer request!!!\n"); ++ via_chrome9ke_assert(0); ++ *lpcmGetSpaceData->pCmdData = (unsigned int) NULL; ++ return; ++ } ++ ++ if ((lpcmDMAManager->pFree + dwRequestSize) > ++ (lpcmDMAManager->pEnd - INV_CMDBUF_THRESHOLD * 2)) ++ kickoff_dma_db_inv(dev); ++ ++ *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree; ++} ++ ++void ++RewindRingAGP_inv(struct drm_device *dev) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ ++ unsigned int AGPBufLinearBase = ++ (unsigned int) lpcmDMAManager->addr_linear; ++ unsigned int AGPBufPhysicalBase = ++ (dev_priv->chip_agp == ++ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + ++ lpcmDMAManager->pPhysical; ++ /*add shadow offset */ ++ ++ unsigned int dwPause, dwJump; ++ unsigned int dwReg66, dwReg67; ++ unsigned int dwReg64, dwReg65; ++ ++ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, ++ INV_ParaType_Dummy); ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); ++ if (dev_priv->chip_sub_index == CHIP_H6S2) ++ while ((unsigned int) lpcmDMAManager->pFree & 0x7F) ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); ++ else ++ while ((unsigned int) lpcmDMAManager->pFree & 0x1F) ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCCCCCCC7); ++ dwJump = ((u32) ((unsigned long *) lpcmDMAManager->pFree)) ++ - AGPBufLinearBase + AGPBufPhysicalBase - 16; ++ ++ lpcmDMAManager->pFree = lpcmDMAManager->pBeg; ++ ++ dwPause = ((u32) ((unsigned long *) lpcmDMAManager->pFree)) ++ - AGPBufLinearBase + AGPBufPhysicalBase - 16; ++ ++ dwReg64 = INV_SubA_HAGPBpL | INV_HWBasL(dwPause); ++ dwReg65 = INV_SubA_HAGPBpID | INV_HWBasH(dwPause) | INV_HAGPBpID_PAUSE; ++ ++ dwReg66 = INV_SubA_HAGPBjumpL | INV_HWBasL(dwJump); ++ dwReg67 = INV_SubA_HAGPBjumpH | INV_HWBasH(dwJump); ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg66); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg67); ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg64); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, dwReg65); ++ lpcmDMAManager->pInUseBySW = lpcmDMAManager->pFree; ++} ++ ++ ++void ++get_space_ring_inv(struct drm_device *dev, ++ struct cmd_get_space *lpcmGetSpaceData) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ unsigned int dwUnFlushed; ++ unsigned int dwRequestSize = lpcmGetSpaceData->dwRequestSize; ++ ++ unsigned int AGPBufLinearBase = ++ (unsigned int) lpcmDMAManager->addr_linear; ++ unsigned int AGPBufPhysicalBase = ++ (dev_priv->chip_agp == ++ CHIP_PCIE) ? 0 : (unsigned int) dev->agp->base + ++ lpcmDMAManager->pPhysical; ++ /*add shadow offset */ ++ u32 BufStart, BufEnd, CurSW, CurHW, NextSW, BoundaryCheck; ++ ++ dwUnFlushed = ++ (unsigned int) (lpcmDMAManager->pFree - lpcmDMAManager->pBeg); ++ /*default bEnableModuleSwitch is on for metro,is off for rest */ ++ /*cmHW_Module_Switch is context-wide variable which is enough for 2d/3d ++ switch in a context. */ ++ /*But we must keep the dma buffer being wrapped head and tail by 3d cmds ++ when it is kicked off to kernel mode. */ ++ /*Get DMA Space (If requested, or no BCI space and BCI not forced. */ ++ ++ if (dwRequestSize > lpcmDMAManager->MaxKickoffSize) { ++ DRM_INFO("too big DMA buffer request!!!\n"); ++ via_chrome9ke_assert(0); ++ *lpcmGetSpaceData->pCmdData = 0; ++ return; ++ } ++ ++ if (dwUnFlushed + dwRequestSize > lpcmDMAManager->MaxKickoffSize) ++ kickoff_dma_ring_inv(dev); ++ ++ BufStart = ++ (u32)((unsigned int) lpcmDMAManager->pBeg) - AGPBufLinearBase + ++ AGPBufPhysicalBase; ++ BufEnd = (u32)((unsigned int) lpcmDMAManager->pEnd) - AGPBufLinearBase + ++ AGPBufPhysicalBase; ++ dwRequestSize = lpcmGetSpaceData->dwRequestSize << 2; ++ NextSW = (u32) ((unsigned int) lpcmDMAManager->pFree) + dwRequestSize + ++ INV_CMDBUF_THRESHOLD * 8 - AGPBufLinearBase + ++ AGPBufPhysicalBase; ++ ++ CurSW = (u32)((unsigned int) lpcmDMAManager->pFree) - AGPBufLinearBase + ++ AGPBufPhysicalBase; ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, INV_RB_AGPCMD_CURRADDR); ++ ++ if (NextSW >= BufEnd) { ++ kickoff_dma_ring_inv(dev); ++ CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) - ++ AGPBufLinearBase + AGPBufPhysicalBase; ++ /* make sure the last rewind is completed */ ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ while (CurHW > CurSW) ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ /* Sometime the value read from HW is unreliable, ++ so need double confirm. */ ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ while (CurHW > CurSW) ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ BoundaryCheck = ++ BufStart + dwRequestSize + INV_QW_PAUSE_ALIGN * 16; ++ if (BoundaryCheck >= BufEnd) ++ /* If an empty command buffer can't hold ++ the request data. */ ++ via_chrome9ke_assert(0); ++ else { ++ /* We need to guarntee the new commands have no chance ++ to override the unexected commands or wait until there ++ is no unexecuted commands in agp buffer */ ++ if (CurSW <= BoundaryCheck) { ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ while (CurHW < CurSW) ++ CurHW = GetMMIORegister( ++ dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ /*Sometime the value read from HW is unreliable, ++ so need double confirm. */ ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ while (CurHW < CurSW) { ++ CurHW = GetMMIORegister( ++ dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ } ++ RewindRingAGP_inv(dev); ++ CurSW = (u32) ((unsigned long *) ++ lpcmDMAManager->pFree) - ++ AGPBufLinearBase + AGPBufPhysicalBase; ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ /* Waiting until hw pointer jump to start ++ and hw pointer will */ ++ /* equal to sw pointer */ ++ while (CurHW != CurSW) { ++ CurHW = GetMMIORegister( ++ dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ } ++ } else { ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ ++ while (CurHW <= BoundaryCheck) { ++ CurHW = GetMMIORegister( ++ dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ } ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ /* Sometime the value read from HW is ++ unreliable, so need double confirm. */ ++ while (CurHW <= BoundaryCheck) { ++ CurHW = GetMMIORegister( ++ dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ } ++ RewindRingAGP_inv(dev); ++ } ++ } ++ } else { ++ /* no need to rewind Ensure unexecuted agp commands will ++ not be override by new ++ agp commands */ ++ CurSW = (u32) ((unsigned int) lpcmDMAManager->pFree) - ++ AGPBufLinearBase + AGPBufPhysicalBase; ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ ++ while ((CurHW > CurSW) && (CurHW <= NextSW)) ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ ++ /* Sometime the value read from HW is unreliable, ++ so need double confirm. */ ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ while ((CurHW > CurSW) && (CurHW <= NextSW)) ++ CurHW = GetMMIORegister(dev_priv->mmio->handle, ++ INV_RB_AGPCMD_CURRADDR); ++ } ++ /*return the space handle */ ++ *lpcmGetSpaceData->pCmdData = (unsigned int) lpcmDMAManager->pFree; ++} ++ ++void ++release_space_inv(struct drm_device *dev, ++ struct cmd_release_space *lpcmReleaseSpaceData) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = ++ dev_priv->dma_manager; ++ unsigned int dwReleaseSize = lpcmReleaseSpaceData->dwReleaseSize; ++ int i = 0; ++ ++ lpcmDMAManager->pFree += dwReleaseSize; ++ ++ /* aligned address */ ++ while (((unsigned int) lpcmDMAManager->pFree) & 0xF) { ++ /* not in 4 unsigned ints (16 Bytes) align address, ++ insert NULL Commands */ ++ *lpcmDMAManager->pFree++ = NULL_COMMAND_INV[i & 0x3]; ++ i++; ++ } ++ ++ if ((dev_priv->chip_sub_index == CHIP_H5 || ++ dev_priv->chip_sub_index == CHIP_H6S2) && ++ (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) { ++ ADDCmdHeader2_INVI(lpcmDMAManager->pFree, INV_REG_CR_TRANS, ++ INV_ParaType_Dummy); ++ for (i = 0; i < NULLCOMMANDNUMBER; i++) ++ ADDCmdData_INVI(lpcmDMAManager->pFree, 0xCC000000); ++ } ++} ++ ++int ++via_chrome9_ioctl_flush(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_flush *dma_info = data; ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ int ret = 0; ++ int result = 0; ++ struct cmd_get_space getspace; ++ struct cmd_release_space releasespace; ++ unsigned long *pCmdData = NULL; ++ ++ switch (dma_info->dma_cmd_type) { ++ /* Copy DMA buffer to BCI command buffer */ ++ case flush_bci: ++ case flush_bci_and_wait: ++ if (dma_info->cmd_size <= 0) ++ return 0; ++ if (dma_info->cmd_size > MAX_BCI_BUFFER_SIZE) { ++ DRM_INFO("too big BCI space request!!!\n"); ++ return 0; ++ } ++ ++ kickoff_bci_inv(dev, dma_info); ++ waitchipidle_inv(dev_priv); ++ break; ++ /* Use DRM DMA buffer manager to kick off DMA directly */ ++ case dma_kickoff: ++ break; ++ ++ /* Copy user mode DMA buffer to kernel DMA buffer, ++ then kick off DMA */ ++ case flush_dma_buffer: ++ case flush_dma_and_wait: ++ if (dma_info->cmd_size <= 0) ++ return 0; ++ ++ getspace.dwRequestSize = dma_info->cmd_size; ++ if ((dev_priv->chip_sub_index == CHIP_H5 || ++ dev_priv->chip_sub_index == CHIP_H6S2) && ++ (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER)) ++ getspace.dwRequestSize += (NULLCOMMANDNUMBER + 4); ++ /*henry:Patch for VT3293 agp ring buffer stability */ ++ getspace.pCmdData = (unsigned int *) &pCmdData; ++ ++ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) ++ get_space_db_inv(dev, &getspace); ++ else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) ++ get_space_ring_inv(dev, &getspace); ++ if (pCmdData) { ++ /*copy data from userspace to kernel-dma-agp buffer */ ++ result = copy_from_user((int *) ++ pCmdData, ++ dma_info->usermode_dma_buf, ++ dma_info->cmd_size << 2); ++ if (result) { ++ DRM_ERROR("In function via_chrome9_ioctl_flush,\ ++ copy_from_user is fault. \n"); ++ return -EINVAL; ++ } ++ ++#if VIA_CHROME9_VERIFY_ENABLE ++ result = via_chrome9_verify_command_stream( ++ (const uint32_t *)pCmdData, dma_info->cmd_size << 2, ++ dev, dev_priv->chip_sub_index == CHIP_H6S2 ? 0 : 1); ++ if (result) { ++ DRM_ERROR("The user command has security issue.\n"); ++ return -EINVAL; ++ } ++#endif ++ ++ releasespace.dwReleaseSize = dma_info->cmd_size; ++ release_space_inv(dev, &releasespace); ++ if (dev_priv->drm_agp_type == DRM_AGP_DOUBLE_BUFFER) ++ kickoff_dma_db_inv(dev); ++ else if (dev_priv->drm_agp_type == DRM_AGP_RING_BUFFER) ++ kickoff_dma_ring_inv(dev); ++ ++ if (dma_info->dma_cmd_type == flush_dma_and_wait) ++ waitchipidle_inv(dev_priv); ++ } else { ++ DRM_INFO("No enough DMA space"); ++ ret = -ENOMEM; ++ } ++ break; ++ ++ default: ++ DRM_INFO("Invalid DMA buffer type"); ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++} ++ ++int ++via_chrome9_ioctl_free(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++int ++via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ ++ waitchipidle_inv(dev_priv); ++ /* maybe_bug here, do we always return 0 */ ++ return 0; ++} ++ ++int ++via_chrome9_ioctl_flush_cache(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return 0; ++} +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_dma.h +@@ -0,0 +1,69 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#ifndef _VIA_CHROME9_DMA_H_ ++#define _VIA_CHROME9_DMA_H_ ++ ++#define MAX_BCI_BUFFER_SIZE (16 * 1024 * 1024) ++ ++enum cmd_request_type { ++ CM_REQUEST_BCI, ++ CM_REQUEST_DMA, ++ CM_REQUEST_RB, ++ CM_REQUEST_RB_FORCED_DMA, ++ CM_REQUEST_NOTAVAILABLE ++}; ++ ++struct cmd_get_space { ++ unsigned int dwRequestSize; ++ enum cmd_request_type hint; ++ __volatile__ unsigned int *pCmdData; ++}; ++ ++struct cmd_release_space { ++ unsigned int dwReleaseSize; ++}; ++ ++extern int via_chrome9_hw_init(struct drm_device *dev, ++ struct drm_via_chrome9_init *init); ++extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data, ++ struct drm_file *file_prev); ++extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_flush_cache(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_flush(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int via_chrome9_ioctl_free(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern unsigned int ProtectSizeValue(unsigned int size); ++extern void SetAGPDoubleCmd_inv(struct drm_device *dev); ++extern void SetAGPRingCmdRegs_inv(struct drm_device *dev); ++extern void via_chrome9_dma_init_inv(struct drm_device *dev); ++ ++#endif +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_drm.c +@@ -0,0 +1,950 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#include "drmP.h" ++#include "via_chrome9_drm.h" ++#include "via_chrome9_drv.h" ++#include "via_chrome9_mm.h" ++#include "via_chrome9_dma.h" ++#include "via_chrome9_3d_reg.h" ++ ++#define VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT 10 ++ ++void *via_chrome9_dev_v4l; ++void *via_chrome9_filepriv_v4l; ++ ++void __via_chrome9ke_udelay(unsigned long usecs) ++{ ++ unsigned long start; ++ unsigned long stop; ++ unsigned long period; ++ unsigned long wait_period; ++ struct timespec tval; ++ ++#ifdef NDELAY_LIMIT ++#define UDELAY_LIMIT (NDELAY_LIMIT/1000) /* supposed to be 10 msec */ ++#else ++#define UDELAY_LIMIT (10000) /* 10 msec */ ++#endif ++ ++ if (usecs > UDELAY_LIMIT) { ++ start = jiffies; ++ tval.tv_sec = usecs / 1000000; ++ tval.tv_nsec = (usecs - tval.tv_sec * 1000000) * 1000; ++ wait_period = timespec_to_jiffies(&tval); ++ do { ++ stop = jiffies; ++ ++ if (stop < start) ++ period = ((unsigned long)-1 - start) + stop + 1; ++ else ++ period = stop - start; ++ ++ } while (period < wait_period); ++ } else ++ udelay(usecs); /* delay value might get checked once again */ ++} ++ ++int via_chrome9_ioctl_process_exit(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++int via_chrome9_ioctl_restore_primary(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++void Initialize3DEngine(struct drm_via_chrome9_private *dev_priv) ++{ ++ int i; ++ unsigned int StageOfTexture; ++ ++ if (dev_priv->chip_sub_index == CHIP_H5 || ++ dev_priv->chip_sub_index == CHIP_H5S1) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ 0x00010000); ++ ++ for (i = 0; i <= 0x8A; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (unsigned int) i << 24); ++ } ++ ++ /* Initial Texture Stage Setting*/ ++ for (StageOfTexture = 0; StageOfTexture < 0xf; ++ StageOfTexture++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00020000 | 0x00000000 | ++ (StageOfTexture & 0xf)<<24)); ++ /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) = ++ (0x00020000 | HC_ParaSubType_Tex0 | (StageOfTexture & ++ 0xf)<<24);*/ ++ for (i = 0 ; i <= 0x30 ; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (unsigned int) i << 24); ++ } ++ } ++ ++ /* Initial Texture Sampler Setting*/ ++ for (StageOfTexture = 0; StageOfTexture < 0xf; ++ StageOfTexture++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00020000 | 0x00020000 | ++ (StageOfTexture & 0xf)<<24)); ++ /* *((unsigned int volatile*)(pMapIOPort+ ++ HC_REG_TRANS_SET)) = (0x00020000 | 0x00020000 | ++ ( StageOfTexture & 0xf)<<24);*/ ++ for (i = 0 ; i <= 0x30 ; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (unsigned int) i << 24); ++ } ++ } ++ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00020000 | 0xfe000000)); ++ /* *((unsigned int volatile*)(pMapIOPort+HC_REG_TRANS_SET)) = ++ (0x00020000 | HC_ParaSubType_TexGen);*/ ++ for (i = 0 ; i <= 0x13 ; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (unsigned int) i << 24); ++ /* *((unsigned int volatile*)(pMapIOPort+ ++ HC_REG_Hpara0)) = ((unsigned int) i << 24);*/ ++ } ++ ++ /* Initial Gamma Table Setting*/ ++ /* Initial Gamma Table Setting*/ ++ /* 5 + 4 = 9 (12) dwords*/ ++ /* sRGB texture is not directly support by H3 hardware. ++ We have to set the deGamma table for texture sampling.*/ ++ ++ /* degamma table*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x15000000)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (30 << 20) | (15 << 10) | (5))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((119 << 20) | (81 << 10) | (52))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((283 << 20) | (219 << 10) | (165))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((535 << 20) | (441 << 10) | (357))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((119 << 20) | (884 << 20) | (757 << 10) | ++ (640))); ++ ++ /* gamma table*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x17000000)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (13 << 20) | (13 << 10) | (13))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (26 << 20) | (26 << 10) | (26))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (39 << 20) | (39 << 10) | (39))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((51 << 20) | (51 << 10) | (51))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((71 << 20) | (71 << 10) | (71))); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (87 << 20) | (87 << 10) | (87)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (113 << 20) | (113 << 10) | (113)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (135 << 20) | (135 << 10) | (135)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (170 << 20) | (170 << 10) | (170)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (199 << 20) | (199 << 10) | (199)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (246 << 20) | (246 << 10) | (246)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (284 << 20) | (284 << 10) | (284)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (317 << 20) | (317 << 10) | (317)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (347 << 20) | (347 << 10) | (347)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (373 << 20) | (373 << 10) | (373)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (398 << 20) | (398 << 10) | (398)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (442 << 20) | (442 << 10) | (442)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (481 << 20) | (481 << 10) | (481)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (517 << 20) | (517 << 10) | (517)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (550 << 20) | (550 << 10) | (550)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (609 << 20) | (609 << 10) | (609)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (662 << 20) | (662 << 10) | (662)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (709 << 20) | (709 << 10) | (709)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (753 << 20) | (753 << 10) | (753)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (794 << 20) | (794 << 10) | (794)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (832 << 20) | (832 << 10) | (832)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (868 << 20) | (868 << 10) | (868)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (902 << 20) | (902 << 10) | (902)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (934 << 20) | (934 << 10) | (934)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (966 << 20) | (966 << 10) | (966)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (996 << 20) | (996 << 10) | (996)); ++ ++ ++ /* ++ For Interrupt Restore only All types of write through ++ regsiters should be write header data to hardware at ++ least before it can restore. H/W will automatically ++ record the header to write through state buffer for ++ resture usage. ++ By Jaren: ++ HParaType = 8'h03, HParaSubType = 8'h00 ++ 8'h11 ++ 8'h12 ++ 8'h14 ++ 8'h15 ++ 8'h17 ++ HParaSubType 8'h12, 8'h15 is initialized. ++ [HWLimit] ++ 1. All these write through registers can't be partial ++ update. ++ 2. All these write through must be AGP command ++ 16 entries : 4 128-bit data */ ++ ++ /* Initialize INV_ParaSubType_TexPal */ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x00000000)); ++ for (i = 0; i < 16; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00000000); ++ } ++ ++ /* Initialize INV_ParaSubType_4X4Cof */ ++ /* 32 entries : 8 128-bit data */ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x11000000)); ++ for (i = 0; i < 32; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00000000); ++ } ++ ++ /* Initialize INV_ParaSubType_StipPal */ ++ /* 5 entries : 2 128-bit data */ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x14000000)); ++ for (i = 0; i < (5+3); i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, 0x00000000); ++ } ++ ++ /* primitive setting & vertex format*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00040000 | 0x14000000)); ++ for (i = 0; i < 52; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, ((unsigned int) i << 24)); ++ } ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ 0x00fe0000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x4000840f); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x47000400); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x44000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x46000000); ++ ++ /* setting Misconfig*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ 0x00fe0000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00001004); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0800004b); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0a000049); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0b0000fb); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0c000001); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0d0000cb); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0e000009); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x10000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x110000ff); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x12000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x130000db); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x14000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x15000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x16000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x17000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x18000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x19000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x20000000); ++ } else if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ 0x00010000); ++ for (i = 0; i <= 0x9A; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (unsigned int) i << 24); ++ } ++ ++ /* Initial Texture Stage Setting*/ ++ for (StageOfTexture = 0; StageOfTexture <= 0xf; ++ StageOfTexture++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00020000 | 0x00000000 | ++ (StageOfTexture & 0xf)<<24)); ++ for (i = 0 ; i <= 0x30 ; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (unsigned int) i << 24); ++ } ++ } ++ ++ /* Initial Texture Sampler Setting*/ ++ for (StageOfTexture = 0; StageOfTexture <= 0xf; ++ StageOfTexture++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00020000 | 0x20000000 | ++ (StageOfTexture & 0xf)<<24)); ++ for (i = 0 ; i <= 0x36 ; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (unsigned int) i << 24); ++ } ++ } ++ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00020000 | 0xfe000000)); ++ for (i = 0 ; i <= 0x13 ; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (unsigned int) i << 24); ++ /* *((unsigned int volatile*)(pMapIOPort+ ++ HC_REG_Hpara0)) =((unsigned int) i << 24);*/ ++ } ++ ++ /* Initial Gamma Table Setting*/ ++ /* Initial Gamma Table Setting*/ ++ /* 5 + 4 = 9 (12) dwords*/ ++ /* sRGB texture is not directly support by ++ H3 hardware.*/ ++ /* We have to set the deGamma table for texture ++ sampling.*/ ++ ++ /* degamma table*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x15000000)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (30 << 20) | (15 << 10) | (5))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((119 << 20) | (81 << 10) | (52))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((283 << 20) | (219 << 10) | (165))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((535 << 20) | (441 << 10) | (357))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((119 << 20) | (884 << 20) | (757 << 10) ++ | (640))); ++ ++ /* gamma table*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x17000000)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (13 << 20) | (13 << 10) | (13))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (26 << 20) | (26 << 10) | (26))); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (0x40000000 | (39 << 20) | (39 << 10) | (39))); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, ((51 << 20) | (51 << 10) | (51))); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, ((71 << 20) | (71 << 10) | (71))); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (87 << 20) | (87 << 10) | (87)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (113 << 20) | (113 << 10) | (113)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (135 << 20) | (135 << 10) | (135)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (170 << 20) | (170 << 10) | (170)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (199 << 20) | (199 << 10) | (199)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (246 << 20) | (246 << 10) | (246)); ++ SetMMIORegister(dev_priv->mmio->handle, ++ 0x440, (284 << 20) | (284 << 10) | (284)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (317 << 20) | (317 << 10) | (317)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (347 << 20) | (347 << 10) | (347)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (373 << 20) | (373 << 10) | (373)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (398 << 20) | (398 << 10) | (398)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (442 << 20) | (442 << 10) | (442)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (481 << 20) | (481 << 10) | (481)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (517 << 20) | (517 << 10) | (517)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (550 << 20) | (550 << 10) | (550)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (609 << 20) | (609 << 10) | (609)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (662 << 20) | (662 << 10) | (662)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (709 << 20) | (709 << 10) | (709)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (753 << 20) | (753 << 10) | (753)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (794 << 20) | (794 << 10) | (794)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (832 << 20) | (832 << 10) | (832)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (868 << 20) | (868 << 10) | (868)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (902 << 20) | (902 << 10) | (902)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (934 << 20) | (934 << 10) | (934)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (966 << 20) | (966 << 10) | (966)); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ (996 << 20) | (996 << 10) | (996)); ++ ++ ++ /* For Interrupt Restore only ++ All types of write through regsiters should be write ++ header data to hardware at least before it can restore. ++ H/W will automatically record the header to write ++ through state buffer for restureusage. ++ By Jaren: ++ HParaType = 8'h03, HParaSubType = 8'h00 ++ 8'h11 ++ 8'h12 ++ 8'h14 ++ 8'h15 ++ 8'h17 ++ HParaSubType 8'h12, 8'h15 is initialized. ++ [HWLimit] ++ 1. All these write through registers can't be partial ++ update. ++ 2. All these write through must be AGP command ++ 16 entries : 4 128-bit data */ ++ ++ /* Initialize INV_ParaSubType_TexPal */ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x00000000)); ++ for (i = 0; i < 16; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00000000); ++ } ++ ++ /* Initialize INV_ParaSubType_4X4Cof */ ++ /* 32 entries : 8 128-bit data */ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x11000000)); ++ for (i = 0; i < 32; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00000000); ++ } ++ ++ /* Initialize INV_ParaSubType_StipPal */ ++ /* 5 entries : 2 128-bit data */ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00030000 | 0x14000000)); ++ for (i = 0; i < (5+3); i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00000000); ++ } ++ ++ /* primitive setting & vertex format*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00040000)); ++ for (i = 0; i <= 0x62; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((unsigned int) i << 24)); ++ } ++ ++ /*ParaType 0xFE - Configure and Misc Setting*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00fe0000)); ++ for (i = 0; i <= 0x47; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((unsigned int) i << 24)); ++ } ++ /*ParaType 0x11 - Frame Buffer Auto-Swapping and ++ Command Regulator Misc*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ (0x00110000)); ++ for (i = 0; i <= 0x20; i++) { ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ ((unsigned int) i << 24)); ++ } ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ 0x00fe0000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x4000840f); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x47000404); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x44000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x46000005); ++ ++ /* setting Misconfig*/ ++ SetMMIORegister(dev_priv->mmio->handle, 0x43C, ++ 0x00fe0000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x00001004); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x08000249); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0a0002c9); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0b0002fb); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0c000000); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0d0002cb); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x0e000009); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x10000049); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x110002ff); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x12000008); ++ SetMMIORegister(dev_priv->mmio->handle, 0x440, ++ 0x130002db); ++ } ++} ++ ++int via_chrome9_drm_resume(struct pci_dev *pci) ++{ ++ struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci); ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ ++ if (!dev_priv->initialized) ++ return 0; ++ ++ Initialize3DEngine(dev_priv); ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, 0x00110000); ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x06000000); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x07100000); ++ } else{ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x02000000); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ 0x03100000); ++ } ++ ++ ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_TRANS, ++ INV_ParaType_PreCR); ++ SetMMIORegister(dev_priv->mmio->handle, INV_REG_CR_BEGIN, ++ INV_SubA_HSetRBGID | INV_HSetRBGID_CR); ++ ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ unsigned int i; ++ /* Here restore SR66~SR6F SR79~SR7B */ ++ for (i = 0; i < 10; i++) { ++ SetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c4, 0x66 + i); ++ SetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c5, dev_priv->gti_backup[i]); ++ } ++ ++ for (i = 0; i < 3; i++) { ++ SetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c4, 0x79 + i); ++ SetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c5, dev_priv->gti_backup[10 + i]); ++ } ++ } ++ ++ via_chrome9_dma_init_inv(dev); ++ ++ return 0; ++} ++ ++int via_chrome9_drm_suspend(struct pci_dev *pci, ++ pm_message_t state) ++{ ++ int i; ++ struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci); ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ ++ if (!dev_priv->initialized) ++ return 0; ++ ++ if (dev_priv->chip_sub_index != CHIP_H6S2) ++ return 0; ++ ++ /* Save registers from SR66~SR6F */ ++ for (i = 0; i < 10; i++) { ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x66 + i); ++ dev_priv->gti_backup[i] = ++ GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ } ++ ++ /* Save registers from SR79~SR7B */ ++ for (i = 0; i < 3; i++) { ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x79 + i); ++ dev_priv->gti_backup[10 + i] = ++ GetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5); ++ } ++ ++ return 0; ++} ++ ++int via_chrome9_driver_load(struct drm_device *dev, ++ unsigned long chipset) ++{ ++ struct drm_via_chrome9_private *dev_priv; ++ int ret = 0; ++ static int associate; ++ ++ if (!associate) { ++ pci_set_drvdata(dev->pdev, dev); ++ dev->pdev->driver = &dev->driver->pci_driver; ++ associate = 1; ++ } ++ ++ dev->counters += 4; ++ dev->types[6] = _DRM_STAT_IRQ; ++ dev->types[7] = _DRM_STAT_PRIMARY; ++ dev->types[8] = _DRM_STAT_SECONDARY; ++ dev->types[9] = _DRM_STAT_DMA; ++ ++ dev_priv = drm_calloc(1, sizeof(struct drm_via_chrome9_private), ++ DRM_MEM_DRIVER); ++ if (dev_priv == NULL) ++ return -ENOMEM; ++ ++ /* Clear */ ++ memset(dev_priv, 0, sizeof(struct drm_via_chrome9_private)); ++ ++ dev_priv->dev = dev; ++ dev->dev_private = (void *)dev_priv; ++ ++ dev_priv->chip_index = chipset; ++ ++ ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); ++ if (ret) ++ drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); ++ return ret; ++} ++ ++int via_chrome9_driver_unload(struct drm_device *dev) ++{ ++ struct drm_via_chrome9_private *dev_priv = dev->dev_private; ++ ++ drm_sman_takedown(&dev_priv->sman); ++ ++ drm_free(dev_priv, sizeof(struct drm_via_chrome9_private), ++ DRM_MEM_DRIVER); ++ ++ dev->dev_private = 0; ++ ++ return 0; ++} ++ ++static int via_chrome9_initialize(struct drm_device *dev, ++ struct drm_via_chrome9_init *init) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ ++ dev_priv->chip_agp = init->chip_agp; ++ dev_priv->chip_index = init->chip_index; ++ dev_priv->chip_sub_index = init->chip_sub_index; ++ ++ dev_priv->usec_timeout = init->usec_timeout; ++ dev_priv->front_offset = init->front_offset; ++ dev_priv->back_offset = init->back_offset >> ++ VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT << ++ VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT; ++ dev_priv->available_fb_size = init->available_fb_size - ++ (init->available_fb_size % ++ (1 << VIA_CHROME9DRM_VIDEO_STARTADDRESS_ALIGNMENT)); ++ dev_priv->depth_offset = init->depth_offset; ++ ++ /* Find all the map added first, doing this is necessary to ++ intialize hw */ ++ if (via_chrome9_map_init(dev, init)) { ++ DRM_ERROR("function via_chrome9_map_init ERROR !\n"); ++ goto error; ++ } ++ ++ /* Necessary information has been gathered for initialize hw */ ++ if (via_chrome9_hw_init(dev, init)) { ++ DRM_ERROR("function via_chrome9_hw_init ERROR !\n"); ++ goto error; ++ } ++ ++ /* After hw intialization, we have kown whether to use agp ++ or to use pcie for texture */ ++ if (via_chrome9_heap_management_init(dev, init)) { ++ DRM_ERROR("function \ ++ via_chrome9_heap_management_init ERROR !\n"); ++ goto error; ++ } ++ ++ dev_priv->initialized = 1; ++ ++ return 0; ++ ++error: ++ /* all the error recover has been processed in relevant function, ++ so here just return error */ ++ return -EINVAL; ++} ++ ++static void via_chrome9_cleanup(struct drm_device *dev, ++ struct drm_via_chrome9_init *init) ++{ ++ struct drm_via_chrome9_DMA_manager *lpcmDMAManager = NULL; ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ DRM_DEBUG("function via_chrome9_cleanup run!\n"); ++ ++ if (!dev_priv) ++ return ; ++ ++ lpcmDMAManager = ++ (struct drm_via_chrome9_DMA_manager *)dev_priv->dma_manager; ++ if (dev_priv->pcie_vmalloc_nocache) { ++ vfree((void *)dev_priv->pcie_vmalloc_nocache); ++ dev_priv->pcie_vmalloc_nocache = 0; ++ if (lpcmDMAManager) ++ lpcmDMAManager->addr_linear = NULL; ++ } ++ ++ if (dev_priv->pagetable_map.pagetable_handle) { ++ iounmap(dev_priv->pagetable_map.pagetable_handle); ++ dev_priv->pagetable_map.pagetable_handle = NULL; ++ } ++ ++ if (lpcmDMAManager && lpcmDMAManager->addr_linear) { ++ iounmap(lpcmDMAManager->addr_linear); ++ lpcmDMAManager->addr_linear = NULL; ++ } ++ ++ kfree(lpcmDMAManager); ++ dev_priv->dma_manager = NULL; ++ ++ if (dev_priv->event_tag_info) { ++ vfree(dev_priv->event_tag_info); ++ dev_priv->event_tag_info = NULL; ++ } ++ ++ if (dev_priv->bci_buffer) { ++ vfree(dev_priv->bci_buffer); ++ dev_priv->bci_buffer = NULL; ++ } ++ ++ via_chrome9_memory_destroy_heap(dev, dev_priv); ++ ++ /* After cleanup, it should to set the value to null */ ++ dev_priv->sarea = dev_priv->mmio = dev_priv->hostBlt = ++ dev_priv->fb = dev_priv->front = dev_priv->back = ++ dev_priv->depth = dev_priv->agp_tex = ++ dev_priv->shadow_map.shadow = 0; ++ dev_priv->sarea_priv = 0; ++ dev_priv->initialized = 0; ++} ++ ++/* ++Do almost everything intialize here,include: ++1.intialize all addmaps in private data structure ++2.intialize memory heap management for video agp/pcie ++3.intialize hw for dma(pcie/agp) function ++ ++Note:all this function will dispatch into relevant function ++*/ ++int via_chrome9_ioctl_init(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_init *init = (struct drm_via_chrome9_init *)data; ++ ++ switch (init->func) { ++ case VIA_CHROME9_INIT: ++ if (via_chrome9_initialize(dev, init)) { ++ DRM_ERROR("function via_chrome9_initialize error\n"); ++ return -1; ++ } ++ via_chrome9_filepriv_v4l = (void *)file_priv; ++ via_chrome9_dev_v4l = (void *)dev; ++ break; ++ ++ case VIA_CHROME9_CLEANUP: ++ via_chrome9_cleanup(dev, init); ++ via_chrome9_filepriv_v4l = 0; ++ via_chrome9_dev_v4l = 0; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int via_chrome9_ioctl_allocate_event_tag(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_event_tag *event_tag = data; ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ struct drm_clb_event_tag_info *event_tag_info = ++ dev_priv->event_tag_info; ++ unsigned int *event_addr = 0, i = 0; ++ ++ for (i = 0; i < NUMBER_OF_EVENT_TAGS; i++) { ++ if (!event_tag_info->usage[i]) ++ break; ++ } ++ ++ if (i < NUMBER_OF_EVENT_TAGS) { ++ event_tag_info->usage[i] = 1; ++ event_tag->event_offset = i; ++ event_tag->last_sent_event_value.event_low = 0; ++ event_tag->current_event_value.event_low = 0; ++ event_addr = event_tag_info->linear_address + ++ event_tag->event_offset * 4; ++ *event_addr = 0; ++ return 0; ++ } else { ++ return -7; ++ } ++ ++ return 0; ++} ++ ++int via_chrome9_ioctl_free_event_tag(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ struct drm_clb_event_tag_info *event_tag_info = ++ dev_priv->event_tag_info; ++ struct drm_via_chrome9_event_tag *event_tag = data; ++ ++ event_tag_info->usage[event_tag->event_offset] = 0; ++ return 0; ++} ++ ++void via_chrome9_lastclose(struct drm_device *dev) ++{ ++ via_chrome9_cleanup(dev, 0); ++ return ; ++} ++ ++static int via_chrome9_do_wait_vblank(struct drm_via_chrome9_private ++ *dev_priv) ++{ ++ int i; ++ ++ for (i = 0; i < dev_priv->usec_timeout; i++) { ++ VIA_CHROME9_WRITE8(0x83d4, 0x34); ++ if ((VIA_CHROME9_READ8(0x83d5)) & 0x8) ++ return 0; ++ __via_chrome9ke_udelay(1); ++ } ++ ++ return -1; ++} ++ ++void via_chrome9_preclose(struct drm_device *dev, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_sarea *sarea_priv = NULL; ++ ++ if (!dev_priv) ++ return ; ++ ++ sarea_priv = dev_priv->sarea_priv; ++ if (!sarea_priv) ++ return ; ++ ++ if ((sarea_priv->page_flip == 1) && ++ (sarea_priv->current_page != VIA_CHROME9_FRONT)) { ++ __volatile__ unsigned long *bci_base; ++ if (via_chrome9_do_wait_vblank(dev_priv)) ++ return; ++ ++ bci_base = (__volatile__ unsigned long *)(dev_priv->bci); ++ ++ BCI_SET_STREAM_REGISTER(bci_base, 0x81c4, 0xc0000000); ++ BCI_SET_STREAM_REGISTER(bci_base, 0x81c0, ++ dev_priv->front_offset); ++ BCI_SEND(bci_base, 0x64000000);/* wait vsync */ ++ ++ sarea_priv->current_page = VIA_CHROME9_FRONT; ++ } ++} ++ ++int via_chrome9_is_agp(struct drm_device *dev) ++{ ++ /* filter out pcie group which has no AGP device */ ++ if (dev->pci_device == 0x1122 || dev->pci_device == 0x5122) { ++ dev->driver->driver_features &= ++ ~(DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_REQUIRE_AGP); ++ return 0; ++ } ++ return 1; ++} ++ +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_drm.h +@@ -0,0 +1,443 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#ifndef _VIA_CHROME9_DRM_H_ ++#define _VIA_CHROME9_DRM_H_ ++ ++/* WARNING: These defines must be the same as what the Xserver uses. ++ * if you change them, you must change the defines in the Xserver. ++ */ ++ ++#ifndef _VIA_CHROME9_DEFINES_ ++#define _VIA_CHROME9_DEFINES_ ++ ++#ifndef __KERNEL__ ++#include "via_drmclient.h" ++#endif ++ ++#define VIA_CHROME9_NR_SAREA_CLIPRECTS 8 ++#define VIA_CHROME9_NR_XVMC_PORTS 10 ++#define VIA_CHROME9_NR_XVMC_LOCKS 5 ++#define VIA_CHROME9_MAX_CACHELINE_SIZE 64 ++#define XVMCLOCKPTR(saPriv,lockNo) \ ++ ((__volatile__ struct drm_hw_lock *) \ ++ (((((unsigned long) (saPriv)->XvMCLockArea) + \ ++ (VIA_CHROME9_MAX_CACHELINE_SIZE - 1)) & \ ++ ~(VIA_CHROME9_MAX_CACHELINE_SIZE - 1)) + \ ++ VIA_CHROME9_MAX_CACHELINE_SIZE*(lockNo))) ++ ++/* Each region is a minimum of 64k, and there are at most 64 of them. ++ */ ++#define VIA_CHROME9_NR_TEX_REGIONS 64 ++#define VIA_CHROME9_LOG_MIN_TEX_REGION_SIZE 16 ++#endif ++ ++#define VIA_CHROME9_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ ++#define VIA_CHROME9_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ ++#define VIA_CHROME9_UPLOAD_CTX 0x4 ++#define VIA_CHROME9_UPLOAD_BUFFERS 0x8 ++#define VIA_CHROME9_UPLOAD_TEX0 0x10 ++#define VIA_CHROME9_UPLOAD_TEX1 0x20 ++#define VIA_CHROME9_UPLOAD_CLIPRECTS 0x40 ++#define VIA_CHROME9_UPLOAD_ALL 0xff ++ ++/* VIA_CHROME9 specific ioctls */ ++#define DRM_VIA_CHROME9_ALLOCMEM 0x00 ++#define DRM_VIA_CHROME9_FREEMEM 0x01 ++#define DRM_VIA_CHROME9_FREE 0x02 ++#define DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG 0x03 ++#define DRM_VIA_CHROME9_FREE_EVENT_TAG 0x04 ++#define DRM_VIA_CHROME9_ALLOCATE_APERTURE 0x05 ++#define DRM_VIA_CHROME9_FREE_APERTURE 0x06 ++#define DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM 0x07 ++#define DRM_VIA_CHROME9_FREE_VIDEO_MEM 0x08 ++#define DRM_VIA_CHROME9_WAIT_CHIP_IDLE 0x09 ++#define DRM_VIA_CHROME9_PROCESS_EXIT 0x0A ++#define DRM_VIA_CHROME9_RESTORE_PRIMARY 0x0B ++#define DRM_VIA_CHROME9_FLUSH_CACHE 0x0C ++#define DRM_VIA_CHROME9_INIT 0x0D ++#define DRM_VIA_CHROME9_FLUSH 0x0E ++#define DRM_VIA_CHROME9_CHECKVIDMEMSIZE 0x0F ++#define DRM_VIA_CHROME9_PCIEMEMCTRL 0x10 ++#define DRM_VIA_CHROME9_AUTH_MAGIC 0x11 ++#define DRM_VIA_CHROME9_GET_PCI_ID 0x12 ++#define DRM_VIA_CHROME9_INIT_JUDGE 0x16 ++#define DRM_VIA_CHROME9_DMA 0x17 ++ ++#define DRM_IOCTL_VIA_CHROME9_INIT \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_INIT, \ ++ struct drm_via_chrome9_init) ++#define DRM_IOCTL_VIA_CHROME9_FLUSH \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FLUSH, \ ++ struct drm_via_chrome9_flush) ++#define DRM_IOCTL_VIA_CHROME9_FREE \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE, int) ++#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_EVENT_TAG \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG, \ ++ struct drm_event_via_chrome9_tag) ++#define DRM_IOCTL_VIA_CHROME9_FREE_EVENT_TAG \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_EVENT_TAG, \ ++ struct drm_event_via_chrome9_tag) ++#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_APERTURE \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_APERTURE, \ ++ struct drm_via_chrome9_aperture) ++#define DRM_IOCTL_VIA_CHROME9_FREE_APERTURE \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_APERTURE, \ ++ struct drm_via_chrome9_aperture) ++#define DRM_IOCTL_VIA_CHROME9_ALLOCATE_VIDEO_MEM \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM, \ ++ struct drm_via_chrome9_memory_alloc) ++#define DRM_IOCTL_VIA_CHROME9_FREE_VIDEO_MEM \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREE_VIDEO_MEM, \ ++ struct drm_via_chrome9_memory_alloc) ++#define DRM_IOCTL_VIA_CHROME9_WAIT_CHIP_IDLE \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_WAIT_CHIP_IDLE, int) ++#define DRM_IOCTL_VIA_CHROME9_PROCESS_EXIT \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_PROCESS_EXIT, int) ++#define DRM_IOCTL_VIA_CHROME9_RESTORE_PRIMARY \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_RESTORE_PRIMARY, int) ++#define DRM_IOCTL_VIA_CHROME9_FLUSH_CACHE \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FLUSH_CACHE, int) ++#define DRM_IOCTL_VIA_CHROME9_ALLOCMEM \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_ALLOCMEM, int) ++#define DRM_IOCTL_VIA_CHROME9_FREEMEM \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_FREEMEM, int) ++#define DRM_IOCTL_VIA_CHROME9_CHECK_VIDMEM_SIZE \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_CHECKVIDMEMSIZE, \ ++ struct drm_via_chrome9_memory_alloc) ++#define DRM_IOCTL_VIA_CHROME9_PCIEMEMCTRL \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_PCIEMEMCTRL,\ ++ drm_via_chrome9_pciemem_ctrl_t) ++#define DRM_IOCTL_VIA_CHROME9_AUTH_MAGIC \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_AUTH_MAGIC, drm_auth_t) ++#define DRM_IOCTL_VIA_CHROME9_GET_PCI_ID \ ++ DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_CHROME9_GET_PCI_ID, \ ++ struct get_pci_id_struct) ++#define DRM_IOCTL_VIA_CHROME9_INIT_JUDGE \ ++ DRM_IOR(DRM_COMMAND_BASE + DRM_VIA_CHROME9_INIT_JUDGE, int) ++#define DRM_IOCTL_VIA_CHROME9_DMA \ ++ DRM_IO(DRM_COMMAND_BASE + DRM_VIA_CHROME9_DMA, int) ++ ++enum S3GCHIPIDS { ++ CHIP_UNKNOWN = -1, ++ CHIP_CMODEL, /*Model for any chip. */ ++ CHIP_CLB, /*Columbia */ ++ CHIP_DST, /*Destination */ ++ CHIP_CSR, /*Castlerock */ ++ CHIP_INV, /*Innovation (H3) */ ++ CHIP_H5, /*Innovation (H5) */ ++ CHIP_H5S1, /*Innovation (H5S1) */ ++ CHIP_H6S2, /*Innovation (H6S2) */ ++ CHIP_CMS, /*Columbia MS */ ++ CHIP_METRO, /*Metropolis */ ++ CHIP_MANHATTAN, /*manhattan */ ++ CHIP_MATRIX, /*matrix */ ++ CHIP_EVO, /*change for GCC 4.1 -add- 07.02.12*/ ++ CHIP_H6S1, /*Innovation (H6S1)*/ ++ CHIP_DST2, /*Destination-2 */ ++ CHIP_LAST /*Maximum number of chips supported. */ ++}; ++ ++enum VIA_CHROME9CHIPBUS { ++ CHIP_PCI, ++ CHIP_AGP, ++ CHIP_PCIE ++}; ++ ++struct drm_via_chrome9_init { ++ enum { ++ VIA_CHROME9_INIT = 0x01, ++ VIA_CHROME9_CLEANUP = 0x02 ++ } func; ++ int chip_agp; ++ int chip_index; ++ int chip_sub_index; ++ int usec_timeout; ++ unsigned int sarea_priv_offset; ++ unsigned int fb_cpp; ++ unsigned int front_offset; ++ unsigned int back_offset; ++ unsigned int depth_offset; ++ unsigned int mmio_handle; ++ unsigned int dma_handle; ++ unsigned int fb_handle; ++ unsigned int front_handle; ++ unsigned int back_handle; ++ unsigned int depth_handle; ++ ++ unsigned int fb_tex_offset; ++ unsigned int fb_tex_size; ++ ++ unsigned int agp_tex_size; ++ unsigned int agp_tex_handle; ++ unsigned int shadow_size; ++ unsigned int shadow_handle; ++ unsigned int garttable_size; ++ unsigned int garttable_offset; ++ unsigned long available_fb_size; ++ unsigned long fb_base_address; ++ unsigned int DMA_size; ++ unsigned long DMA_phys_address; ++ enum { ++ AGP_RING_BUFFER, ++ AGP_DOUBLE_BUFFER, ++ AGP_DISABLED ++ } agp_type; ++ unsigned int hostBlt_handle; ++}; ++ ++enum dma_cmd_type { ++ flush_bci = 0, ++ flush_bci_and_wait, ++ dma_kickoff, ++ flush_dma_buffer, ++ flush_dma_and_wait ++}; ++ ++struct drm_via_chrome9_flush { ++ enum dma_cmd_type dma_cmd_type; ++ /* command buffer index */ ++ int cmd_idx; ++ /* command buffer offset */ ++ int cmd_offset; ++ /* command dword size,command always from beginning */ ++ int cmd_size; ++ /* if use dma kick off,it is dma kick off command */ ++ unsigned long dma_kickoff[2]; ++ /* user mode DMA buffer pointer */ ++ unsigned int *usermode_dma_buf; ++}; ++ ++struct event_value { ++ int event_low; ++ int event_high; ++}; ++ ++struct drm_via_chrome9_event_tag { ++ unsigned int event_size; /* event tag size */ ++ int event_offset; /* event tag id */ ++ struct event_value last_sent_event_value; ++ struct event_value current_event_value; ++ int query_mask0; ++ int query_mask1; ++ int query_Id1; ++}; ++ ++/* Indices into buf.Setup where various bits of state are mirrored per ++ * context and per buffer. These can be fired at the card as a unit, ++ * or in a piecewise fashion as required. ++ */ ++ ++#define VIA_CHROME9_TEX_SETUP_SIZE 8 ++ ++/* Flags for clear ioctl ++ */ ++#define VIA_CHROME9_FRONT 0x1 ++#define VIA_CHROME9_BACK 0x2 ++#define VIA_CHROME9_DEPTH 0x4 ++#define VIA_CHROME9_STENCIL 0x8 ++#define VIA_CHROME9_MEM_VIDEO 0 /* matches drm constant */ ++#define VIA_CHROME9_MEM_AGP 1 /* matches drm constant */ ++#define VIA_CHROME9_MEM_SYSTEM 2 ++#define VIA_CHROME9_MEM_MIXED 3 ++#define VIA_CHROME9_MEM_UNKNOWN 4 ++ ++struct drm_via_chrome9_agp { ++ uint32_t offset; ++ uint32_t size; ++}; ++ ++struct drm_via_chrome9_fb { ++ uint32_t offset; ++ uint32_t size; ++}; ++ ++struct drm_via_chrome9_mem { ++ uint32_t context; ++ uint32_t type; ++ uint32_t size; ++ unsigned long index; ++ unsigned long offset; ++}; ++ ++struct drm_via_chrome9_aperture { ++ /*IN: The frame buffer offset of the surface. */ ++ int surface_offset; ++ /*IN: Surface pitch in byte, */ ++ int pitch; ++ /*IN: Surface width in pixel */ ++ int width; ++ /*IN: Surface height in pixel */ ++ int height; ++ /*IN: Surface color format, Columbia has more color formats */ ++ int color_format; ++ /*IN: Rotation degrees, only for Columbia */ ++ int rotation_degree; ++ /*IN Is the PCIE Video, for MATRIX support NONLOCAL Aperture */ ++ int isPCIEVIDEO; ++ /*IN: Is the surface tilled, only for Columbia */ ++ int is_tiled; ++ /*IN: Only allocate apertur, not hardware setup. */ ++ int allocate_only; ++ /* OUT: linear address for aperture */ ++ unsigned int *aperture_linear_address; ++ /*OUT: The pitch of the aperture,for CPU write not for GE */ ++ int aperture_pitch; ++ /*OUT: The index of the aperture */ ++ int aperture_handle; ++ int apertureID; ++ /* always =0xAAAAAAAA */ ++ /* Aligned surface's width(in pixel) */ ++ int width_aligned; ++ /* Aligned surface's height(in pixel) */ ++ int height_aligned; ++}; ++ ++/* ++ Some fileds of this data structure has no meaning now since ++ we have managed heap based on mechanism provided by DRM ++ Remain what it was to keep consistent with 3D driver interface. ++*/ ++struct drm_via_chrome9_memory_alloc { ++ enum { ++ memory_heap_video = 0, ++ memory_heap_agp, ++ memory_heap_pcie_video, ++ memory_heap_pcie, ++ max_memory_heaps ++ } heap_type; ++ struct { ++ void *lpL1Node; ++ unsigned int alcL1Tag; ++ unsigned int usageCount; ++ unsigned int dwVersion; ++ unsigned int dwResHandle; ++ unsigned int dwProcessID; ++ } heap_info; ++ unsigned int flags; ++ unsigned int size; ++ unsigned int physaddress; ++ unsigned int offset; ++ unsigned int align; ++ void *linearaddress; ++}; ++ ++struct drm_via_chrome9_dma_init { ++ enum { ++ VIA_CHROME9_INIT_DMA = 0x01, ++ VIA_CHROME9_CLEANUP_DMA = 0x02, ++ VIA_CHROME9_DMA_INITIALIZED = 0x03 ++ } func; ++ ++ unsigned long offset; ++ unsigned long size; ++ unsigned long reg_pause_addr; ++}; ++ ++struct drm_via_chrome9_cmdbuffer { ++ char __user *buf; ++ unsigned long size; ++}; ++ ++/* Warning: If you change the SAREA structure you must change the Xserver ++ * structure as well */ ++ ++struct drm_via_chrome9_tex_region { ++ unsigned char next, prev; /* indices to form a circular LRU */ ++ unsigned char inUse; /* owned by a client, or free? */ ++ int age; /* tracked by clients to update local LRU's */ ++}; ++ ++struct drm_via_chrome9_sarea { ++ int page_flip; ++ int current_page; ++ unsigned int req_drawable;/* the X drawable id */ ++ unsigned int req_draw_buffer;/* VIA_CHROME9_FRONT or VIA_CHROME9_BACK */ ++ /* Last context that uploaded state */ ++ int ctx_owner; ++}; ++ ++struct drm_via_chrome9_cmdbuf_size { ++ enum { ++ VIA_CHROME9_CMDBUF_SPACE = 0x01, ++ VIA_CHROME9_CMDBUF_LAG = 0x02 ++ } func; ++ int wait; ++ uint32_t size; ++}; ++ ++struct drm_via_chrome9_DMA_manager { ++ unsigned int *addr_linear; ++ unsigned int DMASize; ++ unsigned int bDMAAgp; ++ unsigned int LastIssuedEventTag; ++ unsigned int *pBeg; ++ unsigned int *pInUseByHW; ++ unsigned int **ppInUseByHW; ++ unsigned int *pInUseBySW; ++ unsigned int *pFree; ++ unsigned int *pEnd; ++ ++ unsigned long pPhysical; ++ unsigned int MaxKickoffSize; ++}; ++ ++struct get_pci_id_struct { ++ unsigned int x; ++ unsigned int y; ++ unsigned int z; ++ unsigned int f; ++}; ++ ++ ++extern void *via_chrome9_dev_v4l; ++extern void *via_chrome9_filepriv_v4l; ++extern int via_chrome9_ioctl_wait_chip_idle(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_init(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_allocate_event_tag(struct drm_device ++ *dev, void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_free_event_tag(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_driver_load(struct drm_device *dev, ++ unsigned long chipset); ++extern int via_chrome9_driver_unload(struct drm_device *dev); ++extern int via_chrome9_ioctl_process_exit(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_restore_primary(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_drm_resume(struct pci_dev *dev); ++extern int via_chrome9_drm_suspend(struct pci_dev *dev, ++ pm_message_t state); ++extern void __via_chrome9ke_udelay(unsigned long usecs); ++extern void via_chrome9_lastclose(struct drm_device *dev); ++extern void via_chrome9_preclose(struct drm_device *dev, ++ struct drm_file *file_priv); ++extern int via_chrome9_is_agp(struct drm_device *dev); ++ ++ ++#endif /* _VIA_CHROME9_DRM_H_ */ +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_drv.c +@@ -0,0 +1,224 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++#include "via_chrome9_drm.h" ++#include "via_chrome9_drv.h" ++#include "via_chrome9_dma.h" ++#include "via_chrome9_mm.h" ++#include "via_chrome9_3d_reg.h" ++ ++#define RING_BUFFER_INIT_FLAG 1 ++#define RING_BUFFER_CLEANUP_FLAG 2 ++ ++static int dri_library_name(struct drm_device *dev, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "via_chrome9"); ++} ++ ++int via_chrome9_drm_authmagic(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++int via_chrome9_drm_get_pci_id(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ unsigned int *reg_val = data; ++ outl(0x8000002C, 0xCF8); ++ *reg_val = inl(0xCFC); ++ outl(0x8000012C, 0xCF8); ++ *(reg_val+1) = inl(0xCFC); ++ outl(0x8000022C, 0xCF8); ++ *(reg_val+2) = inl(0xCFC); ++ outl(0x8000052C, 0xCF8); ++ *(reg_val+3) = inl(0xCFC); ++ ++ return 0; ++} ++int via_chrome9_drm_judge(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ ++ if (dev_priv->initialized) ++ *(int *)data = 1; ++ else ++ *(int *)data = -1; ++ return 0; ++} ++ ++int via_chrome9_dma_init(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ int tmp; ++ unsigned char sr6c; ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ tmp = *((int *)data); ++ ++ switch (tmp) { ++ case RING_BUFFER_INIT_FLAG: ++ via_chrome9_dma_init_inv(dev); ++ break; ++ case RING_BUFFER_CLEANUP_FLAG: ++ if (dev_priv->chip_sub_index == CHIP_H6S2) { ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c4, 0x6c); ++ sr6c = GetMMIORegisterU8(dev_priv->mmio->handle, ++ 0x83c5); ++ sr6c &= 0x7F; ++ SetMMIORegisterU8(dev_priv->mmio->handle, 0x83c5, sr6c); ++ } ++ break; ++ } ++ return 0; ++} ++ ++ ++ ++struct drm_ioctl_desc via_chrome9_ioctls[] = { ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_INIT, via_chrome9_ioctl_init, ++ DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),/* via_chrome9_map.c*/ ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FLUSH, via_chrome9_ioctl_flush, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE, via_chrome9_ioctl_free, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_EVENT_TAG, ++ via_chrome9_ioctl_allocate_event_tag, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_EVENT_TAG, ++ via_chrome9_ioctl_free_event_tag, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_APERTURE, ++ via_chrome9_ioctl_allocate_aperture, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_APERTURE, ++ via_chrome9_ioctl_free_aperture, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCATE_VIDEO_MEM, ++ via_chrome9_ioctl_allocate_mem_wrapper, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREE_VIDEO_MEM, ++ via_chrome9_ioctl_free_mem_wrapper, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_WAIT_CHIP_IDLE, ++ via_chrome9_ioctl_wait_chip_idle, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_PROCESS_EXIT, ++ via_chrome9_ioctl_process_exit, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_RESTORE_PRIMARY, ++ via_chrome9_ioctl_restore_primary, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FLUSH_CACHE, ++ via_chrome9_ioctl_flush_cache, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_ALLOCMEM, ++ via_chrome9_ioctl_allocate_mem_base, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_FREEMEM, ++ via_chrome9_ioctl_freemem_base, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_CHECKVIDMEMSIZE, ++ via_chrome9_ioctl_check_vidmem_size, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_PCIEMEMCTRL, ++ via_chrome9_ioctl_pciemem_ctrl, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_AUTH_MAGIC, via_chrome9_drm_authmagic, 0), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_GET_PCI_ID, ++ via_chrome9_drm_get_pci_id, 0), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_INIT_JUDGE, via_chrome9_drm_judge, 0), ++ DRM_IOCTL_DEF(DRM_VIA_CHROME9_DMA, via_chrome9_dma_init, 0) ++}; ++ ++int via_chrome9_max_ioctl = DRM_ARRAY_SIZE(via_chrome9_ioctls); ++ ++static struct pci_device_id pciidlist[] = { ++ {0x1106, 0x3225, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_DX9_0}, ++ {0x1106, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ {0x1106, 0x1122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_PCIE_GROUP}, ++ {0x1106, 0x5122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_CHROME9_PCIE_GROUP}, ++ {0, 0, 0} ++}; ++ ++int via_chrome9_driver_open(struct drm_device *dev, ++ struct drm_file *priv) ++{ ++ priv->authenticated = 1; ++ return 0; ++} ++ ++static struct drm_driver driver = { ++ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | ++ DRIVER_HAVE_DMA | DRIVER_FB_DMA | DRIVER_USE_MTRR, ++ .open = via_chrome9_driver_open, ++ .load = via_chrome9_driver_load, ++ .unload = via_chrome9_driver_unload, ++ .device_is_agp = via_chrome9_is_agp, ++ .dri_library_name = dri_library_name, ++ .reclaim_buffers = drm_core_reclaim_buffers, ++ .reclaim_buffers_locked = NULL, ++ .reclaim_buffers_idlelocked = via_chrome9_reclaim_buffers_locked, ++ .lastclose = via_chrome9_lastclose, ++ .preclose = via_chrome9_preclose, ++ .get_map_ofs = drm_core_get_map_ofs, ++ .get_reg_ofs = drm_core_get_reg_ofs, ++ .ioctls = via_chrome9_ioctls, ++ .fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .ioctl = drm_ioctl, ++ .mmap = drm_mmap, ++ .poll = drm_poll, ++ .fasync = drm_fasync, ++ }, ++ .pci_driver = { ++ .name = DRIVER_NAME, ++ .id_table = pciidlist, ++ .resume = via_chrome9_drm_resume, ++ .suspend = via_chrome9_drm_suspend, ++ }, ++ ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++static int __init via_chrome9_init(void) ++{ ++ driver.num_ioctls = via_chrome9_max_ioctl; ++#if VIA_CHROME9_VERIFY_ENABLE ++ via_chrome9_init_command_verifier(); ++ DRM_INFO("via_chrome9 verify function enabled. \n"); ++#endif ++ driver.dev_priv_size = sizeof(struct drm_via_chrome9_private); ++ return drm_init(&driver); ++} ++ ++static void __exit via_chrome9_exit(void) ++{ ++ drm_exit(&driver); ++} ++ ++module_init(via_chrome9_init); ++module_exit(via_chrome9_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL and additional rights"); +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_drv.h +@@ -0,0 +1,150 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#ifndef _VIA_CHROME9_DRV_H_ ++#define _VIA_CHROME9_DRV_H_ ++ ++#include "drm_sman.h" ++#include "via_chrome9_verifier.h" ++#define DRIVER_AUTHOR "Various" ++ ++#define DRIVER_NAME "via_chrome9" ++#define DRIVER_DESC "VIA_CHROME9 Unichrome / Pro" ++#define DRIVER_DATE "20080415" ++ ++#define DRIVER_MAJOR 2 ++#define DRIVER_MINOR 11 ++#define DRIVER_PATCHLEVEL 1 ++ ++#define via_chrome9_FIRE_BUF_SIZE 1024 ++#define via_chrome9_NUM_IRQS 4 ++ ++#define MAX_MEMORY_HEAPS 4 ++#define NUMBER_OF_APERTURES 32 ++ ++/*typedef struct drm_via_chrome9_shadow_map drm_via_chrome9_shadow_map_t;*/ ++struct drm_via_chrome9_shadow_map { ++ struct drm_map *shadow; ++ unsigned int shadow_size; ++ unsigned int *shadow_handle; ++}; ++ ++/*typedef struct drm_via_chrome9_pagetable_map ++ *drm_via_chrome9_pagetable_map_t; ++ */ ++struct drm_via_chrome9_pagetable_map { ++ unsigned int pagetable_offset; ++ unsigned int pagetable_size; ++ unsigned int *pagetable_handle; ++ unsigned int mmt_register; ++}; ++ ++/*typedef struct drm_via_chrome9_private drm_via_chrome9_private_t;*/ ++struct drm_via_chrome9_private { ++ int chip_agp; ++ int chip_index; ++ int chip_sub_index; ++ ++ unsigned long front_offset; ++ unsigned long back_offset; ++ unsigned long depth_offset; ++ unsigned long fb_base_address; ++ unsigned long available_fb_size; ++ int usec_timeout; ++ int max_apertures; ++ struct drm_sman sman; ++ unsigned int alignment; ++ /* bit[31]:0:indicate no alignment needed,1:indicate ++ alignment needed and size is bit[0:30]*/ ++ ++ struct drm_map *sarea; ++ struct drm_via_chrome9_sarea *sarea_priv; ++ ++ struct drm_map *mmio; ++ struct drm_map *hostBlt; ++ struct drm_map *fb; ++ struct drm_map *front; ++ struct drm_map *back; ++ struct drm_map *depth; ++ struct drm_map *agp_tex; ++ unsigned int agp_size; ++ unsigned int agp_offset; ++ ++ struct semaphore *drm_s3g_sem; ++ ++ struct drm_via_chrome9_shadow_map shadow_map; ++ struct drm_via_chrome9_pagetable_map pagetable_map; ++ ++ char *bci; ++ ++ int aperture_usage[NUMBER_OF_APERTURES]; ++ void *event_tag_info; ++ ++ /* DMA buffer manager */ ++ void *dma_manager; ++ /* Indicate agp/pcie heap initialization flag */ ++ int agp_initialized; ++ /* Indicate video heap initialization flag */ ++ int vram_initialized; ++ ++ unsigned long pcie_vmalloc_addr; ++ ++ /* pointer to device information */ ++ void *dev; ++ /* if agp init fail, go ahead and force dri use PCI*/ ++ enum { ++ DRM_AGP_RING_BUFFER, ++ DRM_AGP_DOUBLE_BUFFER, ++ DRM_AGP_DISABLED ++ } drm_agp_type; ++ /*end*/ ++#if VIA_CHROME9_VERIFY_ENABLE ++ struct drm_via_chrome9_state hc_state; ++#endif ++ unsigned long *bci_buffer; ++ unsigned long pcie_vmalloc_nocache; ++ unsigned char gti_backup[13]; ++ int initialized; ++ ++}; ++ ++ ++enum via_chrome9_family { ++ VIA_CHROME9_OTHER = 0, /* Baseline */ ++ VIA_CHROME9_PRO_GROUP_A,/* Another video engine and DMA commands */ ++ VIA_CHROME9_DX9_0, ++ VIA_CHROME9_PCIE_GROUP ++}; ++ ++/* VIA_CHROME9 MMIO register access */ ++#define VIA_CHROME9_BASE ((dev_priv->mmio)) ++ ++#define VIA_CHROME9_READ(reg) DRM_READ32(VIA_CHROME9_BASE, reg) ++#define VIA_CHROME9_WRITE(reg, val) DRM_WRITE32(VIA_CHROME9_BASE, reg, val) ++#define VIA_CHROME9_READ8(reg) DRM_READ8(VIA_CHROME9_BASE, reg) ++#define VIA_CHROME9_WRITE8(reg, val) DRM_WRITE8(VIA_CHROME9_BASE, reg, val) ++ ++#endif +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_mm.c +@@ -0,0 +1,435 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include "drmP.h" ++#include "via_chrome9_drm.h" ++#include "via_chrome9_drv.h" ++#include "drm_sman.h" ++#include "via_chrome9_mm.h" ++ ++#define VIA_CHROME9_MM_GRANULARITY 4 ++#define VIA_CHROME9_MM_GRANULARITY_MASK ((1 << VIA_CHROME9_MM_GRANULARITY) - 1) ++ ++ ++int via_chrome9_map_init(struct drm_device *dev, ++ struct drm_via_chrome9_init *init) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ ++ dev_priv->sarea = drm_getsarea(dev); ++ if (!dev_priv->sarea) { ++ DRM_ERROR("could not find sarea!\n"); ++ goto error; ++ } ++ dev_priv->sarea_priv = ++ (struct drm_via_chrome9_sarea *)((unsigned char *)dev_priv-> ++ sarea->handle + init->sarea_priv_offset); ++ ++ dev_priv->fb = drm_core_findmap(dev, init->fb_handle); ++ if (!dev_priv->fb) { ++ DRM_ERROR("could not find framebuffer!\n"); ++ goto error; ++ } ++ /* Frame buffer physical base address */ ++ dev_priv->fb_base_address = init->fb_base_address; ++ ++ if (init->shadow_size) { ++ /* find apg shadow region mappings */ ++ dev_priv->shadow_map.shadow = drm_core_findmap(dev, init-> ++ shadow_handle); ++ if (!dev_priv->shadow_map.shadow) { ++ DRM_ERROR("could not shadow map!\n"); ++ goto error; ++ } ++ dev_priv->shadow_map.shadow_size = init->shadow_size; ++ dev_priv->shadow_map.shadow_handle = (unsigned int *)dev_priv-> ++ shadow_map.shadow->handle; ++ init->shadow_handle = dev_priv->shadow_map.shadow->offset; ++ } ++ if (init->agp_tex_size && init->chip_agp != CHIP_PCIE) { ++ /* find apg texture buffer mappings */ ++ dev_priv->agp_tex = drm_core_findmap(dev, init->agp_tex_handle); ++ dev_priv->agp_size = init->agp_tex_size; ++ dev_priv->agp_offset = init->agp_tex_handle; ++ if (!dev_priv->agp_tex) { ++ DRM_ERROR("could not find agp texture map !\n"); ++ goto error; ++ } ++ } ++ /* find mmio/dma mappings */ ++ dev_priv->mmio = drm_core_findmap(dev, init->mmio_handle); ++ if (!dev_priv->mmio) { ++ DRM_ERROR("failed to find mmio region!\n"); ++ goto error; ++ } ++ ++ dev_priv->hostBlt = drm_core_findmap(dev, init->hostBlt_handle); ++ if (!dev_priv->hostBlt) { ++ DRM_ERROR("failed to find host bitblt region!\n"); ++ goto error; ++ } ++ ++ dev_priv->drm_agp_type = init->agp_type; ++ if (init->agp_type != AGP_DISABLED && init->chip_agp != CHIP_PCIE) { ++ dev->agp_buffer_map = drm_core_findmap(dev, init->dma_handle); ++ if (!dev->agp_buffer_map) { ++ DRM_ERROR("failed to find dma buffer region!\n"); ++ goto error; ++ } ++ } ++ ++ dev_priv->bci = (char *)dev_priv->mmio->handle + 0x10000; ++ ++ return 0; ++ ++error: ++ /* do cleanup here, refine_later */ ++ return -EINVAL; ++} ++ ++int via_chrome9_heap_management_init(struct drm_device *dev, ++ struct drm_via_chrome9_init *init) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ int ret = 0; ++ ++ /* video memory management. range: 0 ---- video_whole_size */ ++ mutex_lock(&dev->struct_mutex); ++ ret = drm_sman_set_range(&dev_priv->sman, VIA_CHROME9_MEM_VIDEO, ++ 0, dev_priv->available_fb_size >> VIA_CHROME9_MM_GRANULARITY); ++ if (ret) { ++ DRM_ERROR("VRAM memory manager initialization ******ERROR\ ++ !******\n"); ++ mutex_unlock(&dev->struct_mutex); ++ goto error; ++ } ++ dev_priv->vram_initialized = 1; ++ /* agp/pcie heap management. ++ note:because agp is contradict with pcie, so only one is enough ++ for managing both of them.*/ ++ init->agp_type = dev_priv->drm_agp_type; ++ if (init->agp_type != AGP_DISABLED && dev_priv->agp_size) { ++ ret = drm_sman_set_range(&dev_priv->sman, VIA_CHROME9_MEM_AGP, ++ 0, dev_priv->agp_size >> VIA_CHROME9_MM_GRANULARITY); ++ if (ret) { ++ DRM_ERROR("AGP/PCIE memory manager initialization ******ERROR\ ++ !******\n"); ++ mutex_unlock(&dev->struct_mutex); ++ goto error; ++ } ++ dev_priv->agp_initialized = 1; ++ } ++ mutex_unlock(&dev->struct_mutex); ++ return 0; ++ ++error: ++ /* Do error recover here, refine_later */ ++ return -EINVAL; ++} ++ ++ ++void via_chrome9_memory_destroy_heap(struct drm_device *dev, ++ struct drm_via_chrome9_private *dev_priv) ++{ ++ mutex_lock(&dev->struct_mutex); ++ drm_sman_cleanup(&dev_priv->sman); ++ dev_priv->vram_initialized = 0; ++ dev_priv->agp_initialized = 0; ++ mutex_unlock(&dev->struct_mutex); ++} ++ ++void via_chrome9_reclaim_buffers_locked(struct drm_device *dev, ++ struct drm_file *file_priv) ++{ ++ return; ++} ++ ++int via_chrome9_ioctl_allocate_aperture(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++int via_chrome9_ioctl_free_aperture(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++ ++/* Allocate memory from DRM module for video playing */ ++int via_chrome9_ioctl_allocate_mem_base(struct drm_device *dev, ++void *data, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_mem *mem = data; ++ struct drm_memblock_item *item; ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ unsigned long tmpSize = 0, offset = 0, alignment = 0; ++ /* modify heap_type to agp for pcie, since we treat pcie/agp heap ++ no difference in heap management */ ++ if (mem->type == memory_heap_pcie) { ++ if (dev_priv->chip_agp != CHIP_PCIE) { ++ DRM_ERROR("User want to alloc memory from pcie heap \ ++ but via_chrome9.ko has no this heap exist.\n"); ++ return -EINVAL; ++ } ++ mem->type = memory_heap_agp; ++ } ++ ++ if (mem->type > VIA_CHROME9_MEM_AGP) { ++ DRM_ERROR("Unknown memory type allocation\n"); ++ return -EINVAL; ++ } ++ mutex_lock(&dev->struct_mutex); ++ if (0 == ((mem->type == VIA_CHROME9_MEM_VIDEO) ? ++ dev_priv->vram_initialized : dev_priv->agp_initialized)) { ++ DRM_ERROR("Attempt to allocate from uninitialized\ ++ memory manager.\n"); ++ mutex_unlock(&dev->struct_mutex); ++ return -EINVAL; ++ } ++ tmpSize = (mem->size + VIA_CHROME9_MM_GRANULARITY_MASK) >> ++ VIA_CHROME9_MM_GRANULARITY; ++ mem->size = tmpSize << VIA_CHROME9_MM_GRANULARITY; ++ alignment = (dev_priv->alignment & 0x80000000) ? dev_priv-> ++ alignment & 0x7FFFFFFF : 0; ++ alignment /= (1 << VIA_CHROME9_MM_GRANULARITY); ++ item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, alignment, ++ (unsigned long)file_priv); ++ mutex_unlock(&dev->struct_mutex); ++ /* alloc failed */ ++ if (!item) { ++ DRM_ERROR("Allocate memory failed ******ERROR******.\n"); ++ return -ENOMEM; ++ } ++ /* Till here every thing is ok, we check the memory type allocated ++ and return appropriate value to user mode Here the value return to ++ user is very difficult to operate. BE CAREFULLY!!! */ ++ /* offset is used by user mode ap to calculate the virtual address ++ which is used to access the memory allocated */ ++ mem->index = item->user_hash.key; ++ offset = item->mm->offset(item->mm, item->mm_info) << ++ VIA_CHROME9_MM_GRANULARITY; ++ switch (mem->type) { ++ case VIA_CHROME9_MEM_VIDEO: ++ mem->offset = offset + dev_priv->back_offset; ++ break; ++ case VIA_CHROME9_MEM_AGP: ++ /* return different value to user according to the chip type */ ++ if (dev_priv->chip_agp == CHIP_PCIE) { ++ mem->offset = offset + ++ ((struct drm_via_chrome9_DMA_manager *)dev_priv-> ++ dma_manager)->DMASize * sizeof(unsigned long); ++ } else { ++ mem->offset = offset; ++ } ++ break; ++ default: ++ /* Strange thing happen! Faint. Code bug! */ ++ DRM_ERROR("Enter here is impossible ******\ ++ ERROR******.\n"); ++ return -EINVAL; ++ } ++ /*DONE. Need we call function copy_to_user ?NO. We can't even ++ touch user's space.But we are lucky, since kernel drm:drm_ioctl ++ will to the job for us. */ ++ return 0; ++} ++ ++/* Allocate video/AGP/PCIE memory from heap management */ ++int via_chrome9_ioctl_allocate_mem_wrapper(struct drm_device ++ *dev, void *data, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_memory_alloc *memory_alloc = ++ (struct drm_via_chrome9_memory_alloc *)data; ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_mem mem; ++ ++ mem.size = memory_alloc->size; ++ mem.type = memory_alloc->heap_type; ++ dev_priv->alignment = memory_alloc->align | 0x80000000; ++ if (via_chrome9_ioctl_allocate_mem_base(dev, &mem, file_priv)) { ++ DRM_ERROR("Allocate memory error!.\n"); ++ return -ENOMEM; ++ } ++ dev_priv->alignment = 0; ++ /* Till here every thing is ok, we check the memory type allocated and ++ return appropriate value to user mode Here the value return to user is ++ very difficult to operate. BE CAREFULLY!!!*/ ++ /* offset is used by user mode ap to calculate the virtual address ++ which is used to access the memory allocated */ ++ memory_alloc->offset = mem.offset; ++ memory_alloc->heap_info.lpL1Node = (void *)mem.index; ++ memory_alloc->size = mem.size; ++ switch (memory_alloc->heap_type) { ++ case VIA_CHROME9_MEM_VIDEO: ++ memory_alloc->physaddress = memory_alloc->offset + ++ dev_priv->fb_base_address; ++ memory_alloc->linearaddress = (void *)memory_alloc->physaddress; ++ break; ++ case VIA_CHROME9_MEM_AGP: ++ /* return different value to user according to the chip type */ ++ if (dev_priv->chip_agp == CHIP_PCIE) { ++ memory_alloc->physaddress = memory_alloc->offset; ++ memory_alloc->linearaddress = (void *)memory_alloc-> ++ physaddress; ++ } else { ++ memory_alloc->physaddress = dev->agp->base + ++ memory_alloc->offset + ++ ((struct drm_via_chrome9_DMA_manager *) ++ dev_priv->dma_manager)->DMASize * sizeof(unsigned long); ++ memory_alloc->linearaddress = ++ (void *)memory_alloc->physaddress; ++ } ++ break; ++ default: ++ /* Strange thing happen! Faint. Code bug! */ ++ DRM_ERROR("Enter here is impossible ******ERROR******.\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int via_chrome9_ioctl_free_mem_wrapper(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_memory_alloc *memory_alloc = data; ++ struct drm_via_chrome9_mem mem; ++ ++ mem.index = (unsigned long)memory_alloc->heap_info.lpL1Node; ++ if (via_chrome9_ioctl_freemem_base(dev, &mem, file_priv)) { ++ DRM_ERROR("function free_mem_wrapper error.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int via_chrome9_ioctl_freemem_base(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ struct drm_via_chrome9_private *dev_priv = dev->dev_private; ++ struct drm_via_chrome9_mem *mem = data; ++ int ret; ++ ++ mutex_lock(&dev->struct_mutex); ++ ret = drm_sman_free_key(&dev_priv->sman, mem->index); ++ mutex_unlock(&dev->struct_mutex); ++ DRM_DEBUG("free = 0x%lx\n", mem->index); ++ ++ return ret; ++} ++ ++int via_chrome9_ioctl_check_vidmem_size(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++int via_chrome9_ioctl_pciemem_ctrl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv) ++{ ++ int result = 0; ++ struct drm_via_chrome9_private *dev_priv = dev->dev_private; ++ struct drm_via_chrome9_pciemem_ctrl *pcie_memory_ctrl = data; ++ switch (pcie_memory_ctrl->ctrl_type) { ++ case pciemem_copy_from_user: ++ result = copy_from_user((void *)( ++ dev_priv->pcie_vmalloc_nocache+ ++ pcie_memory_ctrl->pcieoffset), ++ pcie_memory_ctrl->usermode_data, ++ pcie_memory_ctrl->size); ++ break; ++ case pciemem_copy_to_user: ++ result = copy_to_user(pcie_memory_ctrl->usermode_data, ++ (void *)(dev_priv->pcie_vmalloc_nocache+ ++ pcie_memory_ctrl->pcieoffset), ++ pcie_memory_ctrl->size); ++ break; ++ case pciemem_memset: ++ memset((void *)(dev_priv->pcie_vmalloc_nocache + ++ pcie_memory_ctrl->pcieoffset), ++ pcie_memory_ctrl->memsetdata, ++ pcie_memory_ctrl->size); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++ ++int via_fb_alloc(struct drm_via_chrome9_mem *mem) ++{ ++ struct drm_device *dev = (struct drm_device *)via_chrome9_dev_v4l; ++ struct drm_via_chrome9_private *dev_priv; ++ ++ if (!dev || !dev->dev_private || !via_chrome9_filepriv_v4l) { ++ DRM_ERROR("V4L work before X initialize DRM module !!!\n"); ++ return -EINVAL; ++ } ++ ++ dev_priv = (struct drm_via_chrome9_private *)dev->dev_private; ++ if (!dev_priv->vram_initialized || ++ mem->type != VIA_CHROME9_MEM_VIDEO) { ++ DRM_ERROR("the memory type from V4L is error !!!\n"); ++ return -EINVAL; ++ } ++ ++ if (via_chrome9_ioctl_allocate_mem_base(dev, ++ mem, via_chrome9_filepriv_v4l)) { ++ DRM_ERROR("DRM module allocate memory error for V4L!!!\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(via_fb_alloc); ++ ++int via_fb_free(struct drm_via_chrome9_mem *mem) ++{ ++ struct drm_device *dev = (struct drm_device *)via_chrome9_dev_v4l; ++ struct drm_via_chrome9_private *dev_priv; ++ ++ if (!dev || !dev->dev_private || !via_chrome9_filepriv_v4l) ++ return -EINVAL; ++ ++ dev_priv = (struct drm_via_chrome9_private *)dev->dev_private; ++ if (!dev_priv->vram_initialized || ++ mem->type != VIA_CHROME9_MEM_VIDEO) ++ return -EINVAL; ++ ++ if (via_chrome9_ioctl_freemem_base(dev, mem, via_chrome9_filepriv_v4l)) ++ return -EINVAL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(via_fb_free); +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_mm.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. ++ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to ++ * whom the Software is furnished to do so, subject to the ++ * following conditions: ++ * ++ * The above copyright notice and this permission notice ++ * (including the next paragraph) shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NON-INFRINGEMENT. IN NO EVENT SHALL VIA, S3 GRAPHICS, AND/OR ++ * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++ * THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#ifndef _VIA_CHROME9_MM_H_ ++#define _VIA_CHROME9_MM_H_ ++struct drm_via_chrome9_pciemem_ctrl { ++ enum { ++ pciemem_copy_from_user = 0, ++ pciemem_copy_to_user, ++ pciemem_memset, ++ } ctrl_type; ++ unsigned int pcieoffset; ++ unsigned int size;/*in Byte*/ ++ unsigned char memsetdata;/*for memset*/ ++ void *usermode_data;/*user mode data pointer*/ ++}; ++ ++extern int via_chrome9_map_init(struct drm_device *dev, ++ struct drm_via_chrome9_init *init); ++extern int via_chrome9_heap_management_init(struct drm_device ++ *dev, struct drm_via_chrome9_init *init); ++extern void via_chrome9_memory_destroy_heap(struct drm_device ++ *dev, struct drm_via_chrome9_private *dev_priv); ++extern int via_chrome9_ioctl_check_vidmem_size(struct drm_device ++ *dev, void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_pciemem_ctrl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_allocate_aperture(struct drm_device ++ *dev, void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_free_aperture(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_allocate_mem_base(struct drm_device ++ *dev, void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_allocate_mem_wrapper( ++ struct drm_device *dev, void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_freemem_base(struct drm_device ++ *dev, void *data, struct drm_file *file_priv); ++extern int via_chrome9_ioctl_free_mem_wrapper(struct drm_device ++ *dev, void *data, struct drm_file *file_priv); ++extern void via_chrome9_reclaim_buffers_locked(struct drm_device ++ *dev, struct drm_file *file_priv); ++ ++#endif ++ +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_verifier.c +@@ -0,0 +1,982 @@ ++/* ++* Copyright 2004 The Unichrome Project. All Rights Reserved. ++* Copyright 2005 Thomas Hellstrom. All Rights Reserved. ++* ++* Permission is hereby granted, free of charge, to any person obtaining a ++* copy of this software and associated documentation files (the "Software"), ++* to deal in the Software without restriction, including without limitation ++* the rights to use, copy, modify, merge, publish, distribute, sub license, ++* and/or sell copies of the Software, and to permit persons to whom the ++* Software is furnished to do so, subject to the following conditions: ++* ++* The above copyright notice and this permission notice (including the ++* next paragraph) shall be included in all copies or substantial portions ++* of the Software. ++* ++* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++* THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES ++* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++* DEALINGS IN THE SOFTWARE. ++* ++* This code was written using docs obtained under NDA from VIA Inc. ++* ++* Don't run this code directly on an AGP buffer. Due to cache problems it will ++* be very slow. ++*/ ++ ++#include "via_chrome9_3d_reg.h" ++#include "drmP.h" ++#include "drm.h" ++#include "via_chrome9_drm.h" ++#include "via_chrome9_verifier.h" ++#include "via_chrome9_drv.h" ++ ++#if VIA_CHROME9_VERIFY_ENABLE ++ ++enum verifier_state { ++ state_command, ++ state_header0, ++ state_header1, ++ state_header2, ++ state_header3, ++ state_header4, ++ state_header5, ++ state_header6, ++ state_header7, ++ state_error ++}; ++ ++enum hazard { ++ no_check = 0, ++ check_render_target_addr0, ++ check_render_target_addr1, ++ check_render_target_addr_mode, ++ check_z_buffer_addr0, ++ check_z_buffer_addr1, ++ check_z_buffer_addr_mode, ++ check_zocclusion_addr0, ++ check_zocclusion_addr1, ++ check_coarse_z_addr0, ++ check_coarse_z_addr1, ++ check_fvf_addr_mode, ++ check_t_level0_facen_addr0, ++ check_fence_cmd_addr0, ++ check_fence_cmd_addr1, ++ check_fence_cmd_addr2, ++ forbidden_command ++}; ++ ++/* ++ * Associates each hazard above with a possible multi-command ++ * sequence. For example an address that is split over multiple ++ * commands and that needs to be checked at the first command ++ * that does not include any part of the address. ++ */ ++ ++static enum drm_via_chrome9_sequence seqs[] = { ++ no_sequence, ++ dest_address, ++ dest_address, ++ dest_address, ++ z_address, ++ z_address, ++ z_address, ++ zocclusion_address, ++ zocclusion_address, ++ coarse_z_address, ++ coarse_z_address, ++ fvf_address, ++ tex_address, ++ fence_cmd_address, ++ fence_cmd_address, ++ fence_cmd_address, ++ no_sequence ++}; ++ ++struct hz_init { ++ unsigned int code; ++ enum hazard hz; ++}; ++/* for atrribute other than context hazard detect */ ++static struct hz_init init_table1[] = { ++ {0xcc, no_check}, ++ {0xcd, no_check}, ++ {0xce, no_check}, ++ {0xcf, no_check}, ++ {0xdd, no_check}, ++ {0xee, no_check}, ++ {0x00, no_check}, ++ {0x01, no_check}, ++ {0x10, check_z_buffer_addr0}, ++ {0x11, check_z_buffer_addr1}, ++ {0x12, check_z_buffer_addr_mode}, ++ {0x13, no_check}, ++ {0x14, no_check}, ++ {0x15, no_check}, ++ {0x16, no_check}, ++ {0x17, no_check}, ++ {0x18, no_check}, ++ {0x19, no_check}, ++ {0x1a, no_check}, ++ {0x1b, no_check}, ++ {0x1c, no_check}, ++ {0x1d, no_check}, ++ {0x1e, no_check}, ++ {0x1f, no_check}, ++ {0x20, no_check}, ++ {0x21, check_zocclusion_addr0}, ++ {0x22, check_zocclusion_addr1}, ++ {0x23, no_check}, ++ {0x24, no_check}, ++ {0x25, no_check}, ++ {0x26, no_check}, ++ {0x27, no_check}, ++ /* H5 only*/ ++ {0x28, no_check}, ++ {0x29, check_coarse_z_addr0}, ++ {0x2a, check_coarse_z_addr1}, ++ {0x33, no_check}, ++ {0x34, no_check}, ++ {0x35, no_check}, ++ {0x36, no_check}, ++ {0x37, no_check}, ++ {0x38, no_check}, ++ {0x39, no_check}, ++ {0x3A, no_check}, ++ {0x3B, no_check}, ++ {0x3C, no_check}, ++ {0x3D, no_check}, ++ {0x3E, no_check}, ++ {0x3F, no_check}, ++ /*render target check */ ++ {0x50, check_render_target_addr0}, ++ /* H5/H6 different */ ++ {0x51, check_render_target_addr_mode}, ++ {0x52, check_render_target_addr1}, ++ {0x53, no_check}, ++ {0x58, check_render_target_addr0}, ++ {0x59, check_render_target_addr_mode}, ++ {0x5a, check_render_target_addr1}, ++ {0x5b, no_check}, ++ {0x60, check_render_target_addr0}, ++ {0x61, check_render_target_addr_mode}, ++ {0x62, check_render_target_addr1}, ++ {0x63, no_check}, ++ {0x68, check_render_target_addr0}, ++ {0x69, check_render_target_addr_mode}, ++ {0x6a, check_render_target_addr1}, ++ {0x6b, no_check}, ++ {0x70, no_check}, ++ {0x71, no_check}, ++ {0x72, no_check}, ++ {0x73, no_check}, ++ {0x74, no_check}, ++ {0x75, no_check}, ++ {0x76, no_check}, ++ {0x77, no_check}, ++ {0x78, no_check}, ++ {0x80, no_check}, ++ {0x81, no_check}, ++ {0x82, no_check}, ++ {0x83, no_check}, ++ {0x84, no_check}, ++ {0x85, no_check}, ++ {0x86, no_check}, ++ {0x87, no_check}, ++ {0x88, no_check}, ++ {0x89, no_check}, ++ {0x8a, no_check}, ++ {0x90, no_check}, ++ {0x91, no_check}, ++ {0x92, no_check}, ++ {0x93, no_check}, ++ {0x94, no_check}, ++ {0x95, no_check}, ++ {0x96, no_check}, ++ {0x97, no_check}, ++ {0x98, no_check}, ++ {0x99, no_check}, ++ {0x9a, no_check}, ++ {0x9b, no_check}, ++ {0xaa, no_check} ++}; ++ ++/* for texture stage's hazard detect */ ++static struct hz_init init_table2[] = { ++ {0xcc, no_check}, ++ {0xcd, no_check}, ++ {0xce, no_check}, ++ {0xcf, no_check}, ++ {0xdd, no_check}, ++ {0xee, no_check}, ++ {0x00, no_check}, ++ {0x01, no_check}, ++ {0x02, no_check}, ++ {0x03, no_check}, ++ {0x04, no_check}, ++ {0x05, no_check}, ++ /* H5/H6 diffent */ ++ {0x18, check_t_level0_facen_addr0}, ++ {0x20, no_check}, ++ {0x21, no_check}, ++ {0x22, no_check}, ++ {0x30, no_check}, ++ {0x50, no_check}, ++ {0x51, no_check}, ++ {0x9b, no_check}, ++}; ++ ++/*Check for flexible vertex format */ ++static struct hz_init init_table3[] = { ++ {0xcc, no_check}, ++ {0xcd, no_check}, ++ {0xce, no_check}, ++ {0xcf, no_check}, ++ {0xdd, no_check}, ++ {0xee, no_check}, ++ /* H5/H6 different */ ++ {0x00, check_fvf_addr_mode}, ++ {0x01, no_check}, ++ {0x02, no_check}, ++ {0x03, no_check}, ++ {0x04, no_check}, ++ {0x05, no_check}, ++ {0x08, no_check}, ++ {0x09, no_check}, ++ {0x0a, no_check}, ++ {0x0b, no_check}, ++ {0x0c, no_check}, ++ {0x0d, no_check}, ++ {0x0e, no_check}, ++ {0x0f, no_check}, ++ {0x10, no_check}, ++ {0x11, no_check}, ++ {0x12, no_check}, ++ {0x13, no_check}, ++ {0x14, no_check}, ++ {0x15, no_check}, ++ {0x16, no_check}, ++ {0x17, no_check}, ++ {0x18, no_check}, ++ {0x19, no_check}, ++ {0x1a, no_check}, ++ {0x1b, no_check}, ++ {0x1c, no_check}, ++ {0x1d, no_check}, ++ {0x1e, no_check}, ++ {0x1f, no_check}, ++ {0x20, no_check}, ++ {0x21, no_check}, ++ {0x22, no_check}, ++ {0x23, no_check}, ++ {0x24, no_check}, ++ {0x25, no_check}, ++ {0x26, no_check}, ++ {0x27, no_check}, ++ {0x28, no_check}, ++ {0x29, no_check}, ++ {0x2a, no_check}, ++ {0x2b, no_check}, ++ {0x2c, no_check}, ++ {0x2d, no_check}, ++ {0x2e, no_check}, ++ {0x2f, no_check}, ++ {0x40, no_check}, ++ {0x41, no_check}, ++ {0x42, no_check}, ++ {0x43, no_check}, ++ {0x44, no_check}, ++ {0x45, no_check}, ++ {0x46, no_check}, ++ {0x47, no_check}, ++ {0x48, no_check}, ++ {0x50, no_check}, ++ {0x51, no_check}, ++ {0x52, no_check}, ++ {0x60, no_check}, ++ {0x61, no_check}, ++ {0x62, no_check}, ++ {0x9b, no_check}, ++ {0xaa, no_check} ++}; ++/*Check for 364 fence command id*/ ++static struct hz_init init_table4[] = { ++ {0xcc, no_check}, ++ {0xcd, no_check}, ++ {0xce, no_check}, ++ {0xcf, no_check}, ++ {0xdd, no_check}, ++ {0xee, no_check}, ++ {0x00, no_check}, ++ {0x01, check_fence_cmd_addr0}, ++ {0x02, check_fence_cmd_addr1}, ++ {0x03, check_fence_cmd_addr2}, ++ {0x10, no_check}, ++ {0x11, no_check}, ++ {0x12, no_check}, ++ {0x13, no_check}, ++ {0x14, no_check}, ++ {0x18, no_check}, ++ {0x19, no_check}, ++ {0x1a, no_check}, ++ {0x1b, no_check}, ++ {0x1c, no_check}, ++ {0x20, no_check}, ++ {0xab, no_check}, ++ {0xaa, no_check} ++}; ++ ++/*Check for 353 fence command id*/ ++static struct hz_init init_table5[] = { ++ {0xcc, no_check}, ++ {0xcd, no_check}, ++ {0xce, no_check}, ++ {0xcf, no_check}, ++ {0xdd, no_check}, ++ {0xee, no_check}, ++ {0x00, no_check}, ++ {0x01, no_check}, ++ {0x02, no_check}, ++ {0x03, no_check}, ++ {0x04, check_fence_cmd_addr0}, ++ {0x05, check_fence_cmd_addr1}, ++ {0x06, no_check}, ++ {0x07, check_fence_cmd_addr2}, ++ {0x08, no_check}, ++ {0x09, no_check}, ++ {0x0a, no_check}, ++ {0x0b, no_check}, ++ {0x0c, no_check}, ++ {0x0d, no_check}, ++ {0x0e, no_check}, ++ {0x0f, no_check}, ++ {0x10, no_check}, ++ {0x11, no_check}, ++ {0x12, no_check}, ++ {0x18, no_check}, ++ {0x19, no_check}, ++ {0x1a, no_check}, ++ {0x30, no_check}, ++ {0x31, no_check}, ++ {0x32, no_check}, ++ {0x68, no_check}, ++ {0x69, no_check}, ++ {0x6a, no_check}, ++ {0x6b, no_check}, ++ {0xab, no_check}, ++ {0xaa, no_check} ++}; ++ ++static enum hazard init_table_01_00[256]; ++static enum hazard init_table_02_0n[256]; ++static enum hazard init_table_04_00[256]; ++static enum hazard init_table_11_364[256]; ++static enum hazard init_table_11_353[256]; ++ ++/*Require fence command id location reside in the shadow system memory */ ++static inline int ++check_fence_cmd_addr_range(struct drm_via_chrome9_state *seq, ++ unsigned long fence_cmd_add, unsigned long size, struct drm_device *dev) ++{ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *)dev->dev_private; ++ if (!dev_priv->shadow_map.shadow) ++ return -1; ++ if ((fence_cmd_add < dev_priv->shadow_map.shadow->offset) || ++ (fence_cmd_add + size > ++ dev_priv->shadow_map.shadow->offset + ++ dev_priv->shadow_map.shadow->size)) ++ return -1; ++ return 0; ++} ++ ++/* ++ * Currently we only catch the fence cmd's address, which will ++ * access system memory inevitably. ++ * NOTE:No care about AGP address.(we just think all AGP access are safe now). ++ */ ++ ++static inline int finish_current_sequence(struct drm_via_chrome9_state *cur_seq) ++{ ++ switch (cur_seq->unfinished) { ++ case fence_cmd_address: ++ if (cur_seq->fence_need_check) ++ if (check_fence_cmd_addr_range(cur_seq, ++ cur_seq->fence_cmd_addr, 4, cur_seq->dev)) ++ return -EINVAL; ++ break; ++ default: ++ break; ++ } ++ cur_seq->unfinished = no_sequence; ++ return 0; ++} ++/* Only catch the cmd which potentially access the system memory, and treat all ++ * the other cmds are safe. ++ */ ++static inline int ++investigate_hazard(uint32_t cmd, enum hazard hz, ++ struct drm_via_chrome9_state *cur_seq) ++{ ++ register uint32_t tmp; ++ ++ if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) { ++ int ret = finish_current_sequence(cur_seq); ++ if (ret) ++ return ret; ++ } ++ ++ switch (hz) { ++ case check_render_target_addr0: ++ tmp = ((cmd >> 24) - 0x50) >> 3; ++ cur_seq->unfinished = dest_address; ++ cur_seq->render_target_addr[tmp] = cmd << 8; ++ break; ++ case check_render_target_addr1: ++ cur_seq->unfinished = dest_address; ++ tmp = ((cmd >> 24) - 0x50) >> 3; ++ cur_seq->render_target_pitch[tmp] = (cmd & 0x000001FF) >> 5; ++ break; ++ case check_render_target_addr_mode: ++ cur_seq->unfinished = dest_address; ++ if (!cur_seq->agp) ++ if (((cmd & 0x00300000) >> 20) == 2) { ++ DRM_ERROR("Attempt to place \ ++ render target in system memory\n"); ++ return -EINVAL; ++ } ++ break; ++ case check_z_buffer_addr0: ++ cur_seq->unfinished = z_address; ++ break; ++ case check_z_buffer_addr1: ++ cur_seq->unfinished = z_address; ++ if ((cmd & 0x00000003) == 2) { ++ DRM_ERROR("Attempt to place \ ++ Z buffer in system memory\n"); ++ return -EINVAL; ++ } ++ break; ++ case check_z_buffer_addr_mode: ++ cur_seq->unfinished = z_address; ++ if (((cmd & 0x00000060) >> 5) == 2) { ++ DRM_ERROR("Attempt to place \ ++ stencil buffer in system memory\n"); ++ return -EINVAL; ++ } ++ break; ++ case check_zocclusion_addr0: ++ cur_seq->unfinished = zocclusion_address; ++ break; ++ case check_zocclusion_addr1: ++ cur_seq->unfinished = zocclusion_address; ++ if (((cmd & 0x00c00000) >> 22) == 2) { ++ DRM_ERROR("Attempt to access system memory\n"); ++ return -EINVAL; ++ } ++ break; ++ case check_coarse_z_addr0: ++ cur_seq->unfinished = coarse_z_address; ++ if (((cmd & 0x00300000) >> 20) == 2) ++ return -EINVAL; ++ break; ++ case check_coarse_z_addr1: ++ cur_seq->unfinished = coarse_z_address; ++ break; ++ case check_fvf_addr_mode: ++ cur_seq->unfinished = fvf_address; ++ if (!cur_seq->agp) ++ if (((cmd & 0x0000c000) >> 14) == 2) { ++ DRM_ERROR("Attempt to place \ ++ fvf buffer in system memory\n"); ++ return -EINVAL; ++ } ++ break; ++ case check_t_level0_facen_addr0: ++ cur_seq->unfinished = tex_address; ++ if (!cur_seq->agp) ++ if ((cmd & 0x00000003) == 2 || ++ ((cmd & 0x0000000c) >> 2) == 2 || ++ ((cmd & 0x00000030) >> 4) == 2 || ++ ((cmd & 0x000000c0) >> 6) == 2 || ++ ((cmd & 0x0000c000) >> 14) == 2 || ++ ((cmd & 0x00030000) >> 16) == 2) { ++ DRM_ERROR("Attempt to place \ ++ texture buffer in system memory\n"); ++ return -EINVAL; ++ } ++ break; ++ case check_fence_cmd_addr0: ++ cur_seq->unfinished = fence_cmd_address; ++ if (cur_seq->agp) ++ cur_seq->fence_cmd_addr = ++ (cur_seq->fence_cmd_addr & 0xFF000000) | ++ (cmd & 0x00FFFFFF); ++ else ++ cur_seq->fence_cmd_addr = ++ (cur_seq->fence_cmd_addr & 0x00FFFFFF) | ++ ((cmd & 0x000000FF) << 24); ++ break; ++ case check_fence_cmd_addr1: ++ cur_seq->unfinished = fence_cmd_address; ++ if (!cur_seq->agp) ++ cur_seq->fence_cmd_addr = ++ (cur_seq->fence_cmd_addr & 0xFF000000) | ++ (cmd & 0x00FFFFFF); ++ break; ++ case check_fence_cmd_addr2: ++ cur_seq->unfinished = fence_cmd_address; ++ if (cmd & 0x00040000) ++ cur_seq->fence_need_check = 1; ++ else ++ cur_seq->fence_need_check = 0; ++ break; ++ default: ++ /*We think all the other cmd are safe.*/ ++ return 0; ++ } ++ return 0; ++} ++ ++static inline int verify_mmio_address(uint32_t address) ++{ ++ if ((address > 0x3FF) && (address < 0xC00)) { ++ DRM_ERROR("Invalid VIDEO DMA command. " ++ "Attempt to access 3D- or command burst area.\n"); ++ return 1; ++ } else if ((address > 0xDFF) && (address < 0x1200)) { ++ DRM_ERROR("Invalid VIDEO DMA command. " ++ "Attempt to access PCI DMA area.\n"); ++ return 1; ++ } else if ((address > 0x1DFF) && (address < 0x2200)) { ++ DRM_ERROR("Invalid VIDEO DMA command. " ++ "Attempt to access CBU ROTATE SPACE registers.\n"); ++ return 1; ++ } else if ((address > 0x23FF) && (address < 0x3200)) { ++ DRM_ERROR("Invalid VIDEO DMA command. " ++ "Attempt to access PCI DMA2 area..\n"); ++ return 1; ++ } else if (address > 0x33FF) { ++ DRM_ERROR("Invalid VIDEO DMA command. " ++ "Attempt to access VGA registers.\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++static inline int is_dummy_cmd(uint32_t cmd) ++{ ++ if ((cmd & INV_DUMMY_MASK) == 0xCC000000 || ++ (cmd & INV_DUMMY_MASK) == 0xCD000000 || ++ (cmd & INV_DUMMY_MASK) == 0xCE000000 || ++ (cmd & INV_DUMMY_MASK) == 0xCF000000 || ++ (cmd & INV_DUMMY_MASK) == 0xDD000000) ++ return 1; ++ return 0; ++} ++ ++static inline int ++verify_2d_tail(uint32_t const **buffer, const uint32_t *buf_end, ++ uint32_t dwords) ++{ ++ const uint32_t *buf = *buffer; ++ ++ if (buf_end - buf < dwords) { ++ DRM_ERROR("Illegal termination of 2d command.\n"); ++ return 1; ++ } ++ ++ while (dwords--) { ++ if (!is_dummy_cmd(*buf++)) { ++ DRM_ERROR("Illegal 2d command tail.\n"); ++ return 1; ++ } ++ } ++ ++ *buffer = buf; ++ return 0; ++} ++ ++static inline int ++verify_video_tail(uint32_t const **buffer, const uint32_t *buf_end, ++ uint32_t dwords) ++{ ++ const uint32_t *buf = *buffer; ++ ++ if (buf_end - buf < dwords) { ++ DRM_ERROR("Illegal termination of video command.\n"); ++ return 1; ++ } ++ while (dwords--) { ++ if (*buf && !is_dummy_cmd(*buf)) { ++ DRM_ERROR("Illegal video command tail.\n"); ++ return 1; ++ } ++ buf++; ++ } ++ *buffer = buf; ++ return 0; ++} ++ ++static inline enum verifier_state ++via_chrome9_check_header0(uint32_t const **buffer, const uint32_t *buf_end) ++{ ++ const uint32_t *buf = *buffer; ++ uint32_t cmd, qword, dword; ++ ++ qword = *(buf+1); ++ buf += 4; ++ dword = qword << 1; ++ ++ if (buf_end - buf < dword) ++ return state_error; ++ ++ while (qword-- > 0) { ++ cmd = *buf; ++ /* Is this consition too restrict? */ ++ if ((cmd & 0xFFFF) > 0x1FF) { ++ DRM_ERROR("Invalid header0 command io address 0x%x \ ++ Attempt to access non-2D mmio area.\n", cmd); ++ return state_error; ++ } ++ buf += 2; ++ } ++ ++ if ((dword & 3) && verify_2d_tail(&buf, buf_end, 4 - (dword & 0x3))) ++ return state_error; ++ ++ *buffer = buf; ++ return state_command; ++} ++ ++static inline enum verifier_state ++via_chrome9_check_header1(uint32_t const **buffer, const uint32_t *buf_end) ++{ ++ uint32_t dword; ++ const uint32_t *buf = *buffer; ++ ++ dword = *(buf + 1); ++ buf += 4; ++ ++ if (buf + dword > buf_end) ++ return state_error; ++ ++ buf += dword; ++ ++ if ((dword & 0x3) && verify_2d_tail(&buf, buf_end, 4 - (dword & 0x3))) ++ return state_error; ++ ++ *buffer = buf; ++ return state_command; ++} ++ ++static inline enum verifier_state ++via_chrome9_check_header2(uint32_t const **buffer, ++ const uint32_t *buf_end, struct drm_via_chrome9_state *hc_state) ++{ ++ uint32_t cmd1, cmd2; ++ enum hazard hz; ++ const uint32_t *buf = *buffer; ++ const enum hazard *hz_table; ++ ++ if ((buf_end - buf) < 4) { ++ DRM_ERROR ++ ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n"); ++ return state_error; ++ } ++ cmd1 = *buf & 0x0000FFFF; ++ cmd2 = *++buf & 0x0000FFFF; ++ if (((cmd1 != INV_REG_CR_BEGIN) && (cmd1 != INV_REG_3D_BEGIN)) || ++ ((cmd2 != INV_REG_CR_TRANS) && (cmd2 != INV_REG_3D_TRANS))) { ++ DRM_ERROR ++ ("Illegal IO address of DMA HALCYON_HEADER2 sequence.\n"); ++ return state_error; ++ } ++ /* Advance to get paratype and subparatype */ ++ cmd1 = *++buf & 0xFFFF0000; ++ ++ switch (cmd1) { ++ case INV_ParaType_Attr: ++ buf += 2; ++ hz_table = init_table_01_00; ++ break; ++ case (INV_ParaType_Tex | (INV_SubType_Tex0 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex1 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex2 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex3 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex4 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex5 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex6 << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_Tex7 << 24)): ++ buf += 2; ++ hc_state->texture_index = (cmd1 & INV_ParaSubType_MASK) >> 24; ++ hz_table = init_table_02_0n; ++ break; ++ case INV_ParaType_FVF: ++ buf += 2; ++ hz_table = init_table_04_00; ++ break; ++ case INV_ParaType_CR: ++ buf += 2; ++ if (hc_state->agp) ++ hz_table = init_table_11_364; ++ else ++ hz_table = init_table_11_353; ++ break; ++ case INV_ParaType_Dummy: ++ buf += 2; ++ while ((buf < buf_end) && !is_agp_header(*buf)) ++ if (!is_dummy_cmd(*buf)) ++ return state_error; ++ else ++ buf++; ++ ++ if ((buf_end > buf) && ((buf_end - buf) & 0x3)) ++ return state_error; ++ return state_command; ++ /* We think cases below are all safe. So we feedback only when these ++ these cmd has another header there. ++ */ ++ case INV_ParaType_Vdata: ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex0 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex1 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex2 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex3 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex4 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex5 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex6 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | ++ ((INV_SubType_Tex7 | INV_SubType_TexSample) << 24)): ++ case (INV_ParaType_Tex | (INV_SubType_General << 24)): ++ case INV_ParaType_Pal: ++ case INV_ParaType_PreCR: ++ case INV_ParaType_Cfg: ++ default: ++ buf += 2; ++ while ((buf < buf_end) && !is_agp_header(*buf)) ++ buf++; ++ *buffer = buf; ++ return state_command; ++ } ++ ++ while (buf < buf_end && !is_agp_header(*buf)) { ++ cmd1 = *buf++; ++ hz = hz_table[cmd1 >> 24]; ++ if (hz) { ++ if (investigate_hazard(cmd1, hz, hc_state)) ++ return state_error; ++ } else if (hc_state->unfinished && ++ finish_current_sequence(hc_state)) ++ return state_error; ++ ++ } ++ if (hc_state->unfinished && finish_current_sequence(hc_state)) ++ return state_error; ++ *buffer = buf; ++ return state_command; ++} ++ ++static inline enum verifier_state ++via_chrome9_check_header3(uint32_t const **buffer, ++ const uint32_t *buf_end) ++{ ++ const uint32_t *buf = *buffer; ++ ++ buf += 4; ++ while (buf < buf_end && !is_agp_header(*buf)) ++ buf += 4; ++ ++ *buffer = buf; ++ return state_command; ++} ++ ++ ++static inline enum verifier_state ++via_chrome9_check_vheader4(uint32_t const **buffer, ++ const uint32_t *buf_end) ++{ ++ uint32_t data; ++ const uint32_t *buf = *buffer; ++ ++ if (buf_end - buf < 4) { ++ DRM_ERROR("Illegal termination of video header4 command\n"); ++ return state_error; ++ } ++ ++ data = *buf++ & ~INV_AGPHeader_MASK; ++ if (verify_mmio_address(data)) ++ return state_error; ++ ++ data = *buf; ++ buf += 2; ++ ++ if (*buf++ != 0x00000000) { ++ DRM_ERROR("Illegal header4 header data\n"); ++ return state_error; ++ } ++ ++ if (buf_end - buf < data) ++ return state_error; ++ buf += data; ++ ++ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) ++ return state_error; ++ *buffer = buf; ++ return state_command; ++ ++} ++ ++static inline enum verifier_state ++via_chrome9_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end) ++{ ++ uint32_t data; ++ const uint32_t *buf = *buffer; ++ uint32_t i; ++ ++ if (buf_end - buf < 4) { ++ DRM_ERROR("Illegal termination of video header5 command\n"); ++ return state_error; ++ } ++ ++ data = *++buf; ++ buf += 2; ++ ++ if (*buf++ != 0x00000000) { ++ DRM_ERROR("Illegal header5 header data\n"); ++ return state_error; ++ } ++ if ((buf_end - buf) < (data << 1)) { ++ DRM_ERROR("Illegal termination of video header5 command\n"); ++ return state_error; ++ } ++ for (i = 0; i < data; ++i) { ++ if (verify_mmio_address(*buf++)) ++ return state_error; ++ buf++; ++ } ++ data <<= 1; ++ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) ++ return state_error; ++ *buffer = buf; ++ return state_command; ++} ++ ++int ++via_chrome9_verify_command_stream(const uint32_t *buf, ++ unsigned int size, struct drm_device *dev, int agp) ++{ ++ ++ struct drm_via_chrome9_private *dev_priv = ++ (struct drm_via_chrome9_private *) dev->dev_private; ++ struct drm_via_chrome9_state *hc_state = &dev_priv->hc_state; ++ struct drm_via_chrome9_state saved_state = *hc_state; ++ uint32_t cmd; ++ const uint32_t *buf_end = buf + (size >> 2); ++ enum verifier_state state = state_command; ++ ++ hc_state->dev = dev; ++ hc_state->unfinished = no_sequence; ++ hc_state->agp = agp; ++ ++ while (buf < buf_end) { ++ ++ switch (state) { ++ case state_header0: ++ state = via_chrome9_check_header0(&buf, buf_end); ++ break; ++ case state_header1: ++ state = via_chrome9_check_header1(&buf, buf_end); ++ break; ++ case state_header2: ++ state = via_chrome9_check_header2(&buf, ++ buf_end, hc_state); ++ break; ++ case state_header3: ++ state = via_chrome9_check_header3(&buf, buf_end); ++ break; ++ case state_header4: ++ state = via_chrome9_check_vheader4(&buf, buf_end); ++ break; ++ case state_header5: ++ state = via_chrome9_check_vheader5(&buf, buf_end); ++ break; ++ case state_header6: ++ case state_header7: ++ DRM_ERROR("Unimplemented Header 6/7 command.\n"); ++ state = state_error; ++ break; ++ case state_command: ++ cmd = *buf; ++ if (INV_AGPHeader2 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header2; ++ else if (INV_AGPHeader1 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header1; ++ else if (INV_AGPHeader5 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header5; ++ else if (INV_AGPHeader6 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header6; ++ else if (INV_AGPHeader3 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header3; ++ else if (INV_AGPHeader4 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header4; ++ else if (INV_AGPHeader7 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header7; ++ else if (INV_AGPHeader0 == (cmd & INV_AGPHeader_MASK)) ++ state = state_header0; ++ else { ++ DRM_ERROR("Invalid command sequence\n"); ++ state = state_error; ++ } ++ break; ++ case state_error: ++ default: ++ *hc_state = saved_state; ++ return -EINVAL; ++ } ++ } ++ if (state == state_error) { ++ *hc_state = saved_state; ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++ ++static void ++setup_hazard_table(struct hz_init init_table[], ++enum hazard table[], int size) ++{ ++ int i; ++ ++ for (i = 0; i < 256; ++i) ++ table[i] = forbidden_command; ++ ++ for (i = 0; i < size; ++i) ++ table[init_table[i].code] = init_table[i].hz; ++} ++ ++void via_chrome9_init_command_verifier(void) ++{ ++ setup_hazard_table(init_table1, init_table_01_00, ++ sizeof(init_table1) / sizeof(struct hz_init)); ++ setup_hazard_table(init_table2, init_table_02_0n, ++ sizeof(init_table2) / sizeof(struct hz_init)); ++ setup_hazard_table(init_table3, init_table_04_00, ++ sizeof(init_table3) / sizeof(struct hz_init)); ++ setup_hazard_table(init_table4, init_table_11_364, ++ sizeof(init_table4) / sizeof(struct hz_init)); ++ setup_hazard_table(init_table5, init_table_11_353, ++ sizeof(init_table5) / sizeof(struct hz_init)); ++} ++ ++#endif +--- /dev/null ++++ b/drivers/gpu/drm/via_chrome9/via_chrome9_verifier.h +@@ -0,0 +1,61 @@ ++/* ++* Copyright 2004 The Unichrome Project. All Rights Reserved. ++* ++* Permission is hereby granted, free of charge, to any person obtaining a ++* copy of this software and associated documentation files (the "Software"), ++* to deal in the Software without restriction, including without limitation ++* the rights to use, copy, modify, merge, publish, distribute, sub license, ++* and/or sell copies of the Software, and to permit persons to whom the ++* Software is furnished to do so, subject to the following conditions: ++* ++* The above copyright notice and this permission notice (including the ++* next paragraph) shall be included in all copies or substantial portions ++* of the Software. ++* ++* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++* THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ++* THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++* ++* Author: Scott Fang 2008. ++*/ ++ ++#ifndef _via_chrome9_VERIFIER_H_ ++#define _via_chrome9_VERIFIER_H_ ++ ++#define VIA_CHROME9_VERIFY_ENABLE 1 ++ ++enum drm_via_chrome9_sequence { ++ no_sequence = 0, ++ z_address, ++ dest_address, ++ tex_address, ++ zocclusion_address, ++ coarse_z_address, ++ fvf_address, ++ fence_cmd_address ++}; ++ ++struct drm_via_chrome9_state { ++ uint32_t texture_index; ++ uint32_t render_target_addr[4]; ++ uint32_t render_target_pitch[4]; ++ uint32_t vb_addr; ++ uint32_t fence_cmd_addr; ++ uint32_t fence_need_check; ++ enum drm_via_chrome9_sequence unfinished; ++ int agp_texture; ++ int multitex; ++ struct drm_device *dev; ++ int agp; ++ const uint32_t *buf_start; ++}; ++ ++extern int via_chrome9_verify_command_stream(const uint32_t *buf, ++ unsigned int size, struct drm_device *dev, int agp); ++void via_chrome9_init_command_verifier(void); ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-ad1984-hp-volume-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-ad1984-hp-volume-fix new file mode 100644 index 000000000..24933c4ca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-ad1984-hp-volume-fix @@ -0,0 +1,52 @@ +From 13c989beba166b470b1e6b0fa117148bcbfa3dd1 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 23 Feb 2009 11:33:34 +0100 +Subject: ALSA: hda - Don't give over 0dB volume for AD1984A HP laptops +Patch-mainline: +References: bnc#478158 + +Set the upper limit 0dB to the volume of mixer amp 0x20 for +AD1984A HP laptops. The overloaded volume may damage the internal +speaker. + +Update Wed Apr 1 18:33:51 EDT 2009 jeffm: +- Added the workaround to AD1884A_MOBILE as well. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3959,6 +3959,14 @@ static int patch_ad1884a(struct hda_code + spec->input_mux = &ad1884a_laptop_capture_source; + codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; + codec->patch_ops.init = ad1884a_hp_init; ++ /* set the upper-limit for mixer amp to 0dB for avoiding the ++ * possible damage by overloading ++ */ ++ snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, ++ (0x17 << AC_AMPCAP_OFFSET_SHIFT) | ++ (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | ++ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | ++ (1 << AC_AMPCAP_MUTE_SHIFT)); + break; + case AD1884A_MOBILE: + spec->mixers[0] = ad1884a_mobile_mixers; +@@ -3966,6 +3974,14 @@ static int patch_ad1884a(struct hda_code + spec->multiout.dig_out_nid = 0; + codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; + codec->patch_ops.init = ad1884a_hp_init; ++ /* set the upper-limit for mixer amp to 0dB for avoiding the ++ * possible damage by overloading ++ */ ++ snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, ++ (0x17 << AC_AMPCAP_OFFSET_SHIFT) | ++ (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | ++ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | ++ (1 << AC_AMPCAP_MUTE_SHIFT)); + break; + case AD1884A_THINKPAD: + spec->mixers[0] = ad1984a_thinkpad_mixers; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-ca0106-capture-no-44khz b/src/patches/suse-2.6.27.31/patches.drivers/alsa-ca0106-capture-no-44khz new file mode 100644 index 000000000..346f1f111 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-ca0106-capture-no-44khz @@ -0,0 +1,33 @@ +From: Takashi Iwai +Subject: ALSA: disable 44.1kHz capture on CA0106 +Patch-mainline: +References: bnc#447624 + +The capture with 44.1kHz on CA0106 seems to cause the playback problem +that doesn't suppor 44.1kHz. A simple fix is to disabling 44.1kHz +support. + +Signed-off-by: Takashi Iwai + +--- + +diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c +index 5763174..c2e5c97 100644 +--- a/sound/pci/ca0106/ca0106_main.c ++++ b/sound/pci/ca0106/ca0106_main.c +@@ -305,9 +305,15 @@ static struct snd_pcm_hardware snd_ca0106_capture_hw = { + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, ++#if 0 + .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), + .rate_min = 44100, ++#else ++ .rates = (SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), ++ .rate_min = 48000, ++#endif + .rate_max = 192000, + .channels_min = 2, + .channels_max = 2, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-ca0106-pm-support b/src/patches/suse-2.6.27.31/patches.drivers/alsa-ca0106-pm-support new file mode 100644 index 000000000..a5565f647 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-ca0106-pm-support @@ -0,0 +1,1027 @@ +From 2c5dd6425e72a6e97d9fb9fee9910a58f02d77df Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Subject: ALSA: ca0106 - Add power-amangement support +Patch-mainline: +References: bnc#447624 + +Added the missing PM support for snd-ca0106 driver. + +Signed-off-by: Takashi Iwai + +--- + +--- + sound/pci/ca0106/ca0106.h | 15 + + sound/pci/ca0106/ca0106_main.c | 532 +++++++++++++++++++++++----------------- + sound/pci/ca0106/ca0106_mixer.c | 182 +++++++++---- + 3 files changed, 457 insertions(+), 272 deletions(-) + +--- a/sound/pci/ca0106/ca0106.h ++++ b/sound/pci/ca0106/ca0106.h +@@ -686,7 +686,7 @@ struct snd_ca0106 { + spinlock_t emu_lock; + + struct snd_ac97 *ac97; +- struct snd_pcm *pcm; ++ struct snd_pcm *pcm[4]; + + struct snd_ca0106_channel playback_channels[4]; + struct snd_ca0106_channel capture_channels[4]; +@@ -703,6 +703,11 @@ struct snd_ca0106 { + struct snd_ca_midi midi2; + + u16 spi_dac_reg[16]; ++ ++#ifdef CONFIG_PM ++#define NUM_SAVED_VOLUMES 9 ++ unsigned int saved_vol[NUM_SAVED_VOLUMES]; ++#endif + }; + + int snd_ca0106_mixer(struct snd_ca0106 *emu); +@@ -721,3 +726,11 @@ int snd_ca0106_i2c_write(struct snd_ca01 + + int snd_ca0106_spi_write(struct snd_ca0106 * emu, + unsigned int data); ++ ++#ifdef CONFIG_PM ++void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); ++void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); ++#else ++#define snd_ca0106_mixer_suspend(chip) do { } while (0) ++#define snd_ca0106_mixer_resume(chip) do { } while (0) ++#endif +--- a/sound/pci/ca0106/ca0106_main.c ++++ b/sound/pci/ca0106/ca0106_main.c +@@ -848,15 +848,18 @@ static int snd_ca0106_pcm_trigger_playba + struct snd_pcm_substream *s; + u32 basic = 0; + u32 extended = 0; +- int running=0; ++ u32 bits; ++ int running = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: +- running=1; ++ case SNDRV_PCM_TRIGGER_RESUME: ++ running = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: + default: +- running=0; ++ running = 0; + break; + } + snd_pcm_group_for_each_entry(s, substream) { +@@ -866,22 +869,32 @@ static int snd_ca0106_pcm_trigger_playba + runtime = s->runtime; + epcm = runtime->private_data; + channel = epcm->channel_id; +- //snd_printk("channel=%d\n",channel); ++ /* snd_printk("channel=%d\n",channel); */ + epcm->running = running; +- basic |= (0x1<ac97); + } + ++static void ca0106_stop_chip(struct snd_ca0106 *chip); ++ + static int snd_ca0106_free(struct snd_ca0106 *chip) + { +- if (chip->res_port != NULL) { /* avoid access to already used hardware */ +- // disable interrupts +- snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); +- outl(0, chip->port + INTE); +- snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); +- udelay(1000); +- // disable audio +- //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); +- outl(0, chip->port + HCFG); +- /* FIXME: We need to stop and DMA transfers here. +- * But as I am not sure how yet, we cannot from the dma pages. +- * So we can fix: snd-malloc: Memory leak? pages not freed = 8 +- */ ++ if (chip->res_port != NULL) { ++ /* avoid access to already used hardware */ ++ ca0106_stop_chip(chip); + } + if (chip->irq >= 0) + free_irq(chip->irq, chip); +@@ -1204,15 +1209,14 @@ static irqreturn_t snd_ca0106_interrupt( + return IRQ_HANDLED; + } + +-static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) ++static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) + { + struct snd_pcm *pcm; + struct snd_pcm_substream *substream; + int err; + +- if (rpcm) +- *rpcm = NULL; +- if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) ++ err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); ++ if (err < 0) + return err; + + pcm->private_data = emu; +@@ -1239,7 +1243,6 @@ static int __devinit snd_ca0106_pcm(stru + pcm->info_flags = 0; + pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; + strcpy(pcm->name, "CA0106"); +- emu->pcm = pcm; + + for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + substream; +@@ -1261,8 +1264,7 @@ static int __devinit snd_ca0106_pcm(stru + return err; + } + +- if (rpcm) +- *rpcm = pcm; ++ emu->pcm[device] = pcm; + + return 0; + } +@@ -1302,89 +1304,10 @@ static unsigned int i2c_adc_init[][2] = + { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ + }; + +-static int __devinit snd_ca0106_create(int dev, struct snd_card *card, +- struct pci_dev *pci, +- struct snd_ca0106 **rchip) ++static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) + { +- struct snd_ca0106 *chip; +- struct snd_ca0106_details *c; +- int err; + int ch; +- static struct snd_device_ops ops = { +- .dev_free = snd_ca0106_dev_free, +- }; +- +- *rchip = NULL; +- +- if ((err = pci_enable_device(pci)) < 0) +- return err; +- if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || +- pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { +- printk(KERN_ERR "error to set 32bit mask DMA\n"); +- pci_disable_device(pci); +- return -ENXIO; +- } +- +- chip = kzalloc(sizeof(*chip), GFP_KERNEL); +- if (chip == NULL) { +- pci_disable_device(pci); +- return -ENOMEM; +- } +- +- chip->card = card; +- chip->pci = pci; +- chip->irq = -1; +- +- spin_lock_init(&chip->emu_lock); +- +- chip->port = pci_resource_start(pci, 0); +- if ((chip->res_port = request_region(chip->port, 0x20, +- "snd_ca0106")) == NULL) { +- snd_ca0106_free(chip); +- printk(KERN_ERR "cannot allocate the port\n"); +- return -EBUSY; +- } +- +- if (request_irq(pci->irq, snd_ca0106_interrupt, +- IRQF_SHARED, "snd_ca0106", chip)) { +- snd_ca0106_free(chip); +- printk(KERN_ERR "cannot grab irq\n"); +- return -EBUSY; +- } +- chip->irq = pci->irq; +- +- /* This stores the periods table. */ +- if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { +- snd_ca0106_free(chip); +- return -ENOMEM; +- } +- +- pci_set_master(pci); +- /* read serial */ +- pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); +- pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); +-#if 1 +- printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, +- pci->revision, chip->serial); +-#endif +- strcpy(card->driver, "CA0106"); +- strcpy(card->shortname, "CA0106"); +- +- for (c = ca0106_chip_details; c->serial; c++) { +- if (subsystem[dev]) { +- if (c->serial == subsystem[dev]) +- break; +- } else if (c->serial == chip->serial) +- break; +- } +- chip->details = c; +- if (subsystem[dev]) { +- printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", +- c->name, chip->serial, subsystem[dev]); +- } +- +- sprintf(card->longname, "%s at 0x%lx irq %i", +- c->name, chip->port, chip->irq); ++ unsigned int def_bits; + + outl(0, chip->port + INTE); + +@@ -1402,31 +1325,22 @@ static int __devinit snd_ca0106_create(i + * AN = 0 (Audio data) + * P = 0 (Consumer) + */ +- snd_ca0106_ptr_write(chip, SPCS0, 0, +- chip->spdif_bits[0] = +- SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | +- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | +- SPCS_GENERATIONSTATUS | 0x00001200 | +- 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); ++ def_bits = ++ SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | ++ SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | ++ SPCS_GENERATIONSTATUS | 0x00001200 | ++ 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; ++ if (!resume) { ++ chip->spdif_bits[0] = def_bits; ++ chip->spdif_bits[1] = def_bits; ++ chip->spdif_bits[2] = def_bits; ++ chip->spdif_bits[3] = def_bits; ++ } + /* Only SPCS1 has been tested */ +- snd_ca0106_ptr_write(chip, SPCS1, 0, +- chip->spdif_bits[1] = +- SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | +- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | +- SPCS_GENERATIONSTATUS | 0x00001200 | +- 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); +- snd_ca0106_ptr_write(chip, SPCS2, 0, +- chip->spdif_bits[2] = +- SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | +- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | +- SPCS_GENERATIONSTATUS | 0x00001200 | +- 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); +- snd_ca0106_ptr_write(chip, SPCS3, 0, +- chip->spdif_bits[3] = +- SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | +- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | +- SPCS_GENERATIONSTATUS | 0x00001200 | +- 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); ++ snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); ++ snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); ++ snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); ++ snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); + + snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); + snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); +@@ -1434,92 +1348,124 @@ static int __devinit snd_ca0106_create(i + /* Write 0x8000 to AC97_REC_GAIN to mute it. */ + outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); + outw(0x8000, chip->port + AC97DATA); +-#if 0 ++#if 0 /* FIXME: what are these? */ + snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); + snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); + snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); + snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); + #endif + +- //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ ++ /* OSS drivers set this. */ ++ /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ ++ + /* Analog or Digital output */ + snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); +- snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ ++ /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. ++ * Use 0x000f0000 for surround71 ++ */ ++ snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); ++ + chip->spdif_enable = 0; /* Set digital SPDIF output off */ +- //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ +- //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ ++ /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ ++ /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ ++ ++ /* goes to 0x40c80000 when doing SPDIF IN/OUT */ ++ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); ++ /* (Mute) CAPTURE feedback into PLAYBACK volume. ++ * Only lower 16 bits matter. ++ */ ++ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); ++ /* SPDIF IN Volume */ ++ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); ++ /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ ++ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); + +- snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ +- snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ +- snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ +- snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ + snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); + snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); + snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); + snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); +- for(ch = 0; ch < 4; ch++) { +- snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ ++ ++ for (ch = 0; ch < 4; ch++) { ++ /* Only high 16 bits matter */ ++ snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); + snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); +- //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ +- //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ +- snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ +- snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ ++#if 0 /* Mute */ ++ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); ++ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); ++ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); ++ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); ++#endif + } + if (chip->details->i2c_adc == 1) { + /* Select MIC, Line in, TAD in, AUX in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); + /* Default to CAPTURE_SOURCE to i2s in */ +- chip->capture_source = 3; ++ if (!resume) ++ chip->capture_source = 3; + } else if (chip->details->ac97 == 1) { + /* Default to AC97 in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); + /* Default to CAPTURE_SOURCE to AC97 in */ +- chip->capture_source = 4; ++ if (!resume) ++ chip->capture_source = 4; + } else { + /* Select MIC, Line in, TAD in, AUX in */ + snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); + /* Default to Set CAPTURE_SOURCE to i2s in */ +- chip->capture_source = 3; ++ if (!resume) ++ chip->capture_source = 3; + } + +- if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ +- /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ ++ if (chip->details->gpio_type == 2) { ++ /* The SB0438 use GPIO differently. */ ++ /* FIXME: Still need to find out what the other GPIO bits do. ++ * E.g. For digital spdif out. ++ */ + outl(0x0, chip->port+GPIO); +- //outl(0x00f0e000, chip->port+GPIO); /* Analog */ ++ /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ + outl(0x005f5301, chip->port+GPIO); /* Analog */ +- } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ +- /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ ++ } else if (chip->details->gpio_type == 1) { ++ /* The SB0410 and SB0413 use GPIO differently. */ ++ /* FIXME: Still need to find out what the other GPIO bits do. ++ * E.g. For digital spdif out. ++ */ + outl(0x0, chip->port+GPIO); +- //outl(0x00f0e000, chip->port+GPIO); /* Analog */ ++ /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ + outl(0x005f5301, chip->port+GPIO); /* Analog */ + } else { + outl(0x0, chip->port+GPIO); + outl(0x005f03a3, chip->port+GPIO); /* Analog */ +- //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ ++ /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ + } + snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ + +- //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); +- //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ +- //outl(0x00000009, chip->port+HCFG); +- outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ ++ /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ ++ /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ ++ /* outl(0x00001409, chip->port+HCFG); */ ++ /* outl(0x00000009, chip->port+HCFG); */ ++ /* AC97 2.0, Enable outputs. */ ++ outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); + +- if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ ++ if (chip->details->i2c_adc == 1) { ++ /* The SB0410 and SB0413 use I2C to control ADC. */ + int size, n; + + size = ARRAY_SIZE(i2c_adc_init); +- //snd_printk("I2C:array size=0x%x\n", size); +- for (n=0; n < size; n++) { +- snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); +- } +- for (n=0; n < 4; n++) { +- chip->i2c_capture_volume[n][0]= 0xcf; +- chip->i2c_capture_volume[n][1]= 0xcf; ++ /* snd_printk("I2C:array size=0x%x\n", size); */ ++ for (n = 0; n < size; n++) ++ snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], ++ i2c_adc_init[n][1]); ++ for (n = 0; n < 4; n++) { ++ chip->i2c_capture_volume[n][0] = 0xcf; ++ chip->i2c_capture_volume[n][1] = 0xcf; + } +- chip->i2c_capture_source=2; /* Line in */ +- //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ ++ chip->i2c_capture_source = 2; /* Line in */ ++ /* Enable Line-in capture. MIC in currently untested. */ ++ /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ + } +- if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ ++ ++ if (chip->details->spi_dac == 1) { ++ /* The SB0570 use SPI to control DAC. */ + int size, n; + + size = ARRAY_SIZE(spi_dac_init); +@@ -1531,9 +1477,112 @@ static int __devinit snd_ca0106_create(i + chip->spi_dac_reg[reg] = spi_dac_init[n]; + } + } ++} ++ ++static void ca0106_stop_chip(struct snd_ca0106 *chip) ++{ ++ /* disable interrupts */ ++ snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); ++ outl(0, chip->port + INTE); ++ snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); ++ udelay(1000); ++ /* disable audio */ ++ /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ ++ outl(0, chip->port + HCFG); ++ /* FIXME: We need to stop and DMA transfers here. ++ * But as I am not sure how yet, we cannot from the dma pages. ++ * So we can fix: snd-malloc: Memory leak? pages not freed = 8 ++ */ ++} + +- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, +- chip, &ops)) < 0) { ++static int __devinit snd_ca0106_create(int dev, struct snd_card *card, ++ struct pci_dev *pci, ++ struct snd_ca0106 **rchip) ++{ ++ struct snd_ca0106 *chip; ++ struct snd_ca0106_details *c; ++ int err; ++ static struct snd_device_ops ops = { ++ .dev_free = snd_ca0106_dev_free, ++ }; ++ ++ *rchip = NULL; ++ ++ err = pci_enable_device(pci); ++ if (err < 0) ++ return err; ++ if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || ++ pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { ++ printk(KERN_ERR "error to set 32bit mask DMA\n"); ++ pci_disable_device(pci); ++ return -ENXIO; ++ } ++ ++ chip = kzalloc(sizeof(*chip), GFP_KERNEL); ++ if (chip == NULL) { ++ pci_disable_device(pci); ++ return -ENOMEM; ++ } ++ ++ chip->card = card; ++ chip->pci = pci; ++ chip->irq = -1; ++ ++ spin_lock_init(&chip->emu_lock); ++ ++ chip->port = pci_resource_start(pci, 0); ++ chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); ++ if (!chip->res_port) { ++ snd_ca0106_free(chip); ++ printk(KERN_ERR "cannot allocate the port\n"); ++ return -EBUSY; ++ } ++ ++ if (request_irq(pci->irq, snd_ca0106_interrupt, ++ IRQF_SHARED, "snd_ca0106", chip)) { ++ snd_ca0106_free(chip); ++ printk(KERN_ERR "cannot grab irq\n"); ++ return -EBUSY; ++ } ++ chip->irq = pci->irq; ++ ++ /* This stores the periods table. */ ++ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), ++ 1024, &chip->buffer) < 0) { ++ snd_ca0106_free(chip); ++ return -ENOMEM; ++ } ++ ++ pci_set_master(pci); ++ /* read serial */ ++ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); ++ pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); ++ printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", ++ chip->model, pci->revision, chip->serial); ++ strcpy(card->driver, "CA0106"); ++ strcpy(card->shortname, "CA0106"); ++ ++ for (c = ca0106_chip_details; c->serial; c++) { ++ if (subsystem[dev]) { ++ if (c->serial == subsystem[dev]) ++ break; ++ } else if (c->serial == chip->serial) ++ break; ++ } ++ chip->details = c; ++ if (subsystem[dev]) { ++ printk(KERN_INFO "snd-ca0106: Sound card name=%s, " ++ "subsystem=0x%x. Forced to subsystem=0x%x\n", ++ c->name, chip->serial, subsystem[dev]); ++ } ++ ++ sprintf(card->longname, "%s at 0x%lx irq %i", ++ c->name, chip->port, chip->irq); ++ ++ ca0106_init_chip(chip, 0); ++ ++ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); ++ if (err < 0) { + snd_ca0106_free(chip); + return err; + } +@@ -1630,7 +1679,7 @@ static int __devinit snd_ca0106_probe(st + static int dev; + struct snd_card *card; + struct snd_ca0106 *chip; +- int err; ++ int i, err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; +@@ -1643,44 +1692,31 @@ static int __devinit snd_ca0106_probe(st + if (card == NULL) + return -ENOMEM; + +- if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { +- snd_card_free(card); +- return err; +- } +- +- if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { +- snd_card_free(card); +- return err; +- } +- if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { +- snd_card_free(card); +- return err; +- } +- if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { +- snd_card_free(card); +- return err; +- } +- if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { +- snd_card_free(card); +- return err; +- } +- if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ +- if ((err = snd_ca0106_ac97(chip)) < 0) { +- snd_card_free(card); +- return err; +- } +- } +- if ((err = snd_ca0106_mixer(chip)) < 0) { +- snd_card_free(card); +- return err; +- } ++ err = snd_ca0106_create(dev, card, pci, &chip); ++ if (err < 0) ++ goto error; ++ card->private_data = chip; ++ ++ for (i = 0; i < 4; i++) { ++ err = snd_ca0106_pcm(chip, i); ++ if (err < 0) ++ goto error; ++ } ++ ++ if (chip->details->ac97 == 1) { ++ /* The SB0410 and SB0413 do not have an AC97 chip. */ ++ err = snd_ca0106_ac97(chip); ++ if (err < 0) ++ goto error; ++ } ++ err = snd_ca0106_mixer(chip); ++ if (err < 0) ++ goto error; + + snd_printdd("ca0106: probe for MIDI channel A ..."); +- if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { +- snd_card_free(card); +- snd_printdd(" failed, err=0x%x\n",err); +- return err; +- } ++ err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); ++ if (err < 0) ++ goto error; + snd_printdd(" done.\n"); + + #ifdef CONFIG_PROC_FS +@@ -1689,14 +1725,17 @@ static int __devinit snd_ca0106_probe(st + + snd_card_set_dev(card, &pci->dev); + +- if ((err = snd_card_register(card)) < 0) { +- snd_card_free(card); +- return err; +- } ++ err = snd_card_register(card); ++ if (err < 0) ++ goto error; + + pci_set_drvdata(pci, card); + dev++; + return 0; ++ ++ error: ++ snd_card_free(card); ++ return err; + } + + static void __devexit snd_ca0106_remove(struct pci_dev *pci) +@@ -1705,6 +1744,59 @@ static void __devexit snd_ca0106_remove( + pci_set_drvdata(pci, NULL); + } + ++#ifdef CONFIG_PM ++static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) ++{ ++ struct snd_card *card = pci_get_drvdata(pci); ++ struct snd_ca0106 *chip = card->private_data; ++ int i; ++ ++ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); ++ for (i = 0; i < 4; i++) ++ snd_pcm_suspend_all(chip->pcm[i]); ++ if (chip->details->ac97) ++ snd_ac97_suspend(chip->ac97); ++ snd_ca0106_mixer_suspend(chip); ++ ++ ca0106_stop_chip(chip); ++ ++ pci_disable_device(pci); ++ pci_save_state(pci); ++ pci_set_power_state(pci, pci_choose_state(pci, state)); ++ return 0; ++} ++ ++static int snd_ca0106_resume(struct pci_dev *pci) ++{ ++ struct snd_card *card = pci_get_drvdata(pci); ++ struct snd_ca0106 *chip = card->private_data; ++ int i; ++ ++ pci_set_power_state(pci, PCI_D0); ++ pci_restore_state(pci); ++ ++ if (pci_enable_device(pci) < 0) { ++ snd_card_disconnect(card); ++ return -EIO; ++ } ++ ++ pci_set_master(pci); ++ ++ ca0106_init_chip(chip, 1); ++ ++ if (chip->details->ac97) ++ snd_ac97_resume(chip->ac97); ++ snd_ca0106_mixer_resume(chip); ++ if (chip->details->spi_dac) { ++ for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) ++ snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); ++ } ++ ++ snd_power_change_state(card, SNDRV_CTL_POWER_D0); ++ return 0; ++} ++#endif ++ + // PCI IDs + static struct pci_device_id snd_ca0106_ids[] = { + { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ +@@ -1718,6 +1810,8 @@ static struct pci_driver driver = { + .id_table = snd_ca0106_ids, + .probe = snd_ca0106_probe, + .remove = __devexit_p(snd_ca0106_remove), ++ .suspend = snd_ca0106_suspend, ++ .resume = snd_ca0106_resume, + }; + + // initialization of the module +--- a/sound/pci/ca0106/ca0106_mixer.c ++++ b/sound/pci/ca0106/ca0106_mixer.c +@@ -75,6 +75,84 @@ + + #include "ca0106.h" + ++static void ca0106_spdif_enable(struct snd_ca0106 *emu) ++{ ++ unsigned int val; ++ ++ if (emu->spdif_enable) { ++ /* Digital */ ++ snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); ++ snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); ++ val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; ++ snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); ++ val = inl(emu->port + GPIO) & ~0x101; ++ outl(val, emu->port + GPIO); ++ ++ } else { ++ /* Analog */ ++ snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); ++ snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); ++ val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; ++ snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); ++ val = inl(emu->port + GPIO) | 0x101; ++ outl(val, emu->port + GPIO); ++ } ++} ++ ++static void ca0106_set_capture_source(struct snd_ca0106 *emu) ++{ ++ unsigned int val = emu->capture_source; ++ unsigned int source, mask; ++ source = (val << 28) | (val << 24) | (val << 20) | (val << 16); ++ mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; ++ snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); ++} ++ ++static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, ++ unsigned int val, int force) ++{ ++ unsigned int ngain, ogain; ++ u32 source; ++ ++ snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ ++ ngain = emu->i2c_capture_volume[val][0]; /* Left */ ++ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ ++ if (force || ngain != ogain) ++ snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); ++ ngain = emu->i2c_capture_volume[val][1]; /* Right */ ++ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ ++ if (force || ngain != ogain) ++ snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); ++ source = 1 << val; ++ snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ ++ emu->i2c_capture_source = val; ++} ++ ++static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) ++{ ++ u32 tmp; ++ ++ if (emu->capture_mic_line_in) { ++ /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ ++ tmp = inl(emu->port+GPIO) & ~0x400; ++ tmp = tmp | 0x400; ++ outl(tmp, emu->port+GPIO); ++ /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ ++ } else { ++ /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ ++ tmp = inl(emu->port+GPIO) & ~0x400; ++ outl(tmp, emu->port+GPIO); ++ /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ ++ } ++} ++ ++static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) ++{ ++ snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); ++} ++ ++/* ++ */ + static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); + static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); + +@@ -95,30 +173,12 @@ static int snd_ca0106_shared_spdif_put(s + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; +- u32 mask; + + val = !!ucontrol->value.integer.value[0]; + change = (emu->spdif_enable != val); + if (change) { + emu->spdif_enable = val; +- if (val) { +- /* Digital */ +- snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); +- snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); +- snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, +- snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); +- mask = inl(emu->port + GPIO) & ~0x101; +- outl(mask, emu->port + GPIO); +- +- } else { +- /* Analog */ +- snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); +- snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); +- snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, +- snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); +- mask = inl(emu->port + GPIO) | 0x101; +- outl(mask, emu->port + GPIO); +- } ++ ca0106_spdif_enable(emu); + } + return change; + } +@@ -154,8 +214,6 @@ static int snd_ca0106_capture_source_put + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; +- u32 mask; +- u32 source; + + val = ucontrol->value.enumerated.item[0] ; + if (val >= 6) +@@ -163,9 +221,7 @@ static int snd_ca0106_capture_source_put + change = (emu->capture_source != val); + if (change) { + emu->capture_source = val; +- source = (val << 28) | (val << 24) | (val << 20) | (val << 16); +- mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; +- snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); ++ ca0106_set_capture_source(emu); + } + return change; + } +@@ -200,9 +256,7 @@ static int snd_ca0106_i2c_capture_source + { + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int source_id; +- unsigned int ngain, ogain; + int change = 0; +- u32 source; + /* If the capture source has changed, + * update the capture volume from the cached value + * for the particular source. +@@ -212,18 +266,7 @@ static int snd_ca0106_i2c_capture_source + return -EINVAL; + change = (emu->i2c_capture_source != source_id); + if (change) { +- snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ +- ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ +- ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ +- if (ngain != ogain) +- snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); +- ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ +- ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ +- if (ngain != ogain) +- snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); +- source = 1 << source_id; +- snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ +- emu->i2c_capture_source = source_id; ++ ca0106_set_i2c_capture_source(emu, source_id, 0); + } + return change; + } +@@ -271,7 +314,6 @@ static int snd_ca0106_capture_mic_line_i + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; +- u32 tmp; + + val = ucontrol->value.enumerated.item[0] ; + if (val > 1) +@@ -279,18 +321,7 @@ static int snd_ca0106_capture_mic_line_i + change = (emu->capture_mic_line_in != val); + if (change) { + emu->capture_mic_line_in = val; +- if (val) { +- //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ +- tmp = inl(emu->port+GPIO) & ~0x400; +- tmp = tmp | 0x400; +- outl(tmp, emu->port+GPIO); +- //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); +- } else { +- //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ +- tmp = inl(emu->port+GPIO) & ~0x400; +- outl(tmp, emu->port+GPIO); +- //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); +- } ++ ca0106_set_capture_mic_line_in(emu); + } + return change; + } +@@ -359,8 +390,8 @@ static int snd_ca0106_spdif_put(struct s + (ucontrol->value.iec958.status[3] << 24); + change = val != emu->spdif_bits[idx]; + if (change) { +- snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); + emu->spdif_bits[idx] = val; ++ ca0106_set_spdif_bits(emu, idx); + } + return change; + } +@@ -779,3 +810,50 @@ int __devinit snd_ca0106_mixer(struct sn + return 0; + } + ++#ifdef CONFIG_PM ++struct ca0106_vol_tbl { ++ unsigned int channel_id; ++ unsigned int reg; ++}; ++ ++static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { ++ { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, ++ { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, ++ { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, ++ { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, ++ { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, ++ { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, ++ { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, ++ { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, ++ { 1, CAPTURE_CONTROL }, ++}; ++ ++void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) ++{ ++ int i; ++ ++ /* save volumes */ ++ for (i = 0; i < NUM_SAVED_VOLUMES; i++) ++ chip->saved_vol[i] = ++ snd_ca0106_ptr_read(chip, saved_volumes[i].reg, ++ saved_volumes[i].channel_id); ++} ++ ++void snd_ca0106_mixer_resume(struct snd_ca0106 *chip) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_SAVED_VOLUMES; i++) ++ snd_ca0106_ptr_write(chip, saved_volumes[i].reg, ++ saved_volumes[i].channel_id, ++ chip->saved_vol[i]); ++ ++ ca0106_spdif_enable(chip); ++ ca0106_set_capture_source(chip); ++ ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); ++ for (i = 0; i < 4; i++) ++ ca0106_set_spdif_bits(chip, i); ++ if (chip->details->i2c_adc) ++ ca0106_set_capture_mic_line_in(chip); ++} ++#endif /* CONFIG_PM */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-emu10k1-audigy-fixes b/src/patches/suse-2.6.27.31/patches.drivers/alsa-emu10k1-audigy-fixes new file mode 100644 index 000000000..a20539d10 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-emu10k1-audigy-fixes @@ -0,0 +1,40 @@ +From: Takashi Iwai +Subject: ALSA: emu10k1 - Add more invert_shared_spdif flag to Audigy models +Patch-mainline: 2.6.28-rc4 +References: bnc#440862 + +Reported in Novell bnc#440862: + https://bugzilla.novell.com/show_bug.cgi?id=440862 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/emu10k1/emu10k1_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sound/pci/emu10k1/emu10k1_main.c ++++ b/sound/pci/emu10k1/emu10k1_main.c +@@ -1451,6 +1451,7 @@ static struct snd_emu_chip_details emu_c + .ca0151_chip = 1, + .spk71 = 1, + .spdif_bug = 1, ++ .invert_shared_spdif = 1, /* digital/analog switch swapped */ + .ac97_chip = 1} , + /* Tested by shane-alsa@cm.nu 5th Nov 2005 */ + /* The 0x20061102 does have SB0350 written on it +@@ -1522,6 +1523,7 @@ static struct snd_emu_chip_details emu_c + .ca0151_chip = 1, + .spk71 = 1, + .spdif_bug = 1, ++ .invert_shared_spdif = 1, /* digital/analog switch swapped */ + .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, + .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", +@@ -1541,6 +1543,7 @@ static struct snd_emu_chip_details emu_c + .ca0102_chip = 1, + .ca0151_chip = 1, + .spdif_bug = 1, ++ .invert_shared_spdif = 1, /* digital/analog switch swapped */ + .ac97_chip = 1} , + {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, + .driver = "Audigy", .name = "Audigy 1 [SB0090]", diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-92hd73x-desktop-fixes b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-92hd73x-desktop-fixes new file mode 100644 index 000000000..6070c1fce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-92hd73x-desktop-fixes @@ -0,0 +1,169 @@ +From: Takashi Iwai +Subject: ALSA: Fix plaback problems on Intel desktops with IDT codecs +Patch-mainline: +References: + +The Intel desktops with IDT 92HD* may have no output due to the wrong +routing. Also, when the jack-sensing doesn't work for the front panel, +no I/O is possible there. + +This patch fixes several issues: +- 92HD73* Intel desktop fix +- Add quirk for Dell Studo 17 +- no-jd model addition + +Signed-off-by: Takashi Iwai + +--- + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 2 + + sound/pci/hda/patch_sigmatel.c | 29 +++++++++++++++++++----- + 2 files changed, 26 insertions(+), 5 deletions(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -1067,6 +1067,7 @@ Prior to version 0.9.0rc4 options had a + + STAC9227/9228/9229/927x + ref Reference board ++ ref-no-jd Reference board without HP/Mic jack detection + 3stack D965 3stack + 5stack D965 5stack + SPDIF + dell-3stack Dell Dimension E520 +@@ -1080,6 +1081,7 @@ Prior to version 0.9.0rc4 options had a + + STAC92HD73* + ref Reference board ++ no-jd BIOS setup but without jack-detection + dell-m6-amic Dell desktops/laptops with analog mics + dell-m6-dmic Dell desktops/laptops with digital mics + dell-m6 Dell desktops/laptops with both type of mics +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -69,6 +69,7 @@ enum { + }; + + enum { ++ STAC_92HD73XX_NO_JD, /* no jack-detection */ + STAC_92HD73XX_REF, + STAC_DELL_M6_AMIC, + STAC_DELL_M6_DMIC, +@@ -127,6 +128,7 @@ enum { + }; + + enum { ++ STAC_D965_REF_NO_JD, /* no jack-detection */ + STAC_D965_REF, + STAC_D965_3ST, + STAC_D965_5ST, +@@ -783,8 +785,8 @@ static struct hda_verb dell_m6_core_init + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, + /* setup audio connections */ + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02}, +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -1613,6 +1615,7 @@ static unsigned int *stac92hd73xx_brd_tb + }; + + static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { ++ [STAC_92HD73XX_NO_JD] = "no-jd", + [STAC_92HD73XX_REF] = "ref", + [STAC_DELL_M6_AMIC] = "dell-m6-amic", + [STAC_DELL_M6_DMIC] = "dell-m6-dmic", +@@ -1642,6 +1645,8 @@ static struct snd_pci_quirk stac92hd73xx + "unknown Dell", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f, + "Dell Studio 1537", STAC_DELL_M6_DMIC), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0, ++ "Dell Studio 17", STAC_DELL_M6_DMIC), + {} /* terminator */ + }; + +@@ -2029,6 +2034,7 @@ static unsigned int dell_3st_pin_configs + }; + + static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { ++ [STAC_D965_REF_NO_JD] = ref927x_pin_configs, + [STAC_D965_REF] = ref927x_pin_configs, + [STAC_D965_3ST] = d965_3st_pin_configs, + [STAC_D965_5ST] = d965_5st_pin_configs, +@@ -2037,6 +2043,7 @@ static unsigned int *stac927x_brd_tbl[ST + }; + + static const char *stac927x_models[STAC_927X_MODELS] = { ++ [STAC_D965_REF_NO_JD] = "ref-no-jd", + [STAC_D965_REF] = "ref", + [STAC_D965_3ST] = "3stack", + [STAC_D965_5ST] = "5stack", +@@ -2899,7 +2906,7 @@ static int stac92xx_auto_create_multi_ou + } + + if ((spec->multiout.num_dacs - cfg->line_outs) > 0 && +- cfg->hp_outs && !spec->multiout.hp_nid) ++ cfg->hp_outs == 1 && !spec->multiout.hp_nid) + spec->multiout.hp_nid = nid; + + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { +@@ -4257,14 +4264,17 @@ again: + + switch (spec->multiout.num_dacs) { + case 0x3: /* 6 Channel */ ++ spec->multiout.hp_nid = 0x17; + spec->mixer = stac92hd73xx_6ch_mixer; + spec->init = stac92hd73xx_6ch_core_init; + break; + case 0x4: /* 8 Channel */ ++ spec->multiout.hp_nid = 0x18; + spec->mixer = stac92hd73xx_8ch_mixer; + spec->init = stac92hd73xx_8ch_core_init; + break; + case 0x5: /* 10 Channel */ ++ spec->multiout.hp_nid = 0x19; + spec->mixer = stac92hd73xx_10ch_mixer; + spec->init = stac92hd73xx_10ch_core_init; + }; +@@ -4295,13 +4305,15 @@ again: + case STAC_DELL_M6_AMIC: + case STAC_DELL_M6_DMIC: + case STAC_DELL_M6_BOTH: +- if (!spec->init) +- spec->init = dell_m6_core_init; + spec->num_smuxes = 0; + spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER]; + spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; + spec->eapd_switch = 0; + spec->num_amps = 1; ++ spec->multiout.hp_nid = 0; /* dual HPs */ ++ ++ if (!spec->init) ++ spec->init = dell_m6_core_init; + switch (spec->board_config) { + case STAC_DELL_M6_AMIC: /* Analog Mics */ + stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); +@@ -4353,6 +4365,9 @@ again: + return err; + } + ++ if (spec->board_config == STAC_92HD73XX_NO_JD) ++ spec->hp_detect = 0; ++ + codec->patch_ops = stac92xx_patch_ops; + + return 0; +@@ -4901,6 +4916,10 @@ static int patch_stac927x(struct hda_cod + */ + codec->bus->needs_damn_long_delay = 1; + ++ /* no jack detecion for ref-no-jd model */ ++ if (spec->board_config == STAC_D965_REF_NO_JD) ++ spec->hp_detect = 0; ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-ad1882-id-typo-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-ad1882-id-typo-fix new file mode 100644 index 000000000..6ab370ff9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-ad1882-id-typo-fix @@ -0,0 +1,34 @@ +From c247ed6f5205f9feebd276c4cbe45018b10f19fa Mon Sep 17 00:00:00 2001 +From: Clemens Fruhwirth +Date: Wed, 7 Jan 2009 11:43:48 +0100 +Subject: ALSA: hda - Fix typos for AD1882 codecs +Patch-mainline: 2.6.28 +References: + +Fixed typos of codec-id checks for AD1882/AD1882A. + +Cc: stable@kernel.org +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -4266,13 +4266,13 @@ static int patch_ad1882(struct hda_codec + spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); + spec->adc_nids = ad1882_adc_nids; + spec->capsrc_nids = ad1882_capsrc_nids; +- if (codec->vendor_id == 0x11d1882) ++ if (codec->vendor_id == 0x11d41882) + spec->input_mux = &ad1882_capture_source; + else + spec->input_mux = &ad1882a_capture_source; + spec->num_mixers = 2; + spec->mixers[0] = ad1882_base_mixers; +- if (codec->vendor_id == 0x11d1882) ++ if (codec->vendor_id == 0x11d41882) + spec->mixers[1] = ad1882_loopback_mixers; + else + spec->mixers[1] = ad1882a_loopback_mixers; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-add-volume-offset b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-add-volume-offset new file mode 100644 index 000000000..760819cee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-add-volume-offset @@ -0,0 +1,155 @@ +From 29fdbec2dcb1ce364812778271056aa9516ff3ed Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 20 Jan 2009 13:07:55 +0100 +Subject: ALSA: hda - Add extra volume offset to standard volume amp macros +Patch-mainline: +References: bnc#466428 + + +Added the volume offset to base for the standard volume controls +to handle elements with too big volume scales like -96dB..0dB. +For such elements, you can set the base volume to reduce the range. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 45 +++++++++++++++++++++++++++++++++++++-------- + sound/pci/hda/hda_local.h | 5 ++++- + 2 files changed, 41 insertions(+), 9 deletions(-) + +diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c +index b7bba7d..0cf2424 100644 +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -967,6 +967,7 @@ int snd_hda_mixer_amp_volume_info(struct + u16 nid = get_amp_nid(kcontrol); + u8 chs = get_amp_channels(kcontrol); + int dir = get_amp_direction(kcontrol); ++ unsigned int ofs = get_amp_offset(kcontrol); + u32 caps; + + caps = query_amp_caps(codec, nid, dir); +@@ -978,6 +979,8 @@ int snd_hda_mixer_amp_volume_info(struct + kcontrol->id.name); + return -EINVAL; + } ++ if (ofs < caps) ++ caps -= ofs; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = 0; +@@ -985,6 +988,32 @@ int snd_hda_mixer_amp_volume_info(struct + return 0; + } + ++ ++static inline unsigned int ++read_amp_value(struct hda_codec *codec, hda_nid_t nid, ++ int ch, int dir, int idx, unsigned int ofs) ++{ ++ unsigned int val; ++ val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); ++ val &= HDA_AMP_VOLMASK; ++ if (val >= ofs) ++ val -= ofs; ++ else ++ val = 0; ++ return val; ++} ++ ++static inline int ++update_amp_value(struct hda_codec *codec, hda_nid_t nid, ++ int ch, int dir, int idx, unsigned int ofs, ++ unsigned int val) ++{ ++ if (val > 0) ++ val += ofs; ++ return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, ++ HDA_AMP_VOLMASK, val); ++} ++ + int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +@@ -993,14 +1022,13 @@ int snd_hda_mixer_amp_volume_get(struct + int chs = get_amp_channels(kcontrol); + int dir = get_amp_direction(kcontrol); + int idx = get_amp_index(kcontrol); ++ unsigned int ofs = get_amp_offset(kcontrol); + long *valp = ucontrol->value.integer.value; + + if (chs & 1) +- *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) +- & HDA_AMP_VOLMASK; ++ *valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); + if (chs & 2) +- *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) +- & HDA_AMP_VOLMASK; ++ *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); + return 0; + } + +@@ -1012,18 +1040,17 @@ int snd_hda_mixer_amp_volume_put(struct + int chs = get_amp_channels(kcontrol); + int dir = get_amp_direction(kcontrol); + int idx = get_amp_index(kcontrol); ++ unsigned int ofs = get_amp_offset(kcontrol); + long *valp = ucontrol->value.integer.value; + int change = 0; + + snd_hda_power_up(codec); + if (chs & 1) { +- change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, +- 0x7f, *valp); ++ change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); + valp++; + } + if (chs & 2) +- change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, +- 0x7f, *valp); ++ change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); + snd_hda_power_down(codec); + return change; + } +@@ -1034,6 +1061,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kco + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = get_amp_nid(kcontrol); + int dir = get_amp_direction(kcontrol); ++ unsigned int ofs = get_amp_offset(kcontrol); + u32 caps, val1, val2; + + if (size < 4 * sizeof(unsigned int)) +@@ -1042,6 +1070,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kco + val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; + val2 = (val2 + 1) * 25; + val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); ++ val1 += ofs; + val1 = ((int)val1) * ((int)val2); + if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) + return -EFAULT; +diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h +index 1dd8716..d53ce1f 100644 +--- a/sound/pci/hda/hda_local.h ++++ b/sound/pci/hda/hda_local.h +@@ -26,8 +26,10 @@ + /* + * for mixer controls + */ ++#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \ ++ ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23)) + #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ +- ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) ++ HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0) + /* mono volume with index (index=0,1,...) (channel=1,2) */ + #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ +@@ -432,5 +434,6 @@ int snd_hda_check_amp_list_power(struct + #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) + #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) + #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) ++#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) + + #endif /* __SOUND_HDA_LOCAL_H */ +-- +1.6.1 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-alc269-fsc-amilo b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-alc269-fsc-amilo new file mode 100644 index 000000000..fcbf75aec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-alc269-fsc-amilo @@ -0,0 +1,102 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add ALC269 fujitsu model +Patch-mainline: +References: bnc#440626 + +Added a dedicated quirk model for FSC Amilo with ALC269. +The patch is almost same as in sound git tree, but it has a fix +for capture mixer setup (missing patch-series in SUSE kernel tree). + +Signed-off-by: Takashi Iwai + +--- + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 2 + + sound/pci/hda/patch_realtek.c | 29 +++++++++++++++++++++++- + 2 files changed, 30 insertions(+), 1 deletion(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -857,6 +857,8 @@ Prior to version 0.9.0rc4 options had a + quanta Quanta FL1 + eeepc-p703 ASUS Eeepc P703 P900A + eeepc-p901 ASUS Eeepc P901 S101 ++ fujitsu FSC Amilo ++ auto auto-config reading BIOS (default) + + ALC662/663 + 3stack-dig 3-stack (2-channel) with SPDIF +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -130,6 +130,7 @@ enum { + ALC269_QUANTA_FL1, + ALC269_ASUS_EEEPC_P703, + ALC269_ASUS_EEEPC_P901, ++ ALC269_FUJITSU, + ALC269_AUTO, + ALC269_MODEL_LAST /* last tag */ + }; +@@ -1621,6 +1622,7 @@ static const char *alc_slave_vols[] = { + "Speaker Playback Volume", + "Mono Playback Volume", + "Line-Out Playback Volume", ++ "PCM Playback Volume", + NULL, + }; + +@@ -11937,6 +11939,15 @@ static struct snd_kcontrol_new alc269_ca + static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), ++ { } /* end */ ++}; ++ ++/* FSC amilo */ ++static struct snd_kcontrol_new alc269_fujitsu_mixer[] = { ++ HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), ++ HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol), + { } /* end */ + }; + +@@ -12359,7 +12370,8 @@ static const char *alc269_models[ALC269_ + [ALC269_BASIC] = "basic", + [ALC269_QUANTA_FL1] = "quanta", + [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", +- [ALC269_ASUS_EEEPC_P901] = "eeepc-p901" ++ [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", ++ [ALC269_FUJITSU] = "fujitsu" + }; + + static struct snd_pci_quirk alc269_cfg_tbl[] = { +@@ -12370,6 +12382,7 @@ static struct snd_pci_quirk alc269_cfg_t + ALC269_ASUS_EEEPC_P901), + SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", + ALC269_ASUS_EEEPC_P901), ++ SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), + {} + }; + +@@ -12414,6 +12427,20 @@ static struct alc_config_preset alc269_p + .init_verbs = { alc269_init_verbs, + alc269_eeepc_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), ++ .dac_nids = alc269_dac_nids, ++ .hp_nid = 0x03, ++ .num_channel_mode = ARRAY_SIZE(alc269_modes), ++ .channel_mode = alc269_modes, ++ .input_mux = &alc269_eeepc_dmic_capture_source, ++ .unsol_event = alc269_eeepc_dmic_unsol_event, ++ .init_hook = alc269_eeepc_dmic_inithook, ++ }, ++ [ALC269_FUJITSU] = { ++ .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer, ++ alc269_epc_capture_mixer }, ++ .init_verbs = { alc269_init_verbs, ++ alc269_eeepc_dmic_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-analog-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-analog-update new file mode 100644 index 000000000..e38a48acd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-analog-update @@ -0,0 +1,220 @@ +From: Takashi Iwai +Subject: ALSA: hda - update Analaog Device codec support +Patch-mainline: 2.6.28-rc1 +References: + +- Fix AD1988 output noises +- Slave HDMI support on AD1989 +- Added the support for AD1882A + +Signed-off-by: Takashi Iwai + +--- +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 2 + sound/pci/hda/patch_analog.c | 89 +++++++++++++++++++----- + 2 files changed, 72 insertions(+), 19 deletions(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -929,7 +929,7 @@ Prior to version 0.9.0rc4 options had a + allout 5-jack in back, 2-jack in front, SPDIF out + auto auto-config reading BIOS (default) + +- AD1882 ++ AD1882 / AD1882A + 3stack 3-stack mode (default) + 6stack 6-stack mode + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -1869,9 +1869,14 @@ static hda_nid_t ad1988_capsrc_nids[3] = + 0x0c, 0x0d, 0x0e + }; + +-#define AD1988_SPDIF_OUT 0x02 ++#define AD1988_SPDIF_OUT 0x02 ++#define AD1988_SPDIF_OUT_HDMI 0x0b + #define AD1988_SPDIF_IN 0x07 + ++static hda_nid_t ad1989b_slave_dig_outs[2] = { ++ AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI ++}; ++ + static struct hda_input_mux ad1988_6stack_capture_source = { + .num_items = 5, + .items = { +@@ -2186,6 +2191,7 @@ static struct snd_kcontrol_new ad1988_sp + + static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { + HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), + { } /* end */ + }; + +@@ -2250,6 +2256,8 @@ static struct hda_verb ad1988_6stack_ini + {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, + /* Analog CD Input */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ /* Analog Mix output amp */ ++ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ + + { } + }; +@@ -2383,6 +2391,8 @@ static struct hda_verb ad1988_3stack_ini + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ /* Analog Mix output amp */ ++ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ + { } + }; + +@@ -2456,6 +2466,8 @@ static struct hda_verb ad1988_laptop_ini + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ /* Analog Mix output amp */ ++ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ + { } + }; + +@@ -3023,6 +3035,7 @@ static int patch_ad1988(struct hda_codec + ad1989_spdif_out_mixers; + spec->init_verbs[spec->num_init_verbs++] = + ad1989_spdif_init_verbs; ++ codec->slave_dig_outs = ad1989b_slave_dig_outs; + } else { + spec->mixers[spec->num_mixers++] = + ad1988_spdif_out_mixers; +@@ -3963,7 +3976,7 @@ static int patch_ad1884a(struct hda_code + + + /* +- * AD1882 ++ * AD1882 / AD1882A + * + * port-A - front hp-out + * port-B - front mic-in +@@ -4000,6 +4013,18 @@ static struct hda_input_mux ad1882_captu + }, + }; + ++/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ ++static struct hda_input_mux ad1882a_capture_source = { ++ .num_items = 5, ++ .items = { ++ { "Front Mic", 0x1 }, ++ { "Mic", 0x4}, ++ { "Line", 0x2 }, ++ { "Digital Mic", 0x06 }, ++ { "Mix", 0x7 }, ++ }, ++}; ++ + static struct snd_kcontrol_new ad1882_base_mixers[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), +@@ -4009,16 +4034,7 @@ static struct snd_kcontrol_new ad1882_ba + HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), +- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), +- HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), +- HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), +- HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), +- HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), +- HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), +- HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), +- HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT), +- HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT), ++ + HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT), +@@ -4051,6 +4067,35 @@ static struct snd_kcontrol_new ad1882_ba + { } /* end */ + }; + ++static struct snd_kcontrol_new ad1882_loopback_mixers[] = { ++ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), ++ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), ++ HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), ++ HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), ++ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), ++ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), ++ HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT), ++ HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT), ++ { } /* end */ ++}; ++ ++static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { ++ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), ++ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), ++ HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), ++ HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), ++ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), ++ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), ++ HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT), ++ HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT), ++ HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT), ++ { } /* end */ ++}; ++ + static struct snd_kcontrol_new ad1882_3stack_mixers[] = { + HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), +@@ -4220,9 +4265,16 @@ static int patch_ad1882(struct hda_codec + spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); + spec->adc_nids = ad1882_adc_nids; + spec->capsrc_nids = ad1882_capsrc_nids; +- spec->input_mux = &ad1882_capture_source; +- spec->num_mixers = 1; ++ if (codec->vendor_id == 0x11d1882) ++ spec->input_mux = &ad1882_capture_source; ++ else ++ spec->input_mux = &ad1882a_capture_source; ++ spec->num_mixers = 2; + spec->mixers[0] = ad1882_base_mixers; ++ if (codec->vendor_id == 0x11d1882) ++ spec->mixers[1] = ad1882_loopback_mixers; ++ else ++ spec->mixers[1] = ad1882a_loopback_mixers; + spec->num_init_verbs = 1; + spec->init_verbs[0] = ad1882_init_verbs; + spec->spdif_route = 0; +@@ -4239,8 +4291,8 @@ static int patch_ad1882(struct hda_codec + switch (board_config) { + default: + case AD1882_3STACK: +- spec->num_mixers = 2; +- spec->mixers[1] = ad1882_3stack_mixers; ++ spec->num_mixers = 3; ++ spec->mixers[2] = ad1882_3stack_mixers; + spec->channel_mode = ad1882_modes; + spec->num_channel_mode = ARRAY_SIZE(ad1882_modes); + spec->need_dac_fix = 1; +@@ -4248,8 +4300,8 @@ static int patch_ad1882(struct hda_codec + spec->multiout.num_dacs = 1; + break; + case AD1882_6STACK: +- spec->num_mixers = 2; +- spec->mixers[1] = ad1882_6stack_mixers; ++ spec->num_mixers = 3; ++ spec->mixers[2] = ad1882_6stack_mixers; + break; + } + return 0; +@@ -4272,6 +4324,7 @@ struct hda_codec_preset snd_hda_preset_a + { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, + { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, + { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, ++ { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 }, + { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 }, + { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, + {} /* terminator */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-atihdmi-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-atihdmi-update new file mode 100644 index 000000000..9a42b6221 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-atihdmi-update @@ -0,0 +1,129 @@ +From: Takashi Iwai +Subject: ALSA: hda - update ATI HDMI codec support +Patch-mainline: 2.6.28-rc1 +References: bnc#363153 + +Updates for HDMI support; 8-ch LPCM is capable. + +Signed-off-by: Takashi Iwai + +--- +diff -ruN a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c +--- a/sound/pci/hda/patch_atihdmi.c ++++ b/sound/pci/hda/patch_atihdmi.c +@@ -35,6 +35,9 @@ + struct hda_pcm pcm_rec; + }; + ++#define CVT_NID 0x02 /* audio converter */ ++#define PIN_NID 0x03 /* HDMI output pin */ ++ + static struct hda_verb atihdmi_basic_init[] = { + /* enable digital output on pin widget */ + { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, +@@ -60,8 +63,9 @@ + { + snd_hda_sequence_write(codec, atihdmi_basic_init); + /* SI codec requires to unmute the pin */ +- if (get_wcaps(codec, 0x03) & AC_WCAP_OUT_AMP) +- snd_hda_codec_write(codec, 0x03, 0, AC_VERB_SET_AMP_GAIN_MUTE, ++ if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) ++ snd_hda_codec_write(codec, PIN_NID, 0, ++ AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + return 0; + } +@@ -92,15 +96,29 @@ + struct snd_pcm_substream *substream) + { + struct atihdmi_spec *spec = codec->spec; +- return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, +- format, substream); ++ int chans = substream->runtime->channels; ++ int i, err; ++ ++ err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, ++ format, substream); ++ if (err < 0) ++ return err; ++ snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT, ++ chans - 1); ++ /* FIXME: XXX */ ++ for (i = 0; i < chans; i++) { ++ snd_hda_codec_write(codec, CVT_NID, 0, ++ AC_VERB_SET_HDMI_CHAN_SLOT, ++ (i << 4) | i); ++ } ++ return 0; + } + + static struct hda_pcm_stream atihdmi_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +- .nid = 0x2, /* NID to query formats and rates and setup streams */ ++ .nid = CVT_NID, /* NID to query formats and rates and setup streams */ + .ops = { + .open = atihdmi_dig_playback_pcm_open, + .close = atihdmi_dig_playback_pcm_close, +@@ -112,6 +130,7 @@ + { + struct atihdmi_spec *spec = codec->spec; + struct hda_pcm *info = &spec->pcm_rec; ++ unsigned int chans; + + codec->num_pcms = 1; + codec->pcm_info = info; +@@ -120,6 +139,13 @@ + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; + ++ /* FIXME: we must check ELD and change the PCM parameters dynamically ++ */ ++ chans = get_wcaps(codec, CVT_NID); ++ chans = (chans & AC_WCAP_CHAN_CNT_EXT) >> 13; ++ chans = ((chans << 1) | 1) + 1; ++ info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; ++ + return 0; + } + +@@ -147,9 +173,11 @@ + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 2; +- spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital, +- * seems to be unused in pure-digital +- * case. */ ++ /* NID for copying analog to digital, ++ * seems to be unused in pure-digital ++ * case. ++ */ ++ spec->multiout.dig_out_nid = CVT_NID; + + codec->patch_ops = atihdmi_patch_ops; + +@@ -164,6 +192,7 @@ + { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, + { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, + { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, ++ { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, + { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi }, + { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, + {} /* terminator */ +diff -ruN a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -746,8 +746,10 @@ + Module snd-hda-intel + -------------------- + +- Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8), +- ATI SB450, SB600, RS600, ++ Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8, ICH9, ICH10, ++ PCH, SCH), ++ ATI SB450, SB600, R600, RS600, RS690, RS780, RV610, RV620, ++ RV630, RV635, RV670, RV770, + VIA VT8251/VT8237A, + SIS966, ULI M5461 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep new file mode 100644 index 000000000..3f4fa3c0d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep @@ -0,0 +1,246 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add digital beep support +Patch-mainline: 2.6.28-rc1 +References: bnc#398459, bnc#398455 + +Add the support of digital beep for devices without analog beep. + +Signed-off-by: Takashi Iwai + +--- +diff -ruN a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c +--- a/sound/pci/hda/hda_beep.c ++++ b/sound/pci/hda/hda_beep.c +@@ -0,0 +1,134 @@ ++/* ++ * Digital Beep Input Interface for HD-audio codec ++ * ++ * Author: Matthew Ranostay ++ * Copyright (c) 2008 Embedded Alley Solutions Inc ++ * ++ * This driver is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This driver is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include "hda_beep.h" ++ ++enum { ++ DIGBEEP_HZ_STEP = 46875, /* 46.875 Hz */ ++ DIGBEEP_HZ_MIN = 93750, /* 93.750 Hz */ ++ DIGBEEP_HZ_MAX = 12000000, /* 12 KHz */ ++}; ++ ++static void snd_hda_generate_beep(struct work_struct *work) ++{ ++ struct hda_beep *beep = ++ container_of(work, struct hda_beep, beep_work); ++ struct hda_codec *codec = beep->codec; ++ ++ /* generate tone */ ++ snd_hda_codec_write_cache(codec, beep->nid, 0, ++ AC_VERB_SET_BEEP_CONTROL, beep->tone); ++} ++ ++static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, ++ unsigned int code, int hz) ++{ ++ struct hda_beep *beep = input_get_drvdata(dev); ++ ++ switch (code) { ++ case SND_BELL: ++ if (hz) ++ hz = 1000; ++ case SND_TONE: ++ hz *= 1000; /* fixed point */ ++ hz = hz - DIGBEEP_HZ_MIN; ++ if (hz < 0) ++ hz = 0; /* turn off PC beep*/ ++ else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) ++ hz = 0xff; ++ else { ++ hz /= DIGBEEP_HZ_STEP; ++ hz++; ++ } ++ break; ++ default: ++ return -1; ++ } ++ beep->tone = hz; ++ ++ /* schedule beep event */ ++ schedule_work(&beep->beep_work); ++ return 0; ++} ++ ++int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) ++{ ++ struct input_dev *input_dev; ++ struct hda_beep *beep; ++ int err; ++ ++ beep = kzalloc(sizeof(*beep), GFP_KERNEL); ++ if (beep == NULL) ++ return -ENOMEM; ++ snprintf(beep->phys, sizeof(beep->phys), ++ "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); ++ input_dev = input_allocate_device(); ++ ++ /* setup digital beep device */ ++ input_dev->name = "HDA Digital PCBeep"; ++ input_dev->phys = beep->phys; ++ input_dev->id.bustype = BUS_PCI; ++ ++ input_dev->id.vendor = codec->vendor_id >> 16; ++ input_dev->id.product = codec->vendor_id & 0xffff; ++ input_dev->id.version = 0x01; ++ ++ input_dev->evbit[0] = BIT_MASK(EV_SND); ++ input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); ++ input_dev->event = snd_hda_beep_event; ++ input_dev->dev.parent = &codec->bus->pci->dev; ++ input_set_drvdata(input_dev, beep); ++ ++ err = input_register_device(input_dev); ++ if (err < 0) { ++ input_free_device(input_dev); ++ kfree(beep); ++ return err; ++ } ++ ++ /* enable linear scale */ ++ snd_hda_codec_write(codec, nid, 0, ++ AC_VERB_SET_DIGI_CONVERT_2, 0x01); ++ ++ beep->nid = nid; ++ beep->dev = input_dev; ++ beep->codec = codec; ++ codec->beep = beep; ++ ++ INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); ++ return 0; ++} ++ ++void snd_hda_detach_beep_device(struct hda_codec *codec) ++{ ++ struct hda_beep *beep = codec->beep; ++ if (beep) { ++ cancel_work_sync(&beep->beep_work); ++ flush_scheduled_work(); ++ ++ input_unregister_device(beep->dev); ++ kfree(beep); ++ } ++} +diff -ruN a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h +--- a/sound/pci/hda/hda_beep.h ++++ b/sound/pci/hda/hda_beep.h +@@ -0,0 +1,44 @@ ++/* ++ * Digital Beep Input Interface for HD-audio codec ++ * ++ * Author: Matthew Ranostay ++ * Copyright (c) 2008 Embedded Alley Solutions Inc ++ * ++ * This driver is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This driver is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef __SOUND_HDA_BEEP_H ++#define __SOUND_HDA_BEEP_H ++ ++#include "hda_codec.h" ++ ++/* beep information */ ++struct hda_beep { ++ struct input_dev *dev; ++ struct hda_codec *codec; ++ char phys[32]; ++ int tone; ++ int nid; ++ struct work_struct beep_work; /* scheduled task for beep event */ ++}; ++ ++#ifdef CONFIG_SND_HDA_INPUT_BEEP ++int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); ++void snd_hda_detach_beep_device(struct hda_codec *codec); ++#else ++#define snd_hda_attach_beep_device(...) ++#define snd_hda_detach_beep_device(...) ++#endif ++#endif +diff -ruN a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile +--- a/sound/pci/hda/Makefile ++++ b/sound/pci/hda/Makefile +@@ -5,6 +5,7 @@ + snd-hda-intel-y += hda_codec.o + snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o + snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o ++snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o + snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o +diff -ruN a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -449,6 +449,7 @@ + */ + + struct hda_bus; ++struct hda_beep; + struct hda_codec; + struct hda_pcm; + struct hda_pcm_stream; +@@ -634,6 +635,9 @@ + /* codec specific info */ + void *spec; + ++ /* beep device */ ++ struct hda_beep *beep; ++ + /* widget capabilities cache */ + unsigned int num_nodes; + hda_nid_t start_nid; +diff -ruN a/sound/pci/Kconfig b/sound/pci/Kconfig +--- a/sound/pci/Kconfig ++++ b/sound/pci/Kconfig +@@ -517,6 +517,14 @@ + This interface can be used for out-of-band communication + with codecs for debugging purposes. + ++config SND_HDA_INPUT_BEEP ++ bool "Support digital beep via input layer" ++ depends on SND_HDA_INTEL ++ depends on INPUT=y || INPUT=SND_HDA_INTEL ++ help ++ Say Y here to build a digital beep interface for HD-audio ++ driver. This interface is used to generate digital beeps. ++ + config SND_HDA_CODEC_REALTEK + bool "Build Realtek HD-audio codec support" + depends on SND_HDA_INTEL diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep-dig-switch b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep-dig-switch new file mode 100644 index 000000000..e4c0b4016 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep-dig-switch @@ -0,0 +1,168 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add digital beep playback switch for STAC/IDT codecs +Patch-mainline: +References: #444572 + +The digital beep widget may have no mute control, and always enabling +the beep is ofen pretty annoying, especially on laptops. + +This patch adds a mixer control "PC Beep Playback Switch" when there +is no mixer amp mute is found, and controls it on software. + +Reference: Novell bnc#444572 + https://bugzilla.novell.com/show_bug.cgi?id=444572 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_beep.c | 4 ++ + sound/pci/hda/hda_beep.h | 1 + sound/pci/hda/patch_sigmatel.c | 69 +++++++++++++++++++++++++++++++++++++---- + 3 files changed, 68 insertions(+), 6 deletions(-) + +--- a/sound/pci/hda/hda_beep.c ++++ b/sound/pci/hda/hda_beep.c +@@ -37,6 +37,9 @@ static void snd_hda_generate_beep(struct + container_of(work, struct hda_beep, beep_work); + struct hda_codec *codec = beep->codec; + ++ if (!beep->enabled) ++ return; ++ + /* generate tone */ + snd_hda_codec_write_cache(codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, beep->tone); +@@ -115,6 +118,7 @@ int snd_hda_attach_beep_device(struct hd + beep->nid = nid; + beep->dev = input_dev; + beep->codec = codec; ++ beep->enabled = 1; + codec->beep = beep; + + INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); +--- a/sound/pci/hda/hda_beep.h ++++ b/sound/pci/hda/hda_beep.h +@@ -31,6 +31,7 @@ struct hda_beep { + char phys[32]; + int tone; + int nid; ++ int enabled; + struct work_struct beep_work; /* scheduled task for beep event */ + }; + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -2592,8 +2592,10 @@ static struct snd_kcontrol_new stac92xx_ + }; + + /* add dynamic controls */ +-static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type, +- int idx, const char *name, unsigned long val) ++static int stac92xx_add_control_temp(struct sigmatel_spec *spec, ++ struct snd_kcontrol_new *ktemp, ++ int idx, const char *name, ++ unsigned long val) + { + struct snd_kcontrol_new *knew; + +@@ -2612,20 +2614,29 @@ static int stac92xx_add_control_idx(stru + } + + knew = &spec->kctl_alloc[spec->num_kctl_used]; +- *knew = stac92xx_control_templates[type]; ++ *knew = *ktemp; + knew->index = idx; + knew->name = kstrdup(name, GFP_KERNEL); +- if (! knew->name) ++ if (!knew->name) + return -ENOMEM; + knew->private_value = val; + spec->num_kctl_used++; + return 0; + } + ++static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, ++ int type, int idx, const char *name, ++ unsigned long val) ++{ ++ return stac92xx_add_control_temp(spec, ++ &stac92xx_control_templates[type], ++ idx, name, val); ++} ++ + + /* add dynamic controls */ +-static int stac92xx_add_control(struct sigmatel_spec *spec, int type, +- const char *name, unsigned long val) ++static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, ++ const char *name, unsigned long val) + { + return stac92xx_add_control_idx(spec, type, 0, name, val); + } +@@ -3067,6 +3078,43 @@ static int stac92xx_auto_create_beep_ctl + return 0; + } + ++#ifdef CONFIG_SND_HDA_INPUT_BEEP ++#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info ++ ++static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ ucontrol->value.integer.value[0] = codec->beep->enabled; ++ return 0; ++} ++ ++static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ int enabled = !!ucontrol->value.integer.value[0]; ++ if (codec->beep->enabled != enabled) { ++ codec->beep->enabled = enabled; ++ return 1; ++ } ++ return 0; ++} ++ ++static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .info = stac92xx_dig_beep_switch_info, ++ .get = stac92xx_dig_beep_switch_get, ++ .put = stac92xx_dig_beep_switch_put, ++}; ++ ++static int stac92xx_beep_switch_ctl(struct hda_codec *codec) ++{ ++ return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl, ++ 0, "PC Beep Playback Switch", 0); ++} ++#endif ++ + static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; +@@ -3373,6 +3421,7 @@ static int stac92xx_parse_auto_config(st + #ifdef CONFIG_SND_HDA_INPUT_BEEP + if (spec->digbeep_nid > 0) { + hda_nid_t nid = spec->digbeep_nid; ++ unsigned int caps; + + err = stac92xx_auto_create_beep_ctls(codec, nid); + if (err < 0) +@@ -3380,6 +3429,14 @@ static int stac92xx_parse_auto_config(st + err = snd_hda_attach_beep_device(codec, nid); + if (err < 0) + return err; ++ /* if no beep switch is available, make its own one */ ++ caps = query_amp_caps(codec, nid, HDA_OUTPUT); ++ if (codec->beep && ++ !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) { ++ err = stac92xx_beep_switch_ctl(codec); ++ if (err < 0) ++ return err; ++ } + } + #endif + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep-null-check-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep-null-check-fix new file mode 100644 index 000000000..e4438c541 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-beep-null-check-fix @@ -0,0 +1,31 @@ +From: Takashi Iwai +Subject: ALSA: hda - Missing NULL check in hda_beep.c +Patch-mainline: +References: + +Added a NULL check of input_allocate_device() in hda_beep.c. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_beep.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c +index b1796ae..3ecd7e7 100644 +--- a/sound/pci/hda/hda_beep.c ++++ b/sound/pci/hda/hda_beep.c +@@ -88,6 +88,10 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) + snprintf(beep->phys, sizeof(beep->phys), + "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); + input_dev = input_allocate_device(); ++ if (!input_dev) { ++ kfree(beep); ++ return -ENOMEM; ++ } + + /* setup digital beep device */ + input_dev->name = "HDA Digital PCBeep"; +-- +1.6.0.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-dell-92hd73xx-models b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-dell-92hd73xx-models new file mode 100644 index 000000000..77bb45f30 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-dell-92hd73xx-models @@ -0,0 +1,133 @@ +From: Takashi Iwai +Subject: ALSA: hda - Check model for Dell 92HD73xx laptops +Patch-mainline: +References: bnc#446025 + +Check the model type instead of PCI SSID for detection of the mic types +on Dell laptops with IDT 92HD73xx codecs. In this way, a new laptop +can be tested via model module option. + +Signed-off-by: Takashi Iwai + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 4 +- + sound/pci/hda/patch_sigmatel.c | 47 +++++++++++++----------- + 2 files changed, 29 insertions(+), 22 deletions(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -1080,7 +1080,9 @@ Prior to version 0.9.0rc4 options had a + + STAC92HD73* + ref Reference board +- dell-m6 Dell desktops ++ dell-m6-amic Dell desktops/laptops with analog mics ++ dell-m6-dmic Dell desktops/laptops with digital mics ++ dell-m6 Dell desktops/laptops with both type of mics + + STAC9872 + vaio Setup for VAIO FE550G/SZ110 +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -70,7 +70,9 @@ enum { + + enum { + STAC_92HD73XX_REF, +- STAC_DELL_M6, ++ STAC_DELL_M6_AMIC, ++ STAC_DELL_M6_DMIC, ++ STAC_DELL_M6_BOTH, + STAC_DELL_EQ, + STAC_92HD73XX_MODELS + }; +@@ -1604,13 +1606,17 @@ static unsigned int dell_m6_pin_configs[ + + static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { + [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, +- [STAC_DELL_M6] = dell_m6_pin_configs, ++ [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, ++ [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, ++ [STAC_DELL_M6_BOTH] = dell_m6_pin_configs, + [STAC_DELL_EQ] = dell_m6_pin_configs, + }; + + static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { + [STAC_92HD73XX_REF] = "ref", +- [STAC_DELL_M6] = "dell-m6", ++ [STAC_DELL_M6_AMIC] = "dell-m6-amic", ++ [STAC_DELL_M6_DMIC] = "dell-m6-dmic", ++ [STAC_DELL_M6_BOTH] = "dell-m6", + [STAC_DELL_EQ] = "dell-eq", + }; + +@@ -1619,21 +1625,23 @@ static struct snd_pci_quirk stac92hd73xx + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD73XX_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254, +- "Dell Studio 1535", STAC_DELL_M6), ++ "Dell Studio 1535", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255, +- "unknown Dell", STAC_DELL_M6), ++ "unknown Dell", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256, +- "unknown Dell", STAC_DELL_M6), ++ "unknown Dell", STAC_DELL_M6_BOTH), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257, +- "unknown Dell", STAC_DELL_M6), ++ "unknown Dell", STAC_DELL_M6_BOTH), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e, +- "unknown Dell", STAC_DELL_M6), ++ "unknown Dell", STAC_DELL_M6_AMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f, +- "unknown Dell", STAC_DELL_M6), ++ "unknown Dell", STAC_DELL_M6_AMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271, +- "unknown Dell", STAC_DELL_M6), ++ "unknown Dell", STAC_DELL_M6_DMIC), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272, ++ "unknown Dell", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f, +- "Dell Studio 15", STAC_DELL_M6), ++ "Dell Studio 1537", STAC_DELL_M6_DMIC), + {} /* terminator */ + }; + +@@ -4284,7 +4292,9 @@ again: + case STAC_DELL_EQ: + spec->init = dell_eq_core_init; + /* fallthru */ +- case STAC_DELL_M6: ++ case STAC_DELL_M6_AMIC: ++ case STAC_DELL_M6_DMIC: ++ case STAC_DELL_M6_BOTH: + if (!spec->init) + spec->init = dell_m6_core_init; + spec->num_smuxes = 0; +@@ -4292,23 +4302,18 @@ again: + spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; + spec->eapd_switch = 0; + spec->num_amps = 1; +- switch (codec->subsystem_id) { +- case 0x1028025e: /* Analog Mics */ +- case 0x1028025f: ++ switch (spec->board_config) { ++ case STAC_DELL_M6_AMIC: /* Analog Mics */ + stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); + spec->num_dmics = 0; + spec->private_dimux.num_items = 1; + break; +- case 0x10280271: /* Digital Mics */ +- case 0x10280272: +- case 0x10280254: +- case 0x10280255: ++ case STAC_DELL_M6_DMIC: /* Digital Mics */ + stac92xx_set_config_reg(codec, 0x13, 0x90A60160); + spec->num_dmics = 1; + spec->private_dimux.num_items = 2; + break; +- case 0x10280256: /* Both */ +- case 0x10280057: ++ case STAC_DELL_M6_BOTH: /* Both */ + stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); + stac92xx_set_config_reg(codec, 0x13, 0x90A60160); + spec->num_dmics = 1; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-dell-studio-probe-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-dell-studio-probe-fix new file mode 100644 index 000000000..9dd53226f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-dell-studio-probe-fix @@ -0,0 +1,27 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix probe errors on Dell Studio Desktop +Patch-mainline: +References: bnc#440907 + +BIOS on Dell Studio Desktop tells wrong codec probe masks. +This patch gives the preset mask value to avoid invalid access. +Reference: Novell bug#440907 + https://bugzilla.novell.com/show_bug.cgi?id=440907 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -2097,6 +2097,8 @@ static struct snd_pci_quirk probe_mask_l + SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), ++ /* broken BIOS */ ++ SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), + {} + }; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-fix new file mode 100644 index 000000000..ba444a3be --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-fix @@ -0,0 +1,231 @@ +From 9cb36c2afc298a2f2085ae0071924b7e3f55e72d Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Mon, 11 Aug 2008 10:18:39 +0200 +Subject: ALSA: patch_sigmatel: Add missing Gateway entries and autodetection +Patch-mainline: 2.6.29-rc1 +References: bnc#460478 + + +Gateway autodetection and entries are incomplete. + +This patch adds the entries found at the .INI file for their driver version +5.10.5082.0. + +It also uses the proper code to seek for notebook ID, since this is based on +codec subsystem ID on those devices. + +This should provide a proper pinup for several gateways notebooks: + Gateway M465-E Notebook [Part #1008637] + Gateway M465-G Notebook [Part #1008667] + Gateway NX260X Notebook [Part #1008794] + Gateway NX100X Notebook [Part #1008798] + Gateway E-100M Notebook [Part #1008799] + Gateway E-100M G Notebook [Part #1008800] + Gateway M255-E Notebook [Part #1008801] + Gateway M255-G Notebook [Part #1008803] + Gateway M285-E Convertible Notebook [Part #1008804] + Gateway M285-G Convertible Notebook [Part #1008805] + Gateway CX210S Convertible Notebook [Part #1008807] + Gateway CX210X Convertible Notebook [Part #1008808] + Gateway E-100M SB Notebook [Part #1008973] + Gateway M255-E SB Notebook [Part #1008989] + Gateway M285-E SB Convertible Notebook [Part #1008990] + Gateway M465-E Notebook [Part #1009022] + Gateway CX2724 Convertible Notebook [Part #1009036] + Gateway MX1025 Notebook [Part #1009046] + Gateway CX2720 Convertible Notebook [Part #1009063] + Gateway CX2724h Convertible Notebook [Part #1009089] + Gateway MX1023 Notebook [Part #1009097] + Gateway MX1023h Notebook [Part #1009098] + Gateway NX260X Notebook [Part #1009112] + Gateway E-100M Notebook [Part #1009126] + Gateway MX7533 Notebook [Part #1009146] [Part #1009163] + Gateway CX210X Convertible Notebook [Part #1009346] + Gateway NX570X Notebook [Part #1009442] + Gateway NX570X Notebook [Part #1009448] + Gateway NX270S Notebook [Part #1009550] + Gateway MX6448 Notebook [Part #1013912R] + Gateway MX6453 Notebook [Part #1013913R] + Gateway MX6216 Notebook [Part #1013916R] + Gateway MX6931 Notebook [Part #1013918R] + Gateway CX2726 Convertible Notebook [Part #1013921R] + Gateway MP8708 Notebook [Part #1013924R] + Gateway MX6446 Notebook [Part #1013927R] + Gateway MX6930 Notebook [Part #1013928R] + Gateway MX6447 Notebook [Part #1013932R] + Gateway MX6454 Notebook [Part #1013943R] + Gateway MX6439 Notebook [Part #1013947R] [Part #1013955R] [Part #1013971R] + Gateway MX6930h Notebook [Part #1013973R] [Part #1013974R] [Part #1013975R] + Gateway MX6955 Notebook [Part #1014028R] + Gateway MX6956 Notebook [Part #1014033R] + Gateway MX6959 Notebook [Part #1014061R] + Gateway MX6957 Notebook [Part #1014065R] + Gateway MX6960 Notebook [Part #1014068R] + Gateway MX6958 Notebook [Part #1014072R] + Gateway NX570X Notebook [Part #1014077R] + Gateway NX570XL Notebook [Part #1014078R] + Gateway NX570QS Notebook [Part #1014079R] + Gateway MX6961 Notebook [Part #1014080R] [Part #1014106R] + Gateway MX6961h Notebook [Part #1014112R] + Gateway NX270S Notebook [Part #1014120R] + Gateway MX6431 Notebook [Part #1014121R] + Gateway MX8710 Notebook [Part #2905895R] + Gateway MX3702 Notebook [Part #2905898R] + Blade-K8F GW UMA Single Core Motherboard w/RS485M and 1394 - Quanta (FRU) [Part #4006133R] + +Since some entries conflict with existing pinups, I'm providing a separate +patch to fix those entries. + +Tested only with Gateway MX6453. + +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 89 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 81 insertions(+), 8 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -94,7 +94,13 @@ enum { + + enum { + STAC_925x_REF, ++ STAC_M1, ++ STAC_M1_2, ++ STAC_M2, + STAC_M2_2, ++ STAC_M3, ++ STAC_M5, ++ STAC_M6, + STAC_MA6, + STAC_PA6, + STAC_925x_MODELS +@@ -1551,11 +1557,40 @@ static unsigned int ref925x_pin_configs[ + 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, + }; + ++static unsigned int stac925xM1_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, ++}; ++static unsigned int stac925xM1_2_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, ++}; ++static unsigned int stac925xM2_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, ++}; ++ ++static unsigned int stac925xM3_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, ++}; ++static unsigned int stac925xM5_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, ++}; ++ ++/* Original M6 entry at .ini file */ ++static unsigned int stac925xM6_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, ++}; ++ + static unsigned int stac925x_MA6_pin_configs[8] = { + 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, + 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, + }; + ++/* This entry should be M2 */ + static unsigned int stac925x_PA6_pin_configs[8] = { + 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, + 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e, +@@ -1568,27 +1603,55 @@ static unsigned int stac925xM2_2_pin_con + + static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { + [STAC_REF] = ref925x_pin_configs, ++ [STAC_M1] = stac925xM1_pin_configs, ++ [STAC_M1_2] = stac925xM1_2_pin_configs, ++ [STAC_M2] = stac925xM2_pin_configs, + [STAC_M2_2] = stac925xM2_2_pin_configs, ++ [STAC_M3] = stac925xM3_pin_configs, ++ [STAC_M5] = stac925xM5_pin_configs, ++ [STAC_M6] = stac925xM6_pin_configs, + [STAC_MA6] = stac925x_MA6_pin_configs, + [STAC_PA6] = stac925x_PA6_pin_configs, + }; + + static const char *stac925x_models[STAC_925x_MODELS] = { + [STAC_REF] = "ref", ++ [STAC_M1] = "m1", ++ [STAC_M1_2] = "m1-2", ++ [STAC_M2] = "m2", + [STAC_M2_2] = "m2-2", +- [STAC_MA6] = "m6", ++ [STAC_M3] = "m3", ++ [STAC_M5] = "m5", ++ [STAC_M6] = "m6", ++ [STAC_MA6] = "ma6", + [STAC_PA6] = "pa6", + }; + +-static struct snd_pci_quirk stac925x_cfg_tbl[] = { +- /* SigmaTel reference board */ +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), +- SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), ++static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { + SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF), + SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF), ++ + SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6), + SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6), +- SND_PCI_QUIRK(0x1002, 0x437b, "Gateway MX6453", STAC_M2_2), ++ SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2), ++ ++ /* Not sure about the brand name for those */ ++ SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1), ++ SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3), ++ SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6), ++ SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2), ++ ++ {} /* terminator */ ++}; ++ ++static struct snd_pci_quirk stac925x_cfg_tbl[] = { ++ /* SigmaTel reference board */ ++ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), ++ SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), ++ ++ /* Default table for unknown ID */ ++ SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2), ++ + {} /* terminator */ + }; + +@@ -4149,12 +4212,22 @@ static int patch_stac925x(struct hda_cod + codec->spec = spec; + spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); + spec->pin_nids = stac925x_pin_nids; +- spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, ++ ++ /* Check first for codec ID */ ++ spec->board_config = snd_hda_check_board_codec_sid_config(codec, ++ STAC_925x_MODELS, ++ stac925x_models, ++ stac925x_codec_id_cfg_tbl); ++ ++ /* Now checks for PCI ID, if codec ID is not found */ ++ if (spec->board_config < 0) ++ spec->board_config = snd_hda_check_board_config(codec, ++ STAC_925x_MODELS, + stac925x_models, + stac925x_cfg_tbl); + again: + if (spec->board_config < 0) { +- snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," ++ snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," + "using BIOS defaults\n"); + err = stac92xx_save_bios_config_regs(codec); + if (err < 0) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-fix2 b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-fix2 new file mode 100644 index 000000000..d4c32d011 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-fix2 @@ -0,0 +1,190 @@ +From 58eec4235d63e07b98544527e031e7ae807e15df Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Mon, 11 Aug 2008 10:18:39 +0200 +Subject: ALSA: hda - More fixes on Gateway entries +Patch-mainline: 2.6.29-rc1 +References: bnc#460478 + +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 72 ++++++++++++++++++----------------------- + 1 file changed, 33 insertions(+), 39 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -55,7 +55,8 @@ enum { + STAC_9200_DELL_M25, + STAC_9200_DELL_M26, + STAC_9200_DELL_M27, +- STAC_9200_GATEWAY, ++ STAC_9200_M4, ++ STAC_9200_M4_2, + STAC_9200_PANASONIC, + STAC_9200_MODELS + }; +@@ -101,8 +102,6 @@ enum { + STAC_M3, + STAC_M5, + STAC_M6, +- STAC_MA6, +- STAC_PA6, + STAC_925x_MODELS + }; + +@@ -1326,7 +1325,16 @@ static unsigned int ref9200_pin_configs[ + 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, + }; + +-/* ++static unsigned int gateway9200_m4_pin_configs[8] = { ++ 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, ++ 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, ++}; ++static unsigned int gateway9200_m4_2_pin_configs[8] = { ++ 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, ++ 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, ++}; ++ ++/* + STAC 9200 pin configs for + 102801A8 + 102801DE +@@ -1456,6 +1464,8 @@ static unsigned int *stac9200_brd_tbl[ST + [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, + [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, + [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, ++ [STAC_9200_M4] = gateway9200_m4_pin_configs, ++ [STAC_9200_M4_2] = gateway9200_m4_2_pin_configs, + [STAC_9200_PANASONIC] = ref9200_pin_configs, + }; + +@@ -1472,7 +1482,8 @@ static const char *stac9200_models[STAC_ + [STAC_9200_DELL_M25] = "dell-m25", + [STAC_9200_DELL_M26] = "dell-m26", + [STAC_9200_DELL_M27] = "dell-m27", +- [STAC_9200_GATEWAY] = "gateway", ++ [STAC_9200_M4] = "gateway-m4", ++ [STAC_9200_M4_2] = "gateway-m4-2", + [STAC_9200_PANASONIC] = "panasonic", + }; + +@@ -1542,11 +1553,9 @@ static struct snd_pci_quirk stac9200_cfg + /* Panasonic */ + SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC), + /* Gateway machines needs EAPD to be set on resume */ +- SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY), +- SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", +- STAC_9200_GATEWAY), +- SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", +- STAC_9200_GATEWAY), ++ SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4), ++ SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2), ++ SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2), + /* OQO Mobile */ + SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO), + {} /* terminator */ +@@ -1561,46 +1570,37 @@ static unsigned int stac925xM1_pin_confi + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, + }; ++ + static unsigned int stac925xM1_2_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, + }; ++ + static unsigned int stac925xM2_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, + }; + ++static unsigned int stac925xM2_2_pin_configs[8] = { ++ 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, ++ 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, ++}; ++ + static unsigned int stac925xM3_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, + }; ++ + static unsigned int stac925xM5_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, + }; + +-/* Original M6 entry at .ini file */ + static unsigned int stac925xM6_pin_configs[8] = { + 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, + 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, + }; + +-static unsigned int stac925x_MA6_pin_configs[8] = { +- 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, +- 0x90a70320, 0x90100211, 0x400003f1, 0x9033032e, +-}; +- +-/* This entry should be M2 */ +-static unsigned int stac925x_PA6_pin_configs[8] = { +- 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, +- 0x50a103f0, 0x90100211, 0x400003f1, 0x9033032e, +-}; +- +-static unsigned int stac925xM2_2_pin_configs[8] = { +- 0x40c003f3, 0x424503f2, 0x04180011, 0x02a19020, +- 0x50a103f0, 0x90100212, 0x400003f1, 0x9033032e, +-}; +- + static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { + [STAC_REF] = ref925x_pin_configs, + [STAC_M1] = stac925xM1_pin_configs, +@@ -1610,8 +1610,6 @@ static unsigned int *stac925x_brd_tbl[ST + [STAC_M3] = stac925xM3_pin_configs, + [STAC_M5] = stac925xM5_pin_configs, + [STAC_M6] = stac925xM6_pin_configs, +- [STAC_MA6] = stac925x_MA6_pin_configs, +- [STAC_PA6] = stac925x_PA6_pin_configs, + }; + + static const char *stac925x_models[STAC_925x_MODELS] = { +@@ -1623,24 +1621,19 @@ static const char *stac925x_models[STAC_ + [STAC_M3] = "m3", + [STAC_M5] = "m5", + [STAC_M6] = "m6", +- [STAC_MA6] = "ma6", +- [STAC_PA6] = "pa6", + }; + + static struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { +- SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_REF), +- SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_REF), +- +- SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_MA6), +- SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_PA6), ++ SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2), ++ SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5), ++ SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1), ++ SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2), + SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2), +- + /* Not sure about the brand name for those */ + SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1), + SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3), + SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6), + SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2), +- + {} /* terminator */ + }; + +@@ -4177,7 +4170,8 @@ static int patch_stac9200(struct hda_cod + spec->num_adcs = 1; + spec->num_pwrs = 0; + +- if (spec->board_config == STAC_9200_GATEWAY || ++ if (spec->board_config == STAC_9200_M4 || ++ spec->board_config == STAC_9200_M4_2 || + spec->board_config == STAC_9200_OQO) + spec->init = stac9200_eapd_init; + else diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-t1616-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-t1616-quirk new file mode 100644 index 000000000..83471541c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-gateway-t1616-quirk @@ -0,0 +1,83 @@ +From d9a4268ee92ba1a2355c892a3add1fa66856b510 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 22 Jan 2009 17:40:18 +0100 +Subject: ALSA: hda - Add quirk for Gateway T1616 laptop +Patch-mainline: +References: bnc#467597 + +Gateway T1616 laptop needs EAPD always on while the current STAC9205 +code turns off per HP plug. Added a new model "eapd" to keep it on. + +Reference: Novell bnc#467597 + https://bugzilla.novell.com/show_bug.cgi?id=467597 + +Signed-off-by: Takashi Iwai + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 1 + + sound/pci/hda/patch_sigmatel.c | 10 +++++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -1037,6 +1037,7 @@ Prior to version 0.9.0rc4 options had a + dell-m42 Dell (unknown) + dell-m43 Dell Precision + dell-m44 Dell Inspiron ++ eapd Keep EAPD on (e.g. Gateway T1616) + + STAC9220/9221 + ref Reference board +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -66,6 +66,7 @@ enum { + STAC_9205_DELL_M42, + STAC_9205_DELL_M43, + STAC_9205_DELL_M44, ++ STAC_9205_EAPD, + STAC_9205_MODELS + }; + +@@ -2226,6 +2227,7 @@ static unsigned int *stac9205_brd_tbl[ST + [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, + [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, + [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, ++ [STAC_9205_EAPD] = NULL, + }; + + static const char *stac9205_models[STAC_9205_MODELS] = { +@@ -2233,12 +2235,14 @@ static const char *stac9205_models[STAC_ + [STAC_9205_DELL_M42] = "dell-m42", + [STAC_9205_DELL_M43] = "dell-m43", + [STAC_9205_DELL_M44] = "dell-m44", ++ [STAC_9205_EAPD] = "eapd", + }; + + static struct snd_pci_quirk stac9205_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_9205_REF), ++ /* Dell */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, +@@ -2269,6 +2273,8 @@ static struct snd_pci_quirk stac9205_cfg + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, + "Dell Vostro 1500", STAC_9205_DELL_M42), ++ /* Gateway */ ++ SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD), + {} /* terminator */ + }; + +@@ -5076,7 +5082,9 @@ static int patch_stac9205(struct hda_cod + + spec->aloopback_mask = 0x40; + spec->aloopback_shift = 0; +- spec->eapd_switch = 1; ++ /* Turn on/off EAPD per HP plugging */ ++ if (spec->board_config != STAC_9205_EAPD) ++ spec->eapd_switch = 1; + spec->multiout.dac_nids = spec->dac_nids; + + switch (spec->board_config){ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-3013-master-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-3013-master-fix new file mode 100644 index 000000000..10f3d3411 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-3013-master-fix @@ -0,0 +1,55 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix ALC260 hp3013 master switch +Patch-mainline: +References: bnc#441068 + +The master switch doesn't influence on NID 0x15, the headphone jack +on HP 3013 model because alc260_hp_master_update() ignores the passed +arguments. + +Also, corrected the wrong arguments of hp3013 (0x10 and 0x15) although +this doesn't change any behavior. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -4159,13 +4159,13 @@ static void alc260_hp_master_update(stru + struct alc_spec *spec = codec->spec; + unsigned int val = spec->master_sw ? PIN_HP : 0; + /* change HP and line-out pins */ +- snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + val); +- snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + val); + /* mono (speaker) depending on the HP jack sense */ + val = (val && !spec->jack_present) ? PIN_OUT : 0; +- snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + val); + } + +@@ -4244,7 +4244,7 @@ static struct snd_kcontrol_new alc260_hp + .info = snd_ctl_boolean_mono_info, + .get = alc260_hp_master_sw_get, + .put = alc260_hp_master_sw_put, +- .private_value = (0x10 << 16) | (0x15 << 8) | 0x11 ++ .private_value = (0x15 << 16) | (0x10 << 8) | 0x11 + }, + HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), +@@ -4297,7 +4297,7 @@ static void alc260_hp_3013_automute(stru + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; +- alc260_hp_master_update(codec, 0x10, 0x15, 0x11); ++ alc260_hp_master_update(codec, 0x15, 0x10, 0x11); + } + + static void alc260_hp_3013_unsol_event(struct hda_codec *codec, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv4-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv4-quirk new file mode 100644 index 000000000..ba57d0225 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv4-quirk @@ -0,0 +1,29 @@ +From e0c0e943af71c0f840a1f6a32a8cf0b61ebc61e5 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 22 Jan 2009 12:58:11 +0100 +Subject: ALSA: hda - Add model entry for HP dv4 +Patch-mainline: +References: + +Added model=hp-dv5 for HP dv4 (103c:30f7). + +Reference: kernel bug #12440 + http://bugzilla.kernel.org/show_bug.cgi?id=12440 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1788,6 +1788,8 @@ static struct snd_pci_quirk stac92hd71bx + "HP dv5", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, + "HP dv7", STAC_HP_M4), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7, ++ "HP dv4", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, + "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv5-mic-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv5-mic-fix new file mode 100644 index 000000000..4ae5f2272 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv5-mic-fix @@ -0,0 +1,54 @@ +From 1b0652eb588e57c3ab230e0291e7da99c7e665e0 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 14 Jan 2009 08:27:35 +0100 +Subject: ALSA: hda - Fix HP dv5 mic input +Patch-mainline: 2.6.29-rc1 +References: bnc#462913 + +Fix HP dv5 (103c:3603) built-in mic input. + +Reference: kernel bug 12440 + http://bugzilla.kernel.org/show_bug.cgi?id=12440 + +Signed-off-by: Takashi Iwai +Cc: stable@kernel.org + +--- + sound/pci/hda/patch_sigmatel.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -90,6 +90,7 @@ enum { + STAC_DELL_M4_2, + STAC_DELL_M4_3, + STAC_HP_M4, ++ STAC_HP_DV5, + STAC_92HD71BXX_MODELS + }; + +@@ -1762,6 +1763,7 @@ static unsigned int *stac92hd71bxx_brd_t + [STAC_DELL_M4_2] = dell_m4_2_pin_configs, + [STAC_DELL_M4_3] = dell_m4_3_pin_configs, + [STAC_HP_M4] = NULL, ++ [STAC_HP_DV5] = NULL, + }; + + static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { +@@ -1770,6 +1772,7 @@ static const char *stac92hd71bxx_models[ + [STAC_DELL_M4_2] = "dell-m4-2", + [STAC_DELL_M4_3] = "dell-m4-3", + [STAC_HP_M4] = "hp-m4", ++ [STAC_HP_DV5] = "hp-dv5", + }; + + static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { +@@ -1783,7 +1786,7 @@ static struct snd_pci_quirk stac92hd71bx + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, + "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, +- "HP dv5", STAC_HP_M4), ++ "HP dv5", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, + "unknown HP", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv5-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv5-quirk new file mode 100644 index 000000000..ad94fb9a9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv5-quirk @@ -0,0 +1,29 @@ +From dafb70ce1026d4d6ef1b16ad6996c9589bb11cce Mon Sep 17 00:00:00 2001 +From: Giuseppe Bilotta +Date: Tue, 13 Jan 2009 08:58:49 -0500 +Subject: ALSA: hda - Add quirk for another HP dv5 +Patch-mainline: 2.6.29-rc1 +References: bnc#462913 + +Add the model=hp-m4 quirk for another HP dv5 (103c:3603) +Reference: kernel bug#12440 + http://bugzilla.kernel.org/show_bug.cgi?id=12440 + +Signed-off-by: Takashi Iwai +Cc: stable@kernel.org + +--- + sound/pci/hda/patch_sigmatel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1782,6 +1782,8 @@ static struct snd_pci_quirk stac92hd71bx + "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, + "HP dv7", STAC_HP_M4), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, ++ "HP dv5", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, + "unknown HP", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv7-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv7-quirk new file mode 100644 index 000000000..4cb671523 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-dv7-quirk @@ -0,0 +1,28 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add quirk for another HP dv7 +Patch-mainline: +References: bnc#461108 + +Added the model=hp-m4 quirk for another HP dv7 (103c:30fc) with IDT +92HD71b* codec. + +Reference: Novell bnc#461108 + https://bugzilla.novell.com/show_bug.cgi?id=461108 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1719,6 +1719,8 @@ static struct snd_pci_quirk stac92hd71bx + "HP dv5", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, + "HP dv7", STAC_HP_M4), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, ++ "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, + "unknown HP", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-zenith-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-zenith-quirk new file mode 100644 index 000000000..95676a391 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp-zenith-quirk @@ -0,0 +1,30 @@ +From 67f7857ab12e9f8005ef988f0b667396e07622c2 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 5 Feb 2009 12:14:52 +0100 +Subject: ALSA: hda - Add quirk for HP zenith laptop +Patch-mainline: +References: bnc#472789 + +Added model=laptop for another HP laptop (103c:3072) with AD1984A codec. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3905,6 +3905,12 @@ static struct snd_pci_quirk ad1884a_cfg_ + SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3072, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3073, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3076, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3077, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3079, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x307a, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp2230s-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp2230s-quirk new file mode 100644 index 000000000..81e2419c6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp2230s-quirk @@ -0,0 +1,27 @@ +From d5337debacc00591b3f81fc3c982b40af7de1ab6 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 7 Jan 2009 11:41:57 +0100 +Subject: ALSA: hda - Add quirk for HP 2230s +Patch-mainline: +References: bnc#461660 + +Added a quirk for HP 2230s, model=laptop, with AD1984A codec. +Reference: Novell bnc#461660 + https://bugzilla.novell.com/show_bug.cgi?id=461660 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3903,6 +3903,7 @@ static const char *ad1884a_models[AD1884 + + static struct snd_pci_quirk ad1884a_cfg_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp6530b-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp6530b-quirk new file mode 100644 index 000000000..3189a4c41 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-hp6530b-quirk @@ -0,0 +1,21 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add quirk for HP 6530b +Patch-mainline: +References: bnc#479617 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3913,6 +3913,7 @@ + SND_PCI_QUIRK(0x103c, 0x307a, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), ++ SND_PCI_QUIRK(0x103c, 0x360d, "HP 6530b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), + {} diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-idt92hd83-fix-typo b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-idt92hd83-fix-typo new file mode 100644 index 000000000..9c425ca7f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-idt92hd83-fix-typo @@ -0,0 +1,27 @@ +From f9d088b2080b476c86f8ddbc274851b89668c6d7 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 13 Jan 2009 11:54:49 +0100 +Subject: ALSA: hda - Fix a typo +Patch-mainline: 2.6.29-rc1 +References: + +Fix a typo in stac92hd83xxx_cfg_tbl[]. The actual number is identical +thus there is no behavior change. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1729,7 +1729,7 @@ static const char *stac92hd83xxx_models[ + static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, +- "DFI LanParty", STAC_92HD71BXX_REF), ++ "DFI LanParty", STAC_92HD83XXX_REF), + {} /* terminator */ + }; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-intel-d945-ref-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-intel-d945-ref-quirk new file mode 100644 index 000000000..72443624a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-intel-d945-ref-quirk @@ -0,0 +1,30 @@ +From 8056d47e77a0f7e3c99c114deab4859d31496075 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 23 Jan 2009 09:09:43 +0100 +Subject: ALSA: hda - Add model=ref for Intel board with STAC9221 +Patch-mainline: +References: bnc#406529 + +An intel board (8086:0204) works only with model=ref. + +Reference: Novell bug #406529 + https://bugzilla.novell.com/show_bug.cgi?id=406529 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -2028,6 +2028,9 @@ static struct snd_pci_quirk stac922x_cfg + "Intel D945P", STAC_D945GTP3), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707, + "Intel D945P", STAC_D945GTP5), ++ /* other intel */ ++ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204, ++ "Intel D945", STAC_D945_REF), + /* other systems */ + /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */ + SND_PCI_QUIRK(0x8384, 0x7680, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-nvidia-hdmi b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-nvidia-hdmi new file mode 100644 index 000000000..221dc7064 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-nvidia-hdmi @@ -0,0 +1,232 @@ +From: Takashi Iwai +Subject: ALSA: hda - Nvidia HDMI codec support +Patch-mainline: 2.6.28-rc1 +References: + +Add the minimal support of Nvidia HDMI codec. + +Signed-off-by: Takashi Iwai + +--- +--- + sound/pci/Kconfig | 8 ++ + sound/pci/hda/Makefile | 1 + sound/pci/hda/hda_codec.c | 3 + sound/pci/hda/hda_patch.h | 2 + sound/pci/hda/patch_nvhdmi.c | 165 +++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 179 insertions(+) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -94,6 +94,9 @@ static const struct hda_codec_preset *hd + #ifdef CONFIG_SND_HDA_CODEC_VIA + snd_hda_preset_via, + #endif ++#ifdef CONFIG_SND_HDA_CODEC_NVHDMI ++ snd_hda_preset_nvhdmi, ++#endif + NULL + }; + +--- a/sound/pci/hda/hda_patch.h ++++ b/sound/pci/hda/hda_patch.h +@@ -18,3 +18,5 @@ extern struct hda_codec_preset snd_hda_p + extern struct hda_codec_preset snd_hda_preset_conexant[]; + /* VIA codecs */ + extern struct hda_codec_preset snd_hda_preset_via[]; ++/* NVIDIA HDMI codecs */ ++extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; +--- a/sound/pci/hda/Makefile ++++ b/sound/pci/hda/Makefile +@@ -15,5 +15,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3 + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o ++snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o + + obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o +--- /dev/null ++++ b/sound/pci/hda/patch_nvhdmi.c +@@ -0,0 +1,165 @@ ++/* ++ * Universal Interface for Intel High Definition Audio Codec ++ * ++ * HD audio interface patch for NVIDIA HDMI codecs ++ * ++ * Copyright (c) 2008 NVIDIA Corp. All rights reserved. ++ * Copyright (c) 2008 Wei Ni ++ * ++ * ++ * This driver is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This driver is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include "hda_codec.h" ++#include "hda_local.h" ++ ++struct nvhdmi_spec { ++ struct hda_multi_out multiout; ++ ++ struct hda_pcm pcm_rec; ++}; ++ ++static struct hda_verb nvhdmi_basic_init[] = { ++ /* enable digital output on pin widget */ ++ { 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, ++ {} /* terminator */ ++}; ++ ++/* ++ * Controls ++ */ ++static int nvhdmi_build_controls(struct hda_codec *codec) ++{ ++ struct nvhdmi_spec *spec = codec->spec; ++ int err; ++ ++ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int nvhdmi_init(struct hda_codec *codec) ++{ ++ snd_hda_sequence_write(codec, nvhdmi_basic_init); ++ return 0; ++} ++ ++/* ++ * Digital out ++ */ ++static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ struct snd_pcm_substream *substream) ++{ ++ struct nvhdmi_spec *spec = codec->spec; ++ return snd_hda_multi_out_dig_open(codec, &spec->multiout); ++} ++ ++static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ struct snd_pcm_substream *substream) ++{ ++ struct nvhdmi_spec *spec = codec->spec; ++ return snd_hda_multi_out_dig_close(codec, &spec->multiout); ++} ++ ++static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ unsigned int stream_tag, ++ unsigned int format, ++ struct snd_pcm_substream *substream) ++{ ++ struct nvhdmi_spec *spec = codec->spec; ++ return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, ++ format, substream); ++} ++ ++static struct hda_pcm_stream nvhdmi_pcm_digital_playback = { ++ .substreams = 1, ++ .channels_min = 2, ++ .channels_max = 2, ++ .nid = 0x4, /* NID to query formats and rates and setup streams */ ++ .rates = SNDRV_PCM_RATE_48000, ++ .maxbps = 16, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ .ops = { ++ .open = nvhdmi_dig_playback_pcm_open, ++ .close = nvhdmi_dig_playback_pcm_close, ++ .prepare = nvhdmi_dig_playback_pcm_prepare ++ }, ++}; ++ ++static int nvhdmi_build_pcms(struct hda_codec *codec) ++{ ++ struct nvhdmi_spec *spec = codec->spec; ++ struct hda_pcm *info = &spec->pcm_rec; ++ ++ codec->num_pcms = 1; ++ codec->pcm_info = info; ++ ++ info->name = "NVIDIA HDMI"; ++ info->pcm_type = HDA_PCM_TYPE_HDMI; ++ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback; ++ ++ return 0; ++} ++ ++static void nvhdmi_free(struct hda_codec *codec) ++{ ++ kfree(codec->spec); ++} ++ ++static struct hda_codec_ops nvhdmi_patch_ops = { ++ .build_controls = nvhdmi_build_controls, ++ .build_pcms = nvhdmi_build_pcms, ++ .init = nvhdmi_init, ++ .free = nvhdmi_free, ++}; ++ ++static int patch_nvhdmi(struct hda_codec *codec) ++{ ++ struct nvhdmi_spec *spec; ++ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ codec->spec = spec; ++ ++ spec->multiout.num_dacs = 0; /* no analog */ ++ spec->multiout.max_channels = 2; ++ spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital, ++ * seems to be unused in pure-digital ++ * case. */ ++ ++ codec->patch_ops = nvhdmi_patch_ops; ++ ++ return 0; ++} ++ ++/* ++ * patch entries ++ */ ++struct hda_codec_preset snd_hda_preset_nvhdmi[] = { ++ { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, ++ { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, ++ {} /* terminator */ ++}; +--- a/sound/pci/Kconfig ++++ b/sound/pci/Kconfig +@@ -565,6 +565,14 @@ config SND_HDA_CODEC_ATIHDMI + Say Y here to include ATI HDMI HD-audio codec support in + snd-hda-intel driver, such as ATI RS600 HDMI. + ++config SND_HDA_CODEC_NVHDMI ++ bool "Build NVIDIA HDMI HD-audio codec support" ++ depends on SND_HDA_INTEL ++ default y ++ help ++ Say Y here to include NVIDIA HDMI HD-audio codec support in ++ snd-hda-intel driver, such as NVIDIA MCP78 HDMI. ++ + config SND_HDA_CODEC_CONEXANT + bool "Build Conexant HD-audio codec support" + depends on SND_HDA_INTEL diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-probe-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-probe-fix new file mode 100644 index 000000000..0e65493ba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-probe-fix @@ -0,0 +1,102 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix and clean-up codec-probing +Patch-mainline: 2.6.28-rc1 +References: + +Fixed and cleaned up the codec-probing code. The 4th slot is used +for HDMI on some devices, and this patch allows to probe it as well. + +Signed-off-by: Takashi Iwai + +--- +--- + sound/pci/hda/hda_intel.c | 41 +++++++++++++++++++++++++++-------------- + 1 file changed, 27 insertions(+), 14 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -223,9 +223,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO + #define RIRB_INT_OVERRUN 0x04 + #define RIRB_INT_MASK 0x05 + +-/* STATESTS int mask: SD2,SD1,SD0 */ +-#define AZX_MAX_CODECS 3 +-#define STATESTS_INT_MASK 0x07 ++/* STATESTS int mask: S3,SD2,SD1,SD0 */ ++#define AZX_MAX_CODECS 4 ++#define STATESTS_INT_MASK 0x0f + + /* SD_CTL bits */ + #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ +@@ -402,6 +402,7 @@ enum { + AZX_DRIVER_ULI, + AZX_DRIVER_NVIDIA, + AZX_DRIVER_TERA, ++ AZX_NUM_DRIVERS, /* keep this as last entry */ + }; + + static char *driver_short_names[] __devinitdata = { +@@ -1173,23 +1174,26 @@ static int azx_setup_controller(struct a + * Codec initialization + */ + +-static unsigned int azx_max_codecs[] __devinitdata = { +- [AZX_DRIVER_ICH] = 4, /* Some ICH9 boards use SD3 */ +- [AZX_DRIVER_SCH] = 3, +- [AZX_DRIVER_ATI] = 4, +- [AZX_DRIVER_ATIHDMI] = 4, +- [AZX_DRIVER_VIA] = 3, /* FIXME: correct? */ +- [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ +- [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ +- [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ ++/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ ++static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { + [AZX_DRIVER_TERA] = 1, + }; + ++/* number of slots to probe as default ++ * this can be different from azx_max_codecs[] -- e.g. some boards ++ * report wrongly the non-existing 4th slot availability ++ */ ++static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = { ++ [AZX_DRIVER_ICH] = 3, ++ [AZX_DRIVER_ATI] = 3, ++}; ++ + static int __devinit azx_codec_create(struct azx *chip, const char *model, + unsigned int codec_probe_mask) + { + struct hda_bus_template bus_temp; + int c, codecs, audio_codecs, err; ++ int def_slots, max_slots; + + memset(&bus_temp, 0, sizeof(bus_temp)); + bus_temp.private_data = chip; +@@ -1205,8 +1209,17 @@ static int __devinit azx_codec_create(st + if (err < 0) + return err; + ++ if (chip->driver_type == AZX_DRIVER_NVIDIA) ++ chip->bus->needs_damn_long_delay = 1; ++ + codecs = audio_codecs = 0; +- for (c = 0; c < AZX_MAX_CODECS; c++) { ++ max_slots = azx_max_codecs[chip->driver_type]; ++ if (!max_slots) ++ max_slots = AZX_MAX_CODECS; ++ def_slots = azx_default_codecs[chip->driver_type]; ++ if (!def_slots) ++ def_slots = max_slots; ++ for (c = 0; c < def_slots; c++) { + if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { + struct hda_codec *codec; + err = snd_hda_codec_new(chip->bus, c, &codec); +@@ -1219,7 +1232,7 @@ static int __devinit azx_codec_create(st + } + if (!audio_codecs) { + /* probe additional slots if no codec is found */ +- for (; c < azx_max_codecs[chip->driver_type]; c++) { ++ for (; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { + err = snd_hda_codec_new(chip->bus, c, NULL); + if (err < 0) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-proc-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-proc-fix new file mode 100644 index 000000000..e2a7f02ee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-proc-fix @@ -0,0 +1,58 @@ +From: Takashi Iwai +Subject: ALSA: hda - Misc fixes on proc output +Patch-mainline: 2.6.28-rc1 +References: + +Misc fixes and additions for codec#* proc output. + +Signed-off-by: Takashi Iwai + +--- +--- + sound/pci/hda/hda_proc.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +--- a/sound/pci/hda/hda_proc.c ++++ b/sound/pci/hda/hda_proc.c +@@ -229,6 +229,13 @@ static void print_pin_caps(struct snd_in + snd_iprintf(buffer, " Detect"); + if (caps & AC_PINCAP_BALANCE) + snd_iprintf(buffer, " Balanced"); ++ if (caps & AC_PINCAP_HDMI) { ++ /* Realtek uses this bit as a different meaning */ ++ if ((codec->vendor_id >> 16) == 0x10ec) ++ snd_iprintf(buffer, " R/L"); ++ else ++ snd_iprintf(buffer, " HDMI"); ++ } + if (caps & AC_PINCAP_LR_SWAP) + snd_iprintf(buffer, " R/L"); + if (caps & AC_PINCAP_TRIG_REQ) +@@ -552,9 +559,15 @@ static void print_codec_info(struct snd_ + + snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, + get_wid_type_name(wid_type), wid_caps); +- if (wid_caps & AC_WCAP_STEREO) +- snd_iprintf(buffer, " Stereo"); +- else ++ if (wid_caps & AC_WCAP_STEREO) { ++ unsigned int chans; ++ chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13; ++ chans = ((chans << 1) | 1) + 1; ++ if (chans == 2) ++ snd_iprintf(buffer, " Stereo"); ++ else ++ snd_iprintf(buffer, " %d-Channels", chans); ++ } else + snd_iprintf(buffer, " Mono"); + if (wid_caps & AC_WCAP_DIGITAL) + snd_iprintf(buffer, " Digital"); +@@ -566,6 +579,8 @@ static void print_codec_info(struct snd_ + snd_iprintf(buffer, " Stripe"); + if (wid_caps & AC_WCAP_LR_SWAP) + snd_iprintf(buffer, " R/L"); ++ if (wid_caps & AC_WCAP_CP_CAPS) ++ snd_iprintf(buffer, " CP"); + snd_iprintf(buffer, "\n"); + + /* volume knob is a special widget that always have connection diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-proc-gpio-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-proc-gpio-fix new file mode 100644 index 000000000..aab1e700e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-proc-gpio-fix @@ -0,0 +1,25 @@ +From: Takashi Iwai +Subject: ALSA: hda - Limit the number of GPIOs show in proc +Patch-mainline: 2.6.28-rc4 +References: + +Limit the number of GPIOs shown in proc. Otherwise it gets too long +unnecessarily, and hard to analyze. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_proc.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/hda_proc.c ++++ b/sound/pci/hda/hda_proc.c +@@ -485,6 +485,8 @@ static void print_gpio(struct snd_info_b + (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0, + (gpio & AC_GPIO_WAKE) ? 1 : 0); + max = gpio & AC_GPIO_IO_COUNT; ++ if (!max || max > 8) ++ return; + enable = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_GPIO_MASK, 0); + direction = snd_hda_codec_read(codec, nid, 0, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-acer-dmic b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-acer-dmic new file mode 100644 index 000000000..c376153ce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-acer-dmic @@ -0,0 +1,113 @@ +From: Takashi Iwai +Subject: ALSA: hda - Split ALC268 acer model +Patch-mainline: +References: bnc#420048 + +There are actually two variants of ALC268 Acer implementation, one +with an analog built-in mic (pin 0x19) and another with a digital +mic (pin 0x12). Created a new model, acer-dmic, for the latter case +now. + +So far, all known models are assigned to be analog-mic, according to +the BIOS setup. If this doesn't match with the actual case, one needs +to try model=acer-dmic, and fix the entry to point ALC268_ACER_DMIC +if it works. + +Signed-off-by: Takashi Iwai + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 44 ++++++++++++++++++++++++ + 2 files changed, 45 insertions(+) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -844,6 +844,7 @@ Prior to version 0.9.0rc4 options had a + 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops ++ acer-dmic Acer laptops with digital-mic + acer-aspire Acer Aspire One + dell Dell OEM laptops (Vostro 1200) + zepto Zepto laptops +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -114,6 +114,7 @@ enum { + ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, ++ ALC268_ACER_DMIC, + ALC268_ACER_ASPIRE_ONE, + ALC268_DELL, + ALC268_ZEPTO, +@@ -10948,6 +10949,22 @@ static struct snd_kcontrol_new alc268_ac + { } + }; + ++static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { ++ /* output mixer control */ ++ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = snd_hda_mixer_amp_switch_info, ++ .get = snd_hda_mixer_amp_switch_get, ++ .put = alc268_acer_master_sw_put, ++ .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ }, ++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), ++ { } ++}; ++ + static struct hda_verb alc268_acer_aspire_one_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, +@@ -11280,6 +11297,15 @@ static struct hda_input_mux alc268_acer_ + .num_items = 3, + .items = { + { "Mic", 0x0 }, ++ { "Internal Mic", 0x1 }, ++ { "Line", 0x2 }, ++ }, ++}; ++ ++static struct hda_input_mux alc268_acer_dmic_capture_source = { ++ .num_items = 3, ++ .items = { ++ { "Mic", 0x0 }, + { "Internal Mic", 0x6 }, + { "Line", 0x2 }, + }, +@@ -11560,6 +11586,7 @@ static const char *alc268_models[ALC268_ + [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", ++ [ALC268_ACER_DMIC] = "acer-dmic", + [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", + [ALC268_DELL] = "dell", + [ALC268_ZEPTO] = "zepto", +@@ -11655,6 +11682,23 @@ static struct alc_config_preset alc268_p + .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, + }, ++ [ALC268_ACER_DMIC] = { ++ .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, ++ alc268_beep_mixer }, ++ .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, ++ alc268_acer_verbs }, ++ .num_dacs = ARRAY_SIZE(alc268_dac_nids), ++ .dac_nids = alc268_dac_nids, ++ .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), ++ .adc_nids = alc268_adc_nids_alt, ++ .capsrc_nids = alc268_capsrc_nids, ++ .hp_nid = 0x02, ++ .num_channel_mode = ARRAY_SIZE(alc268_modes), ++ .channel_mode = alc268_modes, ++ .input_mux = &alc268_acer_dmic_capture_source, ++ .unsol_event = alc268_acer_unsol_event, ++ .init_hook = alc268_acer_init_hook, ++ }, + [ALC268_ACER_ASPIRE_ONE] = { + .mixers = { alc268_acer_aspire_one_mixer, + alc268_capture_alt_mixer }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-alc269-dmic b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-alc269-dmic new file mode 100644 index 000000000..1c70ee66a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-alc269-dmic @@ -0,0 +1,45 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add digital-mic for ALC269 auto-probe mode +Patch-mainline: +References: bnc#440626 + +The digital mic wasn't detected properly for ALC269 auto-probing mode +because of its widget number. Fixed now. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -12250,8 +12250,26 @@ static int alc269_auto_create_multi_out_ + return 0; + } + +-#define alc269_auto_create_analog_input_ctls \ +- alc880_auto_create_analog_input_ctls ++static int alc269_auto_create_analog_input_ctls(struct alc_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ int err; ++ ++ err = alc880_auto_create_analog_input_ctls(spec, cfg); ++ if (err < 0) ++ return err; ++ /* digital-mic input pin is excluded in alc880_auto_create..() ++ * because it's under 0x18 ++ */ ++ if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || ++ cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { ++ struct hda_input_mux *imux = &spec->private_imux; ++ imux->items[imux->num_items].label = "Int Mic"; ++ imux->items[imux->num_items].index = 0x05; ++ imux->num_items++; ++ } ++ return 0; ++} + + #ifdef CONFIG_SND_HDA_POWER_SAVE + #define alc269_loopbacks alc880_loopbacks diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-mic-automute-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-mic-automute-fix new file mode 100644 index 000000000..350b3e86f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-mic-automute-fix @@ -0,0 +1,54 @@ +From: Takashi Iwai +Subject: ALSA: hda - Disable broken mic auto-muting in Realtek codes +Patch-mainline: +References: bnc#440626 + +The recent addition of automatic mic-muting is broken in some cases. +The code assumes that the pin nids <= 0x18, but the digital pins can +be less than 0x18. +Also, it assumes the front-mic being the internal mic, but it depends +on the hardware implementation actually. + +Instead of complex case-fixes, better to disable the code as now. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -829,6 +829,7 @@ static void alc_sku_automute(struct hda_ + spec->jack_present ? 0 : PIN_OUT); + } + ++#if 0 /* it's broken in some acses -- temporarily disabled */ + static void alc_mic_automute(struct hda_codec *codec) + { + struct alc_spec *spec = codec->spec; +@@ -849,6 +850,9 @@ static void alc_mic_automute(struct hda_ + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + } ++#else ++#define alc_mic_automute(codec) /* NOP */ ++#endif /* disabled */ + + /* unsolicited event for HP jack sensing */ + static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) +@@ -1060,12 +1064,14 @@ do_sku: + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_HP_EVENT); + ++#if 0 /* it's broken in some acses -- temporarily disabled */ + if (spec->autocfg.input_pins[AUTO_PIN_MIC] && + spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]) + snd_hda_codec_write(codec, + spec->autocfg.input_pins[AUTO_PIN_MIC], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_MIC_EVENT); ++#endif /* disabled */ + + spec->unsol_event = alc_sku_unsol_event; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-update new file mode 100644 index 000000000..35b799c7f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-realtek-update @@ -0,0 +1,3201 @@ +From: Takashi Iwai +Subject: ALSA: hda - Realtek codec updates +Patch-mainline: 2.6.28-rc1 +References: bnc#418181, bnc#417736, bnc#399289, bnc#341339 + +A pile of updates for Realtek codecs: +- DC7600 model +- ALC262 Toshiba laptop fixes +- Acer Aspire-one support +- Support of ALC66x ASUS boards +- Support of ALC883 Lenovo and ASUS boards +- Fix ALC260 auto-probe bugs +- Fix resume with a broken BIOS + +Signed-off-by: Takashi Iwai + +--- +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 17 + sound/pci/hda/patch_realtek.c | 1881 ++++++++++++++++++++---- + 2 files changed, 1660 insertions(+), 238 deletions(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -809,6 +809,7 @@ Prior to version 0.9.0rc4 options had a + ALC260 + hp HP machines + hp-3013 HP machines (3013-variant) ++ hp-dc7600 HP DC7600 + fujitsu Fujitsu S7020 + acer Acer TravelMate + will Will laptops (PB V7900) +@@ -830,8 +831,11 @@ Prior to version 0.9.0rc4 options had a + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection + sony-assamd Sony ASSAMD ++ toshiba-s06 Toshiba S06 ++ toshiba-rx1 Toshiba RX1 + ultra Samsung Q1 Ultra Vista model + lenovo-3000 Lenovo 3000 y410 ++ nec NEC Versa S9100 + basic fixed pin assignment w/o SPDIF + auto auto-config reading BIOS (default) + +@@ -840,6 +844,7 @@ Prior to version 0.9.0rc4 options had a + 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops ++ acer-aspire Acer Aspire One + dell Dell OEM laptops (Vostro 1200) + zepto Zepto laptops + test for testing/debugging purpose, almost all controls can +@@ -849,6 +854,9 @@ Prior to version 0.9.0rc4 options had a + + ALC269 + basic Basic preset ++ quanta Quanta FL1 ++ eeepc-p703 ASUS Eeepc P703 P900A ++ eeepc-p901 ASUS Eeepc P901 S101 + + ALC662/663 + 3stack-dig 3-stack (2-channel) with SPDIF +@@ -858,10 +866,17 @@ Prior to version 0.9.0rc4 options had a + lenovo-101e Lenovo laptop + eeepc-p701 ASUS Eeepc P701 + eeepc-ep20 ASUS Eeepc EP20 ++ ecs ECS/Foxconn mobo + m51va ASUS M51VA + g71v ASUS G71V + h13 ASUS H13 + g50v ASUS G50V ++ asus-mode1 ASUS ++ asus-mode2 ASUS ++ asus-mode3 ASUS ++ asus-mode4 ASUS ++ asus-mode5 ASUS ++ asus-mode6 ASUS + auto auto-config reading BIOS (default) + + ALC882/885 +@@ -893,12 +908,14 @@ Prior to version 0.9.0rc4 options had a + lenovo-101e Lenovo 101E + lenovo-nb0763 Lenovo NB0763 + lenovo-ms7195-dig Lenovo MS7195 ++ lenovo-sky Lenovo Sky + haier-w66 Haier W66 + 3stack-hp HP machines with 3stack (Lucknow, Samba boards) + 6stack-dell Dell machines with 6stack (Inspiron 530) + mitac Mitac 8252D + clevo-m720 Clevo M720 laptop series + fujitsu-pi2515 Fujitsu AMILO Pi2515 ++ 3stack-6ch-intel Intel DG33* boards + auto auto-config reading BIOS (default) + + ALC861/660 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -72,6 +72,7 @@ enum { + enum { + ALC260_BASIC, + ALC260_HP, ++ ALC260_HP_DC7600, + ALC260_HP_3013, + ALC260_FUJITSU_S702X, + ALC260_ACER, +@@ -101,6 +102,8 @@ enum { + ALC262_ULTRA, + ALC262_LENOVO_3000, + ALC262_NEC, ++ ALC262_TOSHIBA_S06, ++ ALC262_TOSHIBA_RX1, + ALC262_AUTO, + ALC262_MODEL_LAST /* last tag */ + }; +@@ -111,6 +114,7 @@ enum { + ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, ++ ALC268_ACER_ASPIRE_ONE, + ALC268_DELL, + ALC268_ZEPTO, + #ifdef CONFIG_SND_DEBUG +@@ -123,6 +127,7 @@ enum { + /* ALC269 models */ + enum { + ALC269_BASIC, ++ ALC269_QUANTA_FL1, + ALC269_ASUS_EEEPC_P703, + ALC269_ASUS_EEEPC_P901, + ALC269_AUTO, +@@ -170,6 +175,13 @@ enum { + ALC663_ASUS_G71V, + ALC663_ASUS_H13, + ALC663_ASUS_G50V, ++ ALC662_ECS, ++ ALC663_ASUS_MODE1, ++ ALC662_ASUS_MODE2, ++ ALC663_ASUS_MODE3, ++ ALC663_ASUS_MODE4, ++ ALC663_ASUS_MODE5, ++ ALC663_ASUS_MODE6, + ALC662_AUTO, + ALC662_MODEL_LAST, + }; +@@ -201,18 +213,21 @@ enum { + ALC883_ACER, + ALC883_ACER_ASPIRE, + ALC883_MEDION, +- ALC883_MEDION_MD2, ++ ALC883_MEDION_MD2, + ALC883_LAPTOP_EAPD, + ALC883_LENOVO_101E_2ch, + ALC883_LENOVO_NB0763, + ALC888_LENOVO_MS7195_DIG, +- ALC883_HAIER_W66, ++ ALC888_LENOVO_SKY, ++ ALC883_HAIER_W66, + ALC888_3ST_HP, + ALC888_6ST_DELL, + ALC883_MITAC, + ALC883_CLEVO_M720, + ALC883_FUJITSU_PI2515, + ALC883_3ST_6ch_INTEL, ++ ALC888_ASUS_M90V, ++ ALC888_ASUS_EEE1601, + ALC883_AUTO, + ALC883_MODEL_LAST, + }; +@@ -406,7 +421,7 @@ static int alc_ch_mode_put(struct snd_kc + + /* + * Control the mode of pin widget settings via the mixer. "pc" is used +- * instead of "%" to avoid consequences of accidently treating the % as ++ * instead of "%" to avoid consequences of accidently treating the % as + * being part of a format specifier. Maximum allowed length of a value is + * 63 characters plus NULL terminator. + * +@@ -437,7 +452,7 @@ static unsigned char alc_pin_mode_values + #define ALC_PIN_DIR_IN_NOMICBIAS 0x03 + #define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04 + +-/* Info about the pin modes supported by the different pin direction modes. ++/* Info about the pin modes supported by the different pin direction modes. + * For each direction the minimum and maximum values are given. + */ + static signed char alc_pin_mode_dir_info[5][2] = { +@@ -510,7 +525,7 @@ static int alc_pin_mode_put(struct snd_k + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); + +- /* Also enable the retasking pin's input/output as required ++ /* Also enable the retasking pin's input/output as required + * for the requested pin mode. Enum values of 2 or less are + * input modes. + * +@@ -715,7 +730,7 @@ static void setup_preset(struct alc_spec + i++) + spec->init_verbs[spec->num_init_verbs++] = + preset->init_verbs[i]; +- ++ + spec->channel_mode = preset->channel_mode; + spec->num_channel_mode = preset->num_channel_mode; + spec->need_dac_fix = preset->need_dac_fix; +@@ -726,7 +741,7 @@ static void setup_preset(struct alc_spec + spec->multiout.dac_nids = preset->dac_nids; + spec->multiout.dig_out_nid = preset->dig_out_nid; + spec->multiout.hp_nid = preset->hp_nid; +- ++ + spec->num_mux_defs = preset->num_mux_defs; + if (!spec->num_mux_defs) + spec->num_mux_defs = 1; +@@ -814,6 +829,27 @@ static void alc_sku_automute(struct hda_ + spec->jack_present ? 0 : PIN_OUT); + } + ++static void alc_mic_automute(struct hda_codec *codec) ++{ ++ struct alc_spec *spec = codec->spec; ++ unsigned int present; ++ unsigned int mic_nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; ++ unsigned int fmic_nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; ++ unsigned int mix_nid = spec->capsrc_nids[0]; ++ unsigned int capsrc_idx_mic, capsrc_idx_fmic; ++ ++ capsrc_idx_mic = mic_nid - 0x18; ++ capsrc_idx_fmic = fmic_nid - 0x18; ++ present = snd_hda_codec_read(codec, mic_nid, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, ++ 0x7000 | (capsrc_idx_mic << 8) | (present ? 0 : 0x80)); ++ snd_hda_codec_write(codec, mix_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, ++ 0x7000 | (capsrc_idx_fmic << 8) | (present ? 0x80 : 0)); ++ snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, capsrc_idx_fmic, ++ HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); ++} ++ + /* unsolicited event for HP jack sensing */ + static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) + { +@@ -821,10 +857,17 @@ static void alc_sku_unsol_event(struct h + res >>= 28; + else + res >>= 26; +- if (res != ALC880_HP_EVENT) +- return; ++ if (res == ALC880_HP_EVENT) ++ alc_sku_automute(codec); ++ ++ if (res == ALC880_MIC_EVENT) ++ alc_mic_automute(codec); ++} + ++static void alc_inithook(struct hda_codec *codec) ++{ + alc_sku_automute(codec); ++ alc_mic_automute(codec); + } + + /* additional initialization for ALC888 variants */ +@@ -863,7 +906,7 @@ static void alc_subsystem_id(struct hda_ + if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + goto do_sku; + +- /* ++ /* + * 31~30 : port conetcivity + * 29~21 : reserve + * 20 : PCBEEP input +@@ -956,7 +999,7 @@ do_sku: + tmp = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, +- AC_VERB_SET_COEF_INDEX, 7); ++ AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x2010); +@@ -971,7 +1014,7 @@ do_sku: + tmp = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, +- AC_VERB_SET_COEF_INDEX, 7); ++ AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x3000); +@@ -980,7 +1023,7 @@ do_sku: + default: + break; + } +- ++ + /* is laptop or Desktop and enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ +@@ -1012,10 +1055,18 @@ do_sku: + else + return; + } ++ if (spec->autocfg.hp_pins[0]) ++ snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, ++ AC_VERB_SET_UNSOLICITED_ENABLE, ++ AC_USRSP_EN | ALC880_HP_EVENT); ++ ++ if (spec->autocfg.input_pins[AUTO_PIN_MIC] && ++ spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]) ++ snd_hda_codec_write(codec, ++ spec->autocfg.input_pins[AUTO_PIN_MIC], 0, ++ AC_VERB_SET_UNSOLICITED_ENABLE, ++ AC_USRSP_EN | ALC880_MIC_EVENT); + +- snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, +- AC_VERB_SET_UNSOLICITED_ENABLE, +- AC_USRSP_EN | ALC880_HP_EVENT); + spec->unsol_event = alc_sku_unsol_event; + } + +@@ -1306,7 +1357,7 @@ static struct snd_kcontrol_new alc880_si + * + * The system also has a pair of internal speakers, and a headphone jack. + * These are both connected to Line2 on the codec, hence to DAC 02. +- * ++ * + * There is a variable resistor to control the speaker or headphone + * volume. This is a hardware-only device without a software API. + * +@@ -1834,7 +1885,7 @@ static struct hda_verb alc880_pin_6stack + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +- ++ + { } + }; + +@@ -1879,7 +1930,7 @@ static struct hda_verb alc880_uniwill_in + + /* + * Uniwill P53 +-* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, ++* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19, + */ + static struct hda_verb alc880_uniwill_p53_init_verbs[] = { + {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ +@@ -1978,7 +2029,7 @@ static void alc880_uniwill_p53_hp_automu + static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; +@@ -2060,7 +2111,7 @@ static struct hda_verb alc880_pin_asus_i + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +- ++ + { } + }; + +@@ -2677,6 +2728,8 @@ static int alc_build_pcms(struct hda_cod + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } ++ /* FIXME: do we need this for all Realtek codec models? */ ++ codec->spdif_status_reset = 1; + } + + /* If the use of more than one ADC is requested for the current +@@ -3754,7 +3807,7 @@ static void alc880_auto_init_multi_out(s + { + struct alc_spec *spec = codec->spec; + int i; +- ++ + alc_subsystem_id(codec, 0x15, 0x1b, 0x14); + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; +@@ -3859,7 +3912,7 @@ static void alc880_auto_init(struct hda_ + alc880_auto_init_extra_out(codec); + alc880_auto_init_analog_input(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + /* +@@ -4196,6 +4249,33 @@ static struct snd_kcontrol_new alc260_hp + { } /* end */ + }; + ++static struct hda_bind_ctls alc260_dc7600_bind_master_vol = { ++ .ops = &snd_hda_bind_vol, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct hda_bind_ctls alc260_dc7600_bind_switch = { ++ .ops = &snd_hda_bind_sw, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol), ++ HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch), ++ HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), ++ { } /* end */ ++}; ++ + static struct hda_verb alc260_hp_3013_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {}, +@@ -4219,7 +4299,30 @@ static void alc260_hp_3013_unsol_event(s + alc260_hp_3013_automute(codec); + } + +-/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, ++static void alc260_hp_3012_automute(struct hda_codec *codec) ++{ ++ unsigned int present, bits; ++ ++ present = snd_hda_codec_read(codec, 0x10, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE; ++ ++ bits = present ? 0 : PIN_OUT; ++ snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++ snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++ snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++} ++ ++static void alc260_hp_3012_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ if ((res >> 26) == ALC880_HP_EVENT) ++ alc260_hp_3012_automute(codec); ++} ++ ++/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, + * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. + */ + static struct snd_kcontrol_new alc260_fujitsu_mixer[] = { +@@ -4550,7 +4653,7 @@ static struct hda_verb alc260_fujitsu_in + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + +- /* Ensure Line1 pin widget takes its input from the OUT1 sum bus ++ /* Ensure Line1 pin widget takes its input from the OUT1 sum bus + * when acting as an output. + */ + {0x0d, AC_VERB_SET_CONNECT_SEL, 0}, +@@ -4575,14 +4678,14 @@ static struct hda_verb alc260_fujitsu_in + * stage. + */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- /* Unmute input buffer of pin widget used for Line-in (no equiv ++ /* Unmute input buffer of pin widget used for Line-in (no equiv + * mixer ctrl) + */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +- /* Set ADC connection select to match default mixer setting - line ++ /* Set ADC connection select to match default mixer setting - line + * in (on mic1 pin) + */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, +@@ -4636,7 +4739,7 @@ static struct hda_verb alc260_acer_init_ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + +- /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum ++ /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum + * bus when acting as outputs. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, +@@ -4747,6 +4850,20 @@ static void alc260_replacer_672v_unsol_e + alc260_replacer_672v_automute(codec); + } + ++static struct hda_verb alc260_hp_dc7600_verbs[] = { ++ {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ + /* Test configuration for debugging, modelled after the ALC880 test + * configuration. + */ +@@ -4758,7 +4875,7 @@ static hda_nid_t alc260_test_adc_nids[2] + 0x04, 0x05, + }; + /* For testing the ALC260, each input MUX needs its own definition since +- * the signal assignments are different. This assumes that the first ADC ++ * the signal assignments are different. This assumes that the first ADC + * is NID 0x04. + */ + static struct hda_input_mux alc260_test_capture_sources[2] = { +@@ -4841,7 +4958,7 @@ static struct snd_kcontrol_new alc260_te + + /* Switches to allow the digital IO pins to be enabled. The datasheet + * is ambigious as to which NID is which; testing on laptops which +- * make this output available should provide clarification. ++ * make this output available should provide clarification. + */ + ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), + ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), +@@ -4877,7 +4994,7 @@ static struct hda_verb alc260_test_init_ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + +- /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the ++ /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the + * OUT1 sum bus when acting as an output. + */ + {0x0b, AC_VERB_SET_CONNECT_SEL, 0}, +@@ -4948,7 +5065,7 @@ static struct hda_verb alc260_test_init_ + */ + + static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, +- const char *pfx) ++ const char *pfx, int *vol_bits) + { + hda_nid_t nid_vol; + unsigned long vol_val, sw_val; +@@ -4969,11 +5086,15 @@ static int alc260_add_playback_controls( + sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + } else + return 0; /* N/A */ +- +- snprintf(name, sizeof(name), "%s Playback Volume", pfx); +- err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val); +- if (err < 0) +- return err; ++ ++ if (!(*vol_bits & (1 << nid_vol))) { ++ /* first control for the volume widget */ ++ snprintf(name, sizeof(name), "%s Playback Volume", pfx); ++ err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val); ++ if (err < 0) ++ return err; ++ *vol_bits |= (1 << nid_vol); ++ } + snprintf(name, sizeof(name), "%s Playback Switch", pfx); + err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val); + if (err < 0) +@@ -4987,6 +5108,7 @@ static int alc260_auto_create_multi_out_ + { + hda_nid_t nid; + int err; ++ int vols = 0; + + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; +@@ -4994,21 +5116,22 @@ static int alc260_auto_create_multi_out_ + + nid = cfg->line_out_pins[0]; + if (nid) { +- err = alc260_add_playback_controls(spec, nid, "Front"); ++ err = alc260_add_playback_controls(spec, nid, "Front", &vols); + if (err < 0) + return err; + } + + nid = cfg->speaker_pins[0]; + if (nid) { +- err = alc260_add_playback_controls(spec, nid, "Speaker"); ++ err = alc260_add_playback_controls(spec, nid, "Speaker", &vols); + if (err < 0) + return err; + } + + nid = cfg->hp_pins[0]; + if (nid) { +- err = alc260_add_playback_controls(spec, nid, "Headphone"); ++ err = alc260_add_playback_controls(spec, nid, "Headphone", ++ &vols); + if (err < 0) + return err; + } +@@ -5075,7 +5198,7 @@ static void alc260_auto_init_multi_out(s + int pin_type = get_pin_type(spec->autocfg.line_out_type); + alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0); + } +- ++ + nid = spec->autocfg.speaker_pins[0]; + if (nid) + alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); +@@ -5117,7 +5240,7 @@ static struct hda_verb alc260_volume_ini + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x05, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- ++ + /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for +@@ -5146,7 +5269,7 @@ static struct hda_verb alc260_volume_ini + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- ++ + { } + }; + +@@ -5207,7 +5330,7 @@ static void alc260_auto_init(struct hda_ + alc260_auto_init_multi_out(codec); + alc260_auto_init_analog_input(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + #ifdef CONFIG_SND_HDA_POWER_SAVE +@@ -5228,6 +5351,7 @@ static const char *alc260_models[ALC260_ + [ALC260_BASIC] = "basic", + [ALC260_HP] = "hp", + [ALC260_HP_3013] = "hp-3013", ++ [ALC260_HP_DC7600] = "hp-dc7600", + [ALC260_FUJITSU_S702X] = "fujitsu", + [ALC260_ACER] = "acer", + [ALC260_WILL] = "will", +@@ -5245,7 +5369,7 @@ static struct snd_pci_quirk alc260_cfg_t + SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), +- SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), ++ SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), + SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), + SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP), +@@ -5291,6 +5415,22 @@ static struct alc_config_preset alc260_p + .unsol_event = alc260_hp_unsol_event, + .init_hook = alc260_hp_automute, + }, ++ [ALC260_HP_DC7600] = { ++ .mixers = { alc260_hp_dc7600_mixer, ++ alc260_input_mixer, ++ alc260_capture_alt_mixer }, ++ .init_verbs = { alc260_init_verbs, ++ alc260_hp_dc7600_verbs }, ++ .num_dacs = ARRAY_SIZE(alc260_dac_nids), ++ .dac_nids = alc260_dac_nids, ++ .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), ++ .adc_nids = alc260_hp_adc_nids, ++ .num_channel_mode = ARRAY_SIZE(alc260_modes), ++ .channel_mode = alc260_modes, ++ .input_mux = &alc260_capture_source, ++ .unsol_event = alc260_hp_3012_unsol_event, ++ .init_hook = alc260_hp_3012_automute, ++ }, + [ALC260_HP_3013] = { + .mixers = { alc260_hp_3013_mixer, + alc260_input_mixer, +@@ -6006,7 +6146,7 @@ static struct hda_verb alc882_targa_verb + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +- ++ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ +@@ -6022,7 +6162,7 @@ static struct hda_verb alc882_targa_verb + static void alc882_targa_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, +@@ -6048,7 +6188,7 @@ static struct hda_verb alc882_asus_a7j_v + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +- ++ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ +@@ -6066,7 +6206,7 @@ static struct hda_verb alc882_asus_a7m_v + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +- ++ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ +@@ -6392,7 +6532,7 @@ static struct alc_config_preset alc882_p + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, +- }, ++ }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, +@@ -6405,14 +6545,14 @@ static struct alc_config_preset alc882_p + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, +- }, ++ }, + }; + + + /* + * Pin config fixes + */ +-enum { ++enum { + PINFIX_ABIT_AW9D_MAX + }; + +@@ -6600,7 +6740,7 @@ static void alc882_auto_init(struct hda_ + alc882_auto_init_analog_input(codec); + alc882_auto_init_input_src(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */ +@@ -6632,6 +6772,7 @@ static int patch_alc882(struct hda_codec + break; + case 0x106b00a0: /* MacBookPro3,1 - Another revision */ + case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ ++ case 0x106b00a4: /* MacbookPro4,1 */ + case 0x106b2c00: /* Macbook Pro rev3 */ + case 0x106b3600: /* Macbook 3.1 */ + case 0x106b3800: /* MacbookPro4,1 - latter revision */ +@@ -6795,6 +6936,23 @@ static struct hda_input_mux alc883_fujit + }, + }; + ++static struct hda_input_mux alc883_lenovo_sky_capture_source = { ++ .num_items = 3, ++ .items = { ++ { "Mic", 0x0 }, ++ { "Front Mic", 0x1 }, ++ { "Line", 0x4 }, ++ }, ++}; ++ ++static struct hda_input_mux alc883_asus_eee1601_capture_source = { ++ .num_items = 2, ++ .items = { ++ { "Mic", 0x0 }, ++ { "Line", 0x2 }, ++ }, ++}; ++ + #define alc883_mux_enum_info alc_mux_enum_info + #define alc883_mux_enum_get alc_mux_enum_get + /* ALC883 has the ALC882-type input selection */ +@@ -7109,13 +7267,11 @@ static struct snd_kcontrol_new alc883_3S + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), +- HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", +- .count = 2, ++ .count = 1, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, +@@ -7333,7 +7489,7 @@ static struct snd_kcontrol_new alc883_me + .put = alc883_mux_enum_put, + }, + { } /* end */ +-}; ++}; + + static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), +@@ -7360,6 +7516,87 @@ static struct snd_kcontrol_new alc883_ac + { } /* end */ + }; + ++static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { ++ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ++ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), ++ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), ++ HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), ++ HDA_CODEC_VOLUME_MONO("Center Playback Volume", ++ 0x0d, 1, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), ++ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), ++ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), ++ HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), ++ HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), ++ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), ++ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), ++ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), ++ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), ++ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), ++ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ /* .name = "Capture Source", */ ++ .name = "Input Source", ++ .count = 2, ++ .info = alc883_mux_enum_info, ++ .get = alc883_mux_enum_get, ++ .put = alc883_mux_enum_put, ++ }, ++ { } /* end */ ++}; ++ ++static struct hda_bind_ctls alc883_bind_cap_vol = { ++ .ops = &snd_hda_bind_vol, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), ++ HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), ++ 0 ++ }, ++}; ++ ++static struct hda_bind_ctls alc883_bind_cap_switch = { ++ .ops = &snd_hda_bind_sw, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), ++ HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), ++ 0 ++ }, ++}; ++ ++static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { ++ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ++ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), ++ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), ++ HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ /* .name = "Capture Source", */ ++ .name = "Input Source", ++ .count = 1, ++ .info = alc883_mux_enum_info, ++ .get = alc883_mux_enum_get, ++ .put = alc883_mux_enum_put, ++ }, ++ { } /* end */ ++}; ++ + static struct snd_kcontrol_new alc883_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +@@ -7373,7 +7610,7 @@ static struct snd_kcontrol_new alc883_ch + + static struct hda_verb alc883_init_verbs[] = { + /* ADC1: mute amp left and right */ +- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +@@ -7438,14 +7675,14 @@ static struct hda_verb alc883_init_verbs + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, +- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, +- {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + { } + }; + +@@ -7545,7 +7782,7 @@ static struct hda_verb alc883_tagra_verb + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +- ++ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ +@@ -7595,6 +7832,18 @@ static struct hda_verb alc883_haier_w66_ + { } /* end */ + }; + ++static struct hda_verb alc888_lenovo_sky_verbs[] = { ++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, ++ { } /* end */ ++}; ++ + static struct hda_verb alc888_3st_hp_verbs[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ +@@ -7632,7 +7881,7 @@ static struct hda_channel_mode alc888_3s + static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, +@@ -7645,7 +7894,7 @@ static void alc888_lenovo_ms7195_front_a + static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, +@@ -7675,7 +7924,7 @@ static struct hda_verb alc883_medion_md2 + static void alc883_medion_md2_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, +@@ -7830,7 +8079,7 @@ static void alc883_lenovo_101e_unsol_eve + static void alc883_acer_aspire_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, +@@ -7867,7 +8116,7 @@ static struct hda_verb alc883_acer_eapd_ + static void alc888_6st_dell_front_automute(struct hda_codec *codec) + { + unsigned int present; +- ++ + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, +@@ -7891,6 +8140,50 @@ static void alc888_6st_dell_unsol_event( + } + } + ++static void alc888_lenovo_sky_front_automute(struct hda_codec *codec) ++{ ++ unsigned int mute; ++ unsigned int present; ++ ++ snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); ++ present = snd_hda_codec_read(codec, 0x1b, 0, ++ AC_VERB_GET_PIN_SENSE, 0); ++ present = (present & 0x80000000) != 0; ++ if (present) { ++ /* mute internal speaker */ ++ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, HDA_AMP_MUTE); ++ snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, HDA_AMP_MUTE); ++ snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, HDA_AMP_MUTE); ++ snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, HDA_AMP_MUTE); ++ snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, HDA_AMP_MUTE); ++ } else { ++ /* unmute internal speaker if necessary */ ++ mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); ++ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, mute); ++ snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, mute); ++ snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, mute); ++ snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, mute); ++ snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, mute); ++ } ++} ++ ++static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ if ((res >> 26) == ALC880_HP_EVENT) ++ alc888_lenovo_sky_front_automute(codec); ++} ++ + /* + * generic initialization of ADC, input mixers and output mixers + */ +@@ -7975,16 +8268,115 @@ static struct snd_kcontrol_new alc883_ca + { } /* end */ + }; + +-#ifdef CONFIG_SND_HDA_POWER_SAVE +-#define alc883_loopbacks alc880_loopbacks +-#endif ++static struct hda_verb alc888_asus_m90v_verbs[] = { ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ /* enable unsolicited event */ ++ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, ++ { } /* end */ ++}; + +-/* pcm configuration: identiacal with ALC880 */ +-#define alc883_pcm_analog_playback alc880_pcm_analog_playback +-#define alc883_pcm_analog_capture alc880_pcm_analog_capture +-#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture +-#define alc883_pcm_digital_playback alc880_pcm_digital_playback +-#define alc883_pcm_digital_capture alc880_pcm_digital_capture ++static void alc883_nb_mic_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ ++ present = snd_hda_codec_read(codec, 0x18, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, ++ 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); ++ snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, ++ 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); ++} ++ ++static void alc883_M90V_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x1b, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ bits = present ? 0 : PIN_OUT; ++ snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++ snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++ snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++} ++ ++static void alc883_mode2_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc883_M90V_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc883_nb_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc883_mode2_inithook(struct hda_codec *codec) ++{ ++ alc883_M90V_speaker_automute(codec); ++ alc883_nb_mic_automute(codec); ++} ++ ++static struct hda_verb alc888_asus_eee1601_verbs[] = { ++ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, ++ {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, ++ {0x20, AC_VERB_SET_PROC_COEF, 0x0838}, ++ /* enable unsolicited event */ ++ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, ++ { } /* end */ ++}; ++ ++static void alc883_eee1601_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x14, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ bits = present ? 0 : PIN_OUT; ++ snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, ++ bits); ++} ++ ++static void alc883_eee1601_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc883_eee1601_speaker_automute(codec); ++ break; ++ } ++} ++ ++static void alc883_eee1601_inithook(struct hda_codec *codec) ++{ ++ alc883_eee1601_speaker_automute(codec); ++} ++ ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++#define alc883_loopbacks alc880_loopbacks ++#endif ++ ++/* pcm configuration: identiacal with ALC880 */ ++#define alc883_pcm_analog_playback alc880_pcm_analog_playback ++#define alc883_pcm_analog_capture alc880_pcm_analog_capture ++#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture ++#define alc883_pcm_digital_playback alc880_pcm_digital_playback ++#define alc883_pcm_digital_capture alc880_pcm_digital_capture + + /* + * configuration and preset +@@ -8004,6 +8396,7 @@ static const char *alc883_models[ALC883_ + [ALC883_LENOVO_101E_2ch] = "lenovo-101e", + [ALC883_LENOVO_NB0763] = "lenovo-nb0763", + [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", ++ [ALC888_LENOVO_SKY] = "lenovo-sky", + [ALC883_HAIER_W66] = "haier-w66", + [ALC888_3ST_HP] = "3stack-hp", + [ALC888_6ST_DELL] = "6stack-dell", +@@ -8020,18 +8413,21 @@ static struct snd_pci_quirk alc883_cfg_t + SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), +- SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), ++ SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ + SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), + SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), ++ SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), ++ SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), + SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), + SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), ++ SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), + SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), + SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), +@@ -8069,6 +8465,7 @@ static struct snd_pci_quirk alc883_cfg_t + SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), ++ SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY), + SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), + SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), + SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), +@@ -8209,7 +8606,7 @@ static struct alc_config_preset alc883_p + .input_mux = &alc883_capture_source, + .unsol_event = alc883_medion_md2_unsol_event, + .init_hook = alc883_medion_md2_automute, +- }, ++ }, + [ALC883_LAPTOP_EAPD] = { + .mixers = { alc883_base_mixer }, + .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, +@@ -8326,6 +8723,49 @@ static struct alc_config_preset alc883_p + .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, + .init_hook = alc883_2ch_fujitsu_pi2515_automute, + }, ++ [ALC888_LENOVO_SKY] = { ++ .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, ++ .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, ++ .num_dacs = ARRAY_SIZE(alc883_dac_nids), ++ .dac_nids = alc883_dac_nids, ++ .dig_out_nid = ALC883_DIGOUT_NID, ++ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), ++ .adc_nids = alc883_adc_nids, ++ .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), ++ .channel_mode = alc883_sixstack_modes, ++ .need_dac_fix = 1, ++ .input_mux = &alc883_lenovo_sky_capture_source, ++ .unsol_event = alc883_lenovo_sky_unsol_event, ++ .init_hook = alc888_lenovo_sky_front_automute, ++ }, ++ [ALC888_ASUS_M90V] = { ++ .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, ++ .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs }, ++ .num_dacs = ARRAY_SIZE(alc883_dac_nids), ++ .dac_nids = alc883_dac_nids, ++ .dig_out_nid = ALC883_DIGOUT_NID, ++ .dig_in_nid = ALC883_DIGIN_NID, ++ .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), ++ .channel_mode = alc883_3ST_6ch_modes, ++ .need_dac_fix = 1, ++ .input_mux = &alc883_fujitsu_pi2515_capture_source, ++ .unsol_event = alc883_mode2_unsol_event, ++ .init_hook = alc883_mode2_inithook, ++ }, ++ [ALC888_ASUS_EEE1601] = { ++ .mixers = { alc883_asus_eee1601_mixer }, ++ .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, ++ .num_dacs = ARRAY_SIZE(alc883_dac_nids), ++ .dac_nids = alc883_dac_nids, ++ .dig_out_nid = ALC883_DIGOUT_NID, ++ .dig_in_nid = ALC883_DIGIN_NID, ++ .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), ++ .channel_mode = alc883_3ST_2ch_modes, ++ .need_dac_fix = 1, ++ .input_mux = &alc883_asus_eee1601_capture_source, ++ .unsol_event = alc883_eee1601_unsol_event, ++ .init_hook = alc883_eee1601_inithook, ++ }, + }; + + +@@ -8435,7 +8875,7 @@ static void alc883_auto_init(struct hda_ + alc883_auto_init_analog_input(codec); + alc883_auto_init_input_src(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + static int patch_alc883(struct hda_codec *codec) +@@ -8479,8 +8919,13 @@ static int patch_alc883(struct hda_codec + + switch (codec->vendor_id) { + case 0x10ec0888: +- spec->stream_name_analog = "ALC888 Analog"; +- spec->stream_name_digital = "ALC888 Digital"; ++ if (codec->revision_id == 0x100101) { ++ spec->stream_name_analog = "ALC1200 Analog"; ++ spec->stream_name_digital = "ALC1200 Digital"; ++ } else { ++ spec->stream_name_analog = "ALC888 Analog"; ++ spec->stream_name_digital = "ALC888 Digital"; ++ } + break; + case 0x10ec0889: + spec->stream_name_analog = "ALC889 Analog"; +@@ -8533,6 +8978,13 @@ static int patch_alc883(struct hda_codec + #define alc262_modes alc260_modes + #define alc262_capture_source alc882_capture_source + ++static hda_nid_t alc262_dmic_adc_nids[1] = { ++ /* ADC0 */ ++ 0x09 ++}; ++ ++static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 }; ++ + static struct snd_kcontrol_new alc262_base_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), +@@ -8914,10 +9366,10 @@ static struct hda_verb alc262_init_verbs + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, +- ++ + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, +- ++ + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ +@@ -8939,6 +9391,12 @@ static struct hda_verb alc262_init_verbs + { } + }; + ++static struct hda_verb alc262_eapd_verbs[] = { ++ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, ++ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, ++ { } ++}; ++ + static struct hda_verb alc262_hippo_unsol_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, +@@ -8965,6 +9423,91 @@ static struct hda_verb alc262_sony_unsol + {} + }; + ++static struct hda_input_mux alc262_dmic_capture_source = { ++ .num_items = 2, ++ .items = { ++ { "Int DMic", 0x9 }, ++ { "Mic", 0x0 }, ++ }, ++}; ++ ++static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { ++ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ /* The multiple "Capture Source" controls confuse alsamixer ++ * So call somewhat different.. ++ */ ++ /* .name = "Capture Source", */ ++ .name = "Input Source", ++ .count = 1, ++ .info = alc_mux_enum_info, ++ .get = alc_mux_enum_get, ++ .put = alc_mux_enum_put, ++ }, ++ { } /* end */ ++}; ++ ++static struct hda_verb alc262_toshiba_s06_verbs[] = { ++ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {0x22, AC_VERB_SET_CONNECT_SEL, 0x09}, ++ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ ++static void alc262_dmic_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ ++ present = snd_hda_codec_read(codec, 0x18, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_write(codec, 0x22, 0, ++ AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); ++} ++ ++/* toggle speaker-output according to the hp-jack state */ ++static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x15, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ bits = present ? 0 : PIN_OUT; ++ snd_hda_codec_write(codec, 0x14, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, bits); ++} ++ ++ ++ ++/* unsolicited event for HP jack sensing */ ++static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ if ((res >> 26) == ALC880_HP_EVENT) ++ alc262_toshiba_s06_speaker_automute(codec); ++ if ((res >> 26) == ALC880_MIC_EVENT) ++ alc262_dmic_automute(codec); ++ ++} ++ ++static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) ++{ ++ alc262_toshiba_s06_speaker_automute(codec); ++ alc262_dmic_automute(codec); ++} ++ + /* mute/unmute internal speaker according to the hp jack and mute state */ + static void alc262_hippo_automute(struct hda_codec *codec) + { +@@ -9299,6 +9842,25 @@ static struct snd_kcontrol_new alc262_le + { } /* end */ + }; + ++static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = snd_hda_mixer_amp_switch_info, ++ .get = snd_hda_mixer_amp_switch_get, ++ .put = alc262_sony_master_sw_put, ++ .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), ++ }, ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), ++ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), ++ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), ++ { } /* end */ ++}; ++ + /* additional init verbs for Benq laptops */ + static struct hda_verb alc262_EAPD_verbs[] = { + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, +@@ -9547,7 +10109,7 @@ static struct hda_verb alc262_volume_ini + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, +- ++ + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +@@ -9602,7 +10164,7 @@ static struct hda_verb alc262_HP_BPC_ini + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, +- ++ + /* + * Set up output mixers (0x0c - 0x0e) + */ +@@ -9763,6 +10325,24 @@ static struct hda_verb alc262_HP_BPC_Wil + { } + }; + ++static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { ++ ++ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */ ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, ++ {0x14, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ ++ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */ ++ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */ ++ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, ++ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) }, ++ ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */ ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ ++ + #ifdef CONFIG_SND_HDA_POWER_SAVE + #define alc262_loopbacks alc880_loopbacks + #endif +@@ -9832,7 +10412,7 @@ static void alc262_auto_init(struct hda_ + alc262_auto_init_analog_input(codec); + alc262_auto_init_input_src(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + /* +@@ -9850,6 +10430,8 @@ static const char *alc262_models[ALC262_ + [ALC262_BENQ_ED8] = "benq", + [ALC262_BENQ_T31] = "benq-t31", + [ALC262_SONY_ASSAMD] = "sony-assamd", ++ [ALC262_TOSHIBA_S06] = "toshiba-s06", ++ [ALC262_TOSHIBA_RX1] = "toshiba-rx1", + [ALC262_ULTRA] = "ultra", + [ALC262_LENOVO_3000] = "lenovo-3000", + [ALC262_NEC] = "nec", +@@ -9887,7 +10469,8 @@ static struct snd_pci_quirk alc262_cfg_t + SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", +- ALC262_SONY_ASSAMD), ++ ALC262_TOSHIBA_RX1), ++ SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), + SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), + SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), +@@ -10042,7 +10625,7 @@ static struct alc_config_preset alc262_p + .input_mux = &alc262_capture_source, + .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, +- }, ++ }, + [ALC262_ULTRA] = { + .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer }, + .init_verbs = { alc262_ultra_verbs }, +@@ -10080,6 +10663,33 @@ static struct alc_config_preset alc262_p + .channel_mode = alc262_modes, + .input_mux = &alc262_capture_source, + }, ++ [ALC262_TOSHIBA_S06] = { ++ .mixers = { alc262_toshiba_s06_mixer }, ++ .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs, ++ alc262_eapd_verbs }, ++ .num_dacs = ARRAY_SIZE(alc262_dac_nids), ++ .capsrc_nids = alc262_dmic_capsrc_nids, ++ .dac_nids = alc262_dac_nids, ++ .adc_nids = alc262_dmic_adc_nids, /* ADC0 */ ++ .dig_out_nid = ALC262_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc262_modes), ++ .channel_mode = alc262_modes, ++ .input_mux = &alc262_dmic_capture_source, ++ .unsol_event = alc262_toshiba_s06_unsol_event, ++ .init_hook = alc262_toshiba_s06_init_hook, ++ }, ++ [ALC262_TOSHIBA_RX1] = { ++ .mixers = { alc262_toshiba_rx1_mixer }, ++ .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs }, ++ .num_dacs = ARRAY_SIZE(alc262_dac_nids), ++ .dac_nids = alc262_dac_nids, ++ .hp_nid = 0x03, ++ .num_channel_mode = ARRAY_SIZE(alc262_modes), ++ .channel_mode = alc262_modes, ++ .input_mux = &alc262_capture_source, ++ .unsol_event = alc262_hippo_unsol_event, ++ .init_hook = alc262_hippo_automute, ++ }, + }; + + static int patch_alc262(struct hda_codec *codec) +@@ -10138,7 +10748,7 @@ static int patch_alc262(struct hda_codec + spec->stream_name_analog = "ALC262 Analog"; + spec->stream_analog_playback = &alc262_pcm_analog_playback; + spec->stream_analog_capture = &alc262_pcm_analog_capture; +- ++ + spec->stream_name_digital = "ALC262 Digital"; + spec->stream_digital_playback = &alc262_pcm_digital_playback; + spec->stream_digital_capture = &alc262_pcm_digital_capture; +@@ -10174,7 +10784,7 @@ static int patch_alc262(struct hda_codec + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; + #endif +- ++ + return 0; + } + +@@ -10183,7 +10793,7 @@ static int patch_alc262(struct hda_codec + */ + #define ALC268_DIGOUT_NID ALC880_DIGOUT_NID + #define alc268_modes alc260_modes +- ++ + static hda_nid_t alc268_dac_nids[2] = { + /* front, hp */ + 0x02, 0x03 +@@ -10243,6 +10853,14 @@ static struct hda_verb alc268_toshiba_ve + { } /* end */ + }; + ++static struct hda_input_mux alc268_acer_lc_capture_source = { ++ .num_items = 2, ++ .items = { ++ { "i-Mic", 0x6 }, ++ { "E-Mic", 0x0 }, ++ }, ++}; ++ + /* Acer specific */ + /* bind volumes of both NID 0x02 and 0x03 */ + static struct hda_bind_ctls alc268_acer_bind_master_vol = { +@@ -10290,6 +10908,21 @@ static int alc268_acer_master_sw_put(str + return change; + } + ++static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { ++ /* output mixer control */ ++ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = snd_hda_mixer_amp_switch_info, ++ .get = snd_hda_mixer_amp_switch_get, ++ .put = alc268_acer_master_sw_put, ++ .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ }, ++ HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT), ++ { } ++}; ++ + static struct snd_kcontrol_new alc268_acer_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), +@@ -10307,6 +10940,16 @@ static struct snd_kcontrol_new alc268_ac + { } + }; + ++static struct hda_verb alc268_acer_aspire_one_verbs[] = { ++ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x23, AC_VERB_SET_CONNECT_SEL, 0x06}, ++ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017}, ++ { } ++}; ++ + static struct hda_verb alc268_acer_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */ + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +@@ -10314,7 +10957,6 @@ static struct hda_verb alc268_acer_verbs + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, +- + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } + }; +@@ -10341,10 +10983,51 @@ static void alc268_acer_init_hook(struct + alc268_acer_automute(codec, 1); + } + +-static struct snd_kcontrol_new alc268_dell_mixer[] = { +- /* output mixer control */ +- HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), ++/* toggle speaker-output according to the hp-jack state */ ++static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x15, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ bits = present ? AMP_IN_MUTE(0) : 0; ++ snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); ++} ++ ++ ++static void alc268_acer_mic_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ ++ present = snd_hda_codec_read(codec, 0x18, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL, ++ present ? 0x0 : 0x6); ++} ++ ++static void alc268_acer_lc_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ if ((res >> 26) == ALC880_HP_EVENT) ++ alc268_aspire_one_speaker_automute(codec); ++ if ((res >> 26) == ALC880_MIC_EVENT) ++ alc268_acer_mic_automute(codec); ++} ++ ++static void alc268_acer_lc_init_hook(struct hda_codec *codec) ++{ ++ alc268_aspire_one_speaker_automute(codec); ++ alc268_acer_mic_automute(codec); ++} ++ ++static struct snd_kcontrol_new alc268_dell_mixer[] = { ++ /* output mixer control */ ++ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), +@@ -10489,7 +11172,7 @@ static struct hda_verb alc268_base_init_ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + + /* Unmute Selector 23h,24h and set the default input to mic-in */ +- ++ + {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, +@@ -10688,7 +11371,7 @@ static int alc268_auto_create_multi_out_ + + nid = cfg->line_out_pins[0]; + if (nid) +- alc268_new_analog_output(spec, nid, "Front", 0); ++ alc268_new_analog_output(spec, nid, "Front", 0); + + nid = cfg->speaker_pins[0]; + if (nid == 0x1d) { +@@ -10710,7 +11393,7 @@ static int alc268_auto_create_multi_out_ + if (err < 0) + return err; + } +- return 0; ++ return 0; + } + + /* create playback/capture controls for input pins */ +@@ -10731,7 +11414,7 @@ static int alc268_auto_create_analog_inp + case 0x1a: + idx1 = 2; /* Line In */ + break; +- case 0x1c: ++ case 0x1c: + idx1 = 3; /* CD */ + break; + case 0x12: +@@ -10743,7 +11426,7 @@ static int alc268_auto_create_analog_inp + } + imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; + imux->items[imux->num_items].index = idx1; +- imux->num_items++; ++ imux->num_items++; + } + return 0; + } +@@ -10773,11 +11456,11 @@ static void alc268_auto_init_mono_speake + } + + dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */ +- if (line_nid == 0x14) ++ if (line_nid == 0x14) + dac_vol2 = AMP_OUT_ZERO; + else if (line_nid == 0x15) + dac_vol1 = AMP_OUT_ZERO; +- if (hp_nid == 0x14) ++ if (hp_nid == 0x14) + dac_vol2 = AMP_OUT_ZERO; + else if (hp_nid == 0x15) + dac_vol1 = AMP_OUT_ZERO; +@@ -10858,7 +11541,7 @@ static void alc268_auto_init(struct hda_ + alc268_auto_init_mono_speaker_out(codec); + alc268_auto_init_analog_input(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + /* +@@ -10869,6 +11552,7 @@ static const char *alc268_models[ALC268_ + [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", ++ [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", + [ALC268_DELL] = "dell", + [ALC268_ZEPTO] = "zepto", + #ifdef CONFIG_SND_DEBUG +@@ -10883,6 +11567,8 @@ static struct snd_pci_quirk alc268_cfg_t + SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), ++ SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", ++ ALC268_ACER_ASPIRE_ONE), + SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), +@@ -10961,6 +11647,23 @@ static struct alc_config_preset alc268_p + .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, + }, ++ [ALC268_ACER_ASPIRE_ONE] = { ++ .mixers = { alc268_acer_aspire_one_mixer, ++ alc268_capture_alt_mixer }, ++ .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, ++ alc268_acer_aspire_one_verbs }, ++ .num_dacs = ARRAY_SIZE(alc268_dac_nids), ++ .dac_nids = alc268_dac_nids, ++ .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), ++ .adc_nids = alc268_adc_nids_alt, ++ .capsrc_nids = alc268_capsrc_nids, ++ .hp_nid = 0x03, ++ .num_channel_mode = ARRAY_SIZE(alc268_modes), ++ .channel_mode = alc268_modes, ++ .input_mux = &alc268_acer_lc_capture_source, ++ .unsol_event = alc268_acer_lc_unsol_event, ++ .init_hook = alc268_acer_lc_init_hook, ++ }, + [ALC268_DELL] = { + .mixers = { alc268_dell_mixer, alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, +@@ -11105,7 +11808,7 @@ static int patch_alc268(struct hda_codec + codec->patch_ops = alc_patch_ops; + if (board_config == ALC268_AUTO) + spec->init_hook = alc268_auto_init; +- ++ + return 0; + } + +@@ -11155,6 +11858,8 @@ static struct snd_kcontrol_new alc269_ba + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT), ++ HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), +@@ -11164,6 +11869,28 @@ static struct snd_kcontrol_new alc269_ba + { } /* end */ + }; + ++static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { ++ /* output mixer control */ ++ HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = snd_hda_mixer_amp_switch_info, ++ .get = snd_hda_mixer_amp_switch_get, ++ .put = alc268_acer_master_sw_put, ++ .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ }, ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), ++ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), ++ HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT), ++ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT), ++ { } ++}; ++ + /* bind volumes of both NID 0x0c and 0x0d */ + static struct hda_bind_ctls alc269_epc_bind_vol = { + .ops = &snd_hda_bind_vol, +@@ -11207,75 +11934,72 @@ static struct snd_kcontrol_new alc269_ep + { } /* end */ + }; + +-/* +- * generic initialization of ADC, input mixers and output mixers +- */ +-static struct hda_verb alc269_init_verbs[] = { +- /* +- * Unmute ADC0 and set the default input to mic-in +- */ +- {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++/* beep control */ ++static struct snd_kcontrol_new alc269_beep_mixer[] = { ++ HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x4, HDA_INPUT), ++ HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x4, HDA_INPUT), ++ { } /* end */ ++}; + +- /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the +- * analog-loopback mixer widget +- * Note: PASD motherboards uses the Line In 2 as the input for +- * front panel mic (mic 2) +- */ +- /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ +- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, +- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, +- {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, ++static struct hda_verb alc269_quanta_fl1_verbs[] = { ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, ++ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ { } ++}; + +- /* +- * Set up output mixers (0x0c - 0x0e) +- */ +- /* set vol=0 to output mixers */ +- {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, +- {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, ++/* toggle speaker-output according to the hp-jack state */ ++static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; + +- /* set up input amps for analog loopback */ +- /* Amp Indices: DAC = 0, mixer = 1 */ +- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ present = snd_hda_codec_read(codec, 0x15, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ bits = present ? AMP_IN_MUTE(0) : 0; ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); + +- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, +- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, +- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, +- {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +- {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ snd_hda_codec_write(codec, 0x20, 0, ++ AC_VERB_SET_COEF_INDEX, 0x0c); ++ snd_hda_codec_write(codec, 0x20, 0, ++ AC_VERB_SET_PROC_COEF, 0x680); + +- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +- {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +- {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +- {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, +- {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ snd_hda_codec_write(codec, 0x20, 0, ++ AC_VERB_SET_COEF_INDEX, 0x0c); ++ snd_hda_codec_write(codec, 0x20, 0, ++ AC_VERB_SET_PROC_COEF, 0x480); ++} + +- {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, ++static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) ++{ ++ unsigned int present; + +- /* FIXME: use matrix-type input source selection */ +- /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ +- /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ +- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, +- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, ++ present = snd_hda_codec_read(codec, 0x18, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_write(codec, 0x23, 0, ++ AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); ++} + +- /* set EAPD */ +- {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, +- {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, +- { } +-}; ++static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ if ((res >> 26) == ALC880_HP_EVENT) ++ alc269_quanta_fl1_speaker_automute(codec); ++ if ((res >> 26) == ALC880_MIC_EVENT) ++ alc269_quanta_fl1_mic_automute(codec); ++} ++ ++static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) ++{ ++ alc269_quanta_fl1_speaker_automute(codec); ++ alc269_quanta_fl1_mic_automute(codec); ++} + + static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, +@@ -11302,42 +12026,42 @@ static struct hda_verb alc269_eeepc_amic + static void alc269_speaker_automute(struct hda_codec *codec) + { + unsigned int present; +- unsigned int bits; ++ unsigned char bits; + + present = snd_hda_codec_read(codec, 0x15, 0, +- AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? AMP_IN_MUTE(0) : 0; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, +- AMP_IN_MUTE(0), bits); ++ AMP_IN_MUTE(0), bits); + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, +- AMP_IN_MUTE(0), bits); ++ AMP_IN_MUTE(0), bits); + } + + static void alc269_eeepc_dmic_automute(struct hda_codec *codec) + { + unsigned int present; + +- present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) +- & AC_PINSENSE_PRESENCE; +- snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_CONNECT_SEL, +- present ? 0 : 5); ++ present = snd_hda_codec_read(codec, 0x18, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_write(codec, 0x23, 0, ++ AC_VERB_SET_CONNECT_SEL, (present ? 0 : 5)); + } + + static void alc269_eeepc_amic_automute(struct hda_codec *codec) + { + unsigned int present; + +- present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) +- & AC_PINSENSE_PRESENCE; ++ present = snd_hda_codec_read(codec, 0x18, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE, +- present ? AMP_IN_UNMUTE(0) : AMP_IN_MUTE(0)); ++ 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x24, 0, AC_VERB_SET_AMP_GAIN_MUTE, +- present ? AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1)); ++ 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); + } + + /* unsolicited event for HP jack sensing */ + static void alc269_eeepc_dmic_unsol_event(struct hda_codec *codec, +- unsigned int res) ++ unsigned int res) + { + if ((res >> 26) == ALC880_HP_EVENT) + alc269_speaker_automute(codec); +@@ -11354,7 +12078,7 @@ static void alc269_eeepc_dmic_inithook(s + + /* unsolicited event for HP jack sensing */ + static void alc269_eeepc_amic_unsol_event(struct hda_codec *codec, +- unsigned int res) ++ unsigned int res) + { + if ((res >> 26) == ALC880_HP_EVENT) + alc269_speaker_automute(codec); +@@ -11369,6 +12093,76 @@ static void alc269_eeepc_amic_inithook(s + alc269_eeepc_amic_automute(codec); + } + ++/* ++ * generic initialization of ADC, input mixers and output mixers ++ */ ++static struct hda_verb alc269_init_verbs[] = { ++ /* ++ * Unmute ADC0 and set the default input to mic-in ++ */ ++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ ++ /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the ++ * analog-loopback mixer widget ++ * Note: PASD motherboards uses the Line In 2 as the input for ++ * front panel mic (mic 2) ++ */ ++ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, ++ ++ /* ++ * Set up output mixers (0x0c - 0x0e) ++ */ ++ /* set vol=0 to output mixers */ ++ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, ++ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, ++ ++ /* set up input amps for analog loopback */ ++ /* Amp Indices: DAC = 0, mixer = 1 */ ++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ ++ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ ++ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ ++ /* FIXME: use matrix-type input source selection */ ++ /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ ++ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ ++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, ++ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, ++ ++ /* set EAPD */ ++ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, ++ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, ++ { } ++}; ++ + /* add playback controls from the parsed DAC table */ + static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec, + const struct auto_pin_cfg *cfg) +@@ -11469,7 +12263,7 @@ static int alc269_auto_create_multi_out_ + static int alc269_parse_auto_config(struct hda_codec *codec) + { + struct alc_spec *spec = codec->spec; +- int err; ++ int i, err; + static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, +@@ -11492,6 +12286,13 @@ static int alc269_parse_auto_config(stru + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + ++ /* create a beep mixer control if the pin 0x1d isn't assigned */ ++ for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) ++ if (spec->autocfg.input_pins[i] == 0x1d) ++ break; ++ if (i >= ARRAY_SIZE(spec->autocfg.input_pins)) ++ spec->mixers[spec->num_mixers++] = alc269_beep_mixer; ++ + spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux; +@@ -11524,21 +12325,27 @@ static void alc269_auto_init(struct hda_ + alc269_auto_init_hp_out(codec); + alc269_auto_init_analog_input(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + /* + * configuration and preset + */ + static const char *alc269_models[ALC269_MODEL_LAST] = { +- [ALC269_BASIC] = "basic", ++ [ALC269_BASIC] = "basic", ++ [ALC269_QUANTA_FL1] = "quanta", ++ [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", ++ [ALC269_ASUS_EEEPC_P901] = "eeepc-p901" + }; + + static struct snd_pci_quirk alc269_cfg_tbl[] = { ++ SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), + SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", + ALC269_ASUS_EEEPC_P703), + SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", + ALC269_ASUS_EEEPC_P901), ++ SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", ++ ALC269_ASUS_EEEPC_P901), + {} + }; + +@@ -11553,17 +12360,29 @@ static struct alc_config_preset alc269_p + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + }, +- [ALC269_ASUS_EEEPC_P703] = { +- .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer }, +- .init_verbs = { alc269_init_verbs, +- alc269_eeepc_amic_init_verbs }, ++ [ALC269_QUANTA_FL1] = { ++ .mixers = { alc269_quanta_fl1_mixer }, ++ .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, +- .input_mux = &alc269_eeepc_amic_capture_source, +- .unsol_event = alc269_eeepc_amic_unsol_event, ++ .input_mux = &alc269_capture_source, ++ .unsol_event = alc269_quanta_fl1_unsol_event, ++ .init_hook = alc269_quanta_fl1_init_hook, ++ }, ++ [ALC269_ASUS_EEEPC_P703] = { ++ .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer }, ++ .init_verbs = { alc269_init_verbs, ++ alc269_eeepc_amic_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc269_dac_nids), ++ .dac_nids = alc269_dac_nids, ++ .hp_nid = 0x03, ++ .num_channel_mode = ARRAY_SIZE(alc269_modes), ++ .channel_mode = alc269_modes, ++ .input_mux = &alc269_eeepc_amic_capture_source, ++ .unsol_event = alc269_eeepc_amic_unsol_event, + .init_hook = alc269_eeepc_amic_inithook, + }, + [ALC269_ASUS_EEEPC_P901] = { +@@ -11834,7 +12653,7 @@ static struct snd_kcontrol_new alc861_to + HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), +- ++ + /*Capture mixer control */ + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), +@@ -11977,20 +12796,20 @@ static struct hda_verb alc861_base_init_ + /* route front mic to ADC1*/ + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- ++ + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- ++ + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- ++ + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +@@ -12046,13 +12865,13 @@ static struct hda_verb alc861_threestack + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- ++ + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- ++ + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +@@ -12108,13 +12927,13 @@ static struct hda_verb alc861_uniwill_m3 + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- ++ + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- ++ + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +@@ -12179,7 +12998,7 @@ static struct hda_verb alc861_asus_init_ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- ++ + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +@@ -12216,20 +13035,20 @@ static struct hda_verb alc861_auto_init_ + */ + /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- ++ + /* Unmute DAC0~3 & spdif out*/ + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- ++ + /* Unmute Mixer 14 (mic) 1c (Line in)*/ + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +- ++ + /* Unmute Stereo Mixer 15 */ + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, +@@ -12588,7 +13407,7 @@ static void alc861_auto_init(struct hda_ + alc861_auto_init_hp_out(codec); + alc861_auto_init_analog_input(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + #ifdef CONFIG_SND_HDA_POWER_SAVE +@@ -12805,7 +13624,7 @@ static int patch_alc861(struct hda_codec + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861_loopbacks; + #endif +- ++ + return 0; + } + +@@ -13059,7 +13878,7 @@ static struct snd_kcontrol_new alc861vd_ + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), +- ++ + { } /* end */ + }; + +@@ -13204,7 +14023,7 @@ static struct hda_verb alc861vd_lenovo_u + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, +- {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {} + }; + +@@ -13266,7 +14085,7 @@ static struct hda_verb alc861vd_dallas_v + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, +- ++ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, +@@ -13291,7 +14110,7 @@ static struct hda_verb alc861vd_dallas_v + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, +- {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + + { } /* end */ +@@ -13450,7 +14269,7 @@ static struct alc_config_preset alc861vd + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, +- }, ++ }, + }; + + /* +@@ -13701,7 +14520,7 @@ static void alc861vd_auto_init(struct hd + alc861vd_auto_init_analog_input(codec); + alc861vd_auto_init_input_src(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + static int patch_alc861vd(struct hda_codec *codec) +@@ -14030,13 +14849,120 @@ static struct snd_kcontrol_new alc662_ee + { } /* end */ + }; + ++static struct hda_bind_ctls alc663_asus_bind_master_vol = { ++ .ops = &snd_hda_bind_vol, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct hda_bind_ctls alc663_asus_one_bind_switch = { ++ .ops = &snd_hda_bind_sw, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ + static struct snd_kcontrol_new alc663_m51va_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), ++ HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ { } /* end */ ++}; ++ ++static struct hda_bind_ctls alc663_asus_tree_bind_switch = { ++ .ops = &snd_hda_bind_sw, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), ++ HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), ++ ++ { } /* end */ ++}; ++ ++static struct hda_bind_ctls alc663_asus_four_bind_switch = { ++ .ops = &snd_hda_bind_sw, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), ++ HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), ++ { } /* end */ ++}; ++ ++static struct snd_kcontrol_new alc662_1bjd_mixer[] = { + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), ++ { } /* end */ ++}; ++ ++static struct hda_bind_ctls alc663_asus_two_bind_master_vol = { ++ .ops = &snd_hda_bind_vol, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct hda_bind_ctls alc663_asus_two_bind_switch = { ++ .ops = &snd_hda_bind_sw, ++ .values = { ++ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT), ++ 0 ++ }, ++}; ++ ++static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", ++ &alc663_asus_two_bind_master_vol), ++ HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), ++ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT), ++ { } /* end */ ++}; ++ ++static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = { ++ HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol), ++ HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch), ++ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), ++ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ + }; + +@@ -14221,14 +15147,81 @@ static struct hda_verb alc663_auto_init_ + }; + + static struct hda_verb alc663_m51va_init_verbs[] = { ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, +- {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ ++ {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; + +- {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, ++static struct hda_verb alc663_21jd_amic_init_verbs[] = { ++ {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ ++static struct hda_verb alc662_1bjd_amic_init_verbs[] = { ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ ++static struct hda_verb alc663_15jd_amic_init_verbs[] = { ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; + ++static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = { ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */ ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ ++static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = { ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} + }; + +@@ -14257,6 +15250,14 @@ static struct hda_verb alc663_g50v_init_ + {} + }; + ++static struct hda_verb alc662_ecs_init_verbs[] = { ++ {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, ++ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, ++ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, ++ {} ++}; ++ + /* capture mixer elements */ + static struct snd_kcontrol_new alc662_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), +@@ -14276,6 +15277,12 @@ static struct snd_kcontrol_new alc662_ca + { } /* end */ + }; + ++static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { ++ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), ++ { } /* end */ ++}; ++ + static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) + { + unsigned int present; +@@ -14356,12 +15363,12 @@ static void alc662_eeepc_ep20_automute(s + if (present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, +- HDA_AMP_MUTE, HDA_AMP_MUTE); ++ HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, +- HDA_AMP_MUTE, mute); ++ HDA_AMP_MUTE, mute); + } + } + +@@ -14384,11 +15391,108 @@ static void alc663_m51va_speaker_automut + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x21, 0, +- AC_VERB_GET_PIN_SENSE, 0) +- & AC_PINSENSE_PRESENCE; ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; + bits = present ? HDA_AMP_MUTE : 0; +- snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, +- HDA_AMP_MUTE, bits); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); ++} ++ ++static void alc663_21jd_two_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x21, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ bits = present ? HDA_AMP_MUTE : 0; ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); ++} ++ ++static void alc663_15jd_two_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x15, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ bits = present ? HDA_AMP_MUTE : 0; ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), bits); ++ snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), bits); ++} ++ ++static void alc662_f5z_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ unsigned char bits; ++ ++ present = snd_hda_codec_read(codec, 0x1b, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ bits = present ? 0 : PIN_OUT; ++ snd_hda_codec_write(codec, 0x14, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, bits); ++} ++ ++static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present1, present2; ++ ++ present1 = snd_hda_codec_read(codec, 0x21, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ present2 = snd_hda_codec_read(codec, 0x15, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ ++ if (present1 || present2) { ++ snd_hda_codec_write_cache(codec, 0x14, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, 0); ++ } else { ++ snd_hda_codec_write_cache(codec, 0x14, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); ++ } ++} ++ ++static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) ++{ ++ unsigned int present1, present2; ++ ++ present1 = snd_hda_codec_read(codec, 0x1b, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ present2 = snd_hda_codec_read(codec, 0x15, 0, ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; ++ ++ if (present1 || present2) { ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), AMP_IN_MUTE(0)); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), AMP_IN_MUTE(0)); ++ } else { ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, ++ AMP_IN_MUTE(0), 0); ++ snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, ++ AMP_IN_MUTE(0), 0); ++ } + } + + static void alc663_m51va_mic_automute(struct hda_codec *codec) +@@ -14396,16 +15500,16 @@ static void alc663_m51va_mic_automute(st + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, +- AC_VERB_GET_PIN_SENSE, 0) +- & AC_PINSENSE_PRESENCE; ++ AC_VERB_GET_PIN_SENSE, 0) ++ & AC_PINSENSE_PRESENCE; + snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, +- 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); ++ 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, +- 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); ++ 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, +- 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); ++ 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); + snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, +- 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); ++ 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); + } + + static void alc663_m51va_unsol_event(struct hda_codec *codec, +@@ -14427,6 +15531,121 @@ static void alc663_m51va_inithook(struct + alc663_m51va_mic_automute(codec); + } + ++/* ***************** Mode1 ******************************/ ++static void alc663_mode1_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc663_m51va_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc662_eeepc_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc663_mode1_inithook(struct hda_codec *codec) ++{ ++ alc663_m51va_speaker_automute(codec); ++ alc662_eeepc_mic_automute(codec); ++} ++/* ***************** Mode2 ******************************/ ++static void alc662_mode2_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc662_f5z_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc662_eeepc_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc662_mode2_inithook(struct hda_codec *codec) ++{ ++ alc662_f5z_speaker_automute(codec); ++ alc662_eeepc_mic_automute(codec); ++} ++/* ***************** Mode3 ******************************/ ++static void alc663_mode3_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc663_two_hp_m1_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc662_eeepc_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc663_mode3_inithook(struct hda_codec *codec) ++{ ++ alc663_two_hp_m1_speaker_automute(codec); ++ alc662_eeepc_mic_automute(codec); ++} ++/* ***************** Mode4 ******************************/ ++static void alc663_mode4_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc663_21jd_two_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc662_eeepc_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc663_mode4_inithook(struct hda_codec *codec) ++{ ++ alc663_21jd_two_speaker_automute(codec); ++ alc662_eeepc_mic_automute(codec); ++} ++/* ***************** Mode5 ******************************/ ++static void alc663_mode5_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc663_15jd_two_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc662_eeepc_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc663_mode5_inithook(struct hda_codec *codec) ++{ ++ alc663_15jd_two_speaker_automute(codec); ++ alc662_eeepc_mic_automute(codec); ++} ++/* ***************** Mode6 ******************************/ ++static void alc663_mode6_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc663_two_hp_m2_speaker_automute(codec); ++ break; ++ case ALC880_MIC_EVENT: ++ alc662_eeepc_mic_automute(codec); ++ break; ++ } ++} ++ ++static void alc663_mode6_inithook(struct hda_codec *codec) ++{ ++ alc663_two_hp_m2_speaker_automute(codec); ++ alc662_eeepc_mic_automute(codec); ++} ++ + static void alc663_g71v_hp_automute(struct hda_codec *codec) + { + unsigned int present; +@@ -14497,6 +15716,46 @@ static void alc663_g50v_inithook(struct + alc662_eeepc_mic_automute(codec); + } + ++/* bind hp and internal speaker mute (with plug check) */ ++static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ long *valp = ucontrol->value.integer.value; ++ int change; ++ ++ change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, ++ valp[0] ? 0 : HDA_AMP_MUTE); ++ change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, ++ valp[1] ? 0 : HDA_AMP_MUTE); ++ if (change) ++ alc262_hippo1_automute(codec); ++ return change; ++} ++ ++static struct snd_kcontrol_new alc662_ecs_mixer[] = { ++ HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = snd_hda_mixer_amp_switch_info, ++ .get = snd_hda_mixer_amp_switch_get, ++ .put = alc662_ecs_master_sw_put, ++ .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), ++ }, ++ ++ HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT), ++ ++ HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), ++ { } /* end */ ++}; ++ + #ifdef CONFIG_SND_HDA_POWER_SAVE + #define alc662_loopbacks alc880_loopbacks + #endif +@@ -14519,21 +15778,68 @@ static const char *alc662_models[ALC662_ + [ALC662_LENOVO_101E] = "lenovo-101e", + [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", + [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", ++ [ALC662_ECS] = "ecs", + [ALC663_ASUS_M51VA] = "m51va", + [ALC663_ASUS_G71V] = "g71v", + [ALC663_ASUS_H13] = "h13", + [ALC663_ASUS_G50V] = "g50v", ++ [ALC663_ASUS_MODE1] = "asus-mode1", ++ [ALC662_ASUS_MODE2] = "asus-mode2", ++ [ALC663_ASUS_MODE3] = "asus-mode3", ++ [ALC663_ASUS_MODE4] = "asus-mode4", ++ [ALC663_ASUS_MODE5] = "asus-mode5", ++ [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC662_AUTO] = "auto", + }; + + static struct snd_pci_quirk alc662_cfg_tbl[] = { +- SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V), + SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), +- SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V), ++ SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V), + SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), + SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), ++ SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1), ++ SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2), ++ SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3), ++ SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3), ++ SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3), ++ SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3), ++ SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3), ++ SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4), ++ SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5), ++ SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6), ++ SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), ++ SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), ++ SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", ++ ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), ++ SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), ++ SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), ++ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", ++ ALC662_3ST_6ch_DIG), ++ SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), ++ SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", ++ ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13), +@@ -14624,6 +15930,18 @@ static struct alc_config_preset alc662_p + .unsol_event = alc662_eeepc_ep20_unsol_event, + .init_hook = alc662_eeepc_ep20_inithook, + }, ++ [ALC662_ECS] = { ++ .mixers = { alc662_ecs_mixer, alc662_capture_mixer }, ++ .init_verbs = { alc662_init_verbs, ++ alc662_ecs_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .dac_nids = alc662_dac_nids, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc662_eeepc_unsol_event, ++ .init_hook = alc662_eeepc_inithook, ++ }, + [ALC663_ASUS_M51VA] = { + .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, + .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, +@@ -14671,6 +15989,91 @@ static struct alc_config_preset alc662_p + .unsol_event = alc663_g50v_unsol_event, + .init_hook = alc663_g50v_inithook, + }, ++ [ALC663_ASUS_MODE1] = { ++ .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer }, ++ .init_verbs = { alc662_init_verbs, ++ alc663_21jd_amic_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .hp_nid = 0x03, ++ .dac_nids = alc662_dac_nids, ++ .dig_out_nid = ALC662_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc663_mode1_unsol_event, ++ .init_hook = alc663_mode1_inithook, ++ }, ++ [ALC662_ASUS_MODE2] = { ++ .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer }, ++ .init_verbs = { alc662_init_verbs, ++ alc662_1bjd_amic_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .dac_nids = alc662_dac_nids, ++ .dig_out_nid = ALC662_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc662_mode2_unsol_event, ++ .init_hook = alc662_mode2_inithook, ++ }, ++ [ALC663_ASUS_MODE3] = { ++ .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer }, ++ .init_verbs = { alc662_init_verbs, ++ alc663_two_hp_amic_m1_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .hp_nid = 0x03, ++ .dac_nids = alc662_dac_nids, ++ .dig_out_nid = ALC662_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc663_mode3_unsol_event, ++ .init_hook = alc663_mode3_inithook, ++ }, ++ [ALC663_ASUS_MODE4] = { ++ .mixers = { alc663_asus_21jd_clfe_mixer, ++ alc662_auto_capture_mixer}, ++ .init_verbs = { alc662_init_verbs, ++ alc663_21jd_amic_init_verbs}, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .hp_nid = 0x03, ++ .dac_nids = alc662_dac_nids, ++ .dig_out_nid = ALC662_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc663_mode4_unsol_event, ++ .init_hook = alc663_mode4_inithook, ++ }, ++ [ALC663_ASUS_MODE5] = { ++ .mixers = { alc663_asus_15jd_clfe_mixer, ++ alc662_auto_capture_mixer }, ++ .init_verbs = { alc662_init_verbs, ++ alc663_15jd_amic_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .hp_nid = 0x03, ++ .dac_nids = alc662_dac_nids, ++ .dig_out_nid = ALC662_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc663_mode5_unsol_event, ++ .init_hook = alc663_mode5_inithook, ++ }, ++ [ALC663_ASUS_MODE6] = { ++ .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer }, ++ .init_verbs = { alc662_init_verbs, ++ alc663_two_hp_amic_m2_init_verbs }, ++ .num_dacs = ARRAY_SIZE(alc662_dac_nids), ++ .hp_nid = 0x03, ++ .dac_nids = alc662_dac_nids, ++ .dig_out_nid = ALC662_DIGOUT_NID, ++ .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), ++ .channel_mode = alc662_3ST_2ch_modes, ++ .input_mux = &alc662_eeepc_capture_source, ++ .unsol_event = alc663_mode6_unsol_event, ++ .init_hook = alc663_mode6_inithook, ++ }, + }; + + +@@ -14707,15 +16110,15 @@ static int alc662_auto_create_multi_out_ + HDA_OUTPUT)); + if (err < 0) + return err; +- err = add_control(spec, ALC_CTL_BIND_MUTE, ++ err = add_control(spec, ALC_CTL_WIDGET_MUTE, + "Center Playback Switch", +- HDA_COMPOSE_AMP_VAL(nid, 1, 2, ++ HDA_COMPOSE_AMP_VAL(0x0e, 1, 0, + HDA_INPUT)); + if (err < 0) + return err; +- err = add_control(spec, ALC_CTL_BIND_MUTE, ++ err = add_control(spec, ALC_CTL_WIDGET_MUTE, + "LFE Playback Switch", +- HDA_COMPOSE_AMP_VAL(nid, 2, 2, ++ HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, + HDA_INPUT)); + if (err < 0) + return err; +@@ -14727,9 +16130,9 @@ static int alc662_auto_create_multi_out_ + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); +- err = add_control(spec, ALC_CTL_BIND_MUTE, name, +- HDA_COMPOSE_AMP_VAL(nid, 3, 2, +- HDA_INPUT)); ++ err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, ++ HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i), ++ 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } +@@ -14924,7 +16327,7 @@ static int alc662_parse_auto_config(stru + + spec->num_mux_defs = 1; + spec->input_mux = &spec->private_imux; +- ++ + spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs; + if (codec->vendor_id == 0x10ec0663) + spec->init_verbs[spec->num_init_verbs++] = +@@ -14950,7 +16353,7 @@ static void alc662_auto_init(struct hda_ + alc662_auto_init_analog_input(codec); + alc662_auto_init_input_src(codec); + if (spec->unsol_event) +- alc_sku_automute(codec); ++ alc_inithook(codec); + } + + static int patch_alc662(struct hda_codec *codec) +@@ -15056,6 +16459,8 @@ struct hda_codec_preset snd_hda_preset_r + { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 }, + { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, ++ { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", ++ .patch = patch_alc883 }, + { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, + {} /* terminator */ + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-seek-for-codec-id b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-seek-for-codec-id new file mode 100644 index 000000000..5be6b6245 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-seek-for-codec-id @@ -0,0 +1,123 @@ +From 2eda344546caaf9168e778a4007f4609e95106e0 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Mon, 11 Aug 2008 10:18:39 +0200 +Subject: ALSA: hda - Add a new function to seek for a codec ID +Patch-mainline: 2.6.29-rc1 +References: bnc#460478 + +Gateway notebooks have their ID inside codec vendor ID, not at PCI ID. Due to +that, model auto-detection were not possible with the standard seek method. + +This is what is found at lspci -vnn: + +00:14.2 Audio device [0403]: ATI Technologies Inc SB450 HDA Audio [1002:437b] (rev 01) + Subsystem: ATI Technologies Inc SB450 HDA Audio [1002:437b] + +Yet, autodetection is possible, since the codec properly reflects the vendor at +the Subsystem ID: + +$ cat /proc/asound/card0/codec#0 |head -4 + +Codec: SigmaTel STAC9250 +Address: 0 +Vendor Id: 0x83847634 +Subsystem Id: 0x107b0367 + +This patch adds a new autodetection function that seeks for codec subsystem ID. + +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ + sound/pci/hda/hda_local.h | 3 ++ + 2 files changed, 63 insertions(+), 0 deletions(-) + +diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c +index 0043448..9c1af01 100644 +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -2364,6 +2364,66 @@ int snd_hda_check_board_config(struct hd + } + + /** ++ * snd_hda_check_board_codec_sid_config - compare the current codec ++ subsystem ID with the ++ config table ++ ++ This is important for Gateway notebooks with SB450 HDA Audio ++ where the vendor ID of the PCI device is: ++ ATI Technologies Inc SB450 HDA Audio [1002:437b] ++ and the vendor/subvendor are found only at the codec. ++ ++ * @codec: the HDA codec ++ * @num_configs: number of config enums ++ * @models: array of model name strings ++ * @tbl: configuration table, terminated by null entries ++ * ++ * Compares the modelname or PCI subsystem id of the current codec with the ++ * given configuration table. If a matching entry is found, returns its ++ * config value (supposed to be 0 or positive). ++ * ++ * If no entries are matching, the function returns a negative value. ++ */ ++int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, ++ int num_configs, const char **models, ++ const struct snd_pci_quirk *tbl) ++{ ++ const struct snd_pci_quirk *q; ++ ++ /* Search for codec ID */ ++ for (q = tbl; q->subvendor; q++) { ++ unsigned long vendorid = (q->subdevice) | (q->subvendor << 16); ++ ++ if (vendorid == codec->subsystem_id) ++ break; ++ } ++ ++ if (!q->subvendor) ++ return -1; ++ ++ tbl = q; ++ ++ if (tbl->value >= 0 && tbl->value < num_configs) { ++#ifdef CONFIG_SND_DEBUG_DETECT ++ char tmp[10]; ++ const char *model = NULL; ++ if (models) ++ model = models[tbl->value]; ++ if (!model) { ++ sprintf(tmp, "#%d", tbl->value); ++ model = tmp; ++ } ++ snd_printdd(KERN_INFO "hda_codec: model '%s' is selected " ++ "for config %x:%x (%s)\n", ++ model, tbl->subvendor, tbl->subdevice, ++ (tbl->name ? tbl->name : "Unknown device")); ++#endif ++ return tbl->value; ++ } ++ return -1; ++} ++ ++/** + * snd_hda_add_new_ctls - create controls from the array + * @codec: the HDA codec + * @knew: the array of struct snd_kcontrol_new +diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h +index 6f2fe0f..1dd8716 100644 +--- a/sound/pci/hda/hda_local.h ++++ b/sound/pci/hda/hda_local.h +@@ -288,6 +288,9 @@ static inline int snd_hda_codec_proc_new + int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, + const char **modelnames, + const struct snd_pci_quirk *pci_list); ++int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, ++ int num_configs, const char **models, ++ const struct snd_pci_quirk *tbl); + int snd_hda_add_new_ctls(struct hda_codec *codec, + struct snd_kcontrol_new *knew); + +-- +1.6.1 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-add-missing-terminators b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-add-missing-terminators new file mode 100644 index 000000000..81601c233 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-add-missing-terminators @@ -0,0 +1,25 @@ +From 574f3c4f5c55e99ea60f71fd98cc54931d4b2eae Mon Sep 17 00:00:00 2001 +From: Herton Ronaldo Krzesinski +Date: Tue, 23 Dec 2008 16:53:00 -0200 +Subject: ALSA: hda - Add missing terminators in patch_sigmatel.c +Patch-mainline: 2.6.28 +References: + +Signed-off-by: Herton Ronaldo Krzesinski +Cc: stable@kernel.org +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1669,6 +1669,7 @@ static struct snd_pci_quirk stac92hd83xx + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD71BXX_REF), ++ {} /* terminator */ + }; + + static unsigned int ref92hd71bxx_pin_configs[11] = { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-hp-m4-check-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-hp-m4-check-fix new file mode 100644 index 000000000..26439e291 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-hp-m4-check-fix @@ -0,0 +1,28 @@ +From: Takashi Iwai +Subject: ALSA: hda - Check model type instead of SSID in patch_92hd71bxx() +Patch-mainline: +References: bnc#444349 + +Check board preset model instead of codec->subsystem_id in +patch_92hd71bxx() so that other hardwares configured via the model +option work like the given model. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -4492,8 +4492,8 @@ again: + codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; + break; + case 0x111d7608: /* 5 Port with Analog Mixer */ +- switch (codec->subsystem_id) { +- case 0x103c361a: ++ switch (spec->board_config) { ++ case STAC_HP_M4: + /* Enable VREF power saving on GPIO1 detect */ + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-spdif-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-spdif-fix new file mode 100644 index 000000000..d5a05184a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-spdif-fix @@ -0,0 +1,29 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix SPDIF mute on IDT/STAC codecs +Patch-mainline: 2.6.28-rc3 +References: + +The SPDIF mute switch code seems broken. It doesn't set unmute bits +properly. Also it contains the duplicated lines (merge error?) to be +cleaned up. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -567,10 +567,8 @@ static int stac92xx_smux_enum_put(struct + nid = codec->slave_dig_outs[smux_idx - 1]; + if (spec->cur_smux[smux_idx] == smux->num_items - 1) + val = AMP_OUT_MUTE; +- if (smux_idx == 0) +- nid = spec->multiout.dig_out_nid; + else +- nid = codec->slave_dig_outs[smux_idx - 1]; ++ val = AMP_OUT_UNMUTE; + /* un/mute SPDIF out */ + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-update new file mode 100644 index 000000000..a41761a51 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-update @@ -0,0 +1,1772 @@ +From: Takashi Iwai +Subject: ALSA: hda - IDT/Sigmatel codec updates +Patch-mainline: 2.6.28-rc1 +References: bnc#409140 + +A pile of updates for IDT/Sigtmatel codecs. + +- digital beep support +- 92HD83x codecs +- HP M4 model support +- ECS 202 model support +- Multiple SPDIF support +- More power-saving + +Signed-off-by: Takashi Iwai + +--- +--- + sound/pci/hda/hda_codec.c | 9 + sound/pci/hda/hda_local.h | 9 + sound/pci/hda/patch_sigmatel.c | 975 ++++++++++++++++++++++++++++++++++++----- + 3 files changed, 877 insertions(+), 116 deletions(-) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -959,15 +959,6 @@ void snd_hda_codec_resume_amp(struct hda + } + #endif /* SND_HDA_NEEDS_RESUME */ + +-/* +- * AMP control callbacks +- */ +-/* retrieve parameters from private_value */ +-#define get_amp_nid(kc) ((kc)->private_value & 0xffff) +-#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) +-#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) +-#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) +- + /* volume */ + int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +--- a/sound/pci/hda/hda_local.h ++++ b/sound/pci/hda/hda_local.h +@@ -421,4 +421,13 @@ int snd_hda_check_amp_list_power(struct + hda_nid_t nid); + #endif /* CONFIG_SND_HDA_POWER_SAVE */ + ++/* ++ * AMP control callbacks ++ */ ++/* retrieve parameters from private_value */ ++#define get_amp_nid(kc) ((kc)->private_value & 0xffff) ++#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) ++#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) ++#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) ++ + #endif /* __SOUND_HDA_LOCAL_H */ +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -33,10 +33,12 @@ + #include "hda_codec.h" + #include "hda_local.h" + #include "hda_patch.h" ++#include "hda_beep.h" + + #define NUM_CONTROL_ALLOC 32 + #define STAC_PWR_EVENT 0x20 + #define STAC_HP_EVENT 0x30 ++#define STAC_VREF_EVENT 0x40 + + enum { + STAC_REF, +@@ -72,9 +74,15 @@ enum { + }; + + enum { ++ STAC_92HD83XXX_REF, ++ STAC_92HD83XXX_MODELS ++}; ++ ++enum { + STAC_92HD71BXX_REF, + STAC_DELL_M4_1, + STAC_DELL_M4_2, ++ STAC_HP_M4, + STAC_92HD71BXX_MODELS + }; + +@@ -132,6 +140,7 @@ struct sigmatel_spec { + unsigned int mic_switch: 1; + unsigned int alt_switch: 1; + unsigned int hp_detect: 1; ++ unsigned int spdif_mute: 1; + + /* gpio lines */ + unsigned int eapd_mask; +@@ -140,17 +149,22 @@ struct sigmatel_spec { + unsigned int gpio_data; + unsigned int gpio_mute; + ++ /* stream */ ++ unsigned int stream_delay; ++ + /* analog loopback */ + unsigned char aloopback_mask; + unsigned char aloopback_shift; + + /* power management */ + unsigned int num_pwrs; ++ unsigned int *pwr_mapping; + hda_nid_t *pwr_nids; + hda_nid_t *dac_list; + + /* playback */ + struct hda_input_mux *mono_mux; ++ struct hda_input_mux *amp_mux; + unsigned int cur_mmux; + struct hda_multi_out multiout; + hda_nid_t dac_nids[5]; +@@ -164,8 +178,14 @@ struct sigmatel_spec { + unsigned int num_dmics; + hda_nid_t *dmux_nids; + unsigned int num_dmuxes; ++ hda_nid_t *smux_nids; ++ unsigned int num_smuxes; ++ const char **spdif_labels; ++ + hda_nid_t dig_in_nid; + hda_nid_t mono_nid; ++ hda_nid_t anabeep_nid; ++ hda_nid_t digbeep_nid; + + /* pin widgets */ + hda_nid_t *pin_nids; +@@ -182,6 +202,12 @@ struct sigmatel_spec { + unsigned int cur_dmux[2]; + struct hda_input_mux *input_mux; + unsigned int cur_mux[3]; ++ struct hda_input_mux *sinput_mux; ++ unsigned int cur_smux[2]; ++ unsigned int cur_amux; ++ hda_nid_t *amp_nids; ++ unsigned int num_amps; ++ unsigned int powerdown_adcs; + + /* i/o switches */ + unsigned int io_switch[2]; +@@ -197,6 +223,8 @@ struct sigmatel_spec { + struct snd_kcontrol_new *kctl_alloc; + struct hda_input_mux private_dimux; + struct hda_input_mux private_imux; ++ struct hda_input_mux private_smux; ++ struct hda_input_mux private_amp_mux; + struct hda_input_mux private_mono_mux; + }; + +@@ -217,10 +245,19 @@ static hda_nid_t stac92hd73xx_pwr_nids[8 + 0x0f, 0x10, 0x11 + }; + ++static hda_nid_t stac92hd73xx_slave_dig_outs[2] = { ++ 0x26, 0, ++}; ++ + static hda_nid_t stac92hd73xx_adc_nids[2] = { + 0x1a, 0x1b + }; + ++#define DELL_M6_AMP 2 ++static hda_nid_t stac92hd73xx_amp_nids[3] = { ++ 0x0b, 0x0c, 0x0e ++}; ++ + #define STAC92HD73XX_NUM_DMICS 2 + static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { + 0x13, 0x14, 0 +@@ -239,6 +276,41 @@ static hda_nid_t stac92hd73xx_dmux_nids[ + 0x20, 0x21, + }; + ++static hda_nid_t stac92hd73xx_smux_nids[2] = { ++ 0x22, 0x23, ++}; ++ ++#define STAC92HD83XXX_NUM_DMICS 2 ++static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { ++ 0x11, 0x12, 0 ++}; ++ ++#define STAC92HD81_DAC_COUNT 2 ++#define STAC92HD83_DAC_COUNT 3 ++static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = { ++ 0x13, 0x14, 0x22, ++}; ++ ++static hda_nid_t stac92hd83xxx_dmux_nids[2] = { ++ 0x17, 0x18, ++}; ++ ++static hda_nid_t stac92hd83xxx_adc_nids[2] = { ++ 0x15, 0x16, ++}; ++ ++static hda_nid_t stac92hd83xxx_pwr_nids[4] = { ++ 0xa, 0xb, 0xd, 0xe, ++}; ++ ++static hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { ++ 0x1e, 0, ++}; ++ ++static unsigned int stac92hd83xxx_pwr_mapping[4] = { ++ 0x03, 0x0c, 0x10, 0x40, ++}; ++ + static hda_nid_t stac92hd71bxx_pwr_nids[3] = { + 0x0a, 0x0d, 0x0f + }; +@@ -251,8 +323,12 @@ static hda_nid_t stac92hd71bxx_mux_nids[ + 0x1a, 0x1b + }; + +-static hda_nid_t stac92hd71bxx_dmux_nids[1] = { +- 0x1c, ++static hda_nid_t stac92hd71bxx_dmux_nids[2] = { ++ 0x1c, 0x1d, ++}; ++ ++static hda_nid_t stac92hd71bxx_smux_nids[2] = { ++ 0x24, 0x25, + }; + + static hda_nid_t stac92hd71bxx_dac_nids[1] = { +@@ -264,6 +340,10 @@ static hda_nid_t stac92hd71bxx_dmic_nids + 0x18, 0x19, 0 + }; + ++static hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { ++ 0x22, 0 ++}; ++ + static hda_nid_t stac925x_adc_nids[1] = { + 0x03, + }; +@@ -301,6 +381,10 @@ static hda_nid_t stac927x_mux_nids[3] = + 0x15, 0x16, 0x17 + }; + ++static hda_nid_t stac927x_smux_nids[1] = { ++ 0x21, ++}; ++ + static hda_nid_t stac927x_dac_nids[6] = { + 0x02, 0x03, 0x04, 0x05, 0x06, 0 + }; +@@ -314,6 +398,11 @@ static hda_nid_t stac927x_dmic_nids[STAC + 0x13, 0x14, 0 + }; + ++static const char *stac927x_spdif_labels[5] = { ++ "Digital Playback", "ADAT", "Analog Mux 1", ++ "Analog Mux 2", "Analog Mux 3" ++}; ++ + static hda_nid_t stac9205_adc_nids[2] = { + 0x12, 0x13 + }; +@@ -326,6 +415,10 @@ static hda_nid_t stac9205_dmux_nids[1] = + 0x1d, + }; + ++static hda_nid_t stac9205_smux_nids[1] = { ++ 0x21, ++}; ++ + #define STAC9205_NUM_DMICS 2 + static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { + 0x17, 0x18, 0 +@@ -349,12 +442,18 @@ static hda_nid_t stac922x_pin_nids[10] = + static hda_nid_t stac92hd73xx_pin_nids[13] = { + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, +- 0x14, 0x1e, 0x22 ++ 0x14, 0x22, 0x23 + }; + +-static hda_nid_t stac92hd71bxx_pin_nids[10] = { ++static hda_nid_t stac92hd83xxx_pin_nids[14] = { ++ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, ++ 0x0f, 0x10, 0x11, 0x12, 0x13, ++ 0x1d, 0x1e, 0x1f, 0x20 ++}; ++static hda_nid_t stac92hd71bxx_pin_nids[11] = { + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x14, 0x18, 0x19, 0x1e, ++ 0x1f, + }; + + static hda_nid_t stac927x_pin_nids[14] = { +@@ -369,6 +468,34 @@ static hda_nid_t stac9205_pin_nids[12] = + 0x21, 0x22, + }; + ++#define stac92xx_amp_volume_info snd_hda_mixer_amp_volume_info ++ ++static int stac92xx_amp_volume_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ hda_nid_t nid = spec->amp_nids[spec->cur_amux]; ++ ++ kcontrol->private_value ^= get_amp_nid(kcontrol); ++ kcontrol->private_value |= nid; ++ ++ return snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); ++} ++ ++static int stac92xx_amp_volume_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ hda_nid_t nid = spec->amp_nids[spec->cur_amux]; ++ ++ kcontrol->private_value ^= get_amp_nid(kcontrol); ++ kcontrol->private_value |= nid; ++ ++ return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); ++} ++ + static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) + { +@@ -399,6 +526,58 @@ static int stac92xx_dmux_enum_put(struct + spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]); + } + ++static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ return snd_hda_input_mux_info(spec->sinput_mux, uinfo); ++} ++ ++static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ++ ++ ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx]; ++ return 0; ++} ++ ++static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ struct hda_input_mux *smux = &spec->private_smux; ++ unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ++ int err, val; ++ hda_nid_t nid; ++ ++ err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol, ++ spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]); ++ if (err < 0) ++ return err; ++ ++ if (spec->spdif_mute) { ++ if (smux_idx == 0) ++ nid = spec->multiout.dig_out_nid; ++ else ++ nid = codec->slave_dig_outs[smux_idx - 1]; ++ if (spec->cur_smux[smux_idx] == smux->num_items - 1) ++ val = AMP_OUT_MUTE; ++ if (smux_idx == 0) ++ nid = spec->multiout.dig_out_nid; ++ else ++ nid = codec->slave_dig_outs[smux_idx - 1]; ++ /* un/mute SPDIF out */ ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_AMP_GAIN_MUTE, val); ++ } ++ return 0; ++} ++ + static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) + { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +@@ -454,6 +633,41 @@ static int stac92xx_mono_mux_enum_put(st + spec->mono_nid, &spec->cur_mmux); + } + ++static int stac92xx_amp_mux_enum_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ return snd_hda_input_mux_info(spec->amp_mux, uinfo); ++} ++ ++static int stac92xx_amp_mux_enum_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ ++ ucontrol->value.enumerated.item[0] = spec->cur_amux; ++ return 0; ++} ++ ++static int stac92xx_amp_mux_enum_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ struct snd_kcontrol *ctl = ++ snd_hda_find_mixer_ctl(codec, "Amp Capture Volume"); ++ if (!ctl) ++ return -EINVAL; ++ ++ snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE | ++ SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); ++ ++ return snd_hda_input_mux_put(codec, spec->amp_mux, ucontrol, ++ 0, &spec->cur_amux); ++} ++ + #define stac92xx_aloopback_info snd_ctl_boolean_mono_info + + static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, +@@ -565,8 +779,8 @@ static struct hda_verb dell_m6_core_init + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, + /* setup audio connections */ + { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02}, ++ { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02}, ++ { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -628,12 +842,25 @@ static struct hda_verb stac92hd73xx_10ch + {} + }; + ++static struct hda_verb stac92hd83xxx_core_init[] = { ++ /* start of config #1 */ ++ { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3}, ++ ++ /* start of config #2 */ ++ { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0}, ++ { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0}, ++ { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1}, ++ ++ /* power state controls amps */ ++ { 0x01, AC_VERB_SET_EAPD, 1 << 2}, ++ {} ++}; ++ + static struct hda_verb stac92hd71bxx_core_init[] = { + /* set master volume and direct control */ + { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, + /* connect headphone jack to dac1 */ + { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, +- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ + /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ + { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +@@ -641,13 +868,12 @@ static struct hda_verb stac92hd71bxx_cor + {} + }; + +-#define HD_DISABLE_PORTF 3 ++#define HD_DISABLE_PORTF 2 + static struct hda_verb stac92hd71bxx_analog_core_init[] = { + /* start of config #1 */ + + /* connect port 0f to audio mixer */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, +- { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ + /* unmute right and left channels for node 0x0f */ + { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* start of config #2 */ +@@ -656,10 +882,6 @@ static struct hda_verb stac92hd71bxx_ana + { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, + /* connect headphone jack to dac1 */ + { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, +- /* connect port 0d to audio mixer */ +- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, +- /* unmute dac0 input in audio mixer */ +- { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, + /* unmute right and left channels for nodes 0x0a, 0xd */ + { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +@@ -691,12 +913,16 @@ static struct hda_verb d965_core_init[] + static struct hda_verb stac927x_core_init[] = { + /* set master volume and direct control */ + { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, ++ /* enable analog pc beep path */ ++ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5}, + {} + }; + + static struct hda_verb stac9205_core_init[] = { + /* set master volume and direct control */ + { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, ++ /* enable analog pc beep path */ ++ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5}, + {} + }; + +@@ -710,6 +936,31 @@ static struct hda_verb stac9205_core_ini + .put = stac92xx_mono_mux_enum_put, \ + } + ++#define STAC_AMP_MUX \ ++ { \ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ ++ .name = "Amp Selector Capture Switch", \ ++ .count = 1, \ ++ .info = stac92xx_amp_mux_enum_info, \ ++ .get = stac92xx_amp_mux_enum_get, \ ++ .put = stac92xx_amp_mux_enum_put, \ ++ } ++ ++#define STAC_AMP_VOL(xname, nid, chs, idx, dir) \ ++ { \ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ ++ .name = xname, \ ++ .index = 0, \ ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ ++ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ ++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ ++ .info = stac92xx_amp_volume_info, \ ++ .get = stac92xx_amp_volume_get, \ ++ .put = stac92xx_amp_volume_put, \ ++ .tlv = { .c = snd_hda_mixer_amp_tlv }, \ ++ .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \ ++ } ++ + #define STAC_INPUT_SOURCE(cnt) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ +@@ -737,33 +988,36 @@ static struct snd_kcontrol_new stac9200_ + STAC_INPUT_SOURCE(1), + HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), +- HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), + { } /* end */ + }; + ++#define DELL_M6_MIXER 6 + static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = { +- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), +- ++ /* start of config #1 */ + HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), + +- HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), +- HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), +- + HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), + ++ HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), ++ HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), ++ ++ /* start of config #2 */ ++ HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), ++ + HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), + +- HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), +- HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), ++ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), ++ ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), ++ ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), ++ + { } /* end */ + }; + +@@ -819,22 +1073,59 @@ static struct snd_kcontrol_new stac92hd7 + { } /* end */ + }; + ++ ++static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT), ++ ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT), ++ ++ HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT), ++ HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT), ++ ++ HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT), ++ ++ HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT), ++ HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT), ++ ++ HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT), ++ HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT), ++ ++ /* ++ HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT), ++ */ ++ { } /* end */ ++}; ++ + static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { + STAC_INPUT_SOURCE(2), ++ STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), +- ++ /* analog pc-beep replaced with digital beep support */ ++ /* + HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), ++ */ ++ ++ HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT), ++ ++ HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT), ++ HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT), + +- HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), +- HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), ++ HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT), ++ HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT), ++ ++ HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT), ++ HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT), + { } /* end */ + }; + +@@ -844,11 +1135,9 @@ static struct snd_kcontrol_new stac92hd7 + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), + { } /* end */ + }; + +@@ -856,7 +1145,6 @@ static struct snd_kcontrol_new stac925x_ + STAC_INPUT_SOURCE(1), + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT), +- HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), + { } /* end */ + }; + +@@ -866,12 +1154,9 @@ static struct snd_kcontrol_new stac9205_ + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT), +- + { } /* end */ + }; + +@@ -880,11 +1165,9 @@ static struct snd_kcontrol_new stac922x_ + STAC_INPUT_SOURCE(2), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT), + { } /* end */ + }; + +@@ -895,15 +1178,12 @@ static struct snd_kcontrol_new stac927x_ + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), +- HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT), + { } /* end */ + }; + +@@ -916,6 +1196,15 @@ static struct snd_kcontrol_new stac_dmux + .put = stac92xx_dmux_enum_put, + }; + ++static struct snd_kcontrol_new stac_smux_mixer = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "IEC958 Playback Source", ++ /* count set later */ ++ .info = stac92xx_smux_enum_info, ++ .get = stac92xx_smux_enum_get, ++ .put = stac92xx_smux_enum_put, ++}; ++ + static const char *slave_vols[] = { + "Front Playback Volume", + "Surround Playback Volume", +@@ -967,6 +1256,22 @@ static int stac92xx_build_controls(struc + if (err < 0) + return err; + } ++ if (spec->num_smuxes > 0) { ++ int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid); ++ struct hda_input_mux *smux = &spec->private_smux; ++ /* check for mute support on SPDIF out */ ++ if (wcaps & AC_WCAP_OUT_AMP) { ++ smux->items[smux->num_items].label = "Off"; ++ smux->items[smux->num_items].index = 0; ++ smux->num_items++; ++ spec->spdif_mute = 1; ++ } ++ stac_smux_mixer.count = spec->num_smuxes; ++ err = snd_ctl_add(codec->bus->card, ++ snd_ctl_new1(&stac_smux_mixer, codec)); ++ if (err < 0) ++ return err; ++ } + + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); +@@ -978,7 +1283,7 @@ static int stac92xx_build_controls(struc + return err; + spec->multiout.share_spdif = 1; + } +- if (spec->dig_in_nid) { ++ if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; +@@ -1330,40 +1635,65 @@ static struct snd_pci_quirk stac92hd73xx + {} /* terminator */ + }; + +-static unsigned int ref92hd71bxx_pin_configs[10] = { ++static unsigned int ref92hd83xxx_pin_configs[14] = { ++ 0x02214030, 0x02211010, 0x02a19020, 0x02170130, ++ 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, ++ 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0, ++ 0x01451160, 0x98560170, ++}; ++ ++static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { ++ [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, ++}; ++ ++static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { ++ [STAC_92HD83XXX_REF] = "ref", ++}; ++ ++static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { ++ /* SigmaTel reference board */ ++ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, ++ "DFI LanParty", STAC_92HD71BXX_REF), ++}; ++ ++static unsigned int ref92hd71bxx_pin_configs[11] = { + 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, +- 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0, +- 0x90a000f0, 0x01452050, ++ 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, ++ 0x90a000f0, 0x01452050, 0x01452050, + }; + +-static unsigned int dell_m4_1_pin_configs[10] = { ++static unsigned int dell_m4_1_pin_configs[11] = { + 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, + 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, +- 0x40f000f0, 0x4f0000f0, ++ 0x40f000f0, 0x4f0000f0, 0x4f0000f0, + }; + +-static unsigned int dell_m4_2_pin_configs[10] = { ++static unsigned int dell_m4_2_pin_configs[11] = { + 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, + 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, +- 0x40f000f0, 0x044413b0, ++ 0x40f000f0, 0x044413b0, 0x044413b0, + }; + + static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { + [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, + [STAC_DELL_M4_1] = dell_m4_1_pin_configs, + [STAC_DELL_M4_2] = dell_m4_2_pin_configs, ++ [STAC_HP_M4] = NULL, + }; + + static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { + [STAC_92HD71BXX_REF] = "ref", + [STAC_DELL_M4_1] = "dell-m4-1", + [STAC_DELL_M4_2] = "dell-m4-2", ++ [STAC_HP_M4] = "hp-m4", + }; + + static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD71BXX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, ++ "unknown HP", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, + "unknown Dell", STAC_DELL_M4_1), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, +@@ -1906,6 +2236,8 @@ static int stac92xx_playback_pcm_open(st + struct snd_pcm_substream *substream) + { + struct sigmatel_spec *spec = codec->spec; ++ if (spec->stream_delay) ++ msleep(spec->stream_delay); + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); + } +@@ -1958,7 +2290,6 @@ static int stac92xx_dig_playback_pcm_pre + stream_tag, format, substream); + } + +- + /* + * Analog capture callbacks + */ +@@ -1969,9 +2300,14 @@ static int stac92xx_capture_pcm_prepare( + struct snd_pcm_substream *substream) + { + struct sigmatel_spec *spec = codec->spec; ++ hda_nid_t nid = spec->adc_nids[substream->number]; + +- snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], +- stream_tag, 0, format); ++ if (spec->powerdown_adcs) { ++ msleep(40); ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_POWER_STATE, AC_PWRST_D0); ++ } ++ snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); + return 0; + } + +@@ -1980,8 +2316,12 @@ static int stac92xx_capture_pcm_cleanup( + struct snd_pcm_substream *substream) + { + struct sigmatel_spec *spec = codec->spec; ++ hda_nid_t nid = spec->adc_nids[substream->number]; + +- snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); ++ snd_hda_codec_cleanup_stream(codec, nid); ++ if (spec->powerdown_adcs) ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + return 0; + } + +@@ -2234,6 +2574,8 @@ enum { + STAC_CTL_WIDGET_VOL, + STAC_CTL_WIDGET_MUTE, + STAC_CTL_WIDGET_MONO_MUX, ++ STAC_CTL_WIDGET_AMP_MUX, ++ STAC_CTL_WIDGET_AMP_VOL, + STAC_CTL_WIDGET_HP_SWITCH, + STAC_CTL_WIDGET_IO_SWITCH, + STAC_CTL_WIDGET_CLFE_SWITCH +@@ -2243,13 +2585,16 @@ static struct snd_kcontrol_new stac92xx_ + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), + STAC_MONO_MUX, ++ STAC_AMP_MUX, ++ STAC_AMP_VOL(NULL, 0, 0, 0, 0), + STAC_CODEC_HP_SWITCH(NULL), + STAC_CODEC_IO_SWITCH(NULL, 0), + STAC_CODEC_CLFE_SWITCH(NULL, 0), + }; + + /* add dynamic controls */ +-static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val) ++static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type, ++ int idx, const char *name, unsigned long val) + { + struct snd_kcontrol_new *knew; + +@@ -2269,6 +2614,7 @@ static int stac92xx_add_control(struct s + + knew = &spec->kctl_alloc[spec->num_kctl_used]; + *knew = stac92xx_control_templates[type]; ++ knew->index = idx; + knew->name = kstrdup(name, GFP_KERNEL); + if (! knew->name) + return -ENOMEM; +@@ -2277,6 +2623,14 @@ static int stac92xx_add_control(struct s + return 0; + } + ++ ++/* add dynamic controls */ ++static int stac92xx_add_control(struct sigmatel_spec *spec, int type, ++ const char *name, unsigned long val) ++{ ++ return stac92xx_add_control_idx(spec, type, 0, name, val); ++} ++ + /* flag inputs as additional dynamic lineouts */ + static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg) + { +@@ -2468,7 +2822,7 @@ static int stac92xx_auto_create_multi_ou + static const char *chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; +- hda_nid_t nid; ++ hda_nid_t nid = 0; + int i, err; + + struct sigmatel_spec *spec = codec->spec; +@@ -2508,6 +2862,10 @@ static int stac92xx_auto_create_multi_ou + } + } + ++ if ((spec->multiout.num_dacs - cfg->line_outs) > 0 && ++ cfg->hp_outs && !spec->multiout.hp_nid) ++ spec->multiout.hp_nid = nid; ++ + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_HP_SWITCH, +@@ -2620,8 +2978,8 @@ static int stac92xx_auto_create_hp_ctls( + } + + /* labels for mono mux outputs */ +-static const char *stac92xx_mono_labels[3] = { +- "DAC0", "DAC1", "Mixer" ++static const char *stac92xx_mono_labels[4] = { ++ "DAC0", "DAC1", "Mixer", "DAC2" + }; + + /* create mono mux for mono out on capable codecs */ +@@ -2650,6 +3008,116 @@ static int stac92xx_auto_create_mono_out + "Mono Mux", spec->mono_nid); + } + ++/* labels for amp mux outputs */ ++static const char *stac92xx_amp_labels[3] = { ++ "Front Microphone", "Microphone", "Line In", ++}; ++ ++/* create amp out controls mux on capable codecs */ ++static int stac92xx_auto_create_amp_output_ctls(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct hda_input_mux *amp_mux = &spec->private_amp_mux; ++ int i, err; ++ ++ for (i = 0; i < spec->num_amps; i++) { ++ amp_mux->items[amp_mux->num_items].label = ++ stac92xx_amp_labels[i]; ++ amp_mux->items[amp_mux->num_items].index = i; ++ amp_mux->num_items++; ++ } ++ ++ if (spec->num_amps > 1) { ++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_MUX, ++ "Amp Selector Capture Switch", 0); ++ if (err < 0) ++ return err; ++ } ++ return stac92xx_add_control(spec, STAC_CTL_WIDGET_AMP_VOL, ++ "Amp Capture Volume", ++ HDA_COMPOSE_AMP_VAL(spec->amp_nids[0], 3, 0, HDA_INPUT)); ++} ++ ++ ++/* create PC beep volume controls */ ++static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, ++ hda_nid_t nid) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); ++ int err; ++ ++ /* check for mute support for the the amp */ ++ if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { ++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, ++ "PC Beep Playback Switch", ++ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ } ++ ++ /* check to see if there is volume support for the amp */ ++ if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { ++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, ++ "PC Beep Playback Volume", ++ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ } ++ return 0; ++} ++ ++static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int wcaps, nid, i, err = 0; ++ ++ for (i = 0; i < spec->num_muxes; i++) { ++ nid = spec->mux_nids[i]; ++ wcaps = get_wcaps(codec, nid); ++ ++ if (wcaps & AC_WCAP_OUT_AMP) { ++ err = stac92xx_add_control_idx(spec, ++ STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume", ++ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ } ++ } ++ return 0; ++}; ++ ++static const char *stac92xx_spdif_labels[3] = { ++ "Digital Playback", "Analog Mux 1", "Analog Mux 2", ++}; ++ ++static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct hda_input_mux *spdif_mux = &spec->private_smux; ++ const char **labels = spec->spdif_labels; ++ int i, num_cons; ++ hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; ++ ++ num_cons = snd_hda_get_connections(codec, ++ spec->smux_nids[0], ++ con_lst, ++ HDA_MAX_NUM_INPUTS); ++ if (!num_cons) ++ return -EINVAL; ++ ++ if (!labels) ++ labels = stac92xx_spdif_labels; ++ ++ for (i = 0; i < num_cons; i++) { ++ spdif_mux->items[spdif_mux->num_items].label = labels[i]; ++ spdif_mux->items[spdif_mux->num_items].index = i; ++ spdif_mux->num_items++; ++ } ++ ++ return 0; ++} ++ + /* labels for dmic mux inputs */ + static const char *stac92xx_dmic_labels[5] = { + "Analog Inputs", "Digital Mic 1", "Digital Mic 2", +@@ -2697,16 +3165,19 @@ static int stac92xx_auto_create_dmic_inp + } + continue; + found: +- wcaps = get_wcaps(codec, nid); ++ wcaps = get_wcaps(codec, nid) & ++ (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); + +- if (wcaps & AC_WCAP_OUT_AMP) { ++ if (wcaps) { + sprintf(name, "%s Capture Volume", + stac92xx_dmic_labels[dimux->num_items]); + + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_VOL, + name, +- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); ++ HDA_COMPOSE_AMP_VAL(nid, 3, 0, ++ (wcaps & AC_WCAP_OUT_AMP) ? ++ HDA_OUTPUT : HDA_INPUT)); + if (err < 0) + return err; + } +@@ -2830,8 +3301,8 @@ static int stac92xx_parse_auto_config(st + hp_speaker_swap = 1; + } + if (spec->autocfg.mono_out_pin) { +- int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin) +- & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT; ++ int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & ++ (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); + u32 caps = query_amp_caps(codec, + spec->autocfg.mono_out_pin, dir); + hda_nid_t conn_list[1]; +@@ -2853,21 +3324,26 @@ static int stac92xx_parse_auto_config(st + !(wcaps & AC_WCAP_LR_SWAP)) + spec->mono_nid = conn_list[0]; + } +- /* all mono outs have a least a mute/unmute switch */ +- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, +- "Mono Playback Switch", +- HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin, +- 1, 0, dir)); +- if (err < 0) +- return err; +- /* check to see if there is volume support for the amp */ +- if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { +- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, +- "Mono Playback Volume", +- HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin, +- 1, 0, dir)); ++ if (dir) { ++ hda_nid_t nid = spec->autocfg.mono_out_pin; ++ ++ /* most mono outs have a least a mute/unmute switch */ ++ dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT; ++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, ++ "Mono Playback Switch", ++ HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir)); + if (err < 0) + return err; ++ /* check for volume support for the amp */ ++ if ((caps & AC_AMPCAP_NUM_STEPS) ++ >> AC_AMPCAP_NUM_STEPS_SHIFT) { ++ err = stac92xx_add_control(spec, ++ STAC_CTL_WIDGET_VOL, ++ "Mono Playback Volume", ++ HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir)); ++ if (err < 0) ++ return err; ++ } + } + + stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin, +@@ -2885,6 +3361,28 @@ static int stac92xx_parse_auto_config(st + if (err < 0) + return err; + ++ /* setup analog beep controls */ ++ if (spec->anabeep_nid > 0) { ++ err = stac92xx_auto_create_beep_ctls(codec, ++ spec->anabeep_nid); ++ if (err < 0) ++ return err; ++ } ++ ++ /* setup digital beep controls and input device */ ++#ifdef CONFIG_SND_HDA_INPUT_BEEP ++ if (spec->digbeep_nid > 0) { ++ hda_nid_t nid = spec->digbeep_nid; ++ ++ err = stac92xx_auto_create_beep_ctls(codec, nid); ++ if (err < 0) ++ return err; ++ err = snd_hda_attach_beep_device(codec, nid); ++ if (err < 0) ++ return err; ++ } ++#endif ++ + if (hp_speaker_swap == 1) { + /* Restore the hp_outs and line_outs */ + memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, +@@ -2913,11 +3411,25 @@ static int stac92xx_parse_auto_config(st + if (err < 0) + return err; + } +- +- if (spec->num_dmics > 0) ++ if (spec->num_amps > 0) { ++ err = stac92xx_auto_create_amp_output_ctls(codec); ++ if (err < 0) ++ return err; ++ } ++ if (spec->num_dmics > 0 && !spec->dinput_mux) + if ((err = stac92xx_auto_create_dmic_input_ctls(codec, + &spec->autocfg)) < 0) + return err; ++ if (spec->num_muxes > 0) { ++ err = stac92xx_auto_create_mux_input_ctls(codec); ++ if (err < 0) ++ return err; ++ } ++ if (spec->num_smuxes > 0) { ++ err = stac92xx_auto_create_spdif_mux_ctls(codec); ++ if (err < 0) ++ return err; ++ } + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + if (spec->multiout.max_channels > 2) +@@ -2925,17 +3437,17 @@ static int stac92xx_parse_auto_config(st + + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = dig_out; +- if (spec->autocfg.dig_in_pin) ++ if (dig_in && spec->autocfg.dig_in_pin) + spec->dig_in_nid = dig_in; + + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->input_mux = &spec->private_imux; +- if (!spec->dinput_mux) +- spec->dinput_mux = &spec->private_dimux; ++ spec->dinput_mux = &spec->private_dimux; ++ spec->sinput_mux = &spec->private_smux; + spec->mono_mux = &spec->private_mono_mux; +- ++ spec->amp_mux = &spec->private_amp_mux; + return 1; + } + +@@ -3115,6 +3627,12 @@ static int stac92xx_init(struct hda_code + + snd_hda_sequence_write(codec, spec->init); + ++ /* power down adcs initially */ ++ if (spec->powerdown_adcs) ++ for (i = 0; i < spec->num_adcs; i++) ++ snd_hda_codec_write_cache(codec, ++ spec->adc_nids[i], 0, ++ AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + /* set up pins */ + if (spec->hp_detect) { + /* Enable unsolicited responses on the HP widget */ +@@ -3136,7 +3654,12 @@ static int stac92xx_init(struct hda_code + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = cfg->input_pins[i]; + if (nid) { +- unsigned int pinctl = AC_PINCTL_IN_EN; ++ unsigned int pinctl = snd_hda_codec_read(codec, nid, ++ 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); ++ /* if PINCTL already set then skip */ ++ if (pinctl & AC_PINCAP_IN) ++ continue; ++ pinctl = AC_PINCTL_IN_EN; + if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) + pinctl |= stac92xx_get_vref(codec, nid); + stac92xx_auto_set_pinctl(codec, nid, pinctl); +@@ -3199,6 +3722,7 @@ static void stac92xx_free(struct hda_cod + kfree(spec->bios_pin_configs); + + kfree(spec); ++ snd_hda_detach_beep_device(codec); + } + + static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, +@@ -3320,7 +3844,12 @@ static void stac92xx_pin_sense(struct hd + val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) + & 0x000000ff; + presence = get_hp_pin_presence(codec, nid); +- idx = 1 << idx; ++ ++ /* several codecs have two power down bits */ ++ if (spec->pwr_mapping) ++ idx = spec->pwr_mapping[idx]; ++ else ++ idx = 1 << idx; + + if (presence) + val &= ~idx; +@@ -3336,13 +3865,22 @@ static void stac92xx_unsol_event(struct + struct sigmatel_spec *spec = codec->spec; + int idx = res >> 26 & 0x0f; + +- switch ((res >> 26) & 0x30) { ++ switch ((res >> 26) & 0x70) { + case STAC_HP_EVENT: + stac92xx_hp_detect(codec, res); + /* fallthru */ + case STAC_PWR_EVENT: + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, idx); ++ break; ++ case STAC_VREF_EVENT: { ++ int data = snd_hda_codec_read(codec, codec->afg, 0, ++ AC_VERB_GET_GPIO_DATA, 0); ++ /* toggle VREF state based on GPIOx status */ ++ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, ++ !!(data & (1 << idx))); ++ break; ++ } + } + } + +@@ -3519,9 +4057,9 @@ static struct hda_input_mux stac92hd73xx + .num_items = 4, + .items = { + { "Analog Inputs", 0x0b }, +- { "CD", 0x08 }, + { "Digital Mic 1", 0x09 }, + { "Digital Mic 2", 0x0a }, ++ { "CD", 0x08 }, + } + }; + +@@ -3536,6 +4074,7 @@ static int patch_stac92hd73xx(struct hda + return -ENOMEM; + + codec->spec = spec; ++ codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; + spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); + spec->pin_nids = stac92hd73xx_pin_nids; + spec->board_config = snd_hda_check_board_config(codec, +@@ -3568,17 +4107,14 @@ again: + + switch (spec->multiout.num_dacs) { + case 0x3: /* 6 Channel */ +- spec->multiout.hp_nid = 0x17; + spec->mixer = stac92hd73xx_6ch_mixer; + spec->init = stac92hd73xx_6ch_core_init; + break; + case 0x4: /* 8 Channel */ +- spec->multiout.hp_nid = 0x18; + spec->mixer = stac92hd73xx_8ch_mixer; + spec->init = stac92hd73xx_8ch_core_init; + break; + case 0x5: /* 10 Channel */ +- spec->multiout.hp_nid = 0x19; + spec->mixer = stac92hd73xx_10ch_mixer; + spec->init = stac92hd73xx_10ch_core_init; + }; +@@ -3587,18 +4123,20 @@ again: + spec->aloopback_mask = 0x01; + spec->aloopback_shift = 8; + ++ spec->digbeep_nid = 0x1c; + spec->mux_nids = stac92hd73xx_mux_nids; + spec->adc_nids = stac92hd73xx_adc_nids; + spec->dmic_nids = stac92hd73xx_dmic_nids; + spec->dmux_nids = stac92hd73xx_dmux_nids; ++ spec->smux_nids = stac92hd73xx_smux_nids; ++ spec->amp_nids = stac92hd73xx_amp_nids; ++ spec->num_amps = ARRAY_SIZE(stac92hd73xx_amp_nids); + + spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); + spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); +- spec->dinput_mux = &stac92hd73xx_dmux; +- /* GPIO0 High = Enable EAPD */ +- spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; +- spec->gpio_data = 0x01; ++ memcpy(&spec->private_dimux, &stac92hd73xx_dmux, ++ sizeof(stac92hd73xx_dmux)); + + switch (spec->board_config) { + case STAC_DELL_EQ: +@@ -3607,11 +4145,16 @@ again: + case STAC_DELL_M6: + if (!spec->init) + spec->init = dell_m6_core_init; ++ spec->num_smuxes = 0; ++ spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER]; ++ spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; ++ spec->num_amps = 1; + switch (codec->subsystem_id) { + case 0x1028025e: /* Analog Mics */ + case 0x1028025f: + stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); + spec->num_dmics = 0; ++ spec->private_dimux.num_items = 1; + break; + case 0x10280271: /* Digital Mics */ + case 0x10280272: +@@ -3619,23 +4162,32 @@ again: + case 0x10280255: + stac92xx_set_config_reg(codec, 0x13, 0x90A60160); + spec->num_dmics = 1; ++ spec->private_dimux.num_items = 2; + break; + case 0x10280256: /* Both */ + case 0x10280057: + stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); + stac92xx_set_config_reg(codec, 0x13, 0x90A60160); + spec->num_dmics = 1; ++ spec->private_dimux.num_items = 2; + break; + } + break; + default: + spec->num_dmics = STAC92HD73XX_NUM_DMICS; ++ spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); + } ++ if (spec->board_config > STAC_92HD73XX_REF) { ++ /* GPIO0 High = Enable EAPD */ ++ spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; ++ spec->gpio_data = 0x01; ++ } ++ spec->dinput_mux = &spec->private_dimux; + + spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); + spec->pwr_nids = stac92hd73xx_pwr_nids; + +- err = stac92xx_parse_auto_config(codec, 0x22, 0x24); ++ err = stac92xx_parse_auto_config(codec, 0x25, 0x27); + + if (!err) { + if (spec->board_config < 0) { +@@ -3657,6 +4209,146 @@ again: + return 0; + } + ++static struct hda_input_mux stac92hd83xxx_dmux = { ++ .num_items = 3, ++ .items = { ++ { "Analog Inputs", 0x03 }, ++ { "Digital Mic 1", 0x04 }, ++ { "Digital Mic 2", 0x05 }, ++ } ++}; ++ ++static int patch_stac92hd83xxx(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec; ++ int err; ++ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ codec->spec = spec; ++ codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; ++ spec->mono_nid = 0x19; ++ spec->digbeep_nid = 0x21; ++ spec->dmic_nids = stac92hd83xxx_dmic_nids; ++ spec->dmux_nids = stac92hd83xxx_dmux_nids; ++ spec->adc_nids = stac92hd83xxx_adc_nids; ++ spec->pwr_nids = stac92hd83xxx_pwr_nids; ++ spec->pwr_mapping = stac92hd83xxx_pwr_mapping; ++ spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); ++ spec->multiout.dac_nids = stac92hd83xxx_dac_nids; ++ ++ spec->init = stac92hd83xxx_core_init; ++ switch (codec->vendor_id) { ++ case 0x111d7605: ++ spec->multiout.num_dacs = STAC92HD81_DAC_COUNT; ++ break; ++ default: ++ spec->num_pwrs--; ++ spec->init++; /* switch to config #2 */ ++ spec->multiout.num_dacs = STAC92HD83_DAC_COUNT; ++ } ++ ++ spec->mixer = stac92hd83xxx_mixer; ++ spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); ++ spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids); ++ spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); ++ spec->num_dmics = STAC92HD83XXX_NUM_DMICS; ++ spec->dinput_mux = &stac92hd83xxx_dmux; ++ spec->pin_nids = stac92hd83xxx_pin_nids; ++ spec->board_config = snd_hda_check_board_config(codec, ++ STAC_92HD83XXX_MODELS, ++ stac92hd83xxx_models, ++ stac92hd83xxx_cfg_tbl); ++again: ++ if (spec->board_config < 0) { ++ snd_printdd(KERN_INFO "hda_codec: Unknown model for" ++ " STAC92HD83XXX, using BIOS defaults\n"); ++ err = stac92xx_save_bios_config_regs(codec); ++ if (err < 0) { ++ stac92xx_free(codec); ++ return err; ++ } ++ spec->pin_configs = spec->bios_pin_configs; ++ } else { ++ spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config]; ++ stac92xx_set_config_regs(codec); ++ } ++ ++ err = stac92xx_parse_auto_config(codec, 0x1d, 0); ++ if (!err) { ++ if (spec->board_config < 0) { ++ printk(KERN_WARNING "hda_codec: No auto-config is " ++ "available, default to model=ref\n"); ++ spec->board_config = STAC_92HD83XXX_REF; ++ goto again; ++ } ++ err = -EINVAL; ++ } ++ ++ if (err < 0) { ++ stac92xx_free(codec); ++ return err; ++ } ++ ++ codec->patch_ops = stac92xx_patch_ops; ++ ++ return 0; ++} ++ ++#ifdef SND_HDA_NEEDS_RESUME ++static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int i; ++ snd_hda_codec_write_cache(codec, codec->afg, 0, ++ AC_VERB_SET_POWER_STATE, pwr); ++ ++ msleep(1); ++ for (i = 0; i < spec->num_adcs; i++) { ++ snd_hda_codec_write_cache(codec, ++ spec->adc_nids[i], 0, ++ AC_VERB_SET_POWER_STATE, pwr); ++ } ++}; ++ ++static int stac92hd71xx_resume(struct hda_codec *codec) ++{ ++ stac92hd71xx_set_power_state(codec, AC_PWRST_D0); ++ return stac92xx_resume(codec); ++} ++ ++static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) ++{ ++ stac92hd71xx_set_power_state(codec, AC_PWRST_D3); ++ return 0; ++}; ++ ++#endif ++ ++static struct hda_codec_ops stac92hd71bxx_patch_ops = { ++ .build_controls = stac92xx_build_controls, ++ .build_pcms = stac92xx_build_pcms, ++ .init = stac92xx_init, ++ .free = stac92xx_free, ++ .unsol_event = stac92xx_unsol_event, ++#ifdef SND_HDA_NEEDS_RESUME ++ .resume = stac92hd71xx_resume, ++ .suspend = stac92hd71xx_suspend, ++#endif ++}; ++ ++static struct hda_input_mux stac92hd71bxx_dmux = { ++ .num_items = 4, ++ .items = { ++ { "Analog Inputs", 0x00 }, ++ { "Mixer", 0x01 }, ++ { "Digital Mic 1", 0x02 }, ++ { "Digital Mic 2", 0x03 }, ++ } ++}; ++ + static int patch_stac92hd71bxx(struct hda_codec *codec) + { + struct sigmatel_spec *spec; +@@ -3667,9 +4359,12 @@ static int patch_stac92hd71bxx(struct hd + return -ENOMEM; + + codec->spec = spec; ++ codec->patch_ops = stac92xx_patch_ops; + spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); + spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); + spec->pin_nids = stac92hd71bxx_pin_nids; ++ memcpy(&spec->private_dimux, &stac92hd71bxx_dmux, ++ sizeof(stac92hd71bxx_dmux)); + spec->board_config = snd_hda_check_board_config(codec, + STAC_92HD71BXX_MODELS, + stac92hd71bxx_models, +@@ -3696,47 +4391,101 @@ again: + case 0x111d76b5: + spec->mixer = stac92hd71bxx_mixer; + spec->init = stac92hd71bxx_core_init; ++ codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; + break; + case 0x111d7608: /* 5 Port with Analog Mixer */ ++ switch (codec->subsystem_id) { ++ case 0x103c361a: ++ /* Enable VREF power saving on GPIO1 detect */ ++ snd_hda_codec_write(codec, codec->afg, 0, ++ AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); ++ snd_hda_codec_write_cache(codec, codec->afg, 0, ++ AC_VERB_SET_UNSOLICITED_ENABLE, ++ (AC_USRSP_EN | STAC_VREF_EVENT | 0x01)); ++ spec->gpio_mask |= 0x02; ++ break; ++ } ++ if ((codec->revision_id & 0xf) == 0 || ++ (codec->revision_id & 0xf) == 1) { ++#ifdef SND_HDA_NEEDS_RESUME ++ codec->patch_ops = stac92hd71bxx_patch_ops; ++#endif ++ spec->stream_delay = 40; /* 40 milliseconds */ ++ } ++ + /* no output amps */ + spec->num_pwrs = 0; + spec->mixer = stac92hd71bxx_analog_mixer; ++ spec->dinput_mux = &spec->private_dimux; + + /* disable VSW */ + spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; + stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); + break; + case 0x111d7603: /* 6 Port with Analog Mixer */ ++ if ((codec->revision_id & 0xf) == 1) { ++#ifdef SND_HDA_NEEDS_RESUME ++ codec->patch_ops = stac92hd71bxx_patch_ops; ++#endif ++ spec->stream_delay = 40; /* 40 milliseconds */ ++ } ++ + /* no output amps */ + spec->num_pwrs = 0; + /* fallthru */ + default: ++ spec->dinput_mux = &spec->private_dimux; + spec->mixer = stac92hd71bxx_analog_mixer; + spec->init = stac92hd71bxx_analog_core_init; ++ codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; + } + +- spec->aloopback_mask = 0x20; ++ spec->aloopback_mask = 0x50; + spec->aloopback_shift = 0; + +- /* GPIO0 High = EAPD */ +- spec->gpio_mask = 0x01; +- spec->gpio_dir = 0x01; +- spec->gpio_data = 0x01; ++ if (spec->board_config > STAC_92HD71BXX_REF) { ++ /* GPIO0 = EAPD */ ++ spec->gpio_mask = 0x01; ++ spec->gpio_dir = 0x01; ++ spec->gpio_data = 0x01; ++ } + ++ spec->powerdown_adcs = 1; ++ spec->digbeep_nid = 0x26; + spec->mux_nids = stac92hd71bxx_mux_nids; + spec->adc_nids = stac92hd71bxx_adc_nids; + spec->dmic_nids = stac92hd71bxx_dmic_nids; + spec->dmux_nids = stac92hd71bxx_dmux_nids; ++ spec->smux_nids = stac92hd71bxx_smux_nids; + spec->pwr_nids = stac92hd71bxx_pwr_nids; + + spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); +- spec->num_dmics = STAC92HD71BXX_NUM_DMICS; +- spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); ++ ++ switch (spec->board_config) { ++ case STAC_HP_M4: ++ spec->num_dmics = 0; ++ spec->num_smuxes = 0; ++ spec->num_dmuxes = 0; ++ ++ /* enable internal microphone */ ++ stac92xx_set_config_reg(codec, 0x0e, 0x01813040); ++ stac92xx_auto_set_pinctl(codec, 0x0e, ++ AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); ++ break; ++ default: ++ spec->num_dmics = STAC92HD71BXX_NUM_DMICS; ++ spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids); ++ spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); ++ }; + + spec->multiout.num_dacs = 1; + spec->multiout.hp_nid = 0x11; + spec->multiout.dac_nids = stac92hd71bxx_dac_nids; ++ if (spec->dinput_mux) ++ spec->private_dimux.num_items += ++ spec->num_dmics - ++ (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1); + + err = stac92xx_parse_auto_config(codec, 0x21, 0x23); + if (!err) { +@@ -3754,8 +4503,6 @@ again: + return err; + } + +- codec->patch_ops = stac92xx_patch_ops; +- + return 0; + }; + +@@ -3897,10 +4644,14 @@ static int patch_stac927x(struct hda_cod + stac92xx_set_config_regs(codec); + } + ++ spec->digbeep_nid = 0x23; + spec->adc_nids = stac927x_adc_nids; + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); + spec->mux_nids = stac927x_mux_nids; + spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); ++ spec->smux_nids = stac927x_smux_nids; ++ spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids); ++ spec->spdif_labels = stac927x_spdif_labels; + spec->dac_list = stac927x_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; + +@@ -3943,9 +4694,11 @@ static int patch_stac927x(struct hda_cod + spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); + break; + default: +- /* GPIO0 High = Enable EAPD */ +- spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; +- spec->gpio_data = 0x01; ++ if (spec->board_config > STAC_D965_REF) { ++ /* GPIO0 High = Enable EAPD */ ++ spec->eapd_mask = spec->gpio_mask = 0x01; ++ spec->gpio_dir = spec->gpio_data = 0x01; ++ } + spec->num_dmics = 0; + + spec->init = stac927x_core_init; +@@ -4017,10 +4770,13 @@ static int patch_stac9205(struct hda_cod + stac92xx_set_config_regs(codec); + } + ++ spec->digbeep_nid = 0x23; + spec->adc_nids = stac9205_adc_nids; + spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); + spec->mux_nids = stac9205_mux_nids; + spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); ++ spec->smux_nids = stac9205_smux_nids; ++ spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids); + spec->dmic_nids = stac9205_dmic_nids; + spec->num_dmics = STAC9205_NUM_DMICS; + spec->dmux_nids = stac9205_dmux_nids; +@@ -4056,6 +4812,9 @@ static int patch_stac9205(struct hda_cod + */ + spec->gpio_data = 0x01; + break; ++ case STAC_9205_REF: ++ /* SPDIF-In enabled */ ++ break; + default: + /* GPIO0 High = EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; +@@ -4375,6 +5134,8 @@ struct hda_codec_preset snd_hda_preset_s + { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, + { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, + { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, ++ { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, ++ { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, + { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, + { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-vref-event-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-vref-event-fix new file mode 100644 index 000000000..662468c7c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sigmatel-vref-event-fix @@ -0,0 +1,36 @@ +From: Matthew Ranostay +Subject: ALSA: hda: STAC_VREF_EVENT value change +Patch-mainline: +References: bnc#444349 + +Changed value for STAC_VREF_EVENT from 0x40 to 0x00 because the +unsol response value is only 6-bits width and the former value +was 1<<6 which is an overrun. + +Signed-off-by: Matthew Ranostay +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c +index 1633ef2..f205570 100644 +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -36,9 +36,11 @@ + #include "hda_beep.h" + + #define NUM_CONTROL_ALLOC 32 ++ ++#define STAC_VREF_EVENT 0x00 ++#define STAC_INSERT_EVENT 0x10 + #define STAC_PWR_EVENT 0x20 + #define STAC_HP_EVENT 0x30 +-#define STAC_VREF_EVENT 0x40 + + enum { + STAC_REF, +-- +1.6.0.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sony-vaio-vgn-sr19xn-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sony-vaio-vgn-sr19xn-quirk new file mode 100644 index 000000000..f87cbeef0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-sony-vaio-vgn-sr19xn-quirk @@ -0,0 +1,26 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add quirk for Sony VAIO VGN-SR19XN +Patch-mainline: +References: bnc#450080 + +Added model=sony-assamd for Sony VAIO VGN-SR19XN with ALC262 codec. +Reference: Novell bnc#450080 + https://bugzilla.novell.com/show_bug.cgi?id=450080 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10477,6 +10477,8 @@ static struct snd_pci_quirk alc262_cfg_t + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), ++ SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN", ++ ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", + ALC262_TOSHIBA_RX1), + SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-bits-cache-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-bits-cache-fix new file mode 100644 index 000000000..d8dfe7332 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-bits-cache-fix @@ -0,0 +1,36 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix caching of SPDIF status bits +Patch-mainline: +References: + +SPDIF status bits controls are written via snd_hda_codec_write() +without caching. This causes a regression at resume that the bits +are lost. + +Simply replacing it with the cached version fixes the problem. + +Reference: http://lkml.org/lkml/2008/11/24/324 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -1430,12 +1430,12 @@ static void set_dig_out(struct hda_codec + { + hda_nid_t *d; + +- snd_hda_codec_write(codec, nid, 0, verb, val); ++ snd_hda_codec_write_cache(codec, nid, 0, verb, val); + d = codec->slave_dig_outs; + if (!d) + return; + for (; *d; d++) +- snd_hda_codec_write(codec, *d, 0, verb, val); ++ snd_hda_codec_write_cache(codec, *d, 0, verb, val); + } + + static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-slave b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-slave new file mode 100644 index 000000000..ecfafcffb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-slave @@ -0,0 +1,334 @@ +From: Takashi Iwai +Subject: ALSA: hda - Slave SPDIF support +Patch-mainline: 2.6.28-rc1 +References: + +Add the support of slave SPDIF outputs for multiple SPDIF devices. + +Signed-off-by: Takashi Iwai + +--- +--- + sound/pci/hda/hda_codec.c | 72 ++++++++++++++++++++++++++----------- + sound/pci/hda/hda_codec.h | 89 +++++++++++++++++++++++++++++++++++++++++++--- + sound/pci/hda/hda_local.h | 15 ++++--- + 3 files changed, 146 insertions(+), 30 deletions(-) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -1430,6 +1430,29 @@ static unsigned int convert_to_spdif_sta + return sbits; + } + ++/* set digital convert verbs both for the given NID and its slaves */ ++static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, ++ int verb, int val) ++{ ++ hda_nid_t *d; ++ ++ snd_hda_codec_write(codec, nid, 0, verb, val); ++ d = codec->slave_dig_outs; ++ if (!d) ++ return; ++ for (; *d; d++) ++ snd_hda_codec_write(codec, *d, 0, verb, val); ++} ++ ++static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid, ++ int dig1, int dig2) ++{ ++ if (dig1 != -1) ++ set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1); ++ if (dig2 != -1) ++ set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2); ++} ++ + static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +@@ -1448,14 +1471,8 @@ static int snd_hda_spdif_default_put(str + change = codec->spdif_ctls != val; + codec->spdif_ctls = val; + +- if (change) { +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_DIGI_CONVERT_1, +- val & 0xff); +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_DIGI_CONVERT_2, +- val >> 8); +- } ++ if (change) ++ set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); + + mutex_unlock(&codec->spdif_mutex); + return change; +@@ -1487,9 +1504,7 @@ static int snd_hda_spdif_out_switch_put( + change = codec->spdif_ctls != val; + if (change) { + codec->spdif_ctls = val; +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_DIGI_CONVERT_1, +- val & 0xff); ++ set_dig_out_convert(codec, nid, val & 0xff, -1); + /* unmute amp switch (if any) */ + if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && + (val & AC_DIG1_ENABLE)) +@@ -2583,14 +2598,31 @@ static void setup_dig_out_stream(struct + unsigned int stream_tag, unsigned int format) + { + /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ +- if (codec->spdif_ctls & AC_DIG1_ENABLE) +- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, +- codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); ++ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) ++ set_dig_out_convert(codec, nid, ++ codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, ++ -1); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); ++ if (codec->slave_dig_outs) { ++ hda_nid_t *d; ++ for (d = codec->slave_dig_outs; *d; d++) ++ snd_hda_codec_setup_stream(codec, *d, stream_tag, 0, ++ format); ++ } + /* turn on again (if needed) */ +- if (codec->spdif_ctls & AC_DIG1_ENABLE) +- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, +- codec->spdif_ctls & 0xff); ++ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) ++ set_dig_out_convert(codec, nid, ++ codec->spdif_ctls & 0xff, -1); ++} ++ ++static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) ++{ ++ snd_hda_codec_cleanup_stream(codec, nid); ++ if (codec->slave_dig_outs) { ++ hda_nid_t *d; ++ for (d = codec->slave_dig_outs; *d; d++) ++ snd_hda_codec_cleanup_stream(codec, *d); ++ } + } + + /* +@@ -2602,7 +2634,7 @@ int snd_hda_multi_out_dig_open(struct hd + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) + /* already opened as analog dup; reset it once */ +- snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); ++ cleanup_dig_out_stream(codec, mout->dig_out_nid); + mout->dig_out_used = HDA_DIG_EXCLUSIVE; + mutex_unlock(&codec->spdif_mutex); + return 0; +@@ -2697,7 +2729,7 @@ int snd_hda_multi_out_analog_prepare(str + stream_tag, format); + } else { + mout->dig_out_used = 0; +- snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); ++ cleanup_dig_out_stream(codec, mout->dig_out_nid); + } + } + mutex_unlock(&codec->spdif_mutex); +@@ -2748,7 +2780,7 @@ int snd_hda_multi_out_analog_cleanup(str + mout->extra_out_nid[i]); + mutex_lock(&codec->spdif_mutex); + if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { +- snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); ++ cleanup_dig_out_stream(codec, mout->dig_out_nid); + mout->dig_out_used = 0; + } + mutex_unlock(&codec->spdif_mutex); +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -90,6 +90,14 @@ enum { + #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c + /* f20: AFG/MFG */ + #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 ++#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d ++#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e ++#define AC_VERB_GET_HDMI_ELDD 0x0f2f ++#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 ++#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 ++#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 ++#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 ++#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 + + /* + * SET verbs +@@ -121,7 +129,14 @@ enum { + #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d + #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e + #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f ++#define AC_VERB_SET_EAPD 0x788 + #define AC_VERB_SET_CODEC_RESET 0x7ff ++#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d ++#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 ++#define AC_VERB_SET_HDMI_DIP_DATA 0x731 ++#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 ++#define AC_VERB_SET_HDMI_CP_CTRL 0x733 ++#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 + + /* + * Parameter IDs +@@ -143,6 +158,7 @@ enum { + #define AC_PAR_GPIO_CAP 0x11 + #define AC_PAR_AMP_OUT_CAP 0x12 + #define AC_PAR_VOL_KNB_CAP 0x13 ++#define AC_PAR_HDMI_LPCM_CAP 0x20 + + /* + * AC_VERB_PARAMETERS results (32bit) +@@ -171,6 +187,8 @@ enum { + #define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ + #define AC_WCAP_POWER (1<<10) /* power control */ + #define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ ++#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ ++#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ + #define AC_WCAP_DELAY (0xf<<16) + #define AC_WCAP_DELAY_SHIFT 16 + #define AC_WCAP_TYPE (0xf<<20) +@@ -206,9 +224,20 @@ enum { + /* Input converter SDI select */ + #define AC_SDI_SELECT (0xf<<0) + +-/* Unsolicited response */ ++/* Unsolicited response control */ + #define AC_UNSOL_TAG (0x3f<<0) + #define AC_UNSOL_ENABLED (1<<7) ++#define AC_USRSP_EN AC_UNSOL_ENABLED ++ ++/* Unsolicited responses */ ++#define AC_UNSOL_RES_TAG (0x3f<<26) ++#define AC_UNSOL_RES_TAG_SHIFT 26 ++#define AC_UNSOL_RES_SUBTAG (0x1f<<21) ++#define AC_UNSOL_RES_SUBTAG_SHIFT 21 ++#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ ++#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ ++#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ ++#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ + + /* Pin widget capabilies */ + #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ +@@ -222,6 +251,10 @@ enum { + * but is marked reserved in the Intel HDA specification. + */ + #define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ ++/* Note: The same bit as LR_SWAP is newly defined as HDMI capability ++ * in HD-audio specification ++ */ ++#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ + #define AC_PINCAP_VREF (0x37<<8) + #define AC_PINCAP_VREF_SHIFT 8 + #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ +@@ -272,6 +305,22 @@ enum { + #define AC_KNBCAP_NUM_STEPS (0x7f<<0) + #define AC_KNBCAP_DELTA (1<<7) + ++/* HDMI LPCM capabilities */ ++#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ ++#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ ++#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ ++#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ ++#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ ++#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ ++#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ ++#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ ++#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ ++#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ ++#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ ++#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ ++#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ ++#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ ++ + /* + * Control Parameters + */ +@@ -317,18 +366,44 @@ enum { + #define AC_PINCTL_OUT_EN (1<<6) + #define AC_PINCTL_HP_EN (1<<7) + +-/* Unsolicited response - 8bit */ +-#define AC_USRSP_EN (1<<7) +- + /* Pin sense - 32bit */ + #define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) + #define AC_PINSENSE_PRESENCE (1<<31) ++#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ + + /* EAPD/BTL enable - 32bit */ + #define AC_EAPDBTL_BALANCED (1<<0) + #define AC_EAPDBTL_EAPD (1<<1) + #define AC_EAPDBTL_LR_SWAP (1<<2) + ++/* HDMI ELD data */ ++#define AC_ELDD_ELD_VALID (1<<31) ++#define AC_ELDD_ELD_DATA 0xff ++ ++/* HDMI DIP size */ ++#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ ++#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ ++ ++/* HDMI DIP index */ ++#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ ++#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ ++ ++/* HDMI DIP xmit (transmit) control */ ++#define AC_DIPXMIT_MASK (0x3<<6) ++#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ ++#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ ++#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ ++ ++/* HDMI content protection (CP) control */ ++#define AC_CPCTRL_CES (1<<9) /* current encryption state */ ++#define AC_CPCTRL_READY (1<<8) /* ready bit */ ++#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ ++#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ ++ ++/* Converter channel <-> HDMI slot mapping */ ++#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ ++#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ ++ + /* configuration default - 32bit */ + #define AC_DEFCFG_SEQUENCE (0xf<<0) + #define AC_DEFCFG_DEF_ASSOC (0xf<<4) +@@ -650,9 +725,15 @@ struct hda_codec { + unsigned int spdif_status; /* IEC958 status bits */ + unsigned short spdif_ctls; /* SPDIF control bits */ + unsigned int spdif_in_enable; /* SPDIF input enable? */ ++ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ + + struct snd_hwdep *hwdep; /* assigned hwdep device */ + ++ /* misc flags */ ++ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each ++ * status change ++ * (e.g. Realtek codecs) ++ */ + #ifdef CONFIG_SND_HDA_POWER_SAVE + unsigned int power_on :1; /* current (global) power-state */ + unsigned int power_transition :1; /* power-state in transition */ +--- a/sound/pci/hda/hda_local.h ++++ b/sound/pci/hda/hda_local.h +@@ -368,12 +368,15 @@ int snd_hda_parse_pin_def_config(struct + #define AMP_OUT_UNMUTE 0xb000 + #define AMP_OUT_ZERO 0xb000 + /* pinctl values */ +-#define PIN_IN 0x20 +-#define PIN_VREF80 0x24 +-#define PIN_VREF50 0x21 +-#define PIN_OUT 0x40 +-#define PIN_HP 0xc0 +-#define PIN_HP_AMP 0x80 ++#define PIN_IN (AC_PINCTL_IN_EN) ++#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) ++#define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50) ++#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) ++#define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80) ++#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) ++#define PIN_OUT (AC_PINCTL_OUT_EN) ++#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN) ++#define PIN_HP_AMP (AC_PINCTL_HP_EN) + + /* + * get widget capabilities diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-92hd71bxx-gpio-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-92hd71bxx-gpio-fix new file mode 100644 index 000000000..974aecda5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-92hd71bxx-gpio-fix @@ -0,0 +1,44 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix GPIO initialization in patch_stac92hd71bxx() +Patch-mainline: +References: bnc#445321,bnc#445161 + +Fixed the GPIO mask and co initialization in patch_stac92hd71bxx() +so that the gpio_maks for HP_M4 model is set properly. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -4482,6 +4482,13 @@ again: + stac92xx_set_config_regs(codec); + } + ++ if (spec->board_config > STAC_92HD71BXX_REF) { ++ /* GPIO0 = EAPD */ ++ spec->gpio_mask = 0x01; ++ spec->gpio_dir = 0x01; ++ spec->gpio_data = 0x01; ++ } ++ + switch (codec->vendor_id) { + case 0x111d76b6: /* 4 Port without Analog Mixer */ + case 0x111d76b7: +@@ -4541,13 +4548,6 @@ again: + spec->aloopback_mask = 0x50; + spec->aloopback_shift = 0; + +- if (spec->board_config > STAC_92HD71BXX_REF) { +- /* GPIO0 = EAPD */ +- spec->gpio_mask = 0x01; +- spec->gpio_dir = 0x01; +- spec->gpio_data = 0x01; +- } +- + spec->powerdown_adcs = 1; + spec->digbeep_nid = 0x26; + spec->mux_nids = stac92hd71bxx_mux_nids; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-dell-m4-3-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-dell-m4-3-quirk new file mode 100644 index 000000000..228d21e67 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-dell-m4-3-quirk @@ -0,0 +1,98 @@ +From: Matthew Ranostay +Subject: ALSA: hda: Add STAC_DELL_M4_3 quirk +Patch-mainline: +References: bnc#446025 + +Added STAC_DELL_M4_3 quirk for Dell systems, also reorganized the +board config switch to assign number of digital muxes, microphones, +and SPDIF muxes via the PCI quirk defined. + +Signed-off-by: Matthew Ranostay +Signed-off-by: Takashi Iwai + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_sigmatel.c | 26 ++++++++++++++++++++---- + 2 files changed, 23 insertions(+), 4 deletions(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -1076,6 +1076,7 @@ Prior to version 0.9.0rc4 options had a + ref Reference board + dell-m4-1 Dell desktops + dell-m4-2 Dell desktops ++ dell-m4-3 Dell desktops + + STAC92HD73* + ref Reference board +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -84,6 +84,7 @@ enum { + STAC_92HD71BXX_REF, + STAC_DELL_M4_1, + STAC_DELL_M4_2, ++ STAC_DELL_M4_3, + STAC_HP_M4, + STAC_92HD71BXX_MODELS + }; +@@ -1675,10 +1676,17 @@ static unsigned int dell_m4_2_pin_config + 0x40f000f0, 0x044413b0, 0x044413b0, + }; + ++static unsigned int dell_m4_3_pin_configs[11] = { ++ 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, ++ 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, ++ 0x40f000f0, 0x044413b0, 0x044413b0, ++}; ++ + static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { + [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, + [STAC_DELL_M4_1] = dell_m4_1_pin_configs, + [STAC_DELL_M4_2] = dell_m4_2_pin_configs, ++ [STAC_DELL_M4_3] = dell_m4_3_pin_configs, + [STAC_HP_M4] = NULL, + }; + +@@ -1686,6 +1694,7 @@ static const char *stac92hd71bxx_models[ + [STAC_92HD71BXX_REF] = "ref", + [STAC_DELL_M4_1] = "dell-m4-1", + [STAC_DELL_M4_2] = "dell-m4-2", ++ [STAC_DELL_M4_3] = "dell-m4-3", + [STAC_HP_M4] = "hp-m4", + }; + +@@ -1721,6 +1730,8 @@ static struct snd_pci_quirk stac92hd71bx + "unknown Dell", STAC_DELL_M4_2), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264, + "unknown Dell", STAC_DELL_M4_2), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa, ++ "unknown Dell", STAC_DELL_M4_3), + {} /* terminator */ + }; + +@@ -4575,14 +4586,21 @@ again: + + switch (spec->board_config) { + case STAC_HP_M4: +- spec->num_dmics = 0; +- spec->num_smuxes = 0; +- spec->num_dmuxes = 0; +- + /* enable internal microphone */ + stac92xx_set_config_reg(codec, 0x0e, 0x01813040); + stac92xx_auto_set_pinctl(codec, 0x0e, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); ++ /* fallthru */ ++ case STAC_DELL_M4_2: ++ spec->num_dmics = 0; ++ spec->num_smuxes = 0; ++ spec->num_dmuxes = 0; ++ break; ++ case STAC_DELL_M4_1: ++ case STAC_DELL_M4_3: ++ spec->num_dmics = 1; ++ spec->num_smuxes = 0; ++ spec->num_dmuxes = 0; + break; + default: + spec->num_dmics = STAC92HD71BXX_NUM_DMICS; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-gpio-unsol-resume-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-gpio-unsol-resume-fix new file mode 100644 index 000000000..8b68d232b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-gpio-unsol-resume-fix @@ -0,0 +1,34 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix resume of GPIO unsol event for STAC/IDT +Patch-mainline: +References: bnc#445321,bnc#445161 + +Use cached write for setting the GPIO unsolicited event mask to be +restored properly at resume. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -4506,7 +4506,7 @@ again: + switch (spec->board_config) { + case STAC_HP_M4: + /* Enable VREF power saving on GPIO1 detect */ +- snd_hda_codec_write(codec, codec->afg, 0, ++ snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, +@@ -4899,7 +4899,7 @@ static int patch_stac9205(struct hda_cod + stac92xx_set_config_reg(codec, 0x20, 0x1c410030); + + /* Enable unsol response for GPIO4/Dock HP connection */ +- snd_hda_codec_write(codec, codec->afg, 0, ++ snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-detect-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-detect-fix new file mode 100644 index 000000000..25cad4a7d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-detect-fix @@ -0,0 +1,153 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix IDT/STAC multiple HP detection +Patch-mainline: +References: bnc#443267 + +Due to the recent change for multiple HP as line-out switch, only +one of the multiple headphons (usually a wrong one) is toggled +and the other pins are still disabled. This causes the silent output +problem on some Dell laptops. + +Also, the hp_switch check is screwed up when a line-in or a mic-in +jack exists. This is added as an additional output, but hp_switch +check doesn't take it into account. + +This patch fixes these issues: simplify hp_switch check by using +the NID instead of bool, and clean up / fix the toggle of HP pins +in unsol event handler code. + +Reference: Novell bnc#443267 + https://bugzilla.novell.com/show_bug.cgi?id=443267 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 57 +++++++++++++++++++++++++++++++---------- + 1 file changed, 44 insertions(+), 13 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -212,7 +212,7 @@ struct sigmatel_spec { + /* i/o switches */ + unsigned int io_switch[2]; + unsigned int clfe_swap; +- unsigned int hp_switch; ++ unsigned int hp_switch; /* NID of HP as line-out */ + unsigned int aloopback; + + struct hda_pcm pcm_rec[2]; /* PCM information */ +@@ -2448,7 +2448,7 @@ static int stac92xx_hp_switch_get(struct + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + +- ucontrol->value.integer.value[0] = spec->hp_switch; ++ ucontrol->value.integer.value[0] = !!spec->hp_switch; + return 0; + } + +@@ -2457,8 +2457,9 @@ static int stac92xx_hp_switch_put(struct + { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; ++ int nid = kcontrol->private_value; + +- spec->hp_switch = ucontrol->value.integer.value[0]; ++ spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; + + /* check to be sure that the ports are upto date with + * switch changes +@@ -2867,7 +2868,8 @@ static int stac92xx_auto_create_multi_ou + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_HP_SWITCH, +- "Headphone as Line Out Switch", 0); ++ "Headphone as Line Out Switch", ++ cfg->hp_pins[cfg->hp_outs - 1]); + if (err < 0) + return err; + } +@@ -3791,11 +3793,30 @@ static int get_hp_pin_presence(struct hd + return 0; + } + ++/* return non-zero if the hp-pin of the given array index isn't ++ * a jack-detection target ++ */ ++static int no_hp_sensing(struct sigmatel_spec *spec, int i) ++{ ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ ++ /* ignore sensing of shared line and mic jacks */ ++ if (spec->line_switch && ++ cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) ++ return 1; ++ if (spec->mic_switch && ++ cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) ++ return 1; ++ /* ignore if the pin is set as line-out */ ++ if (cfg->hp_pins[i] == spec->hp_switch) ++ return 1; ++ return 0; ++} ++ + static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) + { + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; +- int nid = cfg->hp_pins[cfg->hp_outs - 1]; + int i, presence; + + presence = 0; +@@ -3806,15 +3827,16 @@ static void stac92xx_hp_detect(struct hd + for (i = 0; i < cfg->hp_outs; i++) { + if (presence) + break; +- if (spec->hp_switch && cfg->hp_pins[i] == nid) +- break; ++ if (no_hp_sensing(spec, i)) ++ continue; + presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); + } + + if (presence) { +- /* disable lineouts, enable hp */ ++ /* disable lineouts */ + if (spec->hp_switch) +- stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); ++ stac92xx_reset_pinctl(codec, spec->hp_switch, ++ AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->line_outs; i++) + stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], + AC_PINCTL_OUT_EN); +@@ -3826,9 +3848,10 @@ static void stac92xx_hp_detect(struct hd + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); + } else { +- /* enable lineouts, disable hp */ ++ /* enable lineouts */ + if (spec->hp_switch) +- stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); ++ stac92xx_set_pinctl(codec, spec->hp_switch, ++ AC_PINCTL_OUT_EN); + for (i = 0; i < cfg->line_outs; i++) + stac92xx_set_pinctl(codec, cfg->line_out_pins[i], + AC_PINCTL_OUT_EN); +@@ -3840,8 +3863,16 @@ static void stac92xx_hp_detect(struct hd + spec->gpio_dir, spec->gpio_data | + spec->eapd_mask); + } +- if (!spec->hp_switch && cfg->hp_outs > 1 && presence) +- stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); ++ /* toggle hp outs */ ++ for (i = 0; i < cfg->hp_outs; i++) { ++ unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; ++ if (no_hp_sensing(spec, i)) ++ continue; ++ if (presence) ++ stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); ++ else ++ stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); ++ } + } + + static void stac92xx_pin_sense(struct hda_codec *codec, int idx) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-gpio-switch-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-gpio-switch-fix new file mode 100644 index 000000000..e11c91844 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-gpio-switch-fix @@ -0,0 +1,93 @@ +From: Matthew Ranostay +Subject: ALSA: hda: STAC_DELL_M6 EAPD +Patch-mainline: +References: bnc#446025 + +Add support for EAPD on system suspend and disabling EAPD on headphone jack +detection for STAC_DELL_M6 laptops. + +This patch fixes the regressions, the silent output on HP of some Dell +laptops (see Novell bnc#446025): + https://bugzilla.novell.com/show_bug.cgi?id=446025 + +Signed-off-by: Matthew Ranostay +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -137,6 +137,7 @@ struct sigmatel_spec { + unsigned int num_mixers; + + int board_config; ++ unsigned int eapd_switch: 1; + unsigned int surr_switch: 1; + unsigned int line_switch: 1; + unsigned int mic_switch: 1; +@@ -3906,7 +3907,7 @@ static void stac92xx_hp_detect(struct hd + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); +- if (spec->eapd_mask) ++ if (spec->eapd_mask && spec->eapd_switch) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); +@@ -3921,7 +3922,7 @@ static void stac92xx_hp_detect(struct hd + for (i = 0; i < cfg->speaker_outs; i++) + stac92xx_set_pinctl(codec, cfg->speaker_pins[i], + AC_PINCTL_OUT_EN); +- if (spec->eapd_mask) ++ if (spec->eapd_mask && spec->eapd_switch) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data | + spec->eapd_mask); +@@ -4250,6 +4251,7 @@ again: + spec->num_smuxes = 0; + spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER]; + spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; ++ spec->eapd_switch = 0; + spec->num_amps = 1; + switch (codec->subsystem_id) { + case 0x1028025e: /* Analog Mics */ +@@ -4278,6 +4280,7 @@ again: + default: + spec->num_dmics = STAC92HD73XX_NUM_DMICS; + spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); ++ spec->eapd_switch = 1; + } + if (spec->board_config > STAC_92HD73XX_REF) { + /* GPIO0 High = Enable EAPD */ +@@ -4423,7 +4426,13 @@ static int stac92hd71xx_resume(struct hd + + static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) + { ++ struct sigmatel_spec *spec = codec->spec; ++ + stac92hd71xx_set_power_state(codec, AC_PWRST_D3); ++ if (spec->eapd_mask) ++ stac_gpio_set(codec, spec->gpio_mask, ++ spec->gpio_dir, spec->gpio_data & ++ ~spec->eapd_mask); + return 0; + }; + +@@ -4810,6 +4819,7 @@ static int patch_stac927x(struct hda_cod + spec->num_pwrs = 0; + spec->aloopback_mask = 0x40; + spec->aloopback_shift = 0; ++ spec->eapd_switch = 1; + + err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); + if (!err) { +@@ -4890,6 +4900,7 @@ static int patch_stac9205(struct hda_cod + + spec->aloopback_mask = 0x40; + spec->aloopback_shift = 0; ++ spec->eapd_switch = 1; + spec->multiout.dac_nids = spec->dac_nids; + + switch (spec->board_config){ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-pavilion-quirks b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-pavilion-quirks new file mode 100644 index 000000000..b259b9e7c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-hp-pavilion-quirks @@ -0,0 +1,30 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add quirks for HP Pavilion DV models +Patch-mainline: +References: bnc#445321,bnc#445161 + +Added the quirk entries for HP Pavilion DV5 and DV7 with model=hp-m4. + +Reference: Novell bnc#445321, bnc#445161 + https://bugzilla.novell.com/show_bug.cgi?id=445321 + https://bugzilla.novell.com/show_bug.cgi?id=445161 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1692,6 +1692,10 @@ static struct snd_pci_quirk stac92hd71bx + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD71BXX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2, ++ "HP dv5", STAC_HP_M4), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, ++ "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, + "unknown HP", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-reduce-volume-scale b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-reduce-volume-scale new file mode 100644 index 000000000..f578781c8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-reduce-volume-scale @@ -0,0 +1,132 @@ +From 7c7767ebe2fa847c91a0dd5551ca422aba359473 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 20 Jan 2009 15:28:38 +0100 +Subject: ALSA: hda - Halve too large volume scales for STAC/IDT codecs +Patch-mainline: +References: bnc#466428 + +STAC/IDT codecs have often too large volume scales such as -96dB, +and exposing this as is results in too large scale in percentage +representation. + +This patch adds the check of the volume scale and halves the +volume range if it's too large automatically. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 41 +++++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -155,6 +155,7 @@ struct sigmatel_spec { + unsigned int alt_switch: 1; + unsigned int hp_detect: 1; + unsigned int spdif_mute: 1; ++ unsigned int check_volume_offset:1; + + /* gpio lines */ + unsigned int eapd_mask; +@@ -183,6 +184,8 @@ struct sigmatel_spec { + struct hda_multi_out multiout; + hda_nid_t dac_nids[5]; + ++ int volume_offset; ++ + /* capture */ + hda_nid_t *adc_nids; + unsigned int num_adcs; +@@ -1310,6 +1313,8 @@ static int stac92xx_build_controls(struc + unsigned int vmaster_tlv[4]; + snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], + HDA_OUTPUT, vmaster_tlv); ++ /* correct volume offset */ ++ vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + vmaster_tlv, slave_vols); + if (err < 0) +@@ -2885,14 +2890,34 @@ static int stac92xx_auto_fill_dac_nids(s + } + + /* create volume control/switch for the given prefx type */ +-static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) ++static int create_controls(struct hda_codec *codec, const char *pfx, ++ hda_nid_t nid, int chs) + { ++ struct sigmatel_spec *spec = codec->spec; + char name[32]; + int err; + ++ if (!spec->check_volume_offset) { ++ unsigned int caps, step, nums, db_scale; ++ caps = query_amp_caps(codec, nid, HDA_OUTPUT); ++ step = (caps & AC_AMPCAP_STEP_SIZE) >> ++ AC_AMPCAP_STEP_SIZE_SHIFT; ++ step = (step + 1) * 25; /* in .01dB unit */ ++ nums = (caps & AC_AMPCAP_NUM_STEPS) >> ++ AC_AMPCAP_NUM_STEPS_SHIFT; ++ db_scale = nums * step; ++ /* if dB scale is over -64dB, and finer enough, ++ * let's reduce it to half ++ */ ++ if (db_scale > 6400 && nums >= 0x1f) ++ spec->volume_offset = nums / 2; ++ spec->check_volume_offset = 1; ++ } ++ + sprintf(name, "%s Playback Volume", pfx); + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, +- HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); ++ HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, ++ spec->volume_offset)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", pfx); +@@ -2948,10 +2973,10 @@ static int stac92xx_auto_create_multi_ou + + if (i == 2) { + /* Center/LFE */ +- err = create_controls(spec, "Center", nid, 1); ++ err = create_controls(codec, "Center", nid, 1); + if (err < 0) + return err; +- err = create_controls(spec, "LFE", nid, 2); ++ err = create_controls(codec, "LFE", nid, 2); + if (err < 0) + return err; + +@@ -2967,7 +2992,7 @@ static int stac92xx_auto_create_multi_ou + } + + } else { +- err = create_controls(spec, chname[i], nid, 3); ++ err = create_controls(codec, chname[i], nid, 3); + if (err < 0) + return err; + } +@@ -3074,13 +3099,13 @@ static int stac92xx_auto_create_hp_ctls( + static const char *pfxs[] = { + "Speaker", "External Speaker", "Speaker2", + }; +- err = create_controls(spec, pfxs[i - old_num_dacs], ++ err = create_controls(codec, pfxs[i - old_num_dacs], + spec->multiout.dac_nids[i], 3); + if (err < 0) + return err; + } + if (spec->multiout.hp_nid) { +- err = create_controls(spec, "Headphone", ++ err = create_controls(codec, "Headphone", + spec->multiout.hp_nid, 3); + if (err < 0) + return err; +@@ -3670,7 +3695,7 @@ static int stac9200_auto_create_lfe_ctls + } + + if (lfe_pin) { +- err = create_controls(spec, "LFE", lfe_pin, 1); ++ err = create_controls(codec, "LFE", lfe_pin, 1); + if (err < 0) + return err; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-yet-more-fixes b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-yet-more-fixes new file mode 100644 index 000000000..51c7ffdce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac-yet-more-fixes @@ -0,0 +1,166 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix AFG power management on IDT 92HD* codecs +Patch-mainline: +References: bnc#446025 + +The AFG pin power-mapping isn't properly set for the fixed I/O pins +on IDT 92HD* codecs. This resulted in the low power mode after the +boot until any jack detection is executed, thus no output from the +speaker. + +This patch fixes the power mapping for the fixed pins, and also fixes +the GPIO bits and digital I/O pin settings properly in stac92xx_ini(). + +Reference: Novell bnc#446025 + https://bugzilla.novell.com/show_bug.cgi?id=446025 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 80 +++++++++++++++++++++++++++-------------- + 1 file changed, 54 insertions(+), 26 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -3700,10 +3700,14 @@ static void stac92xx_power_down(struct h + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } + ++static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, ++ int enable); ++ + static int stac92xx_init(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; ++ unsigned int gpio; + int i; + + snd_hda_sequence_write(codec, spec->init); +@@ -3714,6 +3718,16 @@ static int stac92xx_init(struct hda_code + snd_hda_codec_write_cache(codec, + spec->adc_nids[i], 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); ++ ++ /* set up GPIO */ ++ gpio = spec->gpio_data; ++ /* turn on EAPD statically when spec->eapd_switch isn't set. ++ * otherwise, unsol event will turn it on/off dynamically ++ */ ++ if (!spec->eapd_switch) ++ gpio |= spec->eapd_mask; ++ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio); ++ + /* set up pins */ + if (spec->hp_detect) { + /* Enable unsolicited responses on the HP widget */ +@@ -3753,39 +3767,43 @@ static int stac92xx_init(struct hda_code + for (i = 0; i < spec->num_dmics; i++) + stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], + AC_PINCTL_IN_EN); ++ if (cfg->dig_out_pin) ++ stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, ++ AC_PINCTL_OUT_EN); ++ if (cfg->dig_in_pin) ++ stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, ++ AC_PINCTL_IN_EN); + for (i = 0; i < spec->num_pwrs; i++) { +- int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) +- ? STAC_HP_EVENT : STAC_PWR_EVENT; +- int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i], +- 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); +- int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], +- 0, AC_VERB_GET_CONFIG_DEFAULT, 0); +- def_conf = get_defcfg_connect(def_conf); ++ hda_nid_t nid = spec->pwr_nids[i]; ++ int pinctl, def_conf; ++ int event = STAC_PWR_EVENT; ++ ++ if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) ++ continue; /* already has an unsol event */ ++ ++ pinctl = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + /* outputs are only ports capable of power management + * any attempts on powering down a input port cause the + * referenced VREF to act quirky. + */ + if (pinctl & AC_PINCTL_IN_EN) + continue; ++ def_conf = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_CONFIG_DEFAULT, 0); ++ def_conf = get_defcfg_connect(def_conf); + /* skip any ports that don't have jacks since presence + * detection is useless */ +- if (def_conf && def_conf != AC_JACK_PORT_FIXED) ++ if (def_conf != AC_JACK_PORT_COMPLEX) { ++ if (def_conf != AC_JACK_PORT_NONE) ++ stac_toggle_power_map(codec, nid, 1); + continue; ++ } + enable_pin_detect(codec, spec->pwr_nids[i], event | i); + codec->patch_ops.unsol_event(codec, (event | i) << 26); + } + if (spec->dac_list) + stac92xx_power_down(codec); +- if (cfg->dig_out_pin) +- stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, +- AC_PINCTL_OUT_EN); +- if (cfg->dig_in_pin) +- stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, +- AC_PINCTL_IN_EN); +- +- stac_gpio_set(codec, spec->gpio_mask, +- spec->gpio_dir, spec->gpio_data); +- + return 0; + } + +@@ -3950,14 +3968,18 @@ static void stac92xx_hp_detect(struct hd + } + } + +-static void stac92xx_pin_sense(struct hda_codec *codec, int idx) ++static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, ++ int enable) + { + struct sigmatel_spec *spec = codec->spec; +- hda_nid_t nid = spec->pwr_nids[idx]; +- int presence, val; +- val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) +- & 0x000000ff; +- presence = get_hp_pin_presence(codec, nid); ++ unsigned int idx, val; ++ ++ for (idx = 0; idx < spec->num_pwrs; idx++) { ++ if (spec->pwr_nids[idx] == nid) ++ break; ++ } ++ if (idx >= spec->num_pwrs) ++ return; + + /* several codecs have two power down bits */ + if (spec->pwr_mapping) +@@ -3965,14 +3987,20 @@ static void stac92xx_pin_sense(struct hd + else + idx = 1 << idx; + +- if (presence) ++ val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff; ++ if (enable) + val &= ~idx; + else + val |= idx; + + /* power down unused output ports */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); +-}; ++} ++ ++static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) ++{ ++ stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid)); ++} + + static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) + { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac9200-missing-mux-capture b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac9200-missing-mux-capture new file mode 100644 index 000000000..05ab956ae --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac9200-missing-mux-capture @@ -0,0 +1,29 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add missing analog-mux mixer creation for STAC9200 +Patch-mainline: +References: bnc#443738 + +The creation of analog-mux mixer element is missing in +patch_stac9200() due to the dynamic allocation patch. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -3535,6 +3535,12 @@ static int stac9200_parse_auto_config(st + if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) + return err; + ++ if (spec->num_muxes > 0) { ++ err = stac92xx_auto_create_mux_input_ctls(codec); ++ if (err < 0) ++ return err; ++ } ++ + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = 0x05; + if (spec->autocfg.dig_in_pin) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac925x-init-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac925x-init-fix new file mode 100644 index 000000000..7cbc635d7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac925x-init-fix @@ -0,0 +1,62 @@ +From c9280d681c4093405fc896dc25f81d5ff9de8183 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 15 Jan 2009 17:31:00 +0100 +Subject: ALSA: hda - Fix (yet more) STAC925x issues +Patch-mainline: 2.6.29-rc1 +References: bnc#460478 + +The codec-parsing of STAC925x was utterly broken due to its unique +design unlike other STAC codecs. It has a volume control only in NID +0x0e (similar as STAC9200), but the parser assumes that the amp is +available on each DAC widget. + +The patch fixes the whole wrong stories: fix the initial volume, +assign the fixed "Master" volume, and avoid to create wrong volume +controls. + +Signed-off-by: Takashi Iwai +--- + sound/pci/hda/patch_sigmatel.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -902,6 +902,8 @@ static struct hda_verb stac92hd71bxx_ana + static struct hda_verb stac925x_core_init[] = { + /* set dac0mux for dac converter */ + { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* mute the master volume */ ++ { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + {} + }; + +@@ -1153,6 +1155,8 @@ static struct snd_kcontrol_new stac92hd7 + }; + + static struct snd_kcontrol_new stac925x_mixer[] = { ++ HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT), ++ HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), + STAC_INPUT_SOURCE(1), + HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT), +@@ -3492,14 +3496,14 @@ static int stac92xx_parse_auto_config(st + + if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) + return err; +- if (spec->multiout.num_dacs == 0) ++ if (spec->multiout.num_dacs == 0) { + if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) + return err; +- +- err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); +- +- if (err < 0) +- return err; ++ err = stac92xx_auto_create_multi_out_ctls(codec, ++ &spec->autocfg); ++ if (err < 0) ++ return err; ++ } + + /* setup analog beep controls */ + if (spec->anabeep_nid > 0) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac92xx-mic-pin-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac92xx-mic-pin-fix new file mode 100644 index 000000000..be1c11f7d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-stac92xx-mic-pin-fix @@ -0,0 +1,51 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix input pin initialization for STAC/IDT codecs +Patch-mainline: +References: bnc#443738 + +The input pins are sometimes not initialized properly because +of the optimization check of the current pinctl code. + +Force to initialize the mic input pins so that they can be set up +properly even if they were in a weird state. But keep other input +pins if already set up as input, since this could be an extra mic +pin. + +Reference: Novell bnc#443738 + https://bugzilla.novell.com/show_bug.cgi?id=443738 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -3658,14 +3658,18 @@ static int stac92xx_init(struct hda_code + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = cfg->input_pins[i]; + if (nid) { +- unsigned int pinctl = snd_hda_codec_read(codec, nid, +- 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); +- /* if PINCTL already set then skip */ +- if (pinctl & AC_PINCAP_IN) +- continue; +- pinctl = AC_PINCTL_IN_EN; +- if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) +- pinctl |= stac92xx_get_vref(codec, nid); ++ unsigned int pinctl; ++ if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { ++ /* for mic pins, force to initialize */ ++ pinctl = stac92xx_get_vref(codec, nid); ++ } else { ++ pinctl = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_PIN_WIDGET_CONTROL, 0); ++ /* if PINCTL already set then skip */ ++ if (pinctl & AC_PINCTL_IN_EN) ++ continue; ++ } ++ pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, pinctl); + } + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-rec-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-rec-fix new file mode 100644 index 000000000..3857ebd4e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-rec-fix @@ -0,0 +1,179 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix DMA pointer calculation on VIA chips +Patch-mainline: 2.6.28-rc1 +References: + +Add a workaround to calculate the DMA position on VIA chips more robustly. + +Signed-off-by: Takashi Iwai + +--- +--- + sound/pci/hda/hda_intel.c | 95 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 91 insertions(+), 4 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -287,6 +287,11 @@ enum { + #define INTEL_SCH_HDA_DEVC 0x78 + #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) + ++/* Define IN stream 0 FIFO size offset in VIA controller */ ++#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 ++/* Define VIA HD Audio Device ID*/ ++#define VIA_HDAC_DEVICE_ID 0x3288 ++ + + /* + */ +@@ -318,6 +323,12 @@ struct azx_dev { + unsigned int running :1; + unsigned int irq_pending :1; + unsigned int irq_ignore :1; ++ /* ++ * For VIA: ++ * A flag to ensure DMA position is 0 ++ * when link position is not greater than FIFO size ++ */ ++ unsigned int insufficient :1; + }; + + /* CORB/RIRB */ +@@ -380,6 +391,7 @@ struct azx { + unsigned int polling_mode :1; + unsigned int msi :1; + unsigned int irq_pending_warned :1; ++ unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ + + /* for debugging */ + unsigned int last_cmd; /* last issued command (to sync) */ +@@ -823,6 +835,11 @@ static void azx_int_clear(struct azx *ch + /* start a stream */ + static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) + { ++ /* ++ * Before stream start, initialize parameter ++ */ ++ azx_dev->insufficient = 1; ++ + /* enable SIE */ + azx_writeb(chip, INTCTL, + azx_readb(chip, INTCTL) | (1 << azx_dev->index)); +@@ -1156,7 +1173,8 @@ static int azx_setup_controller(struct a + + /* enable the position buffer */ + if (chip->position_fix == POS_FIX_POSBUF || +- chip->position_fix == POS_FIX_AUTO) { ++ chip->position_fix == POS_FIX_AUTO || ++ chip->via_dmapos_patch) { + if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, + (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); +@@ -1524,13 +1542,71 @@ static int azx_pcm_trigger(struct snd_pc + return 0; + } + ++/* get the current DMA position with correction on VIA chips */ ++static unsigned int azx_via_get_position(struct azx *chip, ++ struct azx_dev *azx_dev) ++{ ++ unsigned int link_pos, mini_pos, bound_pos; ++ unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; ++ unsigned int fifo_size; ++ ++ link_pos = azx_sd_readl(azx_dev, SD_LPIB); ++ if (azx_dev->index >= 4) { ++ /* Playback, no problem using link position */ ++ return link_pos; ++ } ++ ++ /* Capture */ ++ /* For new chipset, ++ * use mod to get the DMA position just like old chipset ++ */ ++ mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); ++ mod_dma_pos %= azx_dev->period_bytes; ++ ++ /* azx_dev->fifo_size can't get FIFO size of in stream. ++ * Get from base address + offset. ++ */ ++ fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); ++ ++ if (azx_dev->insufficient) { ++ /* Link position never gather than FIFO size */ ++ if (link_pos <= fifo_size) ++ return 0; ++ ++ azx_dev->insufficient = 0; ++ } ++ ++ if (link_pos <= fifo_size) ++ mini_pos = azx_dev->bufsize + link_pos - fifo_size; ++ else ++ mini_pos = link_pos - fifo_size; ++ ++ /* Find nearest previous boudary */ ++ mod_mini_pos = mini_pos % azx_dev->period_bytes; ++ mod_link_pos = link_pos % azx_dev->period_bytes; ++ if (mod_link_pos >= fifo_size) ++ bound_pos = link_pos - mod_link_pos; ++ else if (mod_dma_pos >= mod_mini_pos) ++ bound_pos = mini_pos - mod_mini_pos; ++ else { ++ bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; ++ if (bound_pos >= azx_dev->bufsize) ++ bound_pos = 0; ++ } ++ ++ /* Calculate real DMA position we want */ ++ return bound_pos + mod_dma_pos; ++} ++ + static unsigned int azx_get_position(struct azx *chip, + struct azx_dev *azx_dev) + { + unsigned int pos; + +- if (chip->position_fix == POS_FIX_POSBUF || +- chip->position_fix == POS_FIX_AUTO) { ++ if (chip->via_dmapos_patch) ++ pos = azx_via_get_position(chip, azx_dev); ++ else if (chip->position_fix == POS_FIX_POSBUF || ++ chip->position_fix == POS_FIX_AUTO) { + /* use the position buffer */ + pos = le32_to_cpu(*azx_dev->posbuf); + } else { +@@ -1576,6 +1652,8 @@ static int azx_position_ok(struct azx *c + chip->position_fix = POS_FIX_POSBUF; + } + ++ if (!bdl_pos_adj[chip->dev_index]) ++ return 1; /* no delayed ack */ + if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) + return 0; /* NG - it's below the period boundary */ + return 1; /* OK, it's fine */ +@@ -1687,7 +1765,7 @@ static int __devinit create_codec_pcm(st + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), +- 1024 * 64, 1024 * 1024); ++ 1024 * 64, 32 * 1024 * 1024); + chip->pcm[cpcm->device] = pcm; + return 0; + } +@@ -1987,6 +2065,15 @@ static int __devinit check_position_fix( + { + const struct snd_pci_quirk *q; + ++ /* Check VIA HD Audio Controller exist */ ++ if (chip->pci->vendor == PCI_VENDOR_ID_VIA && ++ chip->pci->device == VIA_HDAC_DEVICE_ID) { ++ chip->via_dmapos_patch = 1; ++ /* Use link position directly, avoid any transfer problem. */ ++ return POS_FIX_LPIB; ++ } ++ chip->via_dmapos_patch = 0; ++ + if (fix == POS_FIX_AUTO) { + q = snd_pci_quirk_lookup(chip->pci, position_fix_list); + if (q) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-update new file mode 100644 index 000000000..15a9407a8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-update @@ -0,0 +1,1858 @@ +From: Takashi Iwai +Subject: ALSA: hda - VIA codecs updates +Patch-mainline: 2.6.28-rc1 +References: + +A pile of updates for VIA HD-audio codecs. + +Signed-off-by: Takashi Iwai + +--- +diff -ruN a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c +--- a/sound/pci/hda/patch_via.c ++++ b/sound/pci/hda/patch_via.c +@@ -1,10 +1,10 @@ + /* + * Universal Interface for Intel High Definition Audio Codec + * +- * HD audio interface patch for VIA VT1708 codec ++ * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec + * +- * Copyright (c) 2006 Lydia Wang +- * Takashi Iwai ++ * Copyright (c) 2006-2008 Lydia Wang ++ * Takashi Iwai + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -29,6 +29,13 @@ + /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ + /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ + /* 2007-09-17 Lydia Wang Add VT1708B codec support */ ++/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ ++/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ ++/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ ++/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ ++/* 2008-04-09 Lydia Wang Add Independent HP feature */ ++/* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ ++/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ + /* */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +@@ -37,6 +44,7 @@ + #include + #include + #include ++#include + #include "hda_codec.h" + #include "hda_local.h" + #include "hda_patch.h" +@@ -53,6 +61,8 @@ + #define VT1708_DIGOUT_NID 0x14 + #define VT1708_DIGIN_NID 0x16 + #define VT1708_DIGIN_PIN 0x26 ++#define VT1708_HP_PIN_NID 0x20 ++#define VT1708_CD_PIN_NID 0x24 + + #define VT1709_HP_DAC_NID 0x28 + #define VT1709_DIGOUT_NID 0x13 +@@ -64,12 +74,64 @@ + #define VT1708B_DIGIN_NID 0x15 + #define VT1708B_DIGIN_PIN 0x21 + ++#define VT1708S_HP_NID 0x25 ++#define VT1708S_DIGOUT_NID 0x12 ++ ++#define VT1702_HP_NID 0x17 ++#define VT1702_DIGOUT_NID 0x11 ++ + #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) + #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) + #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) + #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) + #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) ++#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) ++#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398) ++ ++enum VIA_HDA_CODEC { ++ UNKNOWN = -1, ++ VT1708, ++ VT1709_10CH, ++ VT1709_6CH, ++ VT1708B_8CH, ++ VT1708B_4CH, ++ VT1708S, ++ VT1702, ++ CODEC_TYPES, ++}; ++ ++static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) ++{ ++ u16 ven_id = vendor_id >> 16; ++ u16 dev_id = vendor_id & 0xffff; ++ enum VIA_HDA_CODEC codec_type; ++ ++ /* get codec type */ ++ if (ven_id != 0x1106) ++ codec_type = UNKNOWN; ++ else if (dev_id >= 0x1708 && dev_id <= 0x170b) ++ codec_type = VT1708; ++ else if (dev_id >= 0xe710 && dev_id <= 0xe713) ++ codec_type = VT1709_10CH; ++ else if (dev_id >= 0xe714 && dev_id <= 0xe717) ++ codec_type = VT1709_6CH; ++ else if (dev_id >= 0xe720 && dev_id <= 0xe723) ++ codec_type = VT1708B_8CH; ++ else if (dev_id >= 0xe724 && dev_id <= 0xe727) ++ codec_type = VT1708B_4CH; ++ else if ((dev_id & 0xfff) == 0x397 ++ && (dev_id >> 12) < 8) ++ codec_type = VT1708S; ++ else if ((dev_id & 0xfff) == 0x398 ++ && (dev_id >> 12) < 8) ++ codec_type = VT1702; ++ else ++ codec_type = UNKNOWN; ++ return codec_type; ++}; + ++#define VIA_HP_EVENT 0x01 ++#define VIA_GPIO_EVENT 0x02 + + enum { + VIA_CTL_WIDGET_VOL, +@@ -77,12 +139,54 @@ + }; + + enum { +- AUTO_SEQ_FRONT, ++ AUTO_SEQ_FRONT = 0, + AUTO_SEQ_SURROUND, + AUTO_SEQ_CENLFE, + AUTO_SEQ_SIDE + }; + ++#define get_amp_nid(kc) ((kc)->private_value & 0xffff) ++ ++/* Some VT1708S based boards gets the micboost setting wrong, so we have ++ * to apply some brute-force and re-write the TLV's by software. */ ++static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, ++ unsigned int size, unsigned int __user *_tlv) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ hda_nid_t nid = get_amp_nid(kcontrol); ++ ++ if (get_codec_type(codec->vendor_id) == VT1708S ++ && (nid == 0x1a || nid == 0x1e)) { ++ if (size < 4 * sizeof(unsigned int)) ++ return -ENOMEM; ++ if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */ ++ return -EFAULT; ++ if (put_user(2 * sizeof(unsigned int), _tlv + 1)) ++ return -EFAULT; ++ if (put_user(0, _tlv + 2)) /* offset = 0 */ ++ return -EFAULT; ++ if (put_user(1000, _tlv + 3)) /* step size = 10 dB */ ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ hda_nid_t nid = get_amp_nid(kcontrol); ++ ++ if (get_codec_type(codec->vendor_id) == VT1708S ++ && (nid == 0x1a || nid == 0x1e)) { ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 2; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 3; ++ } ++ return 0; ++} ++ + static struct snd_kcontrol_new vt1708_control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + HDA_CODEC_MUTE(NULL, 0, 0, 0), +@@ -94,7 +198,8 @@ + struct snd_kcontrol_new *mixers[3]; + unsigned int num_mixers; + +- struct hda_verb *init_verbs; ++ struct hda_verb *init_verbs[5]; ++ unsigned int num_iverbs; + + char *stream_name_analog; + struct hda_pcm_stream *stream_analog_playback; +@@ -106,6 +211,7 @@ + + /* playback */ + struct hda_multi_out multiout; ++ hda_nid_t extra_dig_out_nid; + + /* capture */ + unsigned int num_adc_nids; +@@ -117,15 +223,19 @@ + unsigned int cur_mux[3]; + + /* PCM information */ +- struct hda_pcm pcm_rec[2]; ++ struct hda_pcm pcm_rec[3]; + + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + unsigned int num_kctl_alloc, num_kctl_used; + struct snd_kcontrol_new *kctl_alloc; +- struct hda_input_mux private_imux; ++ struct hda_input_mux private_imux[2]; + hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + ++ /* HP mode source */ ++ const struct hda_input_mux *hp_mux; ++ unsigned int hp_independent_mode; ++ + #ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; + #endif +@@ -146,6 +256,16 @@ + 0x13, 0x14 + }; + ++static hda_nid_t vt1708S_adc_nids[2] = { ++ /* ADC1-2 */ ++ 0x13, 0x14 ++}; ++ ++static hda_nid_t vt1702_adc_nids[3] = { ++ /* ADC1-2 */ ++ 0x12, 0x20, 0x1F ++}; ++ + /* add dynamic controls */ + static int via_add_control(struct via_spec *spec, int type, const char *name, + unsigned long val) +@@ -283,19 +403,108 @@ + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + 0x18, &spec->cur_mux[adc_idx]); + else if ((IS_VT1709_10CH_VENDORID(vendor_id) || +- IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0) ++ IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0)) + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + 0x19, &spec->cur_mux[adc_idx]); + else if ((IS_VT1708B_8CH_VENDORID(vendor_id) || +- IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0) ++ IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0)) + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + 0x17, &spec->cur_mux[adc_idx]); ++ else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0)) ++ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, ++ 0x13, &spec->cur_mux[adc_idx]); + else + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->adc_nids[adc_idx], + &spec->cur_mux[adc_idx]); + } + ++static int via_independent_hp_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct via_spec *spec = codec->spec; ++ return snd_hda_input_mux_info(spec->hp_mux, uinfo); ++} ++ ++static int via_independent_hp_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct via_spec *spec = codec->spec; ++ hda_nid_t nid = spec->autocfg.hp_pins[0]; ++ unsigned int pinsel = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_CONNECT_SEL, ++ 0x00); ++ ++ ucontrol->value.enumerated.item[0] = pinsel; ++ ++ return 0; ++} ++ ++static int via_independent_hp_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct via_spec *spec = codec->spec; ++ hda_nid_t nid = spec->autocfg.hp_pins[0]; ++ unsigned int pinsel = ucontrol->value.enumerated.item[0]; ++ unsigned int con_nid = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_CONNECT_LIST, 0) & 0xff; ++ ++ if (con_nid == spec->multiout.hp_nid) { ++ if (pinsel == 0) { ++ if (!spec->hp_independent_mode) { ++ if (spec->multiout.num_dacs > 1) ++ spec->multiout.num_dacs -= 1; ++ spec->hp_independent_mode = 1; ++ } ++ } else if (pinsel == 1) { ++ if (spec->hp_independent_mode) { ++ if (spec->multiout.num_dacs > 1) ++ spec->multiout.num_dacs += 1; ++ spec->hp_independent_mode = 0; ++ } ++ } ++ } else { ++ if (pinsel == 0) { ++ if (spec->hp_independent_mode) { ++ if (spec->multiout.num_dacs > 1) ++ spec->multiout.num_dacs += 1; ++ spec->hp_independent_mode = 0; ++ } ++ } else if (pinsel == 1) { ++ if (!spec->hp_independent_mode) { ++ if (spec->multiout.num_dacs > 1) ++ spec->multiout.num_dacs -= 1; ++ spec->hp_independent_mode = 1; ++ } ++ } ++ } ++ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, ++ pinsel); ++ ++ if (spec->multiout.hp_nid && ++ spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT]) ++ snd_hda_codec_setup_stream(codec, ++ spec->multiout.hp_nid, ++ 0, 0, 0); ++ ++ return 0; ++} ++ ++static struct snd_kcontrol_new via_hp_mixer[] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Independent HP", ++ .count = 1, ++ .info = via_independent_hp_info, ++ .get = via_independent_hp_get, ++ .put = via_independent_hp_put, ++ }, ++ { } /* end */ ++}; ++ + /* capture mixer elements */ + static struct snd_kcontrol_new vt1708_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), +@@ -380,6 +589,138 @@ + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); + } + ++ ++static void playback_multi_pcm_prep_0(struct hda_codec *codec, ++ unsigned int stream_tag, ++ unsigned int format, ++ struct snd_pcm_substream *substream) ++{ ++ struct via_spec *spec = codec->spec; ++ struct hda_multi_out *mout = &spec->multiout; ++ hda_nid_t *nids = mout->dac_nids; ++ int chs = substream->runtime->channels; ++ int i; ++ ++ mutex_lock(&codec->spdif_mutex); ++ if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { ++ if (chs == 2 && ++ snd_hda_is_supported_format(codec, mout->dig_out_nid, ++ format) && ++ !(codec->spdif_status & IEC958_AES0_NONAUDIO)) { ++ mout->dig_out_used = HDA_DIG_ANALOG_DUP; ++ /* turn off SPDIF once; otherwise the IEC958 bits won't ++ * be updated */ ++ if (codec->spdif_ctls & AC_DIG1_ENABLE) ++ snd_hda_codec_write(codec, mout->dig_out_nid, 0, ++ AC_VERB_SET_DIGI_CONVERT_1, ++ codec->spdif_ctls & ++ ~AC_DIG1_ENABLE & 0xff); ++ snd_hda_codec_setup_stream(codec, mout->dig_out_nid, ++ stream_tag, 0, format); ++ /* turn on again (if needed) */ ++ if (codec->spdif_ctls & AC_DIG1_ENABLE) ++ snd_hda_codec_write(codec, mout->dig_out_nid, 0, ++ AC_VERB_SET_DIGI_CONVERT_1, ++ codec->spdif_ctls & 0xff); ++ } else { ++ mout->dig_out_used = 0; ++ snd_hda_codec_setup_stream(codec, mout->dig_out_nid, ++ 0, 0, 0); ++ } ++ } ++ mutex_unlock(&codec->spdif_mutex); ++ ++ /* front */ ++ snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, ++ 0, format); ++ ++ if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && ++ !spec->hp_independent_mode) ++ /* headphone out will just decode front left/right (stereo) */ ++ snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, ++ 0, format); ++ ++ /* extra outputs copied from front */ ++ for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) ++ if (mout->extra_out_nid[i]) ++ snd_hda_codec_setup_stream(codec, ++ mout->extra_out_nid[i], ++ stream_tag, 0, format); ++ ++ /* surrounds */ ++ for (i = 1; i < mout->num_dacs; i++) { ++ if (chs >= (i + 1) * 2) /* independent out */ ++ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, ++ i * 2, format); ++ else /* copy front */ ++ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, ++ 0, format); ++ } ++} ++ ++static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ unsigned int stream_tag, ++ unsigned int format, ++ struct snd_pcm_substream *substream) ++{ ++ struct via_spec *spec = codec->spec; ++ struct hda_multi_out *mout = &spec->multiout; ++ hda_nid_t *nids = mout->dac_nids; ++ ++ if (substream->number == 0) ++ playback_multi_pcm_prep_0(codec, stream_tag, format, ++ substream); ++ else { ++ if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && ++ spec->hp_independent_mode) ++ snd_hda_codec_setup_stream(codec, mout->hp_nid, ++ stream_tag, 0, format); ++ } ++ ++ return 0; ++} ++ ++static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ struct snd_pcm_substream *substream) ++{ ++ struct via_spec *spec = codec->spec; ++ struct hda_multi_out *mout = &spec->multiout; ++ hda_nid_t *nids = mout->dac_nids; ++ int i; ++ ++ if (substream->number == 0) { ++ for (i = 0; i < mout->num_dacs; i++) ++ snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); ++ ++ if (mout->hp_nid && !spec->hp_independent_mode) ++ snd_hda_codec_setup_stream(codec, mout->hp_nid, ++ 0, 0, 0); ++ ++ for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) ++ if (mout->extra_out_nid[i]) ++ snd_hda_codec_setup_stream(codec, ++ mout->extra_out_nid[i], ++ 0, 0, 0); ++ mutex_lock(&codec->spdif_mutex); ++ if (mout->dig_out_nid && ++ mout->dig_out_used == HDA_DIG_ANALOG_DUP) { ++ snd_hda_codec_setup_stream(codec, mout->dig_out_nid, ++ 0, 0, 0); ++ mout->dig_out_used = 0; ++ } ++ mutex_unlock(&codec->spdif_mutex); ++ } else { ++ if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && ++ spec->hp_independent_mode) ++ snd_hda_codec_setup_stream(codec, mout->hp_nid, ++ 0, 0, 0); ++ } ++ ++ return 0; ++} ++ + /* + * Digital out + */ +@@ -399,6 +740,21 @@ + return snd_hda_multi_out_dig_close(codec, &spec->multiout); + } + ++/* setup SPDIF output stream */ ++static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, ++ unsigned int stream_tag, unsigned int format) ++{ ++ /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ ++ if (codec->spdif_ctls & AC_DIG1_ENABLE) ++ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, ++ codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); ++ snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); ++ /* turn on again (if needed) */ ++ if (codec->spdif_ctls & AC_DIG1_ENABLE) ++ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, ++ codec->spdif_ctls & 0xff); ++} ++ + static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, +@@ -406,8 +762,20 @@ + struct snd_pcm_substream *substream) + { + struct via_spec *spec = codec->spec; +- return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, +- stream_tag, format, substream); ++ hda_nid_t nid; ++ ++ /* 1st or 2nd S/PDIF */ ++ if (substream->number == 0) ++ nid = spec->multiout.dig_out_nid; ++ else if (substream->number == 1) ++ nid = spec->extra_dig_out_nid; ++ else ++ return -1; ++ ++ mutex_lock(&codec->spdif_mutex); ++ setup_dig_playback_stream(codec, nid, stream_tag, format); ++ mutex_unlock(&codec->spdif_mutex); ++ return 0; + } + + /* +@@ -436,14 +804,14 @@ + } + + static struct hda_pcm_stream vt1708_pcm_analog_playback = { +- .substreams = 1, ++ .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, +- .prepare = via_playback_pcm_prepare, +- .cleanup = via_playback_pcm_cleanup ++ .prepare = via_playback_multi_pcm_prepare, ++ .cleanup = via_playback_multi_pcm_cleanup + }, + }; + +@@ -515,6 +883,13 @@ + if (err < 0) + return err; + spec->multiout.share_spdif = 1; ++ ++ if (spec->extra_dig_out_nid) { ++ err = snd_hda_create_spdif_out_ctls(codec, ++ spec->extra_dig_out_nid); ++ if (err < 0) ++ return err; ++ } + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); +@@ -580,10 +955,89 @@ + kfree(codec->spec); + } + ++/* mute internal speaker if HP is plugged */ ++static void via_hp_automute(struct hda_codec *codec) ++{ ++ unsigned int present; ++ struct via_spec *spec = codec->spec; ++ ++ present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], ++ HDA_OUTPUT, 0, HDA_AMP_MUTE, ++ present ? HDA_AMP_MUTE : 0); ++} ++ ++static void via_gpio_control(struct hda_codec *codec) ++{ ++ unsigned int gpio_data; ++ unsigned int vol_counter; ++ unsigned int vol; ++ unsigned int master_vol; ++ ++ struct via_spec *spec = codec->spec; ++ ++ gpio_data = snd_hda_codec_read(codec, codec->afg, 0, ++ AC_VERB_GET_GPIO_DATA, 0) & 0x03; ++ ++ vol_counter = (snd_hda_codec_read(codec, codec->afg, 0, ++ 0xF84, 0) & 0x3F0000) >> 16; ++ ++ vol = vol_counter & 0x1F; ++ master_vol = snd_hda_codec_read(codec, 0x1A, 0, ++ AC_VERB_GET_AMP_GAIN_MUTE, ++ AC_AMP_GET_INPUT); ++ ++ if (gpio_data == 0x02) { ++ /* unmute line out */ ++ snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], ++ HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); ++ ++ if (vol_counter & 0x20) { ++ /* decrease volume */ ++ if (vol > master_vol) ++ vol = master_vol; ++ snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, ++ 0, HDA_AMP_VOLMASK, ++ master_vol-vol); ++ } else { ++ /* increase volume */ ++ snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0, ++ HDA_AMP_VOLMASK, ++ ((master_vol+vol) > 0x2A) ? 0x2A : ++ (master_vol+vol)); ++ } ++ } else if (!(gpio_data & 0x02)) { ++ /* mute line out */ ++ snd_hda_codec_amp_stereo(codec, ++ spec->autocfg.line_out_pins[0], ++ HDA_OUTPUT, 0, HDA_AMP_MUTE, ++ HDA_AMP_MUTE); ++ } ++} ++ ++/* unsolicited event for jack sensing */ ++static void via_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ res >>= 26; ++ if (res == VIA_HP_EVENT) ++ via_hp_automute(codec); ++ else if (res == VIA_GPIO_EVENT) ++ via_gpio_control(codec); ++} ++ ++static hda_nid_t slave_dig_outs[] = { ++ 0, ++}; ++ + static int via_init(struct hda_codec *codec) + { + struct via_spec *spec = codec->spec; +- snd_hda_sequence_write(codec, spec->init_verbs); ++ int i; ++ for (i = 0; i < spec->num_iverbs; i++) ++ snd_hda_sequence_write(codec, spec->init_verbs[i]); ++ + /* Lydia Add for EAPD enable */ + if (!spec->dig_in_nid) { /* No Digital In connection */ + if (IS_VT1708_VENDORID(codec->vendor_id)) { +@@ -611,6 +1065,9 @@ + snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); + ++ /* no slave outs */ ++ codec->slave_dig_outs = slave_dig_outs; ++ + return 0; + } + +@@ -657,10 +1114,10 @@ + spec->multiout.dac_nids[i] = 0x12; + break; + case AUTO_SEQ_SURROUND: +- spec->multiout.dac_nids[i] = 0x13; ++ spec->multiout.dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: +- spec->multiout.dac_nids[i] = 0x11; ++ spec->multiout.dac_nids[i] = 0x13; + break; + } + } +@@ -685,7 +1142,7 @@ + continue; + + if (i != AUTO_SEQ_FRONT) +- nid_vol = 0x1b - i + 1; ++ nid_vol = 0x18 + i; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ +@@ -760,6 +1217,24 @@ + return 0; + } + ++static void create_hp_imux(struct via_spec *spec) ++{ ++ int i; ++ struct hda_input_mux *imux = &spec->private_imux[1]; ++ static const char *texts[] = { "OFF", "ON", NULL}; ++ ++ /* for hp mode select */ ++ i = 0; ++ while (texts[i] != NULL) { ++ imux->items[imux->num_items].label = texts[i]; ++ imux->items[imux->num_items].index = i; ++ imux->num_items++; ++ i++; ++ } ++ ++ spec->hp_mux = &spec->private_imux[1]; ++} ++ + static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) + { + int err; +@@ -780,6 +1255,8 @@ + if (err < 0) + return err; + ++ create_hp_imux(spec); ++ + return 0; + } + +@@ -790,7 +1267,7 @@ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; +- struct hda_input_mux *imux = &spec->private_imux; ++ struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + /* for internal loopback recording select */ +@@ -840,11 +1317,36 @@ + }; + #endif + ++static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) ++{ ++ unsigned int def_conf; ++ unsigned char seqassoc; ++ ++ def_conf = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_CONFIG_DEFAULT, 0); ++ seqassoc = (unsigned char) get_defcfg_association(def_conf); ++ seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); ++ if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { ++ if (seqassoc == 0xff) { ++ def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); ++ snd_hda_codec_write(codec, nid, 0, ++ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, ++ def_conf >> 24); ++ } ++ } ++ ++ return; ++} ++ + static int vt1708_parse_auto_config(struct hda_codec *codec) + { + struct via_spec *spec = codec->spec; + int err; + ++ /* Add HP and CD pin config connect bit re-config action */ ++ vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); ++ vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID); ++ + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; +@@ -874,9 +1376,12 @@ + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + +- spec->init_verbs = vt1708_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; ++ ++ spec->input_mux = &spec->private_imux[0]; + +- spec->input_mux = &spec->private_imux; ++ if (spec->hp_mux) ++ spec->mixers[spec->num_mixers++] = via_hp_mixer; + + return 1; + } +@@ -897,7 +1402,7 @@ + int err; + + /* create a codec specific record */ +- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + +@@ -966,6 +1471,11 @@ + { } /* end */ + }; + ++static struct hda_verb vt1709_uniwill_init_verbs[] = { ++ {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, ++ { } ++}; ++ + /* + * generic initialization of ADC, input mixers and output mixers + */ +@@ -1090,11 +1600,11 @@ + break; + case AUTO_SEQ_SURROUND: + /* AOW3 */ +- spec->multiout.dac_nids[i] = 0x27; ++ spec->multiout.dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: + /* AOW1 */ +- spec->multiout.dac_nids[i] = 0x11; ++ spec->multiout.dac_nids[i] = 0x27; + break; + default: + break; +@@ -1203,26 +1713,26 @@ + } else if (i == AUTO_SEQ_SURROUND) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, +- HDA_COMPOSE_AMP_VAL(0x29, 3, 0, ++ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, +- HDA_COMPOSE_AMP_VAL(0x29, 3, 0, ++ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_SIDE) { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, +- HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, ++ HDA_COMPOSE_AMP_VAL(0x29, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, +- HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, ++ HDA_COMPOSE_AMP_VAL(0x29, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; +@@ -1265,7 +1775,7 @@ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; +- struct hda_input_mux *imux = &spec->private_imux; ++ struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + /* for internal loopback recording select */ +@@ -1339,7 +1849,10 @@ + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + +- spec->input_mux = &spec->private_imux; ++ spec->input_mux = &spec->private_imux[0]; ++ ++ if (spec->hp_mux) ++ spec->mixers[spec->num_mixers++] = via_hp_mixer; + + return 1; + } +@@ -1360,7 +1873,7 @@ + int err; + + /* create a codec specific record */ +- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + +@@ -1375,7 +1888,8 @@ + "Using genenic mode...\n"); + } + +- spec->init_verbs = vt1709_10ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1709_10ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; + + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; +@@ -1396,6 +1910,7 @@ + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; ++ codec->patch_ops.unsol_event = via_unsol_event; + #ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; + #endif +@@ -1451,7 +1966,7 @@ + int err; + + /* create a codec specific record */ +- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + +@@ -1466,7 +1981,8 @@ + "Using genenic mode...\n"); + } + +- spec->init_verbs = vt1709_6ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1709_6ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1709_uniwill_init_verbs; + + spec->stream_name_analog = "VT1709 Analog"; + spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; +@@ -1487,6 +2003,7 @@ + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; ++ codec->patch_ops.unsol_event = via_unsol_event; + #ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; + #endif +@@ -1586,27 +2103,32 @@ + { } + }; + ++static struct hda_verb vt1708B_uniwill_init_verbs[] = { ++ {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, ++ { } ++}; ++ + static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { +- .substreams = 1, ++ .substreams = 2, + .channels_min = 2, + .channels_max = 8, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, +- .prepare = via_playback_pcm_prepare, +- .cleanup = via_playback_pcm_cleanup ++ .prepare = via_playback_multi_pcm_prepare, ++ .cleanup = via_playback_multi_pcm_cleanup + }, + }; + + static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { +- .substreams = 1, ++ .substreams = 2, + .channels_min = 2, + .channels_max = 4, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, +- .prepare = via_playback_pcm_prepare, +- .cleanup = via_playback_pcm_cleanup ++ .prepare = via_playback_multi_pcm_prepare, ++ .cleanup = via_playback_multi_pcm_cleanup + }, + }; + +@@ -1662,10 +2184,10 @@ + spec->multiout.dac_nids[i] = 0x24; + break; + case AUTO_SEQ_SURROUND: +- spec->multiout.dac_nids[i] = 0x25; ++ spec->multiout.dac_nids[i] = 0x11; + break; + case AUTO_SEQ_SIDE: +- spec->multiout.dac_nids[i] = 0x11; ++ spec->multiout.dac_nids[i] = 0x25; + break; + } + } +@@ -1680,7 +2202,7 @@ + { + char name[32]; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; +- hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18}; ++ hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; + hda_nid_t nid, nid_vol = 0; + int i, err; + +@@ -1785,6 +2307,8 @@ + if (err < 0) + return err; + ++ create_hp_imux(spec); ++ + return 0; + } + +@@ -1795,7 +2319,7 @@ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; +- struct hda_input_mux *imux = &spec->private_imux; ++ struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + /* for internal loopback recording select */ +@@ -1869,7 +2393,10 @@ + if (spec->kctl_alloc) + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + +- spec->input_mux = &spec->private_imux; ++ spec->input_mux = &spec->private_imux[0]; ++ ++ if (spec->hp_mux) ++ spec->mixers[spec->num_mixers++] = via_hp_mixer; + + return 1; + } +@@ -1890,7 +2417,7 @@ + int err; + + /* create a codec specific record */ +- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + +@@ -1906,7 +2433,8 @@ + "from BIOS. Using genenic mode...\n"); + } + +- spec->init_verbs = vt1708B_8ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1708B_8ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; + + spec->stream_name_analog = "VT1708B Analog"; + spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; +@@ -1926,6 +2454,7 @@ + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; ++ codec->patch_ops.unsol_event = via_unsol_event; + #ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708B_loopbacks; + #endif +@@ -1939,7 +2468,7 @@ + int err; + + /* create a codec specific record */ +- spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + +@@ -1955,7 +2484,8 @@ + "from BIOS. Using genenic mode...\n"); + } + +- spec->init_verbs = vt1708B_4ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1708B_4ch_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1708B_uniwill_init_verbs; + + spec->stream_name_analog = "VT1708B Analog"; + spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; +@@ -1975,6 +2505,7 @@ + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; ++ codec->patch_ops.unsol_event = via_unsol_event; + #ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708B_loopbacks; + #endif +@@ -1982,6 +2513,752 @@ + return 0; + } + ++/* Patch for VT1708S */ ++ ++/* VT1708S software backdoor based override for buggy hardware micboost ++ * setting */ ++#define MIC_BOOST_VOLUME(xname, nid) { \ ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ ++ .name = xname, \ ++ .index = 0, \ ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ ++ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ ++ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ ++ .info = mic_boost_volume_info, \ ++ .get = snd_hda_mixer_amp_volume_get, \ ++ .put = snd_hda_mixer_amp_volume_put, \ ++ .tlv = { .c = mic_boost_tlv }, \ ++ .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) } ++ ++/* capture mixer elements */ ++static struct snd_kcontrol_new vt1708S_capture_mixer[] = { ++ HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), ++ MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A), ++ MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ /* The multiple "Capture Source" controls confuse alsamixer ++ * So call somewhat different.. ++ */ ++ /* .name = "Capture Source", */ ++ .name = "Input Source", ++ .count = 1, ++ .info = via_mux_enum_info, ++ .get = via_mux_enum_get, ++ .put = via_mux_enum_put, ++ }, ++ { } /* end */ ++}; ++ ++static struct hda_verb vt1708S_volume_init_verbs[] = { ++ /* Unmute ADC0-1 and set the default input to mic-in */ ++ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ ++ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the ++ * analog-loopback mixer widget */ ++ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, ++ ++ /* Setup default input of PW4 to MW0 */ ++ {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, ++ /* PW9, PW10 Output enable */ ++ {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, ++ {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, ++ /* Enable Mic Boost Volume backdoor */ ++ {0x1, 0xf98, 0x1}, ++ { } ++}; ++ ++static struct hda_verb vt1708S_uniwill_init_verbs[] = { ++ {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, ++ { } ++}; ++ ++static struct hda_pcm_stream vt1708S_pcm_analog_playback = { ++ .substreams = 2, ++ .channels_min = 2, ++ .channels_max = 8, ++ .nid = 0x10, /* NID to query formats and rates */ ++ .ops = { ++ .open = via_playback_pcm_open, ++ .prepare = via_playback_pcm_prepare, ++ .cleanup = via_playback_pcm_cleanup ++ }, ++}; ++ ++static struct hda_pcm_stream vt1708S_pcm_analog_capture = { ++ .substreams = 2, ++ .channels_min = 2, ++ .channels_max = 2, ++ .nid = 0x13, /* NID to query formats and rates */ ++ .ops = { ++ .prepare = via_capture_pcm_prepare, ++ .cleanup = via_capture_pcm_cleanup ++ }, ++}; ++ ++static struct hda_pcm_stream vt1708S_pcm_digital_playback = { ++ .substreams = 2, ++ .channels_min = 2, ++ .channels_max = 2, ++ /* NID is set in via_build_pcms */ ++ .ops = { ++ .open = via_dig_playback_pcm_open, ++ .close = via_dig_playback_pcm_close, ++ .prepare = via_dig_playback_pcm_prepare ++ }, ++}; ++ ++/* fill in the dac_nids table from the parsed pin configuration */ ++static int vt1708S_auto_fill_dac_nids(struct via_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ int i; ++ hda_nid_t nid; ++ ++ spec->multiout.num_dacs = cfg->line_outs; ++ ++ spec->multiout.dac_nids = spec->private_dac_nids; ++ ++ for (i = 0; i < 4; i++) { ++ nid = cfg->line_out_pins[i]; ++ if (nid) { ++ /* config dac list */ ++ switch (i) { ++ case AUTO_SEQ_FRONT: ++ spec->multiout.dac_nids[i] = 0x10; ++ break; ++ case AUTO_SEQ_CENLFE: ++ spec->multiout.dac_nids[i] = 0x24; ++ break; ++ case AUTO_SEQ_SURROUND: ++ spec->multiout.dac_nids[i] = 0x11; ++ break; ++ case AUTO_SEQ_SIDE: ++ spec->multiout.dac_nids[i] = 0x25; ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* add playback controls from the parsed DAC table */ ++static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ char name[32]; ++ static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; ++ hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; ++ hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; ++ hda_nid_t nid, nid_vol, nid_mute; ++ int i, err; ++ ++ for (i = 0; i <= AUTO_SEQ_SIDE; i++) { ++ nid = cfg->line_out_pins[i]; ++ ++ if (!nid) ++ continue; ++ ++ nid_vol = nid_vols[i]; ++ nid_mute = nid_mutes[i]; ++ ++ if (i == AUTO_SEQ_CENLFE) { ++ /* Center/LFE */ ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "Center Playback Volume", ++ HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "LFE Playback Volume", ++ HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "Center Playback Switch", ++ HDA_COMPOSE_AMP_VAL(nid_mute, ++ 1, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "LFE Playback Switch", ++ HDA_COMPOSE_AMP_VAL(nid_mute, ++ 2, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ } else if (i == AUTO_SEQ_FRONT) { ++ /* add control to mixer index 0 */ ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "Master Front Playback Volume", ++ HDA_COMPOSE_AMP_VAL(0x16, 3, 0, ++ HDA_INPUT)); ++ if (err < 0) ++ return err; ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "Master Front Playback Switch", ++ HDA_COMPOSE_AMP_VAL(0x16, 3, 0, ++ HDA_INPUT)); ++ if (err < 0) ++ return err; ++ ++ /* Front */ ++ sprintf(name, "%s Playback Volume", chname[i]); ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, ++ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ sprintf(name, "%s Playback Switch", chname[i]); ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, ++ HDA_COMPOSE_AMP_VAL(nid_mute, ++ 3, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ } else { ++ sprintf(name, "%s Playback Volume", chname[i]); ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, ++ HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ sprintf(name, "%s Playback Switch", chname[i]); ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, ++ HDA_COMPOSE_AMP_VAL(nid_mute, ++ 3, 0, ++ HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) ++{ ++ int err; ++ ++ if (!pin) ++ return 0; ++ ++ spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ ++ ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "Headphone Playback Volume", ++ HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "Headphone Playback Switch", ++ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ ++ create_hp_imux(spec); ++ ++ return 0; ++} ++ ++/* create playback/capture controls for input pins */ ++static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ static char *labels[] = { ++ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL ++ }; ++ struct hda_input_mux *imux = &spec->private_imux[0]; ++ int i, err, idx = 0; ++ ++ /* for internal loopback recording select */ ++ imux->items[imux->num_items].label = "Stereo Mixer"; ++ imux->items[imux->num_items].index = 5; ++ imux->num_items++; ++ ++ for (i = 0; i < AUTO_PIN_LAST; i++) { ++ if (!cfg->input_pins[i]) ++ continue; ++ ++ switch (cfg->input_pins[i]) { ++ case 0x1a: /* Mic */ ++ idx = 2; ++ break; ++ ++ case 0x1b: /* Line In */ ++ idx = 3; ++ break; ++ ++ case 0x1e: /* Front Mic */ ++ idx = 4; ++ break; ++ ++ case 0x1f: /* CD */ ++ idx = 1; ++ break; ++ } ++ err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], ++ idx, 0x16); ++ if (err < 0) ++ return err; ++ imux->items[imux->num_items].label = labels[i]; ++ imux->items[imux->num_items].index = idx-1; ++ imux->num_items++; ++ } ++ return 0; ++} ++ ++static int vt1708S_parse_auto_config(struct hda_codec *codec) ++{ ++ struct via_spec *spec = codec->spec; ++ int err; ++ static hda_nid_t vt1708s_ignore[] = {0x21, 0}; ++ ++ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, ++ vt1708s_ignore); ++ if (err < 0) ++ return err; ++ err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); ++ if (err < 0) ++ return err; ++ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) ++ return 0; /* can't find valid BIOS pin config */ ++ ++ err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg); ++ if (err < 0) ++ return err; ++ err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); ++ if (err < 0) ++ return err; ++ err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg); ++ if (err < 0) ++ return err; ++ ++ spec->multiout.max_channels = spec->multiout.num_dacs * 2; ++ ++ if (spec->autocfg.dig_out_pin) ++ spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; ++ ++ spec->extra_dig_out_nid = 0x15; ++ ++ if (spec->kctl_alloc) ++ spec->mixers[spec->num_mixers++] = spec->kctl_alloc; ++ ++ spec->input_mux = &spec->private_imux[0]; ++ ++ if (spec->hp_mux) ++ spec->mixers[spec->num_mixers++] = via_hp_mixer; ++ ++ return 1; ++} ++ ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++static struct hda_amp_list vt1708S_loopbacks[] = { ++ { 0x16, HDA_INPUT, 1 }, ++ { 0x16, HDA_INPUT, 2 }, ++ { 0x16, HDA_INPUT, 3 }, ++ { 0x16, HDA_INPUT, 4 }, ++ { } /* end */ ++}; ++#endif ++ ++static int patch_vt1708S(struct hda_codec *codec) ++{ ++ struct via_spec *spec; ++ int err; ++ ++ /* create a codec specific record */ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ codec->spec = spec; ++ ++ /* automatic parse from the BIOS config */ ++ err = vt1708S_parse_auto_config(codec); ++ if (err < 0) { ++ via_free(codec); ++ return err; ++ } else if (!err) { ++ printk(KERN_INFO "hda_codec: Cannot set up configuration " ++ "from BIOS. Using genenic mode...\n"); ++ } ++ ++ spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; ++ ++ spec->stream_name_analog = "VT1708S Analog"; ++ spec->stream_analog_playback = &vt1708S_pcm_analog_playback; ++ spec->stream_analog_capture = &vt1708S_pcm_analog_capture; ++ ++ spec->stream_name_digital = "VT1708S Digital"; ++ spec->stream_digital_playback = &vt1708S_pcm_digital_playback; ++ ++ if (!spec->adc_nids && spec->input_mux) { ++ spec->adc_nids = vt1708S_adc_nids; ++ spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); ++ spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; ++ spec->num_mixers++; ++ } ++ ++ codec->patch_ops = via_patch_ops; ++ ++ codec->patch_ops.init = via_auto_init; ++ codec->patch_ops.unsol_event = via_unsol_event; ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++ spec->loopback.amplist = vt1708S_loopbacks; ++#endif ++ ++ return 0; ++} ++ ++/* Patch for VT1702 */ ++ ++/* capture mixer elements */ ++static struct snd_kcontrol_new vt1702_capture_mixer[] = { ++ HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT), ++ HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0, ++ HDA_INPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ /* The multiple "Capture Source" controls confuse alsamixer ++ * So call somewhat different.. ++ */ ++ /* .name = "Capture Source", */ ++ .name = "Input Source", ++ .count = 1, ++ .info = via_mux_enum_info, ++ .get = via_mux_enum_get, ++ .put = via_mux_enum_put, ++ }, ++ { } /* end */ ++}; ++ ++static struct hda_verb vt1702_volume_init_verbs[] = { ++ /* ++ * Unmute ADC0-1 and set the default input to mic-in ++ */ ++ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ ++ ++ /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback ++ * mixer widget ++ */ ++ /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */ ++ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, ++ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, ++ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, ++ {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, ++ ++ /* Setup default input of PW4 to MW0 */ ++ {0x17, AC_VERB_SET_CONNECT_SEL, 0x1}, ++ /* PW6 PW7 Output enable */ ++ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, ++ {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, ++ { } ++}; ++ ++static struct hda_verb vt1702_uniwill_init_verbs[] = { ++ {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT}, ++ {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, ++ { } ++}; ++ ++static struct hda_pcm_stream vt1702_pcm_analog_playback = { ++ .substreams = 2, ++ .channels_min = 2, ++ .channels_max = 2, ++ .nid = 0x10, /* NID to query formats and rates */ ++ .ops = { ++ .open = via_playback_pcm_open, ++ .prepare = via_playback_multi_pcm_prepare, ++ .cleanup = via_playback_multi_pcm_cleanup ++ }, ++}; ++ ++static struct hda_pcm_stream vt1702_pcm_analog_capture = { ++ .substreams = 3, ++ .channels_min = 2, ++ .channels_max = 2, ++ .nid = 0x12, /* NID to query formats and rates */ ++ .ops = { ++ .prepare = via_capture_pcm_prepare, ++ .cleanup = via_capture_pcm_cleanup ++ }, ++}; ++ ++static struct hda_pcm_stream vt1702_pcm_digital_playback = { ++ .substreams = 2, ++ .channels_min = 2, ++ .channels_max = 2, ++ /* NID is set in via_build_pcms */ ++ .ops = { ++ .open = via_dig_playback_pcm_open, ++ .close = via_dig_playback_pcm_close, ++ .prepare = via_dig_playback_pcm_prepare ++ }, ++}; ++ ++/* fill in the dac_nids table from the parsed pin configuration */ ++static int vt1702_auto_fill_dac_nids(struct via_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ spec->multiout.num_dacs = 1; ++ spec->multiout.dac_nids = spec->private_dac_nids; ++ ++ if (cfg->line_out_pins[0]) { ++ /* config dac list */ ++ spec->multiout.dac_nids[0] = 0x10; ++ } ++ ++ return 0; ++} ++ ++/* add playback controls from the parsed DAC table */ ++static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ int err; ++ ++ if (!cfg->line_out_pins[0]) ++ return -1; ++ ++ /* add control to mixer index 0 */ ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "Master Front Playback Volume", ++ HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); ++ if (err < 0) ++ return err; ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "Master Front Playback Switch", ++ HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT)); ++ if (err < 0) ++ return err; ++ ++ /* Front */ ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "Front Playback Volume", ++ HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "Front Playback Switch", ++ HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) ++{ ++ int err; ++ ++ if (!pin) ++ return 0; ++ ++ spec->multiout.hp_nid = 0x1D; ++ ++ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, ++ "Headphone Playback Volume", ++ HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ ++ err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, ++ "Headphone Playback Switch", ++ HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); ++ if (err < 0) ++ return err; ++ ++ create_hp_imux(spec); ++ ++ return 0; ++} ++ ++/* create playback/capture controls for input pins */ ++static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, ++ const struct auto_pin_cfg *cfg) ++{ ++ static char *labels[] = { ++ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL ++ }; ++ struct hda_input_mux *imux = &spec->private_imux[0]; ++ int i, err, idx = 0; ++ ++ /* for internal loopback recording select */ ++ imux->items[imux->num_items].label = "Stereo Mixer"; ++ imux->items[imux->num_items].index = 3; ++ imux->num_items++; ++ ++ for (i = 0; i < AUTO_PIN_LAST; i++) { ++ if (!cfg->input_pins[i]) ++ continue; ++ ++ switch (cfg->input_pins[i]) { ++ case 0x14: /* Mic */ ++ idx = 1; ++ break; ++ ++ case 0x15: /* Line In */ ++ idx = 2; ++ break; ++ ++ case 0x18: /* Front Mic */ ++ idx = 3; ++ break; ++ } ++ err = via_new_analog_input(spec, cfg->input_pins[i], ++ labels[i], idx, 0x1A); ++ if (err < 0) ++ return err; ++ imux->items[imux->num_items].label = labels[i]; ++ imux->items[imux->num_items].index = idx-1; ++ imux->num_items++; ++ } ++ return 0; ++} ++ ++static int vt1702_parse_auto_config(struct hda_codec *codec) ++{ ++ struct via_spec *spec = codec->spec; ++ int err; ++ static hda_nid_t vt1702_ignore[] = {0x1C, 0}; ++ ++ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, ++ vt1702_ignore); ++ if (err < 0) ++ return err; ++ err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); ++ if (err < 0) ++ return err; ++ if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) ++ return 0; /* can't find valid BIOS pin config */ ++ ++ err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg); ++ if (err < 0) ++ return err; ++ err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); ++ if (err < 0) ++ return err; ++ err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); ++ if (err < 0) ++ return err; ++ ++ spec->multiout.max_channels = spec->multiout.num_dacs * 2; ++ ++ if (spec->autocfg.dig_out_pin) ++ spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; ++ ++ spec->extra_dig_out_nid = 0x1B; ++ ++ if (spec->kctl_alloc) ++ spec->mixers[spec->num_mixers++] = spec->kctl_alloc; ++ ++ spec->input_mux = &spec->private_imux[0]; ++ ++ if (spec->hp_mux) ++ spec->mixers[spec->num_mixers++] = via_hp_mixer; ++ ++ return 1; ++} ++ ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++static struct hda_amp_list vt1702_loopbacks[] = { ++ { 0x1A, HDA_INPUT, 1 }, ++ { 0x1A, HDA_INPUT, 2 }, ++ { 0x1A, HDA_INPUT, 3 }, ++ { 0x1A, HDA_INPUT, 4 }, ++ { } /* end */ ++}; ++#endif ++ ++static int patch_vt1702(struct hda_codec *codec) ++{ ++ struct via_spec *spec; ++ int err; ++ unsigned int response; ++ unsigned char control; ++ ++ /* create a codec specific record */ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ codec->spec = spec; ++ ++ /* automatic parse from the BIOS config */ ++ err = vt1702_parse_auto_config(codec); ++ if (err < 0) { ++ via_free(codec); ++ return err; ++ } else if (!err) { ++ printk(KERN_INFO "hda_codec: Cannot set up configuration " ++ "from BIOS. Using genenic mode...\n"); ++ } ++ ++ spec->init_verbs[spec->num_iverbs++] = vt1702_volume_init_verbs; ++ spec->init_verbs[spec->num_iverbs++] = vt1702_uniwill_init_verbs; ++ ++ spec->stream_name_analog = "VT1702 Analog"; ++ spec->stream_analog_playback = &vt1702_pcm_analog_playback; ++ spec->stream_analog_capture = &vt1702_pcm_analog_capture; ++ ++ spec->stream_name_digital = "VT1702 Digital"; ++ spec->stream_digital_playback = &vt1702_pcm_digital_playback; ++ ++ if (!spec->adc_nids && spec->input_mux) { ++ spec->adc_nids = vt1702_adc_nids; ++ spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids); ++ spec->mixers[spec->num_mixers] = vt1702_capture_mixer; ++ spec->num_mixers++; ++ } ++ ++ codec->patch_ops = via_patch_ops; ++ ++ codec->patch_ops.init = via_auto_init; ++ codec->patch_ops.unsol_event = via_unsol_event; ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++ spec->loopback.amplist = vt1702_loopbacks; ++#endif ++ ++ /* Open backdoor */ ++ response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0); ++ control = (unsigned char)(response & 0xff); ++ control |= 0x3; ++ snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control); ++ ++ /* Enable GPIO 0&1 for volume&mute control */ ++ /* Enable GPIO 2 for DMIC-DATA */ ++ response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0); ++ control = (unsigned char)((response >> 16) & 0x3f); ++ snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control); ++ ++ return 0; ++} ++ + /* + * patch entries + */ +@@ -2022,5 +3299,37 @@ + .patch = patch_vt1708B_4ch}, + { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", + .patch = patch_vt1708B_4ch}, ++ { .id = 0x11060397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11061397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11062397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11063397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11064397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11065397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11066397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11067397, .name = "VIA VT1708S", ++ .patch = patch_vt1708S}, ++ { .id = 0x11060398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11061398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11062398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11063398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11064398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11065398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11066398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, ++ { .id = 0x11067398, .name = "VIA VT1702", ++ .patch = patch_vt1702}, + {} /* terminator */ + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-ad1884a-mobile-init-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-ad1884a-mobile-init-fix new file mode 100644 index 000000000..57a3a598e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-ad1884a-mobile-init-fix @@ -0,0 +1,82 @@ +From: Takashi Iwai +Subject: ALSA: hda - Fix init verbs of AD1884A mobile model +Patch-mainline: +References: bnc#495668 + +The current ad1884a-mobile model has a problem that the speaker output +doesn't work sometimes after boot or power-saving on some HP laptops. +It seems that the verbs accessing to the non-functional widgets cause +this problem. + +This patch simplifies the init verbs for mobile model not to touch +unnecessary setups so that it avoids the speaker-mute problem. + +Signed-off-by: Takashi Iwai + +--- + +--- + sound/pci/hda/patch_analog.c | 45 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 44 insertions(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3798,6 +3798,49 @@ static struct hda_verb ad1884a_laptop_ve + { } /* end */ + }; + ++static struct hda_verb ad1884a_mobile_verbs[] = { ++ /* DACs; unmute as default */ ++ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ ++ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ ++ /* Port-A (HP) mixer - route only from analog mixer */ ++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ /* Port-A pin */ ++ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ /* Port-A (HP) pin - always unmuted */ ++ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ /* Port-B (mic jack) pin */ ++ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ ++ /* Port-C (int mic) pin */ ++ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ ++ /* Port-F (int speaker) mixer - route only from analog mixer */ ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, ++ /* Port-F pin */ ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ /* Analog mixer; mute as default */ ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, ++ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, ++ /* Analog Mix output amp */ ++ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ /* capture sources */ ++ /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ ++ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, ++ {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, ++ /* unsolicited event for pin-sense */ ++ {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, ++ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, ++ { } /* end */ ++}; ++ + /* + * Thinkpad X300 + * 0x11 - HP +@@ -3976,7 +4019,7 @@ static int patch_ad1884a(struct hda_code + break; + case AD1884A_MOBILE: + spec->mixers[0] = ad1884a_mobile_mixers; +- spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; ++ spec->init_verbs[0] = ad1884a_mobile_verbs; + spec->multiout.dig_out_nid = 0; + codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; + codec->patch_ops.init = ad1884a_hp_init; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc268-mono-output-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc268-mono-output-fix new file mode 100644 index 000000000..fa5e59f06 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc268-mono-output-fix @@ -0,0 +1,121 @@ +From 3f3b7c1aed70fa25c6811f830c5fb1a7054681ae Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 17 Jul 2009 14:36:59 +0200 +Subject: ALSA: hda - Fix ALC268 parser for mono speaker +Patch-mainline: +References: bnc#467846 + +- Parse the mono output pin 0x16 correctly even as the primary output +- Create "Speaker" volume control if the primary output is a speaker +- Fix the wrong direction of (optional) "Mono" switch + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 62 +++++++++++++++++++++++++++++------------- + 1 file changed, 43 insertions(+), 19 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -11421,26 +11421,38 @@ static int alc268_new_analog_output(stru + const char *ctlname, int idx) + { + char name[32]; ++ hda_nid_t dac; + int err; + + sprintf(name, "%s Playback Volume", ctlname); +- if (nid == 0x14) { +- err = add_control(spec, ALC_CTL_WIDGET_VOL, name, +- HDA_COMPOSE_AMP_VAL(0x02, 3, idx, +- HDA_OUTPUT)); +- if (err < 0) +- return err; +- } else if (nid == 0x15) { ++ switch (nid) { ++ case 0x14: ++ case 0x16: ++ dac = 0x02; ++ break; ++ case 0x15: ++ dac = 0x03; ++ break; ++ default: ++ return 0; ++ } ++ if (spec->multiout.dac_nids[0] != dac && ++ spec->multiout.dac_nids[1] != dac) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, name, +- HDA_COMPOSE_AMP_VAL(0x03, 3, idx, ++ HDA_COMPOSE_AMP_VAL(dac, 3, idx, + HDA_OUTPUT)); + if (err < 0) + return err; +- } else +- return -1; ++ spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; ++ } ++ + sprintf(name, "%s Playback Switch", ctlname); +- err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, ++ if (nid != 0x16) ++ err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); ++ else /* mono */ ++ err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, ++ HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); + if (err < 0) + return err; + return 0; +@@ -11453,14 +11465,19 @@ static int alc268_auto_create_multi_out_ + hda_nid_t nid; + int err; + +- spec->multiout.num_dacs = 2; /* only use one dac */ + spec->multiout.dac_nids = spec->private_dac_nids; +- spec->multiout.dac_nids[0] = 2; +- spec->multiout.dac_nids[1] = 3; + + nid = cfg->line_out_pins[0]; +- if (nid) +- alc268_new_analog_output(spec, nid, "Front", 0); ++ if (nid) { ++ const char *name; ++ if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ++ name = "Speaker"; ++ else ++ name = "Front"; ++ err = alc268_new_analog_output(spec, nid, name, 0); ++ if (err < 0) ++ return err; ++ } + + nid = cfg->speaker_pins[0]; + if (nid == 0x1d) { +@@ -11469,16 +11486,23 @@ static int alc268_auto_create_multi_out_ + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; ++ } else { ++ err = alc268_new_analog_output(spec, nid, "Speaker", 0); ++ if (err < 0) ++ return err; + } + nid = cfg->hp_pins[0]; +- if (nid) +- alc268_new_analog_output(spec, nid, "Headphone", 0); ++ if (nid) { ++ err = alc268_new_analog_output(spec, nid, "Headphone", 0); ++ if (err < 0) ++ return err; ++ } + + nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; + if (nid == 0x16) { + err = add_control(spec, ALC_CTL_WIDGET_MUTE, + "Mono Playback Switch", +- HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT)); ++ HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc269-fix-vmaster b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc269-fix-vmaster new file mode 100644 index 000000000..ec1063cbc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc269-fix-vmaster @@ -0,0 +1,31 @@ +From 100d5eb36ba20dc0b99a17ea2b9800c567bfc3d1 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 10 Aug 2009 11:55:51 +0200 +Subject: [PATCH] ALSA: hda - Add missing vmaster initialization for ALC269 +Patch-mainline: +References: bnc#527361 + +Without the initialization of vmaster NID, the dB information got +confused for ALC269 codec. + +Reference: Novell bnc#527361 + https://bugzilla.novell.com/show_bug.cgi?id=527361 + +Signed-off-by: Takashi Iwai +Cc: + +--- + sound/pci/hda/patch_realtek.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -12654,6 +12654,8 @@ + spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); + spec->capsrc_nids = alc269_capsrc_nids; + ++ spec->vmaster_nid = 0x02; ++ + codec->patch_ops = alc_patch_ops; + if (board_config == ALC269_AUTO) + spec->init_hook = alc269_auto_init; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-coef-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-coef-fix new file mode 100644 index 000000000..ebf53683c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-coef-fix @@ -0,0 +1,27 @@ +From 37db623ae2a7bde234a8ed683d0d13d6f939199c Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 5 Mar 2009 09:40:16 +0100 +Subject: ALSA: hda - Fix check of ALC888S-VC in alc888_coef_init() +Patch-mainline: +References: bnc#482796 + +Fixed the wrong bits check to identify ALC888S-VC model in +alc888_coef_init(). + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -884,7 +884,7 @@ static void alc888_coef_init(struct hda_ + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); + tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); +- if ((tmp & 0xf0) == 2) ++ if ((tmp & 0xf0) == 0x20) + /* alc888S-VC */ + snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x830); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-3stack-auto-mute b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-3stack-auto-mute new file mode 100644 index 000000000..8df672f5a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-3stack-auto-mute @@ -0,0 +1,76 @@ +From 8718b700ccbcc3c6016d38a75e005293c3660f1c Mon Sep 17 00:00:00 2001 +From: Herton Ronaldo Krzesinski +Date: Wed, 4 Mar 2009 14:22:51 -0300 +Subject: ALSA: hda - Add headphone automute support for 3stack-hp model (ALC888) +Patch-mainline: +References: bnc#482796 + +Mute speaker outputs on headphone insertion for machines that use +3stack-hp model. + +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 38 +++++++++++++++++++++++++++++++++----- + 1 file changed, 33 insertions(+), 5 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -7853,16 +7853,42 @@ static struct hda_verb alc888_lenovo_sky + { } /* end */ + }; + ++static struct hda_verb alc888_6st_dell_verbs[] = { ++ {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, ++ { } ++}; ++ ++static void alc888_3st_hp_front_automute(struct hda_codec *codec) ++{ ++ unsigned int present, bits; ++ ++ present = snd_hda_codec_read(codec, 0x1b, 0, ++ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; ++ bits = present ? HDA_AMP_MUTE : 0; ++ snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, bits); ++ snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, bits); ++ snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, bits); ++} ++ ++static void alc888_3st_hp_unsol_event(struct hda_codec *codec, ++ unsigned int res) ++{ ++ switch (res >> 26) { ++ case ALC880_HP_EVENT: ++ alc888_3st_hp_front_automute(codec); ++ break; ++ } ++} ++ + static struct hda_verb alc888_3st_hp_verbs[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */ +- { } +-}; +- +-static struct hda_verb alc888_6st_dell_verbs[] = { + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +- { } ++ { } /* end */ + }; + + /* +@@ -8715,6 +8741,8 @@ static struct alc_config_preset alc883_p + .channel_mode = alc888_3st_hp_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, ++ .unsol_event = alc888_3st_hp_unsol_event, ++ .init_hook = alc888_3st_hp_front_automute, + }, + [ALC888_6ST_DELL] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-4ch-mode b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-4ch-mode new file mode 100644 index 000000000..838e8f19c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-4ch-mode @@ -0,0 +1,67 @@ +From 3ea0d7cf472c6118bb8c0842d606f5436251e179 Mon Sep 17 00:00:00 2001 +From: Herton Ronaldo Krzesinski +Date: Wed, 4 Mar 2009 14:22:50 -0300 +Subject: ALSA: hda - Add 4 channel mode for 3stack-hp model (ALC888) +Patch-mainline: +References: bnc#482796 + +Add additional 4 channel mode for 3stack-hp models. + +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -7865,24 +7865,45 @@ static struct hda_verb alc888_6st_dell_v + { } + }; + ++/* ++ * 2ch mode ++ */ + static struct hda_verb alc888_3st_hp_2ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +- { } ++ { } /* end */ ++}; ++ ++/* ++ * 4ch mode ++ */ ++static struct hda_verb alc888_3st_hp_4ch_init[] = { ++ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, ++ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, ++ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, ++ { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, ++ { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, ++ { } /* end */ + }; + ++/* ++ * 6ch mode ++ */ + static struct hda_verb alc888_3st_hp_6ch_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, ++ { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +- { } ++ { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 }, ++ { } /* end */ + }; + +-static struct hda_channel_mode alc888_3st_hp_modes[2] = { ++static struct hda_channel_mode alc888_3st_hp_modes[3] = { + { 2, alc888_3st_hp_2ch_init }, ++ { 4, alc888_3st_hp_4ch_init }, + { 6, alc888_3st_hp_6ch_init }, + }; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-quirk new file mode 100644 index 000000000..e4d2a9c78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-alc888-hp-quirk @@ -0,0 +1,30 @@ +From 7ec30f0e7768985ab2ef6334840e3fc8fa253421 Mon Sep 17 00:00:00 2001 +From: Herton Ronaldo Krzesinski +Date: Wed, 4 Mar 2009 14:22:52 -0300 +Subject: ALSA: hda - Map 3stack-hp model (ALC888) for HP Educ.ar +Patch-mainline: +References: bnc#482796 + +Added model=3stack-hp for HP Educ.ar desktop machine (103c:2a72). + +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -8476,8 +8476,11 @@ static struct snd_pci_quirk alc883_cfg_t + SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), + SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), ++ SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), ++ SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), + SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), ++ SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), + SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-alc269-lenovo-capture-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-alc269-lenovo-capture-fix new file mode 100644 index 000000000..db099e349 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-alc269-lenovo-capture-fix @@ -0,0 +1,32 @@ +From: Takashi Iwai +Subject: ALSA: Fix capture volume for Lenovo S10E +Patch-mainline: +References: bnc#516213 + +The capture mixer controls are missing for Lenovo S10E with ALC269. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -11989,7 +11989,6 @@ static struct snd_kcontrol_new alc269_qu + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), +- HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), +@@ -12518,7 +12517,7 @@ static struct alc_config_preset alc269_p + .input_mux = &alc269_capture_source, + }, + [ALC269_QUANTA_FL1] = { +- .mixers = { alc269_quanta_fl1_mixer }, ++ .mixers = { alc269_quanta_fl1_mixer, alc269_epc_capture_mixer }, + .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-ati-pos-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-ati-pos-fix new file mode 100644 index 000000000..748a593cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-ati-pos-fix @@ -0,0 +1,62 @@ +From: Takashi Iwai +Subject: ALSA: hda - Workaround for buggy DMA position on ATI controllers +Patch-mainline: 2.6.30-rc1 +References: bnc#502733 + +The position-buffer on ATI controllers are unreliable as well as +on VIA chips, thus the same workaround for DMA position reading as +VIA is useful for ATI. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -2065,26 +2065,31 @@ + { + const struct snd_pci_quirk *q; + +- /* Check VIA HD Audio Controller exist */ +- if (chip->pci->vendor == PCI_VENDOR_ID_VIA && +- chip->pci->device == VIA_HDAC_DEVICE_ID) { ++ switch (fix) { ++ case POS_FIX_LPIB: ++ case POS_FIX_POSBUF: ++ return fix; ++ } ++ ++ /* Check VIA/ATI HD Audio Controller exist */ ++ switch (chip->driver_type) { ++ case AZX_DRIVER_VIA: ++ case AZX_DRIVER_ATI: + chip->via_dmapos_patch = 1; + /* Use link position directly, avoid any transfer problem. */ + return POS_FIX_LPIB; + } + chip->via_dmapos_patch = 0; + +- if (fix == POS_FIX_AUTO) { +- q = snd_pci_quirk_lookup(chip->pci, position_fix_list); +- if (q) { +- printk(KERN_INFO +- "hda_intel: position_fix set to %d " +- "for device %04x:%04x\n", +- q->value, q->subvendor, q->subdevice); +- return q->value; +- } ++ q = snd_pci_quirk_lookup(chip->pci, position_fix_list); ++ if (q) { ++ printk(KERN_INFO ++ "hda_intel: position_fix set to %d " ++ "for device %04x:%04x\n", ++ q->value, q->subvendor, q->subdevice); ++ return q->value; + } +- return fix; ++ return POS_FIX_AUTO; + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-bus-intapi-change b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-bus-intapi-change new file mode 100644 index 000000000..c3c520284 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-bus-intapi-change @@ -0,0 +1,294 @@ +From: Takashi Iwai +Subject: ALSA: hda - simplify hda_bus ops callbacks +Patch-mainline: 2.6.29-rc1 +References: + +The hda_bus ops callback take struct hda_bus pointer. +Also, the command callback takes the composed command word, instead of +each small bits in arguments. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 59 +++++++++++++++++++++++++++++++++++----------- + sound/pci/hda/hda_codec.h | 7 ++--- + sound/pci/hda/hda_intel.c | 55 +++++++++++++++++------------------------- + 3 files changed, 71 insertions(+), 50 deletions(-) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -107,6 +107,23 @@ + static inline void hda_keep_power_on(struct hda_codec *codec) {} + #endif + ++/* ++ * Compose a 32bit command word to be sent to the HD-audio controller ++ */ ++static inline unsigned int ++make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, ++ unsigned int verb, unsigned int parm) ++{ ++ u32 val; ++ ++ val = (u32)(codec->addr & 0x0f) << 28; ++ val |= (u32)direct << 27; ++ val |= (u32)nid << 20; ++ val |= verb << 8; ++ val |= parm; ++ return val; ++} ++ + /** + * snd_hda_codec_read - send a command and get the response + * @codec: the HDA codec +@@ -123,14 +140,17 @@ + int direct, + unsigned int verb, unsigned int parm) + { ++ struct hda_bus *bus = codec->bus; + unsigned int res; ++ ++ res = make_codec_cmd(codec, nid, direct, verb, parm); + snd_hda_power_up(codec); +- mutex_lock(&codec->bus->cmd_mutex); +- if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) +- res = codec->bus->ops.get_response(codec); ++ mutex_lock(&bus->cmd_mutex); ++ if (!bus->ops.command(bus, res)) ++ res = bus->ops.get_response(bus); + else + res = (unsigned int)-1; +- mutex_unlock(&codec->bus->cmd_mutex); ++ mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); + return res; + } +@@ -150,11 +170,15 @@ + int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int parm) + { ++ struct hda_bus *bus = codec->bus; ++ unsigned int res; + int err; ++ ++ res = make_codec_cmd(codec, nid, direct, verb, parm); + snd_hda_power_up(codec); +- mutex_lock(&codec->bus->cmd_mutex); +- err = codec->bus->ops.command(codec, nid, direct, verb, parm); +- mutex_unlock(&codec->bus->cmd_mutex); ++ mutex_lock(&bus->cmd_mutex); ++ err = bus->ops.command(bus, res); ++ mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); + return err; + } +@@ -1796,10 +1820,14 @@ + int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) + { ++ struct hda_bus *bus = codec->bus; ++ unsigned int res; + int err; ++ ++ res = make_codec_cmd(codec, nid, direct, verb, parm); + snd_hda_power_up(codec); +- mutex_lock(&codec->bus->cmd_mutex); +- err = codec->bus->ops.command(codec, nid, direct, verb, parm); ++ mutex_lock(&bus->cmd_mutex); ++ err = bus->ops.command(bus, res); + if (!err) { + struct hda_cache_head *c; + u32 key = build_cmd_cache_key(nid, verb); +@@ -1807,7 +1835,7 @@ + if (c) + c->val = parm; + } +- mutex_unlock(&codec->bus->cmd_mutex); ++ mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); + return err; + } +@@ -2507,6 +2535,7 @@ + { + struct hda_codec *codec = + container_of(work, struct hda_codec, power_work.work); ++ struct hda_bus *bus = codec->bus; + + if (!codec->power_on || codec->power_count) { + codec->power_transition = 0; +@@ -2514,8 +2543,8 @@ + } + + hda_call_codec_suspend(codec); +- if (codec->bus->ops.pm_notify) +- codec->bus->ops.pm_notify(codec); ++ if (bus->ops.pm_notify) ++ bus->ops.pm_notify(bus); + } + + static void hda_keep_power_on(struct hda_codec *codec) +@@ -2526,13 +2555,15 @@ + + void snd_hda_power_up(struct hda_codec *codec) + { ++ struct hda_bus *bus = codec->bus; ++ + codec->power_count++; + if (codec->power_on || codec->power_transition) + return; + + codec->power_on = 1; +- if (codec->bus->ops.pm_notify) +- codec->bus->ops.pm_notify(codec); ++ if (bus->ops.pm_notify) ++ bus->ops.pm_notify(bus); + hda_call_codec_resume(codec); + cancel_delayed_work(&codec->power_work); + codec->power_transition = 0; +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -536,15 +536,14 @@ + /* bus operators */ + struct hda_bus_ops { + /* send a single command */ +- int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, +- unsigned int verb, unsigned int parm); ++ int (*command)(struct hda_bus *bus, unsigned int cmd); + /* get a response from the last command */ +- unsigned int (*get_response)(struct hda_codec *codec); ++ unsigned int (*get_response)(struct hda_bus *bus); + /* free the private data */ + void (*private_free)(struct hda_bus *); + #ifdef CONFIG_SND_HDA_POWER_SAVE + /* notify power-up/down from codec to controller */ +- void (*pm_notify)(struct hda_codec *codec); ++ void (*pm_notify)(struct hda_bus *bus); + #endif + }; + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -527,9 +527,9 @@ + } + + /* send a command */ +-static int azx_corb_send_cmd(struct hda_codec *codec, u32 val) ++static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) + { +- struct azx *chip = codec->bus->private_data; ++ struct azx *chip = bus->private_data; + unsigned int wp; + + /* add command to corb */ +@@ -577,9 +577,9 @@ + } + + /* receive a response */ +-static unsigned int azx_rirb_get_response(struct hda_codec *codec) ++static unsigned int azx_rirb_get_response(struct hda_bus *bus) + { +- struct azx *chip = codec->bus->private_data; ++ struct azx *chip = bus->private_data; + unsigned long timeout; + + again: +@@ -596,7 +596,7 @@ + } + if (time_after(jiffies, timeout)) + break; +- if (codec->bus->needs_damn_long_delay) ++ if (bus->needs_damn_long_delay) + msleep(2); /* temporary workaround */ + else { + udelay(10); +@@ -646,9 +646,9 @@ + */ + + /* send a command */ +-static int azx_single_send_cmd(struct hda_codec *codec, u32 val) ++static int azx_single_send_cmd(struct hda_bus *bus, u32 val) + { +- struct azx *chip = codec->bus->private_data; ++ struct azx *chip = bus->private_data; + int timeout = 50; + + while (timeout--) { +@@ -671,9 +671,9 @@ + } + + /* receive a response */ +-static unsigned int azx_single_get_response(struct hda_codec *codec) ++static unsigned int azx_single_get_response(struct hda_bus *bus) + { +- struct azx *chip = codec->bus->private_data; ++ struct azx *chip = bus->private_data; + int timeout = 50; + + while (timeout--) { +@@ -696,38 +696,29 @@ + */ + + /* send a command */ +-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, +- int direct, unsigned int verb, +- unsigned int para) +-{ +- struct azx *chip = codec->bus->private_data; +- u32 val; +- +- val = (u32)(codec->addr & 0x0f) << 28; +- val |= (u32)direct << 27; +- val |= (u32)nid << 20; +- val |= verb << 8; +- val |= para; +- chip->last_cmd = val; ++static int azx_send_cmd(struct hda_bus *bus, unsigned int val) ++{ ++ struct azx *chip = bus->private_data; + ++ chip->last_cmd = val; + if (chip->single_cmd) +- return azx_single_send_cmd(codec, val); ++ return azx_single_send_cmd(bus, val); + else +- return azx_corb_send_cmd(codec, val); ++ return azx_corb_send_cmd(bus, val); + } + + /* get a response */ +-static unsigned int azx_get_response(struct hda_codec *codec) ++static unsigned int azx_get_response(struct hda_bus *bus) + { +- struct azx *chip = codec->bus->private_data; ++ struct azx *chip = bus->private_data; + if (chip->single_cmd) +- return azx_single_get_response(codec); ++ return azx_single_get_response(bus); + else +- return azx_rirb_get_response(codec); ++ return azx_rirb_get_response(bus); + } + + #ifdef CONFIG_SND_HDA_POWER_SAVE +-static void azx_power_notify(struct hda_codec *codec); ++static void azx_power_notify(struct hda_bus *bus); + #endif + + /* reset codec link */ +@@ -1905,13 +1896,13 @@ + + #ifdef CONFIG_SND_HDA_POWER_SAVE + /* power-up/down the controller */ +-static void azx_power_notify(struct hda_codec *codec) ++static void azx_power_notify(struct hda_bus *bus) + { +- struct azx *chip = codec->bus->private_data; ++ struct azx *chip = bus->private_data; + struct hda_codec *c; + int power_on = 0; + +- list_for_each_entry(c, &codec->bus->codec_list, list) { ++ list_for_each_entry(c, &bus->codec_list, list) { + if (c->power_on) { + power_on = 1; + break; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-limit-verb-retry b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-limit-verb-retry new file mode 100644 index 000000000..d1ca533dd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-limit-verb-retry @@ -0,0 +1,91 @@ +From: Takashi Iwai +Subject: ALSA: hda - Limit codec-verb retry to limited hardwares +Patch-mainline: +References: bnc#502903 + +The reset of a BUS controller during operations is somehow risky and +shouldn't be done inevitably for devices that have apparently no such +codec-communication problems. + +This patch adds the check of the hardware and limits the bus-reset +capability. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 12 ++---------- + sound/pci/hda/hda_codec.h | 3 +++ + sound/pci/hda/hda_intel.c | 2 +- + sound/pci/hda/patch_sigmatel.c | 9 +++++++++ + 4 files changed, 15 insertions(+), 11 deletions(-) + +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -588,6 +588,9 @@ + + /* misc op flags */ + unsigned int needs_damn_long_delay :1; ++ unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ ++ unsigned int sync_write:1; /* sync after verb write */ ++ /* status for codec/controller */ + unsigned int rirb_error:1; /* error in codec communication */ + unsigned int response_reset:1; /* controller was reset */ + unsigned int in_reset:1; /* during reset operation */ +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -645,7 +645,7 @@ + * to the single_cmd mode + */ + bus->rirb_error = 1; +- if (!bus->response_reset && !bus->in_reset) { ++ if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { + bus->response_reset = 1; + return -1; /* give a chance to retry */ + } +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -229,11 +229,6 @@ + return res; + } + +-/* Define the below to send and receive verbs synchronously. +- * If you often get any codec communication errors, this is worth to try. +- */ +-#define SND_HDA_SUPPORT_SYNC_WRITE +- + /** + * snd_hda_codec_write - send a single command without waiting for response + * @codec: the HDA codec +@@ -250,12 +245,9 @@ + unsigned int verb, unsigned int parm) + { + unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); +-#ifdef SND_HDA_SUPPORT_SYNC_WRITE + unsigned int res; +- return codec_exec_verb(codec, cmd, &res); +-#else +- return codec_exec_verb(codec, cmd, NULL); +-#endif ++ return codec_exec_verb(codec, cmd, ++ codec->bus->sync_write ? &res : NULL); + } + + /** +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -4804,6 +4804,15 @@ + codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; + } + ++ /* Some HP machines seem to have unstable codec communications ++ * especially with ATI fglrx driver. For recovering from the ++ * CORB/RIRB stall, allow the BUS reset and keep always sync ++ */ ++ if (spec->board_config == STAC_HP_DV5) { ++ codec->bus->sync_write = 1; ++ codec->bus->allow_bus_reset = 1; ++ } ++ + spec->aloopback_mask = 0x50; + spec->aloopback_shift = 0; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-verb-retry b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-verb-retry new file mode 100644 index 000000000..3318b0976 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-codec-verb-retry @@ -0,0 +1,175 @@ +From: Takashi Iwai +Subject: ALSA: Add codec bus reset and verb-retry at critical errors +Patch-mainline: +References: bnc#502903 + +The Volna machine causes a severe CORB/RIRB stall when PA is started +together with fglrx. This cannot be recovered without the controller +reset. + +This patch allows the bus controller reset at critical errors so +that the communication gets recovered again. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 13 +++++++++++-- + sound/pci/hda/hda_codec.h | 7 ++++++- + sound/pci/hda/hda_intel.c | 37 +++++++++++++++++++++++++++++++++---- + 3 files changed, 50 insertions(+), 7 deletions(-) + +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -541,6 +541,8 @@ + unsigned int (*get_response)(struct hda_bus *bus); + /* free the private data */ + void (*private_free)(struct hda_bus *); ++ /* reset bus for retry verb */ ++ void (*bus_reset)(struct hda_bus *bus); + #ifdef CONFIG_SND_HDA_POWER_SAVE + /* notify power-up/down from codec to controller */ + void (*pm_notify)(struct hda_bus *bus); +@@ -586,6 +588,9 @@ + + /* misc op flags */ + unsigned int needs_damn_long_delay :1; ++ unsigned int rirb_error:1; /* error in codec communication */ ++ unsigned int response_reset:1; /* controller was reset */ ++ unsigned int in_reset:1; /* during reset operation */ + }; + + /* +@@ -827,7 +832,7 @@ + * power management + */ + #ifdef CONFIG_PM +-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); ++int snd_hda_suspend(struct hda_bus *bus); + int snd_hda_resume(struct hda_bus *bus); + #endif + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -187,6 +187,7 @@ + + if (res) + *res = -1; ++ again: + snd_hda_power_up(codec); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, cmd); +@@ -194,6 +195,15 @@ + *res = bus->ops.get_response(bus); + mutex_unlock(&bus->cmd_mutex); + snd_hda_power_down(codec); ++ if (res && *res == -1 && bus->rirb_error) { ++ if (bus->response_reset) { ++ snd_printd("hda_codec: resetting BUS due to " ++ "fatal communication error\n"); ++ bus->ops.bus_reset(bus); ++ } ++ goto again; ++ } ++ bus->response_reset = 0; + return err; + } + +@@ -3279,11 +3289,10 @@ + /** + * snd_hda_suspend - suspend the codecs + * @bus: the HDA bus +- * @state: suspsend state + * + * Returns 0 if successful. + */ +-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) ++int snd_hda_suspend(struct hda_bus *bus) + { + struct hda_codec *codec; + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -600,6 +600,7 @@ + } + if (!chip->rirb.cmds) { + smp_rmb(); ++ bus->rirb_error = 0; + return chip->rirb.res; /* the last value */ + } + if (time_after(jiffies, timeout)) +@@ -640,14 +641,23 @@ + return -1; + } + ++ /* a fatal communication error; need either to reset or to fallback ++ * to the single_cmd mode ++ */ ++ bus->rirb_error = 1; ++ if (!bus->response_reset && !bus->in_reset) { ++ bus->response_reset = 1; ++ return -1; /* give a chance to retry */ ++ } ++ + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " + "switching to single_cmd mode: last cmd=0x%08x\n", + chip->last_cmd); +- chip->rirb.rp = azx_readb(chip, RIRBWP); +- chip->rirb.cmds = 0; +- /* switch to single_cmd mode */ + chip->single_cmd = 1; ++ bus->response_reset = 0; ++ /* re-initialize CORB/RIRB */ + azx_free_cmd_io(chip); ++ azx_init_cmd_io(chip); + return -1; + } + +@@ -688,6 +698,7 @@ + struct azx *chip = bus->private_data; + int timeout = 50; + ++ bus->rirb_error = 0; + while (timeout--) { + /* check ICB busy bit */ + if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { +@@ -1227,6 +1238,23 @@ + + static void azx_stop_chip(struct azx *chip); + ++static void azx_bus_reset(struct hda_bus *bus) ++{ ++ struct azx *chip = bus->private_data; ++ int i; ++ ++ bus->in_reset = 1; ++ azx_stop_chip(chip); ++ azx_init_chip(chip); ++ if (chip->initialized) { ++ for (i = 0; i < AZX_MAX_PCMS; i++) ++ snd_pcm_suspend_all(chip->pcm[i]); ++ snd_hda_suspend(chip->bus); ++ snd_hda_resume(chip->bus); ++ } ++ bus->in_reset = 0; ++} ++ + /* + * Codec initialization + */ +@@ -1248,6 +1276,7 @@ + bus_temp.pci = chip->pci; + bus_temp.ops.command = azx_send_cmd; + bus_temp.ops.get_response = azx_get_response; ++ bus_temp.ops.bus_reset = azx_bus_reset; + #ifdef CONFIG_SND_HDA_POWER_SAVE + bus_temp.ops.pm_notify = azx_power_notify; + #endif +@@ -2013,7 +2042,7 @@ + for (i = 0; i < AZX_MAX_PCMS; i++) + snd_pcm_suspend_all(chip->pcm[i]); + if (chip->initialized) +- snd_hda_suspend(chip->bus, state); ++ snd_hda_suspend(chip->bus); + azx_stop_chip(chip); + if (chip->irq >= 0) { + free_irq(chip->irq, chip); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-forced-codec-slots b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-forced-codec-slots new file mode 100644 index 000000000..cce8e170a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-forced-codec-slots @@ -0,0 +1,112 @@ +From: Takashi Iwai +Subject: ALSA: hda - Allow fixed codec-probe mask +Patch-mainline: 2.6.30-rc1 +References: bnc#502733 + +Some devices have broken BIOS and they don't set the codec probe-bit +properly after cleared by the driver. This makes the driver skipping +the necessary codec slots. + +Since BIOS update isn't always easy, now the semantics of probe_mask +option is changed a bit. When it contains the bit 8 (0x100), the +lower bits are used to probe that slots regardless of codec-probe bits +returned by the hardware. + +For example, probe_mask=0x103 will force to probe the codec slot #0 +and #1. + +Signed-off-by: Takashi Iwai +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 29 ++++++++++++++++++++++------- + 1 file changed, 22 insertions(+), 7 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -373,6 +373,7 @@ struct azx { + + /* HD codec */ + unsigned short codec_mask; ++ int codec_probe_mask; /* copied from probe_mask option */ + struct hda_bus *bus; + + /* CORB/RIRB */ +@@ -1222,8 +1223,7 @@ static unsigned int azx_max_codecs[AZX_N + [AZX_DRIVER_TERA] = 1, + }; + +-static int __devinit azx_codec_create(struct azx *chip, const char *model, +- unsigned int codec_probe_mask) ++static int __devinit azx_codec_create(struct azx *chip, const char *model) + { + struct hda_bus_template bus_temp; + int c, codecs, err; +@@ -1253,7 +1253,7 @@ static int __devinit azx_codec_create(st + + /* First try to probe all given codec slots */ + for (c = 0; c < max_slots; c++) { +- if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { ++ if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + if (probe_codec(chip, c) < 0) { + /* Some BIOSen give you wrong codec addresses + * that don't exist +@@ -1277,7 +1277,7 @@ static int __devinit azx_codec_create(st + + /* Then create codec instances */ + for (c = 0; c < max_slots; c++) { +- if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { ++ if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + struct hda_codec *codec; + err = snd_hda_codec_new(chip->bus, c, &codec); + if (err < 0) +@@ -2153,23 +2153,38 @@ static struct snd_pci_quirk probe_mask_l + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + /* broken BIOS */ + SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), ++ /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ ++ SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), ++ /* forced codec slots */ ++ SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), + {} + }; + ++#define AZX_FORCE_CODEC_MASK 0x100 ++ + static void __devinit check_probe_mask(struct azx *chip, int dev) + { + const struct snd_pci_quirk *q; + +- if (probe_mask[dev] == -1) { ++ chip->codec_probe_mask = probe_mask[dev]; ++ if (chip->codec_probe_mask == -1) { + q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); + if (q) { + printk(KERN_INFO + "hda_intel: probe_mask set to 0x%x " + "for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); +- probe_mask[dev] = q->value; ++ chip->codec_probe_mask = q->value; + } + } ++ ++ /* check forced option */ ++ if (chip->codec_probe_mask != -1 && ++ (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) { ++ chip->codec_mask = chip->codec_probe_mask & 0xff; ++ printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n", ++ chip->codec_mask); ++ } + } + + +@@ -2407,7 +2422,7 @@ static int __devinit azx_probe(struct pc + card->private_data = chip; + + /* create codec instances */ +- err = azx_codec_create(chip, model[dev], probe_mask[dev]); ++ err = azx_codec_create(chip, model[dev]); + if (err < 0) + goto out_free; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-ad1984a-more-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-ad1984a-more-quirk new file mode 100644 index 000000000..e21e0246c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-ad1984a-more-quirk @@ -0,0 +1,28 @@ +From: Takashi Iwai +Subject: ALSA: update HP quirks for Zenith & co +Patch-mainline: +References: bnc#472789, bnc#479617 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3907,10 +3907,14 @@ + SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3072, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3073, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3074, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3075, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3076, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3077, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x3078, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3079, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x307a, "HP", AD1884A_MOBILE), ++ SND_PCI_QUIRK(0x103c, 0x30e1, "HP 2530p", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x360d, "HP 6530b", AD1884A_LAPTOP), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-ad1984a-more-quirk2 b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-ad1984a-more-quirk2 new file mode 100644 index 000000000..8396308fa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-ad1984a-more-quirk2 @@ -0,0 +1,21 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add yet more quirk for HP laptop +Patch-mainline: +References: bnc#502425, bnc#503101 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3919,6 +3919,7 @@ static struct snd_pci_quirk ad1884a_cfg_ + SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x360d, "HP 6530b", AD1884A_LAPTOP), + SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), ++ SND_PCI_QUIRK(0x103c, 0x3632, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), + {} + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-more-quirks b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-more-quirks new file mode 100644 index 000000000..bd14abe63 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-more-quirks @@ -0,0 +1,36 @@ +From: Takashi Iwai +Subject: ALSA: Add more quirks for HP laptops with IDT codec +Patch-mainline: +References: bnc#479558 + +Fix/add quirk entries for new HP laptops with IDT codec. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1760,14 +1760,18 @@ + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD71BXX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x308c, ++ "HP", STAC_HP_DV5), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x308d, ++ "HP", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2, +- "HP dv5", STAC_HP_M4), ++ "HP dv5", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, + "HP dv7", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7, + "HP dv4", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, +- "HP dv7", STAC_HP_M4), ++ "HP dv7", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600, + "HP dv5", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-xw-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-xw-quirk new file mode 100644 index 000000000..dfb57d7a4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hp-xw-quirk @@ -0,0 +1,23 @@ +From: Takashi Iwai +Subject: ALSA: hda - Add quirk for new HP xw series +Patch-mainline: +References: bnc#480448 + +Added a quirk for new HP machine with ALC262 codec. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -10458,6 +10458,7 @@ static struct snd_pci_quirk alc262_cfg_t + SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC), ++ SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC), + SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), + SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), + SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hwptr-stabilize b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hwptr-stabilize new file mode 100644 index 000000000..c00e20f82 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-hwptr-stabilize @@ -0,0 +1,165 @@ +From: Jaroslav Kysela +Subject: [ALSA] hda_intel: fix unexpected ring buffer positions +Patch-mainline: 2.6.30-rc3 +References: bnc#502733 + +I found two issues with ICH7-M (it should be related to other HDA chipsets +as well): + +- the ring buffer position is not reset when stream restarts (after xrun) - + solved by moving azx_stream_reset() call from open() to prepare() callback + and reset posbuf to zero (it might be filled with hw later than position() + callback is called) +- irq_ignore flag should be set also when ring buffer memory area is not + changed in prepare() callback - this patch replaces irq_ignore with + more universal check based on jiffies clock + +Signed-off-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 39 +++++++++++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 14 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -304,6 +304,9 @@ struct azx_dev { + unsigned int period_bytes; /* size of the period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ ++ unsigned int start_flag: 1; /* stream full start flag */ ++ unsigned long start_jiffies; /* start + minimum jiffies */ ++ unsigned long min_jiffies; /* minimum jiffies before position is valid */ + + void __iomem *sd_addr; /* stream descriptor pointer */ + +@@ -322,7 +325,6 @@ struct azx_dev { + unsigned int opened :1; + unsigned int running :1; + unsigned int irq_pending :1; +- unsigned int irq_ignore :1; + /* + * For VIA: + * A flag to ensure DMA position is 0 +@@ -964,7 +966,7 @@ static irqreturn_t azx_interrupt(int irq + struct azx *chip = dev_id; + struct azx_dev *azx_dev; + u32 status; +- int i; ++ int i, ok; + + spin_lock(&chip->reg_lock); + +@@ -980,18 +982,14 @@ static irqreturn_t azx_interrupt(int irq + azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); + if (!azx_dev->substream || !azx_dev->running) + continue; +- /* ignore the first dummy IRQ (due to pos_adj) */ +- if (azx_dev->irq_ignore) { +- azx_dev->irq_ignore = 0; +- continue; +- } + /* check whether this IRQ is really acceptable */ +- if (azx_position_ok(chip, azx_dev)) { ++ ok = azx_position_ok(chip, azx_dev); ++ if (ok == 1) { + azx_dev->irq_pending = 0; + spin_unlock(&chip->reg_lock); + snd_pcm_period_elapsed(azx_dev->substream); + spin_lock(&chip->reg_lock); +- } else if (chip->bus && chip->bus->workq) { ++ } else if (ok == 0 && chip->bus && chip->bus->workq) { + /* bogus IRQ, process it later */ + azx_dev->irq_pending = 1; + queue_work(chip->bus->workq, +@@ -1080,7 +1078,6 @@ static int azx_setup_periods(struct azx + bdl = (u32 *)azx_dev->bdl.area; + ofs = 0; + azx_dev->frags = 0; +- azx_dev->irq_ignore = 0; + pos_adj = bdl_pos_adj[chip->dev_index]; + if (pos_adj > 0) { + struct snd_pcm_runtime *runtime = substream->runtime; +@@ -1101,7 +1098,6 @@ static int azx_setup_periods(struct azx + &bdl, ofs, pos_adj, 1); + if (ofs < 0) + goto error; +- azx_dev->irq_ignore = 1; + } + } else + pos_adj = 0; +@@ -1147,6 +1143,9 @@ static void azx_stream_reset(struct azx + while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && + --timeout) + ; ++ ++ /* reset first position - may not be synced with hw at this time */ ++ *azx_dev->posbuf = 0; + } + + /* +@@ -1396,7 +1395,6 @@ static int azx_pcm_open(struct snd_pcm_s + snd_pcm_set_sync(substream); + mutex_unlock(&chip->open_mutex); + +- azx_stream_reset(chip, azx_dev); + return 0; + } + +@@ -1461,6 +1459,7 @@ static int azx_pcm_prepare(struct snd_pc + unsigned int bufsize, period_bytes, format_val; + int err; + ++ azx_stream_reset(chip, azx_dev); + format_val = snd_hda_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, +@@ -1489,6 +1488,8 @@ static int azx_pcm_prepare(struct snd_pc + return err; + } + ++ azx_dev->min_jiffies = (runtime->period_size * HZ) / ++ (runtime->rate * 2); + azx_setup_controller(chip, azx_dev); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; +@@ -1505,13 +1506,14 @@ static int azx_pcm_trigger(struct snd_pc + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev; + struct snd_pcm_substream *s; +- int start, nsync = 0, sbits = 0; ++ int rstart = 0, start, nsync = 0, sbits = 0; + int nwait, timeout; + + switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ rstart = 1; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: +- case SNDRV_PCM_TRIGGER_START: + start = 1; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +@@ -1541,6 +1543,10 @@ static int azx_pcm_trigger(struct snd_pc + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); ++ if (rstart) { ++ azx_dev->start_flag = 1; ++ azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies; ++ } + if (start) + azx_stream_start(chip, azx_dev); + else +@@ -1690,6 +1696,11 @@ static int azx_position_ok(struct azx *c + { + unsigned int pos; + ++ if (azx_dev->start_flag && ++ time_before_eq(jiffies, azx_dev->start_jiffies)) ++ return -1; /* bogus (too early) interrupt */ ++ azx_dev->start_flag = 0; ++ + pos = azx_get_position(chip, azx_dev); + if (chip->position_fix == POS_FIX_AUTO) { + if (!pos) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-idt92hd8x-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-idt92hd8x-fix new file mode 100644 index 000000000..cf3e5d293 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-idt92hd8x-fix @@ -0,0 +1,277 @@ +From 667067d8980249a71ccf82a55202fff2cd1cd54f Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 13 Aug 2009 18:14:42 +0200 +Subject: ALSA: hda - Fix / clean up IDT92HD83xxx codec parser +Patch-mainline: +References: bnc#531533 + +A few improvements for IDT 92HD83xxx codec pareser: +- Remove unused / deprecated mixer-amp controls +- Handle d-mics as normal inputs since this codec has no separate + MUXes for analog and digital +- Don't create duplicated controls for capture volumes with Mux + capture volumes + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 150 +++++++++++++++++++---------------------- + 1 file changed, 70 insertions(+), 80 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -349,14 +349,9 @@ + }; + #define stac92hd73xx_capsws stac92hd73xx_capvols + +-#define STAC92HD83XXX_NUM_DMICS 2 +-static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { +- 0x11, 0x12, 0 +-}; +- + #define STAC92HD83_DAC_COUNT 3 + +-static hda_nid_t stac92hd83xxx_dmux_nids[2] = { ++static hda_nid_t stac92hd83xxx_mux_nids[2] = { + 0x17, 0x18, + }; + +@@ -376,10 +371,6 @@ + 0x03, 0x0c, 0x20, 0x40, + }; + +-static hda_nid_t stac92hd83xxx_amp_nids[1] = { +- 0xc, +-}; +- + #define STAC92HD83XXX_NUM_CAPS 2 + static unsigned long stac92hd83xxx_capvols[] = { + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), +@@ -1092,26 +1083,6 @@ + }; + + +-static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { +- HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), +- HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), +- +- HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT), +- HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT), +- +- HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT), +- +- HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT), +- HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT), +- +- /* +- HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT), +- HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT), +- */ +- { } /* end */ +-}; +- + static struct snd_kcontrol_new stac925x_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), +@@ -3380,19 +3351,33 @@ + static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; +- int wcaps, nid, i, err = 0; ++ int i, j, err = 0; + + for (i = 0; i < spec->num_muxes; i++) { ++ hda_nid_t nid; ++ unsigned int wcaps; ++ unsigned long val; ++ + nid = spec->mux_nids[i]; + wcaps = get_wcaps(codec, nid); ++ if (!(wcaps & AC_WCAP_OUT_AMP)) ++ continue; + +- if (wcaps & AC_WCAP_OUT_AMP) { +- err = stac92xx_add_control_idx(spec, +- STAC_CTL_WIDGET_VOL, i, "Mux Capture Volume", +- HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); +- if (err < 0) +- return err; ++ /* check whether already the same control was created as ++ * normal Capture Volume. ++ */ ++ val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); ++ for (j = 0; j < spec->num_caps; j++) { ++ if (spec->capvols[j] == val) ++ break; + } ++ if (j < spec->num_caps) ++ continue; ++ ++ err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i, ++ "Mux Capture Volume", val); ++ if (err < 0) ++ return err; + } + return 0; + }; +@@ -3447,6 +3432,24 @@ + return -1; + } + ++/* create a volume assigned to the given pin (only if supported) */ ++static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, ++ const char *label) ++{ ++ unsigned int caps, nums; ++ char name[32]; ++ ++ if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) ++ return 0; ++ caps = query_amp_caps(codec, nid, HDA_OUTPUT); ++ nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; ++ if (!nums) ++ return 0; ++ snprintf(name, sizeof(name), "%s Capture Volume", label); ++ return stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name, ++ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); ++} ++ + /* create playback/capture controls for input pins on dmic capable codecs */ + static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +@@ -3456,7 +3459,6 @@ + struct hda_input_mux *dimux = &spec->private_dimux; + int err, i, active_mics; + unsigned int def_conf; +- char name[32]; + + dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; + dimux->items[dimux->num_items].index = 0; +@@ -3464,6 +3466,10 @@ + + active_mics = 0; + for (i = 0; i < spec->num_dmics; i++) { ++ /* check the validity: sometimes it's a dead vendor-spec node */ ++ if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i])) ++ != AC_WID_PIN) ++ continue; + def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) + active_mics++; +@@ -3472,14 +3478,15 @@ + for (i = 0; i < spec->num_dmics; i++) { + hda_nid_t nid; + int index; +- unsigned int wcaps; + const char *label; + +- def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); ++ nid = spec->dmic_nids[i]; ++ if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) ++ continue; ++ def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + +- nid = spec->dmic_nids[i]; + index = get_connection_index(codec, spec->dmux_nids[0], nid); + if (index < 0) + continue; +@@ -3489,21 +3496,9 @@ + else + label = stac92xx_dmic_labels[dimux->num_items]; + +- wcaps = get_wcaps(codec, nid) & +- (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); +- +- if (wcaps) { +- sprintf(name, "%s Capture Volume", label); +- +- err = stac92xx_add_control(spec, +- STAC_CTL_WIDGET_VOL, +- name, +- HDA_COMPOSE_AMP_VAL(nid, 3, 0, +- (wcaps & AC_WCAP_OUT_AMP) ? +- HDA_OUTPUT : HDA_INPUT)); +- if (err < 0) +- return err; +- } ++ err = create_elem_capture_vol(codec, nid, label); ++ if (err < 0) ++ return err; + + dimux->items[dimux->num_items].label = label; + dimux->items[dimux->num_items].index = index; +@@ -3604,29 +3599,29 @@ + { + struct sigmatel_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux; +- hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; +- int i, j, k; ++ int i, j; + + for (i = 0; i < AUTO_PIN_LAST; i++) { +- int index; ++ hda_nid_t nid = cfg->input_pins[i]; ++ int index, err; + +- if (!cfg->input_pins[i]) ++ if (!nid) + continue; + index = -1; + for (j = 0; j < spec->num_muxes; j++) { +- int num_cons; +- num_cons = snd_hda_get_connections(codec, +- spec->mux_nids[j], +- con_lst, +- HDA_MAX_NUM_INPUTS); +- for (k = 0; k < num_cons; k++) +- if (con_lst[k] == cfg->input_pins[i]) { +- index = k; +- goto found; +- } ++ index = get_connection_index(codec, spec->mux_nids[j], ++ nid); ++ if (index >= 0) ++ break; + } +- continue; +- found: ++ if (index < 0) ++ continue; ++ ++ err = create_elem_capture_vol(codec, nid, ++ auto_pin_cfg_labels[i]); ++ if (err < 0) ++ return err; ++ + imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; + imux->items[imux->num_items].index = index; + imux->num_items++; +@@ -4998,22 +4993,17 @@ + codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; + spec->mono_nid = 0x19; + spec->digbeep_nid = 0x21; +- spec->dmic_nids = stac92hd83xxx_dmic_nids; +- spec->dmux_nids = stac92hd83xxx_dmux_nids; ++ spec->mux_nids = stac92hd83xxx_mux_nids; ++ spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids); + spec->adc_nids = stac92hd83xxx_adc_nids; ++ spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); + spec->pwr_nids = stac92hd83xxx_pwr_nids; +- spec->amp_nids = stac92hd83xxx_amp_nids; + spec->pwr_mapping = stac92hd83xxx_pwr_mapping; + spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); + spec->multiout.dac_nids = spec->dac_nids; + + spec->init = stac92hd83xxx_core_init; +- spec->mixer = stac92hd83xxx_mixer; + spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); +- spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids); +- spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); +- spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); +- spec->num_dmics = STAC92HD83XXX_NUM_DMICS; + spec->pin_nids = stac92hd83xxx_pin_nids; + spec->num_caps = STAC92HD83XXX_NUM_CAPS; + spec->capvols = stac92hd83xxx_capvols; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-intel-cleanup b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-intel-cleanup new file mode 100644 index 000000000..3abc24e70 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-intel-cleanup @@ -0,0 +1,232 @@ +From: Takashi Iwai +Subject: ALSA: hda - clean up hda_intel.c +Patch-mainline: 2.6.30-rc1 +References: bnc#502733 + +Clean up hda_intel.c for error path. +Also clean up / optimization for stream setups. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 112 +++++++++++++++++++++++++++------------------- + 1 file changed, 67 insertions(+), 45 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -848,13 +848,18 @@ static void azx_stream_start(struct azx + SD_CTL_DMA_START | SD_INT_MASK); + } + +-/* stop a stream */ +-static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) ++/* stop DMA */ ++static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) + { +- /* stop DMA */ + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & + ~(SD_CTL_DMA_START | SD_INT_MASK)); + azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ ++} ++ ++/* stop a stream */ ++static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) ++{ ++ azx_stream_clear(chip, azx_dev); + /* disable SIE */ + azx_writeb(chip, INTCTL, + azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); +@@ -1067,8 +1072,7 @@ static int azx_setup_periods(struct azx + azx_sd_writel(azx_dev, SD_BDLPL, 0); + azx_sd_writel(azx_dev, SD_BDLPU, 0); + +- period_bytes = snd_pcm_lib_period_bytes(substream); +- azx_dev->period_bytes = period_bytes; ++ period_bytes = azx_dev->period_bytes; + periods = azx_dev->bufsize / period_bytes; + + /* program the initial BDL entries */ +@@ -1115,24 +1119,17 @@ static int azx_setup_periods(struct azx + error: + snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", + azx_dev->bufsize, period_bytes); +- /* reset */ +- azx_sd_writel(azx_dev, SD_BDLPL, 0); +- azx_sd_writel(azx_dev, SD_BDLPU, 0); + return -EINVAL; + } + +-/* +- * set up the SD for streaming +- */ +-static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) ++/* reset stream */ ++static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) + { + unsigned char val; + int timeout; + +- /* make sure the run bit is zero for SD */ +- azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & +- ~SD_CTL_DMA_START); +- /* reset stream */ ++ azx_stream_clear(chip, azx_dev); ++ + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | + SD_CTL_STREAM_RESET); + udelay(3); +@@ -1149,7 +1146,15 @@ static int azx_setup_controller(struct a + while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && + --timeout) + ; ++} + ++/* ++ * set up the SD for streaming ++ */ ++static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) ++{ ++ /* make sure the run bit is zero for SD */ ++ azx_stream_clear(chip, azx_dev); + /* program the stream_tag */ + azx_sd_writel(azx_dev, SD_CTL, + (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| +@@ -1390,6 +1395,8 @@ static int azx_pcm_open(struct snd_pcm_s + runtime->private_data = azx_dev; + snd_pcm_set_sync(substream); + mutex_unlock(&chip->open_mutex); ++ ++ azx_stream_reset(chip, azx_dev); + return 0; + } + +@@ -1416,6 +1423,11 @@ static int azx_pcm_close(struct snd_pcm_ + static int azx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) + { ++ struct azx_dev *azx_dev = get_azx_dev(substream); ++ ++ azx_dev->bufsize = 0; ++ azx_dev->period_bytes = 0; ++ azx_dev->format_val = 0; + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + } +@@ -1430,6 +1442,9 @@ static int azx_pcm_hw_free(struct snd_pc + azx_sd_writel(azx_dev, SD_BDLPL, 0); + azx_sd_writel(azx_dev, SD_BDLPU, 0); + azx_sd_writel(azx_dev, SD_CTL, 0); ++ azx_dev->bufsize = 0; ++ azx_dev->period_bytes = 0; ++ azx_dev->format_val = 0; + + hinfo->ops.cleanup(hinfo, apcm->codec, substream); + +@@ -1443,23 +1458,37 @@ static int azx_pcm_prepare(struct snd_pc + struct azx_dev *azx_dev = get_azx_dev(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct snd_pcm_runtime *runtime = substream->runtime; ++ unsigned int bufsize, period_bytes, format_val; ++ int err; + +- azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); +- azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, +- runtime->channels, +- runtime->format, +- hinfo->maxbps); +- if (!azx_dev->format_val) { ++ format_val = snd_hda_calc_stream_format(runtime->rate, ++ runtime->channels, ++ runtime->format, ++ hinfo->maxbps); ++ if (!format_val) { + snd_printk(KERN_ERR SFX + "invalid format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + return -EINVAL; + } + ++ bufsize = snd_pcm_lib_buffer_bytes(substream); ++ period_bytes = snd_pcm_lib_period_bytes(substream); ++ + snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", +- azx_dev->bufsize, azx_dev->format_val); +- if (azx_setup_periods(chip, substream, azx_dev) < 0) +- return -EINVAL; ++ bufsize, format_val); ++ ++ if (bufsize != azx_dev->bufsize || ++ period_bytes != azx_dev->period_bytes || ++ format_val != azx_dev->format_val) { ++ azx_dev->bufsize = bufsize; ++ azx_dev->period_bytes = period_bytes; ++ azx_dev->format_val = format_val; ++ err = azx_setup_periods(chip, substream, azx_dev); ++ if (err < 0) ++ return err; ++ } ++ + azx_setup_controller(chip, azx_dev); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; +@@ -2373,40 +2402,30 @@ static int __devinit azx_probe(struct pc + } + + err = azx_create(card, pci, dev, pci_id->driver_data, &chip); +- if (err < 0) { +- snd_card_free(card); +- return err; +- } ++ if (err < 0) ++ goto out_free; + card->private_data = chip; + + /* create codec instances */ + err = azx_codec_create(chip, model[dev], probe_mask[dev]); +- if (err < 0) { +- snd_card_free(card); +- return err; +- } ++ if (err < 0) ++ goto out_free; + + /* create PCM streams */ + err = azx_pcm_create(chip); +- if (err < 0) { +- snd_card_free(card); +- return err; +- } ++ if (err < 0) ++ goto out_free; + + /* create mixer controls */ + err = azx_mixer_create(chip); +- if (err < 0) { +- snd_card_free(card); +- return err; +- } ++ if (err < 0) ++ goto out_free; + + snd_card_set_dev(card, &pci->dev); + + err = snd_card_register(card); +- if (err < 0) { +- snd_card_free(card); +- return err; +- } ++ if (err < 0) ++ goto out_free; + + pci_set_drvdata(pci, card); + chip->running = 1; +@@ -2415,6 +2434,9 @@ static int __devinit azx_probe(struct pc + + dev++; + return err; ++out_free: ++ snd_card_free(card); ++ return err; + } + + static void __devexit azx_remove(struct pci_dev *pci) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-intelhdmi b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-intelhdmi new file mode 100644 index 000000000..6df467402 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-intelhdmi @@ -0,0 +1,1818 @@ +From: Takashi Iwai +Subject: ALSA: Add Intel HDMI support +Patch-mainline: 2.6.29 +References: bnc#485768 + +Add the support for Intel HDMI devices. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/Kconfig | 12 + sound/pci/hda/Makefile | 2 + sound/pci/hda/hda_codec.c | 87 +++++ + sound/pci/hda/hda_codec.h | 7 + sound/pci/hda/hda_eld.c | 592 ++++++++++++++++++++++++++++++++++ + sound/pci/hda/hda_intel.c | 18 - + sound/pci/hda/hda_local.h | 68 +++ + sound/pci/hda/hda_patch.h | 2 + sound/pci/hda/hda_proc.c | 75 ---- + sound/pci/hda/patch_atihdmi.c | 9 + sound/pci/hda/patch_intelhdmi.c | 694 ++++++++++++++++++++++++++++++++++++++++ + sound/pci/hda/patch_nvhdmi.c | 7 + 12 files changed, 1504 insertions(+), 69 deletions(-) + +--- a/sound/pci/Kconfig ++++ b/sound/pci/Kconfig +@@ -573,6 +573,18 @@ config SND_HDA_CODEC_NVHDMI + Say Y here to include NVIDIA HDMI HD-audio codec support in + snd-hda-intel driver, such as NVIDIA MCP78 HDMI. + ++config SND_HDA_CODEC_INTELHDMI ++ bool "Build INTEL HDMI HD-audio codec support" ++ depends on SND_HDA_INTEL ++ default y ++ help ++ Say Y here to include INTEL HDMI HD-audio codec support in ++ snd-hda-intel driver, such as Eaglelake integrated HDMI. ++ ++config SND_HDA_ELD ++ def_bool y ++ depends on SND_HDA_CODEC_INTELHDMI ++ + config SND_HDA_CODEC_CONEXANT + bool "Build Conexant HD-audio codec support" + depends on SND_HDA_INTEL +--- a/sound/pci/hda/Makefile ++++ b/sound/pci/hda/Makefile +@@ -16,5 +16,7 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATI + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o + snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o ++snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o ++snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o + + obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -55,6 +55,7 @@ static struct hda_vendor_id hda_vendor_i + { 0x1002, "ATI" }, + { 0x1057, "Motorola" }, + { 0x1095, "Silicon Image" }, ++ { 0x10de, "Nvidia" }, + { 0x10ec, "Realtek" }, + { 0x1106, "VIA" }, + { 0x111d, "IDT" }, +@@ -64,7 +65,9 @@ static struct hda_vendor_id hda_vendor_i + { 0x14f1, "Conexant" }, + { 0x17e8, "Chrontel" }, + { 0x1854, "LG" }, ++ { 0x1aec, "Wolfson Microelectronics" }, + { 0x434d, "C-Media" }, ++ { 0x8086, "Intel" }, + { 0x8384, "SigmaTel" }, + {} /* terminator */ + }; +@@ -97,6 +100,9 @@ static const struct hda_codec_preset *hd + #ifdef CONFIG_SND_HDA_CODEC_NVHDMI + snd_hda_preset_nvhdmi, + #endif ++#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI ++ snd_hda_preset_intelhdmi, ++#endif + NULL + }; + +@@ -124,6 +130,52 @@ make_codec_cmd(struct hda_codec *codec, + return val; + } + ++const char *snd_hda_get_jack_location(u32 cfg) ++{ ++ static char *bases[7] = { ++ "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", ++ }; ++ static unsigned char specials_idx[] = { ++ 0x07, 0x08, ++ 0x17, 0x18, 0x19, ++ 0x37, 0x38 ++ }; ++ static char *specials[] = { ++ "Rear Panel", "Drive Bar", ++ "Riser", "HDMI", "ATAPI", ++ "Mobile-In", "Mobile-Out" ++ }; ++ int i; ++ cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; ++ if ((cfg & 0x0f) < 7) ++ return bases[cfg & 0x0f]; ++ for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { ++ if (cfg == specials_idx[i]) ++ return specials[i]; ++ } ++ return "UNKNOWN"; ++} ++ ++const char *snd_hda_get_jack_connectivity(u32 cfg) ++{ ++ static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; ++ ++ return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; ++} ++ ++const char *snd_hda_get_jack_type(u32 cfg) ++{ ++ static char *jack_types[16] = { ++ "Line Out", "Speaker", "HP Out", "CD", ++ "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", ++ "Line In", "Aux", "Mic", "Telephony", ++ "SPDIF In", "Digitial In", "Reserved", "Other" ++ }; ++ ++ return jack_types[(cfg & AC_DEFCFG_DEVICE) ++ >> AC_DEFCFG_DEVICE_SHIFT]; ++} ++ + /** + * snd_hda_codec_read - send a command and get the response + * @codec: the HDA codec +@@ -1636,6 +1688,8 @@ int snd_hda_create_spdif_out_ctls(struct + } + for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { + kctl = snd_ctl_new1(dig_mix, codec); ++ if (!kctl) ++ return -ENOMEM; + kctl->id.index = idx; + kctl->private_value = nid; + err = snd_ctl_add(codec->bus->card, kctl); +@@ -1783,6 +1837,8 @@ int snd_hda_create_spdif_in_ctls(struct + } + for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { + kctl = snd_ctl_new1(dig_mix, codec); ++ if (!kctl) ++ return -ENOMEM; + kctl->private_value = nid; + err = snd_ctl_add(codec->bus->card, kctl); + if (err < 0) +@@ -3263,3 +3319,34 @@ int snd_hda_codecs_inuse(struct hda_bus + } + #endif + #endif ++ ++/* ++ * used by hda_proc.c and hda_eld.c ++ */ ++void snd_print_pcm_rates(int pcm, char *buf, int buflen) ++{ ++ static unsigned int rates[] = { ++ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, ++ 96000, 176400, 192000, 384000 ++ }; ++ int i, j; ++ ++ for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) ++ if (pcm & (1 << i)) ++ j += snprintf(buf + j, buflen - j, " %d", rates[i]); ++ ++ buf[j] = '\0'; /* necessary when j == 0 */ ++} ++ ++void snd_print_pcm_bits(int pcm, char *buf, int buflen) ++{ ++ static unsigned int bits[] = { 8, 16, 20, 24, 32 }; ++ int i, j; ++ ++ for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) ++ if (pcm & (AC_SUPPCM_BITS_8 << i)) ++ j += snprintf(buf + j, buflen - j, " %d", bits[i]); ++ ++ buf[j] = '\0'; /* necessary when j == 0 */ ++} ++ +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -832,6 +832,13 @@ int snd_hda_resume(struct hda_bus *bus); + #endif + + /* ++ * get widget information ++ */ ++const char *snd_hda_get_jack_connectivity(u32 cfg); ++const char *snd_hda_get_jack_type(u32 cfg); ++const char *snd_hda_get_jack_location(u32 cfg); ++ ++/* + * power saving + */ + #ifdef CONFIG_SND_HDA_POWER_SAVE +--- /dev/null ++++ b/sound/pci/hda/hda_eld.c +@@ -0,0 +1,592 @@ ++/* ++ * Generic routines and proc interface for ELD(EDID Like Data) information ++ * ++ * Copyright(c) 2008 Intel Corporation. ++ * ++ * Authors: ++ * Wu Fengguang ++ * ++ * This driver is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This driver is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include "hda_codec.h" ++#include "hda_local.h" ++ ++enum eld_versions { ++ ELD_VER_CEA_861D = 2, ++ ELD_VER_PARTIAL = 31, ++}; ++ ++enum cea_edid_versions { ++ CEA_EDID_VER_NONE = 0, ++ CEA_EDID_VER_CEA861 = 1, ++ CEA_EDID_VER_CEA861A = 2, ++ CEA_EDID_VER_CEA861BCD = 3, ++ CEA_EDID_VER_RESERVED = 4, ++}; ++ ++static char *cea_speaker_allocation_names[] = { ++ /* 0 */ "FL/FR", ++ /* 1 */ "LFE", ++ /* 2 */ "FC", ++ /* 3 */ "RL/RR", ++ /* 4 */ "RC", ++ /* 5 */ "FLC/FRC", ++ /* 6 */ "RLC/RRC", ++ /* 7 */ "FLW/FRW", ++ /* 8 */ "FLH/FRH", ++ /* 9 */ "TC", ++ /* 10 */ "FCH", ++}; ++ ++static char *eld_connection_type_names[4] = { ++ "HDMI", ++ "DisplayPort", ++ "2-reserved", ++ "3-reserved" ++}; ++ ++enum cea_audio_coding_types { ++ AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, ++ AUDIO_CODING_TYPE_LPCM = 1, ++ AUDIO_CODING_TYPE_AC3 = 2, ++ AUDIO_CODING_TYPE_MPEG1 = 3, ++ AUDIO_CODING_TYPE_MP3 = 4, ++ AUDIO_CODING_TYPE_MPEG2 = 5, ++ AUDIO_CODING_TYPE_AACLC = 6, ++ AUDIO_CODING_TYPE_DTS = 7, ++ AUDIO_CODING_TYPE_ATRAC = 8, ++ AUDIO_CODING_TYPE_SACD = 9, ++ AUDIO_CODING_TYPE_EAC3 = 10, ++ AUDIO_CODING_TYPE_DTS_HD = 11, ++ AUDIO_CODING_TYPE_MLP = 12, ++ AUDIO_CODING_TYPE_DST = 13, ++ AUDIO_CODING_TYPE_WMAPRO = 14, ++ AUDIO_CODING_TYPE_REF_CXT = 15, ++ /* also include valid xtypes below */ ++ AUDIO_CODING_TYPE_HE_AAC = 15, ++ AUDIO_CODING_TYPE_HE_AAC2 = 16, ++ AUDIO_CODING_TYPE_MPEG_SURROUND = 17, ++}; ++ ++enum cea_audio_coding_xtypes { ++ AUDIO_CODING_XTYPE_HE_REF_CT = 0, ++ AUDIO_CODING_XTYPE_HE_AAC = 1, ++ AUDIO_CODING_XTYPE_HE_AAC2 = 2, ++ AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, ++ AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, ++}; ++ ++static char *cea_audio_coding_type_names[] = { ++ /* 0 */ "undefined", ++ /* 1 */ "LPCM", ++ /* 2 */ "AC-3", ++ /* 3 */ "MPEG1", ++ /* 4 */ "MP3", ++ /* 5 */ "MPEG2", ++ /* 6 */ "AAC-LC", ++ /* 7 */ "DTS", ++ /* 8 */ "ATRAC", ++ /* 9 */ "DSD (One Bit Audio)", ++ /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", ++ /* 11 */ "DTS-HD", ++ /* 12 */ "MLP (Dolby TrueHD)", ++ /* 13 */ "DST", ++ /* 14 */ "WMAPro", ++ /* 15 */ "HE-AAC", ++ /* 16 */ "HE-AACv2", ++ /* 17 */ "MPEG Surround", ++}; ++ ++/* ++ * The following two lists are shared between ++ * - HDMI audio InfoFrame (source to sink) ++ * - CEA E-EDID Extension (sink to source) ++ */ ++ ++/* ++ * SS1:SS0 index => sample size ++ */ ++static int cea_sample_sizes[4] = { ++ 0, /* 0: Refer to Stream Header */ ++ AC_SUPPCM_BITS_16, /* 1: 16 bits */ ++ AC_SUPPCM_BITS_20, /* 2: 20 bits */ ++ AC_SUPPCM_BITS_24, /* 3: 24 bits */ ++}; ++ ++/* ++ * SF2:SF1:SF0 index => sampling frequency ++ */ ++static int cea_sampling_frequencies[8] = { ++ 0, /* 0: Refer to Stream Header */ ++ SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ ++ SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ ++ SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ ++ SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ ++ SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ ++ SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ ++ SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ ++}; ++ ++static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, ++ int byte_index) ++{ ++ unsigned int val; ++ ++ val = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_HDMI_ELDD, byte_index); ++ ++#ifdef BE_PARANOID ++ printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); ++#endif ++ ++ if ((val & AC_ELDD_ELD_VALID) == 0) { ++ snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", ++ byte_index); ++ val = 0; ++ } ++ ++ return val & AC_ELDD_ELD_DATA; ++} ++ ++#define GRAB_BITS(buf, byte, lowbit, bits) \ ++({ \ ++ BUILD_BUG_ON(lowbit > 7); \ ++ BUILD_BUG_ON(bits > 8); \ ++ BUILD_BUG_ON(bits <= 0); \ ++ \ ++ (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ ++}) ++ ++static void hdmi_update_short_audio_desc(struct cea_sad *a, ++ const unsigned char *buf) ++{ ++ int i; ++ int val; ++ ++ val = GRAB_BITS(buf, 1, 0, 7); ++ a->rates = 0; ++ for (i = 0; i < 7; i++) ++ if (val & (1 << i)) ++ a->rates |= cea_sampling_frequencies[i + 1]; ++ ++ a->channels = GRAB_BITS(buf, 0, 0, 3); ++ a->channels++; ++ ++ a->format = GRAB_BITS(buf, 0, 3, 4); ++ switch (a->format) { ++ case AUDIO_CODING_TYPE_REF_STREAM_HEADER: ++ snd_printd(KERN_INFO ++ "HDMI: audio coding type 0 not expected\n"); ++ break; ++ ++ case AUDIO_CODING_TYPE_LPCM: ++ val = GRAB_BITS(buf, 2, 0, 3); ++ a->sample_bits = 0; ++ for (i = 0; i < 3; i++) ++ if (val & (1 << i)) ++ a->sample_bits |= cea_sample_sizes[i + 1]; ++ break; ++ ++ case AUDIO_CODING_TYPE_AC3: ++ case AUDIO_CODING_TYPE_MPEG1: ++ case AUDIO_CODING_TYPE_MP3: ++ case AUDIO_CODING_TYPE_MPEG2: ++ case AUDIO_CODING_TYPE_AACLC: ++ case AUDIO_CODING_TYPE_DTS: ++ case AUDIO_CODING_TYPE_ATRAC: ++ a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); ++ a->max_bitrate *= 8000; ++ break; ++ ++ case AUDIO_CODING_TYPE_SACD: ++ break; ++ ++ case AUDIO_CODING_TYPE_EAC3: ++ break; ++ ++ case AUDIO_CODING_TYPE_DTS_HD: ++ break; ++ ++ case AUDIO_CODING_TYPE_MLP: ++ break; ++ ++ case AUDIO_CODING_TYPE_DST: ++ break; ++ ++ case AUDIO_CODING_TYPE_WMAPRO: ++ a->profile = GRAB_BITS(buf, 2, 0, 3); ++ break; ++ ++ case AUDIO_CODING_TYPE_REF_CXT: ++ a->format = GRAB_BITS(buf, 2, 3, 5); ++ if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || ++ a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { ++ snd_printd(KERN_INFO ++ "HDMI: audio coding xtype %d not expected\n", ++ a->format); ++ a->format = 0; ++ } else ++ a->format += AUDIO_CODING_TYPE_HE_AAC - ++ AUDIO_CODING_XTYPE_HE_AAC; ++ break; ++ } ++} ++ ++/* ++ * Be careful, ELD buf could be totally rubbish! ++ */ ++static int hdmi_update_eld(struct hdmi_eld *e, ++ const unsigned char *buf, int size) ++{ ++ int mnl; ++ int i; ++ ++ e->eld_ver = GRAB_BITS(buf, 0, 3, 5); ++ if (e->eld_ver != ELD_VER_CEA_861D && ++ e->eld_ver != ELD_VER_PARTIAL) { ++ snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", ++ e->eld_ver); ++ goto out_fail; ++ } ++ ++ e->eld_size = size; ++ e->baseline_len = GRAB_BITS(buf, 2, 0, 8); ++ mnl = GRAB_BITS(buf, 4, 0, 5); ++ e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); ++ ++ e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); ++ e->support_ai = GRAB_BITS(buf, 5, 1, 1); ++ e->conn_type = GRAB_BITS(buf, 5, 2, 2); ++ e->sad_count = GRAB_BITS(buf, 5, 4, 4); ++ ++ e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; ++ e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); ++ ++ e->port_id = get_unaligned_le64(buf + 8); ++ ++ /* not specified, but the spec's tendency is little endian */ ++ e->manufacture_id = get_unaligned_le16(buf + 16); ++ e->product_id = get_unaligned_le16(buf + 18); ++ ++ if (mnl > ELD_MAX_MNL) { ++ snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); ++ goto out_fail; ++ } else if (ELD_FIXED_BYTES + mnl > size) { ++ snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); ++ goto out_fail; ++ } else ++ strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); ++ ++ for (i = 0; i < e->sad_count; i++) { ++ if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { ++ snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); ++ goto out_fail; ++ } ++ hdmi_update_short_audio_desc(e->sad + i, ++ buf + ELD_FIXED_BYTES + mnl + 3 * i); ++ } ++ ++ return 0; ++ ++out_fail: ++ e->eld_ver = 0; ++ return -EINVAL; ++} ++ ++static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) ++{ ++ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); ++} ++ ++static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) ++{ ++ int eldv; ++ int present; ++ ++ present = hdmi_present_sense(codec, nid); ++ eldv = (present & AC_PINSENSE_ELDV); ++ present = (present & AC_PINSENSE_PRESENCE); ++ ++#ifdef CONFIG_SND_DEBUG_VERBOSE ++ printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", ++ !!present, !!eldv); ++#endif ++ ++ return eldv && present; ++} ++ ++int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) ++{ ++ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, ++ AC_DIPSIZE_ELD_BUF); ++} ++ ++int snd_hdmi_get_eld(struct hdmi_eld *eld, ++ struct hda_codec *codec, hda_nid_t nid) ++{ ++ int i; ++ int ret; ++ int size; ++ unsigned char *buf; ++ ++ if (!hdmi_eld_valid(codec, nid)) ++ return -ENOENT; ++ ++ size = snd_hdmi_get_eld_size(codec, nid); ++ if (size == 0) { ++ /* wfg: workaround for ASUS P5E-VM HDMI board */ ++ snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); ++ size = 128; ++ } ++ if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { ++ snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); ++ return -ERANGE; ++ } ++ ++ buf = kmalloc(size, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ for (i = 0; i < size; i++) ++ buf[i] = hdmi_get_eld_byte(codec, nid, i); ++ ++ ret = hdmi_update_eld(eld, buf, size); ++ ++ kfree(buf); ++ return ret; ++} ++ ++static void hdmi_show_short_audio_desc(struct cea_sad *a) ++{ ++ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; ++ char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; ++ ++ if (!a->format) ++ return; ++ ++ snd_print_pcm_rates(a->rates, buf, sizeof(buf)); ++ ++ if (a->format == AUDIO_CODING_TYPE_LPCM) ++ snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); ++ else if (a->max_bitrate) ++ snprintf(buf2, sizeof(buf2), ++ ", max bitrate = %d", a->max_bitrate); ++ else ++ buf2[0] = '\0'; ++ ++ printk(KERN_INFO "HDMI: supports coding type %s:" ++ " channels = %d, rates =%s%s\n", ++ cea_audio_coding_type_names[a->format], ++ a->channels, ++ buf, ++ buf2); ++} ++ ++void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) ++{ ++ int i, j; ++ ++ for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { ++ if (spk_alloc & (1 << i)) ++ j += snprintf(buf + j, buflen - j, " %s", ++ cea_speaker_allocation_names[i]); ++ } ++ buf[j] = '\0'; /* necessary when j == 0 */ ++} ++ ++void snd_hdmi_show_eld(struct hdmi_eld *e) ++{ ++ int i; ++ ++ printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", ++ e->monitor_name, ++ eld_connection_type_names[e->conn_type]); ++ ++ if (e->spk_alloc) { ++ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; ++ snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); ++ printk(KERN_INFO "HDMI: available speakers:%s\n", buf); ++ } ++ ++ for (i = 0; i < e->sad_count; i++) ++ hdmi_show_short_audio_desc(e->sad + i); ++} ++ ++#ifdef CONFIG_PROC_FS ++ ++static void hdmi_print_sad_info(int i, struct cea_sad *a, ++ struct snd_info_buffer *buffer) ++{ ++ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; ++ ++ snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", ++ i, a->format, cea_audio_coding_type_names[a->format]); ++ snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); ++ ++ snd_print_pcm_rates(a->rates, buf, sizeof(buf)); ++ snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); ++ ++ if (a->format == AUDIO_CODING_TYPE_LPCM) { ++ snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); ++ snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", ++ i, a->sample_bits, buf); ++ } ++ ++ if (a->max_bitrate) ++ snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", ++ i, a->max_bitrate); ++ ++ if (a->profile) ++ snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); ++} ++ ++static void hdmi_print_eld_info(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ struct hdmi_eld *e = entry->private_data; ++ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; ++ int i; ++ static char *eld_versoin_names[32] = { ++ "reserved", ++ "reserved", ++ "CEA-861D or below", ++ [3 ... 30] = "reserved", ++ [31] = "partial" ++ }; ++ static char *cea_edid_version_names[8] = { ++ "no CEA EDID Timing Extension block present", ++ "CEA-861", ++ "CEA-861-A", ++ "CEA-861-B, C or D", ++ [4 ... 7] = "reserved" ++ }; ++ ++ snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); ++ snd_iprintf(buffer, "connection_type\t\t%s\n", ++ eld_connection_type_names[e->conn_type]); ++ snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, ++ eld_versoin_names[e->eld_ver]); ++ snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, ++ cea_edid_version_names[e->cea_edid_ver]); ++ snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); ++ snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); ++ snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); ++ snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); ++ snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); ++ snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); ++ ++ snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); ++ snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); ++ ++ snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); ++ ++ for (i = 0; i < e->sad_count; i++) ++ hdmi_print_sad_info(i, e->sad + i, buffer); ++} ++ ++static void hdmi_write_eld_info(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ struct hdmi_eld *e = entry->private_data; ++ char line[64]; ++ char name[64]; ++ char *sname; ++ long long val; ++ int n; ++ ++ while (!snd_info_get_line(buffer, line, sizeof(line))) { ++ if (sscanf(line, "%s %llx", name, &val) != 2) ++ continue; ++ /* ++ * We don't allow modification to these fields: ++ * monitor_name manufacture_id product_id ++ * eld_version edid_version ++ */ ++ if (!strcmp(name, "connection_type")) ++ e->conn_type = val; ++ else if (!strcmp(name, "port_id")) ++ e->port_id = val; ++ else if (!strcmp(name, "support_hdcp")) ++ e->support_hdcp = val; ++ else if (!strcmp(name, "support_ai")) ++ e->support_ai = val; ++ else if (!strcmp(name, "audio_sync_delay")) ++ e->aud_synch_delay = val; ++ else if (!strcmp(name, "speakers")) ++ e->spk_alloc = val; ++ else if (!strcmp(name, "sad_count")) ++ e->sad_count = val; ++ else if (!strncmp(name, "sad", 3)) { ++ sname = name + 4; ++ n = name[3] - '0'; ++ if (name[4] >= '0' && name[4] <= '9') { ++ sname++; ++ n = 10 * n + name[4] - '0'; ++ } ++ if (n < 0 || n > 31) /* double the CEA limit */ ++ continue; ++ if (!strcmp(sname, "_coding_type")) ++ e->sad[n].format = val; ++ else if (!strcmp(sname, "_channels")) ++ e->sad[n].channels = val; ++ else if (!strcmp(sname, "_rates")) ++ e->sad[n].rates = val; ++ else if (!strcmp(sname, "_bits")) ++ e->sad[n].sample_bits = val; ++ else if (!strcmp(sname, "_max_bitrate")) ++ e->sad[n].max_bitrate = val; ++ else if (!strcmp(sname, "_profile")) ++ e->sad[n].profile = val; ++ if (n >= e->sad_count) ++ e->sad_count = n + 1; ++ } ++ } ++} ++ ++ ++int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) ++{ ++ char name[32]; ++ struct snd_info_entry *entry; ++ int err; ++ ++ snprintf(name, sizeof(name), "eld#%d", codec->addr); ++ err = snd_card_proc_new(codec->bus->card, name, &entry); ++ if (err < 0) ++ return err; ++ ++ snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); ++ entry->c.text.write = hdmi_write_eld_info; ++ entry->mode |= S_IWUSR; ++ eld->proc_entry = entry; ++ ++ return 0; ++} ++ ++void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) ++{ ++#if 0 /* we don't support hwdep reconfig yet */ ++ if (!codec->bus->shutdown && eld->proc_entry) { ++ snd_device_free(codec->bus->card, eld->proc_entry); ++ eld->proc_entry = NULL; ++ } ++#endif ++} ++ ++#endif /* CONFIG_PROC_FS */ +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -292,6 +292,8 @@ enum { + /* Define VIA HD Audio Device ID*/ + #define VIA_HDAC_DEVICE_ID 0x3288 + ++/* HD Audio class code */ ++#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 + + /* + */ +@@ -418,6 +420,7 @@ enum { + AZX_DRIVER_ULI, + AZX_DRIVER_NVIDIA, + AZX_DRIVER_TERA, ++ AZX_DRIVER_GENERIC, + AZX_NUM_DRIVERS, /* keep this as last entry */ + }; + +@@ -431,6 +434,7 @@ static char *driver_short_names[] __devi + [AZX_DRIVER_ULI] = "HDA ULI M5461", + [AZX_DRIVER_NVIDIA] = "HDA NVidia", + [AZX_DRIVER_TERA] = "HDA Teradici", ++ [AZX_DRIVER_GENERIC] = "HD-Audio Generic", + }; + + /* +@@ -2321,6 +2325,7 @@ static int __devinit azx_create(struct s + chip->playback_streams = ATIHDMI_NUM_PLAYBACK; + chip->capture_streams = ATIHDMI_NUM_CAPTURE; + break; ++ case AZX_DRIVER_GENERIC: + default: + chip->playback_streams = ICH6_NUM_PLAYBACK; + chip->capture_streams = ICH6_NUM_CAPTURE; +@@ -2530,12 +2535,17 @@ static struct pci_device_id azx_ids[] = + { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, +- { PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA }, +- { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, +- { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, +- { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, ++ { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, ++ { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, ++ { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, ++ { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, + /* Teradici */ + { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, ++ /* AMD Generic, PCI class code and Vendor ID for HD Audio */ ++ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), ++ .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, ++ .class_mask = 0xffffff, ++ .driver_data = AZX_DRIVER_GENERIC }, + { 0, } + }; + MODULE_DEVICE_TABLE(pci, azx_ids); +--- a/sound/pci/hda/hda_local.h ++++ b/sound/pci/hda/hda_local.h +@@ -284,6 +284,12 @@ int snd_hda_codec_proc_new(struct hda_co + static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } + #endif + ++#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 ++void snd_print_pcm_rates(int pcm, char *buf, int buflen); ++ ++#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 ++void snd_print_pcm_bits(int pcm, char *buf, int buflen); ++ + /* + * Misc + */ +@@ -436,4 +442,66 @@ int snd_hda_check_amp_list_power(struct + #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) + #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) + ++/* ++ * CEA Short Audio Descriptor data ++ */ ++struct cea_sad { ++ int channels; ++ int format; /* (format == 0) indicates invalid SAD */ ++ int rates; ++ int sample_bits; /* for LPCM */ ++ int max_bitrate; /* for AC3...ATRAC */ ++ int profile; /* for WMAPRO */ ++}; ++ ++#define ELD_FIXED_BYTES 20 ++#define ELD_MAX_MNL 16 ++#define ELD_MAX_SAD 16 ++ ++/* ++ * ELD: EDID Like Data ++ */ ++struct hdmi_eld { ++ int eld_size; ++ int baseline_len; ++ int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ ++ int cea_edid_ver; ++ char monitor_name[ELD_MAX_MNL + 1]; ++ int manufacture_id; ++ int product_id; ++ u64 port_id; ++ int support_hdcp; ++ int support_ai; ++ int conn_type; ++ int aud_synch_delay; ++ int spk_alloc; ++ int sad_count; ++ struct cea_sad sad[ELD_MAX_SAD]; ++#ifdef CONFIG_PROC_FS ++ struct snd_info_entry *proc_entry; ++#endif ++}; ++ ++int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); ++int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); ++void snd_hdmi_show_eld(struct hdmi_eld *eld); ++ ++#ifdef CONFIG_PROC_FS ++int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); ++void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); ++#else ++static inline int snd_hda_eld_proc_new(struct hda_codec *codec, ++ struct hdmi_eld *eld) ++{ ++ return 0; ++} ++static inline void snd_hda_eld_proc_free(struct hda_codec *codec, ++ struct hdmi_eld *eld) ++{ ++} ++#endif ++ ++#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 ++void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); ++ + #endif /* __SOUND_HDA_LOCAL_H */ +--- a/sound/pci/hda/hda_patch.h ++++ b/sound/pci/hda/hda_patch.h +@@ -20,3 +20,5 @@ extern struct hda_codec_preset snd_hda_p + extern struct hda_codec_preset snd_hda_preset_via[]; + /* NVIDIA HDMI codecs */ + extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; ++/* Intel HDMI codecs */ ++extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; +--- a/sound/pci/hda/hda_proc.c ++++ b/sound/pci/hda/hda_proc.c +@@ -91,31 +91,21 @@ static void print_amp_vals(struct snd_in + + static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) + { +- static unsigned int rates[] = { +- 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, +- 96000, 176400, 192000, 384000 +- }; +- int i; ++ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + + pcm &= AC_SUPPCM_RATES; + snd_iprintf(buffer, " rates [0x%x]:", pcm); +- for (i = 0; i < ARRAY_SIZE(rates); i++) +- if (pcm & (1 << i)) +- snd_iprintf(buffer, " %d", rates[i]); +- snd_iprintf(buffer, "\n"); ++ snd_print_pcm_rates(pcm, buf, sizeof(buf)); ++ snd_iprintf(buffer, "%s\n", buf); + } + + static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) + { +- static unsigned int bits[] = { 8, 16, 20, 24, 32 }; +- int i; ++ char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; + +- pcm = (pcm >> 16) & 0xff; +- snd_iprintf(buffer, " bits [0x%x]:", pcm); +- for (i = 0; i < ARRAY_SIZE(bits); i++) +- if (pcm & (1 << i)) +- snd_iprintf(buffer, " %d", bits[i]); +- snd_iprintf(buffer, "\n"); ++ snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff); ++ snd_print_pcm_bits(pcm, buf, sizeof(buf)); ++ snd_iprintf(buffer, "%s\n", buf); + } + + static void print_pcm_formats(struct snd_info_buffer *buffer, +@@ -145,32 +135,6 @@ static void print_pcm_caps(struct snd_in + print_pcm_formats(buffer, stream); + } + +-static const char *get_jack_location(u32 cfg) +-{ +- static char *bases[7] = { +- "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", +- }; +- static unsigned char specials_idx[] = { +- 0x07, 0x08, +- 0x17, 0x18, 0x19, +- 0x37, 0x38 +- }; +- static char *specials[] = { +- "Rear Panel", "Drive Bar", +- "Riser", "HDMI", "ATAPI", +- "Mobile-In", "Mobile-Out" +- }; +- int i; +- cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; +- if ((cfg & 0x0f) < 7) +- return bases[cfg & 0x0f]; +- for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { +- if (cfg == specials_idx[i]) +- return specials[i]; +- } +- return "UNKNOWN"; +-} +- + static const char *get_jack_connection(u32 cfg) + { + static char *names[16] = { +@@ -206,13 +170,6 @@ static void print_pin_caps(struct snd_in + int *supports_vref) + { + static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; +- static char *jack_types[16] = { +- "Line Out", "Speaker", "HP Out", "CD", +- "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", +- "Line In", "Aux", "Mic", "Telephony", +- "SPDIF In", "Digitial In", "Reserved", "Other" +- }; +- static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; + unsigned int caps, val; + + caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); +@@ -236,8 +193,6 @@ static void print_pin_caps(struct snd_in + else + snd_iprintf(buffer, " HDMI"); + } +- if (caps & AC_PINCAP_LR_SWAP) +- snd_iprintf(buffer, " R/L"); + if (caps & AC_PINCAP_TRIG_REQ) + snd_iprintf(buffer, " Trigger"); + if (caps & AC_PINCAP_IMP_SENSE) +@@ -276,9 +231,9 @@ static void print_pin_caps(struct snd_in + caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, + jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], +- jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], +- jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], +- get_jack_location(caps)); ++ snd_hda_get_jack_type(caps), ++ snd_hda_get_jack_connectivity(caps), ++ snd_hda_get_jack_location(caps)); + snd_iprintf(buffer, " Conn = %s, Color = %s\n", + get_jack_connection(caps), + get_jack_color(caps)); +@@ -444,7 +399,10 @@ static void print_conn_list(struct snd_i + { + int c, curr = -1; + +- if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) ++ if (conn_len > 1 && ++ wid_type != AC_WID_AUD_MIX && ++ wid_type != AC_WID_VOL_KNB && ++ wid_type != AC_WID_POWER) + curr = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + snd_iprintf(buffer, " Connection: %d\n", conn_len); +@@ -502,12 +460,13 @@ static void print_gpio(struct snd_info_b + for (i = 0; i < max; ++i) + snd_iprintf(buffer, + " IO[%d]: enable=%d, dir=%d, wake=%d, " +- "sticky=%d, data=%d\n", i, ++ "sticky=%d, data=%d, unsol=%d\n", i, + (enable & (1< ++ * Wu Fengguang ++ * ++ * Maintained by: ++ * Wu Fengguang ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "hda_codec.h" ++#include "hda_local.h" ++#include "hda_patch.h" ++ ++#define CVT_NID 0x02 /* audio converter */ ++#define PIN_NID 0x03 /* HDMI output pin */ ++ ++#define INTEL_HDMI_EVENT_TAG 0x08 ++ ++struct intel_hdmi_spec { ++ struct hda_multi_out multiout; ++ struct hda_pcm pcm_rec; ++ struct hdmi_eld sink_eld; ++}; ++ ++static struct hda_verb pinout_enable_verb[] = { ++ {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {} /* terminator */ ++}; ++ ++static struct hda_verb unsolicited_response_verb[] = { ++ {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ++ INTEL_HDMI_EVENT_TAG}, ++ {} ++}; ++ ++static struct hda_verb def_chan_map[] = { ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, ++ {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, ++ {} ++}; ++ ++ ++struct hdmi_audio_infoframe { ++ u8 type; /* 0x84 */ ++ u8 ver; /* 0x01 */ ++ u8 len; /* 0x0a */ ++ ++ u8 checksum; /* PB0 */ ++ u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ ++ u8 SS01_SF24; ++ u8 CXT04; ++ u8 CA; ++ u8 LFEPBL01_LSV36_DM_INH7; ++ u8 reserved[5]; /* PB6 - PB10 */ ++}; ++ ++/* ++ * CEA speaker placement: ++ * ++ * FLH FCH FRH ++ * FLW FL FLC FC FRC FR FRW ++ * ++ * LFE ++ * TC ++ * ++ * RL RLC RC RRC RR ++ * ++ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to ++ * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. ++ */ ++enum cea_speaker_placement { ++ FL = (1 << 0), /* Front Left */ ++ FC = (1 << 1), /* Front Center */ ++ FR = (1 << 2), /* Front Right */ ++ FLC = (1 << 3), /* Front Left Center */ ++ FRC = (1 << 4), /* Front Right Center */ ++ RL = (1 << 5), /* Rear Left */ ++ RC = (1 << 6), /* Rear Center */ ++ RR = (1 << 7), /* Rear Right */ ++ RLC = (1 << 8), /* Rear Left Center */ ++ RRC = (1 << 9), /* Rear Right Center */ ++ LFE = (1 << 10), /* Low Frequency Effect */ ++ FLW = (1 << 11), /* Front Left Wide */ ++ FRW = (1 << 12), /* Front Right Wide */ ++ FLH = (1 << 13), /* Front Left High */ ++ FCH = (1 << 14), /* Front Center High */ ++ FRH = (1 << 15), /* Front Right High */ ++ TC = (1 << 16), /* Top Center */ ++}; ++ ++/* ++ * ELD SA bits in the CEA Speaker Allocation data block ++ */ ++static int eld_speaker_allocation_bits[] = { ++ [0] = FL | FR, ++ [1] = LFE, ++ [2] = FC, ++ [3] = RL | RR, ++ [4] = RC, ++ [5] = FLC | FRC, ++ [6] = RLC | RRC, ++ /* the following are not defined in ELD yet */ ++ [7] = FLW | FRW, ++ [8] = FLH | FRH, ++ [9] = TC, ++ [10] = FCH, ++}; ++ ++struct cea_channel_speaker_allocation { ++ int ca_index; ++ int speakers[8]; ++ ++ /* derived values, just for convenience */ ++ int channels; ++ int spk_mask; ++}; ++ ++/* ++ * This is an ordered list! ++ * ++ * The preceding ones have better chances to be selected by ++ * hdmi_setup_channel_allocation(). ++ */ ++static struct cea_channel_speaker_allocation channel_allocations[] = { ++/* channel: 8 7 6 5 4 3 2 1 */ ++{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, ++ /* 2.1 */ ++{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, ++ /* Dolby Surround */ ++{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, ++{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, ++{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, ++{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, ++{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, ++{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, ++{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, ++{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, ++{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, ++ /* 5.1 */ ++{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, ++{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, ++{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, ++ /* 6.1 */ ++{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, ++{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, ++{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, ++ /* 7.1 */ ++{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, ++{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, ++{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, ++{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, ++{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, ++{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, ++{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, ++{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, ++{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, ++{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, ++{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, ++{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, ++{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, ++{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, ++{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, ++{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, ++{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, ++}; ++ ++/* ++ * HDMI routines ++ */ ++ ++#ifdef BE_PARANOID ++static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, ++ int *packet_index, int *byte_index) ++{ ++ int val; ++ ++ val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); ++ ++ *packet_index = val >> 5; ++ *byte_index = val & 0x1f; ++} ++#endif ++ ++static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, ++ int packet_index, int byte_index) ++{ ++ int val; ++ ++ val = (packet_index << 5) | (byte_index & 0x1f); ++ ++ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); ++} ++ ++static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, ++ unsigned char val) ++{ ++ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); ++} ++ ++static void hdmi_enable_output(struct hda_codec *codec) ++{ ++ /* Unmute */ ++ if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) ++ snd_hda_codec_write(codec, PIN_NID, 0, ++ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); ++ /* Enable pin out */ ++ snd_hda_sequence_write(codec, pinout_enable_verb); ++} ++ ++/* ++ * Enable Audio InfoFrame Transmission ++ */ ++static void hdmi_start_infoframe_trans(struct hda_codec *codec) ++{ ++ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); ++ snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, ++ AC_DIPXMIT_BEST); ++} ++ ++/* ++ * Disable Audio InfoFrame Transmission ++ */ ++static void hdmi_stop_infoframe_trans(struct hda_codec *codec) ++{ ++ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); ++ snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, ++ AC_DIPXMIT_DISABLE); ++} ++ ++static int hdmi_get_channel_count(struct hda_codec *codec) ++{ ++ return 1 + snd_hda_codec_read(codec, CVT_NID, 0, ++ AC_VERB_GET_CVT_CHAN_COUNT, 0); ++} ++ ++static void hdmi_set_channel_count(struct hda_codec *codec, int chs) ++{ ++ snd_hda_codec_write(codec, CVT_NID, 0, ++ AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); ++ ++ if (chs != hdmi_get_channel_count(codec)) ++ snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", ++ chs, hdmi_get_channel_count(codec)); ++} ++ ++static void hdmi_debug_channel_mapping(struct hda_codec *codec) ++{ ++#ifdef CONFIG_SND_DEBUG_VERBOSE ++ int i; ++ int slot; ++ ++ for (i = 0; i < 8; i++) { ++ slot = snd_hda_codec_read(codec, CVT_NID, 0, ++ AC_VERB_GET_HDMI_CHAN_SLOT, i); ++ printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", ++ slot >> 4, slot & 0x7); ++ } ++#endif ++} ++ ++static void hdmi_parse_eld(struct hda_codec *codec) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ struct hdmi_eld *eld = &spec->sink_eld; ++ ++ if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) ++ snd_hdmi_show_eld(eld); ++} ++ ++ ++/* ++ * Audio InfoFrame routines ++ */ ++ ++static void hdmi_debug_dip_size(struct hda_codec *codec) ++{ ++#ifdef CONFIG_SND_DEBUG_VERBOSE ++ int i; ++ int size; ++ ++ size = snd_hdmi_get_eld_size(codec, PIN_NID); ++ printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); ++ ++ for (i = 0; i < 8; i++) { ++ size = snd_hda_codec_read(codec, PIN_NID, 0, ++ AC_VERB_GET_HDMI_DIP_SIZE, i); ++ printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); ++ } ++#endif ++} ++ ++static void hdmi_clear_dip_buffers(struct hda_codec *codec) ++{ ++#ifdef BE_PARANOID ++ int i, j; ++ int size; ++ int pi, bi; ++ for (i = 0; i < 8; i++) { ++ size = snd_hda_codec_read(codec, PIN_NID, 0, ++ AC_VERB_GET_HDMI_DIP_SIZE, i); ++ if (size == 0) ++ continue; ++ ++ hdmi_set_dip_index(codec, PIN_NID, i, 0x0); ++ for (j = 1; j < 1000; j++) { ++ hdmi_write_dip_byte(codec, PIN_NID, 0x0); ++ hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); ++ if (pi != i) ++ snd_printd(KERN_INFO "dip index %d: %d != %d\n", ++ bi, pi, i); ++ if (bi == 0) /* byte index wrapped around */ ++ break; ++ } ++ snd_printd(KERN_INFO ++ "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", ++ i, size, j); ++ } ++#endif ++} ++ ++static void hdmi_fill_audio_infoframe(struct hda_codec *codec, ++ struct hdmi_audio_infoframe *ai) ++{ ++ u8 *params = (u8 *)ai; ++ u8 sum = 0; ++ int i; ++ ++ hdmi_debug_dip_size(codec); ++ hdmi_clear_dip_buffers(codec); /* be paranoid */ ++ ++ for (i = 0; i < sizeof(ai); i++) ++ sum += params[i]; ++ ai->checksum = - sum; ++ ++ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); ++ for (i = 0; i < sizeof(ai); i++) ++ hdmi_write_dip_byte(codec, PIN_NID, params[i]); ++} ++ ++/* ++ * Compute derived values in channel_allocations[]. ++ */ ++static void init_channel_allocations(void) ++{ ++ int i, j; ++ struct cea_channel_speaker_allocation *p; ++ ++ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { ++ p = channel_allocations + i; ++ p->channels = 0; ++ p->spk_mask = 0; ++ for (j = 0; j < ARRAY_SIZE(p->speakers); j++) ++ if (p->speakers[j]) { ++ p->channels++; ++ p->spk_mask |= p->speakers[j]; ++ } ++ } ++} ++ ++/* ++ * The transformation takes two steps: ++ * ++ * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask ++ * spk_mask => (channel_allocations[]) => ai->CA ++ * ++ * TODO: it could select the wrong CA from multiple candidates. ++*/ ++static int hdmi_setup_channel_allocation(struct hda_codec *codec, ++ struct hdmi_audio_infoframe *ai) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ struct hdmi_eld *eld = &spec->sink_eld; ++ int i; ++ int spk_mask = 0; ++ int channels = 1 + (ai->CC02_CT47 & 0x7); ++ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; ++ ++ /* ++ * CA defaults to 0 for basic stereo audio ++ */ ++ if (channels <= 2) ++ return 0; ++ ++ /* ++ * HDMI sink's ELD info cannot always be retrieved for now, e.g. ++ * in console or for audio devices. Assume the highest speakers ++ * configuration, to _not_ prohibit multi-channel audio playback. ++ */ ++ if (!eld->spk_alloc) ++ eld->spk_alloc = 0xffff; ++ ++ /* ++ * expand ELD's speaker allocation mask ++ * ++ * ELD tells the speaker mask in a compact(paired) form, ++ * expand ELD's notions to match the ones used by Audio InfoFrame. ++ */ ++ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { ++ if (eld->spk_alloc & (1 << i)) ++ spk_mask |= eld_speaker_allocation_bits[i]; ++ } ++ ++ /* search for the first working match in the CA table */ ++ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { ++ if (channels == channel_allocations[i].channels && ++ (spk_mask & channel_allocations[i].spk_mask) == ++ channel_allocations[i].spk_mask) { ++ ai->CA = channel_allocations[i].ca_index; ++ break; ++ } ++ } ++ ++ snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); ++ snd_printdd(KERN_INFO ++ "HDMI: select CA 0x%x for %d-channel allocation: %s\n", ++ ai->CA, channels, buf); ++ ++ return ai->CA; ++} ++ ++static void hdmi_setup_channel_mapping(struct hda_codec *codec, ++ struct hdmi_audio_infoframe *ai) ++{ ++ if (!ai->CA) ++ return; ++ ++ /* ++ * TODO: adjust channel mapping if necessary ++ * ALSA sequence is front/surr/clfe/side? ++ */ ++ ++ snd_hda_sequence_write(codec, def_chan_map); ++ hdmi_debug_channel_mapping(codec); ++} ++ ++ ++static void hdmi_setup_audio_infoframe(struct hda_codec *codec, ++ struct snd_pcm_substream *substream) ++{ ++ struct hdmi_audio_infoframe ai = { ++ .type = 0x84, ++ .ver = 0x01, ++ .len = 0x0a, ++ .CC02_CT47 = substream->runtime->channels - 1, ++ }; ++ ++ hdmi_setup_channel_allocation(codec, &ai); ++ hdmi_setup_channel_mapping(codec, &ai); ++ ++ hdmi_fill_audio_infoframe(codec, &ai); ++ hdmi_start_infoframe_trans(codec); ++} ++ ++ ++/* ++ * Unsolicited events ++ */ ++ ++static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) ++{ ++ int pind = !!(res & AC_UNSOL_RES_PD); ++ int eldv = !!(res & AC_UNSOL_RES_ELDV); ++ ++ printk(KERN_INFO ++ "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", ++ pind, eldv); ++ ++ if (pind && eldv) { ++ hdmi_parse_eld(codec); ++ /* TODO: do real things about ELD */ ++ } ++} ++ ++static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) ++{ ++ int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; ++ int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); ++ int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); ++ ++ printk(KERN_INFO ++ "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", ++ subtag, ++ cp_state, ++ cp_ready); ++ ++ /* TODO */ ++ if (cp_state) ++ ; ++ if (cp_ready) ++ ; ++} ++ ++ ++static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) ++{ ++ int tag = res >> AC_UNSOL_RES_TAG_SHIFT; ++ int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; ++ ++ if (tag != INTEL_HDMI_EVENT_TAG) { ++ snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); ++ return; ++ } ++ ++ if (subtag == 0) ++ hdmi_intrinsic_event(codec, res); ++ else ++ hdmi_non_intrinsic_event(codec, res); ++} ++ ++/* ++ * Callbacks ++ */ ++ ++static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ struct snd_pcm_substream *substream) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ ++ return snd_hda_multi_out_dig_open(codec, &spec->multiout); ++} ++ ++static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ struct snd_pcm_substream *substream) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ ++ hdmi_stop_infoframe_trans(codec); ++ ++ return snd_hda_multi_out_dig_close(codec, &spec->multiout); ++} ++ ++static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ++ struct hda_codec *codec, ++ unsigned int stream_tag, ++ unsigned int format, ++ struct snd_pcm_substream *substream) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ ++ snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, ++ format, substream); ++ ++ hdmi_set_channel_count(codec, substream->runtime->channels); ++ ++ hdmi_setup_audio_infoframe(codec, substream); ++ ++ return 0; ++} ++ ++static struct hda_pcm_stream intel_hdmi_pcm_playback = { ++ .substreams = 1, ++ .channels_min = 2, ++ .channels_max = 8, ++ .nid = CVT_NID, /* NID to query formats and rates and setup streams */ ++ .ops = { ++ .open = intel_hdmi_playback_pcm_open, ++ .close = intel_hdmi_playback_pcm_close, ++ .prepare = intel_hdmi_playback_pcm_prepare ++ }, ++}; ++ ++static int intel_hdmi_build_pcms(struct hda_codec *codec) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ struct hda_pcm *info = &spec->pcm_rec; ++ ++ codec->num_pcms = 1; ++ codec->pcm_info = info; ++ ++ info->name = "INTEL HDMI"; ++ info->pcm_type = HDA_PCM_TYPE_HDMI; ++ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; ++ ++ return 0; ++} ++ ++static int intel_hdmi_build_controls(struct hda_codec *codec) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ int err; ++ ++ err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int intel_hdmi_init(struct hda_codec *codec) ++{ ++ hdmi_enable_output(codec); ++ ++ snd_hda_sequence_write(codec, unsolicited_response_verb); ++ ++ return 0; ++} ++ ++static void intel_hdmi_free(struct hda_codec *codec) ++{ ++ struct intel_hdmi_spec *spec = codec->spec; ++ ++ snd_hda_eld_proc_free(codec, &spec->sink_eld); ++ kfree(spec); ++} ++ ++static struct hda_codec_ops intel_hdmi_patch_ops = { ++ .init = intel_hdmi_init, ++ .free = intel_hdmi_free, ++ .build_pcms = intel_hdmi_build_pcms, ++ .build_controls = intel_hdmi_build_controls, ++ .unsol_event = intel_hdmi_unsol_event, ++}; ++ ++static int patch_intel_hdmi(struct hda_codec *codec) ++{ ++ struct intel_hdmi_spec *spec; ++ ++ spec = kzalloc(sizeof(*spec), GFP_KERNEL); ++ if (spec == NULL) ++ return -ENOMEM; ++ ++ spec->multiout.num_dacs = 0; /* no analog */ ++ spec->multiout.max_channels = 8; ++ spec->multiout.dig_out_nid = CVT_NID; ++ ++ codec->spec = spec; ++ codec->patch_ops = intel_hdmi_patch_ops; ++ ++ snd_hda_eld_proc_new(codec, &spec->sink_eld); ++ ++ init_channel_allocations(); ++ ++ return 0; ++} ++ ++/* ++ * patch entries ++ */ ++struct hda_codec_preset snd_hda_preset_intelhdmi[] = { ++ { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, ++ { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, ++ { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, ++ { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, ++ { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, ++ { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, ++ {} /* terminator */ ++}; +--- a/sound/pci/hda/patch_nvhdmi.c ++++ b/sound/pci/hda/patch_nvhdmi.c +@@ -159,7 +159,10 @@ static int patch_nvhdmi(struct hda_codec + * patch entries + */ + struct hda_codec_preset snd_hda_preset_nvhdmi[] = { +- { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, +- { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, ++ { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, ++ { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, ++ { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, ++ { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, ++ { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, + {} /* terminator */ + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-internal-binary-compat b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-internal-binary-compat new file mode 100644 index 000000000..ba8a49f8a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-internal-binary-compat @@ -0,0 +1,240 @@ +From: Takashi Iwai +Subject: ALSA: hda - keep internal structure binary compatibility +Patch-mainline: NEVER EVER PUSH THIS EVIL!! +References: bnc#497341 + +Add evil hacks to keep the *INTERNAL* binary compatibility, which +agrmodem driver pokes around. We fake the old bus_ops. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 28 ++++++++++++++++++++++++++++ + sound/pci/hda/hda_codec.h | 22 +++++++++++++++++++--- + sound/pci/hda/hda_intel.c | 39 ++++++++++++++++++++++++++++----------- + 3 files changed, 75 insertions(+), 14 deletions(-) + +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -549,6 +549,17 @@ + #endif + }; + ++/* old hda_bus_ops struct -- just for really evil binary compatibility issues */ ++struct hda_old_bus_ops { ++ int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, ++ unsigned int verb, unsigned int parm); ++ unsigned int (*get_response)(struct hda_codec *codec); ++ void (*private_free)(struct hda_bus *); ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++ void (*pm_notify)(struct hda_codec *codec); ++#endif ++}; ++ + /* template to pass to the bus constructor */ + struct hda_bus_template { + void *private_data; +@@ -570,7 +581,7 @@ + void *private_data; + struct pci_dev *pci; + const char *modelname; +- struct hda_bus_ops ops; ++ struct hda_old_bus_ops old_ops; /* old ops; for binary compatibility */ + + /* codec linked list */ + struct list_head codec_list; +@@ -581,8 +592,6 @@ + + /* unsolicited event queue */ + struct hda_bus_unsolicited *unsol; +- char workq_name[16]; +- struct workqueue_struct *workq; /* common workqueue for codecs */ + + struct snd_info_entry *proc; + +@@ -594,6 +603,13 @@ + unsigned int rirb_error:1; /* error in codec communication */ + unsigned int response_reset:1; /* controller was reset */ + unsigned int in_reset:1; /* during reset operation */ ++ ++ /* real ops */ ++ struct hda_bus_ops ops; ++ ++ /* additional workq stuff */ ++ char workq_name[16]; ++ struct workqueue_struct *workq; /* common workqueue for codecs */ + }; + + /* +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -306,9 +306,6 @@ + unsigned int period_bytes; /* size of the period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ +- unsigned int start_flag: 1; /* stream full start flag */ +- unsigned long start_jiffies; /* start + minimum jiffies */ +- unsigned long min_jiffies; /* minimum jiffies before position is valid */ + + void __iomem *sd_addr; /* stream descriptor pointer */ + +@@ -327,6 +324,7 @@ + unsigned int opened :1; + unsigned int running :1; + unsigned int irq_pending :1; ++ unsigned int irq_ignore :1; /* not used; just placeholder for compat */ + /* + * For VIA: + * A flag to ensure DMA position is 0 +@@ -335,6 +333,14 @@ + unsigned int insufficient :1; + }; + ++/* new stuff; moved here to keep bloody binary compatibility */ ++struct azx_dev_ext { ++ unsigned int start_flag: 1; /* stream full start flag */ ++ unsigned long start_jiffies; /* start + minimum jiffies */ ++ unsigned long min_jiffies; /* minimum jiffies before position is valid */ ++ ++}; ++ + /* CORB/RIRB */ + struct azx_rb { + u32 *buf; /* CORB/RIRB buffer +@@ -377,7 +383,6 @@ + + /* HD codec */ + unsigned short codec_mask; +- int codec_probe_mask; /* copied from probe_mask option */ + struct hda_bus *bus; + + /* CORB/RIRB */ +@@ -407,6 +412,10 @@ + + /* reboot notifier (for mysterious hangup problem at power-down) */ + struct notifier_block reboot_notifier; ++ ++ /* moved here for binary compatibility */ ++ struct azx_dev_ext *azx_dev_ext; ++ int codec_probe_mask; /* copied from probe_mask option */ + }; + + /* driver types */ +@@ -1497,6 +1506,7 @@ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); ++ struct azx_dev_ext *azx_dev_ext; + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int bufsize, period_bytes, format_val; +@@ -1531,7 +1541,8 @@ + return err; + } + +- azx_dev->min_jiffies = (runtime->period_size * HZ) / ++ azx_dev_ext = &chip->azx_dev_ext[azx_dev->index]; ++ azx_dev_ext->min_jiffies = (runtime->period_size * HZ) / + (runtime->rate * 2); + azx_setup_controller(chip, azx_dev); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +@@ -1548,6 +1559,7 @@ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev; ++ struct azx_dev_ext *azx_dev_ext; + struct snd_pcm_substream *s; + int rstart = 0, start, nsync = 0, sbits = 0; + int nwait, timeout; +@@ -1586,9 +1598,10 @@ + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); ++ azx_dev_ext = &chip->azx_dev_ext[azx_dev->index]; + if (rstart) { +- azx_dev->start_flag = 1; +- azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies; ++ azx_dev_ext->start_flag = 1; ++ azx_dev_ext->start_jiffies = jiffies + azx_dev_ext->min_jiffies; + } + if (start) + azx_stream_start(chip, azx_dev); +@@ -1738,11 +1751,12 @@ + static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) + { + unsigned int pos; ++ struct azx_dev_ext *azx_dev_ext = &chip->azx_dev_ext[azx_dev->index]; + +- if (azx_dev->start_flag && +- time_before_eq(jiffies, azx_dev->start_jiffies)) ++ if (azx_dev_ext->start_flag && ++ time_before_eq(jiffies, azx_dev_ext->start_jiffies)) + return -1; /* bogus (too early) interrupt */ +- azx_dev->start_flag = 0; ++ azx_dev_ext->start_flag = 0; + + pos = azx_get_position(chip, azx_dev); + if (chip->position_fix == POS_FIX_AUTO) { +@@ -2144,6 +2158,7 @@ + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + kfree(chip->azx_dev); ++ kfree(chip->azx_dev_ext); + kfree(chip); + + return 0; +@@ -2376,7 +2391,9 @@ + chip->num_streams = chip->playback_streams + chip->capture_streams; + chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), + GFP_KERNEL); +- if (!chip->azx_dev) { ++ chip->azx_dev_ext = kcalloc(chip->num_streams, ++ sizeof(*chip->azx_dev_ext), GFP_KERNEL); ++ if (!chip->azx_dev || !chip->azx_dev_ext) { + snd_printk(KERN_ERR "cannot malloc azx_dev\n"); + goto errout; + } +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -485,6 +485,28 @@ + return snd_hda_bus_free(bus); + } + ++/* ++ * backward-compatible ops ++ */ ++static int old_bus_ops_command(struct hda_codec *codec, hda_nid_t nid, ++ int direct, unsigned int verb, unsigned int parm) ++{ ++ unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); ++ return codec->bus->ops.command(codec->bus, cmd); ++} ++ ++static unsigned int old_bus_ops_get_response(struct hda_codec *codec) ++{ ++ return codec->bus->ops.get_response(codec->bus); ++} ++ ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++static void old_bus_ops_pm_notify(struct hda_codec *codec) ++{ ++ codec->bus->ops.pm_notify(codec->bus); ++} ++#endif ++ + /** + * snd_hda_bus_new - create a HDA bus + * @card: the card entry +@@ -520,6 +542,12 @@ + bus->pci = temp->pci; + bus->modelname = temp->modelname; + bus->ops = temp->ops; ++ bus->old_ops.command = old_bus_ops_command; ++ bus->old_ops.get_response = old_bus_ops_get_response; ++ bus->old_ops.private_free = bus->ops.private_free; ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++ bus->old_ops.pm_notify = old_bus_ops_pm_notify; ++#endif + + mutex_init(&bus->cmd_mutex); + INIT_LIST_HEAD(&bus->codec_list); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-own-workq b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-own-workq new file mode 100644 index 000000000..8d54b509b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-own-workq @@ -0,0 +1,136 @@ +From: Takashi Iwai +Subject: ALSA: hda - Use own workqueue +Patch-mainline: 2.6.29-rc2 +References: bnc#502733 + +snd-hda-intel driver used schedule_work() fot the delayed DMA pointer +updates, but this has several potential problems: +- it may block other eventsd works longer +- it may deadlock when probing fails and flush_scheduled_work() is + called during probe callback (as probe callback itself could be + invoked from eventd) + +This patch adds an own workq for each driver instance to solve these +problems. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_beep.c | 1 - + sound/pci/hda/hda_codec.c | 24 ++++++++++++++++++------ + sound/pci/hda/hda_codec.h | 2 ++ + sound/pci/hda/hda_intel.c | 6 +++--- + 4 files changed, 23 insertions(+), 10 deletions(-) + +--- a/sound/pci/hda/hda_beep.c ++++ b/sound/pci/hda/hda_beep.c +@@ -134,7 +134,6 @@ + struct hda_beep *beep = codec->beep; + if (beep) { + cancel_work_sync(&beep->beep_work); +- flush_scheduled_work(); + + input_unregister_device(beep->dev); + kfree(beep); +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -310,7 +310,7 @@ + unsol->queue[wp] = res; + unsol->queue[wp + 1] = res_ex; + +- schedule_work(&unsol->work); ++ queue_work(bus->workq, &unsol->work); + + return 0; + } +@@ -373,15 +373,17 @@ + + if (!bus) + return 0; +- if (bus->unsol) { +- flush_scheduled_work(); ++ if (bus->workq) ++ flush_workqueue(bus->workq); ++ if (bus->unsol) + kfree(bus->unsol); +- } + list_for_each_entry_safe(codec, n, &bus->codec_list, list) { + snd_hda_codec_free(codec); + } + if (bus->ops.private_free) + bus->ops.private_free(bus); ++ if (bus->workq) ++ destroy_workqueue(bus->workq); + kfree(bus); + return 0; + } +@@ -431,6 +433,16 @@ + mutex_init(&bus->cmd_mutex); + INIT_LIST_HEAD(&bus->codec_list); + ++ snprintf(bus->workq_name, sizeof(bus->workq_name), ++ "hd-audio%d", card->number); ++ bus->workq = create_singlethread_workqueue(bus->workq_name); ++ if (!bus->workq) { ++ snd_printk(KERN_ERR "cannot create workqueue %s\n", ++ bus->workq_name); ++ kfree(bus); ++ return -ENOMEM; ++ } ++ + err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); + if (err < 0) { + snd_hda_bus_free(bus); +@@ -564,7 +576,7 @@ + return; + #ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); +- flush_scheduled_work(); ++ flush_workqueue(codec->bus->workq); + #endif + list_del(&codec->list); + codec->bus->caddr_tbl[codec->addr] = NULL; +@@ -2533,7 +2545,7 @@ + return; + if (power_save) { + codec->power_transition = 1; /* avoid reentrance */ +- schedule_delayed_work(&codec->power_work, ++ queue_delayed_work(codec->bus->workq, &codec->power_work, + msecs_to_jiffies(power_save * 1000)); + } + } +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -580,6 +580,8 @@ + + /* unsolicited event queue */ + struct hda_bus_unsolicited *unsol; ++ char workq_name[16]; ++ struct workqueue_struct *workq; /* common workqueue for codecs */ + + struct snd_info_entry *proc; + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -986,10 +986,11 @@ + spin_unlock(&chip->reg_lock); + snd_pcm_period_elapsed(azx_dev->substream); + spin_lock(&chip->reg_lock); +- } else { ++ } else if (chip->bus && chip->bus->workq) { + /* bogus IRQ, process it later */ + azx_dev->irq_pending = 1; +- schedule_work(&chip->irq_pending_work); ++ queue_work(chip->bus->workq, ++ &chip->irq_pending_work); + } + } + } +@@ -1708,7 +1709,6 @@ + for (i = 0; i < chip->num_streams; i++) + chip->azx_dev[i].irq_pending = 0; + spin_unlock_irq(&chip->reg_lock); +- flush_scheduled_work(); + } + + static struct snd_pcm_ops azx_pcm_ops = { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-pb-rs65-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-pb-rs65-quirk new file mode 100644 index 000000000..bc7e82045 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-pb-rs65-quirk @@ -0,0 +1,35 @@ +From 5bd3729f6818721f76a2a2f7d2ecad899bace340 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 21 Apr 2009 18:36:30 +0200 +Subject: ALSA: hda - Add quirk for Packard Bell RS65 +Patch-mainline: +References: bnc#496878 + +Added a quirk (model=m51va) for Packard Bell RS65 with ALC663. + +Reference: Novell bnc#496787 + https://bugzilla.novell.com/show_bug.cgi?id=496787 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -16010,12 +16010,13 @@ static struct snd_pci_quirk alc662_cfg_t + SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), + SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", + ALC662_3ST_6ch_DIG), +- SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS), + SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), ++ SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA), ++ SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0", + ALC662_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-quirk-ext b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-quirk-ext new file mode 100644 index 000000000..766c195d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-quirk-ext @@ -0,0 +1,97 @@ +From: Takashi Iwai +Subject: ALSA: Backport snd_pci_quirk*() extension +Patch-mainline: +References: bnc#511306 + +Backport the extension of snd_pci_quirk*() helper for updating the +HD-audio stuff. To avoid the conflict, all renamed and localized into +snd-hda-intel driver. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 15 +++++++++++++ + sound/pci/hda/hda_codec.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 66 insertions(+) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -3432,3 +3432,18 @@ + buf[j] = '\0'; /* necessary when j == 0 */ + } + ++/* backported */ ++const struct snd_pci_quirk * ++snd_hda_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) ++{ ++ const struct snd_pci_quirk *q; ++ ++ for (q = list; q->subvendor; q++) { ++ if (q->subvendor != pci->subsystem_vendor) ++ continue; ++ if (!q->subdevice || ++ (pci->subsystem_device & q->subdevice_mask) == q->subdevice) ++ return q; ++ } ++ return NULL; ++} +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -26,6 +26,57 @@ + #include + #include + ++ ++/* ++ * quirk with mask; backported ++ */ ++ ++/* PCI quirk list helper */ ++struct snd_hda_quirk { ++ unsigned short subvendor; /* PCI subvendor ID */ ++ unsigned short subdevice; /* PCI subdevice ID */ ++ unsigned short subdevice_mask; /* bitmask to match */ ++ int value; /* value */ ++#ifdef CONFIG_SND_DEBUG_VERBOSE ++ const char *name; /* name of the device (optional) */ ++#endif ++}; ++ ++#define snd_pci_quirk snd_hda_quirk ++#undef _SND_PCI_QUIRK_ID_MASK ++#undef _SND_PCI_QUIRK_ID ++#undef SND_PCI_QUIRK_ID ++#undef SND_PCI_QUIRK ++#undef SND_PCI_QUIRK_MASK ++#undef SND_PCI_QUIRK_VENDOR ++ ++#define _SND_PCI_QUIRK_ID_MASK(vend, mask, dev) \ ++ .subvendor = (vend), .subdevice = (dev), .subdevice_mask = (mask) ++#define _SND_PCI_QUIRK_ID(vend, dev) \ ++ _SND_PCI_QUIRK_ID_MASK(vend, 0xffff, dev) ++#define SND_PCI_QUIRK_ID(vend,dev) {_SND_PCI_QUIRK_ID(vend, dev)} ++#ifdef CONFIG_SND_DEBUG_VERBOSE ++#define SND_PCI_QUIRK(vend,dev,xname,val) \ ++ {_SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname)} ++#define SND_PCI_QUIRK_VENDOR(vend, xname, val) \ ++ {_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val), .name = (xname)} ++#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val) \ ++ {_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), \ ++ .value = (val), .name = (xname)} ++#else ++#define SND_PCI_QUIRK(vend,dev,xname,val) \ ++ {_SND_PCI_QUIRK_ID(vend, dev), .value = (val)} ++#define SND_PCI_QUIRK_MASK(vend, mask, dev, xname, val) \ ++ {_SND_PCI_QUIRK_ID_MASK(vend, mask, dev), .value = (val)} ++#define SND_PCI_QUIRK_VENDOR(vend, xname, val) \ ++ {_SND_PCI_QUIRK_ID_MASK(vend, 0, 0), .value = (val)} ++#endif ++ ++const struct snd_pci_quirk * ++snd_hda_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); ++ ++#define snd_pci_quirk_lookup snd_hda_quirk_lookup ++ + #if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) + #define SND_HDA_NEEDS_RESUME /* resume control code is required */ + #endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-reduce-click-noise b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-reduce-click-noise new file mode 100644 index 000000000..05dad966b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-reduce-click-noise @@ -0,0 +1,61 @@ +From 05ff7e11b78f18ff6819d2c260b7bcc7da0c8f46 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Subject: [PATCH] ALSA: hda - Reduce click noise at power-saving +Patch-mainline: +References: bnc#521190 + +Add some tricks to reduce the click noise at powering down to D3 +in the power saving mode on STAC/IDT codecs. +The key seems to be to reset PINs before the power-down, and some +delay before entering D3. The needed delay is significantly long, +but I don't know why. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 9 +++++++-- + sound/pci/hda/patch_sigmatel.c | 14 ++++++++++++++ + 2 files changed, 21 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -1979,9 +1979,14 @@ static void hda_set_power_state(struct h + hda_nid_t nid; + int i; + +- snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, ++ /* this delay seems necessary to avoid click noise at power-down */ ++ if (power_state == AC_PWRST_D3) ++ msleep(100); ++ snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, + power_state); +- msleep(10); /* partial workaround for "azx_get_response timeout" */ ++ /* partial workaround for "azx_get_response timeout" */ ++ if (power_state == AC_PWRST_D0) ++ msleep(10); + + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -4268,6 +4268,20 @@ static int stac92xx_resume(struct hda_co + static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) + { + struct sigmatel_spec *spec = codec->spec; ++ int i; ++ hda_nid_t nid; ++ ++ /* reset each pin before powering down DAC/ADC to avoid click noise */ ++ nid = codec->start_nid; ++ for (i = 0; i < codec->num_nodes; i++, nid++) { ++ unsigned int wcaps = get_wcaps(codec, nid); ++ unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> ++ AC_WCAP_TYPE_SHIFT; ++ if (wid_type == AC_WID_PIN) ++ snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, 0); ++ } ++ + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-robust-codec-probe b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-robust-codec-probe new file mode 100644 index 000000000..f8bb18bf3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-robust-codec-probe @@ -0,0 +1,159 @@ +From: Takashi Iwai +Subject: ALSA: hda - Make codec-probing more robust +Patch-mainline: 2.6.29-rc1 +References: bnc#502733 + +When an error occurs during the codec probing, typically accessing to an +non-existing codec slot, the controller chip gets often screwed up and +can no longer communicate with the codecs. + +This patch adds a preparation phase just to probe codec addresses before +actually creating codec instances. If any error occurs during this +probing phase, the driver resets the controller to recover. + +This will (hopefully) fix the famous "single_cmd" errors. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 88 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 59 insertions(+), 29 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -392,6 +392,7 @@ struct azx { + unsigned int msi :1; + unsigned int irq_pending_warned :1; + unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ ++ unsigned int probing :1; /* codec probing phase */ + + /* for debugging */ + unsigned int last_cmd; /* last issued command (to sync) */ +@@ -624,6 +625,14 @@ static unsigned int azx_rirb_get_respons + goto again; + } + ++ if (chip->probing) { ++ /* If this critical timeout happens during the codec probing ++ * phase, this is likely an access to a non-existing codec ++ * slot. Better to return an error and reset the system. ++ */ ++ return -1; ++ } ++ + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " + "switching to single_cmd mode: last cmd=0x%08x\n", + chip->last_cmd); +@@ -1178,6 +1187,26 @@ static int azx_setup_controller(struct a + return 0; + } + ++/* ++ * Probe the given codec address ++ */ ++static int probe_codec(struct azx *chip, int addr) ++{ ++ unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | ++ (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; ++ unsigned int res; ++ ++ chip->probing = 1; ++ azx_send_cmd(chip->bus, cmd); ++ res = azx_get_response(chip->bus); ++ chip->probing = 0; ++ if (res == -1) ++ return -EIO; ++ snd_printdd("hda_intel: codec #%d probed OK\n", addr); ++ return 0; ++} ++ ++static void azx_stop_chip(struct azx *chip); + + /* + * Codec initialization +@@ -1188,21 +1217,12 @@ static unsigned int azx_max_codecs[AZX_N + [AZX_DRIVER_TERA] = 1, + }; + +-/* number of slots to probe as default +- * this can be different from azx_max_codecs[] -- e.g. some boards +- * report wrongly the non-existing 4th slot availability +- */ +-static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = { +- [AZX_DRIVER_ICH] = 3, +- [AZX_DRIVER_ATI] = 3, +-}; +- + static int __devinit azx_codec_create(struct azx *chip, const char *model, + unsigned int codec_probe_mask) + { + struct hda_bus_template bus_temp; +- int c, codecs, audio_codecs, err; +- int def_slots, max_slots; ++ int c, codecs, err; ++ int max_slots; + + memset(&bus_temp, 0, sizeof(bus_temp)); + bus_temp.private_data = chip; +@@ -1221,33 +1241,43 @@ static int __devinit azx_codec_create(st + if (chip->driver_type == AZX_DRIVER_NVIDIA) + chip->bus->needs_damn_long_delay = 1; + +- codecs = audio_codecs = 0; ++ codecs = 0; + max_slots = azx_max_codecs[chip->driver_type]; + if (!max_slots) + max_slots = AZX_MAX_CODECS; +- def_slots = azx_default_codecs[chip->driver_type]; +- if (!def_slots) +- def_slots = max_slots; +- for (c = 0; c < def_slots; c++) { ++ ++ /* First try to probe all given codec slots */ ++ for (c = 0; c < max_slots; c++) { ++ if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { ++ if (probe_codec(chip, c) < 0) { ++ /* Some BIOSen give you wrong codec addresses ++ * that don't exist ++ */ ++ snd_printk(KERN_WARNING ++ "hda_intel: Codec #%d probe error; " ++ "disabling it...\n", c); ++ chip->codec_mask &= ~(1 << c); ++ /* More badly, accessing to a non-existing ++ * codec often screws up the controller chip, ++ * and distrubs the further communications. ++ * Thus if an error occurs during probing, ++ * better to reset the controller chip to ++ * get back to the sanity state. ++ */ ++ azx_stop_chip(chip); ++ azx_init_chip(chip); ++ } ++ } ++ } ++ ++ /* Then create codec instances */ ++ for (c = 0; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { + struct hda_codec *codec; + err = snd_hda_codec_new(chip->bus, c, &codec); + if (err < 0) + continue; + codecs++; +- if (codec->afg) +- audio_codecs++; +- } +- } +- if (!audio_codecs) { +- /* probe additional slots if no codec is found */ +- for (; c < max_slots; c++) { +- if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { +- err = snd_hda_codec_new(chip->bus, c, NULL); +- if (err < 0) +- continue; +- codecs++; +- } + } + } + if (!codecs) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update new file mode 100644 index 000000000..9826d53a8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update @@ -0,0 +1,1583 @@ +From: Takashi Iwai +Subject: Backport fixes for patch_sigmatel.c from 2.6.29 +Patch-mainline: 2.6.29 +References: bcn#457472, bnc#462913, bnc#467381, bnc#479558, bnc#480617, bnc#480809 + +Backport patch_sigmatel fixes from 2.6.29. +This includes fixes for multiple Dell and HP laptops. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 896 +++++++++++++++++++++-------------------- + 1 file changed, 480 insertions(+), 416 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -82,6 +82,7 @@ + + enum { + STAC_92HD83XXX_REF, ++ STAC_92HD83XXX_PWR_REF, + STAC_92HD83XXX_MODELS + }; + +@@ -144,6 +145,13 @@ + STAC_927X_MODELS + }; + ++struct sigmatel_event { ++ hda_nid_t nid; ++ unsigned char type; ++ unsigned char tag; ++ int data; ++}; ++ + struct sigmatel_spec { + struct snd_kcontrol_new *mixers[4]; + unsigned int num_mixers; +@@ -151,8 +159,6 @@ + int board_config; + unsigned int eapd_switch: 1; + unsigned int surr_switch: 1; +- unsigned int line_switch: 1; +- unsigned int mic_switch: 1; + unsigned int alt_switch: 1; + unsigned int hp_detect: 1; + unsigned int spdif_mute: 1; +@@ -178,12 +184,18 @@ + hda_nid_t *pwr_nids; + hda_nid_t *dac_list; + ++ /* events */ ++ int num_events; ++ struct sigmatel_event events[32]; ++ + /* playback */ + struct hda_input_mux *mono_mux; + struct hda_input_mux *amp_mux; + unsigned int cur_mmux; + struct hda_multi_out multiout; + hda_nid_t dac_nids[5]; ++ hda_nid_t hp_dacs[5]; ++ hda_nid_t speaker_dacs[5]; + + int volume_offset; + +@@ -230,7 +242,9 @@ + /* i/o switches */ + unsigned int io_switch[2]; + unsigned int clfe_swap; +- unsigned int hp_switch; /* NID of HP as line-out */ ++ hda_nid_t line_switch; /* shared line-in for input and output */ ++ hda_nid_t mic_switch; /* shared mic-in for input and output */ ++ hda_nid_t hp_switch; /* NID of HP as line-out */ + unsigned int aloopback; + + struct hda_pcm pcm_rec[2]; /* PCM information */ +@@ -282,9 +296,6 @@ + }; + + #define STAC92HD73_DAC_COUNT 5 +-static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = { +- 0x15, 0x16, 0x17, 0x18, 0x19, +-}; + + static hda_nid_t stac92hd73xx_mux_nids[4] = { + 0x28, 0x29, 0x2a, 0x2b, +@@ -303,11 +314,7 @@ + 0x11, 0x12, 0 + }; + +-#define STAC92HD81_DAC_COUNT 2 + #define STAC92HD83_DAC_COUNT 3 +-static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = { +- 0x13, 0x14, 0x22, +-}; + + static hda_nid_t stac92hd83xxx_dmux_nids[2] = { + 0x17, 0x18, +@@ -326,7 +333,11 @@ + }; + + static unsigned int stac92hd83xxx_pwr_mapping[4] = { +- 0x03, 0x0c, 0x10, 0x40, ++ 0x03, 0x0c, 0x20, 0x40, ++}; ++ ++static hda_nid_t stac92hd83xxx_amp_nids[1] = { ++ 0xc, + }; + + static hda_nid_t stac92hd71bxx_pwr_nids[3] = { +@@ -349,10 +360,6 @@ + 0x24, 0x25, + }; + +-static hda_nid_t stac92hd71bxx_dac_nids[1] = { +- 0x10, /*0x11, */ +-}; +- + #define STAC92HD71BXX_NUM_DMICS 2 + static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { + 0x18, 0x19, 0 +@@ -584,12 +591,12 @@ + else + nid = codec->slave_dig_outs[smux_idx - 1]; + if (spec->cur_smux[smux_idx] == smux->num_items - 1) +- val = AMP_OUT_MUTE; ++ val = HDA_AMP_MUTE; + else +- val = AMP_OUT_UNMUTE; ++ val = 0; + /* un/mute SPDIF out */ +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_AMP_GAIN_MUTE, val); ++ snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, ++ HDA_AMP_MUTE, val); + } + return 0; + } +@@ -754,10 +761,6 @@ + static struct hda_verb stac92hd73xx_6ch_core_init[] = { + /* set master volume and direct control */ + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* setup audio connections */ +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, +- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, +- { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -776,10 +779,6 @@ + /* set master volume to max value without distortion + * and direct control */ + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, +- /* setup audio connections */ +- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02}, +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -793,10 +792,6 @@ + + static struct hda_verb dell_m6_core_init[] = { + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* setup audio connections */ +- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -811,13 +806,6 @@ + static struct hda_verb stac92hd73xx_8ch_core_init[] = { + /* set master volume and direct control */ + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* setup audio connections */ +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, +- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, +- { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, +- /* connect hp ports to dac3 */ +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03}, +- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -835,15 +823,8 @@ + static struct hda_verb stac92hd73xx_10ch_core_init[] = { + /* set master volume and direct control */ + { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* setup audio connections */ +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, +- { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 }, +- { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 }, + /* dac3 is connected to import3 mux */ + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f}, +- /* connect hp ports to dac4 */ +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04}, +- { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04}, + /* setup adcs to point to mixer */ + { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, + { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, +@@ -859,10 +840,6 @@ + }; + + static struct hda_verb stac92hd83xxx_core_init[] = { +- /* start of config #1 */ +- { 0xe, AC_VERB_SET_CONNECT_SEL, 0x3}, +- +- /* start of config #2 */ + { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0}, + { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0}, + { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1}, +@@ -875,8 +852,6 @@ + static struct hda_verb stac92hd71bxx_core_init[] = { + /* set master volume and direct control */ + { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* connect headphone jack to dac1 */ +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ + { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +@@ -896,8 +871,6 @@ + + /* set master volume and direct control */ + { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* connect headphone jack to dac1 */ +- { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, + /* unmute right and left channels for nodes 0x0a, 0xd */ + { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +@@ -1099,21 +1072,21 @@ + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT), + +- HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT), +- HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT), ++ HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), ++ HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), + +- HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT), +- HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT), ++ HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT), ++ HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT), + +- HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT), +- HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT), ++ HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT), ++ HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT), + +- HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT), +- HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT), ++ HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT), ++ HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT), + + /* +- HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT), +- HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT), ++ HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT), + */ + { } /* end */ + }; +@@ -1726,10 +1699,12 @@ + + static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { + [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, ++ [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, + }; + + static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { + [STAC_92HD83XXX_REF] = "ref", ++ [STAC_92HD83XXX_PWR_REF] = "mic-ref", + }; + + static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { +@@ -1788,11 +1763,13 @@ + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2, + "HP dv5", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, +- "HP dv7", STAC_HP_M4), ++ "HP dv7", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7, + "HP dv4", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, + "HP dv7", STAC_HP_M4), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600, ++ "HP dv5", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, + "HP dv5", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, +@@ -2419,7 +2396,7 @@ + + if (spec->powerdown_adcs) { + msleep(40); +- snd_hda_codec_write_cache(codec, nid, 0, ++ snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); +@@ -2435,7 +2412,7 @@ + + snd_hda_codec_cleanup_stream(codec, nid); + if (spec->powerdown_adcs) +- snd_hda_codec_write_cache(codec, nid, 0, ++ snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + return 0; + } +@@ -2569,6 +2546,9 @@ + return 0; + } + ++static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, ++ unsigned char type); ++ + static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) + { +@@ -2581,8 +2561,7 @@ + /* check to be sure that the ports are upto date with + * switch changes + */ +- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); +- ++ stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); + return 1; + } + +@@ -2621,7 +2600,7 @@ + * appropriately according to the pin direction + */ + if (spec->hp_detect) +- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); ++ stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); + + return 1; + } +@@ -2758,70 +2737,53 @@ + return stac92xx_add_control_idx(spec, type, 0, name, val); + } + +-/* flag inputs as additional dynamic lineouts */ +-static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg) ++/* check whether the line-input can be used as line-out */ ++static hda_nid_t check_line_out_switch(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; +- unsigned int wcaps, wtype; +- int i, num_dacs = 0; +- +- /* use the wcaps cache to count all DACs available for line-outs */ +- for (i = 0; i < codec->num_nodes; i++) { +- wcaps = codec->wcaps[i]; +- wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ hda_nid_t nid; ++ unsigned int pincap; + +- if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) +- num_dacs++; +- } ++ if (cfg->line_out_type != AUTO_PIN_LINE_OUT) ++ return 0; ++ nid = cfg->input_pins[AUTO_PIN_LINE]; ++ pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); ++ if (pincap & AC_PINCAP_OUT) ++ return nid; ++ return 0; ++} + +- snd_printdd("%s: total dac count=%d\n", __func__, num_dacs); +- +- switch (cfg->line_outs) { +- case 3: +- /* add line-in as side */ +- if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { +- cfg->line_out_pins[cfg->line_outs] = +- cfg->input_pins[AUTO_PIN_LINE]; +- spec->line_switch = 1; +- cfg->line_outs++; +- } +- break; +- case 2: +- /* add line-in as clfe and mic as side */ +- if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { +- cfg->line_out_pins[cfg->line_outs] = +- cfg->input_pins[AUTO_PIN_LINE]; +- spec->line_switch = 1; +- cfg->line_outs++; +- } +- if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { +- cfg->line_out_pins[cfg->line_outs] = +- cfg->input_pins[AUTO_PIN_MIC]; +- spec->mic_switch = 1; +- cfg->line_outs++; +- } +- break; +- case 1: +- /* add line-in as surr and mic as clfe */ +- if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { +- cfg->line_out_pins[cfg->line_outs] = +- cfg->input_pins[AUTO_PIN_LINE]; +- spec->line_switch = 1; +- cfg->line_outs++; +- } +- if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { +- cfg->line_out_pins[cfg->line_outs] = +- cfg->input_pins[AUTO_PIN_MIC]; +- spec->mic_switch = 1; +- cfg->line_outs++; ++/* check whether the mic-input can be used as line-out */ ++static hda_nid_t check_mic_out_switch(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ unsigned int def_conf, pincap; ++ unsigned int mic_pin; ++ ++ if (cfg->line_out_type != AUTO_PIN_LINE_OUT) ++ return 0; ++ mic_pin = AUTO_PIN_MIC; ++ for (;;) { ++ hda_nid_t nid = cfg->input_pins[mic_pin]; ++ def_conf = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_CONFIG_DEFAULT, 0); ++ /* some laptops have an internal analog microphone ++ * which can't be used as a output */ ++ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { ++ pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); ++ if (pincap & AC_PINCAP_OUT) ++ return nid; + } +- break; ++ if (mic_pin == AUTO_PIN_MIC) ++ mic_pin = AUTO_PIN_FRONT_MIC; ++ else ++ break; + } +- + return 0; + } + +- + static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) + { + int i; +@@ -2834,6 +2796,52 @@ + return 0; + } + ++static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) ++{ ++ int i; ++ if (is_in_dac_nids(spec, nid)) ++ return 1; ++ for (i = 0; i < spec->autocfg.hp_outs; i++) ++ if (spec->hp_dacs[i] == nid) ++ return 1; ++ for (i = 0; i < spec->autocfg.speaker_outs; i++) ++ if (spec->speaker_dacs[i] == nid) ++ return 1; ++ return 0; ++} ++ ++static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int j, conn_len; ++ hda_nid_t conn[HDA_MAX_CONNECTIONS]; ++ unsigned int wcaps, wtype; ++ ++ conn_len = snd_hda_get_connections(codec, nid, conn, ++ HDA_MAX_CONNECTIONS); ++ for (j = 0; j < conn_len; j++) { ++ wcaps = snd_hda_param_read(codec, conn[j], ++ AC_PAR_AUDIO_WIDGET_CAP); ++ wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; ++ /* we check only analog outputs */ ++ if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL)) ++ continue; ++ /* if this route has a free DAC, assign it */ ++ if (!check_all_dac_nids(spec, conn[j])) { ++ if (conn_len > 1) { ++ /* select this DAC in the pin's input mux */ ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_CONNECT_SEL, j); ++ } ++ return conn[j]; ++ } ++ } ++ return 0; ++} ++ ++static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid); ++static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid); ++ + /* + * Fill in the dac_nids table from the parsed pin configuration + * This function only works when every pin in line_out_pins[] +@@ -2841,31 +2849,17 @@ + * codecs are not connected directly to a DAC, such as the 9200 + * and 9202/925x. For those, dac_nids[] must be hard-coded. + */ +-static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, +- struct auto_pin_cfg *cfg) ++static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; +- int i, j, conn_len = 0; +- hda_nid_t nid, conn[HDA_MAX_CONNECTIONS]; +- unsigned int wcaps, wtype; ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ int i; ++ hda_nid_t nid, dac; + + for (i = 0; i < cfg->line_outs; i++) { + nid = cfg->line_out_pins[i]; +- conn_len = snd_hda_get_connections(codec, nid, conn, +- HDA_MAX_CONNECTIONS); +- for (j = 0; j < conn_len; j++) { +- wcaps = snd_hda_param_read(codec, conn[j], +- AC_PAR_AUDIO_WIDGET_CAP); +- wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; +- if (wtype != AC_WID_AUD_OUT || +- (wcaps & AC_WCAP_DIGITAL)) +- continue; +- /* conn[j] is a DAC routed to this line-out */ +- if (!is_in_dac_nids(spec, conn[j])) +- break; +- } +- +- if (j == conn_len) { ++ dac = get_unassigned_dac(codec, nid); ++ if (!dac) { + if (spec->multiout.num_dacs > 0) { + /* we have already working output pins, + * so let's drop the broken ones again +@@ -2879,24 +2873,64 @@ + __func__, nid); + return -ENODEV; + } ++ add_spec_dacs(spec, dac); ++ } + +- spec->multiout.dac_nids[i] = conn[j]; +- spec->multiout.num_dacs++; +- if (conn_len > 1) { +- /* select this DAC in the pin's input mux */ +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_CONNECT_SEL, j); ++ /* add line-in as output */ ++ nid = check_line_out_switch(codec); ++ if (nid) { ++ dac = get_unassigned_dac(codec, nid); ++ if (dac) { ++ snd_printdd("STAC: Add line-in 0x%x as output %d\n", ++ nid, cfg->line_outs); ++ cfg->line_out_pins[cfg->line_outs] = nid; ++ cfg->line_outs++; ++ spec->line_switch = nid; ++ add_spec_dacs(spec, dac); ++ } ++ } ++ /* add mic as output */ ++ nid = check_mic_out_switch(codec); ++ if (nid) { ++ dac = get_unassigned_dac(codec, nid); ++ if (dac) { ++ snd_printdd("STAC: Add mic-in 0x%x as output %d\n", ++ nid, cfg->line_outs); ++ cfg->line_out_pins[cfg->line_outs] = nid; ++ cfg->line_outs++; ++ spec->mic_switch = nid; ++ add_spec_dacs(spec, dac); ++ } ++ } + ++ for (i = 0; i < cfg->hp_outs; i++) { ++ nid = cfg->hp_pins[i]; ++ dac = get_unassigned_dac(codec, nid); ++ if (dac) { ++ if (!spec->multiout.hp_nid) ++ spec->multiout.hp_nid = dac; ++ else ++ add_spec_extra_dacs(spec, dac); + } ++ spec->hp_dacs[i] = dac; + } + +- snd_printd("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", ++ for (i = 0; i < cfg->speaker_outs; i++) { ++ nid = cfg->speaker_pins[i]; ++ dac = get_unassigned_dac(codec, nid); ++ if (dac) ++ add_spec_extra_dacs(spec, dac); ++ spec->speaker_dacs[i] = dac; ++ } ++ ++ snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + spec->multiout.num_dacs, + spec->multiout.dac_nids[0], + spec->multiout.dac_nids[1], + spec->multiout.dac_nids[2], + spec->multiout.dac_nids[3], + spec->multiout.dac_nids[4]); ++ + return 0; + } + +@@ -2941,9 +2975,7 @@ + + static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) + { +- if (!spec->multiout.hp_nid) +- spec->multiout.hp_nid = nid; +- else if (spec->multiout.num_dacs > 4) { ++ if (spec->multiout.num_dacs > 4) { + printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); + return 1; + } else { +@@ -2953,35 +2985,47 @@ + return 0; + } + +-static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) ++static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) + { +- if (is_in_dac_nids(spec, nid)) +- return 1; ++ int i; ++ for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { ++ if (!spec->multiout.extra_out_nid[i]) { ++ spec->multiout.extra_out_nid[i] = nid; ++ return 0; ++ } ++ } ++ printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid); ++ return 1; ++} ++ ++static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid) ++{ ++ int i; ++ ++ if (spec->autocfg.line_outs != 1) ++ return 0; + if (spec->multiout.hp_nid == nid) +- return 1; +- return 0; ++ return 0; ++ for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) ++ if (spec->multiout.extra_out_nid[i] == nid) ++ return 0; ++ return 1; + } + + /* add playback controls from the parsed DAC table */ + static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) + { ++ struct sigmatel_spec *spec = codec->spec; + static const char *chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; + hda_nid_t nid = 0; + int i, err; ++ unsigned int wid_caps; + +- struct sigmatel_spec *spec = codec->spec; +- unsigned int wid_caps, pincap; +- +- +- for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) { +- if (!spec->multiout.dac_nids[i]) +- continue; +- ++ for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { + nid = spec->multiout.dac_nids[i]; +- + if (i == 2) { + /* Center/LFE */ + err = create_controls(codec, "Center", nid, 1); +@@ -3003,16 +3047,24 @@ + } + + } else { +- err = create_controls(codec, chname[i], nid, 3); ++ const char *name = chname[i]; ++ /* if it's a single DAC, assign a better name */ ++ if (!i && is_unique_dac(spec, nid)) { ++ switch (cfg->line_out_type) { ++ case AUTO_PIN_HP_OUT: ++ name = "Headphone"; ++ break; ++ case AUTO_PIN_SPEAKER_OUT: ++ name = "Speaker"; ++ break; ++ } ++ } ++ err = create_controls(codec, name, nid, 3); + if (err < 0) + return err; + } + } + +- if ((spec->multiout.num_dacs - cfg->line_outs) > 0 && +- cfg->hp_outs == 1 && !spec->multiout.hp_nid) +- spec->multiout.hp_nid = nid; +- + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_HP_SWITCH, +@@ -3023,45 +3075,19 @@ + } + + if (spec->line_switch) { +- nid = cfg->input_pins[AUTO_PIN_LINE]; +- pincap = snd_hda_param_read(codec, nid, +- AC_PAR_PIN_CAP); +- if (pincap & AC_PINCAP_OUT) { +- err = stac92xx_add_control(spec, +- STAC_CTL_WIDGET_IO_SWITCH, +- "Line In as Output Switch", nid << 8); +- if (err < 0) +- return err; +- } ++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, ++ "Line In as Output Switch", ++ spec->line_switch << 8); ++ if (err < 0) ++ return err; + } + + if (spec->mic_switch) { +- unsigned int def_conf; +- unsigned int mic_pin = AUTO_PIN_MIC; +-again: +- nid = cfg->input_pins[mic_pin]; +- def_conf = snd_hda_codec_read(codec, nid, 0, +- AC_VERB_GET_CONFIG_DEFAULT, 0); +- /* some laptops have an internal analog microphone +- * which can't be used as a output */ +- if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { +- pincap = snd_hda_param_read(codec, nid, +- AC_PAR_PIN_CAP); +- if (pincap & AC_PINCAP_OUT) { +- err = stac92xx_add_control(spec, +- STAC_CTL_WIDGET_IO_SWITCH, +- "Mic as Output Switch", (nid << 8) | 1); +- nid = snd_hda_codec_read(codec, nid, 0, +- AC_VERB_GET_CONNECT_LIST, 0) & 0xff; +- if (!check_in_dac_nids(spec, nid)) +- add_spec_dacs(spec, nid); +- if (err < 0) +- return err; +- } +- } else if (mic_pin == AUTO_PIN_MIC) { +- mic_pin = AUTO_PIN_FRONT_MIC; +- goto again; +- } ++ err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, ++ "Mic as Output Switch", ++ (spec->mic_switch << 8) | 1); ++ if (err < 0) ++ return err; + } + + return 0; +@@ -3073,55 +3099,39 @@ + { + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid; +- int i, old_num_dacs, err; ++ int i, err, nums; + +- old_num_dacs = spec->multiout.num_dacs; ++ nums = 0; + for (i = 0; i < cfg->hp_outs; i++) { ++ static const char *pfxs[] = { ++ "Headphone", "Headphone2", "Headphone3", ++ }; + unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); + if (wid_caps & AC_WCAP_UNSOL_CAP) + spec->hp_detect = 1; +- nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, +- AC_VERB_GET_CONNECT_LIST, 0) & 0xff; +- if (check_in_dac_nids(spec, nid)) +- nid = 0; +- if (! nid) ++ if (nums >= ARRAY_SIZE(pfxs)) + continue; +- add_spec_dacs(spec, nid); +- } +- for (i = 0; i < cfg->speaker_outs; i++) { +- nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0, +- AC_VERB_GET_CONNECT_LIST, 0) & 0xff; +- if (check_in_dac_nids(spec, nid)) +- nid = 0; +- if (! nid) ++ nid = spec->hp_dacs[i]; ++ if (!nid) + continue; +- add_spec_dacs(spec, nid); +- } +- for (i = 0; i < cfg->line_outs; i++) { +- nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0, +- AC_VERB_GET_CONNECT_LIST, 0) & 0xff; +- if (check_in_dac_nids(spec, nid)) +- nid = 0; +- if (! nid) +- continue; +- add_spec_dacs(spec, nid); ++ err = create_controls(codec, pfxs[nums++], nid, 3); ++ if (err < 0) ++ return err; + } +- for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { ++ nums = 0; ++ for (i = 0; i < cfg->speaker_outs; i++) { + static const char *pfxs[] = { + "Speaker", "External Speaker", "Speaker2", + }; +- err = create_controls(codec, pfxs[i - old_num_dacs], +- spec->multiout.dac_nids[i], 3); +- if (err < 0) +- return err; +- } +- if (spec->multiout.hp_nid) { +- err = create_controls(codec, "Headphone", +- spec->multiout.hp_nid, 3); ++ if (nums >= ARRAY_SIZE(pfxs)) ++ continue; ++ nid = spec->speaker_dacs[i]; ++ if (!nid) ++ continue; ++ err = create_controls(codec, pfxs[nums++], nid, 3); + if (err < 0) + return err; + } +- + return 0; + } + +@@ -3459,7 +3469,6 @@ + { + struct sigmatel_spec *spec = codec->spec; + int err; +- int hp_speaker_swap = 0; + + if ((err = snd_hda_parse_pin_def_config(codec, + &spec->autocfg, +@@ -3477,13 +3486,15 @@ + * speaker_outs so that the following routines can handle + * HP pins as primary outputs. + */ ++ snd_printdd("stac92xx: Enabling multi-HPs workaround\n"); + memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins, + sizeof(spec->autocfg.line_out_pins)); + spec->autocfg.speaker_outs = spec->autocfg.line_outs; + memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins, + sizeof(spec->autocfg.hp_pins)); + spec->autocfg.line_outs = spec->autocfg.hp_outs; +- hp_speaker_swap = 1; ++ spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; ++ spec->autocfg.hp_outs = 0; + } + if (spec->autocfg.mono_out_pin) { + int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & +@@ -3535,10 +3546,9 @@ + AC_PINCTL_OUT_EN); + } + +- if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) +- return err; +- if (spec->multiout.num_dacs == 0) { +- if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) ++ if (!spec->multiout.num_dacs) { ++ err = stac92xx_auto_fill_dac_nids(codec); ++ if (err < 0) + return err; + err = stac92xx_auto_create_multi_out_ctls(codec, + &spec->autocfg); +@@ -3577,19 +3587,6 @@ + } + #endif + +- if (hp_speaker_swap == 1) { +- /* Restore the hp_outs and line_outs */ +- memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, +- sizeof(spec->autocfg.line_out_pins)); +- spec->autocfg.hp_outs = spec->autocfg.line_outs; +- memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins, +- sizeof(spec->autocfg.speaker_pins)); +- spec->autocfg.line_outs = spec->autocfg.speaker_outs; +- memset(spec->autocfg.speaker_pins, 0, +- sizeof(spec->autocfg.speaker_pins)); +- spec->autocfg.speaker_outs = 0; +- } +- + err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); + + if (err < 0) +@@ -3638,7 +3635,8 @@ + spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + + spec->input_mux = &spec->private_imux; +- spec->dinput_mux = &spec->private_dimux; ++ if (!spec->dinput_mux) ++ spec->dinput_mux = &spec->private_dimux; + spec->sinput_mux = &spec->private_smux; + spec->mono_mux = &spec->private_mono_mux; + spec->amp_mux = &spec->private_amp_mux; +@@ -3787,13 +3785,68 @@ + AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ + } + ++static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, ++ unsigned char type, int data) ++{ ++ struct sigmatel_event *event; ++ ++ if (spec->num_events >= ARRAY_SIZE(spec->events)) ++ return -ENOMEM; ++ event = &spec->events[spec->num_events++]; ++ event->nid = nid; ++ event->type = type; ++ event->tag = spec->num_events; ++ event->data = data; ++ ++ return event->tag; ++} ++ ++static struct sigmatel_event *stac_get_event(struct hda_codec *codec, ++ hda_nid_t nid, unsigned char type) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct sigmatel_event *event = spec->events; ++ int i; ++ ++ for (i = 0; i < spec->num_events; i++, event++) { ++ if (event->nid == nid && event->type == type) ++ return event; ++ } ++ return NULL; ++} ++ ++static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, ++ unsigned char tag) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct sigmatel_event *event = spec->events; ++ int i; ++ ++ for (i = 0; i < spec->num_events; i++, event++) { ++ if (event->tag == tag) ++ return event; ++ } ++ return NULL; ++} ++ + static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, +- unsigned int event) ++ unsigned int type) + { +- if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_UNSOLICITED_ENABLE, +- (AC_USRSP_EN | event)); ++ struct sigmatel_event *event; ++ int tag; ++ ++ if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) ++ return; ++ event = stac_get_event(codec, nid, type); ++ if (event) ++ tag = event->tag; ++ else ++ tag = stac_add_event(codec->spec, nid, type, 0); ++ if (tag < 0) ++ return; ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_UNSOLICITED_ENABLE, ++ AC_USRSP_EN | tag); + } + + static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) +@@ -3813,9 +3866,8 @@ + /* power down inactive DACs */ + hda_nid_t *dac; + for (dac = spec->dac_list; *dac; dac++) +- if (!is_in_dac_nids(spec, *dac) && +- spec->multiout.hp_nid != *dac) +- snd_hda_codec_write_cache(codec, *dac, 0, ++ if (!check_all_dac_nids(spec, *dac)) ++ snd_hda_codec_write(codec, *dac, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } + +@@ -3834,7 +3886,7 @@ + /* power down adcs initially */ + if (spec->powerdown_adcs) + for (i = 0; i < spec->num_adcs; i++) +- snd_hda_codec_write_cache(codec, ++ snd_hda_codec_write(codec, + spec->adc_nids[i], 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + +@@ -3850,37 +3902,51 @@ + /* set up pins */ + if (spec->hp_detect) { + /* Enable unsolicited responses on the HP widget */ +- for (i = 0; i < cfg->hp_outs; i++) +- enable_pin_detect(codec, cfg->hp_pins[i], +- STAC_HP_EVENT); ++ for (i = 0; i < cfg->hp_outs; i++) { ++ hda_nid_t nid = cfg->hp_pins[i]; ++ enable_pin_detect(codec, nid, STAC_HP_EVENT); ++ } + /* force to enable the first line-out; the others are set up + * in unsol_event + */ + stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], + AC_PINCTL_OUT_EN); +- stac92xx_auto_init_hp_out(codec); + /* fake event to set up pins */ +- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); ++ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], ++ STAC_HP_EVENT); + } else { + stac92xx_auto_init_multi_out(codec); + stac92xx_auto_init_hp_out(codec); ++ for (i = 0; i < cfg->hp_outs; i++) ++ stac_toggle_power_map(codec, cfg->hp_pins[i], 1); + } + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = cfg->input_pins[i]; + if (nid) { +- unsigned int pinctl; ++ unsigned int pinctl, conf; + if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { + /* for mic pins, force to initialize */ + pinctl = stac92xx_get_vref(codec, nid); ++ pinctl |= AC_PINCTL_IN_EN; ++ stac92xx_auto_set_pinctl(codec, nid, pinctl); + } else { + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + /* if PINCTL already set then skip */ +- if (pinctl & AC_PINCTL_IN_EN) +- continue; ++ if (!(pinctl & AC_PINCTL_IN_EN)) { ++ pinctl |= AC_PINCTL_IN_EN; ++ stac92xx_auto_set_pinctl(codec, nid, ++ pinctl); ++ } ++ } ++ conf = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_CONFIG_DEFAULT, 0); ++ if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { ++ enable_pin_detect(codec, nid, ++ STAC_INSERT_EVENT); ++ stac_issue_unsol_event(codec, nid, ++ STAC_INSERT_EVENT); + } +- pinctl |= AC_PINCTL_IN_EN; +- stac92xx_auto_set_pinctl(codec, nid, pinctl); + } + } + for (i = 0; i < spec->num_dmics; i++) +@@ -3895,9 +3961,14 @@ + for (i = 0; i < spec->num_pwrs; i++) { + hda_nid_t nid = spec->pwr_nids[i]; + int pinctl, def_conf; +- int event = STAC_PWR_EVENT; + +- if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) ++ /* power on when no jack detection is available */ ++ if (!spec->hp_detect) { ++ stac_toggle_power_map(codec, nid, 1); ++ continue; ++ } ++ ++ if (is_nid_hp_pin(cfg, nid)) + continue; /* already has an unsol event */ + + pinctl = snd_hda_codec_read(codec, nid, 0, +@@ -3906,8 +3977,10 @@ + * any attempts on powering down a input port cause the + * referenced VREF to act quirky. + */ +- if (pinctl & AC_PINCTL_IN_EN) ++ if (pinctl & AC_PINCTL_IN_EN) { ++ stac_toggle_power_map(codec, nid, 1); + continue; ++ } + def_conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = get_defcfg_connect(def_conf); +@@ -3918,8 +3991,10 @@ + stac_toggle_power_map(codec, nid, 1); + continue; + } +- enable_pin_detect(codec, spec->pwr_nids[i], event | i); +- codec->patch_ops.unsol_event(codec, (event | i) << 26); ++ if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) { ++ enable_pin_detect(codec, nid, STAC_PWR_EVENT); ++ stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); ++ } + } + if (spec->dac_list) + stac92xx_power_down(codec); +@@ -3960,11 +4035,7 @@ + * "xxx as Output" mixer switch + */ + struct sigmatel_spec *spec = codec->spec; +- struct auto_pin_cfg *cfg = &spec->autocfg; +- if ((nid == cfg->input_pins[AUTO_PIN_LINE] && +- spec->line_switch) || +- (nid == cfg->input_pins[AUTO_PIN_MIC] && +- spec->mic_switch)) ++ if (nid == spec->line_switch || nid == spec->mic_switch) + return; + } + +@@ -3988,20 +4059,13 @@ + pin_ctl & ~flag); + } + +-static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) ++static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) + { + if (!nid) + return 0; + if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) +- & (1 << 31)) { +- unsigned int pinctl; +- pinctl = snd_hda_codec_read(codec, nid, 0, +- AC_VERB_GET_PIN_WIDGET_CONTROL, 0); +- if (pinctl & AC_PINCTL_IN_EN) +- return 0; /* mic- or line-input */ +- else +- return 1; /* HP-output */ +- } ++ & (1 << 31)) ++ return 1; + return 0; + } + +@@ -4013,11 +4077,9 @@ + struct auto_pin_cfg *cfg = &spec->autocfg; + + /* ignore sensing of shared line and mic jacks */ +- if (spec->line_switch && +- cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) ++ if (cfg->hp_pins[i] == spec->line_switch) + return 1; +- if (spec->mic_switch && +- cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) ++ if (cfg->hp_pins[i] == spec->mic_switch) + return 1; + /* ignore if the pin is set as line-out */ + if (cfg->hp_pins[i] == spec->hp_switch) +@@ -4025,7 +4087,7 @@ + return 0; + } + +-static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) ++static void stac92xx_hp_detect(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; +@@ -4041,7 +4103,14 @@ + break; + if (no_hp_sensing(spec, i)) + continue; +- presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); ++ presence = get_pin_presence(codec, cfg->hp_pins[i]); ++ if (presence) { ++ unsigned int pinctl; ++ pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, ++ AC_VERB_GET_PIN_WIDGET_CONTROL, 0); ++ if (pinctl & AC_PINCTL_IN_EN) ++ presence = 0; /* mic- or line-input */ ++ } + } + + if (presence) { +@@ -4082,8 +4151,19 @@ + continue; + if (presence) + stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); ++#if 0 /* FIXME */ ++/* Resetting the pinctl like below may lead to (a sort of) regressions ++ * on some devices since they use the HP pin actually for line/speaker ++ * outs although the default pin config shows a different pin (that is ++ * wrong and useless). ++ * ++ * So, it's basically a problem of default pin configs, likely a BIOS issue. ++ * But, disabling the code below just works around it, and I'm too tired of ++ * bug reports with such devices... ++ */ + else + stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val); ++#endif /* FIXME */ + } + } + +@@ -4118,30 +4198,45 @@ + + static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) + { +- stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid)); ++ stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); ++} ++ ++static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, ++ unsigned char type) ++{ ++ struct sigmatel_event *event = stac_get_event(codec, nid, type); ++ if (!event) ++ return; ++ codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); + } + + static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) + { + struct sigmatel_spec *spec = codec->spec; +- int idx = res >> 26 & 0x0f; ++ struct sigmatel_event *event; ++ int tag, data; ++ ++ tag = (res >> 26) & 0x7f; ++ event = stac_get_event_from_tag(codec, tag); ++ if (!event) ++ return; + +- switch ((res >> 26) & 0x70) { ++ switch (event->type) { + case STAC_HP_EVENT: +- stac92xx_hp_detect(codec, res); ++ stac92xx_hp_detect(codec); + /* fallthru */ ++ case STAC_INSERT_EVENT: + case STAC_PWR_EVENT: + if (spec->num_pwrs > 0) +- stac92xx_pin_sense(codec, idx); ++ stac92xx_pin_sense(codec, event->nid); + break; +- case STAC_VREF_EVENT: { +- int data = snd_hda_codec_read(codec, codec->afg, 0, +- AC_VERB_GET_GPIO_DATA, 0); ++ case STAC_VREF_EVENT: ++ data = snd_hda_codec_read(codec, codec->afg, 0, ++ AC_VERB_GET_GPIO_DATA, 0); + /* toggle VREF state based on GPIOx status */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, +- !!(data & (1 << idx))); ++ !!(data & (1 << event->data))); + break; +- } + } + } + +@@ -4151,17 +4246,23 @@ + struct sigmatel_spec *spec = codec->spec; + + stac92xx_set_config_regs(codec); +- snd_hda_sequence_write(codec, spec->init); +- stac_gpio_set(codec, spec->gpio_mask, +- spec->gpio_dir, spec->gpio_data); ++ stac92xx_init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); +- /* power down inactive DACs */ +- if (spec->dac_list) +- stac92xx_power_down(codec); +- /* invoke unsolicited event to reset the HP state */ ++ /* fake event to set up pins again to override cached values */ + if (spec->hp_detect) +- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); ++ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], ++ STAC_HP_EVENT); ++ return 0; ++} ++ ++static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ if (spec->eapd_mask) ++ stac_gpio_set(codec, spec->gpio_mask, ++ spec->gpio_dir, spec->gpio_data & ++ ~spec->eapd_mask); + return 0; + } + #endif +@@ -4173,6 +4274,7 @@ + .free = stac92xx_free, + .unsol_event = stac92xx_unsol_event, + #ifdef SND_HDA_NEEDS_RESUME ++ .suspend = stac92xx_suspend, + .resume = stac92xx_resume, + #endif + }; +@@ -4234,6 +4336,12 @@ + return err; + } + ++ /* CF-74 has no headphone detection, and the driver should *NOT* ++ * do detection and HP/speaker toggle because the hardware does it. ++ */ ++ if (spec->board_config == STAC_9200_PANASONIC) ++ spec->hp_detect = 0; ++ + codec->patch_ops = stac92xx_patch_ops; + + return 0; +@@ -4340,6 +4448,7 @@ + struct sigmatel_spec *spec; + hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; + int err = 0; ++ int num_dacs; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) +@@ -4368,33 +4477,29 @@ + stac92xx_set_config_regs(codec); + } + +- spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, ++ num_dacs = snd_hda_get_connections(codec, 0x0a, + conn, STAC92HD73_DAC_COUNT + 2) - 1; + +- if (spec->multiout.num_dacs < 0) { ++ if (num_dacs < 3 || num_dacs > 5) { + printk(KERN_WARNING "hda_codec: Could not determine " + "number of channels defaulting to DAC count\n"); +- spec->multiout.num_dacs = STAC92HD73_DAC_COUNT; ++ num_dacs = STAC92HD73_DAC_COUNT; + } +- +- switch (spec->multiout.num_dacs) { ++ switch (num_dacs) { + case 0x3: /* 6 Channel */ +- spec->multiout.hp_nid = 0x17; + spec->mixer = stac92hd73xx_6ch_mixer; + spec->init = stac92hd73xx_6ch_core_init; + break; + case 0x4: /* 8 Channel */ +- spec->multiout.hp_nid = 0x18; + spec->mixer = stac92hd73xx_8ch_mixer; + spec->init = stac92hd73xx_8ch_core_init; + break; + case 0x5: /* 10 Channel */ +- spec->multiout.hp_nid = 0x19; + spec->mixer = stac92hd73xx_10ch_mixer; + spec->init = stac92hd73xx_10ch_core_init; +- }; ++ } ++ spec->multiout.dac_nids = spec->dac_nids; + +- spec->multiout.dac_nids = stac92hd73xx_dac_nids; + spec->aloopback_mask = 0x01; + spec->aloopback_shift = 8; + +@@ -4425,9 +4530,8 @@ + spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; + spec->eapd_switch = 0; + spec->num_amps = 1; +- spec->multiout.hp_nid = 0; /* dual HPs */ + +- if (!spec->init) ++ if (spec->board_config != STAC_DELL_EQ) + spec->init = dell_m6_core_init; + switch (spec->board_config) { + case STAC_DELL_M6_AMIC: /* Analog Mics */ +@@ -4500,7 +4604,9 @@ + static int patch_stac92hd83xxx(struct hda_codec *codec) + { + struct sigmatel_spec *spec; ++ hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; + int err; ++ int num_dacs; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) +@@ -4514,25 +4620,25 @@ + spec->dmux_nids = stac92hd83xxx_dmux_nids; + spec->adc_nids = stac92hd83xxx_adc_nids; + spec->pwr_nids = stac92hd83xxx_pwr_nids; ++ spec->amp_nids = stac92hd83xxx_amp_nids; + spec->pwr_mapping = stac92hd83xxx_pwr_mapping; + spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); +- spec->multiout.dac_nids = stac92hd83xxx_dac_nids; ++ spec->multiout.dac_nids = spec->dac_nids; + +- spec->init = stac92hd83xxx_core_init; +- switch (codec->vendor_id) { +- case 0x111d7605: +- spec->multiout.num_dacs = STAC92HD81_DAC_COUNT; +- break; +- default: +- spec->num_pwrs--; +- spec->init++; /* switch to config #2 */ +- spec->multiout.num_dacs = STAC92HD83_DAC_COUNT; +- } ++ /* set port 0xe to select the last DAC ++ */ ++ num_dacs = snd_hda_get_connections(codec, 0x0e, ++ conn, STAC92HD83_DAC_COUNT + 1) - 1; ++ ++ snd_hda_codec_write_cache(codec, 0xe, 0, ++ AC_VERB_SET_CONNECT_SEL, num_dacs); + ++ spec->init = stac92hd83xxx_core_init; + spec->mixer = stac92hd83xxx_mixer; + spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); + spec->num_dmuxes = ARRAY_SIZE(stac92hd83xxx_dmux_nids); + spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); ++ spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); + spec->num_dmics = STAC92HD83XXX_NUM_DMICS; + spec->dinput_mux = &stac92hd83xxx_dmux; + spec->pin_nids = stac92hd83xxx_pin_nids; +@@ -4555,6 +4661,15 @@ + stac92xx_set_config_regs(codec); + } + ++ switch (codec->vendor_id) { ++ case 0x111d7604: ++ case 0x111d7605: ++ if (spec->board_config == STAC_92HD83XXX_PWR_REF) ++ break; ++ spec->num_pwrs = 0; ++ break; ++ } ++ + err = stac92xx_parse_auto_config(codec, 0x1d, 0); + if (!err) { + if (spec->board_config < 0) { +@@ -4576,54 +4691,6 @@ + return 0; + } + +-#ifdef SND_HDA_NEEDS_RESUME +-static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr) +-{ +- struct sigmatel_spec *spec = codec->spec; +- int i; +- snd_hda_codec_write_cache(codec, codec->afg, 0, +- AC_VERB_SET_POWER_STATE, pwr); +- +- msleep(1); +- for (i = 0; i < spec->num_adcs; i++) { +- snd_hda_codec_write_cache(codec, +- spec->adc_nids[i], 0, +- AC_VERB_SET_POWER_STATE, pwr); +- } +-}; +- +-static int stac92hd71xx_resume(struct hda_codec *codec) +-{ +- stac92hd71xx_set_power_state(codec, AC_PWRST_D0); +- return stac92xx_resume(codec); +-} +- +-static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) +-{ +- struct sigmatel_spec *spec = codec->spec; +- +- stac92hd71xx_set_power_state(codec, AC_PWRST_D3); +- if (spec->eapd_mask) +- stac_gpio_set(codec, spec->gpio_mask, +- spec->gpio_dir, spec->gpio_data & +- ~spec->eapd_mask); +- return 0; +-}; +- +-#endif +- +-static struct hda_codec_ops stac92hd71bxx_patch_ops = { +- .build_controls = stac92xx_build_controls, +- .build_pcms = stac92xx_build_pcms, +- .init = stac92xx_init, +- .free = stac92xx_free, +- .unsol_event = stac92xx_unsol_event, +-#ifdef SND_HDA_NEEDS_RESUME +- .resume = stac92hd71xx_resume, +- .suspend = stac92hd71xx_suspend, +-#endif +-}; +- + static struct hda_input_mux stac92hd71bxx_dmux = { + .num_items = 4, + .items = { +@@ -4689,21 +4756,21 @@ + switch (spec->board_config) { + case STAC_HP_M4: + /* Enable VREF power saving on GPIO1 detect */ ++ err = stac_add_event(spec, codec->afg, ++ STAC_VREF_EVENT, 0x02); ++ if (err < 0) ++ return err; + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); + snd_hda_codec_write_cache(codec, codec->afg, 0, +- AC_VERB_SET_UNSOLICITED_ENABLE, +- (AC_USRSP_EN | STAC_VREF_EVENT | 0x01)); ++ AC_VERB_SET_UNSOLICITED_ENABLE, ++ AC_USRSP_EN | err); + spec->gpio_mask |= 0x02; + break; + } + if ((codec->revision_id & 0xf) == 0 || +- (codec->revision_id & 0xf) == 1) { +-#ifdef SND_HDA_NEEDS_RESUME +- codec->patch_ops = stac92hd71bxx_patch_ops; +-#endif ++ (codec->revision_id & 0xf) == 1) + spec->stream_delay = 40; /* 40 milliseconds */ +- } + + /* no output amps */ + spec->num_pwrs = 0; +@@ -4715,12 +4782,8 @@ + stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); + break; + case 0x111d7603: /* 6 Port with Analog Mixer */ +- if ((codec->revision_id & 0xf) == 1) { +-#ifdef SND_HDA_NEEDS_RESUME +- codec->patch_ops = stac92hd71bxx_patch_ops; +-#endif ++ if ((codec->revision_id & 0xf) == 1) + spec->stream_delay = 40; /* 40 milliseconds */ +- } + + /* no output amps */ + spec->num_pwrs = 0; +@@ -4763,7 +4826,7 @@ + case STAC_DELL_M4_3: + spec->num_dmics = 1; + spec->num_smuxes = 0; +- spec->num_dmuxes = 0; ++ spec->num_dmuxes = 1; + break; + default: + spec->num_dmics = STAC92HD71BXX_NUM_DMICS; +@@ -4771,9 +4834,7 @@ + spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); + }; + +- spec->multiout.num_dacs = 1; +- spec->multiout.hp_nid = 0x11; +- spec->multiout.dac_nids = stac92hd71bxx_dac_nids; ++ spec->multiout.dac_nids = spec->dac_nids; + if (spec->dinput_mux) + spec->private_dimux.num_items += + spec->num_dmics - +@@ -5097,11 +5158,14 @@ + stac92xx_set_config_reg(codec, 0x20, 0x1c410030); + + /* Enable unsol response for GPIO4/Dock HP connection */ ++ err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); ++ if (err < 0) ++ return err; + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, +- (AC_USRSP_EN | STAC_HP_EVENT)); ++ AC_USRSP_EN | err); + + spec->gpio_dir = 0x0b; + spec->eapd_mask = 0x01; +@@ -5275,7 +5339,7 @@ + + static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) + { +- if (get_hp_pin_presence(codec, 0x0a)) { ++ if (get_pin_presence(codec, 0x0a)) { + stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + } else { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update2 b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update2 new file mode 100644 index 000000000..33a1bccf7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update2 @@ -0,0 +1,58 @@ +From c50ff7c04225c945b13d410d50fde6ff6c59d7ee Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 6 Mar 2009 09:43:58 +0100 +Subject: ALSA: hda - Fix headphone-detect regression with multiple HP jacks +Patch-mainline: +References: bnc#479558, bnc#482052 + +The recent changes over the DAC detection mechanism in patch_sigmatel.c +breaks the HP detection on the machines with multiple HP jacks. +It's basically because of the workaround to support the multi-channel +output. Since the HP detection is more important feature, disable +the HP-swap workaroud temporarily. + +Reference: Novell bnc#482052 + https://bugzilla.novell.com/show_bug.cgi?id=482052 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1205,7 +1205,7 @@ static const char *slave_vols[] = { + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", +- "Headphone Playback Volume", ++ "Headphone2 Playback Volume", + "Speaker Playback Volume", + "External Speaker Playback Volume", + "Speaker2 Playback Volume", +@@ -1219,7 +1219,7 @@ static const char *slave_sws[] = { + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", +- "Headphone Playback Switch", ++ "Headphone2 Playback Switch", + "Speaker Playback Switch", + "External Speaker Playback Switch", + "Speaker2 Playback Switch", +@@ -3477,6 +3477,7 @@ static int stac92xx_parse_auto_config(st + if (! spec->autocfg.line_outs) + return 0; /* can't find valid pin config */ + ++#if 0 /* FIXME: temporarily disabled */ + /* If we have no real line-out pin and multiple hp-outs, HPs should + * be set up as multi-channel outputs. + */ +@@ -3496,6 +3497,7 @@ static int stac92xx_parse_auto_config(st + spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; + spec->autocfg.hp_outs = 0; + } ++#endif /* FIXME: temporarily disabled */ + if (spec->autocfg.mono_out_pin) { + int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & + (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update3 b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update3 new file mode 100644 index 000000000..69db2de46 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sigmatel-update3 @@ -0,0 +1,232 @@ +From dc04d1b4d2043e2fca2d94d6d5542b930f2bc5b3 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 6 Mar 2009 10:00:05 +0100 +Subject: ALSA: hda - Create output controls according to pin types for IDT/STAC +Patch-mainline: +References: bnc#479558, bnc#482052 + +Improve the parser to pick up more intuitive control names for the +outputs judging from the pin type, instead of fixed names assigned +to channels. + +Also, revive the multi-HP workaround since this change fixes the +problem with the multi-HP detection. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 141 ++++++++++++++++++++--------------------- + 1 file changed, 72 insertions(+), 69 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -2998,35 +2998,33 @@ static int add_spec_extra_dacs(struct si + return 1; + } + +-static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid) +-{ +- int i; +- +- if (spec->autocfg.line_outs != 1) +- return 0; +- if (spec->multiout.hp_nid == nid) +- return 0; +- for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) +- if (spec->multiout.extra_out_nid[i] == nid) +- return 0; +- return 1; +-} +- +-/* add playback controls from the parsed DAC table */ +-static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, +- const struct auto_pin_cfg *cfg) ++/* Create output controls ++ * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT) ++ */ ++static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, ++ const hda_nid_t *pins, ++ const hda_nid_t *dac_nids, ++ int type) + { + struct sigmatel_spec *spec = codec->spec; + static const char *chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; +- hda_nid_t nid = 0; ++ static const char *hp_pfxs[] = { ++ "Headphone", "Headphone2", "Headphone3", "Headphone4" ++ }; ++ static const char *speaker_pfxs[] = { ++ "Speaker", "External Speaker", "Speaker2", "Speaker3" ++ }; ++ hda_nid_t nid; + int i, err; + unsigned int wid_caps; + +- for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { +- nid = spec->multiout.dac_nids[i]; +- if (i == 2) { ++ for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { ++ nid = dac_nids[i]; ++ if (!nid) ++ continue; ++ if (type != AUTO_PIN_HP_OUT && i == 2) { + /* Center/LFE */ + err = create_controls(codec, "Center", nid, 1); + if (err < 0) +@@ -3047,23 +3045,43 @@ static int stac92xx_auto_create_multi_ou + } + + } else { +- const char *name = chname[i]; +- /* if it's a single DAC, assign a better name */ +- if (!i && is_unique_dac(spec, nid)) { +- switch (cfg->line_out_type) { +- case AUTO_PIN_HP_OUT: +- name = "Headphone"; +- break; +- case AUTO_PIN_SPEAKER_OUT: +- name = "Speaker"; +- break; +- } ++ const char *name; ++ switch (type) { ++ case AUTO_PIN_HP_OUT: ++ name = hp_pfxs[i]; ++ break; ++ case AUTO_PIN_SPEAKER_OUT: ++ name = speaker_pfxs[i]; ++ break; ++ default: ++ name = chname[i]; ++ break; + } + err = create_controls(codec, name, nid, 3); + if (err < 0) + return err; ++ if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { ++ wid_caps = get_wcaps(codec, pins[i]); ++ if (wid_caps & AC_WCAP_UNSOL_CAP) ++ spec->hp_detect = 1; ++ } + } + } ++ return 0; ++} ++ ++/* add playback controls from the parsed DAC table */ ++static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, ++ const struct auto_pin_cfg *cfg) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int err; ++ ++ err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, ++ spec->multiout.dac_nids, ++ cfg->line_out_type); ++ if (err < 0) ++ return err; + + if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { + err = stac92xx_add_control(spec, +@@ -3098,40 +3116,18 @@ static int stac92xx_auto_create_hp_ctls( + struct auto_pin_cfg *cfg) + { + struct sigmatel_spec *spec = codec->spec; +- hda_nid_t nid; +- int i, err, nums; ++ int err; ++ ++ err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins, ++ spec->hp_dacs, AUTO_PIN_HP_OUT); ++ if (err < 0) ++ return err; ++ ++ err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, ++ spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT); ++ if (err < 0) ++ return err; + +- nums = 0; +- for (i = 0; i < cfg->hp_outs; i++) { +- static const char *pfxs[] = { +- "Headphone", "Headphone2", "Headphone3", +- }; +- unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); +- if (wid_caps & AC_WCAP_UNSOL_CAP) +- spec->hp_detect = 1; +- if (nums >= ARRAY_SIZE(pfxs)) +- continue; +- nid = spec->hp_dacs[i]; +- if (!nid) +- continue; +- err = create_controls(codec, pfxs[nums++], nid, 3); +- if (err < 0) +- return err; +- } +- nums = 0; +- for (i = 0; i < cfg->speaker_outs; i++) { +- static const char *pfxs[] = { +- "Speaker", "External Speaker", "Speaker2", +- }; +- if (nums >= ARRAY_SIZE(pfxs)) +- continue; +- nid = spec->speaker_dacs[i]; +- if (!nid) +- continue; +- err = create_controls(codec, pfxs[nums++], nid, 3); +- if (err < 0) +- return err; +- } + return 0; + } + +@@ -3468,6 +3464,7 @@ static void stac92xx_auto_init_hp_out(st + static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) + { + struct sigmatel_spec *spec = codec->spec; ++ int hp_swap = 0; + int err; + + if ((err = snd_hda_parse_pin_def_config(codec, +@@ -3477,7 +3474,6 @@ static int stac92xx_parse_auto_config(st + if (! spec->autocfg.line_outs) + return 0; /* can't find valid pin config */ + +-#if 0 /* FIXME: temporarily disabled */ + /* If we have no real line-out pin and multiple hp-outs, HPs should + * be set up as multi-channel outputs. + */ +@@ -3496,8 +3492,8 @@ static int stac92xx_parse_auto_config(st + spec->autocfg.line_outs = spec->autocfg.hp_outs; + spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; + spec->autocfg.hp_outs = 0; ++ hp_swap = 1; + } +-#endif /* FIXME: temporarily disabled */ + if (spec->autocfg.mono_out_pin) { + int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & + (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); +@@ -3590,12 +3586,19 @@ static int stac92xx_parse_auto_config(st + #endif + + err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); +- + if (err < 0) + return err; + +- err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); ++ /* All output parsing done, now restore the swapped hp pins */ ++ if (hp_swap) { ++ memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, ++ sizeof(spec->autocfg.hp_pins)); ++ spec->autocfg.hp_outs = spec->autocfg.line_outs; ++ spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; ++ spec->autocfg.line_outs = 0; ++ } + ++ err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-single-cmd-concurrent-access b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-single-cmd-concurrent-access new file mode 100644 index 000000000..da2ca95b6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-single-cmd-concurrent-access @@ -0,0 +1,55 @@ +From: Takashi Iwai +Subject: ALSA: hda - Allow concurrent RIRB access in single_cmd mode +Patch-mainline: +References: bnc#502903 + +In the single_cmd mode, the current driver code doesn't do any update +for RIRB just for any safety reason. But, actually the RIRB and +single_cmd mode don't conflict. Unsolicited events can be delivered +even while using the single_cmd mode. + +This patch allows the handling of unsolicited events with single_cmd +mode, just always checking RIRB independent from single_cmd flag. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -868,8 +868,7 @@ static void azx_init_chip(struct azx *ch + azx_int_enable(chip); + + /* initialize the codec command I/O */ +- if (!chip->single_cmd) +- azx_init_cmd_io(chip); ++ azx_init_cmd_io(chip); + + /* program the position buffer */ + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); +@@ -989,7 +988,7 @@ static irqreturn_t azx_interrupt(int irq + /* clear rirb int */ + status = azx_readb(chip, RIRBSTS); + if (status & RIRB_INT_MASK) { +- if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) ++ if (status & RIRB_INT_RESPONSE) + azx_update_rirb(chip); + azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); + } +@@ -2272,11 +2271,9 @@ static int __devinit azx_create(struct s + goto errout; + } + /* allocate CORB/RIRB */ +- if (!chip->single_cmd) { +- err = azx_alloc_cmd_io(chip); +- if (err < 0) +- goto errout; +- } ++ err = azx_alloc_cmd_io(chip); ++ if (err < 0) ++ goto errout; + + /* initialize streams */ + azx_init_stream(chip); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-single-cmd-sync-write b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-single-cmd-sync-write new file mode 100644 index 000000000..95fb35682 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-single-cmd-sync-write @@ -0,0 +1,75 @@ +From: Takashi Iwai +Subject: ALSA: hda - Always sync writes in single_cmd mode +Patch-mainline: +References: bnc#502903 + +In the single_cmd mode, the hardware cannot store the multiple replies +like on RIRB, thus each verb has to sync and wait for the response no +matter whether the return value is needed or not. Otherwise it may +result in a wrong return value from the previous verb. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_intel.c | 36 +++++++++++++++++++++++------------- + 1 file changed, 23 insertions(+), 13 deletions(-) + +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -661,6 +661,27 @@ + * I left the codes, however, for debugging/testing purposes. + */ + ++/* receive a response */ ++static int azx_single_wait_for_response(struct azx *chip) ++{ ++ int timeout = 50; ++ ++ while (timeout--) { ++ /* check IRV busy bit */ ++ if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { ++ /* reuse rirb.res as the response return value */ ++ chip->rirb.res = azx_readl(chip, IR); ++ return 0; ++ } ++ udelay(1); ++ } ++ if (printk_ratelimit()) ++ snd_printd(SFX "get_response timeout: IRS=0x%x\n", ++ azx_readw(chip, IRS)); ++ chip->rirb.res = -1; ++ return -EIO; ++} ++ + /* send a command */ + static int azx_single_send_cmd(struct hda_bus *bus, u32 val) + { +@@ -676,7 +697,7 @@ + azx_writel(chip, IC, val); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_BUSY); +- return 0; ++ return azx_single_wait_for_response(chip); + } + udelay(1); + } +@@ -690,18 +711,7 @@ + static unsigned int azx_single_get_response(struct hda_bus *bus) + { + struct azx *chip = bus->private_data; +- int timeout = 50; +- +- while (timeout--) { +- /* check IRV busy bit */ +- if (azx_readw(chip, IRS) & ICH6_IRS_VALID) +- return azx_readl(chip, IR); +- udelay(1); +- } +- if (printk_ratelimit()) +- snd_printd(SFX "get_response timeout: IRS=0x%x\n", +- azx_readw(chip, IRS)); +- return (unsigned int)-1; ++ return chip->rirb.res; + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-snd-array b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-snd-array new file mode 100644 index 000000000..53615e607 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-snd-array @@ -0,0 +1,100 @@ +From: Takashi Iwai +Subject: ALSA: Backport snd_array_*() for HD-audio driver +Patch-mainline: +References: bnc#511306 + +Backport snd_array_*() from the recent kernel to update the +HD-audio driver code. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 37 +++++++++++++++++++++++++++++++++++++ + sound/pci/hda/hda_codec.h | 30 ++++++++++++++++++++++++++++++ + 2 files changed, 67 insertions(+) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -3366,6 +3366,43 @@ + #endif + + /* ++ * generic arrays ++ */ ++ ++/* get a new element from the given array ++ * if it exceeds the pre-allocated array size, re-allocate the array ++ */ ++void *snd_array_new(struct snd_array *array) ++{ ++ if (array->used >= array->alloced) { ++ int num = array->alloced + array->alloc_align; ++ void *nlist; ++ if (num >= 4096) ++ return NULL; ++ nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); ++ if (!nlist) ++ return NULL; ++ if (array->list) { ++ memcpy(nlist, array->list, ++ array->elem_size * array->alloced); ++ kfree(array->list); ++ } ++ array->list = nlist; ++ array->alloced = num; ++ } ++ return snd_array_elem(array, array->used++); ++} ++ ++/* free the given array elements */ ++void snd_array_free(struct snd_array *array) ++{ ++ kfree(array->list); ++ array->used = 0; ++ array->alloced = 0; ++ array->list = NULL; ++} ++ ++/* + * used by hda_proc.c and hda_eld.c + */ + void snd_print_pcm_rates(int pcm, char *buf, int buflen) +--- a/sound/pci/hda/hda_codec.h ++++ b/sound/pci/hda/hda_codec.h +@@ -520,6 +520,36 @@ + #define HDA_MAX_CODEC_ADDRESS 0x0f + + /* ++ * generic arrays ++ */ ++struct snd_array { ++ unsigned int used; ++ unsigned int alloced; ++ unsigned int elem_size; ++ unsigned int alloc_align; ++ void *list; ++}; ++ ++void *snd_array_new(struct snd_array *array); ++void snd_array_free(struct snd_array *array); ++static inline void snd_array_init(struct snd_array *array, unsigned int size, ++ unsigned int align) ++{ ++ array->elem_size = size; ++ array->alloc_align = align; ++} ++ ++static inline void *snd_array_elem(struct snd_array *array, unsigned int idx) ++{ ++ return array->list + idx * array->elem_size; ++} ++ ++static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) ++{ ++ return (unsigned long)(ptr - array->list) / array->elem_size; ++} ++ ++/* + * Structures + */ + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-stac-automic b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-stac-automic new file mode 100644 index 000000000..a2cd15c5e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-stac-automic @@ -0,0 +1,3117 @@ +From: Takashi Iwai +Subject: ALSA: Update STAC/IDT codec support (auto-mic, etc) +Patch-mainline: +References: bnc#511306, bnc#520975 + +Backport the latest STAC/IDT codec driver to support the automatic +mic selection and the proper fix for docking station, etc for HP +and Dell laptops/desktops. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 1791 +++++++++++++++++++++++++---------------- + 1 file changed, 1135 insertions(+), 656 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -35,14 +35,17 @@ + #include "hda_patch.h" + #include "hda_beep.h" + +-#define NUM_CONTROL_ALLOC 32 +- +-#define STAC_VREF_EVENT 0x00 +-#define STAC_INSERT_EVENT 0x10 +-#define STAC_PWR_EVENT 0x20 +-#define STAC_HP_EVENT 0x30 ++enum { ++ STAC_VREF_EVENT = 1, ++ STAC_INSERT_EVENT, ++ STAC_PWR_EVENT, ++ STAC_HP_EVENT, ++ STAC_LO_EVENT, ++ STAC_MIC_EVENT, ++}; + + enum { ++ STAC_AUTO, + STAC_REF, + STAC_9200_OQO, + STAC_9200_DELL_D21, +@@ -62,6 +65,7 @@ + }; + + enum { ++ STAC_9205_AUTO, + STAC_9205_REF, + STAC_9205_DELL_M42, + STAC_9205_DELL_M43, +@@ -71,6 +75,7 @@ + }; + + enum { ++ STAC_92HD73XX_AUTO, + STAC_92HD73XX_NO_JD, /* no jack-detection */ + STAC_92HD73XX_REF, + STAC_DELL_M6_AMIC, +@@ -81,22 +86,28 @@ + }; + + enum { ++ STAC_92HD83XXX_AUTO, + STAC_92HD83XXX_REF, + STAC_92HD83XXX_PWR_REF, ++ STAC_DELL_S14, + STAC_92HD83XXX_MODELS + }; + + enum { ++ STAC_92HD71BXX_AUTO, + STAC_92HD71BXX_REF, + STAC_DELL_M4_1, + STAC_DELL_M4_2, + STAC_DELL_M4_3, + STAC_HP_M4, + STAC_HP_DV5, ++ STAC_HP_HDX, ++ STAC_HP_DV4_1222NR, + STAC_92HD71BXX_MODELS + }; + + enum { ++ STAC_925x_AUTO, + STAC_925x_REF, + STAC_M1, + STAC_M1_2, +@@ -109,6 +120,7 @@ + }; + + enum { ++ STAC_922X_AUTO, + STAC_D945_REF, + STAC_D945GTP3, + STAC_D945GTP5, +@@ -136,10 +148,12 @@ + }; + + enum { ++ STAC_927X_AUTO, + STAC_D965_REF_NO_JD, /* no jack-detection */ + STAC_D965_REF, + STAC_D965_3ST, + STAC_D965_5ST, ++ STAC_D965_5ST_NO_FP, + STAC_DELL_3ST, + STAC_DELL_BIOS, + STAC_927X_MODELS +@@ -152,6 +166,18 @@ + int data; + }; + ++struct sigmatel_jack { ++ hda_nid_t nid; ++ int type; ++ struct snd_jack *jack; ++}; ++ ++struct sigmatel_mic_route { ++ hda_nid_t pin; ++ unsigned char mux_idx; ++ unsigned char dmux_idx; ++}; ++ + struct sigmatel_spec { + struct snd_kcontrol_new *mixers[4]; + unsigned int num_mixers; +@@ -163,6 +189,7 @@ + unsigned int hp_detect: 1; + unsigned int spdif_mute: 1; + unsigned int check_volume_offset:1; ++ unsigned int auto_mic:1; + + /* gpio lines */ + unsigned int eapd_mask; +@@ -170,23 +197,22 @@ + unsigned int gpio_dir; + unsigned int gpio_data; + unsigned int gpio_mute; ++ unsigned int gpio_led; + + /* stream */ + unsigned int stream_delay; + +- /* analog loopback */ +- unsigned char aloopback_mask; +- unsigned char aloopback_shift; +- + /* power management */ + unsigned int num_pwrs; + unsigned int *pwr_mapping; + hda_nid_t *pwr_nids; + hda_nid_t *dac_list; + ++ /* jack detection */ ++ struct snd_array jacks; ++ + /* events */ +- int num_events; +- struct sigmatel_event events[32]; ++ struct snd_array events; + + /* playback */ + struct hda_input_mux *mono_mux; +@@ -210,6 +236,15 @@ + unsigned int num_dmuxes; + hda_nid_t *smux_nids; + unsigned int num_smuxes; ++ unsigned int num_analog_muxes; ++ ++ unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ ++ unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ ++ unsigned int num_caps; /* number of capture volume/switch elements */ ++ ++ struct sigmatel_mic_route ext_mic; ++ struct sigmatel_mic_route int_mic; ++ + const char **spdif_labels; + + hda_nid_t dig_in_nid; +@@ -245,14 +280,12 @@ + hda_nid_t line_switch; /* shared line-in for input and output */ + hda_nid_t mic_switch; /* shared mic-in for input and output */ + hda_nid_t hp_switch; /* NID of HP as line-out */ +- unsigned int aloopback; + + struct hda_pcm pcm_rec[2]; /* PCM information */ + + /* dynamic controls and input_mux */ + struct auto_pin_cfg autocfg; +- unsigned int num_kctl_alloc, num_kctl_used; +- struct snd_kcontrol_new *kctl_alloc; ++ struct snd_array kctls; + struct hda_input_mux private_dimux; + struct hda_input_mux private_imux; + struct hda_input_mux private_smux; +@@ -309,6 +342,13 @@ + 0x22, 0x23, + }; + ++#define STAC92HD73XX_NUM_CAPS 2 ++static unsigned long stac92hd73xx_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), ++}; ++#define stac92hd73xx_capsws stac92hd73xx_capvols ++ + #define STAC92HD83XXX_NUM_DMICS 2 + static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { + 0x11, 0x12, 0 +@@ -340,6 +380,13 @@ + 0xc, + }; + ++#define STAC92HD83XXX_NUM_CAPS 2 ++static unsigned long stac92hd83xxx_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT), ++}; ++#define stac92hd83xxx_capsws stac92hd83xxx_capvols ++ + static hda_nid_t stac92hd71bxx_pwr_nids[3] = { + 0x0a, 0x0d, 0x0f + }; +@@ -369,6 +416,13 @@ + 0x22, 0 + }; + ++#define STAC92HD71BXX_NUM_CAPS 2 ++static unsigned long stac92hd71bxx_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), ++}; ++#define stac92hd71bxx_capsws stac92hd71bxx_capvols ++ + static hda_nid_t stac925x_adc_nids[1] = { + 0x03, + }; +@@ -390,6 +444,13 @@ + 0x14, + }; + ++static unsigned long stac925x_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), ++}; ++static unsigned long stac925x_capsws[] = { ++ HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), ++}; ++ + static hda_nid_t stac922x_adc_nids[2] = { + 0x06, 0x07, + }; +@@ -398,6 +459,17 @@ + 0x12, 0x13, + }; + ++#define STAC922X_NUM_CAPS 2 ++static unsigned long stac922x_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT), ++ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), ++}; ++#define stac922x_capsws stac922x_capvols ++ ++static hda_nid_t stac927x_slave_dig_outs[2] = { ++ 0x1f, 0, ++}; ++ + static hda_nid_t stac927x_adc_nids[3] = { + 0x07, 0x08, 0x09 + }; +@@ -423,6 +495,18 @@ + 0x13, 0x14, 0 + }; + ++#define STAC927X_NUM_CAPS 3 ++static unsigned long stac927x_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), ++ HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT), ++ HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT), ++}; ++static unsigned long stac927x_capsws[] = { ++ HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), ++}; ++ + static const char *stac927x_spdif_labels[5] = { + "Digital Playback", "ADAT", "Analog Mux 1", + "Analog Mux 2", "Analog Mux 3" +@@ -449,6 +533,16 @@ + 0x17, 0x18, 0 + }; + ++#define STAC9205_NUM_CAPS 2 ++static unsigned long stac9205_capvols[] = { ++ HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT), ++ HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT), ++}; ++static unsigned long stac9205_capsws[] = { ++ HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), ++ HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT), ++}; ++ + static hda_nid_t stac9200_pin_nids[8] = { + 0x08, 0x09, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, +@@ -470,15 +564,21 @@ + 0x14, 0x22, 0x23 + }; + +-static hda_nid_t stac92hd83xxx_pin_nids[14] = { ++static hda_nid_t stac92hd83xxx_pin_nids[10] = { + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, +- 0x0f, 0x10, 0x11, 0x12, 0x13, +- 0x1d, 0x1e, 0x1f, 0x20 ++ 0x0f, 0x10, 0x11, 0x1f, 0x20, ++}; ++ ++#define STAC92HD71BXX_NUM_PINS 13 ++static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { ++ 0x0a, 0x0b, 0x0c, 0x0d, 0x00, ++ 0x00, 0x14, 0x18, 0x19, 0x1e, ++ 0x1f, 0x20, 0x27 + }; +-static hda_nid_t stac92hd71bxx_pin_nids[11] = { ++static hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x14, 0x18, 0x19, 0x1e, +- 0x1f, ++ 0x1f, 0x20, 0x27 + }; + + static hda_nid_t stac927x_pin_nids[14] = { +@@ -521,36 +621,6 @@ + return snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + } + +-static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_info *uinfo) +-{ +- struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +- struct sigmatel_spec *spec = codec->spec; +- return snd_hda_input_mux_info(spec->dinput_mux, uinfo); +-} +- +-static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +- struct sigmatel_spec *spec = codec->spec; +- unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); +- +- ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx]; +- return 0; +-} +- +-static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +- struct sigmatel_spec *spec = codec->spec; +- unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); +- +- return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, +- spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]); +-} +- + static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) + { +@@ -601,6 +671,40 @@ + return 0; + } + ++static unsigned int stac92xx_vref_set(struct hda_codec *codec, ++ hda_nid_t nid, unsigned int new_vref) ++{ ++ int error; ++ unsigned int pincfg; ++ pincfg = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_PIN_WIDGET_CONTROL, 0); ++ ++ pincfg &= 0xff; ++ pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); ++ pincfg |= new_vref; ++ ++ if (new_vref == AC_PINCTL_VREF_HIZ) ++ pincfg |= AC_PINCTL_OUT_EN; ++ else ++ pincfg |= AC_PINCTL_IN_EN; ++ ++ error = snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg); ++ if (error < 0) ++ return error; ++ else ++ return 1; ++} ++ ++static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) ++{ ++ unsigned int vref; ++ vref = snd_hda_codec_read(codec, nid, 0, ++ AC_VERB_GET_PIN_WIDGET_CONTROL, 0); ++ vref &= AC_PINCTL_VREFEN; ++ return vref; ++} ++ + static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) + { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +@@ -623,9 +727,35 @@ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ++ const struct hda_input_mux *imux = spec->input_mux; ++ unsigned int idx, prev_idx; + +- return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, +- spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); ++ idx = ucontrol->value.enumerated.item[0]; ++ if (idx >= imux->num_items) ++ idx = imux->num_items - 1; ++ prev_idx = spec->cur_mux[adc_idx]; ++ if (prev_idx == idx) ++ return 0; ++ if (idx < spec->num_analog_muxes) { ++ snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, ++ AC_VERB_SET_CONNECT_SEL, ++ imux->items[idx].index); ++ if (prev_idx >= spec->num_analog_muxes) { ++ imux = spec->dinput_mux; ++ /* 0 = analog */ ++ snd_hda_codec_write_cache(codec, ++ spec->dmux_nids[adc_idx], 0, ++ AC_VERB_SET_CONNECT_SEL, ++ imux->items[0].index); ++ } ++ } else { ++ imux = spec->dinput_mux; ++ snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, ++ AC_VERB_SET_CONNECT_SEL, ++ imux->items[idx - 1].index); ++ } ++ spec->cur_mux[adc_idx] = idx; ++ return 1; + } + + static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, +@@ -691,60 +821,6 @@ + 0, &spec->cur_amux); + } + +-#define stac92xx_aloopback_info snd_ctl_boolean_mono_info +- +-static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); +- struct sigmatel_spec *spec = codec->spec; +- +- ucontrol->value.integer.value[0] = !!(spec->aloopback & +- (spec->aloopback_mask << idx)); +- return 0; +-} +- +-static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct hda_codec *codec = snd_kcontrol_chip(kcontrol); +- struct sigmatel_spec *spec = codec->spec; +- unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); +- unsigned int dac_mode; +- unsigned int val, idx_val; +- +- idx_val = spec->aloopback_mask << idx; +- if (ucontrol->value.integer.value[0]) +- val = spec->aloopback | idx_val; +- else +- val = spec->aloopback & ~idx_val; +- if (spec->aloopback == val) +- return 0; +- +- spec->aloopback = val; +- +- /* Only return the bits defined by the shift value of the +- * first two bytes of the mask +- */ +- dac_mode = snd_hda_codec_read(codec, codec->afg, 0, +- kcontrol->private_value & 0xFFFF, 0x0); +- dac_mode >>= spec->aloopback_shift; +- +- if (spec->aloopback & idx_val) { +- snd_hda_power_up(codec); +- dac_mode |= idx_val; +- } else { +- snd_hda_power_down(codec); +- dac_mode &= ~idx_val; +- } +- +- snd_hda_codec_write_cache(codec, codec->afg, 0, +- kcontrol->private_value >> 16, dac_mode); +- +- return 1; +-} +- + static struct hda_verb stac9200_core_init[] = { + /* set dac0mux for dac converter */ + { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, +@@ -840,9 +916,9 @@ + }; + + static struct hda_verb stac92hd83xxx_core_init[] = { +- { 0xa, AC_VERB_SET_CONNECT_SEL, 0x0}, +- { 0xb, AC_VERB_SET_CONNECT_SEL, 0x0}, +- { 0xd, AC_VERB_SET_CONNECT_SEL, 0x1}, ++ { 0xa, AC_VERB_SET_CONNECT_SEL, 0x1}, ++ { 0xb, AC_VERB_SET_CONNECT_SEL, 0x1}, ++ { 0xd, AC_VERB_SET_CONNECT_SEL, 0x0}, + + /* power state controls amps */ + { 0x01, AC_VERB_SET_EAPD, 1 << 2}, +@@ -852,26 +928,12 @@ + static struct hda_verb stac92hd71bxx_core_init[] = { + /* set master volume and direct control */ + { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ +- { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {} + }; + +-#define HD_DISABLE_PORTF 2 +-static struct hda_verb stac92hd71bxx_analog_core_init[] = { +- /* start of config #1 */ +- +- /* connect port 0f to audio mixer */ +- { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, +- /* unmute right and left channels for node 0x0f */ ++static struct hda_verb stac92hd71bxx_unmute_core_init[] = { ++ /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */ + { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, +- /* start of config #2 */ +- +- /* set master volume and direct control */ +- { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, +- /* unmute right and left channels for nodes 0x0a, 0xd */ + { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {} +@@ -952,31 +1014,20 @@ + .private_value = HDA_COMPOSE_AMP_VAL(nid, chs, idx, dir) \ + } + +-#define STAC_INPUT_SOURCE(cnt) \ +- { \ +- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ +- .name = "Input Source", \ +- .count = cnt, \ +- .info = stac92xx_mux_enum_info, \ +- .get = stac92xx_mux_enum_get, \ +- .put = stac92xx_mux_enum_put, \ +- } +- +-#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ ++#define DC_BIAS(xname, idx, nid) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ +- .name = "Analog Loopback", \ +- .count = cnt, \ +- .info = stac92xx_aloopback_info, \ +- .get = stac92xx_aloopback_get, \ +- .put = stac92xx_aloopback_put, \ +- .private_value = verb_read | (verb_write << 16), \ ++ .name = xname, \ ++ .index = idx, \ ++ .info = stac92xx_dc_bias_info, \ ++ .get = stac92xx_dc_bias_get, \ ++ .put = stac92xx_dc_bias_put, \ ++ .private_value = nid, \ + } + + static struct snd_kcontrol_new stac9200_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), +- STAC_INPUT_SOURCE(1), + HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), + { } /* end */ +@@ -1001,26 +1052,10 @@ + HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), + +- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), +- + { } /* end */ + }; + + static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = { +- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), +- + HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), + +@@ -1039,14 +1074,6 @@ + }; + + static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { +- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), +- + HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), + +@@ -1066,12 +1093,6 @@ + + + static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT), +- + HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), + +@@ -1091,104 +1112,12 @@ + { } /* end */ + }; + +-static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { +- STAC_INPUT_SOURCE(2), +- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), +- /* analog pc-beep replaced with digital beep support */ +- /* +- HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT), +- HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), +- */ +- +- HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT), +- HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT), +- +- HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT), +- HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT), +- +- HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT), +- HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT), +- +- HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT), +- HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT), +- { } /* end */ +-}; +- +-static struct snd_kcontrol_new stac92hd71bxx_mixer[] = { +- STAC_INPUT_SOURCE(2), +- STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), +- { } /* end */ +-}; +- + static struct snd_kcontrol_new stac925x_mixer[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT), +- STAC_INPUT_SOURCE(1), +- HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), +- HDA_CODEC_MUTE("Capture Switch", 0x14, 0, HDA_OUTPUT), +- { } /* end */ +-}; +- +-static struct snd_kcontrol_new stac9205_mixer[] = { +- STAC_INPUT_SOURCE(2), +- STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), +- { } /* end */ +-}; +- +-/* This needs to be generated dynamically based on sequence */ +-static struct snd_kcontrol_new stac922x_mixer[] = { +- STAC_INPUT_SOURCE(2), +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), +- { } /* end */ +-}; +- +- +-static struct snd_kcontrol_new stac927x_mixer[] = { +- STAC_INPUT_SOURCE(3), +- STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), +- +- HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), +- HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), + { } /* end */ + }; + +-static struct snd_kcontrol_new stac_dmux_mixer = { +- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, +- .name = "Digital Input Source", +- /* count set later */ +- .info = stac92xx_dmux_enum_info, +- .get = stac92xx_dmux_enum_get, +- .put = stac92xx_dmux_enum_put, +-}; +- + static struct snd_kcontrol_new stac_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", +@@ -1205,10 +1134,7 @@ + "LFE Playback Volume", + "Side Playback Volume", + "Headphone Playback Volume", +- "Headphone2 Playback Volume", + "Speaker Playback Volume", +- "External Speaker Playback Volume", +- "Speaker2 Playback Volume", + NULL + }; + +@@ -1219,33 +1145,27 @@ + "LFE Playback Switch", + "Side Playback Switch", + "Headphone Playback Switch", +- "Headphone2 Playback Switch", + "Speaker Playback Switch", +- "External Speaker Playback Switch", +- "Speaker2 Playback Switch", + "IEC958 Playback Switch", + NULL + }; + ++static void stac92xx_free_kctls(struct hda_codec *codec); ++ + static int stac92xx_build_controls(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; + int err; + int i; + +- err = snd_hda_add_new_ctls(codec, spec->mixer); +- if (err < 0) +- return err; +- +- for (i = 0; i < spec->num_mixers; i++) { +- err = snd_hda_add_new_ctls(codec, spec->mixers[i]); ++ if (spec->mixer) { ++ err = snd_hda_add_new_ctls(codec, spec->mixer); + if (err < 0) + return err; + } +- if (spec->num_dmuxes > 0) { +- stac_dmux_mixer.count = spec->num_dmuxes; +- err = snd_ctl_add(codec->bus->card, +- snd_ctl_new1(&stac_dmux_mixer, codec)); ++ ++ for (i = 0; i < spec->num_mixers; i++) { ++ err = snd_hda_add_new_ctls(codec, spec->mixers[i]); + if (err < 0) + return err; + } +@@ -1301,6 +1221,8 @@ + return err; + } + ++ stac92xx_free_kctls(codec); /* no longer needed */ ++ + return 0; + } + +@@ -1454,6 +1376,7 @@ + }; + + static const char *stac9200_models[STAC_9200_MODELS] = { ++ [STAC_AUTO] = "auto", + [STAC_REF] = "ref", + [STAC_9200_OQO] = "oqo", + [STAC_9200_DELL_D21] = "dell-d21", +@@ -1471,10 +1394,16 @@ + [STAC_9200_PANASONIC] = "panasonic", + }; + ++#ifndef PCI_VENDOR_ID_DFI ++#define PCI_VENDOR_ID_DFI 0x106e ++#endif ++ + static struct snd_pci_quirk stac9200_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_REF), + /* Dell laptops have BIOS problem */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8, + "unknown Dell", STAC_9200_DELL_D21), +@@ -1597,6 +1526,7 @@ + }; + + static const char *stac925x_models[STAC_925x_MODELS] = { ++ [STAC_925x_AUTO] = "auto", + [STAC_REF] = "ref", + [STAC_M1] = "m1", + [STAC_M1_2] = "m1-2", +@@ -1624,6 +1554,7 @@ + static struct snd_pci_quirk stac925x_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), + + /* Default table for unknown ID */ +@@ -1655,6 +1586,7 @@ + }; + + static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { ++ [STAC_92HD73XX_AUTO] = "auto", + [STAC_92HD73XX_NO_JD] = "no-jd", + [STAC_92HD73XX_REF] = "ref", + [STAC_DELL_M6_AMIC] = "dell-m6-amic", +@@ -1667,6 +1599,8 @@ + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD73XX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_92HD73XX_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254, + "Dell Studio 1535", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255, +@@ -1687,55 +1621,73 @@ + "Dell Studio 1537", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0, + "Dell Studio 17", STAC_DELL_M6_DMIC), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be, ++ "Dell Studio 1555", STAC_DELL_M6_DMIC), + {} /* terminator */ + }; + +-static unsigned int ref92hd83xxx_pin_configs[14] = { ++static unsigned int ref92hd83xxx_pin_configs[10] = { + 0x02214030, 0x02211010, 0x02a19020, 0x02170130, + 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, +- 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x40f000f0, + 0x01451160, 0x98560170, + }; + ++static unsigned int dell_s14_pin_configs[10] = { ++ 0x02214030, 0x02211010, 0x02a19020, 0x01014050, ++ 0x40f000f0, 0x01819040, 0x40f000f0, 0x90a60160, ++ 0x40f000f0, 0x40f000f0, ++}; ++ + static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { + [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, + [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, ++ [STAC_DELL_S14] = dell_s14_pin_configs, + }; + + static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { ++ [STAC_92HD83XXX_AUTO] = "auto", + [STAC_92HD83XXX_REF] = "ref", + [STAC_92HD83XXX_PWR_REF] = "mic-ref", ++ [STAC_DELL_S14] = "dell-s14", + }; + + static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD83XXX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_92HD83XXX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, ++ "unknown Dell", STAC_DELL_S14), + {} /* terminator */ + }; + +-static unsigned int ref92hd71bxx_pin_configs[11] = { ++static unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { + 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, + 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, +- 0x90a000f0, 0x01452050, 0x01452050, ++ 0x90a000f0, 0x01452050, 0x01452050, 0x00000000, ++ 0x00000000 + }; + +-static unsigned int dell_m4_1_pin_configs[11] = { ++static unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { + 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, + 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, +- 0x40f000f0, 0x4f0000f0, 0x4f0000f0, ++ 0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000, ++ 0x00000000 + }; + +-static unsigned int dell_m4_2_pin_configs[11] = { ++static unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { + 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, + 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, +- 0x40f000f0, 0x044413b0, 0x044413b0, ++ 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, ++ 0x00000000 + }; + +-static unsigned int dell_m4_3_pin_configs[11] = { ++static unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { + 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, + 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, +- 0x40f000f0, 0x044413b0, 0x044413b0, ++ 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, ++ 0x00000000 + }; + + static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { +@@ -1745,39 +1697,42 @@ + [STAC_DELL_M4_3] = dell_m4_3_pin_configs, + [STAC_HP_M4] = NULL, + [STAC_HP_DV5] = NULL, ++ [STAC_HP_HDX] = NULL, ++ [STAC_HP_DV4_1222NR] = NULL, + }; + + static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { ++ [STAC_92HD71BXX_AUTO] = "auto", + [STAC_92HD71BXX_REF] = "ref", + [STAC_DELL_M4_1] = "dell-m4-1", + [STAC_DELL_M4_2] = "dell-m4-2", + [STAC_DELL_M4_3] = "dell-m4-3", + [STAC_HP_M4] = "hp-m4", + [STAC_HP_DV5] = "hp-dv5", ++ [STAC_HP_HDX] = "hp-hdx", ++ [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", + }; + + static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_92HD71BXX_REF), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x308c, +- "HP", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x308d, ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_92HD71BXX_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, ++ "HP dv4-1222nr", STAC_HP_DV4_1222NR), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, + "HP", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2, +- "HP dv5", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, +- "HP dv7", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7, +- "HP dv4", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, +- "HP dv7", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600, +- "HP dv5", STAC_HP_DV5), +- SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603, +- "HP dv5", STAC_HP_DV5), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, ++ "HP dv4-7", STAC_HP_DV5), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600, ++ "HP dv4-7", STAC_HP_DV5), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610, ++ "HP HDX", STAC_HP_HDX), /* HDX18 */ + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, +- "unknown HP", STAC_HP_M4), ++ "HP mini 1000", STAC_HP_M4), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b, ++ "HP HDX", STAC_HP_HDX), /* HDX16 */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, + "unknown Dell", STAC_DELL_M4_1), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, +@@ -1929,6 +1884,7 @@ + }; + + static const char *stac922x_models[STAC_922X_MODELS] = { ++ [STAC_922X_AUTO] = "auto", + [STAC_D945_REF] = "ref", + [STAC_D945GTP5] = "5stack", + [STAC_D945GTP3] = "3stack", +@@ -1956,6 +1912,8 @@ + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_D945_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_D945_REF), + /* Intel 945G based systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101, + "Intel D945G", STAC_D945GTP3), +@@ -2036,31 +1994,7 @@ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, + "Dell XPS M1210", STAC_922X_DELL_M82), + /* ECS/PC Chips boards */ +- SND_PCI_QUIRK(0x1019, 0x2144, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2608, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2633, +- "ECS/PC chips P17G/1333", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2811, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2812, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2813, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2814, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2815, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2816, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2817, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2818, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2819, +- "ECS/PC chips", STAC_ECS_202), +- SND_PCI_QUIRK(0x1019, 0x2820, ++ SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000, + "ECS/PC chips", STAC_ECS_202), + {} /* terminator */ + }; +@@ -2086,6 +2020,13 @@ + 0x40000100, 0x40000100 + }; + ++static unsigned int d965_5st_no_fp_pin_configs[14] = { ++ 0x40000100, 0x40000100, 0x0181304e, 0x01014010, ++ 0x01a19040, 0x01011012, 0x01016011, 0x40000100, ++ 0x40000100, 0x40000100, 0x40000100, 0x01442070, ++ 0x40000100, 0x40000100 ++}; ++ + static unsigned int dell_3st_pin_configs[14] = { + 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, + 0x01111212, 0x01116211, 0x01813050, 0x01112214, +@@ -2098,15 +2039,18 @@ + [STAC_D965_REF] = ref927x_pin_configs, + [STAC_D965_3ST] = d965_3st_pin_configs, + [STAC_D965_5ST] = d965_5st_pin_configs, ++ [STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs, + [STAC_DELL_3ST] = dell_3st_pin_configs, + [STAC_DELL_BIOS] = NULL, + }; + + static const char *stac927x_models[STAC_927X_MODELS] = { ++ [STAC_927X_AUTO] = "auto", + [STAC_D965_REF_NO_JD] = "ref-no-jd", + [STAC_D965_REF] = "ref", + [STAC_D965_3ST] = "3stack", + [STAC_D965_5ST] = "5stack", ++ [STAC_D965_5ST_NO_FP] = "5stack-no-fp", + [STAC_DELL_3ST] = "dell-3stack", + [STAC_DELL_BIOS] = "dell-bios", + }; +@@ -2115,26 +2059,16 @@ + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_D965_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_D965_REF), + /* Intel 946 based systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST), + /* 965 based 3 stack systems */ +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2116, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2115, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2114, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2113, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2112, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2111, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2110, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2009, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2008, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2007, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2006, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2005, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2004, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100, ++ "Intel D965", STAC_D965_3ST), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000, ++ "Intel D965", STAC_D965_3ST), + /* Dell 3 stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), +@@ -2144,21 +2078,16 @@ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), +- SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_3ST), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS), + /* 965 based 5 stack systems */ +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2304, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2305, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2501, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2502, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2503, "Intel D965", STAC_D965_5ST), +- SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2504, "Intel D965", STAC_D965_5ST), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300, ++ "Intel D965", STAC_D965_5ST), ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500, ++ "Intel D965", STAC_D965_5ST), + {} /* terminator */ + }; + +@@ -2215,6 +2144,7 @@ + }; + + static const char *stac9205_models[STAC_9205_MODELS] = { ++ [STAC_9205_AUTO] = "auto", + [STAC_9205_REF] = "ref", + [STAC_9205_DELL_M42] = "dell-m42", + [STAC_9205_DELL_M43] = "dell-m43", +@@ -2226,6 +2156,10 @@ + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, + "DFI LanParty", STAC_9205_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30, ++ "SigmaTel", STAC_9205_REF), ++ SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, ++ "DFI LanParty", STAC_9205_REF), + /* Dell */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "unknown Dell", STAC_9205_DELL_M42), +@@ -2258,6 +2192,7 @@ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, + "Dell Vostro 1500", STAC_9205_DELL_M42), + /* Gateway */ ++ SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD), + SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD), + {} /* terminator */ + }; +@@ -2515,10 +2450,18 @@ + return 0; + } + +-static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) ++#define snd_hda_query_pin_caps(codec, nid) \ ++ snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) ++#define snd_hda_codec_get_pincfg(codec, nid) \ ++ snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0) ++#define snd_hda_codec_set_pincfg(codec, nid, val) \ ++ stac92xx_set_config_reg(codec, nid, val) ++#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) ++ ++static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, ++ hda_nid_t nid) + { +- unsigned int pincap = snd_hda_param_read(codec, nid, +- AC_PAR_PIN_CAP); ++ unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + if (pincap & AC_PINCAP_VREF_100) + return AC_PINCTL_VREF_100; +@@ -2550,8 +2493,7 @@ + return 0; + } + +-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, +- unsigned char type); ++static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid); + + static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +@@ -2559,25 +2501,119 @@ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + int nid = kcontrol->private_value; +- ++ + spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; + + /* check to be sure that the ports are upto date with + * switch changes + */ +- stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); ++ stac_issue_unsol_event(codec, nid); ++ + return 1; + } + +-#define stac92xx_io_switch_info snd_ctl_boolean_mono_info ++static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ int i; ++ static char *texts[] = { ++ "Mic In", "Line In", "Line Out" ++ }; ++ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ hda_nid_t nid = kcontrol->private_value; ++ ++ if (nid == spec->mic_switch || nid == spec->line_switch) ++ i = 3; ++ else ++ i = 2; ++ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->value.enumerated.items = i; ++ uinfo->count = 1; ++ if (uinfo->value.enumerated.item >= i) ++ uinfo->value.enumerated.item = i-1; ++ strcpy(uinfo->value.enumerated.name, ++ texts[uinfo->value.enumerated.item]); ++ ++ return 0; ++} ++ ++static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ hda_nid_t nid = kcontrol->private_value; ++ unsigned int vref = stac92xx_vref_get(codec, nid); ++ ++ if (vref == stac92xx_get_default_vref(codec, nid)) ++ ucontrol->value.enumerated.item[0] = 0; ++ else if (vref == AC_PINCTL_VREF_GRD) ++ ucontrol->value.enumerated.item[0] = 1; ++ else if (vref == AC_PINCTL_VREF_HIZ) ++ ucontrol->value.enumerated.item[0] = 2; ++ ++ return 0; ++} ++ ++static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ unsigned int new_vref = 0; ++ int error; ++ hda_nid_t nid = kcontrol->private_value; ++ ++ if (ucontrol->value.enumerated.item[0] == 0) ++ new_vref = stac92xx_get_default_vref(codec, nid); ++ else if (ucontrol->value.enumerated.item[0] == 1) ++ new_vref = AC_PINCTL_VREF_GRD; ++ else if (ucontrol->value.enumerated.item[0] == 2) ++ new_vref = AC_PINCTL_VREF_HIZ; ++ else ++ return 0; ++ ++ if (new_vref != stac92xx_vref_get(codec, nid)) { ++ error = stac92xx_vref_set(codec, nid, new_vref); ++ return error; ++ } ++ ++ return 0; ++} ++ ++static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ static char *texts[2]; ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ struct sigmatel_spec *spec = codec->spec; ++ ++ if (kcontrol->private_value == spec->line_switch) ++ texts[0] = "Line In"; ++ else ++ texts[0] = "Mic In"; ++ texts[1] = "Line Out"; ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; ++ uinfo->value.enumerated.items = 2; ++ uinfo->count = 1; ++ ++ if (uinfo->value.enumerated.item >= 2) ++ uinfo->value.enumerated.item = 1; ++ strcpy(uinfo->value.enumerated.name, ++ texts[uinfo->value.enumerated.item]); ++ ++ return 0; ++} + + static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) + { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; +- int io_idx = kcontrol-> private_value & 0xff; ++ hda_nid_t nid = kcontrol->private_value; ++ int io_idx = (nid == spec->mic_switch) ? 1 : 0; + +- ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; ++ ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; + return 0; + } + +@@ -2585,9 +2621,9 @@ + { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; +- hda_nid_t nid = kcontrol->private_value >> 8; +- int io_idx = kcontrol-> private_value & 0xff; +- unsigned short val = !!ucontrol->value.integer.value[0]; ++ hda_nid_t nid = kcontrol->private_value; ++ int io_idx = (nid == spec->mic_switch) ? 1 : 0; ++ unsigned short val = !!ucontrol->value.enumerated.item[0]; + + spec->io_switch[io_idx] = val; + +@@ -2596,7 +2632,7 @@ + else { + unsigned int pinctl = AC_PINCTL_IN_EN; + if (io_idx) /* set VREF for mic */ +- pinctl |= stac92xx_get_vref(codec, nid); ++ pinctl |= stac92xx_get_default_vref(codec, nid); + stac92xx_auto_set_pinctl(codec, nid, pinctl); + } + +@@ -2604,7 +2640,7 @@ + * appropriately according to the pin direction + */ + if (spec->hp_detect) +- stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); ++ stac_issue_unsol_event(codec, nid); + + return 1; + } +@@ -2677,7 +2713,8 @@ + STAC_CTL_WIDGET_AMP_VOL, + STAC_CTL_WIDGET_HP_SWITCH, + STAC_CTL_WIDGET_IO_SWITCH, +- STAC_CTL_WIDGET_CLFE_SWITCH ++ STAC_CTL_WIDGET_CLFE_SWITCH, ++ STAC_CTL_WIDGET_DC_BIAS + }; + + static struct snd_kcontrol_new stac92xx_control_templates[] = { +@@ -2689,38 +2726,42 @@ + STAC_CODEC_HP_SWITCH(NULL), + STAC_CODEC_IO_SWITCH(NULL, 0), + STAC_CODEC_CLFE_SWITCH(NULL, 0), ++ DC_BIAS(NULL, 0, 0), + }; + + /* add dynamic controls */ +-static int stac92xx_add_control_temp(struct sigmatel_spec *spec, +- struct snd_kcontrol_new *ktemp, +- int idx, const char *name, +- unsigned long val) ++static struct snd_kcontrol_new * ++stac_control_new(struct sigmatel_spec *spec, ++ struct snd_kcontrol_new *ktemp, ++ const char *name) + { + struct snd_kcontrol_new *knew; + +- if (spec->num_kctl_used >= spec->num_kctl_alloc) { +- int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; +- +- knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ +- if (! knew) +- return -ENOMEM; +- if (spec->kctl_alloc) { +- memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); +- kfree(spec->kctl_alloc); +- } +- spec->kctl_alloc = knew; +- spec->num_kctl_alloc = num; +- } +- +- knew = &spec->kctl_alloc[spec->num_kctl_used]; ++ snd_array_init(&spec->kctls, sizeof(*knew), 32); ++ knew = snd_array_new(&spec->kctls); ++ if (!knew) ++ return NULL; + *knew = *ktemp; +- knew->index = idx; + knew->name = kstrdup(name, GFP_KERNEL); +- if (!knew->name) ++ if (!knew->name) { ++ /* roolback */ ++ memset(knew, 0, sizeof(*knew)); ++ spec->kctls.alloced--; ++ return NULL; ++ } ++ return knew; ++} ++ ++static int stac92xx_add_control_temp(struct sigmatel_spec *spec, ++ struct snd_kcontrol_new *ktemp, ++ int idx, const char *name, ++ unsigned long val) ++{ ++ struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name); ++ if (!knew) + return -ENOMEM; ++ knew->index = idx; + knew->private_value = val; +- spec->num_kctl_used++; + return 0; + } + +@@ -2741,7 +2782,60 @@ + return stac92xx_add_control_idx(spec, type, 0, name, val); + } + +-/* check whether the line-input can be used as line-out */ ++static struct snd_kcontrol_new stac_input_src_temp = { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Input Source", ++ .info = stac92xx_mux_enum_info, ++ .get = stac92xx_mux_enum_get, ++ .put = stac92xx_mux_enum_put, ++}; ++ ++static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, ++ hda_nid_t nid, int idx) ++{ ++ int def_conf = snd_hda_codec_get_pincfg(codec, nid); ++ int control = 0; ++ struct sigmatel_spec *spec = codec->spec; ++ char name[22]; ++ ++ if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { ++ if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD ++ && nid == spec->line_switch) ++ control = STAC_CTL_WIDGET_IO_SWITCH; ++ else if (snd_hda_query_pin_caps(codec, nid) ++ & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) ++ control = STAC_CTL_WIDGET_DC_BIAS; ++ else if (nid == spec->mic_switch) ++ control = STAC_CTL_WIDGET_IO_SWITCH; ++ } ++ ++ if (control) { ++ strcpy(name, auto_pin_cfg_labels[idx]); ++ return stac92xx_add_control(codec->spec, control, ++ strcat(name, " Jack Mode"), nid); ++ } ++ ++ return 0; ++} ++ ++static int stac92xx_add_input_source(struct sigmatel_spec *spec) ++{ ++ struct snd_kcontrol_new *knew; ++ struct hda_input_mux *imux = &spec->private_imux; ++ ++ if (spec->auto_mic) ++ return 0; /* no need for input source */ ++ if (!spec->num_adcs || imux->num_items <= 1) ++ return 0; /* no need for input source control */ ++ knew = stac_control_new(spec, &stac_input_src_temp, ++ stac_input_src_temp.name); ++ if (!knew) ++ return -ENOMEM; ++ knew->count = spec->num_adcs; ++ return 0; ++} ++ ++/* check whether the line-input can be used as line-out */ + static hda_nid_t check_line_out_switch(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; +@@ -2752,7 +2846,7 @@ + if (cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + nid = cfg->input_pins[AUTO_PIN_LINE]; +- pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); ++ pincap = snd_hda_query_pin_caps(codec, nid); + if (pincap & AC_PINCAP_OUT) + return nid; + return 0; +@@ -2771,12 +2865,11 @@ + mic_pin = AUTO_PIN_MIC; + for (;;) { + hda_nid_t nid = cfg->input_pins[mic_pin]; +- def_conf = snd_hda_codec_read(codec, nid, 0, +- AC_VERB_GET_CONFIG_DEFAULT, 0); ++ def_conf = snd_hda_codec_get_pincfg(codec, nid); + /* some laptops have an internal analog microphone + * which can't be used as a output */ + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { +- pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); ++ pincap = snd_hda_query_pin_caps(codec, nid); + if (pincap & AC_PINCAP_OUT) + return nid; + } +@@ -2824,9 +2917,8 @@ + conn_len = snd_hda_get_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS); + for (j = 0; j < conn_len; j++) { +- wcaps = snd_hda_param_read(codec, conn[j], +- AC_PAR_AUDIO_WIDGET_CAP); +- wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; ++ wcaps = get_wcaps(codec, conn[j]); ++ wtype = get_wcaps_type(wcaps); + /* we check only analog outputs */ + if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL)) + continue; +@@ -2840,6 +2932,16 @@ + return conn[j]; + } + } ++ /* if all DACs are already assigned, connect to the primary DAC */ ++ if (conn_len > 1) { ++ for (j = 0; j < conn_len; j++) { ++ if (conn[j] == spec->multiout.dac_nids[0]) { ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_CONNECT_SEL, j); ++ break; ++ } ++ } ++ } + return 0; + } + +@@ -2880,6 +2982,26 @@ + add_spec_dacs(spec, dac); + } + ++ for (i = 0; i < cfg->hp_outs; i++) { ++ nid = cfg->hp_pins[i]; ++ dac = get_unassigned_dac(codec, nid); ++ if (dac) { ++ if (!spec->multiout.hp_nid) ++ spec->multiout.hp_nid = dac; ++ else ++ add_spec_extra_dacs(spec, dac); ++ } ++ spec->hp_dacs[i] = dac; ++ } ++ ++ for (i = 0; i < cfg->speaker_outs; i++) { ++ nid = cfg->speaker_pins[i]; ++ dac = get_unassigned_dac(codec, nid); ++ if (dac) ++ add_spec_extra_dacs(spec, dac); ++ spec->speaker_dacs[i] = dac; ++ } ++ + /* add line-in as output */ + nid = check_line_out_switch(codec); + if (nid) { +@@ -2907,26 +3029,6 @@ + } + } + +- for (i = 0; i < cfg->hp_outs; i++) { +- nid = cfg->hp_pins[i]; +- dac = get_unassigned_dac(codec, nid); +- if (dac) { +- if (!spec->multiout.hp_nid) +- spec->multiout.hp_nid = dac; +- else +- add_spec_extra_dacs(spec, dac); +- } +- spec->hp_dacs[i] = dac; +- } +- +- for (i = 0; i < cfg->speaker_outs; i++) { +- nid = cfg->speaker_pins[i]; +- dac = get_unassigned_dac(codec, nid); +- if (dac) +- add_spec_extra_dacs(spec, dac); +- spec->speaker_dacs[i] = dac; +- } +- + snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + spec->multiout.num_dacs, + spec->multiout.dac_nids[0], +@@ -2939,8 +3041,8 @@ + } + + /* create volume control/switch for the given prefx type */ +-static int create_controls(struct hda_codec *codec, const char *pfx, +- hda_nid_t nid, int chs) ++static int create_controls_idx(struct hda_codec *codec, const char *pfx, ++ int idx, hda_nid_t nid, int chs) + { + struct sigmatel_spec *spec = codec->spec; + char name[32]; +@@ -2964,19 +3066,22 @@ + } + + sprintf(name, "%s Playback Volume", pfx); +- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, ++ err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name, + HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, + spec->volume_offset)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", pfx); +- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, ++ err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name, + HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); + if (err < 0) + return err; + return 0; + } + ++#define create_controls(codec, pfx, nid, chs) \ ++ create_controls_idx(codec, pfx, 0, nid, chs) ++ + static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) + { + if (spec->multiout.num_dacs > 4) { +@@ -3014,12 +3119,6 @@ + static const char *chname[4] = { + "Front", "Surround", NULL /*CLFE*/, "Side" + }; +- static const char *hp_pfxs[] = { +- "Headphone", "Headphone2", "Headphone3", "Headphone4" +- }; +- static const char *speaker_pfxs[] = { +- "Speaker", "External Speaker", "Speaker2", "Speaker3" +- }; + hda_nid_t nid; + int i, err; + unsigned int wid_caps; +@@ -3055,18 +3154,22 @@ + + } else { + const char *name; ++ int idx; + switch (type) { + case AUTO_PIN_HP_OUT: +- name = hp_pfxs[i]; ++ name = "Headphone"; ++ idx = i; + break; + case AUTO_PIN_SPEAKER_OUT: +- name = speaker_pfxs[i]; ++ name = "Speaker"; ++ idx = i; + break; + default: + name = chname[i]; ++ idx = 0; + break; + } +- err = create_controls(codec, name, nid, 3); ++ err = create_controls_idx(codec, name, idx, nid, 3); + if (err < 0) + return err; + } +@@ -3074,12 +3177,29 @@ + return 0; + } + ++static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, ++ unsigned long sw, int idx) ++{ ++ int err; ++ err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, ++ "Capture Volume", vol); ++ if (err < 0) ++ return err; ++ err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx, ++ "Capture Switch", sw); ++ if (err < 0) ++ return err; ++ return 0; ++} ++ + /* add playback controls from the parsed DAC table */ + static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) + { + struct sigmatel_spec *spec = codec->spec; ++ hda_nid_t nid; + int err; ++ int idx; + + err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, + spec->multiout.dac_nids, +@@ -3096,20 +3216,13 @@ + return err; + } + +- if (spec->line_switch) { +- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, +- "Line In as Output Switch", +- spec->line_switch << 8); +- if (err < 0) +- return err; +- } +- +- if (spec->mic_switch) { +- err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, +- "Mic as Output Switch", +- (spec->mic_switch << 8) | 1); +- if (err < 0) +- return err; ++ for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { ++ nid = cfg->input_pins[idx]; ++ if (nid) { ++ err = stac92xx_add_jack_mode_control(codec, nid, idx); ++ if (err < 0) ++ return err; ++ } + } + + return 0; +@@ -3152,7 +3265,7 @@ + spec->mono_nid, + con_lst, + HDA_MAX_NUM_INPUTS); +- if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) ++ if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) + return -EINVAL; + + for (i = 0; i < num_cons; i++) { +@@ -3298,7 +3411,7 @@ + spec->smux_nids[0], + con_lst, + HDA_MAX_NUM_INPUTS); +- if (!num_cons) ++ if (num_cons <= 0) + return -EINVAL; + + if (!labels) +@@ -3319,53 +3432,66 @@ + "Digital Mic 3", "Digital Mic 4" + }; + ++static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, ++ hda_nid_t nid) ++{ ++ hda_nid_t conn[HDA_MAX_NUM_INPUTS]; ++ int i, nums; ++ ++ nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); ++ for (i = 0; i < nums; i++) ++ if (conn[i] == nid) ++ return i; ++ return -1; ++} ++ + /* create playback/capture controls for input pins on dmic capable codecs */ + static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) + { + struct sigmatel_spec *spec = codec->spec; ++ struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *dimux = &spec->private_dimux; +- hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; +- int err, i, j; ++ int err, i, active_mics; ++ unsigned int def_conf; + char name[32]; + + dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; + dimux->items[dimux->num_items].index = 0; + dimux->num_items++; + ++ active_mics = 0; ++ for (i = 0; i < spec->num_dmics; i++) { ++ def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); ++ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) ++ active_mics++; ++ } ++ + for (i = 0; i < spec->num_dmics; i++) { + hda_nid_t nid; + int index; +- int num_cons; + unsigned int wcaps; +- unsigned int def_conf; ++ const char *label; + +- def_conf = snd_hda_codec_read(codec, +- spec->dmic_nids[i], +- 0, +- AC_VERB_GET_CONFIG_DEFAULT, +- 0); ++ def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + continue; + + nid = spec->dmic_nids[i]; +- num_cons = snd_hda_get_connections(codec, +- spec->dmux_nids[0], +- con_lst, +- HDA_MAX_NUM_INPUTS); +- for (j = 0; j < num_cons; j++) +- if (con_lst[j] == nid) { +- index = j; +- goto found; +- } +- continue; +-found: ++ index = get_connection_index(codec, spec->dmux_nids[0], nid); ++ if (index < 0) ++ continue; ++ ++ if (active_mics == 1) ++ label = "Digital Mic"; ++ else ++ label = stac92xx_dmic_labels[dimux->num_items]; ++ + wcaps = get_wcaps(codec, nid) & + (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); + + if (wcaps) { +- sprintf(name, "%s Capture Volume", +- stac92xx_dmic_labels[dimux->num_items]); ++ sprintf(name, "%s Capture Volume", label); + + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_VOL, +@@ -3377,15 +3503,100 @@ + return err; + } + +- dimux->items[dimux->num_items].label = +- stac92xx_dmic_labels[dimux->num_items]; ++ dimux->items[dimux->num_items].label = label; + dimux->items[dimux->num_items].index = index; + dimux->num_items++; ++ ++ imux->items[imux->num_items].label = label; ++ imux->items[imux->num_items].index = index; ++ imux->num_items++; + } + + return 0; + } + ++static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, ++ hda_nid_t *fixed, hda_nid_t *ext) ++{ ++ unsigned int cfg; ++ ++ if (!nid) ++ return 0; ++ cfg = snd_hda_codec_get_pincfg(codec, nid); ++ switch (get_defcfg_connect(cfg)) { ++ case AC_JACK_PORT_FIXED: ++ if (*fixed) ++ return 1; /* already occupied */ ++ *fixed = nid; ++ break; ++ case AC_JACK_PORT_COMPLEX: ++ if (*ext) ++ return 1; /* already occupied */ ++ *ext = nid; ++ break; ++ } ++ return 0; ++} ++ ++static int set_mic_route(struct hda_codec *codec, ++ struct sigmatel_mic_route *mic, ++ hda_nid_t pin) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ int i; ++ ++ mic->pin = pin; ++ for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) ++ if (pin == cfg->input_pins[i]) ++ break; ++ if (i <= AUTO_PIN_FRONT_MIC) { ++ /* analog pin */ ++ mic->dmux_idx = 0; ++ i = get_connection_index(codec, spec->mux_nids[0], pin); ++ if (i < 0) ++ return -1; ++ mic->mux_idx = i; ++ } else if (spec->dmux_nids) { ++ /* digital pin */ ++ mic->mux_idx = 0; ++ i = get_connection_index(codec, spec->dmux_nids[0], pin); ++ if (i < 0) ++ return -1; ++ mic->dmux_idx = i; ++ } ++ return 0; ++} ++ ++/* return non-zero if the device is for automatic mic switch */ ++static int stac_check_auto_mic(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ hda_nid_t fixed, ext; ++ int i; ++ ++ for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) { ++ if (cfg->input_pins[i]) ++ return 0; /* must be exclusively mics */ ++ } ++ fixed = ext = 0; ++ for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) ++ if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext)) ++ return 0; ++ for (i = 0; i < spec->num_dmics; i++) ++ if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext)) ++ return 0; ++ if (!fixed || !ext) ++ return 0; ++ if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) ++ return 0; /* no unsol support */ ++ if (set_mic_route(codec, &spec->ext_mic, ext) || ++ set_mic_route(codec, &spec->int_mic, fixed)) ++ return 0; /* something is wrong */ ++ return 1; ++} ++ + /* create playback/capture controls for input pins */ + static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) + { +@@ -3418,6 +3629,7 @@ + imux->items[imux->num_items].index = index; + imux->num_items++; + } ++ spec->num_analog_muxes = imux->num_items; + + if (imux->num_items) { + /* +@@ -3469,7 +3681,7 @@ + { + struct sigmatel_spec *spec = codec->spec; + int hp_swap = 0; +- int err; ++ int i, err; + + if ((err = snd_hda_parse_pin_def_config(codec, + &spec->autocfg, +@@ -3509,11 +3721,10 @@ + if (snd_hda_get_connections(codec, + spec->autocfg.mono_out_pin, conn_list, 1) && + snd_hda_get_connections(codec, conn_list[0], +- conn_list, 1)) { ++ conn_list, 1) > 0) { + + int wcaps = get_wcaps(codec, conn_list[0]); +- int wid_type = (wcaps & AC_WCAP_TYPE) +- >> AC_WCAP_TYPE_SHIFT; ++ int wid_type = get_wcaps_type(wcaps); + /* LR swap check, some stac925x have a mux that + * changes the DACs output path instead of the + * mono-mux path. +@@ -3578,6 +3789,8 @@ + err = snd_hda_attach_beep_device(codec, nid); + if (err < 0) + return err; ++ /* IDT/STAC codecs have linear beep tone parameter */ ++ /*codec->beep->linear_tone = 1;*/ + /* if no beep switch is available, make its own one */ + caps = query_amp_caps(codec, nid, HDA_OUTPUT); + if (codec->beep && +@@ -3602,6 +3815,21 @@ + spec->autocfg.line_outs = 0; + } + ++ if (stac_check_auto_mic(codec)) { ++ spec->auto_mic = 1; ++ /* only one capture for auto-mic */ ++ spec->num_adcs = 1; ++ spec->num_caps = 1; ++ spec->num_muxes = 1; ++ } ++ ++ for (i = 0; i < spec->num_caps; i++) { ++ err = stac92xx_add_capvol_ctls(codec, spec->capvols[i], ++ spec->capsws[i], i); ++ if (err < 0) ++ return err; ++ } ++ + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); + if (err < 0) + return err; +@@ -3631,6 +3859,10 @@ + return err; + } + ++ err = stac92xx_add_input_source(spec); ++ if (err < 0) ++ return err; ++ + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + if (spec->multiout.max_channels > 2) + spec->surr_switch = 1; +@@ -3640,8 +3872,8 @@ + if (dig_in && spec->autocfg.dig_in_pin) + spec->dig_in_nid = dig_in; + +- if (spec->kctl_alloc) +- spec->mixers[spec->num_mixers++] = spec->kctl_alloc; ++ if (spec->kctls.list) ++ spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux; + if (!spec->dinput_mux) +@@ -3698,9 +3930,7 @@ + for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { + hda_nid_t pin = spec->autocfg.line_out_pins[i]; + unsigned int defcfg; +- defcfg = snd_hda_codec_read(codec, pin, 0, +- AC_VERB_GET_CONFIG_DEFAULT, +- 0x00); ++ defcfg = snd_hda_codec_get_pincfg(codec, pin); + if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) { + unsigned int wcaps = get_wcaps(codec, pin); + wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); +@@ -3744,13 +3974,17 @@ + return err; + } + ++ err = stac92xx_add_input_source(spec); ++ if (err < 0) ++ return err; ++ + if (spec->autocfg.dig_out_pin) + spec->multiout.dig_out_nid = 0x05; + if (spec->autocfg.dig_in_pin) + spec->dig_in_nid = 0x04; + +- if (spec->kctl_alloc) +- spec->mixers[spec->num_mixers++] = spec->kctl_alloc; ++ if (spec->kctls.list) ++ spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux; + spec->dinput_mux = &spec->private_dimux; +@@ -3799,26 +4033,27 @@ + { + struct sigmatel_event *event; + +- if (spec->num_events >= ARRAY_SIZE(spec->events)) ++ snd_array_init(&spec->events, sizeof(*event), 32); ++ event = snd_array_new(&spec->events); ++ if (!event) + return -ENOMEM; +- event = &spec->events[spec->num_events++]; + event->nid = nid; + event->type = type; +- event->tag = spec->num_events; ++ event->tag = spec->events.used; + event->data = data; + + return event->tag; + } + + static struct sigmatel_event *stac_get_event(struct hda_codec *codec, +- hda_nid_t nid, unsigned char type) ++ hda_nid_t nid) + { + struct sigmatel_spec *spec = codec->spec; +- struct sigmatel_event *event = spec->events; ++ struct sigmatel_event *event = spec->events.list; + int i; + +- for (i = 0; i < spec->num_events; i++, event++) { +- if (event->nid == nid && event->type == type) ++ for (i = 0; i < spec->events.used; i++, event++) { ++ if (event->nid == nid) + return event; + } + return NULL; +@@ -3828,34 +4063,42 @@ + unsigned char tag) + { + struct sigmatel_spec *spec = codec->spec; +- struct sigmatel_event *event = spec->events; ++ struct sigmatel_event *event = spec->events.list; + int i; + +- for (i = 0; i < spec->num_events; i++, event++) { ++ for (i = 0; i < spec->events.used; i++, event++) { + if (event->tag == tag) + return event; + } + return NULL; + } + +-static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, +- unsigned int type) ++/* check if given nid is a valid pin and no other events are assigned ++ * to it. If OK, assign the event, set the unsol flag, and returns 1. ++ * Otherwise, returns zero. ++ */ ++static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, ++ unsigned int type) + { + struct sigmatel_event *event; + int tag; + + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) +- return; +- event = stac_get_event(codec, nid, type); +- if (event) ++ return 0; ++ event = stac_get_event(codec, nid); ++ if (event) { ++ if (event->type != type) ++ return 0; + tag = event->tag; +- else ++ } else { + tag = stac_add_event(codec->spec, nid, type, 0); +- if (tag < 0) +- return; ++ if (tag < 0) ++ return 0; ++ } + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); ++ return 1; + } + + static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) +@@ -3915,46 +4158,64 @@ + hda_nid_t nid = cfg->hp_pins[i]; + enable_pin_detect(codec, nid, STAC_HP_EVENT); + } ++ if (cfg->line_out_type == AUTO_PIN_LINE_OUT) { ++ /* enable pin-detect for line-outs as well */ ++ for (i = 0; i < cfg->line_outs; i++) { ++ hda_nid_t nid = cfg->line_out_pins[i]; ++ enable_pin_detect(codec, nid, STAC_LO_EVENT); ++ } ++ } ++ + /* force to enable the first line-out; the others are set up + * in unsol_event + */ + stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], +- AC_PINCTL_OUT_EN); ++ AC_PINCTL_OUT_EN); + /* fake event to set up pins */ +- stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], +- STAC_HP_EVENT); ++ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]); + } else { + stac92xx_auto_init_multi_out(codec); + stac92xx_auto_init_hp_out(codec); + for (i = 0; i < cfg->hp_outs; i++) + stac_toggle_power_map(codec, cfg->hp_pins[i], 1); + } ++ if (spec->auto_mic) { ++ /* initialize connection to analog input */ ++ if (spec->dmux_nids) ++ snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, ++ AC_VERB_SET_CONNECT_SEL, 0); ++ if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) ++ stac_issue_unsol_event(codec, spec->ext_mic.pin); ++ } + for (i = 0; i < AUTO_PIN_LAST; i++) { + hda_nid_t nid = cfg->input_pins[i]; + if (nid) { + unsigned int pinctl, conf; + if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { + /* for mic pins, force to initialize */ +- pinctl = stac92xx_get_vref(codec, nid); ++ pinctl = stac92xx_get_default_vref(codec, nid); + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, pinctl); + } else { + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + /* if PINCTL already set then skip */ +- if (!(pinctl & AC_PINCTL_IN_EN)) { ++ /* Also, if both INPUT and OUTPUT are set, ++ * it must be a BIOS bug; need to override, too ++ */ ++ if (!(pinctl & AC_PINCTL_IN_EN) || ++ (pinctl & AC_PINCTL_OUT_EN)) { ++ pinctl &= ~AC_PINCTL_OUT_EN; + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, + pinctl); + } + } +- conf = snd_hda_codec_read(codec, nid, 0, +- AC_VERB_GET_CONFIG_DEFAULT, 0); ++ conf = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { +- enable_pin_detect(codec, nid, +- STAC_INSERT_EVENT); +- stac_issue_unsol_event(codec, nid, +- STAC_INSERT_EVENT); ++ if (enable_pin_detect(codec, nid, ++ STAC_INSERT_EVENT)) ++ stac_issue_unsol_event(codec, nid); + } + } + } +@@ -3990,8 +4251,7 @@ + stac_toggle_power_map(codec, nid, 1); + continue; + } +- def_conf = snd_hda_codec_read(codec, nid, 0, +- AC_VERB_GET_CONFIG_DEFAULT, 0); ++ def_conf = snd_hda_codec_get_pincfg(codec, nid); + def_conf = get_defcfg_connect(def_conf); + /* skip any ports that don't have jacks since presence + * detection is useless */ +@@ -4000,32 +4260,35 @@ + stac_toggle_power_map(codec, nid, 1); + continue; + } +- if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) { +- enable_pin_detect(codec, nid, STAC_PWR_EVENT); +- stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); +- } ++ if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) ++ stac_issue_unsol_event(codec, nid); + } + if (spec->dac_list) + stac92xx_power_down(codec); + return 0; + } + ++static void stac92xx_free_kctls(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ ++ if (spec->kctls.list) { ++ struct snd_kcontrol_new *kctl = spec->kctls.list; ++ int i; ++ for (i = 0; i < spec->kctls.used; i++) ++ kfree(kctl[i].name); ++ } ++ snd_array_free(&spec->kctls); ++} ++ + static void stac92xx_free(struct hda_codec *codec) + { + struct sigmatel_spec *spec = codec->spec; +- int i; + + if (! spec) + return; + +- if (spec->kctl_alloc) { +- for (i = 0; i < spec->num_kctl_used; i++) +- kfree(spec->kctl_alloc[i].name); +- kfree(spec->kctl_alloc); +- } +- +- if (spec->bios_pin_configs) +- kfree(spec->bios_pin_configs); ++ snd_array_free(&spec->events); + + kfree(spec); + snd_hda_detach_beep_device(codec); +@@ -4034,7 +4297,9 @@ + static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, + unsigned int flag) + { +- unsigned int pin_ctl = snd_hda_codec_read(codec, nid, ++ unsigned int old_ctl, pin_ctl; ++ ++ pin_ctl = snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); + + if (pin_ctl & AC_PINCTL_IN_EN) { +@@ -4048,14 +4313,17 @@ + return; + } + ++ old_ctl = pin_ctl; + /* if setting pin direction bits, clear the current + direction bits first */ + if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) + pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); + +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_PIN_WIDGET_CONTROL, +- pin_ctl | flag); ++ pin_ctl |= flag; ++ if (old_ctl != pin_ctl) ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, ++ pin_ctl); + } + + static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, +@@ -4063,9 +4331,10 @@ + { + unsigned int pin_ctl = snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); +- snd_hda_codec_write_cache(codec, nid, 0, +- AC_VERB_SET_PIN_WIDGET_CONTROL, +- pin_ctl & ~flag); ++ if (pin_ctl & flag) ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_PIN_WIDGET_CONTROL, ++ pin_ctl & ~flag); + } + + static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) +@@ -4078,6 +4347,48 @@ + return 0; + } + ++static void stac92xx_line_out_detect(struct hda_codec *codec, ++ int presence) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct auto_pin_cfg *cfg = &spec->autocfg; ++ int i; ++ ++ for (i = 0; i < cfg->line_outs; i++) { ++ if (presence) ++ break; ++ presence = get_pin_presence(codec, cfg->line_out_pins[i]); ++ if (presence) { ++ unsigned int pinctl; ++ pinctl = snd_hda_codec_read(codec, ++ cfg->line_out_pins[i], 0, ++ AC_VERB_GET_PIN_WIDGET_CONTROL, 0); ++ if (pinctl & AC_PINCTL_IN_EN) ++ presence = 0; /* mic- or line-input */ ++ } ++ } ++ ++ if (presence) { ++ /* disable speakers */ ++ for (i = 0; i < cfg->speaker_outs; i++) ++ stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], ++ AC_PINCTL_OUT_EN); ++ if (spec->eapd_mask && spec->eapd_switch) ++ stac_gpio_set(codec, spec->gpio_mask, ++ spec->gpio_dir, spec->gpio_data & ++ ~spec->eapd_mask); ++ } else { ++ /* enable speakers */ ++ for (i = 0; i < cfg->speaker_outs; i++) ++ stac92xx_set_pinctl(codec, cfg->speaker_pins[i], ++ AC_PINCTL_OUT_EN); ++ if (spec->eapd_mask && spec->eapd_switch) ++ stac_gpio_set(codec, spec->gpio_mask, ++ spec->gpio_dir, spec->gpio_data | ++ spec->eapd_mask); ++ } ++} ++ + /* return non-zero if the hp-pin of the given array index isn't + * a jack-detection target + */ +@@ -4130,13 +4441,6 @@ + for (i = 0; i < cfg->line_outs; i++) + stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], + AC_PINCTL_OUT_EN); +- for (i = 0; i < cfg->speaker_outs; i++) +- stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], +- AC_PINCTL_OUT_EN); +- if (spec->eapd_mask && spec->eapd_switch) +- stac_gpio_set(codec, spec->gpio_mask, +- spec->gpio_dir, spec->gpio_data & +- ~spec->eapd_mask); + } else { + /* enable lineouts */ + if (spec->hp_switch) +@@ -4145,14 +4449,8 @@ + for (i = 0; i < cfg->line_outs; i++) + stac92xx_set_pinctl(codec, cfg->line_out_pins[i], + AC_PINCTL_OUT_EN); +- for (i = 0; i < cfg->speaker_outs; i++) +- stac92xx_set_pinctl(codec, cfg->speaker_pins[i], +- AC_PINCTL_OUT_EN); +- if (spec->eapd_mask && spec->eapd_switch) +- stac_gpio_set(codec, spec->gpio_mask, +- spec->gpio_dir, spec->gpio_data | +- spec->eapd_mask); + } ++ stac92xx_line_out_detect(codec, presence); + /* toggle hp outs */ + for (i = 0; i < cfg->hp_outs; i++) { + unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; +@@ -4210,10 +4508,28 @@ + stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); + } + +-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, +- unsigned char type) ++static void stac92xx_mic_detect(struct hda_codec *codec) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ struct sigmatel_mic_route *mic; ++ ++ if (get_pin_presence(codec, spec->ext_mic.pin)) ++ mic = &spec->ext_mic; ++ else ++ mic = &spec->int_mic; ++ if (mic->dmux_idx) ++ snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, ++ AC_VERB_SET_CONNECT_SEL, ++ mic->dmux_idx); ++ else ++ snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0, ++ AC_VERB_SET_CONNECT_SEL, ++ mic->mux_idx); ++} ++ ++static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) + { +- struct sigmatel_event *event = stac_get_event(codec, nid, type); ++ struct sigmatel_event *event = stac_get_event(codec, nid); + if (!event) + return; + codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); +@@ -4232,12 +4548,40 @@ + + switch (event->type) { + case STAC_HP_EVENT: ++ case STAC_LO_EVENT: + stac92xx_hp_detect(codec); +- /* fallthru */ ++ break; ++ case STAC_MIC_EVENT: ++ stac92xx_mic_detect(codec); ++ break; ++ } ++ ++ switch (event->type) { ++ case STAC_HP_EVENT: ++ case STAC_LO_EVENT: ++ case STAC_MIC_EVENT: + case STAC_INSERT_EVENT: + case STAC_PWR_EVENT: + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, event->nid); ++ ++ switch (codec->subsystem_id) { ++ case 0x103c308f: ++ if (event->nid == 0xb) { ++ int pin = AC_PINCTL_IN_EN; ++ ++ if (get_pin_presence(codec, 0xa) ++ && get_pin_presence(codec, 0xb)) ++ pin |= AC_PINCTL_VREF_80; ++ if (!get_pin_presence(codec, 0xb)) ++ pin |= AC_PINCTL_VREF_80; ++ ++ /* toggle VREF state based on mic + hp pin ++ * status ++ */ ++ stac92xx_auto_set_pinctl(codec, 0x0a, pin); ++ } ++ } + break; + case STAC_VREF_EVENT: + data = snd_hda_codec_read(codec, codec->afg, 0, +@@ -4254,17 +4598,48 @@ + { + struct sigmatel_spec *spec = codec->spec; + +- stac92xx_set_config_regs(codec); + stac92xx_init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + /* fake event to set up pins again to override cached values */ + if (spec->hp_detect) +- stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], +- STAC_HP_EVENT); ++ stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]); + return 0; + } + ++/* ++ * using power check for controlling mute led of HP notebooks ++ * check for mute state only on Speakers (nid = 0x10) ++ * ++ * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise ++ * the LED is NOT working properly ! ++ * ++ * Changed name to reflect that it now works for any designated ++ * model, not just HP HDX. ++ */ ++ ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++static int stac92xx_hp_check_power_status(struct hda_codec *codec, ++ hda_nid_t nid) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ ++ if (nid == 0x10) { ++ if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & ++ HDA_AMP_MUTE) ++ spec->gpio_data &= ~spec->gpio_led; /* orange */ ++ else ++ spec->gpio_data |= spec->gpio_led; /* white */ ++ ++ stac_gpio_set(codec, spec->gpio_mask, ++ spec->gpio_dir, ++ spec->gpio_data); ++ } ++ ++ return 0; ++} ++#endif ++ + static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) + { + struct sigmatel_spec *spec = codec->spec; +@@ -4275,8 +4650,7 @@ + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); +- unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> +- AC_WCAP_TYPE_SHIFT; ++ unsigned int wid_type = get_wcaps_type(wcaps); + if (wid_type == AC_WID_PIN) + snd_hda_codec_read(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); +@@ -4435,6 +4809,9 @@ + + spec->init = stac925x_core_init; + spec->mixer = stac925x_mixer; ++ spec->num_caps = 1; ++ spec->capvols = stac925x_capvols; ++ spec->capsws = stac925x_capsws; + + err = stac92xx_parse_auto_config(codec, 0x8, 0x7); + if (!err) { +@@ -4456,16 +4833,6 @@ + return 0; + } + +-static struct hda_input_mux stac92hd73xx_dmux = { +- .num_items = 4, +- .items = { +- { "Analog Inputs", 0x0b }, +- { "Digital Mic 1", 0x09 }, +- { "Digital Mic 2", 0x0a }, +- { "CD", 0x08 }, +- } +-}; +- + static int patch_stac92hd73xx(struct hda_codec *codec) + { + struct sigmatel_spec *spec; +@@ -4520,12 +4887,10 @@ + case 0x5: /* 10 Channel */ + spec->mixer = stac92hd73xx_10ch_mixer; + spec->init = stac92hd73xx_10ch_core_init; ++ break; + } + spec->multiout.dac_nids = spec->dac_nids; + +- spec->aloopback_mask = 0x01; +- spec->aloopback_shift = 8; +- + spec->digbeep_nid = 0x1c; + spec->mux_nids = stac92hd73xx_mux_nids; + spec->adc_nids = stac92hd73xx_adc_nids; +@@ -4538,8 +4903,10 @@ + spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); + spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); +- memcpy(&spec->private_dimux, &stac92hd73xx_dmux, +- sizeof(stac92hd73xx_dmux)); ++ ++ spec->num_caps = STAC92HD73XX_NUM_CAPS; ++ spec->capvols = stac92hd73xx_capvols; ++ spec->capsws = stac92hd73xx_capsws; + + switch (spec->board_config) { + case STAC_DELL_EQ: +@@ -4558,20 +4925,17 @@ + spec->init = dell_m6_core_init; + switch (spec->board_config) { + case STAC_DELL_M6_AMIC: /* Analog Mics */ +- stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); ++ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); + spec->num_dmics = 0; +- spec->private_dimux.num_items = 1; + break; + case STAC_DELL_M6_DMIC: /* Digital Mics */ +- stac92xx_set_config_reg(codec, 0x13, 0x90A60160); ++ snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); + spec->num_dmics = 1; +- spec->private_dimux.num_items = 2; + break; + case STAC_DELL_M6_BOTH: /* Both */ +- stac92xx_set_config_reg(codec, 0x0b, 0x90A70170); +- stac92xx_set_config_reg(codec, 0x13, 0x90A60160); ++ snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); ++ snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); + spec->num_dmics = 1; +- spec->private_dimux.num_items = 2; + break; + } + break; +@@ -4579,13 +4943,13 @@ + spec->num_dmics = STAC92HD73XX_NUM_DMICS; + spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); + spec->eapd_switch = 1; ++ break; + } + if (spec->board_config > STAC_92HD73XX_REF) { + /* GPIO0 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; + spec->gpio_data = 0x01; + } +- spec->dinput_mux = &spec->private_dimux; + + spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); + spec->pwr_nids = stac92hd73xx_pwr_nids; +@@ -4615,21 +4979,13 @@ + return 0; + } + +-static struct hda_input_mux stac92hd83xxx_dmux = { +- .num_items = 3, +- .items = { +- { "Analog Inputs", 0x03 }, +- { "Digital Mic 1", 0x04 }, +- { "Digital Mic 2", 0x05 }, +- } +-}; +- + static int patch_stac92hd83xxx(struct hda_codec *codec) + { + struct sigmatel_spec *spec; + hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; + int err; + int num_dacs; ++ hda_nid_t nid; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) +@@ -4648,14 +5004,6 @@ + spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); + spec->multiout.dac_nids = spec->dac_nids; + +- /* set port 0xe to select the last DAC +- */ +- num_dacs = snd_hda_get_connections(codec, 0x0e, +- conn, STAC92HD83_DAC_COUNT + 1) - 1; +- +- snd_hda_codec_write_cache(codec, 0xe, 0, +- AC_VERB_SET_CONNECT_SEL, num_dacs); +- + spec->init = stac92hd83xxx_core_init; + spec->mixer = stac92hd83xxx_mixer; + spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids); +@@ -4663,8 +5011,11 @@ + spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids); + spec->num_amps = ARRAY_SIZE(stac92hd83xxx_amp_nids); + spec->num_dmics = STAC92HD83XXX_NUM_DMICS; +- spec->dinput_mux = &stac92hd83xxx_dmux; + spec->pin_nids = stac92hd83xxx_pin_nids; ++ spec->num_caps = STAC92HD83XXX_NUM_CAPS; ++ spec->capvols = stac92hd83xxx_capvols; ++ spec->capsws = stac92hd83xxx_capsws; ++ + spec->board_config = snd_hda_check_board_config(codec, + STAC_92HD83XXX_MODELS, + stac92hd83xxx_models, +@@ -4687,6 +5038,7 @@ + switch (codec->vendor_id) { + case 0x111d7604: + case 0x111d7605: ++ case 0x111d76d5: + if (spec->board_config == STAC_92HD83XXX_PWR_REF) + break; + spec->num_pwrs = 0; +@@ -4709,24 +5061,89 @@ + return err; + } + ++ switch (spec->board_config) { ++ case STAC_DELL_S14: ++ nid = 0xf; ++ break; ++ default: ++ nid = 0xe; ++ break; ++ } ++ ++ num_dacs = snd_hda_get_connections(codec, nid, ++ conn, STAC92HD83_DAC_COUNT + 1) - 1; ++ if (num_dacs < 0) ++ num_dacs = STAC92HD83_DAC_COUNT; ++ ++ /* set port X to select the last DAC ++ */ ++ snd_hda_codec_write_cache(codec, nid, 0, ++ AC_VERB_SET_CONNECT_SEL, num_dacs); ++ + codec->patch_ops = stac92xx_patch_ops; + + return 0; + } + +-static struct hda_input_mux stac92hd71bxx_dmux = { +- .num_items = 4, +- .items = { +- { "Analog Inputs", 0x00 }, +- { "Mixer", 0x01 }, +- { "Digital Mic 1", 0x02 }, +- { "Digital Mic 2", 0x03 }, ++/* get the pin connection (fixed, none, etc) */ ++static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ unsigned int cfg; ++ ++ cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]); ++ return get_defcfg_connect(cfg); ++} ++ ++static int stac92hd71bxx_connected_ports(struct hda_codec *codec, ++ hda_nid_t *nids, int num_nids) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int idx, num; ++ unsigned int def_conf; ++ ++ for (num = 0; num < num_nids; num++) { ++ for (idx = 0; idx < spec->num_pins; idx++) ++ if (spec->pin_nids[idx] == nids[num]) ++ break; ++ if (idx >= spec->num_pins) ++ break; ++ def_conf = stac_get_defcfg_connect(codec, idx); ++ if (def_conf == AC_JACK_PORT_NONE) ++ break; + } +-}; ++ return num; ++} ++ ++static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, ++ hda_nid_t dig0pin) ++{ ++ struct sigmatel_spec *spec = codec->spec; ++ int idx; ++ ++ for (idx = 0; idx < spec->num_pins; idx++) ++ if (spec->pin_nids[idx] == dig0pin) ++ break; ++ if ((idx + 2) >= spec->num_pins) ++ return 0; ++ ++ /* dig1pin case */ ++ if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE) ++ return 2; ++ ++ /* dig0pin + dig2pin case */ ++ if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE) ++ return 2; ++ if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE) ++ return 1; ++ else ++ return 0; ++} + + static int patch_stac92hd71bxx(struct hda_codec *codec) + { + struct sigmatel_spec *spec; ++ struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; + int err = 0; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); +@@ -4735,11 +5152,21 @@ + + codec->spec = spec; + codec->patch_ops = stac92xx_patch_ops; +- spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); ++ spec->num_pins = STAC92HD71BXX_NUM_PINS; ++ switch (codec->vendor_id) { ++ case 0x111d76b6: ++ case 0x111d76b7: ++ spec->pin_nids = stac92hd71bxx_pin_nids_4port; ++ break; ++ case 0x111d7603: ++ case 0x111d7608: ++ /* On 92HD75Bx 0x27 isn't a pin nid */ ++ spec->num_pins--; ++ /* fallthrough */ ++ default: ++ spec->pin_nids = stac92hd71bxx_pin_nids_6port; ++ } + spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); +- spec->pin_nids = stac92hd71bxx_pin_nids; +- memcpy(&spec->private_dimux, &stac92hd71bxx_dmux, +- sizeof(stac92hd71bxx_dmux)); + spec->board_config = snd_hda_check_board_config(codec, + STAC_92HD71BXX_MODELS, + stac92hd71bxx_models, +@@ -4766,14 +5193,25 @@ + spec->gpio_data = 0x01; + } + ++ spec->dmic_nids = stac92hd71bxx_dmic_nids; ++ spec->dmux_nids = stac92hd71bxx_dmux_nids; ++ ++ spec->num_caps = STAC92HD71BXX_NUM_CAPS; ++ spec->capvols = stac92hd71bxx_capvols; ++ spec->capsws = stac92hd71bxx_capsws; ++ + switch (codec->vendor_id) { + case 0x111d76b6: /* 4 Port without Analog Mixer */ + case 0x111d76b7: ++ unmute_init++; ++ /* fallthru */ + case 0x111d76b4: /* 6 Port without Analog Mixer */ + case 0x111d76b5: +- spec->mixer = stac92hd71bxx_mixer; + spec->init = stac92hd71bxx_core_init; + codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; ++ spec->num_dmics = stac92hd71bxx_connected_ports(codec, ++ stac92hd71bxx_dmic_nids, ++ STAC92HD71BXX_NUM_DMICS); + break; + case 0x111d7608: /* 5 Port with Analog Mixer */ + switch (spec->board_config) { +@@ -4797,12 +5235,15 @@ + + /* no output amps */ + spec->num_pwrs = 0; +- spec->mixer = stac92hd71bxx_analog_mixer; +- spec->dinput_mux = &spec->private_dimux; +- + /* disable VSW */ +- spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; +- stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); ++ spec->init = stac92hd71bxx_core_init; ++ unmute_init++; ++ snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); ++ snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); ++ stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0; ++ spec->num_dmics = stac92hd71bxx_connected_ports(codec, ++ stac92hd71bxx_dmic_nids, ++ STAC92HD71BXX_NUM_DMICS - 1); + break; + case 0x111d7603: /* 6 Port with Analog Mixer */ + if ((codec->revision_id & 0xf) == 1) +@@ -4812,12 +5253,17 @@ + spec->num_pwrs = 0; + /* fallthru */ + default: +- spec->dinput_mux = &spec->private_dimux; +- spec->mixer = stac92hd71bxx_analog_mixer; +- spec->init = stac92hd71bxx_analog_core_init; ++ spec->init = stac92hd71bxx_core_init; + codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; ++ spec->num_dmics = stac92hd71bxx_connected_ports(codec, ++ stac92hd71bxx_dmic_nids, ++ STAC92HD71BXX_NUM_DMICS); ++ break; + } + ++ if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) ++ snd_hda_sequence_write_cache(codec, unmute_init); ++ + /* Some HP machines seem to have unstable codec communications + * especially with ATI fglrx driver. For recovering from the + * CORB/RIRB stall, allow the BUS reset and keep always sync +@@ -4827,25 +5273,22 @@ + codec->bus->allow_bus_reset = 1; + } + +- spec->aloopback_mask = 0x50; +- spec->aloopback_shift = 0; +- + spec->powerdown_adcs = 1; + spec->digbeep_nid = 0x26; + spec->mux_nids = stac92hd71bxx_mux_nids; + spec->adc_nids = stac92hd71bxx_adc_nids; +- spec->dmic_nids = stac92hd71bxx_dmic_nids; +- spec->dmux_nids = stac92hd71bxx_dmux_nids; + spec->smux_nids = stac92hd71bxx_smux_nids; + spec->pwr_nids = stac92hd71bxx_pwr_nids; + + spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); ++ spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); ++ spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e); + + switch (spec->board_config) { + case STAC_HP_M4: + /* enable internal microphone */ +- stac92xx_set_config_reg(codec, 0x0e, 0x01813040); ++ snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040); + stac92xx_auto_set_pinctl(codec, 0x0e, + AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); + /* fallthru */ +@@ -4860,19 +5303,42 @@ + spec->num_smuxes = 0; + spec->num_dmuxes = 1; + break; +- default: +- spec->num_dmics = STAC92HD71BXX_NUM_DMICS; +- spec->num_smuxes = ARRAY_SIZE(stac92hd71bxx_smux_nids); +- spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); +- }; ++ case STAC_HP_DV4_1222NR: ++ spec->num_dmics = 1; ++ /* I don't know if it needs 1 or 2 smuxes - will wait for ++ * bug reports to fix if needed ++ */ ++ spec->num_smuxes = 1; ++ spec->num_dmuxes = 1; ++ spec->gpio_led = 0x01; ++ /* fallthrough */ ++ case STAC_HP_DV5: ++ snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); ++ stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); ++ break; ++ case STAC_HP_HDX: ++ spec->num_dmics = 1; ++ spec->num_dmuxes = 1; ++ spec->num_smuxes = 1; ++ /* orange/white mute led on GPIO3, orange=0, white=1 */ ++ spec->gpio_led = 0x08; ++ break; ++ } ++ ++#ifdef CONFIG_SND_HDA_POWER_SAVE ++ if (spec->gpio_led) { ++ spec->gpio_mask |= spec->gpio_led; ++ spec->gpio_dir |= spec->gpio_led; ++ spec->gpio_data |= spec->gpio_led; ++ /* register check_power_status callback. */ ++ codec->patch_ops.check_power_status = ++ stac92xx_hp_check_power_status; ++ } ++#endif + + spec->multiout.dac_nids = spec->dac_nids; +- if (spec->dinput_mux) +- spec->private_dimux.num_items += +- spec->num_dmics - +- (ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1); + +- err = stac92xx_parse_auto_config(codec, 0x21, 0x23); ++ err = stac92xx_parse_auto_config(codec, 0x21, 0); + if (!err) { + if (spec->board_config < 0) { + printk(KERN_WARNING "hda_codec: No auto-config is " +@@ -4889,7 +5355,7 @@ + } + + return 0; +-}; ++} + + static int patch_stac922x(struct hda_codec *codec) + { +@@ -4967,7 +5433,10 @@ + spec->num_pwrs = 0; + + spec->init = stac922x_core_init; +- spec->mixer = stac922x_mixer; ++ ++ spec->num_caps = STAC922X_NUM_CAPS; ++ spec->capvols = stac922x_capvols; ++ spec->capsws = stac922x_capsws; + + spec->multiout.dac_nids = spec->dac_nids; + +@@ -5008,6 +5477,7 @@ + return -ENOMEM; + + codec->spec = spec; ++ codec->slave_dig_outs = stac927x_slave_dig_outs; + spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); + spec->pin_nids = stac927x_pin_nids; + spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, +@@ -5049,32 +5519,37 @@ + spec->num_dmics = 0; + + spec->init = d965_core_init; +- spec->mixer = stac927x_mixer; + break; + case STAC_DELL_BIOS: + switch (codec->subsystem_id) { + case 0x10280209: + case 0x1028022e: + /* correct the device field to SPDIF out */ +- stac92xx_set_config_reg(codec, 0x21, 0x01442070); ++ snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); + break; +- }; ++ } + /* configure the analog microphone on some laptops */ +- stac92xx_set_config_reg(codec, 0x0c, 0x90a79130); ++ snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); + /* correct the front output jack as a hp out */ +- stac92xx_set_config_reg(codec, 0x0f, 0x0227011f); ++ snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f); + /* correct the front input jack as a mic */ +- stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); ++ snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130); + /* fallthru */ + case STAC_DELL_3ST: + /* GPIO2 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x04; + spec->gpio_data = 0x04; ++ switch (codec->subsystem_id) { ++ case 0x1028022f: ++ /* correct EAPD to be GPIO0 */ ++ spec->eapd_mask = spec->gpio_mask = 0x01; ++ spec->gpio_dir = spec->gpio_data = 0x01; ++ break; ++ }; + spec->dmic_nids = stac927x_dmic_nids; + spec->num_dmics = STAC927X_NUM_DMICS; + + spec->init = d965_core_init; +- spec->mixer = stac927x_mixer; + spec->dmux_nids = stac927x_dmux_nids; + spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); + break; +@@ -5087,12 +5562,13 @@ + spec->num_dmics = 0; + + spec->init = stac927x_core_init; +- spec->mixer = stac927x_mixer; + } + ++ spec->num_caps = STAC927X_NUM_CAPS; ++ spec->capvols = stac927x_capvols; ++ spec->capsws = stac927x_capsws; ++ + spec->num_pwrs = 0; +- spec->aloopback_mask = 0x40; +- spec->aloopback_shift = 0; + spec->eapd_switch = 1; + + err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); +@@ -5174,10 +5650,11 @@ + spec->num_pwrs = 0; + + spec->init = stac9205_core_init; +- spec->mixer = stac9205_mixer; + +- spec->aloopback_mask = 0x40; +- spec->aloopback_shift = 0; ++ spec->num_caps = STAC9205_NUM_CAPS; ++ spec->capvols = stac9205_capvols; ++ spec->capsws = stac9205_capsws; ++ + /* Turn on/off EAPD per HP plugging */ + if (spec->board_config != STAC_9205_EAPD) + spec->eapd_switch = 1; +@@ -5186,8 +5663,8 @@ + switch (spec->board_config){ + case STAC_9205_DELL_M43: + /* Enable SPDIF in/out */ +- stac92xx_set_config_reg(codec, 0x1f, 0x01441030); +- stac92xx_set_config_reg(codec, 0x20, 0x1c410030); ++ snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030); ++ snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030); + + /* Enable unsol response for GPIO4/Dock HP connection */ + err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); +@@ -5521,6 +5998,7 @@ + { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, + { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, + { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, ++ { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 }, + { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, + { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, + { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, +@@ -5532,6 +6010,7 @@ + { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, + { .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx}, ++ { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, + { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, + { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-stac-lo-detect-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-stac-lo-detect-fix new file mode 100644 index 000000000..d4d366999 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-stac-lo-detect-fix @@ -0,0 +1,30 @@ +From 1c4bdf9be010ae7c2324c0a90dd2296e0d1a775e Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 13 Aug 2009 08:23:24 +0200 +Subject: ALSA: hda - Enable line-out detection only with speakers +Patch-mainline: +References: bnc#520975 + +Enable line-out detection for IDT/STAC codecs only when speaker pins +exist. In some cases, the speaker itself is identified as line-out, +and this confuses the situation. Only the extra line-outs should do +auto-muting. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -4158,7 +4158,8 @@ + hda_nid_t nid = cfg->hp_pins[i]; + enable_pin_detect(codec, nid, STAC_HP_EVENT); + } +- if (cfg->line_out_type == AUTO_PIN_LINE_OUT) { ++ if (cfg->line_out_type == AUTO_PIN_LINE_OUT && ++ cfg->speaker_outs > 0) { + /* enable pin-detect for line-outs as well */ + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sync-verbs b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sync-verbs new file mode 100644 index 000000000..d51f3a5c4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hda-sync-verbs @@ -0,0 +1,139 @@ +From: Takashi Iwai +Subject: ALSA: hda - Support sync after writing a verb +Patch-mainline: +References: bnc#502903 + +This patch adds a debug mode to make the codec communication +synchronous. Define SND_HDA_SUPPORT_SYNC_WRITE in hda_codec.c, +and the call of snd_hda_codec_write*() will become synchronous, +i.e. wait for the reply from the codec at each time issuing a verb. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/hda_codec.c | 87 +++++++++++++++++++++++++--------------------- + 1 file changed, 49 insertions(+), 38 deletions(-) + +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -176,6 +176,27 @@ + >> AC_DEFCFG_DEVICE_SHIFT]; + } + ++/* ++ * Send and receive a verb ++ */ ++static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, ++ unsigned int *res) ++{ ++ struct hda_bus *bus = codec->bus; ++ int err; ++ ++ if (res) ++ *res = -1; ++ snd_hda_power_up(codec); ++ mutex_lock(&bus->cmd_mutex); ++ err = bus->ops.command(bus, cmd); ++ if (!err && res) ++ *res = bus->ops.get_response(bus); ++ mutex_unlock(&bus->cmd_mutex); ++ snd_hda_power_down(codec); ++ return err; ++} ++ + /** + * snd_hda_codec_read - send a command and get the response + * @codec: the HDA codec +@@ -192,21 +213,17 @@ + int direct, + unsigned int verb, unsigned int parm) + { +- struct hda_bus *bus = codec->bus; ++ unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); + unsigned int res; +- +- res = make_codec_cmd(codec, nid, direct, verb, parm); +- snd_hda_power_up(codec); +- mutex_lock(&bus->cmd_mutex); +- if (!bus->ops.command(bus, res)) +- res = bus->ops.get_response(bus); +- else +- res = (unsigned int)-1; +- mutex_unlock(&bus->cmd_mutex); +- snd_hda_power_down(codec); ++ codec_exec_verb(codec, cmd, &res); + return res; + } + ++/* Define the below to send and receive verbs synchronously. ++ * If you often get any codec communication errors, this is worth to try. ++ */ ++#define SND_HDA_SUPPORT_SYNC_WRITE ++ + /** + * snd_hda_codec_write - send a single command without waiting for response + * @codec: the HDA codec +@@ -222,17 +239,13 @@ + int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int parm) + { +- struct hda_bus *bus = codec->bus; ++ unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); ++#ifdef SND_HDA_SUPPORT_SYNC_WRITE + unsigned int res; +- int err; +- +- res = make_codec_cmd(codec, nid, direct, verb, parm); +- snd_hda_power_up(codec); +- mutex_lock(&bus->cmd_mutex); +- err = bus->ops.command(bus, res); +- mutex_unlock(&bus->cmd_mutex); +- snd_hda_power_down(codec); +- return err; ++ return codec_exec_verb(codec, cmd, &res); ++#else ++ return codec_exec_verb(codec, cmd, NULL); ++#endif + } + + /** +@@ -1876,24 +1889,22 @@ + int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) + { +- struct hda_bus *bus = codec->bus; +- unsigned int res; +- int err; ++ int err = snd_hda_codec_write(codec, nid, direct, verb, parm); ++ struct hda_cache_head *c; ++ u32 key; + +- res = make_codec_cmd(codec, nid, direct, verb, parm); +- snd_hda_power_up(codec); +- mutex_lock(&bus->cmd_mutex); +- err = bus->ops.command(bus, res); +- if (!err) { +- struct hda_cache_head *c; +- u32 key = build_cmd_cache_key(nid, verb); +- c = get_alloc_hash(&codec->cmd_cache, key); +- if (c) +- c->val = parm; +- } +- mutex_unlock(&bus->cmd_mutex); +- snd_hda_power_down(codec); +- return err; ++ if (err < 0) ++ return err; ++ /* parm may contain the verb stuff for get/set amp */ ++ verb = verb | (parm >> 8); ++ parm &= 0xff; ++ key = build_cmd_cache_key(nid, verb); ++ mutex_lock(&codec->bus->cmd_mutex); ++ c = get_alloc_hash(&codec->cmd_cache, key); ++ if (c) ++ c->val = parm; ++ mutex_unlock(&codec->bus->cmd_mutex); ++ return 0; + } + + /* resume the all commands from the cache */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-ad1984a-mobile-mute-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-ad1984a-mobile-mute-fix new file mode 100644 index 000000000..96fe2ebf0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-ad1984a-mobile-mute-fix @@ -0,0 +1,64 @@ +From 1a0aa9b7d709547bb9dec1f31e48754318ff121a Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 2 Jul 2009 16:10:23 +0200 +Subject: ALSA: hda - Add GPIO1 control at muting with HP laptops +Patch-mainline: +References: bnc#515266,bnc#522764 + +HP laptops with AD1984A codecs (at least mobile models) need to set +GPIO1 appropriately to indicate the mute state. The BIOS checks this +bit to judge whether the mute on or off is sent via F8 key. +Without changing this bit, the BIOS can be confused and may toggle +the mute wrongly. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_analog.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +--- a/sound/pci/hda/patch_analog.c ++++ b/sound/pci/hda/patch_analog.c +@@ -3713,9 +3713,30 @@ + { } /* end */ + }; + ++static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); ++ int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); ++ int mute = (!ucontrol->value.integer.value[0] && ++ !ucontrol->value.integer.value[1]); ++ /* toggle GPIO1 according to the mute state */ ++ snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, ++ mute ? 0x02 : 0x0); ++ return ret; ++} ++ + static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { + HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), +- HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), ++ /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = snd_hda_mixer_amp_switch_info, ++ .get = snd_hda_mixer_amp_switch_get, ++ .put = ad1884a_mobile_master_sw_put, ++ .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), ++ }, + HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), +@@ -3838,6 +3859,10 @@ + /* unsolicited event for pin-sense */ + {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, ++ /* allow to touch GPIO1 (for mute control) */ ++ {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, ++ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, ++ {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ + { } /* end */ + }; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-dv6736-mic-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-dv6736-mic-fix new file mode 100644 index 000000000..b090e5d8f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-dv6736-mic-fix @@ -0,0 +1,168 @@ +From 79d7d5333b598e9a559bf27833f0ad2b8bf6ad2c Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 4 Mar 2009 09:03:50 +0100 +Subject: ALSA: hda - Fix HP dv6736 mic input +Patch-mainline: +References: bnc#480753 + +Fix the mic input of HP dv6736 with Conexant 5051 codec chip. +This laptop seems have no mic-switching per jack connection. +A new model hp-dv6736 is introduced to match with the h/w implementation. + +Reference: Novell bnc#480753 + https://bugzilla.novell.com/show_bug.cgi?id=480753 + +Signed-off-by: Takashi Iwai +Acked-by: Takashi Iwai + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_conexant.c | 63 ++++++++++++++++++++++-- + 2 files changed, 59 insertions(+), 5 deletions(-) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -1016,6 +1016,7 @@ + Conexant 5051 + laptop Basic Laptop config (default) + hp HP Spartan laptop ++ hp-dv6736 HP dv6736 + lenovo-x200 Lenovo X200 laptop + + STAC9200 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -58,6 +58,7 @@ + */ + unsigned int cur_eapd; + unsigned int hp_present; ++ unsigned int no_auto_mic; + unsigned int need_dac_fix; + + /* capture */ +@@ -1571,8 +1572,11 @@ + /* toggle input of built-in and mic jack appropriately */ + static void cxt5051_portb_automic(struct hda_codec *codec) + { ++ struct conexant_spec *spec = codec->spec; + unsigned int present; + ++ if (spec->no_auto_mic) ++ return; + present = snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_PIN_SENSE, 0) & + AC_PINSENSE_PRESENCE; +@@ -1588,6 +1592,8 @@ + unsigned int present; + hda_nid_t new_adc; + ++ if (spec->no_auto_mic) ++ return; + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & + AC_PINSENSE_PRESENCE; +@@ -1672,6 +1678,22 @@ + {} + }; + ++static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { ++ HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT), ++ HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT), ++ HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "Master Playback Switch", ++ .info = cxt_eapd_info, ++ .get = cxt_eapd_get, ++ .put = cxt5051_hp_master_sw_put, ++ .private_value = 0x1a, ++ }, ++ ++ {} ++}; ++ + static struct hda_verb cxt5051_init_verbs[] = { + /* Line in, Mic */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, +@@ -1702,6 +1724,32 @@ + { } /* end */ + }; + ++static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { ++ /* Line in, Mic */ ++ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, ++ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, ++ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, ++ /* SPK */ ++ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* HP, Amp */ ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* DAC1 */ ++ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ /* Record selector: Int mic */ ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, ++ {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, ++ /* SPDIF route: PCM */ ++ {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, ++ /* EAPD */ ++ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ ++ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, ++ {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, ++ { } /* end */ ++}; ++ + static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { + /* Line in, Mic */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, +@@ -1752,6 +1800,7 @@ + enum { + CXT5051_LAPTOP, /* Laptops w/ EAPD support */ + CXT5051_HP, /* no docking */ ++ CXT5051_HP_DV6736, /* HP without mic switch */ + CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ + CXT5051_MODELS + }; +@@ -1759,10 +1808,12 @@ + static const char *cxt5051_models[CXT5051_MODELS] = { + [CXT5051_LAPTOP] = "laptop", + [CXT5051_HP] = "hp", ++ [CXT5051_HP_DV6736] = "hp-dv6736", + [CXT5051_LENOVO_X200] = "lenovo-x200", + }; + + static struct snd_pci_quirk cxt5051_cfg_tbl[] = { ++ SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), + SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", + CXT5051_LAPTOP), + SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), +@@ -1799,20 +1850,22 @@ + spec->cur_adc = 0; + spec->cur_adc_idx = 0; + ++ codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; ++ + board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, + cxt5051_models, + cxt5051_cfg_tbl); + switch (board_config) { + case CXT5051_HP: +- codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; + spec->mixers[0] = cxt5051_hp_mixers; + break; ++ case CXT5051_HP_DV6736: ++ spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; ++ spec->mixers[0] = cxt5051_hp_dv6736_mixers; ++ spec->no_auto_mic = 1; ++ break; + case CXT5051_LENOVO_X200: + spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; +- /* fallthru */ +- default: +- case CXT5051_LAPTOP: +- codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; + break; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-piaget-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-piaget-quirk new file mode 100644 index 000000000..8e58f1992 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-hp-piaget-quirk @@ -0,0 +1,22 @@ +From: Takashi Iwai +Subject: ALSA: Add quirk for new HP laptops +Patch-mainline: +References: bnc#527284 + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -1733,6 +1733,8 @@ + "HP mini 1000", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b, + "HP HDX", STAC_HP_HDX), /* HDX16 */ ++ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, ++ "HP", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, + "unknown Dell", STAC_DELL_M4_1), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-ideapad-44khz-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-ideapad-44khz-fix new file mode 100644 index 000000000..dea38d96d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-ideapad-44khz-fix @@ -0,0 +1,66 @@ +From: Takashi Iwai +Subject: ALSA: Fix sample rate of Lenovo Ideapad to 44.1kHz +Patch-mainline: +References: bnc#480391 + +Noises can be heard on analog outputs of (some model of) Lenovo +Ideapad due to the hardware problem, and the only workaround right now +is to fix the sample rate to 44.1kHz. + +Signed-off-by: Takashi Iwai +Acked-by: Takashi Iwai + +--- + sound/pci/hda/patch_realtek.c | 34 +++++++++++++++++++++++++++++++--- + 1 file changed, 31 insertions(+), 3 deletions(-) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -12339,6 +12339,27 @@ static int alc269_auto_create_analog_inp + #define alc269_pcm_digital_playback alc880_pcm_digital_playback + #define alc269_pcm_digital_capture alc880_pcm_digital_capture + ++static struct hda_pcm_stream alc269_44k_pcm_analog_playback = { ++ .substreams = 1, ++ .channels_min = 2, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ ++ /* NID is set in alc_build_pcms */ ++ .ops = { ++ .open = alc880_playback_pcm_open, ++ .prepare = alc880_playback_pcm_prepare, ++ .cleanup = alc880_playback_pcm_cleanup ++ }, ++}; ++ ++static struct hda_pcm_stream alc269_44k_pcm_analog_capture = { ++ .substreams = 1, ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ ++ /* NID is set in alc_build_pcms */ ++}; ++ + /* + * BIOS auto configuration + */ +@@ -12540,9 +12561,16 @@ static int patch_alc269(struct hda_codec + setup_preset(spec, &alc269_presets[board_config]); + + spec->stream_name_analog = "ALC269 Analog"; +- spec->stream_analog_playback = &alc269_pcm_analog_playback; +- spec->stream_analog_capture = &alc269_pcm_analog_capture; +- ++ if (codec->subsystem_id == 0x17aa3bf8) { ++ /* Due to a hardware problem on Lenovo Ideadpad, we need to ++ * fix the sample rate of analog I/O to 44.1kHz ++ */ ++ spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; ++ spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; ++ } else { ++ spec->stream_analog_playback = &alc269_pcm_analog_playback; ++ spec->stream_analog_capture = &alc269_pcm_analog_capture; ++ } + spec->stream_name_digital = "ALC269 Digital"; + spec->stream_digital_playback = &alc269_pcm_digital_playback; + spec->stream_digital_capture = &alc269_pcm_digital_capture; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-lenovo-x200-quirk b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-lenovo-x200-quirk new file mode 100644 index 000000000..d853a6526 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-lenovo-x200-quirk @@ -0,0 +1,106 @@ +From 27e089888fb1a3d1d13892262f9d522b03985044 Mon Sep 17 00:00:00 2001 +From: Aristeu Sergio Rozanski Filho +Date: Thu, 12 Feb 2009 17:50:37 -0500 +Subject: ALSA: hda: add quirk for Lenovo X200 laptop dock +Patch-mainline: +References: bnc#480753 + +Currently the HP connector on X200 dock doesn't detect when a HP is connected +nor allows sound to be played using it. This patch fixes the problem by adding +a quirk for this specific model. It's possible that others have the same NID +(0x19) to report when dock HP is connected, but I don't have access to any. +Please Cc me in the reply since I'm not subscribed to alsa-devel@. + +Signed-off-by: Aristeu Rozanski +Signed-off-by: Takashi Iwai + +--- + Documentation/sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_conexant.c | 40 ++++++++++++++++++++++++ + 2 files changed, 41 insertions(+) + +--- a/Documentation/sound/alsa/ALSA-Configuration.txt ++++ b/Documentation/sound/alsa/ALSA-Configuration.txt +@@ -1016,6 +1016,7 @@ + Conexant 5051 + laptop Basic Laptop config (default) + hp HP Spartan laptop ++ lenovo-x200 Lenovo X200 laptop + + STAC9200 + ref Reference board +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -1702,6 +1702,40 @@ + { } /* end */ + }; + ++static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { ++ /* Line in, Mic */ ++ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, ++ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, ++ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, ++ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, ++ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, ++ /* SPK */ ++ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, ++ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* HP, Amp */ ++ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* Docking HP */ ++ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, ++ {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, ++ /* DAC1 */ ++ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, ++ /* Record selector: Int mic */ ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, ++ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, ++ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, ++ /* SPDIF route: PCM */ ++ {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, ++ /* EAPD */ ++ {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ ++ {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, ++ {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, ++ {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, ++ {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, ++ { } /* end */ ++}; ++ + /* initialize jack-sensing, too */ + static int cxt5051_init(struct hda_codec *codec) + { +@@ -1718,18 +1752,21 @@ + enum { + CXT5051_LAPTOP, /* Laptops w/ EAPD support */ + CXT5051_HP, /* no docking */ ++ CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ + CXT5051_MODELS + }; + + static const char *cxt5051_models[CXT5051_MODELS] = { + [CXT5051_LAPTOP] = "laptop", + [CXT5051_HP] = "hp", ++ [CXT5051_LENOVO_X200] = "lenovo-x200", + }; + + static struct snd_pci_quirk cxt5051_cfg_tbl[] = { + SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", + CXT5051_LAPTOP), + SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), ++ SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), + {} + }; + +@@ -1770,6 +1807,9 @@ + codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; + spec->mixers[0] = cxt5051_hp_mixers; + break; ++ case CXT5051_LENOVO_X200: ++ spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; ++ /* fallthru */ + default: + case CXT5051_LAPTOP: + codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-stac-hp-detect-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-stac-hp-detect-fix new file mode 100644 index 000000000..ee493186a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-post-ga-stac-hp-detect-fix @@ -0,0 +1,42 @@ +From ffd0e56c606836581da5df742a43ce8015ca7475 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Subject: ALSA: hda - Fix headphone-detection on some machines with STAC/IDT codecs +Patch-mainline: 2.6.30-rc3 +References: bnc#495515 + +When the headphone can have no unique DAC, the current code doesn't +check the HP-detection although it should. Put the hp-detection check +before the DAC check to fix this bug. + +Signed-off-by: Takashi Iwai + +--- + sound/pci/hda/patch_sigmatel.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/sound/pci/hda/patch_sigmatel.c ++++ b/sound/pci/hda/patch_sigmatel.c +@@ -3025,6 +3025,11 @@ + unsigned int wid_caps; + + for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { ++ if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { ++ wid_caps = get_wcaps(codec, pins[i]); ++ if (wid_caps & AC_WCAP_UNSOL_CAP) ++ spec->hp_detect = 1; ++ } + nid = dac_nids[i]; + if (!nid) + continue; +@@ -3064,11 +3069,6 @@ + err = create_controls(codec, name, nid, 3); + if (err < 0) + return err; +- if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { +- wid_caps = get_wcaps(codec, pins[i]); +- if (wid_caps & AC_WCAP_UNSOL_CAP) +- spec->hp_detect = 1; +- } + } + } + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-powermac-ibook-g4-mic-fix b/src/patches/suse-2.6.27.31/patches.drivers/alsa-powermac-ibook-g4-mic-fix new file mode 100644 index 000000000..e393033a5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/alsa-powermac-ibook-g4-mic-fix @@ -0,0 +1,26 @@ +From: Takashi Iwai +Subject: ALSA: powermac - Rename mic-analog loopback mixer element +Patch-mainline: +References: bnc#444194 + +PCM Playback Volume:1 is actually assigned to a mic loopback volume +on iBook G4. Let's rename it. + +Signed-off-by: Takashi Iwai + +--- + sound/ppc/tumbler.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/sound/ppc/tumbler.c ++++ b/sound/ppc/tumbler.c +@@ -879,7 +879,8 @@ static struct snd_kcontrol_new snapper_m + .put = tumbler_put_master_switch + }, + DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM), +- DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2), ++ /* Alternative PCM is assigned to Mic analog loopback on iBook G4 */ ++ DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2), + DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC), + DEFINE_SNAPPER_MONO("Tone Control - Bass", bass), + DEFINE_SNAPPER_MONO("Tone Control - Treble", treble), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/atl1-add-device_set_wakeup_enable-to-atl1-_set_wol.patch b/src/patches/suse-2.6.27.31/patches.drivers/atl1-add-device_set_wakeup_enable-to-atl1-_set_wol.patch new file mode 100644 index 000000000..e5300572b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/atl1-add-device_set_wakeup_enable-to-atl1-_set_wol.patch @@ -0,0 +1,31 @@ +From: Brandon Philips +Subject: [PATCH] atl1e: add device_set_wakeup_enable to atl1e_set_wol +References: bnc#493214 + +Tell PCI core that atl1e can wakeup the system when WOL is +enabled by calling device_set_wakeup_enable. + +Joerg noted that his atl1e device WOL fine after enabling it with +ethtool and changing /sys/class/net/eth0/device/power/wakeup to enabled +Tested on atl1e: https://bugzilla.novell.com/show_bug.cgi?id=493214 + +Tested by: Joerg Reuter +Signed-off-by: Brandon Philips + +--- + drivers/net/atl1e/atl1e_ethtool.c | 2 ++ + 1 file changed, 2 insertions(+) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/atl1e/atl1e_ethtool.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/atl1e/atl1e_ethtool.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/atl1e/atl1e_ethtool.c +@@ -365,6 +365,8 @@ static int atl1e_set_wol(struct net_devi + if (wol->wolopts & WAKE_PHY) + adapter->wol |= AT_WUFC_LNKC; + ++ device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/atl2-add-atl2-network-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/atl2-add-atl2-network-driver.patch new file mode 100644 index 000000000..92d18e178 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/atl2-add-atl2-network-driver.patch @@ -0,0 +1,3730 @@ +Subject: atl2: add atl2 network driver +From: Chris Snook +Patch-mainline: 2.6.28 + +Driver for Atheros L2 10/100 network device. Includes necessary +changes for Kconfig, Makefile, and pci_ids.h. + +Signed-off-by: Chris Snook +Signed-off-by: Jay Cliburn +Signed-off-by: Greg Kroah-Hartman +--- + +--- + drivers/net/Kconfig | 11 + drivers/net/Makefile | 1 + drivers/net/atlx/Makefile | 2 + drivers/net/atlx/atl2.c | 3127 ++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/atlx/atl2.h | 530 +++++++ + include/linux/pci_ids.h | 1 + 6 files changed, 3672 insertions(+) + +--- /dev/null ++++ b/drivers/net/atlx/atl2.c +@@ -0,0 +1,3127 @@ ++/* ++ * Copyright(c) 2006 - 2007 Atheros Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2008 Chris Snook ++ * ++ * Derived from Intel e1000 driver ++ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "atl2.h" ++ ++#define ATL2_DRV_VERSION "2.2.3" ++ ++static char atl2_driver_name[] = "atl2"; ++static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver"; ++static char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation."; ++static char atl2_driver_version[] = ATL2_DRV_VERSION; ++ ++MODULE_AUTHOR("Atheros Corporation , Chris Snook "); ++MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(ATL2_DRV_VERSION); ++ ++/* ++ * atl2_pci_tbl - PCI Device ID Table ++ */ ++static struct pci_device_id atl2_pci_tbl[] = { ++ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)}, ++ /* required last entry */ ++ {0,} ++}; ++MODULE_DEVICE_TABLE(pci, atl2_pci_tbl); ++ ++static void atl2_set_ethtool_ops(struct net_device *netdev); ++ ++static void atl2_check_options(struct atl2_adapter *adapter); ++ ++/* ++ * atl2_sw_init - Initialize general software structures (struct atl2_adapter) ++ * @adapter: board private structure to initialize ++ * ++ * atl2_sw_init initializes the Adapter private data structure. ++ * Fields are initialized based on PCI device information and ++ * OS network device settings (MTU size). ++ */ ++static int __devinit atl2_sw_init(struct atl2_adapter *adapter) ++{ ++ struct atl2_hw *hw = &adapter->hw; ++ struct pci_dev *pdev = adapter->pdev; ++ ++ /* PCI config space info */ ++ hw->vendor_id = pdev->vendor; ++ hw->device_id = pdev->device; ++ hw->subsystem_vendor_id = pdev->subsystem_vendor; ++ hw->subsystem_id = pdev->subsystem_device; ++ ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); ++ pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); ++ ++ adapter->wol = 0; ++ adapter->ict = 50000; /* ~100ms */ ++ adapter->link_speed = SPEED_0; /* hardware init */ ++ adapter->link_duplex = FULL_DUPLEX; ++ ++ hw->phy_configured = false; ++ hw->preamble_len = 7; ++ hw->ipgt = 0x60; ++ hw->min_ifg = 0x50; ++ hw->ipgr1 = 0x40; ++ hw->ipgr2 = 0x60; ++ hw->retry_buf = 2; ++ hw->max_retry = 0xf; ++ hw->lcol = 0x37; ++ hw->jam_ipg = 7; ++ hw->fc_rxd_hi = 0; ++ hw->fc_rxd_lo = 0; ++ hw->max_frame_size = adapter->netdev->mtu; ++ ++ spin_lock_init(&adapter->stats_lock); ++ spin_lock_init(&adapter->tx_lock); ++ ++ set_bit(__ATL2_DOWN, &adapter->flags); ++ ++ return 0; ++} ++ ++/* ++ * atl2_set_multi - Multicast and Promiscuous mode set ++ * @netdev: network interface device structure ++ * ++ * The set_multi entry point is called whenever the multicast address ++ * list or the network interface flags are updated. This routine is ++ * responsible for configuring the hardware for proper multicast, ++ * promiscuous mode, and all-multi behavior. ++ */ ++static void atl2_set_multi(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ struct dev_mc_list *mc_ptr; ++ u32 rctl; ++ u32 hash_value; ++ ++ /* Check for Promiscuous and All Multicast modes */ ++ rctl = ATL2_READ_REG(hw, REG_MAC_CTRL); ++ ++ if (netdev->flags & IFF_PROMISC) { ++ rctl |= MAC_CTRL_PROMIS_EN; ++ } else if (netdev->flags & IFF_ALLMULTI) { ++ rctl |= MAC_CTRL_MC_ALL_EN; ++ rctl &= ~MAC_CTRL_PROMIS_EN; ++ } else ++ rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); ++ ++ ATL2_WRITE_REG(hw, REG_MAC_CTRL, rctl); ++ ++ /* clear the old settings from the multicast hash table */ ++ ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); ++ ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); ++ ++ /* comoute mc addresses' hash value ,and put it into hash table */ ++ for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { ++ hash_value = atl2_hash_mc_addr(hw, mc_ptr->dmi_addr); ++ atl2_hash_set(hw, hash_value); ++ } ++} ++ ++static void init_ring_ptrs(struct atl2_adapter *adapter) ++{ ++ /* Read / Write Ptr Initialize: */ ++ adapter->txd_write_ptr = 0; ++ atomic_set(&adapter->txd_read_ptr, 0); ++ ++ adapter->rxd_read_ptr = 0; ++ adapter->rxd_write_ptr = 0; ++ ++ atomic_set(&adapter->txs_write_ptr, 0); ++ adapter->txs_next_clear = 0; ++} ++ ++/* ++ * atl2_configure - Configure Transmit&Receive Unit after Reset ++ * @adapter: board private structure ++ * ++ * Configure the Tx /Rx unit of the MAC after a reset. ++ */ ++static int atl2_configure(struct atl2_adapter *adapter) ++{ ++ struct atl2_hw *hw = &adapter->hw; ++ u32 value; ++ ++ /* clear interrupt status */ ++ ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff); ++ ++ /* set MAC Address */ ++ value = (((u32)hw->mac_addr[2]) << 24) | ++ (((u32)hw->mac_addr[3]) << 16) | ++ (((u32)hw->mac_addr[4]) << 8) | ++ (((u32)hw->mac_addr[5])); ++ ATL2_WRITE_REG(hw, REG_MAC_STA_ADDR, value); ++ value = (((u32)hw->mac_addr[0]) << 8) | ++ (((u32)hw->mac_addr[1])); ++ ATL2_WRITE_REG(hw, (REG_MAC_STA_ADDR+4), value); ++ ++ /* HI base address */ ++ ATL2_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, ++ (u32)((adapter->ring_dma & 0xffffffff00000000ULL) >> 32)); ++ ++ /* LO base address */ ++ ATL2_WRITE_REG(hw, REG_TXD_BASE_ADDR_LO, ++ (u32)(adapter->txd_dma & 0x00000000ffffffffULL)); ++ ATL2_WRITE_REG(hw, REG_TXS_BASE_ADDR_LO, ++ (u32)(adapter->txs_dma & 0x00000000ffffffffULL)); ++ ATL2_WRITE_REG(hw, REG_RXD_BASE_ADDR_LO, ++ (u32)(adapter->rxd_dma & 0x00000000ffffffffULL)); ++ ++ /* element count */ ++ ATL2_WRITE_REGW(hw, REG_TXD_MEM_SIZE, (u16)(adapter->txd_ring_size/4)); ++ ATL2_WRITE_REGW(hw, REG_TXS_MEM_SIZE, (u16)adapter->txs_ring_size); ++ ATL2_WRITE_REGW(hw, REG_RXD_BUF_NUM, (u16)adapter->rxd_ring_size); ++ ++ /* config Internal SRAM */ ++/* ++ ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_tx_end); ++ ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_rx_end); ++*/ ++ ++ /* config IPG/IFG */ ++ value = (((u32)hw->ipgt & MAC_IPG_IFG_IPGT_MASK) << ++ MAC_IPG_IFG_IPGT_SHIFT) | ++ (((u32)hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) << ++ MAC_IPG_IFG_MIFG_SHIFT) | ++ (((u32)hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) << ++ MAC_IPG_IFG_IPGR1_SHIFT)| ++ (((u32)hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) << ++ MAC_IPG_IFG_IPGR2_SHIFT); ++ ATL2_WRITE_REG(hw, REG_MAC_IPG_IFG, value); ++ ++ /* config Half-Duplex Control */ ++ value = ((u32)hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | ++ (((u32)hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) << ++ MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | ++ MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | ++ (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | ++ (((u32)hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) << ++ MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); ++ ATL2_WRITE_REG(hw, REG_MAC_HALF_DUPLX_CTRL, value); ++ ++ /* set Interrupt Moderator Timer */ ++ ATL2_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt); ++ ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_ITIMER_EN); ++ ++ /* set Interrupt Clear Timer */ ++ ATL2_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, adapter->ict); ++ ++ /* set MTU */ ++ ATL2_WRITE_REG(hw, REG_MTU, adapter->netdev->mtu + ++ ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE); ++ ++ /* 1590 */ ++ ATL2_WRITE_REG(hw, REG_TX_CUT_THRESH, 0x177); ++ ++ /* flow control */ ++ ATL2_WRITE_REGW(hw, REG_PAUSE_ON_TH, hw->fc_rxd_hi); ++ ATL2_WRITE_REGW(hw, REG_PAUSE_OFF_TH, hw->fc_rxd_lo); ++ ++ /* Init mailbox */ ++ ATL2_WRITE_REGW(hw, REG_MB_TXD_WR_IDX, (u16)adapter->txd_write_ptr); ++ ATL2_WRITE_REGW(hw, REG_MB_RXD_RD_IDX, (u16)adapter->rxd_read_ptr); ++ ++ /* enable DMA read/write */ ++ ATL2_WRITE_REGB(hw, REG_DMAR, DMAR_EN); ++ ATL2_WRITE_REGB(hw, REG_DMAW, DMAW_EN); ++ ++ value = ATL2_READ_REG(&adapter->hw, REG_ISR); ++ if ((value & ISR_PHY_LINKDOWN) != 0) ++ value = 1; /* config failed */ ++ else ++ value = 0; ++ ++ /* clear all interrupt status */ ++ ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0x3fffffff); ++ ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); ++ return value; ++} ++ ++/* ++ * atl2_setup_ring_resources - allocate Tx / RX descriptor resources ++ * @adapter: board private structure ++ * ++ * Return 0 on success, negative on failure ++ */ ++static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ int size; ++ u8 offset = 0; ++ ++ /* real ring DMA buffer */ ++ adapter->ring_size = size = ++ adapter->txd_ring_size * 1 + 7 + /* dword align */ ++ adapter->txs_ring_size * 4 + 7 + /* dword align */ ++ adapter->rxd_ring_size * 1536 + 127; /* 128bytes align */ ++ ++ adapter->ring_vir_addr = pci_alloc_consistent(pdev, size, ++ &adapter->ring_dma); ++ if (!adapter->ring_vir_addr) ++ return -ENOMEM; ++ memset(adapter->ring_vir_addr, 0, adapter->ring_size); ++ ++ /* Init TXD Ring */ ++ adapter->txd_dma = adapter->ring_dma ; ++ offset = (adapter->txd_dma & 0x7) ? (8 - (adapter->txd_dma & 0x7)) : 0; ++ adapter->txd_dma += offset; ++ adapter->txd_ring = (struct tx_pkt_header *) (adapter->ring_vir_addr + ++ offset); ++ ++ /* Init TXS Ring */ ++ adapter->txs_dma = adapter->txd_dma + adapter->txd_ring_size; ++ offset = (adapter->txs_dma & 0x7) ? (8 - (adapter->txs_dma & 0x7)) : 0; ++ adapter->txs_dma += offset; ++ adapter->txs_ring = (struct tx_pkt_status *) ++ (((u8 *)adapter->txd_ring) + (adapter->txd_ring_size + offset)); ++ ++ /* Init RXD Ring */ ++ adapter->rxd_dma = adapter->txs_dma + adapter->txs_ring_size * 4; ++ offset = (adapter->rxd_dma & 127) ? ++ (128 - (adapter->rxd_dma & 127)) : 0; ++ if (offset > 7) ++ offset -= 8; ++ else ++ offset += (128 - 8); ++ ++ adapter->rxd_dma += offset; ++ adapter->rxd_ring = (struct rx_desc *) (((u8 *)adapter->txs_ring) + ++ (adapter->txs_ring_size * 4 + offset)); ++ ++/* ++ * Read / Write Ptr Initialize: ++ * init_ring_ptrs(adapter); ++ */ ++ return 0; ++} ++ ++/* ++ * atl2_irq_enable - Enable default interrupt generation settings ++ * @adapter: board private structure ++ */ ++static inline void atl2_irq_enable(struct atl2_adapter *adapter) ++{ ++ ATL2_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK); ++ ATL2_WRITE_FLUSH(&adapter->hw); ++} ++ ++/* ++ * atl2_irq_disable - Mask off interrupt generation on the NIC ++ * @adapter: board private structure ++ */ ++static inline void atl2_irq_disable(struct atl2_adapter *adapter) ++{ ++ ATL2_WRITE_REG(&adapter->hw, REG_IMR, 0); ++ ATL2_WRITE_FLUSH(&adapter->hw); ++ synchronize_irq(adapter->pdev->irq); ++} ++ ++#ifdef NETIF_F_HW_VLAN_TX ++static void atl2_vlan_rx_register(struct net_device *netdev, ++ struct vlan_group *grp) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ u32 ctrl; ++ ++ atl2_irq_disable(adapter); ++ adapter->vlgrp = grp; ++ ++ if (grp) { ++ /* enable VLAN tag insert/strip */ ++ ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); ++ ctrl |= MAC_CTRL_RMV_VLAN; ++ ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); ++ } else { ++ /* disable VLAN tag insert/strip */ ++ ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); ++ ctrl &= ~MAC_CTRL_RMV_VLAN; ++ ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); ++ } ++ ++ atl2_irq_enable(adapter); ++} ++ ++static void atl2_restore_vlan(struct atl2_adapter *adapter) ++{ ++ atl2_vlan_rx_register(adapter->netdev, adapter->vlgrp); ++} ++#endif ++ ++static void atl2_intr_rx(struct atl2_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ struct rx_desc *rxd; ++ struct sk_buff *skb; ++ ++ do { ++ rxd = adapter->rxd_ring+adapter->rxd_write_ptr; ++ if (!rxd->status.update) ++ break; /* end of tx */ ++ ++ /* clear this flag at once */ ++ rxd->status.update = 0; ++ ++ if (rxd->status.ok && rxd->status.pkt_size >= 60) { ++ int rx_size = (int)(rxd->status.pkt_size - 4); ++ /* alloc new buffer */ ++ skb = netdev_alloc_skb(netdev, rx_size + NET_IP_ALIGN); ++ if (NULL == skb) { ++ printk(KERN_WARNING ++ "%s: Mem squeeze, deferring packet.\n", ++ netdev->name); ++ /* ++ * Check that some rx space is free. If not, ++ * free one and mark stats->rx_dropped++. ++ */ ++ adapter->net_stats.rx_dropped++; ++ break; ++ } ++ skb_reserve(skb, NET_IP_ALIGN); ++ skb->dev = netdev; ++ memcpy(skb->data, rxd->packet, rx_size); ++ skb_put(skb, rx_size); ++ skb->protocol = eth_type_trans(skb, netdev); ++#ifdef NETIF_F_HW_VLAN_TX ++ if (adapter->vlgrp && (rxd->status.vlan)) { ++ u16 vlan_tag = (rxd->status.vtag>>4) | ++ ((rxd->status.vtag&7) << 13) | ++ ((rxd->status.vtag&8) << 9); ++ vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); ++ } else ++#endif ++ netif_rx(skb); ++ adapter->net_stats.rx_bytes += rx_size; ++ adapter->net_stats.rx_packets++; ++ netdev->last_rx = jiffies; ++ } else { ++ adapter->net_stats.rx_errors++; ++ ++ if (rxd->status.ok && rxd->status.pkt_size <= 60) ++ adapter->net_stats.rx_length_errors++; ++ if (rxd->status.mcast) ++ adapter->net_stats.multicast++; ++ if (rxd->status.crc) ++ adapter->net_stats.rx_crc_errors++; ++ if (rxd->status.align) ++ adapter->net_stats.rx_frame_errors++; ++ } ++ ++ /* advance write ptr */ ++ if (++adapter->rxd_write_ptr == adapter->rxd_ring_size) ++ adapter->rxd_write_ptr = 0; ++ } while (1); ++ ++ /* update mailbox? */ ++ adapter->rxd_read_ptr = adapter->rxd_write_ptr; ++ ATL2_WRITE_REGW(&adapter->hw, REG_MB_RXD_RD_IDX, adapter->rxd_read_ptr); ++} ++ ++static void atl2_intr_tx(struct atl2_adapter *adapter) ++{ ++ u32 txd_read_ptr; ++ u32 txs_write_ptr; ++ struct tx_pkt_status *txs; ++ struct tx_pkt_header *txph; ++ int free_hole = 0; ++ ++ do { ++ txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); ++ txs = adapter->txs_ring + txs_write_ptr; ++ if (!txs->update) ++ break; /* tx stop here */ ++ ++ free_hole = 1; ++ txs->update = 0; ++ ++ if (++txs_write_ptr == adapter->txs_ring_size) ++ txs_write_ptr = 0; ++ atomic_set(&adapter->txs_write_ptr, (int)txs_write_ptr); ++ ++ txd_read_ptr = (u32) atomic_read(&adapter->txd_read_ptr); ++ txph = (struct tx_pkt_header *) ++ (((u8 *)adapter->txd_ring) + txd_read_ptr); ++ ++ if (txph->pkt_size != txs->pkt_size) { ++ struct tx_pkt_status *old_txs = txs; ++ printk(KERN_WARNING ++ "%s: txs packet size not consistent with txd" ++ " txd_:0x%08x, txs_:0x%08x!\n", ++ adapter->netdev->name, ++ *(u32 *)txph, *(u32 *)txs); ++ printk(KERN_WARNING ++ "txd read ptr: 0x%x\n", ++ txd_read_ptr); ++ txs = adapter->txs_ring + txs_write_ptr; ++ printk(KERN_WARNING ++ "txs-behind:0x%08x\n", ++ *(u32 *)txs); ++ if (txs_write_ptr < 2) { ++ txs = adapter->txs_ring + ++ (adapter->txs_ring_size + ++ txs_write_ptr - 2); ++ } else { ++ txs = adapter->txs_ring + (txs_write_ptr - 2); ++ } ++ printk(KERN_WARNING ++ "txs-before:0x%08x\n", ++ *(u32 *)txs); ++ txs = old_txs; ++ } ++ ++ /* 4for TPH */ ++ txd_read_ptr += (((u32)(txph->pkt_size) + 7) & ~3); ++ if (txd_read_ptr >= adapter->txd_ring_size) ++ txd_read_ptr -= adapter->txd_ring_size; ++ ++ atomic_set(&adapter->txd_read_ptr, (int)txd_read_ptr); ++ ++ /* tx statistics: */ ++ if (txs->ok) ++ adapter->net_stats.tx_packets++; ++ else ++ adapter->net_stats.tx_errors++; ++ ++ if (txs->defer) ++ adapter->net_stats.collisions++; ++ if (txs->abort_col) ++ adapter->net_stats.tx_aborted_errors++; ++ if (txs->late_col) ++ adapter->net_stats.tx_window_errors++; ++ if (txs->underun) ++ adapter->net_stats.tx_fifo_errors++; ++ } while (1); ++ ++ if (free_hole) { ++ if (netif_queue_stopped(adapter->netdev) && ++ netif_carrier_ok(adapter->netdev)) ++ netif_wake_queue(adapter->netdev); ++ } ++} ++ ++static void atl2_check_for_link(struct atl2_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ u16 phy_data = 0; ++ ++ spin_lock(&adapter->stats_lock); ++ atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); ++ atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); ++ spin_unlock(&adapter->stats_lock); ++ ++ /* notify upper layer link down ASAP */ ++ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ ++ if (netif_carrier_ok(netdev)) { /* old link state: Up */ ++ printk(KERN_INFO "%s: %s NIC Link is Down\n", ++ atl2_driver_name, netdev->name); ++ adapter->link_speed = SPEED_0; ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } ++ } ++ schedule_work(&adapter->link_chg_task); ++} ++ ++static inline void atl2_clear_phy_int(struct atl2_adapter *adapter) ++{ ++ u16 phy_data; ++ spin_lock(&adapter->stats_lock); ++ atl2_read_phy_reg(&adapter->hw, 19, &phy_data); ++ spin_unlock(&adapter->stats_lock); ++} ++ ++/* ++ * atl2_intr - Interrupt Handler ++ * @irq: interrupt number ++ * @data: pointer to a network interface device structure ++ * @pt_regs: CPU registers structure ++ */ ++static irqreturn_t atl2_intr(int irq, void *data) ++{ ++ struct atl2_adapter *adapter = netdev_priv(data); ++ struct atl2_hw *hw = &adapter->hw; ++ u32 status; ++ ++ status = ATL2_READ_REG(hw, REG_ISR); ++ if (0 == status) ++ return IRQ_NONE; ++ ++ /* link event */ ++ if (status & ISR_PHY) ++ atl2_clear_phy_int(adapter); ++ ++ /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ ++ ATL2_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT); ++ ++ /* check if PCIE PHY Link down */ ++ if (status & ISR_PHY_LINKDOWN) { ++ if (netif_running(adapter->netdev)) { /* reset MAC */ ++ ATL2_WRITE_REG(hw, REG_ISR, 0); ++ ATL2_WRITE_REG(hw, REG_IMR, 0); ++ ATL2_WRITE_FLUSH(hw); ++ schedule_work(&adapter->reset_task); ++ return IRQ_HANDLED; ++ } ++ } ++ ++ /* check if DMA read/write error? */ ++ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { ++ ATL2_WRITE_REG(hw, REG_ISR, 0); ++ ATL2_WRITE_REG(hw, REG_IMR, 0); ++ ATL2_WRITE_FLUSH(hw); ++ schedule_work(&adapter->reset_task); ++ return IRQ_HANDLED; ++ } ++ ++ /* link event */ ++ if (status & (ISR_PHY | ISR_MANUAL)) { ++ adapter->net_stats.tx_carrier_errors++; ++ atl2_check_for_link(adapter); ++ } ++ ++ /* transmit event */ ++ if (status & ISR_TX_EVENT) ++ atl2_intr_tx(adapter); ++ ++ /* rx exception */ ++ if (status & ISR_RX_EVENT) ++ atl2_intr_rx(adapter); ++ ++ /* re-enable Interrupt */ ++ ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); ++ return IRQ_HANDLED; ++} ++ ++static int atl2_request_irq(struct atl2_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ int flags, err = 0; ++ ++ flags = IRQF_SHARED; ++#ifdef CONFIG_PCI_MSI ++ adapter->have_msi = true; ++ err = pci_enable_msi(adapter->pdev); ++ if (err) ++ adapter->have_msi = false; ++ ++ if (adapter->have_msi) ++ flags &= ~IRQF_SHARED; ++#endif ++ ++ return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name, ++ netdev); ++} ++ ++/* ++ * atl2_free_ring_resources - Free Tx / RX descriptor Resources ++ * @adapter: board private structure ++ * ++ * Free all transmit software resources ++ */ ++static void atl2_free_ring_resources(struct atl2_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ pci_free_consistent(pdev, adapter->ring_size, adapter->ring_vir_addr, ++ adapter->ring_dma); ++} ++ ++/* ++ * atl2_open - Called when a network interface is made active ++ * @netdev: network interface device structure ++ * ++ * Returns 0 on success, negative value on failure ++ * ++ * The open entry point is called when a network interface is made ++ * active by the system (IFF_UP). At this point all resources needed ++ * for transmit and receive operations are allocated, the interrupt ++ * handler is registered with the OS, the watchdog timer is started, ++ * and the stack is notified that the interface is ready. ++ */ ++static int atl2_open(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ int err; ++ u32 val; ++ ++ /* disallow open during test */ ++ if (test_bit(__ATL2_TESTING, &adapter->flags)) ++ return -EBUSY; ++ ++ /* allocate transmit descriptors */ ++ err = atl2_setup_ring_resources(adapter); ++ if (err) ++ return err; ++ ++ err = atl2_init_hw(&adapter->hw); ++ if (err) { ++ err = -EIO; ++ goto err_init_hw; ++ } ++ ++ /* hardware has been reset, we need to reload some things */ ++ atl2_set_multi(netdev); ++ init_ring_ptrs(adapter); ++ ++#ifdef NETIF_F_HW_VLAN_TX ++ atl2_restore_vlan(adapter); ++#endif ++ ++ if (atl2_configure(adapter)) { ++ err = -EIO; ++ goto err_config; ++ } ++ ++ err = atl2_request_irq(adapter); ++ if (err) ++ goto err_req_irq; ++ ++ clear_bit(__ATL2_DOWN, &adapter->flags); ++ ++ mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ); ++ ++ val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); ++ ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, ++ val | MASTER_CTRL_MANUAL_INT); ++ ++ atl2_irq_enable(adapter); ++ ++ return 0; ++ ++err_init_hw: ++err_req_irq: ++err_config: ++ atl2_free_ring_resources(adapter); ++ atl2_reset_hw(&adapter->hw); ++ ++ return err; ++} ++ ++static void atl2_down(struct atl2_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ ++ /* signal that we're down so the interrupt handler does not ++ * reschedule our watchdog timer */ ++ set_bit(__ATL2_DOWN, &adapter->flags); ++ ++#ifdef NETIF_F_LLTX ++ netif_stop_queue(netdev); ++#else ++ netif_tx_disable(netdev); ++#endif ++ ++ /* reset MAC to disable all RX/TX */ ++ atl2_reset_hw(&adapter->hw); ++ msleep(1); ++ ++ atl2_irq_disable(adapter); ++ ++ del_timer_sync(&adapter->watchdog_timer); ++ del_timer_sync(&adapter->phy_config_timer); ++ clear_bit(0, &adapter->cfg_phy); ++ ++ netif_carrier_off(netdev); ++ adapter->link_speed = SPEED_0; ++ adapter->link_duplex = -1; ++} ++ ++static void atl2_free_irq(struct atl2_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ ++ free_irq(adapter->pdev->irq, netdev); ++ ++#ifdef CONFIG_PCI_MSI ++ if (adapter->have_msi) ++ pci_disable_msi(adapter->pdev); ++#endif ++} ++ ++/* ++ * atl2_close - Disables a network interface ++ * @netdev: network interface device structure ++ * ++ * Returns 0, this is not allowed to fail ++ * ++ * The close entry point is called when an interface is de-activated ++ * by the OS. The hardware is still under the drivers control, but ++ * needs to be disabled. A global MAC reset is issued to stop the ++ * hardware, and all transmit and receive resources are freed. ++ */ ++static int atl2_close(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); ++ ++ atl2_down(adapter); ++ atl2_free_irq(adapter); ++ atl2_free_ring_resources(adapter); ++ ++ return 0; ++} ++ ++static inline int TxsFreeUnit(struct atl2_adapter *adapter) ++{ ++ u32 txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); ++ ++ return (adapter->txs_next_clear >= txs_write_ptr) ? ++ (int) (adapter->txs_ring_size - adapter->txs_next_clear + ++ txs_write_ptr - 1) : ++ (int) (txs_write_ptr - adapter->txs_next_clear - 1); ++} ++ ++static inline int TxdFreeBytes(struct atl2_adapter *adapter) ++{ ++ u32 txd_read_ptr = (u32)atomic_read(&adapter->txd_read_ptr); ++ ++ return (adapter->txd_write_ptr >= txd_read_ptr) ? ++ (int) (adapter->txd_ring_size - adapter->txd_write_ptr + ++ txd_read_ptr - 1) : ++ (int) (txd_read_ptr - adapter->txd_write_ptr - 1); ++} ++ ++static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ unsigned long flags; ++ struct tx_pkt_header *txph; ++ u32 offset, copy_len; ++ int txs_unused; ++ int txbuf_unused; ++ ++ if (test_bit(__ATL2_DOWN, &adapter->flags)) { ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++ if (unlikely(skb->len <= 0)) { ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++#ifdef NETIF_F_LLTX ++ local_irq_save(flags); ++ if (!spin_trylock(&adapter->tx_lock)) { ++ /* Collision - tell upper layer to requeue */ ++ local_irq_restore(flags); ++ return NETDEV_TX_LOCKED; ++ } ++#else ++ spin_lock_irqsave(&adapter->tx_lock, flags); ++#endif ++ txs_unused = TxsFreeUnit(adapter); ++ txbuf_unused = TxdFreeBytes(adapter); ++ ++ if (skb->len + sizeof(struct tx_pkt_header) + 4 > txbuf_unused || ++ txs_unused < 1) { ++ /* not enough resources */ ++ netif_stop_queue(netdev); ++ spin_unlock_irqrestore(&adapter->tx_lock, flags); ++ return NETDEV_TX_BUSY; ++ } ++ ++ offset = adapter->txd_write_ptr; ++ ++ txph = (struct tx_pkt_header *) (((u8 *)adapter->txd_ring) + offset); ++ ++ *(u32 *)txph = 0; ++ txph->pkt_size = skb->len; ++ ++ offset += 4; ++ if (offset >= adapter->txd_ring_size) ++ offset -= adapter->txd_ring_size; ++ copy_len = adapter->txd_ring_size - offset; ++ if (copy_len >= skb->len) { ++ memcpy(((u8 *)adapter->txd_ring) + offset, skb->data, skb->len); ++ offset += ((u32)(skb->len + 3) & ~3); ++ } else { ++ memcpy(((u8 *)adapter->txd_ring)+offset, skb->data, copy_len); ++ memcpy((u8 *)adapter->txd_ring, skb->data+copy_len, ++ skb->len-copy_len); ++ offset = ((u32)(skb->len-copy_len + 3) & ~3); ++ } ++#ifdef NETIF_F_HW_VLAN_TX ++ if (adapter->vlgrp && vlan_tx_tag_present(skb)) { ++ u16 vlan_tag = vlan_tx_tag_get(skb); ++ vlan_tag = (vlan_tag << 4) | ++ (vlan_tag >> 13) | ++ ((vlan_tag >> 9) & 0x8); ++ txph->ins_vlan = 1; ++ txph->vlan = vlan_tag; ++ } ++#endif ++ if (offset >= adapter->txd_ring_size) ++ offset -= adapter->txd_ring_size; ++ adapter->txd_write_ptr = offset; ++ ++ /* clear txs before send */ ++ adapter->txs_ring[adapter->txs_next_clear].update = 0; ++ if (++adapter->txs_next_clear == adapter->txs_ring_size) ++ adapter->txs_next_clear = 0; ++ ++ ATL2_WRITE_REGW(&adapter->hw, REG_MB_TXD_WR_IDX, ++ (adapter->txd_write_ptr >> 2)); ++ ++ spin_unlock_irqrestore(&adapter->tx_lock, flags); ++ ++ netdev->trans_start = jiffies; ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++} ++ ++/* ++ * atl2_get_stats - Get System Network Statistics ++ * @netdev: network interface device structure ++ * ++ * Returns the address of the device statistics structure. ++ * The statistics are actually updated from the timer callback. ++ */ ++static struct net_device_stats *atl2_get_stats(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ return &adapter->net_stats; ++} ++ ++/* ++ * atl2_change_mtu - Change the Maximum Transfer Unit ++ * @netdev: network interface device structure ++ * @new_mtu: new value for maximum frame size ++ * ++ * Returns 0 on success, negative on failure ++ */ ++static int atl2_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ ++ if ((new_mtu < 40) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) ++ return -EINVAL; ++ ++ /* set MTU */ ++ if (hw->max_frame_size != new_mtu) { ++ netdev->mtu = new_mtu; ++ ATL2_WRITE_REG(hw, REG_MTU, new_mtu + ENET_HEADER_SIZE + ++ VLAN_SIZE + ETHERNET_FCS_SIZE); ++ } ++ ++ return 0; ++} ++ ++/* ++ * atl2_set_mac - Change the Ethernet Address of the NIC ++ * @netdev: network interface device structure ++ * @p: pointer to an address structure ++ * ++ * Returns 0 on success, negative on failure ++ */ ++static int atl2_set_mac(struct net_device *netdev, void *p) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct sockaddr *addr = p; ++ ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ if (netif_running(netdev)) ++ return -EBUSY; ++ ++ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); ++ ++ atl2_set_mac_addr(&adapter->hw); ++ ++ return 0; ++} ++ ++/* ++ * atl2_mii_ioctl - ++ * @netdev: ++ * @ifreq: ++ * @cmd: ++ */ ++static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct mii_ioctl_data *data = if_mii(ifr); ++ unsigned long flags; ++ ++ switch (cmd) { ++ case SIOCGMIIPHY: ++ data->phy_id = 0; ++ break; ++ case SIOCGMIIREG: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ if (atl2_read_phy_reg(&adapter->hw, ++ data->reg_num & 0x1F, &data->val_out)) { ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ return -EIO; ++ } ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ break; ++ case SIOCSMIIREG: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ if (data->reg_num & ~(0x1F)) ++ return -EFAULT; ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ if (atl2_write_phy_reg(&adapter->hw, data->reg_num, ++ data->val_in)) { ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ return -EIO; ++ } ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++/* ++ * atl2_ioctl - ++ * @netdev: ++ * @ifreq: ++ * @cmd: ++ */ ++static int atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ++{ ++ switch (cmd) { ++ case SIOCGMIIPHY: ++ case SIOCGMIIREG: ++ case SIOCSMIIREG: ++ return atl2_mii_ioctl(netdev, ifr, cmd); ++#ifdef ETHTOOL_OPS_COMPAT ++ case SIOCETHTOOL: ++ return ethtool_ioctl(ifr); ++#endif ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++/* ++ * atl2_tx_timeout - Respond to a Tx Hang ++ * @netdev: network interface device structure ++ */ ++static void atl2_tx_timeout(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ /* Do the reset outside of interrupt context */ ++ schedule_work(&adapter->reset_task); ++} ++ ++/* ++ * atl2_watchdog - Timer Call-back ++ * @data: pointer to netdev cast into an unsigned long ++ */ ++static void atl2_watchdog(unsigned long data) ++{ ++ struct atl2_adapter *adapter = (struct atl2_adapter *) data; ++ u32 drop_rxd, drop_rxs; ++ unsigned long flags; ++ ++ if (!test_bit(__ATL2_DOWN, &adapter->flags)) { ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV); ++ drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV); ++ adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs); ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ ++ /* Reset the timer */ ++ mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ); ++ } ++} ++ ++/* ++ * atl2_phy_config - Timer Call-back ++ * @data: pointer to netdev cast into an unsigned long ++ */ ++static void atl2_phy_config(unsigned long data) ++{ ++ struct atl2_adapter *adapter = (struct atl2_adapter *) data; ++ struct atl2_hw *hw = &adapter->hw; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ atl2_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); ++ atl2_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN | ++ MII_CR_RESTART_AUTO_NEG); ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++ clear_bit(0, &adapter->cfg_phy); ++} ++ ++static int atl2_up(struct atl2_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ int err = 0; ++ u32 val; ++ ++ /* hardware has been reset, we need to reload some things */ ++ ++ err = atl2_init_hw(&adapter->hw); ++ if (err) { ++ err = -EIO; ++ return err; ++ } ++ ++ atl2_set_multi(netdev); ++ init_ring_ptrs(adapter); ++ ++#ifdef NETIF_F_HW_VLAN_TX ++ atl2_restore_vlan(adapter); ++#endif ++ ++ if (atl2_configure(adapter)) { ++ err = -EIO; ++ goto err_up; ++ } ++ ++ clear_bit(__ATL2_DOWN, &adapter->flags); ++ ++ val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); ++ ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val | ++ MASTER_CTRL_MANUAL_INT); ++ ++ atl2_irq_enable(adapter); ++ ++err_up: ++ return err; ++} ++ ++static void atl2_reinit_locked(struct atl2_adapter *adapter) ++{ ++ WARN_ON(in_interrupt()); ++ while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) ++ msleep(1); ++ atl2_down(adapter); ++ atl2_up(adapter); ++ clear_bit(__ATL2_RESETTING, &adapter->flags); ++} ++ ++static void atl2_reset_task(struct work_struct *work) ++{ ++ struct atl2_adapter *adapter; ++ adapter = container_of(work, struct atl2_adapter, reset_task); ++ ++ atl2_reinit_locked(adapter); ++} ++ ++static void atl2_setup_mac_ctrl(struct atl2_adapter *adapter) ++{ ++ u32 value; ++ struct atl2_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ ++ /* Config MAC CTRL Register */ ++ value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; ++ ++ /* duplex */ ++ if (FULL_DUPLEX == adapter->link_duplex) ++ value |= MAC_CTRL_DUPLX; ++ ++ /* flow control */ ++ value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); ++ ++ /* PAD & CRC */ ++ value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); ++ ++ /* preamble length */ ++ value |= (((u32)adapter->hw.preamble_len & MAC_CTRL_PRMLEN_MASK) << ++ MAC_CTRL_PRMLEN_SHIFT); ++ ++ /* vlan */ ++ if (adapter->vlgrp) ++ value |= MAC_CTRL_RMV_VLAN; ++ ++ /* filter mode */ ++ value |= MAC_CTRL_BC_EN; ++ if (netdev->flags & IFF_PROMISC) ++ value |= MAC_CTRL_PROMIS_EN; ++ else if (netdev->flags & IFF_ALLMULTI) ++ value |= MAC_CTRL_MC_ALL_EN; ++ ++ /* half retry buffer */ ++ value |= (((u32)(adapter->hw.retry_buf & ++ MAC_CTRL_HALF_LEFT_BUF_MASK)) << MAC_CTRL_HALF_LEFT_BUF_SHIFT); ++ ++ ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); ++} ++ ++static int atl2_check_link(struct atl2_adapter *adapter) ++{ ++ struct atl2_hw *hw = &adapter->hw; ++ struct net_device *netdev = adapter->netdev; ++ int ret_val; ++ u16 speed, duplex, phy_data; ++ int reconfig = 0; ++ ++ /* MII_BMSR must read twise */ ++ atl2_read_phy_reg(hw, MII_BMSR, &phy_data); ++ atl2_read_phy_reg(hw, MII_BMSR, &phy_data); ++ if (!(phy_data&BMSR_LSTATUS)) { /* link down */ ++ if (netif_carrier_ok(netdev)) { /* old link state: Up */ ++ u32 value; ++ /* disable rx */ ++ value = ATL2_READ_REG(hw, REG_MAC_CTRL); ++ value &= ~MAC_CTRL_RX_EN; ++ ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); ++ adapter->link_speed = SPEED_0; ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } ++ return 0; ++ } ++ ++ /* Link Up */ ++ ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); ++ if (ret_val) ++ return ret_val; ++ switch (hw->MediaType) { ++ case MEDIA_TYPE_100M_FULL: ++ if (speed != SPEED_100 || duplex != FULL_DUPLEX) ++ reconfig = 1; ++ break; ++ case MEDIA_TYPE_100M_HALF: ++ if (speed != SPEED_100 || duplex != HALF_DUPLEX) ++ reconfig = 1; ++ break; ++ case MEDIA_TYPE_10M_FULL: ++ if (speed != SPEED_10 || duplex != FULL_DUPLEX) ++ reconfig = 1; ++ break; ++ case MEDIA_TYPE_10M_HALF: ++ if (speed != SPEED_10 || duplex != HALF_DUPLEX) ++ reconfig = 1; ++ break; ++ } ++ /* link result is our setting */ ++ if (reconfig == 0) { ++ if (adapter->link_speed != speed || ++ adapter->link_duplex != duplex) { ++ adapter->link_speed = speed; ++ adapter->link_duplex = duplex; ++ atl2_setup_mac_ctrl(adapter); ++ printk(KERN_INFO "%s: %s NIC Link is Up<%d Mbps %s>\n", ++ atl2_driver_name, netdev->name, ++ adapter->link_speed, ++ adapter->link_duplex == FULL_DUPLEX ? ++ "Full Duplex" : "Half Duplex"); ++ } ++ ++ if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ ++ netif_carrier_on(netdev); ++ netif_wake_queue(netdev); ++ } ++ return 0; ++ } ++ ++ /* change original link status */ ++ if (netif_carrier_ok(netdev)) { ++ u32 value; ++ /* disable rx */ ++ value = ATL2_READ_REG(hw, REG_MAC_CTRL); ++ value &= ~MAC_CTRL_RX_EN; ++ ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); ++ ++ adapter->link_speed = SPEED_0; ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } ++ ++ /* auto-neg, insert timer to re-config phy ++ * (if interval smaller than 5 seconds, something strange) */ ++ if (!test_bit(__ATL2_DOWN, &adapter->flags)) { ++ if (!test_and_set_bit(0, &adapter->cfg_phy)) ++ mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ); ++ } ++ ++ return 0; ++} ++ ++/* ++ * atl2_link_chg_task - deal with link change event Out of interrupt context ++ * @netdev: network interface device structure ++ */ ++static void atl2_link_chg_task(struct work_struct *work) ++{ ++ struct atl2_adapter *adapter; ++ unsigned long flags; ++ ++ adapter = container_of(work, struct atl2_adapter, link_chg_task); ++ ++ spin_lock_irqsave(&adapter->stats_lock, flags); ++ atl2_check_link(adapter); ++ spin_unlock_irqrestore(&adapter->stats_lock, flags); ++} ++ ++static void atl2_setup_pcicmd(struct pci_dev *pdev) ++{ ++ u16 cmd; ++ ++ pci_read_config_word(pdev, PCI_COMMAND, &cmd); ++ ++ if (cmd & PCI_COMMAND_INTX_DISABLE) ++ cmd &= ~PCI_COMMAND_INTX_DISABLE; ++ if (cmd & PCI_COMMAND_IO) ++ cmd &= ~PCI_COMMAND_IO; ++ if (0 == (cmd & PCI_COMMAND_MEMORY)) ++ cmd |= PCI_COMMAND_MEMORY; ++ if (0 == (cmd & PCI_COMMAND_MASTER)) ++ cmd |= PCI_COMMAND_MASTER; ++ pci_write_config_word(pdev, PCI_COMMAND, cmd); ++ ++ /* ++ * some motherboards BIOS(PXE/EFI) driver may set PME ++ * while they transfer control to OS (Windows/Linux) ++ * so we should clear this bit before NIC work normally ++ */ ++ pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0); ++} ++ ++/* ++ * atl2_probe - Device Initialization Routine ++ * @pdev: PCI device information struct ++ * @ent: entry in atl2_pci_tbl ++ * ++ * Returns 0 on success, negative on failure ++ * ++ * atl2_probe initializes an adapter identified by a pci_dev structure. ++ * The OS initialization, configuring of the adapter private structure, ++ * and a hardware reset occur. ++ */ ++static int __devinit atl2_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct net_device *netdev; ++ struct atl2_adapter *adapter; ++ static int cards_found; ++ unsigned long mmio_start; ++ int mmio_len; ++ int err; ++ ++ cards_found = 0; ++ ++ err = pci_enable_device(pdev); ++ if (err) ++ return err; ++ ++ /* ++ * atl2 is a shared-high-32-bit device, so we're stuck with 32-bit DMA ++ * until the kernel has the proper infrastructure to support 64-bit DMA ++ * on these devices. ++ */ ++ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) && ++ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { ++ printk(KERN_ERR "atl2: No usable DMA configuration, aborting\n"); ++ goto err_dma; ++ } ++ ++ /* Mark all PCI regions associated with PCI device ++ * pdev as being reserved by owner atl2_driver_name */ ++ err = pci_request_regions(pdev, atl2_driver_name); ++ if (err) ++ goto err_pci_reg; ++ ++ /* Enables bus-mastering on the device and calls ++ * pcibios_set_master to do the needed arch specific settings */ ++ pci_set_master(pdev); ++ ++ err = -ENOMEM; ++ netdev = alloc_etherdev(sizeof(struct atl2_adapter)); ++ if (!netdev) ++ goto err_alloc_etherdev; ++ ++ SET_NETDEV_DEV(netdev, &pdev->dev); ++ ++ pci_set_drvdata(pdev, netdev); ++ adapter = netdev_priv(netdev); ++ adapter->netdev = netdev; ++ adapter->pdev = pdev; ++ adapter->hw.back = adapter; ++ ++ mmio_start = pci_resource_start(pdev, 0x0); ++ mmio_len = pci_resource_len(pdev, 0x0); ++ ++ adapter->hw.mem_rang = (u32)mmio_len; ++ adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); ++ if (!adapter->hw.hw_addr) { ++ err = -EIO; ++ goto err_ioremap; ++ } ++ ++ atl2_setup_pcicmd(pdev); ++ ++ netdev->open = &atl2_open; ++ netdev->stop = &atl2_close; ++ netdev->hard_start_xmit = &atl2_xmit_frame; ++ netdev->get_stats = &atl2_get_stats; ++ netdev->set_multicast_list = &atl2_set_multi; ++ netdev->set_mac_address = &atl2_set_mac; ++ netdev->change_mtu = &atl2_change_mtu; ++ netdev->do_ioctl = &atl2_ioctl; ++ atl2_set_ethtool_ops(netdev); ++ ++#ifdef HAVE_TX_TIMEOUT ++ netdev->tx_timeout = &atl2_tx_timeout; ++ netdev->watchdog_timeo = 5 * HZ; ++#endif ++#ifdef NETIF_F_HW_VLAN_TX ++ netdev->vlan_rx_register = atl2_vlan_rx_register; ++#endif ++ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); ++ ++ netdev->mem_start = mmio_start; ++ netdev->mem_end = mmio_start + mmio_len; ++ adapter->bd_number = cards_found; ++ adapter->pci_using_64 = false; ++ ++ /* setup the private structure */ ++ err = atl2_sw_init(adapter); ++ if (err) ++ goto err_sw_init; ++ ++ err = -EIO; ++ ++#ifdef NETIF_F_HW_VLAN_TX ++ netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); ++#endif ++ ++#ifdef NETIF_F_LLTX ++ netdev->features |= NETIF_F_LLTX; ++#endif ++ ++ /* Init PHY as early as possible due to power saving issue */ ++ atl2_phy_init(&adapter->hw); ++ ++ /* reset the controller to ++ * put the device in a known good starting state */ ++ ++ if (atl2_reset_hw(&adapter->hw)) { ++ err = -EIO; ++ goto err_reset; ++ } ++ ++ /* copy the MAC address out of the EEPROM */ ++ atl2_read_mac_addr(&adapter->hw); ++ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); ++/* FIXME: do we still need this? */ ++#ifdef ETHTOOL_GPERMADDR ++ memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); ++ ++ if (!is_valid_ether_addr(netdev->perm_addr)) { ++#else ++ if (!is_valid_ether_addr(netdev->dev_addr)) { ++#endif ++ err = -EIO; ++ goto err_eeprom; ++ } ++ ++ atl2_check_options(adapter); ++ ++ init_timer(&adapter->watchdog_timer); ++ adapter->watchdog_timer.function = &atl2_watchdog; ++ adapter->watchdog_timer.data = (unsigned long) adapter; ++ ++ init_timer(&adapter->phy_config_timer); ++ adapter->phy_config_timer.function = &atl2_phy_config; ++ adapter->phy_config_timer.data = (unsigned long) adapter; ++ ++ INIT_WORK(&adapter->reset_task, atl2_reset_task); ++ INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task); ++ ++ strcpy(netdev->name, "eth%d"); /* ?? */ ++ err = register_netdev(netdev); ++ if (err) ++ goto err_register; ++ ++ /* assume we have no link for now */ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ ++ cards_found++; ++ ++ return 0; ++ ++err_reset: ++err_register: ++err_sw_init: ++err_eeprom: ++ iounmap(adapter->hw.hw_addr); ++err_ioremap: ++ free_netdev(netdev); ++err_alloc_etherdev: ++ pci_release_regions(pdev); ++err_pci_reg: ++err_dma: ++ pci_disable_device(pdev); ++ return err; ++} ++ ++/* ++ * atl2_remove - Device Removal Routine ++ * @pdev: PCI device information struct ++ * ++ * atl2_remove is called by the PCI subsystem to alert the driver ++ * that it should release a PCI device. The could be caused by a ++ * Hot-Plug event, or because the driver is going to be removed from ++ * memory. ++ */ ++/* FIXME: write the original MAC address back in case it was changed from a ++ * BIOS-set value, as in atl1 -- CHS */ ++static void __devexit atl2_remove(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ /* flush_scheduled work may reschedule our watchdog task, so ++ * explicitly disable watchdog tasks from being rescheduled */ ++ set_bit(__ATL2_DOWN, &adapter->flags); ++ ++ del_timer_sync(&adapter->watchdog_timer); ++ del_timer_sync(&adapter->phy_config_timer); ++ ++ flush_scheduled_work(); ++ ++ unregister_netdev(netdev); ++ ++ atl2_force_ps(&adapter->hw); ++ ++ iounmap(adapter->hw.hw_addr); ++ pci_release_regions(pdev); ++ ++ free_netdev(netdev); ++ ++ pci_disable_device(pdev); ++} ++ ++static int atl2_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ u16 speed, duplex; ++ u32 ctrl = 0; ++ u32 wufc = adapter->wol; ++ ++#ifdef CONFIG_PM ++ int retval = 0; ++#endif ++ ++ netif_device_detach(netdev); ++ ++ if (netif_running(netdev)) { ++ WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); ++ atl2_down(adapter); ++ } ++ ++#ifdef CONFIG_PM ++ retval = pci_save_state(pdev); ++ if (retval) ++ return retval; ++#endif ++ ++ atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl); ++ atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl); ++ if (ctrl & BMSR_LSTATUS) ++ wufc &= ~ATLX_WUFC_LNKC; ++ ++ if (0 != (ctrl & BMSR_LSTATUS) && 0 != wufc) { ++ u32 ret_val; ++ /* get current link speed & duplex */ ++ ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); ++ if (ret_val) { ++ printk(KERN_DEBUG ++ "%s: get speed&duplex error while suspend\n", ++ atl2_driver_name); ++ goto wol_dis; ++ } ++ ++ ctrl = 0; ++ ++ /* turn on magic packet wol */ ++ if (wufc & ATLX_WUFC_MAG) ++ ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN); ++ ++ /* ignore Link Chg event when Link is up */ ++ ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); ++ ++ /* Config MAC CTRL Register */ ++ ctrl = MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; ++ if (FULL_DUPLEX == adapter->link_duplex) ++ ctrl |= MAC_CTRL_DUPLX; ++ ctrl |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); ++ ctrl |= (((u32)adapter->hw.preamble_len & ++ MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); ++ ctrl |= (((u32)(adapter->hw.retry_buf & ++ MAC_CTRL_HALF_LEFT_BUF_MASK)) << ++ MAC_CTRL_HALF_LEFT_BUF_SHIFT); ++ if (wufc & ATLX_WUFC_MAG) { ++ /* magic packet maybe Broadcast&multicast&Unicast */ ++ ctrl |= MAC_CTRL_BC_EN; ++ } ++ ++ ATL2_WRITE_REG(hw, REG_MAC_CTRL, ctrl); ++ ++ /* pcie patch */ ++ ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); ++ ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; ++ ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); ++ ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); ++ ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; ++ ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); ++ ++ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); ++ goto suspend_exit; ++ } ++ ++ if (0 == (ctrl&BMSR_LSTATUS) && 0 != (wufc&ATLX_WUFC_LNKC)) { ++ /* link is down, so only LINK CHG WOL event enable */ ++ ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); ++ ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); ++ ATL2_WRITE_REG(hw, REG_MAC_CTRL, 0); ++ ++ /* pcie patch */ ++ ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); ++ ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; ++ ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); ++ ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); ++ ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; ++ ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); ++ ++ hw->phy_configured = false; /* re-init PHY when resume */ ++ ++ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); ++ ++ goto suspend_exit; ++ } ++ ++wol_dis: ++ /* WOL disabled */ ++ ATL2_WRITE_REG(hw, REG_WOL_CTRL, 0); ++ ++ /* pcie patch */ ++ ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); ++ ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; ++ ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); ++ ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); ++ ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; ++ ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); ++ ++ atl2_force_ps(hw); ++ hw->phy_configured = false; /* re-init PHY when resume */ ++ ++ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); ++ ++suspend_exit: ++ if (netif_running(netdev)) ++ atl2_free_irq(adapter); ++ ++ pci_disable_device(pdev); ++ ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int atl2_resume(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ u32 err; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ ++ err = pci_enable_device(pdev); ++ if (err) { ++ printk(KERN_ERR ++ "atl2: Cannot enable PCI device from suspend\n"); ++ return err; ++ } ++ ++ pci_set_master(pdev); ++ ++ ATL2_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */ ++ ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); ++ ++ ATL2_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); ++ ++ err = atl2_request_irq(adapter); ++ if (netif_running(netdev) && err) ++ return err; ++ ++ atl2_reset_hw(&adapter->hw); ++ ++ if (netif_running(netdev)) ++ atl2_up(adapter); ++ ++ netif_device_attach(netdev); ++ ++ return 0; ++} ++#endif ++ ++static void atl2_shutdown(struct pci_dev *pdev) ++{ ++ atl2_suspend(pdev, PMSG_SUSPEND); ++} ++ ++static struct pci_driver atl2_driver = { ++ .name = atl2_driver_name, ++ .id_table = atl2_pci_tbl, ++ .probe = atl2_probe, ++ .remove = __devexit_p(atl2_remove), ++ /* Power Managment Hooks */ ++ .suspend = atl2_suspend, ++#ifdef CONFIG_PM ++ .resume = atl2_resume, ++#endif ++ .shutdown = atl2_shutdown, ++}; ++ ++/* ++ * atl2_init_module - Driver Registration Routine ++ * ++ * atl2_init_module is the first routine called when the driver is ++ * loaded. All it does is register with the PCI subsystem. ++ */ ++static int __init atl2_init_module(void) ++{ ++ printk(KERN_INFO "%s - version %s\n", atl2_driver_string, ++ atl2_driver_version); ++ printk(KERN_INFO "%s\n", atl2_copyright); ++ return pci_register_driver(&atl2_driver); ++} ++module_init(atl2_init_module); ++ ++/* ++ * atl2_exit_module - Driver Exit Cleanup Routine ++ * ++ * atl2_exit_module is called just before the driver is removed ++ * from memory. ++ */ ++static void __exit atl2_exit_module(void) ++{ ++ pci_unregister_driver(&atl2_driver); ++} ++module_exit(atl2_exit_module); ++ ++static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) ++{ ++ struct atl2_adapter *adapter = hw->back; ++ pci_read_config_word(adapter->pdev, reg, value); ++} ++ ++static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) ++{ ++ struct atl2_adapter *adapter = hw->back; ++ pci_write_config_word(adapter->pdev, reg, *value); ++} ++ ++static int atl2_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ ++ ecmd->supported = (SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++ SUPPORTED_Autoneg | ++ SUPPORTED_TP); ++ ecmd->advertising = ADVERTISED_TP; ++ ++ ecmd->advertising |= ADVERTISED_Autoneg; ++ ecmd->advertising |= hw->autoneg_advertised; ++ ++ ecmd->port = PORT_TP; ++ ecmd->phy_address = 0; ++ ecmd->transceiver = XCVR_INTERNAL; ++ ++ if (adapter->link_speed != SPEED_0) { ++ ecmd->speed = adapter->link_speed; ++ if (adapter->link_duplex == FULL_DUPLEX) ++ ecmd->duplex = DUPLEX_FULL; ++ else ++ ecmd->duplex = DUPLEX_HALF; ++ } else { ++ ecmd->speed = -1; ++ ecmd->duplex = -1; ++ } ++ ++ ecmd->autoneg = AUTONEG_ENABLE; ++ return 0; ++} ++ ++static int atl2_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *ecmd) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ ++ while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) ++ msleep(1); ++ ++ if (ecmd->autoneg == AUTONEG_ENABLE) { ++#define MY_ADV_MASK (ADVERTISE_10_HALF | \ ++ ADVERTISE_10_FULL | \ ++ ADVERTISE_100_HALF| \ ++ ADVERTISE_100_FULL) ++ ++ if ((ecmd->advertising & MY_ADV_MASK) == MY_ADV_MASK) { ++ hw->MediaType = MEDIA_TYPE_AUTO_SENSOR; ++ hw->autoneg_advertised = MY_ADV_MASK; ++ } else if ((ecmd->advertising & MY_ADV_MASK) == ++ ADVERTISE_100_FULL) { ++ hw->MediaType = MEDIA_TYPE_100M_FULL; ++ hw->autoneg_advertised = ADVERTISE_100_FULL; ++ } else if ((ecmd->advertising & MY_ADV_MASK) == ++ ADVERTISE_100_HALF) { ++ hw->MediaType = MEDIA_TYPE_100M_HALF; ++ hw->autoneg_advertised = ADVERTISE_100_HALF; ++ } else if ((ecmd->advertising & MY_ADV_MASK) == ++ ADVERTISE_10_FULL) { ++ hw->MediaType = MEDIA_TYPE_10M_FULL; ++ hw->autoneg_advertised = ADVERTISE_10_FULL; ++ } else if ((ecmd->advertising & MY_ADV_MASK) == ++ ADVERTISE_10_HALF) { ++ hw->MediaType = MEDIA_TYPE_10M_HALF; ++ hw->autoneg_advertised = ADVERTISE_10_HALF; ++ } else { ++ clear_bit(__ATL2_RESETTING, &adapter->flags); ++ return -EINVAL; ++ } ++ ecmd->advertising = hw->autoneg_advertised | ++ ADVERTISED_TP | ADVERTISED_Autoneg; ++ } else { ++ clear_bit(__ATL2_RESETTING, &adapter->flags); ++ return -EINVAL; ++ } ++ ++ /* reset the link */ ++ if (netif_running(adapter->netdev)) { ++ atl2_down(adapter); ++ atl2_up(adapter); ++ } else ++ atl2_reset_hw(&adapter->hw); ++ ++ clear_bit(__ATL2_RESETTING, &adapter->flags); ++ return 0; ++} ++ ++static u32 atl2_get_tx_csum(struct net_device *netdev) ++{ ++ return (netdev->features & NETIF_F_HW_CSUM) != 0; ++} ++ ++static u32 atl2_get_msglevel(struct net_device *netdev) ++{ ++ return 0; ++} ++ ++/* ++ * It's sane for this to be empty, but we might want to take advantage of this. ++ */ ++static void atl2_set_msglevel(struct net_device *netdev, u32 data) ++{ ++} ++ ++static int atl2_get_regs_len(struct net_device *netdev) ++{ ++#define ATL2_REGS_LEN 42 ++ return sizeof(u32) * ATL2_REGS_LEN; ++} ++ ++static void atl2_get_regs(struct net_device *netdev, ++ struct ethtool_regs *regs, void *p) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ u32 *regs_buff = p; ++ u16 phy_data; ++ ++ memset(p, 0, sizeof(u32) * ATL2_REGS_LEN); ++ ++ regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; ++ ++ regs_buff[0] = ATL2_READ_REG(hw, REG_VPD_CAP); ++ regs_buff[1] = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); ++ regs_buff[2] = ATL2_READ_REG(hw, REG_SPI_FLASH_CONFIG); ++ regs_buff[3] = ATL2_READ_REG(hw, REG_TWSI_CTRL); ++ regs_buff[4] = ATL2_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL); ++ regs_buff[5] = ATL2_READ_REG(hw, REG_MASTER_CTRL); ++ regs_buff[6] = ATL2_READ_REG(hw, REG_MANUAL_TIMER_INIT); ++ regs_buff[7] = ATL2_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT); ++ regs_buff[8] = ATL2_READ_REG(hw, REG_PHY_ENABLE); ++ regs_buff[9] = ATL2_READ_REG(hw, REG_CMBDISDMA_TIMER); ++ regs_buff[10] = ATL2_READ_REG(hw, REG_IDLE_STATUS); ++ regs_buff[11] = ATL2_READ_REG(hw, REG_MDIO_CTRL); ++ regs_buff[12] = ATL2_READ_REG(hw, REG_SERDES_LOCK); ++ regs_buff[13] = ATL2_READ_REG(hw, REG_MAC_CTRL); ++ regs_buff[14] = ATL2_READ_REG(hw, REG_MAC_IPG_IFG); ++ regs_buff[15] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); ++ regs_buff[16] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR+4); ++ regs_buff[17] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE); ++ regs_buff[18] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE+4); ++ regs_buff[19] = ATL2_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL); ++ regs_buff[20] = ATL2_READ_REG(hw, REG_MTU); ++ regs_buff[21] = ATL2_READ_REG(hw, REG_WOL_CTRL); ++ regs_buff[22] = ATL2_READ_REG(hw, REG_SRAM_TXRAM_END); ++ regs_buff[23] = ATL2_READ_REG(hw, REG_DESC_BASE_ADDR_HI); ++ regs_buff[24] = ATL2_READ_REG(hw, REG_TXD_BASE_ADDR_LO); ++ regs_buff[25] = ATL2_READ_REG(hw, REG_TXD_MEM_SIZE); ++ regs_buff[26] = ATL2_READ_REG(hw, REG_TXS_BASE_ADDR_LO); ++ regs_buff[27] = ATL2_READ_REG(hw, REG_TXS_MEM_SIZE); ++ regs_buff[28] = ATL2_READ_REG(hw, REG_RXD_BASE_ADDR_LO); ++ regs_buff[29] = ATL2_READ_REG(hw, REG_RXD_BUF_NUM); ++ regs_buff[30] = ATL2_READ_REG(hw, REG_DMAR); ++ regs_buff[31] = ATL2_READ_REG(hw, REG_TX_CUT_THRESH); ++ regs_buff[32] = ATL2_READ_REG(hw, REG_DMAW); ++ regs_buff[33] = ATL2_READ_REG(hw, REG_PAUSE_ON_TH); ++ regs_buff[34] = ATL2_READ_REG(hw, REG_PAUSE_OFF_TH); ++ regs_buff[35] = ATL2_READ_REG(hw, REG_MB_TXD_WR_IDX); ++ regs_buff[36] = ATL2_READ_REG(hw, REG_MB_RXD_RD_IDX); ++ regs_buff[38] = ATL2_READ_REG(hw, REG_ISR); ++ regs_buff[39] = ATL2_READ_REG(hw, REG_IMR); ++ ++ atl2_read_phy_reg(hw, MII_BMCR, &phy_data); ++ regs_buff[40] = (u32)phy_data; ++ atl2_read_phy_reg(hw, MII_BMSR, &phy_data); ++ regs_buff[41] = (u32)phy_data; ++} ++ ++static int atl2_get_eeprom_len(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ if (!atl2_check_eeprom_exist(&adapter->hw)) ++ return 512; ++ else ++ return 0; ++} ++ ++static int atl2_get_eeprom(struct net_device *netdev, ++ struct ethtool_eeprom *eeprom, u8 *bytes) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ u32 *eeprom_buff; ++ int first_dword, last_dword; ++ int ret_val = 0; ++ int i; ++ ++ if (eeprom->len == 0) ++ return -EINVAL; ++ ++ if (atl2_check_eeprom_exist(hw)) ++ return -EINVAL; ++ ++ eeprom->magic = hw->vendor_id | (hw->device_id << 16); ++ ++ first_dword = eeprom->offset >> 2; ++ last_dword = (eeprom->offset + eeprom->len - 1) >> 2; ++ ++ eeprom_buff = kmalloc(sizeof(u32) * (last_dword - first_dword + 1), ++ GFP_KERNEL); ++ if (!eeprom_buff) ++ return -ENOMEM; ++ ++ for (i = first_dword; i < last_dword; i++) { ++ if (!atl2_read_eeprom(hw, i*4, &(eeprom_buff[i-first_dword]))) ++ return -EIO; ++ } ++ ++ memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3), ++ eeprom->len); ++ kfree(eeprom_buff); ++ ++ return ret_val; ++} ++ ++static int atl2_set_eeprom(struct net_device *netdev, ++ struct ethtool_eeprom *eeprom, u8 *bytes) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ struct atl2_hw *hw = &adapter->hw; ++ u32 *eeprom_buff; ++ u32 *ptr; ++ int max_len, first_dword, last_dword, ret_val = 0; ++ int i; ++ ++ if (eeprom->len == 0) ++ return -EOPNOTSUPP; ++ ++ if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) ++ return -EFAULT; ++ ++ max_len = 512; ++ ++ first_dword = eeprom->offset >> 2; ++ last_dword = (eeprom->offset + eeprom->len - 1) >> 2; ++ eeprom_buff = kmalloc(max_len, GFP_KERNEL); ++ if (!eeprom_buff) ++ return -ENOMEM; ++ ++ ptr = (u32 *)eeprom_buff; ++ ++ if (eeprom->offset & 3) { ++ /* need read/modify/write of first changed EEPROM word */ ++ /* only the second byte of the word is being modified */ ++ if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) ++ return -EIO; ++ ptr++; ++ } ++ if (((eeprom->offset + eeprom->len) & 3)) { ++ /* ++ * need read/modify/write of last changed EEPROM word ++ * only the first byte of the word is being modified ++ */ ++ if (!atl2_read_eeprom(hw, last_dword * 4, ++ &(eeprom_buff[last_dword - first_dword]))) ++ return -EIO; ++ } ++ ++ /* Device's eeprom is always little-endian, word addressable */ ++ memcpy(ptr, bytes, eeprom->len); ++ ++ for (i = 0; i < last_dword - first_dword + 1; i++) { ++ if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) ++ return -EIO; ++ } ++ ++ kfree(eeprom_buff); ++ return ret_val; ++} ++ ++static void atl2_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ strncpy(drvinfo->driver, atl2_driver_name, 32); ++ strncpy(drvinfo->version, atl2_driver_version, 32); ++ strncpy(drvinfo->fw_version, "L2", 32); ++ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); ++ drvinfo->n_stats = 0; ++ drvinfo->testinfo_len = 0; ++ drvinfo->regdump_len = atl2_get_regs_len(netdev); ++ drvinfo->eedump_len = atl2_get_eeprom_len(netdev); ++} ++ ++static void atl2_get_wol(struct net_device *netdev, ++ struct ethtool_wolinfo *wol) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ wol->supported = WAKE_MAGIC; ++ wol->wolopts = 0; ++ ++ if (adapter->wol & ATLX_WUFC_EX) ++ wol->wolopts |= WAKE_UCAST; ++ if (adapter->wol & ATLX_WUFC_MC) ++ wol->wolopts |= WAKE_MCAST; ++ if (adapter->wol & ATLX_WUFC_BC) ++ wol->wolopts |= WAKE_BCAST; ++ if (adapter->wol & ATLX_WUFC_MAG) ++ wol->wolopts |= WAKE_MAGIC; ++ if (adapter->wol & ATLX_WUFC_LNKC) ++ wol->wolopts |= WAKE_PHY; ++} ++ ++static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ ++ if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) ++ return -EOPNOTSUPP; ++ ++ if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST)) ++ return -EOPNOTSUPP; ++ ++ /* these settings will always override what we currently have */ ++ adapter->wol = 0; ++ ++ if (wol->wolopts & WAKE_MAGIC) ++ adapter->wol |= ATLX_WUFC_MAG; ++ if (wol->wolopts & WAKE_PHY) ++ adapter->wol |= ATLX_WUFC_LNKC; ++ ++ return 0; ++} ++ ++static int atl2_nway_reset(struct net_device *netdev) ++{ ++ struct atl2_adapter *adapter = netdev_priv(netdev); ++ if (netif_running(netdev)) ++ atl2_reinit_locked(adapter); ++ return 0; ++} ++ ++static struct ethtool_ops atl2_ethtool_ops = { ++ .get_settings = atl2_get_settings, ++ .set_settings = atl2_set_settings, ++ .get_drvinfo = atl2_get_drvinfo, ++ .get_regs_len = atl2_get_regs_len, ++ .get_regs = atl2_get_regs, ++ .get_wol = atl2_get_wol, ++ .set_wol = atl2_set_wol, ++ .get_msglevel = atl2_get_msglevel, ++ .set_msglevel = atl2_set_msglevel, ++ .nway_reset = atl2_nway_reset, ++ .get_link = ethtool_op_get_link, ++ .get_eeprom_len = atl2_get_eeprom_len, ++ .get_eeprom = atl2_get_eeprom, ++ .set_eeprom = atl2_set_eeprom, ++ .get_tx_csum = atl2_get_tx_csum, ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = ethtool_op_set_sg, ++#ifdef NETIF_F_TSO ++ .get_tso = ethtool_op_get_tso, ++#endif ++}; ++ ++static void atl2_set_ethtool_ops(struct net_device *netdev) ++{ ++ SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops); ++} ++ ++#define LBYTESWAP(a) ((((a) & 0x00ff00ff) << 8) | \ ++ (((a) & 0xff00ff00) >> 8)) ++#define LONGSWAP(a) ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16)) ++#define SHORTSWAP(a) (((a) << 8) | ((a) >> 8)) ++ ++/* ++ * Reset the transmit and receive units; mask and clear all interrupts. ++ * ++ * hw - Struct containing variables accessed by shared code ++ * return : 0 or idle status (if error) ++ */ ++static s32 atl2_reset_hw(struct atl2_hw *hw) ++{ ++ u32 icr; ++ u16 pci_cfg_cmd_word; ++ int i; ++ ++ /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ ++ atl2_read_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); ++ if ((pci_cfg_cmd_word & ++ (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) != ++ (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER)) { ++ pci_cfg_cmd_word |= ++ (CMD_IO_SPACE|CMD_MEMORY_SPACE|CMD_BUS_MASTER); ++ atl2_write_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); ++ } ++ ++ /* Clear Interrupt mask to stop board from generating ++ * interrupts & Clear any pending interrupt events ++ */ ++ /* FIXME */ ++ /* ATL2_WRITE_REG(hw, REG_IMR, 0); */ ++ /* ATL2_WRITE_REG(hw, REG_ISR, 0xffffffff); */ ++ ++ /* Issue Soft Reset to the MAC. This will reset the chip's ++ * transmit, receive, DMA. It will not effect ++ * the current PCI configuration. The global reset bit is self- ++ * clearing, and should clear within a microsecond. ++ */ ++ ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST); ++ wmb(); ++ msleep(1); /* delay about 1ms */ ++ ++ /* Wait at least 10ms for All module to be Idle */ ++ for (i = 0; i < 10; i++) { ++ icr = ATL2_READ_REG(hw, REG_IDLE_STATUS); ++ if (!icr) ++ break; ++ msleep(1); /* delay 1 ms */ ++ cpu_relax(); ++ } ++ ++ if (icr) ++ return icr; ++ ++ return 0; ++} ++ ++#define CUSTOM_SPI_CS_SETUP 2 ++#define CUSTOM_SPI_CLK_HI 2 ++#define CUSTOM_SPI_CLK_LO 2 ++#define CUSTOM_SPI_CS_HOLD 2 ++#define CUSTOM_SPI_CS_HI 3 ++ ++static struct atl2_spi_flash_dev flash_table[] = ++{ ++/* MFR WRSR READ PROGRAM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ ++{"Atmel", 0x0, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62 }, ++{"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60 }, ++{"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7 }, ++}; ++ ++static bool atl2_spi_read(struct atl2_hw *hw, u32 addr, u32 *buf) ++{ ++ int i; ++ u32 value; ++ ++ ATL2_WRITE_REG(hw, REG_SPI_DATA, 0); ++ ATL2_WRITE_REG(hw, REG_SPI_ADDR, addr); ++ ++ value = SPI_FLASH_CTRL_WAIT_READY | ++ (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << ++ SPI_FLASH_CTRL_CS_SETUP_SHIFT | ++ (CUSTOM_SPI_CLK_HI & SPI_FLASH_CTRL_CLK_HI_MASK) << ++ SPI_FLASH_CTRL_CLK_HI_SHIFT | ++ (CUSTOM_SPI_CLK_LO & SPI_FLASH_CTRL_CLK_LO_MASK) << ++ SPI_FLASH_CTRL_CLK_LO_SHIFT | ++ (CUSTOM_SPI_CS_HOLD & SPI_FLASH_CTRL_CS_HOLD_MASK) << ++ SPI_FLASH_CTRL_CS_HOLD_SHIFT | ++ (CUSTOM_SPI_CS_HI & SPI_FLASH_CTRL_CS_HI_MASK) << ++ SPI_FLASH_CTRL_CS_HI_SHIFT | ++ (0x1 & SPI_FLASH_CTRL_INS_MASK) << SPI_FLASH_CTRL_INS_SHIFT; ++ ++ ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); ++ ++ value |= SPI_FLASH_CTRL_START; ++ ++ ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); ++ ++ for (i = 0; i < 10; i++) { ++ msleep(1); ++ value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); ++ if (!(value & SPI_FLASH_CTRL_START)) ++ break; ++ } ++ ++ if (value & SPI_FLASH_CTRL_START) ++ return false; ++ ++ *buf = ATL2_READ_REG(hw, REG_SPI_DATA); ++ ++ return true; ++} ++ ++/* ++ * get_permanent_address ++ * return 0 if get valid mac address, ++ */ ++static int get_permanent_address(struct atl2_hw *hw) ++{ ++ u32 Addr[2]; ++ u32 i, Control; ++ u16 Register; ++ u8 EthAddr[NODE_ADDRESS_SIZE]; ++ bool KeyValid; ++ ++ if (is_valid_ether_addr(hw->perm_mac_addr)) ++ return 0; ++ ++ Addr[0] = 0; ++ Addr[1] = 0; ++ ++ if (!atl2_check_eeprom_exist(hw)) { /* eeprom exists */ ++ Register = 0; ++ KeyValid = false; ++ ++ /* Read out all EEPROM content */ ++ i = 0; ++ while (1) { ++ if (atl2_read_eeprom(hw, i + 0x100, &Control)) { ++ if (KeyValid) { ++ if (Register == REG_MAC_STA_ADDR) ++ Addr[0] = Control; ++ else if (Register == ++ (REG_MAC_STA_ADDR + 4)) ++ Addr[1] = Control; ++ KeyValid = false; ++ } else if ((Control & 0xff) == 0x5A) { ++ KeyValid = true; ++ Register = (u16) (Control >> 16); ++ } else { ++ /* assume data end while encount an invalid KEYWORD */ ++ break; ++ } ++ } else { ++ break; /* read error */ ++ } ++ i += 4; ++ } ++ ++ *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); ++ *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); ++ ++ if (is_valid_ether_addr(EthAddr)) { ++ memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); ++ return 0; ++ } ++ return 1; ++ } ++ ++ /* see if SPI flash exists? */ ++ Addr[0] = 0; ++ Addr[1] = 0; ++ Register = 0; ++ KeyValid = false; ++ i = 0; ++ while (1) { ++ if (atl2_spi_read(hw, i + 0x1f000, &Control)) { ++ if (KeyValid) { ++ if (Register == REG_MAC_STA_ADDR) ++ Addr[0] = Control; ++ else if (Register == (REG_MAC_STA_ADDR + 4)) ++ Addr[1] = Control; ++ KeyValid = false; ++ } else if ((Control & 0xff) == 0x5A) { ++ KeyValid = true; ++ Register = (u16) (Control >> 16); ++ } else { ++ break; /* data end */ ++ } ++ } else { ++ break; /* read error */ ++ } ++ i += 4; ++ } ++ ++ *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); ++ *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *)&Addr[1]); ++ if (is_valid_ether_addr(EthAddr)) { ++ memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); ++ return 0; ++ } ++ /* maybe MAC-address is from BIOS */ ++ Addr[0] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); ++ Addr[1] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR + 4); ++ *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); ++ *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); ++ ++ if (is_valid_ether_addr(EthAddr)) { ++ memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * Reads the adapter's MAC address from the EEPROM ++ * ++ * hw - Struct containing variables accessed by shared code ++ */ ++static s32 atl2_read_mac_addr(struct atl2_hw *hw) ++{ ++ u16 i; ++ ++ if (get_permanent_address(hw)) { ++ /* for test */ ++ /* FIXME: shouldn't we use random_ether_addr() here? */ ++ hw->perm_mac_addr[0] = 0x00; ++ hw->perm_mac_addr[1] = 0x13; ++ hw->perm_mac_addr[2] = 0x74; ++ hw->perm_mac_addr[3] = 0x00; ++ hw->perm_mac_addr[4] = 0x5c; ++ hw->perm_mac_addr[5] = 0x38; ++ } ++ ++ for (i = 0; i < NODE_ADDRESS_SIZE; i++) ++ hw->mac_addr[i] = hw->perm_mac_addr[i]; ++ ++ return 0; ++} ++ ++/* ++ * Hashes an address to determine its location in the multicast table ++ * ++ * hw - Struct containing variables accessed by shared code ++ * mc_addr - the multicast address to hash ++ * ++ * atl2_hash_mc_addr ++ * purpose ++ * set hash value for a multicast address ++ * hash calcu processing : ++ * 1. calcu 32bit CRC for multicast address ++ * 2. reverse crc with MSB to LSB ++ */ ++static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr) ++{ ++ u32 crc32, value; ++ int i; ++ ++ value = 0; ++ crc32 = ether_crc_le(6, mc_addr); ++ ++ for (i = 0; i < 32; i++) ++ value |= (((crc32 >> i) & 1) << (31 - i)); ++ ++ return value; ++} ++ ++/* ++ * Sets the bit in the multicast table corresponding to the hash value. ++ * ++ * hw - Struct containing variables accessed by shared code ++ * hash_value - Multicast address hash value ++ */ ++static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value) ++{ ++ u32 hash_bit, hash_reg; ++ u32 mta; ++ ++ /* The HASH Table is a register array of 2 32-bit registers. ++ * It is treated like an array of 64 bits. We want to set ++ * bit BitArray[hash_value]. So we figure out what register ++ * the bit is in, read it, OR in the new bit, then write ++ * back the new value. The register is determined by the ++ * upper 7 bits of the hash value and the bit within that ++ * register are determined by the lower 5 bits of the value. ++ */ ++ hash_reg = (hash_value >> 31) & 0x1; ++ hash_bit = (hash_value >> 26) & 0x1F; ++ ++ mta = ATL2_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg); ++ ++ mta |= (1 << hash_bit); ++ ++ ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta); ++} ++ ++/* ++ * atl2_init_pcie - init PCIE module ++ */ ++static void atl2_init_pcie(struct atl2_hw *hw) ++{ ++ u32 value; ++ value = LTSSM_TEST_MODE_DEF; ++ ATL2_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value); ++ ++ value = PCIE_DLL_TX_CTRL1_DEF; ++ ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, value); ++} ++ ++static void atl2_init_flash_opcode(struct atl2_hw *hw) ++{ ++ if (hw->flash_vendor >= ARRAY_SIZE(flash_table)) ++ hw->flash_vendor = 0; /* ATMEL */ ++ ++ /* Init OP table */ ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_PROGRAM, ++ flash_table[hw->flash_vendor].cmdPROGRAM); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_SC_ERASE, ++ flash_table[hw->flash_vendor].cmdSECTOR_ERASE); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_CHIP_ERASE, ++ flash_table[hw->flash_vendor].cmdCHIP_ERASE); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDID, ++ flash_table[hw->flash_vendor].cmdRDID); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WREN, ++ flash_table[hw->flash_vendor].cmdWREN); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDSR, ++ flash_table[hw->flash_vendor].cmdRDSR); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WRSR, ++ flash_table[hw->flash_vendor].cmdWRSR); ++ ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_READ, ++ flash_table[hw->flash_vendor].cmdREAD); ++} ++ ++/******************************************************************** ++* Performs basic configuration of the adapter. ++* ++* hw - Struct containing variables accessed by shared code ++* Assumes that the controller has previously been reset and is in a ++* post-reset uninitialized state. Initializes multicast table, ++* and Calls routines to setup link ++* Leaves the transmit and receive units disabled and uninitialized. ++********************************************************************/ ++static s32 atl2_init_hw(struct atl2_hw *hw) ++{ ++ u32 ret_val = 0; ++ ++ atl2_init_pcie(hw); ++ ++ /* Zero out the Multicast HASH table */ ++ /* clear the old settings from the multicast hash table */ ++ ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); ++ ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); ++ ++ atl2_init_flash_opcode(hw); ++ ++ ret_val = atl2_phy_init(hw); ++ ++ return ret_val; ++} ++ ++/* ++ * Detects the current speed and duplex settings of the hardware. ++ * ++ * hw - Struct containing variables accessed by shared code ++ * speed - Speed of the connection ++ * duplex - Duplex setting of the connection ++ */ ++static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, ++ u16 *duplex) ++{ ++ s32 ret_val; ++ u16 phy_data; ++ ++ /* Read PHY Specific Status Register (17) */ ++ ret_val = atl2_read_phy_reg(hw, MII_ATLX_PSSR, &phy_data); ++ if (ret_val) ++ return ret_val; ++ ++ if (!(phy_data & MII_ATLX_PSSR_SPD_DPLX_RESOLVED)) ++ return ATLX_ERR_PHY_RES; ++ ++ switch (phy_data & MII_ATLX_PSSR_SPEED) { ++ case MII_ATLX_PSSR_100MBS: ++ *speed = SPEED_100; ++ break; ++ case MII_ATLX_PSSR_10MBS: ++ *speed = SPEED_10; ++ break; ++ default: ++ return ATLX_ERR_PHY_SPEED; ++ break; ++ } ++ ++ if (phy_data & MII_ATLX_PSSR_DPLX) ++ *duplex = FULL_DUPLEX; ++ else ++ *duplex = HALF_DUPLEX; ++ ++ return 0; ++} ++ ++/* ++ * Reads the value from a PHY register ++ * hw - Struct containing variables accessed by shared code ++ * reg_addr - address of the PHY register to read ++ */ ++static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data) ++{ ++ u32 val; ++ int i; ++ ++ val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | ++ MDIO_START | ++ MDIO_SUP_PREAMBLE | ++ MDIO_RW | ++ MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; ++ ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); ++ ++ wmb(); ++ ++ for (i = 0; i < MDIO_WAIT_TIMES; i++) { ++ udelay(2); ++ val = ATL2_READ_REG(hw, REG_MDIO_CTRL); ++ if (!(val & (MDIO_START | MDIO_BUSY))) ++ break; ++ wmb(); ++ } ++ if (!(val & (MDIO_START | MDIO_BUSY))) { ++ *phy_data = (u16)val; ++ return 0; ++ } ++ ++ return ATLX_ERR_PHY; ++} ++ ++/* ++ * Writes a value to a PHY register ++ * hw - Struct containing variables accessed by shared code ++ * reg_addr - address of the PHY register to write ++ * data - data to write to the PHY ++ */ ++static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data) ++{ ++ int i; ++ u32 val; ++ ++ val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | ++ (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | ++ MDIO_SUP_PREAMBLE | ++ MDIO_START | ++ MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; ++ ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); ++ ++ wmb(); ++ ++ for (i = 0; i < MDIO_WAIT_TIMES; i++) { ++ udelay(2); ++ val = ATL2_READ_REG(hw, REG_MDIO_CTRL); ++ if (!(val & (MDIO_START | MDIO_BUSY))) ++ break; ++ ++ wmb(); ++ } ++ ++ if (!(val & (MDIO_START | MDIO_BUSY))) ++ return 0; ++ ++ return ATLX_ERR_PHY; ++} ++ ++/* ++ * Configures PHY autoneg and flow control advertisement settings ++ * ++ * hw - Struct containing variables accessed by shared code ++ */ ++static s32 atl2_phy_setup_autoneg_adv(struct atl2_hw *hw) ++{ ++ s32 ret_val; ++ s16 mii_autoneg_adv_reg; ++ ++ /* Read the MII Auto-Neg Advertisement Register (Address 4). */ ++ mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; ++ ++ /* Need to parse autoneg_advertised and set up ++ * the appropriate PHY registers. First we will parse for ++ * autoneg_advertised software override. Since we can advertise ++ * a plethora of combinations, we need to check each bit ++ * individually. ++ */ ++ ++ /* First we clear all the 10/100 mb speed bits in the Auto-Neg ++ * Advertisement Register (Address 4) and the 1000 mb speed bits in ++ * the 1000Base-T Control Register (Address 9). */ ++ mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; ++ ++ /* Need to parse MediaType and setup the ++ * appropriate PHY registers. */ ++ switch (hw->MediaType) { ++ case MEDIA_TYPE_AUTO_SENSOR: ++ mii_autoneg_adv_reg |= ++ (MII_AR_10T_HD_CAPS | ++ MII_AR_10T_FD_CAPS | ++ MII_AR_100TX_HD_CAPS| ++ MII_AR_100TX_FD_CAPS); ++ hw->autoneg_advertised = ++ ADVERTISE_10_HALF | ++ ADVERTISE_10_FULL | ++ ADVERTISE_100_HALF| ++ ADVERTISE_100_FULL; ++ break; ++ case MEDIA_TYPE_100M_FULL: ++ mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; ++ hw->autoneg_advertised = ADVERTISE_100_FULL; ++ break; ++ case MEDIA_TYPE_100M_HALF: ++ mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; ++ hw->autoneg_advertised = ADVERTISE_100_HALF; ++ break; ++ case MEDIA_TYPE_10M_FULL: ++ mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; ++ hw->autoneg_advertised = ADVERTISE_10_FULL; ++ break; ++ default: ++ mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; ++ hw->autoneg_advertised = ADVERTISE_10_HALF; ++ break; ++ } ++ ++ /* flow control fixed to enable all */ ++ mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); ++ ++ hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; ++ ++ ret_val = atl2_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); ++ ++ if (ret_val) ++ return ret_val; ++ ++ return 0; ++} ++ ++/* ++ * Resets the PHY and make all config validate ++ * ++ * hw - Struct containing variables accessed by shared code ++ * ++ * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) ++ */ ++static s32 atl2_phy_commit(struct atl2_hw *hw) ++{ ++ s32 ret_val; ++ u16 phy_data; ++ ++ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG; ++ ret_val = atl2_write_phy_reg(hw, MII_BMCR, phy_data); ++ if (ret_val) { ++ u32 val; ++ int i; ++ /* pcie serdes link may be down ! */ ++ for (i = 0; i < 25; i++) { ++ msleep(1); ++ val = ATL2_READ_REG(hw, REG_MDIO_CTRL); ++ if (!(val & (MDIO_START | MDIO_BUSY))) ++ break; ++ } ++ ++ if (0 != (val & (MDIO_START | MDIO_BUSY))) { ++ printk(KERN_ERR "atl2: PCIe link down for at least 25ms !\n"); ++ return ret_val; ++ } ++ } ++ return 0; ++} ++ ++static s32 atl2_phy_init(struct atl2_hw *hw) ++{ ++ s32 ret_val; ++ u16 phy_val; ++ ++ if (hw->phy_configured) ++ return 0; ++ ++ /* Enable PHY */ ++ ATL2_WRITE_REGW(hw, REG_PHY_ENABLE, 1); ++ ATL2_WRITE_FLUSH(hw); ++ msleep(1); ++ ++ /* check if the PHY is in powersaving mode */ ++ atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); ++ atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); ++ ++ /* 024E / 124E 0r 0274 / 1274 ? */ ++ if (phy_val & 0x1000) { ++ phy_val &= ~0x1000; ++ atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val); ++ } ++ ++ msleep(1); ++ ++ /*Enable PHY LinkChange Interrupt */ ++ ret_val = atl2_write_phy_reg(hw, 18, 0xC00); ++ if (ret_val) ++ return ret_val; ++ ++ /* setup AutoNeg parameters */ ++ ret_val = atl2_phy_setup_autoneg_adv(hw); ++ if (ret_val) ++ return ret_val; ++ ++ /* SW.Reset & En-Auto-Neg to restart Auto-Neg */ ++ ret_val = atl2_phy_commit(hw); ++ if (ret_val) ++ return ret_val; ++ ++ hw->phy_configured = true; ++ ++ return ret_val; ++} ++ ++static void atl2_set_mac_addr(struct atl2_hw *hw) ++{ ++ u32 value; ++ /* 00-0B-6A-F6-00-DC ++ * 0: 6AF600DC 1: 000B ++ * low dword */ ++ value = (((u32)hw->mac_addr[2]) << 24) | ++ (((u32)hw->mac_addr[3]) << 16) | ++ (((u32)hw->mac_addr[4]) << 8) | ++ (((u32)hw->mac_addr[5])); ++ ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); ++ /* hight dword */ ++ value = (((u32)hw->mac_addr[0]) << 8) | ++ (((u32)hw->mac_addr[1])); ++ ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); ++} ++ ++/* ++ * check_eeprom_exist ++ * return 0 if eeprom exist ++ */ ++static int atl2_check_eeprom_exist(struct atl2_hw *hw) ++{ ++ u32 value; ++ ++ value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); ++ if (value & SPI_FLASH_CTRL_EN_VPD) { ++ value &= ~SPI_FLASH_CTRL_EN_VPD; ++ ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); ++ } ++ value = ATL2_READ_REGW(hw, REG_PCIE_CAP_LIST); ++ return ((value & 0xFF00) == 0x6C00) ? 0 : 1; ++} ++ ++/* FIXME: This doesn't look right. -- CHS */ ++static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value) ++{ ++ return true; ++} ++ ++static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue) ++{ ++ int i; ++ u32 Control; ++ ++ if (Offset & 0x3) ++ return false; /* address do not align */ ++ ++ ATL2_WRITE_REG(hw, REG_VPD_DATA, 0); ++ Control = (Offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; ++ ATL2_WRITE_REG(hw, REG_VPD_CAP, Control); ++ ++ for (i = 0; i < 10; i++) { ++ msleep(2); ++ Control = ATL2_READ_REG(hw, REG_VPD_CAP); ++ if (Control & VPD_CAP_VPD_FLAG) ++ break; ++ } ++ ++ if (Control & VPD_CAP_VPD_FLAG) { ++ *pValue = ATL2_READ_REG(hw, REG_VPD_DATA); ++ return true; ++ } ++ return false; /* timeout */ ++} ++ ++static void atl2_force_ps(struct atl2_hw *hw) ++{ ++ u16 phy_val; ++ ++ atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); ++ atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); ++ atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val | 0x1000); ++ ++ atl2_write_phy_reg(hw, MII_DBG_ADDR, 2); ++ atl2_write_phy_reg(hw, MII_DBG_DATA, 0x3000); ++ atl2_write_phy_reg(hw, MII_DBG_ADDR, 3); ++ atl2_write_phy_reg(hw, MII_DBG_DATA, 0); ++} ++ ++/* This is the only thing that needs to be changed to adjust the ++ * maximum number of ports that the driver can manage. ++ */ ++#define ATL2_MAX_NIC 4 ++ ++#define OPTION_UNSET -1 ++#define OPTION_DISABLED 0 ++#define OPTION_ENABLED 1 ++ ++/* All parameters are treated the same, as an integer array of values. ++ * This macro just reduces the need to repeat the same declaration code ++ * over and over (plus this helps to avoid typo bugs). ++ */ ++#define ATL2_PARAM_INIT {[0 ... ATL2_MAX_NIC] = OPTION_UNSET} ++#ifndef module_param_array ++/* Module Parameters are always initialized to -1, so that the driver ++ * can tell the difference between no user specified value or the ++ * user asking for the default value. ++ * The true default values are loaded in when atl2_check_options is called. ++ * ++ * This is a GCC extension to ANSI C. ++ * See the item "Labeled Elements in Initializers" in the section ++ * "Extensions to the C Language Family" of the GCC documentation. ++ */ ++ ++#define ATL2_PARAM(X, desc) \ ++ static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ ++ MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ ++ MODULE_PARM_DESC(X, desc); ++#else ++#define ATL2_PARAM(X, desc) \ ++ static int __devinitdata X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \ ++ static int num_##X = 0; \ ++ module_param_array_named(X, X, int, &num_##X, 0); \ ++ MODULE_PARM_DESC(X, desc); ++#endif ++ ++/* ++ * Transmit Memory Size ++ * Valid Range: 64-2048 ++ * Default Value: 128 ++ */ ++#define ATL2_MIN_TX_MEMSIZE 4 /* 4KB */ ++#define ATL2_MAX_TX_MEMSIZE 64 /* 64KB */ ++#define ATL2_DEFAULT_TX_MEMSIZE 8 /* 8KB */ ++ATL2_PARAM(TxMemSize, "Bytes of Transmit Memory"); ++ ++/* ++ * Receive Memory Block Count ++ * Valid Range: 16-512 ++ * Default Value: 128 ++ */ ++#define ATL2_MIN_RXD_COUNT 16 ++#define ATL2_MAX_RXD_COUNT 512 ++#define ATL2_DEFAULT_RXD_COUNT 64 ++ATL2_PARAM(RxMemBlock, "Number of receive memory block"); ++ ++/* ++ * User Specified MediaType Override ++ * ++ * Valid Range: 0-5 ++ * - 0 - auto-negotiate at all supported speeds ++ * - 1 - only link at 1000Mbps Full Duplex ++ * - 2 - only link at 100Mbps Full Duplex ++ * - 3 - only link at 100Mbps Half Duplex ++ * - 4 - only link at 10Mbps Full Duplex ++ * - 5 - only link at 10Mbps Half Duplex ++ * Default Value: 0 ++ */ ++ATL2_PARAM(MediaType, "MediaType Select"); ++ ++/* ++ * Interrupt Moderate Timer in units of 2048 ns (~2 us) ++ * Valid Range: 10-65535 ++ * Default Value: 45000(90ms) ++ */ ++#define INT_MOD_DEFAULT_CNT 100 /* 200us */ ++#define INT_MOD_MAX_CNT 65000 ++#define INT_MOD_MIN_CNT 50 ++ATL2_PARAM(IntModTimer, "Interrupt Moderator Timer"); ++ ++/* ++ * FlashVendor ++ * Valid Range: 0-2 ++ * 0 - Atmel ++ * 1 - SST ++ * 2 - ST ++ */ ++ATL2_PARAM(FlashVendor, "SPI Flash Vendor"); ++ ++#define AUTONEG_ADV_DEFAULT 0x2F ++#define AUTONEG_ADV_MASK 0x2F ++#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL ++ ++#define FLASH_VENDOR_DEFAULT 0 ++#define FLASH_VENDOR_MIN 0 ++#define FLASH_VENDOR_MAX 2 ++ ++struct atl2_option { ++ enum { enable_option, range_option, list_option } type; ++ char *name; ++ char *err; ++ int def; ++ union { ++ struct { /* range_option info */ ++ int min; ++ int max; ++ } r; ++ struct { /* list_option info */ ++ int nr; ++ struct atl2_opt_list { int i; char *str; } *p; ++ } l; ++ } arg; ++}; ++ ++static int __devinit atl2_validate_option(int *value, struct atl2_option *opt) ++{ ++ int i; ++ struct atl2_opt_list *ent; ++ ++ if (*value == OPTION_UNSET) { ++ *value = opt->def; ++ return 0; ++ } ++ ++ switch (opt->type) { ++ case enable_option: ++ switch (*value) { ++ case OPTION_ENABLED: ++ printk(KERN_INFO "%s Enabled\n", opt->name); ++ return 0; ++ break; ++ case OPTION_DISABLED: ++ printk(KERN_INFO "%s Disabled\n", opt->name); ++ return 0; ++ break; ++ } ++ break; ++ case range_option: ++ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { ++ printk(KERN_INFO "%s set to %i\n", opt->name, *value); ++ return 0; ++ } ++ break; ++ case list_option: ++ for (i = 0; i < opt->arg.l.nr; i++) { ++ ent = &opt->arg.l.p[i]; ++ if (*value == ent->i) { ++ if (ent->str[0] != '\0') ++ printk(KERN_INFO "%s\n", ent->str); ++ return 0; ++ } ++ } ++ break; ++ default: ++ BUG(); ++ } ++ ++ printk(KERN_INFO "Invalid %s specified (%i) %s\n", ++ opt->name, *value, opt->err); ++ *value = opt->def; ++ return -1; ++} ++ ++/* ++ * atl2_check_options - Range Checking for Command Line Parameters ++ * @adapter: board private structure ++ * ++ * This routine checks all command line parameters for valid user ++ * input. If an invalid value is given, or if no user specified ++ * value exists, a default value is used. The final value is stored ++ * in a variable in the adapter structure. ++ */ ++static void __devinit atl2_check_options(struct atl2_adapter *adapter) ++{ ++ int val; ++ struct atl2_option opt; ++ int bd = adapter->bd_number; ++ if (bd >= ATL2_MAX_NIC) { ++ printk(KERN_NOTICE "Warning: no configuration for board #%i\n", ++ bd); ++ printk(KERN_NOTICE "Using defaults for all values\n"); ++#ifndef module_param_array ++ bd = ATL2_MAX_NIC; ++#endif ++ } ++ ++ /* Bytes of Transmit Memory */ ++ opt.type = range_option; ++ opt.name = "Bytes of Transmit Memory"; ++ opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_TX_MEMSIZE); ++ opt.def = ATL2_DEFAULT_TX_MEMSIZE; ++ opt.arg.r.min = ATL2_MIN_TX_MEMSIZE; ++ opt.arg.r.max = ATL2_MAX_TX_MEMSIZE; ++#ifdef module_param_array ++ if (num_TxMemSize > bd) { ++#endif ++ val = TxMemSize[bd]; ++ atl2_validate_option(&val, &opt); ++ adapter->txd_ring_size = ((u32) val) * 1024; ++#ifdef module_param_array ++ } else ++ adapter->txd_ring_size = ((u32)opt.def) * 1024; ++#endif ++ /* txs ring size: */ ++ adapter->txs_ring_size = adapter->txd_ring_size / 128; ++ if (adapter->txs_ring_size > 160) ++ adapter->txs_ring_size = 160; ++ ++ /* Receive Memory Block Count */ ++ opt.type = range_option; ++ opt.name = "Number of receive memory block"; ++ opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_RXD_COUNT); ++ opt.def = ATL2_DEFAULT_RXD_COUNT; ++ opt.arg.r.min = ATL2_MIN_RXD_COUNT; ++ opt.arg.r.max = ATL2_MAX_RXD_COUNT; ++#ifdef module_param_array ++ if (num_RxMemBlock > bd) { ++#endif ++ val = RxMemBlock[bd]; ++ atl2_validate_option(&val, &opt); ++ adapter->rxd_ring_size = (u32)val; ++ /* FIXME */ ++ /* ((u16)val)&~1; */ /* even number */ ++#ifdef module_param_array ++ } else ++ adapter->rxd_ring_size = (u32)opt.def; ++#endif ++ /* init RXD Flow control value */ ++ adapter->hw.fc_rxd_hi = (adapter->rxd_ring_size / 8) * 7; ++ adapter->hw.fc_rxd_lo = (ATL2_MIN_RXD_COUNT / 8) > ++ (adapter->rxd_ring_size / 12) ? (ATL2_MIN_RXD_COUNT / 8) : ++ (adapter->rxd_ring_size / 12); ++ ++ /* Interrupt Moderate Timer */ ++ opt.type = range_option; ++ opt.name = "Interrupt Moderate Timer"; ++ opt.err = "using default of " __MODULE_STRING(INT_MOD_DEFAULT_CNT); ++ opt.def = INT_MOD_DEFAULT_CNT; ++ opt.arg.r.min = INT_MOD_MIN_CNT; ++ opt.arg.r.max = INT_MOD_MAX_CNT; ++#ifdef module_param_array ++ if (num_IntModTimer > bd) { ++#endif ++ val = IntModTimer[bd]; ++ atl2_validate_option(&val, &opt); ++ adapter->imt = (u16) val; ++#ifdef module_param_array ++ } else ++ adapter->imt = (u16)(opt.def); ++#endif ++ /* Flash Vendor */ ++ opt.type = range_option; ++ opt.name = "SPI Flash Vendor"; ++ opt.err = "using default of " __MODULE_STRING(FLASH_VENDOR_DEFAULT); ++ opt.def = FLASH_VENDOR_DEFAULT; ++ opt.arg.r.min = FLASH_VENDOR_MIN; ++ opt.arg.r.max = FLASH_VENDOR_MAX; ++#ifdef module_param_array ++ if (num_FlashVendor > bd) { ++#endif ++ val = FlashVendor[bd]; ++ atl2_validate_option(&val, &opt); ++ adapter->hw.flash_vendor = (u8) val; ++#ifdef module_param_array ++ } else ++ adapter->hw.flash_vendor = (u8)(opt.def); ++#endif ++ /* MediaType */ ++ opt.type = range_option; ++ opt.name = "Speed/Duplex Selection"; ++ opt.err = "using default of " __MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR); ++ opt.def = MEDIA_TYPE_AUTO_SENSOR; ++ opt.arg.r.min = MEDIA_TYPE_AUTO_SENSOR; ++ opt.arg.r.max = MEDIA_TYPE_10M_HALF; ++#ifdef module_param_array ++ if (num_MediaType > bd) { ++#endif ++ val = MediaType[bd]; ++ atl2_validate_option(&val, &opt); ++ adapter->hw.MediaType = (u16) val; ++#ifdef module_param_array ++ } else ++ adapter->hw.MediaType = (u16)(opt.def); ++#endif ++} +--- /dev/null ++++ b/drivers/net/atlx/atl2.h +@@ -0,0 +1,530 @@ ++/* atl2.h -- atl2 driver definitions ++ * ++ * Copyright(c) 2007 Atheros Corporation. All rights reserved. ++ * Copyright(c) 2006 xiong huang ++ * Copyright(c) 2007 Chris Snook ++ * ++ * Derived from Intel e1000 driver ++ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#ifndef _ATL2_H_ ++#define _ATL2_H_ ++ ++#include ++#include ++ ++#ifndef _ATL2_HW_H_ ++#define _ATL2_HW_H_ ++ ++#ifndef _ATL2_OSDEP_H_ ++#define _ATL2_OSDEP_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include "atlx.h" ++ ++#ifdef ETHTOOL_OPS_COMPAT ++extern int ethtool_ioctl(struct ifreq *ifr); ++#endif ++ ++#define PCI_COMMAND_REGISTER PCI_COMMAND ++#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE ++#define ETH_ADDR_LEN ETH_ALEN ++ ++#define ATL2_WRITE_REG(a, reg, value) (iowrite32((value), \ ++ ((a)->hw_addr + (reg)))) ++ ++#define ATL2_WRITE_FLUSH(a) (ioread32((a)->hw_addr)) ++ ++#define ATL2_READ_REG(a, reg) (ioread32((a)->hw_addr + (reg))) ++ ++#define ATL2_WRITE_REGB(a, reg, value) (iowrite8((value), \ ++ ((a)->hw_addr + (reg)))) ++ ++#define ATL2_READ_REGB(a, reg) (ioread8((a)->hw_addr + (reg))) ++ ++#define ATL2_WRITE_REGW(a, reg, value) (iowrite16((value), \ ++ ((a)->hw_addr + (reg)))) ++ ++#define ATL2_READ_REGW(a, reg) (ioread16((a)->hw_addr + (reg))) ++ ++#define ATL2_WRITE_REG_ARRAY(a, reg, offset, value) \ ++ (iowrite32((value), (((a)->hw_addr + (reg)) + ((offset) << 2)))) ++ ++#define ATL2_READ_REG_ARRAY(a, reg, offset) \ ++ (ioread32(((a)->hw_addr + (reg)) + ((offset) << 2))) ++ ++#endif /* _ATL2_OSDEP_H_ */ ++ ++struct atl2_adapter; ++struct atl2_hw; ++ ++/* function prototype */ ++static s32 atl2_reset_hw(struct atl2_hw *hw); ++static s32 atl2_read_mac_addr(struct atl2_hw *hw); ++static s32 atl2_init_hw(struct atl2_hw *hw); ++static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, ++ u16 *duplex); ++static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr); ++static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value); ++static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data); ++static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data); ++static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value); ++static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value); ++static void atl2_set_mac_addr(struct atl2_hw *hw); ++static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue); ++static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value); ++static s32 atl2_phy_init(struct atl2_hw *hw); ++static int atl2_check_eeprom_exist(struct atl2_hw *hw); ++static void atl2_force_ps(struct atl2_hw *hw); ++ ++/* register definition */ ++ ++/* Block IDLE Status Register */ ++#define IDLE_STATUS_RXMAC 1 /* 1: RXMAC is non-IDLE */ ++#define IDLE_STATUS_TXMAC 2 /* 1: TXMAC is non-IDLE */ ++#define IDLE_STATUS_DMAR 8 /* 1: DMAR is non-IDLE */ ++#define IDLE_STATUS_DMAW 4 /* 1: DMAW is non-IDLE */ ++ ++/* MDIO Control Register */ ++#define MDIO_WAIT_TIMES 10 ++ ++/* MAC Control Register */ ++#define MAC_CTRL_DBG_TX_BKPRESURE 0x100000 /* 1: TX max backoff */ ++#define MAC_CTRL_MACLP_CLK_PHY 0x8000000 /* 1: 25MHz from phy */ ++#define MAC_CTRL_HALF_LEFT_BUF_SHIFT 28 ++#define MAC_CTRL_HALF_LEFT_BUF_MASK 0xF /* MAC retry buf x32B */ ++ ++/* Internal SRAM Partition Register */ ++#define REG_SRAM_TXRAM_END 0x1500 /* Internal tail address of TXRAM ++ * default: 2byte*1024 */ ++#define REG_SRAM_RXRAM_END 0x1502 /* Internal tail address of RXRAM ++ * default: 2byte*1024 */ ++ ++/* Descriptor Control register */ ++#define REG_TXD_BASE_ADDR_LO 0x1544 /* The base address of the Transmit ++ * Data Mem low 32-bit(dword align) */ ++#define REG_TXD_MEM_SIZE 0x1548 /* Transmit Data Memory size(by ++ * double word , max 256KB) */ ++#define REG_TXS_BASE_ADDR_LO 0x154C /* The base address of the Transmit ++ * Status Memory low 32-bit(dword word ++ * align) */ ++#define REG_TXS_MEM_SIZE 0x1550 /* double word unit, max 4*2047 ++ * bytes. */ ++#define REG_RXD_BASE_ADDR_LO 0x1554 /* The base address of the Transmit ++ * Status Memory low 32-bit(unit 8 ++ * bytes) */ ++#define REG_RXD_BUF_NUM 0x1558 /* Receive Data & Status Memory buffer ++ * number (unit 1536bytes, max ++ * 1536*2047) */ ++ ++/* DMAR Control Register */ ++#define REG_DMAR 0x1580 ++#define DMAR_EN 0x1 /* 1: Enable DMAR */ ++ ++/* TX Cur-Through (early tx threshold) Control Register */ ++#define REG_TX_CUT_THRESH 0x1590 /* TxMac begin transmit packet ++ * threshold(unit word) */ ++ ++/* DMAW Control Register */ ++#define REG_DMAW 0x15A0 ++#define DMAW_EN 0x1 ++ ++/* Flow control register */ ++#define REG_PAUSE_ON_TH 0x15A8 /* RXD high watermark of overflow ++ * threshold configuration register */ ++#define REG_PAUSE_OFF_TH 0x15AA /* RXD lower watermark of overflow ++ * threshold configuration register */ ++ ++/* Mailbox Register */ ++#define REG_MB_TXD_WR_IDX 0x15f0 /* double word align */ ++#define REG_MB_RXD_RD_IDX 0x15F4 /* RXD Read index (unit: 1536byets) */ ++ ++/* Interrupt Status Register */ ++#define ISR_TIMER 1 /* Interrupt when Timer counts down to zero */ ++#define ISR_MANUAL 2 /* Software manual interrupt, for debug. Set ++ * when SW_MAN_INT_EN is set in Table 51 ++ * Selene Master Control Register ++ * (Offset 0x1400). */ ++#define ISR_RXF_OV 4 /* RXF overflow interrupt */ ++#define ISR_TXF_UR 8 /* TXF underrun interrupt */ ++#define ISR_TXS_OV 0x10 /* Internal transmit status buffer full ++ * interrupt */ ++#define ISR_RXS_OV 0x20 /* Internal receive status buffer full ++ * interrupt */ ++#define ISR_LINK_CHG 0x40 /* Link Status Change Interrupt */ ++#define ISR_HOST_TXD_UR 0x80 ++#define ISR_HOST_RXD_OV 0x100 /* Host rx data memory full , one pulse */ ++#define ISR_DMAR_TO_RST 0x200 /* DMAR op timeout interrupt. SW should ++ * do Reset */ ++#define ISR_DMAW_TO_RST 0x400 ++#define ISR_PHY 0x800 /* phy interrupt */ ++#define ISR_TS_UPDATE 0x10000 /* interrupt after new tx pkt status written ++ * to host */ ++#define ISR_RS_UPDATE 0x20000 /* interrupt ater new rx pkt status written ++ * to host. */ ++#define ISR_TX_EARLY 0x40000 /* interrupt when txmac begin transmit one ++ * packet */ ++ ++#define ISR_TX_EVENT (ISR_TXF_UR | ISR_TXS_OV | ISR_HOST_TXD_UR |\ ++ ISR_TS_UPDATE | ISR_TX_EARLY) ++#define ISR_RX_EVENT (ISR_RXF_OV | ISR_RXS_OV | ISR_HOST_RXD_OV |\ ++ ISR_RS_UPDATE) ++ ++#define IMR_NORMAL_MASK (\ ++ /*ISR_LINK_CHG |*/\ ++ ISR_MANUAL |\ ++ ISR_DMAR_TO_RST |\ ++ ISR_DMAW_TO_RST |\ ++ ISR_PHY |\ ++ ISR_PHY_LINKDOWN |\ ++ ISR_TS_UPDATE |\ ++ ISR_RS_UPDATE) ++ ++/* Receive MAC Statistics Registers */ ++#define REG_STS_RX_PAUSE 0x1700 /* Num pause packets received */ ++#define REG_STS_RXD_OV 0x1704 /* Num frames dropped due to RX ++ * FIFO overflow */ ++#define REG_STS_RXS_OV 0x1708 /* Num frames dropped due to RX ++ * Status Buffer Overflow */ ++#define REG_STS_RX_FILTER 0x170C /* Num packets dropped due to ++ * address filtering */ ++ ++/* MII definitions */ ++ ++/* PHY Common Register */ ++#define MII_SMARTSPEED 0x14 ++#define MII_DBG_ADDR 0x1D ++#define MII_DBG_DATA 0x1E ++ ++/* PCI Command Register Bit Definitions */ ++#define PCI_REG_COMMAND 0x04 ++#define CMD_IO_SPACE 0x0001 ++#define CMD_MEMORY_SPACE 0x0002 ++#define CMD_BUS_MASTER 0x0004 ++ ++#define MEDIA_TYPE_100M_FULL 1 ++#define MEDIA_TYPE_100M_HALF 2 ++#define MEDIA_TYPE_10M_FULL 3 ++#define MEDIA_TYPE_10M_HALF 4 ++ ++#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x000F /* Everything */ ++ ++/* The size (in bytes) of a ethernet packet */ ++#define ENET_HEADER_SIZE 14 ++#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ ++#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ ++#define ETHERNET_FCS_SIZE 4 ++#define MAX_JUMBO_FRAME_SIZE 0x2000 ++#define VLAN_SIZE 4 ++ ++struct tx_pkt_header { ++ unsigned pkt_size:11; ++ unsigned:4; /* reserved */ ++ unsigned ins_vlan:1; /* txmac should insert vlan */ ++ unsigned short vlan; /* vlan tag */ ++}; ++/* FIXME: replace above bitfields with MASK/SHIFT defines below */ ++#define TX_PKT_HEADER_SIZE_MASK 0x7FF ++#define TX_PKT_HEADER_SIZE_SHIFT 0 ++#define TX_PKT_HEADER_INS_VLAN_MASK 0x1 ++#define TX_PKT_HEADER_INS_VLAN_SHIFT 15 ++#define TX_PKT_HEADER_VLAN_TAG_MASK 0xFFFF ++#define TX_PKT_HEADER_VLAN_TAG_SHIFT 16 ++ ++struct tx_pkt_status { ++ unsigned pkt_size:11; ++ unsigned:5; /* reserved */ ++ unsigned ok:1; /* current packet transmitted without error */ ++ unsigned bcast:1; /* broadcast packet */ ++ unsigned mcast:1; /* multicast packet */ ++ unsigned pause:1; /* transmiited a pause frame */ ++ unsigned ctrl:1; ++ unsigned defer:1; /* current packet is xmitted with defer */ ++ unsigned exc_defer:1; ++ unsigned single_col:1; ++ unsigned multi_col:1; ++ unsigned late_col:1; ++ unsigned abort_col:1; ++ unsigned underun:1; /* current packet is aborted ++ * due to txram underrun */ ++ unsigned:3; /* reserved */ ++ unsigned update:1; /* always 1'b1 in tx_status_buf */ ++}; ++/* FIXME: replace above bitfields with MASK/SHIFT defines below */ ++#define TX_PKT_STATUS_SIZE_MASK 0x7FF ++#define TX_PKT_STATUS_SIZE_SHIFT 0 ++#define TX_PKT_STATUS_OK_MASK 0x1 ++#define TX_PKT_STATUS_OK_SHIFT 16 ++#define TX_PKT_STATUS_BCAST_MASK 0x1 ++#define TX_PKT_STATUS_BCAST_SHIFT 17 ++#define TX_PKT_STATUS_MCAST_MASK 0x1 ++#define TX_PKT_STATUS_MCAST_SHIFT 18 ++#define TX_PKT_STATUS_PAUSE_MASK 0x1 ++#define TX_PKT_STATUS_PAUSE_SHIFT 19 ++#define TX_PKT_STATUS_CTRL_MASK 0x1 ++#define TX_PKT_STATUS_CTRL_SHIFT 20 ++#define TX_PKT_STATUS_DEFER_MASK 0x1 ++#define TX_PKT_STATUS_DEFER_SHIFT 21 ++#define TX_PKT_STATUS_EXC_DEFER_MASK 0x1 ++#define TX_PKT_STATUS_EXC_DEFER_SHIFT 22 ++#define TX_PKT_STATUS_SINGLE_COL_MASK 0x1 ++#define TX_PKT_STATUS_SINGLE_COL_SHIFT 23 ++#define TX_PKT_STATUS_MULTI_COL_MASK 0x1 ++#define TX_PKT_STATUS_MULTI_COL_SHIFT 24 ++#define TX_PKT_STATUS_LATE_COL_MASK 0x1 ++#define TX_PKT_STATUS_LATE_COL_SHIFT 25 ++#define TX_PKT_STATUS_ABORT_COL_MASK 0x1 ++#define TX_PKT_STATUS_ABORT_COL_SHIFT 26 ++#define TX_PKT_STATUS_UNDERRUN_MASK 0x1 ++#define TX_PKT_STATUS_UNDERRUN_SHIFT 27 ++#define TX_PKT_STATUS_UPDATE_MASK 0x1 ++#define TX_PKT_STATUS_UPDATE_SHIFT 31 ++ ++struct rx_pkt_status { ++ unsigned pkt_size:11; /* packet size, max 2047 bytes */ ++ unsigned:5; /* reserved */ ++ unsigned ok:1; /* current packet received ok without error */ ++ unsigned bcast:1; /* current packet is broadcast */ ++ unsigned mcast:1; /* current packet is multicast */ ++ unsigned pause:1; ++ unsigned ctrl:1; ++ unsigned crc:1; /* received a packet with crc error */ ++ unsigned code:1; /* received a packet with code error */ ++ unsigned runt:1; /* received a packet less than 64 bytes ++ * with good crc */ ++ unsigned frag:1; /* received a packet less than 64 bytes ++ * with bad crc */ ++ unsigned trunc:1; /* current frame truncated due to rxram full */ ++ unsigned align:1; /* this packet is alignment error */ ++ unsigned vlan:1; /* this packet has vlan */ ++ unsigned:3; /* reserved */ ++ unsigned update:1; ++ unsigned short vtag; /* vlan tag */ ++ unsigned:16; ++}; ++/* FIXME: replace above bitfields with MASK/SHIFT defines below */ ++#define RX_PKT_STATUS_SIZE_MASK 0x7FF ++#define RX_PKT_STATUS_SIZE_SHIFT 0 ++#define RX_PKT_STATUS_OK_MASK 0x1 ++#define RX_PKT_STATUS_OK_SHIFT 16 ++#define RX_PKT_STATUS_BCAST_MASK 0x1 ++#define RX_PKT_STATUS_BCAST_SHIFT 17 ++#define RX_PKT_STATUS_MCAST_MASK 0x1 ++#define RX_PKT_STATUS_MCAST_SHIFT 18 ++#define RX_PKT_STATUS_PAUSE_MASK 0x1 ++#define RX_PKT_STATUS_PAUSE_SHIFT 19 ++#define RX_PKT_STATUS_CTRL_MASK 0x1 ++#define RX_PKT_STATUS_CTRL_SHIFT 20 ++#define RX_PKT_STATUS_CRC_MASK 0x1 ++#define RX_PKT_STATUS_CRC_SHIFT 21 ++#define RX_PKT_STATUS_CODE_MASK 0x1 ++#define RX_PKT_STATUS_CODE_SHIFT 22 ++#define RX_PKT_STATUS_RUNT_MASK 0x1 ++#define RX_PKT_STATUS_RUNT_SHIFT 23 ++#define RX_PKT_STATUS_FRAG_MASK 0x1 ++#define RX_PKT_STATUS_FRAG_SHIFT 24 ++#define RX_PKT_STATUS_TRUNK_MASK 0x1 ++#define RX_PKT_STATUS_TRUNK_SHIFT 25 ++#define RX_PKT_STATUS_ALIGN_MASK 0x1 ++#define RX_PKT_STATUS_ALIGN_SHIFT 26 ++#define RX_PKT_STATUS_VLAN_MASK 0x1 ++#define RX_PKT_STATUS_VLAN_SHIFT 27 ++#define RX_PKT_STATUS_UPDATE_MASK 0x1 ++#define RX_PKT_STATUS_UPDATE_SHIFT 31 ++#define RX_PKT_STATUS_VLAN_TAG_MASK 0xFFFF ++#define RX_PKT_STATUS_VLAN_TAG_SHIFT 32 ++ ++struct rx_desc { ++ struct rx_pkt_status status; ++ unsigned char packet[1536-sizeof(struct rx_pkt_status)]; ++}; ++ ++enum atl2_speed_duplex { ++ atl2_10_half = 0, ++ atl2_10_full = 1, ++ atl2_100_half = 2, ++ atl2_100_full = 3 ++}; ++ ++struct atl2_spi_flash_dev { ++ const char *manu_name; /* manufacturer id */ ++ /* op-code */ ++ u8 cmdWRSR; ++ u8 cmdREAD; ++ u8 cmdPROGRAM; ++ u8 cmdWREN; ++ u8 cmdWRDI; ++ u8 cmdRDSR; ++ u8 cmdRDID; ++ u8 cmdSECTOR_ERASE; ++ u8 cmdCHIP_ERASE; ++}; ++ ++/* Structure containing variables used by the shared code (atl2_hw.c) */ ++struct atl2_hw { ++ u8 __iomem *hw_addr; ++ void *back; ++ ++ u8 preamble_len; ++ u8 max_retry; /* Retransmission maximum, afterwards the ++ * packet will be discarded. */ ++ u8 jam_ipg; /* IPG to start JAM for collision based flow ++ * control in half-duplex mode. In unit of ++ * 8-bit time. */ ++ u8 ipgt; /* Desired back to back inter-packet gap. The ++ * default is 96-bit time. */ ++ u8 min_ifg; /* Minimum number of IFG to enforce in between ++ * RX frames. Frame gap below such IFP is ++ * dropped. */ ++ u8 ipgr1; /* 64bit Carrier-Sense window */ ++ u8 ipgr2; /* 96-bit IPG window */ ++ u8 retry_buf; /* When half-duplex mode, should hold some ++ * bytes for mac retry . (8*4bytes unit) */ ++ ++ u16 fc_rxd_hi; ++ u16 fc_rxd_lo; ++ u16 lcol; /* Collision Window */ ++ u16 max_frame_size; ++ ++ u16 MediaType; ++ u16 autoneg_advertised; ++ u16 pci_cmd_word; ++ ++ u16 mii_autoneg_adv_reg; ++ ++ u32 mem_rang; ++ u32 txcw; ++ u32 mc_filter_type; ++ u32 num_mc_addrs; ++ u32 collision_delta; ++ u32 tx_packet_delta; ++ u16 phy_spd_default; ++ ++ u16 device_id; ++ u16 vendor_id; ++ u16 subsystem_id; ++ u16 subsystem_vendor_id; ++ u8 revision_id; ++ ++ /* spi flash */ ++ u8 flash_vendor; ++ ++ u8 dma_fairness; ++ u8 mac_addr[NODE_ADDRESS_SIZE]; ++ u8 perm_mac_addr[NODE_ADDRESS_SIZE]; ++ ++ /* FIXME */ ++ /* bool phy_preamble_sup; */ ++ bool phy_configured; ++}; ++ ++#endif /* _ATL2_HW_H_ */ ++ ++struct atl2_ring_header { ++ /* pointer to the descriptor ring memory */ ++ void *desc; ++ /* physical adress of the descriptor ring */ ++ dma_addr_t dma; ++ /* length of descriptor ring in bytes */ ++ unsigned int size; ++}; ++ ++/* board specific private data structure */ ++struct atl2_adapter { ++ /* OS defined structs */ ++ struct net_device *netdev; ++ struct pci_dev *pdev; ++ struct net_device_stats net_stats; ++#ifdef NETIF_F_HW_VLAN_TX ++ struct vlan_group *vlgrp; ++#endif ++ u32 wol; ++ u16 link_speed; ++ u16 link_duplex; ++ ++ spinlock_t stats_lock; ++ spinlock_t tx_lock; ++ ++ struct work_struct reset_task; ++ struct work_struct link_chg_task; ++ struct timer_list watchdog_timer; ++ struct timer_list phy_config_timer; ++ ++ unsigned long cfg_phy; ++ bool mac_disabled; ++ ++ /* All Descriptor memory */ ++ dma_addr_t ring_dma; ++ void *ring_vir_addr; ++ int ring_size; ++ ++ struct tx_pkt_header *txd_ring; ++ dma_addr_t txd_dma; ++ ++ struct tx_pkt_status *txs_ring; ++ dma_addr_t txs_dma; ++ ++ struct rx_desc *rxd_ring; ++ dma_addr_t rxd_dma; ++ ++ u32 txd_ring_size; /* bytes per unit */ ++ u32 txs_ring_size; /* dwords per unit */ ++ u32 rxd_ring_size; /* 1536 bytes per unit */ ++ ++ /* read /write ptr: */ ++ /* host */ ++ u32 txd_write_ptr; ++ u32 txs_next_clear; ++ u32 rxd_read_ptr; ++ ++ /* nic */ ++ atomic_t txd_read_ptr; ++ atomic_t txs_write_ptr; ++ u32 rxd_write_ptr; ++ ++ /* Interrupt Moderator timer ( 2us resolution) */ ++ u16 imt; ++ /* Interrupt Clear timer (2us resolution) */ ++ u16 ict; ++ ++ unsigned long flags; ++ /* structs defined in atl2_hw.h */ ++ u32 bd_number; /* board number */ ++ bool pci_using_64; ++ bool have_msi; ++ struct atl2_hw hw; ++ ++ u32 usr_cmd; ++ /* FIXME */ ++ /* u32 regs_buff[ATL2_REGS_LEN]; */ ++ u32 pci_state[16]; ++ ++ u32 *config_space; ++}; ++ ++enum atl2_state_t { ++ __ATL2_TESTING, ++ __ATL2_RESETTING, ++ __ATL2_DOWN ++}; ++ ++#endif /* _ATL2_H_ */ +--- a/drivers/net/atlx/Makefile ++++ b/drivers/net/atlx/Makefile +@@ -1 +1,3 @@ + obj-$(CONFIG_ATL1) += atl1.o ++obj-$(CONFIG_ATL2) += atl2.o ++ +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -1840,6 +1840,17 @@ config NE_H8300 + Say Y here if you want to use the NE2000 compatible + controller on the Renesas H8/300 processor. + ++config ATL2 ++ tristate "Atheros L2 Fast Ethernet support" ++ depends on PCI ++ select CRC32 ++ select MII ++ help ++ This driver supports the Atheros L2 fast ethernet adapter. ++ ++ To compile this driver as a module, choose M here. The module ++ will be called atl2. ++ + source "drivers/net/fs_enet/Kconfig" + + endif # NET_ETHERNET +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_EHEA) += ehea/ + obj-$(CONFIG_CAN) += can/ + obj-$(CONFIG_BONDING) += bonding/ + obj-$(CONFIG_ATL1) += atlx/ ++obj-$(CONFIG_ATL2) += atlx/ + obj-$(CONFIG_ATL1E) += atl1e/ + obj-$(CONFIG_GIANFAR) += gianfar_driver.o + obj-$(CONFIG_TEHUTI) += tehuti.o +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -2222,6 +2222,7 @@ + + #define PCI_VENDOR_ID_ATTANSIC 0x1969 + #define PCI_DEVICE_ID_ATTANSIC_L1 0x1048 ++#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048 + + #define PCI_VENDOR_ID_JMICRON 0x197B + #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-added-flush_disk b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-added-flush_disk new file mode 100644 index 000000000..470204b21 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-added-flush_disk @@ -0,0 +1,79 @@ +Subject: Added flush_disk to factor out common buffer cache flushing code. +From: Andrew Patterson +Date: Thu Oct 9 08:56:13 2008 +0200: +Git: 56ade44b46780fa291fa68b824f1dafdcb11b0ca +References: FATE#302348,FATE#303786 + +We need to be able to flush the buffer cache for for more than +just when a disk is changed, so we factor out common cache flush code +in check_disk_change() to an internal flush_disk() routine. This +routine will then be used for both disk changes and disk resizes (in a +later patch). + +Include the disk name in the text indicating that there are busy +inodes on the device and increase the KERN severity of the message. + +Adapted for SLES11, based on the original commit. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + fs/block_dev.c | 32 +++++++++++++++++++++++++++----- + 1 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/fs/block_dev.c b/fs/block_dev.c +index f8df73a..eb029ac 100644 +--- a/fs/block_dev.c ++++ b/fs/block_dev.c +@@ -869,6 +869,32 @@ struct block_device *open_by_devnum(dev_t dev, unsigned mode) + EXPORT_SYMBOL(open_by_devnum); + + /** ++ * flush_disk - invalidates all buffer-cache entries on a disk ++ * ++ * @bdev: struct block device to be flushed ++ * ++ * Invalidates all buffer-cache entries on a disk. It should be called ++ * when a disk has been changed -- either by a media change or online ++ * resize. ++ */ ++static void flush_disk(struct block_device *bdev) ++{ ++ if (__invalidate_device(bdev)) { ++ char name[BDEVNAME_SIZE] = ""; ++ ++ if (bdev->bd_disk) ++ disk_name(bdev->bd_disk, 0, name); ++ printk(KERN_WARNING "VFS: busy inodes on changed media or " ++ "resized disk %s\n", name); ++ } ++ ++ if (!bdev->bd_disk) ++ return; ++ if (bdev->bd_disk->minors > 1) ++ bdev->bd_invalidated = 1; ++} ++ ++/** + * check_disk_size_change - checks for disk size change and adjusts + * bdev size. + * +@@ -945,13 +971,9 @@ int check_disk_change(struct block_device *bdev) + if (!bdops->media_changed(bdev->bd_disk)) + return 0; + +- if (__invalidate_device(bdev)) +- printk("VFS: busy inodes on changed media.\n"); +- ++ flush_disk(bdev); + if (bdops->revalidate_disk) + bdops->revalidate_disk(bdev->bd_disk); +- if (bdev->bd_disk->minors > 1) +- bdev->bd_invalidated = 1; + return 1; + } + +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-adjust-block-device-size b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-adjust-block-device-size new file mode 100644 index 000000000..8f8ff9ce6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-adjust-block-device-size @@ -0,0 +1,88 @@ +Subject: Adjust block device size after an online resize of a disk. +From: Andrew Patterson +Date: Thu Oct 9 08:56:12 2008 +0200: +Git: c3279d1454cdfed02a557d789d8a6d08ab4cbe70 +References: FATE#302348,FATE#303786 + +The revalidate_disk routine now checks if a disk has been resized by +comparing the gendisk capacity to the bdev inode size. If they are +different (usually because the disk has been resized underneath the kernel) +the bdev inode size is adjusted to match the capacity. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + fs/block_dev.c | 37 +++++++++++++++++++++++++++++++++++++ + include/linux/fs.h | 2 ++ + 2 files changed, 39 insertions(+) + +--- a/fs/block_dev.c ++++ b/fs/block_dev.c +@@ -869,6 +869,34 @@ struct block_device *open_by_devnum(dev_ + EXPORT_SYMBOL(open_by_devnum); + + /** ++ * check_disk_size_change - checks for disk size change and adjusts ++ * bdev size. ++ * ++ * @disk: struct gendisk to check ++ * @bdev: struct bdev to adjust. ++ * ++ * This routine checks to see if the bdev size does not match the disk size ++ * and adjusts it if it differs. ++ */ ++void check_disk_size_change(struct gendisk *disk, struct block_device *bdev) ++{ ++ loff_t disk_size, bdev_size; ++ ++ disk_size = (loff_t)get_capacity(disk) << 9; ++ bdev_size = i_size_read(bdev->bd_inode); ++ if (disk_size != bdev_size) { ++ char name[BDEVNAME_SIZE]; ++ ++ disk_name(disk, 0, name); ++ printk(KERN_INFO ++ "%s: detected capacity change from %lld to %lld\n", ++ name, bdev_size, disk_size); ++ i_size_write(bdev->bd_inode, disk_size); ++ } ++} ++EXPORT_SYMBOL(check_disk_size_change); ++ ++/** + * revalidate_disk - wrapper for lower-level driver's revalidate_disk + * call-back + * +@@ -880,11 +908,20 @@ EXPORT_SYMBOL(open_by_devnum); + */ + int revalidate_disk(struct gendisk *disk) + { ++ struct block_device *bdev; + int ret = 0; + + if (disk->fops->revalidate_disk) + ret = disk->fops->revalidate_disk(disk); + ++ bdev = bdget_disk(disk, 0); ++ if (!bdev) ++ return ret; ++ ++ mutex_lock(&bdev->bd_mutex); ++ check_disk_size_change(disk, bdev); ++ mutex_unlock(&bdev->bd_mutex); ++ bdput(bdev); + return ret; + } + EXPORT_SYMBOL(revalidate_disk); +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1742,6 +1742,8 @@ extern int fs_may_remount_ro(struct supe + */ + #define bio_data_dir(bio) ((bio)->bi_rw & 1) + ++extern void check_disk_size_change(struct gendisk *disk, ++ struct block_device *bdev); + extern int revalidate_disk(struct gendisk *); + extern int check_disk_change(struct block_device *); + extern int __invalidate_device(struct block_device *); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-call-flush_disk b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-call-flush_disk new file mode 100644 index 000000000..297f18c07 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-call-flush_disk @@ -0,0 +1,48 @@ +Subject: Call flush_disk() after detecting an online resize. +From: Andrew Patterson +Date: Thu Oct 9 08:56:13 2008 +0200: +Git: 608aeef17a91747d6303de4df5e2c2e6899a95e8 +References: FATE#302348,FATE#303786 + +We call flush_disk() to make sure the buffer cache for the disk is +flushed after a disk resize. There are two resize cases, growing and +shrinking. Given that users can shrink/then grow a disk before +revalidate_disk() is called, we treat the grow case identically to +shrinking. We need to flush the buffer cache after an online shrink +because, as James Bottomley puts it, + + The two use cases for shrinking I can see are + + 1. planned: the fs is already shrunk to within the new boundaries + and all data is relocated, so invalidate is fine (any dirty + buffers that might exist in the shrunk region are there only + because they were relocated but not yet written to their + original location). + 2. unplanned: In this case, the fs is probably toast, so whether + we invalidate or not isn't going to make a whole lot of + difference; it's still going to try to read or write from + sectors beyond the new size and get I/O errors. + +Immediately invalidating shrunk disks will cause errors for outstanding +I/Os for reads/write beyond the new end of the disk to be generated +earlier then if we waited for the normal buffer cache operation. It also +removes a potential security hole where we might keep old data around +from beyond the end of the shrunk disk if the disk was not invalidated. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + fs/block_dev.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/block_dev.c ++++ b/fs/block_dev.c +@@ -918,6 +918,7 @@ void check_disk_size_change(struct gendi + "%s: detected capacity change from %lld to %lld\n", + name, bdev_size, disk_size); + i_size_write(bdev->bd_inode, disk_size); ++ flush_disk(bdev); + } + } + EXPORT_SYMBOL(check_disk_size_change); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-check-for-device-resize b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-check-for-device-resize new file mode 100644 index 000000000..684664c8a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-check-for-device-resize @@ -0,0 +1,41 @@ +Subject: Check for device resize when rescanning partitions +From: Andrew Patterson +Date: Thu Oct 9 08:56:12 2008 +0200: +Git: 9bc3ffbfbdf71fefda8a261ef8d6fdc388a29b42 +References: FATE#302348,FATE#303786 + +Check for device resize in the rescan_partitions() routine. If the device +has been resized, the bdev size is set to match. The rescan_partitions() +routine is called when opening the device and when calling the +BLKRRPART ioctl. + +Adapted for SLES11, based on the original commit. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + fs/partitions/check.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/fs/partitions/check.c b/fs/partitions/check.c +index ecc3330..f74d929 100644 +--- a/fs/partitions/check.c ++++ b/fs/partitions/check.c +@@ -480,11 +480,12 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) + res = invalidate_partition(disk, 0); + if (res) + return res; +- bdev->bd_invalidated = 0; + for (p = 1; p < disk->minors; p++) + delete_partition(disk, p); + if (disk->fops->revalidate_disk) + disk->fops->revalidate_disk(disk); ++ check_disk_size_change(disk, bdev); ++ bdev->bd_invalidated = 0; + if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) + return 0; + if (IS_ERR(state)) /* I/O error reading the partition table */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-sd-driver-calls b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-sd-driver-calls new file mode 100644 index 000000000..bacd19997 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-sd-driver-calls @@ -0,0 +1,38 @@ +Subject: SCSI sd driver calls revalidate_disk wrapper. +From: Andrew Patterson +Date: Thu Oct 9 08:56:13 2008 +0200: +Git: f98a8cae12f2b2a8f9bfd7a53c990a1a405e880e +References: FATE#302348,FATE#303786 + +Modify the SCSI disk driver to call the revalidate_disk() +wrapper. This allows us to do some housekeeping such as accounting for +a disk being resized online. The wrapper will call +sd_revalidate_disk() at the appropriate time. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/sd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -160,7 +160,7 @@ sd_store_cache_type(struct device *dev, + sd_print_sense_hdr(sdkp, &sshdr); + return -EINVAL; + } +- sd_revalidate_disk(sdkp->disk); ++ revalidate_disk(sdkp->disk); + return count; + } + +@@ -911,7 +911,7 @@ static void sd_rescan(struct device *dev + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + + if (sdkp) { +- sd_revalidate_disk(sdkp->disk); ++ revalidate_disk(sdkp->disk); + scsi_disk_put(sdkp); + } + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-wrapper-for-revalidate_disk b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-wrapper-for-revalidate_disk new file mode 100644 index 000000000..9383aed02 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bdev-resize-wrapper-for-revalidate_disk @@ -0,0 +1,61 @@ +Subject: Wrapper for lower-level revalidate_disk routines. +From: Andrew Patterson +Date: Thu Oct 9 08:56:12 2008 +0200: +Git: 0c002c2f74e10baa9021d3ecc50585c6eafea568 +References: FATE#302348,FATE#303786 + +This is a wrapper for the lower-level revalidate_disk call-backs such +as sd_revalidate_disk(). It allows us to perform pre and post +operations when calling them. + +We will use this wrapper in a later patch to adjust block device sizes +after an online resize (a _post_ operation). + +Signed-off-by: Andrew Patterson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + fs/block_dev.c | 21 +++++++++++++++++++++ + include/linux/fs.h | 1 + + 2 files changed, 22 insertions(+) + +--- a/fs/block_dev.c ++++ b/fs/block_dev.c +@@ -868,6 +868,27 @@ struct block_device *open_by_devnum(dev_ + + EXPORT_SYMBOL(open_by_devnum); + ++/** ++ * revalidate_disk - wrapper for lower-level driver's revalidate_disk ++ * call-back ++ * ++ * @disk: struct gendisk to be revalidated ++ * ++ * This routine is a wrapper for lower-level driver's revalidate_disk ++ * call-backs. It is used to do common pre and post operations needed ++ * for all revalidate_disk operations. ++ */ ++int revalidate_disk(struct gendisk *disk) ++{ ++ int ret = 0; ++ ++ if (disk->fops->revalidate_disk) ++ ret = disk->fops->revalidate_disk(disk); ++ ++ return ret; ++} ++EXPORT_SYMBOL(revalidate_disk); ++ + /* + * This routine checks whether a removable media has been changed, + * and invalidates all buffer-cache-entries in that case. This +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1742,6 +1742,7 @@ extern int fs_may_remount_ro(struct supe + */ + #define bio_data_dir(bio) ((bio)->bi_rw & 1) + ++extern int revalidate_disk(struct gendisk *); + extern int check_disk_change(struct block_device *); + extern int __invalidate_device(struct block_device *); + extern int invalidate_partition(struct gendisk *, int); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/blk-request-based-multipath-update b/src/patches/suse-2.6.27.31/patches.drivers/blk-request-based-multipath-update new file mode 100644 index 000000000..e2a0ec806 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/blk-request-based-multipath-update @@ -0,0 +1,360 @@ +From: Kiyoshi Ueda +Subject: Block layer fixes for request-based multipathing +References: References: FATE#302108 + +This is a combined patch from linux-2.6.git. Commit-IDs: + +d6c578ec08b3f07050401ed83193b3f21729213b +afac32f0c9c68698eaf7688d52de859301a0539f +ebd2bf40e9cfa4ebfa614703944f4eafdf0d2c64 +509395182b6b7cf7e3c1ca2cd669506d8f43ee01 +88171cad9ace4b67c5298e6504d70454296afb76 + +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 169 +++++++++++++++++++++++++++++++++++++++++++++--- + block/blk-settings.c | 6 + + drivers/scsi/scsi_lib.c | 32 +++++++++ + include/linux/blkdev.h | 12 +++ + 4 files changed, 209 insertions(+), 10 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -592,7 +592,8 @@ blk_init_queue_node(request_fn_proc *rfn + q->request_fn = rfn; + q->prep_rq_fn = NULL; + q->unplug_fn = generic_unplug_device; +- q->queue_flags = (1 << QUEUE_FLAG_CLUSTER); ++ q->queue_flags = (1 << QUEUE_FLAG_CLUSTER | ++ 1 << QUEUE_FLAG_STACKABLE); + q->queue_lock = lock; + + blk_queue_segment_boundary(q, 0xffffffff); +@@ -1586,6 +1587,87 @@ void blkdev_dequeue_request(struct reque + EXPORT_SYMBOL(blkdev_dequeue_request); + + /** ++ * blk_rq_check_limits - Helper function to check a request for the queue limit ++ * @q: the queue ++ * @rq: the request being checked ++ * ++ * Description: ++ * @rq may have been made based on weaker limitations of upper-level queues ++ * in request stacking drivers, and it may violate the limitation of @q. ++ * Since the block layer and the underlying device driver trust @rq ++ * after it is inserted to @q, it should be checked against @q before ++ * the insertion using this generic function. ++ * ++ * This function should also be useful for request stacking drivers ++ * in some cases below, so export this fuction. ++ * Request stacking drivers like request-based dm may change the queue ++ * limits while requests are in the queue (e.g. dm's table swapping). ++ * Such request stacking drivers should check those requests agaist ++ * the new queue limits again when they dispatch those requests, ++ * although such checkings are also done against the old queue limits ++ * when submitting requests. ++ */ ++int blk_rq_check_limits(struct request_queue *q, struct request *rq) ++{ ++ if (rq->nr_sectors > q->max_sectors || ++ rq->data_len > q->max_hw_sectors << 9) { ++ printk(KERN_ERR "%s: over max size limit.\n", __func__); ++ return -EIO; ++ } ++ ++ /* ++ * queue's settings related to segment counting like q->bounce_pfn ++ * may differ from that of other stacking queues. ++ * Recalculate it to check the request correctly on this queue's ++ * limitation. ++ */ ++ blk_recalc_rq_segments(rq); ++ if (rq->nr_phys_segments > q->max_phys_segments || ++ rq->nr_phys_segments > q->max_hw_segments) { ++ printk(KERN_ERR "%s: over max segments limit.\n", __func__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(blk_rq_check_limits); ++ ++/** ++ * blk_insert_cloned_request - Helper for stacking drivers to submit a request ++ * @q: the queue to submit the request ++ * @rq: the request being queued ++ */ ++int blk_insert_cloned_request(struct request_queue *q, struct request *rq) ++{ ++ unsigned long flags; ++ ++ if (blk_rq_check_limits(q, rq)) ++ return -EIO; ++ ++#ifdef CONFIG_FAIL_MAKE_REQUEST ++ if (rq->rq_disk && rq->rq_disk->part0.make_it_fail && ++ should_fail(&fail_make_request, blk_rq_bytes(rq))) ++ return -EIO; ++#endif ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ ++ /* ++ * Submitting request must be dequeued before calling this function ++ * because it will be linked to another request_queue ++ */ ++ BUG_ON(blk_queued_rq(rq)); ++ ++ drive_stat_acct(rq, 1); ++ __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 0); ++ ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(blk_insert_cloned_request); ++ ++/** + * __end_that_request_first - end I/O on a request + * @req: the request being processed + * @error: %0 for success, < %0 for error +@@ -1857,6 +1939,22 @@ void end_request(struct request *req, in + } + EXPORT_SYMBOL(end_request); + ++static int end_that_request_data(struct request *rq, int error, ++ unsigned int nr_bytes, unsigned int bidi_bytes) ++{ ++ if (rq->bio) { ++ if (__end_that_request_first(rq, error, nr_bytes)) ++ return 1; ++ ++ /* Bidi request must be completed as a whole */ ++ if (blk_bidi_rq(rq) && ++ __end_that_request_first(rq->next_rq, error, bidi_bytes)) ++ return 1; ++ } ++ ++ return 0; ++} ++ + /** + * blk_end_io - Generic end_io function to complete a request. + * @rq: the request being processed +@@ -1883,15 +1981,8 @@ static int blk_end_io(struct request *rq + struct request_queue *q = rq->q; + unsigned long flags = 0UL; + +- if (rq->bio) { +- if (__end_that_request_first(rq, error, nr_bytes)) +- return 1; +- +- /* Bidi request must be completed as a whole */ +- if (blk_bidi_rq(rq) && +- __end_that_request_first(rq->next_rq, error, bidi_bytes)) +- return 1; +- } ++ if (end_that_request_data(rq, error, nr_bytes, bidi_bytes)) ++ return 1; + + /* Special feature for tricky drivers */ + if (drv_callback && drv_callback(rq)) +@@ -1974,6 +2065,36 @@ int blk_end_bidi_request(struct request + EXPORT_SYMBOL_GPL(blk_end_bidi_request); + + /** ++ * blk_update_request - Special helper function for request stacking drivers ++ * @rq: the request being processed ++ * @error: %0 for success, < %0 for error ++ * @nr_bytes: number of bytes to complete @rq ++ * ++ * Description: ++ * Ends I/O on a number of bytes attached to @rq, but doesn't complete ++ * the request structure even if @rq doesn't have leftover. ++ * If @rq has leftover, sets it up for the next range of segments. ++ * ++ * This special helper function is only for request stacking drivers ++ * (e.g. request-based dm) so that they can handle partial completion. ++ * Actual device drivers should use blk_end_request instead. ++ */ ++void blk_update_request(struct request *rq, int error, unsigned int nr_bytes) ++{ ++ if (!end_that_request_data(rq, error, nr_bytes, 0)) { ++ /* ++ * These members are not updated in end_that_request_data() ++ * when all bios are completed. ++ * Update them so that the request stacking driver can find ++ * how many bytes remain in the request later. ++ */ ++ rq->nr_sectors = rq->hard_nr_sectors = 0; ++ rq->current_nr_sectors = rq->hard_cur_sectors = 0; ++ } ++} ++EXPORT_SYMBOL_GPL(blk_update_request); ++ ++/** + * blk_end_request_callback - Special helper function for tricky drivers + * @rq: the request being processed + * @error: %0 for success, < %0 for error +@@ -2028,6 +2149,34 @@ void blk_rq_bio_prep(struct request_queu + rq->rq_disk = bio->bi_bdev->bd_disk; + } + ++/** ++ * blk_lld_busy - Check if underlying low-level drivers of a device are busy ++ * @q : the queue of the device being checked ++ * ++ * Description: ++ * Check if underlying low-level drivers of a device are busy. ++ * If the drivers want to export their busy state, they must set own ++ * exporting function using blk_queue_lld_busy() first. ++ * ++ * Basically, this function is used only by request stacking drivers ++ * to stop dispatching requests to underlying devices when underlying ++ * devices are busy. This behavior helps more I/O merging on the queue ++ * of the request stacking driver and prevents I/O throughput regression ++ * on burst I/O load. ++ * ++ * Return: ++ * 0 - Not busy (The request stacking driver should dispatch request) ++ * 1 - Busy (The request stacking driver should stop dispatching request) ++ */ ++int blk_lld_busy(struct request_queue *q) ++{ ++ if (q->lld_busy_fn) ++ return q->lld_busy_fn(q); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(blk_lld_busy); ++ + int kblockd_schedule_work(struct request_queue *q, struct work_struct *work) + { + return queue_work(kblockd_workqueue, work); +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -89,6 +89,12 @@ void blk_queue_rq_timed_out(struct reque + } + EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out); + ++void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn) ++{ ++ q->lld_busy_fn = fn; ++} ++EXPORT_SYMBOL_GPL(blk_queue_lld_busy); ++ + /** + * blk_queue_make_request - define an alternate make_request function for a device + * @q: the request queue for the device to be affected +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1465,6 +1465,37 @@ static inline int scsi_host_queue_ready( + } + + /* ++ * Busy state exporting function for request stacking drivers. ++ * ++ * For efficiency, no lock is taken to check the busy state of ++ * shost/starget/sdev, since the returned value is not guaranteed and ++ * may be changed after request stacking drivers call the function, ++ * regardless of taking lock or not. ++ * ++ * When scsi can't dispatch I/Os anymore and needs to kill I/Os ++ * (e.g. !sdev), scsi needs to return 'not busy'. ++ * Otherwise, request stacking drivers may hold requests forever. ++ */ ++static int scsi_lld_busy(struct request_queue *q) ++{ ++ struct scsi_device *sdev = q->queuedata; ++ struct Scsi_Host *shost; ++ struct scsi_target *starget; ++ ++ if (!sdev) ++ return 0; ++ ++ shost = sdev->host; ++ starget = scsi_target(sdev); ++ ++ if (scsi_host_in_recovery(shost) || scsi_host_is_busy(shost) || ++ scsi_target_is_busy(starget) || scsi_device_is_busy(sdev)) ++ return 1; ++ ++ return 0; ++} ++ ++/* + * Kill a request for a dead device + */ + static void scsi_kill_request(struct request *req, struct request_queue *q) +@@ -1778,6 +1809,7 @@ struct request_queue *scsi_alloc_queue(s + blk_queue_prep_rq(q, scsi_prep_fn); + blk_queue_softirq_done(q, scsi_softirq_done); + blk_queue_rq_timed_out(q, scsi_times_out); ++ blk_queue_lld_busy(q, scsi_lld_busy); + return q; + } + +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -272,6 +272,7 @@ typedef int (merge_bvec_fn) (struct requ + typedef void (prepare_flush_fn) (struct request_queue *, struct request *); + typedef void (softirq_done_fn)(struct request *); + typedef int (dma_drain_needed_fn)(struct request *); ++typedef int (lld_busy_fn) (struct request_queue *q); + + enum blk_eh_timer_return { + BLK_EH_NOT_HANDLED, +@@ -328,6 +329,7 @@ struct request_queue + softirq_done_fn *softirq_done_fn; + rq_timed_out_fn *rq_timed_out_fn; + dma_drain_needed_fn *dma_drain_needed; ++ lld_busy_fn *lld_busy_fn; + + /* + * Dispatch queue sorting +@@ -443,6 +445,7 @@ struct request_queue + #define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */ + #define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */ + #define QUEUE_FLAG_SAME_COMP 11 /* force complete on same CPU */ ++#define QUEUE_FLAG_STACKABLE 13 /* supports request stacking */ + + static inline int queue_is_locked(struct request_queue *q) + { +@@ -549,6 +552,8 @@ enum { + #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) + #define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags) + #define blk_queue_flushing(q) ((q)->ordseq) ++#define blk_queue_stackable(q) \ ++ test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags) + + #define blk_fs_request(rq) ((rq)->cmd_type == REQ_TYPE_FS) + #define blk_pc_request(rq) ((rq)->cmd_type == REQ_TYPE_BLOCK_PC) +@@ -695,6 +700,10 @@ extern void __blk_put_request(struct req + extern struct request *blk_get_request(struct request_queue *, int, gfp_t); + extern void blk_insert_request(struct request_queue *, struct request *, int, void *); + extern void blk_requeue_request(struct request_queue *, struct request *); ++extern int blk_rq_check_limits(struct request_queue *q, struct request *rq); ++extern int blk_lld_busy(struct request_queue *q); ++extern int blk_insert_cloned_request(struct request_queue *q, ++ struct request *rq); + extern void blk_plug_device(struct request_queue *); + extern void blk_plug_device_unlocked(struct request_queue *); + extern int blk_remove_plug(struct request_queue *); +@@ -792,6 +801,8 @@ extern void blk_complete_request(struct + extern void __blk_complete_request(struct request *); + extern void blk_abort_request(struct request *); + extern void blk_abort_queue(struct request_queue *); ++extern void blk_update_request(struct request *rq, int error, ++ unsigned int nr_bytes); + + /* + * blk_end_request() takes bytes instead of sectors as a complete size. +@@ -821,6 +832,7 @@ extern void blk_queue_update_dma_pad(str + extern int blk_queue_dma_drain(struct request_queue *q, + dma_drain_needed_fn *dma_drain_needed, + void *buf, unsigned int size); ++extern void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn); + extern void blk_queue_segment_boundary(struct request_queue *, unsigned long); + extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn); + extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-abort-queue b/src/patches/suse-2.6.27.31/patches.drivers/block-abort-queue new file mode 100644 index 000000000..4da6fb497 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-abort-queue @@ -0,0 +1,108 @@ +Subject: block: Add interface to abort queued requests +From: Mike Anderson +Date: Thu Oct 9 08:56:13 2008 +0200: +Git: 11914a53d2ec2974a565311af327b8983d8c820d +References: FATE#304151,bnc#417544 + +Adapted for SLES11, based on the original commit. + +Signed-off-by: Mike Anderson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-timeout.c | 22 ++++++++++++++++++++++ + block/elevator.c | 13 +++++++++++++ + include/linux/blkdev.h | 1 + + include/linux/blktrace_api.h | 2 ++ + include/linux/elevator.h | 1 + + 5 files changed, 39 insertions(+) + +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -153,3 +153,25 @@ void blk_add_timer(struct request *req) + time_before(expiry, q->timeout.expires)) + mod_timer(&q->timeout, expiry); + } ++ ++/** ++ * blk_abort_queue -- Abort all request on given queue ++ * @queue: pointer to queue ++ * ++ */ ++void blk_abort_queue(struct request_queue *q) ++{ ++ unsigned long flags; ++ struct request *rq, *tmp; ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ ++ elv_abort_queue(q); ++ ++ list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) ++ blk_abort_request(rq); ++ ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ ++} ++EXPORT_SYMBOL_GPL(blk_abort_queue); +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -922,6 +922,19 @@ int elv_may_queue(struct request_queue * + return ELV_MQUEUE_MAY; + } + ++void elv_abort_queue(struct request_queue *q) ++{ ++ struct request *rq; ++ ++ while (!list_empty(&q->queue_head)) { ++ rq = list_entry_rq(q->queue_head.next); ++ rq->cmd_flags |= REQ_QUIET; ++ blk_add_trace_rq(q, rq, BLK_TA_ABORT); ++ end_queued_request(rq, 0); ++ } ++} ++EXPORT_SYMBOL(elv_abort_queue); ++ + void elv_completed_request(struct request_queue *q, struct request *rq) + { + elevator_t *e = q->elevator; +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -780,6 +780,7 @@ extern int blk_end_request_callback(stru + extern void blk_complete_request(struct request *); + extern void __blk_complete_request(struct request *); + extern void blk_abort_request(struct request *); ++extern void blk_abort_queue(struct request_queue *); + + /* + * blk_end_request() takes bytes instead of sectors as a complete size. +--- a/include/linux/blktrace_api.h ++++ b/include/linux/blktrace_api.h +@@ -51,6 +51,7 @@ enum blktrace_act { + __BLK_TA_SPLIT, /* bio was split */ + __BLK_TA_BOUNCE, /* bio was bounced */ + __BLK_TA_REMAP, /* bio was remapped */ ++ __BLK_TA_ABORT, /* request aborted */ + __BLK_TA_DRV_DATA, /* driver-specific binary data */ + }; + +@@ -82,6 +83,7 @@ enum blktrace_notify { + #define BLK_TA_SPLIT (__BLK_TA_SPLIT) + #define BLK_TA_BOUNCE (__BLK_TA_BOUNCE) + #define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE)) ++#define BLK_TA_ABORT (__BLK_TA_ABORT | BLK_TC_ACT(BLK_TC_QUEUE)) + #define BLK_TA_DRV_DATA (__BLK_TA_DRV_DATA | BLK_TC_ACT(BLK_TC_DRV_DATA)) + + #define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY)) +--- a/include/linux/elevator.h ++++ b/include/linux/elevator.h +@@ -112,6 +112,7 @@ extern struct request *elv_latter_reques + extern int elv_register_queue(struct request_queue *q); + extern void elv_unregister_queue(struct request_queue *q); + extern int elv_may_queue(struct request_queue *, int); ++extern void elv_abort_queue(struct request_queue *); + extern void elv_completed_request(struct request_queue *, struct request *); + extern int elv_set_request(struct request_queue *, struct request *, gfp_t); + extern void elv_put_request(struct request_queue *, struct request *); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-abort-request-rq-complete-marking b/src/patches/suse-2.6.27.31/patches.drivers/block-abort-request-rq-complete-marking new file mode 100644 index 000000000..83b21cf9d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-abort-request-rq-complete-marking @@ -0,0 +1,30 @@ +From: Jens Axboe +Date: Tue Sep 16 09:54:11 2008 -0700 +Subject: use rq complete marking in blk_abort_request() +Git: 7ba1fbaa4a478f72fbaf5a56af9c82a77966b4c7 +References: bnc#434105 + +We cannot abort a request if we raced with the timeout handler already, +or with the IO completion. So make blk_abort_request() mark the request +as complete, and only continue if we succeeded. + +Found and suggested by Mike Anderson + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-timeout.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -99,6 +99,8 @@ void blk_rq_timed_out_timer(unsigned lon + */ + void blk_abort_request(struct request *req) + { ++ if (blk_mark_rq_complete(req)) ++ return; + blk_delete_timer(req); + blk_rq_timed_out(req); + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-add-timeout-on-dequeue b/src/patches/suse-2.6.27.31/patches.drivers/block-add-timeout-on-dequeue new file mode 100644 index 000000000..6e5c8bd17 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-add-timeout-on-dequeue @@ -0,0 +1,68 @@ +From: Tejun Heo +Subject: block: add timer on blkdev_dequeue_request() not elv_next_request() +References: bnc#440076 + +Block queue supports two usage models - one where block driver peeks +at the front of queue using elv_next_request(), processes it and +finishes it and the other where block driver peeks at the front of +queue, dequeue the request using blkdev_dequeue_request() and finishes +it. The latter is more flexible as it allows the driver to process +multiple commands concurrently. + +These two inconsistent usage models affect the block layer +implementation confusing. For some, elv_next_request() is considered +the issue point while others consider blkdev_dequeue_request() the +issue point. + +Till now the inconsistency mostly affect only accounting, so it didn't +really break anything seriously; however, with block layer timeout, +this inconsistency hits hard. Block layer considers +elv_next_request() the issue point and adds timer but SCSI layer +thinks it was just peeking and when the request can't process the +command right away, it's just left there without further processing. +This makes the request dangling on the timer list and, when the timer +goes off, the request which the SCSI layer and below think is still on +the block queue ends up in the EH queue, causing various problems - EH +hang (failed count goes over busy count and EH never wakes up), +WARN_ON() and oopses as low level driver trying to handle the unknown +command, etc. depending on the timing. + +As SCSI midlayer is the only user of block layer timer at the moment, +moving blk_add_timer() to elv_dequeue_request() fixes the problem; +however, this two usage models definitely need to be cleaned up in the +future. + +Signed-off-by: Tejun Heo +Signed-off-by: Tejun Heo +--- + block/elevator.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -781,12 +781,6 @@ struct request *elv_next_request(struct + */ + rq->cmd_flags |= REQ_STARTED; + blk_add_trace_rq(q, rq, BLK_TA_ISSUE); +- +- /* +- * We are now handing the request to the hardware, +- * add the timeout handler +- */ +- blk_add_timer(rq); + } + + if (!q->boundary_rq || q->boundary_rq == rq) { +@@ -858,6 +852,12 @@ void elv_dequeue_request(struct request_ + */ + if (blk_account_rq(rq)) + q->in_flight++; ++ ++ /* ++ * We are now handing the request to the hardware, add the ++ * timeout handler. ++ */ ++ blk_add_timer(rq); + } + EXPORT_SYMBOL(elv_dequeue_request); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-call-sync-on-cleanup b/src/patches/suse-2.6.27.31/patches.drivers/block-call-sync-on-cleanup new file mode 100644 index 000000000..634ec23dd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-call-sync-on-cleanup @@ -0,0 +1,34 @@ +Subject: block: blk_cleanup_queue() should call blk_sync_queue() +From: Jens Axboe +Date: Thu Oct 9 08:56:18 2008 +0200: +Git: e3335de94067dbebe22e3962632ead34e832cb60 + +When a driver calls blk_cleanup_queue(), the device should be fully idle. +However, the block layer may have pending plugging timers and the IO +schedulers may have pending work in the work queues. So quisce the device +by waiting for the timer and flushing the work queues. + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -435,6 +435,14 @@ void blk_put_queue(struct request_queue + + void blk_cleanup_queue(struct request_queue *q) + { ++ /* ++ * We know we have process context here, so we can be a little ++ * cautious and ensure that pending block actions on this device ++ * are done before moving on. Going into this function, we should ++ * not have processes doing IO to this device. ++ */ ++ blk_sync_queue(q); ++ + mutex_lock(&q->sysfs_lock); + queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q); + mutex_unlock(&q->sysfs_lock); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-del-timer-after-dequeue b/src/patches/suse-2.6.27.31/patches.drivers/block-del-timer-after-dequeue new file mode 100644 index 000000000..cc4b0afab --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-del-timer-after-dequeue @@ -0,0 +1,35 @@ +From: Mike Anderson +Date: Thu, 30 Oct 2008 02:16:20 -0700 +Subject: blk: move blk_delete_timer call in end_that_request_last +References: bnc#440076 bnc#440173 + +Move the calling blk_delete_timer to later in end_that_request_last to +address an issue where blkdev_dequeue_request may have add a timer for the +request. + +Signed-off-by: Mike Anderson +Signed-off-by: Tejun Heo +--- + block/blk-core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -1665,8 +1665,6 @@ static void end_that_request_last(struct + { + struct gendisk *disk = req->rq_disk; + +- blk_delete_timer(req); +- + if (blk_rq_tagged(req)) + blk_queue_end_tag(req->q, req); + +@@ -1676,6 +1674,8 @@ static void end_that_request_last(struct + if (unlikely(laptop_mode) && blk_fs_request(req)) + laptop_io_completion(); + ++ blk_delete_timer(req); ++ + /* + * Account IO completion. bar_rq isn't accounted as a normal + * IO on queueing nor completion. Accounting the containing diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-internal-dequeue-shouldnt-start-timer b/src/patches/suse-2.6.27.31/patches.drivers/block-internal-dequeue-shouldnt-start-timer new file mode 100644 index 000000000..a8eb023d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-internal-dequeue-shouldnt-start-timer @@ -0,0 +1,132 @@ +From: Tejun Heo +Subject: block: internal dequeue shouldn't start timer +References: bnc#449880 + +blkdev_dequeue_request() and elv_dequeue_request() are equivalent and +both start the timeout timer. Barrier code dequeues the original +barrier request but doesn't passes the request itself to lower level +driver, only broken down proxy requests; however, as the original +barrier code goes through the same dequeue path and timeout timer is +started on it. If barrier sequence takes long enough, this timer +expires but the low level driver has no idea about this request and +oops follows. + +Timeout timer shouldn't have been started on the original barrier +request as it never goes through actual IO. This patch unexports +elv_dequeue_request(), which has no external user anyway, and makes it +operate on elevator proper w/o adding the timer and make +blkdev_dequeue_request() call elv_dequeue_request() and add timer. +Internal users which don't pass the request to driver - barrier code +and end_that_request_last() - are converted to use +elv_dequeue_request(). + +Signed-off-by: Tejun Heo +Cc: Mike Anderson +Signed-off-by: Tejun Heo +--- + block/blk-barrier.c | 4 ++-- + block/blk-core.c | 24 +++++++++++++++++++++++- + block/elevator.c | 7 ------- + include/linux/blkdev.h | 7 ++----- + 4 files changed, 27 insertions(+), 15 deletions(-) + +--- a/block/blk-barrier.c ++++ b/block/blk-barrier.c +@@ -161,7 +161,7 @@ static inline struct request *start_orde + /* + * Prep proxy barrier request. + */ +- blkdev_dequeue_request(rq); ++ elv_dequeue_request(q, rq); + q->orig_bar_rq = rq; + rq = &q->bar_rq; + blk_rq_init(q, rq); +@@ -219,7 +219,7 @@ int blk_do_ordered(struct request_queue + * This can happen when the queue switches to + * ORDERED_NONE while this request is on it. + */ +- blkdev_dequeue_request(rq); ++ elv_dequeue_request(q, rq); + if (__blk_end_request(rq, -EOPNOTSUPP, + blk_rq_bytes(rq))) + BUG(); +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -1536,6 +1536,28 @@ void submit_bio(int rw, struct bio *bio) + EXPORT_SYMBOL(submit_bio); + + /** ++ * blkdev_dequeue_request - dequeue request and start timeout timer ++ * @req: request to dequeue ++ * ++ * Dequeue @req and start timeout timer on it. This hands off the ++ * request to the driver. ++ * ++ * Block internal functions which don't want to start timer should ++ * call elv_dequeue_request(). ++ */ ++void blkdev_dequeue_request(struct request *req) ++{ ++ elv_dequeue_request(req->q, req); ++ ++ /* ++ * We are now handing the request to the hardware, add the ++ * timeout handler. ++ */ ++ blk_add_timer(req); ++} ++EXPORT_SYMBOL(blkdev_dequeue_request); ++ ++/** + * __end_that_request_first - end I/O on a request + * @req: the request being processed + * @error: %0 for success, < %0 for error +@@ -1670,7 +1692,7 @@ static void end_that_request_last(struct + blk_queue_end_tag(req->q, req); + + if (blk_queued_rq(req)) +- blkdev_dequeue_request(req); ++ elv_dequeue_request(req->q, req); + + if (unlikely(laptop_mode) && blk_fs_request(req)) + laptop_io_completion(); +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -852,14 +852,7 @@ void elv_dequeue_request(struct request_ + */ + if (blk_account_rq(rq)) + q->in_flight++; +- +- /* +- * We are now handing the request to the hardware, add the +- * timeout handler. +- */ +- blk_add_timer(rq); + } +-EXPORT_SYMBOL(elv_dequeue_request); + + int elv_queue_empty(struct request_queue *q) + { +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -756,6 +756,8 @@ static inline void blk_run_address_space + blk_run_backing_dev(mapping->backing_dev_info, NULL); + } + ++extern void blkdev_dequeue_request(struct request *req); ++ + /* + * blk_end_request() and friends. + * __blk_end_request() and end_request() must be called with +@@ -790,11 +792,6 @@ extern void blk_abort_queue(struct reque + extern unsigned int blk_rq_bytes(struct request *rq); + extern unsigned int blk_rq_cur_bytes(struct request *rq); + +-static inline void blkdev_dequeue_request(struct request *req) +-{ +- elv_dequeue_request(req->q, req); +-} +- + /* + * Access functions for manipulating queue properties + */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/block-timeout-handling b/src/patches/suse-2.6.27.31/patches.drivers/block-timeout-handling new file mode 100644 index 000000000..619544ea0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/block-timeout-handling @@ -0,0 +1,1604 @@ +Subject: block: unify request timeout handling +From: Jens Axboe +Date: Thu Oct 9 08:56:13 2008 +0200: +Git: 242f9dcb8ba6f68fcd217a119a7648a4f69290e9 +References: FATE#304151,bnc#417544 + +Right now SCSI and others do their own command timeout handling. +Move those bits to the block layer. + +Instead of having a timer per command, we try to be a bit more clever +and simply have one per-queue. This avoids the overhead of having to +tear down and setup a timer for each command, so it will result in a lot +less timer fiddling. + +Signed-off-by: Mike Anderson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + block/Makefile | 4 + block/blk-core.c | 7 + + block/blk-settings.c | 12 ++ + block/blk-softirq.c | 30 ++++-- + block/blk-timeout.c | 155 +++++++++++++++++++++++++++++++++++ + block/blk.h | 24 +++++ + block/elevator.c | 8 + + drivers/ata/libata-eh.c | 13 +- + drivers/ata/libata.h | 2 + drivers/scsi/aacraid/aachba.c | 2 + drivers/scsi/gdth.c | 60 ++++++++----- + drivers/scsi/gdth.h | 2 + drivers/scsi/gdth_proc.c | 66 -------------- + drivers/scsi/gdth_proc.h | 3 + drivers/scsi/ibmvscsi/ibmvscsi.c | 2 + drivers/scsi/ide-scsi.c | 2 + drivers/scsi/ipr.c | 3 + drivers/scsi/ips.c | 2 + drivers/scsi/libiscsi.c | 17 ++- + drivers/scsi/libsas/sas_ata.c | 2 + drivers/scsi/libsas/sas_internal.h | 2 + drivers/scsi/libsas/sas_scsi_host.c | 30 +++--- + drivers/scsi/megaraid/megaraid_sas.c | 6 - + drivers/scsi/ncr53c8xx.c | 4 + drivers/scsi/qla1280.c | 4 + drivers/scsi/qla4xxx/ql4_os.c | 4 + drivers/scsi/scsi.c | 92 +++----------------- + drivers/scsi/scsi_error.c | 90 ++------------------ + drivers/scsi/scsi_lib.c | 17 ++- + drivers/scsi/scsi_priv.h | 7 - + drivers/scsi/scsi_sysfs.c | 7 + + drivers/scsi/scsi_transport_fc.c | 6 - + drivers/scsi/sd.c | 9 -- + drivers/scsi/sr.c | 5 - + drivers/scsi/sym53c8xx_2/sym_glue.c | 4 + include/linux/blkdev.h | 20 ++++ + include/scsi/scsi_cmnd.h | 3 + include/scsi/scsi_host.h | 9 -- + include/scsi/scsi_transport.h | 3 + 39 files changed, 399 insertions(+), 339 deletions(-) + create mode 100644 block/blk-timeout.c + +--- a/block/Makefile ++++ b/block/Makefile +@@ -4,8 +4,8 @@ + + obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ + blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ +- blk-exec.o blk-merge.o blk-softirq.o ioctl.o genhd.o \ +- scsi_ioctl.o cmd-filter.o ++ blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \ ++ ioctl.o genhd.o scsi_ioctl.o cmd-filter.o + + obj-$(CONFIG_BLK_DEV_BSG) += bsg.o + obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -109,6 +109,7 @@ void blk_rq_init(struct request_queue *q + memset(rq, 0, sizeof(*rq)); + + INIT_LIST_HEAD(&rq->queuelist); ++ INIT_LIST_HEAD(&rq->timeout_list); + rq->cpu = -1; + rq->q = q; + rq->sector = rq->hard_sector = (sector_t) -1; +@@ -489,6 +490,8 @@ struct request_queue *blk_alloc_queue_no + } + + init_timer(&q->unplug_timer); ++ setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); ++ INIT_LIST_HEAD(&q->timeout_list); + + kobject_init(&q->kobj, &blk_queue_ktype); + +@@ -896,6 +899,8 @@ EXPORT_SYMBOL(blk_start_queueing); + */ + void blk_requeue_request(struct request_queue *q, struct request *rq) + { ++ blk_delete_timer(rq); ++ blk_clear_rq_complete(rq); + blk_add_trace_rq(q, rq, BLK_TA_REQUEUE); + + if (blk_rq_tagged(rq)) +@@ -1652,6 +1657,8 @@ static void end_that_request_last(struct + { + struct gendisk *disk = req->rq_disk; + ++ blk_delete_timer(req); ++ + if (blk_rq_tagged(req)) + blk_queue_end_tag(req->q, req); + +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -77,6 +77,18 @@ void blk_queue_softirq_done(struct reque + } + EXPORT_SYMBOL(blk_queue_softirq_done); + ++void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout) ++{ ++ q->rq_timeout = timeout; ++} ++EXPORT_SYMBOL_GPL(blk_queue_rq_timeout); ++ ++void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn) ++{ ++ q->rq_timed_out_fn = fn; ++} ++EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out); ++ + /** + * blk_queue_make_request - define an alternate make_request function for a device + * @q: the request queue for the device to be affected +--- a/block/blk-softirq.c ++++ b/block/blk-softirq.c +@@ -101,18 +101,7 @@ static struct notifier_block __cpuinitda + .notifier_call = blk_cpu_notify, + }; + +-/** +- * blk_complete_request - end I/O on a request +- * @req: the request being processed +- * +- * Description: +- * Ends all I/O on a request. It does not handle partial completions, +- * unless the driver actually implements this in its completion callback +- * through requeueing. The actual completion happens out-of-order, +- * through a softirq handler. The user must have registered a completion +- * callback through blk_queue_softirq_done(). +- **/ +-void blk_complete_request(struct request *req) ++void __blk_complete_request(struct request *req) + { + struct request_queue *q = req->q; + unsigned long flags; +@@ -151,6 +140,23 @@ do_local: + + local_irq_restore(flags); + } ++ ++/** ++ * blk_complete_request - end I/O on a request ++ * @req: the request being processed ++ * ++ * Description: ++ * Ends all I/O on a request. It does not handle partial completions, ++ * unless the driver actually implements this in its completion callback ++ * through requeueing. The actual completion happens out-of-order, ++ * through a softirq handler. The user must have registered a completion ++ * callback through blk_queue_softirq_done(). ++ **/ ++void blk_complete_request(struct request *req) ++{ ++ if (!blk_mark_rq_complete(req)) ++ __blk_complete_request(req); ++} + EXPORT_SYMBOL(blk_complete_request); + + __init int blk_softirq_init(void) +--- /dev/null ++++ b/block/blk-timeout.c +@@ -0,0 +1,155 @@ ++/* ++ * Functions related to generic timeout handling of requests. ++ */ ++#include ++#include ++#include ++ ++#include "blk.h" ++ ++/* ++ * blk_delete_timer - Delete/cancel timer for a given function. ++ * @req: request that we are canceling timer for ++ * ++ */ ++void blk_delete_timer(struct request *req) ++{ ++ struct request_queue *q = req->q; ++ ++ /* ++ * Nothing to detach ++ */ ++ if (!q->rq_timed_out_fn || !req->deadline) ++ return; ++ ++ list_del_init(&req->timeout_list); ++ ++ if (list_empty(&q->timeout_list)) ++ del_timer(&q->timeout); ++} ++ ++static void blk_rq_timed_out(struct request *req) ++{ ++ struct request_queue *q = req->q; ++ enum blk_eh_timer_return ret; ++ ++ ret = q->rq_timed_out_fn(req); ++ switch (ret) { ++ case BLK_EH_HANDLED: ++ __blk_complete_request(req); ++ break; ++ case BLK_EH_RESET_TIMER: ++ blk_clear_rq_complete(req); ++ blk_add_timer(req); ++ break; ++ case BLK_EH_NOT_HANDLED: ++ /* ++ * LLD handles this for now but in the future ++ * we can send a request msg to abort the command ++ * and we can move more of the generic scsi eh code to ++ * the blk layer. ++ */ ++ break; ++ default: ++ printk(KERN_ERR "block: bad eh return: %d\n", ret); ++ break; ++ } ++} ++ ++void blk_rq_timed_out_timer(unsigned long data) ++{ ++ struct request_queue *q = (struct request_queue *) data; ++ unsigned long flags, uninitialized_var(next), next_set = 0; ++ struct request *rq, *tmp; ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ ++ list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) { ++ if (time_after_eq(jiffies, rq->deadline)) { ++ list_del_init(&rq->timeout_list); ++ ++ /* ++ * Check if we raced with end io completion ++ */ ++ if (blk_mark_rq_complete(rq)) ++ continue; ++ blk_rq_timed_out(rq); ++ } ++ if (!next_set) { ++ next = rq->deadline; ++ next_set = 1; ++ } else if (time_after(next, rq->deadline)) ++ next = rq->deadline; ++ } ++ ++ if (next_set && !list_empty(&q->timeout_list)) ++ mod_timer(&q->timeout, round_jiffies(next)); ++ ++ spin_unlock_irqrestore(q->queue_lock, flags); ++} ++ ++/** ++ * blk_abort_request -- Request request recovery for the specified command ++ * @req: pointer to the request of interest ++ * ++ * This function requests that the block layer start recovery for the ++ * request by deleting the timer and calling the q's timeout function. ++ * LLDDs who implement their own error recovery MAY ignore the timeout ++ * event if they generated blk_abort_req. Must hold queue lock. ++ */ ++void blk_abort_request(struct request *req) ++{ ++ blk_delete_timer(req); ++ blk_rq_timed_out(req); ++} ++EXPORT_SYMBOL_GPL(blk_abort_request); ++ ++/** ++ * blk_add_timer - Start timeout timer for a single request ++ * @req: request that is about to start running. ++ * ++ * Notes: ++ * Each request has its own timer, and as it is added to the queue, we ++ * set up the timer. When the request completes, we cancel the timer. ++ */ ++void blk_add_timer(struct request *req) ++{ ++ struct request_queue *q = req->q; ++ unsigned long expiry; ++ ++ if (!q->rq_timed_out_fn) ++ return; ++ ++ BUG_ON(!list_empty(&req->timeout_list)); ++ BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags)); ++ ++ if (req->timeout) ++ req->deadline = jiffies + req->timeout; ++ else { ++ req->deadline = jiffies + q->rq_timeout; ++ /* ++ * Some LLDs, like scsi, peek at the timeout to prevent ++ * a command from being retried forever. ++ */ ++ req->timeout = q->rq_timeout; ++ } ++ list_add_tail(&req->timeout_list, &q->timeout_list); ++ ++ /* ++ * If the timer isn't already pending or this timeout is earlier ++ * than an existing one, modify the timer. Round to next nearest ++ * second. ++ */ ++ expiry = round_jiffies(req->deadline); ++ ++ /* ++ * We use ->deadline == 0 to detect whether a timer was added or ++ * not, so just increase to next jiffy for that specific case ++ */ ++ if (unlikely(!req->deadline)) ++ req->deadline = 1; ++ ++ if (!timer_pending(&q->timeout) || ++ time_before(expiry, q->timeout.expires)) ++ mod_timer(&q->timeout, expiry); ++} +--- a/block/blk.h ++++ b/block/blk.h +@@ -17,6 +17,30 @@ void __blk_queue_free_tags(struct reques + + void blk_unplug_work(struct work_struct *work); + void blk_unplug_timeout(unsigned long data); ++void blk_rq_timed_out_timer(unsigned long data); ++void blk_delete_timer(struct request *); ++void blk_add_timer(struct request *); ++ ++/* ++ * Internal atomic flags for request handling ++ */ ++enum rq_atomic_flags { ++ REQ_ATOM_COMPLETE = 0, ++}; ++ ++/* ++ * EH timer and IO completion will both attempt to 'grab' the request, make ++ * sure that only one of them suceeds ++ */ ++static inline int blk_mark_rq_complete(struct request *rq) ++{ ++ return test_and_set_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); ++} ++ ++static inline void blk_clear_rq_complete(struct request *rq) ++{ ++ clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); ++} + + struct io_context *current_io_context(gfp_t gfp_flags, int node); + +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -36,6 +36,8 @@ + #include + #include + ++#include "blk.h" ++ + static DEFINE_SPINLOCK(elv_list_lock); + static LIST_HEAD(elv_list); + +@@ -779,6 +781,12 @@ struct request *elv_next_request(struct + */ + rq->cmd_flags |= REQ_STARTED; + blk_add_trace_rq(q, rq, BLK_TA_ISSUE); ++ ++ /* ++ * We are now handing the request to the hardware, ++ * add the timeout handler ++ */ ++ blk_add_timer(rq); + } + + if (!q->boundary_rq || q->boundary_rq == rq) { +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -33,6 +33,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -457,29 +458,29 @@ static void ata_eh_clear_action(struct a + * RETURNS: + * EH_HANDLED or EH_NOT_HANDLED + */ +-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) ++enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) + { + struct Scsi_Host *host = cmd->device->host; + struct ata_port *ap = ata_shost_to_port(host); + unsigned long flags; + struct ata_queued_cmd *qc; +- enum scsi_eh_timer_return ret; ++ enum blk_eh_timer_return ret; + + DPRINTK("ENTER\n"); + + if (ap->ops->error_handler) { +- ret = EH_NOT_HANDLED; ++ ret = BLK_EH_NOT_HANDLED; + goto out; + } + +- ret = EH_HANDLED; ++ ret = BLK_EH_HANDLED; + spin_lock_irqsave(ap->lock, flags); + qc = ata_qc_from_tag(ap, ap->link.active_tag); + if (qc) { + WARN_ON(qc->scsicmd != cmd); + qc->flags |= ATA_QCFLAG_EH_SCHEDULED; + qc->err_mask |= AC_ERR_TIMEOUT; +- ret = EH_NOT_HANDLED; ++ ret = BLK_EH_NOT_HANDLED; + } + spin_unlock_irqrestore(ap->lock, flags); + +@@ -828,7 +829,7 @@ void ata_qc_schedule_eh(struct ata_queue + * Note that ATA_QCFLAG_FAILED is unconditionally set after + * this function completes. + */ +- scsi_req_abort_cmd(qc->scsicmd); ++ blk_abort_request(qc->scsicmd->request); + } + + /** +--- a/drivers/ata/libata.h ++++ b/drivers/ata/libata.h +@@ -155,7 +155,7 @@ extern int ata_bus_probe(struct ata_port + /* libata-eh.c */ + extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd); + extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd); +-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); ++extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); + extern void ata_scsi_error(struct Scsi_Host *host); + extern void ata_port_wait_eh(struct ata_port *ap); + extern void ata_eh_fastdrain_timerfn(unsigned long arg); +--- a/drivers/scsi/aacraid/aachba.c ++++ b/drivers/scsi/aacraid/aachba.c +@@ -1139,7 +1139,7 @@ static struct aac_srb * aac_scsi_common( + srbcmd->id = cpu_to_le32(scmd_id(cmd)); + srbcmd->lun = cpu_to_le32(cmd->device->lun); + srbcmd->flags = cpu_to_le32(flag); +- timeout = cmd->timeout_per_command/HZ; ++ timeout = cmd->request->timeout/HZ; + if (timeout == 0) + timeout = 1; + srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds +--- a/drivers/scsi/gdth.c ++++ b/drivers/scsi/gdth.c +@@ -464,7 +464,6 @@ int __gdth_execute(struct scsi_device *s + + /* use request field to save the ptr. to completion struct. */ + scp->request = (struct request *)&wait; +- scp->timeout_per_command = timeout*HZ; + scp->cmd_len = 12; + scp->cmnd = cmnd; + cmndinfo.priority = IOCTL_PRI; +@@ -1995,23 +1994,12 @@ static void gdth_putq(gdth_ha_str *ha, S + register Scsi_Cmnd *pscp; + register Scsi_Cmnd *nscp; + ulong flags; +- unchar b, t; + + TRACE(("gdth_putq() priority %d\n",priority)); + spin_lock_irqsave(&ha->smp_lock, flags); + +- if (!cmndinfo->internal_command) { ++ if (!cmndinfo->internal_command) + cmndinfo->priority = priority; +- b = scp->device->channel; +- t = scp->device->id; +- if (priority >= DEFAULT_PRI) { +- if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || +- (b==ha->virt_bus && thdr[t].lock)) { +- TRACE2(("gdth_putq(): locked IO ->update_timeout()\n")); +- cmndinfo->timeout = gdth_update_timeout(scp, 0); +- } +- } +- } + + if (ha->req_first==NULL) { + ha->req_first = scp; /* queue was empty */ +@@ -3899,6 +3887,39 @@ static const char *gdth_info(struct Scsi + return ((const char *)ha->binfo.type_string); + } + ++static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp) ++{ ++ gdth_ha_str *ha = shost_priv(scp->device->host); ++ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); ++ unchar b, t; ++ ulong flags; ++ enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED; ++ ++ TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__)); ++ b = scp->device->channel; ++ t = scp->device->id; ++ ++ /* ++ * We don't really honor the command timeout, but we try to ++ * honor 6 times of the actual command timeout! So reset the ++ * timer if this is less than 6th timeout on this command! ++ */ ++ if (++cmndinfo->timeout_count < 6) ++ retval = BLK_EH_RESET_TIMER; ++ ++ /* Reset the timeout if it is locked IO */ ++ spin_lock_irqsave(&ha->smp_lock, flags); ++ if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha, b)].lock) || ++ (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) { ++ TRACE2(("%s(): locked IO, reset timeout\n", __func__)); ++ retval = BLK_EH_RESET_TIMER; ++ } ++ spin_unlock_irqrestore(&ha->smp_lock, flags); ++ ++ return retval; ++} ++ ++ + static int gdth_eh_bus_reset(Scsi_Cmnd *scp) + { + gdth_ha_str *ha = shost_priv(scp->device->host); +@@ -3992,7 +4013,7 @@ static int gdth_queuecommand(struct scsi + BUG_ON(!cmndinfo); + + scp->scsi_done = done; +- gdth_update_timeout(scp, scp->timeout_per_command * 6); ++ cmndinfo->timeout_count = 0; + cmndinfo->priority = DEFAULT_PRI; + + return __gdth_queuecommand(ha, scp, cmndinfo); +@@ -4096,12 +4117,10 @@ static int ioc_lockdrv(void __user *arg) + ha->hdr[j].lock = 1; + spin_unlock_irqrestore(&ha->smp_lock, flags); + gdth_wait_completion(ha, ha->bus_cnt, j); +- gdth_stop_timeout(ha, ha->bus_cnt, j); + } else { + spin_lock_irqsave(&ha->smp_lock, flags); + ha->hdr[j].lock = 0; + spin_unlock_irqrestore(&ha->smp_lock, flags); +- gdth_start_timeout(ha, ha->bus_cnt, j); + gdth_next(ha); + } + } +@@ -4539,18 +4558,14 @@ static int gdth_ioctl(struct inode *inod + spin_lock_irqsave(&ha->smp_lock, flags); + ha->raw[i].lock = 1; + spin_unlock_irqrestore(&ha->smp_lock, flags); +- for (j = 0; j < ha->tid_cnt; ++j) { ++ for (j = 0; j < ha->tid_cnt; ++j) + gdth_wait_completion(ha, i, j); +- gdth_stop_timeout(ha, i, j); +- } + } else { + spin_lock_irqsave(&ha->smp_lock, flags); + ha->raw[i].lock = 0; + spin_unlock_irqrestore(&ha->smp_lock, flags); +- for (j = 0; j < ha->tid_cnt; ++j) { +- gdth_start_timeout(ha, i, j); ++ for (j = 0; j < ha->tid_cnt; ++j) + gdth_next(ha); +- } + } + } + break; +@@ -4644,6 +4659,7 @@ static struct scsi_host_template gdth_te + .slave_configure = gdth_slave_configure, + .bios_param = gdth_bios_param, + .proc_info = gdth_proc_info, ++ .eh_timed_out = gdth_timed_out, + .proc_name = "gdth", + .can_queue = GDTH_MAXCMDS, + .this_id = -1, +--- a/drivers/scsi/gdth.h ++++ b/drivers/scsi/gdth.h +@@ -916,7 +916,7 @@ typedef struct { + gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/ + dma_addr_t sense_paddr; /* sense dma-addr */ + unchar priority; +- int timeout; ++ int timeout_count; /* # of timeout calls */ + volatile int wait_for_completion; + ushort status; + ulong32 info; +--- a/drivers/scsi/gdth_proc.c ++++ b/drivers/scsi/gdth_proc.c +@@ -748,69 +748,3 @@ static void gdth_wait_completion(gdth_ha + } + spin_unlock_irqrestore(&ha->smp_lock, flags); + } +- +-static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id) +-{ +- ulong flags; +- Scsi_Cmnd *scp; +- unchar b, t; +- +- spin_lock_irqsave(&ha->smp_lock, flags); +- +- for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { +- struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); +- if (!cmndinfo->internal_command) { +- b = scp->device->channel; +- t = scp->device->id; +- if (t == (unchar)id && b == (unchar)busnum) { +- TRACE2(("gdth_stop_timeout(): update_timeout()\n")); +- cmndinfo->timeout = gdth_update_timeout(scp, 0); +- } +- } +- } +- spin_unlock_irqrestore(&ha->smp_lock, flags); +-} +- +-static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id) +-{ +- ulong flags; +- Scsi_Cmnd *scp; +- unchar b, t; +- +- spin_lock_irqsave(&ha->smp_lock, flags); +- +- for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { +- struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); +- if (!cmndinfo->internal_command) { +- b = scp->device->channel; +- t = scp->device->id; +- if (t == (unchar)id && b == (unchar)busnum) { +- TRACE2(("gdth_start_timeout(): update_timeout()\n")); +- gdth_update_timeout(scp, cmndinfo->timeout); +- } +- } +- } +- spin_unlock_irqrestore(&ha->smp_lock, flags); +-} +- +-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout) +-{ +- int oldto; +- +- oldto = scp->timeout_per_command; +- scp->timeout_per_command = timeout; +- +- if (timeout == 0) { +- del_timer(&scp->eh_timeout); +- scp->eh_timeout.data = (unsigned long) NULL; +- scp->eh_timeout.expires = 0; +- } else { +- if (scp->eh_timeout.data != (unsigned long) NULL) +- del_timer(&scp->eh_timeout); +- scp->eh_timeout.data = (unsigned long) scp; +- scp->eh_timeout.expires = jiffies + timeout; +- add_timer(&scp->eh_timeout); +- } +- +- return oldto; +-} +--- a/drivers/scsi/gdth_proc.h ++++ b/drivers/scsi/gdth_proc.h +@@ -20,9 +20,6 @@ static char *gdth_ioctl_alloc(gdth_ha_st + ulong64 *paddr); + static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr); + static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id); +-static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id); +-static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id); +-static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout); + + #endif + +--- a/drivers/scsi/ibmvscsi/ibmvscsi.c ++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c +@@ -756,7 +756,7 @@ static int ibmvscsi_queuecommand(struct + init_event_struct(evt_struct, + handle_cmd_rsp, + VIOSRP_SRP_FORMAT, +- cmnd->timeout_per_command/HZ); ++ cmnd->request->timeout/HZ); + + evt_struct->cmnd = cmnd; + evt_struct->cmnd_done = done; +--- a/drivers/scsi/ide-scsi.c ++++ b/drivers/scsi/ide-scsi.c +@@ -612,7 +612,7 @@ static int idescsi_queue (struct scsi_cm + pc->req_xfer = pc->buf_size = scsi_bufflen(cmd); + pc->scsi_cmd = cmd; + pc->done = done; +- pc->timeout = jiffies + cmd->timeout_per_command; ++ pc->timeout = jiffies + cmd->request->timeout; + + if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { + printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); +--- a/drivers/scsi/ipr.c ++++ b/drivers/scsi/ipr.c +@@ -3670,7 +3670,8 @@ static int ipr_slave_configure(struct sc + sdev->no_uld_attach = 1; + } + if (ipr_is_vset_device(res)) { +- sdev->timeout = IPR_VSET_RW_TIMEOUT; ++ blk_queue_rq_timeout(sdev->request_queue, ++ IPR_VSET_RW_TIMEOUT); + blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); + } + if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) +--- a/drivers/scsi/ips.c ++++ b/drivers/scsi/ips.c +@@ -3818,7 +3818,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * + scb->cmd.dcdb.segment_4G = 0; + scb->cmd.dcdb.enhanced_sg = 0; + +- TimeOut = scb->scsi_cmd->timeout_per_command; ++ TimeOut = scb->scsi_cmd->request->timeout; + + if (ha->subsys->param[4] & 0x00100000) { /* If NEW Tape DCDB is Supported */ + if (!scb->sg_len) { +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -1476,12 +1476,12 @@ static void iscsi_start_tx(struct iscsi_ + scsi_queue_work(conn->session->host, &conn->xmitwork); + } + +-static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) ++static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) + { + struct iscsi_cls_session *cls_session; + struct iscsi_session *session; + struct iscsi_conn *conn; +- enum scsi_eh_timer_return rc = EH_NOT_HANDLED; ++ enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; + + cls_session = starget_to_session(scsi_target(scmd->device)); + session = cls_session->dd_data; +@@ -1494,14 +1494,14 @@ static enum scsi_eh_timer_return iscsi_e + * We are probably in the middle of iscsi recovery so let + * that complete and handle the error. + */ +- rc = EH_RESET_TIMER; ++ rc = BLK_EH_RESET_TIMER; + goto done; + } + + conn = session->leadconn; + if (!conn) { + /* In the middle of shuting down */ +- rc = EH_RESET_TIMER; ++ rc = BLK_EH_RESET_TIMER; + goto done; + } + +@@ -1513,20 +1513,21 @@ static enum scsi_eh_timer_return iscsi_e + */ + if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + + (conn->ping_timeout * HZ), jiffies)) +- rc = EH_RESET_TIMER; ++ rc = BLK_EH_RESET_TIMER; + /* + * if we are about to check the transport then give the command + * more time + */ + if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ), + jiffies)) +- rc = EH_RESET_TIMER; ++ rc = BLK_EH_RESET_TIMER; + /* if in the middle of checking the transport then give us more time */ + if (conn->ping_task) +- rc = EH_RESET_TIMER; ++ rc = BLK_EH_RESET_TIMER; + done: + spin_unlock(&session->lock); +- debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh"); ++ debug_scsi("return %s\n", rc == BLK_EH_RESET_TIMER ? ++ "timer reset" : "nh"); + return rc; + } + +--- a/drivers/scsi/libsas/sas_ata.c ++++ b/drivers/scsi/libsas/sas_ata.c +@@ -398,7 +398,7 @@ void sas_ata_task_abort(struct sas_task + + /* Bounce SCSI-initiated commands to the SCSI EH */ + if (qc->scsicmd) { +- scsi_req_abort_cmd(qc->scsicmd); ++ blk_abort_request(qc->scsicmd->request); + scsi_schedule_eh(qc->scsicmd->device->host); + return; + } +--- a/drivers/scsi/libsas/sas_internal.h ++++ b/drivers/scsi/libsas/sas_internal.h +@@ -55,7 +55,7 @@ void sas_unregister_phys(struct sas_ha_s + int sas_register_ports(struct sas_ha_struct *sas_ha); + void sas_unregister_ports(struct sas_ha_struct *sas_ha); + +-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); ++enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); + + int sas_init_queue(struct sas_ha_struct *sas_ha); + int sas_init_events(struct sas_ha_struct *sas_ha); +--- a/drivers/scsi/libsas/sas_scsi_host.c ++++ b/drivers/scsi/libsas/sas_scsi_host.c +@@ -673,43 +673,43 @@ out: + return; + } + +-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) ++enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) + { + struct sas_task *task = TO_SAS_TASK(cmd); + unsigned long flags; + + if (!task) { +- cmd->timeout_per_command /= 2; ++ cmd->request->timeout /= 2; + SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", +- cmd, task, (cmd->timeout_per_command ? +- "EH_RESET_TIMER" : "EH_NOT_HANDLED")); +- if (!cmd->timeout_per_command) +- return EH_NOT_HANDLED; +- return EH_RESET_TIMER; ++ cmd, task, (cmd->request->timeout ? ++ "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED")); ++ if (!cmd->request->timeout) ++ return BLK_EH_NOT_HANDLED; ++ return BLK_EH_RESET_TIMER; + } + + spin_lock_irqsave(&task->task_state_lock, flags); + BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED); + if (task->task_state_flags & SAS_TASK_STATE_DONE) { + spin_unlock_irqrestore(&task->task_state_lock, flags); +- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", +- cmd, task); +- return EH_HANDLED; ++ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: " ++ "BLK_EH_HANDLED\n", cmd, task); ++ return BLK_EH_HANDLED; + } + if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { + spin_unlock_irqrestore(&task->task_state_lock, flags); + SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " +- "EH_RESET_TIMER\n", ++ "BLK_EH_RESET_TIMER\n", + cmd, task); +- return EH_RESET_TIMER; ++ return BLK_EH_RESET_TIMER; + } + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); + +- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n", ++ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n", + cmd, task); + +- return EH_NOT_HANDLED; ++ return BLK_EH_NOT_HANDLED; + } + + int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +@@ -1039,7 +1039,7 @@ void sas_task_abort(struct sas_task *tas + return; + } + +- scsi_req_abort_cmd(sc); ++ blk_abort_request(sc->request); + scsi_schedule_eh(sc->device->host); + } + +--- a/drivers/scsi/megaraid/megaraid_sas.c ++++ b/drivers/scsi/megaraid/megaraid_sas.c +@@ -1167,7 +1167,7 @@ static int megasas_generic_reset(struct + * cmd has not been completed within the timeout period. + */ + static enum +-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) ++blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) + { + struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr; + struct megasas_instance *instance; +@@ -1175,7 +1175,7 @@ scsi_eh_timer_return megasas_reset_timer + + if (time_after(jiffies, scmd->jiffies_at_alloc + + (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) { +- return EH_NOT_HANDLED; ++ return BLK_EH_NOT_HANDLED; + } + + instance = cmd->instance; +@@ -1189,7 +1189,7 @@ scsi_eh_timer_return megasas_reset_timer + + spin_unlock_irqrestore(instance->host->host_lock, flags); + } +- return EH_RESET_TIMER; ++ return BLK_EH_RESET_TIMER; + } + + /** +--- a/drivers/scsi/ncr53c8xx.c ++++ b/drivers/scsi/ncr53c8xx.c +@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb + ** + **---------------------------------------------------- + */ +- if (np->settle_time && cmd->timeout_per_command >= HZ) { +- u_long tlimit = jiffies + cmd->timeout_per_command - HZ; ++ if (np->settle_time && cmd->request->timeout >= HZ) { ++ u_long tlimit = jiffies + cmd->request->timeout - HZ; + if (time_after(np->settle_time, tlimit)) + np->settle_time = tlimit; + } +--- a/drivers/scsi/qla1280.c ++++ b/drivers/scsi/qla1280.c +@@ -2845,7 +2845,7 @@ qla1280_64bit_start_scsi(struct scsi_qla + memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); + + /* Set ISP command timeout. */ +- pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ); ++ pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ); + + /* Set device target ID and LUN */ + pkt->lun = SCSI_LUN_32(cmd); +@@ -3114,7 +3114,7 @@ qla1280_32bit_start_scsi(struct scsi_qla + memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); + + /* Set ISP command timeout. */ +- pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ); ++ pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ); + + /* Set device target ID and LUN */ + pkt->lun = SCSI_LUN_32(cmd); +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -1542,7 +1542,7 @@ static int qla4xxx_eh_device_reset(struc + DEBUG2(printk(KERN_INFO + "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," + "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, +- cmd, jiffies, cmd->timeout_per_command / HZ, ++ cmd, jiffies, cmd->request->timeout / HZ, + ha->dpc_flags, cmd->result, cmd->allowed)); + + /* FIXME: wait for hba to go online */ +@@ -1598,7 +1598,7 @@ static int qla4xxx_eh_target_reset(struc + DEBUG2(printk(KERN_INFO + "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " + "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", +- ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ, ++ ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, + ha->dpc_flags, cmd->result, cmd->allowed)); + + stat = qla4xxx_reset_target(ha, ddb_entry); +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -291,7 +291,6 @@ struct scsi_cmnd *scsi_get_command(struc + unsigned long flags; + + cmd->device = dev; +- init_timer(&cmd->eh_timeout); + INIT_LIST_HEAD(&cmd->list); + spin_lock_irqsave(&dev->list_lock, flags); + list_add_tail(&cmd->list, &dev->cmd_list); +@@ -652,14 +651,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + unsigned long timeout; + int rtn = 0; + ++ /* ++ * We will use a queued command if possible, otherwise we will ++ * emulate the queuing and calling of completion function ourselves. ++ */ ++ atomic_inc(&cmd->device->iorequest_cnt); ++ + /* check if the device is still usable */ + if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { + /* in SDEV_DEL we error all commands. DID_NO_CONNECT + * returns an immediate error upwards, and signals + * that the device is no longer present */ + cmd->result = DID_NO_CONNECT << 16; +- atomic_inc(&cmd->device->iorequest_cnt); +- __scsi_done(cmd); ++ scsi_done(cmd); + /* return 0 (because the command has been processed) */ + goto out; + } +@@ -672,6 +676,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + * future requests should not occur until the device + * transitions out of the suspend state. + */ ++ + scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); + + SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n")); +@@ -714,21 +719,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + host->resetting = 0; + } + +- /* +- * AK: unlikely race here: for some reason the timer could +- * expire before the serial number is set up below. +- */ +- scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out); +- + scsi_log_send(cmd); + + /* +- * We will use a queued command if possible, otherwise we will +- * emulate the queuing and calling of completion function ourselves. +- */ +- atomic_inc(&cmd->device->iorequest_cnt); +- +- /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ +@@ -744,6 +737,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + } + + spin_lock_irqsave(host->host_lock, flags); ++ /* ++ * AK: unlikely race here: for some reason the timer could ++ * expire before the serial number is set up below. ++ * ++ * TODO: kill serial or move to blk layer ++ */ + scsi_cmd_get_serial(host, cmd); + + if (unlikely(host->shost_state == SHOST_DEL)) { +@@ -754,12 +753,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + } + spin_unlock_irqrestore(host->host_lock, flags); + if (rtn) { +- if (scsi_delete_timer(cmd)) { +- atomic_inc(&cmd->device->iodone_cnt); +- scsi_queue_insert(cmd, +- (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? +- rtn : SCSI_MLQUEUE_HOST_BUSY); +- } ++ scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? ++ rtn : SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, + printk("queuecommand : request rejected\n")); + } +@@ -770,24 +765,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + } + + /** +- * scsi_req_abort_cmd -- Request command recovery for the specified command +- * @cmd: pointer to the SCSI command of interest +- * +- * This function requests that SCSI Core start recovery for the +- * command by deleting the timer and adding the command to the eh +- * queue. It can be called by either LLDDs or SCSI Core. LLDDs who +- * implement their own error recovery MAY ignore the timeout event if +- * they generated scsi_req_abort_cmd. +- */ +-void scsi_req_abort_cmd(struct scsi_cmnd *cmd) +-{ +- if (!scsi_delete_timer(cmd)) +- return; +- scsi_times_out(cmd); +-} +-EXPORT_SYMBOL(scsi_req_abort_cmd); +- +-/** + * scsi_done - Enqueue the finished SCSI command into the done queue. + * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives + * ownership back to SCSI Core -- i.e. the LLDD has finished with it. +@@ -802,42 +779,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd); + */ + static void scsi_done(struct scsi_cmnd *cmd) + { +- /* +- * We don't have to worry about this one timing out anymore. +- * If we are unable to remove the timer, then the command +- * has already timed out. In which case, we have no choice but to +- * let the timeout function run, as we have no idea where in fact +- * that function could really be. It might be on another processor, +- * etc, etc. +- */ +- if (!scsi_delete_timer(cmd)) +- return; +- __scsi_done(cmd); +-} +- +-/* Private entry to scsi_done() to complete a command when the timer +- * isn't running --- used by scsi_times_out */ +-void __scsi_done(struct scsi_cmnd *cmd) +-{ +- struct request *rq = cmd->request; +- +- /* +- * Set the serial numbers back to zero +- */ +- cmd->serial_number = 0; +- +- atomic_inc(&cmd->device->iodone_cnt); +- if (cmd->result) +- atomic_inc(&cmd->device->ioerr_cnt); +- +- BUG_ON(!rq); +- +- /* +- * The uptodate/nbytes values don't matter, as we allow partial +- * completes and thus will check this in the softirq callback +- */ +- rq->completion_data = cmd; +- blk_complete_request(rq); ++ blk_complete_request(cmd->request); + } + + /* Move this to a header if it becomes more generally useful */ +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -112,69 +112,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s + } + + /** +- * scsi_add_timer - Start timeout timer for a single scsi command. +- * @scmd: scsi command that is about to start running. +- * @timeout: amount of time to allow this command to run. +- * @complete: timeout function to call if timer isn't canceled. +- * +- * Notes: +- * This should be turned into an inline function. Each scsi command +- * has its own timer, and as it is added to the queue, we set up the +- * timer. When the command completes, we cancel the timer. +- */ +-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, +- void (*complete)(struct scsi_cmnd *)) +-{ +- +- /* +- * If the clock was already running for this command, then +- * first delete the timer. The timer handling code gets rather +- * confused if we don't do this. +- */ +- if (scmd->eh_timeout.function) +- del_timer(&scmd->eh_timeout); +- +- scmd->eh_timeout.data = (unsigned long)scmd; +- scmd->eh_timeout.expires = jiffies + timeout; +- scmd->eh_timeout.function = (void (*)(unsigned long)) complete; +- +- SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:" +- " %d, (%p)\n", __func__, +- scmd, timeout, complete)); +- +- add_timer(&scmd->eh_timeout); +-} +- +-/** +- * scsi_delete_timer - Delete/cancel timer for a given function. +- * @scmd: Cmd that we are canceling timer for +- * +- * Notes: +- * This should be turned into an inline function. +- * +- * Return value: +- * 1 if we were able to detach the timer. 0 if we blew it, and the +- * timer function has already started to run. +- */ +-int scsi_delete_timer(struct scsi_cmnd *scmd) +-{ +- int rtn; +- +- rtn = del_timer(&scmd->eh_timeout); +- +- SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p," +- " rtn: %d\n", __func__, +- scmd, rtn)); +- +- scmd->eh_timeout.data = (unsigned long)NULL; +- scmd->eh_timeout.function = NULL; +- +- return rtn; +-} +- +-/** + * scsi_times_out - Timeout function for normal scsi commands. +- * @scmd: Cmd that is timing out. ++ * @req: request that is timing out. + * + * Notes: + * We do not need to lock this. There is the potential for a race +@@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd * + * normal completion function determines that the timer has already + * fired, then it mustn't do anything. + */ +-void scsi_times_out(struct scsi_cmnd *scmd) ++enum blk_eh_timer_return scsi_times_out(struct request *req) + { +- enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); ++ struct scsi_cmnd *scmd = req->special; ++ enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); ++ enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; + + scsi_log_completion(scmd, TIMEOUT_ERROR); + +@@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *sc + eh_timed_out = NULL; + + if (eh_timed_out) +- switch (eh_timed_out(scmd)) { +- case EH_HANDLED: +- __scsi_done(scmd); +- return; +- case EH_RESET_TIMER: +- scsi_add_timer(scmd, scmd->timeout_per_command, +- scsi_times_out); +- return; +- case EH_NOT_HANDLED: ++ rtn = eh_timed_out(scmd); ++ switch (rtn) { ++ case BLK_EH_NOT_HANDLED: + break; ++ default: ++ return rtn; + } + + if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { + scmd->result |= DID_TIME_OUT << 16; +- __scsi_done(scmd); ++ return BLK_EH_HANDLED; + } ++ ++ return BLK_EH_NOT_HANDLED; + } + + /** +@@ -1793,7 +1732,6 @@ scsi_reset_provider(struct scsi_device * + + blk_rq_init(NULL, &req); + scmd->request = &req; +- memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout)); + + scmd->cmnd = req.cmd; + +@@ -1804,8 +1742,6 @@ scsi_reset_provider(struct scsi_device * + + scmd->sc_data_direction = DMA_BIDIRECTIONAL; + +- init_timer(&scmd->eh_timeout); +- + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 1; + spin_unlock_irqrestore(shost->host_lock, flags); +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1181,7 +1181,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_d + + cmd->transfersize = req->data_len; + cmd->allowed = req->retries; +- cmd->timeout_per_command = req->timeout; + return BLKPREP_OK; + } + EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd); +@@ -1416,17 +1415,26 @@ static void scsi_kill_request(struct req + spin_unlock(shost->host_lock); + spin_lock(sdev->request_queue->queue_lock); + +- __scsi_done(cmd); ++ blk_complete_request(req); + } + + static void scsi_softirq_done(struct request *rq) + { +- struct scsi_cmnd *cmd = rq->completion_data; +- unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command; ++ struct scsi_cmnd *cmd = rq->special; ++ unsigned long wait_for = (cmd->allowed + 1) * rq->timeout; + int disposition; + + INIT_LIST_HEAD(&cmd->eh_entry); + ++ /* ++ * Set the serial numbers back to zero ++ */ ++ cmd->serial_number = 0; ++ ++ atomic_inc(&cmd->device->iodone_cnt); ++ if (cmd->result) ++ atomic_inc(&cmd->device->ioerr_cnt); ++ + disposition = scsi_decide_disposition(cmd); + if (disposition != SUCCESS && + time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { +@@ -1675,6 +1683,7 @@ struct request_queue *scsi_alloc_queue(s + + blk_queue_prep_rq(q, scsi_prep_fn); + blk_queue_softirq_done(q, scsi_softirq_done); ++ blk_queue_rq_timed_out(q, scsi_times_out); + return q; + } + +--- a/drivers/scsi/scsi_priv.h ++++ b/drivers/scsi/scsi_priv.h +@@ -4,6 +4,7 @@ + #include + + struct request_queue; ++struct request; + struct scsi_cmnd; + struct scsi_device; + struct scsi_host_template; +@@ -27,7 +28,6 @@ extern void scsi_exit_hosts(void); + extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); + extern int scsi_setup_command_freelist(struct Scsi_Host *shost); + extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); +-extern void __scsi_done(struct scsi_cmnd *cmd); + #ifdef CONFIG_SCSI_LOGGING + void scsi_log_send(struct scsi_cmnd *cmd); + void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); +@@ -49,10 +49,7 @@ extern int __init scsi_init_devinfo(void + extern void scsi_exit_devinfo(void); + + /* scsi_error.c */ +-extern void scsi_add_timer(struct scsi_cmnd *, int, +- void (*)(struct scsi_cmnd *)); +-extern int scsi_delete_timer(struct scsi_cmnd *); +-extern void scsi_times_out(struct scsi_cmnd *cmd); ++extern enum blk_eh_timer_return scsi_times_out(struct request *req); + extern int scsi_error_handler(void *host); + extern int scsi_decide_disposition(struct scsi_cmnd *cmd); + extern void scsi_eh_wakeup(struct Scsi_Host *shost); +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -560,12 +560,15 @@ sdev_rd_attr (vendor, "%.8s\n"); + sdev_rd_attr (model, "%.16s\n"); + sdev_rd_attr (rev, "%.4s\n"); + ++/* ++ * TODO: can we make these symlinks to the block layer ones? ++ */ + static ssize_t + sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf) + { + struct scsi_device *sdev; + sdev = to_scsi_device(dev); +- return snprintf (buf, 20, "%d\n", sdev->timeout / HZ); ++ return snprintf(buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ); + } + + static ssize_t +@@ -576,7 +579,7 @@ sdev_store_timeout (struct device *dev, + int timeout; + sdev = to_scsi_device(dev); + sscanf (buf, "%d\n", &timeout); +- sdev->timeout = timeout * HZ; ++ blk_queue_rq_timeout(sdev->request_queue, timeout * HZ); + return count; + } + static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout); +--- a/drivers/scsi/scsi_transport_fc.c ++++ b/drivers/scsi/scsi_transport_fc.c +@@ -1950,15 +1950,15 @@ static int fc_vport_match(struct attribu + * Notes: + * This routine assumes no locks are held on entry. + */ +-static enum scsi_eh_timer_return ++static enum blk_eh_timer_return + fc_timed_out(struct scsi_cmnd *scmd) + { + struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device)); + + if (rport->port_state == FC_PORTSTATE_BLOCKED) +- return EH_RESET_TIMER; ++ return BLK_EH_RESET_TIMER; + +- return EH_NOT_HANDLED; ++ return BLK_EH_NOT_HANDLED; + } + + /* +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -378,7 +378,6 @@ static int sd_prep_fn(struct request_que + sector_t block = rq->sector; + sector_t threshold; + unsigned int this_count = rq->nr_sectors; +- unsigned int timeout = sdp->timeout; + int ret; + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { +@@ -579,7 +578,6 @@ static int sd_prep_fn(struct request_que + SCpnt->transfersize = sdp->sector_size; + SCpnt->underflow = this_count << 9; + SCpnt->allowed = SD_MAX_RETRIES; +- SCpnt->timeout_per_command = timeout; + + /* + * This indicates that the command is ready from our end to be +@@ -1837,11 +1835,12 @@ static int sd_probe(struct device *dev) + sdkp->openers = 0; + sdkp->previous_state = 1; + +- if (!sdp->timeout) { ++ if (!sdp->request_queue->rq_timeout) { + if (sdp->type != TYPE_MOD) +- sdp->timeout = SD_TIMEOUT; ++ blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT); + else +- sdp->timeout = SD_MOD_TIMEOUT; ++ blk_queue_rq_timeout(sdp->request_queue, ++ SD_MOD_TIMEOUT); + } + + device_initialize(&sdkp->dev); +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -331,7 +331,7 @@ static int sr_done(struct scsi_cmnd *SCp + + static int sr_prep_fn(struct request_queue *q, struct request *rq) + { +- int block=0, this_count, s_size, timeout = SR_TIMEOUT; ++ int block = 0, this_count, s_size; + struct scsi_cd *cd; + struct scsi_cmnd *SCpnt; + struct scsi_device *sdp = q->queuedata; +@@ -461,7 +461,6 @@ static int sr_prep_fn(struct request_que + SCpnt->transfersize = cd->device->sector_size; + SCpnt->underflow = this_count << 9; + SCpnt->allowed = MAX_RETRIES; +- SCpnt->timeout_per_command = timeout; + + /* + * This indicates that the command is ready from our end to be +@@ -620,6 +619,8 @@ static int sr_probe(struct device *dev) + disk->fops = &sr_bdops; + disk->flags = GENHD_FL_CD; + ++ blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); ++ + cd->device = sdev; + cd->disk = disk; + cd->driver = &sr_template; +--- a/drivers/scsi/sym53c8xx_2/sym_glue.c ++++ b/drivers/scsi/sym53c8xx_2/sym_glue.c +@@ -519,8 +519,8 @@ static int sym53c8xx_queue_command(struc + * Shorten our settle_time if needed for + * this command not to time out. + */ +- if (np->s.settle_time_valid && cmd->timeout_per_command) { +- unsigned long tlimit = jiffies + cmd->timeout_per_command; ++ if (np->s.settle_time_valid && cmd->request->timeout) { ++ unsigned long tlimit = jiffies + cmd->request->timeout; + tlimit -= SYM_CONF_TIMER_INTERVAL*2; + if (time_after(np->s.settle_time, tlimit)) { + np->s.settle_time = tlimit; +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -147,6 +147,7 @@ struct request { + + unsigned int cmd_flags; + enum rq_cmd_type_bits cmd_type; ++ unsigned long atomic_flags; + + /* Maintain bio traversal state for part by part I/O submission. + * hard_* are block layer internals, no driver should touch them! +@@ -214,6 +215,8 @@ struct request { + void *data; + void *sense; + ++ unsigned long deadline; ++ struct list_head timeout_list; + unsigned int timeout; + int retries; + +@@ -266,6 +269,14 @@ typedef void (prepare_flush_fn) (struct + typedef void (softirq_done_fn)(struct request *); + typedef int (dma_drain_needed_fn)(struct request *); + ++enum blk_eh_timer_return { ++ BLK_EH_NOT_HANDLED, ++ BLK_EH_HANDLED, ++ BLK_EH_RESET_TIMER, ++}; ++ ++typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *); ++ + enum blk_queue_state { + Queue_down, + Queue_up, +@@ -311,6 +322,7 @@ struct request_queue + merge_bvec_fn *merge_bvec_fn; + prepare_flush_fn *prepare_flush_fn; + softirq_done_fn *softirq_done_fn; ++ rq_timed_out_fn *rq_timed_out_fn; + dma_drain_needed_fn *dma_drain_needed; + + /* +@@ -386,6 +398,10 @@ struct request_queue + unsigned int nr_sorted; + unsigned int in_flight; + ++ unsigned int rq_timeout; ++ struct timer_list timeout; ++ struct list_head timeout_list; ++ + /* + * sg stuff + */ +@@ -762,6 +778,8 @@ extern int blk_end_request_callback(stru + unsigned int nr_bytes, + int (drv_callback)(struct request *)); + extern void blk_complete_request(struct request *); ++extern void __blk_complete_request(struct request *); ++extern void blk_abort_request(struct request *); + + /* + * blk_end_request() takes bytes instead of sectors as a complete size. +@@ -803,6 +821,8 @@ extern void blk_queue_dma_alignment(stru + extern void blk_queue_update_dma_alignment(struct request_queue *, int); + extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); + extern void blk_queue_set_discard(struct request_queue *, prepare_discard_fn *); ++extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *); ++extern void blk_queue_rq_timeout(struct request_queue *, unsigned int); + extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); + extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *); + extern int blk_do_ordered(struct request_queue *, struct request **); +--- a/include/scsi/scsi_cmnd.h ++++ b/include/scsi/scsi_cmnd.h +@@ -75,7 +75,6 @@ struct scsi_cmnd { + + int retries; + int allowed; +- int timeout_per_command; + + unsigned char prot_op; + unsigned char prot_type; +@@ -86,7 +85,6 @@ struct scsi_cmnd { + /* These elements define the operation we are about to perform */ + unsigned char *cmnd; + +- struct timer_list eh_timeout; /* Used to time out the command. */ + + /* These elements define the operation we ultimately want to perform */ + struct scsi_data_buffer sdb; +@@ -139,7 +137,6 @@ extern void scsi_put_command(struct scsi + extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *, + struct device *); + extern void scsi_finish_command(struct scsi_cmnd *cmd); +-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); + + extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, + size_t *offset, size_t *len); +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -43,13 +43,6 @@ struct blk_queue_tags; + #define DISABLE_CLUSTERING 0 + #define ENABLE_CLUSTERING 1 + +-enum scsi_eh_timer_return { +- EH_NOT_HANDLED, +- EH_HANDLED, +- EH_RESET_TIMER, +-}; +- +- + struct scsi_host_template { + struct module *module; + const char *name; +@@ -347,7 +340,7 @@ struct scsi_host_template { + * + * Status: OPTIONAL + */ +- enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); ++ enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); + + /* + * Name of proc directory +--- a/include/scsi/scsi_transport.h ++++ b/include/scsi/scsi_transport.h +@@ -21,6 +21,7 @@ + #define SCSI_TRANSPORT_H + + #include ++#include + #include + #include + +@@ -64,7 +65,7 @@ struct scsi_transport_template { + * begin counting again + * EH_NOT_HANDLED Begin normal error recovery + */ +- enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); ++ enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); + + /* + * Used as callback for the completion of i_t_nexus request diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Add-PCI-ID-for-5716S b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Add-PCI-ID-for-5716S new file mode 100644 index 000000000..b18b9a0a3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Add-PCI-ID-for-5716S @@ -0,0 +1,40 @@ +Commit-Id: 1caacecb7cb2b72e798f06a32b5061075cf397fa +From: Michael Chan +Date: Wed, 12 Nov 2008 16:01:12 -0800 +Acked-by: Karsten Keil +Subject: [PATCH] bnx2: Add PCI ID for 5716S. + +Signed-off-by: Michael Chan +Signed-off-by: Matt Carlson +Signed-off-by: Benjamin Li +Signed-off-by: David S. Miller + +diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c +index 51b163a..49ebb50 100644 +--- a/drivers/net/bnx2.c ++++ b/drivers/net/bnx2.c +@@ -89,6 +89,7 @@ typedef enum { + BCM5709, + BCM5709S, + BCM5716, ++ BCM5716S, + } board_t; + + /* indexed by board_t, above */ +@@ -105,6 +106,7 @@ static struct { + { "Broadcom NetXtreme II BCM5709 1000Base-T" }, + { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, + { "Broadcom NetXtreme II BCM5716 1000Base-T" }, ++ { "Broadcom NetXtreme II BCM5716 1000Base-SX" }, + }; + + static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { +@@ -128,6 +130,8 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, + { PCI_VENDOR_ID_BROADCOM, 0x163b, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, ++ { PCI_VENDOR_ID_BROADCOM, 0x163c, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, + { 0, } + }; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Add-bnx2_shutdown_chip b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Add-bnx2_shutdown_chip new file mode 100644 index 000000000..0c53eef6e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Add-bnx2_shutdown_chip @@ -0,0 +1,88 @@ +Commit-Id: 74bf4ba3d367aacbc04fef167289767f162cd730 +From: Michael Chan +Date: Thu, 9 Oct 2008 12:21:08 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] bnx2: Add bnx2_shutdown_chip(). +Reference: bnc#440052 + +This logic is used in bnx2_close() and bnx2_suspend() and +so should be separated out into a separate function. + +Signed-off-by: Michael Chan +Signed-off-by: Benjamin Li +Signed-off-by: Matt Carlson +Signed-off-by: David S. Miller + +--- + drivers/net/bnx2.c | 33 +++++++++++++++++---------------- + 1 file changed, 17 insertions(+), 16 deletions(-) + +--- a/drivers/net/bnx2.c ++++ b/drivers/net/bnx2.c +@@ -5077,6 +5077,21 @@ bnx2_init_nic(struct bnx2 *bp, int reset + } + + static int ++bnx2_shutdown_chip(struct bnx2 *bp) ++{ ++ u32 reset_code; ++ ++ if (bp->flags & BNX2_FLAG_NO_WOL) ++ reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; ++ else if (bp->wol) ++ reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; ++ else ++ reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; ++ ++ return bnx2_reset_chip(bp, reset_code); ++} ++ ++static int + bnx2_test_registers(struct bnx2 *bp) + { + int ret; +@@ -6099,20 +6114,13 @@ static int + bnx2_close(struct net_device *dev) + { + struct bnx2 *bp = netdev_priv(dev); +- u32 reset_code; + + cancel_work_sync(&bp->reset_task); + + bnx2_disable_int_sync(bp); + bnx2_napi_disable(bp); + del_timer_sync(&bp->timer); +- if (bp->flags & BNX2_FLAG_NO_WOL) +- reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; +- else if (bp->wol) +- reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; +- else +- reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; +- bnx2_reset_chip(bp, reset_code); ++ bnx2_shutdown_chip(bp); + bnx2_free_irq(bp); + bnx2_free_skbs(bp); + bnx2_free_mem(bp); +@@ -7783,7 +7791,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_me + { + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp = netdev_priv(dev); +- u32 reset_code; + + /* PCI register 4 needs to be saved whether netif_running() or not. + * MSI address and data need to be saved if using MSI and +@@ -7797,13 +7804,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_me + bnx2_netif_stop(bp); + netif_device_detach(dev); + del_timer_sync(&bp->timer); +- if (bp->flags & BNX2_FLAG_NO_WOL) +- reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; +- else if (bp->wol) +- reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; +- else +- reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; +- bnx2_reset_chip(bp, reset_code); ++ bnx2_shutdown_chip(bp); + bnx2_free_skbs(bp); + bnx2_set_power_state(bp, pci_choose_state(pdev, state)); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Fix-bug-in-bnx2_free_rx_mem_ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Fix-bug-in-bnx2_free_rx_mem_ new file mode 100644 index 000000000..baf70755e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-Fix-bug-in-bnx2_free_rx_mem_ @@ -0,0 +1,31 @@ +Commit-Id: 3298a7388c00227e736d1037328788073c80c7b4 +From: Michael Chan +Date: Wed, 17 Dec 2008 19:06:08 -0800 +Acked-by: Karsten Keil +Subject: [PATCH] bnx2: Fix bug in bnx2_free_rx_mem(). + +DMA memory for the jumbo rx page rings was freed incorrectly using the +wrong local variable as the array index. + +Signed-off-by: Michael Chan +Signed-off-by: David S. Miller + +--- + drivers/net/bnx2.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/bnx2.c ++++ b/drivers/net/bnx2.c +@@ -547,9 +547,9 @@ bnx2_free_rx_mem(struct bnx2 *bp) + for (j = 0; j < bp->rx_max_pg_ring; j++) { + if (rxr->rx_pg_desc_ring[j]) + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, +- rxr->rx_pg_desc_ring[i], +- rxr->rx_pg_desc_mapping[i]); +- rxr->rx_pg_desc_ring[i] = NULL; ++ rxr->rx_pg_desc_ring[j], ++ rxr->rx_pg_desc_mapping[j]); ++ rxr->rx_pg_desc_ring[j] = NULL; + } + if (rxr->rx_pg_ring) + vfree(rxr->rx_pg_ring); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2-check-running.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-check-running.patch new file mode 100644 index 000000000..dad9a115b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2-check-running.patch @@ -0,0 +1,140 @@ +From: Michael Chan +Subject: Check netif_running in most ethtool operations +Acked-by: Karsten Keil +Reference: bnc#440052 + +We need to check netif_running() state in most ethtool operations + and properly handle the !netif_running() state where the chip is + in an uninitailzed state or low power state that may not accept + any MMIO. + + Signed-off-by: Michael Chan + Signed-off-by: Benjamin Li + Signed-off-by: Matt Carlson + Signed-off-by: David S. Miller + +Backport to 2.6.27 + +--- + drivers/net/bnx2.c | 40 ++++++++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 8 deletions(-) + +--- a/drivers/net/bnx2.c ++++ b/drivers/net/bnx2.c +@@ -3252,6 +3252,9 @@ bnx2_set_rx_mode(struct net_device *dev) + struct dev_addr_list *uc_ptr; + int i; + ++ if (!netif_running(dev)) ++ return; ++ + spin_lock_bh(&bp->phy_lock); + + rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS | +@@ -5525,6 +5528,9 @@ bnx2_test_link(struct bnx2 *bp) + { + u32 bmsr; + ++ if (!netif_running(bp->dev)) ++ return -ENODEV; ++ + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { + if (bp->link_up) + return 0; +@@ -6489,6 +6495,9 @@ bnx2_nway_reset(struct net_device *dev) + struct bnx2 *bp = netdev_priv(dev); + u32 bmcr; + ++ if (!netif_running(dev)) ++ return -EAGAIN; ++ + if (!(bp->autoneg & AUTONEG_SPEED)) { + return -EINVAL; + } +@@ -6544,6 +6553,9 @@ bnx2_get_eeprom(struct net_device *dev, + struct bnx2 *bp = netdev_priv(dev); + int rc; + ++ if (!netif_running(dev)) ++ return -EAGAIN; ++ + /* parameters already validated in ethtool_get_eeprom */ + + rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); +@@ -6558,6 +6570,9 @@ bnx2_set_eeprom(struct net_device *dev, + struct bnx2 *bp = netdev_priv(dev); + int rc; + ++ if (!netif_running(dev)) ++ return -EAGAIN; ++ + /* parameters already validated in ethtool_set_eeprom */ + + rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); +@@ -6722,11 +6737,11 @@ bnx2_set_pauseparam(struct net_device *d + bp->autoneg &= ~AUTONEG_FLOW_CTRL; + } + +- spin_lock_bh(&bp->phy_lock); +- +- bnx2_setup_phy(bp, bp->phy_port); +- +- spin_unlock_bh(&bp->phy_lock); ++ if (netif_running(dev)) { ++ spin_lock_bh(&bp->phy_lock); ++ bnx2_setup_phy(bp, bp->phy_port); ++ spin_unlock_bh(&bp->phy_lock); ++ } + + return 0; + } +@@ -6917,6 +6932,8 @@ bnx2_self_test(struct net_device *dev, s + { + struct bnx2 *bp = netdev_priv(dev); + ++ bnx2_set_power_state(bp, PCI_D0); ++ + memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS); + if (etest->flags & ETH_TEST_FL_OFFLINE) { + int i; +@@ -6936,9 +6953,8 @@ bnx2_self_test(struct net_device *dev, s + if ((buf[2] = bnx2_test_loopback(bp)) != 0) + etest->flags |= ETH_TEST_FL_FAILED; + +- if (!netif_running(bp->dev)) { +- bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); +- } ++ if (!netif_running(bp->dev)) ++ bnx2_shutdown_chip(bp); + else { + bnx2_init_nic(bp, 1); + bnx2_netif_start(bp); +@@ -6966,6 +6982,8 @@ bnx2_self_test(struct net_device *dev, s + etest->flags |= ETH_TEST_FL_FAILED; + + } ++ if (!netif_running(bp->dev)) ++ bnx2_set_power_state(bp, PCI_D3hot); + } + + static void +@@ -7031,6 +7049,8 @@ bnx2_phys_id(struct net_device *dev, u32 + int i; + u32 save; + ++ bnx2_set_power_state(bp, PCI_D0); ++ + if (data == 0) + data = 2; + +@@ -7055,6 +7075,10 @@ bnx2_phys_id(struct net_device *dev, u32 + } + REG_WR(bp, BNX2_EMAC_LED, 0); + REG_WR(bp, BNX2_MISC_CFG, save); ++ ++ if (!netif_running(dev)) ++ bnx2_set_power_state(bp, PCI_D3hot); ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-1G-10G-toggling-race.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-1G-10G-toggling-race.patch new file mode 100644 index 000000000..c4e634eb2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-1G-10G-toggling-race.patch @@ -0,0 +1,161 @@ +From 6c55c3cdc86881383075a933594748b30dd0054b Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:13 +0000 +Subject: bnx2x: 1G-10G toggling race +Acked-by: Karsten Keil +Reference: bnc#472500 + +The HW should be configured so fast toggling between 1G and 10G will not be +missed. Make sure that the HW is re-configured in full + +Signed-off-by: Yaniv Rosner +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_link.c | 43 ++++++++++++++++++++++++++++++++----------- + 1 files changed, 32 insertions(+), 11 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_link.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +@@ -317,6 +317,9 @@ static u8 bnx2x_emac_enable(struct link_ + val &= ~0x810; + EMAC_WR(bp, EMAC_REG_EMAC_MODE, val); + ++ /* enable emac */ ++ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1); ++ + /* enable emac for jumbo packets */ + EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE, + (EMAC_RX_MTU_SIZE_JUMBO_ENA | +@@ -1609,7 +1612,7 @@ static u8 bnx2x_link_settings_status(str + u32 gp_status) + { + struct bnx2x *bp = params->bp; +- ++ u16 new_line_speed; + u8 rc = 0; + vars->link_status = 0; + +@@ -1629,7 +1632,7 @@ static u8 bnx2x_link_settings_status(str + + switch (gp_status & GP_STATUS_SPEED_MASK) { + case GP_STATUS_10M: +- vars->line_speed = SPEED_10; ++ new_line_speed = SPEED_10; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_10TFD; + else +@@ -1637,7 +1640,7 @@ static u8 bnx2x_link_settings_status(str + break; + + case GP_STATUS_100M: +- vars->line_speed = SPEED_100; ++ new_line_speed = SPEED_100; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_100TXFD; + else +@@ -1646,7 +1649,7 @@ static u8 bnx2x_link_settings_status(str + + case GP_STATUS_1G: + case GP_STATUS_1G_KX: +- vars->line_speed = SPEED_1000; ++ new_line_speed = SPEED_1000; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_1000TFD; + else +@@ -1654,7 +1657,7 @@ static u8 bnx2x_link_settings_status(str + break; + + case GP_STATUS_2_5G: +- vars->line_speed = SPEED_2500; ++ new_line_speed = SPEED_2500; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_2500TFD; + else +@@ -1671,32 +1674,32 @@ static u8 bnx2x_link_settings_status(str + case GP_STATUS_10G_KX4: + case GP_STATUS_10G_HIG: + case GP_STATUS_10G_CX4: +- vars->line_speed = SPEED_10000; ++ new_line_speed = SPEED_10000; + vars->link_status |= LINK_10GTFD; + break; + + case GP_STATUS_12G_HIG: +- vars->line_speed = SPEED_12000; ++ new_line_speed = SPEED_12000; + vars->link_status |= LINK_12GTFD; + break; + + case GP_STATUS_12_5G: +- vars->line_speed = SPEED_12500; ++ new_line_speed = SPEED_12500; + vars->link_status |= LINK_12_5GTFD; + break; + + case GP_STATUS_13G: +- vars->line_speed = SPEED_13000; ++ new_line_speed = SPEED_13000; + vars->link_status |= LINK_13GTFD; + break; + + case GP_STATUS_15G: +- vars->line_speed = SPEED_15000; ++ new_line_speed = SPEED_15000; + vars->link_status |= LINK_15GTFD; + break; + + case GP_STATUS_16G: +- vars->line_speed = SPEED_16000; ++ new_line_speed = SPEED_16000; + vars->link_status |= LINK_16GTFD; + break; + +@@ -1708,6 +1711,15 @@ static u8 bnx2x_link_settings_status(str + break; + } + ++ /* Upon link speed change set the NIG into drain mode. ++ Comes to deals with possible FIFO glitch due to clk change ++ when speed is decreased without link down indicator */ ++ if (new_line_speed != vars->line_speed) { ++ REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE ++ + params->port*4, 0); ++ msleep(1); ++ } ++ vars->line_speed = new_line_speed; + vars->link_status |= LINK_STATUS_SERDES_LINK; + + if ((params->req_line_speed == SPEED_AUTO_NEG) && +@@ -4194,6 +4206,11 @@ static u8 bnx2x_update_link_down(struct + /* activate nig drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); + ++ /* disable emac */ ++ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); ++ ++ msleep(10); ++ + /* reset BigMac */ + bnx2x_bmac_rx_disable(bp, params->port); + REG_WR(bp, GRCBASE_MISC + +@@ -4238,6 +4255,7 @@ static u8 bnx2x_update_link_up(struct li + + /* update shared memory */ + bnx2x_update_mng(params, vars->link_status); ++ msleep(20); + return rc; + } + /* This function should called upon link interrupt */ +@@ -4276,6 +4294,9 @@ u8 bnx2x_link_update(struct link_params + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); + ++ /* disable emac */ ++ REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); ++ + ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + + /* Check external link change only for non-direct */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Adding-restriction-on-sge_buf_size.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Adding-restriction-on-sge_buf_size.patch new file mode 100644 index 000000000..6eeb1e848 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Adding-restriction-on-sge_buf_size.patch @@ -0,0 +1,30 @@ +From 916c775ff297dc60219a4f0e5527ba6ab4a88ed4 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Mon, 9 Mar 2009 00:52:14 +0000 +Subject: [PATCH] bnx2x: Adding restriction on sge_buf_size +References: bnc#481074 + +sge_buff_size may not be more than 0xffff. + +Reported-by: Bjorn Helgaas +Signed-off-by: Vladislav Zolotarov +Tested-by: Bjorn Helgaas +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +Signed-off-by: Brandon Philips +--- + drivers/net/bnx2x_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/bnx2x_main.c ++++ b/drivers/net/bnx2x_main.c +@@ -4521,7 +4521,8 @@ static void bnx2x_init_context(struct bn + (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA | + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING); + context->ustorm_st_context.common.sge_buff_size = +- (u16)(BCM_PAGE_SIZE*PAGES_PER_SGE); ++ (u16)min((u32)SGE_PAGE_SIZE*PAGES_PER_SGE, ++ (u32)0xffff); + context->ustorm_st_context.common.sge_page_base_hi = + U64_HI(fp->rx_sge_mapping); + context->ustorm_st_context.common.sge_page_base_lo = diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Barriers-for-the-compiler.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Barriers-for-the-compiler.patch new file mode 100644 index 000000000..f0bc6a667 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Barriers-for-the-compiler.patch @@ -0,0 +1,117 @@ +From 237907c1ded8a1a447cea7c4f97ab853e8b46052 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:42:44 +0000 +Subject: bnx2x: Barriers for the compiler +Acked-by: Karsten Keil +Reference: bnc#472500 + +To make sure no swapping are made by the compiler, changed HAS_WORK to inline +functions and added all the necessary barriers + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x.h | 9 +-------- + drivers/net/bnx2x_main.c | 37 ++++++++++++++++++++++++++----------- + 2 files changed, 27 insertions(+), 19 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +@@ -271,14 +271,7 @@ struct bnx2x_fastpath { + + #define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) + +-#define BNX2X_HAS_TX_WORK(fp) \ +- ((fp->tx_pkt_prod != le16_to_cpu(*fp->tx_cons_sb)) || \ +- (fp->tx_pkt_prod != fp->tx_pkt_cons)) +- +-#define BNX2X_HAS_RX_WORK(fp) \ +- (fp->rx_comp_cons != rx_cons_sb) +- +-#define BNX2X_HAS_WORK(fp) (BNX2X_HAS_RX_WORK(fp) || BNX2X_HAS_TX_WORK(fp)) ++#define BNX2X_HAS_WORK(fp) (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp)) + + + /* MC hsi */ +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -733,6 +733,17 @@ static u16 bnx2x_ack_int(struct bnx2x *b + * fast path service functions + */ + ++static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp) ++{ ++ u16 tx_cons_sb; ++ ++ /* Tell compiler that status block fields can change */ ++ barrier(); ++ tx_cons_sb = le16_to_cpu(*fp->tx_cons_sb); ++ return ((fp->tx_pkt_prod != tx_cons_sb) || ++ (fp->tx_pkt_prod != fp->tx_pkt_cons)); ++} ++ + /* free skb in the packet ring at pos idx + * return idx of last bd freed + */ +@@ -6696,7 +6707,7 @@ static int bnx2x_nic_unload(struct bnx2x + + cnt = 1000; + smp_rmb(); +- while (BNX2X_HAS_TX_WORK(fp)) { ++ while (bnx2x_has_tx_work(fp)) { + + bnx2x_tx_int(fp, 1000); + if (!cnt) { +@@ -9285,6 +9296,18 @@ static int bnx2x_set_power_state(struct + return 0; + } + ++static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp) ++{ ++ u16 rx_cons_sb; ++ ++ /* Tell compiler that status block fields can change */ ++ barrier(); ++ rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); ++ if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) ++ rx_cons_sb++; ++ return (fp->rx_comp_cons != rx_cons_sb); ++} ++ + /* + * net_device service functions + */ +@@ -9295,7 +9318,6 @@ static int bnx2x_poll(struct napi_struct + napi); + struct bnx2x *bp = fp->bp; + int work_done = 0; +- u16 rx_cons_sb; + + #ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) +@@ -9308,19 +9330,12 @@ static int bnx2x_poll(struct napi_struct + + bnx2x_update_fpsb_idx(fp); + +- if (BNX2X_HAS_TX_WORK(fp)) ++ if (bnx2x_has_tx_work(fp)) + bnx2x_tx_int(fp, budget); + +- rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); +- if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) +- rx_cons_sb++; +- if (BNX2X_HAS_RX_WORK(fp)) ++ if (bnx2x_has_rx_work(fp)) + work_done = bnx2x_rx_int(fp, budget); +- + rmb(); /* BNX2X_HAS_WORK() reads the status block */ +- rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); +- if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) +- rx_cons_sb++; + + /* must not complete if we consumed full budget */ + if ((work_done < budget) && !BNX2X_HAS_WORK(fp)) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Calling-napi_del.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Calling-napi_del.patch new file mode 100644 index 000000000..1094c0cca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Calling-napi_del.patch @@ -0,0 +1,48 @@ +From 7cde1c8b79f913a0158bae4f4c612de2cb98e7e4 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 06:01:25 +0000 +Subject: bnx2x: Calling napi_del +Acked-by: Karsten Keil +Reference: bnc#472500 + +rmmod might hang without this patch since the reference counter is not going +down + +Signed-off-by: Yitchak Gertner +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6550,6 +6550,8 @@ load_error2: + bnx2x_free_irq(bp); + load_error1: + bnx2x_napi_disable(bp); ++ for_each_queue(bp, i) ++ netif_napi_del(&bnx2x_fp(bp, i, napi)); + bnx2x_free_mem(bp); + + /* TBD we really need to reset the chip +@@ -6858,6 +6860,8 @@ unload_error: + bnx2x_free_skbs(bp); + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); ++ for_each_queue(bp, i) ++ netif_napi_del(&bnx2x_fp(bp, i, napi)); + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; +@@ -10484,6 +10488,8 @@ static int bnx2x_eeh_nic_unload(struct b + bnx2x_free_skbs(bp); + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); ++ for_each_queue(bp, i) ++ netif_napi_del(&bnx2x_fp(bp, i, napi)); + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Carrier-off-first-call.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Carrier-off-first-call.patch new file mode 100644 index 000000000..3586edd71 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Carrier-off-first-call.patch @@ -0,0 +1,39 @@ +From 6eccabb301d442e6106ecc84b07a976c2816d9fb Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 03:37:48 +0000 +Subject: bnx2x: Carrier off first call +Acked-by: Karsten Keil +Reference: bnc#472500 + +Call carrier off should not be called after register_netdev since after +register netdev open can be called at any time followed by an interrupt that +will set it to carrier_on and the probe will resume control and set it to off + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -9831,6 +9831,8 @@ static int bnx2x_open(struct net_device + { + struct bnx2x *bp = netdev_priv(dev); + ++ netif_carrier_off(dev); ++ + bnx2x_set_power_state(bp, PCI_D0); + + return bnx2x_nic_load(bp, LOAD_OPEN); +@@ -10335,8 +10337,6 @@ static int __devinit bnx2x_init_one(stru + goto init_one_exit; + } + +- netif_carrier_off(dev); +- + bp->common.name = board_info[ent->driver_data].name; + printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx," + " IRQ %d, ", dev->name, bp->common.name, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Casting-page-alignment.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Casting-page-alignment.patch new file mode 100644 index 000000000..497908cf2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Casting-page-alignment.patch @@ -0,0 +1,36 @@ +From 6dc7d8c843024c2636cf52d3f93047acbcd765f2 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Mon, 9 Mar 2009 00:52:17 +0000 +Subject: [PATCH] bnx2x: Casting page alignment +References: bnc#481074 + +Adding a proper cast to the argument of PAGE_ALIGN macro so that the output +won't depend on its original type. Without this cast aligned value will be +truncated to the size of the argument type. + +Reported-by: Bjorn Helgaas +Signed-off-by: Vladislav Zolotarov +Tested-by: Bjorn Helgaas +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +Signed-off-by: Brandon Philips +--- + drivers/net/bnx2x.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h +index 15a5cf0..3cf2b92 100644 +--- a/drivers/net/bnx2x.h ++++ b/drivers/net/bnx2x.h +@@ -152,7 +152,7 @@ struct sw_rx_page { + #define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) + #define SGE_PAGE_SIZE PAGE_SIZE + #define SGE_PAGE_SHIFT PAGE_SHIFT +-#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN(addr) ++#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))addr) + + #define BCM_RX_ETH_PAYLOAD_ALIGN 64 + +-- +1.6.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Disable-napi.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Disable-napi.patch new file mode 100644 index 000000000..a43e4e81e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Disable-napi.patch @@ -0,0 +1,39 @@ +From e94d8af3da79f4bfbd22819d28ecf0602456f06f Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 03:37:36 +0000 +Subject: bnx2x: Disable napi +Acked-by: Karsten Keil +Reference: bnc#472500 + +Calling napi disabled unconditionally at netif stop + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 5 ++--- + 1 files changed, 2 insertions(+), 3 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6146,8 +6146,8 @@ static void bnx2x_netif_start(struct bnx + static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) + { + bnx2x_int_disable_sync(bp, disable_hw); ++ bnx2x_napi_disable(bp); + if (netif_running(bp->dev)) { +- bnx2x_napi_disable(bp); + netif_tx_disable(bp->dev); + bp->dev->trans_start = jiffies; /* prevent tx timeout */ + } +@@ -6692,8 +6692,7 @@ static int bnx2x_nic_unload(struct bnx2x + bnx2x_set_storm_rx_mode(bp); + + bnx2x_netif_stop(bp, 1); +- if (!netif_running(bp->dev)) +- bnx2x_napi_disable(bp); ++ + del_timer_sync(&bp->timer); + SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb, + (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq)); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Driver-description-update.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Driver-description-update.patch new file mode 100644 index 000000000..ff15c1cab --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Driver-description-update.patch @@ -0,0 +1,29 @@ +From e47d7e6eb841c1850f0e69b95ae6cf3c86881f53 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:28 +0000 +Subject: bnx2x: Driver description update +Acked-by: Karsten Keil +Reference: bnc#472500 + +The Driver supports the 57711 and 57711E as well but the description was out of +date + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -69,7 +69,7 @@ static char version[] __devinitdata = + DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + + MODULE_AUTHOR("Eliezer Tamir"); +-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver"); ++MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710/57711/57711E Driver"); + MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_MODULE_VERSION); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Endianness-issues.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Endianness-issues.patch new file mode 100644 index 000000000..9e4ed4067 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Endianness-issues.patch @@ -0,0 +1,59 @@ +From 68d5948436c2f782ebb5ddf25a6588ee452e8c30 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:27:36 -0800 +Subject: bnx2x: Endianness issues +Acked-by: Karsten Keil +Reference: bnc#472500 + +Adding missing le_to_cpu and disabling wrong HW endianity flag (the +two complete each other) + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 11 ++++++----- + 1 files changed, 6 insertions(+), 5 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -1439,7 +1439,7 @@ static int bnx2x_rx_int(struct bnx2x_fas + DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x" + " queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags), + cqe_fp_flags, cqe->fast_path_cqe.status_flags, +- cqe->fast_path_cqe.rss_hash_result, ++ le32_to_cpu(cqe->fast_path_cqe.rss_hash_result), + le16_to_cpu(cqe->fast_path_cqe.vlan_tag), + le16_to_cpu(cqe->fast_path_cqe.pkt_len)); + +@@ -2824,8 +2824,10 @@ static void bnx2x_attn_int_deasserted(st + static void bnx2x_attn_int(struct bnx2x *bp) + { + /* read local copy of bits */ +- u32 attn_bits = bp->def_status_blk->atten_status_block.attn_bits; +- u32 attn_ack = bp->def_status_blk->atten_status_block.attn_bits_ack; ++ u32 attn_bits = le32_to_cpu(bp->def_status_blk->atten_status_block. ++ attn_bits); ++ u32 attn_ack = le32_to_cpu(bp->def_status_blk->atten_status_block. ++ attn_bits_ack); + u32 attn_state = bp->attn_state; + + /* look for changed bits */ +@@ -2873,7 +2875,7 @@ static void bnx2x_sp_task(struct work_st + if (status & 0x2) + bp->stats_pending = 0; + +- bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx, ++ bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(bp->def_att_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx), + IGU_INT_NOP, 1); +@@ -5164,7 +5166,6 @@ static int bnx2x_init_common(struct bnx2 + REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); +- REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1); + + /* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ + REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-First-slow-path-interrupt-race.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-First-slow-path-interrupt-race.patch new file mode 100644 index 000000000..5201a7af1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-First-slow-path-interrupt-race.patch @@ -0,0 +1,54 @@ +From 0ef00459a638ae4f5d1e5326d3e50232fa80119f Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:31:08 -0800 +Subject: bnx2x: First slow path interrupt race +Acked-by: Karsten Keil +Reference: bnc#472500 + +The "read for interrupts" flag must be set before enabling slow-path +interrupts as well (and not just before fast-path interrupts) + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 18 +++++++++--------- + 1 files changed, 9 insertions(+), 9 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -4815,6 +4815,15 @@ static void bnx2x_nic_init(struct bnx2x + bnx2x_init_context(bp); + bnx2x_init_internal(bp, load_code); + bnx2x_init_ind_table(bp); ++ bnx2x_stats_init(bp); ++ ++ /* At this point, we are ready for interrupts */ ++ atomic_set(&bp->intr_sem, 0); ++ ++ /* flush all before enabling interrupts */ ++ mb(); ++ mmiowb(); ++ + bnx2x_int_enable(bp); + } + +@@ -6423,17 +6432,8 @@ static int bnx2x_nic_load(struct bnx2x * + } + } + +- bnx2x_stats_init(bp); +- + bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; + +- /* Enable Rx interrupt handling before sending the ramrod +- as it's completed on Rx FP queue */ +- bnx2x_napi_enable(bp); +- +- /* Enable interrupt handling */ +- atomic_set(&bp->intr_sem, 0); +- + rc = bnx2x_setup_leading(bp); + if (rc) { + BNX2X_ERR("Setup leading failed!\n"); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Fixing-the-doorbell-size.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Fixing-the-doorbell-size.patch new file mode 100644 index 000000000..41e1d630a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Fixing-the-doorbell-size.patch @@ -0,0 +1,29 @@ +From a5f67a04d998b0b6e4beb1de8f1247dd93ac1ff4 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:28:13 -0800 +Subject: bnx2x: Fixing the doorbell size +Acked-by: Karsten Keil +Reference: bnc#472500 + +The size of the doorbell is 4KB, this bug become visible when using +more than 8 queues + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +@@ -739,7 +739,7 @@ struct bnx2x { + struct bnx2x_fastpath fp[MAX_CONTEXT]; + void __iomem *regview; + void __iomem *doorbells; +-#define BNX2X_DB_SIZE (16*2048) ++#define BNX2X_DB_SIZE (16*BCM_PAGE_SIZE) + + struct net_device *dev; + struct pci_dev *pdev; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Flow-control-updated-before-reporting-the-lin.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Flow-control-updated-before-reporting-the-lin.patch new file mode 100644 index 000000000..cb444f9c5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Flow-control-updated-before-reporting-the-lin.patch @@ -0,0 +1,30 @@ +From 3c96c68b0c67d11b8519bc38233aec586f0211f4 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:25:31 -0800 +Subject: bnx2x: Flow control updated before reporting the link +Acked-by: Karsten Keil +Reference: bnc#472500 + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -1973,10 +1973,11 @@ static u8 bnx2x_initial_phy_init(struct + rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars); + bnx2x_release_phy_lock(bp); + ++ bnx2x_calc_fc_adv(bp); ++ + if (bp->link_vars.link_up) + bnx2x_link_report(bp); + +- bnx2x_calc_fc_adv(bp); + + return rc; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Free-IRQ.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Free-IRQ.patch new file mode 100644 index 000000000..4aec2c3ac --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Free-IRQ.patch @@ -0,0 +1,39 @@ +From 70b9986ca4baaf6deb6f0e01d50f72457579adea Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:43:48 +0000 +Subject: bnx2x: Free IRQ +Acked-by: Karsten Keil +Reference: bnc#472500 + +Error check could result with not freeing the IRQ + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6687,6 +6687,9 @@ static int bnx2x_nic_unload(struct bnx2x + (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq)); + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + ++ /* Release IRQs */ ++ bnx2x_free_irq(bp); ++ + /* Wait until tx fast path tasks complete */ + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; +@@ -6714,9 +6717,6 @@ static int bnx2x_nic_unload(struct bnx2x + /* Give HW time to discard old tx messages */ + msleep(1); + +- /* Release IRQs */ +- bnx2x_free_irq(bp); +- + if (CHIP_IS_E1(bp)) { + struct mac_configuration_cmd *config = + bnx2x_sp(bp, mcast_config); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-PHY-FW-load-failure.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-PHY-FW-load-failure.patch new file mode 100644 index 000000000..b4b896de7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-PHY-FW-load-failure.patch @@ -0,0 +1,35 @@ +From 16b311cc29806bb968746c1a752a087b32841af9 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:24 +0000 +Subject: bnx2x: Handling PHY FW load failure +Acked-by: Karsten Keil +Reference: bnc#472500 + +If the default PHY version (0x4321) is read - the PHY FW load failed + +Signed-off-by: Yaniv Rosner +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_link.c | 7 ++++--- + 1 files changed, 4 insertions(+), 3 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_link.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +@@ -4404,10 +4404,11 @@ static u8 bnx2x_8073_common_init_phy(str + ext_phy_addr[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); +- if (fw_ver1 == 0) { ++ if (fw_ver1 == 0 || fw_ver1 == 0x4321) { + DP(NETIF_MSG_LINK, +- "bnx2x_8073_common_init_phy port %x " +- "fw Download failed\n", port); ++ "bnx2x_8073_common_init_phy port %x:" ++ "Download failed. fw version = 0x%x\n", ++ port, fw_ver1); + return -EINVAL; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-load-failures.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-load-failures.patch new file mode 100644 index 000000000..233766bfe --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-load-failures.patch @@ -0,0 +1,278 @@ +From 2dfe0e1fecb582b4aae7f2490904864c05472f3a Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 03:37:44 +0000 +Subject: bnx2x: Handling load failures +Acked-by: Karsten Keil +Reference: bnc#472500 + +Failures on load were not handled correctly - separate the flow to handle + +different failures + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 154 ++++++++++++++++++++++++++-------------------- + 1 files changed, 88 insertions(+), 66 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6331,7 +6331,7 @@ static void bnx2x_set_rx_mode(struct net + static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) + { + u32 load_code; +- int i, rc; ++ int i, rc = 0; + #ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EPERM; +@@ -6339,48 +6339,6 @@ static int bnx2x_nic_load(struct bnx2x * + + bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; + +- /* Send LOAD_REQUEST command to MCP +- Returns the type of LOAD command: +- if it is the first port to be initialized +- common blocks should be initialized, otherwise - not +- */ +- if (!BP_NOMCP(bp)) { +- load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); +- if (!load_code) { +- BNX2X_ERR("MCP response failure, aborting\n"); +- return -EBUSY; +- } +- if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) +- return -EBUSY; /* other port in diagnostic mode */ +- +- } else { +- int port = BP_PORT(bp); +- +- DP(NETIF_MSG_IFUP, "NO MCP load counts before us %d, %d, %d\n", +- load_count[0], load_count[1], load_count[2]); +- load_count[0]++; +- load_count[1 + port]++; +- DP(NETIF_MSG_IFUP, "NO MCP new load counts %d, %d, %d\n", +- load_count[0], load_count[1], load_count[2]); +- if (load_count[0] == 1) +- load_code = FW_MSG_CODE_DRV_LOAD_COMMON; +- else if (load_count[1 + port] == 1) +- load_code = FW_MSG_CODE_DRV_LOAD_PORT; +- else +- load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION; +- } +- +- if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || +- (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) +- bp->port.pmf = 1; +- else +- bp->port.pmf = 0; +- DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); +- +- /* if we can't use MSI-X we only need one fp, +- * so try to enable MSI-X with the requested number of fp's +- * and fallback to inta with one fp +- */ + if (use_inta) { + bp->num_queues = 1; + +@@ -6395,7 +6353,15 @@ static int bnx2x_nic_load(struct bnx2x * + else + bp->num_queues = 1; + +- if (bnx2x_enable_msix(bp)) { ++ DP(NETIF_MSG_IFUP, ++ "set number of queues to %d\n", bp->num_queues); ++ ++ /* if we can't use MSI-X we only need one fp, ++ * so try to enable MSI-X with the requested number of fp's ++ * and fallback to MSI or legacy INTx with one fp ++ */ ++ rc = bnx2x_enable_msix(bp); ++ if (rc) { + /* failed to enable MSI-X */ + bp->num_queues = 1; + if (use_multi) +@@ -6403,8 +6369,6 @@ static int bnx2x_nic_load(struct bnx2x * + " to enable MSI-X\n"); + } + } +- DP(NETIF_MSG_IFUP, +- "set number of queues to %d\n", bp->num_queues); + + if (bnx2x_alloc_mem(bp)) + return -ENOMEM; +@@ -6413,30 +6377,85 @@ static int bnx2x_nic_load(struct bnx2x * + bnx2x_fp(bp, i, disable_tpa) = + ((bp->flags & TPA_ENABLE_FLAG) == 0); + ++ for_each_queue(bp, i) ++ netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), ++ bnx2x_poll, 128); ++ ++#ifdef BNX2X_STOP_ON_ERROR ++ for_each_queue(bp, i) { ++ struct bnx2x_fastpath *fp = &bp->fp[i]; ++ ++ fp->poll_no_work = 0; ++ fp->poll_calls = 0; ++ fp->poll_max_calls = 0; ++ fp->poll_complete = 0; ++ fp->poll_exit = 0; ++ } ++#endif ++ bnx2x_napi_enable(bp); ++ + if (bp->flags & USING_MSIX_FLAG) { + rc = bnx2x_req_msix_irqs(bp); + if (rc) { + pci_disable_msix(bp->pdev); +- goto load_error; ++ goto load_error1; + } ++ printk(KERN_INFO PFX "%s: using MSI-X\n", bp->dev->name); + } else { + bnx2x_ack_int(bp); + rc = bnx2x_req_irq(bp); + if (rc) { +- BNX2X_ERR("IRQ request failed, aborting\n"); +- goto load_error; ++ BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc); ++ goto load_error1; + } + } + +- for_each_queue(bp, i) +- netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), +- bnx2x_poll, 128); ++ /* Send LOAD_REQUEST command to MCP ++ Returns the type of LOAD command: ++ if it is the first port to be initialized ++ common blocks should be initialized, otherwise - not ++ */ ++ if (!BP_NOMCP(bp)) { ++ load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); ++ if (!load_code) { ++ BNX2X_ERR("MCP response failure, aborting\n"); ++ rc = -EBUSY; ++ goto load_error2; ++ } ++ if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) { ++ rc = -EBUSY; /* other port in diagnostic mode */ ++ goto load_error2; ++ } ++ ++ } else { ++ int port = BP_PORT(bp); ++ ++ DP(NETIF_MSG_IFUP, "NO MCP load counts before us %d, %d, %d\n", ++ load_count[0], load_count[1], load_count[2]); ++ load_count[0]++; ++ load_count[1 + port]++; ++ DP(NETIF_MSG_IFUP, "NO MCP new load counts %d, %d, %d\n", ++ load_count[0], load_count[1], load_count[2]); ++ if (load_count[0] == 1) ++ load_code = FW_MSG_CODE_DRV_LOAD_COMMON; ++ else if (load_count[1 + port] == 1) ++ load_code = FW_MSG_CODE_DRV_LOAD_PORT; ++ else ++ load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION; ++ } ++ ++ if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || ++ (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) ++ bp->port.pmf = 1; ++ else ++ bp->port.pmf = 0; ++ DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* Initialize HW */ + rc = bnx2x_init_hw(bp, load_code); + if (rc) { + BNX2X_ERR("HW init failed, aborting\n"); +- goto load_int_disable; ++ goto load_error2; + } + + /* Setup NIC internals and enable interrupts */ +@@ -6448,7 +6467,7 @@ static int bnx2x_nic_load(struct bnx2x * + if (!load_code) { + BNX2X_ERR("MCP response failure, aborting\n"); + rc = -EBUSY; +- goto load_rings_free; ++ goto load_error3; + } + } + +@@ -6457,7 +6476,7 @@ static int bnx2x_nic_load(struct bnx2x * + rc = bnx2x_setup_leading(bp); + if (rc) { + BNX2X_ERR("Setup leading failed!\n"); +- goto load_netif_stop; ++ goto load_error3; + } + + if (CHIP_IS_E1H(bp)) +@@ -6470,7 +6489,7 @@ static int bnx2x_nic_load(struct bnx2x * + for_each_nondefault_queue(bp, i) { + rc = bnx2x_setup_multi(bp, i); + if (rc) +- goto load_netif_stop; ++ goto load_error3; + } + + if (CHIP_IS_E1(bp)) +@@ -6486,18 +6505,18 @@ static int bnx2x_nic_load(struct bnx2x * + case LOAD_NORMAL: + /* Tx queue should be only reenabled */ + netif_wake_queue(bp->dev); ++ /* Initialize the receive filter. */ + bnx2x_set_rx_mode(bp->dev); + break; + + case LOAD_OPEN: + netif_start_queue(bp->dev); ++ /* Initialize the receive filter. */ + bnx2x_set_rx_mode(bp->dev); +- if (bp->flags & USING_MSIX_FLAG) +- printk(KERN_INFO PFX "%s: using MSI-X\n", +- bp->dev->name); + break; + + case LOAD_DIAG: ++ /* Initialize the receive filter. */ + bnx2x_set_rx_mode(bp->dev); + bp->state = BNX2X_STATE_DIAG; + break; +@@ -6515,20 +6534,23 @@ static int bnx2x_nic_load(struct bnx2x * + + return 0; + +-load_netif_stop: +- bnx2x_napi_disable(bp); +-load_rings_free: ++load_error3: ++ bnx2x_int_disable_sync(bp, 1); ++ if (!BP_NOMCP(bp)) { ++ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP); ++ bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); ++ } ++ bp->port.pmf = 0; + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); +-load_int_disable: +- bnx2x_int_disable_sync(bp, 1); ++load_error2: + /* Release IRQs */ + bnx2x_free_irq(bp); +-load_error: ++load_error1: ++ bnx2x_napi_disable(bp); + bnx2x_free_mem(bp); +- bp->port.pmf = 0; + + /* TBD we really need to reset the chip + if we want to recover from this */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-probe-failures.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-probe-failures.patch new file mode 100644 index 000000000..e42ee7c33 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Handling-probe-failures.patch @@ -0,0 +1,44 @@ +From 693fc0d14334859430733ab902adac182fdd8153 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:43:52 +0000 +Subject: bnx2x: Handling probe failures +Acked-by: Karsten Keil +Reference: bnc#472500 + +Failures in the probe not handled correctly - separate the flow to handle + +different failures + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 12 +++++------- + 1 files changed, 5 insertions(+), 7 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -10272,17 +10272,15 @@ static int __devinit bnx2x_init_one(stru + return rc; + } + +- rc = register_netdev(dev); +- if (rc) { +- dev_err(&pdev->dev, "Cannot register net device\n"); +- goto init_one_exit; +- } +- + pci_set_drvdata(pdev, dev); + + rc = bnx2x_init_bp(bp); ++ if (rc) ++ goto init_one_exit; ++ ++ rc = register_netdev(dev); + if (rc) { +- unregister_netdev(dev); ++ dev_err(&pdev->dev, "Cannot register net device\n"); + goto init_one_exit; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Indirection-table-initialization-index.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Indirection-table-initialization-index.patch new file mode 100644 index 000000000..17c616427 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Indirection-table-initialization-index.patch @@ -0,0 +1,50 @@ +From 26c8fa4d8a08b6e7a61f23339e2236218957ecc0 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:29:55 -0800 +Subject: bnx2x: Indirection table initialization index +Acked-by: Karsten Keil +Reference: bnc#472500 + +Wrong initialization of the multi-queue indirection table - it should +be using the function and not the port index + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 9 ++++----- + 1 files changed, 4 insertions(+), 5 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -4527,7 +4527,7 @@ static void bnx2x_init_context(struct bn + + static void bnx2x_init_ind_table(struct bnx2x *bp) + { +- int port = BP_PORT(bp); ++ int func = BP_FUNC(bp); + int i; + + if (!is_multi(bp)) +@@ -4536,10 +4536,8 @@ static void bnx2x_init_ind_table(struct + DP(NETIF_MSG_IFUP, "Initializing indirection table\n"); + for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) + REG_WR8(bp, BAR_TSTRORM_INTMEM + +- TSTORM_INDIRECTION_TABLE_OFFSET(port) + i, +- i % bp->num_queues); +- +- REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); ++ TSTORM_INDIRECTION_TABLE_OFFSET(func) + i, ++ BP_CL_ID(bp) + (i % bp->num_queues)); + } + + static void bnx2x_set_client_config(struct bnx2x *bp) +@@ -5243,6 +5241,7 @@ static int bnx2x_init_common(struct bnx2 + } + + bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); ++ REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); + if (CHIP_IS_E1H(bp)) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Legacy-speeds-autoneg-failures.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Legacy-speeds-autoneg-failures.patch new file mode 100644 index 000000000..49fb2c96d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Legacy-speeds-autoneg-failures.patch @@ -0,0 +1,38 @@ +From 44722d1d216c9dd4536de5f88fe8320b07e68a96 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:21 +0000 +Subject: bnx2x: Legacy speeds autoneg failures +Acked-by: Karsten Keil +Reference: bnc#472500 + +10M/100M autoneg was not establishing link. + +Signed-off-by: Yaniv Rosner +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_link.c | 10 ++++++++-- + 1 files changed, 8 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_link.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +@@ -3882,9 +3882,15 @@ static u8 bnx2x_link_initialize(struct l + } + + if (vars->phy_flags & PHY_XGXS_FLAG) { +- if (params->req_line_speed && ++ if ((params->req_line_speed && + ((params->req_line_speed == SPEED_100) || +- (params->req_line_speed == SPEED_10))) { ++ (params->req_line_speed == SPEED_10))) || ++ (!params->req_line_speed && ++ (params->speed_cap_mask >= ++ PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) && ++ (params->speed_cap_mask < ++ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) ++ )) { + vars->phy_flags |= PHY_SGMII_FLAG; + } else { + vars->phy_flags &= ~PHY_SGMII_FLAG; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-MTU-Filter.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-MTU-Filter.patch new file mode 100644 index 000000000..77216d614 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-MTU-Filter.patch @@ -0,0 +1,28 @@ +From e7799c5f79072b5b34cf08170f142bcb8569cfff Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:30:27 -0800 +Subject: bnx2x: MTU Filter +Acked-by: Karsten Keil +Reference: bnc#472500 + +Too big packets could pass due to wrong filter size + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -4546,7 +4546,7 @@ static void bnx2x_set_client_config(stru + int port = BP_PORT(bp); + int i; + +- tstorm_client.mtu = bp->dev->mtu + ETH_OVREHEAD; ++ tstorm_client.mtu = bp->dev->mtu; + tstorm_client.statistics_counter_id = BP_CL_ID(bp); + tstorm_client.config_flags = + TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-brackets.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-brackets.patch new file mode 100644 index 000000000..e1de02bb0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-brackets.patch @@ -0,0 +1,28 @@ +From f5ba6772f226be0266f95642c8162493246d3b79 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:29:18 -0800 +Subject: bnx2x: Missing brackets +Acked-by: Karsten Keil +Reference: bnc#472500 + +Calculation bug due to missing brackets + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -2923,7 +2923,7 @@ static irqreturn_t bnx2x_msix_sp_int(int + #define ADD_64(s_hi, a_hi, s_lo, a_lo) \ + do { \ + s_lo += a_lo; \ +- s_hi += a_hi + (s_lo < a_lo) ? 1 : 0; \ ++ s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \ + } while (0) + + /* difference = minuend - subtrahend */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-mask-when-calculating-flow-control.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-mask-when-calculating-flow-control.patch new file mode 100644 index 000000000..b713ccd4d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-mask-when-calculating-flow-control.patch @@ -0,0 +1,27 @@ +From ad33ea3a8d2ec324dc0f46b6ae404d824d2b349b Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:24:57 -0800 +Subject: bnx2x: Missing mask when calculating flow control +Acked-by: Karsten Keil +Reference: bnc#472500 + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -1902,7 +1902,8 @@ static int bnx2x_set_spio(struct bnx2x * + + static void bnx2x_calc_fc_adv(struct bnx2x *bp) + { +- switch (bp->link_vars.ieee_fc) { ++ switch (bp->link_vars.ieee_fc & ++ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) { + case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE: + bp->port.advertising &= ~(ADVERTISED_Asym_Pause | + ADVERTISED_Pause); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-memory-barriers.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-memory-barriers.patch new file mode 100644 index 000000000..ea5f70ea5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-memory-barriers.patch @@ -0,0 +1,95 @@ +From 58f4c4cfce5c4715b79621f0a635925c55f855d5 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:23:36 -0800 +Subject: bnx2x: Missing memory barriers +Acked-by: Karsten Keil +Reference: bnc#472500 + +While working on IA64, it became clear that the following memory +barriers are missing + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 28 ++++++++++++++++++++++++++-- + 1 files changed, 26 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -1358,11 +1358,23 @@ static inline void bnx2x_update_rx_prod( + rx_prods.cqe_prod = rx_comp_prod; + rx_prods.sge_prod = rx_sge_prod; + ++ /* ++ * Make sure that the BD and SGE data is updated before updating the ++ * producers since FW might read the BD/SGE right after the producer ++ * is updated. ++ * This is only applicable for weak-ordered memory model archs such ++ * as IA-64. The following barrier is also mandatory since FW will ++ * assumes BDs must have buffers. ++ */ ++ wmb(); ++ + for (i = 0; i < sizeof(struct tstorm_eth_rx_producers)/4; i++) + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_RX_PRODS_OFFSET(BP_PORT(bp), FP_CL_ID(fp)) + i*4, + ((u32 *)&rx_prods)[i]); + ++ mmiowb(); /* keep prod updates ordered */ ++ + DP(NETIF_MSG_RX_STATUS, + "Wrote: bd_prod %u cqe_prod %u sge_prod %u\n", + bd_prod, rx_comp_prod, rx_sge_prod); +@@ -1584,7 +1596,6 @@ next_cqe: + /* Update producers */ + bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod, + fp->rx_sge_prod); +- mmiowb(); /* keep prod updates ordered */ + + fp->rx_pkt += rx_pkt; + fp->rx_calls++; +@@ -8732,6 +8743,8 @@ static int bnx2x_run_loopback(struct bnx + tx_bd->general_data = ((UNICAST_ADDRESS << + ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1); + ++ wmb(); ++ + fp->hw_tx_prods->bds_prod = + cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + 1); + mb(); /* FW restriction: must not reorder writing nbd and packets */ +@@ -8784,7 +8797,6 @@ test_loopback_rx_exit: + /* Update producers */ + bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, + fp->rx_sge_prod); +- mmiowb(); /* keep prod updates ordered */ + + test_loopback_exit: + bp->link_params.loopback_mode = LOOPBACK_NONE; +@@ -9711,6 +9723,15 @@ static int bnx2x_start_xmit(struct sk_bu + + DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod); + ++ /* ++ * Make sure that the BD data is updated before updating the producer ++ * since FW might read the BD right after the producer is updated. ++ * This is only applicable for weak-ordered memory model archs such ++ * as IA-64. The following barrier is also mandatory since FW will ++ * assumes packets must have BDs. ++ */ ++ wmb(); ++ + fp->hw_tx_prods->bds_prod = + cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + nbd); + mb(); /* FW restriction: must not reorder writing nbd and packets */ +@@ -9724,6 +9745,9 @@ static int bnx2x_start_xmit(struct sk_bu + dev->trans_start = jiffies; + + if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { ++ /* We want bnx2x_tx_int to "see" the updated tx_bd_prod ++ if we put Tx into XOFF state. */ ++ smp_mb(); + netif_stop_queue(dev); + bp->eth_stats.driver_xoff++; + if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-rmb-when-waiting-for-FW-response.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-rmb-when-waiting-for-FW-response.patch new file mode 100644 index 000000000..71a9dc8e7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Missing-rmb-when-waiting-for-FW-response.patch @@ -0,0 +1,28 @@ +From 5650d9d4cbf3898d3f9725ccad5dfca6bc086324 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 06:01:29 +0000 +Subject: bnx2x: Missing rmb when waiting for FW response +Acked-by: Karsten Keil +Reference: bnc#472500 + +Waiting for the FW to response requires a memory barrier + +Signed-off-by: Michal Kalderon +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6625,6 +6625,7 @@ static int bnx2x_stop_leading(struct bnx + } + cnt--; + msleep(1); ++ rmb(); /* Refresh the dsb_sp_prod */ + } + bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD; + bp->fp[0].state = BNX2X_FP_STATE_CLOSED; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Overstepping-array-bounds.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Overstepping-array-bounds.patch new file mode 100644 index 000000000..2400d00a5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Overstepping-array-bounds.patch @@ -0,0 +1,51 @@ +From 632da4d66324b5baf947a048dd1f1e9093b6dd90 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:10 +0000 +Subject: bnx2x: Overstepping array bounds +Acked-by: Karsten Keil +Reference: bnc#472500 + +If the page size is > 8KB this violation happens + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -9431,6 +9431,7 @@ static inline u32 bnx2x_xmit_type(struct + return rc; + } + ++#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3) + /* check if packet requires linearization (packet is too fragmented) */ + static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb, + u32 xmit_type) +@@ -9508,6 +9509,7 @@ exit_lbl: + + return to_copy; + } ++#endif + + /* called with netif_tx_lock + * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call +@@ -9548,6 +9550,7 @@ static int bnx2x_start_xmit(struct sk_bu + skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr, + ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type); + ++#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3) + /* First, check if we need to linearize the skb + (due to FW restrictions) */ + if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) { +@@ -9560,6 +9563,7 @@ static int bnx2x_start_xmit(struct sk_bu + return NETDEV_TX_OK; + } + } ++#endif + + /* + Please read carefully. First we use one BD which we mark as start, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Potential-race-after-iSCSI-boot.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Potential-race-after-iSCSI-boot.patch new file mode 100644 index 000000000..ff559a4ee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Potential-race-after-iSCSI-boot.patch @@ -0,0 +1,62 @@ +From b4661739c67acd15a02f8e112f8cc52d24b609ed Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:43:56 +0000 +Subject: bnx2x: Potential race after iSCSI boot +Acked-by: Karsten Keil +Reference: bnc#472500 + +The lock was release too soon. Make sure the HW is marked as locked until the +boot driver was unloaded from FW perspective + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 14 +++++++++----- + 1 files changed, 9 insertions(+), 5 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6877,10 +6877,6 @@ static void __devinit bnx2x_undi_unload( + */ + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); +- if (val == 0x7) +- REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); +- bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); +- + if (val == 0x7) { + u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + /* save our func */ +@@ -6888,6 +6884,9 @@ static void __devinit bnx2x_undi_unload( + u32 swap_en; + u32 swap_val; + ++ /* clear the UNDI indication */ ++ REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); ++ + BNX2X_DEV_INFO("UNDI is active! reset device\n"); + + /* try unload UNDI on port 0 */ +@@ -6913,6 +6912,9 @@ static void __devinit bnx2x_undi_unload( + bnx2x_fw_command(bp, reset_code); + } + ++ /* now it's safe to release the lock */ ++ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); ++ + REG_WR(bp, (BP_PORT(bp) ? HC_REG_CONFIG_1 : + HC_REG_CONFIG_0), 0x1000); + +@@ -6957,7 +6959,9 @@ static void __devinit bnx2x_undi_unload( + bp->fw_seq = + (SHMEM_RD(bp, func_mb[bp->func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); +- } ++ ++ } else ++ bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Prevent-self-test-loopback-failures.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Prevent-self-test-loopback-failures.patch new file mode 100644 index 000000000..22c9977b2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Prevent-self-test-loopback-failures.patch @@ -0,0 +1,29 @@ +From 3858276b7198074bf3570470463808627f0c9e31 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:16 +0000 +Subject: bnx2x: Prevent self test loopback failures +Acked-by: Karsten Keil +Reference: bnc#472500 + +Setting loopback requires time to take effect + +Signed-off-by: Yaniv Rosner +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_link.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_link.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +@@ -3583,7 +3583,7 @@ static void bnx2x_set_xgxs_loopback(stru + (MDIO_REG_BANK_CL73_IEEEB0 + + (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)), + 0x6041); +- ++ msleep(200); + /* set aer mmd back */ + bnx2x_set_aer_mmd(params, vars); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Protecting-the-link-change-indication.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Protecting-the-link-change-indication.patch new file mode 100644 index 000000000..4b85642cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Protecting-the-link-change-indication.patch @@ -0,0 +1,51 @@ +From a5e9a7cfad5fd301ce2b7869bbf386b70aa39e7c Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:26:01 -0800 +Subject: bnx2x: Protecting the link change indication +Acked-by: Karsten Keil +Reference: bnc#472500 + +Without this lock, in some race conditions the driver missed link +change indication + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 8 +++++--- + 1 files changed, 5 insertions(+), 3 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -2237,9 +2237,7 @@ static void bnx2x_link_attn(struct bnx2x + /* Make sure that we are synced with the current statistics */ + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + +- bnx2x_acquire_phy_lock(bp); + bnx2x_link_update(&bp->link_params, &bp->link_vars); +- bnx2x_release_phy_lock(bp); + + if (bp->link_vars.link_up) { + +@@ -2488,6 +2486,8 @@ static void bnx2x_attn_int_asserted(stru + if (asserted & ATTN_HARD_WIRED_MASK) { + if (asserted & ATTN_NIG_FOR_FUNC) { + ++ bnx2x_acquire_phy_lock(bp); ++ + /* save nig interrupt mask */ + bp->nig_mask = REG_RD(bp, nig_int_mask_addr); + REG_WR(bp, nig_int_mask_addr, 0); +@@ -2543,8 +2543,10 @@ static void bnx2x_attn_int_asserted(stru + REG_WR(bp, hc_addr, asserted); + + /* now set back the mask */ +- if (asserted & ATTN_NIG_FOR_FUNC) ++ if (asserted & ATTN_NIG_FOR_FUNC) { + REG_WR(bp, nig_int_mask_addr, bp->nig_mask); ++ bnx2x_release_phy_lock(bp); ++ } + } + + static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Read-chip-ID.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Read-chip-ID.patch new file mode 100644 index 000000000..24ae7ecaf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Read-chip-ID.patch @@ -0,0 +1,26 @@ +From 5a40e08e666e8caa1227333de41fd1e2cd84d4f5 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:04 +0000 +Subject: bnx2x: Read chip ID +Acked-by: Karsten Keil +Reference: bnc#472500 + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6978,7 +6978,7 @@ static void __devinit bnx2x_get_common_h + id |= ((val & 0xf) << 12); + val = REG_RD(bp, MISC_REG_CHIP_METAL); + id |= ((val & 0xff) << 4); +- REG_RD(bp, MISC_REG_BOND_ID); ++ val = REG_RD(bp, MISC_REG_BOND_ID); + id |= (val & 0xf); + bp->common.chip_id = id; + bp->link_params.chip_id = bp->common.chip_id; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Reset-HW-before-use.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Reset-HW-before-use.patch new file mode 100644 index 000000000..89b3bbb3b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Reset-HW-before-use.patch @@ -0,0 +1,58 @@ +From 81f75bbf67c7a26ea1266ac93b9319bb985d588d Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 03:37:31 +0000 +Subject: bnx2x: Reset HW before use +Acked-by: Karsten Keil +Reference: bnc#472500 + +To avoid complications, make sure that the HW is in reset (as it should be) +before trying to take it out of reset. In normal flows, the HW is indeed in rest +so this should have no effect + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 17 +++++++++-------- + 1 files changed, 9 insertions(+), 8 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -5151,12 +5151,21 @@ static void enable_blocks_attention(stru + } + + ++static void bnx2x_reset_common(struct bnx2x *bp) ++{ ++ /* reset_common */ ++ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, ++ 0xd3ffff7f); ++ REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); ++} ++ + static int bnx2x_init_common(struct bnx2x *bp) + { + u32 val, i; + + DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(bp)); + ++ bnx2x_reset_common(bp); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc); + +@@ -6643,14 +6652,6 @@ static void bnx2x_reset_port(struct bnx2 + /* TODO: Close Doorbell port? */ + } + +-static void bnx2x_reset_common(struct bnx2x *bp) +-{ +- /* reset_common */ +- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, +- 0xd3ffff7f); +- REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); +-} +- + static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) + { + DP(BNX2X_MSG_MCP, "function %d reset_code %x\n", diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-DMAE-to-initialize-the-chip.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-DMAE-to-initialize-the-chip.patch new file mode 100644 index 000000000..9cf67570a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-DMAE-to-initialize-the-chip.patch @@ -0,0 +1,88 @@ +From db434ac6bff0d991d0b60166dc9d6405b873d0f7 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Mon, 9 Mar 2009 00:52:21 +0000 +Subject: [PATCH] bnx2x: Using DMAE to initialize the chip +References: bnc#484716 + +There was a bug, which occasionally caused failure in PRAM initialization after +the cold boot. +Also incremented version number to 1.45.27. + +Signed-off-by: Vladislav Zolotarov +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +Signed-off-by: Brandon Philips +--- + drivers/net/bnx2x_init.h | 4 ---- + drivers/net/bnx2x_main.c | 18 +++++++++--------- + 2 files changed, 9 insertions(+), 13 deletions(-) + +--- a/drivers/net/bnx2x_init.h ++++ b/drivers/net/bnx2x_init.h +@@ -150,7 +150,6 @@ static void bnx2x_init_ind_wr(struct bnx + + static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len) + { +-#ifdef USE_DMAE + int offset = 0; + + if (bp->dmae_ready) { +@@ -164,9 +163,6 @@ static void bnx2x_write_big_buf(struct b + addr + offset, len); + } else + bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); +-#else +- bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len); +-#endif + } + + static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) +--- a/drivers/net/bnx2x_main.c ++++ b/drivers/net/bnx2x_main.c +@@ -57,7 +57,7 @@ + #include "bnx2x.h" + #include "bnx2x_init.h" + +-#define DRV_MODULE_VERSION "1.45.26" ++#define DRV_MODULE_VERSION "1.45.27" + #define DRV_MODULE_RELDATE "2009/01/26" + #define BNX2X_BC_VER 0x040200 + +@@ -4038,10 +4038,10 @@ static void bnx2x_zero_sb(struct bnx2x * + { + int port = BP_PORT(bp); + +- bnx2x_init_fill(bp, BAR_USTRORM_INTMEM + ++ bnx2x_init_fill(bp, USTORM_INTMEM_ADDR + + USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, + sizeof(struct ustorm_status_block)/4); +- bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM + ++ bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR + + CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, + sizeof(struct cstorm_status_block)/4); + } +@@ -4095,18 +4095,18 @@ static void bnx2x_zero_def_sb(struct bnx + { + int func = BP_FUNC(bp); + +- bnx2x_init_fill(bp, BAR_USTRORM_INTMEM + ++ bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR + ++ TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, ++ sizeof(struct tstorm_def_status_block)/4); ++ bnx2x_init_fill(bp, USTORM_INTMEM_ADDR + + USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct ustorm_def_status_block)/4); +- bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM + ++ bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block)/4); +- bnx2x_init_fill(bp, BAR_XSTRORM_INTMEM + ++ bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR + + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct xstorm_def_status_block)/4); +- bnx2x_init_fill(bp, BAR_TSTRORM_INTMEM + +- TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, +- sizeof(struct tstorm_def_status_block)/4); + } + + static void bnx2x_init_def_sb(struct bnx2x *bp, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-singlethread-work-queue.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-singlethread-work-queue.patch new file mode 100644 index 000000000..72c27142d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-singlethread-work-queue.patch @@ -0,0 +1,114 @@ +From 1cf167f27ad2720af11ee8aa350009342f909e70 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:22:18 -0800 +Subject: bnx2x: Using singlethread work queue +Acked-by: Karsten Keil +Reference: bnc#472500 + +Since slow-path events, including link update, are handled in +work-queue, a race condition was introduced in the self-test that +sometimes caused the link status to fail: the self-test was running +under RTNL lock, and if the link-watch was scheduled it stoped the +shared work-queue (waiting for the RTNL lock) and so the link update +event was not handled until the self-test ended (releasing the RTNL +lock) with failure (since the link status was not updated) + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x.h | 2 +- + drivers/net/bnx2x_main.c | 20 +++++++++++++++----- + 2 files changed, 16 insertions(+), 6 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +@@ -811,7 +811,7 @@ struct bnx2x { + int pm_cap; + int pcie_cap; + +- struct work_struct sp_task; ++ struct delayed_work sp_task; + struct work_struct reset_task; + + struct timer_list timer; +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -95,6 +95,7 @@ MODULE_PARM_DESC(debug, "default debug m + module_param(use_multi, int, 0); + MODULE_PARM_DESC(use_multi, "use per-CPU queues"); + #endif ++static struct workqueue_struct *bnx2x_wq; + + enum bnx2x_board_type { + BCM57710 = 0, +@@ -671,7 +672,8 @@ static void bnx2x_int_disable_sync(struc + synchronize_irq(bp->pdev->irq); + + /* make sure sp_task is not running */ +- cancel_work_sync(&bp->sp_task); ++ cancel_delayed_work(&bp->sp_task); ++ flush_workqueue(bnx2x_wq); + } + + /* fast path */ +@@ -1663,7 +1665,7 @@ static irqreturn_t bnx2x_interrupt(int i + + + if (unlikely(status & 0x1)) { +- schedule_work(&bp->sp_task); ++ queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); + + status &= ~0x1; + if (!status) +@@ -2823,7 +2825,7 @@ static void bnx2x_attn_int(struct bnx2x + + static void bnx2x_sp_task(struct work_struct *work) + { +- struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); ++ struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work); + u16 status; + + +@@ -2878,7 +2880,7 @@ static irqreturn_t bnx2x_msix_sp_int(int + return IRQ_HANDLED; + #endif + +- schedule_work(&bp->sp_task); ++ queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); + + return IRQ_HANDLED; + } +@@ -7504,7 +7506,7 @@ static int __devinit bnx2x_init_bp(struc + + mutex_init(&bp->port.phy_mutex); + +- INIT_WORK(&bp->sp_task, bnx2x_sp_task); ++ INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); + INIT_WORK(&bp->reset_task, bnx2x_reset_task); + + rc = bnx2x_get_hwinfo(bp); +@@ -10522,12 +10524,20 @@ static struct pci_driver bnx2x_pci_drive + + static int __init bnx2x_init(void) + { ++ bnx2x_wq = create_singlethread_workqueue("bnx2x"); ++ if (bnx2x_wq == NULL) { ++ printk(KERN_ERR PFX "Cannot create workqueue\n"); ++ return -ENOMEM; ++ } ++ + return pci_register_driver(&bnx2x_pci_driver); + } + + static void __exit bnx2x_cleanup(void) + { + pci_unregister_driver(&bnx2x_pci_driver); ++ ++ destroy_workqueue(bnx2x_wq); + } + + module_init(bnx2x_init); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-system-page-size-for-SGE.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-system-page-size-for-SGE.patch new file mode 100644 index 000000000..2f3289415 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Using-system-page-size-for-SGE.patch @@ -0,0 +1,141 @@ +From 4f40f2cba244e04c0f385c5ce60498b513b335dd Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:24:17 -0800 +Subject: bnx2x: Using system page size for SGE +Acked-by: Karsten Keil +Reference: bnc#472500 + +When the page size is not 4KB, the FW must be programmed to work with +the right SGE boundaries and fragment list length. + +To avoid confusion with the BCM_PAGE_SIZE which is set to 4KB for the +FW sake, another alias for the system page size was added to +explicitly indicate that it is meant for the SGE + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x.h | 3 +++ + drivers/net/bnx2x_main.c | 32 ++++++++++++++++---------------- + 2 files changed, 19 insertions(+), 16 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +@@ -150,6 +150,9 @@ struct sw_rx_page { + + #define PAGES_PER_SGE_SHIFT 0 + #define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) ++#define SGE_PAGE_SIZE PAGE_SIZE ++#define SGE_PAGE_SHIFT PAGE_SHIFT ++#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN(addr) + + #define BCM_RX_ETH_PAYLOAD_ALIGN 64 + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -974,7 +974,7 @@ static inline void bnx2x_free_rx_sge(str + return; + + pci_unmap_page(bp->pdev, pci_unmap_addr(sw_buf, mapping), +- BCM_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE); ++ SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE); + __free_pages(page, PAGES_PER_SGE_SHIFT); + + sw_buf->page = NULL; +@@ -1002,7 +1002,7 @@ static inline int bnx2x_alloc_rx_sge(str + if (unlikely(page == NULL)) + return -ENOMEM; + +- mapping = pci_map_page(bp->pdev, page, 0, BCM_PAGE_SIZE*PAGES_PER_SGE, ++ mapping = pci_map_page(bp->pdev, page, 0, SGE_PAGE_SIZE*PAGES_PER_SGE, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + __free_pages(page, PAGES_PER_SGE_SHIFT); +@@ -1098,9 +1098,9 @@ static void bnx2x_update_sge_prod(struct + struct eth_fast_path_rx_cqe *fp_cqe) + { + struct bnx2x *bp = fp->bp; +- u16 sge_len = BCM_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) - ++ u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) - + le16_to_cpu(fp_cqe->len_on_bd)) >> +- BCM_PAGE_SHIFT; ++ SGE_PAGE_SHIFT; + u16 last_max, last_elem, first_elem; + u16 delta = 0; + u16 i; +@@ -1205,22 +1205,22 @@ static int bnx2x_fill_frag_skb(struct bn + u16 cqe_idx) + { + struct sw_rx_page *rx_pg, old_rx_pg; +- struct page *sge; + u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd); + u32 i, frag_len, frag_size, pages; + int err; + int j; + + frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd; +- pages = BCM_PAGE_ALIGN(frag_size) >> BCM_PAGE_SHIFT; ++ pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT; + + /* This is needed in order to enable forwarding support */ + if (frag_size) +- skb_shinfo(skb)->gso_size = min((u32)BCM_PAGE_SIZE, ++ skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE, + max(frag_size, (u32)len_on_bd)); + + #ifdef BNX2X_STOP_ON_ERROR +- if (pages > 8*PAGES_PER_SGE) { ++ if (pages > ++ min((u32)8, (u32)MAX_SKB_FRAGS) * SGE_PAGE_SIZE * PAGES_PER_SGE) { + BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n", + pages, cqe_idx); + BNX2X_ERR("fp_cqe->pkt_len = %d fp_cqe->len_on_bd = %d\n", +@@ -1236,9 +1236,8 @@ static int bnx2x_fill_frag_skb(struct bn + + /* FW gives the indices of the SGE as if the ring is an array + (meaning that "next" element will consume 2 indices) */ +- frag_len = min(frag_size, (u32)(BCM_PAGE_SIZE*PAGES_PER_SGE)); ++ frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE)); + rx_pg = &fp->rx_page_ring[sge_idx]; +- sge = rx_pg->page; + old_rx_pg = *rx_pg; + + /* If we fail to allocate a substitute page, we simply stop +@@ -1251,7 +1250,7 @@ static int bnx2x_fill_frag_skb(struct bn + + /* Unmap the page as we r going to pass it to the stack */ + pci_unmap_page(bp->pdev, pci_unmap_addr(&old_rx_pg, mapping), +- BCM_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE); ++ SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE); + + /* Add one frag and update the appropriate fields in the skb */ + skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len); +@@ -4547,7 +4546,7 @@ static void bnx2x_set_client_config(stru + + if (bp->flags & TPA_ENABLE_FLAG) { + tstorm_client.max_sges_for_packet = +- BCM_PAGE_ALIGN(tstorm_client.mtu) >> BCM_PAGE_SHIFT; ++ SGE_PAGE_ALIGN(tstorm_client.mtu) >> SGE_PAGE_SHIFT; + tstorm_client.max_sges_for_packet = + ((tstorm_client.max_sges_for_packet + + PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE - 1))) >> +@@ -4730,10 +4729,11 @@ static void bnx2x_init_internal_func(str + bp->e1hov); + } + +- /* Init CQ ring mapping and aggregation size */ +- max_agg_size = min((u32)(bp->rx_buf_size + +- 8*BCM_PAGE_SIZE*PAGES_PER_SGE), +- (u32)0xffff); ++ /* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */ ++ max_agg_size = ++ min((u32)(min((u32)8, (u32)MAX_SKB_FRAGS) * ++ SGE_PAGE_SIZE * PAGES_PER_SGE), ++ (u32)0xffff); + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-VLAN-tagged-packets-without-VLAN-offload.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-VLAN-tagged-packets-without-VLAN-offload.patch new file mode 100644 index 000000000..ae118c12f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-VLAN-tagged-packets-without-VLAN-offload.patch @@ -0,0 +1,167 @@ +From 0c6671b0d94f706dfc20cb22d792218ba9814412 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 21:26:51 -0800 +Subject: bnx2x: VLAN tagged packets without VLAN offload +Acked-by: Karsten Keil +Reference: bnc#472500 + +Wrong handling of tagged packet if VLAN offload is disabled caused +packets to get corrupted + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x.h | 12 +++++++----- + drivers/net/bnx2x_main.c | 42 +++++++++++++++++++++++++++++++++--------- + 2 files changed, 40 insertions(+), 14 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +@@ -20,6 +20,11 @@ + * (you will need to reboot afterwards) */ + /* #define BNX2X_STOP_ON_ERROR */ + ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++#define BCM_VLAN 1 ++#endif ++ ++ + /* error/debug prints */ + + #define DRV_MODULE_NAME "bnx2x" +@@ -78,11 +83,6 @@ + #endif + + +-#ifdef NETIF_F_HW_VLAN_TX +-#define BCM_VLAN 1 +-#endif +- +- + #define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff) + #define U64_HI(x) (u32)(((u64)(x)) >> 32) + #define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) +@@ -804,6 +804,8 @@ struct bnx2x { + #define TPA_ENABLE_FLAG 0x80 + #define NO_MCP_FLAG 0x100 + #define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG) ++#define HW_VLAN_TX_FLAG 0x400 ++#define HW_VLAN_RX_FLAG 0x800 + + int func; + #define BP_PORT(bp) (bp->func % PORT_MAX) +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -38,9 +38,7 @@ + #include + #include + #include +-#ifdef NETIF_F_HW_VLAN_TX +- #include +-#endif ++#include + #include + #include + #include +@@ -1283,6 +1281,13 @@ static void bnx2x_tpa_stop(struct bnx2x + if (likely(new_skb)) { + /* fix ip xsum and give it to the stack */ + /* (no need to map the new skb) */ ++#ifdef BCM_VLAN ++ int is_vlan_cqe = ++ (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & ++ PARSING_FLAGS_VLAN); ++ int is_not_hwaccel_vlan_cqe = ++ (is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG))); ++#endif + + prefetch(skb); + prefetch(((char *)(skb)) + 128); +@@ -1307,6 +1312,12 @@ static void bnx2x_tpa_stop(struct bnx2x + struct iphdr *iph; + + iph = (struct iphdr *)skb->data; ++#ifdef BCM_VLAN ++ /* If there is no Rx VLAN offloading - ++ take VLAN tag into an account */ ++ if (unlikely(is_not_hwaccel_vlan_cqe)) ++ iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN); ++#endif + iph->check = 0; + iph->check = ip_fast_csum((u8 *)iph, iph->ihl); + } +@@ -1314,9 +1325,8 @@ static void bnx2x_tpa_stop(struct bnx2x + if (!bnx2x_fill_frag_skb(bp, fp, skb, + &cqe->fast_path_cqe, cqe_idx)) { + #ifdef BCM_VLAN +- if ((bp->vlgrp != NULL) && +- (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & +- PARSING_FLAGS_VLAN)) ++ if ((bp->vlgrp != NULL) && is_vlan_cqe && ++ (!is_not_hwaccel_vlan_cqe)) + vlan_hwaccel_receive_skb(skb, bp->vlgrp, + le16_to_cpu(cqe->fast_path_cqe. + vlan_tag)); +@@ -1561,7 +1571,7 @@ reuse_rx: + } + + #ifdef BCM_VLAN +- if ((bp->vlgrp != NULL) && ++ if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) && + (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & + PARSING_FLAGS_VLAN)) + vlan_hwaccel_receive_skb(skb, bp->vlgrp, +@@ -4541,7 +4551,7 @@ static void bnx2x_set_client_config(stru + tstorm_client.config_flags = + TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; + #ifdef BCM_VLAN +- if (bp->rx_mode && bp->vlgrp) { ++ if (bp->rx_mode && bp->vlgrp && (bp->flags & HW_VLAN_RX_FLAG)) { + tstorm_client.config_flags |= + TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE; + DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); +@@ -9571,11 +9581,14 @@ static int bnx2x_start_xmit(struct sk_bu + "sending pkt %u @%p next_idx %u bd %u @%p\n", + pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd); + +- if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb)) { ++#ifdef BCM_VLAN ++ if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) && ++ (bp->flags & HW_VLAN_TX_FLAG)) { + tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; + vlan_off += 4; + } else ++#endif + tx_bd->vlan = cpu_to_le16(pkt_prod); + + if (xmit_type) { +@@ -10024,6 +10037,16 @@ static void bnx2x_vlan_rx_register(struc + struct bnx2x *bp = netdev_priv(dev); + + bp->vlgrp = vlgrp; ++ ++ /* Set flags according to the required capabilities */ ++ bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG); ++ ++ if (dev->features & NETIF_F_HW_VLAN_TX) ++ bp->flags |= HW_VLAN_TX_FLAG; ++ ++ if (dev->features & NETIF_F_HW_VLAN_RX) ++ bp->flags |= HW_VLAN_RX_FLAG; ++ + if (netif_running(dev)) + bnx2x_set_client_config(bp); + } +@@ -10175,6 +10198,7 @@ static int __devinit bnx2x_init_dev(stru + dev->features |= NETIF_F_HIGHDMA; + #ifdef BCM_VLAN + dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); ++ bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG); + #endif + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + dev->features |= NETIF_F_TSO6; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Version-update.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Version-update.patch new file mode 100644 index 000000000..ec2ce680c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Version-update.patch @@ -0,0 +1,75 @@ +From d05c26ce690e867aabfc7d708d481e0f86f23496 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Sat, 17 Jan 2009 23:26:13 -0800 +Subject: bnx2x: Version update +Acked-by: Karsten Keil +Reference: bnc#472500 + +Updating the version and the year of updated files + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x.h | 2 +- + drivers/net/bnx2x_link.c | 2 +- + drivers/net/bnx2x_main.c | 6 +++--- + drivers/net/bnx2x_reg.h | 2 +- + 4 files changed, 6 insertions(+), 6 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h +@@ -1,6 +1,6 @@ + /* bnx2x.h: Broadcom Everest network driver. + * +- * Copyright (c) 2007-2008 Broadcom Corporation ++ * Copyright (c) 2007-2009 Broadcom Corporation + * + * 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 +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_link.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_link.c +@@ -1,4 +1,4 @@ +-/* Copyright 2008 Broadcom Corporation ++/* Copyright 2008-2009 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -1,6 +1,6 @@ + /* bnx2x_main.c: Broadcom Everest network driver. + * +- * Copyright (c) 2007-2008 Broadcom Corporation ++ * Copyright (c) 2007-2009 Broadcom Corporation + * + * 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 +@@ -57,8 +57,8 @@ + #include "bnx2x.h" + #include "bnx2x_init.h" + +-#define DRV_MODULE_VERSION "1.45.23" +-#define DRV_MODULE_RELDATE "2008/11/03" ++#define DRV_MODULE_VERSION "1.45.24" ++#define DRV_MODULE_RELDATE "2009/01/14" + #define BNX2X_BC_VER 0x040200 + + /* Time in jiffies before concluding the transmitter is hung */ +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_reg.h +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_reg.h ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_reg.h +@@ -1,6 +1,6 @@ + /* bnx2x_reg.h: Broadcom Everest network driver. + * +- * Copyright (c) 2007-2008 Broadcom Corporation ++ * Copyright (c) 2007-2009 Broadcom Corporation + * + * 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 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Version.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Version.patch new file mode 100644 index 000000000..a648f9a0a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Version.patch @@ -0,0 +1,28 @@ +From 5422a2257350d984094e655b2361abed51a9ddc1 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 06:01:37 +0000 +Subject: bnx2x: Version +Acked-by: Karsten Keil +Reference: bnc#472500 + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -57,8 +57,8 @@ + #include "bnx2x.h" + #include "bnx2x_init.h" + +-#define DRV_MODULE_VERSION "1.45.24" +-#define DRV_MODULE_RELDATE "2009/01/14" ++#define DRV_MODULE_VERSION "1.45.25" ++#define DRV_MODULE_RELDATE "2009/01/22" + #define BNX2X_BC_VER 0x040200 + + /* Time in jiffies before concluding the transmitter is hung */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Wrong-HDR-offset-in-CAM.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Wrong-HDR-offset-in-CAM.patch new file mode 100644 index 000000000..ebb11e0f2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-Wrong-HDR-offset-in-CAM.patch @@ -0,0 +1,50 @@ +From af2464011f0954785687071b298f066f6cbb1c84 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:43:59 +0000 +Subject: bnx2x: Wrong HDR offset in CAM +Acked-by: Karsten Keil +Reference: bnc#472500 + +Has a negative side effect when sending MAC update with no content (as done in +the self-test) + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 9 ++++++--- + 1 files changed, 6 insertions(+), 3 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -6147,7 +6147,7 @@ static void bnx2x_set_mac_addr_e1(struct + * multicast 64-127:port0 128-191:port1 + */ + config->hdr.length_6b = 2; +- config->hdr.offset = port ? 31 : 0; ++ config->hdr.offset = port ? 32 : 0; + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + +@@ -8914,7 +8914,10 @@ static int bnx2x_test_intr(struct bnx2x + return -ENODEV; + + config->hdr.length_6b = 0; +- config->hdr.offset = 0; ++ if (CHIP_IS_E1(bp)) ++ config->hdr.offset = (BP_PORT(bp) ? 32 : 0); ++ else ++ config->hdr.offset = BP_FUNC(bp); + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + +@@ -9867,7 +9870,7 @@ static void bnx2x_set_rx_mode(struct net + for (; i < old; i++) { + if (CAM_IS_INVALID(config-> + config_table[i])) { +- i--; /* already invalidated */ ++ /* already invalidated */ + break; + } + /* invalidate */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-eeh.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-eeh.patch new file mode 100644 index 000000000..b5f842630 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-eeh.patch @@ -0,0 +1,188 @@ +From: Yitchak Gertner +Subject: bnx2x: EEH recovery fix +Acked-by: Karsten Keil +Reference: bnc#433875 + + +When EEH detects an i/o error it resets the device thus it cannot be accessed. + In this case the driver needs to unload its interface only with OS, kernel and + network stack but not with the device. + After successful recovery, the driver can load normally. + + Signed-off-by: Yitchak Gertner + Signed-off-by: Eilon Greenstein + Signed-off-by: David S. Miller + + +--- + drivers/net/bnx2x_main.c | 95 +++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 83 insertions(+), 12 deletions(-) + +--- a/drivers/net/bnx2x_main.c ++++ b/drivers/net/bnx2x_main.c +@@ -59,8 +59,8 @@ + #include "bnx2x.h" + #include "bnx2x_init.h" + +-#define DRV_MODULE_VERSION "1.45.21" +-#define DRV_MODULE_RELDATE "2008/09/03" ++#define DRV_MODULE_VERSION "1.45.22" ++#define DRV_MODULE_RELDATE "2008/09/09" + #define BNX2X_BC_VER 0x040200 + + /* Time in jiffies before concluding the transmitter is hung */ +@@ -649,15 +649,16 @@ static void bnx2x_int_disable(struct bnx + BNX2X_ERR("BUG! proper val not read from IGU!\n"); + } + +-static void bnx2x_int_disable_sync(struct bnx2x *bp) ++static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) + { + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + int i; + + /* disable interrupt handling */ + atomic_inc(&bp->intr_sem); +- /* prevent the HW from sending interrupts */ +- bnx2x_int_disable(bp); ++ if (disable_hw) ++ /* prevent the HW from sending interrupts */ ++ bnx2x_int_disable(bp); + + /* make sure all ISRs are done */ + if (msix) { +@@ -6086,9 +6087,9 @@ static void bnx2x_netif_start(struct bnx + } + } + +-static void bnx2x_netif_stop(struct bnx2x *bp) ++static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) + { +- bnx2x_int_disable_sync(bp); ++ bnx2x_int_disable_sync(bp, disable_hw); + if (netif_running(bp->dev)) { + bnx2x_napi_disable(bp); + netif_tx_disable(bp->dev); +@@ -6475,7 +6476,7 @@ load_rings_free: + for_each_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); + load_int_disable: +- bnx2x_int_disable_sync(bp); ++ bnx2x_int_disable_sync(bp, 1); + /* Release IRQs */ + bnx2x_free_irq(bp); + load_error: +@@ -6651,7 +6652,7 @@ static int bnx2x_nic_unload(struct bnx2x + bp->rx_mode = BNX2X_RX_MODE_NONE; + bnx2x_set_storm_rx_mode(bp); + +- bnx2x_netif_stop(bp); ++ bnx2x_netif_stop(bp, 1); + if (!netif_running(bp->dev)) + bnx2x_napi_disable(bp); + del_timer_sync(&bp->timer); +@@ -8796,7 +8797,7 @@ static int bnx2x_test_loopback(struct bn + if (!netif_running(bp->dev)) + return BNX2X_LOOPBACK_FAILED; + +- bnx2x_netif_stop(bp); ++ bnx2x_netif_stop(bp, 1); + + if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) { + DP(NETIF_MSG_PROBE, "MAC loopback failed\n"); +@@ -10351,6 +10352,74 @@ static int bnx2x_resume(struct pci_dev * + return rc; + } + ++static int bnx2x_eeh_nic_unload(struct bnx2x *bp) ++{ ++ int i; ++ ++ bp->state = BNX2X_STATE_ERROR; ++ ++ bp->rx_mode = BNX2X_RX_MODE_NONE; ++ ++ bnx2x_netif_stop(bp, 0); ++ ++ del_timer_sync(&bp->timer); ++ bp->stats_state = STATS_STATE_DISABLED; ++ DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n"); ++ ++ /* Release IRQs */ ++ bnx2x_free_irq(bp); ++ ++ if (CHIP_IS_E1(bp)) { ++ struct mac_configuration_cmd *config = ++ bnx2x_sp(bp, mcast_config); ++ ++ for (i = 0; i < config->hdr.length_6b; i++) ++ CAM_INVALIDATE(config->config_table[i]); ++ } ++ ++ /* Free SKBs, SGEs, TPA pool and driver internals */ ++ bnx2x_free_skbs(bp); ++ for_each_queue(bp, i) ++ bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); ++ bnx2x_free_mem(bp); ++ ++ bp->state = BNX2X_STATE_CLOSED; ++ ++ netif_carrier_off(bp->dev); ++ ++ return 0; ++} ++ ++static void bnx2x_eeh_recover(struct bnx2x *bp) ++{ ++ u32 val; ++ ++ mutex_init(&bp->port.phy_mutex); ++ ++ bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); ++ bp->link_params.shmem_base = bp->common.shmem_base; ++ BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); ++ ++ if (!bp->common.shmem_base || ++ (bp->common.shmem_base < 0xA0000) || ++ (bp->common.shmem_base >= 0xC0000)) { ++ BNX2X_DEV_INFO("MCP not active\n"); ++ bp->flags |= NO_MCP_FLAG; ++ return; ++ } ++ ++ val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); ++ if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) ++ != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) ++ BNX2X_ERR("BAD MCP validity signature\n"); ++ ++ if (!BP_NOMCP(bp)) { ++ bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header) ++ & DRV_MSG_SEQ_NUMBER_MASK); ++ BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); ++ } ++} ++ + /** + * bnx2x_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device +@@ -10370,7 +10439,7 @@ static pci_ers_result_t bnx2x_io_error_d + netif_device_detach(dev); + + if (netif_running(dev)) +- bnx2x_nic_unload(bp, UNLOAD_CLOSE); ++ bnx2x_eeh_nic_unload(bp); + + pci_disable_device(pdev); + +@@ -10425,8 +10494,10 @@ static void bnx2x_io_resume(struct pci_d + + rtnl_lock(); + ++ bnx2x_eeh_recover(bp); ++ + if (netif_running(dev)) +- bnx2x_nic_load(bp, LOAD_OPEN); ++ bnx2x_nic_load(bp, LOAD_NORMAL); + + netif_device_attach(dev); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-loopback-test-failure.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-loopback-test-failure.patch new file mode 100644 index 000000000..fad466b54 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-loopback-test-failure.patch @@ -0,0 +1,64 @@ +From 3910c8ae44c59cebed721e33aa496f0a385b4e03 Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Thu, 22 Jan 2009 06:01:32 +0000 +Subject: bnx2x: loopback test failure +Acked-by: Karsten Keil +Reference: bnc#472500 + +A link change interrupt might be queued and activated after the loopback was set +and it will cause the loopback to fail. The PHY lock should be kept until the +loopback test is over. + +That implies that the bnx2x_test_link should used within the loopback function +and not bnx2x_wait_for_link since that function also takes the PHY link + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 13 +++++++------ + 1 files changed, 7 insertions(+), 6 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -8753,18 +8753,17 @@ static int bnx2x_run_loopback(struct bnx + + if (loopback_mode == BNX2X_MAC_LOOPBACK) { + bp->link_params.loopback_mode = LOOPBACK_BMAC; +- bnx2x_acquire_phy_lock(bp); + bnx2x_phy_init(&bp->link_params, &bp->link_vars); +- bnx2x_release_phy_lock(bp); + + } else if (loopback_mode == BNX2X_PHY_LOOPBACK) { ++ u16 cnt = 1000; + bp->link_params.loopback_mode = LOOPBACK_XGXS_10; +- bnx2x_acquire_phy_lock(bp); + bnx2x_phy_init(&bp->link_params, &bp->link_vars); +- bnx2x_release_phy_lock(bp); + /* wait until link state is restored */ +- bnx2x_wait_for_link(bp, link_up); +- ++ if (link_up) ++ while (cnt-- && bnx2x_test_link(&bp->link_params, ++ &bp->link_vars)) ++ msleep(10); + } else + return -EINVAL; + +@@ -8871,6 +8870,7 @@ static int bnx2x_test_loopback(struct bn + return BNX2X_LOOPBACK_FAILED; + + bnx2x_netif_stop(bp, 1); ++ bnx2x_acquire_phy_lock(bp); + + if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) { + DP(NETIF_MSG_PROBE, "MAC loopback failed\n"); +@@ -8882,6 +8882,7 @@ static int bnx2x_test_loopback(struct bn + rc |= BNX2X_PHY_LOOPBACK_FAILED; + } + ++ bnx2x_release_phy_lock(bp); + bnx2x_netif_start(bp); + + return rc; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-tx_has_work-should-not-wait-for-FW.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-tx_has_work-should-not-wait-for-FW.patch new file mode 100644 index 000000000..9c4cf3b1c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-tx_has_work-should-not-wait-for-FW.patch @@ -0,0 +1,62 @@ +From e8b5fc514d1c7637cb4b8f77e7d8ac33ef66130c Mon Sep 17 00:00:00 2001 +From: Vladislav Zolotarov +Date: Mon, 26 Jan 2009 12:36:42 -0800 +Subject: bnx2x: tx_has_work should not wait for FW +Acked-by: Karsten Keil +Reference: bnc#472500 + +The current tx_has_work waited until all packets sent by the driver +are marked as completed by the FW. This is too greedy and it causes +the bnx2x_poll to spin in vain. The driver should only check that all +packets FW already completed are freed - only in unload flow the +driver should make sure that transmit queue is empty + +Signed-off-by: Vladislav Zolotarov +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +--- + drivers/net/bnx2x_main.c | 17 ++++++++++++----- + 1 files changed, 12 insertions(+), 5 deletions(-) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -57,8 +57,8 @@ + #include "bnx2x.h" + #include "bnx2x_init.h" + +-#define DRV_MODULE_VERSION "1.45.25" +-#define DRV_MODULE_RELDATE "2009/01/22" ++#define DRV_MODULE_VERSION "1.45.26" ++#define DRV_MODULE_RELDATE "2009/01/26" + #define BNX2X_BC_VER 0x040200 + + /* Time in jiffies before concluding the transmitter is hung */ +@@ -740,8 +740,15 @@ static inline int bnx2x_has_tx_work(stru + /* Tell compiler that status block fields can change */ + barrier(); + tx_cons_sb = le16_to_cpu(*fp->tx_cons_sb); +- return ((fp->tx_pkt_prod != tx_cons_sb) || +- (fp->tx_pkt_prod != fp->tx_pkt_cons)); ++ return (fp->tx_pkt_cons != tx_cons_sb); ++} ++ ++static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp) ++{ ++ /* Tell compiler that consumer and producer can change */ ++ barrier(); ++ return (fp->tx_pkt_prod != fp->tx_pkt_cons); ++ + } + + /* free skb in the packet ring at pos idx +@@ -6732,7 +6739,7 @@ static int bnx2x_nic_unload(struct bnx2x + + cnt = 1000; + smp_rmb(); +- while (bnx2x_has_tx_work(fp)) { ++ while (bnx2x_has_tx_work_unload(fp)) { + + bnx2x_tx_int(fp, 1000); + if (!cnt) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-version-update.patch b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-version-update.patch new file mode 100644 index 000000000..24572883e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/bnx2x-version-update.patch @@ -0,0 +1,34 @@ +From ca8eac55fa554043c57fd18d595ca356e752833e Mon Sep 17 00:00:00 2001 +From: Eilon Greenstein +Date: Mon, 3 Nov 2008 16:46:58 -0800 +Subject: bnx2x: Version Update +Patch-mainline: 2.6.28 +References: bnc#439679 + +From: Eilon Greenstein + +commit ca8eac55fa554043c57fd18d595ca356e752833e upstream. + +Updating the version + +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/bnx2x_main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/bnx2x_main.c ++++ b/drivers/net/bnx2x_main.c +@@ -59,8 +59,8 @@ + #include "bnx2x.h" + #include "bnx2x_init.h" + +-#define DRV_MODULE_VERSION "1.45.22" +-#define DRV_MODULE_RELDATE "2008/09/09" ++#define DRV_MODULE_VERSION "1.45.23" ++#define DRV_MODULE_RELDATE "2008/11/03" + #define BNX2X_BC_VER 0x040200 + + /* Time in jiffies before concluding the transmitter is hung */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/broadcom-Add-support-for-the-57780-integrated-PHY.patch b/src/patches/suse-2.6.27.31/patches.drivers/broadcom-Add-support-for-the-57780-integrated-PHY.patch new file mode 100644 index 000000000..b6353bf44 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/broadcom-Add-support-for-the-57780-integrated-PHY.patch @@ -0,0 +1,103 @@ +From fe9ea211b215172aca41dff8cc454f60e3346739 Mon Sep 17 00:00:00 2001 +From: root +Date: Fri, 3 Oct 2008 09:59:42 -0700 +Subject: [PATCH 2/2] broadcom: Add support for the 57780 integrated PHY +Acked-by: Karsten Keil +Reference: bnc#434147 + +This patch adds support for the 57780 integrated PHY. +--- + drivers/net/phy/broadcom.c | 24 ++++++++++++++++++++++-- + drivers/net/tg3.c | 9 ++++++++- + drivers/net/tg3.h | 5 +++-- + 3 files changed, 33 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c +index 4b4dc98..ad5c4f7 100644 +--- a/drivers/net/phy/broadcom.c ++++ b/drivers/net/phy/broadcom.c +@@ -402,14 +402,29 @@ static struct phy_driver bcm5481_driver = { + }; + + static struct phy_driver bcm5482_driver = { ++ .phy_id = 0x03625d90, ++ .phy_id_mask = 0xfffffff0, ++ .name = "Broadcom BCM57780", ++ .features = PHY_GBIT_FEATURES | ++ SUPPORTED_Pause | SUPPORTED_Asym_Pause, ++ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, ++ .config_init = bcm5482_config_init, ++ .config_aneg = genphy_config_aneg, ++ .read_status = bcm5482_read_status, ++ .ack_interrupt = bcm54xx_ack_interrupt, ++ .config_intr = bcm54xx_config_intr, ++ .driver = { .owner = THIS_MODULE }, ++}; ++ ++static struct phy_driver bcm57780_driver = { + .phy_id = 0x0143bcb0, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM5482", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, +- .config_init = bcm5482_config_init, ++ .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, +- .read_status = bcm5482_read_status, ++ .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, +@@ -437,8 +452,13 @@ static int __init broadcom_init(void) + ret = phy_driver_register(&bcm5482_driver); + if (ret) + goto out_5482; ++ ret = phy_driver_register(&bcm57780_driver); ++ if (ret) ++ goto out_57780; + return ret; + ++out_57780: ++ phy_driver_unregister(&bcm5482_driver); + out_5482: + phy_driver_unregister(&bcm5481_driver); + out_5481: +diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c +index 7188675..43691c6 100644 +--- a/drivers/net/tg3.c ++++ b/drivers/net/tg3.c +@@ -994,7 +994,14 @@ static int tg3_mdio_init(struct tg3 *tp) + + phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + +- switch (phydev->phy_id) { ++if(!phydev || !phydev->drv) ++ return -1; ++ ++ switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { ++ case TG3_PHY_ID_BCM57780: ++ phydev->interface = PHY_INTERFACE_MODE_GMII; ++ phydev->dev_flags = PHY_BRCM_WIRESPEED_ENABLE; ++ break; + case TG3_PHY_ID_BCM50610: + phydev->interface = PHY_INTERFACE_MODE_RGMII; + if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) +diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h +index 06859d1..fc313a4 100644 +--- a/drivers/net/tg3.h ++++ b/drivers/net/tg3.h +@@ -2592,8 +2592,9 @@ struct tg3 { + #define PHY_REV_BCM5401_B2 0x3 + #define PHY_REV_BCM5401_C0 0x6 + #define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */ +-#define TG3_PHY_ID_BCM50610 0x143bd60 +-#define TG3_PHY_ID_BCMAC131 0x143bc70 ++#define TG3_PHY_ID_BCM50610 0x0143bd60 ++#define TG3_PHY_ID_BCMAC131 0x0143bc70 ++#define TG3_PHY_ID_BCM57780 0x03625d90 + + + u32 led_ctrl; +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cciss-driver-panic-on-volume-delete b/src/patches/suse-2.6.27.31/patches.drivers/cciss-driver-panic-on-volume-delete new file mode 100644 index 000000000..316d707e7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cciss-driver-panic-on-volume-delete @@ -0,0 +1,69 @@ +Subject: cciss driver may panic if a logical volume is deleted +From: Hannes Reinecke +Date: Wed Jan 7 12:32:12 2009 +0100: +References: bnc#459553 + +If the customer uses either ACUXE or hpacucli to delete a logical volume the +Smart Array driver may panic. If the logical volume is in the middle of an +array the driver will panic every time. + +Signed-off-by: Mike Miller +Signed-off-by: Hannes Reinecke + +--- + drivers/block/cciss.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/drivers/block/cciss.c ++++ b/drivers/block/cciss.c +@@ -164,7 +164,7 @@ static int cciss_getgeo(struct block_dev + + static int cciss_revalidate(struct gendisk *disk); + static int rebuild_lun_table(ctlr_info_t *h, int first_time); +-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, ++static int deregister_disk(ctlr_info_t *h, int drv_index, + int clear_all); + + static void cciss_read_capacity(int ctlr, int logvol, int withirq, +@@ -1491,8 +1491,7 @@ static void cciss_update_drive_info(int + * which keeps the interrupt handler from starting + * the queue. + */ +- ret = deregister_disk(h->gendisk[drv_index], +- &h->drv[drv_index], 0); ++ ret = deregister_disk(h, drv_index, 0); + h->drv[drv_index].busy_configuring = 0; + } + +@@ -1710,8 +1709,7 @@ static int rebuild_lun_table(ctlr_info_t + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + h->drv[i].busy_configuring = 1; + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); +- return_code = deregister_disk(h->gendisk[i], +- &h->drv[i], 1); ++ return_code = deregister_disk(h, i, 1); + h->drv[i].busy_configuring = 0; + } + } +@@ -1781,15 +1779,19 @@ mem_msg: + * the highest_lun should be left unchanged and the LunID + * should not be cleared. + */ +-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, ++static int deregister_disk(ctlr_info_t *h, int drv_index, + int clear_all) + { + int i; +- ctlr_info_t *h = get_host(disk); ++ struct gendisk *disk; ++ drive_info_struct *drv; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + ++ drv = &h->drv[drv_index]; ++ disk = h->gendisk[drv_index]; ++ + /* make sure logical volume is NOT is use */ + if (clear_all || (h->gendisk[0] == disk)) { + if (drv->usage_count > 1) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cciss-ignore-stale-commands b/src/patches/suse-2.6.27.31/patches.drivers/cciss-ignore-stale-commands new file mode 100644 index 000000000..837eb444b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cciss-ignore-stale-commands @@ -0,0 +1,231 @@ +From: Hannes Reinecke +Subject: cciss: Ignore stale commands after reboot +References: bnc#513437 +Patch-Mainline: yes + +When doing an unexpected shutdown like kexec the cciss +firmware might still have some commands in flight, which +it is trying to complete. +The driver is doing it's best on resetting the HBA, +but sadly there's a firmware issue causing the firmware +_not_ to abort or drop old commands. +So the firmware will send us commands which we haven't +accounted for, causing the driver to panic. + +This patch also updates the queue handling to using +kernel-provided hashed lists; without it we wouldn't +be able to detect stale commands at all. +Queue handling is backported from mainline. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c +index d7ec8e4..28d3f3d 100644 +--- a/drivers/block/cciss.c ++++ b/drivers/block/cciss.c +@@ -214,31 +214,27 @@ static struct block_device_operations cciss_fops = { + /* + * Enqueuing and dequeuing functions for cmdlists. + */ +-static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) ++static inline void addQ(struct hlist_head *list, CommandList_struct *c) + { +- if (*Qptr == NULL) { +- *Qptr = c; +- c->next = c->prev = c; +- } else { +- c->prev = (*Qptr)->prev; +- c->next = (*Qptr); +- (*Qptr)->prev->next = c; +- (*Qptr)->prev = c; +- } ++ hlist_add_head(&c->list, list); + } + +-static inline CommandList_struct *removeQ(CommandList_struct **Qptr, +- CommandList_struct *c) ++static inline void removeQ(CommandList_struct *c) + { +- if (c && c->next != c) { +- if (*Qptr == c) +- *Qptr = c->next; +- c->prev->next = c->next; +- c->next->prev = c->prev; +- } else { +- *Qptr = NULL; ++ /* ++ * After kexec/dump some commands might still ++ * be in flight, which the firmware will try ++ * to complete. Resetting the firmware doesn't work ++ * with old fw revisions, so we have to mark ++ * them off as 'stale' to prevent the driver from ++ * falling over. ++ */ ++ if (unlikely(hlist_unhashed(&c->list))) { ++ c->cmd_type = CMD_MSG_STALE; ++ return; + } +- return c; ++ ++ hlist_del_init(&c->list); + } + + #include "cciss_scsi.c" /* For SCSI tape support */ +@@ -505,6 +501,7 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool) + c->cmdindex = i; + } + ++ INIT_HLIST_NODE(&c->list); + c->busaddr = (__u32) cmd_dma_handle; + temp64.val = (__u64) err_dma_handle; + c->ErrDesc.Addr.lower = temp64.val32.lower; +@@ -2549,7 +2548,8 @@ static void start_io(ctlr_info_t *h) + { + CommandList_struct *c; + +- while ((c = h->reqQ) != NULL) { ++ while (!hlist_empty(&h->reqQ)) { ++ c = hlist_entry(h->reqQ.first, CommandList_struct, list); + /* can't do anything if fifo is full */ + if ((h->access.fifo_full(h))) { + printk(KERN_WARNING "cciss: fifo full\n"); +@@ -2557,14 +2557,14 @@ static void start_io(ctlr_info_t *h) + } + + /* Get the first entry from the Request Q */ +- removeQ(&(h->reqQ), c); ++ removeQ(c); + h->Qdepth--; + + /* Tell the controller execute command */ + h->access.submit_command(h, c); + + /* Put job onto the completed Q */ +- addQ(&(h->cmpQ), c); ++ addQ(&h->cmpQ, c); + } + } + +@@ -2577,7 +2577,7 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + + /* add it to software queue and then send it to the controller */ +- addQ(&(h->reqQ), c); ++ addQ(&h->reqQ, c); + h->Qdepth++; + if (h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; +@@ -2898,7 +2898,7 @@ static void do_cciss_request(struct request_queue *q) + + spin_lock_irq(q->queue_lock); + +- addQ(&(h->reqQ), c); ++ addQ(&h->reqQ, c); + h->Qdepth++; + if (h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; +@@ -2986,16 +2986,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) + a = c->busaddr; + + } else { ++ struct hlist_node *tmp; ++ + a &= ~3; +- if ((c = h->cmpQ) == NULL) { +- printk(KERN_WARNING +- "cciss: Completion of %08x ignored\n", +- a1); +- continue; +- } +- while (c->busaddr != a) { +- c = c->next; +- if (c == h->cmpQ) ++ c = NULL; ++ hlist_for_each_entry(c, tmp, &h->cmpQ, list) { ++ if (c->busaddr == a) + break; + } + } +@@ -3003,8 +2999,8 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) + * If we've found the command, take it off the + * completion Q and free it + */ +- if (c->busaddr == a) { +- removeQ(&h->cmpQ, c); ++ if (c && c->busaddr == a) { ++ removeQ(c); + if (c->cmd_type == CMD_RWREQ) { + complete_command(h, c, 0); + } else if (c->cmd_type == CMD_IOCTL_PEND) { +@@ -3423,6 +3419,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, + return -1; + + hba[i]->busy_initializing = 1; ++ INIT_HLIST_HEAD(&hba[i]->cmpQ); ++ INIT_HLIST_HEAD(&hba[i]->reqQ); + + if (cciss_pci_init(hba[i], pdev) != 0) + goto clean1; +@@ -3730,16 +3728,19 @@ static void fail_all_cmds(unsigned long ctlr) + pci_disable_device(h->pdev); /* Make sure it is really dead. */ + + /* move everything off the request queue onto the completed queue */ +- while ((c = h->reqQ) != NULL) { +- removeQ(&(h->reqQ), c); ++ while (!hlist_empty(&h->reqQ)) { ++ c = hlist_entry(h->reqQ.first, CommandList_struct, list); ++ removeQ(c); + h->Qdepth--; +- addQ(&(h->cmpQ), c); ++ addQ(&h->cmpQ, c); + } + + /* Now, fail everything on the completed queue with a HW error */ +- while ((c = h->cmpQ) != NULL) { +- removeQ(&h->cmpQ, c); +- c->err_info->CommandStatus = CMD_HARDWARE_ERR; ++ while (!hlist_empty(&h->cmpQ)) { ++ c = hlist_entry(h->cmpQ.first, CommandList_struct, list); ++ removeQ(c); ++ if (c->cmd_type != CMD_MSG_STALE) ++ c->err_info->CommandStatus = CMD_HARDWARE_ERR; + if (c->cmd_type == CMD_RWREQ) { + complete_command(h, c, 0); + } else if (c->cmd_type == CMD_IOCTL_PEND) +diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h +index 24a7efa..15e2b84 100644 +--- a/drivers/block/cciss.h ++++ b/drivers/block/cciss.h +@@ -89,8 +89,8 @@ struct ctlr_info + struct access_method access; + + /* queue and queue Info */ +- CommandList_struct *reqQ; +- CommandList_struct *cmpQ; ++ struct hlist_head reqQ; ++ struct hlist_head cmpQ; + unsigned int Qdepth; + unsigned int maxQsinceinit; + unsigned int maxSG; +diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h +index 43bf559..e4ca588 100644 +--- a/drivers/block/cciss_cmd.h ++++ b/drivers/block/cciss_cmd.h +@@ -249,6 +249,7 @@ typedef struct _ErrorInfo_struct { + #define CMD_SCSI 0x03 + #define CMD_MSG_DONE 0x04 + #define CMD_MSG_TIMEOUT 0x05 ++#define CMD_MSG_STALE 0xff + + /* This structure needs to be divisible by 8 for new + * indexing method. +@@ -265,8 +266,7 @@ typedef struct _CommandList_struct { + int ctlr; + int cmd_type; + long cmdindex; +- struct _CommandList_struct *prev; +- struct _CommandList_struct *next; ++ struct hlist_node list; + struct request * rq; + struct completion *waiting; + int retry_count; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_add_cpu_number_paramater_1.patch b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_add_cpu_number_paramater_1.patch new file mode 100644 index 000000000..0c76a0a71 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_add_cpu_number_paramater_1.patch @@ -0,0 +1,111 @@ +From: Venkatesh Pallipadi +Subject: cpufreq: Add a cpu parameter to __cpufreq_driver_getavg(). + +Add a cpu parameter to __cpufreq_driver_getavg(). This is needed for software +cpufreq coordination where policy->cpu may not be same as the CPU on which we +want to getavg frequency. + +A follow-on patch will use this parameter to getavg freq from all cpus +in policy->cpus. + +Change since last patch. Fix the offline/online and suspend/resume +oops reported by Youquan Song + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Thomas Renninger + +--- + arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 5 +++-- + drivers/cpufreq/cpufreq.c | 6 +++--- + drivers/cpufreq/cpufreq_ondemand.c | 2 +- + include/linux/cpufreq.h | 7 +++++-- + 4 files changed, 12 insertions(+), 8 deletions(-) + +Index: cpufreq.git/drivers/cpufreq/cpufreq.c +=================================================================== +--- cpufreq.git.orig/drivers/cpufreq/cpufreq.c 2008-08-04 10:28:26.000000000 -0700 ++++ cpufreq.git/drivers/cpufreq/cpufreq.c 2008-08-04 10:31:27.000000000 -0700 +@@ -1485,7 +1485,7 @@ int cpufreq_driver_target(struct cpufreq + } + EXPORT_SYMBOL_GPL(cpufreq_driver_target); + +-int __cpufreq_driver_getavg(struct cpufreq_policy *policy) ++int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) + { + int ret = 0; + +@@ -1493,8 +1493,8 @@ int __cpufreq_driver_getavg(struct cpufr + if (!policy) + return -EINVAL; + +- if (cpu_online(policy->cpu) && cpufreq_driver->getavg) +- ret = cpufreq_driver->getavg(policy->cpu); ++ if (cpu_online(cpu) && cpufreq_driver->getavg) ++ ret = cpufreq_driver->getavg(policy, cpu); + + cpufreq_cpu_put(policy); + return ret; +Index: cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- cpufreq.git.orig/drivers/cpufreq/cpufreq_ondemand.c 2008-08-04 10:28:26.000000000 -0700 ++++ cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c 2008-08-04 10:31:27.000000000 -0700 +@@ -415,7 +415,7 @@ static void dbs_check_cpu(struct cpu_dbs + if (load < (dbs_tuners_ins.up_threshold - 10)) { + unsigned int freq_next, freq_cur; + +- freq_cur = __cpufreq_driver_getavg(policy); ++ freq_cur = __cpufreq_driver_getavg(policy, policy->cpu); + if (!freq_cur) + freq_cur = policy->cur; + +Index: cpufreq.git/include/linux/cpufreq.h +=================================================================== +--- cpufreq.git.orig/include/linux/cpufreq.h 2008-08-04 10:28:26.000000000 -0700 ++++ cpufreq.git/include/linux/cpufreq.h 2008-08-04 10:31:27.000000000 -0700 +@@ -187,7 +187,8 @@ extern int __cpufreq_driver_target(struc + unsigned int relation); + + +-extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy); ++extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy, ++ unsigned int cpu); + + int cpufreq_register_governor(struct cpufreq_governor *governor); + void cpufreq_unregister_governor(struct cpufreq_governor *governor); +@@ -226,7 +227,9 @@ struct cpufreq_driver { + unsigned int (*get) (unsigned int cpu); + + /* optional */ +- unsigned int (*getavg) (unsigned int cpu); ++ unsigned int (*getavg) (struct cpufreq_policy *policy, ++ unsigned int cpu); ++ + int (*exit) (struct cpufreq_policy *policy); + int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg); + int (*resume) (struct cpufreq_policy *policy); +Index: cpufreq.git/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +=================================================================== +--- cpufreq.git.orig/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2008-08-04 10:28:26.000000000 -0700 ++++ cpufreq.git/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2008-08-04 10:31:27.000000000 -0700 +@@ -256,7 +256,8 @@ static u32 get_cur_val(const cpumask_t * + * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and + * no meaning should be associated with absolute values of these MSRs. + */ +-static unsigned int get_measured_perf(unsigned int cpu) ++static unsigned int get_measured_perf(struct cpufreq_policy *policy, ++ unsigned int cpu) + { + union { + struct { +@@ -326,7 +327,7 @@ static unsigned int get_measured_perf(un + + #endif + +- retval = per_cpu(drv_data, cpu)->max_freq * perf_percent / 100; ++ retval = per_cpu(drv_data, policy->cpu)->max_freq * perf_percent / 100; + + put_cpu(); + set_cpus_allowed_ptr(current, &saved_mask); + +-- + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_add_idle_microaccounting_6.patch b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_add_idle_microaccounting_6.patch new file mode 100644 index 000000000..c483bcbf6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_add_idle_microaccounting_6.patch @@ -0,0 +1,111 @@ +From: Venkatesh Pallipadi +Subject: cpufreq,ondemand: Use get_cpu_idle_time_us() to get micro-accounted idle information + +Use get_cpu_idle_time_us() to get micro-accounted idle information. +This enables ondemand to get more accurate idle and busy timings +than the jiffy based calculation. As a result, we can decrease +the ondemand safety gaurd band from 80-10 to 95-3. + +Results in more aggressive power savings. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Thomas Renninger + +--- + drivers/cpufreq/cpufreq_ondemand.c | 46 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 45 insertions(+), 1 deletion(-) + +Index: cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- cpufreq.git.orig/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:15.000000000 -0700 ++++ cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:22.000000000 -0700 +@@ -18,6 +18,9 @@ + #include + #include + #include ++#include ++#include ++#include + + /* + * dbs is used in this file as a shortform for demandbased switching +@@ -26,6 +29,8 @@ + + #define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) + #define DEF_FREQUENCY_UP_THRESHOLD (80) ++#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL (3) ++#define MICRO_FREQUENCY_UP_THRESHOLD (95) + #define MIN_FREQUENCY_UP_THRESHOLD (11) + #define MAX_FREQUENCY_UP_THRESHOLD (100) + +@@ -58,6 +63,7 @@ enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE} + struct cpu_dbs_info_s { + cputime64_t prev_cpu_idle; + cputime64_t prev_cpu_wall; ++ cputime64_t prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + struct cpufreq_frequency_table *freq_table; +@@ -97,7 +103,8 @@ static struct dbs_tuners { + .powersave_bias = 0, + }; + +-static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) ++static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, ++ cputime64_t *wall) + { + cputime64_t idle_time; + cputime64_t cur_wall_time; +@@ -123,6 +130,33 @@ static inline cputime64_t get_cpu_idle_t + return idle_time; + } + ++static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) ++{ ++ u64 idle_time = get_cpu_idle_time_us(cpu, wall); ++ ++ if (idle_time == -1ULL) ++ return get_cpu_idle_time_jiffy(cpu, wall); ++ ++ if (dbs_tuners_ins.ignore_nice) { ++ cputime64_t cur_nice; ++ unsigned long cur_nice_jiffies; ++ struct cpu_dbs_info_s *dbs_info; ++ ++ dbs_info = &per_cpu(cpu_dbs_info, cpu); ++ cur_nice = cputime64_sub(kstat_cpu(cpu).cpustat.nice, ++ dbs_info->prev_cpu_nice); ++ /* ++ * Assumption: nice time between sampling periods will be ++ * less than 2^32 jiffies for 32 bit sys ++ */ ++ cur_nice_jiffies = (unsigned long) ++ cputime64_to_jiffies64(cur_nice); ++ dbs_info->prev_cpu_nice = kstat_cpu(cpu).cpustat.nice; ++ return idle_time + jiffies_to_usecs(cur_nice_jiffies); ++ } ++ return idle_time; ++} ++ + /* + * Find right freq to be set now with powersave_bias on. + * Returns the freq_hi to be used right now and will set freq_hi_jiffies, +@@ -602,6 +636,16 @@ EXPORT_SYMBOL(cpufreq_gov_ondemand); + + static int __init cpufreq_gov_dbs_init(void) + { ++ cputime64_t wall; ++ u64 idle_time = get_cpu_idle_time_us(smp_processor_id(), &wall); ++ ++ if (idle_time != -1ULL) { ++ /* Idle micro accounting is supported. Use finer thresholds */ ++ dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; ++ dbs_tuners_ins.down_differential = ++ MICRO_FREQUENCY_DOWN_DIFFERENTIAL; ++ } ++ + kondemand_wq = create_workqueue("kondemand"); + if (!kondemand_wq) { + printk(KERN_ERR "Creation of kondemand failed\n"); + +-- diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_change_load_calculation_2.patch b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_change_load_calculation_2.patch new file mode 100644 index 000000000..57672051a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_change_load_calculation_2.patch @@ -0,0 +1,127 @@ +From: Venkatesh Pallipadi +Subject: cpufreq, ondemand: Change the load calculation, optimizing for dependent cpus + +Change the load calculation algorithm in ondemand to work well with software +coordination of frequency across the dependent cpus. + +Multiply individual CPU utilization with the average freq of that logical CPU +during the measurement interval (using getavg call). And find the max CPU +utilization number in terms of CPU freq. That number is then used to +get to the target freq for next sampling interval. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Thomas Renninger + +--- + drivers/cpufreq/cpufreq_ondemand.c | 65 +++++++++++++++++++------------------ + 1 file changed, 35 insertions(+), 30 deletions(-) + +Index: cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- cpufreq.git.orig/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:33:54.000000000 -0700 ++++ cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:01.000000000 -0700 +@@ -334,9 +334,7 @@ static struct attribute_group dbs_attr_g + + static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) + { +- unsigned int idle_ticks, total_ticks; +- unsigned int load = 0; +- cputime64_t cur_jiffies; ++ unsigned int max_load_freq; + + struct cpufreq_policy *policy; + unsigned int j; +@@ -346,13 +344,7 @@ static void dbs_check_cpu(struct cpu_dbs + + this_dbs_info->freq_lo = 0; + policy = this_dbs_info->cur_policy; +- cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); +- total_ticks = (unsigned int) cputime64_sub(cur_jiffies, +- this_dbs_info->prev_cpu_wall); +- this_dbs_info->prev_cpu_wall = get_jiffies_64(); + +- if (!total_ticks) +- return; + /* + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency +@@ -365,27 +357,46 @@ static void dbs_check_cpu(struct cpu_dbs + * 5% (default) of current frequency + */ + +- /* Get Idle Time */ +- idle_ticks = UINT_MAX; ++ /* Get Absolute Load - in terms of freq */ ++ max_load_freq = 0; ++ + for_each_cpu_mask_nr(j, policy->cpus) { +- cputime64_t total_idle_ticks; +- unsigned int tmp_idle_ticks; + struct cpu_dbs_info_s *j_dbs_info; ++ cputime64_t cur_wall_time, cur_idle_time; ++ unsigned int idle_time, wall_time; ++ unsigned int load, load_freq; ++ int freq_avg; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); +- total_idle_ticks = get_cpu_idle_time(j); +- tmp_idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks, ++ cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); ++ wall_time = (unsigned int) cputime64_sub(cur_wall_time, ++ j_dbs_info->prev_cpu_wall); ++ j_dbs_info->prev_cpu_wall = cur_wall_time; ++ ++ cur_idle_time = get_cpu_idle_time(j); ++ idle_time = (unsigned int) cputime64_sub(cur_idle_time, + j_dbs_info->prev_cpu_idle); +- j_dbs_info->prev_cpu_idle = total_idle_ticks; ++ j_dbs_info->prev_cpu_idle = cur_idle_time; ++ ++ if (unlikely(wall_time <= idle_time || ++ (cputime_to_msecs(wall_time) < ++ dbs_tuners_ins.sampling_rate / (2 * 1000)))) { ++ continue; ++ } ++ ++ load = 100 * (wall_time - idle_time) / wall_time; + +- if (tmp_idle_ticks < idle_ticks) +- idle_ticks = tmp_idle_ticks; ++ freq_avg = __cpufreq_driver_getavg(policy, j); ++ if (freq_avg <= 0) ++ freq_avg = policy->cur; ++ ++ load_freq = load * freq_avg; ++ if (load_freq > max_load_freq) ++ max_load_freq = load_freq; + } +- if (likely(total_ticks > idle_ticks)) +- load = (100 * (total_ticks - idle_ticks)) / total_ticks; + + /* Check for frequency increase */ +- if (load > dbs_tuners_ins.up_threshold) { ++ if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) { + /* if we are already at full speed then break out early */ + if (!dbs_tuners_ins.powersave_bias) { + if (policy->cur == policy->max) +@@ -412,15 +423,9 @@ static void dbs_check_cpu(struct cpu_dbs + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ +- if (load < (dbs_tuners_ins.up_threshold - 10)) { +- unsigned int freq_next, freq_cur; +- +- freq_cur = __cpufreq_driver_getavg(policy, policy->cpu); +- if (!freq_cur) +- freq_cur = policy->cur; +- +- freq_next = (freq_cur * load) / +- (dbs_tuners_ins.up_threshold - 10); ++ if (max_load_freq < (dbs_tuners_ins.up_threshold - 10) * policy->cur) { ++ unsigned int freq_next; ++ freq_next = max_load_freq / (dbs_tuners_ins.up_threshold - 10); + + if (!dbs_tuners_ins.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + +-- diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_changes_to_get_cpu_idle_us_5.patch b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_changes_to_get_cpu_idle_us_5.patch new file mode 100644 index 000000000..70497fe9f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_changes_to_get_cpu_idle_us_5.patch @@ -0,0 +1,61 @@ +From: Venkatesh Pallipadi +Subject: export get_cpu_idle_time_us() + +export get_cpu_idle_time_us() for it to be used in ondemand governor. +Last update time can be current time when the CPU is currently non-idle, +accounting for the busy time since last idle. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Thomas Renninger + +--- + include/linux/tick.h | 2 +- + kernel/time/tick-sched.c | 11 ++++++++++- + 2 files changed, 11 insertions(+), 2 deletions(-) + +Index: cpufreq.git/kernel/time/tick-sched.c +=================================================================== +--- cpufreq.git.orig/kernel/time/tick-sched.c 2008-07-31 10:04:55.000000000 -0700 ++++ cpufreq.git/kernel/time/tick-sched.c 2008-07-31 14:52:18.000000000 -0700 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include + +@@ -184,9 +185,17 @@ u64 get_cpu_idle_time_us(int cpu, u64 *l + { + struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + +- *last_update_time = ktime_to_us(ts->idle_lastupdate); ++ if (!tick_nohz_enabled) ++ return -1; ++ ++ if (ts->idle_active) ++ *last_update_time = ktime_to_us(ts->idle_lastupdate); ++ else ++ *last_update_time = ktime_to_us(ktime_get()); ++ + return ktime_to_us(ts->idle_sleeptime); + } ++EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); + + /** + * tick_nohz_stop_sched_tick - stop the idle tick from the idle task +Index: cpufreq.git/include/linux/tick.h +=================================================================== +--- cpufreq.git.orig/include/linux/tick.h 2008-07-31 10:04:54.000000000 -0700 ++++ cpufreq.git/include/linux/tick.h 2008-07-31 14:52:18.000000000 -0700 +@@ -123,7 +123,7 @@ static inline ktime_t tick_nohz_get_slee + return len; + } + static inline void tick_nohz_stop_idle(int cpu) { } +-static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return 0; } ++static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } + # endif /* !NO_HZ */ + + #endif + +-- diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_get_cpu_idle_time_changes_3.patch b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_get_cpu_idle_time_changes_3.patch new file mode 100644 index 000000000..5a47f9f58 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_get_cpu_idle_time_changes_3.patch @@ -0,0 +1,97 @@ +From: Venkatesh Pallipadi +Subject: cpufreq,ondemand: Prepare changes for doing micro-accounting + +Preparatory changes for doing idle micro-accounting in ondemand governor. +get_cpu_idle_time() gets extra parameter and returns idle time and also the +wall time that corresponds to the idle time measurement. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Thomas Renninger + +--- + drivers/cpufreq/cpufreq_ondemand.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +Index: cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- cpufreq.git.orig/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:01.000000000 -0700 ++++ cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:10.000000000 -0700 +@@ -94,13 +94,13 @@ static struct dbs_tuners { + .powersave_bias = 0, + }; + +-static inline cputime64_t get_cpu_idle_time(unsigned int cpu) ++static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) + { + cputime64_t idle_time; +- cputime64_t cur_jiffies; ++ cputime64_t cur_wall_time; + cputime64_t busy_time; + +- cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); ++ cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user, + kstat_cpu(cpu).cpustat.system); + +@@ -113,7 +113,10 @@ static inline cputime64_t get_cpu_idle_t + kstat_cpu(cpu).cpustat.nice); + } + +- idle_time = cputime64_sub(cur_jiffies, busy_time); ++ idle_time = cputime64_sub(cur_wall_time, busy_time); ++ if (wall) ++ *wall = cur_wall_time; ++ + return idle_time; + } + +@@ -277,8 +280,8 @@ static ssize_t store_ignore_nice_load(st + for_each_online_cpu(j) { + struct cpu_dbs_info_s *dbs_info; + dbs_info = &per_cpu(cpu_dbs_info, j); +- dbs_info->prev_cpu_idle = get_cpu_idle_time(j); +- dbs_info->prev_cpu_wall = get_jiffies_64(); ++ dbs_info->prev_cpu_idle = get_cpu_idle_time(j, ++ &dbs_info->prev_cpu_wall); + } + mutex_unlock(&dbs_mutex); + +@@ -368,21 +371,19 @@ static void dbs_check_cpu(struct cpu_dbs + int freq_avg; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); +- cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); ++ ++ cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); ++ + wall_time = (unsigned int) cputime64_sub(cur_wall_time, + j_dbs_info->prev_cpu_wall); + j_dbs_info->prev_cpu_wall = cur_wall_time; + +- cur_idle_time = get_cpu_idle_time(j); + idle_time = (unsigned int) cputime64_sub(cur_idle_time, + j_dbs_info->prev_cpu_idle); + j_dbs_info->prev_cpu_idle = cur_idle_time; + +- if (unlikely(wall_time <= idle_time || +- (cputime_to_msecs(wall_time) < +- dbs_tuners_ins.sampling_rate / (2 * 1000)))) { ++ if (unlikely(!wall_time || wall_time < idle_time)) + continue; +- } + + load = 100 * (wall_time - idle_time) / wall_time; + +@@ -531,8 +532,8 @@ static int cpufreq_governor_dbs(struct c + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + +- j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j); +- j_dbs_info->prev_cpu_wall = get_jiffies_64(); ++ j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, ++ &j_dbs_info->prev_cpu_wall); + } + this_dbs_info->cpu = cpu; + /* + +-- diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_parameterize_down_differential_4.patch b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_parameterize_down_differential_4.patch new file mode 100644 index 000000000..3b2e0af20 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cpufreq_parameterize_down_differential_4.patch @@ -0,0 +1,57 @@ +From: Venkatesh Pallipadi +Subject: cpufreq, ondemand: Use a parameter for down differential + +Use a parameter for down differential, instead of hardcoded 10%. Follow-on +patch changes the down-differential dynamically, based on whether +we are using idle micro-accounting or not. + +Signed-off-by: Venkatesh Pallipadi +Signed-off-by: Thomas Renninger + +--- + drivers/cpufreq/cpufreq_ondemand.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +Index: cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- cpufreq.git.orig/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:10.000000000 -0700 ++++ cpufreq.git/drivers/cpufreq/cpufreq_ondemand.c 2008-07-31 14:52:15.000000000 -0700 +@@ -24,6 +24,7 @@ + * It helps to keep variable names smaller, simpler + */ + ++#define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) + #define DEF_FREQUENCY_UP_THRESHOLD (80) + #define MIN_FREQUENCY_UP_THRESHOLD (11) + #define MAX_FREQUENCY_UP_THRESHOLD (100) +@@ -86,10 +87,12 @@ static struct workqueue_struct *kondeman + static struct dbs_tuners { + unsigned int sampling_rate; + unsigned int up_threshold; ++ unsigned int down_differential; + unsigned int ignore_nice; + unsigned int powersave_bias; + } dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, ++ .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, + .ignore_nice = 0, + .powersave_bias = 0, + }; +@@ -424,9 +427,13 @@ static void dbs_check_cpu(struct cpu_dbs + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ +- if (max_load_freq < (dbs_tuners_ins.up_threshold - 10) * policy->cur) { ++ if (max_load_freq < ++ (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * ++ policy->cur) { + unsigned int freq_next; +- freq_next = max_load_freq / (dbs_tuners_ins.up_threshold - 10); ++ freq_next = max_load_freq / ++ (dbs_tuners_ins.up_threshold - ++ dbs_tuners_ins.down_differential); + + if (!dbs_tuners_ins.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + +-- diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Add-1G-fiber-support b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Add-1G-fiber-support new file mode 100644 index 000000000..5a445b458 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Add-1G-fiber-support @@ -0,0 +1,296 @@ +Commit-Id: 0ce2f03bade2046d6eb6184d52d065688382d7bd +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:40:28 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: Add 1G fiber support +Reference: bnc#446739 + + +Add support for 1G optical Vitesse PHY. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +Index: linux-2.6.27/drivers/net/cxgb3/common.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/common.h ++++ linux-2.6.27/drivers/net/cxgb3/common.h +@@ -691,6 +691,7 @@ int t3_mdio_change_bits(struct cphy *phy + unsigned int set); + int t3_phy_reset(struct cphy *phy, int mmd, int wait); + int t3_phy_advertise(struct cphy *phy, unsigned int advert); ++int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert); + int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); + int t3_phy_lasi_intr_enable(struct cphy *phy); + int t3_phy_lasi_intr_disable(struct cphy *phy); +Index: linux-2.6.27/drivers/net/cxgb3/t3_hw.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/t3_hw.c ++++ linux-2.6.27/drivers/net/cxgb3/t3_hw.c +@@ -408,6 +408,29 @@ int t3_phy_advertise(struct cphy *phy, u + } + + /** ++ * t3_phy_advertise_fiber - set fiber PHY advertisement register ++ * @phy: the PHY to operate on ++ * @advert: bitmap of capabilities the PHY should advertise ++ * ++ * Sets a fiber PHY's advertisement register to advertise the ++ * requested capabilities. ++ */ ++int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) ++{ ++ unsigned int val = 0; ++ ++ if (advert & ADVERTISED_1000baseT_Half) ++ val |= ADVERTISE_1000XHALF; ++ if (advert & ADVERTISED_1000baseT_Full) ++ val |= ADVERTISE_1000XFULL; ++ if (advert & ADVERTISED_Pause) ++ val |= ADVERTISE_1000XPAUSE; ++ if (advert & ADVERTISED_Asym_Pause) ++ val |= ADVERTISE_1000XPSE_ASYM; ++ return mdio_write(phy, 0, MII_ADVERTISE, val); ++} ++ ++/** + * t3_set_phy_speed_duplex - force PHY speed and duplex + * @phy: the PHY to operate on + * @speed: requested PHY speed +Index: linux-2.6.27/drivers/net/cxgb3/vsc8211.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/vsc8211.c ++++ linux-2.6.27/drivers/net/cxgb3/vsc8211.c +@@ -33,28 +33,40 @@ + + /* VSC8211 PHY specific registers. */ + enum { ++ VSC8211_SIGDET_CTRL = 19, ++ VSC8211_EXT_CTRL = 23, + VSC8211_INTR_ENABLE = 25, + VSC8211_INTR_STATUS = 26, ++ VSC8211_LED_CTRL = 27, + VSC8211_AUX_CTRL_STAT = 28, ++ VSC8211_EXT_PAGE_AXS = 31, + }; + + enum { + VSC_INTR_RX_ERR = 1 << 0, +- VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ +- VSC_INTR_CABLE = 1 << 2, /* cable impairment */ +- VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ +- VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ +- VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ +- VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ +- VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ +- VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ +- VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ +- VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ +- VSC_INTR_LINK_CHG = 1 << 13, /* link change */ +- VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ ++ VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ ++ VSC_INTR_CABLE = 1 << 2, /* cable impairment */ ++ VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ ++ VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ ++ VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ ++ VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ ++ VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ ++ VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ ++ VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ ++ VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ ++ VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ ++ VSC_INTR_LINK_CHG = 1 << 13, /* link change */ ++ VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ ++ VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ ++}; ++ ++enum { ++ VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ ++ VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ + }; + + #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ ++ VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ + VSC_INTR_NEG_DONE) + #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ + VSC_INTR_ENABLE) +@@ -184,6 +196,112 @@ static int vsc8211_get_link_status(struc + return 0; + } + ++static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, ++ int *speed, int *duplex, int *fc) ++{ ++ unsigned int bmcr, status, lpa, adv; ++ int err, sp = -1, dplx = -1, pause = 0; ++ ++ err = mdio_read(cphy, 0, MII_BMCR, &bmcr); ++ if (!err) ++ err = mdio_read(cphy, 0, MII_BMSR, &status); ++ if (err) ++ return err; ++ ++ if (link_ok) { ++ /* ++ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it ++ * once more to get the current link state. ++ */ ++ if (!(status & BMSR_LSTATUS)) ++ err = mdio_read(cphy, 0, MII_BMSR, &status); ++ if (err) ++ return err; ++ *link_ok = (status & BMSR_LSTATUS) != 0; ++ } ++ if (!(bmcr & BMCR_ANENABLE)) { ++ dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; ++ if (bmcr & BMCR_SPEED1000) ++ sp = SPEED_1000; ++ else if (bmcr & BMCR_SPEED100) ++ sp = SPEED_100; ++ else ++ sp = SPEED_10; ++ } else if (status & BMSR_ANEGCOMPLETE) { ++ err = mdio_read(cphy, 0, MII_LPA, &lpa); ++ if (!err) ++ err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); ++ if (err) ++ return err; ++ ++ if (adv & lpa & ADVERTISE_1000XFULL) { ++ dplx = DUPLEX_FULL; ++ sp = SPEED_1000; ++ } else if (adv & lpa & ADVERTISE_1000XHALF) { ++ dplx = DUPLEX_HALF; ++ sp = SPEED_1000; ++ } ++ ++ if (fc && dplx == DUPLEX_FULL) { ++ if (lpa & adv & ADVERTISE_1000XPAUSE) ++ pause = PAUSE_RX | PAUSE_TX; ++ else if ((lpa & ADVERTISE_1000XPAUSE) && ++ (adv & lpa & ADVERTISE_1000XPSE_ASYM)) ++ pause = PAUSE_TX; ++ else if ((lpa & ADVERTISE_1000XPSE_ASYM) && ++ (adv & ADVERTISE_1000XPAUSE)) ++ pause = PAUSE_RX; ++ } ++ } ++ if (speed) ++ *speed = sp; ++ if (duplex) ++ *duplex = dplx; ++ if (fc) ++ *fc = pause; ++ return 0; ++} ++ ++/* ++ * Enable/disable auto MDI/MDI-X in forced link speed mode. ++ */ ++static int vsc8211_set_automdi(struct cphy *phy, int enable) ++{ ++ int err; ++ ++ err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, 18, 0x12); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, 16, 0x87fa); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) ++{ ++ int err; ++ ++ err = t3_set_phy_speed_duplex(phy, speed, duplex); ++ if (!err) ++ err = vsc8211_set_automdi(phy, 1); ++ return err; ++} ++ + static int vsc8211_power_down(struct cphy *cphy, int enable) + { + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, +@@ -221,12 +339,66 @@ static struct cphy_ops vsc8211_ops = { + .power_down = vsc8211_power_down, + }; + ++static struct cphy_ops vsc8211_fiber_ops = { ++ .reset = vsc8211_reset, ++ .intr_enable = vsc8211_intr_enable, ++ .intr_disable = vsc8211_intr_disable, ++ .intr_clear = vsc8211_intr_clear, ++ .intr_handler = vsc8211_intr_handler, ++ .autoneg_enable = vsc8211_autoneg_enable, ++ .autoneg_restart = vsc8211_autoneg_restart, ++ .advertise = t3_phy_advertise_fiber, ++ .set_speed_duplex = t3_set_phy_speed_duplex, ++ .get_link_status = vsc8211_get_link_status_fiber, ++ .power_down = vsc8211_power_down, ++}; ++ + int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) + { ++ int err; ++ unsigned int val; ++ + cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, + SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | + SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); ++ msleep(20); /* PHY needs ~10ms to start responding to MDIO */ ++ ++ err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val); ++ if (err) ++ return err; ++ if (val & VSC_CTRL_MEDIA_MODE_HI) { ++ /* copper interface, just need to configure the LEDs */ ++ return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100); ++ } ++ ++ phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | ++ SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; ++ phy->desc = "1000BASE-X"; ++ phy->ops = &vsc8211_fiber_ops; ++ ++ err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0); ++ if (err) ++ return err; ++ ++ err = mdio_write(phy, 0, VSC8211_EXT_CTRL, ++ val | VSC_CTRL_CLAUSE37_VIEW); ++ if (err) ++ return err; ++ ++ err = vsc8211_reset(phy, 0); ++ if (err) ++ return err; ++ ++ udelay(5); /* delay after reset before next SMI */ + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Allocate-multiqueues-at-init-time b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Allocate-multiqueues-at-init-time new file mode 100644 index 000000000..1de242b1b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Allocate-multiqueues-at-init-time @@ -0,0 +1,379 @@ +Commit-Id: 8c26376112fb4b8dfea42069b602c03d53366052 +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:37:33 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: Allocate multiqueues at init time +Reference: bnc#446739 + +Allocate a queue set per core, up to the maximum of available qsets. +Share the queue sets on multi port adapters. +Rename MSI-X interrupt vectors ethX-N, N being the queue set number. + + commit f9ee3882969224aa9f086268020c31819be6ae99 + cxgb3 - Limit multiqueue setting to msi-x + Allow multiqueue setting in MSI-X mode only + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +--- + drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/cxgb3_ioctl.h | 2 + drivers/net/cxgb3/cxgb3_main.c | 179 +++++++++++++++++++++++++++++++--------- + 3 files changed, 145 insertions(+), 37 deletions(-) + +--- a/drivers/net/cxgb3/common.h ++++ b/drivers/net/cxgb3/common.h +@@ -358,6 +358,7 @@ struct qset_params { /* SGE queue set p + unsigned int jumbo_size; /* # of entries in jumbo free list */ + unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ + unsigned int cong_thres; /* FL congestion threshold */ ++ unsigned int vector; /* Interrupt (line or vector) number */ + }; + + struct sge_params { +--- a/drivers/net/cxgb3/cxgb3_ioctl.h ++++ b/drivers/net/cxgb3/cxgb3_ioctl.h +@@ -92,6 +92,8 @@ struct ch_qset_params { + int32_t polling; + int32_t lro; + int32_t cong_thres; ++ int32_t vector; ++ int32_t qnum; + }; + + struct ch_pktsched_params { +--- a/drivers/net/cxgb3/cxgb3_main.c ++++ b/drivers/net/cxgb3/cxgb3_main.c +@@ -275,10 +275,10 @@ static void name_msix_vecs(struct adapte + + for (i = 0; i < pi->nqsets; i++, msi_idx++) { + snprintf(adap->msix_info[msi_idx].desc, n, +- "%s (queue %d)", d->name, i); ++ "%s-%d", d->name, pi->first_qset + i); + adap->msix_info[msi_idx].desc[n] = 0; + } +- } ++ } + } + + static int request_msix_data_irqs(struct adapter *adap) +@@ -307,6 +307,22 @@ static int request_msix_data_irqs(struct + return 0; + } + ++static void free_irq_resources(struct adapter *adapter) ++{ ++ if (adapter->flags & USING_MSIX) { ++ int i, n = 0; ++ ++ free_irq(adapter->msix_info[0].vec, adapter); ++ for_each_port(adapter, i) ++ n += adap2pinfo(adapter, i)->nqsets; ++ ++ for (i = 0; i < n; ++i) ++ free_irq(adapter->msix_info[i + 1].vec, ++ &adapter->sge.qs[i]); ++ } else ++ free_irq(adapter->pdev->irq, adapter); ++} ++ + static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, + unsigned long n) + { +@@ -474,7 +490,10 @@ static int setup_sge_qsets(struct adapte + struct port_info *pi = netdev_priv(dev); + + pi->qs = &adap->sge.qs[pi->first_qset]; +- for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { ++ for (j = pi->first_qset; j < pi->first_qset + pi->nqsets; ++ ++j, ++qset_idx) { ++ if (!pi->rx_csum_offload) ++ adap->params.sge.qset[qset_idx].lro = 0; + err = t3_sge_alloc_qset(adap, qset_idx, 1, + (adap->flags & USING_MSIX) ? qset_idx + 1 : + irq_idx, +@@ -782,11 +801,12 @@ static void init_port_mtus(struct adapte + t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); + } + +-static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, ++static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, + int hi, int port) + { + struct sk_buff *skb; + struct mngt_pktsched_wr *req; ++ int ret; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); +@@ -797,20 +817,28 @@ static void send_pktsched_cmd(struct ada + req->min = lo; + req->max = hi; + req->binding = port; +- t3_mgmt_tx(adap, skb); ++ ret = t3_mgmt_tx(adap, skb); ++ ++ return ret; + } + +-static void bind_qsets(struct adapter *adap) ++static int bind_qsets(struct adapter *adap) + { +- int i, j; ++ int i, j, err = 0; + + for_each_port(adap, i) { + const struct port_info *pi = adap2pinfo(adap, i); + +- for (j = 0; j < pi->nqsets; ++j) +- send_pktsched_cmd(adap, 1, pi->first_qset + j, -1, +- -1, i); ++ for (j = 0; j < pi->nqsets; ++j) { ++ int ret = send_pktsched_cmd(adap, 1, ++ pi->first_qset + j, -1, ++ -1, i); ++ if (ret) ++ err = ret; ++ } + } ++ ++ return err; + } + + #define FW_FNAME "t3fw-%d.%d.%d.bin" +@@ -989,9 +1017,16 @@ static int cxgb_up(struct adapter *adap) + t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff); + } + +- if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) +- bind_qsets(adap); +- adap->flags |= QUEUES_BOUND; ++ if (!(adap->flags & QUEUES_BOUND)) { ++ err = bind_qsets(adap); ++ if (err) { ++ CH_ERR(adap, "failed to bind qsets, err %d\n", err); ++ t3_intr_disable(adap); ++ free_irq_resources(adap); ++ goto out; ++ } ++ adap->flags |= QUEUES_BOUND; ++ } + + out: + return err; +@@ -1010,19 +1045,7 @@ static void cxgb_down(struct adapter *ad + t3_intr_disable(adapter); + spin_unlock_irq(&adapter->work_lock); + +- if (adapter->flags & USING_MSIX) { +- int i, n = 0; +- +- free_irq(adapter->msix_info[0].vec, adapter); +- for_each_port(adapter, i) +- n += adap2pinfo(adapter, i)->nqsets; +- +- for (i = 0; i < n; ++i) +- free_irq(adapter->msix_info[i + 1].vec, +- &adapter->sge.qs[i]); +- } else +- free_irq(adapter->pdev->irq, adapter); +- ++ free_irq_resources(adapter); + flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */ + quiesce_rx(adapter); + } +@@ -1333,8 +1356,8 @@ static unsigned long collect_sge_port_st + int i; + unsigned long tot = 0; + +- for (i = 0; i < p->nqsets; ++i) +- tot += adapter->sge.qs[i + p->first_qset].port_stats[idx]; ++ for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i) ++ tot += adapter->sge.qs[i].port_stats[idx]; + return tot; + } + +@@ -1538,7 +1561,7 @@ static int set_settings(struct net_devic + struct link_config *lc = &p->link_config; + + if (!(lc->supported & SUPPORTED_Autoneg)) +- return -EOPNOTSUPP; /* can't change speed/duplex */ ++ return -EOPNOTSUPP; /* can't change speed/duplex */ + + if (cmd->autoneg == AUTONEG_DISABLE) { + int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); +@@ -1617,8 +1640,10 @@ static int set_rx_csum(struct net_device + struct adapter *adap = p->adapter; + int i; + +- for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) ++ for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { ++ adap->params.sge.qset[i].lro = 0; + adap->sge.qs[i].lro_enabled = 0; ++ } + } + return 0; + } +@@ -1824,6 +1849,8 @@ static int cxgb_extension_ioctl(struct n + int i; + struct qset_params *q; + struct ch_qset_params t; ++ int q1 = pi->first_qset; ++ int nqsets = pi->nqsets; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; +@@ -1846,6 +1873,16 @@ static int cxgb_extension_ioctl(struct n + || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES, + MAX_RSPQ_ENTRIES)) + return -EINVAL; ++ ++ if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0) ++ for_each_port(adapter, i) { ++ pi = adap2pinfo(adapter, i); ++ if (t.qset_idx >= pi->first_qset && ++ t.qset_idx < pi->first_qset + pi->nqsets && ++ !pi->rx_csum_offload) ++ return -EINVAL; ++ } ++ + if ((adapter->flags & FULL_INIT_DONE) && + (t.rspq_size >= 0 || t.fl_size[0] >= 0 || + t.fl_size[1] >= 0 || t.txq_size[0] >= 0 || +@@ -1853,6 +1890,20 @@ static int cxgb_extension_ioctl(struct n + t.polling >= 0 || t.cong_thres >= 0)) + return -EBUSY; + ++ /* Allow setting of any available qset when offload enabled */ ++ if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { ++ q1 = 0; ++ for_each_port(adapter, i) { ++ pi = adap2pinfo(adapter, i); ++ nqsets += pi->first_qset + pi->nqsets; ++ } ++ } ++ ++ if (t.qset_idx < q1) ++ return -EINVAL; ++ if (t.qset_idx > q1 + nqsets - 1) ++ return -EINVAL; ++ + q = &adapter->params.sge.qset[t.qset_idx]; + + if (t.rspq_size >= 0) +@@ -1902,13 +1953,26 @@ static int cxgb_extension_ioctl(struct n + case CHELSIO_GET_QSET_PARAMS:{ + struct qset_params *q; + struct ch_qset_params t; ++ int q1 = pi->first_qset; ++ int nqsets = pi->nqsets; ++ int i; + + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; +- if (t.qset_idx >= SGE_QSETS) ++ ++ /* Display qsets for all ports when offload enabled */ ++ if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { ++ q1 = 0; ++ for_each_port(adapter, i) { ++ pi = adap2pinfo(adapter, i); ++ nqsets = pi->first_qset + pi->nqsets; ++ } ++ } ++ ++ if (t.qset_idx >= nqsets) + return -EINVAL; + +- q = &adapter->params.sge.qset[t.qset_idx]; ++ q = &adapter->params.sge.qset[q1 + t.qset_idx]; + t.rspq_size = q->rspq_size; + t.txq_size[0] = q->txq_size[0]; + t.txq_size[1] = q->txq_size[1]; +@@ -1919,6 +1983,12 @@ static int cxgb_extension_ioctl(struct n + t.lro = q->lro; + t.intr_lat = q->coalesce_usecs; + t.cong_thres = q->cong_thres; ++ t.qnum = q1; ++ ++ if (adapter->flags & USING_MSIX) ++ t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec; ++ else ++ t.vector = adapter->pdev->irq; + + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; +@@ -2264,8 +2334,8 @@ static void t3_synchronize_rx(struct ada + { + int i; + +- for (i = 0; i < p->nqsets; i++) { +- struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq; ++ for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { ++ struct sge_rspq *q = &adap->sge.qs[i].rspq; + + spin_lock_irq(&q->lock); + spin_unlock_irq(&q->lock); +@@ -2572,6 +2642,42 @@ static struct pci_error_handlers t3_err_ + .resume = t3_io_resume, + }; + ++/* ++ * Set the number of qsets based on the number of CPUs and the number of ports, ++ * not to exceed the number of available qsets, assuming there are enough qsets ++ * per port in HW. ++ */ ++static void set_nqsets(struct adapter *adap) ++{ ++ int i, j = 0; ++ int num_cpus = num_online_cpus(); ++ int hwports = adap->params.nports; ++ int nqsets = SGE_QSETS; ++ ++ if (adap->params.rev > 0 && adap->flags & USING_MSIX) { ++ if (hwports == 2 && ++ (hwports * nqsets > SGE_QSETS || ++ num_cpus >= nqsets / hwports)) ++ nqsets /= hwports; ++ if (nqsets > num_cpus) ++ nqsets = num_cpus; ++ if (nqsets < 1 || hwports == 4) ++ nqsets = 1; ++ } else ++ nqsets = 1; ++ ++ for_each_port(adap, i) { ++ struct port_info *pi = adap2pinfo(adap, i); ++ ++ pi->first_qset = j; ++ pi->nqsets = nqsets; ++ j = pi->first_qset + nqsets; ++ ++ dev_info(&adap->pdev->dev, ++ "Port %d using %d queue sets.\n", i, nqsets); ++ } ++} ++ + static int __devinit cxgb_enable_msix(struct adapter *adap) + { + struct msix_entry entries[SGE_QSETS + 1]; +@@ -2729,9 +2835,6 @@ static int __devinit init_one(struct pci + pi = netdev_priv(netdev); + pi->adapter = adapter; + pi->rx_csum_offload = 1; +- pi->nqsets = 1; +- pi->first_qset = i; +- pi->activity = 0; + pi->port_id = i; + netif_carrier_off(netdev); + netdev->irq = pdev->irq; +@@ -2808,6 +2911,8 @@ static int __devinit init_one(struct pci + else if (msi > 0 && pci_enable_msi(pdev) == 0) + adapter->flags |= USING_MSI; + ++ set_nqsets(adapter); ++ + err = sysfs_create_group(&adapter->port[0]->dev.kobj, + &cxgb3_attr_group); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-More-flexible-support-for-PHY-interrupts b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-More-flexible-support-for-PHY-interrupts new file mode 100644 index 000000000..ef052b920 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-More-flexible-support-for-PHY-interrupts @@ -0,0 +1,150 @@ +Commit-Id: f231e0a5a2d01da40515c24f1daa689fe8cfd8d7 +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:39:00 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: More flexible support for PHY interrupts. +Reference: bnc#446739 + +Do not require PHY interrupts to be connected to GPIs in ascending order. +Base interrupt availability both on PHYs supporting them and on GPIs being +hooked up. Allows boards to specify interrupt GPIs though the PHYs don't +use them. + +Remove spurious PHY interrupts due to clearing T3DBG interrupts before +setting their polarity. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h +index e83a360..75b5ee6 100644 +--- a/drivers/net/cxgb3/common.h ++++ b/drivers/net/cxgb3/common.h +@@ -194,7 +194,7 @@ struct adapter_info { + unsigned char nports; /* # of ports */ + unsigned char phy_base_addr; /* MDIO PHY base address */ + unsigned int gpio_out; /* GPIO output settings */ +- unsigned int gpio_intr; /* GPIO IRQ enable mask */ ++ unsigned char gpio_intr[MAX_NPORTS]; /* GPIO PHY IRQ pins */ + unsigned long caps; /* adapter capabilities */ + const struct mdio_ops *mdio_ops; /* MDIO operations */ + const char *desc; /* product description */ +@@ -517,7 +517,7 @@ enum { + MAC_RXFIFO_SIZE = 32768 + }; + +-/* IEEE 802.3ae specified MDIO devices */ ++/* IEEE 802.3 specified MDIO devices */ + enum { + MDIO_DEV_PMA_PMD = 1, + MDIO_DEV_WIS = 2, +diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h +index 4bda27c..a035d5c 100644 +--- a/drivers/net/cxgb3/regs.h ++++ b/drivers/net/cxgb3/regs.h +@@ -573,6 +573,10 @@ + #define V_GPIO10(x) ((x) << S_GPIO10) + #define F_GPIO10 V_GPIO10(1U) + ++#define S_GPIO9 9 ++#define V_GPIO9(x) ((x) << S_GPIO9) ++#define F_GPIO9 V_GPIO9(1U) ++ + #define S_GPIO7 7 + #define V_GPIO7(x) ((x) << S_GPIO7) + #define F_GPIO7 V_GPIO7(1U) +diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c +index f7ced32..bfce761 100644 +--- a/drivers/net/cxgb3/t3_hw.c ++++ b/drivers/net/cxgb3/t3_hw.c +@@ -445,24 +445,22 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) + static const struct adapter_info t3_adap_info[] = { + {2, 0, + F_GPIO2_OEN | F_GPIO4_OEN | +- F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, +- 0, ++ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, + &mi1_mdio_ops, "Chelsio PE9000"}, + {2, 0, + F_GPIO2_OEN | F_GPIO4_OEN | +- F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, +- 0, ++ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, + &mi1_mdio_ops, "Chelsio T302"}, + {1, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | + F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, +- 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, ++ { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio T310"}, + {2, 0, + F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | + F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | +- F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, +- SUPPORTED_10000baseT_Full | SUPPORTED_AUI, ++ F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, ++ { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio T320"}, + }; + +@@ -1684,19 +1682,15 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx) + */ + int t3_phy_intr_handler(struct adapter *adapter) + { +- u32 mask, gpi = adapter_info(adapter)->gpio_intr; + u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); + + for_each_port(adapter, i) { + struct port_info *p = adap2pinfo(adapter, i); + +- mask = gpi - (gpi & (gpi - 1)); +- gpi -= mask; +- + if (!(p->phy.caps & SUPPORTED_IRQ)) + continue; + +- if (cause & mask) { ++ if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { + int phy_cause = p->phy.ops->intr_handler(&p->phy); + + if (phy_cause & cphy_cause_link_change) +@@ -1765,6 +1759,17 @@ int t3_slow_intr_handler(struct adapter *adapter) + return 1; + } + ++static unsigned int calc_gpio_intr(struct adapter *adap) ++{ ++ unsigned int i, gpi_intr = 0; ++ ++ for_each_port(adap, i) ++ if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && ++ adapter_info(adap)->gpio_intr[i]) ++ gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; ++ return gpi_intr; ++} ++ + /** + * t3_intr_enable - enable interrupts + * @adapter: the adapter whose interrupts should be enabled +@@ -1807,10 +1812,8 @@ void t3_intr_enable(struct adapter *adapter) + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); + } + +- t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, +- adapter_info(adapter)->gpio_intr); +- t3_write_reg(adapter, A_T3DBG_INT_ENABLE, +- adapter_info(adapter)->gpio_intr); ++ t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); ++ + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); + else +@@ -3331,6 +3334,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) + init_hw_for_avail_ports(adapter, adapter->params.nports); + t3_sge_init(adapter, &adapter->params.sge); + ++ t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); ++ + t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); + t3_write_reg(adapter, A_CIM_BOOT_CFG, + V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Support-for-Aeluros-2005-PHY b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Support-for-Aeluros-2005-PHY new file mode 100644 index 000000000..e962fc4b1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-Support-for-Aeluros-2005-PHY @@ -0,0 +1,1183 @@ +Commit-Id: 1e8820256f9921370cd7423396871e2d850e0323 +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:40:07 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: Support for Aeluros 2005 PHY +Reference: bnc#446739 + + +Add support for SR PHY. +Auto-detect phy module type, and report type changes. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +Index: linux-2.6.27/drivers/net/cxgb3/ael1002.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/ael1002.c ++++ linux-2.6.27/drivers/net/cxgb3/ael1002.c +@@ -33,14 +33,57 @@ + #include "regs.h" + + enum { ++ PMD_RSD = 10, /* PMA/PMD receive signal detect register */ ++ PCS_STAT1_X = 24, /* 10GBASE-X PCS status 1 register */ ++ PCS_STAT1_R = 32, /* 10GBASE-R PCS status 1 register */ ++ XS_LN_STAT = 24 /* XS lane status register */ ++}; ++ ++enum { + AEL100X_TX_DISABLE = 9, + AEL100X_TX_CONFIG1 = 0xc002, + AEL1002_PWR_DOWN_HI = 0xc011, + AEL1002_PWR_DOWN_LO = 0xc012, + AEL1002_XFI_EQL = 0xc015, + AEL1002_LB_EN = 0xc017, ++ AEL_OPT_SETTINGS = 0xc017, ++ AEL_I2C_CTRL = 0xc30a, ++ AEL_I2C_DATA = 0xc30b, ++ AEL_I2C_STAT = 0xc30c, ++ AEL2005_GPIO_CTRL = 0xc214, ++ AEL2005_GPIO_STAT = 0xc215, + }; + ++enum { edc_none, edc_sr, edc_twinax }; ++ ++/* PHY module I2C device address */ ++#define MODULE_DEV_ADDR 0xa0 ++ ++#define AEL2005_MODDET_IRQ 4 ++ ++struct reg_val { ++ unsigned short mmd_addr; ++ unsigned short reg_addr; ++ unsigned short clear_bits; ++ unsigned short set_bits; ++}; ++ ++static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) ++{ ++ int err; ++ ++ for (err = 0; rv->mmd_addr && !err; rv++) { ++ if (rv->clear_bits == 0xffff) ++ err = mdio_write(phy, rv->mmd_addr, rv->reg_addr, ++ rv->set_bits); ++ else ++ err = t3_mdio_change_bits(phy, rv->mmd_addr, ++ rv->reg_addr, rv->clear_bits, ++ rv->set_bits); ++ } ++ return err; ++} ++ + static void ael100x_txon(struct cphy *phy) + { + int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; +@@ -81,23 +124,23 @@ static int ael1002_intr_noop(struct cphy + return 0; + } + +-static int ael100x_get_link_status(struct cphy *phy, int *link_ok, +- int *speed, int *duplex, int *fc) ++/* ++ * Get link status for a 10GBASE-R device. ++ */ ++static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, ++ int *duplex, int *fc) + { + if (link_ok) { +- unsigned int status; +- int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); ++ unsigned int stat0, stat1, stat2; ++ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); + +- /* +- * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it +- * once more to get the current link state. +- */ +- if (!err && !(status & BMSR_LSTATUS)) +- err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, +- &status); ++ if (!err) ++ err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_R, &stat1); ++ if (!err) ++ err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); + if (err) + return err; +- *link_ok = !!(status & BMSR_LSTATUS); ++ *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; + } + if (speed) + *speed = SPEED_10000; +@@ -112,7 +155,7 @@ static struct cphy_ops ael1002_ops = { + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, +- .get_link_status = ael100x_get_link_status, ++ .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + }; + +@@ -143,7 +186,7 @@ static struct cphy_ops ael1006_ops = { + .intr_disable = t3_phy_lasi_intr_disable, + .intr_clear = t3_phy_lasi_intr_clear, + .intr_handler = t3_phy_lasi_intr_handler, +- .get_link_status = ael100x_get_link_status, ++ .get_link_status = get_link_status_r, + .power_down = ael1006_power_down, + }; + +@@ -157,13 +200,948 @@ int t3_ael1006_phy_prep(struct cphy *phy + return 0; + } + ++static int ael2005_setup_sr_edc(struct cphy *phy) ++{ ++ static struct reg_val regs[] = { ++ { MDIO_DEV_PMA_PMD, 0xc003, 0xffff, 0x181 }, ++ { MDIO_DEV_PMA_PMD, 0xc010, 0xffff, 0x448a }, ++ { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5200 }, ++ { 0, 0, 0, 0 } ++ }; ++ static u16 sr_edc[] = { ++ 0xcc00, 0x2ff4, ++ 0xcc01, 0x3cd4, ++ 0xcc02, 0x2015, ++ 0xcc03, 0x3105, ++ 0xcc04, 0x6524, ++ 0xcc05, 0x27ff, ++ 0xcc06, 0x300f, ++ 0xcc07, 0x2c8b, ++ 0xcc08, 0x300b, ++ 0xcc09, 0x4009, ++ 0xcc0a, 0x400e, ++ 0xcc0b, 0x2f72, ++ 0xcc0c, 0x3002, ++ 0xcc0d, 0x1002, ++ 0xcc0e, 0x2172, ++ 0xcc0f, 0x3012, ++ 0xcc10, 0x1002, ++ 0xcc11, 0x25d2, ++ 0xcc12, 0x3012, ++ 0xcc13, 0x1002, ++ 0xcc14, 0xd01e, ++ 0xcc15, 0x27d2, ++ 0xcc16, 0x3012, ++ 0xcc17, 0x1002, ++ 0xcc18, 0x2004, ++ 0xcc19, 0x3c84, ++ 0xcc1a, 0x6436, ++ 0xcc1b, 0x2007, ++ 0xcc1c, 0x3f87, ++ 0xcc1d, 0x8676, ++ 0xcc1e, 0x40b7, ++ 0xcc1f, 0xa746, ++ 0xcc20, 0x4047, ++ 0xcc21, 0x5673, ++ 0xcc22, 0x2982, ++ 0xcc23, 0x3002, ++ 0xcc24, 0x13d2, ++ 0xcc25, 0x8bbd, ++ 0xcc26, 0x2862, ++ 0xcc27, 0x3012, ++ 0xcc28, 0x1002, ++ 0xcc29, 0x2092, ++ 0xcc2a, 0x3012, ++ 0xcc2b, 0x1002, ++ 0xcc2c, 0x5cc3, ++ 0xcc2d, 0x314, ++ 0xcc2e, 0x2942, ++ 0xcc2f, 0x3002, ++ 0xcc30, 0x1002, ++ 0xcc31, 0xd019, ++ 0xcc32, 0x2032, ++ 0xcc33, 0x3012, ++ 0xcc34, 0x1002, ++ 0xcc35, 0x2a04, ++ 0xcc36, 0x3c74, ++ 0xcc37, 0x6435, ++ 0xcc38, 0x2fa4, ++ 0xcc39, 0x3cd4, ++ 0xcc3a, 0x6624, ++ 0xcc3b, 0x5563, ++ 0xcc3c, 0x2d42, ++ 0xcc3d, 0x3002, ++ 0xcc3e, 0x13d2, ++ 0xcc3f, 0x464d, ++ 0xcc40, 0x2862, ++ 0xcc41, 0x3012, ++ 0xcc42, 0x1002, ++ 0xcc43, 0x2032, ++ 0xcc44, 0x3012, ++ 0xcc45, 0x1002, ++ 0xcc46, 0x2fb4, ++ 0xcc47, 0x3cd4, ++ 0xcc48, 0x6624, ++ 0xcc49, 0x5563, ++ 0xcc4a, 0x2d42, ++ 0xcc4b, 0x3002, ++ 0xcc4c, 0x13d2, ++ 0xcc4d, 0x2ed2, ++ 0xcc4e, 0x3002, ++ 0xcc4f, 0x1002, ++ 0xcc50, 0x2fd2, ++ 0xcc51, 0x3002, ++ 0xcc52, 0x1002, ++ 0xcc53, 0x004, ++ 0xcc54, 0x2942, ++ 0xcc55, 0x3002, ++ 0xcc56, 0x1002, ++ 0xcc57, 0x2092, ++ 0xcc58, 0x3012, ++ 0xcc59, 0x1002, ++ 0xcc5a, 0x5cc3, ++ 0xcc5b, 0x317, ++ 0xcc5c, 0x2f72, ++ 0xcc5d, 0x3002, ++ 0xcc5e, 0x1002, ++ 0xcc5f, 0x2942, ++ 0xcc60, 0x3002, ++ 0xcc61, 0x1002, ++ 0xcc62, 0x22cd, ++ 0xcc63, 0x301d, ++ 0xcc64, 0x2862, ++ 0xcc65, 0x3012, ++ 0xcc66, 0x1002, ++ 0xcc67, 0x2ed2, ++ 0xcc68, 0x3002, ++ 0xcc69, 0x1002, ++ 0xcc6a, 0x2d72, ++ 0xcc6b, 0x3002, ++ 0xcc6c, 0x1002, ++ 0xcc6d, 0x628f, ++ 0xcc6e, 0x2112, ++ 0xcc6f, 0x3012, ++ 0xcc70, 0x1002, ++ 0xcc71, 0x5aa3, ++ 0xcc72, 0x2dc2, ++ 0xcc73, 0x3002, ++ 0xcc74, 0x1312, ++ 0xcc75, 0x6f72, ++ 0xcc76, 0x1002, ++ 0xcc77, 0x2807, ++ 0xcc78, 0x31a7, ++ 0xcc79, 0x20c4, ++ 0xcc7a, 0x3c24, ++ 0xcc7b, 0x6724, ++ 0xcc7c, 0x1002, ++ 0xcc7d, 0x2807, ++ 0xcc7e, 0x3187, ++ 0xcc7f, 0x20c4, ++ 0xcc80, 0x3c24, ++ 0xcc81, 0x6724, ++ 0xcc82, 0x1002, ++ 0xcc83, 0x2514, ++ 0xcc84, 0x3c64, ++ 0xcc85, 0x6436, ++ 0xcc86, 0xdff4, ++ 0xcc87, 0x6436, ++ 0xcc88, 0x1002, ++ 0xcc89, 0x40a4, ++ 0xcc8a, 0x643c, ++ 0xcc8b, 0x4016, ++ 0xcc8c, 0x8c6c, ++ 0xcc8d, 0x2b24, ++ 0xcc8e, 0x3c24, ++ 0xcc8f, 0x6435, ++ 0xcc90, 0x1002, ++ 0xcc91, 0x2b24, ++ 0xcc92, 0x3c24, ++ 0xcc93, 0x643a, ++ 0xcc94, 0x4025, ++ 0xcc95, 0x8a5a, ++ 0xcc96, 0x1002, ++ 0xcc97, 0x2731, ++ 0xcc98, 0x3011, ++ 0xcc99, 0x1001, ++ 0xcc9a, 0xc7a0, ++ 0xcc9b, 0x100, ++ 0xcc9c, 0xc502, ++ 0xcc9d, 0x53ac, ++ 0xcc9e, 0xc503, ++ 0xcc9f, 0xd5d5, ++ 0xcca0, 0xc600, ++ 0xcca1, 0x2a6d, ++ 0xcca2, 0xc601, ++ 0xcca3, 0x2a4c, ++ 0xcca4, 0xc602, ++ 0xcca5, 0x111, ++ 0xcca6, 0xc60c, ++ 0xcca7, 0x5900, ++ 0xcca8, 0xc710, ++ 0xcca9, 0x700, ++ 0xccaa, 0xc718, ++ 0xccab, 0x700, ++ 0xccac, 0xc720, ++ 0xccad, 0x4700, ++ 0xccae, 0xc801, ++ 0xccaf, 0x7f50, ++ 0xccb0, 0xc802, ++ 0xccb1, 0x7760, ++ 0xccb2, 0xc803, ++ 0xccb3, 0x7fce, ++ 0xccb4, 0xc804, ++ 0xccb5, 0x5700, ++ 0xccb6, 0xc805, ++ 0xccb7, 0x5f11, ++ 0xccb8, 0xc806, ++ 0xccb9, 0x4751, ++ 0xccba, 0xc807, ++ 0xccbb, 0x57e1, ++ 0xccbc, 0xc808, ++ 0xccbd, 0x2700, ++ 0xccbe, 0xc809, ++ 0xccbf, 0x000, ++ 0xccc0, 0xc821, ++ 0xccc1, 0x002, ++ 0xccc2, 0xc822, ++ 0xccc3, 0x014, ++ 0xccc4, 0xc832, ++ 0xccc5, 0x1186, ++ 0xccc6, 0xc847, ++ 0xccc7, 0x1e02, ++ 0xccc8, 0xc013, ++ 0xccc9, 0xf341, ++ 0xccca, 0xc01a, ++ 0xcccb, 0x446, ++ 0xcccc, 0xc024, ++ 0xcccd, 0x1000, ++ 0xccce, 0xc025, ++ 0xcccf, 0xa00, ++ 0xccd0, 0xc026, ++ 0xccd1, 0xc0c, ++ 0xccd2, 0xc027, ++ 0xccd3, 0xc0c, ++ 0xccd4, 0xc029, ++ 0xccd5, 0x0a0, ++ 0xccd6, 0xc030, ++ 0xccd7, 0xa00, ++ 0xccd8, 0xc03c, ++ 0xccd9, 0x01c, ++ 0xccda, 0xc005, ++ 0xccdb, 0x7a06, ++ 0xccdc, 0x000, ++ 0xccdd, 0x2731, ++ 0xccde, 0x3011, ++ 0xccdf, 0x1001, ++ 0xcce0, 0xc620, ++ 0xcce1, 0x000, ++ 0xcce2, 0xc621, ++ 0xcce3, 0x03f, ++ 0xcce4, 0xc622, ++ 0xcce5, 0x000, ++ 0xcce6, 0xc623, ++ 0xcce7, 0x000, ++ 0xcce8, 0xc624, ++ 0xcce9, 0x000, ++ 0xccea, 0xc625, ++ 0xcceb, 0x000, ++ 0xccec, 0xc627, ++ 0xcced, 0x000, ++ 0xccee, 0xc628, ++ 0xccef, 0x000, ++ 0xccf0, 0xc62c, ++ 0xccf1, 0x000, ++ 0xccf2, 0x000, ++ 0xccf3, 0x2806, ++ 0xccf4, 0x3cb6, ++ 0xccf5, 0xc161, ++ 0xccf6, 0x6134, ++ 0xccf7, 0x6135, ++ 0xccf8, 0x5443, ++ 0xccf9, 0x303, ++ 0xccfa, 0x6524, ++ 0xccfb, 0x00b, ++ 0xccfc, 0x1002, ++ 0xccfd, 0x2104, ++ 0xccfe, 0x3c24, ++ 0xccff, 0x2105, ++ 0xcd00, 0x3805, ++ 0xcd01, 0x6524, ++ 0xcd02, 0xdff4, ++ 0xcd03, 0x4005, ++ 0xcd04, 0x6524, ++ 0xcd05, 0x1002, ++ 0xcd06, 0x5dd3, ++ 0xcd07, 0x306, ++ 0xcd08, 0x2ff7, ++ 0xcd09, 0x38f7, ++ 0xcd0a, 0x60b7, ++ 0xcd0b, 0xdffd, ++ 0xcd0c, 0x00a, ++ 0xcd0d, 0x1002, ++ 0xcd0e, 0 ++ }; ++ int i, err; ++ ++ err = set_phy_regs(phy, regs); ++ if (err) ++ return err; ++ ++ msleep(50); ++ ++ for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2) ++ err = mdio_write(phy, MDIO_DEV_PMA_PMD, sr_edc[i], ++ sr_edc[i + 1]); ++ if (!err) ++ phy->priv = edc_sr; ++ return err; ++} ++ ++static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) ++{ ++ static struct reg_val regs[] = { ++ { MDIO_DEV_PMA_PMD, 0xc04a, 0xffff, 0x5a00 }, ++ { 0, 0, 0, 0 } ++ }; ++ static struct reg_val preemphasis[] = { ++ { MDIO_DEV_PMA_PMD, 0xc014, 0xffff, 0xfe16 }, ++ { MDIO_DEV_PMA_PMD, 0xc015, 0xffff, 0xa000 }, ++ { 0, 0, 0, 0 } ++ }; ++ static u16 twinax_edc[] = { ++ 0xcc00, 0x4009, ++ 0xcc01, 0x27ff, ++ 0xcc02, 0x300f, ++ 0xcc03, 0x40aa, ++ 0xcc04, 0x401c, ++ 0xcc05, 0x401e, ++ 0xcc06, 0x2ff4, ++ 0xcc07, 0x3cd4, ++ 0xcc08, 0x2035, ++ 0xcc09, 0x3145, ++ 0xcc0a, 0x6524, ++ 0xcc0b, 0x26a2, ++ 0xcc0c, 0x3012, ++ 0xcc0d, 0x1002, ++ 0xcc0e, 0x29c2, ++ 0xcc0f, 0x3002, ++ 0xcc10, 0x1002, ++ 0xcc11, 0x2072, ++ 0xcc12, 0x3012, ++ 0xcc13, 0x1002, ++ 0xcc14, 0x22cd, ++ 0xcc15, 0x301d, ++ 0xcc16, 0x2e52, ++ 0xcc17, 0x3012, ++ 0xcc18, 0x1002, ++ 0xcc19, 0x28e2, ++ 0xcc1a, 0x3002, ++ 0xcc1b, 0x1002, ++ 0xcc1c, 0x628f, ++ 0xcc1d, 0x2ac2, ++ 0xcc1e, 0x3012, ++ 0xcc1f, 0x1002, ++ 0xcc20, 0x5553, ++ 0xcc21, 0x2ae2, ++ 0xcc22, 0x3002, ++ 0xcc23, 0x1302, ++ 0xcc24, 0x401e, ++ 0xcc25, 0x2be2, ++ 0xcc26, 0x3012, ++ 0xcc27, 0x1002, ++ 0xcc28, 0x2da2, ++ 0xcc29, 0x3012, ++ 0xcc2a, 0x1002, ++ 0xcc2b, 0x2ba2, ++ 0xcc2c, 0x3002, ++ 0xcc2d, 0x1002, ++ 0xcc2e, 0x5ee3, ++ 0xcc2f, 0x305, ++ 0xcc30, 0x400e, ++ 0xcc31, 0x2bc2, ++ 0xcc32, 0x3002, ++ 0xcc33, 0x1002, ++ 0xcc34, 0x2b82, ++ 0xcc35, 0x3012, ++ 0xcc36, 0x1002, ++ 0xcc37, 0x5663, ++ 0xcc38, 0x302, ++ 0xcc39, 0x401e, ++ 0xcc3a, 0x6f72, ++ 0xcc3b, 0x1002, ++ 0xcc3c, 0x628f, ++ 0xcc3d, 0x2be2, ++ 0xcc3e, 0x3012, ++ 0xcc3f, 0x1002, ++ 0xcc40, 0x22cd, ++ 0xcc41, 0x301d, ++ 0xcc42, 0x2e52, ++ 0xcc43, 0x3012, ++ 0xcc44, 0x1002, ++ 0xcc45, 0x2522, ++ 0xcc46, 0x3012, ++ 0xcc47, 0x1002, ++ 0xcc48, 0x2da2, ++ 0xcc49, 0x3012, ++ 0xcc4a, 0x1002, ++ 0xcc4b, 0x2ca2, ++ 0xcc4c, 0x3012, ++ 0xcc4d, 0x1002, ++ 0xcc4e, 0x2fa4, ++ 0xcc4f, 0x3cd4, ++ 0xcc50, 0x6624, ++ 0xcc51, 0x410b, ++ 0xcc52, 0x56b3, ++ 0xcc53, 0x3c4, ++ 0xcc54, 0x2fb2, ++ 0xcc55, 0x3002, ++ 0xcc56, 0x1002, ++ 0xcc57, 0x220b, ++ 0xcc58, 0x303b, ++ 0xcc59, 0x56b3, ++ 0xcc5a, 0x3c3, ++ 0xcc5b, 0x866b, ++ 0xcc5c, 0x400c, ++ 0xcc5d, 0x23a2, ++ 0xcc5e, 0x3012, ++ 0xcc5f, 0x1002, ++ 0xcc60, 0x2da2, ++ 0xcc61, 0x3012, ++ 0xcc62, 0x1002, ++ 0xcc63, 0x2ca2, ++ 0xcc64, 0x3012, ++ 0xcc65, 0x1002, ++ 0xcc66, 0x2fb4, ++ 0xcc67, 0x3cd4, ++ 0xcc68, 0x6624, ++ 0xcc69, 0x56b3, ++ 0xcc6a, 0x3c3, ++ 0xcc6b, 0x866b, ++ 0xcc6c, 0x401c, ++ 0xcc6d, 0x2205, ++ 0xcc6e, 0x3035, ++ 0xcc6f, 0x5b53, ++ 0xcc70, 0x2c52, ++ 0xcc71, 0x3002, ++ 0xcc72, 0x13c2, ++ 0xcc73, 0x5cc3, ++ 0xcc74, 0x317, ++ 0xcc75, 0x2522, ++ 0xcc76, 0x3012, ++ 0xcc77, 0x1002, ++ 0xcc78, 0x2da2, ++ 0xcc79, 0x3012, ++ 0xcc7a, 0x1002, ++ 0xcc7b, 0x2b82, ++ 0xcc7c, 0x3012, ++ 0xcc7d, 0x1002, ++ 0xcc7e, 0x5663, ++ 0xcc7f, 0x303, ++ 0xcc80, 0x401e, ++ 0xcc81, 0x004, ++ 0xcc82, 0x2c42, ++ 0xcc83, 0x3012, ++ 0xcc84, 0x1002, ++ 0xcc85, 0x6f72, ++ 0xcc86, 0x1002, ++ 0xcc87, 0x628f, ++ 0xcc88, 0x2304, ++ 0xcc89, 0x3c84, ++ 0xcc8a, 0x6436, ++ 0xcc8b, 0xdff4, ++ 0xcc8c, 0x6436, ++ 0xcc8d, 0x2ff5, ++ 0xcc8e, 0x3005, ++ 0xcc8f, 0x8656, ++ 0xcc90, 0xdfba, ++ 0xcc91, 0x56a3, ++ 0xcc92, 0xd05a, ++ 0xcc93, 0x21c2, ++ 0xcc94, 0x3012, ++ 0xcc95, 0x1392, ++ 0xcc96, 0xd05a, ++ 0xcc97, 0x56a3, ++ 0xcc98, 0xdfba, ++ 0xcc99, 0x383, ++ 0xcc9a, 0x6f72, ++ 0xcc9b, 0x1002, ++ 0xcc9c, 0x28c5, ++ 0xcc9d, 0x3005, ++ 0xcc9e, 0x4178, ++ 0xcc9f, 0x5653, ++ 0xcca0, 0x384, ++ 0xcca1, 0x22b2, ++ 0xcca2, 0x3012, ++ 0xcca3, 0x1002, ++ 0xcca4, 0x2be5, ++ 0xcca5, 0x3005, ++ 0xcca6, 0x41e8, ++ 0xcca7, 0x5653, ++ 0xcca8, 0x382, ++ 0xcca9, 0x002, ++ 0xccaa, 0x4258, ++ 0xccab, 0x2474, ++ 0xccac, 0x3c84, ++ 0xccad, 0x6437, ++ 0xccae, 0xdff4, ++ 0xccaf, 0x6437, ++ 0xccb0, 0x2ff5, ++ 0xccb1, 0x3c05, ++ 0xccb2, 0x8757, ++ 0xccb3, 0xb888, ++ 0xccb4, 0x9787, ++ 0xccb5, 0xdff4, ++ 0xccb6, 0x6724, ++ 0xccb7, 0x866a, ++ 0xccb8, 0x6f72, ++ 0xccb9, 0x1002, ++ 0xccba, 0x2d01, ++ 0xccbb, 0x3011, ++ 0xccbc, 0x1001, ++ 0xccbd, 0xc620, ++ 0xccbe, 0x14e5, ++ 0xccbf, 0xc621, ++ 0xccc0, 0xc53d, ++ 0xccc1, 0xc622, ++ 0xccc2, 0x3cbe, ++ 0xccc3, 0xc623, ++ 0xccc4, 0x4452, ++ 0xccc5, 0xc624, ++ 0xccc6, 0xc5c5, ++ 0xccc7, 0xc625, ++ 0xccc8, 0xe01e, ++ 0xccc9, 0xc627, ++ 0xccca, 0x000, ++ 0xcccb, 0xc628, ++ 0xcccc, 0x000, ++ 0xcccd, 0xc62b, ++ 0xccce, 0x000, ++ 0xcccf, 0xc62c, ++ 0xccd0, 0x000, ++ 0xccd1, 0x000, ++ 0xccd2, 0x2d01, ++ 0xccd3, 0x3011, ++ 0xccd4, 0x1001, ++ 0xccd5, 0xc620, ++ 0xccd6, 0x000, ++ 0xccd7, 0xc621, ++ 0xccd8, 0x000, ++ 0xccd9, 0xc622, ++ 0xccda, 0x0ce, ++ 0xccdb, 0xc623, ++ 0xccdc, 0x07f, ++ 0xccdd, 0xc624, ++ 0xccde, 0x032, ++ 0xccdf, 0xc625, ++ 0xcce0, 0x000, ++ 0xcce1, 0xc627, ++ 0xcce2, 0x000, ++ 0xcce3, 0xc628, ++ 0xcce4, 0x000, ++ 0xcce5, 0xc62b, ++ 0xcce6, 0x000, ++ 0xcce7, 0xc62c, ++ 0xcce8, 0x000, ++ 0xcce9, 0x000, ++ 0xccea, 0x2d01, ++ 0xcceb, 0x3011, ++ 0xccec, 0x1001, ++ 0xcced, 0xc502, ++ 0xccee, 0x609f, ++ 0xccef, 0xc600, ++ 0xccf0, 0x2a6e, ++ 0xccf1, 0xc601, ++ 0xccf2, 0x2a2c, ++ 0xccf3, 0xc60c, ++ 0xccf4, 0x5400, ++ 0xccf5, 0xc710, ++ 0xccf6, 0x700, ++ 0xccf7, 0xc718, ++ 0xccf8, 0x700, ++ 0xccf9, 0xc720, ++ 0xccfa, 0x4700, ++ 0xccfb, 0xc728, ++ 0xccfc, 0x700, ++ 0xccfd, 0xc729, ++ 0xccfe, 0x1207, ++ 0xccff, 0xc801, ++ 0xcd00, 0x7f50, ++ 0xcd01, 0xc802, ++ 0xcd02, 0x7760, ++ 0xcd03, 0xc803, ++ 0xcd04, 0x7fce, ++ 0xcd05, 0xc804, ++ 0xcd06, 0x520e, ++ 0xcd07, 0xc805, ++ 0xcd08, 0x5c11, ++ 0xcd09, 0xc806, ++ 0xcd0a, 0x3c51, ++ 0xcd0b, 0xc807, ++ 0xcd0c, 0x4061, ++ 0xcd0d, 0xc808, ++ 0xcd0e, 0x49c1, ++ 0xcd0f, 0xc809, ++ 0xcd10, 0x3840, ++ 0xcd11, 0xc80a, ++ 0xcd12, 0x000, ++ 0xcd13, 0xc821, ++ 0xcd14, 0x002, ++ 0xcd15, 0xc822, ++ 0xcd16, 0x046, ++ 0xcd17, 0xc844, ++ 0xcd18, 0x182f, ++ 0xcd19, 0xc013, ++ 0xcd1a, 0xf341, ++ 0xcd1b, 0xc01a, ++ 0xcd1c, 0x446, ++ 0xcd1d, 0xc024, ++ 0xcd1e, 0x1000, ++ 0xcd1f, 0xc025, ++ 0xcd20, 0xa00, ++ 0xcd21, 0xc026, ++ 0xcd22, 0xc0c, ++ 0xcd23, 0xc027, ++ 0xcd24, 0xc0c, ++ 0xcd25, 0xc029, ++ 0xcd26, 0x0a0, ++ 0xcd27, 0xc030, ++ 0xcd28, 0xa00, ++ 0xcd29, 0xc03c, ++ 0xcd2a, 0x01c, ++ 0xcd2b, 0x000, ++ 0xcd2c, 0x2b84, ++ 0xcd2d, 0x3c74, ++ 0xcd2e, 0x6435, ++ 0xcd2f, 0xdff4, ++ 0xcd30, 0x6435, ++ 0xcd31, 0x2806, ++ 0xcd32, 0x3006, ++ 0xcd33, 0x8565, ++ 0xcd34, 0x2b24, ++ 0xcd35, 0x3c24, ++ 0xcd36, 0x6436, ++ 0xcd37, 0x1002, ++ 0xcd38, 0x2b24, ++ 0xcd39, 0x3c24, ++ 0xcd3a, 0x6436, ++ 0xcd3b, 0x4045, ++ 0xcd3c, 0x8656, ++ 0xcd3d, 0x1002, ++ 0xcd3e, 0x2807, ++ 0xcd3f, 0x31a7, ++ 0xcd40, 0x20c4, ++ 0xcd41, 0x3c24, ++ 0xcd42, 0x6724, ++ 0xcd43, 0x1002, ++ 0xcd44, 0x2807, ++ 0xcd45, 0x3187, ++ 0xcd46, 0x20c4, ++ 0xcd47, 0x3c24, ++ 0xcd48, 0x6724, ++ 0xcd49, 0x1002, ++ 0xcd4a, 0x2514, ++ 0xcd4b, 0x3c64, ++ 0xcd4c, 0x6436, ++ 0xcd4d, 0xdff4, ++ 0xcd4e, 0x6436, ++ 0xcd4f, 0x1002, ++ 0xcd50, 0x2806, ++ 0xcd51, 0x3cb6, ++ 0xcd52, 0xc161, ++ 0xcd53, 0x6134, ++ 0xcd54, 0x6135, ++ 0xcd55, 0x5443, ++ 0xcd56, 0x303, ++ 0xcd57, 0x6524, ++ 0xcd58, 0x00b, ++ 0xcd59, 0x1002, ++ 0xcd5a, 0xd019, ++ 0xcd5b, 0x2104, ++ 0xcd5c, 0x3c24, ++ 0xcd5d, 0x2105, ++ 0xcd5e, 0x3805, ++ 0xcd5f, 0x6524, ++ 0xcd60, 0xdff4, ++ 0xcd61, 0x4005, ++ 0xcd62, 0x6524, ++ 0xcd63, 0x2e8d, ++ 0xcd64, 0x303d, ++ 0xcd65, 0x5dd3, ++ 0xcd66, 0x306, ++ 0xcd67, 0x2ff7, ++ 0xcd68, 0x38f7, ++ 0xcd69, 0x60b7, ++ 0xcd6a, 0xdffd, ++ 0xcd6b, 0x00a, ++ 0xcd6c, 0x1002, ++ 0xcd6d, 0 ++ }; ++ int i, err; ++ ++ err = set_phy_regs(phy, regs); ++ if (!err && modtype == phy_modtype_twinax_long) ++ err = set_phy_regs(phy, preemphasis); ++ if (err) ++ return err; ++ ++ msleep(50); ++ ++ for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2) ++ err = mdio_write(phy, MDIO_DEV_PMA_PMD, twinax_edc[i], ++ twinax_edc[i + 1]); ++ if (!err) ++ phy->priv = edc_twinax; ++ return err; ++} ++ ++static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) ++{ ++ int i, err; ++ unsigned int stat, data; ++ ++ err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL_I2C_CTRL, ++ (dev_addr << 8) | (1 << 8) | word_addr); ++ if (err) ++ return err; ++ ++ for (i = 0; i < 5; i++) { ++ msleep(1); ++ err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_STAT, &stat); ++ if (err) ++ return err; ++ if ((stat & 3) == 1) { ++ err = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL_I2C_DATA, ++ &data); ++ if (err) ++ return err; ++ return data >> 8; ++ } ++ } ++ CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n", ++ phy->addr, word_addr); ++ return -ETIMEDOUT; ++} ++ ++static int get_module_type(struct cphy *phy, int delay_ms) ++{ ++ int v; ++ unsigned int stat; ++ ++ v = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, &stat); ++ if (v) ++ return v; ++ ++ if (stat & (1 << 8)) /* module absent */ ++ return phy_modtype_none; ++ ++ if (delay_ms) ++ msleep(delay_ms); ++ ++ /* see SFF-8472 for below */ ++ v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3); ++ if (v < 0) ++ return v; ++ ++ if (v == 0x10) ++ return phy_modtype_sr; ++ if (v == 0x20) ++ return phy_modtype_lr; ++ if (v == 0x40) ++ return phy_modtype_lrm; ++ ++ v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6); ++ if (v < 0) ++ return v; ++ if (v != 4) ++ goto unknown; ++ ++ v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10); ++ if (v < 0) ++ return v; ++ ++ if (v & 0x80) { ++ v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); ++ if (v < 0) ++ return v; ++ return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; ++ } ++unknown: ++ return phy_modtype_unknown; ++} ++ ++static int ael2005_intr_enable(struct cphy *phy) ++{ ++ int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x200); ++ return err ? err : t3_phy_lasi_intr_enable(phy); ++} ++ ++static int ael2005_intr_disable(struct cphy *phy) ++{ ++ int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0x100); ++ return err ? err : t3_phy_lasi_intr_disable(phy); ++} ++ ++static int ael2005_intr_clear(struct cphy *phy) ++{ ++ int err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, 0xd00); ++ return err ? err : t3_phy_lasi_intr_clear(phy); ++} ++ ++static int ael2005_reset(struct cphy *phy, int wait) ++{ ++ static struct reg_val regs0[] = { ++ { MDIO_DEV_PMA_PMD, 0xc001, 0, 1 << 5 }, ++ { MDIO_DEV_PMA_PMD, 0xc017, 0, 1 << 5 }, ++ { MDIO_DEV_PMA_PMD, 0xc013, 0xffff, 0xf341 }, ++ { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 }, ++ { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8100 }, ++ { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0x8000 }, ++ { MDIO_DEV_PMA_PMD, 0xc210, 0xffff, 0 }, ++ { 0, 0, 0, 0 } ++ }; ++ static struct reg_val regs1[] = { ++ { MDIO_DEV_PMA_PMD, 0xca00, 0xffff, 0x0080 }, ++ { MDIO_DEV_PMA_PMD, 0xca12, 0xffff, 0 }, ++ { 0, 0, 0, 0 } ++ }; ++ ++ int err, lasi_ctrl; ++ ++ err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, &lasi_ctrl); ++ if (err) ++ return err; ++ ++ err = t3_phy_reset(phy, MDIO_DEV_PMA_PMD, 0); ++ if (err) ++ return err; ++ ++ msleep(125); ++ phy->priv = edc_none; ++ err = set_phy_regs(phy, regs0); ++ if (err) ++ return err; ++ ++ msleep(50); ++ ++ err = get_module_type(phy, 0); ++ if (err < 0) ++ return err; ++ phy->modtype = err; ++ ++ if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) ++ err = ael2005_setup_twinax_edc(phy, err); ++ else ++ err = ael2005_setup_sr_edc(phy); ++ if (err) ++ return err; ++ ++ err = set_phy_regs(phy, regs1); ++ if (err) ++ return err; ++ ++ /* reset wipes out interrupts, reenable them if they were on */ ++ if (lasi_ctrl & 1) ++ err = ael2005_intr_enable(phy); ++ return err; ++} ++ ++static int ael2005_intr_handler(struct cphy *phy) ++{ ++ unsigned int stat; ++ int ret, edc_needed, cause = 0; ++ ++ ret = mdio_read(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_STAT, &stat); ++ if (ret) ++ return ret; ++ ++ if (stat & AEL2005_MODDET_IRQ) { ++ ret = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL2005_GPIO_CTRL, ++ 0xd00); ++ if (ret) ++ return ret; ++ ++ /* modules have max 300 ms init time after hot plug */ ++ ret = get_module_type(phy, 300); ++ if (ret < 0) ++ return ret; ++ ++ phy->modtype = ret; ++ if (ret == phy_modtype_none) ++ edc_needed = phy->priv; /* on unplug retain EDC */ ++ else if (ret == phy_modtype_twinax || ++ ret == phy_modtype_twinax_long) ++ edc_needed = edc_twinax; ++ else ++ edc_needed = edc_sr; ++ ++ if (edc_needed != phy->priv) { ++ ret = ael2005_reset(phy, 0); ++ return ret ? ret : cphy_cause_module_change; ++ } ++ cause = cphy_cause_module_change; ++ } ++ ++ ret = t3_phy_lasi_intr_handler(phy); ++ if (ret < 0) ++ return ret; ++ ++ ret |= cause; ++ return ret ? ret : cphy_cause_link_change; ++} ++ ++static struct cphy_ops ael2005_ops = { ++ .reset = ael2005_reset, ++ .intr_enable = ael2005_intr_enable, ++ .intr_disable = ael2005_intr_disable, ++ .intr_clear = ael2005_intr_clear, ++ .intr_handler = ael2005_intr_handler, ++ .get_link_status = get_link_status_r, ++ .power_down = ael1002_power_down, ++}; ++ ++int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops) ++{ ++ cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops, ++ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | ++ SUPPORTED_IRQ, "10GBASE-R"); ++ msleep(125); ++ return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL_OPT_SETTINGS, 0, ++ 1 << 5); ++} ++ ++/* ++ * Get link status for a 10GBASE-X device. ++ */ ++static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, ++ int *duplex, int *fc) ++{ ++ if (link_ok) { ++ unsigned int stat0, stat1, stat2; ++ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, PMD_RSD, &stat0); ++ ++ if (!err) ++ err = mdio_read(phy, MDIO_DEV_PCS, PCS_STAT1_X, &stat1); ++ if (!err) ++ err = mdio_read(phy, MDIO_DEV_XGXS, XS_LN_STAT, &stat2); ++ if (err) ++ return err; ++ *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; ++ } ++ if (speed) ++ *speed = SPEED_10000; ++ if (duplex) ++ *duplex = DUPLEX_FULL; ++ return 0; ++} ++ + static struct cphy_ops qt2045_ops = { + .reset = ael1006_reset, + .intr_enable = t3_phy_lasi_intr_enable, + .intr_disable = t3_phy_lasi_intr_disable, + .intr_clear = t3_phy_lasi_intr_clear, + .intr_handler = t3_phy_lasi_intr_handler, +- .get_link_status = ael100x_get_link_status, ++ .get_link_status = get_link_status_x, + .power_down = ael1006_power_down, + }; + +Index: linux-2.6.27/drivers/net/cxgb3/common.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/common.h ++++ linux-2.6.27/drivers/net/cxgb3/common.h +@@ -547,7 +547,19 @@ enum { + /* PHY interrupt types */ + enum { + cphy_cause_link_change = 1, +- cphy_cause_fifo_error = 2 ++ cphy_cause_fifo_error = 2, ++ cphy_cause_module_change = 4, ++}; ++ ++/* PHY module types */ ++enum { ++ phy_modtype_none, ++ phy_modtype_sr, ++ phy_modtype_lr, ++ phy_modtype_lrm, ++ phy_modtype_twinax, ++ phy_modtype_twinax_long, ++ phy_modtype_unknown + }; + + /* PHY operations */ +@@ -572,7 +584,9 @@ struct cphy_ops { + + /* A PHY instance */ + struct cphy { +- int addr; /* PHY address */ ++ u8 addr; /* PHY address */ ++ u8 modtype; /* PHY module type */ ++ short priv; /* scratch pad */ + unsigned int caps; /* PHY capabilities */ + struct adapter *adapter; /* associated adapter */ + const char *desc; /* PHY description */ +@@ -793,6 +807,8 @@ int t3_ael1002_phy_prep(struct cphy *phy + int phy_addr, const struct mdio_ops *mdio_ops); + int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); ++int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops); + int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops); + int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, +Index: linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/cxgb3_main.c ++++ linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +@@ -209,6 +209,31 @@ void t3_os_link_changed(struct adapter * + } + } + ++/** ++ * t3_os_phymod_changed - handle PHY module changes ++ * @phy: the PHY reporting the module change ++ * @mod_type: new module type ++ * ++ * This is the OS-dependent handler for PHY module changes. It is ++ * invoked when a PHY module is removed or inserted for any OS-specific ++ * processing. ++ */ ++void t3_os_phymod_changed(struct adapter *adap, int port_id) ++{ ++ static const char *mod_str[] = { ++ NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" ++ }; ++ ++ const struct net_device *dev = adap->port[port_id]; ++ const struct port_info *pi = netdev_priv(dev); ++ ++ if (pi->phy.modtype == phy_modtype_none) ++ printk(KERN_INFO "%s: PHY module unplugged\n", dev->name); ++ else ++ printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name, ++ mod_str[pi->phy.modtype]); ++} ++ + static void cxgb_set_rxmode(struct net_device *dev) + { + struct t3_rx_mode rm; +Index: linux-2.6.27/drivers/net/cxgb3/t3_hw.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/t3_hw.c ++++ linux-2.6.27/drivers/net/cxgb3/t3_hw.c +@@ -511,7 +511,7 @@ static const struct port_type_info port_ + { t3_vsc8211_phy_prep }, + { NULL}, + { t3_xaui_direct_phy_prep }, +- { NULL }, ++ { t3_ael2005_phy_prep }, + { t3_qt2045_phy_prep }, + { t3_ael1006_phy_prep }, + { NULL }, +@@ -1728,6 +1728,8 @@ int t3_phy_intr_handler(struct adapter * + t3_link_changed(adapter, i); + if (phy_cause & cphy_cause_fifo_error) + p->phy.fifo_errors++; ++ if (phy_cause & cphy_cause_module_change) ++ t3_os_phymod_changed(adapter, i); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-allow-for-PHY-reset-status b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-allow-for-PHY-reset-status new file mode 100644 index 000000000..b3baf3b26 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-allow-for-PHY-reset-status @@ -0,0 +1,167 @@ +Commit-Id: 78e4689e908adc8334272756c32c9218d1967408 +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:38:01 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: allow for PHY reset status +Reference: bnc#446739 + +First step towards overall PHY layering re-organization. +Allow a status return when a PHY is reset. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +Index: linux-2.6.27/drivers/net/cxgb3/ael1002.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/ael1002.c ++++ linux-2.6.27/drivers/net/cxgb3/ael1002.c +@@ -119,11 +119,12 @@ static struct cphy_ops ael1002_ops = { + .power_down = ael1002_power_down, + }; + +-void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops) ++int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops) + { + cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); + ael100x_txon(phy); ++ return 0; + } + + static int ael1006_reset(struct cphy *phy, int wait) +@@ -174,11 +175,12 @@ static struct cphy_ops ael1006_ops = { + .power_down = ael1006_power_down, + }; + +-void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops) ++int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops) + { + cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); + ael100x_txon(phy); ++ return 0; + } + + static struct cphy_ops qt2045_ops = { +@@ -191,8 +193,8 @@ static struct cphy_ops qt2045_ops = { + .power_down = ael1006_power_down, + }; + +-void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops) ++int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops) + { + unsigned int stat; + +@@ -205,6 +207,7 @@ void t3_qt2045_phy_prep(struct cphy *phy + if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && + stat == 0xffff) + phy->addr = 1; ++ return 0; + } + + static int xaui_direct_reset(struct cphy *phy, int wait) +@@ -250,8 +253,9 @@ static struct cphy_ops xaui_direct_ops = + .power_down = xaui_direct_power_down, + }; + +-void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops) ++int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops) + { + cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops); ++ return 0; + } +Index: linux-2.6.27/drivers/net/cxgb3/common.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/common.h ++++ linux-2.6.27/drivers/net/cxgb3/common.h +@@ -203,8 +203,8 @@ struct adapter_info { + }; + + struct port_type_info { +- void (*phy_prep)(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *ops); ++ int (*phy_prep)(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *ops); + unsigned int caps; + const char *desc; + }; +@@ -775,14 +775,14 @@ int t3_sge_read_rspq(struct adapter *ada + int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits); + +-void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops); +-void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops); +-void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops); +-void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, +- const struct mdio_ops *mdio_ops); +-void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops); ++int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops); ++int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops); ++int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops); ++int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, ++ const struct mdio_ops *mdio_ops); ++int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops); + #endif /* __CHELSIO_COMMON_H */ +Index: linux-2.6.27/drivers/net/cxgb3/t3_hw.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/t3_hw.c ++++ linux-2.6.27/drivers/net/cxgb3/t3_hw.c +@@ -3626,8 +3626,11 @@ int t3_prep_adapter(struct adapter *adap + ++j; + + p->port_type = &port_types[adapter->params.vpd.port_type[j]]; +- p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, +- ai->mdio_ops); ++ ret = p->port_type->phy_prep(&p->phy, adapter, ++ ai->phy_base_addr + j, ++ ai->mdio_ops); ++ if (ret) ++ return ret; + mac_prep(&p->mac, adapter, j); + ++j; + +@@ -3674,9 +3677,11 @@ int t3_replay_prep_adapter(struct adapte + while (!adapter->params.vpd.port_type[j]) + ++j; + +- p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, +- ai->mdio_ops); +- ++ ret = p->port_type->phy_prep(&p->phy, adapter, ++ ai->phy_base_addr + j, ++ ai->mdio_ops); ++ if (ret) ++ return ret; + p->phy.ops->power_down(&p->phy, 1); + ++j; + } +Index: linux-2.6.27/drivers/net/cxgb3/vsc8211.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/vsc8211.c ++++ linux-2.6.27/drivers/net/cxgb3/vsc8211.c +@@ -221,8 +221,9 @@ static struct cphy_ops vsc8211_ops = { + .power_down = vsc8211_power_down, + }; + +-void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *mdio_ops) ++int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *mdio_ops) + { + cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops); ++ return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-commnonize-LASI-phy-code b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-commnonize-LASI-phy-code new file mode 100644 index 000000000..969df00c6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-commnonize-LASI-phy-code @@ -0,0 +1,251 @@ +Commit-Id: 9b1e36566c5fafbcc732c971acfcf8580332931a +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:39:31 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: commnonize LASI phy code +Reference: bnc#446739 + +Add generic code to manage interrupt driven PHYs. +Do not reset the phy after link parameters update, +the new values might get lost. +Return early from link change notification +when the link parameters remain unchanged. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +Index: linux-2.6.27/drivers/net/cxgb3/ael1002.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/ael1002.c ++++ linux-2.6.27/drivers/net/cxgb3/ael1002.c +@@ -39,9 +39,6 @@ enum { + AEL1002_PWR_DOWN_LO = 0xc012, + AEL1002_XFI_EQL = 0xc015, + AEL1002_LB_EN = 0xc017, +- +- LASI_CTRL = 0x9002, +- LASI_STAT = 0x9005 + }; + + static void ael100x_txon(struct cphy *phy) +@@ -134,33 +131,6 @@ static int ael1006_reset(struct cphy *ph + return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); + } + +-static int ael1006_intr_enable(struct cphy *phy) +-{ +- return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); +-} +- +-static int ael1006_intr_disable(struct cphy *phy) +-{ +- return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); +-} +- +-static int ael1006_intr_clear(struct cphy *phy) +-{ +- u32 val; +- +- return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); +-} +- +-static int ael1006_intr_handler(struct cphy *phy) +-{ +- unsigned int status; +- int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); +- +- if (err) +- return err; +- return (status & 1) ? cphy_cause_link_change : 0; +-} +- + static int ael1006_power_down(struct cphy *phy, int enable) + { + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, +@@ -169,10 +139,10 @@ static int ael1006_power_down(struct cph + + static struct cphy_ops ael1006_ops = { + .reset = ael1006_reset, +- .intr_enable = ael1006_intr_enable, +- .intr_disable = ael1006_intr_disable, +- .intr_clear = ael1006_intr_clear, +- .intr_handler = ael1006_intr_handler, ++ .intr_enable = t3_phy_lasi_intr_enable, ++ .intr_disable = t3_phy_lasi_intr_disable, ++ .intr_clear = t3_phy_lasi_intr_clear, ++ .intr_handler = t3_phy_lasi_intr_handler, + .get_link_status = ael100x_get_link_status, + .power_down = ael1006_power_down, + }; +@@ -189,10 +159,10 @@ int t3_ael1006_phy_prep(struct cphy *phy + + static struct cphy_ops qt2045_ops = { + .reset = ael1006_reset, +- .intr_enable = ael1006_intr_enable, +- .intr_disable = ael1006_intr_disable, +- .intr_clear = ael1006_intr_clear, +- .intr_handler = ael1006_intr_handler, ++ .intr_enable = t3_phy_lasi_intr_enable, ++ .intr_disable = t3_phy_lasi_intr_disable, ++ .intr_clear = t3_phy_lasi_intr_clear, ++ .intr_handler = t3_phy_lasi_intr_handler, + .get_link_status = ael100x_get_link_status, + .power_down = ael1006_power_down, + }; +Index: linux-2.6.27/drivers/net/cxgb3/common.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/common.h ++++ linux-2.6.27/drivers/net/cxgb3/common.h +@@ -522,7 +522,20 @@ enum { + MDIO_DEV_PMA_PMD = 1, + MDIO_DEV_WIS = 2, + MDIO_DEV_PCS = 3, +- MDIO_DEV_XGXS = 4 ++ MDIO_DEV_XGXS = 4, ++ MDIO_DEV_ANEG = 7, ++ MDIO_DEV_VEND1 = 30, ++ MDIO_DEV_VEND2 = 31 ++}; ++ ++/* LASI control and status registers */ ++enum { ++ RX_ALARM_CTRL = 0x9000, ++ TX_ALARM_CTRL = 0x9001, ++ LASI_CTRL = 0x9002, ++ RX_ALARM_STAT = 0x9003, ++ TX_ALARM_STAT = 0x9004, ++ LASI_STAT = 0x9005 + }; + + /* PHY loopback direction */ +@@ -665,6 +678,10 @@ int t3_mdio_change_bits(struct cphy *phy + int t3_phy_reset(struct cphy *phy, int mmd, int wait); + int t3_phy_advertise(struct cphy *phy, unsigned int advert); + int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); ++int t3_phy_lasi_intr_enable(struct cphy *phy); ++int t3_phy_lasi_intr_disable(struct cphy *phy); ++int t3_phy_lasi_intr_clear(struct cphy *phy); ++int t3_phy_lasi_intr_handler(struct cphy *phy); + + void t3_intr_enable(struct adapter *adapter); + void t3_intr_disable(struct adapter *adapter); +Index: linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/cxgb3_main.c ++++ linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +@@ -1586,11 +1586,22 @@ static int speed_duplex_to_caps(int spee + + static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) + { ++ int cap; + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + +- if (!(lc->supported & SUPPORTED_Autoneg)) +- return -EOPNOTSUPP; /* can't change speed/duplex */ ++ if (!(lc->supported & SUPPORTED_Autoneg)) { ++ /* ++ * PHY offers a single speed/duplex. See if that's what's ++ * being requested. ++ */ ++ if (cmd->autoneg == AUTONEG_DISABLE) { ++ cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); ++ if (lc->supported & cap) ++ return 0; ++ } ++ return -EINVAL; ++ } + + if (cmd->autoneg == AUTONEG_DISABLE) { + int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); +@@ -2281,7 +2292,7 @@ static int cxgb_ioctl(struct net_device + mmd = data->phy_id >> 8; + if (!mmd) + mmd = MDIO_DEV_PCS; +- else if (mmd > MDIO_DEV_XGXS) ++ else if (mmd > MDIO_DEV_VEND2) + return -EINVAL; + + ret = +@@ -2307,7 +2318,7 @@ static int cxgb_ioctl(struct net_device + mmd = data->phy_id >> 8; + if (!mmd) + mmd = MDIO_DEV_PCS; +- else if (mmd > MDIO_DEV_XGXS) ++ else if (mmd > MDIO_DEV_VEND2) + return -EINVAL; + + ret = +Index: linux-2.6.27/drivers/net/cxgb3/t3_hw.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/t3_hw.c ++++ linux-2.6.27/drivers/net/cxgb3/t3_hw.c +@@ -442,6 +442,33 @@ int t3_set_phy_speed_duplex(struct cphy + return mdio_write(phy, 0, MII_BMCR, ctl); + } + ++int t3_phy_lasi_intr_enable(struct cphy *phy) ++{ ++ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); ++} ++ ++int t3_phy_lasi_intr_disable(struct cphy *phy) ++{ ++ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); ++} ++ ++int t3_phy_lasi_intr_clear(struct cphy *phy) ++{ ++ u32 val; ++ ++ return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); ++} ++ ++int t3_phy_lasi_intr_handler(struct cphy *phy) ++{ ++ unsigned int status; ++ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); ++ ++ if (err) ++ return err; ++ return (status & 1) ? cphy_cause_link_change : 0; ++} ++ + static const struct adapter_info t3_adap_info[] = { + {2, 0, + F_GPIO2_OEN | F_GPIO4_OEN | +@@ -1132,6 +1159,15 @@ void t3_link_changed(struct adapter *ada + + phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + ++ if (lc->requested_fc & PAUSE_AUTONEG) ++ fc &= lc->requested_fc; ++ else ++ fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); ++ ++ if (link_ok == lc->link_ok && speed == lc->speed && ++ duplex == lc->duplex && fc == lc->fc) ++ return; /* nothing changed */ ++ + if (link_ok != lc->link_ok && adapter->params.rev > 0 && + uses_xaui(adapter)) { + if (link_ok) +@@ -1142,10 +1178,6 @@ void t3_link_changed(struct adapter *ada + lc->link_ok = link_ok; + lc->speed = speed < 0 ? SPEED_INVALID : speed; + lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; +- if (lc->requested_fc & PAUSE_AUTONEG) +- fc &= lc->requested_fc; +- else +- fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { + /* Set MAC speed, duplex, and flow control to match PHY. */ +@@ -1191,7 +1223,6 @@ int t3_link_start(struct cphy *phy, stru + fc); + /* Also disables autoneg */ + phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); +- phy->ops->reset(phy, 0); + } else + phy->ops->autoneg_enable(phy); + } else { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-eeprom-read-fixes.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-eeprom-read-fixes.patch new file mode 100644 index 000000000..bdbd00ec2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-eeprom-read-fixes.patch @@ -0,0 +1,49 @@ +Subject: [1/2,2.6.28] cxgb3 - eeprom read fixes +Date: Sat, 08 Nov 2008 22:55:28 -0000 +From: Divy Le Ray +Acked-by: Karsten Keil +Reference: bnc#446739 + +From: Divy Le Ray + +Protect against invalid phy entries in the eeprom. +Extend eeprom access timeout. + +Signed-off-by: Divy Le Ray +--- + + drivers/net/cxgb3/t3_hw.c | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + + +-- +To unsubscribe from this list: send the line "unsubscribe netdev" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + +diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c +index 968f64b..9a0898b 100644 +--- a/drivers/net/cxgb3/t3_hw.c ++++ b/drivers/net/cxgb3/t3_hw.c +@@ -572,7 +572,7 @@ struct t3_vpd { + u32 pad; /* for multiple-of-4 sizing and alignment */ + }; + +-#define EEPROM_MAX_POLL 4 ++#define EEPROM_MAX_POLL 40 + #define EEPROM_STAT_ADDR 0x4000 + #define VPD_BASE 0xc00 + +@@ -3690,6 +3690,12 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, + ; + + pti = &port_types[adapter->params.vpd.port_type[j]]; ++ if (!pti->phy_prep) { ++ CH_ALERT(adapter, "Invalid port type index %d\n", ++ adapter->params.vpd.port_type[j]); ++ return -EINVAL; ++ } ++ + ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, + ai->mdio_ops); + if (ret) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-enable-lro-through-ethtool b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-enable-lro-through-ethtool new file mode 100644 index 000000000..353ec0ff7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-enable-lro-through-ethtool @@ -0,0 +1,133 @@ +From: Divy Le Ray +Date: Wed, 29 Oct 2008 05:40:32 +0000 (-0700) +Subject: cxgb3 - enable lro control through ethtool +Acked-by: Karsten Keil +Reference: bnc#446739 + + +cxgb3 - enable lro control through ethtool + +Implement ethtool's get_flags and set_flags methods. +It enables ethtool to control the LRO settings. + +Signed-off-by: Divy Le Ray +Signed-off-by: Jeff Garzik +--- + +Index: linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/cxgb3_main.c ++++ linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +@@ -470,6 +470,36 @@ static void enable_all_napi(struct adapt + } + + /** ++ * set_qset_lro - Turn a queue set's LRO capability on and off ++ * @dev: the device the qset is attached to ++ * @qset_idx: the queue set index ++ * @val: the LRO switch ++ * ++ * Sets LRO on or off for a particular queue set. ++ * the device's features flag is updated to reflect the LRO ++ * capability when all queues belonging to the device are ++ * in the same state. ++ */ ++static void set_qset_lro(struct net_device *dev, int qset_idx, int val) ++{ ++ struct port_info *pi = netdev_priv(dev); ++ struct adapter *adapter = pi->adapter; ++ int i, lro_on = 1; ++ ++ adapter->params.sge.qset[qset_idx].lro = !!val; ++ adapter->sge.qs[qset_idx].lro_enabled = !!val; ++ ++ /* let ethtool report LRO on only if all queues are LRO enabled */ ++ for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; ++i) ++ lro_on &= adapter->params.sge.qset[i].lro; ++ ++ if (lro_on) ++ dev->features |= NETIF_F_LRO; ++ else ++ dev->features &= ~NETIF_F_LRO; ++} ++ ++/** + * setup_sge_qsets - configure SGE Tx/Rx/response queues + * @adap: the adapter + * +@@ -492,8 +522,7 @@ static int setup_sge_qsets(struct adapte + pi->qs = &adap->sge.qs[pi->first_qset]; + for (j = pi->first_qset; j < pi->first_qset + pi->nqsets; + ++j, ++qset_idx) { +- if (!pi->rx_csum_offload) +- adap->params.sge.qset[qset_idx].lro = 0; ++ set_qset_lro(dev, qset_idx, pi->rx_csum_offload); + err = t3_sge_alloc_qset(adap, qset_idx, 1, + (adap->flags & USING_MSIX) ? qset_idx + 1 : + irq_idx, +@@ -1637,13 +1666,10 @@ static int set_rx_csum(struct net_device + + p->rx_csum_offload = data; + if (!data) { +- struct adapter *adap = p->adapter; + int i; + +- for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { +- adap->params.sge.qset[i].lro = 0; +- adap->sge.qs[i].lro_enabled = 0; +- } ++ for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) ++ set_qset_lro(dev, i, 0); + } + return 0; + } +@@ -1798,6 +1824,25 @@ static void get_wol(struct net_device *d + memset(&wol->sopass, 0, sizeof(wol->sopass)); + } + ++static int cxgb3_set_flags(struct net_device *dev, u32 data) ++{ ++ struct port_info *pi = netdev_priv(dev); ++ int i; ++ ++ if (data & ETH_FLAG_LRO) { ++ if (!pi->rx_csum_offload) ++ return -EINVAL; ++ ++ for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) ++ set_qset_lro(dev, i, 1); ++ ++ } else ++ for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) ++ set_qset_lro(dev, i, 0); ++ ++ return 0; ++} ++ + static const struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, +@@ -1827,6 +1872,8 @@ static const struct ethtool_ops cxgb_eth + .get_regs = get_regs, + .get_wol = get_wol, + .set_tso = ethtool_op_set_tso, ++ .get_flags = ethtool_op_get_flags, ++ .set_flags = cxgb3_set_flags, + }; + + static int in_range(int val, int lo, int hi) +@@ -1943,11 +1990,9 @@ static int cxgb_extension_ioctl(struct n + } + } + } +- if (t.lro >= 0) { +- struct sge_qset *qs = &adapter->sge.qs[t.qset_idx]; +- q->lro = t.lro; +- qs->lro_enabled = t.lro; +- } ++ if (t.lro >= 0) ++ set_qset_lro(dev, t.qset_idx, t.lro); ++ + break; + } + case CHELSIO_GET_QSET_PARAMS:{ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-fix_lro_alignment.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-fix_lro_alignment.patch new file mode 100644 index 000000000..312372796 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-fix_lro_alignment.patch @@ -0,0 +1,31 @@ +From: Divy Le Ray +Date: Mon, 19 Jan 2009 06:01:32 +0000 (-0800) +Subject: cxgb3: Fix LRO misalignment +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-2.6.git;a=commitdiff_plain;h=eed087e367591fc08490d7c6c2779b4b72c8f20c + +cxgb3: Fix LRO misalignment + +The lro manager's frag_align_pad setting was missing, +leading to misaligned access to the skb passed up +to the stack. + +Tested-by: Rick Jones +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller +Acked-by: John Jolly +--- + +--- + drivers/net/cxgb3/sge.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/cxgb3/sge.c ++++ b/drivers/net/cxgb3/sge.c +@@ -2098,6 +2098,7 @@ static void init_lro_mgr(struct sge_qset + { + lro_mgr->dev = qs->netdev; + lro_mgr->features = LRO_F_NAPI; ++ lro_mgr->frag_align_pad = NET_IP_ALIGN; + lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; + lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + lro_mgr->max_desc = T3_MAX_LRO_SES; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-fix_lro_switch.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-fix_lro_switch.patch new file mode 100644 index 000000000..40d691471 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-fix_lro_switch.patch @@ -0,0 +1,32 @@ +From: Divy Le Ray +Date: Thu, 5 Feb 2009 00:31:39 +0000 (-0800) +Subject: cxgb3: Fix lro switch +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-2.6.git;a=commitdiff_plain;h=65ab8385b67854792e89267907f9fcb27e779f95 + +cxgb3: Fix lro switch + +The LRO switch is always set to 1 in the rx processing loop. +It breaks the accelerated iSCSI receive traffic. +Fix its computation. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller +Acked-by: John Jolly +--- + +--- + drivers/net/cxgb3/sge.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/net/cxgb3/sge.c ++++ b/drivers/net/cxgb3/sge.c +@@ -2270,8 +2270,7 @@ no_mem: + } else if ((len = ntohl(r->len_cq)) != 0) { + struct sge_fl *fl; + +- if (eth) +- lro = qs->lro_enabled && is_eth_tcp(rss_hi); ++ lro &= eth && is_eth_tcp(rss_hi); + + fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; + if (fl->use_pages) { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-get_drvinfo-deadlock.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-get_drvinfo-deadlock.patch new file mode 100644 index 000000000..1de6cc135 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-get_drvinfo-deadlock.patch @@ -0,0 +1,79 @@ +From: Steve Wise +Subject: RDMA/cxgb3: deadlock in iw_cxgb3 can cause hang when configuring interface. +References: bnc#430998 + +When the iw_cxgb3 module's cxgb3_client "add" func gets called by the +cxgb3 module, the iwarp driver ends up calling the ethtool ops get_drvinfo +function in cxgb3 to get the fw version and other info. Currently the +iwarp driver grabs the rtnl lock around this down call to serialize. +As of 2.6.27 or so, things changed such that the rtnl lock is held around +the call to the netdev driver open function. Also the cxgb3_client "add" +function doesn't get called if the device is down. + +So, if you load cxgb3, then load iw_cxgb3, then ifconfig up the device, +the iw_cxgb3 add func gets called with the rtnl_lock held. If you +load cxgb3, ifconfig up the device, then load iw_cxgb3, the add func +gets called without the rtnl_lock held. The former causes the deadlock, +the latter does not. + +In addition, there are iw_cxgb3 sysfs handlers that also can call +down into cxgb3 to gather the fw and hw versions. These can be called +concurrently on different processors and at any time. Thus we need to +push this serialization down in the cxgb3 driver get_drvinfo func. + +The fix is to remove rtnl lock usage, and use a per-device lock in cxgb3. + +Signed-off-by: Steve Wise +Acked-by: Divy Le Ray +Acked-by: John Jolly + +--- + drivers/infiniband/hw/cxgb3/iwch_provider.c | 6 ------ + drivers/net/cxgb3/cxgb3_main.c | 2 ++ + 2 files changed, 2 insertions(+), 6 deletions(-) + +--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c ++++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c +@@ -1102,9 +1102,7 @@ static u64 fw_vers_string_to_u64(struct + char *cp, *next; + unsigned fw_maj, fw_min, fw_mic; + +- rtnl_lock(); + lldev->ethtool_ops->get_drvinfo(lldev, &info); +- rtnl_unlock(); + + next = info.fw_version + 1; + cp = strsep(&next, "."); +@@ -1195,9 +1193,7 @@ static ssize_t show_fw_ver(struct device + struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; + + PDBG("%s dev 0x%p\n", __func__, dev); +- rtnl_lock(); + lldev->ethtool_ops->get_drvinfo(lldev, &info); +- rtnl_unlock(); + return sprintf(buf, "%s\n", info.fw_version); + } + +@@ -1210,9 +1206,7 @@ static ssize_t show_hca(struct device *d + struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev; + + PDBG("%s dev 0x%p\n", __func__, dev); +- rtnl_lock(); + lldev->ethtool_ops->get_drvinfo(lldev, &info); +- rtnl_unlock(); + return sprintf(buf, "%s\n", info.driver); + } + +--- a/drivers/net/cxgb3/cxgb3_main.c ++++ b/drivers/net/cxgb3/cxgb3_main.c +@@ -1298,8 +1298,10 @@ static void get_drvinfo(struct net_devic + u32 fw_vers = 0; + u32 tp_vers = 0; + ++ spin_lock(&adapter->stats_lock); + t3_get_fw_version(adapter, &fw_vers); + t3_get_tp_version(adapter, &tp_vers); ++ spin_unlock(&adapter->stats_lock); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-handle-err-inject.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-handle-err-inject.patch new file mode 100644 index 000000000..b0f41eb50 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-handle-err-inject.patch @@ -0,0 +1,29 @@ +From: wenxiong@us.ibm.com +Subject: network command hung the system after manully errinjct 6 times EEH + errors. +References: bnc#497648 + +Acked-by: John Jolly +diff -Nuarp cxgb3.sles11_ga/drivers/net/cxgb3/cxgb3_main.c cxgb3.patch.51726/drivers/net/cxgb3/cxgb3_main.c +--- cxgb3.sles11_ga/drivers/net/cxgb3/cxgb3_main.c 2009-05-05 14:21:10.000000000 -0500 ++++ cxgb3.patch.51726/drivers/net/cxgb3/cxgb3_main.c 2009-05-05 15:37:03.000000000 -0500 +@@ -1222,6 +1222,9 @@ static int cxgb_close(struct net_device + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + ++ if (!adapter->open_device_map) ++ return 0; ++ + t3_port_intr_disable(adapter, pi->port_id); + netif_stop_queue(dev); + pi->phy.ops->power_down(&pi->phy, 1); +@@ -2738,6 +2741,9 @@ static pci_ers_result_t t3_io_error_dete + struct adapter *adapter = pci_get_drvdata(pdev); + int ret; + ++ if (state == pci_channel_io_perm_failure) ++ return PCI_ERS_RESULT_DISCONNECT; ++ + ret = t3_adapter_error(adapter, 0); + + /* Request a slot reset. */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-private-iscsi-ip-addresses b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-private-iscsi-ip-addresses new file mode 100644 index 000000000..4c13c935d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-private-iscsi-ip-addresses @@ -0,0 +1,319 @@ +Subject: cxgb3 - manage private iSCSI IP addresses +From: Karen Xie +References: FATE#304154,bnc#433500 + +The accelerated iSCSI traffic uses a private IP address unknown to the OS. +Create a per port sysfs entry to pass an IP address to the NIC driver, +and a control call for the iSCSI driver to grab it. +The IP address is required in both drivers to manage ARP requests and connection set up. + +Signed-off-by: Karen Xie +Signed-off-by: Chandra Seetharaman +Signed-off-by: Hannes Reinecke + +--- +--- + drivers/net/cxgb3/adapter.h | 1 + drivers/net/cxgb3/cxgb3_ctl_defs.h | 9 ++++ + drivers/net/cxgb3/cxgb3_main.c | 46 +++++++++++++++++++++++++ + drivers/net/cxgb3/cxgb3_offload.c | 45 +++++++++++++++++------- + drivers/net/cxgb3/sge.c | 68 ++++++++++++++++++++++++++++++++++--- + 5 files changed, 152 insertions(+), 17 deletions(-) + +--- a/drivers/net/cxgb3/adapter.h ++++ b/drivers/net/cxgb3/adapter.h +@@ -64,6 +64,7 @@ struct port_info { + struct link_config link_config; + struct net_device_stats netstats; + int activity; ++ __be32 iscsi_ipv4addr; + }; + + enum { /* adapter flags */ +--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h ++++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h +@@ -57,6 +57,9 @@ enum { + RDMA_GET_MIB = 19, + + GET_RX_PAGE_INFO = 50, ++ ++ GET_ISCSI_IPV4ADDR = 51, ++ SET_ISCSI_IPV4ADDR = 52, + }; + + /* +@@ -86,6 +89,12 @@ struct iff_mac { + u16 vlan_tag; + }; + ++/* Structure used to request a port's iSCSI IPv4 address */ ++struct iscsi_ipv4addr { ++ struct net_device *dev; /* the net_device */ ++ __be32 ipv4addr; /* the return iSCSI IPv4 address */ ++}; ++ + struct pci_dev; + + /* +--- a/drivers/net/cxgb3/cxgb3_main.c ++++ b/drivers/net/cxgb3/cxgb3_main.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + #include + + #include "common.h" +@@ -688,6 +689,47 @@ static struct attribute *offload_attrs[] + + static struct attribute_group offload_attr_group = {.attrs = offload_attrs }; + ++static ssize_t iscsi_ipv4addr_attr_show(struct device *d, char *buf) ++{ ++ struct port_info *pi = netdev_priv(to_net_dev(d)); ++ ++ __be32 a = pi->iscsi_ipv4addr; ++ return sprintf(buf, NIPQUAD_FMT "\n", NIPQUAD(a)); ++} ++ ++static ssize_t iscsi_ipv4addr_attr_store(struct device *d, ++ const char *buf, size_t len) ++{ ++ struct port_info *pi = netdev_priv(to_net_dev(d)); ++ ++ pi->iscsi_ipv4addr = in_aton(buf); ++ return len; ++} ++ ++#define ISCSI_IPADDR_ATTR(name) \ ++static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ ++ char *buf) \ ++{ \ ++ return iscsi_ipv4addr_attr_show(d, buf); \ ++} \ ++static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ ++ const char *buf, size_t len) \ ++{ \ ++ return iscsi_ipv4addr_attr_store(d, buf, len); \ ++} \ ++static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) ++ ++ISCSI_IPADDR_ATTR(iscsi_ipv4addr); ++ ++static struct attribute *iscsi_offload_attrs[] = { ++ &dev_attr_iscsi_ipv4addr.attr, ++ NULL ++}; ++ ++static struct attribute_group iscsi_offload_attr_group = { ++ .attrs = iscsi_offload_attrs ++}; ++ + /* + * Sends an sk_buff to an offload queue driver + * after dealing with any active network taps. +@@ -1079,6 +1121,7 @@ static int cxgb_open(struct net_device * + if (err) + printk(KERN_WARNING + "Could not initialize offload capabilities\n"); ++ sysfs_create_group(&dev->dev.kobj, &iscsi_offload_attr_group); + } + + link_start(dev); +@@ -1101,6 +1144,9 @@ static int cxgb_close(struct net_device + netif_carrier_off(dev); + t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); + ++ if (is_offload(adapter) && !ofld_disable) ++ sysfs_remove_group(&dev->dev.kobj, &iscsi_offload_attr_group); ++ + spin_lock(&adapter->work_lock); /* sync with update task */ + clear_bit(pi->port_id, &adapter->open_device_map); + spin_unlock(&adapter->work_lock); +--- a/drivers/net/cxgb3/cxgb3_offload.c ++++ b/drivers/net/cxgb3/cxgb3_offload.c +@@ -182,7 +182,9 @@ static struct net_device *get_iff_from_m + static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, + void *data) + { ++ int i; + int ret = 0; ++ unsigned int val = 0; + struct ulp_iscsi_info *uiip = data; + + switch (req) { +@@ -191,31 +193,36 @@ static int cxgb_ulp_iscsi_ctl(struct ada + uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); + uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); + uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); ++ val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ); ++ for (i = 0; i < 4; i++, val >>= 8) ++ uiip->pgsz_factor[i] = val & 0xFF; + /* + * On tx, the iscsi pdu has to be <= tx page size and has to + * fit into the Tx PM FIFO. + */ + uiip->max_txsz = min(adapter->params.tp.tx_pg_size, + t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); +- /* on rx, the iscsi pdu has to be < rx page size and the +- whole pdu + cpl headers has to fit into one sge buffer */ +- uiip->max_rxsz = min_t(unsigned int, +- adapter->params.tp.rx_pg_size, +- (adapter->sge.qs[0].fl[1].buf_size - +- sizeof(struct cpl_rx_data) * 2 - +- sizeof(struct cpl_rx_data_ddp))); ++ /* ++ * on rx, the iscsi pdu has to be < rx page size and the ++ * the max rx data length programmed in TP ++ */ ++ uiip->max_rxsz = min(adapter->params.tp.rx_pg_size, ++ ((t3_read_reg(adapter, A_TP_PARA_REG2)) ++ >> S_MAXRXDATA) & M_MAXRXDATA); + break; + case ULP_ISCSI_SET_PARAMS: + t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); + /* set MaxRxData and MaxCoalesceSize to 16224 */ + t3_write_reg(adapter, A_TP_PARA_REG2, 0x3f603f60); + /* program the ddp page sizes */ +- { +- int i; +- unsigned int val = 0; +- for (i = 0; i < 4; i++) +- val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); +- if (val) ++ for (val = 0, i = 0; i < 4; i++) ++ val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); ++ if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) { ++ printk(KERN_INFO ++ "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n", ++ adapter->name, val, uiip->pgsz_factor[0], ++ uiip->pgsz_factor[1], uiip->pgsz_factor[2], ++ uiip->pgsz_factor[3]); + t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); + } + break; +@@ -407,6 +414,18 @@ static int cxgb_offload_ctl(struct t3cde + rx_page_info->page_size = tp->rx_pg_size; + rx_page_info->num = tp->rx_num_pgs; + break; ++ case GET_ISCSI_IPV4ADDR: { ++ struct iscsi_ipv4addr *p = data; ++ struct port_info *pi = netdev_priv(p->dev); ++ p->ipv4addr = pi->iscsi_ipv4addr; ++ break; ++ } ++ case SET_ISCSI_IPV4ADDR: { ++ struct iscsi_ipv4addr *p = data; ++ struct port_info *pi = netdev_priv(p->dev); ++ pi->iscsi_ipv4addr = p->ipv4addr; ++ break; ++ } + default: + return -EOPNOTSUPP; + } +--- a/drivers/net/cxgb3/sge.c ++++ b/drivers/net/cxgb3/sge.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include "common.h" + #include "regs.h" + #include "sge_defs.h" +@@ -1856,6 +1857,53 @@ static void restart_tx(struct sge_qset * + } + + /** ++ * cxgb3_arp_process - process an ARP request probing a private IP address ++ * @adapter: the adapter ++ * @skb: the skbuff containing the ARP request ++ * ++ * Check if the ARP request is probing the private IP address ++ * dedicated to iSCSI, generate an ARP reply if so. ++ */ ++static void cxgb3_arp_process(struct adapter *adapter, struct sk_buff *skb) ++{ ++ struct net_device *dev = skb->dev; ++ struct port_info *pi; ++ struct arphdr *arp; ++ unsigned char *arp_ptr; ++ unsigned char *sha; ++ __be32 sip, tip; ++ ++ if (!dev) ++ return; ++ ++ skb_reset_network_header(skb); ++ arp = arp_hdr(skb); ++ ++ if (arp->ar_op != htons(ARPOP_REQUEST)) ++ return; ++ ++ arp_ptr = (unsigned char *)(arp + 1); ++ sha = arp_ptr; ++ arp_ptr += dev->addr_len; ++ memcpy(&sip, arp_ptr, sizeof(sip)); ++ arp_ptr += sizeof(sip); ++ arp_ptr += dev->addr_len; ++ memcpy(&tip, arp_ptr, sizeof(tip)); ++ ++ pi = netdev_priv(dev); ++ if (tip != pi->iscsi_ipv4addr) ++ return; ++ ++ arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, ++ dev->dev_addr, sha); ++} ++ ++static inline int is_arp(struct sk_buff *skb) ++{ ++ return skb->protocol == htons(ETH_P_ARP); ++} ++ ++/** + * rx_eth - process an ingress ethernet packet + * @adap: the adapter + * @rq: the response queue that received the packet +@@ -1879,7 +1927,7 @@ static void rx_eth(struct adapter *adap, + pi = netdev_priv(skb->dev); + if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) && + !p->fragment) { +- rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; ++ qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + skb->ip_summed = CHECKSUM_NONE; +@@ -1894,16 +1942,28 @@ static void rx_eth(struct adapter *adap, + grp, + ntohs(p->vlan), + p); +- else ++ else { ++ if (unlikely(pi->iscsi_ipv4addr && ++ is_arp(skb))) { ++ unsigned short vtag = ntohs(p->vlan) & ++ VLAN_VID_MASK; ++ skb->dev = vlan_group_get_device(grp, ++ vtag); ++ cxgb3_arp_process(adap, skb); ++ } + __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), +- rq->polling); ++ rq->polling); ++ } + else + dev_kfree_skb_any(skb); + } else if (rq->polling) { + if (lro) + lro_receive_skb(&qs->lro_mgr, skb, p); +- else ++ else { ++ if (unlikely(pi->iscsi_ipv4addr && is_arp(skb))) ++ cxgb3_arp_process(adap, skb); + netif_receive_skb(skb); ++ } + } else + netif_rx(skb); + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-ser.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-ser.patch new file mode 100644 index 000000000..5d487f030 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-ser.patch @@ -0,0 +1,330 @@ +Subject: reset the adapter on fatal error +From: Divy Le Ray +References: 466062 - LTC51042 + +when a fatal error occurs, bring ports down, reset the chip, +and bring ports back up. + +Factorize code used for both EEH and fatal error recovery. +Fix timer usage when bringing up/resetting sge queue sets. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller +Signed-off-by: Olaf Hering +--- + drivers/net/cxgb3/adapter.h | 1 + drivers/net/cxgb3/common.h | 1 + drivers/net/cxgb3/cxgb3_main.c | 166 +++++++++++++++++++++++++++-------------- + drivers/net/cxgb3/sge.c | 9 -- + drivers/net/cxgb3/t3_hw.c | 4 + 5 files changed, 120 insertions(+), 61 deletions(-) + +--- a/drivers/net/cxgb3/adapter.h ++++ b/drivers/net/cxgb3/adapter.h +@@ -241,6 +241,7 @@ struct adapter { + unsigned int check_task_cnt; + struct delayed_work adap_check_task; + struct work_struct ext_intr_handler_task; ++ struct work_struct fatal_error_handler_task; + + struct dentry *debugfs_root; + +--- a/drivers/net/cxgb3/common.h ++++ b/drivers/net/cxgb3/common.h +@@ -726,6 +726,7 @@ int t3_check_fw_version(struct adapter * + int t3_init_hw(struct adapter *adapter, u32 fw_params); + void mac_prep(struct cmac *mac, struct adapter *adapter, int index); + void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); ++int t3_reset_adapter(struct adapter *adapter); + int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, + int reset); + int t3_replay_prep_adapter(struct adapter *adapter); +--- a/drivers/net/cxgb3/cxgb3_main.c ++++ b/drivers/net/cxgb3/cxgb3_main.c +@@ -1016,6 +1016,13 @@ static int cxgb_up(struct adapter *adap) + goto out; + } + ++ /* ++ * Clear interrupts now to catch errors if t3_init_hw fails. ++ * We clear them again later as initialization may trigger ++ * conditions that can interrupt. ++ */ ++ t3_intr_clear(adap); ++ + err = t3_init_hw(adap, 0); + if (err) + goto out; +@@ -1224,9 +1231,9 @@ static int cxgb_close(struct net_device + if (is_offload(adapter) && !ofld_disable) + sysfs_remove_group(&dev->dev.kobj, &iscsi_offload_attr_group); + +- spin_lock(&adapter->work_lock); /* sync with update task */ ++ spin_lock_irq(&adapter->work_lock); /* sync with update task */ + clear_bit(pi->port_id, &adapter->open_device_map); +- spin_unlock(&adapter->work_lock); ++ spin_unlock_irq(&adapter->work_lock); + + if (!(adapter->open_device_map & PORT_MASK)) + cancel_rearming_delayed_workqueue(cxgb3_wq, +@@ -2555,10 +2562,10 @@ static void t3_adap_check_task(struct wo + check_t3b2_mac(adapter); + + /* Schedule the next check update if any port is active. */ +- spin_lock(&adapter->work_lock); ++ spin_lock_irq(&adapter->work_lock); + if (adapter->open_device_map & PORT_MASK) + schedule_chk_task(adapter); +- spin_unlock(&adapter->work_lock); ++ spin_unlock_irq(&adapter->work_lock); + } + + /* +@@ -2603,6 +2610,96 @@ void t3_os_ext_intr_handler(struct adapt + spin_unlock(&adapter->work_lock); + } + ++static int t3_adapter_error(struct adapter *adapter, int reset) ++{ ++ int i, ret = 0; ++ ++ /* Stop all ports */ ++ for_each_port(adapter, i) { ++ struct net_device *netdev = adapter->port[i]; ++ ++ if (netif_running(netdev)) ++ cxgb_close(netdev); ++ } ++ ++ if (is_offload(adapter) && ++ test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) ++ offload_close(&adapter->tdev); ++ ++ /* Stop SGE timers */ ++ t3_stop_sge_timers(adapter); ++ ++ adapter->flags &= ~FULL_INIT_DONE; ++ ++ if (reset) ++ ret = t3_reset_adapter(adapter); ++ ++ pci_disable_device(adapter->pdev); ++ ++ return ret; ++} ++ ++static int t3_reenable_adapter(struct adapter *adapter) ++{ ++ if (pci_enable_device(adapter->pdev)) { ++ dev_err(&adapter->pdev->dev, ++ "Cannot re-enable PCI device after reset.\n"); ++ goto err; ++ } ++ pci_set_master(adapter->pdev); ++ pci_restore_state(adapter->pdev); ++ ++ /* Free sge resources */ ++ t3_free_sge_resources(adapter); ++ ++ if (t3_replay_prep_adapter(adapter)) ++ goto err; ++ ++ return 0; ++err: ++ return -1; ++} ++ ++static void t3_resume_ports(struct adapter *adapter) ++{ ++ int i; ++ ++ /* Restart the ports */ ++ for_each_port(adapter, i) { ++ struct net_device *netdev = adapter->port[i]; ++ ++ if (netif_running(netdev)) { ++ if (cxgb_open(netdev)) { ++ dev_err(&adapter->pdev->dev, ++ "can't bring device back up" ++ " after reset\n"); ++ continue; ++ } ++ } ++ } ++} ++ ++/* ++ * processes a fatal error. ++ * Bring the ports down, reset the chip, bring the ports back up. ++ */ ++static void fatal_error_task(struct work_struct *work) ++{ ++ struct adapter *adapter = container_of(work, struct adapter, ++ fatal_error_handler_task); ++ int err = 0; ++ ++ rtnl_lock(); ++ err = t3_adapter_error(adapter, 1); ++ if (!err) ++ err = t3_reenable_adapter(adapter); ++ if (!err) ++ t3_resume_ports(adapter); ++ ++ CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded"); ++ rtnl_unlock(); ++} ++ + void t3_fatal_err(struct adapter *adapter) + { + unsigned int fw_status[4]; +@@ -2613,7 +2710,11 @@ void t3_fatal_err(struct adapter *adapte + t3_write_reg(adapter, A_XGM_RX_CTRL, 0); + t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); + t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); ++ ++ spin_lock(&adapter->work_lock); + t3_intr_disable(adapter); ++ queue_work(cxgb3_wq, &adapter->fatal_error_handler_task); ++ spin_unlock(&adapter->work_lock); + } + CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); + if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) +@@ -2635,26 +2736,9 @@ static pci_ers_result_t t3_io_error_dete + pci_channel_state_t state) + { + struct adapter *adapter = pci_get_drvdata(pdev); +- int i; +- +- /* Stop all ports */ +- for_each_port(adapter, i) { +- struct net_device *netdev = adapter->port[i]; +- +- if (netif_running(netdev)) +- cxgb_close(netdev); +- } +- +- if (is_offload(adapter) && +- test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) +- offload_close(&adapter->tdev); +- +- /* Stop SGE timers */ +- t3_stop_sge_timers(adapter); +- +- adapter->flags &= ~FULL_INIT_DONE; +- +- pci_disable_device(pdev); ++ int ret; ++ ++ ret = t3_adapter_error(adapter, 0); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +@@ -2670,22 +2754,9 @@ static pci_ers_result_t t3_io_slot_reset + { + struct adapter *adapter = pci_get_drvdata(pdev); + +- if (pci_enable_device(pdev)) { +- dev_err(&pdev->dev, +- "Cannot re-enable PCI device after reset.\n"); +- goto err; +- } +- pci_set_master(pdev); +- pci_restore_state(pdev); +- +- /* Free sge resources */ +- t3_free_sge_resources(adapter); +- +- if (t3_replay_prep_adapter(adapter)) +- goto err; ++ if (!t3_reenable_adapter(adapter)) ++ return PCI_ERS_RESULT_RECOVERED; + +- return PCI_ERS_RESULT_RECOVERED; +-err: + return PCI_ERS_RESULT_DISCONNECT; + } + +@@ -2699,22 +2770,8 @@ err: + static void t3_io_resume(struct pci_dev *pdev) + { + struct adapter *adapter = pci_get_drvdata(pdev); +- int i; +- +- /* Restart the ports */ +- for_each_port(adapter, i) { +- struct net_device *netdev = adapter->port[i]; + +- if (netif_running(netdev)) { +- if (cxgb_open(netdev)) { +- dev_err(&pdev->dev, +- "can't bring device back up" +- " after reset\n"); +- continue; +- } +- netif_device_attach(netdev); +- } +- } ++ t3_resume_ports(adapter); + } + + static struct pci_error_handlers t3_err_handler = { +@@ -2899,6 +2956,7 @@ static int __devinit init_one(struct pci + + INIT_LIST_HEAD(&adapter->adapter_list); + INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); ++ INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); + INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); + + for (i = 0; i < ai->nports; ++i) { +--- a/drivers/net/cxgb3/sge.c ++++ b/drivers/net/cxgb3/sge.c +@@ -352,7 +352,8 @@ static void free_rx_bufs(struct pci_dev + pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr), + q->buf_size, PCI_DMA_FROMDEVICE); + if (q->use_pages) { +- put_page(d->pg_chunk.page); ++ if (d->pg_chunk.page) ++ put_page(d->pg_chunk.page); + d->pg_chunk.page = NULL; + } else { + kfree_skb(d->skb); +@@ -584,7 +585,7 @@ static void t3_reset_qset(struct sge_qse + memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); + memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); + q->txq_stopped = 0; +- memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer)); ++ q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ + kfree(q->lro_frag_tbl); + q->lro_nfrags = q->lro_frag_len = 0; + } +@@ -2900,9 +2901,7 @@ int t3_sge_alloc_qset(struct adapter *ad + struct net_lro_mgr *lro_mgr = &q->lro_mgr; + + init_qset_cntxt(q, id); +- init_timer(&q->tx_reclaim_timer); +- q->tx_reclaim_timer.data = (unsigned long)q; +- q->tx_reclaim_timer.function = sge_timer_cb; ++ setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q); + + q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, + sizeof(struct rx_desc), +--- a/drivers/net/cxgb3/t3_hw.c ++++ b/drivers/net/cxgb3/t3_hw.c +@@ -1275,7 +1275,7 @@ struct intr_info { + unsigned int mask; /* bits to check in interrupt status */ + const char *msg; /* message to print or NULL */ + short stat_idx; /* stat counter to increment or -1 */ +- unsigned short fatal:1; /* whether the condition reported is fatal */ ++ unsigned short fatal; /* whether the condition reported is fatal */ + }; + + /** +@@ -3551,7 +3551,7 @@ void early_hw_init(struct adapter *adapt + * Older PCIe cards lose their config space during reset, PCI-X + * ones don't. + */ +-static int t3_reset_adapter(struct adapter *adapter) ++int t3_reset_adapter(struct adapter *adapter) + { + int i, save_and_restore_pcie = + adapter->params.rev < T3_REV_B2 && is_pcie(adapter); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-simplify-port-type-struct-and-usage b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-simplify-port-type-struct-and-usage new file mode 100644 index 000000000..d3bccb0f8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-simplify-port-type-struct-and-usage @@ -0,0 +1,475 @@ +Commit-Id: 044979827eda13675abab99879ebe3ea535d59fa +From: Divy Le Ray +Date: Wed, 8 Oct 2008 17:38:29 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: simplify port type struct and usage +Reference: bnc#446739 + + +Second step in overall phy layer reorganization. +Clean up the port_type_info structure. +Support coextistence of clause 22 and clause 45 MDIO devices. +Select the type of MDIO transaction on a per transaction basis. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +Index: linux-2.6.27/drivers/net/cxgb3/adapter.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/adapter.h ++++ linux-2.6.27/drivers/net/cxgb3/adapter.h +@@ -54,7 +54,6 @@ struct port_info { + struct adapter *adapter; + struct vlan_group *vlan_grp; + struct sge_qset *qs; +- const struct port_type_info *port_type; + u8 port_id; + u8 rx_csum_offload; + u8 nqsets; +@@ -283,6 +282,7 @@ int t3_offload_tx(struct t3cdev *tdev, s + void t3_os_ext_intr_handler(struct adapter *adapter); + void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, + int speed, int duplex, int fc); ++void t3_os_phymod_changed(struct adapter *adap, int port_id); + + void t3_sge_start(struct adapter *adap); + void t3_sge_stop(struct adapter *adap); +Index: linux-2.6.27/drivers/net/cxgb3/ael1002.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/ael1002.c ++++ linux-2.6.27/drivers/net/cxgb3/ael1002.c +@@ -122,7 +122,9 @@ static struct cphy_ops ael1002_ops = { + int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) + { +- cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); ++ cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, ++ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, ++ "10GBASE-R"); + ael100x_txon(phy); + return 0; + } +@@ -178,7 +180,9 @@ static struct cphy_ops ael1006_ops = { + int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) + { +- cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); ++ cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops, ++ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, ++ "10GBASE-SR"); + ael100x_txon(phy); + return 0; + } +@@ -198,7 +202,9 @@ int t3_qt2045_phy_prep(struct cphy *phy, + { + unsigned int stat; + +- cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops); ++ cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops, ++ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, ++ "10GBASE-CX4"); + + /* + * Some cards where the PHY is supposed to be at address 0 actually +@@ -256,6 +262,8 @@ static struct cphy_ops xaui_direct_ops = + int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) + { +- cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops); ++ cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, ++ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, ++ "10GBASE-CX4"); + return 0; + } +Index: linux-2.6.27/drivers/net/cxgb3/common.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/common.h ++++ linux-2.6.27/drivers/net/cxgb3/common.h +@@ -193,8 +193,6 @@ struct mdio_ops { + struct adapter_info { + unsigned char nports; /* # of ports */ + unsigned char phy_base_addr; /* MDIO PHY base address */ +- unsigned char mdien; +- unsigned char mdiinv; + unsigned int gpio_out; /* GPIO output settings */ + unsigned int gpio_intr; /* GPIO IRQ enable mask */ + unsigned long caps; /* adapter capabilities */ +@@ -202,13 +200,6 @@ struct adapter_info { + const char *desc; /* product description */ + }; + +-struct port_type_info { +- int (*phy_prep)(struct cphy *phy, struct adapter *adapter, +- int phy_addr, const struct mdio_ops *ops); +- unsigned int caps; +- const char *desc; +-}; +- + struct mc5_stats { + unsigned long parity_err; + unsigned long active_rgn_full; +@@ -548,7 +539,6 @@ enum { + + /* PHY operations */ + struct cphy_ops { +- void (*destroy)(struct cphy *phy); + int (*reset)(struct cphy *phy, int wait); + + int (*intr_enable)(struct cphy *phy); +@@ -569,8 +559,10 @@ struct cphy_ops { + + /* A PHY instance */ + struct cphy { +- int addr; /* PHY address */ ++ int addr; /* PHY address */ ++ unsigned int caps; /* PHY capabilities */ + struct adapter *adapter; /* associated adapter */ ++ const char *desc; /* PHY description */ + unsigned long fifo_errors; /* FIFO over/under-flows */ + const struct cphy_ops *ops; /* PHY operations */ + int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr, +@@ -595,10 +587,13 @@ static inline int mdio_write(struct cphy + /* Convenience initializer */ + static inline void cphy_init(struct cphy *phy, struct adapter *adapter, + int phy_addr, struct cphy_ops *phy_ops, +- const struct mdio_ops *mdio_ops) ++ const struct mdio_ops *mdio_ops, ++ unsigned int caps, const char *desc) + { +- phy->adapter = adapter; + phy->addr = phy_addr; ++ phy->caps = caps; ++ phy->adapter = adapter; ++ phy->desc = desc; + phy->ops = phy_ops; + if (mdio_ops) { + phy->mdio_read = mdio_ops->read; +Index: linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/cxgb3_main.c ++++ linux-2.6.27/drivers/net/cxgb3/cxgb3_main.c +@@ -2454,7 +2454,7 @@ static void check_link_status(struct ada + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + +- if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev)) ++ if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) + t3_link_changed(adapter, i); + } + } +@@ -2767,7 +2767,7 @@ static void __devinit print_port_info(st + if (!test_bit(i, &adap->registered_device_map)) + continue; + printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n", +- dev->name, ai->desc, pi->port_type->desc, ++ dev->name, ai->desc, pi->phy.desc, + is_offload(adap) ? "R" : "", adap->params.rev, buf, + (adap->flags & USING_MSIX) ? " MSI-X" : + (adap->flags & USING_MSI) ? " MSI" : ""); +Index: linux-2.6.27/drivers/net/cxgb3/t3_hw.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/t3_hw.c ++++ linux-2.6.27/drivers/net/cxgb3/t3_hw.c +@@ -194,21 +194,18 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsi + static void mi1_init(struct adapter *adap, const struct adapter_info *ai) + { + u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; +- u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) | +- V_CLKDIV(clkdiv); ++ u32 val = F_PREEN | V_CLKDIV(clkdiv); + +- if (!(ai->caps & SUPPORTED_10000baseT_Full)) +- val |= V_ST(1); + t3_write_reg(adap, A_MI1_CFG, val); + } + +-#define MDIO_ATTEMPTS 10 ++#define MDIO_ATTEMPTS 20 + + /* +- * MI1 read/write operations for direct-addressed PHYs. ++ * MI1 read/write operations for clause 22 PHYs. + */ +-static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, +- int reg_addr, unsigned int *valp) ++static int t3_mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, ++ int reg_addr, unsigned int *valp) + { + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); +@@ -217,16 +214,17 @@ static int mi1_read(struct adapter *adap + return -EINVAL; + + mutex_lock(&adapter->mdio_lock); ++ t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); +- ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); ++ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); + if (!ret) + *valp = t3_read_reg(adapter, A_MI1_DATA); + mutex_unlock(&adapter->mdio_lock); + return ret; + } + +-static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, ++static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val) + { + int ret; +@@ -236,37 +234,51 @@ static int mi1_write(struct adapter *ada + return -EINVAL; + + mutex_lock(&adapter->mdio_lock); ++ t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, val); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); +- ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); ++ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10); + mutex_unlock(&adapter->mdio_lock); + return ret; + } + + static const struct mdio_ops mi1_mdio_ops = { +- mi1_read, +- mi1_write ++ t3_mi1_read, ++ t3_mi1_write + }; + + /* ++ * Performs the address cycle for clause 45 PHYs. ++ * Must be called with the MDIO_LOCK held. ++ */ ++static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr, ++ int reg_addr) ++{ ++ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); ++ ++ t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0); ++ t3_write_reg(adapter, A_MI1_ADDR, addr); ++ t3_write_reg(adapter, A_MI1_DATA, reg_addr); ++ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); ++ return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, ++ MDIO_ATTEMPTS, 10); ++} ++ ++/* + * MI1 read/write operations for indirect-addressed PHYs. + */ + static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *valp) + { + int ret; +- u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); +- t3_write_reg(adapter, A_MI1_ADDR, addr); +- t3_write_reg(adapter, A_MI1_DATA, reg_addr); +- t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); +- ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); ++ ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); + if (!ret) { + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, +- MDIO_ATTEMPTS, 20); ++ MDIO_ATTEMPTS, 10); + if (!ret) + *valp = t3_read_reg(adapter, A_MI1_DATA); + } +@@ -278,18 +290,14 @@ static int mi1_ext_write(struct adapter + int reg_addr, unsigned int val) + { + int ret; +- u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); +- t3_write_reg(adapter, A_MI1_ADDR, addr); +- t3_write_reg(adapter, A_MI1_DATA, reg_addr); +- t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); +- ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); ++ ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); + if (!ret) { + t3_write_reg(adapter, A_MI1_DATA, val); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, +- MDIO_ATTEMPTS, 20); ++ MDIO_ATTEMPTS, 10); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +@@ -435,22 +443,22 @@ int t3_set_phy_speed_duplex(struct cphy + } + + static const struct adapter_info t3_adap_info[] = { +- {2, 0, 0, 0, ++ {2, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, + 0, + &mi1_mdio_ops, "Chelsio PE9000"}, +- {2, 0, 0, 0, ++ {2, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, + 0, + &mi1_mdio_ops, "Chelsio T302"}, +- {1, 0, 0, 0, ++ {1, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | + F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, + 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio T310"}, +- {2, 0, 0, 0, ++ {2, 0, + F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | + F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | + F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, +@@ -467,29 +475,23 @@ const struct adapter_info *t3_get_adapte + return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; + } + +-#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \ +- SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII) +-#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI) ++struct port_type_info { ++ int (*phy_prep)(struct cphy *phy, struct adapter *adapter, ++ int phy_addr, const struct mdio_ops *ops); ++}; + + static const struct port_type_info port_types[] = { +- {NULL}, +- {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE, +- "10GBASE-XR"}, +- {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, +- "10/100/1000BASE-T"}, +- {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, +- "10/100/1000BASE-T"}, +- {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, +- {NULL, CAPS_10G, "10GBASE-KX4"}, +- {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, +- {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE, +- "10GBASE-SR"}, +- {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, ++ { NULL }, ++ { t3_ael1002_phy_prep }, ++ { t3_vsc8211_phy_prep }, ++ { NULL}, ++ { t3_xaui_direct_phy_prep }, ++ { NULL }, ++ { t3_qt2045_phy_prep }, ++ { t3_ael1006_phy_prep }, ++ { NULL }, + }; + +-#undef CAPS_1G +-#undef CAPS_10G +- + #define VPD_ENTRY(name, len) \ + u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + +@@ -1691,7 +1693,7 @@ int t3_phy_intr_handler(struct adapter * + mask = gpi - (gpi & (gpi - 1)); + gpi -= mask; + +- if (!(p->port_type->caps & SUPPORTED_IRQ)) ++ if (!(p->phy.caps & SUPPORTED_IRQ)) + continue; + + if (cause & mask) { +@@ -3556,7 +3558,7 @@ int t3_prep_adapter(struct adapter *adap + int reset) + { + int ret; +- unsigned int i, j = 0; ++ unsigned int i, j = -1; + + get_pci_mode(adapter, &adapter->params.pci); + +@@ -3620,19 +3622,18 @@ int t3_prep_adapter(struct adapter *adap + + for_each_port(adapter, i) { + u8 hw_addr[6]; ++ const struct port_type_info *pti; + struct port_info *p = adap2pinfo(adapter, i); + +- while (!adapter->params.vpd.port_type[j]) +- ++j; ++ while (!adapter->params.vpd.port_type[++j]) ++ ; + +- p->port_type = &port_types[adapter->params.vpd.port_type[j]]; +- ret = p->port_type->phy_prep(&p->phy, adapter, +- ai->phy_base_addr + j, +- ai->mdio_ops); ++ pti = &port_types[adapter->params.vpd.port_type[j]]; ++ ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, ++ ai->mdio_ops); + if (ret) + return ret; + mac_prep(&p->mac, adapter, j); +- ++j; + + /* + * The VPD EEPROM stores the base Ethernet address for the +@@ -3646,9 +3647,9 @@ int t3_prep_adapter(struct adapter *adap + ETH_ALEN); + memcpy(adapter->port[i]->perm_addr, hw_addr, + ETH_ALEN); +- init_link_config(&p->link_config, p->port_type->caps); ++ init_link_config(&p->link_config, p->phy.caps); + p->phy.ops->power_down(&p->phy, 1); +- if (!(p->port_type->caps & SUPPORTED_IRQ)) ++ if (!(p->phy.caps & SUPPORTED_IRQ)) + adapter->params.linkpoll_period = 10; + } + +@@ -3664,7 +3665,7 @@ void t3_led_ready(struct adapter *adapte + int t3_replay_prep_adapter(struct adapter *adapter) + { + const struct adapter_info *ai = adapter->params.info; +- unsigned int i, j = 0; ++ unsigned int i, j = -1; + int ret; + + early_hw_init(adapter, ai); +@@ -3673,17 +3674,17 @@ int t3_replay_prep_adapter(struct adapte + return ret; + + for_each_port(adapter, i) { ++ const struct port_type_info *pti; + struct port_info *p = adap2pinfo(adapter, i); +- while (!adapter->params.vpd.port_type[j]) +- ++j; + +- ret = p->port_type->phy_prep(&p->phy, adapter, +- ai->phy_base_addr + j, +- ai->mdio_ops); ++ while (!adapter->params.vpd.port_type[++j]) ++ ; ++ ++ pti = &port_types[adapter->params.vpd.port_type[j]]; ++ ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL); + if (ret) + return ret; + p->phy.ops->power_down(&p->phy, 1); +- ++j; + } + + return 0; +Index: linux-2.6.27/drivers/net/cxgb3/vsc8211.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/cxgb3/vsc8211.c ++++ linux-2.6.27/drivers/net/cxgb3/vsc8211.c +@@ -224,6 +224,9 @@ static struct cphy_ops vsc8211_ops = { + int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) + { +- cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops); ++ cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, ++ SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | ++ SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | ++ SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-update-driver-version b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-update-driver-version new file mode 100644 index 000000000..fe1a73849 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3-update-driver-version @@ -0,0 +1,26 @@ +Commit-Id: fe642ebc2d5f5b0d82dd248a6f1ef3984b83f3cc +From: Divy Le Ray +Date: Mon, 13 Oct 2008 18:47:02 -0700 +Acked-by: Karsten Keil +Subject: [PATCH] cxgb3: update driver version +Reference: bnc#446739 + +Add a field to the driver versioning info. +Update version to 1.1.0. + +Signed-off-by: Divy Le Ray +Signed-off-by: David S. Miller + +diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h +index 29db711..ed16907 100644 +--- a/drivers/net/cxgb3/version.h ++++ b/drivers/net/cxgb3/version.h +@@ -35,7 +35,7 @@ + #define DRV_DESC "Chelsio T3 Network Driver" + #define DRV_NAME "cxgb3" + /* Driver version */ +-#define DRV_VERSION "1.0-ko" ++#define DRV_VERSION "1.1.0-ko" + + /* Firmware version */ + #define FW_VERSION_MAJOR 7 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i new file mode 100644 index 000000000..32bfb3e2e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i @@ -0,0 +1,4318 @@ +Subject: add cxgb3i iscsi driver +From: Karen Xie +References: FATE#304154,bnc#433500 + +Add Chelsio S3 iscsi initiator driver. +This patch implements the cxgb3i iscsi connection offload. + +Signed-off-by: Karen Xie +Signed-off-by: Chandra Seetharaman +Signed-off-by: Hannes Reinecke +--- + +--- + drivers/scsi/Kconfig | 2 + drivers/scsi/Makefile | 1 + drivers/scsi/cxgb3i/Kconfig | 7 + drivers/scsi/cxgb3i/Makefile | 5 + drivers/scsi/cxgb3i/cxgb3i.h | 179 +++ + drivers/scsi/cxgb3i/cxgb3i_init.c | 109 + + drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 854 ++++++++++++++ + drivers/scsi/cxgb3i/cxgb3i_offload.c | 2021 +++++++++++++++++++++++++++++++++++ + drivers/scsi/cxgb3i/cxgb3i_offload.h | 220 +++ + drivers/scsi/cxgb3i/cxgb3i_ulp2.c | 741 ++++++++++++ + drivers/scsi/cxgb3i/cxgb3i_ulp2.h | 108 + + 11 files changed, 4247 insertions(+) + +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i.h +@@ -0,0 +1,179 @@ ++/* ++ * cxgb3i.h: Chelsio S3xx iSCSI driver. ++ * ++ * Copyright (c) 2008 Chelsio Communications, Inc. ++ * ++ * 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. ++ * ++ * Written by: Karen Xie (kxie@chelsio.com) ++ */ ++ ++#ifndef __CXGB3I_H__ ++#define __CXGB3I_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* from cxgb3 LLD */ ++#include "common.h" ++#include "t3_cpl.h" ++#include "t3cdev.h" ++#include "cxgb3_ctl_defs.h" ++#include "cxgb3_offload.h" ++#include "firmware_exports.h" ++#include "cxgb3i_offload.h" ++/* from iscsi */ ++#include "../iscsi_tcp.h" ++ ++#define CXGB3I_SCSI_QDEPTH_DFLT 128 ++#define CXGB3I_MAX_TARGET CXGB3I_MAX_CONN ++#define CXGB3I_MAX_LUN 512 ++#define ISCSI_PDU_HEADER_MAX (56 + 256) /* bhs + digests + ahs */ ++ ++struct cxgb3i_adapter; ++struct cxgb3i_hba; ++struct cxgb3i_endpoint; ++ ++/** ++ * struct cxgb3i_tag_format - cxgb3i ulp tag for steering pdu payload ++ * ++ * @idx_bits: # of bits used to store itt (from iscsi laryer) ++ * @age_bits: # of bits used to store age (from iscsi laryer) ++ * @rsvd_bits: # of bits used by h/w ++ * @rsvd_shift: shift left ++ * @rsvd_mask: bit mask ++ * @rsvd_tag_mask: h/w tag bit mask ++ * ++ */ ++struct cxgb3i_tag_format { ++ unsigned char idx_bits; ++ unsigned char age_bits; ++ unsigned char rsvd_bits; ++ unsigned char rsvd_shift; ++ u32 rsvd_mask; ++ u32 rsvd_tag_mask; ++}; ++ ++/** ++ * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload ++ * ++ * @llimit: lower bound of the page pod memory ++ * @ulimit: upper bound of the page pod memory ++ * @nppods: # of page pod entries ++ * @idx_last: page pod entry last used ++ * @map_lock: lock to synchonize access to the page pod map ++ * @map: page pod map ++ */ ++struct cxgb3i_ddp_info { ++ unsigned int llimit; ++ unsigned int ulimit; ++ unsigned int nppods; ++ unsigned int idx_last; ++ spinlock_t map_lock; ++ u8 *map; ++}; ++ ++/** ++ * struct cxgb3i_hba - cxgb3i iscsi structure (per port) ++ * ++ * @snic: cxgb3i adapter containing this port ++ * @ndev: pointer to netdev structure ++ * @shost: pointer to scsi host structure ++ */ ++struct cxgb3i_hba { ++ struct cxgb3i_adapter *snic; ++ struct net_device *ndev; ++ struct Scsi_Host *shost; ++}; ++ ++/** ++ * struct cxgb3i_adapter - cxgb3i adapter structure (per pci) ++ * ++ * @listhead: list head to link elements ++ * @lock: lock for this structure ++ * @tdev: pointer to t3cdev used by cxgb3 driver ++ * @pdev: pointer to pci dev ++ * @hba_cnt: # of hbas (the same as # of ports) ++ * @hba: all the hbas on this adapter ++ * @tx_max_size: max. tx packet size supported ++ * @rx_max_size: max. rx packet size supported ++ * @tag_format: ulp tag format settings ++ * @ddp: ulp ddp state ++ */ ++struct cxgb3i_adapter { ++ struct list_head list_head; ++ spinlock_t lock; ++ struct t3cdev *tdev; ++ struct pci_dev *pdev; ++ unsigned char hba_cnt; ++ struct cxgb3i_hba *hba[MAX_NPORTS]; ++ ++ unsigned int tx_max_size; ++ unsigned int rx_max_size; ++ ++ struct cxgb3i_tag_format tag_format; ++ struct cxgb3i_ddp_info ddp; ++}; ++ ++/** ++ * struct cxgb3i_conn - cxgb3i iscsi connection ++ * ++ * @tcp_conn: pointer to iscsi_tcp_conn structure ++ * @listhead: list head to link elements ++ * @conn: pointer to iscsi_conn structure ++ * @hba: pointer to the hba this conn. is going through ++ */ ++struct cxgb3i_conn { ++ struct iscsi_tcp_conn tcp_conn; ++ struct list_head list_head; ++ struct cxgb3i_endpoint *cep; ++ struct iscsi_conn *conn; ++ struct cxgb3i_hba *hba; ++}; ++ ++/** ++ * struct cxgb3i_endpoint - iscsi tcp endpoint ++ * ++ * @c3cn: the h/w tcp connection representation ++ * @hba: pointer to the hba this conn. is going through ++ * @cconn: pointer to the associated cxgb3i iscsi connection ++ */ ++struct cxgb3i_endpoint { ++ struct s3_conn *c3cn; ++ struct cxgb3i_hba *hba; ++ struct cxgb3i_conn *cconn; ++}; ++ ++/* ++ * Function Prototypes ++ */ ++int cxgb3i_iscsi_init(void); ++void cxgb3i_iscsi_cleanup(void); ++ ++struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *); ++void cxgb3i_adapter_remove(struct t3cdev *); ++int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *); ++void cxgb3i_adapter_ulp_cleanup(struct cxgb3i_adapter *); ++ ++struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *); ++struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *, ++ struct net_device *); ++void cxgb3i_hba_host_remove(struct cxgb3i_hba *); ++ ++int cxgb3i_ulp2_init(void); ++void cxgb3i_ulp2_cleanup(void); ++int cxgb3i_conn_ulp_setup(struct cxgb3i_conn *, int, int); ++void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *, u32, ++ struct scatterlist *, unsigned int); ++u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *, unsigned int, ++ u32, unsigned int, struct scatterlist *, ++ unsigned int); ++int cxgb3i_conn_ulp2_xmit(struct iscsi_conn *); ++#endif +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i_init.c +@@ -0,0 +1,109 @@ ++/* cxgb3i_init.c: Chelsio S3xx iSCSI driver. ++ * ++ * Copyright (c) 2008 Chelsio Communications, Inc. ++ * ++ * 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. ++ * ++ * Written by: Karen Xie (kxie@chelsio.com) ++ */ ++ ++#include "cxgb3i.h" ++ ++#define DRV_MODULE_NAME "cxgb3i" ++#define DRV_MODULE_VERSION "1.0.0" ++#define DRV_MODULE_RELDATE "Jun. 1, 2008" ++ ++static char version[] = ++ "Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME ++ " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; ++ ++MODULE_AUTHOR("Karen Xie "); ++MODULE_DESCRIPTION("Chelsio S3xx iSCSI Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_MODULE_VERSION); ++ ++static void open_s3_dev(struct t3cdev *); ++static void close_s3_dev(struct t3cdev *); ++ ++static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; ++static struct cxgb3_client t3c_client = { ++ .name = "iscsi_cxgb3", ++ .handlers = cxgb3i_cpl_handlers, ++ .add = open_s3_dev, ++ .remove = close_s3_dev, ++}; ++ ++/** ++ * open_s3_dev - register with cxgb3 LLD ++ * @t3dev: cxgb3 adapter instance ++ */ ++static void open_s3_dev(struct t3cdev *t3dev) ++{ ++ static int vers_printed; ++ ++ if (!vers_printed) { ++ printk(KERN_INFO "%s", version); ++ vers_printed = 1; ++ } ++ ++ cxgb3i_log_debug("open cxgb3 %s.\n", t3dev->name); ++ cxgb3i_sdev_add(t3dev, &t3c_client); ++ cxgb3i_adapter_add(t3dev); ++} ++ ++/** ++ * close_s3_dev - de-register with cxgb3 LLD ++ * @t3dev: cxgb3 adapter instance ++ */ ++static void close_s3_dev(struct t3cdev *t3dev) ++{ ++ cxgb3i_log_debug("close cxgb3 %s.\n", t3dev->name); ++ cxgb3i_adapter_remove(t3dev); ++ cxgb3i_sdev_remove(t3dev); ++} ++ ++/** ++ * cxgb3i_init_module - module init entry point ++ * ++ * initialize any driver wide global data structures and register itself ++ * with the cxgb3 module ++ */ ++static int __init cxgb3i_init_module(void) ++{ ++ int err; ++ ++ err = cxgb3i_sdev_init(cxgb3i_cpl_handlers); ++ if (err < 0) ++ return err; ++ ++ err = cxgb3i_iscsi_init(); ++ if (err < 0) ++ return err; ++ ++ err = cxgb3i_ulp2_init(); ++ if (err < 0) ++ return err; ++ ++ cxgb3_register_client(&t3c_client); ++ ++ return 0; ++} ++ ++/** ++ * cxgb3i_exit_module - module cleanup/exit entry point ++ * ++ * go through the driver hba list and for each hba, release any resource held. ++ * and unregisters iscsi transport and the cxgb3 module ++ */ ++static void __exit cxgb3i_exit_module(void) ++{ ++ cxgb3_unregister_client(&t3c_client); ++ cxgb3i_ulp2_cleanup(); ++ cxgb3i_iscsi_cleanup(); ++ cxgb3i_sdev_cleanup(); ++} ++ ++module_init(cxgb3i_init_module); ++module_exit(cxgb3i_exit_module); +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +@@ -0,0 +1,854 @@ ++/* cxgb3i_iscsi.c: Chelsio S3xx iSCSI driver. ++ * ++ * Copyright (c) 2008 Chelsio Communications, Inc. ++ * ++ * 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. ++ * ++ * Written by: Karen Xie (kxie@chelsio.com) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cxgb3i.h" ++ ++static struct scsi_transport_template *cxgb3i_scsi_transport; ++static struct scsi_host_template cxgb3i_host_template; ++static struct iscsi_transport cxgb3i_iscsi_transport; ++ ++static LIST_HEAD(cxgb3i_snic_list); ++static DEFINE_RWLOCK(cxgb3i_snic_rwlock); ++ ++/** ++ * cxgb3i_adapter_add - init a s3 adapter structure and any h/w settings ++ * @snic: pointer to adapter instance ++ */ ++struct cxgb3i_adapter *cxgb3i_adapter_add(struct t3cdev *t3dev) ++{ ++ struct cxgb3i_adapter *snic; ++ struct adapter *adapter = tdev2adap(t3dev); ++ int i; ++ ++ snic = kzalloc(sizeof(*snic), GFP_KERNEL); ++ if (!snic) { ++ cxgb3i_log_debug("cxgb3 %s, OOM.\n", t3dev->name); ++ return NULL; ++ } ++ ++ spin_lock_init(&snic->lock); ++ snic->tdev = t3dev; ++ snic->pdev = adapter->pdev; ++ ++ if (cxgb3i_adapter_ulp_init(snic)) ++ goto free_snic; ++ ++ for_each_port(adapter, i) { ++ snic->hba[i] = cxgb3i_hba_host_add(snic, adapter->port[i]); ++ if (!snic->hba[i]) ++ goto ulp_cleanup; ++ } ++ snic->hba_cnt = adapter->params.nports; ++ ++ /* add to the list */ ++ write_lock(&cxgb3i_snic_rwlock); ++ list_add_tail(&snic->list_head, &cxgb3i_snic_list); ++ write_unlock(&cxgb3i_snic_rwlock); ++ ++ return snic; ++ ++ulp_cleanup: ++ cxgb3i_adapter_ulp_cleanup(snic); ++free_snic: ++ kfree(snic); ++ return NULL; ++} ++ ++/** ++ * cxgb3i_snic_cleanup - release all the resources held and cleanup h/w settings ++ * @snic: pointer to adapter instance ++ */ ++void cxgb3i_adapter_remove(struct t3cdev *t3dev) ++{ ++ int i; ++ struct cxgb3i_adapter *snic; ++ ++ /* remove from the list */ ++ read_lock(&cxgb3i_snic_rwlock); ++ list_for_each_entry(snic, &cxgb3i_snic_list, list_head) { ++ if (snic->tdev == t3dev) { ++ list_del(&snic->list_head); ++ break; ++ } ++ } ++ write_unlock(&cxgb3i_snic_rwlock); ++ ++ if (snic) { ++ for (i = 0; i < snic->hba_cnt; i++) { ++ if (snic->hba[i]) { ++ cxgb3i_hba_host_remove(snic->hba[i]); ++ snic->hba[i] = NULL; ++ } ++ } ++ ++ /* release ddp resources */ ++ cxgb3i_adapter_ulp_cleanup(snic); ++ kfree(snic); ++ } ++} ++ ++struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev) ++{ ++ struct cxgb3i_adapter *snic; ++ int i; ++ ++ read_lock(&cxgb3i_snic_rwlock); ++ list_for_each_entry(snic, &cxgb3i_snic_list, list_head) { ++ for (i = 0; i < snic->hba_cnt; i++) { ++ if (snic->hba[i]->ndev == ndev) { ++ read_unlock(&cxgb3i_snic_rwlock); ++ return snic->hba[i]; ++ } ++ } ++ } ++ read_unlock(&cxgb3i_snic_rwlock); ++ return NULL; ++} ++ ++struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic, ++ struct net_device *ndev) ++{ ++ struct cxgb3i_hba *hba; ++ struct Scsi_Host *shost; ++ int err; ++ ++ shost = iscsi_host_alloc(&cxgb3i_host_template, ++ sizeof(struct cxgb3i_hba), ++ CXGB3I_SCSI_QDEPTH_DFLT); ++ if (!shost) { ++ cxgb3i_log_info("iscsi_host_alloc failed.\n"); ++ return NULL; ++ } ++ ++ shost->transportt = cxgb3i_scsi_transport; ++ shost->max_lun = CXGB3I_MAX_LUN; ++ shost->max_id = CXGB3I_MAX_TARGET; ++ shost->max_channel = 0; ++ shost->max_cmd_len = 16; ++ ++ hba = iscsi_host_priv(shost); ++ hba->snic = snic; ++ hba->ndev = ndev; ++ hba->shost = shost; ++ ++ pci_dev_get(snic->pdev); ++ err = iscsi_host_add(shost, &snic->pdev->dev); ++ if (err) { ++ cxgb3i_log_info("iscsi_host_add failed.\n"); ++ goto pci_dev_put; ++ } ++ ++ cxgb3i_log_debug("shost 0x%p, hba 0x%p, no %u.\n", ++ shost, hba, shost->host_no); ++ ++ return hba; ++ ++pci_dev_put: ++ pci_dev_put(snic->pdev); ++ scsi_host_put(shost); ++ return NULL; ++} ++ ++void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba) ++{ ++ cxgb3i_log_debug("shost 0x%p, hba 0x%p, no %u.\n", ++ hba->shost, hba, hba->shost->host_no); ++ iscsi_host_remove(hba->shost); ++ pci_dev_put(hba->snic->pdev); ++ iscsi_host_free(hba->shost); ++} ++ ++/** ++ * cxgb3i_ep_connect - establish TCP connection to target portal ++ * @dst_addr: target IP address ++ * @non_blocking: blocking or non-blocking call ++ * ++ * Initiates a TCP/IP connection to the dst_addr ++ */ ++static struct iscsi_endpoint *cxgb3i_ep_connect(struct sockaddr *dst_addr, ++ int non_blocking) ++{ ++ struct iscsi_endpoint *ep; ++ struct cxgb3i_endpoint *cep; ++ struct cxgb3i_hba *hba; ++ struct s3_conn *c3cn = NULL; ++ int err = 0; ++ ++ c3cn = cxgb3i_c3cn_create(); ++ if (!c3cn) { ++ cxgb3i_log_info("ep connect OOM.\n"); ++ err = -ENOMEM; ++ goto release_conn; ++ } ++ ++ err = cxgb3i_c3cn_connect(c3cn, (struct sockaddr_in *)dst_addr); ++ if (err < 0) { ++ cxgb3i_log_info("ep connect failed.\n"); ++ goto release_conn; ++ } ++ hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev); ++ if (!hba) { ++ err = -ENOSPC; ++ cxgb3i_log_info("NOT going through cxgbi device.\n"); ++ goto release_conn; ++ } ++ if (c3cn_in_state(c3cn, C3CN_STATE_CLOSE)) { ++ err = -ENOSPC; ++ cxgb3i_log_info("ep connect unable to connect.\n"); ++ goto release_conn; ++ } ++ ++ ep = iscsi_create_endpoint(sizeof(*cep)); ++ if (!ep) { ++ err = -ENOMEM; ++ cxgb3i_log_info("iscsi alloc ep, OOM.\n"); ++ goto release_conn; ++ } ++ cep = ep->dd_data; ++ cep->c3cn = c3cn; ++ cep->hba = hba; ++ ++ cxgb3i_log_debug("ep 0x%p, 0x%p, c3cn 0x%p, hba 0x%p.\n", ++ ep, cep, c3cn, hba); ++ return ep; ++ ++release_conn: ++ cxgb3i_log_debug("conn 0x%p failed, release.\n", c3cn); ++ if (c3cn) ++ cxgb3i_c3cn_release(c3cn); ++ return ERR_PTR(err); ++} ++ ++/** ++ * cxgb3i_ep_poll - polls for TCP connection establishement ++ * @ep: TCP connection (endpoint) handle ++ * @timeout_ms: timeout value in milli secs ++ * ++ * polls for TCP connect request to complete ++ */ ++static int cxgb3i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) ++{ ++ struct cxgb3i_endpoint *cep = ep->dd_data; ++ struct s3_conn *c3cn = cep->c3cn; ++ ++ if (!c3cn_in_state(c3cn, C3CN_STATE_ESTABLISHED)) ++ return 0; ++ cxgb3i_log_debug("ep 0x%p, c3cn 0x%p established.\n", ep, c3cn); ++ return 1; ++} ++ ++/** ++ * cxgb3i_ep_disconnect - teardown TCP connection ++ * @ep: TCP connection (endpoint) handle ++ * ++ * teardown TCP connection ++ */ ++static void cxgb3i_ep_disconnect(struct iscsi_endpoint *ep) ++{ ++ struct cxgb3i_endpoint *cep = ep->dd_data; ++ struct cxgb3i_conn *cconn = cep->cconn; ++ ++ cxgb3i_log_debug("ep 0x%p, cep 0x%p.\n", ep, cep); ++ ++ if (cconn && cconn->conn) { ++ struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; ++ ++ /* ++ * stop the xmit path so the xmit_segment function is ++ * not being called ++ */ ++ write_lock_bh(&cep->c3cn->callback_lock); ++ set_bit(ISCSI_SUSPEND_BIT, &cconn->conn->suspend_rx); ++ cep->c3cn->user_data = NULL; ++ cconn->cep = NULL; ++ tcp_conn->sock = NULL; ++ write_unlock_bh(&cep->c3cn->callback_lock); ++ } ++ ++ cxgb3i_log_debug("ep 0x%p, cep 0x%p, release c3cn 0x%p.\n", ++ ep, cep, cep->c3cn); ++ cxgb3i_c3cn_release(cep->c3cn); ++ iscsi_destroy_endpoint(ep); ++} ++ ++/** ++ * cxgb3i_session_create - create a new iscsi session ++ * @cmds_max: max # of commands ++ * @qdepth: scsi queue depth ++ * @initial_cmdsn: initial iscsi CMDSN for this session ++ * @host_no: pointer to return host no ++ * ++ * Creates a new iSCSI session ++ */ ++static struct iscsi_cls_session * ++cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth, ++ u32 initial_cmdsn, u32 *host_no) ++{ ++ struct cxgb3i_endpoint *cep; ++ struct cxgb3i_hba *hba; ++ struct Scsi_Host *shost; ++ struct iscsi_cls_session *cls_session; ++ struct iscsi_session *session; ++ int i; ++ ++ if (!ep) { ++ cxgb3i_log_error("%s, missing endpoint.\n", __func__); ++ return NULL; ++ } ++ ++ cep = ep->dd_data; ++ hba = cep->hba; ++ shost = hba->shost; ++ cxgb3i_log_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba); ++ BUG_ON(hba != iscsi_host_priv(shost)); ++ ++ *host_no = shost->host_no; ++ ++ cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost, ++ cmds_max, ++ sizeof(struct iscsi_tcp_task), ++ initial_cmdsn, ISCSI_MAX_TARGET); ++ if (!cls_session) ++ return NULL; ++ session = cls_session->dd_data; ++ ++ for (i = 0; i < session->cmds_max; i++) { ++ struct iscsi_task *task = session->cmds[i]; ++ struct iscsi_tcp_task *tcp_task = task->dd_data; ++ ++ task->hdr = &tcp_task->hdr.cmd_hdr; ++ task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; ++ } ++ ++ if (iscsi_r2tpool_alloc(session)) ++ goto remove_session; ++ ++ return cls_session; ++ ++remove_session: ++ iscsi_session_teardown(cls_session); ++ return NULL; ++} ++ ++/** ++ * cxgb3i_session_destroy - destroys iscsi session ++ * @cls_session: pointer to iscsi cls session ++ * ++ * Destroys an iSCSI session instance and releases its all resources held ++ */ ++static void cxgb3i_session_destroy(struct iscsi_cls_session *cls_session) ++{ ++ cxgb3i_log_debug("sess 0x%p.\n", cls_session); ++ iscsi_r2tpool_free(cls_session->dd_data); ++ iscsi_session_teardown(cls_session); ++} ++ ++/** ++ * cxgb3i_conn_create - create iscsi connection instance ++ * @cls_session: pointer to iscsi cls session ++ * @cid: iscsi cid ++ * ++ * Creates a new iSCSI connection instance for a given session ++ */ ++static inline void cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) ++{ ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ ++ if (conn->max_xmit_dlength) ++ conn->max_xmit_dlength = min_t(unsigned int, ++ conn->max_xmit_dlength, ++ cconn->hba->snic->tx_max_size - ++ ISCSI_PDU_HEADER_MAX); ++ else ++ conn->max_xmit_dlength = cconn->hba->snic->tx_max_size - ++ ISCSI_PDU_HEADER_MAX; ++ cxgb3i_log_debug("conn 0x%p, max xmit %u.\n", ++ conn, conn->max_xmit_dlength); ++} ++ ++static inline void cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) ++{ ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ ++ if (conn->max_recv_dlength) ++ conn->max_recv_dlength = min_t(unsigned int, ++ conn->max_recv_dlength, ++ cconn->hba->snic->rx_max_size - ++ ISCSI_PDU_HEADER_MAX); ++ else ++ conn->max_recv_dlength = cconn->hba->snic->rx_max_size - ++ ISCSI_PDU_HEADER_MAX; ++ cxgb3i_log_debug("conn 0x%p, max recv %u.\n", ++ conn, conn->max_recv_dlength); ++} ++ ++static struct iscsi_cls_conn *cxgb3i_conn_create(struct iscsi_cls_session ++ *cls_session, u32 cid) ++{ ++ struct iscsi_cls_conn *cls_conn; ++ struct iscsi_conn *conn; ++ struct cxgb3i_conn *cconn; ++ ++ cxgb3i_log_debug("sess 0x%p, cid %u.\n", cls_session, cid); ++ ++ cls_conn = iscsi_conn_setup(cls_session, sizeof(*cconn), cid); ++ if (!cls_conn) ++ return NULL; ++ conn = cls_conn->dd_data; ++ ++ cconn = conn->dd_data; ++ cconn->tcp_conn.iscsi_conn = conn; ++ cconn->conn = conn; ++ ++ return cls_conn; ++} ++ ++/** ++ * cxgb3i_conn_xmit_segment - transmit segment ++ * @conn: pointer to iscsi conn ++ */ ++static int cxgb3i_conn_xmit_segment(struct iscsi_conn *conn) ++{ ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; ++ struct iscsi_segment *segment = &tcp_conn->out.segment; ++ ++ if (segment->total_copied < segment->total_size) ++ return cxgb3i_conn_ulp2_xmit(conn); ++ return 0; ++} ++ ++/** ++ * cxgb3i_conn_bind - binds iscsi sess, conn and endpoint together ++ * @cls_session: pointer to iscsi cls session ++ * @cls_conn: pointer to iscsi cls conn ++ * @transport_eph: 64-bit EP handle ++ * @is_leading: leading connection on this session? ++ * ++ * Binds together an iSCSI session, an iSCSI connection and a ++ * TCP connection. This routine returns error code if the TCP ++ * connection does not belong on the device iSCSI sess/conn is bound ++ */ ++ ++static int cxgb3i_conn_bind(struct iscsi_cls_session *cls_session, ++ struct iscsi_cls_conn *cls_conn, ++ u64 transport_eph, int is_leading) ++{ ++ struct iscsi_conn *conn = cls_conn->dd_data; ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; ++ struct iscsi_endpoint *ep; ++ struct cxgb3i_endpoint *cep; ++ struct s3_conn *c3cn; ++ int err; ++ ++ ep = iscsi_lookup_endpoint(transport_eph); ++ if (!ep) ++ return -EINVAL; ++ ++ cxgb3i_log_debug("ep 0x%p, cls sess 0x%p, cls conn 0x%p.\n", ++ ep, cls_session, cls_conn); ++ ++ err = iscsi_conn_bind(cls_session, cls_conn, is_leading); ++ if (err) ++ return -EINVAL; ++ ++ cep = ep->dd_data; ++ c3cn = cep->c3cn; ++ ++ read_lock(&c3cn->callback_lock); ++ /* mnc: TODO don't abuse iscsi_tcp fields */ ++ tcp_conn->sock = (struct socket *)c3cn; ++ c3cn->user_data = conn; ++ read_unlock(&c3cn->callback_lock); ++ ++ cconn->hba = cep->hba; ++ cconn->cep = cep; ++ cep->cconn = cconn; ++ ++ cxgb3i_conn_max_xmit_dlength(conn); ++ cxgb3i_conn_max_recv_dlength(conn); ++ ++ spin_lock_bh(&conn->session->lock); ++ sprintf(conn->portal_address, NIPQUAD_FMT, ++ NIPQUAD(c3cn->daddr.sin_addr.s_addr)); ++ conn->portal_port = ntohs(c3cn->daddr.sin_port); ++ spin_unlock_bh(&conn->session->lock); ++ ++ tcp_conn->xmit_segment = cxgb3i_conn_xmit_segment; ++ iscsi_tcp_hdr_recv_prep(tcp_conn); ++ ++ return 0; ++} ++ ++/** ++ * cxgb3i_conn_get_param - return iscsi connection parameter to caller ++ * @cls_conn: pointer to iscsi cls conn ++ * @param: parameter type identifier ++ * @buf: buffer pointer ++ * ++ * returns iSCSI connection parameters ++ */ ++static int cxgb3i_conn_get_param(struct iscsi_cls_conn *cls_conn, ++ enum iscsi_param param, char *buf) ++{ ++ struct iscsi_conn *conn = cls_conn->dd_data; ++ int len; ++ ++ cxgb3i_log_debug("cls_conn 0x%p, param %d.\n", cls_conn, param); ++ ++ switch (param) { ++ case ISCSI_PARAM_CONN_PORT: ++ spin_lock_bh(&conn->session->lock); ++ len = sprintf(buf, "%hu\n", conn->portal_port); ++ spin_unlock_bh(&conn->session->lock); ++ break; ++ case ISCSI_PARAM_CONN_ADDRESS: ++ spin_lock_bh(&conn->session->lock); ++ len = sprintf(buf, "%s\n", conn->portal_address); ++ spin_unlock_bh(&conn->session->lock); ++ break; ++ default: ++ return iscsi_conn_get_param(cls_conn, param, buf); ++ } ++ ++ return len; ++} ++ ++static int cxgb3i_conn_set_param(struct iscsi_cls_conn *cls_conn, ++ enum iscsi_param param, char *buf, int buflen) ++{ ++ struct iscsi_conn *conn = cls_conn->dd_data; ++ struct iscsi_session *session = conn->session; ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ int value, err = 0; ++ ++ switch (param) { ++ case ISCSI_PARAM_HDRDGST_EN: ++ err = iscsi_set_param(cls_conn, param, buf, buflen); ++ if (!err && conn->hdrdgst_en) ++ cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en, ++ conn->datadgst_en); ++ break; ++ case ISCSI_PARAM_DATADGST_EN: ++ err = iscsi_set_param(cls_conn, param, buf, buflen); ++ if (!err && conn->datadgst_en) ++ cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en, ++ conn->datadgst_en); ++ break; ++ case ISCSI_PARAM_MAX_R2T: ++ sscanf(buf, "%d", &value); ++ if (value <= 0 || !is_power_of_2(value)) ++ return -EINVAL; ++ if (session->max_r2t == value) ++ break; ++ iscsi_r2tpool_free(session); ++ err = iscsi_set_param(cls_conn, param, buf, buflen); ++ if (!err && iscsi_r2tpool_alloc(session)) ++ return -ENOMEM; ++ case ISCSI_PARAM_MAX_RECV_DLENGTH: ++ err = iscsi_set_param(cls_conn, param, buf, buflen); ++ cxgb3i_conn_max_recv_dlength(conn); ++ break; ++ case ISCSI_PARAM_MAX_XMIT_DLENGTH: ++ err = iscsi_set_param(cls_conn, param, buf, buflen); ++ cxgb3i_conn_max_xmit_dlength(conn); ++ break; ++ default: ++ return iscsi_set_param(cls_conn, param, buf, buflen); ++ } ++ return err; ++} ++ ++/** ++ * cxgb3i_host_set_param - configure host (adapter) related parameters ++ * @shost: scsi host pointer ++ * @param: parameter type identifier ++ * @buf: buffer pointer ++ */ ++static int cxgb3i_host_set_param(struct Scsi_Host *shost, ++ enum iscsi_host_param param, ++ char *buf, int buflen) ++{ ++ struct cxgb3i_hba *hba = iscsi_host_priv(shost); ++ ++ cxgb3i_log_debug("param %d, buf %s.\n", param, buf); ++ ++ if (hba && param == ISCSI_HOST_PARAM_IPADDRESS) { ++ __be32 addr = in_aton(buf); ++ cxgb3i_set_private_ipv4addr(hba->ndev, addr); ++ return 0; ++ } ++ ++ return iscsi_host_get_param(shost, param, buf); ++} ++ ++/** ++ * cxgb3i_host_get_param - returns host (adapter) related parameters ++ * @shost: scsi host pointer ++ * @param: parameter type identifier ++ * @buf: buffer pointer ++ */ ++static int cxgb3i_host_get_param(struct Scsi_Host *shost, ++ enum iscsi_host_param param, char *buf) ++{ ++ struct cxgb3i_hba *hba = iscsi_host_priv(shost); ++ int i; ++ int len = 0; ++ ++ cxgb3i_log_debug("hba %s, param %d.\n", hba->ndev->name, param); ++ ++ switch (param) { ++ case ISCSI_HOST_PARAM_HWADDRESS: ++ for (i = 0; i < 6; i++) ++ len += ++ sprintf(buf + len, "%02x.", ++ hba->ndev->dev_addr[i]); ++ len--; ++ buf[len] = '\0'; ++ break; ++ case ISCSI_HOST_PARAM_NETDEV_NAME: ++ len = sprintf(buf, "%s\n", hba->ndev->name); ++ break; ++ case ISCSI_HOST_PARAM_IPADDRESS: ++ { ++ __be32 addr; ++ ++ addr = cxgb3i_get_private_ipv4addr(hba->ndev); ++ len = sprintf(buf, "%u.%u.%u.%u", NIPQUAD(addr)); ++ break; ++ } ++ default: ++ return iscsi_host_get_param(shost, param, buf); ++ } ++ return len; ++} ++ ++/** ++ * cxgb3i_conn_get_stats - returns iSCSI stats ++ * @cls_conn: pointer to iscsi cls conn ++ * @stats: pointer to iscsi statistic struct ++ */ ++static void cxgb3i_conn_get_stats(struct iscsi_cls_conn *cls_conn, ++ struct iscsi_stats *stats) ++{ ++ struct iscsi_conn *conn = cls_conn->dd_data; ++ ++ stats->txdata_octets = conn->txdata_octets; ++ stats->rxdata_octets = conn->rxdata_octets; ++ stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; ++ stats->dataout_pdus = conn->dataout_pdus_cnt; ++ stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; ++ stats->datain_pdus = conn->datain_pdus_cnt; ++ stats->r2t_pdus = conn->r2t_pdus_cnt; ++ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; ++ stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; ++ stats->digest_err = 0; ++ stats->timeout_err = 0; ++ stats->custom_length = 1; ++ strcpy(stats->custom[0].desc, "eh_abort_cnt"); ++ stats->custom[0].value = conn->eh_abort_cnt; ++} ++ ++static inline u32 tag_base(struct cxgb3i_tag_format *format, ++ unsigned int idx, unsigned int age) ++{ ++ u32 sw_bits = idx | (age << format->idx_bits); ++ u32 tag = sw_bits >> format->rsvd_shift; ++ ++ tag <<= format->rsvd_bits + format->rsvd_shift; ++ tag |= sw_bits & ((1 << format->rsvd_shift) - 1); ++ return tag; ++} ++ ++static inline void cxgb3i_parse_tag(struct cxgb3i_tag_format *format, ++ u32 tag, u32 *rsvd_bits, u32 *sw_bits) ++{ ++ if (rsvd_bits) ++ *rsvd_bits = (tag >> format->rsvd_shift) & format->rsvd_mask; ++ if (sw_bits) { ++ *sw_bits = (tag >> (format->rsvd_shift + format->rsvd_bits)) ++ << format->rsvd_shift; ++ *sw_bits |= tag & ((1 << format->rsvd_shift) - 1); ++ } ++} ++ ++ ++static void cxgb3i_parse_itt(struct iscsi_conn *conn, itt_t itt, ++ int *idx, int *age) ++{ ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ struct cxgb3i_adapter *snic = cconn->hba->snic; ++ u32 sw_bits; ++ ++ cxgb3i_parse_tag(&snic->tag_format, itt, NULL, &sw_bits); ++ if (idx) ++ *idx = sw_bits & ISCSI_ITT_MASK; ++ if (age) ++ *age = (sw_bits >> snic->tag_format.idx_bits) & ISCSI_AGE_MASK; ++} ++ ++static int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) ++{ ++ struct scsi_cmnd *sc = task->sc; ++ struct iscsi_conn *conn = task->conn; ++ struct iscsi_session *sess = conn->session; ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; ++ struct cxgb3i_adapter *snic = cconn->hba->snic; ++ u32 sw_tag = tag_base(&snic->tag_format, task->itt, sess->age); ++ u32 tag = RESERVED_ITT; ++ ++ if (sc && (sc->sc_data_direction == DMA_FROM_DEVICE)) { ++ struct s3_conn *c3cn = (struct s3_conn *)(tcp_conn->sock); ++ tag = ++ cxgb3i_ddp_tag_reserve(snic, c3cn->tid, sw_tag, ++ scsi_out(sc)->length, ++ scsi_out(sc)->table.sgl, ++ scsi_out(sc)->table.nents); ++ } ++ if (tag == RESERVED_ITT) ++ tag = sw_tag | (snic->tag_format.rsvd_mask << ++ snic->tag_format.rsvd_shift); ++ *hdr_itt = htonl(tag); ++ return 0; ++} ++ ++static void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt) ++{ ++ struct scsi_cmnd *sc = task->sc; ++ struct iscsi_conn *conn = task->conn; ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ struct cxgb3i_adapter *snic = cconn->hba->snic; ++ ++ hdr_itt = ntohl(hdr_itt); ++ if (sc && (sc->sc_data_direction == DMA_FROM_DEVICE)) ++ cxgb3i_ddp_tag_release(snic, hdr_itt, ++ scsi_out(sc)->table.sgl, ++ scsi_out(sc)->table.nents); ++} ++ ++/** ++ * cxgb3i_host_template -- Scsi_Host_Template structure ++ * used when registering with the scsi mid layer ++ */ ++static struct scsi_host_template cxgb3i_host_template = { ++ .module = THIS_MODULE, ++ .name = "Chelsio S3xx iSCSI Initiator", ++ .proc_name = "cxgb3i", ++ .queuecommand = iscsi_queuecommand, ++ .change_queue_depth = iscsi_change_queue_depth, ++ .can_queue = 128 * (ISCSI_DEF_XMIT_CMDS_MAX - 1), ++ .sg_tablesize = SG_ALL, ++ .max_sectors = 0xFFFF, ++ .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, ++ .eh_abort_handler = iscsi_eh_abort, ++ .eh_device_reset_handler = iscsi_eh_device_reset, ++ .eh_target_reset_handler = iscsi_eh_host_reset, ++ .use_clustering = DISABLE_CLUSTERING, ++ .this_id = -1, ++}; ++ ++static struct iscsi_transport cxgb3i_iscsi_transport = { ++ .owner = THIS_MODULE, ++ .name = "cxgb3i", ++ .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST ++ | CAP_DATADGST | CAP_DIGEST_OFFLOAD, ++ .param_mask = ISCSI_MAX_RECV_DLENGTH | ++ ISCSI_MAX_XMIT_DLENGTH | ++ ISCSI_HDRDGST_EN | ++ ISCSI_DATADGST_EN | ++ ISCSI_INITIAL_R2T_EN | ++ ISCSI_MAX_R2T | ++ ISCSI_IMM_DATA_EN | ++ ISCSI_FIRST_BURST | ++ ISCSI_MAX_BURST | ++ ISCSI_PDU_INORDER_EN | ++ ISCSI_DATASEQ_INORDER_EN | ++ ISCSI_ERL | ++ ISCSI_CONN_PORT | ++ ISCSI_CONN_ADDRESS | ++ ISCSI_EXP_STATSN | ++ ISCSI_PERSISTENT_PORT | ++ ISCSI_PERSISTENT_ADDRESS | ++ ISCSI_TARGET_NAME | ISCSI_TPGT | ++ ISCSI_USERNAME | ISCSI_PASSWORD | ++ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | ++ ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | ++ ISCSI_LU_RESET_TMO | ++ ISCSI_PING_TMO | ISCSI_RECV_TMO | ++ ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, ++ .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ++ ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME, ++ .get_host_param = cxgb3i_host_get_param, ++ .set_host_param = cxgb3i_host_set_param, ++ /* session management */ ++ .create_session = cxgb3i_session_create, ++ .destroy_session = cxgb3i_session_destroy, ++ .get_session_param = iscsi_session_get_param, ++ /* connection management */ ++ .create_conn = cxgb3i_conn_create, ++ .bind_conn = cxgb3i_conn_bind, ++ .destroy_conn = iscsi_conn_teardown, ++ .start_conn = iscsi_conn_start, ++ .stop_conn = iscsi_conn_stop, ++ .get_conn_param = cxgb3i_conn_get_param, ++ .set_param = cxgb3i_conn_set_param, ++ .get_stats = cxgb3i_conn_get_stats, ++ /* pdu xmit req. from user space */ ++ .send_pdu = iscsi_conn_send_pdu, ++ /* task */ ++ .init_task = iscsi_tcp_task_init, ++ .xmit_task = iscsi_tcp_task_xmit, ++ .cleanup_task = iscsi_tcp_cleanup_task, ++ .parse_itt = cxgb3i_parse_itt, ++ .reserve_itt = cxgb3i_reserve_itt, ++ .release_itt = cxgb3i_release_itt, ++ /* TCP connect/disconnect */ ++ .ep_connect = cxgb3i_ep_connect, ++ .ep_poll = cxgb3i_ep_poll, ++ .ep_disconnect = cxgb3i_ep_disconnect, ++ /* Error recovery timeout call */ ++ .session_recovery_timedout = iscsi_session_recovery_timedout, ++}; ++ ++int cxgb3i_iscsi_init(void) ++{ ++ cxgb3i_scsi_transport = ++ iscsi_register_transport(&cxgb3i_iscsi_transport); ++ if (!cxgb3i_scsi_transport) { ++ cxgb3i_log_error("Could not register cxgb3i transport.\n"); ++ return -ENODEV; ++ } ++ cxgb3i_log_debug("cxgb3i transport 0x%p.\n", cxgb3i_scsi_transport); ++ return 0; ++} ++ ++void cxgb3i_iscsi_cleanup(void) ++{ ++ if (cxgb3i_scsi_transport) { ++ cxgb3i_log_debug("cxgb3i transport 0x%p.\n", ++ cxgb3i_scsi_transport); ++ iscsi_unregister_transport(&cxgb3i_iscsi_transport); ++ } ++} +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c +@@ -0,0 +1,2021 @@ ++/* ++ * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. ++ * ++ * Written by Dimitris Michailidis (dm@chelsio.com) ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this ++ * release for licensing terms and conditions. ++ */ ++ ++#include ++#include ++ ++#include "cxgb3_defs.h" ++#include "cxgb3_ctl_defs.h" ++#include "firmware_exports.h" ++#include "cxgb3i_offload.h" ++#include "cxgb3i_ulp2.h" ++ ++static int cxgb3_rcv_win = 256 * 1024; ++module_param(cxgb3_rcv_win, int, 0644); ++MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=256KB)"); ++ ++static int cxgb3_snd_win = 64 * 1024; ++module_param(cxgb3_snd_win, int, 0644); ++MODULE_PARM_DESC(cxgb3_snd_win, "TCP send window in bytes (default=64KB)"); ++ ++static int cxgb3_rx_credit_thres = 10 * 1024; ++module_param(cxgb3_rx_credit_thres, int, 0644); ++MODULE_PARM_DESC(rx_credit_thres, ++ "RX credits return threshold in bytes (default=10KB)"); ++ ++static unsigned int cxgb3_max_connect = 8 * 1024; ++module_param(cxgb3_max_connect, uint, 0644); ++MODULE_PARM_DESC(cxgb3_max_connect, "Max. # of connections (default=8092)"); ++ ++static unsigned int cxgb3_sport_base = 20000; ++module_param(cxgb3_sport_base, uint, 0644); ++MODULE_PARM_DESC(cxgb3_sport_base, "starting port number (default=20000)"); ++ ++#ifdef __DEBUG_C3CN_TX__ ++#define c3cn_tx_debug cxgb3i_log_debug ++#else ++#define c3cn_tx_debug(fmt...) ++#endif ++ ++/* connection flags */ ++static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag) ++{ ++ __set_bit(flag, &c3cn->flags); ++ c3cn_conn_debug("c3cn 0x%p, set %d, s 0x%x, f 0x%lx.\n", ++ c3cn, flag, c3cn->state, c3cn->flags); ++} ++ ++static inline void c3cn_reset_flag(struct s3_conn *c3cn, enum c3cn_flags flag) ++{ ++ __clear_bit(flag, &c3cn->flags); ++ c3cn_conn_debug("c3cn 0x%p, clear %d, s 0x%x, f 0x%lx.\n", ++ c3cn, flag, c3cn->state, c3cn->flags); ++} ++ ++static inline int c3cn_flag(struct s3_conn *c3cn, enum c3cn_flags flag) ++{ ++ if (c3cn == NULL) ++ return 0; ++ return test_bit(flag, &c3cn->flags); ++} ++ ++/* connection state */ ++static void c3cn_set_state(struct s3_conn *c3cn, int state) ++{ ++ c3cn_conn_debug("c3cn 0x%p state -> 0x%x.\n", c3cn, state); ++ c3cn->state = state; ++} ++ ++/* connection reference count */ ++static inline void c3cn_hold(struct s3_conn *c3cn) ++{ ++ atomic_inc(&c3cn->refcnt); ++} ++ ++static inline void c3cn_put(struct s3_conn *c3cn) ++{ ++ if (atomic_dec_and_test(&c3cn->refcnt)) { ++ c3cn_conn_debug("free c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ kfree(c3cn); ++ } ++} ++ ++/* minimal port allocation management scheme */ ++static spinlock_t sport_map_lock; ++static unsigned int sport_map_next; ++static unsigned long *sport_map; ++ ++/* ++ * Find a free source port in our allocation map. We use a very simple rotor ++ * scheme to look for the next free port. ++ * ++ * If a source port has been specified make sure that it doesn't collide with ++ * our normal source port allocation map. If it's outside the range of our ++ * allocation scheme just let them use it. ++ */ ++static int c3cn_get_port(struct s3_conn *c3cn) ++{ ++ unsigned int start; ++ ++ if (!sport_map) ++ goto error_out; ++ ++ if (c3cn->saddr.sin_port != 0) { ++ int sport = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; ++ int err = 0; ++ ++ if (sport < 0 || sport >= cxgb3_max_connect) ++ return 0; ++ spin_lock(&sport_map_lock); ++ err = __test_and_set_bit(sport, sport_map); ++ spin_unlock(&sport_map_lock); ++ return err ? -EADDRINUSE : 0; ++ } ++ ++ spin_lock(&sport_map_lock); ++ start = sport_map_next; ++ do { ++ unsigned int new = sport_map_next; ++ if (++sport_map_next >= cxgb3_max_connect) ++ sport_map_next = 0; ++ if (!(__test_and_set_bit(new, sport_map))) { ++ spin_unlock(&sport_map_lock); ++ c3cn_conn_debug("reserve port %u.\n", ++ cxgb3_sport_base + new); ++ c3cn->saddr.sin_port = htons(cxgb3_sport_base + new); ++ return 0; ++ } ++ } while (sport_map_next != start); ++ spin_unlock(&sport_map_lock); ++ ++error_out: ++ return -EADDRNOTAVAIL; ++} ++ ++/* ++ * Deallocate a source port from the allocation map. If the source port is ++ * outside our allocation range just return -- the caller is responsible for ++ * keeping track of their port usage outside of our allocation map. ++ */ ++static void c3cn_put_port(struct s3_conn *c3cn) ++{ ++ if (c3cn->saddr.sin_port) { ++ int old = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; ++ c3cn->saddr.sin_port = 0; ++ ++ if (old < 0 || old >= cxgb3_max_connect) ++ return; ++ ++ c3cn_conn_debug("release port %u.\n", cxgb3_sport_base + old); ++ spin_lock(&sport_map_lock); ++ __clear_bit(old, sport_map); ++ spin_unlock(&sport_map_lock); ++ } ++} ++ ++static void c3cn_reset_timer(struct s3_conn *c3cn, struct timer_list *timer, ++ unsigned long expires) ++{ ++ if (!mod_timer(timer, expires)) ++ c3cn_hold(c3cn); ++} ++ ++typedef int (cxgb3_cpl_handler_decl) (struct t3cdev *, ++ struct sk_buff *, void *); ++ ++static cxgb3_cpl_handler_decl do_act_establish; ++static cxgb3_cpl_handler_decl do_act_open_rpl; ++static cxgb3_cpl_handler_decl do_wr_ack; ++static cxgb3_cpl_handler_decl do_peer_close; ++static cxgb3_cpl_handler_decl do_abort_req; ++static cxgb3_cpl_handler_decl do_abort_rpl; ++static cxgb3_cpl_handler_decl do_close_con_rpl; ++static cxgb3_cpl_handler_decl do_iscsi_hdr; ++ ++static LIST_HEAD(cxgb3_list); ++static DEFINE_MUTEX(cxgb3_list_lock); ++ ++/* ++ * For ULP connections HW may inserts digest bytes into the pdu. This array ++ * contains the compensating extra lengths for ULP packets. It is indexed by ++ * a packet's ULP submode. ++ */ ++static const unsigned int cxgb3_ulp_extra_len[] = { 0, 4, 4, 8 }; ++ ++/* ++ * Return the length of any HW additions that will be made to a Tx packet. ++ * Such additions can happen for some types of ULP packets. ++ */ ++static inline unsigned int ulp_extra_len(const struct sk_buff *skb) ++{ ++ return cxgb3_ulp_extra_len[skb_ulp_mode(skb) & 3]; ++} ++ ++/* ++ * Size of WRs in bytes. Note that we assume all devices we are handling have ++ * the same WR size. ++ */ ++static unsigned int wrlen __read_mostly; ++ ++/* ++ * The number of WRs needed for an skb depends on the number of page fragments ++ * in the skb and whether it has any payload in its main body. This maps the ++ * length of the gather list represented by an skb into the # of necessary WRs. ++ */ ++static unsigned int skb_wrs[MAX_SKB_FRAGS + 2] __read_mostly; ++ ++static void s3_init_wr_tab(unsigned int wr_len) ++{ ++ int i; ++ ++ if (skb_wrs[1]) /* already initialized */ ++ return; ++ ++ for (i = 1; i < ARRAY_SIZE(skb_wrs); i++) { ++ int sgl_len = (3 * i) / 2 + (i & 1); ++ ++ sgl_len += 3; ++ skb_wrs[i] = (sgl_len <= wr_len ++ ? 1 : 1 + (sgl_len - 2) / (wr_len - 1)); ++ } ++ ++ wrlen = wr_len * 8; ++} ++ ++/* ++ * cxgb3i API operations. ++ */ ++/* ++ * large memory chunk allocation/release ++ */ ++void *cxgb3i_alloc_big_mem(unsigned int size) ++{ ++ void *p = kmalloc(size, GFP_KERNEL); ++ if (!p) ++ p = vmalloc(size); ++ if (p) ++ memset(p, 0, size); ++ return p; ++} ++ ++void cxgb3i_free_big_mem(void *addr) ++{ ++ if (is_vmalloc_addr(addr)) ++ vfree(addr); ++ else ++ kfree(addr); ++} ++ ++void cxgb3i_sdev_cleanup(void) ++{ ++ if (sport_map) ++ cxgb3i_free_big_mem(sport_map); ++} ++ ++int cxgb3i_sdev_init(cxgb3_cpl_handler_func *cpl_handlers) ++{ ++ cpl_handlers[CPL_ACT_ESTABLISH] = do_act_establish; ++ cpl_handlers[CPL_ACT_OPEN_RPL] = do_act_open_rpl; ++ cpl_handlers[CPL_PEER_CLOSE] = do_peer_close; ++ cpl_handlers[CPL_ABORT_REQ_RSS] = do_abort_req; ++ cpl_handlers[CPL_ABORT_RPL_RSS] = do_abort_rpl; ++ cpl_handlers[CPL_CLOSE_CON_RPL] = do_close_con_rpl; ++ cpl_handlers[CPL_TX_DMA_ACK] = do_wr_ack; ++ cpl_handlers[CPL_ISCSI_HDR] = do_iscsi_hdr; ++ ++ if (cxgb3_max_connect > CXGB3I_MAX_CONN) ++ cxgb3_max_connect = CXGB3I_MAX_CONN; ++ sport_map = cxgb3i_alloc_big_mem(DIV_ROUND_UP(cxgb3_max_connect, ++ 8 * ++ sizeof(unsigned long))); ++ if (!sport_map) ++ return -ENOMEM; ++ return 0; ++} ++ ++void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) ++{ ++ struct cxgb3i_sdev_data *cdata; ++ struct adap_ports *ports; ++ struct ofld_page_info rx_page_info; ++ unsigned int wr_len; ++ int i; ++ ++ cdata = kzalloc(sizeof *cdata, GFP_KERNEL); ++ if (!cdata) ++ return; ++ ports = kzalloc(sizeof *ports, GFP_KERNEL); ++ if (!ports) ++ goto free_ports; ++ cdata->ports = ports; ++ ++ if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || ++ cdev->ctl(cdev, GET_PORTS, cdata->ports) < 0 || ++ cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) ++ goto free_ports; ++ ++ s3_init_wr_tab(wr_len); ++ ++ INIT_LIST_HEAD(&cdata->list); ++ cdata->cdev = cdev; ++ cdata->client = client; ++ cdata->rx_page_size = rx_page_info.page_size; ++ skb_queue_head_init(&cdata->deferq); ++ ++ for (i = 0; i < ports->nports; i++) ++ NDEV2CDATA(ports->lldevs[i]) = cdata; ++ ++ mutex_lock(&cxgb3_list_lock); ++ list_add_tail(&cdata->list, &cxgb3_list); ++ mutex_unlock(&cxgb3_list_lock); ++ ++ return; ++ ++free_ports: ++ kfree(ports); ++ kfree(cdata); ++} ++ ++void cxgb3i_sdev_remove(struct t3cdev *cdev) ++{ ++ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); ++ struct adap_ports *ports = cdata->ports; ++ int i; ++ ++ for (i = 0; i < ports->nports; i++) ++ NDEV2CDATA(ports->lldevs[i]) = NULL; ++ ++ mutex_lock(&cxgb3_list_lock); ++ list_del(&cdata->list); ++ mutex_unlock(&cxgb3_list_lock); ++ ++ kfree(ports); ++ kfree(cdata); ++} ++ ++/* ++ * Return TRUE if the specified net device is for a port on one of our ++ * registered adapters. ++ */ ++static int is_cxgb3_dev(struct net_device *dev) ++{ ++ struct cxgb3i_sdev_data *cdata; ++ ++ mutex_lock(&cxgb3_list_lock); ++ list_for_each_entry(cdata, &cxgb3_list, list) { ++ struct adap_ports *ports = cdata->ports; ++ int i; ++ ++ for (i = 0; i < ports->nports; i++) ++ if (dev == ports->lldevs[i]) { ++ mutex_unlock(&cxgb3_list_lock); ++ return 1; ++ } ++ } ++ mutex_unlock(&cxgb3_list_lock); ++ return 0; ++} ++ ++/* ++ * Primary cxgb3 API operations. ++ * ============================= ++ */ ++ ++static int s3_push_frames(struct s3_conn *, int); ++static int s3_send_reset(struct s3_conn *, int, struct sk_buff *); ++static void t3_release_offload_resources(struct s3_conn *); ++static void mk_close_req(struct s3_conn *); ++ ++struct s3_conn *cxgb3i_c3cn_create(void) ++{ ++ struct s3_conn *c3cn; ++ ++ c3cn = kzalloc(sizeof(*c3cn), GFP_KERNEL); ++ if (c3cn == NULL) ++ return NULL; ++ ++ c3cn_conn_debug("alloc c3cn 0x%p.\n", c3cn); ++ ++ c3cn->flags = 0; ++ spin_lock_init(&c3cn->lock); ++ atomic_set(&c3cn->refcnt, 1); ++ skb_queue_head_init(&c3cn->receive_queue); ++ skb_queue_head_init(&c3cn->write_queue); ++ setup_timer(&c3cn->retry_timer, NULL, (unsigned long)c3cn); ++ rwlock_init(&c3cn->callback_lock); ++ ++ return c3cn; ++} ++ ++static inline void s3_purge_write_queue(struct s3_conn *c3cn) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = __skb_dequeue(&c3cn->write_queue))) ++ __kfree_skb(skb); ++} ++ ++static void c3cn_done(struct s3_conn *c3cn) ++{ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ c3cn_put_port(c3cn); ++ t3_release_offload_resources(c3cn); ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSE); ++ c3cn->shutdown = C3CN_SHUTDOWN_MASK; ++ cxgb3i_conn_closing(c3cn); ++} ++ ++static void c3cn_close(struct s3_conn *c3cn) ++{ ++ int data_lost, old_state; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ dst_confirm(c3cn->dst_cache); ++ ++ spin_lock_bh(&c3cn->lock); ++ c3cn->shutdown |= C3CN_SHUTDOWN_MASK; ++ ++ /* ++ * We need to flush the receive buffs. We do this only on the ++ * descriptor close, not protocol-sourced closes, because the ++ * reader process may not have drained the data yet! Make a note ++ * of whether any received data will be lost so we can decide whether ++ * to FIN or RST. ++ */ ++ data_lost = skb_queue_len(&c3cn->receive_queue); ++ __skb_queue_purge(&c3cn->receive_queue); ++ ++ if (c3cn->state == C3CN_STATE_CLOSE) ++ /* Nothing if we are already closed */ ++ c3cn_conn_debug("c3cn 0x%p, 0x%x, already closed.\n", ++ c3cn, c3cn->state); ++ else if (data_lost || c3cn->state == C3CN_STATE_SYN_SENT) { ++ c3cn_conn_debug("c3cn 0x%p, 0x%x -> closing, send reset.\n", ++ c3cn, c3cn->state); ++ /* Unread data was tossed, zap the connection. */ ++ s3_send_reset(c3cn, CPL_ABORT_SEND_RST, NULL); ++ goto unlock; ++ } else if (c3cn->state == C3CN_STATE_ESTABLISHED) { ++ c3cn_conn_debug("c3cn 0x%p, est. -> closing, send close_req.\n", ++ c3cn); ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSING); ++ mk_close_req(c3cn); ++ } ++ ++unlock: ++ old_state = c3cn->state; ++ c3cn_hold(c3cn); /* must last past the potential destroy() */ ++ ++ spin_unlock_bh(&c3cn->lock); ++ ++ /* ++ * There are no more user references at this point. Grab the ++ * connection lock and finish the close. ++ */ ++ local_bh_disable(); ++ spin_lock(&c3cn->lock); ++ ++ /* ++ * Because the connection was orphaned before the spin_lock() ++ * either the backlog or a BH may have already destroyed it. ++ * Bail out if so. ++ */ ++ if (old_state != C3CN_STATE_CLOSE && c3cn->state == C3CN_STATE_CLOSE) ++ goto out; ++ ++ if (c3cn->state == C3CN_STATE_CLOSE) ++ s3_purge_write_queue(c3cn); ++ ++out: ++ spin_unlock(&c3cn->lock); ++ local_bh_enable(); ++ c3cn_put(c3cn); ++} ++ ++void cxgb3i_c3cn_release(struct s3_conn *c3cn) ++{ ++ c3cn_conn_debug("c3cn 0x%p, s 0x%x, f 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ if (likely(c3cn->state != C3CN_STATE_SYN_SENT)) ++ c3cn_close(c3cn); ++ else ++ c3cn_set_flag(c3cn, C3CN_CLOSE_NEEDED); ++ c3cn_put(c3cn); ++} ++ ++ ++/* ++ * Local utility routines used to implement primary cxgb3 API operations. ++ * ====================================================================== ++ */ ++ ++static u32 s3_send_rx_credits(struct s3_conn *, u32, u32, int); ++static int act_open(struct s3_conn *, struct net_device *); ++static void mk_act_open_req(struct s3_conn *, struct sk_buff *, ++ unsigned int, const struct l2t_entry *); ++static void skb_entail(struct s3_conn *, struct sk_buff *, int); ++ ++static inline void reset_wr_list(struct s3_conn *c3cn) ++{ ++ c3cn->wr_pending_head = NULL; ++} ++ ++/* ++ * Add a WR to a connections's list of pending WRs. This is a singly-linked ++ * list of sk_buffs operating as a FIFO. The head is kept in wr_pending_head ++ * and the tail in wr_pending_tail. ++ */ ++static inline void enqueue_wr(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ skb->sp = NULL; ++ ++ /* ++ * We want to take an extra reference since both us and the driver ++ * need to free the packet before it's really freed. We know there's ++ * just one user currently so we use atomic_set rather than skb_get ++ * to avoid the atomic op. ++ */ ++ atomic_set(&skb->users, 2); ++ ++ if (!c3cn->wr_pending_head) ++ c3cn->wr_pending_head = skb; ++ else ++ c3cn->wr_pending_tail->sp = (void *)skb; ++ c3cn->wr_pending_tail = skb; ++} ++ ++/* ++ * The next two functions calculate the option 0 value for a connection. ++ */ ++static inline int compute_wscale(int win) ++{ ++ int wscale = 0; ++ while (wscale < 14 && (65535<mss_idx); ++} ++ ++static inline unsigned int calc_opt0l(struct s3_conn *c3cn) ++{ ++ return V_ULP_MODE(ULP_MODE_ISCSI) | ++ V_RCV_BUFSIZ(cxgb3_rcv_win>>10); ++} ++ ++static inline void make_tx_data_wr(struct s3_conn *c3cn, ++ struct sk_buff *skb, int len) ++{ ++ struct tx_data_wr *req; ++ ++ skb_reset_transport_header(skb); ++ req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req)); ++ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); ++ req->wr_lo = htonl(V_WR_TID(c3cn->tid)); ++ req->sndseq = htonl(c3cn->snd_nxt); ++ /* len includes the length of any HW ULP additions */ ++ req->len = htonl(len); ++ req->param = htonl(V_TX_PORT(c3cn->l2t->smt_idx)); ++ /* V_TX_ULP_SUBMODE sets both the mode and submode */ ++ req->flags = htonl(V_TX_ULP_SUBMODE(skb_ulp_mode(skb)) | ++ V_TX_SHOVE((skb_peek(&c3cn->write_queue) ? 0 : 1))); ++ ++ if (!c3cn_flag(c3cn, C3CN_TX_DATA_SENT)) { ++ ++ req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | ++ V_TX_CPU_IDX(c3cn->qset)); ++ ++ /* Sendbuffer is in units of 32KB. ++ */ ++ req->param |= htonl(V_TX_SNDBUF(cxgb3_snd_win >> 15)); ++ c3cn_set_flag(c3cn, C3CN_TX_DATA_SENT); ++ } ++} ++ ++/** ++ * cxgb3_egress_dev - return the cxgb3 egress device ++ * @root_dev: the root device anchoring the search ++ * @c3cn: the connection used to determine egress port in bonding mode ++ * @context: in bonding mode, indicates a connection set up or failover ++ * ++ * Return egress device or NULL if the egress device isn't one of our ports. ++ * ++ * Given a root network device it returns the physical egress device that is a ++ * descendant of the root device. The root device may be either a physical ++ * device, in which case it is the device returned, or a virtual device, such ++ * as a VLAN or bonding device. In case of a bonding device the search ++ * considers the decisions of the bonding device given its mode to locate the ++ * correct egress device. ++ */ ++static struct net_device *cxgb3_egress_dev(struct net_device *root_dev, ++ struct s3_conn *c3cn, ++ int context) ++{ ++ while (root_dev) { ++ if (root_dev->priv_flags & IFF_802_1Q_VLAN) ++ root_dev = vlan_dev_real_dev(root_dev); ++ else if (is_cxgb3_dev(root_dev)) ++ return root_dev; ++ else ++ return NULL; ++ } ++ return NULL; ++} ++ ++static struct rtable *find_route(__be32 saddr, __be32 daddr, ++ __be16 sport, __be16 dport) ++{ ++ struct rtable *rt; ++ struct flowi fl = { ++ .oif = 0, ++ .nl_u = { ++ .ip4_u = { ++ .daddr = daddr, ++ .saddr = saddr, ++ .tos = 0 } }, ++ .proto = IPPROTO_TCP, ++ .uli_u = { ++ .ports = { ++ .sport = sport, ++ .dport = dport } } }; ++ ++ if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0)) ++ return NULL; ++ return rt; ++} ++ ++int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) ++{ ++ struct rtable *rt; ++ struct net_device *dev; ++ struct cxgb3i_sdev_data *cdata; ++ struct t3cdev *cdev; ++ __be32 sipv4; ++ int err; ++ ++ if (usin->sin_family != AF_INET) ++ return -EAFNOSUPPORT; ++ ++ /* get a source port if one hasn't been provided */ ++ err = c3cn_get_port(c3cn); ++ if (err) ++ return err; ++ ++ c3cn_conn_debug("c3cn 0x%p get port %u.\n", ++ c3cn, ntohs(c3cn->saddr.sin_port)); ++ ++ c3cn->daddr.sin_port = usin->sin_port; ++ c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; ++ ++ rt = find_route(c3cn->saddr.sin_addr.s_addr, ++ c3cn->daddr.sin_addr.s_addr, ++ c3cn->saddr.sin_port, ++ c3cn->daddr.sin_port); ++ if (rt == NULL) { ++ c3cn_conn_debug("NO route to 0x%x, port %u.\n", ++ c3cn->daddr.sin_addr.s_addr, ++ ntohs(c3cn->daddr.sin_port)); ++ return -ENETUNREACH; ++ } ++ ++ if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { ++ c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n", ++ c3cn->daddr.sin_addr.s_addr, ++ ntohs(c3cn->daddr.sin_port)); ++ ip_rt_put(rt); ++ return -ENETUNREACH; ++ } ++ ++ if (!c3cn->saddr.sin_addr.s_addr) ++ c3cn->saddr.sin_addr.s_addr = rt->rt_src; ++ ++ /* now commit destination to connection */ ++ c3cn->dst_cache = &rt->u.dst; ++ ++ /* try to establish an offloaded connection */ ++ dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0); ++ if (dev == NULL) { ++ c3cn_conn_debug("c3cn 0x%p, egress dev NULL.\n", c3cn); ++ return -ENETUNREACH; ++ } ++ cdata = NDEV2CDATA(dev); ++ cdev = cdata->cdev; ++ ++ sipv4 = cxgb3i_get_private_ipv4addr(dev); ++ if (!sipv4) { ++ c3cn_conn_debug("c3cn 0x%p, iscsi ip not configured.\n", c3cn); ++ sipv4 = c3cn->saddr.sin_addr.s_addr; ++ cxgb3i_set_private_ipv4addr(dev, sipv4); ++ } else ++ c3cn->saddr.sin_addr.s_addr = sipv4; ++ ++ c3cn_conn_debug("c3cn 0x%p, %u.%u.%u.%u,%u-%u.%u.%u.%u,%u SYN_SENT.\n", ++ c3cn, NIPQUAD(c3cn->saddr.sin_addr.s_addr), ++ ntohs(c3cn->saddr.sin_port), ++ NIPQUAD(c3cn->daddr.sin_addr.s_addr), ++ ntohs(c3cn->daddr.sin_port)); ++ ++ c3cn_set_state(c3cn, C3CN_STATE_SYN_SENT); ++ ++ if (!act_open(c3cn, dev)) ++ return 0; ++ ++ /* ++ * If we get here, we don't have an offload connection so simply ++ * return a failure. ++ */ ++ err = -ENOTSUPP; ++ ++ /* ++ * This trashes the connection and releases the local port, ++ * if necessary. ++ */ ++ c3cn_conn_debug("c3cn 0x%p -> CLOSE.\n", c3cn); ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSE); ++ ip_rt_put(rt); ++ c3cn_put_port(c3cn); ++ c3cn->daddr.sin_port = 0; ++ return err; ++} ++ ++/* ++ * Set of states for which we should return RX credits. ++ */ ++#define CREDIT_RETURN_STATE (C3CN_STATE_ESTABLISHED) ++ ++/* ++ * Called after some received data has been read. It returns RX credits ++ * to the HW for the amount of data processed. ++ */ ++void cxgb3i_c3cn_rx_credits(struct s3_conn *c3cn, int copied) ++{ ++ struct t3cdev *cdev; ++ int must_send; ++ u32 credits, dack = 0; ++ ++ if (!c3cn_in_state(c3cn, CREDIT_RETURN_STATE)) ++ return; ++ ++ credits = c3cn->copied_seq - c3cn->rcv_wup; ++ if (unlikely(!credits)) ++ return; ++ ++ cdev = c3cn->cdev; ++ ++ if (unlikely(cxgb3_rx_credit_thres == 0)) ++ return; ++ ++ dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1); ++ ++ /* ++ * For coalescing to work effectively ensure the receive window has ++ * at least 16KB left. ++ */ ++ must_send = credits + 16384 >= cxgb3_rcv_win; ++ ++ if (must_send || credits >= cxgb3_rx_credit_thres) ++ c3cn->rcv_wup += s3_send_rx_credits(c3cn, credits, dack, ++ must_send); ++} ++ ++/* ++ * Generic ARP failure handler that discards the buffer. ++ */ ++static void arp_failure_discard(struct t3cdev *cdev, struct sk_buff *skb) ++{ ++ kfree_skb(skb); ++} ++ ++/* ++ * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a ++ * connection's send queue and sends them on to T3. Must be called with the ++ * connection's lock held. Returns the amount of send buffer space that was ++ * freed as a result of sending queued data to T3. ++ */ ++static int s3_push_frames(struct s3_conn *c3cn, int req_completion) ++{ ++ int total_size = 0; ++ struct sk_buff *skb; ++ struct t3cdev *cdev; ++ struct cxgb3i_sdev_data *cdata; ++ ++ if (unlikely(c3cn_in_state(c3cn, ++ C3CN_STATE_SYN_SENT | C3CN_STATE_CLOSE))) ++ return 0; ++ ++ /* ++ * We shouldn't really be called at all after an abort but check just ++ * in case. ++ */ ++ if (unlikely(c3cn_flag(c3cn, C3CN_ABORT_SHUTDOWN))) ++ return 0; ++ ++ cdev = c3cn->cdev; ++ cdata = CXGB3_SDEV_DATA(cdev); ++ ++ while (c3cn->wr_avail ++ && (skb = skb_peek(&c3cn->write_queue)) != NULL ++ && !c3cn_flag(c3cn, C3CN_TX_WAIT_IDLE)) { ++ ++ int len = skb->len; /* length before skb_push */ ++ int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len); ++ int wrs_needed = skb_wrs[frags]; ++ ++ if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) ++ wrs_needed = 1; ++ ++ WARN_ON(frags >= ARRAY_SIZE(skb_wrs) || wrs_needed < 1); ++ ++ if (c3cn->wr_avail < wrs_needed) ++ break; ++ ++ __skb_unlink(skb, &c3cn->write_queue); ++ skb->priority = CPL_PRIORITY_DATA; ++ skb->csum = wrs_needed; /* remember this until the WR_ACK */ ++ c3cn->wr_avail -= wrs_needed; ++ c3cn->wr_unacked += wrs_needed; ++ enqueue_wr(c3cn, skb); ++ ++ if (likely(CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_NEED_HDR)) { ++ len += ulp_extra_len(skb); ++ make_tx_data_wr(c3cn, skb, len); ++ c3cn->snd_nxt += len; ++ if ((req_completion ++ && c3cn->wr_unacked == wrs_needed) ++ || (CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_COMPL) ++ || c3cn->wr_unacked >= c3cn->wr_max / 2) { ++ struct work_request_hdr *wr = cplhdr(skb); ++ ++ wr->wr_hi |= htonl(F_WR_COMPL); ++ c3cn->wr_unacked = 0; ++ } ++ CXGB3_SKB_CB(skb)->flags &= ~C3CB_FLAG_NEED_HDR; ++ } else if (skb->data[0] == FW_WROPCODE_OFLD_CLOSE_CON) ++ c3cn_set_flag(c3cn, C3CN_CLOSE_CON_REQUESTED); ++ ++ total_size += skb->truesize; ++ set_arp_failure_handler(skb, arp_failure_discard); ++ l2t_send(cdev, skb, c3cn->l2t); ++ } ++ return total_size; ++} ++ ++/* ++ * Handle an ARP failure for a CPL_ABORT_REQ. Change it into a no RST variant ++ * and send it along. ++ */ ++static void abort_arp_failure(struct t3cdev *cdev, struct sk_buff *skb) ++{ ++ struct cpl_abort_req *req = cplhdr(skb); ++ ++ c3cn_conn_debug("tdev 0x%p.\n", cdev); ++ ++ req->cmd = CPL_ABORT_NO_RST; ++ cxgb3_ofld_send(cdev, skb); ++} ++ ++/* ++ * Send an ABORT_REQ message. Cannot fail. This routine makes sure we do ++ * not send multiple ABORT_REQs for the same connection and also that we do ++ * not try to send a message after the connection has closed. Returns 1 if ++ * an ABORT_REQ wasn't generated after all, 0 otherwise. ++ */ ++static int s3_send_reset(struct s3_conn *c3cn, int mode, ++ struct sk_buff *skb) ++{ ++ struct cpl_abort_req *req; ++ unsigned int tid = c3cn->tid; ++ ++ if (unlikely(c3cn_flag(c3cn, C3CN_ABORT_SHUTDOWN) || !c3cn->cdev)) { ++ if (skb) ++ __kfree_skb(skb); ++ return 1; ++ } ++ ++ c3cn_conn_debug("c3cn 0x%p, mode %d, flag ABORT_RPL + ABORT_SHUT.\n", ++ c3cn, mode); ++ ++ c3cn_set_flag(c3cn, C3CN_ABORT_RPL_PENDING); ++ c3cn_set_flag(c3cn, C3CN_ABORT_SHUTDOWN); ++ ++ /* Purge the send queue so we don't send anything after an abort. */ ++ s3_purge_write_queue(c3cn); ++ ++ if (!skb) ++ skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); ++ skb->priority = CPL_PRIORITY_DATA; ++ set_arp_failure_handler(skb, abort_arp_failure); ++ ++ req = (struct cpl_abort_req *)skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); ++ req->wr.wr_lo = htonl(V_WR_TID(tid)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, tid)); ++ req->rsvd0 = htonl(c3cn->snd_nxt); ++ req->rsvd1 = !c3cn_flag(c3cn, C3CN_TX_DATA_SENT); ++ req->cmd = mode; ++ ++ l2t_send(c3cn->cdev, skb, c3cn->l2t); ++ return 0; ++} ++ ++/* ++ * Add a list of skbs to a connection send queue. This interface is intended ++ * for use by in-kernel ULPs. The skbs must comply with the max size limit of ++ * the device and have a headroom of at least TX_HEADER_LEN bytes. ++ */ ++int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb, int flags) ++{ ++ struct sk_buff *next; ++ int err, copied = 0; ++ ++ spin_lock_bh(&c3cn->lock); ++ ++ if (!c3cn_in_state(c3cn, C3CN_STATE_ESTABLISHED)) { ++ err = -EAGAIN; ++ goto out_err; ++ } ++ ++ err = -EPIPE; ++ if (c3cn->err || (c3cn->shutdown & C3CN_SEND_SHUTDOWN)) ++ goto out_err; ++ ++ while (skb) { ++ if (unlikely(skb_headroom(skb) < TX_HEADER_LEN)) { ++ c3cn_tx_debug("c3cn 0x%p, skb head.\n", c3cn); ++ err = -EINVAL; ++ goto out_err; ++ } ++ ++ next = skb->next; ++ skb->next = NULL; ++ skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND | C3CB_FLAG_NEED_HDR); ++ copied += skb->len; ++ c3cn->write_seq += skb->len + ulp_extra_len(skb); ++ skb = next; ++ } ++done: ++ if (likely(skb_queue_len(&c3cn->write_queue))) ++ s3_push_frames(c3cn, 1); ++ spin_unlock_bh(&c3cn->lock); ++ return copied; ++ ++out_err: ++ if (copied == 0 && err == -EPIPE) ++ copied = c3cn->err ? c3cn->err : -EPIPE; ++ goto done; ++} ++ ++/* ++ * Low-level utility routines for primary API functions. ++ * ===================================================== ++ */ ++/* routines to implement CPL message processing */ ++static void c3cn_act_establish(struct s3_conn *, struct sk_buff *); ++static void active_open_failed(struct s3_conn *, struct sk_buff *); ++static void wr_ack(struct s3_conn *, struct sk_buff *); ++static void do_peer_fin(struct s3_conn *, struct sk_buff *); ++static void process_abort_req(struct s3_conn *, struct sk_buff *); ++static void process_abort_rpl(struct s3_conn *, struct sk_buff *); ++static void process_close_con_rpl(struct s3_conn *, struct sk_buff *); ++static void process_rx_iscsi_hdr(struct s3_conn *, struct sk_buff *); ++ ++static struct sk_buff *__get_cpl_reply_skb(struct sk_buff *, size_t, gfp_t); ++ ++static void fail_act_open(struct s3_conn *, int); ++static void init_offload_conn(struct s3_conn *, struct t3cdev *, ++ struct dst_entry *); ++ ++/* ++ * Insert a connection into the TID table and take an extra reference. ++ */ ++static inline void c3cn_insert_tid(struct cxgb3i_sdev_data *cdata, ++ struct s3_conn *c3cn, ++ unsigned int tid) ++{ ++ c3cn_hold(c3cn); ++ cxgb3_insert_tid(cdata->cdev, cdata->client, c3cn, tid); ++} ++ ++static inline void free_atid(struct t3cdev *cdev, unsigned int tid) ++{ ++ struct s3_conn *c3cn = cxgb3_free_atid(cdev, tid); ++ if (c3cn) ++ c3cn_put(c3cn); ++} ++ ++/* ++ * This function is intended for allocations of small control messages. ++ * Such messages go as immediate data and usually the pakets are freed ++ * immediately. We maintain a cache of one small sk_buff and use it whenever ++ * it is available (has a user count of 1). Otherwise we get a fresh buffer. ++ */ ++#define CTRL_SKB_LEN 120 ++ ++static struct sk_buff *alloc_ctrl_skb(const struct s3_conn *c3cn, ++ int len) ++{ ++ struct sk_buff *skb = c3cn->ctrl_skb_cache; ++ ++ if (likely(skb && !skb_shared(skb) && !skb_cloned(skb))) { ++ __skb_trim(skb, 0); ++ atomic_set(&skb->users, 2); ++ } else if (likely(!in_atomic())) ++ skb = alloc_skb(len, GFP_ATOMIC | __GFP_NOFAIL); ++ else ++ skb = alloc_skb(len, GFP_ATOMIC); ++ return skb; ++} ++ ++/* ++ * Handle an ARP failure for an active open. ++ */ ++static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb) ++{ ++ struct s3_conn *c3cn = (struct s3_conn *)skb->sk; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x.\n", c3cn, c3cn->state); ++ ++ c3cn_hold(c3cn); ++ spin_lock(&c3cn->lock); ++ if (c3cn->state == C3CN_STATE_SYN_SENT) { ++ fail_act_open(c3cn, EHOSTUNREACH); ++ __kfree_skb(skb); ++ } ++ spin_unlock(&c3cn->lock); ++ c3cn_put(c3cn); ++} ++ ++/* ++ * Send an active open request. ++ */ ++static int act_open(struct s3_conn *c3cn, struct net_device *dev) ++{ ++ struct cxgb3i_sdev_data *cdata = NDEV2CDATA(dev); ++ struct t3cdev *cdev = cdata->cdev; ++ struct dst_entry *dst = c3cn->dst_cache; ++ struct sk_buff *skb; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ /* ++ * Initialize connection data. Note that the flags and ULP mode are ++ * initialized higher up ... ++ */ ++ c3cn->dev = dev; ++ c3cn->cdev = cdev; ++ c3cn->tid = cxgb3_alloc_atid(cdev, cdata->client, c3cn); ++ if (c3cn->tid < 0) ++ goto out_err; ++ ++ c3cn->qset = 0; ++ c3cn->l2t = t3_l2t_get(cdev, dst->neighbour, dev); ++ if (!c3cn->l2t) ++ goto free_tid; ++ ++ skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_KERNEL); ++ if (!skb) ++ goto free_l2t; ++ ++ skb->sk = (struct sock *)c3cn; ++ set_arp_failure_handler(skb, act_open_req_arp_failure); ++ ++ c3cn_hold(c3cn); ++ ++ init_offload_conn(c3cn, cdev, dst); ++ c3cn->err = 0; ++ c3cn_reset_flag(c3cn, C3CN_DONE); ++ ++ mk_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); ++ l2t_send(cdev, skb, c3cn->l2t); ++ return 0; ++ ++free_l2t: ++ l2t_release(L2DATA(cdev), c3cn->l2t); ++free_tid: ++ free_atid(cdev, c3cn->tid); ++ c3cn->tid = 0; ++out_err: ++ return -1; ++} ++ ++/* ++ * Close a connection by sending a CPL_CLOSE_CON_REQ message. Cannot fail ++ * under any circumstances. We take the easy way out and always queue the ++ * message to the write_queue. We can optimize the case where the queue is ++ * already empty though the optimization is probably not worth it. ++ */ ++static void mk_close_req(struct s3_conn *c3cn) ++{ ++ struct sk_buff *skb; ++ struct cpl_close_con_req *req; ++ unsigned int tid = c3cn->tid; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ skb = alloc_skb(sizeof(struct cpl_close_con_req), ++ GFP_KERNEL | __GFP_NOFAIL); ++ req = (struct cpl_close_con_req *)__skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); ++ req->wr.wr_lo = htonl(V_WR_TID(tid)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); ++ req->rsvd = htonl(c3cn->write_seq); ++ ++ skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND); ++ if (c3cn->state != C3CN_STATE_SYN_SENT) ++ s3_push_frames(c3cn, 1); ++} ++ ++static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb, ++ int flags) ++{ ++ CXGB3_SKB_CB(skb)->seq = c3cn->write_seq; ++ CXGB3_SKB_CB(skb)->flags = flags; ++ __skb_queue_tail(&c3cn->write_queue, skb); ++} ++ ++/* ++ * Send RX credits through an RX_DATA_ACK CPL message. If nofail is 0 we are ++ * permitted to return without sending the message in case we cannot allocate ++ * an sk_buff. Returns the number of credits sent. ++ */ ++static u32 s3_send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack, ++ int nofail) ++{ ++ struct sk_buff *skb; ++ struct cpl_rx_data_ack *req; ++ ++ skb = (nofail ? alloc_ctrl_skb(c3cn, sizeof(*req)) ++ : alloc_skb(sizeof(*req), GFP_ATOMIC)); ++ if (!skb) ++ return 0; ++ ++ req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid)); ++ req->credit_dack = htonl(dack | V_RX_CREDITS(credits)); ++ skb->priority = CPL_PRIORITY_ACK; ++ cxgb3_ofld_send(c3cn->cdev, skb); ++ return credits; ++} ++ ++static void mk_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb, ++ unsigned int atid, const struct l2t_entry *e) ++{ ++ struct cpl_act_open_req *req; ++ ++ c3cn_conn_debug("c3cn 0x%p, atid 0x%x.\n", c3cn, atid); ++ ++ skb->priority = CPL_PRIORITY_SETUP; ++ req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid)); ++ req->local_port = c3cn->saddr.sin_port; ++ req->peer_port = c3cn->daddr.sin_port; ++ req->local_ip = c3cn->saddr.sin_addr.s_addr; ++ req->peer_ip = c3cn->daddr.sin_addr.s_addr; ++ req->opt0h = htonl(calc_opt0h(c3cn) | V_L2T_IDX(e->idx) | ++ V_TX_CHANNEL(e->smt_idx)); ++ req->opt0l = htonl(calc_opt0l(c3cn)); ++ req->params = 0; ++} ++ ++/* ++ * Definitions and declarations for CPL handler functions. ++ * ======================================================= ++ */ ++ ++/* ++ * Similar to process_cpl_msg() but takes an extra connection reference around ++ * the call to the handler. Should be used if the handler may drop a ++ * connection reference. ++ */ ++static inline void process_cpl_msg_ref(void (*fn) (struct s3_conn *, ++ struct sk_buff *), ++ struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ c3cn_hold(c3cn); ++ process_cpl_msg(fn, c3cn, skb); ++ c3cn_put(c3cn); ++} ++ ++/* ++ * Return whether a failed active open has allocated a TID ++ */ ++static inline int act_open_has_tid(int status) ++{ ++ return status != CPL_ERR_TCAM_FULL && status != CPL_ERR_CONN_EXIST && ++ status != CPL_ERR_ARP_MISS; ++} ++ ++/* ++ * Returns true if a connection cannot accept new Rx data. ++ */ ++static inline int c3cn_no_receive(const struct s3_conn *c3cn) ++{ ++ return c3cn->shutdown & C3CN_RCV_SHUTDOWN; ++} ++ ++/* ++ * A helper function that aborts a connection and increments the given MIB ++ * counter. The supplied skb is used to generate the ABORT_REQ message if ++ * possible. Must be called with softirqs disabled. ++ */ ++static inline void abort_conn(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ struct sk_buff *abort_skb; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ abort_skb = __get_cpl_reply_skb(skb, sizeof(struct cpl_abort_req), ++ GFP_ATOMIC); ++ if (abort_skb) ++ s3_send_reset(c3cn, CPL_ABORT_SEND_RST, abort_skb); ++} ++ ++/* ++ * Returns whether an ABORT_REQ_RSS message is a negative advice. ++ */ ++static inline int is_neg_adv_abort(unsigned int status) ++{ ++ return status == CPL_ERR_RTX_NEG_ADVICE || ++ status == CPL_ERR_PERSIST_NEG_ADVICE; ++} ++ ++/* ++ * CPL handler functions. ++ * ====================== ++ */ ++ ++/* ++ * Process a CPL_ACT_ESTABLISH message. ++ */ ++static int do_act_establish(struct t3cdev *cdev, struct sk_buff *skb, ++ void *ctx) ++{ ++ struct cpl_act_establish *req = cplhdr(skb); ++ unsigned int tid = GET_TID(req); ++ unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); ++ struct s3_conn *c3cn = ctx; ++ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); ++ ++ c3cn_conn_debug("rcv, tid 0x%x, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ tid, c3cn, c3cn->state, c3cn->flags); ++ /* ++ * It's OK if the TID is currently in use, the owning connection may ++ * have backlogged its last CPL message(s). Just take it away. ++ */ ++ c3cn->tid = tid; ++ c3cn_insert_tid(cdata, c3cn, tid); ++ free_atid(cdev, atid); ++ ++ c3cn->qset = G_QNUM(ntohl(skb->csum)); ++ ++ process_cpl_msg(c3cn_act_establish, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Process an ACT_OPEN_RPL CPL message. ++ */ ++static int do_act_open_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ struct cpl_act_open_rpl *rpl = cplhdr(skb); ++ ++ c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ rpl->status, c3cn, c3cn->state, c3cn->flags); ++ ++ if (act_open_has_tid(rpl->status)) ++ cxgb3_queue_tid_release(cdev, GET_TID(rpl)); ++ ++ process_cpl_msg_ref(active_open_failed, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Handler RX_ISCSI_HDR CPL messages. ++ */ ++static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ process_cpl_msg(process_rx_iscsi_hdr, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Handler for TX_DATA_ACK CPL messages. ++ */ ++static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ ++ process_cpl_msg(wr_ack, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Handler for PEER_CLOSE CPL messages. ++ */ ++static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ ++ c3cn_conn_debug("rcv, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ process_cpl_msg_ref(do_peer_fin, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Handle an ABORT_REQ_RSS CPL message. ++ */ ++static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ const struct cpl_abort_req_rss *req = cplhdr(skb); ++ struct s3_conn *c3cn = ctx; ++ ++ c3cn_conn_debug("rcv, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ if (is_neg_adv_abort(req->status)) { ++ __kfree_skb(skb); ++ return 0; ++ } ++ ++ process_cpl_msg_ref(process_abort_req, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Handle an ABORT_RPL_RSS CPL message. ++ */ ++static int do_abort_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ struct cpl_abort_rpl_rss *rpl = cplhdr(skb); ++ struct s3_conn *c3cn = ctx; ++ ++ c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ rpl->status, c3cn, c3cn ? c3cn->state : 0, ++ c3cn ? c3cn->flags : 0UL); ++ ++ /* ++ * Ignore replies to post-close aborts indicating that the abort was ++ * requested too late. These connections are terminated when we get ++ * PEER_CLOSE or CLOSE_CON_RPL and by the time the abort_rpl_rss ++ * arrives the TID is either no longer used or it has been recycled. ++ */ ++ if (rpl->status == CPL_ERR_ABORT_FAILED) ++ goto discard; ++ ++ /* ++ * Sometimes we've already closed the connection, e.g., a post-close ++ * abort races with ABORT_REQ_RSS, the latter frees the connection ++ * expecting the ABORT_REQ will fail with CPL_ERR_ABORT_FAILED, ++ * but FW turns the ABORT_REQ into a regular one and so we get ++ * ABORT_RPL_RSS with status 0 and no connection. Only on T3A. ++ */ ++ if (!c3cn) ++ goto discard; ++ ++ process_cpl_msg_ref(process_abort_rpl, c3cn, skb); ++ return 0; ++ ++discard: ++ __kfree_skb(skb); ++ return 0; ++} ++ ++/* ++ * Handler for CLOSE_CON_RPL CPL messages. ++ */ ++static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb, ++ void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ ++ c3cn_conn_debug("rcv, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ process_cpl_msg_ref(process_close_con_rpl, c3cn, skb); ++ return 0; ++} ++ ++/* ++ * Definitions and declarations for CPL message processing. ++ * ======================================================== ++ */ ++ ++static void make_established(struct s3_conn *, u32, unsigned int); ++static void act_open_retry_timer(unsigned long); ++static void mk_act_open_req(struct s3_conn *, struct sk_buff *, ++ unsigned int, const struct l2t_entry *); ++static int act_open_rpl_status_to_errno(int); ++static void handle_excess_rx(struct s3_conn *, struct sk_buff *); ++static int abort_status_to_errno(struct s3_conn *, int, int *); ++static void send_abort_rpl(struct sk_buff *, struct t3cdev *, int); ++static struct sk_buff *get_cpl_reply_skb(struct sk_buff *, size_t, gfp_t); ++ ++/* ++ * Dequeue and return the first unacknowledged's WR on a connections's pending ++ * list. ++ */ ++static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn) ++{ ++ struct sk_buff *skb = c3cn->wr_pending_head; ++ ++ if (likely(skb)) { ++ /* Don't bother clearing the tail */ ++ c3cn->wr_pending_head = (struct sk_buff *)skb->sp; ++ skb->sp = NULL; ++ } ++ return skb; ++} ++ ++/* ++ * Return the first pending WR without removing it from the list. ++ */ ++static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn) ++{ ++ return c3cn->wr_pending_head; ++} ++ ++static inline void free_wr_skb(struct sk_buff *skb) ++{ ++ kfree_skb(skb); ++} ++ ++static void purge_wr_queue(struct s3_conn *c3cn) ++{ ++ struct sk_buff *skb; ++ while ((skb = dequeue_wr(c3cn)) != NULL) ++ free_wr_skb(skb); ++} ++ ++static inline void set_abort_rpl_wr(struct sk_buff *skb, unsigned int tid, ++ int cmd) ++{ ++ struct cpl_abort_rpl *rpl = cplhdr(skb); ++ ++ rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); ++ rpl->wr.wr_lo = htonl(V_WR_TID(tid)); ++ OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid)); ++ rpl->cmd = cmd; ++} ++ ++/* ++ * CPL message processing ... ++ * ========================== ++ */ ++ ++/* ++ * Updates connection state from an active establish CPL message. Runs with ++ * the connection lock held. ++ */ ++static void c3cn_act_establish(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ struct cpl_act_establish *req = cplhdr(skb); ++ u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */ ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ if (unlikely(c3cn->state != C3CN_STATE_SYN_SENT)) ++ printk(KERN_ERR "TID %u expected SYN_SENT, found %d\n", ++ c3cn->tid, c3cn->state); ++ ++ c3cn->copied_seq = c3cn->rcv_wup = c3cn->rcv_nxt = rcv_isn; ++ make_established(c3cn, ntohl(req->snd_isn), ntohs(req->tcp_opt)); ++ ++ if (unlikely(c3cn_flag(c3cn, C3CN_CLOSE_NEEDED))) { ++ /* upper layer has requested closing */ ++ abort_conn(c3cn, skb); ++ return; ++ } ++ ++ __kfree_skb(skb); ++ if (s3_push_frames(c3cn, 1)) ++ cxgb3i_conn_tx_open(c3cn); ++} ++ ++/* ++ * Handle active open failures. ++ */ ++static void active_open_failed(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ struct cpl_act_open_rpl *rpl = cplhdr(skb); ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ if (rpl->status == CPL_ERR_CONN_EXIST && ++ c3cn->retry_timer.function != act_open_retry_timer) { ++ c3cn->retry_timer.function = act_open_retry_timer; ++ c3cn_reset_timer(c3cn, &c3cn->retry_timer, ++ jiffies + HZ / 2); ++ } else ++ fail_act_open(c3cn, act_open_rpl_status_to_errno(rpl->status)); ++ __kfree_skb(skb); ++} ++ ++/* ++ * Process received pdu for a connection. ++ */ ++static void process_rx_iscsi_hdr(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ struct cpl_iscsi_hdr *hdr_cpl = cplhdr(skb); ++ struct cpl_iscsi_hdr_norss data_cpl; ++ struct cpl_rx_data_ddp_norss ddp_cpl; ++ unsigned int hdr_len, data_len, status; ++ unsigned int len; ++ int err; ++ ++ if (unlikely(c3cn_no_receive(c3cn))) { ++ handle_excess_rx(c3cn, skb); ++ return; ++ } ++ ++ CXGB3_SKB_CB(skb)->seq = ntohl(hdr_cpl->seq); ++ CXGB3_SKB_CB(skb)->flags = 0; ++ ++ skb_reset_transport_header(skb); ++ __skb_pull(skb, sizeof(struct cpl_iscsi_hdr)); ++ ++ len = hdr_len = ntohs(hdr_cpl->len); ++ /* msg coalesce is off or not enough data received */ ++ if (skb->len <= hdr_len) { ++ printk(KERN_ERR "%s: TID %u, ISCSI_HDR, skb len %u < %u.\n", ++ c3cn->cdev->name, c3cn->tid, skb->len, hdr_len); ++ goto abort_conn; ++ } ++ ++ err = skb_copy_bits(skb, skb->len - sizeof(ddp_cpl), &ddp_cpl, ++ sizeof(ddp_cpl)); ++ if (err < 0) ++ goto abort_conn; ++ ++ skb_ulp_mode(skb) = ULP2_FLAG_DATA_READY; ++ skb_ulp_pdulen(skb) = ntohs(ddp_cpl.len); ++ skb_ulp_ddigest(skb) = ntohl(ddp_cpl.ulp_crc); ++ status = ntohl(ddp_cpl.ddp_status); ++ ++ if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT)) ++ skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR; ++ if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT)) ++ skb_ulp_mode(skb) |= ULP2_FLAG_DCRC_ERROR; ++ if (status & (1 << RX_DDP_STATUS_PAD_SHIFT)) ++ skb_ulp_mode(skb) |= ULP2_FLAG_PAD_ERROR; ++ ++ if (skb->len > (hdr_len + sizeof(ddp_cpl))) { ++ err = skb_copy_bits(skb, hdr_len, &data_cpl, sizeof(data_cpl)); ++ if (err < 0) ++ goto abort_conn; ++ data_len = ntohs(data_cpl.len); ++ len += sizeof(data_cpl) + data_len; ++ } else if (status & (1 << RX_DDP_STATUS_DDP_SHIFT)) ++ skb_ulp_mode(skb) |= ULP2_FLAG_DATA_DDPED; ++ ++ c3cn->rcv_nxt = ntohl(ddp_cpl.seq) + skb_ulp_pdulen(skb); ++ __pskb_trim(skb, len); ++ __skb_queue_tail(&c3cn->receive_queue, skb); ++ cxgb3i_conn_pdu_ready(c3cn); ++ ++ return; ++ ++abort_conn: ++ s3_send_reset(c3cn, CPL_ABORT_SEND_RST, NULL); ++ __kfree_skb(skb); ++} ++ ++/* ++ * Process an acknowledgment of WR completion. Advance snd_una and send the ++ * next batch of work requests from the write queue. ++ */ ++static void wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) ++{ ++ struct cpl_wr_ack *hdr = cplhdr(skb); ++ unsigned int credits = ntohs(hdr->credits); ++ u32 snd_una = ntohl(hdr->snd_una); ++ ++ c3cn->wr_avail += credits; ++ if (c3cn->wr_unacked > c3cn->wr_max - c3cn->wr_avail) ++ c3cn->wr_unacked = c3cn->wr_max - c3cn->wr_avail; ++ ++ while (credits) { ++ struct sk_buff *p = peek_wr(c3cn); ++ ++ if (unlikely(!p)) { ++ printk(KERN_ERR "%u WR_ACK credits for TID %u with " ++ "nothing pending, state %u\n", ++ credits, c3cn->tid, c3cn->state); ++ break; ++ } ++ if (unlikely(credits < p->csum)) { ++ p->csum -= credits; ++ break; ++ } else { ++ dequeue_wr(c3cn); ++ credits -= p->csum; ++ free_wr_skb(p); ++ } ++ } ++ ++ if (unlikely(before(snd_una, c3cn->snd_una))) ++ goto out_free; ++ ++ if (c3cn->snd_una != snd_una) { ++ c3cn->snd_una = snd_una; ++ dst_confirm(c3cn->dst_cache); ++ if (c3cn->snd_una == c3cn->snd_nxt) ++ c3cn_reset_flag(c3cn, C3CN_TX_WAIT_IDLE); ++ } ++ ++ if (skb_queue_len(&c3cn->write_queue) && s3_push_frames(c3cn, 0)) ++ cxgb3i_conn_tx_open(c3cn); ++out_free: ++ __kfree_skb(skb); ++} ++ ++/* ++ * Handle a peer FIN. ++ */ ++static void do_peer_fin(struct s3_conn *c3cn, struct sk_buff *skb) ++{ ++ int keep = 0; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) ++ goto out; ++ ++ c3cn->shutdown |= C3CN_RCV_SHUTDOWN; ++ c3cn_set_flag(c3cn, C3CN_DONE); ++ ++ switch (c3cn->state) { ++ case C3CN_STATE_ESTABLISHED: ++ break; ++ case C3CN_STATE_CLOSING: ++ c3cn_done(c3cn); ++ break; ++ default: ++ printk(KERN_ERR ++ "%s: TID %u received PEER_CLOSE in bad state %d\n", ++ c3cn->cdev->name, c3cn->tid, c3cn->state); ++ } ++ ++ cxgb3i_conn_closing(c3cn); ++out: ++ if (!keep) ++ __kfree_skb(skb); ++} ++ ++/* ++ * Process abort requests. If we are waiting for an ABORT_RPL we ignore this ++ * request except that we need to reply to it. ++ */ ++static void process_abort_req(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ int rst_status = CPL_ABORT_NO_RST; ++ const struct cpl_abort_req_rss *req = cplhdr(skb); ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ if (!c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) { ++ c3cn_set_flag(c3cn, C3CN_ABORT_REQ_RCVD); ++ c3cn_set_flag(c3cn, C3CN_ABORT_SHUTDOWN); ++ __kfree_skb(skb); ++ return; ++ } ++ c3cn_reset_flag(c3cn, C3CN_ABORT_REQ_RCVD); ++ ++ /* ++ * Three cases to consider: ++ * a) We haven't sent an abort_req; close the connection. ++ * b) We have sent a post-close abort_req that will get to TP too late ++ * and will generate a CPL_ERR_ABORT_FAILED reply. The reply will ++ * be ignored and the connection should be closed now. ++ * c) We have sent a regular abort_req that will get to TP too late. ++ * That will generate an abort_rpl with status 0, wait for it. ++ */ ++ send_abort_rpl(skb, c3cn->cdev, rst_status); ++ ++ if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { ++ c3cn->err = ++ abort_status_to_errno(c3cn, req->status, &rst_status); ++ ++ c3cn_done(c3cn); ++ } ++} ++ ++/* ++ * Process abort replies. We only process these messages if we anticipate ++ * them as the coordination between SW and HW in this area is somewhat lacking ++ * and sometimes we get ABORT_RPLs after we are done with the connection that ++ * originated the ABORT_REQ. ++ */ ++static void process_abort_rpl(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { ++ if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_RCVD)) ++ c3cn_set_flag(c3cn, C3CN_ABORT_RPL_RCVD); ++ else { ++ c3cn_reset_flag(c3cn, C3CN_ABORT_RPL_RCVD); ++ c3cn_reset_flag(c3cn, C3CN_ABORT_RPL_PENDING); ++ BUG_ON(c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)); ++ c3cn_done(c3cn); ++ } ++ } ++ __kfree_skb(skb); ++} ++ ++/* ++ * Process a peer ACK to our FIN. ++ */ ++static void process_close_con_rpl(struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ struct cpl_close_con_rpl *rpl = cplhdr(skb); ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ c3cn->snd_una = ntohl(rpl->snd_nxt) - 1; /* exclude FIN */ ++ ++ if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) ++ goto out; ++ ++ if (c3cn->state == C3CN_STATE_CLOSING) { ++ c3cn_done(c3cn); ++ } else ++ printk(KERN_ERR ++ "%s: TID %u received CLOSE_CON_RPL in bad state %d\n", ++ c3cn->cdev->name, c3cn->tid, c3cn->state); ++out: ++ kfree_skb(skb); ++} ++ ++/* ++ * Random utility functions for CPL message processing ... ++ * ======================================================= ++ */ ++ ++/** ++ * find_best_mtu - find the entry in the MTU table closest to an MTU ++ * @d: TOM state ++ * @mtu: the target MTU ++ * ++ * Returns the index of the value in the MTU table that is closest to but ++ * does not exceed the target MTU. ++ */ ++static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu) ++{ ++ int i = 0; ++ ++ while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu) ++ ++i; ++ return i; ++} ++ ++static unsigned int select_mss(struct s3_conn *c3cn, unsigned int pmtu) ++{ ++ unsigned int idx; ++ struct dst_entry *dst = c3cn->dst_cache; ++ struct t3cdev *cdev = c3cn->cdev; ++ const struct t3c_data *td = T3C_DATA(cdev); ++ u16 advmss = dst_metric(dst, RTAX_ADVMSS); ++ ++ if (advmss > pmtu - 40) ++ advmss = pmtu - 40; ++ if (advmss < td->mtus[0] - 40) ++ advmss = td->mtus[0] - 40; ++ idx = find_best_mtu(td, advmss + 40); ++ return idx; ++} ++ ++static void fail_act_open(struct s3_conn *c3cn, int errno) ++{ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ c3cn->err = errno; ++ c3cn_done(c3cn); ++} ++ ++/* ++ * Assign offload parameters to some connection fields. ++ */ ++static void init_offload_conn(struct s3_conn *c3cn, ++ struct t3cdev *cdev, ++ struct dst_entry *dst) ++{ ++ BUG_ON(c3cn->cdev != cdev); ++ c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs; ++ c3cn->wr_unacked = 0; ++ c3cn->mss_idx = select_mss(c3cn, dst_mtu(dst)); ++ ++ c3cn->ctrl_skb_cache = alloc_skb(CTRL_SKB_LEN, gfp_any()); ++ reset_wr_list(c3cn); ++} ++ ++static void act_open_retry_timer(unsigned long data) ++{ ++ struct sk_buff *skb; ++ struct s3_conn *c3cn = (struct s3_conn *)data; ++ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x.\n", c3cn, c3cn->state); ++ ++ spin_lock(&c3cn->lock); ++ skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_ATOMIC); ++ if (!skb) ++ fail_act_open(c3cn, ENOMEM); ++ else { ++ skb->sk = (struct sock *)c3cn; ++ set_arp_failure_handler(skb, act_open_req_arp_failure); ++ mk_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); ++ l2t_send(c3cn->cdev, skb, c3cn->l2t); ++ } ++ spin_unlock(&c3cn->lock); ++ c3cn_put(c3cn); ++} ++ ++/* ++ * Convert an ACT_OPEN_RPL status to a Linux errno. ++ */ ++static int act_open_rpl_status_to_errno(int status) ++{ ++ switch (status) { ++ case CPL_ERR_CONN_RESET: ++ return ECONNREFUSED; ++ case CPL_ERR_ARP_MISS: ++ return EHOSTUNREACH; ++ case CPL_ERR_CONN_TIMEDOUT: ++ return ETIMEDOUT; ++ case CPL_ERR_TCAM_FULL: ++ return ENOMEM; ++ case CPL_ERR_CONN_EXIST: ++ printk(KERN_ERR "ACTIVE_OPEN_RPL: 4-tuple in use\n"); ++ return EADDRINUSE; ++ default: ++ return EIO; ++ } ++} ++ ++/* ++ * Convert the status code of an ABORT_REQ into a Linux error code. Also ++ * indicate whether RST should be sent in response. ++ */ ++static int abort_status_to_errno(struct s3_conn *c3cn, ++ int abort_reason, int *need_rst) ++{ ++ switch (abort_reason) { ++ case CPL_ERR_BAD_SYN: /* fall through */ ++ case CPL_ERR_CONN_RESET: ++ return c3cn->state == C3CN_STATE_CLOSING ? EPIPE : ECONNRESET; ++ case CPL_ERR_XMIT_TIMEDOUT: ++ case CPL_ERR_PERSIST_TIMEDOUT: ++ case CPL_ERR_FINWAIT2_TIMEDOUT: ++ case CPL_ERR_KEEPALIVE_TIMEDOUT: ++ return ETIMEDOUT; ++ default: ++ return EIO; ++ } ++} ++ ++static void send_abort_rpl(struct sk_buff *skb, struct t3cdev *cdev, ++ int rst_status) ++{ ++ struct sk_buff *reply_skb; ++ struct cpl_abort_req_rss *req = cplhdr(skb); ++ ++ reply_skb = get_cpl_reply_skb(skb, sizeof(struct cpl_abort_rpl), ++ gfp_any()); ++ ++ reply_skb->priority = CPL_PRIORITY_DATA; ++ set_abort_rpl_wr(reply_skb, GET_TID(req), rst_status); ++ kfree_skb(skb); ++ cxgb3_ofld_send(cdev, reply_skb); ++} ++ ++/* ++ * Returns an sk_buff for a reply CPL message of size len. If the input ++ * sk_buff has no other users it is trimmed and reused, otherwise a new buffer ++ * is allocated. The input skb must be of size at least len. Note that this ++ * operation does not destroy the original skb data even if it decides to reuse ++ * the buffer. ++ */ ++static struct sk_buff *get_cpl_reply_skb(struct sk_buff *skb, size_t len, ++ gfp_t gfp) ++{ ++ if (likely(!skb_cloned(skb))) { ++ BUG_ON(skb->len < len); ++ __skb_trim(skb, len); ++ skb_get(skb); ++ } else { ++ skb = alloc_skb(len, gfp); ++ if (skb) ++ __skb_put(skb, len); ++ } ++ return skb; ++} ++ ++/* ++ * Release resources held by an offload connection (TID, L2T entry, etc.) ++ */ ++static void t3_release_offload_resources(struct s3_conn *c3cn) ++{ ++ struct t3cdev *cdev = c3cn->cdev; ++ unsigned int tid = c3cn->tid; ++ ++ if (!cdev) ++ return; ++ ++ c3cn->qset = 0; ++ ++ kfree_skb(c3cn->ctrl_skb_cache); ++ c3cn->ctrl_skb_cache = NULL; ++ ++ if (c3cn->wr_avail != c3cn->wr_max) { ++ purge_wr_queue(c3cn); ++ reset_wr_list(c3cn); ++ } ++ ++ if (c3cn->l2t) { ++ l2t_release(L2DATA(cdev), c3cn->l2t); ++ c3cn->l2t = NULL; ++ } ++ ++ if (c3cn->state == C3CN_STATE_SYN_SENT) /* we have ATID */ ++ free_atid(cdev, tid); ++ else { /* we have TID */ ++ cxgb3_remove_tid(cdev, (void *)c3cn, tid); ++ c3cn_put(c3cn); ++ } ++ ++ c3cn->cdev = NULL; ++} ++ ++/* ++ * Handles Rx data that arrives in a state where the connection isn't ++ * accepting new data. ++ */ ++static void handle_excess_rx(struct s3_conn *c3cn, struct sk_buff *skb) ++{ ++ if (!c3cn_flag(c3cn, C3CN_ABORT_SHUTDOWN)) ++ abort_conn(c3cn, skb); ++ ++ kfree_skb(skb); ++} ++ ++/* ++ * Like get_cpl_reply_skb() but the returned buffer starts out empty. ++ */ ++static struct sk_buff *__get_cpl_reply_skb(struct sk_buff *skb, size_t len, ++ gfp_t gfp) ++{ ++ if (likely(!skb_cloned(skb) && !skb->data_len)) { ++ __skb_trim(skb, 0); ++ skb_get(skb); ++ } else ++ skb = alloc_skb(len, gfp); ++ return skb; ++} ++ ++/* ++ * Completes some final bits of initialization for just established connections ++ * and changes their state to C3CN_STATE_ESTABLISHED. ++ * ++ * snd_isn here is the ISN after the SYN, i.e., the true ISN + 1. ++ */ ++static void make_established(struct s3_conn *c3cn, u32 snd_isn, ++ unsigned int opt) ++{ ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x.\n", c3cn, c3cn->state); ++ ++ c3cn->write_seq = c3cn->snd_nxt = c3cn->snd_una = snd_isn; ++ ++ /* ++ * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't ++ * pass through opt0. ++ */ ++ if (cxgb3_rcv_win > (M_RCV_BUFSIZ << 10)) ++ c3cn->rcv_wup -= cxgb3_rcv_win - (M_RCV_BUFSIZ << 10); ++ ++ dst_confirm(c3cn->dst_cache); ++ ++ smp_mb(); ++ c3cn_set_state(c3cn, C3CN_STATE_ESTABLISHED); ++} +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. ++ * ++ * Written by Dimitris Michailidis (dm@chelsio.com) ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this ++ * release for licensing terms and conditions. ++ */ ++ ++#ifndef _CXGB3I_OFFLOAD_H ++#define _CXGB3I_OFFLOAD_H ++ ++#include ++#include ++ ++#include "common.h" ++#include "adapter.h" ++#include "t3cdev.h" ++#include "cxgb3_offload.h" ++ ++#define cxgb3i_log_error(fmt...) printk(KERN_ERR "cxgb3i: ERR! " fmt) ++#define cxgb3i_log_warn(fmt...) printk(KERN_WARNING "cxgb3i: WARN! " fmt) ++#define cxgb3i_log_info(fmt...) printk(KERN_INFO "cxgb3i: " fmt) ++ ++#ifdef __DEBUG_CXGB3I__ ++#define cxgb3i_log_debug(fmt, args...) \ ++ printk(KERN_INFO "cxgb3i: %s - " fmt, __func__ , ## args) ++#else ++#define cxgb3i_log_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_C3CN_CONN__ ++#define c3cn_conn_debug cxgb3i_log_debug ++#else ++#define c3cn_conn_debug(fmt...) ++#endif ++ ++/* ++ * Data structure to keep track of cxgb3 connection. ++ */ ++struct s3_conn { ++ struct net_device *dev; /* net device of with connection */ ++ struct t3cdev *cdev; /* adapter t3cdev for net device */ ++ unsigned long flags; /* see c3cn_flags below */ ++ int tid; /* ID of TCP Control Block */ ++ int qset; /* queue Set used by connection */ ++ int mss_idx; /* Maximum Segment Size table index */ ++ struct l2t_entry *l2t; /* ARP resolution for offload packets */ ++ int wr_max; /* maximum in-flight writes */ ++ int wr_avail; /* number of writes available */ ++ int wr_unacked; /* writes since last request for */ ++ /* completion notification */ ++ struct sk_buff *wr_pending_head;/* head of pending write queue */ ++ struct sk_buff *wr_pending_tail;/* tail of pending write queue */ ++ struct sk_buff *ctrl_skb_cache; /* single entry cached skb for */ ++ /* short-term control operations */ ++ spinlock_t lock; /* connection status lock */ ++ atomic_t refcnt; /* reference count on connection */ ++ volatile unsigned int state; /* connection state */ ++ struct sockaddr_in saddr; /* source IP/port address */ ++ struct sockaddr_in daddr; /* destination IP/port address */ ++ struct dst_entry *dst_cache; /* reference to destination route */ ++ unsigned char shutdown; /* shutdown status */ ++ struct sk_buff_head receive_queue;/* received PDUs */ ++ struct sk_buff_head write_queue;/* un-pushed pending writes */ ++ ++ struct timer_list retry_timer; /* retry timer for various operations */ ++ int err; /* connection error status */ ++ rwlock_t callback_lock; /* lock for opaque user context */ ++ void *user_data; /* opaque user context */ ++ ++ u32 rcv_nxt; /* what we want to receive next */ ++ u32 copied_seq; /* head of yet unread data */ ++ u32 rcv_wup; /* rcv_nxt on last window update sent */ ++ u32 snd_nxt; /* next sequence we send */ ++ u32 snd_una; /* first byte we want an ack for */ ++ ++ u32 write_seq; /* tail+1 of data held in send buffer */ ++}; ++ ++/* Flags in c3cn->shutdown */ ++#define C3CN_RCV_SHUTDOWN 0x1 ++#define C3CN_SEND_SHUTDOWN 0x2 ++#define C3CN_SHUTDOWN_MASK (C3CN_RCV_SHUTDOWN | C3CN_SEND_SHUTDOWN) ++ ++/* ++ * connection state bitmap ++ */ ++#define C3CN_STATE_CLOSE 0x1 ++#define C3CN_STATE_SYN_SENT 0x2 ++#define C3CN_STATE_ESTABLISHED 0x4 ++#define C3CN_STATE_CLOSING 0x8 ++#define C3CN_STATE_ABORING 0x10 ++ ++#define C3CN_STATE_MASK 0xFF ++ ++static inline unsigned int c3cn_in_state(const struct s3_conn *c3cn, ++ unsigned int states) ++{ ++ return states & c3cn->state; ++} ++ ++/* ++ * Connection flags -- many to track some close related events. ++ */ ++enum c3cn_flags { ++ C3CN_ABORT_RPL_RCVD, /* received one ABORT_RPL_RSS message */ ++ C3CN_ABORT_REQ_RCVD, /* received one ABORT_REQ_RSS message */ ++ C3CN_TX_WAIT_IDLE, /* suspend Tx until in-flight data is ACKed */ ++ C3CN_ABORT_SHUTDOWN, /* shouldn't send more abort requests */ ++ ++ C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */ ++ C3CN_CLOSE_CON_REQUESTED, /* we've sent a close_conn_req */ ++ C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */ ++ C3CN_CLOSE_NEEDED, /* need to be closed */ ++ C3CN_DONE, ++}; ++ ++/* ++ * Per adapter data. Linked off of each Ethernet device port on the adapter. ++ * Also available via the t3cdev structure since we have pointers to our port ++ * net_device's there ... ++ */ ++struct cxgb3i_sdev_data { ++ struct list_head list; /* links for list of all adapters */ ++ struct t3cdev *cdev; /* adapter t3cdev */ ++ struct cxgb3_client *client; /* CPL client pointer */ ++ struct adap_ports *ports; /* array of adapter ports */ ++ unsigned int rx_page_size; /* RX page size */ ++ struct sk_buff_head deferq; /* queue for processing replies from */ ++ /* worker thread context */ ++ struct work_struct deferq_task; /* worker thread */ ++}; ++#define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr) ++#define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev) ++ ++/* ++ * Primary API routines. ++ */ ++void cxgb3i_sdev_cleanup(void); ++int cxgb3i_sdev_init(cxgb3_cpl_handler_func *); ++void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *); ++void cxgb3i_sdev_remove(struct t3cdev *); ++ ++struct s3_conn *cxgb3i_c3cn_create(void); ++int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *); ++void cxgb3i_c3cn_rx_credits(struct s3_conn *, int); ++int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *, int); ++void cxgb3i_c3cn_release(struct s3_conn *); ++ ++/* ++ * Definitions for sk_buff state and ULP mode management. ++ */ ++ ++struct cxgb3_skb_cb { ++ __u8 flags; /* see C3CB_FLAG_* below */ ++ __u8 ulp_mode; /* ULP mode/submode of sk_buff */ ++ __u32 seq; /* sequence number */ ++ __u32 ddigest; /* ULP rx_data_ddp selected field */ ++ __u32 pdulen; /* ULP rx_data_ddp selected field */ ++ __u8 ulp_data[16]; /* scratch area for ULP */ ++}; ++ ++#define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0])) ++ ++#define skb_ulp_mode(skb) (CXGB3_SKB_CB(skb)->ulp_mode) ++#define skb_ulp_ddigest(skb) (CXGB3_SKB_CB(skb)->ddigest) ++#define skb_ulp_pdulen(skb) (CXGB3_SKB_CB(skb)->pdulen) ++#define skb_ulp_data(skb) (CXGB3_SKB_CB(skb)->ulp_data) ++ ++enum { ++ C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */ ++ C3CB_FLAG_NO_APPEND = 1 << 1, /* don't grow this skb */ ++ C3CB_FLAG_BARRIER = 1 << 2, /* set TX_WAIT_IDLE after sending */ ++ C3CB_FLAG_COMPL = 1 << 4, /* request WR completion */ ++}; ++ ++/* ++ * Top-level CPL message processing used by most CPL messages that ++ * pertain to connections. ++ */ ++static inline void process_cpl_msg(void (*fn)(struct s3_conn *, ++ struct sk_buff *), ++ struct s3_conn *c3cn, ++ struct sk_buff *skb) ++{ ++ spin_lock(&c3cn->lock); ++ fn(c3cn, skb); ++ spin_unlock(&c3cn->lock); ++} ++ ++/* ++ * Opaque version of structure the SGE stores at skb->head of TX_DATA packets ++ * and for which we must reserve space. ++ */ ++struct sge_opaque_hdr { ++ void *dev; ++ dma_addr_t addr[MAX_SKB_FRAGS + 1]; ++}; ++ ++/* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ ++#define TX_HEADER_LEN \ ++ (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) ++ ++void *cxgb3i_alloc_big_mem(unsigned int); ++void cxgb3i_free_big_mem(void *); ++ ++/* ++ * get and set private ip for iscsi traffic ++ */ ++#define cxgb3i_get_private_ipv4addr(ndev) \ ++ (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) ++#define cxgb3i_set_private_ipv4addr(ndev, addr) \ ++ (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) = addr ++ ++/* max. connections per adapter */ ++#define CXGB3I_MAX_CONN 16384 ++#endif /* _CXGB3_OFFLOAD_H */ +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i_ulp2.c +@@ -0,0 +1,741 @@ ++/* ++ * cxgb3i_ulp2.c: Chelsio S3xx iSCSI driver. ++ * ++ * Copyright (c) 2008 Chelsio Communications, Inc. ++ * ++ * 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. ++ * ++ * Written by: Karen Xie (kxie@chelsio.com) ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "cxgb3i.h" ++#include "cxgb3i_ulp2.h" ++ ++#ifdef __DEBUG_CXGB3I_RX__ ++#define cxgb3i_rx_debug cxgb3i_log_debug ++#else ++#define cxgb3i_rx_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_CXGB3I_TX__ ++#define cxgb3i_tx_debug cxgb3i_log_debug ++#else ++#define cxgb3i_tx_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_CXGB3I_TAG__ ++#define cxgb3i_tag_debug cxgb3i_log_debug ++#else ++#define cxgb3i_tag_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_CXGB3I_DDP__ ++#define cxgb3i_ddp_debug cxgb3i_log_debug ++#else ++#define cxgb3i_ddp_debug(fmt...) ++#endif ++ ++static struct page *pad_page; ++ ++#define ULP2_PGIDX_MAX 4 ++#define ULP2_4K_PAGE_SHIFT 12 ++#define ULP2_4K_PAGE_MASK (~((1UL << ULP2_4K_PAGE_SHIFT) - 1)) ++static unsigned char ddp_page_order[ULP2_PGIDX_MAX]; ++static unsigned long ddp_page_size[ULP2_PGIDX_MAX]; ++static unsigned char ddp_page_shift[ULP2_PGIDX_MAX]; ++static unsigned char sw_tag_idx_bits; ++static unsigned char sw_tag_age_bits; ++ ++static void cxgb3i_ddp_page_init(void) ++{ ++ int i; ++ unsigned long n = PAGE_SIZE >> ULP2_4K_PAGE_SHIFT; ++ ++ if (PAGE_SIZE & (~ULP2_4K_PAGE_MASK)) { ++ cxgb3i_log_debug("PAGE_SIZE 0x%lx is not multiple of 4K, " ++ "ddp disabled.\n", PAGE_SIZE); ++ return; ++ } ++ n = __ilog2_u32(n); ++ for (i = 0; i < ULP2_PGIDX_MAX; i++, n++) { ++ ddp_page_order[i] = n; ++ ddp_page_shift[i] = ULP2_4K_PAGE_SHIFT + n; ++ ddp_page_size[i] = 1 << ddp_page_shift[i]; ++ cxgb3i_log_debug("%d, order %u, shift %u, size 0x%lx.\n", i, ++ ddp_page_order[i], ddp_page_shift[i], ++ ddp_page_size[i]); ++ } ++ ++ sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1; ++ sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1; ++} ++ ++static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr) ++{ ++ struct ulp_mem_io *req = (struct ulp_mem_io *)skb->head; ++ ++ req->wr.wr_lo = 0; ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS)); ++ req->cmd_lock_addr = htonl(V_ULP_MEMIO_ADDR(addr >> 5) | ++ V_ULPTX_CMD(ULP_MEM_WRITE)); ++ req->len = htonl(V_ULP_MEMIO_DATA_LEN(PPOD_SIZE >> 5) | ++ V_ULPTX_NFLITS((PPOD_SIZE >> 3) + 1)); ++} ++ ++static int set_ddp_map(struct cxgb3i_adapter *snic, struct pagepod_hdr *hdr, ++ unsigned int idx, unsigned int npods, ++ struct scatterlist *sgl, unsigned int sgcnt) ++{ ++ struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ struct scatterlist *sg = sgl; ++ unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; ++ int i; ++ ++ for (i = 0; i < npods; i++, pm_addr += PPOD_SIZE) { ++ struct sk_buff *skb; ++ struct pagepod *ppod; ++ int j, k; ++ skb = ++ alloc_skb(sizeof(struct ulp_mem_io) + PPOD_SIZE, ++ GFP_ATOMIC); ++ if (!skb) { ++ cxgb3i_log_debug("skb OMM.\n"); ++ return -ENOMEM; ++ } ++ skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE); ++ ++ ulp_mem_io_set_hdr(skb, pm_addr); ++ ppod = ++ (struct pagepod *)(skb->head + sizeof(struct ulp_mem_io)); ++ memcpy(&(ppod->hdr), hdr, sizeof(struct pagepod)); ++ for (j = 0, k = i * 4; j < 5; j++, k++) { ++ if (k < sgcnt) { ++ ppod->addr[j] = cpu_to_be64(sg_dma_address(sg)); ++ if (j < 4) ++ sg = sg_next(sg); ++ } else ++ ppod->addr[j] = 0UL; ++ } ++ ++ skb->priority = CPL_PRIORITY_CONTROL; ++ cxgb3_ofld_send(snic->tdev, skb); ++ } ++ return 0; ++} ++ ++static int clear_ddp_map(struct cxgb3i_adapter *snic, unsigned int idx, ++ unsigned int npods) ++{ ++ struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; ++ int i; ++ ++ for (i = 0; i < npods; i++, pm_addr += PPOD_SIZE) { ++ struct sk_buff *skb; ++ skb = ++ alloc_skb(sizeof(struct ulp_mem_io) + PPOD_SIZE, ++ GFP_ATOMIC); ++ if (!skb) ++ return -ENOMEM; ++ skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE); ++ memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE); ++ ulp_mem_io_set_hdr(skb, pm_addr); ++ skb->priority = CPL_PRIORITY_CONTROL; ++ cxgb3_ofld_send(snic->tdev, skb); ++ } ++ return 0; ++} ++ ++static int cxgb3i_ddp_sgl_check(struct scatterlist *sgl, unsigned int sgcnt) ++{ ++ struct scatterlist *sg; ++ int i; ++ ++ /* make sure the sgl is fit for ddp: ++ * each has the same page size, and ++ * first & last page do not need to be used completely, and ++ * the rest of page must be used completely ++ */ ++ for_each_sg(sgl, sg, sgcnt, i) { ++ if ((i && sg->offset) || ++ ((i != sgcnt - 1) && ++ (sg->length + sg->offset) != PAGE_SIZE)) { ++ cxgb3i_tag_debug("sg %u/%u, off %u, len %u.\n", ++ i, sgcnt, sg->offset, sg->length); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp, ++ int start, int max, int count) ++{ ++ unsigned int i, j; ++ ++ spin_lock(&ddp->map_lock); ++ for (i = start; i <= max;) { ++ for (j = 0; j < count; j++) { ++ if (ddp->map[i + j]) ++ break; ++ } ++ if (j == count) { ++ memset(&ddp->map[i], 1, count); ++ spin_unlock(&ddp->map_lock); ++ return i; ++ } ++ i += j + 1; ++ } ++ spin_unlock(&ddp->map_lock); ++ return -EBUSY; ++} ++ ++static inline void ddp_unmark_entries(struct cxgb3i_ddp_info *ddp, ++ int start, int count) ++{ ++ spin_lock(&ddp->map_lock); ++ memset(&ddp->map[start], 0, count); ++ spin_unlock(&ddp->map_lock); ++} ++ ++static inline int sgl_map(struct cxgb3i_adapter *snic, ++ struct scatterlist *sgl, unsigned int sgcnt) ++{ ++ struct scatterlist *sg; ++ int i, err; ++ ++ for_each_sg(sgl, sg, sgcnt, i) { ++ err = pci_map_sg(snic->pdev, sg, 1, PCI_DMA_FROMDEVICE); ++ if (err <= 0) { ++ cxgb3i_tag_debug("sgcnt %d/%u, pci map failed %d.\n", ++ i, sgcnt, err); ++ return err; ++ } ++ } ++ return sgcnt; ++} ++ ++static inline void sgl_unmap(struct cxgb3i_adapter *snic, ++ struct scatterlist *sgl, unsigned int sgcnt) ++{ ++ struct scatterlist *sg; ++ int i; ++ ++ for_each_sg(sgl, sg, sgcnt, i) { ++ if (sg_dma_address(sg)) ++ pci_unmap_sg(snic->pdev, sg, 1, PCI_DMA_FROMDEVICE); ++ else ++ break; ++ } ++} ++ ++u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *snic, unsigned int tid, ++ u32 sw_tag, unsigned int xferlen, ++ struct scatterlist *sgl, unsigned int sgcnt) ++{ ++ struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ struct pagepod_hdr hdr; ++ unsigned int npods; ++ int idx = -1, idx_max; ++ u32 tag; ++ int err; ++ ++ if (!ddp || !sgcnt || xferlen < PAGE_SIZE) { ++ cxgb3i_tag_debug("sgcnt %u, xferlen %u < %lu, NO DDP.\n", ++ sgcnt, xferlen, PAGE_SIZE); ++ return RESERVED_ITT; ++ } ++ ++ err = cxgb3i_ddp_sgl_check(sgl, sgcnt); ++ if (err < 0) { ++ cxgb3i_tag_debug("sgcnt %u, xferlen %u, SGL check fail.\n", ++ sgcnt, xferlen); ++ return RESERVED_ITT; ++ } ++ ++ npods = (sgcnt + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; ++ idx_max = ddp->nppods - npods + 1; ++ ++ if (ddp->idx_last == ddp->nppods) ++ idx = ddp_find_unused_entries(ddp, 0, idx_max, npods); ++ else { ++ idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, idx_max, ++ npods); ++ if ((idx < 0) && (ddp->idx_last >= npods)) ++ idx = ddp_find_unused_entries(ddp, 0, ++ ddp->idx_last - npods + 1, ++ npods); ++ } ++ if (idx < 0) { ++ cxgb3i_tag_debug("sgcnt %u, xferlen %u, npods %u NO DDP.\n", ++ sgcnt, xferlen, npods); ++ return RESERVED_ITT; ++ } ++ ++ err = sgl_map(snic, sgl, sgcnt); ++ if (err < sgcnt) ++ goto unmap_sgl; ++ ++ tag = sw_tag | (idx << snic->tag_format.rsvd_shift); ++ ++ hdr.rsvd = 0; ++ hdr.vld_tid = htonl(F_PPOD_VALID | V_PPOD_TID(tid)); ++ hdr.pgsz_tag_clr = htonl(tag & snic->tag_format.rsvd_tag_mask); ++ hdr.maxoffset = htonl(xferlen); ++ hdr.pgoffset = htonl(sgl->offset); ++ ++ if (set_ddp_map(snic, &hdr, idx, npods, sgl, sgcnt) < 0) ++ goto unmap_sgl; ++ ++ ddp->idx_last = idx; ++ cxgb3i_tag_debug("tid 0x%x, xfer %u, 0x%x -> ddp 0x%x (0x%x, %u).\n", ++ tid, xferlen, sw_tag, tag, idx, npods); ++ return tag; ++ ++unmap_sgl: ++ sgl_unmap(snic, sgl, sgcnt); ++ ddp_unmark_entries(ddp, idx, npods); ++ return RESERVED_ITT; ++} ++ ++void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *snic, u32 tag, ++ struct scatterlist *sgl, unsigned int sgcnt) ++{ ++ u32 idx = (tag >> snic->tag_format.rsvd_shift) & ++ snic->tag_format.rsvd_mask; ++ unsigned int npods = (sgcnt + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; ++ ++ if (idx < snic->tag_format.rsvd_mask) { ++ cxgb3i_tag_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n", ++ tag, idx, npods); ++ clear_ddp_map(snic, idx, npods); ++ ddp_unmark_entries(&snic->ddp, idx, npods); ++ sgl_unmap(snic, sgl, sgcnt); ++ } ++} ++ ++int cxgb3i_conn_ulp_setup(struct cxgb3i_conn *cconn, int hcrc, int dcrc) ++{ ++ struct iscsi_tcp_conn *tcp_conn = cconn->conn->dd_data; ++ struct s3_conn *c3cn = (struct s3_conn *)(tcp_conn->sock); ++ struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field), ++ GFP_KERNEL | __GFP_NOFAIL); ++ struct cpl_set_tcb_field *req; ++ u32 submode = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); ++ ++ /* set up ulp submode and page size */ ++ req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, c3cn->tid)); ++ req->reply = V_NO_REPLY(1); ++ req->cpu_idx = 0; ++ req->word = htons(31); ++ req->mask = cpu_to_be64(0xFF000000); ++ /* the connection page size is always the same as ddp-pgsz0 */ ++ req->val = cpu_to_be64(submode << 24); ++ skb->priority = CPL_PRIORITY_CONTROL; ++ ++ cxgb3_ofld_send(c3cn->cdev, skb); ++ return 0; ++} ++ ++static int cxgb3i_conn_read_pdu_skb(struct iscsi_conn *conn, ++ struct sk_buff *skb) ++{ ++ struct iscsi_tcp_conn *tcp_conn = conn->dd_data; ++ struct iscsi_segment *segment = &tcp_conn->in.segment; ++ struct iscsi_hdr *hdr = (struct iscsi_hdr *)tcp_conn->in.hdr_buf; ++ unsigned char *buf = (unsigned char *)hdr; ++ unsigned int offset = sizeof(struct iscsi_hdr); ++ int err; ++ ++ cxgb3i_rx_debug("conn 0x%p, skb 0x%p, len %u, flag 0x%x.\n", ++ conn, skb, skb->len, skb_ulp_mode(skb)); ++ ++ /* read bhs */ ++ err = skb_copy_bits(skb, 0, buf, sizeof(struct iscsi_hdr)); ++ if (err < 0) ++ return err; ++ segment->copied = sizeof(struct iscsi_hdr); ++ /* read ahs */ ++ if (hdr->hlength) { ++ unsigned int ahslen = hdr->hlength << 2; ++ /* Make sure we don't overflow */ ++ if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf)) ++ return -ISCSI_ERR_AHSLEN; ++ err = skb_copy_bits(skb, offset, buf + offset, ahslen); ++ if (err < 0) ++ return err; ++ offset += ahslen; ++ } ++ /* header digest */ ++ if (conn->hdrdgst_en) ++ offset += ISCSI_DIGEST_SIZE; ++ ++ /* check header digest */ ++ segment->status = (conn->hdrdgst_en && ++ (skb_ulp_mode(skb) & ULP2_FLAG_HCRC_ERROR)) ? ++ ISCSI_SEGMENT_DGST_ERR : 0; ++ ++ hdr->itt = ntohl(hdr->itt); ++ segment->total_copied = segment->total_size; ++ tcp_conn->in.hdr = hdr; ++ err = iscsi_tcp_hdr_dissect(conn, hdr); ++ if (err) ++ return err; ++ ++ if (tcp_conn->in.datalen) { ++ segment = &tcp_conn->in.segment; ++ segment->status = (conn->datadgst_en && ++ (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ? ++ ISCSI_SEGMENT_DGST_ERR : 0; ++ if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { ++ cxgb3i_ddp_debug("opcode 0x%x, data %u, ddp'ed.\n", ++ hdr->opcode & ISCSI_OPCODE_MASK, ++ tcp_conn->in.datalen); ++ segment->total_copied = segment->total_size; ++ } else ++ offset += sizeof(struct cpl_iscsi_hdr_norss); ++ ++ while (segment->total_copied < segment->total_size) { ++ iscsi_tcp_segment_map(segment, 1); ++ err = skb_copy_bits(skb, offset, segment->data, ++ segment->size); ++ iscsi_tcp_segment_unmap(segment); ++ if (err) ++ return err; ++ segment->total_copied += segment->size; ++ offset += segment->size; ++ ++ if (segment->total_copied < segment->total_size) ++ iscsi_tcp_segment_init_sg(segment, ++ sg_next(segment->sg), ++ 0); ++ } ++ err = segment->done(tcp_conn, segment); ++ } ++ return err; ++} ++ ++static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) ++{ ++ u8 submode = 0; ++ ++ if (hcrc) ++ submode |= 1; ++ if (dcrc) ++ submode |= 2; ++ skb_ulp_mode(skb) = (ULP_MODE_ISCSI << 4) | submode; ++} ++ ++int cxgb3i_conn_ulp2_xmit(struct iscsi_conn *conn) ++{ ++ struct iscsi_tcp_conn *tcp_conn = conn->dd_data; ++ struct iscsi_segment *hdr_seg = &tcp_conn->out.segment; ++ struct iscsi_segment *data_seg = &tcp_conn->out.data_segment; ++ unsigned int hdrlen = hdr_seg->total_size; ++ unsigned int datalen = data_seg->total_size; ++ unsigned int padlen = iscsi_padding(datalen); ++ unsigned int copymax = SKB_MAX_HEAD(TX_HEADER_LEN); ++ unsigned int copylen; ++ struct sk_buff *skb; ++ unsigned char *dst; ++ int err = -EAGAIN; ++ ++ if (data_seg->data && ((datalen + padlen) < copymax)) ++ copylen = hdrlen + datalen + padlen; ++ else ++ copylen = hdrlen; ++ ++ /* supports max. 16K pdus, so one skb is enough to hold all the data */ ++ skb = alloc_skb(TX_HEADER_LEN + copylen, GFP_ATOMIC); ++ if (!skb) ++ return -EAGAIN; ++ ++ skb_reserve(skb, TX_HEADER_LEN); ++ skb_put(skb, copylen); ++ dst = skb->data; ++ ++ tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); ++ ++ memcpy(dst, hdr_seg->data, hdrlen); ++ dst += hdrlen; ++ ++ if (!datalen) ++ goto send_pdu; ++ ++ if (data_seg->data) { ++ /* data is in a linear buffer */ ++ if (copylen > hdrlen) { ++ /* data fits in the skb's headroom */ ++ memcpy(dst, data_seg->data, datalen); ++ dst += datalen; ++ if (padlen) ++ memset(dst, 0, padlen); ++ } else { ++ unsigned int offset = 0; ++ while (datalen) { ++ struct page *page = alloc_page(GFP_ATOMIC); ++ int idx = skb_shinfo(skb)->nr_frags; ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[idx]; ++ ++ if (!page) ++ goto free_skb; ++ ++ frag->page = page; ++ frag->page_offset = 0; ++ if (datalen > PAGE_SIZE) ++ frag->size = PAGE_SIZE; ++ else ++ frag->size = datalen; ++ memcpy(page_address(page), ++ data_seg->data + offset, frag->size); ++ ++ skb_shinfo(skb)->nr_frags++; ++ datalen -= frag->size; ++ offset += frag->size; ++ } ++ } ++ } else { ++ struct scatterlist *sg = data_seg->sg; ++ unsigned int offset = data_seg->sg_offset; ++ while (datalen) { ++ int idx = skb_shinfo(skb)->nr_frags; ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[idx]; ++ struct page *pg = sg_page(sg); ++ ++ get_page(pg); ++ frag->page = pg; ++ frag->page_offset = offset + sg->offset; ++ frag->size = min(sg->length, datalen); ++ ++ offset = 0; ++ skb_shinfo(skb)->nr_frags++; ++ datalen -= frag->size; ++ sg = sg_next(sg); ++ } ++ } ++ ++ if (skb_shinfo(skb)->nr_frags) { ++ if (padlen) { ++ int idx = skb_shinfo(skb)->nr_frags; ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[idx]; ++ frag->page = pad_page; ++ frag->page_offset = 0; ++ frag->size = padlen; ++ skb_shinfo(skb)->nr_frags++; ++ } ++ datalen = data_seg->total_size + padlen; ++ skb->data_len += datalen; ++ skb->truesize += datalen; ++ skb->len += datalen; ++ } ++ ++send_pdu: ++ err = cxgb3i_c3cn_send_pdus((struct s3_conn *)tcp_conn->sock, ++ skb, MSG_DONTWAIT | MSG_NOSIGNAL); ++ if (err > 0) { ++ int pdulen = hdrlen + datalen + padlen; ++ if (conn->hdrdgst_en) ++ pdulen += ISCSI_DIGEST_SIZE; ++ if (datalen && conn->datadgst_en) ++ pdulen += ISCSI_DIGEST_SIZE; ++ ++ hdr_seg->total_copied = hdr_seg->total_size; ++ if (datalen) ++ data_seg->total_copied = data_seg->total_size; ++ conn->txdata_octets += pdulen; ++ return pdulen; ++ } ++ ++free_skb: ++ kfree_skb(skb); ++ if (err < 0 && err != -EAGAIN) { ++ cxgb3i_log_error("conn 0x%p, xmit err %d.\n", conn, err); ++ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); ++ return err; ++ } ++ return -EAGAIN; ++} ++ ++int cxgb3i_ulp2_init(void) ++{ ++ pad_page = alloc_page(GFP_KERNEL); ++ if (!pad_page) ++ return -ENOMEM; ++ memset(page_address(pad_page), 0, PAGE_SIZE); ++ cxgb3i_ddp_page_init(); ++ return 0; ++} ++ ++void cxgb3i_ulp2_cleanup(void) ++{ ++ if (pad_page) { ++ __free_page(pad_page); ++ pad_page = NULL; ++ } ++} ++ ++void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) ++{ ++ struct sk_buff *skb; ++ unsigned int read = 0; ++ struct iscsi_conn *conn = c3cn->user_data; ++ int err = 0; ++ ++ cxgb3i_rx_debug("cn 0x%p.\n", c3cn); ++ ++ read_lock(&c3cn->callback_lock); ++ if (unlikely(!conn || conn->suspend_rx)) { ++ cxgb3i_rx_debug("conn 0x%p, id %d, suspend_rx %lu!\n", ++ conn, conn ? conn->id : 0xFF, ++ conn ? conn->suspend_rx : 0xFF); ++ read_unlock(&c3cn->callback_lock); ++ return; ++ } ++ skb = skb_peek(&c3cn->receive_queue); ++ while (!err && skb) { ++ __skb_unlink(skb, &c3cn->receive_queue); ++ read += skb_ulp_pdulen(skb); ++ err = cxgb3i_conn_read_pdu_skb(conn, skb); ++ __kfree_skb(skb); ++ skb = skb_peek(&c3cn->receive_queue); ++ } ++ read_unlock(&c3cn->callback_lock); ++ if (c3cn) { ++ c3cn->copied_seq += read; ++ cxgb3i_c3cn_rx_credits(c3cn, read); ++ } ++ conn->rxdata_octets += read; ++ ++ if (err) { ++ cxgb3i_log_info("conn 0x%p rx failed err %d.\n", conn, err); ++ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); ++ } ++} ++ ++void cxgb3i_conn_tx_open(struct s3_conn *c3cn) ++{ ++ struct iscsi_conn *conn = c3cn->user_data; ++ struct iscsi_tcp_conn *tcp_conn; ++ ++ cxgb3i_tx_debug("cn 0x%p.\n", c3cn); ++ if (conn) { ++ cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id); ++ tcp_conn = conn->dd_data; ++ scsi_queue_work(conn->session->host, &conn->xmitwork); ++ } ++} ++ ++void cxgb3i_conn_closing(struct s3_conn *c3cn) ++{ ++ struct iscsi_conn *conn; ++ ++ read_lock(&c3cn->callback_lock); ++ conn = c3cn->user_data; ++ if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) ++ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); ++ read_unlock(&c3cn->callback_lock); ++} ++ ++int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *snic) ++{ ++ struct t3cdev *tdev = snic->tdev; ++ struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ struct ulp_iscsi_info uinfo; ++ unsigned int ppmax, bits, max_bits; ++ int i, err; ++ ++ spin_lock_init(&ddp->map_lock); ++ ++ err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo); ++ if (err < 0) { ++ cxgb3i_log_error("%s, failed to get iscsi param err=%d.\n", ++ tdev->name, err); ++ return err; ++ } ++ ++ ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT; ++ max_bits = min(PPOD_IDX_MAX_SIZE, ++ (32 - sw_tag_idx_bits - sw_tag_age_bits)); ++ bits = __ilog2_u32(ppmax) + 1; ++ if (bits > max_bits) ++ bits = max_bits; ++ ppmax = (1 << bits) - 1; ++ ++ snic->tx_max_size = min_t(unsigned int, ++ uinfo.max_txsz, ULP2_MAX_PKT_SIZE); ++ snic->rx_max_size = min_t(unsigned int, ++ uinfo.max_rxsz, ULP2_MAX_PKT_SIZE); ++ ++ snic->tag_format.idx_bits = sw_tag_idx_bits; ++ snic->tag_format.age_bits = sw_tag_age_bits; ++ snic->tag_format.rsvd_bits = bits; ++ snic->tag_format.rsvd_shift = PPOD_IDX_SHIFT; ++ snic->tag_format.rsvd_mask = (1 << snic->tag_format.rsvd_bits) - 1; ++ snic->tag_format.rsvd_tag_mask = ++ (1 << (snic->tag_format.rsvd_bits + PPOD_IDX_SHIFT)) - 1; ++ ++ ddp->map = cxgb3i_alloc_big_mem(ppmax); ++ if (!ddp->map) { ++ cxgb3i_log_warn("snic unable to alloc ddp ppod 0x%u, " ++ "ddp disabled.\n", ppmax); ++ return 0; ++ } ++ ddp->llimit = uinfo.llimit; ++ ddp->ulimit = uinfo.ulimit; ++ ++ uinfo.tagmask = ++ snic->tag_format.rsvd_mask << snic->tag_format.rsvd_shift; ++ for (i = 0; i < ULP2_PGIDX_MAX; i++) ++ uinfo.pgsz_factor[i] = ddp_page_order[i]; ++ ++ uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT); ++ ++ err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); ++ if (err < 0) { ++ cxgb3i_log_warn("snic unable to set iscsi param err=%d, " ++ "ddp disabled.\n", err); ++ goto free_ppod_map; ++ } ++ ++ ddp->nppods = ppmax; ++ ddp->idx_last = ppmax; ++ ++ tdev->ulp_iscsi = ddp; ++ ++ cxgb3i_log_info("snic nppods %u (0x%x ~ 0x%x), rsvd shift %u, " ++ "bits %u, mask 0x%x, 0x%x, pkt %u,%u.\n", ++ ppmax, ddp->llimit, ddp->ulimit, ++ snic->tag_format.rsvd_shift, ++ snic->tag_format.rsvd_bits, ++ snic->tag_format.rsvd_mask, uinfo.tagmask, ++ snic->tx_max_size, snic->rx_max_size); ++ ++ return 0; ++ ++free_ppod_map: ++ cxgb3i_free_big_mem(ddp->map); ++ return 0; ++} ++ ++void cxgb3i_adapter_ulp_cleanup(struct cxgb3i_adapter *snic) ++{ ++ u8 *map = snic->ddp.map; ++ ++ if (map) { ++ snic->tdev->ulp_iscsi = NULL; ++ spin_lock(&snic->lock); ++ snic->ddp.map = NULL; ++ spin_unlock(&snic->lock); ++ cxgb3i_free_big_mem(map); ++ } ++} +--- /dev/null ++++ b/drivers/scsi/cxgb3i/cxgb3i_ulp2.h +@@ -0,0 +1,108 @@ ++/* ++ * cxgb3i_ulp2.h: Chelsio S3xx iSCSI driver. ++ * ++ * Copyright (c) 2008 Chelsio Communications, Inc. ++ * ++ * 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. ++ * ++ * Written by: Karen Xie (kxie@chelsio.com) ++ */ ++ ++#ifndef __CXGB3I_ULP2_H__ ++#define __CXGB3I_ULP2_H__ ++ ++#define ULP2_PDU_PAYLOAD_DFLT (16224 - ISCSI_PDU_HEADER_MAX) ++#define PPOD_PAGES_MAX 4 ++#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ ++ ++struct pagepod_hdr { ++ u32 vld_tid; ++ u32 pgsz_tag_clr; ++ u32 maxoffset; ++ u32 pgoffset; ++ u64 rsvd; ++}; ++ ++struct pagepod { ++ struct pagepod_hdr hdr; ++ u64 addr[PPOD_PAGES_MAX + 1]; ++}; ++ ++#define PPOD_SIZE sizeof(struct pagepod) /* 64 */ ++#define PPOD_SIZE_SHIFT 6 ++ ++#define PPOD_COLOR_SHIFT 0 ++#define PPOD_COLOR_SIZE 6 ++#define PPOD_COLOR_MASK ((1 << PPOD_COLOR_SIZE) - 1) ++ ++#define PPOD_IDX_SHIFT PPOD_COLOR_SIZE ++#define PPOD_IDX_MAX_SIZE 24 ++ ++#define S_PPOD_TID 0 ++#define M_PPOD_TID 0xFFFFFF ++#define V_PPOD_TID(x) ((x) << S_PPOD_TID) ++ ++#define S_PPOD_VALID 24 ++#define V_PPOD_VALID(x) ((x) << S_PPOD_VALID) ++#define F_PPOD_VALID V_PPOD_VALID(1U) ++ ++#define S_PPOD_COLOR 0 ++#define M_PPOD_COLOR 0x3F ++#define V_PPOD_COLOR(x) ((x) << S_PPOD_COLOR) ++ ++#define S_PPOD_TAG 6 ++#define M_PPOD_TAG 0xFFFFFF ++#define V_PPOD_TAG(x) ((x) << S_PPOD_TAG) ++ ++#define S_PPOD_PGSZ 30 ++#define M_PPOD_PGSZ 0x3 ++#define V_PPOD_PGSZ(x) ((x) << S_PPOD_PGSZ) ++ ++struct cpl_iscsi_hdr_norss { ++ union opcode_tid ot; ++ u16 pdu_len_ddp; ++ u16 len; ++ u32 seq; ++ u16 urg; ++ u8 rsvd; ++ u8 status; ++}; ++ ++struct cpl_rx_data_ddp_norss { ++ union opcode_tid ot; ++ u16 urg; ++ u16 len; ++ u32 seq; ++ u32 nxt_seq; ++ u32 ulp_crc; ++ u32 ddp_status; ++}; ++ ++#define RX_DDP_STATUS_IPP_SHIFT 27 /* invalid pagepod */ ++#define RX_DDP_STATUS_TID_SHIFT 26 /* tid mismatch */ ++#define RX_DDP_STATUS_COLOR_SHIFT 25 /* color mismatch */ ++#define RX_DDP_STATUS_OFFSET_SHIFT 24 /* offset mismatch */ ++#define RX_DDP_STATUS_ULIMIT_SHIFT 23 /* ulimit error */ ++#define RX_DDP_STATUS_TAG_SHIFT 22 /* tag mismatch */ ++#define RX_DDP_STATUS_DCRC_SHIFT 21 /* dcrc error */ ++#define RX_DDP_STATUS_HCRC_SHIFT 20 /* hcrc error */ ++#define RX_DDP_STATUS_PAD_SHIFT 19 /* pad error */ ++#define RX_DDP_STATUS_PPP_SHIFT 18 /* pagepod parity error */ ++#define RX_DDP_STATUS_LLIMIT_SHIFT 17 /* llimit error */ ++#define RX_DDP_STATUS_DDP_SHIFT 16 /* ddp'able */ ++#define RX_DDP_STATUS_PMM_SHIFT 15 /* pagepod mismatch */ ++ ++#define ULP2_FLAG_DATA_READY 0x1 ++#define ULP2_FLAG_DATA_DDPED 0x2 ++#define ULP2_FLAG_HCRC_ERROR 0x10 ++#define ULP2_FLAG_DCRC_ERROR 0x20 ++#define ULP2_FLAG_PAD_ERROR 0x40 ++ ++#define ULP2_MAX_PKT_SIZE 16224 ++ ++void cxgb3i_conn_closing(struct s3_conn *); ++void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); ++void cxgb3i_conn_tx_open(struct s3_conn *c3cn); ++#endif +--- /dev/null ++++ b/drivers/scsi/cxgb3i/Kconfig +@@ -0,0 +1,7 @@ ++config SCSI_CXGB3_ISCSI ++ tristate "Chelsio S3xx iSCSI support" ++ select CHELSIO_T3 ++ select SCSI_ISCSI_ATTRS ++ select ISCSI_TCP ++ ---help--- ++ This driver supports iSCSI offload for the Chelsio S3 series devices. +--- /dev/null ++++ b/drivers/scsi/cxgb3i/Makefile +@@ -0,0 +1,5 @@ ++EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 ++ ++cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_ulp2.o cxgb3i_offload.o ++ ++obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o +--- a/drivers/scsi/Kconfig ++++ b/drivers/scsi/Kconfig +@@ -352,6 +352,8 @@ config ISCSI_TCP + + http://open-iscsi.org + ++source "drivers/scsi/cxgb3i/Kconfig" ++ + config SGIWD93_SCSI + tristate "SGI WD93C93 SCSI Driver" + depends on SGI_HAS_WD93 && SCSI +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -40,6 +40,7 @@ obj-$(CONFIG_LIBFC) += libfc/ + obj-$(CONFIG_FCOE) += fcoe/ + obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o + obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o ++obj-$(CONFIG_SCSI_CXGB3_ISCSI) += iscsi_tcp.o cxgb3i/ + obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o + obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o + obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-fix-skb-overrun b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-fix-skb-overrun new file mode 100644 index 000000000..84498c561 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-fix-skb-overrun @@ -0,0 +1,1360 @@ +Subject: cxgb3i - fixes over-run of skb MAX_SKB_FRAGS +From: Karen Xie +References: bnc#468314 + +This patch fixes the over-run of skb's MAX_SKB_FRAGS between the cxgb3i and +cxgb3 driver on PPC64 systems. + +Signed-off-by: Karen Xie +Signed-off-by: Chandra Seetharaman +Acked-by: Hannes Reinecke +--- + +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i.h linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i.h +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i.h 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i.h 2009-01-26 22:00:17.000000000 -0800 +@@ -36,6 +36,12 @@ + #define CXGB3I_MAX_TARGET CXGB3I_MAX_CONN + #define CXGB3I_MAX_LUN 512 + #define ISCSI_PDU_HEADER_MAX (56 + 256) /* bhs + digests + ahs */ ++#define ULP2_MAX_PKT_SIZE 16224 ++#define ISCSI_PDU_NONPAYLOAD_MAX \ ++ (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + 2*ISCSI_DIGEST_SIZE) ++#define ULP2_MAX_PDU_PAYLOAD \ ++ (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_MAX) ++ + + struct cxgb3i_adapter; + struct cxgb3i_hba; +@@ -53,12 +59,11 @@ + * + */ + struct cxgb3i_tag_format { +- unsigned char idx_bits; +- unsigned char age_bits; ++ unsigned char sw_bits; + unsigned char rsvd_bits; + unsigned char rsvd_shift; ++ unsigned char filler[1]; + u32 rsvd_mask; +- u32 rsvd_tag_mask; + }; + + /** +@@ -95,11 +100,137 @@ + unsigned int ulimit; + unsigned int nppods; + unsigned int idx_last; ++ unsigned char idx_bits; ++ unsigned char filler[3]; ++ u32 idx_mask; ++ u32 rsvd_tag_mask; + spinlock_t map_lock; + struct cxgb3i_gather_list **gl_map; + struct sk_buff **gl_skb; + }; + ++/* ++ * cxgb3i ddp tag are 32 bits, it consists of reserved bits used by h/w and ++ * non-reserved bits that can be used by the iscsi s/w. ++ * The reserved bits are identified by the rsvd_bits and rsvd_shift fields ++ * in struct cxgb3i_tag_format. ++ * ++ * The upper most reserved bit can be used to check if a tag is ddp tag or not: ++ * if the bit is 0, the tag is a valid ddp tag ++ */ ++ ++/** ++ * cxgb3i_is_ddp_tag - check if a given tag is a hw/ddp tag ++ * @tformat: tag format information ++ * @tag: tag to be checked ++ * ++ * return true if the tag is a ddp tag, false otherwise. ++ */ ++static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag) ++{ ++ return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1))); ++} ++ ++/** ++ * cxgb3i_sw_tag_usable - check if a given s/w tag has enough bits left for ++ * the reserved/hw bits ++ * @tformat: tag format information ++ * @sw_tag: s/w tag to be checked ++ * ++ * return true if the tag is a ddp tag, false otherwise. ++ */ ++static inline int cxgb3i_sw_tag_usable(struct cxgb3i_tag_format *tformat, ++ u32 sw_tag) ++{ ++ sw_tag >>= (32 - tformat->rsvd_bits); ++ return !sw_tag; ++} ++ ++/** ++ * cxgb3i_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag ++ * @tformat: tag format information ++ * @sw_tag: s/w tag to be checked ++ * ++ * insert 1 at the upper most reserved bit to mark it as an invalid ddp tag. ++ */ ++static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat, ++ u32 sw_tag) ++{ ++ unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; ++ u32 mask = (1 << shift) - 1; ++ ++ if (sw_tag && (sw_tag & ~mask)) { ++ u32 v1 = sw_tag & ((1 << shift) - 1); ++ u32 v2 = (sw_tag >> (shift - 1)) << shift; ++ ++ return v2 | v1 | 1 << shift; ++ } ++ return sw_tag | 1 << shift; ++} ++ ++/** ++ * cxgb3i_ddp_tag_base - shift the s/w tag bits so that reserved bits are not ++ * used. ++ * @tformat: tag format information ++ * @sw_tag: s/w tag to be checked ++ */ ++static inline u32 cxgb3i_ddp_tag_base(struct cxgb3i_tag_format *tformat, ++ u32 sw_tag) ++{ ++ u32 mask = (1 << tformat->rsvd_shift) - 1; ++ ++ if (sw_tag && (sw_tag & ~mask)) { ++ u32 v1 = sw_tag & mask; ++ u32 v2 = sw_tag >> tformat->rsvd_shift; ++ ++ v2 <<= tformat->rsvd_shift + tformat->rsvd_bits; ++ return v2 | v1; ++ } ++ return sw_tag; ++} ++ ++/** ++ * cxgb3i_tag_rsvd_bits - get the reserved bits used by the h/w ++ * @tformat: tag format information ++ * @tag: tag to be checked ++ * ++ * return the reserved bits in the tag ++ */ ++static inline u32 cxgb3i_tag_rsvd_bits(struct cxgb3i_tag_format *tformat, ++ u32 tag) ++{ ++ if (cxgb3i_is_ddp_tag(tformat, tag)) ++ return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask; ++ return 0; ++} ++ ++/** ++ * cxgb3i_tag_nonrsvd_bits - get the non-reserved bits used by the s/w ++ * @tformat: tag format information ++ * @tag: tag to be checked ++ * ++ * return the non-reserved bits in the tag. ++ */ ++static inline u32 cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format *tformat, ++ u32 tag) ++{ ++ unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; ++ u32 v1, v2; ++ ++ if (cxgb3i_is_ddp_tag(tformat, tag)) { ++ v1 = tag & ((1 << tformat->rsvd_shift) - 1); ++ v2 = (tag >> (shift + 1)) << tformat->rsvd_shift; ++ } else { ++ u32 mask = (1 << shift) - 1; ++ ++ tag &= ~(1 << shift); ++ v1 = tag & mask; ++ v2 = (tag >> 1) & ~mask; ++ } ++ return v1 | v2; ++} ++ ++ + /** + * struct cxgb3i_hba - cxgb3i iscsi structure (per port) + * +@@ -146,16 +277,22 @@ + * struct cxgb3i_conn - cxgb3i iscsi connection + * + * @tcp_conn: pointer to iscsi_tcp_conn structure +- * @listhead: list head to link elements ++ * @list_head: list head to link elements ++ * @cep: pointer to iscsi_endpoint structure + * @conn: pointer to iscsi_conn structure + * @hba: pointer to the hba this conn. is going through ++ * @task_idx_bits: # of bits needed for session->cmds_max ++ * @frags: temp. holding area for tx coalesced sg list pages. + */ ++#define TX_PDU_PAGES_MAX (16384/512 + 1) + struct cxgb3i_conn { + struct iscsi_tcp_conn tcp_conn; + struct list_head list_head; + struct cxgb3i_endpoint *cep; + struct iscsi_conn *conn; + struct cxgb3i_hba *hba; ++ unsigned int task_idx_bits; ++ skb_frag_t frags[TX_PDU_PAGES_MAX]; + }; + + /** +@@ -190,8 +327,7 @@ + int cxgb3i_ulp2_init(void); + void cxgb3i_ulp2_cleanup(void); + int cxgb3i_conn_ulp_setup(struct cxgb3i_conn *, int, int); +-void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *, u32, +- struct scatterlist *, unsigned int); ++void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *, u32); + u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *, unsigned int, + u32, unsigned int, struct scatterlist *, + unsigned int, int); +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_init.c linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_init.c +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_init.c 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_init.c 2009-01-26 22:00:17.000000000 -0800 +@@ -11,8 +11,8 @@ + + #include "cxgb3i.h" + +-#define DRV_MODULE_NAME "cxgb3i" +-#define DRV_MODULE_VERSION "0.1.0" ++#define DRV_MODULE_NAME "cxgb3i" ++#define DRV_MODULE_VERSION "0.9.0" + #define DRV_MODULE_RELDATE "Jun. 1, 2008" + + static char version[] = +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2009-01-26 22:00:17.000000000 -0800 +@@ -36,10 +36,10 @@ + #define cxgb3i_api_debug(fmt...) + #endif + +-#define align_to_4k_boundary(n) \ +- do { \ +- n = (n) & ~((1 << 12) - 1); \ +- } while(0) ++/* ++ * align pdu size to multiple of 512 for better performance ++ */ ++#define align_pdu_size(n) do { n = (n) & (~511); } while (0) + + static struct scsi_transport_template *cxgb3i_scsi_transport; + static struct scsi_host_template cxgb3i_host_template; +@@ -102,7 +102,7 @@ + struct cxgb3i_adapter *snic; + + /* remove from the list */ +- read_lock(&cxgb3i_snic_rwlock); ++ write_lock(&cxgb3i_snic_rwlock); + list_for_each_entry(snic, &cxgb3i_snic_list, list_head) { + if (snic->tdev == t3dev) { + list_del(&snic->list_head); +@@ -295,6 +295,8 @@ + * stop the xmit path so the xmit_segment function is + * not being called + */ ++ iscsi_suspend_tx(cconn->conn); ++ + write_lock_bh(&cep->c3cn->callback_lock); + set_bit(ISCSI_SUSPEND_BIT, &cconn->conn->suspend_rx); + cep->c3cn->user_data = NULL; +@@ -391,20 +393,17 @@ + static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) + { + struct cxgb3i_conn *cconn = conn->dd_data; +- unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE, +- cconn->hba->snic->tx_max_size - +- ISCSI_PDU_HEADER_MAX); +- +- cxgb3i_api_debug("conn 0x%p, max xmit %u.\n", +- conn, conn->max_xmit_dlength); ++ unsigned int max = min_t(unsigned int, ++ ULP2_MAX_PDU_PAYLOAD, ++ cconn->hba->snic->tx_max_size - ++ ISCSI_PDU_NONPAYLOAD_MAX); + + if (conn->max_xmit_dlength) + conn->max_xmit_dlength = min_t(unsigned int, +- conn->max_xmit_dlength, max); ++ conn->max_xmit_dlength, max); + else + conn->max_xmit_dlength = max; +- +- align_to_4k_boundary(conn->max_xmit_dlength); ++ align_pdu_size(conn->max_xmit_dlength); + + cxgb3i_api_debug("conn 0x%p, set max xmit %u.\n", + conn, conn->max_xmit_dlength); +@@ -415,14 +414,10 @@ + static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) + { + struct cxgb3i_conn *cconn = conn->dd_data; +- unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE, +- cconn->hba->snic->rx_max_size - +- ISCSI_PDU_HEADER_MAX); +- +- cxgb3i_api_debug("conn 0x%p, max recv %u.\n", +- conn, conn->max_recv_dlength); +- +- align_to_4k_boundary(max); ++ unsigned int max = min_t(unsigned int, ++ ULP2_MAX_PDU_PAYLOAD, ++ cconn->hba->snic->tx_max_size - ++ ISCSI_PDU_NONPAYLOAD_MAX); + + if (conn->max_recv_dlength) { + if (conn->max_recv_dlength > max) { +@@ -433,9 +428,9 @@ + } + conn->max_recv_dlength = min_t(unsigned int, + conn->max_recv_dlength, max); +- align_to_4k_boundary(conn->max_recv_dlength); + } else + conn->max_recv_dlength = max; ++ align_pdu_size(conn->max_recv_dlength); + + cxgb3i_api_debug("conn 0x%p, set max recv %u.\n", + conn, conn->max_recv_dlength); +@@ -516,12 +511,14 @@ + + cep = ep->dd_data; + c3cn = cep->c3cn; ++ /* calculate the tag idx bits needed for this conn based on cmds_max */ ++ cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; + +- read_lock(&c3cn->callback_lock); ++ write_lock(&c3cn->callback_lock); + /* mnc: TODO don't abuse iscsi_tcp fields */ + tcp_conn->sock = (struct socket *)c3cn; + c3cn->user_data = conn; +- read_unlock(&c3cn->callback_lock); ++ write_unlock(&c3cn->callback_lock); + + cconn->hba = cep->hba; + cconn->cep = cep; +@@ -609,11 +606,13 @@ + return -ENOMEM; + case ISCSI_PARAM_MAX_RECV_DLENGTH: + err = iscsi_set_param(cls_conn, param, buf, buflen); +- err = cxgb3i_conn_max_recv_dlength(conn); ++ if (!err) ++ err = cxgb3i_conn_max_recv_dlength(conn); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + err = iscsi_set_param(cls_conn, param, buf, buflen); +- err = cxgb3i_conn_max_xmit_dlength(conn); ++ if (!err) ++ err = cxgb3i_conn_max_xmit_dlength(conn); + break; + default: + return iscsi_set_param(cls_conn, param, buf, buflen); +@@ -718,49 +717,23 @@ + stats->custom[0].value = conn->eh_abort_cnt; + } + +-static inline u32 tag_base(struct cxgb3i_tag_format *format, +- unsigned int idx, unsigned int age) +-{ +- u32 sw_bits = idx | (age << format->idx_bits); +- u32 tag = sw_bits >> format->rsvd_shift; +- +- tag <<= format->rsvd_bits + format->rsvd_shift; +- tag |= sw_bits & ((1 << format->rsvd_shift) - 1); +- return tag; +-} +- +-static inline void cxgb3i_parse_tag(struct cxgb3i_tag_format *format, +- u32 tag, u32 *rsvd_bits, u32 *sw_bits) +-{ +- if (rsvd_bits) +- *rsvd_bits = (tag >> format->rsvd_shift) & format->rsvd_mask; +- if (sw_bits) { +- *sw_bits = (tag >> (format->rsvd_shift + format->rsvd_bits)) +- << format->rsvd_shift; +- *sw_bits |= tag & ((1 << format->rsvd_shift) - 1); +- } +- +- cxgb3i_tag_debug("parse tag 0x%x, rsvd 0x%x, sw 0x%x.\n", +- tag, rsvd_bits ? *rsvd_bits : 0xFFFFFFFF, +- sw_bits ? *sw_bits : 0xFFFFFFFF); +-} +- +- + static void cxgb3i_parse_itt(struct iscsi_conn *conn, itt_t itt, + int *idx, int *age) + { + struct cxgb3i_conn *cconn = conn->dd_data; + struct cxgb3i_adapter *snic = cconn->hba->snic; ++ u32 tag = itt; + u32 sw_bits; + +- cxgb3i_parse_tag(&snic->tag_format, itt, NULL, &sw_bits); ++ sw_bits = cxgb3i_tag_nonrsvd_bits(&snic->tag_format, tag); + if (idx) +- *idx = sw_bits & ISCSI_ITT_MASK; ++ *idx = sw_bits & ((1 << cconn->task_idx_bits) - 1); + if (age) +- *age = (sw_bits >> snic->tag_format.idx_bits) & ISCSI_AGE_MASK; ++ *age = (sw_bits >> cconn->task_idx_bits) & ISCSI_AGE_MASK; + +- cxgb3i_tag_debug("parse itt 0x%x, idx 0x%x, age 0x%x.\n", +- itt, idx ? *idx : 0xFFFFF, age ? *age : 0xFF); ++ cxgb3i_tag_debug("parse tag 0x%x/0x%x, sw 0x%x, idx 0x%x, age 0x%x.\n", ++ tag, itt, sw_bits, idx ? *idx : 0xFFFFF, ++ age ? *age : 0xFF); + } + + static int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) +@@ -771,26 +744,40 @@ + struct cxgb3i_conn *cconn = conn->dd_data; + struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; + struct cxgb3i_adapter *snic = cconn->hba->snic; +- u32 sw_tag = tag_base(&snic->tag_format, task->itt, sess->age); ++ struct cxgb3i_tag_format *tformat = &snic->tag_format; ++ u32 sw_tag = (sess->age << cconn->task_idx_bits) | task->itt; + u32 tag = RESERVED_ITT; + +- if (sc && (sc->sc_data_direction == DMA_FROM_DEVICE)) { ++ if (sc && (scsi_bidi_cmnd(sc) || ++ sc->sc_data_direction == DMA_FROM_DEVICE) && ++ cxgb3i_sw_tag_usable(tformat, sw_tag)) { + struct s3_conn *c3cn = (struct s3_conn *)(tcp_conn->sock); +- tag = +- cxgb3i_ddp_tag_reserve(snic, c3cn->tid, sw_tag, ++ tag = cxgb3i_ddp_tag_reserve(snic, c3cn->tid, sw_tag, + scsi_in(sc)->length, + scsi_in(sc)->table.sgl, + scsi_in(sc)->table.nents, + GFP_ATOMIC); + } + if (tag == RESERVED_ITT) +- tag = sw_tag | (snic->tag_format.rsvd_mask << +- snic->tag_format.rsvd_shift); ++ tag = cxgb3i_set_non_ddp_tag(tformat, sw_tag); ++ /* the itt need to sent in big-endian order */ + *hdr_itt = htonl(tag); + +- cxgb3i_tag_debug("new tag 0x%x/0x%x (itt 0x%x, age 0x%x).\n", +- tag, *hdr_itt, task->itt, sess->age); +- ++ if (sc) { ++ if (sc->sc_data_direction == DMA_FROM_DEVICE) ++ cxgb3i_tag_debug("read, len %u, tag 0x%x/0x%x " ++ "(itt 0x%x, age 0x%x, sw 0x%x).\n", ++ scsi_in(sc)->length, tag, *hdr_itt, ++ task->itt, sess->age, sw_tag); ++ else ++ cxgb3i_tag_debug("write, len %u, tag 0x%x/0x%x " ++ "(itt 0x%x, age 0x%x, sw 0x%x).\n", ++ scsi_out(sc)->length, tag, *hdr_itt, ++ task->itt, sess->age, sw_tag); ++ } else ++ cxgb3i_tag_debug("ctrl, tag 0x%x/0x%x (itt 0x%x, age 0x%x, " ++ "sw 0x%x).\n", ++ tag, *hdr_itt, task->itt, sess->age, sw_tag); + return 0; + } + +@@ -800,14 +787,15 @@ + struct iscsi_conn *conn = task->conn; + struct cxgb3i_conn *cconn = conn->dd_data; + struct cxgb3i_adapter *snic = cconn->hba->snic; ++ struct cxgb3i_tag_format *tformat = &snic->tag_format; + u32 tag = ntohl(hdr_itt); + +- cxgb3i_tag_debug("release tag 0x%x.\n", tag); ++ cxgb3i_tag_debug("release %s tag 0x%x.\n", sc ? "scsi" : "ctrl", tag); + +- if (sc && (sc->sc_data_direction == DMA_FROM_DEVICE)) +- cxgb3i_ddp_tag_release(snic, tag, +- scsi_in(sc)->table.sgl, +- scsi_in(sc)->table.nents); ++ if (sc && (scsi_bidi_cmnd(sc) || ++ sc->sc_data_direction == DMA_FROM_DEVICE) && ++ cxgb3i_is_ddp_tag(tformat, tag)) ++ cxgb3i_ddp_tag_release(snic, tag); + } + + /** +@@ -820,7 +808,7 @@ + .proc_name = "cxgb3i", + .queuecommand = iscsi_queuecommand, + .change_queue_depth = iscsi_change_queue_depth, +- .can_queue = 128 * (ISCSI_DEF_XMIT_CMDS_MAX - 1), ++ .can_queue = CXGB3I_SCSI_QDEPTH_DFLT - 1, + .sg_tablesize = SG_ALL, + .max_sectors = 0xFFFF, + .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_offload.c +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_offload.c 2009-01-26 22:00:17.000000000 -0800 +@@ -22,19 +22,19 @@ + #include "cxgb3i_ulp2.h" + + #ifdef __DEBUG_C3CN_CONN__ +-#define c3cn_conn_debug cxgb3i_log_debug ++#define c3cn_conn_debug cxgb3i_log_debug + #else + #define c3cn_conn_debug(fmt...) + #endif + + #ifdef __DEBUG_C3CN_TX__ +-#define c3cn_tx_debug cxgb3i_log_debug ++#define c3cn_tx_debug cxgb3i_log_debug + #else + #define c3cn_tx_debug(fmt...) + #endif + + #ifdef __DEBUG_C3CN_RX__ +-#define c3cn_rx_debug cxgb3i_log_debug ++#define c3cn_rx_debug cxgb3i_log_debug + #else + #define c3cn_rx_debug(fmt...) + #endif +@@ -42,9 +42,9 @@ + /* + * module parameters releated to offloaded iscsi connection + */ +-static int cxgb3_rcv_win = 256 * 1024; ++static int cxgb3_rcv_win = 128 * 1024; + module_param(cxgb3_rcv_win, int, 0644); +-MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=256KB)"); ++MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=128KB)"); + + static int cxgb3_snd_win = 64 * 1024; + module_param(cxgb3_snd_win, int, 0644); +@@ -456,12 +456,9 @@ + * The number of WRs needed for an skb depends on the number of fragments + * in the skb and whether it has any payload in its main body. This maps the + * length of the gather list represented by an skb into the # of necessary WRs. +- * +- * The max. length of an skb is controlled by the max pdu size which is ~16K. +- * Also, assume the min. fragment length is the sector size (512), then add +- * extra fragment counts for iscsi bhs and payload padding. ++ * The extra two fragments are for iscsi bhs and payload padding. + */ +-#define SKB_WR_LIST_SIZE (16384/512 + 3) ++#define SKB_WR_LIST_SIZE (MAX_SKB_FRAGS + 2) + static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly; + + static void s3_init_wr_tab(unsigned int wr_len) +@@ -484,7 +481,7 @@ + + static inline void reset_wr_list(struct s3_conn *c3cn) + { +- c3cn->wr_pending_head = NULL; ++ c3cn->wr_pending_head = c3cn->wr_pending_tail = NULL; + } + + /* +@@ -495,7 +492,7 @@ + static inline void enqueue_wr(struct s3_conn *c3cn, + struct sk_buff *skb) + { +- skb->sp = NULL; ++ skb_wr_next(skb) = NULL; + + /* + * We want to take an extra reference since both us and the driver +@@ -508,10 +505,22 @@ + if (!c3cn->wr_pending_head) + c3cn->wr_pending_head = skb; + else +- c3cn->wr_pending_tail->sp = (void *)skb; ++ skb_wr_next(c3cn->wr_pending_tail) = skb; + c3cn->wr_pending_tail = skb; + } + ++static int count_pending_wrs(struct s3_conn *c3cn) ++{ ++ int n = 0; ++ const struct sk_buff *skb = c3cn->wr_pending_head; ++ ++ while (skb) { ++ n += skb->csum; ++ skb = skb_wr_next(skb); ++ } ++ return n; ++} ++ + static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn) + { + return c3cn->wr_pending_head; +@@ -528,8 +537,8 @@ + + if (likely(skb)) { + /* Don't bother clearing the tail */ +- c3cn->wr_pending_head = (struct sk_buff *)skb->sp; +- skb->sp = NULL; ++ c3cn->wr_pending_head = skb_wr_next(skb); ++ skb_wr_next(skb) = NULL; + } + return skb; + } +@@ -542,13 +551,15 @@ + } + + static inline void make_tx_data_wr(struct s3_conn *c3cn, struct sk_buff *skb, +- int len) ++ int len, int req_completion) + { + struct tx_data_wr *req; + + skb_reset_transport_header(skb); + req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req)); +- req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); ++ ++ req->wr_hi = htonl((V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)) | ++ (req_completion ? F_WR_COMPL : 0)); + req->wr_lo = htonl(V_WR_TID(c3cn->tid)); + req->sndseq = htonl(c3cn->snd_nxt); + /* len includes the length of any HW ULP additions */ +@@ -556,11 +567,11 @@ + req->param = htonl(V_TX_PORT(c3cn->l2t->smt_idx)); + /* V_TX_ULP_SUBMODE sets both the mode and submode */ + req->flags = htonl(V_TX_ULP_SUBMODE(skb_ulp_mode(skb)) | +- V_TX_SHOVE((skb_peek(&c3cn->write_queue) ? 0 : 1))); ++ V_TX_SHOVE((skb_peek(&c3cn->write_queue) ? 0 : 1))); + + if (!c3cn_flag(c3cn, C3CN_TX_DATA_SENT)) { +- req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | +- V_TX_CPU_IDX(c3cn->qset)); ++ req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | ++ V_TX_CPU_IDX(c3cn->qset)); + /* Sendbuffer is in units of 32KB. */ + req->param |= htonl(V_TX_SNDBUF(cxgb3_snd_win >> 15)); + c3cn_set_flag(c3cn, C3CN_TX_DATA_SENT); +@@ -591,7 +602,7 @@ + + if (unlikely(c3cn->state == C3CN_STATE_CONNECTING || + c3cn->state == C3CN_STATE_CLOSE_WAIT_1 || +- c3cn->state == C3CN_STATE_ABORTING)) { ++ c3cn->state >= C3CN_STATE_ABORTING)) { + c3cn_tx_debug("c3cn 0x%p, in closing state %u.\n", + c3cn, c3cn->state); + return 0; +@@ -626,19 +637,22 @@ + c3cn->wr_unacked += wrs_needed; + enqueue_wr(c3cn, skb); + +- if (likely(CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_NEED_HDR)) { +- len += ulp_extra_len(skb); +- make_tx_data_wr(c3cn, skb, len); +- c3cn->snd_nxt += len; +- if ((req_completion +- && c3cn->wr_unacked == wrs_needed) +- || (CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_COMPL) +- || c3cn->wr_unacked >= c3cn->wr_max / 2) { +- struct work_request_hdr *wr = cplhdr(skb); ++ c3cn_tx_debug("c3cn 0x%p, enqueue, skb len %u/%u, frag %u, " ++ "wr %d, left %u, unack %u.\n", ++ c3cn, skb->len, skb->data_len, frags, ++ wrs_needed, c3cn->wr_avail, c3cn->wr_unacked); + +- wr->wr_hi |= htonl(F_WR_COMPL); ++ if (likely(CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_NEED_HDR)) { ++ if ((req_completion && ++ c3cn->wr_unacked == wrs_needed) || ++ (CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_COMPL) || ++ c3cn->wr_unacked >= c3cn->wr_max / 2) { ++ req_completion = 1; + c3cn->wr_unacked = 0; + } ++ len += ulp_extra_len(skb); ++ make_tx_data_wr(c3cn, skb, len, req_completion); ++ c3cn->snd_nxt += len; + CXGB3_SKB_CB(skb)->flags &= ~C3CB_FLAG_NEED_HDR; + } + +@@ -1153,12 +1167,28 @@ + * Process an acknowledgment of WR completion. Advance snd_una and send the + * next batch of work requests from the write queue. + */ ++ ++static void check_wr_invariants(struct s3_conn *c3cn) ++{ ++ int pending = count_pending_wrs(c3cn); ++ ++ if (unlikely(c3cn->wr_avail + pending != c3cn->wr_max)) ++ cxgb3i_log_error("TID %u: credit imbalance: avail %u, " ++ "pending %u, total should be %u\n", ++ c3cn->tid, c3cn->wr_avail, pending, ++ c3cn->wr_max); ++} ++ + static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) + { + struct cpl_wr_ack *hdr = cplhdr(skb); + unsigned int credits = ntohs(hdr->credits); + u32 snd_una = ntohl(hdr->snd_una); + ++ c3cn_tx_debug("%u WR credits, avail %u, unack %u, TID %u, state %u.\n", ++ credits, c3cn->wr_avail, c3cn->wr_unacked, ++ c3cn->tid, c3cn->state); ++ + c3cn->wr_avail += credits; + if (c3cn->wr_unacked > c3cn->wr_max - c3cn->wr_avail) + c3cn->wr_unacked = c3cn->wr_max - c3cn->wr_avail; +@@ -1173,6 +1203,17 @@ + break; + } + if (unlikely(credits < p->csum)) { ++ struct tx_data_wr *w = cplhdr(p); ++ cxgb3i_log_error("TID %u got %u WR credits need %u, " ++ "len %u, main body %u, frags %u, " ++ "seq # %u, ACK una %u, ACK nxt %u, " ++ "WR_AVAIL %u, WRs pending %u\n", ++ c3cn->tid, credits, p->csum, p->len, ++ p->len - p->data_len, ++ skb_shinfo(p)->nr_frags, ++ ntohl(w->sndseq), snd_una, ++ ntohl(hdr->snd_nxt), c3cn->wr_avail, ++ count_pending_wrs(c3cn) - credits); + p->csum -= credits; + break; + } else { +@@ -1182,8 +1223,14 @@ + } + } + +- if (unlikely(before(snd_una, c3cn->snd_una))) ++ check_wr_invariants(c3cn); ++ ++ if (unlikely(before(snd_una, c3cn->snd_una))) { ++ cxgb3i_log_error("TID %u, unexpected sequence # %u in WR_ACK " ++ "snd_una %u\n", ++ c3cn->tid, snd_una, c3cn->snd_una); + goto out_free; ++ } + + if (c3cn->snd_una != snd_una) { + c3cn->snd_una = snd_una; +@@ -1454,11 +1501,14 @@ + struct dst_entry *dst) + { + BUG_ON(c3cn->cdev != cdev); +- c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs; ++ c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs - 1; + c3cn->wr_unacked = 0; + c3cn->mss_idx = select_mss(c3cn, dst_mtu(dst)); + + reset_wr_list(c3cn); ++ ++ c3cn_conn_debug("c3cn 0x%p, wr max %u, avail %u.\n", ++ c3cn, c3cn->wr_max, c3cn->wr_avail); + } + + static int initiate_act_open(struct s3_conn *c3cn, struct net_device *dev) +@@ -1673,9 +1723,17 @@ + goto out_err; + } + +- err = -EPIPE; + if (c3cn->err) { + c3cn_tx_debug("c3cn 0x%p, err %d.\n", c3cn, c3cn->err); ++ err = -EPIPE; ++ goto out_err; ++ } ++ ++ if (c3cn->write_seq - c3cn->snd_una >= cxgb3_snd_win) { ++ c3cn_tx_debug("c3cn 0x%p, snd %u - %u > %u.\n", ++ c3cn, c3cn->write_seq, c3cn->snd_una, ++ cxgb3_snd_win); ++ err = -EAGAIN; + goto out_err; + } + +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_offload.h linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_offload.h +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_offload.h 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_offload.h 2009-01-26 22:00:17.000000000 -0800 +@@ -180,7 +180,7 @@ + * @seq: tcp sequence number + * @ddigest: pdu data digest + * @pdulen: recovered pdu length +- * @ulp_data: scratch area for ULP ++ * @wr_next: scratch area for tx wr + */ + struct cxgb3_skb_cb { + __u8 flags; +@@ -188,7 +188,7 @@ + __u32 seq; + __u32 ddigest; + __u32 pdulen; +- __u8 ulp_data[16]; ++ struct sk_buff *wr_next; + }; + + #define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0])) +@@ -196,7 +196,7 @@ + #define skb_ulp_mode(skb) (CXGB3_SKB_CB(skb)->ulp_mode) + #define skb_ulp_ddigest(skb) (CXGB3_SKB_CB(skb)->ddigest) + #define skb_ulp_pdulen(skb) (CXGB3_SKB_CB(skb)->pdulen) +-#define skb_ulp_data(skb) (CXGB3_SKB_CB(skb)->ulp_data) ++#define skb_wr_next(skb) (CXGB3_SKB_CB(skb)->wr_next) + + enum c3cb_flags { + C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */ +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_ulp2.c +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2009-01-26 22:00:17.000000000 -0800 +@@ -51,6 +51,7 @@ + static unsigned char sw_tag_idx_bits; + static unsigned char sw_tag_age_bits; + static unsigned char page_idx = ULP2_PGIDX_MAX; ++static unsigned int skb_copymax = SKB_MAX_HEAD(TX_HEADER_LEN); + + static void cxgb3i_ddp_page_init(void) + { +@@ -59,6 +60,10 @@ + sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1; + sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1; + ++ cxgb3i_log_info("tag itt 0x%x, %u bits, age 0x%x, %u bits.\n", ++ ISCSI_ITT_MASK, sw_tag_idx_bits, ++ ISCSI_AGE_MASK, sw_tag_age_bits); ++ + for (i = 0; i < ULP2_PGIDX_MAX; i++) { + if (PAGE_SIZE == (1UL << ddp_page_shift[i])) { + page_idx = i; +@@ -312,7 +317,6 @@ + page_idx, sgcnt, xferlen, ULP2_DDP_THRESHOLD); + return RESERVED_ITT; + } +- return RESERVED_ITT; + + gl = ddp_make_gl(xferlen, sgl, sgcnt, gfp); + if (!gl) { +@@ -322,9 +326,9 @@ + } + + npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; +- idx_max = ddp->nppods - npods + 1; ++ idx_max = ddp->nppods - npods; + +- if (ddp->idx_last == ddp->nppods) ++ if (ddp->idx_last >= idx_max) + idx = ddp_find_unused_entries(ddp, 0, idx_max, npods, gl); + else { + idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, idx_max, +@@ -345,12 +349,13 @@ + + if (ddp_gl_map(snic->pdev, gl) < 0) + goto unmap_sgl; +- +- tag = sw_tag | (idx << snic->tag_format.rsvd_shift); ++ ++ tag = cxgb3i_ddp_tag_base(&snic->tag_format, sw_tag); ++ tag |= idx << PPOD_IDX_SHIFT; + + hdr.rsvd = 0; + hdr.vld_tid = htonl(F_PPOD_VALID | V_PPOD_TID(tid)); +- hdr.pgsz_tag_clr = htonl(tag & snic->tag_format.rsvd_tag_mask); ++ hdr.pgsz_tag_clr = htonl(tag & ddp->rsvd_tag_mask); + hdr.maxoffset = htonl(xferlen); + hdr.pgoffset = htonl(gl->offset); + +@@ -372,30 +377,35 @@ + return RESERVED_ITT; + } + +-void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *snic, u32 tag, +- struct scatterlist *sgl, unsigned int sgcnt) ++void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *snic, u32 tag) + { +- u32 idx = (tag >> snic->tag_format.rsvd_shift) & +- snic->tag_format.rsvd_mask; ++ struct cxgb3i_ddp_info *ddp = snic->ddp; ++ u32 idx; + +- if (idx < snic->tag_format.rsvd_mask) { +- struct cxgb3i_ddp_info *ddp = snic->ddp; ++ if (!ddp) { ++ cxgb3i_log_error("release ddp tag 0x%x, ddp NULL.\n", tag); ++ return; ++ } ++ ++ idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask; ++ if (idx < ddp->nppods) { + struct cxgb3i_gather_list *gl = ddp->gl_map[idx]; + unsigned int npods; + + if (!gl || !gl->nelem) { +- cxgb3i_log_warn("release tag 0x%x, idx 0x%x, no gl.\n", +- tag, idx); ++ cxgb3i_log_error("release tag 0x%x, idx 0x%x, no gl.\n", ++ tag, idx); + return; + } + npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; +- + cxgb3i_tag_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n", + tag, idx, npods); + clear_ddp_map(snic, idx, npods); + ddp_unmark_entries(ddp, idx, npods); + ddp_gl_unmap(snic->pdev, gl); +- } ++ } else ++ cxgb3i_log_error("ddp tag 0x%x, idx 0x%x > max 0x%x.\n", ++ tag, idx, ddp->nppods); + } + + int cxgb3i_conn_ulp_setup(struct cxgb3i_conn *cconn, int hcrc, int dcrc) +@@ -403,12 +413,18 @@ + struct iscsi_tcp_conn *tcp_conn = cconn->conn->dd_data; + struct s3_conn *c3cn = (struct s3_conn *)(tcp_conn->sock); + struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field), +- GFP_KERNEL | __GFP_NOFAIL); ++ GFP_KERNEL); + struct cpl_set_tcb_field *req; + u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); + ++ if (!skb) ++ return -ENOMEM; ++ + if (page_idx < ULP2_PGIDX_MAX) + val |= page_idx << 4; ++ else ++ cxgb3i_log_warn("TID 0x%x, host page 0x%lx default to 4K.\n", ++ c3cn->tid, PAGE_SIZE); + + /* set up ulp submode and page size */ + req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); +@@ -476,14 +492,14 @@ + (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ? + ISCSI_SEGMENT_DGST_ERR : 0; + if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { +- cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, " +- "ddp'ed, itt 0x%x.\n", +- skb, hdr->opcode & ISCSI_OPCODE_MASK, +- tcp_conn->in.datalen, hdr->itt); ++ cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, " ++ "ddp'ed, itt 0x%x.\n", ++ skb, hdr->opcode & ISCSI_OPCODE_MASK, ++ tcp_conn->in.datalen, hdr->itt); + segment->total_copied = segment->total_size; + } else { +- cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, " +- "not ddp'ed, itt 0x%x.\n", ++ cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, " ++ "not ddp'ed, itt 0x%x.\n", + skb, hdr->opcode & ISCSI_OPCODE_MASK, + tcp_conn->in.datalen, hdr->itt); + offset += sizeof(struct cpl_iscsi_hdr_norss); +@@ -520,24 +536,141 @@ + skb_ulp_mode(skb) = (ULP_MODE_ISCSI << 4) | submode; + } + ++static int sg_page_coalesce(struct scatterlist *sg, unsigned int offset, ++ unsigned int dlen, skb_frag_t *frags, int frag_max) ++{ ++ unsigned int sglen = sg->length - offset; ++ struct page *page = sg_page(sg); ++ unsigned int datalen = dlen, copy; ++ int i; ++ ++ i = 0; ++ do { ++ if (!sglen) { ++ sg = sg_next(sg); ++ offset = 0; ++ sglen = sg->length; ++ page = sg_page(sg); ++ } ++ copy = min(datalen, sglen); ++ if (i && page == frags[i - 1].page && ++ offset + sg->offset == ++ frags[i - 1].page_offset + frags[i - 1].size) { ++ frags[i - 1].size += copy; ++ } else { ++ if (i >= frag_max) { ++ cxgb3i_log_error("%s, too many pages > %u, " ++ "dlen %u.\n", __func__, ++ frag_max, dlen); ++ return -EINVAL; ++ } ++ ++ frags[i].page = page; ++ frags[i].page_offset = sg->offset + offset; ++ frags[i].size = copy; ++ i++; ++ } ++ datalen -= copy; ++ offset += copy; ++ sglen -= copy; ++ } while (datalen); ++ ++ return i; ++} ++ ++static int copy_frags_to_skb_pages(struct sk_buff *skb, skb_frag_t *frags, ++ int frag_cnt, unsigned int datalen) ++{ ++ struct page *page = NULL; ++ unsigned char *dp; ++ unsigned int pg_left = 0; ++ unsigned int copy_total = 0; ++ int i; ++ ++ for (i = 0; i < frag_cnt; i++, frags++) { ++ while (frags->size) { ++ unsigned char *sp = page_address(frags->page); ++ unsigned int copy; ++ ++ if (!pg_left) { ++ int cnt = skb_shinfo(skb)->nr_frags; ++ ++ if (cnt >= MAX_SKB_FRAGS) { ++ cxgb3i_log_error("%s: pdu data %u.\n", ++ __func__, datalen); ++ return -EINVAL; ++ } ++ page = alloc_page(GFP_ATOMIC); ++ if (!page) ++ return -ENOMEM; ++ dp = page_address(page); ++ pg_left = PAGE_SIZE; ++ ++ copy = min(pg_left, datalen); ++ skb_fill_page_desc(skb, cnt, page, 0, copy); ++ ++ skb->len += copy; ++ skb->data_len += copy; ++ skb->truesize += copy; ++ datalen -= copy; ++ } ++ copy = min(pg_left, frags->size); ++ memcpy(dp, sp + frags->page_offset, copy); ++ ++ frags->size -= copy; ++ frags->page_offset += copy; ++ dp += copy; ++ pg_left -= copy; ++ copy_total += copy; ++ } ++ } ++ ++ return copy_total; ++} ++ + int cxgb3i_conn_ulp2_xmit(struct iscsi_conn *conn) + { +- struct iscsi_tcp_conn *tcp_conn = conn->dd_data; ++ struct cxgb3i_conn *cconn = conn->dd_data; ++ struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; + struct iscsi_segment *hdr_seg = &tcp_conn->out.segment; + struct iscsi_segment *data_seg = &tcp_conn->out.data_segment; + unsigned int hdrlen = hdr_seg->total_size; + unsigned int datalen = data_seg->total_size; + unsigned int padlen = iscsi_padding(datalen); +- unsigned int copymax = SKB_MAX_HEAD(TX_HEADER_LEN); +- unsigned int copylen; ++ unsigned int copylen = hdrlen; ++ unsigned int copy_dlen = 0; + struct sk_buff *skb; + unsigned char *dst; ++ int i, frag_cnt = 0; + int err = -EAGAIN; + +- if (data_seg->data && ((datalen + padlen) < copymax)) +- copylen = hdrlen + datalen + padlen; +- else +- copylen = hdrlen; ++ /* ++ * the whole pdu needs to fit into one skb, make sure we don't overrun ++ * the skb's frag_list. If there are more sg pages than MAX_SKB_FRAGS, ++ * we have to copy the data either to the head or newly allocated ++ * whole new page(s). This could happen if the sg contains a lot of ++ * fragmented data chunks (pages). ++ */ ++ if (datalen) { ++ if (!data_seg->data) { ++ err = sg_page_coalesce(data_seg->sg, ++ data_seg->sg_offset, ++ data_seg->total_size, ++ cconn->frags, ++ TX_PDU_PAGES_MAX); ++ if (err < 0) ++ return err; ++ frag_cnt = err; ++ ++ if (frag_cnt > MAX_SKB_FRAGS || ++ (padlen && frag_cnt + 1 > MAX_SKB_FRAGS)) ++ copy_dlen = datalen + padlen; ++ } else ++ copy_dlen += datalen + padlen; ++ } ++ ++ if (copylen + copy_dlen < skb_copymax) ++ copylen += copy_dlen; + + /* supports max. 16K pdus, so one skb is enough to hold all the data */ + skb = alloc_skb(TX_HEADER_LEN + copylen, GFP_ATOMIC); +@@ -575,70 +708,84 @@ + skb->data_len += datalen; + skb->truesize += datalen; + } +- } else { +- struct scatterlist *sg = data_seg->sg; +- unsigned int offset = data_seg->sg_offset; +- struct page *page = sg_page(sg); +- unsigned int sglen = sg->length - offset; +- +- do { +- int i = skb_shinfo(skb)->nr_frags; +- unsigned int copy; ++ } else if (copy_dlen) { ++ /* need to copy the page fragments */ ++ if (copylen > hdrlen) { ++ skb_frag_t *frag = cconn->frags; + +- if (!sglen) { +- sg = sg_next(sg); +- page = sg_page(sg); +- offset = 0; +- sglen = sg->length; ++ /* data fits in the skb's headroom */ ++ for (i = 0; i < frag_cnt; i++, frag++) { ++ memcpy(dst, ++ page_address(frag->page) + ++ frag->page_offset, ++ frag->size); ++ dst += frag->size; + } +- copy = min(sglen, datalen); +- +- if (i && skb_can_coalesce(skb, i, page, +- sg->offset + offset)) { +- skb_shinfo(skb)->frags[i - 1].size += copy; +- } else { +- get_page(page); +- skb_fill_page_desc(skb, i, page, +- sg->offset + offset, copy); ++ if (padlen) ++ memset(dst, 0, padlen); ++ } else { ++ /* allocate pages to hold the data */ ++ err = copy_frags_to_skb_pages(skb, cconn->frags, ++ frag_cnt, datalen); ++ if (err < 0) { ++ err = -EAGAIN; ++ goto free_skb; + } +- skb->len += copy; +- skb->data_len += copy; +- skb->truesize += copy; +- offset += copy; +- sglen -= copy; +- datalen -= copy; +- } while (datalen); +- } +- +- if (padlen && skb_shinfo(skb)->nr_frags) { +- int idx = skb_shinfo(skb)->nr_frags; +- get_page(pad_page); +- skb_fill_page_desc(skb, idx, pad_page, 0, padlen); +- skb->data_len += padlen; +- skb->truesize += padlen; +- skb->len += padlen; ++ WARN_ON(err != datalen); ++ if (padlen) { ++ skb_frag_t *frag; ++ ++ i = skb_shinfo(skb)->nr_frags; ++ frag = &skb_shinfo(skb)->frags[i]; ++ dst = page_address(frag->page); ++ ++ memset(dst + frag->page_offset + frag->size, ++ 0, padlen); ++ frag->size += padlen; ++ } ++ } ++ } else { ++ /* sg pages fit into frag_list */ ++ for (i = 0; i < frag_cnt; i++) ++ get_page(cconn->frags[i].page); ++ memcpy(skb_shinfo(skb)->frags, cconn->frags, ++ sizeof(skb_frag_t) * frag_cnt); ++ skb_shinfo(skb)->nr_frags = frag_cnt; ++ skb->len += datalen; ++ skb->data_len += datalen; ++ skb->truesize += datalen; ++ ++ if (padlen) { ++ i = skb_shinfo(skb)->nr_frags; ++ get_page(pad_page); ++ skb_fill_page_desc(skb, i, pad_page, 0, padlen); ++ skb->len += padlen; ++ skb->data_len += padlen; ++ skb->truesize += padlen; ++ } + } + + send_pdu: + err = cxgb3i_c3cn_send_pdus((struct s3_conn *)tcp_conn->sock, skb); +- + if (err > 0) { + int pdulen = hdrlen + datalen + padlen; ++ + if (conn->hdrdgst_en) + pdulen += ISCSI_DIGEST_SIZE; + if (datalen && conn->datadgst_en) + pdulen += ISCSI_DIGEST_SIZE; + + hdr_seg->total_copied = hdr_seg->total_size; +- if (datalen) +- data_seg->total_copied = data_seg->total_size; ++ data_seg->total_copied = data_seg->total_size; + conn->txdata_octets += pdulen; + return pdulen; + } + ++free_skb: + kfree_skb(skb); + if (err < 0 && err != -EAGAIN) { +- cxgb3i_log_error("conn 0x%p, xmit err %d.\n", conn, err); ++ cxgb3i_log_error("conn 0x%p, xmit err %d, skb len %u/%u.\n", ++ conn, err, skb->len, skb->data_len); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + return err; + } +@@ -652,6 +799,9 @@ + return -ENOMEM; + memset(page_address(pad_page), 0, PAGE_SIZE); + cxgb3i_ddp_page_init(); ++ cxgb3i_log_info("skb max. frag %u, head %u.\n", ++ (unsigned int)MAX_SKB_FRAGS, ++ (unsigned int)skb_copymax); + return 0; + } + +@@ -720,7 +870,7 @@ + + read_lock(&c3cn->callback_lock); + conn = c3cn->user_data; +- if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) ++ if (conn) + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + read_unlock(&c3cn->callback_lock); + } +@@ -730,7 +880,7 @@ + struct t3cdev *tdev = snic->tdev; + struct cxgb3i_ddp_info *ddp; + struct ulp_iscsi_info uinfo; +- unsigned int ppmax, bits, max_bits; ++ unsigned int ppmax, bits; + int i, err; + + err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo); +@@ -740,26 +890,21 @@ + return err; + } + +- ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT; +- max_bits = min(PPOD_IDX_MAX_SIZE, +- (32 - sw_tag_idx_bits - sw_tag_age_bits)); +- bits = __ilog2_u32(ppmax) + 1; +- if (bits > max_bits) +- bits = max_bits; +- ppmax = (1 << bits) - 1; +- + snic->tx_max_size = min_t(unsigned int, + uinfo.max_txsz, ULP2_MAX_PKT_SIZE); + snic->rx_max_size = min_t(unsigned int, + uinfo.max_rxsz, ULP2_MAX_PKT_SIZE); ++ cxgb3i_log_info("ddp max pkt size: %u/%u,%u, %u/%u,%u.\n", ++ snic->tx_max_size, uinfo.max_txsz, ULP2_MAX_PKT_SIZE, ++ snic->rx_max_size, uinfo.max_rxsz, ULP2_MAX_PKT_SIZE); + +- snic->tag_format.idx_bits = sw_tag_idx_bits; +- snic->tag_format.age_bits = sw_tag_age_bits; +- snic->tag_format.rsvd_bits = bits; +- snic->tag_format.rsvd_shift = PPOD_IDX_SHIFT; +- snic->tag_format.rsvd_mask = (1 << snic->tag_format.rsvd_bits) - 1; +- snic->tag_format.rsvd_tag_mask = +- (1 << (snic->tag_format.rsvd_bits + PPOD_IDX_SHIFT)) - 1; ++ snic->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits; ++ ++ ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT; ++ bits = __ilog2_u32(ppmax) + 1; ++ if (bits > PPOD_IDX_MAX_SIZE) ++ bits = PPOD_IDX_MAX_SIZE; ++ ppmax = (1 << (bits - 1)) - 1; + + ddp = cxgb3i_alloc_big_mem(sizeof(struct cxgb3i_ddp_info) + + ppmax * +@@ -779,12 +924,15 @@ + spin_lock_init(&ddp->map_lock); + ddp->llimit = uinfo.llimit; + ddp->ulimit = uinfo.ulimit; ++ ddp->nppods = ppmax; ++ ddp->idx_last = ppmax; ++ ddp->idx_bits = bits; ++ ddp->idx_mask = (1 << bits) - 1; ++ ddp->rsvd_tag_mask = (1 << (bits + PPOD_IDX_SHIFT)) - 1; + +- uinfo.tagmask = +- snic->tag_format.rsvd_mask << snic->tag_format.rsvd_shift; ++ uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; + for (i = 0; i < ULP2_PGIDX_MAX; i++) + uinfo.pgsz_factor[i] = ddp_page_order[i]; +- + uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT); + + err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); +@@ -794,19 +942,20 @@ + goto free_ppod_map; + } + +- ddp->nppods = ppmax; +- ddp->idx_last = ppmax; +- + tdev->ulp_iscsi = snic->ddp = ddp; + +- cxgb3i_log_info("snic nppods %u (0x%x ~ 0x%x), rsvd shift %u, " +- "bits %u, mask 0x%x, 0x%x, pkt %u,%u.\n", +- ppmax, ddp->llimit, ddp->ulimit, +- snic->tag_format.rsvd_shift, +- snic->tag_format.rsvd_bits, +- snic->tag_format.rsvd_mask, uinfo.tagmask, +- snic->tx_max_size, snic->rx_max_size); ++ cxgb3i_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x.\n", ++ ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits, ++ ddp->idx_mask, ddp->rsvd_tag_mask); + ++ snic->tag_format.rsvd_bits = ddp->idx_bits; ++ snic->tag_format.rsvd_shift = PPOD_IDX_SHIFT; ++ snic->tag_format.rsvd_mask = (1 << snic->tag_format.rsvd_bits) - 1; ++ ++ cxgb3i_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n", ++ snic->tag_format.sw_bits, snic->tag_format.rsvd_bits, ++ snic->tag_format.rsvd_shift, ++ snic->tag_format.rsvd_mask); + return 0; + + free_ppod_map: +diff -uNr linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_ulp2.h +--- linux-2.6.27.11-1.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2009-01-14 15:17:57.000000000 -0800 ++++ linux-2.6.27.11-1.chng/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2009-01-26 22:00:17.000000000 -0800 +@@ -13,7 +13,6 @@ + #ifndef __CXGB3I_ULP2_H__ + #define __CXGB3I_ULP2_H__ + +-#define ULP2_PDU_PAYLOAD_DFLT (16224 - ISCSI_PDU_HEADER_MAX) + #define PPOD_PAGES_MAX 4 + #define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ + +@@ -100,9 +99,6 @@ + #define ULP2_FLAG_DCRC_ERROR 0x20 + #define ULP2_FLAG_PAD_ERROR 0x40 + +-#define ULP2_MAX_PKT_SIZE 16224 +-#define ULP2_MAX_PDU_SIZE 8192 +- + void cxgb3i_conn_closing(struct s3_conn *); + void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); + void cxgb3i_conn_tx_open(struct s3_conn *c3cn); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-fixed-offload-array-size b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-fixed-offload-array-size new file mode 100644 index 000000000..66274fda8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-fixed-offload-array-size @@ -0,0 +1,857 @@ +Subject: cxgb3i - fixed offload wr array size +From: Karen Xie +References: bnc#447409 + +On systems with 64K page size, the size of the wr request array used for calculating # of wrs required per pdu could be too small when scsi buffers are scattered on sector (512 bytes) boundary. This could cause the transmit to stop. + +This patch changed the wr array size to be based on the sector size (512 bytes) instead of page size. It also added logic to coalesce scsi buffers as much as possible when constructing data pdus. + +Signed-off-by: Karen Xie +Signed-off-by: Chandra Seetharaman +Signed-off-by: Hannes Reinecke +--- +diff --git a/drivers/scsi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgb3i/cxgb3i.h +index e3f591f..48bc2ed 100644 +--- a/drivers/scsi/cxgb3i/cxgb3i.h ++++ b/drivers/scsi/cxgb3i/cxgb3i.h +@@ -62,6 +62,25 @@ struct cxgb3i_tag_format { + }; + + /** ++ * struct cxgb3i_gather_list - cxgb3i direct data placement memory ++ * ++ * @tag: ddp tag ++ * @length: total data buffer length ++ * @offset: initial offset to the 1st page ++ * @nelem: # of pages ++ * @pages: pages ++ * @phys_addr: physical address ++ */ ++struct cxgb3i_gather_list { ++ u32 tag; ++ unsigned int length; ++ unsigned int offset; ++ unsigned int nelem; ++ struct page **pages; ++ dma_addr_t phys_addr[0]; ++}; ++ ++/** + * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload + * + * @llimit: lower bound of the page pod memory +@@ -77,7 +96,8 @@ struct cxgb3i_ddp_info { + unsigned int nppods; + unsigned int idx_last; + spinlock_t map_lock; +- u8 *map; ++ struct cxgb3i_gather_list **gl_map; ++ struct sk_buff **gl_skb; + }; + + /** +@@ -119,7 +139,7 @@ struct cxgb3i_adapter { + unsigned int rx_max_size; + + struct cxgb3i_tag_format tag_format; +- struct cxgb3i_ddp_info ddp; ++ struct cxgb3i_ddp_info *ddp; + }; + + /** +@@ -174,6 +194,6 @@ void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *, u32, + struct scatterlist *, unsigned int); + u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *, unsigned int, + u32, unsigned int, struct scatterlist *, +- unsigned int); ++ unsigned int, int); + int cxgb3i_conn_ulp2_xmit(struct iscsi_conn *); + #endif +diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +index 768c872..bc75dff 100644 +--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +@@ -723,14 +723,16 @@ static int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) + struct s3_conn *c3cn = (struct s3_conn *)(tcp_conn->sock); + tag = + cxgb3i_ddp_tag_reserve(snic, c3cn->tid, sw_tag, +- scsi_out(sc)->length, +- scsi_out(sc)->table.sgl, +- scsi_out(sc)->table.nents); ++ scsi_in(sc)->length, ++ scsi_in(sc)->table.sgl, ++ scsi_in(sc)->table.nents, ++ GFP_ATOMIC); + } + if (tag == RESERVED_ITT) + tag = sw_tag | (snic->tag_format.rsvd_mask << + snic->tag_format.rsvd_shift); + *hdr_itt = htonl(tag); ++ + return 0; + } + +@@ -744,8 +746,8 @@ static void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt) + hdr_itt = ntohl(hdr_itt); + if (sc && (sc->sc_data_direction == DMA_FROM_DEVICE)) + cxgb3i_ddp_tag_release(snic, hdr_itt, +- scsi_out(sc)->table.sgl, +- scsi_out(sc)->table.nents); ++ scsi_in(sc)->table.sgl, ++ scsi_in(sc)->table.nents); + } + + /** +diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c +index 8d0b3bf..e3f3008 100644 +--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c +@@ -211,7 +211,8 @@ static unsigned int wrlen __read_mostly; + * in the skb and whether it has any payload in its main body. This maps the + * length of the gather list represented by an skb into the # of necessary WRs. + */ +-static unsigned int skb_wrs[MAX_SKB_FRAGS + 2] __read_mostly; ++#define SKB_WR_LIST_SIZE (16384/512 + 1) ++static unsigned int skb_wrs[SKB_WR_LIST_SIZE + 2] __read_mostly; + + static void s3_init_wr_tab(unsigned int wr_len) + { +@@ -220,7 +221,7 @@ static void s3_init_wr_tab(unsigned int wr_len) + if (skb_wrs[1]) /* already initialized */ + return; + +- for (i = 1; i < ARRAY_SIZE(skb_wrs); i++) { ++ for (i = 1; i < SKB_WR_LIST_SIZE; i++) { + int sgl_len = (3 * i) / 2 + (i & 1); + + sgl_len += 3; +@@ -582,7 +583,6 @@ static inline void make_tx_data_wr(struct s3_conn *c3cn, + V_TX_SHOVE((skb_peek(&c3cn->write_queue) ? 0 : 1))); + + if (!c3cn_flag(c3cn, C3CN_TX_DATA_SENT)) { +- + req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | + V_TX_CPU_IDX(c3cn->qset)); + +@@ -825,7 +825,7 @@ static int s3_push_frames(struct s3_conn *c3cn, int req_completion) + if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) + wrs_needed = 1; + +- WARN_ON(frags >= ARRAY_SIZE(skb_wrs) || wrs_needed < 1); ++ WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1); + + if (c3cn->wr_avail < wrs_needed) + break; +@@ -941,12 +941,23 @@ int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb, int flags) + goto out_err; + + while (skb) { ++ int frags = skb_shinfo(skb)->nr_frags + ++ (skb->len != skb->data_len); ++ + if (unlikely(skb_headroom(skb) < TX_HEADER_LEN)) { + c3cn_tx_debug("c3cn 0x%p, skb head.\n", c3cn); + err = -EINVAL; + goto out_err; + } + ++ if (frags >= SKB_WR_LIST_SIZE) { ++ cxgb3i_log_error("c3cn 0x%p, tx frags %d, len %u,%u.\n", ++ c3cn, skb_shinfo(skb)->nr_frags, ++ skb->len, skb->data_len); ++ err = -EINVAL; ++ goto out_err; ++ } ++ + next = skb->next; + skb->next = NULL; + skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND | C3CB_FLAG_NEED_HDR); +diff --git a/drivers/scsi/cxgb3i/cxgb3i_ulp2.c b/drivers/scsi/cxgb3i/cxgb3i_ulp2.c +index 7b93ba0..fc1d413 100644 +--- a/drivers/scsi/cxgb3i/cxgb3i_ulp2.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_ulp2.c +@@ -45,36 +45,30 @@ + static struct page *pad_page; + + #define ULP2_PGIDX_MAX 4 +-#define ULP2_4K_PAGE_SHIFT 12 +-#define ULP2_4K_PAGE_MASK (~((1UL << ULP2_4K_PAGE_SHIFT) - 1)) +-static unsigned char ddp_page_order[ULP2_PGIDX_MAX]; +-static unsigned long ddp_page_size[ULP2_PGIDX_MAX]; +-static unsigned char ddp_page_shift[ULP2_PGIDX_MAX]; ++#define ULP2_DDP_THRESHOLD 2048 ++static unsigned char ddp_page_order[ULP2_PGIDX_MAX] = {0, 1, 2, 4}; ++static unsigned char ddp_page_shift[ULP2_PGIDX_MAX] = {12, 13, 14, 16}; + static unsigned char sw_tag_idx_bits; + static unsigned char sw_tag_age_bits; ++static unsigned char page_idx = ULP2_PGIDX_MAX; + + static void cxgb3i_ddp_page_init(void) + { + int i; +- unsigned long n = PAGE_SIZE >> ULP2_4K_PAGE_SHIFT; +- +- if (PAGE_SIZE & (~ULP2_4K_PAGE_MASK)) { +- cxgb3i_log_debug("PAGE_SIZE 0x%lx is not multiple of 4K, " +- "ddp disabled.\n", PAGE_SIZE); +- return; +- } +- n = __ilog2_u32(n); +- for (i = 0; i < ULP2_PGIDX_MAX; i++, n++) { +- ddp_page_order[i] = n; +- ddp_page_shift[i] = ULP2_4K_PAGE_SHIFT + n; +- ddp_page_size[i] = 1 << ddp_page_shift[i]; +- cxgb3i_log_debug("%d, order %u, shift %u, size 0x%lx.\n", i, +- ddp_page_order[i], ddp_page_shift[i], +- ddp_page_size[i]); +- } + + sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1; + sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1; ++ ++ for (i = 0; i < ULP2_PGIDX_MAX; i++) { ++ if (PAGE_SIZE == (1UL << ddp_page_shift[i])) { ++ page_idx = i; ++ cxgb3i_log_info("PAGE_SIZE %lu, idx %u.\n", ++ PAGE_SIZE, page_idx); ++ } ++ } ++ ++ if (page_idx == ULP2_PGIDX_MAX) ++ cxgb3i_log_info("PAGE_SIZE %lu, no match.\n", PAGE_SIZE); + } + + static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr) +@@ -91,38 +85,27 @@ static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr) + + static int set_ddp_map(struct cxgb3i_adapter *snic, struct pagepod_hdr *hdr, + unsigned int idx, unsigned int npods, +- struct scatterlist *sgl, unsigned int sgcnt) ++ struct cxgb3i_gather_list *gl) + { +- struct cxgb3i_ddp_info *ddp = &snic->ddp; +- struct scatterlist *sg = sgl; ++ struct cxgb3i_ddp_info *ddp = snic->ddp; + unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; + int i; + +- for (i = 0; i < npods; i++, pm_addr += PPOD_SIZE) { +- struct sk_buff *skb; ++ for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { ++ struct sk_buff *skb = ddp->gl_skb[idx]; + struct pagepod *ppod; +- int j, k; +- skb = +- alloc_skb(sizeof(struct ulp_mem_io) + PPOD_SIZE, +- GFP_ATOMIC); +- if (!skb) { +- cxgb3i_log_debug("skb OMM.\n"); +- return -ENOMEM; +- } +- skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE); ++ int j, pidx; ++ ++ /* hold on to the skb until we clear the ddp mapping */ ++ skb_get(skb); + + ulp_mem_io_set_hdr(skb, pm_addr); + ppod = + (struct pagepod *)(skb->head + sizeof(struct ulp_mem_io)); + memcpy(&(ppod->hdr), hdr, sizeof(struct pagepod)); +- for (j = 0, k = i * 4; j < 5; j++, k++) { +- if (k < sgcnt) { +- ppod->addr[j] = cpu_to_be64(sg_dma_address(sg)); +- if (j < 4) +- sg = sg_next(sg); +- } else +- ppod->addr[j] = 0UL; +- } ++ for (pidx = 4 * i, j = 0; j < 5; ++j, ++pidx) ++ ppod->addr[j] = pidx < gl->nelem ? ++ cpu_to_be64(gl->phys_addr[pidx]) : 0UL; + + skb->priority = CPL_PRIORITY_CONTROL; + cxgb3_ofld_send(snic->tdev, skb); +@@ -133,18 +116,14 @@ static int set_ddp_map(struct cxgb3i_adapter *snic, struct pagepod_hdr *hdr, + static int clear_ddp_map(struct cxgb3i_adapter *snic, unsigned int idx, + unsigned int npods) + { +- struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ struct cxgb3i_ddp_info *ddp = snic->ddp; + unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; + int i; + +- for (i = 0; i < npods; i++, pm_addr += PPOD_SIZE) { +- struct sk_buff *skb; +- skb = +- alloc_skb(sizeof(struct ulp_mem_io) + PPOD_SIZE, +- GFP_ATOMIC); +- if (!skb) +- return -ENOMEM; +- skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE); ++ for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { ++ struct sk_buff *skb = ddp->gl_skb[idx]; ++ ++ ddp->gl_skb[idx] = NULL; + memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE); + ulp_mem_io_set_hdr(skb, pm_addr); + skb->priority = CPL_PRIORITY_CONTROL; +@@ -153,42 +132,80 @@ static int clear_ddp_map(struct cxgb3i_adapter *snic, unsigned int idx, + return 0; + } + +-static int cxgb3i_ddp_sgl_check(struct scatterlist *sgl, unsigned int sgcnt) ++static struct cxgb3i_gather_list *ddp_make_gl(unsigned int xferlen, ++ struct scatterlist *sgl, ++ unsigned int sgcnt, int gfp) + { +- struct scatterlist *sg; +- int i; +- +- /* make sure the sgl is fit for ddp: +- * each has the same page size, and +- * first & last page do not need to be used completely, and +- * the rest of page must be used completely +- */ +- for_each_sg(sgl, sg, sgcnt, i) { +- if ((i && sg->offset) || +- ((i != sgcnt - 1) && +- (sg->length + sg->offset) != PAGE_SIZE)) { +- cxgb3i_tag_debug("sg %u/%u, off %u, len %u.\n", +- i, sgcnt, sg->offset, sg->length); +- return -EINVAL; ++ struct cxgb3i_gather_list *gl; ++ struct scatterlist *sg = sgl; ++ struct page *sgpage = sg_page(sg); ++ unsigned int sglen = sg->length; ++ unsigned int sgoffset = sg->offset; ++ unsigned int npages = (xferlen + sgoffset + PAGE_SIZE - 1) >> ++ PAGE_SHIFT; ++ int i = 1, j = 0; ++ ++ gl = kzalloc(sizeof(struct cxgb3i_gather_list) + ++ npages * (sizeof(dma_addr_t) + sizeof(struct page *)), ++ gfp); ++ if (!gl) ++ return NULL; ++ ++ gl->pages = (struct page **)&gl->phys_addr[npages]; ++ gl->length = xferlen; ++ gl->offset = sgoffset; ++ gl->pages[0] = sgpage; ++ ++ sg = sg_next(sg); ++ while (sg) { ++ struct page *page = sg_page(sg); ++ ++ if (sgpage == page && sg->offset == sgoffset + sglen) ++ sglen += sg->length; ++ else { ++ /* make sure the sgl is fit for ddp: ++ * each has the same page size, and ++ * all of the middle pages are used completely ++ */ ++ if ((j && sgoffset) || ++ ((i != sgcnt - 1) && ++ ((sglen + sgoffset) & ~PAGE_MASK))) ++ goto error_out; ++ ++ j++; ++ if (j == gl->nelem) ++ goto error_out; ++ gl->pages[j] = page; ++ sglen = sg->length; ++ sgoffset = sg->offset; ++ sgpage = page; + } ++ i++; ++ sg = sg_next(sg); + } ++ gl->nelem = ++j; ++ return gl; + +- return 0; ++error_out: ++ kfree(gl); ++ return NULL; + } + + static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp, +- int start, int max, int count) ++ int start, int max, int count, ++ struct cxgb3i_gather_list *gl) + { + unsigned int i, j; + + spin_lock(&ddp->map_lock); + for (i = start; i <= max;) { + for (j = 0; j < count; j++) { +- if (ddp->map[i + j]) ++ if (ddp->gl_map[i + j]) + break; + } + if (j == count) { +- memset(&ddp->map[i], 1, count); ++ for (j = 0; j < count; j++) ++ ddp->gl_map[i + j] = gl; + spin_unlock(&ddp->map_lock); + return i; + } +@@ -202,86 +219,127 @@ static inline void ddp_unmark_entries(struct cxgb3i_ddp_info *ddp, + int start, int count) + { + spin_lock(&ddp->map_lock); +- memset(&ddp->map[start], 0, count); ++ memset(&ddp->gl_map[start], 0, ++ count * sizeof(struct cxgb3i_gather_list *)); + spin_unlock(&ddp->map_lock); + } + +-static inline int sgl_map(struct cxgb3i_adapter *snic, +- struct scatterlist *sgl, unsigned int sgcnt) ++static inline void ddp_free_gl_skb(struct cxgb3i_ddp_info *ddp, ++ int idx, int count) + { +- struct scatterlist *sg; +- int i, err; ++ int i; + +- for_each_sg(sgl, sg, sgcnt, i) { +- err = pci_map_sg(snic->pdev, sg, 1, PCI_DMA_FROMDEVICE); +- if (err <= 0) { +- cxgb3i_tag_debug("sgcnt %d/%u, pci map failed %d.\n", +- i, sgcnt, err); +- return err; ++ for (i = 0; i < count; i++, idx++) ++ if (ddp->gl_skb[idx]) { ++ kfree_skb(ddp->gl_skb[idx]); ++ ddp->gl_skb[idx] = NULL; ++ } ++} ++ ++static inline int ddp_alloc_gl_skb(struct cxgb3i_ddp_info *ddp, ++ int idx, int count, int gfp) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) { ++ struct sk_buff *skb = alloc_skb(sizeof(struct ulp_mem_io) + ++ PPOD_SIZE, gfp); ++ if (skb) { ++ ddp->gl_skb[idx + i] = skb; ++ skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE); ++ } else { ++ ddp_free_gl_skb(ddp, idx, i); ++ return -ENOMEM; + } + } +- return sgcnt; ++ return 0; + } + +-static inline void sgl_unmap(struct cxgb3i_adapter *snic, +- struct scatterlist *sgl, unsigned int sgcnt) ++static inline void ddp_gl_unmap(struct pci_dev *pdev, ++ struct cxgb3i_gather_list *gl) + { +- struct scatterlist *sg; + int i; + +- for_each_sg(sgl, sg, sgcnt, i) { +- if (sg_dma_address(sg)) +- pci_unmap_sg(snic->pdev, sg, 1, PCI_DMA_FROMDEVICE); +- else +- break; ++ for (i = 0; i < gl->nelem; i++) ++ pci_unmap_page(pdev, gl->phys_addr[i], PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++} ++ ++static inline int ddp_gl_map(struct pci_dev *pdev, ++ struct cxgb3i_gather_list *gl) ++{ ++ int i; ++ ++ for (i = 0; i < gl->nelem; i++) { ++ gl->phys_addr[i] = pci_map_page(pdev, gl->pages[i], 0, ++ PAGE_SIZE, ++ PCI_DMA_FROMDEVICE); ++ if (unlikely(pci_dma_mapping_error(pdev, gl->phys_addr[i]))) ++ goto unmap; + } ++ ++ return i; ++ ++unmap: ++ if (i) { ++ unsigned int nelem = gl->nelem; ++ ++ gl->nelem = i; ++ ddp_gl_unmap(pdev, gl); ++ gl->nelem = nelem; ++ } ++ return -ENOMEM; + } + + u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *snic, unsigned int tid, + u32 sw_tag, unsigned int xferlen, +- struct scatterlist *sgl, unsigned int sgcnt) ++ struct scatterlist *sgl, unsigned int sgcnt, ++ int gfp) + { +- struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ struct cxgb3i_ddp_info *ddp = snic->ddp; ++ struct cxgb3i_gather_list *gl; + struct pagepod_hdr hdr; + unsigned int npods; + int idx = -1, idx_max; + u32 tag; +- int err; + +- if (!ddp || !sgcnt || xferlen < PAGE_SIZE) { +- cxgb3i_tag_debug("sgcnt %u, xferlen %u < %lu, NO DDP.\n", +- sgcnt, xferlen, PAGE_SIZE); ++ if (page_idx || !ddp || !sgcnt || xferlen < ULP2_DDP_THRESHOLD) { ++ cxgb3i_tag_debug("pgidx %u, sgcnt %u, xfer %u/%u, NO ddp.\n", ++ page_idx, sgcnt, xferlen, ULP2_DDP_THRESHOLD); + return RESERVED_ITT; + } + +- err = cxgb3i_ddp_sgl_check(sgl, sgcnt); +- if (err < 0) { ++ gl = ddp_make_gl(xferlen, sgl, sgcnt, gfp); ++ if (!gl) { + cxgb3i_tag_debug("sgcnt %u, xferlen %u, SGL check fail.\n", + sgcnt, xferlen); + return RESERVED_ITT; + } + +- npods = (sgcnt + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; ++ npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; + idx_max = ddp->nppods - npods + 1; + + if (ddp->idx_last == ddp->nppods) +- idx = ddp_find_unused_entries(ddp, 0, idx_max, npods); ++ idx = ddp_find_unused_entries(ddp, 0, idx_max, npods, gl); + else { + idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, idx_max, +- npods); ++ npods, gl); + if ((idx < 0) && (ddp->idx_last >= npods)) + idx = ddp_find_unused_entries(ddp, 0, + ddp->idx_last - npods + 1, +- npods); ++ npods, gl); + } + if (idx < 0) { ++ kfree(gl); + cxgb3i_tag_debug("sgcnt %u, xferlen %u, npods %u NO DDP.\n", + sgcnt, xferlen, npods); + return RESERVED_ITT; + } + +- err = sgl_map(snic, sgl, sgcnt); +- if (err < sgcnt) ++ if (ddp_alloc_gl_skb(ddp, idx, npods, gfp) < 0) ++ goto unmark_entries; ++ ++ if (ddp_gl_map(snic->pdev, gl) < 0) + goto unmap_sgl; + + tag = sw_tag | (idx << snic->tag_format.rsvd_shift); +@@ -290,9 +348,9 @@ u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *snic, unsigned int tid, + hdr.vld_tid = htonl(F_PPOD_VALID | V_PPOD_TID(tid)); + hdr.pgsz_tag_clr = htonl(tag & snic->tag_format.rsvd_tag_mask); + hdr.maxoffset = htonl(xferlen); +- hdr.pgoffset = htonl(sgl->offset); ++ hdr.pgoffset = htonl(gl->offset); + +- if (set_ddp_map(snic, &hdr, idx, npods, sgl, sgcnt) < 0) ++ if (set_ddp_map(snic, &hdr, idx, npods, gl) < 0) + goto unmap_sgl; + + ddp->idx_last = idx; +@@ -301,7 +359,9 @@ u32 cxgb3i_ddp_tag_reserve(struct cxgb3i_adapter *snic, unsigned int tid, + return tag; + + unmap_sgl: +- sgl_unmap(snic, sgl, sgcnt); ++ ddp_gl_unmap(snic->pdev, gl); ++ ddp_free_gl_skb(ddp, idx, npods); ++unmark_entries: + ddp_unmark_entries(ddp, idx, npods); + return RESERVED_ITT; + } +@@ -311,14 +371,18 @@ void cxgb3i_ddp_tag_release(struct cxgb3i_adapter *snic, u32 tag, + { + u32 idx = (tag >> snic->tag_format.rsvd_shift) & + snic->tag_format.rsvd_mask; +- unsigned int npods = (sgcnt + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; + + if (idx < snic->tag_format.rsvd_mask) { ++ struct cxgb3i_ddp_info *ddp = snic->ddp; ++ struct cxgb3i_gather_list *gl = ddp->gl_map[idx]; ++ unsigned int npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> ++ PPOD_PAGES_SHIFT; ++ + cxgb3i_tag_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n", + tag, idx, npods); + clear_ddp_map(snic, idx, npods); +- ddp_unmark_entries(&snic->ddp, idx, npods); +- sgl_unmap(snic, sgl, sgcnt); ++ ddp_unmark_entries(ddp, idx, npods); ++ ddp_gl_unmap(snic->pdev, gl); + } + } + +@@ -330,6 +394,7 @@ int cxgb3i_conn_ulp_setup(struct cxgb3i_conn *cconn, int hcrc, int dcrc) + GFP_KERNEL | __GFP_NOFAIL); + struct cpl_set_tcb_field *req; + u32 submode = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); ++ u32 pgcode = page_idx < ULP2_PGIDX_MAX ? page_idx : 0; + + /* set up ulp submode and page size */ + req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); +@@ -339,8 +404,7 @@ int cxgb3i_conn_ulp_setup(struct cxgb3i_conn *cconn, int hcrc, int dcrc) + req->cpu_idx = 0; + req->word = htons(31); + req->mask = cpu_to_be64(0xFF000000); +- /* the connection page size is always the same as ddp-pgsz0 */ +- req->val = cpu_to_be64(submode << 24); ++ req->val = cpu_to_be64(((pgcode << 4) | submode) << 24); + skb->priority = CPL_PRIORITY_CONTROL; + + cxgb3_ofld_send(c3cn->cdev, skb); +@@ -397,13 +461,15 @@ static int cxgb3i_conn_read_pdu_skb(struct iscsi_conn *conn, + segment->status = (conn->datadgst_en && + (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ? + ISCSI_SEGMENT_DGST_ERR : 0; +- if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { +- cxgb3i_ddp_debug("opcode 0x%x, data %u, ddp'ed.\n", +- hdr->opcode & ISCSI_OPCODE_MASK, +- tcp_conn->in.datalen); ++ if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) + segment->total_copied = segment->total_size; +- } else ++ else { ++ cxgb3i_ddp_debug("opcode 0x%x, data %u, NOT ddp'ed, " ++ "itt 0x%x.\n", ++ hdr->opcode & ISCSI_OPCODE_MASK, ++ tcp_conn->in.datalen, hdr->itt); + offset += sizeof(struct cpl_iscsi_hdr_norss); ++ } + + while (segment->total_copied < segment->total_size) { + iscsi_tcp_segment_map(segment, 1); +@@ -481,67 +547,64 @@ int cxgb3i_conn_ulp2_xmit(struct iscsi_conn *conn) + if (padlen) + memset(dst, 0, padlen); + } else { +- unsigned int offset = 0; +- while (datalen) { +- struct page *page = alloc_page(GFP_ATOMIC); +- int idx = skb_shinfo(skb)->nr_frags; +- skb_frag_t *frag = &skb_shinfo(skb)->frags[idx]; +- +- if (!page) +- goto free_skb; +- +- frag->page = page; +- frag->page_offset = 0; +- if (datalen > PAGE_SIZE) +- frag->size = PAGE_SIZE; +- else +- frag->size = datalen; +- memcpy(page_address(page), +- data_seg->data + offset, frag->size); +- +- skb_shinfo(skb)->nr_frags++; +- datalen -= frag->size; +- offset += frag->size; +- } ++ struct page *pg = virt_to_page(data_seg->data); ++ ++ get_page(pg); ++ skb_fill_page_desc(skb, 0, pg, ++ offset_in_page(data_seg->data), ++ datalen); ++ skb->len += datalen; ++ skb->data_len += datalen; ++ skb->truesize += datalen; + } + } else { + struct scatterlist *sg = data_seg->sg; + unsigned int offset = data_seg->sg_offset; +- while (datalen) { +- int idx = skb_shinfo(skb)->nr_frags; +- skb_frag_t *frag = &skb_shinfo(skb)->frags[idx]; +- struct page *pg = sg_page(sg); +- +- get_page(pg); +- frag->page = pg; +- frag->page_offset = offset + sg->offset; +- frag->size = min(sg->length, datalen); +- +- offset = 0; +- skb_shinfo(skb)->nr_frags++; +- datalen -= frag->size; +- sg = sg_next(sg); +- } ++ struct page *page = sg_page(sg); ++ unsigned int sglen = sg->length - offset; ++ ++ do { ++ int i = skb_shinfo(skb)->nr_frags; ++ unsigned int copy; ++ ++ if (!sglen) { ++ sg = sg_next(sg); ++ page = sg_page(sg); ++ offset = 0; ++ sglen = sg->length; ++ } ++ copy = min(sglen, datalen); ++ ++ if (i && skb_can_coalesce(skb, i, page, ++ sg->offset + offset)) { ++ skb_shinfo(skb)->frags[i - 1].size += copy; ++ } else { ++ get_page(page); ++ skb_fill_page_desc(skb, i, page, ++ sg->offset + offset, copy); ++ } ++ skb->len += copy; ++ skb->data_len += copy; ++ skb->truesize += copy; ++ offset += copy; ++ sglen -= copy; ++ datalen -= copy; ++ } while (datalen); + } + +- if (skb_shinfo(skb)->nr_frags) { +- if (padlen) { +- int idx = skb_shinfo(skb)->nr_frags; +- skb_frag_t *frag = &skb_shinfo(skb)->frags[idx]; +- frag->page = pad_page; +- frag->page_offset = 0; +- frag->size = padlen; +- skb_shinfo(skb)->nr_frags++; +- } +- datalen = data_seg->total_size + padlen; +- skb->data_len += datalen; +- skb->truesize += datalen; +- skb->len += datalen; ++ if (padlen && skb_shinfo(skb)->nr_frags) { ++ int idx = skb_shinfo(skb)->nr_frags; ++ get_page(pad_page); ++ skb_fill_page_desc(skb, idx, pad_page, 0, padlen); ++ skb->data_len += padlen; ++ skb->truesize += padlen; ++ skb->len += padlen; + } + + send_pdu: + err = cxgb3i_c3cn_send_pdus((struct s3_conn *)tcp_conn->sock, + skb, MSG_DONTWAIT | MSG_NOSIGNAL); ++ + if (err > 0) { + int pdulen = hdrlen + datalen + padlen; + if (conn->hdrdgst_en) +@@ -556,7 +619,6 @@ send_pdu: + return pdulen; + } + +-free_skb: + kfree_skb(skb); + if (err < 0 && err != -EAGAIN) { + cxgb3i_log_error("conn 0x%p, xmit err %d.\n", conn, err); +@@ -649,13 +711,11 @@ void cxgb3i_conn_closing(struct s3_conn *c3cn) + int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *snic) + { + struct t3cdev *tdev = snic->tdev; +- struct cxgb3i_ddp_info *ddp = &snic->ddp; ++ struct cxgb3i_ddp_info *ddp; + struct ulp_iscsi_info uinfo; + unsigned int ppmax, bits, max_bits; + int i, err; + +- spin_lock_init(&ddp->map_lock); +- + err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo); + if (err < 0) { + cxgb3i_log_error("%s, failed to get iscsi param err=%d.\n", +@@ -684,12 +744,21 @@ int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *snic) + snic->tag_format.rsvd_tag_mask = + (1 << (snic->tag_format.rsvd_bits + PPOD_IDX_SHIFT)) - 1; + +- ddp->map = cxgb3i_alloc_big_mem(ppmax); +- if (!ddp->map) { +- cxgb3i_log_warn("snic unable to alloc ddp ppod 0x%u, " +- "ddp disabled.\n", ppmax); ++ ddp = cxgb3i_alloc_big_mem(sizeof(struct cxgb3i_ddp_info) + ++ ppmax * ++ (sizeof(struct cxgb3i_gather_list *) + ++ sizeof(struct sk_buff *))); ++ if (!ddp) { ++ cxgb3i_log_warn("snic %s unable to alloc ddp ppod 0x%u, " ++ "ddp disabled.\n", tdev->name, ppmax); + return 0; + } ++ ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1); ++ ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) + ++ ppmax * ++ sizeof(struct cxgb3i_gather_list *)); ++ ++ spin_lock_init(&ddp->map_lock); + ddp->llimit = uinfo.llimit; + ddp->ulimit = uinfo.ulimit; + +@@ -710,7 +779,7 @@ int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *snic) + ddp->nppods = ppmax; + ddp->idx_last = ppmax; + +- tdev->ulp_iscsi = ddp; ++ tdev->ulp_iscsi = snic->ddp = ddp; + + cxgb3i_log_info("snic nppods %u (0x%x ~ 0x%x), rsvd shift %u, " + "bits %u, mask 0x%x, 0x%x, pkt %u,%u.\n", +@@ -723,19 +792,33 @@ int cxgb3i_adapter_ulp_init(struct cxgb3i_adapter *snic) + return 0; + + free_ppod_map: +- cxgb3i_free_big_mem(ddp->map); ++ cxgb3i_free_big_mem(ddp); + return 0; + } + + void cxgb3i_adapter_ulp_cleanup(struct cxgb3i_adapter *snic) + { +- u8 *map = snic->ddp.map; ++ struct cxgb3i_ddp_info *ddp = snic->ddp; ++ ++ if (ddp) { ++ int i = 0; + +- if (map) { + snic->tdev->ulp_iscsi = NULL; + spin_lock(&snic->lock); +- snic->ddp.map = NULL; ++ snic->ddp = NULL; + spin_unlock(&snic->lock); +- cxgb3i_free_big_mem(map); ++ ++ while (i < ddp->nppods) { ++ struct cxgb3i_gather_list *gl = ddp->gl_map[i]; ++ if (gl) { ++ int npods = (gl->nelem + PPOD_PAGES_MAX - 1) ++ >> PPOD_PAGES_SHIFT; ++ ++ kfree(gl); ++ ddp_free_gl_skb(ddp, i, npods); ++ } else ++ i++; ++ } ++ cxgb3i_free_big_mem(ddp); + } + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-mainline.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-mainline.patch new file mode 100644 index 000000000..a945cf0cf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i-mainline.patch @@ -0,0 +1,3871 @@ +Subject: fixes bug in tag release and sync-up cxgb3i with mainline state +From: Karen Xie +References: 464508 - LTC50816 + +This patch fixes the tag generation and release and also updates the tcp connection offload to sync-up with the current kernel.org version. + +Signed-off-by: Karen Xie +Signed-off-by: Olaf Hering + +--- + drivers/scsi/cxgb3i/cxgb3i_init.c | 4 + drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 99 - + drivers/scsi/cxgb3i/cxgb3i_offload.c | 2615 +++++++++++++++-------------------- + drivers/scsi/cxgb3i/cxgb3i_offload.h | 251 +-- + drivers/scsi/cxgb3i/cxgb3i_ulp2.c | 25 + drivers/scsi/cxgb3i/cxgb3i_ulp2.h | 23 + 6 files changed, 1429 insertions(+), 1588 deletions(-) + +--- a/drivers/scsi/cxgb3i/cxgb3i_init.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_init.c +@@ -12,7 +12,7 @@ + #include "cxgb3i.h" + + #define DRV_MODULE_NAME "cxgb3i" +-#define DRV_MODULE_VERSION "1.0.0" ++#define DRV_MODULE_VERSION "0.1.0" + #define DRV_MODULE_RELDATE "Jun. 1, 2008" + + static char version[] = +@@ -48,7 +48,6 @@ static void open_s3_dev(struct t3cdev *t + vers_printed = 1; + } + +- cxgb3i_log_debug("open cxgb3 %s.\n", t3dev->name); + cxgb3i_sdev_add(t3dev, &t3c_client); + cxgb3i_adapter_add(t3dev); + } +@@ -59,7 +58,6 @@ static void open_s3_dev(struct t3cdev *t + */ + static void close_s3_dev(struct t3cdev *t3dev) + { +- cxgb3i_log_debug("close cxgb3 %s.\n", t3dev->name); + cxgb3i_adapter_remove(t3dev); + cxgb3i_sdev_remove(t3dev); + } +--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +@@ -24,6 +24,18 @@ + #include "cxgb3i.h" + #include "cxgb3i_ulp2.h" + ++#ifdef __DEBUG_CXGB3I_TAG__ ++#define cxgb3i_tag_debug cxgb3i_log_debug ++#else ++#define cxgb3i_tag_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_CXGB3I_API__ ++#define cxgb3i_api_debug cxgb3i_log_debug ++#else ++#define cxgb3i_api_debug(fmt...) ++#endif ++ + #define align_to_4k_boundary(n) \ + do { \ + n = (n) & ~((1 << 12) - 1); \ +@@ -48,7 +60,7 @@ struct cxgb3i_adapter *cxgb3i_adapter_ad + + snic = kzalloc(sizeof(*snic), GFP_KERNEL); + if (!snic) { +- cxgb3i_log_debug("cxgb3 %s, OOM.\n", t3dev->name); ++ cxgb3i_api_debug("cxgb3 %s, OOM.\n", t3dev->name); + return NULL; + } + +@@ -164,7 +176,7 @@ struct cxgb3i_hba *cxgb3i_hba_host_add(s + goto pci_dev_put; + } + +- cxgb3i_log_debug("shost 0x%p, hba 0x%p, no %u.\n", ++ cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n", + shost, hba, shost->host_no); + + return hba; +@@ -177,7 +189,7 @@ pci_dev_put: + + void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba) + { +- cxgb3i_log_debug("shost 0x%p, hba 0x%p, no %u.\n", ++ cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n", + hba->shost, hba, hba->shost->host_no); + iscsi_host_remove(hba->shost); + pci_dev_put(hba->snic->pdev); +@@ -218,7 +230,7 @@ static struct iscsi_endpoint *cxgb3i_ep_ + cxgb3i_log_info("NOT going through cxgbi device.\n"); + goto release_conn; + } +- if (c3cn_in_state(c3cn, C3CN_STATE_CLOSE)) { ++ if (c3cn_is_closing(c3cn)) { + err = -ENOSPC; + cxgb3i_log_info("ep connect unable to connect.\n"); + goto release_conn; +@@ -234,12 +246,12 @@ static struct iscsi_endpoint *cxgb3i_ep_ + cep->c3cn = c3cn; + cep->hba = hba; + +- cxgb3i_log_debug("ep 0x%p, 0x%p, c3cn 0x%p, hba 0x%p.\n", ++ cxgb3i_api_debug("ep 0x%p, 0x%p, c3cn 0x%p, hba 0x%p.\n", + ep, cep, c3cn, hba); + return ep; + + release_conn: +- cxgb3i_log_debug("conn 0x%p failed, release.\n", c3cn); ++ cxgb3i_api_debug("conn 0x%p failed, release.\n", c3cn); + if (c3cn) + cxgb3i_c3cn_release(c3cn); + return ERR_PTR(err); +@@ -257,9 +269,9 @@ static int cxgb3i_ep_poll(struct iscsi_e + struct cxgb3i_endpoint *cep = ep->dd_data; + struct s3_conn *c3cn = cep->c3cn; + +- if (!c3cn_in_state(c3cn, C3CN_STATE_ESTABLISHED)) ++ if (!c3cn_is_established(c3cn)) + return 0; +- cxgb3i_log_debug("ep 0x%p, c3cn 0x%p established.\n", ep, c3cn); ++ cxgb3i_api_debug("ep 0x%p, c3cn 0x%p established.\n", ep, c3cn); + return 1; + } + +@@ -274,7 +286,7 @@ static void cxgb3i_ep_disconnect(struct + struct cxgb3i_endpoint *cep = ep->dd_data; + struct cxgb3i_conn *cconn = cep->cconn; + +- cxgb3i_log_debug("ep 0x%p, cep 0x%p.\n", ep, cep); ++ cxgb3i_api_debug("ep 0x%p, cep 0x%p.\n", ep, cep); + + if (cconn && cconn->conn) { + struct iscsi_tcp_conn *tcp_conn = &cconn->tcp_conn; +@@ -291,7 +303,7 @@ static void cxgb3i_ep_disconnect(struct + write_unlock_bh(&cep->c3cn->callback_lock); + } + +- cxgb3i_log_debug("ep 0x%p, cep 0x%p, release c3cn 0x%p.\n", ++ cxgb3i_api_debug("ep 0x%p, cep 0x%p, release c3cn 0x%p.\n", + ep, cep, cep->c3cn); + cxgb3i_c3cn_release(cep->c3cn); + iscsi_destroy_endpoint(ep); +@@ -325,7 +337,7 @@ cxgb3i_session_create(struct iscsi_endpo + cep = ep->dd_data; + hba = cep->hba; + shost = hba->shost; +- cxgb3i_log_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba); ++ cxgb3i_api_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba); + BUG_ON(hba != iscsi_host_priv(shost)); + + *host_no = shost->host_no; +@@ -364,7 +376,7 @@ remove_session: + */ + static void cxgb3i_session_destroy(struct iscsi_cls_session *cls_session) + { +- cxgb3i_log_debug("sess 0x%p.\n", cls_session); ++ cxgb3i_api_debug("sess 0x%p.\n", cls_session); + iscsi_r2tpool_free(cls_session->dd_data); + iscsi_session_teardown(cls_session); + } +@@ -380,10 +392,10 @@ static inline int cxgb3i_conn_max_xmit_d + { + struct cxgb3i_conn *cconn = conn->dd_data; + unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE, +- cconn->hba->snic->tx_max_size - +- ISCSI_PDU_HEADER_MAX); ++ cconn->hba->snic->tx_max_size - ++ ISCSI_PDU_HEADER_MAX); + +- cxgb3i_log_debug("conn 0x%p, max xmit %u.\n", ++ cxgb3i_api_debug("conn 0x%p, max xmit %u.\n", + conn, conn->max_xmit_dlength); + + if (conn->max_xmit_dlength) +@@ -394,7 +406,7 @@ static inline int cxgb3i_conn_max_xmit_d + + align_to_4k_boundary(conn->max_xmit_dlength); + +- cxgb3i_log_debug("conn 0x%p, set max xmit %u.\n", ++ cxgb3i_api_debug("conn 0x%p, set max xmit %u.\n", + conn, conn->max_xmit_dlength); + + return 0; +@@ -404,18 +416,18 @@ static inline int cxgb3i_conn_max_recv_d + { + struct cxgb3i_conn *cconn = conn->dd_data; + unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE, +- cconn->hba->snic->rx_max_size - +- ISCSI_PDU_HEADER_MAX); ++ cconn->hba->snic->rx_max_size - ++ ISCSI_PDU_HEADER_MAX); + +- cxgb3i_log_debug("conn 0x%p, max recv %u.\n", ++ cxgb3i_api_debug("conn 0x%p, max recv %u.\n", + conn, conn->max_recv_dlength); + + align_to_4k_boundary(max); + + if (conn->max_recv_dlength) { + if (conn->max_recv_dlength > max) { +- cxgb3i_log_error("MaxRecvDataSegmentLength %u, not supported." +- "Need to be <= %u.\n", ++ cxgb3i_log_error("MaxRecvDataSegmentLength %u, not " ++ "supported. Need to be <= %u.\n", + conn->max_recv_dlength, max); + return -EINVAL; + } +@@ -425,7 +437,7 @@ static inline int cxgb3i_conn_max_recv_d + } else + conn->max_recv_dlength = max; + +- cxgb3i_log_debug("conn 0x%p, set max recv %u.\n", ++ cxgb3i_api_debug("conn 0x%p, set max recv %u.\n", + conn, conn->max_recv_dlength); + + return 0; +@@ -438,7 +450,7 @@ static struct iscsi_cls_conn *cxgb3i_con + struct iscsi_conn *conn; + struct cxgb3i_conn *cconn; + +- cxgb3i_log_debug("sess 0x%p, cid %u.\n", cls_session, cid); ++ cxgb3i_api_debug("sess 0x%p, cid %u.\n", cls_session, cid); + + cls_conn = iscsi_conn_setup(cls_session, sizeof(*cconn), cid); + if (!cls_conn) +@@ -495,7 +507,7 @@ static int cxgb3i_conn_bind(struct iscsi + if (!ep) + return -EINVAL; + +- cxgb3i_log_debug("ep 0x%p, cls sess 0x%p, cls conn 0x%p.\n", ++ cxgb3i_api_debug("ep 0x%p, cls sess 0x%p, cls conn 0x%p.\n", + ep, cls_session, cls_conn); + + err = iscsi_conn_bind(cls_session, cls_conn, is_leading); +@@ -544,7 +556,7 @@ static int cxgb3i_conn_get_param(struct + struct iscsi_conn *conn = cls_conn->dd_data; + int len; + +- cxgb3i_log_debug("cls_conn 0x%p, param %d.\n", cls_conn, param); ++ cxgb3i_api_debug("cls_conn 0x%p, param %d.\n", cls_conn, param); + + switch (param) { + case ISCSI_PARAM_CONN_PORT: +@@ -621,15 +633,22 @@ static int cxgb3i_host_set_param(struct + { + struct cxgb3i_hba *hba = iscsi_host_priv(shost); + +- cxgb3i_log_debug("param %d, buf %s.\n", param, buf); ++ cxgb3i_api_debug("param %d, buf %s.\n", param, buf); + +- if (hba && param == ISCSI_HOST_PARAM_IPADDRESS) { ++ switch (param) { ++ case ISCSI_HOST_PARAM_IPADDRESS: ++ { + __be32 addr = in_aton(buf); + cxgb3i_set_private_ipv4addr(hba->ndev, addr); + return 0; + } +- +- return iscsi_host_get_param(shost, param, buf); ++ case ISCSI_HOST_PARAM_HWADDRESS: ++ case ISCSI_HOST_PARAM_NETDEV_NAME: ++ /* ignore */ ++ return 0; ++ default: ++ return iscsi_host_set_param(shost, param, buf, buflen); ++ } + } + + /** +@@ -645,7 +664,7 @@ static int cxgb3i_host_get_param(struct + int i; + int len = 0; + +- cxgb3i_log_debug("hba %s, param %d.\n", hba->ndev->name, param); ++ cxgb3i_api_debug("hba %s, param %d.\n", hba->ndev->name, param); + + switch (param) { + case ISCSI_HOST_PARAM_HWADDRESS: +@@ -720,6 +739,10 @@ static inline void cxgb3i_parse_tag(stru + << format->rsvd_shift; + *sw_bits |= tag & ((1 << format->rsvd_shift) - 1); + } ++ ++ cxgb3i_tag_debug("parse tag 0x%x, rsvd 0x%x, sw 0x%x.\n", ++ tag, rsvd_bits ? *rsvd_bits : 0xFFFFFFFF, ++ sw_bits ? *sw_bits : 0xFFFFFFFF); + } + + +@@ -735,6 +758,9 @@ static void cxgb3i_parse_itt(struct iscs + *idx = sw_bits & ISCSI_ITT_MASK; + if (age) + *age = (sw_bits >> snic->tag_format.idx_bits) & ISCSI_AGE_MASK; ++ ++ cxgb3i_tag_debug("parse itt 0x%x, idx 0x%x, age 0x%x.\n", ++ itt, idx ? *idx : 0xFFFFF, age ? *age : 0xFF); + } + + static int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) +@@ -762,6 +788,9 @@ static int cxgb3i_reserve_itt(struct isc + snic->tag_format.rsvd_shift); + *hdr_itt = htonl(tag); + ++ cxgb3i_tag_debug("new tag 0x%x/0x%x (itt 0x%x, age 0x%x).\n", ++ tag, *hdr_itt, task->itt, sess->age); ++ + return 0; + } + +@@ -771,10 +800,12 @@ static void cxgb3i_release_itt(struct is + struct iscsi_conn *conn = task->conn; + struct cxgb3i_conn *cconn = conn->dd_data; + struct cxgb3i_adapter *snic = cconn->hba->snic; ++ u32 tag = ntohl(hdr_itt); ++ ++ cxgb3i_tag_debug("release tag 0x%x.\n", tag); + +- hdr_itt = ntohl(hdr_itt); + if (sc && (sc->sc_data_direction == DMA_FROM_DEVICE)) +- cxgb3i_ddp_tag_release(snic, hdr_itt, ++ cxgb3i_ddp_tag_release(snic, tag, + scsi_in(sc)->table.sgl, + scsi_in(sc)->table.nents); + } +@@ -871,14 +902,14 @@ int cxgb3i_iscsi_init(void) + cxgb3i_log_error("Could not register cxgb3i transport.\n"); + return -ENODEV; + } +- cxgb3i_log_debug("cxgb3i transport 0x%p.\n", cxgb3i_scsi_transport); ++ cxgb3i_api_debug("cxgb3i transport 0x%p.\n", cxgb3i_scsi_transport); + return 0; + } + + void cxgb3i_iscsi_cleanup(void) + { + if (cxgb3i_scsi_transport) { +- cxgb3i_log_debug("cxgb3i transport 0x%p.\n", ++ cxgb3i_api_debug("cxgb3i transport 0x%p.\n", + cxgb3i_scsi_transport); + iscsi_unregister_transport(&cxgb3i_iscsi_transport); + } +--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c +@@ -1,12 +1,15 @@ + /* +- * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. ++ * cxgb3i_offload.c: Chelsio S3xx iscsi offloaded tcp connection management + * +- * Written by Dimitris Michailidis (dm@chelsio.com) ++ * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this + * release for licensing terms and conditions. ++ * ++ * Written by: Dimitris Michailidis (dm@chelsio.com) ++ * Karen Xie (kxie@chelsio.com) + */ + + #include +@@ -18,6 +21,27 @@ + #include "cxgb3i_offload.h" + #include "cxgb3i_ulp2.h" + ++#ifdef __DEBUG_C3CN_CONN__ ++#define c3cn_conn_debug cxgb3i_log_debug ++#else ++#define c3cn_conn_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_C3CN_TX__ ++#define c3cn_tx_debug cxgb3i_log_debug ++#else ++#define c3cn_tx_debug(fmt...) ++#endif ++ ++#ifdef __DEBUG_C3CN_RX__ ++#define c3cn_rx_debug cxgb3i_log_debug ++#else ++#define c3cn_rx_debug(fmt...) ++#endif ++ ++/* ++ * module parameters releated to offloaded iscsi connection ++ */ + static int cxgb3_rcv_win = 256 * 1024; + module_param(cxgb3_rcv_win, int, 0644); + MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=256KB)"); +@@ -39,30 +63,91 @@ static unsigned int cxgb3_sport_base = 2 + module_param(cxgb3_sport_base, uint, 0644); + MODULE_PARM_DESC(cxgb3_sport_base, "starting port number (default=20000)"); + +-#ifdef __DEBUG_C3CN_TX__ +-#define c3cn_tx_debug cxgb3i_log_debug +-#else +-#define c3cn_tx_debug(fmt...) +-#endif ++/* ++ * cxgb3i tcp connection data(per adapter) list ++ */ ++static LIST_HEAD(cdata_list); ++static DEFINE_RWLOCK(cdata_rwlock); + +-#ifdef __DEBUG_C3CN_RX__ +-#define c3cn_rx_debug cxgb3i_log_debug +-#else +-#define c3cn_rx_debug(fmt...) +-#endif ++static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion); ++static void c3cn_release_offload_resources(struct s3_conn *c3cn); ++ ++/* ++ * iscsi source port management ++ * ++ * Find a free source port in the port allocation map. We use a very simple ++ * rotor scheme to look for the next free port. ++ * ++ * If a source port has been specified make sure that it doesn't collide with ++ * our normal source port allocation map. If it's outside the range of our ++ * allocation/deallocation scheme just let them use it. ++ * ++ * If the source port is outside our allocation range, the caller is ++ * responsible for keeping track of their port usage. ++ */ ++static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata) ++{ ++ unsigned int start; ++ int idx; ++ ++ if (!cdata) ++ goto error_out; ++ ++ if (c3cn->saddr.sin_port != 0) { ++ idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; ++ if (idx < 0 || idx >= cxgb3_max_connect) ++ return 0; ++ if (!test_and_set_bit(idx, cdata->sport_map)) ++ return -EADDRINUSE; ++ } ++ ++ /* the sport_map_next may not be accurate but that is okay, sport_map ++ should be */ ++ start = idx = cdata->sport_map_next; ++ do { ++ if (++idx >= cxgb3_max_connect) ++ idx = 0; ++ if (!(test_and_set_bit(idx, cdata->sport_map))) { ++ c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx); ++ cdata->sport_map_next = idx; ++ c3cn_conn_debug("%s reserve port %u.\n", ++ cdata->cdev->name, ++ cxgb3_sport_base + idx); ++ return 0; ++ } ++ } while (idx != start); ++ ++error_out: ++ return -EADDRNOTAVAIL; ++} ++ ++static void c3cn_put_port(struct s3_conn *c3cn) ++{ ++ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev); ++ ++ if (c3cn->saddr.sin_port) { ++ int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; ++ ++ c3cn->saddr.sin_port = 0; ++ if (idx < 0 || idx >= cxgb3_max_connect) ++ return; ++ clear_bit(idx, cdata->sport_map); ++ c3cn_conn_debug("%s, release port %u.\n", ++ cdata->cdev->name, cxgb3_sport_base + idx); ++ } ++} + +-/* connection flags */ + static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag) + { + __set_bit(flag, &c3cn->flags); +- c3cn_conn_debug("c3cn 0x%p, set %d, s 0x%x, f 0x%lx.\n", ++ c3cn_conn_debug("c3cn 0x%p, set %d, s %u, f 0x%lx.\n", + c3cn, flag, c3cn->state, c3cn->flags); + } + +-static inline void c3cn_reset_flag(struct s3_conn *c3cn, enum c3cn_flags flag) ++static inline void c3cn_clear_flag(struct s3_conn *c3cn, enum c3cn_flags flag) + { + __clear_bit(flag, &c3cn->flags); +- c3cn_conn_debug("c3cn 0x%p, clear %d, s 0x%x, f 0x%lx.\n", ++ c3cn_conn_debug("c3cn 0x%p, clear %d, s %u, f 0x%lx.\n", + c3cn, flag, c3cn->state, c3cn->flags); + } + +@@ -73,14 +158,12 @@ static inline int c3cn_flag(struct s3_co + return test_bit(flag, &c3cn->flags); + } + +-/* connection state */ + static void c3cn_set_state(struct s3_conn *c3cn, int state) + { +- c3cn_conn_debug("c3cn 0x%p state -> 0x%x.\n", c3cn, state); ++ c3cn_conn_debug("c3cn 0x%p state -> %u.\n", c3cn, state); + c3cn->state = state; + } + +-/* connection reference count */ + static inline void c3cn_hold(struct s3_conn *c3cn) + { + atomic_inc(&c3cn->refcnt); +@@ -89,432 +172,316 @@ static inline void c3cn_hold(struct s3_c + static inline void c3cn_put(struct s3_conn *c3cn) + { + if (atomic_dec_and_test(&c3cn->refcnt)) { +- c3cn_conn_debug("free c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn_conn_debug("free c3cn 0x%p, s %u, f 0x%lx.\n", + c3cn, c3cn->state, c3cn->flags); + kfree(c3cn); + } + } + +-/* minimal port allocation management scheme */ +-static spinlock_t sport_map_lock; +-static unsigned int sport_map_next; +-static unsigned long *sport_map; ++static void c3cn_closed(struct s3_conn *c3cn) ++{ ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ c3cn_put_port(c3cn); ++ c3cn_release_offload_resources(c3cn); ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSED); ++ cxgb3i_conn_closing(c3cn); ++} ++ ++/* ++ * CPL (Chelsio Protocol Language) defines a message passing interface between ++ * the host driver and T3 asic. ++ * The section below implments CPLs that related to iscsi tcp connection ++ * open/close/abort and data send/receive. ++ */ + + /* +- * Find a free source port in our allocation map. We use a very simple rotor +- * scheme to look for the next free port. +- * +- * If a source port has been specified make sure that it doesn't collide with +- * our normal source port allocation map. If it's outside the range of our +- * allocation scheme just let them use it. ++ * CPL connection active open request: host -> + */ +-static int c3cn_get_port(struct s3_conn *c3cn) ++static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu) + { +- unsigned int start; ++ int i = 0; + +- if (!sport_map) +- goto error_out; ++ while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu) ++ ++i; ++ return i; ++} + +- if (c3cn->saddr.sin_port != 0) { +- int sport = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; +- int err = 0; ++static unsigned int select_mss(struct s3_conn *c3cn, unsigned int pmtu) ++{ ++ unsigned int idx; ++ struct dst_entry *dst = c3cn->dst_cache; ++ struct t3cdev *cdev = c3cn->cdev; ++ const struct t3c_data *td = T3C_DATA(cdev); ++ u16 advmss = dst_metric(dst, RTAX_ADVMSS); + +- if (sport < 0 || sport >= cxgb3_max_connect) +- return 0; +- spin_lock(&sport_map_lock); +- err = __test_and_set_bit(sport, sport_map); +- spin_unlock(&sport_map_lock); +- return err ? -EADDRINUSE : 0; +- } ++ if (advmss > pmtu - 40) ++ advmss = pmtu - 40; ++ if (advmss < td->mtus[0] - 40) ++ advmss = td->mtus[0] - 40; ++ idx = find_best_mtu(td, advmss + 40); ++ return idx; ++} + +- spin_lock(&sport_map_lock); +- start = sport_map_next; +- do { +- unsigned int new = sport_map_next; +- if (++sport_map_next >= cxgb3_max_connect) +- sport_map_next = 0; +- if (!(__test_and_set_bit(new, sport_map))) { +- spin_unlock(&sport_map_lock); +- c3cn_conn_debug("reserve port %u.\n", +- cxgb3_sport_base + new); +- c3cn->saddr.sin_port = htons(cxgb3_sport_base + new); +- return 0; +- } +- } while (sport_map_next != start); +- spin_unlock(&sport_map_lock); ++static inline int compute_wscale(int win) ++{ ++ int wscale = 0; ++ while (wscale < 14 && (65535<mss_idx); + } + +-/* +- * Deallocate a source port from the allocation map. If the source port is +- * outside our allocation range just return -- the caller is responsible for +- * keeping track of their port usage outside of our allocation map. +- */ +-static void c3cn_put_port(struct s3_conn *c3cn) ++static inline unsigned int calc_opt0l(struct s3_conn *c3cn) + { +- if (c3cn->saddr.sin_port) { +- int old = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base; +- c3cn->saddr.sin_port = 0; ++ return V_ULP_MODE(ULP_MODE_ISCSI) | ++ V_RCV_BUFSIZ(cxgb3_rcv_win>>10); ++} + +- if (old < 0 || old >= cxgb3_max_connect) +- return; ++static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb, ++ unsigned int atid, const struct l2t_entry *e) ++{ ++ struct cpl_act_open_req *req; + +- c3cn_conn_debug("release port %u.\n", cxgb3_sport_base + old); +- spin_lock(&sport_map_lock); +- __clear_bit(old, sport_map); +- spin_unlock(&sport_map_lock); +- } ++ c3cn_conn_debug("c3cn 0x%p, atid 0x%x.\n", c3cn, atid); ++ ++ skb->priority = CPL_PRIORITY_SETUP; ++ req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid)); ++ req->local_port = c3cn->saddr.sin_port; ++ req->peer_port = c3cn->daddr.sin_port; ++ req->local_ip = c3cn->saddr.sin_addr.s_addr; ++ req->peer_ip = c3cn->daddr.sin_addr.s_addr; ++ req->opt0h = htonl(calc_opt0h(c3cn) | V_L2T_IDX(e->idx) | ++ V_TX_CHANNEL(e->smt_idx)); ++ req->opt0l = htonl(calc_opt0l(c3cn)); ++ req->params = 0; + } + +-static void c3cn_reset_timer(struct s3_conn *c3cn, struct timer_list *timer, +- unsigned long expires) ++static void fail_act_open(struct s3_conn *c3cn, int errno) + { +- if (!mod_timer(timer, expires)) +- c3cn_hold(c3cn); ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ c3cn->err = errno; ++ c3cn_closed(c3cn); + } + +-typedef int (cxgb3_cpl_handler_decl) (struct t3cdev *, +- struct sk_buff *, void *); +- +-static cxgb3_cpl_handler_decl do_act_establish; +-static cxgb3_cpl_handler_decl do_act_open_rpl; +-static cxgb3_cpl_handler_decl do_wr_ack; +-static cxgb3_cpl_handler_decl do_peer_close; +-static cxgb3_cpl_handler_decl do_abort_req; +-static cxgb3_cpl_handler_decl do_abort_rpl; +-static cxgb3_cpl_handler_decl do_close_con_rpl; +-static cxgb3_cpl_handler_decl do_iscsi_hdr; ++static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb) ++{ ++ struct s3_conn *c3cn = (struct s3_conn *)skb->sk; + +-static LIST_HEAD(cxgb3_list); +-static DEFINE_MUTEX(cxgb3_list_lock); ++ c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state); + +-/* +- * For ULP connections HW may inserts digest bytes into the pdu. This array +- * contains the compensating extra lengths for ULP packets. It is indexed by +- * a packet's ULP submode. +- */ +-static const unsigned int cxgb3_ulp_extra_len[] = { 0, 4, 4, 8 }; ++ c3cn_hold(c3cn); ++ spin_lock_bh(&c3cn->lock); ++ if (c3cn->state == C3CN_STATE_CONNECTING) ++ fail_act_open(c3cn, EHOSTUNREACH); ++ spin_unlock_bh(&c3cn->lock); ++ c3cn_put(c3cn); ++ __kfree_skb(skb); ++} + + /* +- * Return the length of any HW additions that will be made to a Tx packet. +- * Such additions can happen for some types of ULP packets. ++ * CPL connection close request: host -> ++ * ++ * Close a connection by sending a CPL_CLOSE_CON_REQ message and queue it to ++ * the write queue (i.e., after any unsent txt data). + */ +-static inline unsigned int ulp_extra_len(const struct sk_buff *skb) ++static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb, ++ int flags) + { +- return cxgb3_ulp_extra_len[skb_ulp_mode(skb) & 3]; ++ CXGB3_SKB_CB(skb)->seq = c3cn->write_seq; ++ CXGB3_SKB_CB(skb)->flags = flags; ++ __skb_queue_tail(&c3cn->write_queue, skb); + } + +-/* +- * Size of WRs in bytes. Note that we assume all devices we are handling have +- * the same WR size. +- */ +-static unsigned int wrlen __read_mostly; +- +-/* +- * The number of WRs needed for an skb depends on the number of page fragments +- * in the skb and whether it has any payload in its main body. This maps the +- * length of the gather list represented by an skb into the # of necessary WRs. +- */ +-#define SKB_WR_LIST_SIZE (16384/512 + 1) +-static unsigned int skb_wrs[SKB_WR_LIST_SIZE + 2] __read_mostly; +- +-static void s3_init_wr_tab(unsigned int wr_len) ++static void send_close_req(struct s3_conn *c3cn) + { +- int i; ++ struct sk_buff *skb = c3cn->cpl_close; ++ struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; ++ unsigned int tid = c3cn->tid; + +- if (skb_wrs[1]) /* already initialized */ +- return; ++ c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); + +- for (i = 1; i < SKB_WR_LIST_SIZE; i++) { +- int sgl_len = (3 * i) / 2 + (i & 1); ++ c3cn->cpl_close = NULL; + +- sgl_len += 3; +- skb_wrs[i] = (sgl_len <= wr_len +- ? 1 : 1 + (sgl_len - 2) / (wr_len - 1)); +- } ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); ++ req->wr.wr_lo = htonl(V_WR_TID(tid)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); ++ req->rsvd = htonl(c3cn->write_seq); + +- wrlen = wr_len * 8; ++ skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND); ++ if (c3cn->state != C3CN_STATE_CONNECTING) ++ c3cn_push_tx_frames(c3cn, 1); + } + + /* +- * cxgb3i API operations. +- */ +-/* +- * large memory chunk allocation/release ++ * CPL connection abort request: host -> ++ * ++ * Send an ABORT_REQ message. Makes sure we do not send multiple ABORT_REQs ++ * for the same connection and also that we do not try to send a message ++ * after the connection has closed. + */ +-void *cxgb3i_alloc_big_mem(unsigned int size) ++static void abort_arp_failure(struct t3cdev *cdev, struct sk_buff *skb) + { +- void *p = kmalloc(size, GFP_KERNEL); +- if (!p) +- p = vmalloc(size); +- if (p) +- memset(p, 0, size); +- return p; +-} ++ struct cpl_abort_req *req = cplhdr(skb); + +-void cxgb3i_free_big_mem(void *addr) +-{ +- if (is_vmalloc_addr(addr)) +- vfree(addr); +- else +- kfree(addr); +-} ++ c3cn_conn_debug("tdev 0x%p.\n", cdev); + +-void cxgb3i_sdev_cleanup(void) +-{ +- if (sport_map) +- cxgb3i_free_big_mem(sport_map); ++ req->cmd = CPL_ABORT_NO_RST; ++ cxgb3_ofld_send(cdev, skb); + } + +-int cxgb3i_sdev_init(cxgb3_cpl_handler_func *cpl_handlers) ++static inline void c3cn_purge_write_queue(struct s3_conn *c3cn) + { +- cpl_handlers[CPL_ACT_ESTABLISH] = do_act_establish; +- cpl_handlers[CPL_ACT_OPEN_RPL] = do_act_open_rpl; +- cpl_handlers[CPL_PEER_CLOSE] = do_peer_close; +- cpl_handlers[CPL_ABORT_REQ_RSS] = do_abort_req; +- cpl_handlers[CPL_ABORT_RPL_RSS] = do_abort_rpl; +- cpl_handlers[CPL_CLOSE_CON_RPL] = do_close_con_rpl; +- cpl_handlers[CPL_TX_DMA_ACK] = do_wr_ack; +- cpl_handlers[CPL_ISCSI_HDR] = do_iscsi_hdr; ++ struct sk_buff *skb; + +- if (cxgb3_max_connect > CXGB3I_MAX_CONN) +- cxgb3_max_connect = CXGB3I_MAX_CONN; +- sport_map = cxgb3i_alloc_big_mem(DIV_ROUND_UP(cxgb3_max_connect, +- 8 * +- sizeof(unsigned long))); +- if (!sport_map) +- return -ENOMEM; +- return 0; ++ while ((skb = __skb_dequeue(&c3cn->write_queue))) ++ __kfree_skb(skb); + } + +-void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) ++static void send_abort_req(struct s3_conn *c3cn) + { +- struct cxgb3i_sdev_data *cdata; +- struct adap_ports *ports; +- struct ofld_page_info rx_page_info; +- unsigned int wr_len; +- int i; ++ struct sk_buff *skb = c3cn->cpl_abort_req; ++ struct cpl_abort_req *req; ++ unsigned int tid = c3cn->tid; + +- cdata = kzalloc(sizeof *cdata, GFP_KERNEL); +- if (!cdata) ++ if (unlikely(c3cn->state == C3CN_STATE_ABORTING) || !skb || ++ !c3cn->cdev) + return; +- ports = kzalloc(sizeof *ports, GFP_KERNEL); +- if (!ports) +- goto free_ports; +- cdata->ports = ports; +- +- if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || +- cdev->ctl(cdev, GET_PORTS, cdata->ports) < 0 || +- cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) +- goto free_ports; + +- s3_init_wr_tab(wr_len); ++ c3cn_set_state(c3cn, C3CN_STATE_ABORTING); + +- INIT_LIST_HEAD(&cdata->list); +- cdata->cdev = cdev; +- cdata->client = client; +- cdata->rx_page_size = rx_page_info.page_size; +- skb_queue_head_init(&cdata->deferq); ++ c3cn_conn_debug("c3cn 0x%p, flag ABORT_RPL + ABORT_SHUT.\n", c3cn); + +- for (i = 0; i < ports->nports; i++) +- NDEV2CDATA(ports->lldevs[i]) = cdata; ++ c3cn_set_flag(c3cn, C3CN_ABORT_RPL_PENDING); + +- mutex_lock(&cxgb3_list_lock); +- list_add_tail(&cdata->list, &cxgb3_list); +- mutex_unlock(&cxgb3_list_lock); ++ /* Purge the send queue so we don't send anything after an abort. */ ++ c3cn_purge_write_queue(c3cn); + +- return; ++ c3cn->cpl_abort_req = NULL; ++ req = (struct cpl_abort_req *)skb->head; + +-free_ports: +- kfree(ports); +- kfree(cdata); +-} ++ skb->priority = CPL_PRIORITY_DATA; ++ set_arp_failure_handler(skb, abort_arp_failure); + +-void cxgb3i_sdev_remove(struct t3cdev *cdev) +-{ +- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); +- struct adap_ports *ports = cdata->ports; +- int i; +- +- for (i = 0; i < ports->nports; i++) +- NDEV2CDATA(ports->lldevs[i]) = NULL; +- +- mutex_lock(&cxgb3_list_lock); +- list_del(&cdata->list); +- mutex_unlock(&cxgb3_list_lock); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); ++ req->wr.wr_lo = htonl(V_WR_TID(tid)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, tid)); ++ req->rsvd0 = htonl(c3cn->snd_nxt); ++ req->rsvd1 = !c3cn_flag(c3cn, C3CN_TX_DATA_SENT); ++ req->cmd = CPL_ABORT_SEND_RST; + +- kfree(ports); +- kfree(cdata); ++ l2t_send(c3cn->cdev, skb, c3cn->l2t); + } + + /* +- * Return TRUE if the specified net device is for a port on one of our +- * registered adapters. ++ * CPL connection abort reply: host -> ++ * ++ * Send an ABORT_RPL message in response of the ABORT_REQ received. + */ +-static int is_cxgb3_dev(struct net_device *dev) ++static void send_abort_rpl(struct s3_conn *c3cn, int rst_status) + { +- struct cxgb3i_sdev_data *cdata; ++ struct sk_buff *skb = c3cn->cpl_abort_rpl; ++ struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; + +- mutex_lock(&cxgb3_list_lock); +- list_for_each_entry(cdata, &cxgb3_list, list) { +- struct adap_ports *ports = cdata->ports; +- int i; ++ c3cn->cpl_abort_rpl = NULL; + +- for (i = 0; i < ports->nports; i++) +- if (dev == ports->lldevs[i]) { +- mutex_unlock(&cxgb3_list_lock); +- return 1; +- } +- } +- mutex_unlock(&cxgb3_list_lock); +- return 0; ++ skb->priority = CPL_PRIORITY_DATA; ++ rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); ++ rpl->wr.wr_lo = htonl(V_WR_TID(c3cn->tid)); ++ OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, c3cn->tid)); ++ rpl->cmd = rst_status; ++ ++ cxgb3_ofld_send(c3cn->cdev, skb); + } + + /* +- * Primary cxgb3 API operations. +- * ============================= ++ * CPL connection rx data ack: host -> ++ * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of ++ * credits sent. + */ +- +-static int s3_push_frames(struct s3_conn *, int); +-static int s3_send_reset(struct s3_conn *, int, struct sk_buff *); +-static void t3_release_offload_resources(struct s3_conn *); +-static void mk_close_req(struct s3_conn *); +- +-struct s3_conn *cxgb3i_c3cn_create(void) ++static u32 send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack) + { +- struct s3_conn *c3cn; +- +- c3cn = kzalloc(sizeof(*c3cn), GFP_KERNEL); +- if (c3cn == NULL) +- return NULL; +- +- c3cn_conn_debug("alloc c3cn 0x%p.\n", c3cn); ++ struct sk_buff *skb; ++ struct cpl_rx_data_ack *req; + +- c3cn->flags = 0; +- spin_lock_init(&c3cn->lock); +- atomic_set(&c3cn->refcnt, 1); +- skb_queue_head_init(&c3cn->receive_queue); +- skb_queue_head_init(&c3cn->write_queue); +- setup_timer(&c3cn->retry_timer, NULL, (unsigned long)c3cn); +- rwlock_init(&c3cn->callback_lock); ++ skb = alloc_skb(sizeof(*req), GFP_ATOMIC); ++ if (!skb) ++ return 0; + +- return c3cn; ++ req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req)); ++ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); ++ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid)); ++ req->credit_dack = htonl(dack | V_RX_CREDITS(credits)); ++ skb->priority = CPL_PRIORITY_ACK; ++ cxgb3_ofld_send(c3cn->cdev, skb); ++ return credits; + } + +-static inline void s3_purge_write_queue(struct s3_conn *c3cn) +-{ +- struct sk_buff *skb; +- +- while ((skb = __skb_dequeue(&c3cn->write_queue))) +- __kfree_skb(skb); +-} ++/* ++ * CPL connection tx data: host -> ++ * ++ * Send iscsi PDU via TX_DATA CPL message. Returns the number of ++ * credits sent. ++ * Each TX_DATA consumes work request credit (wrs), so we need to keep track of ++ * how many we've used so far and how many are pending (i.e., yet ack'ed by T3). ++ */ + +-static void c3cn_done(struct s3_conn *c3cn) ++/* ++ * For ULP connections HW may inserts digest bytes into the pdu. Those digest ++ * bytes are not sent by the host but are part of the TCP payload and therefore ++ * consume TCP sequence space. ++ */ ++static const unsigned int cxgb3_ulp_extra_len[] = { 0, 4, 4, 8 }; ++static inline unsigned int ulp_extra_len(const struct sk_buff *skb) + { +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- +- c3cn_put_port(c3cn); +- t3_release_offload_resources(c3cn); +- c3cn_set_state(c3cn, C3CN_STATE_CLOSE); +- c3cn->shutdown = C3CN_SHUTDOWN_MASK; +- cxgb3i_conn_closing(c3cn); ++ return cxgb3_ulp_extra_len[skb_ulp_mode(skb) & 3]; + } + +-static void c3cn_close(struct s3_conn *c3cn) +-{ +- int data_lost, old_state; +- +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- +- dst_confirm(c3cn->dst_cache); +- +- spin_lock_bh(&c3cn->lock); +- c3cn->shutdown |= C3CN_SHUTDOWN_MASK; +- +- /* +- * We need to flush the receive buffs. We do this only on the +- * descriptor close, not protocol-sourced closes, because the +- * reader process may not have drained the data yet! Make a note +- * of whether any received data will be lost so we can decide whether +- * to FIN or RST. +- */ +- data_lost = skb_queue_len(&c3cn->receive_queue); +- __skb_queue_purge(&c3cn->receive_queue); +- +- if (c3cn->state == C3CN_STATE_CLOSE) +- /* Nothing if we are already closed */ +- c3cn_conn_debug("c3cn 0x%p, 0x%x, already closed.\n", +- c3cn, c3cn->state); +- else if (data_lost || c3cn->state == C3CN_STATE_SYN_SENT) { +- c3cn_conn_debug("c3cn 0x%p, 0x%x -> closing, send reset.\n", +- c3cn, c3cn->state); +- /* Unread data was tossed, zap the connection. */ +- s3_send_reset(c3cn, CPL_ABORT_SEND_RST, NULL); +- goto unlock; +- } else if (c3cn->state == C3CN_STATE_ESTABLISHED) { +- c3cn_conn_debug("c3cn 0x%p, est. -> closing, send close_req.\n", +- c3cn); +- c3cn_set_state(c3cn, C3CN_STATE_CLOSING); +- mk_close_req(c3cn); +- } +- +-unlock: +- old_state = c3cn->state; +- c3cn_hold(c3cn); /* must last past the potential destroy() */ ++static unsigned int wrlen __read_mostly; + +- spin_unlock_bh(&c3cn->lock); ++/* ++ * The number of WRs needed for an skb depends on the number of fragments ++ * in the skb and whether it has any payload in its main body. This maps the ++ * length of the gather list represented by an skb into the # of necessary WRs. ++ * ++ * The max. length of an skb is controlled by the max pdu size which is ~16K. ++ * Also, assume the min. fragment length is the sector size (512), then add ++ * extra fragment counts for iscsi bhs and payload padding. ++ */ ++#define SKB_WR_LIST_SIZE (16384/512 + 3) ++static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly; + +- /* +- * There are no more user references at this point. Grab the +- * connection lock and finish the close. +- */ +- local_bh_disable(); +- spin_lock(&c3cn->lock); ++static void s3_init_wr_tab(unsigned int wr_len) ++{ ++ int i; + +- /* +- * Because the connection was orphaned before the spin_lock() +- * either the backlog or a BH may have already destroyed it. +- * Bail out if so. +- */ +- if (old_state != C3CN_STATE_CLOSE && c3cn->state == C3CN_STATE_CLOSE) +- goto out; ++ if (skb_wrs[1]) /* already initialized */ ++ return; + +- if (c3cn->state == C3CN_STATE_CLOSE) +- s3_purge_write_queue(c3cn); ++ for (i = 1; i < SKB_WR_LIST_SIZE; i++) { ++ int sgl_len = (3 * i) / 2 + (i & 1); + +-out: +- spin_unlock(&c3cn->lock); +- local_bh_enable(); +- c3cn_put(c3cn); +-} ++ sgl_len += 3; ++ skb_wrs[i] = (sgl_len <= wr_len ++ ? 1 : 1 + (sgl_len - 2) / (wr_len - 1)); ++ } + +-void cxgb3i_c3cn_release(struct s3_conn *c3cn) +-{ +- c3cn_conn_debug("c3cn 0x%p, s 0x%x, f 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- if (likely(c3cn->state != C3CN_STATE_SYN_SENT)) +- c3cn_close(c3cn); +- else +- c3cn_set_flag(c3cn, C3CN_CLOSE_NEEDED); +- c3cn_put(c3cn); ++ wrlen = wr_len * 8; + } + +- +-/* +- * Local utility routines used to implement primary cxgb3 API operations. +- * ====================================================================== +- */ +- +-static u32 s3_send_rx_credits(struct s3_conn *, u32, u32, int); +-static int act_open(struct s3_conn *, struct net_device *); +-static void mk_act_open_req(struct s3_conn *, struct sk_buff *, +- unsigned int, const struct l2t_entry *); +-static void skb_entail(struct s3_conn *, struct sk_buff *, int); +- + static inline void reset_wr_list(struct s3_conn *c3cn) + { + c3cn->wr_pending_head = NULL; +@@ -532,7 +499,7 @@ static inline void enqueue_wr(struct s3_ + + /* + * We want to take an extra reference since both us and the driver +- * need to free the packet before it's really freed. We know there's ++ * need to free the packet before it's really freed. We know there's + * just one user currently so we use atomic_set rather than skb_get + * to avoid the atomic op. + */ +@@ -545,34 +512,37 @@ static inline void enqueue_wr(struct s3_ + c3cn->wr_pending_tail = skb; + } + +-/* +- * The next two functions calculate the option 0 value for a connection. +- */ +-static inline int compute_wscale(int win) ++static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn) + { +- int wscale = 0; +- while (wscale < 14 && (65535<wr_pending_head; + } + +-static inline unsigned int calc_opt0h(struct s3_conn *c3cn) ++static inline void free_wr_skb(struct sk_buff *skb) + { +- int wscale = compute_wscale(cxgb3_rcv_win); +- return V_KEEP_ALIVE(1) | +- F_TCAM_BYPASS | +- V_WND_SCALE(wscale) | +- V_MSS_IDX(c3cn->mss_idx); ++ kfree_skb(skb); + } + +-static inline unsigned int calc_opt0l(struct s3_conn *c3cn) ++static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn) + { +- return V_ULP_MODE(ULP_MODE_ISCSI) | +- V_RCV_BUFSIZ(cxgb3_rcv_win>>10); ++ struct sk_buff *skb = c3cn->wr_pending_head; ++ ++ if (likely(skb)) { ++ /* Don't bother clearing the tail */ ++ c3cn->wr_pending_head = (struct sk_buff *)skb->sp; ++ skb->sp = NULL; ++ } ++ return skb; ++} ++ ++static void purge_wr_queue(struct s3_conn *c3cn) ++{ ++ struct sk_buff *skb; ++ while ((skb = dequeue_wr(c3cn)) != NULL) ++ free_wr_skb(skb); + } + +-static inline void make_tx_data_wr(struct s3_conn *c3cn, +- struct sk_buff *skb, int len) ++static inline void make_tx_data_wr(struct s3_conn *c3cn, struct sk_buff *skb, ++ int len) + { + struct tx_data_wr *req; + +@@ -591,250 +561,63 @@ static inline void make_tx_data_wr(struc + if (!c3cn_flag(c3cn, C3CN_TX_DATA_SENT)) { + req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | + V_TX_CPU_IDX(c3cn->qset)); +- +- /* Sendbuffer is in units of 32KB. +- */ ++ /* Sendbuffer is in units of 32KB. */ + req->param |= htonl(V_TX_SNDBUF(cxgb3_snd_win >> 15)); + c3cn_set_flag(c3cn, C3CN_TX_DATA_SENT); + } + } + + /** +- * cxgb3_egress_dev - return the cxgb3 egress device +- * @root_dev: the root device anchoring the search +- * @c3cn: the connection used to determine egress port in bonding mode +- * @context: in bonding mode, indicates a connection set up or failover ++ * c3cn_push_tx_frames -- start transmit ++ * @c3cn: the offloaded connection ++ * @req_completion: request wr_ack or not + * +- * Return egress device or NULL if the egress device isn't one of our ports. +- * +- * Given a root network device it returns the physical egress device that is a +- * descendant of the root device. The root device may be either a physical +- * device, in which case it is the device returned, or a virtual device, such +- * as a VLAN or bonding device. In case of a bonding device the search +- * considers the decisions of the bonding device given its mode to locate the +- * correct egress device. ++ * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a ++ * connection's send queue and sends them on to T3. Must be called with the ++ * connection's lock held. Returns the amount of send buffer space that was ++ * freed as a result of sending queued data to T3. + */ +-static struct net_device *cxgb3_egress_dev(struct net_device *root_dev, +- struct s3_conn *c3cn, +- int context) +-{ +- while (root_dev) { +- if (root_dev->priv_flags & IFF_802_1Q_VLAN) +- root_dev = vlan_dev_real_dev(root_dev); +- else if (is_cxgb3_dev(root_dev)) +- return root_dev; +- else +- return NULL; +- } +- return NULL; +-} +- +-static struct rtable *find_route(__be32 saddr, __be32 daddr, +- __be16 sport, __be16 dport) ++static void arp_failure_discard(struct t3cdev *cdev, struct sk_buff *skb) + { +- struct rtable *rt; +- struct flowi fl = { +- .oif = 0, +- .nl_u = { +- .ip4_u = { +- .daddr = daddr, +- .saddr = saddr, +- .tos = 0 } }, +- .proto = IPPROTO_TCP, +- .uli_u = { +- .ports = { +- .sport = sport, +- .dport = dport } } }; +- +- if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0)) +- return NULL; +- return rt; ++ kfree_skb(skb); + } + +-int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) ++static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion) + { +- struct rtable *rt; +- struct net_device *dev; +- struct cxgb3i_sdev_data *cdata; ++ int total_size = 0; ++ struct sk_buff *skb; + struct t3cdev *cdev; +- __be32 sipv4; +- int err; ++ struct cxgb3i_sdev_data *cdata; + +- if (usin->sin_family != AF_INET) +- return -EAFNOSUPPORT; ++ if (unlikely(c3cn->state == C3CN_STATE_CONNECTING || ++ c3cn->state == C3CN_STATE_CLOSE_WAIT_1 || ++ c3cn->state == C3CN_STATE_ABORTING)) { ++ c3cn_tx_debug("c3cn 0x%p, in closing state %u.\n", ++ c3cn, c3cn->state); ++ return 0; ++ } + +- /* get a source port if one hasn't been provided */ +- err = c3cn_get_port(c3cn); +- if (err) +- return err; ++ cdev = c3cn->cdev; ++ cdata = CXGB3_SDEV_DATA(cdev); + +- c3cn_conn_debug("c3cn 0x%p get port %u.\n", +- c3cn, ntohs(c3cn->saddr.sin_port)); ++ while (c3cn->wr_avail ++ && (skb = skb_peek(&c3cn->write_queue)) != NULL) { ++ int len = skb->len; /* length before skb_push */ ++ int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len); ++ int wrs_needed = skb_wrs[frags]; + +- c3cn->daddr.sin_port = usin->sin_port; +- c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; ++ if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) ++ wrs_needed = 1; + +- rt = find_route(c3cn->saddr.sin_addr.s_addr, +- c3cn->daddr.sin_addr.s_addr, +- c3cn->saddr.sin_port, +- c3cn->daddr.sin_port); +- if (rt == NULL) { +- c3cn_conn_debug("NO route to 0x%x, port %u.\n", +- c3cn->daddr.sin_addr.s_addr, +- ntohs(c3cn->daddr.sin_port)); +- return -ENETUNREACH; +- } ++ WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1); + +- if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { +- c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n", +- c3cn->daddr.sin_addr.s_addr, +- ntohs(c3cn->daddr.sin_port)); +- ip_rt_put(rt); +- return -ENETUNREACH; +- } +- +- if (!c3cn->saddr.sin_addr.s_addr) +- c3cn->saddr.sin_addr.s_addr = rt->rt_src; +- +- /* now commit destination to connection */ +- c3cn->dst_cache = &rt->u.dst; +- +- /* try to establish an offloaded connection */ +- dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0); +- if (dev == NULL) { +- c3cn_conn_debug("c3cn 0x%p, egress dev NULL.\n", c3cn); +- return -ENETUNREACH; +- } +- cdata = NDEV2CDATA(dev); +- cdev = cdata->cdev; +- +- sipv4 = cxgb3i_get_private_ipv4addr(dev); +- if (!sipv4) { +- c3cn_conn_debug("c3cn 0x%p, iscsi ip not configured.\n", c3cn); +- sipv4 = c3cn->saddr.sin_addr.s_addr; +- cxgb3i_set_private_ipv4addr(dev, sipv4); +- } else +- c3cn->saddr.sin_addr.s_addr = sipv4; +- +- c3cn_conn_debug("c3cn 0x%p, %u.%u.%u.%u,%u-%u.%u.%u.%u,%u SYN_SENT.\n", +- c3cn, NIPQUAD(c3cn->saddr.sin_addr.s_addr), +- ntohs(c3cn->saddr.sin_port), +- NIPQUAD(c3cn->daddr.sin_addr.s_addr), +- ntohs(c3cn->daddr.sin_port)); +- +- c3cn_set_state(c3cn, C3CN_STATE_SYN_SENT); +- +- if (!act_open(c3cn, dev)) +- return 0; +- +- /* +- * If we get here, we don't have an offload connection so simply +- * return a failure. +- */ +- err = -ENOTSUPP; +- +- /* +- * This trashes the connection and releases the local port, +- * if necessary. +- */ +- c3cn_conn_debug("c3cn 0x%p -> CLOSE.\n", c3cn); +- c3cn_set_state(c3cn, C3CN_STATE_CLOSE); +- ip_rt_put(rt); +- c3cn_put_port(c3cn); +- c3cn->daddr.sin_port = 0; +- return err; +-} +- +-/* +- * Set of states for which we should return RX credits. +- */ +-#define CREDIT_RETURN_STATE (C3CN_STATE_ESTABLISHED) +- +-/* +- * Called after some received data has been read. It returns RX credits +- * to the HW for the amount of data processed. +- */ +-void cxgb3i_c3cn_rx_credits(struct s3_conn *c3cn, int copied) +-{ +- struct t3cdev *cdev; +- int must_send; +- u32 credits, dack = 0; +- +- if (!c3cn_in_state(c3cn, CREDIT_RETURN_STATE)) +- return; +- +- credits = c3cn->copied_seq - c3cn->rcv_wup; +- if (unlikely(!credits)) +- return; +- +- cdev = c3cn->cdev; +- +- if (unlikely(cxgb3_rx_credit_thres == 0)) +- return; +- +- dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1); +- +- /* +- * For coalescing to work effectively ensure the receive window has +- * at least 16KB left. +- */ +- must_send = credits + 16384 >= cxgb3_rcv_win; +- +- if (must_send || credits >= cxgb3_rx_credit_thres) +- c3cn->rcv_wup += s3_send_rx_credits(c3cn, credits, dack, +- must_send); +-} +- +-/* +- * Generic ARP failure handler that discards the buffer. +- */ +-static void arp_failure_discard(struct t3cdev *cdev, struct sk_buff *skb) +-{ +- kfree_skb(skb); +-} +- +-/* +- * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a +- * connection's send queue and sends them on to T3. Must be called with the +- * connection's lock held. Returns the amount of send buffer space that was +- * freed as a result of sending queued data to T3. +- */ +-static int s3_push_frames(struct s3_conn *c3cn, int req_completion) +-{ +- int total_size = 0; +- struct sk_buff *skb; +- struct t3cdev *cdev; +- struct cxgb3i_sdev_data *cdata; +- +- if (unlikely(c3cn_in_state(c3cn, +- C3CN_STATE_SYN_SENT | C3CN_STATE_CLOSE))) +- return 0; +- +- /* +- * We shouldn't really be called at all after an abort but check just +- * in case. +- */ +- if (unlikely(c3cn_flag(c3cn, C3CN_ABORT_SHUTDOWN))) +- return 0; +- +- cdev = c3cn->cdev; +- cdata = CXGB3_SDEV_DATA(cdev); +- +- while (c3cn->wr_avail +- && (skb = skb_peek(&c3cn->write_queue)) != NULL +- && !c3cn_flag(c3cn, C3CN_TX_WAIT_IDLE)) { +- +- int len = skb->len; /* length before skb_push */ +- int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len); +- int wrs_needed = skb_wrs[frags]; +- +- if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) +- wrs_needed = 1; +- +- WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1); +- +- if (c3cn->wr_avail < wrs_needed) ++ if (c3cn->wr_avail < wrs_needed) { ++ c3cn_tx_debug("c3cn 0x%p, skb len %u/%u, frag %u, " ++ "wr %d < %u.\n", ++ c3cn, skb->len, skb->data_len, frags, ++ wrs_needed, c3cn->wr_avail); + break; ++ } + + __skb_unlink(skb, &c3cn->write_queue); + skb->priority = CPL_PRIORITY_DATA; +@@ -857,8 +640,7 @@ static int s3_push_frames(struct s3_conn + c3cn->wr_unacked = 0; + } + CXGB3_SKB_CB(skb)->flags &= ~C3CB_FLAG_NEED_HDR; +- } else if (skb->data[0] == FW_WROPCODE_OFLD_CLOSE_CON) +- c3cn_set_flag(c3cn, C3CN_CLOSE_CON_REQUESTED); ++ } + + total_size += skb->truesize; + set_arp_failure_handler(skb, arp_failure_discard); +@@ -868,515 +650,386 @@ static int s3_push_frames(struct s3_conn + } + + /* +- * Handle an ARP failure for a CPL_ABORT_REQ. Change it into a no RST variant +- * and send it along. ++ * process_cpl_msg: -> host ++ * Top-level CPL message processing used by most CPL messages that ++ * pertain to connections. + */ +-static void abort_arp_failure(struct t3cdev *cdev, struct sk_buff *skb) ++static inline void process_cpl_msg(void (*fn)(struct s3_conn *, ++ struct sk_buff *), ++ struct s3_conn *c3cn, ++ struct sk_buff *skb) + { +- struct cpl_abort_req *req = cplhdr(skb); +- +- c3cn_conn_debug("tdev 0x%p.\n", cdev); +- +- req->cmd = CPL_ABORT_NO_RST; +- cxgb3_ofld_send(cdev, skb); ++ spin_lock_bh(&c3cn->lock); ++ fn(c3cn, skb); ++ spin_unlock_bh(&c3cn->lock); + } + + /* +- * Send an ABORT_REQ message. Cannot fail. This routine makes sure we do +- * not send multiple ABORT_REQs for the same connection and also that we do +- * not try to send a message after the connection has closed. Returns 1 if +- * an ABORT_REQ wasn't generated after all, 0 otherwise. ++ * process_cpl_msg_ref: -> host ++ * Similar to process_cpl_msg() but takes an extra connection reference around ++ * the call to the handler. Should be used if the handler may drop a ++ * connection reference. + */ +-static int s3_send_reset(struct s3_conn *c3cn, int mode, +- struct sk_buff *skb) ++static inline void process_cpl_msg_ref(void (*fn) (struct s3_conn *, ++ struct sk_buff *), ++ struct s3_conn *c3cn, ++ struct sk_buff *skb) + { +- struct cpl_abort_req *req; +- unsigned int tid = c3cn->tid; ++ c3cn_hold(c3cn); ++ process_cpl_msg(fn, c3cn, skb); ++ c3cn_put(c3cn); ++} + +- if (unlikely(c3cn_flag(c3cn, C3CN_ABORT_SHUTDOWN) || !c3cn->cdev)) { +- if (skb) +- __kfree_skb(skb); +- return 1; +- } ++/* ++ * Process a CPL_ACT_ESTABLISH message: -> host ++ * Updates connection state from an active establish CPL message. Runs with ++ * the connection lock held. ++ */ + +- c3cn_conn_debug("c3cn 0x%p, mode %d, flag ABORT_RPL + ABORT_SHUT.\n", +- c3cn, mode); ++static inline void s3_free_atid(struct t3cdev *cdev, unsigned int tid) ++{ ++ struct s3_conn *c3cn = cxgb3_free_atid(cdev, tid); ++ if (c3cn) ++ c3cn_put(c3cn); ++} + +- c3cn_set_flag(c3cn, C3CN_ABORT_RPL_PENDING); +- c3cn_set_flag(c3cn, C3CN_ABORT_SHUTDOWN); ++static void c3cn_established(struct s3_conn *c3cn, u32 snd_isn, ++ unsigned int opt) ++{ ++ c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state); + +- /* Purge the send queue so we don't send anything after an abort. */ +- s3_purge_write_queue(c3cn); ++ c3cn->write_seq = c3cn->snd_nxt = c3cn->snd_una = snd_isn; + +- if (!skb) +- skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); +- skb->priority = CPL_PRIORITY_DATA; +- set_arp_failure_handler(skb, abort_arp_failure); ++ /* ++ * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't ++ * pass through opt0. ++ */ ++ if (cxgb3_rcv_win > (M_RCV_BUFSIZ << 10)) ++ c3cn->rcv_wup -= cxgb3_rcv_win - (M_RCV_BUFSIZ << 10); + +- req = (struct cpl_abort_req *)skb_put(skb, sizeof(*req)); +- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); +- req->wr.wr_lo = htonl(V_WR_TID(tid)); +- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, tid)); +- req->rsvd0 = htonl(c3cn->snd_nxt); +- req->rsvd1 = !c3cn_flag(c3cn, C3CN_TX_DATA_SENT); +- req->cmd = mode; ++ dst_confirm(c3cn->dst_cache); + +- l2t_send(c3cn->cdev, skb, c3cn->l2t); +- return 0; ++ smp_mb(); ++ ++ c3cn_set_state(c3cn, C3CN_STATE_ESTABLISHED); + } + +-/* +- * Add a list of skbs to a connection send queue. This interface is intended +- * for use by in-kernel ULPs. The skbs must comply with the max size limit of +- * the device and have a headroom of at least TX_HEADER_LEN bytes. +- */ +-int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb, int flags) ++static void process_act_establish(struct s3_conn *c3cn, struct sk_buff *skb) + { +- struct sk_buff *next; +- int err, copied = 0; +- +- spin_lock_bh(&c3cn->lock); ++ struct cpl_act_establish *req = cplhdr(skb); ++ u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */ + +- if (!c3cn_in_state(c3cn, C3CN_STATE_ESTABLISHED)) { +- err = -EAGAIN; +- goto out_err; +- } ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); + +- err = -EPIPE; +- if (c3cn->err || (c3cn->shutdown & C3CN_SEND_SHUTDOWN)) +- goto out_err; ++ if (unlikely(c3cn->state != C3CN_STATE_CONNECTING)) ++ cxgb3i_log_error("TID %u expected SYN_SENT, got EST., s %u\n", ++ c3cn->tid, c3cn->state); + +- while (skb) { +- int frags = skb_shinfo(skb)->nr_frags + +- (skb->len != skb->data_len); ++ c3cn->copied_seq = c3cn->rcv_wup = c3cn->rcv_nxt = rcv_isn; ++ c3cn_established(c3cn, ntohl(req->snd_isn), ntohs(req->tcp_opt)); + +- if (unlikely(skb_headroom(skb) < TX_HEADER_LEN)) { +- c3cn_tx_debug("c3cn 0x%p, skb head.\n", c3cn); +- err = -EINVAL; +- goto out_err; +- } ++ __kfree_skb(skb); + +- if (frags >= SKB_WR_LIST_SIZE) { +- cxgb3i_log_error("c3cn 0x%p, tx frags %d, len %u,%u.\n", +- c3cn, skb_shinfo(skb)->nr_frags, +- skb->len, skb->data_len); +- err = -EINVAL; +- goto out_err; +- } ++ if (unlikely(c3cn_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED))) ++ /* upper layer has requested closing */ ++ send_abort_req(c3cn); ++ else if (c3cn_push_tx_frames(c3cn, 1)) ++ cxgb3i_conn_tx_open(c3cn); ++} + +- next = skb->next; +- skb->next = NULL; +- skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND | C3CB_FLAG_NEED_HDR); +- copied += skb->len; +- c3cn->write_seq += skb->len + ulp_extra_len(skb); +- skb = next; +- } +-done: +- if (likely(skb_queue_len(&c3cn->write_queue))) +- s3_push_frames(c3cn, 1); +- spin_unlock_bh(&c3cn->lock); +- return copied; ++static int do_act_establish(struct t3cdev *cdev, struct sk_buff *skb, ++ void *ctx) ++{ ++ struct cpl_act_establish *req = cplhdr(skb); ++ unsigned int tid = GET_TID(req); ++ unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); ++ struct s3_conn *c3cn = ctx; ++ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); + +-out_err: +- if (copied == 0 && err == -EPIPE) +- copied = c3cn->err ? c3cn->err : -EPIPE; +- goto done; +-} ++ c3cn_conn_debug("rcv, tid 0x%x, c3cn 0x%p, s %u, f 0x%lx.\n", ++ tid, c3cn, c3cn->state, c3cn->flags); + +-/* +- * Low-level utility routines for primary API functions. +- * ===================================================== +- */ +-/* routines to implement CPL message processing */ +-static void c3cn_act_establish(struct s3_conn *, struct sk_buff *); +-static void active_open_failed(struct s3_conn *, struct sk_buff *); +-static void wr_ack(struct s3_conn *, struct sk_buff *); +-static void do_peer_fin(struct s3_conn *, struct sk_buff *); +-static void process_abort_req(struct s3_conn *, struct sk_buff *); +-static void process_abort_rpl(struct s3_conn *, struct sk_buff *); +-static void process_close_con_rpl(struct s3_conn *, struct sk_buff *); +-static void process_rx_iscsi_hdr(struct s3_conn *, struct sk_buff *); ++ c3cn->tid = tid; ++ c3cn_hold(c3cn); ++ cxgb3_insert_tid(cdata->cdev, cdata->client, c3cn, tid); ++ s3_free_atid(cdev, atid); + +-static struct sk_buff *__get_cpl_reply_skb(struct sk_buff *, size_t, gfp_t); ++ c3cn->qset = G_QNUM(ntohl(skb->csum)); + +-static void fail_act_open(struct s3_conn *, int); +-static void init_offload_conn(struct s3_conn *, struct t3cdev *, +- struct dst_entry *); ++ process_cpl_msg(process_act_establish, c3cn, skb); ++ return 0; ++} + + /* +- * Insert a connection into the TID table and take an extra reference. ++ * Process a CPL_ACT_OPEN_RPL message: -> host ++ * Handle active open failures. + */ +-static inline void c3cn_insert_tid(struct cxgb3i_sdev_data *cdata, +- struct s3_conn *c3cn, +- unsigned int tid) ++static int act_open_rpl_status_to_errno(int status) + { +- c3cn_hold(c3cn); +- cxgb3_insert_tid(cdata->cdev, cdata->client, c3cn, tid); +-} +- +-static inline void free_atid(struct t3cdev *cdev, unsigned int tid) +-{ +- struct s3_conn *c3cn = cxgb3_free_atid(cdev, tid); +- if (c3cn) +- c3cn_put(c3cn); +-} +- +-/* +- * This function is intended for allocations of small control messages. +- * Such messages go as immediate data and usually the pakets are freed +- * immediately. We maintain a cache of one small sk_buff and use it whenever +- * it is available (has a user count of 1). Otherwise we get a fresh buffer. +- */ +-#define CTRL_SKB_LEN 120 +- +-static struct sk_buff *alloc_ctrl_skb(const struct s3_conn *c3cn, +- int len) +-{ +- struct sk_buff *skb = c3cn->ctrl_skb_cache; +- +- if (likely(skb && !skb_shared(skb) && !skb_cloned(skb))) { +- __skb_trim(skb, 0); +- atomic_set(&skb->users, 2); +- } else if (likely(!in_atomic())) +- skb = alloc_skb(len, GFP_ATOMIC | __GFP_NOFAIL); +- else +- skb = alloc_skb(len, GFP_ATOMIC); +- return skb; ++ switch (status) { ++ case CPL_ERR_CONN_RESET: ++ return ECONNREFUSED; ++ case CPL_ERR_ARP_MISS: ++ return EHOSTUNREACH; ++ case CPL_ERR_CONN_TIMEDOUT: ++ return ETIMEDOUT; ++ case CPL_ERR_TCAM_FULL: ++ return ENOMEM; ++ case CPL_ERR_CONN_EXIST: ++ cxgb3i_log_error("ACTIVE_OPEN_RPL: 4-tuple in use\n"); ++ return EADDRINUSE; ++ default: ++ return EIO; ++ } + } + +-/* +- * Handle an ARP failure for an active open. +- */ +-static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb) ++static void act_open_retry_timer(unsigned long data) + { +- struct s3_conn *c3cn = (struct s3_conn *)skb->sk; ++ struct sk_buff *skb; ++ struct s3_conn *c3cn = (struct s3_conn *)data; + +- c3cn_conn_debug("c3cn 0x%p, state 0x%x.\n", c3cn, c3cn->state); ++ c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state); + +- c3cn_hold(c3cn); +- spin_lock(&c3cn->lock); +- if (c3cn->state == C3CN_STATE_SYN_SENT) { +- fail_act_open(c3cn, EHOSTUNREACH); +- __kfree_skb(skb); ++ spin_lock_bh(&c3cn->lock); ++ skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_ATOMIC); ++ if (!skb) ++ fail_act_open(c3cn, ENOMEM); ++ else { ++ skb->sk = (struct sock *)c3cn; ++ set_arp_failure_handler(skb, act_open_req_arp_failure); ++ make_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); ++ l2t_send(c3cn->cdev, skb, c3cn->l2t); + } +- spin_unlock(&c3cn->lock); ++ spin_unlock_bh(&c3cn->lock); + c3cn_put(c3cn); + } + +-/* +- * Send an active open request. +- */ +-static int act_open(struct s3_conn *c3cn, struct net_device *dev) ++static void process_act_open_rpl(struct s3_conn *c3cn, struct sk_buff *skb) + { +- struct cxgb3i_sdev_data *cdata = NDEV2CDATA(dev); +- struct t3cdev *cdev = cdata->cdev; +- struct dst_entry *dst = c3cn->dst_cache; +- struct sk_buff *skb; ++ struct cpl_act_open_rpl *rpl = cplhdr(skb); + +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", + c3cn, c3cn->state, c3cn->flags); +- /* +- * Initialize connection data. Note that the flags and ULP mode are +- * initialized higher up ... +- */ +- c3cn->dev = dev; +- c3cn->cdev = cdev; +- c3cn->tid = cxgb3_alloc_atid(cdev, cdata->client, c3cn); +- if (c3cn->tid < 0) +- goto out_err; +- +- c3cn->qset = 0; +- c3cn->l2t = t3_l2t_get(cdev, dst->neighbour, dev); +- if (!c3cn->l2t) +- goto free_tid; + +- skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_KERNEL); +- if (!skb) +- goto free_l2t; ++ if (rpl->status == CPL_ERR_CONN_EXIST && ++ c3cn->retry_timer.function != act_open_retry_timer) { ++ c3cn->retry_timer.function = act_open_retry_timer; ++ if (!mod_timer(&c3cn->retry_timer, jiffies + HZ / 2)) ++ c3cn_hold(c3cn); ++ } else ++ fail_act_open(c3cn, act_open_rpl_status_to_errno(rpl->status)); ++ __kfree_skb(skb); ++} + +- skb->sk = (struct sock *)c3cn; +- set_arp_failure_handler(skb, act_open_req_arp_failure); ++static int do_act_open_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ struct cpl_act_open_rpl *rpl = cplhdr(skb); + +- c3cn_hold(c3cn); ++ c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, s %u, f 0x%lx.\n", ++ rpl->status, c3cn, c3cn->state, c3cn->flags); + +- init_offload_conn(c3cn, cdev, dst); +- c3cn->err = 0; +- c3cn_reset_flag(c3cn, C3CN_DONE); ++ if (rpl->status != CPL_ERR_TCAM_FULL && ++ rpl->status != CPL_ERR_CONN_EXIST && ++ rpl->status != CPL_ERR_ARP_MISS) ++ cxgb3_queue_tid_release(cdev, GET_TID(rpl)); + +- mk_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); +- l2t_send(cdev, skb, c3cn->l2t); ++ process_cpl_msg_ref(process_act_open_rpl, c3cn, skb); + return 0; +- +-free_l2t: +- l2t_release(L2DATA(cdev), c3cn->l2t); +-free_tid: +- free_atid(cdev, c3cn->tid); +- c3cn->tid = 0; +-out_err: +- return -1; + } + + /* +- * Close a connection by sending a CPL_CLOSE_CON_REQ message. Cannot fail +- * under any circumstances. We take the easy way out and always queue the +- * message to the write_queue. We can optimize the case where the queue is +- * already empty though the optimization is probably not worth it. ++ * Process PEER_CLOSE CPL messages: -> host ++ * Handle peer FIN. + */ +-static void mk_close_req(struct s3_conn *c3cn) ++static void process_peer_close(struct s3_conn *c3cn, struct sk_buff *skb) + { +- struct sk_buff *skb; +- struct cpl_close_con_req *req; +- unsigned int tid = c3cn->tid; +- +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", + c3cn, c3cn->state, c3cn->flags); + +- skb = alloc_skb(sizeof(struct cpl_close_con_req), +- GFP_KERNEL | __GFP_NOFAIL); +- req = (struct cpl_close_con_req *)__skb_put(skb, sizeof(*req)); +- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); +- req->wr.wr_lo = htonl(V_WR_TID(tid)); +- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); +- req->rsvd = htonl(c3cn->write_seq); ++ if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) ++ goto out; + +- skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND); +- if (c3cn->state != C3CN_STATE_SYN_SENT) +- s3_push_frames(c3cn, 1); ++ switch (c3cn->state) { ++ case C3CN_STATE_ESTABLISHED: ++ c3cn_set_state(c3cn, C3CN_STATE_PASSIVE_CLOSE); ++ break; ++ case C3CN_STATE_ACTIVE_CLOSE: ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_2); ++ break; ++ case C3CN_STATE_CLOSE_WAIT_1: ++ c3cn_closed(c3cn); ++ break; ++ case C3CN_STATE_ABORTING: ++ break; ++ default: ++ cxgb3i_log_error("%s: peer close, TID %u in bad state %u\n", ++ c3cn->cdev->name, c3cn->tid, c3cn->state); ++ } ++ ++ cxgb3i_conn_closing(c3cn); ++out: ++ __kfree_skb(skb); + } + +-static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb, +- int flags) ++static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) + { +- CXGB3_SKB_CB(skb)->seq = c3cn->write_seq; +- CXGB3_SKB_CB(skb)->flags = flags; +- __skb_queue_tail(&c3cn->write_queue, skb); ++ struct s3_conn *c3cn = ctx; ++ ++ c3cn_conn_debug("rcv, c3cn 0x%p, s %u, f 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ process_cpl_msg_ref(process_peer_close, c3cn, skb); ++ return 0; + } + + /* +- * Send RX credits through an RX_DATA_ACK CPL message. If nofail is 0 we are +- * permitted to return without sending the message in case we cannot allocate +- * an sk_buff. Returns the number of credits sent. ++ * Process CLOSE_CONN_RPL CPL message: -> host ++ * Process a peer ACK to our FIN. + */ +-static u32 s3_send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack, +- int nofail) ++static void process_close_con_rpl(struct s3_conn *c3cn, struct sk_buff *skb) + { +- struct sk_buff *skb; +- struct cpl_rx_data_ack *req; ++ struct cpl_close_con_rpl *rpl = cplhdr(skb); + +- skb = (nofail ? alloc_ctrl_skb(c3cn, sizeof(*req)) +- : alloc_skb(sizeof(*req), GFP_ATOMIC)); +- if (!skb) +- return 0; ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); + +- req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req)); +- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); +- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid)); +- req->credit_dack = htonl(dack | V_RX_CREDITS(credits)); +- skb->priority = CPL_PRIORITY_ACK; +- cxgb3_ofld_send(c3cn->cdev, skb); +- return credits; +-} ++ c3cn->snd_una = ntohl(rpl->snd_nxt) - 1; /* exclude FIN */ + +-static void mk_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb, +- unsigned int atid, const struct l2t_entry *e) +-{ +- struct cpl_act_open_req *req; ++ if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) ++ goto out; + +- c3cn_conn_debug("c3cn 0x%p, atid 0x%x.\n", c3cn, atid); ++ switch (c3cn->state) { ++ case C3CN_STATE_ACTIVE_CLOSE: ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_1); ++ break; ++ case C3CN_STATE_CLOSE_WAIT_1: ++ case C3CN_STATE_CLOSE_WAIT_2: ++ c3cn_closed(c3cn); ++ break; ++ case C3CN_STATE_ABORTING: ++ break; ++ default: ++ cxgb3i_log_error("%s: close_rpl, TID %u in bad state %u\n", ++ c3cn->cdev->name, c3cn->tid, c3cn->state); ++ } + +- skb->priority = CPL_PRIORITY_SETUP; +- req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req)); +- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); +- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid)); +- req->local_port = c3cn->saddr.sin_port; +- req->peer_port = c3cn->daddr.sin_port; +- req->local_ip = c3cn->saddr.sin_addr.s_addr; +- req->peer_ip = c3cn->daddr.sin_addr.s_addr; +- req->opt0h = htonl(calc_opt0h(c3cn) | V_L2T_IDX(e->idx) | +- V_TX_CHANNEL(e->smt_idx)); +- req->opt0l = htonl(calc_opt0l(c3cn)); +- req->params = 0; ++out: ++ kfree_skb(skb); + } + +-/* +- * Definitions and declarations for CPL handler functions. +- * ======================================================= +- */ +- +-/* +- * Similar to process_cpl_msg() but takes an extra connection reference around +- * the call to the handler. Should be used if the handler may drop a +- * connection reference. +- */ +-static inline void process_cpl_msg_ref(void (*fn) (struct s3_conn *, +- struct sk_buff *), +- struct s3_conn *c3cn, +- struct sk_buff *skb) ++static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb, ++ void *ctx) + { +- c3cn_hold(c3cn); +- process_cpl_msg(fn, c3cn, skb); +- c3cn_put(c3cn); +-} ++ struct s3_conn *c3cn = ctx; + +-/* +- * Return whether a failed active open has allocated a TID +- */ +-static inline int act_open_has_tid(int status) +-{ +- return status != CPL_ERR_TCAM_FULL && status != CPL_ERR_CONN_EXIST && +- status != CPL_ERR_ARP_MISS; ++ c3cn_conn_debug("rcv, c3cn 0x%p, s %u, f 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ process_cpl_msg_ref(process_close_con_rpl, c3cn, skb); ++ return 0; + } + + /* +- * Returns true if a connection cannot accept new Rx data. ++ * Process ABORT_REQ_RSS CPL message: -> host ++ * Process abort requests. If we are waiting for an ABORT_RPL we ignore this ++ * request except that we need to reply to it. + */ +-static inline int c3cn_no_receive(const struct s3_conn *c3cn) ++ ++static int abort_status_to_errno(struct s3_conn *c3cn, int abort_reason, ++ int *need_rst) + { +- return c3cn->shutdown & C3CN_RCV_SHUTDOWN; ++ switch (abort_reason) { ++ case CPL_ERR_BAD_SYN: /* fall through */ ++ case CPL_ERR_CONN_RESET: ++ return c3cn->state > C3CN_STATE_ESTABLISHED ? ++ EPIPE : ECONNRESET; ++ case CPL_ERR_XMIT_TIMEDOUT: ++ case CPL_ERR_PERSIST_TIMEDOUT: ++ case CPL_ERR_FINWAIT2_TIMEDOUT: ++ case CPL_ERR_KEEPALIVE_TIMEDOUT: ++ return ETIMEDOUT; ++ default: ++ return EIO; ++ } + } + +-/* +- * A helper function that aborts a connection and increments the given MIB +- * counter. The supplied skb is used to generate the ABORT_REQ message if +- * possible. Must be called with softirqs disabled. +- */ +-static inline void abort_conn(struct s3_conn *c3cn, +- struct sk_buff *skb) ++static void process_abort_req(struct s3_conn *c3cn, struct sk_buff *skb) + { +- struct sk_buff *abort_skb; ++ int rst_status = CPL_ABORT_NO_RST; ++ const struct cpl_abort_req_rss *req = cplhdr(skb); + +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", + c3cn, c3cn->state, c3cn->flags); + +- abort_skb = __get_cpl_reply_skb(skb, sizeof(struct cpl_abort_req), +- GFP_ATOMIC); +- if (abort_skb) +- s3_send_reset(c3cn, CPL_ABORT_SEND_RST, abort_skb); +-} ++ if (!c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) { ++ c3cn_set_flag(c3cn, C3CN_ABORT_REQ_RCVD); ++ c3cn_set_state(c3cn, C3CN_STATE_ABORTING); ++ __kfree_skb(skb); ++ return; ++ } + +-/* +- * Returns whether an ABORT_REQ_RSS message is a negative advice. +- */ +-static inline int is_neg_adv_abort(unsigned int status) +-{ +- return status == CPL_ERR_RTX_NEG_ADVICE || +- status == CPL_ERR_PERSIST_NEG_ADVICE; +-} ++ c3cn_clear_flag(c3cn, C3CN_ABORT_REQ_RCVD); ++ send_abort_rpl(c3cn, rst_status); + +-/* +- * CPL handler functions. +- * ====================== +- */ ++ if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { ++ c3cn->err = ++ abort_status_to_errno(c3cn, req->status, &rst_status); ++ c3cn_closed(c3cn); ++ } ++} + +-/* +- * Process a CPL_ACT_ESTABLISH message. +- */ +-static int do_act_establish(struct t3cdev *cdev, struct sk_buff *skb, +- void *ctx) ++static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) + { +- struct cpl_act_establish *req = cplhdr(skb); +- unsigned int tid = GET_TID(req); +- unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); ++ const struct cpl_abort_req_rss *req = cplhdr(skb); + struct s3_conn *c3cn = ctx; +- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); + +- c3cn_conn_debug("rcv, tid 0x%x, c3cn 0x%p, 0x%x, 0x%lx.\n", +- tid, c3cn, c3cn->state, c3cn->flags); +- /* +- * It's OK if the TID is currently in use, the owning connection may +- * have backlogged its last CPL message(s). Just take it away. +- */ +- c3cn->tid = tid; +- c3cn_insert_tid(cdata, c3cn, tid); +- free_atid(cdev, atid); ++ c3cn_conn_debug("rcv, c3cn 0x%p, s 0x%x, f 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); + +- c3cn->qset = G_QNUM(ntohl(skb->csum)); ++ if (req->status == CPL_ERR_RTX_NEG_ADVICE || ++ req->status == CPL_ERR_PERSIST_NEG_ADVICE) { ++ __kfree_skb(skb); ++ return 0; ++ } + +- process_cpl_msg(c3cn_act_establish, c3cn, skb); ++ process_cpl_msg_ref(process_abort_req, c3cn, skb); + return 0; + } + + /* +- * Process an ACT_OPEN_RPL CPL message. ++ * Process ABORT_RPL_RSS CPL message: -> host ++ * Process abort replies. We only process these messages if we anticipate ++ * them as the coordination between SW and HW in this area is somewhat lacking ++ * and sometimes we get ABORT_RPLs after we are done with the connection that ++ * originated the ABORT_REQ. + */ +-static int do_act_open_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++static void process_abort_rpl(struct s3_conn *c3cn, struct sk_buff *skb) + { +- struct s3_conn *c3cn = ctx; +- struct cpl_act_open_rpl *rpl = cplhdr(skb); +- +- c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, 0x%x, 0x%lx.\n", +- rpl->status, c3cn, c3cn->state, c3cn->flags); +- +- if (act_open_has_tid(rpl->status)) +- cxgb3_queue_tid_release(cdev, GET_TID(rpl)); +- +- process_cpl_msg_ref(active_open_failed, c3cn, skb); +- return 0; +-} +- +-/* +- * Handler RX_ISCSI_HDR CPL messages. +- */ +-static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) +-{ +- struct s3_conn *c3cn = ctx; +- process_cpl_msg(process_rx_iscsi_hdr, c3cn, skb); +- return 0; +-} +- +-/* +- * Handler for TX_DATA_ACK CPL messages. +- */ +-static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +-{ +- struct s3_conn *c3cn = ctx; +- +- process_cpl_msg(wr_ack, c3cn, skb); +- return 0; +-} +- +-/* +- * Handler for PEER_CLOSE CPL messages. +- */ +-static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +-{ +- struct s3_conn *c3cn = ctx; +- +- c3cn_conn_debug("rcv, c3cn 0x%p, 0x%x, 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- process_cpl_msg_ref(do_peer_fin, c3cn, skb); +- return 0; +-} +- +-/* +- * Handle an ABORT_REQ_RSS CPL message. +- */ +-static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) +-{ +- const struct cpl_abort_req_rss *req = cplhdr(skb); +- struct s3_conn *c3cn = ctx; +- +- c3cn_conn_debug("rcv, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", + c3cn, c3cn->state, c3cn->flags); + +- if (is_neg_adv_abort(req->status)) { +- __kfree_skb(skb); +- return 0; ++ if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { ++ if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_RCVD)) ++ c3cn_set_flag(c3cn, C3CN_ABORT_RPL_RCVD); ++ else { ++ c3cn_clear_flag(c3cn, C3CN_ABORT_RPL_RCVD); ++ c3cn_clear_flag(c3cn, C3CN_ABORT_RPL_PENDING); ++ if (c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) ++ cxgb3i_log_error("%s tid %u, ABORT_RPL_RSS\n", ++ c3cn->cdev->name, c3cn->tid); ++ c3cn_closed(c3cn); ++ } + } +- +- process_cpl_msg_ref(process_abort_req, c3cn, skb); +- return 0; ++ __kfree_skb(skb); + } + +-/* +- * Handle an ABORT_RPL_RSS CPL message. +- */ + static int do_abort_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) + { + struct cpl_abort_rpl_rss *rpl = cplhdr(skb); + struct s3_conn *c3cn = ctx; + +- c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, 0x%x, 0x%lx.\n", ++ c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, s %u, 0x%lx.\n", + rpl->status, c3cn, c3cn ? c3cn->state : 0, + c3cn ? c3cn->flags : 0UL); + +@@ -1394,7 +1047,7 @@ static int do_abort_rpl(struct t3cdev *c + * abort races with ABORT_REQ_RSS, the latter frees the connection + * expecting the ABORT_REQ will fail with CPL_ERR_ABORT_FAILED, + * but FW turns the ABORT_REQ into a regular one and so we get +- * ABORT_RPL_RSS with status 0 and no connection. Only on T3A. ++ * ABORT_RPL_RSS with status 0 and no connection. + */ + if (!c3cn) + goto discard; +@@ -1408,144 +1061,11 @@ discard: + } + + /* +- * Handler for CLOSE_CON_RPL CPL messages. +- */ +-static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb, +- void *ctx) +-{ +- struct s3_conn *c3cn = ctx; +- +- c3cn_conn_debug("rcv, c3cn 0x%p, 0x%x, 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- +- process_cpl_msg_ref(process_close_con_rpl, c3cn, skb); +- return 0; +-} +- +-/* +- * Definitions and declarations for CPL message processing. +- * ======================================================== +- */ +- +-static void make_established(struct s3_conn *, u32, unsigned int); +-static void act_open_retry_timer(unsigned long); +-static void mk_act_open_req(struct s3_conn *, struct sk_buff *, +- unsigned int, const struct l2t_entry *); +-static int act_open_rpl_status_to_errno(int); +-static void handle_excess_rx(struct s3_conn *, struct sk_buff *); +-static int abort_status_to_errno(struct s3_conn *, int, int *); +-static void send_abort_rpl(struct sk_buff *, struct t3cdev *, int); +-static struct sk_buff *get_cpl_reply_skb(struct sk_buff *, size_t, gfp_t); +- +-/* +- * Dequeue and return the first unacknowledged's WR on a connections's pending +- * list. +- */ +-static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn) +-{ +- struct sk_buff *skb = c3cn->wr_pending_head; +- +- if (likely(skb)) { +- /* Don't bother clearing the tail */ +- c3cn->wr_pending_head = (struct sk_buff *)skb->sp; +- skb->sp = NULL; +- } +- return skb; +-} +- +-/* +- * Return the first pending WR without removing it from the list. +- */ +-static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn) +-{ +- return c3cn->wr_pending_head; +-} +- +-static inline void free_wr_skb(struct sk_buff *skb) +-{ +- kfree_skb(skb); +-} +- +-static void purge_wr_queue(struct s3_conn *c3cn) +-{ +- struct sk_buff *skb; +- while ((skb = dequeue_wr(c3cn)) != NULL) +- free_wr_skb(skb); +-} +- +-static inline void set_abort_rpl_wr(struct sk_buff *skb, unsigned int tid, +- int cmd) +-{ +- struct cpl_abort_rpl *rpl = cplhdr(skb); +- +- rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); +- rpl->wr.wr_lo = htonl(V_WR_TID(tid)); +- OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid)); +- rpl->cmd = cmd; +-} +- +-/* +- * CPL message processing ... +- * ========================== +- */ +- +-/* +- * Updates connection state from an active establish CPL message. Runs with +- * the connection lock held. +- */ +-static void c3cn_act_establish(struct s3_conn *c3cn, +- struct sk_buff *skb) +-{ +- struct cpl_act_establish *req = cplhdr(skb); +- u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */ +- +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- +- if (unlikely(c3cn->state != C3CN_STATE_SYN_SENT)) +- printk(KERN_ERR "TID %u expected SYN_SENT, found %d\n", +- c3cn->tid, c3cn->state); +- +- c3cn->copied_seq = c3cn->rcv_wup = c3cn->rcv_nxt = rcv_isn; +- make_established(c3cn, ntohl(req->snd_isn), ntohs(req->tcp_opt)); +- +- if (unlikely(c3cn_flag(c3cn, C3CN_CLOSE_NEEDED))) { +- /* upper layer has requested closing */ +- abort_conn(c3cn, skb); +- return; +- } +- +- __kfree_skb(skb); +- if (s3_push_frames(c3cn, 1)) +- cxgb3i_conn_tx_open(c3cn); +-} +- +-/* +- * Handle active open failures. +- */ +-static void active_open_failed(struct s3_conn *c3cn, +- struct sk_buff *skb) +-{ +- struct cpl_act_open_rpl *rpl = cplhdr(skb); +- +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); +- +- if (rpl->status == CPL_ERR_CONN_EXIST && +- c3cn->retry_timer.function != act_open_retry_timer) { +- c3cn->retry_timer.function = act_open_retry_timer; +- c3cn_reset_timer(c3cn, &c3cn->retry_timer, +- jiffies + HZ / 2); +- } else +- fail_act_open(c3cn, act_open_rpl_status_to_errno(rpl->status)); +- __kfree_skb(skb); +-} +- +-/* +- * Process received pdu for a connection. ++ * Process RX_ISCSI_HDR CPL message: -> host ++ * Handle received PDUs, the payload could be DDP'ed. If not, the payload ++ * follow after the bhs. + */ +-static void process_rx_iscsi_hdr(struct s3_conn *c3cn, +- struct sk_buff *skb) ++static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb) + { + struct cpl_iscsi_hdr *hdr_cpl = cplhdr(skb); + struct cpl_iscsi_hdr_norss data_cpl; +@@ -1554,8 +1074,10 @@ static void process_rx_iscsi_hdr(struct + unsigned int len; + int err; + +- if (unlikely(c3cn_no_receive(c3cn))) { +- handle_excess_rx(c3cn, skb); ++ if (unlikely(c3cn->state >= C3CN_STATE_PASSIVE_CLOSE)) { ++ if (c3cn->state != C3CN_STATE_ABORTING) ++ send_abort_req(c3cn); ++ __kfree_skb(skb); + return; + } + +@@ -1568,8 +1090,9 @@ static void process_rx_iscsi_hdr(struct + len = hdr_len = ntohs(hdr_cpl->len); + /* msg coalesce is off or not enough data received */ + if (skb->len <= hdr_len) { +- printk(KERN_ERR "%s: TID %u, ISCSI_HDR, skb len %u < %u.\n", +- c3cn->cdev->name, c3cn->tid, skb->len, hdr_len); ++ cxgb3i_log_error("%s: TID %u, ISCSI_HDR, skb len %u < %u.\n", ++ c3cn->cdev->name, c3cn->tid, ++ skb->len, hdr_len); + goto abort_conn; + } + +@@ -1586,6 +1109,9 @@ static void process_rx_iscsi_hdr(struct + c3cn_rx_debug("skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n", + skb, skb->len, skb_ulp_pdulen(skb), status); + ++ c3cn_rx_debug("rx skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n", ++ skb, skb->len, skb_ulp_pdulen(skb), status); ++ + if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT)) + skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR; + if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT)) +@@ -1610,15 +1136,24 @@ static void process_rx_iscsi_hdr(struct + return; + + abort_conn: +- s3_send_reset(c3cn, CPL_ABORT_SEND_RST, NULL); ++ send_abort_req(c3cn); + __kfree_skb(skb); + } + ++static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ ++ process_cpl_msg(process_rx_iscsi_hdr, c3cn, skb); ++ return 0; ++} ++ + /* ++ * Process TX_DATA_ACK CPL messages: -> host + * Process an acknowledgment of WR completion. Advance snd_una and send the + * next batch of work requests from the write queue. + */ +-static void wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) ++static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb) + { + struct cpl_wr_ack *hdr = cplhdr(skb); + unsigned int credits = ntohs(hdr->credits); +@@ -1632,9 +1167,9 @@ static void wr_ack(struct s3_conn *c3cn, + struct sk_buff *p = peek_wr(c3cn); + + if (unlikely(!p)) { +- printk(KERN_ERR "%u WR_ACK credits for TID %u with " +- "nothing pending, state %u\n", +- credits, c3cn->tid, c3cn->state); ++ cxgb3i_log_error("%u WR_ACK credits for TID %u with " ++ "nothing pending, state %u\n", ++ credits, c3cn->tid, c3cn->state); + break; + } + if (unlikely(credits < p->csum)) { +@@ -1653,186 +1188,262 @@ static void wr_ack(struct s3_conn *c3cn, + if (c3cn->snd_una != snd_una) { + c3cn->snd_una = snd_una; + dst_confirm(c3cn->dst_cache); +- if (c3cn->snd_una == c3cn->snd_nxt) +- c3cn_reset_flag(c3cn, C3CN_TX_WAIT_IDLE); + } + +- if (skb_queue_len(&c3cn->write_queue) && s3_push_frames(c3cn, 0)) ++ if (skb_queue_len(&c3cn->write_queue) && c3cn_push_tx_frames(c3cn, 0)) + cxgb3i_conn_tx_open(c3cn); + out_free: + __kfree_skb(skb); + } + ++static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) ++{ ++ struct s3_conn *c3cn = ctx; ++ ++ process_cpl_msg(process_wr_ack, c3cn, skb); ++ return 0; ++} ++ + /* +- * Handle a peer FIN. ++ * for each connection, pre-allocate skbs needed for close/abort requests. So ++ * that we can service the request right away. + */ +-static void do_peer_fin(struct s3_conn *c3cn, struct sk_buff *skb) ++static void c3cn_free_cpl_skbs(struct s3_conn *c3cn) + { +- int keep = 0; +- +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); ++ if (c3cn->cpl_close) ++ kfree_skb(c3cn->cpl_close); ++ if (c3cn->cpl_abort_req) ++ kfree_skb(c3cn->cpl_abort_req); ++ if (c3cn->cpl_abort_rpl) ++ kfree_skb(c3cn->cpl_abort_rpl); ++} + +- if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) +- goto out; ++static int c3cn_alloc_cpl_skbs(struct s3_conn *c3cn) ++{ ++ c3cn->cpl_close = alloc_skb(sizeof(struct cpl_close_con_req), ++ GFP_KERNEL); ++ if (!c3cn->cpl_close) ++ return -ENOMEM; ++ skb_put(c3cn->cpl_close, sizeof(struct cpl_close_con_req)); + +- c3cn->shutdown |= C3CN_RCV_SHUTDOWN; +- c3cn_set_flag(c3cn, C3CN_DONE); ++ c3cn->cpl_abort_req = alloc_skb(sizeof(struct cpl_abort_req), ++ GFP_KERNEL); ++ if (!c3cn->cpl_abort_req) ++ goto free_cpl_skbs; ++ skb_put(c3cn->cpl_abort_req, sizeof(struct cpl_abort_req)); ++ ++ c3cn->cpl_abort_rpl = alloc_skb(sizeof(struct cpl_abort_rpl), ++ GFP_KERNEL); ++ if (!c3cn->cpl_abort_rpl) ++ goto free_cpl_skbs; ++ skb_put(c3cn->cpl_abort_rpl, sizeof(struct cpl_abort_rpl)); + +- switch (c3cn->state) { +- case C3CN_STATE_ESTABLISHED: +- break; +- case C3CN_STATE_CLOSING: +- c3cn_done(c3cn); +- break; +- default: +- printk(KERN_ERR +- "%s: TID %u received PEER_CLOSE in bad state %d\n", +- c3cn->cdev->name, c3cn->tid, c3cn->state); +- } ++ return 0; + +- cxgb3i_conn_closing(c3cn); +-out: +- if (!keep) +- __kfree_skb(skb); ++free_cpl_skbs: ++ c3cn_free_cpl_skbs(c3cn); ++ return -ENOMEM; + } + +-/* +- * Process abort requests. If we are waiting for an ABORT_RPL we ignore this +- * request except that we need to reply to it. ++/** ++ * c3cn_release_offload_resources - release offload resource ++ * @c3cn: the offloaded iscsi tcp connection. ++ * Release resources held by an offload connection (TID, L2T entry, etc.) + */ +-static void process_abort_req(struct s3_conn *c3cn, +- struct sk_buff *skb) ++static void c3cn_release_offload_resources(struct s3_conn *c3cn) + { +- int rst_status = CPL_ABORT_NO_RST; +- const struct cpl_abort_req_rss *req = cplhdr(skb); +- +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); ++ struct t3cdev *cdev = c3cn->cdev; ++ unsigned int tid = c3cn->tid; + +- if (!c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) { +- c3cn_set_flag(c3cn, C3CN_ABORT_REQ_RCVD); +- c3cn_set_flag(c3cn, C3CN_ABORT_SHUTDOWN); +- __kfree_skb(skb); ++ if (!cdev) + return; +- } +- c3cn_reset_flag(c3cn, C3CN_ABORT_REQ_RCVD); + +- /* +- * Three cases to consider: +- * a) We haven't sent an abort_req; close the connection. +- * b) We have sent a post-close abort_req that will get to TP too late +- * and will generate a CPL_ERR_ABORT_FAILED reply. The reply will +- * be ignored and the connection should be closed now. +- * c) We have sent a regular abort_req that will get to TP too late. +- * That will generate an abort_rpl with status 0, wait for it. +- */ +- send_abort_rpl(skb, c3cn->cdev, rst_status); ++ c3cn->qset = 0; + +- if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { +- c3cn->err = +- abort_status_to_errno(c3cn, req->status, &rst_status); ++ c3cn_free_cpl_skbs(c3cn); + +- c3cn_done(c3cn); ++ if (c3cn->wr_avail != c3cn->wr_max) { ++ purge_wr_queue(c3cn); ++ reset_wr_list(c3cn); + } +-} + +-/* +- * Process abort replies. We only process these messages if we anticipate +- * them as the coordination between SW and HW in this area is somewhat lacking +- * and sometimes we get ABORT_RPLs after we are done with the connection that +- * originated the ABORT_REQ. +- */ +-static void process_abort_rpl(struct s3_conn *c3cn, +- struct sk_buff *skb) +-{ +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); ++ if (c3cn->l2t) { ++ l2t_release(L2DATA(cdev), c3cn->l2t); ++ c3cn->l2t = NULL; ++ } + +- if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) { +- if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_RCVD)) +- c3cn_set_flag(c3cn, C3CN_ABORT_RPL_RCVD); +- else { +- c3cn_reset_flag(c3cn, C3CN_ABORT_RPL_RCVD); +- c3cn_reset_flag(c3cn, C3CN_ABORT_RPL_PENDING); +- BUG_ON(c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)); +- c3cn_done(c3cn); +- } ++ if (c3cn->state == C3CN_STATE_CONNECTING) /* we have ATID */ ++ s3_free_atid(cdev, tid); ++ else { /* we have TID */ ++ cxgb3_remove_tid(cdev, (void *)c3cn, tid); ++ c3cn_put(c3cn); + } +- __kfree_skb(skb); ++ ++ c3cn->cdev = NULL; + } + +-/* +- * Process a peer ACK to our FIN. ++/** ++ * cxgb3i_c3cn_create - allocate and initialize an s3_conn structure ++ * returns the s3_conn structure allocated. + */ +-static void process_close_con_rpl(struct s3_conn *c3cn, +- struct sk_buff *skb) ++struct s3_conn *cxgb3i_c3cn_create(void) + { +- struct cpl_close_con_rpl *rpl = cplhdr(skb); ++ struct s3_conn *c3cn; + +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); ++ c3cn = kzalloc(sizeof(*c3cn), GFP_KERNEL); ++ if (!c3cn) ++ return NULL; + +- c3cn->snd_una = ntohl(rpl->snd_nxt) - 1; /* exclude FIN */ ++ /* pre-allocate close/abort cpl, so we don't need to wait for memory ++ when close/abort is requested. */ ++ if (c3cn_alloc_cpl_skbs(c3cn) < 0) ++ goto free_c3cn; + +- if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) +- goto out; ++ c3cn_conn_debug("alloc c3cn 0x%p.\n", c3cn); + +- if (c3cn->state == C3CN_STATE_CLOSING) { +- c3cn_done(c3cn); +- } else +- printk(KERN_ERR +- "%s: TID %u received CLOSE_CON_RPL in bad state %d\n", +- c3cn->cdev->name, c3cn->tid, c3cn->state); +-out: +- kfree_skb(skb); ++ c3cn->flags = 0; ++ spin_lock_init(&c3cn->lock); ++ atomic_set(&c3cn->refcnt, 1); ++ skb_queue_head_init(&c3cn->receive_queue); ++ skb_queue_head_init(&c3cn->write_queue); ++ setup_timer(&c3cn->retry_timer, NULL, (unsigned long)c3cn); ++ rwlock_init(&c3cn->callback_lock); ++ ++ return c3cn; ++ ++free_c3cn: ++ kfree(c3cn); ++ return NULL; + } + +-/* +- * Random utility functions for CPL message processing ... +- * ======================================================= +- */ ++static void c3cn_active_close(struct s3_conn *c3cn) ++{ ++ int data_lost; ++ int close_req = 0; ++ ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ ++ dst_confirm(c3cn->dst_cache); ++ ++ c3cn_hold(c3cn); ++ spin_lock_bh(&c3cn->lock); ++ ++ data_lost = skb_queue_len(&c3cn->receive_queue); ++ __skb_queue_purge(&c3cn->receive_queue); ++ ++ switch (c3cn->state) { ++ case C3CN_STATE_CLOSED: ++ case C3CN_STATE_ACTIVE_CLOSE: ++ case C3CN_STATE_CLOSE_WAIT_1: ++ case C3CN_STATE_CLOSE_WAIT_2: ++ case C3CN_STATE_ABORTING: ++ /* nothing need to be done */ ++ break; ++ case C3CN_STATE_CONNECTING: ++ /* defer until cpl_act_open_rpl or cpl_act_establish */ ++ c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED); ++ break; ++ case C3CN_STATE_ESTABLISHED: ++ close_req = 1; ++ c3cn_set_state(c3cn, C3CN_STATE_ACTIVE_CLOSE); ++ break; ++ case C3CN_STATE_PASSIVE_CLOSE: ++ close_req = 1; ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_2); ++ break; ++ } ++ ++ if (close_req) { ++ if (data_lost) ++ /* Unread data was tossed, zap the connection. */ ++ send_abort_req(c3cn); ++ else ++ send_close_req(c3cn); ++ } ++ ++ spin_unlock_bh(&c3cn->lock); ++ c3cn_put(c3cn); ++} + + /** +- * find_best_mtu - find the entry in the MTU table closest to an MTU +- * @d: TOM state +- * @mtu: the target MTU +- * +- * Returns the index of the value in the MTU table that is closest to but +- * does not exceed the target MTU. ++ * cxgb3i_c3cn_release - close and release an iscsi tcp connection and any ++ * resource held ++ * @c3cn: the iscsi tcp connection + */ +-static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu) ++void cxgb3i_c3cn_release(struct s3_conn *c3cn) + { +- int i = 0; +- +- while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu) +- ++i; +- return i; ++ c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ if (likely(c3cn->state != C3CN_STATE_CONNECTING)) ++ c3cn_active_close(c3cn); ++ else ++ c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED); ++ c3cn_put(c3cn); + } + +-static unsigned int select_mss(struct s3_conn *c3cn, unsigned int pmtu) ++static int is_cxgb3_dev(struct net_device *dev) + { +- unsigned int idx; +- struct dst_entry *dst = c3cn->dst_cache; +- struct t3cdev *cdev = c3cn->cdev; +- const struct t3c_data *td = T3C_DATA(cdev); +- u16 advmss = dst_metric(dst, RTAX_ADVMSS); ++ struct cxgb3i_sdev_data *cdata; + +- if (advmss > pmtu - 40) +- advmss = pmtu - 40; +- if (advmss < td->mtus[0] - 40) +- advmss = td->mtus[0] - 40; +- idx = find_best_mtu(td, advmss + 40); +- return idx; ++ write_lock(&cdata_rwlock); ++ list_for_each_entry(cdata, &cdata_list, list) { ++ struct adap_ports *ports = &cdata->ports; ++ int i; ++ ++ for (i = 0; i < ports->nports; i++) ++ if (dev == ports->lldevs[i]) { ++ write_unlock(&cdata_rwlock); ++ return 1; ++ } ++ } ++ write_unlock(&cdata_rwlock); ++ return 0; + } + +-static void fail_act_open(struct s3_conn *c3cn, int errno) ++/** ++ * cxgb3_egress_dev - return the cxgb3 egress device ++ * @root_dev: the root device anchoring the search ++ * @c3cn: the connection used to determine egress port in bonding mode ++ * @context: in bonding mode, indicates a connection set up or failover ++ * ++ * Return egress device or NULL if the egress device isn't one of our ports. ++ */ ++static struct net_device *cxgb3_egress_dev(struct net_device *root_dev, ++ struct s3_conn *c3cn, ++ int context) + { +- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n", +- c3cn, c3cn->state, c3cn->flags); ++ while (root_dev) { ++ if (root_dev->priv_flags & IFF_802_1Q_VLAN) ++ root_dev = vlan_dev_real_dev(root_dev); ++ else if (is_cxgb3_dev(root_dev)) ++ return root_dev; ++ else ++ return NULL; ++ } ++ return NULL; ++} + +- c3cn->err = errno; +- c3cn_done(c3cn); ++static struct rtable *find_route(__be32 saddr, __be32 daddr, ++ __be16 sport, __be16 dport) ++{ ++ struct rtable *rt; ++ struct flowi fl = { ++ .oif = 0, ++ .nl_u = { ++ .ip4_u = { ++ .daddr = daddr, ++ .saddr = saddr, ++ .tos = 0 } }, ++ .proto = IPPROTO_TCP, ++ .uli_u = { ++ .ports = { ++ .sport = sport, ++ .dport = dport } } }; ++ ++ if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0)) ++ return NULL; ++ return rt; + } + + /* +@@ -1847,195 +1458,355 @@ static void init_offload_conn(struct s3_ + c3cn->wr_unacked = 0; + c3cn->mss_idx = select_mss(c3cn, dst_mtu(dst)); + +- c3cn->ctrl_skb_cache = alloc_skb(CTRL_SKB_LEN, gfp_any()); + reset_wr_list(c3cn); + } + +-static void act_open_retry_timer(unsigned long data) ++static int initiate_act_open(struct s3_conn *c3cn, struct net_device *dev) + { ++ struct cxgb3i_sdev_data *cdata = NDEV2CDATA(dev); ++ struct t3cdev *cdev = cdata->cdev; ++ struct dst_entry *dst = c3cn->dst_cache; + struct sk_buff *skb; +- struct s3_conn *c3cn = (struct s3_conn *)data; + +- c3cn_conn_debug("c3cn 0x%p, state 0x%x.\n", c3cn, c3cn->state); ++ c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n", ++ c3cn, c3cn->state, c3cn->flags); ++ /* ++ * Initialize connection data. Note that the flags and ULP mode are ++ * initialized higher up ... ++ */ ++ c3cn->dev = dev; ++ c3cn->cdev = cdev; ++ c3cn->tid = cxgb3_alloc_atid(cdev, cdata->client, c3cn); ++ if (c3cn->tid < 0) ++ goto out_err; + +- spin_lock(&c3cn->lock); +- skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_ATOMIC); ++ c3cn->qset = 0; ++ c3cn->l2t = t3_l2t_get(cdev, dst->neighbour, dev); ++ if (!c3cn->l2t) ++ goto free_tid; ++ ++ skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_KERNEL); + if (!skb) +- fail_act_open(c3cn, ENOMEM); +- else { +- skb->sk = (struct sock *)c3cn; +- set_arp_failure_handler(skb, act_open_req_arp_failure); +- mk_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); +- l2t_send(c3cn->cdev, skb, c3cn->l2t); +- } +- spin_unlock(&c3cn->lock); +- c3cn_put(c3cn); +-} ++ goto free_l2t; + +-/* +- * Convert an ACT_OPEN_RPL status to a Linux errno. +- */ +-static int act_open_rpl_status_to_errno(int status) +-{ +- switch (status) { +- case CPL_ERR_CONN_RESET: +- return ECONNREFUSED; +- case CPL_ERR_ARP_MISS: +- return EHOSTUNREACH; +- case CPL_ERR_CONN_TIMEDOUT: +- return ETIMEDOUT; +- case CPL_ERR_TCAM_FULL: +- return ENOMEM; +- case CPL_ERR_CONN_EXIST: +- printk(KERN_ERR "ACTIVE_OPEN_RPL: 4-tuple in use\n"); +- return EADDRINUSE; +- default: +- return EIO; +- } ++ skb->sk = (struct sock *)c3cn; ++ set_arp_failure_handler(skb, act_open_req_arp_failure); ++ ++ c3cn_hold(c3cn); ++ ++ init_offload_conn(c3cn, cdev, dst); ++ c3cn->err = 0; ++ ++ make_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t); ++ l2t_send(cdev, skb, c3cn->l2t); ++ return 0; ++ ++free_l2t: ++ l2t_release(L2DATA(cdev), c3cn->l2t); ++free_tid: ++ s3_free_atid(cdev, c3cn->tid); ++ c3cn->tid = 0; ++out_err: ++ return -1; + } + +-/* +- * Convert the status code of an ABORT_REQ into a Linux error code. Also +- * indicate whether RST should be sent in response. ++ ++/** ++ * cxgb3i_c3cn_connect - initiates an iscsi tcp connection to a given address ++ * @c3cn: the iscsi tcp connection ++ * @usin: destination address ++ * ++ * return 0 if active open request is sent, < 0 otherwise. + */ +-static int abort_status_to_errno(struct s3_conn *c3cn, +- int abort_reason, int *need_rst) ++int cxgb3i_c3cn_connect(struct s3_conn *c3cn, struct sockaddr_in *usin) + { +- switch (abort_reason) { +- case CPL_ERR_BAD_SYN: /* fall through */ +- case CPL_ERR_CONN_RESET: +- return c3cn->state == C3CN_STATE_CLOSING ? EPIPE : ECONNRESET; +- case CPL_ERR_XMIT_TIMEDOUT: +- case CPL_ERR_PERSIST_TIMEDOUT: +- case CPL_ERR_FINWAIT2_TIMEDOUT: +- case CPL_ERR_KEEPALIVE_TIMEDOUT: +- return ETIMEDOUT; +- default: +- return EIO; ++ struct rtable *rt; ++ struct net_device *dev; ++ struct cxgb3i_sdev_data *cdata; ++ struct t3cdev *cdev; ++ __be32 sipv4; ++ int err; ++ ++ if (usin->sin_family != AF_INET) ++ return -EAFNOSUPPORT; ++ ++ c3cn->daddr.sin_port = usin->sin_port; ++ c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr; ++ ++ rt = find_route(c3cn->saddr.sin_addr.s_addr, ++ c3cn->daddr.sin_addr.s_addr, ++ c3cn->saddr.sin_port, ++ c3cn->daddr.sin_port); ++ if (rt == NULL) { ++ c3cn_conn_debug("NO route to 0x%x, port %u.\n", ++ c3cn->daddr.sin_addr.s_addr, ++ ntohs(c3cn->daddr.sin_port)); ++ return -ENETUNREACH; + } +-} + +-static void send_abort_rpl(struct sk_buff *skb, struct t3cdev *cdev, +- int rst_status) +-{ +- struct sk_buff *reply_skb; +- struct cpl_abort_req_rss *req = cplhdr(skb); ++ if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { ++ c3cn_conn_debug("multi-cast route to 0x%x, port %u.\n", ++ c3cn->daddr.sin_addr.s_addr, ++ ntohs(c3cn->daddr.sin_port)); ++ ip_rt_put(rt); ++ return -ENETUNREACH; ++ } + +- reply_skb = get_cpl_reply_skb(skb, sizeof(struct cpl_abort_rpl), +- gfp_any()); ++ if (!c3cn->saddr.sin_addr.s_addr) ++ c3cn->saddr.sin_addr.s_addr = rt->rt_src; + +- reply_skb->priority = CPL_PRIORITY_DATA; +- set_abort_rpl_wr(reply_skb, GET_TID(req), rst_status); +- kfree_skb(skb); +- cxgb3_ofld_send(cdev, reply_skb); +-} ++ /* now commit destination to connection */ ++ c3cn->dst_cache = &rt->u.dst; + +-/* +- * Returns an sk_buff for a reply CPL message of size len. If the input +- * sk_buff has no other users it is trimmed and reused, otherwise a new buffer +- * is allocated. The input skb must be of size at least len. Note that this +- * operation does not destroy the original skb data even if it decides to reuse +- * the buffer. +- */ +-static struct sk_buff *get_cpl_reply_skb(struct sk_buff *skb, size_t len, +- gfp_t gfp) +-{ +- if (likely(!skb_cloned(skb))) { +- BUG_ON(skb->len < len); +- __skb_trim(skb, len); +- skb_get(skb); +- } else { +- skb = alloc_skb(len, gfp); +- if (skb) +- __skb_put(skb, len); ++ /* try to establish an offloaded connection */ ++ dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0); ++ if (dev == NULL) { ++ c3cn_conn_debug("c3cn 0x%p, egress dev NULL.\n", c3cn); ++ return -ENETUNREACH; + } +- return skb; ++ cdata = NDEV2CDATA(dev); ++ cdev = cdata->cdev; ++ ++ /* get a source port if one hasn't been provided */ ++ err = c3cn_get_port(c3cn, cdata); ++ if (err) ++ return err; ++ ++ c3cn_conn_debug("c3cn 0x%p get port %u.\n", ++ c3cn, ntohs(c3cn->saddr.sin_port)); ++ ++ sipv4 = cxgb3i_get_private_ipv4addr(dev); ++ if (!sipv4) { ++ c3cn_conn_debug("c3cn 0x%p, iscsi ip not configured.\n", c3cn); ++ sipv4 = c3cn->saddr.sin_addr.s_addr; ++ cxgb3i_set_private_ipv4addr(dev, sipv4); ++ } else ++ c3cn->saddr.sin_addr.s_addr = sipv4; ++ ++ c3cn_conn_debug("c3cn 0x%p, %u.%u.%u.%u,%u-%u.%u.%u.%u,%u SYN_SENT.\n", ++ c3cn, NIPQUAD(c3cn->saddr.sin_addr.s_addr), ++ ntohs(c3cn->saddr.sin_port), ++ NIPQUAD(c3cn->daddr.sin_addr.s_addr), ++ ntohs(c3cn->daddr.sin_port)); ++ ++ c3cn_set_state(c3cn, C3CN_STATE_CONNECTING); ++ if (!initiate_act_open(c3cn, dev)) ++ return 0; ++ ++ /* ++ * If we get here, we don't have an offload connection so simply ++ * return a failure. ++ */ ++ err = -ENOTSUPP; ++ ++ /* ++ * This trashes the connection and releases the local port, ++ * if necessary. ++ */ ++ c3cn_conn_debug("c3cn 0x%p -> CLOSED.\n", c3cn); ++ c3cn_set_state(c3cn, C3CN_STATE_CLOSED); ++ ip_rt_put(rt); ++ c3cn_put_port(c3cn); ++ c3cn->daddr.sin_port = 0; ++ return err; + } + +-/* +- * Release resources held by an offload connection (TID, L2T entry, etc.) ++/** ++ * cxgb3i_c3cn_rx_credits - ack received tcp data. ++ * @c3cn: iscsi tcp connection ++ * @copied: # of bytes processed ++ * ++ * Called after some received data has been read. It returns RX credits ++ * to the HW for the amount of data processed. + */ +-static void t3_release_offload_resources(struct s3_conn *c3cn) ++void cxgb3i_c3cn_rx_credits(struct s3_conn *c3cn, int copied) + { +- struct t3cdev *cdev = c3cn->cdev; +- unsigned int tid = c3cn->tid; ++ struct t3cdev *cdev; ++ int must_send; ++ u32 credits, dack = 0; + +- if (!cdev) ++ if (c3cn->state != C3CN_STATE_ESTABLISHED) + return; + +- c3cn->qset = 0; ++ credits = c3cn->copied_seq - c3cn->rcv_wup; ++ if (unlikely(!credits)) ++ return; + +- kfree_skb(c3cn->ctrl_skb_cache); +- c3cn->ctrl_skb_cache = NULL; ++ cdev = c3cn->cdev; + +- if (c3cn->wr_avail != c3cn->wr_max) { +- purge_wr_queue(c3cn); +- reset_wr_list(c3cn); ++ if (unlikely(cxgb3_rx_credit_thres == 0)) ++ return; ++ ++ dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1); ++ ++ /* ++ * For coalescing to work effectively ensure the receive window has ++ * at least 16KB left. ++ */ ++ must_send = credits + 16384 >= cxgb3_rcv_win; ++ ++ if (must_send || credits >= cxgb3_rx_credit_thres) ++ c3cn->rcv_wup += send_rx_credits(c3cn, credits, dack); ++} ++ ++/** ++ * cxgb3i_c3cn_send_pdus - send the skbs containing iscsi pdus ++ * @c3cn: iscsi tcp connection ++ * @skb: skb contains the iscsi pdu ++ * ++ * Add a list of skbs to a connection send queue. The skbs must comply with ++ * the max size limit of the device and have a headroom of at least ++ * TX_HEADER_LEN bytes. ++ * Return # of bytes queued. ++ */ ++int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb) ++{ ++ struct sk_buff *next; ++ int err, copied = 0; ++ ++ spin_lock_bh(&c3cn->lock); ++ ++ if (c3cn->state != C3CN_STATE_ESTABLISHED) { ++ c3cn_tx_debug("c3cn 0x%p, not in est. state %u.\n", ++ c3cn, c3cn->state); ++ err = -EAGAIN; ++ goto out_err; + } + +- if (c3cn->l2t) { +- l2t_release(L2DATA(cdev), c3cn->l2t); +- c3cn->l2t = NULL; ++ err = -EPIPE; ++ if (c3cn->err) { ++ c3cn_tx_debug("c3cn 0x%p, err %d.\n", c3cn, c3cn->err); ++ goto out_err; + } + +- if (c3cn->state == C3CN_STATE_SYN_SENT) /* we have ATID */ +- free_atid(cdev, tid); +- else { /* we have TID */ +- cxgb3_remove_tid(cdev, (void *)c3cn, tid); +- c3cn_put(c3cn); ++ while (skb) { ++ int frags = skb_shinfo(skb)->nr_frags + ++ (skb->len != skb->data_len); ++ ++ if (unlikely(skb_headroom(skb) < TX_HEADER_LEN)) { ++ c3cn_tx_debug("c3cn 0x%p, skb head.\n", c3cn); ++ err = -EINVAL; ++ goto out_err; ++ } ++ ++ if (frags >= SKB_WR_LIST_SIZE) { ++ cxgb3i_log_error("c3cn 0x%p, tx frags %d, len %u,%u.\n", ++ c3cn, skb_shinfo(skb)->nr_frags, ++ skb->len, skb->data_len); ++ err = -EINVAL; ++ goto out_err; ++ } ++ ++ next = skb->next; ++ skb->next = NULL; ++ skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND | C3CB_FLAG_NEED_HDR); ++ copied += skb->len; ++ c3cn->write_seq += skb->len + ulp_extra_len(skb); ++ skb = next; + } ++done: ++ if (likely(skb_queue_len(&c3cn->write_queue))) ++ c3cn_push_tx_frames(c3cn, 1); ++ spin_unlock_bh(&c3cn->lock); ++ return copied; + +- c3cn->cdev = NULL; ++out_err: ++ if (copied == 0 && err == -EPIPE) ++ copied = c3cn->err ? c3cn->err : -EPIPE; ++ goto done; + } + +-/* +- * Handles Rx data that arrives in a state where the connection isn't +- * accepting new data. +- */ +-static void handle_excess_rx(struct s3_conn *c3cn, struct sk_buff *skb) ++static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata) + { +- if (!c3cn_flag(c3cn, C3CN_ABORT_SHUTDOWN)) +- abort_conn(c3cn, skb); ++ struct adap_ports *ports = &cdata->ports; ++ int i; + +- kfree_skb(skb); ++ for (i = 0; i < ports->nports; i++) ++ NDEV2CDATA(ports->lldevs[i]) = NULL; ++ cxgb3i_free_big_mem(cdata); + } + +-/* +- * Like get_cpl_reply_skb() but the returned buffer starts out empty. +- */ +-static struct sk_buff *__get_cpl_reply_skb(struct sk_buff *skb, size_t len, +- gfp_t gfp) ++void cxgb3i_sdev_cleanup(void) + { +- if (likely(!skb_cloned(skb) && !skb->data_len)) { +- __skb_trim(skb, 0); +- skb_get(skb); +- } else +- skb = alloc_skb(len, gfp); +- return skb; ++ struct cxgb3i_sdev_data *cdata; ++ ++ write_lock(&cdata_rwlock); ++ list_for_each_entry(cdata, &cdata_list, list) { ++ list_del(&cdata->list); ++ sdev_data_cleanup(cdata); ++ } ++ write_unlock(&cdata_rwlock); + } + +-/* +- * Completes some final bits of initialization for just established connections +- * and changes their state to C3CN_STATE_ESTABLISHED. +- * +- * snd_isn here is the ISN after the SYN, i.e., the true ISN + 1. ++int cxgb3i_sdev_init(cxgb3_cpl_handler_func *cpl_handlers) ++{ ++ cpl_handlers[CPL_ACT_ESTABLISH] = do_act_establish; ++ cpl_handlers[CPL_ACT_OPEN_RPL] = do_act_open_rpl; ++ cpl_handlers[CPL_PEER_CLOSE] = do_peer_close; ++ cpl_handlers[CPL_ABORT_REQ_RSS] = do_abort_req; ++ cpl_handlers[CPL_ABORT_RPL_RSS] = do_abort_rpl; ++ cpl_handlers[CPL_CLOSE_CON_RPL] = do_close_con_rpl; ++ cpl_handlers[CPL_TX_DMA_ACK] = do_wr_ack; ++ cpl_handlers[CPL_ISCSI_HDR] = do_iscsi_hdr; ++ ++ if (cxgb3_max_connect > CXGB3I_MAX_CONN) ++ cxgb3_max_connect = CXGB3I_MAX_CONN; ++ return 0; ++} ++ ++/** ++ * cxgb3i_sdev_add - allocate and initialize resources for each adapter found ++ * @cdev: t3cdev adapter ++ * @client: cxgb3 driver client + */ +-static void make_established(struct s3_conn *c3cn, u32 snd_isn, +- unsigned int opt) ++void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client) + { +- c3cn_conn_debug("c3cn 0x%p, state 0x%x.\n", c3cn, c3cn->state); ++ struct cxgb3i_sdev_data *cdata; ++ struct ofld_page_info rx_page_info; ++ unsigned int wr_len; ++ int mapsize = DIV_ROUND_UP(cxgb3_max_connect, ++ 8 * sizeof(unsigned long)); ++ int i; + +- c3cn->write_seq = c3cn->snd_nxt = c3cn->snd_una = snd_isn; ++ cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL); ++ if (!cdata) ++ return; + +- /* +- * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't +- * pass through opt0. +- */ +- if (cxgb3_rcv_win > (M_RCV_BUFSIZ << 10)) +- c3cn->rcv_wup -= cxgb3_rcv_win - (M_RCV_BUFSIZ << 10); ++ if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 || ++ cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 || ++ cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) ++ goto free_cdata; + +- dst_confirm(c3cn->dst_cache); ++ s3_init_wr_tab(wr_len); + +- smp_mb(); +- c3cn_set_state(c3cn, C3CN_STATE_ESTABLISHED); ++ INIT_LIST_HEAD(&cdata->list); ++ cdata->cdev = cdev; ++ cdata->client = client; ++ ++ for (i = 0; i < cdata->ports.nports; i++) ++ NDEV2CDATA(cdata->ports.lldevs[i]) = cdata; ++ ++ write_lock(&cdata_rwlock); ++ list_add_tail(&cdata->list, &cdata_list); ++ write_unlock(&cdata_rwlock); ++ ++ return; ++ ++free_cdata: ++ cxgb3i_free_big_mem(cdata); ++} ++ ++/** ++ * cxgb3i_sdev_remove - free the allocated resources for the adapter ++ * @cdev: t3cdev adapter ++ */ ++void cxgb3i_sdev_remove(struct t3cdev *cdev) ++{ ++ struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev); ++ ++ write_lock(&cdata_rwlock); ++ list_del(&cdata->list); ++ write_unlock(&cdata_rwlock); ++ ++ sdev_data_cleanup(cdata); + } +--- a/drivers/scsi/cxgb3i/cxgb3i_offload.h ++++ b/drivers/scsi/cxgb3i/cxgb3i_offload.h +@@ -1,12 +1,15 @@ + /* +- * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. ++ * cxgb3i_offload.h: Chelsio S3xx iscsi offloaded tcp connection management + * +- * Written by Dimitris Michailidis (dm@chelsio.com) ++ * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this + * release for licensing terms and conditions. ++ * ++ * Written by: Dimitris Michailidis (dm@chelsio.com) ++ * Karen Xie (kxie@chelsio.com) + */ + + #ifndef _CXGB3I_OFFLOAD_H +@@ -23,83 +26,104 @@ + #define cxgb3i_log_error(fmt...) printk(KERN_ERR "cxgb3i: ERR! " fmt) + #define cxgb3i_log_warn(fmt...) printk(KERN_WARNING "cxgb3i: WARN! " fmt) + #define cxgb3i_log_info(fmt...) printk(KERN_INFO "cxgb3i: " fmt) +- +-#ifdef __DEBUG_CXGB3I__ + #define cxgb3i_log_debug(fmt, args...) \ + printk(KERN_INFO "cxgb3i: %s - " fmt, __func__ , ## args) +-#else +-#define cxgb3i_log_debug(fmt...) +-#endif +- +-#ifdef __DEBUG_C3CN_CONN__ +-#define c3cn_conn_debug cxgb3i_log_debug +-#else +-#define c3cn_conn_debug(fmt...) +-#endif + +-/* +- * Data structure to keep track of cxgb3 connection. ++/** ++ * struct s3_conn - an iscsi tcp connection structure ++ * ++ * @dev: net device of with connection ++ * @cdev: adapter t3cdev for net device ++ * @flags: see c3cn_flags below ++ * @tid: connection id assigned by the h/w ++ * @qset: queue set used by connection ++ * @mss_idx: Maximum Segment Size table index ++ * @l2t: ARP resolution entry for offload packets ++ * @wr_max: maximum in-flight writes ++ * @wr_avail: number of writes available ++ * @wr_unacked: writes since last request for completion notification ++ * @wr_pending_head: head of pending write queue ++ * @wr_pending_tail: tail of pending write queue ++ * @cpl_close: skb for cpl_close_req ++ * @cpl_abort_req: skb for cpl_abort_req ++ * @cpl_abort_rpl: skb for cpl_abort_rpl ++ * @lock: connection status lock ++ * @refcnt: reference count on connection ++ * @state: connection state ++ * @saddr: source ip/port address ++ * @daddr: destination ip/port address ++ * @dst_cache: reference to destination route ++ * @receive_queue: received PDUs ++ * @write_queue: un-pushed pending writes ++ * @retry_timer: retry timer for various operations ++ * @err: connection error status ++ * @callback_lock: lock for opaque user context ++ * @user_data: opaque user context ++ * @rcv_nxt: next receive seq. # ++ * @copied_seq: head of yet unread data ++ * @rcv_wup: rcv_nxt on last window update sent ++ * @snd_nxt: next sequence we send ++ * @snd_una: first byte we want an ack for ++ * @write_seq: tail+1 of data held in send buffer + */ + struct s3_conn { +- struct net_device *dev; /* net device of with connection */ +- struct t3cdev *cdev; /* adapter t3cdev for net device */ +- unsigned long flags; /* see c3cn_flags below */ +- int tid; /* ID of TCP Control Block */ +- int qset; /* queue Set used by connection */ +- int mss_idx; /* Maximum Segment Size table index */ +- struct l2t_entry *l2t; /* ARP resolution for offload packets */ +- int wr_max; /* maximum in-flight writes */ +- int wr_avail; /* number of writes available */ +- int wr_unacked; /* writes since last request for */ +- /* completion notification */ +- struct sk_buff *wr_pending_head;/* head of pending write queue */ +- struct sk_buff *wr_pending_tail;/* tail of pending write queue */ +- struct sk_buff *ctrl_skb_cache; /* single entry cached skb for */ +- /* short-term control operations */ +- spinlock_t lock; /* connection status lock */ +- atomic_t refcnt; /* reference count on connection */ +- volatile unsigned int state; /* connection state */ +- struct sockaddr_in saddr; /* source IP/port address */ +- struct sockaddr_in daddr; /* destination IP/port address */ +- struct dst_entry *dst_cache; /* reference to destination route */ +- unsigned char shutdown; /* shutdown status */ +- struct sk_buff_head receive_queue;/* received PDUs */ +- struct sk_buff_head write_queue;/* un-pushed pending writes */ +- +- struct timer_list retry_timer; /* retry timer for various operations */ +- int err; /* connection error status */ +- rwlock_t callback_lock; /* lock for opaque user context */ +- void *user_data; /* opaque user context */ +- +- u32 rcv_nxt; /* what we want to receive next */ +- u32 copied_seq; /* head of yet unread data */ +- u32 rcv_wup; /* rcv_nxt on last window update sent */ +- u32 snd_nxt; /* next sequence we send */ +- u32 snd_una; /* first byte we want an ack for */ +- +- u32 write_seq; /* tail+1 of data held in send buffer */ +-}; +- +-/* Flags in c3cn->shutdown */ +-#define C3CN_RCV_SHUTDOWN 0x1 +-#define C3CN_SEND_SHUTDOWN 0x2 +-#define C3CN_SHUTDOWN_MASK (C3CN_RCV_SHUTDOWN | C3CN_SEND_SHUTDOWN) ++ struct net_device *dev; ++ struct t3cdev *cdev; ++ unsigned long flags; ++ int tid; ++ int qset; ++ int mss_idx; ++ struct l2t_entry *l2t; ++ int wr_max; ++ int wr_avail; ++ int wr_unacked; ++ struct sk_buff *wr_pending_head; ++ struct sk_buff *wr_pending_tail; ++ struct sk_buff *cpl_close; ++ struct sk_buff *cpl_abort_req; ++ struct sk_buff *cpl_abort_rpl; ++ spinlock_t lock; ++ atomic_t refcnt; ++ volatile unsigned int state; ++ struct sockaddr_in saddr; ++ struct sockaddr_in daddr; ++ struct dst_entry *dst_cache; ++ struct sk_buff_head receive_queue; ++ struct sk_buff_head write_queue; ++ struct timer_list retry_timer; ++ int err; ++ rwlock_t callback_lock; ++ void *user_data; ++ ++ u32 rcv_nxt; ++ u32 copied_seq; ++ u32 rcv_wup; ++ u32 snd_nxt; ++ u32 snd_una; ++ u32 write_seq; ++}; + + /* +- * connection state bitmap +- */ +-#define C3CN_STATE_CLOSE 0x1 +-#define C3CN_STATE_SYN_SENT 0x2 +-#define C3CN_STATE_ESTABLISHED 0x4 +-#define C3CN_STATE_CLOSING 0x8 +-#define C3CN_STATE_ABORING 0x10 +- +-#define C3CN_STATE_MASK 0xFF ++ * connection state ++ */ ++enum conn_states { ++ C3CN_STATE_CONNECTING = 1, ++ C3CN_STATE_ESTABLISHED, ++ C3CN_STATE_ACTIVE_CLOSE, ++ C3CN_STATE_PASSIVE_CLOSE, ++ C3CN_STATE_CLOSE_WAIT_1, ++ C3CN_STATE_CLOSE_WAIT_2, ++ C3CN_STATE_ABORTING, ++ C3CN_STATE_CLOSED, ++}; + +-static inline unsigned int c3cn_in_state(const struct s3_conn *c3cn, +- unsigned int states) ++static inline unsigned int c3cn_is_closing(const struct s3_conn *c3cn) + { +- return states & c3cn->state; ++ return c3cn->state >= C3CN_STATE_ACTIVE_CLOSE; ++} ++static inline unsigned int c3cn_is_established(const struct s3_conn *c3cn) ++{ ++ return c3cn->state == C3CN_STATE_ESTABLISHED; + } + + /* +@@ -108,37 +132,35 @@ static inline unsigned int c3cn_in_state + enum c3cn_flags { + C3CN_ABORT_RPL_RCVD, /* received one ABORT_RPL_RSS message */ + C3CN_ABORT_REQ_RCVD, /* received one ABORT_REQ_RSS message */ +- C3CN_TX_WAIT_IDLE, /* suspend Tx until in-flight data is ACKed */ +- C3CN_ABORT_SHUTDOWN, /* shouldn't send more abort requests */ +- + C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */ +- C3CN_CLOSE_CON_REQUESTED, /* we've sent a close_conn_req */ + C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */ +- C3CN_CLOSE_NEEDED, /* need to be closed */ +- C3CN_DONE, ++ C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */ + }; + +-/* +- * Per adapter data. Linked off of each Ethernet device port on the adapter. ++/** ++ * cxgb3i_sdev_data - Per adapter data. ++ * Linked off of each Ethernet device port on the adapter. + * Also available via the t3cdev structure since we have pointers to our port + * net_device's there ... ++ * ++ * @list: list head to link elements ++ * @cdev: t3cdev adapter ++ * @client: CPL client pointer ++ * @ports: array of adapter ports ++ * @sport_map_next: next index into the port map ++ * @sport_map: source port map + */ + struct cxgb3i_sdev_data { +- struct list_head list; /* links for list of all adapters */ +- struct t3cdev *cdev; /* adapter t3cdev */ +- struct cxgb3_client *client; /* CPL client pointer */ +- struct adap_ports *ports; /* array of adapter ports */ +- unsigned int rx_page_size; /* RX page size */ +- struct sk_buff_head deferq; /* queue for processing replies from */ +- /* worker thread context */ +- struct work_struct deferq_task; /* worker thread */ ++ struct list_head list; ++ struct t3cdev *cdev; ++ struct cxgb3_client *client; ++ struct adap_ports ports; ++ unsigned int sport_map_next; ++ unsigned long sport_map[0]; + }; + #define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr) + #define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev) + +-/* +- * Primary API routines. +- */ + void cxgb3i_sdev_cleanup(void); + int cxgb3i_sdev_init(cxgb3_cpl_handler_func *); + void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *); +@@ -147,20 +169,26 @@ void cxgb3i_sdev_remove(struct t3cdev *) + struct s3_conn *cxgb3i_c3cn_create(void); + int cxgb3i_c3cn_connect(struct s3_conn *, struct sockaddr_in *); + void cxgb3i_c3cn_rx_credits(struct s3_conn *, int); +-int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *, int); ++int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *); + void cxgb3i_c3cn_release(struct s3_conn *); + +-/* +- * Definitions for sk_buff state and ULP mode management. ++/** ++ * cxgb3_skb_cb - control block for received pdu state and ULP mode management. ++ * ++ * @flag: see C3CB_FLAG_* below ++ * @ulp_mode: ULP mode/submode of sk_buff ++ * @seq: tcp sequence number ++ * @ddigest: pdu data digest ++ * @pdulen: recovered pdu length ++ * @ulp_data: scratch area for ULP + */ +- + struct cxgb3_skb_cb { +- __u8 flags; /* see C3CB_FLAG_* below */ +- __u8 ulp_mode; /* ULP mode/submode of sk_buff */ +- __u32 seq; /* sequence number */ +- __u32 ddigest; /* ULP rx_data_ddp selected field */ +- __u32 pdulen; /* ULP rx_data_ddp selected field */ +- __u8 ulp_data[16]; /* scratch area for ULP */ ++ __u8 flags; ++ __u8 ulp_mode; ++ __u32 seq; ++ __u32 ddigest; ++ __u32 pdulen; ++ __u8 ulp_data[16]; + }; + + #define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0])) +@@ -170,28 +198,14 @@ struct cxgb3_skb_cb { + #define skb_ulp_pdulen(skb) (CXGB3_SKB_CB(skb)->pdulen) + #define skb_ulp_data(skb) (CXGB3_SKB_CB(skb)->ulp_data) + +-enum { ++enum c3cb_flags { + C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */ + C3CB_FLAG_NO_APPEND = 1 << 1, /* don't grow this skb */ +- C3CB_FLAG_BARRIER = 1 << 2, /* set TX_WAIT_IDLE after sending */ +- C3CB_FLAG_COMPL = 1 << 4, /* request WR completion */ ++ C3CB_FLAG_COMPL = 1 << 2, /* request WR completion */ + }; + +-/* +- * Top-level CPL message processing used by most CPL messages that +- * pertain to connections. +- */ +-static inline void process_cpl_msg(void (*fn)(struct s3_conn *, +- struct sk_buff *), +- struct s3_conn *c3cn, +- struct sk_buff *skb) +-{ +- spin_lock(&c3cn->lock); +- fn(c3cn, skb); +- spin_unlock(&c3cn->lock); +-} +- +-/* ++/** ++ * sge_opaque_hdr - + * Opaque version of structure the SGE stores at skb->head of TX_DATA packets + * and for which we must reserve space. + */ +@@ -204,9 +218,6 @@ struct sge_opaque_hdr { + #define TX_HEADER_LEN \ + (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) + +-void *cxgb3i_alloc_big_mem(unsigned int); +-void cxgb3i_free_big_mem(void *); +- + /* + * get and set private ip for iscsi traffic + */ +--- a/drivers/scsi/cxgb3i/cxgb3i_ulp2.c ++++ b/drivers/scsi/cxgb3i/cxgb3i_ulp2.c +@@ -312,6 +312,7 @@ u32 cxgb3i_ddp_tag_reserve(struct cxgb3i + page_idx, sgcnt, xferlen, ULP2_DDP_THRESHOLD); + return RESERVED_ITT; + } ++ return RESERVED_ITT; + + gl = ddp_make_gl(xferlen, sgl, sgcnt, gfp); + if (!gl) { +@@ -380,8 +381,14 @@ void cxgb3i_ddp_tag_release(struct cxgb3 + if (idx < snic->tag_format.rsvd_mask) { + struct cxgb3i_ddp_info *ddp = snic->ddp; + struct cxgb3i_gather_list *gl = ddp->gl_map[idx]; +- unsigned int npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> +- PPOD_PAGES_SHIFT; ++ unsigned int npods; ++ ++ if (!gl || !gl->nelem) { ++ cxgb3i_log_warn("release tag 0x%x, idx 0x%x, no gl.\n", ++ tag, idx); ++ return; ++ } ++ npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; + + cxgb3i_tag_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n", + tag, idx, npods); +@@ -469,14 +476,14 @@ static int cxgb3i_conn_read_pdu_skb(stru + (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ? + ISCSI_SEGMENT_DGST_ERR : 0; + if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { +- cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, " +- "itt 0x%x.\n", ++ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, " ++ "ddp'ed, itt 0x%x.\n", + skb, hdr->opcode & ISCSI_OPCODE_MASK, + tcp_conn->in.datalen, hdr->itt); + segment->total_copied = segment->total_size; + } else { +- cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, not ddp'ed, " +- "itt 0x%x.\n", ++ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, " ++ "not ddp'ed, itt 0x%x.\n", + skb, hdr->opcode & ISCSI_OPCODE_MASK, + tcp_conn->in.datalen, hdr->itt); + offset += sizeof(struct cpl_iscsi_hdr_norss); +@@ -613,8 +620,7 @@ int cxgb3i_conn_ulp2_xmit(struct iscsi_c + } + + send_pdu: +- err = cxgb3i_c3cn_send_pdus((struct s3_conn *)tcp_conn->sock, +- skb, MSG_DONTWAIT | MSG_NOSIGNAL); ++ err = cxgb3i_c3cn_send_pdus((struct s3_conn *)tcp_conn->sock, skb); + + if (err > 0) { + int pdulen = hdrlen + datalen + padlen; +@@ -758,7 +764,8 @@ int cxgb3i_adapter_ulp_init(struct cxgb3 + ddp = cxgb3i_alloc_big_mem(sizeof(struct cxgb3i_ddp_info) + + ppmax * + (sizeof(struct cxgb3i_gather_list *) + +- sizeof(struct sk_buff *))); ++ sizeof(struct sk_buff *)), ++ GFP_KERNEL); + if (!ddp) { + cxgb3i_log_warn("snic %s unable to alloc ddp ppod 0x%u, " + "ddp disabled.\n", tdev->name, ppmax); +--- a/drivers/scsi/cxgb3i/cxgb3i_ulp2.h ++++ b/drivers/scsi/cxgb3i/cxgb3i_ulp2.h +@@ -106,4 +106,27 @@ struct cpl_rx_data_ddp_norss { + void cxgb3i_conn_closing(struct s3_conn *); + void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); + void cxgb3i_conn_tx_open(struct s3_conn *c3cn); ++ ++/* ++ * large memory chunk allocation/release ++ * use vmalloc() if kmalloc() fails ++ */ ++static inline void *cxgb3i_alloc_big_mem(unsigned int size, gfp_t gfp) ++{ ++ void *p = kmalloc(size, gfp); ++ ++ if (!p) ++ p = vmalloc(size); ++ if (p) ++ memset(p, 0, size); ++ return p; ++} ++ ++static inline void cxgb3i_free_big_mem(void *addr) ++{ ++ if (is_vmalloc_addr(addr)) ++ vfree(addr); ++ else ++ kfree(addr); ++} + #endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i_ddp.patch b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i_ddp.patch new file mode 100644 index 000000000..46a30835e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/cxgb3i_ddp.patch @@ -0,0 +1,334 @@ +From: Karen Xie +Subject: cxgb3i - added pdu size check and fixed ddp page setup +References: bnc#449519 + +- Added documentation for cxgb3i driver, decribing how to use it to offload + open-iscsi initaitor. +- limit the transmit pdu size to be 4K aligned. +- added check for pdu size, if the negotiated pdu size if too big, print error + message to dmesg, and close the connection. +- fixed ddp page size setup when both header and data digests are off. + +Signed-off-by: Karen Xie +Acked-by: John Jolly +--- + +diff -uNr linux-2.6.27.7-4.orig/Documentation/scsi/cxgb3i.txt linux-2.6.27.7-4.new/Documentation/scsi/cxgb3i.txt +--- linux-2.6.27.7-4.orig/Documentation/scsi/cxgb3i.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.6.27.7-4.new/Documentation/scsi/cxgb3i.txt 2008-12-01 18:32:21.000000000 -0600 +@@ -0,0 +1,51 @@ ++Chelsio S3 iSCSI Driver for Linux ++ ++Introduction ++============ ++ ++The Chelsio T3 ASIC based Adapters (S310, S320, S302, S304, Mezz cards, etc. ++series of products) supports iSCSI acceleration and iSCSI Direct Data Placement ++(DDP) where the hardware handles the expensive byte touching operations, such ++as CRC computation and verification, and direct DMA to the final host memory ++destination. ++ ++The cxgb3i driver interfaces with open-iscsi initiator and provides the iSCSI ++acceleration through Chelsio hardware wherever applicable. ++ ++Using the cxgb3i Driver ++======================= ++ ++The following steps need to be taken to accelerates the open-iscsi initiator: ++ ++1. a new transport class "cxgb3i" need to be specified. This is done by ++ creating a new interface file in /etc/iscsi/ifaces. ++ ++ The content of the file should be in the following format: ++ iface.transport_name = cxgb3i ++ iface.net_ifacename = ++ iface.ipaddress = ++ ++ * iface.ipaddress is optional, can be either the same as ++ the ethX's ip address or an address on the same subnet. Make sure the ++ address is unique in the network. ++ ++2. edit /etc/iscsi/iscsid.conf ++ The default setting for MaxRecvDataSegmentLength (131072) is too big, search ++ and replace all occurances of "xxx.iscsi.MaxRecvDataSegmentLength" to be a ++ smaller value (8192 is recommended): ++ ++ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 8192 ++ node.conn[0].iscsi.MaxRecvDataSegmentLength = 8192 ++ ++3. Load the cxgb3i driver: "modprobe cxgb3i" ++ ++ * in the case of recompiling the kernel, the cxgb3i selection is located at ++ Device Drivers ++ SCSI device support ---> ++ [*] SCSI low-level drivers ---> ++ Chelsio S3xx iSCSI support ++ ++4. To direct open-iscsi traffic to go through cxgb3i's accelerated path, ++ "-I " option needs to be specified with most of the ++ iscsiadm command. is the transport interface file created ++ in step 1. +diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2008-11-25 09:16:10.000000000 -0600 ++++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2008-12-01 18:32:55.000000000 -0600 +@@ -22,6 +22,12 @@ + #include + + #include "cxgb3i.h" ++#include "cxgb3i_ulp2.h" ++ ++#define align_to_4k_boundary(n) \ ++ do { \ ++ n = (n) & ~((1 << 12) - 1); \ ++ } while(0) + + static struct scsi_transport_template *cxgb3i_scsi_transport; + static struct scsi_host_template cxgb3i_host_template; +@@ -370,36 +376,59 @@ + * + * Creates a new iSCSI connection instance for a given session + */ +-static inline void cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) ++static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn) + { + struct cxgb3i_conn *cconn = conn->dd_data; ++ unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE, ++ cconn->hba->snic->tx_max_size - ++ ISCSI_PDU_HEADER_MAX); ++ ++ cxgb3i_log_debug("conn 0x%p, max xmit %u.\n", ++ conn, conn->max_xmit_dlength); + + if (conn->max_xmit_dlength) + conn->max_xmit_dlength = min_t(unsigned int, +- conn->max_xmit_dlength, +- cconn->hba->snic->tx_max_size - +- ISCSI_PDU_HEADER_MAX); ++ conn->max_xmit_dlength, max); + else +- conn->max_xmit_dlength = cconn->hba->snic->tx_max_size - +- ISCSI_PDU_HEADER_MAX; +- cxgb3i_log_debug("conn 0x%p, max xmit %u.\n", ++ conn->max_xmit_dlength = max; ++ ++ align_to_4k_boundary(conn->max_xmit_dlength); ++ ++ cxgb3i_log_debug("conn 0x%p, set max xmit %u.\n", + conn, conn->max_xmit_dlength); ++ ++ return 0; + } + +-static inline void cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) ++static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn) + { + struct cxgb3i_conn *cconn = conn->dd_data; ++ unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE, ++ cconn->hba->snic->rx_max_size - ++ ISCSI_PDU_HEADER_MAX); + +- if (conn->max_recv_dlength) +- conn->max_recv_dlength = min_t(unsigned int, +- conn->max_recv_dlength, +- cconn->hba->snic->rx_max_size - +- ISCSI_PDU_HEADER_MAX); +- else +- conn->max_recv_dlength = cconn->hba->snic->rx_max_size - +- ISCSI_PDU_HEADER_MAX; + cxgb3i_log_debug("conn 0x%p, max recv %u.\n", + conn, conn->max_recv_dlength); ++ ++ align_to_4k_boundary(max); ++ ++ if (conn->max_recv_dlength) { ++ if (conn->max_recv_dlength > max) { ++ cxgb3i_log_error("MaxRecvDataSegmentLength %u, not supported." ++ "Need to be <= %u.\n", ++ conn->max_recv_dlength, max); ++ return -EINVAL; ++ } ++ conn->max_recv_dlength = min_t(unsigned int, ++ conn->max_recv_dlength, max); ++ align_to_4k_boundary(conn->max_recv_dlength); ++ } else ++ conn->max_recv_dlength = max; ++ ++ cxgb3i_log_debug("conn 0x%p, set max recv %u.\n", ++ conn, conn->max_recv_dlength); ++ ++ return 0; + } + + static struct iscsi_cls_conn *cxgb3i_conn_create(struct iscsi_cls_session +@@ -546,13 +575,13 @@ + switch (param) { + case ISCSI_PARAM_HDRDGST_EN: + err = iscsi_set_param(cls_conn, param, buf, buflen); +- if (!err && conn->hdrdgst_en) ++ if (!err) + cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en, + conn->datadgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + err = iscsi_set_param(cls_conn, param, buf, buflen); +- if (!err && conn->datadgst_en) ++ if (!err) + cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en, + conn->datadgst_en); + break; +@@ -568,11 +597,11 @@ + return -ENOMEM; + case ISCSI_PARAM_MAX_RECV_DLENGTH: + err = iscsi_set_param(cls_conn, param, buf, buflen); +- cxgb3i_conn_max_recv_dlength(conn); ++ err = cxgb3i_conn_max_recv_dlength(conn); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + err = iscsi_set_param(cls_conn, param, buf, buflen); +- cxgb3i_conn_max_xmit_dlength(conn); ++ err = cxgb3i_conn_max_xmit_dlength(conn); + break; + default: + return iscsi_set_param(cls_conn, param, buf, buflen); +diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_offload.c +--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c 2008-11-25 09:16:10.000000000 -0600 ++++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_offload.c 2008-12-01 18:32:55.000000000 -0600 +@@ -45,6 +45,12 @@ + #define c3cn_tx_debug(fmt...) + #endif + ++#ifdef __DEBUG_C3CN_RX__ ++#define c3cn_rx_debug cxgb3i_log_debug ++#else ++#define c3cn_rx_debug(fmt...) ++#endif ++ + /* connection flags */ + static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag) + { +@@ -1577,6 +1583,9 @@ + skb_ulp_ddigest(skb) = ntohl(ddp_cpl.ulp_crc); + status = ntohl(ddp_cpl.ddp_status); + ++ c3cn_rx_debug("skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n", ++ skb, skb->len, skb_ulp_pdulen(skb), status); ++ + if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT)) + skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR; + if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT)) +diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.c +--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2008-11-25 09:16:10.000000000 -0600 ++++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2008-12-01 18:32:55.000000000 -0600 +@@ -145,6 +145,9 @@ + PAGE_SHIFT; + int i = 1, j = 0; + ++ if (sgoffset) ++ return NULL; ++ + gl = kzalloc(sizeof(struct cxgb3i_gather_list) + + npages * (sizeof(dma_addr_t) + sizeof(struct page *)), + gfp); +@@ -173,7 +176,7 @@ + goto error_out; + + j++; +- if (j == gl->nelem) ++ if (j == gl->nelem || sg->offset) + goto error_out; + gl->pages[j] = page; + sglen = sg->length; +@@ -303,7 +306,8 @@ + int idx = -1, idx_max; + u32 tag; + +- if (page_idx || !ddp || !sgcnt || xferlen < ULP2_DDP_THRESHOLD) { ++ if (page_idx >= ULP2_PGIDX_MAX || !ddp || !sgcnt || ++ xferlen < ULP2_DDP_THRESHOLD) { + cxgb3i_tag_debug("pgidx %u, sgcnt %u, xfer %u/%u, NO ddp.\n", + page_idx, sgcnt, xferlen, ULP2_DDP_THRESHOLD); + return RESERVED_ITT; +@@ -330,10 +334,9 @@ + npods, gl); + } + if (idx < 0) { +- kfree(gl); + cxgb3i_tag_debug("sgcnt %u, xferlen %u, npods %u NO DDP.\n", + sgcnt, xferlen, npods); +- return RESERVED_ITT; ++ goto free_gl; + } + + if (ddp_alloc_gl_skb(ddp, idx, npods, gfp) < 0) +@@ -341,7 +344,7 @@ + + if (ddp_gl_map(snic->pdev, gl) < 0) + goto unmap_sgl; +- ++ + tag = sw_tag | (idx << snic->tag_format.rsvd_shift); + + hdr.rsvd = 0; +@@ -363,6 +366,8 @@ + ddp_free_gl_skb(ddp, idx, npods); + unmark_entries: + ddp_unmark_entries(ddp, idx, npods); ++free_gl: ++ kfree(gl); + return RESERVED_ITT; + } + +@@ -393,8 +398,10 @@ + struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field), + GFP_KERNEL | __GFP_NOFAIL); + struct cpl_set_tcb_field *req; +- u32 submode = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); +- u32 pgcode = page_idx < ULP2_PGIDX_MAX ? page_idx : 0; ++ u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); ++ ++ if (page_idx < ULP2_PGIDX_MAX) ++ val |= page_idx << 4; + + /* set up ulp submode and page size */ + req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); +@@ -404,7 +411,7 @@ + req->cpu_idx = 0; + req->word = htons(31); + req->mask = cpu_to_be64(0xFF000000); +- req->val = cpu_to_be64(((pgcode << 4) | submode) << 24); ++ req->val = cpu_to_be64(val << 24); + skb->priority = CPL_PRIORITY_CONTROL; + + cxgb3_ofld_send(c3cn->cdev, skb); +@@ -461,12 +468,16 @@ + segment->status = (conn->datadgst_en && + (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ? + ISCSI_SEGMENT_DGST_ERR : 0; +- if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) ++ if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { ++ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, " ++ "itt 0x%x.\n", ++ skb, hdr->opcode & ISCSI_OPCODE_MASK, ++ tcp_conn->in.datalen, hdr->itt); + segment->total_copied = segment->total_size; +- else { +- cxgb3i_ddp_debug("opcode 0x%x, data %u, NOT ddp'ed, " ++ } else { ++ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, not ddp'ed, " + "itt 0x%x.\n", +- hdr->opcode & ISCSI_OPCODE_MASK, ++ skb, hdr->opcode & ISCSI_OPCODE_MASK, + tcp_conn->in.datalen, hdr->itt); + offset += sizeof(struct cpl_iscsi_hdr_norss); + } +diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.h +--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2008-11-25 09:16:10.000000000 -0600 ++++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2008-12-01 18:32:55.000000000 -0600 +@@ -101,6 +101,7 @@ + #define ULP2_FLAG_PAD_ERROR 0x40 + + #define ULP2_MAX_PKT_SIZE 16224 ++#define ULP2_MAX_PDU_SIZE 8192 + + void cxgb3i_conn_closing(struct s3_conn *); + void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/disable-catas_reset-by-default-to-avoid-problems-with-eeh.patch b/src/patches/suse-2.6.27.31/patches.drivers/disable-catas_reset-by-default-to-avoid-problems-with-eeh.patch new file mode 100644 index 000000000..250db096e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/disable-catas_reset-by-default-to-avoid-problems-with-eeh.patch @@ -0,0 +1,48 @@ +From: Xiuling Ma +Subject: [PATCH] disable catas_reset by default to avoid problems with EEH +References: bnc#456389 + +PPC machines with EEH and Mellanox ib/net cards with catastrophic error +recovery that encounter a PCI bus error can crash and become +unresponsive. + +Disable the card reset to avoid this. + +NOTE: an upstream fix will come later once IBM can review a couple of +approaches I suggested since this fix is brute force. This driver didn't have +this reset on error feature in SLES10 so it isn't a feature removal. + +Signed-off-by: Xiuling Ma +Acked-by: Brandon Philips + +--- + drivers/infiniband/hw/mthca/mthca_catas.c | 2 +- + drivers/net/mlx4/catas.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6/drivers/infiniband/hw/mthca/mthca_catas.c +=================================================================== +--- linux-2.6.orig/drivers/infiniband/hw/mthca/mthca_catas.c ++++ linux-2.6/drivers/infiniband/hw/mthca/mthca_catas.c +@@ -51,7 +51,7 @@ static LIST_HEAD(catas_list); + static struct workqueue_struct *catas_wq; + static struct work_struct catas_work; + +-static int catas_reset_disable; ++static int catas_reset_disable = 1; + module_param_named(catas_reset_disable, catas_reset_disable, int, 0644); + MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero"); + +Index: linux-2.6/drivers/net/mlx4/catas.c +=================================================================== +--- linux-2.6.orig/drivers/net/mlx4/catas.c ++++ linux-2.6/drivers/net/mlx4/catas.c +@@ -45,7 +45,7 @@ static LIST_HEAD(catas_list); + static struct workqueue_struct *catas_wq; + static struct work_struct catas_work; + +-static int internal_err_reset = 1; ++static int internal_err_reset = 0; + module_param(internal_err_reset, int, 0644); + MODULE_PARM_DESC(internal_err_reset, + "Reset device on internal errors if non-zero (default 1)"); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/dm-abort-queue-on-failed-paths b/src/patches/suse-2.6.27.31/patches.drivers/dm-abort-queue-on-failed-paths new file mode 100644 index 000000000..8991a34ad --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/dm-abort-queue-on-failed-paths @@ -0,0 +1,69 @@ +Subject: dm: Call blk_abort_queue on failed paths +From: Mike Anderson +Date: Thu Oct 9 08:56:14 2008 +0200: +Git: 224cb3e981f1b2f9f93dbd49eaef505d17d894c2 +References: bnc#434105 + +Another small bugfix for request timeout. + +Signed-off-by: Mike Anderson +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-mpath.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -33,6 +33,7 @@ struct pgpath { + unsigned fail_count; /* Cumulative failure count */ + + struct dm_path path; ++ struct work_struct deactivate_path; + }; + + #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path) +@@ -112,6 +113,7 @@ static struct workqueue_struct *kmultipa + static void process_queued_ios(struct work_struct *work); + static void trigger_event(struct work_struct *work); + static void activate_path(struct work_struct *work); ++static void deactivate_path(struct work_struct *work); + + + /*----------------------------------------------- +@@ -122,8 +124,10 @@ static struct pgpath *alloc_pgpath(void) + { + struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL); + +- if (pgpath) ++ if (pgpath) { + pgpath->path.is_active = 1; ++ INIT_WORK(&pgpath->deactivate_path, deactivate_path); ++ } + + return pgpath; + } +@@ -133,6 +137,14 @@ static void free_pgpath(struct pgpath *p + kfree(pgpath); + } + ++static void deactivate_path(struct work_struct *work) ++{ ++ struct pgpath *pgpath = ++ container_of(work, struct pgpath, deactivate_path); ++ ++ blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue); ++} ++ + static struct priority_group *alloc_priority_group(void) + { + struct priority_group *pg; +@@ -881,6 +893,7 @@ static int fail_path(struct pgpath *pgpa + pgpath->path.dev->name, m->nr_valid_paths); + + queue_work(kmultipathd, &m->trigger_event); ++ queue_work(kmultipathd, &pgpath->deactivate_path); + + out: + spin_unlock_irqrestore(&m->lock, flags); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/dmi-introduce-dmi_first_match b/src/patches/suse-2.6.27.31/patches.drivers/dmi-introduce-dmi_first_match new file mode 100644 index 000000000..4b4edca5f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/dmi-introduce-dmi_first_match @@ -0,0 +1,149 @@ +From 2969c7df1c1808d2a38a9adfbb158de7632a0cfb Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Mon, 3 Nov 2008 19:01:03 +0900 +Subject: [PATCH] DMI: Introduce dmi_first_match to make the interface more flexible +References: bnc#441721 + +Some notebooks from HP have the problem that their BIOSes attempt to +spin down hard drives before entering ACPI system states S4 and S5. +This leads to a yo-yo effect during system power-off shutdown and the +last phase of hibernation when the disk is first spun down by the +kernel and then almost immediately turned on and off by the BIOS. +This, in turn, may result in shortening the disk's life times. + +To prevent this from happening we can blacklist the affected systems +using DMI information. However, only the on-board controlles should +be blacklisted and their PCI slot numbers can be used for this +purpose. Unfortunately the existing interface for checking DMI +information of the system is not very convenient for this purpose, +because to use it, we would have to define special callback functions +or create a separate struct dmi_system_id table for each blacklisted +system. + +To overcome this difficulty introduce a new function +dmi_first_match() returning a pointer to the first entry in an array +of struct dmi_system_id elements that matches the system DMI +information. Then, we can use this pointer to access the entry's +.driver_data field containing the additional information, such as +the PCI slot number, allowing us to do the desired blacklisting. + +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/firmware/dmi_scan.c | 68 +++++++++++++++++++++++++++++++++----------- + include/linux/dmi.h | 3 + + 2 files changed, 55 insertions(+), 16 deletions(-) + +--- a/drivers/firmware/dmi_scan.c ++++ b/drivers/firmware/dmi_scan.c +@@ -407,6 +407,27 @@ void __init dmi_scan_machine(void) + } + + /** ++ * dmi_match - check if dmi_system_id structure matches system DMI data ++ * @dmi: pointer to the dmi_system_id structure to check ++ */ ++static bool dmi_match(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { ++ int s = dmi->matches[i].slot; ++ if (s == DMI_NONE) ++ continue; ++ if (dmi_ident[s] ++ && strstr(dmi_ident[s], dmi->matches[i].substr)) ++ continue; ++ /* No match */ ++ return false; ++ } ++ return true; ++} ++ ++/** + * dmi_check_system - check system DMI data + * @list: array of dmi_system_id structures to match against + * All non-null elements of the list must match +@@ -421,30 +442,45 @@ void __init dmi_scan_machine(void) + */ + int dmi_check_system(const struct dmi_system_id *list) + { +- int i, count = 0; +- const struct dmi_system_id *d = list; ++ int count = 0; ++ const struct dmi_system_id *d; + +- while (d->ident) { +- for (i = 0; i < ARRAY_SIZE(d->matches); i++) { +- int s = d->matches[i].slot; +- if (s == DMI_NONE) +- continue; +- if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) +- continue; +- /* No match */ +- goto fail; ++ for (d = list; d->ident; d++) ++ if (dmi_match(d)) { ++ count++; ++ if (d->callback && d->callback(d)) ++ break; + } +- count++; +- if (d->callback && d->callback(d)) +- break; +-fail: d++; +- } + + return count; + } + EXPORT_SYMBOL(dmi_check_system); + + /** ++ * dmi_first_match - find dmi_system_id structure matching system DMI data ++ * @list: array of dmi_system_id structures to match against ++ * All non-null elements of the list must match ++ * their slot's (field index's) data (i.e., each ++ * list string must be a substring of the specified ++ * DMI slot's string data) to be considered a ++ * successful match. ++ * ++ * Walk the blacklist table until the first match is found. Return the ++ * pointer to the matching entry or NULL if there's no match. ++ */ ++const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) ++{ ++ const struct dmi_system_id *d; ++ ++ for (d = list; d->ident; d++) ++ if (dmi_match(d)) ++ return d; ++ ++ return NULL; ++} ++EXPORT_SYMBOL(dmi_first_match); ++ ++/** + * dmi_get_system_info - return DMI data value + * @field: data index (see enum dmi_field) + * +--- a/include/linux/dmi.h ++++ b/include/linux/dmi.h +@@ -75,6 +75,7 @@ struct dmi_device { + #ifdef CONFIG_DMI + + extern int dmi_check_system(const struct dmi_system_id *list); ++const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); + extern const char * dmi_get_system_info(int field); + extern const struct dmi_device * dmi_find_device(int type, const char *name, + const struct dmi_device *from); +@@ -88,6 +89,8 @@ extern int dmi_walk(void (*decode)(const + #else + + static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } ++static inline const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) ++ { return NULL; } + static inline const char * dmi_get_system_info(int field) { return NULL; } + static inline const struct dmi_device * dmi_find_device(int type, const char *name, + const struct dmi_device *from) { return NULL; } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/driver-core-add-newlines-to-debugging-enabled-disabled-messages.patch b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-add-newlines-to-debugging-enabled-disabled-messages.patch new file mode 100644 index 000000000..738e72b99 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-add-newlines-to-debugging-enabled-disabled-messages.patch @@ -0,0 +1,40 @@ +From aa6f3c640781c8ac213a4ed3011dcced36f899e3 Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Sun, 30 Nov 2008 14:01:26 +0100 +Subject: driver core: add newlines to debugging enabled/disabled messages +Patch-mainline: 2.6.28 + +From: Marcel Holtmann + +commit aa6f3c640781c8ac213a4ed3011dcced36f899e3 upstream. + +Both messages are missing the newline and thus dmesg output gets +scrambled. + +Signed-off-by: Marcel Holtmann +Signed-off-by: Greg Kroah-Hartman + +--- + lib/dynamic_printk.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/lib/dynamic_printk.c ++++ b/lib/dynamic_printk.c +@@ -289,7 +289,7 @@ static ssize_t pr_debug_write(struct fil + dynamic_enabled = DYNAMIC_ENABLED_SOME; + err = 0; + printk(KERN_DEBUG +- "debugging enabled for module %s", ++ "debugging enabled for module %s\n", + elem->name); + } else if (!value && (elem->enable == 1)) { + elem->enable = 0; +@@ -309,7 +309,7 @@ static ssize_t pr_debug_write(struct fil + err = 0; + printk(KERN_DEBUG + "debugging disabled for module " +- "%s", elem->name); ++ "%s\n", elem->name); + } + } + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch new file mode 100644 index 000000000..e6111dd11 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-basic-infrastructure-for-per-module-dynamic-debug-messages.patch @@ -0,0 +1,946 @@ +From jbaron@redhat.com Tue Aug 12 17:09:39 2008 +From: Jason Baron +Date: Tue, 12 Aug 2008 16:46:19 -0400 +Subject: driver core: basic infrastructure for per-module dynamic debug messages +To: Greg KH +Cc: Randy Dunlap , linux-kernel@vger.kernel.org, akpm@linux-foundation.org, joe@perches.com, nick@nick-andrew.net +Message-ID: <20080812204619.GE6056@redhat.com> +Patch-mainline: 2.6.28 + +Base infrastructure to enable per-module debug messages. + +I've introduced CONFIG_DYNAMIC_PRINTK_DEBUG, which when enabled centralizes +control of debugging statements on a per-module basis in one /proc file, +currently, /dynamic_printk/modules. When, CONFIG_DYNAMIC_PRINTK_DEBUG, +is not set, debugging statements can still be enabled as before, often by +defining 'DEBUG' for the proper compilation unit. Thus, this patch set has no +affect when CONFIG_DYNAMIC_PRINTK_DEBUG is not set. + +The infrastructure currently ties into all pr_debug() and dev_dbg() calls. That +is, if CONFIG_DYNAMIC_PRINTK_DEBUG is set, all pr_debug() and dev_dbg() calls +can be dynamically enabled/disabled on a per-module basis. + +Future plans include extending this functionality to subsystems, that define +their own debug levels and flags. + +Usage: + +Dynamic debugging is controlled by the debugfs file, +/dynamic_printk/modules. This file contains a list of the modules that +can be enabled. The format of the file is as follows: + + + . + . + . + + : Name of the module in which the debug call resides + : whether the messages are enabled or not + +For example: + + snd_hda_intel enabled=0 + fixup enabled=1 + driver enabled=0 + +Enable a module: + + $echo "set enabled=1 " > dynamic_printk/modules + +Disable a module: + + $echo "set enabled=0 " > dynamic_printk/modules + +Enable all modules: + + $echo "set enabled=1 all" > dynamic_printk/modules + +Disable all modules: + + $echo "set enabled=0 all" > dynamic_printk/modules + +Finally, passing "dynamic_printk" at the command line enables +debugging for all modules. This mode can be turned off via the above +disable command. + +[gkh: minor cleanups and tweaks to make the build work quietly] + +Signed-off-by: Jason Baron +Signed-off-by: Greg Kroah-Hartman + + +--- + Documentation/kernel-parameters.txt | 5 + include/asm-generic/vmlinux.lds.h | 10 + include/linux/device.h | 6 + include/linux/dynamic_printk.h | 93 ++++++++ + include/linux/kernel.h | 7 + include/linux/module.h | 1 + kernel/module.c | 31 ++ + lib/Kconfig.debug | 55 ++++ + lib/Makefile | 2 + lib/dynamic_printk.c | 418 ++++++++++++++++++++++++++++++++++++ + net/netfilter/nf_conntrack_pptp.c | 2 + scripts/Makefile.lib | 11 + scripts/basic/Makefile | 2 + scripts/basic/hash.c | 64 +++++ + 14 files changed, 700 insertions(+), 7 deletions(-) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1742,6 +1742,11 @@ and is between 256 and 4096 characters. + autoconfiguration. + Ranges are in pairs (memory base and size). + ++ dynamic_printk ++ Enables pr_debug()/dev_dbg() calls if ++ CONFIG_DYNAMIC_PRINTK_DEBUG has been enabled. These can also ++ be switched on/off via /dynamic_printk/modules ++ + print-fatal-signals= + [KNL] debug: print fatal signals + print-fatal-signals=1: print segfault info to +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -268,7 +268,15 @@ + CPU_DISCARD(init.data) \ + CPU_DISCARD(init.rodata) \ + MEM_DISCARD(init.data) \ +- MEM_DISCARD(init.rodata) ++ MEM_DISCARD(init.rodata) \ ++ /* implement dynamic printk debug */ \ ++ VMLINUX_SYMBOL(__start___verbose_strings) = .; \ ++ *(__verbose_strings) \ ++ VMLINUX_SYMBOL(__stop___verbose_strings) = .; \ ++ . = ALIGN(8); \ ++ VMLINUX_SYMBOL(__start___verbose) = .; \ ++ *(__verbose) \ ++ VMLINUX_SYMBOL(__stop___verbose) = .; + + #define INIT_TEXT \ + *(.init.text) \ +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -553,7 +553,11 @@ int printk_dev_hash(const char *, const + #define dev_info(dev, format, arg...) \ + dev_printk_hash(KERN_INFO , dev , format , ## arg) + +-#ifdef DEBUG ++#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) ++#define dev_dbg(dev, format, ...) do { \ ++ dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ ++ } while (0) ++#elif defined(DEBUG) + #define dev_dbg(dev, format, arg...) \ + dev_printk(KERN_DEBUG , dev , format , ## arg) + #else +--- /dev/null ++++ b/include/linux/dynamic_printk.h +@@ -0,0 +1,93 @@ ++#ifndef _DYNAMIC_PRINTK_H ++#define _DYNAMIC_PRINTK_H ++ ++#define DYNAMIC_DEBUG_HASH_BITS 6 ++#define DEBUG_HASH_TABLE_SIZE (1 << DYNAMIC_DEBUG_HASH_BITS) ++ ++#define TYPE_BOOLEAN 1 ++ ++#define DYNAMIC_ENABLED_ALL 0 ++#define DYNAMIC_ENABLED_NONE 1 ++#define DYNAMIC_ENABLED_SOME 2 ++ ++extern int dynamic_enabled; ++ ++/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which ++ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They ++ * use independent hash functions, to reduce the chance of false positives. ++ */ ++extern long long dynamic_printk_enabled; ++extern long long dynamic_printk_enabled2; ++ ++struct mod_debug { ++ char *modname; ++ char *logical_modname; ++ char *flag_names; ++ int type; ++ int hash; ++ int hash2; ++} __attribute__((aligned(8))); ++ ++int register_dynamic_debug_module(char *mod_name, int type, char *share_name, ++ char *flags, int hash, int hash2); ++ ++#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) ++extern int unregister_dynamic_debug_module(char *mod_name); ++extern int __dynamic_dbg_enabled_helper(char *modname, int type, ++ int value, int hash); ++ ++#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ \ ++ int __ret = 0; \ ++ if (unlikely((dynamic_printk_enabled & (1LL << DEBUG_HASH)) && \ ++ (dynamic_printk_enabled2 & (1LL << DEBUG_HASH2)))) \ ++ __ret = __dynamic_dbg_enabled_helper(module, type, \ ++ value, hash);\ ++ __ret; }) ++ ++#define dynamic_pr_debug(fmt, ...) do { \ ++ static char mod_name[] \ ++ __attribute__((section("__verbose_strings"))) \ ++ = KBUILD_MODNAME; \ ++ static struct mod_debug descriptor \ ++ __used \ ++ __attribute__((section("__verbose"), aligned(8))) = \ ++ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\ ++ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \ ++ 0, 0, DEBUG_HASH)) \ ++ printk(KERN_DEBUG KBUILD_MODNAME ":" fmt, \ ++ ##__VA_ARGS__); \ ++ } while (0) ++ ++#define dynamic_dev_dbg(dev, format, ...) do { \ ++ static char mod_name[] \ ++ __attribute__((section("__verbose_strings"))) \ ++ = KBUILD_MODNAME; \ ++ static struct mod_debug descriptor \ ++ __used \ ++ __attribute__((section("__verbose"), aligned(8))) = \ ++ { mod_name, mod_name, NULL, TYPE_BOOLEAN, DEBUG_HASH, DEBUG_HASH2 };\ ++ if (__dynamic_dbg_enabled(KBUILD_MODNAME, TYPE_BOOLEAN, \ ++ 0, 0, DEBUG_HASH)) \ ++ dev_printk(KERN_DEBUG, dev, \ ++ KBUILD_MODNAME ": " format, \ ++ ##__VA_ARGS__); \ ++ } while (0) ++ ++#else ++ ++static inline int unregister_dynamic_debug_module(const char *mod_name) ++{ ++ return 0; ++} ++static inline int __dynamic_dbg_enabled_helper(char *modname, int type, ++ int value, int hash) ++{ ++ return 0; ++} ++ ++#define __dynamic_dbg_enabled(module, type, value, level, hash) ({ 0; }) ++#define dynamic_pr_debug(fmt, ...) do { } while (0) ++#define dynamic_dev_dbg(dev, format, ...) do { } while (0) ++#endif ++ ++#endif +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -331,8 +332,12 @@ int printk_hash(const char *, const char + #define pr_info(fmt, arg...) \ + pr_printk_hash(KERN_INFO, fmt, ##arg) + +-#ifdef DEBUG + /* If you are writing a driver, please use dev_dbg instead */ ++#if defined(CONFIG_DYNAMIC_PRINTK_DEBUG) ++#define pr_debug(fmt, ...) do { \ ++ dynamic_pr_debug(fmt, ##__VA_ARGS__); \ ++ } while (0) ++#elif defined(DEBUG) + #define pr_debug(fmt, arg...) \ + pr_printk(KERN_DEBUG, fmt, ##arg) + #else +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -345,7 +345,6 @@ struct module + /* Reference counts */ + struct module_ref ref[NR_CPUS]; + #endif +- + }; + #ifndef MODULE_ARCH_INIT + #define MODULE_ARCH_INIT {} +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -798,6 +798,7 @@ SYSCALL_DEFINE2(delete_module, const cha + mutex_lock(&module_mutex); + /* Store the name of the last unloaded module for diagnostic purposes */ + strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); ++ unregister_dynamic_debug_module(mod->name); + free_module(mod); + + out: +@@ -1823,6 +1824,33 @@ static inline void add_kallsyms(struct m + } + #endif /* CONFIG_KALLSYMS */ + ++#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG ++static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex) ++{ ++ struct mod_debug *debug_info; ++ unsigned long pos, end; ++ unsigned int num_verbose; ++ ++ pos = sechdrs[verboseindex].sh_addr; ++ num_verbose = sechdrs[verboseindex].sh_size / ++ sizeof(struct mod_debug); ++ end = pos + (num_verbose * sizeof(struct mod_debug)); ++ ++ for (; pos < end; pos += sizeof(struct mod_debug)) { ++ debug_info = (struct mod_debug *)pos; ++ register_dynamic_debug_module(debug_info->modname, ++ debug_info->type, debug_info->logical_modname, ++ debug_info->flag_names, debug_info->hash, ++ debug_info->hash2); ++ } ++} ++#else ++static inline void dynamic_printk_setup(Elf_Shdr *sechdrs, ++ unsigned int verboseindex) ++{ ++} ++#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ ++ + static void *module_alloc_update_bounds(unsigned long size) + { + void *ret = module_alloc(size); +@@ -1871,6 +1899,7 @@ static noinline struct module *load_modu + #endif + unsigned int markersindex; + unsigned int markersstringsindex; ++ unsigned int verboseindex; + struct module *mod; + long err = 0; + void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ +@@ -2157,6 +2186,7 @@ static noinline struct module *load_modu + markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); + markersstringsindex = find_sec(hdr, sechdrs, secstrings, + "__markers_strings"); ++ verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose"); + + /* Now do relocations. */ + for (i = 1; i < hdr->e_shnum; i++) { +@@ -2207,6 +2237,7 @@ static noinline struct module *load_modu + marker_update_probe_range(mod->markers, + mod->markers + mod->num_markers); + #endif ++ dynamic_printk_setup(sechdrs, verboseindex); + err = module_finalize(hdr, sechdrs, mod); + if (err < 0) + goto cleanup; +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -752,6 +752,61 @@ menuconfig BUILD_DOCSRC + + Say N if you are unsure. + ++config DYNAMIC_PRINTK_DEBUG ++ bool "Enable dynamic printk() call support" ++ default n ++ depends on PRINTK ++ select PRINTK_DEBUG ++ help ++ ++ Compiles debug level messages into the kernel, which would not ++ otherwise be available at runtime. These messages can then be ++ enabled/disabled on a per module basis. This mechanism implicitly ++ enables all pr_debug() and dev_dbg() calls. The impact of this ++ compile option is a larger kernel text size of about 2%. ++ ++ Usage: ++ ++ Dynamic debugging is controlled by the debugfs file, ++ dynamic_printk/modules. This file contains a list of the modules that ++ can be enabled. The format of the file is the module name, followed ++ by a set of flags that can be enabled. The first flag is always the ++ 'enabled' flag. For example: ++ ++ ++ . ++ . ++ . ++ ++ : Name of the module in which the debug call resides ++ : whether the messages are enabled or not ++ ++ From a live system: ++ ++ snd_hda_intel enabled=0 ++ fixup enabled=0 ++ driver enabled=0 ++ ++ Enable a module: ++ ++ $echo "set enabled=1 " > dynamic_printk/modules ++ ++ Disable a module: ++ ++ $echo "set enabled=0 " > dynamic_printk/modules ++ ++ Enable all modules: ++ ++ $echo "set enabled=1 all" > dynamic_printk/modules ++ ++ Disable all modules: ++ ++ $echo "set enabled=0 all" > dynamic_printk/modules ++ ++ Finally, passing "dynamic_printk" at the command line enables ++ debugging for all modules. This mode can be turned off via the above ++ disable command. ++ + source "samples/Kconfig" + + source "lib/Kconfig.kgdb" +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -81,6 +81,8 @@ obj-$(CONFIG_HAVE_LMB) += lmb.o + + obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o + ++obj-$(CONFIG_DYNAMIC_PRINTK_DEBUG) += dynamic_printk.o ++ + hostprogs-y := gen_crc32table + clean-files := crc32table.h + +--- /dev/null ++++ b/lib/dynamic_printk.c +@@ -0,0 +1,418 @@ ++/* ++ * lib/dynamic_printk.c ++ * ++ * make pr_debug()/dev_dbg() calls runtime configurable based upon their ++ * their source module. ++ * ++ * Copyright (C) 2008 Red Hat, Inc., Jason Baron ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern struct mod_debug __start___verbose[]; ++extern struct mod_debug __stop___verbose[]; ++ ++struct debug_name { ++ struct hlist_node hlist; ++ struct hlist_node hlist2; ++ int hash1; ++ int hash2; ++ char *name; ++ int enable; ++ int type; ++}; ++ ++static int nr_entries; ++static int num_enabled; ++int dynamic_enabled = DYNAMIC_ENABLED_NONE; ++static struct hlist_head module_table[DEBUG_HASH_TABLE_SIZE] = ++ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; ++static struct hlist_head module_table2[DEBUG_HASH_TABLE_SIZE] = ++ { [0 ... DEBUG_HASH_TABLE_SIZE-1] = HLIST_HEAD_INIT }; ++static DECLARE_MUTEX(debug_list_mutex); ++ ++/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which ++ * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They ++ * use independent hash functions, to reduce the chance of false positives. ++ */ ++long long dynamic_printk_enabled; ++EXPORT_SYMBOL_GPL(dynamic_printk_enabled); ++long long dynamic_printk_enabled2; ++EXPORT_SYMBOL_GPL(dynamic_printk_enabled2); ++ ++/* returns the debug module pointer. */ ++static struct debug_name *find_debug_module(char *module_name) ++{ ++ int i; ++ struct hlist_head *head; ++ struct hlist_node *node; ++ struct debug_name *element; ++ ++ element = NULL; ++ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { ++ head = &module_table[i]; ++ hlist_for_each_entry_rcu(element, node, head, hlist) ++ if (!strcmp(element->name, module_name)) ++ return element; ++ } ++ return NULL; ++} ++ ++/* returns the debug module pointer. */ ++static struct debug_name *find_debug_module_hash(char *module_name, int hash) ++{ ++ struct hlist_head *head; ++ struct hlist_node *node; ++ struct debug_name *element; ++ ++ element = NULL; ++ head = &module_table[hash]; ++ hlist_for_each_entry_rcu(element, node, head, hlist) ++ if (!strcmp(element->name, module_name)) ++ return element; ++ return NULL; ++} ++ ++/* caller must hold mutex*/ ++static int __add_debug_module(char *mod_name, int hash, int hash2) ++{ ++ struct debug_name *new; ++ char *module_name; ++ int ret = 0; ++ ++ if (find_debug_module(mod_name)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ module_name = kmalloc(strlen(mod_name) + 1, GFP_KERNEL); ++ if (!module_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ module_name = strcpy(module_name, mod_name); ++ module_name[strlen(mod_name)] = '\0'; ++ new = kzalloc(sizeof(struct debug_name), GFP_KERNEL); ++ if (!new) { ++ kfree(module_name); ++ ret = -ENOMEM; ++ goto out; ++ } ++ INIT_HLIST_NODE(&new->hlist); ++ INIT_HLIST_NODE(&new->hlist2); ++ new->name = module_name; ++ new->hash1 = hash; ++ new->hash2 = hash2; ++ hlist_add_head_rcu(&new->hlist, &module_table[hash]); ++ hlist_add_head_rcu(&new->hlist2, &module_table2[hash2]); ++ nr_entries++; ++out: ++ return ret; ++} ++ ++int unregister_dynamic_debug_module(char *mod_name) ++{ ++ struct debug_name *element; ++ int ret = 0; ++ ++ down(&debug_list_mutex); ++ element = find_debug_module(mod_name); ++ if (!element) { ++ ret = -EINVAL; ++ goto out; ++ } ++ hlist_del_rcu(&element->hlist); ++ hlist_del_rcu(&element->hlist2); ++ synchronize_rcu(); ++ kfree(element->name); ++ if (element->enable) ++ num_enabled--; ++ kfree(element); ++ nr_entries--; ++out: ++ up(&debug_list_mutex); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module); ++ ++int register_dynamic_debug_module(char *mod_name, int type, char *share_name, ++ char *flags, int hash, int hash2) ++{ ++ struct debug_name *elem; ++ int ret = 0; ++ ++ down(&debug_list_mutex); ++ elem = find_debug_module(mod_name); ++ if (!elem) { ++ if (__add_debug_module(mod_name, hash, hash2)) ++ goto out; ++ elem = find_debug_module(mod_name); ++ if (dynamic_enabled == DYNAMIC_ENABLED_ALL && ++ !strcmp(mod_name, share_name)) { ++ elem->enable = true; ++ num_enabled++; ++ } ++ } ++ elem->type |= type; ++out: ++ up(&debug_list_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(register_dynamic_debug_module); ++ ++int __dynamic_dbg_enabled_helper(char *mod_name, int type, int value, int hash) ++{ ++ struct debug_name *elem; ++ int ret = 0; ++ ++ if (dynamic_enabled == DYNAMIC_ENABLED_ALL) ++ return 1; ++ rcu_read_lock(); ++ elem = find_debug_module_hash(mod_name, hash); ++ if (elem && elem->enable) ++ ret = 1; ++ rcu_read_unlock(); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(__dynamic_dbg_enabled_helper); ++ ++static void set_all(bool enable) ++{ ++ struct debug_name *e; ++ struct hlist_node *node; ++ int i; ++ long long enable_mask; ++ ++ for (i = 0; i < DEBUG_HASH_TABLE_SIZE; i++) { ++ if (module_table[i].first != NULL) { ++ hlist_for_each_entry(e, node, &module_table[i], hlist) { ++ e->enable = enable; ++ } ++ } ++ } ++ if (enable) ++ enable_mask = ULLONG_MAX; ++ else ++ enable_mask = 0; ++ dynamic_printk_enabled = enable_mask; ++ dynamic_printk_enabled2 = enable_mask; ++} ++ ++static int disabled_hash(int i, bool first_table) ++{ ++ struct debug_name *e; ++ struct hlist_node *node; ++ ++ if (first_table) { ++ hlist_for_each_entry(e, node, &module_table[i], hlist) { ++ if (e->enable) ++ return 0; ++ } ++ } else { ++ hlist_for_each_entry(e, node, &module_table2[i], hlist2) { ++ if (e->enable) ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static ssize_t pr_debug_write(struct file *file, const char __user *buf, ++ size_t length, loff_t *ppos) ++{ ++ char *buffer, *s, *value_str, *setting_str; ++ int err, value; ++ struct debug_name *elem = NULL; ++ int all = 0; ++ ++ if (length > PAGE_SIZE || length < 0) ++ return -EINVAL; ++ ++ buffer = (char *)__get_free_page(GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ err = -EFAULT; ++ if (copy_from_user(buffer, buf, length)) ++ goto out; ++ ++ err = -EINVAL; ++ if (length < PAGE_SIZE) ++ buffer[length] = '\0'; ++ else if (buffer[PAGE_SIZE-1]) ++ goto out; ++ ++ err = -EINVAL; ++ down(&debug_list_mutex); ++ ++ if (strncmp("set", buffer, 3)) ++ goto out_up; ++ s = buffer + 3; ++ setting_str = strsep(&s, "="); ++ if (s == NULL) ++ goto out_up; ++ setting_str = strstrip(setting_str); ++ value_str = strsep(&s, " "); ++ if (s == NULL) ++ goto out_up; ++ s = strstrip(s); ++ if (!strncmp(s, "all", 3)) ++ all = 1; ++ else ++ elem = find_debug_module(s); ++ if (!strncmp(setting_str, "enable", 6)) { ++ value = !!simple_strtol(value_str, NULL, 10); ++ if (all) { ++ if (value) { ++ set_all(true); ++ num_enabled = nr_entries; ++ dynamic_enabled = DYNAMIC_ENABLED_ALL; ++ } else { ++ set_all(false); ++ num_enabled = 0; ++ dynamic_enabled = DYNAMIC_ENABLED_NONE; ++ } ++ err = 0; ++ } else { ++ if (elem) { ++ if (value && (elem->enable == 0)) { ++ dynamic_printk_enabled |= ++ (1LL << elem->hash1); ++ dynamic_printk_enabled2 |= ++ (1LL << elem->hash2); ++ elem->enable = 1; ++ num_enabled++; ++ dynamic_enabled = DYNAMIC_ENABLED_SOME; ++ err = 0; ++ printk(KERN_DEBUG ++ "debugging enabled for module %s", ++ elem->name); ++ } else if (!value && (elem->enable == 1)) { ++ elem->enable = 0; ++ num_enabled--; ++ if (disabled_hash(elem->hash1, true)) ++ dynamic_printk_enabled &= ++ ~(1LL << elem->hash1); ++ if (disabled_hash(elem->hash2, false)) ++ dynamic_printk_enabled2 &= ++ ~(1LL << elem->hash2); ++ if (num_enabled) ++ dynamic_enabled = ++ DYNAMIC_ENABLED_SOME; ++ else ++ dynamic_enabled = ++ DYNAMIC_ENABLED_NONE; ++ err = 0; ++ printk(KERN_DEBUG ++ "debugging disabled for module " ++ "%s", elem->name); ++ } ++ } ++ } ++ } ++ if (!err) ++ err = length; ++out_up: ++ up(&debug_list_mutex); ++out: ++ free_page((unsigned long)buffer); ++ return err; ++} ++ ++static void *pr_debug_seq_start(struct seq_file *f, loff_t *pos) ++{ ++ return (*pos < DEBUG_HASH_TABLE_SIZE) ? pos : NULL; ++} ++ ++static void *pr_debug_seq_next(struct seq_file *s, void *v, loff_t *pos) ++{ ++ (*pos)++; ++ if (*pos >= DEBUG_HASH_TABLE_SIZE) ++ return NULL; ++ return pos; ++} ++ ++static void pr_debug_seq_stop(struct seq_file *s, void *v) ++{ ++ /* Nothing to do */ ++} ++ ++static int pr_debug_seq_show(struct seq_file *s, void *v) ++{ ++ struct hlist_head *head; ++ struct hlist_node *node; ++ struct debug_name *elem; ++ unsigned int i = *(loff_t *) v; ++ ++ rcu_read_lock(); ++ head = &module_table[i]; ++ hlist_for_each_entry_rcu(elem, node, head, hlist) { ++ seq_printf(s, "%s enabled=%d", elem->name, elem->enable); ++ seq_printf(s, "\n"); ++ } ++ rcu_read_unlock(); ++ return 0; ++} ++ ++static struct seq_operations pr_debug_seq_ops = { ++ .start = pr_debug_seq_start, ++ .next = pr_debug_seq_next, ++ .stop = pr_debug_seq_stop, ++ .show = pr_debug_seq_show ++}; ++ ++static int pr_debug_open(struct inode *inode, struct file *filp) ++{ ++ return seq_open(filp, &pr_debug_seq_ops); ++} ++ ++static const struct file_operations pr_debug_operations = { ++ .open = pr_debug_open, ++ .read = seq_read, ++ .write = pr_debug_write, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static int __init dynamic_printk_init(void) ++{ ++ struct dentry *dir, *file; ++ struct mod_debug *iter; ++ unsigned long value; ++ ++ dir = debugfs_create_dir("dynamic_printk", NULL); ++ if (!dir) ++ return -ENOMEM; ++ file = debugfs_create_file("modules", 0644, dir, NULL, ++ &pr_debug_operations); ++ if (!file) { ++ debugfs_remove(dir); ++ return -ENOMEM; ++ } ++ for (value = (unsigned long)__start___verbose; ++ value < (unsigned long)__stop___verbose; ++ value += sizeof(struct mod_debug)) { ++ iter = (struct mod_debug *)value; ++ register_dynamic_debug_module(iter->modname, ++ iter->type, ++ iter->logical_modname, ++ iter->flag_names, iter->hash, iter->hash2); ++ } ++ return 0; ++} ++module_init(dynamic_printk_init); ++/* may want to move this earlier so we can get traces as early as possible */ ++ ++static int __init dynamic_printk_setup(char *str) ++{ ++ if (str) ++ return -ENOENT; ++ set_all(true); ++ return 0; ++} ++/* Use early_param(), so we can get debug output as early as possible */ ++early_param("dynamic_printk", dynamic_printk_setup); +--- a/net/netfilter/nf_conntrack_pptp.c ++++ b/net/netfilter/nf_conntrack_pptp.c +@@ -65,7 +65,7 @@ void + struct nf_conntrack_expect *exp) __read_mostly; + EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn); + +-#ifdef DEBUG ++#if defined(DEBUG) || defined(CONFIG_DYNAMIC_PRINTK_DEBUG) + /* PptpControlMessageType names */ + const char *const pptp_msg_name[] = { + "UNKNOWN_MESSAGE", +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -96,6 +96,14 @@ basename_flags = -D"KBUILD_BASENAME=KBUI + modname_flags = $(if $(filter 1,$(words $(modname))),\ + -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") + ++#hash values ++ifdef CONFIG_DYNAMIC_PRINTK_DEBUG ++debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\ ++ -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))" ++else ++debug_flags = ++endif ++ + orig_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(basetarget).o) + _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) + _a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(basetarget).o) +@@ -121,7 +129,8 @@ endif + + c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ + $(__c_flags) $(modkern_cflags) \ +- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) ++ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \ ++ $(debug_flags) + + a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ + $(__a_flags) $(modkern_aflags) +--- a/scripts/basic/Makefile ++++ b/scripts/basic/Makefile +@@ -9,7 +9,7 @@ + # fixdep: Used to generate dependency information during build process + # docproc: Used in Documentation/DocBook + +-hostprogs-y := fixdep docproc ++hostprogs-y := fixdep docproc hash + always := $(hostprogs-y) + + # fixdep is needed to compile other host programs +--- /dev/null ++++ b/scripts/basic/hash.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (C) 2008 Red Hat, Inc., Jason Baron ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#define DYNAMIC_DEBUG_HASH_BITS 6 ++ ++static const char *program; ++ ++static void usage(void) ++{ ++ printf("Usage: %s \n", program); ++ exit(1); ++} ++ ++/* djb2 hashing algorithm by Dan Bernstein. From: ++ * http://www.cse.yorku.ca/~oz/hash.html ++ */ ++ ++unsigned int djb2_hash(char *str) ++{ ++ unsigned long hash = 5381; ++ int c; ++ ++ c = *str; ++ while (c) { ++ hash = ((hash << 5) + hash) + c; ++ c = *++str; ++ } ++ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); ++} ++ ++unsigned int r5_hash(char *str) ++{ ++ unsigned long hash = 0; ++ int c; ++ ++ c = *str; ++ while (c) { ++ hash = (hash + (c << 4) + (c >> 4)) * 11; ++ c = *++str; ++ } ++ return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ program = argv[0]; ++ ++ if (argc != 3) ++ usage(); ++ if (!strcmp(argv[1], "djb2")) ++ printf("%d\n", djb2_hash(argv[2])); ++ else if (!strcmp(argv[1], "r5")) ++ printf("%d\n", r5_hash(argv[2])); ++ else ++ usage(); ++ exit(0); ++} ++ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/driver-core-fix-dynamic_debug-cmd-line-parameter.patch b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-fix-dynamic_debug-cmd-line-parameter.patch new file mode 100644 index 000000000..f8b33a411 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-fix-dynamic_debug-cmd-line-parameter.patch @@ -0,0 +1,45 @@ +From 113328306dbdfd5f146f257e447364dc66d025d4 Mon Sep 17 00:00:00 2001 +From: Jason Baron +Date: Mon, 27 Oct 2008 12:05:14 -0400 +Subject: Driver core: fix 'dynamic_debug' cmd line parameter +Patch-mainline: 2.6.28 + +From: Jason Baron + +commit 113328306dbdfd5f146f257e447364dc66d025d4 upstream. + +In testing 2.6.28-rc1, I found that passing 'dynamic_printk' on the command +line didn't activate the debug code. The problem is that dynamic_printk_setup() +(which activates the debugging) is being called before dynamic_printk_init() is +called (which initializes infrastructure). Fix this by setting setting the +state to 'DYNAMIC_ENABLED_ALL' in dynamic_printk_setup(), which will also +cause all subsequent modules to have debugging automatically started, which is +probably the behavior we want. + +Signed-off-by: Jason Baron +Signed-off-by: Greg Kroah-Hartman + +--- + lib/dynamic_printk.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/lib/dynamic_printk.c ++++ b/lib/dynamic_printk.c +@@ -402,6 +402,8 @@ static int __init dynamic_printk_init(vo + iter->logical_modname, + iter->flag_names, iter->hash, iter->hash2); + } ++ if (dynamic_enabled == DYNAMIC_ENABLED_ALL) ++ set_all(true); + return 0; + } + module_init(dynamic_printk_init); +@@ -411,7 +413,7 @@ static int __init dynamic_printk_setup(c + { + if (str) + return -ENOENT; +- set_all(true); ++ dynamic_enabled = DYNAMIC_ENABLED_ALL; + return 0; + } + /* Use early_param(), so we can get debug output as early as possible */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/driver-core-fix-using-ret-variable-in-unregister_dynamic_debug_module.patch b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-fix-using-ret-variable-in-unregister_dynamic_debug_module.patch new file mode 100644 index 000000000..f7a5c622d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/driver-core-fix-using-ret-variable-in-unregister_dynamic_debug_module.patch @@ -0,0 +1,31 @@ +From 1c93ca09863a544cec24fc8e33491f645df80e59 Mon Sep 17 00:00:00 2001 +From: Johann Felix Soden +Date: Thu, 30 Oct 2008 22:44:39 +0100 +Subject: driver core: fix using 'ret' variable in unregister_dynamic_debug_module +Patch-mainline: 2.6.28 + +From: Johann Felix Soden + +commit 1c93ca09863a544cec24fc8e33491f645df80e59 upstream. + +The 'ret' variable is assigned, but not used in the return statement. Fix this. + +Signed-off-by: Johann Felix Soden +Acked-by: Jason Baron +Signed-off-by: Greg Kroah-Hartman + +--- + lib/dynamic_printk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/dynamic_printk.c ++++ b/lib/dynamic_printk.c +@@ -135,7 +135,7 @@ int unregister_dynamic_debug_module(char + nr_entries--; + out: + up(&debug_list_mutex); +- return 0; ++ return ret; + } + EXPORT_SYMBOL_GPL(unregister_dynamic_debug_module); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/e100-adapt-to-the-reworked-PCI-PM.patch b/src/patches/suse-2.6.27.31/patches.drivers/e100-adapt-to-the-reworked-PCI-PM.patch new file mode 100644 index 000000000..77e0dda5c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/e100-adapt-to-the-reworked-PCI-PM.patch @@ -0,0 +1,72 @@ +From bc79fc8409b3dccbde072e8113cc1fb3fd876fc5 Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Wed, 29 Oct 2008 14:22:18 -0700 +Subject: [PATCH] e100: adapt to the reworked PCI PM +References: bnc#504646 +Acked-by: Brandon Philips + +Adapt the e100 driver to the reworked PCI PM + +* Use the observation that it is sufficient to call pci_enable_wake() + once, unless it fails + +Signed-off-by: Rafael J. Wysocki +Tested-by: Jeff Kirsher +Acked-by: Jeff Kirsher +Cc: Jesse Barnes +Cc: Jeff Garzik +Cc: Frans Pop +Signed-off-by: Andrew Morton +Signed-off-by: Jeff Garzik +--- + drivers/net/e100.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/drivers/net/e100.c ++++ b/drivers/net/e100.c +@@ -2325,7 +2325,8 @@ static int e100_set_wol(struct net_devic + { + struct nic *nic = netdev_priv(netdev); + +- if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) ++ if ((wol->wolopts && wol->wolopts != WAKE_MAGIC) || ++ !device_can_wakeup(&nic->pdev->dev)) + return -EOPNOTSUPP; + + if(wol->wolopts) +@@ -2333,6 +2334,8 @@ static int e100_set_wol(struct net_devic + else + nic->flags &= ~wol_magic; + ++ device_set_wakeup_enable(&nic->pdev->dev, wol->wolopts); ++ + e100_exec_cb(nic, NULL, e100_configure); + + return 0; +@@ -2737,8 +2740,10 @@ static int __devinit e100_probe(struct p + + /* Wol magic packet can be enabled from eeprom */ + if((nic->mac >= mac_82558_D101_A4) && +- (nic->eeprom[eeprom_id] & eeprom_id_wol)) ++ (nic->eeprom[eeprom_id] & eeprom_id_wol)) { + nic->flags |= wol_magic; ++ device_set_wakeup_enable(&pdev->dev, true); ++ } + + /* ack any pending wake events, disable PME */ + pci_pme_active(pdev, false); +@@ -2797,11 +2802,10 @@ static int e100_suspend(struct pci_dev * + pci_save_state(pdev); + + if ((nic->flags & wol_magic) | e100_asf(nic)) { +- pci_enable_wake(pdev, PCI_D3hot, 1); +- pci_enable_wake(pdev, PCI_D3cold, 1); ++ if (pci_enable_wake(pdev, PCI_D3cold, true)) ++ pci_enable_wake(pdev, PCI_D3hot, true); + } else { +- pci_enable_wake(pdev, PCI_D3hot, 0); +- pci_enable_wake(pdev, PCI_D3cold, 0); ++ pci_enable_wake(pdev, PCI_D3hot, false); + } + + pci_disable_device(pdev); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/e1000e-Fixes-possible-phy-corrupton-on-82571-design.patch b/src/patches/suse-2.6.27.31/patches.drivers/e1000e-Fixes-possible-phy-corrupton-on-82571-design.patch new file mode 100644 index 000000000..a235c0a31 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/e1000e-Fixes-possible-phy-corrupton-on-82571-design.patch @@ -0,0 +1,194 @@ +From 23a2d1b233f535fc74f8dca66e488980b4db041b Mon Sep 17 00:00:00 2001 +From: Dave Graham +Date: Mon, 8 Jun 2009 14:28:17 +0000 +Subject: [PATCH] e1000e: Fixes possible phy corrupton on 82571 designs. +References: bnc#495259 + +Phy corruption has been observed on 2-port 82571 adapters, and is root-caused +to lack of synchronization between the 2 driver instances, which conflict +when attempting to access the phy via the single MDIC register. +A semaphore exists for this purpose, and is now used on these designs. Because +PXE &/or EFI boot code (which we cannot expect to be built with this fix) may +leave the inter-instance semaphore in an invalid initial state when the driver +first loads, this fix also includes a one-time (per driver load) fix-up of the +semaphore initial state. + +Signed-off-by: dave graham +Signed-off-by: Jeff Kirsher +Signed-off-by: David S. Miller +Acked-by: Brandon Philips +--- + drivers/net/e1000e/82571.c | 86 +++++++++++++++++++++++++++++++++++++++---- + drivers/net/e1000e/defines.h | 2 + + drivers/net/e1000e/hw.h | 2 + + 3 files changed, 83 insertions(+), 7 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/82571.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/82571.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/82571.c +@@ -68,6 +68,7 @@ static s32 e1000_setup_link_82571(struct + static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); + static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); + static s32 e1000_led_on_82574(struct e1000_hw *hw); ++static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); + + /** + * e1000_init_phy_params_82571 - Init PHY func ptrs. +@@ -206,6 +207,9 @@ static s32 e1000_init_mac_params_82571(s + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_mac_operations *func = &mac->ops; ++ u32 swsm = 0; ++ u32 swsm2 = 0; ++ bool force_clear_smbi = false; + + /* Set media type */ + switch (adapter->pdev->device) { +@@ -269,6 +273,50 @@ static s32 e1000_init_mac_params_82571(s + break; + } + ++ /* ++ * Ensure that the inter-port SWSM.SMBI lock bit is clear before ++ * first NVM or PHY acess. This should be done for single-port ++ * devices, and for one port only on dual-port devices so that ++ * for those devices we can still use the SMBI lock to synchronize ++ * inter-port accesses to the PHY & NVM. ++ */ ++ switch (hw->mac.type) { ++ case e1000_82571: ++ case e1000_82572: ++ swsm2 = er32(SWSM2); ++ ++ if (!(swsm2 & E1000_SWSM2_LOCK)) { ++ /* Only do this for the first interface on this card */ ++ ew32(SWSM2, ++ swsm2 | E1000_SWSM2_LOCK); ++ force_clear_smbi = true; ++ } else ++ force_clear_smbi = false; ++ break; ++ default: ++ force_clear_smbi = true; ++ break; ++ } ++ ++ if (force_clear_smbi) { ++ /* Make sure SWSM.SMBI is clear */ ++ swsm = er32(SWSM); ++ if (swsm & E1000_SWSM_SMBI) { ++ /* This bit should not be set on a first interface, and ++ * indicates that the bootagent or EFI code has ++ * improperly left this bit enabled ++ */ ++ hw_dbg(hw, "Please update your 82571 Bootagent\n"); ++ } ++ ew32(SWSM, swsm & ~E1000_SWSM_SMBI); ++ } ++ ++ /* ++ * Initialze device specific counter of SMBI acquisition ++ * timeouts. ++ */ ++ hw->dev_spec.e82571.smb_counter = 0; ++ + return 0; + } + +@@ -402,11 +450,37 @@ static s32 e1000_get_phy_id_82571(struct + static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) + { + u32 swsm; +- s32 timeout = hw->nvm.word_size + 1; ++ s32 sw_timeout = hw->nvm.word_size + 1; ++ s32 fw_timeout = hw->nvm.word_size + 1; + s32 i = 0; + ++ /* ++ * If we have timedout 3 times on trying to acquire ++ * the inter-port SMBI semaphore, there is old code ++ * operating on the other port, and it is not ++ * releasing SMBI. Modify the number of times that ++ * we try for the semaphore to interwork with this ++ * older code. ++ */ ++ if (hw->dev_spec.e82571.smb_counter > 2) ++ sw_timeout = 1; ++ ++ /* Get the SW semaphore */ ++ while (i < sw_timeout) { ++ swsm = er32(SWSM); ++ if (!(swsm & E1000_SWSM_SMBI)) ++ break; ++ ++ udelay(50); ++ i++; ++ } ++ ++ if (i == sw_timeout) { ++ hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); ++ hw->dev_spec.e82571.smb_counter++; ++ } + /* Get the FW semaphore. */ +- for (i = 0; i < timeout; i++) { ++ for (i = 0; i < fw_timeout; i++) { + swsm = er32(SWSM); + ew32(SWSM, swsm | E1000_SWSM_SWESMBI); + +@@ -417,9 +491,9 @@ static s32 e1000_get_hw_semaphore_82571( + udelay(50); + } + +- if (i == timeout) { ++ if (i == fw_timeout) { + /* Release semaphores */ +- e1000e_put_hw_semaphore(hw); ++ e1000_put_hw_semaphore_82571(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } +@@ -438,9 +512,7 @@ static void e1000_put_hw_semaphore_82571 + u32 swsm; + + swsm = er32(SWSM); +- +- swsm &= ~E1000_SWSM_SWESMBI; +- ++ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + ew32(SWSM, swsm); + } + +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/defines.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/defines.h ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/defines.h +@@ -359,6 +359,8 @@ + #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ + #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ + ++#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ ++ + /* Interrupt Cause Read */ + #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ + #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/hw.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/hw.h ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/hw.h +@@ -209,6 +209,7 @@ enum e1e_registers { + E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ + E1000_SWSM = 0x05B50, /* SW Semaphore */ + E1000_FWSM = 0x05B54, /* FW Semaphore */ ++ E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ + E1000_HICR = 0x08F00, /* Host Interface Control */ + }; + +@@ -856,6 +857,7 @@ struct e1000_fc_info { + struct e1000_dev_spec_82571 { + bool laa_is_present; + bool alt_mac_addr_is_present; ++ u32 smb_counter; + }; + + struct e1000_shadow_ram { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_82574L.patch b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_82574L.patch new file mode 100644 index 000000000..e96c965a9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_82574L.patch @@ -0,0 +1,1489 @@ +From: Bruce Allan +Acked-by: Karsten Keil +Subject: e1000e: add support for new 82574L part +Reference: fate 303916,303898 + +This new part has the same feature set as previous parts with the addition +of MSI-X support. + +Signed-off-by: Bruce Allan +Signed-off-by: Jeff Kirsher +--- + + drivers/net/e1000e/82571.c | 153 ++++++++++++++-- + drivers/net/e1000e/defines.h | 13 + + drivers/net/e1000e/e1000.h | 28 ++ + drivers/net/e1000e/es2lan.c | 2 + drivers/net/e1000e/ethtool.c | 38 +++- + drivers/net/e1000e/hw.h | 11 - + drivers/net/e1000e/ich8lan.c | 18 + + drivers/net/e1000e/lib.c | 7 + drivers/net/e1000e/netdev.c | 405 ++++++++++++++++++++++++++++++++++++++----- + drivers/net/e1000e/param.c | 27 ++ + drivers/net/e1000e/phy.c | 109 +++++++++++ + 11 files changed, 736 insertions(+), 75 deletions(-) + +--- a/drivers/net/e1000e/82571.c ++++ b/drivers/net/e1000e/82571.c +@@ -38,6 +38,7 @@ + * 82573V Gigabit Ethernet Controller (Copper) + * 82573E Gigabit Ethernet Controller (Copper) + * 82573L Gigabit Ethernet Controller ++ * 82574L Gigabit Network Connection + */ + + #include +@@ -54,6 +55,8 @@ + + #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 + ++#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ ++ + static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); + static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); + static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); +@@ -63,6 +66,8 @@ static s32 e1000_fix_nvm_checksum_82571( + static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); + static s32 e1000_setup_link_82571(struct e1000_hw *hw); + static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); ++static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); ++static s32 e1000_led_on_82574(struct e1000_hw *hw); + + /** + * e1000_init_phy_params_82571 - Init PHY func ptrs. +@@ -92,6 +97,9 @@ static s32 e1000_init_phy_params_82571(s + case e1000_82573: + phy->type = e1000_phy_m88; + break; ++ case e1000_82574: ++ phy->type = e1000_phy_bm; ++ break; + default: + return -E1000_ERR_PHY; + break; +@@ -111,6 +119,10 @@ static s32 e1000_init_phy_params_82571(s + if (phy->id != M88E1111_I_PHY_ID) + return -E1000_ERR_PHY; + break; ++ case e1000_82574: ++ if (phy->id != BME1000_E_PHY_ID_R2) ++ return -E1000_ERR_PHY; ++ break; + default: + return -E1000_ERR_PHY; + break; +@@ -150,6 +162,7 @@ static s32 e1000_init_nvm_params_82571(s + + switch (hw->mac.type) { + case e1000_82573: ++ case e1000_82574: + if (((eecd >> 15) & 0x3) == 0x3) { + nvm->type = e1000_nvm_flash_hw; + nvm->word_size = 2048; +@@ -245,6 +258,17 @@ static s32 e1000_init_mac_params_82571(s + break; + } + ++ switch (hw->mac.type) { ++ case e1000_82574: ++ func->check_mng_mode = e1000_check_mng_mode_82574; ++ func->led_on = e1000_led_on_82574; ++ break; ++ default: ++ func->check_mng_mode = e1000e_check_mng_mode_generic; ++ func->led_on = e1000e_led_on_generic; ++ break; ++ } ++ + return 0; + } + +@@ -330,6 +354,8 @@ static s32 e1000_get_variants_82571(stru + static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) + { + struct e1000_phy_info *phy = &hw->phy; ++ s32 ret_val; ++ u16 phy_id = 0; + + switch (hw->mac.type) { + case e1000_82571: +@@ -345,6 +371,20 @@ static s32 e1000_get_phy_id_82571(struct + case e1000_82573: + return e1000e_get_phy_id(hw); + break; ++ case e1000_82574: ++ ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); ++ if (ret_val) ++ return ret_val; ++ ++ phy->id = (u32)(phy_id << 16); ++ udelay(20); ++ ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); ++ if (ret_val) ++ return ret_val; ++ ++ phy->id |= (u32)(phy_id); ++ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); ++ break; + default: + return -E1000_ERR_PHY; + break; +@@ -421,7 +461,7 @@ static s32 e1000_acquire_nvm_82571(struc + if (ret_val) + return ret_val; + +- if (hw->mac.type != e1000_82573) ++ if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574) + ret_val = e1000e_acquire_nvm(hw); + + if (ret_val) +@@ -461,6 +501,7 @@ static s32 e1000_write_nvm_82571(struct + + switch (hw->mac.type) { + case e1000_82573: ++ case e1000_82574: + ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data); + break; + case e1000_82571: +@@ -735,7 +776,7 @@ static s32 e1000_reset_hw_82571(struct e + * Must acquire the MDIO ownership before MAC reset. + * Ownership defaults to firmware after a reset. + */ +- if (hw->mac.type == e1000_82573) { ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + extcnf_ctrl = er32(EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + +@@ -776,7 +817,7 @@ static s32 e1000_reset_hw_82571(struct e + * Need to wait for Phy configuration completion before accessing + * NVM and Phy. + */ +- if (hw->mac.type == e1000_82573) ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) + msleep(25); + + /* Clear any pending interrupt events. */ +@@ -843,7 +884,7 @@ static s32 e1000_init_hw_82571(struct e1 + ew32(TXDCTL(0), reg_data); + + /* ...for both queues. */ +- if (mac->type != e1000_82573) { ++ if (mac->type != e1000_82573 && mac->type != e1000_82574) { + reg_data = er32(TXDCTL(1)); + reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | + E1000_TXDCTL_FULL_TX_DESC_WB | +@@ -918,19 +959,28 @@ static void e1000_initialize_hw_bits_825 + } + + /* Device Control */ +- if (hw->mac.type == e1000_82573) { ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + reg = er32(CTRL); + reg &= ~(1 << 29); + ew32(CTRL, reg); + } + + /* Extended Device Control */ +- if (hw->mac.type == e1000_82573) { ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + reg = er32(CTRL_EXT); + reg &= ~(1 << 23); + reg |= (1 << 22); + ew32(CTRL_EXT, reg); + } ++ ++ /* PCI-Ex Control Register */ ++ if (hw->mac.type == e1000_82574) { ++ reg = er32(GCR); ++ reg |= (1 << 22); ++ ew32(GCR, reg); ++ } ++ ++ return; + } + + /** +@@ -947,7 +997,7 @@ void e1000e_clear_vfta(struct e1000_hw * + u32 vfta_offset = 0; + u32 vfta_bit_in_reg = 0; + +- if (hw->mac.type == e1000_82573) { ++ if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) { + if (hw->mng_cookie.vlan_id != 0) { + /* + * The VFTA is a 4096b bit-field, each identifying +@@ -976,6 +1026,48 @@ void e1000e_clear_vfta(struct e1000_hw * + } + + /** ++ * e1000_check_mng_mode_82574 - Check manageability is enabled ++ * @hw: pointer to the HW structure ++ * ++ * Reads the NVM Initialization Control Word 2 and returns true ++ * (>0) if any manageability is enabled, else false (0). ++ **/ ++static bool e1000_check_mng_mode_82574(struct e1000_hw *hw) ++{ ++ u16 data; ++ ++ e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data); ++ return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0; ++} ++ ++/** ++ * e1000_led_on_82574 - Turn LED on ++ * @hw: pointer to the HW structure ++ * ++ * Turn LED on. ++ **/ ++static s32 e1000_led_on_82574(struct e1000_hw *hw) ++{ ++ u32 ctrl; ++ u32 i; ++ ++ ctrl = hw->mac.ledctl_mode2; ++ if (!(E1000_STATUS_LU & er32(STATUS))) { ++ /* ++ * If no link, then turn LED on by setting the invert bit ++ * for each LED that's "on" (0x0E) in ledctl_mode2. ++ */ ++ for (i = 0; i < 4; i++) ++ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == ++ E1000_LEDCTL_MODE_LED_ON) ++ ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8)); ++ } ++ ew32(LEDCTL, ctrl); ++ ++ return 0; ++} ++ ++/** + * e1000_update_mc_addr_list_82571 - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program +@@ -1018,7 +1110,8 @@ static s32 e1000_setup_link_82571(struct + * the default flow control setting, so we explicitly + * set it to full. + */ +- if (hw->mac.type == e1000_82573) ++ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && ++ hw->fc.type == e1000_fc_default) + hw->fc.type = e1000_fc_full; + + return e1000e_setup_link(hw); +@@ -1045,6 +1138,7 @@ static s32 e1000_setup_copper_link_82571 + + switch (hw->phy.type) { + case e1000_phy_m88: ++ case e1000_phy_bm: + ret_val = e1000e_copper_link_setup_m88(hw); + break; + case e1000_phy_igp_2: +@@ -1114,11 +1208,10 @@ static s32 e1000_valid_led_default_82571 + return ret_val; + } + +- if (hw->mac.type == e1000_82573 && ++ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && + *data == ID_LED_RESERVED_F746) + *data = ID_LED_DEFAULT_82573; +- else if (*data == ID_LED_RESERVED_0000 || +- *data == ID_LED_RESERVED_FFFF) ++ else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + + return 0; +@@ -1265,13 +1358,13 @@ static void e1000_clear_hw_cntrs_82571(s + } + + static struct e1000_mac_operations e82571_mac_ops = { +- .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, ++ /* .check_mng_mode: mac type dependent */ + /* .check_for_link: media type dependent */ + .cleanup_led = e1000e_cleanup_led_generic, + .clear_hw_cntrs = e1000_clear_hw_cntrs_82571, + .get_bus_info = e1000e_get_bus_info_pcie, + /* .get_link_up_info: media type dependent */ +- .led_on = e1000e_led_on_generic, ++ /* .led_on: mac type dependent */ + .led_off = e1000e_led_off_generic, + .update_mc_addr_list = e1000_update_mc_addr_list_82571, + .reset_hw = e1000_reset_hw_82571, +@@ -1312,6 +1405,22 @@ static struct e1000_phy_operations e82_p + .write_phy_reg = e1000e_write_phy_reg_m88, + }; + ++static struct e1000_phy_operations e82_phy_ops_bm = { ++ .acquire_phy = e1000_get_hw_semaphore_82571, ++ .check_reset_block = e1000e_check_reset_block_generic, ++ .commit_phy = e1000e_phy_sw_reset, ++ .force_speed_duplex = e1000e_phy_force_speed_duplex_m88, ++ .get_cfg_done = e1000e_get_cfg_done, ++ .get_cable_length = e1000e_get_cable_length_m88, ++ .get_phy_info = e1000e_get_phy_info_m88, ++ .read_phy_reg = e1000e_read_phy_reg_bm2, ++ .release_phy = e1000_put_hw_semaphore_82571, ++ .reset_phy = e1000e_phy_hw_reset_generic, ++ .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, ++ .set_d3_lplu_state = e1000e_set_d3_lplu_state, ++ .write_phy_reg = e1000e_write_phy_reg_bm2, ++}; ++ + static struct e1000_nvm_operations e82571_nvm_ops = { + .acquire_nvm = e1000_acquire_nvm_82571, + .read_nvm = e1000e_read_nvm_eerd, +@@ -1375,3 +1484,21 @@ struct e1000_info e1000_82573_info = { + .nvm_ops = &e82571_nvm_ops, + }; + ++struct e1000_info e1000_82574_info = { ++ .mac = e1000_82574, ++ .flags = FLAG_HAS_HW_VLAN_FILTER ++ | FLAG_HAS_MSIX ++ | FLAG_HAS_JUMBO_FRAMES ++ | FLAG_HAS_WOL ++ | FLAG_APME_IN_CTRL3 ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_SMART_POWER_DOWN ++ | FLAG_HAS_AMT ++ | FLAG_HAS_CTRLEXT_ON_LOAD, ++ .pba = 20, ++ .get_variants = e1000_get_variants_82571, ++ .mac_ops = &e82571_mac_ops, ++ .phy_ops = &e82_phy_ops_bm, ++ .nvm_ops = &e82571_nvm_ops, ++}; ++ +--- a/drivers/net/e1000e/defines.h ++++ b/drivers/net/e1000e/defines.h +@@ -71,9 +71,11 @@ + #define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ + #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 + #define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 ++#define E1000_CTRL_EXT_EIAME 0x01000000 + #define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ + #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ + #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ ++#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ + + /* Receive Descriptor bit definitions */ + #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +@@ -299,6 +301,7 @@ + #define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ + + /* Header split receive */ ++#define E1000_RFCTL_ACK_DIS 0x00001000 + #define E1000_RFCTL_EXTEN 0x00008000 + #define E1000_RFCTL_IPV6_EX_DIS 0x00010000 + #define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 +@@ -363,6 +366,11 @@ + #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */ + #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */ + #define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ ++#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ ++#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ ++#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ ++#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ ++#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ + + /* + * This defines the bits that are set in the Interrupt Mask +@@ -386,6 +394,11 @@ + #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */ + #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */ + #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */ ++#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ ++#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ ++#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ ++#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */ ++#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ + + /* Interrupt Cause Set */ + #define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +--- a/drivers/net/e1000e/e1000.h ++++ b/drivers/net/e1000e/e1000.h +@@ -62,6 +62,11 @@ struct e1000_info; + e_printk(KERN_NOTICE, adapter, format, ## arg) + + ++/* Interrupt modes, as used by the IntMode paramter */ ++#define E1000E_INT_MODE_LEGACY 0 ++#define E1000E_INT_MODE_MSI 1 ++#define E1000E_INT_MODE_MSIX 2 ++ + /* Tx/Rx descriptor defines */ + #define E1000_DEFAULT_TXD 256 + #define E1000_MAX_TXD 4096 +@@ -95,6 +100,7 @@ enum e1000_boards { + board_82571, + board_82572, + board_82573, ++ board_82574, + board_80003es2lan, + board_ich8lan, + board_ich9lan, +@@ -146,6 +152,12 @@ struct e1000_ring { + /* array of buffer information structs */ + struct e1000_buffer *buffer_info; + ++ char name[IFNAMSIZ + 5]; ++ u32 ims_val; ++ u32 itr_val; ++ u16 itr_register; ++ int set_itr; ++ + struct sk_buff *rx_skb_top; + + struct e1000_queue_stats stats; +@@ -273,6 +285,9 @@ struct e1000_adapter { + u32 test_icr; + + u32 msg_enable; ++ struct msix_entry *msix_entries; ++ int int_mode; ++ u32 eiac_mask; + + u32 eeprom_wol; + u32 wol; +@@ -310,6 +325,7 @@ struct e1000_info { + #define FLAG_HAS_JUMBO_FRAMES (1 << 7) + #define FLAG_READ_ONLY_NVM (1 << 8) + #define FLAG_IS_ICH (1 << 9) ++#define FLAG_HAS_MSIX (1 << 10) + #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) + #define FLAG_IS_QUAD_PORT_A (1 << 12) + #define FLAG_IS_QUAD_PORT (1 << 13) +@@ -371,6 +387,8 @@ extern int e1000e_setup_tx_resources(str + extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); + extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); + extern void e1000e_update_stats(struct e1000_adapter *adapter); ++extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); ++extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); + + extern unsigned int copybreak; + +@@ -379,6 +397,7 @@ extern char *e1000e_get_hw_dev_name(stru + extern struct e1000_info e1000_82571_info; + extern struct e1000_info e1000_82572_info; + extern struct e1000_info e1000_82573_info; ++extern struct e1000_info e1000_82574_info; + extern struct e1000_info e1000_ich8_info; + extern struct e1000_info e1000_ich9_info; + extern struct e1000_info e1000_es2_info; +@@ -458,6 +477,8 @@ extern enum e1000_phy_type e1000e_get_ph + extern s32 e1000e_determine_phy_address(struct e1000_hw *hw); + extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); + extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data); ++extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data); ++extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data); + extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); + extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); + extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); +@@ -528,7 +549,12 @@ static inline s32 e1000_get_phy_info(str + return hw->phy.ops.get_phy_info(hw); + } + +-extern bool e1000e_check_mng_mode(struct e1000_hw *hw); ++static inline s32 e1000e_check_mng_mode(struct e1000_hw *hw) ++{ ++ return hw->mac.ops.check_mng_mode(hw); ++} ++ ++extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw); + extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw); + extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length); + +--- a/drivers/net/e1000e/es2lan.c ++++ b/drivers/net/e1000e/es2lan.c +@@ -1247,7 +1247,7 @@ static void e1000_clear_hw_cntrs_80003es + } + + static struct e1000_mac_operations es2_mac_ops = { +- .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, ++ .check_mng_mode = e1000e_check_mng_mode_generic, + /* check_for_link dependent on media type */ + .cleanup_led = e1000e_cleanup_led_generic, + .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan, +--- a/drivers/net/e1000e/ethtool.c ++++ b/drivers/net/e1000e/ethtool.c +@@ -575,6 +575,7 @@ static int e1000_set_eeprom(struct net_d + * and flush shadow RAM for 82573 controllers + */ + if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || ++ (hw->mac.type == e1000_82574) || + (hw->mac.type == e1000_82573))) + e1000e_update_nvm_checksum(hw); + +@@ -786,6 +787,7 @@ static int e1000_reg_test(struct e1000_a + toggle = 0x7FFFF3FF; + break; + case e1000_82573: ++ case e1000_82574: + case e1000_ich8lan: + case e1000_ich9lan: + toggle = 0x7FFFF033; +@@ -891,10 +893,18 @@ static int e1000_intr_test(struct e1000_ + u32 shared_int = 1; + u32 irq = adapter->pdev->irq; + int i; ++ int ret_val = 0; ++ int int_mode = E1000E_INT_MODE_LEGACY; + + *data = 0; + +- /* NOTE: we don't test MSI interrupts here, yet */ ++ /* NOTE: we don't test MSI/MSI-X interrupts here, yet */ ++ if (adapter->int_mode == E1000E_INT_MODE_MSIX) { ++ int_mode = adapter->int_mode; ++ e1000e_reset_interrupt_capability(adapter); ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; ++ e1000e_set_interrupt_capability(adapter); ++ } + /* Hook up test interrupt handler just for this test */ + if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, + netdev)) { +@@ -902,7 +912,8 @@ static int e1000_intr_test(struct e1000_ + } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; +- return -1; ++ ret_val = -1; ++ goto out; + } + e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared")); + +@@ -981,7 +992,14 @@ static int e1000_intr_test(struct e1000_ + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + +- return *data; ++out: ++ if (int_mode == E1000E_INT_MODE_MSIX) { ++ e1000e_reset_interrupt_capability(adapter); ++ adapter->int_mode = int_mode; ++ e1000e_set_interrupt_capability(adapter); ++ } ++ ++ return ret_val; + } + + static void e1000_free_desc_rings(struct e1000_adapter *adapter) +@@ -1766,11 +1784,13 @@ static void e1000_led_blink_callback(uns + static int e1000_phys_id(struct net_device *netdev, u32 data) + { + struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; + + if (!data) + data = INT_MAX; + +- if (adapter->hw.phy.type == e1000_phy_ife) { ++ if ((hw->phy.type == e1000_phy_ife) || ++ (hw->mac.type == e1000_82574)) { + if (!adapter->blink_timer.function) { + init_timer(&adapter->blink_timer); + adapter->blink_timer.function = +@@ -1780,16 +1800,16 @@ static int e1000_phys_id(struct net_devi + mod_timer(&adapter->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&adapter->blink_timer); +- e1e_wphy(&adapter->hw, +- IFE_PHY_SPECIAL_CONTROL_LED, 0); ++ if (hw->phy.type == e1000_phy_ife) ++ e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); + } else { +- e1000e_blink_led(&adapter->hw); ++ e1000e_blink_led(hw); + msleep_interruptible(data * 1000); + } + +- adapter->hw.mac.ops.led_off(&adapter->hw); ++ hw->mac.ops.led_off(hw); + clear_bit(E1000_LED_ON, &adapter->led_status); +- adapter->hw.mac.ops.cleanup_led(&adapter->hw); ++ hw->mac.ops.cleanup_led(hw); + + return 0; + } +--- a/drivers/net/e1000e/hw.h ++++ b/drivers/net/e1000e/hw.h +@@ -65,7 +65,11 @@ enum e1e_registers { + E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */ + E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */ + E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */ ++ E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */ + E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */ ++ E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */ ++ E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */ ++#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2)) + E1000_RCTL = 0x00100, /* Rx Control - RW */ + E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */ + E1000_TXCW = 0x00178, /* Tx Configuration Word - RW */ +@@ -332,6 +336,7 @@ enum e1e_registers { + #define E1000_DEV_ID_82573E 0x108B + #define E1000_DEV_ID_82573E_IAMT 0x108C + #define E1000_DEV_ID_82573L 0x109A ++#define E1000_DEV_ID_82574L 0x10D3 + + #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 + #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +@@ -357,12 +362,15 @@ enum e1e_registers { + #define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD + #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE + ++#define E1000_REVISION_4 4 ++ + #define E1000_FUNC_1 1 + + enum e1000_mac_type { + e1000_82571, + e1000_82572, + e1000_82573, ++ e1000_82574, + e1000_80003es2lan, + e1000_ich8lan, + e1000_ich9lan, +@@ -696,8 +704,7 @@ struct e1000_host_mng_command_info { + + /* Function pointers and static data for the MAC. */ + struct e1000_mac_operations { +- u32 mng_mode_enab; +- ++ bool (*check_mng_mode)(struct e1000_hw *); + s32 (*check_for_link)(struct e1000_hw *); + s32 (*cleanup_led)(struct e1000_hw *); + void (*clear_hw_cntrs)(struct e1000_hw *); +--- a/drivers/net/e1000e/ich8lan.c ++++ b/drivers/net/e1000e/ich8lan.c +@@ -448,6 +448,22 @@ static void e1000_release_swflag_ich8lan + } + + /** ++ * e1000_check_mng_mode_ich8lan - Checks management mode ++ * @hw: pointer to the HW structure ++ * ++ * This checks if the adapter has manageability enabled. ++ * This is a function pointer entry point only called by read/write ++ * routines for the PHY and NVM parts. ++ **/ ++static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) ++{ ++ u32 fwsm = er32(FWSM); ++ ++ return (fwsm & E1000_FWSM_MODE_MASK) == ++ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); ++} ++ ++/** + * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * +@@ -2365,7 +2381,7 @@ static void e1000_clear_hw_cntrs_ich8lan + } + + static struct e1000_mac_operations ich8_mac_ops = { +- .mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT, ++ .check_mng_mode = e1000_check_mng_mode_ich8lan, + .check_for_link = e1000e_check_for_copper_link, + .cleanup_led = e1000_cleanup_led_ich8lan, + .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, +--- a/drivers/net/e1000e/lib.c ++++ b/drivers/net/e1000e/lib.c +@@ -2222,17 +2222,18 @@ static s32 e1000_mng_enable_host_if(stru + } + + /** +- * e1000e_check_mng_mode - check management mode ++ * e1000e_check_mng_mode_generic - check management mode + * @hw: pointer to the HW structure + * + * Reads the firmware semaphore register and returns true (>0) if + * manageability is enabled, else false (0). + **/ +-bool e1000e_check_mng_mode(struct e1000_hw *hw) ++bool e1000e_check_mng_mode_generic(struct e1000_hw *hw) + { + u32 fwsm = er32(FWSM); + +- return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab; ++ return (fwsm & E1000_FWSM_MODE_MASK) == ++ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); + } + + /** +--- a/drivers/net/e1000e/netdev.c ++++ b/drivers/net/e1000e/netdev.c +@@ -55,6 +55,7 @@ static const struct e1000_info *e1000_in + [board_82571] = &e1000_82571_info, + [board_82572] = &e1000_82572_info, + [board_82573] = &e1000_82573_info, ++ [board_82574] = &e1000_82574_info, + [board_80003es2lan] = &e1000_es2_info, + [board_ich8lan] = &e1000_ich8_info, + [board_ich9lan] = &e1000_ich9_info, +@@ -1201,8 +1202,8 @@ static irqreturn_t e1000_intr(int irq, v + struct net_device *netdev = data; + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; +- + u32 rctl, icr = er32(ICR); ++ + if (!icr) + return IRQ_NONE; /* Not our interrupt */ + +@@ -1258,6 +1259,263 @@ static irqreturn_t e1000_intr(int irq, v + return IRQ_HANDLED; + } + ++static irqreturn_t e1000_msix_other(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ u32 icr = er32(ICR); ++ ++ if (!(icr & E1000_ICR_INT_ASSERTED)) { ++ ew32(IMS, E1000_IMS_OTHER); ++ return IRQ_NONE; ++ } ++ ++ if (icr & adapter->eiac_mask) ++ ew32(ICS, (icr & adapter->eiac_mask)); ++ ++ if (icr & E1000_ICR_OTHER) { ++ if (!(icr & E1000_ICR_LSC)) ++ goto no_link_interrupt; ++ hw->mac.get_link_status = 1; ++ /* guard against interrupt when we're going down */ ++ if (!test_bit(__E1000_DOWN, &adapter->state)) ++ mod_timer(&adapter->watchdog_timer, jiffies + 1); ++ } ++ ++no_link_interrupt: ++ ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++static irqreturn_t e1000_intr_msix_tx(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ ++ ++ adapter->total_tx_bytes = 0; ++ adapter->total_tx_packets = 0; ++ ++ if (!e1000_clean_tx_irq(adapter)) ++ /* Ring was not completely cleaned, so fire another interrupt */ ++ ew32(ICS, tx_ring->ims_val); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t e1000_intr_msix_rx(int irq, void *data) ++{ ++ struct net_device *netdev = data; ++ struct e1000_adapter *adapter = netdev_priv(netdev); ++ ++ /* Write the ITR value calculated at the end of the ++ * previous interrupt. ++ */ ++ if (adapter->rx_ring->set_itr) { ++ writel(1000000000 / (adapter->rx_ring->itr_val * 256), ++ adapter->hw.hw_addr + adapter->rx_ring->itr_register); ++ adapter->rx_ring->set_itr = 0; ++ } ++ ++ if (netif_rx_schedule_prep(netdev, &adapter->napi)) { ++ adapter->total_rx_bytes = 0; ++ adapter->total_rx_packets = 0; ++ __netif_rx_schedule(netdev, &adapter->napi); ++ } ++ return IRQ_HANDLED; ++} ++ ++/** ++ * e1000_configure_msix - Configure MSI-X hardware ++ * ++ * e1000_configure_msix sets up the hardware to properly ++ * generate MSI-X interrupts. ++ **/ ++static void e1000_configure_msix(struct e1000_adapter *adapter) ++{ ++ struct e1000_hw *hw = &adapter->hw; ++ struct e1000_ring *rx_ring = adapter->rx_ring; ++ struct e1000_ring *tx_ring = adapter->tx_ring; ++ int vector = 0; ++ u32 ctrl_ext, ivar = 0; ++ ++ adapter->eiac_mask = 0; ++ ++ /* Workaround issue with spurious interrupts on 82574 in MSI-X mode */ ++ if (hw->mac.type == e1000_82574) { ++ u32 rfctl = er32(RFCTL); ++ rfctl |= E1000_RFCTL_ACK_DIS; ++ ew32(RFCTL, rfctl); ++ } ++ ++#define E1000_IVAR_INT_ALLOC_VALID 0x8 ++ /* Configure Rx vector */ ++ rx_ring->ims_val = E1000_IMS_RXQ0; ++ adapter->eiac_mask |= rx_ring->ims_val; ++ if (rx_ring->itr_val) ++ writel(1000000000 / (rx_ring->itr_val * 256), ++ hw->hw_addr + rx_ring->itr_register); ++ else ++ writel(1, hw->hw_addr + rx_ring->itr_register); ++ ivar = E1000_IVAR_INT_ALLOC_VALID | vector; ++ ++ /* Configure Tx vector */ ++ tx_ring->ims_val = E1000_IMS_TXQ0; ++ vector++; ++ if (tx_ring->itr_val) ++ writel(1000000000 / (tx_ring->itr_val * 256), ++ hw->hw_addr + tx_ring->itr_register); ++ else ++ writel(1, hw->hw_addr + tx_ring->itr_register); ++ adapter->eiac_mask |= tx_ring->ims_val; ++ ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8); ++ ++ /* set vector for Other Causes, e.g. link changes */ ++ vector++; ++ ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16); ++ if (rx_ring->itr_val) ++ writel(1000000000 / (rx_ring->itr_val * 256), ++ hw->hw_addr + E1000_EITR_82574(vector)); ++ else ++ writel(1, hw->hw_addr + E1000_EITR_82574(vector)); ++ ++ /* Cause Tx interrupts on every write back */ ++ ivar |= (1 << 31); ++ ++ ew32(IVAR, ivar); ++ ++ /* enable MSI-X PBA support */ ++ ctrl_ext = er32(CTRL_EXT); ++ ctrl_ext |= E1000_CTRL_EXT_PBA_CLR; ++ ++ /* Auto-Mask Other interrupts upon ICR read */ ++#define E1000_EIAC_MASK_82574 0x01F00000 ++ ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER); ++ ctrl_ext |= E1000_CTRL_EXT_EIAME; ++ ew32(CTRL_EXT, ctrl_ext); ++ e1e_flush(); ++} ++ ++void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter) ++{ ++ if (adapter->msix_entries) { ++ pci_disable_msix(adapter->pdev); ++ kfree(adapter->msix_entries); ++ adapter->msix_entries = NULL; ++ } else if (adapter->flags & FLAG_MSI_ENABLED) { ++ pci_disable_msi(adapter->pdev); ++ adapter->flags &= ~FLAG_MSI_ENABLED; ++ } ++ ++ return; ++} ++ ++/** ++ * e1000e_set_interrupt_capability - set MSI or MSI-X if supported ++ * ++ * Attempt to configure interrupts using the best available ++ * capabilities of the hardware and kernel. ++ **/ ++void e1000e_set_interrupt_capability(struct e1000_adapter *adapter) ++{ ++ int err; ++ int numvecs, i; ++ ++ ++ switch (adapter->int_mode) { ++ case E1000E_INT_MODE_MSIX: ++ if (adapter->flags & FLAG_HAS_MSIX) { ++ numvecs = 3; /* RxQ0, TxQ0 and other */ ++ adapter->msix_entries = kcalloc(numvecs, ++ sizeof(struct msix_entry), ++ GFP_KERNEL); ++ if (adapter->msix_entries) { ++ for (i = 0; i < numvecs; i++) ++ adapter->msix_entries[i].entry = i; ++ ++ err = pci_enable_msix(adapter->pdev, ++ adapter->msix_entries, ++ numvecs); ++ if (err == 0) ++ return; ++ } ++ /* MSI-X failed, so fall through and try MSI */ ++ e_err("Failed to initialize MSI-X interrupts. " ++ "Falling back to MSI interrupts.\n"); ++ e1000e_reset_interrupt_capability(adapter); ++ } ++ adapter->int_mode = E1000E_INT_MODE_MSI; ++ /* Fall through */ ++ case E1000E_INT_MODE_MSI: ++ if (!pci_enable_msi(adapter->pdev)) { ++ adapter->flags |= FLAG_MSI_ENABLED; ++ } else { ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; ++ e_err("Failed to initialize MSI interrupts. Falling " ++ "back to legacy interrupts.\n"); ++ } ++ /* Fall through */ ++ case E1000E_INT_MODE_LEGACY: ++ /* Don't do anything; this is the system default */ ++ break; ++ } ++ ++ return; ++} ++ ++/** ++ * e1000_request_msix - Initialize MSI-X interrupts ++ * ++ * e1000_request_msix allocates MSI-X vectors and requests interrupts from the ++ * kernel. ++ **/ ++static int e1000_request_msix(struct e1000_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdev; ++ int err = 0, vector = 0; ++ ++ if (strlen(netdev->name) < (IFNAMSIZ - 5)) ++ sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name); ++ else ++ memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); ++ err = request_irq(adapter->msix_entries[vector].vector, ++ &e1000_intr_msix_rx, 0, adapter->rx_ring->name, ++ netdev); ++ if (err) ++ goto out; ++ adapter->rx_ring->itr_register = E1000_EITR_82574(vector); ++ adapter->rx_ring->itr_val = adapter->itr; ++ vector++; ++ ++ if (strlen(netdev->name) < (IFNAMSIZ - 5)) ++ sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); ++ else ++ memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); ++ err = request_irq(adapter->msix_entries[vector].vector, ++ &e1000_intr_msix_tx, 0, adapter->tx_ring->name, ++ netdev); ++ if (err) ++ goto out; ++ adapter->tx_ring->itr_register = E1000_EITR_82574(vector); ++ adapter->tx_ring->itr_val = adapter->itr; ++ vector++; ++ ++ err = request_irq(adapter->msix_entries[vector].vector, ++ &e1000_msix_other, 0, netdev->name, netdev); ++ if (err) ++ goto out; ++ ++ e1000_configure_msix(adapter); ++ return 0; ++out: ++ return err; ++} ++ + /** + * e1000_request_irq - initialize interrupts + * +@@ -1267,29 +1525,33 @@ static irqreturn_t e1000_intr(int irq, v + static int e1000_request_irq(struct e1000_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +- int irq_flags = IRQF_SHARED; + int err; + +- if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) { +- err = pci_enable_msi(adapter->pdev); +- if (!err) { +- adapter->flags |= FLAG_MSI_ENABLED; +- irq_flags = 0; +- } ++ if (adapter->msix_entries) { ++ err = e1000_request_msix(adapter); ++ if (!err) ++ return err; ++ /* fall back to MSI */ ++ e1000e_reset_interrupt_capability(adapter); ++ adapter->int_mode = E1000E_INT_MODE_MSI; ++ e1000e_set_interrupt_capability(adapter); + } ++ if (adapter->flags & FLAG_MSI_ENABLED) { ++ err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0, ++ netdev->name, netdev); ++ if (!err) ++ return err; + +- err = request_irq(adapter->pdev->irq, +- ((adapter->flags & FLAG_MSI_ENABLED) ? +- &e1000_intr_msi : &e1000_intr), +- irq_flags, netdev->name, netdev); +- if (err) { +- if (adapter->flags & FLAG_MSI_ENABLED) { +- pci_disable_msi(adapter->pdev); +- adapter->flags &= ~FLAG_MSI_ENABLED; +- } +- e_err("Unable to allocate interrupt, Error: %d\n", err); ++ /* fall back to legacy interrupt */ ++ e1000e_reset_interrupt_capability(adapter); ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; + } + ++ err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED, ++ netdev->name, netdev); ++ if (err) ++ e_err("Unable to allocate interrupt, Error: %d\n", err); ++ + return err; + } + +@@ -1297,11 +1559,21 @@ static void e1000_free_irq(struct e1000_ + { + struct net_device *netdev = adapter->netdev; + +- free_irq(adapter->pdev->irq, netdev); +- if (adapter->flags & FLAG_MSI_ENABLED) { +- pci_disable_msi(adapter->pdev); +- adapter->flags &= ~FLAG_MSI_ENABLED; ++ if (adapter->msix_entries) { ++ int vector = 0; ++ ++ free_irq(adapter->msix_entries[vector].vector, netdev); ++ vector++; ++ ++ free_irq(adapter->msix_entries[vector].vector, netdev); ++ vector++; ++ ++ /* Other Causes interrupt vector */ ++ free_irq(adapter->msix_entries[vector].vector, netdev); ++ return; + } ++ ++ free_irq(adapter->pdev->irq, netdev); + } + + /** +@@ -1312,6 +1584,8 @@ static void e1000_irq_disable(struct e10 + struct e1000_hw *hw = &adapter->hw; + + ew32(IMC, ~0); ++ if (adapter->msix_entries) ++ ew32(EIAC_82574, 0); + e1e_flush(); + synchronize_irq(adapter->pdev->irq); + } +@@ -1323,7 +1597,12 @@ static void e1000_irq_enable(struct e100 + { + struct e1000_hw *hw = &adapter->hw; + +- ew32(IMS, IMS_ENABLE_MASK); ++ if (adapter->msix_entries) { ++ ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); ++ ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC); ++ } else { ++ ew32(IMS, IMS_ENABLE_MASK); ++ } + e1e_flush(); + } + +@@ -1573,9 +1852,8 @@ void e1000e_free_rx_resources(struct e10 + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time +- * while increasing bulk throughput. +- * this functionality is controlled by the InterruptThrottleRate module +- * parameter (see e1000_param.c) ++ * while increasing bulk throughput. This functionality is controlled ++ * by the InterruptThrottleRate module parameter. + **/ + static unsigned int e1000_update_itr(struct e1000_adapter *adapter, + u16 itr_setting, int packets, +@@ -1683,11 +1961,37 @@ set_itr_now: + min(adapter->itr + (new_itr >> 2), new_itr) : + new_itr; + adapter->itr = new_itr; +- ew32(ITR, 1000000000 / (new_itr * 256)); ++ adapter->rx_ring->itr_val = new_itr; ++ if (adapter->msix_entries) ++ adapter->rx_ring->set_itr = 1; ++ else ++ ew32(ITR, 1000000000 / (new_itr * 256)); + } + } + + /** ++ * e1000_alloc_queues - Allocate memory for all rings ++ * @adapter: board private structure to initialize ++ **/ ++static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) ++{ ++ adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); ++ if (!adapter->tx_ring) ++ goto err; ++ ++ adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); ++ if (!adapter->rx_ring) ++ goto err; ++ ++ return 0; ++err: ++ e_err("Unable to allocate memory for queues\n"); ++ kfree(adapter->rx_ring); ++ kfree(adapter->tx_ring); ++ return -ENOMEM; ++} ++ ++/** + * e1000_clean - NAPI Rx polling callback + * @napi: struct associated with this polling callback + * @budget: amount of packets driver is allowed to process this poll +@@ -1695,12 +1999,17 @@ set_itr_now: + static int e1000_clean(struct napi_struct *napi, int budget) + { + struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi); ++ struct e1000_hw *hw = &adapter->hw; + struct net_device *poll_dev = adapter->netdev; + int tx_cleaned = 0, work_done = 0; + + /* Must NOT use netdev_priv macro here. */ + adapter = poll_dev->priv; + ++ if (adapter->msix_entries && ++ !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) ++ goto clean_rx; ++ + /* + * e1000_clean is called per-cpu. This lock protects + * tx_ring from being cleaned by multiple cpus +@@ -1712,6 +2021,7 @@ static int e1000_clean(struct napi_struc + spin_unlock(&adapter->tx_queue_lock); + } + ++clean_rx: + adapter->clean_rx(adapter, &work_done, budget); + + if (tx_cleaned) +@@ -1722,7 +2032,10 @@ static int e1000_clean(struct napi_struc + if (adapter->itr_setting & 3) + e1000_set_itr(adapter); + netif_rx_complete(poll_dev, napi); +- e1000_irq_enable(adapter); ++ if (adapter->msix_entries) ++ ew32(IMS, adapter->rx_ring->ims_val); ++ else ++ e1000_irq_enable(adapter); + } + + return work_done; +@@ -2522,6 +2835,8 @@ int e1000e_up(struct e1000_adapter *adap + clear_bit(__E1000_DOWN, &adapter->state); + + napi_enable(&adapter->napi); ++ if (adapter->msix_entries) ++ e1000_configure_msix(adapter); + e1000_irq_enable(adapter); + + /* fire a link change interrupt to start the watchdog */ +@@ -2605,13 +2920,10 @@ static int __devinit e1000_sw_init(struc + adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + +- adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); +- if (!adapter->tx_ring) +- goto err; ++ e1000e_set_interrupt_capability(adapter); + +- adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL); +- if (!adapter->rx_ring) +- goto err; ++ if (e1000_alloc_queues(adapter)) ++ return -ENOMEM; + + spin_lock_init(&adapter->tx_queue_lock); + +@@ -2620,12 +2932,6 @@ static int __devinit e1000_sw_init(struc + + set_bit(__E1000_DOWN, &adapter->state); + return 0; +- +-err: +- e_err("Unable to allocate memory for queues\n"); +- kfree(adapter->rx_ring); +- kfree(adapter->tx_ring); +- return -ENOMEM; + } + + /** +@@ -2667,6 +2973,7 @@ static int e1000_test_msi_interrupt(stru + + /* free the real vector and request a test handler */ + e1000_free_irq(adapter); ++ e1000e_reset_interrupt_capability(adapter); + + /* Assume that the test fails, if it succeeds then the test + * MSI irq handler will unset this flag */ +@@ -2697,6 +3004,7 @@ static int e1000_test_msi_interrupt(stru + rmb(); + + if (adapter->flags & FLAG_MSI_TEST_FAILED) { ++ adapter->int_mode = E1000E_INT_MODE_LEGACY; + err = -EIO; + e_info("MSI interrupt test failed!\n"); + } +@@ -2710,7 +3018,7 @@ static int e1000_test_msi_interrupt(stru + /* okay so the test worked, restore settings */ + e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name); + msi_test_failed: +- /* restore the original vector, even if it failed */ ++ e1000e_set_interrupt_capability(adapter); + e1000_request_irq(adapter); + return err; + } +@@ -2820,7 +3128,7 @@ static int e1000_open(struct net_device + * ignore e1000e MSI messages, which means we need to test our MSI + * interrupt now + */ +- { ++ if (adapter->int_mode != E1000E_INT_MODE_LEGACY) { + err = e1000_test_msi(adapter); + if (err) { + e_err("Interrupt allocation failed\n"); +@@ -3015,7 +3323,8 @@ void e1000e_update_stats(struct e1000_ad + + adapter->stats.algnerrc += er32(ALGNERRC); + adapter->stats.rxerrc += er32(RXERRC); +- adapter->stats.tncrs += er32(TNCRS); ++ if (hw->mac.type != e1000_82574) ++ adapter->stats.tncrs += er32(TNCRS); + adapter->stats.cexterr += er32(CEXTERR); + adapter->stats.tsctc += er32(TSCTC); + adapter->stats.tsctfc += er32(TSCTFC); +@@ -3325,7 +3634,10 @@ link_up: + } + + /* Cause software interrupt to ensure Rx ring is cleaned */ +- ew32(ICS, E1000_ICS_RXDMT0); ++ if (adapter->msix_entries) ++ ew32(ICS, adapter->rx_ring->ims_val); ++ else ++ ew32(ICS, E1000_ICS_RXDMT0); + + /* Force detection of hung controller every watchdog period */ + adapter->detect_tx_hung = 1; +@@ -4042,6 +4354,7 @@ static int e1000_suspend(struct pci_dev + e1000e_down(adapter); + e1000_free_irq(adapter); + } ++ e1000e_reset_interrupt_capability(adapter); + + retval = pci_save_state(pdev); + if (retval) +@@ -4168,6 +4481,7 @@ static int e1000_resume(struct pci_dev * + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + ++ e1000e_set_interrupt_capability(adapter); + if (netif_running(netdev)) { + err = e1000_request_irq(adapter); + if (err) +@@ -4722,6 +5036,7 @@ static void __devexit e1000_remove(struc + if (!e1000_check_reset_block(&adapter->hw)) + e1000_phy_hw_reset(&adapter->hw); + ++ e1000e_reset_interrupt_capability(adapter); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + +@@ -4763,6 +5078,8 @@ static struct pci_device_id e1000_pci_tb + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 }, + ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 }, ++ + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT), + board_80003es2lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT), +--- a/drivers/net/e1000e/param.c ++++ b/drivers/net/e1000e/param.c +@@ -114,6 +114,15 @@ E1000_PARAM(InterruptThrottleRate, "Inte + #define DEFAULT_ITR 3 + #define MAX_ITR 100000 + #define MIN_ITR 100 ++/* IntMode (Interrupt Mode) ++ * ++ * Valid Range: 0 - 2 ++ * ++ * Default Value: 2 (MSI-X) ++ */ ++E1000_PARAM(IntMode, "Interrupt Mode"); ++#define MAX_INTMODE 2 ++#define MIN_INTMODE 0 + + /* + * Enable Smart Power Down of the PHY +@@ -371,6 +380,24 @@ void __devinit e1000e_check_options(stru + adapter->itr = 20000; + } + } ++ { /* Interrupt Mode */ ++ struct e1000_option opt = { ++ .type = range_option, ++ .name = "Interrupt Mode", ++ .err = "defaulting to 2 (MSI-X)", ++ .def = E1000E_INT_MODE_MSIX, ++ .arg = { .r = { .min = MIN_INTMODE, ++ .max = MAX_INTMODE } } ++ }; ++ ++ if (num_IntMode > bd) { ++ unsigned int int_mode = IntMode[bd]; ++ e1000_validate_option(&int_mode, &opt, adapter); ++ adapter->int_mode = int_mode; ++ } else { ++ adapter->int_mode = opt.def; ++ } ++ } + { /* Smart Power Down */ + const struct e1000_option opt = { + .type = enable_option, +--- a/drivers/net/e1000e/phy.c ++++ b/drivers/net/e1000e/phy.c +@@ -476,7 +476,9 @@ s32 e1000e_copper_link_setup_m88(struct + if (ret_val) + return ret_val; + +- if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) { ++ if ((phy->type == e1000_phy_m88) && ++ (phy->revision < E1000_REVISION_4) && ++ (phy->id != BME1000_E_PHY_ID_R2)) { + /* + * Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. +@@ -504,6 +506,18 @@ s32 e1000e_copper_link_setup_m88(struct + return ret_val; + } + ++ if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) { ++ /* Set PHY page 0, register 29 to 0x0003 */ ++ ret_val = e1e_wphy(hw, 29, 0x0003); ++ if (ret_val) ++ return ret_val; ++ ++ /* Set PHY page 0, register 30 to 0x0000 */ ++ ret_val = e1e_wphy(hw, 30, 0x0000); ++ if (ret_val) ++ return ret_val; ++ } ++ + /* Commit the changes. */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) +@@ -1969,6 +1983,99 @@ out: + } + + /** ++ * e1000e_read_phy_reg_bm2 - Read BM PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to be read ++ * @data: pointer to the read data ++ * ++ * Acquires semaphore, if necessary, then reads the PHY register at offset ++ * and storing the retrieved information in data. Release any acquired ++ * semaphores before exiting. ++ **/ ++s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) ++{ ++ s32 ret_val; ++ u16 page = (u16)(offset >> IGP_PAGE_SHIFT); ++ ++ /* Page 800 works differently than the rest so it has its own func */ ++ if (page == BM_WUC_PAGE) { ++ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, ++ true); ++ return ret_val; ++ } ++ ++ ret_val = hw->phy.ops.acquire_phy(hw); ++ if (ret_val) ++ return ret_val; ++ ++ hw->phy.addr = 1; ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ ++ /* Page is shifted left, PHY expects (page x 32) */ ++ ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, ++ page); ++ ++ if (ret_val) { ++ hw->phy.ops.release_phy(hw); ++ return ret_val; ++ } ++ } ++ ++ ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, ++ data); ++ hw->phy.ops.release_phy(hw); ++ ++ return ret_val; ++} ++ ++/** ++ * e1000e_write_phy_reg_bm2 - Write BM PHY register ++ * @hw: pointer to the HW structure ++ * @offset: register offset to write to ++ * @data: data to write at register offset ++ * ++ * Acquires semaphore, if necessary, then writes the data to PHY register ++ * at the offset. Release any acquired semaphores before exiting. ++ **/ ++s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) ++{ ++ s32 ret_val; ++ u16 page = (u16)(offset >> IGP_PAGE_SHIFT); ++ ++ /* Page 800 works differently than the rest so it has its own func */ ++ if (page == BM_WUC_PAGE) { ++ ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, ++ false); ++ return ret_val; ++ } ++ ++ ret_val = hw->phy.ops.acquire_phy(hw); ++ if (ret_val) ++ return ret_val; ++ ++ hw->phy.addr = 1; ++ ++ if (offset > MAX_PHY_MULTI_PAGE_REG) { ++ /* Page is shifted left, PHY expects (page x 32) */ ++ ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, ++ page); ++ ++ if (ret_val) { ++ hw->phy.ops.release_phy(hw); ++ return ret_val; ++ } ++ } ++ ++ ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, ++ data); ++ ++ hw->phy.ops.release_phy(hw); ++ ++ return ret_val; ++} ++ ++/** + * e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register + * @hw: pointer to the HW structure + * @offset: register offset to be read or written diff --git a/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_ECC b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_ECC new file mode 100644 index 000000000..158d177aa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_ECC @@ -0,0 +1,62 @@ +From: John Ronciak +Acked-by: Karsten Keil +Subject: e1000e: enable ECC +Bugzilla: bnc#445829 + +Small fix accepted upstream to enable ECC in Ophir HW in the e1000e driver. +I'll attach the patch next. IBM is asking for us to get this fix into the +disti releases. + + drivers/net/e1000e/82571.c | 6 ++++++ + drivers/net/e1000e/defines.h | 7 +++++++ + drivers/net/e1000e/hw.h | 1 + + 3 files changed, 14 insertions(+), 0 deletions(-) + + +Index: linux-2.6.27/drivers/net/e1000e/82571.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/e1000e/82571.c ++++ linux-2.6.27/drivers/net/e1000e/82571.c +@@ -973,6 +973,12 @@ static void e1000_initialize_hw_bits_825 + ew32(CTRL_EXT, reg); + } + ++ if (hw->mac.type == e1000_82571) { ++ reg = er32(PBA_ECC); ++ reg |= E1000_PBA_ECC_CORR_EN; ++ ew32(PBA_ECC, reg); ++ } ++ + /* PCI-Ex Control Register */ + if (hw->mac.type == e1000_82574) { + reg = er32(GCR); +Index: linux-2.6.27/drivers/net/e1000e/defines.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/e1000e/defines.h ++++ linux-2.6.27/drivers/net/e1000e/defines.h +@@ -372,6 +372,13 @@ + #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ + #define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ + ++/* PBA ECC Register */ ++#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ ++#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */ ++#define E1000_PBA_ECC_CORR_EN 0x00000001 /* ECC correction enable */ ++#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */ ++#define E1000_PBA_ECC_INT_EN 0x00000004 /* Enable ICR bit 5 for ECC */ ++ + /* + * This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: +Index: linux-2.6.27/drivers/net/e1000e/hw.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/e1000e/hw.h ++++ linux-2.6.27/drivers/net/e1000e/hw.h +@@ -87,6 +87,7 @@ enum e1e_registers { + E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */ + E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */ + E1000_FLOP = 0x0103C, /* FLASH Opcode Register */ ++ E1000_PBA_ECC = 0x01100, /* PBA ECC Register */ + E1000_ERT = 0x02008, /* Early Rx Threshold - RW */ + E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */ + E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_ICH9_BM.patch b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_ICH9_BM.patch new file mode 100644 index 000000000..c08e65b48 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_ICH9_BM.patch @@ -0,0 +1,44 @@ +From: Bruce Allan +Acked-by: Karsten Keil +Subject: e1000e: add support for the 82567LM-4 device +Reference: fate 303916,303898 + +Enable PCI device ID for a new combination of MAC and PHY already supported +in the driver. +--- + + drivers/net/e1000e/hw.h | 1 + + drivers/net/e1000e/ich8lan.c | 1 + + drivers/net/e1000e/netdev.c | 1 + + 3 files changed, 3 insertions(+) + +--- a/drivers/net/e1000e/hw.h ++++ b/drivers/net/e1000e/hw.h +@@ -351,6 +351,7 @@ enum e1e_registers { + #define E1000_DEV_ID_ICH8_IFE_G 0x10C5 + #define E1000_DEV_ID_ICH8_IGP_M 0x104D + #define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD ++#define E1000_DEV_ID_ICH9_BM 0x10E5 + #define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5 + #define E1000_DEV_ID_ICH9_IGP_M 0x10BF + #define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB +--- a/drivers/net/e1000e/ich8lan.c ++++ b/drivers/net/e1000e/ich8lan.c +@@ -44,6 +44,7 @@ + * 82567LF-2 Gigabit Network Connection + * 82567V-2 Gigabit Network Connection + * 82562GT-3 10/100 Network Connection ++ * 82567LM-4 Gigabit Network Connection + */ + + #include +--- a/drivers/net/e1000e/netdev.c ++++ b/drivers/net/e1000e/netdev.c +@@ -5102,6 +5102,7 @@ static struct pci_device_id e1000_pci_tb + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_LOM_devices.patch b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_LOM_devices.patch new file mode 100644 index 000000000..121a108cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/e1000e_add_LOM_devices.patch @@ -0,0 +1,518 @@ +From: Bruce Allan +Acked-by: Karsten Keil +Subject: e1000e: add support for 82567LM-3 and 82567LF-3 (ICH10D) +Reference: fate 303916,303898 + +Add support for new LOM devices on the latest generation ICHx platforms. +--- + + drivers/net/e1000e/defines.h | 2 + drivers/net/e1000e/e1000.h | 3 + drivers/net/e1000e/ethtool.c | 22 +++++- + drivers/net/e1000e/hw.h | 3 + drivers/net/e1000e/ich8lan.c | 154 ++++++++++++++++++++++++++++++++++++++++--- + drivers/net/e1000e/netdev.c | 25 ++++++ + drivers/net/e1000e/phy.c | 85 +++++++++++++++++++++++ + 7 files changed, 280 insertions(+), 14 deletions(-) + +--- a/drivers/net/e1000e/defines.h ++++ b/drivers/net/e1000e/defines.h +@@ -518,6 +518,7 @@ + #define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ + + /* Autoneg Expansion Register */ ++#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ + + /* 1000BASE-T Control Register */ + #define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +@@ -553,6 +554,7 @@ + #define E1000_EECD_DO 0x00000008 /* NVM Data Out */ + #define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ + #define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ ++#define E1000_EECD_PRES 0x00000100 /* NVM Present */ + #define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ + /* NVM Addressing bits based on type (0-small, 1-large) */ + #define E1000_EECD_ADDR_BITS 0x00000400 +--- a/drivers/net/e1000e/e1000.h ++++ b/drivers/net/e1000e/e1000.h +@@ -104,6 +104,7 @@ enum e1000_boards { + board_80003es2lan, + board_ich8lan, + board_ich9lan, ++ board_ich10lan, + }; + + struct e1000_queue_stats { +@@ -400,6 +401,7 @@ extern struct e1000_info e1000_82573_inf + extern struct e1000_info e1000_82574_info; + extern struct e1000_info e1000_ich8_info; + extern struct e1000_info e1000_ich9_info; ++extern struct e1000_info e1000_ich10_info; + extern struct e1000_info e1000_es2_info; + + extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); +@@ -473,6 +475,7 @@ extern s32 e1000e_get_cable_length_m88(s + extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw); + extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); + extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); ++extern s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw); + extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id); + extern s32 e1000e_determine_phy_address(struct e1000_hw *hw); + extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); +--- a/drivers/net/e1000e/ethtool.c ++++ b/drivers/net/e1000e/ethtool.c +@@ -790,6 +790,7 @@ static int e1000_reg_test(struct e1000_a + case e1000_82574: + case e1000_ich8lan: + case e1000_ich9lan: ++ case e1000_ich10lan: + toggle = 0x7FFFF033; + break; + default: +@@ -842,7 +843,9 @@ static int e1000_reg_test(struct e1000_a + REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); + for (i = 0; i < mac->rar_entry_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), +- 0x8003FFFF, 0xFFFFFFFF); ++ ((mac->type == e1000_ich10lan) ? ++ 0x8007FFFF : 0x8003FFFF), ++ 0xFFFFFFFF); + + for (i = 0; i < mac->mta_reg_count; i++) + REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); +@@ -923,12 +926,23 @@ static int e1000_intr_test(struct e1000_ + + /* Test each interrupt */ + for (i = 0; i < 10; i++) { +- if ((adapter->flags & FLAG_IS_ICH) && (i == 8)) +- continue; +- + /* Interrupt to test */ + mask = 1 << i; + ++ if (adapter->flags & FLAG_IS_ICH) { ++ switch (mask) { ++ case E1000_ICR_RXSEQ: ++ continue; ++ case 0x00000100: ++ if (adapter->hw.mac.type == e1000_ich8lan || ++ adapter->hw.mac.type == e1000_ich9lan) ++ continue; ++ break; ++ default: ++ break; ++ } ++ } ++ + if (!shared_int) { + /* + * Disable the interrupt to be reported in +--- a/drivers/net/e1000e/hw.h ++++ b/drivers/net/e1000e/hw.h +@@ -362,6 +362,8 @@ enum e1e_registers { + #define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC + #define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD + #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE ++#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE ++#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF + + #define E1000_REVISION_4 4 + +@@ -375,6 +377,7 @@ enum e1000_mac_type { + e1000_80003es2lan, + e1000_ich8lan, + e1000_ich9lan, ++ e1000_ich10lan, + }; + + enum e1000_media_type { +--- a/drivers/net/e1000e/ich8lan.c ++++ b/drivers/net/e1000e/ich8lan.c +@@ -43,7 +43,8 @@ + * 82567LM-2 Gigabit Network Connection + * 82567LF-2 Gigabit Network Connection + * 82567V-2 Gigabit Network Connection +- * 82562GT-3 10/100 Network Connection ++ * 82567LF-3 Gigabit Network Connection ++ * 82567LM-3 Gigabit Network Connection + * 82567LM-4 Gigabit Network Connection + */ + +@@ -172,12 +173,15 @@ static s32 e1000_check_polarity_ife_ich8 + static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); + static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, + u32 offset, u8 byte); ++static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 *data); + static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, + u16 *data); + static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, + u8 size, u16 *data); + static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw); + static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); ++static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); + + static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) + { +@@ -945,6 +949,56 @@ static s32 e1000_set_d3_lplu_state_ich8l + } + + /** ++ * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 ++ * @hw: pointer to the HW structure ++ * @bank: pointer to the variable that returns the active bank ++ * ++ * Reads signature byte from the NVM using the flash access registers. ++ **/ ++static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) ++{ ++ struct e1000_nvm_info *nvm = &hw->nvm; ++ /* flash bank size is in words */ ++ u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); ++ u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; ++ u8 bank_high_byte = 0; ++ ++ if (hw->mac.type != e1000_ich10lan) { ++ if (er32(EECD) & E1000_EECD_SEC1VAL) ++ *bank = 1; ++ else ++ *bank = 0; ++ } else { ++ /* ++ * Make sure the signature for bank 0 is valid, ++ * if not check for bank1 ++ */ ++ e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte); ++ if ((bank_high_byte & 0xC0) == 0x80) { ++ *bank = 0; ++ } else { ++ /* ++ * find if segment 1 is valid by verifying ++ * bit 15:14 = 10b in word 0x13 ++ */ ++ e1000_read_flash_byte_ich8lan(hw, ++ act_offset + bank1_offset, ++ &bank_high_byte); ++ ++ /* bank1 has a valid signature equivalent to SEC1V */ ++ if ((bank_high_byte & 0xC0) == 0x80) { ++ *bank = 1; ++ } else { ++ hw_dbg(hw, "ERROR: EEPROM not present\n"); ++ return -E1000_ERR_NVM; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/** + * e1000_read_nvm_ich8lan - Read word(s) from the NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the word(s) to read. +@@ -960,6 +1014,7 @@ static s32 e1000_read_nvm_ich8lan(struct + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u32 act_offset; + s32 ret_val; ++ u32 bank = 0; + u16 i, word; + + if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || +@@ -972,10 +1027,11 @@ static s32 e1000_read_nvm_ich8lan(struct + if (ret_val) + return ret_val; + +- /* Start with the bank offset, then add the relative offset. */ +- act_offset = (er32(EECD) & E1000_EECD_SEC1VAL) +- ? nvm->flash_bank_size +- : 0; ++ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); ++ if (ret_val) ++ return ret_val; ++ ++ act_offset = (bank) ? nvm->flash_bank_size : 0; + act_offset += offset; + + for (i = 0; i < words; i++) { +@@ -1123,6 +1179,29 @@ static s32 e1000_read_flash_word_ich8lan + } + + /** ++ * e1000_read_flash_byte_ich8lan - Read byte from flash ++ * @hw: pointer to the HW structure ++ * @offset: The offset of the byte to read. ++ * @data: Pointer to a byte to store the value read. ++ * ++ * Reads a single byte from the NVM using the flash access registers. ++ **/ ++static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, ++ u8 *data) ++{ ++ s32 ret_val; ++ u16 word = 0; ++ ++ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); ++ if (ret_val) ++ return ret_val; ++ ++ *data = (u8)word; ++ ++ return 0; ++} ++ ++/** + * e1000_read_flash_data_ich8lan - Read byte or word from NVM + * @hw: pointer to the HW structure + * @offset: The offset (in bytes) of the byte or word to read. +@@ -1253,7 +1332,7 @@ static s32 e1000_update_nvm_checksum_ich + { + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; +- u32 i, act_offset, new_bank_offset, old_bank_offset; ++ u32 i, act_offset, new_bank_offset, old_bank_offset, bank; + s32 ret_val; + u16 data; + +@@ -1273,7 +1352,11 @@ static s32 e1000_update_nvm_checksum_ich + * write to bank 0 etc. We also need to erase the segment that + * is going to be written + */ +- if (!(er32(EECD) & E1000_EECD_SEC1VAL)) { ++ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); ++ if (ret_val) ++ return ret_val; ++ ++ if (bank == 0) { + new_bank_offset = nvm->flash_bank_size; + old_bank_offset = 0; + e1000_erase_flash_bank_ich8lan(hw, 1); +@@ -2289,13 +2372,14 @@ void e1000e_gig_downshift_workaround_ich + * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation + * to a lower speed. + * +- * Should only be called for ICH9 devices. ++ * Should only be called for ICH9 and ICH10 devices. + **/ + void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) + { + u32 phy_ctrl; + +- if (hw->mac.type == e1000_ich9lan) { ++ if ((hw->mac.type == e1000_ich10lan) || ++ (hw->mac.type == e1000_ich9lan)) { + phy_ctrl = er32(PHY_CTRL); + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | + E1000_PHY_CTRL_GBE_DISABLE; +@@ -2353,6 +2437,39 @@ static s32 e1000_led_off_ich8lan(struct + } + + /** ++ * e1000_get_cfg_done_ich8lan - Read config done bit ++ * @hw: pointer to the HW structure ++ * ++ * Read the management control register for the config done bit for ++ * completion status. NOTE: silicon which is EEPROM-less will fail trying ++ * to read the config done bit, so an error is *ONLY* logged and returns ++ * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon ++ * would not be able to be reset or change link. ++ **/ ++static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) ++{ ++ u32 bank = 0; ++ ++ e1000e_get_cfg_done(hw); ++ ++ /* If EEPROM is not marked present, init the IGP 3 PHY manually */ ++ if (hw->mac.type != e1000_ich10lan) { ++ if (((er32(EECD) & E1000_EECD_PRES) == 0) && ++ (hw->phy.type == e1000_phy_igp_3)) { ++ e1000e_phy_init_script_igp3(hw); ++ } ++ } else { ++ if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { ++ /* Maybe we should do a basic PHY config */ ++ hw_dbg(hw, "EEPROM not present\n"); ++ return -E1000_ERR_CONFIG; ++ } ++ } ++ ++ return 0; ++} ++ ++/** + * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters + * @hw: pointer to the HW structure + * +@@ -2402,7 +2519,7 @@ static struct e1000_phy_operations ich8_ + .check_reset_block = e1000_check_reset_block_ich8lan, + .commit_phy = NULL, + .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan, +- .get_cfg_done = e1000e_get_cfg_done, ++ .get_cfg_done = e1000_get_cfg_done_ich8lan, + .get_cable_length = e1000e_get_cable_length_igp_2, + .get_phy_info = e1000_get_phy_info_ich8lan, + .read_phy_reg = e1000e_read_phy_reg_igp, +@@ -2457,3 +2574,20 @@ struct e1000_info e1000_ich9_info = { + .nvm_ops = &ich8_nvm_ops, + }; + ++struct e1000_info e1000_ich10_info = { ++ .mac = e1000_ich10lan, ++ .flags = FLAG_HAS_JUMBO_FRAMES ++ | FLAG_IS_ICH ++ | FLAG_HAS_WOL ++ | FLAG_RX_CSUM_ENABLED ++ | FLAG_HAS_CTRLEXT_ON_LOAD ++ | FLAG_HAS_AMT ++ | FLAG_HAS_ERT ++ | FLAG_HAS_FLASH ++ | FLAG_APME_IN_WUC, ++ .pba = 10, ++ .get_variants = e1000_get_variants_ich8lan, ++ .mac_ops = &ich8_mac_ops, ++ .phy_ops = &ich8_phy_ops, ++ .nvm_ops = &ich8_nvm_ops, ++}; +--- a/drivers/net/e1000e/netdev.c ++++ b/drivers/net/e1000e/netdev.c +@@ -59,6 +59,7 @@ static const struct e1000_info *e1000_in + [board_80003es2lan] = &e1000_es2_info, + [board_ich8lan] = &e1000_ich8_info, + [board_ich9lan] = &e1000_ich9_info, ++ [board_ich10lan] = &e1000_ich10_info, + }; + + #ifdef DEBUG +@@ -3520,6 +3521,27 @@ static void e1000_watchdog_task(struct w + &adapter->link_duplex); + e1000_print_link_info(adapter); + /* ++ * On supported PHYs, check for duplex mismatch only ++ * if link has autonegotiated at 10/100 half ++ */ ++ if ((hw->phy.type == e1000_phy_igp_3 || ++ hw->phy.type == e1000_phy_bm) && ++ (hw->mac.autoneg == true) && ++ (adapter->link_speed == SPEED_10 || ++ adapter->link_speed == SPEED_100) && ++ (adapter->link_duplex == HALF_DUPLEX)) { ++ u16 autoneg_exp; ++ ++ e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp); ++ ++ if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS)) ++ e_info("Autonegotiated half duplex but" ++ " link partner cannot autoneg. " ++ " Try forcing full duplex if " ++ "link gets many collisions.\n"); ++ } ++ ++ /* + * tweak tx_queue_len according to speed/duplex + * and adjust the timeout factor + */ +@@ -5111,6 +5133,9 @@ static struct pci_device_id e1000_pci_tb + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan }, + ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan }, ++ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan }, ++ + { } /* terminate list */ + }; + MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); +--- a/drivers/net/e1000e/phy.c ++++ b/drivers/net/e1000e/phy.c +@@ -1734,6 +1734,91 @@ s32 e1000e_get_cfg_done(struct e1000_hw + return 0; + } + ++/** ++ * e1000e_phy_init_script_igp3 - Inits the IGP3 PHY ++ * @hw: pointer to the HW structure ++ * ++ * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. ++ **/ ++s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw) ++{ ++ hw_dbg(hw, "Running IGP 3 PHY init script\n"); ++ ++ /* PHY init IGP 3 */ ++ /* Enable rise/fall, 10-mode work in class-A */ ++ e1e_wphy(hw, 0x2F5B, 0x9018); ++ /* Remove all caps from Replica path filter */ ++ e1e_wphy(hw, 0x2F52, 0x0000); ++ /* Bias trimming for ADC, AFE and Driver (Default) */ ++ e1e_wphy(hw, 0x2FB1, 0x8B24); ++ /* Increase Hybrid poly bias */ ++ e1e_wphy(hw, 0x2FB2, 0xF8F0); ++ /* Add 4% to Tx amplitude in Gig mode */ ++ e1e_wphy(hw, 0x2010, 0x10B0); ++ /* Disable trimming (TTT) */ ++ e1e_wphy(hw, 0x2011, 0x0000); ++ /* Poly DC correction to 94.6% + 2% for all channels */ ++ e1e_wphy(hw, 0x20DD, 0x249A); ++ /* ABS DC correction to 95.9% */ ++ e1e_wphy(hw, 0x20DE, 0x00D3); ++ /* BG temp curve trim */ ++ e1e_wphy(hw, 0x28B4, 0x04CE); ++ /* Increasing ADC OPAMP stage 1 currents to max */ ++ e1e_wphy(hw, 0x2F70, 0x29E4); ++ /* Force 1000 ( required for enabling PHY regs configuration) */ ++ e1e_wphy(hw, 0x0000, 0x0140); ++ /* Set upd_freq to 6 */ ++ e1e_wphy(hw, 0x1F30, 0x1606); ++ /* Disable NPDFE */ ++ e1e_wphy(hw, 0x1F31, 0xB814); ++ /* Disable adaptive fixed FFE (Default) */ ++ e1e_wphy(hw, 0x1F35, 0x002A); ++ /* Enable FFE hysteresis */ ++ e1e_wphy(hw, 0x1F3E, 0x0067); ++ /* Fixed FFE for short cable lengths */ ++ e1e_wphy(hw, 0x1F54, 0x0065); ++ /* Fixed FFE for medium cable lengths */ ++ e1e_wphy(hw, 0x1F55, 0x002A); ++ /* Fixed FFE for long cable lengths */ ++ e1e_wphy(hw, 0x1F56, 0x002A); ++ /* Enable Adaptive Clip Threshold */ ++ e1e_wphy(hw, 0x1F72, 0x3FB0); ++ /* AHT reset limit to 1 */ ++ e1e_wphy(hw, 0x1F76, 0xC0FF); ++ /* Set AHT master delay to 127 msec */ ++ e1e_wphy(hw, 0x1F77, 0x1DEC); ++ /* Set scan bits for AHT */ ++ e1e_wphy(hw, 0x1F78, 0xF9EF); ++ /* Set AHT Preset bits */ ++ e1e_wphy(hw, 0x1F79, 0x0210); ++ /* Change integ_factor of channel A to 3 */ ++ e1e_wphy(hw, 0x1895, 0x0003); ++ /* Change prop_factor of channels BCD to 8 */ ++ e1e_wphy(hw, 0x1796, 0x0008); ++ /* Change cg_icount + enable integbp for channels BCD */ ++ e1e_wphy(hw, 0x1798, 0xD008); ++ /* ++ * Change cg_icount + enable integbp + change prop_factor_master ++ * to 8 for channel A ++ */ ++ e1e_wphy(hw, 0x1898, 0xD918); ++ /* Disable AHT in Slave mode on channel A */ ++ e1e_wphy(hw, 0x187A, 0x0800); ++ /* ++ * Enable LPLU and disable AN to 1000 in non-D0a states, ++ * Enable SPD+B2B ++ */ ++ e1e_wphy(hw, 0x0019, 0x008D); ++ /* Enable restart AN on an1000_dis change */ ++ e1e_wphy(hw, 0x001B, 0x2080); ++ /* Enable wh_fifo read clock in 10/100 modes */ ++ e1e_wphy(hw, 0x0014, 0x0045); ++ /* Restart AN, Speed selection is 1000 */ ++ e1e_wphy(hw, 0x0000, 0x1340); ++ ++ return 0; ++} ++ + /* Internal function pointers */ + + /** diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ehca-fix-possible-nullpointer-access-v2.patch b/src/patches/suse-2.6.27.31/patches.drivers/ehca-fix-possible-nullpointer-access-v2.patch new file mode 100644 index 000000000..4aaca56ce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ehca-fix-possible-nullpointer-access-v2.patch @@ -0,0 +1,97 @@ +From: Stefan Roscher +Subject: ehca: fix a possible nullpointer access +References: bnc#441966 + +If the initialization of a special QP (e.g. AQP1) fails due to a + software timeout, we have to remove the reference to that special + QP struct from the port struct preventing the driver to access the + QP, since it will be/has been destroyed by the caller, ie in this + case ib_mad. + +Acked-by: John Jolly + +Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_irq.c +=================================================================== +--- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_irq.c ++++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_irq.c +@@ -359,36 +359,48 @@ static void notify_port_conf_change(stru + *old_attr = new_attr; + } + ++/* replay modify_qp for sqps -- return 0 if all is well, 1 if AQP1 destroyed */ ++static int replay_modify_qp(struct ehca_sport *sport) ++{ ++ int aqp1_destroyed; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sport->mod_sqp_lock, flags); ++ ++ aqp1_destroyed = !sport->ibqp_sqp[IB_QPT_GSI]; ++ ++ if (sport->ibqp_sqp[IB_QPT_SMI]) ++ ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]); ++ if (!aqp1_destroyed) ++ ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]); ++ ++ spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); ++ ++ return aqp1_destroyed; ++} ++ + static void parse_ec(struct ehca_shca *shca, u64 eqe) + { + u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); + u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); + u8 spec_event; + struct ehca_sport *sport = &shca->sport[port - 1]; +- unsigned long flags; + + switch (ec) { + case 0x30: /* port availability change */ + if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { +- int suppress_event; +- /* replay modify_qp for sqps */ +- spin_lock_irqsave(&sport->mod_sqp_lock, flags); +- suppress_event = !sport->ibqp_sqp[IB_QPT_GSI]; +- if (sport->ibqp_sqp[IB_QPT_SMI]) +- ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]); +- if (!suppress_event) +- ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]); +- spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); +- +- /* AQP1 was destroyed, ignore this event */ +- if (suppress_event) +- break; ++ /* only replay modify_qp calls in autodetect mode; ++ * if AQP1 was destroyed, the port is already down ++ * again and we can drop the event. ++ */ ++ if (ehca_nr_ports < 0) ++ if (replay_modify_qp(sport)) ++ break; + + sport->port_state = IB_PORT_ACTIVE; + dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, + "is active"); +- ehca_query_sma_attr(shca, port, +- &sport->saved_attr); ++ ehca_query_sma_attr(shca, port, &sport->saved_attr); + } else { + sport->port_state = IB_PORT_DOWN; + dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, +Index: linux-2.6.27/drivers/infiniband/hw/ehca/ehca_qp.c +=================================================================== +--- linux-2.6.27.orig/drivers/infiniband/hw/ehca/ehca_qp.c ++++ linux-2.6.27/drivers/infiniband/hw/ehca/ehca_qp.c +@@ -854,6 +854,11 @@ static struct ehca_qp *internal_create_q + if (qp_type == IB_QPT_GSI) { + h_ret = ehca_define_sqp(shca, my_qp, init_attr); + if (h_ret != H_SUCCESS) { ++ kfree(my_qp->mod_qp_parm); ++ my_qp->mod_qp_parm = NULL; ++ /* the QP pointer is no longer valid */ ++ shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] = ++ NULL; + ret = ehca2ib_return_code(h_ret); + goto create_qp_exit6; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ehca-flush-cqe.patch b/src/patches/suse-2.6.27.31/patches.drivers/ehca-flush-cqe.patch new file mode 100644 index 000000000..24ffd212e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ehca-flush-cqe.patch @@ -0,0 +1,757 @@ +From: Alexander Schmidt +Subject: Adds software flush CQE generation to the ehca driver. +References: bnc#430344 + +When a QP goes into error state, it is required that flush CQEs are +delivered to the application for any outstanding work requests. eHCA does not +do this in hardware, so this patch adds software flush CQE generation to the +ehca driver. + +Whenever a QP gets into error state, it is added to the QP error list of its +respective CQ. If the error QP list of a CQ is not empty, poll_cq() +generates flush CQEs before polling the actual CQ. + +Signed-off-by: Alexander Schmidt +Acked-by: John Jolly +--- +Applies on top of 2.6.27-rc3, please consider this for 2.6.28. + + drivers/infiniband/hw/ehca/ehca_classes.h | 14 + + drivers/infiniband/hw/ehca/ehca_cq.c | 3 + drivers/infiniband/hw/ehca/ehca_iverbs.h | 2 + drivers/infiniband/hw/ehca/ehca_qp.c | 225 ++++++++++++++++++++++++++++-- + drivers/infiniband/hw/ehca/ehca_reqs.c | 211 ++++++++++++++++++++++++---- + 5 files changed, 412 insertions(+), 43 deletions(-) + +--- infiniband.git.orig/drivers/infiniband/hw/ehca/ehca_classes.h ++++ infiniband.git/drivers/infiniband/hw/ehca/ehca_classes.h +@@ -164,6 +164,13 @@ struct ehca_qmap_entry { + u16 reported; + }; + ++struct ehca_queue_map { ++ struct ehca_qmap_entry *map; ++ unsigned int entries; ++ unsigned int tail; ++ unsigned int left_to_poll; ++}; ++ + struct ehca_qp { + union { + struct ib_qp ib_qp; +@@ -173,8 +180,9 @@ struct ehca_qp { + enum ehca_ext_qp_type ext_type; + enum ib_qp_state state; + struct ipz_queue ipz_squeue; +- struct ehca_qmap_entry *sq_map; ++ struct ehca_queue_map sq_map; + struct ipz_queue ipz_rqueue; ++ struct ehca_queue_map rq_map; + struct h_galpas galpas; + u32 qkey; + u32 real_qp_num; +@@ -204,6 +212,8 @@ struct ehca_qp { + atomic_t nr_events; /* events seen */ + wait_queue_head_t wait_completion; + int mig_armed; ++ struct list_head sq_err_node; ++ struct list_head rq_err_node; + }; + + #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ) +@@ -233,6 +243,8 @@ struct ehca_cq { + /* mmap counter for resources mapped into user space */ + u32 mm_count_queue; + u32 mm_count_galpa; ++ struct list_head sqp_err_list; ++ struct list_head rqp_err_list; + }; + + enum ehca_mr_flag { +--- infiniband.git.orig/drivers/infiniband/hw/ehca/ehca_reqs.c ++++ infiniband.git/drivers/infiniband/hw/ehca/ehca_reqs.c +@@ -53,9 +53,25 @@ + /* in RC traffic, insert an empty RDMA READ every this many packets */ + #define ACK_CIRC_THRESHOLD 2000000 + ++static u64 replace_wr_id(u64 wr_id, u16 idx) ++{ ++ u64 ret; ++ ++ ret = wr_id & ~QMAP_IDX_MASK; ++ ret |= idx & QMAP_IDX_MASK; ++ ++ return ret; ++} ++ ++static u16 get_app_wr_id(u64 wr_id) ++{ ++ return wr_id & QMAP_IDX_MASK; ++} ++ + static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, + struct ehca_wqe *wqe_p, +- struct ib_recv_wr *recv_wr) ++ struct ib_recv_wr *recv_wr, ++ u32 rq_map_idx) + { + u8 cnt_ds; + if (unlikely((recv_wr->num_sge < 0) || +@@ -69,7 +85,7 @@ static inline int ehca_write_rwqe(struct + /* clear wqe header until sglist */ + memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); + +- wqe_p->work_request_id = recv_wr->wr_id; ++ wqe_p->work_request_id = replace_wr_id(recv_wr->wr_id, rq_map_idx); + wqe_p->nr_of_data_seg = recv_wr->num_sge; + + for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) { +@@ -146,6 +162,7 @@ static inline int ehca_write_swqe(struct + u64 dma_length; + struct ehca_av *my_av; + u32 remote_qkey = send_wr->wr.ud.remote_qkey; ++ struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx]; + + if (unlikely((send_wr->num_sge < 0) || + (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) { +@@ -158,11 +175,10 @@ static inline int ehca_write_swqe(struct + /* clear wqe header until sglist */ + memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list)); + +- wqe_p->work_request_id = send_wr->wr_id & ~QMAP_IDX_MASK; +- wqe_p->work_request_id |= sq_map_idx & QMAP_IDX_MASK; ++ wqe_p->work_request_id = replace_wr_id(send_wr->wr_id, sq_map_idx); + +- qp->sq_map[sq_map_idx].app_wr_id = send_wr->wr_id & QMAP_IDX_MASK; +- qp->sq_map[sq_map_idx].reported = 0; ++ qmap_entry->app_wr_id = get_app_wr_id(send_wr->wr_id); ++ qmap_entry->reported = 0; + + switch (send_wr->opcode) { + case IB_WR_SEND: +@@ -496,7 +512,9 @@ static int internal_post_recv(struct ehc + struct ehca_wqe *wqe_p; + int wqe_cnt = 0; + int ret = 0; ++ u32 rq_map_idx; + unsigned long flags; ++ struct ehca_qmap_entry *qmap_entry; + + if (unlikely(!HAS_RQ(my_qp))) { + ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d", +@@ -524,8 +542,15 @@ static int internal_post_recv(struct ehc + } + goto post_recv_exit0; + } ++ /* ++ * Get the index of the WQE in the recv queue. The same index ++ * is used for writing into the rq_map. ++ */ ++ rq_map_idx = start_offset / my_qp->ipz_rqueue.qe_size; ++ + /* write a RECV WQE into the QUEUE */ +- ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr); ++ ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr, ++ rq_map_idx); + /* + * if something failed, + * reset the free entry pointer to the start value +@@ -540,6 +565,11 @@ static int internal_post_recv(struct ehc + } + goto post_recv_exit0; + } ++ ++ qmap_entry = &my_qp->rq_map.map[rq_map_idx]; ++ qmap_entry->app_wr_id = get_app_wr_id(cur_recv_wr->wr_id); ++ qmap_entry->reported = 0; ++ + wqe_cnt++; + } /* eof for cur_recv_wr */ + +@@ -596,10 +626,12 @@ static const u8 ib_wc_opcode[255] = { + /* internal function to poll one entry of cq */ + static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc) + { +- int ret = 0; ++ int ret = 0, qmap_tail_idx; + struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); + struct ehca_cqe *cqe; + struct ehca_qp *my_qp; ++ struct ehca_qmap_entry *qmap_entry; ++ struct ehca_queue_map *qmap; + int cqe_count = 0, is_error; + + repoll: +@@ -674,27 +706,52 @@ repoll: + goto repoll; + wc->qp = &my_qp->ib_qp; + +- if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) { +- struct ehca_qmap_entry *qmap_entry; ++ if (is_error) { + /* +- * We got a send completion and need to restore the original +- * wr_id. ++ * set left_to_poll to 0 because in error state, we will not ++ * get any additional CQEs + */ +- qmap_entry = &my_qp->sq_map[cqe->work_request_id & +- QMAP_IDX_MASK]; ++ ehca_add_to_err_list(my_qp, 1); ++ my_qp->sq_map.left_to_poll = 0; + +- if (qmap_entry->reported) { +- ehca_warn(cq->device, "Double cqe on qp_num=%#x", +- my_qp->real_qp_num); +- /* found a double cqe, discard it and read next one */ +- goto repoll; +- } +- wc->wr_id = cqe->work_request_id & ~QMAP_IDX_MASK; +- wc->wr_id |= qmap_entry->app_wr_id; +- qmap_entry->reported = 1; +- } else ++ if (HAS_RQ(my_qp)) ++ ehca_add_to_err_list(my_qp, 0); ++ my_qp->rq_map.left_to_poll = 0; ++ } ++ ++ qmap_tail_idx = get_app_wr_id(cqe->work_request_id); ++ if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT)) ++ /* We got a send completion. */ ++ qmap = &my_qp->sq_map; ++ else + /* We got a receive completion. */ +- wc->wr_id = cqe->work_request_id; ++ qmap = &my_qp->rq_map; ++ ++ qmap_entry = &qmap->map[qmap_tail_idx]; ++ if (qmap_entry->reported) { ++ ehca_warn(cq->device, "Double cqe on qp_num=%#x", ++ my_qp->real_qp_num); ++ /* found a double cqe, discard it and read next one */ ++ goto repoll; ++ } ++ ++ wc->wr_id = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id); ++ qmap_entry->reported = 1; ++ ++ /* this is a proper completion, we need to advance the tail pointer */ ++ if (++qmap->tail == qmap->entries) ++ qmap->tail = 0; ++ ++ /* if left_to_poll is decremented to 0, add the QP to the error list */ ++ if (qmap->left_to_poll > 0) { ++ qmap->left_to_poll--; ++ if ((my_qp->sq_map.left_to_poll == 0) && ++ (my_qp->rq_map.left_to_poll == 0)) { ++ ehca_add_to_err_list(my_qp, 1); ++ if (HAS_RQ(my_qp)) ++ ehca_add_to_err_list(my_qp, 0); ++ } ++ } + + /* eval ib_wc_opcode */ + wc->opcode = ib_wc_opcode[cqe->optype]-1; +@@ -733,13 +790,88 @@ poll_cq_one_exit0: + return ret; + } + ++static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq, ++ struct ib_wc *wc, int num_entries, ++ struct ipz_queue *ipz_queue, int on_sq) ++{ ++ int nr = 0; ++ struct ehca_wqe *wqe; ++ u64 offset; ++ struct ehca_queue_map *qmap; ++ struct ehca_qmap_entry *qmap_entry; ++ ++ if (on_sq) ++ qmap = &my_qp->sq_map; ++ else ++ qmap = &my_qp->rq_map; ++ ++ qmap_entry = &qmap->map[qmap->tail]; ++ ++ while ((nr < num_entries) && (qmap_entry->reported == 0)) { ++ /* generate flush CQE */ ++ memset(wc, 0, sizeof(*wc)); ++ ++ offset = qmap->tail * ipz_queue->qe_size; ++ wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset); ++ if (!wqe) { ++ ehca_err(cq->device, "Invalid wqe offset=%#lx on " ++ "qp_num=%#x", offset, my_qp->real_qp_num); ++ return nr; ++ } ++ ++ wc->wr_id = replace_wr_id(wqe->work_request_id, ++ qmap_entry->app_wr_id); ++ ++ if (on_sq) { ++ switch (wqe->optype) { ++ case WQE_OPTYPE_SEND: ++ wc->opcode = IB_WC_SEND; ++ break; ++ case WQE_OPTYPE_RDMAWRITE: ++ wc->opcode = IB_WC_RDMA_WRITE; ++ break; ++ case WQE_OPTYPE_RDMAREAD: ++ wc->opcode = IB_WC_RDMA_READ; ++ break; ++ default: ++ ehca_err(cq->device, "Invalid optype=%x", ++ wqe->optype); ++ return nr; ++ } ++ } else ++ wc->opcode = IB_WC_RECV; ++ ++ if (wqe->wr_flag & WQE_WRFLAG_IMM_DATA_PRESENT) { ++ wc->ex.imm_data = wqe->immediate_data; ++ wc->wc_flags |= IB_WC_WITH_IMM; ++ } ++ ++ wc->status = IB_WC_WR_FLUSH_ERR; ++ ++ wc->qp = &my_qp->ib_qp; ++ ++ /* mark as reported and advance tail pointer */ ++ qmap_entry->reported = 1; ++ if (++qmap->tail == qmap->entries) ++ qmap->tail = 0; ++ qmap_entry = &qmap->map[qmap->tail]; ++ ++ wc++; nr++; ++ } ++ ++ return nr; ++ ++} ++ + int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc) + { + struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); + int nr; ++ struct ehca_qp *err_qp; + struct ib_wc *current_wc = wc; + int ret = 0; + unsigned long flags; ++ int entries_left = num_entries; + + if (num_entries < 1) { + ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p " +@@ -749,15 +881,40 @@ int ehca_poll_cq(struct ib_cq *cq, int n + } + + spin_lock_irqsave(&my_cq->spinlock, flags); +- for (nr = 0; nr < num_entries; nr++) { ++ ++ /* generate flush cqes for send queues */ ++ list_for_each_entry(err_qp, &my_cq->sqp_err_list, sq_err_node) { ++ nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left, ++ &err_qp->ipz_squeue, 1); ++ entries_left -= nr; ++ current_wc += nr; ++ ++ if (entries_left == 0) ++ break; ++ } ++ ++ /* generate flush cqes for receive queues */ ++ list_for_each_entry(err_qp, &my_cq->rqp_err_list, rq_err_node) { ++ nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left, ++ &err_qp->ipz_rqueue, 0); ++ entries_left -= nr; ++ current_wc += nr; ++ ++ if (entries_left == 0) ++ break; ++ } ++ ++ for (nr = 0; nr < entries_left; nr++) { + ret = ehca_poll_cq_one(cq, current_wc); + if (ret) + break; + current_wc++; + } /* eof for nr */ ++ entries_left -= nr; ++ + spin_unlock_irqrestore(&my_cq->spinlock, flags); + if (ret == -EAGAIN || !ret) +- ret = nr; ++ ret = num_entries - entries_left; + + poll_cq_exit0: + return ret; +--- infiniband.git.orig/drivers/infiniband/hw/ehca/ehca_cq.c ++++ infiniband.git/drivers/infiniband/hw/ehca/ehca_cq.c +@@ -276,6 +276,9 @@ struct ib_cq *ehca_create_cq(struct ib_d + for (i = 0; i < QP_HASHTAB_LEN; i++) + INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]); + ++ INIT_LIST_HEAD(&my_cq->sqp_err_list); ++ INIT_LIST_HEAD(&my_cq->rqp_err_list); ++ + if (context) { + struct ipz_queue *ipz_queue = &my_cq->ipz_queue; + struct ehca_create_cq_resp resp; +--- infiniband.git.orig/drivers/infiniband/hw/ehca/ehca_qp.c ++++ infiniband.git/drivers/infiniband/hw/ehca/ehca_qp.c +@@ -396,6 +396,50 @@ static void ehca_determine_small_queue(s + queue->is_small = (queue->page_size != 0); + } + ++/* needs to be called with cq->spinlock held */ ++void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq) ++{ ++ struct list_head *list, *node; ++ ++ /* TODO: support low latency QPs */ ++ if (qp->ext_type == EQPT_LLQP) ++ return; ++ ++ if (on_sq) { ++ list = &qp->send_cq->sqp_err_list; ++ node = &qp->sq_err_node; ++ } else { ++ list = &qp->recv_cq->rqp_err_list; ++ node = &qp->rq_err_node; ++ } ++ ++ if (list_empty(node)) ++ list_add_tail(node, list); ++ ++ return; ++} ++ ++static void del_from_err_list(struct ehca_cq *cq, struct list_head *node) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&cq->spinlock, flags); ++ ++ if (!list_empty(node)) ++ list_del_init(node); ++ ++ spin_unlock_irqrestore(&cq->spinlock, flags); ++} ++ ++static void reset_queue_map(struct ehca_queue_map *qmap) ++{ ++ int i; ++ ++ qmap->tail = 0; ++ for (i = 0; i < qmap->entries; i++) ++ qmap->map[i].reported = 1; ++} ++ + /* + * Create an ib_qp struct that is either a QP or an SRQ, depending on + * the value of the is_srq parameter. If init_attr and srq_init_attr share +@@ -407,12 +451,11 @@ static struct ehca_qp *internal_create_q + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata, int is_srq) + { +- struct ehca_qp *my_qp; ++ struct ehca_qp *my_qp, *my_srq = NULL; + struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd); + struct ehca_shca *shca = container_of(pd->device, struct ehca_shca, + ib_device); + struct ib_ucontext *context = NULL; +- u32 nr_qes; + u64 h_ret; + int is_llqp = 0, has_srq = 0; + int qp_type, max_send_sge, max_recv_sge, ret; +@@ -457,8 +500,7 @@ static struct ehca_qp *internal_create_q + + /* handle SRQ base QPs */ + if (init_attr->srq) { +- struct ehca_qp *my_srq = +- container_of(init_attr->srq, struct ehca_qp, ib_srq); ++ my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq); + + has_srq = 1; + parms.ext_type = EQPT_SRQBASE; +@@ -716,15 +758,19 @@ static struct ehca_qp *internal_create_q + "and pages ret=%i", ret); + goto create_qp_exit2; + } +- nr_qes = my_qp->ipz_squeue.queue_length / ++ ++ my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length / + my_qp->ipz_squeue.qe_size; +- my_qp->sq_map = vmalloc(nr_qes * ++ my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries * + sizeof(struct ehca_qmap_entry)); +- if (!my_qp->sq_map) { ++ if (!my_qp->sq_map.map) { + ehca_err(pd->device, "Couldn't allocate squeue " + "map ret=%i", ret); + goto create_qp_exit3; + } ++ INIT_LIST_HEAD(&my_qp->sq_err_node); ++ /* to avoid the generation of bogus flush CQEs */ ++ reset_queue_map(&my_qp->sq_map); + } + + if (HAS_RQ(my_qp)) { +@@ -736,6 +782,25 @@ static struct ehca_qp *internal_create_q + "and pages ret=%i", ret); + goto create_qp_exit4; + } ++ ++ my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length / ++ my_qp->ipz_rqueue.qe_size; ++ my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries * ++ sizeof(struct ehca_qmap_entry)); ++ if (!my_qp->rq_map.map) { ++ ehca_err(pd->device, "Couldn't allocate squeue " ++ "map ret=%i", ret); ++ goto create_qp_exit5; ++ } ++ INIT_LIST_HEAD(&my_qp->rq_err_node); ++ /* to avoid the generation of bogus flush CQEs */ ++ reset_queue_map(&my_qp->rq_map); ++ } else if (init_attr->srq) { ++ /* this is a base QP, use the queue map of the SRQ */ ++ my_qp->rq_map = my_srq->rq_map; ++ INIT_LIST_HEAD(&my_qp->rq_err_node); ++ ++ my_qp->ipz_rqueue = my_srq->ipz_rqueue; + } + + if (is_srq) { +@@ -799,7 +864,7 @@ static struct ehca_qp *internal_create_q + if (ret) { + ehca_err(pd->device, + "Couldn't assign qp to send_cq ret=%i", ret); +- goto create_qp_exit6; ++ goto create_qp_exit7; + } + } + +@@ -825,25 +890,29 @@ static struct ehca_qp *internal_create_q + if (ib_copy_to_udata(udata, &resp, sizeof resp)) { + ehca_err(pd->device, "Copy to udata failed"); + ret = -EINVAL; +- goto create_qp_exit7; ++ goto create_qp_exit8; + } + } + + return my_qp; + +-create_qp_exit7: ++create_qp_exit8: + ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); + +-create_qp_exit6: ++create_qp_exit7: + kfree(my_qp->mod_qp_parm); + ++create_qp_exit6: ++ if (HAS_RQ(my_qp)) ++ vfree(my_qp->rq_map.map); ++ + create_qp_exit5: + if (HAS_RQ(my_qp)) + ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); + + create_qp_exit4: + if (HAS_SQ(my_qp)) +- vfree(my_qp->sq_map); ++ vfree(my_qp->sq_map.map); + + create_qp_exit3: + if (HAS_SQ(my_qp)) +@@ -1035,6 +1104,101 @@ static int prepare_sqe_rts(struct ehca_q + return 0; + } + ++static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue, ++ struct ehca_queue_map *qmap) ++{ ++ void *wqe_v; ++ u64 q_ofs; ++ u32 wqe_idx; ++ ++ /* convert real to abs address */ ++ wqe_p = wqe_p & (~(1UL << 63)); ++ ++ wqe_v = abs_to_virt(wqe_p); ++ ++ if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) { ++ ehca_gen_err("Invalid offset for calculating left cqes " ++ "wqe_p=%#lx wqe_v=%p\n", wqe_p, wqe_v); ++ return -EFAULT; ++ } ++ ++ wqe_idx = q_ofs / ipz_queue->qe_size; ++ if (wqe_idx < qmap->tail) ++ qmap->left_to_poll = (qmap->entries - qmap->tail) + wqe_idx; ++ else ++ qmap->left_to_poll = wqe_idx - qmap->tail; ++ ++ return 0; ++} ++ ++static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca) ++{ ++ u64 h_ret; ++ void *send_wqe_p, *recv_wqe_p; ++ int ret; ++ unsigned long flags; ++ int qp_num = my_qp->ib_qp.qp_num; ++ ++ /* this hcall is not supported on base QPs */ ++ if (my_qp->ext_type != EQPT_SRQBASE) { ++ /* get send and receive wqe pointer */ ++ h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle, ++ my_qp->ipz_qp_handle, &my_qp->pf, ++ &send_wqe_p, &recv_wqe_p, 4); ++ if (h_ret != H_SUCCESS) { ++ ehca_err(&shca->ib_device, "disable_and_get_wqe() " ++ "failed ehca_qp=%p qp_num=%x h_ret=%li", ++ my_qp, qp_num, h_ret); ++ return ehca2ib_return_code(h_ret); ++ } ++ ++ /* ++ * acquire lock to ensure that nobody is polling the cq which ++ * could mean that the qmap->tail pointer is in an ++ * inconsistent state. ++ */ ++ spin_lock_irqsave(&my_qp->send_cq->spinlock, flags); ++ ret = calc_left_cqes((u64)send_wqe_p, &my_qp->ipz_squeue, ++ &my_qp->sq_map); ++ spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags); ++ if (ret) ++ return ret; ++ ++ ++ spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags); ++ ret = calc_left_cqes((u64)recv_wqe_p, &my_qp->ipz_rqueue, ++ &my_qp->rq_map); ++ spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags); ++ if (ret) ++ return ret; ++ } else { ++ spin_lock_irqsave(&my_qp->send_cq->spinlock, flags); ++ my_qp->sq_map.left_to_poll = 0; ++ spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags); ++ ++ spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags); ++ my_qp->rq_map.left_to_poll = 0; ++ spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags); ++ } ++ ++ /* this assures flush cqes being generated only for pending wqes */ ++ if ((my_qp->sq_map.left_to_poll == 0) && ++ (my_qp->rq_map.left_to_poll == 0)) { ++ spin_lock_irqsave(&my_qp->send_cq->spinlock, flags); ++ ehca_add_to_err_list(my_qp, 1); ++ spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags); ++ ++ if (HAS_RQ(my_qp)) { ++ spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags); ++ ehca_add_to_err_list(my_qp, 0); ++ spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, ++ flags); ++ } ++ } ++ ++ return 0; ++} ++ + /* + * internal_modify_qp with circumvention to handle aqp0 properly + * smi_reset2init indicates if this is an internal reset-to-init-call for +@@ -1539,10 +1703,27 @@ static int internal_modify_qp(struct ib_ + goto modify_qp_exit2; + } + } ++ if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) { ++ ret = check_for_left_cqes(my_qp, shca); ++ if (ret) ++ goto modify_qp_exit2; ++ } + + if (statetrans == IB_QPST_ANY2RESET) { + ipz_qeit_reset(&my_qp->ipz_rqueue); + ipz_qeit_reset(&my_qp->ipz_squeue); ++ ++ if (qp_cur_state == IB_QPS_ERR) { ++ del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node); ++ ++ if (HAS_RQ(my_qp)) ++ del_from_err_list(my_qp->recv_cq, ++ &my_qp->rq_err_node); ++ } ++ reset_queue_map(&my_qp->sq_map); ++ ++ if (HAS_RQ(my_qp)) ++ reset_queue_map(&my_qp->rq_map); + } + + if (attr_mask & IB_QP_QKEY) +@@ -1958,6 +2139,16 @@ static int internal_destroy_qp(struct ib + idr_remove(&ehca_qp_idr, my_qp->token); + write_unlock_irqrestore(&ehca_qp_idr_lock, flags); + ++ /* ++ * SRQs will never get into an error list and do not have a recv_cq, ++ * so we need to skip them here. ++ */ ++ if (HAS_RQ(my_qp) && !IS_SRQ(my_qp)) ++ del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node); ++ ++ if (HAS_SQ(my_qp)) ++ del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node); ++ + /* now wait until all pending events have completed */ + wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events)); + +@@ -1983,7 +2174,7 @@ static int internal_destroy_qp(struct ib + if (qp_type == IB_QPT_GSI) { + struct ib_event event; + ehca_info(dev, "device %s: port %x is inactive.", +- shca->ib_device.name, port_num); ++ shca->ib_device.name, port_num); + event.device = &shca->ib_device; + event.event = IB_EVENT_PORT_ERR; + event.element.port_num = port_num; +@@ -1991,11 +2182,15 @@ static int internal_destroy_qp(struct ib + ib_dispatch_event(&event); + } + +- if (HAS_RQ(my_qp)) ++ if (HAS_RQ(my_qp)) { + ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); ++ ++ vfree(my_qp->rq_map.map); ++ } + if (HAS_SQ(my_qp)) { + ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); +- vfree(my_qp->sq_map); ++ ++ vfree(my_qp->sq_map.map); + } + kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); +--- infiniband.git.orig/drivers/infiniband/hw/ehca/ehca_iverbs.h ++++ infiniband.git/drivers/infiniband/hw/ehca/ehca_iverbs.h +@@ -197,6 +197,8 @@ void ehca_poll_eqs(unsigned long data); + int ehca_calc_ipd(struct ehca_shca *shca, int port, + enum ib_rate path_rate, u32 *ipd); + ++void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq); ++ + #ifdef CONFIG_PPC_64K_PAGES + void *ehca_alloc_fw_ctrlblock(gfp_t flags); + void ehca_free_fw_ctrlblock(void *ptr); +-- +To unsubscribe from this list: send the line "unsubscribe linux-kernel" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html +Please read the FAQ at http://www.tux.org/lkml/ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ehca-malloc-speedup b/src/patches/suse-2.6.27.31/patches.drivers/ehca-malloc-speedup new file mode 100644 index 000000000..827ee488a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ehca-malloc-speedup @@ -0,0 +1,365 @@ +From: Stefan Roscher +Subject: Re: [PATCH 1/3] IB/ehca: Replace vmalloc with kmalloc +Date Wed, 22 Apr 2009 16:02:28 +0200 +References: bnc#491430 +Patch-mainline: 2.6.31 + +In case of large queue pairs there is the possibillity of allocation failures +due to memory fragmentation with kmalloc(). To ensure the memory is allocated +even if kmalloc() can not find chunks which are big enough, we try to allocate +the memory with vmalloc(). + +Because kmalloc() is faster than vmalloc() causing a huge performance win +when someone allocates a large number of queue pairs. We fall back to +vmalloc() only if kmalloc() can't deliver the memory chunk. + +Signed-off-by: Stefan Roscher +Acked-by: + +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/ipz_pt_fn.c ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/ipz_pt_fn.c +@@ -220,10 +220,13 @@ int ipz_queue_ctor(struct ehca_pd *pd, s + queue->small_page = NULL; + + /* allocate queue page pointers */ +- queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); ++ queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL); + if (!queue->queue_pages) { +- ehca_gen_err("Couldn't allocate queue page list"); +- return 0; ++ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); ++ if (!queue->queue_pages) { ++ ehca_gen_err("Couldn't allocate queue page list"); ++ return 0; ++ } + } + memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); + +@@ -240,7 +243,10 @@ int ipz_queue_ctor(struct ehca_pd *pd, s + ipz_queue_ctor_exit0: + ehca_gen_err("Couldn't alloc pages queue=%p " + "nr_of_pages=%x", queue, nr_of_pages); +- vfree(queue->queue_pages); ++ if (is_vmalloc_addr(queue->queue_pages)) ++ vfree(queue->queue_pages); ++ else ++ kfree(queue->queue_pages); + + return 0; + } +@@ -262,7 +268,10 @@ int ipz_queue_dtor(struct ehca_pd *pd, s + free_page((unsigned long)queue->queue_pages[i]); + } + +- vfree(queue->queue_pages); ++ if (is_vmalloc_addr(queue->queue_pages)) ++ vfree(queue->queue_pages); ++ else ++ kfree(queue->queue_pages); + + return 1; + } +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/ehca_qp.c ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/ehca_qp.c +@@ -457,7 +457,7 @@ static struct ehca_qp *internal_create_q + ib_device); + struct ib_ucontext *context = NULL; + u64 h_ret; +- int is_llqp = 0, has_srq = 0; ++ int is_llqp = 0, has_srq = 0, is_user = 0; + int qp_type, max_send_sge, max_recv_sge, ret; + + /* h_call's out parameters */ +@@ -599,9 +599,6 @@ static struct ehca_qp *internal_create_q + } + } + +- if (pd->uobject && udata) +- context = pd->uobject->context; +- + my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL); + if (!my_qp) { + ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); +@@ -609,6 +606,11 @@ static struct ehca_qp *internal_create_q + return ERR_PTR(-ENOMEM); + } + ++ if (pd->uobject && udata) { ++ is_user = 1; ++ context = pd->uobject->context; ++ } ++ + atomic_set(&my_qp->nr_events, 0); + init_waitqueue_head(&my_qp->wait_completion); + spin_lock_init(&my_qp->spinlock_s); +@@ -697,7 +699,7 @@ static struct ehca_qp *internal_create_q + (parms.squeue.is_small || parms.rqueue.is_small); + } + +- h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms); ++ h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms, is_user); + if (h_ret != H_SUCCESS) { + ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li", + h_ret); +@@ -759,18 +761,20 @@ static struct ehca_qp *internal_create_q + goto create_qp_exit2; + } + +- my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length / +- my_qp->ipz_squeue.qe_size; +- my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries * +- sizeof(struct ehca_qmap_entry)); +- if (!my_qp->sq_map.map) { +- ehca_err(pd->device, "Couldn't allocate squeue " +- "map ret=%i", ret); +- goto create_qp_exit3; +- } +- INIT_LIST_HEAD(&my_qp->sq_err_node); +- /* to avoid the generation of bogus flush CQEs */ +- reset_queue_map(&my_qp->sq_map); ++ if (!is_user) { ++ my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length / ++ my_qp->ipz_squeue.qe_size; ++ my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries * ++ sizeof(struct ehca_qmap_entry)); ++ if (!my_qp->sq_map.map) { ++ ehca_err(pd->device, "Couldn't allocate squeue " ++ "map ret=%i", ret); ++ goto create_qp_exit3; ++ } ++ INIT_LIST_HEAD(&my_qp->sq_err_node); ++ /* to avoid the generation of bogus flush CQEs */ ++ reset_queue_map(&my_qp->sq_map); ++ } + } + + if (HAS_RQ(my_qp)) { +@@ -782,20 +786,21 @@ static struct ehca_qp *internal_create_q + "and pages ret=%i", ret); + goto create_qp_exit4; + } +- +- my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length / +- my_qp->ipz_rqueue.qe_size; +- my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries * +- sizeof(struct ehca_qmap_entry)); +- if (!my_qp->rq_map.map) { +- ehca_err(pd->device, "Couldn't allocate squeue " +- "map ret=%i", ret); +- goto create_qp_exit5; ++ if (!is_user) { ++ my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length / ++ my_qp->ipz_rqueue.qe_size; ++ my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries * ++ sizeof(struct ehca_qmap_entry)); ++ if (!my_qp->rq_map.map) { ++ ehca_err(pd->device, "Couldn't allocate squeue " ++ "map ret=%i", ret); ++ goto create_qp_exit5; ++ } ++ INIT_LIST_HEAD(&my_qp->rq_err_node); ++ /* to avoid the generation of bogus flush CQEs */ ++ reset_queue_map(&my_qp->rq_map); + } +- INIT_LIST_HEAD(&my_qp->rq_err_node); +- /* to avoid the generation of bogus flush CQEs */ +- reset_queue_map(&my_qp->rq_map); +- } else if (init_attr->srq) { ++ } else if (init_attr->srq && !is_user) { + /* this is a base QP, use the queue map of the SRQ */ + my_qp->rq_map = my_srq->rq_map; + INIT_LIST_HEAD(&my_qp->rq_err_node); +@@ -908,7 +913,7 @@ create_qp_exit7: + kfree(my_qp->mod_qp_parm); + + create_qp_exit6: +- if (HAS_RQ(my_qp)) ++ if (HAS_RQ(my_qp) && !is_user) + vfree(my_qp->rq_map.map); + + create_qp_exit5: +@@ -916,7 +921,7 @@ create_qp_exit5: + ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); + + create_qp_exit4: +- if (HAS_SQ(my_qp)) ++ if (HAS_SQ(my_qp) && !is_user) + vfree(my_qp->sq_map.map); + + create_qp_exit3: +@@ -1224,6 +1229,7 @@ static int internal_modify_qp(struct ib_ + u64 update_mask; + u64 h_ret; + int bad_wqe_cnt = 0; ++ int is_user = 0; + int squeue_locked = 0; + unsigned long flags = 0; + +@@ -1246,6 +1252,8 @@ static int internal_modify_qp(struct ib_ + ret = ehca2ib_return_code(h_ret); + goto modify_qp_exit1; + } ++ if (ibqp->uobject) ++ is_user = 1; + + qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state); + +@@ -1708,7 +1716,8 @@ static int internal_modify_qp(struct ib_ + goto modify_qp_exit2; + } + } +- if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)) { ++ if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR) ++ && !is_user) { + ret = check_for_left_cqes(my_qp, shca); + if (ret) + goto modify_qp_exit2; +@@ -1718,16 +1727,17 @@ static int internal_modify_qp(struct ib_ + ipz_qeit_reset(&my_qp->ipz_rqueue); + ipz_qeit_reset(&my_qp->ipz_squeue); + +- if (qp_cur_state == IB_QPS_ERR) { ++ if (qp_cur_state == IB_QPS_ERR && !is_user) { + del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node); + + if (HAS_RQ(my_qp)) + del_from_err_list(my_qp->recv_cq, + &my_qp->rq_err_node); + } +- reset_queue_map(&my_qp->sq_map); ++ if (!is_user) ++ reset_queue_map(&my_qp->sq_map); + +- if (HAS_RQ(my_qp)) ++ if (HAS_RQ(my_qp) && !is_user) + reset_queue_map(&my_qp->rq_map); + } + +@@ -2118,10 +2128,12 @@ static int internal_destroy_qp(struct ib + int ret; + u64 h_ret; + u8 port_num; ++ int is_user = 0; + enum ib_qp_type qp_type; + unsigned long flags; + + if (uobject) { ++ is_user = 1; + if (my_qp->mm_count_galpa || + my_qp->mm_count_rqueue || my_qp->mm_count_squeue) { + ehca_err(dev, "Resources still referenced in " +@@ -2148,10 +2160,10 @@ static int internal_destroy_qp(struct ib + * SRQs will never get into an error list and do not have a recv_cq, + * so we need to skip them here. + */ +- if (HAS_RQ(my_qp) && !IS_SRQ(my_qp)) ++ if (HAS_RQ(my_qp) && !IS_SRQ(my_qp) && !is_user) + del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node); + +- if (HAS_SQ(my_qp)) ++ if (HAS_SQ(my_qp) && !is_user) + del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node); + + /* now wait until all pending events have completed */ +@@ -2189,13 +2201,13 @@ static int internal_destroy_qp(struct ib + + if (HAS_RQ(my_qp)) { + ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); +- +- vfree(my_qp->rq_map.map); ++ if (!is_user) ++ vfree(my_qp->rq_map.map); + } + if (HAS_SQ(my_qp)) { + ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); +- +- vfree(my_qp->sq_map.map); ++ if (!is_user) ++ vfree(my_qp->sq_map.map); + } + kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_if.c ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_if.c +@@ -284,7 +284,7 @@ u64 hipz_h_alloc_resource_cq(const struc + param->act_pages = (u32)outs[4]; + + if (ret == H_SUCCESS) +- hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]); ++ hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]); + + if (ret == H_NOT_ENOUGH_RESOURCES) + ehca_gen_err("Not enough resources. ret=%li", ret); +@@ -293,7 +293,7 @@ u64 hipz_h_alloc_resource_cq(const struc + } + + u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, +- struct ehca_alloc_qp_parms *parms) ++ struct ehca_alloc_qp_parms *parms, int is_user) + { + u64 ret; + u64 allocate_controls, max_r10_reg, r11, r12; +@@ -359,7 +359,7 @@ u64 hipz_h_alloc_resource_qp(const struc + (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]); + + if (ret == H_SUCCESS) +- hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]); ++ hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]); + + if (ret == H_NOT_ENOUGH_RESOURCES) + ehca_gen_err("Not enough resources. ret=%li", ret); +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_if.h ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_if.h +@@ -78,7 +78,7 @@ u64 hipz_h_alloc_resource_cq(const struc + * initialize resources, create empty QPPTs (2 rings). + */ + u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, +- struct ehca_alloc_qp_parms *parms); ++ struct ehca_alloc_qp_parms *parms, int is_user); + + u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, + const u8 port_id, +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_phyp.c ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_phyp.c +@@ -54,12 +54,15 @@ int hcall_unmap_page(u64 mapaddr) + return 0; + } + +-int hcp_galpas_ctor(struct h_galpas *galpas, ++int hcp_galpas_ctor(struct h_galpas *galpas, int is_user, + u64 paddr_kernel, u64 paddr_user) + { +- int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle); +- if (ret) +- return ret; ++ if (!is_user) { ++ int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle); ++ if (ret) ++ return ret; ++ } else ++ galpas->kernel.fw_handle = NULL; + + galpas->user.fw_handle = paddr_user; + +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/hcp_phyp.h ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/hcp_phyp.h +@@ -78,7 +78,7 @@ static inline void hipz_galpa_store(stru + *(volatile u64 __force *)addr = value; + } + +-int hcp_galpas_ctor(struct h_galpas *galpas, ++int hcp_galpas_ctor(struct h_galpas *galpas, int is_user, + u64 paddr_kernel, u64 paddr_user); + + int hcp_galpas_dtor(struct h_galpas *galpas); +--- linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa.orig/drivers/infiniband/hw/ehca/ehca_main.c ++++ linux-2.6.27.21-SLE11_BRANCH_20090427084335_da0f63fa/drivers/infiniband/hw/ehca/ehca_main.c +@@ -52,7 +52,7 @@ + #include "ehca_tools.h" + #include "hcp_if.h" + +-#define HCAD_VERSION "0026" ++#define HCAD_VERSION "0027" + + MODULE_LICENSE("Dual BSD/GPL"); + MODULE_AUTHOR("Christoph Raisch "); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ehca-rejecting-dynamic-mem-add-remove.patch b/src/patches/suse-2.6.27.31/patches.drivers/ehca-rejecting-dynamic-mem-add-remove.patch new file mode 100644 index 000000000..2a3f7310c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ehca-rejecting-dynamic-mem-add-remove.patch @@ -0,0 +1,101 @@ +Subject: [PATCH]IB/ehca:reject dynamic memory add/remove +From: Stefan Roscher +References: 434651 - LTC48744 + +Since the ehca device driver does not support dynamic memory add and remove +operations, the driver must explicitly reject such requests in order to prevent +unpredictable behaviors related to memory regions already occupied and being +used by InfiniBand applications. +The solution is to add a memory notifier to the ehca device driver and if a request +for dynamic memory add or remove comes in, ehca will always reject it. + +Signed-off-by: Stefan Roscher +Signed-off-by: Olaf Hering + +--- + drivers/infiniband/hw/ehca/ehca_main.c | 46 +++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +--- a/drivers/infiniband/hw/ehca/ehca_main.c ++++ b/drivers/infiniband/hw/ehca/ehca_main.c +@@ -44,6 +44,8 @@ + #include + #endif + ++#include ++#include + #include "ehca_classes.h" + #include "ehca_iverbs.h" + #include "ehca_mrmw.h" +@@ -965,6 +967,39 @@ void ehca_poll_eqs(unsigned long data) + spin_unlock(&shca_list_lock); + } + ++static int ehca_mem_notifier(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ static unsigned long ehca_dmem_warn_time; ++ ++ switch (action) { ++ case MEM_CANCEL_OFFLINE: ++ case MEM_CANCEL_ONLINE: ++ case MEM_ONLINE: ++ case MEM_OFFLINE: ++ return NOTIFY_OK; ++ case MEM_GOING_ONLINE: ++ case MEM_GOING_OFFLINE: ++ /* only ok if no hca is attached to the lpar */ ++ spin_lock(&shca_list_lock); ++ if (list_empty(&shca_list)) { ++ spin_unlock(&shca_list_lock); ++ return NOTIFY_OK; ++ } else { ++ spin_unlock(&shca_list_lock); ++ if (printk_timed_ratelimit(&ehca_dmem_warn_time, ++ 30 * 1000)) ++ ehca_gen_err("DMEM operations are not allowed in conjunction with eHCA"); ++ return NOTIFY_BAD; ++ } ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block ehca_mem_nb = { ++ .notifier_call = ehca_mem_notifier, ++}; ++ + static int __init ehca_module_init(void) + { + int ret; +@@ -992,6 +1027,12 @@ static int __init ehca_module_init(void) + goto module_init2; + } + ++ ret = register_memory_notifier(&ehca_mem_nb); ++ if (ret) { ++ ehca_gen_err("Failed registering memory add/remove notifier"); ++ goto module_init3; ++ } ++ + if (ehca_poll_all_eqs != 1) { + ehca_gen_err("WARNING!!!"); + ehca_gen_err("It is possible to lose interrupts."); +@@ -1004,6 +1045,9 @@ static int __init ehca_module_init(void) + + return 0; + ++module_init3: ++ ibmebus_unregister_driver(&ehca_driver); ++ + module_init2: + ehca_destroy_slab_caches(); + +@@ -1019,6 +1063,8 @@ static void __exit ehca_module_exit(void + + ibmebus_unregister_driver(&ehca_driver); + ++ unregister_memory_notifier(&ehca_mem_nb); ++ + ehca_destroy_slab_caches(); + + ehca_destroy_comp_pool(); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ehea-modinfo.patch b/src/patches/suse-2.6.27.31/patches.drivers/ehea-modinfo.patch new file mode 100644 index 000000000..12d0b56e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ehea-modinfo.patch @@ -0,0 +1,42 @@ +Subject: add alias entry for portN properties +From: olh@suse.de +References: 435215 - LTC48564 + +Use separate table for alias entries in the ehea module, +otherwise the probe() function will operate on the separate ports +instead of the lhea-"root" entry of the device-tree + +--- + drivers/net/ehea/ehea_main.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/drivers/net/ehea/ehea_main.c ++++ b/drivers/net/ehea/ehea_main.c +@@ -111,6 +111,19 @@ static int __devinit ehea_probe_adapter( + + static int __devexit ehea_remove(struct of_device *dev); + ++static struct of_device_id ehea_module_device_table[] = { ++ { ++ .name = "lhea", ++ .compatible = "IBM,lhea", ++ }, ++ { ++ .type = "network", ++ .compatible = "IBM,lhea-ethernet", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ehea_module_device_table); ++ + static struct of_device_id ehea_device_table[] = { + { + .name = "lhea", +@@ -118,7 +131,6 @@ static struct of_device_id ehea_device_t + }, + {}, + }; +-MODULE_DEVICE_TABLE(of, ehea_device_table); + + static struct of_platform_driver ehea_driver = { + .name = "ehea", diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ehea.patch b/src/patches/suse-2.6.27.31/patches.drivers/ehea.patch new file mode 100644 index 000000000..2b0e92a68 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ehea.patch @@ -0,0 +1,356 @@ +Subject: [PATCH] ehea: Fix memory hotplug support +Subject [PATCH] ehea: Add hugepage detection +From: Hannes Hering +References: 436447 - LTC 48713 +References: 439599 - LTC 48958 +References: 477972 - LTC 51731 + +This patch implements the memory notifier to update the busmap instantly +instead of rebuilding the whole map. This is necessary because +walk_memory_resource provides different information than required during memory +hotplug. + +... + +All kernel memory which is used for kernel/hardware data transfer must be registered +with firmware using "memory regions". 16GB hugepages may not be part of a memory region +due to firmware restrictions. +This patch modifies the walk_memory_resource callback fn to filter hugepages and add +only standard memory to the busmap which is later on used for MR registration. + +... + +Added missing set_bit() to disable data transfer when a memchange notification is handled + +... + +Signed-off-by: Thomas Klein +Signed-off-by: Hannes Hering +Signed-off-by: Olaf Hering +--- + drivers/net/ehea/ehea.h | 4 + drivers/net/ehea/ehea_main.c | 27 ++++-- + drivers/net/ehea/ehea_phyp.c | 2 + drivers/net/ehea/ehea_qmr.c | 175 ++++++++++++++++++++++++++++++++++++------- + drivers/net/ehea/ehea_qmr.h | 5 + + 5 files changed, 172 insertions(+), 41 deletions(-) + +--- a/drivers/net/ehea/ehea.h ++++ b/drivers/net/ehea/ehea.h +@@ -40,13 +40,13 @@ + #include + + #define DRV_NAME "ehea" +-#define DRV_VERSION "EHEA_0092" ++#define DRV_VERSION "EHEA_0094-02" + + /* eHEA capability flags */ + #define DLPAR_PORT_ADD_REM 1 + #define DLPAR_MEM_ADD 2 + #define DLPAR_MEM_REM 4 +-#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD) ++#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD | DLPAR_MEM_REM) + + #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ + | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) +--- a/drivers/net/ehea/ehea_main.c ++++ b/drivers/net/ehea/ehea_main.c +@@ -2869,7 +2869,7 @@ static void ehea_rereg_mrs(struct work_s + struct ehea_adapter *adapter; + + mutex_lock(&dlpar_mem_lock); +- ehea_info("LPAR memory enlarged - re-initializing driver"); ++ ehea_info("LPAR memory changed - re-initializing driver"); + + list_for_each_entry(adapter, &adapter_list, list) + if (adapter->active_ports) { +@@ -2906,13 +2906,6 @@ static void ehea_rereg_mrs(struct work_s + } + } + +- ehea_destroy_busmap(); +- ret = ehea_create_busmap(); +- if (ret) { +- ehea_error("creating ehea busmap failed"); +- goto out; +- } +- + clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); + + list_for_each_entry(adapter, &adapter_list, list) +@@ -3525,9 +3518,23 @@ void ehea_crash_handler(void) + static int ehea_mem_notifier(struct notifier_block *nb, + unsigned long action, void *data) + { ++ struct memory_notify *arg = data; + switch (action) { +- case MEM_OFFLINE: +- ehea_info("memory has been removed"); ++ case MEM_CANCEL_OFFLINE: ++ ehea_info("memory offlining canceled"); ++ /* Readd canceled memory block */ ++ case MEM_ONLINE: ++ ehea_info("memory is going online"); ++ set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); ++ if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages)) ++ return NOTIFY_BAD; ++ ehea_rereg_mrs(NULL); ++ break; ++ case MEM_GOING_OFFLINE: ++ ehea_info("memory is going offline"); ++ set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); ++ if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages)) ++ return NOTIFY_BAD; + ehea_rereg_mrs(NULL); + break; + default: +--- a/drivers/net/ehea/ehea_phyp.c ++++ b/drivers/net/ehea/ehea_phyp.c +@@ -535,7 +535,7 @@ u64 ehea_h_query_ehea(const u64 adapter_ + cb_logaddr, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ + #ifdef DEBUG +- ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); ++ ehea_dump(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); + #endif + return hret; + } +--- a/drivers/net/ehea/ehea_qmr.c ++++ b/drivers/net/ehea/ehea_qmr.c +@@ -567,7 +567,7 @@ static inline int ehea_calc_index(unsign + static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, + int dir) + { +- if(!ehea_top_bmap->dir[dir]) { ++ if (!ehea_top_bmap->dir[dir]) { + ehea_top_bmap->dir[dir] = + kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL); + if (!ehea_top_bmap->dir[dir]) +@@ -578,7 +578,7 @@ static inline int ehea_init_top_bmap(str + + static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) + { +- if(!ehea_bmap->top[top]) { ++ if (!ehea_bmap->top[top]) { + ehea_bmap->top[top] = + kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL); + if (!ehea_bmap->top[top]) +@@ -587,52 +587,171 @@ static inline int ehea_init_bmap(struct + return ehea_init_top_bmap(ehea_bmap->top[top], dir); + } + +-static int ehea_create_busmap_callback(unsigned long pfn, +- unsigned long nr_pages, void *arg) ++static DEFINE_MUTEX(ehea_busmap_mutex); ++static unsigned long ehea_mr_len; ++ ++#define EHEA_BUSMAP_ADD_SECT 1 ++#define EHEA_BUSMAP_REM_SECT 0 ++ ++static void ehea_rebuild_busmap(void) ++{ ++ u64 vaddr = EHEA_BUSMAP_START; ++ int top, dir, idx; ++ ++ for (top = 0; top < EHEA_MAP_ENTRIES; top++) { ++ struct ehea_top_bmap *ehea_top; ++ int valid_dir_entries = 0; ++ ++ if (!ehea_bmap->top[top]) ++ continue; ++ ehea_top = ehea_bmap->top[top]; ++ for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) { ++ struct ehea_dir_bmap *ehea_dir; ++ int valid_entries = 0; ++ ++ if (!ehea_top->dir[dir]) ++ continue; ++ valid_dir_entries++; ++ ehea_dir = ehea_top->dir[dir]; ++ for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) { ++ if (!ehea_dir->ent[idx]) ++ continue; ++ valid_entries++; ++ ehea_dir->ent[idx] = vaddr; ++ vaddr += EHEA_SECTSIZE; ++ } ++ if (!valid_entries) { ++ ehea_top->dir[dir] = NULL; ++ kfree(ehea_dir); ++ } ++ } ++ if (!valid_dir_entries) { ++ ehea_bmap->top[top] = NULL; ++ kfree(ehea_top); ++ } ++ } ++} ++ ++static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add) + { +- unsigned long i, mr_len, start_section, end_section; ++ unsigned long i, start_section, end_section; ++ ++ if (!nr_pages) ++ return 0; ++ ++ if (!ehea_bmap) { ++ ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); ++ if (!ehea_bmap) ++ return -ENOMEM; ++ } ++ + start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE; + end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE); +- mr_len = *(unsigned long *)arg; ++ /* Mark entries as valid or invalid only; address is assigned later */ ++ for (i = start_section; i < end_section; i++) { ++ u64 flag; ++ int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); ++ int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); ++ int idx = i & EHEA_INDEX_MASK; ++ ++ if (add) { ++ int ret = ehea_init_bmap(ehea_bmap, top, dir); ++ if (ret) ++ return ret; ++ flag = 1; /* valid */ ++ ehea_mr_len += EHEA_SECTSIZE; ++ } else { ++ if (!ehea_bmap->top[top]) ++ continue; ++ if (!ehea_bmap->top[top]->dir[dir]) ++ continue; ++ flag = 0; /* invalid */ ++ ehea_mr_len -= EHEA_SECTSIZE; ++ } + +- ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); +- if (!ehea_bmap) +- return -ENOMEM; ++ ehea_bmap->top[top]->dir[dir]->ent[idx] = flag; ++ } ++ ehea_rebuild_busmap(); /* Assign contiguous addresses for mr */ ++ return 0; ++} + +- for (i = start_section; i < end_section; i++) { +- int ret; +- int top, dir, idx; +- u64 vaddr; ++int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages) ++{ ++ int ret; + +- top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); +- dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); ++ mutex_lock(&ehea_busmap_mutex); ++ ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); ++ mutex_unlock(&ehea_busmap_mutex); ++ return ret; ++} + +- ret = ehea_init_bmap(ehea_bmap, top, dir); +- if(ret) +- return ret; ++int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages) ++{ ++ int ret; + +- idx = i & EHEA_INDEX_MASK; +- vaddr = EHEA_BUSMAP_START + mr_len + i * EHEA_SECTSIZE; ++ mutex_lock(&ehea_busmap_mutex); ++ ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_REM_SECT); ++ mutex_unlock(&ehea_busmap_mutex); ++ return ret; ++} + +- ehea_bmap->top[top]->dir[dir]->ent[idx] = vaddr; +- } ++static int ehea_is_hugepage(unsigned long pfn) ++{ ++ int page_order; + +- mr_len += nr_pages * PAGE_SIZE; +- *(unsigned long *)arg = mr_len; ++ if (pfn & EHEA_HUGEPAGE_PFN_MASK) ++ return 0; + +- return 0; ++ page_order = compound_order(pfn_to_page(pfn)); ++ if (page_order + PAGE_SHIFT != EHEA_HUGEPAGESHIFT) ++ return 0; ++ ++ return 1; + } + +-static unsigned long ehea_mr_len; ++static int ehea_create_busmap_callback(unsigned long initial_pfn, ++ unsigned long total_nr_pages, void *arg) ++{ ++ int ret; ++ unsigned long pfn, start_pfn, end_pfn, nr_pages; + +-static DEFINE_MUTEX(ehea_busmap_mutex); ++ if ((total_nr_pages * PAGE_SIZE) < EHEA_HUGEPAGE_SIZE) ++ return ehea_update_busmap(initial_pfn, total_nr_pages, ++ EHEA_BUSMAP_ADD_SECT); ++ ++ /* Given chunk is >= 16GB -> check for hugepages */ ++ start_pfn = initial_pfn; ++ end_pfn = initial_pfn + total_nr_pages; ++ pfn = start_pfn; ++ ++ while (pfn < end_pfn) { ++ if (ehea_is_hugepage(pfn)) { ++ /* Add mem found in front of the hugepage */ ++ nr_pages = pfn - start_pfn; ++ ret = ehea_update_busmap(start_pfn, nr_pages, ++ EHEA_BUSMAP_ADD_SECT); ++ if (ret) ++ return ret; ++ ++ /* Skip the hugepage */ ++ pfn += (EHEA_HUGEPAGE_SIZE / PAGE_SIZE); ++ start_pfn = pfn; ++ } else ++ pfn += (EHEA_SECTSIZE / PAGE_SIZE); ++ } ++ ++ /* Add mem found behind the hugepage(s) */ ++ nr_pages = pfn - start_pfn; ++ return ehea_update_busmap(start_pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); ++} + + int ehea_create_busmap(void) + { + int ret; ++ + mutex_lock(&ehea_busmap_mutex); + ehea_mr_len = 0; +- ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, &ehea_mr_len, ++ ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, NULL, + ehea_create_busmap_callback); + mutex_unlock(&ehea_busmap_mutex); + return ret; +--- a/drivers/net/ehea/ehea_qmr.h ++++ b/drivers/net/ehea/ehea_qmr.h +@@ -40,6 +40,9 @@ + #define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT) + #define EHEA_SECTSIZE (1UL << 24) + #define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT) ++#define EHEA_HUGEPAGESHIFT 34 ++#define EHEA_HUGEPAGE_SIZE (1UL << EHEA_HUGEPAGESHIFT) ++#define EHEA_HUGEPAGE_PFN_MASK ((EHEA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT) + + #if ((1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE) + #error eHEA module cannot work if kernel sectionsize < ehea sectionsize +@@ -378,6 +381,8 @@ int ehea_rem_mr(struct ehea_mr *mr); + + void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); + ++int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages); ++int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages); + int ehea_create_busmap(void); + void ehea_destroy_busmap(void); + u64 ehea_map_vaddr(void *caddr); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/elousb.patch b/src/patches/suse-2.6.27.31/patches.drivers/elousb.patch new file mode 100644 index 000000000..81d0defb8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/elousb.patch @@ -0,0 +1,377 @@ +From: Jiri Kosina +Subject: Elo USB touchscreen driver +Patch-mainline: will be submitted for 2.6.28 +References: FATE#304972 + +This is a driver for Elo USB touchscreen devices. + +Signed-off-by: Vojtech Pavlik +Acked-by: Jiri Kosina + +--- + drivers/hid/usbhid/hid-quirks.c | 4 + drivers/input/touchscreen/Kconfig | 12 + + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/elousb.c | 305 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 322 insertions(+) + +--- a/drivers/hid/usbhid/hid-quirks.c ++++ b/drivers/hid/usbhid/hid-quirks.c +@@ -138,7 +138,9 @@ + #define USB_DEVICE_ID_DMI_ENC 0x5fab + + #define USB_VENDOR_ID_ELO 0x04E7 ++#define USB_DEVICE_ID_ELO_4000U 0x0009 + #define USB_DEVICE_ID_ELO_TS2700 0x0020 ++#define USB_DEVICE_ID_ELO_4500U 0x0030 + + #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f + #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 +@@ -485,6 +487,8 @@ static const struct hid_blacklist { + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, ++ { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_4000U, HID_QUIRK_IGNORE }, ++ { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_4500U, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE }, +--- /dev/null ++++ b/drivers/input/touchscreen/elousb.c +@@ -0,0 +1,305 @@ ++/* ++ * Copyright (c) 1999-2001 Vojtech Pavlik ++ * ++ * Elo USB touchscreen support ++ */ ++ ++/* ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Should you need to contact me, the author, you can do so either by ++ * e-mail - mail your message to , or by paper mail: ++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Version Information ++ */ ++#define DRIVER_VERSION "v1.1" ++#define DRIVER_AUTHOR "Vojtech Pavlik " ++#define DRIVER_DESC "Elo USB touchscreen driver" ++#define DRIVER_LICENSE "GPL" ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE(DRIVER_LICENSE); ++ ++struct elousb { ++ char name[128]; ++ char phys[64]; ++ struct usb_device *usbdev; ++ struct input_dev *dev; ++ struct urb *irq; ++ ++ unsigned char *data; ++ dma_addr_t data_dma; ++}; ++ ++static void elousb_irq(struct urb *urb) ++{ ++ struct elousb *elo = urb->context; ++ unsigned char *data = elo->data; ++ struct input_dev *dev = elo->dev; ++ int status; ++ ++ switch (urb->status) { ++ case 0: /* success */ ++ break; ++ case -ECONNRESET: /* unlink */ ++ case -ENOENT: ++ case -ESHUTDOWN: ++ return; ++ /* -EPIPE: should clear the halt */ ++ default: /* error */ ++ goto resubmit; ++ } ++ ++ if (data[0] != 'T') /* Mandatory ELO packet marker */ ++ return; ++ ++ ++ input_report_abs(dev, ABS_X, ((u32)data[3] << 8) | data[2]); ++ input_report_abs(dev, ABS_Y, ((u32)data[5] << 8) | data[4]); ++ ++ input_report_abs(dev, ABS_PRESSURE, ++ (data[1] & 0x80) ? (((u32)data[7] << 8) | data[6]): 0); ++ ++ if (data[1] & 0x03) { ++ input_report_key(dev, BTN_TOUCH, 1); ++ input_sync(dev); ++ } ++ ++ if (data[1] & 0x04) ++ input_report_key(dev, BTN_TOUCH, 0); ++ ++ input_sync(dev); ++ ++resubmit: ++ status = usb_submit_urb (urb, GFP_ATOMIC); ++ if (status) ++ err ("can't resubmit intr, %s-%s/input0, status %d", ++ elo->usbdev->bus->bus_name, ++ elo->usbdev->devpath, status); ++} ++ ++static int elousb_open(struct input_dev *dev) ++{ ++ struct elousb *elo = input_get_drvdata(dev); ++ ++ elo->irq->dev = elo->usbdev; ++ if (usb_submit_urb(elo->irq, GFP_KERNEL)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static void elousb_close(struct input_dev *dev) ++{ ++ struct elousb *elo = input_get_drvdata(dev); ++ ++ usb_kill_urb(elo->irq); ++} ++ ++static int elousb_probe(struct usb_interface *intf, const struct usb_device_id *id) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ struct usb_host_interface *interface; ++ struct usb_endpoint_descriptor *endpoint; ++ struct hid_descriptor *hdesc; ++ struct elousb *elo; ++ struct input_dev *input_dev; ++ int pipe, i; ++ unsigned int rsize = 0; ++ int error = -ENOMEM; ++ char *rdesc; ++ ++ interface = intf->cur_altsetting; ++ ++ if (interface->desc.bNumEndpoints != 1) ++ return -ENODEV; ++ ++ endpoint = &interface->endpoint[0].desc; ++ if (!(endpoint->bEndpointAddress & USB_DIR_IN)) ++ return -ENODEV; ++ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) ++ return -ENODEV; ++ ++ if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ++ (!interface->desc.bNumEndpoints || ++ usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { ++ err("HID class descriptor not present"); ++ return -ENODEV; ++ } ++ ++ for (i = 0; i < hdesc->bNumDescriptors; i++) ++ if (hdesc->desc[i].bDescriptorType == HID_DT_REPORT) ++ rsize = le16_to_cpu(hdesc->desc[i].wDescriptorLength); ++ ++ if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { ++ err("weird size of report descriptor (%u)", rsize); ++ return -ENODEV; ++ } ++ ++ ++ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); ++ ++ elo = kzalloc(sizeof(struct elousb), GFP_KERNEL); ++ input_dev = input_allocate_device(); ++ if (!elo || !input_dev) ++ goto fail1; ++ ++ elo->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &elo->data_dma); ++ if (!elo->data) ++ goto fail1; ++ ++ elo->irq = usb_alloc_urb(0, GFP_KERNEL); ++ if (!elo->irq) ++ goto fail2; ++ ++ if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) ++ goto fail3; ++ ++ elo->usbdev = dev; ++ elo->dev = input_dev; ++ ++ if ((error = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ++ HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, ++ interface->desc.bInterfaceNumber, ++ NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { ++ err("setting HID idle timeout failed, error %d", error); ++ error = -ENODEV; ++ goto fail4; ++ } ++ ++ if ((error = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ++ USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, ++ HID_DT_REPORT << 8, interface->desc.bInterfaceNumber, ++ rdesc, rsize, USB_CTRL_GET_TIMEOUT)) < rsize) { ++ err("reading HID report descriptor failed, error %d", error); ++ error = -ENODEV; ++ goto fail4; ++ } ++ ++ if (dev->manufacturer) ++ strlcpy(elo->name, dev->manufacturer, sizeof(elo->name)); ++ ++ if (dev->product) { ++ if (dev->manufacturer) ++ strlcat(elo->name, " ", sizeof(elo->name)); ++ strlcat(elo->name, dev->product, sizeof(elo->name)); ++ } ++ ++ if (!strlen(elo->name)) ++ snprintf(elo->name, sizeof(elo->name), ++ "Elo touchscreen %04x:%04x", ++ le16_to_cpu(dev->descriptor.idVendor), ++ le16_to_cpu(dev->descriptor.idProduct)); ++ ++ usb_make_path(dev, elo->phys, sizeof(elo->phys)); ++ strlcat(elo->phys, "/input0", sizeof(elo->phys)); ++ ++ input_dev->name = elo->name; ++ input_dev->phys = elo->phys; ++ usb_to_input_id(dev, &input_dev->id); ++ input_dev->dev.parent = &intf->dev; ++ ++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); ++ set_bit(BTN_TOUCH, input_dev->keybit); ++ input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y); ++ set_bit(ABS_PRESSURE, input_dev->absbit); ++ ++ input_set_abs_params(input_dev, ABS_X, 0, 4000, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, 0, 3840, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 256, 0, 0); ++ ++ input_set_drvdata(input_dev, elo); ++ ++ input_dev->open = elousb_open; ++ input_dev->close = elousb_close; ++ ++ usb_fill_int_urb(elo->irq, dev, pipe, elo->data, 8, ++ elousb_irq, elo, endpoint->bInterval); ++ elo->irq->transfer_dma = elo->data_dma; ++ elo->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ input_register_device(elo->dev); ++ ++ usb_set_intfdata(intf, elo); ++ return 0; ++ ++fail4: ++ kfree(rdesc); ++fail3: ++ usb_free_urb(elo->irq); ++fail2: ++ usb_buffer_free(dev, 8, elo->data, elo->data_dma); ++fail1: ++ input_free_device(input_dev); ++ kfree(elo); ++ return -ENOMEM; ++} ++ ++static void elousb_disconnect(struct usb_interface *intf) ++{ ++ struct elousb *elo = usb_get_intfdata (intf); ++ ++ usb_set_intfdata(intf, NULL); ++ if (elo) { ++ usb_kill_urb(elo->irq); ++ input_unregister_device(elo->dev); ++ usb_free_urb(elo->irq); ++ usb_buffer_free(interface_to_usbdev(intf), 8, elo->data, elo->data_dma); ++ kfree(elo); ++ } ++} ++ ++static struct usb_device_id elousb_id_table [] = { ++ { USB_DEVICE(0x04e7, 0x0009) }, /* CarrolTouch 4000U */ ++ { USB_DEVICE(0x04e7, 0x0030) }, /* CarrolTouch 4500U */ ++ { } /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE (usb, elousb_id_table); ++ ++static struct usb_driver elousb_driver = { ++ .name = "elousb", ++ .probe = elousb_probe, ++ .disconnect = elousb_disconnect, ++ .id_table = elousb_id_table, ++}; ++ ++static int __init elousb_init(void) ++{ ++ int retval = usb_register(&elousb_driver); ++ if (retval == 0) ++ info(DRIVER_VERSION ":" DRIVER_DESC); ++ return retval; ++} ++ ++static void __exit elousb_exit(void) ++{ ++ usb_deregister(&elousb_driver); ++} ++ ++module_init(elousb_init); ++module_exit(elousb_exit); +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -91,6 +91,18 @@ config TOUCHSCREEN_ELO + To compile this driver as a module, choose M here: the + module will be called elo. + ++config TOUCHSCREEN_ELOUSB ++ tristate "Elo USB touchscreens" ++ select USB ++ help ++ Say Y here if you have an Elo USB touchscreen connected to ++ your system. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called elousb. ++ + config TOUCHSCREEN_MTOUCH + tristate "MicroTouch serial touchscreens" + select SERIO +--- a/drivers/input/touchscreen/Makefile ++++ b/drivers/input/touchscreen/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY) += h360 + obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o + obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o + obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o ++obj-$(CONFIG_TOUCHSCREEN_ELOUSB) += elousb.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o + obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o + obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/fcoe-exch-mgr-is-freed-while-lport-still-retrying-s.patch b/src/patches/suse-2.6.27.31/patches.drivers/fcoe-exch-mgr-is-freed-while-lport-still-retrying-s.patch new file mode 100644 index 000000000..11dea2fed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/fcoe-exch-mgr-is-freed-while-lport-still-retrying-s.patch @@ -0,0 +1,48 @@ +From 32ffe13b1e76244d93fd28087875d5b182472105 Mon Sep 17 00:00:00 2001 +From: Steve Ma +Date: Wed, 4 Feb 2009 17:29:20 -0800 +Subject: [PATCH] fcoe: exch mgr is freed while lport still retrying sequences +References: bnc#473603 + +When a sequence cannot be delivered to the target, the local +port will schedule retries, While this process is in progress, +if we destroy the FCoE interface, the fcoe_sw_destroy routine is +entered, and the fc_exch_mgr_free(lp->emp) is called. Thus +if fc_exch_alloc() is called when retrying the sequence, +the mempool_alloc() will fail to allocate the exchange because +the mempool of the exchange manager has already been released. +This patch is to cancel any pending retry work of the local +port before we start to destroy the interface. + +Also, when resetting the local port, we should also stop the +scheduled pending retries. + +Signed-off-by: Steve Ma +Acked-by: John Jolly +--- + drivers/scsi/libfc/fc_lport.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index 74f4a0f..780c571 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -617,6 +617,7 @@ int fc_fabric_logoff(struct fc_lport *lport) + { + lport->tt.disc_stop_final(lport); + mutex_lock(&lport->lp_mutex); ++ cancel_delayed_work_sync(&lport->retry_work); + fc_lport_enter_logo(lport); + mutex_unlock(&lport->lp_mutex); + return 0; +@@ -938,6 +939,7 @@ static void fc_lport_enter_reset(struct fc_lport *lport) + fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_RESET); ++ cancel_delayed_work_sync(&lport->retry_work); + + if (lport->dns_rp) + lport->tt.rport_logoff(lport->dns_rp); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/fcoe-fix-handling-of-pending-queue b/src/patches/suse-2.6.27.31/patches.drivers/fcoe-fix-handling-of-pending-queue new file mode 100644 index 000000000..49ff60c56 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/fcoe-fix-handling-of-pending-queue @@ -0,0 +1,167 @@ +From b32a88ad3782fbaa3cb851ebc1b694ba09840c86 Mon Sep 17 00:00:00 2001 +From: Chris Leech +Date: Thu, 19 Feb 2009 14:37:47 -0800 +Subject: fcoe: fix handling of pending queue, prevent out of order frames +References: bnc#477953 + +The per-lport pending queue handling can result in a frame being retried +from a different CPU than it was originally sent from. The scope of the +queue lock is not large enough to prevent reordering of frames within a +sequence in that case. + +Before this change I would see out of order frames on large write IOs, +leading to frequent exchange timeouts and retries. + +With the locking scope changed, the fcoe_insert_wait_queue(_head) helpers +no longer do anything useful, so I removed them as well. + +Signed-off-by: Chris Leech +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/fcoe/libfcoe.c | 64 +++++++++---------------------------------- + 1 files changed, 13 insertions(+), 51 deletions(-) + +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +index ada3ebb..d3f4eb9 100644 +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -71,8 +71,6 @@ struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; + + /* Function Prototyes */ + static int fcoe_check_wait_queue(struct fc_lport *); +-static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *); +-static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *); + static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); + #ifdef CONFIG_HOTPLUG_CPU + static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); +@@ -497,6 +495,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + + /* send down to lld */ + fr_dev(fp) = lp; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); + if (fc->fcoe_pending_queue.qlen) + rc = fcoe_check_wait_queue(lp); + +@@ -504,10 +503,11 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + rc = fcoe_start_io(skb); + + if (rc) { +- fcoe_insert_wait_queue(lp, skb); ++ __skb_queue_tail(&fc->fcoe_pending_queue, skb); + if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) + lp->qfull = 1; + } ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); + + return 0; + } +@@ -732,8 +732,11 @@ void fcoe_watchdog(ulong vp) + + read_lock(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { +- if (fc->lp) ++ if (fc->lp) { ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); + fcoe_check_wait_queue(fc->lp); ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ } + } + read_unlock(&fcoe_hostlist_lock); + +@@ -756,6 +759,8 @@ void fcoe_watchdog(ulong vp) + * in the wait_queue which will be emptied by the time function OR + * by the next skb transmit. + * ++ * Locking: fc->fcoe_pending_queue.lock must be held before calling ++ * + * Returns: 0 for success + **/ + static int fcoe_check_wait_queue(struct fc_lport *lp) +@@ -765,20 +770,17 @@ static int fcoe_check_wait_queue(struct fc_lport *lp) + int rc = -1; + + fc = fcoe_softc(lp); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); + + if (fc->fcoe_pending_queue_active) + goto out; + fc->fcoe_pending_queue_active = 1; + if (fc->fcoe_pending_queue.qlen) { + while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); + rc = fcoe_start_io(skb); +- if (rc) +- fcoe_insert_wait_queue_head(lp, skb); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- if (rc) ++ if (rc) { ++ __skb_queue_head(&fc->fcoe_pending_queue, skb); + break; ++ } + } + /* + * if interface pending queue is below FCOE_LOW_QUEUE_DEPTH +@@ -790,47 +792,10 @@ static int fcoe_check_wait_queue(struct fc_lport *lp) + fc->fcoe_pending_queue_active = 0; + rc = fc->fcoe_pending_queue.qlen; + out: +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); + return rc; + } + + /** +- * fcoe_insert_wait_queue_head - puts skb to fcoe pending queue head +- * @lp: the fc_port for this skb +- * @skb: the associated skb to be xmitted +- * +- * Returns: none +- **/ +-static void fcoe_insert_wait_queue_head(struct fc_lport *lp, +- struct sk_buff *skb) +-{ +- struct fcoe_softc *fc; +- +- fc = fcoe_softc(lp); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- __skb_queue_head(&fc->fcoe_pending_queue, skb); +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +-} +- +-/** +- * fcoe_insert_wait_queue - put the skb into fcoe pending queue tail +- * @lp: the fc_port for this skb +- * @skb: the associated skb to be xmitted +- * +- * Returns: none +- **/ +-static void fcoe_insert_wait_queue(struct fc_lport *lp, +- struct sk_buff *skb) +-{ +- struct fcoe_softc *fc; +- +- fc = fcoe_softc(lp); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- __skb_queue_tail(&fc->fcoe_pending_queue, skb); +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +-} +- +-/** + * fcoe_dev_setup - setup link change notification interface + * + **/ +@@ -1187,11 +1152,8 @@ void fcoe_clean_pending_queue(struct fc_lport *lp) + struct sk_buff *skb; + + spin_lock_bh(&fc->fcoe_pending_queue.lock); +- while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) + kfree_skb(skb); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- } + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + } + EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/fcoe-fix-kfree-skb.patch b/src/patches/suse-2.6.27.31/patches.drivers/fcoe-fix-kfree-skb.patch new file mode 100644 index 000000000..d4fc40859 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/fcoe-fix-kfree-skb.patch @@ -0,0 +1,34 @@ +From 032f92cd2f0a63f641e2157f9d26ae83fc35b791 Mon Sep 17 00:00:00 2001 +From: Roel Kluin +Date: Fri, 2 Jan 2009 04:50:00 -0800 +Subject: [PATCH] fcoe: fix kfree(skb) +References: bnc#473609 + + To: robert.w.love@intel.com, James Bottomley + + Cc: linux-scsi@vger.kernel.org + +Use kfree_skb instead of kfree for struct sk_buff pointers. + +Signed-off-by: Roel Kluin +Acked-by: John Jolly +--- + drivers/scsi/fcoe/libfcoe.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +index 9f8204b..ada3ebb 100644 +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -441,7 +441,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + if (skb_is_nonlinear(skb)) { + skb_frag_t *frag; + if (fcoe_get_paged_crc_eof(skb, tlen)) { +- kfree(skb); ++ kfree_skb(skb); + return -ENOMEM; + } + frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-abort-response.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-abort-response.patch new file mode 100644 index 000000000..61f403539 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-abort-response.patch @@ -0,0 +1,45 @@ +Subject: Fixup command response translation +From: Brian King +References: 459383 - LTC50695 + +If a link down event is received, outstanding commands may get +returned to the ibmvfc driver with a "transaction cancelled implicit" +response. This is currently translated to DID_ABORT, which does +not get retried by SCSI core, but rather passes the failure up +the stack. This can result in I/O errors at the filesystem level. +Fix up this response a well as a few other error responses. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -101,7 +101,7 @@ static const struct { + { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" }, +- { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_NO_CONNECT, 1, 1, "network down" }, ++ { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" }, +@@ -115,11 +115,11 @@ static const struct { + + { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" }, +- { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ABORT, 0, 1, "invalid parameter" }, +- { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ABORT, 0, 1, "missing parameter" }, ++ { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" }, ++ { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" }, +- { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, +- { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, ++ { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" }, ++ { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 0, 1, "transaction cancelled implicit" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-add_sync.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-add_sync.patch new file mode 100644 index 000000000..8912b3d4a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-add_sync.patch @@ -0,0 +1,26 @@ +Subject: Fix errors due to inconsistent command data +From: Brian J. King +References: 456654 - LTC50451 + +In order to ensure the VIOS sees a consistent command buffer, we +need to add a memory barrier after building the command buffer +but before sending the command. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -1381,6 +1381,8 @@ static int ibmvfc_send_event(struct ibmv + add_timer(&evt->timer); + } + ++ mb(); ++ + if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { + list_del(&evt->queue); + del_timer(&evt->timer); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-async-events-oops b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-async-events-oops new file mode 100644 index 000000000..e33ce6436 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc-async-events-oops @@ -0,0 +1,599 @@ +Subject: ibmvfc oops while processing async events +From: Brian King +Date: Thu Nov 20 13:43:45 2008 +0100: +References: bnc#445541 + +While running error injection (port disable/enable loop) during +I/O stress, the following oops occurred: + +cpu 0x0: Vector: 300 (Data Access) at [c00000000f4cbb10] + pc: d0000000000c5c44: .ibmvfc_interrupt+0x1a4/0x1f8 [ibmvfc] + lr: d0000000000c5c44: .ibmvfc_interrupt+0x1a4/0x1f8 [ibmvfc] + sp: c00000000f4cbd90 + msr: 8000000000009032 + dar: 0 + dsisr: 42000000 + current = 0xc00000001dee77a0 + paca = 0xc000000000a92c80 + +There is a window in the ibmvfc interrupt handler. If, while +processing an interrupt, after processing both the regular crq +and the async crq, an async event is added to the async crq, we +will oops when we process the async queue a second time, due to +an obvious bug in the code. + +Signed-off-by: Brian King +Acked-by: Hannes Reinecke + +--- + drivers/scsi/ibmvscsi/ibmvfc.c | 266 +++++++++++++++++++++++++++-------------- + drivers/scsi/ibmvscsi/ibmvfc.h | 26 ++-- + 2 files changed, 191 insertions(+), 101 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -121,6 +121,7 @@ static const struct { + { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, ++ { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, + + { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, +@@ -278,13 +279,6 @@ static int ibmvfc_get_err_result(struct + rsp->data.info.rsp_code)) + return DID_ERROR << 16; + +- if (!vfc_cmd->status) { +- if (rsp->flags & FCP_RESID_OVER) +- return rsp->scsi_status | (DID_ERROR << 16); +- else +- return rsp->scsi_status | (DID_OK << 16); +- } +- + err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); + if (err >= 0) + return rsp->scsi_status | (cmd_status[err].result << 16); +@@ -503,6 +497,7 @@ static void ibmvfc_set_host_action(struc + case IBMVFC_HOST_ACTION_INIT: + case IBMVFC_HOST_ACTION_TGT_DEL: + case IBMVFC_HOST_ACTION_QUERY_TGTS: ++ case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: + case IBMVFC_HOST_ACTION_TGT_ADD: + case IBMVFC_HOST_ACTION_NONE: + default: +@@ -765,6 +760,9 @@ static void ibmvfc_scsi_eh_done(struct i + cmnd->scsi_done(cmnd); + } + ++ if (evt->eh_comp) ++ complete(evt->eh_comp); ++ + ibmvfc_free_event(evt); + } + +@@ -1253,6 +1251,7 @@ static void ibmvfc_init_event(struct ibm + evt->sync_iu = NULL; + evt->crq.format = format; + evt->done = done; ++ evt->eh_comp = NULL; + } + + /** +@@ -1478,6 +1477,11 @@ static void ibmvfc_scsi_done(struct ibmv + sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; + if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) + memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); ++ if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) ++ ibmvfc_reinit_host(evt->vhost); ++ ++ if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) ++ cmnd->result = (DID_ERROR << 16); + + ibmvfc_log_error(evt); + } +@@ -1490,6 +1494,9 @@ static void ibmvfc_scsi_done(struct ibmv + cmnd->scsi_done(cmnd); + } + ++ if (evt->eh_comp) ++ complete(evt->eh_comp); ++ + ibmvfc_free_event(evt); + } + +@@ -1628,7 +1635,7 @@ static int ibmvfc_reset_device(struct sc + struct ibmvfc_host *vhost = shost_priv(sdev->host); + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct ibmvfc_cmd *tmf; +- struct ibmvfc_event *evt; ++ struct ibmvfc_event *evt = NULL; + union ibmvfc_iu rsp_iu; + struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; + int rsp_rc = -EBUSY; +@@ -1790,7 +1797,8 @@ static int ibmvfc_abort_task_set(struct + static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) + { + struct ibmvfc_host *vhost = shost_priv(sdev->host); +- struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); ++ struct scsi_target *starget = scsi_target(sdev); ++ struct fc_rport *rport = starget_to_rport(starget); + struct ibmvfc_tmf *tmf; + struct ibmvfc_event *evt, *found_evt; + union ibmvfc_iu rsp; +@@ -1828,7 +1836,7 @@ static int ibmvfc_cancel_all(struct scsi + int_to_scsilun(sdev->lun, &tmf->lun); + tmf->flags = (type | IBMVFC_TMF_LUA_VALID); + tmf->cancel_key = (unsigned long)sdev->hostdata; +- tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata); ++ tmf->my_cancel_key = (unsigned long)starget->hostdata; + + evt->sync_iu = &rsp; + init_completion(&evt->comp); +@@ -1860,6 +1868,91 @@ static int ibmvfc_cancel_all(struct scsi + } + + /** ++ * ibmvfc_match_target - Match function for specified target ++ * @evt: ibmvfc event struct ++ * @device: device to match (starget) ++ * ++ * Returns: ++ * 1 if event matches starget / 0 if event does not match starget ++ **/ ++static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) ++{ ++ if (evt->cmnd && scsi_target(evt->cmnd->device) == device) ++ return 1; ++ return 0; ++} ++ ++/** ++ * ibmvfc_match_lun - Match function for specified LUN ++ * @evt: ibmvfc event struct ++ * @device: device to match (sdev) ++ * ++ * Returns: ++ * 1 if event matches sdev / 0 if event does not match sdev ++ **/ ++static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) ++{ ++ if (evt->cmnd && evt->cmnd->device == device) ++ return 1; ++ return 0; ++} ++ ++/** ++ * ibmvfc_wait_for_ops - Wait for ops to complete ++ * @vhost: ibmvfc host struct ++ * @device: device to match (starget or sdev) ++ * @match: match function ++ * ++ * Returns: ++ * SUCCESS / FAILED ++ **/ ++static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, ++ int (*match) (struct ibmvfc_event *, void *)) ++{ ++ struct ibmvfc_event *evt; ++ DECLARE_COMPLETION_ONSTACK(comp); ++ int wait; ++ unsigned long flags; ++ signed long timeout = init_timeout * HZ; ++ ++ ENTER; ++ do { ++ wait = 0; ++ spin_lock_irqsave(vhost->host->host_lock, flags); ++ list_for_each_entry(evt, &vhost->sent, queue) { ++ if (match(evt, device)) { ++ evt->eh_comp = ∁ ++ wait++; ++ } ++ } ++ spin_unlock_irqrestore(vhost->host->host_lock, flags); ++ ++ if (wait) { ++ timeout = wait_for_completion_timeout(&comp, timeout); ++ ++ if (!timeout) { ++ wait = 0; ++ spin_lock_irqsave(vhost->host->host_lock, flags); ++ list_for_each_entry(evt, &vhost->sent, queue) { ++ if (match(evt, device)) { ++ evt->eh_comp = NULL; ++ wait++; ++ } ++ } ++ spin_unlock_irqrestore(vhost->host->host_lock, flags); ++ if (wait) ++ dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); ++ LEAVE; ++ return wait ? FAILED : SUCCESS; ++ } ++ } ++ } while (wait); ++ ++ LEAVE; ++ return SUCCESS; ++} ++ ++/** + * ibmvfc_eh_abort_handler - Abort a command + * @cmd: scsi command to abort + * +@@ -1868,29 +1961,21 @@ static int ibmvfc_cancel_all(struct scsi + **/ + static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) + { +- struct ibmvfc_host *vhost = shost_priv(cmd->device->host); +- struct ibmvfc_event *evt, *pos; ++ struct scsi_device *sdev = cmd->device; ++ struct ibmvfc_host *vhost = shost_priv(sdev->host); + int cancel_rc, abort_rc; +- unsigned long flags; ++ int rc = FAILED; + + ENTER; + ibmvfc_wait_while_resetting(vhost); +- cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET); +- abort_rc = ibmvfc_abort_task_set(cmd->device); ++ cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); ++ abort_rc = ibmvfc_abort_task_set(sdev); + +- if (!cancel_rc && !abort_rc) { +- spin_lock_irqsave(vhost->host->host_lock, flags); +- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { +- if (evt->cmnd && evt->cmnd->device == cmd->device) +- ibmvfc_fail_request(evt, DID_ABORT); +- } +- spin_unlock_irqrestore(vhost->host->host_lock, flags); +- LEAVE; +- return SUCCESS; +- } ++ if (!cancel_rc && !abort_rc) ++ rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); + + LEAVE; +- return FAILED; ++ return rc; + } + + /** +@@ -1902,29 +1987,21 @@ static int ibmvfc_eh_abort_handler(struc + **/ + static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) + { +- struct ibmvfc_host *vhost = shost_priv(cmd->device->host); +- struct ibmvfc_event *evt, *pos; ++ struct scsi_device *sdev = cmd->device; ++ struct ibmvfc_host *vhost = shost_priv(sdev->host); + int cancel_rc, reset_rc; +- unsigned long flags; ++ int rc = FAILED; + + ENTER; + ibmvfc_wait_while_resetting(vhost); +- cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET); +- reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN"); ++ cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); ++ reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); + +- if (!cancel_rc && !reset_rc) { +- spin_lock_irqsave(vhost->host->host_lock, flags); +- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { +- if (evt->cmnd && evt->cmnd->device == cmd->device) +- ibmvfc_fail_request(evt, DID_ABORT); +- } +- spin_unlock_irqrestore(vhost->host->host_lock, flags); +- LEAVE; +- return SUCCESS; +- } ++ if (!cancel_rc && !reset_rc) ++ rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); + + LEAVE; +- return FAILED; ++ return rc; + } + + /** +@@ -1960,31 +2037,23 @@ static void ibmvfc_dev_abort_all(struct + **/ + static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) + { +- struct ibmvfc_host *vhost = shost_priv(cmd->device->host); +- struct scsi_target *starget = scsi_target(cmd->device); +- struct ibmvfc_event *evt, *pos; ++ struct scsi_device *sdev = cmd->device; ++ struct ibmvfc_host *vhost = shost_priv(sdev->host); ++ struct scsi_target *starget = scsi_target(sdev); + int reset_rc; ++ int rc = FAILED; + unsigned long cancel_rc = 0; +- unsigned long flags; + + ENTER; + ibmvfc_wait_while_resetting(vhost); + starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); +- reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target"); ++ reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); + +- if (!cancel_rc && !reset_rc) { +- spin_lock_irqsave(vhost->host->host_lock, flags); +- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { +- if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) +- ibmvfc_fail_request(evt, DID_ABORT); +- } +- spin_unlock_irqrestore(vhost->host->host_lock, flags); +- LEAVE; +- return SUCCESS; +- } ++ if (!cancel_rc && !reset_rc) ++ rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); + + LEAVE; +- return FAILED; ++ return rc; + } + + /** +@@ -2014,23 +2083,18 @@ static void ibmvfc_terminate_rport_io(st + struct scsi_target *starget = to_scsi_target(&rport->dev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ibmvfc_host *vhost = shost_priv(shost); +- struct ibmvfc_event *evt, *pos; + unsigned long cancel_rc = 0; + unsigned long abort_rc = 0; +- unsigned long flags; ++ int rc = FAILED; + + ENTER; + starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); + starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); + +- if (!cancel_rc && !abort_rc) { +- spin_lock_irqsave(shost->host_lock, flags); +- list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { +- if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) +- ibmvfc_fail_request(evt, DID_ABORT); +- } +- spin_unlock_irqrestore(shost->host_lock, flags); +- } else ++ if (!cancel_rc && !abort_rc) ++ rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); ++ ++ if (rc == FAILED) + ibmvfc_issue_fc_host_lip(shost); + LEAVE; + } +@@ -2266,6 +2330,28 @@ static int ibmvfc_slave_alloc(struct scs + } + + /** ++ * ibmvfc_target_alloc - Setup the target's task set value ++ * @starget: struct scsi_target ++ * ++ * Set the target's task set value so that error handling works as ++ * expected. ++ * ++ * Returns: ++ * 0 on success / -ENXIO if device does not exist ++ **/ ++static int ibmvfc_target_alloc(struct scsi_target *starget) ++{ ++ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); ++ struct ibmvfc_host *vhost = shost_priv(shost); ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ starget->hostdata = (void *)(unsigned long)vhost->task_set++; ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ return 0; ++} ++ ++/** + * ibmvfc_slave_configure - Configure the device + * @sdev: struct scsi_device device to configure + * +@@ -2544,6 +2630,7 @@ static struct scsi_host_template driver_ + .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, + .slave_alloc = ibmvfc_slave_alloc, + .slave_configure = ibmvfc_slave_configure, ++ .target_alloc = ibmvfc_target_alloc, + .scan_finished = ibmvfc_scan_finished, + .change_queue_depth = ibmvfc_change_queue_depth, + .change_queue_type = ibmvfc_change_queue_type, +@@ -2640,7 +2727,7 @@ static irqreturn_t ibmvfc_interrupt(int + } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { + vio_disable_interrupts(vdev); + ibmvfc_handle_async(async, vhost); +- crq->valid = 0; ++ async->valid = 0; + } else + done = 1; + } +@@ -2711,6 +2798,8 @@ static void ibmvfc_tgt_prli_done(struct + rsp->status, rsp->error, status); + if (ibmvfc_retry_cmd(rsp->status, rsp->error)) + ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); ++ else ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + break; + }; + +@@ -2805,6 +2894,8 @@ static void ibmvfc_tgt_plogi_done(struct + + if (ibmvfc_retry_cmd(rsp->status, rsp->error)) + ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); ++ else ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + break; + }; + +@@ -3096,6 +3187,8 @@ static void ibmvfc_tgt_query_target_done + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) + ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); ++ else ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + break; + }; + +@@ -3426,6 +3519,7 @@ static int __ibmvfc_work_to_do(struct ib + case IBMVFC_HOST_ACTION_ALLOC_TGTS: + case IBMVFC_HOST_ACTION_TGT_ADD: + case IBMVFC_HOST_ACTION_TGT_DEL: ++ case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: + case IBMVFC_HOST_ACTION_QUERY: + default: + break; +@@ -3547,6 +3641,7 @@ static void ibmvfc_do_work(struct ibmvfc + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); + break; + case IBMVFC_HOST_ACTION_TGT_DEL: ++ case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: + list_for_each_entry(tgt, &vhost->targets, queue) { + if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { + tgt_dbg(tgt, "Deleting rport\n"); +@@ -3562,8 +3657,17 @@ static void ibmvfc_do_work(struct ibmvfc + } + + if (vhost->state == IBMVFC_INITIALIZING) { +- ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); +- vhost->job_step = ibmvfc_discover_targets; ++ if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { ++ ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); ++ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); ++ vhost->init_retries = 0; ++ spin_unlock_irqrestore(vhost->host->host_lock, flags); ++ scsi_unblock_requests(vhost->host); ++ return; ++ } else { ++ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); ++ vhost->job_step = ibmvfc_discover_targets; ++ } + } else { + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); + spin_unlock_irqrestore(vhost->host->host_lock, flags); +@@ -3586,14 +3690,8 @@ static void ibmvfc_do_work(struct ibmvfc + } + } + +- if (!ibmvfc_dev_init_to_do(vhost)) { +- ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); +- ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); +- vhost->init_retries = 0; +- spin_unlock_irqrestore(vhost->host->host_lock, flags); +- scsi_unblock_requests(vhost->host); +- return; +- } ++ if (!ibmvfc_dev_init_to_do(vhost)) ++ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); + break; + case IBMVFC_HOST_ACTION_TGT_ADD: + list_for_each_entry(tgt, &vhost->targets, queue) { +@@ -3601,16 +3699,6 @@ static void ibmvfc_do_work(struct ibmvfc + spin_unlock_irqrestore(vhost->host->host_lock, flags); + ibmvfc_tgt_add_rport(tgt); + return; +- } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { +- tgt_dbg(tgt, "Deleting rport\n"); +- rport = tgt->rport; +- tgt->rport = NULL; +- list_del(&tgt->queue); +- spin_unlock_irqrestore(vhost->host->host_lock, flags); +- if (rport) +- fc_remote_port_delete(rport); +- kref_put(&tgt->kref, ibmvfc_release_tgt); +- return; + } + } + +--- a/drivers/scsi/ibmvscsi/ibmvfc.h ++++ b/drivers/scsi/ibmvscsi/ibmvfc.h +@@ -29,8 +29,8 @@ + #include "viosrp.h" + + #define IBMVFC_NAME "ibmvfc" +-#define IBMVFC_DRIVER_VERSION "1.0.2" +-#define IBMVFC_DRIVER_DATE "(August 14, 2008)" ++#define IBMVFC_DRIVER_VERSION "1.0.4" ++#define IBMVFC_DRIVER_DATE "(November 14, 2008)" + + #define IBMVFC_DEFAULT_TIMEOUT 15 + #define IBMVFC_INIT_TIMEOUT 120 +@@ -110,6 +110,7 @@ enum ibmvfc_vios_errors { + IBMVFC_TRANS_CANCELLED = 0x0006, + IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007, + IBMVFC_INSUFFICIENT_RESOURCE = 0x0008, ++ IBMVFC_PLOGI_REQUIRED = 0x0010, + IBMVFC_COMMAND_FAILED = 0x8000, + }; + +@@ -338,7 +339,6 @@ struct ibmvfc_tmf { + #define IBMVFC_TMF_LUA_VALID 0x40 + u32 cancel_key; + u32 my_cancel_key; +-#define IBMVFC_TMF_CANCEL_KEY 0x80000000 + u32 pad; + u64 reserved[2]; + }__attribute__((packed, aligned (8))); +@@ -525,10 +525,10 @@ enum ibmvfc_async_event { + }; + + struct ibmvfc_crq { +- u8 valid; +- u8 format; ++ volatile u8 valid; ++ volatile u8 format; + u8 reserved[6]; +- u64 ioba; ++ volatile u64 ioba; + }__attribute__((packed, aligned (8))); + + struct ibmvfc_crq_queue { +@@ -538,13 +538,13 @@ struct ibmvfc_crq_queue { + }; + + struct ibmvfc_async_crq { +- u8 valid; ++ volatile u8 valid; + u8 pad[3]; + u32 pad2; +- u64 event; +- u64 scsi_id; +- u64 wwpn; +- u64 node_name; ++ volatile u64 event; ++ volatile u64 scsi_id; ++ volatile u64 wwpn; ++ volatile u64 node_name; + u64 reserved; + }__attribute__((packed, aligned (8))); + +@@ -607,6 +607,7 @@ struct ibmvfc_event { + struct srp_direct_buf *ext_list; + dma_addr_t ext_list_token; + struct completion comp; ++ struct completion *eh_comp; + struct timer_list timer; + }; + +@@ -627,6 +628,7 @@ enum ibmvfc_host_action { + IBMVFC_HOST_ACTION_TGT_DEL, + IBMVFC_HOST_ACTION_ALLOC_TGTS, + IBMVFC_HOST_ACTION_TGT_INIT, ++ IBMVFC_HOST_ACTION_TGT_DEL_FAILED, + IBMVFC_HOST_ACTION_TGT_ADD, + }; + +@@ -702,7 +704,7 @@ struct ibmvfc_host { + + #define ibmvfc_log(vhost, level, ...) \ + do { \ +- if (level >= (vhost)->log_level) \ ++ if ((vhost)->log_level >= level) \ + dev_err((vhost)->dev, ##__VA_ARGS__); \ + } while (0) + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_class3.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_class3.patch new file mode 100644 index 000000000..c988be16e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_class3.patch @@ -0,0 +1,30 @@ +Subject: Fix command timeout errors +From: Brian King +References: 472645 - LTC51429 + +Currently the ibmvfc driver sets the IBMVFC_CLASS_3_ERR flag +in the VFC Frame if both the adapter and the device claim support +for Class 3. However, this bit actually refers to Class 3 Error +Recovery, which is currently not supported by the VIOS. Setting this +bit can cause lots of command timeout responses from the VIOS resulting +in general instability. Fix this by never setting this bit. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -1571,9 +1571,6 @@ static int ibmvfc_queuecommand(struct sc + vfc_cmd->resp_len = sizeof(vfc_cmd->rsp); + vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata; + vfc_cmd->tgt_scsi_id = rport->port_id; +- if ((rport->supported_classes & FC_COS_CLASS3) && +- (fc_host_supported_classes(vhost->host) & FC_COS_CLASS3)) +- vfc_cmd->flags = IBMVFC_CLASS_3_ERR; + vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd); + int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); + memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_default_timeout.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_default_timeout.patch new file mode 100644 index 000000000..45e09332f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_default_timeout.patch @@ -0,0 +1,28 @@ +Subject: Increase cancel timeout +From: Brian King +References: 472645 - LTC51429 + +During cancel testing it has been shown that 15 seconds is not +nearly long enough for the VIOS to respond to a cancel under +loaded situations. Increasing this timeout to 60 seconds allows +time for the VIOS to cancel the outstanding commands and prevents +us from escalating to a full host reset, which can take much longer. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.h ++++ b/drivers/scsi/ibmvscsi/ibmvfc.h +@@ -32,7 +32,7 @@ + #define IBMVFC_DRIVER_VERSION "1.0.4" + #define IBMVFC_DRIVER_DATE "(November 14, 2008)" + +-#define IBMVFC_DEFAULT_TIMEOUT 15 ++#define IBMVFC_DEFAULT_TIMEOUT 60 + #define IBMVFC_INIT_TIMEOUT 120 + #define IBMVFC_MAX_REQUESTS_DEFAULT 100 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_prli_initiator_fix.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_prli_initiator_fix.patch new file mode 100644 index 000000000..fc4e0b722 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_prli_initiator_fix.patch @@ -0,0 +1,111 @@ +Subject: Better handle other FC initiators +From: Brian King +References: 471217 - LTC51238 + +The ibmvfc driver currently always sets the role of all rports +to FC_PORT_ROLE_FCP_TARGET, which is not correct for other initiators. +This can cause problems if other initiators are on the fabric +when we then try to scan the rport for LUNs. Fix this by looking +at the service parameters returned in the PRLI to set the roles +appropriately. Also look at the returned service parameters to +decide whether or not we were actually able to successfully log into +the target. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.c | 62 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 58 insertions(+), 4 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -2768,6 +2768,40 @@ static void ibmvfc_retry_tgt_init(struct + ibmvfc_init_tgt(tgt, job_step); + } + ++/* Defined in FC-LS */ ++static const struct { ++ int code; ++ int retry; ++ int logged_in; ++} prli_rsp [] = { ++ { 0, 1, 0 }, ++ { 1, 0, 1 }, ++ { 2, 1, 0 }, ++ { 3, 1, 0 }, ++ { 4, 0, 0 }, ++ { 5, 0, 0 }, ++ { 6, 0, 1 }, ++ { 7, 0, 0 }, ++ { 8, 1, 0 }, ++}; ++ ++/** ++ * ibmvfc_get_prli_rsp - Find PRLI response index ++ * @flags: PRLI response flags ++ * ++ **/ ++static int ibmvfc_get_prli_rsp(u16 flags) ++{ ++ int i; ++ int code = (flags & 0x0f00) >> 8; ++ ++ for (i = 0; i < ARRAY_SIZE(prli_rsp); i++) ++ if (prli_rsp[i].code == code) ++ return i; ++ ++ return 0; ++} ++ + /** + * ibmvfc_tgt_prli_done - Completion handler for Process Login + * @evt: ibmvfc event struct +@@ -2778,15 +2812,36 @@ static void ibmvfc_tgt_prli_done(struct + struct ibmvfc_target *tgt = evt->tgt; + struct ibmvfc_host *vhost = evt->vhost; + struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; ++ struct ibmvfc_prli_svc_parms *parms = &rsp->parms; + u32 status = rsp->common.status; ++ int index; + + vhost->discovery_threads--; + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); + switch (status) { + case IBMVFC_MAD_SUCCESS: +- tgt_dbg(tgt, "Process Login succeeded\n"); +- tgt->need_login = 0; +- ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); ++ tgt_dbg(tgt, "Process Login succeeded: %X %02X %04X\n", ++ parms->type, parms->flags, parms->service_parms); ++ ++ if (parms->type == IBMVFC_SCSI_FCP_TYPE) { ++ index = ibmvfc_get_prli_rsp(parms->flags); ++ if (prli_rsp[index].logged_in) { ++ if (parms->flags & IBMVFC_PRLI_EST_IMG_PAIR) { ++ tgt->need_login = 0; ++ tgt->ids.roles = 0; ++ if (parms->service_parms & IBMVFC_PRLI_TARGET_FUNC) ++ tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET; ++ if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC) ++ tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); ++ } else ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ++ } else if (prli_rsp[index].retry) ++ ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); ++ else ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); ++ } else ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); + break; + case IBMVFC_MAD_DRIVER_FAILED: + break; +@@ -2875,7 +2930,6 @@ static void ibmvfc_tgt_plogi_done(struct + tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); + tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); + tgt->ids.port_id = tgt->scsi_id; +- tgt->ids.roles = FC_PORT_ROLE_FCP_TARGET; + memcpy(&tgt->service_parms, &rsp->service_parms, + sizeof(tgt->service_parms)); + memcpy(&tgt->service_parms_change, &rsp->service_parms_change, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_relogin_fix.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_relogin_fix.patch new file mode 100644 index 000000000..5a45fabf4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_relogin_fix.patch @@ -0,0 +1,50 @@ +Subject: Fix rport relogin +From: Brian King +References: 472645 - LTC51429 + +The ibmvfc driver has a bug in its SCN handling. If it receives +an ELS event such asn an N-Port SCN event or an unsolicited PLOGI, +or any other SCN event which causes ibmvfc_reinit_host to be called, +it is possible that we will call fc_remote_port_add for a target +that already has an rport added, which can result in duplicate +rports getting created for the same targets. Fix this by calling +fc_remote_port_rolechg in this scenario instead to report any possible +role change that may have occurred. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -3315,6 +3315,7 @@ static int ibmvfc_alloc_target(struct ib + return -ENOMEM; + } + ++ memset(tgt, 0, sizeof(*tgt)); + tgt->scsi_id = scsi_id; + tgt->new_scsi_id = scsi_id; + tgt->vhost = vhost; +@@ -3625,9 +3626,18 @@ static void ibmvfc_log_ae(struct ibmvfc_ + static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) + { + struct ibmvfc_host *vhost = tgt->vhost; +- struct fc_rport *rport; ++ struct fc_rport *rport = tgt->rport; + unsigned long flags; + ++ if (rport) { ++ tgt_dbg(tgt, "Setting rport roles\n"); ++ fc_remote_port_rolechg(rport, tgt->ids.roles); ++ spin_lock_irqsave(vhost->host->host_lock, flags); ++ ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); ++ spin_unlock_irqrestore(vhost->host->host_lock, flags); ++ return; ++ } ++ + tgt_dbg(tgt, "Adding rport\n"); + rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); + spin_lock_irqsave(vhost->host->host_lock, flags); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_tasklet.patch b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_tasklet.patch new file mode 100644 index 000000000..d10fa8169 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ibmvfc_tasklet.patch @@ -0,0 +1,98 @@ +Subject: Fix dropped interrupts +From: Brian King +References: 473115 - LTC51485 + +This patch fixes a problem of possible dropped interrupts. Currently, the ibmvfc +driver has a race condition where after ibmvfc_interrupt gets run, the platform +code clears the interrupt. This can result in lost interrupts and, in worst case +scenarios, result in command timeouts. Fix this by implementing a tasklet +similar to what the ibmvscsi driver does so that interrupt processing is no longer +done in the actual interrupt handler, which eliminates the race. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering +--- + + drivers/scsi/ibmvscsi/ibmvfc.c | 25 +++++++++++++++++++++++-- + drivers/scsi/ibmvscsi/ibmvfc.h | 1 + + 2 files changed, 24 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -640,6 +640,7 @@ static void ibmvfc_release_crq_queue(str + + ibmvfc_dbg(vhost, "Releasing CRQ\n"); + free_irq(vdev->irq, vhost); ++ tasklet_kill(&vhost->tasklet); + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); +@@ -2697,6 +2698,25 @@ static struct ibmvfc_crq *ibmvfc_next_cr + static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) + { + struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; ++ unsigned long flags; ++ ++ spin_lock_irqsave(vhost->host->host_lock, flags); ++ vio_disable_interrupts(to_vio_dev(vhost->dev)); ++ tasklet_schedule(&vhost->tasklet); ++ spin_unlock_irqrestore(vhost->host->host_lock, flags); ++ return IRQ_HANDLED; ++} ++ ++/** ++ * ibmvfc_tasklet - Interrupt handler tasklet ++ * @data: ibmvfc host struct ++ * ++ * Returns: ++ * Nothing ++ **/ ++static void ibmvfc_tasklet(void *data) ++{ ++ struct ibmvfc_host *vhost = data; + struct vio_dev *vdev = to_vio_dev(vhost->dev); + struct ibmvfc_crq *crq; + struct ibmvfc_async_crq *async; +@@ -2704,7 +2724,6 @@ static irqreturn_t ibmvfc_interrupt(int + int done = 0; + + spin_lock_irqsave(vhost->host->host_lock, flags); +- vio_disable_interrupts(to_vio_dev(vhost->dev)); + while (!done) { + /* Pull all the valid messages off the CRQ */ + while ((crq = ibmvfc_next_crq(vhost)) != NULL) { +@@ -2732,7 +2751,6 @@ static irqreturn_t ibmvfc_interrupt(int + } + + spin_unlock_irqrestore(vhost->host->host_lock, flags); +- return IRQ_HANDLED; + } + + /** +@@ -3857,6 +3875,8 @@ static int ibmvfc_init_crq(struct ibmvfc + + retrc = 0; + ++ tasklet_init(&vhost->tasklet, (void *)ibmvfc_tasklet, (unsigned long)vhost); ++ + if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { + dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); + goto req_irq_failed; +@@ -3872,6 +3892,7 @@ static int ibmvfc_init_crq(struct ibmvfc + return retrc; + + req_irq_failed: ++ tasklet_kill(&vhost->tasklet); + do { + rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); + } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); +--- a/drivers/scsi/ibmvscsi/ibmvfc.h ++++ b/drivers/scsi/ibmvscsi/ibmvfc.h +@@ -684,6 +684,7 @@ struct ibmvfc_host { + char partition_name[97]; + void (*job_step) (struct ibmvfc_host *); + struct task_struct *work_thread; ++ struct tasklet_struct tasklet; + wait_queue_head_t init_wait_q; + wait_queue_head_t work_wait_q; + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ide-tape-flags-fix.patch b/src/patches/suse-2.6.27.31/patches.drivers/ide-tape-flags-fix.patch new file mode 100644 index 000000000..5e487983b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ide-tape-flags-fix.patch @@ -0,0 +1,181 @@ +From 49d8078ad1c3dca5b11ce18391bf6bd9af9acdf5 Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Sun, 7 Jun 2009 15:37:06 +0200 +Subject: ide-tape: fix IDE_AFLAG_* atomic accesses +Patch-mainline: yes +References: bnc#509071 + +These flags used to be bit numbers and now are single bits in the +->atapi_flags vector. Use them properly. + +Spotted-by: Jiri Slaby +Signed-off-by: Borislav Petkov +Signed-off-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Jiri Slaby +--- + drivers/ide/ide-tape.c | 44 ++++++++++++++++++++++++++------------------ + 1 file changed, 26 insertions(+), 18 deletions(-) + +--- a/drivers/ide/ide-tape.c ++++ b/drivers/ide/ide-tape.c +@@ -652,7 +652,8 @@ static void ide_tape_callback(ide_drive_ + if (readpos[0] & 0x4) { + printk(KERN_INFO "ide-tape: Block location is unknown" + "to the tape\n"); +- clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), ++ &drive->atapi_flags); + uptodate = 0; + } else { + debug_log(DBG_SENSE, "Block Location - %u\n", +@@ -660,7 +661,8 @@ static void ide_tape_callback(ide_drive_ + + tape->partition = readpos[1]; + tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]); +- set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags); ++ set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), ++ &drive->atapi_flags); + } + } + +@@ -1294,7 +1296,7 @@ static int idetape_wait_ready(ide_drive_ + int load_attempted = 0; + + /* Wait for the tape to become ready */ +- set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags); ++ set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags); + timeout += jiffies; + while (time_before(jiffies, timeout)) { + idetape_create_test_unit_ready_cmd(&pc); +@@ -1387,7 +1389,7 @@ static void __ide_tape_discard_merge_buf + if (tape->chrdev_dir != IDETAPE_DIR_READ) + return; + +- clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags); + tape->merge_bh_size = 0; + if (tape->merge_bh != NULL) { + ide_tape_kfree_buffer(tape); +@@ -1626,7 +1628,7 @@ static int idetape_add_chrdev_read_reque + debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks); + + /* If we are at a filemark, return a read length of 0 */ +- if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) ++ if (test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) + return 0; + + idetape_init_read(drive); +@@ -1736,7 +1738,8 @@ static int idetape_space_over_filemarks( + + if (tape->chrdev_dir == IDETAPE_DIR_READ) { + tape->merge_bh_size = 0; +- if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) ++ if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK), ++ &drive->atapi_flags)) + ++count; + ide_tape_discard_merge_buffer(drive, 0); + } +@@ -1791,7 +1794,7 @@ static ssize_t idetape_chrdev_read(struc + debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); + + if (tape->chrdev_dir != IDETAPE_DIR_READ) { +- if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags)) ++ if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags)) + if (count > tape->blk_size && + (count % tape->blk_size) == 0) + tape->user_bs_factor = count / tape->blk_size; +@@ -1831,7 +1834,8 @@ static ssize_t idetape_chrdev_read(struc + tape->merge_bh_size = bytes_read-temp; + } + finish: +- if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) { ++ if (!actually_read && test_bit(ilog2(IDE_AFLAG_FILEMARK), ++ &drive->atapi_flags)) { + debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name); + + idetape_space_over_filemarks(drive, MTFSF, 1); +@@ -2017,7 +2021,8 @@ static int idetape_mtioctop(ide_drive_t + !IDETAPE_LU_LOAD_MASK); + retval = idetape_queue_pc_tail(drive, &pc); + if (!retval) +- clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), ++ &drive->atapi_flags); + return retval; + case MTNOP: + ide_tape_discard_merge_buffer(drive, 0); +@@ -2040,9 +2045,11 @@ static int idetape_mtioctop(ide_drive_t + mt_count % tape->blk_size) + return -EIO; + tape->user_bs_factor = mt_count / tape->blk_size; +- clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_DETECT_BS), ++ &drive->atapi_flags); + } else +- set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags); ++ set_bit(ilog2(IDE_AFLAG_DETECT_BS), ++ &drive->atapi_flags); + return 0; + case MTSEEK: + ide_tape_discard_merge_buffer(drive, 0); +@@ -2192,20 +2199,20 @@ static int idetape_chrdev_open(struct in + + filp->private_data = tape; + +- if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) { ++ if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) { + retval = -EBUSY; + goto out_put_tape; + } + + retval = idetape_wait_ready(drive, 60 * HZ); + if (retval) { +- clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); + printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); + goto out_put_tape; + } + + idetape_read_position(drive); +- if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags)) ++ if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags)) + (void)idetape_rewind_tape(drive); + + /* Read block size and write protect status from drive. */ +@@ -2221,7 +2228,7 @@ static int idetape_chrdev_open(struct in + if (tape->write_prot) { + if ((filp->f_flags & O_ACCMODE) == O_WRONLY || + (filp->f_flags & O_ACCMODE) == O_RDWR) { +- clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); + retval = -EROFS; + goto out_put_tape; + } +@@ -2281,7 +2288,8 @@ static int idetape_chrdev_release(struct + ide_tape_discard_merge_buffer(drive, 1); + } + +- if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags)) ++ if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), ++ &drive->atapi_flags)) + (void) idetape_rewind_tape(drive); + if (tape->chrdev_dir == IDETAPE_DIR_NONE) { + if (tape->door_locked == DOOR_LOCKED) { +@@ -2291,7 +2299,7 @@ static int idetape_chrdev_release(struct + } + } + } +- clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags); ++ clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); + ide_tape_put(tape); + unlock_kernel(); + return 0; +@@ -2476,7 +2484,7 @@ static void idetape_setup(ide_drive_t *d + + /* Command packet DRQ type */ + if (((gcw[0] & 0x60) >> 5) == 1) +- set_bit(IDE_AFLAG_DRQ_INTERRUPT, &drive->atapi_flags); ++ set_bit(ilog2(IDE_AFLAG_DRQ_INTERRUPT), &drive->atapi_flags); + + idetape_get_inquiry_results(drive); + idetape_get_mode_sense_results(drive); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ide-tape-ignore_dsc-flags-fix.patch b/src/patches/suse-2.6.27.31/patches.drivers/ide-tape-ignore_dsc-flags-fix.patch new file mode 100644 index 000000000..63a6cc162 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ide-tape-ignore_dsc-flags-fix.patch @@ -0,0 +1,59 @@ +From 626542ca2277961aaa64855206574f8ca4f360e3 Mon Sep 17 00:00:00 2001 +From: Borislav Petkov +Date: Sun, 7 Jun 2009 15:37:05 +0200 +Subject: ide-tape: change IDE_AFLAG_IGNORE_DSC non-atomically +Patch-mainline: yes +References: bnc#509071 + +There are two sites where the flag is being changed: ide_retry_pc +and idetape_do_request. Both codepaths are protected by hwif->busy +(ide_lock_port) and therefore we shouldn't need the atomic accesses. + +Spotted-by: Jiri Slaby +Signed-off-by: Borislav Petkov +Signed-off-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Jiri Slaby +--- + drivers/ide/ide-tape.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/drivers/ide/ide-tape.c ++++ b/drivers/ide/ide-tape.c +@@ -736,7 +736,7 @@ static void idetape_retry_pc(ide_drive_t + pc = idetape_next_pc_storage(drive); + rq = idetape_next_rq_storage(drive); + idetape_create_request_sense_cmd(pc); +- set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); ++ drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; + idetape_queue_pc_head(drive, pc, rq); + } + +@@ -1013,14 +1013,14 @@ static ide_startstop_t idetape_do_reques + stat = hwif->tp_ops->read_status(hwif); + + if (!drive->dsc_overlap && !(rq->cmd[13] & REQ_IDETAPE_PC2)) +- set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); ++ drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; + + if (drive->post_reset == 1) { +- set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); ++ drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; + drive->post_reset = 0; + } + +- if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) && ++ if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) && + (stat & SEEK_STAT) == 0) { + if (postponed_rq == NULL) { + tape->dsc_polling_start = jiffies; +@@ -1041,7 +1041,9 @@ static ide_startstop_t idetape_do_reques + tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW; + idetape_postpone_request(drive); + return ide_stopped; +- } ++ } else ++ drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC; ++ + if (rq->cmd[13] & REQ_IDETAPE_READ) { + pc = idetape_next_pc_storage(drive); + ide_tape_create_rw_cmd(tape, pc, rq, READ_6); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/igp-fix-ring-on-suspend.patch b/src/patches/suse-2.6.27.31/patches.drivers/igp-fix-ring-on-suspend.patch new file mode 100644 index 000000000..97163ce92 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/igp-fix-ring-on-suspend.patch @@ -0,0 +1,261 @@ +Subject: Fix tx/rx_ring_count parameters for igb on suspend/resume/ring resize +Patch-mainline: 2.6.29-rc3 +References: bnc#465049 +From: Alexander Duyck + +When suspending the device the ring structure is freed which causes it to +loose track of the count. To resolve this we need to move the ring count +outside of the ring structure and store it in the adapter struct. + +In addition to resolving the suspend/resume issue this patch also addresses +issues seen in the event of memory allocation errors causing uneven ring +sizes on multiple queues. + +Signed-off-by: Alexander Duyck +Signed-off-by: Jeff Kirsher +Signed-off-by: David S. Miller +Signed-off-by: Pavel Machek + + + +--- + drivers/net/igb/igb.h | 4 + + drivers/net/igb/igb_ethtool.c | 102 ++++++++++++++++++++---------------------- + drivers/net/igb/igb_main.c | 10 ++-- + 3 files changed, 59 insertions(+), 57 deletions(-) + +--- a/drivers/net/igb/igb_ethtool.c ++++ b/drivers/net/igb/igb_ethtool.c +@@ -714,15 +714,13 @@ static void igb_get_ringparam(struct net + struct ethtool_ringparam *ring) + { + struct igb_adapter *adapter = netdev_priv(netdev); +- struct igb_ring *tx_ring = adapter->tx_ring; +- struct igb_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = IGB_MAX_RXD; + ring->tx_max_pending = IGB_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; +- ring->rx_pending = rx_ring->count; +- ring->tx_pending = tx_ring->count; ++ ring->rx_pending = adapter->rx_ring_count; ++ ring->tx_pending = adapter->tx_ring_count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; + } +@@ -731,12 +729,9 @@ static int igb_set_ringparam(struct net_ + struct ethtool_ringparam *ring) + { + struct igb_adapter *adapter = netdev_priv(netdev); +- struct igb_buffer *old_buf; +- struct igb_buffer *old_rx_buf; +- void *old_desc; ++ struct igb_ring *temp_ring; + int i, err; +- u32 new_rx_count, new_tx_count, old_size; +- dma_addr_t old_dma; ++ u32 new_rx_count, new_tx_count; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; +@@ -749,12 +744,19 @@ static int igb_set_ringparam(struct net_ + new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD); + new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); + +- if ((new_tx_count == adapter->tx_ring->count) && +- (new_rx_count == adapter->rx_ring->count)) { ++ if ((new_tx_count == adapter->tx_ring_count) && ++ (new_rx_count == adapter->rx_ring_count)) { + /* nothing to do */ + return 0; + } + ++ if (adapter->num_tx_queues > adapter->num_rx_queues) ++ temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring)); ++ else ++ temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring)); ++ if (!temp_ring) ++ return -ENOMEM; ++ + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) + msleep(1); + +@@ -766,62 +768,55 @@ static int igb_set_ringparam(struct net_ + * because the ISRs in MSI-X mode get passed pointers + * to the tx and rx ring structs. + */ +- if (new_tx_count != adapter->tx_ring->count) { ++ if (new_tx_count != adapter->tx_ring_count) { ++ memcpy(temp_ring, adapter->tx_ring, ++ adapter->num_tx_queues * sizeof(struct igb_ring)); ++ + for (i = 0; i < adapter->num_tx_queues; i++) { +- /* Save existing descriptor ring */ +- old_buf = adapter->tx_ring[i].buffer_info; +- old_desc = adapter->tx_ring[i].desc; +- old_size = adapter->tx_ring[i].size; +- old_dma = adapter->tx_ring[i].dma; +- /* Try to allocate a new one */ +- adapter->tx_ring[i].buffer_info = NULL; +- adapter->tx_ring[i].desc = NULL; +- adapter->tx_ring[i].count = new_tx_count; +- err = igb_setup_tx_resources(adapter, +- &adapter->tx_ring[i]); ++ temp_ring[i].count = new_tx_count; ++ err = igb_setup_tx_resources(adapter, &temp_ring[i]); + if (err) { +- /* Restore the old one so at least +- the adapter still works, even if +- we failed the request */ +- adapter->tx_ring[i].buffer_info = old_buf; +- adapter->tx_ring[i].desc = old_desc; +- adapter->tx_ring[i].size = old_size; +- adapter->tx_ring[i].dma = old_dma; ++ while (i) { ++ i--; ++ igb_free_tx_resources(&temp_ring[i]); ++ } + goto err_setup; + } +- /* Free the old buffer manually */ +- vfree(old_buf); +- pci_free_consistent(adapter->pdev, old_size, +- old_desc, old_dma); + } ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) ++ igb_free_tx_resources(&adapter->tx_ring[i]); ++ ++ memcpy(adapter->tx_ring, temp_ring, ++ adapter->num_tx_queues * sizeof(struct igb_ring)); ++ ++ adapter->tx_ring_count = new_tx_count; + } + + if (new_rx_count != adapter->rx_ring->count) { +- for (i = 0; i < adapter->num_rx_queues; i++) { ++ memcpy(temp_ring, adapter->rx_ring, ++ adapter->num_rx_queues * sizeof(struct igb_ring)); + +- old_rx_buf = adapter->rx_ring[i].buffer_info; +- old_desc = adapter->rx_ring[i].desc; +- old_size = adapter->rx_ring[i].size; +- old_dma = adapter->rx_ring[i].dma; +- +- adapter->rx_ring[i].buffer_info = NULL; +- adapter->rx_ring[i].desc = NULL; +- adapter->rx_ring[i].dma = 0; +- adapter->rx_ring[i].count = new_rx_count; +- err = igb_setup_rx_resources(adapter, +- &adapter->rx_ring[i]); ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ temp_ring[i].count = new_rx_count; ++ err = igb_setup_rx_resources(adapter, &temp_ring[i]); + if (err) { +- adapter->rx_ring[i].buffer_info = old_rx_buf; +- adapter->rx_ring[i].desc = old_desc; +- adapter->rx_ring[i].size = old_size; +- adapter->rx_ring[i].dma = old_dma; ++ while (i) { ++ i--; ++ igb_free_rx_resources(&temp_ring[i]); ++ } + goto err_setup; + } + +- vfree(old_rx_buf); +- pci_free_consistent(adapter->pdev, old_size, old_desc, +- old_dma); + } ++ ++ for (i = 0; i < adapter->num_rx_queues; i++) ++ igb_free_rx_resources(&adapter->rx_ring[i]); ++ ++ memcpy(adapter->rx_ring, temp_ring, ++ adapter->num_rx_queues * sizeof(struct igb_ring)); ++ ++ adapter->rx_ring_count = new_rx_count; + } + + err = 0; +@@ -830,6 +825,7 @@ err_setup: + igb_up(adapter); + + clear_bit(__IGB_RESETTING, &adapter->state); ++ vfree(temp_ring); + return err; + } + +--- a/drivers/net/igb/igb.h ++++ b/drivers/net/igb/igb.h +@@ -294,6 +294,8 @@ struct igb_adapter { + unsigned int lro_flushed; + unsigned int lro_no_desc; + #endif ++ unsigned int tx_ring_count; ++ unsigned int rx_ring_count; + }; + + #define IGB_FLAG_HAS_MSI (1 << 0) +@@ -325,6 +327,8 @@ extern void igb_reset(struct igb_adapter + extern int igb_set_spd_dplx(struct igb_adapter *, u16); + extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *); + extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *); ++extern void igb_free_tx_resources(struct igb_ring *); ++extern void igb_free_rx_resources(struct igb_ring *); + extern void igb_update_stats(struct igb_adapter *); + extern void igb_set_ethtool_ops(struct net_device *); + +--- a/drivers/net/igb/igb_main.c ++++ b/drivers/net/igb/igb_main.c +@@ -75,8 +75,6 @@ static int igb_setup_all_tx_resources(st + static int igb_setup_all_rx_resources(struct igb_adapter *); + static void igb_free_all_tx_resources(struct igb_adapter *); + static void igb_free_all_rx_resources(struct igb_adapter *); +-static void igb_free_tx_resources(struct igb_ring *); +-static void igb_free_rx_resources(struct igb_ring *); + void igb_update_stats(struct igb_adapter *); + static int igb_probe(struct pci_dev *, const struct pci_device_id *); + static void __devexit igb_remove(struct pci_dev *pdev); +@@ -258,11 +256,13 @@ static int igb_alloc_queues(struct igb_a + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *ring = &(adapter->tx_ring[i]); ++ ring->count = adapter->tx_ring_count; + ring->adapter = adapter; + ring->queue_index = i; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igb_ring *ring = &(adapter->rx_ring[i]); ++ ring->count = adapter->rx_ring_count; + ring->adapter = adapter; + ring->queue_index = i; + ring->itr_register = E1000_ITR; +@@ -1374,6 +1374,8 @@ static int __devinit igb_sw_init(struct + + pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + ++ adapter->tx_ring_count = IGB_DEFAULT_TXD; ++ adapter->rx_ring_count = IGB_DEFAULT_RXD; + adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; + adapter->rx_ps_hdr_size = 0; /* disable packet split */ + adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; +@@ -1962,7 +1964,7 @@ static void igb_configure_rx(struct igb_ + * + * Free all transmit software resources + **/ +-static void igb_free_tx_resources(struct igb_ring *tx_ring) ++void igb_free_tx_resources(struct igb_ring *tx_ring) + { + struct pci_dev *pdev = tx_ring->adapter->pdev; + +@@ -2062,7 +2064,7 @@ static void igb_clean_all_tx_rings(struc + * + * Free all receive software resources + **/ +-static void igb_free_rx_resources(struct igb_ring *rx_ring) ++void igb_free_rx_resources(struct igb_ring *rx_ring) + { + struct pci_dev *pdev = rx_ring->adapter->pdev; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/input-usbtouchscreen-hw-calibration.patch b/src/patches/suse-2.6.27.31/patches.drivers/input-usbtouchscreen-hw-calibration.patch new file mode 100644 index 000000000..8fcbab5de --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/input-usbtouchscreen-hw-calibration.patch @@ -0,0 +1,61 @@ +From: Dan Streetman +Subject: Input: usbtouchscreen - allow reporting calibrated data +Patch-mainline: queued in input tree, will be in 2.6.29 +References: bnc#444814 + +Input: usbtouchscreen - allow reporting calibrated data + +This patch adds a module parameter to report either the raw +coordinate data or the hardware-calibrated coordinate data for +MicroTouch/3M touchscreens. The default is set to the raw +coordinates for backwards compatibilty. + +Signed-off-by: Dan Streetman +Signed-off-by: Dmitry Torokhov +Signed-off-by: Jiri Kosina +--- + +diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c +index 5080b26..6d27a1d 100644 +--- a/drivers/input/touchscreen/usbtouchscreen.c ++++ b/drivers/input/touchscreen/usbtouchscreen.c +@@ -60,6 +60,10 @@ static int swap_xy; + module_param(swap_xy, bool, 0644); + MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); + ++static int hwcalib_xy; ++module_param(hwcalib_xy, bool, 0644); ++MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available"); ++ + /* device specifc data/functions */ + struct usbtouch_usb; + struct usbtouch_device_info { +@@ -260,8 +264,13 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt) + + static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) + { +- dev->x = (pkt[8] << 8) | pkt[7]; +- dev->y = (pkt[10] << 8) | pkt[9]; ++ if (hwcalib_xy) { ++ dev->x = (pkt[4] << 8) | pkt[3]; ++ dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]); ++ } else { ++ dev->x = (pkt[8] << 8) | pkt[7]; ++ dev->y = (pkt[10] << 8) | pkt[9]; ++ } + dev->touch = (pkt[2] & 0x40) ? 1 : 0; + + return 1; +@@ -294,6 +303,12 @@ static int mtouch_init(struct usbtouch_usb *usbtouch) + return ret; + } + ++ /* Default min/max xy are the raw values, override if using hw-calib */ ++ if (hwcalib_xy) { ++ input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0); ++ input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0); ++ } ++ + return 0; + } + #endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/intel-ibex-peak-device-ids.patch b/src/patches/suse-2.6.27.31/patches.drivers/intel-ibex-peak-device-ids.patch new file mode 100644 index 000000000..ce097910d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/intel-ibex-peak-device-ids.patch @@ -0,0 +1,70 @@ +From: Seth Heasley +Date: Thu, 28 Aug 2008 22:40:59 +0000 (-0700) +Subject: x86/PCI: irq and pci_ids patch for Intel Ibex Peak DeviceIDs +X-Git-Tag: v2.6.28-rc1~77^2~28 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=37a84ec668ba251ae02cf2c2c664baf6b247ae1f +References: bnc#415383 + +x86/PCI: irq and pci_ids patch for Intel Ibex Peak DeviceIDs + +This patch updates the Intel Ibex Peak (PCH) LPC and SMBus Controller +DeviceIDs. + +The LPC Controller ID is set by Firmware within the range of +0x3b00-3b1f. This range is included in pci_ids.h using min and max +values, and irq.c now has code to handle the range (in lieu of 32 +additions to a SWITCH statement). + +The SMBus Controller ID is a fixed-value and will not change. + +Signed-off-by: Seth Heasley +Acked-by: Jean Delvare +Signed-off-by: Jesse Barnes +Acked-by: John Jolly +--- + +--- + arch/x86/pci/irq.c | 11 +++++++++-- + include/linux/pci_ids.h | 6 +++--- + 2 files changed, 12 insertions(+), 5 deletions(-) + +--- a/arch/x86/pci/irq.c ++++ b/arch/x86/pci/irq.c +@@ -591,13 +591,20 @@ static __init int intel_router_probe(str + case PCI_DEVICE_ID_INTEL_ICH10_1: + case PCI_DEVICE_ID_INTEL_ICH10_2: + case PCI_DEVICE_ID_INTEL_ICH10_3: +- case PCI_DEVICE_ID_INTEL_PCH_0: +- case PCI_DEVICE_ID_INTEL_PCH_1: + r->name = "PIIX/ICH"; + r->get = pirq_piix_get; + r->set = pirq_piix_set; + return 1; + } ++ ++ if ((device >= PCI_DEVICE_ID_INTEL_PCH_LPC_MIN) && ++ (device <= PCI_DEVICE_ID_INTEL_PCH_LPC_MAX)) { ++ r->name = "PIIX/ICH"; ++ r->get = pirq_piix_get; ++ r->set = pirq_piix_set; ++ return 1; ++ } ++ + return 0; + } + +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -2446,9 +2446,9 @@ + #define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a + #define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 + #define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 +-#define PCI_DEVICE_ID_INTEL_PCH_0 0x3b10 +-#define PCI_DEVICE_ID_INTEL_PCH_1 0x3b11 +-#define PCI_DEVICE_ID_INTEL_PCH_2 0x3b30 ++#define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN 0x3b00 ++#define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX 0x3b1f ++#define PCI_DEVICE_ID_INTEL_PCH_SMBUS 0x3b30 + #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f + #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 + #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/intel-ibex-peak-device-support.patch b/src/patches/suse-2.6.27.31/patches.drivers/intel-ibex-peak-device-support.patch new file mode 100644 index 000000000..eb8bd0e5f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/intel-ibex-peak-device-support.patch @@ -0,0 +1,81 @@ +From: Seth Heasley +Date: Wed, 22 Oct 2008 18:21:29 +0000 (+0200) +Subject: i2c-i801: Add support for Intel Ibex Peak +X-Git-Tag: v2.6.28-rc1~32^2~14 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=c429a247f56d277f12eaffd6525922353e9539a5 +References: bnc#415383 + +i2c-i801: Add support for Intel Ibex Peak + +Adds the Intel Ibex Peak (PCH) SMBus Controller Device IDs. + +Signed-off-by: Seth Heasley +Signed-off-by: Jean Delvare +Acked-by: John Jolly +--- + +diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 +index c31e029..81c0c59 100644 +--- a/Documentation/i2c/busses/i2c-i801 ++++ b/Documentation/i2c/busses/i2c-i801 +@@ -13,8 +13,9 @@ Supported adapters: + * Intel 631xESB/632xESB (ESB2) + * Intel 82801H (ICH8) + * Intel 82801I (ICH9) +- * Intel Tolapai +- * Intel ICH10 ++ * Intel EP80579 (Tolapai) ++ * Intel 82801JI (ICH10) ++ * Intel PCH + Datasheets: Publicly available at the Intel website + + Authors: +@@ -32,7 +33,7 @@ Description + ----------- + + The ICH (properly known as the 82801AA), ICH0 (82801AB), ICH2 (82801BA), +-ICH3 (82801CA/CAM) and later devices are Intel chips that are a part of ++ICH3 (82801CA/CAM) and later devices (PCH) are Intel chips that are a part of + Intel's '810' chipset for Celeron-based PCs, '810E' chipset for + Pentium-based PCs, '815E' chipset, and others. + +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index acadbc5..7f95905 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -97,6 +97,7 @@ config I2C_I801 + ICH9 + Tolapai + ICH10 ++ PCH + + This driver can also be built as a module. If so, the module + will be called i2c-i801. +diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c +index dc7ea32..5123eb6 100644 +--- a/drivers/i2c/busses/i2c-i801.c ++++ b/drivers/i2c/busses/i2c-i801.c +@@ -41,6 +41,7 @@ + Tolapai 0x5032 32 hard yes yes yes + ICH10 0x3a30 32 hard yes yes yes + ICH10 0x3a60 32 hard yes yes yes ++ PCH 0x3b30 32 hard yes yes yes + + Features supported by this driver: + Software PEC no +@@ -576,6 +577,7 @@ static struct pci_device_id i801_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) }, + { 0, } + }; + +@@ -599,6 +601,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id + case PCI_DEVICE_ID_INTEL_TOLAPAI_1: + case PCI_DEVICE_ID_INTEL_ICH10_4: + case PCI_DEVICE_ID_INTEL_ICH10_5: ++ case PCI_DEVICE_ID_INTEL_PCH_SMBUS: + i801_features |= FEATURE_I2C_BLOCK_READ; + /* fall through */ + case PCI_DEVICE_ID_INTEL_82801DB_3: diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ipoib_null_skb_on_free.patch b/src/patches/suse-2.6.27.31/patches.drivers/ipoib_null_skb_on_free.patch new file mode 100644 index 000000000..57f51d424 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ipoib_null_skb_on_free.patch @@ -0,0 +1,90 @@ +From: Arthur Kepner +Subject: ipoib NULL skb pointers on free +References: bnc#503635 + +Acked-by: John Jolly + +Index: linux-2.6.27-SLE11_BRANCH/drivers/infiniband/ulp/ipoib/ipoib_cm.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/infiniband/ulp/ipoib/ipoib_cm.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/infiniband/ulp/ipoib/ipoib_cm.c +@@ -200,6 +200,7 @@ static void ipoib_cm_free_rx_ring(struct + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + rx_ring[i].mapping); + dev_kfree_skb_any(rx_ring[i].skb); ++ rx_ring[i].skb = NULL; + } + + vfree(rx_ring); +@@ -736,6 +737,7 @@ void ipoib_cm_send(struct net_device *de + if (unlikely(ib_dma_mapping_error(priv->ca, addr))) { + ++dev->stats.tx_errors; + dev_kfree_skb_any(skb); ++ tx_req->skb = NULL; + return; + } + +@@ -747,6 +749,7 @@ void ipoib_cm_send(struct net_device *de + ++dev->stats.tx_errors; + ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); ++ tx_req->skb = NULL; + } else { + dev->trans_start = jiffies; + ++tx->tx_head; +@@ -785,6 +788,7 @@ void ipoib_cm_handle_tx_wc(struct net_de + dev->stats.tx_bytes += tx_req->skb->len; + + dev_kfree_skb_any(tx_req->skb); ++ tx_req->skb = NULL; + + spin_lock_irqsave(&priv->tx_lock, flags); + ++tx->tx_tail; +@@ -1179,6 +1183,7 @@ timeout: + ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, + DMA_TO_DEVICE); + dev_kfree_skb_any(tx_req->skb); ++ tx_req->skb = NULL; + ++p->tx_tail; + spin_lock_irqsave(&priv->tx_lock, flags); + if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && +Index: linux-2.6.27-SLE11_BRANCH/drivers/infiniband/ulp/ipoib/ipoib_ib.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/infiniband/ulp/ipoib/ipoib_ib.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/infiniband/ulp/ipoib/ipoib_ib.c +@@ -377,12 +377,14 @@ static void ipoib_ib_handle_tx_wc(struct + + tx_req = &priv->tx_ring[wr_id]; + +- ipoib_dma_unmap_tx(priv->ca, tx_req); ++ if (tx_req->skb) { ++ struct sk_buff *skb = tx_req->skb; + +- ++dev->stats.tx_packets; +- dev->stats.tx_bytes += tx_req->skb->len; +- +- dev_kfree_skb_any(tx_req->skb); ++ ipoib_dma_unmap_tx(priv->ca, tx_req); ++ ++dev->stats.tx_packets; ++ dev->stats.tx_bytes += skb->len; ++ dev_kfree_skb_any(skb); ++ } + + ++priv->tx_tail; + if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && +@@ -571,6 +573,7 @@ void ipoib_send(struct net_device *dev, + if (unlikely(ipoib_dma_map_tx(priv->ca, tx_req))) { + ++dev->stats.tx_errors; + dev_kfree_skb_any(skb); ++ tx_req->skb = NULL; + return; + } + +@@ -593,6 +596,7 @@ void ipoib_send(struct net_device *dev, + --priv->tx_outstanding; + ipoib_dma_unmap_tx(priv->ca, tx_req); + dev_kfree_skb_any(skb); ++ tx_req->skb = NULL; + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } else { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ipr-slave-alloc-crash b/src/patches/suse-2.6.27.31/patches.drivers/ipr-slave-alloc-crash new file mode 100644 index 000000000..f3979a3c7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ipr-slave-alloc-crash @@ -0,0 +1,53 @@ +From: Brian King +Subject: ipr: Fix sleeping function called with interrupts disabled +References: bnc#501234 +Patch-Mainline: Yes + +During 2.6.30-rc2-git2 bootup on a power 7 box, i found the following BUG in +the boot log + +BUG: sleeping function called from invalid context at mm/slab.c:3055 +in_atomic(): 0, irqs_disabled(): 1, pid: 198, name: modprobe + +The ata_sas_slave_configure was changed such that it now allocates +some memory for a drain buffer for ATAPI devices. Fixup the ipr +driver such that we no longer make this call with interrupts disabled. + +Signed-off-by: Brian King +Signed-off-by: Hannes Reinecke +--- + + drivers/scsi/ipr.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/drivers/scsi/ipr.c ++++ b/drivers/scsi/ipr.c +@@ -3658,6 +3658,7 @@ static int ipr_slave_configure(struct sc + { + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct ipr_resource_entry *res; ++ struct ata_port *ap = NULL; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); +@@ -3676,12 +3677,16 @@ static int ipr_slave_configure(struct sc + } + if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) + sdev->allow_restart = 1; +- if (ipr_is_gata(res) && res->sata_port) { ++ if (ipr_is_gata(res) && res->sata_port) ++ ap = res->sata_port->ap; ++ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); ++ ++ if (ap) { + scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN); +- ata_sas_slave_configure(sdev, res->sata_port->ap); +- } else { ++ ata_sas_slave_configure(sdev, ap); ++ } else + scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); +- } ++ return 0; + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-add-bcna-support b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-add-bcna-support new file mode 100644 index 000000000..eb0609806 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-add-bcna-support @@ -0,0 +1,97 @@ +Subject: DCB: Add BCNA support to ixgbe +From: Hannes Reinecke +Date: Thu Nov 6 13:05:27 2008 +0100: +Git: 5091837c7ddfb47111ce456b9addd1476418dcd3 + +Signed-off-by: John Fastabend +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c +index ca2537e..d8db691 100644 +--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c ++++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c +@@ -93,6 +93,8 @@ int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, + dst_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0] = + src_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0]; + } ++ dst_dcb_cfg->bcn.bcna_option[0] = src_dcb_cfg->bcn.bcna_option[0]; ++ dst_dcb_cfg->bcn.bcna_option[1] = src_dcb_cfg->bcn.bcna_option[1]; + dst_dcb_cfg->bcn.rp_alpha = src_dcb_cfg->bcn.rp_alpha; + dst_dcb_cfg->bcn.rp_beta = src_dcb_cfg->bcn.rp_beta; + dst_dcb_cfg->bcn.rp_gd = src_dcb_cfg->bcn.rp_gd; +@@ -451,6 +453,12 @@ static void ixgbe_dcbnl_getbcncfg(struct net_device *netdev, int enum_index, + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + switch (enum_index) { ++ case DCB_BCN_ATTR_BCNA_0: ++ *setting = adapter->dcb_cfg.bcn.bcna_option[0]; ++ break; ++ case DCB_BCN_ATTR_BCNA_1: ++ *setting = adapter->dcb_cfg.bcn.bcna_option[1]; ++ break; + case DCB_BCN_ATTR_ALPHA: + *setting = adapter->dcb_cfg.bcn.rp_alpha; + break; +@@ -510,6 +518,18 @@ static void ixgbe_dcbnl_setbcncfg(struct net_device *netdev, int enum_index, + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + switch (enum_index) { ++ case DCB_BCN_ATTR_BCNA_0: ++ adapter->temp_dcb_cfg.bcn.bcna_option[0] = setting; ++ if (adapter->temp_dcb_cfg.bcn.bcna_option[0] != ++ adapter->dcb_cfg.bcn.bcna_option[0]) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_BCNA_1: ++ adapter->temp_dcb_cfg.bcn.bcna_option[1] = setting; ++ if (adapter->temp_dcb_cfg.bcn.bcna_option[1] != ++ adapter->dcb_cfg.bcn.bcna_option[1]) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; + case DCB_BCN_ATTR_ALPHA: + adapter->temp_dcb_cfg.bcn.rp_alpha = setting; + if (adapter->temp_dcb_cfg.bcn.rp_alpha != +diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h +index 2d5c6fb..e752f2b 100644 +--- a/include/linux/dcbnl.h ++++ b/include/linux/dcbnl.h +@@ -291,6 +291,8 @@ enum dcbnl_bcn_attrs{ + DCB_BCN_ATTR_RP_7, + DCB_BCN_ATTR_RP_ALL, + ++ DCB_BCN_ATTR_BCNA_0, ++ DCB_BCN_ATTR_BCNA_1, + DCB_BCN_ATTR_ALPHA, + DCB_BCN_ATTR_BETA, + DCB_BCN_ATTR_GD, +diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c +index 76b08ec..f5e2b0b 100644 +--- a/net/dcb/dcbnl.c ++++ b/net/dcb/dcbnl.c +@@ -106,6 +106,8 @@ static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { + [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, ++ [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, + [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, + [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, + [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, +@@ -893,7 +895,7 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, + goto err_bcn; + } + +- for (i = DCB_BCN_ATTR_ALPHA; i <= DCB_BCN_ATTR_RI; i++) { ++ for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { + if (!getall && !bcn_tb[i]) + continue; + +@@ -951,7 +953,7 @@ static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, + data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); + } + +- for (i = DCB_BCN_ATTR_ALPHA; i <= DCB_BCN_ATTR_RI; i++) { ++ for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { + if (data[i] == NULL) + continue; + value_int = nla_get_u32(data[i]); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-copper_pond.patch b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-copper_pond.patch new file mode 100644 index 000000000..ef6e5b8b8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-copper_pond.patch @@ -0,0 +1,342 @@ +From: Jesse Brandeburg +Date: Fri, 31 Oct 2008 07:46:40 +0000 (-0700) +Subject: ixgbe: add device support for 82598AT (copper 10GbE) adapters +X-Git-Url: http://gitlad.jf.intel.com/git/?p=davem%2Fnet-next-2.6%2F.git;a=commitdiff_plain;h=0befdb3e0a26a8949063915274e1bec8873c526b +Acked-by: Karsten Keil +Reference: bnc#441471 + +ixgbe: add device support for 82598AT (copper 10GbE) adapters + +Intel is currently shipping support for adapters with a phy +that does 10GBase-T (copper), which is 10 Gigabit ethernet +over standard Category 6 cabling. + +Signed-off-by: Jesse Brandeburg +Signed-off-by: Jeff Kirsher +Signed-off-by: Jeff Garzik +--- + +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe.h ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe.h +@@ -282,6 +282,7 @@ struct ixgbe_adapter { + #define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) + #define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) + #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) ++#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) + #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) + #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) + #define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 24) +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe_82598.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe_82598.c ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe_82598.c +@@ -59,6 +59,11 @@ static s32 ixgbe_get_invariants_82598(st + + /* PHY Init */ + switch (phy->type) { ++ case ixgbe_phy_tn: ++ phy->ops.check_link = &ixgbe_check_phy_link_tnx; ++ phy->ops.get_firmware_version = ++ &ixgbe_get_phy_firmware_version_tnx; ++ break; + default: + break; + } +@@ -189,6 +194,9 @@ static enum ixgbe_media_type ixgbe_get_m + case IXGBE_DEV_ID_82598EB_XF_LR: + media_type = ixgbe_media_type_fiber; + break; ++ case IXGBE_DEV_ID_82598AT: ++ media_type = ixgbe_media_type_copper; ++ break; + default: + media_type = ixgbe_media_type_unknown; + break; +@@ -872,6 +880,10 @@ s32 ixgbe_get_supported_physical_layer_8 + case IXGBE_DEV_ID_82598EB_XF_LR: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; ++ case IXGBE_DEV_ID_82598AT: ++ physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | ++ IXGBE_PHYSICAL_LAYER_1000BASE_T); ++ break; + + default: + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe_ethtool.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe_ethtool.c ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe_ethtool.c +@@ -160,6 +160,8 @@ static int ixgbe_set_settings(struct net + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; ++ u32 advertised, old; ++ s32 err; + + switch (hw->phy.media_type) { + case ixgbe_media_type_fiber: +@@ -168,6 +170,31 @@ static int ixgbe_set_settings(struct net + return -EINVAL; + /* in this case we currently only support 10Gb/FULL */ + break; ++ case ixgbe_media_type_copper: ++ /* 10000/copper and 1000/copper must autoneg ++ * this function does not support any duplex forcing, but can ++ * limit the advertising of the adapter to only 10000 or 1000 */ ++ if (ecmd->autoneg == AUTONEG_DISABLE) ++ return -EINVAL; ++ ++ old = hw->phy.autoneg_advertised; ++ advertised = 0; ++ if (ecmd->advertising & ADVERTISED_10000baseT_Full) ++ advertised |= IXGBE_LINK_SPEED_10GB_FULL; ++ ++ if (ecmd->advertising & ADVERTISED_1000baseT_Full) ++ advertised |= IXGBE_LINK_SPEED_1GB_FULL; ++ ++ if (old == advertised) ++ break; ++ /* this sets the link speed and restarts auto-neg */ ++ err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); ++ if (err) { ++ DPRINTK(PROBE, INFO, ++ "setup link failed with code %d\n", err); ++ hw->mac.ops.setup_link_speed(hw, old, true, true); ++ } ++ break; + default: + break; + } +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe_main.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe_main.c ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe_main.c +@@ -68,6 +68,8 @@ static struct pci_device_id ixgbe_pci_tb + board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), + board_82598 }, ++ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), ++ board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), + board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), +@@ -910,6 +912,17 @@ static void ixgbe_set_itr_msix(struct ix + return; + } + ++static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) ++{ ++ struct ixgbe_hw *hw = &adapter->hw; ++ ++ if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && ++ (eicr & IXGBE_EICR_GPI_SDP1)) { ++ DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n"); ++ /* write to clear the interrupt */ ++ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); ++ } ++} + + static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) + { +@@ -934,6 +947,8 @@ static irqreturn_t ixgbe_msix_lsc(int ir + if (eicr & IXGBE_EICR_LSC) + ixgbe_check_lsc(adapter); + ++ ixgbe_check_fan_failure(adapter, eicr); ++ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + +@@ -1322,6 +1337,8 @@ static irqreturn_t ixgbe_intr(int irq, v + if (eicr & IXGBE_EICR_LSC) + ixgbe_check_lsc(adapter); + ++ ixgbe_check_fan_failure(adapter, eicr); ++ + if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { + adapter->tx_ring[0].total_packets = 0; + adapter->tx_ring[0].total_bytes = 0; +@@ -1424,6 +1441,8 @@ static inline void ixgbe_irq_enable(stru + { + u32 mask; + mask = IXGBE_EIMS_ENABLE_MASK; ++ if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) ++ mask |= IXGBE_EIMS_GPI_SDP1; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); + IXGBE_WRITE_FLUSH(&adapter->hw); + } +@@ -1983,6 +2002,13 @@ static int ixgbe_up_complete(struct ixgb + IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); + } + ++ /* Enable fan failure interrupt if media type is copper */ ++ if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { ++ gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); ++ gpie |= IXGBE_SDP1_GPIEN; ++ IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); ++ } ++ + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); + if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { + mhadd &= ~IXGBE_MHADD_MFS_MASK; +@@ -2679,6 +2705,9 @@ static int __devinit ixgbe_sw_init(struc + rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus()); + adapter->ring_feature[RING_F_RSS].indices = rss; + adapter->flags |= IXGBE_FLAG_RSS_ENABLED; ++ if (hw->mac.ops.get_media_type && ++ (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper)) ++ adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; + adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; + + /* Configure DCB traffic classes */ +@@ -3851,6 +3880,10 @@ static int ixgbe_link_config(struct ixgb + /* must always autoneg for both 1G and 10G link */ + hw->mac.autoneg = true; + ++ if ((hw->mac.type == ixgbe_mac_82598EB) && ++ (hw->phy.media_type == ixgbe_media_type_copper)) ++ autoneg = IXGBE_LINK_SPEED_82598_AUTONEG; ++ + return hw->mac.ops.setup_link_speed(hw, autoneg, true, true); + } + +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe_phy.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe_phy.c ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe_phy.c +@@ -121,6 +121,9 @@ static enum ixgbe_phy_type ixgbe_get_phy + enum ixgbe_phy_type phy_type; + + switch (phy_id) { ++ case TN1010_PHY_ID: ++ phy_type = ixgbe_phy_tn; ++ break; + case QT2022_PHY_ID: + phy_type = ixgbe_phy_qt; + break; +@@ -426,3 +429,68 @@ s32 ixgbe_setup_phy_link_speed_generic(s + return 0; + } + ++/** ++ * ixgbe_check_phy_link_tnx - Determine link and speed status ++ * @hw: pointer to hardware structure ++ * ++ * Reads the VS1 register to determine if link is up and the current speed for ++ * the PHY. ++ **/ ++s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, ++ bool *link_up) ++{ ++ s32 status = 0; ++ u32 time_out; ++ u32 max_time_out = 10; ++ u16 phy_link = 0; ++ u16 phy_speed = 0; ++ u16 phy_data = 0; ++ ++ /* Initialize speed and link to default case */ ++ *link_up = false; ++ *speed = IXGBE_LINK_SPEED_10GB_FULL; ++ ++ /* ++ * Check current speed and link status of the PHY register. ++ * This is a vendor specific register and may have to ++ * be changed for other copper PHYs. ++ */ ++ for (time_out = 0; time_out < max_time_out; time_out++) { ++ udelay(10); ++ status = hw->phy.ops.read_reg(hw, ++ IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, ++ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ++ &phy_data); ++ phy_link = phy_data & ++ IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; ++ phy_speed = phy_data & ++ IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; ++ if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { ++ *link_up = true; ++ if (phy_speed == ++ IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) ++ *speed = IXGBE_LINK_SPEED_1GB_FULL; ++ break; ++ } ++ } ++ ++ return status; ++} ++ ++/** ++ * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version ++ * @hw: pointer to hardware structure ++ * @firmware_version: pointer to the PHY Firmware Version ++ **/ ++s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, ++ u16 *firmware_version) ++{ ++ s32 status = 0; ++ ++ status = hw->phy.ops.read_reg(hw, TNX_FW_REV, ++ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ++ firmware_version); ++ ++ return status; ++} ++ +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe_phy.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe_phy.h ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe_phy.h +@@ -77,4 +77,11 @@ s32 ixgbe_setup_phy_link_speed_generic(s + bool autoneg, + bool autoneg_wait_to_complete); + ++/* PHY specific */ ++s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ++ ixgbe_link_speed *speed, ++ bool *link_up); ++s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, ++ u16 *firmware_version); ++ + #endif /* _IXGBE_PHY_H_ */ +Index: linux-2.6.27/drivers/net/ixgbe/ixgbe_type.h +=================================================================== +--- linux-2.6.27.orig/drivers/net/ixgbe/ixgbe_type.h ++++ linux-2.6.27/drivers/net/ixgbe/ixgbe_type.h +@@ -36,6 +36,7 @@ + /* Device IDs */ + #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 + #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 ++#define IXGBE_DEV_ID_82598AT 0x10C8 + #define IXGBE_DEV_ID_82598EB_CX4 0x10DD + #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC + #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 +@@ -488,6 +489,8 @@ + #define IXGBE_MAX_PHY_ADDR 32 + + /* PHY IDs*/ ++#define TN1010_PHY_ID 0x00A19410 ++#define TNX_FW_REV 0xB + #define QT2022_PHY_ID 0x0043A400 + + /* PHY Types */ +@@ -1202,6 +1205,7 @@ enum ixgbe_mac_type { + + enum ixgbe_phy_type { + ixgbe_phy_unknown = 0, ++ ixgbe_phy_tn, + ixgbe_phy_qt, + ixgbe_phy_xaui, + ixgbe_phy_tw_tyco, +@@ -1396,6 +1400,8 @@ struct ixgbe_phy_operations { + s32 (*setup_link)(struct ixgbe_hw *); + s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, + bool); ++ s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); ++ s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *); + s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); + s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); + s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-dcb-setstate.patch b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-dcb-setstate.patch new file mode 100644 index 000000000..b8c3b3c70 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-dcb-setstate.patch @@ -0,0 +1,132 @@ +From: John Ronciak +Subject: Bugfix for ixgbe and kernel DCB netlink code +Acked-by: Karsten Keil +Reference: bnc#458194 + +The patch file ixgbe-dcb-setstate.patch, created against the SLES11 Beta6 +kernel source, contains the following fixes: + +Change to ixgbe: +- Fix the DCB setstate operation function to check and not attempt to +enable DCB if MSI-X is not enabled. Return a success/failure status to the DCB +netlink layer. + +Change to DCB netlink in kernel: +- Accept a success/failure status from the DCB setstate operation +function. + +- Fix the dcbnl_setnumtcs routine to check for the presence of the +setnumtcs operation function (instead of setstate) + +We are in the process of pushing these changes to the upstream kernel as well. + +diff -Naurp linux-2.6.27.7-4/drivers/net/ixgbe/ixgbe_dcb_nl.c linux-2.6.27.7-4-new/drivers/net/ixgbe/ixgbe_dcb_nl.c +--- linux-2.6.27.7-4/drivers/net/ixgbe/ixgbe_dcb_nl.c 2008-12-10 14:12:15.000000000 -0800 ++++ linux-2.6.27.7-4-new/drivers/net/ixgbe/ixgbe_dcb_nl.c 2008-12-09 15:50:21.000000000 -0800 +@@ -126,7 +126,7 @@ static u16 ixgbe_dcb_select_queue(struct + return 0; + } + +-static void ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) ++static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + +@@ -135,25 +135,30 @@ static void ixgbe_dcbnl_set_state(struct + if (state > 0) { + /* Turn on DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { +- return; +- } else { +- if (netif_running(netdev)) +- netdev->stop(netdev); +- ixgbe_reset_interrupt_capability(adapter); +- ixgbe_napi_del_all(adapter); +- kfree(adapter->tx_ring); +- kfree(adapter->rx_ring); +- adapter->tx_ring = NULL; +- adapter->rx_ring = NULL; +- netdev->select_queue = &ixgbe_dcb_select_queue; ++ return 0; ++ } + +- adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; +- adapter->flags |= IXGBE_FLAG_DCB_ENABLED; +- ixgbe_init_interrupt_scheme(adapter); +- ixgbe_napi_add_all(adapter); +- if (netif_running(netdev)) +- netdev->open(netdev); +- } ++ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { ++ DPRINTK(DRV, ERR, "Enable Failed, needs MSI-X\n"); ++ return 1; ++ } ++ ++ if (netif_running(netdev)) ++ netdev->stop(netdev); ++ ixgbe_reset_interrupt_capability(adapter); ++ ixgbe_napi_del_all(adapter); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ adapter->tx_ring = NULL; ++ adapter->rx_ring = NULL; ++ netdev->select_queue = &ixgbe_dcb_select_queue; ++ ++ adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ++ adapter->flags |= IXGBE_FLAG_DCB_ENABLED; ++ ixgbe_init_interrupt_scheme(adapter); ++ ixgbe_napi_add_all(adapter); ++ if (netif_running(netdev)) ++ netdev->open(netdev); + } else { + /* Turn off DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { +@@ -173,10 +178,9 @@ static void ixgbe_dcbnl_set_state(struct + ixgbe_napi_add_all(adapter); + if (netif_running(netdev)) + netdev->open(netdev); +- } else { +- return; + } + } ++ return 0; + } + + static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, +diff -Naurp linux-2.6.27.7-4/include/net/dcbnl.h linux-2.6.27.7-4-new/include/net/dcbnl.h +--- linux-2.6.27.7-4/include/net/dcbnl.h 2008-12-10 14:00:13.000000000 -0800 ++++ linux-2.6.27.7-4-new/include/net/dcbnl.h 2008-12-10 14:22:03.000000000 -0800 +@@ -13,7 +13,7 @@ + */ + struct dcbnl_rtnl_ops { + u8 (*getstate)(struct net_device *); +- void (*setstate)(struct net_device *, u8); ++ u8 (*setstate)(struct net_device *, u8); + void (*getpermhwaddr)(struct net_device *, u8 *); + void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8); + void (*setpgbwgcfgtx)(struct net_device *, int, u8); +diff -Naurp linux-2.6.27.7-4/net/dcb/dcbnl.c linux-2.6.27.7-4-new/net/dcb/dcbnl.c +--- linux-2.6.27.7-4/net/dcb/dcbnl.c 2008-12-10 13:59:34.000000000 -0800 ++++ linux-2.6.27.7-4-new/net/dcb/dcbnl.c 2008-12-10 14:26:41.000000000 -0800 +@@ -437,7 +437,7 @@ static int dcbnl_setnumtcs(struct net_de + u8 value; + int i; + +- if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setstate) ++ if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) + return ret; + + ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], +@@ -682,10 +682,8 @@ static int dcbnl_setstate(struct net_dev + + value = nla_get_u8(tb[DCB_ATTR_STATE]); + +- netdev->dcbnl_ops->setstate(netdev, value); +- +- ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, +- pid, seq, flags); ++ ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), ++ RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, pid, seq, flags); + + return ret; + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-fcoe-bugfixes b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-fcoe-bugfixes new file mode 100644 index 000000000..f8583ad02 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-fcoe-bugfixes @@ -0,0 +1,8423 @@ +From 401b9a9a678be30083ff7f68fb1ab3fb898d50b4 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:35:05 +0200 +Subject: [PATCH] ixgbe: Bugfixes for FCoE + +Signed-off-by: Jesse Brandeburg +Signed-off-by: Hannes Reinecke +--- + drivers/net/Kconfig | 11 + drivers/net/ixgbe/ixgbe.h | 113 +- + drivers/net/ixgbe/ixgbe_82598.c | 628 +++++++++--- + drivers/net/ixgbe/ixgbe_common.c | 1064 ++++++++++++++------ + drivers/net/ixgbe/ixgbe_common.h | 60 - + drivers/net/ixgbe/ixgbe_ethtool.c | 307 +++-- + drivers/net/ixgbe/ixgbe_main.c | 1981 +++++++++++++++++++++----------------- + drivers/net/ixgbe/ixgbe_phy.c | 248 +--- + drivers/net/ixgbe/ixgbe_phy.h | 63 - + drivers/net/ixgbe/ixgbe_type.h | 559 ++++++---- + 10 files changed, 3159 insertions(+), 1875 deletions(-) + +--- a/drivers/net/ixgbe/ixgbe_82598.c ++++ b/drivers/net/ixgbe/ixgbe_82598.c +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -36,67 +35,62 @@ + #define IXGBE_82598_MAX_TX_QUEUES 32 + #define IXGBE_82598_MAX_RX_QUEUES 64 + #define IXGBE_82598_RAR_ENTRIES 16 ++#define IXGBE_82598_MC_TBL_SIZE 128 ++#define IXGBE_82598_VFT_TBL_SIZE 128 + +-static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw); +-static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, +- bool *autoneg); +-static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, +- u32 *speed, bool *autoneg); +-static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw); +-static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw); +-static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, +- bool *link_up); +-static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed, +- bool autoneg, +- bool autoneg_wait_to_complete); ++static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, ++ ixgbe_link_speed *speed, ++ bool *autoneg); + static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); +-static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, +- bool autoneg, +- bool autoneg_wait_to_complete); +-static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); +- ++static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, ++ ixgbe_link_speed speed, ++ bool autoneg, ++ bool autoneg_wait_to_complete); + ++/** ++ */ + static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) + { +- hw->mac.num_rx_queues = IXGBE_82598_MAX_RX_QUEUES; +- hw->mac.num_tx_queues = IXGBE_82598_MAX_TX_QUEUES; +- hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES; +- +- /* PHY ops are filled in by default properly for Fiber only */ +- if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) { +- hw->mac.ops.setup_link = &ixgbe_setup_copper_link_82598; +- hw->mac.ops.setup_link_speed = &ixgbe_setup_copper_link_speed_82598; +- hw->mac.ops.get_link_settings = +- &ixgbe_get_copper_link_settings_82598; +- +- /* Call PHY identify routine to get the phy type */ +- ixgbe_identify_phy(hw); +- +- switch (hw->phy.type) { +- case ixgbe_phy_tn: +- hw->phy.ops.setup_link = &ixgbe_setup_tnx_phy_link; +- hw->phy.ops.check_link = &ixgbe_check_tnx_phy_link; +- hw->phy.ops.setup_link_speed = +- &ixgbe_setup_tnx_phy_link_speed; +- break; +- default: +- break; +- } ++ struct ixgbe_mac_info *mac = &hw->mac; ++ struct ixgbe_phy_info *phy = &hw->phy; ++ ++ /* Call PHY identify routine to get the phy type */ ++ ixgbe_identify_phy_generic(hw); ++ ++ /* PHY Init */ ++ switch (phy->type) { ++ default: ++ break; + } + ++ if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) { ++ mac->ops.setup_link = &ixgbe_setup_copper_link_82598; ++ mac->ops.setup_link_speed = ++ &ixgbe_setup_copper_link_speed_82598; ++ mac->ops.get_link_capabilities = ++ &ixgbe_get_copper_link_capabilities_82598; ++ } ++ ++ mac->mcft_size = IXGBE_82598_MC_TBL_SIZE; ++ mac->vft_size = IXGBE_82598_VFT_TBL_SIZE; ++ mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES; ++ mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; ++ mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; ++ + return 0; + } + + /** +- * ixgbe_get_link_settings_82598 - Determines default link settings ++ * ixgbe_get_link_capabilities_82598 - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * +- * Determines the default link settings by reading the AUTOC register. ++ * Determines the link capabilities by reading the AUTOC register. + **/ +-static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed, +- bool *autoneg) ++static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, ++ ixgbe_link_speed *speed, ++ bool *autoneg) + { + s32 status = 0; + s32 autoc_reg; +@@ -145,15 +139,16 @@ static s32 ixgbe_get_link_settings_82598 + } + + /** +- * ixgbe_get_copper_link_settings_82598 - Determines default link settings ++ * ixgbe_get_copper_link_capabilities_82598 - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + * +- * Determines the default link settings by reading the AUTOC register. ++ * Determines the link capabilities by reading the AUTOC register. + **/ +-static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw, +- u32 *speed, bool *autoneg) ++s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, ++ ixgbe_link_speed *speed, ++ bool *autoneg) + { + s32 status = IXGBE_ERR_LINK_SETUP; + u16 speed_ability; +@@ -161,9 +156,9 @@ static s32 ixgbe_get_copper_link_setting + *speed = 0; + *autoneg = true; + +- status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, +- IXGBE_MDIO_PMA_PMD_DEV_TYPE, +- &speed_ability); ++ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, ++ &speed_ability); + + if (status == 0) { + if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) +@@ -191,11 +186,9 @@ static enum ixgbe_media_type ixgbe_get_m + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598EB_CX4: + case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: ++ case IXGBE_DEV_ID_82598EB_XF_LR: + media_type = ixgbe_media_type_fiber; + break; +- case IXGBE_DEV_ID_82598AT_DUAL_PORT: +- media_type = ixgbe_media_type_copper; +- break; + default: + media_type = ixgbe_media_type_unknown; + break; +@@ -205,6 +198,122 @@ static enum ixgbe_media_type ixgbe_get_m + } + + /** ++ * ixgbe_setup_fc_82598 - Configure flow control settings ++ * @hw: pointer to hardware structure ++ * @packetbuf_num: packet buffer number (0-7) ++ * ++ * Configures the flow control settings based on SW configuration. This ++ * function is used for 802.3x flow control configuration only. ++ **/ ++s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) ++{ ++ u32 frctl_reg; ++ u32 rmcs_reg; ++ ++ if (packetbuf_num < 0 || packetbuf_num > 7) { ++ hw_dbg(hw, "Invalid packet buffer number [%d], expected range is" ++ " 0-7\n", packetbuf_num); ++ } ++ ++ frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); ++ frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); ++ ++ rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); ++ rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); ++ ++ /* ++ * 10 gig parts do not have a word in the EEPROM to determine the ++ * default flow control setting, so we explicitly set it to full. ++ */ ++ if (hw->fc.type == ixgbe_fc_default) ++ hw->fc.type = ixgbe_fc_full; ++ ++ /* ++ * We want to save off the original Flow Control configuration just in ++ * case we get disconnected and then reconnected into a different hub ++ * or switch with different Flow Control capabilities. ++ */ ++ hw->fc.original_type = hw->fc.type; ++ ++ /* ++ * The possible values of the "flow_control" parameter are: ++ * 0: Flow control is completely disabled ++ * 1: Rx flow control is enabled (we can receive pause frames but not ++ * send pause frames). ++ * 2: Tx flow control is enabled (we can send pause frames but we do not ++ * support receiving pause frames) ++ * 3: Both Rx and Tx flow control (symmetric) are enabled. ++ * other: Invalid. ++ */ ++ switch (hw->fc.type) { ++ case ixgbe_fc_none: ++ break; ++ case ixgbe_fc_rx_pause: ++ /* ++ * Rx Flow control is enabled, ++ * and Tx Flow control is disabled. ++ */ ++ frctl_reg |= IXGBE_FCTRL_RFCE; ++ break; ++ case ixgbe_fc_tx_pause: ++ /* ++ * Tx Flow control is enabled, and Rx Flow control is disabled, ++ * by a software over-ride. ++ */ ++ rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; ++ break; ++ case ixgbe_fc_full: ++ /* ++ * Flow control (both Rx and Tx) is enabled by a software ++ * over-ride. ++ */ ++ frctl_reg |= IXGBE_FCTRL_RFCE; ++ rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; ++ break; ++ default: ++ /* We should never get here. The value should be 0-3. */ ++ hw_dbg(hw, "Flow control param set incorrectly\n"); ++ break; ++ } ++ ++ /* Enable 802.3x based flow control settings. */ ++ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); ++ IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); ++ ++ /* ++ * Check for invalid software configuration, zeros are completely ++ * invalid for all parameters used past this point, and if we enable ++ * flow control with zero water marks, we blast flow control packets. ++ */ ++ if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) { ++ hw_dbg(hw, "Flow control structure initialized incorrectly\n"); ++ return IXGBE_ERR_INVALID_LINK_SETTINGS; ++ } ++ ++ /* ++ * We need to set up the Receive Threshold high and low water ++ * marks as well as (optionally) enabling the transmission of ++ * XON frames. ++ */ ++ if (hw->fc.type & ixgbe_fc_tx_pause) { ++ if (hw->fc.send_xon) { ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), ++ (hw->fc.low_water | IXGBE_FCRTL_XONE)); ++ } else { ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), ++ hw->fc.low_water); ++ } ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), ++ (hw->fc.high_water)|IXGBE_FCRTH_FCEN); ++ } ++ ++ IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); ++ ++ return 0; ++} ++ ++/** + * ixgbe_setup_mac_link_82598 - Configures MAC link settings + * @hw: pointer to hardware structure + * +@@ -248,8 +357,7 @@ static s32 ixgbe_setup_mac_link_82598(st + } + if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) { + status = IXGBE_ERR_AUTONEG_NOT_COMPLETE; +- hw_dbg(hw, +- "Autonegotiation did not complete.\n"); ++ hw_dbg(hw, "Autonegotiation did not complete.\n"); + } + } + } +@@ -259,8 +367,8 @@ static s32 ixgbe_setup_mac_link_82598(st + * case we get disconnected and then reconnected into a different hub + * or switch with different Flow Control capabilities. + */ +- hw->fc.type = hw->fc.original_type; +- ixgbe_setup_fc(hw, 0); ++ hw->fc.original_type = hw->fc.type; ++ ixgbe_setup_fc_82598(hw, 0); + + /* Add delay to filter out noises during initial link setup */ + msleep(50); +@@ -273,20 +381,35 @@ static s32 ixgbe_setup_mac_link_82598(st + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true is link is up, false otherwise ++ * @link_up_wait_to_complete: bool used to wait for link up or not + * + * Reads the links register to determine if link is up and the current speed + **/ +-static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed, +- bool *link_up) ++static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, ++ ixgbe_link_speed *speed, bool *link_up, ++ bool link_up_wait_to_complete) + { + u32 links_reg; ++ u32 i; + + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); +- +- if (links_reg & IXGBE_LINKS_UP) +- *link_up = true; +- else +- *link_up = false; ++ if (link_up_wait_to_complete) { ++ for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { ++ if (links_reg & IXGBE_LINKS_UP) { ++ *link_up = true; ++ break; ++ } else { ++ *link_up = false; ++ } ++ msleep(100); ++ links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); ++ } ++ } else { ++ if (links_reg & IXGBE_LINKS_UP) ++ *link_up = true; ++ else ++ *link_up = false; ++ } + + if (links_reg & IXGBE_LINKS_SPEED) + *speed = IXGBE_LINK_SPEED_10GB_FULL; +@@ -296,6 +419,7 @@ static s32 ixgbe_check_mac_link_82598(st + return 0; + } + ++ + /** + * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed + * @hw: pointer to hardware structure +@@ -306,18 +430,18 @@ static s32 ixgbe_check_mac_link_82598(st + * Set the link speed in the AUTOC register and restarts link. + **/ + static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, +- u32 speed, bool autoneg, +- bool autoneg_wait_to_complete) ++ ixgbe_link_speed speed, bool autoneg, ++ bool autoneg_wait_to_complete) + { + s32 status = 0; + + /* If speed is 10G, then check for CX4 or XAUI. */ + if ((speed == IXGBE_LINK_SPEED_10GB_FULL) && +- (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) ++ (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) { + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; +- else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) ++ } else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) { + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN; +- else if (autoneg) { ++ } else if (autoneg) { + /* BX mode - Autonegotiate 1G */ + if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD)) + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN; +@@ -336,7 +460,7 @@ static s32 ixgbe_setup_mac_link_speed_82 + * ixgbe_hw This will write the AUTOC register based on the new + * stored values + */ +- hw->mac.ops.setup_link(hw); ++ ixgbe_setup_mac_link_82598(hw); + } + + return status; +@@ -354,18 +478,17 @@ static s32 ixgbe_setup_mac_link_speed_82 + **/ + static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) + { +- s32 status = 0; ++ s32 status; + + /* Restart autonegotiation on PHY */ +- if (hw->phy.ops.setup_link) +- status = hw->phy.ops.setup_link(hw); ++ status = hw->phy.ops.setup_link(hw); + +- /* Set MAC to KX/KX4 autoneg, which defaultis to Parallel detection */ ++ /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ + hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; + + /* Set up MAC */ +- hw->mac.ops.setup_link(hw); ++ ixgbe_setup_mac_link_82598(hw); + + return status; + } +@@ -379,23 +502,23 @@ static s32 ixgbe_setup_copper_link_82598 + * + * Sets the link speed in the AUTOC register in the MAC and restarts link. + **/ +-static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, +- bool autoneg, +- bool autoneg_wait_to_complete) ++static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, ++ ixgbe_link_speed speed, ++ bool autoneg, ++ bool autoneg_wait_to_complete) + { +- s32 status = 0; ++ s32 status; + + /* Setup the PHY according to input speed */ +- if (hw->phy.ops.setup_link_speed) +- status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, +- autoneg_wait_to_complete); ++ status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, ++ autoneg_wait_to_complete); + + /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ + hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; + + /* Set up MAC */ +- hw->mac.ops.setup_link(hw); ++ ixgbe_setup_mac_link_82598(hw); + + return status; + } +@@ -404,7 +527,7 @@ static s32 ixgbe_setup_copper_link_speed + * ixgbe_reset_hw_82598 - Performs hardware reset + * @hw: pointer to hardware structure + * +- * Resets the hardware by reseting the transmit and receive units, masks and ++ * Resets the hardware by resetting the transmit and receive units, masks and + * clears all interrupts, performing a PHY reset, and performing a link (MAC) + * reset. + **/ +@@ -418,35 +541,44 @@ static s32 ixgbe_reset_hw_82598(struct i + u8 analog_val; + + /* Call adapter stop to disable tx/rx and clear interrupts */ +- ixgbe_stop_adapter(hw); ++ hw->mac.ops.stop_adapter(hw); + + /* +- * Power up the Atlas TX lanes if they are currently powered down. +- * Atlas TX lanes are powered down for MAC loopback tests, but ++ * Power up the Atlas Tx lanes if they are currently powered down. ++ * Atlas Tx lanes are powered down for MAC loopback tests, but + * they are not automatically restored on reset. + */ +- ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); ++ hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); + if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) { +- /* Enable TX Atlas so packets can be transmitted again */ +- ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val); ++ /* Enable Tx Atlas so packets can be transmitted again */ ++ hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, ++ &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN; +- ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val); ++ hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, ++ analog_val); + +- ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val); ++ hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, ++ &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL; +- ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val); ++ hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, ++ analog_val); + +- ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val); ++ hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, ++ &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL; +- ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val); ++ hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, ++ analog_val); + +- ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val); ++ hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, ++ &analog_val); + analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL; +- ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val); ++ hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, ++ analog_val); + } + + /* Reset PHY */ +- ixgbe_reset_phy(hw); ++ if (hw->phy.reset_disable == false) ++ hw->phy.ops.reset(hw); + + /* + * Prevent the PCI-E bus from from hanging by disabling PCI-E master +@@ -499,29 +631,311 @@ static s32 ixgbe_reset_hw_82598(struct i + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + } else { + hw->mac.link_attach_type = +- (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); ++ (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE); + hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK); + hw->mac.link_settings_loaded = true; + } + + /* Store the permanent mac address */ +- ixgbe_get_mac_addr(hw, hw->mac.perm_addr); ++ hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr); + + return status; + } + ++/** ++ * ixgbe_set_vmdq_82598 - Associate a VMDq set index with a rx address ++ * @hw: pointer to hardware struct ++ * @rar: receive address register index to associate with a VMDq index ++ * @vmdq: VMDq set index ++ **/ ++s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) ++{ ++ u32 rar_high; ++ ++ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar)); ++ rar_high &= ~IXGBE_RAH_VIND_MASK; ++ rar_high |= ((vmdq << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK); ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high); ++ return 0; ++} ++ ++/** ++ * ixgbe_clear_vmdq_82598 - Disassociate a VMDq set index from an rx address ++ * @hw: pointer to hardware struct ++ * @rar: receive address register index to associate with a VMDq index ++ * @vmdq: VMDq clear index (not used in 82598, but elsewhere) ++ **/ ++static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) ++{ ++ u32 rar_high; ++ u32 rar_entries = hw->mac.num_rar_entries; ++ ++ if (rar < rar_entries) { ++ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar)); ++ if (rar_high & IXGBE_RAH_VIND_MASK) { ++ rar_high &= ~IXGBE_RAH_VIND_MASK; ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high); ++ } ++ } else { ++ hw_dbg(hw, "RAR index %d is out of range.\n", rar); ++ } ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_set_vfta_82598 - Set VLAN filter table ++ * @hw: pointer to hardware structure ++ * @vlan: VLAN id to write to VLAN filter ++ * @vind: VMDq output index that maps queue to VLAN id in VFTA ++ * @vlan_on: boolean flag to turn on/off VLAN in VFTA ++ * ++ * Turn on/off specified VLAN in the VLAN filter table. ++ **/ ++s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, ++ bool vlan_on) ++{ ++ u32 regindex; ++ u32 bitindex; ++ u32 bits; ++ u32 vftabyte; ++ ++ if (vlan > 4095) ++ return IXGBE_ERR_PARAM; ++ ++ /* Determine 32-bit word position in array */ ++ regindex = (vlan >> 5) & 0x7F; /* upper seven bits */ ++ ++ /* Determine the location of the (VMD) queue index */ ++ vftabyte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ ++ bitindex = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ ++ ++ /* Set the nibble for VMD queue index */ ++ bits = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(vftabyte, regindex)); ++ bits &= (~(0x0F << bitindex)); ++ bits |= (vind << bitindex); ++ IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vftabyte, regindex), bits); ++ ++ /* Determine the location of the bit for this VLAN id */ ++ bitindex = vlan & 0x1F; /* lower five bits */ ++ ++ bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex)); ++ if (vlan_on) ++ /* Turn on this VLAN id */ ++ bits |= (1 << bitindex); ++ else ++ /* Turn off this VLAN id */ ++ bits &= ~(1 << bitindex); ++ IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_clear_vfta_82598 - Clear VLAN filter table ++ * @hw: pointer to hardware structure ++ * ++ * Clears the VLAN filer table, and the VMDq index associated with the filter ++ **/ ++static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw) ++{ ++ u32 offset; ++ u32 vlanbyte; ++ ++ for (offset = 0; offset < hw->mac.vft_size; offset++) ++ IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); ++ ++ for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) ++ for (offset = 0; offset < hw->mac.vft_size; offset++) ++ IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), ++ 0); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_blink_led_start_82598 - Blink LED based on index. ++ * @hw: pointer to hardware structure ++ * @index: led number to blink ++ **/ ++static s32 ixgbe_blink_led_start_82598(struct ixgbe_hw *hw, u32 index) ++{ ++ ixgbe_link_speed speed = 0; ++ bool link_up = 0; ++ u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); ++ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); ++ ++ /* ++ * Link must be up to auto-blink the LEDs on the 82598EB MAC; ++ * force it if link is down. ++ */ ++ hw->mac.ops.check_link(hw, &speed, &link_up, false); ++ ++ if (!link_up) { ++ autoc_reg |= IXGBE_AUTOC_FLU; ++ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); ++ msleep(10); ++ } ++ ++ led_reg &= ~IXGBE_LED_MODE_MASK(index); ++ led_reg |= IXGBE_LED_BLINK(index); ++ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); ++ IXGBE_WRITE_FLUSH(hw); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_blink_led_stop_82598 - Stop blinking LED based on index. ++ * @hw: pointer to hardware structure ++ * @index: led number to stop blinking ++ **/ ++static s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index) ++{ ++ u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); ++ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); ++ ++ autoc_reg &= ~IXGBE_AUTOC_FLU; ++ autoc_reg |= IXGBE_AUTOC_AN_RESTART; ++ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); ++ ++ led_reg &= ~IXGBE_LED_MODE_MASK(index); ++ led_reg &= ~IXGBE_LED_BLINK(index); ++ led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); ++ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); ++ IXGBE_WRITE_FLUSH(hw); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_read_analog_reg8_82598 - Reads 8 bit Atlas analog register ++ * @hw: pointer to hardware structure ++ * @reg: analog register to read ++ * @val: read value ++ * ++ * Performs read operation to Atlas analog register specified. ++ **/ ++s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) ++{ ++ u32 atlas_ctl; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, ++ IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(10); ++ atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); ++ *val = (u8)atlas_ctl; ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_write_analog_reg8_82598 - Writes 8 bit Atlas analog register ++ * @hw: pointer to hardware structure ++ * @reg: atlas register to write ++ * @val: value to write ++ * ++ * Performs write operation to Atlas analog register specified. ++ **/ ++s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) ++{ ++ u32 atlas_ctl; ++ ++ atlas_ctl = (reg << 8) | val; ++ IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(10); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type ++ * @hw: pointer to hardware structure ++ * ++ * Determines physical layer capabilities of the current configuration. ++ **/ ++s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) ++{ ++ s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; ++ ++ switch (hw->device_id) { ++ case IXGBE_DEV_ID_82598EB_CX4: ++ case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: ++ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; ++ break; ++ case IXGBE_DEV_ID_82598AF_DUAL_PORT: ++ case IXGBE_DEV_ID_82598AF_SINGLE_PORT: ++ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; ++ break; ++ case IXGBE_DEV_ID_82598EB_XF_LR: ++ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; ++ break; ++ ++ default: ++ physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; ++ break; ++ } ++ ++ return physical_layer; ++} ++ + static struct ixgbe_mac_operations mac_ops_82598 = { +- .reset = &ixgbe_reset_hw_82598, ++ .init_hw = &ixgbe_init_hw_generic, ++ .reset_hw = &ixgbe_reset_hw_82598, ++ .start_hw = &ixgbe_start_hw_generic, ++ .clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic, + .get_media_type = &ixgbe_get_media_type_82598, ++ .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82598, ++ .get_mac_addr = &ixgbe_get_mac_addr_generic, ++ .stop_adapter = &ixgbe_stop_adapter_generic, ++ .read_analog_reg8 = &ixgbe_read_analog_reg8_82598, ++ .write_analog_reg8 = &ixgbe_write_analog_reg8_82598, + .setup_link = &ixgbe_setup_mac_link_82598, +- .check_link = &ixgbe_check_mac_link_82598, + .setup_link_speed = &ixgbe_setup_mac_link_speed_82598, +- .get_link_settings = &ixgbe_get_link_settings_82598, ++ .check_link = &ixgbe_check_mac_link_82598, ++ .get_link_capabilities = &ixgbe_get_link_capabilities_82598, ++ .led_on = &ixgbe_led_on_generic, ++ .led_off = &ixgbe_led_off_generic, ++ .blink_led_start = &ixgbe_blink_led_start_82598, ++ .blink_led_stop = &ixgbe_blink_led_stop_82598, ++ .set_rar = &ixgbe_set_rar_generic, ++ .clear_rar = &ixgbe_clear_rar_generic, ++ .set_vmdq = &ixgbe_set_vmdq_82598, ++ .clear_vmdq = &ixgbe_clear_vmdq_82598, ++ .init_rx_addrs = &ixgbe_init_rx_addrs_generic, ++ .update_uc_addr_list = &ixgbe_update_uc_addr_list_generic, ++ .update_mc_addr_list = &ixgbe_update_mc_addr_list_generic, ++ .enable_mc = &ixgbe_enable_mc_generic, ++ .disable_mc = &ixgbe_disable_mc_generic, ++ .clear_vfta = &ixgbe_clear_vfta_82598, ++ .set_vfta = &ixgbe_set_vfta_82598, ++ .setup_fc = &ixgbe_setup_fc_82598, ++}; ++ ++static struct ixgbe_eeprom_operations eeprom_ops_82598 = { ++ .init_params = &ixgbe_init_eeprom_params_generic, ++ .read = &ixgbe_read_eeprom_generic, ++ .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, ++ .update_checksum = &ixgbe_update_eeprom_checksum_generic, ++}; ++ ++static struct ixgbe_phy_operations phy_ops_82598 = { ++ .identify = &ixgbe_identify_phy_generic, ++ /* .identify_sfp = &ixgbe_identify_sfp_module_generic, */ ++ .reset = &ixgbe_reset_phy_generic, ++ .read_reg = &ixgbe_read_phy_reg_generic, ++ .write_reg = &ixgbe_write_phy_reg_generic, ++ .setup_link = &ixgbe_setup_phy_link_generic, ++ .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, + }; + + struct ixgbe_info ixgbe_82598_info = { + .mac = ixgbe_mac_82598EB, + .get_invariants = &ixgbe_get_invariants_82598, + .mac_ops = &mac_ops_82598, ++ .eeprom_ops = &eeprom_ops_82598, ++ .phy_ops = &phy_ops_82598, + }; + +--- a/drivers/net/ixgbe/ixgbe_common.c ++++ b/drivers/net/ixgbe/ixgbe_common.c +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -33,20 +32,28 @@ + #include "ixgbe_common.h" + #include "ixgbe_phy.h" + +-static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw); +- + static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw); ++static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw); + static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw); + static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw); ++static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw); ++static void ixgbe_standby_eeprom(struct ixgbe_hw *hw); ++static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, ++ u16 count); ++static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count); ++static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); ++static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec); ++static void ixgbe_release_eeprom(struct ixgbe_hw *hw); + static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw); + +-static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw); +-static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw); ++static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index); ++static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index); + static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr); + static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr); ++static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq); + + /** +- * ixgbe_start_hw - Prepare hardware for TX/RX ++ * ixgbe_start_hw_generic - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears +@@ -54,7 +61,7 @@ static void ixgbe_add_mc_addr(struct ixg + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +-s32 ixgbe_start_hw(struct ixgbe_hw *hw) ++s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) + { + u32 ctrl_ext; + +@@ -62,22 +69,22 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw) + hw->phy.media_type = hw->mac.ops.get_media_type(hw); + + /* Identify the PHY */ +- ixgbe_identify_phy(hw); ++ hw->phy.ops.identify(hw); + + /* + * Store MAC address from RAR0, clear receive address registers, and + * clear the multicast table + */ +- ixgbe_init_rx_addrs(hw); ++ hw->mac.ops.init_rx_addrs(hw); + + /* Clear the VLAN filter table */ +- ixgbe_clear_vfta(hw); ++ hw->mac.ops.clear_vfta(hw); + + /* Set up link */ + hw->mac.ops.setup_link(hw); + + /* Clear statistics registers */ +- ixgbe_clear_hw_cntrs(hw); ++ hw->mac.ops.clear_hw_cntrs(hw); + + /* Set No Snoop Disable */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); +@@ -92,34 +99,34 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw) + } + + /** +- * ixgbe_init_hw - Generic hardware initialization ++ * ixgbe_init_hw_generic - Generic hardware initialization + * @hw: pointer to hardware structure + * +- * Initialize the hardware by reseting the hardware, filling the bus info ++ * Initialize the hardware by resetting the hardware, filling the bus info + * structure and media type, clears all on chip counters, initializes receive + * address registers, multicast table, VLAN filter table, calls routine to set + * up link and flow control settings, and leaves transmit and receive units + * disabled and uninitialized + **/ +-s32 ixgbe_init_hw(struct ixgbe_hw *hw) ++s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw) + { + /* Reset the hardware */ +- hw->mac.ops.reset(hw); ++ hw->mac.ops.reset_hw(hw); + + /* Start the HW */ +- ixgbe_start_hw(hw); ++ hw->mac.ops.start_hw(hw); + + return 0; + } + + /** +- * ixgbe_clear_hw_cntrs - Generic clear hardware counters ++ * ixgbe_clear_hw_cntrs_generic - Generic clear hardware counters + * @hw: pointer to hardware structure + * + * Clears all hardware statistics counters by reading them from the hardware + * Statistics counters are clear on read. + **/ +-static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw) ++s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw) + { + u16 i = 0; + +@@ -191,7 +198,36 @@ static s32 ixgbe_clear_hw_cntrs(struct i + } + + /** +- * ixgbe_get_mac_addr - Generic get MAC address ++ * ixgbe_read_pba_num_generic - Reads part number from EEPROM ++ * @hw: pointer to hardware structure ++ * @pba_num: stores the part number from the EEPROM ++ * ++ * Reads the part number from the EEPROM. ++ **/ ++s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num) ++{ ++ s32 ret_val; ++ u16 data; ++ ++ ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data); ++ if (ret_val) { ++ hw_dbg(hw, "NVM Read Error\n"); ++ return ret_val; ++ } ++ *pba_num = (u32)(data << 16); ++ ++ ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM1_PTR, &data); ++ if (ret_val) { ++ hw_dbg(hw, "NVM Read Error\n"); ++ return ret_val; ++ } ++ *pba_num |= data; ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_get_mac_addr_generic - Generic get MAC address + * @hw: pointer to hardware structure + * @mac_addr: Adapter MAC address + * +@@ -199,7 +235,7 @@ static s32 ixgbe_clear_hw_cntrs(struct i + * A reset of the adapter must be performed prior to calling this function + * in order for the MAC address to have been loaded from the EEPROM into RAR0 + **/ +-s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr) ++s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) + { + u32 rar_high; + u32 rar_low; +@@ -217,30 +253,8 @@ s32 ixgbe_get_mac_addr(struct ixgbe_hw * + return 0; + } + +-s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num) +-{ +- s32 ret_val; +- u16 data; +- +- ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data); +- if (ret_val) { +- hw_dbg(hw, "NVM Read Error\n"); +- return ret_val; +- } +- *part_num = (u32)(data << 16); +- +- ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data); +- if (ret_val) { +- hw_dbg(hw, "NVM Read Error\n"); +- return ret_val; +- } +- *part_num |= data; +- +- return 0; +-} +- + /** +- * ixgbe_stop_adapter - Generic stop TX/RX units ++ * ixgbe_stop_adapter_generic - Generic stop Tx/Rx units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts, +@@ -248,7 +262,7 @@ s32 ixgbe_read_part_num(struct ixgbe_hw + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +-s32 ixgbe_stop_adapter(struct ixgbe_hw *hw) ++s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) + { + u32 number_of_queues; + u32 reg_val; +@@ -264,6 +278,7 @@ s32 ixgbe_stop_adapter(struct ixgbe_hw * + reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + reg_val &= ~(IXGBE_RXCTRL_RXEN); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); ++ IXGBE_WRITE_FLUSH(hw); + msleep(2); + + /* Clear interrupt mask to stop from interrupts being generated */ +@@ -273,7 +288,7 @@ s32 ixgbe_stop_adapter(struct ixgbe_hw * + IXGBE_READ_REG(hw, IXGBE_EICR); + + /* Disable the transmit unit. Each queue must be disabled. */ +- number_of_queues = hw->mac.num_tx_queues; ++ number_of_queues = hw->mac.max_tx_queues; + for (i = 0; i < number_of_queues; i++) { + reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + if (reg_val & IXGBE_TXDCTL_ENABLE) { +@@ -282,15 +297,22 @@ s32 ixgbe_stop_adapter(struct ixgbe_hw * + } + } + ++ /* ++ * Prevent the PCI-E bus from from hanging by disabling PCI-E master ++ * access and verify no pending requests ++ */ ++ if (ixgbe_disable_pcie_master(hw) != 0) ++ hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); ++ + return 0; + } + + /** +- * ixgbe_led_on - Turns on the software controllable LEDs. ++ * ixgbe_led_on_generic - Turns on the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn on + **/ +-s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index) ++s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index) + { + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + +@@ -304,11 +326,11 @@ s32 ixgbe_led_on(struct ixgbe_hw *hw, u3 + } + + /** +- * ixgbe_led_off - Turns off the software controllable LEDs. ++ * ixgbe_led_off_generic - Turns off the software controllable LEDs. + * @hw: pointer to hardware structure + * @index: led number to turn off + **/ +-s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index) ++s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index) + { + u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + +@@ -321,15 +343,14 @@ s32 ixgbe_led_off(struct ixgbe_hw *hw, u + return 0; + } + +- + /** +- * ixgbe_init_eeprom - Initialize EEPROM params ++ * ixgbe_init_eeprom_params_generic - Initialize EEPROM params + * @hw: pointer to hardware structure + * + * Initializes the EEPROM parameters ixgbe_eeprom_info within the + * ixgbe_hw struct in order to set up EEPROM access. + **/ +-s32 ixgbe_init_eeprom(struct ixgbe_hw *hw) ++s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw) + { + struct ixgbe_eeprom_info *eeprom = &hw->eeprom; + u32 eec; +@@ -337,6 +358,9 @@ s32 ixgbe_init_eeprom(struct ixgbe_hw *h + + if (eeprom->type == ixgbe_eeprom_uninitialized) { + eeprom->type = ixgbe_eeprom_none; ++ /* Set default semaphore delay to 10ms which is a well ++ * tested value */ ++ eeprom->semaphore_delay = 10; + + /* + * Check for EEPROM present first. +@@ -369,18 +393,85 @@ s32 ixgbe_init_eeprom(struct ixgbe_hw *h + } + + /** +- * ixgbe_read_eeprom - Read EEPROM word using EERD ++ * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang ++ * @hw: pointer to hardware structure ++ * @offset: offset within the EEPROM to be read ++ * @data: read 16 bit value from EEPROM ++ * ++ * Reads 16 bit value from EEPROM through bit-bang method ++ **/ ++s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, ++ u16 *data) ++{ ++ s32 status; ++ u16 word_in; ++ u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI; ++ ++ hw->eeprom.ops.init_params(hw); ++ ++ if (offset >= hw->eeprom.word_size) { ++ status = IXGBE_ERR_EEPROM; ++ goto out; ++ } ++ ++ /* Prepare the EEPROM for reading */ ++ status = ixgbe_acquire_eeprom(hw); ++ ++ if (status == 0) { ++ if (ixgbe_ready_eeprom(hw) != 0) { ++ ixgbe_release_eeprom(hw); ++ status = IXGBE_ERR_EEPROM; ++ } ++ } ++ ++ if (status == 0) { ++ ixgbe_standby_eeprom(hw); ++ ++ /* ++ * Some SPI eeproms use the 8th address bit embedded in the ++ * opcode ++ */ ++ if ((hw->eeprom.address_bits == 8) && (offset >= 128)) ++ read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI; ++ ++ /* Send the READ command (opcode + addr) */ ++ ixgbe_shift_out_eeprom_bits(hw, read_opcode, ++ IXGBE_EEPROM_OPCODE_BITS); ++ ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2), ++ hw->eeprom.address_bits); ++ ++ /* Read the data. */ ++ word_in = ixgbe_shift_in_eeprom_bits(hw, 16); ++ *data = (word_in >> 8) | (word_in << 8); ++ ++ /* End this read operation */ ++ ixgbe_release_eeprom(hw); ++ } ++ ++out: ++ return status; ++} ++ ++/** ++ * ixgbe_read_eeprom_generic - Read EEPROM word using EERD + * @hw: pointer to hardware structure + * @offset: offset of word in the EEPROM to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +-s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data) ++s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data) + { + u32 eerd; + s32 status; + ++ hw->eeprom.ops.init_params(hw); ++ ++ if (offset >= hw->eeprom.word_size) { ++ status = IXGBE_ERR_EEPROM; ++ goto out; ++ } ++ + eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) + + IXGBE_EEPROM_READ_REG_START; + +@@ -389,10 +480,11 @@ s32 ixgbe_read_eeprom(struct ixgbe_hw *h + + if (status == 0) + *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >> +- IXGBE_EEPROM_READ_REG_DATA); ++ IXGBE_EEPROM_READ_REG_DATA); + else + hw_dbg(hw, "Eeprom read timed out\n"); + ++out: + return status; + } + +@@ -420,6 +512,58 @@ static s32 ixgbe_poll_eeprom_eerd_done(s + } + + /** ++ * ixgbe_acquire_eeprom - Acquire EEPROM using bit-bang ++ * @hw: pointer to hardware structure ++ * ++ * Prepares EEPROM for access using bit-bang method. This function should ++ * be called before issuing a command to the EEPROM. ++ **/ ++static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw) ++{ ++ s32 status = 0; ++ u32 eec; ++ u32 i; ++ ++ if (ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0) ++ status = IXGBE_ERR_SWFW_SYNC; ++ ++ if (status == 0) { ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ ++ /* Request EEPROM Access */ ++ eec |= IXGBE_EEC_REQ; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ ++ for (i = 0; i < IXGBE_EEPROM_GRANT_ATTEMPTS; i++) { ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ if (eec & IXGBE_EEC_GNT) ++ break; ++ udelay(5); ++ } ++ ++ /* Release if grant not acquired */ ++ if (!(eec & IXGBE_EEC_GNT)) { ++ eec &= ~IXGBE_EEC_REQ; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ hw_dbg(hw, "Could not acquire EEPROM grant\n"); ++ ++ ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); ++ status = IXGBE_ERR_EEPROM; ++ } ++ } ++ ++ /* Setup EEPROM for Read/Write */ ++ if (status == 0) { ++ /* Clear CS and SK */ ++ eec &= ~(IXGBE_EEC_CS | IXGBE_EEC_SK); ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(1); ++ } ++ return status; ++} ++ ++/** + * ixgbe_get_eeprom_semaphore - Get hardware semaphore + * @hw: pointer to hardware structure + * +@@ -475,7 +619,7 @@ static s32 ixgbe_get_eeprom_semaphore(st + */ + if (i >= timeout) { + hw_dbg(hw, "Driver can't access the Eeprom - Semaphore " +- "not granted.\n"); ++ "not granted.\n"); + ixgbe_release_eeprom_semaphore(hw); + status = IXGBE_ERR_EEPROM; + } +@@ -503,6 +647,217 @@ static void ixgbe_release_eeprom_semapho + } + + /** ++ * ixgbe_ready_eeprom - Polls for EEPROM ready ++ * @hw: pointer to hardware structure ++ **/ ++static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) ++{ ++ s32 status = 0; ++ u16 i; ++ u8 spi_stat_reg; ++ ++ /* ++ * Read "Status Register" repeatedly until the LSB is cleared. The ++ * EEPROM will signal that the command has been completed by clearing ++ * bit 0 of the internal status register. If it's not cleared within ++ * 5 milliseconds, then error out. ++ */ ++ for (i = 0; i < IXGBE_EEPROM_MAX_RETRY_SPI; i += 5) { ++ ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_RDSR_OPCODE_SPI, ++ IXGBE_EEPROM_OPCODE_BITS); ++ spi_stat_reg = (u8)ixgbe_shift_in_eeprom_bits(hw, 8); ++ if (!(spi_stat_reg & IXGBE_EEPROM_STATUS_RDY_SPI)) ++ break; ++ ++ udelay(5); ++ ixgbe_standby_eeprom(hw); ++ }; ++ ++ /* ++ * On some parts, SPI write time could vary from 0-20mSec on 3.3V ++ * devices (and only 0-5mSec on 5V devices) ++ */ ++ if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) { ++ hw_dbg(hw, "SPI EEPROM Status error\n"); ++ status = IXGBE_ERR_EEPROM; ++ } ++ ++ return status; ++} ++ ++/** ++ * ixgbe_standby_eeprom - Returns EEPROM to a "standby" state ++ * @hw: pointer to hardware structure ++ **/ ++static void ixgbe_standby_eeprom(struct ixgbe_hw *hw) ++{ ++ u32 eec; ++ ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ ++ /* Toggle CS to flush commands */ ++ eec |= IXGBE_EEC_CS; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(1); ++ eec &= ~IXGBE_EEC_CS; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(1); ++} ++ ++/** ++ * ixgbe_shift_out_eeprom_bits - Shift data bits out to the EEPROM. ++ * @hw: pointer to hardware structure ++ * @data: data to send to the EEPROM ++ * @count: number of bits to shift out ++ **/ ++static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, ++ u16 count) ++{ ++ u32 eec; ++ u32 mask; ++ u32 i; ++ ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ ++ /* ++ * Mask is used to shift "count" bits of "data" out to the EEPROM ++ * one bit at a time. Determine the starting bit based on count ++ */ ++ mask = 0x01 << (count - 1); ++ ++ for (i = 0; i < count; i++) { ++ /* ++ * A "1" is shifted out to the EEPROM by setting bit "DI" to a ++ * "1", and then raising and then lowering the clock (the SK ++ * bit controls the clock input to the EEPROM). A "0" is ++ * shifted out to the EEPROM by setting "DI" to "0" and then ++ * raising and then lowering the clock. ++ */ ++ if (data & mask) ++ eec |= IXGBE_EEC_DI; ++ else ++ eec &= ~IXGBE_EEC_DI; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ IXGBE_WRITE_FLUSH(hw); ++ ++ udelay(1); ++ ++ ixgbe_raise_eeprom_clk(hw, &eec); ++ ixgbe_lower_eeprom_clk(hw, &eec); ++ ++ /* ++ * Shift mask to signify next bit of data to shift in to the ++ * EEPROM ++ */ ++ mask = mask >> 1; ++ }; ++ ++ /* We leave the "DI" bit set to "0" when we leave this routine. */ ++ eec &= ~IXGBE_EEC_DI; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ IXGBE_WRITE_FLUSH(hw); ++} ++ ++/** ++ * ixgbe_shift_in_eeprom_bits - Shift data bits in from the EEPROM ++ * @hw: pointer to hardware structure ++ **/ ++static u16 ixgbe_shift_in_eeprom_bits(struct ixgbe_hw *hw, u16 count) ++{ ++ u32 eec; ++ u32 i; ++ u16 data = 0; ++ ++ /* ++ * In order to read a register from the EEPROM, we need to shift ++ * 'count' bits in from the EEPROM. Bits are "shifted in" by raising ++ * the clock input to the EEPROM (setting the SK bit), and then reading ++ * the value of the "DO" bit. During this "shifting in" process the ++ * "DI" bit should always be clear. ++ */ ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ ++ eec &= ~(IXGBE_EEC_DO | IXGBE_EEC_DI); ++ ++ for (i = 0; i < count; i++) { ++ data = data << 1; ++ ixgbe_raise_eeprom_clk(hw, &eec); ++ ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ ++ eec &= ~(IXGBE_EEC_DI); ++ if (eec & IXGBE_EEC_DO) ++ data |= 1; ++ ++ ixgbe_lower_eeprom_clk(hw, &eec); ++ } ++ ++ return data; ++} ++ ++/** ++ * ixgbe_raise_eeprom_clk - Raises the EEPROM's clock input. ++ * @hw: pointer to hardware structure ++ * @eec: EEC register's current value ++ **/ ++static void ixgbe_raise_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) ++{ ++ /* ++ * Raise the clock input to the EEPROM ++ * (setting the SK bit), then delay ++ */ ++ *eec = *eec | IXGBE_EEC_SK; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(1); ++} ++ ++/** ++ * ixgbe_lower_eeprom_clk - Lowers the EEPROM's clock input. ++ * @hw: pointer to hardware structure ++ * @eecd: EECD's current value ++ **/ ++static void ixgbe_lower_eeprom_clk(struct ixgbe_hw *hw, u32 *eec) ++{ ++ /* ++ * Lower the clock input to the EEPROM (clearing the SK bit), then ++ * delay ++ */ ++ *eec = *eec & ~IXGBE_EEC_SK; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, *eec); ++ IXGBE_WRITE_FLUSH(hw); ++ udelay(1); ++} ++ ++/** ++ * ixgbe_release_eeprom - Release EEPROM, release semaphores ++ * @hw: pointer to hardware structure ++ **/ ++static void ixgbe_release_eeprom(struct ixgbe_hw *hw) ++{ ++ u32 eec; ++ ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ ++ eec |= IXGBE_EEC_CS; /* Pull CS high */ ++ eec &= ~IXGBE_EEC_SK; /* Lower SCK */ ++ ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ IXGBE_WRITE_FLUSH(hw); ++ ++ udelay(1); ++ ++ /* Stop requesting EEPROM access */ ++ eec &= ~IXGBE_EEC_REQ; ++ IXGBE_WRITE_REG(hw, IXGBE_EEC, eec); ++ ++ ixgbe_release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); ++} ++ ++/** + * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum + * @hw: pointer to hardware structure + **/ +@@ -517,7 +872,7 @@ static u16 ixgbe_calc_eeprom_checksum(st + + /* Include 0x0-0x3F in the checksum */ + for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) { +- if (ixgbe_read_eeprom(hw, i, &word) != 0) { ++ if (hw->eeprom.ops.read(hw, i, &word) != 0) { + hw_dbg(hw, "EEPROM read failed\n"); + break; + } +@@ -526,15 +881,15 @@ static u16 ixgbe_calc_eeprom_checksum(st + + /* Include all data from pointers except for the fw pointer */ + for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) { +- ixgbe_read_eeprom(hw, i, &pointer); ++ hw->eeprom.ops.read(hw, i, &pointer); + + /* Make sure the pointer seems valid */ + if (pointer != 0xFFFF && pointer != 0) { +- ixgbe_read_eeprom(hw, pointer, &length); ++ hw->eeprom.ops.read(hw, pointer, &length); + + if (length != 0xFFFF && length != 0) { + for (j = pointer+1; j <= pointer+length; j++) { +- ixgbe_read_eeprom(hw, j, &word); ++ hw->eeprom.ops.read(hw, j, &word); + checksum += word; + } + } +@@ -547,14 +902,15 @@ static u16 ixgbe_calc_eeprom_checksum(st + } + + /** +- * ixgbe_validate_eeprom_checksum - Validate EEPROM checksum ++ * ixgbe_validate_eeprom_checksum_generic - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum_val: calculated checksum + * + * Performs checksum calculation and validates the EEPROM checksum. If the + * caller does not need checksum_val, the value can be NULL. + **/ +-s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val) ++s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, ++ u16 *checksum_val) + { + s32 status; + u16 checksum; +@@ -565,12 +921,12 @@ s32 ixgbe_validate_eeprom_checksum(struc + * not continue or we could be in for a very long wait while every + * EEPROM read fails + */ +- status = ixgbe_read_eeprom(hw, 0, &checksum); ++ status = hw->eeprom.ops.read(hw, 0, &checksum); + + if (status == 0) { + checksum = ixgbe_calc_eeprom_checksum(hw); + +- ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); ++ hw->eeprom.ops.read(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum); + + /* + * Verify read checksum from EEPROM is the same as +@@ -590,6 +946,33 @@ s32 ixgbe_validate_eeprom_checksum(struc + } + + /** ++ * ixgbe_update_eeprom_checksum_generic - Updates the EEPROM checksum ++ * @hw: pointer to hardware structure ++ **/ ++s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw) ++{ ++ s32 status; ++ u16 checksum; ++ ++ /* ++ * Read the first word from the EEPROM. If this times out or fails, do ++ * not continue or we could be in for a very long wait while every ++ * EEPROM read fails ++ */ ++ status = hw->eeprom.ops.read(hw, 0, &checksum); ++ ++ if (status == 0) { ++ checksum = ixgbe_calc_eeprom_checksum(hw); ++ status = hw->eeprom.ops.write(hw, IXGBE_EEPROM_CHECKSUM, ++ checksum); ++ } else { ++ hw_dbg(hw, "EEPROM read failed\n"); ++ } ++ ++ return status; ++} ++ ++/** + * ixgbe_validate_mac_addr - Validate MAC address + * @mac_addr: pointer to MAC address. + * +@@ -607,61 +990,140 @@ s32 ixgbe_validate_mac_addr(u8 *mac_addr + status = IXGBE_ERR_INVALID_MAC_ADDR; + /* Reject the zero address */ + else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 && +- mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) ++ mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) + status = IXGBE_ERR_INVALID_MAC_ADDR; + + return status; + } + + /** +- * ixgbe_set_rar - Set RX address register ++ * ixgbe_set_rar_generic - Set Rx address register + * @hw: pointer to hardware structure +- * @addr: Address to put into receive address register + * @index: Receive address register to write +- * @vind: Vind to set RAR to ++ * @addr: Address to put into receive address register ++ * @vmdq: VMDq "set" or "pool" index + * @enable_addr: set flag that address is active + * + * Puts an ethernet address into a receive address register. + **/ +-s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, +- u32 enable_addr) ++s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, ++ u32 enable_addr) + { + u32 rar_low, rar_high; ++ u32 rar_entries = hw->mac.num_rar_entries; + +- /* +- * HW expects these in little endian so we reverse the byte order from +- * network order (big endian) to little endian +- */ +- rar_low = ((u32)addr[0] | +- ((u32)addr[1] << 8) | +- ((u32)addr[2] << 16) | +- ((u32)addr[3] << 24)); +- +- rar_high = ((u32)addr[4] | +- ((u32)addr[5] << 8) | +- ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK)); ++ /* setup VMDq pool selection before this RAR gets enabled */ ++ hw->mac.ops.set_vmdq(hw, index, vmdq); ++ ++ /* Make sure we are using a valid rar index range */ ++ if (index < rar_entries) { ++ /* ++ * HW expects these in little endian so we reverse the byte ++ * order from network order (big endian) to little endian ++ */ ++ rar_low = ((u32)addr[0] | ++ ((u32)addr[1] << 8) | ++ ((u32)addr[2] << 16) | ++ ((u32)addr[3] << 24)); ++ /* ++ * Some parts put the VMDq setting in the extra RAH bits, ++ * so save everything except the lower 16 bits that hold part ++ * of the address and the address valid bit. ++ */ ++ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); ++ rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); ++ rar_high |= ((u32)addr[4] | ((u32)addr[5] << 8)); + +- if (enable_addr != 0) +- rar_high |= IXGBE_RAH_AV; ++ if (enable_addr != 0) ++ rar_high |= IXGBE_RAH_AV; + +- IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); +- IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); ++ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); ++ } else { ++ hw_dbg(hw, "RAR index %d is out of range.\n", index); ++ } + + return 0; + } + + /** +- * ixgbe_init_rx_addrs - Initializes receive address filters. ++ * ixgbe_clear_rar_generic - Remove Rx address register ++ * @hw: pointer to hardware structure ++ * @index: Receive address register to write ++ * ++ * Clears an ethernet address from a receive address register. ++ **/ ++s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) ++{ ++ u32 rar_high; ++ u32 rar_entries = hw->mac.num_rar_entries; ++ ++ /* Make sure we are using a valid rar index range */ ++ if (index < rar_entries) { ++ /* ++ * Some parts put the VMDq setting in the extra RAH bits, ++ * so save everything except the lower 16 bits that hold part ++ * of the address and the address valid bit. ++ */ ++ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); ++ rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); ++ ++ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); ++ } else { ++ hw_dbg(hw, "RAR index %d is out of range.\n", index); ++ } ++ ++ /* clear VMDq pool/queue selection for this RAR */ ++ hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_enable_rar - Enable Rx address register ++ * @hw: pointer to hardware structure ++ * @index: index into the RAR table ++ * ++ * Enables the select receive address register. ++ **/ ++static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index) ++{ ++ u32 rar_high; ++ ++ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); ++ rar_high |= IXGBE_RAH_AV; ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); ++} ++ ++/** ++ * ixgbe_disable_rar - Disable Rx address register ++ * @hw: pointer to hardware structure ++ * @index: index into the RAR table ++ * ++ * Disables the select receive address register. ++ **/ ++static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index) ++{ ++ u32 rar_high; ++ ++ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); ++ rar_high &= (~IXGBE_RAH_AV); ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); ++} ++ ++/** ++ * ixgbe_init_rx_addrs_generic - Initializes receive address filters. + * @hw: pointer to hardware structure + * + * Places the MAC address in receive address register 0 and clears the rest +- * of the receive addresss registers. Clears the multicast table. Assumes ++ * of the receive address registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + **/ +-static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw) ++s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw) + { + u32 i; +- u32 rar_entries = hw->mac.num_rx_addrs; ++ u32 rar_entries = hw->mac.num_rar_entries; + + /* + * If the current mac address is valid, assume it is a software override +@@ -671,29 +1133,30 @@ static s32 ixgbe_init_rx_addrs(struct ix + if (ixgbe_validate_mac_addr(hw->mac.addr) == + IXGBE_ERR_INVALID_MAC_ADDR) { + /* Get the MAC address from the RAR0 for later reference */ +- ixgbe_get_mac_addr(hw, hw->mac.addr); ++ hw->mac.ops.get_mac_addr(hw, hw->mac.addr); + + hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ", +- hw->mac.addr[0], hw->mac.addr[1], +- hw->mac.addr[2]); ++ hw->mac.addr[0], hw->mac.addr[1], ++ hw->mac.addr[2]); + hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], +- hw->mac.addr[4], hw->mac.addr[5]); ++ hw->mac.addr[4], hw->mac.addr[5]); + } else { + /* Setup the receive address. */ + hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); + hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ", +- hw->mac.addr[0], hw->mac.addr[1], +- hw->mac.addr[2]); ++ hw->mac.addr[0], hw->mac.addr[1], ++ hw->mac.addr[2]); + hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3], +- hw->mac.addr[4], hw->mac.addr[5]); ++ hw->mac.addr[4], hw->mac.addr[5]); + +- ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); ++ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + } ++ hw->addr_ctrl.overflow_promisc = 0; + + hw->addr_ctrl.rar_used_count = 1; + + /* Zero out the other receive addresses. */ +- hw_dbg(hw, "Clearing RAR[1-15]\n"); ++ hw_dbg(hw, "Clearing RAR[1-%d]\n", rar_entries - 1); + for (i = 1; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); +@@ -705,9 +1168,113 @@ static s32 ixgbe_init_rx_addrs(struct ix + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); + + hw_dbg(hw, " Clearing MTA\n"); +- for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) ++ for (i = 0; i < hw->mac.mcft_size; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + ++ if (hw->mac.ops.init_uta_tables) ++ hw->mac.ops.init_uta_tables(hw); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_add_uc_addr - Adds a secondary unicast address. ++ * @hw: pointer to hardware structure ++ * @addr: new address ++ * ++ * Adds it to unused receive address register or goes into promiscuous mode. ++ **/ ++static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) ++{ ++ u32 rar_entries = hw->mac.num_rar_entries; ++ u32 rar; ++ ++ hw_dbg(hw, " UC Addr = %.2X %.2X %.2X %.2X %.2X %.2X\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ ++ /* ++ * Place this address in the RAR if there is room, ++ * else put the controller into promiscuous mode ++ */ ++ if (hw->addr_ctrl.rar_used_count < rar_entries) { ++ rar = hw->addr_ctrl.rar_used_count - ++ hw->addr_ctrl.mc_addr_in_rar_count; ++ hw->mac.ops.set_rar(hw, rar, addr, vmdq, IXGBE_RAH_AV); ++ hw_dbg(hw, "Added a secondary address to RAR[%d]\n", rar); ++ hw->addr_ctrl.rar_used_count++; ++ } else { ++ hw->addr_ctrl.overflow_promisc++; ++ } ++ ++ hw_dbg(hw, "ixgbe_add_uc_addr Complete\n"); ++} ++ ++/** ++ * ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses ++ * @hw: pointer to hardware structure ++ * @addr_list: the list of new addresses ++ * @addr_count: number of addresses ++ * @next: iterator function to walk the address list ++ * ++ * The given list replaces any existing list. Clears the secondary addrs from ++ * receive address registers. Uses unused receive address registers for the ++ * first secondary addresses, and falls back to promiscuous mode as needed. ++ * ++ * Drivers using secondary unicast addresses must set user_set_promisc when ++ * manually putting the device into promiscuous mode. ++ **/ ++s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, ++ u32 addr_count, ixgbe_mc_addr_itr next) ++{ ++ u8 *addr; ++ u32 i; ++ u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc; ++ u32 uc_addr_in_use; ++ u32 fctrl; ++ u32 vmdq; ++ ++ /* ++ * Clear accounting of old secondary address list, ++ * don't count RAR[0] ++ */ ++ uc_addr_in_use = hw->addr_ctrl.rar_used_count - ++ hw->addr_ctrl.mc_addr_in_rar_count - 1; ++ hw->addr_ctrl.rar_used_count -= uc_addr_in_use; ++ hw->addr_ctrl.overflow_promisc = 0; ++ ++ /* Zero out the other receive addresses */ ++ hw_dbg(hw, "Clearing RAR[1-%d]\n", uc_addr_in_use); ++ for (i = 1; i <= uc_addr_in_use; i++) { ++ IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); ++ IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); ++ } ++ ++ /* Add the new addresses */ ++ for (i = 0; i < addr_count; i++) { ++ hw_dbg(hw, " Adding the secondary addresses:\n"); ++ addr = next(hw, &addr_list, &vmdq); ++ ixgbe_add_uc_addr(hw, addr, vmdq); ++ } ++ ++ if (hw->addr_ctrl.overflow_promisc) { ++ /* enable promisc if not already in overflow or set by user */ ++ if (!old_promisc_setting && !hw->addr_ctrl.user_set_promisc) { ++ hw_dbg(hw, " Entering address overflow promisc mode\n"); ++ fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); ++ fctrl |= IXGBE_FCTRL_UPE; ++ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); ++ } ++ } else { ++ /* only disable if set by overflow, not by user */ ++ if (old_promisc_setting && !hw->addr_ctrl.user_set_promisc) { ++ hw_dbg(hw, " Leaving address overflow promisc mode\n"); ++ fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); ++ fctrl &= ~IXGBE_FCTRL_UPE; ++ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); ++ } ++ } ++ ++ hw_dbg(hw, "ixgbe_update_uc_addr_list_generic Complete\n"); + return 0; + } + +@@ -720,7 +1287,7 @@ static s32 ixgbe_init_rx_addrs(struct ix + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set +- * by the MO field of the MCSTCTRL. The MO field is set during initalization ++ * by the MO field of the MCSTCTRL. The MO field is set during initialization + * to mc_filter_type. + **/ + static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) +@@ -728,19 +1295,19 @@ static s32 ixgbe_mta_vector(struct ixgbe + u32 vector = 0; + + switch (hw->mac.mc_filter_type) { +- case 0: /* use bits [47:36] of the address */ ++ case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; +- case 1: /* use bits [46:35] of the address */ ++ case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; +- case 2: /* use bits [45:34] of the address */ ++ case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; +- case 3: /* use bits [43:32] of the address */ ++ case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; +- default: /* Invalid mc_filter_type */ ++ default: /* Invalid mc_filter_type */ + hw_dbg(hw, "MC filter type param set incorrectly\n"); + break; + } +@@ -794,21 +1361,22 @@ static void ixgbe_set_mta(struct ixgbe_h + **/ + static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr) + { +- u32 rar_entries = hw->mac.num_rx_addrs; ++ u32 rar_entries = hw->mac.num_rar_entries; ++ u32 rar; + + hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n", +- mc_addr[0], mc_addr[1], mc_addr[2], +- mc_addr[3], mc_addr[4], mc_addr[5]); ++ mc_addr[0], mc_addr[1], mc_addr[2], ++ mc_addr[3], mc_addr[4], mc_addr[5]); + + /* + * Place this multicast address in the RAR if there is room, + * else put it in the MTA + */ + if (hw->addr_ctrl.rar_used_count < rar_entries) { +- ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count, +- mc_addr, 0, IXGBE_RAH_AV); +- hw_dbg(hw, "Added a multicast address to RAR[%d]\n", +- hw->addr_ctrl.rar_used_count); ++ /* use RAR from the end up for multicast */ ++ rar = rar_entries - hw->addr_ctrl.mc_addr_in_rar_count - 1; ++ hw->mac.ops.set_rar(hw, rar, mc_addr, 0, IXGBE_RAH_AV); ++ hw_dbg(hw, "Added a multicast address to RAR[%d]\n", rar); + hw->addr_ctrl.rar_used_count++; + hw->addr_ctrl.mc_addr_in_rar_count++; + } else { +@@ -819,22 +1387,23 @@ static void ixgbe_add_mc_addr(struct ixg + } + + /** +- * ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses ++ * ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses + * @hw: pointer to hardware structure + * @mc_addr_list: the list of new multicast addresses + * @mc_addr_count: number of addresses +- * @pad: number of bytes between addresses in the list ++ * @next: iterator function to walk the multicast address list + * + * The given list replaces any existing list. Clears the MC addrs from receive +- * address registers and the multicast table. Uses unsed receive address ++ * address registers and the multicast table. Uses unused receive address + * registers for the first multicast addresses, and hashes the rest into the + * multicast table. + **/ +-s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, +- u32 mc_addr_count, u32 pad) ++s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, ++ u32 mc_addr_count, ixgbe_mc_addr_itr next) + { + u32 i; +- u32 rar_entries = hw->mac.num_rx_addrs; ++ u32 rar_entries = hw->mac.num_rar_entries; ++ u32 vmdq; + + /* + * Set the new number of MC addresses that we are being requested to +@@ -846,7 +1415,8 @@ s32 ixgbe_update_mc_addr_list(struct ixg + hw->addr_ctrl.mta_in_use = 0; + + /* Zero out the other receive addresses. */ +- hw_dbg(hw, "Clearing RAR[1-15]\n"); ++ hw_dbg(hw, "Clearing RAR[%d-%d]\n", hw->addr_ctrl.rar_used_count, ++ rar_entries - 1); + for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); +@@ -854,186 +1424,67 @@ s32 ixgbe_update_mc_addr_list(struct ixg + + /* Clear the MTA */ + hw_dbg(hw, " Clearing MTA\n"); +- for (i = 0; i < IXGBE_MC_TBL_SIZE; i++) ++ for (i = 0; i < hw->mac.mcft_size; i++) + IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0); + + /* Add the new addresses */ + for (i = 0; i < mc_addr_count; i++) { + hw_dbg(hw, " Adding the multicast addresses:\n"); +- ixgbe_add_mc_addr(hw, mc_addr_list + +- (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad))); ++ ixgbe_add_mc_addr(hw, next(hw, &mc_addr_list, &vmdq)); + } + + /* Enable mta */ + if (hw->addr_ctrl.mta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, +- IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); ++ IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); + +- hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n"); ++ hw_dbg(hw, "ixgbe_update_mc_addr_list_generic Complete\n"); + return 0; + } + + /** +- * ixgbe_clear_vfta - Clear VLAN filter table ++ * ixgbe_enable_mc_generic - Enable multicast address in RAR + * @hw: pointer to hardware structure + * +- * Clears the VLAN filer table, and the VMDq index associated with the filter ++ * Enables multicast address in RAR and the use of the multicast hash table. + **/ +-static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw) ++s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw) + { +- u32 offset; +- u32 vlanbyte; +- +- for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) +- IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0); +- +- for (vlanbyte = 0; vlanbyte < 4; vlanbyte++) +- for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++) +- IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset), +- 0); +- +- return 0; +-} ++ u32 i; ++ u32 rar_entries = hw->mac.num_rar_entries; ++ struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; + +-/** +- * ixgbe_set_vfta - Set VLAN filter table +- * @hw: pointer to hardware structure +- * @vlan: VLAN id to write to VLAN filter +- * @vind: VMDq output index that maps queue to VLAN id in VFTA +- * @vlan_on: boolean flag to turn on/off VLAN in VFTA +- * +- * Turn on/off specified VLAN in the VLAN filter table. +- **/ +-s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, +- bool vlan_on) +-{ +- u32 VftaIndex; +- u32 BitOffset; +- u32 VftaReg; +- u32 VftaByte; +- +- /* Determine 32-bit word position in array */ +- VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */ +- +- /* Determine the location of the (VMD) queue index */ +- VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */ +- BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */ +- +- /* Set the nibble for VMD queue index */ +- VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex)); +- VftaReg &= (~(0x0F << BitOffset)); +- VftaReg |= (vind << BitOffset); +- IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg); +- +- /* Determine the location of the bit for this VLAN id */ +- BitOffset = vlan & 0x1F; /* lower five bits */ +- +- VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex)); +- if (vlan_on) +- /* Turn on this VLAN id */ +- VftaReg |= (1 << BitOffset); +- else +- /* Turn off this VLAN id */ +- VftaReg &= ~(1 << BitOffset); +- IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg); ++ if (a->mc_addr_in_rar_count > 0) ++ for (i = (rar_entries - a->mc_addr_in_rar_count); ++ i < rar_entries; i++) ++ ixgbe_enable_rar(hw, i); ++ ++ if (a->mta_in_use > 0) ++ IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, IXGBE_MCSTCTRL_MFE | ++ hw->mac.mc_filter_type); + + return 0; + } + + /** +- * ixgbe_setup_fc - Configure flow control settings ++ * ixgbe_disable_mc_generic - Disable multicast address in RAR + * @hw: pointer to hardware structure +- * @packetbuf_num: packet buffer number (0-7) + * +- * Configures the flow control settings based on SW configuration. +- * This function is used for 802.3x flow control configuration only. ++ * Disables multicast address in RAR and the use of the multicast hash table. + **/ +-s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) ++s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) + { +- u32 frctl_reg; +- u32 rmcs_reg; +- +- if (packetbuf_num < 0 || packetbuf_num > 7) +- hw_dbg(hw, "Invalid packet buffer number [%d], expected range " +- "is 0-7\n", packetbuf_num); +- +- frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); +- frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE); +- +- rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS); +- rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X); +- +- /* +- * We want to save off the original Flow Control configuration just in +- * case we get disconnected and then reconnected into a different hub +- * or switch with different Flow Control capabilities. +- */ +- hw->fc.type = hw->fc.original_type; +- +- /* +- * The possible values of the "flow_control" parameter are: +- * 0: Flow control is completely disabled +- * 1: Rx flow control is enabled (we can receive pause frames but not +- * send pause frames). +- * 2: Tx flow control is enabled (we can send pause frames but we do not +- * support receiving pause frames) +- * 3: Both Rx and TX flow control (symmetric) are enabled. +- * other: Invalid. +- */ +- switch (hw->fc.type) { +- case ixgbe_fc_none: +- break; +- case ixgbe_fc_rx_pause: +- /* +- * RX Flow control is enabled, +- * and TX Flow control is disabled. +- */ +- frctl_reg |= IXGBE_FCTRL_RFCE; +- break; +- case ixgbe_fc_tx_pause: +- /* +- * TX Flow control is enabled, and RX Flow control is disabled, +- * by a software over-ride. +- */ +- rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; +- break; +- case ixgbe_fc_full: +- /* +- * Flow control (both RX and TX) is enabled by a software +- * over-ride. +- */ +- frctl_reg |= IXGBE_FCTRL_RFCE; +- rmcs_reg |= IXGBE_RMCS_TFCE_802_3X; +- break; +- default: +- /* We should never get here. The value should be 0-3. */ +- hw_dbg(hw, "Flow control param set incorrectly\n"); +- break; +- } +- +- /* Enable 802.3x based flow control settings. */ +- IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg); +- IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); ++ u32 i; ++ u32 rar_entries = hw->mac.num_rar_entries; ++ struct ixgbe_addr_filter_info *a = &hw->addr_ctrl; + +- /* +- * We need to set up the Receive Threshold high and low water +- * marks as well as (optionally) enabling the transmission of +- * XON frames. +- */ +- if (hw->fc.type & ixgbe_fc_tx_pause) { +- if (hw->fc.send_xon) { +- IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), +- (hw->fc.low_water | IXGBE_FCRTL_XONE)); +- } else { +- IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), +- hw->fc.low_water); +- } +- IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), +- (hw->fc.high_water)|IXGBE_FCRTH_FCEN); +- } ++ if (a->mc_addr_in_rar_count > 0) ++ for (i = (rar_entries - a->mc_addr_in_rar_count); ++ i < rar_entries; i++) ++ ixgbe_disable_rar(hw, i); + +- IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time); +- IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); ++ if (a->mta_in_use > 0) ++ IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type); + + return 0; + } +@@ -1049,13 +1500,24 @@ s32 ixgbe_setup_fc(struct ixgbe_hw *hw, + **/ + s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) + { +- u32 ctrl; +- s32 i; ++ u32 i; ++ u32 reg_val; ++ u32 number_of_queues; + s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + +- ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL); +- ctrl |= IXGBE_CTRL_GIO_DIS; +- IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl); ++ /* Disable the receive unit by stopping each queue */ ++ number_of_queues = hw->mac.max_rx_queues; ++ for (i = 0; i < number_of_queues; i++) { ++ reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); ++ if (reg_val & IXGBE_RXDCTL_ENABLE) { ++ reg_val &= ~IXGBE_RXDCTL_ENABLE; ++ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), reg_val); ++ } ++ } ++ ++ reg_val = IXGBE_READ_REG(hw, IXGBE_CTRL); ++ reg_val |= IXGBE_CTRL_GIO_DIS; ++ IXGBE_WRITE_REG(hw, IXGBE_CTRL, reg_val); + + for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) { +@@ -1070,11 +1532,11 @@ s32 ixgbe_disable_pcie_master(struct ixg + + + /** +- * ixgbe_acquire_swfw_sync - Aquire SWFW semaphore ++ * ixgbe_acquire_swfw_sync - Acquire SWFW semaphore + * @hw: pointer to hardware structure +- * @mask: Mask to specify wich semaphore to acquire ++ * @mask: Mask to specify which semaphore to acquire + * +- * Aquires the SWFW semaphore throught the GSSR register for the specified ++ * Acquires the SWFW semaphore thought the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ + s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) +@@ -1116,9 +1578,9 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe + /** + * ixgbe_release_swfw_sync - Release SWFW semaphore + * @hw: pointer to hardware structure +- * @mask: Mask to specify wich semaphore to release ++ * @mask: Mask to specify which semaphore to release + * +- * Releases the SWFW semaphore throught the GSSR register for the specified ++ * Releases the SWFW semaphore thought the GSSR register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ + void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) +@@ -1135,45 +1597,3 @@ void ixgbe_release_swfw_sync(struct ixgb + ixgbe_release_eeprom_semaphore(hw); + } + +-/** +- * ixgbe_read_analog_reg8 - Reads 8 bit Atlas analog register +- * @hw: pointer to hardware structure +- * @reg: analog register to read +- * @val: read value +- * +- * Performs write operation to analog register specified. +- **/ +-s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val) +-{ +- u32 atlas_ctl; +- +- IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, +- IXGBE_ATLASCTL_WRITE_CMD | (reg << 8)); +- IXGBE_WRITE_FLUSH(hw); +- udelay(10); +- atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL); +- *val = (u8)atlas_ctl; +- +- return 0; +-} +- +-/** +- * ixgbe_write_analog_reg8 - Writes 8 bit Atlas analog register +- * @hw: pointer to hardware structure +- * @reg: atlas register to write +- * @val: value to write +- * +- * Performs write operation to Atlas analog register specified. +- **/ +-s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val) +-{ +- u32 atlas_ctl; +- +- atlas_ctl = (reg << 8) | val; +- IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl); +- IXGBE_WRITE_FLUSH(hw); +- udelay(10); +- +- return 0; +-} +- +--- a/drivers/net/ixgbe/ixgbe_common.h ++++ b/drivers/net/ixgbe/ixgbe_common.h +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -31,34 +30,45 @@ + + #include "ixgbe_type.h" + +-s32 ixgbe_init_hw(struct ixgbe_hw *hw); +-s32 ixgbe_start_hw(struct ixgbe_hw *hw); +-s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr); +-s32 ixgbe_stop_adapter(struct ixgbe_hw *hw); +-s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num); +- +-s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index); +-s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index); +- +-s32 ixgbe_init_eeprom(struct ixgbe_hw *hw); +-s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data); +-s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val); +- +-s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind, +- u32 enable_addr); +-s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list, +- u32 mc_addr_count, u32 pad); +-s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); +-s32 ixgbe_validate_mac_addr(u8 *mac_addr); +- +-s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num); ++s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw); ++s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw); ++s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw); ++s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw); ++s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num); ++s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr); ++s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw); ++s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw); ++ ++s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index); ++s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index); ++ ++s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw); ++s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data); ++s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset, ++ u16 *data); ++s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw, ++ u16 *checksum_val); ++s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw); ++ ++s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, ++ u32 enable_addr); ++s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index); ++s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw); ++s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list, ++ u32 mc_addr_count, ++ ixgbe_mc_addr_itr func); ++s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list, ++ u32 addr_count, ixgbe_mc_addr_itr func); ++s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw); ++s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw); + ++s32 ixgbe_validate_mac_addr(u8 *mac_addr); + s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask); + void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask); + s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw); + +-s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val); +-s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val); ++s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val); ++s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val); + + #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) + +--- a/drivers/net/ixgbe/ixgbe_ethtool.c ++++ b/drivers/net/ixgbe/ixgbe_ethtool.c +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -48,7 +47,7 @@ struct ixgbe_stats { + }; + + #define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \ +- offsetof(struct ixgbe_adapter, m) ++ offsetof(struct ixgbe_adapter, m) + static struct ixgbe_stats ixgbe_gstrings_stats[] = { + {"rx_packets", IXGBE_STAT(net_stats.rx_packets)}, + {"tx_packets", IXGBE_STAT(net_stats.tx_packets)}, +@@ -90,19 +89,22 @@ static struct ixgbe_stats ixgbe_gstrings + {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, + {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, + {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, ++#ifdef CONFIG_IXGBE_LRO + {"lro_aggregated", IXGBE_STAT(lro_aggregated)}, + {"lro_flushed", IXGBE_STAT(lro_flushed)}, ++#endif + }; + + #define IXGBE_QUEUE_STATS_LEN \ +- ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ +- ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ +- (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) +-#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) ++ ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ ++ ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ ++ (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) ++#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) ++#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) + #define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) + + static int ixgbe_get_settings(struct net_device *netdev, +- struct ethtool_cmd *ecmd) ++ struct ethtool_cmd *ecmd) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +@@ -114,7 +116,7 @@ static int ixgbe_get_settings(struct net + ecmd->transceiver = XCVR_EXTERNAL; + if (hw->phy.media_type == ixgbe_media_type_copper) { + ecmd->supported |= (SUPPORTED_1000baseT_Full | +- SUPPORTED_TP | SUPPORTED_Autoneg); ++ SUPPORTED_TP | SUPPORTED_Autoneg); + + ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg); + if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) +@@ -126,14 +128,15 @@ static int ixgbe_get_settings(struct net + } else { + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising = (ADVERTISED_10000baseT_Full | +- ADVERTISED_FIBRE); ++ ADVERTISED_FIBRE); + ecmd->port = PORT_FIBRE; ++ ecmd->autoneg = AUTONEG_DISABLE; + } + +- adapter->hw.mac.ops.check_link(hw, &(link_speed), &link_up); ++ hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + if (link_up) { + ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? +- SPEED_10000 : SPEED_1000; ++ SPEED_10000 : SPEED_1000; + ecmd->duplex = DUPLEX_FULL; + } else { + ecmd->speed = -1; +@@ -144,7 +147,7 @@ static int ixgbe_get_settings(struct net + } + + static int ixgbe_set_settings(struct net_device *netdev, +- struct ethtool_cmd *ecmd) ++ struct ethtool_cmd *ecmd) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +@@ -164,7 +167,7 @@ static int ixgbe_set_settings(struct net + } + + static void ixgbe_get_pauseparam(struct net_device *netdev, +- struct ethtool_pauseparam *pause) ++ struct ethtool_pauseparam *pause) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +@@ -182,7 +185,7 @@ static void ixgbe_get_pauseparam(struct + } + + static int ixgbe_set_pauseparam(struct net_device *netdev, +- struct ethtool_pauseparam *pause) ++ struct ethtool_pauseparam *pause) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +@@ -233,15 +236,15 @@ static int ixgbe_set_rx_csum(struct net_ + + static u32 ixgbe_get_tx_csum(struct net_device *netdev) + { +- return (netdev->features & NETIF_F_HW_CSUM) != 0; ++ return (netdev->features & NETIF_F_IP_CSUM) != 0; + } + + static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data) + { + if (data) +- netdev->features |= NETIF_F_HW_CSUM; ++ netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + else +- netdev->features &= ~NETIF_F_HW_CSUM; ++ netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + + return 0; + } +@@ -281,7 +284,7 @@ static int ixgbe_get_regs_len(struct net + #define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_ + + static void ixgbe_get_regs(struct net_device *netdev, +- struct ethtool_regs *regs, void *p) ++ struct ethtool_regs *regs, void *p) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +@@ -315,7 +318,9 @@ static void ixgbe_get_regs(struct net_de + regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC); + + /* Interrupt */ +- regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR); ++ /* don't read EICR because it can clear interrupt causes, instead ++ * read EICS which is a shadow but doesn't clear EICR */ ++ regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICS); + regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS); + regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS); + regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC); +@@ -325,7 +330,7 @@ static void ixgbe_get_regs(struct net_de + regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0)); + regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT); + regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA); +- regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL); ++ regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL(0)); + regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE); + + /* Flow Control */ +@@ -371,7 +376,7 @@ static void ixgbe_get_regs(struct net_de + regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i)); + for (i = 0; i < 16; i++) + regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i)); +- regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE); ++ regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)); + regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL); + regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL); +@@ -419,7 +424,6 @@ static void ixgbe_get_regs(struct net_de + regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM); + regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT); + +- /* DCE */ + regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS); + regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS); + regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); +@@ -539,21 +543,17 @@ static void ixgbe_get_regs(struct net_de + /* Diagnostic */ + regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL); + for (i = 0; i < 8; i++) +- regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); ++ regs_buff[1072 + i] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i)); + regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN); +- regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0); +- regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1); +- regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2); +- regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3); ++ for (i = 0; i < 4; i++) ++ regs_buff[1081 + i] = IXGBE_READ_REG(hw, IXGBE_RIC_DW(i)); + regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE); + regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL); + for (i = 0; i < 8; i++) +- regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); ++ regs_buff[1087 + i] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i)); + regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN); +- regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0); +- regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1); +- regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2); +- regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3); ++ for (i = 0; i < 4; i++) ++ regs_buff[1096 + i] = IXGBE_READ_REG(hw, IXGBE_TIC_DW(i)); + regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE); + regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL); + regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0); +@@ -566,7 +566,7 @@ static void ixgbe_get_regs(struct net_de + regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2); + regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3); + for (i = 0; i < 8; i++) +- regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); ++ regs_buff[1111 + i] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i)); + regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL); + regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1); + regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2); +@@ -585,7 +585,7 @@ static int ixgbe_get_eeprom_len(struct n + } + + static int ixgbe_get_eeprom(struct net_device *netdev, +- struct ethtool_eeprom *eeprom, u8 *bytes) ++ struct ethtool_eeprom *eeprom, u8 *bytes) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +@@ -608,8 +608,8 @@ static int ixgbe_get_eeprom(struct net_d + return -ENOMEM; + + for (i = 0; i < eeprom_len; i++) { +- if ((ret_val = ixgbe_read_eeprom(hw, first_word + i, +- &eeprom_buff[i]))) ++ if ((ret_val = hw->eeprom.ops.read(hw, first_word + i, ++ &eeprom_buff[i]))) + break; + } + +@@ -624,7 +624,7 @@ static int ixgbe_get_eeprom(struct net_d + } + + static void ixgbe_get_drvinfo(struct net_device *netdev, +- struct ethtool_drvinfo *drvinfo) ++ struct ethtool_drvinfo *drvinfo) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + +@@ -637,7 +637,7 @@ static void ixgbe_get_drvinfo(struct net + } + + static void ixgbe_get_ringparam(struct net_device *netdev, +- struct ethtool_ringparam *ring) ++ struct ethtool_ringparam *ring) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_ring *tx_ring = adapter->tx_ring; +@@ -654,15 +654,12 @@ static void ixgbe_get_ringparam(struct n + } + + static int ixgbe_set_ringparam(struct net_device *netdev, +- struct ethtool_ringparam *ring) ++ struct ethtool_ringparam *ring) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); +- struct ixgbe_tx_buffer *old_buf; +- struct ixgbe_rx_buffer *old_rx_buf; +- void *old_desc; ++ struct ixgbe_ring *temp_ring; + int i, err; +- u32 new_rx_count, new_tx_count, old_size; +- dma_addr_t old_dma; ++ u32 new_rx_count, new_tx_count; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; +@@ -681,6 +678,15 @@ static int ixgbe_set_ringparam(struct ne + return 0; + } + ++ if (adapter->num_tx_queues > adapter->num_rx_queues) ++ temp_ring = vmalloc(adapter->num_tx_queues * ++ sizeof(struct ixgbe_ring)); ++ else ++ temp_ring = vmalloc(adapter->num_rx_queues * ++ sizeof(struct ixgbe_ring)); ++ if (!temp_ring) ++ return -ENOMEM; ++ + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); + +@@ -693,66 +699,61 @@ static int ixgbe_set_ringparam(struct ne + * to the tx and rx ring structs. + */ + if (new_tx_count != adapter->tx_ring->count) { ++ memcpy(temp_ring, adapter->tx_ring, ++ adapter->num_tx_queues * sizeof(struct ixgbe_ring)); ++ + for (i = 0; i < adapter->num_tx_queues; i++) { +- /* Save existing descriptor ring */ +- old_buf = adapter->tx_ring[i].tx_buffer_info; +- old_desc = adapter->tx_ring[i].desc; +- old_size = adapter->tx_ring[i].size; +- old_dma = adapter->tx_ring[i].dma; +- /* Try to allocate a new one */ +- adapter->tx_ring[i].tx_buffer_info = NULL; +- adapter->tx_ring[i].desc = NULL; +- adapter->tx_ring[i].count = new_tx_count; +- err = ixgbe_setup_tx_resources(adapter, +- &adapter->tx_ring[i]); ++ temp_ring[i].count = new_tx_count; ++ err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); + if (err) { +- /* Restore the old one so at least +- the adapter still works, even if +- we failed the request */ +- adapter->tx_ring[i].tx_buffer_info = old_buf; +- adapter->tx_ring[i].desc = old_desc; +- adapter->tx_ring[i].size = old_size; +- adapter->tx_ring[i].dma = old_dma; ++ while (i) { ++ i--; ++ ixgbe_free_tx_resources(adapter, ++ &temp_ring[i]); ++ } + goto err_setup; + } +- /* Free the old buffer manually */ +- vfree(old_buf); +- pci_free_consistent(adapter->pdev, old_size, +- old_desc, old_dma); + } ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) ++ ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); ++ ++ memcpy(adapter->tx_ring, temp_ring, ++ adapter->num_tx_queues * sizeof(struct ixgbe_ring)); ++ ++ adapter->tx_ring_count = new_tx_count; + } + + if (new_rx_count != adapter->rx_ring->count) { +- for (i = 0; i < adapter->num_rx_queues; i++) { ++ memcpy(temp_ring, adapter->rx_ring, ++ adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + +- old_rx_buf = adapter->rx_ring[i].rx_buffer_info; +- old_desc = adapter->rx_ring[i].desc; +- old_size = adapter->rx_ring[i].size; +- old_dma = adapter->rx_ring[i].dma; +- +- adapter->rx_ring[i].rx_buffer_info = NULL; +- adapter->rx_ring[i].desc = NULL; +- adapter->rx_ring[i].dma = 0; +- adapter->rx_ring[i].count = new_rx_count; +- err = ixgbe_setup_rx_resources(adapter, +- &adapter->rx_ring[i]); ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ temp_ring[i].count = new_rx_count; ++ err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); + if (err) { +- adapter->rx_ring[i].rx_buffer_info = old_rx_buf; +- adapter->rx_ring[i].desc = old_desc; +- adapter->rx_ring[i].size = old_size; +- adapter->rx_ring[i].dma = old_dma; ++ while (i) { ++ i--; ++ ixgbe_free_rx_resources(adapter, ++ &temp_ring[i]); ++ } + goto err_setup; + } +- +- vfree(old_rx_buf); +- pci_free_consistent(adapter->pdev, old_size, old_desc, +- old_dma); + } ++ ++ for (i = 0; i < adapter->num_rx_queues; i++) ++ ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); ++ ++ memcpy(adapter->rx_ring, temp_ring, ++ adapter->num_rx_queues * sizeof(struct ixgbe_ring)); ++ ++ adapter->rx_ring_count = new_rx_count; + } + ++ /* success! */ + err = 0; + err_setup: +- if (netif_running(adapter->netdev)) ++ if (netif_running(netdev)) + ixgbe_up(adapter); + + clear_bit(__IXGBE_RESETTING, &adapter->state); +@@ -770,20 +771,31 @@ static int ixgbe_get_sset_count(struct n + } + + static void ixgbe_get_ethtool_stats(struct net_device *netdev, +- struct ethtool_stats *stats, u64 *data) ++ struct ethtool_stats *stats, u64 *data) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u64 *queue_stat; + int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); + int j, k; + int i; ++ ++#ifdef CONFIG_IXGBE_LRO + u64 aggregated = 0, flushed = 0, no_desc = 0; ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated; ++ flushed += adapter->rx_ring[i].lro_mgr.stats.flushed; ++ no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc; ++ } ++ adapter->lro_aggregated = aggregated; ++ adapter->lro_flushed = flushed; ++ adapter->lro_no_desc = no_desc; ++#endif + + ixgbe_update_stats(adapter); + for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset; + data[i] = (ixgbe_gstrings_stats[i].sizeof_stat == +- sizeof(u64)) ? *(u64 *)p : *(u32 *)p; ++ sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + for (j = 0; j < adapter->num_tx_queues; j++) { + queue_stat = (u64 *)&adapter->tx_ring[j].stats; +@@ -792,24 +804,18 @@ static void ixgbe_get_ethtool_stats(stru + i += k; + } + for (j = 0; j < adapter->num_rx_queues; j++) { +- aggregated += adapter->rx_ring[j].lro_mgr.stats.aggregated; +- flushed += adapter->rx_ring[j].lro_mgr.stats.flushed; +- no_desc += adapter->rx_ring[j].lro_mgr.stats.no_desc; + queue_stat = (u64 *)&adapter->rx_ring[j].stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } +- adapter->lro_aggregated = aggregated; +- adapter->lro_flushed = flushed; +- adapter->lro_no_desc = no_desc; + } + + static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, +- u8 *data) ++ u8 *data) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); +- u8 *p = data; ++ char *p = (char *)data; + int i; + + switch (stringset) { +@@ -831,14 +837,14 @@ static void ixgbe_get_strings(struct net + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } +-/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ ++ /* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ + break; + } + } + + + static void ixgbe_get_wol(struct net_device *netdev, +- struct ethtool_wolinfo *wol) ++ struct ethtool_wolinfo *wol) + { + wol->supported = 0; + wol->wolopts = 0; +@@ -859,16 +865,17 @@ static int ixgbe_nway_reset(struct net_d + static int ixgbe_phys_id(struct net_device *netdev, u32 data) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); +- u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL); ++ struct ixgbe_hw *hw = &adapter->hw; ++ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + u32 i; + + if (!data || data > 300) + data = 300; + + for (i = 0; i < (data * 1000); i += 400) { +- ixgbe_led_on(&adapter->hw, IXGBE_LED_ON); ++ hw->mac.ops.led_on(hw, IXGBE_LED_ON); + msleep_interruptible(200); +- ixgbe_led_off(&adapter->hw, IXGBE_LED_ON); ++ hw->mac.ops.led_off(hw, IXGBE_LED_ON); + msleep_interruptible(200); + } + +@@ -879,67 +886,75 @@ static int ixgbe_phys_id(struct net_devi + } + + static int ixgbe_get_coalesce(struct net_device *netdev, +- struct ethtool_coalesce *ec) ++ struct ethtool_coalesce *ec) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + +- if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS) +- ec->rx_coalesce_usecs = adapter->rx_eitr; +- else +- ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr; +- +- if (adapter->tx_eitr < IXGBE_MIN_ITR_USECS) +- ec->tx_coalesce_usecs = adapter->tx_eitr; +- else +- ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr; +- + ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit; ++ ++ /* only valid if in constant ITR mode */ ++ switch (adapter->itr_setting) { ++ case 0: ++ /* throttling disabled */ ++ ec->rx_coalesce_usecs = 0; ++ break; ++ case 1: ++ /* dynamic ITR mode */ ++ ec->rx_coalesce_usecs = 1; ++ break; ++ default: ++ /* fixed interrupt rate mode */ ++ ec->rx_coalesce_usecs = 1000000/adapter->eitr_param; ++ break; ++ } + return 0; + } + + static int ixgbe_set_coalesce(struct net_device *netdev, +- struct ethtool_coalesce *ec) ++ struct ethtool_coalesce *ec) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); +- +- if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || +- ((ec->rx_coalesce_usecs != 0) && +- (ec->rx_coalesce_usecs != 1) && +- (ec->rx_coalesce_usecs != 3) && +- (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) +- return -EINVAL; +- if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) || +- ((ec->tx_coalesce_usecs != 0) && +- (ec->tx_coalesce_usecs != 1) && +- (ec->tx_coalesce_usecs != 3) && +- (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS))) +- return -EINVAL; +- +- /* convert to rate of irq's per second */ +- if (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS) +- adapter->rx_eitr = ec->rx_coalesce_usecs; +- else +- adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs); +- +- if (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS) +- adapter->tx_eitr = ec->rx_coalesce_usecs; +- else +- adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs); ++ struct ixgbe_hw *hw = &adapter->hw; ++ int i; + + if (ec->tx_max_coalesced_frames_irq) +- adapter->tx_ring[0].work_limit = +- ec->tx_max_coalesced_frames_irq; ++ adapter->tx_ring[0].work_limit = ec->tx_max_coalesced_frames_irq; + +- if (netif_running(netdev)) { +- ixgbe_down(adapter); +- ixgbe_up(adapter); ++ if (ec->rx_coalesce_usecs > 1) { ++ /* store the value in ints/second */ ++ adapter->eitr_param = 1000000/ec->rx_coalesce_usecs; ++ ++ /* static value of interrupt rate */ ++ adapter->itr_setting = adapter->eitr_param; ++ /* clear the lower bit */ ++ adapter->itr_setting &= ~1; ++ } else if (ec->rx_coalesce_usecs == 1) { ++ /* 1 means dynamic mode */ ++ adapter->eitr_param = 20000; ++ adapter->itr_setting = 1; ++ } else { ++ /* any other value means disable eitr, which is best ++ * served by setting the interrupt rate very high */ ++ adapter->eitr_param = 3000000; ++ adapter->itr_setting = 0; ++ } ++ ++ for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { ++ struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; ++ if (q_vector->txr_count && !q_vector->rxr_count) ++ q_vector->eitr = (adapter->eitr_param >> 1); ++ else ++ /* rx only or mixed */ ++ q_vector->eitr = adapter->eitr_param; ++ IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ++ EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + } + + return 0; + } + + +-static struct ethtool_ops ixgbe_ethtool_ops = { ++static const struct ethtool_ops ixgbe_ethtool_ops = { + .get_settings = ixgbe_get_settings, + .set_settings = ixgbe_set_settings, + .get_drvinfo = ixgbe_get_drvinfo, +@@ -966,7 +981,7 @@ static struct ethtool_ops ixgbe_ethtool_ + .set_tso = ixgbe_set_tso, + .get_strings = ixgbe_get_strings, + .phys_id = ixgbe_phys_id, +- .get_sset_count = ixgbe_get_sset_count, ++ .get_sset_count = ixgbe_get_sset_count, + .get_ethtool_stats = ixgbe_get_ethtool_stats, + .get_coalesce = ixgbe_get_coalesce, + .set_coalesce = ixgbe_set_coalesce, +--- a/drivers/net/ixgbe/ixgbe.h ++++ b/drivers/net/ixgbe/ixgbe.h +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -32,17 +31,20 @@ + #include + #include + #include ++ ++#ifdef CONFIG_IXGBE_LRO + #include ++#define IXGBE_MAX_LRO_AGGREGATE 32 ++#define IXGBE_MAX_LRO_DESCRIPTORS 8 ++#endif + + #include "ixgbe_type.h" + #include "ixgbe_common.h" + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + #include + #endif + +-#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args) +- + #define PFX "ixgbe: " + #define DPRINTK(nlevel, klevel, fmt, args...) \ + ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \ +@@ -58,23 +60,14 @@ + #define IXGBE_MAX_RXD 4096 + #define IXGBE_MIN_RXD 64 + +-#define IXGBE_DEFAULT_RXQ 1 +-#define IXGBE_MAX_RXQ 1 +-#define IXGBE_MIN_RXQ 1 +- +-#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */ +-#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */ +-#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */ +-#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */ +- + /* flow control */ + #define IXGBE_DEFAULT_FCRTL 0x10000 +-#define IXGBE_MIN_FCRTL 0 ++#define IXGBE_MIN_FCRTL 0x40 + #define IXGBE_MAX_FCRTL 0x7FF80 + #define IXGBE_DEFAULT_FCRTH 0x20000 +-#define IXGBE_MIN_FCRTH 0 ++#define IXGBE_MIN_FCRTH 0x600 + #define IXGBE_MAX_FCRTH 0x7FFF0 +-#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */ ++#define IXGBE_DEFAULT_FCPAUSE 0xFFFF + #define IXGBE_MIN_FCPAUSE 0 + #define IXGBE_MAX_FCPAUSE 0xFFFF + +@@ -88,9 +81,6 @@ + + #define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) + +-/* How many Tx Descriptors do we need to call netif_wake_queue? */ +-#define IXGBE_TX_QUEUE_WAKE 16 +- + /* How many Rx Buffers do we bundle into one write to the hardware ? */ + #define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +@@ -101,9 +91,6 @@ + #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 + #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 + +-#define IXGBE_MAX_LRO_DESCRIPTORS 8 +-#define IXGBE_MAX_LRO_AGGREGATE 32 +- + /* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ + struct ixgbe_tx_buffer { +@@ -119,6 +106,7 @@ struct ixgbe_rx_buffer { + dma_addr_t dma; + struct page *page; + dma_addr_t page_dma; ++ unsigned int page_offset; + }; + + struct ixgbe_queue_stats { +@@ -150,22 +138,22 @@ struct ixgbe_ring { + * offset associated with this ring, which is different + * for DCE and RSS modes */ + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + /* cpu for tx queue */ + int cpu; + #endif ++#ifdef CONFIG_IXGBE_LRO + struct net_lro_mgr lro_mgr; + bool lro_used; ++#endif + struct ixgbe_queue_stats stats; +- u8 v_idx; /* maps directly to the index for this ring in the hardware +- * vector array, can also be used for finding the bit in EICR +- * and friends that represents the vector for this ring */ ++ u16 v_idx; /* maps directly to the index for this ring in the hardware ++ * vector array, can also be used for finding the bit in EICR ++ * and friends that represents the vector for this ring */ + +- u32 eims_value; +- u16 itr_register; + +- char name[IFNAMSIZ + 5]; + u16 work_limit; /* max work per interrupt */ ++ u16 rx_buf_len; + }; + + #define RING_F_VMDQ 1 +@@ -190,8 +178,8 @@ struct ixgbe_q_vector { + DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */ + u8 rxr_count; /* Rx ring count assigned to this vector */ + u8 txr_count; /* Tx ring count assigned to this vector */ +- u8 tx_eitr; +- u8 rx_eitr; ++ u8 tx_itr; ++ u8 rx_itr; + u32 eitr; + }; + +@@ -228,7 +216,6 @@ struct ixgbe_adapter { + struct timer_list watchdog_timer; + struct vlan_group *vlgrp; + u16 bd_number; +- u16 rx_buf_len; + struct work_struct reset_task; + struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; + char name[MAX_MSIX_COUNT][IFNAMSIZ + 5]; +@@ -240,7 +227,9 @@ struct ixgbe_adapter { + + /* TX */ + struct ixgbe_ring *tx_ring; /* One per active queue */ ++ int num_tx_queues; + u64 restart_queue; ++ u64 hw_csum_tx_good; + u64 lsc_int; + u64 hw_tso_ctxt; + u64 hw_tso6_ctxt; +@@ -249,12 +238,10 @@ struct ixgbe_adapter { + + /* RX */ + struct ixgbe_ring *rx_ring; /* One per active queue */ +- u64 hw_csum_tx_good; ++ int num_rx_queues; + u64 hw_csum_rx_error; + u64 hw_csum_rx_good; + u64 non_eop_descs; +- int num_tx_queues; +- int num_rx_queues; + int num_msix_vectors; + struct ixgbe_ring_feature ring_feature[3]; + struct msix_entry *msix_entries; +@@ -267,15 +254,28 @@ struct ixgbe_adapter { + * thus the additional *_CAPABLE flags. + */ + u32 flags; +-#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1 << 0) +-#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1) +-#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2) +-#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3) +-#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4) +-#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 5) +-#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 6) +-#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 7) +-#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 8) ++#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1) ++#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1) ++#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2) ++#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3) ++#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4) ++#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6) ++#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7) ++#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8) ++#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9) ++#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10) ++#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11) ++#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12) ++#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13) ++#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16) ++#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) ++#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) ++#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) ++#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) ++#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) ++ ++/* default to trying for four seconds */ ++#define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) + + /* OS defined structs */ + struct net_device *netdev; +@@ -288,14 +288,23 @@ struct ixgbe_adapter { + struct ixgbe_hw_stats stats; + + /* Interrupt Throttle Rate */ +- u32 rx_eitr; +- u32 tx_eitr; ++ u32 eitr_param; + + unsigned long state; + u64 tx_busy; ++#ifndef IXGBE_NO_INET_LRO + u64 lro_aggregated; + u64 lro_flushed; + u64 lro_no_desc; ++#endif ++ unsigned int tx_ring_count; ++ unsigned int rx_ring_count; ++ ++ u32 link_speed; ++ bool link_up; ++ unsigned long link_check_timeout; ++ ++ struct work_struct watchdog_task; + }; + + enum ixbge_state_t { +@@ -317,11 +326,11 @@ extern int ixgbe_up(struct ixgbe_adapter + extern void ixgbe_down(struct ixgbe_adapter *adapter); + extern void ixgbe_reinit_locked(struct ixgbe_adapter *adapter); + extern void ixgbe_reset(struct ixgbe_adapter *adapter); +-extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); + extern void ixgbe_set_ethtool_ops(struct net_device *netdev); +-extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rxdr); +-extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *txdr); ++extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); ++extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); ++extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); ++extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); ++extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); + + #endif /* _IXGBE_H_ */ +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -46,15 +45,14 @@ + + char ixgbe_driver_name[] = "ixgbe"; + static const char ixgbe_driver_string[] = +- "Intel(R) 10 Gigabit PCI Express Network Driver"; ++ "Intel(R) 10 Gigabit PCI Express Network Driver"; + +-#define DRV_VERSION "1.3.18-k4" ++#define DRV_VERSION "1.3.30-k2" + const char ixgbe_driver_version[] = DRV_VERSION; +-static const char ixgbe_copyright[] = +- "Copyright (c) 1999-2007 Intel Corporation."; ++static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation."; + + static const struct ixgbe_info *ixgbe_info_tbl[] = { +- [board_82598] = &ixgbe_82598_info, ++ [board_82598] = &ixgbe_82598_info, + }; + + /* ixgbe_pci_tbl - PCI Device ID Table +@@ -74,15 +72,17 @@ static struct pci_device_id ixgbe_pci_tb + board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), + board_82598 }, ++ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), ++ board_82598 }, + + /* required last entry */ + {0, } + }; + MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl); + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + static int ixgbe_notify_dca(struct notifier_block *, unsigned long event, +- void *p); ++ void *p); + static struct notifier_block dca_notifier = { + .notifier_call = ixgbe_notify_dca, + .next = NULL, +@@ -104,7 +104,7 @@ static void ixgbe_release_hw_control(str + /* Let firmware take over control of h/w */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, +- ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); ++ ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD); + } + + static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter) +@@ -114,24 +114,11 @@ static void ixgbe_get_hw_control(struct + /* Let firmware know the driver has taken over */ + ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, +- ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); +-} +- +-#ifdef DEBUG +-/** +- * ixgbe_get_hw_dev_name - return device name string +- * used by hardware layer to print debugging information +- **/ +-char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw) +-{ +- struct ixgbe_adapter *adapter = hw->back; +- struct net_device *netdev = adapter->netdev; +- return netdev->name; ++ ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD); + } +-#endif + + static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry, +- u8 msix_vector) ++ u8 msix_vector) + { + u32 ivar, index; + +@@ -144,13 +131,12 @@ static void ixgbe_set_ivar(struct ixgbe_ + } + + static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, +- struct ixgbe_tx_buffer +- *tx_buffer_info) ++ struct ixgbe_tx_buffer ++ *tx_buffer_info) + { + if (tx_buffer_info->dma) { +- pci_unmap_page(adapter->pdev, +- tx_buffer_info->dma, +- tx_buffer_info->length, PCI_DMA_TODEVICE); ++ pci_unmap_page(adapter->pdev, tx_buffer_info->dma, ++ tx_buffer_info->length, PCI_DMA_TODEVICE); + tx_buffer_info->dma = 0; + } + if (tx_buffer_info->skb) { +@@ -161,107 +147,120 @@ static void ixgbe_unmap_and_free_tx_reso + } + + static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring, +- unsigned int eop, +- union ixgbe_adv_tx_desc *eop_desc) ++ struct ixgbe_ring *tx_ring, ++ unsigned int eop) + { ++ struct ixgbe_hw *hw = &adapter->hw; ++ u32 head, tail; ++ + /* Detect a transmit hang in hardware, this serializes the +- * check with the clearing of time_stamp and movement of i */ ++ * check with the clearing of time_stamp and movement of eop */ ++ head = IXGBE_READ_REG(hw, tx_ring->head); ++ tail = IXGBE_READ_REG(hw, tx_ring->tail); + adapter->detect_tx_hung = false; +- if (tx_ring->tx_buffer_info[eop].dma && ++ if ((head != tail) && ++ tx_ring->tx_buffer_info[eop].time_stamp && + time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) && + !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) { + /* detected Tx unit hang */ ++ union ixgbe_adv_tx_desc *tx_desc; ++ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); + DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" +- " TDH <%x>\n" +- " TDT <%x>\n" ++ " Tx Queue <%d>\n" ++ " TDH, TDT <%x>, <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + "tx_buffer_info[next_to_clean]\n" + " time_stamp <%lx>\n" +- " next_to_watch <%x>\n" +- " jiffies <%lx>\n" +- " next_to_watch.status <%x>\n", +- readl(adapter->hw.hw_addr + tx_ring->head), +- readl(adapter->hw.hw_addr + tx_ring->tail), +- tx_ring->next_to_use, +- tx_ring->next_to_clean, +- tx_ring->tx_buffer_info[eop].time_stamp, +- eop, jiffies, eop_desc->wb.status); ++ " jiffies <%lx>\n", ++ tx_ring->queue_index, ++ head, tail, ++ tx_ring->next_to_use, eop, ++ tx_ring->tx_buffer_info[eop].time_stamp, jiffies); + return true; + } + + return false; + } + +-#define IXGBE_MAX_TXD_PWR 14 +-#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) ++#define IXGBE_MAX_TXD_PWR 14 ++#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR) + + /* Tx Descriptors needed, worst case */ + #define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \ + (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) + #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ +- MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ ++ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ ++ ++#define GET_TX_HEAD_FROM_RING(ring) (\ ++ *(volatile u32 *) \ ++ ((union ixgbe_adv_tx_desc *)(ring)->desc + (ring)->count)) ++static void ixgbe_tx_timeout(struct net_device *netdev); + + /** + * ixgbe_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure ++ * @tx_ring: tx ring to clean + **/ + static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring) ++ struct ixgbe_ring *tx_ring) + { +- struct net_device *netdev = adapter->netdev; +- union ixgbe_adv_tx_desc *tx_desc, *eop_desc; ++ union ixgbe_adv_tx_desc *tx_desc; + struct ixgbe_tx_buffer *tx_buffer_info; +- unsigned int i, eop; +- bool cleaned = false; +- unsigned int total_tx_bytes = 0, total_tx_packets = 0; +- ++ struct net_device *netdev = adapter->netdev; ++ struct sk_buff *skb; ++ unsigned int i; ++ u32 head, oldhead; ++ unsigned int count = 0; ++ unsigned int total_bytes = 0, total_packets = 0; ++ ++ rmb(); ++ head = GET_TX_HEAD_FROM_RING(tx_ring); ++ head = le32_to_cpu(head); + i = tx_ring->next_to_clean; +- eop = tx_ring->tx_buffer_info[i].next_to_watch; +- eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); +- while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) { +- cleaned = false; +- while (!cleaned) { ++ while (1) { ++ while (i != head) { + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_buffer_info = &tx_ring->tx_buffer_info[i]; +- cleaned = (i == eop); ++ skb = tx_buffer_info->skb; + +- tx_ring->stats.bytes += tx_buffer_info->length; +- if (cleaned) { +- struct sk_buff *skb = tx_buffer_info->skb; ++ if (skb) { + unsigned int segs, bytecount; ++ ++ /* gso_segs is currently only valid for tcp */ + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + +- skb->len; +- total_tx_packets += segs; +- total_tx_bytes += bytecount; ++ skb->len; ++ total_packets += segs; ++ total_bytes += bytecount; + } ++ + ixgbe_unmap_and_free_tx_resource(adapter, +- tx_buffer_info); +- tx_desc->wb.status = 0; ++ tx_buffer_info); + + i++; + if (i == tx_ring->count) + i = 0; +- } + +- tx_ring->stats.packets++; +- +- eop = tx_ring->tx_buffer_info[i].next_to_watch; +- eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); +- +- /* weight of a sort for tx, avoid endless transmit cleanup */ +- if (total_tx_packets >= tx_ring->work_limit) +- break; +- } ++ count++; ++ if (count == tx_ring->count) ++ goto done_cleaning; ++ } ++ oldhead = head; ++ rmb(); ++ head = GET_TX_HEAD_FROM_RING(tx_ring); ++ head = le32_to_cpu(head); ++ if (head == oldhead) ++ goto done_cleaning; ++ } /* while (1) */ + ++done_cleaning: + tx_ring->next_to_clean = i; + + #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) +- if (total_tx_packets && netif_carrier_ok(netdev) && +- (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) { ++ if (unlikely(count && netif_carrier_ok(netdev) && ++ (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ +@@ -269,59 +268,68 @@ static bool ixgbe_clean_tx_irq(struct ix + if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && + !test_bit(__IXGBE_DOWN, &adapter->state)) { + netif_wake_subqueue(netdev, tx_ring->queue_index); +- adapter->restart_queue++; ++ ++adapter->restart_queue; + } + } + +- if (adapter->detect_tx_hung) +- if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc)) +- netif_stop_subqueue(netdev, tx_ring->queue_index); +- +- if (total_tx_packets >= tx_ring->work_limit) +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value); ++ if (adapter->detect_tx_hung) { ++ if (ixgbe_check_tx_hang(adapter, tx_ring, i)) { ++ /* schedule immediate reset if we believe we hung */ ++ DPRINTK(PROBE, INFO, ++ "tx hang %d detected, resetting adapter\n", ++ adapter->tx_timeout_count + 1); ++ ixgbe_tx_timeout(adapter->netdev); ++ } ++ } + +- tx_ring->total_bytes += total_tx_bytes; +- tx_ring->total_packets += total_tx_packets; +- adapter->net_stats.tx_bytes += total_tx_bytes; +- adapter->net_stats.tx_packets += total_tx_packets; +- cleaned = total_tx_packets ? true : false; +- return cleaned; ++ /* re-arm the interrupt */ ++ if ((total_packets >= tx_ring->work_limit) || ++ (count == tx_ring->count)) ++ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx); ++ ++ tx_ring->total_bytes += total_bytes; ++ tx_ring->total_packets += total_packets; ++ tx_ring->stats.bytes += total_bytes; ++ tx_ring->stats.packets += total_packets; ++ adapter->net_stats.tx_bytes += total_bytes; ++ adapter->net_stats.tx_packets += total_packets; ++ return (total_packets ? true : false); + } + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rxr) ++ struct ixgbe_ring *rx_ring) + { + u32 rxctrl; + int cpu = get_cpu(); +- int q = rxr - adapter->rx_ring; ++ int q = rx_ring - adapter->rx_ring; + +- if (rxr->cpu != cpu) { ++ if (rx_ring->cpu != cpu) { + rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q)); + rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK; +- rxctrl |= dca_get_tag(cpu); ++ rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); + rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN; + rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl); +- rxr->cpu = cpu; ++ rx_ring->cpu = cpu; + } + put_cpu(); + } + + static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *txr) ++ struct ixgbe_ring *tx_ring) + { + u32 txctrl; + int cpu = get_cpu(); +- int q = txr - adapter->tx_ring; ++ int q = tx_ring - adapter->tx_ring; + +- if (txr->cpu != cpu) { ++ if (tx_ring->cpu != cpu) { + txctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q)); + txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK; +- txctrl |= dca_get_tag(cpu); ++ txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); + txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q), txctrl); +- txr->cpu = cpu; ++ tx_ring->cpu = cpu; + } + put_cpu(); + } +@@ -351,11 +359,14 @@ static int __ixgbe_notify_dca(struct dev + + switch (event) { + case DCA_PROVIDER_ADD: +- adapter->flags |= IXGBE_FLAG_DCA_ENABLED; ++ /* if we're already enabled, don't do it again */ ++ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) ++ break; + /* Always use CB2 mode, difference is masked + * in the CB driver. */ + IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_CTRL, 2); + if (dca_add_requester(dev) == 0) { ++ adapter->flags |= IXGBE_FLAG_DCA_ENABLED; + ixgbe_setup_dca(adapter); + break; + } +@@ -372,7 +383,7 @@ static int __ixgbe_notify_dca(struct dev + return 0; + } + +-#endif /* CONFIG_DCA */ ++#endif /* CONFIG_DCA or CONFIG_DCA_MODULE */ + /** + * ixgbe_receive_skb - Send a completed packet up the stack + * @adapter: board private structure +@@ -382,13 +393,14 @@ static int __ixgbe_notify_dca(struct dev + * @rx_desc: rx descriptor + **/ + static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, +- struct sk_buff *skb, u8 status, +- struct ixgbe_ring *ring, ++ struct sk_buff *skb, u8 status, ++ struct ixgbe_ring *ring, + union ixgbe_adv_rx_desc *rx_desc) + { + bool is_vlan = (status & IXGBE_RXD_STAT_VP); + u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); + ++#ifdef CONFIG_IXGBE_LRO + if (adapter->netdev->features & NETIF_F_LRO && + skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (adapter->vlgrp && is_vlan) +@@ -399,6 +411,7 @@ static void ixgbe_receive_skb(struct ixg + lro_receive_skb(&ring->lro_mgr, skb, rx_desc); + ring->lro_used = true; + } else { ++#endif + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { + if (adapter->vlgrp && is_vlan) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); +@@ -410,7 +423,9 @@ static void ixgbe_receive_skb(struct ixg + else + netif_rx(skb); + } ++#ifdef CONFIG_IXGBE_LRO + } ++#endif + } + + /** +@@ -420,14 +435,12 @@ static void ixgbe_receive_skb(struct ixg + * @skb: skb currently being received and modified + **/ + static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, +- u32 status_err, +- struct sk_buff *skb) ++ u32 status_err, struct sk_buff *skb) + { + skb->ip_summed = CHECKSUM_NONE; + +- /* Ignore Checksum bit is set, or rx csum disabled */ +- if ((status_err & IXGBE_RXD_STAT_IXSM) || +- !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) ++ /* Rx csum disabled */ ++ if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) + return; + + /* if IP and error */ +@@ -455,37 +468,44 @@ static inline void ixgbe_rx_checksum(str + * @adapter: address of board private structure + **/ + static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rx_ring, +- int cleaned_count) ++ struct ixgbe_ring *rx_ring, ++ int cleaned_count) + { +- struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc; +- struct ixgbe_rx_buffer *rx_buffer_info; +- struct sk_buff *skb; ++ struct ixgbe_rx_buffer *bi; + unsigned int i; +- unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN; ++ unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN; + + i = rx_ring->next_to_use; +- rx_buffer_info = &rx_ring->rx_buffer_info[i]; ++ bi = &rx_ring->rx_buffer_info[i]; + + while (cleaned_count--) { + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + +- if (!rx_buffer_info->page && +- (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { +- rx_buffer_info->page = alloc_page(GFP_ATOMIC); +- if (!rx_buffer_info->page) { +- adapter->alloc_rx_page_failed++; +- goto no_buffers; ++ if (!bi->page_dma && ++ (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { ++ if (!bi->page) { ++ bi->page = alloc_page(GFP_ATOMIC); ++ if (!bi->page) { ++ adapter->alloc_rx_page_failed++; ++ goto no_buffers; ++ } ++ bi->page_offset = 0; ++ } else { ++ /* use a half page if we're re-using */ ++ bi->page_offset ^= (PAGE_SIZE / 2); + } +- rx_buffer_info->page_dma = +- pci_map_page(pdev, rx_buffer_info->page, +- 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ ++ bi->page_dma = pci_map_page(pdev, bi->page, ++ bi->page_offset, ++ (PAGE_SIZE / 2), ++ PCI_DMA_FROMDEVICE); + } + +- if (!rx_buffer_info->skb) { +- skb = netdev_alloc_skb(netdev, bufsz); ++ if (!bi->skb) { ++ struct sk_buff *skb = netdev_alloc_skb(adapter->netdev, ++ bufsz); + + if (!skb) { + adapter->alloc_rx_buff_failed++; +@@ -499,28 +519,25 @@ static void ixgbe_alloc_rx_buffers(struc + */ + skb_reserve(skb, NET_IP_ALIGN); + +- rx_buffer_info->skb = skb; +- rx_buffer_info->dma = pci_map_single(pdev, skb->data, +- bufsz, +- PCI_DMA_FROMDEVICE); ++ bi->skb = skb; ++ bi->dma = pci_map_single(pdev, skb->data, bufsz, ++ PCI_DMA_FROMDEVICE); + } + /* Refresh the desc even if buffer_addrs didn't change because + * each write-back erases this info. */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +- rx_desc->read.pkt_addr = +- cpu_to_le64(rx_buffer_info->page_dma); +- rx_desc->read.hdr_addr = +- cpu_to_le64(rx_buffer_info->dma); ++ rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma); ++ rx_desc->read.hdr_addr = cpu_to_le64(bi->dma); + } else { +- rx_desc->read.pkt_addr = +- cpu_to_le64(rx_buffer_info->dma); ++ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma); + } + + i++; + if (i == rx_ring->count) + i = 0; +- rx_buffer_info = &rx_ring->rx_buffer_info[i]; ++ bi = &rx_ring->rx_buffer_info[i]; + } ++ + no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; +@@ -538,46 +555,54 @@ no_buffers: + } + } + ++static inline u16 ixgbe_get_hdr_info(union ixgbe_adv_rx_desc *rx_desc) ++{ ++ return rx_desc->wb.lower.lo_dword.hs_rss.hdr_info; ++} ++ ++static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc) ++{ ++ return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; ++} ++ + static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rx_ring, +- int *work_done, int work_to_do) ++ struct ixgbe_ring *rx_ring, ++ int *work_done, int work_to_do) + { +- struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union ixgbe_adv_rx_desc *rx_desc, *next_rxd; + struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer; + struct sk_buff *skb; + unsigned int i; +- u32 upper_len, len, staterr; ++ u32 len, staterr; + u16 hdr_info; + bool cleaned = false; + int cleaned_count = 0; + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + + i = rx_ring->next_to_clean; +- upper_len = 0; + rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + + while (staterr & IXGBE_RXD_STAT_DD) { ++ u32 upper_len = 0; + if (*work_done >= work_to_do) + break; + (*work_done)++; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +- hdr_info = +- le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info); +- len = +- ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> +- IXGBE_RXDADV_HDRBUFLEN_SHIFT); ++ hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc)); ++ len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> ++ IXGBE_RXDADV_HDRBUFLEN_SHIFT; + if (hdr_info & IXGBE_RXDADV_SPH) + adapter->rx_hdr_split++; + if (len > IXGBE_RX_HDR_SIZE) + len = IXGBE_RX_HDR_SIZE; + upper_len = le16_to_cpu(rx_desc->wb.upper.length); +- } else ++ } else { + len = le16_to_cpu(rx_desc->wb.upper.length); ++ } + + cleaned = true; + skb = rx_buffer_info->skb; +@@ -586,18 +611,25 @@ static bool ixgbe_clean_rx_irq(struct ix + + if (len && !skb_shinfo(skb)->nr_frags) { + pci_unmap_single(pdev, rx_buffer_info->dma, +- adapter->rx_buf_len + NET_IP_ALIGN, +- PCI_DMA_FROMDEVICE); ++ rx_ring->rx_buf_len + NET_IP_ALIGN, ++ PCI_DMA_FROMDEVICE); + skb_put(skb, len); + } + + if (upper_len) { + pci_unmap_page(pdev, rx_buffer_info->page_dma, +- PAGE_SIZE, PCI_DMA_FROMDEVICE); ++ PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; + skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, +- rx_buffer_info->page, 0, upper_len); +- rx_buffer_info->page = NULL; ++ rx_buffer_info->page, ++ rx_buffer_info->page_offset, ++ upper_len); ++ ++ if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) || ++ (page_count(rx_buffer_info->page) != 1)) ++ rx_buffer_info->page = NULL; ++ else ++ get_page(rx_buffer_info->page); + + skb->len += upper_len; + skb->data_len += upper_len; +@@ -620,6 +652,7 @@ static bool ixgbe_clean_rx_irq(struct ix + rx_buffer_info->skb = next_buffer->skb; + rx_buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; ++ next_buffer->dma = 0; + adapter->non_eop_descs++; + goto next_desc; + } +@@ -635,9 +668,9 @@ static bool ixgbe_clean_rx_irq(struct ix + total_rx_bytes += skb->len; + total_rx_packets++; + +- skb->protocol = eth_type_trans(skb, netdev); ++ skb->protocol = eth_type_trans(skb, adapter->netdev); + ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); +- netdev->last_rx = jiffies; ++ adapter->netdev->last_rx = jiffies; + + next_desc: + rx_desc->wb.upper.status_error = 0; +@@ -655,10 +688,12 @@ next_desc: + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + } + ++#ifdef CONFIG_IXGBE_LRO + if (rx_ring->lro_used) { + lro_flush_all(&rx_ring->lro_mgr); + rx_ring->lro_used = false; + } ++#endif + + rx_ring->next_to_clean = i; + cleaned_count = IXGBE_DESC_UNUSED(rx_ring); +@@ -666,9 +701,6 @@ next_desc: + if (cleaned_count) + ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count); + +- adapter->net_stats.rx_bytes += total_rx_bytes; +- adapter->net_stats.rx_packets += total_rx_packets; +- + rx_ring->total_packets += total_rx_packets; + rx_ring->total_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; +@@ -700,43 +732,43 @@ static void ixgbe_configure_msix(struct + q_vector = &adapter->q_vector[v_idx]; + /* XXX for_each_bit(...) */ + r_idx = find_first_bit(q_vector->rxr_idx, +- adapter->num_rx_queues); ++ adapter->num_rx_queues); + + for (i = 0; i < q_vector->rxr_count; i++) { + j = adapter->rx_ring[r_idx].reg_idx; + ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(j), v_idx); + r_idx = find_next_bit(q_vector->rxr_idx, +- adapter->num_rx_queues, +- r_idx + 1); ++ adapter->num_rx_queues, ++ r_idx + 1); + } + r_idx = find_first_bit(q_vector->txr_idx, +- adapter->num_tx_queues); ++ adapter->num_tx_queues); + + for (i = 0; i < q_vector->txr_count; i++) { + j = adapter->tx_ring[r_idx].reg_idx; + ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(j), v_idx); + r_idx = find_next_bit(q_vector->txr_idx, +- adapter->num_tx_queues, +- r_idx + 1); ++ adapter->num_tx_queues, ++ r_idx + 1); + } + +- /* if this is a tx only vector use half the irq (tx) rate */ ++ /* if this is a tx only vector halve the interrupt rate */ + if (q_vector->txr_count && !q_vector->rxr_count) +- q_vector->eitr = adapter->tx_eitr; ++ q_vector->eitr = (adapter->eitr_param >> 1); + else +- /* rx only or mixed */ +- q_vector->eitr = adapter->rx_eitr; ++ /* rx only */ ++ q_vector->eitr = adapter->eitr_param; + + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), +- EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); ++ EITR_INTS_PER_SEC_TO_REG(q_vector->eitr)); + } + + ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, v_idx); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950); + +- /* set up to autoclear timer, lsc, and the vectors */ ++ /* set up to autoclear timer, and the vectors */ + mask = IXGBE_EIMS_ENABLE_MASK; +- mask &= ~IXGBE_EIMS_OTHER; ++ mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); + IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, mask); + } + +@@ -766,8 +798,8 @@ enum latency_range { + * parameter (see ixgbe_param.c) + **/ + static u8 ixgbe_update_itr(struct ixgbe_adapter *adapter, +- u32 eitr, u8 itr_setting, +- int packets, int bytes) ++ u32 eitr, u8 itr_setting, ++ int packets, int bytes) + { + unsigned int retval = itr_setting; + u32 timepassed_us; +@@ -814,40 +846,40 @@ static void ixgbe_set_itr_msix(struct ix + u32 new_itr; + u8 current_itr, ret_itr; + int i, r_idx, v_idx = ((void *)q_vector - (void *)(adapter->q_vector)) / +- sizeof(struct ixgbe_q_vector); ++ sizeof(struct ixgbe_q_vector); + struct ixgbe_ring *rx_ring, *tx_ring; + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { + tx_ring = &(adapter->tx_ring[r_idx]); + ret_itr = ixgbe_update_itr(adapter, q_vector->eitr, +- q_vector->tx_eitr, +- tx_ring->total_packets, +- tx_ring->total_bytes); ++ q_vector->tx_itr, ++ tx_ring->total_packets, ++ tx_ring->total_bytes); + /* if the result for this queue would decrease interrupt + * rate for this vector then use that result */ +- q_vector->tx_eitr = ((q_vector->tx_eitr > ret_itr) ? +- q_vector->tx_eitr - 1 : ret_itr); ++ q_vector->tx_itr = ((q_vector->tx_itr > ret_itr) ? ++ q_vector->tx_itr - 1 : ret_itr); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, +- r_idx + 1); ++ r_idx + 1); + } + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); + for (i = 0; i < q_vector->rxr_count; i++) { + rx_ring = &(adapter->rx_ring[r_idx]); + ret_itr = ixgbe_update_itr(adapter, q_vector->eitr, +- q_vector->rx_eitr, +- rx_ring->total_packets, +- rx_ring->total_bytes); ++ q_vector->rx_itr, ++ rx_ring->total_packets, ++ rx_ring->total_bytes); + /* if the result for this queue would decrease interrupt + * rate for this vector then use that result */ +- q_vector->rx_eitr = ((q_vector->rx_eitr > ret_itr) ? +- q_vector->rx_eitr - 1 : ret_itr); ++ q_vector->rx_itr = ((q_vector->rx_itr > ret_itr) ? ++ q_vector->rx_itr - 1 : ret_itr); + r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, +- r_idx + 1); ++ r_idx + 1); + } + +- current_itr = max(q_vector->rx_eitr, q_vector->tx_eitr); ++ current_itr = max(q_vector->rx_itr, q_vector->tx_itr); + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ +@@ -871,13 +903,27 @@ static void ixgbe_set_itr_msix(struct ix + itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr); + /* must write high and low 16 bits to reset counter */ + DPRINTK(TX_ERR, DEBUG, "writing eitr(%d): %08X\n", v_idx, +- itr_reg); ++ itr_reg); + IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg | (itr_reg)<<16); + } + + return; + } + ++ ++static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) ++{ ++ struct ixgbe_hw *hw = &adapter->hw; ++ ++ adapter->lsc_int++; ++ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; ++ adapter->link_check_timeout = jiffies; ++ if (!test_bit(__IXGBE_DOWN, &adapter->state)) { ++ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); ++ schedule_work(&adapter->watchdog_task); ++ } ++} ++ + static irqreturn_t ixgbe_msix_lsc(int irq, void *data) + { + struct net_device *netdev = data; +@@ -885,11 +931,8 @@ static irqreturn_t ixgbe_msix_lsc(int ir + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + +- if (eicr & IXGBE_EICR_LSC) { +- adapter->lsc_int++; +- if (!test_bit(__IXGBE_DOWN, &adapter->state)) +- mod_timer(&adapter->watchdog_timer, jiffies); +- } ++ if (eicr & IXGBE_EICR_LSC) ++ ixgbe_check_lsc(adapter); + + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); +@@ -901,7 +944,7 @@ static irqreturn_t ixgbe_msix_clean_tx(i + { + struct ixgbe_q_vector *q_vector = data; + struct ixgbe_adapter *adapter = q_vector->adapter; +- struct ixgbe_ring *txr; ++ struct ixgbe_ring *tx_ring; + int i, r_idx; + + if (!q_vector->txr_count) +@@ -909,16 +952,16 @@ static irqreturn_t ixgbe_msix_clean_tx(i + + r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues); + for (i = 0; i < q_vector->txr_count; i++) { +- txr = &(adapter->tx_ring[r_idx]); +-#ifdef CONFIG_DCA ++ tx_ring = &(adapter->tx_ring[r_idx]); ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) +- ixgbe_update_tx_dca(adapter, txr); ++ ixgbe_update_tx_dca(adapter, tx_ring); + #endif +- txr->total_bytes = 0; +- txr->total_packets = 0; +- ixgbe_clean_tx_irq(adapter, txr); ++ tx_ring->total_bytes = 0; ++ tx_ring->total_packets = 0; ++ ixgbe_clean_tx_irq(adapter, tx_ring); + r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues, +- r_idx + 1); ++ r_idx + 1); + } + + return IRQ_HANDLED; +@@ -933,18 +976,26 @@ static irqreturn_t ixgbe_msix_clean_rx(i + { + struct ixgbe_q_vector *q_vector = data; + struct ixgbe_adapter *adapter = q_vector->adapter; +- struct ixgbe_ring *rxr; ++ struct ixgbe_ring *rx_ring; + int r_idx; ++ int i; + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); ++ for (i = 0; i < q_vector->rxr_count; i++) { ++ rx_ring = &(adapter->rx_ring[r_idx]); ++ rx_ring->total_bytes = 0; ++ rx_ring->total_packets = 0; ++ r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, ++ r_idx + 1); ++ } ++ + if (!q_vector->rxr_count) + return IRQ_HANDLED; + +- rxr = &(adapter->rx_ring[r_idx]); ++ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); ++ rx_ring = &(adapter->rx_ring[r_idx]); + /* disable interrupts on this vector only */ +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->v_idx); +- rxr->total_bytes = 0; +- rxr->total_packets = 0; ++ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); + netif_rx_schedule(adapter->netdev, &q_vector->napi); + + return IRQ_HANDLED; +@@ -963,39 +1014,90 @@ static irqreturn_t ixgbe_msix_clean_many + * @napi: napi struct with our devices info in it + * @budget: amount of work driver is allowed to do this pass, in packets + * ++ * This function is optimized for cleaning one queue only on a single ++ * q_vector!!! + **/ + static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) + { + struct ixgbe_q_vector *q_vector = +- container_of(napi, struct ixgbe_q_vector, napi); ++ container_of(napi, struct ixgbe_q_vector, napi); + struct ixgbe_adapter *adapter = q_vector->adapter; +- struct ixgbe_ring *rxr; ++ struct ixgbe_ring *rx_ring = NULL; + int work_done = 0; + long r_idx; + + r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); +- rxr = &(adapter->rx_ring[r_idx]); +-#ifdef CONFIG_DCA ++ rx_ring = &(adapter->rx_ring[r_idx]); ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) +- ixgbe_update_rx_dca(adapter, rxr); ++ ixgbe_update_rx_dca(adapter, rx_ring); + #endif + +- ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget); ++ ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget); + + /* If all Rx work done, exit the polling mode */ + if (work_done < budget) { + netif_rx_complete(adapter->netdev, napi); +- if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS) ++ if (adapter->itr_setting & 3) + ixgbe_set_itr_msix(q_vector); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rxr->v_idx); ++ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx); + } + + return work_done; + } + ++/** ++ * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine ++ * @napi: napi struct with our devices info in it ++ * @budget: amount of work driver is allowed to do this pass, in packets ++ * ++ * This function will clean more than one rx queue associated with a ++ * q_vector. ++ **/ ++static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) ++{ ++ struct ixgbe_q_vector *q_vector = ++ container_of(napi, struct ixgbe_q_vector, napi); ++ struct ixgbe_adapter *adapter = q_vector->adapter; ++ struct ixgbe_ring *rx_ring = NULL; ++ int work_done = 0, i; ++ long r_idx; ++ u16 enable_mask = 0; ++ ++ /* attempt to distribute budget to each queue fairly, but don't allow ++ * the budget to go below 1 because we'll exit polling */ ++ budget /= (q_vector->rxr_count ?: 1); ++ budget = max(budget, 1); ++ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); ++ for (i = 0; i < q_vector->rxr_count; i++) { ++ rx_ring = &(adapter->rx_ring[r_idx]); ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) ++ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) ++ ixgbe_update_rx_dca(adapter, rx_ring); ++#endif ++ ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget); ++ enable_mask |= rx_ring->v_idx; ++ r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, ++ r_idx + 1); ++ } ++ ++ r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues); ++ rx_ring = &(adapter->rx_ring[r_idx]); ++ /* If all Rx work done, exit the polling mode */ ++ if (work_done < budget) { ++ netif_rx_complete(adapter->netdev, napi); ++ if (adapter->itr_setting & 3) ++ ixgbe_set_itr_msix(q_vector); ++ if (!test_bit(__IXGBE_DOWN, &adapter->state)) ++ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask); ++ return 0; ++ } ++ ++ return work_done; ++} + static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx, +- int r_idx) ++ int r_idx) + { + a->q_vector[v_idx].adapter = a; + set_bit(r_idx, a->q_vector[v_idx].rxr_idx); +@@ -1004,7 +1106,7 @@ static inline void map_vector_to_rxq(str + } + + static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx, +- int r_idx) ++ int r_idx) + { + a->q_vector[v_idx].adapter = a; + set_bit(r_idx, a->q_vector[v_idx].txr_idx); +@@ -1024,7 +1126,7 @@ static inline void map_vector_to_txq(str + * mapping configurations in here. + **/ + static int ixgbe_map_rings_to_vectors(struct ixgbe_adapter *adapter, +- int vectors) ++ int vectors) + { + int v_start = 0; + int rxr_idx = 0, txr_idx = 0; +@@ -1101,28 +1203,28 @@ static int ixgbe_request_msix_irqs(struc + goto out; + + #define SET_HANDLER(_v) ((!(_v)->rxr_count) ? &ixgbe_msix_clean_tx : \ +- (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \ +- &ixgbe_msix_clean_many) ++ (!(_v)->txr_count) ? &ixgbe_msix_clean_rx : \ ++ &ixgbe_msix_clean_many) + for (vector = 0; vector < q_vectors; vector++) { + handler = SET_HANDLER(&adapter->q_vector[vector]); + sprintf(adapter->name[vector], "%s:v%d-%s", +- netdev->name, vector, +- (handler == &ixgbe_msix_clean_rx) ? "Rx" : +- ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx")); ++ netdev->name, vector, ++ (handler == &ixgbe_msix_clean_rx) ? "Rx" : ++ ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx")); + err = request_irq(adapter->msix_entries[vector].vector, +- handler, 0, adapter->name[vector], +- &(adapter->q_vector[vector])); ++ handler, 0, adapter->name[vector], ++ &(adapter->q_vector[vector])); + if (err) { + DPRINTK(PROBE, ERR, +- "request_irq failed for MSIX interrupt " +- "Error: %d\n", err); ++ "request_irq failed for MSIX interrupt " ++ "Error: %d\n", err); + goto free_queue_irqs; + } + } + + sprintf(adapter->name[vector], "%s:lsc", netdev->name); + err = request_irq(adapter->msix_entries[vector].vector, +- &ixgbe_msix_lsc, 0, adapter->name[vector], netdev); ++ &ixgbe_msix_lsc, 0, adapter->name[vector], netdev); + if (err) { + DPRINTK(PROBE, ERR, + "request_irq for msix_lsc failed: %d\n", err); +@@ -1134,7 +1236,7 @@ static int ixgbe_request_msix_irqs(struc + free_queue_irqs: + for (i = vector - 1; i >= 0; i--) + free_irq(adapter->msix_entries[--vector].vector, +- &(adapter->q_vector[i])); ++ &(adapter->q_vector[i])); + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); +@@ -1152,16 +1254,16 @@ static void ixgbe_set_itr(struct ixgbe_a + struct ixgbe_ring *rx_ring = &adapter->rx_ring[0]; + struct ixgbe_ring *tx_ring = &adapter->tx_ring[0]; + +- q_vector->tx_eitr = ixgbe_update_itr(adapter, new_itr, +- q_vector->tx_eitr, +- tx_ring->total_packets, +- tx_ring->total_bytes); +- q_vector->rx_eitr = ixgbe_update_itr(adapter, new_itr, +- q_vector->rx_eitr, +- rx_ring->total_packets, +- rx_ring->total_bytes); ++ q_vector->tx_itr = ixgbe_update_itr(adapter, new_itr, ++ q_vector->tx_itr, ++ tx_ring->total_packets, ++ tx_ring->total_bytes); ++ q_vector->rx_itr = ixgbe_update_itr(adapter, new_itr, ++ q_vector->rx_itr, ++ rx_ring->total_packets, ++ rx_ring->total_bytes); + +- current_itr = max(q_vector->rx_eitr, q_vector->tx_eitr); ++ current_itr = max(q_vector->rx_itr, q_vector->tx_itr); + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ +@@ -1206,19 +1308,19 @@ static irqreturn_t ixgbe_intr(int irq, v + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr; + +- + /* for NAPI, using EIAM to auto-mask tx/rx interrupt bits on read + * therefore no explict interrupt disable is necessary */ + eicr = IXGBE_READ_REG(hw, IXGBE_EICR); +- if (!eicr) ++ if (!eicr) { ++ /* shared interrupt alert! ++ * make sure interrupts are enabled because the read will ++ * have disabled interrupts due to EIAM */ ++ ixgbe_irq_enable(adapter); + return IRQ_NONE; /* Not our interrupt */ +- +- if (eicr & IXGBE_EICR_LSC) { +- adapter->lsc_int++; +- if (!test_bit(__IXGBE_DOWN, &adapter->state)) +- mod_timer(&adapter->watchdog_timer, jiffies); + } + ++ if (eicr & IXGBE_EICR_LSC) ++ ixgbe_check_lsc(adapter); + + if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { + adapter->tx_ring[0].total_packets = 0; +@@ -1261,10 +1363,10 @@ static int ixgbe_request_irq(struct ixgb + err = ixgbe_request_msix_irqs(adapter); + } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) { + err = request_irq(adapter->pdev->irq, &ixgbe_intr, 0, +- netdev->name, netdev); ++ netdev->name, netdev); + } else { + err = request_irq(adapter->pdev->irq, &ixgbe_intr, IRQF_SHARED, +- netdev->name, netdev); ++ netdev->name, netdev); + } + + if (err) +@@ -1288,7 +1390,7 @@ static void ixgbe_free_irq(struct ixgbe_ + i--; + for (; i >= 0; i--) { + free_irq(adapter->msix_entries[i].vector, +- &(adapter->q_vector[i])); ++ &(adapter->q_vector[i])); + } + + ixgbe_reset_q_vectors(adapter); +@@ -1335,7 +1437,7 @@ static void ixgbe_configure_msi_and_lega + struct ixgbe_hw *hw = &adapter->hw; + + IXGBE_WRITE_REG(hw, IXGBE_EITR(0), +- EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr)); ++ EITR_INTS_PER_SEC_TO_REG(adapter->eitr_param)); + + ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0); + ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(0), 0); +@@ -1347,26 +1449,31 @@ static void ixgbe_configure_msi_and_lega + } + + /** +- * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset ++ * ixgbe_configure_tx - Configure 8259x Transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ + static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) + { +- u64 tdba; ++ u64 tdba, tdwba; + struct ixgbe_hw *hw = &adapter->hw; + u32 i, j, tdlen, txctrl; + + /* Setup the HW Tx Head and Tail descriptor pointers */ + for (i = 0; i < adapter->num_tx_queues; i++) { +- j = adapter->tx_ring[i].reg_idx; +- tdba = adapter->tx_ring[i].dma; +- tdlen = adapter->tx_ring[i].count * +- sizeof(union ixgbe_adv_tx_desc); ++ struct ixgbe_ring *ring = &adapter->tx_ring[i]; ++ j = ring->reg_idx; ++ tdba = ring->dma; ++ tdlen = ring->count * sizeof(union ixgbe_adv_tx_desc); + IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), +- (tdba & DMA_32BIT_MASK)); ++ (tdba & DMA_32BIT_MASK)); + IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); ++ tdwba = ring->dma + ++ (ring->count * sizeof(union ixgbe_adv_tx_desc)); ++ tdwba |= IXGBE_TDWBAL_HEAD_WB_ENABLE; ++ IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(j), tdwba & DMA_32BIT_MASK); ++ IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(j), (tdwba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen); + IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); + IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); +@@ -1375,20 +1482,59 @@ static void ixgbe_configure_tx(struct ix + /* Disable Tx Head Writeback RO bit, since this hoses + * bookkeeping if things aren't delivered in order. + */ +- txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); ++ txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); + txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; +- IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); ++ IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); + } + } + +-#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ +- (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) ++#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 ++ ++static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index) ++{ ++ struct ixgbe_ring *rx_ring; ++ u32 srrctl; ++ int queue0; ++ unsigned long mask; ++ ++ /* we must program one srrctl register per RSS queue since we ++ * have enabled RDRXCTL.MVMEN ++ */ ++ mask = (unsigned long)adapter->ring_feature[RING_F_RSS].mask; ++ queue0 = index & mask; ++ index = index & mask; ++ ++ rx_ring = &adapter->rx_ring[queue0]; ++ ++ srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(index)); ++ ++ srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; ++ srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; ++ ++ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { ++ srrctl |= IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; ++ srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; ++ srrctl |= ((IXGBE_RX_HDR_SIZE << ++ IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & ++ IXGBE_SRRCTL_BSIZEHDR_MASK); ++ } else { ++ srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; ++ ++ if (rx_ring->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) ++ srrctl |= IXGBE_RXBUFFER_2048 >> ++ IXGBE_SRRCTL_BSIZEPKT_SHIFT; ++ else ++ srrctl |= rx_ring->rx_buf_len >> ++ IXGBE_SRRCTL_BSIZEPKT_SHIFT; ++ } ++ IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl); ++} + +-#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 ++#ifdef CONFIG_IXGBE_LRO + /** + * ixgbe_get_skb_hdr - helper function for LRO header processing + * @skb: pointer to sk_buff to be added to LRO packet +- * @iphdr: pointer to tcp header structure ++ * @iphdr: pointer to ip header structure + * @tcph: pointer to tcp header structure + * @hdr_flags: pointer to header flags + * @priv: private data +@@ -1399,8 +1545,8 @@ static int ixgbe_get_skb_hdr(struct sk_b + union ixgbe_adv_rx_desc *rx_desc = priv; + + /* Verify that this is a valid IPv4 TCP packet */ +- if (!(rx_desc->wb.lower.lo_dword.pkt_info & +- (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP))) ++ if (!((ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_IPV4) && ++ (ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_TCP))) + return -1; + + /* Set network headers */ +@@ -1412,8 +1558,12 @@ static int ixgbe_get_skb_hdr(struct sk_b + return 0; + } + ++#endif /* CONFIG_IXGBE_LRO */ ++#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ ++ (((S) & (PAGE_SIZE - 1)) ? 1 : 0)) ++ + /** +- * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset ++ * ixgbe_configure_rx - Configure 8259x Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. +@@ -1426,25 +1576,26 @@ static void ixgbe_configure_rx(struct ix + int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + int i, j; + u32 rdlen, rxctrl, rxcsum; +- u32 random[10]; ++ static const u32 seed[10] = { 0xE291D73D, 0x1805EC6C, 0x2A94B30D, ++ 0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE, ++ 0x6A3E67EA, 0x14364D17, 0x3BED200D}; + u32 fctrl, hlreg0; + u32 pages; +- u32 reta = 0, mrqc, srrctl; ++ u32 reta = 0, mrqc; ++ u32 rdrxctl; ++ int rx_buf_len; + + /* Decide whether to use packet split mode or not */ +- if (netdev->mtu > ETH_DATA_LEN) +- adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; +- else +- adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED; ++ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED; + + /* Set the RX buffer length according to the mode */ + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +- adapter->rx_buf_len = IXGBE_RX_HDR_SIZE; ++ rx_buf_len = IXGBE_RX_HDR_SIZE; + } else { + if (netdev->mtu <= ETH_DATA_LEN) +- adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; ++ rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE; + else +- adapter->rx_buf_len = ALIGN(max_frame, 1024); ++ rx_buf_len = ALIGN(max_frame, 1024); + } + + fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); +@@ -1461,28 +1612,6 @@ static void ixgbe_configure_rx(struct ix + + pages = PAGE_USE_COUNT(adapter->netdev->mtu); + +- srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0)); +- srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; +- srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; +- +- if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +- srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +- srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; +- srrctl |= ((IXGBE_RX_HDR_SIZE << +- IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & +- IXGBE_SRRCTL_BSIZEHDR_MASK); +- } else { +- srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; +- +- if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE) +- srrctl |= +- IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +- else +- srrctl |= +- adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; +- } +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl); +- + rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc); + /* disable receives while setting up the descriptors */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); +@@ -1492,25 +1621,45 @@ static void ixgbe_configure_rx(struct ix + * the Base and Length of the Rx Descriptor Ring */ + for (i = 0; i < adapter->num_rx_queues; i++) { + rdba = adapter->rx_ring[i].dma; +- IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK)); +- IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); +- IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen); +- IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); +- IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); +- adapter->rx_ring[i].head = IXGBE_RDH(i); +- adapter->rx_ring[i].tail = IXGBE_RDT(i); +- } +- +- /* Intitial LRO Settings */ +- adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; +- adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; +- adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; +- adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; +- if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) +- adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; +- adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; +- adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; +- adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; ++ j = adapter->rx_ring[i].reg_idx; ++ IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), (rdba & DMA_32BIT_MASK)); ++ IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); ++ IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), rdlen); ++ IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); ++ IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); ++ adapter->rx_ring[i].head = IXGBE_RDH(j); ++ adapter->rx_ring[i].tail = IXGBE_RDT(j); ++ adapter->rx_ring[i].rx_buf_len = rx_buf_len; ++#ifdef CONFIG_IXGBE_LRO ++ /* Intitial LRO Settings */ ++ adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; ++ adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; ++ adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; ++ adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; ++ if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) ++ adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; ++ adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; ++ adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; ++ adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; ++#endif ++ ++ ixgbe_configure_srrctl(adapter, j); ++ } ++ ++ /* ++ * For VMDq support of different descriptor types or ++ * buffer sizes through the use of multiple SRRCTL ++ * registers, RDRXCTL.MVMEN must be set to 1 ++ * ++ * also, the manual doesn't mention it clearly but DCA hints ++ * will only use queue 0's tags unless this bit is set. Side ++ * effects of setting this bit are only that SRRCTL must be ++ * fully programmed [0..15] ++ */ ++ rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); ++ rdrxctl |= IXGBE_RDRXCTL_MVMEN; ++ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); ++ + + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { + /* Fill out redirection table */ +@@ -1525,22 +1674,20 @@ static void ixgbe_configure_rx(struct ix + } + + /* Fill out hash function seeds */ +- /* XXX use a random constant here to glue certain flows */ +- get_random_bytes(&random[0], 40); + for (i = 0; i < 10; i++) +- IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random[i]); ++ IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]); + + mrqc = IXGBE_MRQC_RSSEN + /* Perform hash on these packet types */ +- | IXGBE_MRQC_RSS_FIELD_IPV4 +- | IXGBE_MRQC_RSS_FIELD_IPV4_TCP +- | IXGBE_MRQC_RSS_FIELD_IPV4_UDP +- | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP +- | IXGBE_MRQC_RSS_FIELD_IPV6_EX +- | IXGBE_MRQC_RSS_FIELD_IPV6 +- | IXGBE_MRQC_RSS_FIELD_IPV6_TCP +- | IXGBE_MRQC_RSS_FIELD_IPV6_UDP +- | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; ++ | IXGBE_MRQC_RSS_FIELD_IPV4 ++ | IXGBE_MRQC_RSS_FIELD_IPV4_TCP ++ | IXGBE_MRQC_RSS_FIELD_IPV4_UDP ++ | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP ++ | IXGBE_MRQC_RSS_FIELD_IPV6_EX ++ | IXGBE_MRQC_RSS_FIELD_IPV6 ++ | IXGBE_MRQC_RSS_FIELD_IPV6_TCP ++ | IXGBE_MRQC_RSS_FIELD_IPV6_UDP ++ | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); + } + +@@ -1562,7 +1709,7 @@ static void ixgbe_configure_rx(struct ix + } + + static void ixgbe_vlan_rx_register(struct net_device *netdev, +- struct vlan_group *grp) ++ struct vlan_group *grp) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u32 ctrl; +@@ -1586,14 +1733,16 @@ static void ixgbe_vlan_rx_register(struc + static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ struct ixgbe_hw *hw = &adapter->hw; + + /* add VID to filter table */ +- ixgbe_set_vfta(&adapter->hw, vid, 0, true); ++ hw->mac.ops.set_vfta(&adapter->hw, vid, 0, true); + } + + static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ struct ixgbe_hw *hw = &adapter->hw; + + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_disable(adapter); +@@ -1604,7 +1753,7 @@ static void ixgbe_vlan_rx_kill_vid(struc + ixgbe_irq_enable(adapter); + + /* remove VID from filter table */ +- ixgbe_set_vfta(&adapter->hw, vid, 0, false); ++ hw->mac.ops.set_vfta(&adapter->hw, vid, 0, false); + } + + static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) +@@ -1621,23 +1770,37 @@ static void ixgbe_restore_vlan(struct ix + } + } + ++static u8 *ixgbe_addr_list_itr(struct ixgbe_hw *hw, u8 **mc_addr_ptr, u32 *vmdq) ++{ ++ struct dev_mc_list *mc_ptr; ++ u8 *addr = *mc_addr_ptr; ++ *vmdq = 0; ++ ++ mc_ptr = container_of(addr, struct dev_mc_list, dmi_addr[0]); ++ if (mc_ptr->next) ++ *mc_addr_ptr = mc_ptr->next->dmi_addr; ++ else ++ *mc_addr_ptr = NULL; ++ ++ return addr; ++} ++ + /** +- * ixgbe_set_multi - Multicast and Promiscuous mode set ++ * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set + * @netdev: network interface device structure + * +- * The set_multi entry point is called whenever the multicast address +- * list or the network interface flags are updated. This routine is +- * responsible for configuring the hardware for proper multicast, +- * promiscuous mode, and all-multi behavior. ++ * The set_rx_method entry point is called whenever the unicast/multicast ++ * address list or the network interface flags are updated. This routine is ++ * responsible for configuring the hardware for proper unicast, multicast and ++ * promiscuous mode. + **/ +-static void ixgbe_set_multi(struct net_device *netdev) ++static void ixgbe_set_rx_mode(struct net_device *netdev) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; +- struct dev_mc_list *mc_ptr; +- u8 *mta_list; + u32 fctrl, vlnctrl; +- int i; ++ u8 *addr_list = NULL; ++ int addr_count = 0; + + /* Check for Promiscuous and All Multicast modes */ + +@@ -1645,6 +1808,7 @@ static void ixgbe_set_multi(struct net_d + vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + + if (netdev->flags & IFF_PROMISC) { ++ hw->addr_ctrl.user_set_promisc = 1; + fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + vlnctrl &= ~IXGBE_VLNCTRL_VFE; + } else { +@@ -1655,33 +1819,25 @@ static void ixgbe_set_multi(struct net_d + fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); + } + vlnctrl |= IXGBE_VLNCTRL_VFE; ++ hw->addr_ctrl.user_set_promisc = 0; + } + + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); + +- if (netdev->mc_count) { +- mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC); +- if (!mta_list) +- return; +- +- /* Shared function expects packed array of only addresses. */ +- mc_ptr = netdev->mc_list; +- +- for (i = 0; i < netdev->mc_count; i++) { +- if (!mc_ptr) +- break; +- memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr, +- ETH_ALEN); +- mc_ptr = mc_ptr->next; +- } +- +- ixgbe_update_mc_addr_list(hw, mta_list, i, 0); +- kfree(mta_list); +- } else { +- ixgbe_update_mc_addr_list(hw, NULL, 0, 0); +- } +- ++ /* reprogram secondary unicast list */ ++ addr_count = netdev->uc_count; ++ if (addr_count) ++ addr_list = netdev->uc_list->dmi_addr; ++ hw->mac.ops.update_uc_addr_list(hw, addr_list, addr_count, ++ ixgbe_addr_list_itr); ++ ++ /* reprogram multicast list */ ++ addr_count = netdev->mc_count; ++ if (addr_count) ++ addr_list = netdev->mc_list->dmi_addr; ++ hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count, ++ ixgbe_addr_list_itr); + } + + static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter) +@@ -1695,10 +1851,16 @@ static void ixgbe_napi_enable_all(struct + q_vectors = 1; + + for (q_idx = 0; q_idx < q_vectors; q_idx++) { ++ struct napi_struct *napi; + q_vector = &adapter->q_vector[q_idx]; + if (!q_vector->rxr_count) + continue; +- napi_enable(&q_vector->napi); ++ napi = &q_vector->napi; ++ if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) && ++ (q_vector->rxr_count > 1)) ++ napi->poll = &ixgbe_clean_rxonly_many; ++ ++ napi_enable(napi); + } + } + +@@ -1725,7 +1887,7 @@ static void ixgbe_configure(struct ixgbe + struct net_device *netdev = adapter->netdev; + int i; + +- ixgbe_set_multi(netdev); ++ ixgbe_set_rx_mode(netdev); + + ixgbe_restore_vlan(adapter); + +@@ -1733,7 +1895,7 @@ static void ixgbe_configure(struct ixgbe + ixgbe_configure_rx(adapter); + for (i = 0; i < adapter->num_rx_queues; i++) + ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i], +- (adapter->rx_ring[i].count - 1)); ++ (adapter->rx_ring[i].count - 1)); + } + + static int ixgbe_up_complete(struct ixgbe_adapter *adapter) +@@ -1751,7 +1913,7 @@ static int ixgbe_up_complete(struct ixgb + (adapter->flags & IXGBE_FLAG_MSI_ENABLED)) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME | +- IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD); ++ IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD); + } else { + /* MSI only */ + gpie = 0; +@@ -1778,6 +1940,8 @@ static int ixgbe_up_complete(struct ixgb + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); ++ /* enable WTHRESH=8 descriptors, to encourage burst writeback */ ++ txdctl |= (8 << 16); + txdctl |= IXGBE_TXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); + } +@@ -1812,6 +1976,8 @@ static int ixgbe_up_complete(struct ixgb + + /* bring the link up in the watchdog, this could race with our first + * link up interrupt but shouldn't be a problem */ ++ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; ++ adapter->link_check_timeout = jiffies; + mod_timer(&adapter->watchdog_timer, jiffies); + return 0; + } +@@ -1836,50 +2002,14 @@ int ixgbe_up(struct ixgbe_adapter *adapt + + void ixgbe_reset(struct ixgbe_adapter *adapter) + { +- if (ixgbe_init_hw(&adapter->hw)) +- DPRINTK(PROBE, ERR, "Hardware Error\n"); ++ struct ixgbe_hw *hw = &adapter->hw; ++ if (hw->mac.ops.init_hw(hw)) ++ dev_err(&adapter->pdev->dev, "Hardware Error\n"); + + /* reprogram the RAR[0] in case user changed it. */ +- ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); +- +-} +- +-#ifdef CONFIG_PM +-static int ixgbe_resume(struct pci_dev *pdev) +-{ +- struct net_device *netdev = pci_get_drvdata(pdev); +- struct ixgbe_adapter *adapter = netdev_priv(netdev); +- u32 err; +- +- pci_set_power_state(pdev, PCI_D0); +- pci_restore_state(pdev); +- err = pci_enable_device(pdev); +- if (err) { +- printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \ +- "suspend\n"); +- return err; +- } +- pci_set_master(pdev); +- +- pci_enable_wake(pdev, PCI_D3hot, 0); +- pci_enable_wake(pdev, PCI_D3cold, 0); +- +- if (netif_running(netdev)) { +- err = ixgbe_request_irq(adapter); +- if (err) +- return err; +- } +- +- ixgbe_reset(adapter); +- +- if (netif_running(netdev)) +- ixgbe_up(adapter); +- +- netif_device_attach(netdev); ++ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + +- return 0; + } +-#endif + + /** + * ixgbe_clean_rx_ring - Free Rx Buffers per Queue +@@ -1887,7 +2017,7 @@ static int ixgbe_resume(struct pci_dev * + * @rx_ring: ring to free buffers from + **/ + static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rx_ring) ++ struct ixgbe_ring *rx_ring) + { + struct pci_dev *pdev = adapter->pdev; + unsigned long size; +@@ -1901,8 +2031,8 @@ static void ixgbe_clean_rx_ring(struct i + rx_buffer_info = &rx_ring->rx_buffer_info[i]; + if (rx_buffer_info->dma) { + pci_unmap_single(pdev, rx_buffer_info->dma, +- adapter->rx_buf_len, +- PCI_DMA_FROMDEVICE); ++ rx_ring->rx_buf_len, ++ PCI_DMA_FROMDEVICE); + rx_buffer_info->dma = 0; + } + if (rx_buffer_info->skb) { +@@ -1911,12 +2041,12 @@ static void ixgbe_clean_rx_ring(struct i + } + if (!rx_buffer_info->page) + continue; +- pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE, +- PCI_DMA_FROMDEVICE); ++ pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2, ++ PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; +- + put_page(rx_buffer_info->page); + rx_buffer_info->page = NULL; ++ rx_buffer_info->page_offset = 0; + } + + size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; +@@ -1938,7 +2068,7 @@ static void ixgbe_clean_rx_ring(struct i + * @tx_ring: ring to be cleaned + **/ + static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring) ++ struct ixgbe_ring *tx_ring) + { + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned long size; +@@ -1991,96 +2121,85 @@ static void ixgbe_clean_all_tx_rings(str + void ixgbe_down(struct ixgbe_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; ++ struct ixgbe_hw *hw = &adapter->hw; + u32 rxctrl; ++ u32 txdctl; ++ int i, j; + + /* signal that we are down to the interrupt handler */ + set_bit(__IXGBE_DOWN, &adapter->state); + + /* disable receives */ +- rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL); +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, +- rxctrl & ~IXGBE_RXCTRL_RXEN); ++ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); ++ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); + + netif_tx_disable(netdev); + +- /* disable transmits in the hardware */ +- +- /* flush both disables */ +- IXGBE_WRITE_FLUSH(&adapter->hw); ++ IXGBE_WRITE_FLUSH(hw); + msleep(10); + ++ netif_tx_stop_all_queues(netdev); ++ + ixgbe_irq_disable(adapter); + + ixgbe_napi_disable_all(adapter); ++ + del_timer_sync(&adapter->watchdog_timer); ++ cancel_work_sync(&adapter->watchdog_task); ++ ++ /* disable transmits in the hardware now that interrupts are off */ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ j = adapter->tx_ring[i].reg_idx; ++ txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); ++ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), ++ (txdctl & ~IXGBE_TXDCTL_ENABLE)); ++ } + + netif_carrier_off(netdev); +- netif_tx_stop_all_queues(netdev); + ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) ++ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { ++ adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; ++ dca_remove_requester(&adapter->pdev->dev); ++ } ++ ++#endif + if (!pci_channel_offline(adapter->pdev)) + ixgbe_reset(adapter); + ixgbe_clean_all_tx_rings(adapter); + ixgbe_clean_all_rx_rings(adapter); + ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) ++ /* since we reset the hardware DCA settings were cleared */ ++ if (dca_add_requester(&adapter->pdev->dev) == 0) { ++ adapter->flags |= IXGBE_FLAG_DCA_ENABLED; ++ /* always use CB2 mode, difference is masked ++ * in the CB driver */ ++ IXGBE_WRITE_REG(hw, IXGBE_DCA_CTRL, 2); ++ ixgbe_setup_dca(adapter); ++ } ++#endif + } + +-static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) ++/** ++ * ixgbe_poll - NAPI Rx polling callback ++ * @napi: structure for representing this polling device ++ * @budget: how many packets driver is allowed to clean ++ * ++ * This function is used for legacy and MSI, NAPI mode ++ **/ ++static int ixgbe_poll(struct napi_struct *napi, int budget) + { +- struct net_device *netdev = pci_get_drvdata(pdev); +- struct ixgbe_adapter *adapter = netdev_priv(netdev); +-#ifdef CONFIG_PM +- int retval = 0; +-#endif +- +- netif_device_detach(netdev); +- +- if (netif_running(netdev)) { +- ixgbe_down(adapter); +- ixgbe_free_irq(adapter); +- } +- +-#ifdef CONFIG_PM +- retval = pci_save_state(pdev); +- if (retval) +- return retval; +-#endif +- +- pci_enable_wake(pdev, PCI_D3hot, 0); +- pci_enable_wake(pdev, PCI_D3cold, 0); +- +- ixgbe_release_hw_control(adapter); +- +- pci_disable_device(pdev); +- +- pci_set_power_state(pdev, pci_choose_state(pdev, state)); +- +- return 0; +-} +- +-static void ixgbe_shutdown(struct pci_dev *pdev) +-{ +- ixgbe_suspend(pdev, PMSG_SUSPEND); +-} +- +-/** +- * ixgbe_poll - NAPI Rx polling callback +- * @napi: structure for representing this polling device +- * @budget: how many packets driver is allowed to clean +- * +- * This function is used for legacy and MSI, NAPI mode +- **/ +-static int ixgbe_poll(struct napi_struct *napi, int budget) +-{ +- struct ixgbe_q_vector *q_vector = container_of(napi, +- struct ixgbe_q_vector, napi); +- struct ixgbe_adapter *adapter = q_vector->adapter; +- int tx_cleaned = 0, work_done = 0; +- +-#ifdef CONFIG_DCA +- if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { +- ixgbe_update_tx_dca(adapter, adapter->tx_ring); +- ixgbe_update_rx_dca(adapter, adapter->rx_ring); +- } ++ struct ixgbe_q_vector *q_vector = container_of(napi, ++ struct ixgbe_q_vector, napi); ++ struct ixgbe_adapter *adapter = q_vector->adapter; ++ int tx_cleaned, work_done = 0; ++ ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) ++ if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { ++ ixgbe_update_tx_dca(adapter, adapter->tx_ring); ++ ixgbe_update_rx_dca(adapter, adapter->rx_ring); ++ } + #endif + + tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); +@@ -2092,12 +2211,11 @@ static int ixgbe_poll(struct napi_struct + /* If budget not fully consumed, exit the polling mode */ + if (work_done < budget) { + netif_rx_complete(adapter->netdev, napi); +- if (adapter->rx_eitr < IXGBE_MIN_ITR_USECS) ++ if (adapter->itr_setting & 3) + ixgbe_set_itr(adapter); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable(adapter); + } +- + return work_done; + } + +@@ -2123,8 +2241,48 @@ static void ixgbe_reset_task(struct work + ixgbe_reinit_locked(adapter); + } + ++static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) ++{ ++ int nrq = 1, ntq = 1; ++ int feature_mask = 0, rss_i, rss_m; ++ ++ /* Number of supported queues */ ++ switch (adapter->hw.mac.type) { ++ case ixgbe_mac_82598EB: ++ rss_i = adapter->ring_feature[RING_F_RSS].indices; ++ rss_m = 0; ++ feature_mask |= IXGBE_FLAG_RSS_ENABLED; ++ ++ switch (adapter->flags & feature_mask) { ++ case (IXGBE_FLAG_RSS_ENABLED): ++ rss_m = 0xF; ++ nrq = rss_i; ++ ntq = rss_i; ++ break; ++ case 0: ++ default: ++ rss_i = 0; ++ rss_m = 0; ++ nrq = 1; ++ ntq = 1; ++ break; ++ } ++ ++ adapter->ring_feature[RING_F_RSS].indices = rss_i; ++ adapter->ring_feature[RING_F_RSS].mask = rss_m; ++ break; ++ default: ++ nrq = 1; ++ ntq = 1; ++ break; ++ } ++ ++ adapter->num_rx_queues = nrq; ++ adapter->num_tx_queues = ntq; ++} ++ + static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, +- int vectors) ++ int vectors) + { + int err, vector_threshold; + +@@ -2143,7 +2301,7 @@ static void ixgbe_acquire_msix_vectors(s + */ + while (vectors >= vector_threshold) { + err = pci_enable_msix(adapter->pdev, adapter->msix_entries, +- vectors); ++ vectors); + if (!err) /* Success in acquiring all requested vectors. */ + break; + else if (err < 0) +@@ -2162,54 +2320,13 @@ static void ixgbe_acquire_msix_vectors(s + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; +- adapter->num_tx_queues = 1; +- adapter->num_rx_queues = 1; ++ ixgbe_set_num_queues(adapter); + } else { + adapter->flags |= IXGBE_FLAG_MSIX_ENABLED; /* Woot! */ + adapter->num_msix_vectors = vectors; + } + } + +-static void __devinit ixgbe_set_num_queues(struct ixgbe_adapter *adapter) +-{ +- int nrq, ntq; +- int feature_mask = 0, rss_i, rss_m; +- +- /* Number of supported queues */ +- switch (adapter->hw.mac.type) { +- case ixgbe_mac_82598EB: +- rss_i = adapter->ring_feature[RING_F_RSS].indices; +- rss_m = 0; +- feature_mask |= IXGBE_FLAG_RSS_ENABLED; +- +- switch (adapter->flags & feature_mask) { +- case (IXGBE_FLAG_RSS_ENABLED): +- rss_m = 0xF; +- nrq = rss_i; +- ntq = rss_i; +- break; +- case 0: +- default: +- rss_i = 0; +- rss_m = 0; +- nrq = 1; +- ntq = 1; +- break; +- } +- +- adapter->ring_feature[RING_F_RSS].indices = rss_i; +- adapter->ring_feature[RING_F_RSS].mask = rss_m; +- break; +- default: +- nrq = 1; +- ntq = 1; +- break; +- } +- +- adapter->num_rx_queues = nrq; +- adapter->num_tx_queues = ntq; +-} +- + /** + * ixgbe_cache_ring_register - Descriptor ring to register mapping + * @adapter: board private structure to initialize +@@ -2219,9 +2336,6 @@ static void __devinit ixgbe_set_num_queu + **/ + static void __devinit ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) + { +- /* TODO: Remove all uses of the indices in the cases where multiple +- * features are OR'd together, if the feature set makes sense. +- */ + int feature_mask = 0, rss_i; + int i, txr_idx, rxr_idx; + +@@ -2262,21 +2376,22 @@ static int __devinit ixgbe_alloc_queues( + int i; + + adapter->tx_ring = kcalloc(adapter->num_tx_queues, +- sizeof(struct ixgbe_ring), GFP_KERNEL); ++ sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!adapter->tx_ring) + goto err_tx_ring_allocation; + + adapter->rx_ring = kcalloc(adapter->num_rx_queues, +- sizeof(struct ixgbe_ring), GFP_KERNEL); ++ sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!adapter->rx_ring) + goto err_rx_ring_allocation; + + for (i = 0; i < adapter->num_tx_queues; i++) { +- adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD; ++ adapter->tx_ring[i].count = adapter->tx_ring_count; + adapter->tx_ring[i].queue_index = i; + } ++ + for (i = 0; i < adapter->num_rx_queues; i++) { +- adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD; ++ adapter->rx_ring[i].count = adapter->rx_ring_count; + adapter->rx_ring[i].queue_index = i; + } + +@@ -2298,25 +2413,19 @@ err_tx_ring_allocation: + * capabilities of the hardware and the kernel. + **/ + static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter +- *adapter) ++ *adapter) + { + int err = 0; + int vector, v_budget; + + /* +- * Set the default interrupt throttle rate. +- */ +- adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS); +- adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS); +- +- /* + * It's easy to be greedy for MSI-X vectors, but it really + * doesn't do us much good if we have a lot more vectors + * than CPU's. So let's be conservative and only ask for + * (roughly) twice the number of vectors as there are CPU's. + */ + v_budget = min(adapter->num_rx_queues + adapter->num_tx_queues, +- (int)(num_online_cpus() * 2)) + NON_Q_VECTORS; ++ (int)(num_online_cpus() * 2)) + NON_Q_VECTORS; + + /* + * At the same time, hardware can only support a maximum of +@@ -2330,7 +2439,7 @@ static int __devinit ixgbe_set_interrupt + /* A failure in MSI-X entry allocation isn't fatal, but it does + * mean we disable MSI-X capabilities of the adapter. */ + adapter->msix_entries = kcalloc(v_budget, +- sizeof(struct msix_entry), GFP_KERNEL); ++ sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) { + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + ixgbe_set_num_queues(adapter); +@@ -2339,7 +2448,7 @@ static int __devinit ixgbe_set_interrupt + err = ixgbe_alloc_queues(adapter); + if (err) { + DPRINTK(PROBE, ERR, "Unable to allocate memory " +- "for queues\n"); ++ "for queues\n"); + goto out; + } + +@@ -2360,7 +2469,7 @@ try_msi: + adapter->flags |= IXGBE_FLAG_MSI_ENABLED; + } else { + DPRINTK(HW, DEBUG, "Unable to allocate MSI interrupt, " +- "falling back to legacy. Error: %d\n", err); ++ "falling back to legacy. Error: %d\n", err); + /* reset err */ + err = 0; + } +@@ -2416,9 +2525,9 @@ static int __devinit ixgbe_init_interrup + } + + DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, " +- "Tx Queue count = %u\n", +- (adapter->num_rx_queues > 1) ? "Enabled" : +- "Disabled", adapter->num_rx_queues, adapter->num_tx_queues); ++ "Tx Queue count = %u\n", ++ (adapter->num_rx_queues > 1) ? "Enabled" : ++ "Disabled", adapter->num_rx_queues, adapter->num_tx_queues); + + set_bit(__IXGBE_DOWN, &adapter->state); + +@@ -2445,33 +2554,44 @@ static int __devinit ixgbe_sw_init(struc + struct pci_dev *pdev = adapter->pdev; + unsigned int rss; + ++ /* PCI config space info */ ++ ++ hw->vendor_id = pdev->vendor; ++ hw->device_id = pdev->device; ++ hw->revision_id = pdev->revision; ++ hw->subsystem_vendor_id = pdev->subsystem_vendor; ++ hw->subsystem_device_id = pdev->subsystem_device; ++ + /* Set capability flags */ + rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus()); + adapter->ring_feature[RING_F_RSS].indices = rss; + adapter->flags |= IXGBE_FLAG_RSS_ENABLED; + +- /* Enable Dynamic interrupt throttling by default */ +- adapter->rx_eitr = 1; +- adapter->tx_eitr = 1; +- + /* default flow control settings */ +- hw->fc.original_type = ixgbe_fc_full; +- hw->fc.type = ixgbe_fc_full; ++ hw->fc.original_type = ixgbe_fc_none; ++ hw->fc.type = ixgbe_fc_none; ++ hw->fc.high_water = IXGBE_DEFAULT_FCRTH; ++ hw->fc.low_water = IXGBE_DEFAULT_FCRTL; ++ hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; ++ hw->fc.send_xon = true; + + /* select 10G link by default */ + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN; +- if (hw->mac.ops.reset(hw)) { +- dev_err(&pdev->dev, "HW Init failed\n"); +- return -EIO; +- } +- if (hw->mac.ops.setup_link_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true, +- false)) { +- dev_err(&pdev->dev, "Link Speed setup failed\n"); +- return -EIO; +- } ++ ++ /* enable itr by default in dynamic mode */ ++ adapter->itr_setting = 1; ++ adapter->eitr_param = 20000; ++ ++ /* set defaults for eitr in MegaBytes */ ++ adapter->eitr_low = 10; ++ adapter->eitr_high = 20; ++ ++ /* set default ring sizes */ ++ adapter->tx_ring_count = IXGBE_DEFAULT_TXD; ++ adapter->rx_ring_count = IXGBE_DEFAULT_RXD; + + /* initialize eeprom parameters */ +- if (ixgbe_init_eeprom(hw)) { ++ if (ixgbe_init_eeprom_params_generic(hw)) { + dev_err(&pdev->dev, "EEPROM initialization failed\n"); + return -EIO; + } +@@ -2487,105 +2607,160 @@ static int __devinit ixgbe_sw_init(struc + /** + * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure +- * @txdr: tx descriptor ring (for a specific queue) to setup ++ * @tx_ring: tx descriptor ring (for a specific queue) to setup + * + * Return 0 on success, negative on failure + **/ + int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *txdr) ++ struct ixgbe_ring *tx_ring) + { + struct pci_dev *pdev = adapter->pdev; + int size; + +- size = sizeof(struct ixgbe_tx_buffer) * txdr->count; +- txdr->tx_buffer_info = vmalloc(size); +- if (!txdr->tx_buffer_info) { +- DPRINTK(PROBE, ERR, +- "Unable to allocate memory for the transmit descriptor ring\n"); +- return -ENOMEM; +- } +- memset(txdr->tx_buffer_info, 0, size); ++ size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count; ++ tx_ring->tx_buffer_info = vmalloc(size); ++ if (!tx_ring->tx_buffer_info) ++ goto err; ++ memset(tx_ring->tx_buffer_info, 0, size); + + /* round up to nearest 4K */ +- txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc); +- txdr->size = ALIGN(txdr->size, 4096); ++ tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc) + ++ sizeof(u32); ++ tx_ring->size = ALIGN(tx_ring->size, 4096); ++ ++ tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, ++ &tx_ring->dma); ++ if (!tx_ring->desc) ++ goto err; + +- txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); +- if (!txdr->desc) { +- vfree(txdr->tx_buffer_info); +- DPRINTK(PROBE, ERR, +- "Memory allocation failed for the tx desc ring\n"); +- return -ENOMEM; +- } ++ tx_ring->next_to_use = 0; ++ tx_ring->next_to_clean = 0; ++ tx_ring->work_limit = tx_ring->count; ++ return 0; + +- txdr->next_to_use = 0; +- txdr->next_to_clean = 0; +- txdr->work_limit = txdr->count; ++err: ++ vfree(tx_ring->tx_buffer_info); ++ tx_ring->tx_buffer_info = NULL; ++ DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit " ++ "descriptor ring\n"); ++ return -ENOMEM; ++} + +- return 0; ++/** ++ * ixgbe_setup_all_tx_resources - allocate all queues Tx resources ++ * @adapter: board private structure ++ * ++ * If this function returns with an error, then it's possible one or ++ * more of the rings is populated (while the rest are not). It is the ++ * callers duty to clean those orphaned rings. ++ * ++ * Return 0 on success, negative on failure ++ **/ ++static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) ++{ ++ int i, err = 0; ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); ++ if (!err) ++ continue; ++ DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i); ++ break; ++ } ++ ++ return err; + } + + /** + * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure +- * @rxdr: rx descriptor ring (for a specific queue) to setup ++ * @rx_ring: rx descriptor ring (for a specific queue) to setup + * + * Returns 0 on success, negative on failure + **/ + int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rxdr) ++ struct ixgbe_ring *rx_ring) + { + struct pci_dev *pdev = adapter->pdev; + int size; + ++#ifdef CONFIG_IXGBE_LRO + size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS; +- rxdr->lro_mgr.lro_arr = vmalloc(size); +- if (!rxdr->lro_mgr.lro_arr) ++ rx_ring->lro_mgr.lro_arr = vmalloc(size); ++ if (!rx_ring->lro_mgr.lro_arr) + return -ENOMEM; +- memset(rxdr->lro_mgr.lro_arr, 0, size); +- +- size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; +- rxdr->rx_buffer_info = vmalloc(size); +- if (!rxdr->rx_buffer_info) { ++ memset(rx_ring->lro_mgr.lro_arr, 0, size); ++#endif ++ size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; ++ rx_ring->rx_buffer_info = vmalloc(size); ++ if (!rx_ring->rx_buffer_info) { + DPRINTK(PROBE, ERR, +- "vmalloc allocation failed for the rx desc ring\n"); ++ "vmalloc allocation failed for the rx desc ring\n"); + goto alloc_failed; + } +- memset(rxdr->rx_buffer_info, 0, size); ++ memset(rx_ring->rx_buffer_info, 0, size); + + /* Round up to nearest 4K */ +- rxdr->size = rxdr->count * sizeof(union ixgbe_adv_rx_desc); +- rxdr->size = ALIGN(rxdr->size, 4096); ++ rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc); ++ rx_ring->size = ALIGN(rx_ring->size, 4096); + +- rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); ++ rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, &rx_ring->dma); + +- if (!rxdr->desc) { ++ if (!rx_ring->desc) { + DPRINTK(PROBE, ERR, +- "Memory allocation failed for the rx desc ring\n"); +- vfree(rxdr->rx_buffer_info); ++ "Memory allocation failed for the rx desc ring\n"); ++ vfree(rx_ring->rx_buffer_info); + goto alloc_failed; + } + +- rxdr->next_to_clean = 0; +- rxdr->next_to_use = 0; ++ rx_ring->next_to_clean = 0; ++ rx_ring->next_to_use = 0; + + return 0; + + alloc_failed: +- vfree(rxdr->lro_mgr.lro_arr); +- rxdr->lro_mgr.lro_arr = NULL; ++#ifdef CONFIG_IXGBE_LRO ++ vfree(rx_ring->lro_mgr.lro_arr); ++ rx_ring->lro_mgr.lro_arr = NULL; ++#endif + return -ENOMEM; + } + + /** ++ * ixgbe_setup_all_rx_resources - allocate all queues Rx resources ++ * @adapter: board private structure ++ * ++ * If this function returns with an error, then it's possible one or ++ * more of the rings is populated (while the rest are not). It is the ++ * callers duty to clean those orphaned rings. ++ * ++ * Return 0 on success, negative on failure ++ **/ ++ ++static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) ++{ ++ int i, err = 0; ++ ++ for (i = 0; i < adapter->num_rx_queues; i++) { ++ err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); ++ if (!err) ++ continue; ++ DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i); ++ break; ++ } ++ ++ return err; ++} ++ ++/** + * ixgbe_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + **/ +-static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring) ++void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter, ++ struct ixgbe_ring *tx_ring) + { + struct pci_dev *pdev = adapter->pdev; + +@@ -2620,13 +2795,15 @@ static void ixgbe_free_all_tx_resources( + * + * Free all receive software resources + **/ +-static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *rx_ring) ++void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, ++ struct ixgbe_ring *rx_ring) + { + struct pci_dev *pdev = adapter->pdev; + ++#ifdef CONFIG_IXGBE_LRO + vfree(rx_ring->lro_mgr.lro_arr); + rx_ring->lro_mgr.lro_arr = NULL; ++#endif + + ixgbe_clean_rx_ring(adapter, rx_ring); + +@@ -2653,59 +2830,6 @@ static void ixgbe_free_all_rx_resources( + } + + /** +- * ixgbe_setup_all_tx_resources - allocate all queues Tx resources +- * @adapter: board private structure +- * +- * If this function returns with an error, then it's possible one or +- * more of the rings is populated (while the rest are not). It is the +- * callers duty to clean those orphaned rings. +- * +- * Return 0 on success, negative on failure +- **/ +-static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) +-{ +- int i, err = 0; +- +- for (i = 0; i < adapter->num_tx_queues; i++) { +- err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]); +- if (err) { +- DPRINTK(PROBE, ERR, +- "Allocation for Tx Queue %u failed\n", i); +- break; +- } +- } +- +- return err; +-} +- +-/** +- * ixgbe_setup_all_rx_resources - allocate all queues Rx resources +- * @adapter: board private structure +- * +- * If this function returns with an error, then it's possible one or +- * more of the rings is populated (while the rest are not). It is the +- * callers duty to clean those orphaned rings. +- * +- * Return 0 on success, negative on failure +- **/ +- +-static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter) +-{ +- int i, err = 0; +- +- for (i = 0; i < adapter->num_rx_queues; i++) { +- err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]); +- if (err) { +- DPRINTK(PROBE, ERR, +- "Allocation for Rx Queue %u failed\n", i); +- break; +- } +- } +- +- return err; +-} +- +-/** + * ixgbe_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size +@@ -2717,12 +2841,12 @@ static int ixgbe_change_mtu(struct net_d + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + +- if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) || +- (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE)) ++ /* MTU < 68 is an error and causes problems on some kernels */ ++ if ((new_mtu < 68) || (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE)) + return -EINVAL; + + DPRINTK(PROBE, INFO, "changing MTU from %d to %d\n", +- netdev->mtu, new_mtu); ++ netdev->mtu, new_mtu); + /* must set new MTU before calling down or up */ + netdev->mtu = new_mtu; + +@@ -2817,6 +2941,135 @@ static int ixgbe_close(struct net_device + } + + /** ++ * ixgbe_napi_add_all - prep napi structs for use ++ * @adapter: private struct ++ * helper function to napi_add each possible q_vector->napi ++ */ ++static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) ++{ ++ int q_idx, q_vectors; ++ int (*poll)(struct napi_struct *, int); ++ ++ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { ++ poll = &ixgbe_clean_rxonly; ++ /* Only enable as many vectors as we have rx queues. */ ++ q_vectors = adapter->num_rx_queues; ++ } else { ++ poll = &ixgbe_poll; ++ /* only one q_vector for legacy modes */ ++ q_vectors = 1; ++ } ++ ++ for (q_idx = 0; q_idx < q_vectors; q_idx++) { ++ struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx]; ++ netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64); ++ } ++} ++ ++static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) ++{ ++ int q_idx; ++ int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; ++ ++ /* legacy and MSI only use one vector */ ++ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) ++ q_vectors = 1; ++ ++ for (q_idx = 0; q_idx < q_vectors; q_idx++) { ++ struct ixgbe_q_vector *q_vector = &adapter->q_vector[q_idx]; ++ if (!q_vector->rxr_count) ++ continue; ++ netif_napi_del(&q_vector->napi); ++ } ++} ++ ++#ifdef CONFIG_PM ++static int ixgbe_resume(struct pci_dev *pdev) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ u32 err; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ err = pci_enable_device(pdev); ++ if (err) { ++ printk(KERN_ERR "ixgbe: Cannot enable PCI device from " ++ "suspend\n"); ++ return err; ++ } ++ pci_set_master(pdev); ++ ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); ++ ++ err = ixgbe_init_interrupt_scheme(adapter); ++ if (err) { ++ printk(KERN_ERR "ixgbe: Cannot initialize interrupts for " ++ "device\n"); ++ return err; ++ } ++ ++ ixgbe_napi_add_all(adapter); ++ ixgbe_reset(adapter); ++ ++ if (netif_running(netdev)) { ++ err = ixgbe_open(adapter->netdev); ++ if (err) ++ return err; ++ } ++ ++ netif_device_attach(netdev); ++ ++ return 0; ++} ++ ++#endif /* CONFIG_PM */ ++static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct net_device *netdev = pci_get_drvdata(pdev); ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++#ifdef CONFIG_PM ++ int retval = 0; ++#endif ++ ++ netif_device_detach(netdev); ++ ++ if (netif_running(netdev)) { ++ ixgbe_down(adapter); ++ ixgbe_free_irq(adapter); ++ ixgbe_free_all_tx_resources(adapter); ++ ixgbe_free_all_rx_resources(adapter); ++ } ++ ixgbe_reset_interrupt_capability(adapter); ++ ixgbe_napi_del_all(adapter); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ ++#ifdef CONFIG_PM ++ retval = pci_save_state(pdev); ++ if (retval) ++ return retval; ++#endif ++ ++ pci_enable_wake(pdev, PCI_D3hot, 0); ++ pci_enable_wake(pdev, PCI_D3cold, 0); ++ ++ ixgbe_release_hw_control(adapter); ++ ++ pci_disable_device(pdev); ++ ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ ++ return 0; ++} ++ ++static void ixgbe_shutdown(struct pci_dev *pdev) ++{ ++ ixgbe_suspend(pdev, PMSG_SUSPEND); ++} ++ ++/** + * ixgbe_update_stats - Update the board statistics counters. + * @adapter: board private structure + **/ +@@ -2889,7 +3142,7 @@ void ixgbe_update_stats(struct ixgbe_ada + + /* Rx Errors */ + adapter->net_stats.rx_errors = adapter->stats.crcerrs + +- adapter->stats.rlec; ++ adapter->stats.rlec; + adapter->net_stats.rx_dropped = 0; + adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; +@@ -2903,27 +3156,74 @@ void ixgbe_update_stats(struct ixgbe_ada + static void ixgbe_watchdog(unsigned long data) + { + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; ++ struct ixgbe_hw *hw = &adapter->hw; ++ ++ /* Do the watchdog outside of interrupt context due to the lovely ++ * delays that some of the newer hardware requires */ ++ if (!test_bit(__IXGBE_DOWN, &adapter->state)) { ++ /* Cause software interrupt to ensure rx rings are cleaned */ ++ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { ++ u32 eics = ++ (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1; ++ IXGBE_WRITE_REG(hw, IXGBE_EICS, eics); ++ } else { ++ /* For legacy and MSI interrupts don't set any bits that ++ * are enabled for EIAM, because this operation would ++ * set *both* EIMS and EICS for any bit in EIAM */ ++ IXGBE_WRITE_REG(hw, IXGBE_EICS, ++ (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); ++ } ++ /* Reset the timer */ ++ mod_timer(&adapter->watchdog_timer, ++ round_jiffies(jiffies + 2 * HZ)); ++ } ++ ++ schedule_work(&adapter->watchdog_task); ++} ++ ++/** ++ * ixgbe_watchdog_task - worker thread to bring link up ++ * @work: pointer to work_struct containing our data ++ **/ ++static void ixgbe_watchdog_task(struct work_struct *work) ++{ ++ struct ixgbe_adapter *adapter = container_of(work, ++ struct ixgbe_adapter, ++ watchdog_task); + struct net_device *netdev = adapter->netdev; +- bool link_up; +- u32 link_speed = 0; ++ struct ixgbe_hw *hw = &adapter->hw; ++ u32 link_speed = adapter->link_speed; ++ bool link_up = adapter->link_up; + +- adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up); ++ adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; ++ ++ if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { ++ hw->mac.ops.check_link(hw, &link_speed, &link_up, false); ++ if (link_up || ++ time_after(jiffies, (adapter->link_check_timeout + ++ IXGBE_TRY_LINK_TIMEOUT))) { ++ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); ++ adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; ++ } ++ adapter->link_up = link_up; ++ adapter->link_speed = link_speed; ++ } + + if (link_up) { + if (!netif_carrier_ok(netdev)) { +- u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); +- u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS); ++ u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); ++ u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); + #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) + #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) + DPRINTK(LINK, INFO, "NIC Link is Up %s, " +- "Flow Control: %s\n", +- (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? +- "10 Gbps" : +- (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? +- "1 Gbps" : "unknown speed")), +- ((FLOW_RX && FLOW_TX) ? "RX/TX" : +- (FLOW_RX ? "RX" : +- (FLOW_TX ? "TX" : "None")))); ++ "Flow Control: %s\n", ++ (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? ++ "10 Gbps" : ++ (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? ++ "1 Gbps" : "unknown speed")), ++ ((FLOW_RX && FLOW_TX) ? "RX/TX" : ++ (FLOW_RX ? "RX" : ++ (FLOW_TX ? "TX" : "None")))); + + netif_carrier_on(netdev); + netif_tx_wake_all_queues(netdev); +@@ -2932,6 +3232,8 @@ static void ixgbe_watchdog(unsigned long + adapter->detect_tx_hung = true; + } + } else { ++ adapter->link_up = false; ++ adapter->link_speed = 0; + if (netif_carrier_ok(netdev)) { + DPRINTK(LINK, INFO, "NIC Link is Down\n"); + netif_carrier_off(netdev); +@@ -2940,36 +3242,19 @@ static void ixgbe_watchdog(unsigned long + } + + ixgbe_update_stats(adapter); +- +- if (!test_bit(__IXGBE_DOWN, &adapter->state)) { +- /* Cause software interrupt to ensure rx rings are cleaned */ +- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { +- u32 eics = +- (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1; +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, eics); +- } else { +- /* for legacy and MSI interrupts don't set any bits that +- * are enabled for EIAM, because this operation would +- * set *both* EIMS and EICS for any bit in EIAM */ +- IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, +- (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); +- } +- /* Reset the timer */ +- mod_timer(&adapter->watchdog_timer, +- round_jiffies(jiffies + 2 * HZ)); +- } ++ adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; + } + + static int ixgbe_tso(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring, struct sk_buff *skb, +- u32 tx_flags, u8 *hdr_len) ++ struct ixgbe_ring *tx_ring, struct sk_buff *skb, ++ u32 tx_flags, u8 *hdr_len) + { + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; + int err; + struct ixgbe_tx_buffer *tx_buffer_info; +- u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; +- u32 mss_l4len_idx = 0, l4len; ++ u32 vlan_macip_lens = 0, type_tucmd_mlhl; ++ u32 mss_l4len_idx, l4len; + + if (skb_is_gso(skb)) { + if (skb_header_cloned(skb)) { +@@ -2985,16 +3270,16 @@ static int ixgbe_tso(struct ixgbe_adapte + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, +- iph->daddr, 0, +- IPPROTO_TCP, +- 0); ++ iph->daddr, 0, ++ IPPROTO_TCP, ++ 0); + adapter->hw_tso_ctxt++; + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, +- &ipv6_hdr(skb)->daddr, +- 0, IPPROTO_TCP, 0); ++ &ipv6_hdr(skb)->daddr, ++ 0, IPPROTO_TCP, 0); + adapter->hw_tso6_ctxt++; + } + +@@ -3008,7 +3293,7 @@ static int ixgbe_tso(struct ixgbe_adapte + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= ((skb_network_offset(skb)) << +- IXGBE_ADVTXD_MACLEN_SHIFT); ++ IXGBE_ADVTXD_MACLEN_SHIFT); + *hdr_len += skb_network_offset(skb); + vlan_macip_lens |= + (skb_transport_header(skb) - skb_network_header(skb)); +@@ -3018,8 +3303,8 @@ static int ixgbe_tso(struct ixgbe_adapte + context_desc->seqnum_seed = 0; + + /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ +- type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | +- IXGBE_ADVTXD_DTYP_CTXT); ++ type_tucmd_mlhl = (IXGBE_TXD_CMD_DEXT | ++ IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->protocol == htons(ETH_P_IP)) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; +@@ -3027,9 +3312,11 @@ static int ixgbe_tso(struct ixgbe_adapte + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); + + /* MSS L4LEN IDX */ +- mss_l4len_idx |= ++ mss_l4len_idx = + (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT); + mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT); ++ /* use index 1 for TSO */ ++ mss_l4len_idx |= (1 << IXGBE_ADVTXD_IDX_SHIFT); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + + tx_buffer_info->time_stamp = jiffies; +@@ -3046,8 +3333,8 @@ static int ixgbe_tso(struct ixgbe_adapte + } + + static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring, +- struct sk_buff *skb, u32 tx_flags) ++ struct ixgbe_ring *tx_ring, ++ struct sk_buff *skb, u32 tx_flags) + { + struct ixgbe_adv_tx_context_desc *context_desc; + unsigned int i; +@@ -3064,16 +3351,16 @@ static bool ixgbe_tx_csum(struct ixgbe_a + vlan_macip_lens |= + (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK); + vlan_macip_lens |= (skb_network_offset(skb) << +- IXGBE_ADVTXD_MACLEN_SHIFT); ++ IXGBE_ADVTXD_MACLEN_SHIFT); + if (skb->ip_summed == CHECKSUM_PARTIAL) + vlan_macip_lens |= (skb_transport_header(skb) - +- skb_network_header(skb)); ++ skb_network_header(skb)); + + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = 0; + + type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | +- IXGBE_ADVTXD_DTYP_CTXT); ++ IXGBE_ADVTXD_DTYP_CTXT); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + switch (skb->protocol) { +@@ -3081,16 +3368,14 @@ static bool ixgbe_tx_csum(struct ixgbe_a + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + type_tucmd_mlhl |= +- IXGBE_ADVTXD_TUCMD_L4T_TCP; ++ IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; +- + case __constant_htons(ETH_P_IPV6): + /* XXX what about other V6 headers?? */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + type_tucmd_mlhl |= +- IXGBE_ADVTXD_TUCMD_L4T_TCP; ++ IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; +- + default: + if (unlikely(net_ratelimit())) { + DPRINTK(PROBE, WARNING, +@@ -3102,10 +3387,12 @@ static bool ixgbe_tx_csum(struct ixgbe_a + } + + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); ++ /* use index zero for tx checksum offload */ + context_desc->mss_l4len_idx = 0; + + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; ++ + adapter->hw_csum_tx_good++; + i++; + if (i == tx_ring->count) +@@ -3114,12 +3401,13 @@ static bool ixgbe_tx_csum(struct ixgbe_a + + return true; + } ++ + return false; + } + + static int ixgbe_tx_map(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring, +- struct sk_buff *skb, unsigned int first) ++ struct ixgbe_ring *tx_ring, ++ struct sk_buff *skb, unsigned int first) + { + struct ixgbe_tx_buffer *tx_buffer_info; + unsigned int len = skb->len; +@@ -3137,8 +3425,8 @@ static int ixgbe_tx_map(struct ixgbe_ada + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_single(adapter->pdev, +- skb->data + offset, +- size, PCI_DMA_TODEVICE); ++ skb->data + offset, ++ size, PCI_DMA_TODEVICE); + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + +@@ -3163,9 +3451,10 @@ static int ixgbe_tx_map(struct ixgbe_ada + + tx_buffer_info->length = size; + tx_buffer_info->dma = pci_map_page(adapter->pdev, +- frag->page, +- offset, +- size, PCI_DMA_TODEVICE); ++ frag->page, ++ offset, ++ size, ++ PCI_DMA_TODEVICE); + tx_buffer_info->time_stamp = jiffies; + tx_buffer_info->next_to_watch = i; + +@@ -3188,8 +3477,8 @@ static int ixgbe_tx_map(struct ixgbe_ada + } + + static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, +- struct ixgbe_ring *tx_ring, +- int tx_flags, int count, u32 paylen, u8 hdr_len) ++ struct ixgbe_ring *tx_ring, ++ int tx_flags, int count, u32 paylen, u8 hdr_len) + { + union ixgbe_adv_tx_desc *tx_desc = NULL; + struct ixgbe_tx_buffer *tx_buffer_info; +@@ -3208,15 +3497,17 @@ static void ixgbe_tx_queue(struct ixgbe_ + cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + + olinfo_status |= IXGBE_TXD_POPTS_TXSM << +- IXGBE_ADVTXD_POPTS_SHIFT; ++ IXGBE_ADVTXD_POPTS_SHIFT; + ++ /* use index 1 context for tso */ ++ olinfo_status |= (1 << IXGBE_ADVTXD_IDX_SHIFT); + if (tx_flags & IXGBE_TX_FLAGS_IPV4) + olinfo_status |= IXGBE_TXD_POPTS_IXSM << +- IXGBE_ADVTXD_POPTS_SHIFT; ++ IXGBE_ADVTXD_POPTS_SHIFT; + + } else if (tx_flags & IXGBE_TX_FLAGS_CSUM) + olinfo_status |= IXGBE_TXD_POPTS_TXSM << +- IXGBE_ADVTXD_POPTS_SHIFT; ++ IXGBE_ADVTXD_POPTS_SHIFT; + + olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT); + +@@ -3226,9 +3517,8 @@ static void ixgbe_tx_queue(struct ixgbe_ + tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); + tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma); + tx_desc->read.cmd_type_len = +- cpu_to_le32(cmd_type_len | tx_buffer_info->length); ++ cpu_to_le32(cmd_type_len | tx_buffer_info->length); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); +- + i++; + if (i == tx_ring->count) + i = 0; +@@ -3249,7 +3539,7 @@ static void ixgbe_tx_queue(struct ixgbe_ + } + + static int __ixgbe_maybe_stop_tx(struct net_device *netdev, +- struct ixgbe_ring *tx_ring, int size) ++ struct ixgbe_ring *tx_ring, int size) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + +@@ -3265,61 +3555,52 @@ static int __ixgbe_maybe_stop_tx(struct + return -EBUSY; + + /* A reprieve! - use start_queue because it doesn't call schedule */ +- netif_wake_subqueue(netdev, tx_ring->queue_index); ++ netif_start_subqueue(netdev, tx_ring->queue_index); + ++adapter->restart_queue; + return 0; + } + + static int ixgbe_maybe_stop_tx(struct net_device *netdev, +- struct ixgbe_ring *tx_ring, int size) ++ struct ixgbe_ring *tx_ring, int size) + { + if (likely(IXGBE_DESC_UNUSED(tx_ring) >= size)) + return 0; + return __ixgbe_maybe_stop_tx(netdev, tx_ring, size); + } + +- + static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_ring *tx_ring; +- unsigned int len = skb->len; + unsigned int first; + unsigned int tx_flags = 0; + u8 hdr_len = 0; + int r_idx = 0, tso; +- unsigned int mss = 0; + int count = 0; + unsigned int f; +- unsigned int nr_frags = skb_shinfo(skb)->nr_frags; +- len -= skb->data_len; ++ + r_idx = (adapter->num_tx_queues - 1) & skb->queue_mapping; + tx_ring = &adapter->tx_ring[r_idx]; + +- +- if (skb->len <= 0) { +- dev_kfree_skb(skb); +- return NETDEV_TX_OK; ++ if (adapter->vlgrp && vlan_tx_tag_present(skb)) { ++ tx_flags |= vlan_tx_tag_get(skb); ++ tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; ++ tx_flags |= IXGBE_TX_FLAGS_VLAN; + } +- mss = skb_shinfo(skb)->gso_size; +- +- if (mss) +- count++; +- else if (skb->ip_summed == CHECKSUM_PARTIAL) ++ /* three things can cause us to need a context descriptor */ ++ if (skb_is_gso(skb) || ++ (skb->ip_summed == CHECKSUM_PARTIAL) || ++ (tx_flags & IXGBE_TX_FLAGS_VLAN)) + count++; + +- count += TXD_USE_COUNT(len); +- for (f = 0; f < nr_frags; f++) ++ count += TXD_USE_COUNT(skb_headlen(skb)); ++ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) + count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); + + if (ixgbe_maybe_stop_tx(netdev, tx_ring, count)) { + adapter->tx_busy++; + return NETDEV_TX_BUSY; + } +- if (adapter->vlgrp && vlan_tx_tag_present(skb)) { +- tx_flags |= IXGBE_TX_FLAGS_VLAN; +- tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT); +- } + + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IXGBE_TX_FLAGS_IPV4; +@@ -3333,12 +3614,12 @@ static int ixgbe_xmit_frame(struct sk_bu + if (tso) + tx_flags |= IXGBE_TX_FLAGS_TSO; + else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) && +- (skb->ip_summed == CHECKSUM_PARTIAL)) ++ (skb->ip_summed == CHECKSUM_PARTIAL)) + tx_flags |= IXGBE_TX_FLAGS_CSUM; + + ixgbe_tx_queue(adapter, tx_ring, tx_flags, +- ixgbe_tx_map(adapter, tx_ring, skb, first), +- skb->len, hdr_len); ++ ixgbe_tx_map(adapter, tx_ring, skb, first), ++ skb->len, hdr_len); + + netdev->trans_start = jiffies; + +@@ -3372,15 +3653,16 @@ static struct net_device_stats *ixgbe_ge + static int ixgbe_set_mac(struct net_device *netdev, void *p) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ struct ixgbe_hw *hw = &adapter->hw; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); +- memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); ++ memcpy(hw->mac.addr, addr->sa_data, netdev->addr_len); + +- ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); ++ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + + return 0; + } +@@ -3404,28 +3686,19 @@ static void ixgbe_netpoll(struct net_dev + #endif + + /** +- * ixgbe_napi_add_all - prep napi structs for use +- * @adapter: private struct +- * helper function to napi_add each possible q_vector->napi +- */ +-static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) ++ * ixgbe_link_config - set up initial link with default speed and duplex ++ * @hw: pointer to private hardware struct ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++static int ixgbe_link_config(struct ixgbe_hw *hw) + { +- int i, q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; +- int (*poll)(struct napi_struct *, int); ++ u32 autoneg = IXGBE_LINK_SPEED_10GB_FULL; + +- if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { +- poll = &ixgbe_clean_rxonly; +- } else { +- poll = &ixgbe_poll; +- /* only one q_vector for legacy modes */ +- q_vectors = 1; +- } ++ /* must always autoneg for both 1G and 10G link */ ++ hw->mac.autoneg = true; + +- for (i = 0; i < q_vectors; i++) { +- struct ixgbe_q_vector *q_vector = &adapter->q_vector[i]; +- netif_napi_add(adapter->netdev, &q_vector->napi, +- (*poll), 64); +- } ++ return hw->mac.ops.setup_link_speed(hw, autoneg, true, true); + } + + /** +@@ -3440,17 +3713,16 @@ static void ixgbe_napi_add_all(struct ix + * and a hardware reset occur. + **/ + static int __devinit ixgbe_probe(struct pci_dev *pdev, +- const struct pci_device_id *ent) ++ const struct pci_device_id *ent) + { + struct net_device *netdev; + struct ixgbe_adapter *adapter = NULL; + struct ixgbe_hw *hw; + const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; +- unsigned long mmio_start, mmio_len; + static int cards_found; + int i, err, pci_using_dac; + u16 link_status, link_speed, link_width; +- u32 part_num; ++ u32 part_num, eec; + + err = pci_enable_device(pdev); + if (err) +@@ -3465,7 +3737,7 @@ static int __devinit ixgbe_probe(struct + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, "No usable DMA " +- "configuration, aborting\n"); ++ "configuration, aborting\n"); + goto err_dma; + } + } +@@ -3498,10 +3770,8 @@ static int __devinit ixgbe_probe(struct + hw->back = adapter; + adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + +- mmio_start = pci_resource_start(pdev, 0); +- mmio_len = pci_resource_len(pdev, 0); +- +- hw->hw_addr = ioremap(mmio_start, mmio_len); ++ hw->hw_addr = ioremap(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)); + if (!hw->hw_addr) { + err = -EIO; + goto err_ioremap; +@@ -3516,7 +3786,8 @@ static int __devinit ixgbe_probe(struct + netdev->stop = &ixgbe_close; + netdev->hard_start_xmit = &ixgbe_xmit_frame; + netdev->get_stats = &ixgbe_get_stats; +- netdev->set_multicast_list = &ixgbe_set_multi; ++ netdev->set_rx_mode = &ixgbe_set_rx_mode; ++ netdev->set_multicast_list = &ixgbe_set_rx_mode; + netdev->set_mac_address = &ixgbe_set_mac; + netdev->change_mtu = &ixgbe_change_mtu; + ixgbe_set_ethtool_ops(netdev); +@@ -3530,22 +3801,23 @@ static int __devinit ixgbe_probe(struct + #endif + strcpy(netdev->name, pci_name(pdev)); + +- netdev->mem_start = mmio_start; +- netdev->mem_end = mmio_start + mmio_len; +- + adapter->bd_number = cards_found; + +- /* PCI config space info */ +- hw->vendor_id = pdev->vendor; +- hw->device_id = pdev->device; +- hw->revision_id = pdev->revision; +- hw->subsystem_vendor_id = pdev->subsystem_vendor; +- hw->subsystem_device_id = pdev->subsystem_device; +- + /* Setup hw api */ + memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops)); + hw->mac.type = ii->mac; + ++ /* EEPROM */ ++ memcpy(&hw->eeprom.ops, ii->eeprom_ops, sizeof(hw->eeprom.ops)); ++ eec = IXGBE_READ_REG(hw, IXGBE_EEC); ++ /* If EEPROM is valid (bit 8 = 1), use default otherwise use bit bang */ ++ if (!(eec & (1 << 8))) ++ hw->eeprom.ops.read = &ixgbe_read_eeprom_bit_bang_generic; ++ ++ /* PHY */ ++ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); ++ /* phy->sfp_type = ixgbe_sfp_type_unknown; */ ++ + err = ii->get_invariants(hw); + if (err) + goto err_hw_init; +@@ -3555,26 +3827,36 @@ static int __devinit ixgbe_probe(struct + if (err) + goto err_sw_init; + ++ /* reset_hw fills in the perm_addr as well */ ++ err = hw->mac.ops.reset_hw(hw); ++ if (err) { ++ dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err); ++ goto err_sw_init; ++ } ++ + netdev->features = NETIF_F_SG | +- NETIF_F_HW_CSUM | +- NETIF_F_HW_VLAN_TX | +- NETIF_F_HW_VLAN_RX | +- NETIF_F_HW_VLAN_FILTER; ++ NETIF_F_IP_CSUM | ++ NETIF_F_HW_VLAN_TX | ++ NETIF_F_HW_VLAN_RX | ++ NETIF_F_HW_VLAN_FILTER; + +- netdev->features |= NETIF_F_LRO; ++ netdev->features |= NETIF_F_IPV6_CSUM; + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; ++#ifdef CONFIG_IXGBE_LRO ++ netdev->features |= NETIF_F_LRO; ++#endif + + netdev->vlan_features |= NETIF_F_TSO; + netdev->vlan_features |= NETIF_F_TSO6; +- netdev->vlan_features |= NETIF_F_HW_CSUM; ++ netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_SG; + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + /* make sure the EEPROM is good */ +- if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) { ++ if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) { + dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; +@@ -3583,7 +3865,8 @@ static int __devinit ixgbe_probe(struct + memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len); + memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len); + +- if (ixgbe_validate_mac_addr(netdev->dev_addr)) { ++ if (ixgbe_validate_mac_addr(netdev->perm_addr)) { ++ dev_err(&pdev->dev, "invalid MAC address\n"); + err = -EIO; + goto err_eeprom; + } +@@ -3593,13 +3876,7 @@ static int __devinit ixgbe_probe(struct + adapter->watchdog_timer.data = (unsigned long)adapter; + + INIT_WORK(&adapter->reset_task, ixgbe_reset_task); +- +- /* initialize default flow control settings */ +- hw->fc.original_type = ixgbe_fc_full; +- hw->fc.type = ixgbe_fc_full; +- hw->fc.high_water = IXGBE_DEFAULT_FCRTH; +- hw->fc.low_water = IXGBE_DEFAULT_FCRTL; +- hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; ++ INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); + + err = ixgbe_init_interrupt_scheme(adapter); + if (err) +@@ -3610,32 +3887,39 @@ static int __devinit ixgbe_probe(struct + link_speed = link_status & IXGBE_PCI_LINK_SPEED; + link_width = link_status & IXGBE_PCI_LINK_WIDTH; + dev_info(&pdev->dev, "(PCI Express:%s:%s) " +- "%02x:%02x:%02x:%02x:%02x:%02x\n", +- ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : +- (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : +- "Unknown"), +- ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" : +- (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" : +- (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : +- (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : +- "Unknown"), +- netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], +- netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); +- ixgbe_read_part_num(hw, &part_num); ++ "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : ++ (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : ++ "Unknown"), ++ ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" : ++ (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" : ++ (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : ++ (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : ++ "Unknown"), ++ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], ++ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); ++ ixgbe_read_pba_num_generic(hw, &part_num); + dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", +- hw->mac.type, hw->phy.type, +- (part_num >> 8), (part_num & 0xff)); ++ hw->mac.type, hw->phy.type, ++ (part_num >> 8), (part_num & 0xff)); + + if (link_width <= IXGBE_PCI_LINK_WIDTH_4) { + dev_warn(&pdev->dev, "PCI-Express bandwidth available for " +- "this card is not sufficient for optimal " +- "performance.\n"); ++ "this card is not sufficient for optimal " ++ "performance.\n"); + dev_warn(&pdev->dev, "For optimal performance a x8 " +- "PCI-Express slot is required.\n"); ++ "PCI-Express slot is required.\n"); + } + + /* reset the hardware with the new settings */ +- ixgbe_start_hw(hw); ++ hw->mac.ops.start_hw(hw); ++ ++ /* link_config depends on start_hw being called at least once */ ++ err = ixgbe_link_config(hw); ++ if (err) { ++ dev_err(&pdev->dev, "setup_link_speed FAILED %d\n", err); ++ goto err_register; ++ } + + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); +@@ -3647,7 +3931,7 @@ static int __devinit ixgbe_probe(struct + if (err) + goto err_register; + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + if (dca_add_requester(&pdev->dev) == 0) { + adapter->flags |= IXGBE_FLAG_DCA_ENABLED; + /* always use CB2 mode, difference is masked +@@ -3697,7 +3981,7 @@ static void __devexit ixgbe_remove(struc + + flush_scheduled_work(); + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { + adapter->flags &= ~IXGBE_FLAG_DCA_ENABLED; + dca_remove_requester(&pdev->dev); +@@ -3715,6 +3999,7 @@ static void __devexit ixgbe_remove(struc + pci_release_regions(pdev); + + DPRINTK(PROBE, INFO, "complete\n"); ++ ixgbe_napi_del_all(adapter); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + +@@ -3732,7 +4017,7 @@ static void __devexit ixgbe_remove(struc + * this device has been detected. + */ + static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, +- pci_channel_state_t state) ++ pci_channel_state_t state) + { + struct net_device *netdev = pci_get_drvdata(pdev); + struct ixgbe_adapter *adapter = netdev->priv; +@@ -3743,7 +4028,7 @@ static pci_ers_result_t ixgbe_io_error_d + ixgbe_down(adapter); + pci_disable_device(pdev); + +- /* Request a slot slot reset. */ ++ /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; + } + +@@ -3760,7 +4045,7 @@ static pci_ers_result_t ixgbe_io_slot_re + + if (pci_enable_device(pdev)) { + DPRINTK(PROBE, ERR, +- "Cannot re-enable PCI device after reset.\n"); ++ "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); +@@ -3794,7 +4079,6 @@ static void ixgbe_io_resume(struct pci_d + } + + netif_device_attach(netdev); +- + } + + static struct pci_error_handlers ixgbe_err_handler = { +@@ -3830,13 +4114,14 @@ static int __init ixgbe_init_module(void + + printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright); + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + dca_register_notify(&dca_notifier); + + #endif + ret = pci_register_driver(&ixgbe_driver); + return ret; + } ++ + module_init(ixgbe_init_module); + + /** +@@ -3847,24 +4132,24 @@ module_init(ixgbe_init_module); + **/ + static void __exit ixgbe_exit_module(void) + { +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + dca_unregister_notify(&dca_notifier); + #endif + pci_unregister_driver(&ixgbe_driver); + } + +-#ifdef CONFIG_DCA ++#if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event, +- void *p) ++ void *p) + { + int ret_val; + + ret_val = driver_for_each_device(&ixgbe_driver.driver, NULL, &event, +- __ixgbe_notify_dca); ++ __ixgbe_notify_dca); + + return ret_val ? NOTIFY_BAD : NOTIFY_DONE; + } +-#endif /* CONFIG_DCA */ ++#endif /* CONFIG_DCA or CONFIG_DCA_MODULE */ + + module_exit(ixgbe_exit_module); + +--- a/drivers/net/ixgbe/ixgbe_phy.c ++++ b/drivers/net/ixgbe/ixgbe_phy.c +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -33,32 +32,36 @@ + #include "ixgbe_common.h" + #include "ixgbe_phy.h" + ++static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); + static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id); + static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw); +-static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr); +-static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, +- u32 device_type, u16 phy_data); + + /** +- * ixgbe_identify_phy - Get physical layer module ++ * ixgbe_identify_phy_generic - Get physical layer module + * @hw: pointer to hardware structure + * + * Determines the physical layer module found on the current adapter. + **/ +-s32 ixgbe_identify_phy(struct ixgbe_hw *hw) ++s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) + { + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + u32 phy_addr; + +- for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { +- if (ixgbe_validate_phy_addr(hw, phy_addr)) { +- hw->phy.addr = phy_addr; +- ixgbe_get_phy_id(hw); +- hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id); +- status = 0; +- break; ++ if (hw->phy.type == ixgbe_phy_unknown) { ++ for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { ++ if (ixgbe_validate_phy_addr(hw, phy_addr)) { ++ hw->phy.addr = phy_addr; ++ ixgbe_get_phy_id(hw); ++ hw->phy.type = ++ ixgbe_get_phy_type_from_id(hw->phy.id); ++ status = 0; ++ break; ++ } + } ++ } else { ++ status = 0; + } ++ + return status; + } + +@@ -73,10 +76,8 @@ static bool ixgbe_validate_phy_addr(stru + bool valid = false; + + hw->phy.addr = phy_addr; +- ixgbe_read_phy_reg(hw, +- IXGBE_MDIO_PHY_ID_HIGH, +- IXGBE_MDIO_PMA_PMD_DEV_TYPE, +- &phy_id); ++ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id); + + if (phy_id != 0xFFFF && phy_id != 0x0) + valid = true; +@@ -95,21 +96,18 @@ static s32 ixgbe_get_phy_id(struct ixgbe + u16 phy_id_high = 0; + u16 phy_id_low = 0; + +- status = ixgbe_read_phy_reg(hw, +- IXGBE_MDIO_PHY_ID_HIGH, +- IXGBE_MDIO_PMA_PMD_DEV_TYPE, +- &phy_id_high); ++ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, ++ &phy_id_high); + + if (status == 0) { + hw->phy.id = (u32)(phy_id_high << 16); +- status = ixgbe_read_phy_reg(hw, +- IXGBE_MDIO_PHY_ID_LOW, +- IXGBE_MDIO_PMA_PMD_DEV_TYPE, +- &phy_id_low); ++ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, ++ &phy_id_low); + hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK); + hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK); + } +- + return status; + } + +@@ -123,9 +121,6 @@ static enum ixgbe_phy_type ixgbe_get_phy + enum ixgbe_phy_type phy_type; + + switch (phy_id) { +- case TN1010_PHY_ID: +- phy_type = ixgbe_phy_tn; +- break; + case QT2022_PHY_ID: + phy_type = ixgbe_phy_qt; + break; +@@ -138,32 +133,31 @@ static enum ixgbe_phy_type ixgbe_get_phy + } + + /** +- * ixgbe_reset_phy - Performs a PHY reset ++ * ixgbe_reset_phy_generic - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +-s32 ixgbe_reset_phy(struct ixgbe_hw *hw) ++s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) + { + /* + * Perform soft PHY reset to the PHY_XS. + * This will cause a soft reset to the PHY + */ +- return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, +- IXGBE_MDIO_PHY_XS_DEV_TYPE, +- IXGBE_MDIO_PHY_XS_RESET); ++ return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, ++ IXGBE_MDIO_PHY_XS_DEV_TYPE, ++ IXGBE_MDIO_PHY_XS_RESET); + } + + /** +- * ixgbe_read_phy_reg - Reads a value from a specified PHY register ++ * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit address of PHY register to read + * @phy_data: Pointer to read data from PHY register + **/ +-s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, +- u32 device_type, u16 *phy_data) ++s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, ++ u32 device_type, u16 *phy_data) + { + u32 command; + u32 i; +- u32 timeout = 10; + u32 data; + s32 status = 0; + u16 gssr; +@@ -179,9 +173,9 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw * + if (status == 0) { + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | +- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | +- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | +- (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); ++ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | ++ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | ++ (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + +@@ -190,7 +184,7 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw * + * The MDI Command bit will clear when the operation is + * complete + */ +- for (i = 0; i < timeout; i++) { ++ for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); +@@ -210,9 +204,9 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw * + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | +- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | +- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | +- (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); ++ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | ++ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | ++ (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + +@@ -221,7 +215,7 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw * + * completed. The MDI Command bit will clear when the + * operation is complete + */ +- for (i = 0; i < timeout; i++) { ++ for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); +@@ -231,8 +225,7 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw * + } + + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { +- hw_dbg(hw, +- "PHY read command didn't complete\n"); ++ hw_dbg(hw, "PHY read command didn't complete\n"); + status = IXGBE_ERR_PHY; + } else { + /* +@@ -247,22 +240,22 @@ s32 ixgbe_read_phy_reg(struct ixgbe_hw * + + ixgbe_release_swfw_sync(hw, gssr); + } ++ + return status; + } + + /** +- * ixgbe_write_phy_reg - Writes a value to specified PHY register ++ * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 5 bit device type + * @phy_data: Data to write to the PHY register + **/ +-static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, +- u32 device_type, u16 phy_data) ++s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, ++ u32 device_type, u16 phy_data) + { + u32 command; + u32 i; +- u32 timeout = 10; + s32 status = 0; + u16 gssr; + +@@ -280,9 +273,9 @@ static s32 ixgbe_write_phy_reg(struct ix + + /* Setup and write the address cycle command */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | +- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | +- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | +- (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); ++ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | ++ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | ++ (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + +@@ -291,19 +284,19 @@ static s32 ixgbe_write_phy_reg(struct ix + * The MDI Command bit will clear when the operation is + * complete + */ +- for (i = 0; i < timeout; i++) { ++ for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + +- if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { +- hw_dbg(hw, "PHY address cmd didn't complete\n"); ++ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; +- } + } + +- if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) ++ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { ++ hw_dbg(hw, "PHY address cmd didn't complete\n"); + status = IXGBE_ERR_PHY; ++ } + + if (status == 0) { + /* +@@ -311,9 +304,9 @@ static s32 ixgbe_write_phy_reg(struct ix + * command + */ + command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) | +- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | +- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | +- (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); ++ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) | ++ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) | ++ (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND)); + + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); + +@@ -322,20 +315,19 @@ static s32 ixgbe_write_phy_reg(struct ix + * completed. The MDI Command bit will clear when the + * operation is complete + */ +- for (i = 0; i < timeout; i++) { ++ for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) { + udelay(10); + + command = IXGBE_READ_REG(hw, IXGBE_MSCA); + +- if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { +- hw_dbg(hw, "PHY write command did not " +- "complete.\n"); ++ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) + break; +- } + } + +- if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) ++ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { ++ hw_dbg(hw, "PHY address cmd didn't complete\n"); + status = IXGBE_ERR_PHY; ++ } + } + + ixgbe_release_swfw_sync(hw, gssr); +@@ -345,67 +337,54 @@ static s32 ixgbe_write_phy_reg(struct ix + } + + /** +- * ixgbe_setup_tnx_phy_link - Set and restart autoneg ++ * ixgbe_setup_phy_link_generic - Set and restart autoneg + * @hw: pointer to hardware structure + * + * Restart autonegotiation and PHY and waits for completion. + **/ +-s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw) ++s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) + { + s32 status = IXGBE_NOT_IMPLEMENTED; + u32 time_out; + u32 max_time_out = 10; +- u16 autoneg_speed_selection_register = 0x10; +- u16 autoneg_restart_mask = 0x0200; +- u16 autoneg_complete_mask = 0x0020; +- u16 autoneg_reg = 0; ++ u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; + + /* + * Set advertisement settings in PHY based on autoneg_advertised + * settings. If autoneg_advertised = 0, then advertise default values +- * txn devices cannot be "forced" to a autoneg 10G and fail. But can ++ * tnx devices cannot be "forced" to a autoneg 10G and fail. But can + * for a 1G. + */ +- ixgbe_read_phy_reg(hw, +- autoneg_speed_selection_register, +- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, +- &autoneg_reg); ++ hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, ++ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); + + if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL) + autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */ + else + autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */ + +- ixgbe_write_phy_reg(hw, +- autoneg_speed_selection_register, +- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, +- autoneg_reg); +- ++ hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG, ++ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + + /* Restart PHY autonegotiation and wait for completion */ +- ixgbe_read_phy_reg(hw, +- IXGBE_MDIO_AUTO_NEG_CONTROL, +- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, +- &autoneg_reg); +- +- autoneg_reg |= autoneg_restart_mask; +- +- ixgbe_write_phy_reg(hw, +- IXGBE_MDIO_AUTO_NEG_CONTROL, +- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, +- autoneg_reg); ++ hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, ++ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); ++ ++ autoneg_reg |= IXGBE_MII_RESTART; ++ ++ hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, ++ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); + + /* Wait for autonegotiation to finish */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + /* Restart PHY autonegotiation and wait for completion */ +- status = ixgbe_read_phy_reg(hw, +- IXGBE_MDIO_AUTO_NEG_STATUS, +- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, +- &autoneg_reg); ++ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, ++ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ++ &autoneg_reg); + +- autoneg_reg &= autoneg_complete_mask; +- if (autoneg_reg == autoneg_complete_mask) { ++ autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; ++ if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { + status = 0; + break; + } +@@ -418,64 +397,17 @@ s32 ixgbe_setup_tnx_phy_link(struct ixgb + } + + /** +- * ixgbe_check_tnx_phy_link - Determine link and speed status +- * @hw: pointer to hardware structure +- * +- * Reads the VS1 register to determine if link is up and the current speed for +- * the PHY. +- **/ +-s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, +- bool *link_up) +-{ +- s32 status = 0; +- u32 time_out; +- u32 max_time_out = 10; +- u16 phy_link = 0; +- u16 phy_speed = 0; +- u16 phy_data = 0; +- +- /* Initialize speed and link to default case */ +- *link_up = false; +- *speed = IXGBE_LINK_SPEED_10GB_FULL; +- +- /* +- * Check current speed and link status of the PHY register. +- * This is a vendor specific register and may have to +- * be changed for other copper PHYs. +- */ +- for (time_out = 0; time_out < max_time_out; time_out++) { +- udelay(10); +- if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { +- *link_up = true; +- if (phy_speed == +- IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) +- *speed = IXGBE_LINK_SPEED_1GB_FULL; +- break; +- } else { +- status = ixgbe_read_phy_reg(hw, +- IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, +- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, +- &phy_data); +- phy_link = phy_data & +- IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; +- phy_speed = phy_data & +- IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; +- } +- } +- +- return status; +-} +- +-/** +- * ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities ++ * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg: true if autonegotiation enabled + **/ +-s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, +- bool autoneg, +- bool autoneg_wait_to_complete) ++s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, ++ ixgbe_link_speed speed, ++ bool autoneg, ++ bool autoneg_wait_to_complete) + { ++ + /* + * Clear autoneg_advertised and set new values based on input link + * speed. +@@ -484,11 +416,13 @@ s32 ixgbe_setup_tnx_phy_link_speed(struc + + if (speed & IXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; ++ + if (speed & IXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; + + /* Setup link based on the new speed settings */ +- ixgbe_setup_tnx_phy_link(hw); ++ hw->phy.ops.setup_link(hw); + + return 0; + } ++ +--- a/drivers/net/ixgbe/ixgbe_phy.h ++++ b/drivers/net/ixgbe/ixgbe_phy.h +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -30,20 +29,52 @@ + #define _IXGBE_PHY_H_ + + #include "ixgbe_type.h" ++#define IXGBE_I2C_EEPROM_DEV_ADDR 0xA0 + +-s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw); +-s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); +-s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, +- bool autoneg_wait_to_complete); +-s32 ixgbe_identify_phy(struct ixgbe_hw *hw); +-s32 ixgbe_reset_phy(struct ixgbe_hw *hw); +-s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr, +- u32 device_type, u16 *phy_data); +- +-/* PHY specific */ +-s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw); +-s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); +-s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, +- bool autoneg_wait_to_complete); ++/* EEPROM byte offsets */ ++#define IXGBE_SFF_IDENTIFIER 0x0 ++#define IXGBE_SFF_IDENTIFIER_SFP 0x3 ++#define IXGBE_SFF_VENDOR_OUI_BYTE0 0x25 ++#define IXGBE_SFF_VENDOR_OUI_BYTE1 0x26 ++#define IXGBE_SFF_VENDOR_OUI_BYTE2 0x27 ++#define IXGBE_SFF_1GBE_COMP_CODES 0x6 ++#define IXGBE_SFF_10GBE_COMP_CODES 0x3 ++#define IXGBE_SFF_TRANSMISSION_MEDIA 0x9 ++ ++/* Bitmasks */ ++#define IXGBE_SFF_TWIN_AX_CAPABLE 0x80 ++#define IXGBE_SFF_1GBASESX_CAPABLE 0x1 ++#define IXGBE_SFF_10GBASESR_CAPABLE 0x10 ++#define IXGBE_SFF_10GBASELR_CAPABLE 0x20 ++#define IXGBE_I2C_EEPROM_READ_MASK 0x100 ++#define IXGBE_I2C_EEPROM_STATUS_MASK 0x3 ++#define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0 ++#define IXGBE_I2C_EEPROM_STATUS_PASS 0x1 ++#define IXGBE_I2C_EEPROM_STATUS_FAIL 0x2 ++#define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS 0x3 ++ ++/* Bit-shift macros */ ++#define IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT 12 ++#define IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT 8 ++#define IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT 4 ++ ++/* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */ ++#define IXGBE_SFF_VENDOR_OUI_TYCO 0x00407600 ++#define IXGBE_SFF_VENDOR_OUI_FTL 0x00906500 ++#define IXGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00 ++ ++ ++s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); ++s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); ++s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw); ++s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, ++ u32 device_type, u16 *phy_data); ++s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, ++ u32 device_type, u16 phy_data); ++s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw); ++s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, ++ ixgbe_link_speed speed, ++ bool autoneg, ++ bool autoneg_wait_to_complete); + + #endif /* _IXGBE_PHY_H_ */ +--- a/drivers/net/ixgbe/ixgbe_type.h ++++ b/drivers/net/ixgbe/ixgbe_type.h +@@ -1,7 +1,7 @@ + /******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver +- Copyright(c) 1999 - 2007 Intel Corporation. ++ Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, +@@ -20,7 +20,6 @@ + the file called "COPYING". + + Contact Information: +- Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +@@ -37,9 +36,9 @@ + /* Device IDs */ + #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 + #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 +-#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10C8 + #define IXGBE_DEV_ID_82598EB_CX4 0x10DD + #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC ++#define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 + + /* General Registers */ + #define IXGBE_CTRL 0x00000 +@@ -70,11 +69,11 @@ + #define IXGBE_EIMC 0x00888 + #define IXGBE_EIAC 0x00810 + #define IXGBE_EIAM 0x00890 +-#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */ +-#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ ++#define IXGBE_EITR(_i) (((_i) <= 23) ? (0x00820 + ((_i) * 4)) : (0x012300 + ((_i) * 4))) ++#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */ + #define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */ + #define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */ +-#define IXGBE_PBACL 0x11068 ++#define IXGBE_PBACL(_i) (((_i) == 0) ? (0x11068) : (0x110C0 + ((_i) * 4))) + #define IXGBE_GPIE 0x00898 + + /* Flow Control Registers */ +@@ -86,20 +85,33 @@ + #define IXGBE_TFCS 0x0CE00 + + /* Receive DMA Registers */ +-#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/ +-#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40)) +-#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40)) +-#define IXGBE_RDH(_i) (0x01010 + ((_i) * 0x40)) +-#define IXGBE_RDT(_i) (0x01018 + ((_i) * 0x40)) +-#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40)) +-#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40)) +-#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4)) +- /* array of 16 (0x02100-0x0213C) */ +-#define IXGBE_DCA_RXCTRL(_i) (0x02200 + ((_i) * 4)) +- /* array of 16 (0x02200-0x0223C) */ +-#define IXGBE_RDRXCTL 0x02F00 ++#define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : (0x0D000 + ((_i - 64) * 0x40))) ++#define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : (0x0D004 + ((_i - 64) * 0x40))) ++#define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : (0x0D008 + ((_i - 64) * 0x40))) ++#define IXGBE_RDH(_i) (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : (0x0D010 + ((_i - 64) * 0x40))) ++#define IXGBE_RDT(_i) (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : (0x0D018 + ((_i - 64) * 0x40))) ++#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : (0x0D028 + ((_i - 64) * 0x40))) ++/* ++ * Split and Replication Receive Control Registers ++ * 00-15 : 0x02100 + n*4 ++ * 16-64 : 0x01014 + n*0x40 ++ * 64-127: 0x0D014 + (n-64)*0x40 ++ */ ++#define IXGBE_SRRCTL(_i) (((_i) <= 15) ? (0x02100 + ((_i) * 4)) : \ ++ (((_i) < 64) ? (0x01014 + ((_i) * 0x40)) : \ ++ (0x0D014 + ((_i - 64) * 0x40)))) ++/* ++ * Rx DCA Control Register: ++ * 00-15 : 0x02200 + n*4 ++ * 16-64 : 0x0100C + n*0x40 ++ * 64-127: 0x0D00C + (n-64)*0x40 ++ */ ++#define IXGBE_DCA_RXCTRL(_i) (((_i) <= 15) ? (0x02200 + ((_i) * 4)) : \ ++ (((_i) < 64) ? (0x0100C + ((_i) * 0x40)) : \ ++ (0x0D00C + ((_i - 64) * 0x40)))) ++#define IXGBE_RDRXCTL 0x02F00 + #define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) +- /* 8 of these 0x03C00 - 0x03C1C */ ++ /* 8 of these 0x03C00 - 0x03C1C */ + #define IXGBE_RXCTRL 0x03000 + #define IXGBE_DROPEN 0x03D04 + #define IXGBE_RXPBSIZE_SHIFT 10 +@@ -107,29 +119,32 @@ + /* Receive Registers */ + #define IXGBE_RXCSUM 0x05000 + #define IXGBE_RFCTL 0x05008 ++#define IXGBE_DRECCCTL 0x02F08 ++#define IXGBE_DRECCCTL_DISABLE 0 ++/* Multicast Table Array - 128 entries */ + #define IXGBE_MTA(_i) (0x05200 + ((_i) * 4)) +- /* Multicast Table Array - 128 entries */ +-#define IXGBE_RAL(_i) (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */ +-#define IXGBE_RAH(_i) (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */ +-#define IXGBE_PSRTYPE 0x05480 +- /* 0x5480-0x54BC Packet split receive type */ ++#define IXGBE_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x0A200 + ((_i) * 8))) ++#define IXGBE_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x0A204 + ((_i) * 8))) ++/* Packet split receive type */ ++#define IXGBE_PSRTYPE(_i) (((_i) <= 15) ? (0x05480 + ((_i) * 4)) : (0x0EA00 + ((_i) * 4))) ++/* array of 4096 1-bit vlan filters */ + #define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4)) +- /* array of 4096 1-bit vlan filters */ ++/*array of 4096 4-bit vlan vmdq indices */ + #define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4)) +- /*array of 4096 4-bit vlan vmdq indicies */ + #define IXGBE_FCTRL 0x05080 + #define IXGBE_VLNCTRL 0x05088 + #define IXGBE_MCSTCTRL 0x05090 + #define IXGBE_MRQC 0x05818 +-#define IXGBE_VMD_CTL 0x0581C + #define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */ + #define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */ + #define IXGBE_IMIRVP 0x05AC0 ++#define IXGBE_VMD_CTL 0x0581C + #define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ + #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ + ++ + /* Transmit DMA registers */ +-#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/ ++#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/ + #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40)) + #define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40)) + #define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40)) +@@ -138,11 +153,10 @@ + #define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40)) + #define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40)) + #define IXGBE_DTXCTL 0x07E00 +-#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) +- /* there are 16 of these (0-15) */ ++ ++#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */ + #define IXGBE_TIPG 0x0CB00 +-#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04)) +- /* there are 8 of these */ ++#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) * 4)) /* 8 of these */ + #define IXGBE_MNGTXMAP 0x0CD10 + #define IXGBE_TIPG_FIBER_DEFAULT 3 + #define IXGBE_TXPBSIZE_SHIFT 10 +@@ -154,6 +168,7 @@ + #define IXGBE_IPAV 0x05838 + #define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */ + #define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */ ++ + #define IXGBE_WUPL 0x05900 + #define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ + #define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */ +@@ -170,6 +185,8 @@ + #define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */ + #define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */ + ++ ++ + /* Stats registers */ + #define IXGBE_CRCERRS 0x04000 + #define IXGBE_ILLERRC 0x04004 +@@ -224,7 +241,7 @@ + #define IXGBE_XEC 0x04120 + + #define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */ +-#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */ ++#define IXGBE_TQSMR(_i) (((_i) <= 7) ? (0x07300 + ((_i) * 4)) : (0x08600 + ((_i) * 4))) + + #define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */ + #define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */ +@@ -275,23 +292,17 @@ + #define IXGBE_DCA_CTRL 0x11074 + + /* Diagnostic Registers */ +-#define IXGBE_RDSTATCTL 0x02C20 +-#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ +-#define IXGBE_RDHMPN 0x02F08 +-#define IXGBE_RIC_DW0 0x02F10 +-#define IXGBE_RIC_DW1 0x02F14 +-#define IXGBE_RIC_DW2 0x02F18 +-#define IXGBE_RIC_DW3 0x02F1C +-#define IXGBE_RDPROBE 0x02F20 +-#define IXGBE_TDSTATCTL 0x07C20 +-#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ +-#define IXGBE_TDHMPN 0x07F08 +-#define IXGBE_TIC_DW0 0x07F10 +-#define IXGBE_TIC_DW1 0x07F14 +-#define IXGBE_TIC_DW2 0x07F18 +-#define IXGBE_TIC_DW3 0x07F1C +-#define IXGBE_TDPROBE 0x07F20 +-#define IXGBE_TXBUFCTRL 0x0C600 ++#define IXGBE_RDSTATCTL 0x02C20 ++#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */ ++#define IXGBE_RDHMPN 0x02F08 ++#define IXGBE_RIC_DW(_i) (0x02F10 + ((_i) * 4)) ++#define IXGBE_RDPROBE 0x02F20 ++#define IXGBE_TDSTATCTL 0x07C20 ++#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ ++#define IXGBE_TDHMPN 0x07F08 ++#define IXGBE_TIC_DW(_i) (0x07F10 + ((_i) * 4)) ++#define IXGBE_TDPROBE 0x07F20 ++#define IXGBE_TXBUFCTRL 0x0C600 + #define IXGBE_TXBUFDATA0 0x0C610 + #define IXGBE_TXBUFDATA1 0x0C614 + #define IXGBE_TXBUFDATA2 0x0C618 +@@ -356,12 +367,10 @@ + #define IXGBE_ANLP2 0x042B4 + #define IXGBE_ATLASCTL 0x04800 + +-/* RSCCTL Bit Masks */ +-#define IXGBE_RSCCTL_RSCEN 0x01 +-#define IXGBE_RSCCTL_MAXDESC_1 0x00 +-#define IXGBE_RSCCTL_MAXDESC_4 0x04 +-#define IXGBE_RSCCTL_MAXDESC_8 0x08 +-#define IXGBE_RSCCTL_MAXDESC_16 0x0C ++/* RDRXCTL Bit Masks */ ++#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 /* Rx Desc Min Threshold Size */ ++#define IXGBE_RDRXCTL_MVMEN 0x00000020 ++#define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */ + + /* CTRL Bit Masks */ + #define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */ +@@ -394,7 +403,7 @@ + + #define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ + #define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ +-#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */ ++#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ + #define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */ + + /* MSCA Bit Masks */ +@@ -418,10 +427,10 @@ + #define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */ + + /* MSRWD bit masks */ +-#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF +-#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 +-#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 +-#define IXGBE_MSRWD_READ_DATA_SHIFT 16 ++#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF ++#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0 ++#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000 ++#define IXGBE_MSRWD_READ_DATA_SHIFT 16 + + /* Atlas registers */ + #define IXGBE_ATLAS_PDN_LPBK 0x24 +@@ -436,6 +445,7 @@ + #define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0 + #define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0 + ++ + /* Device Type definitions for new protocol MDIO commands */ + #define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1 + #define IXGBE_MDIO_PCS_DEV_TYPE 0x3 +@@ -443,6 +453,8 @@ + #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 + #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ + ++#define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ ++ + #define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */ + #define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */ + #define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */ +@@ -456,23 +468,39 @@ + #define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */ + #define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ + #define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ +-#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Abilty Reg */ ++#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Ability Reg */ + #define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */ + #define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */ + ++#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR 0xC30A /* PHY_XS SDA/SCL Address Reg */ ++#define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA 0xC30B /* PHY_XS SDA/SCL Data Reg */ ++#define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT 0xC30C /* PHY_XS SDA/SCL Status Reg */ ++ ++/* MII clause 22/28 definitions */ ++#define IXGBE_MDIO_PHY_LOW_POWER_MODE 0x0800 ++ ++#define IXGBE_MII_SPEED_SELECTION_REG 0x10 ++#define IXGBE_MII_RESTART 0x200 ++#define IXGBE_MII_AUTONEG_COMPLETE 0x20 ++#define IXGBE_MII_AUTONEG_REG 0x0 ++ + #define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 + #define IXGBE_MAX_PHY_ADDR 32 + + /* PHY IDs*/ +-#define TN1010_PHY_ID 0x00A19410 + #define QT2022_PHY_ID 0x0043A400 + ++/* PHY Types */ ++#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 ++ + /* General purpose Interrupt Enable */ +-#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ +-#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ +-#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ +-#define IXGBE_GPIE_EIAME 0x40000000 +-#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 ++#define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ ++#define IXGBE_SDP1_GPIEN 0x00000002 /* SDP1 */ ++#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ ++#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ ++#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ ++#define IXGBE_GPIE_EIAME 0x40000000 ++#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 + + /* Transmit Flow Control status */ + #define IXGBE_TFCS_TXOFF 0x00000001 +@@ -533,7 +561,7 @@ + #define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */ + + /* RMCS Bit Masks */ +-#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recylce Mode enable */ ++#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recycle Mode enable */ + /* Receive Arbitration Control: 0 Round Robin, 1 DFP */ + #define IXGBE_RMCS_RAC 0x00000004 + #define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */ +@@ -541,12 +569,15 @@ + #define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */ + #define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */ + ++ + /* Interrupt register bitmasks */ + + /* Extended Interrupt Cause Read */ + #define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ + #define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */ +-#define IXGBE_EICR_MNG 0x00400000 /* Managability Event Interrupt */ ++#define IXGBE_EICR_MNG 0x00400000 /* Manageability Event Interrupt */ ++#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ ++#define IXGBE_EICR_GPI_SDP1 0x02000000 /* Gen Purpose Interrupt on SDP1 */ + #define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */ + #define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */ + #define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ +@@ -554,11 +585,12 @@ + + /* Extended Interrupt Cause Set */ + #define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ +-#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ +-#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */ +-#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +-#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +-#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ ++#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */ ++#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ ++#define IXGBE_EICS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ ++#define IXGBE_EICS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ ++#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */ ++#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */ + #define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ + #define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +@@ -566,7 +598,9 @@ + #define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ + #define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */ + #define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +-#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ ++#define IXGBE_EIMS_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ ++#define IXGBE_EIMS_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ ++#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */ + #define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */ + #define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ + #define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ +@@ -575,18 +609,20 @@ + #define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */ + #define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */ + #define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */ +-#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */ +-#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */ ++#define IXGBE_EIMC_GPI_SDP0 IXGBE_EICR_GPI_SDP0 /* SDP0 Gen Purpose Int */ ++#define IXGBE_EIMC_GPI_SDP1 IXGBE_EICR_GPI_SDP1 /* SDP1 Gen Purpose Int */ ++#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Err */ ++#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Err */ + #define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */ + #define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */ + +-#define IXGBE_EIMS_ENABLE_MASK (\ +- IXGBE_EIMS_RTX_QUEUE | \ +- IXGBE_EIMS_LSC | \ +- IXGBE_EIMS_TCP_TIMER | \ +- IXGBE_EIMS_OTHER) ++#define IXGBE_EIMS_ENABLE_MASK ( \ ++ IXGBE_EIMS_RTX_QUEUE | \ ++ IXGBE_EIMS_LSC | \ ++ IXGBE_EIMS_TCP_TIMER | \ ++ IXGBE_EIMS_OTHER) + +-/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */ ++/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */ + #define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */ + #define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */ + #define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ +@@ -623,6 +659,7 @@ + #define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */ + #define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */ + ++ + #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */ + + /* STATUS Bit Masks */ +@@ -670,16 +707,16 @@ + #define IXGBE_AUTOC_AN_RESTART 0x00001000 + #define IXGBE_AUTOC_FLU 0x00000001 + #define IXGBE_AUTOC_LMS_SHIFT 13 +-#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) +-#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) +-#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) +-#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) +-#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) +-#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) +-#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) ++#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) ++#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT) ++#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT) ++#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT) ++#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT) ++#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT) ++#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) + +-#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 +-#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 ++#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200 ++#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180 + #define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7 + #define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9 + #define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +@@ -705,6 +742,7 @@ + #define IXGBE_LINKS_TL_FAULT 0x00001000 + #define IXGBE_LINKS_SIGNAL 0x00000F00 + ++#define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ + #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ + + /* SW Semaphore Register bitmasks */ +@@ -759,6 +797,11 @@ + #define IXGBE_PBANUM0_PTR 0x15 + #define IXGBE_PBANUM1_PTR 0x16 + ++/* Legacy EEPROM word offsets */ ++#define IXGBE_ISCSI_BOOT_CAPS 0x0033 ++#define IXGBE_ISCSI_SETUP_PORT_0 0x0030 ++#define IXGBE_ISCSI_SETUP_PORT_1 0x0034 ++ + /* EEPROM Commands - SPI */ + #define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */ + #define IXGBE_EEPROM_STATUS_RDY_SPI 0x01 +@@ -766,7 +809,7 @@ + #define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */ + #define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */ + #define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */ +-/* EEPROM reset Write Enbale latch */ ++/* EEPROM reset Write Enable latch */ + #define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04 + #define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */ + #define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */ +@@ -805,26 +848,20 @@ + /* Number of 100 microseconds we wait for PCI Express master disable */ + #define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 + +-/* PHY Types */ +-#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 +- + /* Check whether address is multicast. This is little-endian specific check.*/ + #define IXGBE_IS_MULTICAST(Address) \ +- (bool)(((u8 *)(Address))[0] & ((u8)0x01)) ++ (bool)(((u8 *)(Address))[0] & ((u8)0x01)) + + /* Check whether an address is broadcast. */ + #define IXGBE_IS_BROADCAST(Address) \ +- ((((u8 *)(Address))[0] == ((u8)0xff)) && \ +- (((u8 *)(Address))[1] == ((u8)0xff))) ++ ((((u8 *)(Address))[0] == ((u8)0xff)) && \ ++ (((u8 *)(Address))[1] == ((u8)0xff))) + + /* RAH */ + #define IXGBE_RAH_VIND_MASK 0x003C0000 + #define IXGBE_RAH_VIND_SHIFT 18 + #define IXGBE_RAH_AV 0x80000000 +- +-/* Filters */ +-#define IXGBE_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ +-#define IXGBE_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ ++#define IXGBE_CLEAR_VMDQ_ALL 0xFFFFFFFF + + /* Header split receive */ + #define IXGBE_RFCTL_ISCSI_DIS 0x00000001 +@@ -853,7 +890,7 @@ + #define IXGBE_MAX_FRAME_SZ 0x40040000 + + #define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */ +-#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */ ++#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq# write-back enable */ + + /* Receive Config masks */ + #define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ +@@ -866,7 +903,7 @@ + #define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */ + #define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */ + #define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */ +-/* Receive Priority Flow Control Enbale */ ++/* Receive Priority Flow Control Enable */ + #define IXGBE_FCTRL_RPFCE 0x00004000 + #define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */ + +@@ -896,9 +933,8 @@ + /* Receive Descriptor bit definitions */ + #define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ + #define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ +-#define IXGBE_RXD_STAT_IXSM 0x04 /* Ignore checksum */ + #define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +-#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ ++#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ + #define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */ + #define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ + #define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */ +@@ -914,7 +950,7 @@ + #define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */ + #define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */ + #define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */ +-#define IXGBE_RXDADV_HBO 0x00800000 ++#define IXGBE_RXDADV_ERR_HBO 0x00800000 /*Header Buffer Overflow */ + #define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */ + #define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */ + #define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */ +@@ -928,15 +964,17 @@ + #define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */ + #define IXGBE_RXD_CFI_SHIFT 12 + ++ + /* SRRCTL bit definitions */ +-#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ +-#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F +-#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 +-#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 ++#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */ ++#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F ++#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00 ++#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000 + #define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 + #define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 + #define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 + #define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 ++#define IXGBE_SRRCTL_DESCTYPE_MASK 0x0E000000 + + #define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000 + #define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF +@@ -970,21 +1008,20 @@ + #define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ + #define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ + #define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ +- + /* Masks to determine if packets should be dropped due to frame errors */ +-#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\ +- IXGBE_RXD_ERR_CE | \ +- IXGBE_RXD_ERR_LE | \ +- IXGBE_RXD_ERR_PE | \ +- IXGBE_RXD_ERR_OSE | \ +- IXGBE_RXD_ERR_USE) +- +-#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\ +- IXGBE_RXDADV_ERR_CE | \ +- IXGBE_RXDADV_ERR_LE | \ +- IXGBE_RXDADV_ERR_PE | \ +- IXGBE_RXDADV_ERR_OSE | \ +- IXGBE_RXDADV_ERR_USE) ++#define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \ ++ IXGBE_RXD_ERR_CE | \ ++ IXGBE_RXD_ERR_LE | \ ++ IXGBE_RXD_ERR_PE | \ ++ IXGBE_RXD_ERR_OSE | \ ++ IXGBE_RXD_ERR_USE) ++ ++#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK ( \ ++ IXGBE_RXDADV_ERR_CE | \ ++ IXGBE_RXDADV_ERR_LE | \ ++ IXGBE_RXDADV_ERR_PE | \ ++ IXGBE_RXDADV_ERR_OSE | \ ++ IXGBE_RXDADV_ERR_USE) + + /* Multicast bit mask */ + #define IXGBE_MCSTCTRL_MFE 0x4 +@@ -1000,6 +1037,7 @@ + #define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */ + #define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT + ++ + /* Transmit Descriptor - Legacy */ + struct ixgbe_legacy_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ +@@ -1007,15 +1045,15 @@ struct ixgbe_legacy_tx_desc { + __le32 data; + struct { + __le16 length; /* Data buffer length */ +- u8 cso; /* Checksum offset */ +- u8 cmd; /* Descriptor control */ ++ u8 cso; /* Checksum offset */ ++ u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + __le32 data; + struct { +- u8 status; /* Descriptor status */ +- u8 css; /* Checksum start */ ++ u8 status; /* Descriptor status */ ++ u8 css; /* Checksum start */ + __le16 vlan; + } fields; + } upper; +@@ -1024,7 +1062,7 @@ struct ixgbe_legacy_tx_desc { + /* Transmit Descriptor - Advanced */ + union ixgbe_adv_tx_desc { + struct { +- __le64 buffer_addr; /* Address of descriptor's data buf */ ++ __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; + } read; +@@ -1039,9 +1077,9 @@ union ixgbe_adv_tx_desc { + struct ixgbe_legacy_rx_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 length; /* Length of data DMAed into data buffer */ +- u16 csum; /* Packet checksum */ +- u8 status; /* Descriptor status */ +- u8 errors; /* Descriptor Errors */ ++ __le16 csum; /* Packet checksum */ ++ u8 status; /* Descriptor status */ ++ u8 errors; /* Descriptor Errors */ + __le16 vlan; + }; + +@@ -1053,15 +1091,18 @@ union ixgbe_adv_rx_desc { + } read; + struct { + struct { +- struct { +- __le16 pkt_info; /* RSS type, Packet type */ +- __le16 hdr_info; /* Split Header, header len */ ++ union { ++ __le32 data; ++ struct { ++ __le16 pkt_info; /* RSS, Pkt type */ ++ __le16 hdr_info; /* Splithdr, hdrlen */ ++ } hs_rss; + } lo_dword; + union { + __le32 rss; /* RSS Hash */ + struct { + __le16 ip_id; /* IP id */ +- u16 csum; /* Packet Checksum */ ++ __le16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; +@@ -1082,49 +1123,69 @@ struct ixgbe_adv_tx_context_desc { + }; + + /* Adv Transmit Descriptor Config Masks */ +-#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */ ++#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buf length(bytes) */ + #define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */ + #define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */ + #define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ + #define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ + #define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ +-#define IXGBE_ADVTXD_DCMD_RDMA 0x04000000 /* RDMA */ + #define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ +-#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ ++#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ + #define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */ + #define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */ + #define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ + #define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ +-#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */ ++#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED pres in WB */ + #define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */ + #define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ ++#define IXGBE_ADVTXD_CC 0x00000080 /* Check Context */ + #define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */ + #define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \ +- IXGBE_ADVTXD_POPTS_SHIFT) ++ IXGBE_ADVTXD_POPTS_SHIFT) + #define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \ +- IXGBE_ADVTXD_POPTS_SHIFT) +-#define IXGBE_ADVTXD_POPTS_EOM 0x00000400 /* Enable L bit-RDMA DDP hdr */ +-#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ +-#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ +-#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ +-#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/ +-#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ +-#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +-#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +-#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ +-#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +-#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ +-#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ +-#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +-#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */ +-#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +-#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ ++ IXGBE_ADVTXD_POPTS_SHIFT) ++#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ ++#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ ++#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ ++#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU */ ++#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */ ++#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ ++#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ ++#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ ++#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ ++#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ ++#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ ++#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ ++#define IXGBE_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ ++#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /*Req requires Markers and CRC*/ ++#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ ++#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + ++/* Autonegotiation advertised speeds */ ++typedef u32 ixgbe_autoneg_advertised; + /* Link speed */ ++typedef u32 ixgbe_link_speed; + #define IXGBE_LINK_SPEED_UNKNOWN 0 + #define IXGBE_LINK_SPEED_100_FULL 0x0008 + #define IXGBE_LINK_SPEED_1GB_FULL 0x0020 + #define IXGBE_LINK_SPEED_10GB_FULL 0x0080 ++#define IXGBE_LINK_SPEED_82598_AUTONEG (IXGBE_LINK_SPEED_1GB_FULL | \ ++ IXGBE_LINK_SPEED_10GB_FULL) ++ ++/* Physical layer type */ ++typedef u32 ixgbe_physical_layer; ++#define IXGBE_PHYSICAL_LAYER_UNKNOWN 0 ++#define IXGBE_PHYSICAL_LAYER_10GBASE_T 0x0001 ++#define IXGBE_PHYSICAL_LAYER_1000BASE_T 0x0002 ++#define IXGBE_PHYSICAL_LAYER_100BASE_T 0x0004 ++#define IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU 0x0008 ++#define IXGBE_PHYSICAL_LAYER_10GBASE_LR 0x0010 ++#define IXGBE_PHYSICAL_LAYER_10GBASE_LRM 0x0020 ++#define IXGBE_PHYSICAL_LAYER_10GBASE_SR 0x0040 ++#define IXGBE_PHYSICAL_LAYER_10GBASE_KX4 0x0080 ++#define IXGBE_PHYSICAL_LAYER_10GBASE_CX4 0x0100 ++#define IXGBE_PHYSICAL_LAYER_1000BASE_KX 0x0200 ++#define IXGBE_PHYSICAL_LAYER_1000BASE_BX 0x0400 + + + enum ixgbe_eeprom_type { +@@ -1141,16 +1202,38 @@ enum ixgbe_mac_type { + + enum ixgbe_phy_type { + ixgbe_phy_unknown = 0, +- ixgbe_phy_tn, + ixgbe_phy_qt, +- ixgbe_phy_xaui ++ ixgbe_phy_xaui, ++ ixgbe_phy_tw_tyco, ++ ixgbe_phy_tw_unknown, ++ ixgbe_phy_sfp_avago, ++ ixgbe_phy_sfp_ftl, ++ ixgbe_phy_sfp_unknown, ++ ixgbe_phy_generic ++}; ++ ++/* ++ * SFP+ module type IDs: ++ * ++ * ID Module Type ++ * ============= ++ * 0 SFP_DA_CU ++ * 1 SFP_SR ++ * 2 SFP_LR ++ */ ++enum ixgbe_sfp_type { ++ ixgbe_sfp_type_da_cu = 0, ++ ixgbe_sfp_type_sr = 1, ++ ixgbe_sfp_type_lr = 2, ++ ixgbe_sfp_type_unknown = 0xFFFF + }; + + enum ixgbe_media_type { + ixgbe_media_type_unknown = 0, + ixgbe_media_type_fiber, + ixgbe_media_type_copper, +- ixgbe_media_type_backplane ++ ixgbe_media_type_backplane, ++ ixgbe_media_type_virtual + }; + + /* Flow Control Settings */ +@@ -1167,6 +1250,8 @@ struct ixgbe_addr_filter_info { + u32 rar_used_count; + u32 mc_addr_in_rar_count; + u32 mta_in_use; ++ u32 overflow_promisc; ++ bool user_set_promisc; + }; + + /* Flow control parameters */ +@@ -1242,57 +1327,118 @@ struct ixgbe_hw_stats { + /* forward declaration */ + struct ixgbe_hw; + ++/* iterator type for walking multicast address lists */ ++typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr, ++ u32 *vmdq); ++ ++/* Function pointer table */ ++struct ixgbe_eeprom_operations { ++ s32 (*init_params)(struct ixgbe_hw *); ++ s32 (*read)(struct ixgbe_hw *, u16, u16 *); ++ s32 (*write)(struct ixgbe_hw *, u16, u16); ++ s32 (*validate_checksum)(struct ixgbe_hw *, u16 *); ++ s32 (*update_checksum)(struct ixgbe_hw *); ++}; ++ + struct ixgbe_mac_operations { +- s32 (*reset)(struct ixgbe_hw *); ++ s32 (*init_hw)(struct ixgbe_hw *); ++ s32 (*reset_hw)(struct ixgbe_hw *); ++ s32 (*start_hw)(struct ixgbe_hw *); ++ s32 (*clear_hw_cntrs)(struct ixgbe_hw *); + enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); ++ s32 (*get_supported_physical_layer)(struct ixgbe_hw *); ++ s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *); ++ s32 (*stop_adapter)(struct ixgbe_hw *); ++ s32 (*get_bus_info)(struct ixgbe_hw *); ++ s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*); ++ s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8); ++ ++ /* Link */ + s32 (*setup_link)(struct ixgbe_hw *); +- s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *); +- s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool); +- s32 (*get_link_settings)(struct ixgbe_hw *, u32 *, bool *); ++ s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, ++ bool); ++ s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); ++ s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, ++ bool *); ++ ++ /* LED */ ++ s32 (*led_on)(struct ixgbe_hw *, u32); ++ s32 (*led_off)(struct ixgbe_hw *, u32); ++ s32 (*blink_led_start)(struct ixgbe_hw *, u32); ++ s32 (*blink_led_stop)(struct ixgbe_hw *, u32); ++ ++ /* RAR, Multicast, VLAN */ ++ s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32, u32); ++ s32 (*clear_rar)(struct ixgbe_hw *, u32); ++ s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32); ++ s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32); ++ s32 (*init_rx_addrs)(struct ixgbe_hw *); ++ s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32, ++ ixgbe_mc_addr_itr); ++ s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32, ++ ixgbe_mc_addr_itr); ++ s32 (*enable_mc)(struct ixgbe_hw *); ++ s32 (*disable_mc)(struct ixgbe_hw *); ++ s32 (*clear_vfta)(struct ixgbe_hw *); ++ s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool); ++ s32 (*init_uta_tables)(struct ixgbe_hw *); ++ ++ /* Flow Control */ ++ s32 (*setup_fc)(struct ixgbe_hw *, s32); + }; + + struct ixgbe_phy_operations { ++ s32 (*identify)(struct ixgbe_hw *); ++ s32 (*identify_sfp)(struct ixgbe_hw *); ++ s32 (*reset)(struct ixgbe_hw *); ++ s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); ++ s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16); + s32 (*setup_link)(struct ixgbe_hw *); +- s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *); +- s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool); +-}; +- +-struct ixgbe_mac_info { +- struct ixgbe_mac_operations ops; +- enum ixgbe_mac_type type; +- u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; +- u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; +- s32 mc_filter_type; +- u32 num_rx_queues; +- u32 num_tx_queues; +- u32 num_rx_addrs; +- u32 link_attach_type; +- u32 link_mode_select; +- bool link_settings_loaded; ++ s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, ++ bool); ++ s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); ++ s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); ++ s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); ++ s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); + }; + + struct ixgbe_eeprom_info { +- enum ixgbe_eeprom_type type; +- u16 word_size; +- u16 address_bits; ++ struct ixgbe_eeprom_operations ops; ++ enum ixgbe_eeprom_type type; ++ u32 semaphore_delay; ++ u16 word_size; ++ u16 address_bits; + }; + +-struct ixgbe_phy_info { +- struct ixgbe_phy_operations ops; +- +- enum ixgbe_phy_type type; +- u32 addr; +- u32 id; +- u32 revision; +- enum ixgbe_media_type media_type; +- u32 autoneg_advertised; +- bool autoneg_wait_to_complete; ++struct ixgbe_mac_info { ++ struct ixgbe_mac_operations ops; ++ enum ixgbe_mac_type type; ++ u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; ++ u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS]; ++ s32 mc_filter_type; ++ u32 mcft_size; ++ u32 vft_size; ++ u32 num_rar_entries; ++ u32 max_tx_queues; ++ u32 max_rx_queues; ++ u32 link_attach_type; ++ u32 link_mode_select; ++ bool link_settings_loaded; ++ bool autoneg; ++ bool autoneg_failed; + }; + +-struct ixgbe_info { +- enum ixgbe_mac_type mac; +- s32 (*get_invariants)(struct ixgbe_hw *); +- struct ixgbe_mac_operations *mac_ops; ++struct ixgbe_phy_info { ++ struct ixgbe_phy_operations ops; ++ enum ixgbe_phy_type type; ++ u32 addr; ++ u32 id; ++ enum ixgbe_sfp_type sfp_type; ++ u32 revision; ++ enum ixgbe_media_type media_type; ++ bool reset_disable; ++ ixgbe_autoneg_advertised autoneg_advertised; ++ bool autoneg_wait_to_complete; + }; + + struct ixgbe_hw { +@@ -1311,6 +1457,15 @@ struct ixgbe_hw { + bool adapter_stopped; + }; + ++struct ixgbe_info { ++ enum ixgbe_mac_type mac; ++ s32 (*get_invariants)(struct ixgbe_hw *); ++ struct ixgbe_mac_operations *mac_ops; ++ struct ixgbe_eeprom_operations *eeprom_ops; ++ struct ixgbe_phy_operations *phy_ops; ++}; ++ ++ + /* Error Codes */ + #define IXGBE_ERR_EEPROM -1 + #define IXGBE_ERR_EEPROM_CHECKSUM -2 +@@ -1329,6 +1484,8 @@ struct ixgbe_hw { + #define IXGBE_ERR_RESET_FAILED -15 + #define IXGBE_ERR_SWFW_SYNC -16 + #define IXGBE_ERR_PHY_ADDR_INVALID -17 ++#define IXGBE_ERR_I2C -18 ++#define IXGBE_ERR_SFP_NOT_SUPPORTED -19 + #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF + + #endif /* _IXGBE_TYPE_H_ */ +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -2381,7 +2381,6 @@ config EHEA + config IXGBE + tristate "Intel(R) 10GbE PCI Express adapters support" + depends on PCI && INET +- select INET_LRO + ---help--- + This driver supports Intel(R) 10GbE PCI Express family of + adapters. For more information on how to identify your adapter, go +@@ -2397,6 +2396,16 @@ config IXGBE + To compile this driver as a module, choose M here. The module + will be called ixgbe. + ++config IXGBE_LRO ++ bool "Use software LRO" ++ depends on IXGBE && INET ++ select INET_LRO ++ default y ++ ---help--- ++ Say Y here if you want to use large receive offload. ++ ++ If in doubt, say N. ++ + config IXGB + tristate "Intel(R) PRO/10GbE support" + depends on PCI diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-sfp.patch b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-sfp.patch new file mode 100644 index 000000000..7fa7a0aba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe-sfp.patch @@ -0,0 +1,802 @@ +From: John Ronciak +Subject: ixgbe driver update to add Longcove (SFP+) NIC support for FCoE needs +Acked-by: Karsten Keil +Reference: bnc#442411 + + +The patch that will be attached is to update the ixgbe driver to add SFP+ NIC +support to SLES11 beta4 version of the ixgbe driver. NIC have been sent to +Nurnberg for testing purposes. We have already been testing the patch with +both our test lab and in our FCoE testing. + + +--- + drivers/net/ixgbe/ixgbe.h | 5 + drivers/net/ixgbe/ixgbe_82598.c | 161 ++++++++++++++++++++++++ + drivers/net/ixgbe/ixgbe_main.c | 92 +++++++++++++- + drivers/net/ixgbe/ixgbe_phy.c | 258 ++++++++++++++++++++++++++++++++++++++++ + drivers/net/ixgbe/ixgbe_phy.h | 18 ++ + drivers/net/ixgbe/ixgbe_type.h | 19 ++ + 6 files changed, 546 insertions(+), 7 deletions(-) + +--- a/drivers/net/ixgbe/ixgbe_82598.c ++++ b/drivers/net/ixgbe/ixgbe_82598.c +@@ -46,6 +46,8 @@ static s32 ixgbe_setup_copper_link_speed + ixgbe_link_speed speed, + bool autoneg, + bool autoneg_wait_to_complete); ++static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, ++ u8 *eeprom_data); + + /** + */ +@@ -53,12 +55,35 @@ static s32 ixgbe_get_invariants_82598(st + { + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; ++ s32 ret_val = 0; ++ u16 list_offset, data_offset; + + /* Call PHY identify routine to get the phy type */ + ixgbe_identify_phy_generic(hw); + + /* PHY Init */ + switch (phy->type) { ++ case ixgbe_phy_nl: ++ phy->ops.reset = &ixgbe_reset_phy_nl; ++ ++ /* Call SFP+ identify routine to get the SFP+ module type */ ++ ret_val = phy->ops.identify_sfp(hw); ++ if (ret_val != 0) ++ goto out; ++ else if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) { ++ ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; ++ goto out; ++ } ++ ++ /* Check to see if SFP+ module is supported */ ++ ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, ++ &list_offset, ++ &data_offset); ++ if (ret_val != 0) { ++ ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; ++ goto out; ++ } ++ break; + case ixgbe_phy_tn: + phy->ops.check_link = &ixgbe_check_phy_link_tnx; + phy->ops.get_firmware_version = +@@ -82,7 +107,8 @@ static s32 ixgbe_get_invariants_82598(st + mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; + mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; + +- return 0; ++out: ++ return ret_val; + } + + /** +@@ -191,7 +217,10 @@ static enum ixgbe_media_type ixgbe_get_m + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598EB_CX4: + case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: ++ case IXGBE_DEV_ID_82598_DA_DUAL_PORT: ++ case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: + case IXGBE_DEV_ID_82598EB_XF_LR: ++ case IXGBE_DEV_ID_82598EB_SFP_LOM: + media_type = ixgbe_media_type_fiber; + break; + case IXGBE_DEV_ID_82598AT: +@@ -399,6 +428,47 @@ static s32 ixgbe_check_mac_link_82598(st + { + u32 links_reg; + u32 i; ++ u16 link_reg, adapt_comp_reg; ++ ++ /* ++ * SERDES PHY requires us to read link status from register 0xC79F. ++ * Bit 0 set indicates link is up/ready; clear indicates link down. ++ * OxC00C is read to check that the XAUI lanes are active. Bit 0 ++ * clear indicates active; set indicates inactive. ++ */ ++ if (hw->phy.type == ixgbe_phy_nl) { ++ hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); ++ hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); ++ hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, ++ &adapt_comp_reg); ++ if (link_up_wait_to_complete) { ++ for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { ++ if ((link_reg & 1) && ++ ((adapt_comp_reg & 1) == 0)) { ++ *link_up = true; ++ break; ++ } else { ++ *link_up = false; ++ } ++ msleep(100); ++ hw->phy.ops.read_reg(hw, 0xC79F, ++ IXGBE_TWINAX_DEV, ++ &link_reg); ++ hw->phy.ops.read_reg(hw, 0xC00C, ++ IXGBE_TWINAX_DEV, ++ &adapt_comp_reg); ++ } ++ } else { ++ if ((link_reg & 1) && ++ ((adapt_comp_reg & 1) == 0)) ++ *link_up = true; ++ else ++ *link_up = false; ++ } ++ ++ if (*link_up == false) ++ goto out; ++ } + + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + if (link_up_wait_to_complete) { +@@ -424,6 +494,7 @@ static s32 ixgbe_check_mac_link_82598(st + else + *speed = IXGBE_LINK_SPEED_1GB_FULL; + ++out: + return 0; + } + +@@ -859,6 +930,69 @@ s32 ixgbe_write_analog_reg8_82598(struct + } + + /** ++ * ixgbe_read_i2c_eeprom_82598 - Reads 8 bit EEPROM word of an SFP+ module ++ * over I2C interface through an intermediate phy. ++ * @hw: pointer to hardware structure ++ * @byte_offset: EEPROM byte offset to read ++ * @eeprom_data: value read ++ * ++ * Performs byte read operation to SFP module's EEPROM over I2C interface. ++ **/ ++s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, ++ u8 *eeprom_data) ++{ ++ s32 status = 0; ++ u16 sfp_addr = 0; ++ u16 sfp_data = 0; ++ u16 sfp_stat = 0; ++ u32 i; ++ ++ if (hw->phy.type == ixgbe_phy_nl) { ++ /* ++ * phy SDA/SCL registers are at addresses 0xC30A to ++ * 0xC30D. These registers are used to talk to the SFP+ ++ * module's EEPROM through the SDA/SCL (I2C) interface. ++ */ ++ sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset; ++ sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); ++ hw->phy.ops.write_reg(hw, ++ IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, ++ sfp_addr); ++ ++ /* Poll status */ ++ for (i = 0; i < 100; i++) { ++ hw->phy.ops.read_reg(hw, ++ IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, ++ &sfp_stat); ++ sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; ++ if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) ++ break; ++ msleep(10); ++ } ++ ++ if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { ++ hw_dbg(hw, "EEPROM read did not pass.\n"); ++ status = IXGBE_ERR_SFP_NOT_PRESENT; ++ goto out; ++ } ++ ++ /* Read data */ ++ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, ++ IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); ++ ++ *eeprom_data = (u8)(sfp_data >> 8); ++ } else { ++ status = IXGBE_ERR_PHY; ++ goto out; ++ } ++ ++out: ++ return status; ++} ++ ++/** + * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type + * @hw: pointer to hardware structure + * +@@ -873,13 +1007,35 @@ s32 ixgbe_get_supported_physical_layer_8 + case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; + break; ++ case IXGBE_DEV_ID_82598_DA_DUAL_PORT: ++ physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; ++ break; + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: ++ case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + break; + case IXGBE_DEV_ID_82598EB_XF_LR: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; ++ case IXGBE_DEV_ID_82598EB_SFP_LOM: ++ hw->phy.ops.identify_sfp(hw); ++ ++ switch (hw->phy.sfp_type) { ++ case ixgbe_sfp_type_da_cu: ++ physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; ++ break; ++ case ixgbe_sfp_type_sr: ++ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; ++ break; ++ case ixgbe_sfp_type_lr: ++ physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; ++ break; ++ default: ++ physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; ++ break; ++ } ++ break; + case IXGBE_DEV_ID_82598AT: + physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | + IXGBE_PHYSICAL_LAYER_1000BASE_T); +@@ -935,12 +1091,13 @@ static struct ixgbe_eeprom_operations ee + + static struct ixgbe_phy_operations phy_ops_82598 = { + .identify = &ixgbe_identify_phy_generic, +- /* .identify_sfp = &ixgbe_identify_sfp_module_generic, */ ++ .identify_sfp = &ixgbe_identify_sfp_module_generic, + .reset = &ixgbe_reset_phy_generic, + .read_reg = &ixgbe_read_phy_reg_generic, + .write_reg = &ixgbe_write_phy_reg_generic, + .setup_link = &ixgbe_setup_phy_link_generic, + .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, ++ .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598, + }; + + struct ixgbe_info ixgbe_82598_info = { +--- a/drivers/net/ixgbe/ixgbe.h ++++ b/drivers/net/ixgbe/ixgbe.h +@@ -318,12 +318,15 @@ struct ixgbe_adapter { + unsigned long link_check_timeout; + + struct work_struct watchdog_task; ++ struct work_struct sfp_task; ++ struct timer_list sfp_timer; + }; + + enum ixbge_state_t { + __IXGBE_TESTING, + __IXGBE_RESETTING, +- __IXGBE_DOWN ++ __IXGBE_DOWN, ++ __IXGBE_SFP_MODULE_NOT_FOUND + }; + + enum ixgbe_boards { +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -74,8 +74,14 @@ static struct pci_device_id ixgbe_pci_tb + board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), + board_82598 }, ++ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), ++ board_82598 }, ++ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), ++ board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), + board_82598 }, ++ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), ++ board_82598 }, + + /* required last entry */ + {0, } +@@ -2678,6 +2684,56 @@ err_alloc_queues: + } + + /** ++ * ixgbe_sfp_timer - worker thread to find a missing module ++ * @data: pointer to our adapter struct ++ **/ ++static void ixgbe_sfp_timer(unsigned long data) ++{ ++ struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; ++ ++ /* Do the sfp_timer outside of interrupt context due to the ++ * delays that sfp+ detection requires */ ++ schedule_work(&adapter->sfp_task); ++} ++ ++/** ++ * ixgbe_sfp_task - worker thread to find a missing module ++ * @work: pointer to work_struct containing our data ++ **/ ++static void ixgbe_sfp_task(struct work_struct *work) ++{ ++ struct ixgbe_adapter *adapter = container_of(work, ++ struct ixgbe_adapter, ++ sfp_task); ++ struct ixgbe_hw *hw = &adapter->hw; ++ ++ if ((hw->phy.type == ixgbe_phy_nl) && ++ (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { ++ s32 ret = hw->phy.ops.identify_sfp(hw); ++ if (ret) ++ goto reschedule; ++ ret = hw->phy.ops.reset(hw); ++ if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { ++ DPRINTK(PROBE, ERR, "failed to initialize because an " ++ "unsupported SFP+ module type was detected.\n" ++ "Reload the driver after installing a " ++ "supported module.\n"); ++ unregister_netdev(adapter->netdev); ++ } else { ++ DPRINTK(PROBE, INFO, "detected SFP+: %d\n", ++ hw->phy.sfp_type); ++ } ++ /* don't need this routine any more */ ++ clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); ++ } ++ return; ++reschedule: ++ if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) ++ mod_timer(&adapter->sfp_timer, ++ round_jiffies(jiffies + (2 * HZ))); ++} ++ ++/** + * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) + * @adapter: board private structure to initialize + * +@@ -4002,11 +4058,30 @@ static int __devinit ixgbe_probe(struct + + /* PHY */ + memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); +- /* phy->sfp_type = ixgbe_sfp_type_unknown; */ ++ hw->phy.sfp_type = ixgbe_sfp_type_unknown; ++ ++ /* set up this timer and work struct before calling get_invariants ++ * which might start the timer */ ++ init_timer(&adapter->sfp_timer); ++ adapter->sfp_timer.function = &ixgbe_sfp_timer; ++ adapter->sfp_timer.data = (unsigned long) adapter; ++ ++ INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); + + err = ii->get_invariants(hw); +- if (err) ++ if (err == IXGBE_ERR_SFP_NOT_PRESENT) { ++ /* start a kernel thread to watch for a module to arrive */ ++ set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); ++ mod_timer(&adapter->sfp_timer, ++ round_jiffies(jiffies + (2 * HZ))); ++ err = 0; ++ } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { ++ DPRINTK(PROBE, ERR, "failed to load because an " ++ "unsupported SFP+ module type was detected.\n"); ++ goto err_hw_init; ++ } else if (err) { + goto err_hw_init; ++ } + + /* setup the private structure */ + err = ixgbe_sw_init(adapter); +@@ -4144,6 +4219,9 @@ err_hw_init: + err_sw_init: + ixgbe_reset_interrupt_capability(adapter); + err_eeprom: ++ clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); ++ del_timer_sync(&adapter->sfp_timer); ++ cancel_work_sync(&adapter->sfp_task); + iounmap(hw->hw_addr); + err_ioremap: + free_netdev(netdev); +@@ -4170,8 +4248,13 @@ static void __devexit ixgbe_remove(struc + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + set_bit(__IXGBE_DOWN, &adapter->state); ++ /* clear the module not found bit to make sure the worker won't ++ * reschedule */ ++ clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); +- ++ del_timer_sync(&adapter->sfp_timer); ++ cancel_work_sync(&adapter->watchdog_task); ++ cancel_work_sync(&adapter->sfp_task); + flush_scheduled_work(); + + #if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) +@@ -4182,7 +4265,8 @@ static void __devexit ixgbe_remove(struc + } + + #endif +- unregister_netdev(netdev); ++ if (netdev->reg_state == NETREG_REGISTERED) ++ unregister_netdev(netdev); + + ixgbe_reset_interrupt_capability(adapter); + +--- a/drivers/net/ixgbe/ixgbe_phy.c ++++ b/drivers/net/ixgbe/ixgbe_phy.c +@@ -127,6 +127,9 @@ static enum ixgbe_phy_type ixgbe_get_phy + case QT2022_PHY_ID: + phy_type = ixgbe_phy_qt; + break; ++ case ATH_PHY_ID: ++ phy_type = ixgbe_phy_nl; ++ break; + default: + phy_type = ixgbe_phy_unknown; + break; +@@ -430,6 +433,261 @@ s32 ixgbe_setup_phy_link_speed_generic(s + } + + /** ++ * ixgbe_reset_phy_nl - Performs a PHY reset ++ * @hw: pointer to hardware structure ++ **/ ++s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) ++{ ++ u16 phy_offset, control, eword, edata, block_crc; ++ bool end_data = false; ++ u16 list_offset, data_offset; ++ u16 phy_data = 0; ++ s32 ret_val = 0; ++ u32 i; ++ ++ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, ++ IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); ++ ++ /* reset the PHY and poll for completion */ ++ hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, ++ IXGBE_MDIO_PHY_XS_DEV_TYPE, ++ (phy_data | IXGBE_MDIO_PHY_XS_RESET)); ++ ++ for (i = 0; i < 100; i++) { ++ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, ++ IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); ++ if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) ++ break; ++ msleep(10); ++ } ++ ++ if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { ++ hw_dbg(hw, "PHY reset did not complete.\n"); ++ ret_val = IXGBE_ERR_PHY; ++ goto out; ++ } ++ ++ /* Get init offsets */ ++ ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, ++ &data_offset); ++ if (ret_val != 0) ++ goto out; ++ ++ ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); ++ data_offset++; ++ while (!end_data) { ++ /* ++ * Read control word from PHY init contents offset ++ */ ++ ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); ++ control = (eword & IXGBE_CONTROL_MASK_NL) >> ++ IXGBE_CONTROL_SHIFT_NL; ++ edata = eword & IXGBE_DATA_MASK_NL; ++ switch (control) { ++ case IXGBE_DELAY_NL: ++ data_offset++; ++ hw_dbg(hw, "DELAY: %d MS\n", edata); ++ msleep(edata); ++ break; ++ case IXGBE_DATA_NL: ++ hw_dbg(hw, "DATA: \n"); ++ data_offset++; ++ hw->eeprom.ops.read(hw, data_offset++, ++ &phy_offset); ++ for (i = 0; i < edata; i++) { ++ hw->eeprom.ops.read(hw, data_offset, &eword); ++ hw->phy.ops.write_reg(hw, phy_offset, ++ IXGBE_TWINAX_DEV, eword); ++ hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, ++ phy_offset); ++ data_offset++; ++ phy_offset++; ++ } ++ break; ++ case IXGBE_CONTROL_NL: ++ data_offset++; ++ hw_dbg(hw, "CONTROL: \n"); ++ if (edata == IXGBE_CONTROL_EOL_NL) { ++ hw_dbg(hw, "EOL\n"); ++ end_data = true; ++ } else if (edata == IXGBE_CONTROL_SOL_NL) { ++ hw_dbg(hw, "SOL\n"); ++ } else { ++ hw_dbg(hw, "Bad control value\n"); ++ ret_val = IXGBE_ERR_PHY; ++ goto out; ++ } ++ break; ++ default: ++ hw_dbg(hw, "Bad control type\n"); ++ ret_val = IXGBE_ERR_PHY; ++ goto out; ++ } ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns ++ * the PHY type. ++ * @hw: pointer to hardware structure ++ * ++ * Searches for and identifies the SFP module. Assigns appropriate PHY type. ++ **/ ++s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) ++{ ++ s32 status = IXGBE_ERR_PHY_ADDR_INVALID; ++ u32 vendor_oui = 0; ++ u8 identifier = 0; ++ u8 comp_codes_1g = 0; ++ u8 comp_codes_10g = 0; ++ u8 oui_bytes[4] = {0, 0, 0, 0}; ++ u8 transmission_media = 0; ++ ++ status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, ++ &identifier); ++ ++ if (status == IXGBE_ERR_SFP_NOT_PRESENT) { ++ hw->phy.sfp_type = ixgbe_sfp_type_not_present; ++ goto out; ++ } ++ ++ if (identifier == IXGBE_SFF_IDENTIFIER_SFP) { ++ hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES, ++ &comp_codes_1g); ++ hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, ++ &comp_codes_10g); ++ hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, ++ &transmission_media); ++ ++ /* ID Module ++ * ============ ++ * 0 SFP_DA_CU ++ * 1 SFP_SR ++ * 2 SFP_LR ++ */ ++ if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) ++ hw->phy.sfp_type = ixgbe_sfp_type_da_cu; ++ else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) ++ hw->phy.sfp_type = ixgbe_sfp_type_sr; ++ else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) ++ hw->phy.sfp_type = ixgbe_sfp_type_lr; ++ else ++ hw->phy.sfp_type = ixgbe_sfp_type_unknown; ++ ++ /* Determine PHY vendor */ ++ if (hw->phy.type == ixgbe_phy_unknown) { ++ hw->phy.id = identifier; ++ hw->phy.ops.read_i2c_eeprom(hw, ++ IXGBE_SFF_VENDOR_OUI_BYTE0, ++ &oui_bytes[0]); ++ hw->phy.ops.read_i2c_eeprom(hw, ++ IXGBE_SFF_VENDOR_OUI_BYTE1, ++ &oui_bytes[1]); ++ hw->phy.ops.read_i2c_eeprom(hw, ++ IXGBE_SFF_VENDOR_OUI_BYTE2, ++ &oui_bytes[2]); ++ ++ vendor_oui = ++ ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | ++ (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | ++ (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); ++ ++ switch (vendor_oui) { ++ case IXGBE_SFF_VENDOR_OUI_TYCO: ++ if (transmission_media & ++ IXGBE_SFF_TWIN_AX_CAPABLE) ++ hw->phy.type = ixgbe_phy_tw_tyco; ++ break; ++ case IXGBE_SFF_VENDOR_OUI_FTL: ++ hw->phy.type = ixgbe_phy_sfp_ftl; ++ break; ++ case IXGBE_SFF_VENDOR_OUI_AVAGO: ++ hw->phy.type = ixgbe_phy_sfp_avago; ++ break; ++ default: ++ if (transmission_media & ++ IXGBE_SFF_TWIN_AX_CAPABLE) ++ hw->phy.type = ixgbe_phy_tw_unknown; ++ else ++ hw->phy.type = ixgbe_phy_sfp_unknown; ++ break; ++ } ++ } ++ status = 0; ++ } ++ ++out: ++ return status; ++} ++ ++/** ++ * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see ++ * if it supports a given SFP+ module type, if so it returns the offsets to the ++ * phy init sequence block. ++ * @hw: pointer to hardware structure ++ * @list_offset: offset to the SFP ID list ++ * @data_offset: offset to the SFP data block ++ **/ ++s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, ++ u16 *list_offset, ++ u16 *data_offset) ++{ ++ u16 sfp_id; ++ ++ if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) ++ return IXGBE_ERR_SFP_NOT_SUPPORTED; ++ ++ if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) ++ return IXGBE_ERR_SFP_NOT_PRESENT; ++ ++ if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && ++ (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) ++ return IXGBE_ERR_SFP_NOT_SUPPORTED; ++ ++ /* Read offset to PHY init contents */ ++ hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); ++ ++ if ((!*list_offset) || (*list_offset == 0xFFFF)) ++ return IXGBE_ERR_PHY; ++ ++ /* Shift offset to first ID word */ ++ (*list_offset)++; ++ ++ /* ++ * Find the matching SFP ID in the EEPROM ++ * and program the init sequence ++ */ ++ hw->eeprom.ops.read(hw, *list_offset, &sfp_id); ++ ++ while (sfp_id != IXGBE_PHY_INIT_END_NL) { ++ if (sfp_id == hw->phy.sfp_type) { ++ (*list_offset)++; ++ hw->eeprom.ops.read(hw, *list_offset, data_offset); ++ if ((!*data_offset) || (*data_offset == 0xFFFF)) { ++ hw_dbg(hw, "SFP+ module not supported\n"); ++ return IXGBE_ERR_SFP_NOT_SUPPORTED; ++ } else { ++ break; ++ } ++ } else { ++ (*list_offset) += 2; ++ if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) ++ return IXGBE_ERR_PHY; ++ } ++ } ++ ++ if (sfp_id == IXGBE_PHY_INIT_END_NL) { ++ hw_dbg(hw, "No matching SFP+ module found\n"); ++ return IXGBE_ERR_SFP_NOT_SUPPORTED; ++ } ++ ++ return 0; ++} ++ ++/** + * ixgbe_check_phy_link_tnx - Determine link and speed status + * @hw: pointer to hardware structure + * +--- a/drivers/net/ixgbe/ixgbe_phy.h ++++ b/drivers/net/ixgbe/ixgbe_phy.h +@@ -63,6 +63,18 @@ + #define IXGBE_SFF_VENDOR_OUI_FTL 0x00906500 + #define IXGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00 + ++/* I2C SDA and SCL timing parameters for standard mode */ ++#define IXGBE_I2C_T_HD_STA 4 ++#define IXGBE_I2C_T_LOW 5 ++#define IXGBE_I2C_T_HIGH 4 ++#define IXGBE_I2C_T_SU_STA 5 ++#define IXGBE_I2C_T_HD_DATA 5 ++#define IXGBE_I2C_T_SU_DATA 1 ++#define IXGBE_I2C_T_RISE 1 ++#define IXGBE_I2C_T_FALL 1 ++#define IXGBE_I2C_T_SU_STO 4 ++#define IXGBE_I2C_T_BUF 5 ++ + + s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); + s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); +@@ -84,4 +96,10 @@ s32 ixgbe_check_phy_link_tnx(struct ixgb + s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version); + ++/* PHY specific */ ++s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw); ++s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); ++s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, ++ u16 *list_offset, ++ u16 *data_offset); + #endif /* _IXGBE_PHY_H_ */ +--- a/drivers/net/ixgbe/ixgbe_type.h ++++ b/drivers/net/ixgbe/ixgbe_type.h +@@ -36,9 +36,12 @@ + /* Device IDs */ + #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 + #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 ++#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB + #define IXGBE_DEV_ID_82598AT 0x10C8 + #define IXGBE_DEV_ID_82598EB_CX4 0x10DD + #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC ++#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 ++#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 + #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 + + /* General Registers */ +@@ -453,6 +456,7 @@ + #define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 + #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 + #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ ++#define IXGBE_TWINAX_DEV 1 + + #define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ + +@@ -492,9 +496,21 @@ + #define TN1010_PHY_ID 0x00A19410 + #define TNX_FW_REV 0xB + #define QT2022_PHY_ID 0x0043A400 ++#define ATH_PHY_ID 0x03429050 + + /* PHY Types */ + #define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 ++/* Special PHY Init Routine */ ++#define IXGBE_PHY_INIT_OFFSET_NL 0x002B ++#define IXGBE_PHY_INIT_END_NL 0xFFFF ++#define IXGBE_CONTROL_MASK_NL 0xF000 ++#define IXGBE_DATA_MASK_NL 0x0FFF ++#define IXGBE_CONTROL_SHIFT_NL 12 ++#define IXGBE_DELAY_NL 0 ++#define IXGBE_DATA_NL 1 ++#define IXGBE_CONTROL_NL 0x000F ++#define IXGBE_CONTROL_EOL_NL 0x0FFF ++#define IXGBE_CONTROL_SOL_NL 0x0000 + + /* General purpose Interrupt Enable */ + #define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ +@@ -1208,6 +1224,7 @@ enum ixgbe_phy_type { + ixgbe_phy_tn, + ixgbe_phy_qt, + ixgbe_phy_xaui, ++ ixgbe_phy_nl, + ixgbe_phy_tw_tyco, + ixgbe_phy_tw_unknown, + ixgbe_phy_sfp_avago, +@@ -1229,6 +1246,7 @@ enum ixgbe_sfp_type { + ixgbe_sfp_type_da_cu = 0, + ixgbe_sfp_type_sr = 1, + ixgbe_sfp_type_lr = 2, ++ ixgbe_sfp_type_not_present = 0xFFFE, + ixgbe_sfp_type_unknown = 0xFFFF + }; + +@@ -1492,6 +1510,7 @@ struct ixgbe_info { + #define IXGBE_ERR_PHY_ADDR_INVALID -17 + #define IXGBE_ERR_I2C -18 + #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 ++#define IXGBE_ERR_SFP_NOT_PRESENT -20 + #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF + + #endif /* _IXGBE_TYPE_H_ */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe_DCB_compile_err.patch b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe_DCB_compile_err.patch new file mode 100644 index 000000000..c79b20c3a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe_DCB_compile_err.patch @@ -0,0 +1,130 @@ +From: John Ronciak +Subject: DCB compile error fix +Acked-by: Karsten Keil +Reference: bnc#465923 + +DCB compile error fix + +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.5) +Gecko/2008120122 Firefox/3.0.5 + +The files ixgbe_dcb.o ixgbe_dcb_82598.c and ixgbe_dcb_nl.c should not be +compiled if DCB_CONFIG is not set. The makefile should handle this correctly +now like in upstream kernel. + + +--- + drivers/net/Kconfig | 10 ++++++++++ + drivers/net/ixgbe/Makefile | 5 +++-- + drivers/net/ixgbe/ixgbe_main.c | 17 +++++++++++++---- + 3 files changed, 26 insertions(+), 6 deletions(-) + +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -1919,6 +1919,7 @@ static void ixgbe_napi_disable_all(struc + } + } + ++#ifdef CONFIG_IXGBE_DCB + /* + * ixgbe_configure_dcb - Configure DCB hardware + * @adapter: ixgbe adapter struct +@@ -1954,6 +1955,7 @@ static void ixgbe_configure_dcb(struct i + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); + hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true); + } ++#endif /* CONFIG_IXGBE_DCB */ + + static void ixgbe_configure(struct ixgbe_adapter *adapter) + { +@@ -1963,12 +1965,17 @@ static void ixgbe_configure(struct ixgbe + ixgbe_set_rx_mode(netdev); + + ixgbe_restore_vlan(adapter); ++#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + netif_set_gso_max_size(netdev, 32768); + ixgbe_configure_dcb(adapter); + } else { + netif_set_gso_max_size(netdev, 65536); + } ++#else ++ netif_set_gso_max_size(netdev, 65536); ++#endif /* CONFIG_IXGBE_DCB */ ++ + + ixgbe_configure_tx(adapter); + ixgbe_configure_rx(adapter); +@@ -2746,8 +2753,10 @@ static int __devinit ixgbe_sw_init(struc + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + unsigned int rss; ++#ifdef CONFIG_IXGBE_DCB + int j; + struct tc_configuration *tc; ++#endif /* CONFIG_IXGBE_DCB */ + + /* PCI config space info */ + +@@ -2766,6 +2775,7 @@ static int __devinit ixgbe_sw_init(struc + adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; + adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; + ++#ifdef CONFIG_IXGBE_DCB + /* Configure DCB traffic classes */ + for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { + tc = &adapter->dcb_cfg.tc_config[j]; +@@ -2780,10 +2790,9 @@ static int __devinit ixgbe_sw_init(struc + adapter->dcb_cfg.rx_pba_cfg = pba_equal; + adapter->dcb_cfg.round_robin_enable = false; + adapter->dcb_set_bitmap = 0x00; +-#ifdef CONFIG_DCBNL + ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, + adapter->ring_feature[RING_F_DCB].indices); +-#endif ++#endif /* CONFIG_IXGBE_DCB */ + + /* default flow control settings */ + hw->fc.original_type = ixgbe_fc_none; +@@ -4116,9 +4125,9 @@ static int __devinit ixgbe_probe(struct + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + +-#ifdef CONFIG_DCBNL ++#ifdef CONFIG_IXGBE_DCB + netdev->dcbnl_ops = &dcbnl_ops; +-#endif ++#endif /* CONFIG_IXGBE_DCB */ + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; +--- a/drivers/net/ixgbe/Makefile ++++ b/drivers/net/ixgbe/Makefile +@@ -33,5 +33,6 @@ + obj-$(CONFIG_IXGBE) += ixgbe.o + + ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ +- ixgbe_82598.o ixgbe_phy.o ixgbe_dcb.o ixgbe_dcb_82598.o \ +- ixgbe_dcb_nl.o ++ ixgbe_82598.o ixgbe_phy.o ++ ++ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o ixgbe_dcb_nl.o +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -2406,6 +2406,16 @@ config IXGBE_LRO + + If in doubt, say N. + ++config IXGBE_DCB ++ bool "Data Center Bridging (DCB) Support" ++ default n ++ depends on IXGBE && DCB ++ ---help--- ++ Say Y here if you want to use Data Center Bridging (DCB) in the ++ driver. ++ ++ If unsure, say N. ++ + config IXGB + tristate "Intel(R) PRO/10GbE support" + depends on PCI diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ixgbe_pagesize_fix.patch b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe_pagesize_fix.patch new file mode 100644 index 000000000..44ff3d18c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ixgbe_pagesize_fix.patch @@ -0,0 +1,54 @@ +From: Jesse Brandeburg +Subject: ixgbe bad performance with 64kB pages and large MTU +Acked-by: Karsten Keil +Reference: bnc#480109 + +it was pointed out on the list that ixgbe was failing when using 64kB pages +and large 16kB MTU. + +since with a 64kB PAGE_SIZE MAX_SKB_FRAGS = 3, the way the driver was +configuring page usage was assuming 2kB is half a page, and was only +ever dmaing that much data to a half page. + +(16kB - header size) / 2048 = 7 or 8 pages, which would far exceed 3 + +adjust the driver to account for these large pages, the hardware can +support DMA to up to 16kB for each descriptor. + +Signed-off-by: Jesse Brandeburg +CC: Breno Leitao +Signed-off-by: Jeff Kirsher +--- + + drivers/net/ixgbe/ixgbe.h | 1 + + drivers/net/ixgbe/ixgbe_main.c | 9 ++++++++- + 2 files changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/net/ixgbe/ixgbe.h ++++ b/drivers/net/ixgbe/ixgbe.h +@@ -77,6 +77,7 @@ + #define IXGBE_RXBUFFER_128 128 /* Used for packet split */ + #define IXGBE_RXBUFFER_256 256 /* Used for packet split */ + #define IXGBE_RXBUFFER_2048 2048 ++#define IXGBE_MAX_RXBUFFER 16384 /* largest size for a single descriptor */ + + #define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256 + +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -1537,7 +1537,14 @@ static void ixgbe_configure_srrctl(struc + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + + if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) { +- srrctl |= IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; ++ u16 bufsz = IXGBE_RXBUFFER_2048; ++ /* grow the amount we can receive on large page machines */ ++ if (bufsz < (PAGE_SIZE / 2)) ++ bufsz = (PAGE_SIZE / 2); ++ /* cap the bufsz at our largest descriptor size */ ++ bufsz = min((u16)IXGBE_MAX_RXBUFFER, bufsz); ++ ++ srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + srrctl |= ((IXGBE_RX_HDR_SIZE << + IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) & diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-6gbps-message b/src/patches/suse-2.6.27.31/patches.drivers/libata-6gbps-message new file mode 100644 index 000000000..02272f54b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-6gbps-message @@ -0,0 +1,39 @@ +From: Shane Huang +Subject: [PATCH] Add SATA GEN3 related messages +References: bnc#522911 + +The present AHCI driver seems to support SATA GEN 3 speed, but the related +messages should be modified. + +Signed-off-by: Shane Huang +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 2 ++ + drivers/ata/libata-core.c | 1 + + 2 files changed, 3 insertions(+) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/ahci.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +@@ -2441,6 +2441,8 @@ static void ahci_print_info(struct ata_h + speed_s = "1.5"; + else if (speed == 2) + speed_s = "3"; ++ else if (speed == 3) ++ speed_s = "6"; + else + speed_s = "?"; + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/libata-core.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/libata-core.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/libata-core.c +@@ -930,6 +930,7 @@ static const char *sata_spd_string(unsig + static const char * const spd_str[] = { + "1.5 Gbps", + "3.0 Gbps", ++ "6.0 Gbps", + }; + + if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str)) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-add-and-use-HORKAGE_ATAPI_MOD16_DMA b/src/patches/suse-2.6.27.31/patches.drivers/libata-add-and-use-HORKAGE_ATAPI_MOD16_DMA new file mode 100644 index 000000000..325edbf3c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-add-and-use-HORKAGE_ATAPI_MOD16_DMA @@ -0,0 +1,54 @@ +From 6a87e42e955ff27e07a77f65f8f077dc7c4171e1 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Mon, 3 Nov 2008 19:01:09 +0900 +Subject: [PATCH] libata: implement ATA_HORKAGE_ATAPI_MOD16_DMA and apply it + +libata always uses PIO for ATAPI commands when the number of bytes to +transfer isn't multiple of 16 but quantum DAT72 chokes on odd bytes +PIO transfers. Implement a horkage to skip the mod16 check and apply +it to the quantum device. + +This is reported by John Clark in the following thread. + + http://thread.gmane.org/gmane.linux.ide/34748 + +Signed-off-by: Tejun Heo +Cc: John Clark +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 4 +++- + include/linux/libata.h | 2 ++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -4036,6 +4036,7 @@ static const struct ata_blacklist_entry + + /* Weird ATAPI devices */ + { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, ++ { "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA }, + + /* Devices we expect to fail diagnostics */ + +@@ -4519,7 +4520,8 @@ int atapi_check_dma(struct ata_queued_cm + /* Don't allow DMA if it isn't multiple of 16 bytes. Quite a + * few ATAPI devices choke on such DMA requests. + */ +- if (unlikely(qc->nbytes & 15)) ++ if (!(qc->dev->horkage & ATA_HORKAGE_ATAPI_MOD16_DMA) && ++ unlikely(qc->nbytes & 15)) + return 1; + + if (ap->ops->check_atapi_dma) +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -372,6 +372,8 @@ enum { + ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ + ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ + ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */ ++ ATA_HORKAGE_ATAPI_MOD16_DMA = (1 << 11), /* use ATAPI DMA for commands ++ not multiple of 16 bytes */ + ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firwmare update warning */ + + /* DMA mask for user DMA control: User visible values; DO NOT diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-add-waits-for-govault b/src/patches/suse-2.6.27.31/patches.drivers/libata-add-waits-for-govault new file mode 100644 index 000000000..ca5191dd2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-add-waits-for-govault @@ -0,0 +1,36 @@ +From: Tejun Heo +Date: Wed, 7 Feb 2007 12:37:41 -0800 +Subject: [PATCH] libata: add waits for GoVault +References: 246451 + +Iomega GoVault drives need specific waits here and there. Upstream +approach hasn't been determined yet. This is temp solution from Gary +Hade. Read the following thread for details. + +http://thread.gmane.org/gmane.linux.ide/14545/focus=14663 + +With recent changes in the reset sequence (ATA_TMOUT_FF_WAIT and +prefer-hardreset), the only thing which needs adjustment is +ATA_TMOUT_FF_WAIT (the prereset wait part is unnecessary as the wait +is necessary only for softreset when SCR registers are accessible and +in those cases libata now always uses hardreset which doesn't require +such wait). + +Signed-off-by: Tejun Heo +--- + include/linux/libata.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.27/include/linux/libata.h +=================================================================== +--- linux-2.6.27.orig/include/linux/libata.h ++++ linux-2.6.27/include/linux/libata.h +@@ -250,7 +250,7 @@ enum { + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ +- ATA_TMOUT_FF_WAIT = 800, ++ ATA_TMOUT_FF_WAIT = 2000, + + /* Spec mandates to wait for ">= 2ms" before checking status + * after reset. We wait 150ms, because that was the magic diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-Withdraw-IGN_SERR_INTERNAL-for-SB800 b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-Withdraw-IGN_SERR_INTERNAL-for-SB800 new file mode 100644 index 000000000..27f8276c3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-Withdraw-IGN_SERR_INTERNAL-for-SB800 @@ -0,0 +1,52 @@ +From e427fe042cf90c0652eed9a85e57a8fd8af89890 Mon Sep 17 00:00:00 2001 +From: Shane Huang +Date: Tue, 30 Dec 2008 10:53:41 +0800 +Subject: ahci: Withdraw IGN_SERR_INTERNAL for SB800 SATA +References: bnc#449873 + +There is an issue in ATI SB600/SB700 SATA that PxSERR.E should not be +set on some conditions, which will lead to many SATA ODD error messages. +commit 55a61604cd1354e1783364e1c901034f2f474b7d is the workaround. +Since SB800 fixed this HW issue, IGN_SERR_INTERNAL should be withdrawn +for SB800. + +Signed-off-by: Shane Huang +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/ahci.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +@@ -95,7 +95,7 @@ enum { + board_ahci_ign_iferr = 2, + board_ahci_sb600 = 3, + board_ahci_mv = 4, +- board_ahci_sb700 = 5, ++ board_ahci_sb700 = 5, /* for SB700 and SB800 */ + board_ahci_mcp65 = 6, + board_ahci_nopmp = 7, + +@@ -428,7 +428,7 @@ static const struct ata_port_info ahci_p + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, +- /* board_ahci_sb700 */ ++ /* board_ahci_sb700, for SB700 and SB800 */ + { + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), + .flags = AHCI_FLAG_COMMON, +@@ -2631,6 +2631,10 @@ static int ahci_init_one(struct pci_dev + (pdev->revision == 0xa1 || pdev->revision == 0xa2)) + hpriv->flags |= AHCI_HFLAG_NO_MSI; + ++ /* SB800 does NOT need the workaround to ignore SERR_INTERNAL */ ++ if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) ++ hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; ++ + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) + pci_intx(pdev, 1); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-blacklist-double-spin-off b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-blacklist-double-spin-off new file mode 100644 index 000000000..e034f3f53 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-blacklist-double-spin-off @@ -0,0 +1,76 @@ +From 60d90dc8151413ae21bc6adcf0cfd995628ae87f Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Mon, 3 Nov 2008 19:01:05 +0900 +Subject: [PATCH] SATA AHCI: Blacklist system that spins off disks during ACPI power off +References: bnc#441721 + +Some notebooks from HP have the problem that their BIOSes attempt to +spin down hard drives before entering ACPI system states S4 and S5. +This leads to a yo-yo effect during system power-off shutdown and the +last phase of hibernation when the disk is first spun down by the +kernel and then almost immediately turned on and off by the BIOS. +This, in turn, may result in shortening the disk's life times. + +To prevent this from happening we can blacklist the affected systems +using DMI information. + +Blacklist HP nx6310 that uses the AHCI driver. + +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 32 ++++++++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +Index: linux-2.6.27/drivers/ata/ahci.c +=================================================================== +--- linux-2.6.27.orig/drivers/ata/ahci.c ++++ linux-2.6.27/drivers/ata/ahci.c +@@ -2528,6 +2528,32 @@ static void ahci_p5wdh_workaround(struct + } + } + ++static bool ahci_broken_system_poweroff(struct pci_dev *pdev) ++{ ++ static const struct dmi_system_id broken_systems[] = { ++ { ++ .ident = "HP Compaq nx6310", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"), ++ }, ++ /* PCI slot number of the controller */ ++ .driver_data = (void *)0x1FUL, ++ }, ++ ++ { } /* terminate list */ ++ }; ++ const struct dmi_system_id *dmi = dmi_first_match(broken_systems); ++ ++ if (dmi) { ++ unsigned long slot = (unsigned long)dmi->driver_data; ++ /* apply the quirk only to on-board controllers */ ++ return slot == PCI_SLOT(pdev->devfn); ++ } ++ ++ return false; ++} ++ + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + { + static int printed_version; +@@ -2623,6 +2649,12 @@ static int ahci_init_one(struct pci_dev + } + } + ++ if (ahci_broken_system_poweroff(pdev)) { ++ pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN; ++ dev_info(&pdev->dev, ++ "quirky BIOS, skipping spindown on poweroff\n"); ++ } ++ + /* CAP.NP sometimes indicate the index of the last enabled + * port, at other times, that of the last possible port, so + * determining the maximum port number requires looking at diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-correct-enclosure-LED-state-save b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-correct-enclosure-LED-state-save new file mode 100644 index 000000000..670308408 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-correct-enclosure-LED-state-save @@ -0,0 +1,39 @@ +From 208f2a886a2f6cf329c9fcbf8d29a0dd245cc763 Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Fri, 20 Mar 2009 14:14:23 -0500 +Subject: ahci: correct enclosure LED state save +References: bnc#489005 + +ahci_transmit_led_message saves off the led_state +with a value that includes the port number OR'd +in, this incorrect value maybe reported back +in ahci_led_store. + +For instance, if you turn off all the leds for +port 1 and cat the value back it will report 1 +instead of 0. + +# echo 0 > /sys/class/scsi_host/host1/em_message +# cat /sys/class/scsi_host/host1/em_message +1 + +Signed-off-by: David Milburn +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/ahci.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +@@ -1325,7 +1325,7 @@ static ssize_t ahci_transmit_led_message + writel(message[1], mmio + hpriv->em_loc+4); + + /* save off new led state for port/slot */ +- emp->led_state = message[1]; ++ emp->led_state = state; + + /* + * tell hardware to transmit the message diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-enclosure-management-bios-workaround b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-enclosure-management-bios-workaround new file mode 100644 index 000000000..18aa069f4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-enclosure-management-bios-workaround @@ -0,0 +1,71 @@ +From 4c1e9aa41b2f9afe8f26e2efe5bb4695f6c40772 Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Fri, 3 Apr 2009 15:36:41 -0500 +Subject: libata: ahci enclosure management bios workaround +References: bnc#489005 + +During driver initialization ahci_start_port may not be able +to turn LEDs off because the hardware may still be transmitting +a message. And since the BIOS may not be setting the LEDs to +off the drive LEDs may end up in a fault state. This has +been seen on ICH9r and ICH10r when configured in AHCI mode +instead of RAID mode, this patch doesn't key off a specific +set of device IDs but will give the EM transmit bit a chance +to clear if busy. + +Signed-off-by: David Milburn +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/ahci.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +@@ -62,6 +62,7 @@ static ssize_t ahci_led_store(struct ata + static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, + ssize_t size); + #define MAX_SLOTS 8 ++#define MAX_RETRY 15 + + enum { + AHCI_PCI_BAR = 5, +@@ -1095,6 +1096,8 @@ static void ahci_start_port(struct ata_p + struct ahci_port_priv *pp = ap->private_data; + struct ata_link *link; + struct ahci_em_priv *emp; ++ ssize_t rc; ++ int i; + + /* enable FIS reception */ + ahci_start_fis_rx(ap); +@@ -1106,7 +1109,17 @@ static void ahci_start_port(struct ata_p + if (ap->flags & ATA_FLAG_EM) { + ata_port_for_each_link(link, ap) { + emp = &pp->em_priv[link->pmp]; +- ahci_transmit_led_message(ap, emp->led_state, 4); ++ ++ /* EM Transmit bit maybe busy during init */ ++ for (i = 0; i < MAX_RETRY; i++) { ++ rc = ahci_transmit_led_message(ap, ++ emp->led_state, ++ 4); ++ if (rc == -EBUSY) ++ udelay(100); ++ else ++ break; ++ } + } + } + +@@ -1308,7 +1321,7 @@ static ssize_t ahci_transmit_led_message + em_ctl = readl(mmio + HOST_EM_CTL); + if (em_ctl & EM_CTL_TM) { + spin_unlock_irqrestore(ap->lock, flags); +- return -EINVAL; ++ return -EBUSY; + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-sb600-srst-workaround-soften-msg b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-sb600-srst-workaround-soften-msg new file mode 100644 index 000000000..ab4632548 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ahci-sb600-srst-workaround-soften-msg @@ -0,0 +1,31 @@ +Subject: ahci: soften up the dmesg on SB600 PMP softreset failure recovery +From: Shane Huang +References: bnc#527748 + +Too strong words led to spurious bug reports: Novell bugzilla #527748, +RedHat bugzilla #468800. This patch is used to soften up the dmesg on +SB600 PMP softreset failure recovery, so as to remove the scariness and +concern from community. + +Reported-by: pgnet Dev +Signed-off-by: Shane Huang +Cc: Tejun Heo +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/ahci.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/ahci.c +@@ -1735,7 +1735,8 @@ static int ahci_sb600_softreset(struct a + irq_sts = readl(port_mmio + PORT_IRQ_STAT); + if (irq_sts & PORT_IRQ_BAD_PMP) { + ata_link_printk(link, KERN_WARNING, +- "failed due to HW bug, retry pmp=0\n"); ++ "applying SB600 PMP SRST workaround " ++ "and retrying\n"); + rc = ahci_do_softreset(link, class, 0, deadline, + ahci_check_ready); + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-Hercules-EC-900-mini-to-laptop-tbl b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-Hercules-EC-900-mini-to-laptop-tbl new file mode 100644 index 000000000..2f17145b4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-Hercules-EC-900-mini-to-laptop-tbl @@ -0,0 +1,22 @@ +From d09addf65cb5b3b19a536aa3329efeedbc6bb56c Mon Sep 17 00:00:00 2001 +From: Herton Ronaldo Krzesinski +Date: Wed, 17 Sep 2008 14:29:05 -0300 +Subject: [PATCH] ata_piix: add Hercules EC-900 mini-notebook to ich_laptop short cable list + +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -587,6 +587,7 @@ static const struct ich_laptop ich_lapto + { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ + { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ + { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ ++ { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */ + { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-VGN-BX297XP-to-broken-suspend-list b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-VGN-BX297XP-to-broken-suspend-list new file mode 100644 index 000000000..a312ac13b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-VGN-BX297XP-to-broken-suspend-list @@ -0,0 +1,36 @@ +From: Tejun Heo +Subject: ata_piix: VGN-BX297XP wants the controller power up on suspend +References: bko#10293, bnc#490517 + +Sony VGN-BX297XP fails suspend if the controller is powered down when +calling into ACPI suspend. Add the machine to piix_broken_suspend +list. + +This problem was reported by GNUtoo@no-log.org on bko#10293. + +Signed-off-by: Tejun Heo +Cc: Rafael J. Wysocki +Reported-by: GNUtoo@no-log.org +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/ata_piix.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/ata_piix.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/ata_piix.c +@@ -1104,6 +1104,13 @@ static int piix_broken_suspend(void) + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"), + }, + }, ++ { ++ .ident = "VGN-BX297XP", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-BX297XP"), ++ }, ++ }, + + { } /* terminate list */ + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-intel-ibex-pci-ids b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-intel-ibex-pci-ids new file mode 100644 index 000000000..191338b31 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-add-intel-ibex-pci-ids @@ -0,0 +1,38 @@ +From 0395e61babd59c749fb5efe112affbfaa7d50eb7 Mon Sep 17 00:00:00 2001 +From: Seth Heasley +Date: Wed, 27 Aug 2008 16:40:06 -0700 +Subject: [PATCH] ata_piix: IDE Mode SATA patch for Intel Ibex Peak DeviceIDs + +This patch updates the Intel Ibex Peak (PCH) IDE mode SATA Controller DeviceIDs. + +Signed-off-by: Seth Heasley +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 5 ++++- + 1 files changed, 4 insertions(+), 1 deletions(-) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index c7db1dc..e9e32ed 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -280,12 +280,15 @@ static const struct pci_device_id piix_pci_tbl[] = { + /* SATA Controller IDE (PCH) */ + { 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (PCH) */ ++ { 0x8086, 0x3b21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, ++ /* SATA Controller IDE (PCH) */ + { 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (PCH) */ ++ { 0x8086, 0x3b28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, ++ /* SATA Controller IDE (PCH) */ + { 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (PCH) */ + { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, +- + { } /* terminate list */ + }; + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-blacklist-double-spin-off b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-blacklist-double-spin-off new file mode 100644 index 000000000..e5165a893 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-blacklist-double-spin-off @@ -0,0 +1,76 @@ +From 6cb195762fb4acc79ab5153452be5d44a40419dc Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Mon, 3 Nov 2008 19:01:07 +0900 +Subject: [PATCH] SATA PIIX: Blacklist system that spins off disks during ACPI power off +References: bnc#441721 + +Some notebooks from HP have the problem that their BIOSes attempt to +spin down hard drives before entering ACPI system states S4 and S5. +This leads to a yo-yo effect during system power-off shutdown and the +last phase of hibernation when the disk is first spun down by the +kernel and then almost immediately turned on and off by the BIOS. +This, in turn, may result in shortening the disk's life times. + +To prevent this from happening we can blacklist the affected systems +using DMI information. + +Blacklist HP 2510p that uses the ata_piix driver. + +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -1409,6 +1409,32 @@ static void piix_iocfg_bit18_quirk(struc + } + } + ++static bool piix_broken_system_poweroff(struct pci_dev *pdev) ++{ ++ static const struct dmi_system_id broken_systems[] = { ++ { ++ .ident = "HP Compaq 2510p", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 2510p"), ++ }, ++ /* PCI slot number of the controller */ ++ .driver_data = (void *)0x1FUL, ++ }, ++ ++ { } /* terminate list */ ++ }; ++ const struct dmi_system_id *dmi = dmi_first_match(broken_systems); ++ ++ if (dmi) { ++ unsigned long slot = (unsigned long)dmi->driver_data; ++ /* apply the quirk only to on-board controllers */ ++ return slot == PCI_SLOT(pdev->devfn); ++ } ++ ++ return false; ++} ++ + /** + * piix_init_one - Register PIIX ATA PCI device with kernel services + * @pdev: PCI device to register +@@ -1444,6 +1470,14 @@ static int __devinit piix_init_one(struc + if (!in_module_init) + return -ENODEV; + ++ if (piix_broken_system_poweroff(pdev)) { ++ piix_port_info[ent->driver_data].flags |= ++ ATA_FLAG_NO_POWEROFF_SPINDOWN | ++ ATA_FLAG_NO_HIBERNATE_SPINDOWN; ++ dev_info(&pdev->dev, "quirky BIOS, skipping spindown " ++ "on poweroff and hibernation\n"); ++ } ++ + port_info[0] = piix_port_info[ent->driver_data]; + port_info[1] = piix_port_info[ent->driver_data]; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-borked-tecra-m4-broken-suspend b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-borked-tecra-m4-broken-suspend new file mode 100644 index 000000000..e3000a7e4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-borked-tecra-m4-broken-suspend @@ -0,0 +1,54 @@ +From: Tejun Heo +Subject: ata_piix: add borked Tecra M4 to broken suspend list +References: bnc#398270 + +Tecra M4 sometimes forget what it is and reports bogus data via DMI +which makes the machine evade broken suspend matching and thus fail +suspend/resume. This patch updates piix_broken_suspend() such that it +can match such case. As the borked DMI data is a bit generic, +matching many entries to make the match more specific is necessary. +As the usual DMI matching is limited to four entries, this patch uses +hard coded manual matching. + +This is reported by Alexandru Romanescu. + +Signed-off-by: Tejun Heo +Cc: Alexandru Romanescu +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +Index: linux-2.6.27/drivers/ata/ata_piix.c +=================================================================== +--- linux-2.6.27.orig/drivers/ata/ata_piix.c ++++ linux-2.6.27/drivers/ata/ata_piix.c +@@ -1119,6 +1119,28 @@ static int piix_broken_suspend(void) + if (dmi_find_device(DMI_DEV_TYPE_OEM_STRING, oemstrs[i], NULL)) + return 1; + ++ /* TECRA M4 sometimes forgets its identify and reports bogus ++ * DMI information. As the bogus information is a bit ++ * generic, match as many entries as possible. This manual ++ * matching is necessary because dmi_system_id.matches is ++ * limited to four entries. ++ */ ++ if (dmi_get_system_info(DMI_SYS_VENDOR) && ++ dmi_get_system_info(DMI_PRODUCT_NAME) && ++ dmi_get_system_info(DMI_PRODUCT_VERSION) && ++ dmi_get_system_info(DMI_PRODUCT_SERIAL) && ++ dmi_get_system_info(DMI_BOARD_VENDOR) && ++ dmi_get_system_info(DMI_BOARD_NAME) && ++ dmi_get_system_info(DMI_BOARD_VERSION) && ++ !strcmp(dmi_get_system_info(DMI_SYS_VENDOR), "TOSHIBA") && ++ !strcmp(dmi_get_system_info(DMI_PRODUCT_NAME), "000000") && ++ !strcmp(dmi_get_system_info(DMI_PRODUCT_VERSION), "000000") && ++ !strcmp(dmi_get_system_info(DMI_PRODUCT_SERIAL), "000000") && ++ !strcmp(dmi_get_system_info(DMI_BOARD_VENDOR), "TOSHIBA") && ++ !strcmp(dmi_get_system_info(DMI_BOARD_NAME), "Portable PC") && ++ !strcmp(dmi_get_system_info(DMI_BOARD_VERSION), "Version A0")) ++ return 1; ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-clear-spurious-IRQ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-clear-spurious-IRQ new file mode 100644 index 000000000..2282b48b5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-clear-spurious-IRQ @@ -0,0 +1,85 @@ +From: Tejun Heo +Subject: ata_piix: detect and clear spurious IRQs +References: bnc#445872 + +The DMA_IRQ bit in the bmdma status register is always set when IDEIRQ +is asserted allowing spurious IRQ detection. Detect spurious IRQs and +clear them. This protects ata_piix against nobody-cared which gets +reported not so rarely. + +Signed-off-by: Tejun Heo +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 53 insertions(+), 1 deletion(-) + +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -923,6 +923,58 @@ static int piix_sidpr_scr_read(struct at + return 0; + } + ++static irqreturn_t piix_interrupt(int irq, void *dev_instance) ++{ ++ struct ata_host *host = dev_instance; ++ unsigned int i; ++ unsigned int handled = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ for (i = 0; i < host->n_ports; i++) { ++ struct ata_port *ap = host->ports[i]; ++ struct ata_queued_cmd *qc; ++ u8 host_stat; ++ ++ if (ata_port_is_dummy(ap)) ++ continue; ++ ++ qc = ata_qc_from_tag(ap, ap->link.active_tag); ++ if (qc && !(qc->tf.flags & ATA_TFLAG_POLLING)) { ++ handled |= ata_sff_host_intr(ap, qc); ++ continue; ++ } ++ ++ /* ++ * Control reaches here if HSM is not expecting IRQ. ++ * If the controller is actually asserting IRQ line, ++ * this will lead to nobody cared. Fortuantely, ++ * DMA_INTR of PIIX is set whenever IDEIRQ is set so ++ * it can be used to detect spurious IRQs. As the ++ * driver is not expecting IRQ at all, clearing IRQ ++ * here won't lead to loss of IRQ event. ++ */ ++ if (unlikely(!ap->ioaddr.bmdma_addr)) ++ continue; ++ ++ host_stat = ap->ops->bmdma_status(ap); ++ if (!(host_stat & ATA_DMA_INTR)) ++ continue; ++ ++ if (printk_ratelimit()) ++ ata_port_printk(ap, KERN_INFO, ++ "clearing spurious IRQ\n"); ++ ap->ops->sff_check_status(ap); ++ ap->ops->sff_irq_clear(ap); ++ handled |= 1; ++ } ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ return IRQ_RETVAL(handled); ++} ++ + static int piix_sidpr_scr_write(struct ata_link *link, + unsigned int reg, u32 val) + { +@@ -1543,7 +1595,7 @@ static int __devinit piix_init_one(struc + } + + pci_set_master(pdev); +- return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); ++ return ata_pci_sff_activate_host(host, piix_interrupt, &piix_sht); + } + + static int __init piix_init(void) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-use-slave_link b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-use-slave_link new file mode 100644 index 000000000..f8f8dfce3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-use-slave_link @@ -0,0 +1,279 @@ +From be77e43abb433c2d6f2fc69352289e34dcbf040a Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 31 Jul 2008 17:02:44 +0900 +Subject: [PATCH] ata_piix: drop merged SCR access and use slave_link instead +References: bnc#441420 + +Now that libata has slave_link, there's no need to keep ugly merged +SCR access. Drop it and use slave_link instead. This results in +simpler code and much better separate link handling for master and +slave. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ata_piix.c | 168 +++++++++++-------------------------------------- + 1 file changed, 41 insertions(+), 127 deletions(-) + +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -887,23 +887,9 @@ static void ich_set_dmamode(struct ata_p + * Serial ATA Index/Data Pair Superset Registers access + * + * Beginning from ICH8, there's a sane way to access SCRs using index +- * and data register pair located at BAR5. This creates an +- * interesting problem of mapping two SCRs to one port. +- * +- * Although they have separate SCRs, the master and slave aren't +- * independent enough to be treated as separate links - e.g. softreset +- * resets both. Also, there's no protocol defined for hard resetting +- * singled device sharing the virtual port (no defined way to acquire +- * device signature). This is worked around by merging the SCR values +- * into one sensible value and requesting follow-up SRST after +- * hardreset. +- * +- * SCR merging is perfomed in nibbles which is the unit contents in +- * SCRs are organized. If two values are equal, the value is used. +- * When they differ, merge table which lists precedence of possible +- * values is consulted and the first match or the last entry when +- * nothing matches is used. When there's no merge table for the +- * specific nibble, value from the first port is used. ++ * and data register pair located at BAR5 which means that we have ++ * separate SCRs for master and slave. This is handled using libata ++ * slave_link facility. + */ + static const int piix_sidx_map[] = { + [SCR_STATUS] = 0, +@@ -911,125 +897,38 @@ static const int piix_sidx_map[] = { + [SCR_CONTROL] = 1, + }; + +-static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg) ++static void piix_sidpr_sel(struct ata_link *link, unsigned int reg) + { +- struct ata_port *ap = dev->link->ap; ++ struct ata_port *ap = link->ap; + struct piix_host_priv *hpriv = ap->host->private_data; + +- iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg], ++ iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg], + hpriv->sidpr + PIIX_SIDPR_IDX); + } + +-static int piix_sidpr_read(struct ata_device *dev, unsigned int reg) +-{ +- struct piix_host_priv *hpriv = dev->link->ap->host->private_data; +- +- piix_sidpr_sel(dev, reg); +- return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); +-} +- +-static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val) +-{ +- struct piix_host_priv *hpriv = dev->link->ap->host->private_data; +- +- piix_sidpr_sel(dev, reg); +- iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); +-} +- +-static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl) +-{ +- u32 val = 0; +- int i, mi; +- +- for (i = 0, mi = 0; i < 32 / 4; i++) { +- u8 c0 = (val0 >> (i * 4)) & 0xf; +- u8 c1 = (val1 >> (i * 4)) & 0xf; +- u8 merged = c0; +- const int *cur; +- +- /* if no merge preference, assume the first value */ +- cur = merge_tbl[mi]; +- if (!cur) +- goto done; +- mi++; +- +- /* if two values equal, use it */ +- if (c0 == c1) +- goto done; +- +- /* choose the first match or the last from the merge table */ +- while (*cur != -1) { +- if (c0 == *cur || c1 == *cur) +- break; +- cur++; +- } +- if (*cur == -1) +- cur--; +- merged = *cur; +- done: +- val |= merged << (i * 4); +- } +- +- return val; +-} +- + static int piix_sidpr_scr_read(struct ata_link *link, + unsigned int reg, u32 *val) + { +- struct ata_port *ap = link->ap; +- const int * const sstatus_merge_tbl[] = { +- /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 }, +- /* SPD */ (const int []){ 2, 1, 0, -1 }, +- /* IPM */ (const int []){ 6, 2, 1, 0, -1 }, +- NULL, +- }; +- const int * const scontrol_merge_tbl[] = { +- /* DET */ (const int []){ 1, 0, 4, 0, -1 }, +- /* SPD */ (const int []){ 0, 2, 1, 0, -1 }, +- /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 }, +- NULL, +- }; +- u32 v0, v1; ++ struct piix_host_priv *hpriv = link->ap->host->private_data; + + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + +- if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) { +- *val = piix_sidpr_read(&ap->link.device[0], reg); +- return 0; +- } +- +- v0 = piix_sidpr_read(&ap->link.device[0], reg); +- v1 = piix_sidpr_read(&ap->link.device[1], reg); +- +- switch (reg) { +- case SCR_STATUS: +- *val = piix_merge_scr(v0, v1, sstatus_merge_tbl); +- break; +- case SCR_ERROR: +- *val = v0 | v1; +- break; +- case SCR_CONTROL: +- *val = piix_merge_scr(v0, v1, scontrol_merge_tbl); +- break; +- } +- ++ piix_sidpr_sel(link, reg); ++ *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); + return 0; + } + + static int piix_sidpr_scr_write(struct ata_link *link, + unsigned int reg, u32 val) + { +- struct ata_port *ap = link->ap; ++ struct piix_host_priv *hpriv = link->ap->host->private_data; + + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + +- piix_sidpr_write(&ap->link.device[0], reg, val); +- +- if (ap->flags & ATA_FLAG_SLAVE_POSS) +- piix_sidpr_write(&ap->link.device[1], reg, val); +- ++ piix_sidpr_sel(link, reg); ++ iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); + return 0; + } + +@@ -1403,32 +1302,33 @@ static bool piix_no_sidpr(struct ata_hos + return false; + } + +-static void __devinit piix_init_sidpr(struct ata_host *host) ++static int __devinit piix_init_sidpr(struct ata_host *host) + { + struct pci_dev *pdev = to_pci_dev(host->dev); + struct piix_host_priv *hpriv = host->private_data; +- struct ata_device *dev0 = &host->ports[0]->link.device[0]; ++ struct ata_link *link0 = &host->ports[0]->link; + u32 scontrol; + int i; ++ int rc; + + /* check for availability */ + for (i = 0; i < 4; i++) + if (hpriv->map[i] == IDE) +- return; ++ return 0; + + /* is it blacklisted? */ + if (piix_no_sidpr(host)) +- return; ++ return 0; + + if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) +- return; ++ return 0; + + if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 || + pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN) +- return; ++ return 0; + + if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME)) +- return; ++ return 0; + + hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR]; + +@@ -1436,7 +1336,7 @@ static void __devinit piix_init_sidpr(st + * Give it a test drive by inhibiting power save modes which + * we'll do anyway. + */ +- scontrol = piix_sidpr_read(dev0, SCR_CONTROL); ++ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol); + + /* if IPM is already 3, SCR access is probably working. Don't + * un-inhibit power save modes as BIOS might have inhibited +@@ -1444,18 +1344,30 @@ static void __devinit piix_init_sidpr(st + */ + if ((scontrol & 0xf00) != 0x300) { + scontrol |= 0x300; +- piix_sidpr_write(dev0, SCR_CONTROL, scontrol); +- scontrol = piix_sidpr_read(dev0, SCR_CONTROL); ++ piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol); ++ piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol); + + if ((scontrol & 0xf00) != 0x300) { + dev_printk(KERN_INFO, host->dev, "SCR access via " + "SIDPR is available but doesn't work\n"); +- return; ++ return 0; + } + } + +- host->ports[0]->ops = &piix_sidpr_sata_ops; +- host->ports[1]->ops = &piix_sidpr_sata_ops; ++ /* okay, SCRs available, set ops and ask libata for slave_link */ ++ for (i = 0; i < 2; i++) { ++ struct ata_port *ap = host->ports[i]; ++ ++ ap->ops = &piix_sidpr_sata_ops; ++ ++ if (ap->flags & ATA_FLAG_SLAVE_POSS) { ++ rc = ata_slave_link_init(ap); ++ if (rc) ++ return rc; ++ } ++ } ++ ++ return 0; + } + + static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) +@@ -1565,7 +1477,9 @@ static int __devinit piix_init_one(struc + /* initialize controller */ + if (port_flags & ATA_FLAG_SATA) { + piix_init_pcs(host, piix_map_db_table[ent->driver_data]); +- piix_init_sidpr(host); ++ rc = piix_init_sidpr(host); ++ if (rc) ++ return rc; + } + + /* apply IOCFG bit18 quirk */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-clear-ering-on-resume b/src/patches/suse-2.6.27.31/patches.drivers/libata-clear-ering-on-resume new file mode 100644 index 000000000..07650bd48 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-clear-ering-on-resume @@ -0,0 +1,47 @@ +From: Tejun Heo +Subject: libata: clear ering on resume +References: bnc#486803 + +Error timestamps are in jiffies which doesn't run while suspended and +PHY events during resume isn't too uncommon. When the two are +combined, it can lead to unnecessary speed downs if the machine is +suspended and resumed repeatedly. Clear error history on resume. + +This was reported and verified in bnc#486803 by Vladimir Botka. + +Signed-off-by: Tejun Heo +Reported-by: Vladimir Botka +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-eh.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -3158,6 +3158,8 @@ static void ata_eh_handle_port_suspend(s + */ + static void ata_eh_handle_port_resume(struct ata_port *ap) + { ++ struct ata_link *link; ++ struct ata_device *dev; + unsigned long flags; + int rc = 0; + +@@ -3172,6 +3174,17 @@ static void ata_eh_handle_port_resume(st + + WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED)); + ++ /* ++ * Error timestamps are in jiffies which doesn't run while ++ * suspended and PHY events during resume isn't too uncommon. ++ * When the two are combined, it can lead to unnecessary speed ++ * downs if the machine is suspended and resumed repeatedly. ++ * Clear error history. ++ */ ++ ata_port_for_each_link(link, ap) ++ ata_link_for_each_dev(dev, link) ++ ata_ering_clear(&dev->ering); ++ + ata_acpi_set_state(ap, PMSG_ON); + + if (ap->ops->port_resume) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-dont-restore-DET-on-detach b/src/patches/suse-2.6.27.31/patches.drivers/libata-dont-restore-DET-on-detach new file mode 100644 index 000000000..7caf356b6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-dont-restore-DET-on-detach @@ -0,0 +1,26 @@ +From: Tejun Heo +Subject: libata: mask off DET when restoring SControl for detach +References: bnc#440980 + +libata restores SControl on detach; however, trying to restore +non-zero DET can cause undeterministic behavior including PMP device +going offline till power cycling. Mask off DET when restoring +SControl. + +Signed-off-by: Tejun Heo +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -5874,7 +5874,7 @@ static void ata_port_detach(struct ata_p + * to us. Restore SControl and disable all existing devices. + */ + __ata_port_for_each_link(link, ap) { +- sata_scr_write(link, SCR_CONTROL, link->saved_scontrol); ++ sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0); + ata_link_for_each_dev(dev, link) + ata_dev_disable(dev); + } diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-eh-fix-slave-link-EH-action-mask-handling b/src/patches/suse-2.6.27.31/patches.drivers/libata-eh-fix-slave-link-EH-action-mask-handling new file mode 100644 index 000000000..a716d807d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-eh-fix-slave-link-EH-action-mask-handling @@ -0,0 +1,35 @@ +From a568d1d2e2aff4f114b087c06bfd350e945ad6cf Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Tue, 21 Oct 2008 20:37:21 +0900 +Subject: [PATCH] libata-eh: fix slave link EH action mask handling +References: bnc#441420 + +Slave link action mask is transferred to master link and all the EH +actions are taken by the master link. ata_eh_about_to_do() and +ata_eh_done() are called with ATA_EH_ALL_ACTIONS to clear the slave +link actions during transfer. This always sets ATA_PFLAG_RECOVERED +flag causing spurious "EH complete" messages. + +Don't set ATA_PFLAG_RECOVERED for slave link actions. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-eh.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -1200,7 +1200,10 @@ void ata_eh_about_to_do(struct ata_link + + ata_eh_clear_action(link, dev, ehi, action); + +- if (!(ehc->i.flags & ATA_EHI_QUIET)) ++ /* About to take EH action, set RECOVERED. Ignore actions on ++ * slave links as master will do them again. ++ */ ++ if (!(ehc->i.flags & ATA_EHI_QUIET) && link != ap->slave_link) + ap->pflags |= ATA_PFLAG_RECOVERED; + + spin_unlock_irqrestore(ap->lock, flags); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-implement-NO_SPINDOWN b/src/patches/suse-2.6.27.31/patches.drivers/libata-implement-NO_SPINDOWN new file mode 100644 index 000000000..920def7e0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-implement-NO_SPINDOWN @@ -0,0 +1,90 @@ +From 8794806469a35ab09378e9ee7ad39da6284cb8ff Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Mon, 3 Nov 2008 19:01:04 +0900 +Subject: [PATCH] SATA: Blacklisting of systems that spin off disks during ACPI power off (rev. 2) +References: bnc#441721 + +Introduce new libata flags ATA_FLAG_NO_POWEROFF_SPINDOWN and +ATA_FLAG_NO_HIBERNATE_SPINDOWN that, if set, will prevent disks from +being spun off during system power off and hibernation, respectively +(to handle the hibernation case we need the new system state +SYSTEM_HIBERNATE_ENTER that can be checked against by libata, in +analogy with SYSTEM_POWER_OFF). + +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-scsi.c | 20 +++++++++++++++++--- + include/linux/libata.h | 2 ++ + 2 files changed, 19 insertions(+), 3 deletions(-) + +Index: linux-2.6.27/drivers/ata/libata-scsi.c +=================================================================== +--- linux-2.6.27.orig/drivers/ata/libata-scsi.c ++++ linux-2.6.27/drivers/ata/libata-scsi.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + + #include "libata.h" + +@@ -1181,6 +1182,17 @@ static unsigned int ata_scsi_start_stop_ + + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ + } else { ++ /* Some odd clown BIOSen issue spindown on power off (ACPI S4 ++ * or S5) causing some drives to spin up and down again. ++ */ ++ if ((qc->ap->flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) && ++ system_state == SYSTEM_POWER_OFF) ++ goto skip; ++ ++ if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) && ++ system_entering_hibernation()) ++ goto skip; ++ + /* XXX: This is for backward compatibility, will be + * removed. Read Documentation/feature-removal-schedule.txt + * for more info. +@@ -1204,8 +1216,7 @@ static unsigned int ata_scsi_start_stop_ + scmd->scsi_done = qc->scsidone; + qc->scsidone = ata_delayed_done; + } +- scmd->result = SAM_STAT_GOOD; +- return 1; ++ goto skip; + } + + /* Issue ATA STANDBY IMMEDIATE command */ +@@ -1221,10 +1232,13 @@ static unsigned int ata_scsi_start_stop_ + + return 0; + +-invalid_fld: ++ invalid_fld: + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; ++ skip: ++ scmd->result = SAM_STAT_GOOD; ++ return 1; + } + + +Index: linux-2.6.27/include/linux/libata.h +=================================================================== +--- linux-2.6.27.orig/include/linux/libata.h ++++ linux-2.6.27/include/linux/libata.h +@@ -186,6 +186,8 @@ enum { + ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD + * doesn't handle PIO interrupts */ + ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ ++ ATA_FLAG_NO_POWEROFF_SPINDOWN = (1 << 11), /* don't spindown before poweroff */ ++ ATA_FLAG_NO_HIBERNATE_SPINDOWN = (1 << 12), /* don't spindown before hibernation */ + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ + ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-implement-slave_link b/src/patches/suse-2.6.27.31/patches.drivers/libata-implement-slave_link new file mode 100644 index 000000000..99221914a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-implement-slave_link @@ -0,0 +1,812 @@ +From b1c72916abbdd0a55015c87358536ca0ebaf6735 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 31 Jul 2008 17:02:43 +0900 +Subject: [PATCH] libata: implement slave_link +References: bnc#441420 + +Explanation taken from the comment of ata_slave_link_init(). + + In libata, a port contains links and a link contains devices. There + is single host link but if a PMP is attached to it, there can be + multiple fan-out links. On SATA, there's usually a single device + connected to a link but PATA and SATA controllers emulating TF based + interface can have two - master and slave. + + However, there are a few controllers which don't fit into this + abstraction too well - SATA controllers which emulate TF interface + with both master and slave devices but also have separate SCR + register sets for each device. These controllers need separate links + for physical link handling (e.g. onlineness, link speed) but should + be treated like a traditional M/S controller for everything else + (e.g. command issue, softreset). + + slave_link is libata's way of handling this class of controllers + without impacting core layer too much. For anything other than + physical link handling, the default host link is used for both master + and slave. For physical link handling, separate @ap->slave_link is + used. All dirty details are implemented inside libata core layer. + From LLD's POV, the only difference is that prereset, hardreset and + postreset are called once more for the slave link, so the reset + sequence looks like the following. + + prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) -> + softreset(M) -> postreset(M) -> postreset(S) + + Note that softreset is called only for the master. Softreset resets + both M/S by definition, so SRST on master should handle both (the + standard method will work just fine). + +As slave_link excludes PMP support and only code paths which deal with +the attributes of physical link are affected, all the changes are +localized to libata.h, libata-core.c and libata-eh.c. + + * ata_is_host_link() updated so that slave_link is considered as host + link too. + + * iterator extended to iterate over the slave_link when using the + underbarred version. + + * force param handling updated such that devno 16 is mapped to the + slave link/device. + + * ata_link_on/offline() updated to return the combined result from + master and slave link. ata_phys_link_on/offline() are the direct + versions. + + * EH autopsy and report are performed separately for master slave + links. Reset is udpated to implement the above described reset + sequence. + +Except for reset update, most changes are minor, many of them just +modifying dev->link to ata_dev_phys_link(dev) or using phys online +test instead. + +After this update, LLDs can take full advantage of per-dev SCR +registers by simply turning on slave link. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 202 ++++++++++++++++++++++++++++++++++++++++------ + drivers/ata/libata-eh.c | 142 ++++++++++++++++++++++++++------ + drivers/ata/libata.h | 3 + include/linux/libata.h | 8 + + 4 files changed, 303 insertions(+), 52 deletions(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -179,13 +179,20 @@ struct ata_link *__ata_port_next_link(st + return &ap->link; + } + +- /* we just iterated over the host link, what's next? */ +- if (ata_is_host_link(link)) { +- if (!sata_pmp_attached(ap)) ++ /* we just iterated over the host master link, what's next? */ ++ if (link == &ap->link) { ++ if (!sata_pmp_attached(ap)) { ++ if (unlikely(ap->slave_link) && !dev_only) ++ return ap->slave_link; + return NULL; ++ } + return ap->pmp_link; + } + ++ /* slave_link excludes PMP */ ++ if (unlikely(link == ap->slave_link)) ++ return NULL; ++ + /* iterate to the next PMP link */ + if (++link < ap->pmp_link + ap->nr_pmp_links) + return link; +@@ -193,6 +200,31 @@ struct ata_link *__ata_port_next_link(st + } + + /** ++ * ata_dev_phys_link - find physical link for a device ++ * @dev: ATA device to look up physical link for ++ * ++ * Look up physical link which @dev is attached to. Note that ++ * this is different from @dev->link only when @dev is on slave ++ * link. For all other cases, it's the same as @dev->link. ++ * ++ * LOCKING: ++ * Don't care. ++ * ++ * RETURNS: ++ * Pointer to the found physical link. ++ */ ++struct ata_link *ata_dev_phys_link(struct ata_device *dev) ++{ ++ struct ata_port *ap = dev->link->ap; ++ ++ if (!ap->slave_link) ++ return dev->link; ++ if (!dev->devno) ++ return &ap->link; ++ return ap->slave_link; ++} ++ ++/** + * ata_force_cbl - force cable type according to libata.force + * @ap: ATA port of interest + * +@@ -235,7 +267,8 @@ void ata_force_cbl(struct ata_port *ap) + * the host link and all fan-out ports connected via PMP. If the + * device part is specified as 0 (e.g. 1.00:), it specifies the + * first fan-out link not the host link. Device number 15 always +- * points to the host link whether PMP is attached or not. ++ * points to the host link whether PMP is attached or not. If the ++ * controller has slave link, device number 16 points to it. + * + * LOCKING: + * EH context. +@@ -243,12 +276,11 @@ void ata_force_cbl(struct ata_port *ap) + static void ata_force_link_limits(struct ata_link *link) + { + bool did_spd = false; +- int linkno, i; ++ int linkno = link->pmp; ++ int i; + + if (ata_is_host_link(link)) +- linkno = 15; +- else +- linkno = link->pmp; ++ linkno += 15; + + for (i = ata_force_tbl_size - 1; i >= 0; i--) { + const struct ata_force_ent *fe = &ata_force_tbl[i]; +@@ -295,9 +327,9 @@ static void ata_force_xfermask(struct at + int alt_devno = devno; + int i; + +- /* allow n.15 for the first device attached to host port */ +- if (ata_is_host_link(dev->link) && devno == 0) +- alt_devno = 15; ++ /* allow n.15/16 for devices attached to host port */ ++ if (ata_is_host_link(dev->link)) ++ alt_devno += 15; + + for (i = ata_force_tbl_size - 1; i >= 0; i--) { + const struct ata_force_ent *fe = &ata_force_tbl[i]; +@@ -349,9 +381,9 @@ static void ata_force_horkage(struct ata + int alt_devno = devno; + int i; + +- /* allow n.15 for the first device attached to host port */ +- if (ata_is_host_link(dev->link) && devno == 0) +- alt_devno = 15; ++ /* allow n.15/16 for devices attached to host port */ ++ if (ata_is_host_link(dev->link)) ++ alt_devno += 15; + + for (i = 0; i < ata_force_tbl_size; i++) { + const struct ata_force_ent *fe = &ata_force_tbl[i]; +@@ -2719,7 +2751,7 @@ static void sata_print_link_status(struc + return; + sata_scr_read(link, SCR_CONTROL, &scontrol); + +- if (ata_link_online(link)) { ++ if (ata_phys_link_online(link)) { + tmp = (sstatus >> 4) & 0xf; + ata_link_printk(link, KERN_INFO, + "SATA link up %s (SStatus %X SControl %X)\n", +@@ -3410,6 +3442,12 @@ int ata_wait_ready(struct ata_link *link + unsigned long nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT); + int warned = 0; + ++ /* Slave readiness can't be tested separately from master. On ++ * M/S emulation configuration, this function should be called ++ * only on the master and it will handle both master and slave. ++ */ ++ WARN_ON(link == link->ap->slave_link); ++ + if (time_after(nodev_deadline, deadline)) + nodev_deadline = deadline; + +@@ -3631,7 +3669,7 @@ int ata_std_prereset(struct ata_link *li + } + + /* no point in trying softreset on offline link */ +- if (ata_link_offline(link)) ++ if (ata_phys_link_offline(link)) + ehc->i.action &= ~ATA_EH_SOFTRESET; + + return 0; +@@ -3709,7 +3747,7 @@ int sata_link_hardreset(struct ata_link + if (rc) + goto out; + /* if link is offline nothing more to do */ +- if (ata_link_offline(link)) ++ if (ata_phys_link_offline(link)) + goto out; + + /* Link is online. From this point, -ENODEV too is an error. */ +@@ -5041,7 +5079,7 @@ int sata_scr_write_flush(struct ata_link + } + + /** +- * ata_link_online - test whether the given link is online ++ * ata_phys_link_online - test whether the given link is online + * @link: ATA link to test + * + * Test whether @link is online. Note that this function returns +@@ -5054,7 +5092,7 @@ int sata_scr_write_flush(struct ata_link + * RETURNS: + * True if the port online status is available and online. + */ +-bool ata_link_online(struct ata_link *link) ++bool ata_phys_link_online(struct ata_link *link) + { + u32 sstatus; + +@@ -5065,7 +5103,7 @@ bool ata_link_online(struct ata_link *li + } + + /** +- * ata_link_offline - test whether the given link is offline ++ * ata_phys_link_offline - test whether the given link is offline + * @link: ATA link to test + * + * Test whether @link is offline. Note that this function +@@ -5078,7 +5116,7 @@ bool ata_link_online(struct ata_link *li + * RETURNS: + * True if the port offline status is available and offline. + */ +-bool ata_link_offline(struct ata_link *link) ++bool ata_phys_link_offline(struct ata_link *link) + { + u32 sstatus; + +@@ -5088,6 +5126,58 @@ bool ata_link_offline(struct ata_link *l + return false; + } + ++/** ++ * ata_link_online - test whether the given link is online ++ * @link: ATA link to test ++ * ++ * Test whether @link is online. This is identical to ++ * ata_phys_link_online() when there's no slave link. When ++ * there's a slave link, this function should only be called on ++ * the master link and will return true if any of M/S links is ++ * online. ++ * ++ * LOCKING: ++ * None. ++ * ++ * RETURNS: ++ * True if the port online status is available and online. ++ */ ++bool ata_link_online(struct ata_link *link) ++{ ++ struct ata_link *slave = link->ap->slave_link; ++ ++ WARN_ON(link == slave); /* shouldn't be called on slave link */ ++ ++ return ata_phys_link_online(link) || ++ (slave && ata_phys_link_online(slave)); ++} ++ ++/** ++ * ata_link_offline - test whether the given link is offline ++ * @link: ATA link to test ++ * ++ * Test whether @link is offline. This is identical to ++ * ata_phys_link_offline() when there's no slave link. When ++ * there's a slave link, this function should only be called on ++ * the master link and will return true if both M/S links are ++ * offline. ++ * ++ * LOCKING: ++ * None. ++ * ++ * RETURNS: ++ * True if the port offline status is available and offline. ++ */ ++bool ata_link_offline(struct ata_link *link) ++{ ++ struct ata_link *slave = link->ap->slave_link; ++ ++ WARN_ON(link == slave); /* shouldn't be called on slave link */ ++ ++ return ata_phys_link_offline(link) && ++ (!slave || ata_phys_link_offline(slave)); ++} ++ + #ifdef CONFIG_PM + static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, + unsigned int action, unsigned int ehi_flags, +@@ -5227,11 +5317,11 @@ int ata_port_start(struct ata_port *ap) + */ + void ata_dev_init(struct ata_device *dev) + { +- struct ata_link *link = dev->link; ++ struct ata_link *link = ata_dev_phys_link(dev); + struct ata_port *ap = link->ap; + unsigned long flags; + +- /* SATA spd limit is bound to the first device */ ++ /* SATA spd limit is bound to the attached device, reset together */ + link->sata_spd_limit = link->hw_sata_spd_limit; + link->sata_spd = 0; + +@@ -5396,6 +5486,7 @@ static void ata_host_release(struct devi + scsi_host_put(ap->scsi_host); + + kfree(ap->pmp_link); ++ kfree(ap->slave_link); + kfree(ap); + host->ports[i] = NULL; + } +@@ -5516,6 +5607,68 @@ struct ata_host *ata_host_alloc_pinfo(st + return host; + } + ++/** ++ * ata_slave_link_init - initialize slave link ++ * @ap: port to initialize slave link for ++ * ++ * Create and initialize slave link for @ap. This enables slave ++ * link handling on the port. ++ * ++ * In libata, a port contains links and a link contains devices. ++ * There is single host link but if a PMP is attached to it, ++ * there can be multiple fan-out links. On SATA, there's usually ++ * a single device connected to a link but PATA and SATA ++ * controllers emulating TF based interface can have two - master ++ * and slave. ++ * ++ * However, there are a few controllers which don't fit into this ++ * abstraction too well - SATA controllers which emulate TF ++ * interface with both master and slave devices but also have ++ * separate SCR register sets for each device. These controllers ++ * need separate links for physical link handling ++ * (e.g. onlineness, link speed) but should be treated like a ++ * traditional M/S controller for everything else (e.g. command ++ * issue, softreset). ++ * ++ * slave_link is libata's way of handling this class of ++ * controllers without impacting core layer too much. For ++ * anything other than physical link handling, the default host ++ * link is used for both master and slave. For physical link ++ * handling, separate @ap->slave_link is used. All dirty details ++ * are implemented inside libata core layer. From LLD's POV, the ++ * only difference is that prereset, hardreset and postreset are ++ * called once more for the slave link, so the reset sequence ++ * looks like the following. ++ * ++ * prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) -> ++ * softreset(M) -> postreset(M) -> postreset(S) ++ * ++ * Note that softreset is called only for the master. Softreset ++ * resets both M/S by definition, so SRST on master should handle ++ * both (the standard method will work just fine). ++ * ++ * LOCKING: ++ * Should be called before host is registered. ++ * ++ * RETURNS: ++ * 0 on success, -errno on failure. ++ */ ++int ata_slave_link_init(struct ata_port *ap) ++{ ++ struct ata_link *link; ++ ++ WARN_ON(ap->slave_link); ++ WARN_ON(ap->flags & ATA_FLAG_PMP); ++ ++ link = kzalloc(sizeof(*link), GFP_KERNEL); ++ if (!link) ++ return -ENOMEM; ++ ++ ata_link_init(ap, link, 1); ++ ap->slave_link = link; ++ return 0; ++} ++ + static void ata_host_stop(struct device *gendev, void *res) + { + struct ata_host *host = dev_get_drvdata(gendev); +@@ -5742,6 +5895,8 @@ int ata_host_register(struct ata_host *h + + /* init sata_spd_limit to the current value */ + sata_link_init_spd(&ap->link); ++ if (ap->slave_link) ++ sata_link_init_spd(ap->slave_link); + + /* print per-port info to dmesg */ + xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, +@@ -6367,6 +6522,7 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param); + EXPORT_SYMBOL_GPL(ata_host_init); + EXPORT_SYMBOL_GPL(ata_host_alloc); + EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); ++EXPORT_SYMBOL_GPL(ata_slave_link_init); + EXPORT_SYMBOL_GPL(ata_host_start); + EXPORT_SYMBOL_GPL(ata_host_register); + EXPORT_SYMBOL_GPL(ata_host_activate); +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -1753,7 +1753,7 @@ static unsigned int ata_eh_speed_down_ve + static unsigned int ata_eh_speed_down(struct ata_device *dev, + unsigned int eflags, unsigned int err_mask) + { +- struct ata_link *link = dev->link; ++ struct ata_link *link = ata_dev_phys_link(dev); + int xfer_ok = 0; + unsigned int verdict; + unsigned int action = 0; +@@ -1877,7 +1877,8 @@ static void ata_eh_link_autopsy(struct a + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + +- if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) ++ if (!(qc->flags & ATA_QCFLAG_FAILED) || ++ ata_dev_phys_link(qc->dev) != link) + continue; + + /* inherit upper level err_mask */ +@@ -1964,6 +1965,23 @@ void ata_eh_autopsy(struct ata_port *ap) + ata_port_for_each_link(link, ap) + ata_eh_link_autopsy(link); + ++ /* Handle the frigging slave link. Autopsy is done similarly ++ * but actions and flags are transferred over to the master ++ * link and handled from there. ++ */ ++ if (ap->slave_link) { ++ struct ata_eh_context *mehc = &ap->link.eh_context; ++ struct ata_eh_context *sehc = &ap->slave_link->eh_context; ++ ++ ata_eh_link_autopsy(ap->slave_link); ++ ++ ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS); ++ mehc->i.action |= sehc->i.action; ++ mehc->i.dev_action[1] |= sehc->i.dev_action[1]; ++ mehc->i.flags |= sehc->i.flags; ++ ata_eh_done(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS); ++ } ++ + /* Autopsy of fanout ports can affect host link autopsy. + * Perform host link autopsy last. + */ +@@ -1998,7 +2016,8 @@ static void ata_eh_link_report(struct at + for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { + struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); + +- if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link || ++ if (!(qc->flags & ATA_QCFLAG_FAILED) || ++ ata_dev_phys_link(qc->dev) != link || + ((qc->flags & ATA_QCFLAG_QUIET) && + qc->err_mask == AC_ERR_DEV)) + continue; +@@ -2065,7 +2084,7 @@ static void ata_eh_link_report(struct at + char cdb_buf[70] = ""; + + if (!(qc->flags & ATA_QCFLAG_FAILED) || +- qc->dev->link != link || !qc->err_mask) ++ ata_dev_phys_link(qc->dev) != link || !qc->err_mask) + continue; + + if (qc->dma_dir != DMA_NONE) { +@@ -2157,12 +2176,14 @@ void ata_eh_report(struct ata_port *ap) + } + + static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, +- unsigned int *classes, unsigned long deadline) ++ unsigned int *classes, unsigned long deadline, ++ bool clear_classes) + { + struct ata_device *dev; + +- ata_link_for_each_dev(dev, link) +- classes[dev->devno] = ATA_DEV_UNKNOWN; ++ if (clear_classes) ++ ata_link_for_each_dev(dev, link) ++ classes[dev->devno] = ATA_DEV_UNKNOWN; + + return reset(link, classes, deadline); + } +@@ -2184,17 +2205,20 @@ int ata_eh_reset(struct ata_link *link, + ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) + { + struct ata_port *ap = link->ap; ++ struct ata_link *slave = ap->slave_link; + struct ata_eh_context *ehc = &link->eh_context; ++ struct ata_eh_context *sehc = &slave->eh_context; + unsigned int *classes = ehc->classes; + unsigned int lflags = link->flags; + int verbose = !(ehc->i.flags & ATA_EHI_QUIET); + int max_tries = 0, try = 0; ++ struct ata_link *failed_link; + struct ata_device *dev; + unsigned long deadline, now; + ata_reset_fn_t reset; + unsigned long flags; + u32 sstatus; +- int nr_known, rc; ++ int nr_unknown, rc; + + /* + * Prepare to reset +@@ -2253,8 +2277,30 @@ int ata_eh_reset(struct ata_link *link, + } + + if (prereset) { +- rc = prereset(link, +- ata_deadline(jiffies, ATA_EH_PRERESET_TIMEOUT)); ++ unsigned long deadline = ata_deadline(jiffies, ++ ATA_EH_PRERESET_TIMEOUT); ++ ++ if (slave) { ++ sehc->i.action &= ~ATA_EH_RESET; ++ sehc->i.action |= ehc->i.action; ++ } ++ ++ rc = prereset(link, deadline); ++ ++ /* If present, do prereset on slave link too. Reset ++ * is skipped iff both master and slave links report ++ * -ENOENT or clear ATA_EH_RESET. ++ */ ++ if (slave && (rc == 0 || rc == -ENOENT)) { ++ int tmp; ++ ++ tmp = prereset(slave, deadline); ++ if (tmp != -ENOENT) ++ rc = tmp; ++ ++ ehc->i.action |= sehc->i.action; ++ } ++ + if (rc) { + if (rc == -ENOENT) { + ata_link_printk(link, KERN_DEBUG, +@@ -2306,25 +2352,51 @@ int ata_eh_reset(struct ata_link *link, + else + ehc->i.flags |= ATA_EHI_DID_SOFTRESET; + +- rc = ata_do_reset(link, reset, classes, deadline); +- if (rc && rc != -EAGAIN) ++ rc = ata_do_reset(link, reset, classes, deadline, true); ++ if (rc && rc != -EAGAIN) { ++ failed_link = link; + goto fail; ++ } ++ ++ /* hardreset slave link if existent */ ++ if (slave && reset == hardreset) { ++ int tmp; ++ ++ if (verbose) ++ ata_link_printk(slave, KERN_INFO, ++ "hard resetting link\n"); ++ ++ ata_eh_about_to_do(slave, NULL, ATA_EH_RESET); ++ tmp = ata_do_reset(slave, reset, classes, deadline, ++ false); ++ switch (tmp) { ++ case -EAGAIN: ++ rc = -EAGAIN; ++ case 0: ++ break; ++ default: ++ failed_link = slave; ++ rc = tmp; ++ goto fail; ++ } ++ } + ++ /* perform follow-up SRST if necessary */ + if (reset == hardreset && + ata_eh_followup_srst_needed(link, rc, classes)) { +- /* okay, let's do follow-up softreset */ + reset = softreset; + + if (!reset) { + ata_link_printk(link, KERN_ERR, + "follow-up softreset required " + "but no softreset avaliable\n"); ++ failed_link = link; + rc = -EINVAL; + goto fail; + } + + ata_eh_about_to_do(link, NULL, ATA_EH_RESET); +- rc = ata_do_reset(link, reset, classes, deadline); ++ rc = ata_do_reset(link, reset, classes, deadline, true); + } + } else { + if (verbose) +@@ -2345,7 +2417,7 @@ int ata_eh_reset(struct ata_link *link, + dev->pio_mode = XFER_PIO_0; + dev->flags &= ~ATA_DFLAG_SLEEPING; + +- if (ata_link_offline(link)) ++ if (ata_phys_link_offline(ata_dev_phys_link(dev))) + continue; + + /* apply class override */ +@@ -2358,6 +2430,8 @@ int ata_eh_reset(struct ata_link *link, + /* record current link speed */ + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) + link->sata_spd = (sstatus >> 4) & 0xf; ++ if (slave && sata_scr_read(slave, SCR_STATUS, &sstatus) == 0) ++ slave->sata_spd = (sstatus >> 4) & 0xf; + + /* thaw the port */ + if (ata_is_host_link(link)) +@@ -2370,12 +2444,17 @@ int ata_eh_reset(struct ata_link *link, + * reset and here. This race is mediated by cross checking + * link onlineness and classification result later. + */ +- if (postreset) ++ if (postreset) { + postreset(link, classes); ++ if (slave) ++ postreset(slave, classes); ++ } + + /* clear cached SError */ + spin_lock_irqsave(link->ap->lock, flags); + link->eh_info.serror = 0; ++ if (slave) ++ slave->eh_info.serror = 0; + spin_unlock_irqrestore(link->ap->lock, flags); + + /* Make sure onlineness and classification result correspond. +@@ -2385,19 +2464,21 @@ int ata_eh_reset(struct ata_link *link, + * link onlineness and classification result, those conditions + * can be reliably detected and retried. + */ +- nr_known = 0; ++ nr_unknown = 0; + ata_link_for_each_dev(dev, link) { + /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */ +- if (classes[dev->devno] == ATA_DEV_UNKNOWN) ++ if (classes[dev->devno] == ATA_DEV_UNKNOWN) { + classes[dev->devno] = ATA_DEV_NONE; +- else +- nr_known++; ++ if (ata_phys_link_online(ata_dev_phys_link(dev))) ++ nr_unknown++; ++ } + } + +- if (classify && !nr_known && ata_link_online(link)) { ++ if (classify && nr_unknown) { + if (try < max_tries) { + ata_link_printk(link, KERN_WARNING, "link online but " + "device misclassified, retrying\n"); ++ failed_link = link; + rc = -EAGAIN; + goto fail; + } +@@ -2408,6 +2489,8 @@ int ata_eh_reset(struct ata_link *link, + + /* reset successful, schedule revalidation */ + ata_eh_done(link, NULL, ATA_EH_RESET); ++ if (slave) ++ ata_eh_done(slave, NULL, ATA_EH_RESET); + ehc->last_reset = jiffies; /* update to completion time */ + ehc->i.action |= ATA_EH_REVALIDATE; + +@@ -2415,6 +2498,8 @@ int ata_eh_reset(struct ata_link *link, + out: + /* clear hotplug flag */ + ehc->i.flags &= ~ATA_EHI_HOTPLUGGED; ++ if (slave) ++ sehc->i.flags &= ~ATA_EHI_HOTPLUGGED; + + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~ATA_PFLAG_RESETTING; +@@ -2435,7 +2520,7 @@ int ata_eh_reset(struct ata_link *link, + if (time_before(now, deadline)) { + unsigned long delta = deadline - now; + +- ata_link_printk(link, KERN_WARNING, ++ ata_link_printk(failed_link, KERN_WARNING, + "reset failed (errno=%d), retrying in %u secs\n", + rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); + +@@ -2443,8 +2528,13 @@ int ata_eh_reset(struct ata_link *link, + delta = schedule_timeout_uninterruptible(delta); + } + +- if (rc == -EPIPE || try == max_tries - 1) ++ if (try == max_tries - 1) { + sata_down_spd_limit(link); ++ if (slave) ++ sata_down_spd_limit(slave); ++ } else if (rc == -EPIPE) ++ sata_down_spd_limit(failed_link); ++ + if (hardreset) + reset = hardreset; + goto retry; +@@ -2476,7 +2566,7 @@ static int ata_eh_revalidate_and_attach( + if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { + WARN_ON(dev->class == ATA_DEV_PMP); + +- if (ata_link_offline(link)) { ++ if (ata_phys_link_offline(ata_dev_phys_link(dev))) { + rc = -EIO; + goto err; + } +@@ -2701,7 +2791,7 @@ static int ata_eh_handle_dev_fail(struct + /* This is the last chance, better to slow + * down than lose it. + */ +- sata_down_spd_limit(dev->link); ++ sata_down_spd_limit(ata_dev_phys_link(dev)); + if (dev->pio_mode > XFER_PIO_0) + ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); + } +@@ -2712,7 +2802,7 @@ static int ata_eh_handle_dev_fail(struct + ata_dev_disable(dev); + + /* detach if offline */ +- if (ata_link_offline(dev->link)) ++ if (ata_phys_link_offline(ata_dev_phys_link(dev))) + ata_eh_detach_dev(dev); + + /* schedule probe if necessary */ +--- a/drivers/ata/libata.h ++++ b/drivers/ata/libata.h +@@ -70,6 +70,7 @@ extern int atapi_passthru16; + extern int libata_fua; + extern int libata_noacpi; + extern int libata_allow_tpm; ++extern struct ata_link *ata_dev_phys_link(struct ata_device *dev); + extern void ata_force_cbl(struct ata_port *ap); + extern u64 ata_tf_to_lba(const struct ata_taskfile *tf); + extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf); +@@ -107,6 +108,8 @@ extern void ata_qc_issue(struct ata_queu + extern void __ata_qc_complete(struct ata_queued_cmd *qc); + extern int atapi_check_dma(struct ata_queued_cmd *qc); + extern void swap_buf_le16(u16 *buf, unsigned int buf_words); ++extern bool ata_phys_link_online(struct ata_link *link); ++extern bool ata_phys_link_offline(struct ata_link *link); + extern void ata_dev_init(struct ata_device *dev); + extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp); + extern int sata_link_init_spd(struct ata_link *link); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -691,7 +691,8 @@ struct ata_port { + unsigned int qc_active; + int nr_active_links; /* #links with active qcs */ + +- struct ata_link link; /* host default link */ ++ struct ata_link link; /* host default link */ ++ struct ata_link *slave_link; /* see ata_slave_link_init() */ + + int nr_pmp_links; /* nr of available PMP links */ + struct ata_link *pmp_link; /* array of PMP links */ +@@ -898,6 +899,7 @@ extern void ata_port_disable(struct ata_ + extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports); + extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, + const struct ata_port_info * const * ppi, int n_ports); ++extern int ata_slave_link_init(struct ata_port *ap); + extern int ata_host_start(struct ata_host *host); + extern int ata_host_register(struct ata_host *host, + struct scsi_host_template *sht); +@@ -1137,7 +1139,7 @@ static inline bool sata_pmp_attached(str + + static inline int ata_is_host_link(const struct ata_link *link) + { +- return link == &link->ap->link; ++ return link == &link->ap->link || link == link->ap->slave_link; + } + #else /* CONFIG_SATA_PMP */ + static inline bool sata_pmp_supported(struct ata_port *ap) +@@ -1170,7 +1172,7 @@ static inline int sata_srst_pmp(struct a + printk("%sata%u: "fmt, lv, (ap)->print_id , ##args) + + #define ata_link_printk(link, lv, fmt, args...) do { \ +- if (sata_pmp_attached((link)->ap)) \ ++ if (sata_pmp_attached((link)->ap) || (link)->ap->slave_link) \ + printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \ + (link)->pmp , ##args); \ + else \ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-make-SCR-access-ops-per-link b/src/patches/suse-2.6.27.31/patches.drivers/libata-make-SCR-access-ops-per-link new file mode 100644 index 000000000..9b8970580 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-make-SCR-access-ops-per-link @@ -0,0 +1,909 @@ +From 82ef04fb4c82542b3eda81cca461f0594ce9cd0b Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 31 Jul 2008 17:02:40 +0900 +Subject: [PATCH] libata: make SCR access ops per-link +References: bnc#441420 + +Logically, SCR access ops should take @link; however, there was no +compelling reason to convert all SCR access ops when adding @link +abstraction as there's one-to-one mapping between a port and a non-PMP +link. However, that assumption won't hold anymore with the scheduled +addition of slave link. + +Make SCR access ops per-link. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/ahci.c | 24 ++++++++++++------------ + drivers/ata/ata_piix.c | 15 +++++++++++---- + drivers/ata/libata-core.c | 13 ++++--------- + drivers/ata/sata_fsl.c | 26 +++++++++++++------------- + drivers/ata/sata_inic162x.c | 8 ++++---- + drivers/ata/sata_mv.c | 28 ++++++++++++++-------------- + drivers/ata/sata_nv.c | 16 ++++++++-------- + drivers/ata/sata_promise.c | 16 +++++++++------- + drivers/ata/sata_qstor.c | 12 ++++++------ + drivers/ata/sata_sil.c | 16 ++++++++-------- + drivers/ata/sata_sil24.c | 12 ++++++------ + drivers/ata/sata_sis.c | 28 ++++++++++++++++------------ + drivers/ata/sata_svw.c | 10 ++++++---- + drivers/ata/sata_uli.c | 24 ++++++++++++------------ + drivers/ata/sata_via.c | 24 ++++++++++++------------ + drivers/ata/sata_vsc.c | 10 ++++++---- + drivers/scsi/libsas/sas_ata.c | 8 ++++---- + include/linux/libata.h | 4 ++-- + 18 files changed, 153 insertions(+), 141 deletions(-) + +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -267,8 +267,8 @@ struct ahci_port_priv { + * per PM slot */ + }; + +-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); + static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +@@ -820,10 +820,10 @@ static unsigned ahci_scr_offset(struct a + return 0; + } + +-static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { +- void __iomem *port_mmio = ahci_port_base(ap); +- int offset = ahci_scr_offset(ap, sc_reg); ++ void __iomem *port_mmio = ahci_port_base(link->ap); ++ int offset = ahci_scr_offset(link->ap, sc_reg); + + if (offset) { + *val = readl(port_mmio + offset); +@@ -832,10 +832,10 @@ static int ahci_scr_read(struct ata_port + return -EINVAL; + } + +-static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { +- void __iomem *port_mmio = ahci_port_base(ap); +- int offset = ahci_scr_offset(ap, sc_reg); ++ void __iomem *port_mmio = ahci_port_base(link->ap); ++ int offset = ahci_scr_offset(link->ap, sc_reg); + + if (offset) { + writel(val, port_mmio + offset); +@@ -973,7 +973,7 @@ static void ahci_disable_alpm(struct ata + writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); + + /* go ahead and clean out PhyRdy Change from Serror too */ +- ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); ++ ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); + + /* + * Clear flag to indicate that we should ignore all PhyRdy +@@ -1937,8 +1937,8 @@ static void ahci_error_intr(struct ata_p + ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); + + /* AHCI needs SError cleared; otherwise, it might lock up */ +- ahci_scr_read(ap, SCR_ERROR, &serror); +- ahci_scr_write(ap, SCR_ERROR, serror); ++ ahci_scr_read(&ap->link, SCR_ERROR, &serror); ++ ahci_scr_write(&ap->link, SCR_ERROR, serror); + host_ehi->serror |= serror; + + /* some controllers set IRQ_IF_ERR on device errors, ignore it */ +@@ -2027,7 +2027,7 @@ static void ahci_port_intr(struct ata_po + if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && + (status & PORT_IRQ_PHYRDY)) { + status &= ~PORT_IRQ_PHYRDY; +- ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); ++ ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18))); + } + + if (unlikely(status & PORT_IRQ_ERROR)) { +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -165,8 +165,10 @@ static void piix_set_dmamode(struct ata_ + static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); + static int ich_pata_cable_detect(struct ata_port *ap); + static u8 piix_vmw_bmdma_status(struct ata_port *ap); +-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); +-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); ++static int piix_sidpr_scr_read(struct ata_link *link, ++ unsigned int reg, u32 *val); ++static int piix_sidpr_scr_write(struct ata_link *link, ++ unsigned int reg, u32 val); + #ifdef CONFIG_PM + static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); + static int piix_pci_device_resume(struct pci_dev *pdev); +@@ -971,8 +973,10 @@ static u32 piix_merge_scr(u32 val0, u32 + return val; + } + +-static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val) ++static int piix_sidpr_scr_read(struct ata_link *link, ++ unsigned int reg, u32 *val) + { ++ struct ata_port *ap = link->ap; + const int * const sstatus_merge_tbl[] = { + /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 }, + /* SPD */ (const int []){ 2, 1, 0, -1 }, +@@ -1013,8 +1017,11 @@ static int piix_sidpr_scr_read(struct at + return 0; + } + +-static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) ++static int piix_sidpr_scr_write(struct ata_link *link, ++ unsigned int reg, u32 val) + { ++ struct ata_port *ap = link->ap; ++ + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -4944,10 +4944,8 @@ int sata_scr_valid(struct ata_link *link + int sata_scr_read(struct ata_link *link, int reg, u32 *val) + { + if (ata_is_host_link(link)) { +- struct ata_port *ap = link->ap; +- + if (sata_scr_valid(link)) +- return ap->ops->scr_read(ap, reg, val); ++ return link->ap->ops->scr_read(link, reg, val); + return -EOPNOTSUPP; + } + +@@ -4973,10 +4971,8 @@ int sata_scr_read(struct ata_link *link, + int sata_scr_write(struct ata_link *link, int reg, u32 val) + { + if (ata_is_host_link(link)) { +- struct ata_port *ap = link->ap; +- + if (sata_scr_valid(link)) +- return ap->ops->scr_write(ap, reg, val); ++ return link->ap->ops->scr_write(link, reg, val); + return -EOPNOTSUPP; + } + +@@ -5001,13 +4997,12 @@ int sata_scr_write(struct ata_link *link + int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) + { + if (ata_is_host_link(link)) { +- struct ata_port *ap = link->ap; + int rc; + + if (sata_scr_valid(link)) { +- rc = ap->ops->scr_write(ap, reg, val); ++ rc = link->ap->ops->scr_write(link, reg, val); + if (rc == 0) +- rc = ap->ops->scr_read(ap, reg, &val); ++ rc = link->ap->ops->scr_read(link, reg, &val); + return rc; + } + return -EOPNOTSUPP; +--- a/drivers/ata/sata_fsl.c ++++ b/drivers/ata/sata_fsl.c +@@ -469,10 +469,10 @@ static bool sata_fsl_qc_fill_rtf(struct + return true; + } + +-static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in, +- u32 val) ++static int sata_fsl_scr_write(struct ata_link *link, ++ unsigned int sc_reg_in, u32 val) + { +- struct sata_fsl_host_priv *host_priv = ap->host->private_data; ++ struct sata_fsl_host_priv *host_priv = link->ap->host->private_data; + void __iomem *ssr_base = host_priv->ssr_base; + unsigned int sc_reg; + +@@ -493,10 +493,10 @@ static int sata_fsl_scr_write(struct ata + return 0; + } + +-static int sata_fsl_scr_read(struct ata_port *ap, unsigned int sc_reg_in, +- u32 *val) ++static int sata_fsl_scr_read(struct ata_link *link, ++ unsigned int sc_reg_in, u32 *val) + { +- struct sata_fsl_host_priv *host_priv = ap->host->private_data; ++ struct sata_fsl_host_priv *host_priv = link->ap->host->private_data; + void __iomem *ssr_base = host_priv->ssr_base; + unsigned int sc_reg; + +@@ -645,12 +645,12 @@ static int sata_fsl_port_start(struct at + * Workaround for 8315DS board 3gbps link-up issue, + * currently limit SATA port to GEN1 speed + */ +- sata_fsl_scr_read(ap, SCR_CONTROL, &temp); ++ sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); + temp &= ~(0xF << 4); + temp |= (0x1 << 4); +- sata_fsl_scr_write(ap, SCR_CONTROL, temp); ++ sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp); + +- sata_fsl_scr_read(ap, SCR_CONTROL, &temp); ++ sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp); + dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n", + temp); + #endif +@@ -868,7 +868,7 @@ issue_srst: + ioread32(CQ + hcr_base), + ioread32(CA + hcr_base), ioread32(CC + hcr_base)); + +- sata_fsl_scr_read(ap, SCR_ERROR, &Serror); ++ sata_fsl_scr_read(&ap->link, SCR_ERROR, &Serror); + + DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS)); + DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL)); +@@ -972,9 +972,9 @@ static void sata_fsl_error_intr(struct a + * Handle & Clear SError + */ + +- sata_fsl_scr_read(ap, SCR_ERROR, &SError); ++ sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError); + if (unlikely(SError & 0xFFFF0000)) { +- sata_fsl_scr_write(ap, SCR_ERROR, SError); ++ sata_fsl_scr_write(&ap->link, SCR_ERROR, SError); + } + + DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n", +@@ -1091,7 +1091,7 @@ static void sata_fsl_host_intr(struct at + + hstatus = ioread32(hcr_base + HSTATUS); + +- sata_fsl_scr_read(ap, SCR_ERROR, &SError); ++ sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError); + + if (unlikely(SError & 0xFFFF0000)) { + DPRINTK("serror @host_intr : 0x%x\n", SError); +--- a/drivers/ata/sata_inic162x.c ++++ b/drivers/ata/sata_inic162x.c +@@ -269,9 +269,9 @@ static void inic_reset_port(void __iomem + writeb(0xff, port_base + PORT_IRQ_STAT); + } + +-static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val) ++static int inic_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val) + { +- void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR; ++ void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR; + void __iomem *addr; + + if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) +@@ -286,9 +286,9 @@ static int inic_scr_read(struct ata_port + return 0; + } + +-static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) ++static int inic_scr_write(struct ata_link *link, unsigned sc_reg, u32 val) + { +- void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR; ++ void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR; + + if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) + return -EINVAL; +--- a/drivers/ata/sata_mv.c ++++ b/drivers/ata/sata_mv.c +@@ -493,10 +493,10 @@ struct mv_hw_ops { + void (*reset_bus)(struct ata_host *host, void __iomem *mmio); + }; + +-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); +-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); +-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); +-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); ++static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val); ++static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val); ++static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val); ++static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val); + static int mv_port_start(struct ata_port *ap); + static void mv_port_stop(struct ata_port *ap); + static int mv_qc_defer(struct ata_queued_cmd *qc); +@@ -1070,23 +1070,23 @@ static unsigned int mv_scr_offset(unsign + return ofs; + } + +-static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) ++static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val) + { + unsigned int ofs = mv_scr_offset(sc_reg_in); + + if (ofs != 0xffffffffU) { +- *val = readl(mv_ap_base(ap) + ofs); ++ *val = readl(mv_ap_base(link->ap) + ofs); + return 0; + } else + return -EINVAL; + } + +-static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) ++static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) + { + unsigned int ofs = mv_scr_offset(sc_reg_in); + + if (ofs != 0xffffffffU) { +- writelfl(val, mv_ap_base(ap) + ofs); ++ writelfl(val, mv_ap_base(link->ap) + ofs); + return 0; + } else + return -EINVAL; +@@ -2251,11 +2251,11 @@ static unsigned int mv5_scr_offset(unsig + return ofs; + } + +-static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) ++static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val) + { +- struct mv_host_priv *hpriv = ap->host->private_data; ++ struct mv_host_priv *hpriv = link->ap->host->private_data; + void __iomem *mmio = hpriv->base; +- void __iomem *addr = mv5_phy_base(mmio, ap->port_no); ++ void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no); + unsigned int ofs = mv5_scr_offset(sc_reg_in); + + if (ofs != 0xffffffffU) { +@@ -2265,11 +2265,11 @@ static int mv5_scr_read(struct ata_port + return -EINVAL; + } + +-static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) ++static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) + { +- struct mv_host_priv *hpriv = ap->host->private_data; ++ struct mv_host_priv *hpriv = link->ap->host->private_data; + void __iomem *mmio = hpriv->base; +- void __iomem *addr = mv5_phy_base(mmio, ap->port_no); ++ void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no); + unsigned int ofs = mv5_scr_offset(sc_reg_in); + + if (ofs != 0xffffffffU) { +--- a/drivers/ata/sata_nv.c ++++ b/drivers/ata/sata_nv.c +@@ -302,8 +302,8 @@ static void nv_ck804_host_stop(struct at + static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); + static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); + static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); +-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + + static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); +@@ -1540,21 +1540,21 @@ static irqreturn_t nv_ck804_interrupt(in + return ret; + } + +-static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; + +- *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); ++ *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + +-static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; + +- iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); ++ iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + +@@ -2243,9 +2243,9 @@ static void nv_swncq_host_interrupt(stru + if (!pp->qc_active) + return; + +- if (ap->ops->scr_read(ap, SCR_ERROR, &serror)) ++ if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror)) + return; +- ap->ops->scr_write(ap, SCR_ERROR, serror); ++ ap->ops->scr_write(&ap->link, SCR_ERROR, serror); + + if (ata_stat & ATA_ERR) { + ata_ehi_clear_desc(ehi); +--- a/drivers/ata/sata_promise.c ++++ b/drivers/ata/sata_promise.c +@@ -137,8 +137,8 @@ struct pdc_port_priv { + dma_addr_t pkt_dma; + }; + +-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + static int pdc_common_port_start(struct ata_port *ap); + static int pdc_sata_port_start(struct ata_port *ap); +@@ -392,19 +392,21 @@ static int pdc_sata_cable_detect(struct + return ATA_CBL_SATA; + } + +-static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int pdc_sata_scr_read(struct ata_link *link, ++ unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); ++ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + +-static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int pdc_sata_scr_write(struct ata_link *link, ++ unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); ++ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + +@@ -751,7 +753,7 @@ static void pdc_error_intr(struct ata_po + if (sata_scr_valid(&ap->link)) { + u32 serror; + +- pdc_sata_scr_read(ap, SCR_ERROR, &serror); ++ pdc_sata_scr_read(&ap->link, SCR_ERROR, &serror); + ehi->serror |= serror; + } + +--- a/drivers/ata/sata_qstor.c ++++ b/drivers/ata/sata_qstor.c +@@ -111,8 +111,8 @@ struct qs_port_priv { + qs_state_t state; + }; + +-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + static int qs_port_start(struct ata_port *ap); + static void qs_host_stop(struct ata_host *host); +@@ -242,11 +242,11 @@ static int qs_prereset(struct ata_link * + return ata_sff_prereset(link, deadline); + } + +-static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8)); ++ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 8)); + return 0; + } + +@@ -256,11 +256,11 @@ static void qs_error_handler(struct ata_ + ata_std_error_handler(ap); + } + +-static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); ++ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 8)); + return 0; + } + +--- a/drivers/ata/sata_sil24.c ++++ b/drivers/ata/sata_sil24.c +@@ -340,8 +340,8 @@ struct sil24_port_priv { + }; + + static void sil24_dev_config(struct ata_device *dev); +-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val); +-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); ++static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val); ++static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val); + static int sil24_qc_defer(struct ata_queued_cmd *qc); + static void sil24_qc_prep(struct ata_queued_cmd *qc); + static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); +@@ -504,9 +504,9 @@ static int sil24_scr_map[] = { + [SCR_ACTIVE] = 3, + }; + +-static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val) ++static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val) + { +- void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL; ++ void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL; + + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void __iomem *addr; +@@ -517,9 +517,9 @@ static int sil24_scr_read(struct ata_por + return -EINVAL; + } + +-static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) ++static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val) + { +- void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL; ++ void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL; + + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void __iomem *addr; +--- a/drivers/ata/sata_sil.c ++++ b/drivers/ata/sata_sil.c +@@ -115,8 +115,8 @@ static int sil_init_one(struct pci_dev * + static int sil_pci_device_resume(struct pci_dev *pdev); + #endif + static void sil_dev_config(struct ata_device *dev); +-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed); + static void sil_freeze(struct ata_port *ap); + static void sil_thaw(struct ata_port *ap); +@@ -317,9 +317,9 @@ static inline void __iomem *sil_scr_addr + return NULL; + } + +-static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { +- void __iomem *mmio = sil_scr_addr(ap, sc_reg); ++ void __iomem *mmio = sil_scr_addr(link->ap, sc_reg); + + if (mmio) { + *val = readl(mmio); +@@ -328,9 +328,9 @@ static int sil_scr_read(struct ata_port + return -EINVAL; + } + +-static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { +- void __iomem *mmio = sil_scr_addr(ap, sc_reg); ++ void __iomem *mmio = sil_scr_addr(link->ap, sc_reg); + + if (mmio) { + writel(val, mmio); +@@ -352,8 +352,8 @@ static void sil_host_intr(struct ata_por + * controllers continue to assert IRQ as long as + * SError bits are pending. Clear SError immediately. + */ +- sil_scr_read(ap, SCR_ERROR, &serror); +- sil_scr_write(ap, SCR_ERROR, serror); ++ sil_scr_read(&ap->link, SCR_ERROR, &serror); ++ sil_scr_write(&ap->link, SCR_ERROR, serror); + + /* Sometimes spurious interrupts occur, double check + * it's PHYRDY CHG. +--- a/drivers/ata/sata_sis.c ++++ b/drivers/ata/sata_sis.c +@@ -64,8 +64,8 @@ enum { + }; + + static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + + static const struct pci_device_id sis_pci_tbl[] = { + { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */ +@@ -134,10 +134,11 @@ static unsigned int get_scr_cfg_addr(str + return addr; + } + +-static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static u32 sis_scr_cfg_read(struct ata_link *link, ++ unsigned int sc_reg, u32 *val) + { +- struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); + u32 val2 = 0; + u8 pmr; + +@@ -158,10 +159,11 @@ static u32 sis_scr_cfg_read(struct ata_p + return 0; + } + +-static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int sis_scr_cfg_write(struct ata_link *link, ++ unsigned int sc_reg, u32 val) + { +- struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); + u8 pmr; + + if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ +@@ -178,8 +180,9 @@ static int sis_scr_cfg_write(struct ata_ + return 0; + } + +-static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { ++ struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 pmr; + +@@ -187,7 +190,7 @@ static int sis_scr_read(struct ata_port + return -EINVAL; + + if (ap->flags & SIS_FLAG_CFGSCR) +- return sis_scr_cfg_read(ap, sc_reg, val); ++ return sis_scr_cfg_read(link, sc_reg, val); + + pci_read_config_byte(pdev, SIS_PMR, &pmr); + +@@ -202,8 +205,9 @@ static int sis_scr_read(struct ata_port + return 0; + } + +-static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { ++ struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 pmr; + +@@ -213,7 +217,7 @@ static int sis_scr_write(struct ata_port + pci_read_config_byte(pdev, SIS_PMR, &pmr); + + if (ap->flags & SIS_FLAG_CFGSCR) +- return sis_scr_cfg_write(ap, sc_reg, val); ++ return sis_scr_cfg_write(link, sc_reg, val); + else { + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || +--- a/drivers/ata/sata_svw.c ++++ b/drivers/ata/sata_svw.c +@@ -123,20 +123,22 @@ static int k2_sata_check_atapi_dma(struc + } + } + +-static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int k2_sata_scr_read(struct ata_link *link, ++ unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); ++ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + + +-static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int k2_sata_scr_write(struct ata_link *link, ++ unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); ++ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + +--- a/drivers/ata/sata_uli.c ++++ b/drivers/ata/sata_uli.c +@@ -57,8 +57,8 @@ struct uli_priv { + }; + + static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + + static const struct pci_device_id uli_pci_tbl[] = { + { PCI_VDEVICE(AL, 0x5289), uli_5289 }, +@@ -107,39 +107,39 @@ static unsigned int get_scr_cfg_addr(str + return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg); + } + +-static u32 uli_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg) ++static u32 uli_scr_cfg_read(struct ata_link *link, unsigned int sc_reg) + { +- struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); + u32 val; + + pci_read_config_dword(pdev, cfg_addr, &val); + return val; + } + +-static void uli_scr_cfg_write(struct ata_port *ap, unsigned int scr, u32 val) ++static void uli_scr_cfg_write(struct ata_link *link, unsigned int scr, u32 val) + { +- struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- unsigned int cfg_addr = get_scr_cfg_addr(ap, scr); ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ unsigned int cfg_addr = get_scr_cfg_addr(link->ap, scr); + + pci_write_config_dword(pdev, cfg_addr, val); + } + +-static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; + +- *val = uli_scr_cfg_read(ap, sc_reg); ++ *val = uli_scr_cfg_read(link, sc_reg); + return 0; + } + +-static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 + return -EINVAL; + +- uli_scr_cfg_write(ap, sc_reg, val); ++ uli_scr_cfg_write(link, sc_reg, val); + return 0; + } + +--- a/drivers/ata/sata_via.c ++++ b/drivers/ata/sata_via.c +@@ -68,8 +68,8 @@ enum { + }; + + static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); +-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); ++static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); + static void svia_noop_freeze(struct ata_port *ap); + static int vt6420_prereset(struct ata_link *link, unsigned long deadline); + static int vt6421_pata_cable_detect(struct ata_port *ap); +@@ -152,19 +152,19 @@ MODULE_LICENSE("GPL"); + MODULE_DEVICE_TABLE(pci, svia_pci_tbl); + MODULE_VERSION(DRV_VERSION); + +-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); ++ *val = ioread32(link->ap->ioaddr.scr_addr + (4 * sc_reg)); + return 0; + } + +-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); ++ iowrite32(val, link->ap->ioaddr.scr_addr + (4 * sc_reg)); + return 0; + } + +@@ -210,20 +210,20 @@ static int vt6420_prereset(struct ata_li + goto skip_scr; + + /* Resume phy. This is the old SATA resume sequence */ +- svia_scr_write(ap, SCR_CONTROL, 0x300); +- svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */ ++ svia_scr_write(link, SCR_CONTROL, 0x300); ++ svia_scr_read(link, SCR_CONTROL, &scontrol); /* flush */ + + /* wait for phy to become ready, if necessary */ + do { + msleep(200); +- svia_scr_read(ap, SCR_STATUS, &sstatus); ++ svia_scr_read(link, SCR_STATUS, &sstatus); + if ((sstatus & 0xf) != 1) + break; + } while (time_before(jiffies, timeout)); + + /* open code sata_print_link_status() */ +- svia_scr_read(ap, SCR_STATUS, &sstatus); +- svia_scr_read(ap, SCR_CONTROL, &scontrol); ++ svia_scr_read(link, SCR_STATUS, &sstatus); ++ svia_scr_read(link, SCR_CONTROL, &scontrol); + + online = (sstatus & 0xf) == 0x3; + +@@ -232,7 +232,7 @@ static int vt6420_prereset(struct ata_li + online ? "up" : "down", sstatus, scontrol); + + /* SStatus is read one more time */ +- svia_scr_read(ap, SCR_STATUS, &sstatus); ++ svia_scr_read(link, SCR_STATUS, &sstatus); + + if (!online) { + /* tell EH to bail */ +--- a/drivers/ata/sata_vsc.c ++++ b/drivers/ata/sata_vsc.c +@@ -98,20 +98,22 @@ enum { + VSC_SATA_INT_PHY_CHANGE), + }; + +-static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) ++static int vsc_sata_scr_read(struct ata_link *link, ++ unsigned int sc_reg, u32 *val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); ++ *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + + +-static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) ++static int vsc_sata_scr_write(struct ata_link *link, ++ unsigned int sc_reg, u32 val) + { + if (sc_reg > SCR_CONTROL) + return -EINVAL; +- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); ++ writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4)); + return 0; + } + +--- a/drivers/scsi/libsas/sas_ata.c ++++ b/drivers/scsi/libsas/sas_ata.c +@@ -294,10 +294,10 @@ static void sas_ata_post_internal(struct + } + } + +-static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, ++static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in, + u32 val) + { +- struct domain_device *dev = ap->private_data; ++ struct domain_device *dev = link->ap->private_data; + + SAS_DPRINTK("STUB %s\n", __func__); + switch (sc_reg_in) { +@@ -319,10 +319,10 @@ static int sas_ata_scr_write(struct ata_ + return 0; + } + +-static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, ++static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in, + u32 *val) + { +- struct domain_device *dev = ap->private_data; ++ struct domain_device *dev = link->ap->private_data; + + SAS_DPRINTK("STUB %s\n", __func__); + switch (sc_reg_in) { +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -773,8 +773,8 @@ struct ata_port_operations { + /* + * Optional features + */ +- int (*scr_read)(struct ata_port *ap, unsigned int sc_reg, u32 *val); +- int (*scr_write)(struct ata_port *ap, unsigned int sc_reg, u32 val); ++ int (*scr_read)(struct ata_link *link, unsigned int sc_reg, u32 *val); ++ int (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val); + void (*pmp_attach)(struct ata_port *ap); + void (*pmp_detach)(struct ata_port *ap); + int (*enable_pm)(struct ata_port *ap, enum link_pm policy); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-misc-updates-to-prepare-for-slave-link b/src/patches/suse-2.6.27.31/patches.drivers/libata-misc-updates-to-prepare-for-slave-link new file mode 100644 index 000000000..1ef7aaa63 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-misc-updates-to-prepare-for-slave-link @@ -0,0 +1,84 @@ +From b5b3fa386b8f96c7fa92e507e5deddc2637924b4 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 31 Jul 2008 17:02:42 +0900 +Subject: [PATCH] libata: misc updates to prepare for slave link +References: bnc#441420 + +* Add ATA_EH_ALL_ACTIONS. + +* Make sata_link_{on|off}_line() return bool instead of int. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 16 ++++++++-------- + include/linux/libata.h | 6 ++++-- + 2 files changed, 12 insertions(+), 10 deletions(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -5052,16 +5052,16 @@ int sata_scr_write_flush(struct ata_link + * None. + * + * RETURNS: +- * 1 if the port online status is available and online. ++ * True if the port online status is available and online. + */ +-int ata_link_online(struct ata_link *link) ++bool ata_link_online(struct ata_link *link) + { + u32 sstatus; + + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) == 0x3) +- return 1; +- return 0; ++ return true; ++ return false; + } + + /** +@@ -5076,16 +5076,16 @@ int ata_link_online(struct ata_link *lin + * None. + * + * RETURNS: +- * 1 if the port offline status is available and offline. ++ * True if the port offline status is available and offline. + */ +-int ata_link_offline(struct ata_link *link) ++bool ata_link_offline(struct ata_link *link) + { + u32 sstatus; + + if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && + (sstatus & 0xf) != 0x3) +- return 1; +- return 0; ++ return true; ++ return false; + } + + #ifdef CONFIG_PM +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -321,6 +321,8 @@ enum { + ATA_EH_LPM = (1 << 4), /* link power management action */ + + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, ++ ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET | ++ ATA_EH_ENABLE_LINK | ATA_EH_LPM, + + /* ata_eh_info->flags */ + ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ +@@ -921,8 +923,8 @@ extern int sata_scr_valid(struct ata_lin + extern int sata_scr_read(struct ata_link *link, int reg, u32 *val); + extern int sata_scr_write(struct ata_link *link, int reg, u32 val); + extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val); +-extern int ata_link_online(struct ata_link *link); +-extern int ata_link_offline(struct ata_link *link); ++extern bool ata_link_online(struct ata_link *link); ++extern bool ata_link_offline(struct ata_link *link); + #ifdef CONFIG_PM + extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); + extern void ata_host_resume(struct ata_host *host); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ocz-vertex-no-hpa b/src/patches/suse-2.6.27.31/patches.drivers/libata-ocz-vertex-no-hpa new file mode 100644 index 000000000..02330c0a3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ocz-vertex-no-hpa @@ -0,0 +1,33 @@ +From: Tejun Heo +Subject: libata: OCZ Vertex can't do HPA +References: bnc#522414 + +OCZ Vertex SSD can't do HPA and not in a usual way. It reports HPA, +allows unlocking but then fails all IOs which fall in the unlocked +area. Quirk it so that HPA unlocking is not used for the device. + +Reported by Daniel Perup in bnc#522414. + + https://bugzilla.novell.com/show_bug.cgi?id=522414 + +Signed-off-by: Tejun Heo +Reported-by: Daniel Perup +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/ata/libata-core.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/ata/libata-core.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/ata/libata-core.c +@@ -4132,6 +4132,9 @@ static const struct ata_blacklist_entry + { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, + { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, + ++ /* this one allows HPA unlocking but fails IOs on the area */ ++ { "OCZ-VERTEX", "1.30", ATA_HORKAGE_BROKEN_HPA }, ++ + /* Devices which report 1 sector over size HPA */ + { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, + { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-fix-cable-detection b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-fix-cable-detection new file mode 100644 index 000000000..af14cadda --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-fix-cable-detection @@ -0,0 +1,39 @@ +From: Tejun Heo +Subject: pata_hpt366: fix cable detection, +References: bnc#362159 + +pata_hpt366 is strange in that its two channels occupy two PCI +functions and both are primary channels and bit1 of PCI configuration +register 0x5A indicates cable for both channels. + +Signed-off-by: Tejun Heo +Cc: Alan Cox +Cc: Sergei Shtylyov +Signed-off-by: Tejun Heo +--- + drivers/ata/pata_hpt366.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +Index: work/drivers/ata/pata_hpt366.c +=================================================================== +--- work.orig/drivers/ata/pata_hpt366.c ++++ work/drivers/ata/pata_hpt366.c +@@ -211,11 +211,15 @@ static u32 hpt36x_find_mode(struct ata_p + + static int hpt36x_cable_detect(struct ata_port *ap) + { +- u8 ata66; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); ++ u8 ata66; + ++ /* ++ * Each channel of pata_hpt366 occupies separate PCI function ++ * as the primary channel and bit1 indicates the cable type. ++ */ + pci_read_config_byte(pdev, 0x5A, &ata66); +- if (ata66 & (1 << ap->port_no)) ++ if (ata66 & 2) + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-fix-clock-detection b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-fix-clock-detection new file mode 100644 index 000000000..d7145d55b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-fix-clock-detection @@ -0,0 +1,31 @@ +From: Tejun Heo +Subject: pata_hpt366: fix clock detection +References: bnc#362159 + +pata_hpt366 had its clock detection wrong and detected 25Mhz as 40Mhz +and vice-versa. Fix it. + +Signed-off-by: Tejun Heo +Signed-off-by: Tejun Heo +--- + drivers/ata/pata_hpt366.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +Index: work/drivers/ata/pata_hpt366.c +=================================================================== +--- work.orig/drivers/ata/pata_hpt366.c ++++ work/drivers/ata/pata_hpt366.c +@@ -382,10 +382,10 @@ static int hpt36x_init_one(struct pci_de + /* PCI clocking determines the ATA timing values to use */ + /* info_hpt366 is safe against re-entry so we can scribble on it */ + switch((reg1 & 0x700) >> 8) { +- case 5: ++ case 9: + hpriv = &hpt366_40; + break; +- case 9: ++ case 5: + hpriv = &hpt366_25; + break; + default: + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-no-ATAPI-DMA b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-no-ATAPI-DMA new file mode 100644 index 000000000..2069e11d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-no-ATAPI-DMA @@ -0,0 +1,28 @@ +From: Tejun Heo +Subject: pata_hpt366: no ATAPI DMA +References: bnc#362159 + +IDE hpt366 driver doesn't allow DMA for ATAPI devices and MWDMA2 on +ATAPI device locks up pata_hpt366. Follow the suit. + +Signed-off-by: Tejun Heo +Signed-off-by: Tejun Heo +--- + drivers/ata/pata_hpt366.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +Index: work/drivers/ata/pata_hpt366.c +=================================================================== +--- work.orig/drivers/ata/pata_hpt366.c ++++ work/drivers/ata/pata_hpt366.c +@@ -183,7 +183,9 @@ static unsigned long hpt366_filter(struc + mask &= ~(0xF8 << ATA_SHIFT_UDMA); + if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4)) + mask &= ~(0xF0 << ATA_SHIFT_UDMA); +- } ++ } else if (adev->class == ATA_DEV_ATAPI) ++ mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); ++ + return ata_bmdma_mode_filter(adev, mask); + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-reimplement-mode-programming b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-reimplement-mode-programming new file mode 100644 index 000000000..d12c3e9b0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_hpt366-reimplement-mode-programming @@ -0,0 +1,180 @@ +From: Tejun Heo +Subject: pata_hpt366: reimplement mode programming +References: bnc#362159 + +Reimplement mode programming logic of pata_hpt366 such that it's +identical to that of IDE hpt366 driver. The differences were... + +* pata_hpt366 used 0xCFFF8FFFF to mask pio modes and 0x3FFFFFFF dma + modes. IDE hpt366 uses 0xC1F8FFFF for PIO, 0x303800FF for MWDMA and + 0x30070000 for UDMA. + +* pata_hpt366 doesn't set 0x08000000 for PIO unless it's already set + and always turns it on for MWDMA/UDMA. IDE hpt366 doesn't bother + with the bit. It always uses what was there. + +* IDE hpt366 always clears 0xC0000000. pata_hpt366 doesn't. + +Signed-off-by: Tejun Heo +Cc: Alan Cox +Cc: Sergei Shtylyov +Signed-off-by: Tejun Heo +--- +Unified pio/dma paths as per Sergei's suggestion. + + drivers/ata/pata_hpt366.c | 109 ++++++++++++++++++---------------------------- + 1 file changed, 44 insertions(+), 65 deletions(-) + +Index: linux-2.6.27/drivers/ata/pata_hpt366.c +=================================================================== +--- linux-2.6.27.orig/drivers/ata/pata_hpt366.c ++++ linux-2.6.27/drivers/ata/pata_hpt366.c +@@ -30,7 +30,7 @@ + #define DRV_VERSION "0.6.2" + + struct hpt_clock { +- u8 xfer_speed; ++ u8 xfer_mode; + u32 timing; + }; + +@@ -189,28 +189,6 @@ static unsigned long hpt366_filter(struc + return ata_bmdma_mode_filter(adev, mask); + } + +-/** +- * hpt36x_find_mode - reset the hpt36x bus +- * @ap: ATA port +- * @speed: transfer mode +- * +- * Return the 32bit register programming information for this channel +- * that matches the speed provided. +- */ +- +-static u32 hpt36x_find_mode(struct ata_port *ap, int speed) +-{ +- struct hpt_clock *clocks = ap->host->private_data; +- +- while(clocks->xfer_speed) { +- if (clocks->xfer_speed == speed) +- return clocks->timing; +- clocks++; +- } +- BUG(); +- return 0xffffffffU; /* silence compiler warning */ +-} +- + static int hpt36x_cable_detect(struct ata_port *ap) + { + struct pci_dev *pdev = to_pci_dev(ap->host->dev); +@@ -226,25 +204,16 @@ static int hpt36x_cable_detect(struct at + return ATA_CBL_PATA80; + } + +-/** +- * hpt366_set_piomode - PIO setup +- * @ap: ATA interface +- * @adev: device on the interface +- * +- * Perform PIO mode setup. +- */ +- +-static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) ++static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev, ++ u8 mode) + { ++ struct hpt_clock *clocks = ap->host->private_data; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- u32 addr1, addr2; +- u32 reg; +- u32 mode; ++ u32 addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); ++ u32 addr2 = 0x51 + 4 * ap->port_no; ++ u32 mask, reg; + u8 fast; + +- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); +- addr2 = 0x51 + 4 * ap->port_no; +- + /* Fast interrupt prediction disable, hold off interrupt disable */ + pci_read_config_byte(pdev, addr2, &fast); + if (fast & 0x80) { +@@ -252,12 +221,43 @@ static void hpt366_set_piomode(struct at + pci_write_config_byte(pdev, addr2, fast); + } + ++ /* determine timing mask and find matching clock entry */ ++ if (mode < XFER_MW_DMA_0) ++ mask = 0xc1f8ffff; ++ else if (mode < XFER_UDMA_0) ++ mask = 0x303800ff; ++ else ++ mask = 0x30070000; ++ ++ while (clocks->xfer_mode) { ++ if (clocks->xfer_mode == mode) ++ break; ++ clocks++; ++ } ++ if (!clocks->xfer_mode) ++ BUG(); ++ ++ /* ++ * Combine new mode bits with old config bits and disable ++ * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid ++ * problems handling I/O errors later. ++ */ + pci_read_config_dword(pdev, addr1, ®); +- mode = hpt36x_find_mode(ap, adev->pio_mode); +- mode &= ~0x8000000; /* No FIFO in PIO */ +- mode &= ~0x30070000; /* Leave config bits alone */ +- reg &= 0x30070000; /* Strip timing bits */ +- pci_write_config_dword(pdev, addr1, reg | mode); ++ reg = ((reg & ~mask) | (clocks->timing & mask)) & ~0xc0000000; ++ pci_write_config_dword(pdev, addr1, reg); ++} ++ ++/** ++ * hpt366_set_piomode - PIO setup ++ * @ap: ATA interface ++ * @adev: device on the interface ++ * ++ * Perform PIO mode setup. ++ */ ++ ++static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) ++{ ++ hpt366_set_mode(ap, adev, adev->pio_mode); + } + + /** +@@ -271,28 +271,7 @@ static void hpt366_set_piomode(struct at + + static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev) + { +- struct pci_dev *pdev = to_pci_dev(ap->host->dev); +- u32 addr1, addr2; +- u32 reg; +- u32 mode; +- u8 fast; +- +- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); +- addr2 = 0x51 + 4 * ap->port_no; +- +- /* Fast interrupt prediction disable, hold off interrupt disable */ +- pci_read_config_byte(pdev, addr2, &fast); +- if (fast & 0x80) { +- fast &= ~0x80; +- pci_write_config_byte(pdev, addr2, fast); +- } +- +- pci_read_config_dword(pdev, addr1, ®); +- mode = hpt36x_find_mode(ap, adev->dma_mode); +- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ +- mode &= ~0xC0000000; /* Leave config bits alone */ +- reg &= 0xC0000000; /* Strip timing bits */ +- pci_write_config_dword(pdev, addr1, reg | mode); ++ hpt366_set_mode(ap, adev, adev->dma_mode); + } + + static struct scsi_host_template hpt36x_sht = { diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_sch-slave-poss b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_sch-slave-poss new file mode 100644 index 000000000..d3645c023 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-pata_sch-slave-poss @@ -0,0 +1,27 @@ +From: Mark Salter +Subject: pata_sch: slave devices +References: bnc#443657 + +I posted this last month, but was prompted to do so again in bz#467457 + +Add capability flag to support slave devices with pata_sch driver. + +Signed-off-by: Mark Salter +Signed-off-by: Tejun Heo +--- + drivers/ata/pata_sch.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.27/drivers/ata/pata_sch.c +=================================================================== +--- linux-2.6.27.orig/drivers/ata/pata_sch.c ++++ linux-2.6.27/drivers/ata/pata_sch.c +@@ -83,7 +83,7 @@ static struct ata_port_operations sch_pa + }; + + static struct ata_port_info sch_port_info = { +- .flags = 0, ++ .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, /* pio0-4 */ + .mwdma_mask = ATA_MWDMA2, /* mwdma0-2 */ + .udma_mask = ATA_UDMA5, /* udma0-5 */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-prefer-over-ide b/src/patches/suse-2.6.27.31/patches.drivers/libata-prefer-over-ide new file mode 100644 index 000000000..fce1918de --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-prefer-over-ide @@ -0,0 +1,29 @@ +From: Tejun Heo +Subject: libata: prefer libata drivers over ide ones +References: bnc#433105 + +When loading modules, modprobe follows modules.order which is +generated according to the link order. libata ones have been our +primary ATA drivers for some time now and having ide drivers before +libata ones trigger unexpected behaviors. Prefer libata over ide. + +Signed-off-by: Tejun Heo +--- + drivers/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.26/drivers/Makefile +=================================================================== +--- linux-2.6.26.orig/drivers/Makefile ++++ linux-2.6.26/drivers/Makefile +@@ -37,9 +37,9 @@ obj-y += base/ block/ misc/ mfd/ net/ + obj-$(CONFIG_NUBUS) += nubus/ + obj-$(CONFIG_ATM) += atm/ + obj-y += macintosh/ +-obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_SCSI) += scsi/ + obj-$(CONFIG_ATA) += ata/ ++obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_FUSION) += message/ + obj-$(CONFIG_FIREWIRE) += firewire/ + obj-y += ieee1394/ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-reimplement-link-iterator b/src/patches/suse-2.6.27.31/patches.drivers/libata-reimplement-link-iterator new file mode 100644 index 000000000..eb4813352 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-reimplement-link-iterator @@ -0,0 +1,111 @@ +From aadffb682cc5572f48cc24883681db65530bd284 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Thu, 31 Jul 2008 17:02:41 +0900 +Subject: [PATCH] libata: reimplement link iterator +References: bnc#441420 + +Implement __ata_port_next_link() and reimplement +__ata_port_for_each_link() and ata_port_for_each_link() using it. +This removes relatively large inlined code and makes iteration easier +to extend. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 30 ++++++++++++++++++++++++++++++ + include/linux/libata.h | 35 +++++++++-------------------------- + 2 files changed, 39 insertions(+), 26 deletions(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -163,6 +163,35 @@ MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_VERSION); + + ++/* ++ * Iterator helpers. Don't use directly. ++ * ++ * LOCKING: ++ * Host lock or EH context. ++ */ ++struct ata_link *__ata_port_next_link(struct ata_port *ap, ++ struct ata_link *link, bool dev_only) ++{ ++ /* NULL link indicates start of iteration */ ++ if (!link) { ++ if (dev_only && sata_pmp_attached(ap)) ++ return ap->pmp_link; ++ return &ap->link; ++ } ++ ++ /* we just iterated over the host link, what's next? */ ++ if (ata_is_host_link(link)) { ++ if (!sata_pmp_attached(ap)) ++ return NULL; ++ return ap->pmp_link; ++ } ++ ++ /* iterate to the next PMP link */ ++ if (++link < ap->pmp_link + ap->nr_pmp_links) ++ return link; ++ return NULL; ++} ++ + /** + * ata_force_cbl - force cable type according to libata.force + * @ap: ATA port of interest +@@ -6333,6 +6362,7 @@ EXPORT_SYMBOL_GPL(ata_base_port_ops); + EXPORT_SYMBOL_GPL(sata_port_ops); + EXPORT_SYMBOL_GPL(ata_dummy_port_ops); + EXPORT_SYMBOL_GPL(ata_dummy_port_info); ++EXPORT_SYMBOL_GPL(__ata_port_next_link); + EXPORT_SYMBOL_GPL(ata_std_bios_param); + EXPORT_SYMBOL_GPL(ata_host_init); + EXPORT_SYMBOL_GPL(ata_host_alloc); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -1266,34 +1266,17 @@ static inline int ata_link_active(struct + return ata_tag_valid(link->active_tag) || link->sactive; + } + +-static inline struct ata_link *ata_port_first_link(struct ata_port *ap) +-{ +- if (sata_pmp_attached(ap)) +- return ap->pmp_link; +- return &ap->link; +-} +- +-static inline struct ata_link *ata_port_next_link(struct ata_link *link) +-{ +- struct ata_port *ap = link->ap; +- +- if (ata_is_host_link(link)) { +- if (!sata_pmp_attached(ap)) +- return NULL; +- return ap->pmp_link; +- } +- +- if (++link < ap->nr_pmp_links + ap->pmp_link) +- return link; +- return NULL; +-} +- +-#define __ata_port_for_each_link(lk, ap) \ +- for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk)) ++extern struct ata_link *__ata_port_next_link(struct ata_port *ap, ++ struct ata_link *link, ++ bool dev_only); ++ ++#define __ata_port_for_each_link(link, ap) \ ++ for ((link) = __ata_port_next_link((ap), NULL, false); (link); \ ++ (link) = __ata_port_next_link((ap), (link), false)) + + #define ata_port_for_each_link(link, ap) \ +- for ((link) = ata_port_first_link(ap); (link); \ +- (link) = ata_port_next_link(link)) ++ for ((link) = __ata_port_next_link((ap), NULL, true); (link); \ ++ (link) = __ata_port_next_link((ap), (link), true)) + + #define ata_link_for_each_dev(dev, link) \ + for ((dev) = (link)->device; \ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_sil-blacklist-double-spin-off b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_sil-blacklist-double-spin-off new file mode 100644 index 000000000..3e9add79b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_sil-blacklist-double-spin-off @@ -0,0 +1,84 @@ +From 285ddd34af077acb9148bba2569947c7af41b8ce Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Mon, 3 Nov 2008 19:01:06 +0900 +Subject: [PATCH] SATA Sil: Blacklist system that spins off disks during ACPI power off +References: bnc#441721 + +Some notebooks from HP have the problem that their BIOSes attempt to +spin down hard drives before entering ACPI system states S4 and S5. +This leads to a yo-yo effect during system power-off shutdown and the +last phase of hibernation when the disk is first spun down by the +kernel and then almost immediately turned on and off by the BIOS. +This, in turn, may result in shortening the disk's life times. + +To prevent this from happening we can blacklist the affected systems +using DMI information. + +Blacklist HP nx6325 that uses the sata_sil driver. + +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/sata_sil.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +Index: linux-2.6.27/drivers/ata/sata_sil.c +=================================================================== +--- linux-2.6.27.orig/drivers/ata/sata_sil.c ++++ linux-2.6.27/drivers/ata/sata_sil.c +@@ -603,11 +603,38 @@ static void sil_init_controller(struct a + } + } + ++static bool sil_broken_system_poweroff(struct pci_dev *pdev) ++{ ++ static const struct dmi_system_id broken_systems[] = { ++ { ++ .ident = "HP Compaq nx6325", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), ++ }, ++ /* PCI slot number of the controller */ ++ .driver_data = (void *)0x12UL, ++ }, ++ ++ { } /* terminate list */ ++ }; ++ const struct dmi_system_id *dmi = dmi_first_match(broken_systems); ++ ++ if (dmi) { ++ unsigned long slot = (unsigned long)dmi->driver_data; ++ /* apply the quirk only to on-board controllers */ ++ return slot == PCI_SLOT(pdev->devfn); ++ } ++ ++ return false; ++} ++ + static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + { + static int printed_version; + int board_id = ent->driver_data; +- const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL }; ++ struct ata_port_info pi = sil_port_info[board_id]; ++ const struct ata_port_info *ppi[] = { &pi, NULL }; + struct ata_host *host; + void __iomem *mmio_base; + int n_ports, rc; +@@ -621,6 +648,13 @@ static int sil_init_one(struct pci_dev * + if (board_id == sil_3114) + n_ports = 4; + ++ if (sil_broken_system_poweroff(pdev)) { ++ pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN | ++ ATA_FLAG_NO_HIBERNATE_SPINDOWN; ++ dev_info(&pdev->dev, "quirky BIOS, skipping spindown " ++ "on poweroff and hibernation\n"); ++ } ++ + host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); + if (!host) + return -ENOMEM; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-add-vt8261-support.patch b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-add-vt8261-support.patch new file mode 100644 index 000000000..c7997d025 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-add-vt8261-support.patch @@ -0,0 +1,30 @@ +From 6813952021a7820a505002de260bda36978671f7 Mon Sep 17 00:00:00 2001 +From: JosephChan@via.com.tw +Date: Fri, 16 Jan 2009 19:44:55 +0800 +Subject: libata: sata_via: Add VT8261 support +Patch-mainline: 2.6.29 +References: bnc#474301 + +From: JosephChan@via.com.tw + +commit 6813952021a7820a505002de260bda36978671f7 upstream. + +Signed-off-by: Joseph Chan +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/ata/sata_via.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/ata/sata_via.c ++++ b/drivers/ata/sata_via.c +@@ -92,6 +92,8 @@ static const struct pci_device_id svia_p + { PCI_VDEVICE(VIA, 0x5372), vt6420 }, + { PCI_VDEVICE(VIA, 0x7372), vt6420 }, + { PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */ ++ { PCI_VDEVICE(VIA, 0x9000), vt8251 }, ++ { PCI_VDEVICE(VIA, 0x9040), vt8251 }, + + { } /* terminate list */ + }; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-fix-support-for-5287 b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-fix-support-for-5287 new file mode 100644 index 000000000..cd3011801 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-fix-support-for-5287 @@ -0,0 +1,271 @@ +From b9d5b89b487517cbd4cb4702da829e07ef9e4432 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 22 Oct 2008 00:46:36 +0900 +Subject: [PATCH] sata_via: fix support for 5287 +References: bnc#441718 + +5287 used to be treated as vt6420 but it didn't work. It's new family +of controllers called vt8251 which hosts four SATA ports as M/S of the +two ATA ports. This configuration is rather peculiar in that although +the M/S devices are on the same port, each have its own SCR (or +equivalent link status/control) registers which screws up the +port-link-device hierarchy assumed by libata. Another controller +which falls into this category is ata_piix w/ SIDPR access. + +libata now has facility to deal with this class of controllers named +slave_link. A low level driver for such controllers can just call +ata_slave_link_init() on the respective ports and libata will handle +all the difficult parts like following up with single SRST after +hardresetting both ports. + +This patch creates new controller class vt8251, implements slave_link +aware init sequence and config space based SCR access for it and moves +5287 to the new class. + +This patch is based on Joseph Chan's larger patch which was created +before slave_link was implemented in libata. + + http://thread.gmane.org/gmane.linux.kernel.commits.mm/40640 + +Signed-off-by: Tejun Heo +Cc: Joseph Chan +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/sata_via.c | 155 ++++++++++++++++++++++++++++++++++++++++++++---- + 1 files changed, 143 insertions(+), 12 deletions(-) + +diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c +index 5b72e73..62367fe 100644 +--- a/drivers/ata/sata_via.c ++++ b/drivers/ata/sata_via.c +@@ -44,11 +44,16 @@ + #include + + #define DRV_NAME "sata_via" +-#define DRV_VERSION "2.3" ++#define DRV_VERSION "2.4" + ++/* ++ * vt8251 is different from other sata controllers of VIA. It has two ++ * channels, each channel has both Master and Slave slot. ++ */ + enum board_ids_enum { + vt6420, + vt6421, ++ vt8251, + }; + + enum { +@@ -70,6 +75,8 @@ enum { + static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); + static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); ++static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val); ++static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val); + static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); + static void svia_noop_freeze(struct ata_port *ap); + static int vt6420_prereset(struct ata_link *link, unsigned long deadline); +@@ -79,12 +86,12 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); + + static const struct pci_device_id svia_pci_tbl[] = { + { PCI_VDEVICE(VIA, 0x5337), vt6420 }, +- { PCI_VDEVICE(VIA, 0x0591), vt6420 }, +- { PCI_VDEVICE(VIA, 0x3149), vt6420 }, +- { PCI_VDEVICE(VIA, 0x3249), vt6421 }, +- { PCI_VDEVICE(VIA, 0x5287), vt6420 }, ++ { PCI_VDEVICE(VIA, 0x0591), vt6420 }, /* 2 sata chnls (Master) */ ++ { PCI_VDEVICE(VIA, 0x3149), vt6420 }, /* 2 sata chnls (Master) */ ++ { PCI_VDEVICE(VIA, 0x3249), vt6421 }, /* 2 sata chnls, 1 pata chnl */ + { PCI_VDEVICE(VIA, 0x5372), vt6420 }, + { PCI_VDEVICE(VIA, 0x7372), vt6420 }, ++ { PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */ + + { } /* terminate list */ + }; +@@ -128,6 +135,13 @@ static struct ata_port_operations vt6421_sata_ops = { + .scr_write = svia_scr_write, + }; + ++static struct ata_port_operations vt8251_ops = { ++ .inherits = &svia_base_ops, ++ .hardreset = sata_std_hardreset, ++ .scr_read = vt8251_scr_read, ++ .scr_write = vt8251_scr_write, ++}; ++ + static const struct ata_port_info vt6420_port_info = { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, +@@ -152,6 +166,15 @@ static struct ata_port_info vt6421_pport_info = { + .port_ops = &vt6421_pata_ops, + }; + ++static struct ata_port_info vt8251_port_info = { ++ .flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS | ++ ATA_FLAG_NO_LEGACY, ++ .pio_mask = 0x1f, ++ .mwdma_mask = 0x07, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &vt8251_ops, ++}; ++ + MODULE_AUTHOR("Jeff Garzik"); + MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); + MODULE_LICENSE("GPL"); +@@ -174,6 +197,83 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + return 0; + } + ++static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val) ++{ ++ static const u8 ipm_tbl[] = { 1, 2, 6, 0 }; ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ int slot = 2 * link->ap->port_no + link->pmp; ++ u32 v = 0; ++ u8 raw; ++ ++ switch (scr) { ++ case SCR_STATUS: ++ pci_read_config_byte(pdev, 0xA0 + slot, &raw); ++ ++ /* read the DET field, bit0 and 1 of the config byte */ ++ v |= raw & 0x03; ++ ++ /* read the SPD field, bit4 of the configure byte */ ++ if (raw & (1 << 4)) ++ v |= 0x02 << 4; ++ else ++ v |= 0x01 << 4; ++ ++ /* read the IPM field, bit2 and 3 of the config byte */ ++ v |= ipm_tbl[(raw >> 2) & 0x3]; ++ break; ++ ++ case SCR_ERROR: ++ /* devices other than 5287 uses 0xA8 as base */ ++ WARN_ON(pdev->device != 0x5287); ++ pci_read_config_dword(pdev, 0xB0 + slot * 4, &v); ++ break; ++ ++ case SCR_CONTROL: ++ pci_read_config_byte(pdev, 0xA4 + slot, &raw); ++ ++ /* read the DET field, bit0 and bit1 */ ++ v |= ((raw & 0x02) << 1) | (raw & 0x01); ++ ++ /* read the IPM field, bit2 and bit3 */ ++ v |= ((raw >> 2) & 0x03) << 8; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ *val = v; ++ return 0; ++} ++ ++static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val) ++{ ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ int slot = 2 * link->ap->port_no + link->pmp; ++ u32 v = 0; ++ ++ switch (scr) { ++ case SCR_ERROR: ++ /* devices other than 5287 uses 0xA8 as base */ ++ WARN_ON(pdev->device != 0x5287); ++ pci_write_config_dword(pdev, 0xB0 + slot * 4, val); ++ return 0; ++ ++ case SCR_CONTROL: ++ /* set the DET field */ ++ v |= ((val & 0x4) >> 1) | (val & 0x1); ++ ++ /* set the IPM field */ ++ v |= ((val >> 8) & 0x3) << 2; ++ ++ pci_write_config_byte(pdev, 0xA4 + slot, v); ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ + /** + * svia_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent +@@ -396,6 +496,30 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) + return 0; + } + ++static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) ++{ ++ const struct ata_port_info *ppi[] = { &vt8251_port_info, NULL }; ++ struct ata_host *host; ++ int i, rc; ++ ++ rc = ata_pci_sff_prepare_host(pdev, ppi, &host); ++ if (rc) ++ return rc; ++ *r_host = host; ++ ++ rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); ++ if (rc) { ++ dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); ++ return rc; ++ } ++ ++ /* 8251 hosts four sata ports as M/S of the two channels */ ++ for (i = 0; i < host->n_ports; i++) ++ ata_slave_link_init(host->ports[i]); ++ ++ return 0; ++} ++ + static void svia_configure(struct pci_dev *pdev) + { + u8 tmp8; +@@ -451,10 +575,10 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + if (rc) + return rc; + +- if (board_id == vt6420) +- bar_sizes = &svia_bar_sizes[0]; +- else ++ if (board_id == vt6421) + bar_sizes = &vt6421_bar_sizes[0]; ++ else ++ bar_sizes = &svia_bar_sizes[0]; + + for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) + if ((pci_resource_start(pdev, i) == 0) || +@@ -467,12 +591,19 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + return -ENODEV; + } + +- if (board_id == vt6420) ++ switch (board_id) { ++ case vt6420: + rc = vt6420_prepare_host(pdev, &host); +- else ++ break; ++ case vt6421: + rc = vt6421_prepare_host(pdev, &host); +- if (rc) +- return rc; ++ break; ++ case vt8251: ++ rc = vt8251_prepare_host(pdev, &host); ++ break; ++ default: ++ return -EINVAL; ++ } + + svia_configure(pdev); + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-load-DEVICE-register-when-CTL-changes b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-load-DEVICE-register-when-CTL-changes new file mode 100644 index 000000000..71c4a8d96 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-load-DEVICE-register-when-CTL-changes @@ -0,0 +1,96 @@ +From b78152e9dbab6d6175e2adcbd8c62959e8f0f922 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 22 Oct 2008 00:45:57 +0900 +Subject: [PATCH] sata_via: load DEVICE register when CTL changes +References: bnc#441718 + +VIA controllers clear DEVICE register when IEN changes. Make sure +DEVICE is updated along with CTL. + +This change is separated from Joseph Chan's larger patch. + + http://thread.gmane.org/gmane.linux.kernel.commits.mm/40640 + +Signed-off-by: Tejun Heo +Cc: Joseph Chan +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/sata_via.c | 35 ++++++++++++++++++++++++++++++++--- + 1 files changed, 32 insertions(+), 3 deletions(-) + +diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c +index 1cfa745..5b72e73 100644 +--- a/drivers/ata/sata_via.c ++++ b/drivers/ata/sata_via.c +@@ -70,6 +70,7 @@ enum { + static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); + static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); ++static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); + static void svia_noop_freeze(struct ata_port *ap); + static int vt6420_prereset(struct ata_link *link, unsigned long deadline); + static int vt6421_pata_cable_detect(struct ata_port *ap); +@@ -103,21 +104,26 @@ static struct scsi_host_template svia_sht = { + ATA_BMDMA_SHT(DRV_NAME), + }; + +-static struct ata_port_operations vt6420_sata_ops = { ++static struct ata_port_operations svia_base_ops = { + .inherits = &ata_bmdma_port_ops, ++ .sff_tf_load = svia_tf_load, ++}; ++ ++static struct ata_port_operations vt6420_sata_ops = { ++ .inherits = &svia_base_ops, + .freeze = svia_noop_freeze, + .prereset = vt6420_prereset, + }; + + static struct ata_port_operations vt6421_pata_ops = { +- .inherits = &ata_bmdma_port_ops, ++ .inherits = &svia_base_ops, + .cable_detect = vt6421_pata_cable_detect, + .set_piomode = vt6421_set_pio_mode, + .set_dmamode = vt6421_set_dma_mode, + }; + + static struct ata_port_operations vt6421_sata_ops = { +- .inherits = &ata_bmdma_port_ops, ++ .inherits = &svia_base_ops, + .scr_read = svia_scr_read, + .scr_write = svia_scr_write, + }; +@@ -168,6 +174,29 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) + return 0; + } + ++/** ++ * svia_tf_load - send taskfile registers to host controller ++ * @ap: Port to which output is sent ++ * @tf: ATA taskfile register set ++ * ++ * Outputs ATA taskfile to standard ATA host controller. ++ * ++ * This is to fix the internal bug of via chipsets, which will ++ * reset the device register after changing the IEN bit on ctl ++ * register. ++ */ ++static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) ++{ ++ struct ata_taskfile ttf; ++ ++ if (tf->ctl != ap->last_ctl) { ++ ttf = *tf; ++ ttf.flags |= ATA_TFLAG_DEVICE; ++ tf = &ttf; ++ } ++ ata_sff_tf_load(ap, tf); ++} ++ + static void svia_noop_freeze(struct ata_port *ap) + { + /* Some VIA controllers choke if ATA_NIEN is manipulated in +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-restore-vt-_prepare_host-error-handling b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-restore-vt-_prepare_host-error-handling new file mode 100644 index 000000000..f87440f88 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-sata_via-restore-vt-_prepare_host-error-handling @@ -0,0 +1,42 @@ +From 554d491de112a378b4d1a705bb93b58bcd444a70 Mon Sep 17 00:00:00 2001 +From: Marcin Slusarz +Date: Sun, 2 Nov 2008 22:18:52 +0100 +Subject: [PATCH] sata_via: restore vt*_prepare_host error handling +References: bnc#441718 + +commit b9d5b89b487517cbd4cb4702da829e07ef9e4432 (sata_via: fix support +for 5287) accidently (?) removed vt*_prepare_host error handling - restore it + +catched by gcc: +drivers/ata/sata_via.c: In function 'svia_init_one': +drivers/ata/sata_via.c:567: warning: 'host' may be used uninitialized in this function + +Signed-off-by: Marcin Slusarz +Cc: Tejun Heo +Cc: Joseph Chan +Cc: Jeff Garzik +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/sata_via.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c +index 62367fe..c18935f 100644 +--- a/drivers/ata/sata_via.c ++++ b/drivers/ata/sata_via.c +@@ -602,8 +602,10 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) + rc = vt8251_prepare_host(pdev, &host); + break; + default: +- return -EINVAL; ++ rc = -EINVAL; + } ++ if (rc) ++ return rc; + + svia_configure(pdev); + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-set-device-class-to-NONE-if-phys_offline b/src/patches/suse-2.6.27.31/patches.drivers/libata-set-device-class-to-NONE-if-phys_offline new file mode 100644 index 000000000..6b42f2cd6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-set-device-class-to-NONE-if-phys_offline @@ -0,0 +1,47 @@ +From 816ab89782ac139a8b65147cca990822bb7e8675 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 22 Oct 2008 00:31:34 +0900 +Subject: [PATCH] libata: set device class to NONE if phys_offline +References: bnc#441420 + +Reset methods don't have access to phys link status for slave links +and may incorrectly indicate device presence causing unnecessary probe +failures for unoccupied links. This patch clears device class to NONE +during post-reset processing if phys link is offline. + +As on/offlineness semantics is strictly defined and used in multiple +places by the core layer, this won't change behavior for drivers which +don't use slave links. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-eh.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -2425,14 +2425,14 @@ int ata_eh_reset(struct ata_link *link, + dev->pio_mode = XFER_PIO_0; + dev->flags &= ~ATA_DFLAG_SLEEPING; + +- if (ata_phys_link_offline(ata_dev_phys_link(dev))) +- continue; +- +- /* apply class override */ +- if (lflags & ATA_LFLAG_ASSUME_ATA) +- classes[dev->devno] = ATA_DEV_ATA; +- else if (lflags & ATA_LFLAG_ASSUME_SEMB) +- classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */ ++ if (!ata_phys_link_offline(ata_dev_phys_link(dev))) { ++ /* apply class override */ ++ if (lflags & ATA_LFLAG_ASSUME_ATA) ++ classes[dev->devno] = ATA_DEV_ATA; ++ else if (lflags & ATA_LFLAG_ASSUME_SEMB) ++ classes[dev->devno] = ATA_DEV_SEMB_UNSUP; ++ } else ++ classes[dev->devno] = ATA_DEV_NONE; + } + + /* record current link speed */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-transfer-EHI-control-flags-to-slave-ehc.i b/src/patches/suse-2.6.27.31/patches.drivers/libata-transfer-EHI-control-flags-to-slave-ehc.i new file mode 100644 index 000000000..761c54935 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-transfer-EHI-control-flags-to-slave-ehc.i @@ -0,0 +1,51 @@ +From 848e4c68c4695beae563f9a3d59fce596b466a74 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Tue, 21 Oct 2008 14:26:39 +0900 +Subject: [PATCH] libata: transfer EHI control flags to slave ehc.i +References: bnc#441420 + +ATA_EHI_NO_AUTOPSY and ATA_EHI_QUIET are used to control the behavior +of EH. As only the master link is visible outside EH, these flags are +set only for the master link although they should also apply to the +slave link, which causes spurious EH messages during probe and +suspend/resume. + +This patch transfers those two flags to slave ehc.i before performing +slave autopsy and reporting. + +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-eh.c | 5 +++++ + include/linux/libata.h | 3 +++ + 2 files changed, 8 insertions(+) + +--- a/drivers/ata/libata-eh.c ++++ b/drivers/ata/libata-eh.c +@@ -1973,8 +1973,13 @@ void ata_eh_autopsy(struct ata_port *ap) + struct ata_eh_context *mehc = &ap->link.eh_context; + struct ata_eh_context *sehc = &ap->slave_link->eh_context; + ++ /* transfer control flags from master to slave */ ++ sehc->i.flags |= mehc->i.flags & ATA_EHI_TO_SLAVE_MASK; ++ ++ /* perform autopsy on the slave link */ + ata_eh_link_autopsy(ap->slave_link); + ++ /* transfer actions from slave to master and clear slave */ + ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS); + mehc->i.action |= sehc->i.action; + mehc->i.dev_action[1] |= sehc->i.dev_action[1]; +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -337,6 +337,9 @@ enum { + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ++ /* mask of flags to transfer *to* the slave link */ ++ ATA_EHI_TO_SLAVE_MASK = ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, ++ + /* max tries if error condition is still set after ->error_handler */ + ATA_EH_MAX_TRIES = 5, + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-unlock-hpa-by-default b/src/patches/suse-2.6.27.31/patches.drivers/libata-unlock-hpa-by-default new file mode 100644 index 000000000..8ab083f46 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-unlock-hpa-by-default @@ -0,0 +1,23 @@ +From: Tejun Heo +Subject: [PATCH] libata: unlock HPA by default +References: 299267 + +Unlock HPA by default. This is to stay compatible with the old IDE +drivers. + +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -137,7 +137,7 @@ int libata_fua = 0; + module_param_named(fua, libata_fua, int, 0444); + MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); + +-static int ata_ignore_hpa; ++static int ata_ignore_hpa = 1; + module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); + MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-whitelist-good-bridges b/src/patches/suse-2.6.27.31/patches.drivers/libata-whitelist-good-bridges new file mode 100644 index 000000000..f62a41b3a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libata-whitelist-good-bridges @@ -0,0 +1,54 @@ +From 9ce8e3073d9cfd6f859c22a25441db41b85cbf6e Mon Sep 17 00:00:00 2001 +From: Jens Axboe +Date: Wed, 27 Aug 2008 15:23:18 +0200 +Subject: [PATCH] libata: add whitelist for devices with known good pata-sata bridges + +libata currently imposes a UDMA5 max transfer rate and 200 sector max +transfer size for SATA devices that sit behind a pata-sata bridge. Lots +of devices have known good bridges that don't need this limit applied. +The MTRON SSD disks are such devices. Transfer rates are increased by +20-30% with the restriction removed. + +So add a "blacklist" entry for the MTRON devices, with a flag indicating +that the bridge is known good. + +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + drivers/ata/libata-core.c | 7 +++++++ + include/linux/libata.h | 1 + + 2 files changed, 8 insertions(+) + +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -2163,6 +2163,10 @@ retry: + static inline u8 ata_dev_knobble(struct ata_device *dev) + { + struct ata_port *ap = dev->link->ap; ++ ++ if (ata_dev_blacklisted(dev) & ATA_HORKAGE_BRIDGE_OK) ++ return 0; ++ + return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id))); + } + +@@ -4141,6 +4145,9 @@ static const struct ata_blacklist_entry + { "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, }, + { "TSSTcorp CDDVDW SH-S202N", "SB01", ATA_HORKAGE_IVB, }, + ++ /* Devices that do not need bridging limits applied */ ++ { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, }, ++ + /* End Marker */ + { } + }; +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -371,6 +371,7 @@ enum { + ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ + ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ + ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ ++ ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */ + ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firwmare update warning */ + + /* DMA mask for user DMA control: User visible values; DO NOT diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libfc-cancel_delayed_work_sync-called-improperly.patch b/src/patches/suse-2.6.27.31/patches.drivers/libfc-cancel_delayed_work_sync-called-improperly.patch new file mode 100644 index 000000000..04e6b5be3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libfc-cancel_delayed_work_sync-called-improperly.patch @@ -0,0 +1,56 @@ +From f929f666ebaeb17afcb2d88b46e17092b3299ce6 Mon Sep 17 00:00:00 2001 +From: Steve Ma +Date: Fri, 13 Feb 2009 13:18:16 -0800 +Subject: [PATCH] libfc: cancel_delayed_work_sync called improperly +References: bnc#477931 + +The cancel_delayed_work_sync routine call can sleep, therefore +it cannot be called in any atomic or critical sections of the code. +In the routine fc_fabric_logoff, the call is moved out of the +critical section, and placed at the end of the routine. +In the routine fc_lport_enter_reset, we may not call +cancel_delayed_work_sync, because fc_lport_enter_reset is +always called when lport mutex locked. So the cancel_delayed_work_sync +is moved to the fc_lport_reset routine, before the lport mutex +lock and the fc_lport_enter_reset call. + +Signed-off-by: Steve Ma +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/libfc/fc_lport.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index 780c571..1559195 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -617,9 +617,9 @@ int fc_fabric_logoff(struct fc_lport *lport) + { + lport->tt.disc_stop_final(lport); + mutex_lock(&lport->lp_mutex); +- cancel_delayed_work_sync(&lport->retry_work); + fc_lport_enter_logo(lport); + mutex_unlock(&lport->lp_mutex); ++ cancel_delayed_work_sync(&lport->retry_work); + return 0; + } + EXPORT_SYMBOL(fc_fabric_logoff); +@@ -919,6 +919,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + */ + int fc_lport_reset(struct fc_lport *lport) + { ++ cancel_delayed_work_sync(&lport->retry_work); + mutex_lock(&lport->lp_mutex); + fc_lport_enter_reset(lport); + mutex_unlock(&lport->lp_mutex); +@@ -939,7 +940,6 @@ static void fc_lport_enter_reset(struct fc_lport *lport) + fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_RESET); +- cancel_delayed_work_sync(&lport->retry_work); + + if (lport->dns_rp) + lport->tt.rport_logoff(lport->dns_rp); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libfc-fix-read-IO-data-integrity b/src/patches/suse-2.6.27.31/patches.drivers/libfc-fix-read-IO-data-integrity new file mode 100644 index 000000000..ae5704834 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/libfc-fix-read-IO-data-integrity @@ -0,0 +1,70 @@ +From 09585f46fdc490d932e9753660a6ee8108acca10 Mon Sep 17 00:00:00 2001 +From: Vasu Dev +Date: Fri, 23 Jan 2009 02:27:33 -0800 +Subject: libfc: IO data integrity issue when a IO data frame lost +References: bnc#469536 + +The fc_fcp_complete_locked detected data underrun in this case and set +the FC_DATA_UNDRUN but that was ignored by fc_io_compl for all cases +including read underrun. + +Added code to not to ignore FC_DATA_UNDRUN for read IO and instead +suggested scsi-ml to retry cmd to recover from lost data frame. + +Not sure if it is okay to ignore FC_DATA_UNDRUN for other case, so let +code as is for other cases but removed or-ing with zero valued fsp->cdb_status +for those cases. + +Please ignore previously submitted patch fixing this issue differently at +http://www.open-fcoe.org/pipermail/devel/2009-January/001543.html. +Although that patch also fixed this issue but was causing unnecessary +FC abort to trigger scsi-ml retry to recover from this underrun issue. + +Also bumped up module version to 1.0.7. + +Signed-off-by: Vasu Dev +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/fcoe/libfcoe.c | 2 +- + drivers/scsi/libfc/fc_fcp.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -60,7 +60,7 @@ static int debug_fcoe; + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("FCoE"); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("1.0.6"); ++MODULE_VERSION("1.0.7"); + + /* fcoe host list */ + LIST_HEAD(fcoe_hostlist); +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -42,7 +42,7 @@ + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("libfc"); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("1.0.6"); ++MODULE_VERSION("1.0.7"); + + static int fc_fcp_debug; + +@@ -1811,12 +1811,12 @@ static void fc_io_compl(struct fc_fcp_pk + sc_cmd->result = DID_ERROR << 16; + break; + case FC_DATA_UNDRUN: +- if (fsp->cdb_status == 0) { ++ if ((fsp->cdb_status == 0) && !(fsp->req_flags & FC_SRB_READ)) { + /* + * scsi status is good but transport level +- * underrun. for read it should be an error?? ++ * underrun. + */ +- sc_cmd->result = (DID_OK << 16) | fsp->cdb_status; ++ sc_cmd->result = DID_OK << 16; + } else { + /* + * scsi got underrun, this is an error diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8-update new file mode 100644 index 000000000..39ac2f0c9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8-update @@ -0,0 +1,12887 @@ +From: Jamie Wellnitz +Subject: Emulex lpfc driver update to 8.2.8 +References: FATE#303485,bnc#420767 + +Update Emulex lpfc driver from 8.2.7 to 8.2.8 + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/lpfc/lpfc.h | 96 +- + drivers/scsi/lpfc/lpfc_attr.c | 1375 +++++++++++++++++++++++++++++ + drivers/scsi/lpfc/lpfc_crtn.h | 51 - + drivers/scsi/lpfc/lpfc_ct.c | 20 + drivers/scsi/lpfc/lpfc_debugfs.c | 400 +++++++- + drivers/scsi/lpfc/lpfc_disc.h | 23 + drivers/scsi/lpfc/lpfc_els.c | 1712 ++++++++++++++++++++++++++++++++++-- + drivers/scsi/lpfc/lpfc_hbadisc.c | 233 ++++- + drivers/scsi/lpfc/lpfc_hw.h | 183 +++ + drivers/scsi/lpfc/lpfc_init.c | 924 +++++++++++++++---- + drivers/scsi/lpfc/lpfc_mbox.c | 624 +++++++++++-- + drivers/scsi/lpfc/lpfc_mem.c | 116 ++ + drivers/scsi/lpfc/lpfc_nl.h | 163 +++ + drivers/scsi/lpfc/lpfc_nportdisc.c | 24 + drivers/scsi/lpfc/lpfc_scsi.c | 516 ++++++++++- + drivers/scsi/lpfc/lpfc_scsi.h | 5 + drivers/scsi/lpfc/lpfc_sli.c | 1715 ++++++++++++++++++++++++++++++++----- + drivers/scsi/lpfc/lpfc_sli.h | 1 + drivers/scsi/lpfc/lpfc_version.h | 6 + drivers/scsi/lpfc/lpfc_vport.c | 168 +++ + drivers/scsi/lpfc/lpfc_vport.h | 4 + 21 files changed, 7464 insertions(+), 895 deletions(-) + +--- a/drivers/scsi/lpfc/lpfc_attr.c ++++ b/drivers/scsi/lpfc/lpfc_attr.c +@@ -32,6 +32,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -49,6 +50,21 @@ + #define LPFC_LINK_SPEED_BITMAP 0x00000117 + #define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8" + ++/** ++ * lpfc_jedec_to_ascii: Hex to ascii convertor according to JEDEC rules. ++ * @incr: integer to convert. ++ * @hdw: ascii string holding converted integer plus a string terminator. ++ * ++ * Description: ++ * JEDEC Joint Electron Device Engineering Council. ++ * Convert a 32 bit integer composed of 8 nibbles into an 8 byte ascii ++ * character string. The string is then terminated with a NULL in byte 9. ++ * Hex 0-9 becomes ascii '0' to '9'. ++ * Hex a-f becomes ascii '=' to 'B' capital B. ++ * ++ * Notes: ++ * Coded for 32 bit integers only. ++ **/ + static void + lpfc_jedec_to_ascii(int incr, char hdw[]) + { +@@ -65,6 +81,14 @@ lpfc_jedec_to_ascii(int incr, char hdw[] + return; + } + ++/** ++ * lpfc_drvr_version_show: Return the Emulex driver string with version number. ++ * @dev: class unused variable. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the module description text. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -72,6 +96,14 @@ lpfc_drvr_version_show(struct device *de + return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); + } + ++/** ++ * lpfc_info_show: Return some pci info about the host in ascii. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the formatted text from lpfc_info(). ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_info_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -81,6 +113,14 @@ lpfc_info_show(struct device *dev, struc + return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host)); + } + ++/** ++ * lpfc_serialnum_show: Return the hba serial number in ascii. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the formatted text serial number. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_serialnum_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -92,6 +132,18 @@ lpfc_serialnum_show(struct device *dev, + return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); + } + ++/** ++ * lpfc_temp_sensor_show: Return the temperature sensor level. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the formatted support level. ++ * ++ * Description: ++ * Returns a number indicating the temperature sensor level currently ++ * supported, zero or one in ascii. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_temp_sensor_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -102,6 +154,14 @@ lpfc_temp_sensor_show(struct device *dev + return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support); + } + ++/** ++ * lpfc_modeldesc_show: Return the model description of the hba. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the scsi vpd model description. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_modeldesc_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -113,6 +173,14 @@ lpfc_modeldesc_show(struct device *dev, + return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); + } + ++/** ++ * lpfc_modelname_show: Return the model name of the hba. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the scsi vpd model name. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_modelname_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -124,6 +192,14 @@ lpfc_modelname_show(struct device *dev, + return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); + } + ++/** ++ * lpfc_programtype_show: Return the program type of the hba. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the scsi vpd program type. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_programtype_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -135,6 +211,33 @@ lpfc_programtype_show(struct device *dev + return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); + } + ++/** ++ * lpfc_mlomgmt_show: Return the Menlo Maintenance sli flag. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the Menlo Maintenance sli flag. ++ * ++ * Returns: size of formatted string. ++ **/ ++static ssize_t ++lpfc_mlomgmt_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ ++ return snprintf(buf, PAGE_SIZE, "%d\n", ++ (phba->sli.sli_flag & LPFC_MENLO_MAINT)); ++} ++ ++/** ++ * lpfc_vportnum_show: Return the port number in ascii of the hba. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains scsi vpd program type. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_vportnum_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -146,6 +249,14 @@ lpfc_vportnum_show(struct device *dev, s + return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port); + } + ++/** ++ * lpfc_fwrev_show: Return the firmware rev running in the hba. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the scsi vpd program type. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_fwrev_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -159,6 +270,14 @@ lpfc_fwrev_show(struct device *dev, stru + return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev); + } + ++/** ++ * lpfc_hdw_show: Return the jedec information about the hba. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the scsi vpd program type. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_hdw_show(struct device *dev, struct device_attribute *attr, char *buf) + { +@@ -171,6 +290,15 @@ lpfc_hdw_show(struct device *dev, struct + lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); + return snprintf(buf, PAGE_SIZE, "%s\n", hdw); + } ++ ++/** ++ * lpfc_option_rom_version_show: Return the adapter ROM FCode version. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the ROM and FCode ascii strings. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -181,6 +309,18 @@ lpfc_option_rom_version_show(struct devi + + return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); + } ++ ++/** ++ * lpfc_state_show: Return the link state of the port. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains text describing the state of the link. ++ * ++ * Notes: ++ * The switch statement has no default so zero will be returned. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_link_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -232,8 +372,10 @@ lpfc_link_state_show(struct device *dev, + "Unknown\n"); + break; + } +- +- if (phba->fc_topology == TOPOLOGY_LOOP) { ++ if (phba->sli.sli_flag & LPFC_MENLO_MAINT) ++ len += snprintf(buf + len, PAGE_SIZE-len, ++ " Menlo Maint Mode\n"); ++ else if (phba->fc_topology == TOPOLOGY_LOOP) { + if (vport->fc_flag & FC_PUBLIC_LOOP) + len += snprintf(buf + len, PAGE_SIZE-len, + " Public Loop\n"); +@@ -253,6 +395,18 @@ lpfc_link_state_show(struct device *dev, + return len; + } + ++/** ++ * lpfc_num_discovered_ports_show: Return sum of mapped and unmapped vports. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the sum of fc mapped and unmapped. ++ * ++ * Description: ++ * Returns the ascii text number of the sum of the fc mapped and unmapped ++ * vport counts. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_num_discovered_ports_show(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -264,7 +418,20 @@ lpfc_num_discovered_ports_show(struct de + vport->fc_map_cnt + vport->fc_unmap_cnt); + } + +- ++/** ++ * lpfc_issue_lip: Misnomer, name carried over from long ago. ++ * @shost: Scsi_Host pointer. ++ * ++ * Description: ++ * Bring the link down gracefully then re-init the link. The firmware will ++ * re-init the fiber channel interface as required. Does not issue a LIP. ++ * ++ * Returns: ++ * -EPERM port offline or management commands are being blocked ++ * -ENOMEM cannot allocate memory for the mailbox command ++ * -EIO error sending the mailbox command ++ * zero for success ++ **/ + static int + lpfc_issue_lip(struct Scsi_Host *shost) + { +@@ -306,6 +473,21 @@ lpfc_issue_lip(struct Scsi_Host *shost) + return 0; + } + ++/** ++ * lpfc_do_offline: Issues a mailbox command to bring the link down. ++ * @phba: lpfc_hba pointer. ++ * @type: LPFC_EVT_OFFLINE, LPFC_EVT_WARM_START, LPFC_EVT_KILL. ++ * ++ * Notes: ++ * Assumes any error from lpfc_do_offline() will be negative. ++ * Can wait up to 5 seconds for the port ring buffers count ++ * to reach zero, prints a warning if it is not zero and continues. ++ * lpfc_workq_post_event() returns a non-zero return coce if call fails. ++ * ++ * Returns: ++ * -EIO error posting the event ++ * zero for success ++ **/ + static int + lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) + { +@@ -353,6 +535,22 @@ lpfc_do_offline(struct lpfc_hba *phba, u + return 0; + } + ++/** ++ * lpfc_selective_reset: Offline then onlines the port. ++ * @phba: lpfc_hba pointer. ++ * ++ * Description: ++ * If the port is configured to allow a reset then the hba is brought ++ * offline then online. ++ * ++ * Notes: ++ * Assumes any error from lpfc_do_offline() will be negative. ++ * ++ * Returns: ++ * lpfc_do_offline() return code if not zero ++ * -EIO reset not configured or error posting the event ++ * zero for success ++ **/ + static int + lpfc_selective_reset(struct lpfc_hba *phba) + { +@@ -378,6 +576,27 @@ lpfc_selective_reset(struct lpfc_hba *ph + return 0; + } + ++/** ++ * lpfc_issue_reset: Selectively resets an adapter. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: containing the string "selective". ++ * @count: unused variable. ++ * ++ * Description: ++ * If the buf contains the string "selective" then lpfc_selective_reset() ++ * is called to perform the reset. ++ * ++ * Notes: ++ * Assumes any error from lpfc_selective_reset() will be negative. ++ * If lpfc_selective_reset() returns zero then the length of the buffer ++ * is returned which indicates succcess ++ * ++ * Returns: ++ * -EINVAL if the buffer does not contain the string "selective" ++ * length of buf if lpfc-selective_reset() if the call succeeds ++ * return value of lpfc_selective_reset() if the call fails ++**/ + static ssize_t + lpfc_issue_reset(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -397,6 +616,14 @@ lpfc_issue_reset(struct device *dev, str + return status; + } + ++/** ++ * lpfc_nport_evt_cnt_show: Return the number of nport events. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the ascii number of nport events. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -408,6 +635,14 @@ lpfc_nport_evt_cnt_show(struct device *d + return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); + } + ++/** ++ * lpfc_board_mode_show: Return the state of the board. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the state of the adapter. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_board_mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -429,6 +664,19 @@ lpfc_board_mode_show(struct device *dev, + return snprintf(buf, PAGE_SIZE, "%s\n", state); + } + ++/** ++ * lpfc_board_mode_store: Puts the hba in online, offline, warm or error state. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: containing one of the strings "online", "offline", "warm" or "error". ++ * @count: unused variable. ++ * ++ * Returns: ++ * -EACCES if enable hba reset not enabled ++ * -EINVAL if the buffer does not contain a valid string (see above) ++ * -EIO if lpfc_workq_post_event() or lpfc_do_offline() fails ++ * buf length greater than zero indicates success ++ **/ + static ssize_t + lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -462,6 +710,24 @@ lpfc_board_mode_store(struct device *dev + return -EIO; + } + ++/** ++ * lpfc_get_hba_info: Return various bits of informaton about the adapter. ++ * @phba: pointer to the adapter structure. ++ * @mxri max xri count. ++ * @axri available xri count. ++ * @mrpi max rpi count. ++ * @arpi available rpi count. ++ * @mvpi max vpi count. ++ * @avpi available vpi count. ++ * ++ * Description: ++ * If an integer pointer for an count is not null then the value for the ++ * count is returned. ++ * ++ * Returns: ++ * zero on error ++ * one for success ++ **/ + static int + lpfc_get_hba_info(struct lpfc_hba *phba, + uint32_t *mxri, uint32_t *axri, +@@ -524,6 +790,20 @@ lpfc_get_hba_info(struct lpfc_hba *phba, + return 1; + } + ++/** ++ * lpfc_max_rpi_show: Return maximum rpi. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the maximum rpi count in decimal or "Unknown". ++ * ++ * Description: ++ * Calls lpfc_get_hba_info() asking for just the mrpi count. ++ * If lpfc_get_hba_info() returns zero (failure) the buffer text is set ++ * to "Unknown" and the buffer length is returned, therefore the caller ++ * must check for "Unknown" in the buffer to detect a failure. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_max_rpi_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -538,6 +818,20 @@ lpfc_max_rpi_show(struct device *dev, st + return snprintf(buf, PAGE_SIZE, "Unknown\n"); + } + ++/** ++ * lpfc_used_rpi_show: Return maximum rpi minus available rpi. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: containing the used rpi count in decimal or "Unknown". ++ * ++ * Description: ++ * Calls lpfc_get_hba_info() asking for just the mrpi and arpi counts. ++ * If lpfc_get_hba_info() returns zero (failure) the buffer text is set ++ * to "Unknown" and the buffer length is returned, therefore the caller ++ * must check for "Unknown" in the buffer to detect a failure. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_used_rpi_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -552,6 +846,20 @@ lpfc_used_rpi_show(struct device *dev, s + return snprintf(buf, PAGE_SIZE, "Unknown\n"); + } + ++/** ++ * lpfc_max_xri_show: Return maximum xri. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the maximum xri count in decimal or "Unknown". ++ * ++ * Description: ++ * Calls lpfc_get_hba_info() asking for just the mrpi count. ++ * If lpfc_get_hba_info() returns zero (failure) the buffer text is set ++ * to "Unknown" and the buffer length is returned, therefore the caller ++ * must check for "Unknown" in the buffer to detect a failure. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_max_xri_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -566,6 +874,20 @@ lpfc_max_xri_show(struct device *dev, st + return snprintf(buf, PAGE_SIZE, "Unknown\n"); + } + ++/** ++ * lpfc_used_xri_show: Return maximum xpi minus the available xpi. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the used xri count in decimal or "Unknown". ++ * ++ * Description: ++ * Calls lpfc_get_hba_info() asking for just the mxri and axri counts. ++ * If lpfc_get_hba_info() returns zero (failure) the buffer text is set ++ * to "Unknown" and the buffer length is returned, therefore the caller ++ * must check for "Unknown" in the buffer to detect a failure. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_used_xri_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -580,6 +902,20 @@ lpfc_used_xri_show(struct device *dev, s + return snprintf(buf, PAGE_SIZE, "Unknown\n"); + } + ++/** ++ * lpfc_max_vpi_show: Return maximum vpi. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the maximum vpi count in decimal or "Unknown". ++ * ++ * Description: ++ * Calls lpfc_get_hba_info() asking for just the mvpi count. ++ * If lpfc_get_hba_info() returns zero (failure) the buffer text is set ++ * to "Unknown" and the buffer length is returned, therefore the caller ++ * must check for "Unknown" in the buffer to detect a failure. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_max_vpi_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -594,6 +930,20 @@ lpfc_max_vpi_show(struct device *dev, st + return snprintf(buf, PAGE_SIZE, "Unknown\n"); + } + ++/** ++ * lpfc_used_vpi_show: Return maximum vpi minus the available vpi. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the used vpi count in decimal or "Unknown". ++ * ++ * Description: ++ * Calls lpfc_get_hba_info() asking for just the mvpi and avpi counts. ++ * If lpfc_get_hba_info() returns zero (failure) the buffer text is set ++ * to "Unknown" and the buffer length is returned, therefore the caller ++ * must check for "Unknown" in the buffer to detect a failure. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_used_vpi_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -608,6 +958,19 @@ lpfc_used_vpi_show(struct device *dev, s + return snprintf(buf, PAGE_SIZE, "Unknown\n"); + } + ++/** ++ * lpfc_npiv_info_show: Return text about NPIV support for the adapter. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: text that must be interpreted to determine if npiv is supported. ++ * ++ * Description: ++ * Buffer will contain text indicating npiv is not suppoerted on the port, ++ * the port is an NPIV physical port, or it is an npiv virtual port with ++ * the id of the vport. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_npiv_info_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -623,6 +986,17 @@ lpfc_npiv_info_show(struct device *dev, + return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi); + } + ++/** ++ * lpfc_poll_show: Return text about poll support for the adapter. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the cfg_poll in hex. ++ * ++ * Notes: ++ * cfg_poll should be a lpfc_polling_flags type. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_poll_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -634,6 +1008,20 @@ lpfc_poll_show(struct device *dev, struc + return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll); + } + ++/** ++ * lpfc_poll_store: Set the value of cfg_poll for the adapter. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: one or more lpfc_polling_flags values. ++ * @count: not used. ++ * ++ * Notes: ++ * buf contents converted to integer and checked for a valid value. ++ * ++ * Returns: ++ * -EINVAL if the buffer connot be converted or is out of range ++ * length of the buf on success ++ **/ + static ssize_t + lpfc_poll_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -692,6 +1080,20 @@ lpfc_poll_store(struct device *dev, stru + return strlen(buf); + } + ++/** ++ * lpfc_param_show: Return a cfg attribute value in decimal. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_show. ++ * ++ * lpfc_##attr##_show: Return the decimal value of an adapters cfg_xxx field. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the attribute value in decimal. ++ * ++ * Returns: size of formatted string. ++ **/ + #define lpfc_param_show(attr) \ + static ssize_t \ + lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ +@@ -706,6 +1108,20 @@ lpfc_##attr##_show(struct device *dev, s + phba->cfg_##attr);\ + } + ++/** ++ * lpfc_param_hex_show: Return a cfg attribute value in hex. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_show ++ * ++ * lpfc_##attr##_show: Return the hex value of an adapters cfg_xxx field. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the attribute value in hexidecimal. ++ * ++ * Returns: size of formatted string. ++ **/ + #define lpfc_param_hex_show(attr) \ + static ssize_t \ + lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ +@@ -720,6 +1136,25 @@ lpfc_##attr##_show(struct device *dev, s + phba->cfg_##attr);\ + } + ++/** ++ * lpfc_param_init: Intializes a cfg attribute. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_init. The macro also ++ * takes a default argument, a minimum and maximum argument. ++ * ++ * lpfc_##attr##_init: Initializes an attribute. ++ * @phba: pointer the the adapter structure. ++ * @val: integer attribute value. ++ * ++ * Validates the min and max values then sets the adapter config field ++ * accordingly, or uses the default if out of range and prints an error message. ++ * ++ * Returns: ++ * zero on success ++ * -EINVAL if default used ++ **/ + #define lpfc_param_init(attr, default, minval, maxval) \ + static int \ + lpfc_##attr##_init(struct lpfc_hba *phba, int val) \ +@@ -735,6 +1170,26 @@ lpfc_##attr##_init(struct lpfc_hba *phba + return -EINVAL;\ + } + ++/** ++ * lpfc_param_set: Set a cfg attribute value. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_set ++ * ++ * lpfc_##attr##_set: Sets an attribute value. ++ * @phba: pointer the the adapter structure. ++ * @val: integer attribute value. ++ * ++ * Description: ++ * Validates the min and max values then sets the ++ * adapter config field if in the valid range. prints error message ++ * and does not set the parameter if invalid. ++ * ++ * Returns: ++ * zero on success ++ * -EINVAL if val is invalid ++ **/ + #define lpfc_param_set(attr, default, minval, maxval) \ + static int \ + lpfc_##attr##_set(struct lpfc_hba *phba, int val) \ +@@ -749,6 +1204,27 @@ lpfc_##attr##_set(struct lpfc_hba *phba, + return -EINVAL;\ + } + ++/** ++ * lpfc_param_store: Set a vport attribute value. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_store. ++ * ++ * lpfc_##attr##_store: Set an sttribute value. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: contains the attribute value in ascii. ++ * @count: not used. ++ * ++ * Description: ++ * Convert the ascii text number to an integer, then ++ * use the lpfc_##attr##_set function to set the value. ++ * ++ * Returns: ++ * -EINVAL if val is invalid or lpfc_##attr##_set() fails ++ * length of buffer upon success. ++ **/ + #define lpfc_param_store(attr) \ + static ssize_t \ + lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ +@@ -768,6 +1244,20 @@ lpfc_##attr##_store(struct device *dev, + return -EINVAL;\ + } + ++/** ++ * lpfc_vport_param_show: Return decimal formatted cfg attribute value. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_show ++ * ++ * lpfc_##attr##_show: prints the attribute value in decimal. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the attribute value in decimal. ++ * ++ * Returns: length of formatted string. ++ **/ + #define lpfc_vport_param_show(attr) \ + static ssize_t \ + lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ +@@ -780,6 +1270,21 @@ lpfc_##attr##_show(struct device *dev, s + return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ + } + ++/** ++ * lpfc_vport_param_hex_show: Return hex formatted attribute value. ++ * ++ * Description: ++ * Macro that given an attr e.g. ++ * hba_queue_depth expands into a function with the name ++ * lpfc_hba_queue_depth_show ++ * ++ * lpfc_##attr##_show: prints the attribute value in hexidecimal. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the attribute value in hexidecimal. ++ * ++ * Returns: length of formatted string. ++ **/ + #define lpfc_vport_param_hex_show(attr) \ + static ssize_t \ + lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ +@@ -792,6 +1297,24 @@ lpfc_##attr##_show(struct device *dev, s + return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ + } + ++/** ++ * lpfc_vport_param_init: Initialize a vport cfg attribute. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_init. The macro also ++ * takes a default argument, a minimum and maximum argument. ++ * ++ * lpfc_##attr##_init: validates the min and max values then sets the ++ * adapter config field accordingly, or uses the default if out of range ++ * and prints an error message. ++ * @phba: pointer the the adapter structure. ++ * @val: integer attribute value. ++ * ++ * Returns: ++ * zero on success ++ * -EINVAL if default used ++ **/ + #define lpfc_vport_param_init(attr, default, minval, maxval) \ + static int \ + lpfc_##attr##_init(struct lpfc_vport *vport, int val) \ +@@ -801,12 +1324,29 @@ lpfc_##attr##_init(struct lpfc_vport *vp + return 0;\ + }\ + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ +- "0449 lpfc_"#attr" attribute cannot be set to %d, "\ ++ "0423 lpfc_"#attr" attribute cannot be set to %d, "\ + "allowed range is ["#minval", "#maxval"]\n", val); \ + vport->cfg_##attr = default;\ + return -EINVAL;\ + } + ++/** ++ * lpfc_vport_param_set: Set a vport cfg attribute. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth expands ++ * into a function with the name lpfc_hba_queue_depth_set ++ * ++ * lpfc_##attr##_set: validates the min and max values then sets the ++ * adapter config field if in the valid range. prints error message ++ * and does not set the parameter if invalid. ++ * @phba: pointer the the adapter structure. ++ * @val: integer attribute value. ++ * ++ * Returns: ++ * zero on success ++ * -EINVAL if val is invalid ++ **/ + #define lpfc_vport_param_set(attr, default, minval, maxval) \ + static int \ + lpfc_##attr##_set(struct lpfc_vport *vport, int val) \ +@@ -816,11 +1356,28 @@ lpfc_##attr##_set(struct lpfc_vport *vpo + return 0;\ + }\ + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ +- "0450 lpfc_"#attr" attribute cannot be set to %d, "\ ++ "0424 lpfc_"#attr" attribute cannot be set to %d, "\ + "allowed range is ["#minval", "#maxval"]\n", val); \ + return -EINVAL;\ + } + ++/** ++ * lpfc_vport_param_store: Set a vport attribute. ++ * ++ * Description: ++ * Macro that given an attr e.g. hba_queue_depth ++ * expands into a function with the name lpfc_hba_queue_depth_store ++ * ++ * lpfc_##attr##_store: convert the ascii text number to an integer, then ++ * use the lpfc_##attr##_set function to set the value. ++ * @cdev: class device that is converted into a Scsi_host. ++ * @buf: contains the attribute value in decimal. ++ * @count: not used. ++ * ++ * Returns: ++ * -EINVAL if val is invalid or lpfc_##attr##_set() fails ++ * length of buffer upon success. ++ **/ + #define lpfc_vport_param_store(attr) \ + static ssize_t \ + lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ +@@ -941,6 +1498,7 @@ static DEVICE_ATTR(option_rom_version, S + lpfc_option_rom_version_show, NULL); + static DEVICE_ATTR(num_discovered_ports, S_IRUGO, + lpfc_num_discovered_ports_show, NULL); ++static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL); + static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); + static DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL); + static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, +@@ -958,6 +1516,17 @@ static DEVICE_ATTR(lpfc_temp_sensor, S_I + + static char *lpfc_soft_wwn_key = "C99G71SL8032A"; + ++/** ++ * lpfc_soft_wwn_enable_store: Allows setting of the wwn if the key is valid. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: containing the string lpfc_soft_wwn_key. ++ * @count: must be size of lpfc_soft_wwn_key. ++ * ++ * Returns: ++ * -EINVAL if the buffer does not contain lpfc_soft_wwn_key ++ * length of buf indicates success ++ **/ + static ssize_t + lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -994,6 +1563,14 @@ lpfc_soft_wwn_enable_store(struct device + static DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, + lpfc_soft_wwn_enable_store); + ++/** ++ * lpfc_soft_wwpn_show: Return the cfg soft ww port name of the adapter. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the wwpn in hexidecimal. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -1006,7 +1583,19 @@ lpfc_soft_wwpn_show(struct device *dev, + (unsigned long long)phba->cfg_soft_wwpn); + } + +- ++/** ++ * lpfc_soft_wwpn_store: Set the ww port name of the adapter. ++ * @dev class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: contains the wwpn in hexidecimal. ++ * @count: number of wwpn bytes in buf ++ * ++ * Returns: ++ * -EACCES hba reset not enabled, adapter over temp ++ * -EINVAL soft wwn not enabled, count is invalid, invalid wwpn byte invalid ++ * -EIO error taking adapter offline or online ++ * value of count on success ++ **/ + static ssize_t + lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -1080,6 +1669,14 @@ lpfc_soft_wwpn_store(struct device *dev, + static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\ + lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); + ++/** ++ * lpfc_soft_wwnn_show: Return the cfg soft ww node name for the adapter. ++ * @dev: class device that is converted into a Scsi_host. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the wwnn in hexidecimal. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -1090,7 +1687,16 @@ lpfc_soft_wwnn_show(struct device *dev, + (unsigned long long)phba->cfg_soft_wwnn); + } + +- ++/** ++ * lpfc_soft_wwnn_store: sets the ww node name of the adapter. ++ * @cdev: class device that is converted into a Scsi_host. ++ * @buf: contains the ww node name in hexidecimal. ++ * @count: number of wwnn bytes in buf. ++ * ++ * Returns: ++ * -EINVAL soft wwn not enabled, count is invalid, invalid wwnn byte invalid ++ * value of count on success ++ **/ + static ssize_t + lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +@@ -1178,6 +1784,15 @@ module_param(lpfc_nodev_tmo, int, 0); + MODULE_PARM_DESC(lpfc_nodev_tmo, + "Seconds driver will hold I/O waiting " + "for a device to come back"); ++ ++/** ++ * lpfc_nodev_tmo_show: Return the hba dev loss timeout value. ++ * @dev: class converted to a Scsi_host structure. ++ * @attr: device attribute, not used. ++ * @buf: on return contains the dev loss timeout in decimal. ++ * ++ * Returns: size of formatted string. ++ **/ + static ssize_t + lpfc_nodev_tmo_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -1189,6 +1804,21 @@ lpfc_nodev_tmo_show(struct device *dev, + return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo); + } + ++/** ++ * lpfc_nodev_tmo_init: Set the hba nodev timeout value. ++ * @vport: lpfc vport structure pointer. ++ * @val: contains the nodev timeout value. ++ * ++ * Description: ++ * If the devloss tmo is already set then nodev tmo is set to devloss tmo, ++ * a kernel error message is printed and zero is returned. ++ * Else if val is in range then nodev tmo and devloss tmo are set to val. ++ * Otherwise nodev tmo is set to the default value. ++ * ++ * Returns: ++ * zero if already set or if val is in range ++ * -EINVAL val out of range ++ **/ + static int + lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val) + { +@@ -1196,7 +1826,7 @@ lpfc_nodev_tmo_init(struct lpfc_vport *v + vport->cfg_nodev_tmo = vport->cfg_devloss_tmo; + if (val != LPFC_DEF_DEVLOSS_TMO) + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0402 Ignoring nodev_tmo module " ++ "0407 Ignoring nodev_tmo module " + "parameter because devloss_tmo is " + "set.\n"); + return 0; +@@ -1215,6 +1845,13 @@ lpfc_nodev_tmo_init(struct lpfc_vport *v + return -EINVAL; + } + ++/** ++ * lpfc_update_rport_devloss_tmo: Update dev loss tmo value. ++ * @vport: lpfc vport structure pointer. ++ * ++ * Description: ++ * Update all the ndlp's dev loss tmo with the vport devloss tmo value. ++ **/ + static void + lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) + { +@@ -1229,6 +1866,21 @@ lpfc_update_rport_devloss_tmo(struct lpf + spin_unlock_irq(shost->host_lock); + } + ++/** ++ * lpfc_nodev_tmo_set: Set the vport nodev tmo and devloss tmo values. ++ * @vport: lpfc vport structure pointer. ++ * @val: contains the tmo value. ++ * ++ * Description: ++ * If the devloss tmo is already set or the vport dev loss tmo has changed ++ * then a kernel error message is printed and zero is returned. ++ * Else if val is in range then nodev tmo and devloss tmo are set to val. ++ * Otherwise nodev tmo is set to the default value. ++ * ++ * Returns: ++ * zero if already set or if val is in range ++ * -EINVAL val out of range ++ **/ + static int + lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val) + { +@@ -1269,6 +1921,21 @@ MODULE_PARM_DESC(lpfc_devloss_tmo, + lpfc_vport_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO, + LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO) + lpfc_vport_param_show(devloss_tmo) ++ ++/** ++ * lpfc_devloss_tmo_set: Sets vport nodev tmo, devloss tmo values, changed bit. ++ * @vport: lpfc vport structure pointer. ++ * @val: contains the tmo value. ++ * ++ * Description: ++ * If val is in a valid range then set the vport nodev tmo, ++ * devloss tmo, also set the vport dev loss tmo changed flag. ++ * Else a kernel error message is printed. ++ * ++ * Returns: ++ * zero if val is in range ++ * -EINVAL val out of range ++ **/ + static int + lpfc_devloss_tmo_set(struct lpfc_vport *vport, int val) + { +@@ -1366,12 +2033,27 @@ MODULE_PARM_DESC(lpfc_restrict_login, + "Restrict virtual ports login to remote initiators."); + lpfc_vport_param_show(restrict_login); + ++/** ++ * lpfc_restrict_login_init: Set the vport restrict login flag. ++ * @vport: lpfc vport structure pointer. ++ * @val: contains the restrict login value. ++ * ++ * Description: ++ * If val is not in a valid range then log a kernel error message and set ++ * the vport restrict login to one. ++ * If the port type is physical clear the restrict login flag and return. ++ * Else set the restrict login flag to val. ++ * ++ * Returns: ++ * zero if val is in range ++ * -EINVAL val out of range ++ **/ + static int + lpfc_restrict_login_init(struct lpfc_vport *vport, int val) + { + if (val < 0 || val > 1) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0449 lpfc_restrict_login attribute cannot " ++ "0422 lpfc_restrict_login attribute cannot " + "be set to %d, allowed range is [0, 1]\n", + val); + vport->cfg_restrict_login = 1; +@@ -1385,12 +2067,28 @@ lpfc_restrict_login_init(struct lpfc_vpo + return 0; + } + ++/** ++ * lpfc_restrict_login_set: Set the vport restrict login flag. ++ * @vport: lpfc vport structure pointer. ++ * @val: contains the restrict login value. ++ * ++ * Description: ++ * If val is not in a valid range then log a kernel error message and set ++ * the vport restrict login to one. ++ * If the port type is physical and the val is not zero log a kernel ++ * error message, clear the restrict login flag and return zero. ++ * Else set the restrict login flag to val. ++ * ++ * Returns: ++ * zero if val is in range ++ * -EINVAL val out of range ++ **/ + static int + lpfc_restrict_login_set(struct lpfc_vport *vport, int val) + { + if (val < 0 || val > 1) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0450 lpfc_restrict_login attribute cannot " ++ "0425 lpfc_restrict_login attribute cannot " + "be set to %d, allowed range is [0, 1]\n", + val); + vport->cfg_restrict_login = 1; +@@ -1441,6 +2139,23 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1, + # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6]. + # Default value is 0. + */ ++ ++/** ++ * lpfc_topology_set: Set the adapters topology field. ++ * @phba: lpfc_hba pointer. ++ * @val: topology value. ++ * ++ * Description: ++ * If val is in a valid range then set the adapter's topology field and ++ * issue a lip; if the lip fails reset the topology to the old value. ++ * ++ * If the value is not in range log a kernel error message and return an error. ++ * ++ * Returns: ++ * zero if val is in range and lip okay ++ * non-zero return value from lpfc_issue_lip() ++ * -EINVAL val out of range ++ **/ + static int + lpfc_topology_set(struct lpfc_hba *phba, int val) + { +@@ -1469,6 +2184,335 @@ lpfc_param_store(topology) + static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, + lpfc_topology_show, lpfc_topology_store); + ++ ++/** ++ * lpfc_stat_data_ctrl_store: write call back for lpfc_stat_data_ctrl ++ * sysfs file. ++ * @dev: Pointer to class device. ++ * @buf: Data buffer. ++ * @count: Size of the data buffer. ++ * ++ * This function get called when an user write to the lpfc_stat_data_ctrl ++ * sysfs file. This function parse the command written to the sysfs file ++ * and take appropriate action. These commands are used for controlling ++ * driver statistical data collection. ++ * Following are the command this function handles. ++ * ++ * setbucket ++ * = Set the latency buckets. ++ * destroybucket = destroy all the buckets. ++ * start = start data collection ++ * stop = stop data collection ++ * reset = reset the collected data ++ **/ ++static ssize_t ++lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++#define LPFC_MAX_DATA_CTRL_LEN 1024 ++ static char bucket_data[LPFC_MAX_DATA_CTRL_LEN]; ++ unsigned long i; ++ char *str_ptr, *token; ++ struct lpfc_vport **vports; ++ struct Scsi_Host *v_shost; ++ char *bucket_type_str, *base_str, *step_str; ++ unsigned long base, step, bucket_type; ++ ++ if (!strncmp(buf, "setbucket", strlen("setbucket"))) { ++ if (strlen(buf) > LPFC_MAX_DATA_CTRL_LEN) ++ return -EINVAL; ++ ++ strcpy(bucket_data, buf); ++ str_ptr = &bucket_data[0]; ++ /* Ignore this token - this is command token */ ++ token = strsep(&str_ptr, "\t "); ++ if (!token) ++ return -EINVAL; ++ ++ bucket_type_str = strsep(&str_ptr, "\t "); ++ if (!bucket_type_str) ++ return -EINVAL; ++ ++ if (!strncmp(bucket_type_str, "linear", strlen("linear"))) ++ bucket_type = LPFC_LINEAR_BUCKET; ++ else if (!strncmp(bucket_type_str, "power2", strlen("power2"))) ++ bucket_type = LPFC_POWER2_BUCKET; ++ else ++ return -EINVAL; ++ ++ base_str = strsep(&str_ptr, "\t "); ++ if (!base_str) ++ return -EINVAL; ++ base = simple_strtoul(base_str, NULL, 0); ++ ++ step_str = strsep(&str_ptr, "\t "); ++ if (!step_str) ++ return -EINVAL; ++ step = simple_strtoul(step_str, NULL, 0); ++ if (!step) ++ return -EINVAL; ++ ++ /* Block the data collection for every vport */ ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports == NULL) ++ return -ENOMEM; ++ ++ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { ++ v_shost = lpfc_shost_from_vport(vports[i]); ++ spin_lock_irq(v_shost->host_lock); ++ /* Block and reset data collection */ ++ vports[i]->stat_data_blocked = 1; ++ if (vports[i]->stat_data_enabled) ++ lpfc_vport_reset_stat_data(vports[i]); ++ spin_unlock_irq(v_shost->host_lock); ++ } ++ ++ /* Set the bucket attributes */ ++ phba->bucket_type = bucket_type; ++ phba->bucket_base = base; ++ phba->bucket_step = step; ++ ++ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { ++ v_shost = lpfc_shost_from_vport(vports[i]); ++ ++ /* Unblock data collection */ ++ spin_lock_irq(v_shost->host_lock); ++ vports[i]->stat_data_blocked = 0; ++ spin_unlock_irq(v_shost->host_lock); ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++ return strlen(buf); ++ } ++ ++ if (!strncmp(buf, "destroybucket", strlen("destroybucket"))) { ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports == NULL) ++ return -ENOMEM; ++ ++ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { ++ v_shost = lpfc_shost_from_vport(vports[i]); ++ spin_lock_irq(shost->host_lock); ++ vports[i]->stat_data_blocked = 1; ++ lpfc_free_bucket(vport); ++ vport->stat_data_enabled = 0; ++ vports[i]->stat_data_blocked = 0; ++ spin_unlock_irq(shost->host_lock); ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++ phba->bucket_type = LPFC_NO_BUCKET; ++ phba->bucket_base = 0; ++ phba->bucket_step = 0; ++ return strlen(buf); ++ } ++ ++ if (!strncmp(buf, "start", strlen("start"))) { ++ /* If no buckets configured return error */ ++ if (phba->bucket_type == LPFC_NO_BUCKET) ++ return -EINVAL; ++ spin_lock_irq(shost->host_lock); ++ if (vport->stat_data_enabled) { ++ spin_unlock_irq(shost->host_lock); ++ return strlen(buf); ++ } ++ lpfc_alloc_bucket(vport); ++ vport->stat_data_enabled = 1; ++ spin_unlock_irq(shost->host_lock); ++ return strlen(buf); ++ } ++ ++ if (!strncmp(buf, "stop", strlen("stop"))) { ++ spin_lock_irq(shost->host_lock); ++ if (vport->stat_data_enabled == 0) { ++ spin_unlock_irq(shost->host_lock); ++ return strlen(buf); ++ } ++ lpfc_free_bucket(vport); ++ vport->stat_data_enabled = 0; ++ spin_unlock_irq(shost->host_lock); ++ return strlen(buf); ++ } ++ ++ if (!strncmp(buf, "reset", strlen("reset"))) { ++ if ((phba->bucket_type == LPFC_NO_BUCKET) ++ || !vport->stat_data_enabled) ++ return strlen(buf); ++ spin_lock_irq(shost->host_lock); ++ vport->stat_data_blocked = 1; ++ lpfc_vport_reset_stat_data(vport); ++ vport->stat_data_blocked = 0; ++ spin_unlock_irq(shost->host_lock); ++ return strlen(buf); ++ } ++ return -EINVAL; ++} ++ ++ ++/** ++ * lpfc_stat_data_ctrl_show: Read callback function for ++ * lpfc_stat_data_ctrl sysfs file. ++ * @dev: Pointer to class device object. ++ * @buf: Data buffer. ++ * ++ * This function is the read call back function for ++ * lpfc_stat_data_ctrl sysfs file. This function report the ++ * current statistical data collection state. ++ **/ ++static ssize_t ++lpfc_stat_data_ctrl_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ int index = 0; ++ int i; ++ char *bucket_type; ++ unsigned long bucket_value; ++ ++ switch (phba->bucket_type) { ++ case LPFC_LINEAR_BUCKET: ++ bucket_type = "linear"; ++ break; ++ case LPFC_POWER2_BUCKET: ++ bucket_type = "power2"; ++ break; ++ default: ++ bucket_type = "No Bucket"; ++ break; ++ } ++ ++ sprintf(&buf[index], "Statistical Data enabled :%d, " ++ "blocked :%d, Bucket type :%s, Bucket base :%d," ++ " Bucket step :%d\nLatency Ranges :", ++ vport->stat_data_enabled, vport->stat_data_blocked, ++ bucket_type, phba->bucket_base, phba->bucket_step); ++ index = strlen(buf); ++ if (phba->bucket_type != LPFC_NO_BUCKET) { ++ for (i = 0; i < LPFC_MAX_BUCKET_COUNT; i++) { ++ if (phba->bucket_type == LPFC_LINEAR_BUCKET) ++ bucket_value = phba->bucket_base + ++ phba->bucket_step * i; ++ else ++ bucket_value = phba->bucket_base + ++ (1 << i) * phba->bucket_step; ++ ++ if (index + 10 > PAGE_SIZE) ++ break; ++ sprintf(&buf[index], "%08ld ", bucket_value); ++ index = strlen(buf); ++ } ++ } ++ sprintf(&buf[index], "\n"); ++ return strlen(buf); ++} ++ ++/* ++ * Sysfs attribute to control the statistical data collection. ++ */ ++static DEVICE_ATTR(lpfc_stat_data_ctrl, S_IRUGO | S_IWUSR, ++ lpfc_stat_data_ctrl_show, lpfc_stat_data_ctrl_store); ++ ++/* ++ * lpfc_drvr_stat_data: sysfs attr to get driver statistical data. ++ */ ++ ++/* ++ * Each Bucket takes 11 characters and 1 new line + 17 bytes WWN ++ * for each target. ++ */ ++#define STAT_DATA_SIZE_PER_TARGET(NUM_BUCKETS) ((NUM_BUCKETS) * 11 + 18) ++#define MAX_STAT_DATA_SIZE_PER_TARGET \ ++ STAT_DATA_SIZE_PER_TARGET(LPFC_MAX_BUCKET_COUNT) ++ ++ ++/** ++ * sysfs_drvr_stat_data_read: Read callback function for lpfc_drvr_stat_data ++ * sysfs attribute. ++ * @kobj: Pointer to the kernel object ++ * @bin_attr: Attribute object ++ * @buff: Buffer pointer ++ * @off: File offset ++ * @count: Buffer size ++ * ++ * This function is the read call back function for lpfc_drvr_stat_data ++ * sysfs file. This function export the statistical data to user ++ * applications. ++ **/ ++static ssize_t ++sysfs_drvr_stat_data_read(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct device *dev = container_of(kobj, struct device, ++ kobj); ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ int i = 0, index = 0; ++ unsigned long nport_index; ++ struct lpfc_nodelist *ndlp = NULL; ++ nport_index = (unsigned long)off / ++ MAX_STAT_DATA_SIZE_PER_TARGET; ++ ++ if (!vport->stat_data_enabled || vport->stat_data_blocked ++ || (phba->bucket_type == LPFC_NO_BUCKET)) ++ return 0; ++ ++ spin_lock_irq(shost->host_lock); ++ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { ++ if (!NLP_CHK_NODE_ACT(ndlp) || !ndlp->lat_data) ++ continue; ++ ++ if (nport_index > 0) { ++ nport_index--; ++ continue; ++ } ++ ++ if ((index + MAX_STAT_DATA_SIZE_PER_TARGET) ++ > count) ++ break; ++ ++ if (!ndlp->lat_data) ++ continue; ++ ++ /* Print the WWN */ ++ sprintf(&buf[index], "%02x%02x%02x%02x%02x%02x%02x%02x:", ++ ndlp->nlp_portname.u.wwn[0], ++ ndlp->nlp_portname.u.wwn[1], ++ ndlp->nlp_portname.u.wwn[2], ++ ndlp->nlp_portname.u.wwn[3], ++ ndlp->nlp_portname.u.wwn[4], ++ ndlp->nlp_portname.u.wwn[5], ++ ndlp->nlp_portname.u.wwn[6], ++ ndlp->nlp_portname.u.wwn[7]); ++ ++ index = strlen(buf); ++ ++ for (i = 0; i < LPFC_MAX_BUCKET_COUNT; i++) { ++ sprintf(&buf[index], "%010u,", ++ ndlp->lat_data[i].cmd_count); ++ index = strlen(buf); ++ } ++ sprintf(&buf[index], "\n"); ++ index = strlen(buf); ++ } ++ spin_unlock_irq(shost->host_lock); ++ return index; ++} ++ ++static struct bin_attribute sysfs_drvr_stat_data_attr = { ++ .attr = { ++ .name = "lpfc_drvr_stat_data", ++ .mode = S_IRUSR, ++ .owner = THIS_MODULE, ++ }, ++ .size = LPFC_MAX_TARGET * MAX_STAT_DATA_SIZE_PER_TARGET, ++ .read = sysfs_drvr_stat_data_read, ++ .write = NULL, ++}; ++ + /* + # lpfc_link_speed: Link speed selection for initializing the Fibre Channel + # connection. +@@ -1479,6 +2523,24 @@ static DEVICE_ATTR(lpfc_topology, S_IRUG + # 8 = 8 Gigabaud + # Value range is [0,8]. Default value is 0. + */ ++ ++/** ++ * lpfc_link_speed_set: Set the adapters link speed. ++ * @phba: lpfc_hba pointer. ++ * @val: link speed value. ++ * ++ * Description: ++ * If val is in a valid range then set the adapter's link speed field and ++ * issue a lip; if the lip fails reset the link speed to the old value. ++ * ++ * Notes: ++ * If the value is not in range log a kernel error message and return an error. ++ * ++ * Returns: ++ * zero if val is in range and lip okay. ++ * non-zero return value from lpfc_issue_lip() ++ * -EINVAL val out of range ++ **/ + static int + lpfc_link_speed_set(struct lpfc_hba *phba, int val) + { +@@ -1513,6 +2575,23 @@ static int lpfc_link_speed = 0; + module_param(lpfc_link_speed, int, 0); + MODULE_PARM_DESC(lpfc_link_speed, "Select link speed"); + lpfc_param_show(link_speed) ++ ++/** ++ * lpfc_link_speed_init: Set the adapters link speed. ++ * @phba: lpfc_hba pointer. ++ * @val: link speed value. ++ * ++ * Description: ++ * If val is in a valid range then set the adapter's link speed field. ++ * ++ * Notes: ++ * If the value is not in range log a kernel error message, clear the link ++ * speed and return an error. ++ * ++ * Returns: ++ * zero if val saved. ++ * -EINVAL val out of range ++ **/ + static int + lpfc_link_speed_init(struct lpfc_hba *phba, int val) + { +@@ -1522,7 +2601,7 @@ lpfc_link_speed_init(struct lpfc_hba *ph + return 0; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0454 lpfc_link_speed attribute cannot " ++ "0405 lpfc_link_speed attribute cannot " + "be set to %d, allowed values are " + "["LPFC_LINK_SPEED_STRING"]\n", val); + phba->cfg_link_speed = 0; +@@ -1548,6 +2627,48 @@ LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1, + "Use ADISC on rediscovery to authenticate FCP devices"); + + /* ++# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue ++# depth. Default value is 0. When the value of this parameter is zero the ++# SCSI command completion time is not used for controlling I/O queue depth. When ++# the parameter is set to a non-zero value, the I/O queue depth is controlled ++# to limit the I/O completion time to the parameter value. ++# The value is set in milliseconds. ++*/ ++static int lpfc_max_scsicmpl_time; ++module_param(lpfc_max_scsicmpl_time, int, 0); ++MODULE_PARM_DESC(lpfc_max_scsicmpl_time, ++ "Use command completion time to control queue depth"); ++lpfc_vport_param_show(max_scsicmpl_time); ++lpfc_vport_param_init(max_scsicmpl_time, 0, 0, 60000); ++static int ++lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_nodelist *ndlp, *next_ndlp; ++ ++ if (val == vport->cfg_max_scsicmpl_time) ++ return 0; ++ if ((val < 0) || (val > 60000)) ++ return -EINVAL; ++ vport->cfg_max_scsicmpl_time = val; ++ ++ spin_lock_irq(shost->host_lock); ++ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { ++ if (!NLP_CHK_NODE_ACT(ndlp)) ++ continue; ++ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) ++ continue; ++ ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; ++ } ++ spin_unlock_irq(shost->host_lock); ++ return 0; ++} ++lpfc_vport_param_store(max_scsicmpl_time); ++static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR, ++ lpfc_max_scsicmpl_time_show, ++ lpfc_max_scsicmpl_time_store); ++ ++/* + # lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value + # range is [0,1]. Default value is 0. + */ +@@ -1623,12 +2744,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, + /* + # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that + # support this feature +-# 0 = MSI disabled (default) ++# 0 = MSI disabled + # 1 = MSI enabled +-# 2 = MSI-X enabled +-# Value range is [0,2]. Default value is 0. ++# 2 = MSI-X enabled (default) ++# Value range is [0,2]. Default value is 2. + */ +-LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " ++LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " + "MSI-X (2), if possible"); + + /* +@@ -1668,6 +2789,7 @@ struct device_attribute *lpfc_hba_attrs[ + &dev_attr_option_rom_version, + &dev_attr_link_state, + &dev_attr_num_discovered_ports, ++ &dev_attr_menlo_mgmt_mode, + &dev_attr_lpfc_drvr_version, + &dev_attr_lpfc_temp_sensor, + &dev_attr_lpfc_log_verbose, +@@ -1709,6 +2831,8 @@ struct device_attribute *lpfc_hba_attrs[ + &dev_attr_lpfc_enable_hba_reset, + &dev_attr_lpfc_enable_hba_heartbeat, + &dev_attr_lpfc_sg_seg_cnt, ++ &dev_attr_lpfc_max_scsicmpl_time, ++ &dev_attr_lpfc_stat_data_ctrl, + NULL, + }; + +@@ -1731,9 +2855,29 @@ struct device_attribute *lpfc_vport_attr + &dev_attr_nport_evt_cnt, + &dev_attr_npiv_info, + &dev_attr_lpfc_enable_da_id, ++ &dev_attr_lpfc_max_scsicmpl_time, ++ &dev_attr_lpfc_stat_data_ctrl, + NULL, + }; + ++/** ++ * sysfs_ctlreg_write: Write method for writing to ctlreg. ++ * @kobj: kernel kobject that contains the kernel class device. ++ * @bin_attr: kernel attributes passed to us. ++ * @buf: contains the data to be written to the adapter IOREG space. ++ * @off: offset into buffer to beginning of data. ++ * @count: bytes to transfer. ++ * ++ * Description: ++ * Accessed via /sys/class/scsi_host/hostxxx/ctlreg. ++ * Uses the adapter io control registers to send buf contents to the adapter. ++ * ++ * Returns: ++ * -ERANGE off and count combo out of range ++ * -EINVAL off, count or buff address invalid ++ * -EPERM adapter is offline ++ * value of count, buf contents written ++ **/ + static ssize_t + sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +@@ -1766,6 +2910,23 @@ sysfs_ctlreg_write(struct kobject *kobj, + return count; + } + ++/** ++ * sysfs_ctlreg_read: Read method for reading from ctlreg. ++ * @kobj: kernel kobject that contains the kernel class device. ++ * @bin_attr: kernel attributes passed to us. ++ * @buf: if succesful contains the data from the adapter IOREG space. ++ * @off: offset into buffer to beginning of data. ++ * @count: bytes to transfer. ++ * ++ * Description: ++ * Accessed via /sys/class/scsi_host/hostxxx/ctlreg. ++ * Uses the adapter io control registers to read data into buf. ++ * ++ * Returns: ++ * -ERANGE off and count combo out of range ++ * -EINVAL off, count or buff address invalid ++ * value of count, buf contents read ++ **/ + static ssize_t + sysfs_ctlreg_read(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +@@ -1810,7 +2971,10 @@ static struct bin_attribute sysfs_ctlreg + .write = sysfs_ctlreg_write, + }; + +- ++/** ++ * sysfs_mbox_idle: frees the sysfs mailbox. ++ * @phba: lpfc_hba pointer ++ **/ + static void + sysfs_mbox_idle(struct lpfc_hba *phba) + { +@@ -1824,6 +2988,27 @@ sysfs_mbox_idle(struct lpfc_hba *phba) + } + } + ++/** ++ * sysfs_mbox_write: Write method for writing information via mbox. ++ * @kobj: kernel kobject that contains the kernel class device. ++ * @bin_attr: kernel attributes passed to us. ++ * @buf: contains the data to be written to sysfs mbox. ++ * @off: offset into buffer to beginning of data. ++ * @count: bytes to transfer. ++ * ++ * Description: ++ * Accessed via /sys/class/scsi_host/hostxxx/mbox. ++ * Uses the sysfs mbox to send buf contents to the adapter. ++ * ++ * Returns: ++ * -ERANGE off and count combo out of range ++ * -EINVAL off, count or buff address invalid ++ * zero if count is zero ++ * -EPERM adapter is offline ++ * -ENOMEM failed to allocate memory for the mail box ++ * -EAGAIN offset, state or mbox is NULL ++ * count number of bytes transferred ++ **/ + static ssize_t + sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +@@ -1878,6 +3063,29 @@ sysfs_mbox_write(struct kobject *kobj, s + return count; + } + ++/** ++ * sysfs_mbox_read: Read method for reading information via mbox. ++ * @kobj: kernel kobject that contains the kernel class device. ++ * @bin_attr: kernel attributes passed to us. ++ * @buf: contains the data to be read from sysfs mbox. ++ * @off: offset into buffer to beginning of data. ++ * @count: bytes to transfer. ++ * ++ * Description: ++ * Accessed via /sys/class/scsi_host/hostxxx/mbox. ++ * Uses the sysfs mbox to receive data from to the adapter. ++ * ++ * Returns: ++ * -ERANGE off greater than mailbox command size ++ * -EINVAL off, count or buff address invalid ++ * zero if off and count are zero ++ * -EACCES adapter over temp ++ * -EPERM garbage can value to catch a multitude of errors ++ * -EAGAIN management IO not permitted, state or off error ++ * -ETIME mailbox timeout ++ * -ENODEV mailbox error ++ * count number of bytes transferred ++ **/ + static ssize_t + sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +@@ -1954,6 +3162,8 @@ sysfs_mbox_read(struct kobject *kobj, st + case MBX_DEL_LD_ENTRY: + case MBX_SET_VARIABLE: + case MBX_WRITE_WWN: ++ case MBX_PORT_CAPABILITIES: ++ case MBX_PORT_IOV_CONTROL: + break; + case MBX_READ_SPARM64: + case MBX_READ_LA: +@@ -1978,17 +3188,15 @@ sysfs_mbox_read(struct kobject *kobj, st + /* If HBA encountered an error attention, allow only DUMP + * or RESTART mailbox commands until the HBA is restarted. + */ +- if ((phba->pport->stopped) && +- (phba->sysfs_mbox.mbox->mb.mbxCommand != +- MBX_DUMP_MEMORY && +- phba->sysfs_mbox.mbox->mb.mbxCommand != +- MBX_RESTART && +- phba->sysfs_mbox.mbox->mb.mbxCommand != +- MBX_WRITE_VPARMS)) { +- sysfs_mbox_idle(phba); +- spin_unlock_irq(&phba->hbalock); +- return -EPERM; +- } ++ if (phba->pport->stopped && ++ phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_DUMP_MEMORY && ++ phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_RESTART && ++ phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_VPARMS && ++ phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_WWN) ++ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, ++ "1259 mbox: Issued mailbox cmd " ++ "0x%x while in stopped state.\n", ++ phba->sysfs_mbox.mbox->mb.mbxCommand); + + phba->sysfs_mbox.mbox->vport = vport; + +@@ -2059,6 +3267,14 @@ static struct bin_attribute sysfs_mbox_a + .write = sysfs_mbox_write, + }; + ++/** ++ * lpfc_alloc_sysfs_attr: Creates the ctlreg and mbox entries. ++ * @vport: address of lpfc vport structure. ++ * ++ * Return codes: ++ * zero on success ++ * error return code from sysfs_create_bin_file() ++ **/ + int + lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) + { +@@ -2075,18 +3291,30 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport + if (error) + goto out_remove_ctlreg_attr; + ++ error = sysfs_create_bin_file(&shost->shost_dev.kobj, ++ &sysfs_drvr_stat_data_attr); ++ if (error) ++ goto out_remove_mbox_attr; ++ + return 0; ++out_remove_mbox_attr: ++ sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); + out_remove_ctlreg_attr: + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); + out: + return error; + } + ++/** ++ * lpfc_free_sysfs_attr: Removes the ctlreg and mbox entries. ++ * @vport: address of lpfc vport structure. ++ **/ + void + lpfc_free_sysfs_attr(struct lpfc_vport *vport) + { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); +- ++ sysfs_remove_bin_file(&shost->shost_dev.kobj, ++ &sysfs_drvr_stat_data_attr); + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); + } +@@ -2096,6 +3324,10 @@ lpfc_free_sysfs_attr(struct lpfc_vport * + * Dynamic FC Host Attributes Support + */ + ++/** ++ * lpfc_get_host_port_id: Copy the vport DID into the scsi host port id. ++ * @shost: kernel scsi host pointer. ++ **/ + static void + lpfc_get_host_port_id(struct Scsi_Host *shost) + { +@@ -2105,6 +3337,10 @@ lpfc_get_host_port_id(struct Scsi_Host * + fc_host_port_id(shost) = vport->fc_myDID; + } + ++/** ++ * lpfc_get_host_port_type: Set the value of the scsi host port type. ++ * @shost: kernel scsi host pointer. ++ **/ + static void + lpfc_get_host_port_type(struct Scsi_Host *shost) + { +@@ -2133,6 +3369,10 @@ lpfc_get_host_port_type(struct Scsi_Host + spin_unlock_irq(shost->host_lock); + } + ++/** ++ * lpfc_get_host_port_state: Set the value of the scsi host port state. ++ * @shost: kernel scsi host pointer. ++ **/ + static void + lpfc_get_host_port_state(struct Scsi_Host *shost) + { +@@ -2167,6 +3407,10 @@ lpfc_get_host_port_state(struct Scsi_Hos + spin_unlock_irq(shost->host_lock); + } + ++/** ++ * lpfc_get_host_speed: Set the value of the scsi host speed. ++ * @shost: kernel scsi host pointer. ++ **/ + static void + lpfc_get_host_speed(struct Scsi_Host *shost) + { +@@ -2199,6 +3443,10 @@ lpfc_get_host_speed(struct Scsi_Host *sh + spin_unlock_irq(shost->host_lock); + } + ++/** ++ * lpfc_get_host_fabric_name: Set the value of the scsi host fabric name. ++ * @shost: kernel scsi host pointer. ++ **/ + static void + lpfc_get_host_fabric_name (struct Scsi_Host *shost) + { +@@ -2221,6 +3469,18 @@ lpfc_get_host_fabric_name (struct Scsi_H + fc_host_fabric_name(shost) = node_name; + } + ++/** ++ * lpfc_get_stats: Return statistical information about the adapter. ++ * @shost: kernel scsi host pointer. ++ * ++ * Notes: ++ * NULL on error for link down, no mbox pool, sli2 active, ++ * management not allowed, memory allocation error, or mbox error. ++ * ++ * Returns: ++ * NULL for error ++ * address of the adapter host statistics ++ **/ + static struct fc_host_statistics * + lpfc_get_stats(struct Scsi_Host *shost) + { +@@ -2334,6 +3594,10 @@ lpfc_get_stats(struct Scsi_Host *shost) + return hs; + } + ++/** ++ * lpfc_reset_stats: Copy the adapter link stats information. ++ * @shost: kernel scsi host pointer. ++ **/ + static void + lpfc_reset_stats(struct Scsi_Host *shost) + { +@@ -2411,6 +3675,14 @@ lpfc_reset_stats(struct Scsi_Host *shost + * are no sysfs handlers for link_down_tmo. + */ + ++/** ++ * lpfc_get_node_by_target: Return the nodelist for a target. ++ * @starget: kernel scsi target pointer. ++ * ++ * Returns: ++ * address of the node list if found ++ * NULL target not found ++ **/ + static struct lpfc_nodelist * + lpfc_get_node_by_target(struct scsi_target *starget) + { +@@ -2432,6 +3704,10 @@ lpfc_get_node_by_target(struct scsi_targ + return NULL; + } + ++/** ++ * lpfc_get_starget_port_id: Set the target port id to the ndlp DID or -1. ++ * @starget: kernel scsi target pointer. ++ **/ + static void + lpfc_get_starget_port_id(struct scsi_target *starget) + { +@@ -2440,6 +3716,12 @@ lpfc_get_starget_port_id(struct scsi_tar + fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1; + } + ++/** ++ * lpfc_get_starget_node_name: Set the target node name. ++ * @starget: kernel scsi target pointer. ++ * ++ * Description: Set the target node name to the ndlp node name wwn or zero. ++ **/ + static void + lpfc_get_starget_node_name(struct scsi_target *starget) + { +@@ -2449,6 +3731,12 @@ lpfc_get_starget_node_name(struct scsi_t + ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0; + } + ++/** ++ * lpfc_get_starget_port_name: Set the target port name. ++ * @starget: kernel scsi target pointer. ++ * ++ * Description: set the target port name to the ndlp port name wwn or zero. ++ **/ + static void + lpfc_get_starget_port_name(struct scsi_target *starget) + { +@@ -2458,6 +3746,15 @@ lpfc_get_starget_port_name(struct scsi_t + ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0; + } + ++/** ++ * lpfc_set_rport_loss_tmo: Set the rport dev loss tmo. ++ * @rport: fc rport address. ++ * @timeout: new value for dev loss tmo. ++ * ++ * Description: ++ * If timeout is non zero set the dev_loss_tmo to timeout, else set ++ * dev_loss_tmo to one. ++ **/ + static void + lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) + { +@@ -2467,7 +3764,18 @@ lpfc_set_rport_loss_tmo(struct fc_rport + rport->dev_loss_tmo = 1; + } + +- ++/** ++ * lpfc_rport_show_function: Return rport target information. ++ * ++ * Description: ++ * Macro that uses field to generate a function with the name lpfc_show_rport_ ++ * ++ * lpfc_show_rport_##field: returns the bytes formatted in buf ++ * @cdev: class converted to an fc_rport. ++ * @buf: on return contains the target_field or zero. ++ * ++ * Returns: size of formatted string. ++ **/ + #define lpfc_rport_show_function(field, format_string, sz, cast) \ + static ssize_t \ + lpfc_show_rport_##field (struct device *dev, \ +@@ -2602,6 +3910,10 @@ struct fc_function_template lpfc_vport_t + .vport_disable = lpfc_vport_disable, + }; + ++/** ++ * lpfc_get_cfgparam: Used during probe_one to init the adapter structure. ++ * @phba: lpfc_hba pointer. ++ **/ + void + lpfc_get_cfgparam(struct lpfc_hba *phba) + { +@@ -2637,6 +3949,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) + return; + } + ++/** ++ * lpfc_get_vport_cfgparam: Used during port create, init the vport structure. ++ * @vport: lpfc_vport pointer. ++ **/ + void + lpfc_get_vport_cfgparam(struct lpfc_vport *vport) + { +@@ -2648,6 +3964,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vpor + lpfc_restrict_login_init(vport, lpfc_restrict_login); + lpfc_fcp_class_init(vport, lpfc_fcp_class); + lpfc_use_adisc_init(vport, lpfc_use_adisc); ++ lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time); + lpfc_fdmi_on_init(vport, lpfc_fdmi_on); + lpfc_discovery_threads_init(vport, lpfc_discovery_threads); + lpfc_max_luns_init(vport, lpfc_max_luns); +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param); ++typedef int (*node_filter)(struct lpfc_nodelist *, void *); + + struct fc_rport; + void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); +@@ -26,11 +26,11 @@ void lpfc_read_nv(struct lpfc_hba *, LPF + void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + + void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); +-int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, +- struct lpfc_dmabuf *mp); ++int lpfc_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *); + void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); +-void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport); ++void lpfc_issue_clear_la(struct lpfc_hba *, struct lpfc_vport *); + void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); ++int lpfc_config_msi(struct lpfc_hba *, LPFC_MBOXQ_t *); + int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); + void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); +@@ -43,7 +43,7 @@ void lpfc_unreg_vpi(struct lpfc_hba *, u + void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); + + struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); +-void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); ++void lpfc_cleanup_rpis(struct lpfc_vport *, int); + int lpfc_linkdown(struct lpfc_hba *); + void lpfc_port_link_failure(struct lpfc_vport *); + void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); +@@ -135,7 +135,7 @@ void lpfc_ct_unsol_event(struct lpfc_hba + int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); + int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); + void lpfc_fdmi_tmo(unsigned long); +-void lpfc_fdmi_timeout_handler(struct lpfc_vport *vport); ++void lpfc_fdmi_timeout_handler(struct lpfc_vport *); + + int lpfc_config_port_prep(struct lpfc_hba *); + int lpfc_config_port_post(struct lpfc_hba *); +@@ -155,6 +155,8 @@ int lpfc_sli_queue_setup(struct lpfc_hba + void lpfc_handle_eratt(struct lpfc_hba *); + void lpfc_handle_latt(struct lpfc_hba *); + irqreturn_t lpfc_intr_handler(int, void *); ++irqreturn_t lpfc_sp_intr_handler(int, void *); ++irqreturn_t lpfc_fp_intr_handler(int, void *); + + void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); +@@ -175,11 +177,12 @@ void lpfc_mem_free(struct lpfc_hba *); + void lpfc_stop_vport_timers(struct lpfc_vport *); + + void lpfc_poll_timeout(unsigned long ptr); +-void lpfc_poll_start_timer(struct lpfc_hba * phba); +-void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba); ++void lpfc_poll_start_timer(struct lpfc_hba *); ++void lpfc_poll_eratt(unsigned long); ++void lpfc_sli_poll_fcp_ring(struct lpfc_hba *); + struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); +-void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); +-uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); ++void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); ++uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); + + void lpfc_reset_barrier(struct lpfc_hba * phba); + int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); +@@ -187,11 +190,13 @@ int lpfc_sli_brdkill(struct lpfc_hba *); + int lpfc_sli_brdreset(struct lpfc_hba *); + int lpfc_sli_brdrestart(struct lpfc_hba *); + int lpfc_sli_hba_setup(struct lpfc_hba *); ++int lpfc_sli_config_port(struct lpfc_hba *, int); + int lpfc_sli_host_down(struct lpfc_vport *); + int lpfc_sli_hba_down(struct lpfc_hba *); + int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + int lpfc_sli_handle_mb_event(struct lpfc_hba *); + int lpfc_sli_flush_mbox_queue(struct lpfc_hba *); ++int lpfc_sli_check_eratt(struct lpfc_hba *); + int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, + struct lpfc_sli_ring *, uint32_t); + void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); +@@ -199,6 +204,7 @@ int lpfc_sli_issue_iocb(struct lpfc_hba + struct lpfc_iocbq *, uint32_t); + void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); + void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); ++void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); + int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, + struct lpfc_dmabuf *); + struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, +@@ -226,17 +232,13 @@ struct lpfc_nodelist *lpfc_findnode_did( + struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, + struct lpfc_name *); + +-int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, +- uint32_t timeout); ++int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + +-int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, +- struct lpfc_sli_ring * pring, +- struct lpfc_iocbq * piocb, +- struct lpfc_iocbq * prspiocbq, +- uint32_t timeout); +-void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, +- struct lpfc_iocbq * cmdiocb, +- struct lpfc_iocbq * rspiocb); ++int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, struct lpfc_sli_ring *, ++ struct lpfc_iocbq *, struct lpfc_iocbq *, ++ uint32_t); ++void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *, ++ struct lpfc_iocbq *); + + void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); + +@@ -269,7 +271,7 @@ void lpfc_dev_loss_tmo_callbk(struct fc_ + + struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *); + int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable); +-void lpfc_mbx_unreg_vpi(struct lpfc_vport *); ++int lpfc_mbx_unreg_vpi(struct lpfc_vport *); + void destroy_port(struct lpfc_vport *); + int lpfc_get_instance(void); + void lpfc_host_attrib_init(struct Scsi_Host *); +@@ -290,6 +292,13 @@ void lpfc_unblock_fabric_iocbs(struct lp + void lpfc_adjust_queue_depth(struct lpfc_hba *); + void lpfc_ramp_down_queue_handler(struct lpfc_hba *); + void lpfc_ramp_up_queue_handler(struct lpfc_hba *); ++void lpfc_scsi_dev_block(struct lpfc_hba *); ++ ++void ++lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *, ++ struct lpfc_iocbq *); ++struct lpfc_fast_path_event *lpfc_alloc_fast_evt(struct lpfc_hba *); ++void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *); + + #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) + #define HBA_EVENT_RSCN 5 +--- a/drivers/scsi/lpfc/lpfc_ct.c ++++ b/drivers/scsi/lpfc/lpfc_ct.c +@@ -34,6 +34,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -134,25 +135,24 @@ lpfc_ct_unsol_event(struct lpfc_hba *phb + } + list_del(&head); + } else { +- struct lpfc_iocbq *next; +- +- list_for_each_entry_safe(iocbq, next, &piocbq->list, list) { ++ INIT_LIST_HEAD(&head); ++ list_add_tail(&head, &piocbq->list); ++ list_for_each_entry(iocbq, &head, list) { + icmd = &iocbq->iocb; + if (icmd->ulpBdeCount == 0) +- lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0); ++ lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0); + for (i = 0; i < icmd->ulpBdeCount; i++) { + paddr = getPaddr(icmd->un.cont64[i].addrHigh, + icmd->un.cont64[i].addrLow); + mp = lpfc_sli_ringpostbuf_get(phba, pring, + paddr); + size = icmd->un.cont64[i].tus.f.bdeSize; +- lpfc_ct_unsol_buffer(phba, piocbq, mp, size); ++ lpfc_ct_unsol_buffer(phba, iocbq, mp, size); + lpfc_in_buf_free(phba, mp); + } +- list_del(&iocbq->list); +- lpfc_sli_release_iocbq(phba, iocbq); + lpfc_post_buffer(phba, pring, i); + } ++ list_del(&head); + } + } + +@@ -212,7 +212,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, + else + list_add_tail(&mp->list, &mlist->list); + +- bpl->tus.f.bdeFlags = BUFF_USE_RCV; ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; + /* build buffer ptr list for IOCB */ + bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); +@@ -283,7 +283,7 @@ lpfc_gen_req(struct lpfc_vport *vport, s + icmd->un.genreq64.bdl.ulpIoTag32 = 0; + icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); + icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); +- icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BDL; ++ icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64)); + + if (usr_flg) +@@ -861,7 +861,7 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, stru + + retry++; + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, +- "0216 Retrying NS cmd %x\n", cmdcode); ++ "0250 Retrying NS cmd %x\n", cmdcode); + rc = lpfc_ns_cmd(vport, cmdcode, retry, 0); + if (rc == 0) + goto out; +--- a/drivers/scsi/lpfc/lpfc_debugfs.c ++++ b/drivers/scsi/lpfc/lpfc_debugfs.c +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2007 Emulex. All rights reserved. * ++ * Copyright (C) 2007-2008 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * +@@ -35,6 +35,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -46,13 +47,14 @@ + #include "lpfc_debugfs.h" + + #ifdef CONFIG_LPFC_DEBUG_FS +-/* debugfs interface ++/** ++ * debugfs interface + * + * To access this interface the user should: + * # mkdir /debug + * # mount -t debugfs none /debug + * +- * The lpfc debugfs directory hierachy is: ++ * The lpfc debugfs directory hierarchy is: + * lpfc/lpfcX/vportY + * where X is the lpfc hba unique_id + * where Y is the vport VPI on that hba +@@ -61,14 +63,21 @@ + * discovery_trace + * This is an ACSII readable file that contains a trace of the last + * lpfc_debugfs_max_disc_trc events that happened on a specific vport. +- * See lpfc_debugfs.h for different categories of +- * discovery events. To enable the discovery trace, the following +- * module parameters must be set: ++ * See lpfc_debugfs.h for different categories of discovery events. ++ * To enable the discovery trace, the following module parameters must be set: + * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support + * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for + * EACH vport. X MUST also be a power of 2. + * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in + * lpfc_debugfs.h . ++ * ++ * slow_ring_trace ++ * This is an ACSII readable file that contains a trace of the last ++ * lpfc_debugfs_max_slow_ring_trc events that happened on a specific HBA. ++ * To enable the slow ring trace, the following module parameters must be set: ++ * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support ++ * lpfc_debugfs_max_slow_ring_trc=X Where X is the event trace depth for ++ * the HBA. X MUST also be a power of 2. + */ + static int lpfc_debugfs_enable = 1; + module_param(lpfc_debugfs_enable, int, 0); +@@ -117,6 +126,25 @@ struct lpfc_debug { + static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0); + static unsigned long lpfc_debugfs_start_time = 0L; + ++/** ++ * lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer. ++ * @vport: The vport to gather the log info from. ++ * @buf: The buffer to dump log into. ++ * @size: The maximum amount of data to process. ++ * ++ * Description: ++ * This routine gathers the lpfc discovery debugfs data from the @vport and ++ * dumps it to @buf up to @size number of bytes. It will start at the next entry ++ * in the log and process the log until the end of the buffer. Then it will ++ * gather from the beginning of the log and process until the current entry. ++ * ++ * Notes: ++ * Discovery logging will be disabled while while this routine dumps the log. ++ * ++ * Return Value: ++ * This routine returns the amount of bytes that were dumped into @buf and will ++ * not exceed @size. ++ **/ + static int + lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) + { +@@ -125,7 +153,6 @@ lpfc_debugfs_disc_trc_data(struct lpfc_v + struct lpfc_debugfs_trc *dtp; + char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; + +- + enable = lpfc_debugfs_enable; + lpfc_debugfs_enable = 0; + +@@ -159,6 +186,25 @@ lpfc_debugfs_disc_trc_data(struct lpfc_v + return len; + } + ++/** ++ * lpfc_debugfs_slow_ring_trc_data - Dump slow ring logging to a buffer. ++ * @phba: The HBA to gather the log info from. ++ * @buf: The buffer to dump log into. ++ * @size: The maximum amount of data to process. ++ * ++ * Description: ++ * This routine gathers the lpfc slow ring debugfs data from the @phba and ++ * dumps it to @buf up to @size number of bytes. It will start at the next entry ++ * in the log and process the log until the end of the buffer. Then it will ++ * gather from the beginning of the log and process until the current entry. ++ * ++ * Notes: ++ * Slow ring logging will be disabled while while this routine dumps the log. ++ * ++ * Return Value: ++ * This routine returns the amount of bytes that were dumped into @buf and will ++ * not exceed @size. ++ **/ + static int + lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) + { +@@ -203,6 +249,25 @@ lpfc_debugfs_slow_ring_trc_data(struct l + + static int lpfc_debugfs_last_hbq = -1; + ++/** ++ * lpfc_debugfs_hbqinfo_data - Dump host buffer queue info to a buffer. ++ * @phba: The HBA to gather host buffer info from. ++ * @buf: The buffer to dump log into. ++ * @size: The maximum amount of data to process. ++ * ++ * Description: ++ * This routine dumps the host buffer queue info from the @phba to @buf up to ++ * @size number of bytes. A header that describes the current hbq state will be ++ * dumped to @buf first and then info on each hbq entry will be dumped to @buf ++ * until @size bytes have been dumped or all the hbq info has been dumped. ++ * ++ * Notes: ++ * This routine will rotate through each configured HBQ each time called. ++ * ++ * Return Value: ++ * This routine returns the amount of bytes that were dumped into @buf and will ++ * not exceed @size. ++ **/ + static int + lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) + { +@@ -303,6 +368,24 @@ skipit: + + static int lpfc_debugfs_last_hba_slim_off; + ++/** ++ * lpfc_debugfs_dumpHBASlim_data - Dump HBA SLIM info to a buffer. ++ * @phba: The HBA to gather SLIM info from. ++ * @buf: The buffer to dump log into. ++ * @size: The maximum amount of data to process. ++ * ++ * Description: ++ * This routine dumps the current contents of HBA SLIM for the HBA associated ++ * with @phba to @buf up to @size bytes of data. This is the raw HBA SLIM data. ++ * ++ * Notes: ++ * This routine will only dump up to 1024 bytes of data each time called and ++ * should be called multiple times to dump the entire HBA SLIM. ++ * ++ * Return Value: ++ * This routine returns the amount of bytes that were dumped into @buf and will ++ * not exceed @size. ++ **/ + static int + lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) + { +@@ -342,6 +425,21 @@ lpfc_debugfs_dumpHBASlim_data(struct lpf + return len; + } + ++/** ++ * lpfc_debugfs_dumpHostSlim_data - Dump host SLIM info to a buffer. ++ * @phba: The HBA to gather Host SLIM info from. ++ * @buf: The buffer to dump log into. ++ * @size: The maximum amount of data to process. ++ * ++ * Description: ++ * This routine dumps the current contents of host SLIM for the host associated ++ * with @phba to @buf up to @size bytes of data. The dump will contain the ++ * Mailbox, PCB, Rings, and Registers that are located in host memory. ++ * ++ * Return Value: ++ * This routine returns the amount of bytes that were dumped into @buf and will ++ * not exceed @size. ++ **/ + static int + lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) + { +@@ -357,7 +455,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lp + spin_lock_irq(&phba->hbalock); + + len += snprintf(buf+len, size-len, "SLIM Mailbox\n"); +- ptr = (uint32_t *)phba->slim2p; ++ ptr = (uint32_t *)phba->slim2p.virt; + i = sizeof(MAILBOX_t); + while (i > 0) { + len += snprintf(buf+len, size-len, +@@ -370,7 +468,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lp + } + + len += snprintf(buf+len, size-len, "SLIM PCB\n"); +- ptr = (uint32_t *)&phba->slim2p->pcb; ++ ptr = (uint32_t *)phba->pcb; + i = sizeof(PCB_t); + while (i > 0) { + len += snprintf(buf+len, size-len, +@@ -382,44 +480,16 @@ lpfc_debugfs_dumpHostSlim_data(struct lp + off += (8 * sizeof(uint32_t)); + } + +- pgpp = (struct lpfc_pgp *)&phba->slim2p->mbx.us.s3_pgp.port; +- pring = &psli->ring[0]; +- len += snprintf(buf+len, size-len, +- "Ring 0: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " +- "RSP PutInx:%d Max:%d\n", +- pgpp->cmdGetInx, pring->numCiocb, +- pring->next_cmdidx, pring->local_getidx, pring->flag, +- pgpp->rspPutInx, pring->numRiocb); +- pgpp++; +- +- pring = &psli->ring[1]; +- len += snprintf(buf+len, size-len, +- "Ring 1: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " +- "RSP PutInx:%d Max:%d\n", +- pgpp->cmdGetInx, pring->numCiocb, +- pring->next_cmdidx, pring->local_getidx, pring->flag, +- pgpp->rspPutInx, pring->numRiocb); +- pgpp++; +- +- pring = &psli->ring[2]; +- len += snprintf(buf+len, size-len, +- "Ring 2: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " +- "RSP PutInx:%d Max:%d\n", +- pgpp->cmdGetInx, pring->numCiocb, +- pring->next_cmdidx, pring->local_getidx, pring->flag, +- pgpp->rspPutInx, pring->numRiocb); +- pgpp++; +- +- pring = &psli->ring[3]; +- len += snprintf(buf+len, size-len, +- "Ring 3: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x) " +- "RSP PutInx:%d Max:%d\n", +- pgpp->cmdGetInx, pring->numCiocb, +- pring->next_cmdidx, pring->local_getidx, pring->flag, +- pgpp->rspPutInx, pring->numRiocb); +- +- +- ptr = (uint32_t *)&phba->slim2p->mbx.us.s3_pgp.hbq_get; ++ for (i = 0; i < 4; i++) { ++ pgpp = &phba->port_gp[i]; ++ pring = &psli->ring[i]; ++ len += snprintf(buf+len, size-len, ++ "Ring %d: CMD GetInx:%d (Max:%d Next:%d " ++ "Local:%d flg:x%x) RSP PutInx:%d Max:%d\n", ++ i, pgpp->cmdGetInx, pring->numCiocb, ++ pring->next_cmdidx, pring->local_getidx, ++ pring->flag, pgpp->rspPutInx, pring->numRiocb); ++ } + word0 = readl(phba->HAregaddr); + word1 = readl(phba->CAregaddr); + word2 = readl(phba->HSregaddr); +@@ -430,6 +500,21 @@ lpfc_debugfs_dumpHostSlim_data(struct lp + return len; + } + ++/** ++ * lpfc_debugfs_nodelist_data - Dump target node list to a buffer. ++ * @vport: The vport to gather target node info from. ++ * @buf: The buffer to dump log into. ++ * @size: The maximum amount of data to process. ++ * ++ * Description: ++ * This routine dumps the current target node list associated with @vport to ++ * @buf up to @size bytes of data. Each node entry in the dump will contain a ++ * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields. ++ * ++ * Return Value: ++ * This routine returns the amount of bytes that were dumped into @buf and will ++ * not exceed @size. ++ **/ + static int + lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) + { +@@ -513,7 +598,22 @@ lpfc_debugfs_nodelist_data(struct lpfc_v + } + #endif + +- ++/** ++ * lpfc_debugfs_disc_trc - Store discovery trace log. ++ * @vport: The vport to associate this trace string with for retrieval. ++ * @mask: Log entry classification. ++ * @fmt: Format string to be displayed when dumping the log. ++ * @data1: 1st data parameter to be applied to @fmt. ++ * @data2: 2nd data parameter to be applied to @fmt. ++ * @data3: 3rd data parameter to be applied to @fmt. ++ * ++ * Description: ++ * This routine is used by the driver code to add a debugfs log entry to the ++ * discovery trace buffer associated with @vport. Only entries with a @mask that ++ * match the current debugfs discovery mask will be saved. Entries that do not ++ * match will be thrown away. @fmt, @data1, @data2, and @data3 are used like ++ * printf when displaying the log. ++ **/ + inline void + lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt, + uint32_t data1, uint32_t data2, uint32_t data3) +@@ -542,6 +642,19 @@ lpfc_debugfs_disc_trc(struct lpfc_vport + return; + } + ++/** ++ * lpfc_debugfs_slow_ring_trc - Store slow ring trace log. ++ * @phba: The phba to associate this trace string with for retrieval. ++ * @fmt: Format string to be displayed when dumping the log. ++ * @data1: 1st data parameter to be applied to @fmt. ++ * @data2: 2nd data parameter to be applied to @fmt. ++ * @data3: 3rd data parameter to be applied to @fmt. ++ * ++ * Description: ++ * This routine is used by the driver code to add a debugfs log entry to the ++ * discovery trace buffer associated with @vport. @fmt, @data1, @data2, and ++ * @data3 are used like printf when displaying the log. ++ **/ + inline void + lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt, + uint32_t data1, uint32_t data2, uint32_t data3) +@@ -568,6 +681,21 @@ lpfc_debugfs_slow_ring_trc(struct lpfc_h + } + + #ifdef CONFIG_LPFC_DEBUG_FS ++/** ++ * lpfc_debugfs_disc_trc_open - Open the discovery trace log. ++ * @inode: The inode pointer that contains a vport pointer. ++ * @file: The file pointer to attach the log output. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs open file operation. It gets ++ * the vport from the i_private field in @inode, allocates the necessary buffer ++ * for the log, fills the buffer from the in-memory log for this vport, and then ++ * returns a pointer to that log in the private_data field in @file. ++ * ++ * Returns: ++ * This function returns zero if successful. On error it will return an negative ++ * error value. ++ **/ + static int + lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file) + { +@@ -585,7 +713,7 @@ lpfc_debugfs_disc_trc_open(struct inode + if (!debug) + goto out; + +- /* Round to page boundry */ ++ /* Round to page boundary */ + size = (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE); + size = PAGE_ALIGN(size); + +@@ -603,6 +731,21 @@ out: + return rc; + } + ++/** ++ * lpfc_debugfs_slow_ring_trc_open - Open the Slow Ring trace log. ++ * @inode: The inode pointer that contains a vport pointer. ++ * @file: The file pointer to attach the log output. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs open file operation. It gets ++ * the vport from the i_private field in @inode, allocates the necessary buffer ++ * for the log, fills the buffer from the in-memory log for this vport, and then ++ * returns a pointer to that log in the private_data field in @file. ++ * ++ * Returns: ++ * This function returns zero if successful. On error it will return an negative ++ * error value. ++ **/ + static int + lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file) + { +@@ -620,7 +763,7 @@ lpfc_debugfs_slow_ring_trc_open(struct i + if (!debug) + goto out; + +- /* Round to page boundry */ ++ /* Round to page boundary */ + size = (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE); + size = PAGE_ALIGN(size); + +@@ -638,6 +781,21 @@ out: + return rc; + } + ++/** ++ * lpfc_debugfs_hbqinfo_open - Open the hbqinfo debugfs buffer. ++ * @inode: The inode pointer that contains a vport pointer. ++ * @file: The file pointer to attach the log output. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs open file operation. It gets ++ * the vport from the i_private field in @inode, allocates the necessary buffer ++ * for the log, fills the buffer from the in-memory log for this vport, and then ++ * returns a pointer to that log in the private_data field in @file. ++ * ++ * Returns: ++ * This function returns zero if successful. On error it will return an negative ++ * error value. ++ **/ + static int + lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file) + { +@@ -649,7 +807,7 @@ lpfc_debugfs_hbqinfo_open(struct inode * + if (!debug) + goto out; + +- /* Round to page boundry */ ++ /* Round to page boundary */ + debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); +@@ -665,6 +823,21 @@ out: + return rc; + } + ++/** ++ * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer. ++ * @inode: The inode pointer that contains a vport pointer. ++ * @file: The file pointer to attach the log output. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs open file operation. It gets ++ * the vport from the i_private field in @inode, allocates the necessary buffer ++ * for the log, fills the buffer from the in-memory log for this vport, and then ++ * returns a pointer to that log in the private_data field in @file. ++ * ++ * Returns: ++ * This function returns zero if successful. On error it will return an negative ++ * error value. ++ **/ + static int + lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file) + { +@@ -676,7 +849,7 @@ lpfc_debugfs_dumpHBASlim_open(struct ino + if (!debug) + goto out; + +- /* Round to page boundry */ ++ /* Round to page boundary */ + debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); +@@ -692,6 +865,21 @@ out: + return rc; + } + ++/** ++ * lpfc_debugfs_dumpHostSlim_open - Open the Dump Host SLIM debugfs buffer. ++ * @inode: The inode pointer that contains a vport pointer. ++ * @file: The file pointer to attach the log output. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs open file operation. It gets ++ * the vport from the i_private field in @inode, allocates the necessary buffer ++ * for the log, fills the buffer from the in-memory log for this vport, and then ++ * returns a pointer to that log in the private_data field in @file. ++ * ++ * Returns: ++ * This function returns zero if successful. On error it will return an negative ++ * error value. ++ **/ + static int + lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file) + { +@@ -703,7 +891,7 @@ lpfc_debugfs_dumpHostSlim_open(struct in + if (!debug) + goto out; + +- /* Round to page boundry */ ++ /* Round to page boundary */ + debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); +@@ -719,6 +907,21 @@ out: + return rc; + } + ++/** ++ * lpfc_debugfs_nodelist_open - Open the nodelist debugfs file. ++ * @inode: The inode pointer that contains a vport pointer. ++ * @file: The file pointer to attach the log output. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs open file operation. It gets ++ * the vport from the i_private field in @inode, allocates the necessary buffer ++ * for the log, fills the buffer from the in-memory log for this vport, and then ++ * returns a pointer to that log in the private_data field in @file. ++ * ++ * Returns: ++ * This function returns zero if successful. On error it will return an negative ++ * error value. ++ **/ + static int + lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file) + { +@@ -730,7 +933,7 @@ lpfc_debugfs_nodelist_open(struct inode + if (!debug) + goto out; + +- /* Round to page boundry */ ++ /* Round to page boundary */ + debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); +@@ -746,6 +949,23 @@ out: + return rc; + } + ++/** ++ * lpfc_debugfs_lseek - Seek through a debugfs file. ++ * @file: The file pointer to seek through. ++ * @off: The offset to seek to or the amount to seek by. ++ * @whence: Indicates how to seek. ++ * ++ * Description: ++ * This routine is the entry point for the debugfs lseek file operation. The ++ * @whence parameter indicates whether @off is the offset to directly seek to, ++ * or if it is a value to seek forward or reverse by. This function figures out ++ * what the new offset of the debugfs file will be and assigns that value to the ++ * f_pos field of @file. ++ * ++ * Returns: ++ * This function returns the new offset if successful and returns a negative ++ * error if unable to process the seek. ++ **/ + static loff_t + lpfc_debugfs_lseek(struct file *file, loff_t off, int whence) + { +@@ -767,6 +987,22 @@ lpfc_debugfs_lseek(struct file *file, lo + return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos); + } + ++/** ++ * lpfc_debugfs_read - Read a debugfs file. ++ * @file: The file pointer to read from. ++ * @buf: The buffer to copy the data to. ++ * @nbytes: The number of bytes to read. ++ * @ppos: The position in the file to start reading from. ++ * ++ * Description: ++ * This routine reads data from from the buffer indicated in the private_data ++ * field of @file. It will start reading at @ppos and copy up to @nbytes of ++ * data to @buf. ++ * ++ * Returns: ++ * This function returns the amount of data that was read (this could be less ++ * than @nbytes if the end of the file was reached) or a negative error value. ++ **/ + static ssize_t + lpfc_debugfs_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +@@ -776,6 +1012,18 @@ lpfc_debugfs_read(struct file *file, cha + debug->len); + } + ++/** ++ * lpfc_debugfs_release - Release the buffer used to store debugfs file data. ++ * @inode: The inode pointer that contains a vport pointer. (unused) ++ * @file: The file pointer that contains the buffer to release. ++ * ++ * Description: ++ * This routine frees the buffer that was allocated when the debugfs file was ++ * opened. ++ * ++ * Returns: ++ * This function returns zero. ++ **/ + static int + lpfc_debugfs_release(struct inode *inode, struct file *file) + { +@@ -845,6 +1093,16 @@ static struct dentry *lpfc_debugfs_root + static atomic_t lpfc_debugfs_hba_count; + #endif + ++/** ++ * lpfc_debugfs_initialize - Initialize debugfs for a vport. ++ * @vport: The vport pointer to initialize. ++ * ++ * Description: ++ * When Debugfs is configured this routine sets up the lpfc debugfs file system. ++ * If not already created, this routine will create the lpfc directory, and ++ * lpfcX directory (for this HBA), and vportX directory for this vport. It will ++ * also create each file used to access lpfc specific debugfs information. ++ **/ + inline void + lpfc_debugfs_initialize(struct lpfc_vport *vport) + { +@@ -862,7 +1120,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + atomic_set(&lpfc_debugfs_hba_count, 0); + if (!lpfc_debugfs_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs root\n"); ++ "0408 Cannot create debugfs root\n"); + goto debug_failed; + } + } +@@ -876,7 +1134,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + debugfs_create_dir(name, lpfc_debugfs_root); + if (!phba->hba_debugfs_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs hba\n"); ++ "0412 Cannot create debugfs hba\n"); + goto debug_failed; + } + atomic_inc(&lpfc_debugfs_hba_count); +@@ -890,7 +1148,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + phba, &lpfc_debugfs_op_hbqinfo); + if (!phba->debug_hbqinfo) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs hbqinfo\n"); ++ "0411 Cannot create debugfs hbqinfo\n"); + goto debug_failed; + } + +@@ -902,7 +1160,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + phba, &lpfc_debugfs_op_dumpHBASlim); + if (!phba->debug_dumpHBASlim) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs dumpHBASlim\n"); ++ "0413 Cannot create debugfs dumpHBASlim\n"); + goto debug_failed; + } + +@@ -914,7 +1172,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + phba, &lpfc_debugfs_op_dumpHostSlim); + if (!phba->debug_dumpHostSlim) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs dumpHostSlim\n"); ++ "0414 Cannot create debugfs dumpHostSlim\n"); + goto debug_failed; + } + +@@ -944,7 +1202,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + phba, &lpfc_debugfs_op_slow_ring_trc); + if (!phba->debug_slow_ring_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs " ++ "0415 Cannot create debugfs " + "slow_ring_trace\n"); + goto debug_failed; + } +@@ -955,7 +1213,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + GFP_KERNEL); + if (!phba->slow_ring_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs " ++ "0416 Cannot create debugfs " + "slow_ring buffer\n"); + goto debug_failed; + } +@@ -972,7 +1230,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + debugfs_create_dir(name, phba->hba_debugfs_root); + if (!vport->vport_debugfs_root) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cant create debugfs"); ++ "0417 Cant create debugfs"); + goto debug_failed; + } + atomic_inc(&phba->debugfs_vport_count); +@@ -1001,7 +1259,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + + if (!vport->disc_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs disc trace " ++ "0418 Cannot create debugfs disc trace " + "buffer\n"); + goto debug_failed; + } +@@ -1014,7 +1272,7 @@ lpfc_debugfs_initialize(struct lpfc_vpor + vport, &lpfc_debugfs_op_disc_trc); + if (!vport->debug_disc_trc) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +- "0409 Cannot create debugfs " ++ "0419 Cannot create debugfs " + "discovery_trace\n"); + goto debug_failed; + } +@@ -1033,7 +1291,17 @@ debug_failed: + #endif + } + +- ++/** ++ * lpfc_debugfs_terminate - Tear down debugfs infrastructure for this vport. ++ * @vport: The vport pointer to remove from debugfs. ++ * ++ * Description: ++ * When Debugfs is configured this routine removes debugfs file system elements ++ * that are specific to this vport. It also checks to see if there are any ++ * users left for the debugfs directories associated with the HBA and driver. If ++ * this is the last user of the HBA directory or driver directory then it will ++ * remove those from the debugfs infrastructure as well. ++ **/ + inline void + lpfc_debugfs_terminate(struct lpfc_vport *vport) + { +@@ -1096,5 +1364,3 @@ lpfc_debugfs_terminate(struct lpfc_vport + #endif + return; + } +- +- +--- a/drivers/scsi/lpfc/lpfc_disc.h ++++ b/drivers/scsi/lpfc/lpfc_disc.h +@@ -37,6 +37,7 @@ enum lpfc_work_type { + LPFC_EVT_KILL, + LPFC_EVT_ELS_RETRY, + LPFC_EVT_DEV_LOSS, ++ LPFC_EVT_FASTPATH_MGMT_EVT, + }; + + /* structure used to queue event to the discovery tasklet */ +@@ -47,6 +48,24 @@ struct lpfc_work_evt { + enum lpfc_work_type evt; + }; + ++struct lpfc_scsi_check_condition_event; ++struct lpfc_scsi_varqueuedepth_event; ++struct lpfc_scsi_event_header; ++struct lpfc_fabric_event_header; ++struct lpfc_fcprdchkerr_event; ++ ++/* structure used for sending events from fast path */ ++struct lpfc_fast_path_event { ++ struct lpfc_work_evt work_evt; ++ struct lpfc_vport *vport; ++ union { ++ struct lpfc_scsi_check_condition_event check_cond_evt; ++ struct lpfc_scsi_varqueuedepth_event queue_depth_evt; ++ struct lpfc_scsi_event_header scsi_evt; ++ struct lpfc_fabric_event_header fabric_evt; ++ struct lpfc_fcprdchkerr_event read_check_error; ++ } un; ++}; + + struct lpfc_nodelist { + struct list_head nlp_listp; +@@ -88,6 +107,10 @@ struct lpfc_nodelist { + unsigned long last_ramp_up_time; /* jiffy of last ramp up */ + unsigned long last_q_full_time; /* jiffy of last queue full */ + struct kref kref; ++ atomic_t cmd_pending; ++ uint32_t cmd_qdepth; ++ unsigned long last_change_time; ++ struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ + }; + + /* Defines for nlp_flag (uint32) */ +--- a/drivers/scsi/lpfc/lpfc_els.c ++++ b/drivers/scsi/lpfc/lpfc_els.c +@@ -30,6 +30,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -53,6 +54,28 @@ static void lpfc_register_new_vport(stru + + static int lpfc_max_els_tries = 3; + ++/** ++ * lpfc_els_chk_latt: Check host link attention event for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine checks whether there is an outstanding host link ++ * attention event during the discovery process with the @vport. It is done ++ * by reading the HBA's Host Attention (HA) register. If there is any host ++ * link attention events during this @vport's discovery process, the @vport ++ * shall be marked as FC_ABORT_DISCOVERY, a host link attention clear shall ++ * be issued if the link state is not already in host link cleared state, ++ * and a return code shall indicate whether the host link attention event ++ * had happened. ++ * ++ * Note that, if either the host link is in state LPFC_LINK_DOWN or @vport ++ * state in LPFC_VPORT_READY, the request for checking host link attention ++ * event will be ignored and a return code shall indicate no host link ++ * attention event had happened. ++ * ++ * Return codes ++ * 0 - no host link attention event happened ++ * 1 - host link attention event happened ++ **/ + int + lpfc_els_chk_latt(struct lpfc_vport *vport) + { +@@ -92,6 +115,34 @@ lpfc_els_chk_latt(struct lpfc_vport *vpo + return 1; + } + ++/** ++ * lpfc_prep_els_iocb: Allocate and prepare a lpfc iocb data structure. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @expectRsp: flag indicating whether response is expected. ++ * @cmdSize: size of the ELS command. ++ * @retry: number of retries to the command IOCB when it fails. ++ * @ndlp: pointer to a node-list data structure. ++ * @did: destination identifier. ++ * @elscmd: the ELS command code. ++ * ++ * This routine is used for allocating a lpfc-IOCB data structure from ++ * the driver lpfc-IOCB free-list and prepare the IOCB with the parameters ++ * passed into the routine for discovery state machine to issue an Extended ++ * Link Service (ELS) commands. It is a generic lpfc-IOCB allocation ++ * and preparation routine that is used by all the discovery state machine ++ * routines and the ELS command-specific fields will be later set up by ++ * the individual discovery machine routines after calling this routine ++ * allocating and preparing a generic IOCB data structure. It fills in the ++ * Buffer Descriptor Entries (BDEs), allocates buffers for both command ++ * payload and response payload (if expected). The reference count on the ++ * ndlp is incremented by 1 and the reference to the ndlp is put into ++ * context1 of the IOCB data structure for this IOCB to hold the ndlp ++ * reference for the command's callback function to access later. ++ * ++ * Return code ++ * Pointer to the newly allocated/prepared els iocb data structure ++ * NULL - when els iocb data structure allocation/preparation failed ++ **/ + static struct lpfc_iocbq * + lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, + uint16_t cmdSize, uint8_t retry, +@@ -150,7 +201,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vp + + icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); + icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); +- icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL; ++ icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.elsreq64.remoteID = did; /* DID */ + if (expectRsp) { + icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); +@@ -185,7 +236,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vp + bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys)); + bpl->tus.f.bdeSize = FCELSSIZE; +- bpl->tus.f.bdeFlags = BUFF_USE_RCV; ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + } + +@@ -233,6 +284,22 @@ els_iocb_free_pcmb_exit: + return NULL; + } + ++/** ++ * lpfc_issue_fabric_reglogin: Issue fabric registration login for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine issues a fabric registration login for a @vport. An ++ * active ndlp node with Fabric_DID must already exist for this @vport. ++ * The routine invokes two mailbox commands to carry out fabric registration ++ * login through the HBA firmware: the first mailbox command requests the ++ * HBA to perform link configuration for the @vport; and the second mailbox ++ * command requests the HBA to perform the actual fabric registration login ++ * with the @vport. ++ * ++ * Return code ++ * 0 - successfully issued fabric registration login for @vport ++ * -ENXIO -- failed to issue fabric registration login for @vport ++ **/ + static int + lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) + { +@@ -313,6 +380,26 @@ fail: + return -ENXIO; + } + ++/** ++ * lpfc_cmpl_els_flogi_fabric: Completion function for flogi to a fabric port. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @sp: pointer to service parameter data structure. ++ * @irsp: pointer to the IOCB within the lpfc response IOCB. ++ * ++ * This routine is invoked by the lpfc_cmpl_els_flogi() completion callback ++ * function to handle the completion of a Fabric Login (FLOGI) into a fabric ++ * port in a fabric topology. It properly sets up the parameters to the @ndlp ++ * from the IOCB response. It also check the newly assigned N_Port ID to the ++ * @vport against the previously assigned N_Port ID. If it is different from ++ * the previously assigned Destination ID (DID), the lpfc_unreg_rpi() routine ++ * is invoked on all the remaining nodes with the @vport to unregister the ++ * Remote Port Indicators (RPIs). Finally, the lpfc_issue_fabric_reglogin() ++ * is invoked to register login to the fabric. ++ * ++ * Return code ++ * 0 - Success (currently, always return 0) ++ **/ + static int + lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct serv_parm *sp, IOCB_t *irsp) +@@ -387,7 +474,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_v + */ + list_for_each_entry_safe(np, next_np, + &vport->fc_nodes, nlp_listp) { +- if (!NLP_CHK_NODE_ACT(ndlp)) ++ if (!NLP_CHK_NODE_ACT(np)) + continue; + if ((np->nlp_state != NLP_STE_NPR_NODE) || + !(np->nlp_flag & NLP_NPR_ADISC)) +@@ -416,9 +503,26 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_v + return 0; + } + +-/* +- * We FLOGIed into an NPort, initiate pt2pt protocol +- */ ++/** ++ * lpfc_cmpl_els_flogi_nport: Completion function for flogi to an N_Port. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @sp: pointer to service parameter data structure. ++ * ++ * This routine is invoked by the lpfc_cmpl_els_flogi() completion callback ++ * function to handle the completion of a Fabric Login (FLOGI) into an N_Port ++ * in a point-to-point topology. First, the @vport's N_Port Name is compared ++ * with the received N_Port Name: if the @vport's N_Port Name is greater than ++ * the received N_Port Name lexicographically, this node shall assign local ++ * N_Port ID (PT2PT_LocalID: 1) and remote N_Port ID (PT2PT_RemoteID: 2) and ++ * will send out Port Login (PLOGI) with the N_Port IDs assigned. Otherwise, ++ * this node shall just wait for the remote node to issue PLOGI and assign ++ * N_Port IDs. ++ * ++ * Return code ++ * 0 - Success ++ * -ENXIO - Fail ++ **/ + static int + lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct serv_parm *sp) +@@ -516,6 +620,29 @@ fail: + return -ENXIO; + } + ++/** ++ * lpfc_cmpl_els_flogi: Completion callback function for flogi. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the top-level completion callback function for issuing ++ * a Fabric Login (FLOGI) command. If the response IOCB reported error, ++ * the lpfc_els_retry() routine shall be invoked to retry the FLOGI. If ++ * retry has been made (either immediately or delayed with lpfc_els_retry() ++ * returning 1), the command IOCB will be released and function returned. ++ * If the retry attempt has been given up (possibly reach the maximum ++ * number of retries), one additional decrement of ndlp reference shall be ++ * invoked before going out after releasing the command IOCB. This will ++ * actually release the remote node (Note, lpfc_els_free_iocb() will also ++ * invoke one decrement of ndlp reference count). If no error reported in ++ * the IOCB status, the command Port ID field is used to determine whether ++ * this is a point-to-point topology or a fabric topology: if the Port ID ++ * field is assigned, it is a fabric topology; otherwise, it is a ++ * point-to-point topology. The routine lpfc_cmpl_els_flogi_fabric() or ++ * lpfc_cmpl_els_flogi_nport() shall be invoked accordingly to handle the ++ * specific topology completion conditions. ++ **/ + static void + lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -618,6 +745,28 @@ out: + lpfc_els_free_iocb(phba, cmdiocb); + } + ++/** ++ * lpfc_issue_els_flogi: Issue an flogi iocb command for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine issues a Fabric Login (FLOGI) Request ELS command ++ * for a @vport. The initiator service parameters are put into the payload ++ * of the FLOGI Request IOCB and the top-level callback function pointer ++ * to lpfc_cmpl_els_flogi() routine is put to the IOCB completion callback ++ * function field. The lpfc_issue_fabric_iocb routine is invoked to send ++ * out FLOGI ELS command with one outstanding fabric IOCB at a time. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the FLOGI ELS command. ++ * ++ * Return code ++ * 0 - successfully issued flogi iocb for @vport ++ * 1 - failed to issue flogi iocb for @vport ++ **/ + static int + lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint8_t retry) +@@ -694,6 +843,20 @@ lpfc_issue_els_flogi(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_els_abort_flogi: Abort all outstanding flogi iocbs. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine aborts all the outstanding Fabric Login (FLOGI) IOCBs ++ * with a @phba. This routine walks all the outstanding IOCBs on the txcmplq ++ * list and issues an abort IOCB commond on each outstanding IOCB that ++ * contains a active Fabric_DID ndlp. Note that this function is to issue ++ * the abort IOCB command on all the outstanding IOCBs, thus when this ++ * function returns, it does not guarantee all the IOCBs are actually aborted. ++ * ++ * Return code ++ * 0 - Sucessfully issued abort iocb on all outstanding flogis (Always 0) ++ **/ + int + lpfc_els_abort_flogi(struct lpfc_hba *phba) + { +@@ -729,6 +892,22 @@ lpfc_els_abort_flogi(struct lpfc_hba *ph + return 0; + } + ++/** ++ * lpfc_initial_flogi: Issue an initial fabric login for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine issues an initial Fabric Login (FLOGI) for the @vport ++ * specified. It first searches the ndlp with the Fabric_DID (0xfffffe) from ++ * the @vport's ndlp list. If no such ndlp found, it will create an ndlp and ++ * put it into the @vport's ndlp list. If an inactive ndlp found on the list, ++ * it will just be enabled and made active. The lpfc_issue_els_flogi() routine ++ * is then invoked with the @vport and the ndlp to perform the FLOGI for the ++ * @vport. ++ * ++ * Return code ++ * 0 - failed to issue initial flogi for @vport ++ * 1 - successfully issued initial flogi for @vport ++ **/ + int + lpfc_initial_flogi(struct lpfc_vport *vport) + { +@@ -764,6 +943,22 @@ lpfc_initial_flogi(struct lpfc_vport *vp + return 1; + } + ++/** ++ * lpfc_initial_fdisc: Issue an initial fabric discovery for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine issues an initial Fabric Discover (FDISC) for the @vport ++ * specified. It first searches the ndlp with the Fabric_DID (0xfffffe) from ++ * the @vport's ndlp list. If no such ndlp found, it will create an ndlp and ++ * put it into the @vport's ndlp list. If an inactive ndlp found on the list, ++ * it will just be enabled and made active. The lpfc_issue_els_fdisc() routine ++ * is then invoked with the @vport and the ndlp to perform the FDISC for the ++ * @vport. ++ * ++ * Return code ++ * 0 - failed to issue initial fdisc for @vport ++ * 1 - successfully issued initial fdisc for @vport ++ **/ + int + lpfc_initial_fdisc(struct lpfc_vport *vport) + { +@@ -797,6 +992,17 @@ lpfc_initial_fdisc(struct lpfc_vport *vp + return 1; + } + ++/** ++ * lpfc_more_plogi: Check and issue remaining plogis for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine checks whether there are more remaining Port Logins ++ * (PLOGI) to be issued for the @vport. If so, it will invoke the routine ++ * lpfc_els_disc_plogi() to go through the Node Port Recovery (NPR) nodes ++ * to issue ELS PLOGIs up to the configured discover threads with the ++ * @vport (@vport->cfg_discovery_threads). The function also decrement ++ * the @vport's num_disc_node by 1 if it is not already 0. ++ **/ + void + lpfc_more_plogi(struct lpfc_vport *vport) + { +@@ -819,6 +1025,37 @@ lpfc_more_plogi(struct lpfc_vport *vport + return; + } + ++/** ++ * lpfc_plogi_confirm_nport: Confirm pologi wwpn matches stored ndlp. ++ * @phba: pointer to lpfc hba data structure. ++ * @prsp: pointer to response IOCB payload. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine checks and indicates whether the WWPN of an N_Port, retrieved ++ * from a PLOGI, matches the WWPN that is stored in the @ndlp for that N_POrt. ++ * The following cases are considered N_Port confirmed: ++ * 1) The N_Port is a Fabric ndlp; 2) The @ndlp is on vport list and matches ++ * the WWPN of the N_Port logged into; 3) The @ndlp is not on vport list but ++ * it does not have WWPN assigned either. If the WWPN is confirmed, the ++ * pointer to the @ndlp will be returned. If the WWPN is not confirmed: ++ * 1) if there is a node on vport list other than the @ndlp with the same ++ * WWPN of the N_Port PLOGI logged into, the lpfc_unreg_rpi() will be invoked ++ * on that node to release the RPI associated with the node; 2) if there is ++ * no node found on vport list with the same WWPN of the N_Port PLOGI logged ++ * into, a new node shall be allocated (or activated). In either case, the ++ * parameters of the @ndlp shall be copied to the new_ndlp, the @ndlp shall ++ * be released and the new_ndlp shall be put on to the vport node list and ++ * its pointer returned as the confirmed node. ++ * ++ * Note that before the @ndlp got "released", the keepDID from not-matching ++ * or inactive "new_ndlp" on the vport node list is assigned to the nlp_DID ++ * of the @ndlp. This is because the release of @ndlp is actually to put it ++ * into an inactive state on the vport node list and the vport node list ++ * management algorithm does not allow two node with a same DID. ++ * ++ * Return code ++ * pointer to the PLOGI N_Port @ndlp ++ **/ + static struct lpfc_nodelist * + lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, + struct lpfc_nodelist *ndlp) +@@ -922,6 +1159,17 @@ lpfc_plogi_confirm_nport(struct lpfc_hba + return new_ndlp; + } + ++/** ++ * lpfc_end_rscn: Check and handle more rscn for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine checks whether more Registration State Change ++ * Notifications (RSCNs) came in while the discovery state machine was in ++ * the FC_RSCN_MODE. If so, the lpfc_els_handle_rscn() routine will be ++ * invoked to handle the additional RSCNs for the @vport. Otherwise, the ++ * FC_RSCN_MODE bit will be cleared with the @vport to mark as the end of ++ * handling the RSCNs. ++ **/ + void + lpfc_end_rscn(struct lpfc_vport *vport) + { +@@ -943,6 +1191,26 @@ lpfc_end_rscn(struct lpfc_vport *vport) + } + } + ++/** ++ * lpfc_cmpl_els_plogi: Completion callback function for plogi. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion callback function for issuing the Port ++ * Login (PLOGI) command. For PLOGI completion, there must be an active ++ * ndlp on the vport node list that matches the remote node ID from the ++ * PLOGI reponse IOCB. If such ndlp does not exist, the PLOGI is simply ++ * ignored and command IOCB released. The PLOGI response IOCB status is ++ * checked for error conditons. If there is error status reported, PLOGI ++ * retry shall be attempted by invoking the lpfc_els_retry() routine. ++ * Otherwise, the lpfc_plogi_confirm_nport() routine shall be invoked on ++ * the ndlp and the NLP_EVT_CMPL_PLOGI state to the Discover State Machine ++ * (DSM) is set for this PLOGI completion. Finally, it checks whether ++ * there are additional N_Port nodes with the vport that need to perform ++ * PLOGI. If so, the lpfc_more_plogi() routine is invoked to issue addition ++ * PLOGIs. ++ **/ + static void + lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -1048,6 +1316,27 @@ out: + return; + } + ++/** ++ * lpfc_issue_els_plogi: Issue an plogi iocb command for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @did: destination port identifier. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine issues a Port Login (PLOGI) command to a remote N_Port ++ * (with the @did) for a @vport. Before issuing a PLOGI to a remote N_Port, ++ * the ndlp with the remote N_Port DID must exist on the @vport's ndlp list. ++ * This routine constructs the proper feilds of the PLOGI IOCB and invokes ++ * the lpfc_sli_issue_iocb() routine to send out PLOGI ELS command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the PLOGI ELS command. ++ * ++ * Return code ++ * 0 - Successfully issued a plogi for @vport ++ * 1 - failed to issue a plogi for @vport ++ **/ + int + lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) + { +@@ -1106,6 +1395,19 @@ lpfc_issue_els_plogi(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_cmpl_els_prli: Completion callback function for prli. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion callback function for a Process Login ++ * (PRLI) ELS command. The PRLI response IOCB status is checked for error ++ * status. If there is error status reported, PRLI retry shall be attempted ++ * by invoking the lpfc_els_retry() routine. Otherwise, the state ++ * NLP_EVT_CMPL_PRLI is sent to the Discover State Machine (DSM) for this ++ * ndlp to mark the PRLI completion. ++ **/ + static void + lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -1164,6 +1466,27 @@ out: + return; + } + ++/** ++ * lpfc_issue_els_prli: Issue a prli iocb command for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine issues a Process Login (PRLI) ELS command for the ++ * @vport. The PRLI service parameters are set up in the payload of the ++ * PRLI Request command and the pointer to lpfc_cmpl_els_prli() routine ++ * is put to the IOCB completion callback func field before invoking the ++ * routine lpfc_sli_issue_iocb() to send out PRLI command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the PRLI ELS command. ++ * ++ * Return code ++ * 0 - successfully issued prli iocb command for @vport ++ * 1 - failed to issue prli iocb command for @vport ++ **/ + int + lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint8_t retry) +@@ -1233,6 +1556,92 @@ lpfc_issue_els_prli(struct lpfc_vport *v + return 0; + } + ++/** ++ * lpfc_rscn_disc: Perform rscn discovery for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine performs Registration State Change Notification (RSCN) ++ * discovery for a @vport. If the @vport's node port recovery count is not ++ * zero, it will invoke the lpfc_els_disc_plogi() to perform PLOGI for all ++ * the nodes that need recovery. If none of the PLOGI were needed through ++ * the lpfc_els_disc_plogi() routine, the lpfc_end_rscn() routine shall be ++ * invoked to check and handle possible more RSCN came in during the period ++ * of processing the current ones. ++ **/ ++static void ++lpfc_rscn_disc(struct lpfc_vport *vport) ++{ ++ lpfc_can_disctmo(vport); ++ ++ /* RSCN discovery */ ++ /* go thru NPR nodes and issue ELS PLOGIs */ ++ if (vport->fc_npr_cnt) ++ if (lpfc_els_disc_plogi(vport)) ++ return; ++ ++ lpfc_end_rscn(vport); ++} ++ ++/** ++ * lpfc_adisc_done: Complete the adisc phase of discovery. ++ * @vport: pointer to lpfc_vport hba data structure that finished all ADISCs. ++ * ++ * This function is called when the final ADISC is completed during discovery. ++ * This function handles clearing link attention or issuing reg_vpi depending ++ * on whether npiv is enabled. This function also kicks off the PLOGI phase of ++ * discovery. ++ * This function is called with no locks held. ++ **/ ++static void ++lpfc_adisc_done(struct lpfc_vport *vport) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_hba *phba = vport->phba; ++ ++ /* ++ * For NPIV, cmpl_reg_vpi will set port_state to READY, ++ * and continue discovery. ++ */ ++ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && ++ !(vport->fc_flag & FC_RSCN_MODE)) { ++ lpfc_issue_reg_vpi(phba, vport); ++ return; ++ } ++ /* ++ * For SLI2, we need to set port_state to READY ++ * and continue discovery. ++ */ ++ if (vport->port_state < LPFC_VPORT_READY) { ++ /* If we get here, there is nothing to ADISC */ ++ if (vport->port_type == LPFC_PHYSICAL_PORT) ++ lpfc_issue_clear_la(phba, vport); ++ if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { ++ vport->num_disc_nodes = 0; ++ /* go thru NPR list, issue ELS PLOGIs */ ++ if (vport->fc_npr_cnt) ++ lpfc_els_disc_plogi(vport); ++ if (!vport->num_disc_nodes) { ++ spin_lock_irq(shost->host_lock); ++ vport->fc_flag &= ~FC_NDISC_ACTIVE; ++ spin_unlock_irq(shost->host_lock); ++ lpfc_can_disctmo(vport); ++ lpfc_end_rscn(vport); ++ } ++ } ++ vport->port_state = LPFC_VPORT_READY; ++ } else ++ lpfc_rscn_disc(vport); ++} ++ ++/** ++ * lpfc_more_adisc: Issue more adisc as needed. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine determines whether there are more ndlps on a @vport ++ * node list need to have Address Discover (ADISC) issued. If so, it will ++ * invoke the lpfc_els_disc_adisc() routine to issue ADISC on the @vport's ++ * remaining nodes which need to have ADISC sent. ++ **/ + void + lpfc_more_adisc(struct lpfc_vport *vport) + { +@@ -1252,23 +1661,27 @@ lpfc_more_adisc(struct lpfc_vport *vport + /* go thru NPR nodes and issue any remaining ELS ADISCs */ + sentadisc = lpfc_els_disc_adisc(vport); + } ++ if (!vport->num_disc_nodes) ++ lpfc_adisc_done(vport); + return; + } + +-static void +-lpfc_rscn_disc(struct lpfc_vport *vport) +-{ +- lpfc_can_disctmo(vport); +- +- /* RSCN discovery */ +- /* go thru NPR nodes and issue ELS PLOGIs */ +- if (vport->fc_npr_cnt) +- if (lpfc_els_disc_plogi(vport)) +- return; +- +- lpfc_end_rscn(vport); +-} +- ++/** ++ * lpfc_cmpl_els_adisc: Completion callback function for adisc. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion function for issuing the Address Discover ++ * (ADISC) command. It first checks to see whether link went down during ++ * the discovery process. If so, the node will be marked as node port ++ * recovery for issuing discover IOCB by the link attention handler and ++ * exit. Otherwise, the response status is checked. If error was reported ++ * in the response status, the ADISC command shall be retried by invoking ++ * the lpfc_els_retry() routine. Otherwise, if no error was reported in ++ * the response status, the state machine is invoked to set transition ++ * with respect to NLP_EVT_CMPL_ADISC event. ++ **/ + static void + lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -1333,57 +1746,34 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phb + lpfc_disc_state_machine(vport, ndlp, cmdiocb, + NLP_EVT_CMPL_ADISC); + +- if (disc && vport->num_disc_nodes) { +- /* Check to see if there are more ADISCs to be sent */ ++ /* Check to see if there are more ADISCs to be sent */ ++ if (disc && vport->num_disc_nodes) + lpfc_more_adisc(vport); +- +- /* Check to see if we are done with ADISC authentication */ +- if (vport->num_disc_nodes == 0) { +- /* If we get here, there is nothing left to ADISC */ +- /* +- * For NPIV, cmpl_reg_vpi will set port_state to READY, +- * and continue discovery. +- */ +- if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && +- !(vport->fc_flag & FC_RSCN_MODE)) { +- lpfc_issue_reg_vpi(phba, vport); +- goto out; +- } +- /* +- * For SLI2, we need to set port_state to READY +- * and continue discovery. +- */ +- if (vport->port_state < LPFC_VPORT_READY) { +- /* If we get here, there is nothing to ADISC */ +- if (vport->port_type == LPFC_PHYSICAL_PORT) +- lpfc_issue_clear_la(phba, vport); +- +- if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { +- vport->num_disc_nodes = 0; +- /* go thru NPR list, issue ELS PLOGIs */ +- if (vport->fc_npr_cnt) +- lpfc_els_disc_plogi(vport); +- +- if (!vport->num_disc_nodes) { +- spin_lock_irq(shost->host_lock); +- vport->fc_flag &= +- ~FC_NDISC_ACTIVE; +- spin_unlock_irq( +- shost->host_lock); +- lpfc_can_disctmo(vport); +- } +- } +- vport->port_state = LPFC_VPORT_READY; +- } else { +- lpfc_rscn_disc(vport); +- } +- } +- } + out: + lpfc_els_free_iocb(phba, cmdiocb); + return; + } + ++/** ++ * lpfc_issue_els_adisc: Issue an address discover iocb to an node on a vport. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine issues an Address Discover (ADISC) for an @ndlp on a ++ * @vport. It prepares the payload of the ADISC ELS command, updates the ++ * and states of the ndlp, and invokes the lpfc_sli_issue_iocb() routine ++ * to issue the ADISC ELS command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the ADISC ELS command. ++ * ++ * Return code ++ * 0 - successfully issued adisc ++ * 1 - failed to issue adisc ++ **/ + int + lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint8_t retry) +@@ -1437,6 +1827,18 @@ lpfc_issue_els_adisc(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_cmpl_els_logo: Completion callback function for logo. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion function for issuing the ELS Logout (LOGO) ++ * command. If no error status was reported from the LOGO response, the ++ * state machine of the associated ndlp shall be invoked for transition with ++ * respect to NLP_EVT_CMPL_LOGO event. Otherwise, if error status was reported, ++ * the lpfc_els_retry() routine will be invoked to retry the LOGO command. ++ **/ + static void + lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -1502,6 +1904,26 @@ out: + return; + } + ++/** ++ * lpfc_issue_els_logo: Issue a logo to an node on a vport. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine constructs and issues an ELS Logout (LOGO) iocb command ++ * to a remote node, referred by an @ndlp on a @vport. It constructs the ++ * payload of the IOCB, properly sets up the @ndlp state, and invokes the ++ * lpfc_sli_issue_iocb() routine to send out the LOGO ELS command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the LOGO ELS command. ++ * ++ * Return code ++ * 0 - successfully issued logo ++ * 1 - failed to issue logo ++ **/ + int + lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint8_t retry) +@@ -1563,6 +1985,22 @@ lpfc_issue_els_logo(struct lpfc_vport *v + return 0; + } + ++/** ++ * lpfc_cmpl_els_cmd: Completion callback function for generic els command. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is a generic completion callback function for ELS commands. ++ * Specifically, it is the callback function which does not need to perform ++ * any command specific operations. It is currently used by the ELS command ++ * issuing routines for the ELS State Change Request (SCR), ++ * lpfc_issue_els_scr(), and the ELS Fibre Channel Address Resolution ++ * Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). Other than ++ * certain debug loggings, this callback function simply invokes the ++ * lpfc_els_chk_latt() routine to check whether link went down during the ++ * discovery process. ++ **/ + static void + lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -1587,6 +2025,28 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, + return; + } + ++/** ++ * lpfc_issue_els_scr: Issue a scr to an node on a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @nportid: N_Port identifier to the remote node. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine issues a State Change Request (SCR) to a fabric node ++ * on a @vport. The remote node @nportid is passed into the function. It ++ * first search the @vport node list to find the matching ndlp. If no such ++ * ndlp is found, a new ndlp shall be created for this (SCR) purpose. An ++ * IOCB is allocated, payload prepared, and the lpfc_sli_issue_iocb() ++ * routine is invoked to send the SCR IOCB. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the SCR ELS command. ++ * ++ * Return code ++ * 0 - Successfully issued scr command ++ * 1 - Failed to issue scr command ++ **/ + int + lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) + { +@@ -1659,6 +2119,28 @@ lpfc_issue_els_scr(struct lpfc_vport *vp + return 0; + } + ++/** ++ * lpfc_issue_els_farpr: Issue a farp to an node on a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @nportid: N_Port identifier to the remote node. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine issues a Fibre Channel Address Resolution Response ++ * (FARPR) to a node on a vport. The remote node N_Port identifier (@nportid) ++ * is passed into the function. It first search the @vport node list to find ++ * the matching ndlp. If no such ndlp is found, a new ndlp shall be created ++ * for this (FARPR) purpose. An IOCB is allocated, payload prepared, and the ++ * lpfc_sli_issue_iocb() routine is invoked to send the FARPR ELS command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the PARPR ELS command. ++ * ++ * Return code ++ * 0 - Successfully issued farpr command ++ * 1 - Failed to issue farpr command ++ **/ + static int + lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) + { +@@ -1748,6 +2230,18 @@ lpfc_issue_els_farpr(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_cancel_retry_delay_tmo: Cancel the timer with delayed iocb-cmd retry. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @nlp: pointer to a node-list data structure. ++ * ++ * This routine cancels the timer with a delayed IOCB-command retry for ++ * a @vport's @ndlp. It stops the timer for the delayed function retrial and ++ * removes the ELS retry event if it presents. In addition, if the ++ * NLP_NPR_2B_DISC bit is set in the @nlp's nlp_flag bitmap, ADISC IOCB ++ * commands are sent for the @vport's nodes that require issuing discovery ++ * ADISC. ++ **/ + void + lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) + { +@@ -1775,25 +2269,36 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_ + if (vport->port_state < LPFC_VPORT_READY) { + /* Check if there are more ADISCs to be sent */ + lpfc_more_adisc(vport); +- if ((vport->num_disc_nodes == 0) && +- (vport->fc_npr_cnt)) +- lpfc_els_disc_plogi(vport); + } else { + /* Check if there are more PLOGIs to be sent */ + lpfc_more_plogi(vport); +- } +- if (vport->num_disc_nodes == 0) { +- spin_lock_irq(shost->host_lock); +- vport->fc_flag &= ~FC_NDISC_ACTIVE; +- spin_unlock_irq(shost->host_lock); +- lpfc_can_disctmo(vport); +- lpfc_end_rscn(vport); ++ if (vport->num_disc_nodes == 0) { ++ spin_lock_irq(shost->host_lock); ++ vport->fc_flag &= ~FC_NDISC_ACTIVE; ++ spin_unlock_irq(shost->host_lock); ++ lpfc_can_disctmo(vport); ++ lpfc_end_rscn(vport); ++ } + } + } + } + return; + } + ++/** ++ * lpfc_els_retry_delay: Timer function with a ndlp delayed function timer. ++ * @ptr: holder for the pointer to the timer function associated data (ndlp). ++ * ++ * This routine is invoked by the ndlp delayed-function timer to check ++ * whether there is any pending ELS retry event(s) with the node. If not, it ++ * simply returns. Otherwise, if there is at least one ELS delayed event, it ++ * adds the delayed events to the HBA work list and invokes the ++ * lpfc_worker_wake_up() routine to wake up worker thread to process the ++ * event. Note that lpfc_nlp_get() is called before posting the event to ++ * the work list to hold reference count of ndlp so that it guarantees the ++ * reference to ndlp will still be available when the worker thread gets ++ * to the event associated with the ndlp. ++ **/ + void + lpfc_els_retry_delay(unsigned long ptr) + { +@@ -1822,6 +2327,15 @@ lpfc_els_retry_delay(unsigned long ptr) + return; + } + ++/** ++ * lpfc_els_retry_delay_handler: Work thread handler for ndlp delayed function. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine is the worker-thread handler for processing the @ndlp delayed ++ * event(s), posted by the lpfc_els_retry_delay() routine. It simply retrieves ++ * the last ELS command from the associated ndlp and invokes the proper ELS ++ * function according to the delayed ELS command to retry the command. ++ **/ + void + lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) + { +@@ -1884,6 +2398,27 @@ lpfc_els_retry_delay_handler(struct lpfc + return; + } + ++/** ++ * lpfc_els_retry: Make retry decision on an els command iocb. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine makes a retry decision on an ELS command IOCB, which has ++ * failed. The following ELS IOCBs use this function for retrying the command ++ * when previously issued command responsed with error status: FLOGI, PLOGI, ++ * PRLI, ADISC, LOGO, and FDISC. Based on the ELS command type and the ++ * returned error status, it makes the decision whether a retry shall be ++ * issued for the command, and whether a retry shall be made immediately or ++ * delayed. In the former case, the corresponding ELS command issuing-function ++ * is called to retry the command. In the later case, the ELS command shall ++ * be posted to the ndlp delayed event and delayed function timer set to the ++ * ndlp for the delayed command issusing. ++ * ++ * Return code ++ * 0 - No retry of els command is made ++ * 1 - Immediate or delayed retry of els command is made ++ **/ + static int + lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -2051,7 +2586,7 @@ lpfc_els_retry(struct lpfc_hba *phba, st + (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID)) + ) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, +- "0123 FDISC Failed (x%x). " ++ "0122 FDISC Failed (x%x). " + "Fabric Detected Bad WWN\n", + stat.un.lsRjtError); + lpfc_vport_set_state(vport, +@@ -2182,12 +2717,26 @@ lpfc_els_retry(struct lpfc_hba *phba, st + return 0; + } + ++/** ++ * lpfc_els_free_data: Free lpfc dma buffer and data structure with an iocb. ++ * @phba: pointer to lpfc hba data structure. ++ * @buf_ptr1: pointer to the lpfc DMA buffer data structure. ++ * ++ * This routine releases the lpfc DMA (Direct Memory Access) buffer(s) ++ * associated with a command IOCB back to the lpfc DMA buffer pool. It first ++ * checks to see whether there is a lpfc DMA buffer associated with the ++ * response of the command IOCB. If so, it will be released before releasing ++ * the lpfc DMA buffer associated with the IOCB itself. ++ * ++ * Return code ++ * 0 - Successfully released lpfc DMA buffer (currently, always return 0) ++ **/ + static int + lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1) + { + struct lpfc_dmabuf *buf_ptr; + +- /* Free the response before processing the command. */ ++ /* Free the response before processing the command. */ + if (!list_empty(&buf_ptr1->list)) { + list_remove_head(&buf_ptr1->list, buf_ptr, + struct lpfc_dmabuf, +@@ -2200,6 +2749,18 @@ lpfc_els_free_data(struct lpfc_hba *phba + return 0; + } + ++/** ++ * lpfc_els_free_bpl: Free lpfc dma buffer and data structure with bpl. ++ * @phba: pointer to lpfc hba data structure. ++ * @buf_ptr: pointer to the lpfc dma buffer data structure. ++ * ++ * This routine releases the lpfc Direct Memory Access (DMA) buffer ++ * associated with a Buffer Pointer List (BPL) back to the lpfc DMA buffer ++ * pool. ++ * ++ * Return code ++ * 0 - Successfully released lpfc DMA buffer (currently, always return 0) ++ **/ + static int + lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) + { +@@ -2208,6 +2769,33 @@ lpfc_els_free_bpl(struct lpfc_hba *phba, + return 0; + } + ++/** ++ * lpfc_els_free_iocb: Free a command iocb and its associated resources. ++ * @phba: pointer to lpfc hba data structure. ++ * @elsiocb: pointer to lpfc els command iocb data structure. ++ * ++ * This routine frees a command IOCB and its associated resources. The ++ * command IOCB data structure contains the reference to various associated ++ * resources, these fields must be set to NULL if the associated reference ++ * not present: ++ * context1 - reference to ndlp ++ * context2 - reference to cmd ++ * context2->next - reference to rsp ++ * context3 - reference to bpl ++ * ++ * It first properly decrements the reference count held on ndlp for the ++ * IOCB completion callback function. If LPFC_DELAY_MEM_FREE flag is not ++ * set, it invokes the lpfc_els_free_data() routine to release the Direct ++ * Memory Access (DMA) buffers associated with the IOCB. Otherwise, it ++ * adds the DMA buffer the @phba data structure for the delayed release. ++ * If reference to the Buffer Pointer List (BPL) is present, the ++ * lpfc_els_free_bpl() routine is invoked to release the DMA memory ++ * associated with BPL. Finally, the lpfc_sli_release_iocbq() routine is ++ * invoked to release the IOCB data structure back to @phba IOCBQ list. ++ * ++ * Return code ++ * 0 - Success (currently, always return 0) ++ **/ + int + lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) + { +@@ -2274,6 +2862,23 @@ lpfc_els_free_iocb(struct lpfc_hba *phba + return 0; + } + ++/** ++ * lpfc_cmpl_els_logo_acc: Completion callback function to logo acc response. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion callback function to the Logout (LOGO) ++ * Accept (ACC) Response ELS command. This routine is invoked to indicate ++ * the completion of the LOGO process. It invokes the lpfc_nlp_not_used() to ++ * release the ndlp if it has the last reference remaining (reference count ++ * is 1). If succeeded (meaning ndlp released), it sets the IOCB context1 ++ * field to NULL to inform the following lpfc_els_free_iocb() routine no ++ * ndlp reference count needs to be decremented. Otherwise, the ndlp ++ * reference use-count shall be decremented by the lpfc_els_free_iocb() ++ * routine. Finally, the lpfc_els_free_iocb() is invoked to release the ++ * IOCB data structure. ++ **/ + static void + lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -2311,6 +2916,19 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * + return; + } + ++/** ++ * lpfc_mbx_cmpl_dflt_rpi: Completion callbk func for unreg dflt rpi mbox cmd. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * This routine is the completion callback function for unregister default ++ * RPI (Remote Port Index) mailbox command to the @phba. It simply releases ++ * the associated lpfc Direct Memory Access (DMA) buffer back to the pool and ++ * decrements the ndlp reference count held for this completion callback ++ * function. After that, it invokes the lpfc_nlp_not_used() to check ++ * whether there is only one reference left on the ndlp. If so, it will ++ * perform one more decrement and trigger the release of the ndlp. ++ **/ + void + lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + { +@@ -2332,6 +2950,22 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba * + return; + } + ++/** ++ * lpfc_cmpl_els_rsp: Completion callback function for els response iocb cmd. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion callback function for ELS Response IOCB ++ * command. In normal case, this callback function just properly sets the ++ * nlp_flag bitmap in the ndlp data structure, if the mbox command reference ++ * field in the command IOCB is not NULL, the referred mailbox command will ++ * be send out, and then invokes the lpfc_els_free_iocb() routine to release ++ * the IOCB. Under error conditions, such as when a LS_RJT is returned or a ++ * link down event occurred during the discovery, the lpfc_nlp_not_used() ++ * routine shall be invoked trying to release the ndlp if no other threads ++ * are currently referring it. ++ **/ + static void + lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -2487,6 +3121,31 @@ out: + return; + } + ++/** ++ * lpfc_els_rsp_acc: Prepare and issue an acc response iocb command. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @flag: the els command code to be accepted. ++ * @oldiocb: pointer to the original lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @mbox: pointer to the driver internal queue element for mailbox command. ++ * ++ * This routine prepares and issues an Accept (ACC) response IOCB ++ * command. It uses the @flag to properly set up the IOCB field for the ++ * specific ACC response command to be issued and invokes the ++ * lpfc_sli_issue_iocb() routine to send out ACC response IOCB. If a ++ * @mbox pointer is passed in, it will be put into the context_un.mbox ++ * field of the IOCB for the completion callback function to issue the ++ * mailbox command to the HBA later when callback is invoked. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the corresponding response ELS IOCB command. ++ * ++ * Return code ++ * 0 - Successfully issued acc response ++ * 1 - Failed to issue acc response ++ **/ + int + lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, + struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, +@@ -2601,6 +3260,28 @@ lpfc_els_rsp_acc(struct lpfc_vport *vpor + return 0; + } + ++/** ++ * lpfc_els_rsp_reject: Propare and issue a rjt response iocb command. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @rejectError: ++ * @oldiocb: pointer to the original lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @mbox: pointer to the driver internal queue element for mailbox command. ++ * ++ * This routine prepares and issue an Reject (RJT) response IOCB ++ * command. If a @mbox pointer is passed in, it will be put into the ++ * context_un.mbox field of the IOCB for the completion callback function ++ * to issue to the HBA later. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the reject response ELS IOCB command. ++ * ++ * Return code ++ * 0 - Successfully issued reject response ++ * 1 - Failed to issue reject response ++ **/ + int + lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, + struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, +@@ -2660,6 +3341,25 @@ lpfc_els_rsp_reject(struct lpfc_vport *v + return 0; + } + ++/** ++ * lpfc_els_rsp_adisc_acc: Prepare and issue acc response to adisc iocb cmd. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @oldiocb: pointer to the original lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine prepares and issues an Accept (ACC) response to Address ++ * Discover (ADISC) ELS command. It simply prepares the payload of the IOCB ++ * and invokes the lpfc_sli_issue_iocb() routine to send out the command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the ADISC Accept response ELS IOCB command. ++ * ++ * Return code ++ * 0 - Successfully issued acc adisc response ++ * 1 - Failed to issue adisc acc response ++ **/ + int + lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, + struct lpfc_nodelist *ndlp) +@@ -2716,6 +3416,25 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport + return 0; + } + ++/** ++ * lpfc_els_rsp_prli_acc: Prepare and issue acc response to prli iocb cmd. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @oldiocb: pointer to the original lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine prepares and issues an Accept (ACC) response to Process ++ * Login (PRLI) ELS command. It simply prepares the payload of the IOCB ++ * and invokes the lpfc_sli_issue_iocb() routine to send out the command. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the PRLI Accept response ELS IOCB command. ++ * ++ * Return code ++ * 0 - Successfully issued acc prli response ++ * 1 - Failed to issue acc prli response ++ **/ + int + lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, + struct lpfc_nodelist *ndlp) +@@ -2795,6 +3514,32 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport + return 0; + } + ++/** ++ * lpfc_els_rsp_rnid_acc: Issue rnid acc response iocb command. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @format: rnid command format. ++ * @oldiocb: pointer to the original lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine issues a Request Node Identification Data (RNID) Accept ++ * (ACC) response. It constructs the RNID ACC response command according to ++ * the proper @format and then calls the lpfc_sli_issue_iocb() routine to ++ * issue the response. Note that this command does not need to hold the ndlp ++ * reference count for the callback. So, the ndlp reference count taken by ++ * the lpfc_prep_els_iocb() routine is put back and the context1 field of ++ * IOCB is set to NULL to indicate to the lpfc_els_free_iocb() routine that ++ * there is no ndlp reference available. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function. However, for the RNID Accept Response ELS command, ++ * this is undone later by this routine after the IOCB is allocated. ++ * ++ * Return code ++ * 0 - Successfully issued acc rnid response ++ * 1 - Failed to issue acc rnid response ++ **/ + static int + lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, + struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) +@@ -2875,6 +3620,25 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport + return 0; + } + ++/** ++ * lpfc_els_disc_adisc: Issue remaining adisc iocbs to npr nodes of a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine issues Address Discover (ADISC) ELS commands to those ++ * N_Ports which are in node port recovery state and ADISC has not been issued ++ * for the @vport. Each time an ELS ADISC IOCB is issued by invoking the ++ * lpfc_issue_els_adisc() routine, the per @vport number of discover count ++ * (num_disc_nodes) shall be incremented. If the num_disc_nodes reaches a ++ * pre-configured threshold (cfg_discovery_threads), the @vport fc_flag will ++ * be marked with FC_NLP_MORE bit and the process of issuing remaining ADISC ++ * IOCBs quit for later pick up. On the other hand, after walking through ++ * all the ndlps with the @vport and there is none ADISC IOCB issued, the ++ * @vport fc_flag shall be cleared with FC_NLP_MORE bit indicating there is ++ * no more ADISC need to be sent. ++ * ++ * Return code ++ * The number of N_Ports with adisc issued. ++ **/ + int + lpfc_els_disc_adisc(struct lpfc_vport *vport) + { +@@ -2914,6 +3678,25 @@ lpfc_els_disc_adisc(struct lpfc_vport *v + return sentadisc; + } + ++/** ++ * lpfc_els_disc_plogi: Issue plogi for all npr nodes of a vport before adisc. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine issues Port Login (PLOGI) ELS commands to all the N_Ports ++ * which are in node port recovery state, with a @vport. Each time an ELS ++ * ADISC PLOGI IOCB is issued by invoking the lpfc_issue_els_plogi() routine, ++ * the per @vport number of discover count (num_disc_nodes) shall be ++ * incremented. If the num_disc_nodes reaches a pre-configured threshold ++ * (cfg_discovery_threads), the @vport fc_flag will be marked with FC_NLP_MORE ++ * bit set and quit the process of issuing remaining ADISC PLOGIN IOCBs for ++ * later pick up. On the other hand, after walking through all the ndlps with ++ * the @vport and there is none ADISC PLOGI IOCB issued, the @vport fc_flag ++ * shall be cleared with the FC_NLP_MORE bit indicating there is no more ADISC ++ * PLOGI need to be sent. ++ * ++ * Return code ++ * The number of N_Ports with plogi issued. ++ **/ + int + lpfc_els_disc_plogi(struct lpfc_vport *vport) + { +@@ -2954,6 +3737,15 @@ lpfc_els_disc_plogi(struct lpfc_vport *v + return sentplogi; + } + ++/** ++ * lpfc_els_flush_rscn: Clean up any rscn activities with a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine cleans up any Registration State Change Notification ++ * (RSCN) activity with a @vport. Note that the fc_rscn_flush flag of the ++ * @vport together with the host_lock is used to prevent multiple thread ++ * trying to access the RSCN array on a same @vport at the same time. ++ **/ + void + lpfc_els_flush_rscn(struct lpfc_vport *vport) + { +@@ -2984,6 +3776,18 @@ lpfc_els_flush_rscn(struct lpfc_vport *v + vport->fc_rscn_flush = 0; + } + ++/** ++ * lpfc_rscn_payload_check: Check whether there is a pending rscn to a did. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @did: remote destination port identifier. ++ * ++ * This routine checks whether there is any pending Registration State ++ * Configuration Notification (RSCN) to a @did on @vport. ++ * ++ * Return code ++ * None zero - The @did matched with a pending rscn ++ * 0 - not able to match @did with a pending rscn ++ **/ + int + lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) + { +@@ -3053,6 +3857,17 @@ return_did_out: + return did; + } + ++/** ++ * lpfc_rscn_recovery_check: Send recovery event to vport nodes matching rscn ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine sends recovery (NLP_EVT_DEVICE_RECOVERY) event to the ++ * state machine for a @vport's nodes that are with pending RSCN (Registration ++ * State Change Notification). ++ * ++ * Return code ++ * 0 - Successful (currently alway return 0) ++ **/ + static int + lpfc_rscn_recovery_check(struct lpfc_vport *vport) + { +@@ -3071,6 +3886,28 @@ lpfc_rscn_recovery_check(struct lpfc_vpo + return 0; + } + ++/** ++ * lpfc_els_rcv_rscn: Process an unsolicited rscn iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes an unsolicited RSCN (Registration State Change ++ * Notification) IOCB. First, the payload of the unsolicited RSCN is walked ++ * to invoke fc_host_post_event() routine to the FC transport layer. If the ++ * discover state machine is about to begin discovery, it just accepts the ++ * RSCN and the discovery process will satisfy the RSCN. If this RSCN only ++ * contains N_Port IDs for other vports on this HBA, it just accepts the ++ * RSCN and ignore processing it. If the state machine is in the recovery ++ * state, the fc_rscn_id_list of this @vport is walked and the ++ * lpfc_rscn_recovery_check() routine is invoked to send recovery event for ++ * all nodes that match RSCN payload. Otherwise, the lpfc_els_handle_rscn() ++ * routine is invoked to handle the RSCN event. ++ * ++ * Return code ++ * 0 - Just sent the acc response ++ * 1 - Sent the acc response and waited for name server completion ++ **/ + static int + lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3130,7 +3967,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vpo + if (rscn_id == hba_id) { + /* ALL NPortIDs in RSCN are on HBA */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, +- "0214 Ignore RSCN " ++ "0219 Ignore RSCN " + "Data: x%x x%x x%x x%x\n", + vport->fc_flag, payload_len, + *lp, vport->fc_rscn_id_cnt); +@@ -3241,6 +4078,22 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vpo + return lpfc_els_handle_rscn(vport); + } + ++/** ++ * lpfc_els_handle_rscn: Handle rscn for a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine handles the Registration State Configuration Notification ++ * (RSCN) for a @vport. If login to NameServer does not exist, a new ndlp shall ++ * be created and a Port Login (PLOGI) to the NameServer is issued. Otherwise, ++ * if the ndlp to NameServer exists, a Common Transport (CT) command to the ++ * NameServer shall be issued. If CT command to the NameServer fails to be ++ * issued, the lpfc_els_flush_rscn() routine shall be invoked to clean up any ++ * RSCN activities with the @vport. ++ * ++ * Return code ++ * 0 - Cleaned up rscn on the @vport ++ * 1 - Wait for plogi to name server before proceed ++ **/ + int + lpfc_els_handle_rscn(struct lpfc_vport *vport) + { +@@ -3313,6 +4166,31 @@ lpfc_els_handle_rscn(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_els_rcv_flogi: Process an unsolicited flogi iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes Fabric Login (FLOGI) IOCB received as an ELS ++ * unsolicited event. An unsolicited FLOGI can be received in a point-to- ++ * point topology. As an unsolicited FLOGI should not be received in a loop ++ * mode, any unsolicited FLOGI received in loop mode shall be ignored. The ++ * lpfc_check_sparm() routine is invoked to check the parameters in the ++ * unsolicited FLOGI. If parameters validation failed, the routine ++ * lpfc_els_rsp_reject() shall be called with reject reason code set to ++ * LSEXP_SPARM_OPTIONS to reject the FLOGI. Otherwise, the Port WWN in the ++ * FLOGI shall be compared with the Port WWN of the @vport to determine who ++ * will initiate PLOGI. The higher lexicographical value party shall has ++ * higher priority (as the winning port) and will initiate PLOGI and ++ * communicate Port_IDs (Addresses) for both nodes in PLOGI. The result ++ * of this will be marked in the @vport fc_flag field with FC_PT2PT_PLOGI ++ * and then the lpfc_els_rsp_acc() routine is invoked to accept the FLOGI. ++ * ++ * Return code ++ * 0 - Successfully processed the unsolicited flogi ++ * 1 - Failed to process the unsolicited flogi ++ **/ + static int + lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3402,6 +4280,22 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vp + return 0; + } + ++/** ++ * lpfc_els_rcv_rnid: Process an unsolicited rnid iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes Request Node Identification Data (RNID) IOCB ++ * received as an ELS unsolicited event. Only when the RNID specified format ++ * 0x0 or 0xDF (Topology Discovery Specific Node Identification Data) ++ * present, this routine will invoke the lpfc_els_rsp_rnid_acc() routine to ++ * Accept (ACC) the RNID ELS command. All the other RNID formats are ++ * rejected by invoking the lpfc_els_rsp_reject() routine. ++ * ++ * Return code ++ * 0 - Successfully processed rnid iocb (currently always return 0) ++ **/ + static int + lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3441,6 +4335,19 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vpo + return 0; + } + ++/** ++ * lpfc_els_rcv_lirr: Process an unsolicited lirr iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes a Link Incident Report Registration(LIRR) IOCB ++ * received as an ELS unsolicited event. Currently, this function just invokes ++ * the lpfc_els_rsp_reject() routine to reject the LIRR IOCB unconditionally. ++ * ++ * Return code ++ * 0 - Successfully processed lirr iocb (currently always return 0) ++ **/ + static int + lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3456,6 +4363,25 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vpo + return 0; + } + ++/** ++ * lpfc_els_rsp_rps_acc: Completion callbk func for MBX_READ_LNK_STAT mbox cmd. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * This routine is the completion callback function for the MBX_READ_LNK_STAT ++ * mailbox command. This callback function is to actually send the Accept ++ * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It ++ * collects the link statistics from the completion of the MBX_READ_LNK_STAT ++ * mailbox command, constructs the RPS response with the link statistics ++ * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC ++ * response to the RPS. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the RPS Accept Response ELS IOCB command. ++ * ++ **/ + static void + lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + { +@@ -3531,6 +4457,24 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *ph + return; + } + ++/** ++ * lpfc_els_rcv_rps: Process an unsolicited rps iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes Read Port Status (RPS) IOCB received as an ++ * ELS unsolicited event. It first checks the remote port state. If the ++ * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE ++ * state, it invokes the lpfc_els_rsp_reject() routine to send the reject ++ * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command ++ * for reading the HBA link statistics. It is for the callback function, ++ * lpfc_els_rsp_rps_acc(), set to the MBX_READ_LNK_STAT mailbox command ++ * to actually sending out RPS Accept (ACC) response. ++ * ++ * Return codes ++ * 0 - Successfully processed rps iocb (currently always return 0) ++ **/ + static int + lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3544,14 +4488,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vpor + struct ls_rjt stat; + + if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && +- (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { +- stat.un.b.lsRjtRsvd0 = 0; +- stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; +- stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; +- stat.un.b.vendorUnique = 0; +- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, +- NULL); +- } ++ (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) ++ /* reject the unsolicited RPS request and done with it */ ++ goto reject_out; + + pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; + lp = (uint32_t *) pcmd->virt; +@@ -3584,6 +4523,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vpor + mempool_free(mbox, phba->mbox_mem_pool); + } + } ++ ++reject_out: ++ /* issue rejection response */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; +@@ -3592,6 +4534,25 @@ lpfc_els_rcv_rps(struct lpfc_vport *vpor + return 0; + } + ++/** ++ * lpfc_els_rsp_rpl_acc: Issue an accept rpl els command. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdsize: size of the ELS command. ++ * @oldiocb: pointer to the original lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine issuees an Accept (ACC) Read Port List (RPL) ELS command. ++ * It is to be called by the lpfc_els_rcv_rpl() routine to accept the RPL. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the RPL Accept Response ELS command. ++ * ++ * Return code ++ * 0 - Successfully issued ACC RPL ELS command ++ * 1 - Failed to issue ACC RPL ELS command ++ **/ + static int + lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, + struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) +@@ -3645,6 +4606,22 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_els_rcv_rpl: Process an unsolicited rpl iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes Read Port List (RPL) IOCB received as an ELS ++ * unsolicited event. It first checks the remote port state. If the remote ++ * port is not in NLP_STE_UNMAPPED_NODE and NLP_STE_MAPPED_NODE states, it ++ * invokes the lpfc_els_rsp_reject() routine to send reject response. ++ * Otherwise, this routine then invokes the lpfc_els_rsp_rpl_acc() routine ++ * to accept the RPL. ++ * ++ * Return code ++ * 0 - Successfully processed rpl iocb (currently always return 0) ++ **/ + static int + lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3658,12 +4635,15 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vpor + + if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && + (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { ++ /* issue rejection response */ + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, + NULL); ++ /* rejected the unsolicited RPL request and done with it */ ++ return 0; + } + + pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; +@@ -3685,6 +4665,30 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vpor + return 0; + } + ++/** ++ * lpfc_els_rcv_farp: Process an unsolicited farp request els command. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes Fibre Channel Address Resolution Protocol ++ * (FARP) Request IOCB received as an ELS unsolicited event. Currently, ++ * the lpfc driver only supports matching on WWPN or WWNN for FARP. As such, ++ * FARP_MATCH_PORT flag and FARP_MATCH_NODE flag are checked against the ++ * Match Flag in the FARP request IOCB: if FARP_MATCH_PORT flag is set, the ++ * remote PortName is compared against the FC PortName stored in the @vport ++ * data structure; if FARP_MATCH_NODE flag is set, the remote NodeName is ++ * compared against the FC NodeName stored in the @vport data structure. ++ * If any of these matches and the FARP_REQUEST_FARPR flag is set in the ++ * FARP request IOCB Response Flag, the lpfc_issue_els_farpr() routine is ++ * invoked to send out FARP Response to the remote node. Before sending the ++ * FARP Response, however, the FARP_REQUEST_PLOGI flag is check in the FARP ++ * request IOCB Response Flag and, if it is set, the lpfc_issue_els_plogi() ++ * routine is invoked to log into the remote port first. ++ * ++ * Return code ++ * 0 - Either the FARP Match Mode not supported or successfully processed ++ **/ + static int + lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3744,6 +4748,20 @@ lpfc_els_rcv_farp(struct lpfc_vport *vpo + return 0; + } + ++/** ++ * lpfc_els_rcv_farpr: Process an unsolicited farp response iocb. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes Fibre Channel Address Resolution Protocol ++ * Response (FARPR) IOCB received as an ELS unsolicited event. It simply ++ * invokes the lpfc_els_rsp_acc() routine to the remote node to accept ++ * the FARP response request. ++ * ++ * Return code ++ * 0 - Successfully processed FARPR IOCB (currently always return 0) ++ **/ + static int + lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +@@ -3768,6 +4786,25 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vp + return 0; + } + ++/** ++ * lpfc_els_rcv_fan: Process an unsolicited fan iocb command. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @fan_ndlp: pointer to a node-list data structure. ++ * ++ * This routine processes a Fabric Address Notification (FAN) IOCB ++ * command received as an ELS unsolicited event. The FAN ELS command will ++ * only be processed on a physical port (i.e., the @vport represents the ++ * physical port). The fabric NodeName and PortName from the FAN IOCB are ++ * compared against those in the phba data structure. If any of those is ++ * different, the lpfc_initial_flogi() routine is invoked to initialize ++ * Fabric Login (FLOGI) to the fabric to start the discover over. Otherwise, ++ * if both of those are identical, the lpfc_issue_fabric_reglogin() routine ++ * is invoked to register login to the fabric. ++ * ++ * Return code ++ * 0 - Successfully processed fan iocb (currently always return 0). ++ **/ + static int + lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *fan_ndlp) +@@ -3797,6 +4834,16 @@ lpfc_els_rcv_fan(struct lpfc_vport *vpor + return 0; + } + ++/** ++ * lpfc_els_timeout: Handler funciton to the els timer. ++ * @ptr: holder for the timer function associated data. ++ * ++ * This routine is invoked by the ELS timer after timeout. It posts the ELS ++ * timer timeout event by setting the WORKER_ELS_TMO bit to the work port ++ * event bitmap and then invokes the lpfc_worker_wake_up() routine to wake ++ * up the worker thread. It is for the worker thread to invoke the routine ++ * lpfc_els_timeout_handler() to work on the posted event WORKER_ELS_TMO. ++ **/ + void + lpfc_els_timeout(unsigned long ptr) + { +@@ -3816,6 +4863,15 @@ lpfc_els_timeout(unsigned long ptr) + return; + } + ++/** ++ * lpfc_els_timeout_handler: Process an els timeout event. ++ * @vport: pointer to a virtual N_Port data structure. ++ * ++ * This routine is the actual handler function that processes an ELS timeout ++ * event. It walks the ELS ring to get and abort all the IOCBs (except the ++ * ABORT/CLOSE/FARP/FARPR/FDISC), which are associated with the @vport by ++ * invoking the lpfc_sli_issue_abort_iotag() routine. ++ **/ + void + lpfc_els_timeout_handler(struct lpfc_vport *vport) + { +@@ -3886,6 +4942,26 @@ lpfc_els_timeout_handler(struct lpfc_vpo + mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); + } + ++/** ++ * lpfc_els_flush_cmd: Clean up the outstanding els commands to a vport. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * ++ * This routine is used to clean up all the outstanding ELS commands on a ++ * @vport. It first aborts the @vport by invoking lpfc_fabric_abort_vport() ++ * routine. After that, it walks the ELS transmit queue to remove all the ++ * IOCBs with the @vport other than the QUE_RING and ABORT/CLOSE IOCBs. For ++ * the IOCBs with a non-NULL completion callback function, the callback ++ * function will be invoked with the status set to IOSTAT_LOCAL_REJECT and ++ * un.ulpWord[4] set to IOERR_SLI_ABORTED. For IOCBs with a NULL completion ++ * callback function, the IOCB will simply be released. Finally, it walks ++ * the ELS transmit completion queue to issue an abort IOCB to any transmit ++ * completion queue IOCB that is associated with the @vport and is not ++ * an IOCB from libdfc (i.e., the management plane IOCBs that are not ++ * part of the discovery state machine) out to HBA by invoking the ++ * lpfc_sli_issue_abort_iotag() routine. Note that this function issues the ++ * abort IOCB to any transmit completion queueed IOCB, it does not guarantee ++ * the IOCBs are aborted when this function returns. ++ **/ + void + lpfc_els_flush_cmd(struct lpfc_vport *vport) + { +@@ -3948,6 +5024,23 @@ lpfc_els_flush_cmd(struct lpfc_vport *vp + return; + } + ++/** ++ * lpfc_els_flush_all_cmd: Clean up all the outstanding els commands to a HBA. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is used to clean up all the outstanding ELS commands on a ++ * @phba. It first aborts the @phba by invoking the lpfc_fabric_abort_hba() ++ * routine. After that, it walks the ELS transmit queue to remove all the ++ * IOCBs to the @phba other than the QUE_RING and ABORT/CLOSE IOCBs. For ++ * the IOCBs with the completion callback function associated, the callback ++ * function will be invoked with the status set to IOSTAT_LOCAL_REJECT and ++ * un.ulpWord[4] set to IOERR_SLI_ABORTED. For IOCBs without the completion ++ * callback function associated, the IOCB will simply be released. Finally, ++ * it walks the ELS transmit completion queue to issue an abort IOCB to any ++ * transmit completion queue IOCB that is not an IOCB from libdfc (i.e., the ++ * management plane IOCBs that are not part of the discovery state machine) ++ * out to HBA by invoking the lpfc_sli_issue_abort_iotag() routine. ++ **/ + void + lpfc_els_flush_all_cmd(struct lpfc_hba *phba) + { +@@ -3992,6 +5085,130 @@ lpfc_els_flush_all_cmd(struct lpfc_hba + return; + } + ++/** ++ * lpfc_send_els_failure_event: Posts an ELS command failure event. ++ * @phba: Pointer to hba context object. ++ * @cmdiocbp: Pointer to command iocb which reported error. ++ * @rspiocbp: Pointer to response iocb which reported error. ++ * ++ * This function sends an event when there is an ELS command ++ * failure. ++ **/ ++void ++lpfc_send_els_failure_event(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdiocbp, ++ struct lpfc_iocbq *rspiocbp) ++{ ++ struct lpfc_vport *vport = cmdiocbp->vport; ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_lsrjt_event lsrjt_event; ++ struct lpfc_fabric_event_header fabric_event; ++ struct ls_rjt stat; ++ struct lpfc_nodelist *ndlp; ++ uint32_t *pcmd; ++ ++ ndlp = cmdiocbp->context1; ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) ++ return; ++ ++ if (rspiocbp->iocb.ulpStatus == IOSTAT_LS_RJT) { ++ lsrjt_event.header.event_type = FC_REG_ELS_EVENT; ++ lsrjt_event.header.subcategory = LPFC_EVENT_LSRJT_RCV; ++ memcpy(lsrjt_event.header.wwpn, &ndlp->nlp_portname, ++ sizeof(struct lpfc_name)); ++ memcpy(lsrjt_event.header.wwnn, &ndlp->nlp_nodename, ++ sizeof(struct lpfc_name)); ++ pcmd = (uint32_t *) (((struct lpfc_dmabuf *) ++ cmdiocbp->context2)->virt); ++ lsrjt_event.command = *pcmd; ++ stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]); ++ lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode; ++ lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp; ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(lsrjt_event), ++ (char *)&lsrjt_event, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ return; ++ } ++ if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) || ++ (rspiocbp->iocb.ulpStatus == IOSTAT_FABRIC_BSY)) { ++ fabric_event.event_type = FC_REG_FABRIC_EVENT; ++ if (rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) ++ fabric_event.subcategory = LPFC_EVENT_PORT_BUSY; ++ else ++ fabric_event.subcategory = LPFC_EVENT_FABRIC_BUSY; ++ memcpy(fabric_event.wwpn, &ndlp->nlp_portname, ++ sizeof(struct lpfc_name)); ++ memcpy(fabric_event.wwnn, &ndlp->nlp_nodename, ++ sizeof(struct lpfc_name)); ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(fabric_event), ++ (char *)&fabric_event, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ return; ++ } ++ ++} ++ ++/** ++ * lpfc_send_els_event: Posts unsolicited els event. ++ * @vport: Pointer to vport object. ++ * @ndlp: Pointer FC node object. ++ * @cmd: ELS command code. ++ * ++ * This function posts an event when there is an incoming ++ * unsolicited ELS command. ++ **/ ++static void ++lpfc_send_els_event(struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp, ++ uint32_t cmd) ++{ ++ struct lpfc_els_event_header els_data; ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ ++ els_data.event_type = FC_REG_ELS_EVENT; ++ switch (cmd) { ++ case ELS_CMD_PLOGI: ++ els_data.subcategory = LPFC_EVENT_PLOGI_RCV; ++ break; ++ case ELS_CMD_PRLO: ++ els_data.subcategory = LPFC_EVENT_PRLO_RCV; ++ break; ++ case ELS_CMD_ADISC: ++ els_data.subcategory = LPFC_EVENT_ADISC_RCV; ++ break; ++ default: ++ return; ++ } ++ memcpy(els_data.wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(els_data.wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(els_data), ++ (char *)&els_data, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ ++ return; ++} ++ ++ ++/** ++ * lpfc_els_unsol_buffer: Process an unsolicited event data buffer. ++ * @phba: pointer to lpfc hba data structure. ++ * @pring: pointer to a SLI ring. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @elsiocb: pointer to lpfc els command iocb data structure. ++ * ++ * This routine is used for processing the IOCB associated with a unsolicited ++ * event. It first determines whether there is an existing ndlp that matches ++ * the DID from the unsolicited IOCB. If not, it will create a new one with ++ * the DID from the unsolicited IOCB. The ELS command from the unsolicited ++ * IOCB is then used to invoke the proper routine and to set up proper state ++ * of the discovery state machine. ++ **/ + static void + lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) +@@ -4059,8 +5276,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p + } + + phba->fc_stat.elsRcvFrame++; +- if (elsiocb->context1) +- lpfc_nlp_put(elsiocb->context1); + + elsiocb->context1 = lpfc_nlp_get(ndlp); + elsiocb->vport = vport; +@@ -4081,6 +5296,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p + phba->fc_stat.elsRcvPLOGI++; + ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); + ++ lpfc_send_els_event(vport, ndlp, cmd); + if (vport->port_state < LPFC_DISC_AUTH) { + if (!(phba->pport->fc_flag & FC_PT2PT) || + (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { +@@ -4130,6 +5346,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvPRLO++; ++ lpfc_send_els_event(vport, ndlp, cmd); + if (vport->port_state < LPFC_DISC_AUTH) { + rjt_err = LSRJT_UNABLE_TPC; + break; +@@ -4147,6 +5364,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p + "RCV ADISC: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + ++ lpfc_send_els_event(vport, ndlp, cmd); + phba->fc_stat.elsRcvADISC++; + if (vport->port_state < LPFC_DISC_AUTH) { + rjt_err = LSRJT_UNABLE_TPC; +@@ -4270,6 +5488,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p + NULL); + } + ++ lpfc_nlp_put(elsiocb->context1); ++ elsiocb->context1 = NULL; + return; + + dropit: +@@ -4282,6 +5502,19 @@ dropit: + phba->fc_stat.elsRcvDrop++; + } + ++/** ++ * lpfc_find_vport_by_vpid: Find a vport on a HBA through vport identifier. ++ * @phba: pointer to lpfc hba data structure. ++ * @vpi: host virtual N_Port identifier. ++ * ++ * This routine finds a vport on a HBA (referred by @phba) through a ++ * @vpi. The function walks the HBA's vport list and returns the address ++ * of the vport with the matching @vpi. ++ * ++ * Return code ++ * NULL - No vport with the matching @vpi found ++ * Otherwise - Address to the vport with the matching @vpi. ++ **/ + static struct lpfc_vport * + lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) + { +@@ -4299,6 +5532,18 @@ lpfc_find_vport_by_vpid(struct lpfc_hba + return NULL; + } + ++/** ++ * lpfc_els_unsol_event: Process an unsolicited event from an els sli ring. ++ * @phba: pointer to lpfc hba data structure. ++ * @pring: pointer to a SLI ring. ++ * @elsiocb: pointer to lpfc els iocb data structure. ++ * ++ * This routine is used to process an unsolicited event received from a SLI ++ * (Service Level Interface) ring. The actual processing of the data buffer ++ * associated with the unsolicited event is done by invoking the routine ++ * lpfc_els_unsol_buffer() after properly set up the iocb buffer from the ++ * SLI ring on which the unsolicited event was received. ++ **/ + void + lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *elsiocb) +@@ -4309,6 +5554,7 @@ lpfc_els_unsol_event(struct lpfc_hba *ph + struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2; + struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3; + ++ elsiocb->context1 = NULL; + elsiocb->context2 = NULL; + elsiocb->context3 = NULL; + +@@ -4356,8 +5602,6 @@ lpfc_els_unsol_event(struct lpfc_hba *ph + * The different unsolicited event handlers would tell us + * if they are done with "mp" by setting context2 to NULL. + */ +- lpfc_nlp_put(elsiocb->context1); +- elsiocb->context1 = NULL; + if (elsiocb->context2) { + lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2); + elsiocb->context2 = NULL; +@@ -4376,6 +5620,19 @@ lpfc_els_unsol_event(struct lpfc_hba *ph + } + } + ++/** ++ * lpfc_do_scr_ns_plogi: Issue a plogi to the name server for scr. ++ * @phba: pointer to lpfc hba data structure. ++ * @vport: pointer to a virtual N_Port data structure. ++ * ++ * This routine issues a Port Login (PLOGI) to the Name Server with ++ * State Change Request (SCR) for a @vport. This routine will create an ++ * ndlp for the Name Server associated to the @vport if such node does ++ * not already exist. The PLOGI to Name Server is issued by invoking the ++ * lpfc_issue_els_plogi() routine. If Fabric-Device Management Interface ++ * (FDMI) is configured to the @vport, a FDMI node will be created and ++ * the PLOGI to FDMI is issued by invoking lpfc_issue_els_plogi() routine. ++ **/ + void + lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) + { +@@ -4434,6 +5691,18 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *ph + return; + } + ++/** ++ * lpfc_cmpl_reg_new_vport: Completion callback function to register new vport. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * This routine is the completion callback function to register new vport ++ * mailbox command. If the new vport mailbox command completes successfully, ++ * the fabric registration login shall be performed on physical port (the ++ * new vport created is actually a physical port, with VPI 0) or the port ++ * login to Name Server for State Change Request (SCR) will be performed ++ * on virtual port (real virtual port, with VPI greater than 0). ++ **/ + static void + lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + { +@@ -4491,6 +5760,15 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba + return; + } + ++/** ++ * lpfc_register_new_vport: Register a new vport with a HBA. ++ * @phba: pointer to lpfc hba data structure. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine registers the @vport as a new virtual port with a HBA. ++ * It is done through a registering vpi mailbox command. ++ **/ + static void + lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp) +@@ -4531,6 +5809,26 @@ mbox_err_exit: + return; + } + ++/** ++ * lpfc_cmpl_els_fdisc: Completion function for fdisc iocb command. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion callback function to a Fabric Discover ++ * (FDISC) ELS command. Since all the FDISC ELS commands are issued ++ * single threaded, each FDISC completion callback function will reset ++ * the discovery timer for all vports such that the timers will not get ++ * unnecessary timeout. The function checks the FDISC IOCB status. If error ++ * detected, the vport will be set to FC_VPORT_FAILED state. Otherwise,the ++ * vport will set to FC_VPORT_ACTIVE state. It then checks whether the DID ++ * assigned to the vport has been changed with the completion of the FDISC ++ * command. If so, both RPI (Remote Port Index) and VPI (Virtual Port Index) ++ * are unregistered from the HBA, and then the lpfc_register_new_vport() ++ * routine is invoked to register new vport with the HBA. Otherwise, the ++ * lpfc_do_scr_ns_plogi() routine is invoked to issue a PLOGI to the Name ++ * Server for State Change Request (SCR). ++ **/ + static void + lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -4565,58 +5863,80 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phb + goto out; + /* FDISC failed */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, +- "0124 FDISC failed. (%d/%d)\n", ++ "0126 FDISC failed. (%d/%d)\n", + irsp->ulpStatus, irsp->un.ulpWord[4]); ++ goto fdisc_failed; ++ } + if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_nlp_put(ndlp); + /* giving up on FDISC. Cancel discovery timer */ + lpfc_can_disctmo(vport); +- } else { +- spin_lock_irq(shost->host_lock); +- vport->fc_flag |= FC_FABRIC; +- if (vport->phba->fc_topology == TOPOLOGY_LOOP) +- vport->fc_flag |= FC_PUBLIC_LOOP; +- spin_unlock_irq(shost->host_lock); ++ spin_lock_irq(shost->host_lock); ++ vport->fc_flag |= FC_FABRIC; ++ if (vport->phba->fc_topology == TOPOLOGY_LOOP) ++ vport->fc_flag |= FC_PUBLIC_LOOP; ++ spin_unlock_irq(shost->host_lock); + +- vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; +- lpfc_vport_set_state(vport, FC_VPORT_ACTIVE); +- if ((vport->fc_prevDID != vport->fc_myDID) && +- !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { +- /* If our NportID changed, we need to ensure all +- * remaining NPORTs get unreg_login'ed so we can +- * issue unreg_vpi. +- */ +- list_for_each_entry_safe(np, next_np, +- &vport->fc_nodes, nlp_listp) { +- if (!NLP_CHK_NODE_ACT(ndlp) || +- (np->nlp_state != NLP_STE_NPR_NODE) || +- !(np->nlp_flag & NLP_NPR_ADISC)) +- continue; +- spin_lock_irq(shost->host_lock); +- np->nlp_flag &= ~NLP_NPR_ADISC; +- spin_unlock_irq(shost->host_lock); +- lpfc_unreg_rpi(vport, np); +- } +- lpfc_mbx_unreg_vpi(vport); ++ vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; ++ lpfc_vport_set_state(vport, FC_VPORT_ACTIVE); ++ if ((vport->fc_prevDID != vport->fc_myDID) && ++ !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { ++ /* If our NportID changed, we need to ensure all ++ * remaining NPORTs get unreg_login'ed so we can ++ * issue unreg_vpi. ++ */ ++ list_for_each_entry_safe(np, next_np, ++ &vport->fc_nodes, nlp_listp) { ++ if (!NLP_CHK_NODE_ACT(ndlp) || ++ (np->nlp_state != NLP_STE_NPR_NODE) || ++ !(np->nlp_flag & NLP_NPR_ADISC)) ++ continue; + spin_lock_irq(shost->host_lock); +- vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; ++ np->nlp_flag &= ~NLP_NPR_ADISC; + spin_unlock_irq(shost->host_lock); ++ lpfc_unreg_rpi(vport, np); + } +- +- if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) +- lpfc_register_new_vport(phba, vport, ndlp); +- else +- lpfc_do_scr_ns_plogi(phba, vport); +- +- /* Unconditionaly kick off releasing fabric node for vports */ +- lpfc_nlp_put(ndlp); ++ lpfc_mbx_unreg_vpi(vport); ++ spin_lock_irq(shost->host_lock); ++ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; ++ spin_unlock_irq(shost->host_lock); + } + ++ if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) ++ lpfc_register_new_vport(phba, vport, ndlp); ++ else ++ lpfc_do_scr_ns_plogi(phba, vport); ++ goto out; ++fdisc_failed: ++ lpfc_vport_set_state(vport, FC_VPORT_FAILED); ++ /* Cancel discovery timer */ ++ lpfc_can_disctmo(vport); ++ lpfc_nlp_put(ndlp); + out: + lpfc_els_free_iocb(phba, cmdiocb); + } + ++/** ++ * lpfc_issue_els_fdisc: Issue a fdisc iocb command. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * @retry: number of retries to the command IOCB. ++ * ++ * This routine prepares and issues a Fabric Discover (FDISC) IOCB to ++ * a remote node (@ndlp) off a @vport. It uses the lpfc_issue_fabric_iocb() ++ * routine to issue the IOCB, which makes sure only one outstanding fabric ++ * IOCB will be sent off HBA at any given time. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the FDISC ELS command. ++ * ++ * Return code ++ * 0 - Successfully issued fdisc iocb command ++ * 1 - Failed to issue fdisc iocb command ++ **/ + static int + lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint8_t retry) +@@ -4691,6 +6011,20 @@ lpfc_issue_els_fdisc(struct lpfc_vport * + return 0; + } + ++/** ++ * lpfc_cmpl_els_npiv_logo: Completion function with vport logo. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the completion callback function to the issuing of a LOGO ++ * ELS command off a vport. It frees the command IOCB and then decrement the ++ * reference count held on ndlp for this completion function, indicating that ++ * the reference to the ndlp is no long needed. Note that the ++ * lpfc_els_free_iocb() routine decrements the ndlp reference held for this ++ * callback function and an additional explicit ndlp reference decrementation ++ * will trigger the actual release of the ndlp. ++ **/ + static void + lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -4712,6 +6046,22 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba + lpfc_nlp_put(ndlp); + } + ++/** ++ * lpfc_issue_els_npiv_logo: Issue a logo off a vport. ++ * @vport: pointer to a virtual N_Port data structure. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine issues a LOGO ELS command to an @ndlp off a @vport. ++ * ++ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp ++ * will be incremented by 1 for holding the ndlp and the reference to ndlp ++ * will be stored into the context1 field of the IOCB for the completion ++ * callback function to the LOGO ELS command. ++ * ++ * Return codes ++ * 0 - Successfully issued logo off the @vport ++ * 1 - Failed to issue logo off the @vport ++ **/ + int + lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) + { +@@ -4757,6 +6107,17 @@ lpfc_issue_els_npiv_logo(struct lpfc_vpo + return 0; + } + ++/** ++ * lpfc_fabric_block_timeout: Handler function to the fabric block timer. ++ * @ptr: holder for the timer function associated data. ++ * ++ * This routine is invoked by the fabric iocb block timer after ++ * timeout. It posts the fabric iocb block timeout event by setting the ++ * WORKER_FABRIC_BLOCK_TMO bit to work port event bitmap and then invokes ++ * lpfc_worker_wake_up() routine to wake up the worker thread. It is for ++ * the worker thread to invoke the lpfc_unblock_fabric_iocbs() on the ++ * posted event WORKER_FABRIC_BLOCK_TMO. ++ **/ + void + lpfc_fabric_block_timeout(unsigned long ptr) + { +@@ -4775,6 +6136,16 @@ lpfc_fabric_block_timeout(unsigned long + return; + } + ++/** ++ * lpfc_resume_fabric_iocbs: Issue a fabric iocb from driver internal list. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine issues one fabric iocb from the driver internal list to ++ * the HBA. It first checks whether it's ready to issue one fabric iocb to ++ * the HBA (whether there is no outstanding fabric iocb). If so, it shall ++ * remove one pending fabric iocb from the driver internal list and invokes ++ * lpfc_sli_issue_iocb() routine to send the fabric iocb to the HBA. ++ **/ + static void + lpfc_resume_fabric_iocbs(struct lpfc_hba *phba) + { +@@ -4824,6 +6195,15 @@ repeat: + return; + } + ++/** ++ * lpfc_unblock_fabric_iocbs: Unblock issuing fabric iocb command. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine unblocks the issuing fabric iocb command. The function ++ * will clear the fabric iocb block bit and then invoke the routine ++ * lpfc_resume_fabric_iocbs() to issue one of the pending fabric iocb ++ * from the driver internal fabric iocb list. ++ **/ + void + lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba) + { +@@ -4833,6 +6213,15 @@ lpfc_unblock_fabric_iocbs(struct lpfc_hb + return; + } + ++/** ++ * lpfc_block_fabric_iocbs: Block issuing fabric iocb command. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine blocks the issuing fabric iocb for a specified amount of ++ * time (currently 100 ms). This is done by set the fabric iocb block bit ++ * and set up a timeout timer for 100ms. When the block bit is set, no more ++ * fabric iocb will be issued out of the HBA. ++ **/ + static void + lpfc_block_fabric_iocbs(struct lpfc_hba *phba) + { +@@ -4846,6 +6235,19 @@ lpfc_block_fabric_iocbs(struct lpfc_hba + return; + } + ++/** ++ * lpfc_cmpl_fabric_iocb: Completion callback function for fabric iocb. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * @rspiocb: pointer to lpfc response iocb data structure. ++ * ++ * This routine is the callback function that is put to the fabric iocb's ++ * callback function pointer (iocb->iocb_cmpl). The original iocb's callback ++ * function pointer has been stored in iocb->fabric_iocb_cmpl. This callback ++ * function first restores and invokes the original iocb's callback function ++ * and then invokes the lpfc_resume_fabric_iocbs() routine to issue the next ++ * fabric bound iocb from the driver internal fabric iocb list onto the wire. ++ **/ + static void + lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -4892,6 +6294,30 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *p + } + } + ++/** ++ * lpfc_issue_fabric_iocb: Issue a fabric iocb command. ++ * @phba: pointer to lpfc hba data structure. ++ * @iocb: pointer to lpfc command iocb data structure. ++ * ++ * This routine is used as the top-level API for issuing a fabric iocb command ++ * such as FLOGI and FDISC. To accommodate certain switch fabric, this driver ++ * function makes sure that only one fabric bound iocb will be outstanding at ++ * any given time. As such, this function will first check to see whether there ++ * is already an outstanding fabric iocb on the wire. If so, it will put the ++ * newly issued iocb onto the driver internal fabric iocb list, waiting to be ++ * issued later. Otherwise, it will issue the iocb on the wire and update the ++ * fabric iocb count it indicate that there is one fabric iocb on the wire. ++ * ++ * Note, this implementation has a potential sending out fabric IOCBs out of ++ * order. The problem is caused by the construction of the "ready" boolen does ++ * not include the condition that the internal fabric IOCB list is empty. As ++ * such, it is possible a fabric IOCB issued by this routine might be "jump" ++ * ahead of the fabric IOCBs in the internal list. ++ * ++ * Return code ++ * IOCB_SUCCESS - either fabric iocb put on the list or issued successfully ++ * IOCB_ERROR - failed to issue fabric iocb ++ **/ + static int + lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) + { +@@ -4937,7 +6363,17 @@ lpfc_issue_fabric_iocb(struct lpfc_hba * + return ret; + } + +- ++/** ++ * lpfc_fabric_abort_vport: Abort a vport's iocbs from driver fabric iocb list. ++ * @vport: pointer to a virtual N_Port data structure. ++ * ++ * This routine aborts all the IOCBs associated with a @vport from the ++ * driver internal fabric IOCB list. The list contains fabric IOCBs to be ++ * issued to the ELS IOCB ring. This abort function walks the fabric IOCB ++ * list, removes each IOCB associated with the @vport off the list, set the ++ * status feild to IOSTAT_LOCAL_REJECT, and invokes the callback function ++ * associated with the IOCB. ++ **/ + static void lpfc_fabric_abort_vport(struct lpfc_vport *vport) + { + LIST_HEAD(completions); +@@ -4967,6 +6403,17 @@ static void lpfc_fabric_abort_vport(stru + } + } + ++/** ++ * lpfc_fabric_abort_nport: Abort a ndlp's iocbs from driver fabric iocb list. ++ * @ndlp: pointer to a node-list data structure. ++ * ++ * This routine aborts all the IOCBs associated with an @ndlp from the ++ * driver internal fabric IOCB list. The list contains fabric IOCBs to be ++ * issued to the ELS IOCB ring. This abort function walks the fabric IOCB ++ * list, removes each IOCB associated with the @ndlp off the list, set the ++ * status feild to IOSTAT_LOCAL_REJECT, and invokes the callback function ++ * associated with the IOCB. ++ **/ + void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) + { + LIST_HEAD(completions); +@@ -4996,6 +6443,17 @@ void lpfc_fabric_abort_nport(struct lpfc + } + } + ++/** ++ * lpfc_fabric_abort_hba: Abort all iocbs on driver fabric iocb list. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine aborts all the IOCBs currently on the driver internal ++ * fabric IOCB list. The list contains fabric IOCBs to be issued to the ELS ++ * IOCB ring. This function takes the entire IOCB list off the fabric IOCB ++ * list, removes IOCBs off the list, set the status feild to ++ * IOSTAT_LOCAL_REJECT, and invokes the callback function associated with ++ * the IOCB. ++ **/ + void lpfc_fabric_abort_hba(struct lpfc_hba *phba) + { + LIST_HEAD(completions); +--- a/drivers/scsi/lpfc/lpfc.h ++++ b/drivers/scsi/lpfc/lpfc.h +@@ -34,7 +34,14 @@ struct lpfc_sli2_slim; + #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ + #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ + #define LPFC_VNAME_LEN 100 /* vport symbolic name length */ ++#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt ++ queue depth change in millisecs */ ++#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */ ++#define LPFC_MIN_TGT_QDEPTH 100 ++#define LPFC_MAX_TGT_QDEPTH 0xFFFF + ++#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data ++ collection. */ + /* + * Following time intervals are used of adjusting SCSI device + * queue depths when there are driver resource error or Firmware +@@ -49,6 +56,9 @@ struct lpfc_sli2_slim; + #define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ + #define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ + ++/* Error Attention event polling interval */ ++#define LPFC_ERATT_POLL_INTERVAL 5 /* EATT poll interval in seconds */ ++ + /* Define macros for 64 bit support */ + #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) + #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) +@@ -60,6 +70,9 @@ struct lpfc_sli2_slim; + + #define MAX_HBAEVT 32 + ++/* Number of MSI-X vectors the driver uses */ ++#define LPFC_MSIX_VECTORS 2 ++ + /* lpfc wait event data ready flag */ + #define LPFC_DATA_READY (1<<0) + +@@ -357,6 +370,7 @@ struct lpfc_vport { + uint32_t cfg_log_verbose; + uint32_t cfg_max_luns; + uint32_t cfg_enable_da_id; ++ uint32_t cfg_max_scsicmpl_time; + + uint32_t dev_loss_tmo_changed; + +@@ -369,6 +383,8 @@ struct lpfc_vport { + struct lpfc_debugfs_trc *disc_trc; + atomic_t disc_trc_cnt; + #endif ++ uint8_t stat_data_enabled; ++ uint8_t stat_data_blocked; + }; + + struct hbq_s { +@@ -407,10 +423,11 @@ struct lpfc_hba { + struct lpfc_sli sli; + uint32_t sli_rev; /* SLI2 or SLI3 */ + uint32_t sli3_options; /* Mask of enabled SLI3 options */ +-#define LPFC_SLI3_ENABLED 0x01 +-#define LPFC_SLI3_HBQ_ENABLED 0x02 +-#define LPFC_SLI3_NPIV_ENABLED 0x04 +-#define LPFC_SLI3_VPORT_TEARDOWN 0x08 ++#define LPFC_SLI3_HBQ_ENABLED 0x01 ++#define LPFC_SLI3_NPIV_ENABLED 0x02 ++#define LPFC_SLI3_VPORT_TEARDOWN 0x04 ++#define LPFC_SLI3_CRP_ENABLED 0x08 ++#define LPFC_SLI3_INB_ENABLED 0x10 + uint32_t iocb_cmd_size; + uint32_t iocb_rsp_size; + +@@ -422,10 +439,20 @@ struct lpfc_hba { + #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ + #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ + +- struct lpfc_sli2_slim *slim2p; +- struct lpfc_dmabuf hbqslimp; ++ uint32_t hba_flag; /* hba generic flags */ ++#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ + +- dma_addr_t slim2p_mapping; ++ struct lpfc_dmabuf slim2p; ++ ++ MAILBOX_t *mbox; ++ uint32_t *inb_ha_copy; ++ uint32_t *inb_counter; ++ uint32_t inb_last_counter; ++ uint32_t ha_copy; ++ struct _PCB *pcb; ++ struct _IOCB *IOCBs; ++ ++ struct lpfc_dmabuf hbqslimp; + + uint16_t pci_cfg_value; + +@@ -492,7 +519,7 @@ struct lpfc_hba { + + wait_queue_head_t work_waitq; + struct task_struct *worker_thread; +- long data_flags; ++ unsigned long data_flags; + + uint32_t hbq_in_use; /* HBQs in use flag */ + struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ +@@ -514,6 +541,7 @@ struct lpfc_hba { + void __iomem *HCregaddr; /* virtual address for host ctl reg */ + + struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */ ++ struct lpfc_pgp *port_gp; + uint32_t __iomem *hbq_put; /* Address in SLIM to HBQ put ptrs */ + uint32_t *hbq_get; /* Host mem address of HBQ get ptrs */ + +@@ -536,6 +564,7 @@ struct lpfc_hba { + uint8_t soft_wwn_enable; + + struct timer_list fcp_poll_timer; ++ struct timer_list eratt_poll; + + /* + * stat counters +@@ -565,7 +594,7 @@ struct lpfc_hba { + + struct fc_host_statistics link_stats; + enum intr_type_t intr_type; +- struct msix_entry msix_entries[1]; ++ struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; + + struct list_head port_list; + struct lpfc_vport *pport; /* physical lpfc_vport pointer */ +@@ -605,6 +634,7 @@ struct lpfc_hba { + unsigned long last_completion_time; + struct timer_list hb_tmofunc; + uint8_t hb_outstanding; ++ enum hba_temp_state over_temp_state; + /* ndlp reference management */ + spinlock_t ndlp_lock; + /* +@@ -613,7 +643,19 @@ struct lpfc_hba { + */ + #define QUE_BUFTAG_BIT (1<<31) + uint32_t buffer_tag_count; +- enum hba_temp_state over_temp_state; ++ int wait_4_mlo_maint_flg; ++ wait_queue_head_t wait_4_mlo_m_q; ++ /* data structure used for latency data collection */ ++#define LPFC_NO_BUCKET 0 ++#define LPFC_LINEAR_BUCKET 1 ++#define LPFC_POWER2_BUCKET 2 ++ uint8_t bucket_type; ++ uint32_t bucket_base; ++ uint32_t bucket_step; ++ ++/* Maximum number of events that can be outstanding at any time*/ ++#define LPFC_MAX_EVT_COUNT 512 ++ atomic_t fast_event_count; + }; + + static inline struct Scsi_Host * +@@ -650,15 +692,25 @@ lpfc_worker_wake_up(struct lpfc_hba *phb + return; + } + +-#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ +-#define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature +- event */ +- +-struct temp_event { +- uint32_t event_type; +- uint32_t event_code; +- uint32_t data; +-}; +-#define LPFC_CRIT_TEMP 0x1 +-#define LPFC_THRESHOLD_TEMP 0x2 +-#define LPFC_NORMAL_TEMP 0x3 ++static inline void ++lpfc_sli_read_hs(struct lpfc_hba *phba) ++{ ++ /* ++ * There was a link/board error. Read the status register to retrieve ++ * the error event and process it. ++ */ ++ phba->sli.slistat.err_attn_event++; ++ ++ /* Save status info */ ++ phba->work_hs = readl(phba->HSregaddr); ++ phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); ++ phba->work_status[1] = readl(phba->MBslimaddr + 0xac); ++ ++ /* Clear chip Host Attention error bit */ ++ writel(HA_ERATT, phba->HAregaddr); ++ readl(phba->HAregaddr); /* flush */ ++ phba->pport->stopped = 1; ++ ++ return; ++} ++ +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -30,6 +30,7 @@ + #include + + #include "lpfc_hw.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_sli.h" + #include "lpfc_scsi.h" +@@ -207,8 +208,16 @@ lpfc_dev_loss_tmo_handler(struct lpfc_no + return; + } + +- if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) ++ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, ++ "0284 Devloss timeout Ignored on " ++ "WWPN %x:%x:%x:%x:%x:%x:%x:%x " ++ "NPort x%x\n", ++ *name, *(name+1), *(name+2), *(name+3), ++ *(name+4), *(name+5), *(name+6), *(name+7), ++ ndlp->nlp_DID); + return; ++ } + + if (ndlp->nlp_type & NLP_FABRIC) { + /* We will clean up these Nodes in linkup */ +@@ -229,8 +238,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_no + lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], + ndlp->nlp_sid, 0, LPFC_CTX_TGT); + } +- if (vport->load_flag & FC_UNLOADING) +- warn_on = 0; + + if (warn_on) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, +@@ -268,6 +275,124 @@ lpfc_dev_loss_tmo_handler(struct lpfc_no + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); + } + ++/** ++ * lpfc_alloc_fast_evt: Allocates data structure for posting event. ++ * @phba: Pointer to hba context object. ++ * ++ * This function is called from the functions which need to post ++ * events from interrupt context. This function allocates data ++ * structure required for posting event. It also keeps track of ++ * number of events pending and prevent event storm when there are ++ * too many events. ++ **/ ++struct lpfc_fast_path_event * ++lpfc_alloc_fast_evt(struct lpfc_hba *phba) { ++ struct lpfc_fast_path_event *ret; ++ ++ /* If there are lot of fast event do not exhaust memory due to this */ ++ if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT) ++ return NULL; ++ ++ ret = kzalloc(sizeof(struct lpfc_fast_path_event), ++ GFP_ATOMIC); ++ if (ret) ++ atomic_inc(&phba->fast_event_count); ++ INIT_LIST_HEAD(&ret->work_evt.evt_listp); ++ ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; ++ return ret; ++} ++ ++/** ++ * lpfc_free_fast_evt: Frees event data structure. ++ * @phba: Pointer to hba context object. ++ * @evt: Event object which need to be freed. ++ * ++ * This function frees the data structure required for posting ++ * events. ++ **/ ++void ++lpfc_free_fast_evt(struct lpfc_hba *phba, ++ struct lpfc_fast_path_event *evt) { ++ ++ atomic_dec(&phba->fast_event_count); ++ kfree(evt); ++} ++ ++/** ++ * lpfc_send_fastpath_evt: Posts events generated from fast path. ++ * @phba: Pointer to hba context object. ++ * @evtp: Event data structure. ++ * ++ * This function is called from worker thread, when the interrupt ++ * context need to post an event. This function posts the event ++ * to fc transport netlink interface. ++ **/ ++static void ++lpfc_send_fastpath_evt(struct lpfc_hba *phba, ++ struct lpfc_work_evt *evtp) ++{ ++ unsigned long evt_category, evt_sub_category; ++ struct lpfc_fast_path_event *fast_evt_data; ++ char *evt_data; ++ uint32_t evt_data_size; ++ struct Scsi_Host *shost; ++ ++ fast_evt_data = container_of(evtp, struct lpfc_fast_path_event, ++ work_evt); ++ ++ evt_category = (unsigned long) fast_evt_data->un.fabric_evt.event_type; ++ evt_sub_category = (unsigned long) fast_evt_data->un. ++ fabric_evt.subcategory; ++ shost = lpfc_shost_from_vport(fast_evt_data->vport); ++ if (evt_category == FC_REG_FABRIC_EVENT) { ++ if (evt_sub_category == LPFC_EVENT_FCPRDCHKERR) { ++ evt_data = (char *) &fast_evt_data->un.read_check_error; ++ evt_data_size = sizeof(fast_evt_data->un. ++ read_check_error); ++ } else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) || ++ (evt_sub_category == IOSTAT_NPORT_BSY)) { ++ evt_data = (char *) &fast_evt_data->un.fabric_evt; ++ evt_data_size = sizeof(fast_evt_data->un.fabric_evt); ++ } else { ++ lpfc_free_fast_evt(phba, fast_evt_data); ++ return; ++ } ++ } else if (evt_category == FC_REG_SCSI_EVENT) { ++ switch (evt_sub_category) { ++ case LPFC_EVENT_QFULL: ++ case LPFC_EVENT_DEVBSY: ++ evt_data = (char *) &fast_evt_data->un.scsi_evt; ++ evt_data_size = sizeof(fast_evt_data->un.scsi_evt); ++ break; ++ case LPFC_EVENT_CHECK_COND: ++ evt_data = (char *) &fast_evt_data->un.check_cond_evt; ++ evt_data_size = sizeof(fast_evt_data->un. ++ check_cond_evt); ++ break; ++ case LPFC_EVENT_VARQUEDEPTH: ++ evt_data = (char *) &fast_evt_data->un.queue_depth_evt; ++ evt_data_size = sizeof(fast_evt_data->un. ++ queue_depth_evt); ++ break; ++ default: ++ lpfc_free_fast_evt(phba, fast_evt_data); ++ return; ++ } ++ } else { ++ lpfc_free_fast_evt(phba, fast_evt_data); ++ return; ++ } ++ ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ evt_data_size, ++ evt_data, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ ++ lpfc_free_fast_evt(phba, fast_evt_data); ++ return; ++} ++ + static void + lpfc_work_list_done(struct lpfc_hba *phba) + { +@@ -339,6 +464,10 @@ lpfc_work_list_done(struct lpfc_hba *phb + lpfc_unblock_mgmt_io(phba); + complete((struct completion *)(evtp->evt_arg2)); + break; ++ case LPFC_EVT_FASTPATH_MGMT_EVT: ++ lpfc_send_fastpath_evt(phba, evtp); ++ free_evt = 0; ++ break; + } + if (free_evt) + kfree(evtp); +@@ -363,6 +492,7 @@ lpfc_work_done(struct lpfc_hba *phba) + spin_unlock_irq(&phba->hbalock); + + if (ha_copy & HA_ERATT) ++ /* Handle the error attention event */ + lpfc_handle_eratt(phba); + + if (ha_copy & HA_MBATT) +@@ -370,6 +500,7 @@ lpfc_work_done(struct lpfc_hba *phba) + + if (ha_copy & HA_LATT) + lpfc_handle_latt(phba); ++ + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for(i = 0; i <= phba->max_vpi; i++) { +@@ -1005,14 +1136,10 @@ out: + } + + static void +-lpfc_mbx_issue_link_down(struct lpfc_hba *phba) ++lpfc_enable_la(struct lpfc_hba *phba) + { + uint32_t control; + struct lpfc_sli *psli = &phba->sli; +- +- lpfc_linkdown(phba); +- +- /* turn on Link Attention interrupts - no CLEAR_LA needed */ + spin_lock_irq(&phba->hbalock); + psli->sli_flag |= LPFC_PROCESS_LA; + control = readl(phba->HCregaddr); +@@ -1022,6 +1149,15 @@ lpfc_mbx_issue_link_down(struct lpfc_hba + spin_unlock_irq(&phba->hbalock); + } + ++static void ++lpfc_mbx_issue_link_down(struct lpfc_hba *phba) ++{ ++ lpfc_linkdown(phba); ++ lpfc_enable_la(phba); ++ /* turn on Link Attention interrupts - no CLEAR_LA needed */ ++} ++ ++ + /* + * This routine handles processing a READ_LA mailbox + * command upon completion. It is setup in the LPFC_MBOXQ +@@ -1069,8 +1205,12 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *p + } + + phba->fc_eventTag = la->eventTag; ++ if (la->mm) ++ phba->sli.sli_flag |= LPFC_MENLO_MAINT; ++ else ++ phba->sli.sli_flag &= ~LPFC_MENLO_MAINT; + +- if (la->attType == AT_LINK_UP) { ++ if (la->attType == AT_LINK_UP && (!la->mm)) { + phba->fc_stat.LinkUp++; + if (phba->link_flag & LS_LOOPBACK_MODE) { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, +@@ -1082,13 +1222,15 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *p + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + "1303 Link Up Event x%x received " +- "Data: x%x x%x x%x x%x\n", ++ "Data: x%x x%x x%x x%x x%x x%x %d\n", + la->eventTag, phba->fc_eventTag, + la->granted_AL_PA, la->UlnkSpeed, +- phba->alpa_map[0]); ++ phba->alpa_map[0], ++ la->mm, la->fa, ++ phba->wait_4_mlo_maint_flg); + } + lpfc_mbx_process_link_up(phba, la); +- } else { ++ } else if (la->attType == AT_LINK_DOWN) { + phba->fc_stat.LinkDown++; + if (phba->link_flag & LS_LOOPBACK_MODE) { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, +@@ -1101,11 +1243,46 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *p + else { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + "1305 Link Down Event x%x received " ++ "Data: x%x x%x x%x x%x x%x\n", ++ la->eventTag, phba->fc_eventTag, ++ phba->pport->port_state, vport->fc_flag, ++ la->mm, la->fa); ++ } ++ lpfc_mbx_issue_link_down(phba); ++ } ++ if (la->mm && la->attType == AT_LINK_UP) { ++ if (phba->link_state != LPFC_LINK_DOWN) { ++ phba->fc_stat.LinkDown++; ++ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, ++ "1312 Link Down Event x%x received " ++ "Data: x%x x%x x%x\n", ++ la->eventTag, phba->fc_eventTag, ++ phba->pport->port_state, vport->fc_flag); ++ lpfc_mbx_issue_link_down(phba); ++ } else ++ lpfc_enable_la(phba); ++ ++ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, ++ "1310 Menlo Maint Mode Link up Event x%x rcvd " + "Data: x%x x%x x%x\n", + la->eventTag, phba->fc_eventTag, + phba->pport->port_state, vport->fc_flag); ++ /* ++ * The cmnd that triggered this will be waiting for this ++ * signal. ++ */ ++ /* WAKEUP for MENLO_SET_MODE or MENLO_RESET command. */ ++ if (phba->wait_4_mlo_maint_flg) { ++ phba->wait_4_mlo_maint_flg = 0; ++ wake_up_interruptible(&phba->wait_4_mlo_m_q); + } +- lpfc_mbx_issue_link_down(phba); ++ } ++ ++ if (la->fa) { ++ if (la->mm) ++ lpfc_issue_clear_la(phba, vport); ++ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, ++ "1311 fa %d\n", la->fa); + } + + lpfc_mbx_cmpl_read_la_free_mbuf: +@@ -1169,7 +1346,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba + scsi_host_put(shost); + } + +-void ++int + lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) + { + struct lpfc_hba *phba = vport->phba; +@@ -1178,7 +1355,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vp + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) +- return; ++ return 1; + + lpfc_unreg_vpi(phba, vport->vpi, mbox); + mbox->vport = vport; +@@ -1189,7 +1366,9 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vp + "1800 Could not issue unreg_vpi\n"); + mempool_free(mbox, phba->mbox_mem_pool); + vport->unreg_vpi_cmpl = VPORT_ERROR; ++ return rc; + } ++ return 0; + } + + static void +@@ -1545,6 +1724,22 @@ lpfc_nlp_state_cleanup(struct lpfc_vport + */ + lpfc_register_remote_port(vport, ndlp); + } ++ if ((new_state == NLP_STE_MAPPED_NODE) && ++ (vport->stat_data_enabled)) { ++ /* ++ * A new target is discovered, if there is no buffer for ++ * statistical data collection allocate buffer. ++ */ ++ ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT, ++ sizeof(struct lpfc_scsicmd_bkt), ++ GFP_KERNEL); ++ ++ if (!ndlp->lat_data) ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, ++ "0286 lpfc_nlp_state_cleanup failed to " ++ "allocate statistical data buffer DID " ++ "0x%x\n", ndlp->nlp_DID); ++ } + /* + * if we added to Mapped list, but the remote port + * registration failed or assigned a target id outside +@@ -2778,7 +2973,7 @@ restart_disc: + + default: + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, +- "0229 Unexpected discovery timeout, " ++ "0273 Unexpected discovery timeout, " + "vport State x%x\n", vport->port_state); + break; + } +@@ -2932,6 +3127,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, + INIT_LIST_HEAD(&ndlp->nlp_listp); + kref_init(&ndlp->kref); + NLP_INT_NODE_ACT(ndlp); ++ atomic_set(&ndlp->cmd_pending, 0); ++ ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "node init: did:x%x", +@@ -2971,8 +3168,10 @@ lpfc_nlp_release(struct kref *kref) + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + + /* free ndlp memory for final ndlp release */ +- if (NLP_CHK_FREE_REQ(ndlp)) ++ if (NLP_CHK_FREE_REQ(ndlp)) { ++ kfree(ndlp->lat_data); + mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); ++ } + } + + /* This routine bumps the reference count for a ndlp structure to ensure +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -1107,6 +1107,8 @@ typedef struct { + /* Start FireFly Register definitions */ + #define PCI_VENDOR_ID_EMULEX 0x10df + #define PCI_DEVICE_ID_FIREFLY 0x1ae5 ++#define PCI_DEVICE_ID_PROTEUS_VF 0xe100 ++#define PCI_DEVICE_ID_PROTEUS_PF 0xe180 + #define PCI_DEVICE_ID_SAT_SMB 0xf011 + #define PCI_DEVICE_ID_SAT_MID 0xf015 + #define PCI_DEVICE_ID_RFLY 0xf095 +@@ -1133,10 +1135,12 @@ typedef struct { + #define PCI_DEVICE_ID_LP11000S 0xfc10 + #define PCI_DEVICE_ID_LPE11000S 0xfc20 + #define PCI_DEVICE_ID_SAT_S 0xfc40 ++#define PCI_DEVICE_ID_PROTEUS_S 0xfc50 + #define PCI_DEVICE_ID_HELIOS 0xfd00 + #define PCI_DEVICE_ID_HELIOS_SCSP 0xfd11 + #define PCI_DEVICE_ID_HELIOS_DCSP 0xfd12 + #define PCI_DEVICE_ID_ZEPHYR 0xfe00 ++#define PCI_DEVICE_ID_HORNET 0xfe05 + #define PCI_DEVICE_ID_ZEPHYR_SCSP 0xfe11 + #define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 + +@@ -1154,6 +1158,7 @@ typedef struct { + #define ZEPHYR_JEDEC_ID 0x0577 + #define VIPER_JEDEC_ID 0x4838 + #define SATURN_JEDEC_ID 0x1004 ++#define HORNET_JDEC_ID 0x2057706D + + #define JEDEC_ID_MASK 0x0FFFF000 + #define JEDEC_ID_SHIFT 12 +@@ -1198,6 +1203,18 @@ typedef struct { /* FireFly BIU registe + #define HA_RXATT 0x00000008 /* Bit 3 */ + #define HA_RXMASK 0x0000000f + ++#define HA_R0_CLR_MSK (HA_R0RE_REQ | HA_R0CE_RSP | HA_R0ATT) ++#define HA_R1_CLR_MSK (HA_R1RE_REQ | HA_R1CE_RSP | HA_R1ATT) ++#define HA_R2_CLR_MSK (HA_R2RE_REQ | HA_R2CE_RSP | HA_R2ATT) ++#define HA_R3_CLR_MSK (HA_R3RE_REQ | HA_R3CE_RSP | HA_R3ATT) ++ ++#define HA_R0_POS 3 ++#define HA_R1_POS 7 ++#define HA_R2_POS 11 ++#define HA_R3_POS 15 ++#define HA_LE_POS 29 ++#define HA_MB_POS 30 ++#define HA_ER_POS 31 + /* Chip Attention Register */ + + #define CA_REG_OFFSET 4 /* Byte offset from register base address */ +@@ -1235,7 +1252,7 @@ typedef struct { /* FireFly BIU registe + + /* Host Control Register */ + +-#define HC_REG_OFFSET 12 /* Word offset from register base address */ ++#define HC_REG_OFFSET 12 /* Byte offset from register base address */ + + #define HC_MBINT_ENA 0x00000001 /* Bit 0 */ + #define HC_R0INT_ENA 0x00000002 /* Bit 1 */ +@@ -1248,6 +1265,19 @@ typedef struct { /* FireFly BIU registe + #define HC_LAINT_ENA 0x20000000 /* Bit 29 */ + #define HC_ERINT_ENA 0x80000000 /* Bit 31 */ + ++/* Message Signaled Interrupt eXtension (MSI-X) message identifiers */ ++#define MSIX_DFLT_ID 0 ++#define MSIX_RNG0_ID 0 ++#define MSIX_RNG1_ID 1 ++#define MSIX_RNG2_ID 2 ++#define MSIX_RNG3_ID 3 ++ ++#define MSIX_LINK_ID 4 ++#define MSIX_MBOX_ID 5 ++ ++#define MSIX_SPARE0_ID 6 ++#define MSIX_SPARE1_ID 7 ++ + /* Mailbox Commands */ + #define MBX_SHUTDOWN 0x00 /* terminate testing */ + #define MBX_LOAD_SM 0x01 +@@ -1285,10 +1315,14 @@ typedef struct { /* FireFly BIU registe + #define MBX_KILL_BOARD 0x24 + #define MBX_CONFIG_FARP 0x25 + #define MBX_BEACON 0x2A ++#define MBX_CONFIG_MSI 0x30 + #define MBX_HEARTBEAT 0x31 + #define MBX_WRITE_VPARMS 0x32 + #define MBX_ASYNCEVT_ENABLE 0x33 + ++#define MBX_PORT_CAPABILITIES 0x3B ++#define MBX_PORT_IOV_CONTROL 0x3C ++ + #define MBX_CONFIG_HBQ 0x7C + #define MBX_LOAD_AREA 0x81 + #define MBX_RUN_BIU_DIAG64 0x84 +@@ -1474,24 +1508,18 @@ struct ulp_bde64 { /* SLI-2 */ + uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED + VALUE !! */ + #endif +- +-#define BUFF_USE_RSVD 0x01 /* bdeFlags */ +-#define BUFF_USE_INTRPT 0x02 /* Not Implemented with LP6000 */ +-#define BUFF_USE_CMND 0x04 /* Optional, 1=cmd/rsp 0=data buffer */ +-#define BUFF_USE_RCV 0x08 /* "" "", 1=rcv buffer, 0=xmit +- buffer */ +-#define BUFF_TYPE_32BIT 0x10 /* "" "", 1=32 bit addr 0=64 bit +- addr */ +-#define BUFF_TYPE_SPECIAL 0x20 /* Not Implemented with LP6000 */ +-#define BUFF_TYPE_BDL 0x40 /* Optional, may be set in BDL */ +-#define BUFF_TYPE_INVALID 0x80 /* "" "" */ ++#define BUFF_TYPE_BDE_64 0x00 /* BDE (Host_resident) */ ++#define BUFF_TYPE_BDE_IMMED 0x01 /* Immediate Data BDE */ ++#define BUFF_TYPE_BDE_64P 0x02 /* BDE (Port-resident) */ ++#define BUFF_TYPE_BDE_64I 0x08 /* Input BDE (Host-resident) */ ++#define BUFF_TYPE_BDE_64IP 0x0A /* Input BDE (Port-resident) */ ++#define BUFF_TYPE_BLP_64 0x40 /* BLP (Host-resident) */ ++#define BUFF_TYPE_BLP_64P 0x42 /* BLP (Port-resident) */ + } f; + } tus; + uint32_t addrLow; + uint32_t addrHigh; + }; +-#define BDE64_SIZE_WORD 0 +-#define BPL64_SIZE_WORD 0x40 + + typedef struct ULP_BDL { /* SLI-2 */ + #ifdef __BIG_ENDIAN_BITFIELD +@@ -2201,7 +2229,10 @@ typedef struct { + typedef struct { + uint32_t eventTag; /* Event tag */ + #ifdef __BIG_ENDIAN_BITFIELD +- uint32_t rsvd1:22; ++ uint32_t rsvd1:19; ++ uint32_t fa:1; ++ uint32_t mm:1; /* Menlo Maintenance mode enabled */ ++ uint32_t rx:1; + uint32_t pb:1; + uint32_t il:1; + uint32_t attType:8; +@@ -2209,7 +2240,10 @@ typedef struct { + uint32_t attType:8; + uint32_t il:1; + uint32_t pb:1; +- uint32_t rsvd1:22; ++ uint32_t rx:1; ++ uint32_t mm:1; ++ uint32_t fa:1; ++ uint32_t rsvd1:19; + #endif + + #define AT_RESERVED 0x00 /* Reserved - attType */ +@@ -2230,6 +2264,7 @@ typedef struct { + + #define TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */ + #define TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */ ++#define TOPOLOGY_LNK_MENLO_MAINTENANCE 0x05 /* maint mode zephtr to menlo */ + + union { + struct ulp_bde lilpBde; /* This BDE points to a 128 byte buffer +@@ -2324,6 +2359,36 @@ typedef struct { + #define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */ + #define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */ + ++/* Structure for MB Command UPDATE_CFG (0x1B) */ ++ ++struct update_cfg_var { ++#ifdef __BIG_ENDIAN_BITFIELD ++ uint32_t rsvd2:16; ++ uint32_t type:8; ++ uint32_t rsvd:1; ++ uint32_t ra:1; ++ uint32_t co:1; ++ uint32_t cv:1; ++ uint32_t req:4; ++ uint32_t entry_length:16; ++ uint32_t region_id:16; ++#else /* __LITTLE_ENDIAN_BITFIELD */ ++ uint32_t req:4; ++ uint32_t cv:1; ++ uint32_t co:1; ++ uint32_t ra:1; ++ uint32_t rsvd:1; ++ uint32_t type:8; ++ uint32_t rsvd2:16; ++ uint32_t region_id:16; ++ uint32_t entry_length:16; ++#endif ++ ++ uint32_t resp_info; ++ uint32_t byte_cnt; ++ uint32_t data_offset; ++}; ++ + struct hbq_mask { + #ifdef __BIG_ENDIAN_BITFIELD + uint8_t tmatch; +@@ -2560,6 +2625,40 @@ typedef struct { + + } CONFIG_PORT_VAR; + ++/* Structure for MB Command CONFIG_MSI (0x30) */ ++struct config_msi_var { ++#ifdef __BIG_ENDIAN_BITFIELD ++ uint32_t dfltMsgNum:8; /* Default message number */ ++ uint32_t rsvd1:11; /* Reserved */ ++ uint32_t NID:5; /* Number of secondary attention IDs */ ++ uint32_t rsvd2:5; /* Reserved */ ++ uint32_t dfltPresent:1; /* Default message number present */ ++ uint32_t addFlag:1; /* Add association flag */ ++ uint32_t reportFlag:1; /* Report association flag */ ++#else /* __LITTLE_ENDIAN_BITFIELD */ ++ uint32_t reportFlag:1; /* Report association flag */ ++ uint32_t addFlag:1; /* Add association flag */ ++ uint32_t dfltPresent:1; /* Default message number present */ ++ uint32_t rsvd2:5; /* Reserved */ ++ uint32_t NID:5; /* Number of secondary attention IDs */ ++ uint32_t rsvd1:11; /* Reserved */ ++ uint32_t dfltMsgNum:8; /* Default message number */ ++#endif ++ uint32_t attentionConditions[2]; ++ uint8_t attentionId[16]; ++ uint8_t messageNumberByHA[64]; ++ uint8_t messageNumberByID[16]; ++ uint32_t autoClearHA[2]; ++#ifdef __BIG_ENDIAN_BITFIELD ++ uint32_t rsvd3:16; ++ uint32_t autoClearID:16; ++#else /* __LITTLE_ENDIAN_BITFIELD */ ++ uint32_t autoClearID:16; ++ uint32_t rsvd3:16; ++#endif ++ uint32_t rsvd4; ++}; ++ + /* SLI-2 Port Control Block */ + + /* SLIM POINTER */ +@@ -2678,10 +2777,12 @@ typedef union { + * NEW_FEATURE + */ + struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */ ++ struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/ + CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ + REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ + UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ + ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ ++ struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI) */ + } MAILVARIANTS; + + /* +@@ -2715,11 +2816,19 @@ struct sli3_pgp { + uint32_t hbq_get[16]; + }; + +-typedef union { +- struct sli2_desc s2; +- struct sli3_desc s3; +- struct sli3_pgp s3_pgp; +-} SLI_VAR; ++struct sli3_inb_pgp { ++ uint32_t ha_copy; ++ uint32_t counter; ++ struct lpfc_pgp port[MAX_RINGS]; ++ uint32_t hbq_get[16]; ++}; ++ ++union sli_var { ++ struct sli2_desc s2; ++ struct sli3_desc s3; ++ struct sli3_pgp s3_pgp; ++ struct sli3_inb_pgp s3_inb_pgp; ++}; + + typedef struct { + #ifdef __BIG_ENDIAN_BITFIELD +@@ -2737,7 +2846,7 @@ typedef struct { + #endif + + MAILVARIANTS un; +- SLI_VAR us; ++ union sli_var us; + } MAILBOX_t; + + /* +@@ -3105,6 +3214,27 @@ struct que_xri64cx_ext_fields { + struct lpfc_hbq_entry buff[5]; + }; + ++#define LPFC_EXT_DATA_BDE_COUNT 3 ++struct fcp_irw_ext { ++ uint32_t io_tag64_low; ++ uint32_t io_tag64_high; ++#ifdef __BIG_ENDIAN_BITFIELD ++ uint8_t reserved1; ++ uint8_t reserved2; ++ uint8_t reserved3; ++ uint8_t ebde_count; ++#else /* __LITTLE_ENDIAN */ ++ uint8_t ebde_count; ++ uint8_t reserved3; ++ uint8_t reserved2; ++ uint8_t reserved1; ++#endif ++ uint32_t reserved4; ++ struct ulp_bde64 rbde; /* response bde */ ++ struct ulp_bde64 dbde[LPFC_EXT_DATA_BDE_COUNT]; /* data BDE or BPL */ ++ uint8_t icd[32]; /* immediate command data (32 bytes) */ ++}; ++ + typedef struct _IOCB { /* IOCB structure */ + union { + GENERIC_RSP grsp; /* Generic response */ +@@ -3190,7 +3320,7 @@ typedef struct _IOCB { /* IOCB structure + + /* words 8-31 used for que_xri_cx iocb */ + struct que_xri64cx_ext_fields que_xri64cx_ext_words; +- ++ struct fcp_irw_ext fcp_ext; + uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ + } unsli3; + +@@ -3292,3 +3422,10 @@ lpfc_error_lost_link(IOCB_t *iocbp) + iocbp->un.ulpWord[4] == IOERR_LINK_DOWN || + iocbp->un.ulpWord[4] == IOERR_SLI_DOWN)); + } ++ ++#define MENLO_TRANSPORT_TYPE 0xfe ++#define MENLO_CONTEXT 0 ++#define MENLO_PU 3 ++#define MENLO_TIMEOUT 30 ++#define SETVAR_MLOMNT 0x103107 ++#define SETVAR_MLORST 0x103007 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -36,6 +36,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -52,17 +53,20 @@ static struct scsi_transport_template *l + static struct scsi_transport_template *lpfc_vport_transport_template = NULL; + static DEFINE_IDR(lpfc_hba_index); + +-/************************************************************************/ +-/* */ +-/* lpfc_config_port_prep */ +-/* This routine will do LPFC initialization prior to the */ +-/* CONFIG_PORT mailbox command. This will be initialized */ +-/* as a SLI layer callback routine. */ +-/* This routine returns 0 on success or -ERESTART if it wants */ +-/* the SLI layer to reset the HBA and try again. Any */ +-/* other return value indicates an error. */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_config_port_prep: Perform lpfc initialization prior to config port. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine will do LPFC initialization prior to issuing the CONFIG_PORT ++ * mailbox command. It retrieves the revision information from the HBA and ++ * collects the Vital Product Data (VPD) about the HBA for preparing the ++ * configuration of the HBA. ++ * ++ * Return codes: ++ * 0 - success. ++ * -ERESTART - requests the SLI layer to reset the HBA and try again. ++ * Any other value - indicates an error. ++ **/ + int + lpfc_config_port_prep(struct lpfc_hba *phba) + { +@@ -180,12 +184,9 @@ lpfc_config_port_prep(struct lpfc_hba *p + sizeof (phba->RandomData)); + + /* Get adapter VPD information */ +- pmb->context2 = kmalloc(DMP_RSP_SIZE, GFP_KERNEL); +- if (!pmb->context2) +- goto out_free_mbox; + lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL); + if (!lpfc_vpd_data) +- goto out_free_context2; ++ goto out_free_mbox; + + do { + lpfc_dump_mem(phba, pmb, offset); +@@ -200,21 +201,29 @@ lpfc_config_port_prep(struct lpfc_hba *p + } + if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) + mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; +- lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset, ++ lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, ++ lpfc_vpd_data + offset, + mb->un.varDmp.word_cnt); + offset += mb->un.varDmp.word_cnt; + } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); + lpfc_parse_vpd(phba, lpfc_vpd_data, offset); + + kfree(lpfc_vpd_data); +-out_free_context2: +- kfree(pmb->context2); + out_free_mbox: + mempool_free(pmb, phba->mbox_mem_pool); + return 0; + } + +-/* Completion handler for config async event mailbox command. */ ++/** ++ * lpfc_config_async_cmpl: Completion handler for config async event mbox cmd. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmboxq: pointer to the driver internal queue element for mailbox command. ++ * ++ * This is the completion handler for driver's configuring asynchronous event ++ * mailbox command to the device. If the mailbox command returns successfully, ++ * it will set internal async event support flag to 1; otherwise, it will ++ * set internal async event support flag to 0. ++ **/ + static void + lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) + { +@@ -226,16 +235,19 @@ lpfc_config_async_cmpl(struct lpfc_hba * + return; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_config_port_post */ +-/* This routine will do LPFC initialization after the */ +-/* CONFIG_PORT mailbox command. This will be initialized */ +-/* as a SLI layer callback routine. */ +-/* This routine returns 0 on success. Any other return value */ +-/* indicates an error. */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_config_port_post: Perform lpfc initialization after config port. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine will do LPFC initialization after the CONFIG_PORT mailbox ++ * command call. It performs all internal resource and state setups on the ++ * port: post IOCB buffers, enable appropriate host interrupt attentions, ++ * ELS ring timers, etc. ++ * ++ * Return codes ++ * 0 - success. ++ * Any other value - error. ++ **/ + int + lpfc_config_port_post(struct lpfc_hba *phba) + { +@@ -378,6 +390,29 @@ lpfc_config_port_post(struct lpfc_hba *p + if (phba->sli_rev != 3) + lpfc_post_rcv_buf(phba); + ++ /* ++ * Configure HBA MSI-X attention conditions to messages if MSI-X mode ++ */ ++ if (phba->intr_type == MSIX) { ++ rc = lpfc_config_msi(phba, pmb); ++ if (rc) { ++ mempool_free(pmb, phba->mbox_mem_pool); ++ return -EIO; ++ } ++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); ++ if (rc != MBX_SUCCESS) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, ++ "0352 Config MSI mailbox command " ++ "failed, mbxCmd x%x, mbxStatus x%x\n", ++ pmb->mb.mbxCommand, pmb->mb.mbxStatus); ++ mempool_free(pmb, phba->mbox_mem_pool); ++ return -EIO; ++ } ++ } ++ ++ /* Initialize ERATT handling flag */ ++ phba->hba_flag &= ~HBA_ERATT_HANDLED; ++ + /* Enable appropriate host interrupts */ + spin_lock_irq(&phba->hbalock); + status = readl(phba->HCregaddr); +@@ -393,26 +428,26 @@ lpfc_config_port_post(struct lpfc_hba *p + + if ((phba->cfg_poll & ENABLE_FCP_RING_POLLING) && + (phba->cfg_poll & DISABLE_FCP_RING_INT)) +- status &= ~(HC_R0INT_ENA << LPFC_FCP_RING); ++ status &= ~(HC_R0INT_ENA); + + writel(status, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + spin_unlock_irq(&phba->hbalock); + +- /* +- * Setup the ring 0 (els) timeout handler +- */ +- timeout = phba->fc_ratov << 1; ++ /* Set up ring-0 (ELS) timer */ ++ timeout = phba->fc_ratov * 2; + mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); ++ /* Set up heart beat (HB) timer */ + mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + phba->hb_outstanding = 0; + phba->last_completion_time = jiffies; ++ /* Set up error attention (ERATT) polling timer */ ++ mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + + lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; +- pmb->vport = vport; +- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + lpfc_set_loopback_flag(phba); ++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0454 Adapter failed to init, mbxCmd x%x " +@@ -447,19 +482,20 @@ lpfc_config_port_post(struct lpfc_hba *p + rc); + mempool_free(pmb, phba->mbox_mem_pool); + } +- return (0); ++ return 0; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_hba_down_prep */ +-/* This routine will do LPFC uninitialization before the */ +-/* HBA is reset when bringing down the SLI Layer. This will be */ +-/* initialized as a SLI layer callback routine. */ +-/* This routine returns 0 on success. Any other return value */ +-/* indicates an error. */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_hba_down_prep: Perform lpfc uninitialization prior to HBA reset. ++ * @phba: pointer to lpfc HBA data structure. ++ * ++ * This routine will do LPFC uninitialization before the HBA is reset when ++ * bringing down the SLI Layer. ++ * ++ * Return codes ++ * 0 - success. ++ * Any other value - error. ++ **/ + int + lpfc_hba_down_prep(struct lpfc_hba *phba) + { +@@ -481,15 +517,17 @@ lpfc_hba_down_prep(struct lpfc_hba *phba + return 0; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_hba_down_post */ +-/* This routine will do uninitialization after the HBA is reset */ +-/* when bringing down the SLI Layer. */ +-/* This routine returns 0 on success. Any other return value */ +-/* indicates an error. */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_hba_down_post: Perform lpfc uninitialization after HBA reset. ++ * @phba: pointer to lpfc HBA data structure. ++ * ++ * This routine will do uninitialization after the HBA is reset when bring ++ * down the SLI Layer. ++ * ++ * Return codes ++ * 0 - sucess. ++ * Any other value - error. ++ **/ + int + lpfc_hba_down_post(struct lpfc_hba *phba) + { +@@ -548,7 +586,18 @@ lpfc_hba_down_post(struct lpfc_hba *phba + return 0; + } + +-/* HBA heart beat timeout handler */ ++/** ++ * lpfc_hb_timeout: The HBA-timer timeout handler. ++ * @ptr: unsigned long holds the pointer to lpfc hba data structure. ++ * ++ * This is the HBA-timer timeout handler registered to the lpfc driver. When ++ * this timer fires, a HBA timeout event shall be posted to the lpfc driver ++ * work-port-events bitmap and the worker thread is notified. This timeout ++ * event will be used by the worker thread to invoke the actual timeout ++ * handler routine, lpfc_hb_timeout_handler. Any periodical operations will ++ * be performed in the timeout handler and the HBA timeout event bit shall ++ * be cleared by the worker thread after it has taken the event bitmap out. ++ **/ + static void + lpfc_hb_timeout(unsigned long ptr) + { +@@ -557,17 +606,36 @@ lpfc_hb_timeout(unsigned long ptr) + unsigned long iflag; + + phba = (struct lpfc_hba *)ptr; ++ ++ /* Check for heart beat timeout conditions */ + spin_lock_irqsave(&phba->pport->work_port_lock, iflag); + tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO; + if (!tmo_posted) + phba->pport->work_port_events |= WORKER_HB_TMO; + spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); + ++ /* Tell the worker thread there is work to do */ + if (!tmo_posted) + lpfc_worker_wake_up(phba); + return; + } + ++/** ++ * lpfc_hb_mbox_cmpl: The lpfc heart-beat mailbox command callback function. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmboxq: pointer to the driver internal queue element for mailbox command. ++ * ++ * This is the callback function to the lpfc heart-beat mailbox command. ++ * If configured, the lpfc driver issues the heart-beat mailbox command to ++ * the HBA every LPFC_HB_MBOX_INTERVAL (current 5) seconds. At the time the ++ * heart-beat mailbox command is issued, the driver shall set up heart-beat ++ * timeout timer to LPFC_HB_MBOX_TIMEOUT (current 30) seconds and marks ++ * heart-beat outstanding state. Once the mailbox command comes back and ++ * no error conditions detected, the heart-beat mailbox command timer is ++ * reset to LPFC_HB_MBOX_INTERVAL seconds and the heart-beat outstanding ++ * state is cleared for the next heart-beat. If the timer expired with the ++ * heart-beat outstanding state set, the driver will put the HBA offline. ++ **/ + static void + lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) + { +@@ -577,6 +645,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba + phba->hb_outstanding = 0; + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); + ++ /* Check and reset heart-beat timer is necessary */ + mempool_free(pmboxq, phba->mbox_mem_pool); + if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && + !(phba->link_state == LPFC_HBA_ERROR) && +@@ -586,6 +655,22 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba + return; + } + ++/** ++ * lpfc_hb_timeout_handler: The HBA-timer timeout handler. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This is the actual HBA-timer timeout handler to be invoked by the worker ++ * thread whenever the HBA timer fired and HBA-timeout event posted. This ++ * handler performs any periodic operations needed for the device. If such ++ * periodic event has already been attended to either in the interrupt handler ++ * or by processing slow-ring or fast-ring events within the HBA-timer ++ * timeout window (LPFC_HB_MBOX_INTERVAL), this handler just simply resets ++ * the timer for the next timeout period. If lpfc heart-beat mailbox command ++ * is configured and there is no heart-beat mailbox command outstanding, a ++ * heart-beat mailbox is issued and timer set properly. Otherwise, if there ++ * has been a heart-beat mailbox command outstanding, the HBA shall be put ++ * to offline. ++ **/ + void + lpfc_hb_timeout_handler(struct lpfc_hba *phba) + { +@@ -684,6 +769,13 @@ lpfc_hb_timeout_handler(struct lpfc_hba + } + } + ++/** ++ * lpfc_offline_eratt: Bring lpfc offline on hardware error attention. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is called to bring the HBA offline when HBA hardware error ++ * other than Port Error 6 has been detected. ++ **/ + static void + lpfc_offline_eratt(struct lpfc_hba *phba) + { +@@ -704,14 +796,16 @@ lpfc_offline_eratt(struct lpfc_hba *phba + return; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_handle_eratt */ +-/* This routine will handle processing a Host Attention */ +-/* Error Status event. This will be initialized */ +-/* as a SLI layer callback routine. */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_handle_eratt: The HBA hardware error handler. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to handle the following HBA hardware error ++ * conditions: ++ * 1 - HBA error attention interrupt ++ * 2 - DMA ring index out of range ++ * 3 - Mailbox command came back as unknown ++ **/ + void + lpfc_handle_eratt(struct lpfc_hba *phba) + { +@@ -722,6 +816,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + unsigned long temperature; + struct temp_event temp_event_data; + struct Scsi_Host *shost; ++ struct lpfc_board_event_header board_event; + + /* If the pci channel is offline, ignore possible errors, + * since we cannot communicate with the pci card anyway. */ +@@ -731,6 +826,16 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + if (!phba->cfg_enable_hba_reset) + return; + ++ /* Send an internal error event to mgmt application */ ++ board_event.event_type = FC_REG_BOARD_EVENT; ++ board_event.subcategory = LPFC_EVENT_PORTINTERR; ++ shost = lpfc_shost_from_vport(phba->pport); ++ fc_host_post_vendor_event(shost, fc_get_event_number(), ++ sizeof(board_event), ++ (char *) &board_event, ++ SCSI_NL_VID_TYPE_PCI ++ | PCI_VENDOR_ID_EMULEX); ++ + if (phba->work_hs & HS_FFER6) { + /* Re-establishing Link */ + lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, +@@ -771,7 +876,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + temp_event_data.data = (uint32_t)temperature; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0459 Adapter maximum temperature exceeded " ++ "0406 Adapter maximum temperature exceeded " + "(%ld), taking this port offline " + "Data: x%x x%x x%x\n", + temperature, phba->work_hs, +@@ -791,8 +896,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + + } else { + /* The if clause above forces this code path when the status +- * failure is a value other than FFER6. Do not call the offline +- * twice. This is the adapter hardware error path. ++ * failure is a value other than FFER6. Do not call the offline ++ * twice. This is the adapter hardware error path. + */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0457 Adapter Hardware Error " +@@ -808,16 +913,16 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + + lpfc_offline_eratt(phba); + } ++ return; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_handle_latt */ +-/* This routine will handle processing a Host Attention */ +-/* Link Status event. This will be initialized */ +-/* as a SLI layer callback routine. */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_handle_latt: The HBA link event handler. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked from the worker thread to handle a HBA host ++ * attention link event. ++ **/ + void + lpfc_handle_latt(struct lpfc_hba *phba) + { +@@ -898,12 +1003,20 @@ lpfc_handle_latt_err_exit: + return; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_parse_vpd */ +-/* This routine will parse the VPD data */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_parse_vpd: Parse VPD (Vital Product Data). ++ * @phba: pointer to lpfc hba data structure. ++ * @vpd: pointer to the vital product data. ++ * @len: length of the vital product data in bytes. ++ * ++ * This routine parses the Vital Product Data (VPD). The VPD is treated as ++ * an array of characters. In this routine, the ModelName, ProgramType, and ++ * ModelDesc, etc. fields of the phba data structure will be populated. ++ * ++ * Return codes ++ * 0 - pointer to the VPD passed in is NULL ++ * 1 - success ++ **/ + static int + lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) + { +@@ -1040,12 +1153,25 @@ lpfc_parse_vpd(struct lpfc_hba *phba, ui + return(1); + } + ++/** ++ * lpfc_get_hba_model_desc: Retrieve HBA device model name and description. ++ * @phba: pointer to lpfc hba data structure. ++ * @mdp: pointer to the data structure to hold the derived model name. ++ * @descp: pointer to the data structure to hold the derived description. ++ * ++ * This routine retrieves HBA's description based on its registered PCI device ++ * ID. The @descp passed into this function points to an array of 256 chars. It ++ * shall be returned with the model name, maximum speed, and the host bus type. ++ * The @mdp passed into this function points to an array of 80 chars. When the ++ * function returns, the @mdp will be filled with the model name. ++ **/ + static void + lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) + { + lpfc_vpd_t *vp; + uint16_t dev_id = phba->pcidev->device; + int max_speed; ++ int GE = 0; + struct { + char * name; + int max_speed; +@@ -1177,6 +1303,19 @@ lpfc_get_hba_model_desc(struct lpfc_hba + case PCI_DEVICE_ID_SAT_S: + m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"}; + break; ++ case PCI_DEVICE_ID_HORNET: ++ m = (typeof(m)){"LP21000", max_speed, "PCIe"}; ++ GE = 1; ++ break; ++ case PCI_DEVICE_ID_PROTEUS_VF: ++ m = (typeof(m)) {"LPev12000", max_speed, "PCIe IOV"}; ++ break; ++ case PCI_DEVICE_ID_PROTEUS_PF: ++ m = (typeof(m)) {"LPev12000", max_speed, "PCIe IOV"}; ++ break; ++ case PCI_DEVICE_ID_PROTEUS_S: ++ m = (typeof(m)) {"LPemv12002-S", max_speed, "PCIe IOV"}; ++ break; + default: + m = (typeof(m)){ NULL }; + break; +@@ -1186,18 +1325,25 @@ lpfc_get_hba_model_desc(struct lpfc_hba + snprintf(mdp, 79,"%s", m.name); + if (descp && descp[0] == '\0') + snprintf(descp, 255, +- "Emulex %s %dGb %s Fibre Channel Adapter", +- m.name, m.max_speed, m.bus); ++ "Emulex %s %d%s %s %s", ++ m.name, m.max_speed, ++ (GE) ? "GE" : "Gb", ++ m.bus, ++ (GE) ? "FCoE Adapter" : "Fibre Channel Adapter"); + } + +-/**************************************************/ +-/* lpfc_post_buffer */ +-/* */ +-/* This routine will post count buffers to the */ +-/* ring with the QUE_RING_BUF_CN command. This */ +-/* allows 3 buffers / command to be posted. */ +-/* Returns the number of buffers NOT posted. */ +-/**************************************************/ ++/** ++ * lpfc_post_buffer: Post IOCB(s) with DMA buffer descriptor(s) to a IOCB ring. ++ * @phba: pointer to lpfc hba data structure. ++ * @pring: pointer to a IOCB ring. ++ * @cnt: the number of IOCBs to be posted to the IOCB ring. ++ * ++ * This routine posts a given number of IOCBs with the associated DMA buffer ++ * descriptors specified by the cnt argument to the given IOCB ring. ++ * ++ * Return codes ++ * The number of IOCBs NOT able to be posted to the IOCB ring. ++ **/ + int + lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) + { +@@ -1287,12 +1433,17 @@ lpfc_post_buffer(struct lpfc_hba *phba, + return 0; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_post_rcv_buf */ +-/* This routine post initial rcv buffers to the configured rings */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_post_rcv_buf: Post the initial receive IOCB buffers to ELS ring. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine posts initial receive IOCB buffers to the ELS ring. The ++ * current number of initial IOCB buffers specified by LPFC_BUF_RING0 is ++ * set to 64 IOCBs. ++ * ++ * Return codes ++ * 0 - success (currently always success) ++ **/ + static int + lpfc_post_rcv_buf(struct lpfc_hba *phba) + { +@@ -1307,11 +1458,13 @@ lpfc_post_rcv_buf(struct lpfc_hba *phba) + + #define S(N,V) (((V)<<(N))|((V)>>(32-(N)))) + +-/************************************************************************/ +-/* */ +-/* lpfc_sha_init */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_sha_init: Set up initial array of hash table entries. ++ * @HashResultPointer: pointer to an array as hash table. ++ * ++ * This routine sets up the initial values to the array of hash table entries ++ * for the LC HBAs. ++ **/ + static void + lpfc_sha_init(uint32_t * HashResultPointer) + { +@@ -1322,11 +1475,16 @@ lpfc_sha_init(uint32_t * HashResultPoint + HashResultPointer[4] = 0xC3D2E1F0; + } + +-/************************************************************************/ +-/* */ +-/* lpfc_sha_iterate */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_sha_iterate: Iterate initial hash table with the working hash table. ++ * @HashResultPointer: pointer to an initial/result hash table. ++ * @HashWorkingPointer: pointer to an working hash table. ++ * ++ * This routine iterates an initial hash table pointed by @HashResultPointer ++ * with the values from the working hash table pointeed by @HashWorkingPointer. ++ * The results are putting back to the initial hash table, returned through ++ * the @HashResultPointer as the result hash table. ++ **/ + static void + lpfc_sha_iterate(uint32_t * HashResultPointer, uint32_t * HashWorkingPointer) + { +@@ -1374,22 +1532,29 @@ lpfc_sha_iterate(uint32_t * HashResultPo + + } + +-/************************************************************************/ +-/* */ +-/* lpfc_challenge_key */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_challenge_key: Create challenge key based on WWPN of the HBA. ++ * @RandomChallenge: pointer to the entry of host challenge random number array. ++ * @HashWorking: pointer to the entry of the working hash array. ++ * ++ * This routine calculates the working hash array referred by @HashWorking ++ * from the challenge random numbers associated with the host, referred by ++ * @RandomChallenge. The result is put into the entry of the working hash ++ * array and returned by reference through @HashWorking. ++ **/ + static void + lpfc_challenge_key(uint32_t * RandomChallenge, uint32_t * HashWorking) + { + *HashWorking = (*RandomChallenge ^ *HashWorking); + } + +-/************************************************************************/ +-/* */ +-/* lpfc_hba_init */ +-/* */ +-/************************************************************************/ ++/** ++ * lpfc_hba_init: Perform special handling for LC HBA initialization. ++ * @phba: pointer to lpfc hba data structure. ++ * @hbainit: pointer to an array of unsigned 32-bit integers. ++ * ++ * This routine performs the special handling for LC HBA initialization. ++ **/ + void + lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) + { +@@ -1412,6 +1577,15 @@ lpfc_hba_init(struct lpfc_hba *phba, uin + kfree(HashWorking); + } + ++/** ++ * lpfc_cleanup: Performs vport cleanups before deleting a vport. ++ * @vport: pointer to a virtual N_Port data structure. ++ * ++ * This routine performs the necessary cleanups before deleting the @vport. ++ * It invokes the discovery state machine to perform necessary state ++ * transitions and to release the ndlps associated with the @vport. Note, ++ * the physical port is treated as @vport 0. ++ **/ + void + lpfc_cleanup(struct lpfc_vport *vport) + { +@@ -1459,14 +1633,6 @@ lpfc_cleanup(struct lpfc_vport *vport) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + +- /* nlp_type zero is not defined, nlp_flag zero also not defined, +- * nlp_state is unused, this happens when +- * an initiator has logged +- * into us so cleanup this ndlp. +- */ +- if ((ndlp->nlp_type == 0) && (ndlp->nlp_flag == 0) && +- (ndlp->nlp_state == 0)) +- lpfc_nlp_put(ndlp); + } + + /* At this point, ALL ndlp's should be gone +@@ -1482,7 +1648,7 @@ lpfc_cleanup(struct lpfc_vport *vport) + &vport->fc_nodes, nlp_listp) { + lpfc_printf_vlog(ndlp->vport, KERN_ERR, + LOG_NODE, +- "0282: did:x%x ndlp:x%p " ++ "0282 did:x%x ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + ndlp->nlp_DID, (void *)ndlp, + ndlp->nlp_usg_map, +@@ -1498,6 +1664,14 @@ lpfc_cleanup(struct lpfc_vport *vport) + return; + } + ++/** ++ * lpfc_stop_vport_timers: Stop all the timers associated with a vport. ++ * @vport: pointer to a virtual N_Port data structure. ++ * ++ * This routine stops all the timers associated with a @vport. This function ++ * is invoked before disabling or deleting a @vport. Note that the physical ++ * port is treated as @vport 0. ++ **/ + void + lpfc_stop_vport_timers(struct lpfc_vport *vport) + { +@@ -1507,6 +1681,13 @@ lpfc_stop_vport_timers(struct lpfc_vport + return; + } + ++/** ++ * lpfc_stop_phba_timers: Stop all the timers associated with an HBA. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine stops all the timers associated with a HBA. This function is ++ * invoked before either putting a HBA offline or unloading the driver. ++ **/ + static void + lpfc_stop_phba_timers(struct lpfc_hba *phba) + { +@@ -1516,9 +1697,20 @@ lpfc_stop_phba_timers(struct lpfc_hba *p + del_timer_sync(&phba->fabric_block_timer); + phba->hb_outstanding = 0; + del_timer_sync(&phba->hb_tmofunc); ++ del_timer_sync(&phba->eratt_poll); + return; + } + ++/** ++ * lpfc_block_mgmt_io: Mark a HBA's management interface as blocked. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine marks a HBA's management interface as blocked. Once the HBA's ++ * management interface is marked as blocked, all the user space access to ++ * the HBA, whether they are from sysfs interface or libdfc interface will ++ * all be blocked. The HBA is set to block the management interface when the ++ * driver prepares the HBA interface for online or offline. ++ **/ + static void + lpfc_block_mgmt_io(struct lpfc_hba * phba) + { +@@ -1529,6 +1721,18 @@ lpfc_block_mgmt_io(struct lpfc_hba * phb + spin_unlock_irqrestore(&phba->hbalock, iflag); + } + ++/** ++ * lpfc_online: Initialize and bring a HBA online. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine initializes the HBA and brings a HBA online. During this ++ * process, the management interface is blocked to prevent user space access ++ * to the HBA interfering with the driver initialization. ++ * ++ * Return codes ++ * 0 - successful ++ * 1 - failed ++ **/ + int + lpfc_online(struct lpfc_hba *phba) + { +@@ -1574,6 +1778,17 @@ lpfc_online(struct lpfc_hba *phba) + return 0; + } + ++/** ++ * lpfc_unblock_mgmt_io: Mark a HBA's management interface to be not blocked. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine marks a HBA's management interface as not blocked. Once the ++ * HBA's management interface is marked as not blocked, all the user space ++ * access to the HBA, whether they are from sysfs interface or libdfc ++ * interface will be allowed. The HBA is set to block the management interface ++ * when the driver prepares the HBA interface for online or offline and then ++ * set to unblock the management interface afterwards. ++ **/ + void + lpfc_unblock_mgmt_io(struct lpfc_hba * phba) + { +@@ -1584,6 +1799,14 @@ lpfc_unblock_mgmt_io(struct lpfc_hba * p + spin_unlock_irqrestore(&phba->hbalock, iflag); + } + ++/** ++ * lpfc_offline_prep: Prepare a HBA to be brought offline. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to prepare a HBA to be brought offline. It performs ++ * unregistration login to all the nodes on all vports and flushes the mailbox ++ * queue to make it ready to be brought offline. ++ **/ + void + lpfc_offline_prep(struct lpfc_hba * phba) + { +@@ -1633,6 +1856,14 @@ lpfc_offline_prep(struct lpfc_hba * phba + lpfc_sli_flush_mbox_queue(phba); + } + ++/** ++ * lpfc_offline: Bring a HBA offline. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine actually brings a HBA offline. It stops all the timers ++ * associated with the HBA, brings down the SLI layer, and eventually ++ * marks the HBA as in offline state for the upper layer protocol. ++ **/ + void + lpfc_offline(struct lpfc_hba *phba) + { +@@ -1670,12 +1901,17 @@ lpfc_offline(struct lpfc_hba *phba) + lpfc_destroy_vport_work_array(phba, vports); + } + +-/****************************************************************************** +-* Function name: lpfc_scsi_free +-* +-* Description: Called from lpfc_pci_remove_one free internal driver resources +-* +-******************************************************************************/ ++/** ++ * lpfc_scsi_free: Free all the SCSI buffers and IOCBs from driver lists. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is to free all the SCSI buffers and IOCBs from the driver ++ * list back to kernel. It is called from lpfc_pci_remove_one to free ++ * the internal resources before the device is removed from the system. ++ * ++ * Return codes ++ * 0 - successful (for now, it always returns 0) ++ **/ + static int + lpfc_scsi_free(struct lpfc_hba *phba) + { +@@ -1704,6 +1940,22 @@ lpfc_scsi_free(struct lpfc_hba *phba) + return 0; + } + ++/** ++ * lpfc_create_port: Create an FC port. ++ * @phba: pointer to lpfc hba data structure. ++ * @instance: a unique integer ID to this FC port. ++ * @dev: pointer to the device data structure. ++ * ++ * This routine creates a FC port for the upper layer protocol. The FC port ++ * can be created on top of either a physical port or a virtual port provided ++ * by the HBA. This routine also allocates a SCSI host data structure (shost) ++ * and associates the FC port created before adding the shost into the SCSI ++ * layer. ++ * ++ * Return codes ++ * @vport - pointer to the virtual N_Port data structure. ++ * NULL - port create failed. ++ **/ + struct lpfc_vport * + lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) + { +@@ -1777,6 +2029,13 @@ out: + return NULL; + } + ++/** ++ * destroy_port: Destroy an FC port. ++ * @vport: pointer to an lpfc virtual N_Port data structure. ++ * ++ * This routine destroys a FC port from the upper layer protocol. All the ++ * resources associated with the port are released. ++ **/ + void + destroy_port(struct lpfc_vport *vport) + { +@@ -1797,6 +2056,16 @@ destroy_port(struct lpfc_vport *vport) + return; + } + ++/** ++ * lpfc_get_instance: Get a unique integer ID. ++ * ++ * This routine allocates a unique integer ID from lpfc_hba_index pool. It ++ * uses the kernel idr facility to perform the task. ++ * ++ * Return codes: ++ * instance - a unique integer ID allocated as the new instance. ++ * -1 - lpfc get instance failed. ++ **/ + int + lpfc_get_instance(void) + { +@@ -1810,11 +2079,21 @@ lpfc_get_instance(void) + return instance; + } + +-/* +- * Note: there is no scan_start function as adapter initialization +- * will have asynchronously kicked off the link initialization. +- */ +- ++/** ++ * lpfc_scan_finished: method for SCSI layer to detect whether scan is done. ++ * @shost: pointer to SCSI host data structure. ++ * @time: elapsed time of the scan in jiffies. ++ * ++ * This routine is called by the SCSI layer with a SCSI host to determine ++ * whether the scan host is finished. ++ * ++ * Note: there is no scan_start function as adapter initialization will have ++ * asynchronously kicked off the link initialization. ++ * ++ * Return codes ++ * 0 - SCSI host scan is not over yet. ++ * 1 - SCSI host scan is over. ++ **/ + int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) + { + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; +@@ -1858,6 +2137,13 @@ finished: + return stat; + } + ++/** ++ * lpfc_host_attrib_init: Initialize SCSI host attributes on a FC port. ++ * @shost: pointer to SCSI host data structure. ++ * ++ * This routine initializes a given SCSI host attributes on a FC port. The ++ * SCSI host can be either on top of a physical port or a virtual port. ++ **/ + void lpfc_host_attrib_init(struct Scsi_Host *shost) + { + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; +@@ -1906,42 +2192,157 @@ void lpfc_host_attrib_init(struct Scsi_H + spin_unlock_irq(shost->host_lock); + } + ++/** ++ * lpfc_enable_msix: Enable MSI-X interrupt mode. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to enable the MSI-X interrupt vectors. The kernel ++ * function pci_enable_msix() is called to enable the MSI-X vectors. Note that ++ * pci_enable_msix(), once invoked, enables either all or nothing, depending ++ * on the current availability of PCI vector resources. The device driver is ++ * responsible for calling the individual request_irq() to register each MSI-X ++ * vector with a interrupt handler, which is done in this function. Note that ++ * later when device is unloading, the driver should always call free_irq() ++ * on all MSI-X vectors it has done request_irq() on before calling ++ * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device ++ * will be left with MSI-X enabled and leaks its vectors. ++ * ++ * Return codes ++ * 0 - sucessful ++ * other values - error ++ **/ + static int + lpfc_enable_msix(struct lpfc_hba *phba) + { +- int error; ++ int rc, i; ++ LPFC_MBOXQ_t *pmb; + +- phba->msix_entries[0].entry = 0; +- phba->msix_entries[0].vector = 0; ++ /* Set up MSI-X multi-message vectors */ ++ for (i = 0; i < LPFC_MSIX_VECTORS; i++) ++ phba->msix_entries[i].entry = i; + +- error = pci_enable_msix(phba->pcidev, phba->msix_entries, ++ /* Configure MSI-X capability structure */ ++ rc = pci_enable_msix(phba->pcidev, phba->msix_entries, + ARRAY_SIZE(phba->msix_entries)); +- if (error) { ++ if (rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0420 Enable MSI-X failed (%d), continuing " +- "with MSI\n", error); +- pci_disable_msix(phba->pcidev); +- return error; ++ "with MSI\n", rc); ++ goto msi_fail_out; ++ } else ++ for (i = 0; i < LPFC_MSIX_VECTORS; i++) ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0477 MSI-X entry[%d]: vector=x%x " ++ "message=%d\n", i, ++ phba->msix_entries[i].vector, ++ phba->msix_entries[i].entry); ++ /* ++ * Assign MSI-X vectors to interrupt handlers ++ */ ++ ++ /* vector-0 is associated to slow-path handler */ ++ rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler, ++ IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba); ++ if (rc) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0421 MSI-X slow-path request_irq failed " ++ "(%d), continuing with MSI\n", rc); ++ goto msi_fail_out; + } + +- error = request_irq(phba->msix_entries[0].vector, lpfc_intr_handler, 0, +- LPFC_DRIVER_NAME, phba); +- if (error) { ++ /* vector-1 is associated to fast-path handler */ ++ rc = request_irq(phba->msix_entries[1].vector, &lpfc_fp_intr_handler, ++ IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba); ++ ++ if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0421 MSI-X request_irq failed (%d), " +- "continuing with MSI\n", error); +- pci_disable_msix(phba->pcidev); ++ "0429 MSI-X fast-path request_irq failed " ++ "(%d), continuing with MSI\n", rc); ++ goto irq_fail_out; + } +- return error; ++ ++ /* ++ * Configure HBA MSI-X attention conditions to messages ++ */ ++ pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); ++ ++ if (!pmb) { ++ rc = -ENOMEM; ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0474 Unable to allocate memory for issuing " ++ "MBOX_CONFIG_MSI command\n"); ++ goto mem_fail_out; ++ } ++ rc = lpfc_config_msi(phba, pmb); ++ if (rc) ++ goto mbx_fail_out; ++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); ++ if (rc != MBX_SUCCESS) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, ++ "0351 Config MSI mailbox command failed, " ++ "mbxCmd x%x, mbxStatus x%x\n", ++ pmb->mb.mbxCommand, pmb->mb.mbxStatus); ++ goto mbx_fail_out; ++ } ++ ++ /* Free memory allocated for mailbox command */ ++ mempool_free(pmb, phba->mbox_mem_pool); ++ return rc; ++ ++mbx_fail_out: ++ /* Free memory allocated for mailbox command */ ++ mempool_free(pmb, phba->mbox_mem_pool); ++ ++mem_fail_out: ++ /* free the irq already requested */ ++ free_irq(phba->msix_entries[1].vector, phba); ++ ++irq_fail_out: ++ /* free the irq already requested */ ++ free_irq(phba->msix_entries[0].vector, phba); ++ ++msi_fail_out: ++ /* Unconfigure MSI-X capability structure */ ++ pci_disable_msix(phba->pcidev); ++ return rc; + } + ++/** ++ * lpfc_disable_msix: Disable MSI-X interrupt mode. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to release the MSI-X vectors and then disable the ++ * MSI-X interrupt mode. ++ **/ + static void + lpfc_disable_msix(struct lpfc_hba *phba) + { +- free_irq(phba->msix_entries[0].vector, phba); ++ int i; ++ ++ /* Free up MSI-X multi-message vectors */ ++ for (i = 0; i < LPFC_MSIX_VECTORS; i++) ++ free_irq(phba->msix_entries[i].vector, phba); ++ /* Disable MSI-X */ + pci_disable_msix(phba->pcidev); + } + ++/** ++ * lpfc_pci_probe_one: lpfc PCI probe func to register device to PCI subsystem. ++ * @pdev: pointer to PCI device ++ * @pid: pointer to PCI device identifier ++ * ++ * This routine is to be registered to the kernel's PCI subsystem. When an ++ * Emulex HBA is presented in PCI bus, the kernel PCI subsystem looks at ++ * PCI device-specific information of the device and driver to see if the ++ * driver state that it can support this kind of device. If the match is ++ * successful, the driver core invokes this routine. If this routine ++ * determines it can claim the HBA, it does all the initialization that it ++ * needs to do to handle the HBA properly. ++ * ++ * Return code ++ * 0 - driver can claim the device ++ * negative value - driver can not claim the device ++ **/ + static int __devinit + lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + { +@@ -1956,6 +2357,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + int i, hbq_count; + uint16_t iotag; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); ++ struct lpfc_adapter_event_header adapter_event; + + if (pci_enable_device_mem(pdev)) + goto out; +@@ -1966,6 +2368,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + if (!phba) + goto out_release_regions; + ++ atomic_set(&phba->fast_event_count, 0); + spin_lock_init(&phba->hbalock); + + /* Initialize ndlp management spinlock */ +@@ -1978,6 +2381,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + goto out_free_phba; + + INIT_LIST_HEAD(&phba->port_list); ++ init_waitqueue_head(&phba->wait_4_mlo_m_q); + /* + * Get all the module params for configuring this host and then + * establish the host. +@@ -2000,6 +2404,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + init_timer(&phba->fabric_block_timer); + phba->fabric_block_timer.function = lpfc_fabric_block_timeout; + phba->fabric_block_timer.data = (unsigned long) phba; ++ init_timer(&phba->eratt_poll); ++ phba->eratt_poll.function = lpfc_poll_eratt; ++ phba->eratt_poll.data = (unsigned long) phba; + + pci_set_master(pdev); + pci_try_set_mwi(pdev); +@@ -2019,7 +2426,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + bar2map_len = pci_resource_len(phba->pcidev, 2); + + /* Map HBA SLIM to a kernel virtual address. */ +- phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); ++ phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); + if (!phba->slim_memmap_p) { + error = -ENODEV; + dev_printk(KERN_ERR, &pdev->dev, +@@ -2037,12 +2444,18 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + } + + /* Allocate memory for SLI-2 structures */ +- phba->slim2p = dma_alloc_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE, +- &phba->slim2p_mapping, GFP_KERNEL); +- if (!phba->slim2p) ++ phba->slim2p.virt = dma_alloc_coherent(&phba->pcidev->dev, ++ SLI2_SLIM_SIZE, ++ &phba->slim2p.phys, ++ GFP_KERNEL); ++ if (!phba->slim2p.virt) + goto out_iounmap; + +- memset(phba->slim2p, 0, SLI2_SLIM_SIZE); ++ memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); ++ phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); ++ phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); ++ phba->IOCBs = (phba->slim2p.virt + ++ offsetof(struct lpfc_sli2_slim, IOCBs)); + + phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev, + lpfc_sli_hbq_size(), +@@ -2111,7 +2524,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + phba->fc_arbtov = FF_DEF_ARBTOV; + + INIT_LIST_HEAD(&phba->work_list); +- phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT); ++ phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT); + phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); + + /* Initialize the wait queue head for the kernel thread */ +@@ -2146,21 +2559,42 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + pci_set_drvdata(pdev, shost); + phba->intr_type = NONE; + ++ phba->MBslimaddr = phba->slim_memmap_p; ++ phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; ++ phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; ++ phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; ++ phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; ++ ++ /* Configure and enable interrupt */ + if (phba->cfg_use_msi == 2) { +- error = lpfc_enable_msix(phba); +- if (!error) +- phba->intr_type = MSIX; ++ /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ ++ error = lpfc_sli_config_port(phba, 3); ++ if (error) ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0427 Firmware not capable of SLI 3 mode.\n"); ++ else { ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0426 Firmware capable of SLI 3 mode.\n"); ++ /* Now, try to enable MSI-X interrupt mode */ ++ error = lpfc_enable_msix(phba); ++ if (!error) { ++ phba->intr_type = MSIX; ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0430 enable MSI-X mode.\n"); ++ } ++ } + } + + /* Fallback to MSI if MSI-X initialization failed */ + if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { + retval = pci_enable_msi(phba->pcidev); +- if (!retval) ++ if (!retval) { + phba->intr_type = MSI; +- else + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0452 Enable MSI failed, continuing " +- "with IRQ\n"); ++ "0473 enable MSI mode.\n"); ++ } else ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0452 enable IRQ mode.\n"); + } + + /* MSI-X is the only case the doesn't need to call request_irq */ +@@ -2176,18 +2610,16 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + phba->intr_type = INTx; + } + +- phba->MBslimaddr = phba->slim_memmap_p; +- phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; +- phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; +- phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; +- phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; +- + if (lpfc_alloc_sysfs_attr(vport)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "1476 Failed to allocate sysfs attr\n"); + error = -ENOMEM; + goto out_free_irq; + } + + if (lpfc_sli_hba_setup(phba)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "1477 Failed to set up hba\n"); + error = -ENODEV; + goto out_remove_device; + } +@@ -2206,6 +2638,16 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + spin_unlock_irq(shost->host_lock); + } + ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0428 Perform SCSI scan\n"); ++ /* Send board arrival event to upper layer */ ++ adapter_event.event_type = FC_REG_ADAPTER_EVENT; ++ adapter_event.subcategory = LPFC_EVENT_ARRIVAL; ++ fc_host_post_vendor_event(shost, fc_get_event_number(), ++ sizeof(adapter_event), ++ (char *) &adapter_event, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ + scsi_scan_host(shost); + + return 0; +@@ -2238,11 +2680,11 @@ out_free_iocbq: + } + lpfc_mem_free(phba); + out_free_hbqslimp: +- dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt, +- phba->hbqslimp.phys); ++ dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), ++ phba->hbqslimp.virt, phba->hbqslimp.phys); + out_free_slim: +- dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p, +- phba->slim2p_mapping); ++ dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, ++ phba->slim2p.virt, phba->slim2p.phys); + out_iounmap: + iounmap(phba->ctrl_regs_memmap_p); + out_iounmap_slim: +@@ -2262,6 +2704,14 @@ out: + return error; + } + ++/** ++ * lpfc_pci_remove_one: lpfc PCI func to unregister device from PCI subsystem. ++ * @pdev: pointer to PCI device ++ * ++ * This routine is to be registered to the kernel's PCI subsystem. When an ++ * Emulex HBA is removed from PCI bus. It perform all the necessary cleanup ++ * for the HBA device to be removed from the PCI subsystem properly. ++ **/ + static void __devexit + lpfc_pci_remove_one(struct pci_dev *pdev) + { +@@ -2316,12 +2766,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev + lpfc_scsi_free(phba); + lpfc_mem_free(phba); + +- dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt, +- phba->hbqslimp.phys); ++ dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), ++ phba->hbqslimp.virt, phba->hbqslimp.phys); + + /* Free resources associated with SLI2 interface */ + dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, +- phba->slim2p, phba->slim2p_mapping); ++ phba->slim2p.virt, phba->slim2p.phys); + + /* unmap adapter SLIM and Control Registers */ + iounmap(phba->ctrl_regs_memmap_p); +@@ -2336,13 +2786,21 @@ lpfc_pci_remove_one(struct pci_dev *pdev + } + + /** +- * lpfc_io_error_detected - called when PCI error is detected +- * @pdev: Pointer to PCI device +- * @state: The current pci conneection state ++ * lpfc_io_error_detected: Driver method for handling PCI I/O error detected. ++ * @pdev: pointer to PCI device. ++ * @state: the current PCI connection state. + * +- * This function is called after a PCI bus error affecting +- * this device has been detected. +- */ ++ * This routine is registered to the PCI subsystem for error handling. This ++ * function is called by the PCI subsystem after a PCI bus error affecting ++ * this device has been detected. When this function is invoked, it will ++ * need to stop all the I/Os and interrupt(s) to the device. Once that is ++ * done, it will return PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to ++ * perform proper recovery as desired. ++ * ++ * Return codes ++ * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery ++ * PCI_ERS_RESULT_DISCONNECT - device could not be recovered ++ **/ + static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) + { +@@ -2351,8 +2809,15 @@ static pci_ers_result_t lpfc_io_error_de + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + +- if (state == pci_channel_io_perm_failure) ++ if (state == pci_channel_io_perm_failure) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0472 PCI channel I/O permanent failure\n"); ++ /* Block all SCSI devices' I/Os on the host */ ++ lpfc_scsi_dev_block(phba); ++ /* Clean up all driver's outstanding SCSI I/Os */ ++ lpfc_sli_flush_fcp_rings(phba); + return PCI_ERS_RESULT_DISCONNECT; ++ } + + pci_disable_device(pdev); + /* +@@ -2376,10 +2841,21 @@ static pci_ers_result_t lpfc_io_error_de + } + + /** +- * lpfc_io_slot_reset - called after the pci bus has been reset. +- * @pdev: Pointer to PCI device ++ * lpfc_io_slot_reset: Restart a PCI device from scratch. ++ * @pdev: pointer to PCI device. ++ * ++ * This routine is registered to the PCI subsystem for error handling. This is ++ * called after PCI bus has been reset to restart the PCI card from scratch, ++ * as if from a cold-boot. During the PCI subsystem error recovery, after the ++ * driver returns PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform ++ * proper error recovery and then call this routine before calling the .resume ++ * method to recover the device. This function will initialize the HBA device, ++ * enable the interrupt, but it will just put the HBA to offline state without ++ * passing any I/O traffic. + * +- * Restart the card from scratch, as if from a cold-boot. ++ * Return codes ++ * PCI_ERS_RESULT_RECOVERED - the device has been recovered ++ * PCI_ERS_RESULT_DISCONNECT - device could not be recovered + */ + static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) + { +@@ -2404,20 +2880,34 @@ static pci_ers_result_t lpfc_io_slot_res + /* Enable configured interrupt method */ + phba->intr_type = NONE; + if (phba->cfg_use_msi == 2) { +- error = lpfc_enable_msix(phba); +- if (!error) +- phba->intr_type = MSIX; ++ /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ ++ error = lpfc_sli_config_port(phba, 3); ++ if (error) ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0478 Firmware not capable of SLI 3 mode.\n"); ++ else { ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0479 Firmware capable of SLI 3 mode.\n"); ++ /* Now, try to enable MSI-X interrupt mode */ ++ error = lpfc_enable_msix(phba); ++ if (!error) { ++ phba->intr_type = MSIX; ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0480 enable MSI-X mode.\n"); ++ } ++ } + } + + /* Fallback to MSI if MSI-X initialization failed */ + if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { + retval = pci_enable_msi(phba->pcidev); +- if (!retval) ++ if (!retval) { + phba->intr_type = MSI; +- else + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0470 Enable MSI failed, continuing " +- "with IRQ\n"); ++ "0481 enable MSI mode.\n"); ++ } else ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0470 enable IRQ mode.\n"); + } + + /* MSI-X is the only case the doesn't need to call request_irq */ +@@ -2440,11 +2930,13 @@ static pci_ers_result_t lpfc_io_slot_res + } + + /** +- * lpfc_io_resume - called when traffic can start flowing again. +- * @pdev: Pointer to PCI device ++ * lpfc_io_resume: Resume PCI I/O operation. ++ * @pdev: pointer to PCI device + * +- * This callback is called when the error recovery driver tells us that +- * its OK to resume normal operation. ++ * This routine is registered to the PCI subsystem for error handling. It is ++ * called when kernel error recovery tells the lpfc driver that it is ok to ++ * resume normal PCI operation after PCI bus error recovery. After this call, ++ * traffic can start to flow from this device again. + */ + static void lpfc_io_resume(struct pci_dev *pdev) + { +@@ -2491,6 +2983,8 @@ static struct pci_device_id lpfc_id_tabl + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR, + PCI_ANY_ID, PCI_ANY_ID, }, ++ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET, ++ PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP, +@@ -2521,6 +3015,12 @@ static struct pci_device_id lpfc_id_tabl + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S, + PCI_ANY_ID, PCI_ANY_ID, }, ++ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF, ++ PCI_ANY_ID, PCI_ANY_ID, }, ++ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF, ++ PCI_ANY_ID, PCI_ANY_ID, }, ++ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S, ++ PCI_ANY_ID, PCI_ANY_ID, }, + { 0 } + }; + +@@ -2540,6 +3040,18 @@ static struct pci_driver lpfc_driver = { + .err_handler = &lpfc_err_handler, + }; + ++/** ++ * lpfc_init: lpfc module initialization routine. ++ * ++ * This routine is to be invoked when the lpfc module is loaded into the ++ * kernel. The special kernel macro module_init() is used to indicate the ++ * role of this routine to the kernel as lpfc module entry point. ++ * ++ * Return codes ++ * 0 - successful ++ * -ENOMEM - FC attach transport failed ++ * all others - failed ++ */ + static int __init + lpfc_init(void) + { +@@ -2567,12 +3079,20 @@ lpfc_init(void) + error = pci_register_driver(&lpfc_driver); + if (error) { + fc_release_transport(lpfc_transport_template); +- fc_release_transport(lpfc_vport_transport_template); ++ if (lpfc_enable_npiv) ++ fc_release_transport(lpfc_vport_transport_template); + } + + return error; + } + ++/** ++ * lpfc_exit: lpfc module removal routine. ++ * ++ * This routine is invoked when the lpfc module is removed from the kernel. ++ * The special kernel macro module_exit() is used to indicate the role of ++ * this routine to the kernel as lpfc module exit point. ++ */ + static void __exit + lpfc_exit(void) + { +--- a/drivers/scsi/lpfc/lpfc_mbox.c ++++ b/drivers/scsi/lpfc/lpfc_mbox.c +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2004-2007 Emulex. All rights reserved. * ++ * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * Portions Copyright (C) 2004-2005 Christoph Hellwig * +@@ -30,6 +30,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -37,10 +38,20 @@ + #include "lpfc_crtn.h" + #include "lpfc_compat.h" + +-/**********************************************/ +- +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_dump_mem: Prepare a mailbox command for retrieving HBA's VPD memory. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @offset: offset for dumping VPD memory mailbox command. ++ * ++ * The dump mailbox command provides a method for the device driver to obtain ++ * various types of information from the HBA device. ++ * ++ * This routine prepares the mailbox command for dumping HBA Vital Product ++ * Data (VPD) memory. This mailbox command is to be used for retrieving a ++ * portion (DMP_RSP_SIZE bytes) of a HBA's VPD from the HBA at an address ++ * offset specified by the offset parameter. ++ **/ + void + lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) + { +@@ -65,10 +76,17 @@ lpfc_dump_mem(struct lpfc_hba * phba, LP + return; + } + +-/**********************************************/ +-/* lpfc_read_nv Issue a READ NVPARAM */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_read_nv: Prepare a mailbox command for reading HBA's NVRAM param. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The read NVRAM mailbox command returns the HBA's non-volatile parameters ++ * that are used as defaults when the Fibre Channel link is brought on-line. ++ * ++ * This routine prepares the mailbox command for reading information stored ++ * in the HBA's NVRAM. Specifically, the HBA's WWNN and WWPN. ++ **/ + void + lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -81,10 +99,19 @@ lpfc_read_nv(struct lpfc_hba * phba, LPF + return; + } + +-/**********************************************/ +-/* lpfc_config_async Issue a */ +-/* MBX_ASYNC_EVT_ENABLE mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_config_async: Prepare a mailbox command for enabling HBA async event. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @ring: ring number for the asynchronous event to be configured. ++ * ++ * The asynchronous event enable mailbox command is used to enable the ++ * asynchronous event posting via the ASYNC_STATUS_CN IOCB response and ++ * specifies the default ring to which events are posted. ++ * ++ * This routine prepares the mailbox command for enabling HBA asynchronous ++ * event support on a IOCB ring. ++ **/ + void + lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, + uint32_t ring) +@@ -99,10 +126,19 @@ lpfc_config_async(struct lpfc_hba * phba + return; + } + +-/**********************************************/ +-/* lpfc_heart_beat Issue a HEART_BEAT */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_heart_beat: Prepare a mailbox command for heart beat. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The heart beat mailbox command is used to detect an unresponsive HBA, which ++ * is defined as any device where no error attention is sent and both mailbox ++ * and rings are not processed. ++ * ++ * This routine prepares the mailbox command for issuing a heart beat in the ++ * form of mailbox command to the HBA. The timely completion of the heart ++ * beat mailbox command indicates the health of the HBA. ++ **/ + void + lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -115,10 +151,26 @@ lpfc_heart_beat(struct lpfc_hba * phba, + return; + } + +-/**********************************************/ +-/* lpfc_read_la Issue a READ LA */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_read_la: Prepare a mailbox command for reading HBA link attention. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @mp: DMA buffer memory for reading the link attention information into. ++ * ++ * The read link attention mailbox command is issued to read the Link Event ++ * Attention information indicated by the HBA port when the Link Event bit ++ * of the Host Attention (HSTATT) register is set to 1. A Link Event ++ * Attention occurs based on an exception detected at the Fibre Channel link ++ * interface. ++ * ++ * This routine prepares the mailbox command for reading HBA link attention ++ * information. A DMA memory has been set aside and address passed to the ++ * HBA through @mp for the HBA to DMA link attention information into the ++ * memory as part of the execution of the mailbox command. ++ * ++ * Return codes ++ * 0 - Success (currently always return 0) ++ **/ + int + lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp) + { +@@ -143,10 +195,21 @@ lpfc_read_la(struct lpfc_hba * phba, LPF + return (0); + } + +-/**********************************************/ +-/* lpfc_clear_la Issue a CLEAR LA */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_clear_la: Prepare a mailbox command for clearing HBA link attention. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The clear link attention mailbox command is issued to clear the link event ++ * attention condition indicated by the Link Event bit of the Host Attention ++ * (HSTATT) register. The link event attention condition is cleared only if ++ * the event tag specified matches that of the current link event counter. ++ * The current event tag is read using the read link attention event mailbox ++ * command. ++ * ++ * This routine prepares the mailbox command for clearing HBA link attention ++ * information. ++ **/ + void + lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -161,10 +224,20 @@ lpfc_clear_la(struct lpfc_hba * phba, LP + return; + } + +-/**************************************************/ +-/* lpfc_config_link Issue a CONFIG LINK */ +-/* mailbox command */ +-/**************************************************/ ++/** ++ * lpfc_config_link: Prepare a mailbox command for configuring link on a HBA. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The configure link mailbox command is used before the initialize link ++ * mailbox command to override default value and to configure link-oriented ++ * parameters such as DID address and various timers. Typically, this ++ * command would be used after an F_Port login to set the returned DID address ++ * and the fabric timeout values. This command is not valid before a configure ++ * port command has configured the HBA port. ++ * ++ * This routine prepares the mailbox command for configuring link on a HBA. ++ **/ + void + lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -199,10 +272,98 @@ lpfc_config_link(struct lpfc_hba * phba, + return; + } + +-/**********************************************/ +-/* lpfc_init_link Issue an INIT LINK */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_config_msi: Prepare a mailbox command for configuring msi-x. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The configure MSI-X mailbox command is used to configure the HBA's SLI-3 ++ * MSI-X multi-message interrupt vector association to interrupt attention ++ * conditions. ++ * ++ * Return codes ++ * 0 - Success ++ * -EINVAL - Failure ++ **/ ++int ++lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ++{ ++ MAILBOX_t *mb = &pmb->mb; ++ uint32_t attentionConditions[2]; ++ ++ /* Sanity check */ ++ if (phba->cfg_use_msi != 2) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0475 Not configured for supporting MSI-X " ++ "cfg_use_msi: 0x%x\n", phba->cfg_use_msi); ++ return -EINVAL; ++ } ++ ++ if (phba->sli_rev < 3) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0476 HBA not supporting SLI-3 or later " ++ "SLI Revision: 0x%x\n", phba->sli_rev); ++ return -EINVAL; ++ } ++ ++ /* Clear mailbox command fields */ ++ memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); ++ ++ /* ++ * SLI-3, Message Signaled Interrupt Fearure. ++ */ ++ ++ /* Multi-message attention configuration */ ++ attentionConditions[0] = (HA_R0ATT | HA_R1ATT | HA_R2ATT | HA_ERATT | ++ HA_LATT | HA_MBATT); ++ attentionConditions[1] = 0; ++ ++ mb->un.varCfgMSI.attentionConditions[0] = attentionConditions[0]; ++ mb->un.varCfgMSI.attentionConditions[1] = attentionConditions[1]; ++ ++ /* ++ * Set up message number to HA bit association ++ */ ++#ifdef __BIG_ENDIAN_BITFIELD ++ /* RA0 (FCP Ring) */ ++ mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS] = 1; ++ /* RA1 (Other Protocol Extra Ring) */ ++ mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS] = 1; ++#else /* __LITTLE_ENDIAN_BITFIELD */ ++ /* RA0 (FCP Ring) */ ++ mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS^3] = 1; ++ /* RA1 (Other Protocol Extra Ring) */ ++ mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS^3] = 1; ++#endif ++ /* Multi-message interrupt autoclear configuration*/ ++ mb->un.varCfgMSI.autoClearHA[0] = attentionConditions[0]; ++ mb->un.varCfgMSI.autoClearHA[1] = attentionConditions[1]; ++ ++ /* For now, HBA autoclear does not work reliably, disable it */ ++ mb->un.varCfgMSI.autoClearHA[0] = 0; ++ mb->un.varCfgMSI.autoClearHA[1] = 0; ++ ++ /* Set command and owner bit */ ++ mb->mbxCommand = MBX_CONFIG_MSI; ++ mb->mbxOwner = OWN_HOST; ++ ++ return 0; ++} ++ ++/** ++ * lpfc_init_link: Prepare a mailbox command for initialize link on a HBA. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @topology: the link topology for the link to be initialized to. ++ * @linkspeed: the link speed for the link to be initialized to. ++ * ++ * The initialize link mailbox command is used to initialize the Fibre ++ * Channel link. This command must follow a configure port command that ++ * establishes the mode of operation. ++ * ++ * This routine prepares the mailbox command for initializing link on a HBA ++ * with the specified link topology and speed. ++ **/ + void + lpfc_init_link(struct lpfc_hba * phba, + LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed) +@@ -269,10 +430,27 @@ lpfc_init_link(struct lpfc_hba * phba, + return; + } + +-/**********************************************/ +-/* lpfc_read_sparam Issue a READ SPARAM */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_read_sparam: Prepare a mailbox command for reading HBA parameters. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @vpi: virtual N_Port identifier. ++ * ++ * The read service parameter mailbox command is used to read the HBA port ++ * service parameters. The service parameters are read into the buffer ++ * specified directly by a BDE in the mailbox command. These service ++ * parameters may then be used to build the payload of an N_Port/F_POrt ++ * login request and reply (LOGI/ACC). ++ * ++ * This routine prepares the mailbox command for reading HBA port service ++ * parameters. The DMA memory is allocated in this function and the addresses ++ * are populated into the mailbox command for the HBA to DMA the service ++ * parameters into. ++ * ++ * Return codes ++ * 0 - Success ++ * 1 - DMA memory allocation failed ++ **/ + int + lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) + { +@@ -312,10 +490,21 @@ lpfc_read_sparam(struct lpfc_hba *phba, + return (0); + } + +-/********************************************/ +-/* lpfc_unreg_did Issue a UNREG_DID */ +-/* mailbox command */ +-/********************************************/ ++/** ++ * lpfc_unreg_did: Prepare a mailbox command for unregistering DID. ++ * @phba: pointer to lpfc hba data structure. ++ * @vpi: virtual N_Port identifier. ++ * @did: remote port identifier. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The unregister DID mailbox command is used to unregister an N_Port/F_Port ++ * login for an unknown RPI by specifying the DID of a remote port. This ++ * command frees an RPI context in the HBA port. This has the effect of ++ * performing an implicit N_Port/F_Port logout. ++ * ++ * This routine prepares the mailbox command for unregistering a remote ++ * N_Port/F_Port (DID) login. ++ **/ + void + lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did, + LPFC_MBOXQ_t * pmb) +@@ -333,10 +522,19 @@ lpfc_unreg_did(struct lpfc_hba * phba, u + return; + } + +-/**********************************************/ +-/* lpfc_read_nv Issue a READ CONFIG */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_read_config: Prepare a mailbox command for reading HBA configuration. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The read configuration mailbox command is used to read the HBA port ++ * configuration parameters. This mailbox command provides a method for ++ * seeing any parameters that may have changed via various configuration ++ * mailbox commands. ++ * ++ * This routine prepares the mailbox command for reading out HBA configuration ++ * parameters. ++ **/ + void + lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -350,10 +548,18 @@ lpfc_read_config(struct lpfc_hba * phba, + return; + } + +-/*************************************************/ +-/* lpfc_read_lnk_stat Issue a READ LINK STATUS */ +-/* mailbox command */ +-/*************************************************/ ++/** ++ * lpfc_read_lnk_stat: Prepare a mailbox command for reading HBA link stats. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The read link status mailbox command is used to read the link status from ++ * the HBA. Link status includes all link-related error counters. These ++ * counters are maintained by the HBA and originated in the link hardware ++ * unit. Note that all of these counters wrap. ++ * ++ * This routine prepares the mailbox command for reading out HBA link status. ++ **/ + void + lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -367,10 +573,30 @@ lpfc_read_lnk_stat(struct lpfc_hba * phb + return; + } + +-/********************************************/ +-/* lpfc_reg_login Issue a REG_LOGIN */ +-/* mailbox command */ +-/********************************************/ ++/** ++ * lpfc_reg_login: Prepare a mailbox command for registering remote login. ++ * @phba: pointer to lpfc hba data structure. ++ * @vpi: virtual N_Port identifier. ++ * @did: remote port identifier. ++ * @param: pointer to memory holding the server parameters. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @flag: action flag to be passed back for the complete function. ++ * ++ * The registration login mailbox command is used to register an N_Port or ++ * F_Port login. This registration allows the HBA to cache the remote N_Port ++ * service parameters internally and thereby make the appropriate FC-2 ++ * decisions. The remote port service parameters are handed off by the driver ++ * to the HBA using a descriptor entry that directly identifies a buffer in ++ * host memory. In exchange, the HBA returns an RPI identifier. ++ * ++ * This routine prepares the mailbox command for registering remote port login. ++ * The function allocates DMA buffer for passing the service parameters to the ++ * HBA with the mailbox command. ++ * ++ * Return codes ++ * 0 - Success ++ * 1 - DMA memory allocation failed ++ **/ + int + lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, + uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag) +@@ -418,10 +644,20 @@ lpfc_reg_login(struct lpfc_hba *phba, ui + return (0); + } + +-/**********************************************/ +-/* lpfc_unreg_login Issue a UNREG_LOGIN */ +-/* mailbox command */ +-/**********************************************/ ++/** ++ * lpfc_unreg_login: Prepare a mailbox command for unregistering remote login. ++ * @phba: pointer to lpfc hba data structure. ++ * @vpi: virtual N_Port identifier. ++ * @rpi: remote port identifier ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The unregistration login mailbox command is used to unregister an N_Port ++ * or F_Port login. This command frees an RPI context in the HBA. It has the ++ * effect of performing an implicit N_Port/F_Port logout. ++ * ++ * This routine prepares the mailbox command for unregistering remote port ++ * login. ++ **/ + void + lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi, + LPFC_MBOXQ_t * pmb) +@@ -440,10 +676,21 @@ lpfc_unreg_login(struct lpfc_hba *phba, + return; + } + +-/**************************************************/ +-/* lpfc_reg_vpi Issue a REG_VPI */ +-/* mailbox command */ +-/**************************************************/ ++/** ++ * lpfc_reg_vpi: Prepare a mailbox command for registering vport identifier. ++ * @phba: pointer to lpfc hba data structure. ++ * @vpi: virtual N_Port identifier. ++ * @sid: Fibre Channel S_ID (N_Port_ID assigned to a virtual N_Port). ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The registration vport identifier mailbox command is used to activate a ++ * virtual N_Port after it has acquired an N_Port_ID. The HBA validates the ++ * N_Port_ID against the information in the selected virtual N_Port context ++ * block and marks it active to allow normal processing of IOCB commands and ++ * received unsolicited exchanges. ++ * ++ * This routine prepares the mailbox command for registering a virtual N_Port. ++ **/ + void + lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid, + LPFC_MBOXQ_t *pmb) +@@ -461,10 +708,22 @@ lpfc_reg_vpi(struct lpfc_hba *phba, uint + + } + +-/**************************************************/ +-/* lpfc_unreg_vpi Issue a UNREG_VNPI */ +-/* mailbox command */ +-/**************************************************/ ++/** ++ * lpfc_unreg_vpi: Prepare a mailbox command for unregistering vport id. ++ * @phba: pointer to lpfc hba data structure. ++ * @vpi: virtual N_Port identifier. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The unregistration vport identifier mailbox command is used to inactivate ++ * a virtual N_Port. The driver must have logged out and unregistered all ++ * remote N_Ports to abort any activity on the virtual N_Port. The HBA will ++ * unregisters any default RPIs associated with the specified vpi, aborting ++ * any active exchanges. The HBA will post the mailbox response after making ++ * the virtual N_Port inactive. ++ * ++ * This routine prepares the mailbox command for unregistering a virtual ++ * N_Port. ++ **/ + void + lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb) + { +@@ -479,12 +738,19 @@ lpfc_unreg_vpi(struct lpfc_hba *phba, ui + + } + ++/** ++ * lpfc_config_pcb_setup: Set up IOCB rings in the Port Control Block (PCB) ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine sets up and initializes the IOCB rings in the Port Control ++ * Block (PCB). ++ **/ + static void + lpfc_config_pcb_setup(struct lpfc_hba * phba) + { + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; +- PCB_t *pcbp = &phba->slim2p->pcb; ++ PCB_t *pcbp = phba->pcb; + dma_addr_t pdma_addr; + uint32_t offset; + uint32_t iocbCnt = 0; +@@ -513,29 +779,43 @@ lpfc_config_pcb_setup(struct lpfc_hba * + continue; + } + /* Command ring setup for ring */ +- pring->cmdringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt]; ++ pring->cmdringaddr = (void *)&phba->IOCBs[iocbCnt]; + pcbp->rdsc[i].cmdEntries = pring->numCiocb; + +- offset = (uint8_t *) &phba->slim2p->IOCBs[iocbCnt] - +- (uint8_t *) phba->slim2p; +- pdma_addr = phba->slim2p_mapping + offset; ++ offset = (uint8_t *) &phba->IOCBs[iocbCnt] - ++ (uint8_t *) phba->slim2p.virt; ++ pdma_addr = phba->slim2p.phys + offset; + pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr); + pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr); + iocbCnt += pring->numCiocb; + + /* Response ring setup for ring */ +- pring->rspringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt]; ++ pring->rspringaddr = (void *) &phba->IOCBs[iocbCnt]; + + pcbp->rdsc[i].rspEntries = pring->numRiocb; +- offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - +- (uint8_t *)phba->slim2p; +- pdma_addr = phba->slim2p_mapping + offset; ++ offset = (uint8_t *)&phba->IOCBs[iocbCnt] - ++ (uint8_t *)phba->slim2p.virt; ++ pdma_addr = phba->slim2p.phys + offset; + pcbp->rdsc[i].rspAddrHigh = putPaddrHigh(pdma_addr); + pcbp->rdsc[i].rspAddrLow = putPaddrLow(pdma_addr); + iocbCnt += pring->numRiocb; + } + } + ++/** ++ * lpfc_read_rev: Prepare a mailbox command for reading HBA revision. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The read revision mailbox command is used to read the revision levels of ++ * the HBA components. These components include hardware units, resident ++ * firmware, and available firmware. HBAs that supports SLI-3 mode of ++ * operation provide different response information depending on the version ++ * requested by the driver. ++ * ++ * This routine prepares the mailbox command for reading HBA revision ++ * information. ++ **/ + void + lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -548,6 +828,16 @@ lpfc_read_rev(struct lpfc_hba * phba, LP + return; + } + ++/** ++ * lpfc_build_hbq_profile2: Set up the HBQ Selection Profile 2. ++ * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. ++ * @hbq_desc: pointer to the HBQ selection profile descriptor. ++ * ++ * The Host Buffer Queue (HBQ) Selection Profile 2 specifies that the HBA ++ * tests the incoming frames' R_CTL/TYPE fields with works 10:15 and performs ++ * the Sequence Length Test using the fields in the Selection Profile 2 ++ * extension in words 20:31. ++ **/ + static void + lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb, + struct lpfc_hbq_init *hbq_desc) +@@ -557,6 +847,16 @@ lpfc_build_hbq_profile2(struct config_hb + hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff; + } + ++/** ++ * lpfc_build_hbq_profile3: Set up the HBQ Selection Profile 3. ++ * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. ++ * @hbq_desc: pointer to the HBQ selection profile descriptor. ++ * ++ * The Host Buffer Queue (HBQ) Selection Profile 3 specifies that the HBA ++ * tests the incoming frame's R_CTL/TYPE fields with words 10:15 and performs ++ * the Sequence Length Test and Byte Field Test using the fields in the ++ * Selection Profile 3 extension in words 20:31. ++ **/ + static void + lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb, + struct lpfc_hbq_init *hbq_desc) +@@ -569,6 +869,17 @@ lpfc_build_hbq_profile3(struct config_hb + sizeof(hbqmb->profiles.profile3.cmdmatch)); + } + ++/** ++ * lpfc_build_hbq_profile5: Set up the HBQ Selection Profile 5. ++ * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. ++ * @hbq_desc: pointer to the HBQ selection profile descriptor. ++ * ++ * The Host Buffer Queue (HBQ) Selection Profile 5 specifies a header HBQ. The ++ * HBA tests the initial frame of an incoming sequence using the frame's ++ * R_CTL/TYPE fields with words 10:15 and performs the Sequence Length Test ++ * and Byte Field Test using the fields in the Selection Profile 5 extension ++ * words 20:31. ++ **/ + static void + lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb, + struct lpfc_hbq_init *hbq_desc) +@@ -581,6 +892,20 @@ lpfc_build_hbq_profile5(struct config_hb + sizeof(hbqmb->profiles.profile5.cmdmatch)); + } + ++/** ++ * lpfc_config_hbq: Prepare a mailbox command for configuring an HBQ. ++ * @phba: pointer to lpfc hba data structure. ++ * @id: HBQ identifier. ++ * @hbq_desc: pointer to the HBA descriptor data structure. ++ * @hbq_entry_index: index of the HBQ entry data structures. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The configure HBQ (Host Buffer Queue) mailbox command is used to configure ++ * an HBQ. The configuration binds events that require buffers to a particular ++ * ring and HBQ based on a selection profile. ++ * ++ * This routine prepares the mailbox command for configuring an HBQ. ++ **/ + void + lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id, + struct lpfc_hbq_init *hbq_desc, +@@ -641,8 +966,23 @@ lpfc_config_hbq(struct lpfc_hba *phba, u + return; + } + +- +- ++/** ++ * lpfc_config_ring: Prepare a mailbox command for configuring an IOCB ring. ++ * @phba: pointer to lpfc hba data structure. ++ * @ring: ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The configure ring mailbox command is used to configure an IOCB ring. This ++ * configuration binds from one to six of HBA RC_CTL/TYPE mask entries to the ++ * ring. This is used to map incoming sequences to a particular ring whose ++ * RC_CTL/TYPE mask entry matches that of the sequence. The driver should not ++ * attempt to configure a ring whose number is greater than the number ++ * specified in the Port Control Block (PCB). It is an error to issue the ++ * configure ring command more than once with the same ring number. The HBA ++ * returns an error if the driver attempts this. ++ * ++ * This routine prepares the mailbox command for configuring IOCB ring. ++ **/ + void + lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) + { +@@ -684,6 +1024,20 @@ lpfc_config_ring(struct lpfc_hba * phba, + return; + } + ++/** ++ * lpfc_config_port: Prepare a mailbox command for configuring port. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The configure port mailbox command is used to identify the Port Control ++ * Block (PCB) in the driver memory. After this command is issued, the ++ * driver must not access the mailbox in the HBA without first resetting ++ * the HBA. The HBA may copy the PCB information to internal storage for ++ * subsequent use; the driver can not change the PCB information unless it ++ * resets the HBA. ++ * ++ * This routine prepares the mailbox command for configuring port. ++ **/ + void + lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + { +@@ -702,8 +1056,8 @@ lpfc_config_port(struct lpfc_hba *phba, + + mb->un.varCfgPort.pcbLen = sizeof(PCB_t); + +- offset = (uint8_t *)&phba->slim2p->pcb - (uint8_t *)phba->slim2p; +- pdma_addr = phba->slim2p_mapping + offset; ++ offset = (uint8_t *)phba->pcb - (uint8_t *)phba->slim2p.virt; ++ pdma_addr = phba->slim2p.phys + offset; + mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); + mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); + +@@ -711,12 +1065,13 @@ lpfc_config_port(struct lpfc_hba *phba, + + if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) { + mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ ++ mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */ ++ mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */ + mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count(); + if (phba->max_vpi && phba->cfg_enable_npiv && + phba->vpd.sli3Feat.cmv) { + mb->un.varCfgPort.max_vpi = phba->max_vpi; + mb->un.varCfgPort.cmv = 1; +- phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; + } else + mb->un.varCfgPort.max_vpi = phba->max_vpi = 0; + } else +@@ -724,16 +1079,15 @@ lpfc_config_port(struct lpfc_hba *phba, + mb->un.varCfgPort.sli_mode = phba->sli_rev; + + /* Now setup pcb */ +- phba->slim2p->pcb.type = TYPE_NATIVE_SLI2; +- phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2; ++ phba->pcb->type = TYPE_NATIVE_SLI2; ++ phba->pcb->feature = FEATURE_INITIAL_SLI2; + + /* Setup Mailbox pointers */ +- phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) + +- sizeof(struct sli2_desc); +- offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p; +- pdma_addr = phba->slim2p_mapping + offset; +- phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr); +- phba->slim2p->pcb.mbAddrLow = putPaddrLow(pdma_addr); ++ phba->pcb->mailBoxSize = sizeof(MAILBOX_t); ++ offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt; ++ pdma_addr = phba->slim2p.phys + offset; ++ phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr); ++ phba->pcb->mbAddrLow = putPaddrLow(pdma_addr); + + /* + * Setup Host Group ring pointer. +@@ -794,13 +1148,13 @@ lpfc_config_port(struct lpfc_hba *phba, + } + + /* mask off BAR0's flag bits 0 - 3 */ +- phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + +- (void __iomem *) phba->host_gp - ++ phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + ++ (void __iomem *)phba->host_gp - + (void __iomem *)phba->MBslimaddr; + if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) +- phba->slim2p->pcb.hgpAddrHigh = bar_high; ++ phba->pcb->hgpAddrHigh = bar_high; + else +- phba->slim2p->pcb.hgpAddrHigh = 0; ++ phba->pcb->hgpAddrHigh = 0; + /* write HGP data to SLIM at the required longword offset */ + memset(&hgp, 0, sizeof(struct lpfc_hgp)); + +@@ -810,17 +1164,19 @@ lpfc_config_port(struct lpfc_hba *phba, + } + + /* Setup Port Group ring pointer */ +- if (phba->sli_rev == 3) +- pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port - +- (uint8_t *)phba->slim2p; +- else +- pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port - +- (uint8_t *)phba->slim2p; +- +- pdma_addr = phba->slim2p_mapping + pgp_offset; +- phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr); +- phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr); +- phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0]; ++ if (phba->sli3_options & LPFC_SLI3_INB_ENABLED) { ++ pgp_offset = offsetof(struct lpfc_sli2_slim, ++ mbx.us.s3_inb_pgp.port); ++ phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get; ++ } else if (phba->sli_rev == 3) { ++ pgp_offset = offsetof(struct lpfc_sli2_slim, ++ mbx.us.s3_pgp.port); ++ phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; ++ } else ++ pgp_offset = offsetof(struct lpfc_sli2_slim, mbx.us.s2.port); ++ pdma_addr = phba->slim2p.phys + pgp_offset; ++ phba->pcb->pgpAddrHigh = putPaddrHigh(pdma_addr); ++ phba->pcb->pgpAddrLow = putPaddrLow(pdma_addr); + + /* Use callback routine to setp rings in the pcb */ + lpfc_config_pcb_setup(phba); +@@ -835,10 +1191,24 @@ lpfc_config_port(struct lpfc_hba *phba, + } + + /* Swap PCB if needed */ +- lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb, +- sizeof(PCB_t)); ++ lpfc_sli_pcimem_bcopy(phba->pcb, phba->pcb, sizeof(PCB_t)); + } + ++/** ++ * lpfc_kill_board: Prepare a mailbox command for killing board. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * ++ * The kill board mailbox command is used to tell firmware to perform a ++ * graceful shutdown of a channel on a specified board to prepare for reset. ++ * When the kill board mailbox command is received, the ER3 bit is set to 1 ++ * in the Host Status register and the ER Attention bit is set to 1 in the ++ * Host Attention register of the HBA function that received the kill board ++ * command. ++ * ++ * This routine prepares the mailbox command for killing the board in ++ * preparation for a graceful shutdown. ++ **/ + void + lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) + { +@@ -850,6 +1220,16 @@ lpfc_kill_board(struct lpfc_hba * phba, + return; + } + ++/** ++ * lpfc_mbox_put: Put a mailbox cmd into the tail of driver's mailbox queue. ++ * @phba: pointer to lpfc hba data structure. ++ * @mbq: pointer to the driver internal queue element for mailbox command. ++ * ++ * Driver maintains a internal mailbox command queue implemented as a linked ++ * list. When a mailbox command is issued, it shall be put into the mailbox ++ * command queue such that they shall be processed orderly as HBA can process ++ * one mailbox command at a time. ++ **/ + void + lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) + { +@@ -864,6 +1244,20 @@ lpfc_mbox_put(struct lpfc_hba * phba, LP + return; + } + ++/** ++ * lpfc_mbox_get: Remove a mailbox cmd from the head of driver's mailbox queue. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * Driver maintains a internal mailbox command queue implemented as a linked ++ * list. When a mailbox command is issued, it shall be put into the mailbox ++ * command queue such that they shall be processed orderly as HBA can process ++ * one mailbox command at a time. After HBA finished processing a mailbox ++ * command, the driver will remove a pending mailbox command from the head of ++ * the mailbox command queue and send to the HBA for processing. ++ * ++ * Return codes ++ * pointer to the driver internal queue element for mailbox command. ++ **/ + LPFC_MBOXQ_t * + lpfc_mbox_get(struct lpfc_hba * phba) + { +@@ -877,6 +1271,17 @@ lpfc_mbox_get(struct lpfc_hba * phba) + return mbq; + } + ++/** ++ * lpfc_mbox_cmpl_put: Put mailbox command into mailbox command complete list. ++ * @phba: pointer to lpfc hba data structure. ++ * @mbq: pointer to the driver internal queue element for mailbox command. ++ * ++ * This routine put the completed mailbox command into the mailbox command ++ * complete list. This routine is called from driver interrupt handler ++ * context.The mailbox complete list is used by the driver worker thread ++ * to process mailbox complete callback functions outside the driver interrupt ++ * handler. ++ **/ + void + lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) + { +@@ -887,6 +1292,17 @@ lpfc_mbox_cmpl_put(struct lpfc_hba * phb + return; + } + ++/** ++ * lpfc_mbox_tmo_val: Retrieve mailbox command timeout value. ++ * @phba: pointer to lpfc hba data structure. ++ * @cmd: mailbox command code. ++ * ++ * This routine retrieves the proper timeout value according to the mailbox ++ * command code. ++ * ++ * Return codes ++ * Timeout value to be used for the given mailbox command ++ **/ + int + lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) + { +--- a/drivers/scsi/lpfc/lpfc_mem.c ++++ b/drivers/scsi/lpfc/lpfc_mem.c +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2004-2006 Emulex. All rights reserved. * ++ * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * Portions Copyright (C) 2004-2005 Christoph Hellwig * +@@ -30,6 +30,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -39,7 +40,21 @@ + #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ + + +- ++/** ++ * lpfc_mem_alloc: create and allocate all PCI and memory pools ++ * @phba: HBA to allocate pools for ++ * ++ * Description: Creates and allocates PCI pools lpfc_scsi_dma_buf_pool, ++ * lpfc_mbuf_pool, lpfc_hbq_pool. Creates and allocates kmalloc-backed mempools ++ * for LPFC_MBOXQ_t and lpfc_nodelist. Also allocates the VPI bitmask. ++ * ++ * Notes: Not interrupt-safe. Must be called with no locks held. If any ++ * allocation fails, frees all successfully allocated memory before returning. ++ * ++ * Returns: ++ * 0 on success ++ * -ENOMEM on failure (if any memory allocations fail) ++ **/ + int + lpfc_mem_alloc(struct lpfc_hba * phba) + { +@@ -120,6 +135,16 @@ lpfc_mem_alloc(struct lpfc_hba * phba) + return -ENOMEM; + } + ++/** ++ * lpfc_mem_free: Frees all PCI and memory allocated by lpfc_mem_alloc ++ * @phba: HBA to free memory for ++ * ++ * Description: Frees PCI pools lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool, ++ * lpfc_hbq_pool. Frees kmalloc-backed mempools for LPFC_MBOXQ_t and ++ * lpfc_nodelist. Also frees the VPI bitmask. ++ * ++ * Returns: None ++ **/ + void + lpfc_mem_free(struct lpfc_hba * phba) + { +@@ -181,12 +206,29 @@ lpfc_mem_free(struct lpfc_hba * phba) + phba->lpfc_scsi_dma_buf_pool = NULL; + phba->lpfc_mbuf_pool = NULL; + +- /* Free the iocb lookup array */ ++ /* Free the iocb lookup array */ + kfree(psli->iocbq_lookup); + psli->iocbq_lookup = NULL; +- + } + ++/** ++ * lpfc_mbuf_alloc: Allocate an mbuf from the lpfc_mbuf_pool PCI pool ++ * @phba: HBA which owns the pool to allocate from ++ * @mem_flags: indicates if this is a priority (MEM_PRI) allocation ++ * @handle: used to return the DMA-mapped address of the mbuf ++ * ++ * Description: Allocates a DMA-mapped buffer from the lpfc_mbuf_pool PCI pool. ++ * Allocates from generic pci_pool_alloc function first and if that fails and ++ * mem_flags has MEM_PRI set (the only defined flag), returns an mbuf from the ++ * HBA's pool. ++ * ++ * Notes: Not interrupt-safe. Must be called with no locks held. Takes ++ * phba->hbalock. ++ * ++ * Returns: ++ * pointer to the allocated mbuf on success ++ * NULL on failure ++ **/ + void * + lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) + { +@@ -206,6 +248,20 @@ lpfc_mbuf_alloc(struct lpfc_hba *phba, i + return ret; + } + ++/** ++ * __lpfc_mem_free: Free an mbuf from the lpfc_mbuf_pool PCI pool (locked) ++ * @phba: HBA which owns the pool to return to ++ * @virt: mbuf to free ++ * @dma: the DMA-mapped address of the lpfc_mbuf_pool to be freed ++ * ++ * Description: Returns an mbuf lpfc_mbuf_pool to the lpfc_mbuf_safety_pool if ++ * it is below its max_count, frees the mbuf otherwise. ++ * ++ * Notes: Must be called with phba->hbalock held to synchronize access to ++ * lpfc_mbuf_safety_pool. ++ * ++ * Returns: None ++ **/ + void + __lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) + { +@@ -221,7 +277,21 @@ __lpfc_mbuf_free(struct lpfc_hba * phba, + return; + } + ++/** ++ * lpfc_mem_free: Free an mbuf from the lpfc_mbuf_pool PCI pool (unlocked) ++ * @phba: HBA which owns the pool to return to ++ * @virt: mbuf to free ++ * @dma: the DMA-mapped address of the lpfc_mbuf_pool to be freed ++ * ++ * Description: Returns an mbuf lpfc_mbuf_pool to the lpfc_mbuf_safety_pool if ++ * it is below its max_count, frees the mbuf otherwise. ++ * ++ * Notes: Takes phba->hbalock. Can be called with or without other locks held. ++ * ++ * Returns: None ++ **/ + void ++ + lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) + { + unsigned long iflags; +@@ -232,6 +302,19 @@ lpfc_mbuf_free(struct lpfc_hba * phba, v + return; + } + ++/** ++ * lpfc_els_hbq_alloc: Allocate an HBQ buffer ++ * @phba: HBA to allocate HBQ buffer for ++ * ++ * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hbq_pool PCI ++ * pool along a non-DMA-mapped container for it. ++ * ++ * Notes: Not interrupt-safe. Must be called with no locks held. ++ * ++ * Returns: ++ * pointer to HBQ on success ++ * NULL on failure ++ **/ + struct hbq_dmabuf * + lpfc_els_hbq_alloc(struct lpfc_hba *phba) + { +@@ -251,6 +334,18 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba + return hbqbp; + } + ++/** ++ * lpfc_mem_hbq_free: Frees an HBQ buffer allocated with lpfc_els_hbq_alloc ++ * @phba: HBA buffer was allocated for ++ * @hbqbp: HBQ container returned by lpfc_els_hbq_alloc ++ * ++ * Description: Frees both the container and the DMA-mapped buffer returned by ++ * lpfc_els_hbq_alloc. ++ * ++ * Notes: Can be called with or without locks held. ++ * ++ * Returns: None ++ **/ + void + lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp) + { +@@ -259,7 +354,18 @@ lpfc_els_hbq_free(struct lpfc_hba *phba, + return; + } + +-/* This is ONLY called for the LPFC_ELS_HBQ */ ++/** ++ * lpfc_in_buf_free: Free a DMA buffer ++ * @phba: HBA buffer is associated with ++ * @mp: Buffer to free ++ * ++ * Description: Frees the given DMA buffer in the appropriate way given if the ++ * HBA is running in SLI3 mode with HBQs enabled. ++ * ++ * Notes: Takes phba->hbalock. Can be called with or without other locks held. ++ * ++ * Returns: None ++ **/ + void + lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) + { +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_nl.h +@@ -0,0 +1,163 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2008 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++/* Event definitions for RegisterForEvent */ ++#define FC_REG_LINK_EVENT 0x0001 /* link up / down events */ ++#define FC_REG_RSCN_EVENT 0x0002 /* RSCN events */ ++#define FC_REG_CT_EVENT 0x0004 /* CT request events */ ++#define FC_REG_DUMP_EVENT 0x0008 /* Dump events */ ++#define FC_REG_TEMPERATURE_EVENT 0x0010 /* temperature events */ ++#define FC_REG_ELS_EVENT 0x0020 /* lpfc els events */ ++#define FC_REG_FABRIC_EVENT 0x0040 /* lpfc fabric events */ ++#define FC_REG_SCSI_EVENT 0x0080 /* lpfc scsi events */ ++#define FC_REG_BOARD_EVENT 0x0100 /* lpfc board events */ ++#define FC_REG_ADAPTER_EVENT 0x0200 /* lpfc adapter events */ ++#define FC_REG_EVENT_MASK (FC_REG_LINK_EVENT | \ ++ FC_REG_RSCN_EVENT | \ ++ FC_REG_CT_EVENT | \ ++ FC_REG_DUMP_EVENT | \ ++ FC_REG_TEMPERATURE_EVENT | \ ++ FC_REG_ELS_EVENT | \ ++ FC_REG_FABRIC_EVENT | \ ++ FC_REG_SCSI_EVENT | \ ++ FC_REG_BOARD_EVENT | \ ++ FC_REG_ADAPTER_EVENT) ++/* Temperature events */ ++#define LPFC_CRIT_TEMP 0x1 ++#define LPFC_THRESHOLD_TEMP 0x2 ++#define LPFC_NORMAL_TEMP 0x3 ++/* ++ * All net link event payloads will begin with and event type ++ * and subcategory. The event type must come first. ++ * The subcategory further defines the data that follows in the rest ++ * of the payload. Each category will have its own unique header plus ++ * any addtional data unique to the subcategory. ++ * The payload sent via the fc transport is one-way driver->application. ++ */ ++ ++/* els event header */ ++struct lpfc_els_event_header { ++ uint32_t event_type; ++ uint32_t subcategory; ++ uint8_t wwpn[8]; ++ uint8_t wwnn[8]; ++}; ++ ++/* subcategory codes for FC_REG_ELS_EVENT */ ++#define LPFC_EVENT_PLOGI_RCV 0x01 ++#define LPFC_EVENT_PRLO_RCV 0x02 ++#define LPFC_EVENT_ADISC_RCV 0x04 ++#define LPFC_EVENT_LSRJT_RCV 0x08 ++ ++/* special els lsrjt event */ ++struct lpfc_lsrjt_event { ++ struct lpfc_els_event_header header; ++ uint32_t command; ++ uint32_t reason_code; ++ uint32_t explanation; ++}; ++ ++ ++/* fabric event header */ ++struct lpfc_fabric_event_header { ++ uint32_t event_type; ++ uint32_t subcategory; ++ uint8_t wwpn[8]; ++ uint8_t wwnn[8]; ++}; ++ ++/* subcategory codes for FC_REG_FABRIC_EVENT */ ++#define LPFC_EVENT_FABRIC_BUSY 0x01 ++#define LPFC_EVENT_PORT_BUSY 0x02 ++#define LPFC_EVENT_FCPRDCHKERR 0x04 ++ ++/* special case fabric fcprdchkerr event */ ++struct lpfc_fcprdchkerr_event { ++ struct lpfc_fabric_event_header header; ++ uint32_t lun; ++ uint32_t opcode; ++ uint32_t fcpiparam; ++}; ++ ++ ++/* scsi event header */ ++struct lpfc_scsi_event_header { ++ uint32_t event_type; ++ uint32_t subcategory; ++ uint32_t lun; ++ uint8_t wwpn[8]; ++ uint8_t wwnn[8]; ++}; ++ ++/* subcategory codes for FC_REG_SCSI_EVENT */ ++#define LPFC_EVENT_QFULL 0x0001 ++#define LPFC_EVENT_DEVBSY 0x0002 ++#define LPFC_EVENT_CHECK_COND 0x0004 ++#define LPFC_EVENT_LUNRESET 0x0008 ++#define LPFC_EVENT_TGTRESET 0x0010 ++#define LPFC_EVENT_BUSRESET 0x0020 ++#define LPFC_EVENT_VARQUEDEPTH 0x0040 ++ ++/* special case scsi varqueuedepth event */ ++struct lpfc_scsi_varqueuedepth_event { ++ struct lpfc_scsi_event_header scsi_event; ++ uint32_t oldval; ++ uint32_t newval; ++}; ++ ++/* special case scsi check condition event */ ++struct lpfc_scsi_check_condition_event { ++ struct lpfc_scsi_event_header scsi_event; ++ uint8_t sense_key; ++ uint8_t asc; ++ uint8_t ascq; ++}; ++ ++/* event codes for FC_REG_BOARD_EVENT */ ++#define LPFC_EVENT_PORTINTERR 0x01 ++ ++/* board event header */ ++struct lpfc_board_event_header { ++ uint32_t event_type; ++ uint32_t subcategory; ++}; ++ ++ ++/* event codes for FC_REG_ADAPTER_EVENT */ ++#define LPFC_EVENT_ARRIVAL 0x01 ++ ++/* adapter event header */ ++struct lpfc_adapter_event_header { ++ uint32_t event_type; ++ uint32_t subcategory; ++}; ++ ++ ++/* event codes for temp_event */ ++#define LPFC_CRIT_TEMP 0x1 ++#define LPFC_THRESHOLD_TEMP 0x2 ++#define LPFC_NORMAL_TEMP 0x3 ++ ++struct temp_event { ++ uint32_t event_type; ++ uint32_t event_code; ++ uint32_t data; ++}; ++ +--- a/drivers/scsi/lpfc/lpfc_nportdisc.c ++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c +@@ -30,6 +30,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -1003,20 +1004,8 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_v + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); +- +- if (vport->num_disc_nodes) { ++ if (vport->num_disc_nodes) + lpfc_more_adisc(vport); +- if ((vport->num_disc_nodes == 0) && +- (vport->fc_npr_cnt)) +- lpfc_els_disc_plogi(vport); +- if (vport->num_disc_nodes == 0) { +- spin_lock_irq(shost->host_lock); +- vport->fc_flag &= ~FC_NDISC_ACTIVE; +- spin_unlock_irq(shost->host_lock); +- lpfc_can_disctmo(vport); +- lpfc_end_rscn(vport); +- } +- } + } + return ndlp->nlp_state; + } +@@ -1865,8 +1854,13 @@ static uint32_t + lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) + { ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ if (ndlp->nlp_DID == Fabric_DID) { ++ spin_lock_irq(shost->host_lock); ++ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); ++ spin_unlock_irq(shost->host_lock); ++ } + lpfc_unreg_rpi(vport, ndlp); +- /* This routine does nothing, just return the current state */ + return ndlp->nlp_state; + } + +@@ -2155,7 +2149,7 @@ lpfc_disc_state_machine(struct lpfc_vpor + lpfc_nlp_put(ndlp); + } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, +- "0212 DSM out state %d on NPort free\n", rc); ++ "0213 DSM out state %d on NPort free\n", rc); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, + "DSM out: ste:%d did:x%x flg:x%x", +diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c +index a22bdf9..e1d5421 100644 +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -32,6 +32,7 @@ + #include "lpfc_version.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -42,6 +43,111 @@ + #define LPFC_RESET_WAIT 2 + #define LPFC_ABORT_WAIT 2 + ++/** ++ * lpfc_update_stats: Update statistical data for the command completion. ++ * @phba: Pointer to HBA object. ++ * @lpfc_cmd: lpfc scsi command object pointer. ++ * ++ * This function is called when there is a command completion and this ++ * function updates the statistical data for the command completion. ++ **/ ++static void ++lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) ++{ ++ struct lpfc_rport_data *rdata = lpfc_cmd->rdata; ++ struct lpfc_nodelist *pnode = rdata->pnode; ++ struct scsi_cmnd *cmd = lpfc_cmd->pCmd; ++ unsigned long flags; ++ struct Scsi_Host *shost = cmd->device->host; ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ unsigned long latency; ++ int i; ++ ++ if (cmd->result) ++ return; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ if (!vport->stat_data_enabled || ++ vport->stat_data_blocked || ++ !pnode->lat_data || ++ (phba->bucket_type == LPFC_NO_BUCKET)) { ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ return; ++ } ++ latency = jiffies_to_msecs(jiffies - lpfc_cmd->start_time); ++ ++ if (phba->bucket_type == LPFC_LINEAR_BUCKET) { ++ i = (latency + phba->bucket_step - 1 - phba->bucket_base)/ ++ phba->bucket_step; ++ if (i >= LPFC_MAX_BUCKET_COUNT) ++ i = LPFC_MAX_BUCKET_COUNT; ++ } else { ++ for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++) ++ if (latency <= (phba->bucket_base + ++ ((1<bucket_step))) ++ break; ++ } ++ ++ pnode->lat_data[i].cmd_count++; ++ spin_unlock_irqrestore(shost->host_lock, flags); ++} ++ ++ ++/** ++ * lpfc_send_sdev_queuedepth_change_event: Posts a queuedepth change ++ * event. ++ * @phba: Pointer to HBA context object. ++ * @vport: Pointer to vport object. ++ * @ndlp: Pointer to FC node associated with the target. ++ * @lun: Lun number of the scsi device. ++ * @old_val: Old value of the queue depth. ++ * @new_val: New value of the queue depth. ++ * ++ * This function sends an event to the mgmt application indicating ++ * there is a change in the scsi device queue depth. ++ **/ ++static void ++lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba, ++ struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp, ++ uint32_t lun, ++ uint32_t old_val, ++ uint32_t new_val) ++{ ++ struct lpfc_fast_path_event *fast_path_evt; ++ unsigned long flags; ++ ++ fast_path_evt = lpfc_alloc_fast_evt(phba); ++ if (!fast_path_evt) ++ return; ++ ++ fast_path_evt->un.queue_depth_evt.scsi_event.event_type = ++ FC_REG_SCSI_EVENT; ++ fast_path_evt->un.queue_depth_evt.scsi_event.subcategory = ++ LPFC_EVENT_VARQUEDEPTH; ++ ++ /* Report all luns with change in queue depth */ ++ fast_path_evt->un.queue_depth_evt.scsi_event.lun = lun; ++ if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { ++ memcpy(&fast_path_evt->un.queue_depth_evt.scsi_event.wwpn, ++ &ndlp->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(&fast_path_evt->un.queue_depth_evt.scsi_event.wwnn, ++ &ndlp->nlp_nodename, sizeof(struct lpfc_name)); ++ } ++ ++ fast_path_evt->un.queue_depth_evt.oldval = old_val; ++ fast_path_evt->un.queue_depth_evt.newval = new_val; ++ fast_path_evt->vport = vport; ++ ++ fast_path_evt->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; ++ spin_lock_irqsave(&phba->hbalock, flags); ++ list_add_tail(&fast_path_evt->work_evt.evt_listp, &phba->work_list); ++ spin_unlock_irqrestore(&phba->hbalock, flags); ++ lpfc_worker_wake_up(phba); ++ ++ return; ++} ++ + /* + * This function is called with no lock held when there is a resource + * error in driver or in firmware. +@@ -117,9 +223,10 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) + struct lpfc_vport **vports; + struct Scsi_Host *shost; + struct scsi_device *sdev; +- unsigned long new_queue_depth; ++ unsigned long new_queue_depth, old_queue_depth; + unsigned long num_rsrc_err, num_cmd_success; + int i; ++ struct lpfc_rport_data *rdata; + + num_rsrc_err = atomic_read(&phba->num_rsrc_err); + num_cmd_success = atomic_read(&phba->num_cmd_success); +@@ -137,6 +244,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) + else + new_queue_depth = sdev->queue_depth - + new_queue_depth; ++ old_queue_depth = sdev->queue_depth; + if (sdev->ordered_tags) + scsi_adjust_queue_depth(sdev, + MSG_ORDERED_TAG, +@@ -145,6 +253,13 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) + scsi_adjust_queue_depth(sdev, + MSG_SIMPLE_TAG, + new_queue_depth); ++ rdata = sdev->hostdata; ++ if (rdata) ++ lpfc_send_sdev_queuedepth_change_event( ++ phba, vports[i], ++ rdata->pnode, ++ sdev->lun, old_queue_depth, ++ new_queue_depth); + } + } + lpfc_destroy_vport_work_array(phba, vports); +@@ -159,6 +274,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) + struct Scsi_Host *shost; + struct scsi_device *sdev; + int i; ++ struct lpfc_rport_data *rdata; + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) +@@ -176,6 +292,14 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) + scsi_adjust_queue_depth(sdev, + MSG_SIMPLE_TAG, + sdev->queue_depth+1); ++ rdata = sdev->hostdata; ++ if (rdata) ++ lpfc_send_sdev_queuedepth_change_event( ++ phba, vports[i], ++ rdata->pnode, ++ sdev->lun, ++ sdev->queue_depth - 1, ++ sdev->queue_depth); + } + } + lpfc_destroy_vport_work_array(phba, vports); +@@ -183,6 +307,35 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) + atomic_set(&phba->num_cmd_success, 0); + } + ++/** ++ * lpfc_scsi_dev_block: set all scsi hosts to block state. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function walks vport list and set each SCSI host to block state ++ * by invoking fc_remote_port_delete() routine. This function is invoked ++ * with EEH when device's PCI slot has been permanently disabled. ++ **/ ++void ++lpfc_scsi_dev_block(struct lpfc_hba *phba) ++{ ++ struct lpfc_vport **vports; ++ struct Scsi_Host *shost; ++ struct scsi_device *sdev; ++ struct fc_rport *rport; ++ int i; ++ ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports != NULL) ++ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { ++ shost = lpfc_shost_from_vport(vports[i]); ++ shost_for_each_device(sdev, shost) { ++ rport = starget_to_rport(scsi_target(sdev)); ++ fc_remote_port_delete(rport); ++ } ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++} ++ + /* + * This routine allocates a scsi buffer, which contains all the necessary + * information needed to initiate a SCSI I/O. The non-DMAable buffer region +@@ -198,7 +351,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) + struct lpfc_scsi_buf *psb; + struct ulp_bde64 *bpl; + IOCB_t *iocb; +- dma_addr_t pdma_phys; ++ dma_addr_t pdma_phys_fcp_cmd; ++ dma_addr_t pdma_phys_fcp_rsp; ++ dma_addr_t pdma_phys_bpl; + uint16_t iotag; + + psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); +@@ -238,40 +393,60 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) + + /* Initialize local short-hand pointers. */ + bpl = psb->fcp_bpl; +- pdma_phys = psb->dma_handle; ++ pdma_phys_fcp_cmd = psb->dma_handle; ++ pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd); ++ pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) + ++ sizeof(struct fcp_rsp); + + /* + * The first two bdes are the FCP_CMD and FCP_RSP. The balance are sg + * list bdes. Initialize the first two and leave the rest for + * queuecommand. + */ +- bpl->addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys)); +- bpl->addrLow = le32_to_cpu(putPaddrLow(pdma_phys)); +- bpl->tus.f.bdeSize = sizeof (struct fcp_cmnd); +- bpl->tus.f.bdeFlags = BUFF_USE_CMND; +- bpl->tus.w = le32_to_cpu(bpl->tus.w); +- bpl++; ++ bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd)); ++ bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); ++ bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); ++ bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ bpl[0].tus.w = le32_to_cpu(bpl->tus.w); + + /* Setup the physical region for the FCP RSP */ +- pdma_phys += sizeof (struct fcp_cmnd); +- bpl->addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys)); +- bpl->addrLow = le32_to_cpu(putPaddrLow(pdma_phys)); +- bpl->tus.f.bdeSize = sizeof (struct fcp_rsp); +- bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV); +- bpl->tus.w = le32_to_cpu(bpl->tus.w); ++ bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); ++ bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); ++ bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); ++ bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ bpl[1].tus.w = le32_to_cpu(bpl->tus.w); + + /* + * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, + * initialize it with all known data now. + */ +- pdma_phys += (sizeof (struct fcp_rsp)); + iocb = &psb->cur_iocbq.iocb; + iocb->un.fcpi64.bdl.ulpIoTag32 = 0; +- iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys); +- iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys); +- iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); +- iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL; +- iocb->ulpBdeCount = 1; ++ if (phba->sli_rev == 3) { ++ /* fill in immediate fcp command BDE */ ++ iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED; ++ iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); ++ iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t, ++ unsli3.fcp_ext.icd); ++ iocb->un.fcpi64.bdl.addrHigh = 0; ++ iocb->ulpBdeCount = 0; ++ iocb->ulpLe = 0; ++ /* fill in responce BDE */ ++ iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = ++ sizeof(struct fcp_rsp); ++ iocb->unsli3.fcp_ext.rbde.addrLow = ++ putPaddrLow(pdma_phys_fcp_rsp); ++ iocb->unsli3.fcp_ext.rbde.addrHigh = ++ putPaddrHigh(pdma_phys_fcp_rsp); ++ } else { ++ iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64; ++ iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); ++ iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_bpl); ++ iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_bpl); ++ iocb->ulpBdeCount = 1; ++ iocb->ulpLe = 1; ++ } + iocb->ulpClass = CLASS3; + + return psb; +@@ -313,8 +488,9 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) + struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; + struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl; + IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; ++ struct ulp_bde64 *data_bde = iocb_cmd->unsli3.fcp_ext.dbde; + dma_addr_t physaddr; +- uint32_t i, num_bde = 0; ++ uint32_t num_bde = 0; + int nseg, datadir = scsi_cmnd->sc_data_direction; + + /* +@@ -352,37 +528,159 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) + * during probe that limits the number of sg elements in any + * single scsi command. Just run through the seg_cnt and format + * the bde's. ++ * When using SLI-3 the driver will try to fit all the BDEs into ++ * the IOCB. If it can't then the BDEs get added to a BPL as it ++ * does for SLI-2 mode. + */ +- scsi_for_each_sg(scsi_cmnd, sgel, nseg, i) { ++ scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) { + physaddr = sg_dma_address(sgel); +- bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr)); +- bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr)); +- bpl->tus.f.bdeSize = sg_dma_len(sgel); +- if (datadir == DMA_TO_DEVICE) +- bpl->tus.f.bdeFlags = 0; +- else +- bpl->tus.f.bdeFlags = BUFF_USE_RCV; +- bpl->tus.w = le32_to_cpu(bpl->tus.w); +- bpl++; +- num_bde++; ++ if (phba->sli_rev == 3 && ++ nseg <= LPFC_EXT_DATA_BDE_COUNT) { ++ data_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ data_bde->tus.f.bdeSize = sg_dma_len(sgel); ++ data_bde->addrLow = putPaddrLow(physaddr); ++ data_bde->addrHigh = putPaddrHigh(physaddr); ++ data_bde++; ++ } else { ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ bpl->tus.f.bdeSize = sg_dma_len(sgel); ++ bpl->tus.w = le32_to_cpu(bpl->tus.w); ++ bpl->addrLow = ++ le32_to_cpu(putPaddrLow(physaddr)); ++ bpl->addrHigh = ++ le32_to_cpu(putPaddrHigh(physaddr)); ++ bpl++; ++ } + } + } + + /* + * Finish initializing those IOCB fields that are dependent on the +- * scsi_cmnd request_buffer. Note that the bdeSize is explicitly +- * reinitialized since all iocb memory resources are used many times +- * for transmit, receive, and continuation bpl's. ++ * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is ++ * explicitly reinitialized and for SLI-3 the extended bde count is ++ * explicitly reinitialized since all iocb memory resources are reused. + */ +- iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); +- iocb_cmd->un.fcpi64.bdl.bdeSize += +- (num_bde * sizeof (struct ulp_bde64)); +- iocb_cmd->ulpBdeCount = 1; +- iocb_cmd->ulpLe = 1; ++ if (phba->sli_rev == 3) { ++ if (num_bde > LPFC_EXT_DATA_BDE_COUNT) { ++ /* ++ * The extended IOCB format can only fit 3 BDE or a BPL. ++ * This I/O has more than 3 BDE so the 1st data bde will ++ * be a BPL that is filled in here. ++ */ ++ physaddr = lpfc_cmd->dma_handle; ++ data_bde->tus.f.bdeFlags = BUFF_TYPE_BLP_64; ++ data_bde->tus.f.bdeSize = (num_bde * ++ sizeof(struct ulp_bde64)); ++ physaddr += (sizeof(struct fcp_cmnd) + ++ sizeof(struct fcp_rsp) + ++ (2 * sizeof(struct ulp_bde64))); ++ data_bde->addrHigh = putPaddrHigh(physaddr); ++ data_bde->addrLow = putPaddrLow(physaddr); ++ /* ebde count includes the responce bde and data bpl */ ++ iocb_cmd->unsli3.fcp_ext.ebde_count = 2; ++ } else { ++ /* ebde count includes the responce bde and data bdes */ ++ iocb_cmd->unsli3.fcp_ext.ebde_count = (num_bde + 1); ++ } ++ } else { ++ iocb_cmd->un.fcpi64.bdl.bdeSize = ++ ((num_bde + 2) * sizeof(struct ulp_bde64)); ++ } + fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); + return 0; + } + ++/** ++ * lpfc_send_scsi_error_event: Posts an event when there is SCSI error. ++ * @phba: Pointer to hba context object. ++ * @vport: Pointer to vport object. ++ * @lpfc_cmd: Pointer to lpfc scsi command which reported the error. ++ * @rsp_iocb: Pointer to response iocb object which reported error. ++ * ++ * This function posts an event when there is a SCSI command reporting ++ * error from the scsi device. ++ **/ ++static void ++lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, ++ struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb) { ++ struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; ++ struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; ++ uint32_t resp_info = fcprsp->rspStatus2; ++ uint32_t scsi_status = fcprsp->rspStatus3; ++ uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; ++ struct lpfc_fast_path_event *fast_path_evt = NULL; ++ struct lpfc_nodelist *pnode = lpfc_cmd->rdata->pnode; ++ unsigned long flags; ++ ++ /* If there is queuefull or busy condition send a scsi event */ ++ if ((cmnd->result == SAM_STAT_TASK_SET_FULL) || ++ (cmnd->result == SAM_STAT_BUSY)) { ++ fast_path_evt = lpfc_alloc_fast_evt(phba); ++ if (!fast_path_evt) ++ return; ++ fast_path_evt->un.scsi_evt.event_type = ++ FC_REG_SCSI_EVENT; ++ fast_path_evt->un.scsi_evt.subcategory = ++ (cmnd->result == SAM_STAT_TASK_SET_FULL) ? ++ LPFC_EVENT_QFULL : LPFC_EVENT_DEVBSY; ++ fast_path_evt->un.scsi_evt.lun = cmnd->device->lun; ++ memcpy(&fast_path_evt->un.scsi_evt.wwpn, ++ &pnode->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(&fast_path_evt->un.scsi_evt.wwnn, ++ &pnode->nlp_nodename, sizeof(struct lpfc_name)); ++ } else if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen && ++ ((cmnd->cmnd[0] == READ_10) || (cmnd->cmnd[0] == WRITE_10))) { ++ fast_path_evt = lpfc_alloc_fast_evt(phba); ++ if (!fast_path_evt) ++ return; ++ fast_path_evt->un.check_cond_evt.scsi_event.event_type = ++ FC_REG_SCSI_EVENT; ++ fast_path_evt->un.check_cond_evt.scsi_event.subcategory = ++ LPFC_EVENT_CHECK_COND; ++ fast_path_evt->un.check_cond_evt.scsi_event.lun = ++ cmnd->device->lun; ++ memcpy(&fast_path_evt->un.check_cond_evt.scsi_event.wwpn, ++ &pnode->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(&fast_path_evt->un.check_cond_evt.scsi_event.wwnn, ++ &pnode->nlp_nodename, sizeof(struct lpfc_name)); ++ fast_path_evt->un.check_cond_evt.sense_key = ++ cmnd->sense_buffer[2] & 0xf; ++ fast_path_evt->un.check_cond_evt.asc = cmnd->sense_buffer[12]; ++ fast_path_evt->un.check_cond_evt.ascq = cmnd->sense_buffer[13]; ++ } else if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && ++ fcpi_parm && ++ ((be32_to_cpu(fcprsp->rspResId) != fcpi_parm) || ++ ((scsi_status == SAM_STAT_GOOD) && ++ !(resp_info & (RESID_UNDER | RESID_OVER))))) { ++ /* ++ * If status is good or resid does not match with fcp_param and ++ * there is valid fcpi_parm, then there is a read_check error ++ */ ++ fast_path_evt = lpfc_alloc_fast_evt(phba); ++ if (!fast_path_evt) ++ return; ++ fast_path_evt->un.read_check_error.header.event_type = ++ FC_REG_FABRIC_EVENT; ++ fast_path_evt->un.read_check_error.header.subcategory = ++ LPFC_EVENT_FCPRDCHKERR; ++ memcpy(&fast_path_evt->un.read_check_error.header.wwpn, ++ &pnode->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(&fast_path_evt->un.read_check_error.header.wwnn, ++ &pnode->nlp_nodename, sizeof(struct lpfc_name)); ++ fast_path_evt->un.read_check_error.lun = cmnd->device->lun; ++ fast_path_evt->un.read_check_error.opcode = cmnd->cmnd[0]; ++ fast_path_evt->un.read_check_error.fcpiparam = ++ fcpi_parm; ++ } else ++ return; ++ ++ fast_path_evt->vport = vport; ++ spin_lock_irqsave(&phba->hbalock, flags); ++ list_add_tail(&fast_path_evt->work_evt.evt_listp, &phba->work_list); ++ spin_unlock_irqrestore(&phba->hbalock, flags); ++ lpfc_worker_wake_up(phba); ++ return; ++} + static void + lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) + { +@@ -411,6 +709,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, + uint32_t rsplen = 0; + uint32_t logit = LOG_FCP | LOG_FCP_ERROR; + ++ + /* + * If this is a task management command, there is no + * scsi packet associated with this lpfc_cmd. The driver +@@ -526,6 +825,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, + + out: + cmnd->result = ScsiResult(host_status, scsi_status); ++ lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, rsp_iocb); + } + + static void +@@ -542,9 +842,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + struct scsi_device *sdev, *tmp_sdev; + int depth = 0; + unsigned long flags; ++ struct lpfc_fast_path_event *fast_path_evt; + + lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; + lpfc_cmd->status = pIocbOut->iocb.ulpStatus; ++ atomic_dec(&pnode->cmd_pending); + + if (lpfc_cmd->status) { + if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && +@@ -570,12 +872,36 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + break; + case IOSTAT_NPORT_BSY: + case IOSTAT_FABRIC_BSY: +- cmd->result = ScsiResult(DID_BUS_BUSY, 0); ++ cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); ++ fast_path_evt = lpfc_alloc_fast_evt(phba); ++ if (!fast_path_evt) ++ break; ++ fast_path_evt->un.fabric_evt.event_type = ++ FC_REG_FABRIC_EVENT; ++ fast_path_evt->un.fabric_evt.subcategory = ++ (lpfc_cmd->status == IOSTAT_NPORT_BSY) ? ++ LPFC_EVENT_PORT_BUSY : LPFC_EVENT_FABRIC_BUSY; ++ if (pnode && NLP_CHK_NODE_ACT(pnode)) { ++ memcpy(&fast_path_evt->un.fabric_evt.wwpn, ++ &pnode->nlp_portname, ++ sizeof(struct lpfc_name)); ++ memcpy(&fast_path_evt->un.fabric_evt.wwnn, ++ &pnode->nlp_nodename, ++ sizeof(struct lpfc_name)); ++ } ++ fast_path_evt->vport = vport; ++ fast_path_evt->work_evt.evt = ++ LPFC_EVT_FASTPATH_MGMT_EVT; ++ spin_lock_irqsave(&phba->hbalock, flags); ++ list_add_tail(&fast_path_evt->work_evt.evt_listp, ++ &phba->work_list); ++ spin_unlock_irqrestore(&phba->hbalock, flags); ++ lpfc_worker_wake_up(phba); + break; + case IOSTAT_LOCAL_REJECT: +- if (lpfc_cmd->result == RJT_UNAVAIL_PERM || ++ if (lpfc_cmd->result == IOERR_INVALID_RPI || + lpfc_cmd->result == IOERR_NO_RESOURCES || +- lpfc_cmd->result == RJT_LOGIN_REQUIRED) { ++ lpfc_cmd->result == IOERR_ABORT_REQUESTED) { + cmd->result = ScsiResult(DID_REQUEUE, 0); + break; + } /* else: fall through */ +@@ -586,7 +912,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + + if (!pnode || !NLP_CHK_NODE_ACT(pnode) + || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) +- cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); ++ cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, ++ SAM_STAT_BUSY); + } else { + cmd->result = ScsiResult(DID_OK, 0); + } +@@ -602,8 +929,32 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + scsi_get_resid(cmd)); + } + ++ lpfc_update_stats(phba, lpfc_cmd); + result = cmd->result; + sdev = cmd->device; ++ if (vport->cfg_max_scsicmpl_time && ++ time_after(jiffies, lpfc_cmd->start_time + ++ msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { ++ spin_lock_irqsave(sdev->host->host_lock, flags); ++ if ((pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) && ++ (atomic_read(&pnode->cmd_pending) > LPFC_MIN_TGT_QDEPTH) && ++ ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)))) ++ pnode->cmd_qdepth = atomic_read(&pnode->cmd_pending); ++ ++ pnode->last_change_time = jiffies; ++ spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ } else if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && ++ time_after(jiffies, pnode->last_change_time + ++ msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { ++ spin_lock_irqsave(sdev->host->host_lock, flags); ++ pnode->cmd_qdepth += pnode->cmd_qdepth * ++ LPFC_TGTQ_RAMPUP_PCENT / 100; ++ if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) ++ pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; ++ pnode->last_change_time = jiffies; ++ spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ } ++ + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); + cmd->scsi_done(cmd); + +@@ -647,6 +998,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + pnode->last_ramp_up_time = jiffies; + } + } ++ lpfc_send_sdev_queuedepth_change_event(phba, vport, pnode, ++ 0xFFFFFFFF, ++ sdev->queue_depth - 1, sdev->queue_depth); + } + + /* +@@ -676,6 +1030,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "0711 detected queue full - lun queue " + "depth adjusted to %d.\n", depth); ++ lpfc_send_sdev_queuedepth_change_event(phba, vport, ++ pnode, 0xFFFFFFFF, ++ depth+1, depth); + } + } + +@@ -692,6 +1049,24 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + lpfc_release_scsi_buf(phba, lpfc_cmd); + } + ++/** ++ * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB. ++ * @data: A pointer to the immediate command data portion of the IOCB. ++ * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. ++ * ++ * The routine copies the entire FCP command from @fcp_cmnd to @data while ++ * byte swapping the data to big endian format for transmission on the wire. ++ **/ ++static void ++lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) ++{ ++ int i, j; ++ for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); ++ i += sizeof(uint32_t), j++) { ++ ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); ++ } ++} ++ + static void + lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, + struct lpfc_nodelist *pnode) +@@ -758,7 +1133,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, + fcp_cmnd->fcpCntl3 = 0; + phba->fc4ControlRequests++; + } +- ++ if (phba->sli_rev == 3) ++ lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); + /* + * Finish initializing those IOCB fields that are independent + * of the scsi_cmnd request_buffer +@@ -798,11 +1174,13 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, + piocb = &piocbq->iocb; + + fcp_cmnd = lpfc_cmd->fcp_cmnd; +- int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun); ++ /* Clear out any old data in the FCP command area */ ++ memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); ++ int_to_scsilun(lun, &fcp_cmnd->fcp_lun); + fcp_cmnd->fcpCntl2 = task_mgmt_cmd; +- ++ if (vport->phba->sli_rev == 3) ++ lpfc_fcpcmd_to_iocb(piocb->unsli3.fcp_ext.icd, fcp_cmnd); + piocb->ulpCommand = CMD_FCP_ICMND64_CR; +- + piocb->ulpContext = ndlp->nlp_rpi; + if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { + piocb->ulpFCP2Rcvy = 1; +@@ -966,8 +1344,13 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + * Catch race where our node has transitioned, but the + * transport is still transitioning. + */ +- if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) +- goto out_target_busy; ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { ++ cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); ++ goto out_fail_command; ++ } ++ ++ if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) ++ goto out_host_busy; + + lpfc_cmd = lpfc_get_scsi_buf(phba); + if (lpfc_cmd == NULL) { +@@ -986,6 +1370,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + lpfc_cmd->pCmd = cmnd; + lpfc_cmd->rdata = rdata; + lpfc_cmd->timeout = 0; ++ lpfc_cmd->start_time = jiffies; + cmnd->host_scribble = (unsigned char *)lpfc_cmd; + cmnd->scsi_done = done; + +@@ -995,6 +1380,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + + lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); + ++ atomic_inc(&ndlp->cmd_pending); + err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], + &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); + if (err) +@@ -1009,12 +1395,11 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + return 0; + + out_host_busy_free_buf: ++ atomic_dec(&ndlp->cmd_pending); + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); + lpfc_release_scsi_buf(phba, lpfc_cmd); + out_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; +- out_target_busy: +- return SCSI_MLQUEUE_TARGET_BUSY; + + out_fail_command: + done(cmnd); +@@ -1146,6 +1531,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) + int ret = SUCCESS; + int status; + int cnt; ++ struct lpfc_scsi_event_header scsi_event; + + lpfc_block_error_handler(cmnd); + /* +@@ -1164,6 +1550,19 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) + break; + pnode = rdata->pnode; + } ++ ++ scsi_event.event_type = FC_REG_SCSI_EVENT; ++ scsi_event.subcategory = LPFC_EVENT_TGTRESET; ++ scsi_event.lun = 0; ++ memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); ++ ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(scsi_event), ++ (char *)&scsi_event, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ + if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0721 LUN Reset rport " +@@ -1243,10 +1642,23 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp = NULL; + int match; +- int ret = SUCCESS, status, i; ++ int ret = SUCCESS, status = SUCCESS, i; + int cnt; + struct lpfc_scsi_buf * lpfc_cmd; + unsigned long later; ++ struct lpfc_scsi_event_header scsi_event; ++ ++ scsi_event.event_type = FC_REG_SCSI_EVENT; ++ scsi_event.subcategory = LPFC_EVENT_BUSRESET; ++ scsi_event.lun = 0; ++ memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); ++ memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); ++ ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(scsi_event), ++ (char *)&scsi_event, ++ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); + + lpfc_block_error_handler(cmnd); + /* +--- a/drivers/scsi/lpfc/lpfc_scsi.h ++++ b/drivers/scsi/lpfc/lpfc_scsi.h +@@ -107,6 +107,10 @@ struct fcp_cmnd { + + }; + ++struct lpfc_scsicmd_bkt { ++ uint32_t cmd_count; ++}; ++ + struct lpfc_scsi_buf { + struct list_head list; + struct scsi_cmnd *pCmd; +@@ -139,6 +143,7 @@ struct lpfc_scsi_buf { + */ + struct lpfc_iocbq cur_iocbq; + wait_queue_head_t *waitq; ++ unsigned long start_time; + }; + + #define LPFC_SCSI_DMA_EXT_SIZE 264 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -32,6 +32,7 @@ + + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -66,10 +67,16 @@ typedef enum _lpfc_iocb_type { + LPFC_ABORT_IOCB + } lpfc_iocb_type; + +- /* SLI-2/SLI-3 provide different sized iocbs. Given a pointer +- * to the start of the ring, and the slot number of the +- * desired iocb entry, calc a pointer to that entry. +- */ ++/** ++ * lpfc_cmd_iocb: Get next command iocb entry in the ring. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function returns pointer to next command iocb entry ++ * in the command ring. The caller must hold hbalock to prevent ++ * other threads consume the next command iocb. ++ * SLI-2/SLI-3 provide different sized iocbs. ++ **/ + static inline IOCB_t * + lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -77,6 +84,16 @@ lpfc_cmd_iocb(struct lpfc_hba *phba, str + pring->cmdidx * phba->iocb_cmd_size); + } + ++/** ++ * lpfc_resp_iocb: Get next response iocb entry in the ring. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function returns pointer to next response iocb entry ++ * in the response ring. The caller must hold hbalock to make sure ++ * that no other thread consume the next response iocb. ++ * SLI-2/SLI-3 provide different sized iocbs. ++ **/ + static inline IOCB_t * + lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -84,6 +101,15 @@ lpfc_resp_iocb(struct lpfc_hba *phba, st + pring->rspidx * phba->iocb_rsp_size); + } + ++/** ++ * __lpfc_sli_get_iocbq: Allocates an iocb object from iocb pool. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called with hbalock held. This function ++ * allocates a new driver iocb object from the iocb pool. If the ++ * allocation is successful, it returns pointer to the newly ++ * allocated iocb object else it returns NULL. ++ **/ + static struct lpfc_iocbq * + __lpfc_sli_get_iocbq(struct lpfc_hba *phba) + { +@@ -94,6 +120,15 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *ph + return iocbq; + } + ++/** ++ * lpfc_sli_get_iocbq: Allocates an iocb object from iocb pool. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called with no lock held. This function ++ * allocates a new driver iocb object from the iocb pool. If the ++ * allocation is successful, it returns pointer to the newly ++ * allocated iocb object else it returns NULL. ++ **/ + struct lpfc_iocbq * + lpfc_sli_get_iocbq(struct lpfc_hba *phba) + { +@@ -106,6 +141,16 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba + return iocbq; + } + ++/** ++ * __lpfc_sli_release_iocbq: Release iocb to the iocb pool. ++ * @phba: Pointer to HBA context object. ++ * @iocbq: Pointer to driver iocb object. ++ * ++ * This function is called with hbalock held to release driver ++ * iocb object to the iocb pool. The iotag in the iocb object ++ * does not change for each use of the iocb object. This function ++ * clears all other fields of the iocb object when it is freed. ++ **/ + static void + __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) + { +@@ -118,6 +163,14 @@ __lpfc_sli_release_iocbq(struct lpfc_hba + list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); + } + ++/** ++ * lpfc_sli_release_iocbq: Release iocb to the iocb pool. ++ * @phba: Pointer to HBA context object. ++ * @iocbq: Pointer to driver iocb object. ++ * ++ * This function is called with no lock held to release the iocb to ++ * iocb pool. ++ **/ + void + lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) + { +@@ -131,10 +184,21 @@ lpfc_sli_release_iocbq(struct lpfc_hba * + spin_unlock_irqrestore(&phba->hbalock, iflags); + } + +-/* +- * Translate the iocb command to an iocb command type used to decide the final +- * disposition of each completed IOCB. +- */ ++/** ++ * lpfc_sli_iocb_cmd_type: Get the iocb type. ++ * @iocb_cmnd : iocb command code. ++ * ++ * This function is called by ring event handler function to get the iocb type. ++ * This function translates the iocb command to an iocb command type used to ++ * decide the final disposition of each completed IOCB. ++ * The function returns ++ * LPFC_UNKNOWN_IOCB if it is an unsupported iocb ++ * LPFC_SOL_IOCB if it is a solicited iocb completion ++ * LPFC_ABORT_IOCB if it is an abort iocb ++ * LPFC_UNSOL_IOCB if it is an unsolicited iocb ++ * ++ * The caller is not required to hold any lock. ++ **/ + static lpfc_iocb_type + lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) + { +@@ -230,6 +294,17 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd + return type; + } + ++/** ++ * lpfc_sli_ring_map: Issue config_ring mbox for all rings. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called from SLI initialization code ++ * to configure every ring of the HBA's SLI interface. The ++ * caller is not required to hold any lock. This function issues ++ * a config_ring mailbox command for each ring. ++ * This function returns zero if successful else returns a negative ++ * error code. ++ **/ + static int + lpfc_sli_ring_map(struct lpfc_hba *phba) + { +@@ -262,6 +337,18 @@ lpfc_sli_ring_map(struct lpfc_hba *phba) + return ret; + } + ++/** ++ * lpfc_sli_ringtxcmpl_put: Adds new iocb to the txcmplq. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @piocb: Pointer to the driver iocb object. ++ * ++ * This function is called with hbalock held. The function adds the ++ * new iocb to txcmplq of the given ring. This function always returns ++ * 0. If this function is called for ELS ring, this function checks if ++ * there is a vport associated with the ELS command. This function also ++ * starts els_tmofunc timer if this is an ELS command. ++ **/ + static int + lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *piocb) +@@ -282,6 +369,16 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba + return 0; + } + ++/** ++ * lpfc_sli_ringtx_get: Get first element of the txq. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function is called with hbalock held to get next ++ * iocb in txq of the given ring. If there is any iocb in ++ * the txq, the function returns first iocb in the list after ++ * removing the iocb from the list, else it returns NULL. ++ **/ + static struct lpfc_iocbq * + lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -293,14 +390,25 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phb + return cmd_iocb; + } + ++/** ++ * lpfc_sli_next_iocb_slot: Get next iocb slot in the ring. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function is called with hbalock held and the caller must post the ++ * iocb without releasing the lock. If the caller releases the lock, ++ * iocb slot returned by the function is not guaranteed to be available. ++ * The function returns pointer to the next available iocb slot if there ++ * is available slot in the ring, else it returns NULL. ++ * If the get index of the ring is ahead of the put index, the function ++ * will post an error attention event to the worker thread to take the ++ * HBA to offline state. ++ **/ + static IOCB_t * + lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +- struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? +- &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : +- &phba->slim2p->mbx.us.s2.port[pring->ringno]; ++ struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; + uint32_t max_cmd_idx = pring->numCiocb; +- + if ((pring->next_cmdidx == pring->cmdidx) && + (++pring->next_cmdidx >= max_cmd_idx)) + pring->next_cmdidx = 0; +@@ -336,6 +444,18 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba + return lpfc_cmd_iocb(phba, pring); + } + ++/** ++ * lpfc_sli_next_iotag: Get an iotag for the iocb. ++ * @phba: Pointer to HBA context object. ++ * @iocbq: Pointer to driver iocb object. ++ * ++ * This function gets an iotag for the iocb. If there is no unused iotag and ++ * the iocbq_lookup_len < 0xffff, this function allocates a bigger iotag_lookup ++ * array and assigns a new iotag. ++ * The function returns the allocated iotag if successful, else returns zero. ++ * Zero is not a valid iotag. ++ * The caller is not required to hold any lock. ++ **/ + uint16_t + lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) + { +@@ -399,6 +519,20 @@ lpfc_sli_next_iotag(struct lpfc_hba *phb + return 0; + } + ++/** ++ * lpfc_sli_submit_iocb: Submit an iocb to the firmware. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @iocb: Pointer to iocb slot in the ring. ++ * @nextiocb: Pointer to driver iocb object which need to be ++ * posted to firmware. ++ * ++ * This function is called with hbalock held to post a new iocb to ++ * the firmware. This function copies the new iocb to ring iocb slot and ++ * updates the ring pointers. It adds the new iocb to txcmplq if there is ++ * a completion call back for this iocb else the function will free the ++ * iocb object. ++ **/ + static void + lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + IOCB_t *iocb, struct lpfc_iocbq *nextiocb) +@@ -441,6 +575,18 @@ lpfc_sli_submit_iocb(struct lpfc_hba *ph + writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); + } + ++/** ++ * lpfc_sli_update_full_ring: Update the chip attention register. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * The caller is not required to hold any lock for calling this function. ++ * This function updates the chip attention bits for the ring to inform firmware ++ * that there are pending work to be done for this ring and requests an ++ * interrupt when there is space available in the ring. This function is ++ * called when the driver is unable to post more iocbs to the ring due ++ * to unavailability of space in the ring. ++ **/ + static void + lpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -460,6 +606,15 @@ lpfc_sli_update_full_ring(struct lpfc_hb + pring->stats.iocb_cmd_full++; + } + ++/** ++ * lpfc_sli_update_ring: Update chip attention register. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function updates the chip attention register bit for the ++ * given ring to inform HBA that there is more work to be done ++ * in this ring. The caller is not required to hold any lock. ++ **/ + static void + lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -468,11 +623,22 @@ lpfc_sli_update_ring(struct lpfc_hba *ph + /* + * Tell the HBA that there is work to do in this ring. + */ +- wmb(); +- writel(CA_R0ATT << (ringno * 4), phba->CAregaddr); +- readl(phba->CAregaddr); /* flush */ ++ if (!(phba->sli3_options & LPFC_SLI3_CRP_ENABLED)) { ++ wmb(); ++ writel(CA_R0ATT << (ringno * 4), phba->CAregaddr); ++ readl(phba->CAregaddr); /* flush */ ++ } + } + ++/** ++ * lpfc_sli_resume_iocb: Process iocbs in the txq. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function is called with hbalock held to post pending iocbs ++ * in the txq to the firmware. This function is called when driver ++ * detects space available in the ring. ++ **/ + static void + lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -504,6 +670,16 @@ lpfc_sli_resume_iocb(struct lpfc_hba *ph + return; + } + ++/** ++ * lpfc_sli_next_hbq_slot: Get next hbq entry for the HBQ. ++ * @phba: Pointer to HBA context object. ++ * @hbqno: HBQ number. ++ * ++ * This function is called with hbalock held to get the next ++ * available slot for the given HBQ. If there is free slot ++ * available for the HBQ it will return pointer to the next available ++ * HBQ entry else it will return NULL. ++ **/ + static struct lpfc_hbq_entry * + lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) + { +@@ -539,6 +715,15 @@ lpfc_sli_next_hbq_slot(struct lpfc_hba * + hbqp->hbqPutIdx; + } + ++/** ++ * lpfc_sli_hbqbuf_free_all: Free all the hbq buffers. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called with no lock held to free all the ++ * hbq buffers while uninitializing the SLI interface. It also ++ * frees the HBQ buffers returned by the firmware but not yet ++ * processed by the upper layers. ++ **/ + void + lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) + { +@@ -584,6 +769,18 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba + spin_unlock_irqrestore(&phba->hbalock, flags); + } + ++/** ++ * lpfc_sli_hbq_to_firmware: Post the hbq buffer to firmware. ++ * @phba: Pointer to HBA context object. ++ * @hbqno: HBQ number. ++ * @hbq_buf: Pointer to HBQ buffer. ++ * ++ * This function is called with the hbalock held to post a ++ * hbq buffer to the firmware. If the function finds an empty ++ * slot in the HBQ, it will post the buffer. The function will return ++ * pointer to the hbq entry if it successfully post the buffer ++ * else it will return NULL. ++ **/ + static struct lpfc_hbq_entry * + lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno, + struct hbq_dmabuf *hbq_buf) +@@ -612,6 +809,7 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba + return hbqe; + } + ++/* HBQ for ELS and CT traffic. */ + static struct lpfc_hbq_init lpfc_els_hbq = { + .rn = 1, + .entry_count = 200, +@@ -623,6 +821,7 @@ static struct lpfc_hbq_init lpfc_els_hbq + .add_count = 5, + }; + ++/* HBQ for the extra ring if needed */ + static struct lpfc_hbq_init lpfc_extra_hbq = { + .rn = 1, + .entry_count = 200, +@@ -634,51 +833,81 @@ static struct lpfc_hbq_init lpfc_extra_h + .add_count = 5, + }; + ++/* Array of HBQs */ + struct lpfc_hbq_init *lpfc_hbq_defs[] = { + &lpfc_els_hbq, + &lpfc_extra_hbq, + }; + ++/** ++ * lpfc_sli_hbqbuf_fill_hbqs: Post more hbq buffers to HBQ. ++ * @phba: Pointer to HBA context object. ++ * @hbqno: HBQ number. ++ * @count: Number of HBQ buffers to be posted. ++ * ++ * This function is called with no lock held to post more hbq buffers to the ++ * given HBQ. The function returns the number of HBQ buffers successfully ++ * posted. ++ **/ + static int + lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) + { +- uint32_t i, start, end; ++ uint32_t i, posted = 0; + unsigned long flags; + struct hbq_dmabuf *hbq_buffer; +- ++ LIST_HEAD(hbq_buf_list); + if (!phba->hbqs[hbqno].hbq_alloc_buffer) + return 0; + +- start = phba->hbqs[hbqno].buffer_count; +- end = count + start; +- if (end > lpfc_hbq_defs[hbqno]->entry_count) +- end = lpfc_hbq_defs[hbqno]->entry_count; +- ++ if ((phba->hbqs[hbqno].buffer_count + count) > ++ lpfc_hbq_defs[hbqno]->entry_count) ++ count = lpfc_hbq_defs[hbqno]->entry_count - ++ phba->hbqs[hbqno].buffer_count; ++ if (!count) ++ return 0; ++ /* Allocate HBQ entries */ ++ for (i = 0; i < count; i++) { ++ hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); ++ if (!hbq_buffer) ++ break; ++ list_add_tail(&hbq_buffer->dbuf.list, &hbq_buf_list); ++ } + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) +- goto out; +- +- /* Populate HBQ entries */ +- for (i = start; i < end; i++) { +- hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); +- if (!hbq_buffer) +- goto err; +- hbq_buffer->tag = (i | (hbqno << 16)); +- if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) ++ goto err; ++ while (!list_empty(&hbq_buf_list)) { ++ list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf, ++ dbuf.list); ++ hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count | ++ (hbqno << 16)); ++ if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) { + phba->hbqs[hbqno].buffer_count++; +- else ++ posted++; ++ } else + (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); + } +- +- out: + spin_unlock_irqrestore(&phba->hbalock, flags); +- return 0; +- err: ++ return posted; ++err: + spin_unlock_irqrestore(&phba->hbalock, flags); +- return 1; ++ while (!list_empty(&hbq_buf_list)) { ++ list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf, ++ dbuf.list); ++ (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); ++ } ++ return 0; + } + ++/** ++ * lpfc_sli_hbqbuf_add_hbqs: Post more HBQ buffers to firmware. ++ * @phba: Pointer to HBA context object. ++ * @qno: HBQ number. ++ * ++ * This function posts more buffers to the HBQ. This function ++ * is called with no lock held. The function returns the number of HBQ entries ++ * successfully allocated. ++ **/ + int + lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno) + { +@@ -686,6 +915,15 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba + lpfc_hbq_defs[qno]->add_count)); + } + ++/** ++ * lpfc_sli_hbqbuf_init_hbqs: Post initial buffers to the HBQ. ++ * @phba: Pointer to HBA context object. ++ * @qno: HBQ queue number. ++ * ++ * This function is called from SLI initialization code path with ++ * no lock held to post initial HBQ buffers to firmware. The ++ * function returns the number of HBQ entries successfully allocated. ++ **/ + static int + lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno) + { +@@ -693,6 +931,16 @@ lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hb + lpfc_hbq_defs[qno]->init_count)); + } + ++/** ++ * lpfc_sli_hbqbuf_find: Find the hbq buffer associated with a tag. ++ * @phba: Pointer to HBA context object. ++ * @tag: Tag of the hbq buffer. ++ * ++ * This function is called with hbalock held. This function searches ++ * for the hbq buffer associated with the given tag in the hbq buffer ++ * list. If it finds the hbq buffer, it returns the hbq_buffer other wise ++ * it returns NULL. ++ **/ + static struct hbq_dmabuf * + lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) + { +@@ -716,6 +964,15 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *ph + return NULL; + } + ++/** ++ * lpfc_sli_free_hbq: Give back the hbq buffer to firmware. ++ * @phba: Pointer to HBA context object. ++ * @hbq_buffer: Pointer to HBQ buffer. ++ * ++ * This function is called with hbalock. This function gives back ++ * the hbq buffer to firmware. If the HBQ does not have space to ++ * post the buffer, it will free the buffer. ++ **/ + void + lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer) + { +@@ -729,6 +986,15 @@ lpfc_sli_free_hbq(struct lpfc_hba *phba, + } + } + ++/** ++ * lpfc_sli_chk_mbx_command: Check if the mailbox is a legitimate mailbox. ++ * @mbxCommand: mailbox command code. ++ * ++ * This function is called by the mailbox event handler function to verify ++ * that the completed mailbox command is a legitimate mailbox command. If the ++ * completed mailbox is not known to the function, it will return MBX_SHUTDOWN ++ * and the mailbox event handler will take the HBA offline. ++ **/ + static int + lpfc_sli_chk_mbx_command(uint8_t mbxCommand) + { +@@ -785,6 +1051,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxComm + case MBX_REG_VPI: + case MBX_UNREG_VPI: + case MBX_HEARTBEAT: ++ case MBX_PORT_CAPABILITIES: ++ case MBX_PORT_IOV_CONTROL: + ret = mbxCommand; + break; + default: +@@ -793,6 +1061,19 @@ lpfc_sli_chk_mbx_command(uint8_t mbxComm + } + return ret; + } ++ ++/** ++ * lpfc_sli_wake_mbox_wait: Completion handler for mbox issued from ++ * lpfc_sli_issue_mbox_wait. ++ * @phba: Pointer to HBA context object. ++ * @pmboxq: Pointer to mailbox command. ++ * ++ * This is completion handler function for mailbox commands issued from ++ * lpfc_sli_issue_mbox_wait function. This function is called by the ++ * mailbox event handler function with no lock held. This function ++ * will wake up thread waiting on the wait queue pointed by context1 ++ * of the mailbox. ++ **/ + static void + lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) + { +@@ -812,6 +1093,17 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba + return; + } + ++ ++/** ++ * lpfc_sli_def_mbox_cmpl: Default mailbox completion handler. ++ * @phba: Pointer to HBA context object. ++ * @pmb: Pointer to mailbox object. ++ * ++ * This function is the default mailbox completion handler. It ++ * frees the memory resources associated with the completed mailbox ++ * command. If the completed command is a REG_LOGIN mailbox command, ++ * this function will issue a UREG_LOGIN to re-claim the RPI. ++ **/ + void + lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + { +@@ -846,6 +1138,19 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba * + return; + } + ++/** ++ * lpfc_sli_handle_mb_event: Handle mailbox completions from firmware. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called with no lock held. This function processes all ++ * the completed mailbox commands and gives it to upper layers. The interrupt ++ * service routine processes mailbox completion interrupt and adds completed ++ * mailbox commands to the mboxq_cmpl queue and signals the worker thread. ++ * Worker thread call lpfc_sli_handle_mb_event, which will return the ++ * completed mailbox commands in mboxq_cmpl queue to the upper layers. This ++ * function returns the mailbox commands to the upper layer by calling the ++ * completion handler function of each mailbox. ++ **/ + int + lpfc_sli_handle_mb_event(struct lpfc_hba *phba) + { +@@ -953,6 +1258,18 @@ lpfc_sli_handle_mb_event(struct lpfc_hba + return 0; + } + ++/** ++ * lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer. ++ * @phba: Pointer to HBA context object. ++ * @tag: Tag for the HBQ buffer. ++ * ++ * This function is called from unsolicited event handler code path to get the ++ * HBQ buffer associated with an unsolicited iocb. This function is called with ++ * no lock held. It returns the buffer associated with the given tag and posts ++ * another buffer to the firmware. Note that the new buffer must be allocated ++ * before taking the hbalock and that the hba lock must be held until it is ++ * finished with the hbq entry swap. ++ **/ + static struct lpfc_dmabuf * + lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) + { +@@ -962,22 +1279,28 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba + dma_addr_t phys; /* mapped address */ + unsigned long flags; + ++ hbqno = tag >> 16; ++ new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { ++ if (new_hbq_entry) ++ (phba->hbqs[hbqno].hbq_free_buffer)(phba, ++ new_hbq_entry); + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; + } + + hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); + if (hbq_entry == NULL) { ++ if (new_hbq_entry) ++ (phba->hbqs[hbqno].hbq_free_buffer)(phba, ++ new_hbq_entry); + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; + } + list_del(&hbq_entry->dbuf.list); + +- hbqno = tag >> 16; +- new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); + if (new_hbq_entry == NULL) { + list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list); + spin_unlock_irqrestore(&phba->hbalock, flags); +@@ -997,6 +1320,18 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba + return &new_hbq_entry->dbuf; + } + ++/** ++ * lpfc_sli_get_buff: Get the buffer associated with the buffer tag. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @tag: buffer tag. ++ * ++ * This function is called with no lock held. When QUE_BUFTAG_BIT bit ++ * is set in the tag the buffer is posted for a particular exchange, ++ * the function will return the buffer without replacing the buffer. ++ * If the buffer is for unsolicited ELS or CT traffic, this function ++ * returns the buffer and also posts another buffer to the firmware. ++ **/ + static struct lpfc_dmabuf * + lpfc_sli_get_buff(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, +@@ -1008,6 +1343,21 @@ lpfc_sli_get_buff(struct lpfc_hba *phba, + return lpfc_sli_replace_hbqbuff(phba, tag); + } + ++ ++/** ++ * lpfc_sli_process_unsol_iocb: Unsolicited iocb handler. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @saveq: Pointer to the unsolicited iocb. ++ * ++ * This function is called with no lock held by the ring event handler ++ * when there is an unsolicited iocb posted to the response ring by the ++ * firmware. This function gets the buffer associated with the iocbs ++ * and calls the event handler for the ring. This function handles both ++ * qring buffers and hbq buffers. ++ * When the function returns 1 the caller can free the iocb object otherwise ++ * upper layer functions will free the iocb objects. ++ **/ + static int + lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *saveq) +@@ -1192,6 +1542,18 @@ lpfc_sli_process_unsol_iocb(struct lpfc_ + return 1; + } + ++/** ++ * lpfc_sli_iocbq_lookup: Find command iocb for the given response iocb. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @prspiocb: Pointer to response iocb object. ++ * ++ * This function looks up the iocb_lookup table to get the command iocb ++ * corresponding to the given response iocb using the iotag of the ++ * response iocb. This function is called with the hbalock held. ++ * This function returns the command iocb object if it finds the command ++ * iocb else returns NULL. ++ **/ + static struct lpfc_iocbq * + lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, +@@ -1217,6 +1579,23 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *p + return NULL; + } + ++/** ++ * lpfc_sli_process_sol_iocb: process solicited iocb completion. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @saveq: Pointer to the response iocb to be processed. ++ * ++ * This function is called by the ring event handler for non-fcp ++ * rings when there is a new response iocb in the response ring. ++ * The caller is not required to hold any locks. This function ++ * gets the command iocb associated with the response iocb and ++ * calls the completion handler for the command iocb. If there ++ * is no completion handler, the function will free the resources ++ * associated with command iocb. If the response iocb is for ++ * an already aborted command iocb, the status of the completion ++ * is changed to IOSTAT_LOCAL_REJECT/IOERR_SLI_ABORTED. ++ * This function always returns 1. ++ **/ + static int + lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *saveq) +@@ -1233,6 +1612,17 @@ lpfc_sli_process_sol_iocb(struct lpfc_hb + if (cmdiocbp) { + if (cmdiocbp->iocb_cmpl) { + /* ++ * If an ELS command failed send an event to mgmt ++ * application. ++ */ ++ if (saveq->iocb.ulpStatus && ++ (pring->ringno == LPFC_ELS_RING) && ++ (cmdiocbp->iocb.ulpCommand == ++ CMD_ELS_REQUEST64_CR)) ++ lpfc_send_els_failure_event(phba, ++ cmdiocbp, saveq); ++ ++ /* + * Post all ELS completions to the worker thread. + * All other are passed to the completion callback. + */ +@@ -1282,12 +1672,20 @@ lpfc_sli_process_sol_iocb(struct lpfc_hb + return rc; + } + ++/** ++ * lpfc_sli_rsp_pointers_error: Response ring pointer error handler. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function is called from the iocb ring event handlers when ++ * put pointer is ahead of the get pointer for a ring. This function signal ++ * an error attention condition to the worker thread and the worker ++ * thread will transition the HBA to offline state. ++ **/ + static void + lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +- struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? +- &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : +- &phba->slim2p->mbx.us.s2.port[pring->ringno]; ++ struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; + /* + * Ring handler: portRspPut is bigger then + * rsp ring +@@ -1312,6 +1710,51 @@ lpfc_sli_rsp_pointers_error(struct lpfc_ + return; + } + ++/** ++ * lpfc_poll_eratt: Error attention polling timer timeout handler. ++ * @ptr: Pointer to address of HBA context object. ++ * ++ * This function is invoked by the Error Attention polling timer when the ++ * timer times out. It will check the SLI Error Attention register for ++ * possible attention events. If so, it will post an Error Attention event ++ * and wake up worker thread to process it. Otherwise, it will set up the ++ * Error Attention polling timer for the next poll. ++ **/ ++void lpfc_poll_eratt(unsigned long ptr) ++{ ++ struct lpfc_hba *phba; ++ uint32_t eratt = 0; ++ ++ phba = (struct lpfc_hba *)ptr; ++ ++ /* Check chip HA register for error event */ ++ eratt = lpfc_sli_check_eratt(phba); ++ ++ if (eratt) ++ /* Tell the worker thread there is work to do */ ++ lpfc_worker_wake_up(phba); ++ else ++ /* Restart the timer for next eratt poll */ ++ mod_timer(&phba->eratt_poll, jiffies + ++ HZ * LPFC_ERATT_POLL_INTERVAL); ++ return; ++} ++ ++/** ++ * lpfc_sli_poll_fcp_ring: Handle FCP ring completion in polling mode. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called from lpfc_queuecommand, lpfc_poll_timeout, ++ * lpfc_abort_handler and lpfc_slave_configure when FCP_RING_POLLING ++ * is enabled. ++ * ++ * The caller does not hold any lock. ++ * The function processes each response iocb in the response ring until it ++ * finds an iocb with LE bit set and chains all the iocbs upto the iocb with ++ * LE bit set. The function will call the completion handler of the command iocb ++ * if the response iocb indicates a completion for a command iocb or it is ++ * an abort completion. ++ **/ + void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) + { + struct lpfc_sli *psli = &phba->sli; +@@ -1320,7 +1763,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_ + IOCB_t *entry = NULL; + struct lpfc_iocbq *cmdiocbq = NULL; + struct lpfc_iocbq rspiocbq; +- struct lpfc_pgp *pgp; ++ struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; + uint32_t status; + uint32_t portRspPut, portRspMax; + int type; +@@ -1330,11 +1773,6 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_ + + pring->stats.iocb_event++; + +- pgp = (phba->sli_rev == 3) ? +- &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : +- &phba->slim2p->mbx.us.s2.port[pring->ringno]; +- +- + /* + * The next available response entry should never exceed the maximum + * entries. If it does, treat it as an adapter hardware error. +@@ -1372,8 +1810,8 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_ + irsp->un.ulpWord[3], + irsp->un.ulpWord[4], + irsp->un.ulpWord[5], +- *(((uint32_t *) irsp) + 6), +- *(((uint32_t *) irsp) + 7)); ++ *(uint32_t *)&irsp->un1, ++ *((uint32_t *)&irsp->un1 + 1)); + } + + switch (type) { +@@ -1465,17 +1903,28 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_ + return; + } + +-/* ++/** ++ * lpfc_sli_handle_fast_ring_event: Handle ring events on FCP ring. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @mask: Host attention register mask for this ring. ++ * ++ * This function is called from the interrupt context when there is a ring ++ * event for the fcp ring. The caller does not hold any lock. ++ * The function processes each response iocb in the response ring until it ++ * finds an iocb with LE bit set and chains all the iocbs upto the iocb with ++ * LE bit set. The function will call the completion handler of the command iocb ++ * if the response iocb indicates a completion for a command iocb or it is ++ * an abort completion. The function will call lpfc_sli_process_unsol_iocb ++ * function if this is an unsolicited iocb. + * This routine presumes LPFC_FCP_RING handling and doesn't bother +- * to check it explicitly. +- */ ++ * to check it explicitly. This function always returns 1. ++ **/ + static int + lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, uint32_t mask) + { +- struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? +- &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : +- &phba->slim2p->mbx.us.s2.port[pring->ringno]; ++ struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; + IOCB_t *irsp = NULL; + IOCB_t *entry = NULL; + struct lpfc_iocbq *cmdiocbq = NULL; +@@ -1548,8 +1997,8 @@ lpfc_sli_handle_fast_ring_event(struct l + irsp->un.ulpWord[3], + irsp->un.ulpWord[4], + irsp->un.ulpWord[5], +- *(((uint32_t *) irsp) + 6), +- *(((uint32_t *) irsp) + 7)); ++ *(uint32_t *)&irsp->un1, ++ *((uint32_t *)&irsp->un1 + 1)); + } + + switch (type) { +@@ -1646,13 +2095,28 @@ lpfc_sli_handle_fast_ring_event(struct l + return rc; + } + ++/** ++ * lpfc_sli_handle_slow_ring_event: Handle ring events for non-FCP rings. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @mask: Host attention register mask for this ring. ++ * ++ * This function is called from the worker thread when there is a ring ++ * event for non-fcp rings. The caller does not hold any lock . ++ * The function processes each response iocb in the response ring until it ++ * finds an iocb with LE bit set and chains all the iocbs upto the iocb with ++ * LE bit set. The function will call lpfc_sli_process_sol_iocb function if the ++ * response iocb indicates a completion of a command iocb. The function ++ * will call lpfc_sli_process_unsol_iocb function if this is an unsolicited ++ * iocb. The function frees the resources or calls the completion handler if ++ * this iocb is an abort completion. The function returns 0 when the allocated ++ * iocbs are not freed, otherwise returns 1. ++ **/ + int + lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, uint32_t mask) + { +- struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? +- &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : +- &phba->slim2p->mbx.us.s2.port[pring->ringno]; ++ struct lpfc_pgp *pgp; + IOCB_t *entry; + IOCB_t *irsp = NULL; + struct lpfc_iocbq *rspiocbp = NULL; +@@ -1666,6 +2130,7 @@ lpfc_sli_handle_slow_ring_event(struct l + int rc = 1; + unsigned long iflag; + ++ pgp = &phba->port_gp[pring->ringno]; + spin_lock_irqsave(&phba->hbalock, iflag); + pring->stats.iocb_event++; + +@@ -1904,6 +2369,16 @@ lpfc_sli_handle_slow_ring_event(struct l + return rc; + } + ++/** ++ * lpfc_sli_abort_iocb_ring: Abort all iocbs in the ring. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * ++ * This function aborts all iocbs in the given ring and frees all the iocb ++ * objects in txq. This function issues an abort iocb for all the iocb commands ++ * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before ++ * the return of this function. The caller is not required to hold any locks. ++ **/ + void + lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) + { +@@ -1943,6 +2418,83 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba + } + } + ++/** ++ * lpfc_sli_flush_fcp_rings: flush all iocbs in the fcp ring. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function flushes all iocbs in the fcp ring and frees all the iocb ++ * objects in txq and txcmplq. This function will not issue abort iocbs ++ * for all the iocb commands in txcmplq, they will just be returned with ++ * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI ++ * slot has been permanently disabled. ++ **/ ++void ++lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) ++{ ++ LIST_HEAD(txq); ++ LIST_HEAD(txcmplq); ++ struct lpfc_iocbq *iocb; ++ IOCB_t *cmd = NULL; ++ struct lpfc_sli *psli = &phba->sli; ++ struct lpfc_sli_ring *pring; ++ ++ /* Currently, only one fcp ring */ ++ pring = &psli->ring[psli->fcp_ring]; ++ ++ spin_lock_irq(&phba->hbalock); ++ /* Retrieve everything on txq */ ++ list_splice_init(&pring->txq, &txq); ++ pring->txq_cnt = 0; ++ ++ /* Retrieve everything on the txcmplq */ ++ list_splice_init(&pring->txcmplq, &txcmplq); ++ pring->txcmplq_cnt = 0; ++ spin_unlock_irq(&phba->hbalock); ++ ++ /* Flush the txq */ ++ while (!list_empty(&txq)) { ++ iocb = list_get_first(&txq, struct lpfc_iocbq, list); ++ cmd = &iocb->iocb; ++ list_del_init(&iocb->list); ++ ++ if (!iocb->iocb_cmpl) ++ lpfc_sli_release_iocbq(phba, iocb); ++ else { ++ cmd->ulpStatus = IOSTAT_LOCAL_REJECT; ++ cmd->un.ulpWord[4] = IOERR_SLI_DOWN; ++ (iocb->iocb_cmpl) (phba, iocb, iocb); ++ } ++ } ++ ++ /* Flush the txcmpq */ ++ while (!list_empty(&txcmplq)) { ++ iocb = list_get_first(&txcmplq, struct lpfc_iocbq, list); ++ cmd = &iocb->iocb; ++ list_del_init(&iocb->list); ++ ++ if (!iocb->iocb_cmpl) ++ lpfc_sli_release_iocbq(phba, iocb); ++ else { ++ cmd->ulpStatus = IOSTAT_LOCAL_REJECT; ++ cmd->un.ulpWord[4] = IOERR_SLI_DOWN; ++ (iocb->iocb_cmpl) (phba, iocb, iocb); ++ } ++ } ++} ++ ++/** ++ * lpfc_sli_brdready: Check for host status bits. ++ * @phba: Pointer to HBA context object. ++ * @mask: Bit mask to be checked. ++ * ++ * This function reads the host status register and compares ++ * with the provided bit mask to check if HBA completed ++ * the restart. This function will wait in a loop for the ++ * HBA to complete restart. If the HBA does not restart within ++ * 15 iterations, the function will reset the HBA again. The ++ * function returns 1 when HBA fail to restart otherwise returns ++ * zero. ++ **/ + int + lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) + { +@@ -1990,6 +2542,13 @@ lpfc_sli_brdready(struct lpfc_hba *phba, + + #define BARRIER_TEST_PATTERN (0xdeadbeef) + ++/** ++ * lpfc_reset_barrier: Make HBA ready for HBA reset. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called before resetting an HBA. This ++ * function requests HBA to quiesce DMAs before a reset. ++ **/ + void lpfc_reset_barrier(struct lpfc_hba *phba) + { + uint32_t __iomem *resp_buf; +@@ -2063,6 +2622,17 @@ restore_hc: + readl(phba->HCregaddr); /* flush */ + } + ++/** ++ * lpfc_sli_brdkill: Issue a kill_board mailbox command. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function issues a kill_board mailbox command and waits for ++ * the error attention interrupt. This function is called for stopping ++ * the firmware processing. The caller is not required to hold any ++ * locks. This function calls lpfc_hba_down_post function to free ++ * any pending commands after the kill. The function will return 1 when it ++ * fails to kill the board else will return 0. ++ **/ + int + lpfc_sli_brdkill(struct lpfc_hba *phba) + { +@@ -2139,6 +2709,17 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) + return ha_copy & HA_ERATT ? 0 : 1; + } + ++/** ++ * lpfc_sli_brdreset: Reset the HBA. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function resets the HBA by writing HC_INITFF to the control ++ * register. After the HBA resets, this function resets all the iocb ring ++ * indices. This function disables PCI layer parity checking during ++ * the reset. ++ * This function returns 0 always. ++ * The caller is not required to hold any locks. ++ **/ + int + lpfc_sli_brdreset(struct lpfc_hba *phba) + { +@@ -2191,6 +2772,19 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) + return 0; + } + ++/** ++ * lpfc_sli_brdrestart: Restart the HBA. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called in the SLI initialization code path to ++ * restart the HBA. The caller is not required to hold any lock. ++ * This function writes MBX_RESTART mailbox command to the SLIM and ++ * resets the HBA. At the end of the function, it calls lpfc_hba_down_post ++ * function to free any pending commands. The function enables ++ * POST only during the first initialization. The function returns zero. ++ * The function does not guarantee completion of MBX_RESTART mailbox ++ * command before the return of this function. ++ **/ + int + lpfc_sli_brdrestart(struct lpfc_hba *phba) + { +@@ -2251,6 +2845,16 @@ lpfc_sli_brdrestart(struct lpfc_hba *phb + return 0; + } + ++/** ++ * lpfc_sli_chipset_init: Wait for the restart of the HBA after a restart. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called after a HBA restart to wait for successful ++ * restart of the HBA. Successful restart of the HBA is indicated by ++ * HS_FFRDY and HS_MBRDY bits. If the HBA fails to restart even after 15 ++ * iteration, the function will restart the HBA again. The function returns ++ * zero if HBA successfully restarted else returns negative error code. ++ **/ + static int + lpfc_sli_chipset_init(struct lpfc_hba *phba) + { +@@ -2336,12 +2940,25 @@ lpfc_sli_chipset_init(struct lpfc_hba *p + return 0; + } + ++/** ++ * lpfc_sli_hbq_count: Get the number of HBQs to be configured. ++ * ++ * This function calculates and returns the number of HBQs required to be ++ * configured. ++ **/ + int + lpfc_sli_hbq_count(void) + { + return ARRAY_SIZE(lpfc_hbq_defs); + } + ++/** ++ * lpfc_sli_hbq_entry_count: Calculate total number of hbq entries. ++ * ++ * This function adds the number of hbq entries in every HBQ to get ++ * the total number of hbq entries required for the HBA and returns ++ * the total count. ++ **/ + static int + lpfc_sli_hbq_entry_count(void) + { +@@ -2354,12 +2971,27 @@ lpfc_sli_hbq_entry_count(void) + return count; + } + ++/** ++ * lpfc_sli_hbq_size: Calculate memory required for all hbq entries. ++ * ++ * This function calculates amount of memory required for all hbq entries ++ * to be configured and returns the total memory required. ++ **/ + int + lpfc_sli_hbq_size(void) + { + return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry); + } + ++/** ++ * lpfc_sli_hbq_setup: configure and initialize HBQs. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called during the SLI initialization to configure ++ * all the HBQs and post buffers to the HBQ. The caller is not ++ * required to hold any locks. This function will return zero if successful ++ * else it will return negative error code. ++ **/ + static int + lpfc_sli_hbq_setup(struct lpfc_hba *phba) + { +@@ -2415,15 +3047,26 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba + mempool_free(pmb, phba->mbox_mem_pool); + + /* Initially populate or replenish the HBQs */ +- for (hbqno = 0; hbqno < hbq_count; ++hbqno) { +- if (lpfc_sli_hbqbuf_init_hbqs(phba, hbqno)) +- return -ENOMEM; +- } ++ for (hbqno = 0; hbqno < hbq_count; ++hbqno) ++ lpfc_sli_hbqbuf_init_hbqs(phba, hbqno); + return 0; + } + +-static int +-lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode) ++/** ++ * lpfc_sli_config_port: Issue config port mailbox command. ++ * @phba: Pointer to HBA context object. ++ * @sli_mode: sli mode - 2/3 ++ * ++ * This function is called by the sli intialization code path ++ * to issue config_port mailbox command. This function restarts the ++ * HBA firmware and issues a config_port mailbox command to configure ++ * the SLI interface in the sli mode specified by sli_mode ++ * variable. The caller is not required to hold any locks. ++ * The function returns 0 if successful, else returns negative error ++ * code. ++ **/ ++int ++lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) + { + LPFC_MBOXQ_t *pmb; + uint32_t resetcount = 0, rc = 0, done = 0; +@@ -2460,13 +3103,15 @@ lpfc_do_config_port(struct lpfc_hba *phb + if (rc == -ERESTART) { + phba->link_state = LPFC_LINK_UNKNOWN; + continue; +- } else if (rc) { ++ } else if (rc) + break; +- } +- + phba->link_state = LPFC_INIT_MBX_CMDS; + lpfc_config_port(phba, pmb); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); ++ phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED | ++ LPFC_SLI3_HBQ_ENABLED | ++ LPFC_SLI3_CRP_ENABLED | ++ LPFC_SLI3_INB_ENABLED); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0442 Adapter failed to init, mbxCmd x%x " +@@ -2476,30 +3121,64 @@ lpfc_do_config_port(struct lpfc_hba *phb + phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + rc = -ENXIO; +- } else { ++ } else + done = 1; +- phba->max_vpi = (phba->max_vpi && +- pmb->mb.un.varCfgPort.gmv) != 0 +- ? pmb->mb.un.varCfgPort.max_vpi +- : 0; +- } + } +- + if (!done) { + rc = -EINVAL; + goto do_prep_failed; + } +- +- if ((pmb->mb.un.varCfgPort.sli_mode == 3) && +- (!pmb->mb.un.varCfgPort.cMA)) { +- rc = -ENXIO; ++ if (pmb->mb.un.varCfgPort.sli_mode == 3) { ++ if (!pmb->mb.un.varCfgPort.cMA) { ++ rc = -ENXIO; ++ goto do_prep_failed; ++ } ++ if (phba->max_vpi && pmb->mb.un.varCfgPort.gmv) { ++ phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; ++ phba->max_vpi = pmb->mb.un.varCfgPort.max_vpi; ++ } else ++ phba->max_vpi = 0; ++ if (pmb->mb.un.varCfgPort.gerbm) ++ phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; ++ if (pmb->mb.un.varCfgPort.gcrp) ++ phba->sli3_options |= LPFC_SLI3_CRP_ENABLED; ++ if (pmb->mb.un.varCfgPort.ginb) { ++ phba->sli3_options |= LPFC_SLI3_INB_ENABLED; ++ phba->port_gp = phba->mbox->us.s3_inb_pgp.port; ++ phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy; ++ phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter; ++ phba->inb_last_counter = ++ phba->mbox->us.s3_inb_pgp.counter; ++ } else { ++ phba->port_gp = phba->mbox->us.s3_pgp.port; ++ phba->inb_ha_copy = NULL; ++ phba->inb_counter = NULL; ++ } ++ } else { ++ phba->port_gp = phba->mbox->us.s2.port; ++ phba->inb_ha_copy = NULL; ++ phba->inb_counter = NULL; ++ phba->max_vpi = 0; + } +- + do_prep_failed: + mempool_free(pmb, phba->mbox_mem_pool); + return rc; + } + ++ ++/** ++ * lpfc_sli_hba_setup: SLI intialization function. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is the main SLI intialization function. This function ++ * is called by the HBA intialization code, HBA reset code and HBA ++ * error attention handler code. Caller is not required to hold any ++ * locks. This function issues config_port mailbox command to configure ++ * the SLI, setup iocb rings and HBQ rings. In the end the function ++ * calls the config_port_post function to issue init_link mailbox ++ * command and to start the discovery. The function will return zero ++ * if successful, else it will return negative error code. ++ **/ + int + lpfc_sli_hba_setup(struct lpfc_hba *phba) + { +@@ -2528,22 +3207,20 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba + break; + } + +- rc = lpfc_do_config_port(phba, mode); ++ rc = lpfc_sli_config_port(phba, mode); ++ + if (rc && lpfc_sli_mode == 3) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, + "1820 Unable to select SLI-3. " + "Not supported by adapter.\n"); + if (rc && mode != 2) +- rc = lpfc_do_config_port(phba, 2); ++ rc = lpfc_sli_config_port(phba, 2); + if (rc) + goto lpfc_sli_hba_setup_error; + + if (phba->sli_rev == 3) { + phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE; + phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE; +- phba->sli3_options |= LPFC_SLI3_ENABLED; +- phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; +- + } else { + phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE; + phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE; +@@ -2558,8 +3235,7 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba + if (rc) + goto lpfc_sli_hba_setup_error; + +- /* Init HBQs */ +- ++ /* Init HBQs */ + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + rc = lpfc_sli_hbq_setup(phba); + if (rc) +@@ -2581,19 +3257,19 @@ lpfc_sli_hba_setup_error: + return rc; + } + +-/*! lpfc_mbox_timeout +- * +- * \pre +- * \post +- * \param hba Pointer to per struct lpfc_hba structure +- * \param l1 Pointer to the driver's mailbox queue. +- * \return +- * void +- * +- * \b Description: ++ ++/** ++ * lpfc_mbox_timeout: Timeout call back function for mbox timer. ++ * @ptr: context object - pointer to hba structure. + * +- * This routine handles mailbox timeout events at timer interrupt context. +- */ ++ * This is the callback function for mailbox timer. The mailbox ++ * timer is armed when a new mailbox command is issued and the timer ++ * is deleted when the mailbox complete. The function is called by ++ * the kernel timer code when a mailbox does not complete within ++ * expected time. This function wakes up the worker thread to ++ * process the mailbox timeout and returns. All the processing is ++ * done by the worker thread function lpfc_mbox_timeout_handler. ++ **/ + void + lpfc_mbox_timeout(unsigned long ptr) + { +@@ -2612,6 +3288,15 @@ lpfc_mbox_timeout(unsigned long ptr) + return; + } + ++ ++/** ++ * lpfc_mbox_timeout_handler: Worker thread function to handle mailbox timeout. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called from worker thread when a mailbox command times out. ++ * The caller is not required to hold any locks. This function will reset the ++ * HBA and recover all the pending commands. ++ **/ + void + lpfc_mbox_timeout_handler(struct lpfc_hba *phba) + { +@@ -2666,6 +3351,32 @@ lpfc_mbox_timeout_handler(struct lpfc_hb + return; + } + ++/** ++ * lpfc_sli_issue_mbox: Issue a mailbox command to firmware. ++ * @phba: Pointer to HBA context object. ++ * @pmbox: Pointer to mailbox object. ++ * @flag: Flag indicating how the mailbox need to be processed. ++ * ++ * This function is called by discovery code and HBA management code ++ * to submit a mailbox command to firmware. This function gets the ++ * hbalock to protect the data structures. ++ * The mailbox command can be submitted in polling mode, in which case ++ * this function will wait in a polling loop for the completion of the ++ * mailbox. ++ * If the mailbox is submitted in no_wait mode (not polling) the ++ * function will submit the command and returns immediately without waiting ++ * for the mailbox completion. The no_wait is supported only when HBA ++ * is in SLI2/SLI3 mode - interrupts are enabled. ++ * The SLI interface allows only one mailbox pending at a time. If the ++ * mailbox is issued in polling mode and there is already a mailbox ++ * pending, then the function will return an error. If the mailbox is issued ++ * in NO_WAIT mode and there is a mailbox pending already, the function ++ * will return MBX_BUSY after queuing the mailbox into mailbox queue. ++ * The sli layer owns the mailbox object until the completion of mailbox ++ * command if this function return MBX_BUSY or MBX_SUCCESS. For all other ++ * return codes the caller owns the mailbox command after the return of ++ * the function. ++ **/ + int + lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) + { +@@ -2676,7 +3387,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + int i; + unsigned long timeout; + unsigned long drvr_flag = 0; +- volatile uint32_t word0, ldata; ++ uint32_t word0, ldata; + void __iomem *to_slim; + int processing_queue = 0; + +@@ -2836,12 +3547,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + /* First copy command data to host SLIM area */ +- lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); ++ lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); + } else { + if (mb->mbxCommand == MBX_CONFIG_PORT) { + /* copy command data into host mbox for cmpl */ +- lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, +- MAILBOX_CMD_SIZE); ++ lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); + } + + /* First copy mbox command data to HBA SLIM, skip past first +@@ -2851,7 +3561,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + MAILBOX_CMD_SIZE - sizeof (uint32_t)); + + /* Next copy over first word, with mbxOwner set */ +- ldata = *((volatile uint32_t *)mb); ++ ldata = *((uint32_t *)mb); + to_slim = phba->MBslimaddr; + writel(ldata, to_slim); + readl(to_slim); /* flush */ +@@ -2883,7 +3593,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + /* First read mbox status word */ +- word0 = *((volatile uint32_t *)&phba->slim2p->mbx); ++ word0 = *((uint32_t *)phba->mbox); + word0 = le32_to_cpu(word0); + } else { + /* First read mbox status word */ +@@ -2922,12 +3632,11 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + /* First copy command data */ +- word0 = *((volatile uint32_t *) +- &phba->slim2p->mbx); ++ word0 = *((uint32_t *)phba->mbox); + word0 = le32_to_cpu(word0); + if (mb->mbxCommand == MBX_CONFIG_PORT) { + MAILBOX_t *slimmb; +- volatile uint32_t slimword0; ++ uint32_t slimword0; + /* Check real SLIM for any errors */ + slimword0 = readl(phba->MBslimaddr); + slimmb = (MAILBOX_t *) & slimword0; +@@ -2948,8 +3657,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + /* copy results back to user */ +- lpfc_sli_pcimem_bcopy(&phba->slim2p->mbx, mb, +- MAILBOX_CMD_SIZE); ++ lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); + } else { + /* First copy command data */ + lpfc_memcpy_from_slim(mb, phba->MBslimaddr, +@@ -2980,9 +3688,16 @@ out_not_finished: + return MBX_NOT_FINISHED; + } + +-/* +- * Caller needs to hold lock. +- */ ++/** ++ * __lpfc_sli_ringtx_put: Add an iocb to the txq. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @piocb: Pointer to address of newly added command iocb. ++ * ++ * This function is called with hbalock held to add a command ++ * iocb to the txq when SLI layer cannot submit the command iocb ++ * to the ring. ++ **/ + static void + __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *piocb) +@@ -2992,6 +3707,23 @@ __lpfc_sli_ringtx_put(struct lpfc_hba *p + pring->txq_cnt++; + } + ++/** ++ * lpfc_sli_next_iocb: Get the next iocb in the txq. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @piocb: Pointer to address of newly added command iocb. ++ * ++ * This function is called with hbalock held before a new ++ * iocb is submitted to the firmware. This function checks ++ * txq to flush the iocbs in txq to Firmware before ++ * submitting new iocbs to the Firmware. ++ * If there are iocbs in the txq which need to be submitted ++ * to firmware, lpfc_sli_next_iocb returns the first element ++ * of the txq after dequeuing it from txq. ++ * If there is no iocb in the txq then the function will return ++ * *piocb and *piocb is set to NULL. Caller needs to check ++ * *piocb to find if there are more commands in the txq. ++ **/ + static struct lpfc_iocbq * + lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq **piocb) +@@ -3007,9 +3739,30 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba + return nextiocb; + } + +-/* +- * Lockless version of lpfc_sli_issue_iocb. +- */ ++/** ++ * __lpfc_sli_issue_iocb: Lockless version of lpfc_sli_issue_iocb. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @piocb: Pointer to command iocb. ++ * @flag: Flag indicating if this command can be put into txq. ++ * ++ * __lpfc_sli_issue_iocb is used by other functions in the driver ++ * to issue an iocb command to the HBA. If the PCI slot is recovering ++ * from error state or if HBA is resetting or if LPFC_STOP_IOCB_EVENT ++ * flag is turned on, the function returns IOCB_ERROR. ++ * When the link is down, this function allows only iocbs for ++ * posting buffers. ++ * This function finds next available slot in the command ring and ++ * posts the command to the available slot and writes the port ++ * attention register to request HBA start processing new iocb. ++ * If there is no slot available in the ring and ++ * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the ++ * txq, otherwise the function returns IOCB_BUSY. ++ * ++ * This function is called with hbalock held. ++ * The function will return success after it successfully submit the ++ * iocb to firmware or after adding to the txq. ++ **/ + static int + __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *piocb, uint32_t flag) +@@ -3052,6 +3805,16 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *p + * can be issued if the link is not up. + */ + switch (piocb->iocb.ulpCommand) { ++ case CMD_GEN_REQUEST64_CR: ++ case CMD_GEN_REQUEST64_CX: ++ if (!(phba->sli.sli_flag & LPFC_MENLO_MAINT) || ++ (piocb->iocb.un.genreq64.w5.hcsw.Rctl != ++ FC_FCP_CMND) || ++ (piocb->iocb.un.genreq64.w5.hcsw.Type != ++ MENLO_TRANSPORT_TYPE)) ++ ++ goto iocb_busy; ++ break; + case CMD_QUE_RING_BUF_CN: + case CMD_QUE_RING_BUF64_CN: + /* +@@ -3106,6 +3869,19 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *p + } + + ++/** ++ * lpfc_sli_issue_iocb: Wrapper function for __lpfc_sli_issue_iocb. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @piocb: Pointer to command iocb. ++ * @flag: Flag indicating if this command can be put into txq. ++ * ++ * lpfc_sli_issue_iocb is a wrapper around __lpfc_sli_issue_iocb ++ * function. This function gets the hbalock and calls ++ * __lpfc_sli_issue_iocb function and will return the error returned ++ * by __lpfc_sli_issue_iocb function. This wrapper is used by ++ * functions which do not hold hbalock. ++ **/ + int + lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *piocb, uint32_t flag) +@@ -3120,6 +3896,17 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phb + return rc; + } + ++/** ++ * lpfc_extra_ring_setup: Extra ring setup function. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function is called while driver attaches with the ++ * HBA to setup the extra ring. The extra ring is used ++ * only when driver needs to support target mode functionality ++ * or IP over FC functionalities. ++ * ++ * This function is called with no lock held. ++ **/ + static int + lpfc_extra_ring_setup( struct lpfc_hba *phba) + { +@@ -3155,6 +3942,19 @@ lpfc_extra_ring_setup( struct lpfc_hba * + return 0; + } + ++/** ++ * lpfc_sli_async_event_handler: ASYNC iocb handler function. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @iocbq: Pointer to iocb object. ++ * ++ * This function is called by the slow ring event handler ++ * function when there is an ASYNC event iocb in the ring. ++ * This function is called with no lock held. ++ * Currently this function handles only temperature related ++ * ASYNC events. The function decodes the temperature sensor ++ * event message and posts events for the management applications. ++ **/ + static void + lpfc_sli_async_event_handler(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq) +@@ -3210,6 +4010,17 @@ lpfc_sli_async_event_handler(struct lpfc + } + + ++/** ++ * lpfc_sli_setup: SLI ring setup function. ++ * @phba: Pointer to HBA context object. ++ * ++ * lpfc_sli_setup sets up rings of the SLI interface with ++ * number of iocbs per ring and iotags. This function is ++ * called while driver attach to the HBA and before the ++ * interrupts are enabled. So there is no need for locking. ++ * ++ * This function always returns 0. ++ **/ + int + lpfc_sli_setup(struct lpfc_hba *phba) + { +@@ -3321,6 +4132,17 @@ lpfc_sli_setup(struct lpfc_hba *phba) + return 0; + } + ++/** ++ * lpfc_sli_queue_setup: Queue initialization function. ++ * @phba: Pointer to HBA context object. ++ * ++ * lpfc_sli_queue_setup sets up mailbox queues and iocb queues for each ++ * ring. This function also initializes ring indices of each ring. ++ * This function is called during the initialization of the SLI ++ * interface of an HBA. ++ * This function is called with no lock held and always returns ++ * 1. ++ **/ + int + lpfc_sli_queue_setup(struct lpfc_hba *phba) + { +@@ -3349,6 +4171,23 @@ lpfc_sli_queue_setup(struct lpfc_hba *ph + return 1; + } + ++/** ++ * lpfc_sli_host_down: Vport cleanup function. ++ * @vport: Pointer to virtual port object. ++ * ++ * lpfc_sli_host_down is called to clean up the resources ++ * associated with a vport before destroying virtual ++ * port data structures. ++ * This function does following operations: ++ * - Free discovery resources associated with this virtual ++ * port. ++ * - Free iocbs associated with this virtual port in ++ * the txq. ++ * - Send abort for all iocb commands associated with this ++ * vport in txcmplq. ++ * ++ * This function is called with no lock held and always returns 1. ++ **/ + int + lpfc_sli_host_down(struct lpfc_vport *vport) + { +@@ -3411,6 +4250,21 @@ lpfc_sli_host_down(struct lpfc_vport *vp + return 1; + } + ++/** ++ * lpfc_sli_hba_down: Resource cleanup function for the HBA. ++ * @phba: Pointer to HBA context object. ++ * ++ * This function cleans up all iocb, buffers, mailbox commands ++ * while shutting down the HBA. This function is called with no ++ * lock held and always returns 1. ++ * This function does the following to cleanup driver resources: ++ * - Free discovery resources for each virtual port ++ * - Cleanup any pending fabric iocbs ++ * - Iterate through the iocb txq and free each entry ++ * in the list. ++ * - Free up any buffer posted to the HBA ++ * - Free mailbox commands in the mailbox queue. ++ **/ + int + lpfc_sli_hba_down(struct lpfc_hba *phba) + { +@@ -3501,6 +4355,18 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) + return 1; + } + ++/** ++ * lpfc_sli_pcimem_bcopy: SLI memory copy function. ++ * @srcp: Source memory pointer. ++ * @destp: Destination memory pointer. ++ * @cnt: Number of words required to be copied. ++ * ++ * This function is used for copying data between driver memory ++ * and the SLI memory. This function also changes the endianness ++ * of each word if native endianness is different from SLI ++ * endianness. This function can be called with or without ++ * lock. ++ **/ + void + lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt) + { +@@ -3518,6 +4384,17 @@ lpfc_sli_pcimem_bcopy(void *srcp, void * + } + } + ++ ++/** ++ * lpfc_sli_ringpostbuf_put: Function to add a buffer to postbufq. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @mp: Pointer to driver buffer object. ++ * ++ * This function is called with no lock held. ++ * It always return zero after adding the buffer to the postbufq ++ * buffer list. ++ **/ + int + lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_dmabuf *mp) +@@ -3531,6 +4408,18 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba + return 0; + } + ++/** ++ * lpfc_sli_get_buffer_tag: Tag allocation function for a buffer posted ++ * using CMD_QUE_XRI64_CX iocb. ++ * @phba: Pointer to HBA context object. ++ * ++ * When HBQ is enabled, buffers are searched based on tags. This function ++ * allocates a tag for buffer posted using CMD_QUE_XRI64_CX iocb. The ++ * tag is bit wise or-ed with QUE_BUFTAG_BIT to make sure that the tag ++ * does not conflict with tags of buffer posted for unsolicited events. ++ * The function returns the allocated tag. The function is called with ++ * no locks held. ++ **/ + uint32_t + lpfc_sli_get_buffer_tag(struct lpfc_hba *phba) + { +@@ -3545,6 +4434,22 @@ lpfc_sli_get_buffer_tag(struct lpfc_hba + return phba->buffer_tag_count; + } + ++/** ++ * lpfc_sli_ring_taggedbuf_get: Search HBQ buffer associated with ++ * posted using CMD_QUE_XRI64_CX iocb. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @tag: Buffer tag. ++ * ++ * Buffers posted using CMD_QUE_XRI64_CX iocb are in pring->postbufq ++ * list. After HBA DMA data to these buffers, CMD_IOCB_RET_XRI64_CX ++ * iocb is posted to the response ring with the tag of the buffer. ++ * This function searches the pring->postbufq list using the tag ++ * to find buffer associated with CMD_IOCB_RET_XRI64_CX ++ * iocb. If the buffer is found then lpfc_dmabuf object of the ++ * buffer is returned to the caller else NULL is returned. ++ * This function is called with no lock held. ++ **/ + struct lpfc_dmabuf * + lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + uint32_t tag) +@@ -3565,7 +4470,7 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_ + + spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0410 Cannot find virtual addr for buffer tag on " ++ "0402 Cannot find virtual addr for buffer tag on " + "ring %d Data x%lx x%p x%p x%x\n", + pring->ringno, (unsigned long) tag, + slp->next, slp->prev, pring->postbufq_cnt); +@@ -3573,6 +4478,23 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_ + return NULL; + } + ++/** ++ * lpfc_sli_ringpostbuf_get: SLI2 buffer search function for ++ * unsolicited ct and els events. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @phys: DMA address of the buffer. ++ * ++ * This function searches the buffer list using the dma_address ++ * of unsolicited event to find the driver's lpfc_dmabuf object ++ * corresponding to the dma_address. The function returns the ++ * lpfc_dmabuf object if a buffer is found else it returns NULL. ++ * This function is called by the ct and els unsolicited event ++ * handlers to get the buffer associated with the unsolicited ++ * event. ++ * ++ * This function is called with no lock held. ++ **/ + struct lpfc_dmabuf * + lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + dma_addr_t phys) +@@ -3600,6 +4522,17 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba + return NULL; + } + ++/** ++ * lpfc_sli_abort_els_cmpl: Completion handler for the els abort iocbs. ++ * @phba: Pointer to HBA context object. ++ * @cmdiocb: Pointer to driver command iocb object. ++ * @rspiocb: Pointer to driver response iocb object. ++ * ++ * This function is the completion handler for the abort iocbs for ++ * ELS commands. This function is called from the ELS ring event ++ * handler with no lock held. This function frees memory resources ++ * associated with the abort iocb. ++ **/ + static void + lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -3665,6 +4598,17 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba + return; + } + ++/** ++ * lpfc_ignore_els_cmpl: Completion handler for aborted ELS command. ++ * @phba: Pointer to HBA context object. ++ * @cmdiocb: Pointer to driver command iocb object. ++ * @rspiocb: Pointer to driver response iocb object. ++ * ++ * The function is called from SLI ring event handler with no ++ * lock held. This function is the completion handler for ELS commands ++ * which are aborted. The function frees memory resources used for ++ * the aborted ELS commands. ++ **/ + static void + lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -3673,7 +4617,7 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *ph + + /* ELS cmd tag completes */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, +- "0133 Ignoring ELS cmd tag x%x completion Data: " ++ "0139 Ignoring ELS cmd tag x%x completion Data: " + "x%x x%x x%x\n", + irsp->ulpIoTag, irsp->ulpStatus, + irsp->un.ulpWord[4], irsp->ulpTimeout); +@@ -3684,6 +4628,17 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *ph + return; + } + ++/** ++ * lpfc_sli_issue_abort_iotag: Abort function for a command iocb. ++ * @phba: Pointer to HBA context object. ++ * @pring: Pointer to driver SLI ring object. ++ * @cmdiocb: Pointer to driver command iocb object. ++ * ++ * This function issues an abort iocb for the provided command ++ * iocb. This function is called with hbalock held. ++ * The function returns 0 when it fails due to memory allocation ++ * failure or when the command iocb is an abort request. ++ **/ + int + lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + struct lpfc_iocbq *cmdiocb) +@@ -3748,6 +4703,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_h + iabt->un.acxri.abortIoTag, abtsiocbp->iotag); + retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0); + ++ if (retval) ++ __lpfc_sli_release_iocbq(phba, abtsiocbp); + abort_iotag_exit: + /* + * Caller to this routine should check for IOCB_ERROR +@@ -3757,6 +4714,29 @@ abort_iotag_exit: + return retval; + } + ++/** ++ * lpfc_sli_validate_fcp_iocb: Filtering function, used to find commands ++ * associated with a vport/SCSI target/lun. ++ * @iocbq: Pointer to driver iocb object. ++ * @vport: Pointer to driver virtual port object. ++ * @tgt_id: SCSI ID of the target. ++ * @lun_id: LUN ID of the scsi device. ++ * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST ++ * ++ * This function acts as iocb filter for functions which abort or count ++ * all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return ++ * 0 if the filtering criteria is met for the given iocb and will return ++ * 1 if the filtering criteria is not met. ++ * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the ++ * given iocb is for the SCSI device specified by vport, tgt_id and ++ * lun_id parameter. ++ * If ctx_cmd == LPFC_CTX_TGT, the function returns 0 only if the ++ * given iocb is for the SCSI target specified by vport and tgt_id ++ * parameters. ++ * If ctx_cmd == LPFC_CTX_HOST, the function returns 0 only if the ++ * given iocb is for the SCSI host associated with the given vport. ++ * This function is called with no locks held. ++ **/ + static int + lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, + uint16_t tgt_id, uint64_t lun_id, +@@ -3800,6 +4780,25 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_i + return rc; + } + ++/** ++ * lpfc_sli_sum_iocb: Function to count the number of FCP iocbs pending. ++ * @vport: Pointer to virtual port. ++ * @tgt_id: SCSI ID of the target. ++ * @lun_id: LUN ID of the scsi device. ++ * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. ++ * ++ * This function returns number of FCP commands pending for the vport. ++ * When ctx_cmd == LPFC_CTX_LUN, the function returns number of FCP ++ * commands pending on the vport associated with SCSI device specified ++ * by tgt_id and lun_id parameters. ++ * When ctx_cmd == LPFC_CTX_TGT, the function returns number of FCP ++ * commands pending on the vport associated with SCSI target specified ++ * by tgt_id parameter. ++ * When ctx_cmd == LPFC_CTX_HOST, the function returns number of FCP ++ * commands pending on the vport. ++ * This function returns the number of iocbs which satisfy the filter. ++ * This function is called without any lock held. ++ **/ + int + lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, + lpfc_ctx_cmd ctx_cmd) +@@ -3819,6 +4818,17 @@ lpfc_sli_sum_iocb(struct lpfc_vport *vpo + return sum; + } + ++/** ++ * lpfc_sli_abort_fcp_cmpl: Completion handler function for an aborted ++ * FCP iocb. ++ * @phba: Pointer to HBA context object ++ * @cmdiocb: Pointer to command iocb object. ++ * @rspiocb: Pointer to response iocb object. ++ * ++ * This function is called when an aborted FCP iocb completes. This ++ * function is called by the ring event handler with no lock held. ++ * This function frees the iocb. ++ **/ + void + lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +@@ -3827,6 +4837,28 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba + return; + } + ++/** ++ * lpfc_sli_abort_iocb: This function issue abort for all SCSI commands ++ * pending on a SCSI host(vport)/target/lun. ++ * @vport: Pointer to virtual port. ++ * @pring: Pointer to driver SLI ring object. ++ * @tgt_id: SCSI ID of the target. ++ * @lun_id: LUN ID of the scsi device. ++ * @abort_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. ++ * ++ * This function sends an abort command for every SCSI command ++ * associated with the given virtual port pending on the ring ++ * filtered by lpfc_sli_validate_fcp_iocb function. ++ * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the ++ * FCP iocbs associated with lun specified by tgt_id and lun_id ++ * parameters ++ * When abort_cmd == LPFC_CTX_TGT, the function sends abort only to the ++ * FCP iocbs associated with SCSI target specified by tgt_id parameter. ++ * When abort_cmd == LPFC_CTX_HOST, the function sends abort to all ++ * FCP iocbs associated with virtual port. ++ * This function returns number of iocbs it failed to abort. ++ * This function is called with no locks held. ++ **/ + int + lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, + uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd abort_cmd) +@@ -3878,6 +4910,24 @@ lpfc_sli_abort_iocb(struct lpfc_vport *v + return errcnt; + } + ++/** ++ * lpfc_sli_wake_iocb_wait: iocb completion handler for iocb issued using ++ * lpfc_sli_issue_iocb_wait. ++ * @phba: Pointer to HBA context object. ++ * @cmdiocbq: Pointer to command iocb. ++ * @rspiocbq: Pointer to response iocb. ++ * ++ * This function is the completion handler for iocbs issued using ++ * lpfc_sli_issue_iocb_wait function. This function is called by the ++ * ring event handler function without any lock held. This function ++ * can be called from both worker thread context and interrupt ++ * context. This function also can be called from other thread which ++ * cleans up the SLI layer objects. ++ * This function copy the contents of the response iocb to the ++ * response iocb memory object provided by the caller of ++ * lpfc_sli_issue_iocb_wait and then wakes up the thread which ++ * sleeps for the iocb completion. ++ **/ + static void + lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, +@@ -3899,13 +4949,36 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba + return; + } + +-/* +- * Issue the caller's iocb and wait for its completion, but no longer than the +- * caller's timeout. Note that iocb_flags is cleared before the +- * lpfc_sli_issue_call since the wake routine sets a unique value and by +- * definition this is a wait function. +- */ +- ++/** ++ * lpfc_sli_issue_iocb_wait: Synchronous function to issue iocb commands. ++ * @phba: Pointer to HBA context object.. ++ * @pring: Pointer to sli ring. ++ * @piocb: Pointer to command iocb. ++ * @prspiocbq: Pointer to response iocb. ++ * @timeout: Timeout in number of seconds. ++ * ++ * This function issues the iocb to firmware and waits for the ++ * iocb to complete. If the iocb command is not ++ * completed within timeout seconds, it returns IOCB_TIMEDOUT. ++ * Caller should not free the iocb resources if this function ++ * returns IOCB_TIMEDOUT. ++ * The function waits for the iocb completion using an ++ * non-interruptible wait. ++ * This function will sleep while waiting for iocb completion. ++ * So, this function should not be called from any context which ++ * does not allow sleeping. Due to the same reason, this function ++ * cannot be called with interrupt disabled. ++ * This function assumes that the iocb completions occur while ++ * this function sleep. So, this function cannot be called from ++ * the thread which process iocb completion for this ring. ++ * This function clears the iocb_flag of the iocb object before ++ * issuing the iocb and the iocb completion handler sets this ++ * flag and wakes this thread when the iocb completes. ++ * The contents of the response iocb will be copied to prspiocbq ++ * by the completion handler when the command completes. ++ * This function returns IOCB_SUCCESS when success. ++ * This function is called with no lock held. ++ **/ + int + lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, +@@ -3963,7 +5036,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba + } + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, +- ":0332 IOCB wait issue failed, Data x%x\n", ++ "0332 IOCB wait issue failed, Data x%x\n", + retval); + retval = IOCB_ERROR; + } +@@ -3983,6 +5056,32 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba + return retval; + } + ++/** ++ * lpfc_sli_issue_mbox_wait: Synchronous function to issue mailbox. ++ * @phba: Pointer to HBA context object. ++ * @pmboxq: Pointer to driver mailbox object. ++ * @timeout: Timeout in number of seconds. ++ * ++ * This function issues the mailbox to firmware and waits for the ++ * mailbox command to complete. If the mailbox command is not ++ * completed within timeout seconds, it returns MBX_TIMEOUT. ++ * The function waits for the mailbox completion using an ++ * interruptible wait. If the thread is woken up due to a ++ * signal, MBX_TIMEOUT error is returned to the caller. Caller ++ * should not free the mailbox resources, if this function returns ++ * MBX_TIMEOUT. ++ * This function will sleep while waiting for mailbox completion. ++ * So, this function should not be called from any context which ++ * does not allow sleeping. Due to the same reason, this function ++ * cannot be called with interrupt disabled. ++ * This function assumes that the mailbox completion occurs while ++ * this function sleep. So, this function cannot be called from ++ * the worker thread which processes mailbox completion. ++ * This function is called in the context of HBA management ++ * applications. ++ * This function returns MBX_SUCCESS when successful. ++ * This function is called with no lock held. ++ **/ + int + lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, + uint32_t timeout) +@@ -4027,6 +5126,18 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba + return retval; + } + ++/** ++ * lpfc_sli_flush_mbox_queue: mailbox queue cleanup function. ++ * @phba: Pointer to HBA context. ++ * ++ * This function is called to cleanup any pending mailbox ++ * objects in the driver queue before bringing the HBA offline. ++ * This function is called while resetting the HBA. ++ * The function is called without any lock held. The function ++ * takes hbalock to update SLI data structure. ++ * This function returns 1 when there is an active mailbox ++ * command pending else returns 0. ++ **/ + int + lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba) + { +@@ -4058,8 +5169,74 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hb + return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0; + } + ++/** ++ * lpfc_sli_check_eratt: check error attention events ++ * @phba: Pointer to HBA context. ++ * ++ * This function is called form timer soft interrupt context to check HBA's ++ * error attention register bit for error attention events. ++ * ++ * This fucntion returns 1 when there is Error Attention in the Host Attention ++ * Register and returns 0 otherwise. ++ **/ ++int ++lpfc_sli_check_eratt(struct lpfc_hba *phba) ++{ ++ uint32_t ha_copy; ++ ++ /* If somebody is waiting to handle an eratt, don't process it ++ * here. The brdkill function will do this. ++ */ ++ if (phba->link_flag & LS_IGNORE_ERATT) ++ return 0; ++ ++ /* Check if interrupt handler handles this ERATT */ ++ spin_lock_irq(&phba->hbalock); ++ if (phba->hba_flag & HBA_ERATT_HANDLED) { ++ /* Interrupt handler has handled ERATT */ ++ spin_unlock_irq(&phba->hbalock); ++ return 0; ++ } ++ ++ /* Read chip Host Attention (HA) register */ ++ ha_copy = readl(phba->HAregaddr); ++ if (ha_copy & HA_ERATT) { ++ /* Read host status register to retrieve error event */ ++ lpfc_sli_read_hs(phba); ++ /* Set the driver HA work bitmap */ ++ phba->work_ha |= HA_ERATT; ++ /* Indicate polling handles this ERATT */ ++ phba->hba_flag |= HBA_ERATT_HANDLED; ++ spin_unlock_irq(&phba->hbalock); ++ return 1; ++ } ++ spin_unlock_irq(&phba->hbalock); ++ return 0; ++} ++ ++/** ++ * lpfc_sp_intr_handler: The slow-path interrupt handler of lpfc driver. ++ * @irq: Interrupt number. ++ * @dev_id: The device context pointer. ++ * ++ * This function is directly called from the PCI layer as an interrupt ++ * service routine when the device is enabled with MSI-X multi-message ++ * interrupt mode and there are slow-path events in the HBA. However, ++ * when the device is enabled with either MSI or Pin-IRQ interrupt mode, ++ * this function is called as part of the device-level interrupt handler. ++ * When the PCI slot is in error recovery or the HBA is undergoing ++ * initialization, the interrupt handler will not process the interrupt. ++ * The link attention and ELS ring attention events are handled by the ++ * worker thread. The interrupt handler signals the worker thread and ++ * and returns for these events. This function is called without any ++ * lock held. It gets the hbalock to access and update SLI data ++ * structures. ++ * ++ * This function returns IRQ_HANDLED when interrupt is handled else it ++ * returns IRQ_NONE. ++ **/ + irqreturn_t +-lpfc_intr_handler(int irq, void *dev_id) ++lpfc_sp_intr_handler(int irq, void *dev_id) + { + struct lpfc_hba *phba; + uint32_t ha_copy; +@@ -4078,48 +5255,52 @@ lpfc_intr_handler(int irq, void *dev_id) + * Get the driver's phba structure from the dev_id and + * assume the HBA is not interrupting. + */ +- phba = (struct lpfc_hba *) dev_id; ++ phba = (struct lpfc_hba *)dev_id; + + if (unlikely(!phba)) + return IRQ_NONE; + +- /* If the pci channel is offline, ignore all the interrupts. */ +- if (unlikely(pci_channel_offline(phba->pcidev))) +- return IRQ_NONE; +- +- phba->sli.slistat.sli_intr++; +- + /* +- * Call the HBA to see if it is interrupting. If not, don't claim +- * the interrupt +- */ +- +- /* Ignore all interrupts during initialization. */ +- if (unlikely(phba->link_state < LPFC_LINK_DOWN)) +- return IRQ_NONE; +- +- /* +- * Read host attention register to determine interrupt source +- * Clear Attention Sources, except Error Attention (to +- * preserve status) and Link Attention +- */ +- spin_lock(&phba->hbalock); +- ha_copy = readl(phba->HAregaddr); +- /* If somebody is waiting to handle an eratt don't process it +- * here. The brdkill function will do this. ++ * Stuff needs to be attented to when this function is invoked as an ++ * individual interrupt handler in MSI-X multi-message interrupt mode + */ +- if (phba->link_flag & LS_IGNORE_ERATT) +- ha_copy &= ~HA_ERATT; +- writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); +- readl(phba->HAregaddr); /* flush */ +- spin_unlock(&phba->hbalock); +- +- if (unlikely(!ha_copy)) +- return IRQ_NONE; ++ if (phba->intr_type == MSIX) { ++ /* If the pci channel is offline, ignore all the interrupts */ ++ if (unlikely(pci_channel_offline(phba->pcidev))) ++ return IRQ_NONE; ++ /* Update device-level interrupt statistics */ ++ phba->sli.slistat.sli_intr++; ++ /* Ignore all interrupts during initialization. */ ++ if (unlikely(phba->link_state < LPFC_LINK_DOWN)) ++ return IRQ_NONE; ++ /* Need to read HA REG for slow-path events */ ++ spin_lock(&phba->hbalock); ++ ha_copy = readl(phba->HAregaddr); ++ /* If somebody is waiting to handle an eratt don't process it ++ * here. The brdkill function will do this. ++ */ ++ if (phba->link_flag & LS_IGNORE_ERATT) ++ ha_copy &= ~HA_ERATT; ++ /* Check the need for handling ERATT in interrupt handler */ ++ if (ha_copy & HA_ERATT) { ++ if (phba->hba_flag & HBA_ERATT_HANDLED) ++ /* ERATT polling has handled ERATT */ ++ ha_copy &= ~HA_ERATT; ++ else ++ /* Indicate interrupt handler handles ERATT */ ++ phba->hba_flag |= HBA_ERATT_HANDLED; ++ } ++ /* Clear up only attention source related to slow-path */ ++ writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)), ++ phba->HAregaddr); ++ readl(phba->HAregaddr); /* flush */ ++ spin_unlock(&phba->hbalock); ++ } else ++ ha_copy = phba->ha_copy; + + work_ha_copy = ha_copy & phba->work_ha_mask; + +- if (unlikely(work_ha_copy)) { ++ if (work_ha_copy) { + if (work_ha_copy & HA_LATT) { + if (phba->sli.sli_flag & LPFC_PROCESS_LA) { + /* +@@ -4138,7 +5319,7 @@ lpfc_intr_handler(int irq, void *dev_id) + work_ha_copy &= ~HA_LATT; + } + +- if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) { ++ if (work_ha_copy & ~(HA_ERATT | HA_MBATT | HA_LATT)) { + /* + * Turn off Slow Rings interrupts, LPFC_ELS_RING is + * the only slow ring. +@@ -4179,31 +5360,13 @@ lpfc_intr_handler(int irq, void *dev_id) + spin_unlock(&phba->hbalock); + } + } +- +- if (work_ha_copy & HA_ERATT) { +- /* +- * There was a link/board error. Read the +- * status register to retrieve the error event +- * and process it. +- */ +- phba->sli.slistat.err_attn_event++; +- /* Save status info */ +- phba->work_hs = readl(phba->HSregaddr); +- phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); +- phba->work_status[1] = readl(phba->MBslimaddr + 0xac); +- +- /* Clear Chip error bit */ +- writel(HA_ERATT, phba->HAregaddr); +- readl(phba->HAregaddr); /* flush */ +- phba->pport->stopped = 1; +- } +- + spin_lock(&phba->hbalock); +- if ((work_ha_copy & HA_MBATT) && +- (phba->sli.mbox_active)) { ++ if (work_ha_copy & HA_ERATT) ++ lpfc_sli_read_hs(phba); ++ if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { + pmb = phba->sli.mbox_active; + pmbox = &pmb->mb; +- mbox = &phba->slim2p->mbx; ++ mbox = phba->mbox; + vport = pmb->vport; + + /* First check out the status word */ +@@ -4270,7 +5433,7 @@ lpfc_intr_handler(int irq, void *dev_id) + lpfc_printf_log(phba, + KERN_ERR, + LOG_MBOX | LOG_SLI, +- "0306 rc should have" ++ "0350 rc should have" + "been MBX_BUSY"); + goto send_current_mbox; + } +@@ -4283,6 +5446,7 @@ lpfc_intr_handler(int irq, void *dev_id) + } + } else + spin_unlock(&phba->hbalock); ++ + if ((work_ha_copy & HA_MBATT) && + (phba->sli.mbox_active == NULL)) { + send_current_mbox: +@@ -4302,15 +5466,74 @@ send_current_mbox: + spin_unlock(&phba->hbalock); + lpfc_worker_wake_up(phba); + } ++ return IRQ_HANDLED; + +- ha_copy &= ~(phba->work_ha_mask); ++} /* lpfc_sp_intr_handler */ ++ ++/** ++ * lpfc_fp_intr_handler: The fast-path interrupt handler of lpfc driver. ++ * @irq: Interrupt number. ++ * @dev_id: The device context pointer. ++ * ++ * This function is directly called from the PCI layer as an interrupt ++ * service routine when the device is enabled with MSI-X multi-message ++ * interrupt mode and there is a fast-path FCP IOCB ring event in the ++ * HBA. However, when the device is enabled with either MSI or Pin-IRQ ++ * interrupt mode, this function is called as part of the device-level ++ * interrupt handler. When the PCI slot is in error recovery or the HBA ++ * is undergoing initialization, the interrupt handler will not process ++ * the interrupt. The SCSI FCP fast-path ring event are handled in the ++ * intrrupt context. This function is called without any lock held. It ++ * gets the hbalock to access and update SLI data structures. ++ * ++ * This function returns IRQ_HANDLED when interrupt is handled else it ++ * returns IRQ_NONE. ++ **/ ++irqreturn_t ++lpfc_fp_intr_handler(int irq, void *dev_id) ++{ ++ struct lpfc_hba *phba; ++ uint32_t ha_copy; ++ unsigned long status; ++ ++ /* Get the driver's phba structure from the dev_id and ++ * assume the HBA is not interrupting. ++ */ ++ phba = (struct lpfc_hba *) dev_id; ++ ++ if (unlikely(!phba)) ++ return IRQ_NONE; ++ ++ /* ++ * Stuff needs to be attented to when this function is invoked as an ++ * individual interrupt handler in MSI-X multi-message interrupt mode ++ */ ++ if (phba->intr_type == MSIX) { ++ /* If pci channel is offline, ignore all the interrupts */ ++ if (unlikely(pci_channel_offline(phba->pcidev))) ++ return IRQ_NONE; ++ /* Update device-level interrupt statistics */ ++ phba->sli.slistat.sli_intr++; ++ /* Ignore all interrupts during initialization. */ ++ if (unlikely(phba->link_state < LPFC_LINK_DOWN)) ++ return IRQ_NONE; ++ /* Need to read HA REG for FCP ring and other ring events */ ++ ha_copy = readl(phba->HAregaddr); ++ /* Clear up only attention source related to fast-path */ ++ spin_lock(&phba->hbalock); ++ writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)), ++ phba->HAregaddr); ++ readl(phba->HAregaddr); /* flush */ ++ spin_unlock(&phba->hbalock); ++ } else ++ ha_copy = phba->ha_copy; + + /* +- * Process all events on FCP ring. Take the optimized path for +- * FCP IO. Any other IO is slow path and is handled by +- * the worker thread. ++ * Process all events on FCP ring. Take the optimized path for FCP IO. + */ +- status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); ++ ha_copy &= ~(phba->work_ha_mask); ++ ++ status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); + status >>= (4*LPFC_FCP_RING); + if (status & HA_RXMASK) + lpfc_sli_handle_fast_ring_event(phba, +@@ -4319,11 +5542,10 @@ send_current_mbox: + + if (phba->cfg_multi_ring_support == 2) { + /* +- * Process all events on extra ring. Take the optimized path +- * for extra ring IO. Any other IO is slow path and is handled +- * by the worker thread. ++ * Process all events on extra ring. Take the optimized path ++ * for extra ring IO. + */ +- status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); ++ status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); + status >>= (4*LPFC_EXTRA_RING); + if (status & HA_RXMASK) { + lpfc_sli_handle_fast_ring_event(phba, +@@ -4332,5 +5554,106 @@ send_current_mbox: + } + } + return IRQ_HANDLED; ++} /* lpfc_fp_intr_handler */ ++ ++/** ++ * lpfc_intr_handler: The device-level interrupt handler of lpfc driver. ++ * @irq: Interrupt number. ++ * @dev_id: The device context pointer. ++ * ++ * This function is the device-level interrupt handler called from the PCI ++ * layer when either MSI or Pin-IRQ interrupt mode is enabled and there is ++ * an event in the HBA which requires driver attention. This function ++ * invokes the slow-path interrupt attention handling function and fast-path ++ * interrupt attention handling function in turn to process the relevant ++ * HBA attention events. This function is called without any lock held. It ++ * gets the hbalock to access and update SLI data structures. ++ * ++ * This function returns IRQ_HANDLED when interrupt is handled, else it ++ * returns IRQ_NONE. ++ **/ ++irqreturn_t ++lpfc_intr_handler(int irq, void *dev_id) ++{ ++ struct lpfc_hba *phba; ++ irqreturn_t sp_irq_rc, fp_irq_rc; ++ unsigned long status1, status2; ++ ++ /* ++ * Get the driver's phba structure from the dev_id and ++ * assume the HBA is not interrupting. ++ */ ++ phba = (struct lpfc_hba *) dev_id; ++ ++ if (unlikely(!phba)) ++ return IRQ_NONE; ++ ++ /* If the pci channel is offline, ignore all the interrupts. */ ++ if (unlikely(pci_channel_offline(phba->pcidev))) ++ return IRQ_NONE; ++ ++ /* Update device level interrupt statistics */ ++ phba->sli.slistat.sli_intr++; ++ ++ /* Ignore all interrupts during initialization. */ ++ if (unlikely(phba->link_state < LPFC_LINK_DOWN)) ++ return IRQ_NONE; ++ ++ spin_lock(&phba->hbalock); ++ phba->ha_copy = readl(phba->HAregaddr); ++ if (unlikely(!phba->ha_copy)) { ++ spin_unlock(&phba->hbalock); ++ return IRQ_NONE; ++ } else if (phba->ha_copy & HA_ERATT) { ++ if (phba->hba_flag & HBA_ERATT_HANDLED) ++ /* ERATT polling has handled ERATT */ ++ phba->ha_copy &= ~HA_ERATT; ++ else ++ /* Indicate interrupt handler handles ERATT */ ++ phba->hba_flag |= HBA_ERATT_HANDLED; ++ } ++ ++ /* Clear attention sources except link and error attentions */ ++ writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); ++ readl(phba->HAregaddr); /* flush */ ++ spin_unlock(&phba->hbalock); ++ ++ /* ++ * Invokes slow-path host attention interrupt handling as appropriate. ++ */ ++ ++ /* status of events with mailbox and link attention */ ++ status1 = phba->ha_copy & (HA_MBATT | HA_LATT | HA_ERATT); ++ ++ /* status of events with ELS ring */ ++ status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); ++ status2 >>= (4*LPFC_ELS_RING); ++ ++ if (status1 || (status2 & HA_RXMASK)) ++ sp_irq_rc = lpfc_sp_intr_handler(irq, dev_id); ++ else ++ sp_irq_rc = IRQ_NONE; ++ ++ /* ++ * Invoke fast-path host attention interrupt handling as appropriate. ++ */ ++ ++ /* status of events with FCP ring */ ++ status1 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); ++ status1 >>= (4*LPFC_FCP_RING); ++ ++ /* status of events with extra ring */ ++ if (phba->cfg_multi_ring_support == 2) { ++ status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); ++ status2 >>= (4*LPFC_EXTRA_RING); ++ } else ++ status2 = 0; ++ ++ if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK)) ++ fp_irq_rc = lpfc_fp_intr_handler(irq, dev_id); ++ else ++ fp_irq_rc = IRQ_NONE; + +-} /* lpfc_intr_handler */ ++ /* Return device-level interrupt handling status */ ++ return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc; ++} /* lpfc_intr_handler */ +--- a/drivers/scsi/lpfc/lpfc_sli.h ++++ b/drivers/scsi/lpfc/lpfc_sli.h +@@ -233,6 +233,7 @@ struct lpfc_sli { + #define LPFC_SLI2_ACTIVE 0x200 /* SLI2 overlay in firmware is active */ + #define LPFC_PROCESS_LA 0x400 /* Able to process link attention */ + #define LPFC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */ ++#define LPFC_MENLO_MAINT 0x1000 /* need for menl fw download */ + + struct lpfc_sli_ring ring[LPFC_MAX_RING]; + int fcp_ring; /* ring used for FCP initiator commands */ +--- a/drivers/scsi/lpfc/lpfc_version.h ++++ b/drivers/scsi/lpfc/lpfc_version.h +@@ -18,9 +18,11 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.7" ++#define LPFC_DRIVER_VERSION "8.2.8" + +-#define LPFC_DRIVER_NAME "lpfc" ++#define LPFC_DRIVER_NAME "lpfc" ++#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" ++#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" + + #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ + LPFC_DRIVER_VERSION +--- a/drivers/scsi/lpfc/lpfc_vport.c ++++ b/drivers/scsi/lpfc/lpfc_vport.c +@@ -34,6 +34,7 @@ + #include + #include "lpfc_hw.h" + #include "lpfc_sli.h" ++#include "lpfc_nl.h" + #include "lpfc_disc.h" + #include "lpfc_scsi.h" + #include "lpfc.h" +@@ -204,6 +205,77 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, + return 1; + } + ++/** ++ * lpfc_discovery_wait: Wait for driver discovery to quiesce. ++ * @vport: The virtual port for which this call is being executed. ++ * ++ * This driver calls this routine specifically from lpfc_vport_delete ++ * to enforce a synchronous execution of vport ++ * delete relative to discovery activities. The ++ * lpfc_vport_delete routine should not return until it ++ * can reasonably guarantee that discovery has quiesced. ++ * Post FDISC LOGO, the driver must wait until its SAN teardown is ++ * complete and all resources recovered before allowing ++ * cleanup. ++ * ++ * This routine does not require any locks held. ++ **/ ++static void lpfc_discovery_wait(struct lpfc_vport *vport) ++{ ++ struct lpfc_hba *phba = vport->phba; ++ uint32_t wait_flags = 0; ++ unsigned long wait_time_max; ++ unsigned long start_time; ++ ++ wait_flags = FC_RSCN_MODE | FC_RSCN_DISCOVERY | FC_NLP_MORE | ++ FC_RSCN_DEFERRED | FC_NDISC_ACTIVE | FC_DISC_TMO; ++ ++ /* ++ * The time constraint on this loop is a balance between the ++ * fabric RA_TOV value and dev_loss tmo. The driver's ++ * devloss_tmo is 10 giving this loop a 3x multiplier minimally. ++ */ ++ wait_time_max = msecs_to_jiffies(((phba->fc_ratov * 3) + 3) * 1000); ++ wait_time_max += jiffies; ++ start_time = jiffies; ++ while (time_before(jiffies, wait_time_max)) { ++ if ((vport->num_disc_nodes > 0) || ++ (vport->fc_flag & wait_flags) || ++ ((vport->port_state > LPFC_VPORT_FAILED) && ++ (vport->port_state < LPFC_VPORT_READY))) { ++ lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, ++ "1833 Vport discovery quiesce Wait:" ++ " vpi x%x state x%x fc_flags x%x" ++ " num_nodes x%x, waiting 1000 msecs" ++ " total wait msecs x%x\n", ++ vport->vpi, vport->port_state, ++ vport->fc_flag, vport->num_disc_nodes, ++ jiffies_to_msecs(jiffies - start_time)); ++ msleep(1000); ++ } else { ++ /* Base case. Wait variants satisfied. Break out */ ++ lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, ++ "1834 Vport discovery quiesced:" ++ " vpi x%x state x%x fc_flags x%x" ++ " wait msecs x%x\n", ++ vport->vpi, vport->port_state, ++ vport->fc_flag, ++ jiffies_to_msecs(jiffies ++ - start_time)); ++ break; ++ } ++ } ++ ++ if (time_after(jiffies, wait_time_max)) ++ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, ++ "1835 Vport discovery quiesce failed:" ++ " vpi x%x state x%x fc_flags x%x" ++ " wait msecs x%x\n", ++ vport->vpi, vport->port_state, ++ vport->fc_flag, ++ jiffies_to_msecs(jiffies - start_time)); ++} ++ + int + lpfc_vport_create(struct fc_vport *fc_vport, bool disable) + { +@@ -506,8 +578,12 @@ lpfc_vport_delete(struct fc_vport *fc_vp + * initiated after we've disposed of all other resources associated + * with the port. + */ +- if (!scsi_host_get(shost) || !scsi_host_get(shost)) ++ if (!scsi_host_get(shost)) ++ return VPORT_INVAL; ++ if (!scsi_host_get(shost)) { ++ scsi_host_put(shost); + return VPORT_INVAL; ++ } + spin_lock_irq(&phba->hbalock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(&phba->hbalock); +@@ -597,11 +673,16 @@ lpfc_vport_delete(struct fc_vport *fc_vp + } + vport->unreg_vpi_cmpl = VPORT_INVAL; + timeout = msecs_to_jiffies(phba->fc_ratov * 2000); ++ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) ++ goto skip_logo; + if (!lpfc_issue_els_npiv_logo(vport, ndlp)) + while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) + timeout = schedule_timeout(timeout); + } + ++ if (!(phba->pport->load_flag & FC_UNLOADING)) ++ lpfc_discovery_wait(vport); ++ + skip_logo: + lpfc_cleanup(vport); + lpfc_sli_host_down(vport); +@@ -615,8 +696,10 @@ skip_logo: + * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) + * does the scsi_host_put() to release the vport. + */ +- lpfc_mbx_unreg_vpi(vport); +- } ++ if (lpfc_mbx_unreg_vpi(vport)) ++ scsi_host_put(shost); ++ } else ++ scsi_host_put(shost); + + lpfc_free_vpi(phba, vport->vpi); + vport->work_port_events = 0; +@@ -663,3 +746,82 @@ lpfc_destroy_vport_work_array(struct lpf + scsi_host_put(lpfc_shost_from_vport(vports[i])); + kfree(vports); + } ++ ++ ++/** ++ * lpfc_vport_reset_stat_data: Reset the statistical data for the vport. ++ * @vport: Pointer to vport object. ++ * ++ * This function resets the statistical data for the vport. This function ++ * is called with the host_lock held ++ **/ ++void ++lpfc_vport_reset_stat_data(struct lpfc_vport *vport) ++{ ++ struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; ++ ++ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { ++ if (!NLP_CHK_NODE_ACT(ndlp)) ++ continue; ++ if (ndlp->lat_data) ++ memset(ndlp->lat_data, 0, LPFC_MAX_BUCKET_COUNT * ++ sizeof(struct lpfc_scsicmd_bkt)); ++ } ++} ++ ++ ++/** ++ * lpfc_alloc_bucket: Allocate data buffer required for collecting ++ * statistical data. ++ * @vport: Pointer to vport object. ++ * ++ * This function allocates data buffer required for all the FC ++ * nodes of the vport to collect statistical data. ++ **/ ++void ++lpfc_alloc_bucket(struct lpfc_vport *vport) ++{ ++ struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; ++ ++ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { ++ if (!NLP_CHK_NODE_ACT(ndlp)) ++ continue; ++ ++ kfree(ndlp->lat_data); ++ ndlp->lat_data = NULL; ++ ++ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { ++ ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT, ++ sizeof(struct lpfc_scsicmd_bkt), ++ GFP_ATOMIC); ++ ++ if (!ndlp->lat_data) ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, ++ "0287 lpfc_alloc_bucket failed to " ++ "allocate statistical data buffer DID " ++ "0x%x\n", ndlp->nlp_DID); ++ } ++ } ++} ++ ++/** ++ * lpfc_free_bucket: Free data buffer required for collecting ++ * statistical data. ++ * @vport: Pointer to vport object. ++ * ++ * Th function frees statistical data buffer of all the FC ++ * nodes of the vport. ++ **/ ++void ++lpfc_free_bucket(struct lpfc_vport *vport) ++{ ++ struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; ++ ++ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { ++ if (!NLP_CHK_NODE_ACT(ndlp)) ++ continue; ++ ++ kfree(ndlp->lat_data); ++ ndlp->lat_data = NULL; ++ } ++} +--- a/drivers/scsi/lpfc/lpfc_vport.h ++++ b/drivers/scsi/lpfc/lpfc_vport.h +@@ -112,4 +112,8 @@ struct vport_cmd_tag { + void lpfc_vport_set_state(struct lpfc_vport *vport, + enum fc_vport_state new_state); + ++void lpfc_vport_reset_stat_data(struct lpfc_vport *); ++void lpfc_alloc_bucket(struct lpfc_vport *); ++void lpfc_free_bucket(struct lpfc_vport *); ++ + #endif /* H_LPFC_VPORT */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.1-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.1-update new file mode 100644 index 000000000..ac37664b1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.1-update @@ -0,0 +1,9328 @@ +From: Jamie Wellnitz +Subject: Update lpfc to 8.2.8.1 +References: bnc#420767 + +This patch adds a few features (including FC authentication and a few +management ioctls) to lpfc 8.2.8 and generates 8.2.8.1. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/lpfc/Makefile | 5 + drivers/scsi/lpfc/lpfc.h | 129 + + drivers/scsi/lpfc/lpfc_attr.c | 976 ++++++++++++- + drivers/scsi/lpfc/lpfc_auth.c | 838 +++++++++++ + drivers/scsi/lpfc/lpfc_auth.h | 92 + + drivers/scsi/lpfc/lpfc_auth_access.c | 598 ++++++++ + drivers/scsi/lpfc/lpfc_auth_access.h | 245 +++ + drivers/scsi/lpfc/lpfc_crtn.h | 37 + drivers/scsi/lpfc/lpfc_disc.h | 3 + drivers/scsi/lpfc/lpfc_els.c | 663 +++++++++ + drivers/scsi/lpfc/lpfc_hbadisc.c | 154 +- + drivers/scsi/lpfc/lpfc_hw.h | 52 + drivers/scsi/lpfc/lpfc_init.c | 154 +- + drivers/scsi/lpfc/lpfc_ioctl.c | 2519 +++++++++++++++++++++++++++++++++++ + drivers/scsi/lpfc/lpfc_ioctl.h | 184 ++ + drivers/scsi/lpfc/lpfc_logmsg.h | 1 + drivers/scsi/lpfc/lpfc_mbox.c | 2 + drivers/scsi/lpfc/lpfc_menlo.c | 1174 ++++++++++++++++ + drivers/scsi/lpfc/lpfc_scsi.c | 36 + drivers/scsi/lpfc/lpfc_security.c | 339 ++++ + drivers/scsi/lpfc/lpfc_security.h | 24 + drivers/scsi/lpfc/lpfc_sli.c | 59 + drivers/scsi/lpfc/lpfc_sli.h | 3 + drivers/scsi/lpfc/lpfc_version.h | 2 + drivers/scsi/lpfc/lpfc_vport.c | 16 + 25 files changed, 8149 insertions(+), 156 deletions(-) + +--- a/drivers/scsi/lpfc/lpfc_attr.c ++++ b/drivers/scsi/lpfc/lpfc_attr.c +@@ -41,6 +41,7 @@ + #include "lpfc_compat.h" + #include "lpfc_crtn.h" + #include "lpfc_vport.h" ++#include "lpfc_auth_access.h" + + #define LPFC_DEF_DEVLOSS_TMO 30 + #define LPFC_MIN_DEVLOSS_TMO 1 +@@ -50,6 +51,15 @@ + #define LPFC_LINK_SPEED_BITMAP 0x00000117 + #define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8" + ++extern struct bin_attribute sysfs_menlo_attr; ++ ++/* ++ * Write key size should be multiple of 4. If write key is changed ++ * make sure that library write key is also changed. ++ */ ++#define LPFC_REG_WRITE_KEY_SIZE 4 ++#define LPFC_REG_WRITE_KEY "EMLX" ++ + /** + * lpfc_jedec_to_ascii: Hex to ascii convertor according to JEDEC rules. + * @incr: integer to convert. +@@ -551,7 +561,7 @@ lpfc_do_offline(struct lpfc_hba *phba, u + * -EIO reset not configured or error posting the event + * zero for success + **/ +-static int ++int + lpfc_selective_reset(struct lpfc_hba *phba) + { + struct completion online_compl; +@@ -1080,6 +1090,141 @@ lpfc_poll_store(struct device *dev, stru + return strlen(buf); + } + ++static ssize_t ++lpfc_auth_state_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ switch (vport->auth.auth_state) { ++ case LPFC_AUTH_UNKNOWN: ++ if (vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS_REPLY) ++ return snprintf(buf, PAGE_SIZE, "Authenticating\n"); ++ else ++ return snprintf(buf, PAGE_SIZE, "Not Authenticated\n"); ++ case LPFC_AUTH_FAIL: ++ return snprintf(buf, PAGE_SIZE, "Failed\n"); ++ case LPFC_AUTH_SUCCESS: ++ if (vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS_REPLY) ++ return snprintf(buf, PAGE_SIZE, "Authenticating\n"); ++ else if (vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS) ++ return snprintf(buf, PAGE_SIZE, "Authenticated\n"); ++ } ++ return snprintf(buf, PAGE_SIZE, "Unknown\n"); ++} ++ ++static ssize_t ++lpfc_auth_dir_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ if (!vport->cfg_enable_auth || ++ vport->auth.auth_state != LPFC_AUTH_SUCCESS) ++ return snprintf(buf, PAGE_SIZE, "Unknown\n"); ++ if (vport->auth.direction == AUTH_DIRECTION_LOCAL) ++ return snprintf(buf, PAGE_SIZE, "Local Authenticated\n"); ++ else if (vport->auth.direction == AUTH_DIRECTION_REMOTE) ++ return snprintf(buf, PAGE_SIZE, "Remote Authenticated\n"); ++ else if (vport->auth.direction == AUTH_DIRECTION_BIDI) ++ return snprintf(buf, PAGE_SIZE, "Bidi Authentication\n"); ++ return snprintf(buf, PAGE_SIZE, "Unknown\n"); ++} ++ ++static ssize_t ++lpfc_auth_protocol_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ if (vport->cfg_enable_auth && ++ vport->auth.auth_state == LPFC_AUTH_SUCCESS) ++ return snprintf(buf, PAGE_SIZE, "1 (DH-CHAP)\n"); ++ else ++ return snprintf(buf, PAGE_SIZE, "Unknown\n"); ++} ++ ++static ssize_t ++lpfc_auth_dhgroup_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ if (!vport->cfg_enable_auth || ++ vport->auth.auth_state != LPFC_AUTH_SUCCESS) ++ return snprintf(buf, PAGE_SIZE, "Unknown\n"); ++ switch (vport->auth.group_id) { ++ case DH_GROUP_NULL: ++ return snprintf(buf, PAGE_SIZE, "0 (NULL)\n"); ++ case DH_GROUP_1024: ++ return snprintf(buf, PAGE_SIZE, "1 (1024)\n"); ++ case DH_GROUP_1280: ++ return snprintf(buf, PAGE_SIZE, "2 (1280)\n"); ++ case DH_GROUP_1536: ++ return snprintf(buf, PAGE_SIZE, "3 (1536)\n"); ++ case DH_GROUP_2048: ++ return snprintf(buf, PAGE_SIZE, "4 (2048)\n"); ++ } ++ return snprintf(buf, PAGE_SIZE, "%d (Unrecognized)\n", ++ vport->auth.group_id); ++} ++ ++static ssize_t ++lpfc_auth_hash_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ if (!vport->cfg_enable_auth || ++ vport->auth.auth_state != LPFC_AUTH_SUCCESS) ++ return snprintf(buf, PAGE_SIZE, "Unknown\n"); ++ switch (vport->auth.hash_id) { ++ case FC_SP_HASH_MD5: ++ return snprintf(buf, PAGE_SIZE, "5 (MD5)\n"); ++ case FC_SP_HASH_SHA1: ++ return snprintf(buf, PAGE_SIZE, "6 (SHA1)\n"); ++ } ++ return snprintf(buf, PAGE_SIZE, "%d (Unrecognized)\n", ++ vport->auth.hash_id); ++} ++static ssize_t ++lpfc_auth_last_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct timeval last_time; ++ if (!vport->cfg_enable_auth || vport->auth.last_auth == 0) ++ return snprintf(buf, PAGE_SIZE, "%d\n", -1); ++ jiffies_to_timeval((jiffies - vport->auth.last_auth), &last_time); ++ return snprintf(buf, PAGE_SIZE, "%ld\n", last_time.tv_sec); ++} ++ ++static ssize_t ++lpfc_auth_next_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ unsigned long next_jiff; ++ struct timeval next_time; ++ if (!vport->cfg_enable_auth || ++ vport->auth.last_auth == 0 || ++ vport->auth.reauth_interval == 0) ++ return snprintf(buf, PAGE_SIZE, "%d\n", -1); ++ /* calculate the amount of time left until next auth */ ++ next_jiff = (msecs_to_jiffies(vport->auth.reauth_interval * 60000) + ++ vport->auth.last_auth) - jiffies; ++ jiffies_to_timeval(next_jiff, &next_time); ++ return snprintf(buf, PAGE_SIZE, "%ld\n", next_time.tv_sec); ++} ++ + /** + * lpfc_param_show: Return a cfg attribute value in decimal. + * +@@ -1512,7 +1657,38 @@ static DEVICE_ATTR(max_xri, S_IRUGO, lpf + static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); + static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); + static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL); ++static DEVICE_ATTR(auth_state, S_IRUGO, lpfc_auth_state_show, NULL); ++static DEVICE_ATTR(auth_dir, S_IRUGO, lpfc_auth_dir_show, NULL); ++static DEVICE_ATTR(auth_protocol, S_IRUGO, lpfc_auth_protocol_show, NULL); ++static DEVICE_ATTR(auth_dhgroup, S_IRUGO, lpfc_auth_dhgroup_show, NULL); ++static DEVICE_ATTR(auth_hash, S_IRUGO, lpfc_auth_hash_show, NULL); ++static DEVICE_ATTR(auth_last, S_IRUGO, lpfc_auth_last_show, NULL); ++static DEVICE_ATTR(auth_next, S_IRUGO, lpfc_auth_next_show, NULL); ++ ++static int ++lpfc_parse_wwn(const char *ns, uint8_t *nm) ++{ ++ unsigned int i, j; ++ memset(nm, 0, 8); ++ ++ /* Validate and store the new name */ ++ for (i = 0, j = 0; i < 16; i++) { ++ if ((*ns >= 'a') && (*ns <= 'f')) ++ j = ((j << 4) | ((*ns++ - 'a') + 10)); ++ else if ((*ns >= 'A') && (*ns <= 'F')) ++ j = ((j << 4) | ((*ns++ - 'A') + 10)); ++ else if ((*ns >= '0') && (*ns <= '9')) ++ j = ((j << 4) | (*ns++ - '0')); ++ else ++ return -EINVAL; ++ if (i % 2) { ++ nm[i/2] = j & 0xff; ++ j = 0; ++ } ++ } + ++ return 0; ++} + + static char *lpfc_soft_wwn_key = "C99G71SL8032A"; + +@@ -1908,6 +2084,87 @@ lpfc_vport_param_store(nodev_tmo) + + static DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR, + lpfc_nodev_tmo_show, lpfc_nodev_tmo_store); ++static ssize_t ++lpfc_authenticate(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ struct lpfc_nodelist *ndlp; ++ int status; ++ struct lpfc_name wwpn; ++ ++ if (lpfc_parse_wwn(buf, wwpn.u.wwn)) ++ return -EINVAL; ++ ++ if (vport->port_state == LPFC_VPORT_FAILED) { ++ lpfc_issue_lip(shost); ++ return strlen(buf); ++ } ++ if ((vport->fc_flag & FC_OFFLINE_MODE) || ++ (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || ++ (!vport->cfg_enable_auth)) ++ return -EPERM; ++ ++ /* If vport already in the middle of authentication do not restart */ ++ if ((vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE) || ++ (vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE) || ++ (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY)) ++ return -EAGAIN; ++ ++ if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN) ++ ndlp = lpfc_findnode_did(vport, Fabric_DID); ++ else ++ ndlp = lpfc_findnode_wwnn(vport, &wwpn); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) ++ return -EPERM; ++ status = lpfc_start_node_authentication(ndlp); ++ if (status) ++ return status; ++ return strlen(buf); ++} ++static DEVICE_ATTR(lpfc_authenticate, S_IRUGO | S_IWUSR, NULL, ++ lpfc_authenticate); ++ ++static ssize_t ++lpfc_update_auth_config(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ struct lpfc_nodelist *ndlp; ++ struct lpfc_name wwpn; ++ int status; ++ ++ if (lpfc_parse_wwn(buf, wwpn.u.wwn)) ++ return -EINVAL; ++ ++ if ((vport->fc_flag & FC_OFFLINE_MODE) || ++ (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || ++ (!vport->cfg_enable_auth)) ++ return -EPERM; ++ ++ /* If vport already in the middle of authentication do not restart */ ++ if ((vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE) || ++ (vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE) || ++ (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY)) ++ return -EAGAIN; ++ ++ if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN) ++ ndlp = lpfc_findnode_did(vport, Fabric_DID); ++ else ++ ndlp = lpfc_findnode_wwnn(vport, &wwpn); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) ++ return -EPERM; ++ status = lpfc_get_auth_config(ndlp, &wwpn); ++ if (status) ++ return -EPERM; ++ return strlen(buf); ++} ++static DEVICE_ATTR(lpfc_update_auth_config, S_IRUGO | S_IWUSR, ++ NULL, lpfc_update_auth_config); + + /* + # lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that +@@ -2753,6 +3010,48 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Messa + "MSI-X (2), if possible"); + + /* ++# lpfc_enable_auth: controls FC Authentication. ++# 0 = Authentication OFF ++# 1 = Authentication ON ++# Value range [0,1]. Default value is 0. ++*/ ++static int lpfc_enable_auth; ++module_param(lpfc_enable_auth, int, 0); ++MODULE_PARM_DESC(lpfc_enable_auth, "Enable FC Authentication"); ++lpfc_vport_param_show(enable_auth); ++lpfc_vport_param_init(enable_auth, 0, 0, 1); ++static int ++lpfc_enable_auth_set(struct lpfc_vport *vport, int val) ++{ ++ if (val == vport->cfg_enable_auth) ++ return 0; ++ if (val == 0) { ++ spin_lock_irq(&fc_security_user_lock); ++ list_del(&vport->sc_users); ++ spin_unlock_irq(&fc_security_user_lock); ++ vport->cfg_enable_auth = val; ++ lpfc_fc_queue_security_work(vport, ++ &vport->sc_offline_work); ++ return 0; ++ } else if (val == 1) { ++ spin_lock_irq(&fc_security_user_lock); ++ list_add_tail(&vport->sc_users, &fc_security_user_list); ++ spin_unlock_irq(&fc_security_user_lock); ++ vport->cfg_enable_auth = val; ++ lpfc_fc_queue_security_work(vport, ++ &vport->sc_online_work); ++ return 0; ++ } ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, ++ "0431 lpfc_enable_auth attribute cannot be set to %d, " ++ "allowed range is [0, 1]\n", val); ++ return -EINVAL; ++} ++lpfc_vport_param_store(enable_auth); ++static DEVICE_ATTR(lpfc_enable_auth, S_IRUGO | S_IWUSR, ++ lpfc_enable_auth_show, lpfc_enable_auth_store); ++ ++/* + # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. + # 0 = HBA resets disabled + # 1 = HBA resets enabled (default) +@@ -2825,6 +3124,16 @@ struct device_attribute *lpfc_hba_attrs[ + &dev_attr_lpfc_poll, + &dev_attr_lpfc_poll_tmo, + &dev_attr_lpfc_use_msi, ++ &dev_attr_lpfc_enable_auth, ++ &dev_attr_lpfc_authenticate, ++ &dev_attr_lpfc_update_auth_config, ++ &dev_attr_auth_state, ++ &dev_attr_auth_dir, ++ &dev_attr_auth_protocol, ++ &dev_attr_auth_dhgroup, ++ &dev_attr_auth_hash, ++ &dev_attr_auth_last, ++ &dev_attr_auth_next, + &dev_attr_lpfc_soft_wwnn, + &dev_attr_lpfc_soft_wwpn, + &dev_attr_lpfc_soft_wwn_enable, +@@ -2855,6 +3164,14 @@ struct device_attribute *lpfc_vport_attr + &dev_attr_nport_evt_cnt, + &dev_attr_npiv_info, + &dev_attr_lpfc_enable_da_id, ++ &dev_attr_auth_state, ++ &dev_attr_auth_dir, ++ &dev_attr_auth_protocol, ++ &dev_attr_auth_dhgroup, ++ &dev_attr_auth_hash, ++ &dev_attr_auth_last, ++ &dev_attr_auth_next, ++ + &dev_attr_lpfc_max_scsicmpl_time, + &dev_attr_lpfc_stat_data_ctrl, + NULL, +@@ -2888,21 +3205,23 @@ sysfs_ctlreg_write(struct kobject *kobj, + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + +- if ((off + count) > FF_REG_AREA_SIZE) ++ if ((off + count) > FF_REG_AREA_SIZE + LPFC_REG_WRITE_KEY_SIZE) + return -ERANGE; + +- if (count == 0) return 0; ++ if (count <= LPFC_REG_WRITE_KEY_SIZE) ++ return 0; + + if (off % 4 || count % 4 || (unsigned long)buf % 4) + return -EINVAL; + +- if (!(vport->fc_flag & FC_OFFLINE_MODE)) { +- return -EPERM; +- } ++ /* This is to protect HBA registers from accidental writes. */ ++ if (memcmp(buf, LPFC_REG_WRITE_KEY, LPFC_REG_WRITE_KEY_SIZE)) ++ return -EINVAL; + + spin_lock_irq(&phba->hbalock); +- for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) +- writel(*((uint32_t *)(buf + buf_off)), ++ for (buf_off = 0; buf_off < count - LPFC_REG_WRITE_KEY_SIZE; ++ buf_off += sizeof(uint32_t)) ++ writel(*((uint32_t *)(buf + buf_off + LPFC_REG_WRITE_KEY_SIZE)), + phba->ctrl_regs_memmap_p + off + buf_off); + + spin_unlock_irq(&phba->hbalock); +@@ -2971,21 +3290,211 @@ static struct bin_attribute sysfs_ctlreg + .write = sysfs_ctlreg_write, + }; + ++static struct lpfc_sysfs_mbox * ++lpfc_get_sysfs_mbox(struct lpfc_hba *phba, uint8_t create) ++{ ++ struct lpfc_sysfs_mbox *sysfs_mbox; ++ pid_t pid; ++ ++ pid = current->pid; ++ ++ spin_lock_irq(&phba->hbalock); ++ list_for_each_entry(sysfs_mbox, &phba->sysfs_mbox_list, list) { ++ if (sysfs_mbox->pid == pid) { ++ spin_unlock_irq(&phba->hbalock); ++ return sysfs_mbox; ++ } ++ } ++ if (!create) { ++ spin_unlock_irq(&phba->hbalock); ++ return NULL; ++ } ++ spin_unlock_irq(&phba->hbalock); ++ sysfs_mbox = kzalloc(sizeof(struct lpfc_sysfs_mbox), ++ GFP_KERNEL); ++ if (!sysfs_mbox) ++ return NULL; ++ sysfs_mbox->state = SMBOX_IDLE; ++ sysfs_mbox->pid = pid; ++ spin_lock_irq(&phba->hbalock); ++ list_add_tail(&sysfs_mbox->list, &phba->sysfs_mbox_list); ++ ++ spin_unlock_irq(&phba->hbalock); ++ return sysfs_mbox; ++ ++} + /** + * sysfs_mbox_idle: frees the sysfs mailbox. + * @phba: lpfc_hba pointer + **/ + static void +-sysfs_mbox_idle(struct lpfc_hba *phba) ++sysfs_mbox_idle(struct lpfc_hba *phba, ++ struct lpfc_sysfs_mbox *sysfs_mbox) + { +- phba->sysfs_mbox.state = SMBOX_IDLE; +- phba->sysfs_mbox.offset = 0; +- +- if (phba->sysfs_mbox.mbox) { +- mempool_free(phba->sysfs_mbox.mbox, ++ list_del_init(&sysfs_mbox->list); ++ if (sysfs_mbox->mbox) { ++ mempool_free(sysfs_mbox->mbox, + phba->mbox_mem_pool); +- phba->sysfs_mbox.mbox = NULL; + } ++ ++ if (sysfs_mbox->mbext) ++ kfree(sysfs_mbox->mbext); ++ ++ /* If txmit buffer allocated free txmit buffer */ ++ if (sysfs_mbox->txmit_buff) { ++ if (sysfs_mbox->txmit_buff->virt) ++ __lpfc_mbuf_free(phba, ++ sysfs_mbox->txmit_buff->virt, ++ sysfs_mbox->txmit_buff->phys); ++ kfree(sysfs_mbox->txmit_buff); ++ } ++ ++ /* If rcv buffer allocated free txmit buffer */ ++ if (sysfs_mbox->rcv_buff) { ++ if (sysfs_mbox->rcv_buff->virt) ++ __lpfc_mbuf_free(phba, ++ sysfs_mbox->rcv_buff->virt, ++ sysfs_mbox->rcv_buff->phys); ++ kfree(sysfs_mbox->rcv_buff); ++ } ++ ++ kfree(sysfs_mbox); ++} ++ ++static size_t ++lpfc_syfs_mbox_copy_rcv_buff(struct lpfc_hba *phba, ++ struct lpfc_sysfs_mbox *sysfs_mbox, ++ char *buf, loff_t off, size_t count) ++{ ++ uint32_t size; ++ spin_lock_irq(&phba->hbalock); ++ if (!sysfs_mbox->mbox) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ if (sysfs_mbox->mbox->mb.mbxCommand == MBX_READ_EVENT_LOG) ++ size = sysfs_mbox->mbox->mb.un. ++ varRdEventLog.rcv_bde64.tus.f.bdeSize; ++ else ++ size = sysfs_mbox->mbox->mb.un. ++ varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize; ++ ++ ++ if ((count + off) > size) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ if (count > LPFC_BPL_SIZE) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ if (sysfs_mbox->extoff != off) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ memcpy(buf, (uint8_t *) sysfs_mbox->rcv_buff->virt + off, count); ++ sysfs_mbox->extoff = off + count; ++ ++ if (sysfs_mbox->extoff >= size) ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ ++ spin_unlock_irq(&phba->hbalock); ++ ++ return count; ++} ++ ++static size_t ++lpfc_syfs_mbox_copy_extdata(struct lpfc_hba *phba, ++ struct lpfc_sysfs_mbox * sysfs_mbox, ++ char *buf, loff_t off, size_t count) ++{ ++ uint32_t size; ++ ++ spin_lock_irq(&phba->hbalock); ++ if (!sysfs_mbox->mbox) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ size = sysfs_mbox->mbox_data.out_ext_wlen * sizeof(uint32_t); ++ ++ if ((count + off) > size) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (size > MAILBOX_EXT_SIZE) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (sysfs_mbox->extoff != off) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ memcpy(buf, (uint8_t *) sysfs_mbox->mbext + off, count); ++ sysfs_mbox->extoff = off + count; ++ ++ if (sysfs_mbox->extoff >= size) ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ ++ spin_unlock_irq(&phba->hbalock); ++ ++ return count; ++} ++ ++static size_t ++lpfc_syfs_mbox_copy_txmit_buff(struct lpfc_hba *phba, ++ struct lpfc_sysfs_mbox *sysfs_mbox, ++ char *buf, loff_t off, size_t count) ++{ ++ uint32_t size; ++ spin_lock_irq(&phba->hbalock); ++ if (!sysfs_mbox->mbox || ++ (sysfs_mbox->offset != sizeof(struct lpfc_sysfs_mbox_data))) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ size = sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.xmit_bde64. ++ tus.f.bdeSize; ++ ++ if ((count + off) > size) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (size > LPFC_BPL_SIZE) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (sysfs_mbox->extoff != off) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ memcpy((uint8_t *) sysfs_mbox->txmit_buff->virt + off, buf, count); ++ sysfs_mbox->extoff = off + count; ++ ++ spin_unlock_irq(&phba->hbalock); ++ ++ return count; + } + + /** +@@ -3018,6 +3527,9 @@ sysfs_mbox_write(struct kobject *kobj, s + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfcMboxq *mbox = NULL; ++ struct lpfc_sysfs_mbox *sysfs_mbox; ++ uint8_t *ext; ++ uint32_t size; + + if ((count + off) > MAILBOX_CMD_SIZE) + return -ERANGE; +@@ -3029,34 +3541,232 @@ sysfs_mbox_write(struct kobject *kobj, s + return 0; + + if (off == 0) { ++ sysfs_mbox = lpfc_get_sysfs_mbox(phba, 1); ++ if (sysfs_mbox == NULL) ++ return -ENOMEM; ++ /* ++ * If sysfs expect the reading of buffer and ++ * app doesnot know how to do it, use a different ++ * context. ++ */ ++ if (sysfs_mbox->state == SMBOX_READING_BUFF || ++ sysfs_mbox->state == SMBOX_READING_MBEXT) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ sysfs_mbox = lpfc_get_sysfs_mbox(phba, 1); ++ if (sysfs_mbox == NULL) ++ return -ENOMEM; ++ } ++ } else { ++ sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0); ++ if (sysfs_mbox == NULL) ++ return -EAGAIN; ++ } ++ spin_lock_irq(&phba->hbalock); ++ if (sysfs_mbox->state == SMBOX_WRITING_MBEXT) { ++ if (!sysfs_mbox->mbox || ++ (sysfs_mbox->offset != ++ sizeof(struct lpfc_sysfs_mbox_data))) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ size = sysfs_mbox->mbox_data.in_ext_wlen * sizeof(uint32_t); ++ ++ if ((count + sysfs_mbox->extoff) > size) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (size > MAILBOX_EXT_SIZE) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (!sysfs_mbox->mbext) { ++ spin_unlock_irq(&phba->hbalock); ++ ++ ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL); ++ if (!ext) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox->mbext = ext; ++ } ++ ++ if (sysfs_mbox->extoff != off) { ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EAGAIN; ++ } ++ ++ memcpy((uint8_t *) sysfs_mbox->mbext + off, buf, count); ++ sysfs_mbox->extoff = off + count; ++ ++ spin_unlock_irq(&phba->hbalock); ++ ++ return count; ++ } ++ ++ spin_unlock_irq(&phba->hbalock); ++ ++ if (sysfs_mbox->state == SMBOX_WRITING_BUFF) ++ return lpfc_syfs_mbox_copy_txmit_buff(phba, ++ sysfs_mbox, buf, off, count); ++ ++ if ((count + off) > sizeof(struct lpfc_sysfs_mbox_data)) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ERANGE; ++ } ++ ++ if (off == 0) { + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); +- if (!mbox) ++ if (!mbox) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); + return -ENOMEM; ++ } + memset(mbox, 0, sizeof (LPFC_MBOXQ_t)); + } + + spin_lock_irq(&phba->hbalock); + + if (off == 0) { +- if (phba->sysfs_mbox.mbox) ++ if (sysfs_mbox->mbox) + mempool_free(mbox, phba->mbox_mem_pool); + else +- phba->sysfs_mbox.mbox = mbox; +- phba->sysfs_mbox.state = SMBOX_WRITING; ++ sysfs_mbox->mbox = mbox; ++ sysfs_mbox->state = SMBOX_WRITING; + } else { +- if (phba->sysfs_mbox.state != SMBOX_WRITING || +- phba->sysfs_mbox.offset != off || +- phba->sysfs_mbox.mbox == NULL) { +- sysfs_mbox_idle(phba); ++ if (sysfs_mbox->state != SMBOX_WRITING || ++ sysfs_mbox->offset != off || ++ sysfs_mbox->mbox == NULL) { ++ sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + } + +- memcpy((uint8_t *) & phba->sysfs_mbox.mbox->mb + off, ++ memcpy((uint8_t *) & sysfs_mbox->mbox_data + off, + buf, count); + +- phba->sysfs_mbox.offset = off + count; ++ sysfs_mbox->offset = off + count; ++ ++ if (sysfs_mbox->offset == sizeof(struct lpfc_sysfs_mbox_data)) { ++ memcpy((uint8_t *) & sysfs_mbox->mbox->mb, ++ (uint8_t *) &sysfs_mbox->mbox_data.mbox, ++ sizeof(MAILBOX_t)); ++ } ++ ++ if ((sysfs_mbox->offset == sizeof(struct lpfc_sysfs_mbox_data)) && ++ (sysfs_mbox->mbox_data.in_ext_wlen || ++ sysfs_mbox->mbox_data.out_ext_wlen)) { ++ ++ if (!sysfs_mbox->mbext) { ++ spin_unlock_irq(&phba->hbalock); ++ ++ ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL); ++ if (!ext) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox->mbext = ext; ++ } ++ } ++ ++ if ((sysfs_mbox->offset == sizeof(struct lpfc_sysfs_mbox_data)) && ++ (sysfs_mbox->mbox_data.in_ext_wlen)) { ++ sysfs_mbox->state = SMBOX_WRITING_MBEXT; ++ } ++ ++ if ((sysfs_mbox->offset == sizeof(struct lpfc_sysfs_mbox_data)) && ++ (sysfs_mbox->mbox->mb.mbxCommand == MBX_RUN_BIU_DIAG64)) { ++ sysfs_mbox->state = SMBOX_WRITING_BUFF; ++ spin_unlock_irq(&phba->hbalock); ++ ++ /* Allocate txmit buffer */ ++ sysfs_mbox->txmit_buff = ++ kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); ++ if (!sysfs_mbox->txmit_buff) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ INIT_LIST_HEAD(&sysfs_mbox->txmit_buff->list); ++ sysfs_mbox->txmit_buff->virt = ++ lpfc_mbuf_alloc(phba, 0, ++ &(sysfs_mbox->txmit_buff->phys)); ++ if (!sysfs_mbox->txmit_buff->virt) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ ++ /* Allocate rcv buffer */ ++ sysfs_mbox->rcv_buff = ++ kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); ++ if (!sysfs_mbox->rcv_buff) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ INIT_LIST_HEAD(&sysfs_mbox->rcv_buff->list); ++ sysfs_mbox->rcv_buff->virt = ++ lpfc_mbuf_alloc(phba, 0, ++ &(sysfs_mbox->rcv_buff->phys)); ++ if (!sysfs_mbox->rcv_buff->virt) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ return count; ++ } ++ if ((sysfs_mbox->offset == sizeof(struct lpfc_sysfs_mbox_data)) && ++ (sysfs_mbox->mbox->mb.mbxCommand == MBX_READ_EVENT_LOG)) { ++ sysfs_mbox->state = SMBOX_WRITING; ++ spin_unlock_irq(&phba->hbalock); ++ ++ ++ /* Allocate rcv buffer */ ++ sysfs_mbox->rcv_buff = ++ kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); ++ if (!sysfs_mbox->rcv_buff) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ INIT_LIST_HEAD(&sysfs_mbox->rcv_buff->list); ++ sysfs_mbox->rcv_buff->virt = ++ lpfc_mbuf_alloc(phba, 0, ++ &(sysfs_mbox->rcv_buff->phys)); ++ if (!sysfs_mbox->rcv_buff->virt) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -ENOMEM; ++ } ++ return count; ++ } + + spin_unlock_irq(&phba->hbalock); + +@@ -3095,6 +3805,42 @@ sysfs_mbox_read(struct kobject *kobj, st + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int rc; ++ int wait_4_menlo_maint = 0; ++ struct lpfc_sysfs_mbox *sysfs_mbox; ++ ssize_t ret; ++ sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0); ++ ++ if (!sysfs_mbox) ++ return -EPERM; ++ ++ /* ++ * If sysfs expect the writing of buffer and ++ * app doesnot know how to do it, fail the mailbox ++ * command. ++ */ ++ if ((sysfs_mbox->state == SMBOX_WRITING_BUFF) && ++ (sysfs_mbox->extoff == 0)) { ++ spin_lock_irq(&phba->hbalock); ++ sysfs_mbox_idle(phba, sysfs_mbox); ++ spin_unlock_irq(&phba->hbalock); ++ return -EINVAL; ++ } ++ if (sysfs_mbox->state == SMBOX_READING_BUFF) { ++ ret = lpfc_syfs_mbox_copy_rcv_buff(phba, sysfs_mbox, ++ buf, off, count); ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "1245 mbox: cmd 0x%x, 0x%x ret %x\n", ++ sysfs_mbox->mbox->mb.mbxCommand, ++ sysfs_mbox->mbox->mb.un.varWords[0], ++ (uint32_t)ret); ++ return ret; ++ } ++ ++ if (sysfs_mbox->state == SMBOX_READING_MBEXT) { ++ ret = lpfc_syfs_mbox_copy_extdata(phba, sysfs_mbox, ++ buf, off, count); ++ return ret; ++ } + + if (off > MAILBOX_CMD_SIZE) + return -ERANGE; +@@ -3111,16 +3857,18 @@ sysfs_mbox_read(struct kobject *kobj, st + spin_lock_irq(&phba->hbalock); + + if (phba->over_temp_state == HBA_OVER_TEMP) { +- sysfs_mbox_idle(phba); ++ sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EACCES; + } + + if (off == 0 && +- phba->sysfs_mbox.state == SMBOX_WRITING && +- phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { ++ ((sysfs_mbox->state == SMBOX_WRITING) || ++ (sysfs_mbox->state == SMBOX_WRITING_MBEXT) || ++ (sysfs_mbox->state == SMBOX_WRITING_BUFF) ) && ++ sysfs_mbox->offset >= 2 * sizeof(uint32_t)) { + +- switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { ++ switch (sysfs_mbox->mbox->mb.mbxCommand) { + /* Offline only */ + case MBX_INIT_LINK: + case MBX_DOWN_LINK: +@@ -3133,12 +3881,11 @@ sysfs_mbox_read(struct kobject *kobj, st + case MBX_RUN_DIAGS: + case MBX_RESTART: + case MBX_SET_MASK: +- case MBX_SET_DEBUG: + if (!(vport->fc_flag & FC_OFFLINE_MODE)) { + printk(KERN_WARNING "mbox_read:Command 0x%x " + "is illegal in on-line state\n", +- phba->sysfs_mbox.mbox->mb.mbxCommand); +- sysfs_mbox_idle(phba); ++ sysfs_mbox->mbox->mb.mbxCommand); ++ sysfs_mbox_idle(phba,sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EPERM; + } +@@ -3160,11 +3907,63 @@ sysfs_mbox_read(struct kobject *kobj, st + case MBX_LOAD_EXP_ROM: + case MBX_BEACON: + case MBX_DEL_LD_ENTRY: +- case MBX_SET_VARIABLE: ++ case MBX_SET_DEBUG: + case MBX_WRITE_WWN: ++ case MBX_READ_EVENT_LOG_STATUS: ++ case MBX_WRITE_EVENT_LOG: + case MBX_PORT_CAPABILITIES: + case MBX_PORT_IOV_CONTROL: + break; ++ case MBX_SET_VARIABLE: ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "1226 mbox: set_variable 0x%x, 0x%x\n", ++ sysfs_mbox->mbox->mb.un.varWords[0], ++ sysfs_mbox->mbox->mb.un.varWords[1]); ++ if ((sysfs_mbox->mbox->mb.un.varWords[0] == ++ SETVAR_MLOMNT) && ++ (sysfs_mbox->mbox->mb.un.varWords[1] == 1)) { ++ wait_4_menlo_maint = 1; ++ phba->wait_4_mlo_maint_flg = 1; ++ } ++ break; ++ case MBX_RUN_BIU_DIAG64: ++ if (sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. ++ xmit_bde64.tus.f.bdeSize) { ++ sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. ++ xmit_bde64.addrHigh = ++ putPaddrHigh(sysfs_mbox-> ++ txmit_buff->phys); ++ sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. ++ xmit_bde64.addrLow = ++ putPaddrLow(sysfs_mbox-> ++ txmit_buff->phys); ++ } ++ ++ if (sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. ++ rcv_bde64.tus.f.bdeSize) { ++ sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. ++ rcv_bde64.addrHigh = ++ putPaddrHigh(sysfs_mbox-> ++ rcv_buff->phys); ++ sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. ++ rcv_bde64.addrLow = ++ putPaddrLow(sysfs_mbox->rcv_buff->phys); ++ } ++ break; ++ case MBX_READ_EVENT_LOG: ++ ++ if (sysfs_mbox->mbox->mb.un.varRdEventLog. ++ rcv_bde64.tus.f.bdeSize) { ++ sysfs_mbox->mbox->mb.un.varRdEventLog. ++ rcv_bde64.addrHigh = ++ putPaddrHigh(sysfs_mbox-> ++ rcv_buff->phys); ++ sysfs_mbox->mbox->mb.un.varRdEventLog. ++ rcv_bde64.addrLow = ++ putPaddrLow(sysfs_mbox->rcv_buff->phys); ++ } ++ break; ++ + case MBX_READ_SPARM64: + case MBX_READ_LA: + case MBX_READ_LA64: +@@ -3173,38 +3972,51 @@ sysfs_mbox_read(struct kobject *kobj, st + case MBX_CONFIG_PORT: + case MBX_RUN_BIU_DIAG: + printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n", +- phba->sysfs_mbox.mbox->mb.mbxCommand); +- sysfs_mbox_idle(phba); ++ sysfs_mbox->mbox->mb.mbxCommand); ++ sysfs_mbox_idle(phba,sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EPERM; + default: + printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n", +- phba->sysfs_mbox.mbox->mb.mbxCommand); +- sysfs_mbox_idle(phba); ++ sysfs_mbox->mbox->mb.mbxCommand); ++ sysfs_mbox_idle(phba,sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EPERM; + } + ++ if (sysfs_mbox->mbox_data.in_ext_wlen || ++ sysfs_mbox->mbox_data.out_ext_wlen) { ++ sysfs_mbox->mbox->context2 = sysfs_mbox->mbext; ++ sysfs_mbox->mbox->in_ext_byte_len = ++ sysfs_mbox->mbox_data.in_ext_wlen * ++ sizeof(uint32_t); ++ sysfs_mbox->mbox->out_ext_byte_len = ++ sysfs_mbox->mbox_data.out_ext_wlen * ++ sizeof(uint32_t); ++ sysfs_mbox->mbox->mbox_offset_word = ++ sysfs_mbox->mbox_data.mboffset; ++ } ++ + /* If HBA encountered an error attention, allow only DUMP + * or RESTART mailbox commands until the HBA is restarted. + */ + if (phba->pport->stopped && +- phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_DUMP_MEMORY && +- phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_RESTART && +- phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_VPARMS && +- phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_WRITE_WWN) ++ sysfs_mbox->mbox->mb.mbxCommand != MBX_DUMP_MEMORY && ++ sysfs_mbox->mbox->mb.mbxCommand != MBX_RESTART && ++ sysfs_mbox->mbox->mb.mbxCommand != MBX_WRITE_VPARMS && ++ sysfs_mbox->mbox->mb.mbxCommand != MBX_WRITE_WWN) + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, + "1259 mbox: Issued mailbox cmd " + "0x%x while in stopped state.\n", +- phba->sysfs_mbox.mbox->mb.mbxCommand); ++ sysfs_mbox->mbox->mb.mbxCommand); + +- phba->sysfs_mbox.mbox->vport = vport; ++ sysfs_mbox->mbox->vport = vport; + + /* Don't allow mailbox commands to be sent when blocked + * or when in the middle of discovery + */ + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { +- sysfs_mbox_idle(phba); ++ sysfs_mbox_idle(phba,sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } +@@ -3214,43 +4026,86 @@ sysfs_mbox_read(struct kobject *kobj, st + + spin_unlock_irq(&phba->hbalock); + rc = lpfc_sli_issue_mbox (phba, +- phba->sysfs_mbox.mbox, ++ sysfs_mbox->mbox, + MBX_POLL); + spin_lock_irq(&phba->hbalock); + + } else { + spin_unlock_irq(&phba->hbalock); + rc = lpfc_sli_issue_mbox_wait (phba, +- phba->sysfs_mbox.mbox, ++ sysfs_mbox->mbox, + lpfc_mbox_tmo_val(phba, +- phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ); ++ sysfs_mbox->mbox->mb.mbxCommand) * HZ); + spin_lock_irq(&phba->hbalock); + } + + if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) { +- phba->sysfs_mbox.mbox = NULL; ++ sysfs_mbox->mbox = NULL; + } +- sysfs_mbox_idle(phba); ++ sysfs_mbox_idle(phba,sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; + } +- phba->sysfs_mbox.state = SMBOX_READING; ++ if (wait_4_menlo_maint) { ++ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, ++ "1229 waiting for menlo mnt\n"); ++ spin_unlock_irq(&phba->hbalock); ++ if (phba->wait_4_mlo_maint_flg) ++ wait_event_interruptible_timeout( ++ phba->wait_4_mlo_m_q, ++ phba->wait_4_mlo_maint_flg == 0, ++ 60 * HZ); ++ spin_lock_irq(&phba->hbalock); ++ if (phba->wait_4_mlo_maint_flg) { ++ sysfs_mbox_idle(phba,sysfs_mbox); ++ phba->wait_4_mlo_maint_flg = 0; ++ spin_unlock_irq(&phba->hbalock); ++ return -EINTR; ++ } else ++ spin_unlock_irq(&phba->hbalock); ++ ++ spin_lock_irq(&phba->hbalock); ++ if (phba->wait_4_mlo_maint_flg != 0) { ++ sysfs_mbox_idle(phba,sysfs_mbox); ++ phba->wait_4_mlo_maint_flg = 0; ++ spin_unlock_irq(&phba->hbalock); ++ return -ETIME; ++ } ++ ++ } ++ sysfs_mbox->state = SMBOX_READING; + } +- else if (phba->sysfs_mbox.offset != off || +- phba->sysfs_mbox.state != SMBOX_READING) { +- printk(KERN_WARNING "mbox_read: Bad State\n"); +- sysfs_mbox_idle(phba); ++ else if (sysfs_mbox->offset != off || ++ sysfs_mbox->state != SMBOX_READING) { ++ sysfs_mbox_idle(phba,sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + +- memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count); ++ memcpy(buf, (uint8_t *) & sysfs_mbox->mbox->mb + off, count); ++ ++ sysfs_mbox->offset = off + count; + +- phba->sysfs_mbox.offset = off + count; ++ if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) && ++ ((sysfs_mbox->mbox->mb.mbxCommand == MBX_RUN_BIU_DIAG64) || ++ (sysfs_mbox->mbox->mb.mbxCommand == MBX_READ_EVENT_LOG))) { ++ sysfs_mbox->state = SMBOX_READING_BUFF; ++ sysfs_mbox->extoff = 0; ++ spin_unlock_irq(&phba->hbalock); ++ return count; ++ } ++ ++ if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) && ++ sysfs_mbox->mbox_data.out_ext_wlen) { ++ sysfs_mbox->state = SMBOX_READING_MBEXT; ++ sysfs_mbox->extoff = 0; ++ spin_unlock_irq(&phba->hbalock); ++ return count; ++ } + +- if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE) +- sysfs_mbox_idle(phba); ++ if (sysfs_mbox->offset == MAILBOX_CMD_SIZE) ++ sysfs_mbox_idle(phba,sysfs_mbox); + + spin_unlock_irq(&phba->hbalock); + +@@ -3262,7 +4117,7 @@ static struct bin_attribute sysfs_mbox_a + .name = "mbox", + .mode = S_IRUSR | S_IWUSR, + }, +- .size = MAILBOX_CMD_SIZE, ++ .size = MAILBOX_MAX_XMIT_SIZE, + .read = sysfs_mbox_read, + .write = sysfs_mbox_write, + }; +@@ -3317,6 +4172,7 @@ lpfc_free_sysfs_attr(struct lpfc_vport * + &sysfs_drvr_stat_data_attr); + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); ++ sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_menlo_attr); + } + + +@@ -3935,7 +4791,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) + phba->cfg_soft_wwpn = 0L; + lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); + /* Also reinitialize the host templates with new values. */ +- lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; + /* + * Since the sg_tablesize is module parameter, the sg_dma_buf_size +@@ -3970,5 +4825,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vpor + lpfc_max_luns_init(vport, lpfc_max_luns); + lpfc_scan_down_init(vport, lpfc_scan_down); + lpfc_enable_da_id_init(vport, lpfc_enable_da_id); ++ lpfc_enable_auth_init(vport, lpfc_enable_auth); + return; + } +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_auth_access.c +@@ -0,0 +1,598 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2007 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include /* workqueue stuff, HZ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "lpfc_hw.h" ++#include "lpfc_sli.h" ++#include "lpfc_nl.h" ++#include "lpfc_disc.h" ++#include "lpfc_scsi.h" ++#include "lpfc.h" ++#include "lpfc_logmsg.h" ++#include "lpfc_crtn.h" ++#include "lpfc_vport.h" ++#include "lpfc_auth_access.h" ++ ++/* fc security */ ++struct workqueue_struct *security_work_q = NULL; ++struct list_head fc_security_user_list; ++int fc_service_state = FC_SC_SERVICESTATE_UNKNOWN; ++static int fc_service_pid; ++DEFINE_SPINLOCK(fc_security_user_lock); ++ ++static inline struct lpfc_vport * ++lpfc_fc_find_vport(unsigned long host_no) ++{ ++ struct lpfc_vport *vport; ++ struct Scsi_Host *shost; ++ ++ list_for_each_entry(vport, &fc_security_user_list, sc_users) { ++ shost = lpfc_shost_from_vport(vport); ++ if (shost && (shost->host_no == host_no)) ++ return vport; ++ } ++ ++ return NULL; ++} ++ ++ ++/** ++ * lpfc_fc_sc_add_timer ++ * ++ * ++ **/ ++ ++void ++lpfc_fc_sc_add_timer(struct fc_security_request *req, int timeout, ++ void (*complete)(struct fc_security_request *)) ++{ ++ ++ init_timer(&req->timer); ++ ++ ++ req->timer.data = (unsigned long)req; ++ req->timer.expires = jiffies + timeout; ++ req->timer.function = (void (*)(unsigned long)) complete; ++ ++ add_timer(&req->timer); ++} ++/** ++ * lpfc_fc_sc_req_times_out ++ * ++ * ++ **/ ++ ++void ++lpfc_fc_sc_req_times_out(struct fc_security_request *req) ++{ ++ ++ unsigned long flags; ++ int found = 0; ++ struct fc_security_request *fc_sc_req; ++ struct lpfc_vport *vport = req->vport; ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ ++ if (!req) ++ return; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ ++ /* To avoid a completion race check to see if request is on the list */ ++ ++ list_for_each_entry(fc_sc_req, &vport->sc_response_wait_queue, rlist) ++ if (fc_sc_req == req) { ++ found = 1; ++ break; ++ } ++ ++ if (!found) { ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ return; ++ } ++ ++ list_del(&fc_sc_req->rlist); ++ ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, ++ "1019 Request tranid %d timed out\n", ++ fc_sc_req->tran_id); ++ ++ switch (fc_sc_req->req_type) { ++ ++ case FC_NL_SC_GET_CONFIG_REQ: ++ lpfc_security_config(shost, -ETIMEDOUT, ++ fc_sc_req->data); ++ break; ++ ++ case FC_NL_SC_DHCHAP_MAKE_CHALLENGE_REQ: ++ lpfc_dhchap_make_challenge(shost, -ETIMEDOUT, ++ fc_sc_req->data, 0); ++ break; ++ ++ case FC_NL_SC_DHCHAP_MAKE_RESPONSE_REQ: ++ lpfc_dhchap_make_response(shost, -ETIMEDOUT, ++ fc_sc_req->data, 0); ++ break; ++ ++ case FC_NL_SC_DHCHAP_AUTHENTICATE_REQ: ++ lpfc_dhchap_authenticate(shost, -ETIMEDOUT, fc_sc_req->data, 0); ++ break; ++ } ++ ++ kfree(fc_sc_req); ++ ++} ++ ++ ++static inline struct fc_security_request * ++lpfc_fc_find_sc_request(u32 tran_id, u32 type, struct lpfc_vport *vport) ++{ ++ struct fc_security_request *fc_sc_req; ++ ++ list_for_each_entry(fc_sc_req, &vport->sc_response_wait_queue, rlist) ++ if (fc_sc_req->tran_id == tran_id && ++ fc_sc_req->req_type == type) ++ return fc_sc_req; ++ return NULL; ++} ++ ++ ++ ++/** ++ * lpfc_fc_sc_request ++ * ++ * ++ **/ ++ ++int ++lpfc_fc_sc_request(struct lpfc_vport *vport, ++ u32 msg_type, ++ struct fc_auth_req *auth_req, ++ u32 auth_req_len, /* includes length of struct fc_auth_req */ ++ struct fc_auth_rsp *auth_rsp, ++ u32 auth_rsp_len) /* includes length of struct fc_auth_rsp */ ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct fc_security_request *fc_sc_req; ++ struct fc_nl_sc_message *fc_nl_sc_msg; ++ unsigned long flags; ++ u32 len; ++ u32 seq = ++vport->sc_tran_id; ++ ++ if (fc_service_state != FC_SC_SERVICESTATE_ONLINE) ++ return -EINVAL; ++ ++ if (vport->port_state == FC_PORTSTATE_DELETED) ++ return -EINVAL; ++ ++ fc_sc_req = kzalloc(sizeof(struct fc_security_request), GFP_KERNEL); ++ if (!fc_sc_req) ++ return -ENOMEM; ++ ++ fc_sc_req->req_type = msg_type; ++ fc_sc_req->data = auth_rsp; ++ fc_sc_req->data_len = auth_rsp_len; ++ fc_sc_req->vport = vport; ++ fc_sc_req->tran_id = seq; ++ ++ len = sizeof(struct fc_nl_sc_message) + auth_req_len; ++ fc_nl_sc_msg = kzalloc(sizeof(struct fc_nl_sc_message) + auth_req_len, ++ GFP_KERNEL); ++ if (!fc_nl_sc_msg) ++ return -ENOMEM; ++ fc_nl_sc_msg->msgtype = msg_type; ++ fc_nl_sc_msg->data_len = auth_req_len; ++ memcpy(fc_nl_sc_msg->data, auth_req, auth_req_len); ++ fc_nl_sc_msg->tran_id = seq; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_add_tail(&fc_sc_req->rlist, &vport->sc_response_wait_queue); ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ scsi_nl_send_vendor_msg(fc_service_pid, shost->host_no, ++ (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX), ++ (char *) fc_nl_sc_msg, len); ++ lpfc_fc_sc_add_timer(fc_sc_req, FC_SC_REQ_TIMEOUT, ++ lpfc_fc_sc_req_times_out); ++ return 0; ++} ++ ++/** ++ * lpfc_fc_security_get_config ++ * ++ * ++ **/ ++ ++int ++lpfc_fc_security_get_config(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 auth_req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 auth_rsp_len) ++{ ++ ++ return(lpfc_fc_sc_request((struct lpfc_vport *) shost->hostdata, ++ FC_NL_SC_GET_CONFIG_REQ, auth_req, ++ auth_req_len, auth_rsp, auth_rsp_len)); ++ ++} ++EXPORT_SYMBOL(lpfc_fc_security_get_config); ++ ++/** ++ * lpfc_fc_security_dhchap_make_challenge ++ * ++ * ++ **/ ++ ++int ++lpfc_fc_security_dhchap_make_challenge(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 auth_req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 auth_rsp_len) ++{ ++ ++ return(lpfc_fc_sc_request((struct lpfc_vport *) shost->hostdata, ++ FC_NL_SC_DHCHAP_MAKE_CHALLENGE_REQ, ++ auth_req, auth_req_len, auth_rsp, auth_rsp_len)); ++ ++} ++EXPORT_SYMBOL(lpfc_fc_security_dhchap_make_challenge); ++ ++/** ++ * lpfc_fc_security_dhchap_make_response ++ * ++ * ++ **/ ++ ++int ++lpfc_fc_security_dhchap_make_response(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 auth_req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 auth_rsp_len) ++{ ++ ++ return(lpfc_fc_sc_request((struct lpfc_vport *) shost->hostdata, ++ FC_NL_SC_DHCHAP_MAKE_RESPONSE_REQ, ++ auth_req, auth_req_len, auth_rsp, auth_rsp_len)); ++ ++} ++EXPORT_SYMBOL(lpfc_fc_security_dhchap_make_response); ++ ++ ++/** ++ * lpfc_fc_security_dhchap_authenticate ++ * ++ * ++ **/ ++ ++int ++lpfc_fc_security_dhchap_authenticate(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 auth_req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 auth_rsp_len) ++{ ++ ++ return(lpfc_fc_sc_request((struct lpfc_vport *) shost->hostdata, ++ FC_NL_SC_DHCHAP_AUTHENTICATE_REQ, ++ auth_req, auth_req_len, auth_rsp, auth_rsp_len)); ++ ++} ++EXPORT_SYMBOL(lpfc_fc_security_dhchap_authenticate); ++ ++/** ++ * lpfc_fc_queue_security_work - Queue work to the fc_host security workqueue. ++ * @shost: Pointer to Scsi_Host bound to fc_host. ++ * @work: Work to queue for execution. ++ * ++ * Return value: ++ * 1 - work queued for execution ++ * 0 - work is already queued ++ * -EINVAL - work queue doesn't exist ++ **/ ++int ++lpfc_fc_queue_security_work(struct lpfc_vport *vport, struct work_struct *work) ++{ ++ if (unlikely(!security_work_q)) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1021 ERROR: attempted to queue security work, " ++ "when no workqueue created.\n"); ++ dump_stack(); ++ ++ return -EINVAL; ++ } ++ ++ return queue_work(security_work_q, work); ++ ++} ++ ++ ++ ++ /** ++ * lpfc_fc_sc_schedule_notify_all ++ * ++ * ++ **/ ++ ++void ++lpfc_fc_sc_schedule_notify_all(int message) ++{ ++ struct lpfc_vport *vport; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fc_security_user_lock, flags); ++ ++ list_for_each_entry(vport, &fc_security_user_list, sc_users) { ++ ++ switch (message) { ++ ++ case FC_NL_SC_REG: ++ lpfc_fc_queue_security_work(vport, ++ &vport->sc_online_work); ++ break; ++ ++ case FC_NL_SC_DEREG: ++ lpfc_fc_queue_security_work(vport, ++ &vport->sc_offline_work); ++ break; ++ } ++ } ++ ++ spin_unlock_irqrestore(&fc_security_user_lock, flags); ++} ++ ++ ++ ++/** ++ * lpfc_fc_sc_security_online ++ * ++ * ++ **/ ++ ++void ++lpfc_fc_sc_security_online(struct work_struct *work) ++{ ++ struct lpfc_vport *vport = container_of(work, struct lpfc_vport, ++ sc_online_work); ++ lpfc_security_service_online(lpfc_shost_from_vport(vport)); ++ return; ++} ++ ++/** ++ * lpfc_fc_sc_security_offline ++ * ++ * ++ **/ ++void ++lpfc_fc_sc_security_offline(struct work_struct *work) ++{ ++ struct lpfc_vport *vport = container_of(work, struct lpfc_vport, ++ sc_offline_work); ++ lpfc_security_service_offline(lpfc_shost_from_vport(vport)); ++ return; ++} ++ ++ ++/** ++ * lpfc_fc_sc_process_msg ++ * ++ * ++ **/ ++static void ++lpfc_fc_sc_process_msg(struct work_struct *work) ++{ ++ struct fc_sc_msg_work_q_wrapper *wqw = ++ container_of(work, struct fc_sc_msg_work_q_wrapper, work); ++ ++ switch (wqw->msgtype) { ++ ++ case FC_NL_SC_GET_CONFIG_RSP: ++ lpfc_security_config(lpfc_shost_from_vport(wqw->fc_sc_req-> ++ vport), wqw->status, ++ wqw->fc_sc_req->data); ++ break; ++ ++ case FC_NL_SC_DHCHAP_MAKE_CHALLENGE_RSP: ++ lpfc_dhchap_make_challenge(lpfc_shost_from_vport(wqw-> ++ fc_sc_req->vport), wqw->status, ++ wqw->fc_sc_req->data, wqw->data_len); ++ break; ++ ++ case FC_NL_SC_DHCHAP_MAKE_RESPONSE_RSP: ++ lpfc_dhchap_make_response(lpfc_shost_from_vport(wqw-> ++ fc_sc_req->vport), wqw->status, ++ wqw->fc_sc_req->data, wqw->data_len); ++ break; ++ ++ case FC_NL_SC_DHCHAP_AUTHENTICATE_RSP: ++ lpfc_dhchap_authenticate(lpfc_shost_from_vport(wqw->fc_sc_req-> ++ vport), ++ wqw->status, ++ wqw->fc_sc_req->data, wqw->data_len); ++ break; ++ } ++ ++ kfree(wqw->fc_sc_req); ++ kfree(wqw); ++ ++ return; ++} ++ ++ ++/** ++ * lpfc_fc_sc_schedule_msg ++ * ++ * ++ **/ ++ ++int ++lpfc_fc_sc_schedule_msg(struct Scsi_Host *shost, ++ struct fc_nl_sc_message *fc_nl_sc_msg, int rcvlen) ++{ ++ struct fc_security_request *fc_sc_req; ++ u32 req_type; ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ int err = 0; ++ struct fc_sc_msg_work_q_wrapper *wqw; ++ unsigned long flags; ++ ++ if (vport->port_state == FC_PORTSTATE_DELETED) { ++ printk(KERN_WARNING ++ "%s: Host being deleted.\n", __func__); ++ return -EBADR; ++ } ++ ++ wqw = kzalloc(sizeof(struct fc_sc_msg_work_q_wrapper), GFP_KERNEL); ++ ++ if (!wqw) ++ return -ENOMEM; ++ ++ switch (fc_nl_sc_msg->msgtype) { ++ case FC_NL_SC_GET_CONFIG_RSP: ++ req_type = FC_NL_SC_GET_CONFIG_REQ; ++ break; ++ ++ case FC_NL_SC_DHCHAP_MAKE_CHALLENGE_RSP: ++ req_type = FC_NL_SC_DHCHAP_MAKE_CHALLENGE_REQ; ++ break; ++ ++ case FC_NL_SC_DHCHAP_MAKE_RESPONSE_RSP: ++ req_type = FC_NL_SC_DHCHAP_MAKE_RESPONSE_REQ; ++ break; ++ ++ case FC_NL_SC_DHCHAP_AUTHENTICATE_RSP: ++ req_type = FC_NL_SC_DHCHAP_AUTHENTICATE_REQ; ++ break; ++ ++ default: ++ kfree(wqw); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ ++ fc_sc_req = lpfc_fc_find_sc_request(fc_nl_sc_msg->tran_id, ++ req_type, vport); ++ ++ if (!fc_sc_req) { ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, ++ "1022 Security request does not exist.\n"); ++ kfree(wqw); ++ return -EBADR; ++ } ++ ++ list_del(&fc_sc_req->rlist); ++ ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ del_singleshot_timer_sync(&fc_sc_req->timer); ++ ++ wqw->status = 0; ++ wqw->fc_sc_req = fc_sc_req; ++ wqw->data_len = rcvlen; ++ wqw->msgtype = fc_nl_sc_msg->msgtype; ++ ++ if (!fc_sc_req->data || ++ (fc_sc_req->data_len < fc_nl_sc_msg->data_len)) { ++ wqw->status = -ENOBUFS; ++ wqw->data_len = 0; ++ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, ++ "1023 Warning - data may have been truncated. " ++ "data:%p reqdl:%x mesdl:%x\n", ++ fc_sc_req->data, ++ fc_sc_req->data_len, fc_nl_sc_msg->data_len); ++ } else { ++ memcpy(fc_sc_req->data, fc_nl_sc_msg->data, ++ fc_nl_sc_msg->data_len); ++ } ++ ++ INIT_WORK(&wqw->work, lpfc_fc_sc_process_msg); ++ lpfc_fc_queue_security_work(vport, &wqw->work); ++ ++ return err; ++} ++ ++int ++lpfc_rcv_nl_msg(struct Scsi_Host *shost, void *payload, ++ uint32_t len, uint32_t pid) ++{ ++ struct fc_nl_sc_message *msg = (struct fc_nl_sc_message *)payload; ++ int err = 0; ++ ++ switch (msg->msgtype) { ++ case FC_NL_SC_REG: ++ fc_service_pid = pid; ++ fc_service_state = FC_SC_SERVICESTATE_ONLINE; ++ lpfc_fc_sc_schedule_notify_all(FC_NL_SC_REG); ++ break; ++ case FC_NL_SC_DEREG: ++ fc_service_pid = pid; ++ fc_service_state = FC_SC_SERVICESTATE_OFFLINE; ++ lpfc_fc_sc_schedule_notify_all(FC_NL_SC_DEREG); ++ break; ++ case FC_NL_SC_GET_CONFIG_RSP: ++ case FC_NL_SC_DHCHAP_MAKE_CHALLENGE_RSP: ++ case FC_NL_SC_DHCHAP_MAKE_RESPONSE_RSP: ++ case FC_NL_SC_DHCHAP_AUTHENTICATE_RSP: ++ err = lpfc_fc_sc_schedule_msg(shost, msg, len); ++ break; ++ default: ++ printk(KERN_WARNING "%s: unknown msg type 0x%x len %d\n", ++ __func__, msg->msgtype, len); ++ break; ++ } ++ return err; ++} ++ ++void ++lpfc_rcv_nl_event(struct notifier_block *this, ++ unsigned long event, ++ void *ptr) ++{ ++ struct netlink_notify *n = ptr; ++ if ((event == NETLINK_URELEASE) && ++ (n->protocol == NETLINK_SCSITRANSPORT) && (n->pid)) { ++ printk(KERN_WARNING "Warning - Security Service Offline\n"); ++ fc_service_state = FC_SC_SERVICESTATE_OFFLINE; ++ lpfc_fc_sc_schedule_notify_all(FC_NL_SC_DEREG); ++ } ++} +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_auth_access.h +@@ -0,0 +1,245 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2007 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) ++ ++/* scsi_nl_hdr->version value */ ++#define SCSI_NL_VERSION 1 ++ ++/* scsi_nl_hdr->magic value */ ++#define SCSI_NL_MAGIC 0xA1B2 ++ ++/* scsi_nl_hdr->transport value */ ++#define SCSI_NL_TRANSPORT 0 ++#define SCSI_NL_TRANSPORT_FC 1 ++#define SCSI_NL_MAX_TRANSPORTS 2 ++ ++#define FC_NL_GROUP_CNT 0 ++ ++ /* Note: when specifying vendor_id to fc_host_post_vendor_event() ++ * be sure to read the Vendor Type and ID formatting requirements ++ * specified in scsi_netlink.h ++ */ ++ ++#define FC_SC_REQ_TIMEOUT (60*HZ) ++ ++enum fc_sc_service_state { ++ FC_SC_SERVICESTATE_UNKNOWN, ++ FC_SC_SERVICESTATE_ONLINE, ++ FC_SC_SERVICESTATE_OFFLINE, ++ FC_SC_SERVICESTATE_ERROR, ++}; ++ ++struct fc_security_request { ++ struct list_head rlist; ++ int pid; ++ u32 tran_id; ++ u32 req_type; ++ struct timer_list timer; ++ struct lpfc_vport *vport; ++ u32 data_len; ++ void *data; ++}; ++ ++struct fc_sc_msg_work_q_wrapper { ++ struct work_struct work; ++ struct fc_security_request *fc_sc_req; ++ u32 data_len; ++ int status; ++ u32 msgtype; ++}; ++struct fc_sc_notify_work_q_wrapper { ++ struct work_struct work; ++ struct Scsi_Host *shost; ++ int msg; ++}; ++ ++#define FC_DHCHAP 1 ++#define FC_FCAP 2 ++#define FC_FCPAP 3 ++#define FC_KERBEROS 4 ++ ++#define FC_AUTHMODE_UNKNOWN 0 ++#define FC_AUTHMODE_NONE 1 ++#define FC_AUTHMODE_ACTIVE 2 ++#define FC_AUTHMODE_PASSIVE 3 ++ ++#define FC_SP_HASH_MD5 0x5 ++#define FC_SP_HASH_SHA1 0x6 ++ ++#define DH_GROUP_NULL 0x00 ++#define DH_GROUP_1024 0x01 ++#define DH_GROUP_1280 0x02 ++#define DH_GROUP_1536 0x03 ++#define DH_GROUP_2048 0x04 ++ ++#define MAX_AUTH_REQ_SIZE 1024 ++#define MAX_AUTH_RSP_SIZE 1024 ++ ++#define AUTH_FABRIC_WWN 0xFFFFFFFFFFFFFFFFLL ++ ++struct fc_auth_req { ++ uint64_t local_wwpn; ++ uint64_t remote_wwpn; ++ union { ++ struct dhchap_challenge_req { ++ uint32_t transaction_id; ++ uint32_t dh_group_id; ++ uint32_t hash_id; ++ } dhchap_challenge; ++ struct dhchap_reply_req { ++ uint32_t transaction_id; ++ uint32_t dh_group_id; ++ uint32_t hash_id; ++ uint32_t bidirectional; ++ uint32_t received_challenge_len; ++ uint32_t received_public_key_len; ++ uint8_t data[0]; ++ } dhchap_reply; ++ struct dhchap_success_req { ++ uint32_t transaction_id; ++ uint32_t dh_group_id; ++ uint32_t hash_id; ++ uint32_t our_challenge_len; ++ uint32_t received_response_len; ++ uint32_t received_public_key_len; ++ uint32_t received_challenge_len; ++ uint8_t data[0]; ++ } dhchap_success; ++ }u; ++} __attribute__ ((packed)); ++ ++struct fc_auth_rsp { ++ uint64_t local_wwpn; ++ uint64_t remote_wwpn; ++ union { ++ struct authinfo { ++ uint8_t auth_mode; ++ uint16_t auth_timeout; ++ uint8_t bidirectional; ++ uint8_t type_priority[4]; ++ uint16_t type_len; ++ uint8_t hash_priority[4]; ++ uint16_t hash_len; ++ uint8_t dh_group_priority[8]; ++ uint16_t dh_group_len; ++ uint32_t reauth_interval; ++ } dhchap_security_config; ++ struct dhchap_challenge_rsp { ++ uint32_t transaction_id; ++ uint32_t our_challenge_len; ++ uint32_t our_public_key_len; ++ uint8_t data[0]; ++ } dhchap_challenge; ++ struct dhchap_reply_rsp { ++ uint32_t transaction_id; ++ uint32_t our_challenge_rsp_len; ++ uint32_t our_public_key_len; ++ uint32_t our_challenge_len; ++ uint8_t data[0]; ++ } dhchap_reply; ++ struct dhchap_success_rsp { ++ uint32_t transaction_id; ++ uint32_t authenticated; ++ uint32_t response_len; ++ uint8_t data[0]; ++ } dhchap_success; ++ }u; ++}__attribute__ ((packed)); ++ ++int ++lpfc_fc_security_get_config(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 rsp_len); ++int ++lpfc_fc_security_dhchap_make_challenge(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 rsp_len); ++int ++lpfc_fc_security_dhchap_make_response(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 rsp_len); ++int ++lpfc_fc_security_dhchap_authenticate(struct Scsi_Host *shost, ++ struct fc_auth_req *auth_req, ++ u32 req_len, ++ struct fc_auth_rsp *auth_rsp, ++ u32 rsp_len); ++ ++int lpfc_fc_queue_security_work(struct lpfc_vport *, ++ struct work_struct *); ++ ++/* ++ * FC Transport Message Types ++ */ ++ /* user -> kernel */ ++#define FC_NL_EVENTS_REG 0x0001 ++#define FC_NL_EVENTS_DEREG 0x0002 ++#define FC_NL_SC_REG 0x0003 ++#define FC_NL_SC_DEREG 0x0004 ++#define FC_NL_SC_GET_CONFIG_RSP 0x0005 ++#define FC_NL_SC_SET_CONFIG_RSP 0x0006 ++#define FC_NL_SC_DHCHAP_MAKE_CHALLENGE_RSP 0x0007 ++#define FC_NL_SC_DHCHAP_MAKE_RESPONSE_RSP 0x0008 ++#define FC_NL_SC_DHCHAP_AUTHENTICATE_RSP 0x0009 ++ /* kernel -> user */ ++//#define FC_NL_ASYNC_EVENT 0x0100 ++#define FC_NL_SC_GET_CONFIG_REQ 0x0020 ++#define FC_NL_SC_SET_CONFIG_REQ 0x0030 ++#define FC_NL_SC_DHCHAP_MAKE_CHALLENGE_REQ 0x0040 ++#define FC_NL_SC_DHCHAP_MAKE_RESPONSE_REQ 0x0050 ++#define FC_NL_SC_DHCHAP_AUTHENTICATE_REQ 0x0060 ++ ++/* ++ * Message Structures : ++ */ ++ ++/* macro to round up message lengths to 8byte boundary */ ++#define FC_NL_MSGALIGN(len) (((len) + 7) & ~7) ++ ++#define FC_NETLINK_API_VERSION 1 ++ ++/* Single Netlink Message type to send all FC Transport messages */ ++#define FC_TRANSPORT_MSG NLMSG_MIN_TYPE + 1 ++ ++/* SCSI_TRANSPORT_MSG event message header */ ++/* ++struct scsi_nl_hdr { ++ uint8_t version; ++ uint8_t transport; ++ uint16_t magic; ++ uint16_t msgtype; ++ uint16_t msglen; ++} __attribute__((aligned(sizeof(uint64_t)))); ++*/ ++struct fc_nl_sc_message { ++ uint16_t msgtype; ++ uint16_t rsvd; ++ uint32_t tran_id; ++ uint32_t data_len; ++ uint8_t data[0]; ++} __attribute__((aligned(sizeof(uint64_t)))); ++ +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_auth.c +@@ -0,0 +1,838 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2008 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++/* See Fibre Channel protocol T11 FC-SP for details */ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "lpfc_hw.h" ++#include "lpfc_sli.h" ++#include "lpfc_nl.h" ++#include "lpfc_disc.h" ++#include "lpfc.h" ++#include "lpfc_crtn.h" ++#include "lpfc_logmsg.h" ++#include "lpfc_auth_access.h" ++#include "lpfc_auth.h" ++ ++void ++lpfc_start_authentication(struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp) ++{ ++ uint32_t nego_payload_len; ++ uint8_t *nego_payload; ++ ++ nego_payload = kmalloc(MAX_AUTH_REQ_SIZE, GFP_KERNEL); ++ if (!nego_payload) ++ return; ++ vport->auth.trans_id++; ++ vport->auth.auth_msg_state = LPFC_AUTH_NEGOTIATE; ++ nego_payload_len = lpfc_build_auth_neg(vport, nego_payload); ++ lpfc_issue_els_auth(vport, ndlp, AUTH_NEGOTIATE, ++ nego_payload, nego_payload_len); ++ kfree(nego_payload); ++} ++ ++void ++lpfc_dhchap_make_challenge(struct Scsi_Host *shost, int status, ++ void *rsp, uint32_t rsp_len) ++{ ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_nodelist *ndlp; ++ uint32_t chal_payload_len; ++ uint8_t *chal_payload; ++ struct fc_auth_rsp *auth_rsp = rsp; ++ ++ ndlp = lpfc_findnode_did(vport, Fabric_DID); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { ++ kfree(rsp); ++ return; ++ } ++ ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, ++ "1003 Send dhchap challenge local_wwpn " ++ "%llX remote_wwpn %llX \n", ++ (unsigned long long)auth_rsp->local_wwpn, ++ (unsigned long long)auth_rsp->remote_wwpn); ++ ++ chal_payload = kmalloc(MAX_AUTH_REQ_SIZE, GFP_KERNEL); ++ if (!chal_payload) { ++ kfree(rsp); ++ return; ++ } ++ vport->auth.auth_msg_state = LPFC_DHCHAP_CHALLENGE; ++ chal_payload_len = lpfc_build_dhchap_challenge(vport, ++ chal_payload, rsp); ++ lpfc_issue_els_auth(vport, ndlp, DHCHAP_CHALLENGE, ++ chal_payload, chal_payload_len); ++ kfree(chal_payload); ++ kfree(rsp); ++} ++ ++ ++void ++lpfc_dhchap_make_response(struct Scsi_Host *shost, int status, ++ void *rsp, uint32_t rsp_len) ++{ ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_nodelist *ndlp; ++ uint32_t reply_payload_len; ++ uint8_t *reply_payload; ++ struct fc_auth_rsp *auth_rsp = rsp; ++ ++ ndlp = lpfc_findnode_did(vport, Fabric_DID); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { ++ kfree(rsp); ++ return; ++ } ++ ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, ++ "1004 Send dhchap reply local_wwpn " ++ "%llX remote_wwpn %llX \n", ++ (unsigned long long)auth_rsp->local_wwpn, ++ (unsigned long long)auth_rsp->remote_wwpn); ++ ++ reply_payload = kmalloc(MAX_AUTH_REQ_SIZE, GFP_KERNEL); ++ if (!reply_payload) { ++ kfree(rsp); ++ return; ++ } ++ ++ vport->auth.auth_msg_state = LPFC_DHCHAP_REPLY; ++ reply_payload_len = lpfc_build_dhchap_reply(vport, reply_payload, rsp); ++ lpfc_issue_els_auth(vport, ndlp, DHCHAP_REPLY, ++ reply_payload, reply_payload_len); ++ kfree(reply_payload); ++ kfree(rsp); ++ ++} ++ ++ ++void ++lpfc_dhchap_authenticate(struct Scsi_Host *shost, ++ int status, void *rsp, ++ uint32_t rsp_len) ++{ ++ struct fc_auth_rsp *auth_rsp = (struct fc_auth_rsp *)rsp; ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_nodelist *ndlp; ++ ++ ndlp = lpfc_findnode_did(vport, Fabric_DID); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { ++ kfree(rsp); ++ return; ++ } ++ if (status != 0) { ++ lpfc_issue_els_auth_reject(vport, ndlp, ++ AUTH_ERR, AUTHENTICATION_FAILED); ++ kfree(rsp); ++ return; ++ } ++ ++ if (auth_rsp->u.dhchap_success.authenticated) { ++ uint32_t suc_payload_len; ++ uint8_t *suc_payload; ++ ++ suc_payload = kmalloc(MAX_AUTH_REQ_SIZE, GFP_KERNEL); ++ if (!suc_payload) { ++ lpfc_issue_els_auth_reject(vport, ndlp, ++ AUTH_ERR, AUTHENTICATION_FAILED); ++ kfree(rsp); ++ return; ++ } ++ suc_payload_len = lpfc_build_dhchap_success(vport, ++ suc_payload, rsp); ++ if (suc_payload_len == sizeof(uint32_t)) { ++ /* Authentication is complete after sending this SUCCESS */ ++ vport->auth.auth_msg_state = LPFC_DHCHAP_SUCCESS; ++ } else { ++ /* Need to wait for SUCCESS from Auth Initiator */ ++ vport->auth.auth_msg_state = LPFC_DHCHAP_SUCCESS_REPLY; ++ } ++ lpfc_issue_els_auth(vport, ndlp, DHCHAP_SUCCESS, ++ suc_payload, suc_payload_len); ++ kfree(suc_payload); ++ vport->auth.direction |= AUTH_DIRECTION_LOCAL; ++ } else { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1005 AUTHENTICATION_FAILURE Nport:x%x\n", ++ ndlp->nlp_DID); ++ lpfc_issue_els_auth_reject(vport, ndlp, ++ AUTH_ERR, AUTHENTICATION_FAILED); ++ if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) { ++ lpfc_port_auth_failed(ndlp); ++ } ++ } ++ ++ kfree(rsp); ++} ++ ++int ++lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, ++ uint8_t *reason, uint8_t *explanation) ++{ ++ uint32_t prot_len; ++ uint32_t param_len; ++ int i, j = 0; ++ ++ /* Following is the format of the message. Name Format. ++ * uint16_t nameTag; ++ * uint16_t nameLength; ++ * uint8_t name[8]; ++ * AUTH_Negotiate Message ++ * uint32_t NumberOfAuthProtocals ++ * uint32_t AuthProtParameter#1Len ++ * uint32_t AuthProtID#1 (DH-CHAP = 0x1) ++ * AUTH_Negotiate DH-CHAP ++ * uint16_t DH-CHAPParameterTag (HashList = 0x1) ++ * uint16_t DH-CHAPParameterWordCount (number of uint32_t entries) ++ * uint8_t DH-CHAPParameter[]; (uint32_t entries) ++ * uint16_t DH-CHAPParameterTag (DHglDList = 0x2) ++ * uint16_t DH-CHAPParameterWordCount (number of uint32_t entries) ++ * uint8_t DH-CHAPParameter[]; (uint32_t entries) ++ * DHCHAP_Challenge Message ++ * uint32_t hashIdentifier; ++ * uint32_t dhgroupIdentifier; ++ * uint32_t challengevalueLen; ++ * uint8_t challengeValue[]; ++ * uint32_t dhvalueLen; ++ * uint8_t dhvalue[]; ++ */ ++ ++ /* Name Tag */ ++ if (be16_to_cpu(*(uint16_t *)message) != NAME_TAG) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1006 Bad Name tag in auth message 0x%x\n", ++ be16_to_cpu(*(uint16_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint16_t); ++ ++ /* Name Length */ ++ if (be16_to_cpu(*(uint16_t *)message) != NAME_LEN) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1007 Bad Name length in auth message 0x%x\n", ++ be16_to_cpu(*(uint16_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint16_t); ++ ++ /* Skip over Remote Port Name */ ++ message += NAME_LEN; ++ ++ /* Number of Auth Protocols must be 1 DH-CHAP */ ++ if (be32_to_cpu(*(uint32_t *)message) != 1) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1008 Bad Number of Protocols 0x%x\n", ++ be32_to_cpu(*(uint32_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint32_t); ++ ++ /* Protocol Parameter Length */ ++ prot_len = be32_to_cpu(*(uint32_t *)message); ++ message += sizeof(uint32_t); ++ ++ /* Protocol Parameter type */ ++ if (be32_to_cpu(*(uint32_t *)message) != FC_DHCHAP) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1009 Bad param type 0x%x\n", ++ be32_to_cpu(*(uint32_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint32_t); ++ ++ /* Parameter #1 Tag */ ++ if (be16_to_cpu(*(uint16_t *)message) != HASH_LIST_TAG) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1010 Bad Tag 1 0x%x\n", ++ be16_to_cpu(*(uint16_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint16_t); ++ ++ /* Parameter #1 Length */ ++ param_len = be16_to_cpu(*(uint16_t *)message); ++ message += sizeof(uint16_t); ++ ++ /* Choose a hash function */ ++ for (i = 0; i < vport->auth.hash_len; i++) { ++ for (j = 0; j < param_len; j++) { ++ if (vport->auth.hash_priority[i] == ++ be32_to_cpu(((uint32_t *)message)[j])) ++ break; ++ } ++ if (j != param_len) ++ break; ++ } ++ if (i == vport->auth.hash_len && j == param_len) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1011 Auth_neg no hash function chosen.\n"); ++ return 1; ++ } ++ vport->auth.hash_id = vport->auth.hash_priority[i]; ++ message += sizeof(uint32_t) * param_len; ++ ++ /* Parameter #2 Tag */ ++ if (be16_to_cpu(*(uint16_t *)message) != DHGID_LIST_TAG) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1012 Auth_negotiate Bad Tag 2 0x%x\n", ++ be16_to_cpu(*(uint16_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint16_t); ++ ++ /* Parameter #2 Length */ ++ param_len = be16_to_cpu(*(uint16_t *)message); ++ message += sizeof(uint16_t); ++ ++ /* Choose a DH Group */ ++ for (i = 0; i < vport->auth.dh_group_len; i++) { ++ for (j = 0; j < param_len; j++) { ++ if (vport->auth.dh_group_priority[i] == ++ be32_to_cpu(((uint32_t *)message)[j])) ++ break; ++ } ++ if (j != param_len) ++ break; ++ } ++ if (i == vport->auth.dh_group_len && j == param_len) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1013 Auth_negotiate no DH_group found. \n"); ++ return 1; ++ } ++ vport->auth.group_id = vport->auth.dh_group_priority[i]; ++ message += sizeof(uint32_t) * param_len; ++ ++ return 0; ++} ++ ++int ++lpfc_unpack_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, ++ uint8_t *reason, uint8_t *explanation) ++{ ++ int i; ++ ++ /* Following is the format of the message DHCHAP_Challenge. ++ * uint16_t nameTag; ++ * uint16_t nameLength; ++ * uint8_t name[8]; ++ * uint32_t hashIdentifier; ++ * uint32_t dhgroupIdentifier; ++ * uint32_t challengevalueLen; ++ * uint8_t challengeValue[]; ++ * uint32_t dhvalueLen; ++ * uint8_t dhvalue[]; ++ */ ++ ++ /* Name Tag */ ++ if (be16_to_cpu(*(uint16_t *)message) != NAME_TAG) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1014 dhchap challenge bad name tag 0x%x. \n", ++ be16_to_cpu(*(uint16_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint16_t); ++ ++ /* Name Length */ ++ if (be16_to_cpu(*(uint16_t *)message) != NAME_LEN) { ++ *reason = AUTH_ERR; ++ *explanation = BAD_PAYLOAD; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1015 dhchap challenge bad name length " ++ "0x%x.\n", be16_to_cpu(*(uint16_t *)message)); ++ return 1; ++ } ++ message += sizeof(uint16_t); ++ ++ /* Remote Port Name */ ++ message += NAME_LEN; ++ ++ /* Hash ID */ ++ vport->auth.hash_id = be32_to_cpu(*(uint32_t *)message); /* Hash id */ ++ for (i = 0; i < vport->auth.hash_len; i++) { ++ if (vport->auth.hash_id == vport->auth.hash_priority[i]) ++ break; ++ } ++ if (i == vport->auth.hash_len) { ++ *reason = LOGIC_ERR; ++ *explanation = BAD_ALGORITHM; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1016 dhchap challenge Hash ID not Supported " ++ "0x%x. \n", vport->auth.hash_id); ++ return 1; ++ } ++ message += sizeof(uint32_t); ++ ++ vport->auth.group_id = ++ be32_to_cpu(*(uint32_t *)message); /* DH group id */ ++ for (i = 0; i < vport->auth.dh_group_len; i++) { ++ if (vport->auth.group_id == vport->auth.dh_group_priority[i]) ++ break; ++ } ++ if (i == vport->auth.dh_group_len) { ++ *reason = LOGIC_ERR; ++ *explanation = BAD_DHGROUP; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1017 dhchap challenge could not find DH " ++ "Group. \n"); ++ return 1; ++ } ++ message += sizeof(uint32_t); ++ ++ vport->auth.challenge_len = ++ be32_to_cpu(*(uint32_t *)message); /* Challenge Len */ ++ message += sizeof(uint32_t); ++ ++ /* copy challenge to vport */ ++ if (vport->auth.challenge != NULL) { ++ kfree(vport->auth.challenge); ++ } ++ vport->auth.challenge = kmalloc(vport->auth.challenge_len, GFP_KERNEL); ++ if (!vport->auth.challenge) { ++ *reason = AUTH_ERR; ++ return 1; ++ } ++ memcpy (vport->auth.challenge, message, vport->auth.challenge_len); ++ message += vport->auth.challenge_len; ++ ++ vport->auth.dh_pub_key_len = ++ be32_to_cpu(*(uint32_t *)message); /* DH Value Len */ ++ message += sizeof(uint32_t); ++ ++ if (vport->auth.dh_pub_key_len != 0) { ++ if (vport->auth.group_id == DH_GROUP_NULL) { ++ *reason = LOGIC_ERR; ++ *explanation = BAD_DHGROUP; ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1018 dhchap challenge No Public key " ++ "for non-NULL DH Group.\n"); ++ return 1; ++ } ++ ++ /* Copy to the vport to save for authentication */ ++ if (vport->auth.dh_pub_key != NULL) ++ kfree(vport->auth.dh_pub_key); ++ vport->auth.dh_pub_key = kmalloc(vport->auth.dh_pub_key_len, ++ GFP_KERNEL); ++ if (!vport->auth.dh_pub_key) { ++ *reason = AUTH_ERR; ++ return 1; ++ } ++ memcpy(vport->auth.dh_pub_key, message, ++ vport->auth.dh_pub_key_len); ++ } ++ return 0; ++} ++ ++int ++lpfc_unpack_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_req *fc_req) ++{ ++ uint32_t rsp_len; ++ uint32_t dh_len; ++ uint32_t challenge_len; ++ ++ /* Following is the format of the message DHCHAP_Reply. ++ * uint32_t Response Value Length; ++ * uint8_t Response Value[]; ++ * uint32_t DH Value Length; ++ * uint8_t DH Value[]; ++ * uint32_t Challenge Value Length; ++ * uint8_t Challenge Value[]; ++ */ ++ ++ rsp_len = be32_to_cpu(*(uint32_t *)message); /* Response Len */ ++ message += sizeof(uint32_t); ++ memcpy (fc_req->u.dhchap_success.data + vport->auth.challenge_len, ++ message, rsp_len); ++ fc_req->u.dhchap_success.received_response_len = rsp_len; ++ message += rsp_len; ++ ++ dh_len = be32_to_cpu(*(uint32_t *)message); /* DH Len */ ++ message += sizeof(uint32_t); ++ memcpy (fc_req->u.dhchap_success.data + vport->auth.challenge_len + ++ rsp_len, message, dh_len); ++ fc_req->u.dhchap_success.received_public_key_len = dh_len; ++ message += dh_len; ++ ++ challenge_len = be32_to_cpu(*(uint32_t *)message); /* Challenge Len */ ++ message += sizeof(uint32_t); ++ memcpy (fc_req->u.dhchap_success.data + vport->auth.challenge_len ++ + rsp_len + dh_len, ++ message, challenge_len); ++ fc_req->u.dhchap_success.received_challenge_len = challenge_len; ++ message += challenge_len; ++ ++ return (rsp_len + dh_len + challenge_len); ++} ++ ++int ++lpfc_unpack_dhchap_success(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_req *fc_req) ++{ ++ uint32_t rsp_len = 0; ++ ++ /* DHCHAP_Success. ++ * uint32_t responseValueLen; ++ * uint8_t response[]; ++ */ ++ ++ rsp_len = be32_to_cpu(*(uint32_t *)message); /* Response Len */ ++ message += sizeof(uint32_t); ++ memcpy(fc_req->u.dhchap_success.data + vport->auth.challenge_len, ++ message, rsp_len); ++ fc_req->u.dhchap_success.received_response_len = rsp_len; ++ ++ memcpy(fc_req->u.dhchap_success.data + ++ vport->auth.challenge_len + rsp_len, ++ vport->auth.dh_pub_key, vport->auth.dh_pub_key_len); ++ ++ fc_req->u.dhchap_success.received_public_key_len = ++ vport->auth.dh_pub_key_len; ++ ++ fc_req->u.dhchap_success.received_challenge_len = 0; ++ ++ return (vport->auth.challenge_len + rsp_len + ++ vport->auth.dh_pub_key_len); ++ return 0; ++} ++ ++int ++lpfc_build_auth_neg(struct lpfc_vport *vport, uint8_t *message) ++{ ++ uint8_t *message_start = message; ++ uint8_t *params_start; ++ uint32_t *params_len; ++ uint32_t len; ++ int i; ++ ++ /* Because some of the fields are not static in length ++ * and number we will pack on the fly.This will be expanded ++ * in the future to optionally offer DHCHAP or FCAP or both. ++ * The packing is done in Big Endian byte order DHCHAP_Reply. ++ * ++ * uint16_t nameTag; ++ * uint16_t nameLength; ++ * uint8_t name[8]; ++ * uint32_t available; For now we will only offer one ++ protocol ( DHCHAP ) for authentication. ++ * uint32_t potocolParamsLenId#1; ++ * uint32_t protocolId#1; 1 : DHCHAP. The protocol list is ++ * in order of preference. ++ * uint16_t parameter#1Tag 1 : HashList ++ * uint16_t parameter#1Len 2 : Count of how many parameter values ++ * follow in order of preference. ++ * uint16_t parameter#1value#1 5 : MD5 Hash Function ++ * uint16_t parameter#1value#2 6 : SHA-1 Hash Function ++ * uint16_t parameter#2Tag 2 : DHglDList ++ * uint16_t parameter#2Len 1 : Only One is supported now ++ * uint16_t parameter#2value#1 0 : NULL DH-CHAP Algorithm ++ * uint16_t parameter#2value#2 ... ++ * uint32_t protocolParamsLenId#2; ++ * uint32_t protocolId#2; 2 = FCAP ++ * uint16_t parameter#1Tag ++ * uint16_t parameter#1Len ++ * uint16_t parameter#1value#1 ++ * uint16_t parameter#1value#2 ... ++ * uint16_t parameter#2Tag ++ * uint16_t parameter#2Len ++ * uint16_t parameter#2value#1 ++ * uint16_t parameter#2value#2 ... ++ */ ++ ++ ++ /* Name Tag */ ++ *((uint16_t *)message) = cpu_to_be16(NAME_TAG); ++ message += sizeof(uint16_t); ++ ++ /* Name Len */ ++ *((uint16_t *)message) = cpu_to_be16(NAME_LEN); ++ message += sizeof(uint16_t); ++ ++ memcpy(message, vport->fc_portname.u.wwn, sizeof(uint64_t)); ++ ++ message += sizeof(uint64_t); ++ ++ /* Protocols Available */ ++ *((uint32_t *)message) = cpu_to_be32(PROTS_NUM); ++ message += sizeof(uint32_t); ++ ++ /* First Protocol Params Len */ ++ params_len = (uint32_t *)message; ++ message += sizeof(uint32_t); ++ ++ /* Start of first Param */ ++ params_start = message; ++ ++ /* Protocol Id */ ++ *((uint32_t *)message) = cpu_to_be32(FC_DHCHAP); ++ message += sizeof(uint32_t); ++ ++ /* Hash List Tag */ ++ *((uint16_t *)message) = cpu_to_be16(HASH_LIST_TAG); ++ message += sizeof(uint16_t); ++ ++ /* Hash Value Len */ ++ *((uint16_t *)message) = cpu_to_be16(vport->auth.hash_len); ++ message += sizeof(uint16_t); ++ ++ /* Hash Value each 4 byte words */ ++ for (i = 0; i < vport->auth.hash_len; i++) { ++ *((uint32_t *)message) = ++ cpu_to_be32(vport->auth.hash_priority[i]); ++ message += sizeof(uint32_t); ++ } ++ ++ /* DHgIDList Tag */ ++ *((uint16_t *)message) = cpu_to_be16(DHGID_LIST_TAG); ++ message += sizeof(uint16_t); ++ ++ /* DHgIDListValue Len */ ++ *((uint16_t *)message) = cpu_to_be16(vport->auth.dh_group_len); ++ ++ message += sizeof(uint16_t); ++ ++ /* DHgIDList each 4 byte words */ ++ ++ for (i = 0; i < vport->auth.dh_group_len; i++) { ++ *((uint32_t *)message) = ++ cpu_to_be32(vport->auth.dh_group_priority[i]); ++ message += sizeof(uint32_t); ++ } ++ ++ *params_len = cpu_to_be32(message - params_start); ++ ++ len = (uint32_t)(message - message_start); ++ ++ return len; ++} ++ ++int ++lpfc_build_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_rsp *fc_rsp) ++{ ++ uint8_t *message_start = message; ++ ++ /* Because some of the fields are not static in length and number ++ * we will pack on the fly. The packing is done in Big Endian byte ++ * order DHCHAP_Challenge. ++ * ++ * uint16_t nameTag; ++ * uint16_t nameLength; ++ * uint8_t name[8]; ++ * uint32_t Hash_Identifier; ++ * uint32_t DH_Group_Identifier; ++ * uint32_t Challenge_Value_Length; ++ * uint8_t Challenge_Value[]; ++ * uint32_t DH_Value_Length; ++ * uint8_t DH_Value[]; ++ */ ++ ++ /* Name Tag */ ++ *((uint16_t *)message) = cpu_to_be16(NAME_TAG); ++ message += sizeof(uint16_t); ++ ++ /* Name Len */ ++ *((uint16_t *)message) = cpu_to_be16(NAME_LEN); ++ message += sizeof(uint16_t); ++ ++ memcpy(message, vport->fc_portname.u.wwn, NAME_LEN); ++ message += NAME_LEN; ++ ++ /* Hash Value each 4 byte words */ ++ *((uint32_t *)message) = cpu_to_be32(vport->auth.hash_id); ++ message += sizeof(uint32_t); ++ ++ /* DH group id each 4 byte words */ ++ *((uint32_t *)message) = cpu_to_be32(vport->auth.group_id); ++ message += sizeof(uint32_t); ++ ++ /* Challenge Length */ ++ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u. ++ dhchap_challenge.our_challenge_len); ++ message += sizeof(uint32_t); ++ ++ /* copy challenge to vport to save */ ++ if (vport->auth.challenge) ++ kfree(vport->auth.challenge); ++ vport->auth.challenge_len = fc_rsp->u. ++ dhchap_challenge.our_challenge_len; ++ vport->auth.challenge = kmalloc(vport->auth.challenge_len, GFP_KERNEL); ++ ++ if (!vport->auth.challenge) ++ return 0; ++ ++ memcpy(vport->auth.challenge, fc_rsp->u.dhchap_challenge.data, ++ fc_rsp->u.dhchap_challenge.our_challenge_len); ++ ++ /* Challenge */ ++ memcpy(message, fc_rsp->u.dhchap_challenge.data, ++ fc_rsp->u.dhchap_challenge.our_challenge_len); ++ message += fc_rsp->u.dhchap_challenge.our_challenge_len; ++ ++ /* Public Key length */ ++ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u. ++ dhchap_challenge.our_public_key_len); ++ message += sizeof(uint32_t); ++ ++ /* Public Key */ ++ memcpy(message, fc_rsp->u.dhchap_challenge.data + ++ fc_rsp->u.dhchap_challenge.our_challenge_len, ++ fc_rsp->u.dhchap_challenge.our_public_key_len); ++ message += fc_rsp->u.dhchap_challenge.our_public_key_len; ++ ++ return ((uint32_t)(message - message_start)); ++ ++} ++ ++int ++lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_rsp *fc_rsp) ++ ++{ ++ uint8_t *message_start = message; ++ ++ /* ++ * Because some of the fields are not static in length and ++ * number we will pack on the fly. The packing is done in ++ * Big Endian byte order DHCHAP_Reply. ++ * ++ * uint32_t ResonseLength; ++ * uint8_t ResponseValue[]; ++ * uint32_t DHLength; ++ * uint8_t DHValue[]; Our Public key ++ * uint32_t ChallengeLength; Used for bi-directional authentication ++ * uint8_t ChallengeValue[]; ++ * ++ * The combined key ( g^x mod p )^y mod p is used as the last ++ * hash of the password. ++ * ++ * g is the base 2 or 5. ++ * y is our private key. ++ * ( g^y mod p ) is our public key which we send. ++ * ( g^x mod p ) is their public key which we received. ++ */ ++ /* Response Value Length */ ++ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u.dhchap_reply. ++ our_challenge_rsp_len); ++ ++ message += sizeof(uint32_t); ++ /* Response Value */ ++ memcpy(message, fc_rsp->u.dhchap_reply.data, ++ fc_rsp->u.dhchap_reply.our_challenge_rsp_len); ++ ++ message += fc_rsp->u.dhchap_reply.our_challenge_rsp_len; ++ /* DH Value Length */ ++ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u.dhchap_reply. ++ our_public_key_len); ++ ++ message += sizeof(uint32_t); ++ /* DH Value */ ++ memcpy(message, fc_rsp->u.dhchap_reply.data + ++ fc_rsp->u.dhchap_reply.our_challenge_rsp_len, ++ fc_rsp->u.dhchap_reply.our_public_key_len); ++ ++ message += fc_rsp->u.dhchap_reply.our_public_key_len; ++ ++ if (vport->auth.bidirectional) { ++ ++ /* copy to vport to save */ ++ if (vport->auth.challenge) ++ kfree(vport->auth.challenge); ++ vport->auth.challenge_len = fc_rsp->u.dhchap_reply. ++ our_challenge_len; ++ vport->auth.challenge = kmalloc(vport->auth.challenge_len, ++ GFP_KERNEL); ++ if (!vport->auth.challenge) ++ return 0; ++ ++ memcpy(vport->auth.challenge, fc_rsp->u.dhchap_reply.data + ++ fc_rsp->u.dhchap_reply.our_challenge_rsp_len + ++ fc_rsp->u.dhchap_reply.our_public_key_len, ++ fc_rsp->u.dhchap_reply.our_challenge_len); ++ /* Challenge Value Length */ ++ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u. ++ dhchap_reply.our_challenge_len); ++ message += sizeof(uint32_t); ++ /* Challenge Value */ ++ memcpy(message, fc_rsp->u.dhchap_reply.data + ++ fc_rsp->u.dhchap_reply.our_challenge_rsp_len + ++ fc_rsp->u.dhchap_reply.our_public_key_len, ++ fc_rsp->u.dhchap_reply.our_challenge_len); ++ ++ message += fc_rsp->u.dhchap_reply.our_challenge_len; ++ ++ } else { ++ *((uint32_t *)message) = 0; /* Challenge Len for No ++ bidirectional authentication */ ++ message += sizeof(uint32_t); /* Challenge Value Not Present */ ++ } ++ ++ return ((uint32_t)(message - message_start)); ++ ++} ++ ++int ++lpfc_build_dhchap_success(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_rsp *fc_rsp) ++{ ++ uint8_t *message_start = message; ++ ++ /* ++ * Because some of the fields are not static in length and number ++ * we will pack on the fly. The packing is done in Big Endian byte ++ * order DHCHAP_Success. ++ * uint32_t responseValueLen; ++ * uint8_t response[];. ++ */ ++ ++ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u. ++ dhchap_success.response_len); ++ message += sizeof(uint32_t); ++ ++ memcpy(message, fc_rsp->u.dhchap_success.data, ++ fc_rsp->u.dhchap_success.response_len); ++ message += fc_rsp->u.dhchap_success.response_len; ++ ++ return ((uint32_t)(message - message_start)); ++} ++ +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_auth.h +@@ -0,0 +1,92 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2007 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#define N_DH_GROUP 4 ++#define ELS_CMD_AUTH_BYTE 0x90 ++ ++#define AUTH_REJECT 0xA ++#define AUTH_NEGOTIATE 0xB ++#define AUTH_DONE 0xC ++ ++#define DHCHAP_CHALLENGE 0x10 ++#define DHCHAP_REPLY 0x11 ++#define DHCHAP_SUCCESS 0x12 ++ ++#define FCAP_REQUEST 0x13 ++#define FCAP_ACK 0x14 ++#define FCAP_CONFIRM 0x15 ++ ++#define PROTS_NUM 0x01 ++ ++#define NAME_TAG 0x01 ++#define NAME_LEN 0x08 ++ ++#define HASH_LIST_TAG 0x01 ++ ++#define DHGID_LIST_TAG 0x02 ++ ++#define HBA_SECURITY 0x20 ++ ++#define AUTH_ERR 0x1 ++#define LOGIC_ERR 0x2 ++ ++#define BAD_DHGROUP 0x2 ++#define BAD_ALGORITHM 0x3 ++#define AUTHENTICATION_FAILED 0x5 ++#define BAD_PAYLOAD 0x6 ++#define BAD_PROTOCOL 0x7 ++#define RESTART 0x8 ++ ++#define AUTH_VERSION 0x1 ++ ++#define MAX_AUTH_MESSAGE_SIZE 1024 ++ ++struct lpfc_auth_reject { ++ uint8_t reason; ++ uint8_t explanation; ++ uint8_t reserved[2]; ++} __attribute__ ((packed)); ++ ++struct lpfc_auth_message { /* Structure is in Big Endian format */ ++ uint8_t command_code; ++ uint8_t flags; ++ uint8_t message_code; ++ uint8_t protocol_ver; ++ uint32_t message_len; ++ uint32_t trans_id; ++ uint8_t data[0]; ++} __attribute__ ((packed)); ++ ++int lpfc_build_auth_neg(struct lpfc_vport *vport, uint8_t *message); ++int lpfc_build_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_rsp *fc_rsp); ++int lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_rsp *fc_rsp); ++int lpfc_build_dhchap_success(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_rsp *fc_rsp); ++ ++int lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, ++ uint8_t *reason, uint8_t *explanation); ++int lpfc_unpack_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, ++ uint8_t *reason, uint8_t *explanation); ++int lpfc_unpack_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_req *fc_req); ++int lpfc_unpack_dhchap_success(struct lpfc_vport *vport, uint8_t *message, ++ struct fc_auth_req *fc_req); +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -21,6 +21,12 @@ + typedef int (*node_filter)(struct lpfc_nodelist *, void *); + + struct fc_rport; ++int lpfc_issue_els_auth(struct lpfc_vport *, struct lpfc_nodelist *, ++ uint8_t message_code, uint8_t *payload, ++ uint32_t payload_len); ++int lpfc_issue_els_auth_reject(struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp, ++ uint8_t reason, uint8_t explanation); + void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); + void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); +@@ -80,7 +86,10 @@ void lpfc_cleanup(struct lpfc_vport *); + void lpfc_disc_timeout(unsigned long); + + struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); ++struct lpfc_nodelist *lpfc_findnode_wwnn(struct lpfc_vport *, ++ struct lpfc_name *); + ++void lpfc_port_auth_failed(struct lpfc_nodelist *); + void lpfc_worker_wake_up(struct lpfc_hba *); + int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); + int lpfc_do_work(void *); +@@ -95,6 +104,9 @@ void lpfc_more_plogi(struct lpfc_vport * + void lpfc_more_adisc(struct lpfc_vport *); + void lpfc_end_rscn(struct lpfc_vport *); + int lpfc_els_chk_latt(struct lpfc_vport *); ++struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t, ++ uint8_t, struct lpfc_nodelist *, uint32_t, ++ uint32_t); + int lpfc_els_abort_flogi(struct lpfc_hba *); + int lpfc_initial_flogi(struct lpfc_vport *); + int lpfc_initial_fdisc(struct lpfc_vport *); +@@ -117,6 +129,8 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vp + void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *); + void lpfc_els_retry_delay(unsigned long); + void lpfc_els_retry_delay_handler(struct lpfc_nodelist *); ++void lpfc_reauth_node(unsigned long); ++void lpfc_reauthentication_handler(struct lpfc_nodelist *); + void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, + struct lpfc_iocbq *); + int lpfc_els_handle_rscn(struct lpfc_vport *); +@@ -258,7 +272,6 @@ void lpfc_free_sysfs_attr(struct lpfc_vp + extern struct device_attribute *lpfc_hba_attrs[]; + extern struct device_attribute *lpfc_vport_attrs[]; + extern struct scsi_host_template lpfc_template; +-extern struct scsi_host_template lpfc_vport_template; + extern struct fc_function_template lpfc_transport_functions; + extern struct fc_function_template lpfc_vport_transport_functions; + extern int lpfc_sli_mode; +@@ -276,6 +289,22 @@ void destroy_port(struct lpfc_vport *); + int lpfc_get_instance(void); + void lpfc_host_attrib_init(struct Scsi_Host *); + ++int lpfc_selective_reset(struct lpfc_hba *); ++int lpfc_security_wait(struct lpfc_hba *); ++int lpfc_get_security_enabled(struct Scsi_Host *); ++void lpfc_security_service_online(struct Scsi_Host *); ++void lpfc_security_service_offline(struct Scsi_Host *); ++void lpfc_security_config(struct Scsi_Host *, int status, void *); ++int lpfc_security_config_wait(struct lpfc_vport *vport); ++void lpfc_dhchap_make_challenge(struct Scsi_Host *, int , void *, uint32_t); ++void lpfc_dhchap_make_response(struct Scsi_Host *, int , void *, uint32_t); ++void lpfc_dhchap_authenticate(struct Scsi_Host *, int , void *, uint32_t); ++int lpfc_start_node_authentication(struct lpfc_nodelist *); ++int lpfc_get_auth_config(struct lpfc_nodelist *, struct lpfc_name *); ++void lpfc_start_discovery(struct lpfc_vport *vport); ++void lpfc_start_authentication(struct lpfc_vport *, struct lpfc_nodelist *); ++int lpfc_rcv_nl_msg(struct Scsi_Host *, void *, uint32_t, uint32_t); ++ + extern void lpfc_debugfs_initialize(struct lpfc_vport *); + extern void lpfc_debugfs_terminate(struct lpfc_vport *); + extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t, +@@ -284,6 +313,11 @@ extern void lpfc_debugfs_slow_ring_trc(s + uint32_t, uint32_t); + extern struct lpfc_hbq_init *lpfc_hbq_defs[]; + ++extern uint8_t lpfc_security_service_state; ++extern spinlock_t fc_security_user_lock; ++extern struct list_head fc_security_user_list; ++extern int fc_service_state; ++ + /* Interface exported by fabric iocb scheduler */ + void lpfc_fabric_abort_nport(struct lpfc_nodelist *); + void lpfc_fabric_abort_hba(struct lpfc_hba *); +@@ -293,6 +327,7 @@ void lpfc_adjust_queue_depth(struct lpfc + void lpfc_ramp_down_queue_handler(struct lpfc_hba *); + void lpfc_ramp_up_queue_handler(struct lpfc_hba *); + void lpfc_scsi_dev_block(struct lpfc_hba *); ++void lpfc_scsi_dev_rescan(struct lpfc_hba *); + + void + lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *, +--- a/drivers/scsi/lpfc/lpfc_disc.h ++++ b/drivers/scsi/lpfc/lpfc_disc.h +@@ -37,6 +37,7 @@ enum lpfc_work_type { + LPFC_EVT_KILL, + LPFC_EVT_ELS_RETRY, + LPFC_EVT_DEV_LOSS, ++ LPFC_EVT_REAUTH, + LPFC_EVT_FASTPATH_MGMT_EVT, + }; + +@@ -99,10 +100,12 @@ struct lpfc_nodelist { + #define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */ + + struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ ++ struct timer_list nlp_reauth_tmr; /* Used for re-authentication */ + struct fc_rport *rport; /* Corresponding FC transport + port structure */ + struct lpfc_vport *vport; + struct lpfc_work_evt els_retry_evt; ++ struct lpfc_work_evt els_reauth_evt; + struct lpfc_work_evt dev_loss_evt; + unsigned long last_ramp_up_time; /* jiffy of last ramp up */ + unsigned long last_q_full_time; /* jiffy of last queue full */ +--- a/drivers/scsi/lpfc/lpfc_els.c ++++ b/drivers/scsi/lpfc/lpfc_els.c +@@ -38,6 +38,9 @@ + #include "lpfc_crtn.h" + #include "lpfc_vport.h" + #include "lpfc_debugfs.h" ++#include "lpfc_auth_access.h" ++#include "lpfc_auth.h" ++#include "lpfc_security.h" + + static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *, + struct lpfc_iocbq *); +@@ -143,7 +146,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vpo + * Pointer to the newly allocated/prepared els iocb data structure + * NULL - when els iocb data structure allocation/preparation failed + **/ +-static struct lpfc_iocbq * ++struct lpfc_iocbq * + lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, + uint16_t cmdSize, uint8_t retry, + struct lpfc_nodelist *ndlp, uint32_t did, +@@ -653,6 +656,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phb + struct lpfc_nodelist *ndlp = cmdiocb->context1; + struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; + struct serv_parm *sp; ++ struct lpfc_name wwpn; + int rc; + + /* Check to see if link went down during discovery */ +@@ -703,7 +707,10 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phb + prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); + + sp = prsp->virt + sizeof(uint32_t); +- ++ if (sp->cmn.security) ++ ndlp->nlp_flag |= NLP_SC_REQ; ++ else ++ ndlp->nlp_flag &= ~NLP_SC_REQ; + /* FLOGI completes successfully */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0101 FLOGI completes sucessfully " +@@ -711,6 +718,20 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phb + irsp->un.ulpWord[4], sp->cmn.e_d_tov, + sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution); + ++ if (vport->cfg_enable_auth) { ++ u64_to_wwn(AUTH_FABRIC_WWN, wwpn.u.wwn); ++ if (lpfc_get_auth_config(ndlp, &wwpn)) ++ goto flogifail; ++ } else { ++ vport->auth.security_active = 0; ++ if (sp->cmn.security) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1055 Authentication parameter is " ++ "disabled, but is required by " ++ "the fabric.\n"); ++ goto flogifail; ++ } ++ } + if (vport->port_state == LPFC_FLOGI) { + /* + * If Common Service Parameters indicate Nport +@@ -800,6 +821,10 @@ lpfc_issue_els_flogi(struct lpfc_vport * + sp = (struct serv_parm *) pcmd; + + /* Setup CSPs accordingly for Fabric */ ++ ++ if (vport->cfg_enable_auth) ++ sp->cmn.security = 1; ++ + sp->cmn.e_d_tov = 0; + sp->cmn.w2.r_a_tov = 0; + sp->cls1.classValid = 0; +@@ -965,6 +990,17 @@ lpfc_initial_fdisc(struct lpfc_vport *vp + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + ++ if (vport->cfg_enable_auth) { ++ if (lpfc_security_wait(phba)) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1049 Authentication is enabled but " ++ "authentication service is not " ++ "running\n"); ++ vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; ++ return 0; ++ } ++ } ++ + /* First look for the Fabric ndlp */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) { +@@ -2697,6 +2733,17 @@ lpfc_els_retry(struct lpfc_hba *phba, st + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry); + return 1; ++ case ELS_CMD_AUTH_NEG: ++ case ELS_CMD_DH_CHA: ++ case ELS_CMD_DH_REP: ++ case ELS_CMD_DH_SUC: ++ ndlp->nlp_prev_state = ndlp->nlp_state; ++ ndlp->nlp_state = NLP_STE_NPR_NODE; ++ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, ++ "0143 Authentication LS_RJT Logical " ++ "busy\n"); ++ lpfc_start_authentication(vport, ndlp); ++ return 1; + } + } + /* No retry ELS command to remote NPORT */ +@@ -5085,6 +5132,363 @@ lpfc_els_flush_all_cmd(struct lpfc_hba + return; + } + ++static void ++lpfc_els_rcv_auth_neg(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_nodelist *ndlp) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_dmabuf *pcmd = cmdiocb->context2; ++ struct lpfc_auth_message *authcmd; ++ uint8_t reason, explanation; ++ uint32_t message_len; ++ uint32_t trans_id; ++ struct fc_auth_req *fc_req; ++ struct fc_auth_rsp *fc_rsp; ++ ++ authcmd = pcmd->virt; ++ message_len = be32_to_cpu(authcmd->message_len); ++ trans_id = be32_to_cpu(authcmd->trans_id); ++ ++ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); ++ ++ vport->auth.trans_id = trans_id; ++ ++ if (lpfc_unpack_auth_negotiate(vport, authcmd->data, ++ &reason, &explanation)) { ++ lpfc_issue_els_auth_reject(vport, ndlp, reason, explanation); ++ return; ++ } ++ vport->auth.direction = AUTH_DIRECTION_NONE; ++ lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, ++ "1033 Received auth_negotiate from Nport:x%x\n", ++ ndlp->nlp_DID); ++ ++ fc_req = kzalloc(sizeof(struct fc_auth_req), GFP_KERNEL); ++ ++ fc_req->local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn); ++ if (ndlp->nlp_type & NLP_FABRIC) ++ fc_req->remote_wwpn = AUTH_FABRIC_WWN; ++ else ++ fc_req->remote_wwpn = wwn_to_u64(ndlp->nlp_portname.u.wwn); ++ fc_req->u.dhchap_challenge.transaction_id = vport->auth.trans_id; ++ fc_req->u.dhchap_challenge.dh_group_id = vport->auth.group_id; ++ fc_req->u.dhchap_challenge.hash_id = vport->auth.hash_id; ++ ++ fc_rsp = kzalloc(MAX_AUTH_RSP_SIZE, GFP_KERNEL); ++ ++ if (lpfc_fc_security_dhchap_make_challenge(shost, ++ fc_req, sizeof(struct fc_auth_req), ++ fc_rsp, MAX_AUTH_RSP_SIZE)) { ++ kfree(fc_rsp); ++ lpfc_issue_els_auth_reject(vport, ndlp, LOGIC_ERR, 0); ++ } ++ ++ kfree(fc_req); ++ ++} ++ ++static void ++lpfc_els_rcv_chap_chal(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_nodelist *ndlp) ++{ ++ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_dmabuf *pcmd = cmdiocb->context2; ++ struct lpfc_auth_message *authcmd; ++ uint8_t reason, explanation; ++ uint32_t message_len; ++ uint32_t trans_id; ++ struct fc_auth_req *fc_req; ++ struct fc_auth_rsp *fc_rsp; ++ uint32_t fc_req_len; ++ ++ authcmd = pcmd->virt; ++ message_len = be32_to_cpu(authcmd->message_len); ++ trans_id = be32_to_cpu(authcmd->trans_id); ++ ++ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); ++ ++ if (vport->auth.auth_msg_state != LPFC_AUTH_NEGOTIATE) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1034 Not Expecting Challenge - Rejecting " ++ "Challenge.\n"); ++ lpfc_issue_els_auth_reject(vport, ndlp, AUTH_ERR, BAD_PROTOCOL); ++ return; ++ } ++ ++ if (trans_id != vport->auth.trans_id) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1035 Transport ID does not match - Rejecting " ++ "Challenge.\n"); ++ lpfc_issue_els_auth_reject(vport, ndlp, AUTH_ERR, BAD_PAYLOAD); ++ return; ++ } ++ ++ if (lpfc_unpack_dhchap_challenge(vport, authcmd->data, ++ &reason, &explanation)) { ++ lpfc_issue_els_auth_reject(vport, ndlp, reason, explanation); ++ return; ++ } ++ vport->auth.direction = AUTH_DIRECTION_NONE; ++ ++ fc_req_len = (sizeof(struct fc_auth_req) + ++ vport->auth.challenge_len + ++ vport->auth.dh_pub_key_len); ++ fc_req = kzalloc(fc_req_len, GFP_KERNEL); ++ fc_req->local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn); ++ if (ndlp->nlp_type & NLP_FABRIC) ++ fc_req->remote_wwpn = AUTH_FABRIC_WWN; ++ else ++ fc_req->remote_wwpn = wwn_to_u64(ndlp->nlp_portname.u.wwn); ++ fc_req->u.dhchap_reply.transaction_id = vport->auth.trans_id; ++ fc_req->u.dhchap_reply.dh_group_id = vport->auth.group_id; ++ fc_req->u.dhchap_reply.hash_id = vport->auth.hash_id; ++ fc_req->u.dhchap_reply.bidirectional = vport->auth.bidirectional; ++ fc_req->u.dhchap_reply.received_challenge_len = ++ vport->auth.challenge_len; ++ fc_req->u.dhchap_reply.received_public_key_len = ++ vport->auth.dh_pub_key_len; ++ memcpy(fc_req->u.dhchap_reply.data, vport->auth.challenge, ++ vport->auth.challenge_len); ++ if (vport->auth.group_id != DH_GROUP_NULL) { ++ memcpy(fc_req->u.dhchap_reply.data + vport->auth.challenge_len, ++ vport->auth.dh_pub_key, vport->auth.dh_pub_key_len); ++ } ++ ++ fc_rsp = kzalloc(MAX_AUTH_RSP_SIZE, GFP_KERNEL); ++ ++ if (lpfc_fc_security_dhchap_make_response(shost, ++ fc_req, fc_req_len, ++ fc_rsp, MAX_AUTH_RSP_SIZE)) { ++ kfree(fc_rsp); ++ lpfc_issue_els_auth_reject(vport, ndlp, LOGIC_ERR, 0); ++ } ++ ++ kfree(fc_req); ++ ++} ++ ++static void ++lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_nodelist *ndlp) ++{ ++ ++ struct lpfc_dmabuf *pcmd = cmdiocb->context2; ++ struct lpfc_auth_message *authcmd; ++ uint32_t message_len; ++ uint32_t trans_id; ++ struct lpfc_auth_reject *rjt; ++ struct lpfc_hba *phba = vport->phba; ++ ++ authcmd = pcmd->virt; ++ rjt = (struct lpfc_auth_reject *)authcmd->data; ++ ++ message_len = be32_to_cpu(authcmd->message_len); ++ trans_id = be32_to_cpu(authcmd->trans_id); ++ ++ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); ++ ++ if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1036 Authentication transaction reject - " ++ "re-auth request reason 0x%x exp 0x%x\n", ++ rjt->reason, rjt->explanation); ++ lpfc_port_auth_failed(ndlp); ++ if (vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS) { ++ /* start authentication */ ++ lpfc_start_authentication(vport, ndlp); ++ } ++ } else { ++ if (rjt->reason == LOGIC_ERR && rjt->explanation == RESTART) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1037 Authentication transaction " ++ "reject - restarting authentication. " ++ "reason 0x%x exp 0x%x\n", ++ rjt->reason, rjt->explanation); ++ /* restart auth */ ++ lpfc_start_authentication(vport, ndlp); ++ } else { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1057 Authentication transaction " ++ "reject. reason 0x%x exp 0x%x\n", ++ rjt->reason, rjt->explanation); ++ vport->auth.auth_msg_state = LPFC_AUTH_REJECT; ++ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && ++ (phba->link_state != LPFC_CLEAR_LA)) { ++ /* If Auth failed enable link interrupt. */ ++ lpfc_issue_clear_la(phba, vport); ++ } ++ } ++ } ++} ++ ++static void ++lpfc_els_rcv_chap_reply(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_nodelist *ndlp) ++{ ++ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_dmabuf *pcmd = cmdiocb->context2; ++ struct lpfc_auth_message *authcmd; ++ uint32_t message_len; ++ uint32_t trans_id; ++ struct fc_auth_req *fc_req; ++ struct fc_auth_rsp *fc_rsp; ++ uint32_t data_len; ++ ++ authcmd = pcmd->virt; ++ message_len = be32_to_cpu(authcmd->message_len); ++ trans_id = be32_to_cpu(authcmd->trans_id); ++ ++ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); ++ ++ fc_req = kzalloc(MAX_AUTH_REQ_SIZE, GFP_KERNEL); ++ ++ fc_req->local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn); ++ if (ndlp->nlp_type & NLP_FABRIC) ++ fc_req->remote_wwpn = AUTH_FABRIC_WWN; ++ else ++ fc_req->remote_wwpn = wwn_to_u64(ndlp->nlp_portname.u.wwn); ++ ++ if (vport->auth.auth_msg_state != LPFC_DHCHAP_CHALLENGE) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1039 Not Expecting Reply - rejecting. State " ++ "0x%x\n", vport->auth.auth_state); ++ ++ lpfc_issue_els_auth_reject(vport, ndlp, AUTH_ERR, BAD_PROTOCOL); ++ return; ++ } ++ ++ if (trans_id != vport->auth.trans_id) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1040 Bad Reply trans_id- rejecting. " ++ "Trans_id: 0x%x Expecting: 0x%x \n", ++ trans_id, vport->auth.trans_id); ++ lpfc_issue_els_auth_reject(vport, ndlp, AUTH_ERR, BAD_PAYLOAD); ++ return; ++ } ++ ++ /* Zero is a valid length to be returned */ ++ data_len = lpfc_unpack_dhchap_reply(vport, authcmd->data, fc_req); ++ fc_req->u.dhchap_success.hash_id = vport->auth.hash_id; ++ fc_req->u.dhchap_success.dh_group_id = vport->auth.group_id; ++ fc_req->u.dhchap_success.transaction_id = vport->auth.trans_id; ++ fc_req->u.dhchap_success.our_challenge_len = vport->auth.challenge_len; ++ memcpy(fc_req->u.dhchap_success.data, vport->auth.challenge, ++ vport->auth.challenge_len); ++ ++ fc_rsp = kzalloc(MAX_AUTH_RSP_SIZE, GFP_KERNEL); ++ ++ if (lpfc_fc_security_dhchap_authenticate(shost, fc_req, ++ (sizeof(struct fc_auth_req) + ++ data_len + vport->auth.challenge_len), ++ fc_rsp, MAX_AUTH_RSP_SIZE)) { ++ kfree(fc_rsp); ++ lpfc_issue_els_auth_reject(vport, ndlp, LOGIC_ERR, 0); ++ } ++ ++ kfree(fc_req); ++ ++} ++ ++static void ++lpfc_els_rcv_chap_suc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_nodelist *ndlp) ++{ ++ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_dmabuf *pcmd = cmdiocb->context2; ++ struct lpfc_auth_message *authcmd; ++ uint32_t message_len; ++ uint32_t trans_id; ++ struct fc_auth_req *fc_req; ++ struct fc_auth_rsp *fc_rsp; ++ uint32_t data_len; ++ ++ authcmd = pcmd->virt; ++ message_len = be32_to_cpu(authcmd->message_len); ++ trans_id = be32_to_cpu(authcmd->trans_id); ++ ++ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); ++ ++ if (vport->auth.auth_msg_state != LPFC_DHCHAP_REPLY && ++ vport->auth.auth_msg_state != LPFC_DHCHAP_SUCCESS_REPLY) { ++ lpfc_issue_els_auth_reject(vport, ndlp, AUTH_ERR, BAD_PROTOCOL); ++ return; ++ } ++ ++ if (trans_id != vport->auth.trans_id) { ++ lpfc_issue_els_auth_reject(vport, ndlp, AUTH_ERR, BAD_PAYLOAD); ++ return; ++ } ++ ++ if (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY && ++ vport->auth.bidirectional) { ++ ++ fc_req = kzalloc(MAX_AUTH_REQ_SIZE, GFP_KERNEL); ++ if (!fc_req) ++ return; ++ ++ fc_req->local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn); ++ if (ndlp->nlp_type & NLP_FABRIC) ++ fc_req->remote_wwpn = AUTH_FABRIC_WWN; ++ else ++ fc_req->remote_wwpn = ++ wwn_to_u64(ndlp->nlp_portname.u.wwn); ++ fc_req->u.dhchap_success.hash_id = vport->auth.hash_id; ++ fc_req->u.dhchap_success.dh_group_id = vport->auth.group_id; ++ fc_req->u.dhchap_success.transaction_id = vport->auth.trans_id; ++ fc_req->u.dhchap_success.our_challenge_len = ++ vport->auth.challenge_len; ++ ++ memcpy(fc_req->u.dhchap_success.data, vport->auth.challenge, ++ vport->auth.challenge_len); ++ ++ /* Zero is a valid return length */ ++ data_len = lpfc_unpack_dhchap_success(vport, ++ authcmd->data, ++ fc_req); ++ ++ fc_rsp = kzalloc(MAX_AUTH_RSP_SIZE, GFP_KERNEL); ++ if (!fc_rsp) ++ return; ++ ++ if (lpfc_fc_security_dhchap_authenticate(shost, ++ fc_req, sizeof(struct fc_auth_req) + data_len, ++ fc_rsp, MAX_AUTH_RSP_SIZE)) { ++ kfree(fc_rsp); ++ lpfc_issue_els_auth_reject(vport, ndlp, LOGIC_ERR, 0); ++ } ++ ++ kfree(fc_req); ++ ++ } else { ++ vport->auth.auth_msg_state = LPFC_DHCHAP_SUCCESS; ++ ++ kfree(vport->auth.challenge); ++ vport->auth.challenge = NULL; ++ vport->auth.challenge_len = 0; ++ ++ if (vport->auth.auth_state != LPFC_AUTH_SUCCESS) { ++ vport->auth.auth_state = LPFC_AUTH_SUCCESS; ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, ++ "1041 Authentication Successful\n"); ++ ++ lpfc_start_discovery(vport); ++ ++ } else { ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, ++ "1042 Re-Authentication Successful\n"); ++ } ++ /* If config requires re-authentication start the timer */ ++ vport->auth.last_auth = jiffies; ++ if (vport->auth.reauth_interval) ++ mod_timer(&ndlp->nlp_reauth_tmr, jiffies + ++ vport->auth.reauth_interval * 60 * HZ); ++ } ++ vport->auth.direction |= AUTH_DIRECTION_REMOTE; ++} ++ + /** + * lpfc_send_els_failure_event: Posts an ELS command failure event. + * @phba: Pointer to hba context object. +@@ -5462,6 +5866,48 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p + if (newnode) + lpfc_nlp_put(ndlp); + break; ++ case ELS_CMD_AUTH_RJT: ++ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, ++ "RCV AUTH_RJT: did:x%x/ste:x%x flg:x%x", ++ did, vport->port_state, ndlp->nlp_flag); ++ ++ lpfc_els_rcv_auth_rjt(vport, elsiocb, ndlp); ++ break; ++ case ELS_CMD_AUTH_NEG: ++ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, ++ "RCV AUTH_NEG: did:x%x/ste:x%x flg:x%x", ++ did, vport->port_state, ndlp->nlp_flag); ++ ++ lpfc_els_rcv_auth_neg(vport, elsiocb, ndlp); ++ break; ++ case ELS_CMD_DH_CHA: ++ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, ++ "RCV DH_CHA: did:x%x/ste:x%x flg:x%x", ++ did, vport->port_state, ndlp->nlp_flag); ++ ++ lpfc_els_rcv_chap_chal(vport, elsiocb, ndlp); ++ break; ++ case ELS_CMD_DH_REP: ++ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, ++ "RCV DH_REP: did:x%x/ste:x%x flg:x%x", ++ did, vport->port_state, ndlp->nlp_flag); ++ ++ lpfc_els_rcv_chap_reply(vport, elsiocb, ndlp); ++ break; ++ case ELS_CMD_DH_SUC: ++ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, ++ "RCV DH_SUC: did:x%x/ste:x%x flg:x%x", ++ did, vport->port_state, ndlp->nlp_flag); ++ ++ lpfc_els_rcv_chap_suc(vport, elsiocb, ndlp); ++ break; ++ ++ case ELS_CMD_AUTH_DONE: ++ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, ++ "RCV AUTH_DONE: did:x%x/ste:x%x flg:x%x", ++ did, vport->port_state, ndlp->nlp_flag); ++ ++ + default: + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", +@@ -5747,7 +6193,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba + } else { + if (vport == phba->pport) + lpfc_issue_fabric_reglogin(vport); +- else ++ else if (!vport->cfg_enable_auth) + lpfc_do_scr_ns_plogi(phba, vport); + } + +@@ -5840,6 +6286,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phb + struct lpfc_nodelist *next_np; + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_iocbq *piocb; ++ struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; ++ struct serv_parm *sp; ++ struct lpfc_name wwpn; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "0123 FDISC completes. x%x/x%x prevDID: x%x\n", +@@ -5867,11 +6316,26 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phb + irsp->ulpStatus, irsp->un.ulpWord[4]); + goto fdisc_failed; + } +- if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) +- lpfc_vport_set_state(vport, FC_VPORT_FAILED); +- lpfc_nlp_put(ndlp); +- /* giving up on FDISC. Cancel discovery timer */ +- lpfc_can_disctmo(vport); ++ prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); ++ sp = prsp->virt + sizeof(uint32_t); ++ if (sp->cmn.security) ++ ndlp->nlp_flag |= NLP_SC_REQ; ++ else ++ ndlp->nlp_flag &= ~NLP_SC_REQ; ++ if (vport->cfg_enable_auth) { ++ u64_to_wwn(AUTH_FABRIC_WWN, wwpn.u.wwn); ++ if (lpfc_get_auth_config(ndlp, &wwpn)) ++ goto fdisc_failed; ++ } else { ++ vport->auth.security_active = 0; ++ if (sp->cmn.security) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1056 Authentication mode is " ++ "disabled, but is required " ++ "by the fabric.\n"); ++ goto fdisc_failed; ++ } ++ } + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_FABRIC; + if (vport->phba->fc_topology == TOPOLOGY_LOOP) +@@ -5905,7 +6369,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phb + + if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) + lpfc_register_new_vport(phba, vport, ndlp); +- else ++ else if (!vport->cfg_enable_auth) + lpfc_do_scr_ns_plogi(phba, vport); + goto out; + fdisc_failed: +@@ -5980,6 +6444,10 @@ lpfc_issue_els_fdisc(struct lpfc_vport * + sp->cls2.seqDelivery = 1; + sp->cls3.seqDelivery = 1; + ++ /* Set the security service parameter */ ++ if (vport->cfg_enable_auth) ++ sp->cmn.security = 1; ++ + pcmd += sizeof(uint32_t); /* CSP Word 2 */ + pcmd += sizeof(uint32_t); /* CSP Word 3 */ + pcmd += sizeof(uint32_t); /* CSP Word 4 */ +@@ -6474,3 +6942,180 @@ void lpfc_fabric_abort_hba(struct lpfc_h + (piocb->iocb_cmpl) (phba, piocb, piocb); + } + } ++static void ++lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_iocbq *rspiocb) ++{ ++ IOCB_t *irsp = &rspiocb->iocb; ++ struct lpfc_vport *vport = cmdiocb->vport; ++ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; ++ ++ /* Check to see if link went down during discovery */ ++ if (lpfc_els_chk_latt(vport)) { ++ vport->auth.auth_msg_state = LPFC_AUTH_NONE; ++ lpfc_els_free_iocb(phba, cmdiocb); ++ return; ++ } ++ ++ if (irsp->ulpStatus) { ++ if (irsp->ulpStatus == IOSTAT_LS_RJT) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ++ "1043 Authentication LS_RJT\n"); ++ } ++ /* Check for retry */ ++ if (!lpfc_els_retry(phba, cmdiocb, rspiocb)) { ++ if (irsp->ulpStatus != IOSTAT_LS_RJT) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ++ "1045 Issue AUTH_NEG failed." ++ "Status:%x\n", ++ irsp->ulpStatus); ++ } ++ if (vport->auth.auth_mode == FC_AUTHMODE_ACTIVE) { ++ lpfc_can_disctmo(vport); ++ lpfc_port_auth_failed(ndlp); ++ } ++ } ++ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && ++ (phba->link_state != LPFC_CLEAR_LA)) ++ lpfc_issue_clear_la(phba, vport); ++ lpfc_els_free_iocb(phba, cmdiocb); ++ return; ++ } ++ ++ if (vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS || ++ vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS_REPLY) { ++ ++ kfree(vport->auth.challenge); ++ vport->auth.challenge = NULL; ++ vport->auth.challenge_len = 0; ++ kfree(vport->auth.dh_pub_key); ++ vport->auth.dh_pub_key = NULL; ++ vport->auth.dh_pub_key_len = 0; ++ ++ if (vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS) { ++ if (vport->auth.auth_state != LPFC_AUTH_SUCCESS) { ++ lpfc_printf_vlog(vport, KERN_WARNING, ++ LOG_SECURITY, "1046 " ++ "Authentication Successful\n"); ++ vport->auth.auth_state = LPFC_AUTH_SUCCESS; ++ lpfc_start_discovery(vport); ++ } else { ++ lpfc_printf_vlog(vport, KERN_WARNING, ++ LOG_SECURITY, ++ "1047 Re-Authentication" ++ " Successful\n"); ++ } ++ } ++ /* restart authentication timer */ ++ vport->auth.last_auth = jiffies; ++ if (vport->auth.reauth_interval) ++ mod_timer(&ndlp->nlp_reauth_tmr, ++ jiffies + ++ vport->auth.reauth_interval * 60 * HZ); ++ } ++ lpfc_els_free_iocb(phba, cmdiocb); ++} ++ ++int ++lpfc_issue_els_auth(struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp, ++ uint8_t message_code, ++ uint8_t *payload, ++ uint32_t payload_len) ++{ ++ struct lpfc_hba *phba = vport->phba; ++ struct lpfc_iocbq *elsiocb; ++ struct lpfc_auth_message *authreq; ++ ++ elsiocb = lpfc_prep_els_iocb(vport, 1, ++ sizeof(struct lpfc_auth_message) + payload_len, ++ 0, ndlp, ndlp->nlp_DID, ELS_CMD_AUTH); ++ ++ if (!elsiocb) ++ return 1; ++ authreq = (struct lpfc_auth_message *) ++ (((struct lpfc_dmabuf *) elsiocb->context2)->virt); ++ authreq->command_code = ELS_CMD_AUTH_BYTE; ++ authreq->flags = 0; ++ authreq->message_code = message_code; ++ authreq->protocol_ver = AUTH_VERSION; ++ authreq->message_len = cpu_to_be32(payload_len); ++ authreq->trans_id = cpu_to_be32(vport->auth.trans_id); ++ memcpy(authreq->data, payload, payload_len); ++ ++ elsiocb->iocb_cmpl = lpfc_cmpl_els_auth; ++ ++ if (lpfc_sli_issue_iocb(phba, &phba->sli.ring[LPFC_ELS_RING], ++ elsiocb, 0) == IOCB_ERROR) { ++ lpfc_els_free_iocb(phba, elsiocb); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void ++lpfc_cmpl_els_auth_reject(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ++ struct lpfc_iocbq *rspiocb) ++{ ++ struct lpfc_vport *vport = cmdiocb->vport; ++ IOCB_t *irsp = &rspiocb->iocb; ++ ++ if (irsp->ulpStatus) { ++ /* Check for retry */ ++ if (!lpfc_els_retry(phba, cmdiocb, rspiocb)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_ELS, ++ "1048 Issue AUTH_REJECT failed.\n"); ++ } ++ } else ++ vport->port_state = LPFC_VPORT_UNKNOWN; ++ ++ lpfc_els_free_iocb(phba, cmdiocb); ++} ++ ++int ++lpfc_issue_els_auth_reject(struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp, ++ uint8_t reason, uint8_t explanation) ++{ ++ struct lpfc_hba *phba = vport->phba; ++ struct lpfc_iocbq *elsiocb; ++ struct lpfc_sli_ring *pring; ++ struct lpfc_sli *psli; ++ struct lpfc_auth_message *authreq; ++ struct lpfc_auth_reject *reject; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ ++ vport->auth.auth_msg_state = LPFC_AUTH_REJECT; ++ ++ elsiocb = lpfc_prep_els_iocb(vport, 1, sizeof(struct lpfc_auth_message) ++ + sizeof(struct lpfc_auth_reject), 0, ndlp, ++ ndlp->nlp_DID, ELS_CMD_AUTH); ++ ++ if (!elsiocb) ++ return 1; ++ ++ authreq = (struct lpfc_auth_message *) ++ (((struct lpfc_dmabuf *) elsiocb->context2)->virt); ++ authreq->command_code = ELS_CMD_AUTH_BYTE; ++ authreq->flags = 0; ++ authreq->message_code = AUTH_REJECT; ++ authreq->protocol_ver = AUTH_VERSION; ++ reject = (struct lpfc_auth_reject *)authreq->data; ++ memset(reject, 0, sizeof(struct lpfc_auth_reject)); ++ reject->reason = reason; ++ reject->explanation = explanation; ++ ++ authreq->message_len = cpu_to_be32(sizeof(struct lpfc_auth_reject)); ++ authreq->trans_id = cpu_to_be32(vport->auth.trans_id); ++ elsiocb->iocb_cmpl = lpfc_cmpl_els_auth_reject; ++ ++ if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { ++ lpfc_els_free_iocb(phba, elsiocb); ++ return 1; ++ } ++ ++ return 0; ++} +--- a/drivers/scsi/lpfc/lpfc.h ++++ b/drivers/scsi/lpfc/lpfc.h +@@ -217,18 +217,81 @@ struct lpfc_stats { + uint32_t fcpLocalErr; + }; + ++struct lpfc_dmabufext { ++ struct lpfc_dmabuf dma; ++ uint32_t size; ++ uint32_t flag; ++}; ++ + enum sysfs_mbox_state { + SMBOX_IDLE, + SMBOX_WRITING, +- SMBOX_READING ++ SMBOX_WRITING_MBEXT, ++ SMBOX_READING_MBEXT, ++ SMBOX_READING, ++ SMBOX_WRITING_BUFF, ++ SMBOX_READING_BUFF ++}; ++ ++struct lpfc_sysfs_mbox_data { ++ MAILBOX_t mbox; ++ uint32_t mboffset; ++ uint32_t in_ext_wlen; ++ uint32_t out_ext_wlen; + }; + + struct lpfc_sysfs_mbox { ++ struct lpfc_sysfs_mbox_data mbox_data; + enum sysfs_mbox_state state; + size_t offset; + struct lpfcMboxq * mbox; ++ /* process id of the mgmt application */ ++ pid_t pid; ++ struct list_head list; ++ uint8_t * mbext; ++ uint32_t extoff; ++ struct lpfc_dmabuf * txmit_buff; ++ struct lpfc_dmabuf * rcv_buff; ++}; ++#define MENLO_DID 0x0000FC0E ++ ++enum sysfs_menlo_state { ++ SMENLO_IDLE, ++ SMENLO_WRITING, ++ SMENLO_WRITING_MBEXT, ++ SMENLO_READING ++}; ++ ++struct lpfc_sysfs_menlo_hdr { ++ uint32_t cmd; ++ uint32_t cmdsize; ++ uint32_t rspsize; ++}; ++ ++struct lpfc_menlo_genreq64 { ++ size_t offset; ++ struct lpfc_iocbq *cmdiocbq; ++ struct lpfc_iocbq *rspiocbq; ++ struct lpfc_dmabuf *bmp; ++ struct lpfc_dmabufext *indmp; ++ struct ulp_bde64 *cmdbpl; ++ struct lpfc_dmabufext *outdmp; ++ uint32_t timeout; ++ struct list_head inhead; ++ struct list_head outhead; + }; + ++struct lpfc_sysfs_menlo { ++ enum sysfs_menlo_state state; ++ /* process id of the mgmt application */ ++ struct lpfc_sysfs_menlo_hdr cmdhdr; ++ struct lpfc_menlo_genreq64 cr; ++ struct lpfc_menlo_genreq64 cx; ++ pid_t pid; ++ struct list_head list; ++}; ++ ++ + struct lpfc_hba; + + +@@ -261,6 +324,52 @@ enum hba_state { + LPFC_HBA_ERROR = -1 + }; + ++enum auth_state { ++ LPFC_AUTH_UNKNOWN = 0, ++ LPFC_AUTH_SUCCESS = 1, ++ LPFC_AUTH_FAIL = 2, ++}; ++enum auth_msg_state { ++ LPFC_AUTH_NONE = 0, ++ LPFC_AUTH_REJECT = 1, /* Sent a Reject */ ++ LPFC_AUTH_NEGOTIATE = 2, /* Auth Negotiate */ ++ LPFC_DHCHAP_CHALLENGE = 3, /* Challenge */ ++ LPFC_DHCHAP_REPLY = 4, /* Reply */ ++ LPFC_DHCHAP_SUCCESS_REPLY = 5, /* Success with Reply */ ++ LPFC_DHCHAP_SUCCESS = 6, /* Success */ ++ LPFC_AUTH_DONE = 7, ++}; ++ ++struct lpfc_auth { ++ uint8_t auth_mode; ++ uint8_t bidirectional; ++ uint8_t hash_priority[4]; ++ uint32_t hash_len; ++ uint8_t dh_group_priority[8]; ++ uint32_t dh_group_len; ++ uint32_t reauth_interval; ++ ++ uint8_t security_active; ++ enum auth_state auth_state; ++ enum auth_msg_state auth_msg_state; ++ uint32_t trans_id; /* current transaction id. Can be set ++ by incomming transactions as well */ ++ uint32_t group_id; ++ uint32_t hash_id; ++ uint32_t direction; ++#define AUTH_DIRECTION_NONE 0 ++#define AUTH_DIRECTION_REMOTE 0x1 ++#define AUTH_DIRECTION_LOCAL 0x2 ++#define AUTH_DIRECTION_BIDI (AUTH_DIRECTION_LOCAL|AUTH_DIRECTION_REMOTE) ++ ++ uint8_t *challenge; ++ uint32_t challenge_len; ++ uint8_t *dh_pub_key; ++ uint32_t dh_pub_key_len; ++ ++ unsigned long last_auth; ++}; ++ + struct lpfc_vport { + struct list_head listentry; + struct lpfc_hba *phba; +@@ -356,6 +465,14 @@ struct lpfc_vport { + #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ + char *vname; /* Application assigned name */ + ++ /* Fields used for accessing auth service */ ++ struct lpfc_auth auth; ++ uint32_t sc_tran_id; ++ struct list_head sc_response_wait_queue; ++ struct list_head sc_users; ++ struct work_struct sc_online_work; ++ struct work_struct sc_offline_work; ++ + /* Vport Config Parameters */ + uint32_t cfg_scan_down; + uint32_t cfg_lun_queue_depth; +@@ -371,6 +488,7 @@ struct lpfc_vport { + uint32_t cfg_max_luns; + uint32_t cfg_enable_da_id; + uint32_t cfg_max_scsicmpl_time; ++ uint32_t cfg_enable_auth; + + uint32_t dev_loss_tmo_changed; + +@@ -445,6 +563,7 @@ struct lpfc_hba { + struct lpfc_dmabuf slim2p; + + MAILBOX_t *mbox; ++ uint32_t *mbox_ext; + uint32_t *inb_ha_copy; + uint32_t *inb_counter; + uint32_t inb_last_counter; +@@ -573,7 +692,9 @@ struct lpfc_hba { + uint64_t fc4OutputRequests; + uint64_t fc4ControlRequests; + +- struct lpfc_sysfs_mbox sysfs_mbox; ++ /* List of mailbox commands issued through sysfs */ ++ struct list_head sysfs_mbox_list; ++ struct list_head sysfs_menlo_list; + + /* fastpath list. */ + spinlock_t scsi_buf_list_lock; +@@ -595,11 +716,13 @@ struct lpfc_hba { + struct fc_host_statistics link_stats; + enum intr_type_t intr_type; + struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; ++ struct lpfcdfc_host *dfc_host; + + struct list_head port_list; + struct lpfc_vport *pport; /* physical lpfc_vport pointer */ + uint16_t max_vpi; /* Maximum virtual nports */ +-#define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ ++#define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ ++#define LPFC_INTR_VPI 100 /* Intermediate VPI supported */ + unsigned long *vpi_bmask; /* vpi allocation table */ + + /* Data structure used by fabric iocb scheduler */ +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -59,6 +59,47 @@ static uint8_t lpfcAlpaArray[] = { + + static void lpfc_disc_timeout_handler(struct lpfc_vport *); + static void lpfc_disc_flush_list(struct lpfc_vport *vport); ++void ++lpfc_start_discovery(struct lpfc_vport *vport) ++{ ++ struct lpfc_hba *phba = vport->phba; ++ struct lpfc_vport **vports; ++ int i; ++ ++ if (vport->auth.security_active && ++ vport->auth.auth_state != LPFC_AUTH_SUCCESS) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, ++ "0285 Authentication not complete.\n"); ++ return; ++ } ++ if (vport->port_type == LPFC_NPIV_PORT) { ++ lpfc_do_scr_ns_plogi(phba, vport); ++ return; ++ } ++ ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports != NULL) ++ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { ++ if (vports[i]->port_type == LPFC_PHYSICAL_PORT) ++ continue; ++ if (phba->fc_topology == TOPOLOGY_LOOP) { ++ lpfc_vport_set_state(vports[i], ++ FC_VPORT_LINKDOWN); ++ continue; ++ } ++ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) ++ lpfc_initial_fdisc(vports[i]); ++ else { ++ lpfc_vport_set_state(vports[i], ++ FC_VPORT_NO_FABRIC_SUPP); ++ lpfc_printf_vlog(vports[i], KERN_ERR, LOG_ELS, ++ "0259 No NPIV Fabric " ++ "support\n"); ++ } ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++ lpfc_do_scr_ns_plogi(phba, vport); ++} + + void + lpfc_terminate_rport_io(struct fc_rport *rport) +@@ -416,6 +457,15 @@ lpfc_work_list_done(struct lpfc_hba *phb + */ + lpfc_nlp_put(ndlp); + break; ++ case LPFC_EVT_REAUTH: ++ ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); ++ lpfc_reauthentication_handler(ndlp); ++ free_evt = 0; /* evt is part of ndlp */ ++ /* decrement the node reference count held ++ * for this queued work ++ */ ++ lpfc_nlp_put(ndlp); ++ break; + case LPFC_EVT_DEV_LOSS: + ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + lpfc_dev_loss_tmo_handler(ndlp); +@@ -648,6 +698,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vpo + continue; + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + continue; ++ /* Stop re-authentication timer of all nodes. */ ++ del_timer_sync(&ndlp->nlp_reauth_tmr); ++ + if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || + ((vport->port_type == LPFC_NPIV_PORT) && + (ndlp->nlp_DID == NameServer_DID))) +@@ -697,6 +750,23 @@ lpfc_linkdown_port(struct lpfc_vport *vp + + lpfc_port_link_failure(vport); + ++ vport->auth.auth_state = LPFC_AUTH_UNKNOWN; ++ vport->auth.auth_msg_state = LPFC_AUTH_NONE; ++} ++ ++void ++lpfc_port_auth_failed(struct lpfc_nodelist *ndlp) ++{ ++ struct lpfc_vport *vport = ndlp->vport; ++ ++ vport->auth.auth_state = LPFC_AUTH_FAIL; ++ vport->auth.auth_msg_state = LPFC_AUTH_NONE; ++ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); ++ if (ndlp->nlp_type & NLP_FABRIC) { ++ lpfc_port_link_failure(vport); ++ lpfc_vport_set_state(vport, FC_VPORT_FAILED); ++ lpfc_issue_els_logo(vport, ndlp, 0); ++ } + } + + int +@@ -801,7 +871,6 @@ lpfc_linkup_port(struct lpfc_vport *vpor + return; + + fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0); +- + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | + FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); +@@ -1424,8 +1493,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lp + MAILBOX_t *mb = &pmb->mb; + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); + struct lpfc_nodelist *ndlp; +- struct lpfc_vport **vports; +- int i; + + ndlp = (struct lpfc_nodelist *) pmb->context2; + pmb->context1 = NULL; +@@ -1463,33 +1530,9 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lp + ndlp->nlp_type |= NLP_FABRIC; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + +- if (vport->port_state == LPFC_FABRIC_CFG_LINK) { +- vports = lpfc_create_vport_work_array(phba); +- if (vports != NULL) +- for(i = 0; +- i <= phba->max_vpi && vports[i] != NULL; +- i++) { +- if (vports[i]->port_type == LPFC_PHYSICAL_PORT) +- continue; +- if (phba->fc_topology == TOPOLOGY_LOOP) { +- lpfc_vport_set_state(vports[i], +- FC_VPORT_LINKDOWN); +- continue; +- } +- if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) +- lpfc_initial_fdisc(vports[i]); +- else { +- lpfc_vport_set_state(vports[i], +- FC_VPORT_NO_FABRIC_SUPP); +- lpfc_printf_vlog(vport, KERN_ERR, +- LOG_ELS, +- "0259 No NPIV " +- "Fabric support\n"); +- } +- } +- lpfc_destroy_vport_work_array(phba, vports); +- lpfc_do_scr_ns_plogi(phba, vport); +- } ++ if (vport->port_state == LPFC_FABRIC_CFG_LINK && ++ !vport->cfg_enable_auth) ++ lpfc_start_discovery(vport); + + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); +@@ -1894,9 +1937,13 @@ lpfc_enable_node(struct lpfc_vport *vpor + sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); + INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); + INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); ++ INIT_LIST_HEAD(&ndlp->els_reauth_evt.evt_listp); + init_timer(&ndlp->nlp_delayfunc); + ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; + ndlp->nlp_delayfunc.data = (unsigned long)ndlp; ++ init_timer(&ndlp->nlp_reauth_tmr); ++ ndlp->nlp_reauth_tmr.function = lpfc_reauth_node; ++ ndlp->nlp_reauth_tmr.data = (unsigned long)ndlp; + ndlp->nlp_DID = did; + ndlp->vport = vport; + ndlp->nlp_sid = NLP_NO_SID; +@@ -2264,9 +2311,12 @@ lpfc_cleanup_node(struct lpfc_vport *vpo + + ndlp->nlp_last_elscmd = 0; + del_timer_sync(&ndlp->nlp_delayfunc); ++ del_timer_sync(&ndlp->nlp_reauth_tmr); + + list_del_init(&ndlp->els_retry_evt.evt_listp); + list_del_init(&ndlp->dev_loss_evt.evt_listp); ++ if (!list_empty(&ndlp->els_reauth_evt.evt_listp)) ++ list_del_init(&ndlp->els_reauth_evt.evt_listp); + + lpfc_unreg_rpi(vport, ndlp); + +@@ -3073,7 +3123,14 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist + sizeof(ndlp->nlp_portname)) == 0; + } + +-static struct lpfc_nodelist * ++static int ++lpfc_filter_by_wwnn(struct lpfc_nodelist *ndlp, void *param) ++{ ++ return memcmp(&ndlp->nlp_nodename, param, ++ sizeof(ndlp->nlp_nodename)) == 0; ++} ++ ++struct lpfc_nodelist * + __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) + { + struct lpfc_nodelist *ndlp; +@@ -3086,6 +3143,22 @@ __lpfc_find_node(struct lpfc_vport *vpor + } + + /* ++ * Search node lists for a remote port matching filter criteria ++ * Caller needs to hold host_lock before calling this routine. ++ */ ++struct lpfc_nodelist * ++lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_nodelist *ndlp; ++ ++ spin_lock_irq(shost->host_lock); ++ ndlp = __lpfc_find_node(vport, filter, param); ++ spin_unlock_irq(shost->host_lock); ++ return ndlp; ++} ++ ++/* + * This routine looks up the ndlp lists for the given RPI. If rpi found it + * returns the node list element pointer else return NULL. + */ +@@ -3111,6 +3184,21 @@ lpfc_findnode_wwpn(struct lpfc_vport *vp + return ndlp; + } + ++/* ++ * This routine looks up the ndlp lists for the given WWNN. If WWNN found it ++ * returns the node element list pointer else return NULL. ++ */ ++struct lpfc_nodelist * ++lpfc_findnode_wwnn(struct lpfc_vport *vport, struct lpfc_name *wwnn) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ struct lpfc_nodelist *ndlp; ++ ++ spin_lock_irq(shost->host_lock); ++ ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwnn, wwnn); ++ spin_unlock_irq(shost->host_lock); ++ return ndlp; ++} + void + lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint32_t did) +@@ -3118,9 +3206,13 @@ lpfc_nlp_init(struct lpfc_vport *vport, + memset(ndlp, 0, sizeof (struct lpfc_nodelist)); + INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); + INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); ++ INIT_LIST_HEAD(&ndlp->els_reauth_evt.evt_listp); + init_timer(&ndlp->nlp_delayfunc); + ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; + ndlp->nlp_delayfunc.data = (unsigned long)ndlp; ++ init_timer(&ndlp->nlp_reauth_tmr); ++ ndlp->nlp_reauth_tmr.function = lpfc_reauth_node; ++ ndlp->nlp_reauth_tmr.data = (unsigned long)ndlp; + ndlp->nlp_DID = did; + ndlp->vport = vport; + ndlp->nlp_sid = NLP_NO_SID; +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -64,6 +64,7 @@ + #define SLI3_IOCB_CMD_SIZE 128 + #define SLI3_IOCB_RSP_SIZE 64 + ++#define BUF_SZ_4K 4096 + + /* Common Transport structures and definitions */ + +@@ -350,7 +351,8 @@ struct csp { + + uint16_t huntgroup:1; /* FC Word 1, bit 23 */ + uint16_t simplex:1; /* FC Word 1, bit 22 */ +- uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ ++ uint16_t security:1; /* FC Word 1, bit 21 */ ++ uint16_t word1Reserved1:2; /* FC Word 1, bit 20:19 */ + uint16_t dhd:1; /* FC Word 1, bit 18 */ + uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ + uint16_t payloadlength:1; /* FC Word 1, bit 16 */ +@@ -367,7 +369,8 @@ struct csp { + uint16_t payloadlength:1; /* FC Word 1, bit 16 */ + uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ + uint16_t dhd:1; /* FC Word 1, bit 18 */ +- uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ ++ uint16_t word1Reserved1:2; /* FC Word 1, bit 20:19 */ ++ uint16_t security:1; /* FC Word 1, bit 21 */ + uint16_t simplex:1; /* FC Word 1, bit 22 */ + uint16_t huntgroup:1; /* FC Word 1, bit 23 */ + #endif +@@ -506,6 +509,17 @@ struct serv_parm { /* Structure is in Bi + #define ELS_CMD_SCR 0x62000000 + #define ELS_CMD_RNID 0x78000000 + #define ELS_CMD_LIRR 0x7A000000 ++/* ++ * ELS commands for authentication ++ * ELS_CMD_AUTH<<24 | AUTH_NEGOTIATE<<8 | AUTH_VERSION ++ */ ++#define ELS_CMD_AUTH 0x90000000 ++#define ELS_CMD_AUTH_RJT 0x90000A01 ++#define ELS_CMD_AUTH_NEG 0x90000B01 ++#define ELS_CMD_AUTH_DONE 0x90000C01 ++#define ELS_CMD_DH_CHA 0x90001001 ++#define ELS_CMD_DH_REP 0x90001101 ++#define ELS_CMD_DH_SUC 0x90001201 + #else /* __LITTLE_ENDIAN_BITFIELD */ + #define ELS_CMD_MASK 0xffff + #define ELS_RSP_MASK 0xff +@@ -542,6 +556,17 @@ struct serv_parm { /* Structure is in Bi + #define ELS_CMD_SCR 0x62 + #define ELS_CMD_RNID 0x78 + #define ELS_CMD_LIRR 0x7A ++/* ++ * ELS commands for authentication ++ * ELS_CMD_AUTH | AUTH_NEGOTIATE<<16 | AUTH_VERSION<<24 ++ */ ++#define ELS_CMD_AUTH 0x00000090 ++#define ELS_CMD_AUTH_RJT 0x010A0090 ++#define ELS_CMD_AUTH_NEG 0x010B0090 ++#define ELS_CMD_AUTH_DONE 0x010C0090 ++#define ELS_CMD_DH_CHA 0x01100090 ++#define ELS_CMD_DH_REP 0x01110090 ++#define ELS_CMD_DH_SUC 0x01120090 + #endif + + /* +@@ -1319,6 +1344,9 @@ typedef struct { /* FireFly BIU registe + #define MBX_HEARTBEAT 0x31 + #define MBX_WRITE_VPARMS 0x32 + #define MBX_ASYNCEVT_ENABLE 0x33 ++#define MBX_READ_EVENT_LOG_STATUS 0x37 ++#define MBX_READ_EVENT_LOG 0x38 ++#define MBX_WRITE_EVENT_LOG 0x39 + + #define MBX_PORT_CAPABILITIES 0x3B + #define MBX_PORT_IOV_CONTROL 0x3C +@@ -1457,6 +1485,7 @@ typedef struct { /* FireFly BIU registe + #define MBXERR_BAD_RCV_LENGTH 14 + #define MBXERR_DMA_ERROR 15 + #define MBXERR_ERROR 16 ++#define MBXERR_UNKNOWN_CMD 18 + #define MBX_NOT_FINISHED 255 + + #define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ +@@ -1624,6 +1653,13 @@ typedef struct { + } un; + } BIU_DIAG_VAR; + ++/* Structure for MB command READ_EVENT_LOG (0x38) */ ++typedef struct { ++ uint32_t rsvd1; ++ uint32_t offset; ++ struct ulp_bde64 rcv_bde64; ++}READ_EVENT_LOG_VAR; ++ + /* Structure for MB Command INIT_LINK (05) */ + + typedef struct { +@@ -2744,6 +2780,10 @@ typedef struct { + /* Union of all Mailbox Command types */ + #define MAILBOX_CMD_WSIZE 32 + #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) ++#define MAILBOX_EXT_WSIZE 512 ++#define MAILBOX_EXT_SIZE (MAILBOX_EXT_WSIZE * sizeof(uint32_t)) ++#define MAILBOX_HBA_EXT_OFFSET 0x100 ++#define MAILBOX_MAX_XMIT_SIZE 1024 + + typedef union { + uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ +@@ -2783,6 +2823,7 @@ typedef union { + UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ + ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ + struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI) */ ++ READ_EVENT_LOG_VAR varRdEventLog; /* cmd = 0x38 (READ_EVENT_LOG) */ + } MAILVARIANTS; + + /* +@@ -3364,14 +3405,16 @@ typedef struct _IOCB { /* IOCB structure + #define SLI1_SLIM_SIZE (4 * 1024) + + /* Up to 498 IOCBs will fit into 16k +- * 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384 ++ * 256 (MAILBOX_t) + 512 mailbox extension + ++ * 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384 + */ + #define SLI2_SLIM_SIZE (64 * 1024) + + /* Maximum IOCBs that will fit in SLI2 slim */ + #define MAX_SLI2_IOCB 498 + #define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \ +- (sizeof(MAILBOX_t) + sizeof(PCB_t))) ++ (sizeof(MAILBOX_t) + sizeof(PCB_t) + \ ++ sizeof(uint32_t) * MAILBOX_EXT_WSIZE)) + + /* HBQ entries are 4 words each = 4k */ + #define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \ +@@ -3379,6 +3422,7 @@ typedef struct _IOCB { /* IOCB structure + + struct lpfc_sli2_slim { + MAILBOX_t mbx; ++ uint32_t mbx_ext_words[MAILBOX_EXT_WSIZE]; + PCB_t pcb; + IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE]; + }; +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -44,7 +44,22 @@ + #include "lpfc_crtn.h" + #include "lpfc_vport.h" + #include "lpfc_version.h" +- ++#include "lpfc_auth_access.h" ++#include "lpfc_security.h" ++#include ++#include ++ ++/* vendor ID used in SCSI netlink calls */ ++#define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX) ++const char *security_work_q_name = "fc_sc_wq"; ++extern struct workqueue_struct *security_work_q; ++extern struct list_head fc_security_user_list; ++extern int fc_service_state; ++void lpfc_fc_sc_security_online(struct work_struct *work); ++void lpfc_fc_sc_security_offline(struct work_struct *work); ++int lpfc_fc_queue_security_work(struct lpfc_vport *, struct work_struct *); ++void lpfc_rcv_nl_event(struct notifier_block *, unsigned long , void *); ++#include "lpfc_ioctl.h" + static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); + static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); + static int lpfc_post_rcv_buf(struct lpfc_hba *); +@@ -54,6 +69,26 @@ static struct scsi_transport_template *l + static DEFINE_IDR(lpfc_hba_index); + + /** ++ * lpfc_hba_max_vpi - Get the maximum supported VPI for an HBA ++ * @device: The PCI device ID for this HBA ++ * ++ * Description: ++ * This routine will return the maximum supported VPI limit for each HBA. In ++ * most cases the maximum VPI limit will be 0xFFFF, which indicates that the ++ * driver supports whatever the HBA can support. In some cases the driver ++ * supports fewer VPI that the HBA supports. ++ */ ++static inline uint16_t ++lpfc_hba_max_vpi(unsigned short device) ++{ ++ if ((device == PCI_DEVICE_ID_HELIOS) || ++ (device == PCI_DEVICE_ID_ZEPHYR)) ++ return LPFC_INTR_VPI; ++ else ++ return LPFC_MAX_VPI; ++} ++ ++/** + * lpfc_config_port_prep: Perform lpfc initialization prior to config port. + * @phba: pointer to lpfc hba data structure. + * +@@ -444,9 +479,20 @@ lpfc_config_port_post(struct lpfc_hba *p + /* Set up error attention (ERATT) polling timer */ + mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + ++ if (vport->cfg_enable_auth) { ++ if (lpfc_security_service_state == SECURITY_OFFLINE) { ++ lpfc_printf_log(vport->phba, KERN_ERR, LOG_SECURITY, ++ "1000 Authentication is enabled but " ++ "authentication service is not running\n"); ++ vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; ++ phba->link_state = LPFC_HBA_ERROR; ++ mempool_free(pmb, phba->mbox_mem_pool); ++ return 0; ++ } ++ } ++ + lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; +- lpfc_set_loopback_flag(phba); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +@@ -886,8 +932,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), + (char *) &temp_event_data, +- SCSI_NL_VID_TYPE_PCI +- | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + spin_lock_irq(&phba->hbalock); + phba->over_temp_state = HBA_OVER_TEMP; +@@ -909,7 +954,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + shost = lpfc_shost_from_vport(vport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(event_data), (char *) &event_data, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + lpfc_offline_eratt(phba); + } +@@ -1675,8 +1720,15 @@ lpfc_cleanup(struct lpfc_vport *vport) + void + lpfc_stop_vport_timers(struct lpfc_vport *vport) + { ++ struct fc_security_request *fc_sc_req; + del_timer_sync(&vport->els_tmofunc); + del_timer_sync(&vport->fc_fdmitmo); ++ while (!list_empty(&vport->sc_response_wait_queue)) { ++ fc_sc_req = list_get_first(&vport->sc_response_wait_queue, ++ struct fc_security_request, rlist); ++ del_timer_sync(&fc_sc_req->timer); ++ kfree(fc_sc_req); ++ } + lpfc_can_disctmo(vport); + return; + } +@@ -1963,12 +2015,7 @@ lpfc_create_port(struct lpfc_hba *phba, + struct Scsi_Host *shost; + int error = 0; + +- if (dev != &phba->pcidev->dev) +- shost = scsi_host_alloc(&lpfc_vport_template, +- sizeof(struct lpfc_vport)); +- else +- shost = scsi_host_alloc(&lpfc_template, +- sizeof(struct lpfc_vport)); ++ shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport)); + if (!shost) + goto out; + +@@ -2017,6 +2064,15 @@ lpfc_create_port(struct lpfc_hba *phba, + error = scsi_add_host(shost, dev); + if (error) + goto out_put_shost; ++ vport->auth.challenge = NULL; ++ vport->auth.challenge_len = 0; ++ vport->auth.dh_pub_key = NULL; ++ vport->auth.dh_pub_key_len = 0; ++ ++ INIT_WORK(&vport->sc_online_work, lpfc_fc_sc_security_online); ++ INIT_WORK(&vport->sc_offline_work, lpfc_fc_sc_security_offline); ++ INIT_LIST_HEAD(&vport->sc_users); ++ INIT_LIST_HEAD(&vport->sc_response_wait_queue); + + spin_lock_irq(&phba->hbalock); + list_add_tail(&vport->listentry, &phba->port_list); +@@ -2387,7 +2443,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + * establish the host. + */ + lpfc_get_cfgparam(phba); +- phba->max_vpi = LPFC_MAX_VPI; ++ phba->max_vpi = lpfc_hba_max_vpi(phba->pcidev->device); + + /* Initialize timers used by driver */ + init_timer(&phba->hb_tmofunc); +@@ -2453,6 +2509,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + + memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); + phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); ++ phba->mbox_ext = (phba->slim2p.virt + ++ offsetof(struct lpfc_sli2_slim, mbx_ext_words)); + phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); + phba->IOCBs = (phba->slim2p.virt + + offsetof(struct lpfc_sli2_slim, IOCBs)); +@@ -2548,11 +2606,30 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + /* Initialize list to save ELS buffers */ + INIT_LIST_HEAD(&phba->elsbuf); + ++ /* Initialize list of sysfs mailbox commands */ ++ INIT_LIST_HEAD(&phba->sysfs_mbox_list); ++ /* Initialize list of sysfs menlo commands */ ++ INIT_LIST_HEAD(&phba->sysfs_menlo_list); ++ + vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); + if (!vport) + goto out_kthread_stop; + + shost = lpfc_shost_from_vport(vport); ++ ++ if ((lpfc_get_security_enabled)(shost)) { ++ unsigned long flags; ++ /* Triggers fcauthd to register if it is running */ ++ fc_host_post_event(shost, fc_get_event_number(), ++ FCH_EVT_PORT_ONLINE, shost->host_no); ++ spin_lock_irqsave(&fc_security_user_lock, flags); ++ list_add_tail(&vport->sc_users, &fc_security_user_list); ++ spin_unlock_irqrestore(&fc_security_user_lock, flags); ++ if (fc_service_state == FC_SC_SERVICESTATE_ONLINE) { ++ lpfc_fc_queue_security_work(vport, ++ &vport->sc_online_work); ++ } ++ } + phba->pport = vport; + lpfc_debugfs_initialize(vport); + +@@ -2610,6 +2687,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + phba->intr_type = INTx; + } + ++ phba->dfc_host = lpfcdfc_host_add(pdev, shost, phba); ++ if (!phba->dfc_host) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1201 Failed to allocate dfc_host \n"); ++ error = -ENOMEM; ++ goto out_free_irq; ++ } ++ + if (lpfc_alloc_sysfs_attr(vport)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1476 Failed to allocate sysfs attr\n"); +@@ -2658,6 +2743,8 @@ out_remove_device: + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(shost->host_lock); + out_free_irq: ++ if (phba->dfc_host) ++ lpfcdfc_host_del(phba->dfc_host); + lpfc_stop_phba_timers(phba); + phba->pport->work_port_events = 0; + +@@ -2720,6 +2807,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev + struct lpfc_hba *phba = vport->phba; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + ++ /* In case PCI channel permanently disabled, rescan SCSI devices */ ++ if (pdev->error_state == pci_channel_io_perm_failure) ++ lpfc_scsi_dev_rescan(phba); ++ lpfcdfc_host_del(phba->dfc_host); ++ phba->dfc_host = NULL; ++ + spin_lock_irq(&phba->hbalock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(&phba->hbalock); +@@ -3076,12 +3169,34 @@ lpfc_init(void) + return -ENOMEM; + } + } ++ error = scsi_nl_add_driver(LPFC_NL_VENDOR_ID, &lpfc_template, ++ lpfc_rcv_nl_msg, lpfc_rcv_nl_event); ++ if (error) ++ goto out_release_transport; ++ security_work_q = create_singlethread_workqueue(security_work_q_name); ++ if (!security_work_q) ++ goto out_nl_remove_driver; ++ INIT_LIST_HEAD(&fc_security_user_list); + error = pci_register_driver(&lpfc_driver); +- if (error) { +- fc_release_transport(lpfc_transport_template); +- if (lpfc_enable_npiv) +- fc_release_transport(lpfc_vport_transport_template); +- } ++ if (error) ++ goto out_destroy_workqueue; ++ error = lpfc_cdev_init(); ++ if (error) ++ goto out_pci_unregister; ++ ++ return error; ++ ++out_pci_unregister: ++ pci_unregister_driver(&lpfc_driver); ++out_destroy_workqueue: ++ destroy_workqueue(security_work_q); ++ security_work_q = NULL; ++out_nl_remove_driver: ++ scsi_nl_remove_driver(LPFC_NL_VENDOR_ID); ++out_release_transport: ++ fc_release_transport(lpfc_transport_template); ++ if (lpfc_enable_npiv) ++ fc_release_transport(lpfc_vport_transport_template); + + return error; + } +@@ -3097,9 +3212,14 @@ static void __exit + lpfc_exit(void) + { + pci_unregister_driver(&lpfc_driver); ++ if (security_work_q) ++ destroy_workqueue(security_work_q); ++ security_work_q = NULL; ++ scsi_nl_remove_driver(LPFC_NL_VENDOR_ID); + fc_release_transport(lpfc_transport_template); + if (lpfc_enable_npiv) + fc_release_transport(lpfc_vport_transport_template); ++ lpfc_cdev_exit(); + } + + module_init(lpfc_init); +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_ioctl.c +@@ -0,0 +1,2519 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2008 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "lpfc_hw.h" ++#include "lpfc_sli.h" ++#include "lpfc_nl.h" ++#include "lpfc_disc.h" ++#include "lpfc_scsi.h" ++#include "lpfc.h" ++#include "lpfc_crtn.h" ++#include "lpfc_ioctl.h" ++#include "lpfc_logmsg.h" ++#include "lpfc_vport.h" ++ ++ ++struct lpfcdfc_event { ++ struct list_head node; ++ int ref; ++ wait_queue_head_t wq; ++ ++ /* Event type and waiter identifiers */ ++ uint32_t type_mask; ++ uint32_t req_id; ++ uint32_t reg_id; ++ ++ /* next two flags are here for the auto-delete logic */ ++ unsigned long wait_time_stamp; ++ int waiting; ++ ++ /* seen and not seen events */ ++ struct list_head events_to_get; ++ struct list_head events_to_see; ++}; ++ ++struct event_data { ++ struct list_head node; ++ uint32_t type; ++ uint32_t immed_dat; ++ void * data; ++ uint32_t len; ++}; ++ ++ ++/* values for a_topology */ ++#define LNK_LOOP 0x1 ++#define LNK_PUBLIC_LOOP 0x2 ++#define LNK_FABRIC 0x3 ++#define LNK_PT2PT 0x4 ++ ++/* values for a_linkState */ ++#define LNK_DOWN 0x1 ++#define LNK_UP 0x2 ++#define LNK_FLOGI 0x3 ++#define LNK_DISCOVERY 0x4 ++#define LNK_REDISCOVERY 0x5 ++#define LNK_READY 0x6 ++ ++struct lpfcdfc_host { ++ struct list_head node; ++ int inst; ++ struct lpfc_hba * phba; ++ struct lpfc_vport *vport; ++ struct Scsi_Host * host; ++ struct pci_dev * dev; ++ void (*base_ct_unsol_event)(struct lpfc_hba *, ++ struct lpfc_sli_ring *, ++ struct lpfc_iocbq *); ++ /* Threads waiting for async event */ ++ struct list_head ev_waiters; ++ uint32_t blocked; ++ uint32_t ref_count; ++}; ++ ++ ++ ++ ++static void lpfc_ioctl_timeout_iocb_cmpl(struct lpfc_hba *, ++ struct lpfc_iocbq *, struct lpfc_iocbq *); ++ ++static struct lpfc_dmabufext * ++dfc_cmd_data_alloc(struct lpfc_hba *, char *, ++ struct ulp_bde64 *, uint32_t); ++static int dfc_cmd_data_free(struct lpfc_hba *, struct lpfc_dmabufext *); ++static int dfc_rsp_data_copy(struct lpfc_hba *, uint8_t *, ++ struct lpfc_dmabufext *, ++ uint32_t); ++static int lpfc_issue_ct_rsp(struct lpfc_hba *, uint32_t, struct lpfc_dmabuf *, ++ struct lpfc_dmabufext *); ++ ++static struct lpfcdfc_host * lpfcdfc_host_from_hba(struct lpfc_hba *); ++ ++static DEFINE_MUTEX(lpfcdfc_lock); ++ ++static struct list_head lpfcdfc_hosts = LIST_HEAD_INIT(lpfcdfc_hosts); ++ ++static int lpfcdfc_major = 0; ++ ++static int ++lpfc_ioctl_hba_rnid(struct lpfc_hba * phba, ++ struct lpfcCmdInput * cip, ++ void *dataout) ++{ ++ struct nport_id idn; ++ struct lpfc_sli *psli; ++ struct lpfc_iocbq *cmdiocbq = NULL; ++ struct lpfc_iocbq *rspiocbq = NULL; ++ RNID *prsp; ++ uint32_t *pcmd; ++ uint32_t *psta; ++ IOCB_t *rsp; ++ struct lpfc_sli_ring *pring; ++ void *context2; ++ int i0; ++ int rtnbfrsiz; ++ struct lpfc_nodelist *pndl; ++ int rc = 0; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ ++ if (copy_from_user((uint8_t *) &idn, (void __user *) cip->lpfc_arg1, ++ sizeof(struct nport_id))) { ++ rc = EIO; ++ return rc; ++ } ++ ++ if (idn.idType == LPFC_WWNN_TYPE) ++ pndl = lpfc_findnode_wwnn(phba->pport, ++ (struct lpfc_name *) idn.wwpn); ++ else ++ pndl = lpfc_findnode_wwpn(phba->pport, ++ (struct lpfc_name *) idn.wwpn); ++ ++ if (!pndl || !NLP_CHK_NODE_ACT(pndl)) ++ return ENODEV; ++ ++ for (i0 = 0; ++ i0 < 10 && (pndl->nlp_flag & NLP_ELS_SND_MASK) == NLP_RNID_SND; ++ i0++) { ++ mdelay(1000); ++ } ++ ++ if (i0 == 10) { ++ pndl->nlp_flag &= ~NLP_RNID_SND; ++ return EBUSY; ++ } ++ ++ cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, (2 * sizeof(uint32_t)), 0, ++ pndl, pndl->nlp_DID, ELS_CMD_RNID); ++ if (!cmdiocbq) ++ return ENOMEM; ++ ++ /* ++ * Context2 is used by prep/free to locate cmd and rsp buffers, ++ * but context2 is also used by iocb_wait to hold a rspiocb ptr. ++ * The rsp iocbq can be returned from the completion routine for ++ * iocb_wait, so save the prep/free value locally . It will be ++ * restored after returning from iocb_wait. ++ */ ++ context2 = cmdiocbq->context2; ++ ++ if ((rspiocbq = lpfc_sli_get_iocbq(phba)) == NULL) { ++ rc = ENOMEM; ++ goto sndrndqwt; ++ } ++ rsp = &(rspiocbq->iocb); ++ ++ pcmd = (uint32_t *) (((struct lpfc_dmabuf *) cmdiocbq->context2)->virt); ++ *pcmd++ = ELS_CMD_RNID; ++ ++ memset((void *) pcmd, 0, sizeof (RNID)); ++ ((RNID *) pcmd)->Format = 0; ++ ((RNID *) pcmd)->Format = RNID_TOPOLOGY_DISC; ++ cmdiocbq->context1 = NULL; ++ cmdiocbq->context2 = NULL; ++ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; ++ ++ pndl->nlp_flag |= NLP_RNID_SND; ++ cmdiocbq->iocb.ulpTimeout = (phba->fc_ratov * 2) + 3 ; ++ ++ rc = lpfc_sli_issue_iocb_wait(phba, pring, cmdiocbq, rspiocbq, ++ (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); ++ pndl->nlp_flag &= ~NLP_RNID_SND; ++ cmdiocbq->context2 = context2; ++ ++ if (rc == IOCB_TIMEDOUT) { ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ cmdiocbq->context1 = NULL; ++ cmdiocbq->iocb_cmpl = lpfc_ioctl_timeout_iocb_cmpl; ++ return EIO; ++ } ++ ++ if (rc != IOCB_SUCCESS) { ++ rc = EIO; ++ goto sndrndqwt; ++ } ++ ++ if (rsp->ulpStatus == IOSTAT_SUCCESS) { ++ struct lpfc_dmabuf *buf_ptr1, *buf_ptr; ++ buf_ptr1 = (struct lpfc_dmabuf *)(cmdiocbq->context2); ++ buf_ptr = list_entry(buf_ptr1->list.next, struct lpfc_dmabuf, ++ list); ++ psta = (uint32_t*)buf_ptr->virt; ++ prsp = (RNID *) (psta + 1); /* then rnid response data */ ++ rtnbfrsiz = prsp->CommonLen + prsp->SpecificLen + ++ sizeof (uint32_t); ++ memcpy((uint8_t *) dataout, (uint8_t *) psta, rtnbfrsiz); ++ ++ if (rtnbfrsiz > cip->lpfc_outsz) ++ rtnbfrsiz = cip->lpfc_outsz; ++ if (copy_to_user ++ ((void __user *) cip->lpfc_arg2, (uint8_t *) & rtnbfrsiz, ++ sizeof (int))) ++ rc = EIO; ++ } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { ++ uint8_t ls_rjt[8]; ++ uint32_t *ls_rjtrsp; ++ ++ ls_rjtrsp = (uint32_t*)(ls_rjt + 4); ++ ++ /* construct the LS_RJT payload */ ++ ls_rjt[0] = 0x01; ++ ls_rjt[1] = 0x00; ++ ls_rjt[2] = 0x00; ++ ls_rjt[3] = 0x00; ++ ++ *ls_rjtrsp = be32_to_cpu(rspiocbq->iocb.un.ulpWord[4]); ++ rtnbfrsiz = 8; ++ memcpy((uint8_t *) dataout, (uint8_t *) ls_rjt, rtnbfrsiz); ++ if (copy_to_user ++ ((void __user *) cip->lpfc_arg2, (uint8_t *) & rtnbfrsiz, ++ sizeof (int))) ++ rc = EIO; ++ } else ++ rc = EACCES; ++ ++sndrndqwt: ++ if (cmdiocbq) ++ lpfc_els_free_iocb(phba, cmdiocbq); ++ ++ if (rspiocbq) ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ ++ return rc; ++} ++ ++static void ++lpfc_ioctl_timeout_iocb_cmpl(struct lpfc_hba * phba, ++ struct lpfc_iocbq * cmd_iocb_q, ++ struct lpfc_iocbq * rsp_iocb_q) ++{ ++ struct lpfc_timedout_iocb_ctxt *iocb_ctxt = cmd_iocb_q->context1; ++ ++ if (!iocb_ctxt) { ++ if (cmd_iocb_q->context2) ++ lpfc_els_free_iocb(phba, cmd_iocb_q); ++ else ++ lpfc_sli_release_iocbq(phba,cmd_iocb_q); ++ return; ++ } ++ ++ if (iocb_ctxt->outdmp) ++ dfc_cmd_data_free(phba, iocb_ctxt->outdmp); ++ ++ if (iocb_ctxt->indmp) ++ dfc_cmd_data_free(phba, iocb_ctxt->indmp); ++ ++ if (iocb_ctxt->mp) { ++ lpfc_mbuf_free(phba, ++ iocb_ctxt->mp->virt, ++ iocb_ctxt->mp->phys); ++ kfree(iocb_ctxt->mp); ++ } ++ ++ if (iocb_ctxt->bmp) { ++ lpfc_mbuf_free(phba, ++ iocb_ctxt->bmp->virt, ++ iocb_ctxt->bmp->phys); ++ kfree(iocb_ctxt->bmp); ++ } ++ ++ lpfc_sli_release_iocbq(phba,cmd_iocb_q); ++ ++ if (iocb_ctxt->rspiocbq) ++ lpfc_sli_release_iocbq(phba, iocb_ctxt->rspiocbq); ++ ++ kfree(iocb_ctxt); ++} ++ ++ ++static int ++lpfc_ioctl_send_els(struct lpfc_hba * phba, ++ struct lpfcCmdInput * cip, void *dataout) ++{ ++ struct lpfc_sli *psli = &phba->sli; ++ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; ++ struct lpfc_iocbq *cmdiocbq, *rspiocbq; ++ struct lpfc_dmabufext *pcmdext = NULL, *prspext = NULL; ++ struct lpfc_nodelist *pndl; ++ struct ulp_bde64 *bpl; ++ IOCB_t *rsp; ++ struct lpfc_dmabuf *pcmd, *prsp, *pbuflist = NULL; ++ uint16_t rpi = 0; ++ struct nport_id destID; ++ int rc = 0; ++ uint32_t cmdsize; ++ uint32_t rspsize; ++ uint32_t elscmd; ++ int iocb_status; ++ ++ elscmd = *(uint32_t *)cip->lpfc_arg2; ++ cmdsize = cip->lpfc_arg4; ++ rspsize = cip->lpfc_outsz; ++ ++ if (copy_from_user((uint8_t *)&destID, (void __user *)cip->lpfc_arg1, ++ sizeof(struct nport_id))) ++ return EIO; ++ ++ if ((rspiocbq = lpfc_sli_get_iocbq(phba)) == NULL) ++ return ENOMEM; ++ ++ rsp = &rspiocbq->iocb; ++ ++ if (destID.idType == 0) ++ pndl = lpfc_findnode_wwpn(phba->pport, ++ (struct lpfc_name *)&destID.wwpn); ++ else { ++ destID.d_id = (destID.d_id & Mask_DID); ++ pndl = lpfc_findnode_did(phba->pport, destID.d_id); ++ } ++ ++ if (!pndl || !NLP_CHK_NODE_ACT(pndl)) { ++ if (destID.idType == 0) { ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return ENODEV; ++ } ++ if (!pndl) { ++ pndl = kmalloc(sizeof (struct lpfc_nodelist), ++ GFP_KERNEL); ++ if (!pndl) { ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return ENODEV; ++ } ++ lpfc_nlp_init(phba->pport, pndl, destID.d_id); ++ lpfc_nlp_set_state(phba->pport, pndl, NLP_STE_NPR_NODE); ++ } else { ++ pndl = lpfc_enable_node(phba->pport, pndl, ++ NLP_STE_NPR_NODE); ++ if (!pndl) { ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return ENODEV; ++ } ++ } ++ } else { ++ lpfc_nlp_get(pndl); ++ rpi = pndl->nlp_rpi; ++ } ++ ++ cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, pndl, ++ pndl->nlp_DID, elscmd); ++ ++ /* release the new pndl once the iocb complete */ ++ lpfc_nlp_put(pndl); ++ ++ if (cmdiocbq == NULL) { ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return EIO; ++ } ++ ++ pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; ++ prsp = (struct lpfc_dmabuf *) pcmd->list.next; ++ ++ /* ++ * If we exceed the size of the allocated mbufs we need to ++ * free them and allocate our own. ++ */ ++ if ((cmdsize > LPFC_BPL_SIZE) || (rspsize > LPFC_BPL_SIZE)) { ++ lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); ++ kfree(pcmd); ++ lpfc_mbuf_free(phba, prsp->virt, prsp->phys); ++ kfree(prsp); ++ cmdiocbq->context2 = NULL; ++ ++ pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; ++ bpl = (struct ulp_bde64 *) pbuflist->virt; ++ pcmdext = dfc_cmd_data_alloc(phba, cip->lpfc_arg2, ++ bpl, cmdsize); ++ if (!pcmdext) { ++ lpfc_els_free_iocb(phba, cmdiocbq); ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return ENOMEM; ++ } ++ bpl += pcmdext->flag; ++ prspext = dfc_cmd_data_alloc(phba, NULL, bpl, rspsize); ++ if (!prspext) { ++ dfc_cmd_data_free(phba, pcmdext); ++ lpfc_els_free_iocb(phba, cmdiocbq); ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return ENOMEM; ++ } ++ } else { ++ /* Copy the command from user space */ ++ if (copy_from_user((uint8_t *) pcmd->virt, ++ (void __user *) cip->lpfc_arg2, ++ cmdsize)) { ++ lpfc_els_free_iocb(phba, cmdiocbq); ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return EIO; ++ } ++ } ++ ++ cmdiocbq->iocb.ulpContext = rpi; ++ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; ++ cmdiocbq->context1 = NULL; ++ cmdiocbq->context2 = NULL; ++ ++ iocb_status = lpfc_sli_issue_iocb_wait(phba, pring, cmdiocbq, rspiocbq, ++ (phba->fc_ratov*2) + LPFC_DRVR_TIMEOUT); ++ rc = iocb_status; ++ ++ if (rc == IOCB_SUCCESS) { ++ if (rsp->ulpStatus == IOSTAT_SUCCESS) { ++ if (rspsize < (rsp->un.ulpWord[0] & 0xffffff)) { ++ rc = ERANGE; ++ } else { ++ rspsize = rsp->un.ulpWord[0] & 0xffffff; ++ if (pbuflist) { ++ if (dfc_rsp_data_copy( ++ phba, ++ (uint8_t *) cip->lpfc_dataout, ++ prspext, ++ rspsize)) { ++ rc = EIO; ++ } else { ++ cip->lpfc_outsz = 0; ++ } ++ } else { ++ if (copy_to_user( (void __user *) ++ cip->lpfc_dataout, ++ (uint8_t *) prsp->virt, ++ rspsize)) { ++ rc = EIO; ++ } else { ++ cip->lpfc_outsz = 0; ++ } ++ } ++ } ++ } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { ++ uint8_t ls_rjt[8]; ++ ++ /* construct the LS_RJT payload */ ++ ls_rjt[0] = 0x01; ++ ls_rjt[1] = 0x00; ++ ls_rjt[2] = 0x00; ++ ls_rjt[3] = 0x00; ++ memcpy(&ls_rjt[4], (uint8_t *) &rsp->un.ulpWord[4], ++ sizeof(uint32_t)); ++ ++ if (rspsize < 8) ++ rc = ERANGE; ++ else ++ rspsize = 8; ++ ++ memcpy(dataout, ls_rjt, rspsize); ++ } else ++ rc = EIO; ++ ++ if (copy_to_user((void __user *)cip->lpfc_arg3, ++ (uint8_t *)&rspsize, sizeof(uint32_t))) ++ rc = EIO; ++ } else { ++ rc = EIO; ++ } ++ ++ if (pbuflist) { ++ dfc_cmd_data_free(phba, pcmdext); ++ dfc_cmd_data_free(phba, prspext); ++ } else ++ cmdiocbq->context2 = (uint8_t *) pcmd; ++ ++ if (iocb_status != IOCB_TIMEDOUT) ++ lpfc_els_free_iocb(phba, cmdiocbq); ++ ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ return rc; ++} ++ ++static int ++lpfc_ioctl_send_mgmt_rsp(struct lpfc_hba * phba, ++ struct lpfcCmdInput * cip) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); ++ struct ulp_bde64 *bpl; ++ struct lpfc_dmabuf *bmp = NULL; ++ struct lpfc_dmabufext *indmp = NULL; ++ uint32_t tag = (uint32_t)cip->lpfc_flag; /* XRI for XMIT_SEQUENCE */ ++ unsigned long reqbfrcnt = (unsigned long)cip->lpfc_arg2; ++ int rc = 0; ++ unsigned long iflag; ++ ++ if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { ++ rc = ERANGE; ++ return rc; ++ } ++ ++ bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); ++ if (!bmp) { ++ rc = ENOMEM; ++ goto send_mgmt_rsp_exit; ++ } ++ spin_lock_irqsave(shost->host_lock, iflag); ++ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); ++ spin_unlock_irqrestore(shost->host_lock, iflag); /* remove */ ++ if (!bmp->virt) { ++ rc = ENOMEM; ++ goto send_mgmt_rsp_free_bmp; ++ } ++ ++ INIT_LIST_HEAD(&bmp->list); ++ bpl = (struct ulp_bde64 *) bmp->virt; ++ ++ indmp = dfc_cmd_data_alloc(phba, cip->lpfc_arg1, bpl, reqbfrcnt); ++ if (!indmp) { ++ rc = ENOMEM; ++ goto send_mgmt_rsp_free_bmpvirt; ++ } ++ rc = lpfc_issue_ct_rsp(phba, tag, bmp, indmp); ++ if (rc) { ++ if (rc == IOCB_TIMEDOUT) ++ rc = ETIMEDOUT; ++ else if (rc == IOCB_ERROR) ++ rc = EACCES; ++ } ++ ++ dfc_cmd_data_free(phba, indmp); ++send_mgmt_rsp_free_bmpvirt: ++ lpfc_mbuf_free(phba, bmp->virt, bmp->phys); ++send_mgmt_rsp_free_bmp: ++ kfree(bmp); ++send_mgmt_rsp_exit: ++ return rc; ++} ++ ++static int ++lpfc_ioctl_send_mgmt_cmd(struct lpfc_hba * phba, ++ struct lpfcCmdInput * cip, void *dataout) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); ++ struct lpfc_nodelist *pndl = NULL; ++ struct ulp_bde64 *bpl = NULL; ++ struct lpfc_name findwwn; ++ uint32_t finddid, timeout; ++ struct lpfc_iocbq *cmdiocbq = NULL, *rspiocbq = NULL; ++ struct lpfc_dmabufext *indmp = NULL, *outdmp = NULL; ++ IOCB_t *cmd = NULL, *rsp = NULL; ++ struct lpfc_dmabuf *bmp = NULL; ++ struct lpfc_sli *psli = NULL; ++ struct lpfc_sli_ring *pring = NULL; ++ int i0 = 0, rc = 0, reqbfrcnt, snsbfrcnt; ++ struct lpfc_timedout_iocb_ctxt *iocb_ctxt; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ ++ if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { ++ rc = EACCES; ++ goto send_mgmt_cmd_exit; ++ } ++ ++ reqbfrcnt = cip->lpfc_arg4; ++ snsbfrcnt = cip->lpfc_arg5; ++ ++ if (!reqbfrcnt || !snsbfrcnt ++ || (reqbfrcnt + snsbfrcnt > 80 * BUF_SZ_4K)) { ++ rc = ERANGE; ++ goto send_mgmt_cmd_exit; ++ } ++ ++ if (phba->pport->port_state != LPFC_VPORT_READY) { ++ rc = ENODEV; ++ goto send_mgmt_cmd_exit; ++ } ++ ++ if (cip->lpfc_cmd == LPFC_HBA_SEND_MGMT_CMD) { ++ rc = copy_from_user(&findwwn, (void __user *)cip->lpfc_arg3, ++ sizeof(struct lpfc_name)); ++ if (rc) { ++ rc = EIO; ++ goto send_mgmt_cmd_exit; ++ } ++ pndl = lpfc_findnode_wwpn(phba->pport, &findwwn); ++ /* Do additional get to pndl found so that at the end of the ++ * function we can do unditional lpfc_nlp_put on it. ++ */ ++ if (pndl && NLP_CHK_NODE_ACT(pndl)) ++ lpfc_nlp_get(pndl); ++ } else { ++ finddid = (uint32_t)(unsigned long)cip->lpfc_arg3; ++ pndl = lpfc_findnode_did(phba->pport, finddid); ++ if (!pndl || !NLP_CHK_NODE_ACT(pndl)) { ++ if (phba->pport->fc_flag & FC_FABRIC) { ++ if (!pndl) { ++ pndl = kmalloc(sizeof ++ (struct lpfc_nodelist), ++ GFP_KERNEL); ++ if (!pndl) { ++ rc = ENODEV; ++ goto send_mgmt_cmd_exit; ++ } ++ lpfc_nlp_init(phba->pport, pndl, ++ finddid); ++ lpfc_nlp_set_state(phba->pport, ++ pndl, NLP_STE_PLOGI_ISSUE); ++ /* Indicate free ioctl allocated ++ * memory for ndlp after it's done ++ */ ++ NLP_SET_FREE_REQ(pndl); ++ } else ++ lpfc_enable_node(phba->pport, ++ pndl, NLP_STE_PLOGI_ISSUE); ++ ++ if (lpfc_issue_els_plogi(phba->pport, ++ pndl->nlp_DID, 0)) { ++ rc = ENODEV; ++ goto send_mgmt_cmd_free_pndl_exit; ++ } ++ ++ /* Allow the node to complete discovery */ ++ while (i0++ < 4) { ++ if (pndl->nlp_state == ++ NLP_STE_UNMAPPED_NODE) ++ break; ++ msleep(500); ++ } ++ ++ if (i0 == 4) { ++ rc = ENODEV; ++ goto send_mgmt_cmd_free_pndl_exit; ++ } ++ } else { ++ rc = ENODEV; ++ goto send_mgmt_cmd_exit; ++ } ++ } else ++ /* Do additional get to pndl found so at the end of ++ * the function we can do unconditional lpfc_nlp_put. ++ */ ++ lpfc_nlp_get(pndl); ++ } ++ ++ if (!pndl || !NLP_CHK_NODE_ACT(pndl)) { ++ rc = ENODEV; ++ goto send_mgmt_cmd_exit; ++ } ++ ++ if (pndl->nlp_flag & NLP_ELS_SND_MASK) { ++ rc = ENODEV; ++ goto send_mgmt_cmd_free_pndl_exit; ++ } ++ ++ spin_lock_irq(shost->host_lock); ++ cmdiocbq = lpfc_sli_get_iocbq(phba); ++ if (!cmdiocbq) { ++ rc = ENOMEM; ++ spin_unlock_irq(shost->host_lock); ++ goto send_mgmt_cmd_free_pndl_exit; ++ } ++ cmd = &cmdiocbq->iocb; ++ ++ rspiocbq = lpfc_sli_get_iocbq(phba); ++ if (!rspiocbq) { ++ rc = ENOMEM; ++ goto send_mgmt_cmd_free_cmdiocbq; ++ } ++ spin_unlock_irq(shost->host_lock); ++ ++ rsp = &rspiocbq->iocb; ++ ++ bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); ++ if (!bmp) { ++ rc = ENOMEM; ++ spin_lock_irq(shost->host_lock); ++ goto send_mgmt_cmd_free_rspiocbq; ++ } ++ ++ spin_lock_irq(shost->host_lock); ++ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); ++ if (!bmp->virt) { ++ rc = ENOMEM; ++ goto send_mgmt_cmd_free_bmp; ++ } ++ spin_unlock_irq(shost->host_lock); ++ ++ INIT_LIST_HEAD(&bmp->list); ++ bpl = (struct ulp_bde64 *) bmp->virt; ++ indmp = dfc_cmd_data_alloc(phba, cip->lpfc_arg1, bpl, reqbfrcnt); ++ if (!indmp) { ++ rc = ENOMEM; ++ spin_lock_irq(shost->host_lock); ++ goto send_mgmt_cmd_free_bmpvirt; ++ } ++ ++ /* flag contains total number of BPLs for xmit */ ++ bpl += indmp->flag; ++ ++ outdmp = dfc_cmd_data_alloc(phba, NULL, bpl, snsbfrcnt); ++ if (!outdmp) { ++ rc = ENOMEM; ++ spin_lock_irq(shost->host_lock); ++ goto send_mgmt_cmd_free_indmp; ++ } ++ ++ cmd->un.genreq64.bdl.ulpIoTag32 = 0; ++ cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); ++ cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); ++ cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; ++ cmd->un.genreq64.bdl.bdeSize = ++ (outdmp->flag + indmp->flag) * sizeof (struct ulp_bde64); ++ cmd->ulpCommand = CMD_GEN_REQUEST64_CR; ++ cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); ++ cmd->un.genreq64.w5.hcsw.Dfctl = 0; ++ cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; ++ cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; ++ cmd->ulpBdeCount = 1; ++ cmd->ulpLe = 1; ++ cmd->ulpClass = CLASS3; ++ cmd->ulpContext = pndl->nlp_rpi; ++ cmd->ulpOwner = OWN_CHIP; ++ cmdiocbq->vport = phba->pport; ++ cmdiocbq->context1 = NULL; ++ cmdiocbq->context2 = NULL; ++ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; ++ ++ if (cip->lpfc_flag == 0 ) ++ timeout = phba->fc_ratov * 2 ; ++ else ++ timeout = cip->lpfc_flag; ++ ++ cmd->ulpTimeout = timeout; ++ ++ rc = lpfc_sli_issue_iocb_wait(phba, pring, cmdiocbq, rspiocbq, ++ timeout + LPFC_DRVR_TIMEOUT); ++ ++ if (rc == IOCB_TIMEDOUT) { ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ iocb_ctxt = kmalloc(sizeof(struct lpfc_timedout_iocb_ctxt), ++ GFP_KERNEL); ++ if (!iocb_ctxt) { ++ rc = EACCES; ++ goto send_mgmt_cmd_free_pndl_exit; ++ } ++ ++ cmdiocbq->context1 = iocb_ctxt; ++ cmdiocbq->context2 = NULL; ++ iocb_ctxt->rspiocbq = NULL; ++ iocb_ctxt->mp = NULL; ++ iocb_ctxt->bmp = bmp; ++ iocb_ctxt->outdmp = outdmp; ++ iocb_ctxt->lpfc_cmd = NULL; ++ iocb_ctxt->indmp = indmp; ++ ++ cmdiocbq->iocb_cmpl = lpfc_ioctl_timeout_iocb_cmpl; ++ rc = EACCES; ++ goto send_mgmt_cmd_free_pndl_exit; ++ } ++ ++ if (rc != IOCB_SUCCESS) { ++ rc = EACCES; ++ goto send_mgmt_cmd_free_outdmp; ++ } ++ ++ if (rsp->ulpStatus) { ++ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { ++ switch (rsp->un.ulpWord[4] & 0xff) { ++ case IOERR_SEQUENCE_TIMEOUT: ++ rc = ETIMEDOUT; ++ break; ++ case IOERR_INVALID_RPI: ++ rc = EFAULT; ++ break; ++ default: ++ rc = EACCES; ++ break; ++ } ++ goto send_mgmt_cmd_free_outdmp; ++ } ++ } else ++ outdmp->flag = rsp->un.genreq64.bdl.bdeSize; ++ ++ /* Copy back response data */ ++ if (outdmp->flag > snsbfrcnt) { ++ rc = ERANGE; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1209 C_CT Request error Data: x%x x%x\n", ++ outdmp->flag, BUF_SZ_4K); ++ goto send_mgmt_cmd_free_outdmp; ++ } ++ ++ /* copy back size of response, and response itself */ ++ memcpy(dataout, &outdmp->flag, sizeof (int)); ++ rc = dfc_rsp_data_copy (phba, cip->lpfc_arg2, outdmp, outdmp->flag); ++ if (rc) ++ rc = EIO; ++ ++send_mgmt_cmd_free_outdmp: ++ spin_lock_irq(shost->host_lock); ++ dfc_cmd_data_free(phba, outdmp); ++send_mgmt_cmd_free_indmp: ++ dfc_cmd_data_free(phba, indmp); ++send_mgmt_cmd_free_bmpvirt: ++ lpfc_mbuf_free(phba, bmp->virt, bmp->phys); ++send_mgmt_cmd_free_bmp: ++ kfree(bmp); ++send_mgmt_cmd_free_rspiocbq: ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++send_mgmt_cmd_free_cmdiocbq: ++ lpfc_sli_release_iocbq(phba, cmdiocbq); ++ spin_unlock_irq(shost->host_lock); ++send_mgmt_cmd_free_pndl_exit: ++ lpfc_nlp_put(pndl); ++send_mgmt_cmd_exit: ++ return rc; ++} ++ ++static inline struct lpfcdfc_event * ++lpfcdfc_event_new(uint32_t ev_mask, ++ int ev_reg_id, ++ uint32_t ev_req_id) ++{ ++ struct lpfcdfc_event * evt = kzalloc(sizeof(*evt), GFP_KERNEL); ++ if (evt == NULL) ++ return NULL; ++ ++ INIT_LIST_HEAD(&evt->events_to_get); ++ INIT_LIST_HEAD(&evt->events_to_see); ++ evt->type_mask = ev_mask; ++ evt->req_id = ev_req_id; ++ evt->reg_id = ev_reg_id; ++ evt->wait_time_stamp = jiffies; ++ init_waitqueue_head(&evt->wq); ++ ++ return evt; ++} ++ ++static inline void lpfcdfc_event_free(struct lpfcdfc_event * evt) ++{ ++ struct event_data * ed; ++ ++ list_del(&evt->node); ++ ++ while(!list_empty(&evt->events_to_get)) { ++ ed = list_entry(evt->events_to_get.next, typeof(*ed), node); ++ list_del(&ed->node); ++ kfree(ed->data); ++ kfree(ed); ++ } ++ ++ while(!list_empty(&evt->events_to_see)) { ++ ed = list_entry(evt->events_to_see.next, typeof(*ed), node); ++ list_del(&ed->node); ++ kfree(ed->data); ++ kfree(ed); ++ } ++ ++ kfree(evt); ++} ++ ++#define lpfcdfc_event_ref(evt) evt->ref++ ++ ++#define lpfcdfc_event_unref(evt) \ ++ if (--evt->ref < 0) \ ++ lpfcdfc_event_free(evt); ++ ++static int ++lpfc_ioctl_hba_get_event(struct lpfc_hba * phba, ++ struct lpfcCmdInput * cip, ++ void **dataout, int *data_size) ++{ ++ uint32_t ev_mask = ((uint32_t)(unsigned long)cip->lpfc_arg3 & ++ FC_REG_EVENT_MASK); ++ int ev_reg_id = (uint32_t) cip->lpfc_flag; ++ uint32_t ev_req_id = 0; ++ struct lpfcdfc_host * dfchba; ++ struct lpfcdfc_event * evt; ++ struct event_data * evt_dat = NULL; ++ int ret_val = 0; ++ ++ /* All other events supported through NET_LINK_EVENTs */ ++ if (ev_mask != FC_REG_CT_EVENT) ++ return ENOENT; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(dfchba, &lpfcdfc_hosts, node) ++ if (dfchba->phba == phba) ++ break; ++ mutex_unlock(&lpfcdfc_lock); ++ ++ BUG_ON(&dfchba->node == &lpfcdfc_hosts); ++ ++ if ((ev_mask == FC_REG_CT_EVENT) && ++ copy_from_user(&ev_req_id, (void __user *)cip->lpfc_arg2, ++ sizeof (uint32_t))) ++ return EIO; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(evt, &dfchba->ev_waiters, node) ++ if (evt->reg_id == ev_reg_id) { ++ if(list_empty(&evt->events_to_get)) ++ break; ++ lpfcdfc_event_ref(evt); ++ evt->wait_time_stamp = jiffies; ++ evt_dat = list_entry(evt->events_to_get.prev, ++ struct event_data, node); ++ list_del(&evt_dat->node); ++ break; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ ++ if (evt_dat == NULL) ++ return ENOENT; ++ ++ BUG_ON((ev_mask & evt_dat->type) == 0); ++ ++ if (evt_dat->len > cip->lpfc_outsz) ++ evt_dat->len = cip->lpfc_outsz; ++ ++ if (copy_to_user((void __user *)cip->lpfc_arg2, &evt_dat->immed_dat, ++ sizeof (uint32_t)) || ++ copy_to_user((void __user *)cip->lpfc_arg1, &evt_dat->len, ++ sizeof (uint32_t))) { ++ ret_val = EIO; ++ goto error_get_event_exit; ++ } ++ ++ if (evt_dat->len > 0) { ++ *data_size = evt_dat->len; ++ *dataout = kmalloc(*data_size, GFP_KERNEL); ++ if (*dataout) ++ memcpy(*dataout, evt_dat->data, *data_size); ++ else ++ *data_size = 0; ++ ++ } else ++ *data_size = 0; ++ ret_val = 0; ++ ++error_get_event_exit: ++ ++ kfree(evt_dat->data); ++ kfree(evt_dat); ++ mutex_lock(&lpfcdfc_lock); ++ lpfcdfc_event_unref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ ++ return ret_val; ++} ++ ++static int ++lpfc_ioctl_hba_set_event(struct lpfc_hba * phba, ++ struct lpfcCmdInput * cip) ++{ ++ uint32_t ev_mask = ((uint32_t)(unsigned long)cip->lpfc_arg3 & ++ FC_REG_EVENT_MASK); ++ int ev_reg_id = cip->lpfc_flag; ++ uint32_t ev_req_id = 0; ++ ++ struct lpfcdfc_host * dfchba; ++ struct lpfcdfc_event * evt; ++ ++ int ret_val = 0; ++ ++ /* All other events supported through NET_LINK_EVENTs */ ++ if (ev_mask != FC_REG_CT_EVENT) ++ return ENOENT; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(dfchba, &lpfcdfc_hosts, node) { ++ if (dfchba->phba == phba) ++ break; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ BUG_ON(&dfchba->node == &lpfcdfc_hosts); ++ ++ if (ev_mask == FC_REG_CT_EVENT) ++ ev_req_id = ((uint32_t)(unsigned long)cip->lpfc_arg2); ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(evt, &dfchba->ev_waiters, node) { ++ if (evt->reg_id == ev_reg_id) { ++ lpfcdfc_event_ref(evt); ++ evt->wait_time_stamp = jiffies; ++ break; ++ } ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ ++ if (&evt->node == &dfchba->ev_waiters) { ++ /* no event waiting struct yet - first call */ ++ evt = lpfcdfc_event_new(ev_mask, ev_reg_id, ev_req_id); ++ if (evt == NULL) ++ return ENOMEM; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_add(&evt->node, &dfchba->ev_waiters); ++ lpfcdfc_event_ref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ } ++ ++ evt->waiting = 1; ++ if (wait_event_interruptible(evt->wq, ++ (!list_empty(&evt->events_to_see) || ++ dfchba->blocked))) { ++ mutex_lock(&lpfcdfc_lock); ++ lpfcdfc_event_unref(evt); /* release ref */ ++ lpfcdfc_event_unref(evt); /* delete */ ++ mutex_unlock(&lpfcdfc_lock); ++ return EINTR; ++ } ++ ++ mutex_lock(&lpfcdfc_lock); ++ if (dfchba->blocked) { ++ lpfcdfc_event_unref(evt); ++ lpfcdfc_event_unref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ return ENODEV; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ ++ evt->wait_time_stamp = jiffies; ++ evt->waiting = 0; ++ ++ BUG_ON(list_empty(&evt->events_to_see)); ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_move(evt->events_to_see.prev, &evt->events_to_get); ++ lpfcdfc_event_unref(evt); /* release ref */ ++ mutex_unlock(&lpfcdfc_lock); ++ ++ return ret_val; ++} ++ ++static int ++lpfc_ioctl_loopback_mode(struct lpfc_hba *phba, ++ struct lpfcCmdInput *cip, void *dataout) ++{ ++ struct Scsi_Host *shost; ++ struct lpfc_sli *psli = &phba->sli; ++ struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; ++ uint32_t link_flags = cip->lpfc_arg4; ++ uint32_t timeout = cip->lpfc_arg5 * 100; ++ struct lpfc_vport **vports; ++ LPFC_MBOXQ_t *pmboxq; ++ int mbxstatus; ++ int i = 0; ++ int rc = 0; ++ ++ if ((phba->link_state == LPFC_HBA_ERROR) || ++ (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || ++ (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) ++ return EACCES; ++ ++ if ((pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL)) == 0) ++ return ENOMEM; ++ ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports != NULL) { ++ for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++){ ++ shost = lpfc_shost_from_vport(vports[i]); ++ scsi_block_requests(shost); ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++ } ++ else { ++ shost = lpfc_shost_from_vport(phba->pport); ++ scsi_block_requests(shost); ++ } ++ ++ while (pring->txcmplq_cnt) { ++ if (i++ > 500) /* wait up to 5 seconds */ ++ break; ++ ++ mdelay(10); ++ } ++ ++ memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); ++ pmboxq->mb.mbxCommand = MBX_DOWN_LINK; ++ pmboxq->mb.mbxOwner = OWN_HOST; ++ ++ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); ++ ++ if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) { ++ ++ /* wait for link down before proceeding */ ++ i = 0; ++ while (phba->link_state != LPFC_LINK_DOWN) { ++ if (i++ > timeout) { ++ rc = ETIMEDOUT; ++ goto loopback_mode_exit; ++ } ++ msleep(10); ++ } ++ ++ memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); ++ if (link_flags == INTERNAL_LOOP_BACK) ++ pmboxq->mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; ++ else ++ pmboxq->mb.un.varInitLnk.link_flags = ++ FLAGS_TOPOLOGY_MODE_LOOP; ++ ++ pmboxq->mb.mbxCommand = MBX_INIT_LINK; ++ pmboxq->mb.mbxOwner = OWN_HOST; ++ ++ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, ++ LPFC_MBOX_TMO); ++ ++ if ((mbxstatus != MBX_SUCCESS) || (pmboxq->mb.mbxStatus)) ++ rc = ENODEV; ++ else { ++ phba->link_flag |= LS_LOOPBACK_MODE; ++ /* wait for the link attention interrupt */ ++ msleep(100); ++ ++ i = 0; ++ while (phba->link_state != LPFC_HBA_READY) { ++ if (i++ > timeout) { ++ rc = ETIMEDOUT; ++ break; ++ } ++ msleep(10); ++ } ++ } ++ } else ++ rc = ENODEV; ++ ++loopback_mode_exit: ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports != NULL) { ++ for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++){ ++ shost = lpfc_shost_from_vport(vports[i]); ++ scsi_unblock_requests(shost); ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++ } ++ else { ++ shost = lpfc_shost_from_vport(phba->pport); ++ scsi_unblock_requests(shost); ++ } ++ ++ /* ++ * Let SLI layer release mboxq if mbox command completed after timeout. ++ */ ++ if (mbxstatus != MBX_TIMEOUT) ++ mempool_free( pmboxq, phba->mbox_mem_pool); ++ ++ return rc; ++} ++ ++static int lpfcdfc_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi) ++{ ++ LPFC_MBOXQ_t *mbox; ++ struct lpfc_dmabuf *dmabuff; ++ int status; ++ ++ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); ++ if (mbox == NULL) ++ return ENOMEM; ++ ++ status = lpfc_reg_login(phba, 0, phba->pport->fc_myDID, ++ (uint8_t *)&phba->pport->fc_sparam, mbox, 0); ++ if (status) { ++ mempool_free(mbox, phba->mbox_mem_pool); ++ return ENOMEM; ++ } ++ ++ dmabuff = (struct lpfc_dmabuf *) mbox->context1; ++ mbox->context1 = NULL; ++ status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); ++ ++ if ((status != MBX_SUCCESS) || (mbox->mb.mbxStatus)) { ++ lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); ++ kfree(dmabuff); ++ if (status != MBX_TIMEOUT) ++ mempool_free(mbox, phba->mbox_mem_pool); ++ return ENODEV; ++ } ++ ++ *rpi = mbox->mb.un.varWords[0]; ++ ++ lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); ++ kfree(dmabuff); ++ mempool_free(mbox, phba->mbox_mem_pool); ++ ++ return 0; ++} ++ ++static int lpfcdfc_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) ++{ ++ LPFC_MBOXQ_t * mbox; ++ int status; ++ ++ /* Allocate mboxq structure */ ++ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); ++ if (mbox == NULL) ++ return ENOMEM; ++ ++ lpfc_unreg_login(phba, 0, rpi, mbox); ++ status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); ++ ++ if ((status != MBX_SUCCESS) || (mbox->mb.mbxStatus)) { ++ if (status != MBX_TIMEOUT) ++ mempool_free(mbox, phba->mbox_mem_pool); ++ return EIO; ++ } ++ ++ mempool_free(mbox, phba->mbox_mem_pool); ++ return 0; ++} ++ ++ ++static int lpfcdfc_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, ++ uint16_t *txxri, uint16_t * rxxri) ++{ ++ struct lpfc_sli *psli = &phba->sli; ++ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; ++ ++ struct lpfcdfc_host * dfchba; ++ struct lpfcdfc_event * evt; ++ ++ struct lpfc_iocbq *cmdiocbq, *rspiocbq; ++ IOCB_t *cmd, *rsp; ++ ++ struct lpfc_dmabuf * dmabuf; ++ struct ulp_bde64 *bpl = NULL; ++ struct lpfc_sli_ct_request *ctreq = NULL; ++ ++ int ret_val = 0; ++ ++ *txxri = 0; ++ *rxxri = 0; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(dfchba, &lpfcdfc_hosts, node) { ++ if (dfchba->phba == phba) ++ break; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ BUG_ON(&dfchba->node == &lpfcdfc_hosts); ++ ++ evt = lpfcdfc_event_new(FC_REG_CT_EVENT, current->pid, ++ SLI_CT_ELX_LOOPBACK); ++ if (evt == NULL) ++ return ENOMEM; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_add(&evt->node, &dfchba->ev_waiters); ++ lpfcdfc_event_ref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ ++ cmdiocbq = lpfc_sli_get_iocbq(phba); ++ rspiocbq = lpfc_sli_get_iocbq(phba); ++ ++ dmabuf = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); ++ if (dmabuf) { ++ dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); ++ INIT_LIST_HEAD(&dmabuf->list); ++ bpl = (struct ulp_bde64 *) dmabuf->virt; ++ memset(bpl, 0, sizeof(*bpl)); ++ ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); ++ bpl->addrHigh = ++ le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl))); ++ bpl->addrLow = ++ le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl))); ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; ++ bpl->tus.w = le32_to_cpu(bpl->tus.w); ++ } ++ ++ if (cmdiocbq == NULL || rspiocbq == NULL || ++ dmabuf == NULL || bpl == NULL || ctreq == NULL) { ++ ret_val = ENOMEM; ++ goto err_get_xri_exit; ++ } ++ ++ cmd = &cmdiocbq->iocb; ++ rsp = &rspiocbq->iocb; ++ ++ memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); ++ ++ ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; ++ ctreq->RevisionId.bits.InId = 0; ++ ctreq->FsType = SLI_CT_ELX_LOOPBACK; ++ ctreq->FsSubType = 0; ++ ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; ++ ctreq->CommandResponse.bits.Size = 0; ++ ++ ++ cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); ++ cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); ++ cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; ++ cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); ++ ++ cmd->un.xseq64.w5.hcsw.Fctl = LA; ++ cmd->un.xseq64.w5.hcsw.Dfctl = 0; ++ cmd->un.xseq64.w5.hcsw.Rctl = FC_UNSOL_CTL; ++ cmd->un.xseq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; ++ ++ cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; ++ cmd->ulpBdeCount = 1; ++ cmd->ulpLe = 1; ++ cmd->ulpClass = CLASS3; ++ cmd->ulpContext = rpi; ++ ++ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; ++ cmdiocbq->vport = phba->pport; ++ ++ ret_val = lpfc_sli_issue_iocb_wait(phba, pring, cmdiocbq, rspiocbq, ++ (phba->fc_ratov * 2) ++ + LPFC_DRVR_TIMEOUT); ++ if (ret_val) ++ goto err_get_xri_exit; ++ ++ *txxri = rsp->ulpContext; ++ ++ evt->waiting = 1; ++ evt->wait_time_stamp = jiffies; ++ ret_val = wait_event_interruptible_timeout( ++ evt->wq, !list_empty(&evt->events_to_see), ++ ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); ++ if (list_empty(&evt->events_to_see)) ++ ret_val = (ret_val) ? EINTR : ETIMEDOUT; ++ else { ++ ret_val = IOCB_SUCCESS; ++ mutex_lock(&lpfcdfc_lock); ++ list_move(evt->events_to_see.prev, &evt->events_to_get); ++ mutex_unlock(&lpfcdfc_lock); ++ *rxxri = (list_entry(evt->events_to_get.prev, ++ typeof(struct event_data), ++ node))->immed_dat; ++ } ++ evt->waiting = 0; ++ ++err_get_xri_exit: ++ mutex_lock(&lpfcdfc_lock); ++ lpfcdfc_event_unref(evt); /* release ref */ ++ lpfcdfc_event_unref(evt); /* delete */ ++ mutex_unlock(&lpfcdfc_lock); ++ ++ if(dmabuf) { ++ if(dmabuf->virt) ++ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); ++ kfree(dmabuf); ++ } ++ ++ if (cmdiocbq && (ret_val != IOCB_TIMEDOUT)) ++ lpfc_sli_release_iocbq(phba, cmdiocbq); ++ if (rspiocbq) ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ ++ return ret_val; ++} ++ ++static int lpfcdfc_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, ++ size_t len) ++{ ++ struct lpfc_sli *psli = &phba->sli; ++ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; ++ struct lpfc_iocbq *cmdiocbq; ++ IOCB_t *cmd = NULL; ++ struct list_head head, *curr, *next; ++ struct lpfc_dmabuf *rxbmp; ++ struct lpfc_dmabuf *dmp; ++ struct lpfc_dmabuf *mp[2] = {NULL, NULL}; ++ struct ulp_bde64 *rxbpl = NULL; ++ uint32_t num_bde; ++ struct lpfc_dmabufext *rxbuffer = NULL; ++ int ret_val = 0; ++ int i = 0; ++ ++ cmdiocbq = lpfc_sli_get_iocbq(phba); ++ rxbmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); ++ if (rxbmp != NULL) { ++ rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); ++ INIT_LIST_HEAD(&rxbmp->list); ++ rxbpl = (struct ulp_bde64 *) rxbmp->virt; ++ rxbuffer = dfc_cmd_data_alloc(phba, NULL, rxbpl, len); ++ } ++ ++ if(cmdiocbq == NULL || rxbmp == NULL || ++ rxbpl == NULL || rxbuffer == NULL) { ++ ret_val = ENOMEM; ++ goto err_post_rxbufs_exit; ++ } ++ ++ /* Queue buffers for the receive exchange */ ++ num_bde = (uint32_t)rxbuffer->flag; ++ dmp = &rxbuffer->dma; ++ ++ cmd = &cmdiocbq->iocb; ++ i = 0; ++ ++ INIT_LIST_HEAD(&head); ++ list_add_tail(&head, &dmp->list); ++ list_for_each_safe(curr, next, &head) { ++ mp[i] = list_entry(curr, struct lpfc_dmabuf, list); ++ list_del(curr); ++ ++ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { ++ mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); ++ cmd->un.quexri64cx.buff.bde.addrHigh = ++ putPaddrHigh(mp[i]->phys); ++ cmd->un.quexri64cx.buff.bde.addrLow = ++ putPaddrLow(mp[i]->phys); ++ cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = ++ ((struct lpfc_dmabufext *)mp[i])->size; ++ cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; ++ cmd->ulpCommand = CMD_QUE_XRI64_CX; ++ cmd->ulpPU = 0; ++ cmd->ulpLe = 1; ++ cmd->ulpBdeCount = 1; ++ cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; ++ ++ } else { ++ cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); ++ cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); ++ cmd->un.cont64[i].tus.f.bdeSize = ++ ((struct lpfc_dmabufext *)mp[i])->size; ++ cmd->ulpBdeCount = ++i; ++ ++ if ((--num_bde > 0) && (i < 2)) ++ continue; ++ ++ cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; ++ cmd->ulpLe = 1; ++ } ++ ++ cmd->ulpClass = CLASS3; ++ cmd->ulpContext = rxxri; ++ ++ ret_val = lpfc_sli_issue_iocb(phba, pring, cmdiocbq, 0); ++ ++ if (ret_val == IOCB_ERROR) { ++ dfc_cmd_data_free(phba, (struct lpfc_dmabufext *)mp[0]); ++ if (mp[1]) ++ dfc_cmd_data_free(phba, ++ (struct lpfc_dmabufext *)mp[1]); ++ dmp = list_entry(next, struct lpfc_dmabuf, list); ++ ret_val = EIO; ++ goto err_post_rxbufs_exit; ++ } ++ ++ lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); ++ if (mp[1]) { ++ lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); ++ mp[1] = NULL; ++ } ++ ++ /* The iocb was freed by lpfc_sli_issue_iocb */ ++ if ((cmdiocbq = lpfc_sli_get_iocbq(phba)) == NULL) { ++ dmp = list_entry(next, struct lpfc_dmabuf, list); ++ ret_val = EIO; ++ goto err_post_rxbufs_exit; ++ } ++ cmd = &cmdiocbq->iocb; ++ i = 0; ++ } ++ list_del(&head); ++ ++err_post_rxbufs_exit: ++ ++ if(rxbmp) { ++ if(rxbmp->virt) ++ lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); ++ kfree(rxbmp); ++ } ++ ++ if (cmdiocbq) ++ lpfc_sli_release_iocbq(phba, cmdiocbq); ++ ++ return ret_val; ++} ++static int ++lpfc_ioctl_loopback_test(struct lpfc_hba *phba, ++ struct lpfcCmdInput *cip, void *dataout) ++{ ++ struct lpfcdfc_host * dfchba; ++ struct lpfcdfc_event * evt; ++ struct event_data * evdat; ++ ++ struct lpfc_sli *psli = &phba->sli; ++ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; ++ uint32_t size = cip->lpfc_outsz; ++ uint32_t full_size = size + ELX_LOOPBACK_HEADER_SZ; ++ size_t segment_len = 0, segment_offset = 0, current_offset = 0; ++ uint16_t rpi; ++ struct lpfc_iocbq *cmdiocbq, *rspiocbq; ++ IOCB_t *cmd, *rsp; ++ struct lpfc_sli_ct_request *ctreq; ++ struct lpfc_dmabuf *txbmp; ++ struct ulp_bde64 *txbpl = NULL; ++ struct lpfc_dmabufext *txbuffer = NULL; ++ struct list_head head; ++ struct lpfc_dmabuf *curr; ++ uint16_t txxri, rxxri; ++ uint32_t num_bde; ++ uint8_t *ptr = NULL, *rx_databuf = NULL; ++ int rc; ++ ++ if ((phba->link_state == LPFC_HBA_ERROR) || ++ (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || ++ (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) ++ return EACCES; ++ ++ if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) ++ return EACCES; ++ ++ if ((size == 0) || (size > 80 * BUF_SZ_4K)) ++ return ERANGE; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(dfchba, &lpfcdfc_hosts, node) { ++ if (dfchba->phba == phba) ++ break; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ BUG_ON(&dfchba->node == &lpfcdfc_hosts); ++ ++ rc = lpfcdfc_loop_self_reg(phba, &rpi); ++ if (rc) ++ return rc; ++ ++ rc = lpfcdfc_loop_get_xri(phba, rpi, &txxri, &rxxri); ++ if (rc) { ++ lpfcdfc_loop_self_unreg(phba, rpi); ++ return rc; ++ } ++ ++ rc = lpfcdfc_loop_post_rxbufs(phba, rxxri, full_size); ++ if (rc) { ++ lpfcdfc_loop_self_unreg(phba, rpi); ++ return rc; ++ } ++ ++ evt = lpfcdfc_event_new(FC_REG_CT_EVENT, current->pid, ++ SLI_CT_ELX_LOOPBACK); ++ if (evt == NULL) { ++ lpfcdfc_loop_self_unreg(phba, rpi); ++ return ENOMEM; ++ } ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_add(&evt->node, &dfchba->ev_waiters); ++ lpfcdfc_event_ref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ ++ cmdiocbq = lpfc_sli_get_iocbq(phba); ++ rspiocbq = lpfc_sli_get_iocbq(phba); ++ txbmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); ++ ++ if (txbmp) { ++ txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); ++ INIT_LIST_HEAD(&txbmp->list); ++ txbpl = (struct ulp_bde64 *) txbmp->virt; ++ if (txbpl) ++ txbuffer = dfc_cmd_data_alloc(phba, NULL, ++ txbpl, full_size); ++ } ++ ++ if (cmdiocbq == NULL || rspiocbq == NULL ++ || txbmp == NULL || txbpl == NULL || txbuffer == NULL) { ++ rc = ENOMEM; ++ goto err_loopback_test_exit; ++ } ++ ++ cmd = &cmdiocbq->iocb; ++ rsp = &rspiocbq->iocb; ++ ++ INIT_LIST_HEAD(&head); ++ list_add_tail(&head, &txbuffer->dma.list); ++ list_for_each_entry(curr, &head, list) { ++ segment_len = ((struct lpfc_dmabufext *)curr)->size; ++ if (current_offset == 0) { ++ ctreq = curr->virt; ++ memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); ++ ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; ++ ctreq->RevisionId.bits.InId = 0; ++ ctreq->FsType = SLI_CT_ELX_LOOPBACK; ++ ctreq->FsSubType = 0; ++ ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA ; ++ ctreq->CommandResponse.bits.Size = size; ++ segment_offset = ELX_LOOPBACK_HEADER_SZ; ++ } else ++ segment_offset = 0; ++ ++ BUG_ON(segment_offset >= segment_len); ++ if (copy_from_user (curr->virt + segment_offset, ++ (void __user *)cip->lpfc_arg1 ++ + current_offset, ++ segment_len - segment_offset)) { ++ rc = EIO; ++ list_del(&head); ++ goto err_loopback_test_exit; ++ } ++ ++ current_offset += segment_len - segment_offset; ++ BUG_ON(current_offset > size); ++ } ++ list_del(&head); ++ ++ /* Build the XMIT_SEQUENCE iocb */ ++ ++ num_bde = (uint32_t)txbuffer->flag; ++ ++ cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); ++ cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); ++ cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; ++ cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); ++ ++ cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); ++ cmd->un.xseq64.w5.hcsw.Dfctl = 0; ++ cmd->un.xseq64.w5.hcsw.Rctl = FC_UNSOL_CTL; ++ cmd->un.xseq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; ++ ++ cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; ++ cmd->ulpBdeCount = 1; ++ cmd->ulpLe = 1; ++ cmd->ulpClass = CLASS3; ++ cmd->ulpContext = txxri; ++ ++ cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; ++ cmdiocbq->vport = phba->pport; ++ ++ rc = lpfc_sli_issue_iocb_wait(phba, pring, cmdiocbq, rspiocbq, ++ (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); ++ ++ if ((rc != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { ++ rc = EIO; ++ goto err_loopback_test_exit; ++ } ++ ++ evt->waiting = 1; ++ rc = wait_event_interruptible_timeout( ++ evt->wq, !list_empty(&evt->events_to_see), ++ ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); ++ evt->waiting = 0; ++ if (list_empty(&evt->events_to_see)) ++ rc = (rc) ? EINTR : ETIMEDOUT; ++ else { ++ ptr = dataout; ++ mutex_lock(&lpfcdfc_lock); ++ list_move(evt->events_to_see.prev, &evt->events_to_get); ++ evdat = list_entry(evt->events_to_get.prev, ++ typeof(*evdat), node); ++ mutex_unlock(&lpfcdfc_lock); ++ rx_databuf = evdat->data; ++ if (evdat->len != full_size) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1603 Loopback test did not receive expected " ++ "data length. actual length 0x%x expected " ++ "length 0x%x\n", ++ evdat->len, full_size); ++ rc = EIO; ++ } ++ else if (rx_databuf == NULL) ++ rc = EIO; ++ else { ++ rx_databuf += ELX_LOOPBACK_HEADER_SZ; ++ memcpy(ptr, rx_databuf, size); ++ rc = IOCB_SUCCESS; ++ } ++ } ++ ++err_loopback_test_exit: ++ lpfcdfc_loop_self_unreg(phba, rpi); ++ ++ mutex_lock(&lpfcdfc_lock); ++ lpfcdfc_event_unref(evt); /* release ref */ ++ lpfcdfc_event_unref(evt); /* delete */ ++ mutex_unlock(&lpfcdfc_lock); ++ ++ if (cmdiocbq != NULL) ++ lpfc_sli_release_iocbq(phba, cmdiocbq); ++ ++ if (rspiocbq != NULL) ++ lpfc_sli_release_iocbq(phba, rspiocbq); ++ ++ if (txbmp != NULL) { ++ if (txbpl != NULL) { ++ if (txbuffer != NULL) ++ dfc_cmd_data_free(phba, txbuffer); ++ lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); ++ } ++ kfree(txbmp); ++ } ++ return rc; ++} ++ ++static int ++dfc_rsp_data_copy(struct lpfc_hba * phba, ++ uint8_t * outdataptr, struct lpfc_dmabufext * mlist, ++ uint32_t size) ++{ ++ struct lpfc_dmabufext *mlast = NULL; ++ int cnt, offset = 0; ++ struct list_head head, *curr, *next; ++ ++ if (!mlist) ++ return 0; ++ ++ list_add_tail(&head, &mlist->dma.list); ++ ++ list_for_each_safe(curr, next, &head) { ++ mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); ++ if (!size) ++ break; ++ ++ /* We copy chucks of 4K */ ++ if (size > BUF_SZ_4K) ++ cnt = BUF_SZ_4K; ++ else ++ cnt = size; ++ ++ if (outdataptr) { ++ pci_dma_sync_single_for_device(phba->pcidev, ++ mlast->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); ++ ++ /* Copy data to user space */ ++ if (copy_to_user ++ ((void __user *) (outdataptr + offset), ++ (uint8_t *) mlast->dma.virt, cnt)) ++ return 1; ++ } ++ offset += cnt; ++ size -= cnt; ++ } ++ list_del(&head); ++ return 0; ++} ++ ++static int ++lpfc_issue_ct_rsp(struct lpfc_hba * phba, uint32_t tag, ++ struct lpfc_dmabuf * bmp, ++ struct lpfc_dmabufext * inp) ++{ ++ struct lpfc_sli *psli; ++ IOCB_t *icmd; ++ struct lpfc_iocbq *ctiocb; ++ struct lpfc_sli_ring *pring; ++ uint32_t num_entry; ++ int rc = 0; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ num_entry = inp->flag; ++ inp->flag = 0; ++ ++ /* Allocate buffer for command iocb */ ++ ctiocb = lpfc_sli_get_iocbq(phba); ++ if (!ctiocb) { ++ rc = ENOMEM; ++ goto issue_ct_rsp_exit; ++ } ++ icmd = &ctiocb->iocb; ++ ++ icmd->un.xseq64.bdl.ulpIoTag32 = 0; ++ icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); ++ icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); ++ icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; ++ icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64)); ++ icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); ++ icmd->un.xseq64.w5.hcsw.Dfctl = 0; ++ icmd->un.xseq64.w5.hcsw.Rctl = FC_SOL_CTL; ++ icmd->un.xseq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; ++ ++ pci_dma_sync_single_for_device(phba->pcidev, bmp->phys, LPFC_BPL_SIZE, ++ PCI_DMA_TODEVICE); ++ ++ /* Fill in rest of iocb */ ++ icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; ++ icmd->ulpBdeCount = 1; ++ icmd->ulpLe = 1; ++ icmd->ulpClass = CLASS3; ++ icmd->ulpContext = (ushort) tag; ++ icmd->ulpTimeout = phba->fc_ratov * 2; ++ ++ /* Xmit CT response on exchange */ ++ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, ++ "1200 Xmit CT response on exchange x%x Data: x%x x%x\n", ++ icmd->ulpContext, icmd->ulpIoTag, phba->link_state); ++ ++ ctiocb->iocb_cmpl = NULL; ++ ctiocb->iocb_flag |= LPFC_IO_LIBDFC; ++ ctiocb->vport = phba->pport; ++ rc = lpfc_sli_issue_iocb_wait(phba, pring, ctiocb, NULL, ++ phba->fc_ratov * 2 + LPFC_DRVR_TIMEOUT); ++ ++ if (rc == IOCB_TIMEDOUT) { ++ ctiocb->context1 = NULL; ++ ctiocb->context2 = NULL; ++ ctiocb->iocb_cmpl = lpfc_ioctl_timeout_iocb_cmpl; ++ return rc; ++ } ++ ++ /* Calling routine takes care of IOCB_ERROR => EIO translation */ ++ if (rc != IOCB_SUCCESS) ++ rc = IOCB_ERROR; ++ ++ lpfc_sli_release_iocbq(phba, ctiocb); ++issue_ct_rsp_exit: ++ return rc; ++} ++ ++ ++static void ++lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, ++ struct lpfc_sli_ring * pring, ++ struct lpfc_iocbq * piocbq) ++{ ++ struct lpfcdfc_host * dfchba = lpfcdfc_host_from_hba(phba); ++ uint32_t evt_req_id = 0; ++ uint32_t cmd; ++ uint32_t len; ++ struct lpfc_dmabuf *dmabuf = NULL; ++ struct lpfcdfc_event * evt; ++ struct event_data * evt_dat = NULL; ++ struct lpfc_iocbq * iocbq; ++ size_t offset = 0; ++ struct list_head head; ++ struct ulp_bde64 * bde; ++ dma_addr_t dma_addr; ++ int i; ++ struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; ++ struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; ++ struct lpfc_hbq_entry *hbqe; ++ ++ BUG_ON(&dfchba->node == &lpfcdfc_hosts); ++ INIT_LIST_HEAD(&head); ++ if (piocbq->iocb.ulpBdeCount == 0 || ++ piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) ++ goto error_unsol_ct_exit; ++ ++ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) ++ dmabuf = bdeBuf1; ++ else { ++ dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, ++ piocbq->iocb.un.cont64[0].addrLow); ++ dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); ++ } ++ BUG_ON(dmabuf == NULL); ++ evt_req_id = ((struct lpfc_sli_ct_request *)(dmabuf->virt))->FsType; ++ cmd = ((struct lpfc_sli_ct_request *) ++ (dmabuf->virt))->CommandResponse.bits.CmdRsp; ++ len = ((struct lpfc_sli_ct_request *) ++ (dmabuf->virt))->CommandResponse.bits.Size; ++ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) ++ lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(evt, &dfchba->ev_waiters, node) { ++ if (!(evt->type_mask & FC_REG_CT_EVENT) || ++ evt->req_id != evt_req_id) ++ continue; ++ ++ lpfcdfc_event_ref(evt); ++ ++ if ((evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL)) == NULL) { ++ lpfcdfc_event_unref(evt); ++ break; ++ } ++ ++ mutex_unlock(&lpfcdfc_lock); ++ ++ INIT_LIST_HEAD(&head); ++ list_add_tail(&head, &piocbq->list); ++ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { ++ /* take accumulated byte count from the last iocbq */ ++ iocbq = list_entry(head.prev, typeof(*iocbq), list); ++ evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; ++ } else { ++ list_for_each_entry(iocbq, &head, list) { ++ for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) ++ evt_dat->len += ++ iocbq->iocb.un.cont64[i].tus.f.bdeSize; ++ } ++ } ++ ++ ++ evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); ++ if (evt_dat->data == NULL) { ++ kfree (evt_dat); ++ mutex_lock(&lpfcdfc_lock); ++ lpfcdfc_event_unref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ goto error_unsol_ct_exit; ++ } ++ ++ list_for_each_entry(iocbq, &head, list) { ++ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { ++ bdeBuf1 = iocbq->context2; ++ bdeBuf2 = iocbq->context3; ++ } ++ for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { ++ int size = 0; ++ if (phba->sli3_options & ++ LPFC_SLI3_HBQ_ENABLED) { ++ BUG_ON(i>1); ++ if (i == 0) { ++ hbqe = (struct lpfc_hbq_entry *) ++ &iocbq->iocb.un.ulpWord[0]; ++ size = hbqe->bde.tus.f.bdeSize; ++ dmabuf = bdeBuf1; ++ } else if (i == 1) { ++ hbqe = (struct lpfc_hbq_entry *) ++ &iocbq->iocb.unsli3. ++ sli3Words[4]; ++ size = hbqe->bde.tus.f.bdeSize; ++ dmabuf = bdeBuf2; ++ } ++ if ((offset + size) > evt_dat->len) ++ size = evt_dat->len - offset; ++ } else { ++ size = iocbq->iocb.un.cont64[i]. ++ tus.f.bdeSize; ++ bde = &iocbq->iocb.un.cont64[i]; ++ dma_addr = getPaddr(bde->addrHigh, ++ bde->addrLow); ++ dmabuf = lpfc_sli_ringpostbuf_get(phba, ++ pring, dma_addr); ++ } ++ if (dmabuf == NULL) { ++ kfree (evt_dat->data); ++ kfree (evt_dat); ++ mutex_lock(&lpfcdfc_lock); ++ lpfcdfc_event_unref(evt); ++ mutex_unlock(&lpfcdfc_lock); ++ goto error_unsol_ct_exit; ++ } ++ memcpy ((char *)(evt_dat->data) + offset, ++ dmabuf->virt, size); ++ offset += size; ++ if (evt_req_id != SLI_CT_ELX_LOOPBACK && ++ !(phba->sli3_options & ++ LPFC_SLI3_HBQ_ENABLED)) ++ lpfc_sli_ringpostbuf_put(phba, pring, ++ dmabuf); ++ else { ++ switch (cmd) { ++ case ELX_LOOPBACK_DATA: ++ dfc_cmd_data_free(phba, ++ (struct lpfc_dmabufext *) ++ dmabuf); ++ break; ++ case ELX_LOOPBACK_XRI_SETUP: ++ if (!(phba->sli3_options & ++ LPFC_SLI3_HBQ_ENABLED)) ++ lpfc_post_buffer(phba, ++ pring, ++ 1); ++ else ++ lpfc_in_buf_free(phba, ++ dmabuf); ++ break; ++ default: ++ if (!(phba->sli3_options & ++ LPFC_SLI3_HBQ_ENABLED)) ++ lpfc_post_buffer(phba, ++ pring, ++ 1); ++ break; ++ } ++ } ++ } ++ } ++ ++ mutex_lock(&lpfcdfc_lock); ++ evt_dat->immed_dat = piocbq->iocb.ulpContext; ++ evt_dat->type = FC_REG_CT_EVENT; ++ list_add(&evt_dat->node, &evt->events_to_see); ++ wake_up_interruptible(&evt->wq); ++ lpfcdfc_event_unref(evt); ++ if (evt_req_id == SLI_CT_ELX_LOOPBACK) ++ break; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ ++error_unsol_ct_exit: ++ if(!list_empty(&head)) ++ list_del(&head); ++ if (evt_req_id != SLI_CT_ELX_LOOPBACK && ++ dfchba->base_ct_unsol_event != NULL) ++ (dfchba->base_ct_unsol_event)(phba, pring, piocbq); ++ ++ return; ++} ++ ++ ++struct lpfc_dmabufext * ++__dfc_cmd_data_alloc(struct lpfc_hba * phba, ++ char *indataptr, struct ulp_bde64 * bpl, uint32_t size, ++ int nocopydata) ++{ ++ struct lpfc_dmabufext *mlist = NULL; ++ struct lpfc_dmabufext *dmp; ++ int cnt, offset = 0, i = 0; ++ struct pci_dev *pcidev; ++ ++ pcidev = phba->pcidev; ++ ++ while (size) { ++ /* We get chunks of 4K */ ++ if (size > BUF_SZ_4K) ++ cnt = BUF_SZ_4K; ++ else ++ cnt = size; ++ ++ /* allocate struct lpfc_dmabufext buffer header */ ++ dmp = kmalloc(sizeof (struct lpfc_dmabufext), GFP_KERNEL); ++ if (dmp == 0) ++ goto out; ++ ++ INIT_LIST_HEAD(&dmp->dma.list); ++ ++ /* Queue it to a linked list */ ++ if (mlist) ++ list_add_tail(&dmp->dma.list, &mlist->dma.list); ++ else ++ mlist = dmp; ++ ++ /* allocate buffer */ ++ dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, ++ cnt, ++ &(dmp->dma.phys), ++ GFP_KERNEL); ++ ++ if (dmp->dma.virt == NULL) ++ goto out; ++ ++ dmp->size = cnt; ++ ++ if (indataptr || nocopydata) { ++ if (indataptr) ++ /* Copy data from user space in */ ++ if (copy_from_user ((uint8_t *) dmp->dma.virt, ++ (void __user *) (indataptr + offset), ++ cnt)) { ++ goto out; ++ } ++ ++ pci_dma_sync_single_for_device(phba->pcidev, ++ dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); ++ ++ } else ++ memset((uint8_t *)dmp->dma.virt, 0, cnt); ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ ++ /* build buffer ptr list for IOCB */ ++ bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); ++ bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); ++ bpl->tus.f.bdeSize = (ushort) cnt; ++ bpl->tus.w = le32_to_cpu(bpl->tus.w); ++ bpl++; ++ ++ i++; ++ offset += cnt; ++ size -= cnt; ++ } ++ ++ mlist->flag = i; ++ return mlist; ++out: ++ dfc_cmd_data_free(phba, mlist); ++ return NULL; ++} ++ ++static struct lpfc_dmabufext * ++dfc_cmd_data_alloc(struct lpfc_hba * phba, ++ char *indataptr, struct ulp_bde64 * bpl, uint32_t size) ++{ ++ /* if indataptr is null it is a rsp buffer. */ ++ return __dfc_cmd_data_alloc(phba, indataptr, bpl, size, ++ 0 /* don't copy user data */); ++} ++ ++int ++__dfc_cmd_data_free(struct lpfc_hba * phba, struct lpfc_dmabufext * mlist) ++{ ++ return dfc_cmd_data_free(phba, mlist); ++} ++static int ++dfc_cmd_data_free(struct lpfc_hba * phba, struct lpfc_dmabufext * mlist) ++{ ++ struct lpfc_dmabufext *mlast; ++ struct pci_dev *pcidev; ++ struct list_head head, *curr, *next; ++ ++ if ((!mlist) || (!lpfc_is_link_up(phba) && ++ (phba->link_flag & LS_LOOPBACK_MODE))) { ++ return 0; ++ } ++ ++ pcidev = phba->pcidev; ++ list_add_tail(&head, &mlist->dma.list); ++ ++ list_for_each_safe(curr, next, &head) { ++ mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); ++ if (mlast->dma.virt) ++ dma_free_coherent(&pcidev->dev, ++ mlast->size, ++ mlast->dma.virt, ++ mlast->dma.phys); ++ kfree(mlast); ++ } ++ return 0; ++} ++ ++ ++/* The only reason we need that reverce find, is because we ++ * are bent on keeping original calling conventions. ++ */ ++static struct lpfcdfc_host * ++lpfcdfc_host_from_hba(struct lpfc_hba * phba) ++{ ++ struct lpfcdfc_host * dfchba; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(dfchba, &lpfcdfc_hosts, node) { ++ if (dfchba->phba == phba) ++ break; ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ ++ return dfchba; ++} ++ ++struct lpfcdfc_host * ++lpfcdfc_host_add (struct pci_dev * dev, ++ struct Scsi_Host * host, ++ struct lpfc_hba * phba) ++{ ++ struct lpfcdfc_host * dfchba = NULL; ++ struct lpfc_sli_ring_mask * prt = NULL; ++ ++ dfchba = kzalloc(sizeof(*dfchba), GFP_KERNEL); ++ if (dfchba == NULL) ++ return NULL; ++ ++ dfchba->inst = phba->brd_no; ++ dfchba->phba = phba; ++ dfchba->vport = phba->pport; ++ dfchba->host = host; ++ dfchba->dev = dev; ++ dfchba->blocked = 0; ++ ++ spin_lock_irq(&phba->hbalock); ++ prt = phba->sli.ring[LPFC_ELS_RING].prt; ++ dfchba->base_ct_unsol_event = prt[2].lpfc_sli_rcv_unsol_event; ++ prt[2].lpfc_sli_rcv_unsol_event = lpfcdfc_ct_unsol_event; ++ prt[3].lpfc_sli_rcv_unsol_event = lpfcdfc_ct_unsol_event; ++ spin_unlock_irq(&phba->hbalock); ++ mutex_lock(&lpfcdfc_lock); ++ list_add_tail(&dfchba->node, &lpfcdfc_hosts); ++ INIT_LIST_HEAD(&dfchba->ev_waiters); ++ mutex_unlock(&lpfcdfc_lock); ++ ++ return dfchba; ++} ++ ++ ++void ++lpfcdfc_host_del (struct lpfcdfc_host * dfchba) ++{ ++ struct Scsi_Host * host; ++ struct lpfc_hba * phba = NULL; ++ struct lpfc_sli_ring_mask * prt = NULL; ++ struct lpfcdfc_event * evt; ++ ++ mutex_lock(&lpfcdfc_lock); ++ dfchba->blocked = 1; ++ ++ list_for_each_entry(evt, &dfchba->ev_waiters, node) { ++ wake_up_interruptible(&evt->wq); ++ } ++ ++ while (dfchba->ref_count) { ++ mutex_unlock(&lpfcdfc_lock); ++ msleep(2000); ++ mutex_lock(&lpfcdfc_lock); ++ } ++ ++ if (dfchba->dev->driver) { ++ host = pci_get_drvdata(dfchba->dev); ++ if ((host != NULL) && ++ (struct lpfc_vport *)host->hostdata == dfchba->vport) { ++ phba = dfchba->phba; ++ mutex_unlock(&lpfcdfc_lock); ++ spin_lock_irq(&phba->hbalock); ++ prt = phba->sli.ring[LPFC_ELS_RING].prt; ++ prt[2].lpfc_sli_rcv_unsol_event = ++ dfchba->base_ct_unsol_event; ++ prt[3].lpfc_sli_rcv_unsol_event = ++ dfchba->base_ct_unsol_event; ++ spin_unlock_irq(&phba->hbalock); ++ mutex_lock(&lpfcdfc_lock); ++ } ++ } ++ list_del_init(&dfchba->node); ++ mutex_unlock(&lpfcdfc_lock); ++ kfree (dfchba); ++} ++ ++/* ++ * Retrieve lpfc_hba * matching instance (board no) ++ * If found return lpfc_hba * ++ * If not found return NULL ++ */ ++static struct lpfcdfc_host * ++lpfcdfc_get_phba_by_inst(int inst) ++{ ++ struct Scsi_Host * host = NULL; ++ struct lpfcdfc_host * dfchba; ++ ++ mutex_lock(&lpfcdfc_lock); ++ list_for_each_entry(dfchba, &lpfcdfc_hosts, node) { ++ if (dfchba->inst == inst) { ++ if (dfchba->dev->driver) { ++ host = pci_get_drvdata(dfchba->dev); ++ if ((host != NULL) && ++ (struct lpfc_vport *)host->hostdata == ++ dfchba->vport) { ++ mutex_unlock(&lpfcdfc_lock); ++ BUG_ON(dfchba->phba->brd_no != inst); ++ return dfchba; ++ } ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ return NULL; ++ } ++ } ++ mutex_unlock(&lpfcdfc_lock); ++ ++ return NULL; ++} ++ ++static int ++lpfcdfc_do_ioctl(struct lpfcCmdInput *cip) ++{ ++ struct lpfcdfc_host * dfchba = NULL; ++ struct lpfc_hba *phba = NULL; ++ int rc; ++ uint32_t total_mem; ++ void *dataout; ++ ++ ++ /* Some ioctls are per module and do not need phba */ ++ switch (cip->lpfc_cmd) { ++ case LPFC_GET_DFC_REV: ++ break; ++ default: ++ dfchba = lpfcdfc_get_phba_by_inst(cip->lpfc_brd); ++ if (dfchba == NULL) ++ return EINVAL; ++ phba = dfchba->phba; ++ break; ++ }; ++ ++ if (phba) ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1601 libdfc ioctl entry Data: x%x x%lx x%lx x%x\n", ++ cip->lpfc_cmd, (unsigned long) cip->lpfc_arg1, ++ (unsigned long) cip->lpfc_arg2, cip->lpfc_outsz); ++ mutex_lock(&lpfcdfc_lock); ++ if (dfchba && dfchba->blocked) { ++ mutex_unlock(&lpfcdfc_lock); ++ return EINVAL; ++ } ++ if (dfchba) ++ dfchba->ref_count++; ++ mutex_unlock(&lpfcdfc_lock); ++ if (cip->lpfc_outsz >= BUF_SZ_4K) { ++ ++ /* ++ * Allocate memory for ioctl data. If buffer is bigger than 64k, ++ * then we allocate 64k and re-use that buffer over and over to ++ * xfer the whole block. This is because Linux kernel has a ++ * problem allocating more than 120k of kernel space memory. Saw ++ * problem with GET_FCPTARGETMAPPING... ++ */ ++ if (cip->lpfc_outsz <= (64 * 1024)) ++ total_mem = cip->lpfc_outsz; ++ else ++ total_mem = 64 * 1024; ++ } else { ++ /* Allocate memory for ioctl data */ ++ total_mem = BUF_SZ_4K; ++ } ++ ++ /* ++ * For LPFC_HBA_GET_EVENT allocate memory which is needed to store ++ * event info. Allocating maximum possible buffer size (64KB) can fail ++ * some times under heavy IO. ++ */ ++ if (cip->lpfc_cmd == LPFC_HBA_GET_EVENT) { ++ dataout = NULL; ++ } else { ++ dataout = kmalloc(total_mem, GFP_KERNEL); ++ ++ if (!dataout && dfchba != NULL) { ++ mutex_lock(&lpfcdfc_lock); ++ if (dfchba) ++ dfchba->ref_count--; ++ mutex_unlock(&lpfcdfc_lock); ++ return ENOMEM; ++ } ++ } ++ ++ switch (cip->lpfc_cmd) { ++ ++ case LPFC_GET_DFC_REV: ++ ((struct DfcRevInfo *) dataout)->a_Major = DFC_MAJOR_REV; ++ ((struct DfcRevInfo *) dataout)->a_Minor = DFC_MINOR_REV; ++ cip->lpfc_outsz = sizeof (struct DfcRevInfo); ++ rc = 0; ++ break; ++ ++ case LPFC_SEND_ELS: ++ rc = lpfc_ioctl_send_els(phba, cip, dataout); ++ break; ++ ++ case LPFC_HBA_SEND_MGMT_RSP: ++ rc = lpfc_ioctl_send_mgmt_rsp(phba, cip); ++ break; ++ ++ case LPFC_HBA_SEND_MGMT_CMD: ++ case LPFC_CT: ++ rc = lpfc_ioctl_send_mgmt_cmd(phba, cip, dataout); ++ break; ++ ++ case LPFC_HBA_GET_EVENT: ++ rc = lpfc_ioctl_hba_get_event(phba, cip, &dataout, &total_mem); ++ if ((total_mem) && (copy_to_user ((void __user *) ++ cip->lpfc_dataout, (uint8_t *) dataout, total_mem))) ++ rc = EIO; ++ /* This is to prevent copy_to_user at end of the function. */ ++ cip->lpfc_outsz = 0; ++ break; ++ ++ case LPFC_HBA_SET_EVENT: ++ rc = lpfc_ioctl_hba_set_event(phba, cip); ++ break; ++ ++ case LPFC_LOOPBACK_MODE: ++ rc = lpfc_ioctl_loopback_mode(phba, cip, dataout); ++ break; ++ ++ case LPFC_LOOPBACK_TEST: ++ rc = lpfc_ioctl_loopback_test(phba, cip, dataout); ++ break; ++ ++ case LPFC_HBA_RNID: ++ rc = lpfc_ioctl_hba_rnid(phba, cip, dataout); ++ break; ++ ++ default: ++ rc = EINVAL; ++ break; ++ } ++ ++ if (phba) ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1602 libdfc ioctl exit Data: x%x x%x x%lx\n", ++ rc, cip->lpfc_outsz, (unsigned long) cip->lpfc_dataout); ++ /* Copy data to user space config method */ ++ if (rc == 0) { ++ if (cip->lpfc_outsz) { ++ if (copy_to_user ++ ((void __user *) cip->lpfc_dataout, ++ (uint8_t *) dataout, cip->lpfc_outsz)) { ++ rc = EIO; ++ } ++ } ++ } ++ ++ kfree(dataout); ++ mutex_lock(&lpfcdfc_lock); ++ if (dfchba) ++ dfchba->ref_count--; ++ mutex_unlock(&lpfcdfc_lock); ++ ++ return rc; ++} ++ ++static int ++lpfcdfc_ioctl(struct inode *inode, ++ struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int rc; ++ struct lpfcCmdInput *ci; ++ ++ if (!arg) ++ return -EINVAL; ++ ++ ci = (struct lpfcCmdInput *) kmalloc(sizeof (struct lpfcCmdInput), ++ GFP_KERNEL); ++ ++ if (!ci) ++ return -ENOMEM; ++ ++ if ((rc = copy_from_user ++ ((uint8_t *) ci, (void __user *) arg, ++ sizeof (struct lpfcCmdInput)))) { ++ kfree(ci); ++ return -EIO; ++ } ++ ++ rc = lpfcdfc_do_ioctl(ci); ++ ++ kfree(ci); ++ return -rc; ++} ++ ++#ifdef CONFIG_COMPAT ++static long ++lpfcdfc_compat_ioctl(struct file * file, unsigned int cmd, unsigned long arg) ++{ ++ struct lpfcCmdInput32 arg32; ++ struct lpfcCmdInput arg64; ++ int ret; ++ ++ if(copy_from_user(&arg32, (void __user *)arg, ++ sizeof(struct lpfcCmdInput32))) ++ return -EFAULT; ++ ++ arg64.lpfc_brd = arg32.lpfc_brd; ++ arg64.lpfc_ring = arg32.lpfc_ring; ++ arg64.lpfc_iocb = arg32.lpfc_iocb; ++ arg64.lpfc_flag = arg32.lpfc_flag; ++ arg64.lpfc_arg1 = (void *)(unsigned long) arg32.lpfc_arg1; ++ arg64.lpfc_arg2 = (void *)(unsigned long) arg32.lpfc_arg2; ++ arg64.lpfc_arg3 = (void *)(unsigned long) arg32.lpfc_arg3; ++ arg64.lpfc_dataout = (void *)(unsigned long) arg32.lpfc_dataout; ++ arg64.lpfc_cmd = arg32.lpfc_cmd; ++ arg64.lpfc_outsz = arg32.lpfc_outsz; ++ arg64.lpfc_arg4 = arg32.lpfc_arg4; ++ arg64.lpfc_arg5 = arg32.lpfc_arg5; ++ ++ ret = lpfcdfc_do_ioctl(&arg64); ++ ++ arg32.lpfc_brd = arg64.lpfc_brd; ++ arg32.lpfc_ring = arg64.lpfc_ring; ++ arg32.lpfc_iocb = arg64.lpfc_iocb; ++ arg32.lpfc_flag = arg64.lpfc_flag; ++ arg32.lpfc_arg1 = (u32)(unsigned long) arg64.lpfc_arg1; ++ arg32.lpfc_arg2 = (u32)(unsigned long) arg64.lpfc_arg2; ++ arg32.lpfc_arg3 = (u32)(unsigned long) arg64.lpfc_arg3; ++ arg32.lpfc_dataout = (u32)(unsigned long) arg64.lpfc_dataout; ++ arg32.lpfc_cmd = arg64.lpfc_cmd; ++ arg32.lpfc_outsz = arg64.lpfc_outsz; ++ arg32.lpfc_arg4 = arg64.lpfc_arg4; ++ arg32.lpfc_arg5 = arg64.lpfc_arg5; ++ ++ if(copy_to_user((void __user *)arg, &arg32, ++ sizeof(struct lpfcCmdInput32))) ++ return -EFAULT; ++ ++ return -ret; ++} ++#endif ++ ++static struct file_operations lpfc_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = lpfcdfc_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = lpfcdfc_compat_ioctl, ++#endif ++}; ++ ++int ++lpfc_cdev_init(void) ++{ ++ ++ lpfcdfc_major = register_chrdev(0, LPFC_CHAR_DEV_NAME, &lpfc_fops); ++ if (lpfcdfc_major < 0) { ++ printk(KERN_ERR "%s:%d Unable to register \"%s\" device.\n", ++ __func__, __LINE__, LPFC_CHAR_DEV_NAME); ++ return lpfcdfc_major; ++ } ++ ++ return 0; ++} ++ ++void ++lpfc_cdev_exit(void) ++{ ++ unregister_chrdev(lpfcdfc_major, LPFC_CHAR_DEV_NAME); ++} +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_ioctl.h +@@ -0,0 +1,184 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#define DFC_MAJOR_REV 81 ++#define DFC_MINOR_REV 0 ++ ++#define LPFC_MAX_EVENT 128 ++ ++#define LPFC_CT 0x42 /* Send CT passthru command */ ++#define LPFC_HBA_RNID 0x52 /* Send an RNID request */ ++#define LPFC_HBA_REFRESHINFO 0x56 /* Do a refresh of the stats */ ++#define LPFC_SEND_ELS 0x57 /* Send out an ELS command */ ++#define LPFC_HBA_SET_EVENT 0x59 /* Set FCP event(s) */ ++#define LPFC_HBA_GET_EVENT 0x5a /* Get FCP event(s) */ ++#define LPFC_HBA_SEND_MGMT_CMD 0x5b /* Send a management command */ ++#define LPFC_HBA_SEND_MGMT_RSP 0x5c /* Send a management response */ ++ ++#define LPFC_GET_DFC_REV 0x68 /* Get the rev of the ioctl ++ driver */ ++#define LPFC_LOOPBACK_TEST 0x72 /* Run Loopback test */ ++#define LPFC_LOOPBACK_MODE 0x73 /* Enter Loopback mode */ ++/* LPFC_LAST_IOCTL_USED 0x73 Last LPFC Ioctl used */ ++ ++#define INTERNAL_LOOP_BACK 0x1 ++#define EXTERNAL_LOOP_BACK 0x2 ++ ++/* the DfcRevInfo structure */ ++struct DfcRevInfo { ++ uint32_t a_Major; ++ uint32_t a_Minor; ++} ; ++ ++#define LPFC_WWPN_TYPE 0 ++#define LPFC_PORTID_TYPE 1 ++#define LPFC_WWNN_TYPE 2 ++ ++struct nport_id { ++ uint32_t idType; /* 0 - wwpn, 1 - d_id, 2 - wwnn */ ++ uint32_t d_id; ++ uint8_t wwpn[8]; ++}; ++ ++#define LPFC_EVENT_LIP_OCCURRED 1 ++#define LPFC_EVENT_LINK_UP 2 ++#define LPFC_EVENT_LINK_DOWN 3 ++#define LPFC_EVENT_LIP_RESET_OCCURRED 4 ++#define LPFC_EVENT_RSCN 5 ++#define LPFC_EVENT_PROPRIETARY 0xFFFF ++ ++struct lpfc_hba_event_info { ++ uint32_t event_code; ++ uint32_t port_id; ++ union { ++ uint32_t rscn_event_info; ++ uint32_t pty_event_info; ++ } event; ++}; ++ ++ ++#define LPFC_CHAR_DEV_NAME "lpfcdfc" ++ ++/* ++ * Diagnostic (DFC) Command & Input structures: (LPFC) ++ */ ++struct lpfcCmdInput { ++ short lpfc_brd; ++ short lpfc_ring; ++ short lpfc_iocb; ++ short lpfc_flag; ++ void *lpfc_arg1; ++ void *lpfc_arg2; ++ void *lpfc_arg3; ++ char *lpfc_dataout; ++ uint32_t lpfc_cmd; ++ uint32_t lpfc_outsz; ++ uint32_t lpfc_arg4; ++ uint32_t lpfc_arg5; ++}; ++/* Used for ioctl command */ ++#define LPFC_DFC_CMD_IOCTL_MAGIC 0xFC ++#define LPFC_DFC_CMD_IOCTL _IOWR(LPFC_DFC_CMD_IOCTL_MAGIC, 0x1,\ ++ struct lpfcCmdInput) ++ ++#ifdef CONFIG_COMPAT ++/* 32 bit version */ ++struct lpfcCmdInput32 { ++ short lpfc_brd; ++ short lpfc_ring; ++ short lpfc_iocb; ++ short lpfc_flag; ++ u32 lpfc_arg1; ++ u32 lpfc_arg2; ++ u32 lpfc_arg3; ++ u32 lpfc_dataout; ++ uint32_t lpfc_cmd; ++ uint32_t lpfc_outsz; ++ uint32_t lpfc_arg4; ++ uint32_t lpfc_arg5; ++}; ++#endif ++ ++#define SLI_CT_ELX_LOOPBACK 0x10 ++ ++enum ELX_LOOPBACK_CMD { ++ ELX_LOOPBACK_XRI_SETUP, ++ ELX_LOOPBACK_DATA, ++}; ++ ++ ++struct lpfc_link_info { ++ uint32_t a_linkEventTag; ++ uint32_t a_linkUp; ++ uint32_t a_linkDown; ++ uint32_t a_linkMulti; ++ uint32_t a_DID; ++ uint8_t a_topology; ++ uint8_t a_linkState; ++ uint8_t a_alpa; ++ uint8_t a_alpaCnt; ++ uint8_t a_alpaMap[128]; ++ uint8_t a_wwpName[8]; ++ uint8_t a_wwnName[8]; ++}; ++ ++enum lpfc_host_event_code { ++ LPFCH_EVT_LIP = 0x1, ++ LPFCH_EVT_LINKUP = 0x2, ++ LPFCH_EVT_LINKDOWN = 0x3, ++ LPFCH_EVT_LIPRESET = 0x4, ++ LPFCH_EVT_RSCN = 0x5, ++ LPFCH_EVT_ADAPTER_CHANGE = 0x103, ++ LPFCH_EVT_PORT_UNKNOWN = 0x200, ++ LPFCH_EVT_PORT_OFFLINE = 0x201, ++ LPFCH_EVT_PORT_ONLINE = 0x202, ++ LPFCH_EVT_PORT_FABRIC = 0x204, ++ LPFCH_EVT_LINK_UNKNOWN = 0x500, ++ LPFCH_EVT_VENDOR_UNIQUE = 0xffff, ++}; ++ ++#define ELX_LOOPBACK_HEADER_SZ \ ++ (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) ++ ++struct lpfc_host_event { ++ uint32_t seq_num; ++ enum lpfc_host_event_code event_code; ++ uint32_t data; ++}; ++ ++struct lpfc_timedout_iocb_ctxt { ++ struct lpfc_iocbq *rspiocbq; ++ struct lpfc_dmabuf *mp; ++ struct lpfc_dmabuf *bmp; ++ struct lpfc_scsi_buf *lpfc_cmd; ++ struct lpfc_dmabufext *outdmp; ++ struct lpfc_dmabufext *indmp; ++}; ++ ++#ifdef __KERNEL__ ++struct lpfcdfc_host; ++ ++/* Initialize/Un-initialize char device */ ++int lpfc_cdev_init(void); ++void lpfc_cdev_exit(void); ++void lpfcdfc_host_del(struct lpfcdfc_host *); ++struct lpfcdfc_host *lpfcdfc_host_add(struct pci_dev *, struct Scsi_Host *, ++ struct lpfc_hba *); ++#endif /* __KERNEL__ */ +--- a/drivers/scsi/lpfc/lpfc_logmsg.h ++++ b/drivers/scsi/lpfc/lpfc_logmsg.h +@@ -32,6 +32,7 @@ + #define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */ + #define LOG_LIBDFC 0x2000 /* Libdfc events */ + #define LOG_VPORT 0x4000 /* NPIV events */ ++#define LOG_SECURITY 0x8000 /* FC Security */ + #define LOG_ALL_MSG 0xffff /* LOG all messages */ + + #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ +--- a/drivers/scsi/lpfc/lpfc_mbox.c ++++ b/drivers/scsi/lpfc/lpfc_mbox.c +@@ -1083,7 +1083,7 @@ lpfc_config_port(struct lpfc_hba *phba, + phba->pcb->feature = FEATURE_INITIAL_SLI2; + + /* Setup Mailbox pointers */ +- phba->pcb->mailBoxSize = sizeof(MAILBOX_t); ++ phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE; + offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt; + pdma_addr = phba->slim2p.phys + offset; + phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr); +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_menlo.c +@@ -0,0 +1,1174 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2007-2008 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lpfc_hw.h" ++#include "lpfc_sli.h" ++#include "lpfc_nl.h" ++#include "lpfc_disc.h" ++#include "lpfc_scsi.h" ++#include "lpfc.h" ++#include "lpfc_logmsg.h" ++#include "lpfc_version.h" ++#include "lpfc_compat.h" ++#include "lpfc_crtn.h" ++#include "lpfc_vport.h" ++ ++#define MENLO_CMD_FW_DOWNLOAD 0x00000002 ++ ++static void lpfc_menlo_iocb_timeout_cmpl(struct lpfc_hba *, ++ struct lpfc_iocbq *, struct lpfc_iocbq *); ++ ++extern int ++__dfc_cmd_data_free(struct lpfc_hba * phba, struct lpfc_dmabufext * mlist); ++ ++extern struct lpfc_dmabufext * ++__dfc_cmd_data_alloc(struct lpfc_hba * phba, ++ char *indataptr, struct ulp_bde64 * bpl, uint32_t size, ++ int nocopydata); ++/* ++ * The size for the menlo interface is set at 336k because it only uses ++ * one bpl. A bpl can contain 85 BDE descriptors. Each BDE can represent ++ * up to 4k. I used 84 BDE entries to do this calculation because the ++ * 1st sysfs_menlo_write is for just the cmd header which is 12 bytes. ++ * size = PAGE_SZ * (sizeof(bpl) / sizeof(BDE)) -1; ++ */ ++#define SYSFS_MENLO_ATTR_SIZE 344064 ++typedef struct menlo_get_cmd ++{ ++ uint32_t code; /* Command code */ ++ uint32_t context; /* Context */ ++ uint32_t length; /* Max response length */ ++} menlo_get_cmd_t; ++ ++typedef struct menlo_init_rsp ++{ ++ uint32_t code; ++ uint32_t bb_credit; /* Menlo FC BB Credit */ ++ uint32_t frame_size; /* Menlo FC receive frame size */ ++ uint32_t fw_version; /* Menlo firmware version */ ++ uint32_t reset_status; /* Reason for previous reset */ ++ ++#define MENLO_RESET_STATUS_NORMAL 0 ++#define MENLO_RESET_STATUS_PANIC 1 ++ ++ uint32_t maint_status; /* Menlo Maintenance Mode status at link up */ ++ ++ ++#define MENLO_MAINTENANCE_MODE_DISABLE 0 ++#define MENLO_MAINTENANCE_MODE_ENABLE 1 ++ uint32_t fw_type; ++ uint32_t fru_data_valid; /* 0=invalid, 1=valid */ ++} menlo_init_rsp_t; ++ ++#define MENLO_CMD_GET_INIT 0x00000007 ++#define MENLO_FW_TYPE_OPERATIONAL 0xABCD0001 ++#define MENLO_FW_TYPE_GOLDEN 0xABCD0002 ++#define MENLO_FW_TYPE_DIAG 0xABCD0003 ++ ++void ++BE_swap32_buffer(void *srcp, uint32_t cnt) ++{ ++ uint32_t *src = srcp; ++ uint32_t *dest = srcp; ++ uint32_t ldata; ++ int i; ++ ++ for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) { ++ ldata = *src; ++ ldata = cpu_to_le32(ldata); ++ *dest = ldata; ++ src++; ++ dest++; ++ } ++} ++ ++ ++static int ++lpfc_alloc_menlo_genrequest64(struct lpfc_hba * phba, ++ struct lpfc_menlo_genreq64 *sysfs_menlo, ++ struct lpfc_sysfs_menlo_hdr *cmdhdr) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); ++ struct ulp_bde64 *bpl = NULL; ++ IOCB_t *cmd = NULL, *rsp = NULL; ++ struct lpfc_sli *psli = NULL; ++ struct lpfc_sli_ring *pring = NULL; ++ int rc = 0; ++ uint32_t cmdsize; ++ uint32_t rspsize; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ ++ if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { ++ rc = EACCES; ++ goto send_menlomgmt_cmd_exit; ++ } ++ ++ if (!sysfs_menlo) { ++ rc = EINVAL; ++ goto send_menlomgmt_cmd_exit; ++ } ++ ++ cmdsize = cmdhdr->cmdsize; ++ rspsize = cmdhdr->rspsize; ++ ++ if (!cmdsize || !rspsize || (cmdsize + rspsize > 80 * BUF_SZ_4K)) { ++ rc = ERANGE; ++ goto send_menlomgmt_cmd_exit; ++ } ++ ++ spin_lock_irq(shost->host_lock); ++ sysfs_menlo->cmdiocbq = lpfc_sli_get_iocbq(phba); ++ if (!sysfs_menlo->cmdiocbq) { ++ rc = ENOMEM; ++ spin_unlock_irq(shost->host_lock); ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1202 alloc_menlo_genreq64: couldn't alloc cmdiocbq\n"); ++ goto send_menlomgmt_cmd_exit; ++ } ++ cmd = &sysfs_menlo->cmdiocbq->iocb; ++ ++ sysfs_menlo->rspiocbq = lpfc_sli_get_iocbq(phba); ++ if (!sysfs_menlo->rspiocbq) { ++ rc = ENOMEM; ++ spin_unlock_irq(shost->host_lock); ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1203 alloc_menlo_genreq64: couldn't alloc rspiocbq\n"); ++ goto send_menlomgmt_cmd_exit; ++ } ++ spin_unlock_irq(shost->host_lock); ++ ++ rsp = &sysfs_menlo->rspiocbq->iocb; ++ ++ ++ sysfs_menlo->bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); ++ if (!sysfs_menlo->bmp) { ++ rc = ENOMEM; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1204 alloc_menlo_genreq64: couldn't alloc bmp\n"); ++ goto send_menlomgmt_cmd_exit; ++ } ++ ++ spin_lock_irq(shost->host_lock); ++ sysfs_menlo->bmp->virt = lpfc_mbuf_alloc(phba, 0, ++ &sysfs_menlo->bmp->phys); ++ if (!sysfs_menlo->bmp->virt) { ++ rc = ENOMEM; ++ spin_unlock_irq(shost->host_lock); ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1205 alloc_menlo_genreq64: couldn't alloc bpl\n"); ++ goto send_menlomgmt_cmd_exit; ++ } ++ spin_unlock_irq(shost->host_lock); ++ ++ INIT_LIST_HEAD(&sysfs_menlo->bmp->list); ++ bpl = (struct ulp_bde64 *) sysfs_menlo->bmp->virt; ++ memset((uint8_t*)bpl, 0 , 1024); ++ sysfs_menlo->indmp = __dfc_cmd_data_alloc(phba, NULL, bpl, cmdsize, 1); ++ if (!sysfs_menlo->indmp) { ++ rc = ENOMEM; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1206 alloc_menlo_genreq64: couldn't alloc cmdbuf\n"); ++ goto send_menlomgmt_cmd_exit; ++ } ++ sysfs_menlo->cmdbpl = bpl; ++ INIT_LIST_HEAD(&sysfs_menlo->inhead); ++ list_add_tail(&sysfs_menlo->inhead, &sysfs_menlo->indmp->dma.list); ++ ++ /* flag contains total number of BPLs for xmit */ ++ ++ bpl += sysfs_menlo->indmp->flag; ++ ++ sysfs_menlo->outdmp = __dfc_cmd_data_alloc(phba, NULL, bpl, rspsize, 0); ++ if (!sysfs_menlo->outdmp) { ++ rc = ENOMEM; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1207 alloc_menlo_genreq64: couldn't alloc rspbuf\n"); ++ goto send_menlomgmt_cmd_exit; ++ } ++ INIT_LIST_HEAD(&sysfs_menlo->outhead); ++ list_add_tail(&sysfs_menlo->outhead, &sysfs_menlo->outdmp->dma.list); ++ ++ cmd->un.genreq64.bdl.ulpIoTag32 = 0; ++ cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(sysfs_menlo->bmp->phys); ++ cmd->un.genreq64.bdl.addrLow = putPaddrLow(sysfs_menlo->bmp->phys); ++ cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; ++ cmd->un.genreq64.bdl.bdeSize = ++ (sysfs_menlo->outdmp->flag + sysfs_menlo->indmp->flag) ++ * sizeof(struct ulp_bde64); ++ cmd->ulpCommand = CMD_GEN_REQUEST64_CR; ++ cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); ++ cmd->un.genreq64.w5.hcsw.Dfctl = 0; ++ cmd->un.genreq64.w5.hcsw.Rctl = FC_FCP_CMND; ++ cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ ++ cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ ++ cmd->ulpBdeCount = 1; ++ cmd->ulpClass = CLASS3; ++ cmd->ulpContext = MENLO_CONTEXT; /* 0 */ ++ cmd->ulpOwner = OWN_CHIP; ++ cmd->ulpPU = MENLO_PU; /* 3 */ ++ cmd->ulpLe = 1; /* Limited Edition */ ++ sysfs_menlo->cmdiocbq->vport = phba->pport; ++ sysfs_menlo->cmdiocbq->context1 = NULL; ++ sysfs_menlo->cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; ++ /* We want the firmware to timeout before we do */ ++ cmd->ulpTimeout = MENLO_TIMEOUT - 5; ++ ++ sysfs_menlo->timeout = cmd->ulpTimeout; ++ ++send_menlomgmt_cmd_exit: ++ return rc; ++} ++ ++void ++sysfs_menlo_genreq_free(struct lpfc_hba *phba, ++ struct lpfc_menlo_genreq64 *sysfs_menlo) ++{ ++ if ( !list_empty(&sysfs_menlo->outhead)) ++ list_del_init( &sysfs_menlo->outhead); ++ ++ if (!list_empty(&sysfs_menlo->inhead)) ++ list_del_init( &sysfs_menlo->inhead); ++ ++ if (sysfs_menlo->outdmp) { ++ __dfc_cmd_data_free(phba, sysfs_menlo->outdmp); ++ sysfs_menlo->outdmp = NULL; ++ } ++ if (sysfs_menlo->indmp) { ++ __dfc_cmd_data_free(phba, sysfs_menlo->indmp); ++ sysfs_menlo->indmp = NULL; ++ } ++ if (sysfs_menlo->bmp) { ++ lpfc_mbuf_free(phba, sysfs_menlo->bmp->virt, ++ sysfs_menlo->bmp->phys); ++ kfree(sysfs_menlo->bmp); ++ sysfs_menlo->bmp = NULL; ++ } ++ if (sysfs_menlo->rspiocbq) { ++ lpfc_sli_release_iocbq(phba, sysfs_menlo->rspiocbq); ++ sysfs_menlo->rspiocbq = NULL; ++ } ++ ++ if (sysfs_menlo->cmdiocbq) { ++ lpfc_sli_release_iocbq(phba, sysfs_menlo->cmdiocbq); ++ sysfs_menlo->cmdiocbq = NULL; ++ } ++} ++ ++static void ++sysfs_menlo_idle(struct lpfc_hba *phba, ++ struct lpfc_sysfs_menlo *sysfs_menlo) ++{ ++ struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); ++ ++ spin_lock_irq(&phba->hbalock); ++ list_del_init(&sysfs_menlo->list); ++ spin_unlock_irq(&phba->hbalock); ++ spin_lock_irq(shost->host_lock); ++ ++ if (sysfs_menlo->cr.cmdiocbq) ++ sysfs_menlo_genreq_free(phba, &sysfs_menlo->cr); ++ if (sysfs_menlo->cx.cmdiocbq) ++ sysfs_menlo_genreq_free(phba, &sysfs_menlo->cx); ++ ++ spin_unlock_irq(shost->host_lock); ++ kfree(sysfs_menlo); ++} ++ ++static void ++lpfc_menlo_iocb_timeout_cmpl(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdq, ++ struct lpfc_iocbq *rspq) ++{ ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1241 Menlo IOCB timeout: deleting %p\n", ++ cmdq->context3); ++ sysfs_menlo_idle(phba, (struct lpfc_sysfs_menlo *)cmdq->context3); ++} ++ ++static void ++lpfc_menlo_iocb_cmpl(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdq, ++ struct lpfc_iocbq *rspq) ++{ ++ struct lpfc_sysfs_menlo * sysfs_menlo = ++ (struct lpfc_sysfs_menlo *)cmdq->context2; ++ struct lpfc_dmabufext *mlast = NULL; ++ IOCB_t *rsp = NULL; ++ IOCB_t *cmd = NULL; ++ uint32_t * tmpptr = NULL; ++ menlo_init_rsp_t *mlorsp = NULL; ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1254 Menlo IOCB complete: %p\n", ++ cmdq->context2); ++ rsp = &rspq->iocb; ++ cmd = &cmdq->iocb; ++ if ( !sysfs_menlo ) { ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1255 Menlo IOCB complete:NULL CTX \n"); ++ return; ++ } ++ if ( rsp->ulpStatus ) { ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1242 iocb async cmpl: ulpStatus 0x%x " ++ "ulpWord[4] 0x%x\n", ++ rsp->ulpStatus, rsp->un.ulpWord[4]); ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1260 cr:%.08x %.08x %.08x %.08x " ++ "%.08x %.08x %.08x %.08x\n", ++ cmd->un.ulpWord[0], cmd->un.ulpWord[1], ++ cmd->un.ulpWord[2], cmd->un.ulpWord[3], ++ cmd->un.ulpWord[4], cmd->un.ulpWord[5], ++ *(uint32_t *)&cmd->un1, *((uint32_t *)&cmd->un1 + 1)); ++ mlast = list_get_first(&sysfs_menlo->cr.inhead, ++ struct lpfc_dmabufext, ++ dma.list); ++ if (!mlast) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1231 bad bpl:\n"); ++ goto lpfc_menlo_iocb_cmpl_ext; ++ } ++ tmpptr = ( uint32_t *) mlast->dma.virt; ++ BE_swap32_buffer ((uint8_t *) tmpptr, ++ sizeof( menlo_get_cmd_t)); ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1261 cmd:%.08x %.08x %.08x\n", ++ *tmpptr, *(tmpptr+1), *(tmpptr+2)); ++ goto lpfc_menlo_iocb_cmpl_ext; ++ } ++ ++ mlast = list_get_first(&sysfs_menlo->cr.outhead, ++ struct lpfc_dmabufext, ++ dma.list); ++ if (!mlast) { ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1256 bad bpl:\n"); ++ goto lpfc_menlo_iocb_cmpl_ext; ++ } ++ mlorsp = ( menlo_init_rsp_t *) mlast->dma.virt; ++ BE_swap32_buffer ((uint8_t *) mlorsp, ++ sizeof( menlo_init_rsp_t)); ++ ++ if (mlorsp->code != 0) { ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1243 Menlo command error. code=%d.\n", mlorsp->code); ++ goto lpfc_menlo_iocb_cmpl_ext; ++ ++ } ++ ++ switch (mlorsp->fw_type) ++ { ++ case MENLO_FW_TYPE_OPERATIONAL: /* Menlo Operational */ ++ break; ++ case MENLO_FW_TYPE_GOLDEN: /* Menlo Golden */ ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1246 FCoE chip is running golden firmware. " ++ "Update FCoE chip firmware immediately %x\n", ++ mlorsp->fw_type); ++ break; ++ case MENLO_FW_TYPE_DIAG: /* Menlo Diag */ ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1247 FCoE chip is running diagnostic " ++ "firmware. Operational use suspended. %x\n", ++ mlorsp->fw_type); ++ break; ++ default: ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1248 FCoE chip is running unknown " ++ "firmware x%x.\n", mlorsp->fw_type); ++ break; ++ } ++ if (!mlorsp->fru_data_valid ++ && (mlorsp->fw_type == MENLO_FW_TYPE_OPERATIONAL) ++ && (!mlorsp->maint_status)) ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1249 Invalid FRU data found on adapter." ++ "Return adapter to Emulex for repair\n"); ++ ++lpfc_menlo_iocb_cmpl_ext: ++ sysfs_menlo_idle(phba, (struct lpfc_sysfs_menlo *)cmdq->context2); ++} ++ ++static struct lpfc_sysfs_menlo * ++lpfc_get_sysfs_menlo(struct lpfc_hba *phba, uint8_t create) ++{ ++ struct lpfc_sysfs_menlo *sysfs_menlo; ++ pid_t pid; ++ ++ pid = current->pid; ++ ++ spin_lock_irq(&phba->hbalock); ++ list_for_each_entry(sysfs_menlo, &phba->sysfs_menlo_list, list) { ++ if (sysfs_menlo->pid == pid) { ++ spin_unlock_irq(&phba->hbalock); ++ return sysfs_menlo; ++ } ++ } ++ if (!create) { ++ spin_unlock_irq(&phba->hbalock); ++ return NULL; ++ } ++ spin_unlock_irq(&phba->hbalock); ++ sysfs_menlo = kzalloc(sizeof(struct lpfc_sysfs_menlo), ++ GFP_KERNEL); ++ if (!sysfs_menlo) ++ return NULL; ++ sysfs_menlo->state = SMENLO_IDLE; ++ sysfs_menlo->pid = pid; ++ spin_lock_irq(&phba->hbalock); ++ list_add_tail(&sysfs_menlo->list, &phba->sysfs_menlo_list); ++ ++ spin_unlock_irq(&phba->hbalock); ++ return sysfs_menlo; ++ ++} ++ ++static ssize_t ++lpfc_menlo_write(struct lpfc_hba *phba, ++ char *buf, loff_t off, size_t count) ++{ ++ struct lpfc_sysfs_menlo *sysfs_menlo; ++ struct lpfc_dmabufext *mlast = NULL; ++ struct lpfc_sysfs_menlo_hdr cmdhdrCR; ++ struct lpfc_menlo_genreq64 *genreq = NULL; ++ loff_t temp_off = 0; ++ struct ulp_bde64 *bpl = NULL; ++ int mlastcnt = 0; ++ uint32_t * tmpptr = NULL; ++ uint32_t addr_high = 0; ++ uint32_t addr_low = 0; ++ int hdr_offset = sizeof(struct lpfc_sysfs_menlo_hdr); ++ ++ if (off % 4 || count % 4 || (unsigned long)buf % 4) ++ return -EINVAL; ++ ++ if (count == 0) ++ return 0; ++ ++ if (off == 0) { ++ ssize_t rc; ++ struct lpfc_sysfs_menlo_hdr *cmdhdr = ++ (struct lpfc_sysfs_menlo_hdr *)buf; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1208 menlo_write: cmd %x cmdsz %d rspsz %d\n", ++ cmdhdr->cmd, cmdhdr->cmdsize, ++ cmdhdr->rspsize); ++ if (count != sizeof(struct lpfc_sysfs_menlo_hdr)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1210 Invalid cmd size: cmd %x " ++ "cmdsz %d rspsz %d\n", ++ cmdhdr->cmd, cmdhdr->cmdsize, ++ cmdhdr->rspsize); ++ return -EINVAL; ++ } ++ ++ sysfs_menlo = lpfc_get_sysfs_menlo(phba, 1); ++ if (!sysfs_menlo) ++ return -ENOMEM; ++ sysfs_menlo->cmdhdr = *cmdhdr; ++ if (cmdhdr->cmd == MENLO_CMD_FW_DOWNLOAD) { ++ sysfs_menlo->cmdhdr.cmdsize ++ -= sizeof(struct lpfc_sysfs_menlo_hdr); ++ ++ rc = lpfc_alloc_menlo_genrequest64(phba, ++ &sysfs_menlo->cx, ++ &sysfs_menlo->cmdhdr); ++ if (rc != 0) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1211 genreq alloc failed: %d\n", ++ (int) rc); ++ sysfs_menlo_idle(phba,sysfs_menlo); ++ return -ENOMEM; ++ } ++ cmdhdrCR.cmd = cmdhdr->cmd; ++ cmdhdrCR.cmdsize = sizeof(struct lpfc_sysfs_menlo_hdr); ++ cmdhdrCR.rspsize = 4; ++ } else ++ cmdhdrCR = *cmdhdr; ++ ++ rc = lpfc_alloc_menlo_genrequest64(phba, ++ &sysfs_menlo->cr,&cmdhdrCR); ++ if (rc != 0) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1223 menlo_write: couldn't alloc genreq %d\n", ++ (int) rc); ++ sysfs_menlo_idle(phba,sysfs_menlo); ++ return -ENOMEM; ++ } ++ } else { ++ sysfs_menlo = lpfc_get_sysfs_menlo(phba, 0); ++ if (!sysfs_menlo) ++ return -EAGAIN; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1212 menlo_write: sysfs_menlo %p cmd %x cmdsz %d" ++ " rspsz %d cr-off %d cx-off %d count %d\n", ++ sysfs_menlo, ++ sysfs_menlo->cmdhdr.cmd, ++ sysfs_menlo->cmdhdr.cmdsize, ++ sysfs_menlo->cmdhdr.rspsize, ++ (int)sysfs_menlo->cr.offset, ++ (int)sysfs_menlo->cx.offset, ++ (int)count); ++ } ++ ++ if ((count + sysfs_menlo->cr.offset) > sysfs_menlo->cmdhdr.cmdsize) { ++ if ( sysfs_menlo->cmdhdr.cmdsize != 4) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1213 FCoE cmd overflow: off %d + cnt %d > cmdsz %d\n", ++ (int)sysfs_menlo->cr.offset, ++ (int)count, ++ (int)sysfs_menlo->cmdhdr.cmdsize); ++ sysfs_menlo_idle(phba, sysfs_menlo); ++ return -ERANGE; ++ } ++ } ++ ++ spin_lock_irq(&phba->hbalock); ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD) ++ genreq = &sysfs_menlo->cx; ++ else ++ genreq = &sysfs_menlo->cr; ++ ++ if (off == 0) { ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD) { ++ tmpptr = NULL; ++ genreq = &sysfs_menlo->cr; ++ ++ if (!mlast) { ++ mlast = list_get_first(&genreq->inhead, ++ struct lpfc_dmabufext, ++ dma.list); ++ } ++ if (mlast) { ++ bpl = genreq->cmdbpl; ++ memcpy((uint8_t *) mlast->dma.virt, buf, count); ++ genreq->offset += count; ++ tmpptr = (uint32_t *)mlast->dma.virt; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1258 cmd %x cmdsz %d rspsz %d " ++ "copied %d addrL:%x addrH:%x\n", ++ *tmpptr, ++ *(tmpptr+1), ++ *(tmpptr+2), ++ (int)count, ++ bpl->addrLow,bpl->addrHigh); ++ } else { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1230 Could not find buffer for FCoE" ++ " cmd:off %d indmp %p %d\n", (int)off, ++ genreq->indmp,(int)count); ++ } ++ } ++ ++ sysfs_menlo->state = SMENLO_WRITING; ++ spin_unlock_irq(&phba->hbalock); ++ return count; ++ } else { ++ ssize_t adj_off = off - sizeof(struct lpfc_sysfs_menlo_hdr); ++ int found = 0; ++ if (sysfs_menlo->state != SMENLO_WRITING || ++ genreq->offset != adj_off) { ++ spin_unlock_irq(&phba->hbalock); ++ sysfs_menlo_idle(phba, sysfs_menlo); ++ return -EAGAIN; ++ } ++ mlast = NULL; ++ temp_off = sizeof(struct lpfc_sysfs_menlo_hdr); ++ if (genreq->indmp) { ++ list_for_each_entry(mlast, ++ &genreq->inhead, dma.list) { ++ if (temp_off == off) ++ break; ++ else ++ temp_off += BUF_SZ_4K; ++ mlastcnt++; ++ } ++ } ++ addr_low = le32_to_cpu( putPaddrLow(mlast->dma.phys) ); ++ addr_high = le32_to_cpu( putPaddrHigh(mlast->dma.phys) ); ++ bpl = genreq->cmdbpl; ++ bpl += mlastcnt; ++ if (bpl->addrLow != addr_low || bpl->addrHigh != addr_high) { ++ mlast = NULL; ++ list_for_each_entry(mlast, ++ &genreq->inhead, dma.list) { ++ ++ addr_low = le32_to_cpu( ++ putPaddrLow(mlast->dma.phys) ); ++ addr_high = le32_to_cpu( ++ putPaddrHigh(mlast->dma.phys) ); ++ if (bpl->addrLow == addr_low ++ && bpl->addrHigh == addr_high) { ++ found = 1; ++ break; ++ } ++ if ( mlastcnt < 3 ) ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1234 menlo_write: off:%d " ++ " mlastcnt:%d addl:%x addl:%x " ++ " addrh:%x addrh:%x mlast:%p\n", ++ (int)genreq->offset, ++ mlastcnt, ++ bpl->addrLow, ++ addr_low, ++ bpl->addrHigh, ++ addr_high,mlast); ++ } ++ } else ++ found = 1; ++ ++ if (!found) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1235 Could not find buffer for FCoE" ++ " cmd: off:%d poff:%d cnt:%d" ++ " mlastcnt:%d addl:%x addh:%x mdsz:%d \n", ++ (int)genreq->offset, ++ (int)off, ++ (int)count, ++ mlastcnt, ++ bpl->addrLow, ++ bpl->addrHigh, ++ (int)sysfs_menlo->cmdhdr.cmdsize); ++ mlast = NULL; ++ } ++ ++ } ++ ++ if (mlast) { ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD ) { ++ bpl = genreq->cmdbpl; ++ bpl += mlastcnt; ++ tmpptr = (uint32_t *)mlast->dma.virt; ++ if ( genreq->offset < hdr_offset ) { ++ memcpy((uint8_t *) mlast->dma.virt, ++ buf+hdr_offset, ++ count-hdr_offset); ++ bpl->tus.f.bdeSize = (ushort)count-hdr_offset; ++ mlast->size = (ushort)count-hdr_offset; ++ } else { ++ memcpy((uint8_t *) mlast->dma.virt, buf, count); ++ bpl->tus.f.bdeSize = (ushort)count; ++ mlast->size = (ushort)count; ++ } ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; ++ bpl->tus.w = le32_to_cpu(bpl->tus.w); ++ ++ } else ++ memcpy((uint8_t *) mlast->dma.virt, buf, count); ++ ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD ++ && genreq->offset < hdr_offset) { ++ if (sysfs_menlo->cr.indmp ++ && sysfs_menlo->cr.indmp->dma.virt) { ++ mlast = sysfs_menlo->cr.indmp; ++ memcpy((uint8_t *) mlast->dma.virt, ++ buf, hdr_offset); ++ tmpptr = (uint32_t *)mlast->dma.virt; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1237 cmd %x cmd1 %x cmd2 %x " ++ "copied %d\n", ++ *tmpptr, ++ *(tmpptr+1), ++ *(tmpptr+2), ++ hdr_offset); ++ } ++ } ++ genreq->offset += count; ++ } else { ++ spin_unlock_irq(&phba->hbalock); ++ sysfs_menlo_idle(phba,sysfs_menlo); ++ return -ERANGE; ++ } ++ ++ spin_unlock_irq(&phba->hbalock); ++ return count; ++ ++} ++ ++ ++static ssize_t ++sysfs_menlo_write(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ ++ return lpfc_menlo_write(phba, buf, off, count); ++} ++ ++ ++static ssize_t ++sysfs_menlo_issue_iocb_wait(struct lpfc_hba *phba, ++ struct lpfc_menlo_genreq64 *req, ++ struct lpfc_sysfs_menlo *sysfs_menlo) ++{ ++ struct lpfc_sli *psli = NULL; ++ struct lpfc_sli_ring *pring = NULL; ++ int rc = 0; ++ IOCB_t *rsp = NULL; ++ struct lpfc_iocbq *cmdiocbq = NULL; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ rsp = &req->rspiocbq->iocb; ++ cmdiocbq = req->cmdiocbq; ++ ++ rc = lpfc_sli_issue_iocb_wait(phba, pring, req->cmdiocbq, req->rspiocbq, ++ req->timeout); ++ ++ if (rc == IOCB_TIMEDOUT) { ++ ++ cmdiocbq->context2 = NULL; ++ cmdiocbq->context3 = sysfs_menlo; ++ cmdiocbq->iocb_cmpl = lpfc_menlo_iocb_timeout_cmpl; ++ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, ++ "1227 FCoE IOCB TMO: handler set for %p\n", ++ cmdiocbq->context3); ++ return -EACCES; ++ } ++ ++ if (rc != IOCB_SUCCESS) { ++ rc = -EFAULT; ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1216 FCoE IOCB failed: off %d rc=%d \n", ++ (int)req->offset, rc); ++ goto sysfs_menlo_issue_iocb_wait_exit; ++ } ++ ++ if (rsp->ulpStatus) { ++ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { ++ switch (rsp->un.ulpWord[4] & 0xff) { ++ case IOERR_SEQUENCE_TIMEOUT: ++ rc = -ETIMEDOUT; ++ break; ++ case IOERR_INVALID_RPI: ++ rc = -EFAULT; ++ break; ++ default: ++ rc = -EFAULT; ++ break; ++ } ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1217 mlo_issueIocb:2 off %d rc=%d " ++ "ulpWord[4] 0x%x\n", ++ (int)req->offset, rc, rsp->un.ulpWord[4]); ++ } ++ } ++sysfs_menlo_issue_iocb_wait_exit: ++ return rc; ++} ++ ++ ++static ssize_t ++sysfs_menlo_issue_iocb(struct lpfc_hba *phba, struct lpfc_menlo_genreq64 *req, ++ struct lpfc_sysfs_menlo *sysfs_menlo) ++{ ++ struct lpfc_sli *psli = NULL; ++ struct lpfc_sli_ring *pring = NULL; ++ int rc = 0; ++ IOCB_t *rsp = NULL; ++ struct lpfc_iocbq *cmdiocbq = NULL; ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ rsp = &req->rspiocbq->iocb; ++ cmdiocbq = req->cmdiocbq; ++ cmdiocbq->context2 = sysfs_menlo; ++ cmdiocbq->iocb_cmpl = lpfc_menlo_iocb_cmpl; ++ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, ++ "1257 lpfc_menlo_issue_iocb: handler set for %p\n", ++ cmdiocbq->context3); ++ ++ rc = lpfc_sli_issue_iocb(phba, pring, req->cmdiocbq, 0); ++ ++ if (rc == IOCB_TIMEDOUT) { ++ ++ cmdiocbq->context2 = NULL; ++ cmdiocbq->context3 = sysfs_menlo; ++ cmdiocbq->iocb_cmpl = lpfc_menlo_iocb_timeout_cmpl; ++ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, ++ "1228 FCoE IOCB TMO: handler set for %p\n", ++ cmdiocbq->context3); ++ return -EACCES; ++ } ++ ++ if (rc != IOCB_SUCCESS) { ++ rc = -EFAULT; ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1238 FCoE IOCB failed: off %d rc=%d \n", ++ (int)req->offset, rc); ++ goto sysfs_menlo_issue_iocb_exit; ++ } ++ ++ if (rsp->ulpStatus) { ++ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { ++ switch (rsp->un.ulpWord[4] & 0xff) { ++ case IOERR_SEQUENCE_TIMEOUT: ++ rc = -ETIMEDOUT; ++ break; ++ case IOERR_INVALID_RPI: ++ rc = -EFAULT; ++ break; ++ default: ++ rc = -EFAULT; ++ break; ++ } ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1239 mlo_issueIocb:2 off %d rc=%d " ++ "ulpWord[4] 0x%x\n", ++ (int)req->offset, rc, rsp->un.ulpWord[4]); ++ } ++ } ++sysfs_menlo_issue_iocb_exit: ++ return rc; ++} ++ ++static ssize_t ++lpfc_menlo_read(struct lpfc_hba *phba, char *buf, loff_t off, size_t count, ++ int wait) ++{ ++ struct lpfc_sli *psli = NULL; ++ struct lpfc_sli_ring *pring = NULL; ++ int rc = 0; ++ struct lpfc_sysfs_menlo *sysfs_menlo; ++ struct lpfc_dmabufext *mlast = NULL; ++ loff_t temp_off = 0; ++ struct lpfc_menlo_genreq64 *genreq = NULL; ++ IOCB_t *cmd = NULL, *rsp = NULL; ++ uint32_t * uptr = NULL; ++ ++ ++ psli = &phba->sli; ++ pring = &psli->ring[LPFC_ELS_RING]; ++ ++ if (off > SYSFS_MENLO_ATTR_SIZE) ++ return -ERANGE; ++ ++ if ((count + off) > SYSFS_MENLO_ATTR_SIZE) ++ count = SYSFS_MENLO_ATTR_SIZE - off; ++ ++ if (off % 4 || count % 4 || (unsigned long)buf % 4) ++ return -EINVAL; ++ ++ if (off && count == 0) ++ return 0; ++ ++ sysfs_menlo = lpfc_get_sysfs_menlo(phba, 0); ++ ++ if (!sysfs_menlo) ++ return -EPERM; ++ ++ if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { ++ sysfs_menlo_idle(phba, sysfs_menlo); ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1214 Can not issue FCoE cmd," ++ " SLI not active: off %d rc= -EACCESS\n", ++ (int)off); ++ return -EACCES; ++ } ++ ++ ++ if ((phba->link_state < LPFC_LINK_UP) ++ && !(psli->sli_flag & LPFC_MENLO_MAINT) ++ && wait) { ++ rc = -EPERM; ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ "1215 Can not issue FCoE cmd:" ++ " not ready or not in maint mode" ++ " off %d rc=%d \n", ++ (int)off, rc); ++ spin_lock_irq(&phba->hbalock); ++ goto lpfc_menlo_read_err_exit; ++ } ++ ++ if (off == 0 && sysfs_menlo->state == SMENLO_WRITING) { ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD) { ++ spin_lock_irq(&phba->hbalock); ++ genreq = &sysfs_menlo->cr; ++ spin_unlock_irq(&phba->hbalock); ++ } ++ if ( wait ) ++ rc = sysfs_menlo_issue_iocb_wait(phba, ++ &sysfs_menlo->cr, ++ sysfs_menlo); ++ else { ++ rc = sysfs_menlo_issue_iocb(phba, ++ &sysfs_menlo->cr, ++ sysfs_menlo); ++ return rc; ++ } ++ ++ spin_lock_irq(&phba->hbalock); ++ if (rc < 0) { ++ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, ++ "1224 FCoE iocb failed: off %d rc=%d \n", ++ (int)off, rc); ++ if (rc != -EACCES) ++ goto lpfc_menlo_read_err_exit; ++ else { ++ spin_unlock_irq(&phba->hbalock); ++ return rc; ++ } ++ } ++ ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD) { ++ cmd = &sysfs_menlo->cx.cmdiocbq->iocb; ++ rsp = &sysfs_menlo->cr.rspiocbq->iocb; ++ mlast = list_get_first(&sysfs_menlo->cr.outhead, ++ struct lpfc_dmabufext, ++ dma.list); ++ if ( *((uint32_t *) mlast->dma.virt) != 0 ) { ++ memcpy(buf,(uint8_t *) mlast->dma.virt, count); ++ goto lpfc_menlo_read_err_exit; ++ } ++ mlast = NULL; ++ ++ cmd->ulpCommand = CMD_GEN_REQUEST64_CX; ++ cmd->ulpContext = rsp->ulpContext; ++ cmd->ulpPU = 1; /* RelOffset */ ++ cmd->un.ulpWord[4] = 0; /* offset 0 */ ++ ++ spin_unlock_irq(&phba->hbalock); ++ rc = sysfs_menlo_issue_iocb_wait(phba, &sysfs_menlo->cx, ++ sysfs_menlo); ++ spin_lock_irq(&phba->hbalock); ++ if (rc < 0) { ++ uptr = (uint32_t *) rsp; ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1225 menlo_read: off %d rc=%d " ++ "rspxri %d cmdxri %d \n", ++ (int)off, rc, rsp->ulpContext, ++ cmd->ulpContext); ++ uptr = (uint32_t *) ++ &sysfs_menlo->cr.cmdiocbq->iocb; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1236 cr:%.08x %.08x %.08x %.08x " ++ "%.08x %.08x %.08x %.08x %.08x\n", ++ *uptr, *(uptr+1), *(uptr+2), ++ *(uptr+3), *(uptr+4), *(uptr+5), ++ *(uptr+6), *(uptr+7), *(uptr+8)); ++ uptr = (uint32_t *)rsp; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1232 cr-rsp:%.08x %.08x %.08x %.08x " ++ "%.08x %.08x %.08x %.08x %.08x\n", ++ *uptr, *(uptr+1), *(uptr+2), ++ *(uptr+3), *(uptr+4), *(uptr+5), ++ *(uptr+6), *(uptr+7), *(uptr+8)); ++ uptr = (uint32_t *)cmd; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1233 cx:%.08x %.08x %.08x %.08x " ++ "%.08x %.08x %.08x %.08x %.08x\n", ++ *uptr, *(uptr+1), *(uptr+2), ++ *(uptr+3), *(uptr+4), *(uptr+5), ++ *(uptr+6), *(uptr+7), *(uptr+8)); ++ if (rc != -EACCES) ++ goto lpfc_menlo_read_err_exit; ++ else { ++ spin_unlock_irq(&phba->hbalock); ++ return rc; ++ } ++ } ++ } ++ sysfs_menlo->state = SMENLO_READING; ++ sysfs_menlo->cr.offset = 0; ++ ++ } else ++ spin_lock_irq(&phba->hbalock); ++ ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD) ++ genreq = &sysfs_menlo->cx; ++ else ++ genreq = &sysfs_menlo->cr; ++ ++ /* Copy back response data */ ++ if (sysfs_menlo->cmdhdr.rspsize > count) { ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1218 MloMgnt Rqst err Data: x%x %d %d %d %d\n", ++ genreq->outdmp->flag, ++ sysfs_menlo->cmdhdr.rspsize, ++ (int)count, (int)off, (int)genreq->offset); ++ } ++ ++ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { ++ rc = -EAGAIN; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1219 menlo_read:4 off %d rc=%d \n", ++ (int)off, rc); ++ goto lpfc_menlo_read_err_exit; ++ } ++ else if ( sysfs_menlo->state != SMENLO_READING) { ++ rc = -EAGAIN; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1220 menlo_read:5 off %d reg off %d rc=%d state %x\n", ++ (int)off,(int)genreq->offset, sysfs_menlo->state, rc); ++ goto lpfc_menlo_read_err_exit; ++ } ++ temp_off = 0; ++ mlast = NULL; ++ list_for_each_entry(mlast, &genreq->outhead, dma.list) { ++ if (temp_off == off) ++ break; ++ else ++ temp_off += BUF_SZ_4K; ++ } ++ if (mlast) ++ memcpy(buf,(uint8_t *) mlast->dma.virt, count); ++ else { ++ rc = -ERANGE; ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1221 menlo_read:6 off %d rc=%d \n", ++ (int)off, rc); ++ goto lpfc_menlo_read_err_exit; ++ } ++ genreq->offset += count; ++ ++ ++ if (genreq->offset >= sysfs_menlo->cmdhdr.rspsize) { ++ lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, ++ "1222 menlo_read: done off %d rc=%d" ++ " cnt %d rsp_code %x\n", ++ (int)off, rc, (int)count,*((uint32_t *)buf)); ++ rc = count; ++ goto lpfc_menlo_read_err_exit; ++ } ++ ++ if (count >= sysfs_menlo->cmdhdr.rspsize) ++ rc = sysfs_menlo->cmdhdr.rspsize; ++ else /* Can there be a > 4k response */ ++ rc = count; ++ if (genreq->offset < sysfs_menlo->cmdhdr.rspsize) { ++ spin_unlock_irq(&phba->hbalock); ++ return rc; ++ } ++ ++lpfc_menlo_read_err_exit: ++ spin_unlock_irq(&phba->hbalock); ++ sysfs_menlo_idle(phba,sysfs_menlo); ++ return rc; ++} ++ ++ ++static ssize_t ++sysfs_menlo_read(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ ++ return lpfc_menlo_read(phba, buf, off, count, 1); ++} ++int need_non_blocking = 0; ++void lpfc_check_menlo_cfg(struct lpfc_hba *phba) ++{ ++ uint32_t cmd_size; ++ uint32_t rsp_size; ++ menlo_get_cmd_t *cmd = NULL; ++ menlo_init_rsp_t *rsp = NULL; ++ int rc = 0; ++ ++ lpfc_printf_log (phba, KERN_INFO, LOG_LINK_EVENT, ++ "1253 Checking FCoE chip firmware.\n"); ++ if ( need_non_blocking ) /* Need non blocking issue_iocb */ ++ return; ++ ++ cmd_size = sizeof (menlo_get_cmd_t); ++ cmd = kmalloc(cmd_size, GFP_KERNEL); ++ if (!cmd ) { ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1240 Unable to allocate command buffer memory.\n"); ++ return; ++ } ++ ++ rsp_size = sizeof (menlo_init_rsp_t); ++ rsp = kmalloc(rsp_size, GFP_KERNEL); ++ if (!rsp ) { ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1244 Unable to allocate response buffer memory.\n"); ++ kfree(rsp); ++ return; ++ } ++ ++ memset(cmd,0, cmd_size); ++ memset(rsp,0, rsp_size); ++ ++ cmd->code = MENLO_CMD_GET_INIT; ++ cmd->context = cmd_size; ++ cmd->length = rsp_size; ++ rc = lpfc_menlo_write (phba, (char *) cmd, 0, cmd_size); ++ if ( rc != cmd_size ) { ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1250 Menlo command error. code=%d.\n", rc); ++ ++ kfree (cmd); ++ kfree (rsp); ++ return; ++ } ++ cmd->code = MENLO_CMD_GET_INIT; ++ cmd->context = 0; ++ cmd->length = rsp_size; ++ BE_swap32_buffer ((uint8_t *) cmd, cmd_size); ++ rc = lpfc_menlo_write (phba, (char *) cmd, cmd_size, cmd_size); ++ if ( rc != cmd_size ) { ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1251 Menlo command error. code=%d.\n", rc); ++ ++ kfree (cmd); ++ kfree (rsp); ++ return; ++ } ++ rc = lpfc_menlo_read (phba, (char *) rsp, 0, rsp_size,0); ++ if ( rc && rc != rsp_size ) { ++ lpfc_printf_log (phba, KERN_ERR, LOG_LINK_EVENT, ++ "1252 Menlo command error. code=%d.\n", rc); ++ ++ } ++ kfree (cmd); ++ kfree (rsp); ++ return; ++} ++ ++struct bin_attribute sysfs_menlo_attr = { ++ .attr = { ++ .name = "menlo", ++ .mode = S_IRUSR | S_IWUSR, ++ .owner = THIS_MODULE, ++ }, ++ .size = SYSFS_MENLO_ATTR_SIZE, ++ .read = sysfs_menlo_read, ++ .write = sysfs_menlo_write, ++}; +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -42,7 +42,6 @@ + + #define LPFC_RESET_WAIT 2 + #define LPFC_ABORT_WAIT 2 +- + /** + * lpfc_update_stats: Update statistical data for the command completion. + * @phba: Pointer to HBA object. +@@ -336,6 +335,22 @@ lpfc_scsi_dev_block(struct lpfc_hba *phb + lpfc_destroy_vport_work_array(phba, vports); + } + ++void ++lpfc_scsi_dev_rescan(struct lpfc_hba *phba) ++{ ++ struct lpfc_vport **vports; ++ struct Scsi_Host *shost; ++ int i; ++ ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports != NULL) ++ for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { ++ shost = lpfc_shost_from_vport(vports[i]); ++ scsi_scan_host(shost); ++ } ++ lpfc_destroy_vport_work_array(phba, vports); ++} ++ + /* + * This routine allocates a scsi buffer, which contains all the necessary + * information needed to initiate a SCSI I/O. The non-DMAable buffer region +@@ -1841,22 +1856,3 @@ struct scsi_host_template lpfc_template + .max_sectors = 0xFFFF, + }; + +-struct scsi_host_template lpfc_vport_template = { +- .module = THIS_MODULE, +- .name = LPFC_DRIVER_NAME, +- .info = lpfc_info, +- .queuecommand = lpfc_queuecommand, +- .eh_abort_handler = lpfc_abort_handler, +- .eh_device_reset_handler= lpfc_device_reset_handler, +- .eh_bus_reset_handler = lpfc_bus_reset_handler, +- .slave_alloc = lpfc_slave_alloc, +- .slave_configure = lpfc_slave_configure, +- .slave_destroy = lpfc_slave_destroy, +- .scan_finished = lpfc_scan_finished, +- .this_id = -1, +- .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, +- .cmd_per_lun = LPFC_CMD_PER_LUN, +- .use_clustering = ENABLE_CLUSTERING, +- .shost_attrs = lpfc_vport_attrs, +- .max_sectors = 0xFFFF, +-}; +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_security.c +@@ -0,0 +1,339 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2008 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "lpfc_hw.h" ++#include "lpfc_sli.h" ++#include "lpfc_nl.h" ++#include "lpfc_disc.h" ++#include "lpfc.h" ++#include "lpfc_crtn.h" ++#include "lpfc_logmsg.h" ++#include "lpfc_security.h" ++#include "lpfc_auth_access.h" ++#include "lpfc_vport.h" ++ ++uint8_t lpfc_security_service_state = SECURITY_OFFLINE; ++ ++void ++lpfc_security_service_online(struct Scsi_Host *shost) ++{ ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ ++ lpfc_security_service_state = SECURITY_ONLINE; ++ if (vport->cfg_enable_auth && ++ vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN && ++ vport->phba->link_state == LPFC_HBA_ERROR) ++ lpfc_selective_reset(vport->phba); ++} ++ ++void ++lpfc_security_service_offline(struct Scsi_Host *shost) ++{ ++ lpfc_security_service_state = SECURITY_OFFLINE; ++} ++ ++void ++lpfc_security_config(struct Scsi_Host *shost, int status, void *rsp) ++{ ++ struct fc_auth_rsp *auth_rsp = (struct fc_auth_rsp *)rsp; ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ struct lpfc_nodelist *ndlp; ++ uint32_t old_interval, new_interval; ++ unsigned long new_jiffies, temp_jiffies; ++ uint8_t last_auth_mode; ++ ++ if (status) ++ return; ++ ndlp = lpfc_findnode_did(vport, Fabric_DID); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) ++ return; ++ ++ vport->auth.bidirectional = ++ auth_rsp->u.dhchap_security_config.bidirectional; ++ memcpy(&vport->auth.hash_priority[0], ++ &auth_rsp->u.dhchap_security_config.hash_priority[0], ++ sizeof(vport->auth.hash_priority)); ++ vport->auth.hash_len = auth_rsp->u.dhchap_security_config.hash_len; ++ memcpy(&vport->auth.dh_group_priority[0], ++ &auth_rsp->u.dhchap_security_config. ++ dh_group_priority[0], ++ sizeof(vport->auth.dh_group_priority)); ++ vport->auth.dh_group_len = ++ auth_rsp->u.dhchap_security_config.dh_group_len; ++ old_interval = vport->auth.reauth_interval; ++ vport->auth.reauth_interval = ++ auth_rsp->u.dhchap_security_config.reauth_interval; ++ new_interval = vport->auth.reauth_interval; ++ /* ++ * If interval changed we need to adjust the running timer ++ * If enabled then start timer now. ++ * If disabled then stop the timer. ++ * If changed to chorter then elapsed time, then set to fire now ++ * If changed to longer than elapsed time, extend the timer. ++ */ ++ if (old_interval != new_interval && ++ vport->auth.auth_state == LPFC_AUTH_SUCCESS) { ++ new_jiffies = msecs_to_jiffies(new_interval * 60000); ++ del_timer_sync(&ndlp->nlp_reauth_tmr); ++ if (old_interval == 0) ++ temp_jiffies = jiffies + new_jiffies; ++ if (new_interval == 0) ++ temp_jiffies = 0; ++ else if (new_jiffies < (jiffies - vport->auth.last_auth)) ++ temp_jiffies = jiffies + msecs_to_jiffies(1); ++ else ++ temp_jiffies = jiffies + (new_jiffies - ++ (jiffies - vport->auth.last_auth)); ++ if (temp_jiffies) ++ mod_timer(&ndlp->nlp_reauth_tmr, temp_jiffies); ++ } ++ last_auth_mode = vport->auth.auth_mode; ++ vport->auth.auth_mode = ++ auth_rsp->u.dhchap_security_config.auth_mode; ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, ++ "1025 Received security config local_wwpn:" ++ "%llX remote_wwpn:%llX \nmode:0x%x " ++ "hash(%d):%x:%x:%x:%x bidir:0x%x " ++ "dh_group(%d):%x:%x:%x:%x:%x:%x:%x:%x " ++ "reauth_interval:0x%x\n", ++ (unsigned long long)auth_rsp->local_wwpn, ++ (unsigned long long)auth_rsp->remote_wwpn, ++ auth_rsp->u.dhchap_security_config.auth_mode, ++ auth_rsp->u.dhchap_security_config.hash_len, ++ auth_rsp->u.dhchap_security_config.hash_priority[0], ++ auth_rsp->u.dhchap_security_config.hash_priority[1], ++ auth_rsp->u.dhchap_security_config.hash_priority[2], ++ auth_rsp->u.dhchap_security_config.hash_priority[3], ++ auth_rsp->u.dhchap_security_config.bidirectional, ++ auth_rsp->u.dhchap_security_config.dh_group_len, ++ auth_rsp->u.dhchap_security_config.dh_group_priority[0], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[1], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[2], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[3], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[4], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[5], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[6], ++ auth_rsp->u.dhchap_security_config.dh_group_priority[7], ++ auth_rsp->u.dhchap_security_config.reauth_interval); ++ kfree(auth_rsp); ++ if (vport->auth.auth_mode == FC_AUTHMODE_ACTIVE) ++ vport->auth.security_active = 1; ++ else if (vport->auth.auth_mode == FC_AUTHMODE_PASSIVE) { ++ if (ndlp->nlp_flag & NLP_SC_REQ) ++ vport->auth.security_active = 1; ++ else { ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, ++ "1038 Authentication not " ++ "required by the fabric. " ++ "Disabled.\n"); ++ vport->auth.security_active = 0; ++ } ++ } else { ++ vport->auth.security_active = 0; ++ /* ++ * If switch require authentication and authentication ++ * is disabled for this HBA/Fabric port, fail the ++ * discovery. ++ */ ++ if (ndlp->nlp_flag & NLP_SC_REQ) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1050 Authentication mode is " ++ "disabled, but is required by " ++ "the fabric.\n"); ++ lpfc_vport_set_state(vport, FC_VPORT_FAILED); ++ /* Cancel discovery timer */ ++ lpfc_can_disctmo(vport); ++ } ++ } ++ if (last_auth_mode == FC_AUTHMODE_UNKNOWN) { ++ if (vport->auth.security_active) ++ lpfc_start_authentication(vport, ndlp); ++ else ++ lpfc_start_discovery(vport); ++ } ++} ++ ++int ++lpfc_get_security_enabled(struct Scsi_Host *shost) ++{ ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ ++ return(vport->cfg_enable_auth); ++} ++ ++int ++lpfc_security_wait(struct lpfc_hba *phba) ++{ ++ int i = 0; ++ if (lpfc_security_service_state == SECURITY_ONLINE) ++ return 0; ++ lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY, ++ "1058 Waiting for authentication service...\n"); ++ while (lpfc_security_service_state == SECURITY_OFFLINE) { ++ i++; ++ if (i > SECURITY_WAIT_TMO * 2) ++ return -ETIMEDOUT; ++ /* Delay for half of a second */ ++ msleep(500); ++ } ++ lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY, ++ "1059 Authentication service online.\n"); ++ return 0; ++} ++ ++int ++lpfc_security_config_wait(struct lpfc_vport *vport) ++{ ++ int i = 0; ++ ++ while (vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN) { ++ i++; ++ if (i > 120) { ++ return -ETIMEDOUT; ++ } ++ /* Delay for half of a second */ ++ msleep(500); ++ } ++ return 0; ++} ++ ++void ++lpfc_reauth_node(unsigned long ptr) ++{ ++ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr; ++ struct lpfc_vport *vport = ndlp->vport; ++ struct lpfc_hba *phba = vport->phba; ++ unsigned long flags; ++ struct lpfc_work_evt *evtp = &ndlp->els_reauth_evt; ++ ++ ndlp = (struct lpfc_nodelist *) ptr; ++ phba = ndlp->vport->phba; ++ ++ spin_lock_irqsave(&phba->hbalock, flags); ++ if (!list_empty(&evtp->evt_listp)) { ++ spin_unlock_irqrestore(&phba->hbalock, flags); ++ return; ++ } ++ ++ /* We need to hold the node resource by incrementing the reference ++ * count until this queued work is done ++ */ ++ evtp->evt_arg1 = lpfc_nlp_get(ndlp); ++ if (evtp->evt_arg1) { ++ evtp->evt = LPFC_EVT_REAUTH; ++ list_add_tail(&evtp->evt_listp, &phba->work_list); ++ lpfc_worker_wake_up(phba); ++ } ++ spin_unlock_irqrestore(&phba->hbalock, flags); ++ return; ++} ++ ++void ++lpfc_reauthentication_handler(struct lpfc_nodelist *ndlp) ++{ ++ struct lpfc_vport *vport = ndlp->vport; ++ if (vport->auth.auth_msg_state != LPFC_DHCHAP_SUCCESS) ++ return; ++ ++ if (lpfc_start_node_authentication(ndlp)) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1029 Reauthentication Failure\n"); ++ if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) ++ lpfc_port_auth_failed(ndlp); ++ } ++} ++ ++/* ++ * This function will kick start authentication for a node. ++ * This is used for re-authentication of a node or a user ++ * initiated node authentication. ++ */ ++int ++lpfc_start_node_authentication(struct lpfc_nodelist *ndlp) ++{ ++ struct lpfc_vport *vport; ++ int ret; ++ ++ vport = ndlp->vport; ++ /* If there is authentication timer cancel the timer */ ++ del_timer_sync(&ndlp->nlp_reauth_tmr); ++ ret = lpfc_get_auth_config(ndlp, &ndlp->nlp_portname); ++ if (ret) ++ return ret; ++ ret = lpfc_security_config_wait(vport); ++ if (ret) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1032 Start Authentication: get config " ++ "timed out.\n"); ++ return ret; ++ } ++ return 0; ++} ++ ++int ++lpfc_get_auth_config(struct lpfc_nodelist *ndlp, struct lpfc_name *rwwn) ++{ ++ struct lpfc_vport *vport; ++ struct fc_auth_req auth_req; ++ struct fc_auth_rsp *auth_rsp; ++ struct Scsi_Host *shost; ++ int ret; ++ ++ vport = ndlp->vport; ++ shost = lpfc_shost_from_vport(vport); ++ ++ auth_req.local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn); ++ if (ndlp->nlp_type & NLP_FABRIC) ++ auth_req.remote_wwpn = AUTH_FABRIC_WWN; ++ else ++ auth_req.remote_wwpn = wwn_to_u64(rwwn->u.wwn); ++ if (lpfc_security_service_state == SECURITY_OFFLINE) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1053 Start Authentication: " ++ "Security service offline.\n"); ++ return -EINVAL; ++ } ++ auth_rsp = kmalloc(sizeof(struct fc_auth_rsp), GFP_KERNEL); ++ if (!auth_rsp) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1028 Start Authentication: No buffers\n"); ++ return -ENOMEM; ++ } ++ vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; ++ ret = lpfc_fc_security_get_config(shost, &auth_req, ++ sizeof(struct fc_auth_req), ++ auth_rsp, ++ sizeof(struct fc_auth_rsp)); ++ if (ret) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, ++ "1031 Start Authentication: Get config " ++ "failed.\n"); ++ kfree(auth_rsp); ++ return ret; ++ } ++ return 0; ++} +--- /dev/null ++++ b/drivers/scsi/lpfc/lpfc_security.h +@@ -0,0 +1,24 @@ ++/******************************************************************* ++ * This file is part of the Emulex Linux Device Driver for * ++ * Fibre Channel Host Bus Adapters. * ++ * Copyright (C) 2006-2007 Emulex. All rights reserved. * ++ * EMULEX and SLI are trademarks of Emulex. * ++ * www.emulex.com * ++ * * ++ * This program is free software; you can redistribute it and/or * ++ * modify it under the terms of version 2 of the GNU General * ++ * Public License as published by the Free Software Foundation. * ++ * This program is distributed in the hope that it will be useful. * ++ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * ++ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * ++ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * ++ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * ++ * TO BE LEGALLY INVALID. See the GNU General Public License for * ++ * more details, a copy of which can be found in the file COPYING * ++ * included with this package. * ++ *******************************************************************/ ++ ++#define SECURITY_OFFLINE 0x0 ++#define SECURITY_ONLINE 0x1 ++ ++#define SECURITY_WAIT_TMO 30 /* seconds to wait for the auth service */ +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -796,7 +796,7 @@ lpfc_sli_hbq_to_firmware(struct lpfc_hba + hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr)); + hbqe->bde.addrLow = le32_to_cpu(putPaddrLow(physaddr)); + hbqe->bde.tus.f.bdeSize = hbq_buf->size; +- hbqe->bde.tus.f.bdeFlags = 0; ++ hbqe->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; + hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w); + hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag); + /* Sync SLIM */ +@@ -1051,6 +1051,9 @@ lpfc_sli_chk_mbx_command(uint8_t mbxComm + case MBX_REG_VPI: + case MBX_UNREG_VPI: + case MBX_HEARTBEAT: ++ case MBX_READ_EVENT_LOG_STATUS: ++ case MBX_READ_EVENT_LOG: ++ case MBX_WRITE_EVENT_LOG: + case MBX_PORT_CAPABILITIES: + case MBX_PORT_IOV_CONTROL: + ret = mbxCommand; +@@ -3546,9 +3549,35 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + mb->mbxOwner = OWN_CHIP; + + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { +- /* First copy command data to host SLIM area */ ++ /* Populate mbox extension offset word. */ ++ if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) { ++ *(((uint32_t *)mb) + pmbox->mbox_offset_word) ++ = (uint8_t *)phba->mbox_ext ++ - (uint8_t *)phba->mbox; ++ } ++ ++ /* Copy the mailbox extension data */ ++ if (pmbox->in_ext_byte_len && pmbox->context2) { ++ lpfc_sli_pcimem_bcopy(pmbox->context2, ++ (uint8_t*)phba->mbox_ext, ++ pmbox->in_ext_byte_len); ++ } ++ /* Copy command data to host SLIM area */ + lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); ++ + } else { ++ /* Populate mbox extension offset word. */ ++ if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) ++ *(((uint32_t *)mb) + pmbox->mbox_offset_word) ++ = MAILBOX_HBA_EXT_OFFSET; ++ ++ /* Copy the mailbox extension data */ ++ if (pmbox->in_ext_byte_len && pmbox->context2) { ++ lpfc_memcpy_to_slim(phba->MBslimaddr + ++ MAILBOX_HBA_EXT_OFFSET, ++ pmbox->context2, pmbox->in_ext_byte_len); ++ ++ } + if (mb->mbxCommand == MBX_CONFIG_PORT) { + /* copy command data into host mbox for cmpl */ + lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); +@@ -3658,15 +3687,22 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phb + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { + /* copy results back to user */ + lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); ++ /* Copy the mailbox extension data */ ++ if (pmbox->out_ext_byte_len && pmbox->context2) { ++ lpfc_sli_pcimem_bcopy(phba->mbox_ext, ++ pmbox->context2, ++ pmbox->out_ext_byte_len); ++ } + } else { + /* First copy command data */ + lpfc_memcpy_from_slim(mb, phba->MBslimaddr, + MAILBOX_CMD_SIZE); +- if ((mb->mbxCommand == MBX_DUMP_MEMORY) && +- pmbox->context2) { +- lpfc_memcpy_from_slim((void *)pmbox->context2, +- phba->MBslimaddr + DMP_RSP_OFFSET, +- mb->un.varDmp.word_cnt); ++ /* Copy the mailbox extension data */ ++ if (pmbox->out_ext_byte_len && pmbox->context2) { ++ lpfc_memcpy_from_slim(pmbox->context2, ++ phba->MBslimaddr + ++ MAILBOX_HBA_EXT_OFFSET, ++ pmbox->out_ext_byte_len); + } + } + +@@ -5395,6 +5431,15 @@ lpfc_sp_intr_handler(int irq, void *dev_ + if (pmb->mbox_cmpl) { + lpfc_sli_pcimem_bcopy(mbox, pmbox, + MAILBOX_CMD_SIZE); ++ /* Copy the mailbox extension data */ ++ if (pmb->out_ext_byte_len && ++ pmb->context2) { ++ lpfc_sli_pcimem_bcopy( ++ phba->mbox_ext, ++ pmb->context2, ++ pmb->out_ext_byte_len); ++ } ++ + } + if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { + pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; +--- a/drivers/scsi/lpfc/lpfc_sli.h ++++ b/drivers/scsi/lpfc/lpfc_sli.h +@@ -88,6 +88,9 @@ typedef struct lpfcMboxq { + + void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); + uint8_t mbox_flag; ++ uint16_t in_ext_byte_len; ++ uint16_t out_ext_byte_len; ++ uint8_t mbox_offset_word; + + } LPFC_MBOXQ_t; + +--- a/drivers/scsi/lpfc/lpfc_version.h ++++ b/drivers/scsi/lpfc/lpfc_version.h +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8" ++#define LPFC_DRIVER_VERSION "8.2.8.1" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" +--- a/drivers/scsi/lpfc/lpfc_vport.c ++++ b/drivers/scsi/lpfc/lpfc_vport.c +@@ -42,6 +42,7 @@ + #include "lpfc_crtn.h" + #include "lpfc_version.h" + #include "lpfc_vport.h" ++#include "lpfc_auth_access.h" + + inline void lpfc_vport_set_state(struct lpfc_vport *vport, + enum fc_vport_state new_state) +@@ -394,6 +395,21 @@ lpfc_vport_create(struct fc_vport *fc_vp + goto error_out; + } + ++ shost = lpfc_shost_from_vport(vport); ++ ++ if ((lpfc_get_security_enabled)(shost)) { ++ spin_lock_irq(&fc_security_user_lock); ++ ++ list_add_tail(&vport->sc_users, &fc_security_user_list); ++ ++ spin_unlock_irq(&fc_security_user_lock); ++ ++ if (fc_service_state == FC_SC_SERVICESTATE_ONLINE) { ++ lpfc_fc_queue_security_work(vport, ++ &vport->sc_online_work); ++ } ++ } ++ + *(struct lpfc_vport **)fc_vport->dd_data = vport; + vport->fc_vport = fc_vport; + +--- a/drivers/scsi/lpfc/Makefile ++++ b/drivers/scsi/lpfc/Makefile +@@ -1,7 +1,7 @@ + #/******************************************************************* + # * This file is part of the Emulex Linux Device Driver for * + # * Fibre Channel Host Bus Adapters. * +-# * Copyright (C) 2004-2006 Emulex. All rights reserved. * ++# * Copyright (C) 2004-2008 Emulex. All rights reserved. * + # * EMULEX and SLI are trademarks of Emulex. * + # * www.emulex.com * + # * * +@@ -28,4 +28,5 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o + + lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \ + lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \ +- lpfc_vport.o lpfc_debugfs.o ++ lpfc_vport.o lpfc_debugfs.o lpfc_security.o lpfc_auth_access.o \ ++ lpfc_auth.o lpfc_ioctl.o lpfc_menlo.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.10-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.10-update new file mode 100644 index 000000000..6573fca3d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.10-update @@ -0,0 +1,231 @@ +Subject: Emulex 8.2.8.10 driver patches for SLE11 +From: Jamie Wellnitz +References: bnc#460775 + +Changes from 8.2.8.9 to 8.2.8.10: + +* Changed version number to 8.2.8.10 +* Fix crash during driver load when authentication is enabled (CR 86652 86677) + + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke +-- +diff -urpN a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +--- a/drivers/scsi/lpfc/lpfc_attr.c 2008-12-16 16:01:42.260089000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_attr.c 2008-12-16 16:01:42.586088000 -0500 +@@ -4303,7 +4303,7 @@ lpfc_get_host_port_state(struct Scsi_Hos + fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; + else { + if ((vport->cfg_enable_auth) && +- (lpfc_security_service_state == SECURITY_OFFLINE)) { ++ (vport->security_service_state == SECURITY_OFFLINE)) { + fc_host_port_state(shost) = FC_PORTSTATE_ERROR; + spin_unlock_irq(shost->host_lock); + return; +diff -urpN a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +--- a/drivers/scsi/lpfc/lpfc_crtn.h 2008-12-16 16:01:42.285088000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_crtn.h 2008-12-16 16:01:42.606088000 -0500 +@@ -295,7 +295,7 @@ int lpfc_get_instance(void); + void lpfc_host_attrib_init(struct Scsi_Host *); + + int lpfc_selective_reset(struct lpfc_hba *); +-int lpfc_security_wait(struct lpfc_hba *); ++int lpfc_security_wait(struct lpfc_vport *); + int lpfc_get_security_enabled(struct Scsi_Host *); + void lpfc_security_service_online(struct Scsi_Host *); + void lpfc_security_service_offline(struct Scsi_Host *); +@@ -318,7 +318,6 @@ extern void lpfc_debugfs_slow_ring_trc(s + uint32_t, uint32_t); + extern struct lpfc_hbq_init *lpfc_hbq_defs[]; + +-extern uint8_t lpfc_security_service_state; + extern spinlock_t fc_security_user_lock; + extern struct list_head fc_security_user_list; + extern int fc_service_state; +diff -urpN a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c +--- a/drivers/scsi/lpfc/lpfc_els.c 2008-12-16 16:01:42.345090000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_els.c 2008-12-16 16:01:42.652088000 -0500 +@@ -945,7 +945,7 @@ lpfc_initial_flogi(struct lpfc_vport *vp + struct lpfc_nodelist *ndlp; + + if ((vport->cfg_enable_auth) && +- (lpfc_security_service_state == SECURITY_OFFLINE)) ++ (vport->security_service_state == SECURITY_OFFLINE)) + return 1; + + vport->port_state = LPFC_FLOGI; +@@ -1000,7 +1000,7 @@ lpfc_initial_fdisc(struct lpfc_vport *vp + struct lpfc_nodelist *ndlp; + + if (vport->cfg_enable_auth) { +- if (lpfc_security_wait(phba)) { ++ if (lpfc_security_wait(vport)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, + "1049 Authentication is enabled but " + "authentication service is not " +diff -urpN a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h +--- a/drivers/scsi/lpfc/lpfc.h 2008-12-16 16:01:42.366088000 -0500 ++++ b/drivers/scsi/lpfc/lpfc.h 2008-12-16 16:01:42.656088000 -0500 +@@ -478,6 +478,7 @@ struct lpfc_vport { + struct list_head sc_users; + struct work_struct sc_online_work; + struct work_struct sc_offline_work; ++ uint8_t security_service_state; + + /* Vport Config Parameters */ + uint32_t cfg_scan_down; +diff -urpN a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c 2008-12-16 16:01:42.378088000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c 2008-12-16 16:01:42.668088000 -0500 +@@ -1010,7 +1010,7 @@ lpfc_mbx_cmpl_local_config_link(struct l + * LPFC_FLOGI while waiting for FLOGI cmpl + */ + if ((vport->cfg_enable_auth) && +- (lpfc_security_service_state == SECURITY_OFFLINE)) ++ (vport->security_service_state == SECURITY_OFFLINE)) + lpfc_issue_clear_la(phba, vport); + else if (vport->port_state != LPFC_FLOGI) + lpfc_initial_flogi(vport); +diff -urpN a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +--- a/drivers/scsi/lpfc/lpfc_init.c 2008-12-16 16:01:42.403088000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_init.c 2008-12-16 16:01:42.693090000 -0500 +@@ -549,14 +549,9 @@ lpfc_config_port_post(struct lpfc_hba *p + mempool_free(pmb, phba->mbox_mem_pool); + } + +- if (vport->cfg_enable_auth) { +- if (lpfc_security_service_state == SECURITY_OFFLINE) { +- lpfc_printf_log(vport->phba, KERN_ERR, LOG_SECURITY, +- "1000 Authentication is enabled but " +- "authentication service is not running\n"); ++ if (vport->cfg_enable_auth && ++ vport->security_service_state == SECURITY_OFFLINE) + vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; +- } +- } + + /* Allocate new MBOX buffer, will be freed in mbox compl */ + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); +@@ -2124,6 +2119,7 @@ lpfc_create_port(struct lpfc_hba *phba, + INIT_WORK(&vport->sc_offline_work, lpfc_fc_sc_security_offline); + INIT_LIST_HEAD(&vport->sc_users); + INIT_LIST_HEAD(&vport->sc_response_wait_queue); ++ vport->security_service_state = SECURITY_OFFLINE; + + spin_lock_irq(&phba->hbalock); + list_add_tail(&vport->listentry, &phba->port_list); +@@ -2904,19 +2900,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + + shost = lpfc_shost_from_vport(vport); + +- if ((lpfc_get_security_enabled)(shost)) { +- unsigned long flags; +- spin_lock_irqsave(&fc_security_user_lock, flags); +- list_add_tail(&vport->sc_users, &fc_security_user_list); +- spin_unlock_irqrestore(&fc_security_user_lock, flags); +- if (fc_service_state == FC_SC_SERVICESTATE_ONLINE) { +- lpfc_fc_queue_security_work(vport, +- &vport->sc_online_work); +- } +- /* Triggers fcauthd to register if it is running */ +- fc_host_post_event(shost, fc_get_event_number(), +- FCH_EVT_PORT_ONLINE, shost->host_no); +- } + phba->pport = vport; + lpfc_debugfs_initialize(vport); + +@@ -2990,6 +2973,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + } + } + ++ if ((lpfc_get_security_enabled)(shost)) { ++ unsigned long flags; ++ spin_lock_irqsave(&fc_security_user_lock, flags); ++ list_add_tail(&vport->sc_users, &fc_security_user_list); ++ spin_unlock_irqrestore(&fc_security_user_lock, flags); ++ /* Triggers fcauthd to register if it is running */ ++ fc_host_post_event(shost, fc_get_event_number(), ++ FCH_EVT_PORT_ONLINE, shost->host_no); ++ } + /* + * hba setup may have changed the hba_queue_depth so we need to adjust + * the value of can_queue. +diff -urpN a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c +--- a/drivers/scsi/lpfc/lpfc_security.c 2008-12-16 16:01:42.464088000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_security.c 2008-12-16 16:01:42.808089000 -0500 +@@ -36,14 +36,12 @@ + #include "lpfc_auth_access.h" + #include "lpfc_vport.h" + +-uint8_t lpfc_security_service_state = SECURITY_OFFLINE; +- + void + lpfc_security_service_online(struct Scsi_Host *shost) + { + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + +- lpfc_security_service_state = SECURITY_ONLINE; ++ vport->security_service_state = SECURITY_ONLINE; + if (vport->cfg_enable_auth && + vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN) + lpfc_selective_reset(vport->phba); +@@ -52,7 +50,9 @@ lpfc_security_service_online(struct Scsi + void + lpfc_security_service_offline(struct Scsi_Host *shost) + { +- lpfc_security_service_state = SECURITY_OFFLINE; ++ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; ++ ++ vport->security_service_state = SECURITY_OFFLINE; + } + + void +@@ -185,21 +185,21 @@ lpfc_get_security_enabled(struct Scsi_Ho + } + + int +-lpfc_security_wait(struct lpfc_hba *phba) ++lpfc_security_wait(struct lpfc_vport *vport) + { + int i = 0; +- if (lpfc_security_service_state == SECURITY_ONLINE) ++ if (vport->security_service_state == SECURITY_ONLINE) + return 0; +- lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY, ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, + "1058 Waiting for authentication service...\n"); +- while (lpfc_security_service_state == SECURITY_OFFLINE) { ++ while (vport->security_service_state == SECURITY_OFFLINE) { + i++; + if (i > SECURITY_WAIT_TMO * 2) + return -ETIMEDOUT; + /* Delay for half of a second */ + msleep(500); + } +- lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY, ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, + "1059 Authentication service online.\n"); + return 0; + } +@@ -310,7 +310,7 @@ lpfc_get_auth_config(struct lpfc_nodelis + auth_req.remote_wwpn = AUTH_FABRIC_WWN; + else + auth_req.remote_wwpn = wwn_to_u64(rwwn->u.wwn); +- if (lpfc_security_service_state == SECURITY_OFFLINE) { ++ if (vport->security_service_state == SECURITY_OFFLINE) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, + "1053 Start Authentication: " + "Security service offline.\n"); +diff -urpN a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +--- a/drivers/scsi/lpfc/lpfc_version.h 2008-12-16 16:01:42.512089000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_version.h 2008-12-16 16:01:42.835094000 -0500 +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.9" ++#define LPFC_DRIVER_VERSION "8.2.8.10" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.11-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.11-update new file mode 100644 index 000000000..6b75c4143 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.11-update @@ -0,0 +1,489 @@ +From: Jamie Wellnitz +Subject: Update lpfc from 8.2.8.10 to 8.2.8.11 +References: bnc#464662 + +Changes from 8.2.8.10 to 8.2.8.11: + +* Changed version number to 8.2.8.11 +* Implemented host memory based HGP pointers (CR 87327) +* Removed de-reference of scsi device after scsi_done is called + (CR 87269) +* Fixed system panic due to ndlp indirect reference to phba through + vport (CR 86370) +* Fixed nodelist not empty when unloading the driver after target + reboot test (CR 86213) +* Fixed a panic in mailbox timeout handler (CR 85228) + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke + +-- +diff -urpN a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +--- a/drivers/scsi/lpfc/lpfc_attr.c 2009-01-08 16:17:47.894022000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_attr.c 2009-01-08 16:17:48.134023000 -0500 +@@ -2277,6 +2277,16 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1 + "Max number of FCP commands we can queue to a specific LUN"); + + /* ++# hostmem_hgp: This parameter is used to force driver to keep host group ++# pointers in host memory. When the parameter is set to zero, the driver ++# keeps the host group pointers in HBA memory otherwise the host group ++# pointers are kept in the host memory. Value range is [0,1]. Default value ++# is 0. ++*/ ++LPFC_ATTR_R(hostmem_hgp, 0, 0, 1, ++ "Use host memory for host group pointers."); ++ ++/* + # hba_queue_depth: This parameter is used to limit the number of outstanding + # commands per lpfc HBA. Value range is [32,8192]. If this parameter + # value is greater than the maximum number of exchanges supported by the HBA, +@@ -3191,6 +3201,7 @@ struct device_attribute *lpfc_hba_attrs[ + &dev_attr_lpfc_sg_seg_cnt, + &dev_attr_lpfc_max_scsicmpl_time, + &dev_attr_lpfc_stat_data_ctrl, ++ &dev_attr_lpfc_hostmem_hgp, + NULL, + }; + +@@ -4881,6 +4892,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) + lpfc_use_msi_init(phba, lpfc_use_msi); + lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); + lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); ++ lpfc_hostmem_hgp_init(phba, lpfc_hostmem_hgp); + phba->cfg_poll = lpfc_poll; + phba->cfg_soft_wwnn = 0L; + phba->cfg_soft_wwpn = 0L; +diff -urpN a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h +--- a/drivers/scsi/lpfc/lpfc_disc.h 2009-01-08 16:17:47.932022000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_disc.h 2009-01-08 16:17:48.172023000 -0500 +@@ -101,6 +101,7 @@ struct lpfc_nodelist { + + struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ + struct timer_list nlp_reauth_tmr; /* Used for re-authentication */ ++ struct lpfc_hba *phba; + struct fc_rport *rport; /* Corresponding FC transport + port structure */ + struct lpfc_vport *vport; +diff -urpN a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c +--- a/drivers/scsi/lpfc/lpfc_els.c 2009-01-08 16:17:47.955022000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_els.c 2009-01-08 16:17:48.195023000 -0500 +@@ -6978,7 +6978,7 @@ static void lpfc_fabric_abort_vport(stru + void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) + { + LIST_HEAD(completions); +- struct lpfc_hba *phba = ndlp->vport->phba; ++ struct lpfc_hba *phba = ndlp->phba; + struct lpfc_iocbq *tmp_iocb, *piocb; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + IOCB_t *cmd; +diff -urpN a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h +--- a/drivers/scsi/lpfc/lpfc.h 2009-01-08 16:17:47.958022000 -0500 ++++ b/drivers/scsi/lpfc/lpfc.h 2009-01-08 16:17:48.198024000 -0500 +@@ -634,6 +634,7 @@ struct lpfc_hba { + uint32_t cfg_enable_hba_reset; + uint32_t cfg_enable_hba_heartbeat; + uint32_t cfg_pci_max_read; ++ uint32_t cfg_hostmem_hgp; + + lpfc_vpd_t vpd; /* vital product data */ + +diff -urpN a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c 2009-01-08 16:17:47.970022000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c 2009-01-08 16:17:48.210025000 -0500 +@@ -120,7 +120,7 @@ lpfc_terminate_rport_io(struct fc_rport + return; + } + +- phba = ndlp->vport->phba; ++ phba = ndlp->phba; + + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, + "rport terminate: sid:x%x did:x%x flg:x%x", +@@ -1912,9 +1912,14 @@ lpfc_disable_node(struct lpfc_vport *vpo + * @vport: Pointer to Virtual Port object. + * @ndlp: Pointer to FC node object. + * @did: FC_ID of the node. +- * This function is always called when node object need to +- * be initialized. It initializes all the fields of the node +- * object. ++ * ++ * This function is always called when node object need to be initialized. ++ * It initializes all the fields of the node object. Although the reference ++ * to phba from @ndlp can be obtained indirectly through it's reference to ++ * @vport, a direct reference to phba is taken here by @ndlp. This is due ++ * to the life-span of the @ndlp might go beyond the existence of @vport as ++ * the final release of ndlp is determined by its reference count. And, the ++ * operation on @ndlp needs the reference to phba. + **/ + static inline void + lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, +@@ -1931,6 +1936,7 @@ lpfc_initialize_node(struct lpfc_vport * + ndlp->nlp_reauth_tmr.data = (unsigned long)ndlp; + ndlp->nlp_DID = did; + ndlp->vport = vport; ++ ndlp->phba = vport->phba; + ndlp->nlp_sid = NLP_NO_SID; + kref_init(&ndlp->kref); + NLP_INT_NODE_ACT(ndlp); +@@ -3268,7 +3274,7 @@ lpfc_nlp_release(struct kref *kref) + lpfc_nlp_remove(ndlp->vport, ndlp); + + /* clear the ndlp active flag for all release cases */ +- phba = ndlp->vport->phba; ++ phba = ndlp->phba; + spin_lock_irqsave(&phba->ndlp_lock, flags); + NLP_CLR_NODE_ACT(ndlp); + spin_unlock_irqrestore(&phba->ndlp_lock, flags); +@@ -3276,7 +3282,7 @@ lpfc_nlp_release(struct kref *kref) + /* free ndlp memory for final ndlp release */ + if (NLP_CHK_FREE_REQ(ndlp)) { + kfree(ndlp->lat_data); +- mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); ++ mempool_free(ndlp, ndlp->phba->nlp_mem_pool); + } + } + +@@ -3299,7 +3305,7 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) + * ndlp reference count that is in the process of being + * released. + */ +- phba = ndlp->vport->phba; ++ phba = ndlp->phba; + spin_lock_irqsave(&phba->ndlp_lock, flags); + if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { + spin_unlock_irqrestore(&phba->ndlp_lock, flags); +@@ -3335,7 +3341,7 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); +- phba = ndlp->vport->phba; ++ phba = ndlp->phba; + spin_lock_irqsave(&phba->ndlp_lock, flags); + /* Check the ndlp memory free acknowledge flag to avoid the + * possible race condition that kref_put got invoked again +diff -urpN a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +--- a/drivers/scsi/lpfc/lpfc_init.c 2009-01-08 16:17:48.011024000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_init.c 2009-01-08 16:17:48.260024000 -0500 +@@ -3087,8 +3087,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev + + lpfc_free_sysfs_attr(vport); + +- kthread_stop(phba->worker_thread); +- + /* Release all the vports against this physical port */ + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) +@@ -3106,7 +3104,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev + * clears the rings, discards all mailbox commands, and resets + * the HBA. + */ ++ ++ /* HBA interrupt will be diabled after this call */ + lpfc_sli_hba_down(phba); ++ /* Stop kthread signal shall trigger work_done one more time */ ++ kthread_stop(phba->worker_thread); ++ /* Final cleanup of txcmplq and reset the HBA */ + lpfc_sli_brdrestart(phba); + + lpfc_stop_phba_timers(phba); +diff -urpN a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c +--- a/drivers/scsi/lpfc/lpfc_mbox.c 2009-01-08 16:17:48.031024000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_mbox.c 2009-01-08 16:17:48.281022000 -0500 +@@ -1127,9 +1127,6 @@ lpfc_config_port(struct lpfc_hba *phba, + mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); + mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); + +- /* Always Host Group Pointer is in SLIM */ +- mb->un.varCfgPort.hps = 1; +- + /* If HBA supports SLI=3 ask for it */ + + if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) { +@@ -1208,28 +1205,41 @@ lpfc_config_port(struct lpfc_hba *phba, + * + */ + +- if (phba->sli_rev == 3) { +- phba->host_gp = &mb_slim->us.s3.host[0]; +- phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; +- } else { +- phba->host_gp = &mb_slim->us.s2.host[0]; ++ if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) { ++ phba->host_gp = &phba->mbox->us.s2.host[0]; + phba->hbq_put = NULL; +- } ++ offset = (uint8_t *)&phba->mbox->us.s2.host - ++ (uint8_t *)phba->slim2p.virt; ++ pdma_addr = phba->slim2p.phys + offset; ++ phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr); ++ phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr); ++ } else { ++ /* Always Host Group Pointer is in SLIM */ ++ mb->un.varCfgPort.hps = 1; + +- /* mask off BAR0's flag bits 0 - 3 */ +- phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + +- (void __iomem *)phba->host_gp - +- (void __iomem *)phba->MBslimaddr; +- if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) +- phba->pcb->hgpAddrHigh = bar_high; +- else +- phba->pcb->hgpAddrHigh = 0; +- /* write HGP data to SLIM at the required longword offset */ +- memset(&hgp, 0, sizeof(struct lpfc_hgp)); ++ if (phba->sli_rev == 3) { ++ phba->host_gp = &mb_slim->us.s3.host[0]; ++ phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; ++ } else { ++ phba->host_gp = &mb_slim->us.s2.host[0]; ++ phba->hbq_put = NULL; ++ } ++ ++ /* mask off BAR0's flag bits 0 - 3 */ ++ phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + ++ (void __iomem *)phba->host_gp - ++ (void __iomem *)phba->MBslimaddr; ++ if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) ++ phba->pcb->hgpAddrHigh = bar_high; ++ else ++ phba->pcb->hgpAddrHigh = 0; ++ /* write HGP data to SLIM at the required longword offset */ ++ memset(&hgp, 0, sizeof(struct lpfc_hgp)); + +- for (i=0; i < phba->sli.num_rings; i++) { +- lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, ++ for (i = 0; i < phba->sli.num_rings; i++) { ++ lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, + sizeof(*phba->host_gp)); ++ } + } + + /* Setup Port Group offset */ +diff -urpN a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c +--- a/drivers/scsi/lpfc/lpfc_scsi.c 2009-01-08 16:17:48.061026000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_scsi.c 2009-01-08 16:17:48.310022000 -0500 +@@ -198,14 +198,14 @@ lpfc_rampdown_queue_depth(struct lpfc_hb + */ + static inline void + lpfc_rampup_queue_depth(struct lpfc_vport *vport, +- struct scsi_device *sdev) ++ uint32_t queue_depth) + { + unsigned long flags; + struct lpfc_hba *phba = vport->phba; + uint32_t evt_posted; + atomic_inc(&phba->num_cmd_success); + +- if (vport->cfg_lun_queue_depth <= sdev->queue_depth) ++ if (vport->cfg_lun_queue_depth <= queue_depth) + return; + spin_lock_irqsave(&phba->hbalock, flags); + if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) || +@@ -849,10 +849,12 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + struct lpfc_nodelist *pnode = rdata->pnode; + struct scsi_cmnd *cmd = lpfc_cmd->pCmd; + int result; +- struct scsi_device *sdev, *tmp_sdev; ++ struct scsi_device *tmp_sdev; + int depth = 0; + unsigned long flags; + struct lpfc_fast_path_event *fast_path_evt; ++ struct Scsi_Host *shost = cmd->device->host; ++ uint32_t queue_depth, scsi_id; + + lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; + lpfc_cmd->status = pIocbOut->iocb.ulpStatus; +@@ -942,11 +944,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + + lpfc_update_stats(phba, lpfc_cmd); + result = cmd->result; +- sdev = cmd->device; + if (vport->cfg_max_scsicmpl_time && + time_after(jiffies, lpfc_cmd->start_time + + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { +- spin_lock_irqsave(sdev->host->host_lock, flags); ++ spin_lock_irqsave(shost->host_lock, flags); + if (pnode && NLP_CHK_NODE_ACT(pnode)) { + if (pnode->cmd_qdepth > + atomic_read(&pnode->cmd_pending) && +@@ -959,22 +960,26 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + + pnode->last_change_time = jiffies; + } +- spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ spin_unlock_irqrestore(shost->host_lock, flags); + } else if (pnode && NLP_CHK_NODE_ACT(pnode)) { + if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && + time_after(jiffies, pnode->last_change_time + + msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { +- spin_lock_irqsave(sdev->host->host_lock, flags); ++ spin_lock_irqsave(shost->host_lock, flags); + pnode->cmd_qdepth += pnode->cmd_qdepth * + LPFC_TGTQ_RAMPUP_PCENT / 100; + if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) + pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; + pnode->last_change_time = jiffies; +- spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ spin_unlock_irqrestore(shost->host_lock, flags); + } + } + + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); ++ ++ /* The sdev is not guaranteed to be valid post scsi_done upcall. */ ++ queue_depth = cmd->device->queue_depth; ++ scsi_id = cmd->device->id; + cmd->scsi_done(cmd); + + if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { +@@ -982,28 +987,28 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + * If there is a thread waiting for command completion + * wake up the thread. + */ +- spin_lock_irqsave(sdev->host->host_lock, flags); ++ spin_lock_irqsave(shost->host_lock, flags); + lpfc_cmd->pCmd = NULL; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); +- spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ spin_unlock_irqrestore(shost->host_lock, flags); + lpfc_release_scsi_buf(phba, lpfc_cmd); + return; + } + + + if (!result) +- lpfc_rampup_queue_depth(vport, sdev); ++ lpfc_rampup_queue_depth(vport, queue_depth); + + if (!result && pnode && NLP_CHK_NODE_ACT(pnode) && + ((jiffies - pnode->last_ramp_up_time) > + LPFC_Q_RAMP_UP_INTERVAL * HZ) && + ((jiffies - pnode->last_q_full_time) > + LPFC_Q_RAMP_UP_INTERVAL * HZ) && +- (vport->cfg_lun_queue_depth > sdev->queue_depth)) { +- shost_for_each_device(tmp_sdev, sdev->host) { ++ (vport->cfg_lun_queue_depth > queue_depth)) { ++ shost_for_each_device(tmp_sdev, shost) { + if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){ +- if (tmp_sdev->id != sdev->id) ++ if (tmp_sdev->id != scsi_id) + continue; + if (tmp_sdev->ordered_tags) + scsi_adjust_queue_depth(tmp_sdev, +@@ -1019,7 +1024,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + } + lpfc_send_sdev_queuedepth_change_event(phba, vport, pnode, + 0xFFFFFFFF, +- sdev->queue_depth - 1, sdev->queue_depth); ++ queue_depth , queue_depth + 1); + } + + /* +@@ -1030,8 +1035,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + NLP_CHK_NODE_ACT(pnode)) { + pnode->last_q_full_time = jiffies; + +- shost_for_each_device(tmp_sdev, sdev->host) { +- if (tmp_sdev->id != sdev->id) ++ shost_for_each_device(tmp_sdev, shost) { ++ if (tmp_sdev->id != scsi_id) + continue; + depth = scsi_track_queue_full(tmp_sdev, + tmp_sdev->queue_depth - 1); +@@ -1043,7 +1048,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + * scsi_track_queue_full. + */ + if (depth == -1) +- depth = sdev->host->cmd_per_lun; ++ depth = shost->cmd_per_lun; + + if (depth) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, +@@ -1059,11 +1064,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba + * If there is a thread waiting for command completion + * wake up the thread. + */ +- spin_lock_irqsave(sdev->host->host_lock, flags); ++ spin_lock_irqsave(shost->host_lock, flags); + lpfc_cmd->pCmd = NULL; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); +- spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ spin_unlock_irqrestore(shost->host_lock, flags); + + lpfc_release_scsi_buf(phba, lpfc_cmd); + } +diff -urpN a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c +--- a/drivers/scsi/lpfc/lpfc_security.c 2009-01-08 16:17:48.067023000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_security.c 2009-01-08 16:17:48.316022000 -0500 +@@ -230,7 +230,7 @@ lpfc_reauth_node(unsigned long ptr) + struct lpfc_work_evt *evtp = &ndlp->els_reauth_evt; + + ndlp = (struct lpfc_nodelist *) ptr; +- phba = ndlp->vport->phba; ++ phba = ndlp->phba; + + spin_lock_irqsave(&phba->hbalock, flags); + if (!list_empty(&evtp->evt_listp)) { +diff -urpN a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +--- a/drivers/scsi/lpfc/lpfc_sli.c 2009-01-08 16:17:48.087024000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_sli.c 2009-01-08 16:17:48.335025000 -0500 +@@ -3327,6 +3327,21 @@ lpfc_mbox_timeout_handler(struct lpfc_hb + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + ++ /* Check the pmbox pointer first. There is a race condition ++ * between the mbox timeout handler getting executed in the ++ * worklist and the mailbox actually completing. When this ++ * race condition occurs, the mbox_active will be NULL. ++ */ ++ spin_lock_irq(&phba->hbalock); ++ if (pmbox == NULL) { ++ lpfc_printf_log(phba, KERN_WARNING, ++ LOG_MBOX | LOG_SLI, ++ "0353 Active Mailbox cleared - mailbox timeout " ++ "exiting\n"); ++ spin_unlock_irq(&phba->hbalock); ++ return; ++ } ++ + /* Mbox cmd timeout */ + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0310 Mailbox command x%x timeout Data: x%x x%x x%p\n", +@@ -3334,6 +3349,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hb + phba->pport->port_state, + phba->sli.sli_flag, + phba->sli.mbox_active); ++ spin_unlock_irq(&phba->hbalock); + + /* Setting state unknown so lpfc_sli_abort_iocb_ring + * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing +diff -urpN a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +--- a/drivers/scsi/lpfc/lpfc_version.h 2009-01-08 16:17:48.093023000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_version.h 2009-01-08 16:17:48.341024000 -0500 +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2004-2008 Emulex. All rights reserved. * ++ * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.10" ++#define LPFC_DRIVER_VERSION "8.2.8.11" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" +@@ -26,4 +26,4 @@ + + #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ + LPFC_DRIVER_VERSION +-#define LPFC_COPYRIGHT "Copyright(c) 2004-2008 Emulex. All rights reserved." ++#define LPFC_COPYRIGHT "Copyright(c) 2004-2009 Emulex. All rights reserved." diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.12-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.12-update new file mode 100644 index 000000000..9c925f2b3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.12-update @@ -0,0 +1,99 @@ +From: Jamie Wellnitz +Subject: Update lpfc from 8.2.8.11 to 8.2.8.12 +References: bnc#467713 + +lpfc 8.2.8.12 fixes a few bugs found in our qual cycle on SLES 11 RC2: + +* Changed version number to 8.2.8.12 +* Fixed bug with sysfs fc_host WWNs not being updated after changing the WWNs +(CR 87391) +* Increased HBQ buffers to support 40KB SSC sequences (CR 86564) +* Fixed a kernel panic while trying to delete authentication timer (CR 87144) + + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke +-- +diff -urpN a/drivers/scsi/lpfc/lpfc_auth_access.c b/drivers/scsi/lpfc/lpfc_auth_access.c +--- a/drivers/scsi/lpfc/lpfc_auth_access.c 2009-01-20 13:31:08.517461000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_auth_access.c 2009-01-20 13:31:08.600460000 -0500 +@@ -223,6 +223,9 @@ lpfc_fc_sc_request(struct lpfc_vport *vp + memcpy(fc_nl_sc_msg->data, auth_req, auth_req_len); + fc_nl_sc_msg->tran_id = seq; + ++ lpfc_fc_sc_add_timer(fc_sc_req, FC_SC_REQ_TIMEOUT, ++ lpfc_fc_sc_req_times_out); ++ + spin_lock_irqsave(shost->host_lock, flags); + list_add_tail(&fc_sc_req->rlist, &vport->sc_response_wait_queue); + spin_unlock_irqrestore(shost->host_lock, flags); +@@ -230,8 +233,6 @@ lpfc_fc_sc_request(struct lpfc_vport *vp + (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX), + (char *) fc_nl_sc_msg, len); + kfree(fc_nl_sc_msg); +- lpfc_fc_sc_add_timer(fc_sc_req, FC_SC_REQ_TIMEOUT, +- lpfc_fc_sc_req_times_out); + return 0; + } + +diff -urpN a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +--- a/drivers/scsi/lpfc/lpfc_init.c 2009-01-20 13:31:08.554460000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_init.c 2009-01-20 13:31:08.640460000 -0500 +@@ -332,6 +332,7 @@ int + lpfc_config_port_post(struct lpfc_hba *phba) + { + struct lpfc_vport *vport = phba->pport; ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + LPFC_MBOXQ_t *pmb; + MAILBOX_t *mb; + struct lpfc_dmabuf *mp; +@@ -389,6 +390,11 @@ lpfc_config_port_post(struct lpfc_hba *p + sizeof (struct lpfc_name)); + memcpy(&vport->fc_portname, &vport->fc_sparam.portName, + sizeof (struct lpfc_name)); ++ ++ /* Update the fc_host data structures with new wwn. */ ++ fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); ++ fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); ++ + /* If no serial number in VPD data, use low 6 bytes of WWNN */ + /* This should be consolidated into parse_vpd ? - mr */ + if (phba->SerialNumber[0] == 0) { +@@ -1765,8 +1771,10 @@ lpfc_stop_vport_timers(struct lpfc_vport + del_timer_sync(&vport->els_tmofunc); + del_timer_sync(&vport->fc_fdmitmo); + while (!list_empty(&vport->sc_response_wait_queue)) { +- fc_sc_req = list_get_first(&vport->sc_response_wait_queue, ++ list_remove_head(&vport->sc_response_wait_queue, fc_sc_req, + struct fc_security_request, rlist); ++ if (!fc_sc_req) ++ continue; + del_timer_sync(&fc_sc_req->timer); + kfree(fc_sc_req); + } +diff -urpN a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +--- a/drivers/scsi/lpfc/lpfc_sli.c 2009-01-20 13:31:08.580458000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_sli.c 2009-01-20 13:31:08.665462000 -0500 +@@ -817,8 +817,8 @@ static struct lpfc_hbq_init lpfc_els_hbq + .profile = 0, + .ring_mask = (1 << LPFC_ELS_RING), + .buffer_count = 0, +- .init_count = 20, +- .add_count = 5, ++ .init_count = 40, ++ .add_count = 40, + }; + + /* HBQ for the extra ring if needed */ +diff -urpN a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +--- a/drivers/scsi/lpfc/lpfc_version.h 2009-01-20 13:31:08.583459000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_version.h 2009-01-20 13:31:08.668462000 -0500 +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.11" ++#define LPFC_DRIVER_VERSION "8.2.8.12" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.13-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.13-update new file mode 100644 index 000000000..743bc910c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.13-update @@ -0,0 +1,196 @@ +From: Laurie Barry +Subject: Update lpfc from 8.2.8.12 to 8.2.8.13 +References: bnc#472608 + +lpfc 8.2.8.13 fixes a few bugs found in our qual cycle on SLES 11 RC3: + +* Changed version number to 8.2.8.13 +* Added sysfs interface to update speed and topology parameter without link +bounce (CR 87013) +* Fixed loopback test failure (CR 87414) + +Acked-by: Hannes Reinecke + +-- +diff -urpN a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +--- a/drivers/scsi/lpfc/lpfc_attr.c 2009-02-04 11:14:24.143349000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_attr.c 2009-02-04 11:14:24.291344000 -0500 +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2004-2008 Emulex. All rights reserved. * ++ * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * Portions Copyright (C) 2004-2005 Christoph Hellwig * +@@ -2449,18 +2449,41 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1, + * non-zero return value from lpfc_issue_lip() + * -EINVAL val out of range + **/ +-static int +-lpfc_topology_set(struct lpfc_hba *phba, int val) ++static ssize_t ++lpfc_topology_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) + { ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ int val = 0; ++ int nolip = 0; ++ const char *val_buf = buf; + int err; + uint32_t prev_val; ++ ++ if (!strncmp(buf, "nolip ", strlen("nolip "))) { ++ nolip = 1; ++ val_buf = &buf[strlen("nolip ")]; ++ } ++ ++ if (!isdigit(val_buf[0])) ++ return -EINVAL; ++ if (sscanf(val_buf, "%i", &val) != 1) ++ return -EINVAL; ++ + if (val >= 0 && val <= 6) { + prev_val = phba->cfg_topology; + phba->cfg_topology = val; ++ if (nolip) ++ return strlen(buf); ++ + err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); +- if (err) ++ if (err) { + phba->cfg_topology = prev_val; +- return err; ++ return -EINVAL; ++ } else ++ return strlen(buf); + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "%d:0467 lpfc_topology attribute cannot be set to %d, " +@@ -2473,7 +2496,6 @@ module_param(lpfc_topology, int, 0); + MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology"); + lpfc_param_show(topology) + lpfc_param_init(topology, 0, 0, 6) +-lpfc_param_store(topology) + static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, + lpfc_topology_show, lpfc_topology_store); + +@@ -2834,12 +2856,29 @@ static struct bin_attribute sysfs_drvr_s + * non-zero return value from lpfc_issue_lip() + * -EINVAL val out of range + **/ +-static int +-lpfc_link_speed_set(struct lpfc_hba *phba, int val) ++static ssize_t ++lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) + { ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_hba *phba = vport->phba; ++ int val = 0; ++ int nolip = 0; ++ const char *val_buf = buf; + int err; + uint32_t prev_val; + ++ if (!strncmp(buf, "nolip ", strlen("nolip "))) { ++ nolip = 1; ++ val_buf = &buf[strlen("nolip ")]; ++ } ++ ++ if (!isdigit(val_buf[0])) ++ return -EINVAL; ++ if (sscanf(val_buf, "%i", &val) != 1) ++ return -EINVAL; ++ + if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) || + ((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) || + ((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || +@@ -2847,14 +2886,19 @@ lpfc_link_speed_set(struct lpfc_hba *phb + ((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb))) + return -EINVAL; + +- if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED) ++ if ((val >= 0 && val <= 8) + && (LPFC_LINK_SPEED_BITMAP & (1 << val))) { + prev_val = phba->cfg_link_speed; + phba->cfg_link_speed = val; ++ if (nolip) ++ return strlen(buf); ++ + err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); +- if (err) ++ if (err) { + phba->cfg_link_speed = prev_val; +- return err; ++ return -EINVAL; ++ } else ++ return strlen(buf); + } + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +@@ -2901,7 +2945,6 @@ lpfc_link_speed_init(struct lpfc_hba *ph + return -EINVAL; + } + +-lpfc_param_store(link_speed) + static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, + lpfc_link_speed_show, lpfc_link_speed_store); + +@@ -3981,6 +4024,10 @@ sysfs_mbox_read(struct kobject *kobj, st + (sysfs_mbox->mbox->mb.un.varWords[1] == 1)) { + wait_4_menlo_maint = 1; + phba->wait_4_mlo_maint_flg = 1; ++ } else if (sysfs_mbox->mbox->mb.un.varWords[0] == ++ SETVAR_MLORST) { ++ phba->link_flag &= ~LS_LOOPBACK_MODE; ++ phba->fc_topology = TOPOLOGY_PT_PT; + } + break; + case MBX_RUN_BIU_DIAG64: +diff -urpN a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c +--- a/drivers/scsi/lpfc/lpfc_els.c 2009-02-04 11:14:24.218344000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_els.c 2009-02-04 11:14:24.311341000 -0500 +@@ -2514,8 +2514,10 @@ lpfc_els_retry(struct lpfc_hba *phba, st + switch ((irsp->un.ulpWord[4] & 0xff)) { + case IOERR_LOOP_OPEN_FAILURE: + if (cmd == ELS_CMD_FLOGI) { +- if (PCI_DEVICE_ID_HORNET == +- phba->pcidev->device) { ++ if ((PCI_DEVICE_ID_HORNET == ++ phba->pcidev->device) ++ && phba->link_flag == ++ LS_LOOPBACK_MODE) { + phba->fc_topology = TOPOLOGY_LOOP; + phba->pport->fc_myDID = 0; + phba->alpa_map[0] = 0; +diff -urpN a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c 2009-02-04 11:14:24.223338000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c 2009-02-04 11:14:24.315342000 -0500 +@@ -2574,6 +2574,10 @@ lpfc_disc_list_loopmap(struct lpfc_vport + if (phba->fc_topology != TOPOLOGY_LOOP) + return; + ++ if ((PCI_DEVICE_ID_HORNET == phba->pcidev->device) ++ && (phba->link_flag & LS_LOOPBACK_MODE)) ++ return; ++ + /* Check for loop map present or not */ + if (phba->alpa_map[0]) { + for (j = 1; j <= phba->alpa_map[0]; j++) { +diff -urpN a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +--- a/drivers/scsi/lpfc/lpfc_version.h 2009-02-04 11:14:24.270343000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_version.h 2009-02-04 11:14:24.351338000 -0500 +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.12" ++#define LPFC_DRIVER_VERSION "8.2.8.13" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.14-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.14-update new file mode 100644 index 000000000..1e43f528a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.14-update @@ -0,0 +1,165 @@ +From: Jamie Wellnitz +Subject: Disable MSI by default in lpfc driver +References: bnc#477843 + +Update lpfc from 8.2.8.13 to 8.2.8.14 + +We (Emulex) have seen too many MSI/MSI-X issues to be comfortable at this +stage, so we've decided to revert lpfc to using INTx interrupts by default and +allowing MSI or MSI-X to be enabled with the lpfc_use_msi driver parameter. + +We will also include a change to only test MSI-X and MSI interrupts in the +interrupt method failback logic. This way, lpfc will not fail port +initialization if the first few INTx interrupts are slow to arrive. Lpfc will +still verify MSI/MSI-X interrupts are actually delivered before continuing port +initialization. + +Signed-off-by: Hannes Reinecke + +-- +diff -urpN a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +--- a/drivers/scsi/lpfc/lpfc_attr.c 2009-02-19 17:49:17.668021000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_attr.c 2009-02-19 17:49:17.761982000 -0500 +@@ -3080,12 +3080,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, + /* + # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that + # support this feature +-# 0 = MSI disabled ++# 0 = MSI disabled (default) + # 1 = MSI enabled +-# 2 = MSI-X enabled (default) +-# Value range is [0,2]. Default value is 2. ++# 2 = MSI-X enabled ++# Value range is [0,2]. Default value is 0. + */ +-LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " ++LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " + "MSI-X (2), if possible"); + + /* +diff -urpN a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c 2009-02-19 17:49:17.697993000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c 2009-02-19 17:49:17.792982000 -0500 +@@ -2246,9 +2246,13 @@ lpfc_unreg_all_rpis(struct lpfc_vport *v + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); +- if (rc == MBX_NOT_FINISHED) { ++ if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); +- } ++ ++ if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, ++ "1836 Could not issue " ++ "unreg_login(all_rpis) status %d\n", rc); + } + } + +@@ -2266,12 +2270,14 @@ lpfc_unreg_default_rpis(struct lpfc_vpor + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); +- if (rc == MBX_NOT_FINISHED) { ++ if (rc != MBX_TIMEOUT) ++ mempool_free(mbox, phba->mbox_mem_pool); ++ ++ if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) + lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, + "1815 Could not issue " +- "unreg_did (default rpis)\n"); +- mempool_free(mbox, phba->mbox_mem_pool); +- } ++ "unreg_did (default rpis) status %d\n", ++ rc); + } + } + +diff -urpN a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +--- a/drivers/scsi/lpfc/lpfc_init.c 2009-02-19 17:49:17.710980000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_init.c 2009-02-19 17:49:17.817984000 -0500 +@@ -1355,7 +1355,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba + m = (typeof(m)){"LPe11000", max_speed, "PCIe"}; + break; + case PCI_DEVICE_ID_ZEPHYR_DCSP: +- m = (typeof(m)){"LPe11002-SP", max_speed, "PCIe"}; ++ m = (typeof(m)){"LP2105", max_speed, "PCIe"}; ++ GE = 1; + break; + case PCI_DEVICE_ID_ZMID: + m = (typeof(m)){"LPe1150", max_speed, "PCIe"}; +@@ -2954,8 +2955,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + + /* Wait 50ms for the interrupts of previous mailbox commands */ + msleep(50); +- /* Check active interrupts received */ +- if (phba->sli.slistat.sli_intr > LPFC_INTR_THRESHOLD) { ++ /* Check active interrupts received only for MSI/MSI-X */ ++ if (phba->sli.slistat.sli_intr > LPFC_INTR_THRESHOLD || ++ intr_mode == 0) { + /* Log the current active interrupt mode */ + phba->intr_mode = intr_mode; + lpfc_log_intr_mode(phba, intr_mode); +@@ -2965,13 +2967,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, + "0451 Configure interrupt mode (%d) " + "failed active interrupt test.\n", + intr_mode); +- if (intr_mode == 0) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0479 Failed to enable " +- "interrupt.\n"); +- error = -ENODEV; +- goto out_remove_device; +- } + /* Stop HBA SLI setups */ + lpfc_stop_port(phba); + /* Disable the current interrupt mode */ +diff -urpN a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +--- a/drivers/scsi/lpfc/lpfc_sli.c 2009-02-19 17:49:17.741980000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_sli.c 2009-02-19 17:49:17.845982000 -0500 +@@ -4031,6 +4031,7 @@ lpfc_sli_async_event_handler(struct lpfc + uint16_t temp; + struct temp_event temp_event_data; + struct Scsi_Host *shost; ++ uint32_t *iocb_w; + + icmd = &iocbq->iocb; + evt_code = icmd->un.asyncstat.evt_code; +@@ -4038,13 +4039,23 @@ lpfc_sli_async_event_handler(struct lpfc + + if ((evt_code != ASYNC_TEMP_WARN) && + (evt_code != ASYNC_TEMP_SAFE)) { ++ iocb_w = (uint32_t *) icmd; + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0346 Ring %d handler: unexpected ASYNC_STATUS" +- " evt_code 0x%x\n", ++ " evt_code 0x%x \n" ++ "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" ++ "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" ++ "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" ++ "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", + pring->ringno, +- icmd->un.asyncstat.evt_code); ++ icmd->un.asyncstat.evt_code, ++ iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], ++ iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], ++ iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], ++ iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); ++ + return; + } + temp_event_data.data = (uint32_t)temp; +diff -urpN a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +--- a/drivers/scsi/lpfc/lpfc_version.h 2009-02-19 17:49:17.744980000 -0500 ++++ b/drivers/scsi/lpfc/lpfc_version.h 2009-02-19 17:49:17.848982000 -0500 +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.13" ++#define LPFC_DRIVER_VERSION "8.2.8.14" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.3-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.3-update new file mode 100644 index 000000000..e4b57fd2f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.3-update @@ -0,0 +1,1355 @@ +From: Jamie Wellnitz +Subject: Update lpfc to 8.2.8.3 +References: bnc#420767 + +This patch updates the SLES 11 inbox lpfc driver to 8.2.8.3 which has several +changes, mainly bugfixes: + + * Changed version number to 8.2.8.3 + * Resolved uninitialized node access (CR 83287) + * Fixed failing ioctl commands (CR 83850) + * Cosmetic coding style clean up + * Fix echotest failure when NPIV is enabled (CR 75009) + * Fixed Port busy events + * Back out slow vports fix (CR 83103) + * Added a vendor unique RSCN event to send entire payload to mgmt application + * Fixed internal loopback Hornet hardware (CR 83323) + * Fixed sysfs write handler for mailbox interface (CR 83674) + * Implement driver support for Power Management Suspend/Resume operations (CR + 74378) + * Changed version number to 8.2.8.2 + * Added data structures required for new events. + * Streamlined interrupt enable/disable logic into helper routines + * Fixed incorrect decrement of cmd_pending count. (CR 83286) + * Fixed internal and external loopback on Hornet. (CR 83323) + * Removed unnecessary sleeps during HBA initialization. (CR 82846) + * Fixed RSCN address format not handled properly. (CR 82252) + * Fixed unload driver with vports locks up driver (CR 83334) + * Avoid polling HBA Error Attention when HBA's PCI channel is offline + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +index 273aa4f..8e94902 100644 +--- a/drivers/scsi/lpfc/lpfc_attr.c ++++ b/drivers/scsi/lpfc/lpfc_attr.c +@@ -3531,9 +3531,6 @@ sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr, + uint8_t *ext; + uint32_t size; + +- if ((count + off) > MAILBOX_CMD_SIZE) +- return -ERANGE; +- + if (off % 4 || count % 4 || (unsigned long)buf % 4) + return -EINVAL; + +diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +index 0c90479..a93c555 100644 +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -323,11 +323,10 @@ void lpfc_fabric_abort_nport(struct lpfc_nodelist *); + void lpfc_fabric_abort_hba(struct lpfc_hba *); + void lpfc_fabric_block_timeout(unsigned long); + void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); +-void lpfc_adjust_queue_depth(struct lpfc_hba *); ++void lpfc_rampdown_queue_depth(struct lpfc_hba *); + void lpfc_ramp_down_queue_handler(struct lpfc_hba *); + void lpfc_ramp_up_queue_handler(struct lpfc_hba *); + void lpfc_scsi_dev_block(struct lpfc_hba *); +-void lpfc_scsi_dev_rescan(struct lpfc_hba *); + + void + lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *, +diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c +index bce59ec..a95815e 100644 +--- a/drivers/scsi/lpfc/lpfc_els.c ++++ b/drivers/scsi/lpfc/lpfc_els.c +@@ -224,7 +224,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, + /* For ELS_REQUEST64_CR, use the VPI by default */ + icmd->ulpContext = vport->vpi; + icmd->ulpCt_h = 0; +- icmd->ulpCt_l = 1; ++ /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ ++ if (elscmd == ELS_CMD_ECHO) ++ icmd->ulpCt_l = 0; /* context = invalid RPI */ ++ else ++ icmd->ulpCt_l = 1; /* context = VPI */ + } + + bpl = (struct ulp_bde64 *) pbuflist->virt; +@@ -2504,6 +2508,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + case IOSTAT_LOCAL_REJECT: + switch ((irsp->un.ulpWord[4] & 0xff)) { + case IOERR_LOOP_OPEN_FAILURE: ++ if (cmd == ELS_CMD_FLOGI) { ++ if (PCI_DEVICE_ID_HORNET == ++ phba->pcidev->device) { ++ phba->fc_topology = TOPOLOGY_LOOP; ++ phba->pport->fc_myDID = 0; ++ phba->alpa_map[0] = 0; ++ phba->alpa_map[1] = 0; ++ } ++ } + if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0) + delay = 1000; + retry = 1; +@@ -3870,27 +3883,21 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) + while (payload_len) { + rscn_did.un.word = be32_to_cpu(*lp++); + payload_len -= sizeof(uint32_t); +- switch (rscn_did.un.b.resv) { +- case 0: /* Single N_Port ID effected */ ++ switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) { ++ case RSCN_ADDRESS_FORMAT_PORT: + if (ns_did.un.word == rscn_did.un.word) + goto return_did_out; + break; +- case 1: /* Whole N_Port Area effected */ ++ case RSCN_ADDRESS_FORMAT_AREA: + if ((ns_did.un.b.domain == rscn_did.un.b.domain) + && (ns_did.un.b.area == rscn_did.un.b.area)) + goto return_did_out; + break; +- case 2: /* Whole N_Port Domain effected */ ++ case RSCN_ADDRESS_FORMAT_DOMAIN: + if (ns_did.un.b.domain == rscn_did.un.b.domain) + goto return_did_out; + break; +- default: +- /* Unknown Identifier in RSCN node */ +- lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, +- "0217 Unknown Identifier in " +- "RSCN payload Data: x%x\n", +- rscn_did.un.word); +- case 3: /* Whole Fabric effected */ ++ case RSCN_ADDRESS_FORMAT_FABRIC: + goto return_did_out; + } + } +@@ -3934,6 +3941,49 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) + } + + /** ++ * lpfc_send_rscn_event: Send an RSCN event to management application. ++ * @vport: pointer to a host virtual N_Port data structure. ++ * @cmdiocb: pointer to lpfc command iocb data structure. ++ * ++ * lpfc_send_rscn_event sends an RSCN netlink event to management ++ * applications. ++ */ ++static void ++lpfc_send_rscn_event(struct lpfc_vport *vport, ++ struct lpfc_iocbq *cmdiocb) ++{ ++ struct lpfc_dmabuf *pcmd; ++ struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ++ uint32_t *payload_ptr; ++ uint32_t payload_len; ++ struct lpfc_rscn_event_header *rscn_event_data; ++ ++ pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; ++ payload_ptr = (uint32_t *) pcmd->virt; ++ payload_len = be32_to_cpu(*payload_ptr & ~ELS_CMD_MASK); ++ ++ rscn_event_data = kmalloc(sizeof(struct lpfc_rscn_event_header) + ++ payload_len, GFP_KERNEL); ++ if (!rscn_event_data) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ++ "0147 Failed to allocate memory for RSCN event\n"); ++ return; ++ } ++ rscn_event_data->event_type = FC_REG_RSCN_EVENT; ++ rscn_event_data->payload_length = payload_len; ++ memcpy(rscn_event_data->rscn_payload, payload_ptr, ++ payload_len); ++ ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(struct lpfc_els_event_header) + payload_len, ++ (char *)rscn_event_data, ++ LPFC_NL_VENDOR_ID); ++ ++ kfree(rscn_event_data); ++} ++ ++/** + * lpfc_els_rcv_rscn: Process an unsolicited rscn iocb. + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. +@@ -3980,6 +4030,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + "0214 RSCN received Data: x%x x%x x%x x%x\n", + vport->fc_flag, payload_len, *lp, + vport->fc_rscn_id_cnt); ++ ++ /* Send an RSCN event to the management application */ ++ lpfc_send_rscn_event(vport, cmdiocb); ++ + for (i = 0; i < payload_len/sizeof(uint32_t); i++) + fc_host_post_event(shost, fc_get_event_number(), + FCH_EVT_RSCN, lp[i]); +@@ -5532,7 +5586,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, + fc_get_event_number(), + sizeof(lsrjt_event), + (char *)&lsrjt_event, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + return; + } + if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) || +@@ -5550,7 +5604,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, + fc_get_event_number(), + sizeof(fabric_event), + (char *)&fabric_event, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + return; + } + +@@ -5568,32 +5622,68 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, + static void + lpfc_send_els_event(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, +- uint32_t cmd) ++ uint32_t *payload) + { +- struct lpfc_els_event_header els_data; ++ struct lpfc_els_event_header *els_data = NULL; ++ struct lpfc_logo_event *logo_data = NULL; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + +- els_data.event_type = FC_REG_ELS_EVENT; +- switch (cmd) { ++ if (*payload == ELS_CMD_LOGO) { ++ logo_data = kmalloc(sizeof(struct lpfc_logo_event), GFP_KERNEL); ++ if (!logo_data) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ++ "0148 Failed to allocate memory " ++ "for LOGO event\n"); ++ return; ++ } ++ els_data = &logo_data->header; ++ } else { ++ els_data = kmalloc(sizeof(struct lpfc_els_event_header), ++ GFP_KERNEL); ++ if (!els_data) { ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ++ "0149 Failed to allocate memory " ++ "for ELS event\n"); ++ return; ++ } ++ } ++ els_data->event_type = FC_REG_ELS_EVENT; ++ switch (*payload) { + case ELS_CMD_PLOGI: +- els_data.subcategory = LPFC_EVENT_PLOGI_RCV; ++ els_data->subcategory = LPFC_EVENT_PLOGI_RCV; + break; + case ELS_CMD_PRLO: +- els_data.subcategory = LPFC_EVENT_PRLO_RCV; ++ els_data->subcategory = LPFC_EVENT_PRLO_RCV; + break; + case ELS_CMD_ADISC: +- els_data.subcategory = LPFC_EVENT_ADISC_RCV; ++ els_data->subcategory = LPFC_EVENT_ADISC_RCV; ++ break; ++ case ELS_CMD_LOGO: ++ els_data->subcategory = LPFC_EVENT_LOGO_RCV; ++ /* Copy the WWPN in the LOGO payload */ ++ memcpy(logo_data->logo_wwpn, &payload[2], ++ sizeof(struct lpfc_name)); + break; + default: + return; + } +- memcpy(els_data.wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); +- memcpy(els_data.wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); +- fc_host_post_vendor_event(shost, +- fc_get_event_number(), +- sizeof(els_data), +- (char *)&els_data, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ memcpy(els_data->wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); ++ memcpy(els_data->wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); ++ if (*payload == ELS_CMD_LOGO) { ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(struct lpfc_logo_event), ++ (char *)logo_data, ++ LPFC_NL_VENDOR_ID); ++ kfree(logo_data); ++ } else { ++ fc_host_post_vendor_event(shost, ++ fc_get_event_number(), ++ sizeof(struct lpfc_els_event_header), ++ (char *)els_data, ++ LPFC_NL_VENDOR_ID); ++ kfree(els_data); ++ } + + return; + } +@@ -5700,7 +5790,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + phba->fc_stat.elsRcvPLOGI++; + ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); + +- lpfc_send_els_event(vport, ndlp, cmd); ++ lpfc_send_els_event(vport, ndlp, payload); + if (vport->port_state < LPFC_DISC_AUTH) { + if (!(phba->pport->fc_flag & FC_PT2PT) || + (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { +@@ -5738,6 +5828,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvLOGO++; ++ lpfc_send_els_event(vport, ndlp, payload); + if (vport->port_state < LPFC_DISC_AUTH) { + rjt_err = LSRJT_UNABLE_TPC; + break; +@@ -5750,7 +5841,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvPRLO++; +- lpfc_send_els_event(vport, ndlp, cmd); ++ lpfc_send_els_event(vport, ndlp, payload); + if (vport->port_state < LPFC_DISC_AUTH) { + rjt_err = LSRJT_UNABLE_TPC; + break; +@@ -5768,7 +5859,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + "RCV ADISC: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + +- lpfc_send_els_event(vport, ndlp, cmd); ++ lpfc_send_els_event(vport, ndlp, payload); + phba->fc_stat.elsRcvADISC++; + if (vport->port_state < LPFC_DISC_AUTH) { + rjt_err = LSRJT_UNABLE_TPC; +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 3d825ff..502a9a5 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -391,7 +391,7 @@ lpfc_send_fastpath_evt(struct lpfc_hba *phba, + evt_data_size = sizeof(fast_evt_data->un. + read_check_error); + } else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) || +- (evt_sub_category == IOSTAT_NPORT_BSY)) { ++ (evt_sub_category == LPFC_EVENT_PORT_BUSY)) { + evt_data = (char *) &fast_evt_data->un.fabric_evt; + evt_data_size = sizeof(fast_evt_data->un.fabric_evt); + } else { +@@ -428,7 +428,7 @@ lpfc_send_fastpath_evt(struct lpfc_hba *phba, + fc_get_event_number(), + evt_data_size, + evt_data, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + lpfc_free_fast_evt(phba, fast_evt_data); + return; +@@ -635,20 +635,25 @@ lpfc_do_work(void *p) + set_user_nice(current, -20); + phba->data_flags = 0; + +- while (1) { ++ while (!kthread_should_stop()) { + /* wait and check worker queue activities */ + rc = wait_event_interruptible(phba->work_waitq, + (test_and_clear_bit(LPFC_DATA_READY, + &phba->data_flags) + || kthread_should_stop())); +- BUG_ON(rc); +- +- if (kthread_should_stop()) ++ /* Signal wakeup shall terminate the worker thread */ ++ if (rc) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_ELS, ++ "0433 Wakeup on signal: rc=x%x\n", rc); + break; ++ } + + /* Attend pending lpfc data processing */ + lpfc_work_done(phba); + } ++ phba->worker_thread = NULL; ++ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, ++ "0432 Worker thread stopped.\n"); + return 0; + } + +@@ -1895,6 +1900,36 @@ lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) + lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, + NLP_STE_UNUSED_NODE); + } ++/** ++ * lpfc_initialize_node: Initialize all fields of node object. ++ * @vport: Pointer to Virtual Port object. ++ * @ndlp: Pointer to FC node object. ++ * @did: FC_ID of the node. ++ * This function is always called when node object need to ++ * be initialized. It initializes all the fields of the node ++ * object. ++ **/ ++static inline void ++lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ++ uint32_t did) ++{ ++ INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); ++ INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); ++ INIT_LIST_HEAD(&ndlp->els_reauth_evt.evt_listp); ++ init_timer(&ndlp->nlp_delayfunc); ++ ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; ++ ndlp->nlp_delayfunc.data = (unsigned long)ndlp; ++ init_timer(&ndlp->nlp_reauth_tmr); ++ ndlp->nlp_reauth_tmr.function = lpfc_reauth_node; ++ ndlp->nlp_reauth_tmr.data = (unsigned long)ndlp; ++ ndlp->nlp_DID = did; ++ ndlp->vport = vport; ++ ndlp->nlp_sid = NLP_NO_SID; ++ kref_init(&ndlp->kref); ++ NLP_INT_NODE_ACT(ndlp); ++ atomic_set(&ndlp->cmd_pending, 0); ++ ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; ++} + + struct lpfc_nodelist * + lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, +@@ -1935,21 +1970,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + /* re-initialize ndlp except of ndlp linked list pointer */ + memset((((char *)ndlp) + sizeof (struct list_head)), 0, + sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); +- INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); +- INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); +- INIT_LIST_HEAD(&ndlp->els_reauth_evt.evt_listp); +- init_timer(&ndlp->nlp_delayfunc); +- ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; +- ndlp->nlp_delayfunc.data = (unsigned long)ndlp; +- init_timer(&ndlp->nlp_reauth_tmr); +- ndlp->nlp_reauth_tmr.function = lpfc_reauth_node; +- ndlp->nlp_reauth_tmr.data = (unsigned long)ndlp; +- ndlp->nlp_DID = did; +- ndlp->vport = vport; +- ndlp->nlp_sid = NLP_NO_SID; +- /* ndlp management re-initialize */ +- kref_init(&ndlp->kref); +- NLP_INT_NODE_ACT(ndlp); ++ lpfc_initialize_node(vport, ndlp, did); + + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + +@@ -2561,7 +2582,8 @@ lpfc_disc_list_loopmap(struct lpfc_vport *vport) + alpa = lpfcAlpaArray[index]; + if ((vport->fc_myDID & 0xff) == alpa) + continue; +- lpfc_setup_disc_node(vport, alpa); ++ if (!(phba->link_flag & LS_LOOPBACK_MODE)) ++ lpfc_setup_disc_node(vport, alpa); + } + } + return; +@@ -3204,23 +3226,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint32_t did) + { + memset(ndlp, 0, sizeof (struct lpfc_nodelist)); +- INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); +- INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); +- INIT_LIST_HEAD(&ndlp->els_reauth_evt.evt_listp); +- init_timer(&ndlp->nlp_delayfunc); +- ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; +- ndlp->nlp_delayfunc.data = (unsigned long)ndlp; +- init_timer(&ndlp->nlp_reauth_tmr); +- ndlp->nlp_reauth_tmr.function = lpfc_reauth_node; +- ndlp->nlp_reauth_tmr.data = (unsigned long)ndlp; +- ndlp->nlp_DID = did; +- ndlp->vport = vport; +- ndlp->nlp_sid = NLP_NO_SID; ++ lpfc_initialize_node(vport, ndlp, did); + INIT_LIST_HEAD(&ndlp->nlp_listp); +- kref_init(&ndlp->kref); +- NLP_INT_NODE_ACT(ndlp); +- atomic_set(&ndlp->cmd_pending, 0); +- ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "node init: did:x%x", +diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h +index 9fc50ef..90d0c5a 100644 +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -66,6 +66,9 @@ + + #define BUF_SZ_4K 4096 + ++/* vendor ID used in SCSI netlink calls */ ++#define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX) ++ + /* Common Transport structures and definitions */ + + union CtRevisionId { +@@ -891,6 +894,12 @@ typedef struct _D_ID { /* Structure is in Big Endian format */ + } un; + } D_ID; + ++#define RSCN_ADDRESS_FORMAT_PORT 0x0 ++#define RSCN_ADDRESS_FORMAT_AREA 0x1 ++#define RSCN_ADDRESS_FORMAT_DOMAIN 0x2 ++#define RSCN_ADDRESS_FORMAT_FABRIC 0x3 ++#define RSCN_ADDRESS_FORMAT_MASK 0x3 ++ + /* + * Structure to define all ELS Payload types + */ +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index c19c631..c0ea4fc 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -879,8 +879,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(board_event), + (char *) &board_event, +- SCSI_NL_VID_TYPE_PCI +- | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + if (phba->work_hs & HS_FFER6) { + /* Re-establishing Link */ +@@ -2383,6 +2382,98 @@ lpfc_disable_msix(struct lpfc_hba *phba) + } + + /** ++ * lpfc_enable_intr: Enable device interrupt. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to enable device interrupt and associate driver's ++ * interrupt handler(s) to interrupt vector(s). Depends on the interrupt ++ * mode configured to the driver, the driver will try to fallback from the ++ * configured interrupt mode to an interrupt mode which is supported by the ++ * platform, kernel, and device in the order of: MSI-X -> MSI -> IRQ. ++ * ++ * Return codes ++ * 0 - sucessful ++ * other values - error ++ **/ ++static int ++lpfc_enable_intr(struct lpfc_hba *phba) ++{ ++ int retval = 0; ++ ++ /* Starting point of configuring interrupt method */ ++ phba->intr_type = NONE; ++ ++ if (phba->cfg_use_msi == 2) { ++ /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ ++ retval = lpfc_sli_config_port(phba, 3); ++ if (retval) ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0478 Firmware not capable of SLI 3 mode.\n"); ++ else { ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0479 Firmware capable of SLI 3 mode.\n"); ++ /* Now, try to enable MSI-X interrupt mode */ ++ retval = lpfc_enable_msix(phba); ++ if (!retval) { ++ phba->intr_type = MSIX; ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0480 enable MSI-X mode.\n"); ++ } ++ } ++ } ++ ++ /* Fallback to MSI if MSI-X initialization failed */ ++ if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { ++ retval = pci_enable_msi(phba->pcidev); ++ if (!retval) { ++ phba->intr_type = MSI; ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0481 enable MSI mode.\n"); ++ } else ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0470 enable IRQ mode.\n"); ++ } ++ ++ /* MSI-X is the only case the doesn't need to call request_irq */ ++ if (phba->intr_type != MSIX) { ++ retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, ++ IRQF_SHARED, LPFC_DRIVER_NAME, phba); ++ if (retval) { ++ if (phba->intr_type == MSI) ++ pci_disable_msi(phba->pcidev); ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0471 Enable interrupt handler " ++ "failed\n"); ++ } else if (phba->intr_type != MSI) ++ phba->intr_type = INTx; ++ } ++ ++ return retval; ++} ++ ++/** ++ * lpfc_disable_intr: Disable device interrupt. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to disable device interrupt and disassociate the ++ * driver's interrupt handler(s) from interrupt vector(s). Depending on the ++ * interrupt mode, the driver will release the interrupt vector(s) for the ++ * message signaled interrupt. ++ **/ ++static void ++lpfc_disable_intr(struct lpfc_hba *phba) ++{ ++ if (phba->intr_type == MSIX) ++ lpfc_disable_msix(phba); ++ else { ++ free_irq(phba->pcidev->irq, phba); ++ if (phba->intr_type == MSI) ++ pci_disable_msi(phba->pcidev); ++ } ++ return; ++} ++ ++/** + * lpfc_pci_probe_one: lpfc PCI probe func to register device to PCI subsystem. + * @pdev: pointer to PCI device + * @pid: pointer to PCI device identifier +@@ -2634,7 +2725,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + lpfc_debugfs_initialize(vport); + + pci_set_drvdata(pdev, shost); +- phba->intr_type = NONE; + + phba->MBslimaddr = phba->slim_memmap_p; + phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; +@@ -2643,48 +2733,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; + + /* Configure and enable interrupt */ +- if (phba->cfg_use_msi == 2) { +- /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ +- error = lpfc_sli_config_port(phba, 3); +- if (error) +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0427 Firmware not capable of SLI 3 mode.\n"); +- else { +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0426 Firmware capable of SLI 3 mode.\n"); +- /* Now, try to enable MSI-X interrupt mode */ +- error = lpfc_enable_msix(phba); +- if (!error) { +- phba->intr_type = MSIX; +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0430 enable MSI-X mode.\n"); +- } +- } +- } +- +- /* Fallback to MSI if MSI-X initialization failed */ +- if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { +- retval = pci_enable_msi(phba->pcidev); +- if (!retval) { +- phba->intr_type = MSI; +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0473 enable MSI mode.\n"); +- } else +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0452 enable IRQ mode.\n"); +- } +- +- /* MSI-X is the only case the doesn't need to call request_irq */ +- if (phba->intr_type != MSIX) { +- retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, +- IRQF_SHARED, LPFC_DRIVER_NAME, phba); +- if (retval) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable " +- "interrupt handler failed\n"); +- error = retval; +- goto out_disable_msi; +- } else if (phba->intr_type != MSI) +- phba->intr_type = INTx; ++ error = lpfc_enable_intr(phba); ++ if (error) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0426 Failed to enable interrupt.\n"); ++ goto out_destroy_port; + } + + phba->dfc_host = lpfcdfc_host_add(pdev, shost, phba); +@@ -2731,7 +2784,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(adapter_event), + (char *) &adapter_event, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + scsi_scan_host(shost); + +@@ -2747,15 +2800,8 @@ out_free_irq: + lpfcdfc_host_del(phba->dfc_host); + lpfc_stop_phba_timers(phba); + phba->pport->work_port_events = 0; +- +- if (phba->intr_type == MSIX) +- lpfc_disable_msix(phba); +- else +- free_irq(phba->pcidev->irq, phba); +- +-out_disable_msi: +- if (phba->intr_type == MSI) +- pci_disable_msi(phba->pcidev); ++ lpfc_disable_intr(phba); ++out_destroy_port: + destroy_port(vport); + out_kthread_stop: + kthread_stop(phba->worker_thread); +@@ -2796,7 +2842,7 @@ out: + * @pdev: pointer to PCI device + * + * This routine is to be registered to the kernel's PCI subsystem. When an +- * Emulex HBA is removed from PCI bus. It perform all the necessary cleanup ++ * Emulex HBA is removed from PCI bus, it performs all the necessary cleanup + * for the HBA device to be removed from the PCI subsystem properly. + **/ + static void __devexit +@@ -2804,12 +2850,11 @@ lpfc_pci_remove_one(struct pci_dev *pdev) + { + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ struct lpfc_vport **vports; + struct lpfc_hba *phba = vport->phba; ++ int i; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + +- /* In case PCI channel permanently disabled, rescan SCSI devices */ +- if (pdev->error_state == pci_channel_io_perm_failure) +- lpfc_scsi_dev_rescan(phba); + lpfcdfc_host_del(phba->dfc_host); + phba->dfc_host = NULL; + +@@ -2822,6 +2867,14 @@ lpfc_pci_remove_one(struct pci_dev *pdev) + + kthread_stop(phba->worker_thread); + ++ /* Release all the vports against this physical port */ ++ vports = lpfc_create_vport_work_array(phba); ++ if (vports != NULL) ++ for (i = 1; i <= phba->max_vpi && vports[i] != NULL; i++) ++ fc_vport_terminate(vports[i]->fc_vport); ++ lpfc_destroy_vport_work_array(phba, vports); ++ ++ /* Remove FC host and then SCSI host with the physical port */ + fc_remove_host(shost); + scsi_remove_host(shost); + lpfc_cleanup(vport); +@@ -2841,13 +2894,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) + + lpfc_debugfs_terminate(vport); + +- if (phba->intr_type == MSIX) +- lpfc_disable_msix(phba); +- else { +- free_irq(phba->pcidev->irq, phba); +- if (phba->intr_type == MSI) +- pci_disable_msi(phba->pcidev); +- } ++ /* Disable interrupt */ ++ lpfc_disable_intr(phba); + + pci_set_drvdata(pdev, NULL); + scsi_host_put(shost); +@@ -2879,6 +2927,111 @@ lpfc_pci_remove_one(struct pci_dev *pdev) + } + + /** ++ * lpfc_pci_suspend_one: lpfc PCI func to suspend device for power management. ++ * @pdev: pointer to PCI device ++ * @msg: power management message ++ * ++ * This routine is to be registered to the kernel's PCI subsystem to support ++ * system Power Management (PM). When PM invokes this method, it quiesces the ++ * device by stopping the driver's worker thread for the device, turning off ++ * device's interrupt and DMA, and bring the device offline. Note that as the ++ * driver implements the minimum PM requirements to a power-aware driver's PM ++ * support for suspend/resume -- all the possible PM messages (SUSPEND, ++ * HIBERNATE, FREEZE) to the suspend() method call will be treated as SUSPEND ++ * and the driver will fully reinitialize its device during resume() method ++ * call, the driver will set device to PCI_D3hot state in PCI config space ++ * instead of setting it according to the @msg provided by the PM. ++ * ++ * Return code ++ * 0 - driver suspended the device ++ * Error otherwise ++ **/ ++static int ++lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) ++{ ++ struct Scsi_Host *shost = pci_get_drvdata(pdev); ++ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0473 PCI device Power Management suspend.\n"); ++ ++ /* Bring down the device */ ++ lpfc_offline_prep(phba); ++ lpfc_offline(phba); ++ kthread_stop(phba->worker_thread); ++ ++ /* Disable interrupt from device */ ++ lpfc_disable_intr(phba); ++ ++ /* Save device state to PCI config space */ ++ pci_save_state(pdev); ++ pci_set_power_state(pdev, PCI_D3hot); ++ ++ return 0; ++} ++ ++/** ++ * lpfc_pci_resume_one: lpfc PCI func to resume device for power management. ++ * @pdev: pointer to PCI device ++ * ++ * This routine is to be registered to the kernel's PCI subsystem to support ++ * system Power Management (PM). When PM invokes this method, it restores ++ * the device's PCI config space state and fully reinitializes the device ++ * and brings it online. Note that as the driver implements the minimum PM ++ * requirements to a power-aware driver's PM for suspend/resume -- all ++ * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend() ++ * method call will be treated as SUSPEND and the driver will fully ++ * reinitialize its device during resume() method call, the device will be ++ * set to PCI_D0 directly in PCI config space before restoring the state. ++ * ++ * Return code ++ * 0 - driver suspended the device ++ * Error otherwise ++ **/ ++static int ++lpfc_pci_resume_one(struct pci_dev *pdev) ++{ ++ struct Scsi_Host *shost = pci_get_drvdata(pdev); ++ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; ++ int error; ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0452 PCI device Power Management resume.\n"); ++ ++ /* Restore device state from PCI config space */ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ if (pdev->is_busmaster) ++ pci_set_master(pdev); ++ ++ /* Startup the kernel thread for this host adapter. */ ++ phba->worker_thread = kthread_run(lpfc_do_work, phba, ++ "lpfc_worker_%d", phba->brd_no); ++ if (IS_ERR(phba->worker_thread)) { ++ error = PTR_ERR(phba->worker_thread); ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0434 PM resume failed to start worker " ++ "thread: error=x%x.\n", error); ++ return error; ++ } ++ ++ /* Enable interrupt from device */ ++ error = lpfc_enable_intr(phba); ++ if (error) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0430 PM resume Failed to enable interrupt: " ++ "error=x%x.\n", error); ++ return error; ++ } ++ ++ /* Restart HBA and bring it online */ ++ lpfc_sli_brdrestart(phba); ++ lpfc_online(phba); ++ ++ return 0; ++} ++ ++/** + * lpfc_io_error_detected: Driver method for handling PCI I/O error detected. + * @pdev: pointer to PCI device. + * @state: the current PCI connection state. +@@ -2921,13 +3074,8 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + +- if (phba->intr_type == MSIX) +- lpfc_disable_msix(phba); +- else { +- free_irq(phba->pcidev->irq, phba); +- if (phba->intr_type == MSI) +- pci_disable_msi(phba->pcidev); +- } ++ /* Disable interrupt */ ++ lpfc_disable_intr(phba); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +@@ -2955,7 +3103,7 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + struct lpfc_sli *psli = &phba->sli; +- int error, retval; ++ int error; + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_mem(pdev)) { +@@ -2971,48 +3119,12 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) + spin_unlock_irq(&phba->hbalock); + + /* Enable configured interrupt method */ +- phba->intr_type = NONE; +- if (phba->cfg_use_msi == 2) { +- /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ +- error = lpfc_sli_config_port(phba, 3); +- if (error) +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0478 Firmware not capable of SLI 3 mode.\n"); +- else { +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0479 Firmware capable of SLI 3 mode.\n"); +- /* Now, try to enable MSI-X interrupt mode */ +- error = lpfc_enable_msix(phba); +- if (!error) { +- phba->intr_type = MSIX; +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0480 enable MSI-X mode.\n"); +- } +- } +- } +- +- /* Fallback to MSI if MSI-X initialization failed */ +- if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { +- retval = pci_enable_msi(phba->pcidev); +- if (!retval) { +- phba->intr_type = MSI; +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0481 enable MSI mode.\n"); +- } else +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0470 enable IRQ mode.\n"); +- } +- +- /* MSI-X is the only case the doesn't need to call request_irq */ +- if (phba->intr_type != MSIX) { +- retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, +- IRQF_SHARED, LPFC_DRIVER_NAME, phba); +- if (retval) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0471 Enable interrupt handler " +- "failed\n"); +- } else if (phba->intr_type != MSI) +- phba->intr_type = INTx; ++ error = lpfc_enable_intr(phba); ++ if (error) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0427 Cannot re-enable interrupt after " ++ "slot reset.\n"); ++ return PCI_ERS_RESULT_DISCONNECT; + } + + /* Take device offline; this will perform cleanup */ +@@ -3130,6 +3242,8 @@ static struct pci_driver lpfc_driver = { + .id_table = lpfc_id_table, + .probe = lpfc_pci_probe_one, + .remove = __devexit_p(lpfc_pci_remove_one), ++ .suspend = lpfc_pci_suspend_one, ++ .resume = lpfc_pci_resume_one, + .err_handler = &lpfc_err_handler, + }; + +diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c +index 242bed3..e80d157 100644 +--- a/drivers/scsi/lpfc/lpfc_ioctl.c ++++ b/drivers/scsi/lpfc/lpfc_ioctl.c +@@ -828,10 +828,10 @@ lpfc_ioctl_send_mgmt_cmd(struct lpfc_hba * phba, + rc = EIO; + + send_mgmt_cmd_free_outdmp: +- spin_lock_irq(shost->host_lock); + dfc_cmd_data_free(phba, outdmp); + send_mgmt_cmd_free_indmp: + dfc_cmd_data_free(phba, indmp); ++ spin_lock_irq(shost->host_lock); + send_mgmt_cmd_free_bmpvirt: + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); + send_mgmt_cmd_free_bmp: +@@ -2069,14 +2069,14 @@ __dfc_cmd_data_alloc(struct lpfc_hba * phba, + cnt)) { + goto out; + } +- ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; + pci_dma_sync_single_for_device(phba->pcidev, + dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); + +- } else ++ } else { + memset((uint8_t *)dmp->dma.virt, 0, cnt); +- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; +- ++ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; ++ } + /* build buffer ptr list for IOCB */ + bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); + bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); +diff --git a/drivers/scsi/lpfc/lpfc_menlo.c b/drivers/scsi/lpfc/lpfc_menlo.c +index 60d3df8..aa36c16 100644 +--- a/drivers/scsi/lpfc/lpfc_menlo.c ++++ b/drivers/scsi/lpfc/lpfc_menlo.c +@@ -42,6 +42,7 @@ + #include "lpfc_vport.h" + + #define MENLO_CMD_FW_DOWNLOAD 0x00000002 ++#define MENLO_CMD_LOOPBACK 0x00000014 + + static void lpfc_menlo_iocb_timeout_cmpl(struct lpfc_hba *, + struct lpfc_iocbq *, struct lpfc_iocbq *); +@@ -686,6 +687,16 @@ lpfc_menlo_write(struct lpfc_hba *phba, + } else + memcpy((uint8_t *) mlast->dma.virt, buf, count); + ++ if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_LOOPBACK) { ++ if (mlast) { ++ tmpptr = (uint32_t *)mlast->dma.virt; ++ if (*(tmpptr+2)) ++ phba->link_flag |= LS_LOOPBACK_MODE; ++ else ++ phba->link_flag &= ~LS_LOOPBACK_MODE; ++ } ++ } ++ + if (sysfs_menlo->cmdhdr.cmd == MENLO_CMD_FW_DOWNLOAD + && genreq->offset < hdr_offset) { + if (sysfs_menlo->cr.indmp +diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h +index 1accb5a..991ad53 100644 +--- a/drivers/scsi/lpfc/lpfc_nl.h ++++ b/drivers/scsi/lpfc/lpfc_nl.h +@@ -52,6 +52,13 @@ + * The payload sent via the fc transport is one-way driver->application. + */ + ++/* RSCN event header */ ++struct lpfc_rscn_event_header { ++ uint32_t event_type; ++ uint32_t payload_length; /* RSCN data length in bytes */ ++ uint32_t rscn_payload[]; ++}; ++ + /* els event header */ + struct lpfc_els_event_header { + uint32_t event_type; +@@ -65,6 +72,7 @@ struct lpfc_els_event_header { + #define LPFC_EVENT_PRLO_RCV 0x02 + #define LPFC_EVENT_ADISC_RCV 0x04 + #define LPFC_EVENT_LSRJT_RCV 0x08 ++#define LPFC_EVENT_LOGO_RCV 0x10 + + /* special els lsrjt event */ + struct lpfc_lsrjt_event { +@@ -74,6 +82,11 @@ struct lpfc_lsrjt_event { + uint32_t explanation; + }; + ++/* special els logo event */ ++struct lpfc_logo_event { ++ struct lpfc_els_event_header header; ++ uint8_t logo_wwpn[8]; ++}; + + /* fabric event header */ + struct lpfc_fabric_event_header { +@@ -125,6 +138,7 @@ struct lpfc_scsi_varqueuedepth_event { + /* special case scsi check condition event */ + struct lpfc_scsi_check_condition_event { + struct lpfc_scsi_event_header scsi_event; ++ uint8_t opcode; + uint8_t sense_key; + uint8_t asc; + uint8_t ascq; +diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c +index a116875..a7ea952 100644 +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -147,12 +147,19 @@ lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba, + return; + } + +-/* +- * This function is called with no lock held when there is a resource +- * error in driver or in firmware. +- */ ++/** ++ * lpfc_rampdown_queue_depth: Post RAMP_DOWN_QUEUE event to worker thread. ++ * @phba: The Hba for which this call is being executed. ++ * ++ * This routine is called when there is resource error in driver or firmware. ++ * This routine posts WORKER_RAMP_DOWN_QUEUE event for @phba. This routine ++ * posts at most 1 event each second. This routine wakes up worker thread of ++ * @phba to process WORKER_RAM_DOWN_EVENT event. ++ * ++ * This routine should be called with no lock held. ++ **/ + void +-lpfc_adjust_queue_depth(struct lpfc_hba *phba) ++lpfc_rampdown_queue_depth(struct lpfc_hba *phba) + { + unsigned long flags; + uint32_t evt_posted; +@@ -335,22 +342,6 @@ lpfc_scsi_dev_block(struct lpfc_hba *phba) + lpfc_destroy_vport_work_array(phba, vports); + } + +-void +-lpfc_scsi_dev_rescan(struct lpfc_hba *phba) +-{ +- struct lpfc_vport **vports; +- struct Scsi_Host *shost; +- int i; +- +- vports = lpfc_create_vport_work_array(phba); +- if (vports != NULL) +- for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { +- shost = lpfc_shost_from_vport(vports[i]); +- scsi_scan_host(shost); +- } +- lpfc_destroy_vport_work_array(phba, vports); +-} +- + /* + * This routine allocates a scsi buffer, which contains all the necessary + * information needed to initiate a SCSI I/O. The non-DMAable buffer region +@@ -861,7 +852,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + + lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; + lpfc_cmd->status = pIocbOut->iocb.ulpStatus; +- atomic_dec(&pnode->cmd_pending); ++ if (pnode && NLP_CHK_NODE_ACT(pnode)) ++ atomic_dec(&pnode->cmd_pending); + + if (lpfc_cmd->status) { + if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && +@@ -951,23 +943,31 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + time_after(jiffies, lpfc_cmd->start_time + + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { + spin_lock_irqsave(sdev->host->host_lock, flags); +- if ((pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) && +- (atomic_read(&pnode->cmd_pending) > LPFC_MIN_TGT_QDEPTH) && +- ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)))) +- pnode->cmd_qdepth = atomic_read(&pnode->cmd_pending); +- +- pnode->last_change_time = jiffies; ++ if (pnode && NLP_CHK_NODE_ACT(pnode)) { ++ if (pnode->cmd_qdepth > ++ atomic_read(&pnode->cmd_pending) && ++ (atomic_read(&pnode->cmd_pending) > ++ LPFC_MIN_TGT_QDEPTH) && ++ ((cmd->cmnd[0] == READ_10) || ++ (cmd->cmnd[0] == WRITE_10))) ++ pnode->cmd_qdepth = ++ atomic_read(&pnode->cmd_pending); ++ ++ pnode->last_change_time = jiffies; ++ } + spin_unlock_irqrestore(sdev->host->host_lock, flags); +- } else if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && ++ } else if (pnode && NLP_CHK_NODE_ACT(pnode)) { ++ if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && + time_after(jiffies, pnode->last_change_time + +- msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { +- spin_lock_irqsave(sdev->host->host_lock, flags); +- pnode->cmd_qdepth += pnode->cmd_qdepth * +- LPFC_TGTQ_RAMPUP_PCENT / 100; +- if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) +- pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; +- pnode->last_change_time = jiffies; +- spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { ++ spin_lock_irqsave(sdev->host->host_lock, flags); ++ pnode->cmd_qdepth += pnode->cmd_qdepth * ++ LPFC_TGTQ_RAMPUP_PCENT / 100; ++ if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) ++ pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; ++ pnode->last_change_time = jiffies; ++ spin_unlock_irqrestore(sdev->host->host_lock, flags); ++ } + } + + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); +@@ -1363,13 +1363,13 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); + goto out_fail_command; + } +- +- if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) ++ if (vport->cfg_max_scsicmpl_time && ++ (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)) + goto out_host_busy; + + lpfc_cmd = lpfc_get_scsi_buf(phba); + if (lpfc_cmd == NULL) { +- lpfc_adjust_queue_depth(phba); ++ lpfc_rampdown_queue_depth(phba); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "0707 driver's buffer pool is empty, " +@@ -1397,9 +1397,10 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + atomic_inc(&ndlp->cmd_pending); + err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], + &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); +- if (err) ++ if (err) { ++ atomic_dec(&ndlp->cmd_pending); + goto out_host_busy_free_buf; +- ++ } + if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { + lpfc_sli_poll_fcp_ring(phba); + if (phba->cfg_poll & DISABLE_FCP_RING_INT) +@@ -1409,7 +1410,6 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) + return 0; + + out_host_busy_free_buf: +- atomic_dec(&ndlp->cmd_pending); + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); + lpfc_release_scsi_buf(phba, lpfc_cmd); + out_host_busy: +@@ -1575,7 +1575,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) + fc_get_event_number(), + sizeof(scsi_event), + (char *)&scsi_event, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, +@@ -1672,7 +1672,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) + fc_get_event_number(), + sizeof(scsi_event), + (char *)&scsi_event, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + lpfc_block_error_handler(cmnd); + /* +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index d4341df..ac78493 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -1985,7 +1985,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, + if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + spin_unlock_irqrestore(&phba->hbalock, iflag); +- lpfc_adjust_queue_depth(phba); ++ lpfc_rampdown_queue_depth(phba); + spin_lock_irqsave(&phba->hbalock, iflag); + } + +@@ -2228,7 +2228,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, + if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { + spin_unlock_irqrestore(&phba->hbalock, iflag); +- lpfc_adjust_queue_depth(phba); ++ lpfc_rampdown_queue_depth(phba); + spin_lock_irqsave(&phba->hbalock, iflag); + } + +@@ -2793,7 +2793,6 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba) + { + MAILBOX_t *mb; + struct lpfc_sli *psli; +- uint16_t skip_post; + volatile uint32_t word0; + void __iomem *to_slim; + +@@ -2818,13 +2817,10 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba) + readl(to_slim); /* flush */ + + /* Only skip post after fc_ffinit is completed */ +- if (phba->pport->port_state) { +- skip_post = 1; ++ if (phba->pport->port_state) + word0 = 1; /* This is really setting up word1 */ +- } else { +- skip_post = 0; ++ else + word0 = 0; /* This is really setting up word1 */ +- } + to_slim = phba->MBslimaddr + sizeof (uint32_t); + writel(*(uint32_t *) mb, to_slim); + readl(to_slim); /* flush */ +@@ -2838,10 +2834,8 @@ lpfc_sli_brdrestart(struct lpfc_hba *phba) + memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); + psli->stats_start = get_seconds(); + +- if (skip_post) +- mdelay(100); +- else +- mdelay(2000); ++ /* Give the INITFF and Post time to settle. */ ++ mdelay(100); + + lpfc_hba_down_post(phba); + +@@ -3087,7 +3081,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) + spin_unlock_irq(&phba->hbalock); + phba->pport->port_state = LPFC_VPORT_UNKNOWN; + lpfc_sli_brdrestart(phba); +- msleep(2500); + rc = lpfc_sli_chipset_init(phba); + if (rc) + break; +@@ -4041,7 +4034,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), (char *) &temp_event_data, +- SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); ++ LPFC_NL_VENDOR_ID); + + } + +@@ -5220,6 +5213,10 @@ lpfc_sli_check_eratt(struct lpfc_hba *phba) + { + uint32_t ha_copy; + ++ /* If PCI channel is offline, don't process it */ ++ if (unlikely(pci_channel_offline(phba->pcidev))) ++ return 0; ++ + /* If somebody is waiting to handle an eratt, don't process it + * here. The brdkill function will do this. + */ +diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +index 899a337..a42cef2 100644 +--- a/drivers/scsi/lpfc/lpfc_version.h ++++ b/drivers/scsi/lpfc/lpfc_version.h +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.1" ++#define LPFC_DRIVER_VERSION "8.2.8.3" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" +diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c +index 8761840..c3a3f6e 100644 +--- a/drivers/scsi/lpfc/lpfc_vport.c ++++ b/drivers/scsi/lpfc/lpfc_vport.c +@@ -605,6 +605,8 @@ lpfc_vport_delete(struct fc_vport *fc_vport) + spin_unlock_irq(&phba->hbalock); + kfree(vport->vname); + lpfc_debugfs_terminate(vport); ++ ++ /* Remove FC host and then SCSI host with the vport */ + fc_remove_host(lpfc_shost_from_vport(vport)); + scsi_remove_host(lpfc_shost_from_vport(vport)); + +@@ -689,8 +691,6 @@ lpfc_vport_delete(struct fc_vport *fc_vport) + } + vport->unreg_vpi_cmpl = VPORT_INVAL; + timeout = msecs_to_jiffies(phba->fc_ratov * 2000); +- if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) +- goto skip_logo; + if (!lpfc_issue_els_npiv_logo(vport, ndlp)) + while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) + timeout = schedule_timeout(timeout); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.4-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.4-update new file mode 100644 index 000000000..a1ce3b51c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.4-update @@ -0,0 +1,725 @@ +Subject: Update lpfc to 8.2.8.4 +From: Hannes Reinecke +Date: Tue Oct 7 13:50:11 2008 +0200: +References: bnc#420767 + +This patch updates the SLES 11 lpfc driver to 8.2.8.4 which has +the following changes: + +* Changed version number to 8.2.8.4 +* Added code to get option ROM version from HBA +* Added support for FC_REG_VPORTRSCN_EVENT +* Fix the authentication error when the initial authentication is rejected +* Add the lpfc_symbolic_name back into the scsi_host attributes +* Fix vport failed to create when link was down or in loop (CR 83339) +* Fix authentication failures always show up an generic errors (CR 74969) +* Fixed statistical data collection for virtual ports +* Support changes to vport's symbolic name +* Fix Vport created in disabled state doesn't have correct state +* Fix vport disable attribute missing +* Fix vport attributes by removing physical attributes + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h +index 10e1ac6..7508dea 100644 +--- a/drivers/scsi/lpfc/lpfc.h ++++ b/drivers/scsi/lpfc/lpfc.h +@@ -328,6 +328,11 @@ enum auth_state { + LPFC_AUTH_UNKNOWN = 0, + LPFC_AUTH_SUCCESS = 1, + LPFC_AUTH_FAIL = 2, ++ LPFC_AUTH_FAIL_ELS_TMO = 3, ++ LPFC_AUTH_FAIL_TRANS_TMO = 4, ++ LPFC_AUTH_FAIL_LS_RJT_GEN = 5, ++ LPFC_AUTH_FAIL_LS_RJT_BUSY = 6, ++ LPFC_AUTH_FAIL_AUTH_RJT = 7, + }; + enum auth_msg_state { + LPFC_AUTH_NONE = 0, +@@ -463,8 +468,6 @@ struct lpfc_vport { + uint8_t load_flag; + #define FC_LOADING 0x1 /* HBA in process of loading drvr */ + #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ +- char *vname; /* Application assigned name */ +- + /* Fields used for accessing auth service */ + struct lpfc_auth auth; + uint32_t sc_tran_id; +diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +index 8e94902..1069491 100644 +--- a/drivers/scsi/lpfc/lpfc_attr.c ++++ b/drivers/scsi/lpfc/lpfc_attr.c +@@ -1107,6 +1107,17 @@ lpfc_auth_state_show(struct device *dev, struct device_attribute *attr, + return snprintf(buf, PAGE_SIZE, "Not Authenticated\n"); + case LPFC_AUTH_FAIL: + return snprintf(buf, PAGE_SIZE, "Failed\n"); ++ case LPFC_AUTH_FAIL_ELS_TMO: ++ return snprintf(buf, PAGE_SIZE, "Failed - ELS Timeout\n"); ++ case LPFC_AUTH_FAIL_TRANS_TMO: ++ return snprintf(buf, PAGE_SIZE, "Failed - " ++ "Transaction Timeout\n"); ++ case LPFC_AUTH_FAIL_LS_RJT_GEN: ++ return snprintf(buf, PAGE_SIZE, "Failed - LS_RJT\n"); ++ case LPFC_AUTH_FAIL_LS_RJT_BUSY: ++ return snprintf(buf, PAGE_SIZE, "Failed - LS_RJT Busy\n"); ++ case LPFC_AUTH_FAIL_AUTH_RJT: ++ return snprintf(buf, PAGE_SIZE, "Failed - AUTH RJT\n"); + case LPFC_AUTH_SUCCESS: + if (vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE || + vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE || +@@ -1665,6 +1676,20 @@ static DEVICE_ATTR(auth_hash, S_IRUGO, lpfc_auth_hash_show, NULL); + static DEVICE_ATTR(auth_last, S_IRUGO, lpfc_auth_last_show, NULL); + static DEVICE_ATTR(auth_next, S_IRUGO, lpfc_auth_next_show, NULL); + ++static ssize_t ++lpfc_symbolic_name_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct Scsi_Host *shost = class_to_shost(dev); ++ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; ++ int length; ++ char symbname[256]; ++ ++ length = lpfc_vport_symbolic_port_name(vport, symbname, 256); ++ return snprintf(buf, PAGE_SIZE, "%s\n", symbname); ++} ++static DEVICE_ATTR(lpfc_symbolic_name, S_IRUGO, lpfc_symbolic_name_show, NULL); ++ + static int + lpfc_parse_wwn(const char *ns, uint8_t *nm) + { +@@ -3134,6 +3159,7 @@ struct device_attribute *lpfc_hba_attrs[] = { + &dev_attr_auth_hash, + &dev_attr_auth_last, + &dev_attr_auth_next, ++ &dev_attr_lpfc_symbolic_name, + &dev_attr_lpfc_soft_wwnn, + &dev_attr_lpfc_soft_wwpn, + &dev_attr_lpfc_soft_wwn_enable, +@@ -3171,7 +3197,7 @@ struct device_attribute *lpfc_vport_attrs[] = { + &dev_attr_auth_hash, + &dev_attr_auth_last, + &dev_attr_auth_next, +- ++ &dev_attr_lpfc_symbolic_name, + &dev_attr_lpfc_max_scsicmpl_time, + &dev_attr_lpfc_stat_data_ctrl, + NULL, +@@ -4134,25 +4160,28 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) + int error; + + error = sysfs_create_bin_file(&shost->shost_dev.kobj, +- &sysfs_ctlreg_attr); +- if (error) ++ &sysfs_drvr_stat_data_attr); ++ ++ /* Virtual ports do not need ctrl_reg and mbox */ ++ if (error || vport->port_type == LPFC_NPIV_PORT) + goto out; + + error = sysfs_create_bin_file(&shost->shost_dev.kobj, +- &sysfs_mbox_attr); ++ &sysfs_ctlreg_attr); + if (error) +- goto out_remove_ctlreg_attr; ++ goto out_remove_stat_attr; + + error = sysfs_create_bin_file(&shost->shost_dev.kobj, +- &sysfs_drvr_stat_data_attr); ++ &sysfs_mbox_attr); + if (error) +- goto out_remove_mbox_attr; ++ goto out_remove_ctlreg_attr; + + return 0; +-out_remove_mbox_attr: +- sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); + out_remove_ctlreg_attr: + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); ++out_remove_stat_attr: ++ sysfs_remove_bin_file(&shost->shost_dev.kobj, ++ &sysfs_drvr_stat_data_attr); + out: + return error; + } +@@ -4167,6 +4196,9 @@ lpfc_free_sysfs_attr(struct lpfc_vport *vport) + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + sysfs_remove_bin_file(&shost->shost_dev.kobj, + &sysfs_drvr_stat_data_attr); ++ /* Virtual ports do not need ctrl_reg and mbox */ ++ if (vport->port_type == LPFC_NPIV_PORT) ++ return; + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_menlo_attr); +@@ -4645,6 +4677,23 @@ lpfc_show_rport_##field (struct device *dev, \ + lpfc_rport_show_function(field, format_string, sz, ) \ + static FC_RPORT_ATTR(field, S_IRUGO, lpfc_show_rport_##field, NULL) + ++/** ++ * lpfc_set_vport_symbolic_name: Set the vport's symbolic name. ++ * @fc_vport: The fc_vport who's symbolic name has been changed. ++ * ++ * Description: ++ * This function is called by the transport after the @fc_vport's symbolic name ++ * has been changed. This function re-registers the symbolic name with the ++ * switch to propogate the change into the fabric if the vport is active. ++ **/ ++static void ++lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) ++{ ++ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; ++ ++ if (vport->port_state == LPFC_VPORT_READY) ++ lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); ++} + + struct fc_function_template lpfc_transport_functions = { + /* fixed attributes the driver supports */ +@@ -4654,6 +4703,7 @@ struct fc_function_template lpfc_transport_functions = { + .show_host_supported_fc4s = 1, + .show_host_supported_speeds = 1, + .show_host_maxframe_size = 1, ++ .show_host_symbolic_name = 1, + + /* dynamic attributes the driver supports */ + .get_host_port_id = lpfc_get_host_port_id, +@@ -4703,6 +4753,10 @@ struct fc_function_template lpfc_transport_functions = { + .terminate_rport_io = lpfc_terminate_rport_io, + + .dd_fcvport_size = sizeof(struct lpfc_vport *), ++ ++ .vport_disable = lpfc_vport_disable, ++ ++ .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, + }; + + struct fc_function_template lpfc_vport_transport_functions = { +@@ -4713,6 +4767,7 @@ struct fc_function_template lpfc_vport_transport_functions = { + .show_host_supported_fc4s = 1, + .show_host_supported_speeds = 1, + .show_host_maxframe_size = 1, ++ .show_host_symbolic_name = 1, + + /* dynamic attributes the driver supports */ + .get_host_port_id = lpfc_get_host_port_id, +@@ -4761,6 +4816,8 @@ struct fc_function_template lpfc_vport_transport_functions = { + .terminate_rport_io = lpfc_terminate_rport_io, + + .vport_disable = lpfc_vport_disable, ++ ++ .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, + }; + + /** +@@ -4788,6 +4845,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) + phba->cfg_soft_wwpn = 0L; + lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); + /* Also reinitialize the host templates with new values. */ ++ lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; + /* + * Since the sg_tablesize is module parameter, the sg_dma_buf_size +diff --git a/drivers/scsi/lpfc/lpfc_auth.c b/drivers/scsi/lpfc/lpfc_auth.c +index 6a5da93..7dc3600 100644 +--- a/drivers/scsi/lpfc/lpfc_auth.c ++++ b/drivers/scsi/lpfc/lpfc_auth.c +@@ -179,9 +179,8 @@ lpfc_dhchap_authenticate(struct Scsi_Host *shost, + ndlp->nlp_DID); + lpfc_issue_els_auth_reject(vport, ndlp, + AUTH_ERR, AUTHENTICATION_FAILED); +- if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) { +- lpfc_port_auth_failed(ndlp); +- } ++ if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) ++ lpfc_port_auth_failed(ndlp, LPFC_AUTH_FAIL_AUTH_RJT); + } + + kfree(rsp); +diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +index a93c555..380acef 100644 +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -28,6 +28,7 @@ int lpfc_issue_els_auth_reject(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, + uint8_t reason, uint8_t explanation); + void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); ++void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + +@@ -89,7 +90,7 @@ struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); + struct lpfc_nodelist *lpfc_findnode_wwnn(struct lpfc_vport *, + struct lpfc_name *); + +-void lpfc_port_auth_failed(struct lpfc_nodelist *); ++void lpfc_port_auth_failed(struct lpfc_nodelist *, enum auth_state); + void lpfc_worker_wake_up(struct lpfc_hba *); + int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); + int lpfc_do_work(void *); +@@ -272,6 +273,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *); + extern struct device_attribute *lpfc_hba_attrs[]; + extern struct device_attribute *lpfc_vport_attrs[]; + extern struct scsi_host_template lpfc_template; ++extern struct scsi_host_template lpfc_vport_template; + extern struct fc_function_template lpfc_transport_functions; + extern struct fc_function_template lpfc_vport_transport_functions; + extern int lpfc_sli_mode; +diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c +index 26dae8b..7fecdbb 100644 +--- a/drivers/scsi/lpfc/lpfc_ct.c ++++ b/drivers/scsi/lpfc/lpfc_ct.c +@@ -1008,8 +1008,10 @@ lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, + if (n < size) + n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi); + +- if (n < size && vport->vname) +- n += snprintf(symbol + n, size - n, " VName-%s", vport->vname); ++ if (n < size && ++ strlen(vport->fc_vport->symbolic_name)) ++ n += snprintf(symbol + n, size - n, " VName-%s", ++ vport->fc_vport->symbolic_name); + return n; + } + +diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c +index a95815e..3f58a4b 100644 +--- a/drivers/scsi/lpfc/lpfc_els.c ++++ b/drivers/scsi/lpfc/lpfc_els.c +@@ -5347,7 +5347,7 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + "1036 Authentication transaction reject - " + "re-auth request reason 0x%x exp 0x%x\n", + rjt->reason, rjt->explanation); +- lpfc_port_auth_failed(ndlp); ++ lpfc_port_auth_failed(ndlp, LPFC_AUTH_FAIL_AUTH_RJT); + if (vport->auth.auth_msg_state == LPFC_DHCHAP_SUCCESS) { + /* start authentication */ + lpfc_start_authentication(vport, ndlp); +@@ -5366,6 +5366,7 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + "1057 Authentication transaction " + "reject. reason 0x%x exp 0x%x\n", + rjt->reason, rjt->explanation); ++ lpfc_port_auth_failed(ndlp, LPFC_AUTH_FAIL_AUTH_RJT); + vport->auth.auth_msg_state = LPFC_AUTH_REJECT; + if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (phba->link_state != LPFC_CLEAR_LA)) { +@@ -7040,6 +7041,8 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; ++ enum auth_state auth_state; ++ struct ls_rjt stat; + + /* Check to see if link went down during discovery */ + if (lpfc_els_chk_latt(vport)) { +@@ -7049,9 +7052,19 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + } + + if (irsp->ulpStatus) { ++ auth_state = LPFC_AUTH_FAIL; + if (irsp->ulpStatus == IOSTAT_LS_RJT) { ++ stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "1043 Authentication LS_RJT\n"); ++ if (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY) ++ auth_state = LPFC_AUTH_FAIL_LS_RJT_BUSY; ++ else ++ auth_state = LPFC_AUTH_FAIL_LS_RJT_GEN; ++ } else if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT && ++ (irsp->un.ulpWord[4] & 0xff) == ++ IOERR_SEQUENCE_TIMEOUT) { ++ auth_state = LPFC_AUTH_FAIL_ELS_TMO; + } + /* Check for retry */ + if (!lpfc_els_retry(phba, cmdiocb, rspiocb)) { +@@ -7063,7 +7076,7 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + } + if (vport->auth.auth_mode == FC_AUTHMODE_ACTIVE) { + lpfc_can_disctmo(vport); +- lpfc_port_auth_failed(ndlp); ++ lpfc_port_auth_failed(ndlp, auth_state); + } + } + if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 502a9a5..358e9de 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -754,17 +754,18 @@ lpfc_linkdown_port(struct lpfc_vport *vport) + vport->port_state, vport->fc_ns_retry, vport->fc_flag); + + lpfc_port_link_failure(vport); +- +- vport->auth.auth_state = LPFC_AUTH_UNKNOWN; +- vport->auth.auth_msg_state = LPFC_AUTH_NONE; ++ if (vport->auth.auth_state < LPFC_AUTH_FAIL) { ++ vport->auth.auth_state = LPFC_AUTH_UNKNOWN; ++ vport->auth.auth_msg_state = LPFC_AUTH_NONE; ++ } + } + + void +-lpfc_port_auth_failed(struct lpfc_nodelist *ndlp) ++lpfc_port_auth_failed(struct lpfc_nodelist *ndlp, enum auth_state fail_state) + { + struct lpfc_vport *vport = ndlp->vport; + +- vport->auth.auth_state = LPFC_AUTH_FAIL; ++ vport->auth.auth_state = fail_state; + vport->auth.auth_msg_state = LPFC_AUTH_NONE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + if (ndlp->nlp_type & NLP_FABRIC) { +@@ -886,6 +887,8 @@ lpfc_linkup_port(struct lpfc_vport *vport) + if (vport->fc_flag & FC_LBIT) + lpfc_linkup_cleanup_nodes(vport); + ++ vport->auth.auth_state = LPFC_AUTH_UNKNOWN; ++ vport->auth.auth_msg_state = LPFC_AUTH_NONE; + } + + static int +diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h +index 90d0c5a..c77d49e 100644 +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -2404,6 +2404,30 @@ typedef struct { + #define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */ + #define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */ + ++#define WAKE_UP_PARMS_REGION_ID 4 ++#define WAKE_UP_PARMS_WORD_SIZE 15 ++ ++/* Option rom version structure */ ++struct prog_id { ++#ifdef __BIG_ENDIAN_BITFIELD ++ uint8_t type; ++ uint8_t id; ++ uint32_t ver:4; /* Major Version */ ++ uint32_t rev:4; /* Revision */ ++ uint32_t lev:2; /* Level */ ++ uint32_t dist:2; /* Dist Type */ ++ uint32_t num:4; /* number after dist type */ ++#else /* __LITTLE_ENDIAN_BITFIELD */ ++ uint32_t num:4; /* number after dist type */ ++ uint32_t dist:2; /* Dist Type */ ++ uint32_t lev:2; /* Level */ ++ uint32_t rev:4; /* Revision */ ++ uint32_t ver:4; /* Major Version */ ++ uint8_t id; ++ uint8_t type; ++#endif ++}; ++ + /* Structure for MB Command UPDATE_CFG (0x1B) */ + + struct update_cfg_var { +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index c0ea4fc..c151651 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -271,6 +271,48 @@ lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) + } + + /** ++ * lpfc_dump_wakeup_param_cmpl: Completion handler for dump memory mailbox ++ * command used for getting wake up parameters. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmboxq: pointer to the driver internal queue element for mailbox command. ++ * ++ * This is the completion handler for dump mailbox command for getting ++ * wake up parameters. When this command complete, the response contain ++ * Option rom version of the HBA. This function translate the version number ++ * into a human readable string and store it in OptionROMVersion. ++ **/ ++static void ++lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) ++{ ++ struct prog_id *prg; ++ uint32_t prog_id_word; ++ char dist = ' '; ++ /* character array used for decoding dist type. */ ++ char dist_char[] = "nabx"; ++ ++ if (pmboxq->mb.mbxStatus != MBX_SUCCESS) ++ return; ++ ++ prg = (struct prog_id *) &prog_id_word; ++ ++ /* word 7 contain option rom version */ ++ prog_id_word = pmboxq->mb.un.varWords[7]; ++ ++ /* Decode the Option rom version word to a readable string */ ++ if (prg->dist < 4) ++ dist = dist_char[prg->dist]; ++ ++ if ((prg->dist == 3) && (prg->num == 0)) ++ sprintf(phba->OptionROMVersion, "%d.%d%d", ++ prg->ver, prg->rev, prg->lev); ++ else ++ sprintf(phba->OptionROMVersion, "%d.%d%d%c%d", ++ prg->ver, prg->rev, prg->lev, ++ dist, prg->num); ++ return; ++} ++ ++/** + * lpfc_config_port_post: Perform lpfc initialization after config port. + * @phba: pointer to lpfc hba data structure. + * +@@ -528,6 +570,20 @@ lpfc_config_port_post(struct lpfc_hba *phba) + rc); + mempool_free(pmb, phba->mbox_mem_pool); + } ++ ++ /* Get Option rom version */ ++ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); ++ lpfc_dump_wakeup_param(phba, pmb); ++ pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl; ++ pmb->vport = phba->pport; ++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); ++ ++ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed " ++ "to get Option ROM version status x%x\n.", rc); ++ mempool_free(pmb, phba->mbox_mem_pool); ++ } ++ + return 0; + } + +@@ -2014,7 +2070,12 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) + struct Scsi_Host *shost; + int error = 0; + +- shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport)); ++ if (dev != &phba->pcidev->dev) ++ shost = scsi_host_alloc(&lpfc_vport_template, ++ sizeof(struct lpfc_vport)); ++ else ++ shost = scsi_host_alloc(&lpfc_template, ++ sizeof(struct lpfc_vport)); + if (!shost) + goto out; + +@@ -2097,8 +2158,6 @@ destroy_port(struct lpfc_vport *vport) + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; + +- kfree(vport->vname); +- + lpfc_debugfs_terminate(vport); + fc_remove_host(shost); + scsi_remove_host(shost); +@@ -2862,7 +2921,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(&phba->hbalock); + +- kfree(vport->vname); + lpfc_free_sysfs_attr(vport); + + kthread_stop(phba->worker_thread); +diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c +index 184fe62..f0ab456 100644 +--- a/drivers/scsi/lpfc/lpfc_mbox.c ++++ b/drivers/scsi/lpfc/lpfc_mbox.c +@@ -77,6 +77,38 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) + } + + /** ++ * lpfc_dump_mem: Prepare a mailbox command for retrieving wakeup params. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * This function create a dump memory mailbox command to dump wake up ++ * parameters. ++ */ ++void ++lpfc_dump_wakeup_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ++{ ++ MAILBOX_t *mb; ++ void *ctx; ++ ++ mb = &pmb->mb; ++ /* Save context so that we can restore after memset */ ++ ctx = pmb->context2; ++ ++ /* Setup to dump VPD region */ ++ memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); ++ mb->mbxCommand = MBX_DUMP_MEMORY; ++ mb->mbxOwner = OWN_HOST; ++ mb->un.varDmp.cv = 1; ++ mb->un.varDmp.type = DMP_NV_PARAMS; ++ mb->un.varDmp.entry_index = 0; ++ mb->un.varDmp.region_id = WAKE_UP_PARMS_REGION_ID; ++ mb->un.varDmp.word_cnt = WAKE_UP_PARMS_WORD_SIZE; ++ mb->un.varDmp.co = 0; ++ mb->un.varDmp.resp_offset = 0; ++ pmb->context2 = ctx; ++ return; ++} ++ ++/** + * lpfc_read_nv: Prepare a mailbox command for reading HBA's NVRAM param. + * @phba: pointer to lpfc hba data structure. + * @pmb: pointer to the driver internal queue element for mailbox command. +diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h +index 991ad53..27d1a88 100644 +--- a/drivers/scsi/lpfc/lpfc_nl.h ++++ b/drivers/scsi/lpfc/lpfc_nl.h +@@ -22,18 +22,20 @@ + #define FC_REG_LINK_EVENT 0x0001 /* link up / down events */ + #define FC_REG_RSCN_EVENT 0x0002 /* RSCN events */ + #define FC_REG_CT_EVENT 0x0004 /* CT request events */ +-#define FC_REG_DUMP_EVENT 0x0008 /* Dump events */ +-#define FC_REG_TEMPERATURE_EVENT 0x0010 /* temperature events */ +-#define FC_REG_ELS_EVENT 0x0020 /* lpfc els events */ +-#define FC_REG_FABRIC_EVENT 0x0040 /* lpfc fabric events */ +-#define FC_REG_SCSI_EVENT 0x0080 /* lpfc scsi events */ +-#define FC_REG_BOARD_EVENT 0x0100 /* lpfc board events */ +-#define FC_REG_ADAPTER_EVENT 0x0200 /* lpfc adapter events */ ++#define FC_REG_DUMP_EVENT 0x0010 /* Dump events */ ++#define FC_REG_TEMPERATURE_EVENT 0x0020 /* temperature events */ ++#define FC_REG_VPORTRSCN_EVENT 0x0040 /* Vport RSCN events */ ++#define FC_REG_ELS_EVENT 0x0080 /* lpfc els events */ ++#define FC_REG_FABRIC_EVENT 0x0100 /* lpfc fabric events */ ++#define FC_REG_SCSI_EVENT 0x0200 /* lpfc scsi events */ ++#define FC_REG_BOARD_EVENT 0x0400 /* lpfc board events */ ++#define FC_REG_ADAPTER_EVENT 0x0800 /* lpfc adapter events */ + #define FC_REG_EVENT_MASK (FC_REG_LINK_EVENT | \ + FC_REG_RSCN_EVENT | \ + FC_REG_CT_EVENT | \ + FC_REG_DUMP_EVENT | \ + FC_REG_TEMPERATURE_EVENT | \ ++ FC_REG_VPORTRSCN_EVENT | \ + FC_REG_ELS_EVENT | \ + FC_REG_FABRIC_EVENT | \ + FC_REG_SCSI_EVENT | \ +diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c +index a7ea952..fed32ff 100644 +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -1842,7 +1842,7 @@ struct scsi_host_template lpfc_template = { + .info = lpfc_info, + .queuecommand = lpfc_queuecommand, + .eh_abort_handler = lpfc_abort_handler, +- .eh_device_reset_handler= lpfc_device_reset_handler, ++ .eh_device_reset_handler = lpfc_device_reset_handler, + .eh_bus_reset_handler = lpfc_bus_reset_handler, + .slave_alloc = lpfc_slave_alloc, + .slave_configure = lpfc_slave_configure, +@@ -1856,3 +1856,22 @@ struct scsi_host_template lpfc_template = { + .max_sectors = 0xFFFF, + }; + ++struct scsi_host_template lpfc_vport_template = { ++ .module = THIS_MODULE, ++ .name = LPFC_DRIVER_NAME, ++ .info = lpfc_info, ++ .queuecommand = lpfc_queuecommand, ++ .eh_abort_handler = lpfc_abort_handler, ++ .eh_device_reset_handler = lpfc_device_reset_handler, ++ .eh_bus_reset_handler = lpfc_bus_reset_handler, ++ .slave_alloc = lpfc_slave_alloc, ++ .slave_configure = lpfc_slave_configure, ++ .slave_destroy = lpfc_slave_destroy, ++ .scan_finished = lpfc_scan_finished, ++ .this_id = -1, ++ .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, ++ .cmd_per_lun = LPFC_CMD_PER_LUN, ++ .use_clustering = ENABLE_CLUSTERING, ++ .shost_attrs = lpfc_vport_attrs, ++ .max_sectors = 0xFFFF, ++}; +diff --git a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c +index d136f67..c0fbe56 100644 +--- a/drivers/scsi/lpfc/lpfc_security.c ++++ b/drivers/scsi/lpfc/lpfc_security.c +@@ -263,7 +263,7 @@ lpfc_reauthentication_handler(struct lpfc_nodelist *ndlp) + lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, + "1029 Reauthentication Failure\n"); + if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) +- lpfc_port_auth_failed(ndlp); ++ lpfc_port_auth_failed(ndlp, LPFC_AUTH_FAIL); + } + } + +diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +index a42cef2..57b559a 100644 +--- a/drivers/scsi/lpfc/lpfc_version.h ++++ b/drivers/scsi/lpfc/lpfc_version.h +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.3" ++#define LPFC_DRIVER_VERSION "8.2.8.4" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" +diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c +index c3a3f6e..ae8256d 100644 +--- a/drivers/scsi/lpfc/lpfc_vport.c ++++ b/drivers/scsi/lpfc/lpfc_vport.c +@@ -289,10 +289,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) + int vpi; + int rc = VPORT_ERROR; + int status; +- int size; + +- if ((phba->sli_rev < 3) || +- !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { ++ if ((phba->sli_rev < 3) || !(phba->cfg_enable_npiv)) { + lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + "1808 Create VPORT failed: " + "NPIV is not enabled: SLImode:%d\n", +@@ -352,20 +350,6 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) + + memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); + memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); +- size = strnlen(fc_vport->symbolic_name, LPFC_VNAME_LEN); +- if (size) { +- vport->vname = kzalloc(size+1, GFP_KERNEL); +- if (!vport->vname) { +- lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, +- "1814 Create VPORT failed. " +- "vname allocation failed.\n"); +- rc = VPORT_ERROR; +- lpfc_free_vpi(phba, vpi); +- destroy_port(vport); +- goto error_out; +- } +- memcpy(vport->vname, fc_vport->symbolic_name, size+1); +- } + if (fc_vport->node_name != 0) + u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); + if (fc_vport->port_name != 0) +@@ -410,6 +394,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) + } + } + ++ /* Create binary sysfs attribute for vport */ ++ lpfc_alloc_sysfs_attr(vport); ++ + *(struct lpfc_vport **)fc_vport->dd_data = vport; + vport->fc_vport = fc_vport; + +@@ -421,6 +408,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) + } + + if (disable) { ++ lpfc_vport_set_state(vport, FC_VPORT_DISABLED); + rc = VPORT_OK; + goto out; + } +@@ -603,7 +591,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport) + spin_lock_irq(&phba->hbalock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(&phba->hbalock); +- kfree(vport->vname); ++ ++ lpfc_free_sysfs_attr(vport); ++ + lpfc_debugfs_terminate(vport); + + /* Remove FC host and then SCSI host with the vport */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.7-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.7-update new file mode 100644 index 000000000..9914a87c9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.7-update @@ -0,0 +1,1676 @@ +From: Jamie Wellnitz +Subject: Update lpfc to 8.2.8.7 +References: bnc#420767 + +This patch updates the SLES 11 inbox lpfc driver 8.2.8.7, which fixes several +issues we've found in testing on SLES 11 Beta. + +* Changed version number to 8.2.8.7 +* Fixed system lockup problem when HBA is in MSI-X mode (CR 85802, 85441) +* Fixed slow vport deletes +* Fixed locking issue when lpfc_ioctl_send_mgmt_cmd fails to allocate buffer +* Changed mdelay to msleep in the ioctl path (CR 85606) +* Fixed a discovery issue (CR 85714) +* Extended Error Handling (EEH) support on IBM PowerPC P6 platform (CR 85671) +* Fix allocation of HBQs should not be done in interrupt context (CR 84717) +* Fixed loopback tests not working if auth enabled but auth service not + available (CR 85334) +* Changed version number to 8.2.8.6 +* Fix memory leaks in netlink send code +* Fixed fail-to-enable INTx when auth is enabled but auth service is not + running (CR 85162) +* Fix build warning of uninitialized variable in lpfc_enable_intr +* Fix crash when running latency test (CR 85257) +* Fixed missing CNA attribute for sysfs (CR 85265) +* Fixed false overrun failure for menlo commands that are less than the command + header size (CR 85168) +* Fixed mbuf leak when lpfc_pci_probe_one hit an error exit in SLI-2 mode +* Fix memory leak with dump mailbox completion +* Fix bpl size to reflect the correct buffer's size +* Fixed lpfc install problem for SLES 11 Beta2 (CR 84623) +* Fix driver online notification to come after port is added to auth list +* Added active interrupt test and automatic fallback for enabling + MSI/MSI-X/INTx (CR 84266) +* Fixed NULL pointer dereference in lpfc_prep_els_iocb (CR 84470) +* Fixed time out handling in the worker thread (CR 84540) +* Changed version number to 8.2.8.5 +* Small cleanup to match upstream 8.2.8 changes +* Fix bug with Interrupt Enable Block support (CR 84106) +* Applied pci_max_read fix from 8.2.0.x driver series (CR 84414) +* Added support for hps bit (CR 84425 84428) + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h +index 7508dea..7bb7971 100644 +--- a/drivers/scsi/lpfc/lpfc.h ++++ b/drivers/scsi/lpfc/lpfc.h +@@ -73,6 +73,9 @@ struct lpfc_sli2_slim; + /* Number of MSI-X vectors the driver uses */ + #define LPFC_MSIX_VECTORS 2 + ++/* Active interrupt test threshold */ ++#define LPFC_INTR_THRESHOLD 1 ++ + /* lpfc wait event data ready flag */ + #define LPFC_DATA_READY (1<<0) + +@@ -629,6 +632,7 @@ struct lpfc_hba { + uint32_t cfg_hba_queue_depth; + uint32_t cfg_enable_hba_reset; + uint32_t cfg_enable_hba_heartbeat; ++ uint32_t cfg_pci_max_read; + + lpfc_vpd_t vpd; /* vital product data */ + +@@ -718,6 +722,8 @@ struct lpfc_hba { + + struct fc_host_statistics link_stats; + enum intr_type_t intr_type; ++ uint32_t intr_mode; ++#define LPFC_INTR_ERROR 0xFFFFFFFF + struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; + struct lpfcdfc_host *dfc_host; + +diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +index 1069491..2140408 100644 +--- a/drivers/scsi/lpfc/lpfc_attr.c ++++ b/drivers/scsi/lpfc/lpfc_attr.c +@@ -42,6 +42,7 @@ + #include "lpfc_crtn.h" + #include "lpfc_vport.h" + #include "lpfc_auth_access.h" ++#include "lpfc_security.h" + + #define LPFC_DEF_DEVLOSS_TMO 30 + #define LPFC_MIN_DEVLOSS_TMO 1 +@@ -3100,6 +3101,27 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat."); + */ + LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, + LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); ++/* ++ * lpfc_pci_max_read: Maximum DMA read byte count. This parameter can have ++ * values 512, 1024, 2048, 4096. Default value is 2048. ++ */ ++static int lpfc_pci_max_read = 2048; ++module_param(lpfc_pci_max_read, int, 0); ++MODULE_PARM_DESC(lpfc_pci_max_read, ++ "Maximum DMA read byte count. Allowed values:" ++ " 512,1024,2048,4096."); ++static int ++lpfc_pci_max_read_init(struct lpfc_hba *phba, int val) ++{ ++ phba->cfg_pci_max_read = 2048; ++ if ((val == 512) || (val == 1024) || (val == 2048) || (val == 4096)) ++ phba->cfg_pci_max_read = val; ++ return 0; ++} ++ ++lpfc_param_show(pci_max_read) ++static DEVICE_ATTR(lpfc_pci_max_read, S_IRUGO, ++ lpfc_pci_max_read_show, NULL); + + struct device_attribute *lpfc_hba_attrs[] = { + &dev_attr_info, +@@ -3136,6 +3158,7 @@ struct device_attribute *lpfc_hba_attrs[] = { + &dev_attr_lpfc_fdmi_on, + &dev_attr_lpfc_max_luns, + &dev_attr_lpfc_enable_npiv, ++ &dev_attr_lpfc_pci_max_read, + &dev_attr_nport_evt_cnt, + &dev_attr_board_mode, + &dev_attr_max_vpi, +@@ -4176,12 +4199,22 @@ lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) + if (error) + goto out_remove_ctlreg_attr; + ++ error = sysfs_create_bin_file(&shost->shost_dev.kobj, ++ &sysfs_menlo_attr); ++ if (error) ++ goto out_remove_menlo_attr; ++ ++ + return 0; + out_remove_ctlreg_attr: + sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); + out_remove_stat_attr: + sysfs_remove_bin_file(&shost->shost_dev.kobj, + &sysfs_drvr_stat_data_attr); ++out_remove_menlo_attr: ++ sysfs_remove_bin_file(&shost->shost_dev.kobj, ++ &sysfs_menlo_attr); ++ + out: + return error; + } +@@ -4269,6 +4302,13 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) + if (vport->fc_flag & FC_OFFLINE_MODE) + fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; + else { ++ if ((vport->cfg_enable_auth) && ++ (lpfc_security_service_state == SECURITY_OFFLINE)) { ++ fc_host_port_state(shost) = FC_PORTSTATE_ERROR; ++ spin_unlock_irq(shost->host_lock); ++ return; ++ } ++ + switch (phba->link_state) { + case LPFC_LINK_UNKNOWN: + case LPFC_LINK_DOWN: +@@ -4837,6 +4877,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) + lpfc_link_speed_init(phba, lpfc_link_speed); + lpfc_poll_tmo_init(phba, lpfc_poll_tmo); + lpfc_enable_npiv_init(phba, lpfc_enable_npiv); ++ lpfc_pci_max_read_init(phba, lpfc_pci_max_read); + lpfc_use_msi_init(phba, lpfc_use_msi); + lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); + lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); +diff --git a/drivers/scsi/lpfc/lpfc_auth_access.c b/drivers/scsi/lpfc/lpfc_auth_access.c +index 7481eb0..9f48c59 100644 +--- a/drivers/scsi/lpfc/lpfc_auth_access.c ++++ b/drivers/scsi/lpfc/lpfc_auth_access.c +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2006-2007 Emulex. All rights reserved. * ++ * Copyright (C) 2006-2008 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * +@@ -213,10 +213,11 @@ lpfc_fc_sc_request(struct lpfc_vport *vport, + fc_sc_req->tran_id = seq; + + len = sizeof(struct fc_nl_sc_message) + auth_req_len; +- fc_nl_sc_msg = kzalloc(sizeof(struct fc_nl_sc_message) + auth_req_len, +- GFP_KERNEL); +- if (!fc_nl_sc_msg) ++ fc_nl_sc_msg = kzalloc(len, GFP_KERNEL); ++ if (!fc_nl_sc_msg) { ++ kfree(fc_sc_req); + return -ENOMEM; ++ } + fc_nl_sc_msg->msgtype = msg_type; + fc_nl_sc_msg->data_len = auth_req_len; + memcpy(fc_nl_sc_msg->data, auth_req, auth_req_len); +@@ -228,6 +229,7 @@ lpfc_fc_sc_request(struct lpfc_vport *vport, + scsi_nl_send_vendor_msg(fc_service_pid, shost->host_no, + (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX), + (char *) fc_nl_sc_msg, len); ++ kfree(fc_nl_sc_msg); + lpfc_fc_sc_add_timer(fc_sc_req, FC_SC_REQ_TIMEOUT, + lpfc_fc_sc_req_times_out); + return 0; +diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +index 380acef..cedbfea 100644 +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -43,6 +43,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); + int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, + LPFC_MBOXQ_t *, uint32_t); ++void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); + void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); + void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); + void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); +@@ -166,6 +167,8 @@ void lpfc_offline(struct lpfc_hba *); + + int lpfc_sli_setup(struct lpfc_hba *); + int lpfc_sli_queue_setup(struct lpfc_hba *); ++int lpfc_sli_set_dma_length(struct lpfc_hba *, uint32_t); ++ + + void lpfc_handle_eratt(struct lpfc_hba *); + void lpfc_handle_latt(struct lpfc_hba *); +diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c +index 7fecdbb..896c7b0 100644 +--- a/drivers/scsi/lpfc/lpfc_ct.c ++++ b/drivers/scsi/lpfc/lpfc_ct.c +@@ -560,18 +560,25 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry); + + /* Don't bother processing response if vport is being torn down. */ +- if (vport->load_flag & FC_UNLOADING) ++ if (vport->load_flag & FC_UNLOADING) { ++ if (vport->fc_flag & FC_RSCN_MODE) ++ lpfc_els_flush_rscn(vport); + goto out; ++ } + + if (lpfc_els_chk_latt(vport)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "0216 Link event during NS query\n"); ++ if (vport->fc_flag & FC_RSCN_MODE) ++ lpfc_els_flush_rscn(vport); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + goto out; + } + if (lpfc_error_lost_link(irsp)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "0226 NS query failed due to link event\n"); ++ if (vport->fc_flag & FC_RSCN_MODE) ++ lpfc_els_flush_rscn(vport); + goto out; + } + if (irsp->ulpStatus) { +@@ -587,6 +594,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + if (rc == 0) + goto out; + } ++ if (vport->fc_flag & FC_RSCN_MODE) ++ lpfc_els_flush_rscn(vport); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0257 GID_FT Query error: 0x%x 0x%x\n", +diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c +index 3f58a4b..69f92e8 100644 +--- a/drivers/scsi/lpfc/lpfc_els.c ++++ b/drivers/scsi/lpfc/lpfc_els.c +@@ -278,7 +278,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, + return elsiocb; + + els_iocb_free_pbuf_exit: +- lpfc_mbuf_free(phba, prsp->virt, prsp->phys); ++ if (expectRsp) ++ lpfc_mbuf_free(phba, prsp->virt, prsp->phys); + kfree(pbuflist); + + els_iocb_free_prsp_exit: +@@ -943,6 +944,10 @@ lpfc_initial_flogi(struct lpfc_vport *vport) + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + ++ if ((vport->cfg_enable_auth) && ++ (lpfc_security_service_state == SECURITY_OFFLINE)) ++ return 1; ++ + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + +@@ -4985,10 +4990,6 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) + uint32_t timeout; + uint32_t remote_ID = 0xffffffff; + +- /* If the timer is already canceled do nothing */ +- if ((vport->work_port_events & WORKER_ELS_TMO) == 0) { +- return; +- } + spin_lock_irq(&phba->hbalock); + timeout = (uint32_t)(phba->fc_ratov << 1); + +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 358e9de..f02c2bb 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -39,6 +39,7 @@ + #include "lpfc_crtn.h" + #include "lpfc_vport.h" + #include "lpfc_debugfs.h" ++#include "lpfc_security.h" + + /* AlpaArray for assignment of scsid for scan-down and bind_method */ + static uint8_t lpfcAlpaArray[] = { +@@ -1008,9 +1009,12 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + /* Start discovery by sending a FLOGI. port_state is identically + * LPFC_FLOGI while waiting for FLOGI cmpl + */ +- if (vport->port_state != LPFC_FLOGI) { ++ if ((vport->cfg_enable_auth) && ++ (lpfc_security_service_state == SECURITY_OFFLINE)) ++ lpfc_issue_clear_la(phba, vport); ++ else if (vport->port_state != LPFC_FLOGI) + lpfc_initial_flogi(vport); +- } ++ + return; + + out: +diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h +index c77d49e..f9a42f6 100644 +--- a/drivers/scsi/lpfc/lpfc_hw.h ++++ b/drivers/scsi/lpfc/lpfc_hw.h +@@ -2370,6 +2370,14 @@ typedef struct { + uint32_t rsvd1; + } CLEAR_LA_VAR; + ++/* Structure for MB Command SET_SLIM (33) */ ++/* Values needed to set MAX_DMA_LENGTH parameter */ ++#define SLIM_VAR_MAX_DMA_LENGTH 0x100506 ++#define SLIM_VAL_MAX_DMA_512 0x0 ++#define SLIM_VAL_MAX_DMA_1024 0x1 ++#define SLIM_VAL_MAX_DMA_2048 0x2 ++#define SLIM_VAL_MAX_DMA_4096 0x3 ++ + /* Structure for MB Command DUMP */ + + typedef struct { +@@ -2621,10 +2629,17 @@ typedef struct { + + uint32_t pcbLow; /* bit 31:0 of memory based port config block */ + uint32_t pcbHigh; /* bit 63:32 of memory based port config block */ +- uint32_t hbainit[6]; ++ uint32_t hbainit[5]; ++#ifdef __BIG_ENDIAN_BITFIELD ++ uint32_t hps : 1; /* bit 31 word9 Host Pointer in slim */ ++ uint32_t rsvd : 31; /* least significant 31 bits of word 9 */ ++#else /* __LITTLE_ENDIAN */ ++ uint32_t rsvd : 31; /* least significant 31 bits of word 9 */ ++ uint32_t hps : 1; /* bit 31 word9 Host Pointer in slim */ ++#endif + + #ifdef __BIG_ENDIAN_BITFIELD +- uint32_t rsvd : 24; /* Reserved */ ++ uint32_t rsvd1 : 24; /* Reserved */ + uint32_t cmv : 1; /* Configure Max VPIs */ + uint32_t ccrp : 1; /* Config Command Ring Polling */ + uint32_t csah : 1; /* Configure Synchronous Abort Handling */ +@@ -2642,7 +2657,7 @@ typedef struct { + uint32_t csah : 1; /* Configure Synchronous Abort Handling */ + uint32_t ccrp : 1; /* Config Command Ring Polling */ + uint32_t cmv : 1; /* Configure Max VPIs */ +- uint32_t rsvd : 24; /* Reserved */ ++ uint32_t rsvd1 : 24; /* Reserved */ + #endif + #ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd2 : 24; /* Reserved */ +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index c151651..4032bda 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -290,8 +290,10 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) + /* character array used for decoding dist type. */ + char dist_char[] = "nabx"; + +- if (pmboxq->mb.mbxStatus != MBX_SUCCESS) ++ if (pmboxq->mb.mbxStatus != MBX_SUCCESS) { ++ mempool_free(pmboxq, phba->mbox_mem_pool); + return; ++ } + + prg = (struct prog_id *) &prog_id_word; + +@@ -309,6 +311,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) + sprintf(phba->OptionROMVersion, "%d.%d%d%c%d", + prg->ver, prg->rev, prg->lev, + dist, prg->num); ++ mempool_free(pmboxq, phba->mbox_mem_pool); + return; + } + +@@ -521,22 +524,46 @@ lpfc_config_port_post(struct lpfc_hba *phba) + /* Set up error attention (ERATT) polling timer */ + mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + ++ /* Use the existing MBOX buffer, it will be freed in mbox compl */ ++ lpfc_config_async(phba, pmb, LPFC_ELS_RING); ++ pmb->mbox_cmpl = lpfc_config_async_cmpl; ++ pmb->vport = phba->pport; ++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); ++ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0456 Adapter failed to issue " ++ "ASYNCEVT_ENABLE mbox status x%x \n.", rc); ++ mempool_free(pmb, phba->mbox_mem_pool); ++ } ++ ++ /* Allocate new MBOX buffer, it will be freed in mbox compl */ ++ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); ++ lpfc_dump_wakeup_param(phba, pmb); ++ pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl; ++ pmb->vport = phba->pport; ++ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); ++ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0435 Adapter failed to get Option " ++ "ROM version status x%x\n.", rc); ++ mempool_free(pmb, phba->mbox_mem_pool); ++ } ++ + if (vport->cfg_enable_auth) { + if (lpfc_security_service_state == SECURITY_OFFLINE) { + lpfc_printf_log(vport->phba, KERN_ERR, LOG_SECURITY, + "1000 Authentication is enabled but " + "authentication service is not running\n"); + vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; +- phba->link_state = LPFC_HBA_ERROR; +- mempool_free(pmb, phba->mbox_mem_pool); +- return 0; + } + } + ++ /* Allocate new MBOX buffer, will be freed in mbox compl */ ++ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); +- if (rc != MBX_SUCCESS) { ++ if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0454 Adapter failed to init, mbxCmd x%x " + "INIT_LINK, mbxStatus x%x\n", +@@ -550,40 +577,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) + readl(phba->HAregaddr); /* flush */ + + phba->link_state = LPFC_HBA_ERROR; +- if (rc != MBX_BUSY) +- mempool_free(pmb, phba->mbox_mem_pool); +- return -EIO; +- } +- /* MBOX buffer will be freed in mbox compl */ +- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); +- lpfc_config_async(phba, pmb, LPFC_ELS_RING); +- pmb->mbox_cmpl = lpfc_config_async_cmpl; +- pmb->vport = phba->pport; +- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); +- +- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { +- lpfc_printf_log(phba, +- KERN_ERR, +- LOG_INIT, +- "0456 Adapter failed to issue " +- "ASYNCEVT_ENABLE mbox status x%x \n.", +- rc); +- mempool_free(pmb, phba->mbox_mem_pool); +- } +- +- /* Get Option rom version */ +- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); +- lpfc_dump_wakeup_param(phba, pmb); +- pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl; +- pmb->vport = phba->pport; +- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); +- +- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed " +- "to get Option ROM version status x%x\n.", rc); + mempool_free(pmb, phba->mbox_mem_pool); ++ return -EIO; + } +- + return 0; + } + +@@ -788,11 +784,6 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) + return; + + spin_lock_irq(&phba->pport->work_port_lock); +- /* If the timer is already canceled do nothing */ +- if (!(phba->pport->work_port_events & WORKER_HB_TMO)) { +- spin_unlock_irq(&phba->pport->work_port_lock); +- return; +- } + + if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ, + jiffies)) { +@@ -2307,6 +2298,51 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) + } + + /** ++ * lpfc_setup_max_dma_length: Check the host's chipset and adjust HBA's ++ * max DMA length. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to test the machines chipsets. Some of Emulex's ++ * HBA models expose bugs in these chipsets. To work around these bugs we ++ * tell the HBA to use a smaller maxium DMA length. ++ * This routine is only called during module init. The DMA length is passed ++ * to the driver as a module parameter(lpfc_pci_max_read). ++ * ++ * return: NONE. ++ **/ ++void ++lpfc_setup_max_dma_length(struct lpfc_hba *phba) ++{ ++ struct pci_dev *pdev = phba->pcidev; ++ struct pci_bus *bus = pdev->bus; ++ uint8_t rev; ++ ++ while (bus) { ++ /* ++ * 0x7450 == PCI_DEVICE_ID_AMD_8131_BRIDGE for 2.6 kernels ++ * 0x7450 == PCI_DEVICE_ID_AMD_8131_APIC for 2.4 kernels ++ */ ++ if (bus->self && ++ (bus->self->vendor == PCI_VENDOR_ID_AMD) && ++ (bus->self->device == 0x7450)) { ++ pci_read_config_byte(bus->self, 0x08, &rev); ++ if (rev == 0x13) { ++ /* ++ * If set a value in module paramter, ++ * use that value. ++ */ ++ if (phba->cfg_pci_max_read == 2048) ++ phba->cfg_pci_max_read = 1024; ++ return; ++ } ++ } ++ bus = bus->parent; ++ } ++ return; ++} ++ ++ ++/** + * lpfc_enable_msix: Enable MSI-X interrupt mode. + * @phba: pointer to lpfc hba data structure. + * +@@ -2340,8 +2376,7 @@ lpfc_enable_msix(struct lpfc_hba *phba) + ARRAY_SIZE(phba->msix_entries)); + if (rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0420 Enable MSI-X failed (%d), continuing " +- "with MSI\n", rc); ++ "0420 PCI enable MSI-X failed (%d)\n", rc); + goto msi_fail_out; + } else + for (i = 0; i < LPFC_MSIX_VECTORS; i++) +@@ -2358,9 +2393,9 @@ lpfc_enable_msix(struct lpfc_hba *phba) + rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler, + IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba); + if (rc) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0421 MSI-X slow-path request_irq failed " +- "(%d), continuing with MSI\n", rc); ++ "(%d)\n", rc); + goto msi_fail_out; + } + +@@ -2369,9 +2404,9 @@ lpfc_enable_msix(struct lpfc_hba *phba) + IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba); + + if (rc) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, + "0429 MSI-X fast-path request_irq failed " +- "(%d), continuing with MSI\n", rc); ++ "(%d)\n", rc); + goto irq_fail_out; + } + +@@ -2392,7 +2427,7 @@ lpfc_enable_msix(struct lpfc_hba *phba) + goto mbx_fail_out; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); + if (rc != MBX_SUCCESS) { +- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, ++ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, + "0351 Config MSI mailbox command failed, " + "mbxCmd x%x, mbxStatus x%x\n", + pmb->mb.mbxCommand, pmb->mb.mbxStatus); +@@ -2441,6 +2476,111 @@ lpfc_disable_msix(struct lpfc_hba *phba) + } + + /** ++ * lpfc_enable_msi: Enable MSI interrupt mode. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to enable the MSI interrupt mode. The kernel ++ * function pci_enable_msi() is called to enable the MSI vector. The ++ * device driver is responsible for calling the request_irq() to register ++ * MSI vector with a interrupt the handler, which is done in this function. ++ * ++ * Return codes ++ * 0 - sucessful ++ * other values - error ++ */ ++static int ++lpfc_enable_msi(struct lpfc_hba *phba) ++{ ++ int rc; ++ ++ rc = pci_enable_msi(phba->pcidev); ++ if (!rc) ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0462 PCI enable MSI mode success.\n"); ++ else { ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0471 PCI enable MSI mode failed (%d)\n", rc); ++ return rc; ++ } ++ ++ rc = request_irq(phba->pcidev->irq, lpfc_intr_handler, ++ IRQF_SHARED, LPFC_DRIVER_NAME, phba); ++ if (rc) { ++ pci_disable_msi(phba->pcidev); ++ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, ++ "0478 MSI request_irq failed (%d)\n", rc); ++ } ++ return rc; ++} ++ ++/** ++ * lpfc_disable_msi: Disable MSI interrupt mode. ++ * @phba: pointer to lpfc hba data structure. ++ * ++ * This routine is invoked to disable the MSI interrupt mode. The driver ++ * calls free_irq() on MSI vector it has done request_irq() on before ++ * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and ++ * a device will be left with MSI enabled and leaks its vector. ++ */ ++ ++static void ++lpfc_disable_msi(struct lpfc_hba *phba) ++{ ++ free_irq(phba->pcidev->irq, phba); ++ pci_disable_msi(phba->pcidev); ++ return; ++} ++ ++/** ++ * lpfc_log_intr_mode: Log the active interrupt mode ++ * @phba: pointer to lpfc hba data structure. ++ * @intr_mode: active interrupt mode adopted. ++ * ++ * This routine it invoked to log the currently used active interrupt mode ++ * to the device. ++ */ ++static void ++lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) ++{ ++ switch (intr_mode) { ++ case 0: ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0470 Enable INTx interrupt mode.\n"); ++ break; ++ case 1: ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0481 Enabled MSI interrupt mode.\n"); ++ break; ++ case 2: ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0480 Enabled MSI-X interrupt mode.\n"); ++ break; ++ default: ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0482 Illegal interrupt mode.\n"); ++ break; ++ } ++ return; ++} ++ ++static void ++lpfc_stop_port(struct lpfc_hba *phba) ++{ ++ /* Clear all interrupt enable conditions */ ++ writel(0, phba->HCregaddr); ++ readl(phba->HCregaddr); /* flush */ ++ /* Clear all pending interrupts */ ++ writel(0xffffffff, phba->HAregaddr); ++ readl(phba->HAregaddr); /* flush */ ++ ++ /* Reset some HBA SLI setup states */ ++ lpfc_stop_phba_timers(phba); ++ phba->pport->work_port_events = 0; ++ ++ return; ++} ++ ++/** + * lpfc_enable_intr: Enable device interrupt. + * @phba: pointer to lpfc hba data structure. + * +@@ -2454,60 +2594,47 @@ lpfc_disable_msix(struct lpfc_hba *phba) + * 0 - sucessful + * other values - error + **/ +-static int +-lpfc_enable_intr(struct lpfc_hba *phba) ++static uint32_t ++lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) + { +- int retval = 0; +- +- /* Starting point of configuring interrupt method */ +- phba->intr_type = NONE; ++ uint32_t intr_mode = LPFC_INTR_ERROR; ++ int retval; + +- if (phba->cfg_use_msi == 2) { ++ if (cfg_mode == 2) { + /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ + retval = lpfc_sli_config_port(phba, 3); +- if (retval) +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0478 Firmware not capable of SLI 3 mode.\n"); +- else { +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0479 Firmware capable of SLI 3 mode.\n"); ++ if (!retval) { + /* Now, try to enable MSI-X interrupt mode */ + retval = lpfc_enable_msix(phba); + if (!retval) { ++ /* Indicate initialization to MSI-X mode */ + phba->intr_type = MSIX; +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0480 enable MSI-X mode.\n"); ++ intr_mode = 2; + } + } + } + + /* Fallback to MSI if MSI-X initialization failed */ +- if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { +- retval = pci_enable_msi(phba->pcidev); ++ if (cfg_mode >= 1 && phba->intr_type == NONE) { ++ retval = lpfc_enable_msi(phba); + if (!retval) { ++ /* Indicate initialization to MSI mode */ + phba->intr_type = MSI; +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0481 enable MSI mode.\n"); +- } else +- lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +- "0470 enable IRQ mode.\n"); ++ intr_mode = 1; ++ } + } + +- /* MSI-X is the only case the doesn't need to call request_irq */ +- if (phba->intr_type != MSIX) { ++ /* Fallback to INTx if both MSI-X/MSI initalization failed */ ++ if (phba->intr_type == NONE) { + retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, + IRQF_SHARED, LPFC_DRIVER_NAME, phba); +- if (retval) { +- if (phba->intr_type == MSI) +- pci_disable_msi(phba->pcidev); +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0471 Enable interrupt handler " +- "failed\n"); +- } else if (phba->intr_type != MSI) ++ if (!retval) { ++ /* Indicate initialization to INTx mode */ + phba->intr_type = INTx; ++ intr_mode = 0; ++ } + } +- +- return retval; ++ return intr_mode; + } + + /** +@@ -2522,13 +2649,18 @@ lpfc_enable_intr(struct lpfc_hba *phba) + static void + lpfc_disable_intr(struct lpfc_hba *phba) + { ++ /* Disable the currently initialized interrupt mode */ + if (phba->intr_type == MSIX) + lpfc_disable_msix(phba); +- else { ++ else if (phba->intr_type == MSI) ++ lpfc_disable_msi(phba); ++ else if (phba->intr_type == INTx) + free_irq(phba->pcidev->irq, phba); +- if (phba->intr_type == MSI) +- pci_disable_msi(phba->pcidev); +- } ++ ++ /* Reset interrupt management states */ ++ phba->intr_type = NONE; ++ phba->sli.slistat.sli_intr = 0; ++ + return; + } + +@@ -2562,6 +2694,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + int error = -ENODEV, retval; + int i, hbq_count; + uint16_t iotag; ++ uint32_t cfg_mode, intr_mode; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + struct lpfc_adapter_event_header adapter_event; + +@@ -2593,6 +2726,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + * establish the host. + */ + lpfc_get_cfgparam(phba); ++ /* Check if we need to change the DMA length */ ++ lpfc_setup_max_dma_length(phba); ++ + phba->max_vpi = lpfc_hba_max_vpi(phba->pcidev->device); + + /* Initialize timers used by driver */ +@@ -2615,6 +2751,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + phba->eratt_poll.data = (unsigned long) phba; + + pci_set_master(pdev); ++ pci_save_state(pdev); + pci_try_set_mwi(pdev); + + if (pci_set_dma_mask(phba->pcidev, DMA_64BIT_MASK) != 0) +@@ -2769,9 +2906,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + + if ((lpfc_get_security_enabled)(shost)) { + unsigned long flags; +- /* Triggers fcauthd to register if it is running */ +- fc_host_post_event(shost, fc_get_event_number(), +- FCH_EVT_PORT_ONLINE, shost->host_no); + spin_lock_irqsave(&fc_security_user_lock, flags); + list_add_tail(&vport->sc_users, &fc_security_user_list); + spin_unlock_irqrestore(&fc_security_user_lock, flags); +@@ -2779,6 +2913,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + lpfc_fc_queue_security_work(vport, + &vport->sc_online_work); + } ++ /* Triggers fcauthd to register if it is running */ ++ fc_host_post_event(shost, fc_get_event_number(), ++ FCH_EVT_PORT_ONLINE, shost->host_no); + } + phba->pport = vport; + lpfc_debugfs_initialize(vport); +@@ -2791,34 +2928,66 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; + phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; + +- /* Configure and enable interrupt */ +- error = lpfc_enable_intr(phba); +- if (error) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0426 Failed to enable interrupt.\n"); +- goto out_destroy_port; +- } +- ++ /* Confiugre sysfs attributes */ + phba->dfc_host = lpfcdfc_host_add(pdev, shost, phba); + if (!phba->dfc_host) { + lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "1201 Failed to allocate dfc_host \n"); + error = -ENOMEM; +- goto out_free_irq; ++ goto out_destroy_port; + } + + if (lpfc_alloc_sysfs_attr(vport)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1476 Failed to allocate sysfs attr\n"); + error = -ENOMEM; +- goto out_free_irq; ++ goto out_del_dfc_host; + } + +- if (lpfc_sli_hba_setup(phba)) { +- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "1477 Failed to set up hba\n"); +- error = -ENODEV; +- goto out_remove_device; ++ cfg_mode = phba->cfg_use_msi; ++ while (true) { ++ /* Configure and enable interrupt */ ++ intr_mode = lpfc_enable_intr(phba, cfg_mode); ++ if (intr_mode == LPFC_INTR_ERROR) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0426 Failed to enable interrupt.\n"); ++ goto out_free_sysfs_attr; ++ } ++ /* HBA SLI setup */ ++ if (lpfc_sli_hba_setup(phba)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "1477 Failed to set up hba\n"); ++ error = -ENODEV; ++ goto out_remove_device; ++ } ++ ++ /* Wait 50ms for the interrupts of previous mailbox commands */ ++ msleep(50); ++ /* Check active interrupts received */ ++ if (phba->sli.slistat.sli_intr > LPFC_INTR_THRESHOLD) { ++ /* Log the current active interrupt mode */ ++ phba->intr_mode = intr_mode; ++ lpfc_log_intr_mode(phba, intr_mode); ++ break; ++ } else { ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "0451 Configure interrupt mode (%d) " ++ "failed active interrupt test.\n", ++ intr_mode); ++ if (intr_mode == 0) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "0479 Failed to enable " ++ "interrupt.\n"); ++ error = -ENODEV; ++ goto out_remove_device; ++ } ++ /* Stop HBA SLI setups */ ++ lpfc_stop_port(phba); ++ /* Disable the current interrupt mode */ ++ lpfc_disable_intr(phba); ++ /* Try next level of interrupt mode */ ++ cfg_mode = --intr_mode; ++ } + } + + /* +@@ -2850,16 +3019,19 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) + return 0; + + out_remove_device: +- lpfc_free_sysfs_attr(vport); + spin_lock_irq(shost->host_lock); + vport->load_flag |= FC_UNLOADING; + spin_unlock_irq(shost->host_lock); +-out_free_irq: +- if (phba->dfc_host) +- lpfcdfc_host_del(phba->dfc_host); + lpfc_stop_phba_timers(phba); + phba->pport->work_port_events = 0; + lpfc_disable_intr(phba); ++ lpfc_sli_hba_down(phba); ++ lpfc_sli_brdrestart(phba); ++out_free_sysfs_attr: ++ lpfc_free_sysfs_attr(vport); ++out_del_dfc_host: ++ if (phba->dfc_host) ++ lpfcdfc_host_del(phba->dfc_host); + out_destroy_port: + destroy_port(vport); + out_kthread_stop: +@@ -3051,6 +3223,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev) + { + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; ++ uint32_t intr_mode; + int error; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, +@@ -3073,19 +3246,22 @@ lpfc_pci_resume_one(struct pci_dev *pdev) + return error; + } + +- /* Enable interrupt from device */ +- error = lpfc_enable_intr(phba); +- if (error) { ++ /* Configure and enable interrupt */ ++ intr_mode = lpfc_enable_intr(phba, phba->intr_mode); ++ if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +- "0430 PM resume Failed to enable interrupt: " +- "error=x%x.\n", error); +- return error; +- } ++ "0430 PM resume Failed to enable interrupt\n"); ++ return -EIO; ++ } else ++ phba->intr_mode = intr_mode; + + /* Restart HBA and bring it online */ + lpfc_sli_brdrestart(phba); + lpfc_online(phba); + ++ /* Log the current active interrupt mode */ ++ lpfc_log_intr_mode(phba, phba->intr_mode); ++ + return 0; + } + +@@ -3161,7 +3337,7 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + struct lpfc_sli *psli = &phba->sli; +- int error; ++ uint32_t intr_mode; + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_mem(pdev)) { +@@ -3170,25 +3346,31 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) + return PCI_ERS_RESULT_DISCONNECT; + } + +- pci_set_master(pdev); ++ pci_restore_state(pdev); ++ if (pdev->is_busmaster) ++ pci_set_master(pdev); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + +- /* Enable configured interrupt method */ +- error = lpfc_enable_intr(phba); +- if (error) { ++ /* Configure and enable interrupt */ ++ intr_mode = lpfc_enable_intr(phba, phba->intr_mode); ++ if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0427 Cannot re-enable interrupt after " + "slot reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; +- } ++ } else ++ phba->intr_mode = intr_mode; + + /* Take device offline; this will perform cleanup */ + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + ++ /* Log the current active interrupt mode */ ++ lpfc_log_intr_mode(phba, phba->intr_mode); ++ + return PCI_ERS_RESULT_RECOVERED; + } + +diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c +index e80d157..127b47b 100644 +--- a/drivers/scsi/lpfc/lpfc_ioctl.c ++++ b/drivers/scsi/lpfc/lpfc_ioctl.c +@@ -162,7 +162,7 @@ lpfc_ioctl_hba_rnid(struct lpfc_hba * phba, + for (i0 = 0; + i0 < 10 && (pndl->nlp_flag & NLP_ELS_SND_MASK) == NLP_RNID_SND; + i0++) { +- mdelay(1000); ++ msleep(1000); + } + + if (i0 == 10) { +@@ -731,7 +731,6 @@ lpfc_ioctl_send_mgmt_cmd(struct lpfc_hba * phba, + outdmp = dfc_cmd_data_alloc(phba, NULL, bpl, snsbfrcnt); + if (!outdmp) { + rc = ENOMEM; +- spin_lock_irq(shost->host_lock); + goto send_mgmt_cmd_free_indmp; + } + +@@ -1104,7 +1103,7 @@ lpfc_ioctl_loopback_mode(struct lpfc_hba *phba, + if (i++ > 500) /* wait up to 5 seconds */ + break; + +- mdelay(10); ++ msleep(10); + } + + memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); +diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c +index f0ab456..84619ed 100644 +--- a/drivers/scsi/lpfc/lpfc_mbox.c ++++ b/drivers/scsi/lpfc/lpfc_mbox.c +@@ -835,6 +835,40 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) + } + + /** ++ * lpfc_set_var: Prepare a mailbox command to write slim. ++ * @phba: pointer to lpfc hba data structure. ++ * @pmb: pointer to the driver internal queue element for mailbox command. ++ * @addr: This the set variable number that identifies the variable. ++ * @value:The value that we are setting the parameter to. ++ * ++ * The routine just sets the addr and value in the set variable mailbox ++ * command structure. ++ * returns: NONE. ++ **/ ++void ++lpfc_set_var(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint32_t addr, ++ uint32_t value) ++{ ++ MAILBOX_t *mb; ++ ++ mb = &pmb->mb; ++ memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); ++ ++ /* ++ * Always turn on DELAYED ABTS for ELS timeouts ++ */ ++ if ((addr == 0x052198) && (value == 0)) ++ value = 1; ++ ++ mb->un.varWords[0] = addr; ++ mb->un.varWords[1] = value; ++ ++ mb->mbxCommand = MBX_SET_VARIABLE; ++ mb->mbxOwner = OWN_HOST; ++ return; ++} ++ ++/** + * lpfc_read_rev: Prepare a mailbox command for reading HBA revision. + * @phba: pointer to lpfc hba data structure. + * @pmb: pointer to the driver internal queue element for mailbox command. +@@ -1093,6 +1127,9 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); + mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); + ++ /* Always Host Group Pointer is in SLIM */ ++ mb->un.varCfgPort.hps = 1; ++ + /* If HBA supports SLI=3 ask for it */ + + if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) { +@@ -1195,16 +1232,11 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) + sizeof(*phba->host_gp)); + } + +- /* Setup Port Group ring pointer */ +- if (phba->sli3_options & LPFC_SLI3_INB_ENABLED) { +- pgp_offset = offsetof(struct lpfc_sli2_slim, +- mbx.us.s3_inb_pgp.port); +- phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get; +- } else if (phba->sli_rev == 3) { ++ /* Setup Port Group offset */ ++ if (phba->sli_rev == 3) + pgp_offset = offsetof(struct lpfc_sli2_slim, + mbx.us.s3_pgp.port); +- phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; +- } else ++ else + pgp_offset = offsetof(struct lpfc_sli2_slim, mbx.us.s2.port); + pdma_addr = phba->slim2p.phys + pgp_offset; + phba->pcb->pgpAddrHigh = putPaddrHigh(pdma_addr); +diff --git a/drivers/scsi/lpfc/lpfc_menlo.c b/drivers/scsi/lpfc/lpfc_menlo.c +index aa36c16..4f3b332 100644 +--- a/drivers/scsi/lpfc/lpfc_menlo.c ++++ b/drivers/scsi/lpfc/lpfc_menlo.c +@@ -289,19 +289,16 @@ static void + sysfs_menlo_idle(struct lpfc_hba *phba, + struct lpfc_sysfs_menlo *sysfs_menlo) + { +- struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); + + spin_lock_irq(&phba->hbalock); + list_del_init(&sysfs_menlo->list); + spin_unlock_irq(&phba->hbalock); +- spin_lock_irq(shost->host_lock); + + if (sysfs_menlo->cr.cmdiocbq) + sysfs_menlo_genreq_free(phba, &sysfs_menlo->cr); + if (sysfs_menlo->cx.cmdiocbq) + sysfs_menlo_genreq_free(phba, &sysfs_menlo->cx); + +- spin_unlock_irq(shost->host_lock); + kfree(sysfs_menlo); + } + +@@ -543,14 +540,15 @@ lpfc_menlo_write(struct lpfc_hba *phba, + } + + if ((count + sysfs_menlo->cr.offset) > sysfs_menlo->cmdhdr.cmdsize) { +- if ( sysfs_menlo->cmdhdr.cmdsize != 4) { +- lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, ++ if (sysfs_menlo->cmdhdr.cmdsize >= ++ sizeof(struct lpfc_sysfs_menlo_hdr)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, + "1213 FCoE cmd overflow: off %d + cnt %d > cmdsz %d\n", +- (int)sysfs_menlo->cr.offset, +- (int)count, +- (int)sysfs_menlo->cmdhdr.cmdsize); +- sysfs_menlo_idle(phba, sysfs_menlo); +- return -ERANGE; ++ (int)sysfs_menlo->cr.offset, ++ (int)count, ++ (int)sysfs_menlo->cmdhdr.cmdsize); ++ sysfs_menlo_idle(phba, sysfs_menlo); ++ return -ERANGE; + } + } + +diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c +index 0c25d97..8f548ad 100644 +--- a/drivers/scsi/lpfc/lpfc_nportdisc.c ++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c +@@ -1929,10 +1929,10 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + if (vport->fc_flag & FC_RSCN_DEFERRED) + return ndlp->nlp_state; + ++ lpfc_cancel_retry_delay_tmo(vport, ndlp); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); + spin_unlock_irq(shost->host_lock); +- lpfc_cancel_retry_delay_tmo(vport, ndlp); + return ndlp->nlp_state; + } + +diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c +index daf400e..38a7faf 100644 +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -65,6 +65,8 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) + if (cmd->result) + return; + ++ latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time); ++ + spin_lock_irqsave(shost->host_lock, flags); + if (!vport->stat_data_enabled || + vport->stat_data_blocked || +@@ -73,13 +75,15 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) + spin_unlock_irqrestore(shost->host_lock, flags); + return; + } +- latency = jiffies_to_msecs(jiffies - lpfc_cmd->start_time); + + if (phba->bucket_type == LPFC_LINEAR_BUCKET) { + i = (latency + phba->bucket_step - 1 - phba->bucket_base)/ + phba->bucket_step; +- if (i >= LPFC_MAX_BUCKET_COUNT) +- i = LPFC_MAX_BUCKET_COUNT; ++ /* check array subscript bounds */ ++ if (i < 0) ++ i = 0; ++ else if (i >= LPFC_MAX_BUCKET_COUNT) ++ i = LPFC_MAX_BUCKET_COUNT - 1; + } else { + for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++) + if (latency <= (phba->bucket_base + +@@ -413,14 +417,14 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) + bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); + bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); + bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; +- bpl[0].tus.w = le32_to_cpu(bpl->tus.w); ++ bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); + + /* Setup the physical region for the FCP RSP */ + bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); + bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); + bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); + bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; +- bpl[1].tus.w = le32_to_cpu(bpl->tus.w); ++ bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); + + /* + * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, +@@ -920,7 +924,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, + if (!pnode || !NLP_CHK_NODE_ACT(pnode) + || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, +- SAM_STAT_BUSY); ++ SAM_STAT_BUSY); + } else { + cmd->result = ScsiResult(DID_OK, 0); + } +diff --git a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c +index c0fbe56..3d2a8c8 100644 +--- a/drivers/scsi/lpfc/lpfc_security.c ++++ b/drivers/scsi/lpfc/lpfc_security.c +@@ -45,8 +45,7 @@ lpfc_security_service_online(struct Scsi_Host *shost) + + lpfc_security_service_state = SECURITY_ONLINE; + if (vport->cfg_enable_auth && +- vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN && +- vport->phba->link_state == LPFC_HBA_ERROR) ++ vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN) + lpfc_selective_reset(vport->phba); + } + +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index ac78493..5838e41 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -1262,68 +1262,6 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) + } + + /** +- * lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer. +- * @phba: Pointer to HBA context object. +- * @tag: Tag for the HBQ buffer. +- * +- * This function is called from unsolicited event handler code path to get the +- * HBQ buffer associated with an unsolicited iocb. This function is called with +- * no lock held. It returns the buffer associated with the given tag and posts +- * another buffer to the firmware. Note that the new buffer must be allocated +- * before taking the hbalock and that the hba lock must be held until it is +- * finished with the hbq entry swap. +- **/ +-static struct lpfc_dmabuf * +-lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) +-{ +- struct hbq_dmabuf *hbq_entry, *new_hbq_entry; +- uint32_t hbqno; +- void *virt; /* virtual address ptr */ +- dma_addr_t phys; /* mapped address */ +- unsigned long flags; +- +- hbqno = tag >> 16; +- new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); +- /* Check whether HBQ is still in use */ +- spin_lock_irqsave(&phba->hbalock, flags); +- if (!phba->hbq_in_use) { +- if (new_hbq_entry) +- (phba->hbqs[hbqno].hbq_free_buffer)(phba, +- new_hbq_entry); +- spin_unlock_irqrestore(&phba->hbalock, flags); +- return NULL; +- } +- +- hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); +- if (hbq_entry == NULL) { +- if (new_hbq_entry) +- (phba->hbqs[hbqno].hbq_free_buffer)(phba, +- new_hbq_entry); +- spin_unlock_irqrestore(&phba->hbalock, flags); +- return NULL; +- } +- list_del(&hbq_entry->dbuf.list); +- +- if (new_hbq_entry == NULL) { +- list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list); +- spin_unlock_irqrestore(&phba->hbalock, flags); +- return &hbq_entry->dbuf; +- } +- new_hbq_entry->tag = -1; +- phys = new_hbq_entry->dbuf.phys; +- virt = new_hbq_entry->dbuf.virt; +- new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys; +- new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt; +- hbq_entry->dbuf.phys = phys; +- hbq_entry->dbuf.virt = virt; +- lpfc_sli_free_hbq(phba, hbq_entry); +- list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list); +- spin_unlock_irqrestore(&phba->hbalock, flags); +- +- return &new_hbq_entry->dbuf; +-} +- +-/** + * lpfc_sli_get_buff: Get the buffer associated with the buffer tag. + * @phba: Pointer to HBA context object. + * @pring: Pointer to driver SLI ring object. +@@ -1337,13 +1275,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) + **/ + static struct lpfc_dmabuf * + lpfc_sli_get_buff(struct lpfc_hba *phba, +- struct lpfc_sli_ring *pring, +- uint32_t tag) ++ struct lpfc_sli_ring *pring, ++ uint32_t tag) + { ++ struct hbq_dmabuf *hbq_entry; ++ + if (tag & QUE_BUFTAG_BIT) + return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); +- else +- return lpfc_sli_replace_hbqbuff(phba, tag); ++ hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); ++ if (!hbq_entry) ++ return NULL; ++ return &hbq_entry->dbuf; + } + + +@@ -1375,8 +1317,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + match = 0; + irsp = &(saveq->iocb); + +- if (irsp->ulpStatus == IOSTAT_NEED_BUFFER) +- return 1; + if (irsp->ulpCommand == CMD_ASYNC_STATUS) { + if (pring->lpfc_sli_rcv_async_status) + pring->lpfc_sli_rcv_async_status(phba, pring, saveq); +@@ -2776,6 +2716,86 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) + } + + /** ++ * lpfc_sli_set_dma_length: Set the HBA's max DMA length. ++ * @phba: Pointer to HBA context object. ++ * @polling: flag that indicates if interrupts are enabled. ++ * ++ * This function sets the HBA's max dma length by issuing a set variable ++ * mailbox command. The dma length is taking from the cfg_pci_max_read ++ * configuration parameter. This parameter is passed as a module parameter ++ * during the driver load. If the HBA does not support this set variable ++ * mbox command the failure status will reset the cfg_pci_max_read to the ++ * default(2048). ++ * If interrupts are not enabled yet then the polling flag = 1 should be ++ * be used so that the right mailbox routine is called. ++ * This function returns 0 for success, non 0 returned for failure. ++ **/ ++int ++lpfc_sli_set_dma_length(struct lpfc_hba *phba, uint32_t polling) ++{ ++ uint32_t dma_length; ++ LPFC_MBOXQ_t *mbox; ++ int ret = 0; ++ ++ switch (phba->cfg_pci_max_read) { ++ case 512: ++ dma_length = SLIM_VAL_MAX_DMA_512; ++ break; ++ case 1024: ++ dma_length = SLIM_VAL_MAX_DMA_1024; ++ break; ++ case 2048: ++ dma_length = SLIM_VAL_MAX_DMA_2048; ++ break; ++ case 4096: ++ dma_length = SLIM_VAL_MAX_DMA_4096; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); ++ if (!mbox) ++ goto failed; ++ ++ lpfc_set_var(phba, mbox, SLIM_VAR_MAX_DMA_LENGTH, dma_length); ++ ++ if (polling) ++ ret = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); ++ else ++ ret = lpfc_sli_issue_mbox_wait(phba, mbox, ++ LPFC_MBOX_TMO * 2); ++ ++ if (ret != MBX_SUCCESS) { ++ if (mbox->mb.mbxStatus != MBXERR_UNKNOWN_CMD) ++ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, ++ "%d:0443 Adapter failed to set maximum" ++ " DMA length mbxStatus x%x \n", ++ phba->brd_no, mbox->mb.mbxStatus); ++ else ++ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, ++ "%d:0447 Adapter failed to set maximum" ++ " DMA length mbxStatus x%x \n", ++ phba->brd_no, mbox->mb.mbxStatus); ++ goto failed; ++ } ++ ++ mempool_free(mbox, phba->mbox_mem_pool); ++ return 0; ++ ++failed: ++ /* If mailbox command failed, reset the value to default value */ ++ phba->cfg_pci_max_read = 2048; ++ if (ret == MBX_TIMEOUT) { ++ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; ++ return -EPERM; ++ } else if (mbox) { ++ mempool_free(mbox, phba->mbox_mem_pool); ++ return -EPERM; ++ } else ++ return -ENOMEM; ++} ++/** + * lpfc_sli_brdrestart: Restart the HBA. + * @phba: Pointer to HBA context object. + * +@@ -3140,17 +3160,20 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) + phba->sli3_options |= LPFC_SLI3_CRP_ENABLED; + if (pmb->mb.un.varCfgPort.ginb) { + phba->sli3_options |= LPFC_SLI3_INB_ENABLED; ++ phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get; + phba->port_gp = phba->mbox->us.s3_inb_pgp.port; + phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy; + phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter; + phba->inb_last_counter = + phba->mbox->us.s3_inb_pgp.counter; + } else { ++ phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; + phba->port_gp = phba->mbox->us.s3_pgp.port; + phba->inb_ha_copy = NULL; + phba->inb_counter = NULL; + } + } else { ++ phba->hbq_get = NULL; + phba->port_gp = phba->mbox->us.s2.port; + phba->inb_ha_copy = NULL; + phba->inb_counter = NULL; +@@ -3226,6 +3249,9 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0444 Firmware in SLI %x mode. Max_vpi %d\n", + phba->sli_rev, phba->max_vpi); ++ ++ lpfc_sli_set_dma_length(phba, 1); ++ + rc = lpfc_sli_ring_map(phba); + + if (rc) +@@ -3301,10 +3327,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + +- if (!(phba->pport->work_port_events & WORKER_MBOX_TMO)) { +- return; +- } +- + /* Mbox cmd timeout */ + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0310 Mailbox command x%x timeout Data: x%x x%x x%p\n", +@@ -5275,6 +5297,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + uint32_t ha_copy; + uint32_t work_ha_copy; + unsigned long status; ++ unsigned long iflag; + uint32_t control; + + MAILBOX_t *mbox, *pmbox; +@@ -5307,7 +5330,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + if (unlikely(phba->link_state < LPFC_LINK_DOWN)) + return IRQ_NONE; + /* Need to read HA REG for slow-path events */ +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + ha_copy = readl(phba->HAregaddr); + /* If somebody is waiting to handle an eratt don't process it + * here. The brdkill function will do this. +@@ -5327,7 +5350,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)), + phba->HAregaddr); + readl(phba->HAregaddr); /* flush */ +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + } else + ha_copy = phba->ha_copy; + +@@ -5340,13 +5363,13 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + * Turn off Link Attention interrupts + * until CLEAR_LA done + */ +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + phba->sli.sli_flag &= ~LPFC_PROCESS_LA; + control = readl(phba->HCregaddr); + control &= ~HC_LAINT_ENA; + writel(control, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + } + else + work_ha_copy &= ~HA_LATT; +@@ -5361,7 +5384,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + (HA_RXMASK << (4*LPFC_ELS_RING))); + status >>= (4*LPFC_ELS_RING); + if (status & HA_RXMASK) { +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + control = readl(phba->HCregaddr); + + lpfc_debugfs_slow_ring_trc(phba, +@@ -5390,10 +5413,10 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + (uint32_t)((unsigned long) + &phba->work_waitq)); + } +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + } + } +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + if (work_ha_copy & HA_ERATT) + lpfc_sli_read_hs(phba); + if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { +@@ -5405,7 +5428,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + /* First check out the status word */ + lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t)); + if (pmbox->mbxOwner != OWN_HOST) { +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + /* + * Stray Mailbox Interrupt, mbxCommand + * mbxStatus +@@ -5422,7 +5445,7 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + work_ha_copy &= ~HA_MBATT; + } else { + phba->sli.mbox_active = NULL; +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + phba->last_completion_time = jiffies; + del_timer(&phba->sli.mbox_tmo); + if (pmb->mbox_cmpl) { +@@ -5480,14 +5503,18 @@ lpfc_sp_intr_handler(int irq, void *dev_id) + goto send_current_mbox; + } + } +- spin_lock(&phba->pport->work_port_lock); ++ spin_lock_irqsave( ++ &phba->pport->work_port_lock, ++ iflag); + phba->pport->work_port_events &= + ~WORKER_MBOX_TMO; +- spin_unlock(&phba->pport->work_port_lock); ++ spin_unlock_irqrestore( ++ &phba->pport->work_port_lock, ++ iflag); + lpfc_mbox_cmpl_put(phba, pmb); + } + } else +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + + if ((work_ha_copy & HA_MBATT) && + (phba->sli.mbox_active == NULL)) { +@@ -5503,9 +5530,9 @@ send_current_mbox: + "MBX_SUCCESS"); + } + +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + phba->work_ha |= work_ha_copy; +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + lpfc_worker_wake_up(phba); + } + return IRQ_HANDLED; +@@ -5537,6 +5564,7 @@ lpfc_fp_intr_handler(int irq, void *dev_id) + struct lpfc_hba *phba; + uint32_t ha_copy; + unsigned long status; ++ unsigned long iflag; + + /* Get the driver's phba structure from the dev_id and + * assume the HBA is not interrupting. +@@ -5562,11 +5590,11 @@ lpfc_fp_intr_handler(int irq, void *dev_id) + /* Need to read HA REG for FCP ring and other ring events */ + ha_copy = readl(phba->HAregaddr); + /* Clear up only attention source related to fast-path */ +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)), + phba->HAregaddr); + readl(phba->HAregaddr); /* flush */ +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + } else + ha_copy = phba->ha_copy; + +diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +index 57b559a..16626a5 100644 +--- a/drivers/scsi/lpfc/lpfc_version.h ++++ b/drivers/scsi/lpfc/lpfc_version.h +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.4" ++#define LPFC_DRIVER_VERSION "8.2.8.7" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.9-update b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.9-update new file mode 100644 index 000000000..a2869b1c0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/lpfc-8.2.8.9-update @@ -0,0 +1,122 @@ +Subject: Update Emulex lpfc driver to 8.2.8.9 +From: Jamie Wellnitz +Date: Wed Dec 3 09:06:44 2008 +0100: +References: bnc#420767 + +Changes from 8.2.8.7 to 8.2.8.9: + +* Changed version number to 8.2.8.9 +* Remove unused defines from lpfc_auth_access.h +* Fix firmware dump on CNAs (CR 86157) +* Changed version number to 8.2.8.8 +* Fixed wrong number of bytes copied reported to applications (CR 85743) +* Fixed potential spin_lock problem when HBA is in MSI-X mode + +Signed-off-by: Jamie Wellnitz +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/lpfc/lpfc_auth_access.h b/drivers/scsi/lpfc/lpfc_auth_access.h +index be7525f..0aadcd3 100644 +--- a/drivers/scsi/lpfc/lpfc_auth_access.h ++++ b/drivers/scsi/lpfc/lpfc_auth_access.h +@@ -1,7 +1,7 @@ + /******************************************************************* + * This file is part of the Emulex Linux Device Driver for * + * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2006-2007 Emulex. All rights reserved. * ++ * Copyright (C) 2006-2008 Emulex. All rights reserved. * + * EMULEX and SLI are trademarks of Emulex. * + * www.emulex.com * + * * +@@ -18,26 +18,6 @@ + * included with this package. * + *******************************************************************/ + +-#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) +- +-/* scsi_nl_hdr->version value */ +-#define SCSI_NL_VERSION 1 +- +-/* scsi_nl_hdr->magic value */ +-#define SCSI_NL_MAGIC 0xA1B2 +- +-/* scsi_nl_hdr->transport value */ +-#define SCSI_NL_TRANSPORT 0 +-#define SCSI_NL_TRANSPORT_FC 1 +-#define SCSI_NL_MAX_TRANSPORTS 2 +- +-#define FC_NL_GROUP_CNT 0 +- +- /* Note: when specifying vendor_id to fc_host_post_vendor_event() +- * be sure to read the Vendor Type and ID formatting requirements +- * specified in scsi_netlink.h +- */ +- + #define FC_SC_REQ_TIMEOUT (60*HZ) + + enum fc_sc_service_state { +diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c +index 84619ed..b5c7876 100644 +--- a/drivers/scsi/lpfc/lpfc_mbox.c ++++ b/drivers/scsi/lpfc/lpfc_mbox.c +@@ -1349,10 +1349,12 @@ lpfc_mbox_get(struct lpfc_hba * phba) + void + lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) + { ++ unsigned long iflag; ++ + /* This function expects to be called from interrupt context */ +- spin_lock(&phba->hbalock); ++ spin_lock_irqsave(&phba->hbalock, iflag); + list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl); +- spin_unlock(&phba->hbalock); ++ spin_unlock_irqrestore(&phba->hbalock, iflag); + return; + } + +diff --git a/drivers/scsi/lpfc/lpfc_menlo.c b/drivers/scsi/lpfc/lpfc_menlo.c +index 4f3b332..12fd7fe 100644 +--- a/drivers/scsi/lpfc/lpfc_menlo.c ++++ b/drivers/scsi/lpfc/lpfc_menlo.c +@@ -1064,13 +1064,22 @@ lpfc_menlo_read(struct lpfc_hba *phba, char *buf, loff_t off, size_t count, + } + genreq->offset += count; + +- +- if (genreq->offset >= sysfs_menlo->cmdhdr.rspsize) { ++ if (genreq->offset >= (genreq->rspiocbq->iocb.un.ulpWord[0] & ++ 0x00ffffff)) { + lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, +- "1222 menlo_read: done off %d rc=%d" +- " cnt %d rsp_code %x\n", +- (int)off, rc, (int)count,*((uint32_t *)buf)); +- rc = count; ++ "1222 menlo_read: done off %d genoff:%d rspsz:%d " ++ "rc=%d cnt %d rsp_code %x Word0:%x\n", ++ (int)off, (int)genreq->offset, ++ sysfs_menlo->cmdhdr.rspsize, rc, (int)count, ++ *((uint32_t *)buf), ++ genreq->rspiocbq->iocb.un.ulpWord[0]); ++ ++ if ((genreq->rspiocbq->iocb.un.ulpWord[0] & 0x00ffffff) ++ < sysfs_menlo->cmdhdr.rspsize) ++ rc = (genreq->rspiocbq->iocb.un.ulpWord[0] & 0x00ffffff) ++ + count - genreq->offset; ++ else ++ rc = count; + goto lpfc_menlo_read_err_exit; + } + +diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h +index 16626a5..26f6760 100644 +--- a/drivers/scsi/lpfc/lpfc_version.h ++++ b/drivers/scsi/lpfc/lpfc_version.h +@@ -18,7 +18,7 @@ + * included with this package. * + *******************************************************************/ + +-#define LPFC_DRIVER_VERSION "8.2.8.7" ++#define LPFC_DRIVER_VERSION "8.2.8.9" + + #define LPFC_DRIVER_NAME "lpfc" + #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" diff --git a/src/patches/suse-2.6.27.31/patches.drivers/megaraid-mbox-fix-SG_IO b/src/patches/suse-2.6.27.31/patches.drivers/megaraid-mbox-fix-SG_IO new file mode 100644 index 000000000..e69ca9031 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/megaraid-mbox-fix-SG_IO @@ -0,0 +1,65 @@ +From: Martin Wilck +Subject: megaraid_mbox: Oops on SG_IO +References: bnc#475619 + +This patch fixes an Oops in megaraid_mbox that happens when a +MODE_SENSE command for a logical drive is started viaioctl(SG_IO). + +The problem only occurs if the buffer specified by the user to receive +the mode data resides in highmem and if the buffer is aligned for +direct dma (no bounce buffer necessary). megaraid_mbox emulates +the MODE_SENSE command and writes the data using memset() directly +into user buffer. If the buffer is at a currently unmapped highmem +page, this leads to an Oops. + +Signed-off-by: Hannes Reinecke + +--- linux-2.6.27.7-9/drivers/scsi/megaraid/megaraid_mbox.c.orig 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27.7-9/drivers/scsi/megaraid/megaraid_mbox.c 2009-02-03 15:01:56.000000000 +0100 +@@ -1580,13 +1580,20 @@ megaraid_mbox_build_cmd(adapter_t *adapt + case MODE_SENSE: + { + struct scatterlist *sgl; +- caddr_t vaddr; ++ struct page *pg; ++ unsigned char *vaddr; ++ unsigned long flags; + + sgl = scsi_sglist(scp); +- if (sg_page(sgl)) { +- vaddr = (caddr_t) sg_virt(&sgl[0]); ++ pg = sg_page(sgl); ++ if (pg) { ++ local_irq_save(flags); ++ vaddr = kmap_atomic(pg, KM_BIO_SRC_IRQ) + sgl->offset; + + memset(vaddr, 0, scp->cmnd[4]); ++ ++ kunmap_atomic(vaddr, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); + } + else { + con_log(CL_ANN, (KERN_WARNING +@@ -2324,9 +2331,20 @@ megaraid_mbox_dpc(unsigned long devp) + if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0 + && IS_RAID_CH(raid_dev, scb->dev_channel)) { + ++ struct page *pg; ++ unsigned char *vaddr; ++ unsigned long flags; ++ + sgl = scsi_sglist(scp); +- if (sg_page(sgl)) { +- c = *(unsigned char *) sg_virt(&sgl[0]); ++ pg = sg_page(sgl); ++ if (pg) { ++ local_irq_save(flags); ++ vaddr = kmap_atomic(pg, KM_BIO_SRC_IRQ) + sgl->offset; ++ ++ c = *vaddr; ++ ++ kunmap_atomic(vaddr, KM_BIO_SRC_IRQ); ++ local_irq_restore(flags); + } else { + con_log(CL_ANN, (KERN_WARNING + "megaraid mailbox: invalid sg:%d\n", diff --git a/src/patches/suse-2.6.27.31/patches.drivers/mpt-fusion-4.00.43.00-update b/src/patches/suse-2.6.27.31/patches.drivers/mpt-fusion-4.00.43.00-update new file mode 100644 index 000000000..139298f2d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/mpt-fusion-4.00.43.00-update @@ -0,0 +1,28445 @@ +Subject: Update MPT Fusion driver to v4.00.43.00 +From: Hannes Reinecke +Date: Tue Sep 30 13:38:53 2008 +0200: +Git: a958ec0d1685af04282982f2e53b66c947fc7426 + +References: bnc#425660 + +This patch updates the MPT fusion drivers to v4.00.43.00. + +Signed-off-by: Sathya Prakash +Signed-off-by: Hannes Reinecke + +--- + drivers/message/fusion/Kconfig | 16 + drivers/message/fusion/Makefile | 13 + drivers/message/fusion/csmi/csmisas.c | 5888 ++++++++++++++++++ + drivers/message/fusion/csmi/csmisas.h | 1854 +++++ + drivers/message/fusion/lsi/mpi.h | 7 + drivers/message/fusion/lsi/mpi_cnfg.h | 47 + drivers/message/fusion/lsi/mpi_fc.h | 2 + drivers/message/fusion/lsi/mpi_history.txt | 86 + drivers/message/fusion/lsi/mpi_init.h | 2 + drivers/message/fusion/lsi/mpi_ioc.h | 22 + drivers/message/fusion/lsi/mpi_lan.h | 2 + drivers/message/fusion/lsi/mpi_log_fc.h | 2 + drivers/message/fusion/lsi/mpi_log_sas.h | 31 + drivers/message/fusion/lsi/mpi_raid.h | 11 + drivers/message/fusion/lsi/mpi_sas.h | 18 + drivers/message/fusion/lsi/mpi_targ.h | 2 + drivers/message/fusion/lsi/mpi_tool.h | 2 + drivers/message/fusion/lsi/mpi_type.h | 19 + drivers/message/fusion/mptbase.c | 2700 +++++--- + drivers/message/fusion/mptbase.h | 291 + drivers/message/fusion/mptctl.c | 1020 +-- + drivers/message/fusion/mptctl.h | 5 + drivers/message/fusion/mptdebug.h | 12 + drivers/message/fusion/mptfc.c | 189 + drivers/message/fusion/mptlan.c | 56 + drivers/message/fusion/mptlan.h | 3 + drivers/message/fusion/mptsas.c | 5921 ++++++++++++------- + drivers/message/fusion/mptsas.h | 71 + drivers/message/fusion/mptscsih.c | 2252 +++---- + drivers/message/fusion/mptscsih.h | 13 + drivers/message/fusion/mptspi.c | 265 + drivers/message/fusion/rejected_ioctls/diag_buffer.c | 667 ++ + drivers/message/fusion/rejected_ioctls/diag_buffer.h | 101 + 33 files changed, 16615 insertions(+), 4975 deletions(-) + +--- /dev/null ++++ b/drivers/message/fusion/csmi/csmisas.c +@@ -0,0 +1,5888 @@ ++/* ++ * linux/drivers/message/fusion/csmi/csmisas.c ++ * For use with LSI PCI chip/adapter(s) ++ * running LSI Fusion MPT (Message Passing Technology) firmware. ++ * ++ * Copyright (c) 1999-2008 LSI Corporation ++ * (mailto:DL-MPTFusionLinux@lsi.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; version 2 of the License. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ NO WARRANTY ++ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR ++ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT ++ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, ++ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is ++ solely responsible for determining the appropriateness of using and ++ distributing the Program and assumes all risks associated with its ++ exercise of rights under this Agreement, including but not limited to ++ the risks and costs of program errors, damage to or loss of data, ++ programs or equipment, and unavailability or interruption of operations. ++ ++ DISCLAIMER OF LIABILITY ++ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY ++ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED ++ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++ ++#define MPT_CSMI_DESCRIPTION "LSI Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON ++#define csmisas_is_this_sas_cntr(ioc) (ioc->bus_type == SAS) ? 1 : 0 ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) ++#define __user ++#include ++#endif ++ ++static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, ++ u8 VolumeId, pMpiRaidActionReply_t reply); ++static u8 map_sas_status_to_csmi(u8 mpi_sas_status); ++ ++/** ++ * reverse_byte_order64 ++ * ++ * @data64 ++ * ++ **/ ++static u64 ++reverse_byte_order64(u64 data64) ++{ ++ int i; ++ u64 rc; ++ u8 *inWord = (u8*)&data64, *outWord = (u8*)&rc; ++ ++ for (i = 0 ; i < 8 ; i++) ++ outWord[i] = inWord[7-i]; ++ ++ return rc; ++} ++ ++/** ++ * csmisas_is_sata ++ * ++ * @phys_disk ++ * ++ **/ ++static int ++csmisas_is_sata(RaidPhysDiskPage0_t *phys_disk) ++{ ++ if ((phys_disk->ExtDiskIdentifier[0] == 'A') && ++ (phys_disk->ExtDiskIdentifier[1] == 'T') && ++ (phys_disk->ExtDiskIdentifier[2] == 'A')) ++ return 1; ++ else ++ return 0; ++} ++ ++/** ++ * csmisas_is_end_device ++ * ++ * @attached ++ * ++ **/ ++static inline int ++csmisas_is_end_device(struct mptsas_devinfo * attached) ++{ ++ if ((attached->sas_address) && ++ (attached->device_info & ++ MPI_SAS_DEVICE_INFO_END_DEVICE) && ++ ((attached->device_info & ++ MPI_SAS_DEVICE_INFO_SSP_TARGET) | ++ (attached->device_info & ++ MPI_SAS_DEVICE_INFO_STP_TARGET) | ++ (attached->device_info & ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE))) ++ return 1; ++ else ++ return 0; ++} ++ ++/** ++ * csmisas_is_phys_disk ++ * ++ * returns (1) success (0) fail - not a phys disk ++ **/ ++static int ++csmisas_is_phys_disk(MPT_ADAPTER *ioc, int channel, int id) ++{ ++ struct inactive_raid_component_info *component_info; ++ int i; ++ int rc = 0; ++ ++ if (!ioc->raid_data.pIocPg3) ++ goto out; ++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { ++ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && ++ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { ++ rc = 1; ++ goto out; ++ } ++ } ++ ++ /* ++ * Check inactive list for matching phys disks ++ */ ++ if (list_empty(&ioc->raid_data.inactive_list)) ++ goto out; ++ ++ down(&ioc->raid_data.inactive_list_mutex); ++ list_for_each_entry(component_info, &ioc->raid_data.inactive_list, ++ list) { ++ if ((component_info->d.PhysDiskID == id) && ++ (component_info->d.PhysDiskBus == channel)) ++ rc = 1; ++ } ++ up(&ioc->raid_data.inactive_list_mutex); ++ ++ out: ++ return rc; ++} ++ ++/** ++ * csmisas_raid_id_to_num ++ * ++ * Obtains the phys disk num for given H:C:T nexus ++ * ++ * input (channel/id) ++ * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden component) ++ * ++ * returns - signed return means failure ++ **/ ++static s8 ++csmisas_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) ++{ ++ struct inactive_raid_component_info *component_info; ++ int i; ++ s8 rc = -ENXIO; ++ ++ if (!ioc->raid_data.pIocPg3) ++ goto out; ++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { ++ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && ++ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { ++ rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; ++ goto out; ++ } ++ } ++ ++ /* ++ * Check inactive list for matching phys disks ++ */ ++ if (list_empty(&ioc->raid_data.inactive_list)) ++ goto out; ++ ++ down(&ioc->raid_data.inactive_list_mutex); ++ list_for_each_entry(component_info, &ioc->raid_data.inactive_list, ++ list) { ++ if ((component_info->d.PhysDiskID == id) && ++ (component_info->d.PhysDiskBus == channel)) ++ rc = component_info->d.PhysDiskNum; ++ } ++ up(&ioc->raid_data.inactive_list_mutex); ++ ++ out: ++ return rc; ++} ++ ++/** ++ * csmisas_get_device_component_by_os ++ * ++ * Obtain device component object by operating system mapping ++ * ++ * @ioc ++ * @channel ++ * @id ++ * ++ **/ ++static struct sas_device_info * ++csmisas_get_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) ++{ ++ struct sas_device_info *sas_info, *p; ++ ++ sas_info = NULL; ++ ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry(p, &ioc->sas_device_info_list, list) { ++ if (p->os.channel == channel && p->os.id == id) { ++ sas_info = p; ++ goto out; ++ } ++ } ++ ++ out: ++ up(&ioc->sas_device_info_mutex); ++ return sas_info; ++} ++ ++/** ++ * csmisas_get_device_component ++ * ++ * Obtain device component object by firmware system mapping ++ * ++ * @ioc ++ * @channel ++ * @id ++ * ++ **/ ++static struct sas_device_info * ++csmisas_get_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) ++{ ++ struct sas_device_info *sas_info, *p; ++ ++ sas_info = NULL; ++ ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry(p, &ioc->sas_device_info_list, list) { ++ if (p->fw.channel == channel && p->fw.id == id) { ++ sas_info = p; ++ goto out; ++ } ++ } ++ ++ out: ++ up(&ioc->sas_device_info_mutex); ++ return sas_info; ++} ++ ++ ++/** ++ * csmisas_get_device_component_by_sas_addr ++ * ++ * Obtain device component object by sas address ++ * ++ * @ioc ++ * @channel ++ * @id ++ * ++ **/ ++static struct sas_device_info * ++csmisas_get_device_component_by_sas_addr(MPT_ADAPTER *ioc, u64 sas_address) ++{ ++ struct sas_device_info *sas_info, *p; ++ ++ sas_info = NULL; ++ ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry(p, &ioc->sas_device_info_list, list) { ++ if (p->sas_address == sas_address) { ++ sas_info = p; ++ goto out; ++ } ++ } ++ ++ out: ++ up(&ioc->sas_device_info_mutex); ++ return sas_info; ++} ++ ++/** ++ * csmisas_send_command_wait ++ * ++ * Send mf to firmware ++ * ++ * @ioc ++ * @mf ++ * @timeout - timeout ++ * ++ * Return: 0 for success ++ * non-zero, failure ++ **/ ++static int ++csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout) ++{ ++ int rc; ++ unsigned long timeleft; ++ ++ timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout); ++ rc = 0; ++ timeleft = 0; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) ++ ++ INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status) ++ ioc->ioctl_cmds.wait_done = 0; ++ ioc->ioctl_cmds.timer.expires = jiffies + (MPT_JIFFY * timeout); ++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE; ++ ADD_TIMER(&ioc->ioctl_cmds.timer); ++ mpt_put_msg_frame(mptctl_id, ioc, mf); ++ WAIT_EVENT(mptctl_wait, ioc->ioctl_cmds.wait_done); ++ ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) ++ ++ INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status) ++ ioc->ioctl_cmds.wait_done = 0; ++ mpt_put_msg_frame(mptctl_id, ioc, mf); ++ ++ if ((wait_event_timeout(mptctl_wait, ++ ioc->ioctl_cmds.wait_done == 1, HZ * timeout) <=0) && ++ ioc->ioctl_cmds.wait_done != 1 ) { ++ mptctl_timeout_expired(ioc,mf); ++ mpt_free_msg_frame(ioc, mf); ++ rc = -1; ++ } ++ ++#else ++ ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, ++ mf->u.hdr.MsgContext); ++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) ++ mpt_put_msg_frame(mptctl_id, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, timeout*HZ); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ rc = -1; ++ printk("%s: failed\n", __FUNCTION__); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) ++ return rc; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(ioc, mf); ++ } ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); ++#endif ++ return rc; ++} ++ ++/** ++ * csmisas_send_handshake_wait ++ * ++ * Handshake a mf to firmware ++ * ++ * @ioc ++ * @mf ++ * @mf_size ++ * @timeout - timeout ++ * ++ * Return: 0 for success ++ * non-zero, failure ++ **/ ++static int ++csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout) ++{ ++ int rc; ++ unsigned long timeleft; ++ ++ timeout = max_t(unsigned long, MPT_IOCTL_DEFAULT_TIMEOUT, timeout); ++ rc = 0; ++ timeleft = 0; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) ++ ++ INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status) ++ ioc->taskmgmt_cmds.timer.expires = jiffies + (MPT_JIFFY*timeout); ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE; ++ ioc->taskmgmt_cmds.wait_done = 0; ++ ADD_TIMER(&ioc->taskmgmt_cmds.timer); ++ rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc, ++ sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP); ++ if (rc != 0) ++ return rc; ++ WAIT_EVENT(mptctl_taskmgmt_wait, ioc->taskmgmt_cmds.wait_done); ++ ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) ++ ++ INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status) ++ ioc->taskmgmt_cmds.wait_done = 0; ++ rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc, ++ sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP); ++ if (rc != 0) ++ return rc; ++ if ((wait_event_timeout(mptctl_taskmgmt_wait, ++ ioc->taskmgmt_cmds.wait_done == 1, HZ * timeout) <=0) && ++ ioc->taskmgmt_cmds.wait_done != 1 ) { ++ mptctl_timeout_expired(ioc, mf); ++ mpt_free_msg_frame(ioc, mf); ++ rc = -1; ++ } ++ ++#else ++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ rc = -1; ++ printk("%s: failed\n", __FUNCTION__); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ return rc; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(ioc, mf); ++ } ++#endif ++ return rc; ++} ++ ++/** ++ * csmisas_get_number_hotspares - returns num hot spares in this ioc ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ * Return: number of hotspares ++ * ++ **/ ++static int ++csmisas_get_number_hotspares(MPT_ADAPTER *ioc) ++{ ++ ConfigPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ IOCPage5_t *buffer = NULL; ++ dma_addr_t dma_handle; ++ int data_sz; ++ int rc; ++ ++ memset(&hdr, 0, sizeof(ConfigPageHeader_t)); ++ memset(&cfg, 0, sizeof(CONFIGPARMS)); ++ ++ rc = 0; ++ data_sz = 0; ++ hdr.PageNumber = 5; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_IOC; ++ cfg.cfghdr.hdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if (mpt_config(ioc, &cfg) != 0) ++ goto get_ioc_pg5; ++ ++ if (hdr.PageLength == 0) ++ goto get_ioc_pg5; ++ ++ data_sz = hdr.PageLength * 4; ++ buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev, ++ data_sz, &dma_handle); ++ if (!buffer) ++ goto get_ioc_pg5; ++ ++ memset((u8 *)buffer, 0, data_sz); ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if (mpt_config(ioc, &cfg) != 0) ++ goto get_ioc_pg5; ++ ++ rc = buffer->NumHotSpares; ++ ++ get_ioc_pg5: ++ ++ if (buffer) ++ pci_free_consistent(ioc->pcidev, data_sz, ++ (u8 *) buffer, dma_handle); ++ ++ return rc; ++} ++ ++ ++/** ++ * csmisas_get_ioc_pg5 - ioc Page 5 hot spares ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @pIocPage5: ioc page 5 ++ * @data_size: expected data size(units=bytes) ++ * ++ * Return: 0 for success ++ * -ENOMEM if no memory available ++ * -EPERM if not allowed due to ISR context ++ * -EAGAIN if no msg frames currently available ++ * -EFAULT for non-successful reply or no reply (timeout) ++ **/ ++static int ++csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IOCPage5_t *iocPage5, int data_size) ++{ ++ ConfigPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ IOCPage5_t *buffer = NULL; ++ dma_addr_t dma_handle; ++ int data_sz; ++ int rc; ++ ++ memset(&hdr, 0, sizeof(ConfigPageHeader_t)); ++ memset(&cfg, 0, sizeof(CONFIGPARMS)); ++ ++ rc = 0; ++ data_sz = 0; ++ hdr.PageNumber = 5; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_IOC; ++ cfg.cfghdr.hdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) ++ goto get_ioc_pg5; ++ ++ if (hdr.PageLength == 0) { ++ rc = -EFAULT; ++ goto get_ioc_pg5; ++ } ++ ++ data_sz = hdr.PageLength * 4; ++ buffer = (IOCPage5_t *) pci_alloc_consistent(ioc->pcidev, ++ data_sz, &dma_handle); ++ if (!buffer) { ++ rc = -ENOMEM; ++ goto get_ioc_pg5; ++ } ++ ++ memset((u8 *)buffer, 0, data_sz); ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) ++ goto get_ioc_pg5; ++ ++ memcpy(iocPage5, buffer, data_size); ++ ++ get_ioc_pg5: ++ ++ if (buffer) ++ pci_free_consistent(ioc->pcidev, data_sz, ++ (u8 *) buffer, dma_handle); ++ ++ return rc; ++} ++ ++/** ++ * csmisas_sas_device_pg0 - sas device page 0 ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @mptsas_devinfo: structure found in mptsas.h ++ * @form, @form_specific - defines the Page Address field in the config page ++ * (pls refer to chapter 5.1 in the mpi spec) ++ * ++ * Return: 0 for success ++ * -ENOMEM if no memory available ++ * -EPERM if not allowed due to ISR context ++ * -EAGAIN if no msg frames currently available ++ * -EFAULT for non-successful reply or no reply (timeout) ++ **/ ++static int ++csmisas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, ++ u32 form, u32 form_specific) ++{ ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ SasDevicePage0_t *buffer; ++ dma_addr_t dma_handle; ++ u64 sas_address; ++ int rc; ++ ++ rc = 0; ++ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.pageAddr = form + form_specific; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = 10; ++ ++ memset(device_info, 0, sizeof(struct mptsas_devinfo)); ++ if ((rc = mpt_config(ioc, &cfg)) != 0) ++ goto out; ++ ++ if (!hdr.ExtPageLength) { ++ rc = -ENXIO; ++ goto out; ++ } ++ ++ buffer = pci_alloc_consistent(ioc->pcidev, ++ hdr.ExtPageLength * 4, &dma_handle); ++ if (!buffer) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) ++ goto out_free_consistent; ++ ++ device_info->handle = le16_to_cpu(buffer->DevHandle); ++ device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); ++ device_info->handle_enclosure = ++ le16_to_cpu(buffer->EnclosureHandle); ++ device_info->slot = le16_to_cpu(buffer->Slot); ++ device_info->phy_id = buffer->PhyNum; ++ device_info->port_id = buffer->PhysicalPort; ++ device_info->id = buffer->TargetID; ++ device_info->channel = buffer->Bus; ++ memcpy(&sas_address, &buffer->SASAddress, sizeof(u64)); ++ device_info->sas_address = le64_to_cpu(sas_address); ++ device_info->device_info = ++ le32_to_cpu(buffer->DeviceInfo); ++ ++ out_free_consistent: ++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ buffer, dma_handle); ++ out: ++ return rc; ++} ++ ++/** ++ * Routine for the CSMI Sas Get Driver Info command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_driver_info(unsigned long arg) ++{ ++ ++ CSMI_SAS_DRIVER_INFO_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_DRIVER_INFO_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in csmi_sas_get_driver_info_buffer struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Fill in the data and return the structure to the calling ++ * program ++ */ ++ memcpy( karg.Information.szName, MPT_MISCDEV_BASENAME, ++ sizeof(MPT_MISCDEV_BASENAME)); ++ memcpy( karg.Information.szDescription, MPT_CSMI_DESCRIPTION, ++ sizeof(MPT_CSMI_DESCRIPTION)); ++ ++ karg.Information.usMajorRevision = MPT_LINUX_MAJOR_VERSION; ++ karg.Information.usMinorRevision = MPT_LINUX_MINOR_VERSION; ++ karg.Information.usBuildRevision = MPT_LINUX_BUILD_VERSION; ++ karg.Information.usReleaseRevision = MPT_LINUX_RELEASE_VERSION; ++ ++ karg.Information.usCSMIMajorRevision = CSMI_MAJOR_REVISION; ++ karg.Information.usCSMIMinorRevision = CSMI_MINOR_REVISION; ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI_SAS_GET_CNTLR_CONFIG command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_cntlr_config(unsigned long arg) ++{ ++ ++ CSMI_SAS_CNTLR_CONFIG_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_CNTLR_CONFIG_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ u64 mem_phys; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in csmi_sas_get_cntlr_config_buffer struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Clear the struct before filling in data. */ ++ memset( &karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG)); ++ ++ /* Fill in the data and return the structure to the calling ++ * program ++ */ ++ ++ karg.Configuration.uBaseIoAddress = ioc->pio_mem_phys; ++ karg.Configuration.BaseMemoryAddress.uLowPart = ioc->mem_phys; ++ if (sizeof(ioc->mem_phys) == sizeof(u64)) { ++ mem_phys = ioc->mem_phys; ++ karg.Configuration.BaseMemoryAddress.uHighPart = ++ (u32)(mem_phys >> 32); ++ } ++ ++ karg.Configuration.uBoardID = (ioc->pcidev->subsystem_device << 16) | ++ (ioc->pcidev->subsystem_vendor); ++ ++ karg.Configuration.usSlotNumber = ++ (ioc->pci_slot_number = 0xff) ? ++ SLOT_NUMBER_UNKNOWN : ioc->pci_slot_number; ++ karg.Configuration.bControllerClass = CSMI_SAS_CNTLR_CLASS_HBA; ++ karg.Configuration.bIoBusType = CSMI_SAS_BUS_TYPE_PCI; ++ karg.Configuration.BusAddress.PciAddress.bBusNumber = ++ ioc->pcidev->bus->number; ++ karg.Configuration.BusAddress.PciAddress.bDeviceNumber = ++ PCI_SLOT(ioc->pcidev->devfn); ++ karg.Configuration.BusAddress.PciAddress.bFunctionNumber = ++ PCI_FUNC(ioc->pcidev->devfn); ++ karg.Configuration.BusAddress.PciAddress.bReserved = 0; ++ memcpy( &karg.Configuration.szSerialNumber, ioc->board_tracer, 16 ); ++ karg.Configuration.usMajorRevision = ioc->facts.FWVersion.Struct.Major; ++ karg.Configuration.usMinorRevision = ioc->facts.FWVersion.Struct.Minor; ++ karg.Configuration.usBuildRevision = ioc->facts.FWVersion.Struct.Unit; ++ karg.Configuration.usReleaseRevision = ioc->facts.FWVersion.Struct.Dev; ++ karg.Configuration.usBIOSMajorRevision = ++ (ioc->biosVersion & 0xFF000000) >> 24; ++ karg.Configuration.usBIOSMinorRevision = ++ (ioc->biosVersion & 0x00FF0000) >> 16; ++ karg.Configuration.usBIOSBuildRevision = ++ (ioc->biosVersion & 0x0000FF00) >> 8; ++ karg.Configuration.usBIOSReleaseRevision = ++ (ioc->biosVersion & 0x000000FF); ++ karg.Configuration.uControllerFlags = CSMI_SAS_CNTLR_SAS_HBA | ++ CSMI_SAS_CNTLR_FWD_SUPPORT | CSMI_SAS_CNTLR_FWD_ONLINE | ++ CSMI_SAS_CNTLR_FWD_SRESET ; ++ ++ /* ++ * Enabling CSMI_SAS_CNTLR_SAS_RAID bit when IR fw detected ++ */ ++ if (ioc->ir_firmware) ++ karg.Configuration.uControllerFlags |= CSMI_SAS_CNTLR_SAS_RAID; ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* All Rrom entries will be zero. Skip them. */ ++ /* bReserved will also be zeros. */ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI Sas Get Controller Status command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_cntlr_status(unsigned long arg) ++{ ++ ++ CSMI_SAS_CNTLR_STATUS_BUFFER __user *uarg = (void __user *) arg; ++ MPT_ADAPTER *ioc = NULL; ++ CSMI_SAS_CNTLR_STATUS_BUFFER karg; ++ int iocnum; ++ int rc; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in csmi_sas_get_cntlr_status_buffer struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Fill in the data and return the structure to the calling ++ * program ++ */ ++ ++ rc = mpt_GetIocState(ioc, 1); ++ switch (rc) { ++ case MPI_IOC_STATE_OPERATIONAL: ++ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_GOOD; ++ karg.Status.uOfflineReason = 0; ++ break; ++ ++ case MPI_IOC_STATE_FAULT: ++ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_FAILED; ++ karg.Status.uOfflineReason = 0; ++ break; ++ ++ case MPI_IOC_STATE_RESET: ++ case MPI_IOC_STATE_READY: ++ default: ++ karg.Status.uStatus = CSMI_SAS_CNTLR_STATUS_OFFLINE; ++ karg.Status.uOfflineReason = ++ CSMI_SAS_OFFLINE_REASON_INITIALIZING; ++ break; ++ } ++ ++ memset(&karg.Status.bReserved, 0, 28); ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to write out csmi_sas_get_cntlr_status @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI Sas Get Phy Info command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_phy_info(unsigned long arg) ++{ ++ CSMI_SAS_PHY_INFO_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_PHY_INFO_BUFFER *karg; ++ MPT_ADAPTER *ioc = NULL; ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ SasIOUnitPage0_t *sasIoUnitPg0; ++ dma_addr_t sasIoUnitPg0_dma; ++ int sasIoUnitPg0_data_sz; ++ SasPhyPage0_t *sasPhyPg0; ++ dma_addr_t sasPhyPg0_dma; ++ int sasPhyPg0_data_sz; ++ u16 protocol; ++ int iocnum; ++ int rc; ++ int ii; ++ u64 sas_address; ++ struct mptsas_devinfo device_info; ++ int memory_pages; ++ ++ sasIoUnitPg0=NULL; ++ sasPhyPg0=NULL; ++ sasIoUnitPg0_data_sz=0; ++ sasPhyPg0_data_sz=0; ++ ++ memory_pages = get_order(sizeof(CSMI_SAS_PHY_INFO_BUFFER)); ++ karg = (CSMI_SAS_PHY_INFO_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!karg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc CSMI_SAS_PHY_INFO_BUFFER " ++ "malloc_data_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ (int)sizeof(CSMI_SAS_PHY_INFO_BUFFER), memory_pages); ++ return -ENOMEM; ++ } ++ ++ memset(karg, 0, sizeof(*karg)); ++ ++ if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_PHY_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in csmisas_get_phy_info_buffer struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Fill in the data and return the structure to the calling ++ * program ++ */ ++ ++ /* Issue a config request to get the number of phys ++ */ ++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: HEADER\n")); ++ dcsmisasprintk(ioc, printk(": rc=%x\n",rc)); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4; ++ rc = -ENOMEM; ++ ++ sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev, ++ sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma); ++ ++ if (!sasIoUnitPg0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz); ++ cfg.physAddr = sasIoUnitPg0_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: PAGE\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ /* Number of Phys. */ ++ karg->Information.bNumberOfPhys = sasIoUnitPg0->NumPhys; ++ ++ /* Fill in information for each phy. */ ++ for (ii = 0; ii < karg->Information.bNumberOfPhys; ii++) { ++ ++/* EDM : dump IO Unit Page 0 data*/ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", ++ le16_to_cpu(sasIoUnitPg0->PhyData[ii].AttachedDeviceHandle))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n", ++ le16_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerDevHandle))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", ++ sasIoUnitPg0->PhyData[ii].Port)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", ++ sasIoUnitPg0->PhyData[ii].PortFlags)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", ++ sasIoUnitPg0->PhyData[ii].PhyFlags)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", ++ sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n", ++ le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n", ++ le32_to_cpu(sasIoUnitPg0->PhyData[ii].DiscoveryStatus))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); ++/* EDM : debug data */ ++ ++ /* PHY stuff. */ ++ karg->Information.Phy[ii].bPortIdentifier = ++ sasIoUnitPg0->PhyData[ii].Port; ++ ++ /* Get the negotiated link rate for the phy. */ ++ switch (sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate) { ++ ++ case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: ++ karg->Information.Phy[ii].bNegotiatedLinkRate = ++ CSMI_SAS_PHY_DISABLED; ++ break; ++ ++ case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: ++ karg->Information.Phy[ii].bNegotiatedLinkRate = ++ CSMI_SAS_LINK_RATE_FAILED; ++ break; ++ ++ case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: ++ break; ++ ++ case MPI_SAS_IOUNIT0_RATE_1_5: ++ karg->Information.Phy[ii].bNegotiatedLinkRate = ++ CSMI_SAS_LINK_RATE_1_5_GBPS; ++ break; ++ ++ case MPI_SAS_IOUNIT0_RATE_3_0: ++ karg->Information.Phy[ii].bNegotiatedLinkRate = ++ CSMI_SAS_LINK_RATE_3_0_GBPS; ++ break; ++ ++ case MPI_SAS_IOUNIT0_RATE_UNKNOWN: ++ default: ++ karg->Information.Phy[ii].bNegotiatedLinkRate = ++ CSMI_SAS_LINK_RATE_UNKNOWN; ++ break; ++ } ++ ++ if (sasIoUnitPg0->PhyData[ii].PortFlags & ++ MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS) { ++ karg->Information.Phy[ii].bAutoDiscover = ++ CSMI_SAS_DISCOVER_IN_PROGRESS; ++ } else { ++ karg->Information.Phy[ii].bAutoDiscover = ++ CSMI_SAS_DISCOVER_COMPLETE; ++ } ++ ++ /* Issue a config request to get ++ * phy information. ++ */ ++ hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = ii; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n")); ++ dcsmisasprintk(ioc, printk(": rc=%x\n",rc)); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ sasPhyPg0_data_sz = hdr.ExtPageLength * 4; ++ rc = -ENOMEM; ++ ++ sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent( ++ ioc->pcidev, sasPhyPg0_data_sz, &sasPhyPg0_dma); ++ ++ if (! sasPhyPg0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto sas_get_phy_info_exit; ++ } ++ ++ memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz); ++ cfg.physAddr = sasPhyPg0_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, ++ (u8 *) sasPhyPg0, sasPhyPg0_dma); ++ goto sas_get_phy_info_exit; ++ } ++ ++/* EDM : dump PHY Page 0 data*/ ++ memcpy(&sas_address, &sasPhyPg0->SASAddress, sizeof(u64)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", ++ le16_to_cpu(sasPhyPg0->AttachedDevHandle))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", ++ (unsigned long long)sas_address)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", ++ sasPhyPg0->AttachedPhyIdentifier)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n", ++ le32_to_cpu(sasPhyPg0->AttachedDeviceInfo))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", ++ sasPhyPg0->ProgrammedLinkRate)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", ++ sasPhyPg0->HwLinkRate)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", ++ sasPhyPg0->ChangeCount)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n", ++ le32_to_cpu(sasPhyPg0->PhyInfo))); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); ++/* EDM : debug data */ ++ ++ /* save the data */ ++ ++ /* Set Max hardware link rate. ++ * This value is hard coded ++ * because the HW link rate ++ * is currently being ++ * overwritten in FW. ++ */ ++ ++ /* Set Max hardware link rate. */ ++ switch (sasPhyPg0->HwLinkRate & ++ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { ++ ++ case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: ++ karg->Information.Phy[ii].bMaximumLinkRate = ++ CSMI_SAS_LINK_RATE_1_5_GBPS; ++ break; ++ ++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: ++ karg->Information.Phy[ii].bMaximumLinkRate = ++ CSMI_SAS_LINK_RATE_3_0_GBPS; ++ break; ++ default: ++ break; ++ } ++ ++ /* Set Max programmed link rate. */ ++ switch (sasPhyPg0->ProgrammedLinkRate & ++ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { ++ ++ case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: ++ karg->Information.Phy[ii].bMaximumLinkRate |= ++ (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4); ++ break; ++ ++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: ++ karg->Information.Phy[ii].bMaximumLinkRate |= ++ (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4); ++ break; ++ default: ++ break; ++ } ++ ++ /* Set Min hardware link rate. */ ++ switch (sasPhyPg0->HwLinkRate & ++ MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { ++ ++ case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: ++ karg->Information.Phy[ii].bMinimumLinkRate = ++ CSMI_SAS_LINK_RATE_1_5_GBPS; ++ break; ++ ++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: ++ karg->Information.Phy[ii].bMinimumLinkRate = ++ CSMI_SAS_LINK_RATE_3_0_GBPS; ++ break; ++ default: ++ break; ++ } ++ ++ /* Set Min programmed link rate. */ ++ switch (sasPhyPg0->ProgrammedLinkRate & ++ MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { ++ ++ case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: ++ karg->Information.Phy[ii].bMinimumLinkRate |= ++ (CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS << 4); ++ break; ++ ++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: ++ karg->Information.Phy[ii].bMinimumLinkRate |= ++ (CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS << 4); ++ break; ++ default: ++ break; ++ } ++ ++ karg->Information.Phy[ii].bPhyChangeCount = sasPhyPg0->ChangeCount; ++ if( sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY ) ++ karg->Information.Phy[ii].bPhyFeatures = CSMI_SAS_PHY_VIRTUAL_SMP; ++ ++ /* Fill in Attached Device ++ * Initiator Port Protocol. ++ * Bits 6:3 ++ * More than one bit can be set. ++ */ ++ protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x78; ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = 0; ++ if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = ++ CSMI_SAS_PROTOCOL_SSP; ++ if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR) ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_STP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_SMP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST) ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_SATA; ++ ++ /* Fill in Phy Target Port ++ * Protocol. Bits 10:7 ++ * More than one bit can be set. ++ */ ++ protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x780; ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol = 0; ++ if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET) ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_SSP; ++ if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET) ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_STP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET) ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_SMP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE) ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_SATA; ++ ++ ++ /* Fill in Attached device type */ ++ switch (le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & ++ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { ++ ++ case MPI_SAS_DEVICE_INFO_NO_DEVICE: ++ karg->Information.Phy[ii].Attached.bDeviceType = ++ CSMI_SAS_NO_DEVICE_ATTACHED; ++ break; ++ ++ case MPI_SAS_DEVICE_INFO_END_DEVICE: ++ karg->Information.Phy[ii].Attached.bDeviceType = ++ CSMI_SAS_END_DEVICE; ++ break; ++ ++ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: ++ karg->Information.Phy[ii].Attached.bDeviceType = ++ CSMI_SAS_EDGE_EXPANDER_DEVICE; ++ break; ++ ++ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: ++ karg->Information.Phy[ii].Attached.bDeviceType = ++ CSMI_SAS_FANOUT_EXPANDER_DEVICE; ++ break; ++ } ++ ++ /* Identify Info. */ ++ switch (le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & ++ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { ++ ++ case MPI_SAS_DEVICE_INFO_NO_DEVICE: ++ karg->Information.Phy[ii].Identify.bDeviceType = ++ CSMI_SAS_NO_DEVICE_ATTACHED; ++ break; ++ ++ case MPI_SAS_DEVICE_INFO_END_DEVICE: ++ karg->Information.Phy[ii].Identify.bDeviceType = ++ CSMI_SAS_END_DEVICE; ++ break; ++ ++ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: ++ karg->Information.Phy[ii].Identify.bDeviceType = ++ CSMI_SAS_EDGE_EXPANDER_DEVICE; ++ break; ++ ++ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: ++ karg->Information.Phy[ii].Identify.bDeviceType = ++ CSMI_SAS_FANOUT_EXPANDER_DEVICE; ++ break; ++ } ++ ++ /* Fill in Phy Initiator Port Protocol. Bits 6:3 ++ * More than one bit can be set, fall through cases. ++ */ ++ protocol = le32_to_cpu( ++ sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x78; ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol = 0; ++ if( protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR ) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_SSP; ++ if( protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR ) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_STP; ++ if( protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR ) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_SMP; ++ if( protocol & MPI_SAS_DEVICE_INFO_SATA_HOST ) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= ++ CSMI_SAS_PROTOCOL_SATA; ++ ++ /* Fill in Phy Target Port Protocol. Bits 10:7 ++ * More than one bit can be set, fall through cases. ++ */ ++ protocol = le32_to_cpu( ++ sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x780; ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol = 0; ++ if( protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET ) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_SSP; ++ if( protocol & MPI_SAS_DEVICE_INFO_STP_TARGET ) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_STP; ++ if( protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET ) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_SMP; ++ if( protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE ) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol |= ++ CSMI_SAS_PROTOCOL_SATA; ++ ++ /* Setup SAS Address for the attached device */ ++ if (sasPhyPg0->AttachedDevHandle) { ++ sas_address = reverse_byte_order64(sas_address); ++ memcpy(karg->Information.Phy[ii].Attached.bSASAddress, ++ &sas_address, sizeof(u64)); ++ karg->Information.Phy[ii].Attached.bPhyIdentifier = ++ sasPhyPg0->AttachedPhyIdentifier; ++ } ++ ++ /* Setup SAS Address for the parent device */ ++ csmisas_sas_device_pg0(ioc, &device_info, ++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ sasIoUnitPg0->PhyData[ii].ControllerDevHandle); ++ sas_address = reverse_byte_order64(device_info.sas_address); ++ memcpy(karg->Information.Phy[ii].Identify.bSASAddress, ++ &sas_address, sizeof(u64)); ++ karg->Information.Phy[ii].Identify.bPhyIdentifier = ii; ++ ++ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, ++ (u8 *) sasPhyPg0, sasPhyPg0_dma); ++ } ++ ++sas_get_phy_info_exit: ++ ++ if (sasIoUnitPg0) ++ pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz, ++ (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, karg, ++ sizeof(CSMI_SAS_PHY_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to write out csmisas_get_phy_info_buffer @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ free_pages((unsigned long)karg, memory_pages); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Set PHY Info command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_set_phy_info(unsigned long arg) ++{ ++ CSMI_SAS_SET_PHY_INFO_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_SET_PHY_INFO_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_set_phy_info struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++/* TODO - implement IOCTL here */ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); ++ ++// cim_set_phy_info_exit: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_set_phy_info @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++ ++} ++ ++/** ++ * Prototype Routine for the CSMI Sas Get SCSI Address command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_scsi_address(unsigned long arg) ++{ ++ CSMI_SAS_GET_SCSI_ADDRESS_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_GET_SCSI_ADDRESS_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ u64 sas_address; ++ struct sas_device_info *sas_info; ++ ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_get_scsi_address struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* reverse byte order the sas address */ ++ memcpy(&sas_address, karg.bSASAddress, sizeof(u64)); ++ sas_address = reverse_byte_order64(sas_address); ++ ++ /* Search the list for the matching SAS address. */ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SCSI_ADDRESS; ++ karg.bPathId = 0; ++ karg.bTargetId = 0; ++ karg.bLun = 0; ++ ++ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address); ++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) ++ goto csmisas_get_scsi_address_exit; ++ ++ karg.bPathId = sas_info->os.channel; ++ karg.bTargetId = sas_info->os.id; ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ csmisas_get_scsi_address_exit: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_get_scsi_address @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI Sas Get SCSI Address command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_sata_signature(unsigned long arg) ++{ ++ CSMI_SAS_SATA_SIGNATURE_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_SATA_SIGNATURE_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ int rc, jj; ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ SasPhyPage0_t *sasPhyPg0; ++ dma_addr_t sasPhyPg0_dma; ++ int sasPhyPg0_data_sz; ++ SasDevicePage1_t *sasDevicePg1; ++ dma_addr_t sasDevicePg1_dma; ++ int sasDevicePg1_data_sz; ++ u8 phyId; ++ u64 sas_address; ++ ++ sasPhyPg0=NULL; ++ sasPhyPg0_data_sz=0; ++ sasDevicePg1=NULL; ++ sasDevicePg1_data_sz=0; ++ ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_sata_signature struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ phyId = karg.Signature.bPhyIdentifier; ++ if (phyId >= ioc->num_ports) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST; ++ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); ++ goto cim_sata_signature_exit; ++ } ++ ++ /* Default to success.*/ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Issue a config request to get the devHandle of the attached device ++ */ ++ ++ /* Issue a config request to get phy information. */ ++ hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = phyId; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ ++ sasPhyPg0_data_sz = hdr.ExtPageLength * 4; ++ rc = -ENOMEM; ++ ++ sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(ioc->pcidev, ++ sasPhyPg0_data_sz, &sasPhyPg0_dma); ++ ++ if (! sasPhyPg0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ memset((u8 *)sasPhyPg0, 0, sasPhyPg0_data_sz); ++ cfg.physAddr = sasPhyPg0_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ /* Make sure a SATA device is attached. */ ++ if ((le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) { ++ dcsmisasprintk(ioc, printk(KERN_WARNING ": NOT A SATA DEVICE\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE; ++ goto cim_sata_signature_exit; ++ } ++ ++ /* Get device page 1 for FIS signature. */ ++ hdr.PageVersion = MPI_SASDEVICE1_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 1 /* page number 1 */; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ ++ cfg.pageAddr = ((MPI_SAS_DEVICE_PGAD_FORM_HANDLE << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT) | ++ le16_to_cpu(sasPhyPg0->AttachedDevHandle)); ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASDEVICE1_PAGEVERSION: HEADER\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ sasDevicePg1_data_sz = hdr.ExtPageLength * 4; ++ rc = -ENOMEM; ++ ++ sasDevicePg1 = (SasDevicePage1_t *) pci_alloc_consistent ++ (ioc->pcidev, sasDevicePg1_data_sz, &sasDevicePg1_dma); ++ ++ if (! sasDevicePg1) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++ memset((u8 *)sasDevicePg1, 0, sasDevicePg1_data_sz); ++ cfg.physAddr = sasDevicePg1_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASDEVICE1_PAGEVERSION: PAGE\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sata_signature_exit; ++ } ++ ++/* EDM : dump Device Page 1 data*/ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 1 ---------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%x\n",sasDevicePg1->DevHandle)); ++ memcpy(&sas_address, &sasDevicePg1->SASAddress, sizeof(u64)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", ++ (unsigned long long)sas_address)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%x\n",sasDevicePg1->TargetID)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Bus=0x%x\n",sasDevicePg1->Bus)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Initial Reg Device FIS=")); ++ for(jj=0;jj<20;jj++) ++ dcsmisasprintk(ioc, printk("%02x ", ++ ((u8 *)&sasDevicePg1->InitialRegDeviceFIS)[jj])); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n")); ++/* EDM : debug data */ ++ ++ memcpy(karg.Signature.bSignatureFIS, ++ sasDevicePg1->InitialRegDeviceFIS,20); ++ ++ cim_sata_signature_exit: ++ ++ if (sasPhyPg0) ++ pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, ++ (u8 *) sasPhyPg0, sasPhyPg0_dma); ++ ++ if (sasDevicePg1) ++ pci_free_consistent(ioc->pcidev, sasDevicePg1_data_sz, ++ (u8 *) sasDevicePg1, sasDevicePg1_dma); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_sata_signature @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI Sas Get SCSI Address command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_device_address(unsigned long arg) ++{ ++ CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ struct sas_device_info *sas_info; ++ u64 sas_address; ++ ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_get_device_address_buffer struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_DEVICE_ADDRESS; ++ memset(karg.bSASAddress, 0, sizeof(u64)); ++ memset(karg.bSASLun, 0, sizeof(karg.bSASLun)); ++ ++ /* Search the list for the matching SAS address. */ ++ sas_info = csmisas_get_device_component_by_os(ioc, karg.bPathId, ++ karg.bTargetId); ++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) ++ goto csmisas_get_device_address_exit; ++ ++ sas_address = reverse_byte_order64(sas_info->sas_address); ++ memcpy(karg.bSASAddress, &sas_address, sizeof(u64)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ csmisas_get_device_address_exit: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_get_device_address_buffer @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI Sas Get Link Errors command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_link_errors(unsigned long arg) ++{ ++ CSMI_SAS_LINK_ERRORS_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_LINK_ERRORS_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ int iocnum; ++ int rc; ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ SasPhyPage1_t *sasPhyPage1; ++ dma_addr_t sasPhyPage1_dma; ++ int sasPhyPage1_data_sz; ++ SasIoUnitControlRequest_t *sasIoUnitCntrReq; ++ SasIoUnitControlReply_t *sasIoUnitCntrReply; ++ u8 phyId; ++ u16 ioc_status; ++ u32 MsgContext; ++ ++ sasPhyPage1=NULL; ++ sasPhyPage1_data_sz=0; ++ ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmisas_get_link_errors struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ phyId = karg.Information.bPhyIdentifier; ++ if (phyId >= ioc->num_ports) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST; ++ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); ++ goto cim_get_link_errors_exit; ++ } ++ ++ /* Default to success.*/ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Issue a config request to get the devHandle of the attached device ++ */ ++ ++ /* Issue a config request to get phy information. */ ++ hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 1 /* page number 1*/; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = phyId; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASPHY1_PAGEVERSION: HEADER\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_link_errors_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_link_errors_exit; ++ } ++ ++ ++ sasPhyPage1_data_sz = hdr.ExtPageLength * 4; ++ rc = -ENOMEM; ++ ++ sasPhyPage1 = (SasPhyPage1_t *) pci_alloc_consistent(ioc->pcidev, ++ sasPhyPage1_data_sz, &sasPhyPage1_dma); ++ ++ if (! sasPhyPage1) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_link_errors_exit; ++ } ++ ++ memset((u8 *)sasPhyPage1, 0, sasPhyPage1_data_sz); ++ cfg.physAddr = sasPhyPage1_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ /* Don't check if this failed. Already in a ++ * failure case. ++ */ ++ dcsmisasprintk(ioc, printk(KERN_ERR ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_link_errors_exit; ++ } ++ ++/* EDM : dump PHY Page 1 data*/ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", ++ sasPhyPage1->InvalidDwordCount)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n", ++ sasPhyPage1->RunningDisparityErrorCount)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", ++ sasPhyPage1->LossDwordSynchCount)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n", ++ sasPhyPage1->PhyResetProblemCount)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n")); ++/* EDM : debug data */ ++ ++ karg.Information.uInvalidDwordCount = ++ le32_to_cpu(sasPhyPage1->InvalidDwordCount); ++ karg.Information.uRunningDisparityErrorCount = ++ le32_to_cpu(sasPhyPage1->RunningDisparityErrorCount); ++ karg.Information.uLossOfDwordSyncCount = ++ le32_to_cpu(sasPhyPage1->LossDwordSynchCount); ++ karg.Information.uPhyResetProblemCount = ++ le32_to_cpu(sasPhyPage1->PhyResetProblemCount); ++ ++ if (karg.Information.bResetCounts == ++ CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS ) { ++ goto cim_get_link_errors_exit; ++ } ++ ++ /* Clear Error log ++ * ++ * Issue IOUNIT Control Reqeust Message ++ */ ++ ++ /* Get a MF for this command. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_link_errors_exit; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; ++ memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); ++ sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; ++ sasIoUnitCntrReq->MsgContext = MsgContext; ++ sasIoUnitCntrReq->PhyNum = phyId; ++ sasIoUnitCntrReq->Operation = MPI_SAS_OP_PHY_CLEAR_ERROR_LOG; ++ ++ if (csmisas_send_command_wait(ioc, mf, karg.IoctlHeader.Timeout) != 0) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_link_errors_exit; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { ++ ++ sasIoUnitCntrReply = ++ (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply; ++ ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus) ++ & MPI_IOCSTATUS_MASK; ++ ++ if (ioc_status != MPI_IOCSTATUS_SUCCESS) { ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SAS IO Unit Control: ")); ++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ sasIoUnitCntrReply->IOCStatus, ++ sasIoUnitCntrReply->IOCLogInfo)); ++ } ++ } ++ ++ cim_get_link_errors_exit: ++ ++ if (sasPhyPage1) ++ pci_free_consistent(ioc->pcidev, sasPhyPage1_data_sz, ++ (u8 *) sasPhyPage1, sasPhyPage1_dma); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmisas_get_link_errors @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++ ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS SMP Passthru command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_smp_passthru(unsigned long arg) ++{ ++ CSMI_SAS_SMP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg; ++ MPT_ADAPTER *ioc; ++ CSMI_SAS_SMP_PASSTHRU_BUFFER *karg; ++ pSmpPassthroughRequest_t smpReq; ++ pSmpPassthroughReply_t smpReply; ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ char *psge; ++ int iocnum, flagsLength; ++ void * request_data; ++ dma_addr_t request_data_dma; ++ u32 request_data_sz; ++ void * response_data; ++ dma_addr_t response_data_dma; ++ u32 response_data_sz; ++ u16 ioc_status; ++ u64 sas_address; ++ u32 MsgContext; ++ int malloc_data_sz; ++ int memory_pages; ++ ++ malloc_data_sz = sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER); ++ memory_pages = get_order(malloc_data_sz); ++ karg = (CSMI_SAS_SMP_PASSTHRU_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!karg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc CSMI_SAS_SMP_PASSTHRU_BUFFER " ++ "malloc_data_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ malloc_data_sz, memory_pages); ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_smp_passthru struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ request_data = NULL; ++ response_data = NULL; ++ response_data_sz = sizeof(CSMI_SAS_SMP_RESPONSE); ++ request_data_sz = karg->Parameters.uRequestLength; ++ ++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (ioc->ioc_reset_in_progress) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Busy with IOC Reset \n", ++ __FILE__, __LINE__,__FUNCTION__); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EBUSY; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Default to success.*/ ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Do some error checking on the request. */ ++ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT; ++ goto cim_smp_passthru_exit; ++ } ++ ++ if ((request_data_sz > 0xFFFF) || (!request_data_sz)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_smp_passthru_exit; ++ } ++ ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_smp_passthru_exit; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ smpReq = (pSmpPassthroughRequest_t ) mf; ++ ++ memset(smpReq,0,ioc->req_sz); ++ ++ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress, ++ sizeof(u64)); ++ sas_address = cpu_to_le64(reverse_byte_order64(sas_address)); ++ memcpy(&smpReq->SASAddress, &sas_address, sizeof(u64)); ++ ++ /* Fill in smp request. */ ++ smpReq->PhysicalPort = karg->Parameters.bPortIdentifier; ++ smpReq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; ++ smpReq->RequestDataLength = cpu_to_le16(request_data_sz); ++ smpReq->ConnectionRate = karg->Parameters.bConnectionRate; ++ smpReq->MsgContext = MsgContext; ++ smpReq->Reserved2 = 0; ++ smpReq->Reserved3 = 0; ++ ++ /* ++ * Prepare the necessary pointers to run ++ * through the SGL generation ++ */ ++ ++ psge = (char *)&smpReq->SGL; ++ ++ /* setup the *Request* payload SGE */ ++ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_SYSTEM_ADDRESS | ++ MPI_SGE_FLAGS_HOST_TO_IOC | ++ MPI_SGE_FLAGS_END_OF_BUFFER; ++ ++ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; ++ flagsLength |= request_data_sz; ++ ++ request_data = pci_alloc_consistent( ++ ioc->pcidev, request_data_sz, &request_data_dma); ++ ++ if (!request_data) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ mpt_free_msg_frame(ioc, mf); ++ goto cim_smp_passthru_exit; ++ } ++ ++ ioc->add_sge(psge, flagsLength, request_data_dma); ++ psge += ioc->SGE_size; ++ ++ memcpy(request_data, &karg->Parameters.Request, request_data_sz); ++ ++ /* setup the *Response* payload SGE */ ++ response_data = pci_alloc_consistent( ++ ioc->pcidev, response_data_sz, &response_data_dma); ++ ++ if (!response_data) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ mpt_free_msg_frame(ioc, mf); ++ goto cim_smp_passthru_exit; ++ } ++ ++ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_SYSTEM_ADDRESS | ++ MPI_SGE_FLAGS_IOC_TO_HOST | ++ MPI_SGE_FLAGS_END_OF_BUFFER; ++ ++ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; ++ flagsLength |= response_data_sz; ++ ++ ioc->add_sge(psge, flagsLength, response_data_dma); ++ ++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_smp_passthru_exit; ++ } ++ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: oh no, there is no reply!!")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_smp_passthru_exit; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ smpReply = (pSmpPassthroughReply_t )ioc->ioctl_cmds.reply; ++ ioc_status = le16_to_cpu(smpReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ ++ if ((ioc_status != MPI_IOCSTATUS_SUCCESS) && ++ (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: ")); ++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", ++ le16_to_cpu(smpReply->IOCStatus), ++ le32_to_cpu(smpReply->IOCLogInfo), ++ smpReply->SASStatus)); ++ goto cim_smp_passthru_exit; ++ } ++ ++ karg->Parameters.bConnectionStatus = ++ map_sas_status_to_csmi(smpReply->SASStatus); ++ ++ ++ if (le16_to_cpu(smpReply->ResponseDataLength)) { ++ karg->Parameters.uResponseBytes = le16_to_cpu(smpReply->ResponseDataLength); ++ memcpy(&karg->Parameters.Response, ++ response_data, le16_to_cpu(smpReply->ResponseDataLength)); ++ } ++ ++ cim_smp_passthru_exit: ++ ++ if (request_data) ++ pci_free_consistent(ioc->pcidev, request_data_sz, ++ (u8 *)request_data, request_data_dma); ++ ++ if (response_data) ++ pci_free_consistent(ioc->pcidev, response_data_sz, ++ (u8 *)response_data, response_data_dma); ++ ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, karg, ++ sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_smp_passthru @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ free_pages((unsigned long)karg, memory_pages); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS SSP Passthru command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int csmisas_ssp_passthru(unsigned long arg) ++{ ++ CSMI_SAS_SSP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_SSP_PASSTHRU_BUFFER karg_hdr, * karg; ++ MPT_ADAPTER *ioc = NULL; ++ pSCSIIORequest_t pScsiRequest; ++ pSCSIIOReply_t pScsiReply; ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ int iocnum,ii; ++ u64 sas_address; ++ u16 req_idx; ++ char *psge; ++ int flagsLength; ++ void * request_data; ++ dma_addr_t request_data_dma; ++ u32 request_data_sz; ++ int malloc_data_sz; ++ int memory_pages; ++ u16 ioc_status; ++ u8 volume_id; ++ u8 volume_bus; ++ u8 is_hidden_raid_component; ++ u8 channel; ++ u8 id; ++ struct sas_device_info *sas_info; ++ u8 skey, asc, ascq; ++ u32 MsgContext; ++ ++ if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_SSP_PASSTHRU_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ request_data = NULL; ++ request_data_sz = karg_hdr.Parameters.uDataLength; ++ channel = 0; ++ id = 0; ++ volume_id = 0; ++ volume_bus = 0; ++ is_hidden_raid_component = 0; ++ ++ malloc_data_sz = (request_data_sz + ++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer)); ++ memory_pages = get_order(malloc_data_sz); ++ karg = (CSMI_SAS_SSP_PASSTHRU_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!karg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc SAS_SSP_PASSTHRU_BUFFER " ++ "malloc_data_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ malloc_data_sz, memory_pages); ++ return -ENOMEM; ++ } ++ ++ memset(karg, 0, sizeof(*karg)); ++ ++ if (copy_from_user(karg, uarg, request_data_sz + ++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ /* ++ * some checks of the incoming frame ++ */ ++ if ( offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer) + ++ request_data_sz - sizeof(IOCTL_HEADER) > ++ karg->IoctlHeader.Length ) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ "%s::%s()" ++ " @%d - expected datalen incorrect!\n", ++ __FILE__, __FUNCTION__, __LINE__)); ++ goto cim_ssp_passthru_exit; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ goto cim_ssp_passthru_exit; ++ } ++ ++ if (ioc->ioc_reset_in_progress) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Busy with IOC Reset \n", ++ __FILE__, __LINE__,__FUNCTION__); ++ return -EBUSY; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ printk(KERN_ERR "%s::%s()@%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ goto cim_ssp_passthru_exit; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Default to success. ++ */ ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Neither a phy nor a port has been selected. ++ */ ++ if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) && ++ (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT; ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ "%s::%s()" ++ " @%d - incorrect bPhyIdentifier and bPortIdentifier!\n", ++ __FILE__, __FUNCTION__, __LINE__)); ++ goto cim_ssp_passthru_exit; ++ } ++ ++ /* A phy has been selected. Verify that it's valid. ++ */ ++ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) { ++ ++ /* Is the phy in range? */ ++ if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) { ++ dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports (%d %d)\n", ++ karg->Parameters.bPhyIdentifier, ++ ioc->num_ports)); ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_PHY_DOES_NOT_EXIST; ++ goto cim_ssp_passthru_exit; ++ } ++ } ++ ++ if(karg->Parameters.bAdditionalCDBLength) { ++ /* TODO - SCSI IO (32) Request Message support ++ */ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": greater than 16-byte cdb " ++ "is not supported!\n")); ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ goto cim_ssp_passthru_exit; ++ } ++ ++ /* we will use SAS address to resolve the scsi adddressing ++ */ ++ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress, ++ sizeof(u64)); ++ sas_address = reverse_byte_order64(sas_address); ++ ++ /* Search the list for the matching SAS address. ++ */ ++ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address); ++ if (!sas_info || sas_info->is_cached) { ++ /* ++ *Invalid SAS address ++ */ ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ "%s::%s() @%d - couldn't find associated " ++ "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__, ++ (unsigned long long)sas_address)); ++ goto cim_ssp_passthru_exit; ++ } ++ ++ id = sas_info->fw.id; ++ channel = sas_info->fw.channel; ++ ++ if (csmisas_is_phys_disk(ioc, channel, id)) { ++ id = csmisas_raid_id_to_num(ioc, channel, id); ++ channel = 0; ++ is_hidden_raid_component = 1; ++ } ++ ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_ssp_passthru_exit; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ pScsiRequest = (pSCSIIORequest_t) mf; ++ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); ++ ++ memset(pScsiRequest,0,sizeof(SCSIIORequest_t)); ++ ++ /* Fill in SCSI IO (16) request. ++ */ ++ ++ pScsiRequest->Function = (is_hidden_raid_component == 1) ? ++ MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH : MPI_FUNCTION_SCSI_IO_REQUEST; ++ pScsiRequest->TargetID = id; ++ pScsiRequest->Bus = channel; ++ memcpy(pScsiRequest->LUN, &karg->Parameters.bLun, 8); ++ pScsiRequest->CDBLength = karg->Parameters.bCDBLength; ++ pScsiRequest->DataLength = cpu_to_le32(request_data_sz); ++ pScsiRequest->MsgContext = MsgContext; ++ memcpy(pScsiRequest->CDB, karg->Parameters.bCDB, ++ pScsiRequest->CDBLength); ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\tchannel = %d id = %d ", ++ sas_info->fw.channel, sas_info->fw.id)); ++ dcsmisasprintk(ioc, if(is_hidden_raid_component) ++ printk(KERN_DEBUG "num_id = %d ", id)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\tcdb_len = %d request_len = %d\n", ++ pScsiRequest->CDBLength, request_data_sz)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\t")); ++ dcsmisasprintk(ioc, for (ii = 0; ii < pScsiRequest->CDBLength; ++ii) ++ printk(" %02x", pScsiRequest->CDB[ii])); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); ++ ++ /* direction ++ */ ++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) { ++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ); ++ } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) { ++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_WRITE); ++ } else if ((karg->Parameters.uFlags & CSMI_SAS_SSP_UNSPECIFIED) && ++ (!karg->Parameters.uDataLength)) { ++ /* no data transfer ++ */ ++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_NODATATRANSFER); ++ } else { ++ /* no direction specified ++ */ ++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ); ++ pScsiRequest->MsgFlags = ++ MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR; ++ } ++ ++ pScsiRequest->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; ++ if (ioc->sg_addr_size == sizeof(u64)) ++ pScsiRequest->MsgFlags |= MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64; ++ ++ /* task attributes ++ */ ++ if((karg->Parameters.uFlags && 0xFF) == 0) { ++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ); ++ } else if (karg->Parameters.uFlags & ++ CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE) { ++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ); ++ } else if (karg->Parameters.uFlags & ++ CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED) { ++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ); ++ } else if (karg->Parameters.uFlags & ++ CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA) { ++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ACAQ); ++ } else { ++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED); ++ } ++ ++ /* setup sense ++ */ ++ pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; ++ pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + ++ (req_idx * MPT_SENSE_BUFFER_ALLOC)); ++ ++ /* setup databuffer sg, assuming we fit everything one contiguous buffer ++ */ ++ psge = (char *)&pScsiRequest->SGL; ++ ++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) { ++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; ++ } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) { ++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; ++ }else { ++ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_DIRECTION ) ++ << MPI_SGE_FLAGS_SHIFT; ++ } ++ flagsLength |= request_data_sz; ++ ++ if ( request_data_sz > 0) { ++ request_data = pci_alloc_consistent( ++ ioc->pcidev, request_data_sz, &request_data_dma); ++ ++ if (request_data == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED " ++ "request_data_sz=%d\n", request_data_sz)); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ mpt_free_msg_frame(ioc, mf); ++ goto cim_ssp_passthru_exit; ++ } ++ ++ ioc->add_sge(psge, flagsLength, request_data_dma); ++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) ++ memcpy(request_data, karg->bDataBuffer, request_data_sz); ++ } else { ++ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); ++ } ++ ++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_ssp_passthru_exit; ++ } ++ ++ memset(&karg->Status,0,sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); ++ karg->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT; ++ karg->Status.bDataPresent = CSMI_SAS_SSP_NO_DATA_PRESENT; ++ karg->Status.bStatus = GOOD; ++ karg->Status.bResponseLength[0] = 0; ++ karg->Status.bResponseLength[1] = 0; ++ karg->Status.uDataBytes = request_data_sz; ++ ++ /* process the completed Reply Message Frame */ ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { ++ ++ pScsiReply = (pSCSIIOReply_t ) ioc->ioctl_cmds.reply; ++ karg->Status.bStatus = pScsiReply->SCSIStatus; ++ karg->Status.uDataBytes = min(le32_to_cpu(pScsiReply->TransferCount), ++ request_data_sz); ++ ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ ++ if (pScsiReply->SCSIState == ++ MPI_SCSI_STATE_AUTOSENSE_VALID) { ++ karg->Status.bConnectionStatus = ++ CSMI_SAS_SSP_SENSE_DATA_PRESENT; ++ karg->Status.bResponseLength[0] = ++ (u8)le32_to_cpu(pScsiReply->SenseCount) & 0xFF; ++ memcpy(karg->Status.bResponse, ++ ioc->ioctl_cmds.sense, le32_to_cpu(pScsiReply->SenseCount)); ++ ++ skey = ioc->ioctl_cmds.sense[2] & 0x0F; ++ asc = ioc->ioctl_cmds.sense[12]; ++ ascq = ioc->ioctl_cmds.sense[13]; ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "\t [sense_key,asc,ascq]: " ++ "[0x%02x,0x%02x,0x%02x]\n", ++ skey, asc, ascq)); ++ ++ } else if(pScsiReply->SCSIState == ++ MPI_SCSI_STATE_RESPONSE_INFO_VALID) { ++ karg->Status.bDataPresent = ++ CSMI_SAS_SSP_RESPONSE_DATA_PRESENT; ++ karg->Status.bResponseLength[0] = ++ sizeof(pScsiReply->ResponseInfo); ++ for (ii=0;iiResponseInfo);ii++) { ++ karg->Status.bResponse[ii] = ++ ((u8*)&pScsiReply->ResponseInfo)[ ++ (sizeof(pScsiReply->ResponseInfo)-1)-ii]; ++ } ++ } else if ((ioc_status != MPI_IOCSTATUS_SUCCESS) && ++ (ioc_status != MPI_IOCSTATUS_SCSI_RECOVERED_ERROR) && ++ (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": SCSI IO : ")); ++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ pScsiReply->IOCStatus, ++ pScsiReply->IOCLogInfo)); ++ } ++ } ++ ++ if ((karg->Status.uDataBytes) && (request_data) && ++ (karg->Parameters.uFlags & CSMI_SAS_SSP_READ)) { ++ if (copy_to_user((void __user *)uarg->bDataBuffer, ++ request_data, karg->Status.uDataBytes)) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to write data to user %p\n", ++ __FILE__, __LINE__,__FUNCTION__, ++ (void*)karg->bDataBuffer); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ } ++ } ++ ++ cim_ssp_passthru_exit: ++ ++ ++ if (request_data) ++ pci_free_consistent(ioc->pcidev, request_data_sz, ++ (u8 *)request_data, request_data_dma); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, karg, ++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_ssp_passthru @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ free_pages((unsigned long)karg, memory_pages); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS STP Passthru command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_stp_passthru(unsigned long arg) ++{ ++ CSMI_SAS_STP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_STP_PASSTHRU_BUFFER karg_hdr, *karg; ++ MPT_ADAPTER *ioc = NULL; ++ pSataPassthroughRequest_t pSataRequest; ++ pSataPassthroughReply_t pSataReply; ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ int iocnum; ++ u32 data_sz; ++ u64 sas_address; ++ u16 req_idx; ++ char *psge; ++ int flagsLength; ++ void * request_data; ++ dma_addr_t request_data_dma; ++ u32 request_data_sz; ++ int malloc_data_sz; ++ int memory_pages; ++ u8 channel; ++ u8 id; ++ u8 volume_id; ++ u8 volume_bus; ++ struct sas_device_info *sas_info; ++ u16 ioc_status; ++ u32 MsgContext; ++ ++ if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ request_data=NULL; ++ request_data_sz = karg_hdr.Parameters.uDataLength; ++ volume_id = 0; ++ volume_bus = 0; ++ channel = 0; ++ id = 0; ++ ++ malloc_data_sz = (request_data_sz + ++ offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer)); ++ memory_pages = get_order(malloc_data_sz); ++ karg = (CSMI_SAS_STP_PASSTHRU_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!karg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc CSMI_SAS_STP_PASSTHRU_BUFFER " ++ "malloc_data_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ malloc_data_sz, memory_pages); ++ return -ENOMEM; ++ } ++ ++ memset(karg, 0, sizeof(*karg)); ++ ++ if (copy_from_user(karg, uarg, malloc_data_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (ioc->ioc_reset_in_progress) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Busy with IOC Reset \n", ++ __FILE__, __LINE__,__FUNCTION__); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EBUSY; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Default to success. ++ */ ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* Neither a phy nor a port has been selected. ++ */ ++ if ((karg->Parameters.bPhyIdentifier == CSMI_SAS_USE_PORT_IDENTIFIER) && ++ (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT; ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ "%s::%s() @%d - incorrect bPhyIdentifier and bPortIdentifier!\n", ++ __FILE__,__FUNCTION__, __LINE__)); ++ goto cim_stp_passthru_exit; ++ } ++ ++ /* A phy has been selected. Verify that it's valid. ++ */ ++ if (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT) { ++ ++ /* Is the phy in range? */ ++ if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_PHY_DOES_NOT_EXIST; ++ goto cim_stp_passthru_exit; ++ } ++ } ++ ++ data_sz = sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) - ++ sizeof(IOCTL_HEADER) - sizeof(u8*) + ++ request_data_sz; ++ ++ if ( data_sz > karg->IoctlHeader.Length ) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ "%s::%s() @%d - expected datalen incorrect!\n", ++ __FILE__, __FUNCTION__,__LINE__)); ++ goto cim_stp_passthru_exit; ++ } ++ ++ ++ /* we will use SAS address to resolve the scsi adddressing ++ */ ++ memcpy(&sas_address, karg->Parameters.bDestinationSASAddress, ++ sizeof(u64)); ++ sas_address = reverse_byte_order64(sas_address); ++ ++ /* Search the list for the matching SAS address. ++ */ ++ sas_info = csmisas_get_device_component_by_sas_addr(ioc, sas_address); ++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) { ++ /* ++ *Invalid SAS address ++ */ ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ "%s::%s() @%d - couldn't find associated " ++ "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__, ++ (unsigned long long)sas_address)); ++ goto cim_stp_passthru_exit; ++ } ++ ++ id = sas_info->fw.id; ++ channel = sas_info->fw.channel; ++ ++ /* check that this is an STP or SATA target device ++ */ ++ if ( !(sas_info->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET ) && ++ !(sas_info->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE )) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ goto cim_stp_passthru_exit; ++ } ++ ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_stp_passthru_exit; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ pSataRequest = (pSataPassthroughRequest_t) mf; ++ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); ++ ++ memset(pSataRequest,0,sizeof(pSataPassthroughRequest_t)); ++ ++ pSataRequest->TargetID = id; ++ pSataRequest->Bus = channel; ++ pSataRequest->Function = MPI_FUNCTION_SATA_PASSTHROUGH; ++ pSataRequest->PassthroughFlags = cpu_to_le16(karg->Parameters.uFlags); ++ pSataRequest->ConnectionRate = karg->Parameters.bConnectionRate; ++ pSataRequest->MsgContext = MsgContext; ++ pSataRequest->DataLength = cpu_to_le32(request_data_sz); ++ pSataRequest->MsgFlags = 0; ++ memcpy( pSataRequest->CommandFIS,karg->Parameters.bCommandFIS, 20); ++ ++ psge = (char *)&pSataRequest->SGL; ++ if (karg->Parameters.uFlags & CSMI_SAS_STP_WRITE) { ++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; ++ } else if (karg->Parameters.uFlags & CSMI_SAS_STP_READ) { ++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; ++ }else { ++ flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_DIRECTION ) ++ << MPI_SGE_FLAGS_SHIFT; ++ } ++ ++ flagsLength |= request_data_sz; ++ if (request_data_sz > 0) { ++ request_data = pci_alloc_consistent( ++ ioc->pcidev, request_data_sz, &request_data_dma); ++ ++ if (request_data == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ mpt_free_msg_frame(ioc, mf); ++ goto cim_stp_passthru_exit; ++ } ++ ++ ioc->add_sge(psge, flagsLength, request_data_dma); ++ if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) ++ memcpy(request_data, karg->bDataBuffer, request_data_sz); ++ } else { ++ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); ++ } ++ ++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_stp_passthru_exit; ++ } ++ ++ memset(&karg->Status,0,sizeof(CSMI_SAS_STP_PASSTHRU_STATUS)); ++ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: oh no, there is no reply!!")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_stp_passthru_exit; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ pSataReply = (pSataPassthroughReply_t ) ioc->ioctl_cmds.reply; ++ ioc_status = le16_to_cpu(pSataReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ ++ if (ioc_status != MPI_IOCSTATUS_SUCCESS && ++ ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) { ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: ")); ++ dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", ++ le16_to_cpu(pSataReply->IOCStatus), ++ le32_to_cpu(pSataReply->IOCLogInfo), ++ pSataReply->SASStatus)); ++ } ++ ++ karg->Status.bConnectionStatus = ++ map_sas_status_to_csmi(pSataReply->SASStatus); ++ ++ memcpy(karg->Status.bStatusFIS,pSataReply->StatusFIS, 20); ++ ++ /* ++ * for now, just zero out uSCR array, ++ * then copy the one dword returned ++ * in the reply frame into uSCR[0] ++ */ ++ memset( karg->Status.uSCR, 0, 64); ++ karg->Status.uSCR[0] = le32_to_cpu(pSataReply->StatusControlRegisters); ++ ++ if((le32_to_cpu(pSataReply->TransferCount)) && (request_data) && ++ (karg->Parameters.uFlags & CSMI_SAS_STP_READ)) { ++ karg->Status.uDataBytes = ++ min(le32_to_cpu(pSataReply->TransferCount),request_data_sz); ++ if (copy_to_user((void __user *)uarg->bDataBuffer, ++ request_data, karg->Status.uDataBytes)) { ++ printk(KERN_ERR "%s::%s() @%d - " ++ "Unable to write data to user %p\n", ++ __FILE__, __FUNCTION__, __LINE__, ++ (void*)karg->bDataBuffer); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ } ++ } ++ ++ cim_stp_passthru_exit: ++ ++ if (request_data) ++ pci_free_consistent(ioc->pcidev, request_data_sz, ++ (u8 *)request_data, request_data_dma); ++ ++ /* Copy th data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, karg, ++ offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_ssp_passthru @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ free_pages((unsigned long)karg, memory_pages); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Firmware Download command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_firmware_download(unsigned long arg) ++{ ++ CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ pMpiFwHeader_t pFwHeader=NULL; ++ ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_firmware_download struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ /* Default to success.*/ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ karg.Information.usStatus = CSMI_SAS_FWD_SUCCESS; ++ karg.Information.usSeverity = CSMI_SAS_FWD_INFORMATION; ++ ++ /* some checks of the incoming frame */ ++ if ((karg.Information.uBufferLength + ++ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD)) > ++ karg.IoctlHeader.Length) { ++ karg.IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ karg.Information.usStatus = CSMI_SAS_FWD_FAILED; ++ goto cim_firmware_download_exit; ++ } ++ ++ if ( karg.Information.uDownloadFlags & ++ (CSMI_SAS_FWD_SOFT_RESET | CSMI_SAS_FWD_VALIDATE)) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ karg.Information.usStatus = CSMI_SAS_FWD_REJECT; ++ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR; ++ goto cim_firmware_download_exit; ++ } ++ ++ /* now we need to alloc memory so we can pull in the ++ * fw image attached to end of incoming packet. ++ */ ++ pFwHeader = kmalloc(karg.Information.uBufferLength, GFP_KERNEL); ++ if (!pFwHeader){ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ karg.Information.usStatus = CSMI_SAS_FWD_REJECT; ++ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR; ++ goto cim_firmware_download_exit; ++ } ++ memset(pFwHeader, 0, sizeof(*pFwHeader)); ++ ++ if (copy_from_user(pFwHeader, uarg->bDataBuffer, ++ karg.Information.uBufferLength)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in pFwHeader @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if ( !((pFwHeader->Signature0 == MPI_FW_HEADER_SIGNATURE_0) && ++ (pFwHeader->Signature1 == MPI_FW_HEADER_SIGNATURE_1) && ++ (pFwHeader->Signature2 == MPI_FW_HEADER_SIGNATURE_2))) { ++ // the signature check failed ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ karg.Information.usStatus = CSMI_SAS_FWD_REJECT; ++ karg.Information.usSeverity = CSMI_SAS_FWD_ERROR; ++ goto cim_firmware_download_exit; ++ } ++ ++ if ( mptctl_do_fw_download(karg.IoctlHeader.IOControllerNumber, ++ uarg->bDataBuffer, karg.Information.uBufferLength) ++ != 0) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ karg.Information.usStatus = CSMI_SAS_FWD_FAILED; ++ karg.Information.usSeverity = CSMI_SAS_FWD_FATAL; ++ goto cim_firmware_download_exit; ++ } ++ ++ if((karg.Information.uDownloadFlags & CSMI_SAS_FWD_SOFT_RESET) || ++ (karg.Information.uDownloadFlags & CSMI_SAS_FWD_HARD_RESET)) { ++ if (mpt_HardResetHandler(ioc, CAN_SLEEP) != 0) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ karg.Information.usStatus = CSMI_SAS_FWD_FAILED; ++ karg.Information.usSeverity = CSMI_SAS_FWD_FATAL; ++ } ++ } ++ ++ cim_firmware_download_exit: ++ ++ if(pFwHeader) ++ kfree(pFwHeader); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_firmware_download @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Get RAID Info command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_raid_info(unsigned long arg) ++{ ++ CSMI_SAS_RAID_INFO_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_RAID_INFO_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ u32 raidFlags; ++ u8 maxRaidTypes; ++ u8 maxDrivesPerSet; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_get_raid_info struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ if (!ioc->raid_data.pIocPg2) ++ goto csmisas_get_raid_info_out; ++ karg.Information.uNumRaidSets = ++ ioc->raid_data.pIocPg2->NumActiveVolumes; ++ karg.Information.uMaxRaidSets = ioc->raid_data.pIocPg2->MaxVolumes; ++ if( ioc->raid_data.pIocPg6 ) { ++ // get absolute maximum for all RAID sets ++ maxDrivesPerSet = ioc->raid_data.pIocPg6->MaxDrivesIS; ++ maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIM, ++ maxDrivesPerSet); ++ maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIME, ++ maxDrivesPerSet); ++ karg.Information.uMaxDrivesPerSet = maxDrivesPerSet; ++ } ++ else ++ karg.Information.uMaxDrivesPerSet = 8; ++ // For bMaxRaidSets, count bits set in bits 0-6 of CapabilitiesFlags ++ raidFlags = ioc->raid_data.pIocPg2->CapabilitiesFlags & 0x0000007F; ++ for( maxRaidTypes=0; raidFlags; maxRaidTypes++ ) ++ raidFlags &= raidFlags - 1; ++ karg.Information.bMaxRaidTypes = maxRaidTypes; ++ // ulMinRaidSetBlocks hard coded to 1MB until available from config page ++ karg.Information.ulMinRaidSetBlocks.uLowPart = 2048; ++ karg.Information.ulMinRaidSetBlocks.uHighPart = 0; ++ karg.Information.ulMaxRaidSetBlocks.uLowPart = 0xffffffff; ++ if( ioc->raid_data.pIocPg2->CapabilitiesFlags & ++ MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING ) ++ karg.Information.ulMaxRaidSetBlocks.uHighPart = 0xffffffff; ++ else ++ karg.Information.ulMaxRaidSetBlocks.uHighPart = 0; ++ karg.Information.uMaxPhysicalDrives = ++ ioc->raid_data.pIocPg2->MaxPhysDisks; ++ karg.Information.uMaxExtents = 1; ++ karg.Information.uMaxModules = 0; ++ karg.Information.uMaxTransformationMemory = 0; ++ karg.Information.uChangeCount = ioc->csmi_change_count; ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++csmisas_get_raid_info_out: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_RAID_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_get_raid_info @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * csmisas_do_raid - Format and Issue a RAID volume request message. ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @action: What do be done. ++ * @PhysDiskNum: Logical target id. ++ * @VolumeBus: Target locations bus. ++ * @VolumeId: Volume id ++ * ++ * Returns: < 0 on a fatal error ++ * 0 on success ++ * ++ * Remark: Wait to return until reply processed by the ISR. ++ **/ ++static int ++csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, u8 VolumeId, pMpiRaidActionReply_t reply) ++{ ++ MpiRaidActionRequest_t *pReq; ++ MpiRaidActionReply_t *pReply; ++ MPT_FRAME_HDR *mf; ++ ++ /* Get and Populate a free Frame ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ return -EAGAIN; ++ } ++ pReq = (MpiRaidActionRequest_t *)mf; ++ pReq->Action = action; ++ pReq->Reserved1 = 0; ++ pReq->ChainOffset = 0; ++ pReq->Function = MPI_FUNCTION_RAID_ACTION; ++ pReq->VolumeID = VolumeId; ++ pReq->VolumeBus = VolumeBus; ++ pReq->PhysDiskNum = PhysDiskNum; ++ pReq->MsgFlags = 0; ++ pReq->Reserved2 = 0; ++ pReq->ActionDataWord = 0; /* Reserved for this action */ ++ //pReq->ActionDataSGE = 0; ++ ++ ioc->add_sge((char *)&pReq->ActionDataSGE, ++ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); ++ ++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) ++ return -ENODATA; ++ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) && ++ (reply != NULL)){ ++ pReply = (MpiRaidActionReply_t *)&(ioc->ioctl_cmds.reply); ++ memcpy(reply, pReply, ++ min(ioc->reply_sz, ++ 4*pReply->MsgLength)); ++ } ++ ++ return 0; ++} ++ ++/** ++ * csmisas_raid_inq ++ * @ioc = per host instance ++ * @opcode = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH or ++ * MPI_FUNCTION_SCSI_IO_REQUEST ++ * @id = target id ++ * @bus = target bus ++ * @inq_vpd = inquiry data, returned ++ * @inq_vpd_sz = maximum size of inquiry data ++ * ++ * Return = 0(sucess), non-zero(failure) ++ **/ ++static int ++csmisas_raid_inq(MPT_ADAPTER *ioc, u8 opcode, u8 bus, u8 id, u8 inq_vpd_page, ++ u8 * inq_vpd, u32 inq_vpd_sz) ++{ ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ pSCSIIORequest_t pScsiRequest; ++ u16 req_idx; ++ char *psge; ++ u8 inq_vpd_cdb[6]; ++ u8 *request_data=NULL; ++ dma_addr_t request_data_dma; ++ u32 request_data_sz; ++ int rc = 0; ++ u32 MsgContext; ++ ++ request_data_sz = inq_vpd_sz; ++ ++ /* fill-in cdb */ ++ memset(inq_vpd_cdb, 0, sizeof(inq_vpd_cdb)); ++ inq_vpd_cdb[0] = 0x12; ++ if (inq_vpd_page) { ++ inq_vpd_cdb[1] = 0x01; /* evpd bit */ ++ inq_vpd_cdb[2] = inq_vpd_page; ++ } ++ inq_vpd_cdb[3] = (u8)(request_data_sz >> 8); ++ inq_vpd_cdb[4] = (u8)request_data_sz; ++ ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ goto csmisas_raid_inq_exit; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ pScsiRequest = (pSCSIIORequest_t) mf; ++ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); ++ ++ memset(pScsiRequest,0,sizeof(SCSIIORequest_t)); ++ pScsiRequest->Function = opcode; ++ pScsiRequest->TargetID = id; ++ pScsiRequest->Bus = bus; ++ pScsiRequest->CDBLength = 6; ++ pScsiRequest->DataLength = cpu_to_le32(request_data_sz); ++ pScsiRequest->MsgContext = MsgContext; ++ memcpy(pScsiRequest->CDB,inq_vpd_cdb,pScsiRequest->CDBLength); ++ pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ); ++ pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ); ++ pScsiRequest->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; ++ if (ioc->sg_addr_size == sizeof(u64)) ++ pScsiRequest->MsgFlags |= MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64; ++ ++ /* setup sense ++ */ ++ pScsiRequest->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; ++ pScsiRequest->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + ++ (req_idx * MPT_SENSE_BUFFER_ALLOC)); ++ ++ request_data = pci_alloc_consistent( ++ ioc->pcidev, request_data_sz, &request_data_dma); ++ ++ if (request_data == NULL) { ++ mpt_free_msg_frame(ioc, mf); ++ rc=-1; ++ goto csmisas_raid_inq_exit; ++ } ++ ++ memset(request_data,0,request_data_sz); ++ psge = (char *)&pScsiRequest->SGL; ++ ioc->add_sge(psge, (MPT_SGE_FLAGS_SSIMPLE_READ | 0xFC) , ++ request_data_dma); ++ ++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) { ++ rc=-1; ++ goto csmisas_raid_inq_exit; ++ } ++ ++ /* copy the request_data */ ++ memcpy(inq_vpd, request_data, request_data_sz); ++ ++ csmisas_raid_inq_exit: ++ ++ if (request_data) ++ pci_free_consistent(ioc->pcidev, request_data_sz, ++ request_data, request_data_dma); ++ ++ return rc; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Get RAID Config command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_raid_config(unsigned long arg) ++{ ++ CSMI_SAS_RAID_CONFIG_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_RAID_CONFIG_BUFFER karg,*pKarg=NULL; ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t header; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ u8 volumeID, VolumeBus; ++ u8 physDiskNum, physDiskNumMax; ++ int volumepage0sz = 0; ++ int physdiskpage0sz = 0, ioc_page5_sz = 0; ++ dma_addr_t volume0_dma, physdisk0_dma; ++ dma_addr_t ioc_page5_dma = 0; ++ pRaidVolumePage0_t pVolume0 = NULL; ++ pRaidPhysDiskPage0_t pPhysDisk0 = NULL; ++ pMpiRaidActionReply_t pRaidActionReply = NULL; ++ u32 device_info = 0; ++ pIOCPage5_t pIocPage5 = NULL; ++ int i, idx, csmi_sas_raid_config_buffer_sz; ++ int memory_pages; ++ int copy_buffer_sz = 0; ++ u64 totalMaxLBA, tmpTotalMaxLBA; ++ u64 sas_address; ++ struct sas_device_info *sas_info; ++ ++ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmisas_get_raid_config struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ csmi_sas_raid_config_buffer_sz = karg.IoctlHeader.Length; ++ memory_pages = get_order(csmi_sas_raid_config_buffer_sz); ++ pKarg = (CSMI_SAS_RAID_CONFIG_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!pKarg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc RAID_CONFIG_BUFFER " ++ "csmi_sas_raid_config_buffer_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ csmi_sas_raid_config_buffer_sz, memory_pages); ++ return -ENOMEM; ++ } ++ memset(pKarg, 0, sizeof(*pKarg)); ++ ++ if (copy_from_user(pKarg, uarg, csmi_sas_raid_config_buffer_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmisas_get_raid_config struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ if (pKarg->Configuration.uChangeCount != 0 && ++ pKarg->Configuration.uChangeCount != ioc->csmi_change_count ) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Configuration.uFailureCode = ++ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID; ++ goto cim_get_raid_config_exit; ++ } ++ ++ if (!ioc->raid_data.pIocPg2) { ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ /* ++ * Check to see if the input uRaidSetIndex is ++ * greater than the number of RAID sets ++ */ ++ if (pKarg->Configuration.uRaidSetIndex >= ++ ioc->raid_data.pIocPg2->NumActiveVolumes) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_RAID_SET_OUT_OF_RANGE; ++ goto cim_get_raid_config_exit; ++ } ++ ++ /* ++ * get RAID Volume Page 0 ++ */ ++ volumeID = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeID; ++ VolumeBus = ioc->raid_data.pIocPg2->RaidVolume[pKarg->Configuration.uRaidSetIndex].VolumeBus; ++ ++ header.PageVersion = 0; ++ header.PageLength = 0; ++ header.PageNumber = 0; ++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; ++ cfg.cfghdr.hdr = &header; ++ cfg.physAddr = -1; ++ cfg.pageAddr = (VolumeBus << 8) + volumeID; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ if (mpt_config(ioc, &cfg) != 0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ if (header.PageLength == 0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ volumepage0sz = header.PageLength * 4; ++ pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz, ++ &volume0_dma); ++ if (!pVolume0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.physAddr = volume0_dma; ++ if (mpt_config(ioc, &cfg) != 0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) | ++ ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32; ++ tmpTotalMaxLBA = totalMaxLBA + 1; ++ do_div(tmpTotalMaxLBA, 2048); ++ pKarg->Configuration.bDriveCount = 0; ++ pKarg->Configuration.uCapacity = tmpTotalMaxLBA; ++ pKarg->Configuration.uStripeSize = ++ le32_to_cpu(pVolume0->StripeSize)/2; ++ ++ switch(pVolume0->VolumeType) { ++ case MPI_RAID_VOL_TYPE_IS: ++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_0; ++ break; ++ case MPI_RAID_VOL_TYPE_IME: ++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_10; ++ break; ++ case MPI_RAID_VOL_TYPE_IM: ++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_1; ++ break; ++ default: ++ pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_OTHER; ++ break; ++ } ++ ++ switch (pVolume0->VolumeStatus.State) { ++ case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: ++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OK; ++ break; ++ case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: ++ /* Volume is degraded, check if Resyncing or Inactive */ ++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_DEGRADED; ++ break; ++ case MPI_RAIDVOL0_STATUS_STATE_FAILED: ++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_FAILED; ++ break; ++ } ++ ++ /* check flags */ ++ if (pVolume0->VolumeStatus.Flags & ++ MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE) ++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OFFLINE; ++ else if (pVolume0->VolumeStatus.Flags & ++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) ++ pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_REBUILDING; ++ ++ pKarg->Configuration.bInformation = 0; /* default */ ++ if(pVolume0->VolumeStatus.Flags & ++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ) { ++ ++ uint64_t * ptrUint64; ++ uint64_t totalBlocks64, blocksRemaining64; ++ uint32_t totalBlocks32, blocksRemaining32; ++ ++ /* get percentage complete */ ++ pRaidActionReply = kmalloc( sizeof(MPI_RAID_VOL_INDICATOR) + ++ offsetof(MSG_RAID_ACTION_REPLY,ActionData), ++ GFP_KERNEL); ++ ++ if (!pRaidActionReply){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__,pKarg); ++ goto cim_get_raid_config_exit; ++ } ++ memset(pRaidActionReply, 0, sizeof(*pRaidActionReply)); ++ ++ csmisas_do_raid(ioc, ++ MPI_RAID_ACTION_INDICATOR_STRUCT, ++ 0, VolumeBus, volumeID, pRaidActionReply); ++ ++ ptrUint64 = (uint64_t *)&pRaidActionReply->ActionData; ++ totalBlocks64 = *ptrUint64; ++ ptrUint64++; ++ blocksRemaining64 = *ptrUint64; ++ while(totalBlocks64 > 0xFFFFFFFFUL){ ++ totalBlocks64 = totalBlocks64 >> 1; ++ blocksRemaining64 = blocksRemaining64 >> 1; ++ } ++ totalBlocks32 = (uint32_t)totalBlocks64; ++ blocksRemaining32 = (uint32_t)blocksRemaining64; ++ ++ if(totalBlocks32) ++ pKarg->Configuration.bInformation = ++ (totalBlocks32 - blocksRemaining32) / ++ (totalBlocks32 / 100); ++ ++ kfree(pRaidActionReply); ++ } ++ ++ /* fill-in more information depending on data type */ ++ if (pKarg->Configuration.bDataType == ++ CSMI_SAS_RAID_DATA_ADDITIONAL_DATA) { ++ pKarg->Configuration.Data->bLabel[0] = '\0'; ++ pKarg->Configuration.Data->bRaidSetLun[1] = 0; ++ pKarg->Configuration.Data->bWriteProtection = ++ CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN; ++ pKarg->Configuration.Data->bCacheSetting = ++ CSMI_SAS_RAID_SET_CACHE_UNKNOWN; ++ pKarg->Configuration.Data->bCacheRatio = 0; ++ pKarg->Configuration.Data->usBlockSize = 512; ++ pKarg->Configuration.Data->ulRaidSetExtentOffset.uLowPart = 0; ++ pKarg->Configuration.Data->ulRaidSetExtentOffset.uHighPart = 0; ++ pKarg->Configuration.Data->ulRaidSetBlocks.uLowPart = ++ le32_to_cpu(pVolume0->MaxLBA); ++ pKarg->Configuration.Data->ulRaidSetBlocks.uHighPart = ++ le32_to_cpu(pVolume0->MaxLBAHigh); ++ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS || ++ pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME ) { ++ pKarg->Configuration.Data->uStripeSizeInBlocks = ++ le32_to_cpu(pVolume0->StripeSize); ++ } else { ++ pKarg->Configuration.Data->uStripeSizeInBlocks = 0; ++ } ++ pKarg->Configuration.Data->uSectorsPerTrack = 128; ++ for (i=0; i<16; i++) { ++ // unsupported ++ pKarg->Configuration.Data->bApplicationScratchPad[i] = ++ 0xFF; ++ } ++ pKarg->Configuration.Data->uNumberOfHeads = 16; ++ ++ tmpTotalMaxLBA = totalMaxLBA; ++ do_div(tmpTotalMaxLBA, ++ (pKarg->Configuration.Data->uNumberOfHeads * ++ pKarg->Configuration.Data->uSectorsPerTrack)); ++ pKarg->Configuration.Data->uNumberOfTracks = tmpTotalMaxLBA; ++ } else if ( pKarg->Configuration.bDataType == ++ CSMI_SAS_RAID_DATA_DEVICE_ID ) { ++ /* Send inquiry to get VPD Page 0x83 */ ++ u32 vpd_page_sz; ++ vpd_page_sz = csmi_sas_raid_config_buffer_sz - ++ offsetof(CSMI_SAS_RAID_CONFIG,DeviceId); ++ if (csmisas_raid_inq(ioc, MPI_FUNCTION_SCSI_IO_REQUEST, ++ VolumeBus, volumeID, 0x83, ++ (u8*)&pKarg->Configuration.DeviceId->bDeviceIdentificationVPDPage, ++ vpd_page_sz) != 0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ } else { ++ /* suppress drive information */ ++ if (pKarg->Configuration.bDriveCount == ++ CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ goto cim_get_raid_config_exit; ++ } ++ } ++ ++ /* get hotspare info, used later in this function */ ++ if (pVolume0->VolumeSettings.HotSparePool) { ++ /* Read and save IOC Page 5 ++ */ ++ header.PageVersion = 0; ++ header.PageLength = 0; ++ header.PageNumber = 5; ++ header.PageType = MPI_CONFIG_PAGETYPE_IOC; ++ cfg.cfghdr.hdr = &header; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ if ((mpt_config(ioc, &cfg) == 0) && (header.PageLength)) { ++ ioc_page5_sz = header.PageLength * 4; ++ pIocPage5 = pci_alloc_consistent(ioc->pcidev, ++ ioc_page5_sz, ++ &ioc_page5_dma); ++ memset(pIocPage5,0,ioc_page5_sz); ++ if (ioc_page5_dma) { ++ cfg.physAddr = ioc_page5_dma; ++ cfg.action = ++ MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ mpt_config(ioc, &cfg); ++ } ++ } ++ } ++ ++ /* ++ * get RAID Physical Disk Page 0 ++ */ ++ header.PageVersion = 0; ++ header.PageLength = 0; ++ header.PageNumber = 0; ++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; ++ cfg.cfghdr.hdr = &header; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ if (mpt_config(ioc, &cfg) != 0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ if (header.PageLength == 0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ physdiskpage0sz = header.PageLength * 4; ++ pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz, ++ &physdisk0_dma); ++ if (!pPhysDisk0) { ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ cfg.physAddr = physdisk0_dma; ++ ++ physDiskNumMax = (csmi_sas_raid_config_buffer_sz - ++ offsetof(CSMI_SAS_RAID_CONFIG,Drives)) ++ / sizeof(CSMI_SAS_RAID_DRIVES); ++ ++ tmpTotalMaxLBA = totalMaxLBA; ++ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) { ++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "IS Volume tmpTotalMaxLBA=%llX\n", ++ (unsigned long long)tmpTotalMaxLBA)); ++ } ++ else if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) { ++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks * 2); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "IME Volume tmpTotalMaxLBA=%llX\n", ++ (unsigned long long)tmpTotalMaxLBA)); ++ } else { ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "IM Volume tmpTotalMaxLBA=%llX\n", ++ (unsigned long long)tmpTotalMaxLBA)); ++ } ++ ++ for (i=0; i< min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { ++ ++ physDiskNum = pVolume0->PhysDisk[i].PhysDiskNum; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = physDiskNum; ++ if (mpt_config(ioc, &cfg) != 0){ ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_raid_config_exit; ++ } ++ ++ pKarg->Configuration.bDriveCount++; ++ if (pKarg->Configuration.bDataType != CSMI_SAS_RAID_DATA_DRIVES) ++ continue; ++ ++ /* Search the list for the matching SAS address. */ ++ sas_info = csmisas_get_device_component_by_fw(ioc, pPhysDisk0->PhysDiskBus, ++ pPhysDisk0->PhysDiskID); ++ if (sas_info) { ++ sas_address = reverse_byte_order64(sas_info->sas_address); ++ memcpy(pKarg->Configuration.Drives[i].bSASAddress, ++ &sas_address,sizeof(u64)); ++ if (!device_info) ++ device_info = sas_info->device_info; ++ } ++ ++ memcpy(pKarg->Configuration.Drives[i].bModel, ++ pPhysDisk0->InquiryData.VendorID, ++ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel)); ++ memcpy(pKarg->Configuration.Drives[i].bFirmware, ++ pPhysDisk0->InquiryData.ProductRevLevel, ++ sizeof(pPhysDisk0->InquiryData.ProductRevLevel)); ++ if (csmisas_is_sata(pPhysDisk0)) { ++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber, ++ &pPhysDisk0->ExtDiskIdentifier[4], ++ 4); ++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4], ++ &pPhysDisk0->DiskIdentifier, ++ sizeof(pPhysDisk0->DiskIdentifier)); ++ } else { ++ memcpy(pKarg->Configuration.Drives[i].bSerialNumber, ++ pPhysDisk0->DiskIdentifier, ++ sizeof(pPhysDisk0->DiskIdentifier)); ++ } ++ ++ pKarg->Configuration.Drives[i].bDriveUsage = ++ (pPhysDisk0->PhysDiskStatus.Flags & ++ MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME) ? ++ CSMI_SAS_DRIVE_CONFIG_NOT_USED : ++ CSMI_SAS_DRIVE_CONFIG_MEMBER; ++ ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_OK; ++ if (pPhysDisk0->PhysDiskStatus.State == ++ MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED) { ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_OFFLINE; ++ } else if(pPhysDisk0->PhysDiskStatus.State) { ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_FAILED; ++ if(pKarg->Configuration.bStatus == ++ CSMI_SAS_RAID_SET_STATUS_DEGRADED) ++ pKarg->Configuration.bInformation = i; ++ } else if((pVolume0->VolumeStatus.Flags & ++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) && ++ (pPhysDisk0->PhysDiskStatus.Flags & ++ MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC)) ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_REBUILDING; ++ else if(pPhysDisk0->ErrorData.SmartCount || ++ (pPhysDisk0->PhysDiskStatus.Flags & ++ MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC)) ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_DEGRADED; ++ ++ memset(pKarg->Configuration.Drives[i].bSASLun, ++ 0, sizeof(pKarg->Configuration.Drives[i].bSASLun)); ++ if (csmisas_is_sata(pPhysDisk0)) { ++ pKarg->Configuration.Drives[i].bDriveType = ++ CSMI_SAS_DRIVE_TYPE_SATA; ++ } else { /* drive in a volume can only be SAS/SATA */ ++ pKarg->Configuration.Drives[i].bDriveType = ++ CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS; ++ if (mpt_raid_phys_disk_get_num_paths(ioc, ++ pVolume0->PhysDisk[i].PhysDiskNum) > 1) ++ pKarg->Configuration.Drives[i].bDriveType = ++ CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS; ++ } ++ ++ pKarg->Configuration.Drives[i].usBlockSize = 512; ++ pKarg->Configuration.Drives[i].uDriveIndex = ++ pPhysDisk0->PhysDiskNum; ++ pKarg->Configuration.Drives[i].ulTotalUserBlocks.uLowPart = ++ (u32)tmpTotalMaxLBA; ++ pKarg->Configuration.Drives[i].ulTotalUserBlocks.uHighPart = ++ (u32)(tmpTotalMaxLBA >> 32); ++ } ++ ++ /* adding hot spare info at the end */ ++ if ((pVolume0->VolumeSettings.HotSparePool) && (pIocPage5) && ++ (pVolume0->VolumeType != MPI_RAID_VOL_TYPE_IS)) { ++ for (idx = 0, i = pVolume0->NumPhysDisks ; ++ idx < pIocPage5->NumHotSpares ; idx++) { ++ if (i >= physDiskNumMax) ++ break; ++ if ((pVolume0->VolumeSettings.HotSparePool & ++ pIocPage5->HotSpare[idx].HotSparePool) == 0) ++ continue; ++ if(pIocPage5->HotSpare[idx].Flags != ++ MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE) ++ continue; ++ physDiskNum = pIocPage5->HotSpare[idx].PhysDiskNum; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = physDiskNum; ++ if (mpt_config(ioc, &cfg) != 0) ++ continue; ++ ++ /* don't mix SSP hot spare ++ * in SATA volume ++ */ ++ if (!csmisas_is_sata(pPhysDisk0) && ++ (device_info & ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) ++ continue; ++ ++ /* don't mix SATA hot spare ++ * in SSP volume ++ */ ++ if (csmisas_is_sata(pPhysDisk0) && ++ (device_info & ++ MPI_SAS_DEVICE_INFO_SSP_TARGET)) ++ continue; ++ ++ /* capacity check for IM volumes*/ ++ if ((pVolume0->VolumeType == ++ MPI_RAID_VOL_TYPE_IM) && ++ (totalMaxLBA + ++ (64*2*1024) /* metadata = 64MB*/ > ++ le32_to_cpu(pPhysDisk0->MaxLBA))) ++ continue; ++ ++ tmpTotalMaxLBA = totalMaxLBA; ++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks); ++ /* capacity check for IME volumes*/ ++ if ((pVolume0->VolumeType == ++ MPI_RAID_VOL_TYPE_IME) && ++ (((totalMaxLBA + ++ pVolume0->NumPhysDisks) * 2) + ++ (64*2*1024 ) /*metadata = 64MB*/ > ++ le32_to_cpu(pPhysDisk0->MaxLBA))) ++ continue; ++ ++ pKarg->Configuration.bDriveCount++; ++ if (pKarg->Configuration.bDataType != ++ CSMI_SAS_RAID_DATA_DRIVES) { ++ i++; ++ continue; ++ } ++ ++ /* Search the list for the matching SAS address. */ ++ sas_info = csmisas_get_device_component_by_fw(ioc, ++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); ++ if (sas_info) { ++ sas_address = reverse_byte_order64(sas_info->sas_address); ++ memcpy(pKarg->Configuration.Drives[i].bSASAddress, ++ &sas_address,sizeof(u64)); ++ } ++ ++ memcpy(pKarg->Configuration.Drives[i].bModel, ++ pPhysDisk0->InquiryData.VendorID, ++ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel)); ++ memcpy(pKarg->Configuration.Drives[i].bFirmware, ++ pPhysDisk0->InquiryData.ProductRevLevel, ++ sizeof(pPhysDisk0->InquiryData.ProductRevLevel)); ++ if (csmisas_is_sata(pPhysDisk0)) { ++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber, ++ &pPhysDisk0->ExtDiskIdentifier[4], ++ 4); ++ memcpy(&pKarg->Configuration.Drives[i].bSerialNumber[4], ++ &pPhysDisk0->DiskIdentifier, ++ sizeof(pPhysDisk0->DiskIdentifier)); ++ } else { ++ memcpy(pKarg->Configuration.Drives[i].bSerialNumber, ++ pPhysDisk0->DiskIdentifier, ++ sizeof(pPhysDisk0->DiskIdentifier)); ++ } ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_OK; ++ if(pPhysDisk0->PhysDiskStatus.State) ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_FAILED; ++ else if(pPhysDisk0->ErrorData.SmartCount) ++ pKarg->Configuration.Drives[i].bDriveStatus = ++ CSMI_SAS_DRIVE_STATUS_DEGRADED; ++ pKarg->Configuration.Drives[i].bDriveUsage = ++ CSMI_SAS_DRIVE_CONFIG_SPARE; ++ pKarg->Configuration.Drives[i].usBlockSize = 512; ++ pKarg->Configuration.Drives[i].uDriveIndex = ++ pPhysDisk0->PhysDiskNum; ++ if (csmisas_is_sata(pPhysDisk0)) { ++ pKarg->Configuration.Drives[i].bDriveType = ++ CSMI_SAS_DRIVE_TYPE_SATA; ++ } else { /* drive in a volume can only be SAS/SATA */ ++ pKarg->Configuration.Drives[i].bDriveType = ++ CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS; ++ if (mpt_raid_phys_disk_get_num_paths(ioc, ++ pVolume0->PhysDisk[i].PhysDiskNum) > 1) ++ pKarg->Configuration.Drives[i].bDriveType = ++ CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS; ++ } ++ i++; ++ } ++ } ++ ++ // Only return data on the first 240 drives ++ if( pKarg->Configuration.bDriveCount > 0xF0 ) ++ pKarg->Configuration.bDriveCount = ++ CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG; ++ ++ pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ cim_get_raid_config_exit: ++ ++ if (pVolume0 != NULL) ++ pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0, ++ volume0_dma); ++ ++ if(pPhysDisk0 != NULL) ++ pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0, ++ physdisk0_dma); ++ ++ if(pIocPage5 != NULL) ++ pci_free_consistent(ioc->pcidev, ioc_page5_sz, pIocPage5, ++ ioc_page5_dma); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ ++ /* find the buffer size to copy depending on how much is filled-in */ ++ switch (pKarg->Configuration.bDataType) { ++ case CSMI_SAS_RAID_DATA_ADDITIONAL_DATA: ++ copy_buffer_sz = sizeof(IOCTL_HEADER) + ++ offsetof(CSMI_SAS_RAID_CONFIG,Data) + ++ sizeof(CSMI_SAS_RAID_SET_ADDITIONAL_DATA); ++ break; ++ case CSMI_SAS_RAID_DATA_DRIVES: ++ if (pKarg->Configuration.bDriveCount == ++ CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED) ++ copy_buffer_sz = sizeof(IOCTL_HEADER) + ++ offsetof(CSMI_SAS_RAID_CONFIG,Drives); ++ else ++ copy_buffer_sz = sizeof(IOCTL_HEADER) + ++ offsetof(CSMI_SAS_RAID_CONFIG,Drives) + ++ (pKarg->Configuration.bDriveCount * ++ sizeof(CSMI_SAS_RAID_DRIVES)); ++ break; ++ case CSMI_SAS_RAID_DATA_DEVICE_ID: ++ copy_buffer_sz = csmi_sas_raid_config_buffer_sz; ++ break; ++ } ++ ++ if (copy_to_user(uarg, pKarg, copy_buffer_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_get_raid_config @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Get RAID Features command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_raid_features(unsigned long arg) ++{ ++ CSMI_SAS_RAID_FEATURES_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_RAID_FEATURES_BUFFER karg, *pKarg=NULL; ++ int csmi_sas_raid_features_buffer_sz, iocnum; ++ int memory_pages; ++ MPT_ADAPTER *ioc = NULL; ++ ++ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_get_raid_features struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ csmi_sas_raid_features_buffer_sz = karg.IoctlHeader.Length; ++ memory_pages = get_order(csmi_sas_raid_features_buffer_sz); ++ pKarg = (CSMI_SAS_RAID_FEATURES_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!pKarg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc RAID_FEATURES_BUFFER " ++ "csmi_sas_raid_features_buffer_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ csmi_sas_raid_features_buffer_sz, memory_pages); ++ return -ENOMEM; ++ } ++ memset(pKarg, 0, sizeof(*pKarg)); ++ ++ if (copy_from_user(pKarg, uarg, csmi_sas_raid_features_buffer_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_get_raid_features struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ if (pKarg->Information.uChangeCount != 0 && ++ pKarg->Information.uChangeCount != ioc->csmi_change_count ) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Information.uFailureCode = ++ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID; ++ goto cim_get_raid_features_exit; ++ } ++ ++ pKarg->Information.uFeatures = CSMI_SAS_RAID_FEATURE_REBUILD | ++ CSMI_SAS_RAID_FEATURE_SURFACE_SCAN | ++ CSMI_SAS_RAID_FEATURE_SPARES_SHARED; ++ pKarg->Information.bDefaultTransformPriority = ++ CSMI_SAS_PRIORITY_UNKNOWN; ++ pKarg->Information.bTransformPriority = CSMI_SAS_PRIORITY_UNKNOWN; ++ pKarg->Information.bDefaultRebuildPriority = CSMI_SAS_PRIORITY_UNKNOWN; ++ pKarg->Information.bRebuildPriority = ++ pKarg->Information.bDefaultRebuildPriority; ++ pKarg->Information.bDefaultSurfaceScanPriority = ++ CSMI_SAS_PRIORITY_UNKNOWN; ++ pKarg->Information.bSurfaceScanPriority = CSMI_SAS_PRIORITY_UNKNOWN; ++ pKarg->Information.uRaidSetTransformationRules = 0; ++ ++ /* IS */ ++ pKarg->Information.RaidType[0].bRaidType = CSMI_SAS_RAID_TYPE_0; ++ pKarg->Information.RaidType[0].uSupportedStripeSizeMap = 0x80; ++ ++ /* IM */ ++ pKarg->Information.RaidType[1].bRaidType = CSMI_SAS_RAID_TYPE_1; ++ pKarg->Information.RaidType[1].uSupportedStripeSizeMap = 0; ++ ++ /* IME */ ++ pKarg->Information.RaidType[2].bRaidType = CSMI_SAS_RAID_TYPE_1E; ++ pKarg->Information.RaidType[2].uSupportedStripeSizeMap = 0x80; ++ ++ pKarg->Information.RaidType[3].bRaidType = CSMI_SAS_RAID_TYPE_END; ++ pKarg->Information.bCacheRatiosSupported[0] = ++ CSMI_SAS_RAID_CACHE_RATIO_END; ++ ++ cim_get_raid_features_exit: ++ ++ /* ++ * Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, pKarg, ++ sizeof(CSMI_SAS_RAID_FEATURES_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_get_raid_features @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Set RAID Control command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_set_raid_control(unsigned long arg) ++{ ++ CSMI_SAS_RAID_CONTROL_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_RAID_CONTROL_BUFFER karg, *pKarg=NULL; ++ int csmi_sas_raid_control_buffer_sz, iocnum; ++ int memory_pages; ++ MPT_ADAPTER *ioc = NULL; ++ ++ if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_set_raid_control struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ csmi_sas_raid_control_buffer_sz = karg.IoctlHeader.Length; ++ memory_pages = get_order(csmi_sas_raid_control_buffer_sz); ++ pKarg = (CSMI_SAS_RAID_CONTROL_BUFFER *)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!pKarg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc RAID_CONTROL_BUFFER " ++ "csmi_sas_raid_control_buffer_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ csmi_sas_raid_control_buffer_sz, memory_pages); ++ return -ENOMEM; ++ } ++ memset(pKarg, 0, sizeof(*pKarg)); ++ ++ if (copy_from_user(pKarg, uarg, csmi_sas_raid_control_buffer_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_set_raid_control struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ if (pKarg->Information.uChangeCount != 0 && ++ pKarg->Information.uChangeCount != ioc->csmi_change_count ) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Information.uFailureCode = ++ CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID; ++ goto cim_set_raid_control_exit; ++ } ++ ++ if (pKarg->Information.bTransformPriority != ++ CSMI_SAS_PRIORITY_UNCHANGED) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Information.uFailureCode = ++ CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID; ++ goto cim_set_raid_control_exit; ++ } ++ ++ if (pKarg->Information.bRebuildPriority != ++ CSMI_SAS_PRIORITY_AUTO && ++ pKarg->Information.bRebuildPriority != ++ CSMI_SAS_PRIORITY_UNCHANGED) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Information.uFailureCode = ++ CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID; ++ goto cim_set_raid_control_exit; ++ } ++ ++ if (pKarg->Information.bCacheRatioFlag == ++ CSMI_SAS_RAID_CACHE_RATIO_DISABLE) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Information.uFailureCode = ++ CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID; ++ goto cim_set_raid_control_exit; ++ } ++ ++ if( !strcmp(pKarg->Information.bClearConfiguration, ++ CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE) ) { ++ pKarg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ pKarg->Information.uFailureCode = ++ CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID; ++ goto cim_set_raid_control_exit; ++ } ++ ++ pKarg->Information.bFailureDescription[0] = '\0'; ++ ++ cim_set_raid_control_exit: ++ ++ /* ++ * Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, pKarg, ++ sizeof(CSMI_SAS_RAID_CONTROL_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_set_raid_control @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ free_pages((unsigned long)pKarg, memory_pages); ++ return 0; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Get Raid Element. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_raid_element(unsigned long arg) ++{ ++ CSMI_SAS_RAID_ELEMENT_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_RAID_ELEMENT_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmisas_get_raid_element struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++/* TODO - implement IOCTL here */ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); ++ ++// csmisas_get_raid_element_exit: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmisas_get_raid_element @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++ ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Set Raid Operation ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_set_raid_operation(unsigned long arg) ++{ ++ CSMI_SAS_RAID_SET_OPERATION_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_RAID_SET_OPERATION_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_set_raid_operation struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++/* TODO - implement IOCTL here */ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); ++ ++// cim_set_raid_operation: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_set_raid_operation @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++ ++} ++ ++ ++/** ++ * Prototype Routine for the CSMI SAS Task Managment Config command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_task_managment(unsigned long arg) ++{ ++ CSMI_SAS_SSP_TASK_IU_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_SSP_TASK_IU_BUFFER karg; ++ pSCSITaskMgmt_t pScsiTm; ++ pSCSITaskMgmtReply_t pScsiTmReply; ++ MPT_ADAPTER *ioc = NULL; ++ MPT_SCSI_HOST *hd; ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ int iocnum; ++ u8 taskType; ++ u8 channel; ++ u8 id; ++ u8 queueTag; ++ u32 TaskMsgContext = 0; ++ int i; ++ u8 found_qtag; ++ struct sas_device_info *sas_info; ++ u16 ioc_status; ++ u32 MsgContext; ++ ++ if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_task_managment struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ ++ sas_info = csmisas_get_device_component_by_os(ioc, ++ karg.Parameters.bPathId, karg.Parameters.bTargetId); ++ if (!sas_info || sas_info->is_cached || sas_info->is_logical_volume) ++ goto cim_get_task_managment_exit; ++ ++ channel = sas_info->fw.channel; ++ id = sas_info->fw.id; ++ queueTag = (u8)karg.Parameters.uQueueTag & 0xFF; ++ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; ++ ++ /* try to catch an error ++ */ ++ if ((karg.Parameters.uFlags & CSMI_SAS_TASK_IU) && ++ (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE)) ++ goto cim_get_task_managment_exit; ++ ++ if (karg.Parameters.uFlags & CSMI_SAS_TASK_IU) { ++ switch (karg.Parameters.bTaskManagementFunction) { ++ ++ case CSMI_SAS_SSP_ABORT_TASK: ++ taskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; ++ break; ++ case CSMI_SAS_SSP_ABORT_TASK_SET: ++ taskType = MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET; ++ break; ++ case CSMI_SAS_SSP_CLEAR_TASK_SET: ++ taskType = MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET; ++ break; ++ case CSMI_SAS_SSP_LOGICAL_UNIT_RESET: ++ taskType = MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET; ++ break; ++ case CSMI_SAS_SSP_CLEAR_ACA: ++ case CSMI_SAS_SSP_QUERY_TASK: ++ default: ++ goto cim_get_task_managment_exit; ++ } ++ } else if (karg.Parameters.uFlags & CSMI_SAS_HARD_RESET_SEQUENCE) ++ taskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; ++ else ++ goto cim_get_task_managment_exit; ++ ++ switch (karg.Parameters.uInformation) { ++ case CSMI_SAS_SSP_TEST: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request for test purposes\n")); ++ break; ++ case CSMI_SAS_SSP_EXCEEDED: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request due to timeout\n")); ++ break; ++ case CSMI_SAS_SSP_DEMAND: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request demanded by app\n")); ++ break; ++ case CSMI_SAS_SSP_TRIGGER: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request sent to trigger event\n")); ++ break; ++ } ++ ++ switch (taskType) { ++ ++ case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: ++ /* ++ * look up qtag in the ScsiLookup[] table ++ */ ++ for (i = 0, found_qtag = 0; i < hd->ioc->req_depth; i++) { ++ if ((ioc->ScsiLookup[i]) && ++ (ioc->ScsiLookup[i]->tag == queueTag)) { ++ mf = MPT_INDEX_2_MFPTR(hd->ioc, i); ++ TaskMsgContext = ++ mf->u.frame.hwhdr.msgctxu.MsgContext; ++ found_qtag=1; ++ break; ++ } ++ } ++ ++ if(!found_qtag) ++ goto cim_get_task_managment_exit; ++ ++ case MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: ++ case MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: ++ case MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET: ++ /* for now, this should work ++ */ ++ case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: ++ ++ /* Single threading .... ++ */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) ++ mutex_lock(&ioc->taskmgmt_cmds.mutex); ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ karg.IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_FAILED; ++ goto cim_get_task_managment_exit; ++ } ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) ++ if (mptctl_set_tm_flags(hd) != 0) { ++ karg.IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_FAILED; ++ goto cim_get_task_managment_exit; ++ } ++#endif ++ /* Send request ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) ++ mptctl_free_tm_flags(ioc); ++#endif ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_task_managment_exit; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ pScsiTm = (pSCSITaskMgmt_t ) mf; ++ ++ memset(pScsiTm,0,sizeof(SCSITaskMgmt_t)); ++ pScsiTm->TaskType = taskType; ++ pScsiTm->Bus = channel; ++ pScsiTm->TargetID = id; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) ++ int_to_scsilun(karg.Parameters.bLun, ++ (struct scsi_lun *)pScsiTm->LUN); ++#else ++ pScsiTm->LUN[1] = karg.Parameters.bLun; ++#endif ++ pScsiTm->MsgContext = MsgContext; ++ pScsiTm->TaskMsgContext = TaskMsgContext; ++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; ++ ++ if (csmisas_send_handshake_wait(ioc, mf, ++ karg.IoctlHeader.Timeout) != 0) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++#endif ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_get_task_managment_exit; ++ } ++ ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { ++ ++ pScsiTmReply = ++ (pSCSITaskMgmtReply_t ) ioc->ioctl_cmds.reply; ++ ++ ioc_status = le16_to_cpu(pScsiTmReply->IOCStatus) ++ & MPI_IOCSTATUS_MASK; ++ ++ memset(&karg.Status,0, ++ sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); ++ ++ if(ioc_status == MPI_IOCSTATUS_SUCCESS) { ++ karg.IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_SUCCESS; ++ karg.Status.bSSPStatus = ++ CSMI_SAS_SSP_STATUS_COMPLETED; ++ }else if(ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) { ++ karg.IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_SUCCESS; ++ karg.Status.bSSPStatus = ++ CSMI_SAS_SSP_STATUS_RETRY; ++ }else { ++ karg.IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_FAILED; ++ karg.Status.bSSPStatus = ++ CSMI_SAS_SSP_STATUS_FATAL_ERROR; ++ } ++ } else ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ ++ break; ++ ++ default: ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ break; ++ } ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++#endif ++ ++ cim_get_task_managment_exit: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_task_managment @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * map_sas_status_to_csmi - Conversion for Connection Status ++ * @mpi_sas_status: Sas status returned by the firmware ++ * ++ * Returns converted connection status ++ * ++ **/ ++static u8 ++map_sas_status_to_csmi(u8 mpi_sas_status) ++{ ++ u8 csmi_connect_status; ++ ++ switch (mpi_sas_status) { ++ ++ case MPI_SASSTATUS_SUCCESS: ++ csmi_connect_status = CSMI_SAS_OPEN_ACCEPT; ++ break; ++ ++ case MPI_SASSTATUS_UTC_BAD_DEST: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_BAD_DESTINATION; ++ break; ++ ++ case MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED; ++ break; ++ ++ case MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED: ++ csmi_connect_status = ++ CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED; ++ break; ++ ++ case MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY; ++ break; ++ ++ case MPI_SASSTATUS_UTC_WRONG_DESTINATION: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION; ++ break; ++ ++ case MPI_SASSTATUS_SDSF_NAK_RECEIVED: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RETRY; ++ break; ++ ++ case MPI_SASSTATUS_SDSF_CONNECTION_FAILED: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED; ++ break; ++ ++ case MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_NO_DESTINATION; ++ break; ++ ++ case MPI_SASSTATUS_UNKNOWN_ERROR: ++ case MPI_SASSTATUS_INVALID_FRAME: ++ case MPI_SASSTATUS_UTC_BREAK_RECEIVED: ++ case MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST: ++ case MPI_SASSTATUS_SHORT_INFORMATION_UNIT: ++ case MPI_SASSTATUS_LONG_INFORMATION_UNIT: ++ case MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA: ++ case MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR: ++ case MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED: ++ case MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH: ++ case MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA: ++ case MPI_SASSTATUS_DATA_OFFSET_ERROR: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP; ++ break; ++ ++ default: ++ csmi_connect_status = CSMI_SAS_OPEN_REJECT_RESERVE_STOP; ++ break; ++ } ++ ++ return csmi_connect_status; ++} ++ ++/** ++ * csmisas_phy_reset ++ * Issues a phy link reset or phy hard reset ++ * ++ * @ioc - Pointer to MPT_ADAPTER structure ++ * @PhyNum - phy number ++ * @opcode - {MPI_SAS_OP_PHY_LINK_RESET,MPI_SAS_OP_PHY_HARD_RESET} ++ * ++ * Returns: 0 for success, non-zero error ++ **/ ++static int ++csmisas_phy_reset(MPT_ADAPTER *ioc, u8 PhyNum, u8 opcode) ++{ ++ SasIoUnitControlRequest_t *sasIoUnitCntrReq; ++ SasIoUnitControlReply_t *sasIoUnitCntrReply; ++ MPT_FRAME_HDR *mf = NULL; ++ MPIHeader_t *mpi_hdr; ++ u16 ioc_status; ++ u32 MsgContext; ++ ++ if ((opcode != MPI_SAS_OP_PHY_LINK_RESET) && ++ (opcode != MPI_SAS_OP_PHY_HARD_RESET)) ++ return -1; ++ ++ /* Get a MF for this command. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); ++ return -1; ++ } ++ ++ mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; ++ sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; ++ memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); ++ sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; ++ sasIoUnitCntrReq->MsgContext = MsgContext; ++ sasIoUnitCntrReq->Operation = opcode; ++ sasIoUnitCntrReq->PhyNum = PhyNum; ++ ++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) ++ return -1; ++ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) ++ return -1; ++ ++ /* process the completed Reply Message Frame */ ++ sasIoUnitCntrReply = (SasIoUnitControlReply_t *)ioc->ioctl_cmds.reply; ++ ioc_status = le16_to_cpu(sasIoUnitCntrReply->IOCStatus) ++ & MPI_IOCSTATUS_MASK; ++ if (ioc_status != MPI_IOCSTATUS_SUCCESS) { ++ printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ __FUNCTION__, ++ sasIoUnitCntrReply->IOCStatus, ++ sasIoUnitCntrReply->IOCLogInfo); ++ return -1; ++ } ++ return 0; ++} ++ ++/** Prototype Routine for the CSMI SAS Phy Control command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_phy_control(unsigned long arg) ++{ ++ CSMI_SAS_PHY_CONTROL_BUFFER __user *uarg = (void __user *) arg; ++ IOCTL_HEADER ioctl_header; ++ PCSMI_SAS_PHY_CONTROL_BUFFER karg; ++ SasIOUnitPage0_t *sasIoUnitPg0=NULL; ++ dma_addr_t sasIoUnitPg0_dma; ++ int sasIoUnitPg0_data_sz=0; ++ SasIOUnitPage1_t *sasIoUnitPg1=NULL; ++ dma_addr_t sasIoUnitPg1_dma; ++ int sasIoUnitPg1_data_sz=0; ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum; ++ int csmi_sas_phy_control_buffer_sz; ++ int memory_pages; ++ ++ if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in IOCTL_HEADER" ++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ csmi_sas_phy_control_buffer_sz = ioctl_header.Length; ++ memory_pages = get_order(csmi_sas_phy_control_buffer_sz); ++ karg = (PCSMI_SAS_PHY_CONTROL_BUFFER)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!karg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc SAS_PHY_CONTROL_BUFFER " ++ "csmi_sas_phy_control_buffer_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ csmi_sas_phy_control_buffer_sz, memory_pages); ++ return -ENOMEM; ++ } ++ memset(karg, 0, sizeof(*karg)); ++ ++ if (copy_from_user(karg, uarg, csmi_sas_phy_control_buffer_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_phy_control_buffer " ++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(ioctl_header.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ if (karg->bPhyIdentifier >= ioc->num_ports) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ /* ++ * Retreive SAS IOUNIT PAGE 0 ++ */ ++ ++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: READ MPI_SASIOUNITPAGE0: HEADER\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ sasIoUnitPg0_data_sz = hdr.ExtPageLength * 4; ++ sasIoUnitPg0 = (SasIOUnitPage0_t *) pci_alloc_consistent(ioc->pcidev, ++ sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma); ++ ++ if (!sasIoUnitPg0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ memset((u8 *)sasIoUnitPg0, 0, sasIoUnitPg0_data_sz); ++ cfg.physAddr = sasIoUnitPg0_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: READ MPI_SASIOUNITPAGE0: CURRENT\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ /* ++ * Retreive SAS IOUNIT PAGE 1 ++ */ ++ ++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 1; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: READ MPI_SASIOUNITPAGE1: HEADER\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ sasIoUnitPg1_data_sz = hdr.ExtPageLength * 4; ++ sasIoUnitPg1 = (SasIOUnitPage1_t *) pci_alloc_consistent(ioc->pcidev, ++ sasIoUnitPg1_data_sz, &sasIoUnitPg1_dma); ++ ++ if (!sasIoUnitPg1) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ memset((u8 *)sasIoUnitPg1, 0, sasIoUnitPg1_data_sz); ++ cfg.physAddr = sasIoUnitPg1_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: READ MPI_SASIOUNITPAGE1: CURRENT\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ ++ switch (karg->uFunction) { ++ ++ case CSMI_SAS_PC_LINK_RESET: ++ case CSMI_SAS_PC_HARD_RESET: ++ { ++ u8 opcode = (karg->uFunction==CSMI_SAS_PC_LINK_RESET) ? ++ MPI_SAS_OP_PHY_LINK_RESET : MPI_SAS_OP_PHY_HARD_RESET; ++ ++ if((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) && ++ (karg->usLengthOfControl >= sizeof(CSMI_SAS_PHY_CONTROL)) && ++ (karg->bNumberOfControls > 0)){ ++ if(karg->Control[0].bRate == ++ CSMI_SAS_LINK_RATE_1_5_GBPS) { ++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate = ++ MPI_SAS_IOUNIT1_MAX_RATE_1_5 | ++ MPI_SAS_IOUNIT1_MIN_RATE_1_5; ++ } ++ else if(karg->Control[0].bRate == ++ CSMI_SAS_LINK_RATE_3_0_GBPS) { ++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate = ++ MPI_SAS_IOUNIT1_MAX_RATE_3_0 | ++ MPI_SAS_IOUNIT1_MIN_RATE_3_0; ++ } ++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags &= ++ ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE; ++ cfg.dir = 1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n")); ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n")); ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ } ++ if (csmisas_phy_reset(ioc, ++ karg->bPhyIdentifier, opcode) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: csmisas_phy_reset\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ break; ++ ++ } ++ case CSMI_SAS_PC_PHY_DISABLE: ++ if(karg->usLengthOfControl || karg->bNumberOfControls) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ break; ++ } ++ sasIoUnitPg1->PhyData[karg->bPhyIdentifier].PhyFlags |= ++ MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE; ++ cfg.dir = 1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 NVRAM\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; ++ if (mpt_config(ioc, &cfg) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: WRITE MPI_SASIOUNITPAGE1 CURRENT\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ if (csmisas_phy_reset(ioc, ++ karg->bPhyIdentifier, MPI_SAS_OP_PHY_HARD_RESET) != 0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: csmisas_phy_reset\n")); ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_phy_control_exit; ++ } ++ break; ++ ++ case CSMI_SAS_PC_GET_PHY_SETTINGS: ++ if(karg->usLengthOfControl || karg->bNumberOfControls) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ break; ++ } ++ if(csmi_sas_phy_control_buffer_sz < ++ offsetof(CSMI_SAS_PHY_CONTROL_BUFFER,Control) + ++ (4* sizeof(CSMI_SAS_PHY_CONTROL))) { ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_INVALID_PARAMETER; ++ break; ++ } ++ karg->usLengthOfControl = sizeof(CSMI_SAS_PHY_CONTROL); ++ karg->bNumberOfControls = 4; ++ karg->Control[0].bType = CSMI_SAS_SAS; ++ karg->Control[0].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS; ++ karg->Control[1].bType = CSMI_SAS_SAS; ++ karg->Control[1].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS; ++ karg->Control[2].bType = CSMI_SAS_SATA; ++ karg->Control[2].bRate = CSMI_SAS_LINK_RATE_1_5_GBPS; ++ karg->Control[3].bType = CSMI_SAS_SATA; ++ karg->Control[3].bRate = CSMI_SAS_LINK_RATE_3_0_GBPS; ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ break; ++ default: ++ break; ++ } ++ ++ cim_sas_phy_control_exit: ++ ++ if (sasIoUnitPg0) ++ pci_free_consistent(ioc->pcidev, sasIoUnitPg0_data_sz, ++ (u8 *) sasIoUnitPg0, sasIoUnitPg0_dma); ++ ++ if (sasIoUnitPg1) ++ pci_free_consistent(ioc->pcidev, sasIoUnitPg1_data_sz, ++ (u8 *) sasIoUnitPg1, sasIoUnitPg1_dma); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, karg,csmi_sas_phy_control_buffer_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_phy_control_buffer @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ free_pages((unsigned long)karg, memory_pages); ++ return 0; ++} ++ ++/** ++ * csmisas_get_manuf_pg_7 - Fetch Manufacturing config Page7. ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @mfgpage7_buffer: pointer to ManufacturingPage7_t that returns config ++ * page data ++ * @mfg_size - max size of buffer ++ * ++ * Return: 0 for success ++ * -ENOMEM if no memory available ++ * -EPERM if not allowed due to ISR context ++ * -EAGAIN if no msg frames currently available ++ * -EFAULT for non-successful reply or no reply (timeout) ++ **/ ++static int ++csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, int mfg_size) ++{ ++ ConfigPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ ManufacturingPage7_t *mfgPage7 = NULL; ++ dma_addr_t mfgPage7_dma; ++ int data_sz = 0; ++ int rc; ++ ++ /* Get Manufacturing Page 7 header */ ++ hdr.PageVersion = MPI_MANUFACTURING0_PAGEVERSION; ++ hdr.PageLength = 0; ++ hdr.PageNumber = 7; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; ++ cfg.cfghdr.hdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.pageAddr = 0; ++ cfg.timeout = 0; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) ++ goto csmisas_get_manuf_pg_7_exit; ++ ++ if (hdr.PageLength == 0) { ++ rc = -EFAULT; ++ goto csmisas_get_manuf_pg_7_exit; ++ } ++ ++ data_sz = hdr.PageLength * 4; ++ mfgPage7 = pci_alloc_consistent(ioc->pcidev, data_sz, &mfgPage7_dma); ++ if (!mfgPage7) { ++ rc = -ENOMEM; ++ goto csmisas_get_manuf_pg_7_exit; ++ } ++ ++ memset((u8 *)mfgPage7, 0, data_sz); ++ cfg.physAddr = mfgPage7_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) ++ goto csmisas_get_manuf_pg_7_exit; ++ ++ /* copy buffer back to user */ ++ memcpy(mfgpage7_buffer, mfgPage7, min(data_sz, mfg_size)); ++ ++ csmisas_get_manuf_pg_7_exit: ++ ++ if (mfgPage7) ++ pci_free_consistent(ioc->pcidev, data_sz, (u8 *)mfgPage7, ++ mfgPage7_dma); ++ ++ return rc; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Get Connector info command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ **/ ++static int ++csmisas_get_connector_info(unsigned long arg) ++{ ++ CSMI_SAS_CONNECTOR_INFO_BUFFER __user *uarg = (void __user *) arg; ++ CSMI_SAS_CONNECTOR_INFO_BUFFER karg; ++ MPT_ADAPTER *ioc = NULL; ++ ManufacturingPage7_t *mfgPg7 = NULL; ++ int mfgPg7_sz; ++ int iocnum; ++ int i; ++ ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_connector_info_buffer" ++ " struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ ++ /* `32` is the sizeof MPI_MANPAGE7_CONNECTOR_INFO */ ++ for (i = 0; i < 32; i++) { ++ karg.Reference[i].uPinout = CSMI_SAS_CON_UNKNOWN; ++ strcpy(karg.Reference[i].bConnector,""); ++ karg.Reference[i].bLocation = CSMI_SAS_CON_UNKNOWN; ++ } ++ ++ mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7,ConnectorInfo) + ++ (ioc->num_ports * sizeof(MPI_MANPAGE7_CONNECTOR_INFO)); ++ mfgPg7 = kmalloc(mfgPg7_sz, GFP_KERNEL); ++ if (!mfgPg7){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, mfgPg7); ++ return -EFAULT; ++ } ++ memset(mfgPg7, 0, mfgPg7_sz); ++ ++ if (!csmisas_get_manuf_pg_7(ioc, mfgPg7, mfgPg7_sz)) { ++ for (i = 0; i < ioc->num_ports; i++) { ++ karg.Reference[i].uPinout = ++ le32_to_cpu(mfgPg7->ConnectorInfo[i].Pinout); ++ /*endian conversion , this is u8 * 16 ?? */ ++ strncpy(karg.Reference[i].bConnector, ++ mfgPg7->ConnectorInfo[i].Connector, 16); ++ karg.Reference[i].bLocation = ++ mfgPg7->ConnectorInfo[i].Location; ++ } ++ } ++ ++ kfree(mfgPg7); ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, &karg, ++ sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_connector_info_buffer @" ++ "%p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return 0; ++} ++ ++/** ++ * csmisas_fill_location_data ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ **/ ++static int ++csmisas_fill_location_data(MPT_ADAPTER *ioc, u8 bus, u8 id, u8 opcode, ++ CSMI_SAS_LOCATION_IDENTIFIER * location_ident) ++{ ++ ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ int rc; ++ SasDevicePage0_t *sasDevicePg0=NULL; ++ SasEnclosurePage0_t *sasEnclosurePg0=NULL; ++ dma_addr_t sasDevicePg0_dma,sasEnclosurePg0_dma; ++ int sasDevicePg0_data_sz=0; ++ int sasEnclosurePg0_data_sz=0; ++ u64 sas_address; ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ memset (location_ident, 0, sizeof(*location_ident)); ++ ++ /* SAS Device Page 0 */ ++ hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ rc=-1; ++ goto fill_location_data_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ rc=-1; ++ goto fill_location_data_exit; ++ } ++ ++ sasDevicePg0_data_sz = hdr.ExtPageLength * 4; ++ sasDevicePg0 = (SasDevicePage0_t *) pci_alloc_consistent( ++ ioc->pcidev, sasDevicePg0_data_sz, &sasDevicePg0_dma); ++ if (!sasDevicePg0) { ++ rc=-1; ++ goto fill_location_data_exit; ++ } ++ ++ memset((u8 *)sasDevicePg0, 0, sasDevicePg0_data_sz); ++ cfg.physAddr = sasDevicePg0_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = (bus << 8) + id ++ + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT); ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ rc=-1; ++ goto fill_location_data_exit; ++ } ++ ++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_ADDRESS_VALID; ++ memcpy(&sas_address, &sasDevicePg0->SASAddress, sizeof(u64)); ++ sas_address = reverse_byte_order64(sas_address); ++ memcpy(location_ident->bSASAddress, &sas_address, sizeof(u64)); ++ ++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_SAS_LUN_VALID; ++ memset(location_ident->bSASLun, 0, sizeof(location_ident->bSASLun)); ++ ++ /* SAS Enclosure Page 0 */ ++ hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 0; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ rc=0; ++ goto fill_location_data_exit; ++ } ++ ++ if (hdr.ExtPageLength == 0) { ++ rc=0; ++ goto fill_location_data_exit; ++ } ++ ++ sasEnclosurePg0_data_sz = hdr.ExtPageLength * 4; ++ sasEnclosurePg0 = (SasEnclosurePage0_t *) pci_alloc_consistent( ++ ioc->pcidev, sasEnclosurePg0_data_sz, &sasEnclosurePg0_dma); ++ if (!sasEnclosurePg0) { ++ rc=0; ++ goto fill_location_data_exit; ++ } ++ cfg.physAddr = sasEnclosurePg0_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = sasDevicePg0->EnclosureHandle ++ + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT); ++ ++ if ((rc = mpt_config(ioc, &cfg)) != 0) { ++ rc=0; ++ goto fill_location_data_exit; ++ } ++ ++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID; ++ memcpy(&sas_address, &sasEnclosurePg0->EnclosureLogicalID, sizeof(u64)); ++ sas_address = reverse_byte_order64(sas_address); ++ if (sas_address) ++ memcpy(location_ident->bEnclosureIdentifier, &sas_address, sizeof(u64)); ++ else ++ strcpy(location_ident->bEnclosureIdentifier,"Internal"); ++ ++// bBayPrefix - not supported ++ ++// TODO - We need to look at sasEnclosurePg0-.Flags , to determine ++// whether SEP BUS/TargetID is valid. Ifs its a SES device, then ++// issue internal inquiry to (bus/id) to gather the Enclosure name. ++// If the device is SMP, then issue SMP_MANUFACTURING to get enclosure name ++// If its direct attached, there is no enclosure name ++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID; ++ strcpy(location_ident->bEnclosureName,"Not Supported"); ++ ++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_LOCATION_STATE_VALID; ++ location_ident->bLocationState = CSMI_SAS_LOCATE_UNKNOWN; ++ ++ location_ident->bLocationFlags |= CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID; ++ location_ident->bBayIdentifier = le16_to_cpu(sasDevicePg0->Slot); ++ ++ ++// TODO - illuminating LEDs, ++// karg->bIdentify = CSMI_SAS_LOCATE_FORCE_OFF, CSMI_SAS_LOCATE_FORCE_ON ++// We can enable/disable LEDs by SCSI Enclosure Processor MPI request message ++// printk("Flags=0x%x\n",sasEnclosurePg0->Flags); ++ ++/* check sasEnclosurePg0->Flags - ++ * to validate whether we need to send the SEPRequest ++ * bit:5 should be set ++ * bit:3-0 any bit should be set. If zero, then SEPRequest will fail ++*/ ++ ++/* MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR ++ * Look in mpi_init.h ++ * SEPRequest_t = structure ++ * ++ * SEPRequest_t->Action should be set to MPI_SEP_REQ_ACTION_WRITE_STATUS ++ * ++ * SEPRequest_t->Flags should be set to ++ * MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS, to pass along enclosure/slot ids ++ * ++ * SEPRequest_t->SlotStatus |= MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST - this ++ * will illuminate the LEDs ++ */ ++ ++fill_location_data_exit: ++ ++ if (sasDevicePg0 != NULL) ++ pci_free_consistent(ioc->pcidev, sasDevicePg0_data_sz, ++ sasDevicePg0, sasDevicePg0_dma); ++ ++ if (sasEnclosurePg0 != NULL) ++ pci_free_consistent(ioc->pcidev, sasEnclosurePg0_data_sz, ++ sasEnclosurePg0, sasEnclosurePg0_dma); ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ return rc; ++} ++ ++static int ++csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus, ++ u8 volumeID) ++{ ++ pRaidVolumePage0_t pVolume0 = NULL; ++ pRaidPhysDiskPage0_t pPhysDisk0 = NULL; ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t header; ++ u8 physDiskNumMax; ++ int volumepage0sz = 0, physdiskpage0sz = 0; ++ dma_addr_t volume0_dma, physdisk0_dma; ++ int csmi_sas_get_location_sz; ++ int rc = 0, i, idx; ++ int num_hotpares; ++ u64 totalMaxLBA, tmpTotalMaxLBA; ++ IOCPage5_t *iocPage5 = NULL; ++ u32 device_info = 0; ++ struct sas_device_info *sas_info; ++ ++ int sz; ++ ++ csmi_sas_get_location_sz = karg->IoctlHeader.Length; ++ physDiskNumMax = (csmi_sas_get_location_sz - ++ offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) ++ / sizeof(CSMI_SAS_LOCATION_IDENTIFIER); ++ karg->bNumberOfLocationIdentifiers=0; ++ ++ /* ++ * get RAID Volume Page 0 ++ */ ++ ++ header.PageVersion = 0; ++ header.PageLength = 0; ++ header.PageNumber = 0; ++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; ++ cfg.cfghdr.hdr = &header; ++ cfg.physAddr = -1; ++ cfg.pageAddr = (VolumeBus << 8) + volumeID; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ if (mpt_config(ioc, &cfg) != 0) { ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ if (header.PageLength == 0) { ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ volumepage0sz = header.PageLength * 4; ++ pVolume0 = pci_alloc_consistent(ioc->pcidev, volumepage0sz, ++ &volume0_dma); ++ if (!pVolume0) { ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.physAddr = volume0_dma; ++ if (mpt_config(ioc, &cfg) != 0){ ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ totalMaxLBA = (u64)le32_to_cpu(pVolume0->MaxLBA) | ++ ((u64)le32_to_cpu(pVolume0->MaxLBAHigh)) << 32; ++ ++ /* ++ * get RAID Physical Disk Page 0 ++ */ ++ header.PageVersion = 0; ++ header.PageLength = 0; ++ header.PageNumber = 0; ++ header.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; ++ cfg.cfghdr.hdr = &header; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; ++ if (mpt_config(ioc, &cfg) != 0) { ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ if (header.PageLength == 0) { ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ physdiskpage0sz = header.PageLength * 4; ++ pPhysDisk0 = pci_alloc_consistent(ioc->pcidev, physdiskpage0sz, ++ &physdisk0_dma); ++ if (!pPhysDisk0) { ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ cfg.physAddr = physdisk0_dma; ++ ++ for (i=0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { ++ ++ /* obtain a refresh of pPhysDisk0 */ ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = pVolume0->PhysDisk[i].PhysDiskNum; ++ if (mpt_config(ioc, &cfg) != 0){ ++ rc = -1; ++ goto sas_fill_location_data_raid_exit; ++ } ++ ++ if((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus, ++ pPhysDisk0->PhysDiskID, karg->bIdentify, ++ &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0) ++ karg->bNumberOfLocationIdentifiers++; ++ ++ if (device_info) ++ continue; ++ sas_info = csmisas_get_device_component_by_fw(ioc, ++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); ++ if (!sas_info || sas_info->is_cached) ++ continue; ++ device_info = sas_info->device_info; ++ } ++ ++ if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) ++ goto sas_fill_location_data_raid_exit; ++ ++ /* ++ * hot spare support ++ * ++ */ ++ ++ num_hotpares = csmisas_get_number_hotspares(ioc); ++ ++ if (num_hotpares) { ++ ++ sz = offsetof(IOCPage5_t, HotSpare) + ++ num_hotpares * sizeof(IOC_5_HOT_SPARE); ++ iocPage5 = kmalloc(sz, GFP_KERNEL); ++ ++ if (!iocPage5) ++ goto sas_fill_location_data_raid_exit; ++ memset(iocPage5, 0, sizeof(*iocPage5)); ++ ++ if (csmisas_get_ioc_pg5(ioc, iocPage5, sz) != 0) ++ goto sas_fill_location_data_raid_exit; ++ ++ for(i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares; ++ i++, idx++) { ++ ++ if (idx >= physDiskNumMax) ++ break; ++ ++ /* obtain a refresh of pPhysDisk0 */ ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = iocPage5->HotSpare[i].PhysDiskNum; ++ if (mpt_config(ioc, &cfg) != 0) ++ goto sas_fill_location_data_raid_exit; ++ ++ /* Search the list for the matching SAS address. */ ++ sas_info = csmisas_get_device_component_by_fw(ioc, ++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); ++ ++ if (!sas_info || sas_info->is_cached) ++ continue; ++ ++ /* don't mix SSP hot spare ++ * in SATA volume ++ */ ++ if (!csmisas_is_sata(pPhysDisk0) && ++ (device_info & ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) ++ continue; ++ ++ /* don't mix SATA hot spare ++ * in SSP volume ++ */ ++ if (csmisas_is_sata(pPhysDisk0) && ++ (device_info & ++ MPI_SAS_DEVICE_INFO_SSP_TARGET)) ++ continue; ++ ++ /* capacity check for IM volumes*/ ++ if ((pVolume0->VolumeType == ++ MPI_RAID_VOL_TYPE_IM) && ++ (totalMaxLBA + ++ (64*2*1024) /* metadata = 64MB*/ > ++ le32_to_cpu(pPhysDisk0->MaxLBA))) ++ continue; ++ ++ tmpTotalMaxLBA = totalMaxLBA; ++ do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks); ++ /* capacity check for IME volumes*/ ++ if ((pVolume0->VolumeType == ++ MPI_RAID_VOL_TYPE_IME) && ++ ((tmpTotalMaxLBA * 2) + ++ (64*2*1024 ) /*metadata = 64MB*/ > ++ le32_to_cpu(pPhysDisk0->MaxLBA))) ++ continue; ++ ++ if((csmisas_fill_location_data(ioc, ++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID, ++ karg->bIdentify, ++ &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0) ++ karg->bNumberOfLocationIdentifiers++; ++ } ++ } ++ ++ ++ sas_fill_location_data_raid_exit: ++ ++ kfree(iocPage5); ++ ++ if (pVolume0) ++ pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0, ++ volume0_dma); ++ ++ if(pPhysDisk0) ++ pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0, ++ physdisk0_dma); ++ ++ return rc; ++} ++ ++/** ++ * Prototype Routine for the CSMI SAS Get location command. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -ENODEV if no such device/adapter ++ */ ++static int ++csmisas_get_location(unsigned long arg) ++{ ++ CSMI_SAS_GET_LOCATION_BUFFER __user *uarg = (void __user *) arg; ++ PCSMI_SAS_GET_LOCATION_BUFFER karg; ++ IOCTL_HEADER ioctl_header; ++ MPT_ADAPTER *ioc = NULL; ++ int iocnum,i; ++ int csmi_sas_get_location_sz; ++ int memory_pages; ++ struct sas_device_info *sas_info; ++ ++ if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in IOCTL_HEADER" ++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ csmi_sas_get_location_sz = ioctl_header.Length; ++ memory_pages = get_order(csmi_sas_get_location_sz); ++ karg = (PCSMI_SAS_GET_LOCATION_BUFFER)__get_free_pages( ++ GFP_KERNEL, memory_pages); ++ if (!karg){ ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to malloc GET_LOCATION_BUFFER " ++ "csmi_sas_get_location_sz=%d memory_pages=%d\n", ++ __FILE__, __LINE__, __FUNCTION__, ++ csmi_sas_get_location_sz, memory_pages); ++ return -ENOMEM; ++ } ++ memset(karg, 0, sizeof(*karg)); ++ ++ if (copy_from_user(karg, uarg, csmi_sas_get_location_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to read in csmi_sas_phy_control_buffer " ++ "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, ++ &ioc)) < 0) || (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ if (!csmisas_is_this_sas_cntr(ioc)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ free_pages((unsigned long)karg, memory_pages); ++ return -ENODEV; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ if(karg->bLengthOfLocationIdentifier != ++ sizeof(CSMI_SAS_LOCATION_IDENTIFIER)) ++ goto cim_sas_get_location_exit; ++ ++ sas_info = csmisas_get_device_component_by_os(ioc, karg->bPathId, ++ karg->bTargetId); ++ if (!sas_info) ++ goto cim_sas_get_location_exit; ++ ++ /* RAID SUPPORT */ ++ if (ioc->raid_data.pIocPg2 && sas_info->is_logical_volume) { ++ for (i=0; iraid_data.pIocPg2->NumActiveVolumes; i++){ ++ if (sas_info->fw.id == ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID && ++ sas_info->fw.channel == ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus) { ++ if(csmisas_fill_location_data_raid(ioc, karg, ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus, ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) == 0) ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_SUCCESS; ++ else ++ karg->IoctlHeader.ReturnCode = ++ CSMI_SAS_STATUS_FAILED; ++ goto cim_sas_get_location_exit; ++ } ++ } ++ } ++ ++ /* NON-RAID SUPPORT */ ++ if (sas_info->is_cached || sas_info->is_logical_volume) ++ goto cim_sas_get_location_exit; ++ ++ /* make sure there's enough room to populate the Location[] struct */ ++ if ((csmi_sas_get_location_sz - ++ offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) < ++ sizeof(CSMI_SAS_LOCATION_IDENTIFIER)) ++ goto cim_sas_get_location_exit; ++ ++ karg->bNumberOfLocationIdentifiers=1; ++ karg->Location[0].bLocationFlags=0; ++ if((csmisas_fill_location_data(ioc, sas_info->fw.channel, ++ sas_info->fw.id, karg->bIdentify, &karg->Location[0])) == 0) ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; ++ else ++ karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; ++ ++ cim_sas_get_location_exit: ++ ++ /* Copy the data from kernel memory to user memory ++ */ ++ if (copy_to_user(uarg, karg, csmi_sas_get_location_sz)) { ++ printk(KERN_ERR "%s@%d::%s() - " ++ "Unable to write out csmi_sas_get_location_buffer " ++ "@ %p\n",__FILE__, __LINE__, __FUNCTION__, uarg); ++ free_pages((unsigned long)karg, memory_pages); ++ return -EFAULT; ++ } ++ ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ free_pages((unsigned long)karg, memory_pages); ++ return 0; ++} +--- /dev/null ++++ b/drivers/message/fusion/csmi/csmisas.h +@@ -0,0 +1,1854 @@ ++/************************************************************************** ++ ++Module Name: ++ ++ CSMISAS.H ++ ++ ++Abstract: ++ ++ This file contains constants and data structure definitions used by drivers ++ that support the Common Storage Management Interface specification for ++ SAS or SATA in either the Windows or Linux. ++ ++ This should be considered as a reference implementation only. Changes may ++ be necessary to accommodate a specific build environment or target OS. ++ ++Revision History: ++ ++ 001 SEF 8/12/03 Initial release. ++ 002 SEF 8/20/03 Cleanup to match documentation. ++ 003 SEF 9/12/03 Additional cleanup, created combined header ++ 004 SEF 9/23/03 Changed base types to match linux defaults ++ Added RAID signature ++ Added bControllerFlags to CSMI_SAS_CNTLR_CONFIG ++ Changed CSMI_SAS_BEGIN_PACK to 8 for common structures ++ Fixed other typos identified in first compilation test ++ 005 SEF 10/03/03 Additions to match first version of CSMI document ++ 006 SEF 10/14/03 Fixed typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER ++ Added defines for bConnectionRate ++ 007 SEF 10/15/03 Added Firmware Download Control Code and support ++ Added CSMI revision support ++ 008 SEF 10/30/03 No functional change, just updated version to track ++ spec changes ++ 009 SEF 12/09/03 No functional change, just updated version to track ++ spec changes ++ 010 SEF 3/11/04 Fixed typedef struct CSMI_SAS_RAID_DRIVES to include the ++ bFirmware member that is defined in the spec, but ++ was missing in this file, ++ added CC_CSMI_SAS_TASK_MANAGEMENT ++ 011 SEF 4/02/04 No functional change, added comment line before ++ CC_CSMI_SAS_TASK_MANAGEMENT ++ 012 SEF 4/16/04 Added IOControllerNumber to linux header, ++ Modified linux control codes to have upper word of ++ 0xCC77.... to indicate CSMI version 77 ++ Added bSignalClass to CC_CSMI_SET_PHY_INFO ++ Added CC_CSMI_SAS_PHY_CONTROL support ++ 013 SEF 5/14/04 Added CC_CSMI_SAS_GET_CONNECTOR_INFO support ++ 014 SEF 5/24/04 No functional change, just updated version to track spec ++ changes ++ 015 SEF 6/16/04 changed bPinout to uPinout to reflect proper size, ++ changed width of bLocation defines to reflect size ++ 016 SEF 6/17/04 changed bLengthOfControls in CSMI_SAS_PHY_CONTROL ++ to be proper size ++ 017 SEF 9/17/04 added CSMI_SAS_SATA_PORT_SELECTOR, ++ CSMI_SAS_LINK_VIRTUAL, CSMI_SAS_CON_NOT_PRESENT, and ++ CSMI_SAS_CON_NOT_CONNECTED ++ 018 SEF 9/20/04 added CSMI_SAS_PHY_USER_PATTERN, ++ changed definition of CSMI_SAS_PHY_FIXED_PATTERN to not ++ conflict with activate definition ++ 019 SEF 12/06/04 added CSMI_SAS_GET_LOCATION ++ added bSSPStatus to CSMI_SAS_SSP_PASSTHRU_STATUS ++ structure ++ 020 SEF 5/25/05 added CSMI_SAS_PHY_VIRTUAL_SMP, and changes to ++ CSMI_SAS_GET_LOCATION ++ 021 SEF 11/03/05 added new RAID creation functionality ++ 022 SEF 2/01/06 corrected typo bNegotitiatedLInkRate ++ Added two more RAID_TYPES, 7 and 8 ++ 023 SEF 4/04/06 added CSMI_RAID_TYPE_1E ++ changed structures that contained surface scan ++ to priority approach rather than time, causes ++ 0.89 to incompatible with 0.87, so a version ++ check is necessary when interpreting the ++ raid structures ++ Added netware section ++ 024 DRG 5/22/06 Added uFailureCode to CSMI_SAS_RAID_CONFIG and ++ CSMI_SAS_RAID_FEATURES ++ Changed __u64 fields to high and low __u32 fields in ++ order to avoid backward compatibility issues with ++ packing and alignment. ++ Fixed alignment problem in CSMI_SAS_RAID_DRIVES. ++ Added CSMI_SAS_CNTLR_SMART_ARRAY to uControllerFlags ++ Reassigned the value of CSMI_SAS_CNTLR_RAID_CFG_SUPPORT ++ to avoid a conflict. ++ ++**************************************************************************/ ++ ++#ifndef _CSMI_SAS_H_ ++#define _CSMI_SAS_H_ ++ ++// CSMI Specification Revision, the intent is that all versions of the ++// specification will be backward compatible after the 1.00 release. ++// Major revision number, corresponds to xxxx. of CSMI specification ++// Minor revision number, corresponds to .xxxx of CSMI specification ++#define CSMI_MAJOR_REVISION 0 ++#define CSMI_MINOR_REVISION 90 ++ ++/*************************************************************************/ ++/* PATCHES FOR TYPOS */ ++/*************************************************************************/ ++ ++#define bNegotitiatedLInkRate bNegotiatedLinkRate ++ ++/*************************************************************************/ ++/* TARGET OS LINUX SPECIFIC CODE */ ++/*************************************************************************/ ++ ++// EDM #ifdef _linux ++#ifdef __KERNEL__ ++ ++// Linux base types ++ ++#include ++ ++#define __i8 char ++ ++// pack definition ++ ++// EDM #define CSMI_SAS_BEGIN_PACK(x) pack(x) ++// EDM #define CSMI_SAS_END_PACK pack() ++ ++// IOCTL Control Codes ++// (IoctlHeader.ControlCode) ++ ++// Control Codes prior to 0.77 ++ ++// Control Codes requiring CSMI_ALL_SIGNATURE ++ ++// #define CC_CSMI_SAS_GET_DRIVER_INFO 0x12345678 ++// #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x23456781 ++// #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x34567812 ++// #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x92345678 ++ ++// Control Codes requiring CSMI_RAID_SIGNATURE ++ ++// #define CC_CSMI_SAS_GET_RAID_INFO 0x45678123 ++// #define CC_CSMI_SAS_GET_RAID_CONFIG 0x56781234 ++ ++// Control Codes requiring CSMI_SAS_SIGNATURE ++ ++// #define CC_CSMI_SAS_GET_PHY_INFO 0x67812345 ++// #define CC_CSMI_SAS_SET_PHY_INFO 0x78123456 ++// #define CC_CSMI_SAS_GET_LINK_ERRORS 0x81234567 ++// #define CC_CSMI_SAS_SMP_PASSTHRU 0xA1234567 ++// #define CC_CSMI_SAS_SSP_PASSTHRU 0xB1234567 ++// #define CC_CSMI_SAS_STP_PASSTHRU 0xC1234567 ++// #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567 ++// #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xE1234567 ++// #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567 ++// #define CC_CSMI_SAS_TASK_MANAGEMENT 0xA2345678 ++ ++// Control Codes for 0.77 and later ++ ++// Control Codes requiring CSMI_ALL_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_DRIVER_INFO 0xCC770001 ++#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0xCC770002 ++#define CC_CSMI_SAS_GET_CNTLR_STATUS 0xCC770003 ++#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0xCC770004 ++ ++// Control Codes requiring CSMI_RAID_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_RAID_INFO 0xCC77000A ++#define CC_CSMI_SAS_GET_RAID_CONFIG 0xCC77000B ++#define CC_CSMI_SAS_GET_RAID_FEATURES 0xCC77000C ++#define CC_CSMI_SAS_SET_RAID_CONTROL 0xCC77000D ++#define CC_CSMI_SAS_GET_RAID_ELEMENT 0xCC77000E ++#define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F ++ ++// Control Codes requiring CSMI_SAS_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_PHY_INFO 0xCC770014 ++#define CC_CSMI_SAS_SET_PHY_INFO 0xCC770015 ++#define CC_CSMI_SAS_GET_LINK_ERRORS 0xCC770016 ++#define CC_CSMI_SAS_SMP_PASSTHRU 0xCC770017 ++#define CC_CSMI_SAS_SSP_PASSTHRU 0xCC770018 ++#define CC_CSMI_SAS_STP_PASSTHRU 0xCC770019 ++#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xCC770020 ++#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xCC770021 ++#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xCC770022 ++#define CC_CSMI_SAS_TASK_MANAGEMENT 0xCC770023 ++#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0xCC770024 ++#define CC_CSMI_SAS_GET_LOCATION 0xCC770025 ++ ++ ++// Control Codes requiring CSMI_PHY_SIGNATURE ++ ++#define CC_CSMI_SAS_PHY_CONTROL 0xCC77003C ++ ++// EDM #pragma CSMI_SAS_BEGIN_PACK(8) ++#pragma pack(8) ++ ++// IOCTL_HEADER ++typedef struct _IOCTL_HEADER { ++ __u32 IOControllerNumber; ++ __u32 Length; ++ __u32 ReturnCode; ++ __u32 Timeout; ++ __u16 Direction; ++} IOCTL_HEADER, ++ *PIOCTL_HEADER; ++ ++// EDM #pragma CSMI_SAS_END_PACK ++#pragma pack() ++ ++#endif ++ ++/*************************************************************************/ ++/* TARGET OS WINDOWS SPECIFIC CODE */ ++/*************************************************************************/ ++ ++#ifdef _WIN32 ++ ++// windows IOCTL definitions ++ ++#ifndef _NTDDSCSIH_ ++#include ++#endif ++ ++// pack definition ++ ++#if defined _MSC_VER ++ #define CSMI_SAS_BEGIN_PACK(x) pack(push,x) ++ #define CSMI_SAS_END_PACK pack(pop) ++#elif defined __BORLANDC__ ++ #define CSMI_SAS_BEGIN_PACK(x) option -a##x ++ #define CSMI_SAS_END_PACK option -a. ++#else ++ #error "CSMISAS.H - Must externally define a pack compiler designator." ++#endif ++ ++// base types ++ ++#define __u8 unsigned char ++#define __u16 unsigned short ++#define __u32 unsigned long ++#define __u64 unsigned __int64 ++ ++#define __i8 char ++ ++// IOCTL Control Codes ++// (IoctlHeader.ControlCode) ++ ++// Control Codes requiring CSMI_ALL_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_DRIVER_INFO 1 ++#define CC_CSMI_SAS_GET_CNTLR_CONFIG 2 ++#define CC_CSMI_SAS_GET_CNTLR_STATUS 3 ++#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 4 ++ ++// Control Codes requiring CSMI_RAID_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_RAID_INFO 10 ++#define CC_CSMI_SAS_GET_RAID_CONFIG 11 ++#define CC_CSMI_SAS_GET_RAID_FEATURES 12 ++#define CC_CSMI_SAS_SET_RAID_CONTROL 13 ++#define CC_CSMI_SAS_GET_RAID_ELEMENT 14 ++#define CC_CSMI_SAS_SET_RAID_OPERATION 15 ++ ++// Control Codes requiring CSMI_SAS_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_PHY_INFO 20 ++#define CC_CSMI_SAS_SET_PHY_INFO 21 ++#define CC_CSMI_SAS_GET_LINK_ERRORS 22 ++#define CC_CSMI_SAS_SMP_PASSTHRU 23 ++#define CC_CSMI_SAS_SSP_PASSTHRU 24 ++#define CC_CSMI_SAS_STP_PASSTHRU 25 ++#define CC_CSMI_SAS_GET_SATA_SIGNATURE 26 ++#define CC_CSMI_SAS_GET_SCSI_ADDRESS 27 ++#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28 ++#define CC_CSMI_SAS_TASK_MANAGEMENT 29 ++#define CC_CSMI_SAS_GET_CONNECTOR_INFO 30 ++#define CC_CSMI_SAS_GET_LOCATION 31 ++ ++// Control Codes requiring CSMI_PHY_SIGNATURE ++ ++#define CC_CSMI_SAS_PHY_CONTROL 60 ++ ++#define IOCTL_HEADER SRB_IO_CONTROL ++#define PIOCTL_HEADER PSRB_IO_CONTROL ++ ++#endif ++ ++/*************************************************************************/ ++/* TARGET OS NETWARE SPECIFIC CODE */ ++/*************************************************************************/ ++ ++#ifdef _NETWARE ++ ++// NetWare IOCTL definitions ++ ++#define CSMI_SAS_BEGIN_PACK(x) pack(x) ++#define CSMI_SAS_END_PACK pack() ++ ++#ifndef LONG ++typedef unsigned long LONG; ++#endif ++ ++#ifndef WORD ++typedef unsigned short WORD; ++#endif ++ ++#ifndef BYTE ++typedef unsigned char BYTE; ++#endif ++ ++/* Need to have these definitions for Netware */ ++#define __u8 unsigned char ++#define __u16 unsigned short ++#define __u32 unsigned long ++#define __u64 unsigned __int64 ++ ++#define __i8 char ++ ++ ++// EDM #pragma CSMI_SAS_BEGIN_PACK(8) ++#pragma pack(8) ++ ++// IOCTL_HEADER ++typedef struct _IOCTL_HEADER { ++ __u32 Length; ++ __u32 ReturnCode; ++} IOCTL_HEADER, ++ *PIOCTL_HEADER; ++ ++// EDM #pragma CSMI_SAS_END_PACK ++#pragma pack() ++ ++// IOCTL Control Codes ++// (IoctlHeader.ControlCode) ++ ++// Control Codes requiring CSMI_ALL_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_DRIVER_INFO 0x01FF0001 ++#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x01FF0002 ++#define CC_CSMI_SAS_GET_CNTLR_STATUS 0x01FF0003 ++#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x01FF0004 ++ ++// Control Codes requiring CSMI_RAID_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_RAID_INFO 0x01FF000A ++#define CC_CSMI_SAS_GET_RAID_CONFIG 0x01FF000B ++#define CC_CSMI_SAS_GET_RAID_FEATURES 0x01FF000C ++#define CC_CSMI_SAS_SET_RAID_CONTROL 0x01FF000D ++#define CC_CSMI_SAS_GET_RAID_ELEMENT 0x01FF000E ++#define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F ++ ++// Control Codes requiring CSMI_SAS_SIGNATURE ++ ++#define CC_CSMI_SAS_GET_PHY_INFO 0x01FF0014 ++#define CC_CSMI_SAS_SET_PHY_INFO 0x01FF0015 ++#define CC_CSMI_SAS_GET_LINK_ERRORS 0x01FF0016 ++#define CC_CSMI_SAS_SMP_PASSTHRU 0x01FF0017 ++#define CC_CSMI_SAS_SSP_PASSTHRU 0x01FF0018 ++#define CC_CSMI_SAS_STP_PASSTHRU 0x01FF0019 ++#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A ++#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0x01FF001B ++#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C ++#define CC_CSMI_SAS_TASK_MANAGEMENT 0x01FF001D ++#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E ++#define CC_CSMI_SAS_GET_LOCATION 0x01FF001F ++ ++// Control Codes requiring CSMI_PHY_SIGNATURE ++ ++#define CC_CSMI_SAS_PHY_CONTROL 60 ++ ++#endif ++ ++/*************************************************************************/ ++/* TARGET OS NOT DEFINED ERROR */ ++/*************************************************************************/ ++ ++// EDM ++//#if (!_WIN32 && !_linux && !_NETWARE) ++// #error "Unknown target OS." ++//#endif ++ ++/*************************************************************************/ ++/* OS INDEPENDENT CODE */ ++/*************************************************************************/ ++ ++/* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */ ++ ++// Return codes for all IOCTL's regardless of class ++// (IoctlHeader.ReturnCode) ++ ++#define CSMI_SAS_STATUS_SUCCESS 0 ++#define CSMI_SAS_STATUS_FAILED 1 ++#define CSMI_SAS_STATUS_BAD_CNTL_CODE 2 ++#define CSMI_SAS_STATUS_INVALID_PARAMETER 3 ++#define CSMI_SAS_STATUS_WRITE_ATTEMPTED 4 ++ ++// Signature value ++// (IoctlHeader.Signature) ++ ++#define CSMI_ALL_SIGNATURE "CSMIALL" ++ ++// Timeout value default of 60 seconds ++// (IoctlHeader.Timeout) ++ ++#define CSMI_ALL_TIMEOUT 60 ++ ++// Direction values for data flow on this IOCTL ++// (IoctlHeader.Direction, Linux only) ++#define CSMI_SAS_DATA_READ 0 ++#define CSMI_SAS_DATA_WRITE 1 ++ ++// I/O Bus Types ++// ISA and EISA bus types are not supported ++// (bIoBusType) ++ ++#define CSMI_SAS_BUS_TYPE_PCI 3 ++#define CSMI_SAS_BUS_TYPE_PCMCIA 4 ++ ++// Controller Status ++// (uStatus) ++ ++#define CSMI_SAS_CNTLR_STATUS_GOOD 1 ++#define CSMI_SAS_CNTLR_STATUS_FAILED 2 ++#define CSMI_SAS_CNTLR_STATUS_OFFLINE 3 ++#define CSMI_SAS_CNTLR_STATUS_POWEROFF 4 ++ ++// Offline Status Reason ++// (uOfflineReason) ++ ++#define CSMI_SAS_OFFLINE_REASON_NO_REASON 0 ++#define CSMI_SAS_OFFLINE_REASON_INITIALIZING 1 ++#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2 ++#define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE 3 ++ ++// Controller Class ++// (bControllerClass) ++ ++#define CSMI_SAS_CNTLR_CLASS_HBA 5 ++ ++// Controller Flag bits ++// (uControllerFlags) ++ ++#define CSMI_SAS_CNTLR_SAS_HBA 0x00000001 ++#define CSMI_SAS_CNTLR_SAS_RAID 0x00000002 ++#define CSMI_SAS_CNTLR_SATA_HBA 0x00000004 ++#define CSMI_SAS_CNTLR_SATA_RAID 0x00000008 ++#define CSMI_SAS_CNTLR_SMART_ARRAY 0x00000010 ++ ++// for firmware download ++#define CSMI_SAS_CNTLR_FWD_SUPPORT 0x00010000 ++#define CSMI_SAS_CNTLR_FWD_ONLINE 0x00020000 ++#define CSMI_SAS_CNTLR_FWD_SRESET 0x00040000 ++#define CSMI_SAS_CNTLR_FWD_HRESET 0x00080000 ++#define CSMI_SAS_CNTLR_FWD_RROM 0x00100000 ++ ++// for RAID configuration supported ++#define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000 ++ ++// Download Flag bits ++// (uDownloadFlags) ++#define CSMI_SAS_FWD_VALIDATE 0x00000001 ++#define CSMI_SAS_FWD_SOFT_RESET 0x00000002 ++#define CSMI_SAS_FWD_HARD_RESET 0x00000004 ++ ++// Firmware Download Status ++// (usStatus) ++#define CSMI_SAS_FWD_SUCCESS 0 ++#define CSMI_SAS_FWD_FAILED 1 ++#define CSMI_SAS_FWD_USING_RROM 2 ++#define CSMI_SAS_FWD_REJECT 3 ++#define CSMI_SAS_FWD_DOWNREV 4 ++ ++// Firmware Download Severity ++// (usSeverity> ++#define CSMI_SAS_FWD_INFORMATION 0 ++#define CSMI_SAS_FWD_WARNING 1 ++#define CSMI_SAS_FWD_ERROR 2 ++#define CSMI_SAS_FWD_FATAL 3 ++ ++/* * * * * * * * * * SAS RAID Class IOCTL Constants * * * * * * * * */ ++ ++// Return codes for the RAID IOCTL's regardless of class ++// (IoctlHeader.ReturnCode) ++ ++#define CSMI_SAS_RAID_SET_OUT_OF_RANGE 1000 ++#define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL 1001 ++#define CSMI_SAS_RAID_SET_DATA_CHANGED 1002 ++ ++// Signature value ++// (IoctlHeader.Signature) ++ ++#define CSMI_RAID_SIGNATURE "CSMIARY" ++ ++// Timeout value default of 60 seconds ++// (IoctlHeader.Timeout) ++ ++#define CSMI_RAID_TIMEOUT 60 ++ ++// RAID Types ++// (bRaidType) ++#define CSMI_SAS_RAID_TYPE_NONE 0 ++#define CSMI_SAS_RAID_TYPE_0 1 ++#define CSMI_SAS_RAID_TYPE_1 2 ++#define CSMI_SAS_RAID_TYPE_10 3 ++#define CSMI_SAS_RAID_TYPE_5 4 ++#define CSMI_SAS_RAID_TYPE_15 5 ++#define CSMI_SAS_RAID_TYPE_6 6 ++#define CSMI_SAS_RAID_TYPE_50 7 ++#define CSMI_SAS_RAID_TYPE_VOLUME 8 ++#define CSMI_SAS_RAID_TYPE_1E 9 ++#define CSMI_SAS_RAID_TYPE_OTHER 255 ++// the last value 255 was already defined for other ++// so end is defined as 254 ++#define CSMI_SAS_RAID_TYPE_END 254 ++ ++// RAID Status ++// (bStatus) ++#define CSMI_SAS_RAID_SET_STATUS_OK 0 ++#define CSMI_SAS_RAID_SET_STATUS_DEGRADED 1 ++#define CSMI_SAS_RAID_SET_STATUS_REBUILDING 2 ++#define CSMI_SAS_RAID_SET_STATUS_FAILED 3 ++#define CSMI_SAS_RAID_SET_STATUS_OFFLINE 4 ++#define CSMI_SAS_RAID_SET_STATUS_TRANSFORMING 5 ++#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD 6 ++#define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION 7 ++ ++// RAID Drive Count ++// (bDriveCount, 0xF1 to 0xFF are reserved) ++#define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG 0xF1 ++#define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2 ++ ++// RAID Data Type ++// (bDataType) ++#define CSMI_SAS_RAID_DATA_DRIVES 0 ++#define CSMI_SAS_RAID_DATA_DEVICE_ID 1 ++#define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA 2 ++ ++// RAID Drive Status ++// (bDriveStatus) ++#define CSMI_SAS_DRIVE_STATUS_OK 0 ++#define CSMI_SAS_DRIVE_STATUS_REBUILDING 1 ++#define CSMI_SAS_DRIVE_STATUS_FAILED 2 ++#define CSMI_SAS_DRIVE_STATUS_DEGRADED 3 ++#define CSMI_SAS_DRIVE_STATUS_OFFLINE 4 ++#define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5 ++ ++// RAID Drive Usage ++// (bDriveUsage) ++#define CSMI_SAS_DRIVE_CONFIG_NOT_USED 0 ++#define CSMI_SAS_DRIVE_CONFIG_MEMBER 1 ++#define CSMI_SAS_DRIVE_CONFIG_SPARE 2 ++#define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE 3 ++ ++// RAID Drive Type ++// (bDriveType) ++#define CSMI_SAS_DRIVE_TYPE_UNKNOWN 0 ++#define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1 ++#define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS 2 ++#define CSMI_SAS_DRIVE_TYPE_SATA 3 ++#define CSMI_SAS_DRIVE_TYPE_SATA_PS 4 ++#define CSMI_SAS_DRIVE_TYPE_OTHER 255 ++ ++// RAID Write Protect ++// (bWriteProtect) ++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN 0 ++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED 0 ++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED 1 ++#define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED 2 ++ ++// RAID Cache Setting ++// (bCacheSetting) ++#define CSMI_SAS_RAID_SET_CACHE_UNKNOWN 0 ++#define CSMI_SAS_RAID_SET_CACHE_UNCHANGED 0 ++#define CSMI_SAS_RAID_SET_CACHE_ENABLED 1 ++#define CSMI_SAS_RAID_SET_CACHE_DISABLED 2 ++#define CSMI_SAS_RAID_SET_CACHE_CORRUPT 3 ++ ++// RAID Features ++// (uFeatures) ++#define CSMI_SAS_RAID_FEATURE_TRANSFORMATION 0x00000001 ++#define CSMI_SAS_RAID_FEATURE_REBUILD 0x00000002 ++#define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR 0x00000004 ++#define CSMI_SAS_RAID_FEATURE_MERGE_MIRROR 0x00000008 ++#define CSMI_SAS_RAID_FEATURE_LUN_RENUMBER 0x00000010 ++#define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN 0x00000020 ++#define CSMI_SAS_RAID_FEATURE_SPARES_SHARED 0x00000040 ++ ++// RAID Priority ++// (bDefaultTransformPriority, etc.) ++#define CSMI_SAS_PRIORITY_UNKNOWN 0 ++#define CSMI_SAS_PRIORITY_UNCHANGED 0 ++#define CSMI_SAS_PRIORITY_AUTO 1 ++#define CSMI_SAS_PRIORITY_OFF 2 ++#define CSMI_SAS_PRIORITY_LOW 3 ++#define CSMI_SAS_PRIORITY_MEDIUM 4 ++#define CSMI_SAS_PRIORITY_HIGH 5 ++ ++// RAID Transformation Rules ++// (uRaidSetTransformationRules) ++#define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY 0x00000001 ++#define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS 0x00000002 ++ ++// RAID Cache Ratios Supported ++// (bCacheRatiosSupported) ++// from 0 to 100 defines the write to read ratio, 0 is 100% write ++#define CSMI_SAS_RAID_CACHE_RATIO_RANGE 101 ++#define CSMI_SAS_RAID_CACHE_RATIO_FIXED 102 ++#define CSMI_SAS_RAID_CACHE_RATIO_AUTO 103 ++#define CSMI_SAS_RAID_CACHE_RATIO_END 255 ++ ++// RAID Cache Ratio Flag ++// (bCacheRatioFlag) ++#define CSMI_SAS_RAID_CACHE_RATIO_DISABLE 0 ++#define CSMI_SAS_RAID_CACHE_RATIO_ENABLE 1 ++ ++// RAID Clear Configuration Signature ++// (bClearConfiguration) ++#define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR" ++ ++// RAID Failure Codes ++// (uFailureCode) ++#define CSMI_SAS_FAIL_CODE_OK 0 ++#define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID 1000 ++#define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID 1001 ++#define CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID 1002 ++#define CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID 1003 ++#define CSMI_SAS_FAIL_CODE_SURFACE_SCAN_INVALID 1004 ++#define CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID 1005 ++#define CSMI_SAS_FAIL_CODE_ELEMENT_INDEX_INVALID 1006 ++#define CSMI_SAS_FAIL_CODE_SUBELEMENT_INDEX_INVALID 1007 ++#define CSMI_SAS_FAIL_CODE_EXTENT_INVALID 1008 ++#define CSMI_SAS_FAIL_CODE_BLOCK_COUNT_INVALID 1009 ++#define CSMI_SAS_FAIL_CODE_DRIVE_INDEX_INVALID 1010 ++#define CSMI_SAS_FAIL_CODE_EXISTING_LUN_INVALID 1011 ++#define CSMI_SAS_FAIL_CODE_RAID_TYPE_INVALID 1012 ++#define CSMI_SAS_FAIL_CODE_STRIPE_SIZE_INVALID 1013 ++#define CSMI_SAS_FAIL_CODE_TRANSFORMATION_INVALID 1014 ++#define CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID 1015 ++#define CSMI_SAS_FAIL_CODE_ENUMERATION_TYPE_INVALID 1016 ++ ++#define CSMI_SAS_FAIL_CODE_EXCEEDED_RAID_SET_COUNT 2000 ++#define CSMI_SAS_FAIL_CODE_DUPLICATE_LUN 2001 ++ ++#define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION 3000 ++ ++// RAID Enumeration Types ++// (uEnumerationType) ++#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE 0 ++#define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE 1 ++#define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET 2 ++#define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE 3 ++ ++// RAID Extent Types ++// (bExtentType) ++#define CSMI_SAS_RAID_EXTENT_RESERVED 0 ++#define CSMI_SAS_RAID_EXTENT_METADATA 1 ++#define CSMI_SAS_RAID_EXTENT_ALLOCATED 2 ++#define CSMI_SAS_RAID_EXTENT_UNALLOCATED 3 ++ ++// RAID Operation Types ++// (uOperationType) ++#define CSMI_SAS_RAID_SET_CREATE 0 ++#define CSMI_SAS_RAID_SET_LABEL 1 ++#define CSMI_SAS_RAID_SET_TRANSFORM 2 ++#define CSMI_SAS_RAID_SET_DELETE 3 ++#define CSMI_SAS_RAID_SET_WRITE_PROTECT 4 ++#define CSMI_SAS_RAID_SET_CACHE 5 ++#define CSMI_SAS_RAID_SET_ONLINE_STATE 6 ++#define CSMI_SAS_RAID_SET_SPARE 7 ++ ++// RAID Transform Types ++// (bTransformType) ++#define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR 0 ++#define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0 1 ++#define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER 2 ++#define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET 3 ++ ++// RAID Online State ++// (bOnlineState) ++#define CSMI_SAS_RAID_SET_STATE_UNKNOWN 0 ++#define CSMI_SAS_RAID_SET_STATE_ONLINE 1 ++#define CSMI_SAS_RAID_SET_STATE_OFFLINE 2 ++ ++/* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */ ++ ++// Return codes for SAS IOCTL's ++// (IoctlHeader.ReturnCode) ++ ++#define CSMI_SAS_PHY_INFO_CHANGED CSMI_SAS_STATUS_SUCCESS ++#define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE 2000 ++#define CSMI_SAS_LINK_RATE_OUT_OF_RANGE 2001 ++ ++#define CSMI_SAS_PHY_DOES_NOT_EXIST 2002 ++#define CSMI_SAS_PHY_DOES_NOT_MATCH_PORT 2003 ++#define CSMI_SAS_PHY_CANNOT_BE_SELECTED 2004 ++#define CSMI_SAS_SELECT_PHY_OR_PORT 2005 ++#define CSMI_SAS_PORT_DOES_NOT_EXIST 2006 ++#define CSMI_SAS_PORT_CANNOT_BE_SELECTED 2007 ++#define CSMI_SAS_CONNECTION_FAILED 2008 ++ ++#define CSMI_SAS_NO_SATA_DEVICE 2009 ++#define CSMI_SAS_NO_SATA_SIGNATURE 2010 ++#define CSMI_SAS_SCSI_EMULATION 2011 ++#define CSMI_SAS_NOT_AN_END_DEVICE 2012 ++#define CSMI_SAS_NO_SCSI_ADDRESS 2013 ++#define CSMI_SAS_NO_DEVICE_ADDRESS 2014 ++ ++// Signature value ++// (IoctlHeader.Signature) ++ ++#define CSMI_SAS_SIGNATURE "CSMISAS" ++ ++// Timeout value default of 60 seconds ++// (IoctlHeader.Timeout) ++ ++#define CSMI_SAS_TIMEOUT 60 ++ ++// Device types ++// (bDeviceType) ++ ++#define CSMI_SAS_PHY_UNUSED 0x00 ++#define CSMI_SAS_NO_DEVICE_ATTACHED 0x00 ++#define CSMI_SAS_END_DEVICE 0x10 ++#define CSMI_SAS_EDGE_EXPANDER_DEVICE 0x20 ++#define CSMI_SAS_FANOUT_EXPANDER_DEVICE 0x30 ++ ++// Protocol options ++// (bInitiatorPortProtocol, bTargetPortProtocol) ++ ++#define CSMI_SAS_PROTOCOL_SATA 0x01 ++#define CSMI_SAS_PROTOCOL_SMP 0x02 ++#define CSMI_SAS_PROTOCOL_STP 0x04 ++#define CSMI_SAS_PROTOCOL_SSP 0x08 ++ ++// Negotiated and hardware link rates ++// (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate) ++ ++#define CSMI_SAS_LINK_RATE_UNKNOWN 0x00 ++#define CSMI_SAS_PHY_DISABLED 0x01 ++#define CSMI_SAS_LINK_RATE_FAILED 0x02 ++#define CSMI_SAS_SATA_SPINUP_HOLD 0x03 ++#define CSMI_SAS_SATA_PORT_SELECTOR 0x04 ++#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08 ++#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09 ++#define CSMI_SAS_LINK_VIRTUAL 0x10 ++ ++// Discover state ++// (bAutoDiscover) ++ ++#define CSMI_SAS_DISCOVER_NOT_SUPPORTED 0x00 ++#define CSMI_SAS_DISCOVER_NOT_STARTED 0x01 ++#define CSMI_SAS_DISCOVER_IN_PROGRESS 0x02 ++#define CSMI_SAS_DISCOVER_COMPLETE 0x03 ++#define CSMI_SAS_DISCOVER_ERROR 0x04 ++ ++// Phy features ++ ++#define CSMI_SAS_PHY_VIRTUAL_SMP 0x01 ++ ++// Programmed link rates ++// (bMinimumLinkRate, bMaximumLinkRate) ++// (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate) ++ ++#define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00 ++#define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS 0x08 ++#define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS 0x09 ++ ++// Link rate ++// (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO) ++ ++#define CSMI_SAS_LINK_RATE_NEGOTIATE 0x00 ++#define CSMI_SAS_LINK_RATE_PHY_DISABLED 0x01 ++ ++// Signal class ++// (bSignalClass in CSMI_SAS_SET_PHY_INFO) ++ ++#define CSMI_SAS_SIGNAL_CLASS_UNKNOWN 0x00 ++#define CSMI_SAS_SIGNAL_CLASS_DIRECT 0x01 ++#define CSMI_SAS_SIGNAL_CLASS_SERVER 0x02 ++#define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE 0x03 ++ ++// Link error reset ++// (bResetCounts) ++ ++#define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS 0x00 ++#define CSMI_SAS_LINK_ERROR_RESET_COUNTS 0x01 ++ ++// Phy identifier ++// (bPhyIdentifier) ++ ++#define CSMI_SAS_USE_PORT_IDENTIFIER 0xFF ++ ++// Port identifier ++// (bPortIdentifier) ++ ++#define CSMI_SAS_IGNORE_PORT 0xFF ++ ++// Programmed link rates ++// (bConnectionRate) ++ ++#define CSMI_SAS_LINK_RATE_NEGOTIATED 0x00 ++#define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08 ++#define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09 ++ ++// Connection status ++// (bConnectionStatus) ++ ++#define CSMI_SAS_OPEN_ACCEPT 0 ++#define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION 1 ++#define CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED 2 ++#define CSMI_SAS_OPEN_REJECT_NO_DESTINATION 3 ++#define CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED 4 ++#define CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED 5 ++#define CSMI_SAS_OPEN_REJECT_RESERVE_ABANDON 6 ++#define CSMI_SAS_OPEN_REJECT_RESERVE_CONTINUE 7 ++#define CSMI_SAS_OPEN_REJECT_RESERVE_INITIALIZE 8 ++#define CSMI_SAS_OPEN_REJECT_RESERVE_STOP 9 ++#define CSMI_SAS_OPEN_REJECT_RETRY 10 ++#define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY 11 ++#define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION 12 ++ ++// SSP Status ++// (bSSPStatus) ++ ++#define CSMI_SAS_SSP_STATUS_UNKNOWN 0x00 ++#define CSMI_SAS_SSP_STATUS_WAITING 0x01 ++#define CSMI_SAS_SSP_STATUS_COMPLETED 0x02 ++#define CSMI_SAS_SSP_STATUS_FATAL_ERROR 0x03 ++#define CSMI_SAS_SSP_STATUS_RETRY 0x04 ++#define CSMI_SAS_SSP_STATUS_NO_TAG 0x05 ++ ++// SSP Flags ++// (uFlags) ++ ++#define CSMI_SAS_SSP_READ 0x00000001 ++#define CSMI_SAS_SSP_WRITE 0x00000002 ++#define CSMI_SAS_SSP_UNSPECIFIED 0x00000004 ++ ++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_SIMPLE 0x00000000 ++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE 0x00000010 ++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED 0x00000020 ++#define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA 0x00000040 ++ ++// SSP Data present ++// (bDataPresent) ++ ++#define CSMI_SAS_SSP_NO_DATA_PRESENT 0x00 ++#define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT 0x01 ++#define CSMI_SAS_SSP_SENSE_DATA_PRESENT 0x02 ++ ++// STP Flags ++// (uFlags) ++ ++#define CSMI_SAS_STP_READ 0x00000001 ++#define CSMI_SAS_STP_WRITE 0x00000002 ++#define CSMI_SAS_STP_UNSPECIFIED 0x00000004 ++#define CSMI_SAS_STP_PIO 0x00000010 ++#define CSMI_SAS_STP_DMA 0x00000020 ++#define CSMI_SAS_STP_PACKET 0x00000040 ++#define CSMI_SAS_STP_DMA_QUEUED 0x00000080 ++#define CSMI_SAS_STP_EXECUTE_DIAG 0x00000100 ++#define CSMI_SAS_STP_RESET_DEVICE 0x00000200 ++ ++// Task Management Flags ++// (uFlags) ++ ++#define CSMI_SAS_TASK_IU 0x00000001 ++#define CSMI_SAS_HARD_RESET_SEQUENCE 0x00000002 ++#define CSMI_SAS_SUPPRESS_RESULT 0x00000004 ++ ++// Task Management Functions ++// (bTaskManagement) ++ ++#define CSMI_SAS_SSP_ABORT_TASK 0x01 ++#define CSMI_SAS_SSP_ABORT_TASK_SET 0x02 ++#define CSMI_SAS_SSP_CLEAR_TASK_SET 0x04 ++#define CSMI_SAS_SSP_LOGICAL_UNIT_RESET 0x08 ++#define CSMI_SAS_SSP_CLEAR_ACA 0x40 ++#define CSMI_SAS_SSP_QUERY_TASK 0x80 ++ ++// Task Management Information ++// (uInformation) ++ ++#define CSMI_SAS_SSP_TEST 1 ++#define CSMI_SAS_SSP_EXCEEDED 2 ++#define CSMI_SAS_SSP_DEMAND 3 ++#define CSMI_SAS_SSP_TRIGGER 4 ++ ++// Connector Pinout Information ++// (uPinout) ++ ++#define CSMI_SAS_CON_UNKNOWN 0x00000001 ++#define CSMI_SAS_CON_SFF_8482 0x00000002 ++#define CSMI_SAS_CON_SFF_8470_LANE_1 0x00000100 ++#define CSMI_SAS_CON_SFF_8470_LANE_2 0x00000200 ++#define CSMI_SAS_CON_SFF_8470_LANE_3 0x00000400 ++#define CSMI_SAS_CON_SFF_8470_LANE_4 0x00000800 ++#define CSMI_SAS_CON_SFF_8484_LANE_1 0x00010000 ++#define CSMI_SAS_CON_SFF_8484_LANE_2 0x00020000 ++#define CSMI_SAS_CON_SFF_8484_LANE_3 0x00040000 ++#define CSMI_SAS_CON_SFF_8484_LANE_4 0x00080000 ++ ++// Connector Location Information ++// (bLocation) ++ ++// same as uPinout above... ++// #define CSMI_SAS_CON_UNKNOWN 0x01 ++#define CSMI_SAS_CON_INTERNAL 0x02 ++#define CSMI_SAS_CON_EXTERNAL 0x04 ++#define CSMI_SAS_CON_SWITCHABLE 0x08 ++#define CSMI_SAS_CON_AUTO 0x10 ++#define CSMI_SAS_CON_NOT_PRESENT 0x20 ++#define CSMI_SAS_CON_NOT_CONNECTED 0x80 ++ ++// Device location identification ++// (bIdentify) ++ ++#define CSMI_SAS_LOCATE_UNKNOWN 0x00 ++#define CSMI_SAS_LOCATE_FORCE_OFF 0x01 ++#define CSMI_SAS_LOCATE_FORCE_ON 0x02 ++ ++// Location Valid flags ++// (uLocationFlags) ++ ++#define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID 0x00000001 ++#define CSMI_SAS_LOCATE_SAS_LUN_VALID 0x00000002 ++#define CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID 0x00000004 ++#define CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID 0x00000008 ++#define CSMI_SAS_LOCATE_BAY_PREFIX_VALID 0x00000010 ++#define CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID 0x00000020 ++#define CSMI_SAS_LOCATE_LOCATION_STATE_VALID 0x00000040 ++ ++/* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */ ++ ++// Return codes for SAS Phy Control IOCTL's ++// (IoctlHeader.ReturnCode) ++ ++// Signature value ++// (IoctlHeader.Signature) ++ ++#define CSMI_PHY_SIGNATURE "CSMIPHY" ++ ++// Phy Control Functions ++// (bFunction) ++ ++// values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL ++// function defined in the SAS spec ++#define CSMI_SAS_PC_NOP 0x00000000 ++#define CSMI_SAS_PC_LINK_RESET 0x00000001 ++#define CSMI_SAS_PC_HARD_RESET 0x00000002 ++#define CSMI_SAS_PC_PHY_DISABLE 0x00000003 ++// 0x04 to 0xFF reserved... ++#define CSMI_SAS_PC_GET_PHY_SETTINGS 0x00000100 ++ ++// Link Flags ++#define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 ++#define CSMI_SAS_PHY_UPDATE_SPINUP_RATE 0x00000002 ++#define CSMI_SAS_PHY_AUTO_COMWAKE 0x00000004 ++ ++// Device Types for Phy Settings ++// (bType) ++#define CSMI_SAS_UNDEFINED 0x00 ++#define CSMI_SAS_SATA 0x01 ++#define CSMI_SAS_SAS 0x02 ++ ++// Transmitter Flags ++// (uTransmitterFlags) ++#define CSMI_SAS_PHY_PREEMPHASIS_DISABLED 0x00000001 ++ ++// Receiver Flags ++// (uReceiverFlags) ++#define CSMI_SAS_PHY_EQUALIZATION_DISABLED 0x00000001 ++ ++// Pattern Flags ++// (uPatternFlags) ++// #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 ++#define CSMI_SAS_PHY_DISABLE_SCRAMBLING 0x00000002 ++#define CSMI_SAS_PHY_DISABLE_ALIGN 0x00000004 ++#define CSMI_SAS_PHY_DISABLE_SSC 0x00000008 ++ ++#define CSMI_SAS_PHY_FIXED_PATTERN 0x00000010 ++#define CSMI_SAS_PHY_USER_PATTERN 0x00000020 ++ ++// Fixed Patterns ++// (bFixedPattern) ++#define CSMI_SAS_PHY_CJPAT 0x00000001 ++#define CSMI_SAS_PHY_ALIGN 0x00000002 ++ ++// Type Flags ++// (bTypeFlags) ++#define CSMI_SAS_PHY_POSITIVE_DISPARITY 0x01 ++#define CSMI_SAS_PHY_NEGATIVE_DISPARITY 0x02 ++#define CSMI_SAS_PHY_CONTROL_CHARACTER 0x04 ++ ++// Miscellaneous ++#define SLOT_NUMBER_UNKNOWN 0xFFFF ++ ++/*************************************************************************/ ++/* DATA STRUCTURES */ ++/*************************************************************************/ ++ ++/* * * * * * * * * * Class Independent Structures * * * * * * * * * */ ++ ++// EDM #pragma CSMI_SAS_BEGIN_PACK(8) ++#pragma pack(8) ++ ++// CC_CSMI_SAS_DRIVER_INFO ++ ++typedef struct _CSMI_SAS_DRIVER_INFO { ++ __u8 szName[81]; ++ __u8 szDescription[81]; ++ __u16 usMajorRevision; ++ __u16 usMinorRevision; ++ __u16 usBuildRevision; ++ __u16 usReleaseRevision; ++ __u16 usCSMIMajorRevision; ++ __u16 usCSMIMinorRevision; ++} CSMI_SAS_DRIVER_INFO, ++ *PCSMI_SAS_DRIVER_INFO; ++ ++typedef struct _CSMI_SAS_DRIVER_INFO_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_DRIVER_INFO Information; ++} CSMI_SAS_DRIVER_INFO_BUFFER, ++ *PCSMI_SAS_DRIVER_INFO_BUFFER; ++ ++// CC_CSMI_SAS_CNTLR_CONFIGURATION ++ ++typedef struct _CSMI_SAS_PCI_BUS_ADDRESS { ++ __u8 bBusNumber; ++ __u8 bDeviceNumber; ++ __u8 bFunctionNumber; ++ __u8 bReserved; ++} CSMI_SAS_PCI_BUS_ADDRESS, ++ *PCSMI_SAS_PCI_BUS_ADDRESS; ++ ++typedef union _CSMI_SAS_IO_BUS_ADDRESS { ++ CSMI_SAS_PCI_BUS_ADDRESS PciAddress; ++ __u8 bReserved[32]; ++} CSMI_SAS_IO_BUS_ADDRESS, ++ *PCSMI_SAS_IO_BUS_ADDRESS; ++ ++typedef struct _CSMI_SAS_CNTLR_CONFIG { ++ __u32 uBaseIoAddress; ++ struct { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } BaseMemoryAddress; ++ __u32 uBoardID; ++ __u16 usSlotNumber; ++ __u8 bControllerClass; ++ __u8 bIoBusType; ++ CSMI_SAS_IO_BUS_ADDRESS BusAddress; ++ __u8 szSerialNumber[81]; ++ __u16 usMajorRevision; ++ __u16 usMinorRevision; ++ __u16 usBuildRevision; ++ __u16 usReleaseRevision; ++ __u16 usBIOSMajorRevision; ++ __u16 usBIOSMinorRevision; ++ __u16 usBIOSBuildRevision; ++ __u16 usBIOSReleaseRevision; ++ __u32 uControllerFlags; ++ __u16 usRromMajorRevision; ++ __u16 usRromMinorRevision; ++ __u16 usRromBuildRevision; ++ __u16 usRromReleaseRevision; ++ __u16 usRromBIOSMajorRevision; ++ __u16 usRromBIOSMinorRevision; ++ __u16 usRromBIOSBuildRevision; ++ __u16 usRromBIOSReleaseRevision; ++ __u8 bReserved[7]; ++} CSMI_SAS_CNTLR_CONFIG, ++ *PCSMI_SAS_CNTLR_CONFIG; ++ ++typedef struct _CSMI_SAS_CNTLR_CONFIG_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_CNTLR_CONFIG Configuration; ++} CSMI_SAS_CNTLR_CONFIG_BUFFER, ++ *PCSMI_SAS_CNTLR_CONFIG_BUFFER; ++ ++// CC_CSMI_SAS_CNTLR_STATUS ++ ++typedef struct _CSMI_SAS_CNTLR_STATUS { ++ __u32 uStatus; ++ __u32 uOfflineReason; ++ __u8 bReserved[28]; ++} CSMI_SAS_CNTLR_STATUS, ++ *PCSMI_SAS_CNTLR_STATUS; ++ ++typedef struct _CSMI_SAS_CNTLR_STATUS_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_CNTLR_STATUS Status; ++} CSMI_SAS_CNTLR_STATUS_BUFFER, ++ *PCSMI_SAS_CNTLR_STATUS_BUFFER; ++ ++// CC_CSMI_SAS_FIRMWARE_DOWNLOAD ++ ++typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD { ++ __u32 uBufferLength; ++ __u32 uDownloadFlags; ++ __u8 bReserved[32]; ++ __u16 usStatus; ++ __u16 usSeverity; ++} CSMI_SAS_FIRMWARE_DOWNLOAD, ++ *PCSMI_SAS_FIRMWARE_DOWNLOAD; ++ ++typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_FIRMWARE_DOWNLOAD Information; ++ __u8 bDataBuffer[1]; ++} CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER, ++ *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER; ++ ++// CC_CSMI_SAS_RAID_INFO ++ ++typedef struct _CSMI_SAS_RAID_INFO { ++ __u32 uNumRaidSets; ++ __u32 uMaxDrivesPerSet; ++ __u32 uMaxRaidSets; ++ __u8 bMaxRaidTypes; ++ __u8 bReservedByteFields[7]; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulMinRaidSetBlocks; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulMaxRaidSetBlocks; ++ __u32 uMaxPhysicalDrives; ++ __u32 uMaxExtents; ++ __u32 uMaxModules; ++ __u32 uMaxTransformationMemory; ++ __u32 uChangeCount; ++ __u8 bReserved[44]; ++} CSMI_SAS_RAID_INFO, ++ *PCSMI_SAS_RAID_INFO; ++ ++typedef struct _CSMI_SAS_RAID_INFO_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_RAID_INFO Information; ++} CSMI_SAS_RAID_INFO_BUFFER, ++ *PCSMI_SAS_RAID_INFO_BUFFER; ++ ++// CC_CSMI_SAS_GET_RAID_CONFIG ++ ++typedef struct _CSMI_SAS_RAID_DRIVES { ++ __u8 bModel[40]; ++ __u8 bFirmware[8]; ++ __u8 bSerialNumber[40]; ++ __u8 bSASAddress[8]; ++ __u8 bSASLun[8]; ++ __u8 bDriveStatus; ++ __u8 bDriveUsage; ++ __u16 usBlockSize; ++ __u8 bDriveType; ++ __u8 bReserved[15]; ++ __u32 uDriveIndex; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulTotalUserBlocks; ++} CSMI_SAS_RAID_DRIVES, ++ *PCSMI_SAS_RAID_DRIVES; ++ ++typedef struct _CSMI_SAS_RAID_DEVICE_ID { ++ __u8 bDeviceIdentificationVPDPage[1]; ++} CSMI_SAS_RAID_DEVICE_ID, ++ *PCSMI_SAS_RAID_DEVICE_ID; ++ ++typedef struct _CSMI_SAS_RAID_SET_ADDITIONAL_DATA { ++ __u8 bLabel[16]; ++ __u8 bRaidSetLun[8]; ++ __u8 bWriteProtection; ++ __u8 bCacheSetting; ++ __u8 bCacheRatio; ++ __u16 usBlockSize; ++ __u8 bReservedBytes[11]; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulRaidSetExtentOffset; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulRaidSetBlocks; ++ __u32 uStripeSizeInBlocks; ++ __u32 uSectorsPerTrack; ++ __u8 bApplicationScratchPad[16]; ++ __u32 uNumberOfHeads; ++ __u32 uNumberOfTracks; ++ __u8 bReserved[24]; ++} CSMI_SAS_RAID_SET_ADDITIONAL_DATA, ++ *PCSMI_SAS_RAID_SET_ADDITIONAL_DATA; ++ ++typedef struct _CSMI_SAS_RAID_CONFIG { ++ __u32 uRaidSetIndex; ++ __u32 uCapacity; ++ __u32 uStripeSize; ++ __u8 bRaidType; ++ __u8 bStatus; ++ __u8 bInformation; ++ __u8 bDriveCount; ++ __u8 bDataType; ++ __u8 bReserved[11]; ++ __u32 uFailureCode; ++ __u32 uChangeCount; ++ union { ++ CSMI_SAS_RAID_DRIVES Drives[1]; ++ CSMI_SAS_RAID_DEVICE_ID DeviceId[1]; ++ CSMI_SAS_RAID_SET_ADDITIONAL_DATA Data[1]; ++ }; ++} CSMI_SAS_RAID_CONFIG, ++ *PCSMI_SAS_RAID_CONFIG; ++ ++typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_RAID_CONFIG Configuration; ++} CSMI_SAS_RAID_CONFIG_BUFFER, ++ *PCSMI_SAS_RAID_CONFIG_BUFFER; ++ ++// CC_CSMI_SAS_GET_RAID_FEATURES ++ ++typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION { ++ __u8 bRaidType; ++ __u8 bReservedBytes[7]; ++ __u32 uSupportedStripeSizeMap; ++ __u8 bReserved[24]; ++} CSMI_SAS_RAID_TYPE_DESCRIPTION, ++ *PCSMI_SAS_RAID_TYPE_DESCRIPTION; ++ ++typedef struct _CSMI_SAS_RAID_FEATURES { ++ __u32 uFeatures; ++ __u8 bReservedFeatures[32]; ++ __u8 bDefaultTransformPriority; ++ __u8 bTransformPriority; ++ __u8 bDefaultRebuildPriority; ++ __u8 bRebuildPriority; ++ __u8 bDefaultSurfaceScanPriority; ++ __u8 bSurfaceScanPriority; ++ __u16 usReserved; ++ __u32 uRaidSetTransformationRules; ++ __u32 uReserved[11]; ++ CSMI_SAS_RAID_TYPE_DESCRIPTION RaidType[24]; ++ __u8 bCacheRatiosSupported[104]; ++ __u32 uChangeCount; ++ __u32 uFailureCode; ++ __u8 bReserved[120]; ++} CSMI_SAS_RAID_FEATURES, ++ *PCSMI_SAS_RAID_FEATURES; ++ ++typedef struct _CSMI_SAS_RAID_FEATURES_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_RAID_FEATURES Information; ++} CSMI_SAS_RAID_FEATURES_BUFFER, ++ *PCSMI_SAS_RAID_FEATURES_BUFFER; ++ ++// CC_CSMI_SAS_SET_RAID_CONTROL ++ ++typedef struct _CSMI_SAS_RAID_CONTROL { ++ __u8 bTransformPriority; ++ __u8 bRebuildPriority; ++ __u8 bCacheRatioFlag; ++ __u8 bCacheRatio; ++ __u8 bSurfaceScanPriority; ++ __u8 bReservedBytes[15]; ++ __u8 bClearConfiguration[8]; ++ __u32 uChangeCount; ++ __u8 bReserved[88]; ++ __u32 uFailureCode; ++ __u8 bFailureDescription[80]; ++} CSMI_SAS_RAID_CONTROL, ++ *PCSMI_SAS_RAID_CONTROL; ++ ++typedef struct _CSMI_SAS_RAID_CONTROL_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_RAID_CONTROL Information; ++} CSMI_SAS_RAID_CONTROL_BUFFER, ++ *PCSMI_SAS_RAID_CONTROL_BUFFER; ++ ++// CC_CSMI_SAS_GET_RAID_ELEMENT ++ ++typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO { ++ __u32 uDriveIndex; ++ __u8 bExtentType; ++ __u8 bReservedBytes[7]; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulExtentOffset; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulExtentBlocks; ++ __u32 uRaidSetIndex; ++ __u8 bReserved[96]; ++} CSMI_SAS_DRIVE_EXTENT_INFO, ++ *PCSMI_SAS_DRIVE_EXTENT_INFO; ++ ++typedef struct _CSMI_SAS_RAID_MODULE_INFO { ++ __u8 bReserved[128]; ++} CSMI_SAS_RAID_MODULE_INFO, ++ *PCSMI_SAS_RAID_MODULE_INFO; ++ ++typedef struct _CSMI_SAS_DRIVE_LOCATION { ++ __u8 bConnector[16]; ++ __u8 bBoxName[16]; ++ __u32 uBay; ++ __u8 bReservedBytes[4]; ++ __u8 bAttachedSASAddress[8]; ++ __u8 bAttachedPhyIdentifier; ++ __u8 bReserved[79]; ++} CSMI_SAS_DRIVE_LOCATION, ++ *PCSMI_SAS_DRIVE_LOCATION; ++ ++typedef struct _CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA { ++ __u8 bNegotiatedLinkRate[2]; ++ __u8 bReserved[126]; ++} CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA, ++ *PCSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA; ++ ++typedef struct _CSMI_SAS_DRIVE_INFO { ++ CSMI_SAS_RAID_DRIVES Device; ++ CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA Data; ++ CSMI_SAS_DRIVE_LOCATION Location; ++ __u8 bReserved[16]; ++} CSMI_SAS_DRIVE_INFO, ++ *PCSMI_SAS_DRIVE_INFO; ++ ++typedef struct _CSMI_SAS_RAID_ELEMENT { ++ __u32 uEnumerationType; ++ __u32 uElementIndex; ++ __u32 uNumElements; ++ __u32 uChangeCount; ++ __u32 uSubElementIndex; ++ __u8 bReserved[32]; ++ __u32 uFailureCode; ++ __u8 bFailureDescription[80]; ++ union { ++ CSMI_SAS_DRIVE_INFO Drive; ++ CSMI_SAS_RAID_MODULE_INFO Module; ++ CSMI_SAS_DRIVE_EXTENT_INFO Extent; ++ } Element; ++} CSMI_SAS_RAID_ELEMENT, ++ *PCSMI_SAS_RAID_ELEMENT; ++ ++typedef struct _CSMI_SAS_RAID_ELEMENT_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_RAID_ELEMENT Information; ++} CSMI_SAS_RAID_ELEMENT_BUFFER, ++ *PCSMI_SAS_RAID_ELEMENT_BUFFER; ++ ++// CC_CSMI_SAS_SET_RAID_OPERATION ++ ++typedef struct _CSMI_SAS_RAID_SET_LIST { ++ __u32 uRaidSetIndex; ++ __u8 bExistingLun[8]; ++ __u8 bNewLun[8]; ++ __u8 bReserved[12]; ++} CSMI_SAS_RAID_SET_LIST, ++ *PCSMI_SAS_RAID_SET_LIST; ++ ++typedef struct _CSMI_SAS_RAID_SET_DRIVE_LIST { ++ __u32 uDriveIndex; ++ __u8 bDriveUsage; ++ __u8 bReserved[27]; ++} CSMI_SAS_RAID_SET_DRIVE_LIST, ++ *PCSMI_SAS_RAID_SET_DRIVE_LIST; ++ ++typedef struct _CSMI_SAS_RAID_SET_SPARE_INFO { ++ __u32 uRaidSetIndex; ++ __u32 uDriveCount; ++ __u8 bApplicationScratchPad[16]; ++ __u8 bReserved[104]; ++} CSMI_SAS_RAID_SET_SPARE_INFO, ++ *PCSMI_SAS_RAID_SET_SPARE_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_ONLINE_STATE_INFO { ++ __u32 uRaidSetIndex; ++ __u8 bOnlineState; ++ __u8 bReserved[123]; ++} CSMI_SAS_RAID_SET_ONLINE_STATE_INFO, ++ *PCSMI_SAS_RAID_SET_ONLINE_STATE_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_CACHE_INFO { ++ __u32 uRaidSetIndex; ++ __u8 bCacheSetting; ++ __u8 bCacheRatioFlag; ++ __u8 bCacheRatio; ++ __u8 bReserved[121]; ++} CSMI_SAS_RAID_SET_CACHE_INFO, ++ *PCSMI_SAS_RAID_SET_CACHE_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO { ++ __u32 uRaidSetIndex; ++ __u8 bWriteProtectSetting; ++ __u8 bReserved[123]; ++} CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO, ++ *PCSMI_SAS_RAID_SET_WRITE_PROTECT_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_DELETE_INFO { ++ __u32 uRaidSetIndex; ++ __u8 bReserved[124]; ++} CSMI_SAS_RAID_SET_DELETE_INFO, ++ *PCSMI_SAS_RAID_SET_DELETE_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_MODIFY_INFO { ++ __u8 bRaidType; ++ __u8 bReservedBytes[7]; ++ __u32 uStripeSize; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulRaidSetBlocks; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulRaidSetExtentOffset; ++ __u32 uDriveCount; ++ __u8 bReserved[96]; ++} CSMI_SAS_RAID_SET_MODIFY_INFO, ++ *PCSMI_SAS_RAID_SET_MODIFY_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_TRANSFORM_INFO { ++ __u8 bTransformType; ++ __u8 bReservedBytes[3]; ++ __u32 uRaidSetIndex; ++ __u8 bRaidType; ++ __u8 bReservedBytes2[11]; ++ __u32 uAdditionalRaidSetIndex; ++ __u32 uRaidSetCount; ++ __u8 bApplicationScratchPad[16]; ++ CSMI_SAS_RAID_SET_MODIFY_INFO Modify; ++ __u8 bReserved[80]; ++} CSMI_SAS_RAID_SET_TRANSFORM_INFO, ++ *PCSMI_SAS_RAID_SET_TRANSFORM_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_LABEL_INFO { ++ __u32 uRaidSetIndex; ++ __u8 bLabel[16]; ++ __u8 bReserved[108]; ++} CSMI_SAS_RAID_SET_LABEL_INFO, ++ *PCSMI_SAS_RAID_SET_LABEL_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_CREATE_INFO { ++ __u8 bRaidType; ++ __u8 bReservedBytes[7]; ++ __u32 uStripeSize; ++ __u32 uTrackSectorCount; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulRaidSetBlocks; ++ struct ++ { ++ __u32 uLowPart; ++ __u32 uHighPart; ++ } ulRaidSetExtentOffset; ++ __u32 uDriveCount; ++ __u8 bLabel[16]; ++ __u32 uRaidSetIndex; ++ __u8 bApplicationScratchPad[16]; ++ __u32 uNumberOfHeads; ++ __u32 uNumberOfTracks; ++ __u8 bReserved[48]; ++} CSMI_SAS_RAID_SET_CREATE_INFO, ++ *PCSMI_SAS_RAID_SET_CREATE_INFO; ++ ++typedef struct _CSMI_SAS_RAID_SET_OPERATION { ++ __u32 uOperationType; ++ __u32 uChangeCount; ++ __u32 uFailureCode; ++ __u8 bFailureDescription[80]; ++ __u8 bReserved[28]; ++ union { ++ CSMI_SAS_RAID_SET_CREATE_INFO Create; ++ CSMI_SAS_RAID_SET_LABEL_INFO Label; ++ CSMI_SAS_RAID_SET_TRANSFORM_INFO Transform; ++ CSMI_SAS_RAID_SET_DELETE_INFO Delete; ++ CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO Protect; ++ CSMI_SAS_RAID_SET_CACHE_INFO Cache; ++ CSMI_SAS_RAID_SET_ONLINE_STATE_INFO State; ++ CSMI_SAS_RAID_SET_SPARE_INFO Spare; ++ } Operation; ++ union { ++ CSMI_SAS_RAID_SET_DRIVE_LIST DriveList[1]; ++ CSMI_SAS_RAID_SET_LIST RaidSetList[1]; ++ } Parameters; ++} CSMI_SAS_RAID_SET_OPERATION, ++ *PCSMI_SAS_RAID_SET_OPERATION; ++ ++typedef struct _CSMI_SAS_RAID_SET_OPERATION_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_RAID_SET_OPERATION Information; ++} CSMI_SAS_RAID_SET_OPERATION_BUFFER, ++ *PCSMI_SAS_RAID_SET_OPERATION_BUFFER; ++ ++/* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */ ++ ++// CC_CSMI_SAS_GET_PHY_INFO ++ ++typedef struct _CSMI_SAS_IDENTIFY { ++ __u8 bDeviceType; ++ __u8 bRestricted; ++ __u8 bInitiatorPortProtocol; ++ __u8 bTargetPortProtocol; ++ __u8 bRestricted2[8]; ++ __u8 bSASAddress[8]; ++ __u8 bPhyIdentifier; ++ __u8 bSignalClass; ++ __u8 bReserved[6]; ++} CSMI_SAS_IDENTIFY, ++ *PCSMI_SAS_IDENTIFY; ++ ++typedef struct _CSMI_SAS_PHY_ENTITY { ++ CSMI_SAS_IDENTIFY Identify; ++ __u8 bPortIdentifier; ++ __u8 bNegotiatedLinkRate; ++ __u8 bMinimumLinkRate; ++ __u8 bMaximumLinkRate; ++ __u8 bPhyChangeCount; ++ __u8 bAutoDiscover; ++ __u8 bPhyFeatures; ++ __u8 bReserved; ++ CSMI_SAS_IDENTIFY Attached; ++} CSMI_SAS_PHY_ENTITY, ++ *PCSMI_SAS_PHY_ENTITY; ++ ++typedef struct _CSMI_SAS_PHY_INFO { ++ __u8 bNumberOfPhys; ++ __u8 bReserved[3]; ++ CSMI_SAS_PHY_ENTITY Phy[32]; ++} CSMI_SAS_PHY_INFO, ++ *PCSMI_SAS_PHY_INFO; ++ ++typedef struct _CSMI_SAS_PHY_INFO_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_PHY_INFO Information; ++} CSMI_SAS_PHY_INFO_BUFFER, ++ *PCSMI_SAS_PHY_INFO_BUFFER; ++ ++// CC_CSMI_SAS_SET_PHY_INFO ++ ++typedef struct _CSMI_SAS_SET_PHY_INFO { ++ __u8 bPhyIdentifier; ++ __u8 bNegotiatedLinkRate; ++ __u8 bProgrammedMinimumLinkRate; ++ __u8 bProgrammedMaximumLinkRate; ++ __u8 bSignalClass; ++ __u8 bReserved[3]; ++} CSMI_SAS_SET_PHY_INFO, ++ *PCSMI_SAS_SET_PHY_INFO; ++ ++typedef struct _CSMI_SAS_SET_PHY_INFO_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_SET_PHY_INFO Information; ++} CSMI_SAS_SET_PHY_INFO_BUFFER, ++ *PCSMI_SAS_SET_PHY_INFO_BUFFER; ++ ++// CC_CSMI_SAS_GET_LINK_ERRORS ++ ++typedef struct _CSMI_SAS_LINK_ERRORS { ++ __u8 bPhyIdentifier; ++ __u8 bResetCounts; ++ __u8 bReserved[2]; ++ __u32 uInvalidDwordCount; ++ __u32 uRunningDisparityErrorCount; ++ __u32 uLossOfDwordSyncCount; ++ __u32 uPhyResetProblemCount; ++} CSMI_SAS_LINK_ERRORS, ++ *PCSMI_SAS_LINK_ERRORS; ++ ++typedef struct _CSMI_SAS_LINK_ERRORS_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_LINK_ERRORS Information; ++} CSMI_SAS_LINK_ERRORS_BUFFER, ++ *PCSMI_SAS_LINK_ERRORS_BUFFER; ++ ++// CC_CSMI_SAS_SMP_PASSTHRU ++ ++typedef struct _CSMI_SAS_SMP_REQUEST { ++ __u8 bFrameType; ++ __u8 bFunction; ++ __u8 bReserved[2]; ++ __u8 bAdditionalRequestBytes[1016]; ++} CSMI_SAS_SMP_REQUEST, ++ *PCSMI_SAS_SMP_REQUEST; ++ ++typedef struct _CSMI_SAS_SMP_RESPONSE { ++ __u8 bFrameType; ++ __u8 bFunction; ++ __u8 bFunctionResult; ++ __u8 bReserved; ++ __u8 bAdditionalResponseBytes[1016]; ++} CSMI_SAS_SMP_RESPONSE, ++ *PCSMI_SAS_SMP_RESPONSE; ++ ++typedef struct _CSMI_SAS_SMP_PASSTHRU { ++ __u8 bPhyIdentifier; ++ __u8 bPortIdentifier; ++ __u8 bConnectionRate; ++ __u8 bReserved; ++ __u8 bDestinationSASAddress[8]; ++ __u32 uRequestLength; ++ CSMI_SAS_SMP_REQUEST Request; ++ __u8 bConnectionStatus; ++ __u8 bReserved2[3]; ++ __u32 uResponseBytes; ++ CSMI_SAS_SMP_RESPONSE Response; ++} CSMI_SAS_SMP_PASSTHRU, ++ *PCSMI_SAS_SMP_PASSTHRU; ++ ++typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_SMP_PASSTHRU Parameters; ++} CSMI_SAS_SMP_PASSTHRU_BUFFER, ++ *PCSMI_SAS_SMP_PASSTHRU_BUFFER; ++ ++// CC_CSMI_SAS_SSP_PASSTHRU ++ ++typedef struct _CSMI_SAS_SSP_PASSTHRU { ++ __u8 bPhyIdentifier; ++ __u8 bPortIdentifier; ++ __u8 bConnectionRate; ++ __u8 bReserved; ++ __u8 bDestinationSASAddress[8]; ++ __u8 bLun[8]; ++ __u8 bCDBLength; ++ __u8 bAdditionalCDBLength; ++ __u8 bReserved2[2]; ++ __u8 bCDB[16]; ++ __u32 uFlags; ++ __u8 bAdditionalCDB[24]; ++ __u32 uDataLength; ++} CSMI_SAS_SSP_PASSTHRU, ++ *PCSMI_SAS_SSP_PASSTHRU; ++ ++typedef struct _CSMI_SAS_SSP_PASSTHRU_STATUS { ++ __u8 bConnectionStatus; ++ __u8 bSSPStatus; ++ __u8 bReserved[2]; ++ __u8 bDataPresent; ++ __u8 bStatus; ++ __u8 bResponseLength[2]; ++ __u8 bResponse[256]; ++ __u32 uDataBytes; ++} CSMI_SAS_SSP_PASSTHRU_STATUS, ++ *PCSMI_SAS_SSP_PASSTHRU_STATUS; ++ ++typedef struct _CSMI_SAS_SSP_PASSTHRU_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_SSP_PASSTHRU Parameters; ++ CSMI_SAS_SSP_PASSTHRU_STATUS Status; ++ __u8 bDataBuffer[1]; ++} CSMI_SAS_SSP_PASSTHRU_BUFFER, ++ *PCSMI_SAS_SSP_PASSTHRU_BUFFER; ++ ++// CC_CSMI_SAS_STP_PASSTHRU ++ ++typedef struct _CSMI_SAS_STP_PASSTHRU { ++ __u8 bPhyIdentifier; ++ __u8 bPortIdentifier; ++ __u8 bConnectionRate; ++ __u8 bReserved; ++ __u8 bDestinationSASAddress[8]; ++ __u8 bReserved2[4]; ++ __u8 bCommandFIS[20]; ++ __u32 uFlags; ++ __u32 uDataLength; ++} CSMI_SAS_STP_PASSTHRU, ++ *PCSMI_SAS_STP_PASSTHRU; ++ ++typedef struct _CSMI_SAS_STP_PASSTHRU_STATUS { ++ __u8 bConnectionStatus; ++ __u8 bReserved[3]; ++ __u8 bStatusFIS[20]; ++ __u32 uSCR[16]; ++ __u32 uDataBytes; ++} CSMI_SAS_STP_PASSTHRU_STATUS, ++ *PCSMI_SAS_STP_PASSTHRU_STATUS; ++ ++typedef struct _CSMI_SAS_STP_PASSTHRU_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_STP_PASSTHRU Parameters; ++ CSMI_SAS_STP_PASSTHRU_STATUS Status; ++ __u8 bDataBuffer[1]; ++} CSMI_SAS_STP_PASSTHRU_BUFFER, ++ *PCSMI_SAS_STP_PASSTHRU_BUFFER; ++ ++// CC_CSMI_SAS_GET_SATA_SIGNATURE ++ ++typedef struct _CSMI_SAS_SATA_SIGNATURE { ++ __u8 bPhyIdentifier; ++ __u8 bReserved[3]; ++ __u8 bSignatureFIS[20]; ++} CSMI_SAS_SATA_SIGNATURE, ++ *PCSMI_SAS_SATA_SIGNATURE; ++ ++typedef struct _CSMI_SAS_SATA_SIGNATURE_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_SATA_SIGNATURE Signature; ++} CSMI_SAS_SATA_SIGNATURE_BUFFER, ++ *PCSMI_SAS_SATA_SIGNATURE_BUFFER; ++ ++// CC_CSMI_SAS_GET_SCSI_ADDRESS ++ ++typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ __u8 bSASAddress[8]; ++ __u8 bSASLun[8]; ++ __u8 bHostIndex; ++ __u8 bPathId; ++ __u8 bTargetId; ++ __u8 bLun; ++} CSMI_SAS_GET_SCSI_ADDRESS_BUFFER, ++ *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER; ++ ++// CC_CSMI_SAS_GET_DEVICE_ADDRESS ++ ++typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ __u8 bHostIndex; ++ __u8 bPathId; ++ __u8 bTargetId; ++ __u8 bLun; ++ __u8 bSASAddress[8]; ++ __u8 bSASLun[8]; ++} CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER, ++ *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER; ++ ++// CC_CSMI_SAS_TASK_MANAGEMENT ++ ++typedef struct _CSMI_SAS_SSP_TASK_IU { ++ __u8 bHostIndex; ++ __u8 bPathId; ++ __u8 bTargetId; ++ __u8 bLun; ++ __u32 uFlags; ++ __u32 uQueueTag; ++ __u32 uReserved; ++ __u8 bTaskManagementFunction; ++ __u8 bReserved[7]; ++ __u32 uInformation; ++} CSMI_SAS_SSP_TASK_IU, ++ *PCSMI_SAS_SSP_TASK_IU; ++ ++typedef struct _CSMI_SAS_SSP_TASK_IU_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_SSP_TASK_IU Parameters; ++ CSMI_SAS_SSP_PASSTHRU_STATUS Status; ++} CSMI_SAS_SSP_TASK_IU_BUFFER, ++ *PCSMI_SAS_SSP_TASK_IU_BUFFER; ++ ++// CC_CSMI_SAS_GET_CONNECTOR_INFO ++ ++typedef struct _CSMI_SAS_GET_CONNECTOR_INFO { ++ __u32 uPinout; ++ __u8 bConnector[16]; ++ __u8 bLocation; ++ __u8 bReserved[15]; ++} CSMI_SAS_CONNECTOR_INFO, ++ *PCSMI_SAS_CONNECTOR_INFO; ++ ++typedef struct _CSMI_SAS_CONNECTOR_INFO_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ CSMI_SAS_CONNECTOR_INFO Reference[32]; ++} CSMI_SAS_CONNECTOR_INFO_BUFFER, ++ *PCSMI_SAS_CONNECTOR_INFO_BUFFER; ++ ++// CC_CSMI_SAS_GET_LOCATION ++ ++typedef struct _CSMI_SAS_LOCATION_IDENTIFIER { ++ __u32 bLocationFlags; ++ __u8 bSASAddress[8]; ++ __u8 bSASLun[8]; ++ __u8 bEnclosureIdentifier[8]; ++ __u8 bEnclosureName[32]; ++ __u8 bBayPrefix[32]; ++ __u8 bBayIdentifier; ++ __u8 bLocationState; ++ __u8 bReserved[2]; ++} CSMI_SAS_LOCATION_IDENTIFIER, ++ *PCSMI_SAS_LOCATION_IDENTIFIER; ++ ++typedef struct _CSMI_SAS_GET_LOCATION_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ __u8 bHostIndex; ++ __u8 bPathId; ++ __u8 bTargetId; ++ __u8 bLun; ++ __u8 bIdentify; ++ __u8 bNumberOfLocationIdentifiers; ++ __u8 bLengthOfLocationIdentifier; ++ CSMI_SAS_LOCATION_IDENTIFIER Location[1]; ++} CSMI_SAS_GET_LOCATION_BUFFER, ++ *PCSMI_SAS_GET_LOCATION_BUFFER; ++ ++// CC_CSMI_SAS_PHY_CONTROL ++ ++typedef struct _CSMI_SAS_CHARACTER { ++ __u8 bTypeFlags; ++ __u8 bValue; ++} CSMI_SAS_CHARACTER, ++ *PCSMI_SAS_CHARACTER; ++ ++typedef struct _CSMI_SAS_PHY_CONTROL { ++ __u8 bType; ++ __u8 bRate; ++ __u8 bReserved[6]; ++ __u32 uVendorUnique[8]; ++ __u32 uTransmitterFlags; ++ __i8 bTransmitAmplitude; ++ __i8 bTransmitterPreemphasis; ++ __i8 bTransmitterSlewRate; ++ __i8 bTransmitterReserved[13]; ++ __u8 bTransmitterVendorUnique[64]; ++ __u32 uReceiverFlags; ++ __i8 bReceiverThreshold; ++ __i8 bReceiverEqualizationGain; ++ __i8 bReceiverReserved[14]; ++ __u8 bReceiverVendorUnique[64]; ++ __u32 uPatternFlags; ++ __u8 bFixedPattern; ++ __u8 bUserPatternLength; ++ __u8 bPatternReserved[6]; ++ CSMI_SAS_CHARACTER UserPatternBuffer[16]; ++} CSMI_SAS_PHY_CONTROL, ++ *PCSMI_SAS_PHY_CONTROL; ++ ++typedef struct _CSMI_SAS_PHY_CONTROL_BUFFER { ++ IOCTL_HEADER IoctlHeader; ++ __u32 uFunction; ++ __u8 bPhyIdentifier; ++ __u16 usLengthOfControl; ++ __u8 bNumberOfControls; ++ __u8 bReserved[4]; ++ __u32 uLinkFlags; ++ __u8 bSpinupRate; ++ __u8 bLinkReserved[7]; ++ __u32 uVendorUnique[8]; ++ CSMI_SAS_PHY_CONTROL Control[1]; ++} CSMI_SAS_PHY_CONTROL_BUFFER, ++ *PCSMI_SAS_PHY_CONTROL_BUFFER; ++ ++//EDM #pragma CSMI_SAS_END_PACK ++#pragma pack() ++ ++#endif // _CSMI_SAS_H_ +--- a/drivers/message/fusion/Kconfig ++++ b/drivers/message/fusion/Kconfig +@@ -61,13 +61,25 @@ config FUSION_SAS + LSISAS1078 + + config FUSION_MAX_SGE +- int "Maximum number of scatter gather entries (16 - 128)" ++ int "Maximum number of scatter gather entries for SAS and SPI (16 - 128)" + default "128" + range 16 128 + help + This option allows you to specify the maximum number of scatter- + gather entries per I/O. The driver default is 128, which matches +- SCSI_MAX_PHYS_SEGMENTS. However, it may decreased down to 16. ++ SAFE_PHYS_SEGMENTS. However, it may decreased down to 16. ++ Decreasing this parameter will reduce memory requirements ++ on a per controller instance. ++ ++config FUSION_MAX_FC_SGE ++ int "Maximum number of scatter gather entries for FC (16 - 256)" ++ depends on FUSION_FC ++ default "256" ++ range 16 256 ++ help ++ This option allows you to specify the maximum number of scatter- ++ gather entries per I/O. The driver default is 256, which matches ++ MAX_PHYS_SEGMENTS. However, it may decreased down to 16. + Decreasing this parameter will reduce memory requirements + on a per controller instance. + +--- a/drivers/message/fusion/lsi/mpi_cnfg.h ++++ b/drivers/message/fusion/lsi/mpi_cnfg.h +@@ -6,7 +6,7 @@ + * Title: MPI Config message, structures, and Pages + * Creation Date: July 27, 2000 + * +- * mpi_cnfg.h Version: 01.05.15 ++ * mpi_cnfg.h Version: 01.05.18 + * + * Version History + * --------------- +@@ -308,6 +308,20 @@ + * Expander Page 0 Flags field. + * Fixed define for + * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED. ++ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT ++ * define. ++ * Added BIOS Page 4 structure. ++ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID ++ * Physcial Disk Page 1. ++ * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of ++ * Manufacturing Page 4. ++ * Added Solid State Drives Supported bit to IOC Page 6 ++ * Capabilities Flags. ++ * Added new value for AccessStatus field of SAS Device ++ * Page 0 (_SATA_NEEDS_INITIALIZATION). ++ * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field ++ * to control coercion size and the mixing of SAS and SATA ++ * SSD drives. + * -------------------------------------------------------------------------- + */ + +@@ -686,6 +700,14 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN + #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) + + /* defines for the ExtFlags field */ ++#define MPI_MANPAGE4_EXTFLAGS_MASK_COERCION_SIZE (0x0180) ++#define MPI_MANPAGE4_EXTFLAGS_SHIFT_COERCION_SIZE (7) ++#define MPI_MANPAGE4_EXTFLAGS_1GB_COERCION_SIZE (0) ++#define MPI_MANPAGE4_EXTFLAGS_128MB_COERCION_SIZE (1) ++ ++#define MPI_MANPAGE4_EXTFLAGS_NO_MIX_SSD_SAS_SATA (0x0040) ++#define MPI_MANPAGE4_EXTFLAGS_MIX_SSD_AND_NON_SSD (0x0020) ++#define MPI_MANPAGE4_EXTFLAGS_DUAL_PORT_SUPPORT (0x0010) + #define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008) + #define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004) + #define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002) +@@ -1159,6 +1181,8 @@ typedef struct _CONFIG_PAGE_IOC_6 + + /* IOC Page 6 Capabilities Flags */ + ++#define MPI_IOCPAGE6_CAP_FLAGS_SSD_SUPPORT (0x00000020) ++#define MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT (0x00000010) + #define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008) + + #define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006) +@@ -1428,6 +1452,15 @@ typedef struct _CONFIG_PAGE_BIOS_2 + #define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05) + #define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) + ++typedef struct _CONFIG_PAGE_BIOS_4 ++{ ++ CONFIG_PAGE_HEADER Header; /* 00h */ ++ U64 ReassignmentBaseWWID; /* 04h */ ++} CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4, ++ BIOSPage4_t, MPI_POINTER pBIOSPage4_t; ++ ++#define MPI_BIOSPAGE4_PAGEVERSION (0x00) ++ + + /**************************************************************************** + * SCSI Port Config Pages +@@ -2419,6 +2452,15 @@ typedef struct _RAID_PHYS_DISK1_PATH + #define MPI_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) + #define MPI_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + ++ ++/* ++ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to ++ * one and check Header.PageLength or NumPhysDiskPaths at runtime. ++ */ ++#ifndef MPI_RAID_PHYS_DISK1_PATH_MAX ++#define MPI_RAID_PHYS_DISK1_PATH_MAX (1) ++#endif ++ + typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1 + { + CONFIG_PAGE_HEADER Header; /* 00h */ +@@ -2426,7 +2468,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DI + U8 PhysDiskNum; /* 05h */ + U16 Reserved2; /* 06h */ + U32 Reserved1; /* 08h */ +- RAID_PHYS_DISK1_PATH Path[1]; /* 0Ch */ ++ RAID_PHYS_DISK1_PATH Path[MPI_RAID_PHYS_DISK1_PATH_MAX];/* 0Ch */ + } CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1, + RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t; + +@@ -2844,6 +2886,7 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0 + #define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) + #define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) + #define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) ++#define MPI_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) + /* specific values for SATA Init failures */ + #define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) + #define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) +--- a/drivers/message/fusion/lsi/mpi_fc.h ++++ b/drivers/message/fusion/lsi/mpi_fc.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000-2004 LSI Corporation. ++ * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi_fc.h +--- a/drivers/message/fusion/lsi/mpi.h ++++ b/drivers/message/fusion/lsi/mpi.h +@@ -6,7 +6,7 @@ + * Title: MPI Message independent structures and definitions + * Creation Date: July 27, 2000 + * +- * mpi.h Version: 01.05.13 ++ * mpi.h Version: 01.05.16 + * + * Version History + * --------------- +@@ -79,6 +79,9 @@ + * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. + * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. + * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT. ++ * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT. ++ * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT. ++ * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT. + * -------------------------------------------------------------------------- + */ + +@@ -109,7 +112,7 @@ + /* Note: The major versions of 0xe0 through 0xff are reserved */ + + /* versioning for this MPI header set */ +-#define MPI_HEADER_VERSION_UNIT (0x10) ++#define MPI_HEADER_VERSION_UNIT (0x13) + #define MPI_HEADER_VERSION_DEV (0x00) + #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) + #define MPI_HEADER_VERSION_UNIT_SHIFT (8) +--- a/drivers/message/fusion/lsi/mpi_history.txt ++++ b/drivers/message/fusion/lsi/mpi_history.txt +@@ -3,28 +3,28 @@ + MPI Header File Change History + ============================== + +- Copyright (c) 2000-2007 LSI Corporation. ++ Copyright (c) 2000-2008 LSI Corporation. + + --------------------------------------- +- Header Set Release Version: 01.05.16 +- Header Set Release Date: 05-24-07 ++ Header Set Release Version: 01.05.19 ++ Header Set Release Date: 03-28-08 + --------------------------------------- + + Filename Current version Prior version + ---------- --------------- ------------- +- mpi.h 01.05.13 01.05.12 +- mpi_ioc.h 01.05.14 01.05.13 +- mpi_cnfg.h 01.05.15 01.05.14 ++ mpi.h 01.05.16 01.05.15 ++ mpi_ioc.h 01.05.16 01.05.15 ++ mpi_cnfg.h 01.05.18 01.05.17 + mpi_init.h 01.05.09 01.05.09 + mpi_targ.h 01.05.06 01.05.06 + mpi_fc.h 01.05.01 01.05.01 + mpi_lan.h 01.05.01 01.05.01 +- mpi_raid.h 01.05.03 01.05.03 ++ mpi_raid.h 01.05.05 01.05.05 + mpi_tool.h 01.05.03 01.05.03 + mpi_inb.h 01.05.01 01.05.01 +- mpi_sas.h 01.05.04 01.05.04 ++ mpi_sas.h 01.05.05 01.05.05 + mpi_type.h 01.05.02 01.05.02 +- mpi_history.txt 01.05.14 01.05.14 ++ mpi_history.txt 01.05.19 01.05.18 + + + * Date Version Description +@@ -96,6 +96,9 @@ mpi.h + * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. + * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. + * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT. ++ * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT. ++ * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT. ++ * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT. + * -------------------------------------------------------------------------- + + mpi_ioc.h +@@ -127,7 +130,7 @@ mpi_ioc.h + * 08-08-01 01.02.01 Original release for v1.2 work. + * New format for FWVersion and ProductId in + * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER. +- * 08-31-01 01.02.02 Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and ++ * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and + * related structure and defines. + * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED. + * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE. +@@ -187,7 +190,7 @@ mpi_ioc.h + * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. + * Added MaxInitiators field to PortFacts reply. + * Added SAS Device Status Change ReasonCode for +- * asynchronous notification. ++ * asynchronous notificaiton. + * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event + * data structure. + * Added new ImageType values for FWDownload and FWUpload +@@ -199,6 +202,16 @@ mpi_ioc.h + * added _MULTI_PORT_DOMAIN. + * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. + * Added Common Boot Block type to FWUpload Request. ++ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. ++ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and ++ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. ++ * Added SASAddress field to SAS Initiator Device Table ++ * Overflow event data structure. ++ * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status ++ * Change Event data to indicate completion of internally ++ * generated task management. ++ * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. ++ * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. + * -------------------------------------------------------------------------- + + mpi_cnfg.h +@@ -213,7 +226,7 @@ mpi_cnfg.h + * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 + * page and updated the page version. + * Added Information field and _INFO_PARAMS_NEGOTIATED +- * definition to SCSI_DEVICE_0 page. ++ * definitionto SCSI_DEVICE_0 page. + * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the + * page version. + * Added BucketsRemaining to LAN_1 page, redefined the +@@ -496,6 +509,20 @@ mpi_cnfg.h + * Expander Page 0 Flags field. + * Fixed define for + * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED. ++ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT ++ * define. ++ * Added BIOS Page 4 structure. ++ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID ++ * Physcial Disk Page 1. ++ * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of ++ * Manufacturing Page 4. ++ * Added Solid State Drives Supported bit to IOC Page 6 ++ * Capabilities Flags. ++ * Added new value for AccessStatus field of SAS Device ++ * Page 0 (_SATA_NEEDS_INITIALIZATION). ++ * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field ++ * to control coercion size and the mixing of SAS and SATA ++ * SSD drives. + * -------------------------------------------------------------------------- + + mpi_init.h +@@ -661,6 +688,9 @@ mpi_raid.h + * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. + * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and + * associated defines. ++ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord ++ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME. ++ * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME. + * -------------------------------------------------------------------------- + + mpi_tool.h +@@ -694,6 +724,10 @@ mpi_sas.h + * reply. + * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO + * Unit Control request. ++ * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER, ++ * including adding IOCParameter and IOCParameter value ++ * fields to SAS IO Unit Control Request. ++ * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define. + * -------------------------------------------------------------------------- + + mpi_type.h +@@ -709,20 +743,20 @@ mpi_type.h + + mpi_history.txt Parts list history + +-Filename 01.05.15 01.05.15 +----------- -------- -------- +-mpi.h 01.05.12 01.05.13 +-mpi_ioc.h 01.05.13 01.05.14 +-mpi_cnfg.h 01.05.14 01.05.15 +-mpi_init.h 01.05.09 01.05.09 +-mpi_targ.h 01.05.06 01.05.06 +-mpi_fc.h 01.05.01 01.05.01 +-mpi_lan.h 01.05.01 01.05.01 +-mpi_raid.h 01.05.03 01.05.03 +-mpi_tool.h 01.05.03 01.05.03 +-mpi_inb.h 01.05.01 01.05.01 +-mpi_sas.h 01.05.04 01.05.04 +-mpi_type.h 01.05.02 01.05.02 ++Filename 01.05.19 01.05.18 01.05.17 01.05.16 01.05.15 ++---------- -------- -------- -------- -------- -------- ++mpi.h 01.05.16 01.05.15 01.05.14 01.05.13 01.05.12 ++mpi_ioc.h 01.05.16 01.05.15 01.05.15 01.05.14 01.05.13 ++mpi_cnfg.h 01.05.18 01.05.17 01.05.16 01.05.15 01.05.14 ++mpi_init.h 01.05.09 01.05.09 01.05.09 01.05.09 01.05.09 ++mpi_targ.h 01.05.06 01.05.06 01.05.06 01.05.06 01.05.06 ++mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 ++mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 ++mpi_raid.h 01.05.05 01.05.05 01.05.04 01.05.03 01.05.03 ++mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 ++mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 ++mpi_sas.h 01.05.05 01.05.05 01.05.04 01.05.04 01.05.04 ++mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 + + Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 + ---------- -------- -------- -------- -------- -------- -------- +--- a/drivers/message/fusion/lsi/mpi_init.h ++++ b/drivers/message/fusion/lsi/mpi_init.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000-2007 LSI Corporation. ++ * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi_init.h +--- a/drivers/message/fusion/lsi/mpi_ioc.h ++++ b/drivers/message/fusion/lsi/mpi_ioc.h +@@ -1,12 +1,12 @@ + /* +- * Copyright (c) 2000-2007 LSI Corporation. ++ * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi_ioc.h + * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages + * Creation Date: August 11, 2000 + * +- * mpi_ioc.h Version: 01.05.14 ++ * mpi_ioc.h Version: 01.05.16 + * + * Version History + * --------------- +@@ -113,6 +113,16 @@ + * added _MULTI_PORT_DOMAIN. + * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. + * Added Common Boot Block type to FWUpload Request. ++ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. ++ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and ++ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. ++ * Added SASAddress field to SAS Initiator Device Table ++ * Overflow event data structure. ++ * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status ++ * Change Event data to indicate completion of internally ++ * generated task management. ++ * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. ++ * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. + * -------------------------------------------------------------------------- + */ + +@@ -612,6 +622,8 @@ typedef struct _EVENT_DATA_SAS_DEVICE_ST + #define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) + #define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) + #define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) ++#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET (0x0E) ++#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL (0x0F) + + + /* SCSI Event data for Queue Full event */ +@@ -708,6 +720,8 @@ typedef struct _MPI_EVENT_DATA_IR2 + #define MPI_EVENT_IR2_RC_PD_REMOVED (0x05) + #define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED (0x06) + #define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR (0x07) ++#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED (0x08) ++#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED (0x09) + + /* defines for logical disk states */ + #define MPI_LD_STATE_OPTIMAL (0x00) +@@ -867,6 +881,7 @@ typedef struct _EVENT_DATA_DISCOVERY_ERR + #define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800) + #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) + #define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000) ++#define MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE (0x00004000) + + /* SAS SMP Error Event data */ + +@@ -902,6 +917,8 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_ + + /* defines for the ReasonCode field of the SAS Initiator Device Status Change event */ + #define MPI_EVENT_SAS_INIT_RC_ADDED (0x01) ++#define MPI_EVENT_SAS_INIT_RC_REMOVED (0x02) ++#define MPI_EVENT_SAS_INIT_RC_INACCESSIBLE (0x03) + + /* SAS Initiator Device Table Overflow Event data */ + +@@ -910,6 +927,7 @@ typedef struct _EVENT_DATA_SAS_INIT_TABL + U8 MaxInit; /* 00h */ + U8 CurrentInit; /* 01h */ + U16 Reserved1; /* 02h */ ++ U64 SASAddress; /* 04h */ + } EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MpiEventDataSasInitTableOverflow_t, +--- a/drivers/message/fusion/lsi/mpi_lan.h ++++ b/drivers/message/fusion/lsi/mpi_lan.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000-2004 LSI Corporation. ++ * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi_lan.h +--- a/drivers/message/fusion/lsi/mpi_log_fc.h ++++ b/drivers/message/fusion/lsi/mpi_log_fc.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000-2001 LSI Corporation. All rights reserved. ++ * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. + * + * NAME: fc_log.h + * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips +--- a/drivers/message/fusion/lsi/mpi_log_sas.h ++++ b/drivers/message/fusion/lsi/mpi_log_sas.h +@@ -1,6 +1,6 @@ + /*************************************************************************** + * * +- * Copyright 2003 LSI Corporation. All rights reserved. * ++ * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. * + * * + * Description * + * ------------ * +@@ -73,6 +73,8 @@ + #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004) + #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005) + ++#define IOP_LOGINFO_CODE_LOG_TIMESTAMP_EVENT (0x00080000) ++ + /****************************************************************************/ + /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */ + /****************************************************************************/ +@@ -92,7 +94,7 @@ + #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C) + #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D) + #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E) +-#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011) ++#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST (0x00000011) + #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012) + #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013) + #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014) +@@ -162,7 +164,7 @@ + #define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */ + /* Bit 0 is Status Bit 0: FrameXferErr */ + /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */ +- /* Bit 3 is Status Bit 18 WriteDataLengthGTDataLengthErr */ ++ /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */ + + #define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) + #define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) +@@ -177,6 +179,10 @@ + #define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01) + #define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00) + #define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000) ++#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000) /* not currently used in mainline */ ++#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK (0x00003000) ++#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP (0x00004000) ++#define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000) + + #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ + #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ +@@ -243,6 +249,8 @@ + #define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014) + /* Activation failed trying to import the volume */ + #define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015) ++/* Activation failed trying to import the volume */ ++#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_PHYS_DISKS (0x00010016) + + /* Phys Disk failed, too many phys disks */ + #define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020) +@@ -285,6 +293,23 @@ + /* Compatibility Error : IME size limited to < 2TB */ + #define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D) + ++/* Device Firmware Update: DFU can only be started once */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DFU_IN_PROGRESS (0x00010050) ++/* Device Firmware Update: Volume must be Optimal/Active/non-Quiesced */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DEVICE_IN_INVALID_STATE (0x00010051) ++/* Device Firmware Update: DFU Timeout cannot be zero */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_INVALID_TIMEOUT (0x00010052) ++/* Device Firmware Update: CREATE TIMER FAILED */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_NO_TIMERS (0x00010053) ++/* Device Firmware Update: Failed to read SAS_IO_UNIT_PG_1 */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_READING_CFG_PAGE (0x00010054) ++/* Device Firmware Update: Invalid SAS_IO_UNIT_PG_1 value(s) */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_PORT_IO_TIMEOUTS_REQUIRED (0x00010055) ++/* Device Firmware Update: Unable to allocate memory for page */ ++#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE (0x00010056) ++/* Device Firmware Update: */ ++//#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ (0x00010054) ++ + + /****************************************************************************/ + /* Defines for convenience */ +--- a/drivers/message/fusion/lsi/mpi_raid.h ++++ b/drivers/message/fusion/lsi/mpi_raid.h +@@ -1,12 +1,12 @@ + /* +- * Copyright (c) 2001-2007 LSI Corporation. ++ * Copyright (c) 2001-2008 LSI Corporation. + * + * + * Name: mpi_raid.h + * Title: MPI RAID message and structures + * Creation Date: February 27, 2001 + * +- * mpi_raid.h Version: 01.05.03 ++ * mpi_raid.h Version: 01.05.05 + * + * Version History + * --------------- +@@ -34,6 +34,9 @@ + * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. + * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and + * associated defines. ++ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord ++ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME. ++ * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME. + * -------------------------------------------------------------------------- + */ + +@@ -93,6 +96,7 @@ typedef struct _MSG_RAID_ACTION + #define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13) + #define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14) + #define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) ++#define MPI_RAID_ACTION_SET_VOLUME_NAME (0x16) + + /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */ + #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001) +@@ -105,6 +109,9 @@ typedef struct _MSG_RAID_ACTION + #define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) + #define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002) + ++/* ActionDataWord defines for use with MPI_RAID_ACTION_DISABLE_VOLUME action */ ++#define MPI_RAID_ACTION_ADATA_DISABLE_FULL_REBUILD (0x00000001) ++ + /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */ + #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001) + +--- a/drivers/message/fusion/lsi/mpi_sas.h ++++ b/drivers/message/fusion/lsi/mpi_sas.h +@@ -1,12 +1,12 @@ + /* +- * Copyright (c) 2004-2006 LSI Corporation. ++ * Copyright (c) 2004-2008 LSI Corporation. + * + * + * Name: mpi_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: August 19, 2004 + * +- * mpi_sas.h Version: 01.05.04 ++ * mpi_sas.h Version: 01.05.05 + * + * Version History + * --------------- +@@ -23,6 +23,10 @@ + * reply. + * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO + * Unit Control request. ++ * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER, ++ * including adding IOCParameter and IOCParameter value ++ * fields to SAS IO Unit Control Request. ++ * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define. + * -------------------------------------------------------------------------- + */ + +@@ -60,6 +64,8 @@ + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS IO Unit Configuration pages. + */ ++#define MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC (0xF0000000) ++ + #define MPI_SAS_DEVICE_INFO_SEP (0x00004000) + #define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) + #define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +@@ -216,7 +222,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 DevHandle; /* 04h */ +- U8 Reserved3; /* 06h */ ++ U8 IOCParameter; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 TargetID; /* 0Ch */ +@@ -225,7 +231,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R + U8 PrimFlags; /* 0Fh */ + U32 Primitive; /* 10h */ + U64 SASAddress; /* 14h */ +- U32 Reserved4; /* 1Ch */ ++ U32 IOCParameterValue; /* 1Ch */ + } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST, + SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t; + +@@ -241,6 +247,8 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R + #define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) + #define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */ + #define MPI_SAS_OP_REMOVE_DEVICE (0x0D) ++#define MPI_SAS_OP_SET_IOC_PARAMETER (0x0E) ++#define MPI_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) + + /* values for the PrimFlags field */ + #define MPI_SAS_PRIMFLAGS_SINGLE (0x08) +@@ -256,7 +264,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_R + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 DevHandle; /* 04h */ +- U8 Reserved3; /* 06h */ ++ U8 IOCParameter; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ +--- a/drivers/message/fusion/lsi/mpi_targ.h ++++ b/drivers/message/fusion/lsi/mpi_targ.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000-2004 LSI Corporation. ++ * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi_targ.h +--- a/drivers/message/fusion/lsi/mpi_tool.h ++++ b/drivers/message/fusion/lsi/mpi_tool.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2001-2005 LSI Corporation. ++ * Copyright (c) 2001-2008 LSI Corporation. + * + * + * Name: mpi_tool.h +--- a/drivers/message/fusion/lsi/mpi_type.h ++++ b/drivers/message/fusion/lsi/mpi_type.h +@@ -1,12 +1,12 @@ + /* +- * Copyright (c) 2000-2004 LSI Corporation. ++ * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi_type.h + * Title: MPI Basic type definitions + * Creation Date: June 6, 2000 + * +- * mpi_type.h Version: 01.05.01 ++ * mpi_type.h Version: 01.05.02 + * + * Version History + * --------------- +@@ -20,6 +20,7 @@ + * 08-08-01 01.02.01 Original release for v1.2 work. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Original release for MPI v1.5. ++ * 08-30-05 01.05.02 Added PowerPC option to #ifdef's. + * -------------------------------------------------------------------------- + */ + +@@ -49,8 +50,18 @@ typedef signed short S16; + typedef unsigned short U16; + + +-typedef int32_t S32; +-typedef u_int32_t U32; ++#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc) ++ ++ typedef signed int S32; ++ typedef unsigned int U32; ++ ++#else ++ ++ typedef signed long S32; ++ typedef unsigned long U32; ++ ++#endif ++ + + typedef struct _S64 + { +--- a/drivers/message/fusion/Makefile ++++ b/drivers/message/fusion/Makefile +@@ -1,12 +1,17 @@ +-# Fusion MPT drivers; recognized debug defines... ++# ++# LSI mpt fusion ++# ++ ++# csmi ioctls enable ++EXTRA_CFLAGS += -DCPQ_CIM ++EXTRA_CFLAGS += -DDIAG_BUFFER_SUPPORT ++ ++EXTRA_CFLAGS += -DCONFIG_FUSION_LOGGING + + # enable verbose logging + # CONFIG_FUSION_LOGGING needs to be enabled in Kconfig + #EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE + +- +-#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC +- + obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o + obj-$(CONFIG_FUSION_FC) += mptbase.o mptscsih.o mptfc.o + obj-$(CONFIG_FUSION_SAS) += mptbase.o mptscsih.o mptsas.o +--- a/drivers/message/fusion/mptbase.c ++++ b/drivers/message/fusion/mptbase.c +@@ -58,6 +58,7 @@ + #include + #include /* needed for in_interrupt() proto */ + #include ++#include + #include + #ifdef CONFIG_MTRR + #include +@@ -79,19 +80,38 @@ MODULE_VERSION(my_VERSION); + /* + * cmd line parameters + */ +-static int mpt_msi_enable = -1; +-module_param(mpt_msi_enable, int, 0); +-MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)"); ++ ++static int mpt_msi_enable_spi; ++module_param(mpt_msi_enable_spi, int, 0); ++MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI controllers (default=0)"); ++ ++static int mpt_msi_enable_fc; ++module_param(mpt_msi_enable_fc, int, 0); ++MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC controllers (default=0)"); ++ ++static int mpt_msi_enable_sas = 1; ++module_param(mpt_msi_enable_sas, int, 0); ++MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS controllers (default=1)"); ++ + + static int mpt_channel_mapping; + module_param(mpt_channel_mapping, int, 0); + MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); + +-static int mpt_debug_level; ++int mpt_debug_level; + static int mpt_set_debug_level(const char *val, struct kernel_param *kp); + module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, + &mpt_debug_level, 0600); + MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)"); ++EXPORT_SYMBOL(mpt_debug_level); ++ ++int mpt_fwfault_debug; ++module_param_call(mpt_fwfault_debug, param_set_int, param_get_int, ++ &mpt_fwfault_debug, 0600); ++MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault" ++ " and halt Firmware on fault - (default=0)"); ++EXPORT_SYMBOL(mpt_fwfault_debug); ++ + + #ifdef MFCNT + static int mfcounter = 0; +@@ -102,8 +122,7 @@ static int mfcounter = 0; + /* + * Public data... + */ +- +-static struct proc_dir_entry *mpt_proc_root_dir; ++struct proc_dir_entry *mpt_proc_root_dir; + + #define WHOINIT_UNKNOWN 0xAA + +@@ -125,6 +144,8 @@ static struct mpt_pci_driver *MptDevice + + static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++ + /* + * Driver Callback Index's + */ +@@ -135,8 +156,7 @@ static u8 last_drv_idx; + /* + * Forward protos... + */ +-static irqreturn_t mpt_interrupt(int irq, void *bus_id); +-static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); ++static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); + static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, + u32 *req, int replyBytes, u16 *u16reply, int maxwait, + int sleepFlag); +@@ -167,9 +187,8 @@ static int mpt_GetScsiPortSettings(MPT_A + static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); + static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); + static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); +-static void mpt_timer_expired(unsigned long data); + static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); +-static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); ++static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag); + static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); + static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); + static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); +@@ -184,7 +203,6 @@ static int procmpt_iocinfo_read(char *bu + #endif + static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); + +-//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); + static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); + static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); + static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); +@@ -193,6 +211,7 @@ static void mpt_sas_log_info(MPT_ADAPTER + static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); + static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); + ++ + /* module entry point */ + static int __init fusion_init (void); + static void __exit fusion_exit (void); +@@ -223,7 +242,16 @@ pci_enable_io_access(struct pci_dev *pde + pci_write_config_word(pdev, PCI_COMMAND, command_reg); + } + +-static int mpt_set_debug_level(const char *val, struct kernel_param *kp) ++/** ++ * mpt_set_debug_level - global setting of the mpt_debug_level ++ * found via /sys/module/mptbase/parameters/mpt_debug_level ++ * @val: ++ * @kp: ++ * ++ * Returns ++ **/ ++static int ++mpt_set_debug_level(const char *val, struct kernel_param *kp) + { + int ret = param_set_int(val, kp); + MPT_ADAPTER *ioc; +@@ -254,6 +282,56 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) + } + + /** ++ * mpt_is_discovery_complete - determine if discovery has completed ++ * @ioc: per adatper instance ++ * ++ * Returns 1 when discovery completed, else zero. ++ */ ++static int ++mpt_is_discovery_complete(MPT_ADAPTER *ioc) ++{ ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ SasIOUnitPage0_t *buffer; ++ dma_addr_t dma_handle; ++ int rc = 0; ++ ++ memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); ++ memset(&cfg, 0, sizeof(CONFIGPARMS)); ++ hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ ++ if ((mpt_config(ioc, &cfg))) ++ goto out; ++ if (!hdr.ExtPageLength) ++ goto out; ++ ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ &dma_handle); ++ if (!buffer) ++ goto out; ++ ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ if ((mpt_config(ioc, &cfg))) ++ goto out_free_consistent; ++ ++ if (!(buffer->PhyData[0].PortFlags & ++ MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) ++ rc = 1; ++ ++ out_free_consistent: ++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ buffer, dma_handle); ++ out: ++ return rc; ++} ++ ++/** + * mpt_fault_reset_work - work performed on workq after ioc fault + * @work: input argument, used to derive ioc + * +@@ -267,23 +345,29 @@ mpt_fault_reset_work(struct work_struct + int rc; + unsigned long flags; + +- if (ioc->diagPending || !ioc->active) ++ if (ioc->ioc_reset_in_progress || !ioc->active) + goto out; + + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", +- ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); ++ ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", +- ioc->name, __func__); ++ ioc->name, __FUNCTION__); + rc = mpt_HardResetHandler(ioc, CAN_SLEEP); + printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, +- __func__, (rc == 0) ? "success" : "failed"); ++ __FUNCTION__, (rc == 0) ? "success" : "failed"); + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " + "reset (%04xh)\n", ioc->name, ioc_raw_state & + MPI_DOORBELL_DATA_MASK); ++ } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { ++ if ((mpt_is_discovery_complete(ioc))) { ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " ++ "discovery_quiesce_io flag\n", ioc->name)); ++ ioc->sas_discovery_quiesce_io = 0; ++ } + } + + out: +@@ -294,14 +378,13 @@ mpt_fault_reset_work(struct work_struct + ioc = ioc->alt_ioc; + + /* rearm the timer */ +- spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->reset_work_q) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); +- spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + } + +- + /* + * Process turbo (context) reply... + */ +@@ -354,9 +437,9 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa + + /* Check for (valid) IO callback! */ + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || +- MptCallbacks[cb_idx] == NULL) { ++ MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", +- __func__, ioc->name, cb_idx); ++ __FUNCTION__, ioc->name, cb_idx); + goto out; + } + +@@ -398,6 +481,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", + ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); ++ + DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); + + /* Check/log IOC log info +@@ -413,14 +497,17 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + mpt_sas_log_info(ioc, log_info); + } + ++ /* TODO - add shost_attrs, or command line option, and ++ * extend this to SAS/FC ++ */ + if (ioc_stat & MPI_IOCSTATUS_MASK) + mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); + + /* Check for (valid) IO callback! */ + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || +- MptCallbacks[cb_idx] == NULL) { ++ MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", +- __func__, ioc->name, cb_idx); ++ __FUNCTION__, ioc->name, cb_idx); + freeme = 0; + goto out; + } +@@ -436,11 +523,11 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + mb(); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. + * @irq: irq number (not used) + * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure ++ * @r: pt_regs pointer (not used) + * + * This routine is registered via the request_irq() kernel API call, + * and handles all interrupts generated from a specific MPT adapter +@@ -452,7 +539,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + * This routine handles register-level access of the adapter but + * dispatches (calls) a protocol-specific callback routine to handle + * the protocol-specific details of the MPT request completion. +- */ ++ **/ + static irqreturn_t + mpt_interrupt(int irq, void *bus_id) + { +@@ -478,9 +565,9 @@ mpt_interrupt(int irq, void *bus_id) + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_base_reply - MPT base driver's callback routine ++ * mptbase_reply - MPT base driver's callback routine + * @ioc: Pointer to MPT_ADAPTER structure +- * @mf: Pointer to original MPT request frame ++ * @req: Pointer to original MPT request frame + * @reply: Pointer to MPT reply frame (NULL if TurboReply) + * + * MPT base driver's callback routine; all base driver +@@ -491,122 +578,49 @@ mpt_interrupt(int irq, void *bus_id) + * should be freed, or 0 if it shouldn't. + */ + static int +-mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) ++mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) + { ++ EventNotificationReply_t *pEventReply; ++ u8 event; ++ int evHandlers; + int freereq = 1; +- u8 func; +- +- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name)); +-#ifdef CONFIG_FUSION_LOGGING +- if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) && +- !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { +- dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n", +- ioc->name, mf)); +- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf); +- } +-#endif +- +- func = reply->u.hdr.Function; +- dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n", +- ioc->name, func)); +- +- if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { +- EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply; +- int evHandlers = 0; +- int results; +- +- results = ProcessEventNotification(ioc, pEvReply, &evHandlers); +- if (results != evHandlers) { +- /* CHECKME! Any special handling needed here? */ +- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", +- ioc->name, evHandlers, results)); +- } + +- /* +- * Hmmm... It seems that EventNotificationReply is an exception +- * to the rule of one reply per request. +- */ +- if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) { ++ switch (reply->u.hdr.Function) { ++ case MPI_FUNCTION_EVENT_NOTIFICATION: ++ pEventReply = (EventNotificationReply_t *)reply; ++ evHandlers = 0; ++ ProcessEventNotification(ioc, pEventReply, &evHandlers); ++ event = le32_to_cpu(pEventReply->Event) & 0xFF; ++ if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) + freereq = 0; +- } else { +- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n", +- ioc->name, pEvReply)); +- } +- +-#ifdef CONFIG_PROC_FS +-// LogEvent(ioc, pEvReply); +-#endif +- +- } else if (func == MPI_FUNCTION_EVENT_ACK) { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n", +- ioc->name)); +- } else if (func == MPI_FUNCTION_CONFIG) { +- CONFIGPARMS *pCfg; +- unsigned long flags; +- +- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n", +- ioc->name, mf, reply)); +- +- pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *))); +- +- if (pCfg) { +- /* disable timer and remove from linked list */ +- del_timer(&pCfg->timer); +- +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- list_del(&pCfg->linkage); +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- +- /* +- * If IOC Status is SUCCESS, save the header +- * and set the status code to GOOD. +- */ +- pCfg->status = MPT_CONFIG_ERROR; +- if (reply) { +- ConfigReply_t *pReply = (ConfigReply_t *)reply; +- u16 status; +- +- status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; +- dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n", +- ioc->name, status, le32_to_cpu(pReply->IOCLogInfo))); +- +- pCfg->status = status; +- if (status == MPI_IOCSTATUS_SUCCESS) { +- if ((pReply->Header.PageType & +- MPI_CONFIG_PAGETYPE_MASK) == +- MPI_CONFIG_PAGETYPE_EXTENDED) { +- pCfg->cfghdr.ehdr->ExtPageLength = +- le16_to_cpu(pReply->ExtPageLength); +- pCfg->cfghdr.ehdr->ExtPageType = +- pReply->ExtPageType; +- } +- pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; +- +- /* If this is a regular header, save PageLength. */ +- /* LMP Do this better so not using a reserved field! */ +- pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; +- pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; +- pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; +- } +- } +- +- /* +- * Wake up the original calling thread +- */ +- pCfg->wait_done = 1; +- wake_up(&mpt_waitq); +- } +- } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) { +- /* we should be always getting a reply frame */ +- memcpy(ioc->persist_reply_frame, reply, +- min(MPT_DEFAULT_FRAME_SIZE, +- 4*reply->u.reply.MsgLength)); +- del_timer(&ioc->persist_timer); +- ioc->persist_wait_done = 1; +- wake_up(&mpt_waitq); +- } else { +- printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", +- ioc->name, func); ++ if (event != MPI_EVENT_EVENT_CHANGE) ++ break; ++ case MPI_FUNCTION_CONFIG: ++ case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: ++ ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ++ if (reply) { ++ ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; ++ memcpy(ioc->mptbase_cmds.reply, reply, ++ min(MPT_DEFAULT_FRAME_SIZE, ++ 4 * reply->u.reply.MsgLength)); ++ } ++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->mptbase_cmds.done); ++ } else ++ freereq = 0; ++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) ++ freereq = 1; ++ break; ++ case MPI_FUNCTION_EVENT_ACK: ++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "EventAck reply received\n", ioc->name)); ++ break; ++ default: ++ printk(MYIOC_s_ERR_FMT ++ "Unexpected msg function (=%02Xh) reply received!\n", ++ ioc->name, reply->u.hdr.Function); ++ break; + } + + /* +@@ -616,7 +630,6 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA + return freereq; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_register - Register protocol-specific main callback handler. + * @cbfunc: callback function pointer +@@ -635,7 +648,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA + * {N,...,7,6,5,...,1} if successful. + * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be + * considered an error by the caller. +- */ ++ **/ + u8 + mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) + { +@@ -659,14 +672,13 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DR + return last_drv_idx; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_deregister - Deregister a protocol drivers resources. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine when its + * module is unloaded. +- */ ++ **/ + void + mpt_deregister(u8 cb_idx) + { +@@ -679,9 +691,9 @@ mpt_deregister(u8 cb_idx) + } + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_event_register - Register protocol-specific event callback handler. ++ * mpt_event_register - Register protocol-specific event callback ++ * handler. + * @cb_idx: previously registered (via mpt_register) callback handle + * @ev_cbfunc: callback function + * +@@ -689,7 +701,7 @@ mpt_deregister(u8 cb_idx) + * if/when they choose to be notified of MPT events. + * + * Returns 0 for success. +- */ ++ **/ + int + mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) + { +@@ -700,15 +712,15 @@ mpt_event_register(u8 cb_idx, MPT_EVHAND + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_event_deregister - Deregister protocol-specific event callback handler ++ * mpt_event_deregister - Deregister protocol-specific event callback ++ * handler. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine + * when it does not (or can no longer) handle events, + * or when its module is unloaded. +- */ ++ **/ + void + mpt_event_deregister(u8 cb_idx) + { +@@ -718,7 +730,6 @@ mpt_event_deregister(u8 cb_idx) + MptEvHandlers[cb_idx] = NULL; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_reset_register - Register protocol-specific IOC reset handler. + * @cb_idx: previously registered (via mpt_register) callback handle +@@ -728,7 +739,7 @@ mpt_event_deregister(u8 cb_idx) + * if/when they choose to be notified of IOC resets. + * + * Returns 0 for success. +- */ ++ **/ + int + mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) + { +@@ -739,7 +750,6 @@ mpt_reset_register(u8 cb_idx, MPT_RESETH + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. + * @cb_idx: previously registered callback handle +@@ -747,7 +757,7 @@ mpt_reset_register(u8 cb_idx, MPT_RESETH + * Each protocol-specific driver should call this routine + * when it does not (or can no longer) handle IOC reset handling, + * or when its module is unloaded. +- */ ++ **/ + void + mpt_reset_deregister(u8 cb_idx) + { +@@ -757,12 +767,11 @@ mpt_reset_deregister(u8 cb_idx) + MptResetHandlers[cb_idx] = NULL; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_device_driver_register - Register device driver hooks + * @dd_cbfunc: driver callbacks struct + * @cb_idx: MPT protocol driver index +- */ ++ **/ + int + mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) + { +@@ -776,20 +785,21 @@ mpt_device_driver_register(struct mpt_pc + + /* call per pci device probe entry point */ + list_for_each_entry(ioc, &ioc_list, list) { ++ if (!pci_get_drvdata(ioc->pcidev)) ++ continue; + id = ioc->pcidev->driver ? + ioc->pcidev->driver->id_table : NULL; + if (dd_cbfunc->probe) + dd_cbfunc->probe(ioc->pcidev, id); +- } ++ } + + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_device_driver_deregister - DeRegister device driver hooks + * @cb_idx: MPT protocol driver index +- */ ++ **/ + void + mpt_device_driver_deregister(u8 cb_idx) + { +@@ -809,19 +819,15 @@ mpt_device_driver_deregister(u8 cb_idx) + MptDeviceDriverHandlers[cb_idx] = NULL; + } + +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_get_msg_frame - Obtain an MPT request frame from the pool ++ * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) ++ * allocated per MPT adapter. + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * +- * Obtain an MPT request frame from the pool (of 1024) that are +- * allocated per MPT adapter. +- * + * Returns pointer to a MPT request frame or %NULL if none are available + * or IOC is not active. +- */ ++ **/ + MPT_FRAME_HDR* + mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) + { +@@ -851,7 +857,6 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER + mf->u.frame.linkage.arg1 = 0; + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; +- /* u16! */ + req_idx = req_offset / ioc->req_sz; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; +@@ -881,16 +886,16 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER + return mf; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC ++ * mpt_put_msg_frame - Send a protocol specific MPT request frame ++ * to a IOC. + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * @mf: Pointer to MPT request frame + * +- * This routine posts an MPT request frame to the request post FIFO of a ++ * This routine posts a MPT request frame to the request post FIFO of a + * specific MPT adapter. +- */ ++ **/ + void + mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) + { +@@ -901,14 +906,14 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER + /* ensure values are reset properly! */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; +- /* u16! */ + req_idx = req_offset / ioc->req_sz; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + + DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); + +- mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; ++ mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ++ ioc->RequestNB[req_idx]; + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d " + "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, + ioc->RequestNB[req_idx])); +@@ -916,15 +921,13 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER + } + + /** +- * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame ++ * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame ++ * to a IOC using hi priority request queue. + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * @mf: Pointer to MPT request frame + * +- * Send a protocol-specific MPT request frame to an IOC using +- * hi-priority request queue. +- * +- * This routine posts an MPT request frame to the request post FIFO of a ++ * This routine posts a MPT request frame to the request post FIFO of a + * specific MPT adapter. + **/ + void +@@ -949,7 +952,6 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ + CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_free_msg_frame - Place MPT request frame back on FreeQ. + * @handle: Handle of registered MPT protocol driver +@@ -958,7 +960,7 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. +- */ ++ **/ + void + mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) + { +@@ -966,43 +968,144 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT + + /* Put Request back on FreeQ! */ + spin_lock_irqsave(&ioc->FreeQlock, flags); +- mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */ ++ if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) ++ goto out; ++ mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); /* signature to know if this mf is freed */ + list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); + #ifdef MFCNT + ioc->mfcnt--; + #endif ++ out: + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_add_sge - Place a simple SGE at address pAddr. ++ * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. +- */ +-void ++ **/ ++static void + mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) + { +- if (sizeof(dma_addr_t) == sizeof(u64)) { +- SGESimple64_t *pSge = (SGESimple64_t *) pAddr; +- u32 tmp = dma_addr & 0xFFFFFFFF; ++ SGESimple32_t *pSge = (SGESimple32_t *) pAddr; ++ pSge->FlagsLength = cpu_to_le32(flagslength); ++ pSge->Address = cpu_to_le32(dma_addr); ++} + +- pSge->FlagsLength = cpu_to_le32(flagslength); +- pSge->Address.Low = cpu_to_le32(tmp); +- tmp = (u32) ((u64)dma_addr >> 32); +- pSge->Address.High = cpu_to_le32(tmp); + +- } else { +- SGESimple32_t *pSge = (SGESimple32_t *) pAddr; +- pSge->FlagsLength = cpu_to_le32(flagslength); +- pSge->Address = cpu_to_le32(dma_addr); ++/** ++ * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. ++ * @pAddr: virtual address for SGE ++ * @flagslength: SGE flags and data transfer length ++ * @dma_addr: Physical address ++ * ++ * This routine places a MPT request frame back on the MPT adapter's ++ * FreeQ. ++ **/ ++static void ++mpt_add_sge_64bit(char *pAddr, u32 flagslength, dma_addr_t dma_addr) ++{ ++ SGESimple64_t *pSge = (SGESimple64_t *) pAddr; ++ u32 tmp; ++ ++ tmp = dma_addr & 0xFFFFFFFF; ++ pSge->Address.Low = cpu_to_le32(tmp); ++ tmp = (u32) ((u64)dma_addr >> 32); ++ pSge->Address.High = cpu_to_le32(tmp); ++ pSge->FlagsLength = cpu_to_le32( ++ (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); ++} ++ ++ ++/** ++ * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr ++ * (1078 workaround). ++ * @pAddr: virtual address for SGE ++ * @flagslength: SGE flags and data transfer length ++ * @dma_addr: Physical address ++ * ++ * This routine places a MPT request frame back on the MPT adapter's ++ * FreeQ. ++ **/ ++static void ++mpt_add_sge_64bit_1078(char *pAddr, u32 flagslength, dma_addr_t dma_addr) ++{ ++ SGESimple64_t *pSge = (SGESimple64_t *) pAddr; ++ u32 tmp; ++ ++ tmp = dma_addr & 0xFFFFFFFF; ++ pSge->Address.Low = cpu_to_le32(tmp); ++ tmp = (u32) ((u64)dma_addr >> 32); ++ ++ /* ++ * 1078 errata workaround for the 36GB limitation ++ */ ++ if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { ++ flagslength |= ++ MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); ++ tmp |= (1<<31); ++ if (mpt_debug_level & MPT_DEBUG_36GB_MEM) ++ printk(KERN_DEBUG "1078 P0M2 addressing for " ++ "addr = 0x%llx len = %d\n", ++ (unsigned long long)dma_addr, ++ MPI_SGE_LENGTH(flagslength)); + } ++ ++ pSge->Address.High = cpu_to_le32(tmp); ++ pSge->FlagsLength = cpu_to_le32( ++ (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/** ++ * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. ++ * @pAddr: virtual address for SGE ++ * @next: nextChainOffset value (u32's) ++ * @length: length of next SGL segment ++ * @dma_addr: Physical address ++ * ++ */ ++static void ++mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) ++{ ++ SGEChain32_t *pChain = (SGEChain32_t *) pAddr; ++ pChain->Length = cpu_to_le16(length); ++ pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; ++ pChain->NextChainOffset = next; ++ pChain->Address = cpu_to_le32(dma_addr); ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/** ++ * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. ++ * @pAddr: virtual address for SGE ++ * @next: nextChainOffset value (u32's) ++ * @length: length of next SGL segment ++ * @dma_addr: Physical address ++ * ++ */ ++static void ++mpt_add_chain_64bit(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) ++{ ++ SGEChain64_t *pChain = (SGEChain64_t *) pAddr; ++ u32 tmp = dma_addr & 0xFFFFFFFF; ++ ++ pChain->Length = cpu_to_le16(length); ++ pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | ++ MPI_SGE_FLAGS_64_BIT_ADDRESSING); ++ ++ pChain->NextChainOffset = next; ++ ++ pChain->Address.Low = cpu_to_le32(tmp); ++ tmp = (u32) ((u64)dma_addr >> 32); ++ pChain->Address.High = cpu_to_le32(tmp); + } + ++ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_send_handshake_request - Send MPT request via doorbell handshake method. +@@ -1019,11 +1122,11 @@ mpt_add_sge(char *pAddr, u32 flagslength + * request which are greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + int + mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) + { +- int r = 0; ++ int r = 0; + u8 *req_as_bytes; + int ii; + +@@ -1038,7 +1141,7 @@ mpt_send_handshake_request(u8 cb_idx, MP + * is in proper (pre-alloc'd) request buffer range... + */ + ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); +- if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { ++ if (ii >= 0 && ii < ioc->req_depth) { + MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; +@@ -1096,7 +1199,6 @@ mpt_send_handshake_request(u8 cb_idx, MP + return r; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_host_page_access_control - control the IOC's Host Page Buffer access + * @ioc: Pointer to MPT adapter structure +@@ -1113,8 +1215,7 @@ mpt_send_handshake_request(u8 cb_idx, MP + * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } + * + * Returns 0 for success, non-zero for failure. +- */ +- ++ **/ + static int + mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) + { +@@ -1139,7 +1240,6 @@ mpt_host_page_access_control(MPT_ADAPTER + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_host_page_alloc - allocate system memory for the fw + * @ioc: Pointer to pointer to IOC adapter +@@ -1147,7 +1247,7 @@ mpt_host_page_access_control(MPT_ADAPTER + * + * If we already allocated memory in past, then resend the same pointer. + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) + { +@@ -1171,7 +1271,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI + host_page_buffer_sz, + &ioc->HostPageBuffer_dma)) != NULL) { + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, + (u32)ioc->HostPageBuffer_dma, +@@ -1195,21 +1295,16 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI + psge = (char *)&ioc_init->HostPageBufferSGE; + flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | +- MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; +- if (sizeof(dma_addr_t) == sizeof(u64)) { +- flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING; +- } + flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; + flags_length |= ioc->HostPageBuffer_sz; +- mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma); ++ ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); + ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; + + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. + * @iocid: IOC unique identifier (integer) +@@ -1220,7 +1315,7 @@ return 0; + * + * Returns iocid and sets iocpp if iocid is found. + * Returns -1 if iocid is not found. +- */ ++ **/ + int + mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) + { +@@ -1493,7 +1588,6 @@ mpt_mapresources(MPT_ADAPTER *ioc) + unsigned long port; + u32 msize; + u32 psize; +- u8 revision; + int r = -ENODEV; + struct pci_dev *pdev; + +@@ -1509,24 +1603,39 @@ mpt_mapresources(MPT_ADAPTER *ioc) + "MEM failed\n", ioc->name); + return r; + } ++ if (sizeof(dma_addr_t) > 4) { ++ const uint64_t required_mask = dma_get_required_mask(&pdev->dev); ++ if (required_mask > DMA_32BIT_MASK ++ && !pci_set_dma_mask(pdev, DMA_64BIT_MASK) ++ && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { ++ ioc->dma_mask = DMA_64BIT_MASK; ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ++ ioc->name)); ++ } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) ++ && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { ++ ioc->dma_mask = DMA_32BIT_MASK; ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ++ ioc->name)); ++ } else { ++ printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", ++ ioc->name, pci_name(pdev)); ++ return r; ++ } + +- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); +- +- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) +- && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT +- ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", +- ioc->name)); +- } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) +- && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT +- ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", +- ioc->name)); + } else { +- printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", +- ioc->name, pci_name(pdev)); +- pci_release_selected_regions(pdev, ioc->bars); +- return r; ++ if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) ++ && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { ++ ioc->dma_mask = DMA_32BIT_MASK; ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ++ ioc->name)); ++ } else { ++ printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", ++ ioc->name, pci_name(pdev)); ++ return r; ++ } + } + + mem_phys = msize = 0; +@@ -1554,7 +1663,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) + mem = ioremap(mem_phys, msize); + if (mem == NULL) { + printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" +- " memory!\n", ioc->name); ++ "memory!\n", ioc->name); + return -EINVAL; + } + ioc->memmap = mem; +@@ -1565,13 +1674,15 @@ mpt_mapresources(MPT_ADAPTER *ioc) + ioc->chip = (SYSIF_REGS __iomem *)mem; + + /* Save Port IO values in case we need to do downloadboot */ +- ioc->pio_mem_phys = port; +- ioc->pio_chip = (SYSIF_REGS __iomem *)port; ++ { ++ u8 *pmem = (u8*)port; ++ ioc->pio_mem_phys = port; ++ ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; ++ } + + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_attach - Install a PCI intelligent MPT adapter. + * @pdev: Pointer to pci_dev structure +@@ -1588,7 +1699,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) + * Returns 0 for success, non-zero for failure. + * + * TODO: Add support for polled controllers +- */ ++ **/ + int + mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) + { +@@ -1610,6 +1721,7 @@ mpt_attach(struct pci_dev *pdev, const s + + ioc->id = mpt_ids++; + sprintf(ioc->name, "ioc%d", ioc->id); ++ dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); + + /* + * set initial debug level +@@ -1620,7 +1732,6 @@ mpt_attach(struct pci_dev *pdev, const s + if (mpt_debug_level) + printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level); + +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); + + ioc->pcidev = pdev; + if (mpt_mapresources(ioc)) { +@@ -1628,14 +1739,34 @@ mpt_attach(struct pci_dev *pdev, const s + return r; + } + ++ /* ++ * Setting up proper handlers for scatter gather handling ++ */ ++ if (ioc->dma_mask == DMA_64BIT_MASK) { ++ if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) ++ ioc->add_sge = &mpt_add_sge_64bit_1078; ++ else ++ ioc->add_sge = &mpt_add_sge_64bit; ++ ioc->add_chain = &mpt_add_chain_64bit; ++ ioc->sg_addr_size = 8; ++ } else { ++ ioc->add_sge = &mpt_add_sge; ++ ioc->add_chain = &mpt_add_chain; ++ ioc->sg_addr_size = 4; ++ } ++ ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; ++ + ioc->alloc_total = sizeof(MPT_ADAPTER); + ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ + ioc->reply_sz = MPT_REPLY_FRAME_SIZE; + +- ioc->pcidev = pdev; +- ioc->diagPending = 0; +- spin_lock_init(&ioc->diagLock); +- spin_lock_init(&ioc->initializing_hba_lock); ++ spin_lock_init(&ioc->taskmgmt_lock); ++ mutex_init(&ioc->internal_cmds.mutex); ++ init_completion(&ioc->internal_cmds.done); ++ mutex_init(&ioc->mptbase_cmds.mutex); ++ init_completion(&ioc->mptbase_cmds.done); ++ mutex_init(&ioc->taskmgmt_cmds.mutex); ++ init_completion(&ioc->taskmgmt_cmds.done); + + /* Initialize the event logging. + */ +@@ -1648,16 +1779,13 @@ mpt_attach(struct pci_dev *pdev, const s + ioc->mfcnt = 0; + #endif + ++ ioc->sh = NULL; + ioc->cached_fw = NULL; + + /* Initilize SCSI Config Data structure + */ + memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); + +- /* Initialize the running configQ head. +- */ +- INIT_LIST_HEAD(&ioc->configQ); +- + /* Initialize the fc rport list head. + */ + INIT_LIST_HEAD(&ioc->fc_rports); +@@ -1665,11 +1793,10 @@ mpt_attach(struct pci_dev *pdev, const s + /* Find lookup slot. */ + INIT_LIST_HEAD(&ioc->list); + +- +- /* Initialize workqueue */ ++ /* Initialize work */ + INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); +- spin_lock_init(&ioc->fault_reset_work_lock); + ++ /* Initialize workqueue */ + snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name), + "mpt_poll_%d", ioc->id); + ioc->reset_work_q = +@@ -1682,8 +1809,8 @@ mpt_attach(struct pci_dev *pdev, const s + return -ENOMEM; + } + +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", +- ioc->name, &ioc->facts, &ioc->pfacts[0])); ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts @ %p, pfacts[0] @ %p\n", ++ ioc->name, &ioc->facts, &ioc->pfacts[0])); + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); +@@ -1703,14 +1830,14 @@ mpt_attach(struct pci_dev *pdev, const s + case MPI_MANUFACTPAGE_DEVICEID_FC929X: + if (revision < XL_929) { + /* 929X Chip Fix. Set Split transactions level +- * for PCIX. Set MOST bits to zero. +- */ ++ * for PCIX. Set MOST bits to zero. ++ */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); + } else { + /* 929XL Chip Fix. Set MMRBC to 0x08. +- */ ++ */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd |= 0x08; + pci_write_config_byte(pdev, 0x6a, pcixcmd); +@@ -1728,6 +1855,7 @@ mpt_attach(struct pci_dev *pdev, const s + ioc->bus_type = FC; + break; + ++ + case MPI_MANUFACTPAGE_DEVID_53C1030: + /* 1030 Chip Fix. Disable Split transactions + * for PCIX. Set MOST bits to zero if Rev < C0( = 8). +@@ -1745,22 +1873,33 @@ mpt_attach(struct pci_dev *pdev, const s + case MPI_MANUFACTPAGE_DEVID_SAS1064: + case MPI_MANUFACTPAGE_DEVID_SAS1068: + ioc->errata_flag_1064 = 1; ++ ioc->bus_type = SAS; ++ break; + + case MPI_MANUFACTPAGE_DEVID_SAS1064E: + case MPI_MANUFACTPAGE_DEVID_SAS1068E: + case MPI_MANUFACTPAGE_DEVID_SAS1078: + ioc->bus_type = SAS; ++ break; + } + +- if (mpt_msi_enable == -1) { +- /* Enable on SAS, disable on FC and SPI */ +- if (ioc->bus_type == SAS) +- ioc->msi_enable = 1; +- else +- ioc->msi_enable = 0; +- } else +- /* follow flag: 0 - disable; 1 - enable */ +- ioc->msi_enable = mpt_msi_enable; ++ switch (ioc->bus_type) { ++ case SAS: ++ ioc->msi_enable = mpt_msi_enable_sas; ++ break; ++ ++ case SPI: ++ ioc->msi_enable = mpt_msi_enable_spi; ++ break; ++ ++ case FC: ++ ioc->msi_enable = mpt_msi_enable_fc; ++ break; ++ ++ default: ++ ioc->msi_enable = 0; ++ break; ++ } + + if (ioc->errata_flag_1064) + pci_disable_io_access(pdev); +@@ -1772,9 +1911,6 @@ mpt_attach(struct pci_dev *pdev, const s + ioc->active = 0; + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + +- /* Set IOC ptr in the pcidev's driver data. */ +- pci_set_drvdata(ioc->pcidev, ioc); +- + /* Set lookup ptr. */ + list_add_tail(&ioc->list, &ioc_list); + +@@ -1782,10 +1918,17 @@ mpt_attach(struct pci_dev *pdev, const s + */ + mpt_detect_bound_ports(ioc, pdev); + ++ ++ INIT_LIST_HEAD(&ioc->fw_event_list); ++ spin_lock_init(&ioc->fw_event_lock); ++ snprintf(ioc->fw_event_q_name, sizeof(ioc->fw_event_q_name), ++ "mpt/%d", ioc->id); ++ ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); ++ + if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, + CAN_SLEEP)) != 0){ + printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", +- ioc->name, r); ++ ioc->name, r); + + list_del(&ioc->list); + if (ioc->alt_ioc) +@@ -1796,7 +1939,8 @@ mpt_attach(struct pci_dev *pdev, const s + + destroy_workqueue(ioc->reset_work_q); + ioc->reset_work_q = NULL; +- ++ destroy_workqueue(ioc->fw_event_q); ++ ioc->fw_event_q = NULL; + kfree(ioc); + pci_set_drvdata(pdev, NULL); + return r; +@@ -1832,35 +1976,37 @@ mpt_attach(struct pci_dev *pdev, const s + if (!ioc->alt_ioc) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); +- + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_detach - Remove a PCI intelligent MPT adapter. + * @pdev: Pointer to pci_dev structure +- */ +- ++ **/ + void + mpt_detach(struct pci_dev *pdev) + { + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + char pname[32]; + u8 cb_idx; +- unsigned long flags; ++ unsigned long flags; + struct workqueue_struct *wq; + + /* + * Stop polling ioc for fault condition + */ +- spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + wq = ioc->reset_work_q; + ioc->reset_work_q = NULL; +- spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + cancel_delayed_work(&ioc->fault_reset_work); + destroy_workqueue(wq); + ++ spin_lock_irqsave(&ioc->fw_event_lock, flags); ++ wq = ioc->fw_event_q; ++ ioc->fw_event_q = NULL; ++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); ++ destroy_workqueue(wq); + + sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); + remove_proc_entry(pname, NULL); +@@ -1877,32 +2023,18 @@ mpt_detach(struct pci_dev *pdev) + } + } + +- /* Disable interrupts! */ +- CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); +- +- ioc->active = 0; +- synchronize_irq(pdev->irq); +- +- /* Clear any lingering interrupt */ +- CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); +- +- CHIPREG_READ32(&ioc->chip->IntStatus); +- +- mpt_adapter_dispose(ioc); +- +- pci_set_drvdata(pdev, NULL); +-} ++ mpt_adapter_dispose(ioc); ++} + + /************************************************************************** + * Power Management + */ + #ifdef CONFIG_PM +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_suspend - Fusion MPT base driver suspend routine. + * @pdev: Pointer to pci_dev structure + * @state: new state to enter +- */ ++ **/ + int + mpt_suspend(struct pci_dev *pdev, pm_message_t state) + { +@@ -1923,7 +2055,6 @@ mpt_suspend(struct pci_dev *pdev, pm_mes + /* disable interrupts */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; +- + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + +@@ -1938,11 +2069,10 @@ mpt_suspend(struct pci_dev *pdev, pm_mes + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_resume - Fusion MPT base driver resume routine. + * @pdev: Pointer to pci_dev structure +- */ ++ **/ + int + mpt_resume(struct pci_dev *pdev) + { +@@ -1962,6 +2092,22 @@ mpt_resume(struct pci_dev *pdev) + err = mpt_mapresources(ioc); + if (err) + return err; ++ ++ if (ioc->dma_mask == DMA_64BIT_MASK) { ++ if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) ++ ioc->add_sge = &mpt_add_sge_64bit_1078; ++ else ++ ioc->add_sge = &mpt_add_sge_64bit; ++ ioc->add_chain = &mpt_add_chain_64bit; ++ ioc->sg_addr_size = 8; ++ } else { ++ ++ ioc->add_sge = &mpt_add_sge; ++ ioc->add_chain = &mpt_add_chain; ++ ioc->sg_addr_size = 4; ++ } ++ ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; ++ + + printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", + ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), +@@ -1986,9 +2132,7 @@ mpt_resume(struct pci_dev *pdev) + + /* bring ioc to operational state */ + printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); +- recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, +- CAN_SLEEP); +- if (recovery_state != 0) ++ if ((recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) + printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " + "error:[%x]\n", ioc->name, recovery_state); + else +@@ -1996,7 +2140,6 @@ mpt_resume(struct pci_dev *pdev) + "pci-resume: success\n", ioc->name); + out: + return 0; +- + } + #endif + +@@ -2015,7 +2158,6 @@ mpt_signal_reset(u8 index, MPT_ADAPTER * + return (MptResetHandlers[index])(ioc, reset_phase); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_do_ioc_recovery - Initialize or recover MPT adapter. + * @ioc: Pointer to MPT adapter structure +@@ -2034,9 +2176,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER * + * -2 if READY but IOCFacts Failed + * -3 if READY but PrimeIOCFifos Failed + * -4 if READY but IOCInit Failed +- * -5 if failed to enable_device and/or request_selected_regions +- * -6 if failed to upload firmware +- */ ++ **/ + static int + mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) + { +@@ -2045,14 +2185,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + int hard; + int rc=0; + int ii; +- u8 cb_idx; +- int handlers; + int ret = 0; + int reset_alt_ioc_active = 0; + int irq_allocated = 0; + u8 *a; + +- printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name, ++ printk(MYIOC_s_DEBUG_FMT "Initiating %s\n", ioc->name, + reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); + + /* Disable reply interrupts (also blocks FreeQ) */ +@@ -2060,7 +2198,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + ioc->active = 0; + + if (ioc->alt_ioc) { +- if (ioc->alt_ioc->active) ++ if (ioc->alt_ioc->active || reason == MPT_HOSTEVENT_IOC_RECOVER) + reset_alt_ioc_active = 1; + + /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ +@@ -2079,16 +2217,17 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ +- dprintk(ioc, printk(MYIOC_s_INFO_FMT +- "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": alt-ioc reply irq re-enabled\n", ++ ioc->alt_ioc->name)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); + ioc->alt_ioc->active = 1; + } + + } else { +- printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name); ++ printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ioc->name); + } +- return -1; ++ ret = -1; ++ goto out; + } + + /* hard_reset_done = 0 if a soft reset was performed +@@ -2098,7 +2237,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) + alt_ioc_ready = 1; + else +- printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name); ++ printk(MYIOC_s_WARN_FMT ++ ": alt-ioc Not ready WARNING!\n", ioc->alt_ioc->name); + } + + for (ii=0; ii<5; ii++) { +@@ -2156,23 +2296,28 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + if (ioc->pcidev->irq) { + if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev)) + printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", +- ioc->name); ++ ioc->name); + else + ioc->msi_enable = 0; ++ + rc = request_irq(ioc->pcidev->irq, mpt_interrupt, + IRQF_SHARED, ioc->name, ioc); + if (rc < 0) { + printk(MYIOC_s_ERR_FMT "Unable to allocate " +- "interrupt %d!\n", ioc->name, ioc->pcidev->irq); ++ "interrupt %d!\n", ioc->name, ++ ioc->pcidev->irq); + if (ioc->msi_enable) + pci_disable_msi(ioc->pcidev); +- return -EBUSY; ++ ret = -EBUSY; ++ goto out; + } + irq_allocated = 1; + ioc->pci_irq = ioc->pcidev->irq; + pci_set_master(ioc->pcidev); /* ?? */ +- dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt " +- "%d\n", ioc->name, ioc->pcidev->irq)); ++ pci_set_drvdata(ioc->pcidev, ioc); ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "installed at interrupt %d\n", ioc->name, ++ ioc->pcidev->irq)); + } + } + +@@ -2181,18 +2326,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + * init as upper addresses are needed for init. + * If fails, continue with alt-ioc processing + */ ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", ++ ioc->name)); + if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) + ret = -3; + + /* May need to check/upload firmware & data here! + * If fails, continue with alt-ioc processing + */ ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", ++ ioc->name)); + if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) + ret = -4; + // NEW! + if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { +- printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n", +- ioc->alt_ioc->name, rc); ++ printk(MYIOC_s_WARN_FMT ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", ++ ioc->alt_ioc->name, rc); + alt_ioc_ready = 0; + reset_alt_ioc_active = 0; + } +@@ -2201,15 +2350,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { + alt_ioc_ready = 0; + reset_alt_ioc_active = 0; +- printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n", +- ioc->alt_ioc->name, rc); ++ printk(MYIOC_s_WARN_FMT ++ ": alt-ioc: (%d) init failure WARNING!\n", ++ ioc->alt_ioc->name, rc); + } + } + + if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ + if (ioc->upload_fw) { + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "firmware upload required!\n", ioc->name)); ++ "firmware upload required!\n", ioc->name)); + + /* Controller is not operational, cannot do upload + */ +@@ -2232,34 +2382,39 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + } else { + printk(MYIOC_s_WARN_FMT + "firmware upload failure!\n", ioc->name); +- ret = -6; ++ ret = -5; + } + } + } + } + ++ /* Enable MPT base driver management of EventNotification ++ * and EventAck handling. ++ */ ++ if ((ret == 0) && (!ioc->facts.EventState)) { ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendEventNotification\n", ++ ioc->name)); ++ ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ ++ } ++ ++ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) ++ rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); ++ + if (ret == 0) { + /* Enable! (reply interrupt) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); + ioc->active = 1; + } +- +- if (reset_alt_ioc_active && ioc->alt_ioc) { +- /* (re)Enable alt-IOC! (reply interrupt) */ +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n", +- ioc->alt_ioc->name)); +- CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); +- ioc->alt_ioc->active = 1; ++ if (rc == 0) { /* alt ioc */ ++ if (reset_alt_ioc_active && ioc->alt_ioc) { ++ /* (re)Enable alt-IOC! (reply interrupt) */ ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc reply irq re-enabled\n", ++ ioc->alt_ioc->name)); ++ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ++ ioc->alt_ioc->active = 1; ++ } + } + +- /* Enable MPT base driver management of EventNotification +- * and EventAck handling. +- */ +- if ((ret == 0) && (!ioc->facts.EventState)) +- (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ +- +- if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) +- (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ + + /* Add additional "reason" check before call to GetLanConfigPages + * (combined with GetIoUnitPage2 call). This prevents a somewhat +@@ -2272,11 +2427,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + /* + * Initalize link list for inactive raid volumes. + */ +- mutex_init(&ioc->raid_data.inactive_list_mutex); ++ init_MUTEX(&ioc->raid_data.inactive_list_mutex); + INIT_LIST_HEAD(&ioc->raid_data.inactive_list); + +- if (ioc->bus_type == SAS) { ++ switch (ioc->bus_type) { + ++ case SAS: + /* clear persistency table */ + if(ioc->facts.IOCExceptions & + MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { +@@ -2290,8 +2446,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + */ + mpt_findImVolumes(ioc); + +- } else if (ioc->bus_type == FC) { +- if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && ++ /* Check, and possibly reset, the coalescing value ++ */ ++ mpt_read_ioc_pg_1(ioc); ++ ++ break; ++ ++ case FC: ++ if ((ioc->pfacts[0].ProtocolFlags & ++ MPI_PORTFACTS_PROTOCOL_LAN) && + (ioc->lan_cnfg_page0.Header.PageLength == 0)) { + /* + * Pre-fetch the ports LAN MAC address! +@@ -2300,11 +2463,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + (void) GetLanConfigPages(ioc); + a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", +- ioc->name, a[5], a[4], a[3], a[2], a[1], a[0])); +- ++ "LanAddr = %02X:%02X:%02X" ++ ":%02X:%02X:%02X\n", ++ ioc->name, a[5], a[4], ++ a[3], a[2], a[1], a[0])); + } +- } else { ++ break; ++ ++ case SPI: + /* Get NVRAM and adapter maximums from SPP 0 and 2 + */ + mpt_GetScsiPortSettings(ioc, 0); +@@ -2323,41 +2489,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + mpt_read_ioc_pg_1(ioc); + + mpt_read_ioc_pg_4(ioc); ++ ++ break; + } + + GetIoUnitPage2(ioc); + mpt_get_manufacturing_pg_0(ioc); + } + +- /* +- * Call each currently registered protocol IOC reset handler +- * with post-reset indication. +- * NOTE: If we're doing _IOC_BRINGUP, there can be no +- * MptResetHandlers[] registered yet. +- */ +- if (hard_reset_done) { +- rc = handlers = 0; +- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { +- if ((ret == 0) && MptResetHandlers[cb_idx]) { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Calling IOC post_reset handler #%d\n", +- ioc->name, cb_idx)); +- rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); +- handlers++; +- } +- +- if (alt_ioc_ready && MptResetHandlers[cb_idx]) { +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Calling IOC post_reset handler #%d\n", +- ioc->alt_ioc->name, cb_idx)); +- rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); +- handlers++; +- } +- } +- /* FIXME? Examine results here? */ +- } +- + out: ++ + if ((ret != 0) && irq_allocated) { + free_irq(ioc->pci_irq, ioc); + if (ioc->msi_enable) +@@ -2366,7 +2507,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + return ret; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_detect_bound_ports - Search for matching PCI bus/dev_function + * @ioc: Pointer to MPT adapter structure +@@ -2378,7 +2518,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + * + * If match on PCI dev_function +/-1 is found, bind the two MPT adapters + * using alt_ioc pointer fields in their %MPT_ADAPTER structures. +- */ ++ **/ + static void + mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) + { +@@ -2389,8 +2529,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, + + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," + " searching for devfn match on %x or %x\n", +- ioc->name, pci_name(pdev), pdev->bus->number, +- pdev->devfn, func-1, func+1)); ++ ioc->name, pci_name(pdev), pdev->bus->number, ++ pdev->devfn, func-1, func+1)); + + peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); + if (!peer) { +@@ -2404,16 +2544,16 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, + if (_pcidev == peer) { + /* Paranoia checks */ + if (ioc->alt_ioc != NULL) { +- printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", +- ioc->name, ioc->alt_ioc->name); ++ printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n", ++ ioc->name, ioc->name, ioc->alt_ioc->name); + break; + } else if (ioc_srch->alt_ioc != NULL) { +- printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", +- ioc_srch->name, ioc_srch->alt_ioc->name); ++ printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n", ++ ioc_srch->name, ioc_srch->name, ioc_srch->alt_ioc->name); + break; + } +- dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n", +- ioc->name, ioc_srch->name)); ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FOUND! binding %s <==> %s\n", ++ ioc->name, ioc->name, ioc_srch->name)); + ioc_srch->alt_ioc = ioc; + ioc->alt_ioc = ioc_srch; + } +@@ -2421,11 +2561,10 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, + pci_dev_put(peer); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_adapter_disable - Disable misbehaving MPT adapter. + * @ioc: Pointer to MPT adapter structure +- */ ++ **/ + static void + mpt_adapter_disable(MPT_ADAPTER *ioc) + { +@@ -2433,26 +2572,43 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + int ret; + + if (ioc->cached_fw != NULL) { +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto " +- "adapter\n", __func__, ioc->name)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_adapter_disable: " ++ "Pushing FW onto adapter\n", ioc->name)); + if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) + ioc->cached_fw, CAN_SLEEP)) < 0) { + printk(MYIOC_s_WARN_FMT +- ": firmware downloadboot failure (%d)!\n", +- ioc->name, ret); ++ ": firmware downloadboot failure (%d)!\n", ioc->name, ret); + } + } + ++ /* ++ * Put the controller into ready state (if its not already) ++ */ ++ if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { ++ if(!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, ++ CAN_SLEEP)) { ++ if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) ++ printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " ++ "reset failed to put ioc in ready state!\n", ++ ioc->name, __FUNCTION__); ++ } else ++ printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " ++ "failed!\n", ioc->name, __FUNCTION__); ++ } ++ + /* Disable adapter interrupts! */ ++ synchronize_irq(ioc->pcidev->irq); + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; ++ + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); ++ CHIPREG_READ32(&ioc->chip->IntStatus); + + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; +- dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n", +- ioc->name, ioc->alloc, ioc->alloc_sz)); ++ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free @ %p, sz=%d bytes\n", ++ ioc->name, ioc->alloc, ioc->alloc_sz)); + pci_free_consistent(ioc->pcidev, sz, + ioc->alloc, ioc->alloc_dma); + ioc->reply_frames = NULL; +@@ -2482,8 +2638,10 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + mpt_inactive_raid_list_free(ioc); + kfree(ioc->raid_data.pIocPg2); + kfree(ioc->raid_data.pIocPg3); ++ kfree(ioc->raid_data.pIocPg6); + ioc->spi_data.nvram = NULL; + ioc->raid_data.pIocPg3 = NULL; ++ ioc->raid_data.pIocPg6 = NULL; + + if (ioc->spi_data.pIocPg4 != NULL) { + sz = ioc->spi_data.IocPg4Sz; +@@ -2507,27 +2665,29 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + if((ret = mpt_host_page_access_control(ioc, + MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { + printk(MYIOC_s_ERR_FMT +- "host page buffers free failed (%d)!\n", +- ioc->name, ret); ++ ": %s: host page buffers free failed (%d)!\n", ++ ioc->name, __FUNCTION__, ret); + } +- dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", ++ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); + pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, +- ioc->HostPageBuffer, ioc->HostPageBuffer_dma); ++ ioc->HostPageBuffer, ++ ioc->HostPageBuffer_dma); + ioc->HostPageBuffer = NULL; + ioc->HostPageBuffer_sz = 0; + ioc->alloc_total -= ioc->HostPageBuffer_sz; + } ++ ++ pci_set_drvdata(ioc->pcidev, NULL); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_adapter_dispose - Free all resources associated with an MPT adapter + * @ioc: Pointer to MPT adapter structure + * + * This routine unregisters h/w resources and frees all alloc'd memory + * associated with a MPT adapter structure. +- */ ++ **/ + static void + mpt_adapter_dispose(MPT_ADAPTER *ioc) + { +@@ -2558,7 +2718,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) + #if defined(CONFIG_MTRR) && 0 + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); +- dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name)); ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region de-registered\n", ioc->name)); + } + #endif + +@@ -2566,8 +2726,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) + list_del(&ioc->list); + + sz_last = ioc->alloc_total; +- dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n", +- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free'd %d of %d bytes\n", ++ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); + + if (ioc->alt_ioc) + ioc->alt_ioc->alt_ioc = NULL; +@@ -2575,11 +2735,10 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) + kfree(ioc); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * MptDisplayIocCapabilities - Disply IOC's capabilities. + * @ioc: Pointer to MPT adapter structure +- */ ++ **/ + static void + MptDisplayIocCapabilities(MPT_ADAPTER *ioc) + { +@@ -2618,7 +2777,6 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i + printk("}\n"); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * MakeIocReady - Get IOC to a READY state, using KickStart if needed. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2632,7 +2790,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i + * -2 - Msg Unit Reset Failed + * -3 - IO Unit Reset Failed + * -4 - IOC owned by a PEER +- */ ++ **/ + static int + MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) + { +@@ -2646,7 +2804,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + + /* Get current [raw] IOC state */ + ioc_state = mpt_GetIocState(ioc, 0); +- dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state)); ++ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state)); + + /* + * Check to see if IOC got left/stuck in doorbell handshake +@@ -2659,8 +2817,11 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + } + + /* Is it already READY? */ +- if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) ++ if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) { ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "IOC is in READY state\n", ++ ioc->name)); + return 0; ++ } + + /* + * Check to see if IOC is in FAULT state. +@@ -2668,9 +2829,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + statefault = 2; + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", +- ioc->name); +- printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n", +- ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK); ++ ioc->name); ++ printk(KERN_WARNING " FAULT code = %04xh\n", ++ ioc_state & MPI_DOORBELL_DATA_MASK); + } + + /* +@@ -2686,7 +2847,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + * Else, fall through to KickStart case + */ + whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "whoinit 0x%x statefault %d force %d\n", + ioc->name, whoinit, statefault, force)); + if (whoinit == MPI_WHOINIT_PCI_PEER) +@@ -2733,15 +2894,15 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + + ii++; cntdn--; + if (!cntdn) { +- printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", +- ioc->name, (int)((ii+5)/HZ)); ++ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n", ++ ioc->name, ioc_state, (int)((ii+5)/HZ)); + return -ETIME; + } + + if (sleepFlag == CAN_SLEEP) { + msleep(1); + } else { +- mdelay (1); /* 1 msec delay */ ++ mdelay(1); /* 1 msec delay */ + } + + } +@@ -2755,7 +2916,6 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + return hard_reset_done; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_GetIocState - Get the current state of a MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2763,7 +2923,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + * + * Returns all IOC Doorbell register bits if cooked==0, else just the + * Doorbell bits in MPI_IOC_STATE_MASK. +- */ ++ **/ + u32 + mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) + { +@@ -2779,7 +2939,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co + return cooked ? sc : s; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetIocFacts - Send IOCFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2787,7 +2946,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co + * @reason: If recovery, only update facts. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) + { +@@ -2802,8 +2961,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { +- printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n", +- ioc->name, ioc->last_state ); ++ printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", ++ ioc->name, ++ ioc->last_state ); + return -44; + } + +@@ -2820,7 +2980,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + get_facts.Function = MPI_FUNCTION_IOC_FACTS; + /* Assert: All other get_facts fields are zero! */ + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "Sending get IocFacts request req_sz=%d reply_sz=%d\n", + ioc->name, req_sz, reply_sz)); + +@@ -2850,6 +3010,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + } + + facts->MsgVersion = le16_to_cpu(facts->MsgVersion); ++ if (facts->MsgVersion == MPI_VERSION_01_05) ++ facts->HeaderVersion = le16_to_cpu(facts->HeaderVersion); + facts->MsgContext = le32_to_cpu(facts->MsgContext); + facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); + facts->IOCStatus = le16_to_cpu(facts->IOCStatus); +@@ -2865,7 +3027,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + * Old: u16{Major(4),Minor(4),SubMinor(8)} + * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} + */ +- if (facts->MsgVersion < 0x0102) { ++ if (facts->MsgVersion < MPI_VERSION_01_02) { + /* + * Handle old FC f/w style, convert to new... + */ +@@ -2877,9 +3039,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); + + facts->ProductID = le16_to_cpu(facts->ProductID); ++ + if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) + > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) + ioc->ir_firmware = 1; ++ + facts->CurrentHostMfaHighAddr = + le32_to_cpu(facts->CurrentHostMfaHighAddr); + facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); +@@ -2895,7 +3059,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + * to 14 in MPI-1.01.0x. + */ + if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && +- facts->MsgVersion > 0x0100) { ++ facts->MsgVersion > MPI_VERSION_01_00) { + facts->FWImageSize = le32_to_cpu(facts->FWImageSize); + } + +@@ -2956,7 +3120,6 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetPortFacts - Send PortFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2964,7 +3127,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + * @sleepFlag: Specifies whether the process can sleep + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) + { +@@ -2977,8 +3140,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { +- printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n", +- ioc->name, ioc->last_state ); ++ printk(MYIOC_s_ERR_FMT "Can't get PortFacts, " ++ " NOT READY! (%08x)\n", ioc->name, ioc->last_state ); + return -4; + } + +@@ -2996,14 +3159,14 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + get_pfacts.PortNumber = portnum; + /* Assert: All other get_pfacts fields are zero! */ + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n", +- ioc->name, portnum)); ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", ++ ioc->name, portnum)); + + /* No non-zero fields in the get_pfacts request are greater than + * 1 byte in size, so we can just fire it off as is. + */ + ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, +- reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); ++ reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); + if (ii != 0) + return ii; + +@@ -3038,7 +3201,6 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendIocInit - Send IOCInit request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3047,7 +3209,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) + { +@@ -3077,7 +3239,8 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF + + ioc_init.MaxDevices = (U8)ioc->devices_per_bus; + ioc_init.MaxBuses = (U8)ioc->number_of_buses; +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n", ++ ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n", + ioc->name, ioc->facts.MsgVersion)); + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { + // set MsgVersion and HeaderVersion host driver was built with +@@ -3091,7 +3254,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF + } + ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ + +- if (sizeof(dma_addr_t) == sizeof(u64)) { ++ if (ioc->sg_addr_size == sizeof(u64)) { + /* Save the upper 32-bits of the request + * (reply) and sense buffers. + */ +@@ -3160,7 +3323,6 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF + return r; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendPortEnable - Send PortEnable request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3170,7 +3332,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF + * Send PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) + { +@@ -3193,7 +3355,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int por + /* port_enable.MsgFlags = 0; */ + /* port_enable.MsgContext = 0; */ + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n", ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", + ioc->name, portnum, &port_enable)); + + /* RAID FW may take a long time to enable +@@ -3273,7 +3435,6 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) + ioc->cached_fw = NULL; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3286,7 +3447,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) + * on the bound IOC, the second image is discarded + * and memory is free'd. Both channels must upload to prevent + * IOC from running in degraded mode. +- */ ++ **/ + static int + mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) + { +@@ -3294,22 +3455,19 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + FWUpload_t *prequest; + FWUploadReply_t *preply; + FWUploadTCSGE_t *ptcsge; +- int sgeoffset; + u32 flagsLength; +- int ii, sz, reply_sz; ++ int ii, reply_sz; + int cmdStatus; ++ int request_size; + + /* If the image size is 0, we are done. + */ +- if ((sz = ioc->facts.FWImageSize) == 0) ++ if (!ioc->facts.FWImageSize) + return 0; + + if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) + return -ENOMEM; + +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", +- ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); +- + prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : + kzalloc(ioc->req_sz, GFP_KERNEL); + if (!prequest) { +@@ -3326,49 +3484,47 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + + prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; + prequest->Function = MPI_FUNCTION_FW_UPLOAD; +- + ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; + ptcsge->DetailsLength = 12; + ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; +- ptcsge->ImageSize = cpu_to_le32(sz); ++ ptcsge->ImageSize = cpu_to_le32(ioc->facts.FWImageSize); + ptcsge++; + +- sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); +- +- flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; +- mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); +- +- sgeoffset += sizeof(u32) + sizeof(dma_addr_t); +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n", +- ioc->name, prequest, sgeoffset)); ++ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | ioc->facts.FWImageSize; ++ ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); ++ request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + ++ ioc->SGE_size; ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " ++ " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, ++ ioc->facts.FWImageSize, request_size)); + DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); + +- ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, +- reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); ++ ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32*)prequest, ++ reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii)); ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " ++ "rc=%x \n", ioc->name, ii)); + + cmdStatus = -EFAULT; + if (ii == 0) { + /* Handshake transfer was complete and successful. + * Check the Reply Frame. + */ +- int status, transfer_sz; +- status = le16_to_cpu(preply->IOCStatus); +- if (status == MPI_IOCSTATUS_SUCCESS) { +- transfer_sz = le32_to_cpu(preply->ActualImageSize); +- if (transfer_sz == sz) +- cmdStatus = 0; +- } ++ int status; ++ status = le16_to_cpu(preply->IOCStatus) & ++ MPI_IOCSTATUS_MASK; ++ if (status == MPI_IOCSTATUS_SUCCESS && ++ ioc->facts.FWImageSize == ++ le32_to_cpu(preply->ActualImageSize)); ++ cmdStatus = 0; + } +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n", +- ioc->name, cmdStatus)); ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n", ++ ioc->name, cmdStatus)); + + + if (cmdStatus) { +- +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n", +- ioc->name)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " ++ "freeing image \n", ioc->name)); + mpt_free_fw_memory(ioc); + } + kfree(prequest); +@@ -3376,7 +3532,6 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + return cmdStatus; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_downloadboot - DownloadBoot code + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3389,7 +3544,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + * -1 FW Image size is 0 + * -2 No valid cached_fw Pointer + * <0 for fw upload failure. +- */ ++ **/ + static int + mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) + { +@@ -3401,10 +3556,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + u32 diagRwData; + u32 nextImage; + u32 load_addr; +- u32 ioc_state=0; ++ u32 doorbell; + + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", +- ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); ++ ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); + + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); +@@ -3416,11 +3571,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); + + /* wait 1 msec */ +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep(1); +- } else { +- mdelay (1); +- } ++ else ++ mdelay(1); + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); +@@ -3433,11 +3587,10 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + break; + } + /* wait .1 sec */ +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep (100); +- } else { ++ else + mdelay (100); +- } + } + + if ( count == 30 ) { +@@ -3455,6 +3608,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + + /* Set the DiagRwEn and Disable ARM bits */ ++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); + + fwSize = (pFwHeader->ImageSize + 3)/4; +@@ -3468,13 +3622,12 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n", +- ioc->name, pFwHeader->LoadStartAddress)); ++ ioc->name, pFwHeader->LoadStartAddress)); + + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n", +- ioc->name, fwSize*4, ptrFw)); +- while (fwSize--) { ++ ioc->name, fwSize*4, ptrFw)); ++ while (fwSize--) + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); +- } + + nextImage = pFwHeader->NextImageHeaderOffset; + while (nextImage) { +@@ -3486,21 +3639,22 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + ptrFw = (u32 *)pExtImage; + + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", +- ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); ++ ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); + +- while (fwSize--) { ++ while (fwSize--) + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); +- } + nextImage = pExtImage->NextImageHeaderOffset; + } + + /* Write the IopResetVectorRegAddr */ +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ++ ioc->name, pFwHeader->IopResetRegAddr)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); + + /* Write the IopResetVectorValue */ +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ++ ioc->name, pFwHeader->IopResetVectorValue)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); + + /* Clear the internal flash bad bit - autoincrementing register, +@@ -3517,75 +3671,75 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); + +- } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { +- diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +- CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | +- MPI_DIAG_CLEAR_FLASH_BAD_SIG); +- +- /* wait 1 msec */ +- if (sleepFlag == CAN_SLEEP) { +- msleep (1); +- } else { +- mdelay (1); +- } + } + + if (ioc->errata_flag_1064) + pci_disable_io_access(ioc->pcidev); + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, " +- "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", +- ioc->name, diag0val)); +- diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n", +- ioc->name, diag0val)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x, turning off" ++ " PREVENT_IOC_BOOT and DISABLE_ARM\n", ioc->name, diag0val)); ++ diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "diag0val=%x\n", ++ ioc->name, diag0val)); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + +- /* Write 0xFF to reset the sequencer */ +- CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); ++ if (ioc->bus_type == SAS ) { ++ /* wait 1 sec */ ++ if (sleepFlag == CAN_SLEEP) ++ msleep(1000); ++ else ++ mdelay(1000); + +- if (ioc->bus_type == SAS) { +- ioc_state = mpt_GetIocState(ioc, 0); +- if ( (GetIocFacts(ioc, sleepFlag, +- MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n", +- ioc->name, ioc_state)); +- return -EFAULT; ++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); ++ ddlprintk(ioc, printk (MYIOC_s_DEBUG_FMT ++ "diag0val=%x, turning off RW_ENABLE\n", ioc->name, ++ diag0val)); ++ diag0val &= ~(MPI_DIAG_RW_ENABLE); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "now diag0val=%x\n", ioc->name, diag0val)); ++ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); ++ ++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); ++ if (diag0val & MPI_DIAG_FLASH_BAD_SIG) { ++ diag0val |= MPI_DIAG_CLEAR_FLASH_BAD_SIG; ++ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); ++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + } ++ diag0val &= ~(MPI_DIAG_DISABLE_ARM); ++ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); ++ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); ++ CHIPREG_WRITE32(&ioc->chip->DiagRwAddress, 0x3f000004); + } + +- for (count=0; countname, count, ioc_state)); +- if (ioc->bus_type == SAS) { ++ /* Write 0xFF to reset the sequencer */ ++ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); ++ ++ for (count = 0; count < 30; count ++) { ++ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_IOC_STATE_MASK; ++ if (doorbell == MPI_IOC_STATE_READY) { ++ if (ioc->bus_type == SAS) + return 0; +- } + if ((SendIocInit(ioc, sleepFlag)) != 0) { +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "downloadboot: SendIocInit failed\n", +- ioc->name)); ++ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "SendIocInit failed\n", ioc->name)); + return -EFAULT; + } + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "downloadboot: SendIocInit successful\n", +- ioc->name)); ++ "SendIocInit successful\n", ioc->name)); + return 0; + } +- if (sleepFlag == CAN_SLEEP) { +- msleep (10); +- } else { +- mdelay (10); +- } ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE:" ++ " doorbell=%x count=%d\n", ioc->name, doorbell, count)); ++ if (sleepFlag == CAN_SLEEP) ++ msleep(1000); ++ else ++ mdelay(1000); + } +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "downloadboot failed! IocState=%x\n",ioc->name, ioc_state)); ++ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT "downloadboot failed! count=%d\n", ioc->name, count)); + return -EFAULT; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * KickStart - Perform hard reset of MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3610,7 +3764,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + * OR reset but failed to come READY + * -2 - no reset, could not enter DIAG mode + * -3 - reset but bad FW bit +- */ ++ **/ + static int + KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) + { +@@ -3618,7 +3772,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i + u32 ioc_state=0; + int cnt,cntdn; + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name)); ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": KickStart\n", ioc->name)); + if (ioc->bus_type == SPI) { + /* Always issue a Msg Unit Reset first. This will clear some + * SCSI bus hang conditions. +@@ -3636,14 +3790,15 @@ KickStart(MPT_ADAPTER *ioc, int force, i + if (hard_reset_done < 0) + return hard_reset_done; + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n", +- ioc->name)); ++ /* may not have worked but hard_reset_done doesn't always signal failure */ ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Diagnostic reset completed!\n", ++ ioc->name)); + + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ + for (cnt=0; cntname, cnt)); + return hard_reset_done; + } +@@ -3655,11 +3810,10 @@ KickStart(MPT_ADAPTER *ioc, int force, i + } + + dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", +- ioc->name, mpt_GetIocState(ioc, 0))); ++ ioc->name, mpt_GetIocState(ioc, 0))); + return -1; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_diag_reset - Perform hard reset of the adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3677,30 +3831,46 @@ KickStart(MPT_ADAPTER *ioc, int force, i + * 0 no reset performed because reset history bit set + * -2 enabling diagnostic mode failed + * -3 diagnostic reset failed +- */ ++ **/ + static int + mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) + { + u32 diag0val; +- u32 doorbell; ++ u32 doorbell = 0; + int hard_reset_done = 0; + int count = 0; + u32 diag1val = 0; + MpiFwHeader_t *cached_fw; /* Pointer to FW */ ++ u8 cb_idx; + + /* Clear any existing interrupts */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { ++ ++ if (!ignore) ++ return 0; ++ + drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " +- "address=%p\n", ioc->name, __func__, +- &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); ++ "address=%p\n", ioc->name, __FUNCTION__, &ioc->chip->Doorbell, ++ &ioc->chip->Reset_1078)); + CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); + if (sleepFlag == CAN_SLEEP) + msleep(1); + else + mdelay(1); + ++ /* ++ * Call each currently registered protocol IOC reset handler ++ * with pre-reset indication. ++ * NOTE: If we're doing _IOC_BRINGUP, there can be no ++ * MptResetHandlers[] registered yet. ++ */ ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) ++ (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET); ++ } ++ + for (count = 0; count < 60; count ++) { + doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); + doorbell &= MPI_IOC_STATE_MASK; +@@ -3709,9 +3879,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + "looking for READY STATE: doorbell=%x" + " count=%d\n", + ioc->name, doorbell, count)); +- if (doorbell == MPI_IOC_STATE_READY) { ++ ++ if (doorbell == MPI_IOC_STATE_READY) + return 1; +- } ++ ++ /* ++ * Early out for hard fault ++ */ ++ if (count && doorbell == MPI_IOC_STATE_FAULT) ++ break; + + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) +@@ -3719,16 +3895,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + else + mdelay(1000); + } ++ ++ if (doorbell != MPI_IOC_STATE_READY) ++ printk(MYIOC_s_ERR_FMT "Failed to come READY after " ++ "reset! IocState=%x", ioc->name, doorbell); + return -1; + } + + /* Use "Diagnostic reset" method! (only thing available!) */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + +- if (ioc->debug_level & MPT_DEBUG) { ++ if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } + +@@ -3748,11 +3928,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + + /* wait 100 msec */ +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep (100); +- } else { ++ else + mdelay (100); +- } + + count++; + if (count > 20) { +@@ -3764,14 +3943,14 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", + ioc->name, diag0val)); + } + +- if (ioc->debug_level & MPT_DEBUG) { ++ if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } + /* +@@ -3787,7 +3966,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + */ + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); + hard_reset_done = 1; +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", + ioc->name)); + + /* +@@ -3796,25 +3975,13 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + * NOTE: If we're doing _IOC_BRINGUP, there can be no + * MptResetHandlers[] registered yet. + */ +- { +- u8 cb_idx; +- int r = 0; +- +- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { +- if (MptResetHandlers[cb_idx]) { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Calling IOC pre_reset handler #%d\n", +- ioc->name, cb_idx)); +- r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); +- if (ioc->alt_ioc) { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Calling alt-%s pre_reset handler #%d\n", +- ioc->name, ioc->alt_ioc->name, cb_idx)); +- r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); +- } ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) { ++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); ++ if (ioc->alt_ioc) { ++ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); + } + } +- /* FIXME? Examine results here? */ + } + + if (ioc->cached_fw) +@@ -3834,20 +4001,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + break; + } + +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", + ioc->name, diag0val, count)); + /* wait 1 sec */ +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep (1000); +- } else { ++ else + mdelay (1000); +- } + } + if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) { + printk(MYIOC_s_WARN_FMT + "firmware downloadboot failure (%d)!\n", ioc->name, count); + } +- + } else { + /* Wait for FW to reload and for board + * to go to the READY state. +@@ -3859,25 +4024,38 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); + doorbell &= MPI_IOC_STATE_MASK; + +- if (doorbell == MPI_IOC_STATE_READY) { ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "looking for READY STATE: doorbell=%x" ++ " count=%d\n", ioc->name, doorbell, count)); ++ ++ if (doorbell == MPI_IOC_STATE_READY) ++ break; ++ ++ /* ++ * Early out for hard fault ++ */ ++ if (count && doorbell == MPI_IOC_STATE_FAULT) + break; +- } + + /* wait 1 sec */ +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep (1000); +- } else { ++ else + mdelay (1000); +- } + } ++ ++ if (doorbell != MPI_IOC_STATE_READY) ++ printk(MYIOC_s_ERR_FMT "Failed to come READY " ++ "after reset! IocState=%x", ioc->name, ++ doorbell); + } + } + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +- if (ioc->debug_level & MPT_DEBUG) { ++ if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } + +@@ -3898,11 +4076,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + + /* wait 100 msec */ +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep (100); +- } else { ++ else + mdelay (100); +- } + + count++; + if (count > 20) { +@@ -3933,11 +4110,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + return -3; + } + +- if (ioc->debug_level & MPT_DEBUG) { ++ if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", +- ioc->name, diag0val, diag1val)); ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", ++ ioc->name, diag0val, diag1val)); + } + + /* +@@ -3951,7 +4128,6 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + return hard_reset_done; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendIocReset - Send IOCReset request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3962,7 +4138,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + * Send IOCReset request to the MPT adapter. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) + { +@@ -3973,7 +4149,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n", + ioc->name, reset_type)); + CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<name, (int)((count+5)/HZ)); ++ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n", ++ ioc->name, state, (int)((count+5)/HZ)); + return -ETIME; + } + + if (sleepFlag == CAN_SLEEP) { + msleep(1); + } else { +- mdelay (1); /* 1 msec delay */ ++ mdelay(1); /* 1 msec delay */ + } + } + +@@ -4010,14 +4186,13 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * initChainBuffers - Allocate memory for and initialize chain buffers + * @ioc: Pointer to MPT_ADAPTER structure + * + * Allocates memory for and initializes chain buffers, + * chain buffer control arrays and spinlock. +- */ ++ **/ + static int + initChainBuffers(MPT_ADAPTER *ioc) + { +@@ -4059,24 +4234,30 @@ initChainBuffers(MPT_ADAPTER *ioc) + * num_sge = num sge in request frame + last chain buffer + * scale = num sge per chain buffer if no chain element + */ +- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); +- if (sizeof(dma_addr_t) == sizeof(u64)) +- num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); ++ scale = ioc->req_sz/ ioc->SGE_size; ++ if (ioc->sg_addr_size == sizeof(u64)) ++ num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; + else +- num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); ++ num_sge = 1+ scale + (ioc->req_sz - 64) / ioc->SGE_size; + +- if (sizeof(dma_addr_t) == sizeof(u64)) { ++ if (ioc->sg_addr_size == sizeof(u64)) { + numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); ++ (ioc->req_sz - 60) / ioc->SGE_size; + } else { + numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); ++ (ioc->req_sz - 64) / ioc->SGE_size; + } + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", + ioc->name, num_sge, numSGE)); + +- if ( numSGE > MPT_SCSI_SG_DEPTH ) +- numSGE = MPT_SCSI_SG_DEPTH; ++ if (ioc->bus_type == FC) { ++ if (numSGE > MPT_SCSI_FC_SG_DEPTH) ++ numSGE = MPT_SCSI_FC_SG_DEPTH; ++ } ++ else { ++ if (numSGE > MPT_SCSI_SG_DEPTH) ++ numSGE = MPT_SCSI_SG_DEPTH; ++ } + + num_chain = 1; + while (numSGE - num_sge > 0) { +@@ -4111,7 +4292,6 @@ initChainBuffers(MPT_ADAPTER *ioc) + return num_chain; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4121,7 +4301,7 @@ initChainBuffers(MPT_ADAPTER *ioc) + * reply frames. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + PrimeIocFifos(MPT_ADAPTER *ioc) + { +@@ -4130,13 +4310,36 @@ PrimeIocFifos(MPT_ADAPTER *ioc) + dma_addr_t alloc_dma; + u8 *mem; + int i, reply_sz, sz, total_size, num_chain; ++ u64 dma_mask; + +- /* Prime reply FIFO... */ ++ dma_mask = 0; + ++ /* Prime reply FIFO... */ + if (ioc->reply_frames == NULL) { + if ( (num_chain = initChainBuffers(ioc)) < 0) + return -1; + ++ /* ++ * 1078 errata workaround for the 36GB limitation ++ */ ++ if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && ++ ioc->dma_mask > MPT_DMA_35BIT_MASK) { ++ if (!pci_set_dma_mask(ioc->pcidev, DMA_32BIT_MASK) ++ && !pci_set_consistent_dma_mask(ioc->pcidev, ++ DMA_32BIT_MASK)) { ++ dma_mask = MPT_DMA_35BIT_MASK; ++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "setting 35 bit addressing for " ++ "Request/Reply/Chain and Sense Buffers\n", ++ ioc->name)); ++ } else { ++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "failed setting 35 bit addressing for " ++ "Request/Reply/Chain and Sense Buffers\n", ++ ioc->name)); ++ } ++ } ++ + total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", + ioc->name, ioc->reply_sz, ioc->reply_depth)); +@@ -4274,9 +4477,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc) + alloc_dma += ioc->reply_sz; + } + ++ if (dma_mask == MPT_DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev, ++ ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev, ++ ioc->dma_mask)) ++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "restoring 64 bit addressing\n", ioc->name)); ++ + return 0; + + out_fail: ++ + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; + pci_free_consistent(ioc->pcidev, +@@ -4293,10 +4503,16 @@ out_fail: + ioc->sense_buf_pool, ioc->sense_buf_pool_dma); + ioc->sense_buf_pool = NULL; + } ++ ++ if (dma_mask == MPT_DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev, ++ DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(ioc->pcidev, ++ DMA_64BIT_MASK)) ++ d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "restoring 64 bit addressing\n", ioc->name)); ++ + return -1; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_handshake_req_reply_wait - Send MPT request to and receive reply + * from IOC via doorbell handshake method. +@@ -4314,7 +4530,7 @@ out_fail: + * greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, + int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) +@@ -4408,7 +4624,6 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER + return -failcnt; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4420,7 +4635,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER + * bit in its IntStatus register being clear. + * + * Returns a negative value on failure, else wait loop count. +- */ ++ **/ + static int + WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) + { +@@ -4459,7 +4674,6 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int + return -1; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4470,7 +4684,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int + * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. + * + * Returns a negative value on failure, else wait loop count. +- */ ++ **/ + static int + WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) + { +@@ -4481,18 +4695,18 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int + cntdn = 1000 * howlong; + if (sleepFlag == CAN_SLEEP) { + while (--cntdn) { ++ msleep(1); + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; +- msleep(1); + count++; + } + } else { + while (--cntdn) { ++ udelay (1000); + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; +- udelay (1000); + count++; + } + } +@@ -4508,7 +4722,6 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int + return -1; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4520,7 +4733,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int + * of 128 bytes of reply data. + * + * Returns a negative value on failure, else size of reply in WORDS. +- */ ++ **/ + static int + WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) + { +@@ -4594,7 +4807,6 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i + return u16cnt/2; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetLanConfigPages - Fetch LANConfig pages. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4604,7 +4816,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) +- */ ++ **/ + static int + GetLanConfigPages(MPT_ADAPTER *ioc) + { +@@ -4705,7 +4917,6 @@ GetLanConfigPages(MPT_ADAPTER *ioc) + return rc; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4718,9 +4929,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) + * NOTE: Don't use not this function during interrupt time. + * + * Returns 0 for success, non-zero error +- */ +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++ **/ + int + mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) + { +@@ -4728,7 +4937,14 @@ mptbase_sas_persist_operation(MPT_ADAPTE + SasIoUnitControlReply_t *sasIoUnitCntrReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; ++ int ret = 0; ++ unsigned long timeleft; ++ ++ mutex_lock(&ioc->mptbase_cmds.mutex); + ++ /* init the internal cmd struct */ ++ memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); ++ INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) + + /* insure garbage is not sent to fw */ + switch(persist_opcode) { +@@ -4738,17 +4954,18 @@ mptbase_sas_persist_operation(MPT_ADAPTE + break; + + default: +- return -1; +- break; ++ ret = -1; ++ goto out; + } + +- printk("%s: persist_opcode=%x\n",__func__, persist_opcode); ++ printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { +- printk("%s: no msg frames!\n",__func__); +- return -1; ++ printk("%s: no msg frames!\n",__FUNCTION__); ++ ret = -1; ++ goto out; + } + + mpi_hdr = (MPIHeader_t *) mf; +@@ -4758,31 +4975,44 @@ mptbase_sas_persist_operation(MPT_ADAPTE + sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq->Operation = persist_opcode; + +- init_timer(&ioc->persist_timer); +- ioc->persist_timer.data = (unsigned long) ioc; +- ioc->persist_timer.function = mpt_timer_expired; +- ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */; +- ioc->persist_wait_done=0; +- add_timer(&ioc->persist_timer); + mpt_put_msg_frame(mpt_base_index, ioc, mf); +- wait_event(mpt_waitq, ioc->persist_wait_done); ++ timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); ++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ ret = -ETIME; ++ printk("%s: failed\n", __FUNCTION__); ++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out; ++ if (!timeleft) { ++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ mpt_free_msg_frame(ioc, mf); ++ } ++ goto out; ++ } ++ ++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ ret = -1; ++ goto out; ++ } + + sasIoUnitCntrReply = +- (SasIoUnitControlReply_t *)ioc->persist_reply_frame; ++ (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; + if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { +- printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", +- __func__, +- sasIoUnitCntrReply->IOCStatus, +- sasIoUnitCntrReply->IOCLogInfo); +- return -1; +- } ++ printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", __FUNCTION__, ++ sasIoUnitCntrReply->IOCStatus, sasIoUnitCntrReply->IOCLogInfo); ++ printk("%s: failed\n",__FUNCTION__); ++ ret = -1; ++ } else ++ printk("%s: success\n",__FUNCTION__); ++ out: + +- printk("%s: success\n",__func__); +- return 0; ++ CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) ++ mutex_unlock(&ioc->mptbase_cmds.mutex); ++ return ret; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +- + static void + mptbase_raid_process_event_data(MPT_ADAPTER *ioc, + MpiEventDataRaid_t * pRaidEventData) +@@ -4913,7 +5143,6 @@ mptbase_raid_process_event_data(MPT_ADAP + } + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetIoUnitPage2 - Retrieve BIOS version and boot order information. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4923,7 +5152,7 @@ mptbase_raid_process_event_data(MPT_ADAP + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) +- */ ++ **/ + static int + GetIoUnitPage2(MPT_ADAPTER *ioc) + { +@@ -4971,7 +5200,6 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) + return rc; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 + * @ioc: Pointer to a Adapter Strucutre +@@ -4991,7 +5219,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) + * Both valid + * Return 0 + * CHECK - what type of locking mechanisms should be used???? +- */ ++ **/ + static int + mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) + { +@@ -5051,8 +5279,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; + rc = 1; + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Unable to read PortPage0 minSyncFactor=%x\n", +- ioc->name, ioc->spi_data.minSyncFactor)); ++ "Unable to read PortPage0 minSyncFactor=%x\n", ++ ioc->name, ioc->spi_data.minSyncFactor)); + } else { + /* Save the Port Page 0 data + */ +@@ -5062,8 +5290,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { + ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "noQas due to Capabilities=%x\n", ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "noQas due to Capabilities=%x\n", + ioc->name, pPP0->Capabilities)); + } + ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; +@@ -5072,8 +5299,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + ioc->spi_data.maxSyncOffset = (u8) (data >> 16); + data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; + ioc->spi_data.minSyncFactor = (u8) (data >> 8); +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "PortPage0 minSyncFactor=%x\n", ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); + } else { + ioc->spi_data.maxSyncOffset = 0; +@@ -5089,8 +5315,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + + if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { + ioc->spi_data.minSyncFactor = MPT_ULTRA; +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "HVD or SE detected, minSyncFactor=%x\n", ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HVD or SE detected, minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); + } + } +@@ -5195,7 +5420,6 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + return rc; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_readScsiDevicePageHeaders - save version and length of SDP1 + * @ioc: Pointer to a Adapter Strucutre +@@ -5203,7 +5427,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + * + * Return: -EFAULT if read of config page header fails + * or 0 if success. +- */ ++ **/ + static int + mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) + { +@@ -5246,9 +5470,73 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE + return 0; + } + ++static void ++mpt_read_ioc_pg_6(MPT_ADAPTER *ioc) ++{ ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t header; ++ IOCPage6_t *pIoc6=NULL; ++ dma_addr_t ioc6_dma; ++ int iocpage6sz; ++ void *mem; ++ ++ /* Free the old page ++ */ ++ if (ioc->raid_data.pIocPg6) { ++ kfree(ioc->raid_data.pIocPg6); ++ ioc->raid_data.pIocPg6 = NULL; ++ } ++ ++ /* There is at least one physical disk. ++ * Read and save IOC Page 3 ++ */ ++ header.PageVersion = 0; ++ header.PageLength = 0; ++ header.PageNumber = 6; ++ header.PageType = MPI_CONFIG_PAGETYPE_IOC; ++ cfg.cfghdr.hdr = &header; ++ cfg.physAddr = -1; ++ cfg.pageAddr = 0; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; ++ cfg.timeout = 0; ++ if (mpt_config(ioc, &cfg) != 0) ++ goto out; ++ ++ if (header.PageLength == 0) ++ goto out; ++ ++ /* Read Header good, alloc memory ++ */ ++ iocpage6sz = header.PageLength * 4; ++ pIoc6 = pci_alloc_consistent(ioc->pcidev, iocpage6sz, &ioc6_dma); ++ if (!pIoc6) ++ goto out; ++ ++ /* Read the Page and save the data ++ * into malloc'd memory. ++ */ ++ cfg.physAddr = ioc6_dma; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ if (mpt_config(ioc, &cfg) != 0) ++ goto out; ++ ++ mem = kmalloc(iocpage6sz, GFP_ATOMIC); ++ if (!mem) ++ goto out; ++ ++ memcpy(mem, pIoc6, iocpage6sz); ++ ioc->raid_data.pIocPg6 = mem; ++ ++ out: ++ if (pIoc6) ++ pci_free_consistent(ioc->pcidev, iocpage6sz, pIoc6, ioc6_dma); ++} ++ + /** +- * mpt_inactive_raid_list_free - This clears this link list. +- * @ioc : pointer to per adapter structure ++ * mpt_inactive_raid_list_free - This clears this link list. ++ * @ioc : pointer to per adapter structure ++ * + **/ + static void + mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) +@@ -5258,21 +5546,23 @@ mpt_inactive_raid_list_free(MPT_ADAPTER + if (list_empty(&ioc->raid_data.inactive_list)) + return; + +- mutex_lock(&ioc->raid_data.inactive_list_mutex); ++ down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry_safe(component_info, pNext, + &ioc->raid_data.inactive_list, list) { + list_del(&component_info->list); + kfree(component_info); + } +- mutex_unlock(&ioc->raid_data.inactive_list_mutex); ++ up(&ioc->raid_data.inactive_list_mutex); + } + + /** +- * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume +- * +- * @ioc : pointer to per adapter structure +- * @channel : volume channel +- * @id : volume target id ++ * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums ++ * for devices belonging in an inactive volume ++ * ++ * @ioc : pointer to per adapter structure ++ * @channel : volume channel ++ * @id : volume target id ++ * + **/ + static void + mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) +@@ -5281,10 +5571,12 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidVolumePage0_t buffer = NULL; +- int i; ++ int i, j; + RaidPhysDiskPage0_t phys_disk; ++ RaidPhysDiskPage1_t *phys_disk_1; + struct inactive_raid_component_info *component_info; + int handle_inactive_volumes; ++ int num_paths, device_is_online; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); +@@ -5323,14 +5615,37 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + if (!handle_inactive_volumes) + goto out; + +- mutex_lock(&ioc->raid_data.inactive_list_mutex); ++ down(&ioc->raid_data.inactive_list_mutex); + for (i = 0; i < buffer->NumPhysDisks; i++) { + if(mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) + continue; + ++ if (phys_disk.PhysDiskStatus.State != ++ MPI_PHYSDISK0_STATUS_ONLINE) ++ continue; ++ ++ /* check to see if device is online by checking phys_disk_pg1 */ ++ device_is_online = 0; ++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc, ++ buffer->PhysDisk[i].PhysDiskNum); ++ if (num_paths < 2) ++ continue; ++ phys_disk_1 = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); ++ if (!phys_disk_1) ++ continue; ++ mpt_raid_phys_disk_pg1(ioc, buffer->PhysDisk[i].PhysDiskNum, ++ phys_disk_1); ++ for (j = 0; j < num_paths && !device_is_online; j++) ++ if (!phys_disk_1->Path[j].Flags) ++ device_is_online = 1; ++ kfree(phys_disk_1); ++ if (!device_is_online) ++ continue; ++ + if ((component_info = kmalloc(sizeof (*component_info), +- GFP_KERNEL)) == NULL) ++ GFP_KERNEL)) == NULL) + continue; + + component_info->volumeID = id; +@@ -5343,7 +5658,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + list_add_tail(&component_info->list, + &ioc->raid_data.inactive_list); + } +- mutex_unlock(&ioc->raid_data.inactive_list_mutex); ++ up(&ioc->raid_data.inactive_list_mutex); + + out: + if (buffer) +@@ -5363,7 +5678,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + * -ENOMEM if pci_alloc failed + **/ + int +-mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk) ++mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage0_t *phys_disk) + { + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; +@@ -5373,7 +5688,9 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); ++ memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); + ++ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; +@@ -5420,6 +5737,181 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, + } + + /** ++ * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num ++ * @ioc: Pointer to a Adapter Structure ++ * @phys_disk_num: io unit unique phys disk num generated by the ioc ++ * ++ * Return: ++ * returns number paths ++ **/ ++int ++mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) ++{ ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t hdr; ++ dma_addr_t dma_handle; ++ pRaidPhysDiskPage1_t buffer = NULL; ++ int rc; ++ ++ memset(&cfg, 0 , sizeof(CONFIGPARMS)); ++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); ++ ++ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; ++ hdr.PageNumber = 1; ++ cfg.cfghdr.hdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ rc = 0; ++ goto out; ++ } ++ ++ if (!hdr.PageLength) { ++ rc = 0; ++ goto out; ++ } ++ ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, ++ &dma_handle); ++ ++ if (!buffer) { ++ rc = 0; ++ goto out; ++ } ++ ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = phys_disk_num; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ rc = 0; ++ goto out; ++ } ++ ++ rc = buffer->NumPhysDiskPaths; ++ out: ++ ++ if (buffer) ++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, ++ dma_handle); ++ ++ return rc; ++} ++ ++/** ++ * mpt_raid_phys_disk_pg1 - returns phys disk page 1 ++ * @ioc: Pointer to a Adapter Structure ++ * @phys_disk_num: io unit unique phys disk num generated by the ioc ++ * @phys_disk: requested payload data returned ++ * ++ * Return: ++ * 0 on success ++ * -EFAULT if read of config page header fails or data pointer not NULL ++ * -ENOMEM if pci_alloc failed ++ **/ ++int ++mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage1_t *phys_disk) ++{ ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t hdr; ++ dma_addr_t dma_handle; ++ pRaidPhysDiskPage1_t buffer = NULL; ++ int rc; ++ int i; ++ __le64 sas_address; ++ ++ memset(&cfg, 0 , sizeof(CONFIGPARMS)); ++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); ++ rc = 0; ++ ++ hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; ++ hdr.PageNumber = 1; ++ cfg.cfghdr.hdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ if (!hdr.PageLength) { ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, ++ &dma_handle); ++ ++ if (!buffer) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ cfg.pageAddr = phys_disk_num; ++ ++ if (mpt_config(ioc, &cfg) != 0) { ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; ++ phys_disk->PhysDiskNum = phys_disk_num; ++ for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { ++ phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; ++ phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; ++ phys_disk->Path[i].OwnerIdentifier = buffer->Path[i].OwnerIdentifier; ++ phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); ++ memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); ++ sas_address = le64_to_cpu(sas_address); ++ memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); ++ memcpy(&sas_address, &buffer->Path[i].OwnerWWID, sizeof(__le64)); ++ sas_address = le64_to_cpu(sas_address); ++ memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, sizeof(__le64)); ++ } ++ ++ out: ++ ++ if (buffer) ++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, ++ dma_handle); ++ ++ return rc; ++} ++ ++/** ++ * mpt_sort_ioc_pg2 - compare function for sorting volumes ++ * in ascending order ++ * @a: ioc_pg2 raid volume page ++ * @b: ioc_pg2 raid volume page ++ * ++ * Return: ++ * 0 same, 1 (a is bigger), -1 (b is bigger) ++ **/ ++static int ++mpt_sort_ioc_pg2(const void *a, const void *b) ++{ ++ ConfigPageIoc2RaidVol_t * volume_a = (ConfigPageIoc2RaidVol_t *)a; ++ ConfigPageIoc2RaidVol_t * volume_b = (ConfigPageIoc2RaidVol_t *)b; ++ ++ if (volume_a->VolumeBus == volume_b->VolumeBus) { ++ if (volume_a->VolumeID == volume_b->VolumeID) ++ return 0; ++ if (volume_a->VolumeID < volume_b->VolumeID) ++ return -1; ++ return 1; ++ } ++ if (volume_a->VolumeBus < volume_b->VolumeBus) ++ return -1; ++ return 1; ++} ++ ++/** + * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes + * @ioc: Pointer to a Adapter Strucutre + * @portnum: IOC port number +@@ -5482,16 +5974,22 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) + if (!mem) + goto out; + ++ /* ++ * sort volumes in ascending order ++ */ ++ sort(pIoc2->RaidVolume, pIoc2->NumActiveVolumes, ++ sizeof(ConfigPageIoc2RaidVol_t), mpt_sort_ioc_pg2, NULL); + memcpy(mem, (u8 *)pIoc2, iocpage2sz); + ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; + +- mpt_read_ioc_pg_3(ioc); +- + for (i = 0; i < pIoc2->NumActiveVolumes ; i++) + mpt_inactive_raid_volumes(ioc, + pIoc2->RaidVolume[i].VolumeBus, + pIoc2->RaidVolume[i].VolumeID); + ++ mpt_read_ioc_pg_3(ioc); ++ mpt_read_ioc_pg_6(ioc); ++ + out: + pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); + +@@ -5651,6 +6149,9 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + ++#if defined(CPQ_CIM) ++ ioc->pci_slot_number = pIoc1->PCISlotNum; ++#endif + tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING; + if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) { + tmp = le32_to_cpu(pIoc1->CoalescingTimeout); +@@ -5671,19 +6172,16 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) + + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; + if (mpt_config(ioc, &cfg) == 0) { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Reset NVRAM Coalescing Timeout to = %d\n", ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout to = %d\n", + ioc->name, MPT_COALESCING_TIMEOUT)); + } else { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Reset NVRAM Coalescing Timeout Failed\n", +- ioc->name)); ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset NVRAM Coalescing Timeout Failed\n", ++ ioc->name)); + } + + } else { +- dprintk(ioc, printk(MYIOC_s_WARN_FMT +- "Reset of Current Coalescing Timeout Failed!\n", +- ioc->name)); ++ dprintk(ioc, printk(MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n", ++ ioc->name)); + } + } + +@@ -5740,43 +6238,39 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER * + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendEventNotification - Send EventNotification (on or off) request to adapter + * @ioc: Pointer to MPT_ADAPTER structure + * @EvSwitch: Event switch flags +- */ ++ * @sleepFlag: Specifies whether the process can sleep ++ **/ + static int +-SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) ++SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) + { +- EventNotification_t *evnp; +- +- evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc); +- if (evnp == NULL) { +- devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", +- ioc->name)); +- return 0; +- } +- memset(evnp, 0, sizeof(*evnp)); ++ EventNotification_t evn; ++ MPIDefaultReply_t reply_buf; + +- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp)); ++ memset(&evn, 0, sizeof(EventNotification_t)); ++ memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); + +- evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; +- evnp->ChainOffset = 0; +- evnp->MsgFlags = 0; +- evnp->Switch = EvSwitch; ++ evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; ++ evn.Switch = EvSwitch; ++ evn.MsgContext = cpu_to_le32(mpt_base_index << 16); + +- mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp); ++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Sending EventNotification (%d) request %p\n", ++ ioc->name, EvSwitch, &evn)); + +- return 0; ++ return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), ++ (u32*)&evn, sizeof(MPIDefaultReply_t), (u16*)&reply_buf, 30, ++ sleepFlag); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendEventAck - Send EventAck request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @evnp: Pointer to original EventNotification request +- */ ++ **/ + static int + SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) + { +@@ -5784,7 +6278,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti + + if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", +- ioc->name,__func__)); ++ ioc->name,__FUNCTION__)); + return -1; + } + +@@ -5803,7 +6297,6 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_config - Generic function to issue config message + * @ioc: Pointer to an adapter structure +@@ -5816,35 +6309,62 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) +- */ ++ **/ + int + mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) + { + Config_t *pReq; ++ ConfigReply_t *pReply; + ConfigExtendedPageHeader_t *pExtHdr = NULL; + MPT_FRAME_HDR *mf; +- unsigned long flags; +- int ii, rc; ++ int ii; + int flagsLength; +- int in_isr; ++ long timeout; ++ int ret; ++ u8 page_type = 0, extend_page; ++ unsigned long timeleft; ++ unsigned long flags; ++ u8 issue_hard_reset = 0; ++ u8 retry_count = 0; + +- /* Prevent calling wait_event() (below), if caller happens +- * to be in ISR context, because that is fatal! +- */ +- in_isr = in_interrupt(); +- if (in_isr) { +- dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", +- ioc->name)); ++ if (in_interrupt()) + return -EPERM; ++ ++ /* don't send a config page during diag reset */ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress) { ++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: busy with host reset\n", ioc->name, __FUNCTION__)); ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ return -EBUSY; ++ } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ ++ /* don't send if no chance of success */ ++ if (!ioc->active || ++ mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { ++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: ioc not operational, %d, %xh\n", ++ ioc->name, __FUNCTION__, ioc->active, ++ mpt_GetIocState(ioc, 0))); ++ return -EFAULT; + } + ++ retry_config: ++ mutex_lock(&ioc->mptbase_cmds.mutex); ++ /* init the internal cmd struct */ ++ memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); ++ INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) ++ + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { +- dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", +- ioc->name)); +- return -EAGAIN; ++ dcprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "mpt_config: no msg frames!\n", ioc->name)); ++ ret = -EAGAIN; ++ goto out; + } ++ + pReq = (Config_t *)mf; + pReq->Action = pCfg->action; + pReq->Reserved = 0; +@@ -5870,7 +6390,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + pReq->ExtPageType = pExtHdr->ExtPageType; + pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + +- /* Page Length must be treated as a reserved field for the extended header. */ ++ /* Page Length must be treated as a reserved field for the ++ * extended header. ++ */ + pReq->Header.PageLength = 0; + } + +@@ -5883,126 +6405,126 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + else + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; + +- if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { ++ if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == ++ MPI_CONFIG_PAGETYPE_EXTENDED) { + flagsLength |= pExtHdr->ExtPageLength * 4; +- +- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n", +- ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action)); +- } +- else { ++ page_type = pReq->ExtPageType; ++ extend_page = 1; ++ } else { + flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; +- +- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n", +- ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); ++ page_type = pReq->Header.PageType; ++ extend_page = 0; + } + +- mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); ++ dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Sending Config request type 0x%x, page 0x%x and action %d\n", ++ ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); + +- /* Append pCfg pointer to end of mf +- */ +- *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; +- +- /* Initalize the timer +- */ +- init_timer(&pCfg->timer); +- pCfg->timer.data = (unsigned long) ioc; +- pCfg->timer.function = mpt_timer_expired; +- pCfg->wait_done = 0; +- +- /* Set the timer; ensure 10 second minimum */ +- if (pCfg->timeout < 10) +- pCfg->timer.expires = jiffies + HZ*10; +- else +- pCfg->timer.expires = jiffies + HZ*pCfg->timeout; +- +- /* Add to end of Q, set timer and then issue this command */ +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- list_add_tail(&pCfg->linkage, &ioc->configQ); +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- +- add_timer(&pCfg->timer); ++ ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); ++ timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; + mpt_put_msg_frame(mpt_base_index, ioc, mf); +- wait_event(mpt_waitq, pCfg->wait_done); +- +- /* mf has been freed - do not access */ +- +- rc = pCfg->status; ++ timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout); ++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ ret = -ETIME; ++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Failed Sending Config request type 0x%x, page 0x%x," ++ " action %d, status %xh, time left %ld\n\n", ++ ioc->name, page_type, pReq->Header.PageNumber, ++ pReq->Action, ioc->mptbase_cmds.status, timeleft)); ++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out; ++ if (!timeleft) ++ issue_hard_reset = 1; ++ goto out; ++ } + +- return rc; +-} ++ if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ ret = -1; ++ goto out; ++ } ++ pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; ++ ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ if (ret == MPI_IOCSTATUS_SUCCESS) { ++ if (extend_page) { ++ pCfg->cfghdr.ehdr->ExtPageLength = ++ le16_to_cpu(pReply->ExtPageLength); ++ pCfg->cfghdr.ehdr->ExtPageType = ++ pReply->ExtPageType; ++ } ++ pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; ++ pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; ++ pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; ++ pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mpt_timer_expired - Callback for timer process. +- * Used only internal config functionality. +- * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long +- */ +-static void +-mpt_timer_expired(unsigned long data) +-{ +- MPT_ADAPTER *ioc = (MPT_ADAPTER *) data; ++ } + +- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name)); ++ if (retry_count) ++ printk(MYIOC_s_INFO_FMT "Retry completed ret=0x%x timeleft=%ld\n", ++ ioc->name, ret, timeleft); + +- /* Perform a FW reload */ +- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) +- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); ++ dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", ++ ret, le32_to_cpu(pReply->IOCLogInfo))); + +- /* No more processing. +- * Hard reset clean-up will wake up +- * process and free all resources. +- */ +- dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name)); ++ out: + +- return; ++ CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) ++ mutex_unlock(&ioc->mptbase_cmds.mutex); ++ if (issue_hard_reset) { ++ issue_hard_reset = 0; ++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ mpt_free_msg_frame(ioc, mf); ++ /* attempt one retry for a timed out command */ ++ if (!retry_count) { ++ printk(MYIOC_s_INFO_FMT ++ "Attempting Retry Config request type 0x%x, page 0x%x," ++ " action %d\n", ioc->name, page_type, ++ pCfg->cfghdr.hdr->PageNumber, pCfg->action); ++ retry_count++; ++ goto retry_config; ++ } ++ } ++ return ret; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mpt_ioc_reset - Base cleanup for hard reset +- * @ioc: Pointer to the adapter structure +- * @reset_phase: Indicates pre- or post-reset functionality +- * +- * Remark: Frees resources with internally generated commands. +- */ +-static int +-mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) +-{ +- CONFIGPARMS *pCfg; +- unsigned long flags; +- +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- ": IOC %s_reset routed to MPT base driver!\n", +- ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( +- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); +- +- if (reset_phase == MPT_IOC_SETUP_RESET) { +- ; +- } else if (reset_phase == MPT_IOC_PRE_RESET) { +- /* If the internal config Q is not empty - +- * delete timer. MF resources will be freed when +- * the FIFO's are primed. +- */ +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- list_for_each_entry(pCfg, &ioc->configQ, linkage) +- del_timer(&pCfg->timer); +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- +- } else { +- CONFIGPARMS *pNext; +- +- /* Search the configQ for internal commands. +- * Flush the Q, and wake up all suspended threads. +- */ +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) { +- list_del(&pCfg->linkage); +- +- pCfg->status = MPT_CONFIG_ERROR; +- pCfg->wait_done = 1; +- wake_up(&mpt_waitq); ++/** ++ * mpt_ioc_reset - Base cleanup for hard reset ++ * @ioc: Pointer to the adapter structure ++ * @reset_phase: Indicates pre- or post-reset functionality ++ * ++ * Remark: Frees resources with internally generated commands. ++ **/ ++static int ++mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) ++{ ++ switch(reset_phase) { ++ case MPT_IOC_SETUP_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ ioc->taskmgmt_quiesce_io = 1; ++ break; ++ case MPT_IOC_PRE_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ break; ++ case MPT_IOC_POST_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++/* wake up mptbase_cmds */ ++ if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ complete(&ioc->mptbase_cmds.done); ++ } ++/* wake up taskmgmt_cmds */ ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ complete(&ioc->taskmgmt_cmds.done); + } +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); ++ break; ++ default: ++ break; + } + + return 1; /* currently means nothing really */ +@@ -6010,16 +6532,11 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int rese + + + #ifdef CONFIG_PROC_FS /* { */ +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* +- * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... +- */ +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int + procmpt_create(void) + { +@@ -6040,12 +6557,11 @@ procmpt_create(void) + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static void + procmpt_destroy(void) + { +@@ -6054,7 +6570,6 @@ procmpt_destroy(void) + remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_summary_read - Handle read request of a summary file + * @buf: Pointer to area to write information +@@ -6066,7 +6581,7 @@ procmpt_destroy(void) + * + * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. + * Returns number of characters written to process performing the read. +- */ ++ **/ + static int + procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) + { +@@ -6098,7 +6613,6 @@ procmpt_summary_read(char *buf, char **s + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_version_read - Handle read request from /proc/mpt/version. + * @buf: Pointer to area to write information +@@ -6109,7 +6623,7 @@ procmpt_summary_read(char *buf, char **s + * @data: Pointer + * + * Returns number of characters written to process performing the read. +- */ ++ **/ + static int + procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) + { +@@ -6154,7 +6668,6 @@ procmpt_version_read(char *buf, char **s + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. + * @buf: Pointer to area to write information +@@ -6165,7 +6678,7 @@ procmpt_version_read(char *buf, char **s + * @data: Pointer + * + * Returns number of characters written to process performing the read. +- */ ++ **/ + static int + procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) + { +@@ -6251,7 +6764,6 @@ procmpt_iocinfo_read(char *buf, char **s + + #endif /* CONFIG_PROC_FS } */ + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static void + mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) + { +@@ -6267,7 +6779,6 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE + } + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -6278,7 +6789,7 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE + * + * This routine writes (english readable) ASCII text, which represents + * a summary of IOC information, to a buffer. +- */ ++ **/ + void + mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) + { +@@ -6319,6 +6830,220 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, + /* + * Reset Handling + */ ++ ++/** ++ * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ * Returns 0 for SUCCESS or -1 if FAILED. ++ * ++ * If -1 is return, then it was not possible to set the flags ++ **/ ++int ++mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) ++{ ++ unsigned long flags; ++ int retval; ++ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || ++ (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { ++ retval = -1; ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ goto out; ++ } ++ retval = 0; ++ ioc->taskmgmt_in_progress = 1; ++ ioc->taskmgmt_quiesce_io = 1; ++ if (ioc->alt_ioc) { ++ ioc->alt_ioc->taskmgmt_in_progress = 1; ++ ioc->alt_ioc->taskmgmt_quiesce_io = 1; ++ } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ ++ out: ++ return retval; ++} ++ ++/** ++ * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ **/ ++void ++mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ ioc->taskmgmt_in_progress = 0; ++ ioc->taskmgmt_quiesce_io = 0; ++ if (ioc->alt_ioc) { ++ ioc->alt_ioc->taskmgmt_in_progress = 0; ++ ioc->alt_ioc->taskmgmt_quiesce_io = 0; ++ } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++} ++ ++/** ++ * mpt_halt_firmware - Halts the firmware if it is operational and panic ++ * the kernel ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ **/ ++void ++mpt_halt_firmware(MPT_ADAPTER *ioc) ++{ ++ u32 ioc_raw_state; ++ ++ ioc_raw_state = mpt_GetIocState(ioc, 0); ++ ++ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { ++ printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", ++ ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); ++ if(mpt_fwfault_debug == 2) ++ for(;;); ++ else ++ panic("%s: IOC Fault (%04xh)!!!\n",ioc->name, ++ ioc_raw_state & MPI_DOORBELL_DATA_MASK); ++ } else { ++ CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); ++ if(mpt_fwfault_debug == 2) { ++ printk("%s: Firmware is halted due to command timeout\n" ++ ,ioc->name); ++ for(;;); ++ } ++ else ++ panic("%s: Firmware is halted due to command timeout\n", ++ ioc->name); ++ } ++} ++ ++/** ++ * mpt_SoftResetHandler - Issues a less expensive reset ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @sleepFlag: Indicates if sleep or schedule must be called. ++ ++ * ++ * Returns 0 for SUCCESS or -1 if FAILED. ++ * ++ * Message Unit Reset - instructs the IOC to reset the Reply Post and ++ * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. ++ * All posted buffers are freed, and event notification is turned off. ++ * IOC doesnt reply to any outstanding request. This will transfer IOC ++ * to READY state. ++ **/ ++int ++mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag) ++{ ++ int rc; ++ int ii; ++ u8 cb_idx; ++ unsigned long flags; ++ u32 ioc_state; ++ unsigned long time_count; ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", ioc->name)); ++ ++ ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; ++ ++ if(mpt_fwfault_debug) ++ mpt_halt_firmware(ioc); ++ ++ if (ioc_state == MPI_IOC_STATE_FAULT || ioc_state == MPI_IOC_STATE_RESET) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "skipping, either in FAULT or RESET state!\n", ioc->name)); ++ return -1; ++ } ++ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress) { ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ return -1; ++ } ++ ioc->ioc_reset_in_progress = 1; ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ ++ rc = -1; ++ ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) ++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); ++ } ++ ++ /* Disable reply interrupts (also blocks FreeQ) */ ++ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ++ ioc->active = 0; ++ time_count = jiffies; ++ ++ rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); ++ ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) ++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); ++ } ++ ++ if (rc) ++ goto out; ++ ++ ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; ++ if (ioc_state != MPI_IOC_STATE_READY) ++ goto out; ++ ++ for (ii = 0; ii < 5; ii++) { ++ /* Get IOC facts! Allow 5 retries */ ++ if ((rc = GetIocFacts(ioc, sleepFlag, ++ MPT_HOSTEVENT_IOC_RECOVER)) == 0) ++ break; ++ if (sleepFlag == CAN_SLEEP) { ++ msleep(100); ++ } else { ++ mdelay(100); ++ } ++ } ++ if (ii == 5) ++ goto out; ++ ++ if ((rc = PrimeIocFifos(ioc)) != 0) ++ goto out; ++ ++ if ((rc = SendIocInit(ioc, sleepFlag)) != 0) ++ goto out; ++ ++ if ((rc = SendEventNotification(ioc, 1, sleepFlag)) != 0) ++ goto out; ++ ++ if (ioc->hard_resets < -1) ++ ioc->hard_resets++; ++ ++ /* ++ * At this point, we know soft reset succeeded. ++ */ ++ ++ ioc->active = 1; ++ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ++ ++ out: ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ ioc->ioc_reset_in_progress = 0; ++ ioc->taskmgmt_quiesce_io = 0; ++ ioc->taskmgmt_in_progress = 0; ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ ++ if (ioc->active) { /* otherwise, hard reset coming */ ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) ++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); ++ } ++ } ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler: completed (%d seconds): %s\n", ++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, ++ ((rc == 0) ? "SUCCESS" : "FAILED"))); ++ ++ return rc; ++} ++ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_HardResetHandler - Generic reset handler +@@ -6335,12 +7060,14 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, + * FW reload/initialization failed. + * + * Returns 0 for SUCCESS or -1 if FAILED. +- */ ++ **/ + int + mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) + { +- int rc; ++ int rc; ++ u8 cb_idx; + unsigned long flags; ++ unsigned long time_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); + #ifdef MFCNT +@@ -6348,67 +7075,82 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i + printk("MF count 0x%x !\n", ioc->mfcnt); + #endif + ++ if(mpt_fwfault_debug) ++ mpt_halt_firmware(ioc); ++ + /* Reset the adapter. Prevent more than 1 call to + * mpt_do_ioc_recovery at any instant in time. + */ +- spin_lock_irqsave(&ioc->diagLock, flags); +- if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){ +- spin_unlock_irqrestore(&ioc->diagLock, flags); ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress) { ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return 0; +- } else { +- ioc->diagPending = 1; + } +- spin_unlock_irqrestore(&ioc->diagLock, flags); ++ ioc->ioc_reset_in_progress = 1; ++ if (ioc->alt_ioc) ++ ioc->alt_ioc->ioc_reset_in_progress = 1; ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + +- /* FIXME: If do_ioc_recovery fails, repeat.... +- */ + + /* The SCSI driver needs to adjust timeouts on all current + * commands prior to the diagnostic reset being issued. + * Prevents timeouts occurring during a diagnostic reset...very bad. + * For all other protocol drivers, this is a no-op. + */ +- { +- u8 cb_idx; +- int r = 0; +- +- for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { +- if (MptResetHandlers[cb_idx]) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n", +- ioc->name, cb_idx)); +- r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); +- if (ioc->alt_ioc) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n", +- ioc->name, ioc->alt_ioc->name, cb_idx)); +- r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); +- } +- } ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) { ++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); ++ if (ioc->alt_ioc) ++ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); + } + } + ++ time_count = jiffies; + if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { +- printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc); ++ printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", ++ rc, ioc->name); ++ } else { ++ if (ioc->hard_resets < -1) ++ ioc->hard_resets++; + } +- ioc->reload_fw = 0; +- if (ioc->alt_ioc) +- ioc->alt_ioc->reload_fw = 0; + +- spin_lock_irqsave(&ioc->diagLock, flags); +- ioc->diagPending = 0; +- if (ioc->alt_ioc) +- ioc->alt_ioc->diagPending = 0; +- spin_unlock_irqrestore(&ioc->diagLock, flags); ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ ioc->ioc_reset_in_progress = 0; ++ ioc->taskmgmt_quiesce_io = 0; ++ ioc->taskmgmt_in_progress = 0; ++ if (ioc->alt_ioc) { ++ ioc->alt_ioc->ioc_reset_in_progress = 0; ++ ioc->alt_ioc->taskmgmt_quiesce_io = 0; ++ ioc->alt_ioc->taskmgmt_in_progress = 0; ++ } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); ++ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { ++ if (MptResetHandlers[cb_idx]) { ++ mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); ++ if (ioc->alt_ioc) ++ mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); ++ } ++ } + ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n", ++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, ++ ((rc == 0) ? "SUCCESS" : "FAILED"))); + return rc; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++#ifdef CONFIG_FUSION_LOGGING + static void +-EventDescriptionStr(u8 event, u32 evData0, char *evStr) ++mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) + { + char *ds = NULL; ++ u32 evData0; ++ int ii; ++ u8 event; ++ char *evStr = ioc->evStr; ++ ++ event = le32_to_cpu(pEventReply->Event) & 0xFF; ++ evData0 = le32_to_cpu(pEventReply->Data[0]); + + switch(event) { + case MPI_EVENT_NONE: +@@ -6442,9 +7184,9 @@ EventDescriptionStr(u8 event, u32 evData + if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) + ds = "Loop State(LIP) Change"; + else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) +- ds = "Loop State(LPE) Change"; /* ??? */ ++ ds = "Loop State(LPE) Change"; + else +- ds = "Loop State(LPB) Change"; /* ??? */ ++ ds = "Loop State(LPB) Change"; + break; + case MPI_EVENT_LOGOUT: + ds = "Logout"; +@@ -6540,6 +7282,11 @@ EventDescriptionStr(u8 event, u32 evData + "SAS Device Status Change: Internal Device " + "Reset : id=%d channel=%d", id, channel); + break; ++ case MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET: ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "SAS Device Status Change: Internal Device " ++ "Reset Completed: id=%d channel=%d", id, channel); ++ break; + case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Task " +@@ -6560,6 +7307,11 @@ EventDescriptionStr(u8 event, u32 evData + "SAS Device Status Change: Internal Query " + "Task : id=%d channel=%d", id, channel); + break; ++ case MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "SAS Device Status Change: Async Notification " ++ "Task : id=%d channel=%d", id, channel); ++ break; + default: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Unknown: " +@@ -6644,28 +7396,65 @@ EventDescriptionStr(u8 event, u32 evData + } + case MPI_EVENT_IR2: + { ++ u8 id = (u8)(evData0); ++ u8 channel = (u8)(evData0 >> 8); ++ u8 phys_num = (u8)(evData0 >> 24); + u8 ReasonCode = (u8)(evData0 >> 16); ++ + switch (ReasonCode) { + case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: +- ds = "IR2: LD State Changed"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: LD State Changed: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: +- ds = "IR2: PD State Changed"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: PD State Changed " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: +- ds = "IR2: Bad Block Table Full"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: Bad Block Table Full: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_PD_INSERTED: +- ds = "IR2: PD Inserted"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: PD Inserted: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_PD_REMOVED: +- ds = "IR2: PD Removed"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: PD Removed: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: +- ds = "IR2: Foreign CFG Detected"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: Foreign CFG Detected: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: +- ds = "IR2: Rebuild Medium Error"; ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: Rebuild Medium Error: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); ++ break; ++ case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: Dual Port Added: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); ++ break; ++ case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: ++ snprintf(evStr, EVENT_DESCR_STR_SZ, ++ "IR2: Dual Port Removed: " ++ "id=%d channel=%d phys_num=%d", ++ id, channel, phys_num); + break; + default: + ds = "IR2"; +@@ -6689,25 +7478,46 @@ EventDescriptionStr(u8 event, u32 evData + { + u8 phy_num = (u8)(evData0); + u8 port_num = (u8)(evData0 >> 8); +- u8 port_width = (u8)(evData0 >> 16); ++ u8 num_phys = (u8)(evData0 >> 16); + u8 primative = (u8)(evData0 >> 24); ++ char *primative_str = NULL; ++ ++ switch (primative) { ++ case MPI_EVENT_PRIMITIVE_CHANGE: ++ primative_str = "change"; ++ break; ++ case MPI_EVENT_PRIMITIVE_EXPANDER: ++ primative_str = "expander"; ++ break; ++ case MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT: ++ primative_str = "asyn event"; ++ break; ++ default: ++ primative_str = "reserved"; ++ break; ++ } + snprintf(evStr, EVENT_DESCR_STR_SZ, +- "SAS Broadcase Primative: phy=%d port=%d " +- "width=%d primative=0x%02x", +- phy_num, port_num, port_width, primative); ++ "SAS Broadcast Primative: phy=%d port=%d " ++ "num_phys=%d primative=%s (0x%02x)", ++ phy_num, port_num, num_phys, primative_str, primative); + break; + } + + case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: + { + u8 reason = (u8)(evData0); +- u8 port_num = (u8)(evData0 >> 8); +- u16 handle = le16_to_cpu(evData0 >> 16); + +- snprintf(evStr, EVENT_DESCR_STR_SZ, +- "SAS Initiator Device Status Change: reason=0x%02x " +- "port=%d handle=0x%04x", +- reason, port_num, handle); ++ switch (reason) { ++ case MPI_EVENT_SAS_INIT_RC_ADDED: ++ ds = "SAS Initiator Status Change: Added"; ++ break; ++ case MPI_EVENT_SAS_INIT_RC_REMOVED: ++ ds = "SAS Initiator Status Change: Deleted"; ++ break; ++ default: ++ ds = "SAS Initiator Status Change"; ++ break; ++ } + break; + } + +@@ -6755,6 +7565,24 @@ EventDescriptionStr(u8 event, u32 evData + break; + } + ++ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: ++ { ++ u8 reason = (u8)(evData0); ++ ++ switch (reason) { ++ case MPI_EVENT_SAS_EXP_RC_ADDED: ++ ds = "Expander Status Change: Added"; ++ break; ++ case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: ++ ds = "Expander Status Change: Deleted"; ++ break; ++ default: ++ ds = "Expander Status Change"; ++ break; ++ } ++ break; ++ } ++ + /* + * MPT base "custom" events may be added here... + */ +@@ -6764,9 +7592,21 @@ EventDescriptionStr(u8 event, u32 evData + } + if (ds) + strncpy(evStr, ds, EVENT_DESCR_STR_SZ); ++ ++ ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "MPT event:(%02Xh) : %s\n", ++ ioc->name, event, evStr)); ++ ++ devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM ++ ": Event data:\n")); ++ for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) ++ devtverboseprintk(ioc, printk(" %08x", ++ le32_to_cpu(pEventReply->Data[ii]))); ++ devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); + } ++#endif + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * ProcessEventNotification - Route EventNotificationReply to all event handlers + * @ioc: Pointer to MPT_ADAPTER structure +@@ -6776,43 +7616,30 @@ EventDescriptionStr(u8 event, u32 evData + * Routes a received EventNotificationReply to all currently registered + * event handlers. + * Returns sum of event handlers return values. +- */ ++ **/ + static int + ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) + { + u16 evDataLen; + u32 evData0 = 0; +-// u32 evCtx; + int ii; + u8 cb_idx; + int r = 0; + int handlers = 0; +- char evStr[EVENT_DESCR_STR_SZ]; + u8 event; + ++ + /* + * Do platform normalization of values + */ + event = le32_to_cpu(pEventReply->Event) & 0xFF; +-// evCtx = le32_to_cpu(pEventReply->EventContext); + evDataLen = le16_to_cpu(pEventReply->EventDataLength); +- if (evDataLen) { ++ if (evDataLen) + evData0 = le32_to_cpu(pEventReply->Data[0]); +- } +- +- EventDescriptionStr(event, evData0, evStr); +- devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n", +- ioc->name, +- event, +- evStr)); + + #ifdef CONFIG_FUSION_LOGGING +- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- ": Event data:\n", ioc->name)); +- for (ii = 0; ii < evDataLen; ii++) +- devtverboseprintk(ioc, printk(" %08x", +- le32_to_cpu(pEventReply->Data[ii]))); +- devtverboseprintk(ioc, printk("\n")); ++ if (evDataLen) ++ mpt_display_event_info(ioc, pEventReply); + #endif + + /* +@@ -6867,8 +7694,8 @@ ProcessEventNotification(MPT_ADAPTER *io + */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptEvHandlers[cb_idx]) { +- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n", +- ioc->name, cb_idx)); ++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Routing Event to event handler #%d\n", ioc->name, cb_idx)); + r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); + handlers++; + } +@@ -6935,7 +7762,6 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo + ioc->name, log_info, desc, (log_info & 0xFFFFFF)); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -6943,7 +7769,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo + * @log_info: U32 LogInfo word from the IOC + * + * Refer to lsi/sp_log.h. +- */ ++ **/ + static void + mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) + { +@@ -6953,8 +7779,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l + switch (info) { + case 0x00010000: + desc = "bug! MID not found"; +- if (ioc->reload_fw == 0) +- ioc->reload_fw++; + break; + + case 0x00020000: +@@ -7149,7 +7973,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 l + "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ + }; + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_sas_log_info - Log information returned from SAS IOC. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -7229,7 +8052,6 @@ union loginfo_type { + sas_loginfo.dw.code, sas_loginfo.dw.subcode); + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_iocstatus_info_config - IOCSTATUS information for config pages + * @ioc: Pointer to MPT_ADAPTER structure +@@ -7531,8 +8353,7 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 + if (!desc) + return; + +- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", +- ioc->name, status, desc)); ++ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc)); + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -7543,6 +8364,7 @@ EXPORT_SYMBOL(mpt_resume); + EXPORT_SYMBOL(mpt_suspend); + #endif + EXPORT_SYMBOL(ioc_list); ++EXPORT_SYMBOL(mpt_proc_root_dir); + EXPORT_SYMBOL(mpt_register); + EXPORT_SYMBOL(mpt_deregister); + EXPORT_SYMBOL(mpt_event_register); +@@ -7555,25 +8377,29 @@ EXPORT_SYMBOL(mpt_get_msg_frame); + EXPORT_SYMBOL(mpt_put_msg_frame); + EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); + EXPORT_SYMBOL(mpt_free_msg_frame); +-EXPORT_SYMBOL(mpt_add_sge); + EXPORT_SYMBOL(mpt_send_handshake_request); + EXPORT_SYMBOL(mpt_verify_adapter); + EXPORT_SYMBOL(mpt_GetIocState); + EXPORT_SYMBOL(mpt_print_ioc_summary); + EXPORT_SYMBOL(mpt_HardResetHandler); ++EXPORT_SYMBOL(mpt_SoftResetHandler); + EXPORT_SYMBOL(mpt_config); + EXPORT_SYMBOL(mpt_findImVolumes); + EXPORT_SYMBOL(mpt_alloc_fw_memory); + EXPORT_SYMBOL(mpt_free_fw_memory); + EXPORT_SYMBOL(mptbase_sas_persist_operation); + EXPORT_SYMBOL(mpt_raid_phys_disk_pg0); ++EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); ++EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); ++EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); ++EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); ++EXPORT_SYMBOL(mpt_halt_firmware); + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * fusion_init - Fusion MPT base driver initialization routine. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int __init + fusion_init(void) + { +@@ -7592,7 +8418,7 @@ fusion_init(void) + /* Register ourselves (mptbase) in order to facilitate + * EventNotification handling. + */ +- mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); ++ mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER); + + /* Register for hard reset handling callbacks. + */ +@@ -7604,17 +8430,15 @@ fusion_init(void) + return 0; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * fusion_exit - Perform driver unload cleanup. + * + * This routine frees all resources associated with each MPT adapter + * and removes all %MPT_PROCFS_MPTBASEDIR entries. +- */ ++ **/ + static void __exit + fusion_exit(void) + { +- + mpt_reset_deregister(mpt_base_index); + + #ifdef CONFIG_PROC_FS +--- a/drivers/message/fusion/mptbase.h ++++ b/drivers/message/fusion/mptbase.h +@@ -49,10 +49,6 @@ + #define MPTBASE_H_INCLUDED + /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +-#include +-#include +-#include +- + #include "lsi/mpi_type.h" + #include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ + #include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */ +@@ -76,9 +72,13 @@ + #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR + #endif + +-#define MPT_LINUX_VERSION_COMMON "3.04.07" +-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.07" ++#define MPT_LINUX_VERSION_COMMON "4.00.43.00" ++#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.00.43.00" + #define WHAT_MAGIC_STRING "@" "(" "#" ")" ++#define MPT_LINUX_MAJOR_VERSION 4 ++#define MPT_LINUX_MINOR_VERSION 00 ++#define MPT_LINUX_BUILD_VERSION 43 ++#define MPT_LINUX_RELEASE_VERSION 00 + + #define show_mptmod_ver(s,ver) \ + printk(KERN_INFO "%s %s\n", s, ver); +@@ -87,6 +87,8 @@ + /* + * Fusion MPT(linux) driver configurable stuff... + */ ++#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */ ++ + #define MPT_MAX_ADAPTERS 18 + #define MPT_MAX_PROTOCOL_DRIVERS 16 + #define MPT_MAX_BUS 1 /* Do not change */ +@@ -134,6 +136,8 @@ + + #define MPT_COALESCING_TIMEOUT 0x10 + ++#define MPT_DMA_35BIT_MASK 0x00000007ffffffffULL ++ + /* + * SCSI transfer rate defines. + */ +@@ -173,10 +177,21 @@ + #define MPT_SCSI_SG_DEPTH 40 + #endif + ++#ifdef CONFIG_FUSION_MAX_FC_SGE ++#if CONFIG_FUSION_MAX_FC_SGE < 16 ++#define MPT_SCSI_FC_SG_DEPTH 16 ++#elif CONFIG_FUSION_MAX_FC_SGE > 256 ++#define MPT_SCSI_FC_SG_DEPTH 256 ++#else ++#define MPT_SCSI_FC_SG_DEPTH CONFIG_FUSION_MAX_FC_SGE ++#endif ++#else ++#define MPT_SCSI_FC_SG_DEPTH 40 ++#endif ++ + /* debug print string length used for events and iocstatus */ +-# define EVENT_DESCR_STR_SZ 100 ++# define EVENT_DESCR_STR_SZ 100 + +-#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */ + + #ifdef __KERNEL__ /* { */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -224,7 +239,6 @@ typedef struct _ATTO_CONFIG_PAGE_SCSI_PO + } fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2, + ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t; + +- + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* + * MPT protocol driver defs... +@@ -372,8 +386,8 @@ typedef struct _VirtTarget { + struct scsi_target *starget; + u8 tflags; + u8 ioc_id; +- u8 id; +- u8 channel; ++ u8 id; /* logical target id */ ++ u8 channel; /* logical channel number */ + u8 minSyncFactor; /* 0xFF is async */ + u8 maxOffset; /* 0 if async */ + u8 maxWidth; /* 0 if narrow, 1 if wide */ +@@ -381,7 +395,7 @@ typedef struct _VirtTarget { + u8 raidVolume; /* set, if RAID Volume */ + u8 type; /* byte 0 of Inquiry data */ + u8 deleted; /* target in process of being removed */ +- u32 num_luns; ++ int num_luns; + } VirtTarget; + + typedef struct _VirtDevice { +@@ -427,42 +441,33 @@ do { \ + } while (0) + + +-/* +- * IOCTL structure and associated defines +- */ +- +-#define MPT_IOCTL_STATUS_DID_IOCRESET 0x01 /* IOC Reset occurred on the current*/ +-#define MPT_IOCTL_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ +-#define MPT_IOCTL_STATUS_TIMER_ACTIVE 0x04 /* The timer is running */ +-#define MPT_IOCTL_STATUS_SENSE_VALID 0x08 /* Sense data is valid */ +-#define MPT_IOCTL_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ +-#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE 0x20 /* The TM timer is running */ +-#define MPT_IOCTL_STATUS_TM_FAILED 0x40 /* User TM request failed */ +- +-#define MPTCTL_RESET_OK 0x01 /* Issue Bus Reset */ +- +-typedef struct _MPT_IOCTL { +- struct _MPT_ADAPTER *ioc; +- u8 ReplyFrame[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ +- u8 sense[MPT_SENSE_BUFFER_ALLOC]; +- int wait_done; /* wake-up value for this ioc */ +- u8 rsvd; +- u8 status; /* current command status */ +- u8 reset; /* 1 if bus reset allowed */ +- u8 id; /* target for reset */ +- struct mutex ioctl_mutex; +-} MPT_IOCTL; +- +-#define MPT_SAS_MGMT_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ +-#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ +-#define MPT_SAS_MGMT_STATUS_TM_FAILED 0x40 /* User TM request failed */ ++#define MPT_MGMT_STATUS_RF_VALID 0x01 /* The Reply Frame is VALID */ ++#define MPT_MGMT_STATUS_COMMAND_GOOD 0x02 /* Command Status GOOD */ ++#define MPT_MGMT_STATUS_PENDING 0x04 /* command is pending */ ++#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred on the current*/ ++#define MPT_MGMT_STATUS_SENSE_VALID 0x10 /* valid sense info */ ++#define MPT_MGMT_STATUS_TIMER_ACTIVE 0x20 /* obsolete */ ++#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from complete routine */ ++ ++ ++#define INITIALIZE_MGMT_STATUS(status) \ ++ status = MPT_MGMT_STATUS_PENDING; ++#define CLEAR_MGMT_STATUS(status) \ ++ status = 0; ++#define CLEAR_MGMT_PENDING_STATUS(status) \ ++ status &= ~MPT_MGMT_STATUS_PENDING; ++#define SET_MGMT_MSG_CONTEXT(msg_context, value) \ ++ msg_context = value; + +-typedef struct _MPT_SAS_MGMT { ++typedef struct _MPT_MGMT { + struct mutex mutex; + struct completion done; + u8 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ ++ u8 sense[MPT_SENSE_BUFFER_ALLOC]; + u8 status; /* current command status */ +-}MPT_SAS_MGMT; ++ int completion_code; ++ u32 msg_context; ++}MPT_MGMT; + + /* + * Event Structure and define +@@ -534,7 +539,8 @@ struct inactive_raid_component_info { + typedef struct _RaidCfgData { + IOCPage2_t *pIocPg2; /* table of Raid Volumes */ + IOCPage3_t *pIocPg3; /* table of physical disks */ +- struct mutex inactive_list_mutex; ++ IOCPage6_t *pIocPg6; /* table of IR static data */ ++ struct semaphore inactive_list_mutex; + struct list_head inactive_list; /* link list for physical + disk that belong in + inactive volumes */ +@@ -564,6 +570,9 @@ struct mptfc_rport_info + u8 flags; + }; + ++typedef void (*MPT_ADD_SGE)(char *pAddr, u32 flagslength, dma_addr_t dma_addr); ++typedef void (*MPT_ADD_CHAIN)(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr); ++ + /* + * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS + */ +@@ -573,6 +582,9 @@ typedef struct _MPT_ADAPTER + int pci_irq; /* This irq */ + char name[MPT_NAME_LENGTH]; /* "iocN" */ + char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ ++#ifdef CONFIG_FUSION_LOGGING ++ char evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */ ++#endif + char board_name[16]; + char board_assembly[16]; + char board_tracer[16]; +@@ -584,8 +596,8 @@ typedef struct _MPT_ADAPTER + SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */ + SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ + u8 bus_type; +- u32 mem_phys; /* == f4020000 (mmap) */ +- u32 pio_mem_phys; /* Programmed IO (downloadboot) */ ++ unsigned long mem_phys; /* == f4020000 (mmap) */ ++ unsigned long pio_mem_phys; /* Programmed IO (downloadboot) */ + int mem_size; /* mmap memory size */ + int number_of_buses; + int devices_per_bus; +@@ -600,6 +612,8 @@ typedef struct _MPT_ADAPTER + int reply_depth; /* Num Allocated reply frames */ + int reply_sz; /* Reply frame size */ + int num_chain; /* Number of chain buffers */ ++ MPT_ADD_SGE add_sge; /* Pointer to add_sge function */ ++ MPT_ADD_CHAIN add_chain; /* Pointer to add_chain function */ + /* Pool of buffers for chaining. ReqToChain + * and ChainToChain track index of chain buffers. + * ChainBuffer (DMA) virt/phys addresses. +@@ -628,31 +642,27 @@ typedef struct _MPT_ADAPTER + dma_addr_t sense_buf_pool_dma; + u32 sense_buf_low_dma; + u8 *HostPageBuffer; /* SAS - host page buffer support */ +- u32 HostPageBuffer_sz; +- dma_addr_t HostPageBuffer_dma; ++ u32 HostPageBuffer_sz; ++ dma_addr_t HostPageBuffer_dma; + int mtrr_reg; + struct pci_dev *pcidev; /* struct pci_dev pointer */ +- int bars; /* bitmask of BAR's that must be configured */ +- int msi_enable; ++ int bars; /* bitmask of BAR's that must be configured */ ++ int msi_enable; + u8 __iomem *memmap; /* mmap address */ + struct Scsi_Host *sh; /* Scsi Host pointer */ +- SpiCfgData spi_data; /* Scsi config. data */ +- RaidCfgData raid_data; /* Raid config. data */ +- SasCfgData sas_data; /* Sas config. data */ +- FcCfgData fc_data; /* Fc config. data */ +- MPT_IOCTL *ioctl; /* ioctl data pointer */ ++ SpiCfgData spi_data; /* Scsi config. data */ ++ RaidCfgData raid_data; /* Raid config. data */ ++ SasCfgData sas_data; /* Sas config. data */ ++ FcCfgData fc_data; /* Fc config. data */ + struct proc_dir_entry *ioc_dentry; + struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */ +- spinlock_t diagLock; /* diagnostic reset lock */ +- int diagPending; + u32 biosVersion; /* BIOS version from IO Unit Page 2 */ + int eventTypes; /* Event logging parameters */ + int eventContext; /* Next event context */ + int eventLogSize; /* Max number of cached events */ + struct _mpt_ioctl_events *events; /* pointer to event log */ + u8 *cached_fw; /* Pointer to FW */ +- dma_addr_t cached_fw_dma; +- struct list_head configQ; /* linked list of config. requests */ ++ dma_addr_t cached_fw_dma; + int hs_reply_idx; + #ifndef MFCNT + u32 pad0; +@@ -665,13 +675,16 @@ typedef struct _MPT_ADAPTER + IOCFactsReply_t facts; + PortFactsReply_t pfacts[2]; + FCPortPage0_t fc_port_page0[2]; +- struct timer_list persist_timer; /* persist table timer */ +- int persist_wait_done; /* persist completion flag */ +- u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */ + LANPage0_t lan_cnfg_page0; + LANPage1_t lan_cnfg_page1; ++#if defined(CPQ_CIM) ++ u32 csmi_change_count; /* count to track all IR ++ events for CSMI */ ++ u8 pci_slot_number; /* ioc page 1 - pci slot number */ ++#endif + + u8 ir_firmware; /* =1 if IR firmware detected */ ++ + /* + * Description: errata_flag_1064 + * If a PCIX read occurs within 1 or 2 cycles after the chip receives +@@ -682,25 +695,46 @@ typedef struct _MPT_ADAPTER + int aen_event_read_flag; /* flag to indicate event log was read*/ + u8 FirstWhoInit; + u8 upload_fw; /* If set, do a fw upload */ +- u8 reload_fw; /* Force a FW Reload on next reset */ + u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ +- u8 pad1[4]; + u8 DoneCtx; + u8 TaskCtx; + u8 InternalCtx; +- spinlock_t initializing_hba_lock; +- int initializing_hba_lock_flag; + struct list_head list; + struct net_device *netdev; + struct list_head sas_topology; + struct mutex sas_topology_mutex; +- struct mutex sas_discovery_mutex; +- u8 sas_discovery_runtime; +- u8 sas_discovery_ignore_events; ++ u8 disable_hotplug_remove; ++ ++ struct workqueue_struct *fw_event_q; ++ struct list_head fw_event_list; ++ spinlock_t fw_event_lock; ++ u8 fw_events_off; /* if '1', then ignore events */ ++ char fw_event_q_name[20]; ++ ++ struct mptsas_portinfo *hba_port_info; /* port_info object for the host */ ++ u64 hba_port_sas_addr; ++ u16 hba_port_num_phy; ++ struct list_head sas_device_info_list; ++ struct semaphore sas_device_info_mutex; ++ u8 old_sas_discovery_protocal; ++ u8 sas_discovery_quiesce_io; + int sas_index; /* index refrencing */ +- MPT_SAS_MGMT sas_mgmt; +- struct work_struct sas_persist_task; ++ MPT_MGMT sas_mgmt; ++ MPT_MGMT internal_cmds; ++ MPT_MGMT mptbase_cmds; /* for sending config pages */ ++ MPT_MGMT taskmgmt_cmds; ++ MPT_MGMT ioctl_cmds; /* ioctl data pointer */ ++ spinlock_t taskmgmt_lock; /* diagnostic reset lock */ ++ int taskmgmt_in_progress; ++ u8 taskmgmt_quiesce_io; ++ u8 ioc_reset_in_progress; ++#if defined(CPQ_CIM) ++ u8 num_ports; ++#endif + ++ char reset_work_q_name[20]; ++ struct workqueue_struct *reset_work_q; ++ struct delayed_work fault_reset_work; + struct work_struct fc_setup_reset_work; + struct list_head fc_rports; + struct work_struct fc_lsc_work; +@@ -709,14 +743,27 @@ typedef struct _MPT_ADAPTER + struct work_struct fc_rescan_work; + char fc_rescan_work_q_name[20]; + struct workqueue_struct *fc_rescan_work_q; ++ unsigned long hard_resets; /* driver forced bus resets count */ ++ unsigned long soft_resets; /* fw/external bus resets count */ ++ unsigned long timeouts; /* cmd timeouts */ + struct scsi_cmnd **ScsiLookup; + spinlock_t scsi_lookup_lock; +- +- char reset_work_q_name[20]; +- struct workqueue_struct *reset_work_q; +- struct delayed_work fault_reset_work; +- spinlock_t fault_reset_work_lock; +- ++ int sdev_queue_depth; /* sdev queue depth */ ++ u64 dma_mask; ++ u32 broadcast_aen_busy; ++#if defined(DIAG_BUFFER_SUPPORT) ++ u8 *DiagBuffer[MPI_DIAG_BUF_TYPE_COUNT]; ++ u32 DataSize[MPI_DIAG_BUF_TYPE_COUNT]; ++ u32 DiagBuffer_sz[MPI_DIAG_BUF_TYPE_COUNT]; ++ dma_addr_t DiagBuffer_dma[MPI_DIAG_BUF_TYPE_COUNT]; ++ u8 TraceLevel[MPI_DIAG_BUF_TYPE_COUNT]; ++ u8 DiagBuffer_Status[MPI_DIAG_BUF_TYPE_COUNT]; ++ u32 UniqueId[MPI_DIAG_BUF_TYPE_COUNT]; ++ u32 ExtendedType[MPI_DIAG_BUF_TYPE_COUNT]; ++ u32 ProductSpecific[MPI_DIAG_BUF_TYPE_COUNT][4]; ++#endif ++ u8 sg_addr_size; ++ u8 SGE_size; + } MPT_ADAPTER; + + /* +@@ -753,13 +800,12 @@ typedef struct _mpt_sge { + dma_addr_t Address; + } MptSge_t; + +-#define mpt_addr_size() \ +- ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \ +- MPI_SGE_FLAGS_32_BIT_ADDRESSING) +- +-#define mpt_msg_flags() \ +- ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ +- MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32) ++#define mpt_msg_flags(ioc) \ ++ (ioc->sg_addr_size == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ ++ MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 ++ ++#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \ ++ (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT) + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* +@@ -778,26 +824,10 @@ typedef struct _mpt_sge { + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +-#define SCSI_STD_SENSE_BYTES 18 +-#define SCSI_STD_INQUIRY_BYTES 36 +-#define SCSI_MAX_INQUIRY_BYTES 96 +- + /* + * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers + * Private to the driver. + */ +-/* LOCAL structure and fields used when processing +- * internally generated commands. These include: +- * bus scan, dv and config requests. +- */ +-typedef struct _MPT_LOCAL_REPLY { +- ConfigPageHeader_t header; +- int completion; +- u8 sense[SCSI_STD_SENSE_BYTES]; +- u8 scsiStatus; +- u8 skip; +- u32 pad; +-} MPT_LOCAL_REPLY; + + #define MPT_HOST_BUS_UNKNOWN (0xFF) + #define MPT_HOST_TOO_MANY_TM (0x05) +@@ -813,13 +843,6 @@ typedef struct _MPT_LOCAL_REPLY { + #define MPT_NVRAM_WIDE_DISABLE (0x00100000) + #define MPT_NVRAM_BOOT_CHOICE (0x00200000) + +-/* The TM_STATE variable is used to provide strict single threading of TM +- * requests as well as communicate TM error conditions. +- */ +-#define TM_STATE_NONE (0) +-#define TM_STATE_IN_PROGRESS (1) +-#define TM_STATE_ERROR (2) +- + typedef enum { + FC, + SPI, +@@ -828,63 +851,28 @@ typedef enum { + + typedef struct _MPT_SCSI_HOST { + MPT_ADAPTER *ioc; +- int port; +- u32 pad0; +- MPT_LOCAL_REPLY *pLocal; /* used for internal commands */ +- struct timer_list timer; +- /* Pool of memory for holding SCpnts before doing +- * OS callbacks. freeQ is the free pool. +- */ +- u8 tmPending; +- u8 resetPending; +- u8 negoNvram; /* DV disabled, nego NVRAM */ +- u8 pad1; +- u8 tmState; +- u8 rsvd[2]; +- MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ +- struct scsi_cmnd *abortSCpnt; +- MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */ +- unsigned long hard_resets; /* driver forced bus resets count */ +- unsigned long soft_resets; /* fw/external bus resets count */ +- unsigned long timeouts; /* cmd timeouts */ + ushort sel_timeout[MPT_MAX_FC_DEVICES]; + char *info_kbuf; +- wait_queue_head_t scandv_waitq; +- int scandv_wait_done; + long last_queue_full; +- u16 tm_iocstatus; + u16 spi_pending; + struct list_head target_reset_list; + } MPT_SCSI_HOST; + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* +- * More Dynamic Multi-Pathing stuff... +- */ +- +-/* Forward decl, a strange C thing, to prevent gcc compiler warnings */ +-struct scsi_cmnd; +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* + * Generic structure passed to the base mpt_config function. + */ + typedef struct _x_config_parms { +- struct list_head linkage; /* linked list */ +- struct timer_list timer; /* timer function for this request */ + union { + ConfigExtendedPageHeader_t *ehdr; + ConfigPageHeader_t *hdr; + } cfghdr; + dma_addr_t physAddr; +- int wait_done; /* wait for this request */ + u32 pageAddr; /* properly formatted */ ++ u16 status; + u8 action; + u8 dir; + u8 timeout; /* seconds */ +- u8 pad1; +- u16 status; +- u16 pad2; + } CONFIGPARMS; + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -909,29 +897,37 @@ extern MPT_FRAME_HDR *mpt_get_msg_frame( + extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); + extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); + extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); +-extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr); +- + extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag); + extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); + extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); + extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); + extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); ++extern int mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag); + extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); + extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size); + extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); + extern int mpt_findImVolumes(MPT_ADAPTER *ioc); + extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); + extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk); ++extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage1_t phys_disk); ++extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num); ++ ++extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); ++extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); ++extern void mpt_halt_firmware(MPT_ADAPTER *ioc); + + /* + * Public data decl's... + */ + extern struct list_head ioc_list; ++extern struct proc_dir_entry *mpt_proc_root_dir; ++extern int mpt_debug_level; ++extern int mpt_fwfault_debug; + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + #endif /* } __KERNEL__ */ + +-#ifdef CONFIG_64BIT ++#if defined(__alpha__) || defined(__sparc_v9__) || defined(__ia64__) || defined(__x86_64__) || defined(__powerpc64__) + #define CAST_U32_TO_PTR(x) ((void *)(u64)x) + #define CAST_PTR_TO_U32(x) ((u32)(u64)x) + #else +@@ -956,7 +952,6 @@ extern struct list_head ioc_list; + #define MPT_SGE_FLAGS_END_OF_BUFFER (0x40000000) + #define MPT_SGE_FLAGS_LOCAL_ADDRESS (0x08000000) + #define MPT_SGE_FLAGS_DIRECTION (0x04000000) +-#define MPT_SGE_FLAGS_ADDRESSING (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT) + #define MPT_SGE_FLAGS_END_OF_LIST (0x01000000) + + #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT (0x00000000) +@@ -969,14 +964,12 @@ extern struct list_head ioc_list; + MPT_SGE_FLAGS_END_OF_BUFFER | \ + MPT_SGE_FLAGS_END_OF_LIST | \ + MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ +- MPT_SGE_FLAGS_ADDRESSING | \ + MPT_TRANSFER_IOC_TO_HOST) + #define MPT_SGE_FLAGS_SSIMPLE_WRITE \ + (MPT_SGE_FLAGS_LAST_ELEMENT | \ + MPT_SGE_FLAGS_END_OF_BUFFER | \ + MPT_SGE_FLAGS_END_OF_LIST | \ + MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ +- MPT_SGE_FLAGS_ADDRESSING | \ + MPT_TRANSFER_HOST_TO_IOC) + + /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +--- a/drivers/message/fusion/mptctl.c ++++ b/drivers/message/fusion/mptctl.c +@@ -45,6 +45,7 @@ + */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + ++#include + #include + #include + #include +@@ -71,6 +72,15 @@ + #include "mptbase.h" + #include "mptctl.h" + ++#if defined(CPQ_CIM) ++#include "mptsas.h" ++#include "csmi/csmisas.h" ++#endif // CPQ_CIM ++ ++#if defined(DIAG_BUFFER_SUPPORT) ++#include "rejected_ioctls/diag_buffer.h" ++#endif ++ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + #define my_NAME "Fusion MPT misc device (ioctl) driver" + #define my_VERSION MPT_LINUX_VERSION_COMMON +@@ -84,6 +94,7 @@ MODULE_VERSION(my_VERSION); + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + + static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; ++static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS; + + static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); + +@@ -112,6 +123,42 @@ static int mptctl_do_reset(unsigned long + static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd); + static int mptctl_hp_targetinfo(unsigned long arg); + ++#if defined(CPQ_CIM) ++/* csmisas proto's*/ ++static int csmisas_get_driver_info(unsigned long arg); ++static int csmisas_get_cntlr_status(unsigned long arg); ++static int csmisas_get_cntlr_config(unsigned long arg); ++static int csmisas_get_phy_info(unsigned long arg); ++static int csmisas_get_scsi_address(unsigned long arg); ++static int csmisas_get_link_errors(unsigned long arg); ++static int csmisas_smp_passthru(unsigned long arg); ++static int csmisas_firmware_download(unsigned long arg); ++static int csmisas_get_raid_info(unsigned long arg); ++static int csmisas_get_raid_config(unsigned long arg); ++static int csmisas_get_raid_features(unsigned long arg); ++static int csmisas_set_raid_control(unsigned long arg); ++static int csmisas_get_raid_element(unsigned long arg); ++static int csmisas_set_raid_operation(unsigned long arg); ++static int csmisas_set_phy_info(unsigned long arg); ++static int csmisas_ssp_passthru(unsigned long arg); ++static int csmisas_stp_passthru(unsigned long arg); ++static int csmisas_get_sata_signature(unsigned long arg); ++static int csmisas_get_device_address(unsigned long arg); ++static int csmisas_task_managment(unsigned long arg); ++static int csmisas_phy_control(unsigned long arg); ++static int csmisas_get_connector_info(unsigned long arg); ++static int csmisas_get_location(unsigned long arg); ++#endif // CPQ_CIM ++ ++#if defined(DIAG_BUFFER_SUPPORT) ++/* diag_buffer proto's */ ++static int mptctl_register_diag_buffer(unsigned long arg); ++static int mptctl_release_diag_buffer(unsigned long arg); ++static int mptctl_unregister_diag_buffer(unsigned long arg); ++static int mptctl_query_diag_buffer(unsigned long arg); ++static int mptctl_read_diag_buffer(unsigned long arg); ++#endif // DIAG_BUFFER_SUPPORT ++ + static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); + static void mptctl_remove(struct pci_dev *); + +@@ -127,10 +174,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int by + struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); + static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, + struct buflist *buflist, MPT_ADAPTER *ioc); +-static void mptctl_timeout_expired (MPT_IOCTL *ioctl); +-static int mptctl_bus_reset(MPT_IOCTL *ioctl); +-static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd); +-static void mptctl_free_tm_flags(MPT_ADAPTER *ioc); + + /* + * Reset Handler cleanup function +@@ -183,10 +226,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in + int rc = 0; + + if (nonblock) { +- if (!mutex_trylock(&ioc->ioctl->ioctl_mutex)) ++ if (!mutex_trylock(&ioc->ioctl_cmds.mutex)) + rc = -EAGAIN; + } else { +- if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex)) ++ if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex)) + rc = -ERESTARTSYS; + } + return rc; +@@ -202,131 +245,104 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in + static int + mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) + { +- char *sense_data; +- int sz, req_index; +- u16 iocStatus; +- u8 cmd; +- +- if (req) +- cmd = req->u.hdr.Function; +- else +- return 1; +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, " +- "reply=%p\n", ioc->name, req->u.hdr.Function, req, reply)); +- +- if (ioc->ioctl) { ++ char *sense_data; ++ int req_index; ++ int sz; + +- if (reply==NULL) { ++ if (!req) ++ return 0; + +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply " +- "Function=%x!\n", ioc->name, cmd)); ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function " ++ "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function, ++ req, reply)); + +- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; +- ioc->ioctl->reset &= ~MPTCTL_RESET_OK; ++ /* ++ * Handling continuation of the same reply. Processing the first ++ * reply, and eating the other replys that come later. ++ */ ++ if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext) ++ goto out_continuation; + +- /* We are done, issue wake up +- */ +- ioc->ioctl->wait_done = 1; +- wake_up (&mptctl_wait); +- return 1; ++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + +- } ++ if (!reply) ++ goto out; + +- /* Copy the reply frame (which much exist +- * for non-SCSI I/O) to the IOC structure. +- */ +- memcpy(ioc->ioctl->ReplyFrame, reply, +- min(ioc->reply_sz, 4*reply->u.reply.MsgLength)); +- ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID; ++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID; ++ sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength); ++ memcpy(ioc->ioctl_cmds.reply, reply, sz); + +- /* Set the command status to GOOD if IOC Status is GOOD +- * OR if SCSI I/O cmd and data underrun or recovered error. +- */ +- iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK; +- if (iocStatus == MPI_IOCSTATUS_SUCCESS) +- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; +- +- if (iocStatus || reply->u.reply.IOCLogInfo) +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), " +- "loginfo (0x%08X)\n", ioc->name, +- iocStatus, +- le32_to_cpu(reply->u.reply.IOCLogInfo))); +- +- if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || +- (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { +- +- if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "\tscsi_status (0x%02x), scsi_state (0x%02x), " +- "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, +- reply->u.sreply.SCSIStatus, +- reply->u.sreply.SCSIState, +- le16_to_cpu(reply->u.sreply.TaskTag), +- le32_to_cpu(reply->u.sreply.TransferCount))); +- +- ioc->ioctl->reset &= ~MPTCTL_RESET_OK; +- +- if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || +- (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) { +- ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; +- } +- } ++ if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo) ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name, ++ le16_to_cpu(reply->u.reply.IOCStatus), ++ le32_to_cpu(reply->u.reply.IOCLogInfo))); ++ ++ if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) || ++ (req->u.hdr.Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { ++ ++ if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "scsi_status (0x%02x), scsi_state (0x%02x), " ++ "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, ++ reply->u.sreply.SCSIStatus, ++ reply->u.sreply.SCSIState, ++ le16_to_cpu(reply->u.sreply.TaskTag), ++ le32_to_cpu(reply->u.sreply.TransferCount))); + +- /* Copy the sense data - if present +- */ +- if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) && +- (reply->u.sreply.SCSIState & +- MPI_SCSI_STATE_AUTOSENSE_VALID)){ ++ if (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + sz = req->u.scsireq.SenseBufferLength; + req_index = + le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); +- sense_data = +- ((u8 *)ioc->sense_buf_pool + ++ sense_data = ((u8 *)ioc->sense_buf_pool + + (req_index * MPT_SENSE_BUFFER_ALLOC)); +- memcpy(ioc->ioctl->sense, sense_data, sz); +- ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID; ++ memcpy(ioc->ioctl_cmds.sense, sense_data, sz); ++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID; + } ++ } + +- if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) +- mptctl_free_tm_flags(ioc); +- +- /* We are done, issue wake up +- */ +- ioc->ioctl->wait_done = 1; +- wake_up (&mptctl_wait); ++ out: ++ /* We are done, issue wake up ++ */ ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->ioctl_cmds.done); + } ++ ++ out_continuation: ++ if (reply && (reply->u.reply.MsgFlags & ++ MPI_MSGFLAGS_CONTINUATION_REPLY)) ++ return 0; + return 1; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* mptctl_timeout_expired +- * +- * Expecting an interrupt, however timed out. +- * +- */ +-static void mptctl_timeout_expired (MPT_IOCTL *ioctl) ++static int ++mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) + { +- int rc = 1; ++ if (!mf) ++ return 0; + +- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n", +- ioctl->ioc->name, ioctl->ioc->id)); +- if (ioctl == NULL) +- return; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n", ++ ioc->name, mf, mr)); + +- ioctl->wait_done = 0; +- if (ioctl->reset & MPTCTL_RESET_OK) +- rc = mptctl_bus_reset(ioctl); +- +- if (rc) { +- /* Issue a reset for this device. +- * The IOC is not responding. +- */ +- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", +- ioctl->ioc->name)); +- mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP); +- } +- return; ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ++ ++ if (!mr) ++ goto out; + ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; ++ memcpy(ioc->taskmgmt_cmds.reply, mr, ++ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); ++ out: ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->taskmgmt_cmds.done); ++ return 1; ++ } ++ return 0; + } + + /* mptctl_bus_reset +@@ -334,132 +350,181 @@ static void mptctl_timeout_expired (MPT_ + * Bus reset code. + * + */ +-static int mptctl_bus_reset(MPT_IOCTL *ioctl) ++static int ++mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function) + { + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; +- MPT_SCSI_HOST *hd; ++ SCSITaskMgmtReply_t *pScsiTmReply; + int ii; +- int retval=0; +- +- +- ioctl->reset &= ~MPTCTL_RESET_OK; +- +- if (ioctl->ioc->sh == NULL) ++ int retval; ++ unsigned long timeout; ++ unsigned long time_count; ++ u16 iocstatus; ++ ++ /* bus reset is only good for SCSI IO, RAID PASSTHRU */ ++ if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) || ++ (function == MPI_FUNCTION_SCSI_IO_REQUEST)) { ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n", ++ ioc->name)); + return -EPERM; ++ } + +- hd = shost_priv(ioctl->ioc->sh); +- if (hd == NULL) ++ mutex_lock(&ioc->taskmgmt_cmds.mutex); ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); + return -EPERM; ++ } + +- /* Single threading .... +- */ +- if (mptctl_set_tm_flags(hd) != 0) +- return -EPERM; ++ retval = 0; + + /* Send request + */ +- if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) { +- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n", +- ioctl->ioc->name)); +- +- mptctl_free_tm_flags(ioctl->ioc); +- return -ENOMEM; ++ if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", ++ ioc->name)); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ retval = -ENOMEM; ++ goto mptctl_bus_reset_done; + } + +- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", +- ioctl->ioc->name, mf)); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", ++ ioc->name, mf)); + + pScsiTm = (SCSITaskMgmt_t *) mf; +- pScsiTm->TargetID = ioctl->id; +- pScsiTm->Bus = hd->port; /* 0 */ +- pScsiTm->ChainOffset = 0; ++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; +- pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; +- pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; +- ++ pScsiTm->TargetID = 0; ++ pScsiTm->Bus = 0; ++ pScsiTm->ChainOffset = 0; ++ pScsiTm->Reserved = 0; ++ pScsiTm->Reserved1 = 0; ++ pScsiTm->TaskMsgContext = 0; + for (ii= 0; ii < 8; ii++) + pScsiTm->LUN[ii] = 0; +- + for (ii=0; ii < 7; ii++) + pScsiTm->Reserved2[ii] = 0; + +- pScsiTm->TaskMsgContext = 0; +- dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT +- "mptctl_bus_reset: issued.\n", ioctl->ioc->name)); +- +- DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf); ++ switch (ioc->bus_type) { ++ case FC: ++ timeout = 40; ++ break; ++ case SAS: ++ timeout = 30; ++ break; ++ case SPI: ++ default: ++ timeout = 2; ++ break; ++ } + +- ioctl->wait_done=0; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", ++ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); + +- if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && +- (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05)) +- mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf); ++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ time_count = jiffies; ++ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && ++ (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) ++ mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); + else { +- retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, +- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); ++ retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc, ++ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + if (retval != 0) { +- dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!" +- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, +- hd->ioc, mf)); ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!" ++ " (ioc %p, mf %p, rc=%d) \n", ioc->name, ++ ioc, mf, retval)); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); + goto mptctl_bus_reset_done; + } + } + + /* Now wait for the command to complete */ +- ii = wait_event_timeout(mptctl_wait, +- ioctl->wait_done == 1, +- HZ*5 /* 5 second timeout */); +- +- if(ii <=0 && (ioctl->wait_done != 1 )) { +- mpt_free_msg_frame(hd->ioc, mf); +- ioctl->wait_done = 0; +- retval = -1; /* return failure */ ++ ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt failed\n", ioc->name)); ++ mpt_free_msg_frame(ioc, mf); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ retval = 0; ++ else ++ retval = -1; /* return failure */ ++ goto mptctl_bus_reset_done; + } + +-mptctl_bus_reset_done: +- +- mptctl_free_tm_flags(ioctl->ioc); +- return retval; +-} +- +-static int +-mptctl_set_tm_flags(MPT_SCSI_HOST *hd) { +- unsigned long flags; +- +- spin_lock_irqsave(&hd->ioc->FreeQlock, flags); ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt failed\n", ioc->name)); ++ retval = -1; /* return failure */ ++ goto mptctl_bus_reset_done; ++ } + +- if (hd->tmState == TM_STATE_NONE) { +- hd->tmState = TM_STATE_IN_PROGRESS; +- hd->tmPending = 1; +- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); +- } else { +- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); +- return -EBUSY; ++ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, " ++ "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, " ++ "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus, ++ pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, ++ le16_to_cpu(pScsiTmReply->IOCStatus), ++ le32_to_cpu(pScsiTmReply->IOCLogInfo), ++ pScsiTmReply->ResponseCode, ++ le32_to_cpu(pScsiTmReply->TerminationCount))); ++ ++ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ ++ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || ++ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED || ++ iocstatus == MPI_IOCSTATUS_SUCCESS) ++ retval = 0; ++ else { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt failed\n", ioc->name)); ++ retval = -1; /* return failure */ + } + +- return 0; ++ ++ mptctl_bus_reset_done: ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ return retval; + } + + static void +-mptctl_free_tm_flags(MPT_ADAPTER *ioc) ++mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) + { +- MPT_SCSI_HOST * hd; + unsigned long flags; + +- hd = shost_priv(ioc->sh); +- if (hd == NULL) ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", ++ ioc->name, __FUNCTION__)); ++ ++ if(mpt_fwfault_debug) ++ mpt_halt_firmware(ioc); ++ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress) { ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) ++ mpt_free_msg_frame(ioc, mf); + return; ++ } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + +- spin_lock_irqsave(&ioc->FreeQlock, flags); + +- hd->tmState = TM_STATE_NONE; +- hd->tmPending = 0; +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); ++ if (!mptctl_bus_reset(ioc, mf->u.hdr.Function)) ++ return; + +- return; ++ /* Issue a reset for this device. ++ * The IOC is not responding. ++ */ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", ++ ioc->name)); ++ CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ mpt_free_msg_frame(ioc, mf); + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -472,22 +537,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc) + static int + mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) + { +- MPT_IOCTL *ioctl = ioc->ioctl; +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name, +- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( +- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); +- +- if(ioctl == NULL) +- return 1; +- + switch(reset_phase) { + case MPT_IOC_SETUP_RESET: +- ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ break; ++ case MPT_IOC_PRE_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); + break; + case MPT_IOC_POST_RESET: +- ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ complete(&ioc->ioctl_cmds.done); ++ } + break; +- case MPT_IOC_PRE_RESET: + default: + break; + } +@@ -505,7 +571,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, E + event = le32_to_cpu(pEvReply->Event) & 0xFF; + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n", +- ioc->name, __func__)); ++ ioc->name, __FUNCTION__)); + if(async_queue == NULL) + return 1; + +@@ -548,15 +614,11 @@ static int + mptctl_fasync(int fd, struct file *filep, int mode) + { + MPT_ADAPTER *ioc; +- int ret; + +- lock_kernel(); + list_for_each_entry(ioc, &ioc_list, list) + ioc->aen_event_read_flag=0; + +- ret = fasync_helper(fd, filep, mode, &async_queue); +- unlock_kernel(); +- return ret; ++ return fasync_helper(fd, filep, mode, &async_queue); + } + + static int +@@ -582,6 +644,7 @@ __mptctl_ioctl(struct file *file, unsign + int ret; + MPT_ADAPTER *iocp = NULL; + ++ + if (copy_from_user(&khdr, uhdr, sizeof(khdr))) { + printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - " + "Unable to copy mpt_ioctl_header data @ %p\n", +@@ -596,17 +659,12 @@ __mptctl_ioctl(struct file *file, unsign + iocnumX = khdr.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX); + return -ENODEV; + } + +- if (!iocp->active) { +- printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n", +- __FILE__, __LINE__); +- return -EFAULT; +- } +- + /* Handle those commands that are just returning + * information stored in the driver. + * These commands should never time out and are unaffected +@@ -626,6 +684,25 @@ __mptctl_ioctl(struct file *file, unsign + return mptctl_eventreport(arg); + } else if (cmd == MPTFWREPLACE) { + return mptctl_replace_fw(arg); ++#if defined(DIAG_BUFFER_SUPPORT) ++/* diag_buffer static data calls*/ ++ } else if (cmd == MPTDIAGQUERY) { ++ return mptctl_query_diag_buffer(arg); ++ } else if (cmd == MPTDIAGUNREGISTER) { ++ return mptctl_unregister_diag_buffer(arg); ++#endif ++ ++#if defined(CPQ_CIM) ++/* csmisas static data calls*/ ++ } else if (cmd == CC_CSMI_SAS_GET_DRIVER_INFO) { ++ return csmisas_get_driver_info(arg); ++ } else if (cmd == CC_CSMI_SAS_GET_CNTLR_STATUS) { ++ return csmisas_get_cntlr_status(arg); ++ } else if (cmd == CC_CSMI_SAS_GET_SCSI_ADDRESS) { ++ return csmisas_get_scsi_address(arg); ++ } else if (cmd == CC_CSMI_SAS_GET_DEVICE_ADDRESS){ ++ return csmisas_get_device_address(arg); ++#endif // CPQ_CIM + } + + /* All of these commands require an interrupt or +@@ -634,6 +711,8 @@ __mptctl_ioctl(struct file *file, unsign + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + ++// dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT ": mptctl_ioctl()\n", iocp->name)); ++ + if (cmd == MPTFWDOWNLOAD) + ret = mptctl_fw_download(arg); + else if (cmd == MPTCOMMAND) +@@ -644,10 +723,61 @@ __mptctl_ioctl(struct file *file, unsign + ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd)); + else if (cmd == HP_GETTARGETINFO) + ret = mptctl_hp_targetinfo(arg); ++#if defined(CPQ_CIM) ++/* csmisas requiring fw calls*/ ++ else if (cmd == CC_CSMI_SAS_GET_CNTLR_CONFIG) ++ ret = csmisas_get_cntlr_config(arg); ++ else if (cmd == CC_CSMI_SAS_GET_PHY_INFO) ++ ret = csmisas_get_phy_info(arg); ++ else if (cmd == CC_CSMI_SAS_GET_SATA_SIGNATURE) ++ ret = csmisas_get_sata_signature(arg); ++ else if (cmd == CC_CSMI_SAS_GET_LINK_ERRORS) ++ ret = csmisas_get_link_errors(arg); ++ else if (cmd == CC_CSMI_SAS_SMP_PASSTHRU) ++ ret = csmisas_smp_passthru(arg); ++ else if (cmd == CC_CSMI_SAS_SSP_PASSTHRU) ++ ret = csmisas_ssp_passthru(arg); ++ else if (cmd == CC_CSMI_SAS_FIRMWARE_DOWNLOAD) ++ ret = csmisas_firmware_download(arg); ++ else if (cmd == CC_CSMI_SAS_GET_RAID_INFO) ++ ret = csmisas_get_raid_info(arg); ++ else if (cmd == CC_CSMI_SAS_GET_RAID_CONFIG) ++ ret = csmisas_get_raid_config(arg); ++ else if (cmd == CC_CSMI_SAS_GET_RAID_FEATURES) ++ ret = csmisas_get_raid_features(arg); ++ else if (cmd == CC_CSMI_SAS_SET_RAID_CONTROL) ++ ret = csmisas_set_raid_control(arg); ++ else if (cmd == CC_CSMI_SAS_GET_RAID_ELEMENT) ++ ret = csmisas_get_raid_element(arg); ++ else if (cmd == CC_CSMI_SAS_SET_RAID_OPERATION) ++ ret = csmisas_set_raid_operation(arg); ++ else if (cmd == CC_CSMI_SAS_SET_PHY_INFO) ++ ret = csmisas_set_phy_info(arg); ++ else if (cmd == CC_CSMI_SAS_STP_PASSTHRU) ++ ret = csmisas_stp_passthru(arg); ++ else if (cmd == CC_CSMI_SAS_TASK_MANAGEMENT) ++ ret = csmisas_task_managment(arg); ++ else if (cmd == CC_CSMI_SAS_PHY_CONTROL) ++ ret = csmisas_phy_control(arg); ++ else if (cmd == CC_CSMI_SAS_GET_CONNECTOR_INFO) ++ ret = csmisas_get_connector_info(arg); ++ else if (cmd == CC_CSMI_SAS_GET_LOCATION) ++ ret = csmisas_get_location(arg); ++#endif // CPQ_CIM ++ ++#if defined(DIAG_BUFFER_SUPPORT) ++/* diag_buffer requiring fw calls*/ ++ else if (cmd == MPTDIAGREGISTER) ++ ret = mptctl_register_diag_buffer(arg); ++ else if (cmd == MPTDIAGRELEASE) ++ ret = mptctl_release_diag_buffer(arg); ++ else if (cmd == MPTDIAGREADBUFFER) ++ ret = mptctl_read_diag_buffer(arg); ++#endif // DIAG_BUFFER_SUPPORT + else + ret = -EINVAL; + +- mutex_unlock(&iocp->ioctl->ioctl_mutex); ++ mutex_unlock(&iocp->ioctl_cmds.mutex); + + return ret; + } +@@ -676,6 +806,7 @@ static int mptctl_do_reset(unsigned long + } + + if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n", + __FILE__, __LINE__, krinfo.hdr.iocnum); + return -ENODEV; /* (-6) No such device or address */ +@@ -763,10 +894,11 @@ mptctl_do_fw_download(int ioc, char __us + int sge_offset = 0; + u16 iocstat; + pFWDownloadReply_t ReplyMsg = NULL; ++ unsigned long timeleft; + + if (mpt_verify_adapter(ioc, &iocp) < 0) { +- printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", +- ioc); ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) ++ printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", ioc); + return -ENODEV; /* (-6) No such device or address */ + } else { + +@@ -847,10 +979,10 @@ mptctl_do_fw_download(int ioc, char __us + * 64 4 + */ + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) +- / (sizeof(dma_addr_t) + sizeof(u32)); ++ / iocp->SGE_size; + if (numfrags > maxfrags) { + ret = -EMLINK; +- goto fwdl_out; ++ goto fwdl_out; + } + + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n", +@@ -875,19 +1007,19 @@ mptctl_do_fw_download(int ioc, char __us + if (nib == 0 || nib == 3) { + ; + } else if (sgIn->Address) { +- mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); ++ iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); + n++; + if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { + printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - " +- "Unable to copy f/w buffer hunk#%d @ %p\n", +- iocp->name, __FILE__, __LINE__, n, ufwbuf); ++ "Unable to copy f/w buffer hunk#%d @ %p\n", ++ iocp->name, __FILE__, __LINE__, n, ufwbuf); + goto fwdl_out; + } + fw_bytes_copied += bl->len; + } + sgIn++; + bl++; +- sgOut += (sizeof(dma_addr_t) + sizeof(u32)); ++ sgOut += iocp->SGE_size; + } + + DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags); +@@ -896,16 +1028,27 @@ mptctl_do_fw_download(int ioc, char __us + * Finally, perform firmware download. + */ + ReplyMsg = NULL; ++ SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext); ++ INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, iocp, mf); + + /* Now wait for the command to complete */ +- ret = wait_event_timeout(mptctl_wait, +- iocp->ioctl->wait_done == 1, +- HZ*60); +- +- if(ret <=0 && (iocp->ioctl->wait_done != 1 )) { +- /* Now we need to reset the board */ +- mptctl_timeout_expired(iocp->ioctl); ++ timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60); ++ if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ ret = -ETIME; ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); ++ if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(iocp, mf); ++ goto fwdl_out; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(iocp, mf); ++ goto fwdl_out; ++ } ++ ++ if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); ++ mpt_free_msg_frame(iocp, mf); + ret = -ENODATA; + goto fwdl_out; + } +@@ -913,31 +1056,34 @@ mptctl_do_fw_download(int ioc, char __us + if (sgl) + kfree_sgl(sgl, sgl_dma, buflist, iocp); + +- ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame; ++ ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; + iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; + if (iocstat == MPI_IOCSTATUS_SUCCESS) { +- printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name); ++ printk(MYIOC_s_INFO_FMT ": F/W update successfully sent!\n", iocp->name); + return 0; + } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { +- printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n", +- iocp->name); ++ printk(MYIOC_s_WARN_FMT "Hmmm... doesn't support F/W download?\n", ++ iocp->name); + printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n", +- iocp->name); ++ iocp->name); + return -EBADRQC; + } else if (iocstat == MPI_IOCSTATUS_BUSY) { + printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name); + printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name); + return -EBUSY; + } else { +- printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n", +- iocp->name, iocstat); ++ printk(MYIOC_s_WARN_FMT "returned [bad] status = %04xh\n", ++ iocp->name, iocstat); + printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name); + return -ENOMSG; + } + return 0; + + fwdl_out: +- kfree_sgl(sgl, sgl_dma, buflist, iocp); ++ ++ CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status); ++ SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0); ++ kfree_sgl(sgl, sgl_dma, buflist, iocp); + return ret; + } + +@@ -1008,7 +1154,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i + * + */ + sgl = sglbuf; +- sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1; ++ sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1; + while (bytes_allocd < bytes) { + this_alloc = min(alloc_sz, bytes-bytes_allocd); + buflist[buflist_ent].len = this_alloc; +@@ -1019,9 +1165,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i + alloc_sz = alloc_sz / 2; + if (alloc_sz == 0) { + printk(MYIOC_s_WARN_FMT "-SG: No can do - " +- "not enough memory! :-(\n", ioc->name); ++ "not enough memory! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n", +- ioc->name, numfrags); ++ ioc->name, numfrags); + goto free_and_fail; + } + continue; +@@ -1029,7 +1175,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i + dma_addr_t dma_addr; + + bytes_allocd += this_alloc; +- sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc); ++ sgl->FlagsLength = (0x10000000|sgdir|this_alloc); ++ if (ioc->sg_addr_size == sizeof(u64)) ++ sgl->FlagsLength |= MPT_SGE_FLAGS_64_BIT_ADDRESSING; + dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); + sgl->Address = dma_addr; + +@@ -1044,8 +1192,8 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i + + /* Need to chain? */ + if (fragcnt == sg_spill) { +- printk(MYIOC_s_WARN_FMT +- "-SG: No can do - " "Chain required! :-(\n", ioc->name); ++ printk(MYIOC_s_WARN_FMT "-SG: No can do - " ++ "Chain required! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags); + goto free_and_fail; + } +@@ -1054,9 +1202,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i + if (numfrags*8 > MAX_SGL_BYTES){ + /* GRRRRR... */ + printk(MYIOC_s_WARN_FMT "-SG: No can do - " +- "too many SG frags! :-(\n", ioc->name); ++ "too many SG frags! :-(\n", ioc->name); + printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n", +- ioc->name, numfrags); ++ ioc->name, numfrags); + goto free_and_fail; + } + } +@@ -1213,6 +1361,7 @@ mptctl_getiocinfo (unsigned long arg, un + + if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + kfree(karg); +@@ -1222,8 +1371,8 @@ mptctl_getiocinfo (unsigned long arg, un + /* Verify the data transfer size is correct. */ + if (karg->hdr.maxDataSize != data_size) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " +- "Structure size mismatch. Command not completed.\n", +- ioc->name, __FILE__, __LINE__); ++ "Structure size mismatch. Command not completed.\n", ++ ioc->name, __FILE__, __LINE__); + kfree(karg); + return -EFAULT; + } +@@ -1275,6 +1424,8 @@ mptctl_getiocinfo (unsigned long arg, un + if (ioc->sh) { + shost_for_each_device(sdev, ioc->sh) { + vdevice = sdev->hostdata; ++ if (vdevice == NULL || vdevice->vtarget == NULL) ++ continue; + if (vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; +@@ -1346,6 +1497,7 @@ mptctl_gettargetinfo (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; +@@ -1362,8 +1514,8 @@ mptctl_gettargetinfo (unsigned long arg) + port = karg.hdr.port; + + if (maxWordsLeft <= 0) { +- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n", +- ioc->name, __FILE__, __LINE__); ++ printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n", ++ ioc->name, __FILE__, __LINE__); + return -ENOMEM; + } + +@@ -1383,8 +1535,8 @@ mptctl_gettargetinfo (unsigned long arg) + */ + pmem = kzalloc(numBytes, GFP_KERNEL); + if (!pmem) { +- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n", +- ioc->name, __FILE__, __LINE__); ++ printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n", ++ ioc->name, __FILE__, __LINE__); + return -ENOMEM; + } + pdata = (int *) pmem; +@@ -1396,6 +1548,8 @@ mptctl_gettargetinfo (unsigned long arg) + if (!maxWordsLeft) + continue; + vdevice = sdev->hostdata; ++ if (vdevice == NULL || vdevice->vtarget == NULL) ++ continue; + if (vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; +@@ -1460,6 +1614,7 @@ mptctl_readtest (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; +@@ -1521,6 +1676,7 @@ mptctl_eventquery (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; +@@ -1560,6 +1716,7 @@ mptctl_eventenable (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; +@@ -1573,8 +1730,7 @@ mptctl_eventenable (unsigned long arg) + int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + ioc->events = kzalloc(sz, GFP_KERNEL); + if (!ioc->events) { +- printk(MYIOC_s_ERR_FMT +- ": ERROR - Insufficient memory to add adapter!\n", ++ printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", + ioc->name); + return -ENOMEM; + } +@@ -1609,13 +1765,14 @@ mptctl_eventreport (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } ++ + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n", + ioc->name)); +- + numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header); + maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS); + +@@ -1663,6 +1820,7 @@ mptctl_replace_fw (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; +@@ -1694,8 +1852,8 @@ mptctl_replace_fw (unsigned long arg) + */ + if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - " +- "Unable to read in mpt_ioctl_replace_fw image " +- "@ %p\n", ioc->name, __FILE__, __LINE__, uarg); ++ "Unable to read in mpt_ioctl_replace_fw image " ++ "@ %p\n", ioc->name, __FILE__, __LINE__, uarg); + mpt_free_fw_memory(ioc); + return -EFAULT; + } +@@ -1712,7 +1870,7 @@ mptctl_replace_fw (unsigned long arg) + * + * Outputs: None. + * Return: 0 if successful +- * -EBUSY if previous command timeout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires +@@ -1737,6 +1895,7 @@ mptctl_mpt_command (unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; +@@ -1752,7 +1911,7 @@ mptctl_mpt_command (unsigned long arg) + * + * Outputs: None. + * Return: 0 if successful +- * -EBUSY if previous command timeout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires +@@ -1775,8 +1934,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + int sz, rc = 0; + int msgContext; + u16 req_idx; +- ulong timeout; ++ unsigned long timeout; ++ unsigned long timeleft; + struct scsi_device *sdev; ++ unsigned long flags; ++ u8 function; + + /* bufIn and bufOut are used for user to kernel space transfers + */ +@@ -1785,28 +1947,28 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } +- if (!ioc->ioctl) { +- printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " +- "No memory available during driver init.\n", +- __FILE__, __LINE__); +- return -ENOMEM; +- } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { ++ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress) { ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " +- "Busy with IOC Reset \n", __FILE__, __LINE__); ++ "Busy with diagnostic reset\n", __FILE__, __LINE__); + return -EBUSY; + } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + /* Verify that the final request frame will not be too large. + */ + sz = karg.dataSgeOffset * 4; + if (karg.dataInSize > 0) +- sz += sizeof(dma_addr_t) + sizeof(u32); ++ sz += ioc->SGE_size; + if (karg.dataOutSize > 0) +- sz += sizeof(dma_addr_t) + sizeof(u32); ++ sz += ioc->SGE_size; + + if (sz > ioc->req_sz) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " +@@ -1832,18 +1994,19 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " + "Unable to read MF from mpt_ioctl_command struct @ %p\n", + ioc->name, __FILE__, __LINE__, mfPtr); ++ function = -1; + rc = -EFAULT; + goto done_free_mem; + } + hdr->MsgContext = cpu_to_le32(msgContext); +- ++ function = hdr->Function; + + /* Verify that this request is allowed. + */ + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n", +- ioc->name, hdr->Function, mf)); ++ ioc->name, function, mf)); + +- switch (hdr->Function) { ++ switch (function) { + case MPI_FUNCTION_IOC_FACTS: + case MPI_FUNCTION_PORT_FACTS: + karg.dataOutSize = karg.dataInSize = 0; +@@ -1898,7 +2061,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + } + + pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; +- pScsiReq->MsgFlags |= mpt_msg_flags(); ++ pScsiReq->MsgFlags |= mpt_msg_flags(ioc); + + + /* verify that app has not requested +@@ -1920,6 +2083,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + struct scsi_target *starget = scsi_target(sdev); + VirtTarget *vtarget = starget->hostdata; + ++ if (vtarget == NULL) ++ continue; + if ((pScsiReq->TargetID == vtarget->id) && + (pScsiReq->Bus == vtarget->channel) && + (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) +@@ -1940,9 +2105,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + pScsiReq->Control = cpu_to_le32(scsidir | qtag); + pScsiReq->DataLength = cpu_to_le32(dataSize); + +- ioc->ioctl->reset = MPTCTL_RESET_OK; +- ioc->ioctl->id = pScsiReq->TargetID; +- + } else { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " + "SCSI driver is not loaded. \n", +@@ -1955,7 +2117,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + case MPI_FUNCTION_SMP_PASSTHROUGH: + /* Check mf->PassthruFlags to determine if + * transfer is ImmediateMode or not. +- * Immediate mode returns data in the ReplyFrame. ++ * Immediate mode returns data in the reply. + * Else, we are sending request and response data + * in two SGLs at the end of the mf. + */ +@@ -1984,7 +2146,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + int dataSize; + + pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; +- pScsiReq->MsgFlags |= mpt_msg_flags(); ++ pScsiReq->MsgFlags |= mpt_msg_flags(ioc); + + + /* verify that app has not requested +@@ -2019,8 +2181,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + pScsiReq->Control = cpu_to_le32(scsidir | qtag); + pScsiReq->DataLength = cpu_to_le32(dataSize); + +- ioc->ioctl->reset = MPTCTL_RESET_OK; +- ioc->ioctl->id = pScsiReq->TargetID; + } else { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " + "SCSI driver is not loaded. \n", +@@ -2031,20 +2191,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + break; + + case MPI_FUNCTION_SCSI_TASK_MGMT: +- { +- MPT_SCSI_HOST *hd = NULL; +- if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) { +- printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " +- "SCSI driver not loaded or SCSI host not found. \n", +- ioc->name, __FILE__, __LINE__); +- rc = -EFAULT; +- goto done_free_mem; +- } else if (mptctl_set_tm_flags(hd) != 0) { +- rc = -EPERM; +- goto done_free_mem; +- } +- } ++ { ++ SCSITaskMgmt_t *pScsiTm; ++ pScsiTm = (SCSITaskMgmt_t *)mf; ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tTaskType=0x%x MsgFlags=0x%x " ++ "TaskMsgContext=0x%x id=%d channel=%d\n", ioc->name, pScsiTm->TaskType, ++ le32_to_cpu(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags, ++ pScsiTm->TargetID, pScsiTm->Bus)); + break; ++ } + + case MPI_FUNCTION_IOC_INIT: + { +@@ -2054,7 +2209,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + /* Verify that all entries in the IOC INIT match + * existing setup (and in LE format). + */ +- if (sizeof(dma_addr_t) == sizeof(u64)) { ++ if (ioc->sg_addr_size == sizeof(u64)) { + high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); + sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); + } else { +@@ -2062,6 +2217,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + sense_high= 0; + } + ++ if (!pInit->MaxDevices && !pInit->MaxBuses) { ++ pInit->MaxDevices = ioc->facts.MaxDevices; ++ pInit->MaxBuses = ioc->facts.MaxBuses; ++ } ++ + if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) || + (pInit->MaxBuses != ioc->facts.MaxBuses) || + (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) || +@@ -2102,7 +2262,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " + "Illegal request (function 0x%x) \n", +- ioc->name, __FILE__, __LINE__, hdr->Function); ++ ioc->name, __FILE__, __LINE__, function); + rc = -EFAULT; + goto done_free_mem; + } +@@ -2128,8 +2288,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + if (karg.dataInSize > 0) { + flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | +- MPI_SGE_FLAGS_DIRECTION | +- mpt_addr_size() ) ++ MPI_SGE_FLAGS_DIRECTION ) + << MPI_SGE_FLAGS_SHIFT; + } else { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; +@@ -2146,8 +2305,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + /* Set up this SGE. + * Copy to MF and to sglbuf + */ +- mpt_add_sge(psge, flagsLength, dma_addr_out); +- psge += (sizeof(u32) + sizeof(dma_addr_t)); ++ ioc->add_sge(psge, flagsLength, dma_addr_out); ++ psge += ioc->SGE_size; + + /* Copy user data to kernel space. + */ +@@ -2180,17 +2339,24 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + /* Set up this SGE + * Copy to MF and to sglbuf + */ +- mpt_add_sge(psge, flagsLength, dma_addr_in); ++ ioc->add_sge(psge, flagsLength, dma_addr_in); + } + } + } else { + /* Add a NULL SGE + */ +- mpt_add_sge(psge, flagsLength, (dma_addr_t) -1); ++ ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); + } + +- ioc->ioctl->wait_done = 0; +- if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext); ++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) ++ if (function == MPI_FUNCTION_SCSI_TASK_MGMT) { ++ ++ mutex_lock(&ioc->taskmgmt_cmds.mutex); ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ goto done_free_mem; ++ } + + DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); + +@@ -2198,53 +2364,57 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf); + else { +- rc =mpt_send_handshake_request(mptctl_id, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); ++ rc = mpt_send_handshake_request(mptctl_id, ioc, ++ sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); + if (rc != 0) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "_send_handshake FAILED! (ioc %p, mf %p)\n", ++ "send_handshake FAILED! (ioc %p, mf %p)\n", + ioc->name, ioc, mf)); +- mptctl_free_tm_flags(ioc); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); + rc = -ENODATA; ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); + goto done_free_mem; + } + } +- + } else + mpt_put_msg_frame(mptctl_id, ioc, mf); + + /* Now wait for the command to complete */ + timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT; +- timeout = wait_event_timeout(mptctl_wait, +- ioc->ioctl->wait_done == 1, +- HZ*timeout); +- +- if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) { +- /* Now we need to reset the board */ +- +- if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) +- mptctl_free_tm_flags(ioc); +- +- mptctl_timeout_expired(ioc->ioctl); +- rc = -ENODATA; ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ rc = -ETIME; ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n", ++ ioc->name, __FUNCTION__)); ++ if (function == MPI_FUNCTION_SCSI_TASK_MGMT) ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ goto done_free_mem; ++ } ++ if (!timeleft) { ++ mptctl_timeout_expired(ioc, mf); ++ mf = NULL; ++ } + goto done_free_mem; + } + ++ if (function == MPI_FUNCTION_SCSI_TASK_MGMT) ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ + mf = NULL; + + /* If a valid reply frame, copy to the user. + * Offset 2: reply length in U32's + */ +- if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + if (karg.maxReplyBytes < ioc->reply_sz) { +- sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); ++ sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]); + } else { +- sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); ++ sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]); + } +- + if (sz > 0) { + if (copy_to_user(karg.replyFrameBufPtr, +- &ioc->ioctl->ReplyFrame, sz)){ ++ ioc->ioctl_cmds.reply, sz)){ + printk(MYIOC_s_ERR_FMT + "%s@%d::mptctl_do_mpt_command - " + "Unable to write out reply frame %p\n", +@@ -2257,10 +2427,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + + /* If valid sense data, copy to user. + */ +- if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) { ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) { + sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); + if (sz > 0) { +- if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) { ++ if (copy_to_user(karg.senseDataPtr, ioc->ioctl_cmds.sense, sz)) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " + "Unable to write sense data to user %p\n", + ioc->name, __FILE__, __LINE__, +@@ -2274,9 +2444,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + /* If the overall status is _GOOD and data in, copy data + * to user. + */ +- if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) && +- (karg.dataInSize > 0) && (bufIn.kptr)) { +- ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) && ++ (karg.dataInSize > 0) && (bufIn.kptr)) { + if (copy_to_user(karg.dataInBufPtr, + bufIn.kptr, karg.dataInSize)) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " +@@ -2289,9 +2458,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + + done_free_mem: + +- ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD | +- MPT_IOCTL_STATUS_SENSE_VALID | +- MPT_IOCTL_STATUS_RF_VALID ); ++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + + /* Free the allocated memory. + */ +@@ -2320,7 +2488,7 @@ done_free_mem: + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timeout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error +@@ -2331,16 +2499,17 @@ mptctl_hp_hostinfo(unsigned long arg, un + hp_host_info_t __user *uarg = (void __user *) arg; + MPT_ADAPTER *ioc; + struct pci_dev *pdev; +- char *pbuf=NULL; ++ char *pbuf=NULL; + dma_addr_t buf_dma; + hp_host_info_t karg; +- CONFIGPARMS cfg; +- ConfigPageHeader_t hdr; + int iocnum; +- int rc, cim_rev; ++ int cim_rev; + ToolboxIstwiReadWriteRequest_t *IstwiRWRequest; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; ++ unsigned long timeleft; ++ int retval; ++ u32 MsgContext; + + /* Reset long to int. Should affect IA64 and SPARC only + */ +@@ -2360,13 +2529,14 @@ mptctl_hp_hostinfo(unsigned long arg, un + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } ++ + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n", + ioc->name)); +- + /* Fill in the data and return the structure to the calling + * program + */ +@@ -2406,42 +2576,9 @@ mptctl_hp_hostinfo(unsigned long arg, un + karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0'; + karg.fw_version[11] = '\0'; + +- /* Issue a config request to get the device serial number +- */ +- hdr.PageVersion = 0; +- hdr.PageLength = 0; +- hdr.PageNumber = 0; +- hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; +- cfg.cfghdr.hdr = &hdr; +- cfg.physAddr = -1; +- cfg.pageAddr = 0; +- cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; +- cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ strncpy(karg.serial_number, ioc->board_tracer, 16); + +- strncpy(karg.serial_number, " ", 24); +- if (mpt_config(ioc, &cfg) == 0) { +- if (cfg.cfghdr.hdr->PageLength > 0) { +- /* Issue the second config page request */ +- cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; +- +- pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); +- if (pbuf) { +- cfg.physAddr = buf_dma; +- if (mpt_config(ioc, &cfg) == 0) { +- ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; +- if (strlen(pdata->BoardTracerNumber) > 1) { +- strncpy(karg.serial_number, pdata->BoardTracerNumber, 24); +- karg.serial_number[24-1]='\0'; +- } +- } +- pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); +- pbuf = NULL; +- } +- } +- } +- rc = mpt_GetIocState(ioc, 1); +- switch (rc) { ++ switch (mpt_GetIocState(ioc, 1)) { + case MPI_IOC_STATE_OPERATIONAL: + karg.ioc_status = HP_STATUS_OK; + break; +@@ -2468,12 +2605,12 @@ mptctl_hp_hostinfo(unsigned long arg, un + karg.soft_resets = 0; + karg.timeouts = 0; + if (ioc->sh != NULL) { +- MPT_SCSI_HOST *hd = shost_priv(ioc->sh); ++ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + + if (hd && (cim_rev == 1)) { +- karg.hard_resets = hd->hard_resets; +- karg.soft_resets = hd->soft_resets; +- karg.timeouts = hd->timeouts; ++ karg.hard_resets = ioc->hard_resets; ++ karg.soft_resets = ioc->soft_resets; ++ karg.timeouts = ioc->timeouts; + } + } + +@@ -2482,16 +2619,18 @@ mptctl_hp_hostinfo(unsigned long arg, un + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", +- ioc->name,__func__)); ++ ioc->name,__FUNCTION__)); ++ retval = -ENOMEM; + goto out; + } + + IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf; + mpi_hdr = (MPIHeader_t *) mf; ++ MsgContext = mpi_hdr->MsgContext; + memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t)); + IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX; + IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL; +- IstwiRWRequest->MsgContext = mpi_hdr->MsgContext; ++ IstwiRWRequest->MsgContext = MsgContext; + IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ; + IstwiRWRequest->NumAddressBytes = 0x01; + IstwiRWRequest->DataLength = cpu_to_le16(0x04); +@@ -2501,28 +2640,30 @@ mptctl_hp_hostinfo(unsigned long arg, un + IstwiRWRequest->DeviceAddr = 0xB0; + + pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); +- if (!pbuf) ++ if (!pbuf) { ++ retval = -ENOMEM; + goto out; +- mpt_add_sge((char *)&IstwiRWRequest->SGL, +- (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma); ++ } ++ ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4),buf_dma); + +- ioc->ioctl->wait_done = 0; ++ retval = 0; ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, IstwiRWRequest->MsgContext); ++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); +- +- rc = wait_event_timeout(mptctl_wait, +- ioc->ioctl->wait_done == 1, +- HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */); +- +- if(rc <=0 && (ioc->ioctl->wait_done != 1 )) { +- /* +- * Now we need to reset the board +- */ +- mpt_free_msg_frame(ioc, mf); +- mptctl_timeout_expired(ioc->ioctl); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*MPT_IOCTL_DEFAULT_TIMEOUT); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ retval = -ETIME; ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __FUNCTION__); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ goto out; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(ioc, mf); + goto out; + } + +- /* ++ /* + *ISTWI Data Definition + * pbuf[0] = FW_VERSION = 0x4 + * pbuf[1] = Bay Count = 6 or 4 or 2, depending on +@@ -2531,10 +2672,13 @@ mptctl_hp_hostinfo(unsigned long arg, un + * bays have drives in them + * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3) + */ +- if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) + karg.rsvd = *(u32 *)pbuf; + + out: ++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); ++ + if (pbuf) + pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); + +@@ -2547,7 +2691,7 @@ mptctl_hp_hostinfo(unsigned long arg, un + return -EFAULT; + } + +- return 0; ++ return retval; + + } + +@@ -2557,7 +2701,7 @@ mptctl_hp_hostinfo(unsigned long arg, un + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timeout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error +@@ -2587,13 +2731,14 @@ mptctl_hp_targetinfo(unsigned long arg) + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnum); + return -ENODEV; + } +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", +- ioc->name)); + ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n", ++ ioc->name)); + /* There is nothing to do for FCP parts. + */ + if ((ioc->bus_type == SAS) || (ioc->bus_type == FC)) +@@ -2685,7 +2830,7 @@ mptctl_hp_targetinfo(unsigned long arg) + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma); + } + } +- hd = shost_priv(ioc->sh); ++ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd != NULL) + karg.select_timeouts = hd->sel_timeout[karg.hdr.id]; + +@@ -2703,7 +2848,7 @@ mptctl_hp_targetinfo(unsigned long arg) + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +-static const struct file_operations mptctl_fops = { ++static struct file_operations mptctl_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .release = mptctl_release, +@@ -2743,8 +2888,9 @@ compat_mptfwxfer_ioctl(struct file *filp + iocnumX = kfw32.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n", +- __LINE__, iocnumX); ++ __LINE__, iocnumX); + return -ENODEV; + } + +@@ -2759,7 +2905,7 @@ compat_mptfwxfer_ioctl(struct file *filp + + ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + +- mutex_unlock(&iocp->ioctl->ioctl_mutex); ++ mutex_unlock(&iocp->ioctl_cmds.mutex); + + return ret; + } +@@ -2783,8 +2929,9 @@ compat_mpt_command(struct file *filp, un + iocnumX = karg32.hdr.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { ++ if (mpt_debug_level & MPT_DEBUG_IOCTL) + printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n", +- __LINE__, iocnumX); ++ __LINE__, iocnumX); + return -ENODEV; + } + +@@ -2813,7 +2960,7 @@ compat_mpt_command(struct file *filp, un + */ + ret = mptctl_do_mpt_command (karg, &uarg->MF); + +- mutex_unlock(&iocp->ioctl->ioctl_mutex); ++ mutex_unlock(&iocp->ioctl_cmds.mutex); + + return ret; + } +@@ -2833,6 +2980,31 @@ static long compat_mpctl_ioctl(struct fi + case MPTHARDRESET: + case HP_GETHOSTINFO: + case HP_GETTARGETINFO: ++#if defined(CPQ_CIM) ++ case CC_CSMI_SAS_GET_DRIVER_INFO: ++ case CC_CSMI_SAS_GET_CNTLR_CONFIG: ++ case CC_CSMI_SAS_GET_CNTLR_STATUS: ++ case CC_CSMI_SAS_GET_SCSI_ADDRESS: ++ case CC_CSMI_SAS_GET_DEVICE_ADDRESS: ++ case CC_CSMI_SAS_GET_PHY_INFO: ++ case CC_CSMI_SAS_GET_SATA_SIGNATURE: ++ case CC_CSMI_SAS_GET_LINK_ERRORS: ++ case CC_CSMI_SAS_SMP_PASSTHRU: ++ case CC_CSMI_SAS_SSP_PASSTHRU: ++ case CC_CSMI_SAS_FIRMWARE_DOWNLOAD: ++ case CC_CSMI_SAS_GET_RAID_INFO: ++ case CC_CSMI_SAS_GET_RAID_CONFIG: ++ case CC_CSMI_SAS_GET_RAID_FEATURES: ++ case CC_CSMI_SAS_SET_RAID_CONTROL: ++ case CC_CSMI_SAS_GET_RAID_ELEMENT: ++ case CC_CSMI_SAS_SET_RAID_OPERATION: ++ case CC_CSMI_SAS_SET_PHY_INFO: ++ case CC_CSMI_SAS_STP_PASSTHRU: ++ case CC_CSMI_SAS_TASK_MANAGEMENT: ++ case CC_CSMI_SAS_PHY_CONTROL: ++ case CC_CSMI_SAS_GET_CONNECTOR_INFO: ++ case CC_CSMI_SAS_GET_LOCATION: ++#endif /* CPQ_CIM */ + case MPTTEST: + ret = __mptctl_ioctl(f, cmd, arg); + break; +@@ -2865,21 +3037,11 @@ static long compat_mpctl_ioctl(struct fi + static int + mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { +- MPT_IOCTL *mem; + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + +- /* +- * Allocate and inite a MPT_IOCTL structure +- */ +- mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL); +- if (!mem) { +- mptctl_remove(pdev); +- return -ENOMEM; +- } ++ mutex_init(&ioc->ioctl_cmds.mutex); ++ init_completion(&ioc->ioctl_cmds.done); + +- ioc->ioctl = mem; +- ioc->ioctl->ioc = ioc; +- mutex_init(&ioc->ioctl->ioctl_mutex); + return 0; + } + +@@ -2893,9 +3055,22 @@ mptctl_probe(struct pci_dev *pdev, const + static void + mptctl_remove(struct pci_dev *pdev) + { ++#if defined(DIAG_BUFFER_SUPPORT) + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); ++ int i; + +- kfree ( ioc->ioctl ); ++ /* ++ * Cleanup diag buffer allocated memory ++ */ ++ for (i = 0; i < MPI_DIAG_BUF_TYPE_COUNT; i++) { ++ if (ioc->DiagBuffer[i] == NULL) ++ continue; ++ pci_free_consistent(ioc->pcidev, ioc->DiagBuffer_sz[i], ++ ioc->DiagBuffer[i], ioc->DiagBuffer_dma[i]); ++ ioc->DiagBuffer[i] = NULL; ++ ioc->DiagBuffer_Status[i] = 0; ++ } ++#endif + } + + static struct mpt_pci_driver mptctl_driver = { +@@ -2935,6 +3110,7 @@ static int __init mptctl_init(void) + goto out_fail; + } + ++ mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER); + mpt_reset_register(mptctl_id, mptctl_ioc_reset); + mpt_event_register(mptctl_id, mptctl_event_process); + +@@ -2956,15 +3132,23 @@ static void mptctl_exit(void) + + /* De-register reset handler from base module */ + mpt_reset_deregister(mptctl_id); ++ mpt_reset_deregister(mptctl_taskmgmt_id); + + /* De-register callback handler from base module */ + mpt_deregister(mptctl_id); + + mpt_device_driver_deregister(MPTCTL_DRIVER); +- + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + ++#if defined(CPQ_CIM) ++#include "csmi/csmisas.c" ++#endif // CPQ_CIM ++ ++#if defined(DIAG_BUFFER_SUPPORT) ++#include "rejected_ioctls/diag_buffer.c" ++#endif ++ + module_init(mptctl_init); + module_exit(mptctl_exit); +--- a/drivers/message/fusion/mptctl.h ++++ b/drivers/message/fusion/mptctl.h +@@ -1,5 +1,5 @@ + /* +- * linux/drivers/message/fusion/mptioctl.h ++ * linux/drivers/message/fusion/mptctl.h + * Fusion MPT misc device (ioctl) driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel +@@ -460,8 +460,5 @@ typedef struct _hp_target_info { + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +- + #endif + +--- a/drivers/message/fusion/mptdebug.h ++++ b/drivers/message/fusion/mptdebug.h +@@ -17,6 +17,10 @@ + * + * Example: (programming for MPT_DEBUG_EVENTS on host 5) + * ++ * global setting: ++ * echo 8 > /sys/module/mptbase/parameters/mpt_debug_level ++ * ++ * per host setting: + * echo 8 > /sys/class/scsi_host/host5/debug_level + * + * -------------------------------------------------------- +@@ -55,9 +59,11 @@ + #define MPT_DEBUG_RESET 0x00008000 + #define MPT_DEBUG_SCSI 0x00010000 + #define MPT_DEBUG_IOCTL 0x00020000 ++#define MPT_DEBUG_CSMISAS 0x00040000 + #define MPT_DEBUG_FC 0x00080000 + #define MPT_DEBUG_SAS 0x00100000 + #define MPT_DEBUG_SAS_WIDE 0x00200000 ++#define MPT_DEBUG_36GB_MEM 0x00400000 + + /* + * CONFIG_FUSION_LOGGING - enabled in Kconfig +@@ -126,6 +132,9 @@ + #define dctlprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL) + ++#define dcsmisasprintk(IOC, CMD) \ ++ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS) ++ + #define dfcprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FC) + +@@ -135,7 +144,8 @@ + #define dsaswideprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) + +- ++#define d36memprintk(IOC, CMD) \ ++ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM) + + /* + * Verbose logging +--- a/drivers/message/fusion/mptfc.c ++++ b/drivers/message/fusion/mptfc.c +@@ -43,6 +43,7 @@ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++ + #include + #include + #include +@@ -52,8 +53,10 @@ + #include /* for mdelay */ + #include /* needed for in_interrupt() proto */ + #include /* notifier code */ ++#include + #include + #include ++#include + + #include + #include +@@ -84,6 +87,14 @@ MODULE_PARM_DESC(mptfc_dev_loss_tmo, " I + " return following a device loss event." + " Default=60."); + ++static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; ++static int mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp); ++module_param_call(mpt_sdev_queue_depth, mptfc_set_sdev_queue_depth, ++ param_get_int, &mpt_sdev_queue_depth, 0600); ++MODULE_PARM_DESC(mpt_sdev_queue_depth, ++ " Max Device Queue Depth (default=" ++ __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")"); ++ + /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ + #define MPTFC_MAX_LUN (16895) + static int max_lun = MPTFC_MAX_LUN; +@@ -183,6 +194,34 @@ static struct fc_function_template mptfc + .show_host_symbolic_name = 1, + }; + ++/** ++ * mptfc_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth ++ * found via /sys/module/mptfc/parameters/mpt_sdev_queue_depth ++ * @val: ++ * @kp: ++ * ++ * Returns ++ **/ ++static int ++mptfc_set_sdev_queue_depth(const char *val, struct kernel_param *kp) ++{ ++ int ret = param_set_int(val, kp); ++ MPT_ADAPTER *ioc; ++ struct scsi_device *sdev; ++ ++ if (ret) ++ return ret; ++ ++ list_for_each_entry(ioc, &ioc_list, list) { ++ if (ioc->bus_type != FC) ++ continue; ++ shost_for_each_device(sdev, ioc->sh) ++ mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth); ++ ioc->sdev_queue_depth = mpt_sdev_queue_depth; ++ } ++ return 0; ++} ++ + static int + mptfc_block_error_handler(struct scsi_cmnd *SCpnt, + int (*func)(struct scsi_cmnd *SCpnt), +@@ -194,7 +233,7 @@ mptfc_block_error_handler(struct scsi_cm + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + unsigned long flags; + int ready; +- MPT_ADAPTER *ioc; ++ MPT_ADAPTER *ioc; + + hd = shost_priv(SCpnt->device->host); + ioc = hd->ioc; +@@ -231,28 +270,28 @@ static int + mptfc_abort(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__); ++ mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__); + } + + static int + mptfc_dev_reset(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__); ++ mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__); + } + + static int + mptfc_bus_reset(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__); ++ mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__); + } + + static int + mptfc_host_reset(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__); ++ mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__); + } + + static void +@@ -476,6 +515,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int + if (vtarget) { + vtarget->id = pg0->CurrentTargetID; + vtarget->channel = pg0->CurrentBus; ++ vtarget->deleted = 0; + } + } + *((struct mptfc_rport_info **)rport->dd_data) = ri; +@@ -513,6 +553,7 @@ mptfc_target_destroy(struct scsi_target + struct fc_rport *rport; + struct mptfc_rport_info *ri; + ++ printk("%s - starget=%p\n", __FUNCTION__, starget); + rport = starget_to_rport(starget); + if (rport) { + ri = *((struct mptfc_rport_info **)rport->dd_data); +@@ -560,6 +601,7 @@ mptfc_target_alloc(struct scsi_target *s + + return rc; + } ++ + /* + * mptfc_dump_lun_info + * @ioc +@@ -589,7 +631,6 @@ mptfc_dump_lun_info(MPT_ADAPTER *ioc, st + (unsigned long long)nn)); + } + +- + /* + * OS entry point to allow host driver to alloc memory + * for each scsi device. Called once per device the bus scan. +@@ -604,7 +645,7 @@ mptfc_slave_alloc(struct scsi_device *sd + VirtDevice *vdevice; + struct scsi_target *starget; + struct fc_rport *rport; +- MPT_ADAPTER *ioc; ++ MPT_ADAPTER *ioc; + + starget = scsi_target(sdev); + rport = starget_to_rport(starget); +@@ -614,11 +655,10 @@ mptfc_slave_alloc(struct scsi_device *sd + + hd = shost_priv(sdev->host); + ioc = hd->ioc; +- + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { + printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", +- ioc->name, sizeof(VirtDevice)); ++ ioc->name, sizeof(VirtDevice)); + return -ENOMEM; + } + +@@ -635,10 +675,7 @@ mptfc_slave_alloc(struct scsi_device *sd + vdevice->lun = sdev->lun; + + vtarget->num_luns++; +- +- + mptfc_dump_lun_info(ioc, rport, sdev, vtarget); +- + return 0; + } + +@@ -944,11 +981,12 @@ start_over: + return rc; + } + +-static void ++static int + mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc) + { + int ii; + FCPortPage1_t *pp1; ++ int rc; + + #define MPTFC_FW_DEVICE_TIMEOUT (1) + #define MPTFC_FW_IO_PEND_TIMEOUT (1) +@@ -956,8 +994,8 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE + #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS) + + for (ii=0; iifacts.NumberOfPorts; ii++) { +- if (mptfc_GetFcPortPage1(ioc, ii) != 0) +- continue; ++ if ((rc = mptfc_GetFcPortPage1(ioc, ii)) < 0) ++ return rc; + pp1 = ioc->fc_data.fc_port_page1[ii].data; + if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT) + && (pp1->InitiatorIoPendTimeout == MPTFC_FW_IO_PEND_TIMEOUT) +@@ -968,8 +1006,10 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE + pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT; + pp1->Flags &= ~OFF_FLAGS; + pp1->Flags |= ON_FLAGS; +- mptfc_WriteFcPortPage1(ioc, ii); ++ if ((rc = mptfc_WriteFcPortPage1(ioc, ii)) < 0) ++ return rc; + } ++ return 0; + } + + +@@ -1082,10 +1122,13 @@ mptfc_link_status_change(struct work_str + static void + mptfc_setup_reset(struct work_struct *work) + { +- MPT_ADAPTER *ioc = ++ MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_setup_reset_work); + u64 pn; + struct mptfc_rport_info *ri; ++ struct scsi_target *starget; ++ VirtTarget *vtarget; ++ + + /* reset about to happen, delete (block) all rports */ + list_for_each_entry(ri, &ioc->fc_rports, list) { +@@ -1093,6 +1136,12 @@ mptfc_setup_reset(struct work_struct *wo + ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED; + fc_remote_port_delete(ri->rport); /* won't sleep */ + ri->rport = NULL; ++ starget = ri->starget; ++ if (starget) { ++ vtarget = starget->hostdata; ++ if (vtarget) ++ vtarget->deleted = 1; ++ } + + pn = (u64)ri->pg0.WWPN.High << 32 | + (u64)ri->pg0.WWPN.Low; +@@ -1111,8 +1160,22 @@ mptfc_rescan_devices(struct work_struct + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fc_rescan_work); + int ii; ++ int rc; + u64 pn; + struct mptfc_rport_info *ri; ++ struct scsi_target *starget; ++ VirtTarget *vtarget; ++ ++ /* ++ * if cannot set defaults, something's really wrong, bail out ++ */ ++ ++ if ((rc = mptfc_SetFcPortPage1_defaults(ioc)) < 0) { ++ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT ++ "mptfc_rescan.%d: unable to set PP1 defaults, rc %d.\n", ++ ioc->name, ioc->sh->host_no, rc)); ++ return; ++ } + + /* start by tagging all ports as missing */ + list_for_each_entry(ri, &ioc->fc_rports, list) { +@@ -1140,6 +1203,12 @@ mptfc_rescan_devices(struct work_struct + MPT_RPORT_INFO_FLAGS_MISSING); + fc_remote_port_delete(ri->rport); /* won't sleep */ + ri->rport = NULL; ++ starget = ri->starget; ++ if (starget) { ++ vtarget = starget->hostdata; ++ if (vtarget) ++ vtarget->deleted = 1; ++ } + + pn = (u64)ri->pg0.WWPN.High << 32 | + (u64)ri->pg0.WWPN.Low; +@@ -1238,6 +1307,10 @@ mptfc_probe(struct pci_dev *pdev, const + sh->max_id = ioc->pfacts->MaxDevices; + sh->max_lun = max_lun; + ++ sh->this_id = ioc->pfacts[0].PortSCSIID; ++ ++ ioc->sdev_queue_depth = mpt_sdev_queue_depth; ++ + /* Required entry. + */ + sh->unique_id = ioc->id; +@@ -1251,17 +1324,15 @@ mptfc_probe(struct pci_dev *pdev, const + * A slightly different algorithm is required for + * 64bit SGEs. + */ +- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); +- if (sizeof(dma_addr_t) == sizeof(u64)) { ++ scale = ioc->req_sz/ioc->SGE_size; ++ if (ioc->sg_addr_size == sizeof(u64)) { + numSGE = (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 60) / (sizeof(dma_addr_t) + +- sizeof(u32)); ++ (ioc->req_sz - 60) / ioc->SGE_size; + } else { + numSGE = 1 + (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 64) / (sizeof(dma_addr_t) + +- sizeof(u32)); ++ (ioc->req_sz - 64) / ioc->SGE_size; + } + + if (numSGE < sh->sg_tablesize) { +@@ -1290,30 +1361,6 @@ mptfc_probe(struct pci_dev *pdev, const + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", + ioc->name, ioc->ScsiLookup)); + +- /* Clear the TM flags +- */ +- hd->tmPending = 0; +- hd->tmState = TM_STATE_NONE; +- hd->resetPending = 0; +- hd->abortSCpnt = NULL; +- +- /* Clear the pointer used to store +- * single-threaded commands, i.e., those +- * issued during a bus scan, dv and +- * configuration pages. +- */ +- hd->cmdPtr = NULL; +- +- /* Initialize this SCSI Hosts' timers +- * To use, set the timer expires field +- * and add_timer +- */ +- init_timer(&hd->timer); +- hd->timer.data = (unsigned long) hd; +- hd->timer.function = mptscsih_timer_expired; +- +- init_waitqueue_head(&hd->scandv_waitq); +- hd->scandv_wait_done = 0; + hd->last_queue_full = 0; + + sh->transportt = mptfc_transport_template; +@@ -1326,8 +1373,8 @@ mptfc_probe(struct pci_dev *pdev, const + + /* initialize workqueue */ + +- snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name), +- "mptfc_wq_%d", sh->host_no); ++ snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name), "mptfc_wq_%d", ++ sh->host_no); + ioc->fc_rescan_work_q = + create_singlethread_workqueue(ioc->fc_rescan_work_q_name); + if (!ioc->fc_rescan_work_q) +@@ -1340,7 +1387,6 @@ mptfc_probe(struct pci_dev *pdev, const + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { + (void) mptfc_GetFcPortPage0(ioc, ii); + } +- mptfc_SetFcPortPage1_defaults(ioc); + + /* + * scan for rports - +@@ -1378,9 +1424,6 @@ mptfc_event_process(MPT_ADAPTER *ioc, Ev + unsigned long flags; + int rc=1; + +- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", +- ioc->name, event)); +- + if (ioc->sh == NULL || + ((hd = shost_priv(ioc->sh)) == NULL)) + return 1; +@@ -1416,45 +1459,45 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int re + unsigned long flags; + + rc = mptscsih_ioc_reset(ioc,reset_phase); +- if (rc == 0) ++ if ((ioc->bus_type != FC) || (!rc)) + return rc; + +- +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- ": IOC %s_reset routed to FC host driver!\n",ioc->name, +- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( +- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); +- +- if (reset_phase == MPT_IOC_SETUP_RESET) { ++ switch(reset_phase) { ++ case MPT_IOC_SETUP_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + if (ioc->fc_rescan_work_q) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_setup_reset_work); + } + spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); +- } +- +- else if (reset_phase == MPT_IOC_PRE_RESET) { +- } +- +- else { /* MPT_IOC_POST_RESET */ +- mptfc_SetFcPortPage1_defaults(ioc); ++ break; ++ case MPT_IOC_PRE_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ break; ++ case MPT_IOC_POST_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + if (ioc->fc_rescan_work_q) { + queue_work(ioc->fc_rescan_work_q, + &ioc->fc_rescan_work); + } + spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); ++ break; ++ default: ++ break; + } + return 1; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int __init + mptfc_init(void) + { +@@ -1486,12 +1529,11 @@ mptfc_init(void) + return error; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptfc_remove - Remove fc infrastructure for devices + * @pdev: Pointer to pci_dev structure + * +- */ ++ **/ + static void __devexit + mptfc_remove(struct pci_dev *pdev) + { +@@ -1501,6 +1543,8 @@ mptfc_remove(struct pci_dev *pdev) + unsigned long flags; + int ii; + ++ printk("%s -pdev=%p\n", __FUNCTION__, pdev); ++ + /* destroy workqueue */ + if ((work_q=ioc->fc_rescan_work_q)) { + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); +@@ -1543,7 +1587,6 @@ mptfc_exit(void) + + mpt_reset_deregister(mptfcDoneCtx); + mpt_event_deregister(mptfcDoneCtx); +- + mpt_deregister(mptfcInternalCtx); + mpt_deregister(mptfcTaskCtx); + mpt_deregister(mptfcDoneCtx); +--- a/drivers/message/fusion/mptlan.c ++++ b/drivers/message/fusion/mptlan.c +@@ -6,7 +6,6 @@ + * + * Copyright (c) 2000-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) +- * + */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* +@@ -165,6 +164,11 @@ DEFINE_RWLOCK(bad_naa_lock); + #endif + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/* ++ * Fusion MPT LAN external data ++ */ ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * lan_reply - Handle all data sent from the hardware. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -190,8 +194,7 @@ lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_H + u32 tmsg = CAST_PTR_TO_U32(reply); + + dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n", +- IOC_AND_NETDEV_NAMES_s_s(dev), +- tmsg)); ++ IOC_AND_NETDEV_NAMES_s_s(dev), tmsg)); + + switch (GET_LAN_FORM(tmsg)) { + +@@ -440,6 +443,7 @@ mpt_lan_open(struct net_device *dev) + dlprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); + + mpt_lan_post_receive_buckets(priv); ++ + printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + +@@ -610,7 +614,7 @@ mpt_lan_send_turbo(struct net_device *de + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), +- __func__, sent)); ++ __FUNCTION__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, +@@ -676,7 +680,7 @@ mpt_lan_send_reply(struct net_device *de + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), +- __func__, sent)); ++ __FUNCTION__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, +@@ -715,7 +719,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + u16 cur_naa = 0x1000; + + dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", +- __func__, skb)); ++ __FUNCTION__, skb)); + + spin_lock_irqsave(&priv->txfidx_lock, flags); + if (priv->mpt_txfidx_tail < 0) { +@@ -723,7 +727,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: no tx context available: %u\n", +- __func__, priv->mpt_txfidx_tail); ++ __FUNCTION__, priv->mpt_txfidx_tail); + return 1; + } + +@@ -733,7 +737,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: Unable to alloc request frame\n", +- __func__); ++ __FUNCTION__); + return 1; + } + +@@ -780,6 +784,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + // ctx, skb, skb->data)); + + mac = skb_mac_header(skb); ++ + #ifdef QLOGIC_NAA_WORKAROUND + { + struct NAA_Hosed *nh; +@@ -805,6 +810,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + } + #endif + ++ + pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | + (mac[0] << 8) | + (mac[1] << 0)); +@@ -828,7 +834,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) | + skb->len); + pSimple->Address.Low = cpu_to_le32((u32) dma); +- if (sizeof(dma_addr_t) > sizeof(u32)) ++ if (mpt_dev->sg_addr_size > sizeof(u32)) + pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32)); + else + pSimple->Address.High = 0; +@@ -1117,7 +1123,6 @@ mpt_lan_receive_post_reply(struct net_de + PCI_DMA_FROMDEVICE); + + skb_copy_from_linear_data(old_skb, skb_put(skb, len), len); +- + pci_dma_sync_single_for_device(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, +@@ -1208,7 +1213,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", + IOC_AND_NETDEV_NAMES_s_s(dev), +- __func__, buckets, curr)); ++ __FUNCTION__, buckets, curr)); + + max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / + (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); +@@ -1217,9 +1222,9 @@ mpt_lan_post_receive_buckets(struct mpt_ + mf = mpt_get_msg_frame(LanCtx, mpt_dev); + if (mf == NULL) { + printk (KERN_ERR "%s: Unable to alloc request frame\n", +- __func__); ++ __FUNCTION__); + dioprintk((KERN_ERR "%s: %u buckets remaining\n", +- __func__, buckets)); ++ __FUNCTION__, buckets)); + goto out; + } + pRecvReq = (LANReceivePostRequest_t *) mf; +@@ -1244,7 +1249,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + spin_lock_irqsave(&priv->rxfidx_lock, flags); + if (priv->mpt_rxfidx_tail < 0) { + printk (KERN_ERR "%s: Can't alloc context\n", +- __func__); ++ __FUNCTION__); + spin_unlock_irqrestore(&priv->rxfidx_lock, + flags); + break; +@@ -1267,7 +1272,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + if (skb == NULL) { + printk (KERN_WARNING + MYNAM "/%s: Can't alloc skb\n", +- __func__); ++ __FUNCTION__); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + break; +@@ -1295,7 +1300,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len); + pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma); +- if (sizeof(dma_addr_t) > sizeof(u32)) ++ if (mpt_dev->sg_addr_size > sizeof(u32)) + pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32)); + else + pSimple->Address.High = 0; +@@ -1305,7 +1310,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + + if (pSimple == NULL) { + /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", +-/**/ __func__); ++/**/ __FUNCTION__); + mpt_free_msg_frame(mpt_dev, mf); + goto out; + } +@@ -1329,9 +1334,9 @@ mpt_lan_post_receive_buckets(struct mpt_ + + out: + dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", +- __func__, buckets, atomic_read(&priv->buckets_out))); ++ __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); + dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", +- __func__, priv->total_posted, priv->total_received)); ++ __FUNCTION__, priv->total_posted, priv->total_received)); + + clear_bit(0, &priv->post_buckets_active); + } +@@ -1340,18 +1345,17 @@ static void + mpt_lan_post_receive_buckets_work(struct work_struct *work) + { + mpt_lan_post_receive_buckets(container_of(work, struct mpt_lan_priv, +- post_buckets_task.work)); ++ post_buckets_task.work)); + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static struct net_device * + mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) + { +- struct net_device *dev; +- struct mpt_lan_priv *priv; ++ struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv)); ++ struct mpt_lan_priv *priv = NULL; + u8 HWaddr[FC_ALEN], *a; + +- dev = alloc_fcdev(sizeof(struct mpt_lan_priv)); + if (!dev) + return NULL; + +@@ -1363,8 +1367,9 @@ mpt_register_lan_device (MPT_ADAPTER *mp + priv->mpt_dev = mpt_dev; + priv->pnum = pnum; + ++ memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task)); + INIT_DELAYED_WORK(&priv->post_buckets_task, +- mpt_lan_post_receive_buckets_work); ++ mpt_lan_post_receive_buckets_work); + priv->post_buckets_active = 0; + + dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", +@@ -1387,6 +1392,8 @@ mpt_register_lan_device (MPT_ADAPTER *mp + spin_lock_init(&priv->txfidx_lock); + spin_lock_init(&priv->rxfidx_lock); + ++ memset(&priv->stats, 0, sizeof(priv->stats)); ++ + /* Grab pre-fetched LANPage1 stuff. :-) */ + a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow; + +@@ -1421,6 +1428,7 @@ mpt_register_lan_device (MPT_ADAPTER *mp + dlprintk((KERN_INFO MYNAM ": Finished registering dev " + "and setting initial values\n")); + ++ + if (register_netdev(dev) != 0) { + free_netdev(dev); + dev = NULL; +--- a/drivers/message/fusion/mptlan.h ++++ b/drivers/message/fusion/mptlan.h +@@ -6,7 +6,6 @@ + * + * Copyright (c) 2000-2008 LSI Corporation + * (mailto:DL-MPTFusionLinux@lsi.com) +- * + */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /* +@@ -55,6 +54,7 @@ + #include + #endif + ++#include + #include + #include + // #include +@@ -73,6 +73,7 @@ + + #include + #include ++#include + + /* Override mptbase.h by pre-defining these! */ + #define MODULEAUTHOR "LSI Corporation" +--- a/drivers/message/fusion/mptsas.c ++++ b/drivers/message/fusion/mptsas.c +@@ -47,9 +47,11 @@ + #include + #include + #include +-#include ++#include + #include ++#include + #include /* for mdelay */ ++#include + + #include + #include +@@ -62,7 +64,6 @@ + #include "mptscsih.h" + #include "mptsas.h" + +- + #define my_NAME "Fusion MPT SAS Host driver" + #define my_VERSION MPT_LINUX_VERSION_COMMON + #define MYNAM "mptsas" +@@ -72,6 +73,8 @@ + */ + #define MPTSAS_RAID_CHANNEL 1 + ++#define SAS_CONFIG_PAGE_TIMEOUT 30 ++ + MODULE_AUTHOR(MODULEAUTHOR); + MODULE_DESCRIPTION(my_NAME); + MODULE_LICENSE("GPL"); +@@ -83,6 +86,25 @@ MODULE_PARM_DESC(mpt_pt_clear, + " Clear persistency table: enable=1 " + "(default=MPTSCSIH_PT_CLEAR=0)"); + ++static int mpt_cmd_retry_count = 144; ++module_param(mpt_cmd_retry_count, int, 0); ++MODULE_PARM_DESC(mpt_cmd_retry_count, ++ " Device discovery TUR command retry count: default=144"); ++ ++static int mpt_disable_hotplug_remove = 0; ++module_param(mpt_disable_hotplug_remove, int, 0); ++MODULE_PARM_DESC(mpt_disable_hotplug_remove, ++ " Disable hotpug remove events: default=0"); ++ ++static int mpt_sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; ++static int mptsas_set_sdev_queue_depth(const char *val, ++ struct kernel_param *kp); ++module_param_call(mpt_sdev_queue_depth, mptsas_set_sdev_queue_depth, ++ param_get_int, &mpt_sdev_queue_depth, 0600); ++MODULE_PARM_DESC(mpt_sdev_queue_depth, ++ " Max Device Queue Depth (default=" ++ __MODULE_STRING(MPT_SCSI_CMD_PER_DEV_HIGH) ")"); ++ + /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ + #define MPTSAS_MAX_LUN (16895) + static int max_lun = MPTSAS_MAX_LUN; +@@ -93,8 +115,53 @@ static u8 mptsasDoneCtx = MPT_MAX_PROTOC + static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; + static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ + static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; ++static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; ++ ++static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); ++static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, ++ u64 sas_address); ++static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, ++ u32 form, u32 form_specific); ++static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, ++ u32 form, u32 form_specific); ++ ++static int mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info); ++static void mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info); ++static void mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info); ++static int mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, ++ u32 form, u32 form_specific); ++static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); ++static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); ++ ++static void mptsas_firmware_event_work(struct work_struct *work); ++ ++/** ++ * mptsas_set_sdev_queue_depth - global setting of the mpt_sdev_queue_depth ++ * found via /sys/module/mptsas/parameters/mpt_sdev_queue_depth ++ * @val: ++ * @kp: ++ * ++ * Returns ++ **/ ++static int ++mptsas_set_sdev_queue_depth(const char *val, struct kernel_param *kp) ++{ ++ int ret = param_set_int(val, kp); ++ MPT_ADAPTER *ioc; ++ struct scsi_device *sdev; + +-static void mptsas_hotplug_work(struct work_struct *work); ++ if (ret) ++ return ret; ++ ++ list_for_each_entry(ioc, &ioc_list, list) { ++ if (ioc->bus_type != SAS) ++ continue; ++ shost_for_each_device(sdev, ioc->sh) ++ mptscsih_change_queue_depth(sdev, mpt_sdev_queue_depth); ++ ioc->sdev_queue_depth = mpt_sdev_queue_depth; ++ } ++ return 0; ++} + + static void mptsas_print_phy_data(MPT_ADAPTER *ioc, + MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) +@@ -218,37 +285,183 @@ static void mptsas_print_expander_pg1(MP + le16_to_cpu(pg1->AttachedDevHandle))); + } + +-static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) ++/* inhibit sas firmware event handling */ ++static void ++mptsas_fw_event_off(MPT_ADAPTER *ioc) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioc->fw_event_lock, flags); ++ ioc->fw_events_off = 1; ++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); ++ ++} ++ ++/* enable sas firmware event handling */ ++static void ++mptsas_fw_event_on(MPT_ADAPTER *ioc) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioc->fw_event_lock, flags); ++ ioc->fw_events_off = 0; ++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); ++} ++ ++/* queue a sas firmware event */ ++static void ++mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, ++ unsigned long delay) ++{ ++ unsigned long flags; ++ ++#if defined(CPQ_CIM) ++ ioc->csmi_change_count++; ++#endif ++ ++ spin_lock_irqsave(&ioc->fw_event_lock, flags); ++ list_add_tail(&fw_event->list, &ioc->fw_event_list); ++ INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: add (fw_event=0x%p)\n", ++ ioc->name,__FUNCTION__, fw_event)); ++ queue_delayed_work(ioc->fw_event_q, &fw_event->work, ++ msecs_to_jiffies(delay)); ++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); ++} ++ ++/* requeue a sas firmware event */ ++static void ++mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, ++ unsigned long delay) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&ioc->fw_event_lock, flags); ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: reschedule task " ++ "(fw_event=0x%p)\n", ioc->name,__FUNCTION__, fw_event)); ++ fw_event->retries++; ++ queue_delayed_work(ioc->fw_event_q, &fw_event->work, ++ msecs_to_jiffies(delay)); ++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); ++} ++ ++/* free memory assoicated to a sas firmware event */ ++static void ++mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ioc->fw_event_lock, flags); ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: kfree (fw_event=0x%p)\n", ++ ioc->name,__FUNCTION__, fw_event)); ++ list_del(&fw_event->list); ++ kfree(fw_event); ++ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); ++} ++ ++/* walk the firmware event queue, and either stop or wait for outstanding events to complete */ ++static void ++mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) ++{ ++ struct fw_event_work *fw_event, *next; ++ struct mptsas_target_reset_event *target_reset_list, *n; ++ u8 flush_q; ++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh); ++ ++ /* flush the target_reset_list */ ++ if (!list_empty(&hd->target_reset_list)) { ++ list_for_each_entry_safe(target_reset_list, n, ++ &hd->target_reset_list, list) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: removing target reset for id=%d\n", ++ ioc->name, __FUNCTION__, ++ target_reset_list->sas_event_data.TargetID)); ++ list_del(&target_reset_list->list); ++ kfree(target_reset_list); ++ } ++ } ++ ++ if (list_empty(&ioc->fw_event_list) || ++ !ioc->fw_event_q || in_interrupt()) ++ return; ++ ++ flush_q = 0; ++ list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { ++ if (cancel_delayed_work(&fw_event->work)) ++ mptsas_free_fw_event(ioc, fw_event); ++ else ++ flush_q = 1; ++ } ++ if (flush_q) ++ flush_workqueue(ioc->fw_event_q); ++} ++ ++ ++/** ++ * phy_to_ioc - ++ * @phy: ++ * ++ * ++ **/ ++static inline MPT_ADAPTER * ++phy_to_ioc(struct sas_phy *phy) + { + struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); + return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; + } + +-static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) ++/** ++ * rphy_to_ioc - ++ * @rphy: ++ * ++ * ++ **/ ++static inline MPT_ADAPTER * ++rphy_to_ioc(struct sas_rphy *rphy) + { + struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); + return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; + } + ++/** ++ * mptsas_find_portinfo_by_sas_address - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @handle: ++ * ++ * This function should be called with the sas_topology_mutex already held ++ * ++ **/ + static struct mptsas_portinfo * +-mptsas_get_hba_portinfo(MPT_ADAPTER *ioc) ++mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) + { +- struct list_head *head = &ioc->sas_topology; +- struct mptsas_portinfo *pi = NULL; +- +- /* always the first entry on sas_topology list */ +- +- if (!list_empty(head)) +- pi = list_entry(head->next, struct mptsas_portinfo, list); ++ struct mptsas_portinfo *port_info, *rc=NULL; ++ int i; ++ ++ if (sas_address >= ioc->hba_port_sas_addr && ++ sas_address < (ioc->hba_port_sas_addr + ++ ioc->hba_port_num_phy)) ++ return ioc->hba_port_info; + +- return pi; ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_for_each_entry(port_info, &ioc->sas_topology, list) ++ for (i = 0; i < port_info->num_phys; i++) ++ if (port_info->phy_info[i].identify.sas_address == ++ sas_address) { ++ rc = port_info; ++ goto out; ++ } ++ out: ++ mutex_unlock(&ioc->sas_topology_mutex); ++ return rc; + } + +-/* +- * mptsas_find_portinfo_by_handle ++/** ++ * mptsas_find_portinfo_by_handle - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @handle: + * +- * This function should be called with the sas_topology_mutex already held +- */ ++ * This function should be called with the sas_topology_mutex already held ++ * ++ **/ + static struct mptsas_portinfo * + mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) + { +@@ -265,9 +478,12 @@ mptsas_find_portinfo_by_handle(MPT_ADAPT + return rc; + } + +-/* +- * Returns true if there is a scsi end device +- */ ++/** ++ * mptsas_is_end_device - ++ * @attached: ++ * ++ * Returns true if there is a scsi end device ++ **/ + static inline int + mptsas_is_end_device(struct mptsas_devinfo * attached) + { +@@ -285,7 +501,14 @@ mptsas_is_end_device(struct mptsas_devin + return 0; + } + +-/* no mutex */ ++/** ++ * mptsas_port_delete - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @port_details: ++ * ++ * (no mutex) ++ * ++ **/ + static void + mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) + { +@@ -300,7 +523,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, str + phy_info = port_info->phy_info; + + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " +- "bitmask=0x%016llX\n", ioc->name, __func__, port_details, ++ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, + port_details->num_phys, (unsigned long long) + port_details->phy_bitmask)); + +@@ -308,11 +531,17 @@ mptsas_port_delete(MPT_ADAPTER *ioc, str + if(phy_info->port_details != port_details) + continue; + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); ++ mptsas_set_rphy(ioc, phy_info, NULL); + phy_info->port_details = NULL; + } + kfree(port_details); + } + ++/** ++ * mptsas_get_rphy - ++ * @phy_info: ++ * ++ **/ + static inline struct sas_rphy * + mptsas_get_rphy(struct mptsas_phyinfo *phy_info) + { +@@ -322,13 +551,20 @@ mptsas_get_rphy(struct mptsas_phyinfo *p + return NULL; + } + ++/** ++ * mptsas_set_rphy - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phy_info: ++ * @rphy: ++ * ++ **/ + static inline void + mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) + { + if (phy_info->port_details) { + phy_info->port_details->rphy = rphy; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n", +- ioc->name, rphy)); ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "sas_rphy_add: rphy=%p\n", ioc->name, rphy)); + } + + if (rphy) { +@@ -339,6 +575,11 @@ mptsas_set_rphy(MPT_ADAPTER *ioc, struct + } + } + ++/** ++ * mptsas_get_port - ++ * @phy_info: ++ * ++ **/ + static inline struct sas_port * + mptsas_get_port(struct mptsas_phyinfo *phy_info) + { +@@ -348,6 +589,13 @@ mptsas_get_port(struct mptsas_phyinfo *p + return NULL; + } + ++/** ++ * mptsas_set_port - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phy_info: ++ * @port: ++ * ++ **/ + static inline void + mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port) + { +@@ -362,6 +610,11 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct + } + } + ++/** ++ * mptsas_get_starget - ++ * @phy_info: ++ * ++ **/ + static inline struct scsi_target * + mptsas_get_starget(struct mptsas_phyinfo *phy_info) + { +@@ -371,6 +624,12 @@ mptsas_get_starget(struct mptsas_phyinfo + return NULL; + } + ++/** ++ * mptsas_set_starget - ++ * @phy_info: ++ * @starget: ++ * ++ **/ + static inline void + mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * + starget) +@@ -379,714 +638,787 @@ starget) + phy_info->port_details->starget = starget; + } + +- +-/* +- * mptsas_setup_wide_ports ++/** ++ * mptsas_add_device_component - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: fw mapped id's ++ * @id: ++ * @sas_address: ++ * @device_info: + * +- * Updates for new and existing narrow/wide port configuration +- * in the sas_topology +- */ ++ **/ + static void +-mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) ++mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, ++ u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) + { +- struct mptsas_portinfo_details * port_details; +- struct mptsas_phyinfo *phy_info, *phy_info_cmp; +- u64 sas_address; +- int i, j; +- +- mutex_lock(&ioc->sas_topology_mutex); +- +- phy_info = port_info->phy_info; +- for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { +- if (phy_info->attached.handle) +- continue; +- port_details = phy_info->port_details; +- if (!port_details) +- continue; +- if (port_details->num_phys < 2) +- continue; +- /* +- * Removing a phy from a port, letting the last +- * phy be removed by firmware events. +- */ +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: [%p]: deleting phy = %d\n", +- ioc->name, __func__, port_details, i)); +- port_details->num_phys--; +- port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); +- memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); +- sas_port_delete_phy(port_details->port, phy_info->phy); +- phy_info->port_details = NULL; ++ struct sas_device_info *sas_info, *next; ++ struct scsi_device *sdev; ++ struct scsi_target *starget; ++ struct sas_rphy *rphy; ++ ++ /* ++ * Delete all matching devices out of the list ++ */ ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, ++ list) { ++ if (!sas_info->is_logical_volume && ++ (sas_info->sas_address == sas_address || ++ (sas_info->fw.channel == channel && ++ sas_info->fw.id == id))) { ++ list_del(&sas_info->list); ++ kfree(sas_info); ++ } + } + ++ if (!(sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL))) ++ goto out; ++ + /* +- * Populate and refresh the tree ++ * Set Firmware mapping + */ +- phy_info = port_info->phy_info; +- for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { +- sas_address = phy_info->attached.sas_address; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", +- ioc->name, i, (unsigned long long)sas_address)); +- if (!sas_address) +- continue; +- port_details = phy_info->port_details; +- /* +- * Forming a port +- */ +- if (!port_details) { +- port_details = kzalloc(sizeof(*port_details), +- GFP_KERNEL); +- if (!port_details) +- goto out; +- port_details->num_phys = 1; +- port_details->port_info = port_info; +- if (phy_info->phy_id < 64 ) +- port_details->phy_bitmask |= +- (1 << phy_info->phy_id); +- phy_info->sas_port_add_phy=1; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" +- "phy_id=%d sas_address=0x%018llX\n", +- ioc->name, i, (unsigned long long)sas_address)); +- phy_info->port_details = port_details; +- } ++ sas_info->fw.id = id; ++ sas_info->fw.channel = channel; + +- if (i == port_info->num_phys - 1) +- continue; +- phy_info_cmp = &port_info->phy_info[i + 1]; +- for (j = i + 1 ; j < port_info->num_phys ; j++, +- phy_info_cmp++) { +- if (!phy_info_cmp->attached.sas_address) +- continue; +- if (sas_address != phy_info_cmp->attached.sas_address) +- continue; +- if (phy_info_cmp->port_details == port_details ) +- continue; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "\t\tphy_id=%d sas_address=0x%018llX\n", +- ioc->name, j, (unsigned long long) +- phy_info_cmp->attached.sas_address)); +- if (phy_info_cmp->port_details) { +- port_details->rphy = +- mptsas_get_rphy(phy_info_cmp); +- port_details->port = +- mptsas_get_port(phy_info_cmp); +- port_details->starget = +- mptsas_get_starget(phy_info_cmp); +- port_details->num_phys = +- phy_info_cmp->port_details->num_phys; +- if (!phy_info_cmp->port_details->num_phys) +- kfree(phy_info_cmp->port_details); +- } else +- phy_info_cmp->sas_port_add_phy=1; +- /* +- * Adding a phy to a port +- */ +- phy_info_cmp->port_details = port_details; +- if (phy_info_cmp->phy_id < 64 ) +- port_details->phy_bitmask |= +- (1 << phy_info_cmp->phy_id); +- port_details->num_phys++; ++ sas_info->sas_address = sas_address; ++ sas_info->device_info = device_info; ++ sas_info->slot = slot; ++ sas_info->enclosure_logical_id = enclosure_logical_id; ++ INIT_LIST_HEAD(&sas_info->list); ++ list_add_tail(&sas_info->list, &ioc->sas_device_info_list); ++ ++ /* ++ * Set OS mapping ++ */ ++ shost_for_each_device(sdev, ioc->sh) { ++ starget = scsi_target(sdev); ++ rphy = dev_to_rphy(starget->dev.parent); ++ if (rphy->identify.sas_address == sas_address) { ++ sas_info->os.id = starget->id; ++ sas_info->os.channel = starget->channel; + } + } + + out: +- +- for (i = 0; i < port_info->num_phys; i++) { +- port_details = port_info->phy_info[i].port_details; +- if (!port_details) +- continue; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: [%p]: phy_id=%02d num_phys=%02d " +- "bitmask=0x%016llX\n", ioc->name, __func__, +- port_details, i, port_details->num_phys, +- (unsigned long long)port_details->phy_bitmask)); +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", +- ioc->name, port_details->port, port_details->rphy)); +- } +- dsaswideprintk(ioc, printk("\n")); +- mutex_unlock(&ioc->sas_topology_mutex); ++ up(&ioc->sas_device_info_mutex); ++ return; + } + + /** +- * csmisas_find_vtarget +- * +- * @ioc +- * @volume_id +- * @volume_bus ++ * mptsas_add_device_component_by_fw - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: fw mapped id's ++ * @id: + * + **/ +-static VirtTarget * +-mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) ++static void ++mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) + { +- struct scsi_device *sdev; +- VirtDevice *vdevice; +- VirtTarget *vtarget = NULL; ++ struct mptsas_devinfo sas_device; ++ struct mptsas_enclosure enclosure_info; ++ int rc; + +- shost_for_each_device(sdev, ioc->sh) { +- if ((vdevice = sdev->hostdata) == NULL) +- continue; +- if (vdevice->vtarget->id == id && +- vdevice->vtarget->channel == channel) +- vtarget = vdevice->vtarget; +- } +- return vtarget; ++ rc = mptsas_sas_device_pg0(ioc, &sas_device, ++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ (channel << 8) + id); ++ if (rc) ++ return; ++ ++ memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); ++ mptsas_sas_enclosure_pg0(ioc, &enclosure_info, ++ (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << ++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), ++ sas_device.handle_enclosure); ++ ++ mptsas_add_device_component(ioc, sas_device.channel, ++ sas_device.id, sas_device.sas_address, sas_device.device_info, ++ sas_device.slot, enclosure_info.enclosure_logical_id); + } + + /** +- * mptsas_target_reset +- * +- * Issues TARGET_RESET to end device using handshaking method +- * +- * @ioc +- * @channel +- * @id +- * +- * Returns (1) success +- * (0) failure +- * +- **/ +-static int +-mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) +-{ +- MPT_FRAME_HDR *mf; +- SCSITaskMgmt_t *pScsiTm; +- +- if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { +- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", +- ioc->name,__func__, __LINE__)); +- return 0; +- } +- +- /* Format the Request +- */ +- pScsiTm = (SCSITaskMgmt_t *) mf; +- memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); +- pScsiTm->TargetID = id; +- pScsiTm->Bus = channel; +- pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; +- pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; +- pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; +- +- DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); +- +- mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); +- +- return 1; +-} +- +-/** +- * mptsas_target_reset_queue +- * +- * Receive request for TARGET_RESET after recieving an firmware +- * event NOT_RESPONDING_EVENT, then put command in link list +- * and queue if task_queue already in use. +- * +- * @ioc +- * @sas_event_data ++ * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding ++ * each individual device to list ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: fw mapped id's ++ * @id: + * + **/ + static void +-mptsas_target_reset_queue(MPT_ADAPTER *ioc, +- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) ++mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, struct scsi_target *starget) + { +- MPT_SCSI_HOST *hd = shost_priv(ioc->sh); +- VirtTarget *vtarget = NULL; +- struct mptsas_target_reset_event *target_reset_list; +- u8 id, channel; ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t hdr; ++ dma_addr_t dma_handle; ++ pRaidVolumePage0_t buffer = NULL; ++ int i; ++ RaidPhysDiskPage0_t phys_disk; ++ struct sas_device_info *sas_info, *next; + +- id = sas_event_data->TargetID; +- channel = sas_event_data->Bus; ++ memset(&cfg, 0 , sizeof(CONFIGPARMS)); ++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); ++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; ++ /* assumption that all volumes on channel = 0 */ ++ cfg.pageAddr = starget->id; ++ cfg.cfghdr.hdr = &hdr; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + +- if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) +- return; ++ if (mpt_config(ioc, &cfg) != 0) ++ goto out; + +- vtarget->deleted = 1; /* block IO */ ++ if (!hdr.PageLength) ++ goto out; + +- target_reset_list = kzalloc(sizeof(*target_reset_list), +- GFP_ATOMIC); +- if (!target_reset_list) { +- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", +- ioc->name,__func__, __LINE__)); +- return; +- } ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, ++ &dma_handle); + +- memcpy(&target_reset_list->sas_event_data, sas_event_data, +- sizeof(*sas_event_data)); +- list_add_tail(&target_reset_list->list, &hd->target_reset_list); ++ if (!buffer) ++ goto out; + +- if (hd->resetPending) +- return; ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + +- if (mptsas_target_reset(ioc, channel, id)) { +- target_reset_list->target_reset_issued = 1; +- hd->resetPending = 1; +- } +-} ++ if (mpt_config(ioc, &cfg) != 0) ++ goto out; + +-/** +- * mptsas_dev_reset_complete +- * +- * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, +- * enable work queue to finish off removing device from upper layers. +- * then send next TARGET_RESET in the queue. +- * +- * @ioc +- * +- **/ +-static void +-mptsas_dev_reset_complete(MPT_ADAPTER *ioc) +-{ +- MPT_SCSI_HOST *hd = shost_priv(ioc->sh); +- struct list_head *head = &hd->target_reset_list; +- struct mptsas_target_reset_event *target_reset_list; +- struct mptsas_hotplug_event *ev; +- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; +- u8 id, channel; +- __le64 sas_address; ++ if (!buffer->NumPhysDisks) ++ goto out; + +- if (list_empty(head)) +- return; ++ /* ++ * Adding entry for hidden components ++ */ ++ for (i = 0; i < buffer->NumPhysDisks; i++) { + +- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); ++ if(mpt_raid_phys_disk_pg0(ioc, ++ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) ++ continue; + +- sas_event_data = &target_reset_list->sas_event_data; +- id = sas_event_data->TargetID; +- channel = sas_event_data->Bus; +- hd->resetPending = 0; ++ mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, ++ phys_disk.PhysDiskID); + +- /* +- * retry target reset +- */ +- if (!target_reset_list->target_reset_issued) { +- if (mptsas_target_reset(ioc, channel, id)) { +- target_reset_list->target_reset_issued = 1; +- hd->resetPending = 1; ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry(sas_info, &ioc->sas_device_info_list, ++ list) { ++ if (!sas_info->is_logical_volume && ++ (sas_info->fw.channel == phys_disk.PhysDiskBus && ++ sas_info->fw.id == phys_disk.PhysDiskID)) { ++ sas_info->is_hidden_raid_component = 1; ++ sas_info->volume_id = starget->id; ++ } + } +- return; ++ up(&ioc->sas_device_info_mutex); + } + + /* +- * enable work queue to remove device from upper layers ++ * Delete all matching devices out of the list + */ +- list_del(&target_reset_list->list); ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, ++ list) { ++ if (sas_info->is_logical_volume && sas_info->fw.id == ++ starget->id) { ++ list_del(&sas_info->list); ++ kfree(sas_info); ++ } ++ } + +- ev = kzalloc(sizeof(*ev), GFP_ATOMIC); +- if (!ev) { +- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", +- ioc->name,__func__, __LINE__)); +- return; ++ sas_info = kzalloc(sizeof(struct sas_device_info), GFP_KERNEL); ++ if (sas_info) { ++ sas_info->fw.id = starget->id; ++ sas_info->os.id = starget->id; ++ sas_info->os.channel = starget->channel; ++ sas_info->is_logical_volume = 1; ++ INIT_LIST_HEAD(&sas_info->list); ++ list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + } ++ up(&ioc->sas_device_info_mutex); + +- INIT_WORK(&ev->work, mptsas_hotplug_work); +- ev->ioc = ioc; +- ev->handle = le16_to_cpu(sas_event_data->DevHandle); +- ev->parent_handle = +- le16_to_cpu(sas_event_data->ParentDevHandle); +- ev->channel = channel; +- ev->id =id; +- ev->phy_id = sas_event_data->PhyNum; +- memcpy(&sas_address, &sas_event_data->SASAddress, +- sizeof(__le64)); +- ev->sas_address = le64_to_cpu(sas_address); +- ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); +- ev->event_type = MPTSAS_DEL_DEVICE; +- schedule_work(&ev->work); +- kfree(target_reset_list); ++ out: ++ if (buffer) ++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, ++ dma_handle); ++} + +- /* +- * issue target reset to next device in the queue +- */ ++/** ++ * mptsas_add_device_component_starget - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @starget: ++ * ++ **/ ++static void ++mptsas_add_device_component_starget(MPT_ADAPTER *ioc, struct scsi_target *starget) ++{ ++ VirtTarget *vtarget; ++ struct sas_rphy *rphy; ++ struct mptsas_phyinfo *phy_info = NULL; ++ struct mptsas_enclosure enclosure_info; + +- head = &hd->target_reset_list; +- if (list_empty(head)) ++ rphy = dev_to_rphy(starget->dev.parent); ++ vtarget = starget->hostdata; ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ rphy->identify.sas_address); ++ if (!phy_info) + return; + +- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, +- list); +- +- sas_event_data = &target_reset_list->sas_event_data; +- id = sas_event_data->TargetID; +- channel = sas_event_data->Bus; +- +- if (mptsas_target_reset(ioc, channel, id)) { +- target_reset_list->target_reset_issued = 1; +- hd->resetPending = 1; +- } ++ memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); ++ mptsas_sas_enclosure_pg0(ioc, &enclosure_info, ++ (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << ++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), ++ phy_info->attached.handle_enclosure); ++ ++ mptsas_add_device_component(ioc, phy_info->attached.channel, ++ phy_info->attached.id, phy_info->attached.sas_address, ++ phy_info->attached.device_info, ++ phy_info->attached.slot, enclosure_info.enclosure_logical_id); + } + + /** +- * mptsas_taskmgmt_complete +- * +- * @ioc +- * @mf +- * @mr ++ * mptsas_del_device_component_by_os - Once a device has been removed, we ++ * mark the entry in the list as being cached ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: os mapped id's ++ * @id: + * + **/ +-static int +-mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ++static void ++mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) + { +- mptsas_dev_reset_complete(ioc); +- return mptscsih_taskmgmt_complete(ioc, mf, mr); ++ struct sas_device_info *sas_info, *next; ++ ++ /* ++ * Set is_cached flag ++ */ ++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, ++ list) { ++ if (sas_info->os.channel == channel && sas_info->os.id == id) ++ sas_info->is_cached = 1; ++ } + } + + /** +- * mptscsih_ioc_reset +- * +- * @ioc +- * @reset_phase ++ * mptsas_del_device_components - Cleaning the list ++ * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +-static int +-mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) ++static void ++mptsas_del_device_components(MPT_ADAPTER *ioc) + { +- MPT_SCSI_HOST *hd; +- struct mptsas_target_reset_event *target_reset_list, *n; +- int rc; +- +- rc = mptscsih_ioc_reset(ioc, reset_phase); +- +- if (ioc->bus_type != SAS) +- goto out; +- +- if (reset_phase != MPT_IOC_POST_RESET) +- goto out; ++ struct sas_device_info *sas_info, *next; + +- if (!ioc->sh || !ioc->sh->hostdata) +- goto out; +- hd = shost_priv(ioc->sh); +- if (!hd->ioc) +- goto out; +- +- if (list_empty(&hd->target_reset_list)) +- goto out; +- +- /* flush the target_reset_list */ +- list_for_each_entry_safe(target_reset_list, n, +- &hd->target_reset_list, list) { +- list_del(&target_reset_list->list); +- kfree(target_reset_list); ++ down(&ioc->sas_device_info_mutex); ++ list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, ++ list) { ++ list_del(&sas_info->list); ++ kfree(sas_info); + } +- +- out: +- return rc; ++ up(&ioc->sas_device_info_mutex); + } + +-static int +-mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, +- u32 form, u32 form_specific) ++/** ++ * mptsas_setup_wide_ports - Updates for new and existing narrow/wide port ++ * configuration ++ * in the sas_topology ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @port_info: ++ * ++ */ ++static void ++mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) + { +- ConfigExtendedPageHeader_t hdr; +- CONFIGPARMS cfg; +- SasEnclosurePage0_t *buffer; +- dma_addr_t dma_handle; +- int error; +- __le64 le_identifier; +- +- memset(&hdr, 0, sizeof(hdr)); +- hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; +- hdr.PageNumber = 0; +- hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; +- hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; ++ struct mptsas_portinfo_details * port_details; ++ struct mptsas_phyinfo *phy_info, *phy_info_cmp; ++ u64 sas_address; ++ int i, j; + +- cfg.cfghdr.ehdr = &hdr; +- cfg.physAddr = -1; +- cfg.pageAddr = form + form_specific; +- cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; +- cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ mutex_lock(&ioc->sas_topology_mutex); + +- error = mpt_config(ioc, &cfg); +- if (error) +- goto out; +- if (!hdr.ExtPageLength) { +- error = -ENXIO; +- goto out; +- } ++ phy_info = port_info->phy_info; ++ for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { ++ if (phy_info->attached.handle) ++ continue; ++ port_details = phy_info->port_details; ++ if (!port_details) ++ continue; ++ if (port_details->num_phys < 2) ++ continue; + +- buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, +- &dma_handle); +- if (!buffer) { +- error = -ENOMEM; +- goto out; ++ /* ++ * Removing a phy from a port, letting the last ++ * phy be removed by firmware events. ++ */ ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: [%p]: deleting phy = %d\n", ++ ioc->name, __FUNCTION__, port_details, i)); ++ port_details->num_phys--; ++ port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); ++ memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); ++ devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, ++ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, ++ phy_info->phy_id, phy_info->phy)); ++ sas_port_delete_phy(port_details->port, phy_info->phy); ++ phy_info->port_details = NULL; + } + +- cfg.physAddr = dma_handle; +- cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; +- +- error = mpt_config(ioc, &cfg); +- if (error) +- goto out_free_consistent; +- +- /* save config data */ +- memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); +- enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); +- enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); +- enclosure->flags = le16_to_cpu(buffer->Flags); +- enclosure->num_slot = le16_to_cpu(buffer->NumSlots); +- enclosure->start_slot = le16_to_cpu(buffer->StartSlot); +- enclosure->start_id = buffer->StartTargetID; +- enclosure->start_channel = buffer->StartBus; +- enclosure->sep_id = buffer->SEPTargetID; +- enclosure->sep_channel = buffer->SEPBus; ++ /* ++ * Populate and refresh the tree ++ */ ++ phy_info = port_info->phy_info; ++ for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { ++ sas_address = phy_info->attached.sas_address; ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", ++ ioc->name, i, (unsigned long long)sas_address)); ++ if (!sas_address) ++ continue; ++ port_details = phy_info->port_details; ++ /* ++ * Forming a port ++ */ ++ if (!port_details) { ++ port_details = kzalloc(sizeof(struct mptsas_portinfo_details), ++ GFP_KERNEL); ++ if (!port_details) ++ goto out; ++ port_details->num_phys = 1; ++ port_details->port_info = port_info; ++ if (phy_info->phy_id < 64 ) ++ port_details->phy_bitmask |= ++ (1 << phy_info->phy_id); ++ phy_info->sas_port_add_phy=1; ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" ++ "phy_id=%d sas_address=0x%018llX\n", ioc->name, i, ++ (unsigned long long) sas_address)); ++ phy_info->port_details = port_details; ++ } ++ ++ if (i == port_info->num_phys - 1) ++ continue; ++ phy_info_cmp = &port_info->phy_info[i + 1]; ++ for (j = i + 1 ; j < port_info->num_phys ; j++, ++ phy_info_cmp++) { ++ if (!phy_info_cmp->attached.sas_address) ++ continue; ++ if (sas_address != phy_info_cmp->attached.sas_address) ++ continue; ++ if (phy_info_cmp->port_details == port_details ) ++ continue; ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "\t\tphy_id=%d sas_address=0x%018llX\n", ++ ioc->name, j, (unsigned long long) ++ phy_info_cmp->attached.sas_address)); ++ if (phy_info_cmp->port_details) { ++ port_details->rphy = ++ mptsas_get_rphy(phy_info_cmp); ++ port_details->port = ++ mptsas_get_port(phy_info_cmp); ++ port_details->starget = ++ mptsas_get_starget(phy_info_cmp); ++ port_details->num_phys = ++ phy_info_cmp->port_details->num_phys; ++ if (!phy_info_cmp->port_details->num_phys) ++ kfree(phy_info_cmp->port_details); ++ } else ++ phy_info_cmp->sas_port_add_phy=1; ++ /* ++ * Adding a phy to a port ++ */ ++ phy_info_cmp->port_details = port_details; ++ if (phy_info_cmp->phy_id < 64 ) ++ port_details->phy_bitmask |= ++ (1 << phy_info_cmp->phy_id); ++ port_details->num_phys++; ++ } ++ } + +- out_free_consistent: +- pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, +- buffer, dma_handle); + out: +- return error; ++ ++ for (i = 0; i < port_info->num_phys; i++) { ++ port_details = port_info->phy_info[i].port_details; ++ if (!port_details) ++ continue; ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: [%p]: phy_id=%02d num_phys=%02d " ++ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, ++ port_details, i, port_details->num_phys, ++ (unsigned long long)port_details->phy_bitmask)); ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", ++ ioc->name, port_details->port, port_details->rphy)); ++ } ++ dsaswideprintk(ioc, printk("\n")); ++ mutex_unlock(&ioc->sas_topology_mutex); + } + +-static int +-mptsas_slave_configure(struct scsi_device *sdev) ++/** ++ * mptsas_find_vtarget - obtain vtarget object for non-raid devices ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: ++ * @id: ++ * ++ **/ ++static VirtTarget * ++mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) ++{ ++ struct scsi_device *sdev; ++ VirtDevice *vdevice; ++ VirtTarget *vtarget = NULL; ++ ++ shost_for_each_device(sdev, ioc->sh) { ++ if ((vdevice = sdev->hostdata) == NULL || ++ (vdevice->vtarget == NULL)) ++ continue; ++ if ((vdevice->vtarget->tflags & ++ MPT_TARGET_FLAGS_RAID_COMPONENT || ++ vdevice->vtarget->raidVolume)) ++ continue; ++ if (vdevice->vtarget->id == id && ++ vdevice->vtarget->channel == channel) ++ vtarget = vdevice->vtarget; ++ } ++ return vtarget; ++} ++ ++static void ++mptsas_queue_device_delete(MPT_ADAPTER *ioc, ++ MpiEventDataSasDeviceStatusChange_t *sas_event_data) + { ++ struct fw_event_work *fw_event; ++ int sz; + +- if (sdev->channel == MPTSAS_RAID_CHANNEL) +- goto out; ++ sz = offsetof(struct fw_event_work, event_data) + ++ sizeof(MpiEventDataSasDeviceStatusChange_t); ++ fw_event = kzalloc(sz, GFP_ATOMIC); ++ if (!fw_event) { ++ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ++ ioc->name, __FUNCTION__, __LINE__); ++ return; ++ } ++ memcpy(fw_event->event_data, sas_event_data, ++ sizeof(MpiEventDataSasDeviceStatusChange_t)); ++ fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; ++ fw_event->ioc = ioc; ++ mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); ++} + +- sas_read_port_mode_page(sdev); ++static void ++mptsas_queue_rescan(MPT_ADAPTER *ioc) ++{ ++ struct fw_event_work *fw_event; ++ int sz; + +- out: +- return mptscsih_slave_configure(sdev); ++ sz = offsetof(struct fw_event_work, event_data); ++ fw_event = kzalloc(sz, GFP_ATOMIC); ++ if (!fw_event) { ++ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ++ ioc->name, __FUNCTION__, __LINE__); ++ return; ++ } ++ fw_event->event = -1; ++ fw_event->ioc = ioc; ++ mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); + } + ++ ++/** ++ * mptsas_target_reset - Issues TARGET_RESET to end device using ++ * handshaking method ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: ++ * @id: ++ * ++ * Returns (1) success ++ * (0) failure ++ * ++ **/ + static int +-mptsas_target_alloc(struct scsi_target *starget) ++mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) + { +- struct Scsi_Host *host = dev_to_shost(&starget->dev); +- MPT_SCSI_HOST *hd = shost_priv(host); +- VirtTarget *vtarget; +- u8 id, channel; +- struct sas_rphy *rphy; +- struct mptsas_portinfo *p; +- int i; +- MPT_ADAPTER *ioc = hd->ioc; ++ MPT_FRAME_HDR *mf; ++ SCSITaskMgmt_t *pScsiTm; + +- vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); +- if (!vtarget) +- return -ENOMEM; ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) ++ return 0; + +- vtarget->starget = starget; +- vtarget->ioc_id = ioc->id; +- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; +- id = starget->id; +- channel = 0; ++ if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) { ++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", ++ ioc->name,__FUNCTION__, __LINE__)); ++ goto out_fail; ++ } + +- /* +- * RAID volumes placed beyond the last expected port. ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", ++ ioc->name, mf)); ++ ++ /* Format the Request + */ +- if (starget->channel == MPTSAS_RAID_CHANNEL) { +- for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) +- if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) +- channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; +- goto out; +- } ++ pScsiTm = (SCSITaskMgmt_t *) mf; ++ memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); ++ pScsiTm->TargetID = id; ++ pScsiTm->Bus = channel; ++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; ++ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; ++ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; + +- rphy = dev_to_rphy(starget->dev.parent); +- mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry(p, &ioc->sas_topology, list) { +- for (i = 0; i < p->num_phys; i++) { +- if (p->phy_info[i].attached.sas_address != +- rphy->identify.sas_address) +- continue; +- id = p->phy_info[i].attached.id; +- channel = p->phy_info[i].attached.channel; +- mptsas_set_starget(&p->phy_info[i], starget); ++ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); + +- /* +- * Exposing hidden raid components +- */ +- if (mptscsih_is_phys_disk(ioc, channel, id)) { +- id = mptscsih_raid_id_to_num(ioc, +- channel, id); +- vtarget->tflags |= +- MPT_TARGET_FLAGS_RAID_COMPONENT; +- p->phy_info[i].attached.phys_disk_num = id; +- } +- mutex_unlock(&ioc->sas_topology_mutex); +- goto out; +- } +- } +- mutex_unlock(&ioc->sas_topology_mutex); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", ++ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); + +- kfree(vtarget); +- return -ENXIO; ++ mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); + +- out: +- vtarget->id = id; +- vtarget->channel = channel; +- starget->hostdata = vtarget; ++ return 1; ++ ++ out_fail: ++ ++ mpt_clear_taskmgmt_in_progress_flag(ioc); + return 0; + } +- ++/** ++ * mptsas_target_reset_queue - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @sas_event_data: ++ * ++ * Receive request for TARGET_RESET after ++ * recieving an firmware event NOT_RESPONDING_EVENT, then put command in ++ * link list and queue if task_queue already in use. ++ **/ + static void +-mptsas_target_destroy(struct scsi_target *starget) ++mptsas_target_reset_queue(MPT_ADAPTER *ioc, ++ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) + { +- struct Scsi_Host *host = dev_to_shost(&starget->dev); +- MPT_SCSI_HOST *hd = shost_priv(host); +- struct sas_rphy *rphy; +- struct mptsas_portinfo *p; +- int i; +- MPT_ADAPTER *ioc = hd->ioc; ++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh); ++ VirtTarget *vtarget = NULL; ++ struct mptsas_target_reset_event *target_reset_list; ++ u8 id, channel; + +- if (!starget->hostdata) +- return; ++ id = sas_event_data->TargetID; ++ channel = sas_event_data->Bus; + +- if (starget->channel == MPTSAS_RAID_CHANNEL) +- goto out; ++ if ((vtarget = mptsas_find_vtarget(ioc, channel, id))) { ++ if (!ioc->disable_hotplug_remove) ++ vtarget->deleted = 1; /* block IO */ ++ } + +- rphy = dev_to_rphy(starget->dev.parent); +- list_for_each_entry(p, &ioc->sas_topology, list) { +- for (i = 0; i < p->num_phys; i++) { +- if (p->phy_info[i].attached.sas_address != +- rphy->identify.sas_address) +- continue; +- mptsas_set_starget(&p->phy_info[i], NULL); +- goto out; +- } ++ target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), ++ GFP_ATOMIC); ++ if (!target_reset_list) { ++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", ++ ioc->name,__FUNCTION__, __LINE__)); ++ return; + } + +- out: +- kfree(starget->hostdata); +- starget->hostdata = NULL; +-} ++ memcpy(&target_reset_list->sas_event_data, sas_event_data, ++ sizeof(*sas_event_data)); ++ list_add_tail(&target_reset_list->list, &hd->target_reset_list); ++ ++ target_reset_list->time_count = jiffies; + ++ if (mptsas_target_reset(ioc, channel, id)) ++ target_reset_list->target_reset_issued = 1; ++} + ++/** ++ * mptsas_taskmgmt_complete - Completion for TARGET_RESET after ++ * NOT_RESPONDING_EVENT, enable work queue to finish off removing device ++ * from upper layers. then send next TARGET_RESET in the queue. ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ **/ + static int +-mptsas_slave_alloc(struct scsi_device *sdev) ++mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) + { +- struct Scsi_Host *host = sdev->host; +- MPT_SCSI_HOST *hd = shost_priv(host); +- struct sas_rphy *rphy; +- struct mptsas_portinfo *p; +- VirtDevice *vdevice; +- struct scsi_target *starget; +- int i; +- MPT_ADAPTER *ioc = hd->ioc; ++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh); ++ struct list_head *head = &hd->target_reset_list; ++ struct mptsas_target_reset_event *target_reset_list; ++ u8 id, channel; ++ SCSITaskMgmtReply_t *pScsiTmReply; + +- vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); +- if (!vdevice) { +- printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", +- ioc->name, sizeof(VirtDevice)); +- return -ENOMEM; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " ++ "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); ++ ++ pScsiTmReply = (SCSITaskMgmtReply_t *)mr; ++ if (pScsiTmReply) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" ++ "\ttask_type = 0x%02X, iocstatus = 0x%04X " ++ "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " ++ "term_cmnds = %d\n", ioc->name, ++ pScsiTmReply->Bus, pScsiTmReply->TargetID, ++ pScsiTmReply->TaskType, ++ le16_to_cpu(pScsiTmReply->IOCStatus), ++ le32_to_cpu(pScsiTmReply->IOCLogInfo), ++ pScsiTmReply->ResponseCode, ++ le32_to_cpu(pScsiTmReply->TerminationCount))); ++ ++ if (pScsiTmReply->ResponseCode) ++ mptscsih_taskmgmt_response_code(ioc, ++ pScsiTmReply->ResponseCode); ++ } ++ ++ if (pScsiTmReply && (pScsiTmReply->TaskType == ++ MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == ++ MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) { ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; ++ memcpy(ioc->taskmgmt_cmds.reply, mr, ++ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->taskmgmt_cmds.done); ++ return 1; ++ } ++ return 0; + } +- starget = scsi_target(sdev); +- vdevice->vtarget = starget->hostdata; + +- if (sdev->channel == MPTSAS_RAID_CHANNEL) +- goto out; ++ mpt_clear_taskmgmt_in_progress_flag(ioc); + +- rphy = dev_to_rphy(sdev->sdev_target->dev.parent); +- mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry(p, &ioc->sas_topology, list) { +- for (i = 0; i < p->num_phys; i++) { +- if (p->phy_info[i].attached.sas_address != +- rphy->identify.sas_address) +- continue; +- vdevice->lun = sdev->lun; +- /* +- * Exposing hidden raid components +- */ +- if (mptscsih_is_phys_disk(ioc, +- p->phy_info[i].attached.channel, +- p->phy_info[i].attached.id)) +- sdev->no_uld_attach = 1; +- mutex_unlock(&ioc->sas_topology_mutex); +- goto out; +- } ++ if (list_empty(head)) ++ return 1; ++ ++ target_reset_list = list_entry(head->next, ++ struct mptsas_target_reset_event, list); ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt: completed (%d seconds)\n", ++ ioc->name, jiffies_to_msecs(jiffies - ++ target_reset_list->time_count)/1000)); ++ ++ id = pScsiTmReply->TargetID; ++ channel = pScsiTmReply->Bus; ++ target_reset_list->time_count = jiffies; ++ ++ /* ++ * retry target reset ++ */ ++ if (!target_reset_list->target_reset_issued) { ++ if (mptsas_target_reset(ioc, channel, id)) ++ target_reset_list->target_reset_issued = 1; ++ return 1; + } +- mutex_unlock(&ioc->sas_topology_mutex); + +- kfree(vdevice); +- return -ENXIO; ++ /* ++ * enable work queue to remove device from upper layers ++ */ ++ list_del(&target_reset_list->list); ++ if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) ++ mptsas_queue_device_delete(ioc, &target_reset_list->sas_event_data); + +- out: +- vdevice->vtarget->num_luns++; +- sdev->hostdata = vdevice; +- return 0; ++ ++ /* ++ * issue target reset to next device in the queue ++ */ ++ ++ head = &hd->target_reset_list; ++ if (list_empty(head)) ++ return 1; ++ ++ target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, ++ list); ++ ++ id = target_reset_list->sas_event_data.TargetID; ++ channel = target_reset_list->sas_event_data.Bus; ++ target_reset_list->time_count = jiffies; ++ ++ if (mptsas_target_reset(ioc, channel, id)) ++ target_reset_list->target_reset_issued = 1; ++ ++ return 1; + } + ++/** ++ * mptsas_ioc_reset - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @reset_phase: ++ * ++ **/ + static int +-mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) ++mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) + { +- VirtDevice *vdevice = SCpnt->device->hostdata; +- +- if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { +- SCpnt->result = DID_NO_CONNECT << 16; +- done(SCpnt); +- return 0; +- } ++ MPT_SCSI_HOST *hd; ++ int rc; + +-// scsi_print_command(SCpnt); ++ rc = mptscsih_ioc_reset(ioc, reset_phase); ++ if ((ioc->bus_type != SAS) || (!rc)) ++ return rc; + +- return mptscsih_qcmd(SCpnt,done); +-} ++ hd = shost_priv(ioc->sh); ++ if (!hd->ioc) ++ goto out; + ++ switch(reset_phase) { ++ case MPT_IOC_SETUP_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ mptsas_fw_event_off(ioc); ++ break; ++ case MPT_IOC_PRE_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ break; ++ case MPT_IOC_POST_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ complete(&ioc->sas_mgmt.done); ++ } ++ mptsas_cleanup_fw_event_q(ioc); ++ mptsas_queue_rescan(ioc); ++ mptsas_fw_event_on(ioc); ++ break; ++ default: ++ break; ++ } + +-static struct scsi_host_template mptsas_driver_template = { +- .module = THIS_MODULE, +- .proc_name = "mptsas", +- .proc_info = mptscsih_proc_info, +- .name = "MPT SPI Host", +- .info = mptscsih_info, +- .queuecommand = mptsas_qcmd, +- .target_alloc = mptsas_target_alloc, +- .slave_alloc = mptsas_slave_alloc, +- .slave_configure = mptsas_slave_configure, +- .target_destroy = mptsas_target_destroy, +- .slave_destroy = mptscsih_slave_destroy, +- .change_queue_depth = mptscsih_change_queue_depth, +- .eh_abort_handler = mptscsih_abort, +- .eh_device_reset_handler = mptscsih_dev_reset, +- .eh_bus_reset_handler = mptscsih_bus_reset, +- .eh_host_reset_handler = mptscsih_host_reset, +- .bios_param = mptscsih_bios_param, +- .can_queue = MPT_FC_CAN_QUEUE, +- .this_id = -1, +- .sg_tablesize = MPT_SCSI_SG_DEPTH, +- .max_sectors = 8192, +- .cmd_per_lun = 7, +- .use_clustering = ENABLE_CLUSTERING, +- .shost_attrs = mptscsih_host_attrs, +-}; ++ out: ++ return rc; ++} + +-static int mptsas_get_linkerrors(struct sas_phy *phy) ++/** ++ * mptsas_sas_enclosure_pg0 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @enclosure: ++ * @form: ++ * @form_specific: ++ * ++ **/ ++static int ++mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, ++ u32 form, u32 form_specific) + { +- MPT_ADAPTER *ioc = phy_to_ioc(phy); + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; +- SasPhyPage1_t *buffer; ++ SasEnclosurePage0_t *buffer; + dma_addr_t dma_handle; + int error; ++ __le64 le_identifier; + +- /* FIXME: only have link errors on local phys */ +- if (!scsi_is_sas_phy_local(phy)) +- return -EINVAL; +- +- hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; +- hdr.ExtPageLength = 0; +- hdr.PageNumber = 1 /* page number 1*/; +- hdr.Reserved1 = 0; +- hdr.Reserved2 = 0; ++ memset(&hdr, 0, sizeof(hdr)); ++ hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; ++ hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; +- hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; +- cfg.pageAddr = phy->identify.phy_identifier; ++ cfg.pageAddr = form + form_specific; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; +- cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + + error = mpt_config(ioc, &cfg); + if (error) +- return error; +- if (!hdr.ExtPageLength) +- return -ENXIO; ++ goto out; ++ if (!hdr.ExtPageLength) { ++ error = -ENXIO; ++ goto out; ++ } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, +- &dma_handle); +- if (!buffer) +- return -ENOMEM; ++ &dma_handle); ++ if (!buffer) { ++ error = -ENOMEM; ++ goto out; ++ } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; +@@ -1095,289 +1427,852 @@ static int mptsas_get_linkerrors(struct + if (error) + goto out_free_consistent; + +- mptsas_print_phy_pg1(ioc, buffer); +- +- phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); +- phy->running_disparity_error_count = +- le32_to_cpu(buffer->RunningDisparityErrorCount); +- phy->loss_of_dword_sync_count = +- le32_to_cpu(buffer->LossDwordSynchCount); +- phy->phy_reset_problem_count = +- le32_to_cpu(buffer->PhyResetProblemCount); ++ /* save config data */ ++ memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); ++ enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); ++ enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); ++ enclosure->flags = le16_to_cpu(buffer->Flags); ++ enclosure->num_slot = le16_to_cpu(buffer->NumSlots); ++ enclosure->start_slot = le16_to_cpu(buffer->StartSlot); ++ enclosure->start_id = buffer->StartTargetID; ++ enclosure->start_channel = buffer->StartBus; ++ enclosure->sep_id = buffer->SEPTargetID; ++ enclosure->sep_channel = buffer->SEPBus; + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); ++ out: + return error; + } + +-static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, +- MPT_FRAME_HDR *reply) ++/** ++ * mptsas_get_lun_number - returns the first entry in report_luns table ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: ++ * @id: ++ * @lun: ++ * ++ */ ++static int ++mptsas_get_lun_number(MPT_ADAPTER *ioc, u8 channel, u8 id, int *lun) + { +- ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; +- if (reply != NULL) { +- ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; +- memcpy(ioc->sas_mgmt.reply, reply, +- min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); +- } +- complete(&ioc->sas_mgmt.done); +- return 1; +-} ++ INTERNAL_CMD *iocmd; ++ struct scsi_lun *lun_data; ++ dma_addr_t lun_data_dma; ++ u32 lun_data_len; ++ u8 *data; ++ MPT_SCSI_HOST *hd; ++ int rc; ++ u32 length, num_luns; + +-static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) +-{ +- MPT_ADAPTER *ioc = phy_to_ioc(phy); +- SasIoUnitControlRequest_t *req; +- SasIoUnitControlReply_t *reply; +- MPT_FRAME_HDR *mf; +- MPIHeader_t *hdr; +- unsigned long timeleft; +- int error = -ERESTARTSYS; ++ iocmd = NULL; ++ hd = shost_priv(ioc->sh); ++ lun_data_len = (255 * sizeof(struct scsi_lun)); ++ lun_data = pci_alloc_consistent(ioc->pcidev, lun_data_len, ++ &lun_data_dma); ++ if (!lun_data) { ++ printk(MYIOC_s_ERR_FMT "%s: pci_alloc_consistent(%d) FAILED!\n", ++ ioc->name, __FUNCTION__, lun_data_len); ++ rc = -ENOMEM; ++ goto out; ++ } + +- /* FIXME: fusion doesn't allow non-local phy reset */ +- if (!scsi_is_sas_phy_local(phy)) +- return -EINVAL; ++ iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); ++ if (!iocmd) { ++ printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", ++ ioc->name, __FUNCTION__, sizeof(INTERNAL_CMD)); ++ rc = -ENOMEM; ++ goto out; ++ } + +- /* not implemented for expanders */ +- if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) +- return -ENXIO; ++ /* ++ * Report Luns ++ */ ++ iocmd->cmd = REPORT_LUNS; ++ iocmd->data_dma = lun_data_dma; ++ iocmd->data = (u8 *)lun_data; ++ iocmd->size = lun_data_len; ++ iocmd->channel = channel; ++ iocmd->id = id; + +- if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) ++ if ((rc = mptscsih_do_cmd(hd, iocmd)) < 0) { ++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " ++ "report_luns failed due to rc=0x%x\n", ioc->name, ++ __FUNCTION__, channel, id, rc); + goto out; ++ } + +- mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); +- if (!mf) { +- error = -ENOMEM; +- goto out_unlock; ++ if (rc != MPT_SCANDV_GOOD) { ++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " ++ "report_luns failed due to rc=0x%x\n", ioc->name, ++ __FUNCTION__, channel, id, rc); ++ rc = -rc; ++ goto out; + } + +- hdr = (MPIHeader_t *) mf; +- req = (SasIoUnitControlRequest_t *)mf; +- memset(req, 0, sizeof(SasIoUnitControlRequest_t)); +- req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; +- req->MsgContext = hdr->MsgContext; +- req->Operation = hard_reset ? +- MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; +- req->PhyNum = phy->identify.phy_identifier; ++ data = (u8 *)lun_data; ++ length = ((data[0] << 24) | (data[1] << 16) | ++ (data[2] << 8) | (data[3] << 0)); + +- mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); ++ num_luns = (length / sizeof(struct scsi_lun)); ++ if (!num_luns) ++ goto out; ++ /* return 1st lun in the list */ ++ *lun = scsilun_to_int(&lun_data[1]); + +- timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, +- 10 * HZ); +- if (!timeleft) { +- /* On timeout reset the board */ +- mpt_free_msg_frame(ioc, mf); +- mpt_HardResetHandler(ioc, CAN_SLEEP); +- error = -ETIMEDOUT; +- goto out_unlock; ++#if 0 ++ /* some debugging, left commented out */ ++ { ++ struct scsi_lun *lunp; ++ for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++) ++ printk("%x\n", scsilun_to_int(lunp)); + } ++#endif + +- /* a reply frame is expected */ +- if ((ioc->sas_mgmt.status & +- MPT_IOCTL_STATUS_RF_VALID) == 0) { +- error = -ENXIO; +- goto out_unlock; +- } ++ out: ++ if (lun_data) ++ pci_free_consistent(ioc->pcidev, lun_data_len, lun_data, ++ lun_data_dma); ++ kfree(iocmd); ++ return rc; ++} + +- /* process the completed Reply Message Frame */ +- reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; +- if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { +- printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", +- ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); +- error = -ENXIO; +- goto out_unlock; ++/** ++ * enum device_state - ++ * @DEVICE_RETRY: need to retry the TUR ++ * @DEVICE_ERROR: TUR return error, don't add device ++ * @DEVICE_READY: device can be added ++ * ++ */ ++enum device_state{ ++ DEVICE_RETRY, ++ DEVICE_ERROR, ++ DEVICE_READY, ++}; ++ ++/** ++ * mptsas_test_unit_ready - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: ++ * @id: ++ * @count: retry count ++ * ++ */ ++enum device_state ++mptsas_test_unit_ready(MPT_ADAPTER *ioc, u8 channel, u8 id, u16 count) ++{ ++ INTERNAL_CMD *iocmd; ++ MPT_SCSI_HOST *hd = shost_priv(ioc->sh); ++ enum device_state state; ++ int rc; ++ u8 skey, asc, ascq; ++ u8 retry_ua; ++ ++ if (count >= mpt_cmd_retry_count) ++ return DEVICE_ERROR; ++ ++ retry_ua = 0; ++ iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); ++ if (!iocmd) { ++ printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", ++ __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD)); ++ return DEVICE_ERROR; ++ } ++ ++ state = DEVICE_ERROR; ++ iocmd->cmd = TEST_UNIT_READY; ++ iocmd->data_dma = -1; ++ iocmd->data = NULL; ++ ++ if (mptscsih_is_phys_disk(ioc, channel, id)) { ++ iocmd->flags |= MPT_ICFLAG_PHYS_DISK; ++ iocmd->physDiskNum = mptscsih_raid_id_to_num(ioc, channel, id); ++ iocmd->id = id; ++ } ++ iocmd->channel = channel; ++ iocmd->id = id; ++ ++ retry: ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d " ++ "fw_id=%d retry=%d\n", ioc->name, __FUNCTION__, channel, id, count)); ++ rc = mptscsih_do_cmd(hd, iocmd); ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rc=0x%02x\n", ++ ioc->name, __FUNCTION__, rc)); ++ if (rc < 0) { ++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " ++ "tur failed due to timeout\n", ioc->name, ++ __FUNCTION__, channel, id); ++ goto tur_done; ++ } ++ ++ switch(rc) { ++ case MPT_SCANDV_GOOD: ++ state = DEVICE_READY; ++ goto tur_done; ++ case MPT_SCANDV_BUSY: ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " ++ "fw_channel=%d fw_id=%d : device busy\n", ++ ioc->name, __FUNCTION__, channel, id)); ++ state = DEVICE_RETRY; ++ break; ++ case MPT_SCANDV_DID_RESET: ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " ++ "fw_channel=%d fw_id=%d : did reset\n", ++ ioc->name, __FUNCTION__, channel, id)); ++ state = DEVICE_RETRY; ++ break; ++ case MPT_SCANDV_SENSE: ++ skey = ioc->internal_cmds.sense[2] & 0x0F; ++ asc = ioc->internal_cmds.sense[12]; ++ ascq = ioc->internal_cmds.sense[13]; ++ ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " ++ "fw_channel=%d fw_id=%d : [sense_key,asc," ++ "ascq]: [0x%02x,0x%02x,0x%02x]\n", ioc->name, ++ __FUNCTION__, channel, id, skey, asc, ascq)); ++ ++ if (skey == UNIT_ATTENTION) { ++ if (!retry_ua) { ++ retry_ua++; ++ goto retry; ++ } ++ } else if (skey == NOT_READY) { ++ /* ++ * medium isn't present ++ */ ++ if (asc == 0x3a) { ++ state = DEVICE_READY; ++ goto tur_done; ++ } ++ /* ++ * LU becoming ready, or ++ * LU hasn't self-configured yet ++ */ ++ if ((asc == 0x04 && ascq == 0x01) || ++ (asc == 0x04 && ascq == 0x11) || ++ asc == 0x3e) { ++ state = DEVICE_RETRY; ++ break; ++ } ++ } else if (skey == ILLEGAL_REQUEST) { ++ /* try sending a tur to a non-zero lun number */ ++ if (!iocmd->lun && !mptsas_get_lun_number(ioc, ++ channel, id, &iocmd->lun) && iocmd->lun) ++ goto retry; ++ } ++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d : " ++ "tur failed due to [sense_key,asc,ascq]: " ++ "[0x%02x,0x%02x,0x%02x]\n", ioc->name, ++ __FUNCTION__, channel, id, skey, asc, ascq); ++ goto tur_done; ++ case MPT_SCANDV_SELECTION_TIMEOUT: ++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " ++ "tur failed due to no device\n", ioc->name, ++ __FUNCTION__, channel, ++ id); ++ goto tur_done; ++ case MPT_SCANDV_SOME_ERROR: ++ printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " ++ "tur failed due to some error\n", ioc->name, ++ __FUNCTION__, ++ channel, id); ++ goto tur_done; ++ default: ++ printk(MYIOC_s_ERR_FMT ++ "%s: fw_channel=%d fw_id=%d: tur failed due to " ++ "unknown rc=0x%02x\n", ioc->name, __FUNCTION__, ++ channel, id, rc ); ++ goto tur_done; ++ } ++ tur_done: ++ kfree(iocmd); ++ return state; ++} ++ ++/** ++ * mptsas_issue_tlr - Enabling Transport Layer Retries ++ * @hd: ++ * @sdev: ++ * ++ **/ ++static void ++mptsas_issue_tlr(MPT_SCSI_HOST *hd, struct scsi_device *sdev) ++{ ++ INTERNAL_CMD *iocmd; ++ VirtDevice *vdevice = sdev->hostdata; ++ u8 retries; ++ u8 rc; ++ MPT_ADAPTER *ioc = hd->ioc; ++ ++ if ( sdev->inquiry[8] == 'H' && ++ sdev->inquiry[9] == 'P' && ++ sdev->inquiry[10] == ' ' && ++ sdev->inquiry[11] == ' ' && ++ sdev->inquiry[12] == ' ' && ++ sdev->inquiry[13] == ' ' && ++ sdev->inquiry[14] == ' ' && ++ sdev->inquiry[15] == ' ' ) { ++ ++ iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); ++ if (!iocmd) { ++ printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", ++ __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD)); ++ return; ++ } ++ iocmd->id = vdevice->vtarget->id; ++ iocmd->channel = vdevice->vtarget->channel; ++ iocmd->lun = vdevice->lun; ++ iocmd->physDiskNum = -1; ++ iocmd->cmd = TRANSPORT_LAYER_RETRIES; ++ iocmd->data_dma = -1; ++ for (retries = 0, rc = -1; retries < 3; retries++) { ++ rc = mptscsih_do_cmd(hd, iocmd); ++ if (!rc) ++ break; ++ } ++ if (rc != 0) ++ printk(MYIOC_s_DEBUG_FMT "unable to enable TLR on" ++ " fw_channel %d, fw_id %d, lun=%d\n", ++ ioc->name, vdevice->vtarget->channel, ++ vdevice->vtarget->id, sdev->lun); ++ kfree(iocmd); + } ++} + +- error = 0; ++/** ++ * mptsas_slave_configure - ++ * @sdev: ++ * ++ **/ ++static int ++mptsas_slave_configure(struct scsi_device *sdev) ++{ ++ struct Scsi_Host *host = sdev->host; ++ MPT_SCSI_HOST *hd = shost_priv(host); ++ MPT_ADAPTER *ioc = hd->ioc; ++ VirtDevice *vdevice = sdev->hostdata; ++ ++ ++ if (vdevice->vtarget->deleted) { ++ sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); ++ vdevice->vtarget->deleted = 0; ++ } + +- out_unlock: +- mutex_unlock(&ioc->sas_mgmt.mutex); ++ /* ++ * RAID volumes placed beyond the last expected port. ++ * Ignore sending sas mode pages in that case.. ++ */ ++ if (sdev->channel == MPTSAS_RAID_CHANNEL) { ++ mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); ++ goto out; ++ } ++ ++ sas_read_port_mode_page(sdev); ++ ++ mptsas_add_device_component_starget(ioc, scsi_target(sdev)); ++ ++ if (sdev->type == TYPE_TAPE && ++ (ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_TLR )) ++ mptsas_issue_tlr(hd, sdev); + out: +- return error; ++ ++ return mptscsih_slave_configure(sdev); + } + ++/** ++ * mptsas_target_alloc - ++ * @starget: ++ * ++ **/ + static int +-mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) ++mptsas_target_alloc(struct scsi_target *starget) + { +- MPT_ADAPTER *ioc = rphy_to_ioc(rphy); +- int i, error; +- struct mptsas_portinfo *p; +- struct mptsas_enclosure enclosure_info; +- u64 enclosure_handle; ++ struct Scsi_Host *host = dev_to_shost(&starget->dev); ++ MPT_SCSI_HOST *hd = shost_priv(host); ++ VirtTarget *vtarget; ++ u8 id, channel; ++ struct sas_rphy *rphy; ++ struct mptsas_portinfo *p; ++ int i; ++ MPT_ADAPTER *ioc = hd->ioc; ++ ++ vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); ++ if (!vtarget) ++ return -ENOMEM; ++ ++ vtarget->starget = starget; ++ vtarget->ioc_id = ioc->id; ++ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; ++ id = starget->id; ++ channel = 0; ++ ++ /* ++ * RAID volumes placed beyond the last expected port. ++ */ ++ if (starget->channel == MPTSAS_RAID_CHANNEL) { ++ if (!ioc->raid_data.pIocPg2) { ++ kfree(vtarget); ++ return -ENXIO; ++ } ++ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) ++ if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) ++ channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; ++ vtarget->raidVolume = 1; ++ goto out; ++ } + ++ rphy = dev_to_rphy(starget->dev.parent); + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(p, &ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { +- if (p->phy_info[i].attached.sas_address == +- rphy->identify.sas_address) { +- enclosure_handle = p->phy_info[i]. +- attached.handle_enclosure; +- goto found_info; ++ if (p->phy_info[i].attached.sas_address != ++ rphy->identify.sas_address) ++ continue; ++ id = p->phy_info[i].attached.id; ++ channel = p->phy_info[i].attached.channel; ++ mptsas_set_starget(&p->phy_info[i], starget); ++ ++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT ++ "add device: fw_channel %d, fw_id %d, phy %d, sas_addr 0x%llx\n", ++ ioc->name, p->phy_info[i].attached.channel, ++ p->phy_info[i].attached.id, p->phy_info[i].attached.phy_id, ++ (unsigned long long)p->phy_info[i].attached.sas_address); ++ ++ /* ++ * Exposing hidden raid components ++ */ ++ if (mptscsih_is_phys_disk(ioc, channel, id)) { ++ id = mptscsih_raid_id_to_num(ioc, ++ channel, id); ++ vtarget->tflags |= ++ MPT_TARGET_FLAGS_RAID_COMPONENT; ++ p->phy_info[i].attached.phys_disk_num = id; + } ++ mutex_unlock(&ioc->sas_topology_mutex); ++ goto out; + } + } + mutex_unlock(&ioc->sas_topology_mutex); ++ ++ kfree(vtarget); + return -ENXIO; + +- found_info: +- mutex_unlock(&ioc->sas_topology_mutex); +- memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); +- error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, +- (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << +- MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); +- if (!error) +- *identifier = enclosure_info.enclosure_logical_id; +- return error; ++ out: ++ vtarget->id = id; ++ vtarget->channel = channel; ++ starget->hostdata = vtarget; ++ return 0; + } + +-static int +-mptsas_get_bay_identifier(struct sas_rphy *rphy) ++/** ++ * mptsas_target_destroy - ++ * @starget: ++ * ++ **/ ++static void ++mptsas_target_destroy(struct scsi_target *starget) + { +- MPT_ADAPTER *ioc = rphy_to_ioc(rphy); +- struct mptsas_portinfo *p; +- int i, rc; ++ struct Scsi_Host *host = dev_to_shost(&starget->dev); ++ MPT_SCSI_HOST *hd = shost_priv(host); ++ struct sas_rphy *rphy; ++ struct mptsas_portinfo *p; ++ int i; ++ MPT_ADAPTER *ioc = hd->ioc; + +- mutex_lock(&ioc->sas_topology_mutex); ++ if (!starget->hostdata) ++ return; ++ ++ mptsas_del_device_component_by_os(ioc, starget->channel, ++ starget->id); ++ ++ if (starget->channel == MPTSAS_RAID_CHANNEL) ++ goto out; ++ ++ rphy = dev_to_rphy(starget->dev.parent); + list_for_each_entry(p, &ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { +- if (p->phy_info[i].attached.sas_address == +- rphy->identify.sas_address) { +- rc = p->phy_info[i].attached.slot; +- goto out; +- } ++ if (p->phy_info[i].attached.sas_address != ++ rphy->identify.sas_address) ++ continue; ++ ++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT ++ "delete device: fw_channel %d, fw_id %d, phy %d, " ++ "sas_addr 0x%llx\n", ioc->name, ++ p->phy_info[i].attached.channel, ++ p->phy_info[i].attached.id, ++ p->phy_info[i].attached.phy_id, (unsigned long long) ++ p->phy_info[i].attached.sas_address); ++ ++ mptsas_port_delete(ioc, p->phy_info[i].port_details); + } + } +- rc = -ENXIO; ++ + out: +- mutex_unlock(&ioc->sas_topology_mutex); +- return rc; ++ kfree(starget->hostdata); ++ starget->hostdata = NULL; + } + +-static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, +- struct request *req) ++/** ++ * mptsas_slave_alloc - ++ * @sdev: ++ * ++ **/ ++static int ++mptsas_slave_alloc(struct scsi_device *sdev) + { +- MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; +- MPT_FRAME_HDR *mf; +- SmpPassthroughRequest_t *smpreq; +- struct request *rsp = req->next_rq; +- int ret; +- int flagsLength; +- unsigned long timeleft; +- char *psge; +- dma_addr_t dma_addr_in = 0; +- dma_addr_t dma_addr_out = 0; +- u64 sas_address = 0; +- +- if (!rsp) { +- printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", +- ioc->name, __func__); +- return -EINVAL; +- } ++ struct Scsi_Host *host = sdev->host; ++ MPT_SCSI_HOST *hd = shost_priv(host); ++ struct sas_rphy *rphy; ++ struct mptsas_portinfo *p; ++ VirtDevice *vdevice; ++ struct scsi_target *starget; ++ int i; ++ MPT_ADAPTER *ioc = hd->ioc; + +- /* do we need to support multiple segments? */ +- if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { +- printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", +- ioc->name, __func__, req->bio->bi_vcnt, req->data_len, +- rsp->bio->bi_vcnt, rsp->data_len); +- return -EINVAL; ++ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); ++ if (!vdevice) { ++ printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", ++ ioc->name, sizeof(VirtDevice)); ++ return -ENOMEM; + } ++ starget = scsi_target(sdev); ++ vdevice->vtarget = starget->hostdata; + +- ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); +- if (ret) ++ /* ++ * RAID volumes placed beyond the last expected port. ++ */ ++ if (sdev->channel == MPTSAS_RAID_CHANNEL) + goto out; + +- mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); +- if (!mf) { +- ret = -ENOMEM; +- goto out_unlock; ++ rphy = dev_to_rphy(sdev->sdev_target->dev.parent); ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_for_each_entry(p, &ioc->sas_topology, list) { ++ for (i = 0; i < p->num_phys; i++) { ++ if (p->phy_info[i].attached.sas_address != ++ rphy->identify.sas_address) ++ continue; ++ vdevice->lun = sdev->lun; ++ /* ++ * Exposing hidden raid components ++ */ ++ if (mptscsih_is_phys_disk(ioc, ++ p->phy_info[i].attached.channel, ++ p->phy_info[i].attached.id)) ++ sdev->no_uld_attach = 1; ++ mutex_unlock(&ioc->sas_topology_mutex); ++ goto out; ++ } + } ++ mutex_unlock(&ioc->sas_topology_mutex); + +- smpreq = (SmpPassthroughRequest_t *)mf; +- memset(smpreq, 0, sizeof(*smpreq)); ++ kfree(vdevice); ++ return -ENXIO; + +- smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); +- smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; ++ out: ++ vdevice->vtarget->num_luns++; ++ sdev->hostdata = vdevice; ++ return 0; ++} + +- if (rphy) +- sas_address = rphy->identify.sas_address; +- else { +- struct mptsas_portinfo *port_info; ++/** ++ * mptsas_qcmd - ++ * @SCpnt: ++ * @done: ++ * ++ **/ ++static int ++mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) ++{ ++ MPT_SCSI_HOST *hd; ++ MPT_ADAPTER *ioc; ++ VirtDevice *vdevice = SCpnt->device->hostdata; + +- mutex_lock(&ioc->sas_topology_mutex); +- port_info = mptsas_get_hba_portinfo(ioc); +- if (port_info && port_info->phy_info) +- sas_address = +- port_info->phy_info[0].phy->identify.sas_address; +- mutex_unlock(&ioc->sas_topology_mutex); ++ if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { ++ SCpnt->result = DID_NO_CONNECT << 16; ++ done(SCpnt); ++ return 0; + } + +- *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); ++ hd = shost_priv(SCpnt->device->host); ++ ioc = hd->ioc; + +- psge = (char *) +- (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); ++ if (ioc->sas_discovery_quiesce_io) ++ return SCSI_MLQUEUE_HOST_BUSY; + +- /* request */ +- flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | +- MPI_SGE_FLAGS_END_OF_BUFFER | +- MPI_SGE_FLAGS_DIRECTION | +- mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT; +- flagsLength |= (req->data_len - 4); +- +- dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), +- req->data_len, PCI_DMA_BIDIRECTIONAL); +- if (!dma_addr_out) +- goto put_mf; +- mpt_add_sge(psge, flagsLength, dma_addr_out); +- psge += (sizeof(u32) + sizeof(dma_addr_t)); +- +- /* response */ +- flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; +- flagsLength |= rsp->data_len + 4; +- dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), +- rsp->data_len, PCI_DMA_BIDIRECTIONAL); +- if (!dma_addr_in) +- goto unmap; +- mpt_add_sge(psge, flagsLength, dma_addr_in); ++// scsi_print_command(SCpnt); ++ return mptscsih_qcmd(SCpnt,done); ++} + +- mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); + +- timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); +- if (!timeleft) { +- printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__); +- /* On timeout reset the board */ +- mpt_HardResetHandler(ioc, CAN_SLEEP); +- ret = -ETIMEDOUT; +- goto unmap; +- } +- mf = NULL; +- +- if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) { +- SmpPassthroughReply_t *smprep; +- +- smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; +- memcpy(req->sense, smprep, sizeof(*smprep)); +- req->sense_len = sizeof(*smprep); +- req->data_len = 0; +- rsp->data_len -= smprep->ResponseDataLength; +- } else { +- printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", +- ioc->name, __func__); +- ret = -ENXIO; +- } +-unmap: +- if (dma_addr_out) +- pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, +- PCI_DMA_BIDIRECTIONAL); +- if (dma_addr_in) +- pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, +- PCI_DMA_BIDIRECTIONAL); +-put_mf: +- if (mf) ++static struct scsi_host_template mptsas_driver_template = { ++ .module = THIS_MODULE, ++ .proc_name = "mptsas", ++ .proc_info = mptscsih_proc_info, ++ .name = "MPT SPI Host", ++ .info = mptscsih_info, ++ .queuecommand = mptsas_qcmd, ++ .target_alloc = mptsas_target_alloc, ++ .slave_alloc = mptsas_slave_alloc, ++ .slave_configure = mptsas_slave_configure, ++ .target_destroy = mptsas_target_destroy, ++ .slave_destroy = mptscsih_slave_destroy, ++ .change_queue_depth = mptscsih_change_queue_depth, ++ .eh_abort_handler = mptscsih_abort, ++ .eh_device_reset_handler = mptscsih_dev_reset, ++ .eh_bus_reset_handler = mptscsih_bus_reset, ++ .eh_host_reset_handler = mptscsih_host_reset, ++ .bios_param = mptscsih_bios_param, ++ .can_queue = MPT_FC_CAN_QUEUE, ++ .this_id = -1, ++ .sg_tablesize = MPT_SCSI_SG_DEPTH, ++ .max_sectors = 8192, ++ .cmd_per_lun = 7, ++ .use_clustering = ENABLE_CLUSTERING, ++ .shost_attrs = mptscsih_host_attrs, ++}; ++ ++/** ++ * mptsas_get_linkerrors - ++ * @phy: ++ * ++ **/ ++static int mptsas_get_linkerrors(struct sas_phy *phy) ++{ ++ MPT_ADAPTER *ioc = phy_to_ioc(phy); ++ ConfigExtendedPageHeader_t hdr; ++ CONFIGPARMS cfg; ++ SasPhyPage1_t *buffer; ++ dma_addr_t dma_handle; ++ int error; ++ ++ /* FIXME: only have link errors on local phys */ ++ if (!scsi_is_sas_phy_local(phy)) ++ return -EINVAL; ++ ++ hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; ++ hdr.ExtPageLength = 0; ++ hdr.PageNumber = 1 /* page number 1*/; ++ hdr.Reserved1 = 0; ++ hdr.Reserved2 = 0; ++ hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; ++ hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; ++ ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = phy->identify.phy_identifier; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; ++ ++ error = mpt_config(ioc, &cfg); ++ if (error) ++ return error; ++ if (!hdr.ExtPageLength) ++ return -ENXIO; ++ ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ &dma_handle); ++ if (!buffer) ++ return -ENOMEM; ++ ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ error = mpt_config(ioc, &cfg); ++ if (error) ++ goto out_free_consistent; ++ ++ mptsas_print_phy_pg1(ioc, buffer); ++ ++ phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); ++ phy->running_disparity_error_count = ++ le32_to_cpu(buffer->RunningDisparityErrorCount); ++ phy->loss_of_dword_sync_count = ++ le32_to_cpu(buffer->LossDwordSynchCount); ++ phy->phy_reset_problem_count = ++ le32_to_cpu(buffer->PhyResetProblemCount); ++ ++ out_free_consistent: ++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ buffer, dma_handle); ++ return error; ++} ++ ++/** ++ * mptsas_mgmt_done - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @req: ++ * @reply: ++ * ++ **/ ++static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, ++ MPT_FRAME_HDR *reply) ++{ ++ ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ++ if (reply != NULL) { ++ ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; ++ memcpy(ioc->sas_mgmt.reply, reply, ++ min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); ++ } ++ ++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->sas_mgmt.done); ++ return 1; ++ } ++ return 0; ++} ++ ++/** ++ * mptsas_phy_reset - ++ * @phy: ++ * @hard_reset: ++ * ++ **/ ++static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) ++{ ++ MPT_ADAPTER *ioc = phy_to_ioc(phy); ++ SasIoUnitControlRequest_t *req; ++ SasIoUnitControlReply_t *reply; ++ MPT_FRAME_HDR *mf; ++ MPIHeader_t *hdr; ++ unsigned long timeleft; ++ int error = -ERESTARTSYS; ++ ++ /* FIXME: fusion doesn't allow non-local phy reset */ ++ if (!scsi_is_sas_phy_local(phy)) ++ return -EINVAL; ++ ++ /* not implemented for expanders */ ++ if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) ++ return -ENXIO; ++ ++ if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) ++ goto out; ++ ++ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); ++ if (!mf) { ++ error = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ hdr = (MPIHeader_t *) mf; ++ req = (SasIoUnitControlRequest_t *)mf; ++ memset(req, 0, sizeof(SasIoUnitControlRequest_t)); ++ req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; ++ req->MsgContext = hdr->MsgContext; ++ req->Operation = hard_reset ? ++ MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; ++ req->PhyNum = phy->identify.phy_identifier; ++ ++ INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) ++ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10*HZ); ++ if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ error = -ETIME; + mpt_free_msg_frame(ioc, mf); +-out_unlock: ++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out; ++ if (!timeleft) { ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ } ++ goto out_unlock; ++ } ++ ++ /* a reply frame is expected */ ++ if ((ioc->sas_mgmt.status & ++ MPT_MGMT_STATUS_RF_VALID) == 0) { ++ error = -ENXIO; ++ goto out_unlock; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; ++ if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { ++ printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); ++ error = -ENXIO; ++ goto out_unlock; ++ } ++ ++ error = 0; ++ ++ out_unlock: ++ CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) + mutex_unlock(&ioc->sas_mgmt.mutex); +-out: +- return ret; ++ out: ++ return error; ++} ++ ++/** ++ * mptsas_get_enclosure_identifier - ++ * @rphy: ++ * @identifier: ++ * ++ **/ ++static int ++mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) ++{ ++ MPT_ADAPTER *ioc = rphy_to_ioc(rphy); ++ int i, error; ++ struct mptsas_portinfo *p; ++ struct mptsas_enclosure enclosure_info; ++ u64 enclosure_handle; ++ ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_for_each_entry(p, &ioc->sas_topology, list) { ++ for (i = 0; i < p->num_phys; i++) { ++ if (p->phy_info[i].attached.sas_address == ++ rphy->identify.sas_address) { ++ enclosure_handle = p->phy_info[i]. ++ attached.handle_enclosure; ++ goto found_info; ++ } ++ } ++ } ++ mutex_unlock(&ioc->sas_topology_mutex); ++ return -ENXIO; ++ ++ found_info: ++ mutex_unlock(&ioc->sas_topology_mutex); ++ memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); ++ error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, ++ (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << ++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), ++ enclosure_handle); ++ if (!error) ++ *identifier = enclosure_info.enclosure_logical_id; ++ return error; ++} ++ ++/** ++ * mptsas_get_bay_identifier - ++ * @rphy: ++ * ++ **/ ++static int ++mptsas_get_bay_identifier(struct sas_rphy *rphy) ++{ ++ MPT_ADAPTER *ioc = rphy_to_ioc(rphy); ++ struct mptsas_portinfo *p; ++ int i, rc; ++ ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_for_each_entry(p, &ioc->sas_topology, list) { ++ for (i = 0; i < p->num_phys; i++) { ++ if (p->phy_info[i].attached.sas_address == ++ rphy->identify.sas_address) { ++ rc = p->phy_info[i].attached.slot; ++ goto out; ++ } ++ } ++ } ++ rc = -ENXIO; ++ out: ++ mutex_unlock(&ioc->sas_topology_mutex); ++ return rc; + } + + static struct sas_function_template mptsas_transport_functions = { +@@ -1385,11 +2280,16 @@ static struct sas_function_template mpts + .get_enclosure_identifier = mptsas_get_enclosure_identifier, + .get_bay_identifier = mptsas_get_bay_identifier, + .phy_reset = mptsas_phy_reset, +- .smp_handler = mptsas_smp_handler, + }; + + static struct scsi_transport_template *mptsas_transport_template; + ++/** ++ * mptsas_sas_io_unit_pg0 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @port_info: ++ * ++ **/ + static int + mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) + { +@@ -1412,7 +2312,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + + error = mpt_config(ioc, &cfg); + if (error) +@@ -1438,7 +2338,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, + + port_info->num_phys = buffer->NumPhys; + port_info->phy_info = kcalloc(port_info->num_phys, +- sizeof(*port_info->phy_info),GFP_KERNEL); ++ sizeof(struct mptsas_phyinfo),GFP_KERNEL); + if (!port_info->phy_info) { + error = -ENOMEM; + goto out_free_consistent; +@@ -1459,6 +2359,8 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); ++ port_info->phy_info[i].port_flags = ++ buffer->PhyData[i].PortFlags; + } + + out_free_consistent: +@@ -1468,6 +2370,11 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, + return error; + } + ++/** ++ * mptsas_sas_io_unit_pg1 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ **/ + static int + mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) + { +@@ -1483,11 +2390,11 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) + + cfg.cfghdr.ehdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; +- cfg.timeout = 10; + cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; + cfg.cfghdr.ehdr->PageNumber = 1; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + + error = mpt_config(ioc, &cfg); + if (error) +@@ -1525,6 +2432,14 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) + return error; + } + ++/** ++ * mptsas_sas_phy_pg0 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phy_info: ++ * @form: ++ * @form_specific: ++ * ++ **/ + static int + mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, + u32 form, u32 form_specific) +@@ -1545,12 +2460,12 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str + + cfg.cfghdr.ehdr = &hdr; + cfg.dir = 0; /* read */ +- cfg.timeout = 10; + + /* Get Phy Pg 0 for each Phy. */ + cfg.physAddr = -1; + cfg.pageAddr = form + form_specific; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + + error = mpt_config(ioc, &cfg); + if (error) +@@ -1581,6 +2496,8 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str + phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; + phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); + phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); ++ phy_info->change_count = buffer->ChangeCount; ++ phy_info->phy_info = le32_to_cpu(buffer->PhyInfo); + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, +@@ -1589,6 +2506,14 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, str + return error; + } + ++/** ++ * mptsas_sas_device_pg0 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @device_info: ++ * @form: ++ * @form_specific: ++ * ++ **/ + static int + mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, + u32 form, u32 form_specific) +@@ -1600,10 +2525,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, + __le64 sas_address; + int error=0; + +- if (ioc->sas_discovery_runtime && +- mptsas_is_end_device(device_info)) +- goto out; +- + hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; +@@ -1617,9 +2538,8 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + +- memset(device_info, 0, sizeof(struct mptsas_devinfo)); + error = mpt_config(ioc, &cfg); + if (error) + goto out; +@@ -1639,11 +2559,18 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); ++ ++ if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { ++ error = -ENODEV; ++ goto out_free_consistent; ++ } ++ + if (error) + goto out_free_consistent; + + mptsas_print_device_pg0(ioc, buffer); + ++ memset(device_info, 0, sizeof(struct mptsas_devinfo)); + device_info->handle = le16_to_cpu(buffer->DevHandle); + device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); + device_info->handle_enclosure = +@@ -1666,6 +2593,14 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, + return error; + } + ++/** ++ * mptsas_sas_expander_pg0 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @port_info: ++ * @form: ++ * @form_specific: ++ * ++ **/ + static int + mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, + u32 form, u32 form_specific) +@@ -1675,7 +2610,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc + SasExpanderPage0_t *buffer; + dma_addr_t dma_handle; + int i, error; ++ __le64 sas_address; + ++ memset(port_info, 0, sizeof(struct mptsas_portinfo)); + hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; +@@ -1689,9 +2626,8 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc + cfg.pageAddr = form + form_specific; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + +- memset(port_info, 0, sizeof(struct mptsas_portinfo)); + error = mpt_config(ioc, &cfg); + if (error) + goto out; +@@ -1712,27 +2648,32 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); +- if (error) +- goto out_free_consistent; +- +- if (!buffer->NumPhys) { ++ if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + error = -ENODEV; + goto out_free_consistent; + } + ++ if (error) ++ goto out_free_consistent; ++ + /* save config data */ +- port_info->num_phys = buffer->NumPhys; ++ port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; + port_info->phy_info = kcalloc(port_info->num_phys, +- sizeof(*port_info->phy_info),GFP_KERNEL); ++ sizeof(struct mptsas_phyinfo),GFP_KERNEL); + if (!port_info->phy_info) { + error = -ENOMEM; + goto out_free_consistent; + } + ++ memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(buffer->DevHandle); ++ port_info->phy_info[i].identify.sas_address = ++ le64_to_cpu(sas_address); ++ port_info->phy_info[i].identify.handle_parent = ++ le16_to_cpu(buffer->ParentDevHandle); + } + + out_free_consistent: +@@ -1742,6 +2683,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc + return error; + } + ++/** ++ * mptsas_sas_expander_pg1 - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phy_info: ++ * @form: ++ * @form_specific: ++ * ++ **/ + static int + mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, + u32 form, u32 form_specific) +@@ -1752,11 +2701,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc + dma_addr_t dma_handle; + int error=0; + +- if (ioc->sas_discovery_runtime && +- mptsas_is_end_device(&phy_info->attached)) +- goto out; +- +- hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; ++ hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 1; + hdr.Reserved1 = 0; +@@ -1764,1352 +2709,2349 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; + +- cfg.cfghdr.ehdr = &hdr; +- cfg.physAddr = -1; +- cfg.pageAddr = form + form_specific; ++ cfg.cfghdr.ehdr = &hdr; ++ cfg.physAddr = -1; ++ cfg.pageAddr = form + form_specific; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ cfg.dir = 0; /* read */ ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; ++ ++ error = mpt_config(ioc, &cfg); ++ if (error) ++ goto out; ++ ++ if (!hdr.ExtPageLength) { ++ error = -ENXIO; ++ goto out; ++ } ++ ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ &dma_handle); ++ if (!buffer) { ++ error = -ENOMEM; ++ goto out; ++ } ++ ++ cfg.physAddr = dma_handle; ++ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ ++ error = mpt_config(ioc, &cfg); ++ if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { ++ error = -ENODEV; ++ goto out; ++ } ++ ++ if (error) ++ goto out_free_consistent; ++ ++ ++ mptsas_print_expander_pg1(ioc, buffer); ++ ++ /* save config data */ ++ phy_info->phy_id = buffer->PhyIdentifier; ++ phy_info->port_id = buffer->PhysicalPort; ++ phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; ++ phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; ++ phy_info->hw_link_rate = buffer->HwLinkRate; ++ phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); ++ phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); ++ phy_info->change_count = buffer->ChangeCount; ++ phy_info->phy_info = le32_to_cpu(buffer->PhyInfo); ++ ++ out_free_consistent: ++ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, ++ buffer, dma_handle); ++ out: ++ return error; ++} ++ ++/** ++ * mptsas_parse_device_info - ++ * @identify: ++ * @device_info: ++ * ++ **/ ++static void ++mptsas_parse_device_info(struct sas_identify *identify, ++ struct mptsas_devinfo *device_info) ++{ ++ u16 protocols; ++ ++ identify->sas_address = device_info->sas_address; ++ identify->phy_identifier = device_info->phy_id; ++ ++ /* ++ * Fill in Phy Initiator Port Protocol. ++ * Bits 6:3, more than one bit can be set, fall through cases. ++ */ ++ protocols = device_info->device_info & 0x78; ++ identify->initiator_port_protocols = 0; ++ if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) ++ identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; ++ if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) ++ identify->initiator_port_protocols |= SAS_PROTOCOL_STP; ++ if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) ++ identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; ++ if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) ++ identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; ++ ++ /* ++ * Fill in Phy Target Port Protocol. ++ * Bits 10:7, more than one bit can be set, fall through cases. ++ */ ++ protocols = device_info->device_info & 0x780; ++ identify->target_port_protocols = 0; ++ if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) ++ identify->target_port_protocols |= SAS_PROTOCOL_SSP; ++ if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) ++ identify->target_port_protocols |= SAS_PROTOCOL_STP; ++ if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) ++ identify->target_port_protocols |= SAS_PROTOCOL_SMP; ++ if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) ++ identify->target_port_protocols |= SAS_PROTOCOL_SATA; ++ ++ /* ++ * Fill in Attached device type. ++ */ ++ switch (device_info->device_info & ++ MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { ++ case MPI_SAS_DEVICE_INFO_NO_DEVICE: ++ identify->device_type = SAS_PHY_UNUSED; ++ break; ++ case MPI_SAS_DEVICE_INFO_END_DEVICE: ++ identify->device_type = SAS_END_DEVICE; ++ break; ++ case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: ++ identify->device_type = SAS_EDGE_EXPANDER_DEVICE; ++ break; ++ case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: ++ identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; ++ break; ++ } ++} ++ ++/** ++ * mptsas_probe_one_phy - ++ * @dev: ++ * @phy_info: ++ * @local: ++ * ++ **/ ++static int mptsas_probe_one_phy(struct device *dev, ++ struct mptsas_phyinfo *phy_info, int index, int local) ++{ ++ MPT_ADAPTER *ioc; ++ struct sas_phy *phy; ++ struct sas_port *port; ++ int error = 0; ++ ++ if (!dev) { ++ error = -ENODEV; ++ goto out; ++ } ++ ++ if (!phy_info->phy) { ++ phy = sas_phy_alloc(dev, index); ++ if (!phy) { ++ error = -ENOMEM; ++ goto out; ++ } ++ } else ++ phy = phy_info->phy; ++ ++ mptsas_parse_device_info(&phy->identify, &phy_info->identify); ++ ++ /* ++ * Set Negotiated link rate. ++ */ ++ switch (phy_info->negotiated_link_rate) { ++ case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: ++ phy->negotiated_linkrate = SAS_PHY_DISABLED; ++ break; ++ case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: ++ phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; ++ break; ++ case MPI_SAS_IOUNIT0_RATE_1_5: ++ phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; ++ break; ++ case MPI_SAS_IOUNIT0_RATE_3_0: ++ phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; ++ break; ++ case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: ++ case MPI_SAS_IOUNIT0_RATE_UNKNOWN: ++ default: ++ phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; ++ break; ++ } ++ ++ /* ++ * Set Max hardware link rate. ++ */ ++ switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { ++ case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: ++ phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; ++ break; ++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: ++ phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; ++ break; ++ default: ++ break; ++ } ++ ++ /* ++ * Set Max programmed link rate. ++ */ ++ switch (phy_info->programmed_link_rate & ++ MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { ++ case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: ++ phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; ++ break; ++ case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: ++ phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; ++ break; ++ default: ++ break; ++ } ++ ++ /* ++ * Set Min hardware link rate. ++ */ ++ switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { ++ case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: ++ phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; ++ break; ++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: ++ phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; ++ break; ++ default: ++ break; ++ } ++ ++ /* ++ * Set Min programmed link rate. ++ */ ++ switch (phy_info->programmed_link_rate & ++ MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { ++ case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: ++ phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; ++ break; ++ case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: ++ phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; ++ break; ++ default: ++ break; ++ } ++ ++ if (!phy_info->phy) { ++ ++ error = sas_phy_add(phy); ++ if (error) { ++ sas_phy_free(phy); ++ goto out; ++ } ++ phy_info->phy = phy; ++ } ++ ++ if (!phy_info->attached.handle || ++ !phy_info->port_details) ++ goto out; ++ ++ port = mptsas_get_port(phy_info); ++ ioc = phy_to_ioc(phy_info->phy); ++ ++ if (phy_info->sas_port_add_phy) { ++ if (!port) { ++ port = sas_port_alloc_num(dev); ++ if (!port) { ++ error = -ENOMEM; ++ goto out; ++ } ++ error = sas_port_add(port); ++ if (error) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: exit at line=%d\n", ioc->name, ++ __FUNCTION__, __LINE__)); ++ goto out; ++ } ++ mptsas_set_port(ioc, phy_info, port); ++ devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, ++ MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", ++ ioc->name, port->port_identifier, ++ (unsigned long long)phy_info->attached.sas_address)); ++ } ++ sas_port_add_phy(port, phy_info->phy); ++ phy_info->sas_port_add_phy = 0; ++ devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, ++ MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, ++ phy_info->phy_id, phy_info->phy)); ++ } ++ ++ if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { ++ ++ struct sas_rphy *rphy; ++ struct device *parent; ++ struct sas_identify identify; ++ ++ parent = dev->parent->parent; ++ ++ if (mptsas_is_end_device(&phy_info->attached) && ++ phy_info->attached.handle_parent) { ++ goto out; ++ } ++ ++ mptsas_parse_device_info(&identify, &phy_info->attached); ++ if (scsi_is_host_device(parent)) { ++ struct mptsas_portinfo *port_info; ++ int i; ++ ++ port_info = ioc->hba_port_info; ++ for (i = 0; i < port_info->num_phys; i++) ++ if (port_info->phy_info[i].identify.sas_address == ++ identify.sas_address) { ++ sas_port_mark_backlink(port); ++ goto out; ++ } ++ ++ } else if (scsi_is_sas_rphy(parent)) { ++ struct sas_rphy *parent_rphy = dev_to_rphy(parent); ++ if (identify.sas_address == ++ parent_rphy->identify.sas_address) { ++ sas_port_mark_backlink(port); ++ goto out; ++ } ++ } ++ ++ switch (identify.device_type) { ++ case SAS_END_DEVICE: ++ rphy = sas_end_device_alloc(port); ++ break; ++ case SAS_EDGE_EXPANDER_DEVICE: ++ case SAS_FANOUT_EXPANDER_DEVICE: ++ rphy = sas_expander_alloc(port, identify.device_type); ++ break; ++ default: ++ rphy = NULL; ++ break; ++ } ++ if (!rphy) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: exit at line=%d\n", ioc->name, ++ __FUNCTION__, __LINE__)); ++ goto out; ++ } ++ ++ rphy->identify = identify; ++ error = sas_rphy_add(rphy); ++ if (error) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: exit at line=%d\n", ioc->name, ++ __FUNCTION__, __LINE__)); ++ sas_rphy_free(rphy); ++ goto out; ++ } ++ mptsas_set_rphy(ioc, phy_info, rphy); ++ } ++ ++ out: ++ return error; ++} ++ ++/** ++ * mptsas_probe_hba_phys - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @handle: ++ * ++ **/ ++static int ++mptsas_probe_hba_phys(MPT_ADAPTER *ioc) ++{ ++ struct mptsas_portinfo *port_info, *hba; ++ int error = -ENOMEM, i; ++ ++ hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); ++ if (! hba) ++ goto out; ++ ++ error = mptsas_sas_io_unit_pg0(ioc, hba); ++ if (error) ++ goto out_free_port_info; ++ ++ mptsas_sas_io_unit_pg1(ioc); ++ mutex_lock(&ioc->sas_topology_mutex); ++ port_info = ioc->hba_port_info; ++ if (!port_info) { ++ ioc->hba_port_info = port_info = hba; ++ ioc->hba_port_num_phy = port_info->num_phys; ++ list_add_tail(&port_info->list, &ioc->sas_topology); ++ } else { ++ for (i = 0; i < hba->num_phys; i++) { ++ port_info->phy_info[i].negotiated_link_rate = ++ hba->phy_info[i].negotiated_link_rate; ++ port_info->phy_info[i].handle = ++ hba->phy_info[i].handle; ++ port_info->phy_info[i].port_id = ++ hba->phy_info[i].port_id; ++ port_info->phy_info[i].port_flags = ++ hba->phy_info[i].port_flags; ++ } ++ kfree(hba->phy_info); ++ kfree(hba); ++ hba = NULL; ++ } ++ mutex_unlock(&ioc->sas_topology_mutex); ++#if defined(CPQ_CIM) ++ ioc->num_ports = port_info->num_phys; ++#endif ++ for (i = 0; i < port_info->num_phys; i++) { ++ mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], ++ (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << ++ MPI_SAS_PHY_PGAD_FORM_SHIFT), i); ++ port_info->phy_info[i].identify.handle = ++ port_info->phy_info[i].handle; ++ mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, ++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ port_info->phy_info[i].identify.handle); ++ if (!ioc->hba_port_sas_addr) ++ ioc->hba_port_sas_addr = ++ port_info->phy_info[i].identify.sas_address; ++ port_info->phy_info[i].identify.phy_id = ++ port_info->phy_info[i].phy_id = i; ++ if (port_info->phy_info[i].attached.handle) ++ mptsas_sas_device_pg0(ioc, ++ &port_info->phy_info[i].attached, ++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ port_info->phy_info[i].attached.handle); ++ } ++ ++ mptsas_setup_wide_ports(ioc, port_info); ++ ++ for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) ++ mptsas_probe_one_phy(&ioc->sh->shost_gendev, ++ &port_info->phy_info[i], ioc->sas_index, 1); ++ ++ return 0; ++ ++ out_free_port_info: ++ kfree(hba); ++ out: ++ return error; ++} ++ ++/** ++ * mptsas_find_phyinfo_by_sas_address - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @sas_address: ++ * ++ **/ ++static struct mptsas_phyinfo * ++mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) ++{ ++ struct mptsas_portinfo *port_info; ++ struct mptsas_phyinfo *phy_info = NULL; ++ int i; ++ ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_for_each_entry(port_info, &ioc->sas_topology, list) { ++ for (i = 0; i < port_info->num_phys; i++) { ++ if (!mptsas_is_end_device( ++ &port_info->phy_info[i].attached)) ++ continue; ++ if (port_info->phy_info[i].attached.sas_address ++ != sas_address) ++ continue; ++ phy_info = &port_info->phy_info[i]; ++ break; ++ } ++ } ++ mutex_unlock(&ioc->sas_topology_mutex); ++ return phy_info; ++} ++ ++/** ++ * mptsas_find_phyinfo_by_phys_disk_num - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phys_disk_num: ++ * @channel: ++ * @id: ++ * ++ **/ ++static struct mptsas_phyinfo * ++mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, ++ u8 channel, u8 id) ++{ ++ struct mptsas_phyinfo *phy_info; ++ struct mptsas_portinfo *port_info; ++ RaidPhysDiskPage1_t *phys_disk = NULL; ++ int num_paths; ++ u64 sas_address = 0; ++ int i; ++ ++ phy_info = NULL; ++ if (!ioc->raid_data.pIocPg3) ++ return NULL; ++ /* dual port support */ ++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); ++ if (!num_paths) ++ goto out; ++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); ++ if (!phys_disk) ++ goto out; ++ mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); ++ for (i = 0; i < num_paths; i++) { ++ if ((phys_disk->Path[i].Flags & 1) != 0) ++ /* entry no longer valid */ ++ continue; ++ if ((id == phys_disk->Path[i].PhysDiskID) && ++ (channel == phys_disk->Path[i].PhysDiskBus)) { ++ memcpy(&sas_address, &phys_disk->Path[i].WWID, ++ sizeof(u64)); ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_address); ++ goto out; ++ } ++ } ++ ++ out: ++ kfree(phys_disk); ++ if (phy_info) ++ return phy_info; ++ ++ /* ++ * Extra code to handle RAID0 case, where the sas_address is not updated ++ * in phys_disk_page_1 when hotswapped ++ */ ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_for_each_entry(port_info, &ioc->sas_topology, list) { ++ for (i = 0; i < port_info->num_phys && !phy_info; i++) { ++ if (!mptsas_is_end_device( ++ &port_info->phy_info[i].attached)) ++ continue; ++ if (port_info->phy_info[i].attached.phys_disk_num == ~0) ++ continue; ++ if (port_info->phy_info[i].attached.phys_disk_num == phys_disk_num && ++ port_info->phy_info[i].attached.id == id && ++ port_info->phy_info[i].attached.channel == channel) ++ phy_info = &port_info->phy_info[i]; ++ } ++ } ++ mutex_unlock(&ioc->sas_topology_mutex); ++ return phy_info; ++} ++ ++/** ++ * mptsas_reprobe_lun - ++ * @sdev: ++ * @data: ++ * ++ **/ ++static void ++mptsas_reprobe_lun(struct scsi_device *sdev, void *data) ++{ ++ int rc; ++ ++ sdev->no_uld_attach = data ? 1 : 0; ++ rc = scsi_device_reprobe(sdev); ++} ++ ++/** ++ * mptsas_reprobe_target - ++ * @starget: ++ * @uld_attach: ++ * ++ **/ ++static void ++mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) ++{ ++ starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, ++ mptsas_reprobe_lun); ++} ++ ++/** ++ * mptsas_adding_inactive_raid_components - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @channel: ++ * @id: ++ * ++ * ++ * TODO: check for hotspares ++ **/ ++static void ++mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) ++{ ++ CONFIGPARMS cfg; ++ ConfigPageHeader_t hdr; ++ dma_addr_t dma_handle; ++ pRaidVolumePage0_t buffer = NULL; ++ RaidPhysDiskPage0_t phys_disk; ++ int i; ++ struct mptsas_phyinfo *phy_info; ++ struct mptsas_devinfo sas_device; ++ ++ memset(&cfg, 0 , sizeof(CONFIGPARMS)); ++ memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); ++ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; ++ cfg.pageAddr = (channel << 8) + id; ++ cfg.cfghdr.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; +- cfg.dir = 0; /* read */ +- cfg.timeout = 10; ++ cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + +- error = mpt_config(ioc, &cfg); +- if (error) ++ if (mpt_config(ioc, &cfg) != 0) + goto out; + +- if (!hdr.ExtPageLength) { +- error = -ENXIO; ++ if (!hdr.PageLength) + goto out; +- } + +- buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, +- &dma_handle); +- if (!buffer) { +- error = -ENOMEM; ++ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, ++ &dma_handle); ++ ++ if (!buffer) + goto out; +- } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + +- error = mpt_config(ioc, &cfg); +- if (error) +- goto out_free_consistent; +- +- +- mptsas_print_expander_pg1(ioc, buffer); +- +- /* save config data */ +- phy_info->phy_id = buffer->PhyIdentifier; +- phy_info->port_id = buffer->PhysicalPort; +- phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; +- phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; +- phy_info->hw_link_rate = buffer->HwLinkRate; +- phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); +- phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); ++ if (mpt_config(ioc, &cfg) != 0) ++ goto out; + +- out_free_consistent: +- pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, +- buffer, dma_handle); +- out: +- return error; +-} ++ if (!(buffer->VolumeStatus.Flags & ++ MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) ++ goto out; + +-static void +-mptsas_parse_device_info(struct sas_identify *identify, +- struct mptsas_devinfo *device_info) +-{ +- u16 protocols; ++ if (!buffer->NumPhysDisks) ++ goto out; + +- identify->sas_address = device_info->sas_address; +- identify->phy_identifier = device_info->phy_id; ++ for (i = 0; i < buffer->NumPhysDisks; i++) { + +- /* +- * Fill in Phy Initiator Port Protocol. +- * Bits 6:3, more than one bit can be set, fall through cases. +- */ +- protocols = device_info->device_info & 0x78; +- identify->initiator_port_protocols = 0; +- if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) +- identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; +- if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) +- identify->initiator_port_protocols |= SAS_PROTOCOL_STP; +- if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) +- identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; +- if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) +- identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; ++ if (mpt_raid_phys_disk_pg0(ioc, ++ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) ++ continue; + +- /* +- * Fill in Phy Target Port Protocol. +- * Bits 10:7, more than one bit can be set, fall through cases. +- */ +- protocols = device_info->device_info & 0x780; +- identify->target_port_protocols = 0; +- if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) +- identify->target_port_protocols |= SAS_PROTOCOL_SSP; +- if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) +- identify->target_port_protocols |= SAS_PROTOCOL_STP; +- if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) +- identify->target_port_protocols |= SAS_PROTOCOL_SMP; +- if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) +- identify->target_port_protocols |= SAS_PROTOCOL_SATA; ++ if (mptsas_sas_device_pg0(ioc, &sas_device, ++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ (phys_disk.PhysDiskBus << 8) + ++ phys_disk.PhysDiskID)) ++ continue; + +- /* +- * Fill in Attached device type. +- */ +- switch (device_info->device_info & +- MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { +- case MPI_SAS_DEVICE_INFO_NO_DEVICE: +- identify->device_type = SAS_PHY_UNUSED; +- break; +- case MPI_SAS_DEVICE_INFO_END_DEVICE: +- identify->device_type = SAS_END_DEVICE; +- break; +- case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: +- identify->device_type = SAS_EDGE_EXPANDER_DEVICE; +- break; +- case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: +- identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; +- break; ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ sas_device.sas_address); ++ mptsas_add_end_device(ioc, phy_info); + } ++ ++ out: ++ if (buffer) ++ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, ++ dma_handle); + } + +-static int mptsas_probe_one_phy(struct device *dev, +- struct mptsas_phyinfo *phy_info, int index, int local) ++/** ++ * mptsas_add_end_device - report a new end device to sas transport layer ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phy_info: decribes attached device ++ * ++ * return (0) success (1) failure ++ * ++ **/ ++static int ++mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) + { +- MPT_ADAPTER *ioc; +- struct sas_phy *phy; ++ struct sas_rphy *rphy; + struct sas_port *port; +- int error = 0; ++ struct sas_identify identify; ++ char *ds = NULL; ++ u8 fw_id; + +- if (!dev) { +- error = -ENODEV; +- goto out; ++ if (!phy_info){ ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: exit at line=%d\n", ioc->name, ++ __FUNCTION__, __LINE__)); ++ return 1; + } + +- if (!phy_info->phy) { +- phy = sas_phy_alloc(dev, index); +- if (!phy) { +- error = -ENOMEM; +- goto out; +- } +- } else +- phy = phy_info->phy; +- +- mptsas_parse_device_info(&phy->identify, &phy_info->identify); +- +- /* +- * Set Negotiated link rate. +- */ +- switch (phy_info->negotiated_link_rate) { +- case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: +- phy->negotiated_linkrate = SAS_PHY_DISABLED; +- break; +- case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: +- phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; +- break; +- case MPI_SAS_IOUNIT0_RATE_1_5: +- phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; +- break; +- case MPI_SAS_IOUNIT0_RATE_3_0: +- phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; +- break; +- case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: +- case MPI_SAS_IOUNIT0_RATE_UNKNOWN: +- default: +- phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; +- break; +- } ++ fw_id = phy_info->attached.id; + +- /* +- * Set Max hardware link rate. +- */ +- switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { +- case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: +- phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; +- break; +- case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: +- phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; +- break; +- default: +- break; ++ if (mptsas_get_rphy(phy_info)) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ return 2; + } + +- /* +- * Set Max programmed link rate. +- */ +- switch (phy_info->programmed_link_rate & +- MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { +- case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: +- phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; +- break; +- case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: +- phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; +- break; +- default: +- break; ++ port = mptsas_get_port(phy_info); ++ if (!port) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ return 3; ++ } ++ ++ if (phy_info->attached.device_info & ++ MPI_SAS_DEVICE_INFO_SSP_TARGET) ++ ds = "ssp"; ++ if (phy_info->attached.device_info & ++ MPI_SAS_DEVICE_INFO_STP_TARGET) ++ ds = "stp"; ++ if (phy_info->attached.device_info & ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE) ++ ds = "sata"; ++ ++ printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," ++ " phy %d, sas_addr 0x%llx\n", ioc->name, ds, ++ phy_info->attached.channel, phy_info->attached.id, ++ phy_info->attached.phy_id, (unsigned long long) ++ phy_info->attached.sas_address); ++ ++ mptsas_parse_device_info(&identify, &phy_info->attached); ++ rphy = sas_end_device_alloc(port); ++ if (!rphy) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ return 5; /* non-fatal: an rphy can be added later */ ++ } ++ ++ rphy->identify = identify; ++ if (sas_rphy_add(rphy)) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ sas_rphy_free(rphy); ++ return 6; + } ++ mptsas_set_rphy(ioc, phy_info, rphy); ++ return 0; ++} + +- /* +- * Set Min hardware link rate. +- */ +- switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { +- case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: +- phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; +- break; +- case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: +- phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; +- break; +- default: +- break; +- } ++/** ++ * mptsas_del_end_device - report a deleted end device to sas transport ++ * layer ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @phy_info: decribes attached device ++ * ++ **/ ++static void ++mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) ++{ ++ struct sas_rphy *rphy; ++ struct sas_port *port; ++ struct mptsas_portinfo *port_info; ++ struct mptsas_phyinfo *phy_info_parent; ++ int i; ++ struct scsi_target * starget; ++ char *ds = NULL; ++ u8 fw_id; ++ u64 sas_address; + +- /* +- * Set Min programmed link rate. +- */ +- switch (phy_info->programmed_link_rate & +- MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { +- case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: +- phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; +- break; +- case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: +- phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; +- break; +- default: +- break; +- } ++ if (!phy_info) ++ return; + +- if (!phy_info->phy) { ++ fw_id = phy_info->attached.id; ++ sas_address = phy_info->attached.sas_address; + +- error = sas_phy_add(phy); +- if (error) { +- sas_phy_free(phy); +- goto out; +- } +- phy_info->phy = phy; ++ if (!phy_info->port_details) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ return; + } +- +- if (!phy_info->attached.handle || +- !phy_info->port_details) +- goto out; ++ rphy = mptsas_get_rphy(phy_info); ++ if (!rphy) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ return; ++ } ++ if (phy_info->attached.device_info & ++ MPI_SAS_DEVICE_INFO_SSP_TARGET) ++ ds = "ssp"; ++ if (phy_info->attached.device_info & ++ MPI_SAS_DEVICE_INFO_STP_TARGET) ++ ds = "stp"; ++ if (phy_info->attached.device_info & ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE) ++ ds = "sata"; ++ ++ starget = mptsas_get_starget(phy_info); ++ ++ printk(MYIOC_s_INFO_FMT "removing %s device: fw_channel %d," ++ " fw_id %d, phy %d, sas_addr 0x%llx\n", ioc->name, ds, ++ phy_info->attached.channel, phy_info->attached.id, ++ phy_info->attached.phy_id, (unsigned long long) ++ sas_address); + + port = mptsas_get_port(phy_info); +- ioc = phy_to_ioc(phy_info->phy); ++ if (!port) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, fw_id, __LINE__)); ++ return; ++ } ++ port_info = phy_info->portinfo; ++ phy_info_parent = port_info->phy_info; ++ for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { ++ if(!phy_info_parent->phy) ++ continue; ++ if (phy_info_parent->attached.sas_address != ++ sas_address) ++ continue; ++ dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, ++ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ++ ioc->name, phy_info_parent->phy_id, ++ phy_info_parent->phy); ++ sas_port_delete_phy(port, phy_info_parent->phy); ++ } ++ ++ dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT ++ "delete port %d, sas_addr (0x%llx)\n", ioc->name, ++ port->port_identifier, (unsigned long long)sas_address); ++ sas_port_delete(port); ++// mptsas_port_delete(ioc, phy_info->port_details); ++} + +- if (phy_info->sas_port_add_phy) { ++struct mptsas_phyinfo * ++mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, struct mptsas_devinfo *sas_device) ++{ ++ struct mptsas_phyinfo *phy_info; ++ struct mptsas_portinfo *port_info; ++ int i; + +- if (!port) { +- port = sas_port_alloc_num(dev); +- if (!port) { +- error = -ENOMEM; +- goto out; +- } +- error = sas_port_add(port); +- if (error) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- goto out; +- } +- mptsas_set_port(ioc, phy_info, port); +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "sas_port_alloc: port=%p dev=%p port_id=%d\n", +- ioc->name, port, dev, port->port_identifier)); +- } +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n", +- ioc->name, phy_info->phy_id)); +- sas_port_add_phy(port, phy_info->phy); +- phy_info->sas_port_add_phy = 0; ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ sas_device->sas_address); ++ if (!phy_info) ++ goto out; ++ port_info = phy_info->portinfo; ++ if (!port_info) ++ goto out; ++ mutex_lock(&ioc->sas_topology_mutex); ++ for (i = 0; i < port_info->num_phys; i++) { ++ if(port_info->phy_info[i].attached.sas_address != ++ sas_device->sas_address) ++ continue; ++ port_info->phy_info[i].attached.channel = sas_device->channel; ++ port_info->phy_info[i].attached.id = sas_device->id; ++ port_info->phy_info[i].attached.sas_address = ++ sas_device->sas_address; ++ port_info->phy_info[i].attached.handle = sas_device->handle; ++ port_info->phy_info[i].attached.handle_parent = ++ sas_device->handle_parent; ++ port_info->phy_info[i].attached.handle_enclosure = ++ sas_device->handle_enclosure; + } ++ mutex_unlock(&ioc->sas_topology_mutex); ++ out: ++ return phy_info; ++} + +- if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { +- +- struct sas_rphy *rphy; +- struct device *parent; +- struct sas_identify identify; + +- parent = dev->parent->parent; +- /* +- * Let the hotplug_work thread handle processing +- * the adding/removing of devices that occur +- * after start of day. +- */ +- if (ioc->sas_discovery_runtime && +- mptsas_is_end_device(&phy_info->attached)) +- goto out; ++/** ++ * mptsas_hotplug_work - Work queue thread to handle SAS hotplug events ++ * ++ * ++ **/ ++static void ++mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, ++ struct mptsas_hotplug_event *hot_plug_info) ++{ ++ struct mptsas_phyinfo *phy_info; ++ struct scsi_target * starget; ++ struct mptsas_devinfo sas_device; ++ VirtTarget *vtarget; ++ enum device_state state; ++ int i; + +- mptsas_parse_device_info(&identify, &phy_info->attached); +- if (scsi_is_host_device(parent)) { +- struct mptsas_portinfo *port_info; +- int i; ++ switch (hot_plug_info->event_type) { + +- mutex_lock(&ioc->sas_topology_mutex); +- port_info = mptsas_get_hba_portinfo(ioc); +- mutex_unlock(&ioc->sas_topology_mutex); ++ case MPTSAS_ADD_PHYSDISK: + +- for (i = 0; i < port_info->num_phys; i++) +- if (port_info->phy_info[i].identify.sas_address == +- identify.sas_address) { +- sas_port_mark_backlink(port); +- goto out; +- } ++ if (!ioc->raid_data.pIocPg2) ++ break; + +- } else if (scsi_is_sas_rphy(parent)) { +- struct sas_rphy *parent_rphy = dev_to_rphy(parent); +- if (identify.sas_address == +- parent_rphy->identify.sas_address) { +- sas_port_mark_backlink(port); +- goto out; ++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { ++ if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == ++ hot_plug_info->id) { ++ printk(MYIOC_s_WARN_FMT "firmware bug: unable " ++ "to add hidden disk - target_id matchs " ++ "volume_id\n", ioc->name); ++ mptsas_free_fw_event(ioc, fw_event); ++ return; + } + } + +- switch (identify.device_type) { +- case SAS_END_DEVICE: +- rphy = sas_end_device_alloc(port); +- break; +- case SAS_EDGE_EXPANDER_DEVICE: +- case SAS_FANOUT_EXPANDER_DEVICE: +- rphy = sas_expander_alloc(port, identify.device_type); ++ case MPTSAS_ADD_DEVICE: ++ memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); ++ mptsas_sas_device_pg0(ioc, &sas_device, ++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ (hot_plug_info->channel << 8) + ++ hot_plug_info->id); ++ ++ if (!sas_device.handle) ++ return; ++ ++ phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); ++ if (!phy_info) + break; +- default: +- rphy = NULL; ++ ++ if (mptsas_get_rphy(phy_info)) + break; +- } +- if (!rphy) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- goto out; +- } + +- rphy->identify = identify; +- error = sas_rphy_add(rphy); +- if (error) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- sas_rphy_free(rphy); +- goto out; ++ state = mptsas_test_unit_ready(ioc, phy_info->attached.channel, ++ phy_info->attached.id, fw_event->retries); ++ ++ if (state == DEVICE_RETRY && !ioc->fw_events_off) { ++ mptsas_requeue_fw_event(ioc, fw_event, 1000); ++ return; + } +- mptsas_set_rphy(ioc, phy_info, rphy); +- } + +- out: +- return error; +-} ++ if (state == DEVICE_READY) ++ mptsas_add_end_device(ioc, phy_info); ++ break; + +-static int +-mptsas_probe_hba_phys(MPT_ADAPTER *ioc) +-{ +- struct mptsas_portinfo *port_info, *hba; +- int error = -ENOMEM, i; ++ case MPTSAS_DEL_DEVICE: + +- hba = kzalloc(sizeof(*port_info), GFP_KERNEL); +- if (! hba) +- goto out; ++ if (!ioc->disable_hotplug_remove) { ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ hot_plug_info->sas_address); ++ mptsas_del_end_device(ioc, phy_info); ++ } ++ break; + +- error = mptsas_sas_io_unit_pg0(ioc, hba); +- if (error) +- goto out_free_port_info; ++ case MPTSAS_DEL_PHYSDISK: + +- mptsas_sas_io_unit_pg1(ioc); +- mutex_lock(&ioc->sas_topology_mutex); +- port_info = mptsas_get_hba_portinfo(ioc); +- if (!port_info) { +- port_info = hba; +- list_add_tail(&port_info->list, &ioc->sas_topology); +- } else { +- for (i = 0; i < hba->num_phys; i++) { +- port_info->phy_info[i].negotiated_link_rate = +- hba->phy_info[i].negotiated_link_rate; +- port_info->phy_info[i].handle = +- hba->phy_info[i].handle; +- port_info->phy_info[i].port_id = +- hba->phy_info[i].port_id; +- } +- kfree(hba->phy_info); +- kfree(hba); +- hba = NULL; +- } +- mutex_unlock(&ioc->sas_topology_mutex); +- for (i = 0; i < port_info->num_phys; i++) { +- mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], +- (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << +- MPI_SAS_PHY_PGAD_FORM_SHIFT), i); ++ mpt_findImVolumes(ioc); + +- mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, +- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), +- port_info->phy_info[i].handle); +- port_info->phy_info[i].identify.phy_id = +- port_info->phy_info[i].phy_id = i; +- if (port_info->phy_info[i].attached.handle) +- mptsas_sas_device_pg0(ioc, +- &port_info->phy_info[i].attached, +- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), +- port_info->phy_info[i].attached.handle); +- } ++ phy_info = mptsas_find_phyinfo_by_phys_disk_num( ++ ioc, hot_plug_info->phys_disk_num, hot_plug_info->channel, ++ hot_plug_info->id); ++ mptsas_del_end_device(ioc, phy_info); ++ break; + +- mptsas_setup_wide_ports(ioc, port_info); ++ case MPTSAS_ADD_PHYSDISK_REPROBE: + +- for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) +- mptsas_probe_one_phy(&ioc->sh->shost_gendev, +- &port_info->phy_info[i], ioc->sas_index, 1); ++ if (mptsas_sas_device_pg0(ioc, &sas_device, ++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ (hot_plug_info->channel << 8) + hot_plug_info->id)) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; ++ } + +- return 0; ++ phy_info = mptsas_find_phyinfo_by_sas_address( ++ ioc, sas_device.sas_address); + +- out_free_port_info: +- kfree(hba); +- out: +- return error; +-} ++ if (!phy_info){ ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; ++ } + +-static int +-mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) +-{ +- struct mptsas_portinfo *port_info, *p, *ex; +- struct device *parent; +- struct sas_rphy *rphy; +- int error = -ENOMEM, i, j; ++ starget = mptsas_get_starget(phy_info); ++ if (!starget) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; ++ } + +- ex = kzalloc(sizeof(*port_info), GFP_KERNEL); +- if (!ex) +- goto out; ++ vtarget = starget->hostdata; ++ if (!vtarget) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; ++ } + +- error = mptsas_sas_expander_pg0(ioc, ex, +- (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << +- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); +- if (error) +- goto out_free_port_info; ++ mpt_findImVolumes(ioc); + +- *handle = ex->phy_info[0].handle; ++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " ++ "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", ++ ioc->name, hot_plug_info->channel, hot_plug_info->id, ++ hot_plug_info->phys_disk_num, (unsigned long long) ++ sas_device.sas_address); ++ ++ vtarget->id = hot_plug_info->phys_disk_num; ++ vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; ++ phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; ++ mptsas_reprobe_target(starget, 1); ++ break; + +- mutex_lock(&ioc->sas_topology_mutex); +- port_info = mptsas_find_portinfo_by_handle(ioc, *handle); +- if (!port_info) { +- port_info = ex; +- list_add_tail(&port_info->list, &ioc->sas_topology); +- } else { +- for (i = 0; i < ex->num_phys; i++) { +- port_info->phy_info[i].handle = +- ex->phy_info[i].handle; +- port_info->phy_info[i].port_id = +- ex->phy_info[i].port_id; ++ case MPTSAS_DEL_PHYSDISK_REPROBE: ++ ++ if (mptsas_sas_device_pg0(ioc, &sas_device, ++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ (hot_plug_info->channel << 8) + hot_plug_info->id)) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ++ ioc->name, __FUNCTION__, ++ hot_plug_info->id, __LINE__)); ++ break; + } +- kfree(ex->phy_info); +- kfree(ex); +- ex = NULL; +- } +- mutex_unlock(&ioc->sas_topology_mutex); + +- for (i = 0; i < port_info->num_phys; i++) { +- mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], +- (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << +- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ sas_device.sas_address); ++ if (!phy_info) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; ++ } + +- if (port_info->phy_info[i].identify.handle) { +- mptsas_sas_device_pg0(ioc, +- &port_info->phy_info[i].identify, +- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), +- port_info->phy_info[i].identify.handle); +- port_info->phy_info[i].identify.phy_id = +- port_info->phy_info[i].phy_id; ++ starget = mptsas_get_starget(phy_info); ++ if (!starget) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; + } + +- if (port_info->phy_info[i].attached.handle) { +- mptsas_sas_device_pg0(ioc, +- &port_info->phy_info[i].attached, +- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), +- port_info->phy_info[i].attached.handle); +- port_info->phy_info[i].attached.phy_id = +- port_info->phy_info[i].phy_id; ++ vtarget = starget->hostdata; ++ if (!vtarget) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; + } +- } + +- parent = &ioc->sh->shost_gendev; +- for (i = 0; i < port_info->num_phys; i++) { +- mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry(p, &ioc->sas_topology, list) { +- for (j = 0; j < p->num_phys; j++) { +- if (port_info->phy_info[i].identify.handle != +- p->phy_info[j].attached.handle) +- continue; +- rphy = mptsas_get_rphy(&p->phy_info[j]); +- parent = &rphy->dev; +- } ++ if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: fw_id=%d exit at line=%d\n", ioc->name, ++ __FUNCTION__, hot_plug_info->id, __LINE__)); ++ break; + } +- mutex_unlock(&ioc->sas_topology_mutex); +- } + +- mptsas_setup_wide_ports(ioc, port_info); ++ mpt_findImVolumes(ioc); ++ ++ starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" ++ " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", ++ ioc->name, hot_plug_info->channel, hot_plug_info->id, ++ hot_plug_info->phys_disk_num, (unsigned long long) ++ sas_device.sas_address); ++ ++ vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; ++ vtarget->id = hot_plug_info->id; ++ phy_info->attached.phys_disk_num = ~0; ++ mptsas_reprobe_target(starget, 0); ++ mptsas_add_device_component_by_fw(ioc, ++ hot_plug_info->channel, hot_plug_info->id); ++ break; ++ ++ case MPTSAS_ADD_RAID: ++ ++ mpt_findImVolumes(ioc); ++ printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " ++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ++ hot_plug_info->id); ++ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ++ hot_plug_info->id, 0); ++ break; ++ ++ case MPTSAS_DEL_RAID: ++ ++ mpt_findImVolumes(ioc); ++ printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " ++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ++ hot_plug_info->id); ++ scsi_remove_device(hot_plug_info->sdev); ++ scsi_device_put(hot_plug_info->sdev); ++ break; + +- for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) +- mptsas_probe_one_phy(parent, &port_info->phy_info[i], +- ioc->sas_index, 0); ++ case MPTSAS_ADD_INACTIVE_VOLUME: + +- return 0; ++ mpt_findImVolumes(ioc); ++ mptsas_adding_inactive_raid_components(ioc, ++ hot_plug_info->channel, hot_plug_info->id); ++ break; + +- out_free_port_info: +- if (ex) { +- kfree(ex->phy_info); +- kfree(ex); ++ default: ++ break; + } +- out: +- return error; ++ ++ mptsas_free_fw_event(ioc, fw_event); + } + +-/* +- * mptsas_delete_expander_phys ++/** ++ * mptsas_send_sas_event + * + * +- * This will traverse topology, and remove expanders +- * that are no longer present +- */ ++ * @ioc ++ * @sas_event_data ++ * ++ **/ + static void +-mptsas_delete_expander_phys(MPT_ADAPTER *ioc) ++mptsas_send_sas_event(struct fw_event_work *fw_event) + { +- struct mptsas_portinfo buffer; +- struct mptsas_portinfo *port_info, *n, *parent; +- struct mptsas_phyinfo *phy_info; +- struct sas_port * port; +- int i; +- u64 expander_sas_address; ++ MPT_ADAPTER *ioc; ++ struct mptsas_hotplug_event hot_plug_info; ++ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; ++ u32 device_info; ++ u64 sas_address; + +- mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { ++ ioc = fw_event->ioc; ++ sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) ++ fw_event->event_data; ++ device_info = le32_to_cpu(sas_event_data->DeviceInfo); + +- if (port_info->phy_info && +- (!(port_info->phy_info[0].identify.device_info & +- MPI_SAS_DEVICE_INFO_SMP_TARGET))) +- continue; ++ if ((device_info & ++ (MPI_SAS_DEVICE_INFO_SSP_TARGET | ++ MPI_SAS_DEVICE_INFO_STP_TARGET | ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) { ++ mptsas_free_fw_event(ioc, fw_event); ++ return; ++ } + +- if (mptsas_sas_expander_pg0(ioc, &buffer, +- (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << +- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), +- port_info->phy_info[0].handle)) { ++ if (sas_event_data->ReasonCode == ++ MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { ++ mptbase_sas_persist_operation(ioc, ++ MPI_SAS_OP_CLEAR_NOT_PRESENT); ++ mptsas_free_fw_event(ioc, fw_event); ++ return; ++ } + +- /* +- * Obtain the port_info instance to the parent port +- */ +- parent = mptsas_find_portinfo_by_handle(ioc, +- port_info->phy_info[0].identify.handle_parent); ++ switch (sas_event_data->ReasonCode) { ++ case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: ++ case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: ++ memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); ++ hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); ++ hot_plug_info.channel = sas_event_data->Bus; ++ hot_plug_info.id = sas_event_data->TargetID; ++ hot_plug_info.phy_id = sas_event_data->PhyNum; ++ memcpy(&sas_address, &sas_event_data->SASAddress, ++ sizeof(u64)); ++ hot_plug_info.sas_address = le64_to_cpu(sas_address); ++ hot_plug_info.device_info = device_info; ++ if (sas_event_data->ReasonCode & ++ MPI_EVENT_SAS_DEV_STAT_RC_ADDED) ++ hot_plug_info.event_type = MPTSAS_ADD_DEVICE; ++ else ++ hot_plug_info.event_type = MPTSAS_DEL_DEVICE; ++ mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); ++ break; ++ ++ case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: ++ mptbase_sas_persist_operation(ioc, ++ MPI_SAS_OP_CLEAR_NOT_PRESENT); ++ mptsas_free_fw_event(ioc, fw_event); ++ break; + +- if (!parent) +- goto next_port; ++ case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: ++ /* TODO */ ++ case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: ++ /* TODO */ ++ default: ++ mptsas_free_fw_event(ioc, fw_event); ++ break; ++ } ++} + +- expander_sas_address = +- port_info->phy_info[0].identify.sas_address; + +- /* +- * Delete rphys in the parent that point +- * to this expander. The transport layer will +- * cleanup all the children. +- */ +- phy_info = parent->phy_info; +- for (i = 0; i < parent->num_phys; i++, phy_info++) { +- port = mptsas_get_port(phy_info); +- if (!port) +- continue; +- if (phy_info->attached.sas_address != +- expander_sas_address) +- continue; +- dsaswideprintk(ioc, +- dev_printk(KERN_DEBUG, &port->dev, +- MYIOC_s_FMT "delete port (%d)\n", ioc->name, +- port->port_identifier)); +- sas_port_delete(port); +- mptsas_port_delete(ioc, phy_info->port_details); +- } +- next_port: +- +- phy_info = port_info->phy_info; +- for (i = 0; i < port_info->num_phys; i++, phy_info++) +- mptsas_port_delete(ioc, phy_info->port_details); +- +- list_del(&port_info->list); +- kfree(port_info->phy_info); +- kfree(port_info); ++/** ++ * mptsas_send_raid_event ++ * ++ * ++ * @ioc ++ * @raid_event_data ++ * ++ **/ ++static void ++mptsas_send_raid_event(struct fw_event_work *fw_event) ++{ ++ MPT_ADAPTER *ioc; ++ EVENT_DATA_RAID *raid_event_data; ++ struct mptsas_hotplug_event hot_plug_info; ++ int status; ++ int state; ++ struct scsi_device *sdev = NULL; ++ VirtDevice *vdevice = NULL; ++ RaidPhysDiskPage0_t phys_disk; ++ ++ ioc = fw_event->ioc; ++ raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; ++ status = le32_to_cpu(raid_event_data->SettingsStatus); ++ state = (status >> 8) & 0xff; ++ ++ memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); ++ hot_plug_info.id = raid_event_data->VolumeID; ++ hot_plug_info.channel = raid_event_data->VolumeBus; ++ hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; ++ ++ if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || ++ raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || ++ raid_event_data->ReasonCode == ++ MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { ++ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, ++ hot_plug_info.id, 0); ++ hot_plug_info.sdev = sdev; ++ if (sdev) ++ vdevice = sdev->hostdata; ++ } ++ ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: " ++ "ReasonCode=%02x\n", ioc->name, __FUNCTION__, ++ raid_event_data->ReasonCode)); ++ ++ switch (raid_event_data->ReasonCode) { ++ case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: ++ hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; ++ break; ++ case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: ++ hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; ++ break; ++ case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: ++ switch (state) { ++ case MPI_PD_STATE_ONLINE: ++ case MPI_PD_STATE_NOT_COMPATIBLE: ++ mpt_raid_phys_disk_pg0(ioc, ++ raid_event_data->PhysDiskNum, &phys_disk); ++ hot_plug_info.id = phys_disk.PhysDiskID; ++ hot_plug_info.channel = phys_disk.PhysDiskBus; ++ hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; ++ break; ++ case MPI_PD_STATE_FAILED: ++ case MPI_PD_STATE_MISSING: ++ case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: ++ case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: ++ case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: ++ hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; ++ break; ++ default: ++ break; + } +- /* +- * Free this memory allocated from inside +- * mptsas_sas_expander_pg0 +- */ +- kfree(buffer.phy_info); ++ break; ++ case MPI_EVENT_RAID_RC_VOLUME_DELETED: ++ if (!sdev) ++ break; ++ vdevice->vtarget->deleted = 1; /* block IO */ ++ hot_plug_info.event_type = MPTSAS_DEL_RAID; ++ break; ++ case MPI_EVENT_RAID_RC_VOLUME_CREATED: ++ if (sdev) { ++ scsi_device_put(sdev); ++ break; ++ } ++ hot_plug_info.event_type = MPTSAS_ADD_RAID; ++ break; ++ case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: ++ if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { ++ if (!sdev) ++ break; ++ vdevice->vtarget->deleted = 1; /* block IO */ ++ hot_plug_info.event_type = MPTSAS_DEL_RAID; ++ break; ++ } ++ switch (state) { ++ case MPI_RAIDVOL0_STATUS_STATE_FAILED: ++ case MPI_RAIDVOL0_STATUS_STATE_MISSING: ++ if (!sdev) ++ break; ++ vdevice->vtarget->deleted = 1; /* block IO */ ++ hot_plug_info.event_type = MPTSAS_DEL_RAID; ++ break; ++ case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: ++ case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: ++ if (sdev) { ++ scsi_device_put(sdev); ++ break; ++ } ++ hot_plug_info.event_type = MPTSAS_ADD_RAID; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; + } +- mutex_unlock(&ioc->sas_topology_mutex); ++ ++ if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) ++ mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); ++ else ++ mptsas_free_fw_event(ioc, fw_event); + } + +-/* +- * Start of day discovery +- */ +-static void +-mptsas_scan_sas_topology(MPT_ADAPTER *ioc) ++/** ++ * mptsas_issue_tm - send mptsas internal tm request ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @type ++ * @channel ++ * @id ++ * @lun ++ * @task_context ++ * @timeout ++ * ++ * return: ++ * ++ **/ ++static int ++mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, int task_context, ulong timeout, ++ u8 *issue_reset) + { +- u32 handle = 0xFFFF; +- int i; ++ MPT_FRAME_HDR *mf; ++ SCSITaskMgmt_t *pScsiTm; ++ int retval; ++ unsigned long timeleft; + +- mutex_lock(&ioc->sas_discovery_mutex); +- mptsas_probe_hba_phys(ioc); +- while (!mptsas_probe_expander_phys(ioc, &handle)) +- ; +- /* +- Reporting RAID volumes. +- */ +- if (!ioc->ir_firmware) ++ *issue_reset = 0; ++ if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) { ++ retval = -1; /* return failure */ ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " ++ "msg frames!!\n", ioc->name)); + goto out; +- if (!ioc->raid_data.pIocPg2) ++ } ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " ++ "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " ++ "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, ++ type, timeout, channel, id, (unsigned long long)lun, ++ task_context)); ++ ++ pScsiTm = (SCSITaskMgmt_t *) mf; ++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); ++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; ++ pScsiTm->TaskType = type; ++ pScsiTm->MsgFlags = 0; ++ pScsiTm->TargetID = id; ++ pScsiTm->Bus = channel; ++ pScsiTm->ChainOffset = 0; ++ pScsiTm->Reserved = 0; ++ pScsiTm->Reserved1 = 0; ++ pScsiTm->TaskMsgContext = task_context; ++ int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); ++ ++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status) ++ retval = 0; ++ mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); ++ ++ /* Now wait for the command to complete */ ++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, ++ timeout*HZ); ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ retval = -1; /* return failure */ ++ dtmprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); ++ mpt_free_msg_frame(ioc, mf); ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out; ++ *issue_reset = 1; + goto out; +- if (!ioc->raid_data.pIocPg2->NumActiveVolumes) ++ } ++ ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ retval = -1; /* return failure */ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt request: failed with no reply\n", ioc->name)); + goto out; +- for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { +- scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, +- ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); + } ++ + out: +- mutex_unlock(&ioc->sas_discovery_mutex); ++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ return retval; + } + +-/* +- * Work queue thread to handle Runtime discovery +- * Mere purpose is the hot add/delete of expanders +- *(Mutex UNLOCKED) +- */ ++/** ++ * mptsas_broadcast_primative_work - Work queue thread to handle ++ * broadcast primitive events ++ * @work: work queue payload containing info describing the event ++ * ++ **/ + static void +-__mptsas_discovery_work(MPT_ADAPTER *ioc) ++mptsas_broadcast_primative_work(struct fw_event_work *fw_event) + { +- u32 handle = 0xFFFF; ++ MPT_ADAPTER *ioc = fw_event->ioc; ++ MPT_FRAME_HDR *mf; ++ VirtDevice *vdevice; ++ int ii; ++ struct scsi_cmnd *sc; ++ SCSITaskMgmtReply_t * pScsiTmReply; ++ u8 issue_reset; ++ int task_context; ++ u8 channel, id; ++ int lun; ++ u32 termination_count; ++ u32 query_count; ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s - enter\n", ioc->name, __FUNCTION__)); ++ ++ mutex_lock(&ioc->taskmgmt_cmds.mutex); ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ mptsas_requeue_fw_event(ioc, fw_event, 1000); ++ return; ++ } + +- ioc->sas_discovery_runtime=1; +- mptsas_delete_expander_phys(ioc); +- mptsas_probe_hba_phys(ioc); +- while (!mptsas_probe_expander_phys(ioc, &handle)) +- ; +- ioc->sas_discovery_runtime=0; ++ issue_reset = 0; ++ termination_count = 0; ++ query_count = 0; ++ mpt_findImVolumes(ioc); ++ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; ++ ++ for (ii = 0; ii < ioc->req_depth; ii++) { ++ sc = mptscsih_get_scsi_lookup(ioc, ii); ++ if (!sc) ++ continue; ++ mf = MPT_INDEX_2_MFPTR(ioc, ii); ++ if (!mf) ++ continue; ++ task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; ++ vdevice = sc->device->hostdata; ++ if (!vdevice || !vdevice->vtarget) ++ continue; ++ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) ++ continue; /* skip hidden raid components */ ++ if (vdevice->vtarget->raidVolume) ++ continue; /* skip hidden raid components */ ++ channel = vdevice->vtarget->channel; ++ id = vdevice->vtarget->id; ++ lun = vdevice->lun; ++ if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, ++ channel, id, (u64)lun, task_context, 30, &issue_reset)) ++ goto out; ++ query_count++; ++ termination_count += ++ le32_to_cpu(pScsiTmReply->TerminationCount); ++ if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && ++ (pScsiTmReply->ResponseCode == ++ MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || ++ pScsiTmReply->ResponseCode == ++ MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) ++ continue; ++ if (mptsas_issue_tm(ioc, ++ MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, ++ channel, id, (u64)lun, 0, 30, &issue_reset)) ++ goto out; ++ termination_count += ++ le32_to_cpu(pScsiTmReply->TerminationCount); ++ } ++ ++ out: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s - exit, query_count = %d termination_count = %d\n", ++ ioc->name, __FUNCTION__, query_count, termination_count)); ++ ++ ioc->broadcast_aen_busy = 0; ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ ++ if (issue_reset) { ++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP)) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ } ++ mptsas_free_fw_event(ioc, fw_event); + } + +-/* +- * Work queue thread to handle Runtime discovery +- * Mere purpose is the hot add/delete of expanders +- *(Mutex LOCKED) +- */ ++/** ++ * mptsas_send_ir2_event - handle exposing hidden disk when an inactive raid volume is added ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @ir2_data: ++ * ++ **/ + static void +-mptsas_discovery_work(struct work_struct *work) ++mptsas_send_ir2_event(struct fw_event_work *fw_event) + { +- struct mptsas_discovery_event *ev = +- container_of(work, struct mptsas_discovery_event, work); +- MPT_ADAPTER *ioc = ev->ioc; +- +- mutex_lock(&ioc->sas_discovery_mutex); +- __mptsas_discovery_work(ioc); +- mutex_unlock(&ioc->sas_discovery_mutex); +- kfree(ev); ++ MPT_ADAPTER *ioc; ++ struct mptsas_hotplug_event hot_plug_info; ++ MPI_EVENT_DATA_IR2 * ir2_data; ++ u8 reasonCode; ++ RaidPhysDiskPage0_t phys_disk; ++ ++ ioc = fw_event->ioc; ++ ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; ++ reasonCode = ir2_data->ReasonCode; ++ ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: " ++ "ReasonCode=%02x\n", ioc->name,__FUNCTION__, reasonCode)); ++ ++ memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); ++ hot_plug_info.id = ir2_data->TargetID; ++ hot_plug_info.channel = ir2_data->Bus; ++ switch (reasonCode) { ++ case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: ++ hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; ++ break; ++ case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: ++ hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; ++ hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; ++ break; ++ case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: ++ hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; ++ mpt_raid_phys_disk_pg0(ioc, ++ ir2_data->PhysDiskNum, &phys_disk); ++ hot_plug_info.id = phys_disk.PhysDiskID; ++ hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; ++ break; ++ default: ++ mptsas_free_fw_event(ioc, fw_event); ++ return; ++ } ++ mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); + } + +-static struct mptsas_phyinfo * +-mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) ++static void ++mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) + { +- struct mptsas_portinfo *port_info; +- struct mptsas_phyinfo *phy_info = NULL; +- int i; ++ struct mptsas_portinfo *parent; ++ struct device *parent_dev; ++ struct sas_rphy *rphy; ++ int i; ++ u64 sas_address; /* expander sas address */ ++ u32 handle; + +- mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry(port_info, &ioc->sas_topology, list) { +- for (i = 0; i < port_info->num_phys; i++) { +- if (!mptsas_is_end_device( +- &port_info->phy_info[i].attached)) +- continue; +- if (port_info->phy_info[i].attached.sas_address +- != sas_address) +- continue; +- phy_info = &port_info->phy_info[i]; +- break; +- } +- } +- mutex_unlock(&ioc->sas_topology_mutex); +- return phy_info; +-} ++ handle = port_info->phy_info[0].handle; ++ sas_address = port_info->phy_info[0].identify.sas_address; ++ for (i = 0; i < port_info->num_phys; i++) { ++ mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], ++ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << ++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); + +-static struct mptsas_phyinfo * +-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) +-{ +- struct mptsas_portinfo *port_info; +- struct mptsas_phyinfo *phy_info = NULL; +- int i; ++ mptsas_sas_device_pg0(ioc, ++ &port_info->phy_info[i].identify, ++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ port_info->phy_info[i].identify.handle); ++ port_info->phy_info[i].identify.phy_id = ++ port_info->phy_info[i].phy_id; + +- mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry(port_info, &ioc->sas_topology, list) { +- for (i = 0; i < port_info->num_phys; i++) { +- if (!mptsas_is_end_device( +- &port_info->phy_info[i].attached)) +- continue; +- if (port_info->phy_info[i].attached.id != id) +- continue; +- if (port_info->phy_info[i].attached.channel != channel) +- continue; +- phy_info = &port_info->phy_info[i]; +- break; ++ if (port_info->phy_info[i].attached.handle) { ++ mptsas_sas_device_pg0(ioc, ++ &port_info->phy_info[i].attached, ++ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ port_info->phy_info[i].attached.handle); ++ port_info->phy_info[i].attached.phy_id = ++ port_info->phy_info[i].phy_id; + } + } +- mutex_unlock(&ioc->sas_topology_mutex); +- return phy_info; +-} +- +-static struct mptsas_phyinfo * +-mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) +-{ +- struct mptsas_portinfo *port_info; +- struct mptsas_phyinfo *phy_info = NULL; +- int i; + + mutex_lock(&ioc->sas_topology_mutex); +- list_for_each_entry(port_info, &ioc->sas_topology, list) { +- for (i = 0; i < port_info->num_phys; i++) { +- if (!mptsas_is_end_device( +- &port_info->phy_info[i].attached)) +- continue; +- if (port_info->phy_info[i].attached.phys_disk_num == ~0) +- continue; +- if (port_info->phy_info[i].attached.phys_disk_num != id) +- continue; +- if (port_info->phy_info[i].attached.channel != channel) +- continue; +- phy_info = &port_info->phy_info[i]; +- break; ++ parent = mptsas_find_portinfo_by_handle(ioc, ++ port_info->phy_info[0].identify.handle_parent); ++ if (!parent) { ++ mutex_unlock(&ioc->sas_topology_mutex); ++ return; ++ } ++ for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; ++ i++) { ++ if (parent->phy_info[i].attached.sas_address == sas_address) { ++ rphy = mptsas_get_rphy(&parent->phy_info[i]); ++ parent_dev = &rphy->dev; + } + } + mutex_unlock(&ioc->sas_topology_mutex); +- return phy_info; ++ ++ mptsas_setup_wide_ports(ioc, port_info); ++ for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) ++ mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], ++ ioc->sas_index, 0); + } + +-/* +- * Work queue thread to clear the persitency table +- */ + static void +-mptsas_persist_clear_table(struct work_struct *work) ++mptsas_expander_event_add(MPT_ADAPTER *ioc, ++ MpiEventDataSasExpanderStatusChange_t* expander_data) + { +- MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); ++ struct mptsas_portinfo *port_info; ++ int i; ++ __le64 sas_address; + +- mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); +-} ++ port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); ++ if (!port_info) ++ BUG(); ++ port_info->num_phys = (expander_data->NumPhys) ? ++ expander_data->NumPhys : 1; ++ port_info->phy_info = kcalloc(port_info->num_phys, ++ sizeof(struct mptsas_phyinfo),GFP_KERNEL); ++ if (!port_info->phy_info) ++ BUG(); ++ memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); ++ for (i = 0; i < port_info->num_phys; i++) { ++ port_info->phy_info[i].portinfo = port_info; ++ port_info->phy_info[i].handle = ++ le16_to_cpu(expander_data->DevHandle); ++ port_info->phy_info[i].identify.sas_address = ++ le64_to_cpu(sas_address); ++ port_info->phy_info[i].identify.handle_parent = ++ le16_to_cpu(expander_data->ParentDevHandle); ++ } + +-static void +-mptsas_reprobe_lun(struct scsi_device *sdev, void *data) +-{ +- int rc; ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_add_tail(&port_info->list, &ioc->sas_topology); ++ mutex_unlock(&ioc->sas_topology_mutex); + +- sdev->no_uld_attach = data ? 1 : 0; +- rc = scsi_device_reprobe(sdev); +-} ++ printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " ++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, ++ (unsigned long long)sas_address); + +-static void +-mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) +-{ +- starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, +- mptsas_reprobe_lun); ++ mptsas_expander_refresh(ioc, port_info); + } + ++/** ++ * mptsas_delete_expander_siblings - remove siblings attached to expander ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @parent: the parent port_info object ++ * @expander: the expander port_info object ++ **/ + static void +-mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) ++mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo ++ *parent, struct mptsas_portinfo *expander) + { +- CONFIGPARMS cfg; +- ConfigPageHeader_t hdr; +- dma_addr_t dma_handle; +- pRaidVolumePage0_t buffer = NULL; +- RaidPhysDiskPage0_t phys_disk; +- int i; +- struct mptsas_hotplug_event *ev; ++ struct mptsas_phyinfo *phy_info; ++ struct mptsas_portinfo *port_info; ++ struct sas_rphy *rphy; ++ int i; + +- memset(&cfg, 0 , sizeof(CONFIGPARMS)); +- memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); +- hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; +- cfg.pageAddr = (channel << 8) + id; +- cfg.cfghdr.hdr = &hdr; +- cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; ++ phy_info = expander->phy_info; ++ for (i = 0; i < expander->num_phys; i++, phy_info++) { ++ if (!(rphy = mptsas_get_rphy(phy_info))) ++ continue; ++ if (rphy->identify.device_type == SAS_END_DEVICE) ++ mptsas_del_end_device(ioc, phy_info); ++ } + +- if (mpt_config(ioc, &cfg) != 0) +- goto out; ++ phy_info = expander->phy_info; ++ for (i = 0; i < expander->num_phys; i++, phy_info++) { ++ if (!(rphy = mptsas_get_rphy(phy_info))) ++ continue; ++ if (rphy->identify.device_type == ++ MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || ++ rphy->identify.device_type == ++ MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { ++ port_info = mptsas_find_portinfo_by_sas_address(ioc, ++ rphy->identify.sas_address); ++ if (!port_info) ++ continue; ++ if (port_info == parent) /* backlink rphy */ ++ continue; ++ mptsas_expander_delete(ioc, port_info); ++ } ++ } ++} + +- if (!hdr.PageLength) +- goto out; + +- buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, +- &dma_handle); ++/** ++ * mptsas_expander_delete - remove this expander ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @port_info: expander port_info struct ++ * ++ **/ + +- if (!buffer) +- goto out; ++static void ++mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) ++{ + +- cfg.physAddr = dma_handle; +- cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; ++ struct mptsas_portinfo *parent; ++ int i; ++ u64 expander_sas_address; ++ struct mptsas_phyinfo *phy_info; ++ struct mptsas_portinfo buffer; ++ struct mptsas_portinfo_details * port_details; ++ struct sas_port * port; + +- if (mpt_config(ioc, &cfg) != 0) +- goto out; ++ if (!port_info) ++ return; + +- if (!(buffer->VolumeStatus.Flags & +- MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) +- goto out; ++ /* see if expander is still there before deleting */ ++ mptsas_sas_expander_pg0(ioc, &buffer, ++ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << ++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), ++ port_info->phy_info[0].identify.handle); + +- if (!buffer->NumPhysDisks) +- goto out; ++ if (buffer.num_phys) { ++ kfree(buffer.phy_info); ++ return; ++ } + +- for (i = 0; i < buffer->NumPhysDisks; i++) { + +- if (mpt_raid_phys_disk_pg0(ioc, +- buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) +- continue; ++ /* ++ * Obtain the port_info instance to the parent port ++ */ ++ port_details = NULL; ++ expander_sas_address = ++ port_info->phy_info[0].identify.sas_address; ++ parent = mptsas_find_portinfo_by_handle(ioc, ++ port_info->phy_info[0].identify.handle_parent); ++ mptsas_delete_expander_siblings(ioc, parent, port_info); ++ if (!parent) ++ goto out; + +- ev = kzalloc(sizeof(*ev), GFP_ATOMIC); +- if (!ev) { +- printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); +- goto out; ++ /* ++ * Delete rphys in the parent that point ++ * to this expander. ++ */ ++ phy_info = parent->phy_info; ++ port = NULL; ++ for (i = 0; i < parent->num_phys; i++, phy_info++) { ++ if(!phy_info->phy) ++ continue; ++ if (phy_info->attached.sas_address != ++ expander_sas_address) ++ continue; ++ if (!port) { ++ port = mptsas_get_port(phy_info); ++ port_details = phy_info->port_details; + } +- +- INIT_WORK(&ev->work, mptsas_hotplug_work); +- ev->ioc = ioc; +- ev->id = phys_disk.PhysDiskID; +- ev->channel = phys_disk.PhysDiskBus; +- ev->phys_disk_num_valid = 1; +- ev->phys_disk_num = phys_disk.PhysDiskNum; +- ev->event_type = MPTSAS_ADD_DEVICE; +- schedule_work(&ev->work); ++ dev_printk(KERN_DEBUG, &phy_info->phy->dev, ++ MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, ++ phy_info->phy_id, phy_info->phy); ++ sas_port_delete_phy(port, phy_info->phy); ++ } ++ if (port) { ++ dev_printk(KERN_DEBUG, &port->dev, ++ MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", ++ ioc->name, port->port_identifier, ++ (unsigned long long)expander_sas_address); ++ sas_port_delete(port); ++ mptsas_port_delete(ioc, port_details); + } +- + out: +- if (buffer) +- pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, +- dma_handle); ++ ++ printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " ++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, ++ (unsigned long long)expander_sas_address); ++ ++ /* ++ * free link ++ */ ++ list_del(&port_info->list); ++ kfree(port_info->phy_info); ++ kfree(port_info); + } +-/* +- * Work queue thread to handle SAS hotplug events ++ ++ ++/** ++ * mptsas_send_expander_event - expanders events ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @expander_data: event data ++ * ++ * ++ * This function handles adding, removing, and refreshing ++ * device handles within the expander objects. + */ + static void +-mptsas_hotplug_work(struct work_struct *work) ++mptsas_send_expander_event(struct fw_event_work *fw_event) + { +- struct mptsas_hotplug_event *ev = +- container_of(work, struct mptsas_hotplug_event, work); ++ MPT_ADAPTER *ioc; ++ MpiEventDataSasExpanderStatusChange_t* expander_data; ++ struct mptsas_portinfo *port_info; ++ __le64 sas_address; ++ int i; + +- MPT_ADAPTER *ioc = ev->ioc; +- struct mptsas_phyinfo *phy_info; +- struct sas_rphy *rphy; +- struct sas_port *port; +- struct scsi_device *sdev; +- struct scsi_target * starget; +- struct sas_identify identify; +- char *ds = NULL; +- struct mptsas_devinfo sas_device; +- VirtTarget *vtarget; +- VirtDevice *vdevice; ++ ioc = fw_event->ioc; ++ expander_data = (MpiEventDataSasExpanderStatusChange_t *) ++ fw_event->event_data; ++ memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); ++ port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); ++ ++ if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { ++ if (port_info) { ++ for (i = 0; i < port_info->num_phys; i++) { ++ port_info->phy_info[i].portinfo = port_info; ++ port_info->phy_info[i].handle = ++ le16_to_cpu(expander_data->DevHandle); ++ port_info->phy_info[i].identify.sas_address = ++ le64_to_cpu(sas_address); ++ port_info->phy_info[i].identify.handle_parent = ++ le16_to_cpu(expander_data->ParentDevHandle); ++ } ++ mptsas_expander_refresh(ioc, port_info); ++ } else if (!port_info && expander_data->NumPhys) ++ mptsas_expander_event_add(ioc, expander_data); ++ } else if (expander_data->ReasonCode == ++ MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) ++ mptsas_expander_delete(ioc, port_info); + +- mutex_lock(&ioc->sas_discovery_mutex); +- switch (ev->event_type) { +- case MPTSAS_DEL_DEVICE: ++ mptsas_free_fw_event(ioc, fw_event); ++} + +- phy_info = NULL; +- if (ev->phys_disk_num_valid) { +- if (ev->hidden_raid_component){ +- if (mptsas_sas_device_pg0(ioc, &sas_device, +- (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), +- (ev->channel << 8) + ev->id)) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } +- phy_info = mptsas_find_phyinfo_by_sas_address( +- ioc, sas_device.sas_address); +- }else +- phy_info = mptsas_find_phyinfo_by_phys_disk_num( +- ioc, ev->channel, ev->phys_disk_num); +- } + +- if (!phy_info) +- phy_info = mptsas_find_phyinfo_by_target(ioc, +- ev->channel, ev->id); ++/** ++ * mptsas_expander_add - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @handle: ++ * ++ */ ++struct mptsas_portinfo * ++mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) ++{ ++ struct mptsas_portinfo buffer, *port_info; ++ int i; + +- /* +- * Sanity checks, for non-existing phys and remote rphys. +- */ +- if (!phy_info){ +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } +- if (!phy_info->port_details) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } +- rphy = mptsas_get_rphy(phy_info); +- if (!rphy) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } ++ if ((mptsas_sas_expander_pg0(ioc, &buffer, ++ (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << ++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) ++ return NULL; + +- port = mptsas_get_port(phy_info); +- if (!port) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } ++ port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); ++ if (!port_info) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: exit at line=%d\n", ioc->name, ++ __FUNCTION__, __LINE__)); ++ return NULL; ++ } ++ port_info->num_phys = buffer.num_phys; ++ port_info->phy_info = buffer.phy_info; ++ for (i = 0; i < port_info->num_phys; i++) ++ port_info->phy_info[i].portinfo = port_info; ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_add_tail(&port_info->list, &ioc->sas_topology); ++ mutex_unlock(&ioc->sas_topology_mutex); ++ printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " ++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, ++ (unsigned long long)buffer.phy_info[0].identify.sas_address); ++ mptsas_expander_refresh(ioc, port_info); ++ return port_info; ++} + +- starget = mptsas_get_starget(phy_info); +- if (starget) { +- vtarget = starget->hostdata; ++static void ++mptsas_send_link_status_event(struct fw_event_work *fw_event) ++{ ++ MPT_ADAPTER *ioc; ++ MpiEventDataSasPhyLinkStatus_t *link_data; ++ struct mptsas_portinfo *port_info; ++ struct mptsas_phyinfo *phy_info = NULL; ++ __le64 sas_address; ++ u8 phy_num; ++ u8 link_rate; + +- if (!vtarget) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } ++ ioc = fw_event->ioc; ++ link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; + +- /* +- * Handling RAID components +- */ +- if (ev->phys_disk_num_valid && +- ev->hidden_raid_component) { +- printk(MYIOC_s_INFO_FMT +- "RAID Hidding: channel=%d, id=%d, " +- "physdsk %d \n", ioc->name, ev->channel, +- ev->id, ev->phys_disk_num); +- vtarget->id = ev->phys_disk_num; +- vtarget->tflags |= +- MPT_TARGET_FLAGS_RAID_COMPONENT; +- mptsas_reprobe_target(starget, 1); +- phy_info->attached.phys_disk_num = +- ev->phys_disk_num; +- break; ++ memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); ++ sas_address = le64_to_cpu(sas_address); ++ link_rate = link_data->LinkRates >> 4; ++ phy_num = link_data->PhyNum; ++ ++ port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); ++ if (port_info) { ++ phy_info = &port_info->phy_info[phy_num]; ++ if (phy_info) ++ phy_info->negotiated_link_rate = link_rate; ++ } ++ ++ if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || ++ link_rate == MPI_SAS_IOUNIT0_RATE_3_0) { ++ ++ if (!port_info) { ++ if (ioc->old_sas_discovery_protocal) { ++ port_info = mptsas_expander_add(ioc, ++ le16_to_cpu(link_data->DevHandle)); ++ if (port_info) ++ goto out; + } ++ goto out; + } ++ if (port_info == ioc->hba_port_info) ++ mptsas_probe_hba_phys(ioc); ++ else ++ mptsas_expander_refresh(ioc, port_info); ++ } else if (phy_info && phy_info->phy) { ++ if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) ++ phy_info->phy->negotiated_linkrate = ++ SAS_PHY_DISABLED; ++ else if (link_rate == ++ MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) ++ phy_info->phy->negotiated_linkrate = ++ SAS_LINK_RATE_FAILED; ++ else ++ phy_info->phy->negotiated_linkrate = ++ SAS_LINK_RATE_UNKNOWN; ++ } ++ out: ++ mptsas_free_fw_event(ioc, fw_event); ++} + +- if (phy_info->attached.device_info & +- MPI_SAS_DEVICE_INFO_SSP_TARGET) +- ds = "ssp"; +- if (phy_info->attached.device_info & +- MPI_SAS_DEVICE_INFO_STP_TARGET) +- ds = "stp"; +- if (phy_info->attached.device_info & +- MPI_SAS_DEVICE_INFO_SATA_DEVICE) +- ds = "sata"; +- +- printk(MYIOC_s_INFO_FMT +- "removing %s device, channel %d, id %d, phy %d\n", +- ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); +- dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT +- "delete port (%d)\n", ioc->name, port->port_identifier); +- sas_port_delete(port); +- mptsas_port_delete(ioc, phy_info->port_details); +- break; +- case MPTSAS_ADD_DEVICE: +- +- if (ev->phys_disk_num_valid) +- mpt_findImVolumes(ioc); + +- /* +- * Refresh sas device pg0 data +- */ +- if (mptsas_sas_device_pg0(ioc, &sas_device, +- (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), +- (ev->channel << 8) + ev->id)) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; ++static void ++mptsas_handle_queue_full_event(struct fw_event_work *fw_event) ++{ ++ MPT_ADAPTER *ioc; ++ EventDataQueueFull_t *qfull_data; ++ struct sas_device_info *sas_info; ++ struct scsi_device *sdev; ++ int depth; ++ int id = -1; ++ int channel = -1; ++ int fw_id, fw_channel; ++ u16 current_depth; ++ ++ ++ ioc = fw_event->ioc; ++ qfull_data = (EventDataQueueFull_t *)fw_event->event_data; ++ fw_id = qfull_data->TargetID; ++ fw_channel = qfull_data->Bus; ++ current_depth = le16_to_cpu(qfull_data->CurrentDepth); ++ ++ /* if hidden raid component, look for the volume id */ ++ down(&ioc->sas_device_info_mutex); ++ if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { ++ list_for_each_entry(sas_info, &ioc->sas_device_info_list, ++ list) { ++ if (sas_info->is_cached || ++ sas_info->is_logical_volume) ++ continue; ++ if (sas_info->is_hidden_raid_component && ++ (sas_info->fw.channel == fw_channel && ++ sas_info->fw.id == fw_id)) { ++ id = sas_info->volume_id; ++ channel = MPTSAS_RAID_CHANNEL; ++ goto out; ++ } + } +- +- __mptsas_discovery_work(ioc); +- +- phy_info = mptsas_find_phyinfo_by_sas_address(ioc, +- sas_device.sas_address); +- +- if (!phy_info || !phy_info->port_details) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; ++ } else { ++ list_for_each_entry(sas_info, &ioc->sas_device_info_list, ++ list) { ++ if (sas_info->is_cached || ++ sas_info->is_hidden_raid_component || ++ sas_info->is_logical_volume) ++ continue; ++ if (sas_info->fw.channel == fw_channel && ++ sas_info->fw.id == fw_id) { ++ id = sas_info->os.id; ++ channel = sas_info->os.channel; ++ goto out; ++ } + } + +- starget = mptsas_get_starget(phy_info); +- if (starget && (!ev->hidden_raid_component)){ +- +- vtarget = starget->hostdata; ++ } + +- if (!vtarget) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } +- /* +- * Handling RAID components +- */ +- if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { +- printk(MYIOC_s_INFO_FMT +- "RAID Exposing: channel=%d, id=%d, " +- "physdsk %d \n", ioc->name, ev->channel, +- ev->id, ev->phys_disk_num); +- vtarget->tflags &= +- ~MPT_TARGET_FLAGS_RAID_COMPONENT; +- vtarget->id = ev->id; +- mptsas_reprobe_target(starget, 0); +- phy_info->attached.phys_disk_num = ~0; ++ out: ++ up(&ioc->sas_device_info_mutex); ++ ++ if (id != -1) { ++ shost_for_each_device(sdev, ioc->sh) { ++ if (sdev->id == id && sdev->channel == channel) { ++ if (current_depth > sdev->queue_depth) { ++ sdev_printk(KERN_INFO, sdev, ++ "strange observation, the queue " ++ "depth is (%d) meanwhile fw queue " ++ "depth (%d)\n", sdev->queue_depth, ++ current_depth); ++ continue; ++ } ++ depth = scsi_track_queue_full(sdev, ++ current_depth - 1); ++ if (depth > 0) ++ sdev_printk(KERN_INFO, sdev, ++ "Queue depth reduced to (%d)\n", ++ depth); ++ else if (depth < 0) ++ sdev_printk(KERN_INFO, sdev, ++ "Tagged Command Queueing is being " ++ "disabled\n"); ++ else if (depth == 0) ++ sdev_printk(KERN_INFO, sdev, ++ "Queue depth not changed yet\n"); + } +- break; + } ++ } + +- if (mptsas_get_rphy(phy_info)) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- if (ev->channel) printk("%d\n", __LINE__); +- break; +- } ++ mptsas_free_fw_event(ioc, fw_event); ++} + +- port = mptsas_get_port(phy_info); +- if (!port) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; +- } +- memcpy(&phy_info->attached, &sas_device, +- sizeof(struct mptsas_devinfo)); ++/** ++ * mptsas_firmware_event_work - work thread for processing fw events ++ * @work: work queue payload containing info describing the event ++ * Context: user ++ * ++ */ ++static void ++mptsas_firmware_event_work(struct work_struct *work) ++{ ++ struct fw_event_work *fw_event = ++ container_of(work, struct fw_event_work, work.work); ++ MPT_ADAPTER *ioc = fw_event->ioc; ++ ++ /* special rescan topology handling */ ++ if (fw_event->event == -1) { ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: rescan after " ++ "reset\n", ioc->name,__FUNCTION__)); ++ mptsas_not_responding_devices(ioc); ++ mptsas_scan_sas_topology(ioc); ++ mptsas_free_fw_event(ioc, fw_event); ++ return; ++ } + +- if (phy_info->attached.device_info & +- MPI_SAS_DEVICE_INFO_SSP_TARGET) +- ds = "ssp"; +- if (phy_info->attached.device_info & +- MPI_SAS_DEVICE_INFO_STP_TARGET) +- ds = "stp"; +- if (phy_info->attached.device_info & +- MPI_SAS_DEVICE_INFO_SATA_DEVICE) +- ds = "sata"; +- +- printk(MYIOC_s_INFO_FMT +- "attaching %s device, channel %d, id %d, phy %d\n", +- ioc->name, ds, ev->channel, ev->id, ev->phy_id); ++ /* events handling turned off during host reset */ ++ if (ioc->fw_events_off) { ++ mptsas_free_fw_event(ioc, fw_event); ++ return; ++ } + +- mptsas_parse_device_info(&identify, &phy_info->attached); +- rphy = sas_end_device_alloc(port); +- if (!rphy) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- break; /* non-fatal: an rphy can be added later */ +- } ++ devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: fw_event=(0x%p), " ++ "event = (0x%02x)\n", ioc->name,__FUNCTION__, fw_event, ++ (fw_event->event & 0xFF))); + +- rphy->identify = identify; +- if (sas_rphy_add(rphy)) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT +- "%s: exit at line=%d\n", ioc->name, +- __func__, __LINE__)); +- sas_rphy_free(rphy); +- break; +- } +- mptsas_set_rphy(ioc, phy_info, rphy); ++ switch (fw_event->event) { ++ case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: ++ mptsas_send_sas_event(fw_event); + break; +- case MPTSAS_ADD_RAID: +- sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, +- ev->id, 0); +- if (sdev) { +- scsi_device_put(sdev); +- break; +- } +- printk(MYIOC_s_INFO_FMT +- "attaching raid volume, channel %d, id %d\n", +- ioc->name, MPTSAS_RAID_CHANNEL, ev->id); +- scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0); +- mpt_findImVolumes(ioc); ++ case MPI_EVENT_INTEGRATED_RAID: ++ mptsas_send_raid_event(fw_event); + break; +- case MPTSAS_DEL_RAID: +- sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, +- ev->id, 0); +- if (!sdev) +- break; +- printk(MYIOC_s_INFO_FMT +- "removing raid volume, channel %d, id %d\n", +- ioc->name, MPTSAS_RAID_CHANNEL, ev->id); +- vdevice = sdev->hostdata; +- scsi_remove_device(sdev); +- scsi_device_put(sdev); +- mpt_findImVolumes(ioc); ++ case MPI_EVENT_IR2: ++ mptsas_send_ir2_event(fw_event); + break; +- case MPTSAS_ADD_INACTIVE_VOLUME: +- mptsas_adding_inactive_raid_components(ioc, +- ev->channel, ev->id); ++ case MPI_EVENT_PERSISTENT_TABLE_FULL: ++ mptbase_sas_persist_operation(ioc, ++ MPI_SAS_OP_CLEAR_NOT_PRESENT); ++ mptsas_free_fw_event(ioc, fw_event); + break; +- case MPTSAS_IGNORE_EVENT: +- default: ++ case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: ++ mptsas_broadcast_primative_work(fw_event); ++ break; ++ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: ++ mptsas_send_expander_event(fw_event); ++ break; ++ case MPI_EVENT_SAS_PHY_LINK_STATUS: ++ mptsas_send_link_status_event(fw_event); ++ break; ++ case MPI_EVENT_QUEUE_FULL: ++ mptsas_handle_queue_full_event(fw_event); + break; + } +- +- mutex_unlock(&ioc->sas_discovery_mutex); +- kfree(ev); + } + +-static void +-mptsas_send_sas_event(MPT_ADAPTER *ioc, +- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) +-{ +- struct mptsas_hotplug_event *ev; +- u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); +- __le64 sas_address; + +- if ((device_info & +- (MPI_SAS_DEVICE_INFO_SSP_TARGET | +- MPI_SAS_DEVICE_INFO_STP_TARGET | +- MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) +- return; ++/** ++ * mptsas_event_process - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @reply: ++ * ++ **/ ++static int ++mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) ++{ ++ u32 event = le32_to_cpu(reply->Event); ++ int sz, event_data_sz; ++ struct fw_event_work *fw_event; ++ unsigned long delay; + +- switch (sas_event_data->ReasonCode) { +- case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: ++ /* events turned off due to host reset or driver unloading */ ++ if (ioc->fw_events_off) ++ return 0; + +- mptsas_target_reset_queue(ioc, sas_event_data); ++ delay = msecs_to_jiffies(1); ++ switch (event) { ++ case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: ++ { ++ EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = ++ (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; ++ if (broadcast_event_data->Primitive != ++ MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) ++ return 0; ++ if (ioc->broadcast_aen_busy) ++ return 0; ++ ioc->broadcast_aen_busy = 1; + break; ++ } ++ case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: ++ { ++ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = ++ (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; + +- case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: +- ev = kzalloc(sizeof(*ev), GFP_ATOMIC); +- if (!ev) { +- printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); +- break; ++ if (sas_event_data->ReasonCode == ++ MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { ++ mptsas_target_reset_queue(ioc, sas_event_data); ++ return 0; + } ++ break; ++ } ++ case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: ++ { ++ MpiEventDataSasExpanderStatusChange_t *expander_data = ++ (MpiEventDataSasExpanderStatusChange_t *)reply->Data; + +- INIT_WORK(&ev->work, mptsas_hotplug_work); +- ev->ioc = ioc; +- ev->handle = le16_to_cpu(sas_event_data->DevHandle); +- ev->parent_handle = +- le16_to_cpu(sas_event_data->ParentDevHandle); +- ev->channel = sas_event_data->Bus; +- ev->id = sas_event_data->TargetID; +- ev->phy_id = sas_event_data->PhyNum; +- memcpy(&sas_address, &sas_event_data->SASAddress, +- sizeof(__le64)); +- ev->sas_address = le64_to_cpu(sas_address); +- ev->device_info = device_info; ++ if (ioc->old_sas_discovery_protocal) ++ return 0; + +- if (sas_event_data->ReasonCode & +- MPI_EVENT_SAS_DEV_STAT_RC_ADDED) +- ev->event_type = MPTSAS_ADD_DEVICE; +- else +- ev->event_type = MPTSAS_DEL_DEVICE; +- schedule_work(&ev->work); ++ if (expander_data->ReasonCode == ++ MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && ++ ioc->device_missing_delay) ++ delay = HZ * ioc->device_missing_delay; + break; +- case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: +- /* +- * Persistent table is full. +- */ +- INIT_WORK(&ioc->sas_persist_task, +- mptsas_persist_clear_table); +- schedule_work(&ioc->sas_persist_task); ++ } ++ case MPI_EVENT_SAS_DISCOVERY: ++ { ++ u32 discovery_status; ++ EventDataSasDiscovery_t *discovery_data = ++ (EventDataSasDiscovery_t *)reply->Data; ++ ++ discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); ++ ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; ++ if (ioc->old_sas_discovery_protocal && !discovery_status) ++ mptsas_queue_rescan(ioc); ++ return 0; ++ } ++ case MPI_EVENT_INTEGRATED_RAID: ++ case MPI_EVENT_PERSISTENT_TABLE_FULL: ++ case MPI_EVENT_IR2: ++ case MPI_EVENT_SAS_PHY_LINK_STATUS: ++ case MPI_EVENT_QUEUE_FULL: + break; +- /* +- * TODO, handle other events +- */ +- case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: +- case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: +- case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: +- case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: +- case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: +- case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: +- case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: + default: +- break; ++ return 0; + } ++ ++ event_data_sz = ((reply->MsgLength * 4) - ++ offsetof(EventNotificationReply_t, Data)); ++ sz = offsetof(struct fw_event_work, event_data) + event_data_sz; ++ fw_event = kzalloc(sz, GFP_ATOMIC); ++ if (!fw_event) { ++ printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, ++ __FUNCTION__, __LINE__); ++ return 0; ++ } ++ memcpy(fw_event->event_data, reply->Data, event_data_sz); ++ fw_event->event = event; ++ fw_event->ioc = ioc; ++ mptsas_add_fw_event(ioc, fw_event, delay); ++ return 0; + } +-static void +-mptsas_send_raid_event(MPT_ADAPTER *ioc, +- EVENT_DATA_RAID *raid_event_data) ++ ++ ++/* Delete a volume when no longer listed in ioc pg2 ++ */ ++static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) + { +- struct mptsas_hotplug_event *ev; +- int status = le32_to_cpu(raid_event_data->SettingsStatus); +- int state = (status >> 8) & 0xff; ++ struct scsi_device *sdev; ++ int i; + +- if (ioc->bus_type != SAS) ++ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); ++ if (!sdev) + return; ++ if (!ioc->raid_data.pIocPg2) ++ goto out; ++ if (!ioc->raid_data.pIocPg2->NumActiveVolumes) ++ goto out; ++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) ++ if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) ++ goto release_sdev; ++ out: ++ printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " ++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,id); ++ scsi_remove_device(sdev); ++ release_sdev: ++ scsi_device_put(sdev); ++} ++ ++static void ++mptsas_not_responding_devices(MPT_ADAPTER *ioc) ++{ ++ struct mptsas_portinfo buffer, *port_info; ++ struct sas_device_info *sas_info; ++ struct mptsas_devinfo sas_device; ++ u32 handle; ++ VirtTarget *vtarget = NULL; ++ struct mptsas_phyinfo *phy_info; ++ u8 found_expander; + +- ev = kzalloc(sizeof(*ev), GFP_ATOMIC); +- if (!ev) { +- printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); ++ if (ioc->disable_hotplug_remove) + return; ++ ++ mpt_findImVolumes(ioc); ++ ++ /* devices, logical volumes */ ++ redo_device_scan: ++ list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { ++ if (sas_info->is_cached) ++ continue; ++ if (!sas_info->is_logical_volume) { ++ sas_device.handle = 0; ++ mptsas_sas_device_pg0(ioc, &sas_device, ++ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ++ (sas_info->fw.channel << 8) + ++ sas_info->fw.id); ++ if (sas_device.handle) ++ continue; ++ /* delete device */ ++ if ((vtarget = mptsas_find_vtarget(ioc, ++ sas_info->fw.channel, ++ sas_info->fw.id))) ++ vtarget->deleted = 1; ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ sas_info->sas_address); ++ if (phy_info) { ++ mptsas_del_end_device(ioc, phy_info); ++ goto redo_device_scan; ++ } ++ } else ++ mptsas_volume_delete(ioc, sas_info->fw.id); + } + +- INIT_WORK(&ev->work, mptsas_hotplug_work); +- ev->ioc = ioc; +- ev->id = raid_event_data->VolumeID; +- ev->channel = raid_event_data->VolumeBus; +- ev->event_type = MPTSAS_IGNORE_EVENT; ++ /* expanders */ ++ redo_expander_scan: ++ list_for_each_entry(port_info, &ioc->sas_topology, list) { + +- switch (raid_event_data->ReasonCode) { +- case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: +- ev->phys_disk_num_valid = 1; +- ev->phys_disk_num = raid_event_data->PhysDiskNum; +- ev->event_type = MPTSAS_ADD_DEVICE; +- break; +- case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: +- ev->phys_disk_num_valid = 1; +- ev->phys_disk_num = raid_event_data->PhysDiskNum; +- ev->hidden_raid_component = 1; +- ev->event_type = MPTSAS_DEL_DEVICE; +- break; +- case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: +- switch (state) { +- case MPI_PD_STATE_ONLINE: +- case MPI_PD_STATE_NOT_COMPATIBLE: +- ev->phys_disk_num_valid = 1; +- ev->phys_disk_num = raid_event_data->PhysDiskNum; +- ev->hidden_raid_component = 1; +- ev->event_type = MPTSAS_ADD_DEVICE; +- break; +- case MPI_PD_STATE_MISSING: +- case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: +- case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: +- case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: +- ev->phys_disk_num_valid = 1; +- ev->phys_disk_num = raid_event_data->PhysDiskNum; +- ev->event_type = MPTSAS_DEL_DEVICE; +- break; +- default: +- break; ++ if (port_info->phy_info && ++ (!(port_info->phy_info[0].identify.device_info & ++ MPI_SAS_DEVICE_INFO_SMP_TARGET))) ++ continue; ++ found_expander = 0; ++ handle = 0xFFFF; ++ while (!mptsas_sas_expander_pg0(ioc, &buffer, ++ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << ++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && ++ !found_expander) { ++ ++ handle = buffer.phy_info[0].handle; ++ if (buffer.phy_info[0].identify.sas_address == ++ port_info->phy_info[0].identify.sas_address) { ++ found_expander = 1; ++ } ++ kfree(buffer.phy_info); + } +- break; +- case MPI_EVENT_RAID_RC_VOLUME_DELETED: +- ev->event_type = MPTSAS_DEL_RAID; +- break; +- case MPI_EVENT_RAID_RC_VOLUME_CREATED: +- ev->event_type = MPTSAS_ADD_RAID; +- break; +- case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: +- switch (state) { +- case MPI_RAIDVOL0_STATUS_STATE_FAILED: +- case MPI_RAIDVOL0_STATUS_STATE_MISSING: +- ev->event_type = MPTSAS_DEL_RAID; +- break; +- case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: +- case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: +- ev->event_type = MPTSAS_ADD_RAID; +- break; +- default: +- break; ++ ++ if (!found_expander) { ++ mptsas_expander_delete(ioc, port_info); ++ goto redo_expander_scan; + } +- break; +- default: +- break; + } +- schedule_work(&ev->work); + } + ++/** ++ * mptsas_probe_expanders - adding expanders ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * ++ **/ + static void +-mptsas_send_discovery_event(MPT_ADAPTER *ioc, +- EVENT_DATA_SAS_DISCOVERY *discovery_data) ++mptsas_probe_expanders(MPT_ADAPTER *ioc) + { +- struct mptsas_discovery_event *ev; ++ struct mptsas_portinfo buffer, *port_info; ++ u32 handle; ++ int i; + +- /* +- * DiscoveryStatus +- * +- * This flag will be non-zero when firmware +- * kicks off discovery, and return to zero +- * once its completed. +- */ +- if (discovery_data->DiscoveryStatus) +- return; ++ handle = 0xFFFF; ++ while (!mptsas_sas_expander_pg0(ioc, &buffer, ++ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << ++ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { + +- ev = kzalloc(sizeof(*ev), GFP_ATOMIC); +- if (!ev) +- return; +- INIT_WORK(&ev->work, mptsas_discovery_work); +- ev->ioc = ioc; +- schedule_work(&ev->work); +-}; ++ handle = buffer.phy_info[0].handle; ++ port_info = mptsas_find_portinfo_by_sas_address(ioc, ++ buffer.phy_info[0].identify.sas_address); ++ ++ if (port_info) { ++ /* refreshing handles */ ++ for (i = 0; i < buffer.num_phys; i++) { ++ port_info->phy_info[i].handle = handle; ++ port_info->phy_info[i].identify.handle_parent = ++ buffer.phy_info[0].identify.handle_parent; ++ } ++ mptsas_expander_refresh(ioc, port_info); ++ kfree(buffer.phy_info); ++ continue; ++ } ++ ++ port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); ++ if (!port_info) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "%s: exit at line=%d\n", ioc->name, ++ __FUNCTION__, __LINE__)); ++ return; ++ } ++ port_info->num_phys = buffer.num_phys; ++ port_info->phy_info = buffer.phy_info; ++ for (i = 0; i < port_info->num_phys; i++) ++ port_info->phy_info[i].portinfo = port_info; ++ mutex_lock(&ioc->sas_topology_mutex); ++ list_add_tail(&port_info->list, &ioc->sas_topology); ++ mutex_unlock(&ioc->sas_topology_mutex); ++ printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " ++ "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, ++ (unsigned long long)buffer.phy_info[0].identify.sas_address); ++ mptsas_expander_refresh(ioc, port_info); ++ } ++} + +-/* +- * mptsas_send_ir2_event - handle exposing hidden disk when +- * an inactive raid volume is added +- * +- * @ioc: Pointer to MPT_ADAPTER structure +- * @ir2_data +- * +- */ + static void +-mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) ++mptsas_probe_devices(MPT_ADAPTER *ioc) + { +- struct mptsas_hotplug_event *ev; ++ u16 retry_count; ++ u16 handle; ++ struct mptsas_devinfo sas_device; ++ struct mptsas_phyinfo *phy_info; ++ enum device_state state; + +- if (ir2_data->ReasonCode != +- MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) +- return; ++ handle = 0xFFFF; ++ while (!(mptsas_sas_device_pg0(ioc, &sas_device, ++ MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { ++ ++ handle = sas_device.handle; ++ ++ if ((sas_device.device_info & ++ (MPI_SAS_DEVICE_INFO_SSP_TARGET | ++ MPI_SAS_DEVICE_INFO_STP_TARGET | ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) ++ continue; + +- ev = kzalloc(sizeof(*ev), GFP_ATOMIC); +- if (!ev) +- return; ++ phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); ++ if (!phy_info) ++ continue; + +- INIT_WORK(&ev->work, mptsas_hotplug_work); +- ev->ioc = ioc; +- ev->id = ir2_data->TargetID; +- ev->channel = ir2_data->Bus; +- ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; ++ if (mptsas_get_rphy(phy_info)) ++ continue; + +- schedule_work(&ev->work); +-}; ++ state = DEVICE_RETRY; ++ retry_count = 0; ++ while(state == DEVICE_RETRY) { ++ state = mptsas_test_unit_ready(ioc, sas_device.channel, ++ sas_device.id, retry_count++); ++ ssleep(1); ++ } ++ if (state == DEVICE_READY) ++ mptsas_add_end_device(ioc, phy_info); ++ } ++} + +-static int +-mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) ++/** ++ * mptsas_scan_sas_topology - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @sas_address: ++ * ++ **/ ++static void ++mptsas_scan_sas_topology(MPT_ADAPTER *ioc) + { +- int rc=1; +- u8 event = le32_to_cpu(reply->Event) & 0xFF; ++ struct scsi_device *sdev; ++ int i; + +- if (!ioc->sh) +- goto out; ++ mptsas_probe_hba_phys(ioc); ++ mptsas_probe_expanders(ioc); ++ mptsas_probe_devices(ioc); + + /* +- * sas_discovery_ignore_events +- * +- * This flag is to prevent anymore processing of +- * sas events once mptsas_remove function is called. +- */ +- if (ioc->sas_discovery_ignore_events) { +- rc = mptscsih_event_process(ioc, reply); +- goto out; +- } +- +- switch (event) { +- case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: +- mptsas_send_sas_event(ioc, +- (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); +- break; +- case MPI_EVENT_INTEGRATED_RAID: +- mptsas_send_raid_event(ioc, +- (EVENT_DATA_RAID *)reply->Data); +- break; +- case MPI_EVENT_PERSISTENT_TABLE_FULL: +- INIT_WORK(&ioc->sas_persist_task, +- mptsas_persist_clear_table); +- schedule_work(&ioc->sas_persist_task); +- break; +- case MPI_EVENT_SAS_DISCOVERY: +- mptsas_send_discovery_event(ioc, +- (EVENT_DATA_SAS_DISCOVERY *)reply->Data); +- break; +- case MPI_EVENT_IR2: +- mptsas_send_ir2_event(ioc, +- (PTR_MPI_EVENT_DATA_IR2)reply->Data); +- break; +- default: +- rc = mptscsih_event_process(ioc, reply); +- break; ++ Reporting RAID volumes. ++ */ ++ if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || ++ !ioc->raid_data.pIocPg2->NumActiveVolumes) ++ return; ++ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { ++ if ((sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0))) { ++ scsi_device_put(sdev); ++ continue; ++ } ++ printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " ++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); ++ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ++ ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); + } +- out: +- +- return rc; + } + ++/** ++ * mptsas_probe - ++ * @pdev: ++ * @id: ++ * ++ **/ + static int + mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { +@@ -3129,6 +5071,7 @@ mptsas_probe(struct pci_dev *pdev, const + return r; + + ioc = pci_get_drvdata(pdev); ++ mptsas_fw_event_off(ioc); + ioc->DoneCtx = mptsasDoneCtx; + ioc->TaskCtx = mptsasTaskCtx; + ioc->InternalCtx = mptsasInternalCtx; +@@ -3173,7 +5116,7 @@ mptsas_probe(struct pci_dev *pdev, const + ioc->name); + error = -1; + goto out_mptsas_probe; +- } ++ } + + spin_lock_irqsave(&ioc->FreeQlock, flags); + +@@ -3187,10 +5130,9 @@ mptsas_probe(struct pci_dev *pdev, const + + /* set 16 byte cdb's */ + sh->max_cmd_len = 16; +- ++ sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); + sh->max_id = ioc->pfacts[0].PortSCSIID; + sh->max_lun = max_lun; +- + sh->transportt = mptsas_transport_template; + + /* Required entry. +@@ -3199,10 +5141,10 @@ mptsas_probe(struct pci_dev *pdev, const + + INIT_LIST_HEAD(&ioc->sas_topology); + mutex_init(&ioc->sas_topology_mutex); +- mutex_init(&ioc->sas_discovery_mutex); + mutex_init(&ioc->sas_mgmt.mutex); + init_completion(&ioc->sas_mgmt.done); + ++ + /* Verify that we won't exceed the maximum + * number of chain buffers + * We can optimize: ZZ = req_sz/sizeof(SGE) +@@ -3212,17 +5154,16 @@ mptsas_probe(struct pci_dev *pdev, const + * A slightly different algorithm is required for + * 64bit SGEs. + */ +- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); +- if (sizeof(dma_addr_t) == sizeof(u64)) { ++ ++ scale = ioc->req_sz/ioc->SGE_size; ++ if (ioc->sg_addr_size == sizeof(u64)) { + numSGE = (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 60) / (sizeof(dma_addr_t) + +- sizeof(u32)); ++ (ioc->req_sz - 60) / ioc->SGE_size; + } else { + numSGE = 1 + (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 64) / (sizeof(dma_addr_t) + +- sizeof(u32)); ++ (ioc->req_sz - 64) / ioc->SGE_size; + } + + if (numSGE < sh->sg_tablesize) { +@@ -3250,34 +5191,17 @@ mptsas_probe(struct pci_dev *pdev, const + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", + ioc->name, ioc->ScsiLookup)); + +- /* Clear the TM flags +- */ +- hd->tmPending = 0; +- hd->tmState = TM_STATE_NONE; +- hd->resetPending = 0; +- hd->abortSCpnt = NULL; +- +- /* Clear the pointer used to store +- * single-threaded commands, i.e., those +- * issued during a bus scan, dv and +- * configuration pages. +- */ +- hd->cmdPtr = NULL; +- +- /* Initialize this SCSI Hosts' timers +- * To use, set the timer expires field +- * and add_timer +- */ +- init_timer(&hd->timer); +- hd->timer.data = (unsigned long) hd; +- hd->timer.function = mptscsih_timer_expired; +- ++ ioc->sdev_queue_depth = mpt_sdev_queue_depth; + ioc->sas_data.ptClear = mpt_pt_clear; +- +- init_waitqueue_head(&hd->scandv_waitq); +- hd->scandv_wait_done = 0; + hd->last_queue_full = 0; ++ ioc->disable_hotplug_remove = mpt_disable_hotplug_remove; ++ if (ioc->disable_hotplug_remove) ++ printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ioc->name); ++ + INIT_LIST_HEAD(&hd->target_reset_list); ++ INIT_LIST_HEAD(&ioc->sas_device_info_list); ++ init_MUTEX(&ioc->sas_device_info_mutex); ++ + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + if (ioc->sas_data.ptClear==1) { +@@ -3292,8 +5216,11 @@ mptsas_probe(struct pci_dev *pdev, const + goto out_mptsas_probe; + } + ++ /* older firmware doesn't support expander events */ ++ if ((ioc->facts.HeaderVersion >> 8) < 0xE) ++ ioc->old_sas_discovery_protocal = 1; + mptsas_scan_sas_topology(ioc); +- ++ mptsas_fw_event_on(ioc); + return 0; + + out_mptsas_probe: +@@ -3302,13 +5229,23 @@ mptsas_probe(struct pci_dev *pdev, const + return error; + } + +-static void __devexit mptsas_remove(struct pci_dev *pdev) ++/** ++ * mptsas_remove - ++ * @pdev: ++ * ++ **/ ++static void __devexit ++mptsas_remove(struct pci_dev *pdev) + { + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct mptsas_portinfo *p, *n; + int i; + +- ioc->sas_discovery_ignore_events = 1; ++ mptsas_fw_event_off(ioc); ++ mptsas_cleanup_fw_event_q(ioc); ++ ++ mptsas_del_device_components(ioc); ++ + sas_remove_host(ioc->sh); + + mutex_lock(&ioc->sas_topology_mutex); +@@ -3316,11 +5253,12 @@ static void __devexit mptsas_remove(stru + list_del(&p->list); + for (i = 0 ; i < p->num_phys ; i++) + mptsas_port_delete(ioc, p->phy_info[i].port_details); ++ + kfree(p->phy_info); + kfree(p); + } + mutex_unlock(&ioc->sas_topology_mutex); +- ++ ioc->hba_port_info = NULL; + mptscsih_remove(pdev); + } + +@@ -3352,6 +5290,10 @@ static struct pci_driver mptsas_driver = + #endif + }; + ++/** ++ * mptsas_init - ++ * ++ **/ + static int __init + mptsas_init(void) + { +@@ -3365,10 +5307,12 @@ mptsas_init(void) + return -ENODEV; + + mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); +- mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); ++ mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); + mptsasInternalCtx = + mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); + mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); ++ mptsasDeviceResetCtx = ++ mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); + + mpt_event_register(mptsasDoneCtx, mptsas_event_process); + mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); +@@ -3380,6 +5324,10 @@ mptsas_init(void) + return error; + } + ++/** ++ * mptsas_exit - ++ * ++ **/ + static void __exit + mptsas_exit(void) + { +@@ -3393,6 +5341,7 @@ mptsas_exit(void) + mpt_deregister(mptsasInternalCtx); + mpt_deregister(mptsasTaskCtx); + mpt_deregister(mptsasDoneCtx); ++ mpt_deregister(mptsasDeviceResetCtx); + } + + module_init(mptsas_init); +--- a/drivers/message/fusion/mptsas.h ++++ b/drivers/message/fusion/mptsas.h +@@ -50,9 +50,10 @@ + /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + + struct mptsas_target_reset_event { +- struct list_head list; +- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; ++ struct list_head list; ++ MpiEventDataSasDeviceStatusChange_t sas_event_data; + u8 target_reset_issued; ++ unsigned long time_count; + }; + + enum mptsas_hotplug_action { +@@ -61,11 +62,34 @@ enum mptsas_hotplug_action { + MPTSAS_ADD_RAID, + MPTSAS_DEL_RAID, + MPTSAS_ADD_INACTIVE_VOLUME, ++ MPTSAS_ADD_PHYSDISK, ++ MPTSAS_ADD_PHYSDISK_REPROBE, ++ MPTSAS_DEL_PHYSDISK, ++ MPTSAS_DEL_PHYSDISK_REPROBE, ++ MPTSAS_REQUEUE_EVENT, + MPTSAS_IGNORE_EVENT, + }; + ++struct sas_mapping{ ++ u8 id; ++ u8 channel; ++}; ++ ++struct sas_device_info { ++ struct list_head list; ++ struct sas_mapping os; /* operating system mapping*/ ++ struct sas_mapping fw; /* firmware mapping */ ++ u64 sas_address; ++ u32 device_info; /* specific bits for devices */ ++ u16 slot; /* enclosure slot id */ ++ u64 enclosure_logical_id; /*enclosure address */ ++ u8 is_logical_volume; /* is this logical volume */ ++ u8 is_hidden_raid_component; /* this belongs to volume */ ++ u8 volume_id; /* this valid when is_hidden_raid_component set */ ++ u8 is_cached; /* cached data for a removed device */ ++}; ++ + struct mptsas_hotplug_event { +- struct work_struct work; + MPT_ADAPTER *ioc; + enum mptsas_hotplug_action event_type; + u64 sas_address; +@@ -73,17 +97,28 @@ struct mptsas_hotplug_event { + u8 id; + u32 device_info; + u16 handle; +- u16 parent_handle; + u8 phy_id; +- u8 phys_disk_num_valid; /* hrc (hidden raid component) */ + u8 phys_disk_num; /* hrc - unique index*/ +- u8 hidden_raid_component; /* hrc - don't expose*/ ++ struct scsi_device *sdev; + }; + +-struct mptsas_discovery_event { ++ ++struct fw_event_work { ++ struct list_head list; ++ struct delayed_work work; ++ MPT_ADAPTER *ioc; ++ u32 event; ++ u8 retries; ++ u8 event_data[1]; ++}; ++ ++#if 0 ++struct mptsas_link_status_event { + struct work_struct work; ++ MpiEventDataSasPhyLinkStatus_t link_data; + MPT_ADAPTER *ioc; + }; ++#endif + + /* + * SAS topology structures +@@ -113,32 +148,35 @@ struct mptsas_devinfo { + * Specific details on ports, wide/narrow + */ + struct mptsas_portinfo_details{ +- u16 num_phys; /* number of phys belong to this port */ +- u64 phy_bitmask; /* TODO, extend support for 255 phys */ +- struct sas_rphy *rphy; /* transport layer rphy object */ ++ u16 num_phys; /* number of phys beloing to this port */ ++ u64 phy_bitmask; /* this needs extending to support 128 phys */ ++ struct sas_rphy *rphy; /* rphy for end devices */ + struct sas_port *port; /* transport layer port object */ + struct scsi_target *starget; + struct mptsas_portinfo *port_info; + }; + + struct mptsas_phyinfo { +- u16 handle; /* unique id to address this */ +- u8 phy_id; /* phy index */ +- u8 port_id; /* firmware port identifier */ ++ u16 handle; /* handle for this phy */ ++ u8 phy_id; /* phy index */ ++ u8 port_id; /* port number this phy is part of */ + u8 negotiated_link_rate; /* nego'd link rate for this phy */ +- u8 hw_link_rate; /* hardware max/min phys link rate */ ++ u8 hw_link_rate; /* hardware max/min phys link rate */ + u8 programmed_link_rate; /* programmed max/min phy link rate */ + u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/ ++ u8 change_count; /* change count of the phy */ ++ u8 port_flags; /* info wrt host sas ports */ ++ u32 phy_info; /* various info wrt the phy */ + struct mptsas_devinfo identify; /* point to phy device info */ + struct mptsas_devinfo attached; /* point to attached device info */ +- struct sas_phy *phy; /* transport layer phy object */ ++ struct sas_phy *phy; + struct mptsas_portinfo *portinfo; + struct mptsas_portinfo_details * port_details; + }; + + struct mptsas_portinfo { + struct list_head list; +- u16 num_phys; /* number of phys */ ++ u16 num_phys; /* number of phys */ + struct mptsas_phyinfo *phy_info; + }; + +@@ -156,3 +194,4 @@ struct mptsas_enclosure { + + /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + #endif ++ +--- a/drivers/message/fusion/mptscsih.c ++++ b/drivers/message/fusion/mptscsih.c +@@ -53,7 +53,9 @@ + #include /* for mdelay */ + #include /* needed for in_interrupt() proto */ + #include /* notifier code */ ++#include + #include ++#include + + #include + #include +@@ -77,10 +79,15 @@ MODULE_LICENSE("GPL"); + MODULE_VERSION(my_VERSION); + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++typedef struct _BIG_SENSE_BUF { ++ u8 data[MPT_SENSE_BUFFER_ALLOC]; ++} BIG_SENSE_BUF; ++ ++ + /* + * Other private/forward protos... + */ +-static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); ++struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); + static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i); + static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd); + static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd); +@@ -92,17 +99,10 @@ static int mptscsih_AddSGE(MPT_ADAPTER * + SCSIIORequest_t *pReq, int req_idx); + static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); + static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); +-static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); +-static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); +- +-static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); + + int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); + int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +- +-int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); +-static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); +-static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); ++static void mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice); + + void mptscsih_remove(struct pci_dev *); + void mptscsih_shutdown(struct pci_dev *); +@@ -111,81 +111,17 @@ int mptscsih_suspend(struct pci_dev *p + int mptscsih_resume(struct pci_dev *pdev); + #endif + +-#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mptscsih_add_sge - Place a simple SGE at address pAddr. +- * @pAddr: virtual address for SGE +- * @flagslength: SGE flags and data transfer length +- * @dma_addr: Physical address +- * +- * This routine places a MPT request frame back on the MPT adapter's +- * FreeQ. +- */ +-static inline void +-mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) +-{ +- if (sizeof(dma_addr_t) == sizeof(u64)) { +- SGESimple64_t *pSge = (SGESimple64_t *) pAddr; +- u32 tmp = dma_addr & 0xFFFFFFFF; +- +- pSge->FlagsLength = cpu_to_le32(flagslength); +- pSge->Address.Low = cpu_to_le32(tmp); +- tmp = (u32) ((u64)dma_addr >> 32); +- pSge->Address.High = cpu_to_le32(tmp); +- +- } else { +- SGESimple32_t *pSge = (SGESimple32_t *) pAddr; +- pSge->FlagsLength = cpu_to_le32(flagslength); +- pSge->Address = cpu_to_le32(dma_addr); +- } +-} /* mptscsih_add_sge() */ ++#define SNS_LEN(scp) sizeof((scp)->sense_buffer) + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mptscsih_add_chain - Place a chain SGE at address pAddr. +- * @pAddr: virtual address for SGE +- * @next: nextChainOffset value (u32's) +- * @length: length of next SGL segment +- * @dma_addr: Physical address +- * +- * This routine places a MPT request frame back on the MPT adapter's +- * FreeQ. +- */ +-static inline void +-mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +-{ +- if (sizeof(dma_addr_t) == sizeof(u64)) { +- SGEChain64_t *pChain = (SGEChain64_t *) pAddr; +- u32 tmp = dma_addr & 0xFFFFFFFF; +- +- pChain->Length = cpu_to_le16(length); +- pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); +- +- pChain->NextChainOffset = next; +- +- pChain->Address.Low = cpu_to_le32(tmp); +- tmp = (u32) ((u64)dma_addr >> 32); +- pChain->Address.High = cpu_to_le32(tmp); +- } else { +- SGEChain32_t *pChain = (SGEChain32_t *) pAddr; +- pChain->Length = cpu_to_le16(length); +- pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); +- pChain->NextChainOffset = next; +- pChain->Address = cpu_to_le32(dma_addr); +- } +-} /* mptscsih_add_chain() */ +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* + * mptscsih_getFreeChainBuffer - Function to get a free chain + * from the MPT_SCSI_HOST FreeChainQ. + * @ioc: Pointer to MPT_ADAPTER structure + * @req_idx: Index of the SCSI IO request frame. (output) + * + * return SUCCESS or FAILED +- */ ++ **/ + static inline int + mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) + { +@@ -195,7 +131,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER + int chain_idx; + + dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n", +- ioc->name)); ++ ioc->name)); + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (!list_empty(&ioc->FreeChainQ)) { + int offset; +@@ -206,14 +142,13 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER + offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; + chain_idx = offset / ioc->req_sz; + rc = SUCCESS; +- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", +- ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); ++ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", ++ ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); + } else { + rc = FAILED; + chain_idx = MPT_HOST_NO_CHAIN; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", +- ioc->name)); ++ ioc->name)); + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + +@@ -222,7 +157,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER + } /* mptscsih_getFreeChainBuffer() */ + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_AddSGE - Add a SGE (plus chain buffers) to the + * SCSIIORequest_t Message Frame. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -230,7 +165,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER + * @pReq: Pointer to SCSIIORequest_t structure + * + * Returns ... +- */ ++ **/ + static int + mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, + SCSIIORequest_t *pReq, int req_idx) +@@ -281,10 +216,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct + */ + + nextSGEset: +- numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); ++ numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size ); + numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; + +- sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; ++ sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir; + + /* Get first (num - 1) SG elements + * Skip any SG entries with a length of 0 +@@ -299,11 +234,11 @@ nextSGEset: + } + + v2 = sg_dma_address(sg); +- mptscsih_add_sge(psge, sgflags | thisxfer, v2); ++ ioc->add_sge(psge, sgflags | thisxfer, v2); + + sg = sg_next(sg); /* Get next SG element from the OS */ +- psge += (sizeof(u32) + sizeof(dma_addr_t)); +- sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); ++ psge += ioc->SGE_size; ++ sgeOffset += ioc->SGE_size; + sg_done++; + } + +@@ -320,12 +255,8 @@ nextSGEset: + thisxfer = sg_dma_len(sg); + + v2 = sg_dma_address(sg); +- mptscsih_add_sge(psge, sgflags | thisxfer, v2); +- /* +- sg = sg_next(sg); +- psge += (sizeof(u32) + sizeof(dma_addr_t)); +- */ +- sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); ++ ioc->add_sge(psge, sgflags | thisxfer, v2); ++ sgeOffset += ioc->SGE_size; + sg_done++; + + if (chainSge) { +@@ -334,7 +265,7 @@ nextSGEset: + * Update the chain element + * Offset and Length fields. + */ +- mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); ++ ioc->add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + } else { + /* The current buffer is the original MF + * and there is no Chain buffer. +@@ -367,7 +298,7 @@ nextSGEset: + * set properly). + */ + if (sg_done) { +- u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); ++ u32 *ptmp = (u32 *) (psge - ioc->SGE_size); + sgflags = le32_to_cpu(*ptmp); + sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; + *ptmp = cpu_to_le32(sgflags); +@@ -381,8 +312,8 @@ nextSGEset: + * Old chain element is now complete. + */ + u8 nextChain = (u8) (sgeOffset >> 2); +- sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); +- mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); ++ sgeOffset += ioc->SGE_size; ++ ioc->add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + } else { + /* The original MF buffer requires a chain buffer - + * set the offset. +@@ -461,7 +392,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER * + + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", +- ioc->name,__func__)); ++ ioc->name,__FUNCTION__)); + return; + } + +@@ -592,14 +523,14 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s + } + + scsi_print_command(sc); +- printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n", +- ioc->name, pScsiReply->Bus, pScsiReply->TargetID); +- printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, " +- "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow, +- scsi_get_resid(sc)); +- printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, " +- "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag), ++ printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n", ++ ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun); ++ printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, resid = %d\n", ++ ioc->name, scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc)); ++ printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, sc->result = %08X\n", ++ ioc->name, le16_to_cpu(pScsiReply->TaskTag), + le32_to_cpu(pScsiReply->TransferCount), sc->result); ++ + printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), " + "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n", + ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus, +@@ -625,7 +556,7 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s + #endif + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_io_done - Main SCSI IO callback routine registered to + * Fusion MPT (base) driver + * @ioc: Pointer to MPT_ADAPTER structure +@@ -638,7 +569,7 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. +- */ ++ **/ + int + mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) + { +@@ -651,14 +582,15 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + VirtTarget *vtarget; + + hd = shost_priv(ioc->sh); ++ + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + req_idx_MR = (mr != NULL) ? + le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; + if ((req_idx != req_idx_MR) || +- (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) { +- printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n", +- ioc->name); +- printk (MYIOC_s_ERR_FMT ++ (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) { ++ printk(MYIOC_s_WARN_FMT ++ "Received a mf that was already freed\n", ioc->name); ++ printk (MYIOC_s_WARN_FMT + "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", + ioc->name, req_idx, req_idx_MR, mf, mr, + mptscsih_get_scsi_lookup(ioc, req_idx_MR)); +@@ -693,7 +625,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + + if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){ + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n", ++ "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task_tag=%d)\n", + ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag)); + }else{ + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT +@@ -706,6 +638,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + ; + } else { + u32 xfer_cnt; ++ u32 difftransfer; + u16 status; + u8 scsi_state, scsi_status; + u32 log_info; +@@ -716,6 +649,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); + scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt); + log_info = le32_to_cpu(pScsiReply->IOCLogInfo); ++ vdevice = sc->device->hostdata; + + /* + * if we get a data underrun indication, yet no data was +@@ -733,20 +667,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) + mptscsih_copy_sense_data(sc, hd, mf, pScsiReply); + +- /* +- * Look for + dump FCP ResponseInfo[]! +- */ +- if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && +- pScsiReply->ResponseInfo) { +- printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] " +- "FCP_ResponseInfo=%08xh\n", ioc->name, +- sc->device->host->host_no, sc->device->channel, +- sc->device->id, sc->device->lun, +- le32_to_cpu(pScsiReply->ResponseInfo)); +- } +- + switch(status) { + case MPI_IOCSTATUS_BUSY: /* 0x0002 */ ++ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ + /* CHECKME! + * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) + * But not: DID_BUS_BUSY lest one risk +@@ -771,7 +694,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) + hd->sel_timeout[pScsiReq->TargetID]++; + +- vdevice = sc->device->hostdata; + if (!vdevice) + break; + vtarget = vdevice->vtarget; +@@ -793,14 +715,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + } + } + } else if (ioc->bus_type == FC) { +- /* +- * The FC IOC may kill a request for variety of +- * reasons, some of which may be recovered by a +- * retry, some which are unlikely to be +- * recovered. Return DID_ERROR instead of +- * DID_RESET to permit retry of the command, +- * just not an infinite number of them +- */ ++ /* The FC IOC may kill a request for variety of reasons, ++ some of which may be recovered by a retry, some which ++ are unlikely to be recovered. Return DID_ERROR instead ++ of DID_RESET to permit retry of the command, just not ++ an infinite number of them */ + sc->result = DID_ERROR << 16; + break; + } +@@ -810,12 +729,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + */ + + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ +- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + /* Linux handles an unsolicited DID_RESET better + * than an unsolicited DID_ABORT. + */ + sc->result = DID_RESET << 16; + ++ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ ++ if ( ioc->bus_type == FC ) ++ sc->result = DID_ERROR << 16; ++ else ++ sc->result = DID_RESET << 16; + break; + + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ +@@ -824,9 +747,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + sc->result=DID_SOFT_ERROR << 16; + else /* Sufficient data transfer occurred */ + sc->result = (DID_OK << 16) | scsi_status; +- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n", +- ioc->name, sc->result, sc->device->channel, sc->device->id)); + break; + + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ +@@ -835,11 +755,34 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + * precedence! + */ + sc->result = (DID_OK << 16) | scsi_status; +- if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { +- /* Have already saved the status and sense data ++ ++ if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) { ++ ++ /* ++ * For an Errata on LSI53C1030 ++ * When the length of request data ++ * and transfer data are different ++ * with result of command (READ or VERIFY), ++ * DID_SOFT_ERROR is set. + */ +- ; +- } else { ++ if (ioc->bus_type == SPI && vdevice && ++ vdevice->vtarget->type == TYPE_DISK) { ++ if (pScsiReq->CDB[0] == READ_6 || ++ pScsiReq->CDB[0] == READ_10 || ++ pScsiReq->CDB[0] == READ_12 || ++ pScsiReq->CDB[0] == READ_16 || ++ pScsiReq->CDB[0] == VERIFY || ++ pScsiReq->CDB[0] == VERIFY_16) { ++ if (scsi_bufflen(sc) != ++ xfer_cnt) { ++ sc->result = DID_SOFT_ERROR << 16; ++ printk(MYIOC_s_WARN_FMT "Errata" ++ "on LSI53C1030 occurred. sc->request_bufflen=0x%02x, " ++ "xfer_cnt=0x%02x\n", ioc->name, scsi_bufflen(sc), xfer_cnt); ++ } ++ } ++ } ++ + if (xfer_cnt < sc->underflow) { + if (scsi_status == SAM_STAT_BUSY) + sc->result = SAM_STAT_BUSY; +@@ -848,7 +791,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + } + if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + /* What to do? +- */ ++ */ + sc->result = DID_SOFT_ERROR << 16; + } + else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { +@@ -857,13 +800,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + } + } + +- +- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", +- ioc->name, sc->underflow)); +- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt)); +- + /* Report Queue Full + */ + if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) +@@ -879,6 +815,44 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + if (scsi_state == 0) { + ; + } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { ++ ++ /* ++ * For potential trouble on LSI53C1030. (date:2007.xx.) ++ * It is checked whether the length of request data is equal to ++ * the length of transfer and residual. ++ * MEDIUM_ERROR is set by incorrect data. ++ */ ++ if (ioc->bus_type == SPI && vdevice && ++ vdevice->vtarget->type == TYPE_DISK) { ++ if (sc->sense_buffer[2] & 0x20) { ++ difftransfer = ++ sc->sense_buffer[3] << 24 | ++ sc->sense_buffer[4] << 16 | ++ sc->sense_buffer[5] << 8 | ++ sc->sense_buffer[6]; ++ if ((sc->sense_buffer[3] & 0x80) == 0x80) { ++ if (scsi_bufflen(sc) != xfer_cnt) { ++ sc->sense_buffer[2] = MEDIUM_ERROR; ++ sc->sense_buffer[12] = 0xff; ++ sc->sense_buffer[13] = 0xff; ++ printk(MYIOC_s_WARN_FMT "Errata on " ++ "LSI53C1030 occurred. sc->request_bufflen=0x%02x," ++ "xfer_cnt=0x%02x\n", ioc->name, scsi_bufflen(sc), xfer_cnt); ++ } ++ } else { ++ if (scsi_bufflen(sc) != xfer_cnt + difftransfer) { ++ sc->sense_buffer[2] = MEDIUM_ERROR; ++ sc->sense_buffer[12] = 0xff; ++ sc->sense_buffer[13] = 0xff; ++ printk(MYIOC_s_WARN_FMT "Errata on " ++ "LSI53C1030 occurred. sc->request_bufflen=0x%02x," ++ " xfer_cnt=0x%02x, difftransfer=0x%02x\n", ++ ioc->name, scsi_bufflen(sc) , xfer_cnt, difftransfer); ++ } ++ } ++ } ++ } ++ + /* + * If running against circa 200003dd 909 MPT f/w, + * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL +@@ -890,7 +864,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + + } + else if (scsi_state & +- (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS) ++ (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS) + ) { + /* + * What to do? +@@ -926,7 +900,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ + case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ + case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ +- case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ + case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ + case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ +@@ -957,7 +930,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + return 1; + } + +-/* ++/** + * mptscsih_flush_running_cmds - For each command found, search + * Scsi_Host instance taskQ and reply to OS. + * Called only if recovering from a FW reload. +@@ -966,7 +939,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + * Returns: None. + * + * Must be called while new I/Os are being queued. +- */ ++ **/ + static void + mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) + { +@@ -992,14 +965,14 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOS + scsi_dma_unmap(sc); + sc->result = DID_RESET << 16; + sc->host_scribble = NULL; +- sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT +- "completing cmds: fw_channel %d, fw_id %d, sc=%p," +- " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii); ++ dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT ++ "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, " ++ "idx=%x\n", ioc->name, channel, id, sc, mf, ii)); + sc->scsi_done(sc); + } + } + +-/* ++/** + * mptscsih_search_running_cmds - Delete any commands associated + * with the specified target and lun. Function called only + * when a lun is disable by mid-layer. +@@ -1012,15 +985,15 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOS + * Returns: None. + * + * Called from slave_destroy. +- */ ++ **/ + static void + mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) + { + SCSIIORequest_t *mf = NULL; + int ii; + struct scsi_cmnd *sc; +- struct scsi_lun lun; +- MPT_ADAPTER *ioc = hd->ioc; ++ struct scsi_lun lun; ++ MPT_ADAPTER *ioc = hd->ioc; + unsigned long flags; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +@@ -1030,8 +1003,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HO + mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii); + if (mf == NULL) + continue; +- /* If the device is a hidden raid component, then its +- * expected that the mf->function will be RAID_SCSI_IO ++ ++ /* ++ * If the device is a hidden raid component, ++ * then its expected that ++ * the function would be raid scsi io + */ + if (vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function != +@@ -1053,9 +1029,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HO + scsi_dma_unmap(sc); + sc->host_scribble = NULL; + sc->result = DID_NO_CONNECT << 16; +- sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d," +- "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel, +- vdevice->vtarget->id, sc, mf, ii); ++ dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, ++ MYIOC_s_FMT "completing cmds: fw_channel %d, " ++ "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, ++ vdevice->vtarget->channel, vdevice->vtarget->id, ++ sc, mf, ii)); + sc->scsi_done(sc); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + } +@@ -1067,7 +1045,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HO + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_report_queue_full - Report QUEUE_FULL status returned + * from a SCSI target device. + * @sc: Pointer to scsi_cmnd structure +@@ -1077,12 +1055,12 @@ mptscsih_search_running_cmds(MPT_SCSI_HO + * This routine periodically reports QUEUE_FULL status returned from a + * SCSI target device. It reports this to the console via kernel + * printk() API call, not more than once every 10 seconds. +- */ ++ **/ + static void + mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) + { + long time = jiffies; +- MPT_SCSI_HOST *hd; ++ MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; + + if (sc->device == NULL) +@@ -1100,12 +1078,12 @@ mptscsih_report_queue_full(struct scsi_c + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_remove - Removed scsi devices + * @pdev: Pointer to pci_dev structure + * + * +- */ ++ **/ + void + mptscsih_remove(struct pci_dev *pdev) + { +@@ -1151,10 +1129,10 @@ mptscsih_remove(struct pci_dev *pdev) + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_shutdown - reboot notifier + * +- */ ++ **/ + void + mptscsih_shutdown(struct pci_dev *pdev) + { +@@ -1162,11 +1140,11 @@ mptscsih_shutdown(struct pci_dev *pdev) + + #ifdef CONFIG_PM + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_suspend - Fusion MPT scsi driver suspend routine. + * + * +- */ ++ **/ + int + mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) + { +@@ -1179,11 +1157,11 @@ mptscsih_suspend(struct pci_dev *pdev, p + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_resume - Fusion MPT scsi driver resume routine. + * + * +- */ ++ **/ + int + mptscsih_resume(struct pci_dev *pdev) + { +@@ -1205,7 +1183,7 @@ mptscsih_resume(struct pci_dev *pdev) + * (linux scsi_host_template.info routine) + * + * Returns pointer to buffer where information was written. +- */ ++ **/ + const char * + mptscsih_info(struct Scsi_Host *SChost) + { +@@ -1338,7 +1316,7 @@ mptscsih_proc_info(struct Scsi_Host *hos + * from a linux scsi_cmnd request and send it to the IOC. + * + * Returns 0. (rtn value discarded by linux scsi mid-layer) +- */ ++ **/ + int + mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) + { +@@ -1346,7 +1324,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + MPT_FRAME_HDR *mf; + SCSIIORequest_t *pScsiReq; + VirtDevice *vdevice = SCpnt->device->hostdata; +- int lun; + u32 datalen; + u32 scsictl; + u32 scsidir; +@@ -1357,24 +1334,20 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + + hd = shost_priv(SCpnt->device->host); + ioc = hd->ioc; +- lun = SCpnt->device->lun; + SCpnt->scsi_done = done; + + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n", + ioc->name, SCpnt, done)); + +- if (hd->resetPending) { +- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", +- ioc->name, SCpnt)); ++ if (ioc->taskmgmt_quiesce_io) + return SCSI_MLQUEUE_HOST_BUSY; +- } + + /* + * Put together a MPT SCSI request... + */ + if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { + dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n", +- ioc->name)); ++ ioc->name)); + return SCSI_MLQUEUE_HOST_BUSY; + } + +@@ -1422,7 +1395,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + pScsiReq->CDBLength = SCpnt->cmd_len; + pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + pScsiReq->Reserved = 0; +- pScsiReq->MsgFlags = mpt_msg_flags(); ++ pScsiReq->MsgFlags = mpt_msg_flags(ioc); + int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); + pScsiReq->Control = cpu_to_le32(scsictl); + +@@ -1448,7 +1421,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + */ + if (datalen == 0) { + /* Add a NULL SGE */ +- mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, ++ ioc->add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, + (dma_addr_t) -1); + } else { + /* Add a 32 or 64 bit SGE */ +@@ -1472,7 +1445,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_freeChainBuffers - Function to free chain buffers associated + * with a SCSI IO request + * @hd: Pointer to the MPT_SCSI_HOST instance +@@ -1480,7 +1453,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + * + * Called if SG chain buffer allocation fails and mptscsih callbacks. + * No return. +- */ ++ **/ + static void + mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) + { +@@ -1527,243 +1500,457 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i + */ + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mptscsih_TMHandler - Generic handler for SCSI Task Management. +- * @hd: Pointer to MPT SCSI HOST structure +- * @type: Task Management type +- * @channel: channel number for task management +- * @id: Logical Target ID for reset (if appropriate) +- * @lun: Logical Unit for reset (if appropriate) +- * @ctx2abort: Context for the task to be aborted (if appropriate) +- * @timeout: timeout for task management control +- * +- * Fall through to mpt_HardResetHandler if: not operational, too many +- * failed TM requests or handshake failure. +- * +- * Remark: Currently invoked from a non-interrupt thread (_bh). +- * +- * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC +- * will be active. +- * +- * Returns 0 for SUCCESS, or %FAILED. +- **/ +-int +-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) +-{ +- MPT_ADAPTER *ioc; +- int rc = -1; +- u32 ioc_raw_state; +- unsigned long flags; +- +- ioc = hd->ioc; +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name)); +- +- // SJR - CHECKME - Can we avoid this here? +- // (mpt_HardResetHandler has this check...) +- spin_lock_irqsave(&ioc->diagLock, flags); +- if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { +- spin_unlock_irqrestore(&ioc->diagLock, flags); +- return FAILED; +- } +- spin_unlock_irqrestore(&ioc->diagLock, flags); +- +- /* Wait a fixed amount of time for the TM pending flag to be cleared. +- * If we time out and not bus reset, then we return a FAILED status +- * to the caller. +- * The call to mptscsih_tm_pending_wait() will set the pending flag +- * if we are +- * successful. Otherwise, reload the FW. +- */ +- if (mptscsih_tm_pending_wait(hd) == FAILED) { +- if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: " +- "Timed out waiting for last TM (%d) to complete! \n", +- ioc->name, hd->tmPending)); +- return FAILED; +- } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target " +- "reset: Timed out waiting for last TM (%d) " +- "to complete! \n", ioc->name, +- hd->tmPending)); +- return FAILED; +- } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: " +- "Timed out waiting for last TM (%d) to complete! \n", +- ioc->name, hd->tmPending)); +- return FAILED; +- } +- } else { +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- hd->tmPending |= (1 << type); +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- } +- +- ioc_raw_state = mpt_GetIocState(ioc, 0); +- +- if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { +- printk(MYIOC_s_WARN_FMT +- "TM Handler for type=%x: IOC Not operational (0x%x)!\n", +- ioc->name, type, ioc_raw_state); +- printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name); +- if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) +- printk(MYIOC_s_WARN_FMT "TMHandler: HardReset " +- "FAILED!!\n", ioc->name); +- return FAILED; +- } +- +- if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { +- printk(MYIOC_s_WARN_FMT +- "TM Handler for type=%x: ioc_state: " +- "DOORBELL_ACTIVE (0x%x)!\n", +- ioc->name, type, ioc_raw_state); +- return FAILED; +- } +- +- /* Isse the Task Mgmt request. +- */ +- if (hd->hard_resets < -1) +- hd->hard_resets++; +- +- rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, +- ctx2abort, timeout); +- if (rc) +- printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", +- ioc->name); +- else +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n", +- ioc->name)); +- +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "TMHandler rc = %d!\n", ioc->name, rc)); +- +- return rc; +-} +- +- + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mptscsih_IssueTaskMgmt - Generic send Task Management function. +- * @hd: Pointer to MPT_SCSI_HOST structure +- * @type: Task Management type +- * @channel: channel number for task management +- * @id: Logical Target ID for reset (if appropriate) +- * @lun: Logical Unit for reset (if appropriate) +- * @ctx2abort: Context for the task to be aborted (if appropriate) +- * @timeout: timeout for task management control +- * +- * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) +- * or a non-interrupt thread. In the former, must not call schedule(). +- * +- * Not all fields are meaningfull for all task types. +- * +- * Returns 0 for SUCCESS, or FAILED. +- * +- **/ ++ + static int +-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) ++mptscsih_scandv_bus_reset(MPT_ADAPTER *ioc) + { + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; ++ SCSITaskMgmtReply_t *pScsiTmReply; + int ii; + int retval; +- MPT_ADAPTER *ioc = hd->ioc; ++ unsigned long timeout; ++ unsigned long time_count; ++ u16 iocstatus; ++ ++ mutex_lock(&ioc->taskmgmt_cmds.mutex); ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ return -EPERM; ++ } + +- /* Return Fail to calling function if no message frames available. ++ /* Send request + */ + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", + ioc->name)); +- return FAILED; ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ retval = -ENOMEM; ++ goto out; + } +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", +- ioc->name, mf)); + +- /* Format the Request +- */ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", ++ ioc->name, mf)); ++ + pScsiTm = (SCSITaskMgmt_t *) mf; +- pScsiTm->TargetID = id; +- pScsiTm->Bus = channel; +- pScsiTm->ChainOffset = 0; ++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; +- ++ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; ++ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; ++ pScsiTm->TargetID = 0; ++ pScsiTm->Bus = 0; ++ pScsiTm->ChainOffset = 0; + pScsiTm->Reserved = 0; +- pScsiTm->TaskType = type; + pScsiTm->Reserved1 = 0; +- pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) +- ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; +- +- int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); +- ++ pScsiTm->TaskMsgContext = 0; ++ for (ii= 0; ii < 8; ii++) ++ pScsiTm->LUN[ii] = 0; + for (ii=0; ii < 7; ii++) + pScsiTm->Reserved2[ii] = 0; + +- pScsiTm->TaskMsgContext = ctx2abort; +- +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " +- "type=%d\n", ioc->name, ctx2abort, type)); ++ switch (ioc->bus_type) { ++ case FC: ++ timeout = 40; ++ break; ++ case SAS: ++ timeout = 30; ++ break; ++ case SPI: ++ default: ++ timeout = 2; ++ break; ++ } + +- DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", ++ ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); + ++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status) ++ retval = 0; ++ time_count = jiffies; + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); + else { + retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); +- if (retval) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!" +- " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd, +- ioc, mf, retval)); +- goto fail_out; ++ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); ++ if (retval != 0) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!" ++ " (ioc %p, mf %p, rc=%d) \n", ioc->name, ++ ioc, mf, retval)); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ goto out; + } + } + +- if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!" +- " (hd %p, ioc %p, mf %p) \n", ioc->name, hd, +- ioc, mf)); +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", +- ioc->name)); +- retval = mpt_HardResetHandler(ioc, CAN_SLEEP); +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n", +- ioc->name, retval)); +- goto fail_out; ++ /* Now wait for the command to complete */ ++ ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt failed\n", ioc->name)); ++ mpt_free_msg_frame(ioc, mf); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ retval = -1; /* return failure */ ++ goto out; + } + +- /* +- * Handle success case, see if theres a non-zero ioc_status. +- */ +- if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || +- hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || +- hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) +- retval = 0; +- else +- retval = FAILED; ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt failed\n", ioc->name)); ++ retval = -1; /* return failure */ ++ goto out; ++ } + +- return retval; ++ pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n" ++ "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n" ++ "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus, ++ pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, ++ le16_to_cpu(pScsiTmReply->IOCStatus), ++ le32_to_cpu(pScsiTmReply->IOCLogInfo), ++ pScsiTmReply->ResponseCode, ++ le32_to_cpu(pScsiTmReply->TerminationCount))); + +- fail_out: ++ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + +- /* +- * Free task management mf, and corresponding tm flags +- */ +- mpt_free_msg_frame(ioc, mf); +- hd->tmPending = 0; +- hd->tmState = TM_STATE_NONE; +- return FAILED; ++ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || ++ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED || ++ iocstatus == MPI_IOCSTATUS_SUCCESS) ++ retval = 0; ++ else { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt failed\n", ioc->name)); ++ retval = -1; /* return failure */ ++ } ++ ++ out: ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ return retval; + } + +-static int +-mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) ++int ++mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) + { +- switch (ioc->bus_type) { +- case FC: +- return 40; +- case SAS: +- return 10; ++ MPT_SCSI_HOST *hd; ++ ++ if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL)) ++ return 0; ++ ++ switch (reset_phase) { ++ case MPT_IOC_SETUP_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ break; ++ case MPT_IOC_PRE_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ hd = shost_priv(ioc->sh); ++ mptscsih_flush_running_cmds(hd); ++ break; ++ case MPT_IOC_POST_RESET: ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ ioc->internal_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ complete(&ioc->internal_cmds.done); ++ } ++ break; ++ default: ++ break; ++ } ++ return 1; /* currently means nothing really */ ++} ++ ++void ++mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) ++{ ++ char *desc; ++ ++ switch (response_code) { ++ case MPI_SCSITASKMGMT_RSP_TM_COMPLETE: ++ desc = "The task completed."; ++ break; ++ case MPI_SCSITASKMGMT_RSP_INVALID_FRAME: ++ desc = "The IOC received an invalid frame status."; ++ break; ++ case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: ++ desc = "The task type is not supported."; ++ break; ++ case MPI_SCSITASKMGMT_RSP_TM_FAILED: ++ desc = "The requested task failed."; ++ break; ++ case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED: ++ desc = "The task completed successfully."; ++ break; ++ case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN: ++ desc = "The LUN request is invalid."; ++ break; ++ case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: ++ desc = "The task is in the IOC queue and has not been sent to target."; ++ break; ++ default: ++ desc = "unknown"; ++ break; ++ } ++ printk(MYIOC_s_DEBUG_FMT "Response Code(0x%08x): F/W: %s\n", ++ ioc->name, response_code, desc); ++} ++ ++static int ++mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply) ++{ ++ u16 iocstatus; ++ u32 termination_count; ++ int retval; ++ ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { ++ retval = FAILED; ++ goto out; ++ } ++ ++ DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); ++ ++ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n" ++ "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n" ++ "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus, ++ pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus), ++ le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode, ++ termination_count)); ++ ++ if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && ++ pScsiTmReply->ResponseCode) ++ mptscsih_taskmgmt_response_code(ioc, ++ pScsiTmReply->ResponseCode); ++ ++ if (iocstatus == MPI_IOCSTATUS_SUCCESS) { ++ retval = 0; ++ goto out; ++ } ++ ++ retval = FAILED; ++ if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { ++ if (termination_count == 1) ++ retval = 0; ++ goto out; ++ } ++ ++ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || ++ iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) ++ retval = 0; ++ ++ out: ++ return retval; ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/** ++ * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @mf: Pointer to SCSI task mgmt request frame ++ * @mr: Pointer to SCSI task mgmt reply frame ++ * ++ * This routine is called from mptbase.c::mpt_interrupt() at the completion ++ * of any SCSI task management request. ++ * This routine is registered with the MPT (base) driver at driver ++ * load/init time via the mpt_register() API call. ++ * ++ * Returns 1 indicating alloc'd request frame ptr should be freed. ++ **/ ++int ++mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ++{ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n", ++ ioc->name, mf, mr)); ++ ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ++ ++ if (!mr) ++ goto out; ++ ++ ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; ++ memcpy(ioc->taskmgmt_cmds.reply, mr, ++ min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); ++ out: ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->taskmgmt_cmds.done); ++ return 1; ++ } ++ return 0; ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/** ++ * mptscsih_IssueTaskMgmt - Generic send Task Management function. ++ * @hd: Pointer to MPT_SCSI_HOST structure ++ * @type: Task Management type ++ * @channel: channel number for task management ++ * @id: Logical Target ID for reset (if appropriate) ++ * @lun: Logical Unit for reset (if appropriate) ++ * @ctx2abort: Context for the task to be aborted (if appropriate) ++ * @timeout: timeout for task management control ++ * ++ * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) ++ * or a non-interrupt thread. In the former, must not call schedule(). ++ * ++ * Not all fields are meaningfull for all task types. ++ * ++ * Returns 0 for SUCCESS, or FAILED. ++ * ++ **/ ++int ++mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) ++{ ++ MPT_FRAME_HDR *mf = NULL; ++ SCSITaskMgmt_t *pScsiTm; ++ int ii; ++ int retval; ++ MPT_ADAPTER *ioc = hd->ioc; ++ unsigned long timeleft; ++ u8 issue_hard_reset; ++ u32 ioc_raw_state; ++ unsigned long time_count; ++ ++ issue_hard_reset = 0; ++ ioc_raw_state = mpt_GetIocState(ioc, 0); ++ ++ if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { ++ printk(MYIOC_s_WARN_FMT ++ "TaskMgmt type=%x: IOC Not operational (0x%x)!\n", ++ ioc->name, type, ioc_raw_state); ++ printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) ++ printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset " ++ "FAILED!!\n", ioc->name); ++ return 0; ++ } ++ ++ if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { ++ printk(MYIOC_s_WARN_FMT ++ "TaskMgmt type=%x: ioc_state: " ++ "DOORBELL_ACTIVE (0x%x)!\n", ++ ioc->name, type, ioc_raw_state); ++ return FAILED; ++ } ++ ++ mutex_lock(&ioc->taskmgmt_cmds.mutex); ++ if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ retval = FAILED; ++ goto out; ++ } ++ ++ /* Return Fail to calling function if no message frames available. ++ */ ++ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt no msg frames!!\n", ++ ioc->name)); ++ retval = FAILED; ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ goto out; ++ } ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", ++ ioc->name, mf)); ++ ++ /* Format the Request ++ */ ++ pScsiTm = (SCSITaskMgmt_t *) mf; ++ pScsiTm->TargetID = id; ++ pScsiTm->Bus = channel; ++ pScsiTm->ChainOffset = 0; ++ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; ++ ++ pScsiTm->Reserved = 0; ++ pScsiTm->TaskType = type; ++ pScsiTm->Reserved1 = 0; ++ pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) ++ ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; ++ ++ int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); ++ ++ for (ii=0; ii < 7; ii++) ++ pScsiTm->Reserved2[ii] = 0; ++ ++ pScsiTm->TaskMsgContext = ctx2abort; ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) " ++ "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort, ++ type, timeout)); ++ ++ DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); ++ ++ INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ time_count = jiffies; ++ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && ++ (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) ++ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); ++ else { ++ retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, ++ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); ++ if (retval) { ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt handshake FAILED!" ++ " (mf=%p, rc=%d) \n", ioc->name, mf, retval)); ++ mpt_free_msg_frame(ioc, mf); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ goto out; ++ } ++ } ++ ++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); ++ if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ retval = FAILED; ++ dtmprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf)); ++ mpt_clear_taskmgmt_in_progress_flag(ioc); ++ if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out; ++ issue_hard_reset = 1; ++ goto out; ++ } ++ ++ retval = mptscsih_taskmgmt_reply(ioc, type, ++ (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply); ++ ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt completed (%d seconds)\n", ++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000)); ++ ++ out: ++ ++ CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) ++ if(issue_hard_reset) { ++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) ++ retval = mpt_HardResetHandler(ioc, CAN_SLEEP); ++ mpt_free_msg_frame(ioc, mf); ++ } ++ ++ retval = (retval == 0) ? 0 : FAILED; ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ return retval; ++} ++ ++static int ++mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) ++{ ++ switch (ioc->bus_type) { ++ case FC: ++ return 40; ++ case SAS: ++ return 30; + case SPI: + default: +- return 2; ++ return 10; + } + } + +@@ -1786,7 +1973,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) + int retval; + VirtDevice *vdevice; + ulong sn = SCpnt->serial_number; +- MPT_ADAPTER *ioc; ++ MPT_ADAPTER *ioc; + + /* If we can't locate our host adapter structure, return FAILED status. + */ +@@ -1810,7 +1997,21 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) + ioc->name, SCpnt)); + SCpnt->result = DID_NO_CONNECT << 16; + SCpnt->scsi_done(SCpnt); +- retval = 0; ++ retval = SUCCESS; ++ goto out; ++ } ++ ++ /* Find this command ++ */ ++ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) { ++ /* Cmd not found in ScsiLookup. ++ * Do OS callback. ++ */ ++ SCpnt->result = DID_RESET << 16; ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "task abort: command not in the active list! (sc=%p)\n", ++ ioc->name, SCpnt)); ++ retval = SUCCESS; + goto out; + } + +@@ -1825,27 +2026,23 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) + goto out; + } + +- /* Find this command ++ /* Task aborts are not supported for volumes. + */ +- if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) { +- /* Cmd not found in ScsiLookup. +- * Do OS callback. +- */ ++ if (vdevice->vtarget->raidVolume) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "task abort: raid volume (sc=%p)\n", ++ ioc->name, SCpnt)); + SCpnt->result = DID_RESET << 16; +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: " +- "Command not in the active list! (sc=%p)\n", ioc->name, +- SCpnt)); +- retval = 0; +- goto out; +- } +- +- if (hd->resetPending) { + retval = FAILED; + goto out; + } + +- if (hd->timeouts < -1) +- hd->timeouts++; ++ if(mpt_fwfault_debug) ++ mpt_halt_firmware(ioc); ++ ++ if (ioc->timeouts < -1) ++ ioc->timeouts++; ++ + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) +@@ -1856,25 +2053,31 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) + */ + mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx); + ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; +- +- hd->abortSCpnt = SCpnt; +- +- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, ++ mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, + vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, + ctx2abort, mptscsih_get_tm_timeout(ioc)); + ++ /* check to see whether command actually completed and/or ++ * terminated ++ */ + if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && +- SCpnt->serial_number == sn) ++ SCpnt->serial_number == sn) { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "task abort: command still in active list! (sc=%p)\n", ++ ioc->name, SCpnt)); + retval = FAILED; ++ } else { ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "task abort: command cleared from active list! (sc=%p)\n", ++ ioc->name, SCpnt)); ++ retval = SUCCESS; ++ } + + out: + printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", +- ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); ++ ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt); + +- if (retval == 0) +- return SUCCESS; +- else +- return FAILED; ++ return retval; + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -1907,14 +2110,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SC + ioc->name, SCpnt); + scsi_print_command(SCpnt); + +- if (hd->resetPending) { +- retval = FAILED; +- goto out; +- } +- + vdevice = SCpnt->device->hostdata; + if (!vdevice || !vdevice->vtarget) { +- retval = 0; ++ retval = SUCCESS; + goto out; + } + +@@ -1925,12 +2123,12 @@ mptscsih_dev_reset(struct scsi_cmnd * SC + goto out; + } + +- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, +- vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0, +- mptscsih_get_tm_timeout(ioc)); ++ retval = mptscsih_IssueTaskMgmt(hd, ++ MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, vdevice->vtarget->channel, ++ vdevice->vtarget->id, 0, 0, mptscsih_get_tm_timeout(ioc)); + + out: +- printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", ++ printk(MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", + ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + + if (retval == 0) +@@ -1955,12 +2153,12 @@ mptscsih_bus_reset(struct scsi_cmnd * SC + MPT_SCSI_HOST *hd; + int retval; + VirtDevice *vdevice; +- MPT_ADAPTER *ioc; ++ MPT_ADAPTER *ioc; + + /* If we can't locate our host adapter structure, return FAILED status. + */ + if ((hd = shost_priv(SCpnt->device->host)) == NULL){ +- printk(KERN_ERR MYNAM ": bus reset: " ++ printk(KERN_ERR MYNAM ": bus_reset: " + "Can't locate host! (sc=%p)\n", SCpnt); + return FAILED; + } +@@ -1970,11 +2168,13 @@ mptscsih_bus_reset(struct scsi_cmnd * SC + ioc->name, SCpnt); + scsi_print_command(SCpnt); + +- if (hd->timeouts < -1) +- hd->timeouts++; ++ if (ioc->timeouts < -1) ++ ioc->timeouts++; + + vdevice = SCpnt->device->hostdata; +- retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, ++ if (!vdevice || !vdevice->vtarget) ++ return SUCCESS; ++ retval = mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); + + printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n", +@@ -1999,8 +2199,9 @@ int + mptscsih_host_reset(struct scsi_cmnd *SCpnt) + { + MPT_SCSI_HOST * hd; +- int retval; +- MPT_ADAPTER *ioc; ++ int status = SUCCESS; ++ MPT_ADAPTER *ioc; ++ int retval; + + /* If we can't locate the host to reset, then we failed. */ + if ((hd = shost_priv(SCpnt->device->host)) == NULL){ +@@ -2011,237 +2212,29 @@ mptscsih_host_reset(struct scsi_cmnd *SC + + ioc = hd->ioc; + printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n", +- ioc->name, SCpnt); ++ ioc->name, SCpnt); + + /* If our attempts to reset the host failed, then return a failed + * status. The host will be taken off line by the SCSI mid-layer. + */ +- if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) { +- retval = FAILED; +- } else { +- /* Make sure TM pending is cleared and TM state is set to +- * NONE. +- */ +- retval = 0; +- hd->tmPending = 0; +- hd->tmState = TM_STATE_NONE; +- } ++ if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) ++ retval = mpt_HardResetHandler(ioc, CAN_SLEEP); ++ ++ if (retval < 0) ++ status = FAILED; ++ else ++ status = SUCCESS; + + printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n", + ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + +- return retval; +-} +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mptscsih_tm_pending_wait - wait for pending task management request to complete +- * @hd: Pointer to MPT host structure. +- * +- * Returns {SUCCESS,FAILED}. +- */ +-static int +-mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) +-{ +- unsigned long flags; +- int loop_count = 4 * 10; /* Wait 10 seconds */ +- int status = FAILED; +- MPT_ADAPTER *ioc = hd->ioc; +- +- do { +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- if (hd->tmState == TM_STATE_NONE) { +- hd->tmState = TM_STATE_IN_PROGRESS; +- hd->tmPending = 1; +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- status = SUCCESS; +- break; +- } +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- msleep(250); +- } while (--loop_count); +- + return status; + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mptscsih_tm_wait_for_completion - wait for completion of TM task +- * @hd: Pointer to MPT host structure. +- * @timeout: timeout value +- * +- * Returns {SUCCESS,FAILED}. +- */ +-static int +-mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) +-{ +- unsigned long flags; +- int loop_count = 4 * timeout; +- int status = FAILED; +- MPT_ADAPTER *ioc = hd->ioc; +- +- do { +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- if(hd->tmPending == 0) { +- status = SUCCESS; +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- break; +- } +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- msleep(250); +- } while (--loop_count); +- +- return status; +-} +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-static void +-mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) +-{ +- char *desc; +- +- switch (response_code) { +- case MPI_SCSITASKMGMT_RSP_TM_COMPLETE: +- desc = "The task completed."; +- break; +- case MPI_SCSITASKMGMT_RSP_INVALID_FRAME: +- desc = "The IOC received an invalid frame status."; +- break; +- case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: +- desc = "The task type is not supported."; +- break; +- case MPI_SCSITASKMGMT_RSP_TM_FAILED: +- desc = "The requested task failed."; +- break; +- case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED: +- desc = "The task completed successfully."; +- break; +- case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN: +- desc = "The LUN request is invalid."; +- break; +- case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: +- desc = "The task is in the IOC queue and has not been sent to target."; +- break; +- default: +- desc = "unknown"; +- break; +- } +- printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", +- ioc->name, response_code, desc); +-} +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/** +- * mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver +- * @ioc: Pointer to MPT_ADAPTER structure +- * @mf: Pointer to SCSI task mgmt request frame +- * @mr: Pointer to SCSI task mgmt reply frame +- * +- * This routine is called from mptbase.c::mpt_interrupt() at the completion +- * of any SCSI task management request. +- * This routine is registered with the MPT (base) driver at driver +- * load/init time via the mpt_register() API call. +- * +- * Returns 1 indicating alloc'd request frame ptr should be freed. +- **/ +-int +-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +-{ +- SCSITaskMgmtReply_t *pScsiTmReply; +- SCSITaskMgmt_t *pScsiTmReq; +- MPT_SCSI_HOST *hd; +- unsigned long flags; +- u16 iocstatus; +- u8 tmType; +- u32 termination_count; +- +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", +- ioc->name, mf, mr)); +- if (!ioc->sh) { +- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT +- "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); +- return 1; +- } +- +- if (mr == NULL) { +- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT +- "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); +- return 1; +- } +- +- hd = shost_priv(ioc->sh); +- pScsiTmReply = (SCSITaskMgmtReply_t*)mr; +- pScsiTmReq = (SCSITaskMgmt_t*)mf; +- tmType = pScsiTmReq->TaskType; +- iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; +- termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); +- +- if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && +- pScsiTmReply->ResponseCode) +- mptscsih_taskmgmt_response_code(ioc, +- pScsiTmReply->ResponseCode); +- DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); +- +-#ifdef CONFIG_FUSION_LOGGING +- if ((ioc->debug_level & MPT_DEBUG_REPLY) || +- (ioc->debug_level & MPT_DEBUG_TM )) +- printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " +- "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " +- "term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus, +- pScsiTmReply->TargetID, pScsiTmReq->TaskType, +- le16_to_cpu(pScsiTmReply->IOCStatus), +- le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, +- le32_to_cpu(pScsiTmReply->TerminationCount)); +-#endif +- if (!iocstatus) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name)); +- hd->abortSCpnt = NULL; +- goto out; +- } +- +- /* Error? (anything non-zero?) */ +- +- /* clear flags and continue. +- */ +- switch (tmType) { +- +- case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: +- if (termination_count == 1) +- iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED; +- hd->abortSCpnt = NULL; +- break; +- +- case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: +- +- /* If an internal command is present +- * or the TM failed - reload the FW. +- * FC FW may respond FAILED to an ABORT +- */ +- if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || +- hd->cmdPtr) +- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) +- printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name); +- break; +- +- case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: +- default: +- break; +- } +- +- out: +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- hd->tmPending = 0; +- hd->tmState = TM_STATE_NONE; +- hd->tm_iocstatus = iocstatus; +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- +- return 1; +-} +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* + * This is anyones guess quite frankly. +- */ ++ **/ + int + mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, + sector_t capacity, int geom[]) +@@ -2278,40 +2271,82 @@ mptscsih_bios_param(struct scsi_device * + return 0; + } + +-/* Search IOC page 3 to determine if this is hidden physical disk ++/** ++ * Search IOC page 3 to determine if this is hidden physical disk + * +- */ ++ **/ + int + mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) + { + struct inactive_raid_component_info *component_info; +- int i; ++ u8 i, j; ++ RaidPhysDiskPage1_t *phys_disk; + int rc = 0; ++ int num_paths; + + if (!ioc->raid_data.pIocPg3) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && +- (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { ++ (channel == ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = 1; + goto out; + } + } + ++ if (ioc->bus_type != SAS) ++ goto out; ++ ++ /* ++ * Check if dual path ++ */ ++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { ++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc, ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); ++ if (num_paths < 2) ++ continue; ++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); ++ if (!phys_disk) ++ continue; ++ if ((mpt_raid_phys_disk_pg1(ioc, ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, ++ phys_disk))) { ++ kfree(phys_disk); ++ continue; ++ } ++ for (j = 0; j < num_paths; j++) { ++ if ((phys_disk->Path[j].Flags & ++ MPI_RAID_PHYSDISK1_FLAG_INVALID)) ++ continue; ++ if ((phys_disk->Path[j].Flags & ++ MPI_RAID_PHYSDISK1_FLAG_BROKEN)) ++ continue; ++ if ((id == phys_disk->Path[j].PhysDiskID) && ++ (channel == phys_disk->Path[j].PhysDiskBus)) { ++ rc = 1; ++ kfree(phys_disk); ++ goto out; ++ } ++ } ++ kfree(phys_disk); ++ } ++ + /* + * Check inactive list for matching phys disks + */ + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + +- mutex_lock(&ioc->raid_data.inactive_list_mutex); ++ down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = 1; + } +- mutex_unlock(&ioc->raid_data.inactive_list_mutex); ++ up(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +@@ -2322,43 +2357,84 @@ u8 + mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) + { + struct inactive_raid_component_info *component_info; +- int i; ++ int i,j; ++ RaidPhysDiskPage1_t *phys_disk; + int rc = -ENXIO; ++ u8 num_paths; + + if (!ioc->raid_data.pIocPg3) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && +- (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { ++ (channel == ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; + goto out; + } + } + ++ if (ioc->bus_type != SAS) ++ goto out; ++ ++ /* ++ * Check if dual path ++ */ ++ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { ++ num_paths = mpt_raid_phys_disk_get_num_paths(ioc, ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); ++ if (num_paths < 2) ++ continue; ++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); ++ if (!phys_disk) ++ continue; ++ if ((mpt_raid_phys_disk_pg1(ioc, ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, ++ phys_disk))) { ++ kfree(phys_disk); ++ continue; ++ } ++ for (j = 0; j < num_paths; j++) { ++ if ((phys_disk->Path[j].Flags & ++ MPI_RAID_PHYSDISK1_FLAG_INVALID)) ++ continue; ++ if ((phys_disk->Path[j].Flags & ++ MPI_RAID_PHYSDISK1_FLAG_BROKEN)) ++ continue; ++ if ((id == phys_disk->Path[j].PhysDiskID) && ++ (channel == phys_disk->Path[j].PhysDiskBus)) { ++ rc = phys_disk->PhysDiskNum; ++ kfree(phys_disk); ++ goto out; ++ } ++ } ++ kfree(phys_disk); ++ } ++ + /* + * Check inactive list for matching phys disks + */ + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + +- mutex_lock(&ioc->raid_data.inactive_list_mutex); ++ down(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = component_info->d.PhysDiskNum; + } +- mutex_unlock(&ioc->raid_data.inactive_list_mutex); ++ up(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; + } + EXPORT_SYMBOL(mptscsih_raid_id_to_num); + +-/* ++/** + * OS entry point to allow for host driver to free allocated memory + * Called if no device present or device being unloaded +- */ ++ **/ + void + mptscsih_slave_destroy(struct scsi_device *sdev) + { +@@ -2370,23 +2446,25 @@ mptscsih_slave_destroy(struct scsi_devic + + starget = scsi_target(sdev); + vtarget = starget->hostdata; ++ vtarget->num_luns--; + vdevice = sdev->hostdata; ++ if (!vdevice) ++ return; + + mptscsih_search_running_cmds(hd, vdevice); +- vtarget->num_luns--; +- mptscsih_synchronize_cache(hd, vdevice); ++ mptscsih_synchronize_cache(sdev, hd, vdevice); + kfree(vdevice); + sdev->hostdata = NULL; + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptscsih_change_queue_depth - This function will set a devices queue depth + * @sdev: per scsi_device pointer + * @qdepth: requested queue depth + * + * Adding support for new 'change_queue_depth' api. +-*/ ++ **/ + int + mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) + { +@@ -2401,15 +2479,16 @@ mptscsih_change_queue_depth(struct scsi_ + vtarget = starget->hostdata; + + if (ioc->bus_type == SPI) { +- if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) +- max_depth = 1; +- else if (sdev->type == TYPE_DISK && +- vtarget->minSyncFactor <= MPT_ULTRA160) ++ if (sdev->type == TYPE_DISK && ++ vtarget->minSyncFactor <= MPT_ULTRA160) + max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; + else + max_depth = MPT_SCSI_CMD_PER_DEV_LOW; + } else +- max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; ++ max_depth = ioc->sh->can_queue; ++ ++ if (!sdev->tagged_supported) ++ max_depth = 1; + + if (qdepth > max_depth) + qdepth = max_depth; +@@ -2419,15 +2498,24 @@ mptscsih_change_queue_depth(struct scsi_ + tagged = MSG_SIMPLE_TAG; + + scsi_adjust_queue_depth(sdev, tagged, qdepth); ++ ++ if (sdev->inquiry_len > 7) ++ sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "qdepth=%d, " ++ "tagged=%d, simple=%d, ordered=%d, scsi_level=%d, " ++ "cmd_que=%d\n", ioc->name, sdev->queue_depth, ++ sdev->tagged_supported, sdev->simple_tags, ++ sdev->ordered_tags, sdev->scsi_level, ++ (sdev->inquiry[7] & 2) >> 1); ++ + return sdev->queue_depth; + } + +-/* ++/** + * OS entry point to adjust the queue_depths on a per-device basis. + * Called once per device the bus scan. Use it to force the queue_depth + * member to 1 if a device does not support Q tags. + * Return non-zero if fails. +- */ ++ **/ + int + mptscsih_slave_configure(struct scsi_device *sdev) + { +@@ -2436,52 +2524,37 @@ mptscsih_slave_configure(struct scsi_dev + VirtDevice *vdevice; + struct scsi_target *starget; + MPT_SCSI_HOST *hd = shost_priv(sh); +- MPT_ADAPTER *ioc = hd->ioc; ++ MPT_ADAPTER *ioc = hd->ioc; + + starget = scsi_target(sdev); + vtarget = starget->hostdata; + vdevice = sdev->hostdata; ++ vdevice->configured_lun = 1; + +- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "device @ %p, channel=%d, id=%d, lun=%d\n", +- ioc->name, sdev, sdev->channel, sdev->id, sdev->lun)); +- if (ioc->bus_type == SPI) +- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "sdtr %d wdtr %d ppr %d inq length=%d\n", +- ioc->name, sdev->sdtr, sdev->wdtr, +- sdev->ppr, sdev->inquiry_len)); ++ if ((ioc->bus_type != SAS) && (sdev->id > sh->max_id)) { ++ /* error case, should never happen */ ++ scsi_adjust_queue_depth(sdev, 0, 1); ++ goto slave_configure_exit; ++ } + +- vdevice->configured_lun = 1; +- mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); ++ mptscsih_change_queue_depth(sdev, ioc->sdev_queue_depth); + +- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Queue depth=%d, tflags=%x\n", +- ioc->name, sdev->queue_depth, vtarget->tflags)); +- +- if (ioc->bus_type == SPI) +- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", +- ioc->name, vtarget->negoFlags, vtarget->maxOffset, +- vtarget->minSyncFactor)); +- +- dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "tagged %d, simple %d, ordered %d\n", +- ioc->name,sdev->tagged_supported, sdev->simple_tags, +- sdev->ordered_tags)); ++slave_configure_exit: + + return 0; + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * Private routines... + */ + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* Utility function to copy sense data from the scsi_cmnd buffer ++/** ++ * Utility function to copy sense data from the scsi_cmnd buffer + * to the FC and SCSI target structures. + * +- */ ++ **/ + static void + mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) + { +@@ -2521,31 +2594,31 @@ mptscsih_copy_sense_data(struct scsi_cmn + ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12]; + + ioc->eventContext++; +- if (ioc->pcidev->vendor == +- PCI_VENDOR_ID_IBM) { +- mptscsih_issue_sep_command(ioc, +- vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); +- vdevice->vtarget->tflags |= +- MPT_TARGET_FLAGS_LED_ON; ++ if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) { ++ mptscsih_issue_sep_command(ioc, vdevice->vtarget, ++ MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); ++ vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON; + } + } + } + } else { + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n", +- ioc->name)); ++ ioc->name)); + } + } + + /** + * mptscsih_get_scsi_lookup +- * @ioc: Pointer to MPT_ADAPTER structure +- * @i: index into the array + * + * retrieves scmd entry from ScsiLookup[] array list + * ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @i: index into the array ++ * + * Returns the scsi_cmd pointer ++ * + **/ +-static struct scsi_cmnd * ++struct scsi_cmnd * + mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) + { + unsigned long flags; +@@ -2560,12 +2633,14 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *io + + /** + * mptscsih_getclear_scsi_lookup +- * @ioc: Pointer to MPT_ADAPTER structure +- * @i: index into the array + * + * retrieves and clears scmd entry from ScsiLookup[] array list + * ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @i: index into the array ++ * + * Returns the scsi_cmd pointer ++ * + **/ + static struct scsi_cmnd * + mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) +@@ -2602,10 +2677,14 @@ mptscsih_set_scsi_lookup(MPT_ADAPTER *io + } + + /** +- * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list ++ * SCPNT_TO_LOOKUP_IDX ++ * ++ * search's for a given scmd in the ScsiLookup[] array list ++ * + * @ioc: Pointer to MPT_ADAPTER structure +- * @sc: scsi_cmnd pointer +- */ ++ * @scmd: scsi_cmnd pointer ++ * ++ **/ + static int + SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc) + { +@@ -2627,380 +2706,226 @@ SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, st + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + int +-mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) ++mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) + { +- MPT_SCSI_HOST *hd; +- unsigned long flags; +- +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- ": IOC %s_reset routed to SCSI host driver!\n", +- ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( +- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); +- +- /* If a FW reload request arrives after base installed but +- * before all scsi hosts have been attached, then an alt_ioc +- * may have a NULL sh pointer. +- */ +- if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL) +- return 0; +- else +- hd = shost_priv(ioc->sh); +- +- if (reset_phase == MPT_IOC_SETUP_RESET) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name)); +- +- /* Clean Up: +- * 1. Set Hard Reset Pending Flag +- * All new commands go to doneQ +- */ +- hd->resetPending = 1; +- +- } else if (reset_phase == MPT_IOC_PRE_RESET) { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name)); +- +- /* 2. Flush running commands +- * Clean ScsiLookup (and associated memory) +- * AND clean mytaskQ +- */ ++ u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; + +- /* 2b. Reply to OS all known outstanding I/O commands. +- */ +- mptscsih_flush_running_cmds(hd); ++ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "MPT event (=%02Xh) routed to SCSI host driver!\n", ++ ioc->name, event)); + +- /* 2c. If there was an internal command that +- * has not completed, configuration or io request, +- * free these resources. +- */ +- if (hd->cmdPtr) { +- del_timer(&hd->timer); +- mpt_free_msg_frame(ioc, hd->cmdPtr); +- } ++ if ((event == MPI_EVENT_IOC_BUS_RESET || ++ event == MPI_EVENT_EXT_BUS_RESET) && ++ (ioc->bus_type == SPI) && (ioc->soft_resets < -1)) ++ ioc->soft_resets++; + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name)); ++ return 1; /* currently means nothing really */ ++} + +- } else { +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name)); ++int ++mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) ++{ ++ MPT_ADAPTER *ioc = hd->ioc; ++ MpiRaidActionRequest_t *pReq; ++ MPT_FRAME_HDR *mf; ++ int ret; ++ unsigned long timeleft; + +- /* Once a FW reload begins, all new OS commands are +- * redirected to the doneQ w/ a reset status. +- * Init all control structures. +- */ ++ mutex_lock(&ioc->internal_cmds.mutex); + +- /* 2. Chain Buffer initialization +- */ ++ /* Get and Populate a free Frame ++ */ ++ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { ++ dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!\n", ++ ioc->name, __FUNCTION__)); ++ ret = -EAGAIN; ++ goto out; ++ } ++ pReq = (MpiRaidActionRequest_t *)mf; ++ if (quiesce) ++ pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; ++ else ++ pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; ++ pReq->Reserved1 = 0; ++ pReq->ChainOffset = 0; ++ pReq->Function = MPI_FUNCTION_RAID_ACTION; ++ pReq->VolumeID = id; ++ pReq->VolumeBus = channel; ++ pReq->PhysDiskNum = 0; ++ pReq->MsgFlags = 0; ++ pReq->Reserved2 = 0; ++ pReq->ActionDataWord = 0; /* Reserved for this action */ + +- /* 4. Renegotiate to all devices, if SPI +- */ ++ ioc->add_sge((char *)&pReq->ActionDataSGE, ++ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); + +- /* 5. Enable new commands to be posted +- */ +- spin_lock_irqsave(&ioc->FreeQlock, flags); +- hd->tmPending = 0; +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- hd->resetPending = 0; +- hd->tmState = TM_STATE_NONE; ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", ++ ioc->name, pReq->Action, channel, id)); + +- /* 6. If there was an internal command, +- * wake this process up. +- */ +- if (hd->cmdPtr) { +- /* +- * Wake up the original calling thread +- */ +- hd->pLocal = &hd->localReply; +- hd->pLocal->completion = MPT_SCANDV_DID_RESET; +- hd->scandv_wait_done = 1; +- wake_up(&hd->scandv_waitq); +- hd->cmdPtr = NULL; ++ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) ++ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ); ++ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ ret = -ETIME; ++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n", ++ ioc->name, __FUNCTION__)); ++ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out; ++ if (!timeleft) { ++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ mpt_free_msg_frame(ioc, mf); + } +- +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name)); +- ++ goto out; + } + +- return 1; /* currently means nothing really */ ++ ret = ioc->internal_cmds.completion_code; ++ ++ out: ++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status) ++ mutex_unlock(&ioc->internal_cmds.mutex); ++ return ret; + } + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-int +-mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) ++/** ++ * mptscsih_get_completion_code - ++ * @ioc: Pointer to MPT_ADAPTER structure ++ * @reply: ++ * @cmd: ++ * ++ **/ ++static int ++mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) + { +- MPT_SCSI_HOST *hd; +- u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; ++ SCSIIOReply_t *pReply; ++ MpiRaidActionReply_t *pr; ++ u8 scsi_status; ++ u16 status; ++ int completion_code; + +- devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", +- ioc->name, event)); ++ pReply = (SCSIIOReply_t *)reply; ++ status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ scsi_status = pReply->SCSIStatus; + +- if (ioc->sh == NULL || +- ((hd = shost_priv(ioc->sh)) == NULL)) +- return 1; ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", ++ ioc->name, status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo))); + +- switch (event) { +- case MPI_EVENT_UNIT_ATTENTION: /* 03 */ +- /* FIXME! */ +- break; +- case MPI_EVENT_IOC_BUS_RESET: /* 04 */ +- case MPI_EVENT_EXT_BUS_RESET: /* 05 */ +- if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1)) +- hd->soft_resets++; +- break; +- case MPI_EVENT_LOGOUT: /* 09 */ +- /* FIXME! */ ++ switch(status) { ++ ++ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ ++ completion_code = MPT_SCANDV_SELECTION_TIMEOUT; + break; + +- case MPI_EVENT_RESCAN: /* 06 */ ++ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ ++ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ ++ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ ++ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ ++ completion_code = MPT_SCANDV_DID_RESET; + break; + +- /* +- * CHECKME! Don't think we need to do +- * anything for these, but... +- */ +- case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ +- case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ +- /* +- * CHECKME! Falling thru... +- */ ++ case MPI_IOCSTATUS_BUSY: ++ case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: ++ completion_code = MPT_SCANDV_BUSY; + break; + +- case MPI_EVENT_INTEGRATED_RAID: /* 0B */ ++ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ ++ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ ++ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ ++ if (pReply->Function == MPI_FUNCTION_CONFIG) { ++ completion_code = MPT_SCANDV_GOOD; ++ } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { ++ pr = (MpiRaidActionReply_t *)reply; ++ if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) ++ completion_code = MPT_SCANDV_GOOD; ++ else ++ completion_code = MPT_SCANDV_SOME_ERROR; ++ } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) ++ completion_code = MPT_SCANDV_SENSE; ++ else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { ++ if (req->u.scsireq.CDB[0] == INQUIRY) ++ completion_code = MPT_SCANDV_ISSUE_SENSE; ++ else ++ completion_code = MPT_SCANDV_DID_RESET; ++ } ++ else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) ++ completion_code = MPT_SCANDV_DID_RESET; ++ else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) ++ completion_code = MPT_SCANDV_DID_RESET; ++ else if (scsi_status == MPI_SCSI_STATUS_BUSY) ++ completion_code = MPT_SCANDV_BUSY; ++ else ++ completion_code = MPT_SCANDV_GOOD; + break; + +- case MPI_EVENT_NONE: /* 00 */ +- case MPI_EVENT_LOG_DATA: /* 01 */ +- case MPI_EVENT_STATE_CHANGE: /* 02 */ +- case MPI_EVENT_EVENT_CHANGE: /* 0A */ ++ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ ++ if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) ++ completion_code = MPT_SCANDV_DID_RESET; ++ else ++ completion_code = MPT_SCANDV_SOME_ERROR; ++ break; + default: +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n", +- ioc->name, event)); ++ completion_code = MPT_SCANDV_SOME_ERROR; + break; +- } + +- return 1; /* currently means nothing really */ +-} ++ } /* switch(status) */ + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* +- * Bus Scan and Domain Validation functionality ... +- */ ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ " completionCode set to %08xh\n", ioc->name, completion_code)); ++ return completion_code; ++} + +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* +- * mptscsih_scandv_complete - Scan and DV callback routine registered +- * to Fustion MPT (base) driver. +- * ++/** ++ * mptscsih_scandv_complete - + * @ioc: Pointer to MPT_ADAPTER structure +- * @mf: Pointer to original MPT request frame +- * @mr: Pointer to MPT reply frame (NULL if TurboReply) ++ * @req: ++ * @reply: + * +- * This routine is called from mpt.c::mpt_interrupt() at the completion +- * of any SCSI IO request. +- * This routine is registered with the Fusion MPT (base) driver at driver +- * load/init time via the mpt_register() API call. +- * +- * Returns 1 indicating alloc'd request frame ptr should be freed. +- * +- * Remark: Sets a completion code and (possibly) saves sense data +- * in the IOC member localReply structure. +- * Used ONLY for DV and other internal commands. +- */ ++ **/ + int +-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ++mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) + { +- MPT_SCSI_HOST *hd; + SCSIIORequest_t *pReq; +- int completionCode; ++ SCSIIOReply_t *pReply; ++ u8 cmd; + u16 req_idx; ++ u8 *sense_data; ++ int sz; + +- hd = shost_priv(ioc->sh); +- +- if ((mf == NULL) || +- (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { +- printk(MYIOC_s_ERR_FMT +- "ScanDvComplete, %s req frame ptr! (=%p)\n", +- ioc->name, mf?"BAD":"NULL", (void *) mf); +- goto wakeup; +- } +- +- del_timer(&hd->timer); +- req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); +- mptscsih_set_scsi_lookup(ioc, req_idx, NULL); +- pReq = (SCSIIORequest_t *) mf; ++ ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; ++ ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD; ++ if (!reply) ++ goto out; + +- if (mf != hd->cmdPtr) { +- printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", +- ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); ++ pReply = (SCSIIOReply_t *) reply; ++ pReq = (SCSIIORequest_t *) req; ++ ioc->internal_cmds.completion_code = ++ mptscsih_get_completion_code(ioc, req, reply); ++ ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID; ++ memcpy(ioc->internal_cmds.reply, reply, ++ min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength)); ++ cmd = reply->u.hdr.Function; ++ if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || ++ (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) && ++ (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) { ++ req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); ++ sense_data = ((u8 *)ioc->sense_buf_pool + ++ (req_idx * MPT_SENSE_BUFFER_ALLOC)); ++ sz = min_t(int, pReq->SenseBufferLength, ++ MPT_SENSE_BUFFER_ALLOC); ++ memcpy(ioc->internal_cmds.sense, sense_data, sz); + } +- hd->cmdPtr = NULL; +- +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", +- ioc->name, mf, mr, req_idx)); +- +- hd->pLocal = &hd->localReply; +- hd->pLocal->scsiStatus = 0; +- +- /* If target struct exists, clear sense valid flag. +- */ +- if (mr == NULL) { +- completionCode = MPT_SCANDV_GOOD; +- } else { +- SCSIIOReply_t *pReply; +- u16 status; +- u8 scsi_status; +- +- pReply = (SCSIIOReply_t *) mr; +- +- status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; +- scsi_status = pReply->SCSIStatus; +- +- +- switch(status) { +- +- case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ +- completionCode = MPT_SCANDV_SELECTION_TIMEOUT; +- break; +- +- case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ +- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ +- case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ +- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ +- completionCode = MPT_SCANDV_DID_RESET; +- break; +- +- case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ +- case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ +- case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ +- if (pReply->Function == MPI_FUNCTION_CONFIG) { +- ConfigReply_t *pr = (ConfigReply_t *)mr; +- completionCode = MPT_SCANDV_GOOD; +- hd->pLocal->header.PageVersion = pr->Header.PageVersion; +- hd->pLocal->header.PageLength = pr->Header.PageLength; +- hd->pLocal->header.PageNumber = pr->Header.PageNumber; +- hd->pLocal->header.PageType = pr->Header.PageType; +- +- } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { +- /* If the RAID Volume request is successful, +- * return GOOD, else indicate that +- * some type of error occurred. +- */ +- MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; +- if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) +- completionCode = MPT_SCANDV_GOOD; +- else +- completionCode = MPT_SCANDV_SOME_ERROR; +- memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense)); +- +- } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { +- u8 *sense_data; +- int sz; +- +- /* save sense data in global structure +- */ +- completionCode = MPT_SCANDV_SENSE; +- hd->pLocal->scsiStatus = scsi_status; +- sense_data = ((u8 *)ioc->sense_buf_pool + +- (req_idx * MPT_SENSE_BUFFER_ALLOC)); +- +- sz = min_t(int, pReq->SenseBufferLength, +- SCSI_STD_SENSE_BYTES); +- memcpy(hd->pLocal->sense, sense_data, sz); +- +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n", +- ioc->name, sense_data)); +- } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { +- if (pReq->CDB[0] == INQUIRY) +- completionCode = MPT_SCANDV_ISSUE_SENSE; +- else +- completionCode = MPT_SCANDV_DID_RESET; +- } +- else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) +- completionCode = MPT_SCANDV_DID_RESET; +- else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) +- completionCode = MPT_SCANDV_DID_RESET; +- else { +- completionCode = MPT_SCANDV_GOOD; +- hd->pLocal->scsiStatus = scsi_status; +- } +- break; +- +- case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ +- if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) +- completionCode = MPT_SCANDV_DID_RESET; +- else +- completionCode = MPT_SCANDV_SOME_ERROR; +- break; +- +- default: +- completionCode = MPT_SCANDV_SOME_ERROR; +- break; +- +- } /* switch(status) */ +- +- } /* end of address reply case */ +- +- hd->pLocal->completion = completionCode; +- +- /* MF and RF are freed in mpt_interrupt +- */ +-wakeup: +- /* Free Chain buffers (will never chain) in scan or dv */ +- //mptscsih_freeChainBuffers(ioc, req_idx); +- +- /* +- * Wake up the original calling thread +- */ +- hd->scandv_wait_done = 1; +- wake_up(&hd->scandv_waitq); +- ++ out: ++ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING)) ++ return 0; ++ ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING; ++ complete(&ioc->internal_cmds.done); + return 1; + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* mptscsih_timer_expired - Call back for timer process. +- * Used only for dv functionality. +- * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long +- * +- */ +-void +-mptscsih_timer_expired(unsigned long data) +-{ +- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; +- MPT_ADAPTER *ioc = hd->ioc; +- +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr)); +- +- if (hd->cmdPtr) { +- MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; +- +- if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { +- /* Desire to issue a task management request here. +- * TM requests MUST be single threaded. +- * If old eh code and no TM current, issue request. +- * If new eh code, do nothing. Wait for OS cmd timeout +- * for bus reset. +- */ +- } else { +- /* Perform a FW reload */ +- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { +- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); +- } +- } +- } else { +- /* This should NEVER happen */ +- printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name); +- } +- +- /* No more processing. +- * TM call will generate an interrupt for SCSI TM Management. +- * The FW will reply to all outstanding commands, callback will finish cleanup. +- * Hard reset clean-up will free all resources. +- */ +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name)); +- +- return; +-} +- +- +-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptscsih_do_cmd - Do internal command. + * @hd: MPT_SCSI_HOST pointer +@@ -3019,28 +2944,33 @@ mptscsih_timer_expired(unsigned long dat + * 0 if good + * + * > 0 if command complete but some type of completion error. +- */ +-static int ++ **/ ++int + mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) + { + MPT_FRAME_HDR *mf; + SCSIIORequest_t *pScsiReq; +- SCSIIORequest_t ReqCopy; + int my_idx, ii, dir; +- int rc, cmdTimeout; +- int in_isr; ++ int timeout; + char cmdLen; + char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +- char cmd = io->cmd; +- MPT_ADAPTER *ioc = hd->ioc; ++ u8 cmd = io->cmd; ++ MPT_ADAPTER *ioc = hd->ioc; ++ int ret = 0; ++ unsigned long timeleft; ++ unsigned long flags; + +- in_isr = in_interrupt(); +- if (in_isr) { +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n", +- ioc->name)); +- return -EPERM; ++ /* don't send internal command during diag reset */ ++ spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ if (ioc->ioc_reset_in_progress) { ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: busy with host reset\n", ioc->name, __FUNCTION__)); ++ return MPT_SCANDV_BUSY; + } ++ spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + ++ mutex_lock(&ioc->internal_cmds.mutex); + + /* Set command specific information + */ +@@ -3050,13 +2980,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + CDB[4] = io->size; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case TEST_UNIT_READY: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case START_STOP: +@@ -3064,7 +2994,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + CDB[4] = 1; /*Spin up the disk */ +- cmdTimeout = 15; ++ timeout = 15; + break; + + case REQUEST_SENSE: +@@ -3072,7 +3002,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + CDB[0] = cmd; + CDB[4] = io->size; + dir = MPI_SCSIIO_CONTROL_READ; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case READ_BUFFER: +@@ -3091,7 +3021,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + CDB[6] = (io->size >> 16) & 0xFF; + CDB[7] = (io->size >> 8) & 0xFF; + CDB[8] = io->size & 0xFF; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case WRITE_BUFFER: +@@ -3106,21 +3036,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + CDB[6] = (io->size >> 16) & 0xFF; + CDB[7] = (io->size >> 8) & 0xFF; + CDB[8] = io->size & 0xFF; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case RESERVE: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case RELEASE: + cmdLen = 6; + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; +- cmdTimeout = 10; ++ timeout = 10; + break; + + case SYNCHRONIZE_CACHE: +@@ -3128,20 +3058,42 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + dir = MPI_SCSIIO_CONTROL_READ; + CDB[0] = cmd; + // CDB[1] = 0x02; /* set immediate bit */ +- cmdTimeout = 10; ++ timeout = 10; ++ break; ++ ++ case REPORT_LUNS: ++ cmdLen = 12; ++ dir = MPI_SCSIIO_CONTROL_READ; ++ CDB[0] = cmd; ++ CDB[6] = (io->size >> 24) & 0xFF; ++ CDB[7] = (io->size >> 16) & 0xFF; ++ CDB[8] = (io->size >> 8) & 0xFF; ++ CDB[9] = io->size & 0xFF; ++ timeout = 10; ++ break; ++ ++ case TRANSPORT_LAYER_RETRIES: ++ CDB[0] = cmd; ++ CDB[1] = 0x01; ++ cmdLen = 6; ++ dir = MPI_SCSIIO_CONTROL_READ; ++ timeout = 10; + break; + + default: + /* Error Case */ +- return -EFAULT; ++ ret = -EFAULT; ++ goto out; + } + + /* Get and Populate a free Frame ++ * MsgContext set in mpt_get_msg_frame call + */ + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { +- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n", +- ioc->name)); +- return -EBUSY; ++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n", ++ ioc->name, __FUNCTION__)); ++ ret = MPT_SCANDV_BUSY; ++ goto out; + } + + pScsiReq = (SCSIIORequest_t *) mf; +@@ -3164,14 +3116,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + + pScsiReq->CDBLength = cmdLen; + pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; +- + pScsiReq->Reserved = 0; +- +- pScsiReq->MsgFlags = mpt_msg_flags(); +- /* MsgContext set in mpt_get_msg_fram call */ ++ pScsiReq->MsgFlags = mpt_msg_flags(ioc); + + int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN); +- + if (io->flags & MPT_ICFLAG_TAGGED_CMD) + pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ); + else +@@ -3179,74 +3127,61 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + + if (cmd == REQUEST_SENSE) { + pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n", +- ioc->name, cmd)); ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: Untagged! 0x%02x\n", ioc->name, __FUNCTION__, cmd)); + } + +- for (ii=0; ii < 16; ii++) +- pScsiReq->CDB[ii] = CDB[ii]; ++ for (ii = 0; ii < 16; ii++) ++ pScsiReq->CDB[ii] = CDB[ii]; + + pScsiReq->DataLength = cpu_to_le32(io->size); + pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + + (my_idx * MPT_SENSE_BUFFER_ALLOC)); + +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n", +- ioc->name, cmd, io->channel, io->id, io->lun)); +- +- if (dir == MPI_SCSIIO_CONTROL_READ) { +- mpt_add_sge((char *) &pScsiReq->SGL, +- MPT_SGE_FLAGS_SSIMPLE_READ | io->size, +- io->data_dma); +- } else { +- mpt_add_sge((char *) &pScsiReq->SGL, +- MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, +- io->data_dma); +- } +- +- /* The ISR will free the request frame, but we need +- * the information to initialize the target. Duplicate. +- */ +- memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t)); +- +- /* Issue this command after: +- * finish init +- * add timer +- * Wait until the reply has been received +- * ScsiScanDvCtx callback function will +- * set hd->pLocal; +- * set scandv_wait_done and call wake_up +- */ +- hd->pLocal = NULL; +- hd->timer.expires = jiffies + HZ*cmdTimeout; +- hd->scandv_wait_done = 0; +- +- /* Save cmd pointer, for resource free if timeout or +- * FW reload occurs +- */ +- hd->cmdPtr = mf; ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n", ++ ioc->name, __FUNCTION__, cmd, io->channel, io->id, io->lun)); ++ ++ if (dir == MPI_SCSIIO_CONTROL_READ) ++ ioc->add_sge((char *) &pScsiReq->SGL, ++ MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma); ++ else ++ ioc->add_sge((char *) &pScsiReq->SGL, ++ MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma); + +- add_timer(&hd->timer); ++ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) + mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); +- wait_event(hd->scandv_waitq, hd->scandv_wait_done); +- +- if (hd->pLocal) { +- rc = hd->pLocal->completion; +- hd->pLocal->skip = 0; +- +- /* Always set fatal error codes in some cases. +- */ +- if (rc == MPT_SCANDV_SELECTION_TIMEOUT) +- rc = -ENXIO; +- else if (rc == MPT_SCANDV_SOME_ERROR) +- rc = -rc; +- } else { +- rc = -EFAULT; +- /* This should never happen. */ +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n", +- ioc->name)); ++ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, ++ timeout*HZ); ++ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ ret = MPT_SCANDV_DID_RESET; ++ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __FUNCTION__, ++ cmd)); ++ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ goto out; ++ } ++ if (!timeleft) { ++ if (!mptscsih_scandv_bus_reset(ioc)) ++ goto out; ++ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", ++ ioc->name, __FUNCTION__); ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ mpt_free_msg_frame(ioc, mf); ++ } ++ goto out; + } + +- return rc; ++ ret = ioc->internal_cmds.completion_code; ++ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n", ++ ioc->name, __FUNCTION__, ret)); ++ ++ out: ++ CLEAR_MGMT_STATUS(ioc->internal_cmds.status) ++ mutex_unlock(&ioc->internal_cmds.mutex); ++ return ret; + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -3260,9 +3195,10 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + * + */ + static void +-mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice) ++mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice) + { + INTERNAL_CMD iocmd; ++ MPT_ADAPTER *ioc = hd->ioc; + + /* Ignore hidden raid components, this is handled when the command + * is sent to the volume +@@ -3274,23 +3210,23 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST + !vdevice->configured_lun) + return; + +- /* Following parameters will not change +- * in this routine. +- */ ++ memset(&iocmd, 0, sizeof(INTERNAL_CMD)); + iocmd.cmd = SYNCHRONIZE_CACHE; +- iocmd.flags = 0; + iocmd.physDiskNum = -1; + iocmd.data = NULL; + iocmd.data_dma = -1; +- iocmd.size = 0; +- iocmd.rsvd = iocmd.rsvd2 = 0; + iocmd.channel = vdevice->vtarget->channel; + iocmd.id = vdevice->vtarget->id; + iocmd.lun = vdevice->lun; + ++ sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "SYNCHRONIZE_CACHE: fw_channel %d," ++ " fw_id %d\n", ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id); + mptscsih_do_cmd(hd, &iocmd); + } + ++/* ++ * shost attributes ++ */ + static ssize_t + mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -3464,13 +3400,44 @@ mptscsih_debug_level_store(struct device + return -EINVAL; + + ioc->debug_level = val; +- printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n", +- ioc->name, ioc->debug_level); ++ printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n", ioc->name, ++ ioc->debug_level); + return strlen(buf); + } + static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, + mptscsih_debug_level_show, mptscsih_debug_level_store); + ++static ssize_t ++mptscsih_disable_hotplug_remove_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct Scsi_Host *host = class_to_shost(dev); ++ MPT_SCSI_HOST *hd = shost_priv(host); ++ MPT_ADAPTER *ioc = hd->ioc; ++ ++ return snprintf(buf, PAGE_SIZE, "%02xh\n", ioc->disable_hotplug_remove); ++} ++static ssize_t ++mptscsih_disable_hotplug_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct Scsi_Host *host = class_to_shost(dev); ++ MPT_SCSI_HOST *hd = shost_priv(host); ++ MPT_ADAPTER *ioc = hd->ioc; ++ int val = 0; ++ ++ if (sscanf(buf, "%x", &val) != 1) ++ return -EINVAL; ++ ++ ioc->disable_hotplug_remove = val; ++ if (ioc->disable_hotplug_remove) ++ printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ++ ioc->name); ++ else ++ printk(MYIOC_s_INFO_FMT "eanbling hotplug remove\n", ioc->name); ++ return strlen(buf); ++} ++static DEVICE_ATTR(disable_hotplug_remove, S_IRUGO | S_IWUSR, ++ mptscsih_disable_hotplug_remove_show, mptscsih_disable_hotplug_remove_store); ++ + struct device_attribute *mptscsih_host_attrs[] = { + &dev_attr_version_fw, + &dev_attr_version_bios, +@@ -3484,6 +3451,7 @@ struct device_attribute *mptscsih_host_a + &dev_attr_io_delay, + &dev_attr_device_delay, + &dev_attr_debug_level, ++ &dev_attr_disable_hotplug_remove, + NULL, + }; + EXPORT_SYMBOL(mptscsih_host_attrs); +@@ -3510,7 +3478,9 @@ EXPORT_SYMBOL(mptscsih_scandv_complete); + EXPORT_SYMBOL(mptscsih_event_process); + EXPORT_SYMBOL(mptscsih_ioc_reset); + EXPORT_SYMBOL(mptscsih_change_queue_depth); +-EXPORT_SYMBOL(mptscsih_timer_expired); +-EXPORT_SYMBOL(mptscsih_TMHandler); +- ++EXPORT_SYMBOL(mptscsih_IssueTaskMgmt); ++EXPORT_SYMBOL(mptscsih_do_cmd); ++EXPORT_SYMBOL(mptscsih_quiesce_raid); ++EXPORT_SYMBOL(mptscsih_get_scsi_lookup); ++EXPORT_SYMBOL(mptscsih_taskmgmt_response_code); + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +--- a/drivers/message/fusion/mptscsih.h ++++ b/drivers/message/fusion/mptscsih.h +@@ -60,6 +60,7 @@ + #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) + #define MPT_SCANDV_ISSUE_SENSE (0x00000010) + #define MPT_SCANDV_FALLBACK (0x00000020) ++#define MPT_SCANDV_BUSY (0x00000040) + + #define MPT_SCANDV_MAX_RETRIES (10) + +@@ -71,6 +72,7 @@ + #define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */ + #define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */ + ++ + #define MPT_SCSI_CMD_PER_DEV_HIGH 64 + #define MPT_SCSI_CMD_PER_DEV_LOW 32 + +@@ -84,9 +86,11 @@ + #define MPTSCSIH_DOMAIN_VALIDATION 1 + #define MPTSCSIH_MAX_WIDTH 1 + #define MPTSCSIH_MIN_SYNC 0x08 ++#define MPTSCSIH_QAS 1 + #define MPTSCSIH_SAF_TE 0 + #define MPTSCSIH_PT_CLEAR 0 + ++#define TRANSPORT_LAYER_RETRIES 0xC2 + #endif + + typedef struct _internal_cmd { +@@ -112,7 +116,7 @@ extern int mptscsih_resume(struct pci_de + extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func); + extern const char * mptscsih_info(struct Scsi_Host *SChost); + extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)); +-extern void mptscsih_slave_destroy(struct scsi_device *device); ++extern void mptscsih_slave_destroy(struct scsi_device *sdev); + extern int mptscsih_slave_configure(struct scsi_device *device); + extern int mptscsih_abort(struct scsi_cmnd * SCpnt); + extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt); +@@ -125,8 +129,11 @@ extern int mptscsih_scandv_complete(MPT_ + extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); + extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); + extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); +-extern void mptscsih_timer_expired(unsigned long data); +-extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); ++extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); + extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); + extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); ++extern int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); + extern struct device_attribute *mptscsih_host_attrs[]; ++extern int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id); ++extern struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); ++extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); +--- a/drivers/message/fusion/mptspi.c ++++ b/drivers/message/fusion/mptspi.c +@@ -53,8 +53,10 @@ + #include /* for mdelay */ + #include /* needed for in_interrupt() proto */ + #include /* notifier code */ ++#include + #include + #include ++#include + + #include + #include +@@ -83,6 +85,10 @@ static int mpt_saf_te = MPTSCSIH_SAF_TE; + module_param(mpt_saf_te, int, 0); + MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)"); + ++static int mpt_qas = MPTSCSIH_QAS; ++module_param(mpt_qas, int, 1); ++MODULE_PARM_DESC(mpt_qas, " Quick Arbitration and Selection (QAS) enabled=1, disabled=0 (default=MPTSCSIH_QAS=1)"); ++ + static void mptspi_write_offset(struct scsi_target *, int); + static void mptspi_write_width(struct scsi_target *, int); + static int mptspi_write_spi_device_pg1(struct scsi_target *, +@@ -95,12 +101,12 @@ static u8 mptspiTaskCtx = MPT_MAX_PROTOC + static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ + + /** +- * mptspi_setTargetNegoParms - Update the target negotiation parameters ++ * mptspi_setTargetNegoParms - Update the target negotiation parameters + * @hd: Pointer to a SCSI Host Structure + * @target: per target private data + * @sdev: SCSI device + * +- * Update the target negotiation parameters based on the the Inquiry ++ * Update the target negotiation parameters based on the the Inquiry + * data, adapter capabilities, and NVRAM settings. + **/ + static void +@@ -131,7 +137,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST + if (scsi_device_sync(sdev)) { + factor = pspi_data->minSyncFactor; + if (!scsi_device_dt(sdev)) +- factor = MPT_ULTRA2; ++ factor = MPT_ULTRA2; + else { + if (!scsi_device_ius(sdev) && + !scsi_device_qas(sdev)) +@@ -209,6 +215,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST + target->maxOffset = offset; + target->maxWidth = width; + ++ spi_min_period(scsi_target(sdev)) = factor; ++ spi_max_offset(scsi_target(sdev)) = offset; ++ spi_max_width(scsi_target(sdev)) = width; ++ + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + + /* Disable unused features. +@@ -230,7 +240,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST + */ + + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); ++ "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); + } + } + +@@ -262,7 +272,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, + */ + if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT +- "writeIOCPage4 : no msg frames!\n",ioc->name)); ++ "writeIOCPage4 : no msg frames!\n", ioc->name)); + return -EAGAIN; + } + +@@ -300,11 +310,11 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | + (IOCPage4Ptr->Header.PageLength + ii) * 4; + +- mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); ++ ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", +- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); ++ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); + + mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); + +@@ -371,7 +381,7 @@ mptspi_initTarget(MPT_SCSI_HOST *hd, Vir + * non-zero = true + * zero = false + * +- */ ++ **/ + static int + mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id) + { +@@ -399,12 +409,11 @@ static int mptspi_target_alloc(struct sc + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct _MPT_SCSI_HOST *hd = shost_priv(shost); + VirtTarget *vtarget; +- MPT_ADAPTER *ioc; ++ MPT_ADAPTER *ioc = hd->ioc; + + if (hd == NULL) + return -ENODEV; + +- ioc = hd->ioc; + vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); + if (!vtarget) + return -ENOMEM; +@@ -471,9 +480,12 @@ mptspi_target_destroy(struct scsi_target + static void + mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) + { +- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x" ++ if (!(hd->ioc->debug_level & MPT_DEBUG_DV)) ++ return; ++ ++ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Wrote = 0x%08x" + " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", +- hd->ioc->name, starget->id, ii, ++ hd->ioc->name, ii, + ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", + ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), + ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", +@@ -483,7 +495,7 @@ mptspi_print_write_nego(struct _MPT_SCSI + ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", + ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", + ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", +- ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); ++ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""); + } + + /** +@@ -496,9 +508,12 @@ mptspi_print_write_nego(struct _MPT_SCSI + static void + mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii) + { +- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x" ++ if (!(hd->ioc->debug_level & MPT_DEBUG_DV)) ++ return; ++ ++ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT "Read = 0x%08x" + " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n", +- hd->ioc->name, starget->id, ii, ++ hd->ioc->name, ii, + ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "", + ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF), + ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "", +@@ -508,7 +523,7 @@ mptspi_print_read_nego(struct _MPT_SCSI_ + ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", + ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", + ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", +- ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": "")); ++ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""); + } + + static int mptspi_read_spi_device_pg0(struct scsi_target *starget, +@@ -557,9 +572,11 @@ static int mptspi_read_spi_device_pg0(st + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.dir = 0; + cfg.pageAddr = starget->id; ++ cfg.timeout = 60; + + if (mpt_config(ioc, &cfg)) { +- starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); ++ starget_printk(KERN_ERR, starget, ++ MYIOC_s_FMT "mpt_config failed\n", ioc->name); + goto out_free; + } + err = 0; +@@ -614,64 +631,11 @@ static void mptspi_read_parameters(struc + spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; + } + +-static int +-mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) +-{ +- MpiRaidActionRequest_t *pReq; +- MPT_FRAME_HDR *mf; +- MPT_ADAPTER *ioc = hd->ioc; +- +- /* Get and Populate a free Frame +- */ +- if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { +- ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", +- ioc->name)); +- return -EAGAIN; +- } +- pReq = (MpiRaidActionRequest_t *)mf; +- if (quiesce) +- pReq->Action = MPI_RAID_ACTION_QUIESCE_PHYS_IO; +- else +- pReq->Action = MPI_RAID_ACTION_ENABLE_PHYS_IO; +- pReq->Reserved1 = 0; +- pReq->ChainOffset = 0; +- pReq->Function = MPI_FUNCTION_RAID_ACTION; +- pReq->VolumeID = id; +- pReq->VolumeBus = channel; +- pReq->PhysDiskNum = 0; +- pReq->MsgFlags = 0; +- pReq->Reserved2 = 0; +- pReq->ActionDataWord = 0; /* Reserved for this action */ +- +- mpt_add_sge((char *)&pReq->ActionDataSGE, +- MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); +- +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", +- ioc->name, pReq->Action, channel, id)); +- +- hd->pLocal = NULL; +- hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ +- hd->scandv_wait_done = 0; +- +- /* Save cmd pointer, for resource free if timeout or +- * FW reload occurs +- */ +- hd->cmdPtr = mf; +- +- add_timer(&hd->timer); +- mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); +- wait_event(hd->scandv_waitq, hd->scandv_wait_done); +- +- if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) +- return -1; +- +- return 0; +-} +- + static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, + struct scsi_device *sdev) + { + VirtTarget *vtarget = scsi_target(sdev)->hostdata; ++ struct scsi_target *starget = scsi_target(sdev); + MPT_ADAPTER *ioc = hd->ioc; + + /* no DV on RAID devices */ +@@ -679,11 +643,20 @@ static void mptspi_dv_device(struct _MPT + mptspi_is_raid(hd, sdev->id)) + return; + ++ if (ioc->debug_level & MPT_DEBUG_DV) ++ starget_printk(KERN_DEBUG, starget, MYIOC_s_FMT ++ "sdtr=%d, wdtr=%d, ppr=%d, min_period=0x%02x, " ++ "max_offset=0x%02x, max_width=%d, nego_flags=0x%02x, " ++ "tflags=0x%02x\n", ioc->name, sdev->sdtr, sdev->wdtr, ++ sdev->ppr, spi_min_period(starget), ++ spi_max_offset(starget), spi_max_width(starget), ++ vtarget->negoFlags, vtarget->tflags); ++ + /* If this is a piece of a RAID, then quiesce first */ + if (sdev->channel == 1 && + mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) { +- starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT +- "Integrated RAID quiesce failed\n", ioc->name); ++ starget_printk(KERN_ERR, scsi_target(sdev), ++ MYIOC_s_FMT "Integrated RAID quiesce failed\n", ioc->name); + return; + } + +@@ -693,8 +666,8 @@ static void mptspi_dv_device(struct _MPT + + if (sdev->channel == 1 && + mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0) +- starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT +- "Integrated RAID resume failed\n", ioc->name); ++ starget_printk(KERN_ERR, scsi_target(sdev), ++ MYIOC_s_FMT "Integrated RAID resume failed\n", ioc->name); + + mptspi_read_parameters(sdev->sdev_target); + spi_display_xfer_agreement(sdev->sdev_target); +@@ -716,7 +689,7 @@ static int mptspi_slave_alloc(struct scs + vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdevice) { + printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", +- ioc->name, sizeof(VirtDevice)); ++ ioc->name, sizeof(VirtDevice)); + return -ENOMEM; + } + +@@ -738,21 +711,13 @@ static int mptspi_slave_configure(struct + { + struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host); + VirtTarget *vtarget = scsi_target(sdev)->hostdata; +- int ret; ++ int ret; + + mptspi_initTarget(hd, vtarget, sdev); +- + ret = mptscsih_slave_configure(sdev); +- + if (ret) + return ret; + +- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x" +- " max_offset=0x%02x max_width=%d\n", hd->ioc->name, +- sdev->id, spi_min_period(scsi_target(sdev)), +- spi_max_offset(scsi_target(sdev)), +- spi_max_width(scsi_target(sdev)))); +- + if ((sdev->channel == 1 || + !(mptspi_is_raid(hd, sdev->id))) && + !spi_initial_dv(sdev->sdev_target)) +@@ -857,8 +822,8 @@ static int mptspi_write_spi_device_pg1(s + + pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); + if (pg1 == NULL) { +- starget_printk(KERN_ERR, starget, MYIOC_s_FMT +- "dma_alloc_coherent for parameters failed\n", ioc->name); ++ starget_printk(KERN_ERR, starget, ++ MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name); + return -EINVAL; + } + +@@ -887,8 +852,8 @@ static int mptspi_write_spi_device_pg1(s + mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); + + if (mpt_config(ioc, &cfg)) { +- starget_printk(KERN_ERR, starget, MYIOC_s_FMT +- "mpt_config failed\n", ioc->name); ++ starget_printk(KERN_ERR, starget, ++ MYIOC_s_FMT "mpt_config failed\n", ioc->name); + goto out_free; + } + err = 0; +@@ -963,14 +928,15 @@ static void mptspi_write_dt(struct scsi_ + if (spi_period(starget) == -1) + mptspi_read_parameters(starget); + +- if (!dt && spi_period(starget) < 10) +- spi_period(starget) = 10; ++ if (!dt) { ++ spi_qas(starget) = 0; ++ spi_iu(starget) = 0; ++ } + + spi_dt(starget) = dt; + + nego = mptspi_getRP(starget); + +- + pg1.RequestedParameters = cpu_to_le32(nego); + pg1.Reserved = 0; + pg1.Configuration = 0; +@@ -986,9 +952,6 @@ static void mptspi_write_iu(struct scsi_ + if (spi_period(starget) == -1) + mptspi_read_parameters(starget); + +- if (!iu && spi_period(starget) < 9) +- spi_period(starget) = 9; +- + spi_iu(starget) = iu; + + nego = mptspi_getRP(starget); +@@ -1030,9 +993,11 @@ static void mptspi_write_qas(struct scsi + struct _MPT_SCSI_HOST *hd = shost_priv(shost); + VirtTarget *vtarget = starget->hostdata; + u32 nego; ++ MPT_ADAPTER *ioc = hd->ioc; + +- if ((vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) || +- hd->ioc->spi_data.noQas) ++ if (!mpt_qas || ++ (vtarget->negoFlags & MPT_TARGET_NO_NEGO_QAS) || ++ ioc->spi_data.noQas) + spi_qas(starget) = 0; + else + spi_qas(starget) = qas; +@@ -1053,8 +1018,8 @@ static void mptspi_write_width(struct sc + + if (!width) { + spi_dt(starget) = 0; +- if (spi_period(starget) < 10) +- spi_period(starget) = 10; ++ spi_qas(starget) = 0; ++ spi_iu(starget) = 0; + } + + spi_width(starget) = width; +@@ -1074,7 +1039,8 @@ struct work_queue_wrapper { + int disk; + }; + +-static void mpt_work_wrapper(struct work_struct *work) ++static void ++mpt_work_wrapper(struct work_struct *work) + { + struct work_queue_wrapper *wqw = + container_of(work, struct work_queue_wrapper, work); +@@ -1105,12 +1071,12 @@ static void mpt_work_wrapper(struct work + if(vtarget->id != disk) + continue; + +- starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT +- "Integrated RAID requests DV of new device\n", ioc->name); ++ starget_printk(KERN_INFO, vtarget->starget, ++ MYIOC_s_FMT "Integrated RAID requests DV of new device\n", ioc->name); + mptspi_dv_device(hd, sdev); + } +- shost_printk(KERN_INFO, shost, MYIOC_s_FMT +- "Integrated RAID detects new device %d\n", ioc->name, disk); ++ shost_printk(KERN_INFO, shost, ++ MYIOC_s_FMT "Integrated RAID detects new device %d\n", ioc->name, disk); + scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1); + } + +@@ -1121,8 +1087,8 @@ static void mpt_dv_raid(struct _MPT_SCSI + MPT_ADAPTER *ioc = hd->ioc; + + if (!wqw) { +- shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT +- "Failed to act on RAID event for physical disk %d\n", ++ shost_printk(KERN_ERR, ioc->sh, ++ MYIOC_s_FMT "Failed to act on RAID event for physical disk %d\n", + ioc->name, disk); + return; + } +@@ -1213,9 +1179,9 @@ static struct pci_device_id mptspi_pci_t + MODULE_DEVICE_TABLE(pci, mptspi_pci_table); + + +-/* ++/** + * renegotiate for a given target +- */ ++ **/ + static void + mptspi_dv_renegotiate_work(struct work_struct *work) + { +@@ -1261,32 +1227,33 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_H + schedule_work(&wqw->work); + } + +-/* ++/** + * spi module reset handler +- */ ++ **/ + static int + mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) + { ++ struct _MPT_SCSI_HOST *hd = NULL; + int rc; + + rc = mptscsih_ioc_reset(ioc, reset_phase); ++ if ((ioc->bus_type != SPI) || (!rc)) ++ goto out; + +- /* only try to do a renegotiation if we're properly set up +- * if we get an ioc fault on bringup, ioc->sh will be NULL */ +- if (reset_phase == MPT_IOC_POST_RESET && +- ioc->sh) { +- struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); ++ hd = shost_priv(ioc->sh); ++ if (!hd->ioc) ++ goto out; + ++ if (ioc->active && reset_phase == MPT_IOC_POST_RESET) + mptspi_dv_renegotiate(hd); +- } +- ++ out: + return rc; + } + + #ifdef CONFIG_PM +-/* ++/** + * spi module resume handler +- */ ++ **/ + static int + mptspi_resume(struct pci_dev *pdev) + { +@@ -1303,13 +1270,13 @@ mptspi_resume(struct pci_dev *pdev) + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +-/* ++/** + * mptspi_probe - Installs scsi devices per bus. + * @pdev: Pointer to pci_dev structure + * + * Returns 0 for success, non-zero for failure. + * +- */ ++ **/ + static int + mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) + { +@@ -1423,19 +1390,18 @@ mptspi_probe(struct pci_dev *pdev, const + * A slightly different algorithm is required for + * 64bit SGEs. + */ +- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); +- if (sizeof(dma_addr_t) == sizeof(u64)) { ++ scale = ioc->req_sz/ioc->SGE_size; ++ if (ioc->sg_addr_size == sizeof(u64)) { + numSGE = (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 60) / (sizeof(dma_addr_t) + +- sizeof(u32)); ++ (ioc->req_sz - 60) / ioc->SGE_size; + } else { + numSGE = 1 + (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + +- (ioc->req_sz - 64) / (sizeof(dma_addr_t) + +- sizeof(u32)); ++ (ioc->req_sz - 64) / ioc->SGE_size; + } + ++ + if (numSGE < sh->sg_tablesize) { + /* Reset this value */ + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT +@@ -1444,11 +1410,11 @@ mptspi_probe(struct pci_dev *pdev, const + sh->sg_tablesize = numSGE; + } + +- spin_unlock_irqrestore(&ioc->FreeQlock, flags); +- + hd = shost_priv(sh); + hd->ioc = ioc; + ++ spin_unlock_irqrestore(&ioc->FreeQlock, flags); ++ + /* SCSI needs scsi_cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ +@@ -1462,39 +1428,12 @@ mptspi_probe(struct pci_dev *pdev, const + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", + ioc->name, ioc->ScsiLookup)); + +- /* Clear the TM flags +- */ +- hd->tmPending = 0; +- hd->tmState = TM_STATE_NONE; +- hd->resetPending = 0; +- hd->abortSCpnt = NULL; +- +- /* Clear the pointer used to store +- * single-threaded commands, i.e., those +- * issued during a bus scan, dv and +- * configuration pages. +- */ +- hd->cmdPtr = NULL; +- +- /* Initialize this SCSI Hosts' timers +- * To use, set the timer expires field +- * and add_timer +- */ +- init_timer(&hd->timer); +- hd->timer.data = (unsigned long) hd; +- hd->timer.function = mptscsih_timer_expired; +- ++ ioc->sdev_queue_depth = MPT_SCSI_CMD_PER_DEV_HIGH; + ioc->spi_data.Saf_Te = mpt_saf_te; +- +- hd->negoNvram = MPT_SCSICFG_USE_NVRAM; + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "saf_te %x\n", +- ioc->name, +- mpt_saf_te)); +- ioc->spi_data.noQas = 0; ++ "saf_te %x\n", ioc->name, mpt_saf_te)); ++ ioc->spi_data.noQas = mpt_qas ? 0 : MPT_TARGET_NO_NEGO_QAS; + +- init_waitqueue_head(&hd->scandv_waitq); +- hd->scandv_wait_done = 0; + hd->last_queue_full = 0; + hd->spi_pending = 0; + +@@ -1514,7 +1453,7 @@ mptspi_probe(struct pci_dev *pdev, const + * issue internal bus reset + */ + if (ioc->spi_data.bus_reset) +- mptscsih_TMHandler(hd, ++ mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + 0, 0, 0, 0, 5); + +@@ -1544,7 +1483,7 @@ static struct pci_driver mptspi_driver = + * mptspi_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. + * + * Returns 0 for success, non-zero for failure. +- */ ++ **/ + static int __init + mptspi_init(void) + { +@@ -1574,7 +1513,8 @@ mptspi_init(void) + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptspi_exit - Unregisters MPT adapter(s) +- */ ++ * ++ **/ + static void __exit + mptspi_exit(void) + { +@@ -1582,7 +1522,6 @@ mptspi_exit(void) + + mpt_reset_deregister(mptspiDoneCtx); + mpt_event_deregister(mptspiDoneCtx); +- + mpt_deregister(mptspiInternalCtx); + mpt_deregister(mptspiTaskCtx); + mpt_deregister(mptspiDoneCtx); +--- /dev/null ++++ b/drivers/message/fusion/rejected_ioctls/diag_buffer.c +@@ -0,0 +1,667 @@ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/* REGISTER DIAG BUFFER Routine. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -EBUSY if previous command timout and IOC reset is not complete. ++ * -ENODEV if no such device/adapter ++ * -ETIME if timer expires ++ * -ENOMEM if memory allocation error ++ */ ++static int ++mptctl_register_diag_buffer (unsigned long arg) ++{ ++ mpt_diag_register_t __user *uarg = (void __user *) arg; ++ mpt_diag_register_t karg; ++ MPT_ADAPTER *ioc; ++ int iocnum, rc, ii; ++ void * request_data; ++ dma_addr_t request_data_dma; ++ u32 request_data_sz; ++ MPT_FRAME_HDR *mf; ++ DiagBufferPostRequest_t *diag_buffer_post_request; ++ DiagBufferPostReply_t *diag_buffer_post_reply; ++ u32 tmp; ++ u8 buffer_type; ++ unsigned long timeleft; ++ ++ rc = 0; ++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_register_t))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in mpt_diag_register_t struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || ++ (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, ++ __FUNCTION__)); ++ buffer_type = karg.data.BufferType; ++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ return -ENODEV; ++ } ++ ++ if (ioc->DiagBuffer_Status[buffer_type] & ++ MPT_DIAG_BUFFER_IS_REGISTERED) { ++ printk(MYIOC_s_DEBUG_FMT "%s: already has a Registered " ++ "buffer for buffer_type=%x\n", ioc->name, __FUNCTION__, ++ buffer_type); ++ return -EFAULT; ++ } ++ ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) ++ return -EAGAIN; ++ ++ request_data = ioc->DiagBuffer[buffer_type]; ++ request_data_sz = karg.data.RequestedBufferSize; ++ ++ if (request_data) { ++ request_data_dma = ioc->DiagBuffer_dma[buffer_type]; ++ if (request_data_sz != ioc->DiagBuffer_sz[buffer_type]) { ++ pci_free_consistent(ioc->pcidev, ++ ioc->DiagBuffer_sz[buffer_type], ++ request_data, request_data_dma); ++ request_data = NULL; ++ } ++ } ++ ++ if (request_data == NULL) { ++ ioc->DiagBuffer_sz[buffer_type] = 0; ++ ioc->DiagBuffer_dma[buffer_type] = 0; ++ ioc->DataSize[buffer_type] = 0; ++ request_data = pci_alloc_consistent( ++ ioc->pcidev, request_data_sz, &request_data_dma); ++ if (request_data == NULL) { ++ printk(MYIOC_s_DEBUG_FMT "%s: pci_alloc_consistent" ++ " FAILED, (request_sz=%d)\n", ioc->name, ++ __FUNCTION__, request_data_sz); ++ mpt_free_msg_frame(ioc, mf); ++ return -EAGAIN; ++ } ++ ioc->DiagBuffer[buffer_type] = request_data; ++ ioc->DiagBuffer_sz[buffer_type] = request_data_sz; ++ ioc->DiagBuffer_dma[buffer_type] = request_data_dma; ++ } ++ ++ ioc->DiagBuffer_Status[buffer_type] = 0; ++ diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; ++ diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST; ++ diag_buffer_post_request->ChainOffset = 0; ++ diag_buffer_post_request->BufferType = karg.data.BufferType; ++ diag_buffer_post_request->TraceLevel = ioc->TraceLevel[buffer_type] = ++ karg.data.TraceLevel; ++ diag_buffer_post_request->MsgFlags = 0; ++ diag_buffer_post_request->Reserved1 = 0; ++ diag_buffer_post_request->Reserved2 = 0; ++ diag_buffer_post_request->Reserved3 = 0; ++ diag_buffer_post_request->BufferAddress.High = 0; ++ if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) ++ ioc->ExtendedType[buffer_type] = karg.data.ExtendedType; ++ else ++ ioc->ExtendedType[buffer_type] = 0; ++ diag_buffer_post_request->ExtendedType = ++ cpu_to_le32(ioc->ExtendedType[buffer_type]); ++ ioc->UniqueId[buffer_type] = karg.data.UniqueId; ++ diag_buffer_post_request->BufferLength = cpu_to_le32(request_data_sz); ++ for (ii = 0; ii < 4; ii++) { ++ ioc->ProductSpecific[buffer_type][ii] = ++ karg.data.ProductSpecific[ii]; ++ diag_buffer_post_request->ProductSpecific[ii] = ++ cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]); ++ } ++ ++ tmp = request_data_dma & 0xFFFFFFFF; ++ diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp); ++ if (ioc->sg_addr_size == sizeof(u64)) { ++ tmp = (u32)((u64)request_data_dma >> 32); ++ diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp); ++ } ++ ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, ++ diag_buffer_post_request->MsgContext); ++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) ++ mpt_put_msg_frame(mptctl_id, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, ++ MPT_IOCTL_DEFAULT_TIMEOUT*HZ); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ rc = -ETIME; ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, ++ __FUNCTION__); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ goto out; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(ioc, mf); ++ goto out; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", ++ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply; ++ if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) == ++ MPI_IOCSTATUS_SUCCESS) { ++ if (diag_buffer_post_reply->MsgLength > 5) ++ ioc->DataSize[buffer_type] = ++ le32_to_cpu(diag_buffer_post_reply->TransferLength); ++ ioc->DiagBuffer_Status[buffer_type] |= ++ MPT_DIAG_BUFFER_IS_REGISTERED; ++ } else { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " ++ "IOCLogInfo=%x\n", ioc->name, __FUNCTION__, ++ diag_buffer_post_reply->IOCStatus, ++ diag_buffer_post_reply->IOCLogInfo)); ++ rc = -EFAULT; ++ } ++ ++ out: ++ ++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); ++ if (rc) ++ pci_free_consistent(ioc->pcidev, request_data_sz, ++ request_data, request_data_dma); ++ return rc; ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/* RELEASE DIAG BUFFER Routine. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -EBUSY if previous command timout and IOC reset is not complete. ++ * -ENODEV if no such device/adapter ++ * -ETIME if timer expires ++ * -ENOMEM if memory allocation error ++ */ ++static int ++mptctl_release_diag_buffer (unsigned long arg) ++{ ++ mpt_diag_release_t __user *uarg = (void __user *) arg; ++ mpt_diag_release_t karg; ++ MPT_ADAPTER *ioc; ++ void * request_data; ++ int iocnum, rc; ++ MPT_FRAME_HDR *mf; ++ DiagReleaseRequest_t *diag_release; ++ DiagReleaseReply_t *diag_release_reply; ++ u8 buffer_type; ++ unsigned long timeleft; ++ ++ rc = 0; ++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_release_t))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in mpt_diag_release_t struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || ++ (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, ++ __FUNCTION__)); ++ buffer_type = karg.data.UniqueId & 0x000000ff; ++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ return -ENODEV; ++ } ++ ++ if ((ioc->DiagBuffer_Status[buffer_type] & ++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0 ) { ++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " ++ "registered\n", ioc->name, __FUNCTION__, buffer_type); ++ return -EFAULT; ++ } ++ ++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { ++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", ++ ioc->name, __FUNCTION__, karg.data.UniqueId); ++ return -EFAULT; ++ } ++ ++ if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x " ++ "is already released\n", ioc->name, __FUNCTION__, ++ buffer_type)); ++ return rc; ++ } ++ ++ request_data = ioc->DiagBuffer[buffer_type]; ++ ++ if (request_data == NULL) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ return -ENODEV; ++ } ++ ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) ++ return -EAGAIN; ++ ++ diag_release = (DiagReleaseRequest_t *)mf; ++ diag_release->Function = MPI_FUNCTION_DIAG_RELEASE; ++ diag_release->BufferType = buffer_type; ++ diag_release->ChainOffset = 0; ++ diag_release->Reserved1 = 0; ++ diag_release->Reserved2 = 0; ++ diag_release->Reserved3 = 0; ++ diag_release->MsgFlags = 0; ++ ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, ++ diag_release->MsgContext); ++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) ++ mpt_put_msg_frame(mptctl_id, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, ++ MPT_IOCTL_DEFAULT_TIMEOUT*HZ); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ rc = -ETIME; ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, ++ __FUNCTION__); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ goto out; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(ioc, mf); ++ goto out; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", ++ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); ++ rc = -EFAULT; ++ goto out; ++ } ++ ++ diag_release_reply = (DiagReleaseReply_t *)ioc->ioctl_cmds.reply; ++ if (le16_to_cpu(diag_release_reply->IOCStatus) != ++ MPI_IOCSTATUS_SUCCESS) { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " ++ "IOCLogInfo=%x\n", ++ ioc->name, __FUNCTION__, diag_release_reply->IOCStatus, ++ diag_release_reply->IOCLogInfo)); ++ rc = -EFAULT; ++ } else ++ ioc->DiagBuffer_Status[buffer_type] |= ++ MPT_DIAG_BUFFER_IS_RELEASED; ++ ++ out: ++ ++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); ++ return rc; ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/* UNREGISTER DIAG BUFFER Routine. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -EBUSY if previous command timout and IOC reset is not complete. ++ * -ENODEV if no such device/adapter ++ * -ETIME if timer expires ++ * -ENOMEM if memory allocation error ++ */ ++static int ++mptctl_unregister_diag_buffer (unsigned long arg) ++{ ++ mpt_diag_unregister_t __user *uarg = (void __user *) arg; ++ mpt_diag_unregister_t karg; ++ MPT_ADAPTER *ioc; ++ int iocnum; ++ void * request_data; ++ dma_addr_t request_data_dma; ++ u32 request_data_sz; ++ u8 buffer_type; ++ ++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_unregister_t))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in mpt_diag_unregister_t struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || ++ (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, ++ __FUNCTION__)); ++ buffer_type = karg.data.UniqueId & 0x000000ff; ++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ return -ENODEV; ++ } ++ ++ if ((ioc->DiagBuffer_Status[buffer_type] & ++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { ++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " ++ "registered\n", ioc->name, __FUNCTION__, buffer_type); ++ return -EFAULT; ++ } ++ if ((ioc->DiagBuffer_Status[buffer_type] & ++ MPT_DIAG_BUFFER_IS_RELEASED) == 0) { ++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x has not been " ++ "released\n", ioc->name, __FUNCTION__, buffer_type); ++ return -EFAULT; ++ } ++ ++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { ++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", ++ ioc->name, __FUNCTION__, karg.data.UniqueId); ++ return -EFAULT; ++ } ++ ++ request_data = ioc->DiagBuffer[buffer_type]; ++ if (!request_data) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ return -ENODEV; ++ } ++ ++ request_data_sz = ioc->DiagBuffer_sz[buffer_type]; ++ request_data_dma = ioc->DiagBuffer_dma[buffer_type]; ++ pci_free_consistent(ioc->pcidev, request_data_sz, ++ request_data, request_data_dma); ++ ioc->DiagBuffer[buffer_type] = NULL; ++ ioc->DiagBuffer_Status[buffer_type] = 0; ++ return 0; ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/* QUERY DIAG BUFFER Routine. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -EBUSY if previous command timout and IOC reset is not complete. ++ * -ENODEV if no such device/adapter ++ * -ETIME if timer expires ++ * -ENOMEM if memory allocation error ++ */ ++static int ++mptctl_query_diag_buffer (unsigned long arg) ++{ ++ mpt_diag_query_t __user *uarg = (void __user *)arg; ++ mpt_diag_query_t karg; ++ MPT_ADAPTER *ioc; ++ void * request_data; ++ int iocnum, ii, rc; ++ u8 buffer_type; ++ ++ rc = -EFAULT; ++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_query_t))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in mpt_diag_query_t struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ karg.data.Flags = 0; ++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || ++ (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ goto out; ++ } ++ ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, ++ __FUNCTION__)); ++ buffer_type = karg.data.BufferType; ++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ goto out; ++ } ++ ++ if ((ioc->DiagBuffer_Status[buffer_type] & ++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { ++ printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " ++ "registered\n", ioc->name, __FUNCTION__, buffer_type); ++ goto out; ++ } ++ ++ if (karg.data.UniqueId & 0xffffff00) { ++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { ++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not " ++ "registered\n", ioc->name, __FUNCTION__, ++ karg.data.UniqueId); ++ goto out; ++ } ++ } ++ ++ request_data = ioc->DiagBuffer[buffer_type]; ++ if (!request_data) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ goto out; ++ } ++ ++ rc = 0; ++ if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) { ++ if (karg.data.ExtendedType != ioc->ExtendedType[buffer_type]) ++ goto out; ++ } else ++ karg.data.ExtendedType = 0; ++ ++ if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) ++ karg.data.Flags = 3; ++ else ++ karg.data.Flags = 7; ++ karg.data.TraceLevel = ioc->TraceLevel[buffer_type]; ++ for (ii = 0; ii < 4; ii++) ++ karg.data.ProductSpecific[ii] = ++ ioc->ProductSpecific[buffer_type][ii]; ++ karg.data.DataSize = ioc->DiagBuffer_sz[buffer_type]; ++ karg.data.DriverAddedBufferSize = 0; ++ karg.data.UniqueId = ioc->UniqueId[buffer_type]; ++ ++ out: ++ if (copy_to_user(uarg, &karg, sizeof(mpt_diag_query_t))) { ++ printk(MYIOC_s_ERR_FMT "%s Unable to write mpt_diag_query_t " ++ "data @ %p\n", ioc->name, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ return rc; ++} ++ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++/* READ DIAG BUFFER Routine. ++ * ++ * Outputs: None. ++ * Return: 0 if successful ++ * -EFAULT if data unavailable ++ * -EBUSY if previous command timout and IOC reset is not complete. ++ * -ENODEV if no such device/adapter ++ * -ETIME if timer expires ++ * -ENOMEM if memory allocation error ++ */ ++static int ++mptctl_read_diag_buffer (unsigned long arg) ++{ ++ mpt_diag_read_buffer_t __user *uarg = (void __user *) arg; ++ mpt_diag_read_buffer_t karg; ++ MPT_ADAPTER *ioc; ++ void *request_data, *diagData; ++ dma_addr_t request_data_dma; ++ DiagBufferPostRequest_t *diag_buffer_post_request; ++ DiagBufferPostReply_t *diag_buffer_post_reply; ++ MPT_FRAME_HDR *mf; ++ int iocnum, rc, ii; ++ u8 buffer_type; ++ u32 tmp; ++ unsigned long timeleft; ++ ++ rc = 0; ++ if (copy_from_user(&karg, uarg, sizeof(mpt_diag_read_buffer_t))) { ++ printk(KERN_ERR "%s@%d::%s - " ++ "Unable to read in mpt_diag_read_buffer_t struct @ %p\n", ++ __FILE__, __LINE__, __FUNCTION__, uarg); ++ return -EFAULT; ++ } ++ ++ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || ++ (ioc == NULL)) { ++ printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", ++ __FILE__, __FUNCTION__, __LINE__, iocnum); ++ return -ENODEV; ++ } ++ ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, ++ __FUNCTION__)); ++ buffer_type = karg.data.UniqueId & 0x000000ff; ++ if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability " ++ "for buffer_type=%x\n", ioc->name, __FUNCTION__, ++ buffer_type); ++ return -EFAULT; ++ } ++ ++ if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { ++ printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", ++ ioc->name, __FUNCTION__, karg.data.UniqueId); ++ return -EFAULT; ++ } ++ ++ request_data = ioc->DiagBuffer[buffer_type]; ++ if (!request_data) { ++ printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ return -EFAULT; ++ } ++ ++ diagData = (void *)(request_data + karg.data.StartingOffset); ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: diagData=%p " ++ "request_data=%p StartingOffset=%x\n", ioc->name, __FUNCTION__, ++ diagData, request_data, karg.data.StartingOffset)); ++ ++ if (copy_to_user((void __user *)&uarg->data.DiagnosticData[0], ++ diagData, karg.data.BytesToRead)) { ++ printk(MYIOC_s_ERR_FMT "%s: Unable to write " ++ "mpt_diag_read_buffer_t data @ %p\n", ioc->name, ++ __FUNCTION__, diagData); ++ return -EFAULT; ++ } ++ ++ if ((karg.data.Flags & MPI_FW_DIAG_FLAG_REREGISTER) == 0) ++ goto out; ++ ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Reregister " ++ "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type)); ++ if ((ioc->DiagBuffer_Status[buffer_type] & ++ MPT_DIAG_BUFFER_IS_RELEASED) == 0) { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x " ++ "is still registered\n", ioc->name, __FUNCTION__, ++ buffer_type)); ++ return rc; ++ } ++ /* Get a free request frame and save the message context. ++ */ ++ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) ++ return -EAGAIN; ++ ++ diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; ++ diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST; ++ diag_buffer_post_request->ChainOffset = 0; ++ diag_buffer_post_request->BufferType = buffer_type; ++ diag_buffer_post_request->TraceLevel = ++ ioc->TraceLevel[buffer_type]; ++ diag_buffer_post_request->MsgFlags = 0; ++ diag_buffer_post_request->Reserved1 = 0; ++ diag_buffer_post_request->Reserved2 = 0; ++ diag_buffer_post_request->Reserved3 = 0; ++ diag_buffer_post_request->BufferAddress.High = 0; ++ if ( buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED ) ++ diag_buffer_post_request->ExtendedType = ++ cpu_to_le32(ioc->ExtendedType[buffer_type]); ++ diag_buffer_post_request->BufferLength = ++ cpu_to_le32(ioc->DiagBuffer_sz[buffer_type]); ++ for (ii = 0; ii < 4; ii++) ++ diag_buffer_post_request->ProductSpecific[ii] = ++ cpu_to_le32(ioc->ProductSpecific[buffer_type][ii]); ++ request_data_dma = ioc->DiagBuffer_dma[buffer_type]; ++ tmp = request_data_dma & 0xFFFFFFFF; ++ diag_buffer_post_request->BufferAddress.Low = cpu_to_le32(tmp); ++ if (ioc->sg_addr_size == sizeof(u64)) { ++ tmp = (u32)((u64)request_data_dma >> 32); ++ diag_buffer_post_request->BufferAddress.High = cpu_to_le32(tmp); ++ } ++ ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, ++ diag_buffer_post_request->MsgContext); ++ INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) ++ mpt_put_msg_frame(mptctl_id, ioc, mf); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, ++ MPT_IOCTL_DEFAULT_TIMEOUT*HZ); ++ if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ rc = -ETIME; ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, ++ __FUNCTION__); ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ mpt_free_msg_frame(ioc, mf); ++ goto out; ++ } ++ if (!timeleft) ++ mptctl_timeout_expired(ioc, mf); ++ goto out; ++ } ++ ++ /* process the completed Reply Message Frame */ ++ if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", ++ ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); ++ rc = -EFAULT; ++ } ++ ++ diag_buffer_post_reply = (DiagBufferPostReply_t *)ioc->ioctl_cmds.reply; ++ if (le16_to_cpu(diag_buffer_post_reply->IOCStatus) == ++ MPI_IOCSTATUS_SUCCESS) { ++ if (diag_buffer_post_reply->MsgLength > 5) ++ ioc->DataSize[buffer_type] = ++ le32_to_cpu(diag_buffer_post_reply->TransferLength); ++ ioc->DiagBuffer_Status[buffer_type] |= ++ MPT_DIAG_BUFFER_IS_REGISTERED; ++ } else { ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " ++ "IOCLogInfo=%x\n", ioc->name, __FUNCTION__, ++ diag_buffer_post_reply->IOCStatus, ++ diag_buffer_post_reply->IOCLogInfo)); ++ rc = -EFAULT; ++ } ++ ++ out: ++ CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); ++ return rc; ++} +--- /dev/null ++++ b/drivers/message/fusion/rejected_ioctls/diag_buffer.h +@@ -0,0 +1,101 @@ ++#define MPTDIAGREGISTER _IOWR(MPT_MAGIC_NUMBER,26,mpt_diag_register_t) ++#define MPTDIAGRELEASE _IOWR(MPT_MAGIC_NUMBER,27,mpt_diag_release_t) ++#define MPTDIAGUNREGISTER _IOWR(MPT_MAGIC_NUMBER,28,mpt_diag_unregister_t) ++#define MPTDIAGQUERY _IOWR(MPT_MAGIC_NUMBER,29,mpt_diag_query_t) ++#define MPTDIAGREADBUFFER _IOWR(MPT_MAGIC_NUMBER,30,mpt_diag_read_buffer_t) ++ ++#define MPI_FW_DIAG_IOCTL (0x80646961) ++#define MPI_FW_DIAG_TYPE_REGISTER (0x00000001) ++#define MPI_FW_DIAG_TYPE_UNREGISTER (0x00000002) ++#define MPI_FW_DIAG_TYPE_QUERY (0x00000003) ++#define MPI_FW_DIAG_TYPE_READ_BUFFER (0x00000004) ++#define MPI_FW_DIAG_TYPE_RELEASE (0x00000005) ++ ++#define MPI_FW_DIAG_INVALID_UID (0x00000000) ++#define FW_DIAGNOSTIC_BUFFER_COUNT (3) ++#define FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF) ++ ++#define MPI_FW_DIAG_ERROR_SUCCESS (0x00000000) ++#define MPI_FW_DIAG_ERROR_FAILURE (0x00000001) ++#define MPI_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002) ++#define MPI_FW_DIAG_ERROR_POST_FAILED (0x00000010) ++#define MPI_FW_DIAG_ERROR_INVALID_UID (0x00000011) ++ ++#define MPI_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012) ++#define MPI_FW_DIAG_ERROR_NO_BUFFER (0x00000013) ++#define MPI_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014) ++ ++#define MPT_DIAG_CAPABILITY(bufftype) (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER << bufftype) ++ ++#define MPT_DIAG_BUFFER_IS_REGISTERED 1 ++#define MPT_DIAG_BUFFER_IS_RELEASED 2 ++ ++typedef struct _MPI_FW_DIAG_REGISTER { ++ u8 TraceLevel; ++ u8 BufferType; ++ u16 Flags; ++ u32 ExtendedType; ++ u32 ProductSpecific[4]; ++ u32 RequestedBufferSize; ++ u32 UniqueId; ++} MPI_FW_DIAG_REGISTER, *PTR_MPI_FW_DIAG_REGISTER; ++ ++typedef struct _mpt_diag_register { ++ mpt_ioctl_header hdr; ++ MPI_FW_DIAG_REGISTER data; ++} mpt_diag_register_t; ++ ++typedef struct _MPI_FW_DIAG_UNREGISTER { ++ u32 UniqueId; ++} MPI_FW_DIAG_UNREGISTER, *PTR_MPI_FW_DIAG_UNREGISTER; ++ ++typedef struct _mpt_diag_unregister { ++ mpt_ioctl_header hdr; ++ MPI_FW_DIAG_UNREGISTER data; ++} mpt_diag_unregister_t; ++ ++#define MPI_FW_DIAG_FLAG_APP_OWNED (0x0001) ++#define MPI_FW_DIAG_FLAG_BUFFER_VALID (0x0002) ++#define MPI_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004) ++ ++typedef struct _MPI_FW_DIAG_QUERY { ++ u8 TraceLevel; ++ u8 BufferType; ++ u16 Flags; ++ u32 ExtendedType; ++ u32 ProductSpecific[4]; ++ u32 DataSize; ++ u32 DriverAddedBufferSize; ++ u32 UniqueId; ++} MPI_FW_DIAG_QUERY, *PTR_MPI_FW_DIAG_QUERY; ++ ++typedef struct _mpt_diag_query { ++ mpt_ioctl_header hdr; ++ MPI_FW_DIAG_QUERY data; ++} mpt_diag_query_t; ++ ++typedef struct _MPI_FW_DIAG_RELEASE { ++ u32 UniqueId; ++} MPI_FW_DIAG_RELEASE, *PTR_MPI_FW_DIAG_RELEASE; ++ ++typedef struct _mpt_diag_release { ++ mpt_ioctl_header hdr; ++ MPI_FW_DIAG_RELEASE data; ++} mpt_diag_release_t; ++ ++#define MPI_FW_DIAG_FLAG_REREGISTER (0x0001) ++ ++typedef struct _MPI_FW_DIAG_READ_BUFFER { ++ u8 Status; ++ u8 Reserved; ++ u16 Flags; ++ u32 StartingOffset; ++ u32 BytesToRead; ++ u32 UniqueId; ++ u32 DiagnosticData[1]; ++} MPI_FW_DIAG_READ_BUFFER, *PTR_MPI_FW_DIAG_READ_BUFFER; ++ ++typedef struct _mpt_diag_read_buffer { ++ mpt_ioctl_header hdr; ++ MPI_FW_DIAG_READ_BUFFER data; ++} mpt_diag_read_buffer_t; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/mpt-fusion-4.16.00.00-update b/src/patches/suse-2.6.27.31/patches.drivers/mpt-fusion-4.16.00.00-update new file mode 100644 index 000000000..4179cb02a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/mpt-fusion-4.16.00.00-update @@ -0,0 +1,11390 @@ +Subject: MPT fusion driver update to 4.16.00.00 +From: Satya Prakash +Date: Thu Nov 20 14:13:01 2008 +0100: +References: bnc#425660 + +Update the mpt fusion driver to internal version 4.16.00.00. + +Signed-off-by: Satya Prakash +Acked-by: Hannes Reinecke + +Index: linux-2.6.27/drivers/message/fusion/csmi/csmisas.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/csmi/csmisas.c ++++ linux-2.6.27/drivers/message/fusion/csmi/csmisas.c +@@ -43,16 +43,13 @@ + */ + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +-#define MPT_CSMI_DESCRIPTION "LSI Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON ++#define MPT_CSMI_DESCRIPTION \ ++ "LSI Corporation: Fusion MPT Driver "MPT_LINUX_VERSION_COMMON + #define csmisas_is_this_sas_cntr(ioc) (ioc->bus_type == SAS) ? 1 : 0 + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +-#define __user +-#include +-#endif + +-static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, +- u8 VolumeId, pMpiRaidActionReply_t reply); ++static int csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, ++ u8 VolumeBus, u8 VolumeId, pMpiRaidActionReply_t reply); + static u8 map_sas_status_to_csmi(u8 mpi_sas_status); + + /** +@@ -66,7 +63,7 @@ reverse_byte_order64(u64 data64) + { + int i; + u64 rc; +- u8 *inWord = (u8*)&data64, *outWord = (u8*)&rc; ++ u8 *inWord = (u8 *)&data64, *outWord = (u8 *)&rc; + + for (i = 0 ; i < 8 ; i++) + outWord[i] = inWord[7-i]; +@@ -98,7 +95,7 @@ csmisas_is_sata(RaidPhysDiskPage0_t *phy + * + **/ + static inline int +-csmisas_is_end_device(struct mptsas_devinfo * attached) ++csmisas_is_end_device(struct mptsas_devinfo *attached) + { + if ((attached->sas_address) && + (attached->device_info & +@@ -130,7 +127,8 @@ csmisas_is_phys_disk(MPT_ADAPTER *ioc, i + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && +- (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { ++ (channel == ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = 1; + goto out; + } +@@ -142,14 +140,14 @@ csmisas_is_phys_disk(MPT_ADAPTER *ioc, i + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + +- down(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = 1; + } +- up(&ioc->raid_data.inactive_list_mutex); ++ mutex_unlock(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +@@ -161,7 +159,8 @@ csmisas_is_phys_disk(MPT_ADAPTER *ioc, i + * Obtains the phys disk num for given H:C:T nexus + * + * input (channel/id) +- * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden component) ++ * output (phys disk number - used by SCSI_IO_PASSTHRU to access hidden ++ * component) + * + * returns - signed return means failure + **/ +@@ -176,7 +175,8 @@ csmisas_raid_id_to_num(MPT_ADAPTER *ioc, + goto out; + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) && +- (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { ++ (channel == ++ ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) { + rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum; + goto out; + } +@@ -188,14 +188,14 @@ csmisas_raid_id_to_num(MPT_ADAPTER *ioc, + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + +- down(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = component_info->d.PhysDiskNum; + } +- up(&ioc->raid_data.inactive_list_mutex); ++ mutex_unlock(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +@@ -218,7 +218,7 @@ csmisas_get_device_component_by_os(MPT_A + + sas_info = NULL; + +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry(p, &ioc->sas_device_info_list, list) { + if (p->os.channel == channel && p->os.id == id) { + sas_info = p; +@@ -227,7 +227,7 @@ csmisas_get_device_component_by_os(MPT_A + } + + out: +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + return sas_info; + } + +@@ -248,7 +248,7 @@ csmisas_get_device_component_by_fw(MPT_A + + sas_info = NULL; + +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry(p, &ioc->sas_device_info_list, list) { + if (p->fw.channel == channel && p->fw.id == id) { + sas_info = p; +@@ -257,7 +257,7 @@ csmisas_get_device_component_by_fw(MPT_A + } + + out: +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + return sas_info; + } + +@@ -279,7 +279,7 @@ csmisas_get_device_component_by_sas_addr + + sas_info = NULL; + +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry(p, &ioc->sas_device_info_list, list) { + if (p->sas_address == sas_address) { + sas_info = p; +@@ -288,7 +288,7 @@ csmisas_get_device_component_by_sas_addr + } + + out: +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + return sas_info; + } + +@@ -305,7 +305,8 @@ csmisas_get_device_component_by_sas_addr + * non-zero, failure + **/ + static int +-csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout) ++csmisas_send_command_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, ++ unsigned long timeout) + { + int rc; + unsigned long timeleft; +@@ -314,40 +315,15 @@ csmisas_send_command_wait(MPT_ADAPTER *i + rc = 0; + timeleft = 0; + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +- +- INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status) +- ioc->ioctl_cmds.wait_done = 0; +- ioc->ioctl_cmds.timer.expires = jiffies + (MPT_JIFFY * timeout); +- ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE; +- ADD_TIMER(&ioc->ioctl_cmds.timer); +- mpt_put_msg_frame(mptctl_id, ioc, mf); +- WAIT_EVENT(mptctl_wait, ioc->ioctl_cmds.wait_done); +- +-#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) +- +- INITIALIZE_IOCTL_STATUS(ioc->ioctl_cmds.status) +- ioc->ioctl_cmds.wait_done = 0; +- mpt_put_msg_frame(mptctl_id, ioc, mf); +- +- if ((wait_event_timeout(mptctl_wait, +- ioc->ioctl_cmds.wait_done == 1, HZ * timeout) <=0) && +- ioc->ioctl_cmds.wait_done != 1 ) { +- mptctl_timeout_expired(ioc,mf); +- mpt_free_msg_frame(ioc, mf); +- rc = -1; +- } +- +-#else +- + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + mf->u.hdr.MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); +- timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, timeout*HZ); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, ++ timeout*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -1; +- printk("%s: failed\n", __FUNCTION__); ++ printk(KERN_WARNING "%s: failed\n", __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) +@@ -357,7 +333,6 @@ csmisas_send_command_wait(MPT_ADAPTER *i + mptctl_timeout_expired(ioc, mf); + } + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); +-#endif + return rc; + } + +@@ -375,7 +350,8 @@ csmisas_send_command_wait(MPT_ADAPTER *i + * non-zero, failure + **/ + static int +-csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, unsigned long timeout) ++csmisas_send_handshake_wait(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, ++ unsigned long timeout) + { + int rc; + unsigned long timeleft; +@@ -384,42 +360,13 @@ csmisas_send_handshake_wait(MPT_ADAPTER + rc = 0; + timeleft = 0; + +-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) +- +- INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status) +- ioc->taskmgmt_cmds.timer.expires = jiffies + (MPT_JIFFY*timeout); +- ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_TIMER_ACTIVE; +- ioc->taskmgmt_cmds.wait_done = 0; +- ADD_TIMER(&ioc->taskmgmt_cmds.timer); +- rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP); +- if (rc != 0) +- return rc; +- WAIT_EVENT(mptctl_taskmgmt_wait, ioc->taskmgmt_cmds.wait_done); +- +-#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) +- +- INITIALIZE_IOCTL_STATUS(ioc->taskmgmt_cmds.status) +- ioc->taskmgmt_cmds.wait_done = 0; +- rc = mpt_send_special_message(mptctl_taskmgmt_id, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)mf, timeout, CAN_SLEEP); +- if (rc != 0) +- return rc; +- if ((wait_event_timeout(mptctl_taskmgmt_wait, +- ioc->taskmgmt_cmds.wait_done == 1, HZ * timeout) <=0) && +- ioc->taskmgmt_cmds.wait_done != 1 ) { +- mptctl_timeout_expired(ioc, mf); +- mpt_free_msg_frame(ioc, mf); +- rc = -1; +- } +- +-#else + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); +- timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); ++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, ++ timeout*HZ); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -1; +- printk("%s: failed\n", __FUNCTION__); ++ printk(KERN_WARNING "%s: failed\n", __func__); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); +@@ -429,7 +376,6 @@ csmisas_send_handshake_wait(MPT_ADAPTER + if (!timeleft) + mptctl_timeout_expired(ioc, mf); + } +-#endif + return rc; + } + +@@ -527,7 +473,8 @@ csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IO + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + +- if ((rc = mpt_config(ioc, &cfg)) != 0) ++ rc = mpt_config(ioc, &cfg); ++ if (rc != 0) + goto get_ioc_pg5; + + if (hdr.PageLength == 0) { +@@ -547,7 +494,8 @@ csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IO + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + +- if ((rc = mpt_config(ioc, &cfg)) != 0) ++ rc = mpt_config(ioc, &cfg); ++ if (rc != 0) + goto get_ioc_pg5; + + memcpy(iocPage5, buffer, data_size); +@@ -565,7 +513,8 @@ csmisas_get_ioc_pg5(MPT_ADAPTER *ioc, IO + * csmisas_sas_device_pg0 - sas device page 0 + * @ioc: Pointer to MPT_ADAPTER structure + * @mptsas_devinfo: structure found in mptsas.h +- * @form, @form_specific - defines the Page Address field in the config page ++ * @form, @form_specific - defines the Page Address field in ++ * the config page + * (pls refer to chapter 5.1 in the mpi spec) + * + * Return: 0 for success +@@ -602,7 +551,8 @@ csmisas_sas_device_pg0(MPT_ADAPTER *ioc, + cfg.timeout = 10; + + memset(device_info, 0, sizeof(struct mptsas_devinfo)); +- if ((rc = mpt_config(ioc, &cfg)) != 0) ++ rc = mpt_config(ioc, &cfg); ++ if (rc != 0) + goto out; + + if (!hdr.ExtPageLength) { +@@ -620,7 +570,8 @@ csmisas_sas_device_pg0(MPT_ADAPTER *ioc, + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + +- if ((rc = mpt_config(ioc, &cfg)) != 0) ++ rc = mpt_config(ioc, &cfg); ++ if (rc != 0) + goto out_free_consistent; + + device_info->handle = le16_to_cpu(buffer->DevHandle); +@@ -664,31 +615,31 @@ csmisas_get_driver_info(unsigned long ar + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmi_sas_get_driver_info_buffer struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Fill in the data and return the structure to the calling + * program + */ +- memcpy( karg.Information.szName, MPT_MISCDEV_BASENAME, ++ memcpy(karg.Information.szName, MPT_MISCDEV_BASENAME, + sizeof(MPT_MISCDEV_BASENAME)); +- memcpy( karg.Information.szDescription, MPT_CSMI_DESCRIPTION, ++ memcpy(karg.Information.szDescription, MPT_CSMI_DESCRIPTION, + sizeof(MPT_CSMI_DESCRIPTION)); + + karg.Information.usMajorRevision = MPT_LINUX_MAJOR_VERSION; +@@ -707,11 +658,11 @@ csmisas_get_driver_info(unsigned long ar + sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -736,28 +687,28 @@ csmisas_get_cntlr_config(unsigned long a + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_CONFIG_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmi_sas_get_cntlr_config_buffer struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Clear the struct before filling in data. */ +- memset( &karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG)); ++ memset(&karg.Configuration, 0, sizeof(CSMI_SAS_CNTLR_CONFIG)); + + /* Fill in the data and return the structure to the calling + * program +@@ -786,7 +737,7 @@ csmisas_get_cntlr_config(unsigned long a + karg.Configuration.BusAddress.PciAddress.bFunctionNumber = + PCI_FUNC(ioc->pcidev->devfn); + karg.Configuration.BusAddress.PciAddress.bReserved = 0; +- memcpy( &karg.Configuration.szSerialNumber, ioc->board_tracer, 16 ); ++ memcpy(&karg.Configuration.szSerialNumber, ioc->board_tracer, 16); + karg.Configuration.usMajorRevision = ioc->facts.FWVersion.Struct.Major; + karg.Configuration.usMinorRevision = ioc->facts.FWVersion.Struct.Minor; + karg.Configuration.usBuildRevision = ioc->facts.FWVersion.Struct.Unit; +@@ -819,11 +770,11 @@ csmisas_get_cntlr_config(unsigned long a + sizeof(CSMI_SAS_DRIVER_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmi_sas_get_driver_info_buffer @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -848,24 +799,24 @@ csmisas_get_cntlr_status(unsigned long a + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmi_sas_get_cntlr_status_buffer struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Fill in the data and return the structure to the calling + * program +@@ -902,11 +853,11 @@ csmisas_get_cntlr_status(unsigned long a + sizeof(CSMI_SAS_CNTLR_STATUS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmi_sas_get_cntlr_status @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -940,19 +891,19 @@ csmisas_get_phy_info(unsigned long arg) + struct mptsas_devinfo device_info; + int memory_pages; + +- sasIoUnitPg0=NULL; +- sasPhyPg0=NULL; +- sasIoUnitPg0_data_sz=0; +- sasPhyPg0_data_sz=0; ++ sasIoUnitPg0 = NULL; ++ sasPhyPg0 = NULL; ++ sasIoUnitPg0_data_sz = 0; ++ sasPhyPg0_data_sz = 0; + + memory_pages = get_order(sizeof(CSMI_SAS_PHY_INFO_BUFFER)); + karg = (CSMI_SAS_PHY_INFO_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!karg){ ++ if (!karg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc CSMI_SAS_PHY_INFO_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + (int)sizeof(CSMI_SAS_PHY_INFO_BUFFER), memory_pages); + return -ENOMEM; + } +@@ -962,7 +913,7 @@ csmisas_get_phy_info(unsigned long arg) + if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in csmisas_get_phy_info_buffer struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } +@@ -970,19 +921,19 @@ csmisas_get_phy_info(unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Fill in the data and return the structure to the calling + * program +@@ -1011,7 +962,7 @@ csmisas_get_phy_info(unsigned long arg) + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: HEADER\n")); +- dcsmisasprintk(ioc, printk(": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(": rc=%x\n", rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } +@@ -1020,7 +971,8 @@ csmisas_get_phy_info(unsigned long arg) + /* Don't check if this failed. Already in a + * failure case. + */ +- dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": hdr.ExtPageLength == 0\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } +@@ -1032,7 +984,8 @@ csmisas_get_phy_info(unsigned long arg) + sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma); + + if (!sasIoUnitPg0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } +@@ -1048,7 +1001,7 @@ csmisas_get_phy_info(unsigned long arg) + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASIOUNITPAGE0_PAGEVERSION: PAGE\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } +@@ -1058,27 +1011,30 @@ csmisas_get_phy_info(unsigned long arg) + + /* Fill in information for each phy. */ + for (ii = 0; ii < karg->Information.bNumberOfPhys; ii++) { +- +-/* EDM : dump IO Unit Page 0 data*/ +- dcsmisasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n")); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "---- IO UNIT PAGE 0 ------------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Handle=0x%X\n", + le16_to_cpu(sasIoUnitPg0->PhyData[ii].AttachedDeviceHandle))); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Controller Handle=0x%X\n", + le16_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerDevHandle))); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Port=0x%X\n", + sasIoUnitPg0->PhyData[ii].Port)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", + sasIoUnitPg0->PhyData[ii].PortFlags)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", + sasIoUnitPg0->PhyData[ii].PhyFlags)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Negotiated Link Rate=0x%X\n", + sasIoUnitPg0->PhyData[ii].NegotiatedLinkRate)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Controller PHY Device Info=0x%X\n", + le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n", + le32_to_cpu(sasIoUnitPg0->PhyData[ii].DiscoveryStatus))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); +-/* EDM : debug data */ + + /* PHY stuff. */ + karg->Information.Phy[ii].bPortIdentifier = +@@ -1147,13 +1103,14 @@ csmisas_get_phy_info(unsigned long arg) + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n")); +- dcsmisasprintk(ioc, printk(": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(": rc=%x\n", rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } + + if (hdr.ExtPageLength == 0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } +@@ -1164,8 +1121,9 @@ csmisas_get_phy_info(unsigned long arg) + sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent( + ioc->pcidev, sasPhyPg0_data_sz, &sasPhyPg0_dma); + +- if (! sasPhyPg0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ if (!sasPhyPg0) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto sas_get_phy_info_exit; + } +@@ -1177,34 +1135,37 @@ csmisas_get_phy_info(unsigned long arg) + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + pci_free_consistent(ioc->pcidev, sasPhyPg0_data_sz, + (u8 *) sasPhyPg0, sasPhyPg0_dma); + goto sas_get_phy_info_exit; + } + +-/* EDM : dump PHY Page 0 data*/ + memcpy(&sas_address, &sasPhyPg0->SASAddress, sizeof(u64)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "---- SAS PHY PAGE 0 ------------\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n", + le16_to_cpu(sasPhyPg0->AttachedDevHandle))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", + (unsigned long long)sas_address)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Attached PHY Identifier=0x%X\n", + sasPhyPg0->AttachedPhyIdentifier)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Attached Device Info=0x%X\n", + le32_to_cpu(sasPhyPg0->AttachedDeviceInfo))); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Programmed Link Rate=0x%X\n", + sasPhyPg0->ProgrammedLinkRate)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Hardware Link Rate=0x%X\n", + sasPhyPg0->HwLinkRate)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", + sasPhyPg0->ChangeCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n", + le32_to_cpu(sasPhyPg0->PhyInfo))); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); +-/* EDM : debug data */ + + /* save the data */ + +@@ -1284,8 +1245,9 @@ csmisas_get_phy_info(unsigned long arg) + } + + karg->Information.Phy[ii].bPhyChangeCount = sasPhyPg0->ChangeCount; +- if( sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY ) +- karg->Information.Phy[ii].bPhyFeatures = CSMI_SAS_PHY_VIRTUAL_SMP; ++ if (sasPhyPg0->PhyInfo & MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY) ++ karg->Information.Phy[ii].bPhyFeatures ++ = CSMI_SAS_PHY_VIRTUAL_SMP; + + /* Fill in Attached Device + * Initiator Port Protocol. +@@ -1295,17 +1257,17 @@ csmisas_get_phy_info(unsigned long arg) + protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x78; + karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = 0; + if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) +- karg->Information.Phy[ii].Attached.bInitiatorPortProtocol = +- CSMI_SAS_PROTOCOL_SSP; ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol ++ = CSMI_SAS_PROTOCOL_SSP; + if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR) +- karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_STP; ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_STP; + if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) +- karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_SMP; ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_SMP; + if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST) +- karg->Information.Phy[ii].Attached.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_SATA; ++ karg->Information.Phy[ii].Attached.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_SATA; + + /* Fill in Phy Target Port + * Protocol. Bits 10:7 +@@ -1314,17 +1276,17 @@ csmisas_get_phy_info(unsigned long arg) + protocol = le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & 0x780; + karg->Information.Phy[ii].Attached.bTargetPortProtocol = 0; + if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET) +- karg->Information.Phy[ii].Attached.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_SSP; ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_SSP; + if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET) +- karg->Information.Phy[ii].Attached.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_STP; ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_STP; + if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET) +- karg->Information.Phy[ii].Attached.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_SMP; ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_SMP; + if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE) +- karg->Information.Phy[ii].Attached.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_SATA; ++ karg->Information.Phy[ii].Attached.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_SATA; + + + /* Fill in Attached device type */ +@@ -1353,7 +1315,8 @@ csmisas_get_phy_info(unsigned long arg) + } + + /* Identify Info. */ +- switch (le32_to_cpu(sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & ++ switch (le32_to_cpu ++ (sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & + MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { + + case MPI_SAS_DEVICE_INFO_NO_DEVICE: +@@ -1383,18 +1346,18 @@ csmisas_get_phy_info(unsigned long arg) + protocol = le32_to_cpu( + sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x78; + karg->Information.Phy[ii].Identify.bInitiatorPortProtocol = 0; +- if( protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR ) +- karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_SSP; +- if( protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR ) +- karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_STP; +- if( protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR ) +- karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_SMP; +- if( protocol & MPI_SAS_DEVICE_INFO_SATA_HOST ) +- karg->Information.Phy[ii].Identify.bInitiatorPortProtocol |= +- CSMI_SAS_PROTOCOL_SATA; ++ if (protocol & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_SSP; ++ if (protocol & MPI_SAS_DEVICE_INFO_STP_INITIATOR) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_STP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_SMP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SATA_HOST) ++ karg->Information.Phy[ii].Identify.bInitiatorPortProtocol ++ |= CSMI_SAS_PROTOCOL_SATA; + + /* Fill in Phy Target Port Protocol. Bits 10:7 + * More than one bit can be set, fall through cases. +@@ -1402,18 +1365,18 @@ csmisas_get_phy_info(unsigned long arg) + protocol = le32_to_cpu( + sasIoUnitPg0->PhyData[ii].ControllerPhyDeviceInfo) & 0x780; + karg->Information.Phy[ii].Identify.bTargetPortProtocol = 0; +- if( protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET ) +- karg->Information.Phy[ii].Identify.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_SSP; +- if( protocol & MPI_SAS_DEVICE_INFO_STP_TARGET ) +- karg->Information.Phy[ii].Identify.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_STP; +- if( protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET ) +- karg->Information.Phy[ii].Identify.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_SMP; +- if( protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE ) +- karg->Information.Phy[ii].Identify.bTargetPortProtocol |= +- CSMI_SAS_PROTOCOL_SATA; ++ if (protocol & MPI_SAS_DEVICE_INFO_SSP_TARGET) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_SSP; ++ if (protocol & MPI_SAS_DEVICE_INFO_STP_TARGET) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_STP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SMP_TARGET) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_SMP; ++ if (protocol & MPI_SAS_DEVICE_INFO_SATA_DEVICE) ++ karg->Information.Phy[ii].Identify.bTargetPortProtocol ++ |= CSMI_SAS_PROTOCOL_SATA; + + /* Setup SAS Address for the attached device */ + if (sasPhyPg0->AttachedDevHandle) { +@@ -1450,13 +1413,13 @@ sas_get_phy_info_exit: + sizeof(CSMI_SAS_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write out csmisas_get_phy_info_buffer @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + free_pages((unsigned long)karg, memory_pages); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -1479,30 +1442,28 @@ csmisas_set_phy_info(unsigned long arg) + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_set_phy_info struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + +-/* TODO - implement IOCTL here */ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); + +-// cim_set_phy_info_exit: + + /* Copy the data from kernel memory to user memory + */ +@@ -1510,11 +1471,11 @@ csmisas_set_phy_info(unsigned long arg) + sizeof(CSMI_SAS_SET_PHY_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_set_phy_info @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + + } +@@ -1541,24 +1502,24 @@ csmisas_get_scsi_address(unsigned long a + sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_get_scsi_address struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* reverse byte order the sas address */ + memcpy(&sas_address, karg.bSASAddress, sizeof(u64)); +@@ -1586,11 +1547,11 @@ csmisas_get_scsi_address(unsigned long a + sizeof(CSMI_SAS_GET_SCSI_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_scsi_address @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -1621,37 +1582,38 @@ csmisas_get_sata_signature(unsigned long + u8 phyId; + u64 sas_address; + +- sasPhyPg0=NULL; +- sasPhyPg0_data_sz=0; +- sasDevicePg1=NULL; +- sasDevicePg1_data_sz=0; ++ sasPhyPg0 = NULL; ++ sasPhyPg0_data_sz = 0; ++ sasDevicePg1 = NULL; ++ sasDevicePg1_data_sz = 0; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_sata_signature struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + phyId = karg.Signature.bPhyIdentifier; + if (phyId >= ioc->num_ports) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST; +- dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); + goto cim_sata_signature_exit; + } + +@@ -1683,7 +1645,7 @@ csmisas_get_sata_signature(unsigned long + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: HEADER\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } +@@ -1692,7 +1654,8 @@ csmisas_get_sata_signature(unsigned long + /* Don't check if this failed. Already in a + * failure case. + */ +- dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } +@@ -1704,8 +1667,9 @@ csmisas_get_sata_signature(unsigned long + sasPhyPg0 = (SasPhyPage0_t *) pci_alloc_consistent(ioc->pcidev, + sasPhyPg0_data_sz, &sasPhyPg0_dma); + +- if (! sasPhyPg0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ if (!sasPhyPg0) { ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } +@@ -1720,7 +1684,7 @@ csmisas_get_sata_signature(unsigned long + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY0_PAGEVERSION: PAGE\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } +@@ -1728,7 +1692,8 @@ csmisas_get_sata_signature(unsigned long + /* Make sure a SATA device is attached. */ + if ((le32_to_cpu(sasPhyPg0->AttachedDeviceInfo) & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) == 0) { +- dcsmisasprintk(ioc, printk(KERN_WARNING ": NOT A SATA DEVICE\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_WARNING ": NOT A SATA DEVICE\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_SATA_DEVICE; + goto cim_sata_signature_exit; + } +@@ -1755,13 +1720,14 @@ csmisas_get_sata_signature(unsigned long + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASDEVICE1_PAGEVERSION: HEADER\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + + if (hdr.ExtPageLength == 0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": hdr.ExtPageLength == 0\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } +@@ -1772,8 +1738,9 @@ csmisas_get_sata_signature(unsigned long + sasDevicePg1 = (SasDevicePage1_t *) pci_alloc_consistent + (ioc->pcidev, sasDevicePg1_data_sz, &sasDevicePg1_dma); + +- if (! sasDevicePg1) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ if (!sasDevicePg1) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } +@@ -1785,29 +1752,31 @@ csmisas_get_sata_signature(unsigned long + if ((rc = mpt_config(ioc, &cfg)) != 0) { + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASDEVICE1_PAGEVERSION: PAGE\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sata_signature_exit; + } + +-/* EDM : dump Device Page 1 data*/ +- dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 1 ---------\n")); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Handle=0x%x\n",sasDevicePg1->DevHandle)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "---- SAS DEVICE PAGE 1 ---------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Handle=0x%x\n", sasDevicePg1->DevHandle)); + memcpy(&sas_address, &sasDevicePg1->SASAddress, sizeof(u64)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", + (unsigned long long)sas_address)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%x\n",sasDevicePg1->TargetID)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Bus=0x%x\n",sasDevicePg1->Bus)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Target ID=0x%x\n", sasDevicePg1->TargetID)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Bus=0x%x\n", sasDevicePg1->Bus)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Initial Reg Device FIS=")); +- for(jj=0;jj<20;jj++) ++ for (jj = 0; jj < 20; jj++) + dcsmisasprintk(ioc, printk("%02x ", + ((u8 *)&sasDevicePg1->InitialRegDeviceFIS)[jj])); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n")); +-/* EDM : debug data */ + + memcpy(karg.Signature.bSignatureFIS, +- sasDevicePg1->InitialRegDeviceFIS,20); ++ sasDevicePg1->InitialRegDeviceFIS, 20); + + cim_sata_signature_exit: + +@@ -1825,11 +1794,11 @@ csmisas_get_sata_signature(unsigned long + sizeof(CSMI_SAS_SATA_SIGNATURE_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_sata_signature @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -1855,24 +1824,24 @@ csmisas_get_device_address(unsigned long + sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_get_device_address_buffer struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_NO_DEVICE_ADDRESS; + memset(karg.bSASAddress, 0, sizeof(u64)); +@@ -1896,11 +1865,11 @@ csmisas_get_device_address(unsigned long + sizeof(CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_device_address_buffer @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -1933,35 +1902,36 @@ csmisas_get_link_errors(unsigned long ar + u16 ioc_status; + u32 MsgContext; + +- sasPhyPage1=NULL; +- sasPhyPage1_data_sz=0; ++ sasPhyPage1 = NULL; ++ sasPhyPage1_data_sz = 0; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmisas_get_link_errors struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + phyId = karg.Information.bPhyIdentifier; + if (phyId >= ioc->num_ports) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_PHY_DOES_NOT_EXIST; +- dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports\n")); ++ dcsmisasprintk(ioc, printk(KERN_WARNING ++ ": phyId >= ioc->num_ports\n")); + goto cim_get_link_errors_exit; + } + +@@ -1993,7 +1963,7 @@ csmisas_get_link_errors(unsigned long ar + */ + dcsmisasprintk(ioc, printk(KERN_ERR + ": FAILED: MPI_SASPHY1_PAGEVERSION: HEADER\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } +@@ -2002,7 +1972,8 @@ csmisas_get_link_errors(unsigned long ar + /* Don't check if this failed. Already in a + * failure case. + */ +- dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": hdr.ExtPageLength == 0\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } +@@ -2014,8 +1985,9 @@ csmisas_get_link_errors(unsigned long ar + sasPhyPage1 = (SasPhyPage1_t *) pci_alloc_consistent(ioc->pcidev, + sasPhyPage1_data_sz, &sasPhyPage1_dma); + +- if (! sasPhyPage1) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ if (!sasPhyPage1) { ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } +@@ -2028,24 +2000,25 @@ csmisas_get_link_errors(unsigned long ar + /* Don't check if this failed. Already in a + * failure case. + */ +- dcsmisasprintk(ioc, printk(KERN_ERR ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n")); +- dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n",rc)); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": FAILED: MPI_SASPHY1_PAGEVERSION: PAGE\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ": rc=%x\n", rc)); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; + } + +-/* EDM : dump PHY Page 1 data*/ +- dcsmisasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "---- SAS PHY PAGE 1 ------------\n")); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", + sasPhyPage1->InvalidDwordCount)); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "Running Disparity Error Count=0x%x\n", + sasPhyPage1->RunningDisparityErrorCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", + sasPhyPage1->LossDwordSynchCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n", + sasPhyPage1->PhyResetProblemCount)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n\n")); +-/* EDM : debug data */ + + karg.Information.uInvalidDwordCount = + le32_to_cpu(sasPhyPage1->InvalidDwordCount); +@@ -2057,7 +2030,7 @@ csmisas_get_link_errors(unsigned long ar + le32_to_cpu(sasPhyPage1->PhyResetProblemCount); + + if (karg.Information.bResetCounts == +- CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS ) { ++ CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS) { + goto cim_get_link_errors_exit; + } + +@@ -2072,12 +2045,12 @@ csmisas_get_link_errors(unsigned long ar + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_link_errors_exit; +- } ++ } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; +- memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); ++ memset(sasIoUnitCntrReq, 0, sizeof(SasIoUnitControlRequest_t)); + sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; + sasIoUnitCntrReq->MsgContext = MsgContext; + sasIoUnitCntrReq->PhyNum = phyId; +@@ -2097,8 +2070,10 @@ csmisas_get_link_errors(unsigned long ar + & MPI_IOCSTATUS_MASK; + + if (ioc_status != MPI_IOCSTATUS_SUCCESS) { +- dcsmisasprintk(ioc, printk(KERN_DEBUG ": SAS IO Unit Control: ")); +- dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ ": SAS IO Unit Control: ")); ++ dcsmisasprintk(ioc, printk( ++ "IOCStatus=0x%X IOCLogInfo=0x%X\n", + sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo)); + } +@@ -2116,11 +2091,11 @@ csmisas_get_link_errors(unsigned long ar + sizeof(CSMI_SAS_LINK_ERRORS_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmisas_get_link_errors @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + + } +@@ -2145,10 +2120,10 @@ csmisas_smp_passthru(unsigned long arg) + MPIHeader_t *mpi_hdr; + char *psge; + int iocnum, flagsLength; +- void * request_data; ++ void *request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; +- void * response_data; ++ void *response_data; + dma_addr_t response_data_dma; + u32 response_data_sz; + u16 ioc_status; +@@ -2161,11 +2136,11 @@ csmisas_smp_passthru(unsigned long arg) + memory_pages = get_order(malloc_data_sz); + karg = (CSMI_SAS_SMP_PASSTHRU_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!karg){ ++ if (!karg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc CSMI_SAS_SMP_PASSTHRU_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + malloc_data_sz, memory_pages); + return -ENOMEM; + } +@@ -2173,7 +2148,7 @@ csmisas_smp_passthru(unsigned long arg) + if (copy_from_user(karg, uarg, sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_smp_passthru struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } +@@ -2186,7 +2161,7 @@ csmisas_smp_passthru(unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } +@@ -2194,19 +2169,19 @@ csmisas_smp_passthru(unsigned long arg) + if (ioc->ioc_reset_in_progress) { + printk(KERN_ERR "%s@%d::%s - " + "Busy with IOC Reset \n", +- __FILE__, __LINE__,__FUNCTION__); ++ __FILE__, __LINE__, __func__); + free_pages((unsigned long)karg, memory_pages); + return -EBUSY; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Default to success.*/ + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; +@@ -2228,13 +2203,13 @@ csmisas_smp_passthru(unsigned long arg) + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; +- } ++ } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; +- smpReq = (pSmpPassthroughRequest_t ) mf; ++ smpReq = (pSmpPassthroughRequest_t) mf; + +- memset(smpReq,0,ioc->req_sz); ++ memset(smpReq, 0, ioc->req_sz); + + memcpy(&sas_address, karg->Parameters.bDestinationSASAddress, + sizeof(u64)); +@@ -2270,7 +2245,8 @@ csmisas_smp_passthru(unsigned long arg) + ioc->pcidev, request_data_sz, &request_data_dma); + + if (!request_data) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); + goto cim_smp_passthru_exit; +@@ -2286,7 +2262,8 @@ csmisas_smp_passthru(unsigned long arg) + ioc->pcidev, response_data_sz, &response_data_dma); + + if (!response_data) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); + goto cim_smp_passthru_exit; +@@ -2302,26 +2279,29 @@ csmisas_smp_passthru(unsigned long arg) + + ioc->add_sge(psge, flagsLength, response_data_dma); + +- if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { ++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) ++ != 0) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; + } + + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { +- dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: oh no, there is no reply!!")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ ": SMP Passthru: oh no, there is no reply!!")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_smp_passthru_exit; + } + + /* process the completed Reply Message Frame */ +- smpReply = (pSmpPassthroughReply_t )ioc->ioctl_cmds.reply; ++ smpReply = (pSmpPassthroughReply_t)ioc->ioctl_cmds.reply; + ioc_status = le16_to_cpu(smpReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if ((ioc_status != MPI_IOCSTATUS_SUCCESS) && + (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": SMP Passthru: ")); +- dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", ++ dcsmisasprintk(ioc, printk( ++ "IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", + le16_to_cpu(smpReply->IOCStatus), + le32_to_cpu(smpReply->IOCLogInfo), + smpReply->SASStatus)); +@@ -2333,7 +2313,8 @@ csmisas_smp_passthru(unsigned long arg) + + + if (le16_to_cpu(smpReply->ResponseDataLength)) { +- karg->Parameters.uResponseBytes = le16_to_cpu(smpReply->ResponseDataLength); ++ karg->Parameters.uResponseBytes ++ = le16_to_cpu(smpReply->ResponseDataLength); + memcpy(&karg->Parameters.Response, + response_data, le16_to_cpu(smpReply->ResponseDataLength)); + } +@@ -2355,13 +2336,13 @@ csmisas_smp_passthru(unsigned long arg) + sizeof(CSMI_SAS_SMP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_smp_passthru @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + free_pages((unsigned long)karg, memory_pages); +- dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n", __func__)); + return 0; + } + +@@ -2376,18 +2357,18 @@ csmisas_smp_passthru(unsigned long arg) + static int csmisas_ssp_passthru(unsigned long arg) + { + CSMI_SAS_SSP_PASSTHRU_BUFFER __user *uarg = (void __user *) arg; +- CSMI_SAS_SSP_PASSTHRU_BUFFER karg_hdr, * karg; ++ CSMI_SAS_SSP_PASSTHRU_BUFFER karg_hdr, *karg; + MPT_ADAPTER *ioc = NULL; + pSCSIIORequest_t pScsiRequest; + pSCSIIOReply_t pScsiReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; +- int iocnum,ii; ++ int iocnum, ii; + u64 sas_address; + u16 req_idx; + char *psge; + int flagsLength; +- void * request_data; ++ void *request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + int malloc_data_sz; +@@ -2402,10 +2383,11 @@ static int csmisas_ssp_passthru(unsigned + u8 skey, asc, ascq; + u32 MsgContext; + +- if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_SSP_PASSTHRU_BUFFER))) { ++ if (copy_from_user(&karg_hdr, uarg, ++ sizeof(CSMI_SAS_SSP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +@@ -2422,11 +2404,11 @@ static int csmisas_ssp_passthru(unsigned + memory_pages = get_order(malloc_data_sz); + karg = (CSMI_SAS_SSP_PASSTHRU_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!karg){ ++ if (!karg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc SAS_SSP_PASSTHRU_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + malloc_data_sz, memory_pages); + return -ENOMEM; + } +@@ -2434,10 +2416,10 @@ static int csmisas_ssp_passthru(unsigned + memset(karg, 0, sizeof(*karg)); + + if (copy_from_user(karg, uarg, request_data_sz + +- offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer))) { ++ offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } +@@ -2445,40 +2427,43 @@ static int csmisas_ssp_passthru(unsigned + /* + * some checks of the incoming frame + */ +- if ( offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER,bDataBuffer) + ++ if (offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer) + + request_data_sz - sizeof(IOCTL_HEADER) > +- karg->IoctlHeader.Length ) { +- karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ karg->IoctlHeader.Length) { ++ karg->IoctlHeader.ReturnCode ++ = CSMI_SAS_STATUS_INVALID_PARAMETER; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s()" + " @%d - expected datalen incorrect!\n", +- __FILE__, __FUNCTION__, __LINE__)); ++ __FILE__, __func__, __LINE__)); + goto cim_ssp_passthru_exit; + } + + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { +- karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ karg->IoctlHeader.ReturnCode ++ = CSMI_SAS_STATUS_INVALID_PARAMETER; + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + goto cim_ssp_passthru_exit; + } + + if (ioc->ioc_reset_in_progress) { + printk(KERN_ERR "%s@%d::%s - " + "Busy with IOC Reset \n", +- __FILE__, __LINE__,__FUNCTION__); ++ __FILE__, __LINE__, __func__); + return -EBUSY; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { +- karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; ++ karg->IoctlHeader.ReturnCode ++ = CSMI_SAS_STATUS_INVALID_PARAMETER; + printk(KERN_ERR "%s::%s()@%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + goto cim_ssp_passthru_exit; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Default to success. + */ +@@ -2492,7 +2477,7 @@ static int csmisas_ssp_passthru(unsigned + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s()" + " @%d - incorrect bPhyIdentifier and bPortIdentifier!\n", +- __FILE__, __FUNCTION__, __LINE__)); ++ __FILE__, __func__, __LINE__)); + goto cim_ssp_passthru_exit; + } + +@@ -2502,7 +2487,8 @@ static int csmisas_ssp_passthru(unsigned + + /* Is the phy in range? */ + if (karg->Parameters.bPhyIdentifier >= ioc->num_ports) { +- dcsmisasprintk(ioc, printk(KERN_WARNING ": phyId >= ioc->num_ports (%d %d)\n", ++ dcsmisasprintk(ioc, printk(KERN_WARNING ++ ": phyId >= ioc->num_ports (%d %d)\n", + karg->Parameters.bPhyIdentifier, + ioc->num_ports)); + karg->IoctlHeader.ReturnCode = +@@ -2511,10 +2497,9 @@ static int csmisas_ssp_passthru(unsigned + } + } + +- if(karg->Parameters.bAdditionalCDBLength) { +- /* TODO - SCSI IO (32) Request Message support +- */ +- dcsmisasprintk(ioc, printk(KERN_DEBUG ": greater than 16-byte cdb " ++ if (karg->Parameters.bAdditionalCDBLength) { ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ ": greater than 16-byte cdb " + "is not supported!\n")); + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; +@@ -2538,7 +2523,7 @@ static int csmisas_ssp_passthru(unsigned + CSMI_SAS_STATUS_INVALID_PARAMETER; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s() @%d - couldn't find associated " +- "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__, ++ "SASAddress=%llX!\n", __FILE__, __func__, __LINE__, + (unsigned long long)sas_address)); + goto cim_ssp_passthru_exit; + } +@@ -2558,20 +2543,21 @@ static int csmisas_ssp_passthru(unsigned + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_ssp_passthru_exit; +- } ++ } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + pScsiRequest = (pSCSIIORequest_t) mf; + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + +- memset(pScsiRequest,0,sizeof(SCSIIORequest_t)); ++ memset(pScsiRequest, 0, sizeof(SCSIIORequest_t)); + + /* Fill in SCSI IO (16) request. + */ + + pScsiRequest->Function = (is_hidden_raid_component == 1) ? +- MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH : MPI_FUNCTION_SCSI_IO_REQUEST; ++ MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ++ : MPI_FUNCTION_SCSI_IO_REQUEST; + pScsiRequest->TargetID = id; + pScsiRequest->Bus = channel; + memcpy(pScsiRequest->LUN, &karg->Parameters.bLun, 8); +@@ -2583,10 +2569,11 @@ static int csmisas_ssp_passthru(unsigned + + dcsmisasprintk(ioc, printk(KERN_DEBUG "\tchannel = %d id = %d ", + sas_info->fw.channel, sas_info->fw.id)); +- dcsmisasprintk(ioc, if(is_hidden_raid_component) ++ dcsmisasprintk(ioc, if (is_hidden_raid_component) + printk(KERN_DEBUG "num_id = %d ", id)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\n")); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "\tcdb_len = %d request_len = %d\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "\tcdb_len = %d request_len = %d\n", + pScsiRequest->CDBLength, request_data_sz)); + dcsmisasprintk(ioc, printk(KERN_DEBUG "\t")); + dcsmisasprintk(ioc, for (ii = 0; ii < pScsiRequest->CDBLength; ++ii) +@@ -2603,7 +2590,8 @@ static int csmisas_ssp_passthru(unsigned + (!karg->Parameters.uDataLength)) { + /* no data transfer + */ +- pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_NODATATRANSFER); ++ pScsiRequest->Control ++ = cpu_to_le32(MPI_SCSIIO_CONTROL_NODATATRANSFER); + } else { + /* no direction specified + */ +@@ -2618,19 +2606,23 @@ static int csmisas_ssp_passthru(unsigned + + /* task attributes + */ +- if((karg->Parameters.uFlags && 0xFF) == 0) { +- pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ); ++ if ((karg->Parameters.uFlags && 0xFF) == 0) { ++ pScsiRequest->Control ++ |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ); + } else if (karg->Parameters.uFlags & + CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE) { +- pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ); ++ pScsiRequest->Control ++ |= cpu_to_le32(MPI_SCSIIO_CONTROL_HEADOFQ); + } else if (karg->Parameters.uFlags & + CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED) { +- pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ); ++ pScsiRequest->Control ++ |= cpu_to_le32(MPI_SCSIIO_CONTROL_ORDEREDQ); + } else if (karg->Parameters.uFlags & + CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA) { + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_ACAQ); + } else { +- pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED); ++ pScsiRequest->Control ++ |= cpu_to_le32(MPI_SCSIIO_CONTROL_UNTAGGED); + } + + /* setup sense +@@ -2647,19 +2639,20 @@ static int csmisas_ssp_passthru(unsigned + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; + } else if (karg->Parameters.uFlags & CSMI_SAS_SSP_READ) { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; +- }else { +- flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | +- MPI_SGE_FLAGS_DIRECTION ) ++ } else { ++ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_DIRECTION) + << MPI_SGE_FLAGS_SHIFT; + } + flagsLength |= request_data_sz; + +- if ( request_data_sz > 0) { ++ if (request_data_sz > 0) { + request_data = pci_alloc_consistent( + ioc->pcidev, request_data_sz, &request_data_dma); + + if (request_data == NULL) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED " ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED " + "request_data_sz=%d\n", request_data_sz)); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); +@@ -2668,17 +2661,19 @@ static int csmisas_ssp_passthru(unsigned + + ioc->add_sge(psge, flagsLength, request_data_dma); + if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) +- memcpy(request_data, karg->bDataBuffer, request_data_sz); ++ memcpy(request_data, karg->bDataBuffer, ++ request_data_sz); + } else { + ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); + } + +- if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { ++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) ++ != 0) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_ssp_passthru_exit; + } + +- memset(&karg->Status,0,sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); ++ memset(&karg->Status, 0, sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); + karg->Status.bConnectionStatus = CSMI_SAS_OPEN_ACCEPT; + karg->Status.bDataPresent = CSMI_SAS_SSP_NO_DATA_PRESENT; + karg->Status.bStatus = GOOD; +@@ -2689,11 +2684,13 @@ static int csmisas_ssp_passthru(unsigned + /* process the completed Reply Message Frame */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + +- pScsiReply = (pSCSIIOReply_t ) ioc->ioctl_cmds.reply; ++ pScsiReply = (pSCSIIOReply_t) ioc->ioctl_cmds.reply; + karg->Status.bStatus = pScsiReply->SCSIStatus; +- karg->Status.uDataBytes = min(le32_to_cpu(pScsiReply->TransferCount), ++ karg->Status.uDataBytes ++ = min(le32_to_cpu(pScsiReply->TransferCount), + request_data_sz); +- ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; ++ ioc_status ++ = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if (pScsiReply->SCSIState == + MPI_SCSI_STATE_AUTOSENSE_VALID) { +@@ -2701,26 +2698,28 @@ static int csmisas_ssp_passthru(unsigned + CSMI_SAS_SSP_SENSE_DATA_PRESENT; + karg->Status.bResponseLength[0] = + (u8)le32_to_cpu(pScsiReply->SenseCount) & 0xFF; +- memcpy(karg->Status.bResponse, +- ioc->ioctl_cmds.sense, le32_to_cpu(pScsiReply->SenseCount)); ++ memcpy(karg->Status.bResponse, ioc->ioctl_cmds.sense, ++ le32_to_cpu(pScsiReply->SenseCount)); + + skey = ioc->ioctl_cmds.sense[2] & 0x0F; + asc = ioc->ioctl_cmds.sense[12]; + ascq = ioc->ioctl_cmds.sense[13]; + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "\t [sense_key,asc,ascq]: " +- "[0x%02x,0x%02x,0x%02x]\n", +- skey, asc, ascq)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "\t [sense_key,asc,ascq]: " ++ "[0x%02x,0x%02x,0x%02x]\n", ++ skey, asc, ascq)); + +- } else if(pScsiReply->SCSIState == ++ } else if (pScsiReply->SCSIState == + MPI_SCSI_STATE_RESPONSE_INFO_VALID) { + karg->Status.bDataPresent = + CSMI_SAS_SSP_RESPONSE_DATA_PRESENT; + karg->Status.bResponseLength[0] = + sizeof(pScsiReply->ResponseInfo); +- for (ii=0;iiResponseInfo);ii++) { ++ for (ii = 0; ii < sizeof(pScsiReply->ResponseInfo); ++ ii++) { + karg->Status.bResponse[ii] = +- ((u8*)&pScsiReply->ResponseInfo)[ ++ ((u8 *)&pScsiReply->ResponseInfo)[ + (sizeof(pScsiReply->ResponseInfo)-1)-ii]; + } + } else if ((ioc_status != MPI_IOCSTATUS_SUCCESS) && +@@ -2728,7 +2727,8 @@ static int csmisas_ssp_passthru(unsigned + (ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": SCSI IO : ")); +- dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ dcsmisasprintk(ioc, ++ printk("IOCStatus=0x%X IOCLogInfo=0x%X\n", + pScsiReply->IOCStatus, + pScsiReply->IOCLogInfo)); + } +@@ -2740,8 +2740,8 @@ static int csmisas_ssp_passthru(unsigned + request_data, karg->Status.uDataBytes)) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to write data to user %p\n", +- __FILE__, __LINE__,__FUNCTION__, +- (void*)karg->bDataBuffer); ++ __FILE__, __LINE__, __func__, ++ (void *)karg->bDataBuffer); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + } + } +@@ -2759,12 +2759,12 @@ static int csmisas_ssp_passthru(unsigned + offsetof(CSMI_SAS_SSP_PASSTHRU_BUFFER, bDataBuffer))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_ssp_passthru @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + free_pages((unsigned long)karg, memory_pages); + return 0; + } +@@ -2793,7 +2793,7 @@ csmisas_stp_passthru(unsigned long arg) + u16 req_idx; + char *psge; + int flagsLength; +- void * request_data; ++ void *request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + int malloc_data_sz; +@@ -2806,14 +2806,15 @@ csmisas_stp_passthru(unsigned long arg) + u16 ioc_status; + u32 MsgContext; + +- if (copy_from_user(&karg_hdr, uarg, sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER))) { ++ if (copy_from_user(&karg_hdr, uarg, ++ sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- request_data=NULL; ++ request_data = NULL; + request_data_sz = karg_hdr.Parameters.uDataLength; + volume_id = 0; + volume_bus = 0; +@@ -2825,11 +2826,11 @@ csmisas_stp_passthru(unsigned long arg) + memory_pages = get_order(malloc_data_sz); + karg = (CSMI_SAS_STP_PASSTHRU_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!karg){ ++ if (!karg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc CSMI_SAS_STP_PASSTHRU_BUFFER " + "malloc_data_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + malloc_data_sz, memory_pages); + return -ENOMEM; + } +@@ -2839,7 +2840,7 @@ csmisas_stp_passthru(unsigned long arg) + if (copy_from_user(karg, uarg, malloc_data_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_ssp_passthru struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } +@@ -2847,7 +2848,7 @@ csmisas_stp_passthru(unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } +@@ -2855,19 +2856,19 @@ csmisas_stp_passthru(unsigned long arg) + if (ioc->ioc_reset_in_progress) { + printk(KERN_ERR "%s@%d::%s - " + "Busy with IOC Reset \n", +- __FILE__, __LINE__,__FUNCTION__); ++ __FILE__, __LINE__, __func__); + free_pages((unsigned long)karg, memory_pages); + return -EBUSY; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Default to success. + */ +@@ -2879,8 +2880,9 @@ csmisas_stp_passthru(unsigned long arg) + (karg->Parameters.bPortIdentifier == CSMI_SAS_IGNORE_PORT)) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_SELECT_PHY_OR_PORT; + dcsmisasprintk(ioc, printk(KERN_ERR +- "%s::%s() @%d - incorrect bPhyIdentifier and bPortIdentifier!\n", +- __FILE__,__FUNCTION__, __LINE__)); ++ "%s::%s() @%d -incorrect bPhyIdentifier" ++ " and bPortIdentifier!\n", ++ __FILE__, __func__, __LINE__)); + goto cim_stp_passthru_exit; + } + +@@ -2897,15 +2899,15 @@ csmisas_stp_passthru(unsigned long arg) + } + + data_sz = sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) - +- sizeof(IOCTL_HEADER) - sizeof(u8*) + ++ sizeof(IOCTL_HEADER) - sizeof(u8 *) + + request_data_sz; + +- if ( data_sz > karg->IoctlHeader.Length ) { ++ if (data_sz > karg->IoctlHeader.Length) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s() @%d - expected datalen incorrect!\n", +- __FILE__, __FUNCTION__,__LINE__)); ++ __FILE__, __func__, __LINE__)); + goto cim_stp_passthru_exit; + } + +@@ -2927,7 +2929,7 @@ csmisas_stp_passthru(unsigned long arg) + CSMI_SAS_STATUS_INVALID_PARAMETER; + dcsmisasprintk(ioc, printk(KERN_ERR + "%s::%s() @%d - couldn't find associated " +- "SASAddress=%llX!\n", __FILE__, __FUNCTION__, __LINE__, ++ "SASAddress=%llX!\n", __FILE__, __func__, __LINE__, + (unsigned long long)sas_address)); + goto cim_stp_passthru_exit; + } +@@ -2937,8 +2939,8 @@ csmisas_stp_passthru(unsigned long arg) + + /* check that this is an STP or SATA target device + */ +- if ( !(sas_info->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET ) && +- !(sas_info->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE )) { ++ if (!(sas_info->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) && ++ !(sas_info->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + goto cim_stp_passthru_exit; +@@ -2950,14 +2952,14 @@ csmisas_stp_passthru(unsigned long arg) + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_stp_passthru_exit; +- } ++ } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + pSataRequest = (pSataPassthroughRequest_t) mf; + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + +- memset(pSataRequest,0,sizeof(pSataPassthroughRequest_t)); ++ memset(pSataRequest, 0, sizeof(pSataPassthroughRequest_t)); + + pSataRequest->TargetID = id; + pSataRequest->Bus = channel; +@@ -2967,16 +2969,16 @@ csmisas_stp_passthru(unsigned long arg) + pSataRequest->MsgContext = MsgContext; + pSataRequest->DataLength = cpu_to_le32(request_data_sz); + pSataRequest->MsgFlags = 0; +- memcpy( pSataRequest->CommandFIS,karg->Parameters.bCommandFIS, 20); ++ memcpy(pSataRequest->CommandFIS, karg->Parameters.bCommandFIS, 20); + + psge = (char *)&pSataRequest->SGL; + if (karg->Parameters.uFlags & CSMI_SAS_STP_WRITE) { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; + } else if (karg->Parameters.uFlags & CSMI_SAS_STP_READ) { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; +- }else { +- flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | +- MPI_SGE_FLAGS_DIRECTION ) ++ } else { ++ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_DIRECTION) + << MPI_SGE_FLAGS_SHIFT; + } + +@@ -2986,7 +2988,8 @@ csmisas_stp_passthru(unsigned long arg) + ioc->pcidev, request_data_sz, &request_data_dma); + + if (request_data == NULL) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, printk(KERN_ERR ++ ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + mpt_free_msg_frame(ioc, mf); + goto cim_stp_passthru_exit; +@@ -2994,33 +2997,37 @@ csmisas_stp_passthru(unsigned long arg) + + ioc->add_sge(psge, flagsLength, request_data_dma); + if (karg->Parameters.uFlags & CSMI_SAS_SSP_WRITE) +- memcpy(request_data, karg->bDataBuffer, request_data_sz); ++ memcpy(request_data, karg->bDataBuffer, ++ request_data_sz); + } else { + ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); + } + +- if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) != 0) { ++ if (csmisas_send_command_wait(ioc, mf, karg->IoctlHeader.Timeout) ++ != 0) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_stp_passthru_exit; + } + +- memset(&karg->Status,0,sizeof(CSMI_SAS_STP_PASSTHRU_STATUS)); ++ memset(&karg->Status, 0, sizeof(CSMI_SAS_STP_PASSTHRU_STATUS)); + + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { +- dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: oh no, there is no reply!!")); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ ": STP Passthru: oh no, there is no reply!!")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_stp_passthru_exit; + } + + /* process the completed Reply Message Frame */ +- pSataReply = (pSataPassthroughReply_t ) ioc->ioctl_cmds.reply; ++ pSataReply = (pSataPassthroughReply_t) ioc->ioctl_cmds.reply; + ioc_status = le16_to_cpu(pSataReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if (ioc_status != MPI_IOCSTATUS_SUCCESS && + ioc_status != MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) { + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": STP Passthru: ")); +- dcsmisasprintk(ioc, printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", ++ dcsmisasprintk(ioc, ++ printk("IOCStatus=0x%X IOCLogInfo=0x%X SASStatus=0x%X\n", + le16_to_cpu(pSataReply->IOCStatus), + le32_to_cpu(pSataReply->IOCLogInfo), + pSataReply->SASStatus)); +@@ -3029,26 +3036,27 @@ csmisas_stp_passthru(unsigned long arg) + karg->Status.bConnectionStatus = + map_sas_status_to_csmi(pSataReply->SASStatus); + +- memcpy(karg->Status.bStatusFIS,pSataReply->StatusFIS, 20); ++ memcpy(karg->Status.bStatusFIS, pSataReply->StatusFIS, 20); + + /* + * for now, just zero out uSCR array, + * then copy the one dword returned + * in the reply frame into uSCR[0] + */ +- memset( karg->Status.uSCR, 0, 64); ++ memset(karg->Status.uSCR, 0, 64); + karg->Status.uSCR[0] = le32_to_cpu(pSataReply->StatusControlRegisters); + +- if((le32_to_cpu(pSataReply->TransferCount)) && (request_data) && ++ if ((le32_to_cpu(pSataReply->TransferCount)) && (request_data) && + (karg->Parameters.uFlags & CSMI_SAS_STP_READ)) { + karg->Status.uDataBytes = +- min(le32_to_cpu(pSataReply->TransferCount),request_data_sz); ++ min(le32_to_cpu(pSataReply->TransferCount), ++ request_data_sz); + if (copy_to_user((void __user *)uarg->bDataBuffer, + request_data, karg->Status.uDataBytes)) { + printk(KERN_ERR "%s::%s() @%d - " + "Unable to write data to user %p\n", +- __FILE__, __FUNCTION__, __LINE__, +- (void*)karg->bDataBuffer); ++ __FILE__, __func__, __LINE__, ++ (void *)karg->bDataBuffer); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + } + } +@@ -3065,13 +3073,13 @@ csmisas_stp_passthru(unsigned long arg) + offsetof(CSMI_SAS_STP_PASSTHRU_BUFFER, bDataBuffer))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_ssp_passthru @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + + free_pages((unsigned long)karg, memory_pages); +- dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ": %s exit.\n", __func__)); + return 0; + } + +@@ -3090,30 +3098,30 @@ csmisas_firmware_download(unsigned long + CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER karg; + MPT_ADAPTER *ioc = NULL; + int iocnum; +- pMpiFwHeader_t pFwHeader=NULL; ++ pMpiFwHeader_t pFwHeader = NULL; + + if (copy_from_user(&karg, uarg, + sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " +- "Unable to read in csmi_sas_firmware_download struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ "Unable to read in csmi_sas_firmware_download struct@ %p\n", ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + /* Default to success.*/ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; +@@ -3130,7 +3138,7 @@ csmisas_firmware_download(unsigned long + goto cim_firmware_download_exit; + } + +- if ( karg.Information.uDownloadFlags & ++ if (karg.Information.uDownloadFlags & + (CSMI_SAS_FWD_SOFT_RESET | CSMI_SAS_FWD_VALIDATE)) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + karg.Information.usStatus = CSMI_SAS_FWD_REJECT; +@@ -3142,7 +3150,7 @@ csmisas_firmware_download(unsigned long + * fw image attached to end of incoming packet. + */ + pFwHeader = kmalloc(karg.Information.uBufferLength, GFP_KERNEL); +- if (!pFwHeader){ ++ if (!pFwHeader) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + karg.Information.usStatus = CSMI_SAS_FWD_REJECT; + karg.Information.usSeverity = CSMI_SAS_FWD_ERROR; +@@ -3154,21 +3162,21 @@ csmisas_firmware_download(unsigned long + karg.Information.uBufferLength)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in pFwHeader @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- if ( !((pFwHeader->Signature0 == MPI_FW_HEADER_SIGNATURE_0) && ++ if (!((pFwHeader->Signature0 == MPI_FW_HEADER_SIGNATURE_0) && + (pFwHeader->Signature1 == MPI_FW_HEADER_SIGNATURE_1) && + (pFwHeader->Signature2 == MPI_FW_HEADER_SIGNATURE_2))) { +- // the signature check failed ++ /* the signature check failed */ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + karg.Information.usStatus = CSMI_SAS_FWD_REJECT; + karg.Information.usSeverity = CSMI_SAS_FWD_ERROR; + goto cim_firmware_download_exit; + } + +- if ( mptctl_do_fw_download(karg.IoctlHeader.IOControllerNumber, ++ if (mptctl_do_fw_download(karg.IoctlHeader.IOControllerNumber, + uarg->bDataBuffer, karg.Information.uBufferLength) + != 0) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; +@@ -3177,7 +3185,7 @@ csmisas_firmware_download(unsigned long + goto cim_firmware_download_exit; + } + +- if((karg.Information.uDownloadFlags & CSMI_SAS_FWD_SOFT_RESET) || ++ if ((karg.Information.uDownloadFlags & CSMI_SAS_FWD_SOFT_RESET) || + (karg.Information.uDownloadFlags & CSMI_SAS_FWD_HARD_RESET)) { + if (mpt_HardResetHandler(ioc, CAN_SLEEP) != 0) { + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; +@@ -3188,7 +3196,7 @@ csmisas_firmware_download(unsigned long + + cim_firmware_download_exit: + +- if(pFwHeader) ++ if (pFwHeader) + kfree(pFwHeader); + + /* Copy the data from kernel memory to user memory +@@ -3197,11 +3205,11 @@ csmisas_firmware_download(unsigned long + sizeof(CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_firmware_download @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -3227,24 +3235,24 @@ csmisas_get_raid_info(unsigned long arg) + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_get_raid_info struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + if (!ioc->raid_data.pIocPg2) +@@ -3252,8 +3260,8 @@ csmisas_get_raid_info(unsigned long arg) + karg.Information.uNumRaidSets = + ioc->raid_data.pIocPg2->NumActiveVolumes; + karg.Information.uMaxRaidSets = ioc->raid_data.pIocPg2->MaxVolumes; +- if( ioc->raid_data.pIocPg6 ) { +- // get absolute maximum for all RAID sets ++ if (ioc->raid_data.pIocPg6) { ++ /* get absolute maximum for all RAID sets */ + maxDrivesPerSet = ioc->raid_data.pIocPg6->MaxDrivesIS; + maxDrivesPerSet = max(ioc->raid_data.pIocPg6->MaxDrivesIM, + maxDrivesPerSet); +@@ -3263,17 +3271,19 @@ csmisas_get_raid_info(unsigned long arg) + } + else + karg.Information.uMaxDrivesPerSet = 8; +- // For bMaxRaidSets, count bits set in bits 0-6 of CapabilitiesFlags ++ /* For bMaxRaidSets, count bits set in bits 0-6 of CapabilitiesFlags */ + raidFlags = ioc->raid_data.pIocPg2->CapabilitiesFlags & 0x0000007F; +- for( maxRaidTypes=0; raidFlags; maxRaidTypes++ ) ++ for (maxRaidTypes = 0; raidFlags; maxRaidTypes++) + raidFlags &= raidFlags - 1; + karg.Information.bMaxRaidTypes = maxRaidTypes; +- // ulMinRaidSetBlocks hard coded to 1MB until available from config page ++ /* ulMinRaidSetBlocks hard coded to 1MB until available ++ * from config page ++ */ + karg.Information.ulMinRaidSetBlocks.uLowPart = 2048; + karg.Information.ulMinRaidSetBlocks.uHighPart = 0; + karg.Information.ulMaxRaidSetBlocks.uLowPart = 0xffffffff; +- if( ioc->raid_data.pIocPg2->CapabilitiesFlags & +- MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING ) ++ if (ioc->raid_data.pIocPg2->CapabilitiesFlags & ++ MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING) + karg.Information.ulMaxRaidSetBlocks.uHighPart = 0xffffffff; + else + karg.Information.ulMaxRaidSetBlocks.uHighPart = 0; +@@ -3293,11 +3303,11 @@ csmisas_get_raid_info_out: + sizeof(CSMI_SAS_RAID_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_raid_info @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -3315,7 +3325,8 @@ csmisas_get_raid_info_out: + * Remark: Wait to return until reply processed by the ISR. + **/ + static int +-csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, u8 VolumeId, pMpiRaidActionReply_t reply) ++csmisas_do_raid(MPT_ADAPTER *ioc, u8 action, u8 PhysDiskNum, u8 VolumeBus, ++ u8 VolumeId, pMpiRaidActionReply_t reply) + { + MpiRaidActionRequest_t *pReq; + MpiRaidActionReply_t *pReply; +@@ -3338,7 +3349,6 @@ csmisas_do_raid(MPT_ADAPTER *ioc, u8 act + pReq->MsgFlags = 0; + pReq->Reserved2 = 0; + pReq->ActionDataWord = 0; /* Reserved for this action */ +- //pReq->ActionDataSGE = 0; + + ioc->add_sge((char *)&pReq->ActionDataSGE, + MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); +@@ -3347,7 +3357,7 @@ csmisas_do_raid(MPT_ADAPTER *ioc, u8 act + return -ENODATA; + + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) && +- (reply != NULL)){ ++ (reply != NULL)) { + pReply = (MpiRaidActionReply_t *)&(ioc->ioctl_cmds.reply); + memcpy(reply, pReply, + min(ioc->reply_sz, +@@ -3371,7 +3381,7 @@ csmisas_do_raid(MPT_ADAPTER *ioc, u8 act + **/ + static int + csmisas_raid_inq(MPT_ADAPTER *ioc, u8 opcode, u8 bus, u8 id, u8 inq_vpd_page, +- u8 * inq_vpd, u32 inq_vpd_sz) ++ u8 *inq_vpd, u32 inq_vpd_sz) + { + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; +@@ -3379,7 +3389,7 @@ csmisas_raid_inq(MPT_ADAPTER *ioc, u8 op + u16 req_idx; + char *psge; + u8 inq_vpd_cdb[6]; +- u8 *request_data=NULL; ++ u8 *request_data = NULL; + dma_addr_t request_data_dma; + u32 request_data_sz; + int rc = 0; +@@ -3409,14 +3419,14 @@ csmisas_raid_inq(MPT_ADAPTER *ioc, u8 op + pScsiRequest = (pSCSIIORequest_t) mf; + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + +- memset(pScsiRequest,0,sizeof(SCSIIORequest_t)); ++ memset(pScsiRequest, 0, sizeof(SCSIIORequest_t)); + pScsiRequest->Function = opcode; + pScsiRequest->TargetID = id; + pScsiRequest->Bus = bus; + pScsiRequest->CDBLength = 6; + pScsiRequest->DataLength = cpu_to_le32(request_data_sz); + pScsiRequest->MsgContext = MsgContext; +- memcpy(pScsiRequest->CDB,inq_vpd_cdb,pScsiRequest->CDBLength); ++ memcpy(pScsiRequest->CDB, inq_vpd_cdb, pScsiRequest->CDBLength); + pScsiRequest->Control = cpu_to_le32(MPI_SCSIIO_CONTROL_READ); + pScsiRequest->Control |= cpu_to_le32(MPI_SCSIIO_CONTROL_SIMPLEQ); + pScsiRequest->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; +@@ -3434,17 +3444,18 @@ csmisas_raid_inq(MPT_ADAPTER *ioc, u8 op + + if (request_data == NULL) { + mpt_free_msg_frame(ioc, mf); +- rc=-1; ++ rc = -1; + goto csmisas_raid_inq_exit; + } + +- memset(request_data,0,request_data_sz); ++ memset(request_data, 0, request_data_sz); + psge = (char *)&pScsiRequest->SGL; + ioc->add_sge(psge, (MPT_SGE_FLAGS_SSIMPLE_READ | 0xFC) , + request_data_dma); + +- if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) != 0) { +- rc=-1; ++ if (csmisas_send_command_wait(ioc, mf, MPT_IOCTL_DEFAULT_TIMEOUT) ++ != 0) { ++ rc = -1; + goto csmisas_raid_inq_exit; + } + +@@ -3472,7 +3483,7 @@ static int + csmisas_get_raid_config(unsigned long arg) + { + CSMI_SAS_RAID_CONFIG_BUFFER __user *uarg = (void __user *) arg; +- CSMI_SAS_RAID_CONFIG_BUFFER karg,*pKarg=NULL; ++ CSMI_SAS_RAID_CONFIG_BUFFER karg, *pKarg = NULL; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + MPT_ADAPTER *ioc = NULL; +@@ -3498,7 +3509,7 @@ csmisas_get_raid_config(unsigned long ar + if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmisas_get_raid_config struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +@@ -3506,11 +3517,11 @@ csmisas_get_raid_config(unsigned long ar + memory_pages = get_order(csmi_sas_raid_config_buffer_sz); + pKarg = (CSMI_SAS_RAID_CONFIG_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!pKarg){ ++ if (!pKarg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc RAID_CONFIG_BUFFER " + "csmi_sas_raid_config_buffer_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + csmi_sas_raid_config_buffer_sz, memory_pages); + return -ENOMEM; + } +@@ -3519,7 +3530,7 @@ csmisas_get_raid_config(unsigned long ar + if (copy_from_user(pKarg, uarg, csmi_sas_raid_config_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmisas_get_raid_config struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)pKarg, memory_pages); + return -EFAULT; + } +@@ -3527,22 +3538,22 @@ csmisas_get_raid_config(unsigned long ar + if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)pKarg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)pKarg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + if (pKarg->Configuration.uChangeCount != 0 && +- pKarg->Configuration.uChangeCount != ioc->csmi_change_count ) { ++ pKarg->Configuration.uChangeCount != ioc->csmi_change_count) { + pKarg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + pKarg->Configuration.uFailureCode = +@@ -3615,7 +3626,7 @@ csmisas_get_raid_config(unsigned long ar + pKarg->Configuration.uStripeSize = + le32_to_cpu(pVolume0->StripeSize)/2; + +- switch(pVolume0->VolumeType) { ++ switch (pVolume0->VolumeType) { + case MPI_RAID_VOL_TYPE_IS: + pKarg->Configuration.bRaidType = CSMI_SAS_RAID_TYPE_0; + break; +@@ -3636,7 +3647,8 @@ csmisas_get_raid_config(unsigned long ar + break; + case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: + /* Volume is degraded, check if Resyncing or Inactive */ +- pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_DEGRADED; ++ pKarg->Configuration.bStatus ++ = CSMI_SAS_RAID_SET_STATUS_DEGRADED; + break; + case MPI_RAIDVOL0_STATUS_STATE_FAILED: + pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_FAILED; +@@ -3649,25 +3661,26 @@ csmisas_get_raid_config(unsigned long ar + pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_OFFLINE; + else if (pVolume0->VolumeStatus.Flags & + MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) +- pKarg->Configuration.bStatus = CSMI_SAS_RAID_SET_STATUS_REBUILDING; ++ pKarg->Configuration.bStatus ++ = CSMI_SAS_RAID_SET_STATUS_REBUILDING; + + pKarg->Configuration.bInformation = 0; /* default */ +- if(pVolume0->VolumeStatus.Flags & +- MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ) { ++ if (pVolume0->VolumeStatus.Flags & ++ MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { + +- uint64_t * ptrUint64; ++ uint64_t *ptrUint64; + uint64_t totalBlocks64, blocksRemaining64; + uint32_t totalBlocks32, blocksRemaining32; + + /* get percentage complete */ +- pRaidActionReply = kmalloc( sizeof(MPI_RAID_VOL_INDICATOR) + +- offsetof(MSG_RAID_ACTION_REPLY,ActionData), ++ pRaidActionReply = kmalloc(sizeof(MPI_RAID_VOL_INDICATOR) + ++ offsetof(MSG_RAID_ACTION_REPLY, ActionData), + GFP_KERNEL); + +- if (!pRaidActionReply){ ++ if (!pRaidActionReply) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc @ %p\n", +- __FILE__, __LINE__, __FUNCTION__,pKarg); ++ __FILE__, __LINE__, __func__, pKarg); + goto cim_get_raid_config_exit; + } + memset(pRaidActionReply, 0, sizeof(*pRaidActionReply)); +@@ -3680,14 +3693,14 @@ csmisas_get_raid_config(unsigned long ar + totalBlocks64 = *ptrUint64; + ptrUint64++; + blocksRemaining64 = *ptrUint64; +- while(totalBlocks64 > 0xFFFFFFFFUL){ ++ while (totalBlocks64 > 0xFFFFFFFFUL) { + totalBlocks64 = totalBlocks64 >> 1; + blocksRemaining64 = blocksRemaining64 >> 1; + } + totalBlocks32 = (uint32_t)totalBlocks64; + blocksRemaining32 = (uint32_t)blocksRemaining64; + +- if(totalBlocks32) ++ if (totalBlocks32) + pKarg->Configuration.bInformation = + (totalBlocks32 - blocksRemaining32) / + (totalBlocks32 / 100); +@@ -3713,15 +3726,14 @@ csmisas_get_raid_config(unsigned long ar + pKarg->Configuration.Data->ulRaidSetBlocks.uHighPart = + le32_to_cpu(pVolume0->MaxLBAHigh); + if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS || +- pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME ) { ++ pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) { + pKarg->Configuration.Data->uStripeSizeInBlocks = + le32_to_cpu(pVolume0->StripeSize); + } else { + pKarg->Configuration.Data->uStripeSizeInBlocks = 0; + } + pKarg->Configuration.Data->uSectorsPerTrack = 128; +- for (i=0; i<16; i++) { +- // unsupported ++ for (i = 0; i < 16; i++) { + pKarg->Configuration.Data->bApplicationScratchPad[i] = + 0xFF; + } +@@ -3732,15 +3744,15 @@ csmisas_get_raid_config(unsigned long ar + (pKarg->Configuration.Data->uNumberOfHeads * + pKarg->Configuration.Data->uSectorsPerTrack)); + pKarg->Configuration.Data->uNumberOfTracks = tmpTotalMaxLBA; +- } else if ( pKarg->Configuration.bDataType == +- CSMI_SAS_RAID_DATA_DEVICE_ID ) { ++ } else if (pKarg->Configuration.bDataType == ++ CSMI_SAS_RAID_DATA_DEVICE_ID) { + /* Send inquiry to get VPD Page 0x83 */ + u32 vpd_page_sz; + vpd_page_sz = csmi_sas_raid_config_buffer_sz - +- offsetof(CSMI_SAS_RAID_CONFIG,DeviceId); ++ offsetof(CSMI_SAS_RAID_CONFIG, DeviceId); + if (csmisas_raid_inq(ioc, MPI_FUNCTION_SCSI_IO_REQUEST, + VolumeBus, volumeID, 0x83, +- (u8*)&pKarg->Configuration.DeviceId->bDeviceIdentificationVPDPage, ++ (u8 *)&pKarg->Configuration.DeviceId->bDeviceIdentificationVPDPage, + vpd_page_sz) != 0) { + pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_raid_config_exit; +@@ -3773,7 +3785,7 @@ csmisas_get_raid_config(unsigned long ar + pIocPage5 = pci_alloc_consistent(ioc->pcidev, + ioc_page5_sz, + &ioc_page5_dma); +- memset(pIocPage5,0,ioc_page5_sz); ++ memset(pIocPage5, 0, ioc_page5_sz); + if (ioc_page5_dma) { + cfg.physAddr = ioc_page5_dma; + cfg.action = +@@ -3816,52 +3828,55 @@ csmisas_get_raid_config(unsigned long ar + cfg.physAddr = physdisk0_dma; + + physDiskNumMax = (csmi_sas_raid_config_buffer_sz - +- offsetof(CSMI_SAS_RAID_CONFIG,Drives)) ++ offsetof(CSMI_SAS_RAID_CONFIG, Drives)) + / sizeof(CSMI_SAS_RAID_DRIVES); + + tmpTotalMaxLBA = totalMaxLBA; + if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IS) { + do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "IS Volume tmpTotalMaxLBA=%llX\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "IS Volume tmpTotalMaxLBA=%llX\n", + (unsigned long long)tmpTotalMaxLBA)); +- } +- else if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) { ++ } else if (pVolume0->VolumeType == MPI_RAID_VOL_TYPE_IME) { + do_div(tmpTotalMaxLBA, pVolume0->NumPhysDisks * 2); +- dcsmisasprintk(ioc, printk(KERN_DEBUG "IME Volume tmpTotalMaxLBA=%llX\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "IME Volume tmpTotalMaxLBA=%llX\n", + (unsigned long long)tmpTotalMaxLBA)); + } else { +- dcsmisasprintk(ioc, printk(KERN_DEBUG "IM Volume tmpTotalMaxLBA=%llX\n", ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "IM Volume tmpTotalMaxLBA=%llX\n", + (unsigned long long)tmpTotalMaxLBA)); + } + +- for (i=0; i< min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { ++ for (i = 0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { + + physDiskNum = pVolume0->PhysDisk[i].PhysDiskNum; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = physDiskNum; +- if (mpt_config(ioc, &cfg) != 0){ ++ if (mpt_config(ioc, &cfg) != 0) { + pKarg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_raid_config_exit; + } + +- pKarg->Configuration.bDriveCount++; ++ pKarg->Configuration.bDriveCount++; + if (pKarg->Configuration.bDataType != CSMI_SAS_RAID_DATA_DRIVES) + continue; + + /* Search the list for the matching SAS address. */ +- sas_info = csmisas_get_device_component_by_fw(ioc, pPhysDisk0->PhysDiskBus, +- pPhysDisk0->PhysDiskID); ++ sas_info = csmisas_get_device_component_by_fw(ioc, ++ pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); + if (sas_info) { +- sas_address = reverse_byte_order64(sas_info->sas_address); ++ sas_address ++ = reverse_byte_order64(sas_info->sas_address); + memcpy(pKarg->Configuration.Drives[i].bSASAddress, +- &sas_address,sizeof(u64)); ++ &sas_address, sizeof(u64)); + if (!device_info) + device_info = sas_info->device_info; + } + + memcpy(pKarg->Configuration.Drives[i].bModel, + pPhysDisk0->InquiryData.VendorID, +- offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel)); ++ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA, ProductRevLevel)); + memcpy(pKarg->Configuration.Drives[i].bFirmware, + pPhysDisk0->InquiryData.ProductRevLevel, + sizeof(pPhysDisk0->InquiryData.ProductRevLevel)); +@@ -3890,19 +3905,19 @@ csmisas_get_raid_config(unsigned long ar + MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED) { + pKarg->Configuration.Drives[i].bDriveStatus = + CSMI_SAS_DRIVE_STATUS_OFFLINE; +- } else if(pPhysDisk0->PhysDiskStatus.State) { ++ } else if (pPhysDisk0->PhysDiskStatus.State) { + pKarg->Configuration.Drives[i].bDriveStatus = + CSMI_SAS_DRIVE_STATUS_FAILED; +- if(pKarg->Configuration.bStatus == ++ if (pKarg->Configuration.bStatus == + CSMI_SAS_RAID_SET_STATUS_DEGRADED) + pKarg->Configuration.bInformation = i; +- } else if((pVolume0->VolumeStatus.Flags & ++ } else if ((pVolume0->VolumeStatus.Flags & + MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) && + (pPhysDisk0->PhysDiskStatus.Flags & + MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC)) + pKarg->Configuration.Drives[i].bDriveStatus = + CSMI_SAS_DRIVE_STATUS_REBUILDING; +- else if(pPhysDisk0->ErrorData.SmartCount || ++ else if (pPhysDisk0->ErrorData.SmartCount || + (pPhysDisk0->PhysDiskStatus.Flags & + MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC)) + pKarg->Configuration.Drives[i].bDriveStatus = +@@ -3918,7 +3933,7 @@ csmisas_get_raid_config(unsigned long ar + CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS; + if (mpt_raid_phys_disk_get_num_paths(ioc, + pVolume0->PhysDisk[i].PhysDiskNum) > 1) +- pKarg->Configuration.Drives[i].bDriveType = ++ pKarg->Configuration.Drives[i].bDriveType = + CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS; + } + +@@ -3941,9 +3956,9 @@ csmisas_get_raid_config(unsigned long ar + if ((pVolume0->VolumeSettings.HotSparePool & + pIocPage5->HotSpare[idx].HotSparePool) == 0) + continue; +- if(pIocPage5->HotSpare[idx].Flags != ++ if (pIocPage5->HotSpare[idx].Flags != + MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE) +- continue; ++ continue; + physDiskNum = pIocPage5->HotSpare[idx].PhysDiskNum; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = physDiskNum; +@@ -3981,11 +3996,11 @@ csmisas_get_raid_config(unsigned long ar + MPI_RAID_VOL_TYPE_IME) && + (((totalMaxLBA + + pVolume0->NumPhysDisks) * 2) + +- (64*2*1024 ) /*metadata = 64MB*/ > ++ (64*2*1024) /*metadata = 64MB*/ > + le32_to_cpu(pPhysDisk0->MaxLBA))) + continue; + +- pKarg->Configuration.bDriveCount++; ++ pKarg->Configuration.bDriveCount++; + if (pKarg->Configuration.bDataType != + CSMI_SAS_RAID_DATA_DRIVES) { + i++; +@@ -3996,14 +4011,16 @@ csmisas_get_raid_config(unsigned long ar + sas_info = csmisas_get_device_component_by_fw(ioc, + pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID); + if (sas_info) { +- sas_address = reverse_byte_order64(sas_info->sas_address); ++ sas_address = ++ reverse_byte_order64(sas_info->sas_address); + memcpy(pKarg->Configuration.Drives[i].bSASAddress, +- &sas_address,sizeof(u64)); ++ &sas_address, sizeof(u64)); + } + + memcpy(pKarg->Configuration.Drives[i].bModel, + pPhysDisk0->InquiryData.VendorID, +- offsetof(RAID_PHYS_DISK0_INQUIRY_DATA,ProductRevLevel)); ++ offsetof(RAID_PHYS_DISK0_INQUIRY_DATA, ++ ProductRevLevel)); + memcpy(pKarg->Configuration.Drives[i].bFirmware, + pPhysDisk0->InquiryData.ProductRevLevel, + sizeof(pPhysDisk0->InquiryData.ProductRevLevel)); +@@ -4021,10 +4038,10 @@ csmisas_get_raid_config(unsigned long ar + } + pKarg->Configuration.Drives[i].bDriveStatus = + CSMI_SAS_DRIVE_STATUS_OK; +- if(pPhysDisk0->PhysDiskStatus.State) ++ if (pPhysDisk0->PhysDiskStatus.State) + pKarg->Configuration.Drives[i].bDriveStatus = + CSMI_SAS_DRIVE_STATUS_FAILED; +- else if(pPhysDisk0->ErrorData.SmartCount) ++ else if (pPhysDisk0->ErrorData.SmartCount) + pKarg->Configuration.Drives[i].bDriveStatus = + CSMI_SAS_DRIVE_STATUS_DEGRADED; + pKarg->Configuration.Drives[i].bDriveUsage = +@@ -4047,8 +4064,8 @@ csmisas_get_raid_config(unsigned long ar + } + } + +- // Only return data on the first 240 drives +- if( pKarg->Configuration.bDriveCount > 0xF0 ) ++ /* Only return data on the first 240 drives */ ++ if (pKarg->Configuration.bDriveCount > 0xF0) + pKarg->Configuration.bDriveCount = + CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG; + +@@ -4060,11 +4077,11 @@ csmisas_get_raid_config(unsigned long ar + pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0, + volume0_dma); + +- if(pPhysDisk0 != NULL) ++ if (pPhysDisk0 != NULL) + pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0, + physdisk0_dma); + +- if(pIocPage5 != NULL) ++ if (pIocPage5 != NULL) + pci_free_consistent(ioc->pcidev, ioc_page5_sz, pIocPage5, + ioc_page5_dma); + +@@ -4075,17 +4092,17 @@ csmisas_get_raid_config(unsigned long ar + switch (pKarg->Configuration.bDataType) { + case CSMI_SAS_RAID_DATA_ADDITIONAL_DATA: + copy_buffer_sz = sizeof(IOCTL_HEADER) + +- offsetof(CSMI_SAS_RAID_CONFIG,Data) + ++ offsetof(CSMI_SAS_RAID_CONFIG, Data) + + sizeof(CSMI_SAS_RAID_SET_ADDITIONAL_DATA); + break; + case CSMI_SAS_RAID_DATA_DRIVES: + if (pKarg->Configuration.bDriveCount == + CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED) + copy_buffer_sz = sizeof(IOCTL_HEADER) + +- offsetof(CSMI_SAS_RAID_CONFIG,Drives); +- else ++ offsetof(CSMI_SAS_RAID_CONFIG, Drives); ++ else + copy_buffer_sz = sizeof(IOCTL_HEADER) + +- offsetof(CSMI_SAS_RAID_CONFIG,Drives) + ++ offsetof(CSMI_SAS_RAID_CONFIG, Drives) + + (pKarg->Configuration.bDriveCount * + sizeof(CSMI_SAS_RAID_DRIVES)); + break; +@@ -4097,12 +4114,12 @@ csmisas_get_raid_config(unsigned long ar + if (copy_to_user(uarg, pKarg, copy_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_raid_config @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)pKarg, memory_pages); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + free_pages((unsigned long)pKarg, memory_pages); + return 0; + } +@@ -4119,15 +4136,15 @@ static int + csmisas_get_raid_features(unsigned long arg) + { + CSMI_SAS_RAID_FEATURES_BUFFER __user *uarg = (void __user *) arg; +- CSMI_SAS_RAID_FEATURES_BUFFER karg, *pKarg=NULL; ++ CSMI_SAS_RAID_FEATURES_BUFFER karg, *pKarg = NULL; + int csmi_sas_raid_features_buffer_sz, iocnum; + int memory_pages; + MPT_ADAPTER *ioc = NULL; + + if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) { +- printk(KERN_ERR "%s@%d::%s() - " +- "Unable to read in csmi_sas_get_raid_features struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ printk(KERN_ERR "%s@%d::%s() - Unable to " ++ "read in csmi_sas_get_raid_features struct @ %p\n", ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +@@ -4135,20 +4152,20 @@ csmisas_get_raid_features(unsigned long + memory_pages = get_order(csmi_sas_raid_features_buffer_sz); + pKarg = (CSMI_SAS_RAID_FEATURES_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!pKarg){ ++ if (!pKarg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc RAID_FEATURES_BUFFER " + "csmi_sas_raid_features_buffer_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + csmi_sas_raid_features_buffer_sz, memory_pages); + return -ENOMEM; + } + memset(pKarg, 0, sizeof(*pKarg)); + + if (copy_from_user(pKarg, uarg, csmi_sas_raid_features_buffer_sz)) { +- printk(KERN_ERR "%s@%d::%s() - " +- "Unable to read in csmi_sas_get_raid_features struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ printk(KERN_ERR "%s@%d::%s() - Unable to " ++ "read in csmi_sas_get_raid_features struct @ %p\n", ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)pKarg, memory_pages); + return -EFAULT; + } +@@ -4156,22 +4173,22 @@ csmisas_get_raid_features(unsigned long + if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)pKarg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)pKarg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + if (pKarg->Information.uChangeCount != 0 && +- pKarg->Information.uChangeCount != ioc->csmi_change_count ) { ++ pKarg->Information.uChangeCount != ioc->csmi_change_count) { + pKarg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + pKarg->Information.uFailureCode = +@@ -4218,12 +4235,12 @@ csmisas_get_raid_features(unsigned long + sizeof(CSMI_SAS_RAID_FEATURES_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_raid_features @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)pKarg, memory_pages); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + free_pages((unsigned long)pKarg, memory_pages); + return 0; + } +@@ -4240,7 +4257,7 @@ static int + csmisas_set_raid_control(unsigned long arg) + { + CSMI_SAS_RAID_CONTROL_BUFFER __user *uarg = (void __user *) arg; +- CSMI_SAS_RAID_CONTROL_BUFFER karg, *pKarg=NULL; ++ CSMI_SAS_RAID_CONTROL_BUFFER karg, *pKarg = NULL; + int csmi_sas_raid_control_buffer_sz, iocnum; + int memory_pages; + MPT_ADAPTER *ioc = NULL; +@@ -4248,7 +4265,7 @@ csmisas_set_raid_control(unsigned long a + if (copy_from_user(&karg, uarg, sizeof(IOCTL_HEADER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_set_raid_control struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +@@ -4256,11 +4273,11 @@ csmisas_set_raid_control(unsigned long a + memory_pages = get_order(csmi_sas_raid_control_buffer_sz); + pKarg = (CSMI_SAS_RAID_CONTROL_BUFFER *)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!pKarg){ ++ if (!pKarg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc RAID_CONTROL_BUFFER " + "csmi_sas_raid_control_buffer_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + csmi_sas_raid_control_buffer_sz, memory_pages); + return -ENOMEM; + } +@@ -4269,7 +4286,7 @@ csmisas_set_raid_control(unsigned long a + if (copy_from_user(pKarg, uarg, csmi_sas_raid_control_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_set_raid_control struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)pKarg, memory_pages); + return -EFAULT; + } +@@ -4277,22 +4294,22 @@ csmisas_set_raid_control(unsigned long a + if (((iocnum = mpt_verify_adapter(pKarg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)pKarg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)pKarg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + if (pKarg->Information.uChangeCount != 0 && +- pKarg->Information.uChangeCount != ioc->csmi_change_count ) { ++ pKarg->Information.uChangeCount != ioc->csmi_change_count) { + pKarg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + pKarg->Information.uFailureCode = +@@ -4329,8 +4346,8 @@ csmisas_set_raid_control(unsigned long a + goto cim_set_raid_control_exit; + } + +- if( !strcmp(pKarg->Information.bClearConfiguration, +- CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE) ) { ++ if (!strcmp(pKarg->Information.bClearConfiguration, ++ CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE)) { + pKarg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + pKarg->Information.uFailureCode = +@@ -4349,12 +4366,12 @@ csmisas_set_raid_control(unsigned long a + sizeof(CSMI_SAS_RAID_CONTROL_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_set_raid_control @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)pKarg, memory_pages); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + free_pages((unsigned long)pKarg, memory_pages); + return 0; + } +@@ -4378,42 +4395,39 @@ csmisas_get_raid_element(unsigned long a + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmisas_get_raid_element struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + +-/* TODO - implement IOCTL here */ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); + +-// csmisas_get_raid_element_exit: +- + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_RAID_ELEMENT_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmisas_get_raid_element @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + + } +@@ -4434,45 +4448,43 @@ csmisas_set_raid_operation(unsigned long + MPT_ADAPTER *ioc = NULL; + int iocnum; + +- if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) { ++ if (copy_from_user(&karg, uarg, ++ sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_set_raid_operation struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + +-/* TODO - implement IOCTL here */ + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_BAD_CNTL_CODE; + dcsmisasprintk(ioc, printk(KERN_DEBUG ": not implemented\n")); + +-// cim_set_raid_operation: +- + /* Copy the data from kernel memory to user memory + */ + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_RAID_SET_OPERATION_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_set_raid_operation @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + + } +@@ -4512,24 +4524,24 @@ csmisas_task_managment(unsigned long arg + if (copy_from_user(&karg, uarg, sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_task_managment struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; + +@@ -4575,18 +4587,22 @@ csmisas_task_managment(unsigned long arg + goto cim_get_task_managment_exit; + + switch (karg.Parameters.uInformation) { +- case CSMI_SAS_SSP_TEST: +- dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request for test purposes\n")); +- break; +- case CSMI_SAS_SSP_EXCEEDED: +- dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request due to timeout\n")); +- break; +- case CSMI_SAS_SSP_DEMAND: +- dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request demanded by app\n")); +- break; +- case CSMI_SAS_SSP_TRIGGER: +- dcsmisasprintk(ioc, printk(KERN_DEBUG "TM request sent to trigger event\n")); +- break; ++ case CSMI_SAS_SSP_TEST: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "TM request for test purposes\n")); ++ break; ++ case CSMI_SAS_SSP_EXCEEDED: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "TM request due to timeout\n")); ++ break; ++ case CSMI_SAS_SSP_DEMAND: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "TM request demanded by app\n")); ++ break; ++ case CSMI_SAS_SSP_TRIGGER: ++ dcsmisasprintk(ioc, printk(KERN_DEBUG ++ "TM request sent to trigger event\n")); ++ break; + } + + switch (taskType) { +@@ -4601,12 +4617,12 @@ csmisas_task_managment(unsigned long arg + mf = MPT_INDEX_2_MFPTR(hd->ioc, i); + TaskMsgContext = + mf->u.frame.hwhdr.msgctxu.MsgContext; +- found_qtag=1; ++ found_qtag = 1; + break; + } + } + +- if(!found_qtag) ++ if (!found_qtag) + goto cim_get_task_managment_exit; + + case MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: +@@ -4618,7 +4634,6 @@ csmisas_task_managment(unsigned long arg + + /* Single threading .... + */ +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); +@@ -4626,50 +4641,34 @@ csmisas_task_managment(unsigned long arg + CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) +- if (mptctl_set_tm_flags(hd) != 0) { +- karg.IoctlHeader.ReturnCode = +- CSMI_SAS_STATUS_FAILED; +- goto cim_get_task_managment_exit; +- } +-#endif + /* Send request + */ + if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": no msg frames!\n")); + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mpt_clear_taskmgmt_in_progress_flag(ioc); +-#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) +- mptctl_free_tm_flags(ioc); +-#endif + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; +- pScsiTm = (pSCSITaskMgmt_t ) mf; ++ pScsiTm = (pSCSITaskMgmt_t) mf; + +- memset(pScsiTm,0,sizeof(SCSITaskMgmt_t)); ++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->TaskType = taskType; + pScsiTm->Bus = channel; + pScsiTm->TargetID = id; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + int_to_scsilun(karg.Parameters.bLun, + (struct scsi_lun *)pScsiTm->LUN); +-#else +- pScsiTm->LUN[1] = karg.Parameters.bLun; +-#endif + pScsiTm->MsgContext = MsgContext; + pScsiTm->TaskMsgContext = TaskMsgContext; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + if (csmisas_send_handshake_wait(ioc, mf, + karg.IoctlHeader.Timeout) != 0) { +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); +-#endif + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_get_task_managment_exit; + } +@@ -4677,25 +4676,26 @@ csmisas_task_managment(unsigned long arg + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + + pScsiTmReply = +- (pSCSITaskMgmtReply_t ) ioc->ioctl_cmds.reply; ++ (pSCSITaskMgmtReply_t) ioc->ioctl_cmds.reply; + + ioc_status = le16_to_cpu(pScsiTmReply->IOCStatus) + & MPI_IOCSTATUS_MASK; + +- memset(&karg.Status,0, ++ memset(&karg.Status, 0, + sizeof(CSMI_SAS_SSP_PASSTHRU_STATUS)); + +- if(ioc_status == MPI_IOCSTATUS_SUCCESS) { ++ if (ioc_status == MPI_IOCSTATUS_SUCCESS) { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_SUCCESS; + karg.Status.bSSPStatus = + CSMI_SAS_SSP_STATUS_COMPLETED; +- }else if(ioc_status == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) { ++ } else if (ioc_status ++ == MPI_IOCSTATUS_INSUFFICIENT_RESOURCES) { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_SUCCESS; + karg.Status.bSSPStatus = + CSMI_SAS_SSP_STATUS_RETRY; +- }else { ++ } else { + karg.IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_FAILED; + karg.Status.bSSPStatus = +@@ -4711,9 +4711,7 @@ csmisas_task_managment(unsigned long arg + break; + } + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); +-#endif + + cim_get_task_managment_exit: + +@@ -4723,11 +4721,11 @@ csmisas_task_managment(unsigned long arg + sizeof(CSMI_SAS_SSP_TASK_IU_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_task_managment @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -4827,19 +4825,19 @@ csmisas_phy_reset(MPT_ADAPTER *ioc, u8 P + + if ((opcode != MPI_SAS_OP_PHY_LINK_RESET) && + (opcode != MPI_SAS_OP_PHY_HARD_RESET)) +- return -1; ++ return -1; + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dcsmisasprintk(ioc, printk(KERN_ERR ": no msg frames!\n")); + return -1; +- } ++ } + + mpi_hdr = (MPIHeader_t *) mf; + MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; +- memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); ++ memset(sasIoUnitCntrReq, 0, sizeof(SasIoUnitControlRequest_t)); + sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; + sasIoUnitCntrReq->MsgContext = MsgContext; + sasIoUnitCntrReq->Operation = opcode; +@@ -4857,7 +4855,7 @@ csmisas_phy_reset(MPT_ADAPTER *ioc, u8 P + & MPI_IOCSTATUS_MASK; + if (ioc_status != MPI_IOCSTATUS_SUCCESS) { + printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", +- __FUNCTION__, ++ __func__, + sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo); + return -1; +@@ -4878,12 +4876,12 @@ csmisas_phy_control(unsigned long arg) + CSMI_SAS_PHY_CONTROL_BUFFER __user *uarg = (void __user *) arg; + IOCTL_HEADER ioctl_header; + PCSMI_SAS_PHY_CONTROL_BUFFER karg; +- SasIOUnitPage0_t *sasIoUnitPg0=NULL; ++ SasIOUnitPage0_t *sasIoUnitPg0 = NULL; + dma_addr_t sasIoUnitPg0_dma; +- int sasIoUnitPg0_data_sz=0; +- SasIOUnitPage1_t *sasIoUnitPg1=NULL; ++ int sasIoUnitPg0_data_sz = 0; ++ SasIOUnitPage1_t *sasIoUnitPg1 = NULL; + dma_addr_t sasIoUnitPg1_dma; +- int sasIoUnitPg1_data_sz=0; ++ int sasIoUnitPg1_data_sz = 0; + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + MPT_ADAPTER *ioc = NULL; +@@ -4894,7 +4892,7 @@ csmisas_phy_control(unsigned long arg) + if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in IOCTL_HEADER" +- "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ "struct @ %p\n", __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +@@ -4902,11 +4900,11 @@ csmisas_phy_control(unsigned long arg) + memory_pages = get_order(csmi_sas_phy_control_buffer_sz); + karg = (PCSMI_SAS_PHY_CONTROL_BUFFER)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!karg){ ++ if (!karg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc SAS_PHY_CONTROL_BUFFER " + "csmi_sas_phy_control_buffer_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + csmi_sas_phy_control_buffer_sz, memory_pages); + return -ENOMEM; + } +@@ -4915,7 +4913,7 @@ csmisas_phy_control(unsigned long arg) + if (copy_from_user(karg, uarg, csmi_sas_phy_control_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_phy_control_buffer " +- "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ "struct @ %p\n", __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } +@@ -4923,19 +4921,19 @@ csmisas_phy_control(unsigned long arg) + if (((iocnum = mpt_verify_adapter(ioctl_header.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + if (karg->bPhyIdentifier >= ioc->num_ports) { + karg->IoctlHeader.ReturnCode = +@@ -4970,7 +4968,8 @@ csmisas_phy_control(unsigned long arg) + } + + if (hdr.ExtPageLength == 0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } +@@ -4980,7 +4979,8 @@ csmisas_phy_control(unsigned long arg) + sasIoUnitPg0_data_sz, &sasIoUnitPg0_dma); + + if (!sasIoUnitPg0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } +@@ -5023,7 +5023,8 @@ csmisas_phy_control(unsigned long arg) + } + + if (hdr.ExtPageLength == 0) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": hdr.ExtPageLength == 0\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } +@@ -5033,7 +5034,8 @@ csmisas_phy_control(unsigned long arg) + sasIoUnitPg1_data_sz, &sasIoUnitPg1_dma); + + if (!sasIoUnitPg1) { +- dcsmisasprintk(ioc, printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); ++ dcsmisasprintk(ioc, ++ printk(KERN_ERR ": pci_alloc_consistent: FAILED\n")); + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_FAILED; + goto cim_sas_phy_control_exit; + } +@@ -5054,19 +5056,18 @@ csmisas_phy_control(unsigned long arg) + case CSMI_SAS_PC_LINK_RESET: + case CSMI_SAS_PC_HARD_RESET: + { +- u8 opcode = (karg->uFunction==CSMI_SAS_PC_LINK_RESET) ? ++ u8 opcode = (karg->uFunction == CSMI_SAS_PC_LINK_RESET) ? + MPI_SAS_OP_PHY_LINK_RESET : MPI_SAS_OP_PHY_HARD_RESET; + +- if((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) && ++ if ((karg->uLinkFlags & CSMI_SAS_PHY_ACTIVATE_CONTROL) && + (karg->usLengthOfControl >= sizeof(CSMI_SAS_PHY_CONTROL)) && +- (karg->bNumberOfControls > 0)){ +- if(karg->Control[0].bRate == ++ (karg->bNumberOfControls > 0)) { ++ if (karg->Control[0].bRate == + CSMI_SAS_LINK_RATE_1_5_GBPS) { + sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate = + MPI_SAS_IOUNIT1_MAX_RATE_1_5 | + MPI_SAS_IOUNIT1_MIN_RATE_1_5; +- } +- else if(karg->Control[0].bRate == ++ } else if (karg->Control[0].bRate == + CSMI_SAS_LINK_RATE_3_0_GBPS) { + sasIoUnitPg1->PhyData[karg->bPhyIdentifier].MaxMinLinkRate = + MPI_SAS_IOUNIT1_MAX_RATE_3_0 | +@@ -5103,7 +5104,7 @@ csmisas_phy_control(unsigned long arg) + + } + case CSMI_SAS_PC_PHY_DISABLE: +- if(karg->usLengthOfControl || karg->bNumberOfControls) { ++ if (karg->usLengthOfControl || karg->bNumberOfControls) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + break; +@@ -5135,14 +5136,14 @@ csmisas_phy_control(unsigned long arg) + break; + + case CSMI_SAS_PC_GET_PHY_SETTINGS: +- if(karg->usLengthOfControl || karg->bNumberOfControls) { ++ if (karg->usLengthOfControl || karg->bNumberOfControls) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + break; + } +- if(csmi_sas_phy_control_buffer_sz < +- offsetof(CSMI_SAS_PHY_CONTROL_BUFFER,Control) + +- (4* sizeof(CSMI_SAS_PHY_CONTROL))) { ++ if (csmi_sas_phy_control_buffer_sz < ++ offsetof(CSMI_SAS_PHY_CONTROL_BUFFER, Control) + ++ (4 * sizeof(CSMI_SAS_PHY_CONTROL))) { + karg->IoctlHeader.ReturnCode = + CSMI_SAS_STATUS_INVALID_PARAMETER; + break; +@@ -5175,15 +5176,15 @@ csmisas_phy_control(unsigned long arg) + + /* Copy the data from kernel memory to user memory + */ +- if (copy_to_user(uarg, karg,csmi_sas_phy_control_buffer_sz)) { ++ if (copy_to_user(uarg, karg, csmi_sas_phy_control_buffer_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_phy_control_buffer @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + free_pages((unsigned long)karg, memory_pages); + return 0; + } +@@ -5202,7 +5203,8 @@ csmisas_phy_control(unsigned long arg) + * -EFAULT for non-successful reply or no reply (timeout) + **/ + static int +-csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, int mfg_size) ++csmisas_get_manuf_pg_7(MPT_ADAPTER *ioc, ManufacturingPage7_t *mfgpage7_buffer, ++ int mfg_size) + { + ConfigPageHeader_t hdr; + CONFIGPARMS cfg; +@@ -5281,41 +5283,41 @@ csmisas_get_connector_info(unsigned long + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_connector_info_buffer" + " struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + if (((iocnum = mpt_verify_adapter(karg.IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + karg.IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + + /* `32` is the sizeof MPI_MANPAGE7_CONNECTOR_INFO */ + for (i = 0; i < 32; i++) { + karg.Reference[i].uPinout = CSMI_SAS_CON_UNKNOWN; +- strcpy(karg.Reference[i].bConnector,""); ++ strcpy(karg.Reference[i].bConnector, ""); + karg.Reference[i].bLocation = CSMI_SAS_CON_UNKNOWN; + } + +- mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7,ConnectorInfo) + ++ mfgPg7_sz = offsetof(CONFIG_PAGE_MANUFACTURING_7, ConnectorInfo) + + (ioc->num_ports * sizeof(MPI_MANPAGE7_CONNECTOR_INFO)); + mfgPg7 = kmalloc(mfgPg7_sz, GFP_KERNEL); +- if (!mfgPg7){ ++ if (!mfgPg7) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, mfgPg7); ++ __FILE__, __LINE__, __func__, mfgPg7); + return -EFAULT; + } + memset(mfgPg7, 0, mfgPg7_sz); +@@ -5339,13 +5341,12 @@ csmisas_get_connector_info(unsigned long + if (copy_to_user(uarg, &karg, + sizeof(CSMI_SAS_CONNECTOR_INFO_BUFFER))) { + printk(KERN_ERR "%s@%d::%s() - " +- "Unable to write out csmi_sas_connector_info_buffer @" +- "%p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ "Unable to write out csmi_sas_connector_info_buffer @%p\n", ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return 0; + } + +@@ -5357,21 +5358,21 @@ csmisas_get_connector_info(unsigned long + **/ + static int + csmisas_fill_location_data(MPT_ADAPTER *ioc, u8 bus, u8 id, u8 opcode, +- CSMI_SAS_LOCATION_IDENTIFIER * location_ident) ++ CSMI_SAS_LOCATION_IDENTIFIER *location_ident) + { + + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + int rc; +- SasDevicePage0_t *sasDevicePg0=NULL; +- SasEnclosurePage0_t *sasEnclosurePg0=NULL; +- dma_addr_t sasDevicePg0_dma,sasEnclosurePg0_dma; +- int sasDevicePg0_data_sz=0; +- int sasEnclosurePg0_data_sz=0; ++ SasDevicePage0_t *sasDevicePg0 = NULL; ++ SasEnclosurePage0_t *sasEnclosurePg0 = NULL; ++ dma_addr_t sasDevicePg0_dma, sasEnclosurePg0_dma; ++ int sasDevicePg0_data_sz = 0; ++ int sasEnclosurePg0_data_sz = 0; + u64 sas_address; + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); +- memset (location_ident, 0, sizeof(*location_ident)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); ++ memset(location_ident, 0, sizeof(*location_ident)); + + /* SAS Device Page 0 */ + hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; +@@ -5389,12 +5390,12 @@ csmisas_fill_location_data(MPT_ADAPTER * + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { +- rc=-1; ++ rc = -1; + goto fill_location_data_exit; + } + + if (hdr.ExtPageLength == 0) { +- rc=-1; ++ rc = -1; + goto fill_location_data_exit; + } + +@@ -5402,7 +5403,7 @@ csmisas_fill_location_data(MPT_ADAPTER * + sasDevicePg0 = (SasDevicePage0_t *) pci_alloc_consistent( + ioc->pcidev, sasDevicePg0_data_sz, &sasDevicePg0_dma); + if (!sasDevicePg0) { +- rc=-1; ++ rc = -1; + goto fill_location_data_exit; + } + +@@ -5411,10 +5412,10 @@ csmisas_fill_location_data(MPT_ADAPTER * + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = (bus << 8) + id + + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << +- MPI_SAS_DEVICE_PGAD_FORM_SHIFT); ++ MPI_SAS_DEVICE_PGAD_FORM_SHIFT); + + if ((rc = mpt_config(ioc, &cfg)) != 0) { +- rc=-1; ++ rc = -1; + goto fill_location_data_exit; + } + +@@ -5442,12 +5443,12 @@ csmisas_fill_location_data(MPT_ADAPTER * + cfg.timeout = MPT_IOCTL_DEFAULT_TIMEOUT; + + if ((rc = mpt_config(ioc, &cfg)) != 0) { +- rc=0; ++ rc = 0; + goto fill_location_data_exit; + } + + if (hdr.ExtPageLength == 0) { +- rc=0; ++ rc = 0; + goto fill_location_data_exit; + } + +@@ -5455,36 +5456,34 @@ csmisas_fill_location_data(MPT_ADAPTER * + sasEnclosurePg0 = (SasEnclosurePage0_t *) pci_alloc_consistent( + ioc->pcidev, sasEnclosurePg0_data_sz, &sasEnclosurePg0_dma); + if (!sasEnclosurePg0) { +- rc=0; ++ rc = 0; + goto fill_location_data_exit; + } + cfg.physAddr = sasEnclosurePg0_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = sasDevicePg0->EnclosureHandle +- + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT); ++ + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << ++ MPI_SAS_ENCLOS_PGAD_FORM_SHIFT); + + if ((rc = mpt_config(ioc, &cfg)) != 0) { +- rc=0; ++ rc = 0; + goto fill_location_data_exit; + } + +- location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID; ++ location_ident->bLocationFlags |= ++ CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID; + memcpy(&sas_address, &sasEnclosurePg0->EnclosureLogicalID, sizeof(u64)); + sas_address = reverse_byte_order64(sas_address); + if (sas_address) +- memcpy(location_ident->bEnclosureIdentifier, &sas_address, sizeof(u64)); ++ memcpy(location_ident->bEnclosureIdentifier, &sas_address, ++ sizeof(u64)); + else +- strcpy(location_ident->bEnclosureIdentifier,"Internal"); ++ strcpy(location_ident->bEnclosureIdentifier, "Internal"); + +-// bBayPrefix - not supported ++/* bBayPrefix - not supported */ + +-// TODO - We need to look at sasEnclosurePg0-.Flags , to determine +-// whether SEP BUS/TargetID is valid. Ifs its a SES device, then +-// issue internal inquiry to (bus/id) to gather the Enclosure name. +-// If the device is SMP, then issue SMP_MANUFACTURING to get enclosure name +-// If its direct attached, there is no enclosure name + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID; +- strcpy(location_ident->bEnclosureName,"Not Supported"); ++ strcpy(location_ident->bEnclosureName, "Not Supported"); + + location_ident->bLocationFlags |= CSMI_SAS_LOCATE_LOCATION_STATE_VALID; + location_ident->bLocationState = CSMI_SAS_LOCATE_UNKNOWN; +@@ -5493,11 +5492,6 @@ csmisas_fill_location_data(MPT_ADAPTER * + location_ident->bBayIdentifier = le16_to_cpu(sasDevicePg0->Slot); + + +-// TODO - illuminating LEDs, +-// karg->bIdentify = CSMI_SAS_LOCATE_FORCE_OFF, CSMI_SAS_LOCATE_FORCE_ON +-// We can enable/disable LEDs by SCSI Enclosure Processor MPI request message +-// printk("Flags=0x%x\n",sasEnclosurePg0->Flags); +- + /* check sasEnclosurePg0->Flags - + * to validate whether we need to send the SEPRequest + * bit:5 should be set +@@ -5527,13 +5521,13 @@ fill_location_data_exit: + pci_free_consistent(ioc->pcidev, sasEnclosurePg0_data_sz, + sasEnclosurePg0, sasEnclosurePg0_dma); + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + return rc; + } + + static int +-csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus, +- u8 volumeID) ++csmisas_fill_location_data_raid(MPT_ADAPTER *ioc, ++ PCSMI_SAS_GET_LOCATION_BUFFER karg, u8 VolumeBus, u8 volumeID) + { + pRaidVolumePage0_t pVolume0 = NULL; + pRaidPhysDiskPage0_t pPhysDisk0 = NULL; +@@ -5554,9 +5548,9 @@ csmisas_fill_location_data_raid(MPT_ADAP + + csmi_sas_get_location_sz = karg->IoctlHeader.Length; + physDiskNumMax = (csmi_sas_get_location_sz - +- offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) ++ offsetof(CSMI_SAS_GET_LOCATION_BUFFER, Location)) + / sizeof(CSMI_SAS_LOCATION_IDENTIFIER); +- karg->bNumberOfLocationIdentifiers=0; ++ karg->bNumberOfLocationIdentifiers = 0; + + /* + * get RAID Volume Page 0 +@@ -5592,7 +5586,7 @@ csmisas_fill_location_data_raid(MPT_ADAP + + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.physAddr = volume0_dma; +- if (mpt_config(ioc, &cfg) != 0){ ++ if (mpt_config(ioc, &cfg) != 0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } +@@ -5632,17 +5626,17 @@ csmisas_fill_location_data_raid(MPT_ADAP + } + cfg.physAddr = physdisk0_dma; + +- for (i=0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { ++ for (i = 0; i < min(pVolume0->NumPhysDisks, physDiskNumMax); i++) { + + /* obtain a refresh of pPhysDisk0 */ + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = pVolume0->PhysDisk[i].PhysDiskNum; +- if (mpt_config(ioc, &cfg) != 0){ ++ if (mpt_config(ioc, &cfg) != 0) { + rc = -1; + goto sas_fill_location_data_raid_exit; + } + +- if((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus, ++ if ((csmisas_fill_location_data(ioc, pPhysDisk0->PhysDiskBus, + pPhysDisk0->PhysDiskID, karg->bIdentify, + &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0) + karg->bNumberOfLocationIdentifiers++; +@@ -5679,7 +5673,7 @@ csmisas_fill_location_data_raid(MPT_ADAP + if (csmisas_get_ioc_pg5(ioc, iocPage5, sz) != 0) + goto sas_fill_location_data_raid_exit; + +- for(i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares; ++ for (i = 0, idx = pVolume0->NumPhysDisks ; i < num_hotpares; + i++, idx++) { + + if (idx >= physDiskNumMax) +@@ -5728,11 +5722,11 @@ csmisas_fill_location_data_raid(MPT_ADAP + if ((pVolume0->VolumeType == + MPI_RAID_VOL_TYPE_IME) && + ((tmpTotalMaxLBA * 2) + +- (64*2*1024 ) /*metadata = 64MB*/ > ++ (64*2*1024) /*metadata = 64MB*/ > + le32_to_cpu(pPhysDisk0->MaxLBA))) + continue; + +- if((csmisas_fill_location_data(ioc, ++ if ((csmisas_fill_location_data(ioc, + pPhysDisk0->PhysDiskBus, pPhysDisk0->PhysDiskID, + karg->bIdentify, + &karg->Location[karg->bNumberOfLocationIdentifiers])) == 0) +@@ -5749,7 +5743,7 @@ csmisas_fill_location_data_raid(MPT_ADAP + pci_free_consistent(ioc->pcidev, volumepage0sz, pVolume0, + volume0_dma); + +- if(pPhysDisk0) ++ if (pPhysDisk0) + pci_free_consistent(ioc->pcidev, physdiskpage0sz, pPhysDisk0, + physdisk0_dma); + +@@ -5771,7 +5765,7 @@ csmisas_get_location(unsigned long arg) + PCSMI_SAS_GET_LOCATION_BUFFER karg; + IOCTL_HEADER ioctl_header; + MPT_ADAPTER *ioc = NULL; +- int iocnum,i; ++ int iocnum, i; + int csmi_sas_get_location_sz; + int memory_pages; + struct sas_device_info *sas_info; +@@ -5779,7 +5773,7 @@ csmisas_get_location(unsigned long arg) + if (copy_from_user(&ioctl_header, uarg, sizeof(IOCTL_HEADER))) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in IOCTL_HEADER" +- "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ "struct @ %p\n", __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +@@ -5787,11 +5781,11 @@ csmisas_get_location(unsigned long arg) + memory_pages = get_order(csmi_sas_get_location_sz); + karg = (PCSMI_SAS_GET_LOCATION_BUFFER)__get_free_pages( + GFP_KERNEL, memory_pages); +- if (!karg){ ++ if (!karg) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to malloc GET_LOCATION_BUFFER " + "csmi_sas_get_location_sz=%d memory_pages=%d\n", +- __FILE__, __LINE__, __FUNCTION__, ++ __FILE__, __LINE__, __func__, + csmi_sas_get_location_sz, memory_pages); + return -ENOMEM; + } +@@ -5800,7 +5794,7 @@ csmisas_get_location(unsigned long arg) + if (copy_from_user(karg, uarg, csmi_sas_get_location_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to read in csmi_sas_phy_control_buffer " +- "struct @ %p\n", __FILE__, __LINE__, __FUNCTION__, uarg); ++ "struct @ %p\n", __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } +@@ -5808,22 +5802,22 @@ csmisas_get_location(unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg->IoctlHeader.IOControllerNumber, + &ioc)) < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + + if (!csmisas_is_this_sas_cntr(ioc)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not SAS controller!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + free_pages((unsigned long)karg, memory_pages); + return -ENODEV; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s enter.\n", __func__)); + + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_INVALID_PARAMETER; +- if(karg->bLengthOfLocationIdentifier != ++ if (karg->bLengthOfLocationIdentifier != + sizeof(CSMI_SAS_LOCATION_IDENTIFIER)) + goto cim_sas_get_location_exit; + +@@ -5834,12 +5828,12 @@ csmisas_get_location(unsigned long arg) + + /* RAID SUPPORT */ + if (ioc->raid_data.pIocPg2 && sas_info->is_logical_volume) { +- for (i=0; iraid_data.pIocPg2->NumActiveVolumes; i++){ ++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (sas_info->fw.id == + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID && + sas_info->fw.channel == + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus) { +- if(csmisas_fill_location_data_raid(ioc, karg, ++ if (csmisas_fill_location_data_raid(ioc, karg, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) == 0) + karg->IoctlHeader.ReturnCode = +@@ -5858,13 +5852,13 @@ csmisas_get_location(unsigned long arg) + + /* make sure there's enough room to populate the Location[] struct */ + if ((csmi_sas_get_location_sz - +- offsetof(CSMI_SAS_GET_LOCATION_BUFFER,Location)) < ++ offsetof(CSMI_SAS_GET_LOCATION_BUFFER, Location)) < + sizeof(CSMI_SAS_LOCATION_IDENTIFIER)) + goto cim_sas_get_location_exit; + +- karg->bNumberOfLocationIdentifiers=1; +- karg->Location[0].bLocationFlags=0; +- if((csmisas_fill_location_data(ioc, sas_info->fw.channel, ++ karg->bNumberOfLocationIdentifiers = 1; ++ karg->Location[0].bLocationFlags = 0; ++ if ((csmisas_fill_location_data(ioc, sas_info->fw.channel, + sas_info->fw.id, karg->bIdentify, &karg->Location[0])) == 0) + karg->IoctlHeader.ReturnCode = CSMI_SAS_STATUS_SUCCESS; + else +@@ -5877,12 +5871,12 @@ csmisas_get_location(unsigned long arg) + if (copy_to_user(uarg, karg, csmi_sas_get_location_sz)) { + printk(KERN_ERR "%s@%d::%s() - " + "Unable to write out csmi_sas_get_location_buffer " +- "@ %p\n",__FILE__, __LINE__, __FUNCTION__, uarg); ++ "@ %p\n", __FILE__, __LINE__, __func__, uarg); + free_pages((unsigned long)karg, memory_pages); + return -EFAULT; + } + +- dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n",__FUNCTION__)); ++ dcsmisasprintk(ioc, printk(KERN_DEBUG "%s exit.\n", __func__)); + free_pages((unsigned long)karg, memory_pages); + return 0; + } +Index: linux-2.6.27/drivers/message/fusion/csmi/csmisas.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/csmi/csmisas.h ++++ linux-2.6.27/drivers/message/fusion/csmi/csmisas.h +@@ -87,10 +87,10 @@ Revision History: + #ifndef _CSMI_SAS_H_ + #define _CSMI_SAS_H_ + +-// CSMI Specification Revision, the intent is that all versions of the +-// specification will be backward compatible after the 1.00 release. +-// Major revision number, corresponds to xxxx. of CSMI specification +-// Minor revision number, corresponds to .xxxx of CSMI specification ++/* CSMI Specification Revision, the intent is that all versions of the ++ specification will be backward compatible after the 1.00 release. ++ Major revision number, corresponds to xxxx. of CSMI specification ++ Minor revision number, corresponds to .xxxx of CSMI specification */ + #define CSMI_MAJOR_REVISION 0 + #define CSMI_MINOR_REVISION 90 + +@@ -104,60 +104,60 @@ Revision History: + /* TARGET OS LINUX SPECIFIC CODE */ + /*************************************************************************/ + +-// EDM #ifdef _linux + #ifdef __KERNEL__ + +-// Linux base types ++/* Linux base types */ + + #include + + #define __i8 char + +-// pack definition ++/* pack definition */ + +-// EDM #define CSMI_SAS_BEGIN_PACK(x) pack(x) +-// EDM #define CSMI_SAS_END_PACK pack() ++#if 0 ++ #define CSMI_SAS_BEGIN_PACK(x) pack(x) ++ #define CSMI_SAS_END_PACK pack() + +-// IOCTL Control Codes +-// (IoctlHeader.ControlCode) ++ /* IOCTL Control Codes */ ++ /* (IoctlHeader.ControlCode) */ + +-// Control Codes prior to 0.77 ++ /* Control Codes prior to 0.77 */ + +-// Control Codes requiring CSMI_ALL_SIGNATURE ++ /* Control Codes requiring CSMI_ALL_SIGNATURE */ + +-// #define CC_CSMI_SAS_GET_DRIVER_INFO 0x12345678 +-// #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x23456781 +-// #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x34567812 +-// #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x92345678 ++ #define CC_CSMI_SAS_GET_DRIVER_INFO 0x12345678 ++ #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x23456781 ++ #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x34567812 ++ #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x92345678 + +-// Control Codes requiring CSMI_RAID_SIGNATURE ++ /* Control Codes requiring CSMI_RAID_SIGNATURE */ + +-// #define CC_CSMI_SAS_GET_RAID_INFO 0x45678123 +-// #define CC_CSMI_SAS_GET_RAID_CONFIG 0x56781234 ++ #define CC_CSMI_SAS_GET_RAID_INFO 0x45678123 ++ #define CC_CSMI_SAS_GET_RAID_CONFIG 0x56781234 + +-// Control Codes requiring CSMI_SAS_SIGNATURE ++ /* Control Codes requiring CSMI_SAS_SIGNATURE */ + +-// #define CC_CSMI_SAS_GET_PHY_INFO 0x67812345 +-// #define CC_CSMI_SAS_SET_PHY_INFO 0x78123456 +-// #define CC_CSMI_SAS_GET_LINK_ERRORS 0x81234567 +-// #define CC_CSMI_SAS_SMP_PASSTHRU 0xA1234567 +-// #define CC_CSMI_SAS_SSP_PASSTHRU 0xB1234567 +-// #define CC_CSMI_SAS_STP_PASSTHRU 0xC1234567 +-// #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567 +-// #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xE1234567 +-// #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567 +-// #define CC_CSMI_SAS_TASK_MANAGEMENT 0xA2345678 +- +-// Control Codes for 0.77 and later ++ #define CC_CSMI_SAS_GET_PHY_INFO 0x67812345 ++ #define CC_CSMI_SAS_SET_PHY_INFO 0x78123456 ++ #define CC_CSMI_SAS_GET_LINK_ERRORS 0x81234567 ++ #define CC_CSMI_SAS_SMP_PASSTHRU 0xA1234567 ++ #define CC_CSMI_SAS_SSP_PASSTHRU 0xB1234567 ++ #define CC_CSMI_SAS_STP_PASSTHRU 0xC1234567 ++ #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567 ++ #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xE1234567 ++ #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567 ++ #define CC_CSMI_SAS_TASK_MANAGEMENT 0xA2345678 ++#endif ++ /* Control Codes for 0.77 and later */ + +-// Control Codes requiring CSMI_ALL_SIGNATURE ++ /* Control Codes requiring CSMI_ALL_SIGNATURE */ + + #define CC_CSMI_SAS_GET_DRIVER_INFO 0xCC770001 + #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0xCC770002 + #define CC_CSMI_SAS_GET_CNTLR_STATUS 0xCC770003 + #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0xCC770004 + +-// Control Codes requiring CSMI_RAID_SIGNATURE ++/* Control Codes requiring CSMI_RAID_SIGNATURE */ + + #define CC_CSMI_SAS_GET_RAID_INFO 0xCC77000A + #define CC_CSMI_SAS_GET_RAID_CONFIG 0xCC77000B +@@ -166,7 +166,7 @@ Revision History: + #define CC_CSMI_SAS_GET_RAID_ELEMENT 0xCC77000E + #define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F + +-// Control Codes requiring CSMI_SAS_SIGNATURE ++/* Control Codes requiring CSMI_SAS_SIGNATURE */ + + #define CC_CSMI_SAS_GET_PHY_INFO 0xCC770014 + #define CC_CSMI_SAS_SET_PHY_INFO 0xCC770015 +@@ -182,14 +182,14 @@ Revision History: + #define CC_CSMI_SAS_GET_LOCATION 0xCC770025 + + +-// Control Codes requiring CSMI_PHY_SIGNATURE ++/* Control Codes requiring CSMI_PHY_SIGNATURE */ + + #define CC_CSMI_SAS_PHY_CONTROL 0xCC77003C + +-// EDM #pragma CSMI_SAS_BEGIN_PACK(8) ++/* #pragma CSMI_SAS_BEGIN_PACK(8) */ + #pragma pack(8) + +-// IOCTL_HEADER ++/* IOCTL_HEADER */ + typedef struct _IOCTL_HEADER { + __u32 IOControllerNumber; + __u32 Length; +@@ -199,189 +199,18 @@ typedef struct _IOCTL_HEADER { + } IOCTL_HEADER, + *PIOCTL_HEADER; + +-// EDM #pragma CSMI_SAS_END_PACK +-#pragma pack() +- +-#endif +- +-/*************************************************************************/ +-/* TARGET OS WINDOWS SPECIFIC CODE */ +-/*************************************************************************/ +- +-#ifdef _WIN32 +- +-// windows IOCTL definitions +- +-#ifndef _NTDDSCSIH_ +-#include +-#endif +- +-// pack definition +- +-#if defined _MSC_VER +- #define CSMI_SAS_BEGIN_PACK(x) pack(push,x) +- #define CSMI_SAS_END_PACK pack(pop) +-#elif defined __BORLANDC__ +- #define CSMI_SAS_BEGIN_PACK(x) option -a##x +- #define CSMI_SAS_END_PACK option -a. +-#else +- #error "CSMISAS.H - Must externally define a pack compiler designator." +-#endif +- +-// base types +- +-#define __u8 unsigned char +-#define __u16 unsigned short +-#define __u32 unsigned long +-#define __u64 unsigned __int64 +- +-#define __i8 char +- +-// IOCTL Control Codes +-// (IoctlHeader.ControlCode) +- +-// Control Codes requiring CSMI_ALL_SIGNATURE +- +-#define CC_CSMI_SAS_GET_DRIVER_INFO 1 +-#define CC_CSMI_SAS_GET_CNTLR_CONFIG 2 +-#define CC_CSMI_SAS_GET_CNTLR_STATUS 3 +-#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 4 +- +-// Control Codes requiring CSMI_RAID_SIGNATURE +- +-#define CC_CSMI_SAS_GET_RAID_INFO 10 +-#define CC_CSMI_SAS_GET_RAID_CONFIG 11 +-#define CC_CSMI_SAS_GET_RAID_FEATURES 12 +-#define CC_CSMI_SAS_SET_RAID_CONTROL 13 +-#define CC_CSMI_SAS_GET_RAID_ELEMENT 14 +-#define CC_CSMI_SAS_SET_RAID_OPERATION 15 +- +-// Control Codes requiring CSMI_SAS_SIGNATURE +- +-#define CC_CSMI_SAS_GET_PHY_INFO 20 +-#define CC_CSMI_SAS_SET_PHY_INFO 21 +-#define CC_CSMI_SAS_GET_LINK_ERRORS 22 +-#define CC_CSMI_SAS_SMP_PASSTHRU 23 +-#define CC_CSMI_SAS_SSP_PASSTHRU 24 +-#define CC_CSMI_SAS_STP_PASSTHRU 25 +-#define CC_CSMI_SAS_GET_SATA_SIGNATURE 26 +-#define CC_CSMI_SAS_GET_SCSI_ADDRESS 27 +-#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28 +-#define CC_CSMI_SAS_TASK_MANAGEMENT 29 +-#define CC_CSMI_SAS_GET_CONNECTOR_INFO 30 +-#define CC_CSMI_SAS_GET_LOCATION 31 +- +-// Control Codes requiring CSMI_PHY_SIGNATURE +- +-#define CC_CSMI_SAS_PHY_CONTROL 60 +- +-#define IOCTL_HEADER SRB_IO_CONTROL +-#define PIOCTL_HEADER PSRB_IO_CONTROL +- +-#endif +- +-/*************************************************************************/ +-/* TARGET OS NETWARE SPECIFIC CODE */ +-/*************************************************************************/ +- +-#ifdef _NETWARE +- +-// NetWare IOCTL definitions +- +-#define CSMI_SAS_BEGIN_PACK(x) pack(x) +-#define CSMI_SAS_END_PACK pack() +- +-#ifndef LONG +-typedef unsigned long LONG; +-#endif +- +-#ifndef WORD +-typedef unsigned short WORD; +-#endif +- +-#ifndef BYTE +-typedef unsigned char BYTE; +-#endif +- +-/* Need to have these definitions for Netware */ +-#define __u8 unsigned char +-#define __u16 unsigned short +-#define __u32 unsigned long +-#define __u64 unsigned __int64 +- +-#define __i8 char +- +- +-// EDM #pragma CSMI_SAS_BEGIN_PACK(8) +-#pragma pack(8) +- +-// IOCTL_HEADER +-typedef struct _IOCTL_HEADER { +- __u32 Length; +- __u32 ReturnCode; +-} IOCTL_HEADER, +- *PIOCTL_HEADER; +- +-// EDM #pragma CSMI_SAS_END_PACK + #pragma pack() + +-// IOCTL Control Codes +-// (IoctlHeader.ControlCode) +- +-// Control Codes requiring CSMI_ALL_SIGNATURE +- +-#define CC_CSMI_SAS_GET_DRIVER_INFO 0x01FF0001 +-#define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x01FF0002 +-#define CC_CSMI_SAS_GET_CNTLR_STATUS 0x01FF0003 +-#define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x01FF0004 +- +-// Control Codes requiring CSMI_RAID_SIGNATURE +- +-#define CC_CSMI_SAS_GET_RAID_INFO 0x01FF000A +-#define CC_CSMI_SAS_GET_RAID_CONFIG 0x01FF000B +-#define CC_CSMI_SAS_GET_RAID_FEATURES 0x01FF000C +-#define CC_CSMI_SAS_SET_RAID_CONTROL 0x01FF000D +-#define CC_CSMI_SAS_GET_RAID_ELEMENT 0x01FF000E +-#define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F +- +-// Control Codes requiring CSMI_SAS_SIGNATURE +- +-#define CC_CSMI_SAS_GET_PHY_INFO 0x01FF0014 +-#define CC_CSMI_SAS_SET_PHY_INFO 0x01FF0015 +-#define CC_CSMI_SAS_GET_LINK_ERRORS 0x01FF0016 +-#define CC_CSMI_SAS_SMP_PASSTHRU 0x01FF0017 +-#define CC_CSMI_SAS_SSP_PASSTHRU 0x01FF0018 +-#define CC_CSMI_SAS_STP_PASSTHRU 0x01FF0019 +-#define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A +-#define CC_CSMI_SAS_GET_SCSI_ADDRESS 0x01FF001B +-#define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C +-#define CC_CSMI_SAS_TASK_MANAGEMENT 0x01FF001D +-#define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E +-#define CC_CSMI_SAS_GET_LOCATION 0x01FF001F +- +-// Control Codes requiring CSMI_PHY_SIGNATURE +- +-#define CC_CSMI_SAS_PHY_CONTROL 60 +- + #endif + + /*************************************************************************/ +-/* TARGET OS NOT DEFINED ERROR */ +-/*************************************************************************/ +- +-// EDM +-//#if (!_WIN32 && !_linux && !_NETWARE) +-// #error "Unknown target OS." +-//#endif +- +-/*************************************************************************/ + /* OS INDEPENDENT CODE */ + /*************************************************************************/ + + /* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */ + +-// Return codes for all IOCTL's regardless of class +-// (IoctlHeader.ReturnCode) ++/* Return codes for all IOCTL's regardless of class*/ ++/* (IoctlHeader.ReturnCode) */ + + #define CSMI_SAS_STATUS_SUCCESS 0 + #define CSMI_SAS_STATUS_FAILED 1 +@@ -389,51 +218,51 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_STATUS_INVALID_PARAMETER 3 + #define CSMI_SAS_STATUS_WRITE_ATTEMPTED 4 + +-// Signature value +-// (IoctlHeader.Signature) ++/* Signature value ++ (IoctlHeader.Signature) */ + + #define CSMI_ALL_SIGNATURE "CSMIALL" + +-// Timeout value default of 60 seconds +-// (IoctlHeader.Timeout) ++/* Timeout value default of 60 seconds ++ (IoctlHeader.Timeout) */ + + #define CSMI_ALL_TIMEOUT 60 + +-// Direction values for data flow on this IOCTL +-// (IoctlHeader.Direction, Linux only) ++/* Direction values for data flow on this IOCTL ++ (IoctlHeader.Direction, Linux only) */ + #define CSMI_SAS_DATA_READ 0 + #define CSMI_SAS_DATA_WRITE 1 + +-// I/O Bus Types +-// ISA and EISA bus types are not supported +-// (bIoBusType) ++/* I/O Bus Types ++ ISA and EISA bus types are not supported ++ (bIoBusType) */ + + #define CSMI_SAS_BUS_TYPE_PCI 3 + #define CSMI_SAS_BUS_TYPE_PCMCIA 4 + +-// Controller Status +-// (uStatus) ++/* Controller Status ++ (uStatus) */ + + #define CSMI_SAS_CNTLR_STATUS_GOOD 1 + #define CSMI_SAS_CNTLR_STATUS_FAILED 2 + #define CSMI_SAS_CNTLR_STATUS_OFFLINE 3 + #define CSMI_SAS_CNTLR_STATUS_POWEROFF 4 + +-// Offline Status Reason +-// (uOfflineReason) ++/* Offline Status Reason ++ (uOfflineReason) */ + + #define CSMI_SAS_OFFLINE_REASON_NO_REASON 0 + #define CSMI_SAS_OFFLINE_REASON_INITIALIZING 1 + #define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2 + #define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE 3 + +-// Controller Class +-// (bControllerClass) ++/* Controller Class ++ (bControllerClass) */ + + #define CSMI_SAS_CNTLR_CLASS_HBA 5 + +-// Controller Flag bits +-// (uControllerFlags) ++/* Controller Flag bits ++ (uControllerFlags) */ + + #define CSMI_SAS_CNTLR_SAS_HBA 0x00000001 + #define CSMI_SAS_CNTLR_SAS_RAID 0x00000002 +@@ -441,32 +270,29 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_CNTLR_SATA_RAID 0x00000008 + #define CSMI_SAS_CNTLR_SMART_ARRAY 0x00000010 + +-// for firmware download ++/* for firmware download */ + #define CSMI_SAS_CNTLR_FWD_SUPPORT 0x00010000 + #define CSMI_SAS_CNTLR_FWD_ONLINE 0x00020000 + #define CSMI_SAS_CNTLR_FWD_SRESET 0x00040000 + #define CSMI_SAS_CNTLR_FWD_HRESET 0x00080000 + #define CSMI_SAS_CNTLR_FWD_RROM 0x00100000 + +-// for RAID configuration supported ++/* for RAID configuration supported */ + #define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000 + +-// Download Flag bits +-// (uDownloadFlags) ++/* Download Flag bits (uDownloadFlags) */ + #define CSMI_SAS_FWD_VALIDATE 0x00000001 + #define CSMI_SAS_FWD_SOFT_RESET 0x00000002 + #define CSMI_SAS_FWD_HARD_RESET 0x00000004 + +-// Firmware Download Status +-// (usStatus) ++/* Firmware Download Status (usStatus) */ + #define CSMI_SAS_FWD_SUCCESS 0 + #define CSMI_SAS_FWD_FAILED 1 + #define CSMI_SAS_FWD_USING_RROM 2 + #define CSMI_SAS_FWD_REJECT 3 + #define CSMI_SAS_FWD_DOWNREV 4 + +-// Firmware Download Severity +-// (usSeverity> ++/* Firmware Download Severity (usSeverity) */ + #define CSMI_SAS_FWD_INFORMATION 0 + #define CSMI_SAS_FWD_WARNING 1 + #define CSMI_SAS_FWD_ERROR 2 +@@ -474,25 +300,22 @@ typedef struct _IOCTL_HEADER { + + /* * * * * * * * * * SAS RAID Class IOCTL Constants * * * * * * * * */ + +-// Return codes for the RAID IOCTL's regardless of class +-// (IoctlHeader.ReturnCode) ++/* Return codes for the RAID IOCTL's regardless of class */ ++/* (IoctlHeader.ReturnCode) */ + + #define CSMI_SAS_RAID_SET_OUT_OF_RANGE 1000 + #define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL 1001 + #define CSMI_SAS_RAID_SET_DATA_CHANGED 1002 + +-// Signature value +-// (IoctlHeader.Signature) ++/* Signature value (IoctlHeader.Signature) */ + + #define CSMI_RAID_SIGNATURE "CSMIARY" + +-// Timeout value default of 60 seconds +-// (IoctlHeader.Timeout) ++/* Timeout value default of 60 seconds (IoctlHeader.Timeout) */ + + #define CSMI_RAID_TIMEOUT 60 + +-// RAID Types +-// (bRaidType) ++/* RAID Types (bRaidType) */ + #define CSMI_SAS_RAID_TYPE_NONE 0 + #define CSMI_SAS_RAID_TYPE_0 1 + #define CSMI_SAS_RAID_TYPE_1 2 +@@ -504,12 +327,11 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_RAID_TYPE_VOLUME 8 + #define CSMI_SAS_RAID_TYPE_1E 9 + #define CSMI_SAS_RAID_TYPE_OTHER 255 +-// the last value 255 was already defined for other +-// so end is defined as 254 ++/* the last value 255 was already defined for other so end is defined as 254 */ + #define CSMI_SAS_RAID_TYPE_END 254 + +-// RAID Status +-// (bStatus) ++/* RAID Status (bStatus) */ ++ + #define CSMI_SAS_RAID_SET_STATUS_OK 0 + #define CSMI_SAS_RAID_SET_STATUS_DEGRADED 1 + #define CSMI_SAS_RAID_SET_STATUS_REBUILDING 2 +@@ -519,19 +341,16 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD 6 + #define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION 7 + +-// RAID Drive Count +-// (bDriveCount, 0xF1 to 0xFF are reserved) ++/* RAID Drive Count (bDriveCount, 0xF1 to 0xFF are reserved) */ + #define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG 0xF1 + #define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2 + +-// RAID Data Type +-// (bDataType) ++/* RAID Data Type (bDataType) */ + #define CSMI_SAS_RAID_DATA_DRIVES 0 + #define CSMI_SAS_RAID_DATA_DEVICE_ID 1 + #define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA 2 + +-// RAID Drive Status +-// (bDriveStatus) ++/* RAID Drive Status (bDriveStatus) */ + #define CSMI_SAS_DRIVE_STATUS_OK 0 + #define CSMI_SAS_DRIVE_STATUS_REBUILDING 1 + #define CSMI_SAS_DRIVE_STATUS_FAILED 2 +@@ -539,15 +358,13 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_DRIVE_STATUS_OFFLINE 4 + #define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5 + +-// RAID Drive Usage +-// (bDriveUsage) ++/* RAID Drive Usage (bDriveUsage) */ + #define CSMI_SAS_DRIVE_CONFIG_NOT_USED 0 + #define CSMI_SAS_DRIVE_CONFIG_MEMBER 1 + #define CSMI_SAS_DRIVE_CONFIG_SPARE 2 + #define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE 3 + +-// RAID Drive Type +-// (bDriveType) ++/* RAID Drive Type (bDriveType) */ + #define CSMI_SAS_DRIVE_TYPE_UNKNOWN 0 + #define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1 + #define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS 2 +@@ -555,23 +372,20 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_DRIVE_TYPE_SATA_PS 4 + #define CSMI_SAS_DRIVE_TYPE_OTHER 255 + +-// RAID Write Protect +-// (bWriteProtect) ++/* RAID Write Protect (bWriteProtect) */ + #define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN 0 + #define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED 0 + #define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED 1 + #define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED 2 + +-// RAID Cache Setting +-// (bCacheSetting) ++/* RAID Cache Setting (bCacheSetting) */ + #define CSMI_SAS_RAID_SET_CACHE_UNKNOWN 0 + #define CSMI_SAS_RAID_SET_CACHE_UNCHANGED 0 + #define CSMI_SAS_RAID_SET_CACHE_ENABLED 1 + #define CSMI_SAS_RAID_SET_CACHE_DISABLED 2 + #define CSMI_SAS_RAID_SET_CACHE_CORRUPT 3 + +-// RAID Features +-// (uFeatures) ++/* RAID Features (uFeatures) */ + #define CSMI_SAS_RAID_FEATURE_TRANSFORMATION 0x00000001 + #define CSMI_SAS_RAID_FEATURE_REBUILD 0x00000002 + #define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR 0x00000004 +@@ -580,8 +394,7 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN 0x00000020 + #define CSMI_SAS_RAID_FEATURE_SPARES_SHARED 0x00000040 + +-// RAID Priority +-// (bDefaultTransformPriority, etc.) ++/* RAID Priority (bDefaultTransformPriority, etc.) */ + #define CSMI_SAS_PRIORITY_UNKNOWN 0 + #define CSMI_SAS_PRIORITY_UNCHANGED 0 + #define CSMI_SAS_PRIORITY_AUTO 1 +@@ -590,30 +403,25 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_PRIORITY_MEDIUM 4 + #define CSMI_SAS_PRIORITY_HIGH 5 + +-// RAID Transformation Rules +-// (uRaidSetTransformationRules) ++/* RAID Transformation Rules (uRaidSetTransformationRules) */ + #define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY 0x00000001 + #define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS 0x00000002 + +-// RAID Cache Ratios Supported +-// (bCacheRatiosSupported) +-// from 0 to 100 defines the write to read ratio, 0 is 100% write ++/* RAID Cache Ratios Supported (bCacheRatiosSupported) */ ++/* from 0 to 100 defines the write to read ratio, 0 is 100% write */ + #define CSMI_SAS_RAID_CACHE_RATIO_RANGE 101 + #define CSMI_SAS_RAID_CACHE_RATIO_FIXED 102 + #define CSMI_SAS_RAID_CACHE_RATIO_AUTO 103 + #define CSMI_SAS_RAID_CACHE_RATIO_END 255 + +-// RAID Cache Ratio Flag +-// (bCacheRatioFlag) ++/* RAID Cache Ratio Flag (bCacheRatioFlag) */ + #define CSMI_SAS_RAID_CACHE_RATIO_DISABLE 0 + #define CSMI_SAS_RAID_CACHE_RATIO_ENABLE 1 + +-// RAID Clear Configuration Signature +-// (bClearConfiguration) ++/* RAID Clear Configuration Signature (bClearConfiguration) */ + #define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR" + +-// RAID Failure Codes +-// (uFailureCode) ++/* RAID Failure Codes (uFailureCode) */ + #define CSMI_SAS_FAIL_CODE_OK 0 + #define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID 1000 + #define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID 1001 +@@ -638,22 +446,19 @@ typedef struct _IOCTL_HEADER { + + #define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION 3000 + +-// RAID Enumeration Types +-// (uEnumerationType) ++/* RAID Enumeration Types (uEnumerationType) */ + #define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE 0 + #define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE 1 + #define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET 2 + #define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE 3 + +-// RAID Extent Types +-// (bExtentType) ++/* RAID Extent Types (bExtentType) */ + #define CSMI_SAS_RAID_EXTENT_RESERVED 0 + #define CSMI_SAS_RAID_EXTENT_METADATA 1 + #define CSMI_SAS_RAID_EXTENT_ALLOCATED 2 + #define CSMI_SAS_RAID_EXTENT_UNALLOCATED 3 + +-// RAID Operation Types +-// (uOperationType) ++/* RAID Operation Types (uOperationType) */ + #define CSMI_SAS_RAID_SET_CREATE 0 + #define CSMI_SAS_RAID_SET_LABEL 1 + #define CSMI_SAS_RAID_SET_TRANSFORM 2 +@@ -663,23 +468,20 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_RAID_SET_ONLINE_STATE 6 + #define CSMI_SAS_RAID_SET_SPARE 7 + +-// RAID Transform Types +-// (bTransformType) ++/* RAID Transform Types (bTransformType) */ + #define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR 0 + #define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0 1 + #define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER 2 + #define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET 3 + +-// RAID Online State +-// (bOnlineState) ++/* RAID Online State (bOnlineState) */ + #define CSMI_SAS_RAID_SET_STATE_UNKNOWN 0 + #define CSMI_SAS_RAID_SET_STATE_ONLINE 1 + #define CSMI_SAS_RAID_SET_STATE_OFFLINE 2 + + /* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */ + +-// Return codes for SAS IOCTL's +-// (IoctlHeader.ReturnCode) ++/* Return codes for SAS IOCTL's (IoctlHeader.ReturnCode) */ + + #define CSMI_SAS_PHY_INFO_CHANGED CSMI_SAS_STATUS_SUCCESS + #define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE 2000 +@@ -700,18 +502,15 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_NO_SCSI_ADDRESS 2013 + #define CSMI_SAS_NO_DEVICE_ADDRESS 2014 + +-// Signature value +-// (IoctlHeader.Signature) ++/* Signature value (IoctlHeader.Signature) */ + + #define CSMI_SAS_SIGNATURE "CSMISAS" + +-// Timeout value default of 60 seconds +-// (IoctlHeader.Timeout) ++/* Timeout value default of 60 seconds (IoctlHeader.Timeout) */ + + #define CSMI_SAS_TIMEOUT 60 + +-// Device types +-// (bDeviceType) ++/* Device types (bDeviceType) */ + + #define CSMI_SAS_PHY_UNUSED 0x00 + #define CSMI_SAS_NO_DEVICE_ATTACHED 0x00 +@@ -719,16 +518,15 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_EDGE_EXPANDER_DEVICE 0x20 + #define CSMI_SAS_FANOUT_EXPANDER_DEVICE 0x30 + +-// Protocol options +-// (bInitiatorPortProtocol, bTargetPortProtocol) ++/* Protocol options (bInitiatorPortProtocol, bTargetPortProtocol) */ + + #define CSMI_SAS_PROTOCOL_SATA 0x01 + #define CSMI_SAS_PROTOCOL_SMP 0x02 + #define CSMI_SAS_PROTOCOL_STP 0x04 + #define CSMI_SAS_PROTOCOL_SSP 0x08 + +-// Negotiated and hardware link rates +-// (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate) ++/* Negotiated and hardware link rates */ ++/* (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate) */ + + #define CSMI_SAS_LINK_RATE_UNKNOWN 0x00 + #define CSMI_SAS_PHY_DISABLED 0x01 +@@ -739,8 +537,7 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09 + #define CSMI_SAS_LINK_VIRTUAL 0x10 + +-// Discover state +-// (bAutoDiscover) ++/* Discover state (bAutoDiscover) */ + + #define CSMI_SAS_DISCOVER_NOT_SUPPORTED 0x00 + #define CSMI_SAS_DISCOVER_NOT_STARTED 0x01 +@@ -748,57 +545,49 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_DISCOVER_COMPLETE 0x03 + #define CSMI_SAS_DISCOVER_ERROR 0x04 + +-// Phy features ++/* Phy features */ + + #define CSMI_SAS_PHY_VIRTUAL_SMP 0x01 + +-// Programmed link rates +-// (bMinimumLinkRate, bMaximumLinkRate) +-// (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate) ++/* Programmed link rates (bMinimumLinkRate, bMaximumLinkRate) */ ++/* (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate) */ + + #define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00 + #define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS 0x08 + #define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS 0x09 + +-// Link rate +-// (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO) ++/* Link rate (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO) */ + + #define CSMI_SAS_LINK_RATE_NEGOTIATE 0x00 + #define CSMI_SAS_LINK_RATE_PHY_DISABLED 0x01 + +-// Signal class +-// (bSignalClass in CSMI_SAS_SET_PHY_INFO) ++/* Signal class (bSignalClass in CSMI_SAS_SET_PHY_INFO) */ + + #define CSMI_SAS_SIGNAL_CLASS_UNKNOWN 0x00 + #define CSMI_SAS_SIGNAL_CLASS_DIRECT 0x01 + #define CSMI_SAS_SIGNAL_CLASS_SERVER 0x02 + #define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE 0x03 + +-// Link error reset +-// (bResetCounts) ++/* Link error reset (bResetCounts) */ + + #define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS 0x00 + #define CSMI_SAS_LINK_ERROR_RESET_COUNTS 0x01 + +-// Phy identifier +-// (bPhyIdentifier) ++/* Phy identifier (bPhyIdentifier) */ + + #define CSMI_SAS_USE_PORT_IDENTIFIER 0xFF + +-// Port identifier +-// (bPortIdentifier) ++/* Port identifier (bPortIdentifier) */ + + #define CSMI_SAS_IGNORE_PORT 0xFF + +-// Programmed link rates +-// (bConnectionRate) ++/* Programmed link rates (bConnectionRate) */ + + #define CSMI_SAS_LINK_RATE_NEGOTIATED 0x00 + #define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08 + #define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09 + +-// Connection status +-// (bConnectionStatus) ++/* Connection status (bConnectionStatus) */ + + #define CSMI_SAS_OPEN_ACCEPT 0 + #define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION 1 +@@ -814,8 +603,7 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY 11 + #define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION 12 + +-// SSP Status +-// (bSSPStatus) ++/* SSP Status (bSSPStatus)*/ + + #define CSMI_SAS_SSP_STATUS_UNKNOWN 0x00 + #define CSMI_SAS_SSP_STATUS_WAITING 0x01 +@@ -824,8 +612,7 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_SSP_STATUS_RETRY 0x04 + #define CSMI_SAS_SSP_STATUS_NO_TAG 0x05 + +-// SSP Flags +-// (uFlags) ++/* SSP Flags (uFlags) */ + + #define CSMI_SAS_SSP_READ 0x00000001 + #define CSMI_SAS_SSP_WRITE 0x00000002 +@@ -836,15 +623,13 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED 0x00000020 + #define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA 0x00000040 + +-// SSP Data present +-// (bDataPresent) ++/* SSP Data present (bDataPresent) */ + + #define CSMI_SAS_SSP_NO_DATA_PRESENT 0x00 + #define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT 0x01 + #define CSMI_SAS_SSP_SENSE_DATA_PRESENT 0x02 + +-// STP Flags +-// (uFlags) ++/* STP Flags (uFlags) */ + + #define CSMI_SAS_STP_READ 0x00000001 + #define CSMI_SAS_STP_WRITE 0x00000002 +@@ -856,15 +641,13 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_STP_EXECUTE_DIAG 0x00000100 + #define CSMI_SAS_STP_RESET_DEVICE 0x00000200 + +-// Task Management Flags +-// (uFlags) ++/* Task Management Flags (uFlags) */ + + #define CSMI_SAS_TASK_IU 0x00000001 + #define CSMI_SAS_HARD_RESET_SEQUENCE 0x00000002 + #define CSMI_SAS_SUPPRESS_RESULT 0x00000004 + +-// Task Management Functions +-// (bTaskManagement) ++/* Task Management Functions (bTaskManagement) */ + + #define CSMI_SAS_SSP_ABORT_TASK 0x01 + #define CSMI_SAS_SSP_ABORT_TASK_SET 0x02 +@@ -873,16 +656,14 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_SSP_CLEAR_ACA 0x40 + #define CSMI_SAS_SSP_QUERY_TASK 0x80 + +-// Task Management Information +-// (uInformation) ++/* Task Management Information (uInformation) */ + + #define CSMI_SAS_SSP_TEST 1 + #define CSMI_SAS_SSP_EXCEEDED 2 + #define CSMI_SAS_SSP_DEMAND 3 + #define CSMI_SAS_SSP_TRIGGER 4 + +-// Connector Pinout Information +-// (uPinout) ++/* Connector Pinout Information (uPinout) */ + + #define CSMI_SAS_CON_UNKNOWN 0x00000001 + #define CSMI_SAS_CON_SFF_8482 0x00000002 +@@ -895,10 +676,9 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_CON_SFF_8484_LANE_3 0x00040000 + #define CSMI_SAS_CON_SFF_8484_LANE_4 0x00080000 + +-// Connector Location Information +-// (bLocation) ++/* Connector Location Information (bLocation) */ + +-// same as uPinout above... ++/* same as uPinout above... */ + // #define CSMI_SAS_CON_UNKNOWN 0x01 + #define CSMI_SAS_CON_INTERNAL 0x02 + #define CSMI_SAS_CON_EXTERNAL 0x04 +@@ -907,15 +687,13 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_CON_NOT_PRESENT 0x20 + #define CSMI_SAS_CON_NOT_CONNECTED 0x80 + +-// Device location identification +-// (bIdentify) ++/* Device location identification (bIdentify) */ + + #define CSMI_SAS_LOCATE_UNKNOWN 0x00 + #define CSMI_SAS_LOCATE_FORCE_OFF 0x01 + #define CSMI_SAS_LOCATE_FORCE_ON 0x02 + +-// Location Valid flags +-// (uLocationFlags) ++/* Location Valid flags (uLocationFlags) */ + + #define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID 0x00000001 + #define CSMI_SAS_LOCATE_SAS_LUN_VALID 0x00000002 +@@ -927,48 +705,41 @@ typedef struct _IOCTL_HEADER { + + /* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */ + +-// Return codes for SAS Phy Control IOCTL's +-// (IoctlHeader.ReturnCode) ++/* Return codes for SAS Phy Control IOCTL's (IoctlHeader.ReturnCode) */ + +-// Signature value +-// (IoctlHeader.Signature) ++/* Signature value (IoctlHeader.Signature) */ + + #define CSMI_PHY_SIGNATURE "CSMIPHY" + +-// Phy Control Functions +-// (bFunction) ++/* Phy Control Functions (bFunction) */ + +-// values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL +-// function defined in the SAS spec ++/* values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL ++ function defined in the SAS spec */ + #define CSMI_SAS_PC_NOP 0x00000000 + #define CSMI_SAS_PC_LINK_RESET 0x00000001 + #define CSMI_SAS_PC_HARD_RESET 0x00000002 + #define CSMI_SAS_PC_PHY_DISABLE 0x00000003 +-// 0x04 to 0xFF reserved... ++/* 0x04 to 0xFF reserved... */ + #define CSMI_SAS_PC_GET_PHY_SETTINGS 0x00000100 + +-// Link Flags ++/* Link Flags */ + #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 + #define CSMI_SAS_PHY_UPDATE_SPINUP_RATE 0x00000002 + #define CSMI_SAS_PHY_AUTO_COMWAKE 0x00000004 + +-// Device Types for Phy Settings +-// (bType) ++/* Device Types for Phy Settings (bType) */ + #define CSMI_SAS_UNDEFINED 0x00 + #define CSMI_SAS_SATA 0x01 + #define CSMI_SAS_SAS 0x02 + +-// Transmitter Flags +-// (uTransmitterFlags) ++/* Transmitter Flags (uTransmitterFlags) */ + #define CSMI_SAS_PHY_PREEMPHASIS_DISABLED 0x00000001 + +-// Receiver Flags +-// (uReceiverFlags) ++/* Receiver Flags (uReceiverFlags) */ + #define CSMI_SAS_PHY_EQUALIZATION_DISABLED 0x00000001 + +-// Pattern Flags +-// (uPatternFlags) +-// #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 ++/* Pattern Flags (uPatternFlags) */ ++#define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 + #define CSMI_SAS_PHY_DISABLE_SCRAMBLING 0x00000002 + #define CSMI_SAS_PHY_DISABLE_ALIGN 0x00000004 + #define CSMI_SAS_PHY_DISABLE_SSC 0x00000008 +@@ -976,18 +747,16 @@ typedef struct _IOCTL_HEADER { + #define CSMI_SAS_PHY_FIXED_PATTERN 0x00000010 + #define CSMI_SAS_PHY_USER_PATTERN 0x00000020 + +-// Fixed Patterns +-// (bFixedPattern) ++/* Fixed Patterns (bFixedPattern) */ + #define CSMI_SAS_PHY_CJPAT 0x00000001 + #define CSMI_SAS_PHY_ALIGN 0x00000002 + +-// Type Flags +-// (bTypeFlags) ++/* Type Flags (bTypeFlags) */ + #define CSMI_SAS_PHY_POSITIVE_DISPARITY 0x01 + #define CSMI_SAS_PHY_NEGATIVE_DISPARITY 0x02 + #define CSMI_SAS_PHY_CONTROL_CHARACTER 0x04 + +-// Miscellaneous ++/* Miscellaneous */ + #define SLOT_NUMBER_UNKNOWN 0xFFFF + + /*************************************************************************/ +@@ -996,10 +765,9 @@ typedef struct _IOCTL_HEADER { + + /* * * * * * * * * * Class Independent Structures * * * * * * * * * */ + +-// EDM #pragma CSMI_SAS_BEGIN_PACK(8) + #pragma pack(8) + +-// CC_CSMI_SAS_DRIVER_INFO ++/* CC_CSMI_SAS_DRIVER_INFO */ + + typedef struct _CSMI_SAS_DRIVER_INFO { + __u8 szName[81]; +@@ -1019,7 +787,7 @@ typedef struct _CSMI_SAS_DRIVER_INFO_BUF + } CSMI_SAS_DRIVER_INFO_BUFFER, + *PCSMI_SAS_DRIVER_INFO_BUFFER; + +-// CC_CSMI_SAS_CNTLR_CONFIGURATION ++/* CC_CSMI_SAS_CNTLR_CONFIGURATION */ + + typedef struct _CSMI_SAS_PCI_BUS_ADDRESS { + __u8 bBusNumber; +@@ -1074,7 +842,7 @@ typedef struct _CSMI_SAS_CNTLR_CONFIG_BU + } CSMI_SAS_CNTLR_CONFIG_BUFFER, + *PCSMI_SAS_CNTLR_CONFIG_BUFFER; + +-// CC_CSMI_SAS_CNTLR_STATUS ++/* CC_CSMI_SAS_CNTLR_STATUS */ + + typedef struct _CSMI_SAS_CNTLR_STATUS { + __u32 uStatus; +@@ -1089,7 +857,7 @@ typedef struct _CSMI_SAS_CNTLR_STATUS_BU + } CSMI_SAS_CNTLR_STATUS_BUFFER, + *PCSMI_SAS_CNTLR_STATUS_BUFFER; + +-// CC_CSMI_SAS_FIRMWARE_DOWNLOAD ++/* CC_CSMI_SAS_FIRMWARE_DOWNLOAD */ + + typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD { + __u32 uBufferLength; +@@ -1107,7 +875,7 @@ typedef struct _CSMI_SAS_FIRMWARE_DOWNLO + } CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER, + *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER; + +-// CC_CSMI_SAS_RAID_INFO ++/* CC_CSMI_SAS_RAID_INFO */ + + typedef struct _CSMI_SAS_RAID_INFO { + __u32 uNumRaidSets; +@@ -1140,7 +908,7 @@ typedef struct _CSMI_SAS_RAID_INFO_BUFFE + } CSMI_SAS_RAID_INFO_BUFFER, + *PCSMI_SAS_RAID_INFO_BUFFER; + +-// CC_CSMI_SAS_GET_RAID_CONFIG ++/* CC_CSMI_SAS_GET_RAID_CONFIG */ + + typedef struct _CSMI_SAS_RAID_DRIVES { + __u8 bModel[40]; +@@ -1220,7 +988,7 @@ typedef struct _CSMI_SAS_RAID_CONFIG_BUF + } CSMI_SAS_RAID_CONFIG_BUFFER, + *PCSMI_SAS_RAID_CONFIG_BUFFER; + +-// CC_CSMI_SAS_GET_RAID_FEATURES ++/* CC_CSMI_SAS_GET_RAID_FEATURES */ + + typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION { + __u8 bRaidType; +@@ -1256,7 +1024,7 @@ typedef struct _CSMI_SAS_RAID_FEATURES_B + } CSMI_SAS_RAID_FEATURES_BUFFER, + *PCSMI_SAS_RAID_FEATURES_BUFFER; + +-// CC_CSMI_SAS_SET_RAID_CONTROL ++/* CC_CSMI_SAS_SET_RAID_CONTROL */ + + typedef struct _CSMI_SAS_RAID_CONTROL { + __u8 bTransformPriority; +@@ -1279,7 +1047,7 @@ typedef struct _CSMI_SAS_RAID_CONTROL_BU + } CSMI_SAS_RAID_CONTROL_BUFFER, + *PCSMI_SAS_RAID_CONTROL_BUFFER; + +-// CC_CSMI_SAS_GET_RAID_ELEMENT ++/* CC_CSMI_SAS_GET_RAID_ELEMENT */ + + typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO { + __u32 uDriveIndex; +@@ -1353,7 +1121,7 @@ typedef struct _CSMI_SAS_RAID_ELEMENT_BU + } CSMI_SAS_RAID_ELEMENT_BUFFER, + *PCSMI_SAS_RAID_ELEMENT_BUFFER; + +-// CC_CSMI_SAS_SET_RAID_OPERATION ++/* CC_CSMI_SAS_SET_RAID_OPERATION */ + + typedef struct _CSMI_SAS_RAID_SET_LIST { + __u32 uRaidSetIndex; +@@ -1503,7 +1271,7 @@ typedef struct _CSMI_SAS_RAID_SET_OPERAT + + /* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */ + +-// CC_CSMI_SAS_GET_PHY_INFO ++/* CC_CSMI_SAS_GET_PHY_INFO */ + + typedef struct _CSMI_SAS_IDENTIFY { + __u8 bDeviceType; +@@ -1545,7 +1313,7 @@ typedef struct _CSMI_SAS_PHY_INFO_BUFFER + } CSMI_SAS_PHY_INFO_BUFFER, + *PCSMI_SAS_PHY_INFO_BUFFER; + +-// CC_CSMI_SAS_SET_PHY_INFO ++/* CC_CSMI_SAS_SET_PHY_INFO */ + + typedef struct _CSMI_SAS_SET_PHY_INFO { + __u8 bPhyIdentifier; +@@ -1563,7 +1331,7 @@ typedef struct _CSMI_SAS_SET_PHY_INFO_BU + } CSMI_SAS_SET_PHY_INFO_BUFFER, + *PCSMI_SAS_SET_PHY_INFO_BUFFER; + +-// CC_CSMI_SAS_GET_LINK_ERRORS ++/* CC_CSMI_SAS_GET_LINK_ERRORS */ + + typedef struct _CSMI_SAS_LINK_ERRORS { + __u8 bPhyIdentifier; +@@ -1582,7 +1350,7 @@ typedef struct _CSMI_SAS_LINK_ERRORS_BUF + } CSMI_SAS_LINK_ERRORS_BUFFER, + *PCSMI_SAS_LINK_ERRORS_BUFFER; + +-// CC_CSMI_SAS_SMP_PASSTHRU ++/* CC_CSMI_SAS_SMP_PASSTHRU */ + + typedef struct _CSMI_SAS_SMP_REQUEST { + __u8 bFrameType; +@@ -1622,7 +1390,7 @@ typedef struct _CSMI_SAS_SMP_PASSTHRU_BU + } CSMI_SAS_SMP_PASSTHRU_BUFFER, + *PCSMI_SAS_SMP_PASSTHRU_BUFFER; + +-// CC_CSMI_SAS_SSP_PASSTHRU ++/* CC_CSMI_SAS_SSP_PASSTHRU */ + + typedef struct _CSMI_SAS_SSP_PASSTHRU { + __u8 bPhyIdentifier; +@@ -1661,7 +1429,7 @@ typedef struct _CSMI_SAS_SSP_PASSTHRU_BU + } CSMI_SAS_SSP_PASSTHRU_BUFFER, + *PCSMI_SAS_SSP_PASSTHRU_BUFFER; + +-// CC_CSMI_SAS_STP_PASSTHRU ++/* CC_CSMI_SAS_STP_PASSTHRU */ + + typedef struct _CSMI_SAS_STP_PASSTHRU { + __u8 bPhyIdentifier; +@@ -1693,7 +1461,7 @@ typedef struct _CSMI_SAS_STP_PASSTHRU_BU + } CSMI_SAS_STP_PASSTHRU_BUFFER, + *PCSMI_SAS_STP_PASSTHRU_BUFFER; + +-// CC_CSMI_SAS_GET_SATA_SIGNATURE ++/* CC_CSMI_SAS_GET_SATA_SIGNATURE */ + + typedef struct _CSMI_SAS_SATA_SIGNATURE { + __u8 bPhyIdentifier; +@@ -1708,7 +1476,7 @@ typedef struct _CSMI_SAS_SATA_SIGNATURE_ + } CSMI_SAS_SATA_SIGNATURE_BUFFER, + *PCSMI_SAS_SATA_SIGNATURE_BUFFER; + +-// CC_CSMI_SAS_GET_SCSI_ADDRESS ++/* CC_CSMI_SAS_GET_SCSI_ADDRESS */ + + typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER { + IOCTL_HEADER IoctlHeader; +@@ -1721,7 +1489,7 @@ typedef struct _CSMI_SAS_GET_SCSI_ADDRES + } CSMI_SAS_GET_SCSI_ADDRESS_BUFFER, + *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER; + +-// CC_CSMI_SAS_GET_DEVICE_ADDRESS ++/* CC_CSMI_SAS_GET_DEVICE_ADDRESS */ + + typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER { + IOCTL_HEADER IoctlHeader; +@@ -1734,7 +1502,7 @@ typedef struct _CSMI_SAS_GET_DEVICE_ADDR + } CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER, + *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER; + +-// CC_CSMI_SAS_TASK_MANAGEMENT ++/* CC_CSMI_SAS_TASK_MANAGEMENT */ + + typedef struct _CSMI_SAS_SSP_TASK_IU { + __u8 bHostIndex; +@@ -1757,7 +1525,7 @@ typedef struct _CSMI_SAS_SSP_TASK_IU_BUF + } CSMI_SAS_SSP_TASK_IU_BUFFER, + *PCSMI_SAS_SSP_TASK_IU_BUFFER; + +-// CC_CSMI_SAS_GET_CONNECTOR_INFO ++/* CC_CSMI_SAS_GET_CONNECTOR_INFO */ + + typedef struct _CSMI_SAS_GET_CONNECTOR_INFO { + __u32 uPinout; +@@ -1773,7 +1541,7 @@ typedef struct _CSMI_SAS_CONNECTOR_INFO_ + } CSMI_SAS_CONNECTOR_INFO_BUFFER, + *PCSMI_SAS_CONNECTOR_INFO_BUFFER; + +-// CC_CSMI_SAS_GET_LOCATION ++/* CC_CSMI_SAS_GET_LOCATION */ + + typedef struct _CSMI_SAS_LOCATION_IDENTIFIER { + __u32 bLocationFlags; +@@ -1801,7 +1569,7 @@ typedef struct _CSMI_SAS_GET_LOCATION_BU + } CSMI_SAS_GET_LOCATION_BUFFER, + *PCSMI_SAS_GET_LOCATION_BUFFER; + +-// CC_CSMI_SAS_PHY_CONTROL ++/* CC_CSMI_SAS_PHY_CONTROL */ + + typedef struct _CSMI_SAS_CHARACTER { + __u8 bTypeFlags; +@@ -1848,7 +1616,6 @@ typedef struct _CSMI_SAS_PHY_CONTROL_BUF + } CSMI_SAS_PHY_CONTROL_BUFFER, + *PCSMI_SAS_PHY_CONTROL_BUFFER; + +-//EDM #pragma CSMI_SAS_END_PACK + #pragma pack() + + #endif // _CSMI_SAS_H_ +Index: linux-2.6.27/drivers/message/fusion/lsi/mpi_cnfg.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/lsi/mpi_cnfg.h ++++ linux-2.6.27/drivers/message/fusion/lsi/mpi_cnfg.h +@@ -1452,8 +1452,7 @@ typedef struct _CONFIG_PAGE_BIOS_2 + #define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05) + #define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) + +-typedef struct _CONFIG_PAGE_BIOS_4 +-{ ++typedef struct _CONFIG_PAGE_BIOS_4 { + CONFIG_PAGE_HEADER Header; /* 00h */ + U64 ReassignmentBaseWWID; /* 04h */ + } CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4, +Index: linux-2.6.27/drivers/message/fusion/lsi/mpi_log_sas.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/lsi/mpi_log_sas.h ++++ linux-2.6.27/drivers/message/fusion/lsi/mpi_log_sas.h +@@ -160,11 +160,12 @@ + + + #define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200) ++ + #define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300) +-#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */ +- /* Bit 0 is Status Bit 0: FrameXferErr */ +- /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */ +- /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */ ++/* Bits 0-3 encode Transport Status Register (offset 0x08) */ ++/* Bit 0 is Status Bit 0: FrameXferErr */ ++/* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */ ++/* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */ + + #define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) + #define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) +@@ -179,7 +180,7 @@ + #define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01) + #define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00) + #define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000) +-#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000) /* not currently used in mainline */ ++#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000) + #define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK (0x00003000) + #define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP (0x00004000) + #define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000) +@@ -308,7 +309,6 @@ + /* Device Firmware Update: Unable to allocate memory for page */ + #define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE (0x00010056) + /* Device Firmware Update: */ +-//#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ (0x00010054) + + + /****************************************************************************/ +Index: linux-2.6.27/drivers/message/fusion/lsi/mpi_type.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/lsi/mpi_type.h ++++ linux-2.6.27/drivers/message/fusion/lsi/mpi_type.h +@@ -50,18 +50,8 @@ typedef signed short S16; + typedef unsigned short U16; + + +-#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc) +- +- typedef signed int S32; +- typedef unsigned int U32; +- +-#else +- +- typedef signed long S32; +- typedef unsigned long U32; +- +-#endif +- ++typedef int32_t S32; ++typedef u_int32_t U32; + + typedef struct _S64 + { +Index: linux-2.6.27/drivers/message/fusion/mptbase.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptbase.c ++++ linux-2.6.27/drivers/message/fusion/mptbase.c +@@ -83,15 +83,18 @@ MODULE_VERSION(my_VERSION); + + static int mpt_msi_enable_spi; + module_param(mpt_msi_enable_spi, int, 0); +-MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI controllers (default=0)"); ++MODULE_PARM_DESC(mpt_msi_enable_spi, ++ " Enable MSI Support for SPI controllers (default=0)"); + + static int mpt_msi_enable_fc; + module_param(mpt_msi_enable_fc, int, 0); +-MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC controllers (default=0)"); ++MODULE_PARM_DESC(mpt_msi_enable_fc, ++ " Enable MSI Support for FC controllers (default=0)"); + + static int mpt_msi_enable_sas = 1; + module_param(mpt_msi_enable_sas, int, 0); +-MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS controllers (default=1)"); ++MODULE_PARM_DESC(mpt_msi_enable_sas, ++ " Enable MSI Support for SAS controllers (default=1)"); + + + static int mpt_channel_mapping; +@@ -99,18 +102,20 @@ module_param(mpt_channel_mapping, int, 0 + MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); + + int mpt_debug_level; ++EXPORT_SYMBOL(mpt_debug_level); ++ + static int mpt_set_debug_level(const char *val, struct kernel_param *kp); + module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, + &mpt_debug_level, 0600); +-MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)"); +-EXPORT_SYMBOL(mpt_debug_level); ++MODULE_PARM_DESC(mpt_debug_level, ++ " debug level - refer to mptdebug.h - (default=0)"); + + int mpt_fwfault_debug; ++EXPORT_SYMBOL(mpt_fwfault_debug); + module_param_call(mpt_fwfault_debug, param_set_int, param_get_int, + &mpt_fwfault_debug, 0600); + MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault" + " and halt Firmware on fault - (default=0)"); +-EXPORT_SYMBOL(mpt_fwfault_debug); + + + #ifdef MFCNT +@@ -122,7 +127,7 @@ static int mfcounter = 0; + /* + * Public data... + */ +-struct proc_dir_entry *mpt_proc_root_dir; ++static struct proc_dir_entry *mpt_proc_root_dir; + + #define WHOINIT_UNKNOWN 0xAA + +@@ -156,7 +161,8 @@ static u8 last_drv_idx; + /* + * Forward protos... + */ +-static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); ++static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, ++ MPT_FRAME_HDR *reply); + static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, + u32 *req, int replyBytes, u16 *u16reply, int maxwait, + int sleepFlag); +@@ -188,7 +194,8 @@ static int mpt_readScsiDevicePageHeaders + static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); + static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); + static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); +-static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag); ++static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, ++ int sleepFlag); + static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); + static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); + static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); +@@ -353,10 +360,10 @@ mpt_fault_reset_work(struct work_struct + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", + ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + rc = mpt_HardResetHandler(ioc, CAN_SLEEP); + printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, +- __FUNCTION__, (rc == 0) ? "success" : "failed"); ++ __func__, (rc == 0) ? "success" : "failed"); + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " +@@ -378,11 +385,11 @@ mpt_fault_reset_work(struct work_struct + ioc = ioc->alt_ioc; + + /* rearm the timer */ +- spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); + if (ioc->reset_work_q) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); +- spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); + } + + /* +@@ -439,7 +446,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", +- __FUNCTION__, ioc->name, cb_idx); ++ __func__, ioc->name, cb_idx); + goto out; + } + +@@ -497,9 +504,6 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + mpt_sas_log_info(ioc, log_info); + } + +- /* TODO - add shost_attrs, or command line option, and +- * extend this to SAS/FC +- */ + if (ioc_stat & MPI_IOCSTATUS_MASK) + mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); + +@@ -507,7 +511,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", +- __FUNCTION__, ioc->name, cb_idx); ++ __func__, ioc->name, cb_idx); + freeme = 0; + goto out; + } +@@ -523,11 +527,11 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + mb(); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. + * @irq: irq number (not used) + * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure +- * @r: pt_regs pointer (not used) + * + * This routine is registered via the request_irq() kernel API call, + * and handles all interrupts generated from a specific MPT adapter +@@ -539,7 +543,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) + * This routine handles register-level access of the adapter but + * dispatches (calls) a protocol-specific callback routine to handle + * the protocol-specific details of the MPT request completion. +- **/ ++ */ + static irqreturn_t + mpt_interrupt(int irq, void *bus_id) + { +@@ -630,6 +634,7 @@ mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAM + return freereq; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_register - Register protocol-specific main callback handler. + * @cbfunc: callback function pointer +@@ -648,7 +653,7 @@ mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAM + * {N,...,7,6,5,...,1} if successful. + * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be + * considered an error by the caller. +- **/ ++ */ + u8 + mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) + { +@@ -672,13 +677,14 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DR + return last_drv_idx; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_deregister - Deregister a protocol drivers resources. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine when its + * module is unloaded. +- **/ ++ */ + void + mpt_deregister(u8 cb_idx) + { +@@ -691,9 +697,9 @@ mpt_deregister(u8 cb_idx) + } + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_event_register - Register protocol-specific event callback +- * handler. ++ * mpt_event_register - Register protocol-specific event callback handler. + * @cb_idx: previously registered (via mpt_register) callback handle + * @ev_cbfunc: callback function + * +@@ -701,7 +707,7 @@ mpt_deregister(u8 cb_idx) + * if/when they choose to be notified of MPT events. + * + * Returns 0 for success. +- **/ ++ */ + int + mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) + { +@@ -712,15 +718,15 @@ mpt_event_register(u8 cb_idx, MPT_EVHAND + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_event_deregister - Deregister protocol-specific event callback +- * handler. ++ * mpt_event_deregister - Deregister protocol-specific event callback handler. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine + * when it does not (or can no longer) handle events, + * or when its module is unloaded. +- **/ ++ */ + void + mpt_event_deregister(u8 cb_idx) + { +@@ -730,6 +736,7 @@ mpt_event_deregister(u8 cb_idx) + MptEvHandlers[cb_idx] = NULL; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_reset_register - Register protocol-specific IOC reset handler. + * @cb_idx: previously registered (via mpt_register) callback handle +@@ -739,7 +746,7 @@ mpt_event_deregister(u8 cb_idx) + * if/when they choose to be notified of IOC resets. + * + * Returns 0 for success. +- **/ ++ */ + int + mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) + { +@@ -750,6 +757,7 @@ mpt_reset_register(u8 cb_idx, MPT_RESETH + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. + * @cb_idx: previously registered callback handle +@@ -757,7 +765,7 @@ mpt_reset_register(u8 cb_idx, MPT_RESETH + * Each protocol-specific driver should call this routine + * when it does not (or can no longer) handle IOC reset handling, + * or when its module is unloaded. +- **/ ++ */ + void + mpt_reset_deregister(u8 cb_idx) + { +@@ -767,11 +775,12 @@ mpt_reset_deregister(u8 cb_idx) + MptResetHandlers[cb_idx] = NULL; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_device_driver_register - Register device driver hooks + * @dd_cbfunc: driver callbacks struct + * @cb_idx: MPT protocol driver index +- **/ ++ */ + int + mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) + { +@@ -785,8 +794,6 @@ mpt_device_driver_register(struct mpt_pc + + /* call per pci device probe entry point */ + list_for_each_entry(ioc, &ioc_list, list) { +- if (!pci_get_drvdata(ioc->pcidev)) +- continue; + id = ioc->pcidev->driver ? + ioc->pcidev->driver->id_table : NULL; + if (dd_cbfunc->probe) +@@ -796,10 +803,11 @@ mpt_device_driver_register(struct mpt_pc + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_device_driver_deregister - DeRegister device driver hooks + * @cb_idx: MPT protocol driver index +- **/ ++ */ + void + mpt_device_driver_deregister(u8 cb_idx) + { +@@ -819,15 +827,18 @@ mpt_device_driver_deregister(u8 cb_idx) + MptDeviceDriverHandlers[cb_idx] = NULL; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) +- * allocated per MPT adapter. ++ * mpt_get_msg_frame - Obtain an MPT request frame from the pool + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * ++ * Obtain an MPT request frame from the pool (of 1024) that are ++ * allocated per MPT adapter. ++ * + * Returns pointer to a MPT request frame or %NULL if none are available + * or IOC is not active. +- **/ ++ */ + MPT_FRAME_HDR* + mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) + { +@@ -886,16 +897,16 @@ mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER + return mf; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** +- * mpt_put_msg_frame - Send a protocol specific MPT request frame +- * to a IOC. ++ * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * @mf: Pointer to MPT request frame + * +- * This routine posts a MPT request frame to the request post FIFO of a ++ * This routine posts an MPT request frame to the request post FIFO of a + * specific MPT adapter. +- **/ ++ */ + void + mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) + { +@@ -921,13 +932,15 @@ mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER + } + + /** +- * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame +- * to a IOC using hi priority request queue. ++ * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame + * @cb_idx: Handle of registered MPT protocol driver + * @ioc: Pointer to MPT adapter structure + * @mf: Pointer to MPT request frame + * +- * This routine posts a MPT request frame to the request post FIFO of a ++ * Send a protocol-specific MPT request frame to an IOC using ++ * hi-priority request queue. ++ * ++ * This routine posts an MPT request frame to the request post FIFO of a + * specific MPT adapter. + **/ + void +@@ -952,6 +965,7 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ + CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_free_msg_frame - Place MPT request frame back on FreeQ. + * @handle: Handle of registered MPT protocol driver +@@ -960,7 +974,7 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. +- **/ ++ */ + void + mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) + { +@@ -970,7 +984,8 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) + goto out; +- mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); /* signature to know if this mf is freed */ ++ /* signature to know if this mf is freed */ ++ mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); + list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); + #ifdef MFCNT + ioc->mfcnt--; +@@ -1122,7 +1137,7 @@ mpt_add_chain_64bit(char *pAddr, u8 next + * request which are greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + int + mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) + { +@@ -1199,6 +1214,7 @@ mpt_send_handshake_request(u8 cb_idx, MP + return r; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_host_page_access_control - control the IOC's Host Page Buffer access + * @ioc: Pointer to MPT adapter structure +@@ -1215,7 +1231,7 @@ mpt_send_handshake_request(u8 cb_idx, MP + * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) + { +@@ -1240,6 +1256,7 @@ mpt_host_page_access_control(MPT_ADAPTER + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_host_page_alloc - allocate system memory for the fw + * @ioc: Pointer to pointer to IOC adapter +@@ -1247,7 +1264,7 @@ mpt_host_page_access_control(MPT_ADAPTER + * + * If we already allocated memory in past, then resend the same pointer. + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) + { +@@ -1305,6 +1322,7 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pI + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. + * @iocid: IOC unique identifier (integer) +@@ -1315,7 +1333,7 @@ return 0; + * + * Returns iocid and sets iocpp if iocid is found. + * Returns -1 if iocid is not found. +- **/ ++ */ + int + mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) + { +@@ -1604,7 +1622,8 @@ mpt_mapresources(MPT_ADAPTER *ioc) + return r; + } + if (sizeof(dma_addr_t) > 4) { +- const uint64_t required_mask = dma_get_required_mask(&pdev->dev); ++ uint64_t required_mask; ++ required_mask = dma_get_required_mask(&pdev->dev); + if (required_mask > DMA_32BIT_MASK + && !pci_set_dma_mask(pdev, DMA_64BIT_MASK) + && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { +@@ -1674,15 +1693,13 @@ mpt_mapresources(MPT_ADAPTER *ioc) + ioc->chip = (SYSIF_REGS __iomem *)mem; + + /* Save Port IO values in case we need to do downloadboot */ +- { +- u8 *pmem = (u8*)port; +- ioc->pio_mem_phys = port; +- ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; +- } ++ ioc->pio_mem_phys = port; ++ ioc->pio_chip = (SYSIF_REGS __iomem *)port; + + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_attach - Install a PCI intelligent MPT adapter. + * @pdev: Pointer to pci_dev structure +@@ -1698,8 +1715,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) + * + * Returns 0 for success, non-zero for failure. + * +- * TODO: Add support for polled controllers +- **/ ++ */ + int + mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) + { +@@ -1795,6 +1811,7 @@ mpt_attach(struct pci_dev *pdev, const s + + /* Initialize work */ + INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); ++ spin_lock_init(&ioc->fault_reset_work_lock); + + /* Initialize workqueue */ + snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name), +@@ -1809,7 +1826,8 @@ mpt_attach(struct pci_dev *pdev, const s + return -ENOMEM; + } + +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts @ %p, pfacts[0] @ %p\n", ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts @ %p," ++ " pfacts[0] @ %p\n", + ioc->name, &ioc->facts, &ioc->pfacts[0])); + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); +@@ -1911,6 +1929,9 @@ mpt_attach(struct pci_dev *pdev, const s + ioc->active = 0; + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + ++ /* Set IOC ptr in the pcidev's driver data. */ ++ pci_set_drvdata(ioc->pcidev, ioc); ++ + /* Set lookup ptr. */ + list_add_tail(&ioc->list, &ioc_list); + +@@ -1979,10 +2000,11 @@ mpt_attach(struct pci_dev *pdev, const s + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_detach - Remove a PCI intelligent MPT adapter. + * @pdev: Pointer to pci_dev structure +- **/ ++ */ + void + mpt_detach(struct pci_dev *pdev) + { +@@ -1995,10 +2017,10 @@ mpt_detach(struct pci_dev *pdev) + /* + * Stop polling ioc for fault condition + */ +- spin_lock_irqsave(&ioc->taskmgmt_lock, flags); ++ spin_lock_irqsave(&ioc->fault_reset_work_lock, flags); + wq = ioc->reset_work_q; + ioc->reset_work_q = NULL; +- spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); ++ spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags); + cancel_delayed_work(&ioc->fault_reset_work); + destroy_workqueue(wq); + +@@ -2030,11 +2052,12 @@ mpt_detach(struct pci_dev *pdev) + * Power Management + */ + #ifdef CONFIG_PM ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_suspend - Fusion MPT base driver suspend routine. + * @pdev: Pointer to pci_dev structure + * @state: new state to enter +- **/ ++ */ + int + mpt_suspend(struct pci_dev *pdev, pm_message_t state) + { +@@ -2069,10 +2092,11 @@ mpt_suspend(struct pci_dev *pdev, pm_mes + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_resume - Fusion MPT base driver resume routine. + * @pdev: Pointer to pci_dev structure +- **/ ++ */ + int + mpt_resume(struct pci_dev *pdev) + { +@@ -2132,7 +2156,9 @@ mpt_resume(struct pci_dev *pdev) + + /* bring ioc to operational state */ + printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); +- if ((recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) ++ recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, ++ CAN_SLEEP); ++ if (recovery_state != 0) + printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " + "error:[%x]\n", ioc->name, recovery_state); + else +@@ -2158,6 +2184,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER * + return (MptResetHandlers[index])(ioc, reset_phase); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_do_ioc_recovery - Initialize or recover MPT adapter. + * @ioc: Pointer to MPT adapter structure +@@ -2176,7 +2203,9 @@ mpt_signal_reset(u8 index, MPT_ADAPTER * + * -2 if READY but IOCFacts Failed + * -3 if READY but PrimeIOCFifos Failed + * -4 if READY but IOCInit Failed +- **/ ++ * -5 if failed to enable_device and/or request_selected_regions ++ * -6 if failed to upload firmware ++ */ + static int + mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) + { +@@ -2217,14 +2246,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": alt-ioc reply irq re-enabled\n", ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ ": alt-ioc reply irq re-enabled\n", + ioc->alt_ioc->name)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); + ioc->alt_ioc->active = 1; + } + + } else { +- printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ioc->name); ++ printk(MYIOC_s_WARN_FMT "NOT READY WARNING!\n", ++ ioc->name); + } + ret = -1; + goto out; +@@ -2238,7 +2269,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + alt_ioc_ready = 1; + else + printk(MYIOC_s_WARN_FMT +- ": alt-ioc Not ready WARNING!\n", ioc->alt_ioc->name); ++ ": alt-ioc Not ready WARNING!\n", ++ ioc->alt_ioc->name); + } + + for (ii=0; ii<5; ii++) { +@@ -2340,8 +2372,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + ret = -4; + // NEW! + if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { +- printk(MYIOC_s_WARN_FMT ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", +- ioc->alt_ioc->name, rc); ++ printk(MYIOC_s_WARN_FMT ++ ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", ++ ioc->alt_ioc->name, rc); + alt_ioc_ready = 0; + reset_alt_ioc_active = 0; + } +@@ -2382,7 +2415,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + } else { + printk(MYIOC_s_WARN_FMT + "firmware upload failure!\n", ioc->name); +- ret = -5; ++ ret = -6; + } + } + } +@@ -2392,8 +2425,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + * and EventAck handling. + */ + if ((ret == 0) && (!ioc->facts.EventState)) { +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendEventNotification\n", +- ioc->name)); ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "SendEventNotification\n", ioc->name)); + ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ + } + +@@ -2408,9 +2441,11 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + if (rc == 0) { /* alt ioc */ + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt) */ +- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc reply irq re-enabled\n", ++ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "alt-ioc reply irq re-enabled\n", + ioc->alt_ioc->name)); +- CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ++ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ++ MPI_HIM_DIM); + ioc->alt_ioc->active = 1; + } + } +@@ -2427,7 +2462,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + /* + * Initalize link list for inactive raid volumes. + */ +- init_MUTEX(&ioc->raid_data.inactive_list_mutex); ++ mutex_init(&ioc->raid_data.inactive_list_mutex); + INIT_LIST_HEAD(&ioc->raid_data.inactive_list); + + switch (ioc->bus_type) { +@@ -2461,7 +2496,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + * (LANPage1_t stuff) + */ + (void) GetLanConfigPages(ioc); +- a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; ++ a = (u8 *) ++ &ioc->lan_cnfg_page1.HardwareAddressLow; + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "LanAddr = %02X:%02X:%02X" + ":%02X:%02X:%02X\n", +@@ -2507,6 +2543,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + return ret; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_detect_bound_ports - Search for matching PCI bus/dev_function + * @ioc: Pointer to MPT adapter structure +@@ -2518,7 +2555,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 + * + * If match on PCI dev_function +/-1 is found, bind the two MPT adapters + * using alt_ioc pointer fields in their %MPT_ADAPTER structures. +- **/ ++ */ + static void + mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) + { +@@ -2544,15 +2581,19 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, + if (_pcidev == peer) { + /* Paranoia checks */ + if (ioc->alt_ioc != NULL) { +- printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n", +- ioc->name, ioc->name, ioc->alt_ioc->name); ++ printk(MYIOC_s_WARN_FMT ++ "Oops, already bound (%s <==> %s)!\n", ++ ioc->name, ioc->name, ioc->alt_ioc->name); + break; + } else if (ioc_srch->alt_ioc != NULL) { +- printk(MYIOC_s_WARN_FMT "Oops, already bound (%s <==> %s)!\n", +- ioc_srch->name, ioc_srch->name, ioc_srch->alt_ioc->name); ++ printk(MYIOC_s_WARN_FMT ++ "Oops, already bound (%s <==> %s)!\n", ++ ioc_srch->name, ioc_srch->name, ++ ioc_srch->alt_ioc->name); + break; + } +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FOUND! binding %s <==> %s\n", ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "FOUND! binding %s <==> %s\n", + ioc->name, ioc->name, ioc_srch->name)); + ioc_srch->alt_ioc = ioc; + ioc->alt_ioc = ioc_srch; +@@ -2561,10 +2602,11 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, + pci_dev_put(peer); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_adapter_disable - Disable misbehaving MPT adapter. + * @ioc: Pointer to MPT adapter structure +- **/ ++ */ + static void + mpt_adapter_disable(MPT_ADAPTER *ioc) + { +@@ -2577,7 +2619,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) + ioc->cached_fw, CAN_SLEEP)) < 0) { + printk(MYIOC_s_WARN_FMT +- ": firmware downloadboot failure (%d)!\n", ioc->name, ret); ++ ": firmware downloadboot failure (%d)!\n", ++ ioc->name, ret); + } + } + +@@ -2585,15 +2628,15 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + * Put the controller into ready state (if its not already) + */ + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { +- if(!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, ++ if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, + CAN_SLEEP)) { + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " + "reset failed to put ioc in ready state!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + } else + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " +- "failed!\n", ioc->name, __FUNCTION__); ++ "failed!\n", ioc->name, __func__); + } + + /* Disable adapter interrupts! */ +@@ -2607,8 +2650,9 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; +- dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free @ %p, sz=%d bytes\n", +- ioc->name, ioc->alloc, ioc->alloc_sz)); ++ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "free @ %p, sz=%d bytes\n", ioc->name, ++ ioc->alloc, ioc->alloc_sz)); + pci_free_consistent(ioc->pcidev, sz, + ioc->alloc, ioc->alloc_dma); + ioc->reply_frames = NULL; +@@ -2666,10 +2710,11 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { + printk(MYIOC_s_ERR_FMT + ": %s: host page buffers free failed (%d)!\n", +- ioc->name, __FUNCTION__, ret); ++ ioc->name, __func__, ret); + } +- dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", +- ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); ++ dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "HostPageBuffer free @ %p, sz=%d bytes\n", ioc->name, ++ ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); + pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, + ioc->HostPageBuffer, + ioc->HostPageBuffer_dma); +@@ -2681,13 +2726,14 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) + pci_set_drvdata(ioc->pcidev, NULL); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_adapter_dispose - Free all resources associated with an MPT adapter + * @ioc: Pointer to MPT adapter structure + * + * This routine unregisters h/w resources and frees all alloc'd memory + * associated with a MPT adapter structure. +- **/ ++ */ + static void + mpt_adapter_dispose(MPT_ADAPTER *ioc) + { +@@ -2718,7 +2764,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) + #if defined(CONFIG_MTRR) && 0 + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); +- dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region de-registered\n", ioc->name)); ++ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "MTRR region de-registered\n", ioc->name)); + } + #endif + +@@ -2727,7 +2774,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) + + sz_last = ioc->alloc_total; + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free'd %d of %d bytes\n", +- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); ++ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), ++ sz_first)); + + if (ioc->alt_ioc) + ioc->alt_ioc->alt_ioc = NULL; +@@ -2735,10 +2783,11 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) + kfree(ioc); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * MptDisplayIocCapabilities - Disply IOC's capabilities. + * @ioc: Pointer to MPT adapter structure +- **/ ++ */ + static void + MptDisplayIocCapabilities(MPT_ADAPTER *ioc) + { +@@ -2777,6 +2826,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i + printk("}\n"); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * MakeIocReady - Get IOC to a READY state, using KickStart if needed. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2790,7 +2840,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *i + * -2 - Msg Unit Reset Failed + * -3 - IO Unit Reset Failed + * -4 - IOC owned by a PEER +- **/ ++ */ + static int + MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) + { +@@ -2804,7 +2854,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + + /* Get current [raw] IOC state */ + ioc_state = mpt_GetIocState(ioc, 0); +- dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state)); ++ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "MakeIocReady, [raw] state=%08x\n", ioc->name, ioc_state)); + + /* + * Check to see if IOC got left/stuck in doorbell handshake +@@ -2817,8 +2868,10 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + } + + /* Is it already READY? */ +- if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) { +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "IOC is in READY state\n", ++ if (!statefault && ++ (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) { ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "IOC is in READY state\n", + ioc->name)); + return 0; + } +@@ -2894,8 +2947,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + + ii++; cntdn--; + if (!cntdn) { +- printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n", +- ioc->name, ioc_state, (int)((ii+5)/HZ)); ++ printk(MYIOC_s_ERR_FMT ++ "Wait IOC_READY state (0x%x) timeout(%d)!\n", ++ ioc->name, ioc_state, (int)((ii+5)/HZ)); + return -ETIME; + } + +@@ -2916,6 +2970,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + return hard_reset_done; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_GetIocState - Get the current state of a MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2923,7 +2978,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force + * + * Returns all IOC Doorbell register bits if cooked==0, else just the + * Doorbell bits in MPI_IOC_STATE_MASK. +- **/ ++ */ + u32 + mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) + { +@@ -2939,6 +2994,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co + return cooked ? sc : s; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetIocFacts - Send IOCFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -2946,7 +3002,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int co + * @reason: If recovery, only update facts. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) + { +@@ -2961,9 +3017,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { +- printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", +- ioc->name, +- ioc->last_state ); ++ printk(KERN_ERR MYNAM ++ ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", ++ ioc->name, ioc->last_state); + return -44; + } + +@@ -3011,7 +3067,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + + facts->MsgVersion = le16_to_cpu(facts->MsgVersion); + if (facts->MsgVersion == MPI_VERSION_01_05) +- facts->HeaderVersion = le16_to_cpu(facts->HeaderVersion); ++ facts->HeaderVersion = ++ le16_to_cpu(facts->HeaderVersion); + facts->MsgContext = le32_to_cpu(facts->MsgContext); + facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); + facts->IOCStatus = le16_to_cpu(facts->IOCStatus); +@@ -3120,6 +3177,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetPortFacts - Send PortFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3127,7 +3185,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF + * @sleepFlag: Specifies whether the process can sleep + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) + { +@@ -3141,7 +3199,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { + printk(MYIOC_s_ERR_FMT "Can't get PortFacts, " +- " NOT READY! (%08x)\n", ioc->name, ioc->last_state ); ++ " NOT READY! (%08x)\n", ioc->name, ioc->last_state); + return -4; + } + +@@ -3159,14 +3217,14 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + get_pfacts.PortNumber = portnum; + /* Assert: All other get_pfacts fields are zero! */ + +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", +- ioc->name, portnum)); ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "Sending get PortFacts(%d) request\n", ioc->name, portnum)); + + /* No non-zero fields in the get_pfacts request are greater than + * 1 byte in size, so we can just fire it off as is. + */ + ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, +- reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); ++ reply_sz, (u16 *)pfacts, 5 /*seconds*/, sleepFlag); + if (ii != 0) + return ii; + +@@ -3201,6 +3259,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendIocInit - Send IOCInit request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3209,7 +3268,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn + * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) + { +@@ -3323,6 +3382,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF + return r; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendPortEnable - Send PortEnable request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3332,7 +3392,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF + * Send PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) + { +@@ -3355,18 +3415,19 @@ SendPortEnable(MPT_ADAPTER *ioc, int por + /* port_enable.MsgFlags = 0; */ + /* port_enable.MsgContext = 0; */ + +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", +- ioc->name, portnum, &port_enable)); ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "Sending Port(%d)Enable (req @ %p)\n", ioc->name, ++ portnum, &port_enable)); + + /* RAID FW may take a long time to enable + */ + if (ioc->ir_firmware || ioc->bus_type == SAS) { + rc = mpt_handshake_req_reply_wait(ioc, req_sz, +- (u32*)&port_enable, reply_sz, (u16*)&reply_buf, ++ (u32 *)&port_enable, reply_sz, (u16 *)&reply_buf, + 300 /*seconds*/, sleepFlag); + } else { + rc = mpt_handshake_req_reply_wait(ioc, req_sz, +- (u32*)&port_enable, reply_sz, (u16*)&reply_buf, ++ (u32 *)&port_enable, reply_sz, (u16 *)&reply_buf, + 30 /*seconds*/, sleepFlag); + } + return rc; +@@ -3435,6 +3496,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) + ioc->cached_fw = NULL; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3447,7 +3509,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) + * on the bound IOC, the second image is discarded + * and memory is free'd. Both channels must upload to prevent + * IOC from running in degraded mode. +- **/ ++ */ + static int + mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) + { +@@ -3499,8 +3561,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + ioc->facts.FWImageSize, request_size)); + DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); + +- ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32*)prequest, +- reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); ++ ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, ++ reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag); + + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " + "rc=%x \n", ioc->name, ii)); +@@ -3512,10 +3574,10 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + */ + int status; + status = le16_to_cpu(preply->IOCStatus) & +- MPI_IOCSTATUS_MASK; ++ MPI_IOCSTATUS_MASK; + if (status == MPI_IOCSTATUS_SUCCESS && + ioc->facts.FWImageSize == +- le32_to_cpu(preply->ActualImageSize)); ++ le32_to_cpu(preply->ActualImageSize)) + cmdStatus = 0; + } + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "do_upload cmdStatus=%d \n", +@@ -3532,6 +3594,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + return cmdStatus; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_downloadboot - DownloadBoot code + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3544,7 +3607,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee + * -1 FW Image size is 0 + * -2 No valid cached_fw Pointer + * <0 for fw upload failure. +- **/ ++ */ + static int + mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) + { +@@ -3648,13 +3711,15 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + } + + /* Write the IopResetVectorRegAddr */ +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", +- ioc->name, pFwHeader->IopResetRegAddr)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Write IopResetVector Addr=%x!\n", ioc->name, ++ pFwHeader->IopResetRegAddr)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); + + /* Write the IopResetVectorValue */ +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", +- ioc->name, pFwHeader->IopResetVectorValue)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Write IopResetVector Value=%x!\n", ioc->name, ++ pFwHeader->IopResetVectorValue)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); + + /* Clear the internal flash bad bit - autoincrementing register, +@@ -3684,7 +3749,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + ioc->name, diag0val)); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + +- if (ioc->bus_type == SAS ) { ++ if (ioc->bus_type == SAS) { + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) + msleep(1000); +@@ -3692,7 +3757,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + mdelay(1000); + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); +- ddlprintk(ioc, printk (MYIOC_s_DEBUG_FMT ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "diag0val=%x, turning off RW_ENABLE\n", ioc->name, + diag0val)); + diag0val &= ~(MPI_DIAG_RW_ENABLE); +@@ -3715,8 +3780,9 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + /* Write 0xFF to reset the sequencer */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + +- for (count = 0; count < 30; count ++) { +- doorbell = CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_IOC_STATE_MASK; ++ for (count = 0; count < 30; count++) { ++ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell) ++ & MPI_IOC_STATE_MASK; + if (doorbell == MPI_IOC_STATE_READY) { + if (ioc->bus_type == SAS) + return 0; +@@ -3729,17 +3795,20 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + "SendIocInit successful\n", ioc->name)); + return 0; + } +- ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "looking for READY STATE:" +- " doorbell=%x count=%d\n", ioc->name, doorbell, count)); ++ ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "looking for READY STATE: doorbell=%x count=%d\n", ++ ioc->name, doorbell, count)); + if (sleepFlag == CAN_SLEEP) + msleep(1000); + else + mdelay(1000); + } +- ddlprintk(ioc, printk(MYIOC_s_WARN_FMT "downloadboot failed! count=%d\n", ioc->name, count)); ++ ddlprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "downloadboot failed! count=%d\n", ioc->name, count)); + return -EFAULT; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * KickStart - Perform hard reset of MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3764,7 +3833,7 @@ mpt_downloadboot(MPT_ADAPTER *ioc, MpiFw + * OR reset but failed to come READY + * -2 - no reset, could not enter DIAG mode + * -3 - reset but bad FW bit +- **/ ++ */ + static int + KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) + { +@@ -3790,16 +3859,20 @@ KickStart(MPT_ADAPTER *ioc, int force, i + if (hard_reset_done < 0) + return hard_reset_done; + +- /* may not have worked but hard_reset_done doesn't always signal failure */ +- dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "Diagnostic reset completed!\n", +- ioc->name)); ++ /* may not have worked but hard_reset_done ++ * doesn't always signal failure ++ */ ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "Diagnostic reset completed!\n", ioc->name)); + + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ + for (cnt=0; cntname, cnt)); ++ if ((ioc_state == MPI_IOC_STATE_READY) || ++ (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { ++ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ++ "KickStart successful! (cnt=%d)\n", ioc->name, ++ cnt)); + return hard_reset_done; + } + if (sleepFlag == CAN_SLEEP) { +@@ -3814,6 +3887,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i + return -1; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_diag_reset - Perform hard reset of the adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -3831,7 +3905,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i + * 0 no reset performed because reset history bit set + * -2 enabling diagnostic mode failed + * -3 diagnostic reset failed +- **/ ++ */ + static int + mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) + { +@@ -3852,7 +3926,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + return 0; + + drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " +- "address=%p\n", ioc->name, __FUNCTION__, &ioc->chip->Doorbell, ++ "address=%p\n", ioc->name, __func__, &ioc->chip->Doorbell, + &ioc->chip->Reset_1078)); + CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); + if (sleepFlag == CAN_SLEEP) +@@ -3868,7 +3942,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) +- (*(MptResetHandlers[cb_idx]))(ioc, MPT_IOC_PRE_RESET); ++ (*(MptResetHandlers[cb_idx])) ++ (ioc, MPT_IOC_PRE_RESET); + } + + for (count = 0; count < 60; count ++) { +@@ -3907,8 +3982,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) +- diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", ++ diag1val = ++ CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "DbG1: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } + +@@ -3943,14 +4020,16 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", +- ioc->name, diag0val)); ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Wrote magic DiagWriteEn sequence (%x)\n", ++ ioc->name, diag0val)); + } + + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "DbG2: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } + /* +@@ -3966,8 +4045,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + */ + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); + hard_reset_done = 1; +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", +- ioc->name)); ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "Diagnostic reset performed\n", ioc->name)); + + /* + * Call each currently registered protocol IOC reset handler +@@ -3977,10 +4056,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { +- mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); +- if (ioc->alt_ioc) { +- mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); +- } ++ mpt_signal_reset(cb_idx, ioc, ++ MPT_IOC_PRE_RESET); ++ if (ioc->alt_ioc) ++ mpt_signal_reset(cb_idx, ++ ioc->alt_ioc, MPT_IOC_PRE_RESET); + } + } + +@@ -4001,7 +4081,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + break; + } + +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "cached_fw: diag0val=%x count=%d\n", + ioc->name, diag0val, count)); + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) +@@ -4055,7 +4136,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "DbG3: diag0=%08x, diag1=%08x\n", + ioc->name, diag0val, diag1val)); + } + +@@ -4113,8 +4195,9 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + if (ioc->debug_level & MPT_DEBUG_RESET) { + if (ioc->alt_ioc) + diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); +- drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", +- ioc->name, diag0val, diag1val)); ++ drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "DbG4: diag0=%08x, diag1=%08x\n", ++ ioc->name, diag0val, diag1val)); + } + + /* +@@ -4128,6 +4211,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + return hard_reset_done; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendIocReset - Send IOCReset request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4138,7 +4222,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign + * Send IOCReset request to the MPT adapter. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) + { +@@ -4164,8 +4248,9 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ + if (sleepFlag != CAN_SLEEP) + count *= 10; + +- printk(MYIOC_s_ERR_FMT "Wait IOC_READY state (0x%x) timeout(%d)!\n", +- ioc->name, state, (int)((count+5)/HZ)); ++ printk(MYIOC_s_ERR_FMT ++ "Wait IOC_READY state (0x%x) timeout(%d)!\n", ++ ioc->name, state, (int)((count+5)/HZ)); + return -ETIME; + } + +@@ -4176,23 +4261,20 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ + } + } + +- /* TODO! +- * Cleanup all event stuff for this IOC; re-issue EventNotification +- * request if needed. +- */ + if (ioc->facts.Function) + ioc->facts.EventState = 0; + + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * initChainBuffers - Allocate memory for and initialize chain buffers + * @ioc: Pointer to MPT_ADAPTER structure + * + * Allocates memory for and initializes chain buffers, + * chain buffer control arrays and spinlock. +- **/ ++ */ + static int + initChainBuffers(MPT_ADAPTER *ioc) + { +@@ -4234,11 +4316,11 @@ initChainBuffers(MPT_ADAPTER *ioc) + * num_sge = num sge in request frame + last chain buffer + * scale = num sge per chain buffer if no chain element + */ +- scale = ioc->req_sz/ ioc->SGE_size; ++ scale = ioc->req_sz / ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) + num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; + else +- num_sge = 1+ scale + (ioc->req_sz - 64) / ioc->SGE_size; ++ num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size; + + if (ioc->sg_addr_size == sizeof(u64)) { + numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + +@@ -4253,8 +4335,7 @@ initChainBuffers(MPT_ADAPTER *ioc) + if (ioc->bus_type == FC) { + if (numSGE > MPT_SCSI_FC_SG_DEPTH) + numSGE = MPT_SCSI_FC_SG_DEPTH; +- } +- else { ++ } else { + if (numSGE > MPT_SCSI_SG_DEPTH) + numSGE = MPT_SCSI_SG_DEPTH; + } +@@ -4292,6 +4373,7 @@ initChainBuffers(MPT_ADAPTER *ioc) + return num_chain; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4301,7 +4383,7 @@ initChainBuffers(MPT_ADAPTER *ioc) + * reply frames. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + PrimeIocFifos(MPT_ADAPTER *ioc) + { +@@ -4513,6 +4595,7 @@ out_fail: + return -1; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_handshake_req_reply_wait - Send MPT request to and receive reply + * from IOC via doorbell handshake method. +@@ -4530,7 +4613,7 @@ out_fail: + * greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, + int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) +@@ -4624,6 +4707,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER + return -failcnt; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4635,7 +4719,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER + * bit in its IntStatus register being clear. + * + * Returns a negative value on failure, else wait loop count. +- **/ ++ */ + static int + WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) + { +@@ -4674,6 +4758,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int + return -1; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4684,7 +4769,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int + * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. + * + * Returns a negative value on failure, else wait loop count. +- **/ ++ */ + static int + WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) + { +@@ -4703,7 +4788,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int + } + } else { + while (--cntdn) { +- udelay (1000); ++ udelay(1000); + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; +@@ -4722,6 +4807,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int + return -1; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4733,7 +4819,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int + * of 128 bytes of reply data. + * + * Returns a negative value on failure, else size of reply in WORDS. +- **/ ++ */ + static int + WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) + { +@@ -4807,6 +4893,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i + return u16cnt/2; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetLanConfigPages - Fetch LANConfig pages. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4816,7 +4903,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) +- **/ ++ */ + static int + GetLanConfigPages(MPT_ADAPTER *ioc) + { +@@ -4863,10 +4950,6 @@ GetLanConfigPages(MPT_ADAPTER *ioc) + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); + +- /* FIXME! +- * Normalize endianness of structure data, +- * by byte-swapping all > 1 byte fields! +- */ + + } + +@@ -4907,16 +4990,12 @@ GetLanConfigPages(MPT_ADAPTER *ioc) + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma); + +- /* FIXME! +- * Normalize endianness of structure data, +- * by byte-swapping all > 1 byte fields! +- */ +- + } + + return rc; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table + * @ioc: Pointer to MPT_ADAPTER structure +@@ -4929,7 +5008,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) + * NOTE: Don't use not this function during interrupt time. + * + * Returns 0 for success, non-zero error +- **/ ++ */ + int + mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) + { +@@ -4958,12 +5037,12 @@ mptbase_sas_persist_operation(MPT_ADAPTE + goto out; + } + +- printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); ++ printk("%s: persist_opcode=%x\n",__func__, persist_opcode); + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { +- printk("%s: no msg frames!\n",__FUNCTION__); ++ printk("%s: no msg frames!\n",__func__); + ret = -1; + goto out; + } +@@ -4979,12 +5058,12 @@ mptbase_sas_persist_operation(MPT_ADAPTE + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; +- printk("%s: failed\n", __FUNCTION__); ++ printk(KERN_WARNING "%s: failed\n", __func__); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); +@@ -5000,12 +5079,13 @@ mptbase_sas_persist_operation(MPT_ADAPTE + sasIoUnitCntrReply = + (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; + if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { +- printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", __FUNCTION__, +- sasIoUnitCntrReply->IOCStatus, sasIoUnitCntrReply->IOCLogInfo); +- printk("%s: failed\n",__FUNCTION__); ++ printk(KERN_WARNING "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", ++ __func__, sasIoUnitCntrReply->IOCStatus, ++ sasIoUnitCntrReply->IOCLogInfo); ++ printk(KERN_WARNING "%s: failed\n", __func__); + ret = -1; + } else +- printk("%s: success\n",__FUNCTION__); ++ printk(KERN_INFO "%s: success\n", __func__); + out: + + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) +@@ -5013,6 +5093,8 @@ mptbase_sas_persist_operation(MPT_ADAPTE + return ret; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ ++ + static void + mptbase_raid_process_event_data(MPT_ADAPTER *ioc, + MpiEventDataRaid_t * pRaidEventData) +@@ -5143,6 +5225,7 @@ mptbase_raid_process_event_data(MPT_ADAP + } + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * GetIoUnitPage2 - Retrieve BIOS version and boot order information. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -5152,7 +5235,7 @@ mptbase_raid_process_event_data(MPT_ADAP + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) +- **/ ++ */ + static int + GetIoUnitPage2(MPT_ADAPTER *ioc) + { +@@ -5200,6 +5283,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) + return rc; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 + * @ioc: Pointer to a Adapter Strucutre +@@ -5219,7 +5303,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) + * Both valid + * Return 0 + * CHECK - what type of locking mechanisms should be used???? +- **/ ++ */ + static int + mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) + { +@@ -5290,7 +5374,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { + ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "noQas due to Capabilities=%x\n", ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "noQas due to Capabilities=%x\n", + ioc->name, pPP0->Capabilities)); + } + ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; +@@ -5299,7 +5384,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + ioc->spi_data.maxSyncOffset = (u8) (data >> 16); + data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; + ioc->spi_data.minSyncFactor = (u8) (data >> 8); +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PortPage0 minSyncFactor=%x\n", ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); + } else { + ioc->spi_data.maxSyncOffset = 0; +@@ -5315,7 +5401,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + + if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { + ioc->spi_data.minSyncFactor = MPT_ULTRA; +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HVD or SE detected, minSyncFactor=%x\n", ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "HVD or SE detected, minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); + } + } +@@ -5420,6 +5507,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + return rc; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_readScsiDevicePageHeaders - save version and length of SDP1 + * @ioc: Pointer to a Adapter Strucutre +@@ -5427,7 +5515,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc + * + * Return: -EFAULT if read of config page header fails + * or 0 if success. +- **/ ++ */ + static int + mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) + { +@@ -5475,7 +5563,7 @@ mpt_read_ioc_pg_6(MPT_ADAPTER *ioc) + { + CONFIGPARMS cfg; + ConfigPageHeader_t header; +- IOCPage6_t *pIoc6=NULL; ++ IOCPage6_t *pIoc6 = NULL; + dma_addr_t ioc6_dma; + int iocpage6sz; + void *mem; +@@ -5546,13 +5634,13 @@ mpt_inactive_raid_list_free(MPT_ADAPTER + if (list_empty(&ioc->raid_data.inactive_list)) + return; + +- down(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry_safe(component_info, pNext, + &ioc->raid_data.inactive_list, list) { + list_del(&component_info->list); + kfree(component_info); + } +- up(&ioc->raid_data.inactive_list_mutex); ++ mutex_unlock(&ioc->raid_data.inactive_list_mutex); + } + + /** +@@ -5615,7 +5703,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + if (!handle_inactive_volumes) + goto out; + +- down(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + for (i = 0; i < buffer->NumPhysDisks; i++) { + if(mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) +@@ -5631,7 +5719,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + buffer->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; +- phys_disk_1 = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ phys_disk_1 = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk_1) + continue; +@@ -5658,7 +5746,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + list_add_tail(&component_info->list, + &ioc->raid_data.inactive_list); + } +- up(&ioc->raid_data.inactive_list_mutex); ++ mutex_unlock(&ioc->raid_data.inactive_list_mutex); + + out: + if (buffer) +@@ -5678,7 +5766,8 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *i + * -ENOMEM if pci_alloc failed + **/ + int +-mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage0_t *phys_disk) ++mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, ++ RaidPhysDiskPage0_t *phys_disk) + { + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; +@@ -5812,7 +5901,8 @@ mpt_raid_phys_disk_get_num_paths(MPT_ADA + * -ENOMEM if pci_alloc failed + **/ + int +-mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, RaidPhysDiskPage1_t *phys_disk) ++mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, ++ RaidPhysDiskPage1_t *phys_disk) + { + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; +@@ -5865,14 +5955,20 @@ mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, + for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { + phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; + phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; +- phys_disk->Path[i].OwnerIdentifier = buffer->Path[i].OwnerIdentifier; +- phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); +- memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); ++ phys_disk->Path[i].OwnerIdentifier = ++ buffer->Path[i].OwnerIdentifier; ++ phys_disk->Path[i].Flags = ++ le16_to_cpu(buffer->Path[i].Flags); ++ memcpy(&sas_address, &buffer->Path[i].WWID, ++ sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); +- memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); +- memcpy(&sas_address, &buffer->Path[i].OwnerWWID, sizeof(__le64)); ++ memcpy(&phys_disk->Path[i].WWID, &sas_address, ++ sizeof(__le64)); ++ memcpy(&sas_address, &buffer->Path[i].OwnerWWID, ++ sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); +- memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, sizeof(__le64)); ++ memcpy(&phys_disk->Path[i].OwnerWWID, &sas_address, ++ sizeof(__le64)); + } + + out: +@@ -5896,8 +5992,8 @@ mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, + static int + mpt_sort_ioc_pg2(const void *a, const void *b) + { +- ConfigPageIoc2RaidVol_t * volume_a = (ConfigPageIoc2RaidVol_t *)a; +- ConfigPageIoc2RaidVol_t * volume_b = (ConfigPageIoc2RaidVol_t *)b; ++ ConfigPageIoc2RaidVol_t *volume_a = (ConfigPageIoc2RaidVol_t *)a; ++ ConfigPageIoc2RaidVol_t *volume_b = (ConfigPageIoc2RaidVol_t *)b; + + if (volume_a->VolumeBus == volume_b->VolumeBus) { + if (volume_a->VolumeID == volume_b->VolumeID) +@@ -6186,7 +6282,8 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) + } + + } else { +- dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); ++ dprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "Coalescing Disabled\n", ioc->name)); + } + } + +@@ -6238,12 +6335,13 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER * + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendEventNotification - Send EventNotification (on or off) request to adapter + * @ioc: Pointer to MPT_ADAPTER structure + * @EvSwitch: Event switch flags + * @sleepFlag: Specifies whether the process can sleep +- **/ ++ */ + static int + SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) + { +@@ -6262,15 +6360,16 @@ SendEventNotification(MPT_ADAPTER *ioc, + ioc->name, EvSwitch, &evn)); + + return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), +- (u32*)&evn, sizeof(MPIDefaultReply_t), (u16*)&reply_buf, 30, ++ (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30, + sleepFlag); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * SendEventAck - Send EventAck request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @evnp: Pointer to original EventNotification request +- **/ ++ */ + static int + SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) + { +@@ -6278,7 +6377,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti + + if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", +- ioc->name,__FUNCTION__)); ++ ioc->name,__func__)); + return -1; + } + +@@ -6297,6 +6396,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_config - Generic function to issue config message + * @ioc: Pointer to an adapter structure +@@ -6309,7 +6409,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNoti + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) +- **/ ++ */ + int + mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) + { +@@ -6334,7 +6434,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: busy with host reset\n", ioc->name, __FUNCTION__)); ++ "%s: busy with host reset\n", ioc->name, __func__)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -EBUSY; + } +@@ -6345,7 +6445,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: ioc not operational, %d, %xh\n", +- ioc->name, __FUNCTION__, ioc->active, ++ ioc->name, __func__, ioc->active, + mpt_GetIocState(ioc, 0))); + return -EFAULT; + } +@@ -6423,7 +6523,8 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); + timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; + mpt_put_msg_frame(mpt_base_index, ioc, mf); +- timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout); ++ timeleft = ++ wait_for_completion_timeout(&ioc->mptbase_cmds.done, timeout); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT +@@ -6459,7 +6560,8 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + } + + if (retry_count) +- printk(MYIOC_s_INFO_FMT "Retry completed ret=0x%x timeleft=%ld\n", ++ printk(MYIOC_s_INFO_FMT ++ "Retry completed ret=0x%x timeleft=%ld\n", + ioc->name, ret, timeleft); + + dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", +@@ -6472,15 +6574,15 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + if (issue_hard_reset) { + issue_hard_reset = 0; + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + /* attempt one retry for a timed out command */ + if (!retry_count) { + printk(MYIOC_s_INFO_FMT +- "Attempting Retry Config request type 0x%x, page 0x%x," +- " action %d\n", ioc->name, page_type, ++ "Attempting Retry Config request type 0x%x," ++ " page 0x%x, action %d\n", ioc->name, page_type, + pCfg->cfghdr.hdr->PageNumber, pCfg->action); + retry_count++; + goto retry_config; +@@ -6489,37 +6591,40 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS + return ret; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_ioc_reset - Base cleanup for hard reset + * @ioc: Pointer to the adapter structure + * @reset_phase: Indicates pre- or post-reset functionality + * + * Remark: Frees resources with internally generated commands. +- **/ ++ */ + static int + mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) + { +- switch(reset_phase) { ++ switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + ioc->taskmgmt_quiesce_io = 1; + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + /* wake up mptbase_cmds */ + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { +- ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ ioc->mptbase_cmds.status ++ |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->mptbase_cmds.done); + } + /* wake up taskmgmt_cmds */ + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { +- ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ ioc->taskmgmt_cmds.status ++ |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->taskmgmt_cmds.done); + } + break; +@@ -6532,11 +6637,12 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int rese + + + #ifdef CONFIG_PROC_FS /* { */ ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int + procmpt_create(void) + { +@@ -6557,11 +6663,12 @@ procmpt_create(void) + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static void + procmpt_destroy(void) + { +@@ -6570,6 +6677,7 @@ procmpt_destroy(void) + remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_summary_read - Handle read request of a summary file + * @buf: Pointer to area to write information +@@ -6581,7 +6689,7 @@ procmpt_destroy(void) + * + * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. + * Returns number of characters written to process performing the read. +- **/ ++ */ + static int + procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) + { +@@ -6613,6 +6721,7 @@ procmpt_summary_read(char *buf, char **s + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_version_read - Handle read request from /proc/mpt/version. + * @buf: Pointer to area to write information +@@ -6623,7 +6732,7 @@ procmpt_summary_read(char *buf, char **s + * @data: Pointer + * + * Returns number of characters written to process performing the read. +- **/ ++ */ + static int + procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) + { +@@ -6668,6 +6777,7 @@ procmpt_version_read(char *buf, char **s + MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. + * @buf: Pointer to area to write information +@@ -6678,7 +6788,7 @@ procmpt_version_read(char *buf, char **s + * @data: Pointer + * + * Returns number of characters written to process performing the read. +- **/ ++ */ + static int + procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) + { +@@ -6779,6 +6889,7 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE + } + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -6789,7 +6900,7 @@ mpt_get_fw_exp_ver(char *buf, MPT_ADAPTE + * + * This routine writes (english readable) ASCII text, which represents + * a summary of IOC information, to a buffer. +- **/ ++ */ + void + mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) + { +@@ -6901,19 +7012,19 @@ mpt_halt_firmware(MPT_ADAPTER *ioc) + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", + ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); +- if(mpt_fwfault_debug == 2) +- for(;;); ++ if (mpt_fwfault_debug == 2) ++ for (;;); + else +- panic("%s: IOC Fault (%04xh)!!!\n",ioc->name, ++ panic("%s: IOC Fault (%04xh)!!!\n", ioc->name, + ioc_raw_state & MPI_DOORBELL_DATA_MASK); + } else { + CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); +- if(mpt_fwfault_debug == 2) { +- printk("%s: Firmware is halted due to command timeout\n" +- ,ioc->name); +- for(;;); +- } +- else ++ if (mpt_fwfault_debug == 2) { ++ printk(KERN_ERR ++ "%s: Firmware is halted due to command timeout\n", ++ ioc->name); ++ for (;;); ++ } else + panic("%s: Firmware is halted due to command timeout\n", + ioc->name); + } +@@ -6943,14 +7054,16 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, i + u32 ioc_state; + unsigned long time_count; + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", ioc->name)); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "SoftResetHandler Entered!\n", ioc->name)); + + ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; + +- if(mpt_fwfault_debug) ++ if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + +- if (ioc_state == MPI_IOC_STATE_FAULT || ioc_state == MPI_IOC_STATE_RESET) { ++ if (ioc_state == MPI_IOC_STATE_FAULT ++ || ioc_state == MPI_IOC_STATE_RESET) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "skipping, either in FAULT or RESET state!\n", ioc->name)); + return -1; +@@ -6995,11 +7108,10 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, i + if ((rc = GetIocFacts(ioc, sleepFlag, + MPT_HOSTEVENT_IOC_RECOVER)) == 0) + break; +- if (sleepFlag == CAN_SLEEP) { ++ if (sleepFlag == CAN_SLEEP) + msleep(100); +- } else { ++ else + mdelay(100); +- } + } + if (ii == 5) + goto out; +@@ -7033,13 +7145,15 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, i + if (ioc->active) { /* otherwise, hard reset coming */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) +- mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); ++ mpt_signal_reset(cb_idx, ++ ioc, MPT_IOC_POST_RESET); + } + } + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler: completed (%d seconds): %s\n", +- ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, +- ((rc == 0) ? "SUCCESS" : "FAILED"))); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "SoftResetHandler: completed (%d seconds): %s\n", ++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, ++ ((rc == 0) ? "SUCCESS" : "FAILED"))); + + return rc; + } +@@ -7060,7 +7174,7 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, i + * FW reload/initialization failed. + * + * Returns 0 for SUCCESS or -1 if FAILED. +- **/ ++ */ + int + mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) + { +@@ -7075,7 +7189,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i + printk("MF count 0x%x !\n", ioc->mfcnt); + #endif + +- if(mpt_fwfault_debug) ++ if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + /* Reset the adapter. Prevent more than 1 call to +@@ -7101,14 +7215,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); + if (ioc->alt_ioc) +- mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); ++ mpt_signal_reset(cb_idx, ++ ioc->alt_ioc, MPT_IOC_SETUP_RESET); + } + } + + time_count = jiffies; + if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { +- printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", +- rc, ioc->name); ++ printk(KERN_WARNING MYNAM ++ ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); + } else { + if (ioc->hard_resets < -1) + ioc->hard_resets++; +@@ -7129,13 +7244,15 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, i + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); + if (ioc->alt_ioc) +- mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); ++ mpt_signal_reset(cb_idx, ++ ioc->alt_ioc, MPT_IOC_POST_RESET); + } + } + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n", +- ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, +- ((rc == 0) ? "SUCCESS" : "FAILED"))); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "HardResetHandler: completed (%d seconds): %s\n", ++ ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, ++ ((rc == 0) ? "SUCCESS" : "FAILED"))); + return rc; + } + +@@ -7607,6 +7724,7 @@ mpt_display_event_info(MPT_ADAPTER *ioc, + } + #endif + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * ProcessEventNotification - Route EventNotificationReply to all event handlers + * @ioc: Pointer to MPT_ADAPTER structure +@@ -7616,7 +7734,7 @@ mpt_display_event_info(MPT_ADAPTER *ioc, + * Routes a received EventNotificationReply to all currently registered + * event handlers. + * Returns sum of event handlers return values. +- **/ ++ */ + static int + ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) + { +@@ -7695,12 +7813,12 @@ ProcessEventNotification(MPT_ADAPTER *io + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptEvHandlers[cb_idx]) { + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Routing Event to event handler #%d\n", ioc->name, cb_idx)); ++ "Routing Event to event handler #%d\n", ++ ioc->name, cb_idx)); + r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); + handlers++; + } + } +- /* FIXME? Examine results here? */ + + /* + * If needed, send (a single) EventAck. +@@ -7762,6 +7880,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo + ioc->name, log_info, desc, (log_info & 0xFFFFFF)); + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. + * @ioc: Pointer to MPT_ADAPTER structure +@@ -7769,7 +7888,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo + * @log_info: U32 LogInfo word from the IOC + * + * Refer to lsi/sp_log.h. +- **/ ++ */ + static void + mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) + { +@@ -8353,7 +8472,8 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 + if (!desc) + return; + +- dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc)); ++ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "IOCStatus(0x%04X): %s\n", ioc->name, status, desc)); + } + + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +@@ -8364,7 +8484,6 @@ EXPORT_SYMBOL(mpt_resume); + EXPORT_SYMBOL(mpt_suspend); + #endif + EXPORT_SYMBOL(ioc_list); +-EXPORT_SYMBOL(mpt_proc_root_dir); + EXPORT_SYMBOL(mpt_register); + EXPORT_SYMBOL(mpt_deregister); + EXPORT_SYMBOL(mpt_event_register); +@@ -8395,11 +8514,12 @@ EXPORT_SYMBOL(mpt_set_taskmgmt_in_progre + EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); + EXPORT_SYMBOL(mpt_halt_firmware); + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * fusion_init - Fusion MPT base driver initialization routine. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int __init + fusion_init(void) + { +@@ -8430,12 +8550,13 @@ fusion_init(void) + return 0; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * fusion_exit - Perform driver unload cleanup. + * + * This routine frees all resources associated with each MPT adapter + * and removes all %MPT_PROCFS_MPTBASEDIR entries. +- **/ ++ */ + static void __exit + fusion_exit(void) + { +Index: linux-2.6.27/drivers/message/fusion/mptbase.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptbase.h ++++ linux-2.6.27/drivers/message/fusion/mptbase.h +@@ -72,8 +72,8 @@ + #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR + #endif + +-#define MPT_LINUX_VERSION_COMMON "4.00.43.00" +-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.00.43.00" ++#define MPT_LINUX_VERSION_COMMON "4.00.43.00suse" ++#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-4.00.43.00suse" + #define WHAT_MAGIC_STRING "@" "(" "#" ")" + #define MPT_LINUX_MAJOR_VERSION 4 + #define MPT_LINUX_MINOR_VERSION 00 +@@ -177,10 +177,10 @@ + #define MPT_SCSI_SG_DEPTH 40 + #endif + +-#ifdef CONFIG_FUSION_MAX_FC_SGE +-#if CONFIG_FUSION_MAX_FC_SGE < 16 ++#ifdef CONFIG_FUSION_MAX_FC_SGE ++#if CONFIG_FUSION_MAX_FC_SGE < 16 + #define MPT_SCSI_FC_SG_DEPTH 16 +-#elif CONFIG_FUSION_MAX_FC_SGE > 256 ++#elif CONFIG_FUSION_MAX_FC_SGE > 256 + #define MPT_SCSI_FC_SG_DEPTH 256 + #else + #define MPT_SCSI_FC_SG_DEPTH CONFIG_FUSION_MAX_FC_SGE +@@ -444,10 +444,10 @@ do { \ + #define MPT_MGMT_STATUS_RF_VALID 0x01 /* The Reply Frame is VALID */ + #define MPT_MGMT_STATUS_COMMAND_GOOD 0x02 /* Command Status GOOD */ + #define MPT_MGMT_STATUS_PENDING 0x04 /* command is pending */ +-#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred on the current*/ ++#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred */ + #define MPT_MGMT_STATUS_SENSE_VALID 0x10 /* valid sense info */ + #define MPT_MGMT_STATUS_TIMER_ACTIVE 0x20 /* obsolete */ +-#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from complete routine */ ++#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf */ + + + #define INITIALIZE_MGMT_STATUS(status) \ +@@ -467,7 +467,7 @@ typedef struct _MPT_MGMT { + u8 status; /* current command status */ + int completion_code; + u32 msg_context; +-}MPT_MGMT; ++} MPT_MGMT; + + /* + * Event Structure and define +@@ -540,7 +540,7 @@ typedef struct _RaidCfgData { + IOCPage2_t *pIocPg2; /* table of Raid Volumes */ + IOCPage3_t *pIocPg3; /* table of physical disks */ + IOCPage6_t *pIocPg6; /* table of IR static data */ +- struct semaphore inactive_list_mutex; ++ struct mutex inactive_list_mutex; + struct list_head inactive_list; /* link list for physical + disk that belong in + inactive volumes */ +@@ -571,7 +571,8 @@ struct mptfc_rport_info + }; + + typedef void (*MPT_ADD_SGE)(char *pAddr, u32 flagslength, dma_addr_t dma_addr); +-typedef void (*MPT_ADD_CHAIN)(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr); ++typedef void (*MPT_ADD_CHAIN) ++ (char *pAddr, u8 next, u16 length, dma_addr_t dma_addr); + + /* + * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS +@@ -583,7 +584,8 @@ typedef struct _MPT_ADAPTER + char name[MPT_NAME_LENGTH]; /* "iocN" */ + char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ + #ifdef CONFIG_FUSION_LOGGING +- char evStr[EVENT_DESCR_STR_SZ]; /* used in mpt_display_event_info */ ++ /* used in mpt_display_event_info */ ++ char evStr[EVENT_DESCR_STR_SZ]; + #endif + char board_name[16]; + char board_assembly[16]; +@@ -597,7 +599,8 @@ typedef struct _MPT_ADAPTER + SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ + u8 bus_type; + unsigned long mem_phys; /* == f4020000 (mmap) */ +- unsigned long pio_mem_phys; /* Programmed IO (downloadboot) */ ++ /* Programmed IO (downloadboot) */ ++ unsigned long pio_mem_phys; + int mem_size; /* mmap memory size */ + int number_of_buses; + int devices_per_bus; +@@ -612,8 +615,10 @@ typedef struct _MPT_ADAPTER + int reply_depth; /* Num Allocated reply frames */ + int reply_sz; /* Reply frame size */ + int num_chain; /* Number of chain buffers */ +- MPT_ADD_SGE add_sge; /* Pointer to add_sge function */ +- MPT_ADD_CHAIN add_chain; /* Pointer to add_chain function */ ++ /* Pointer to add_sge function */ ++ MPT_ADD_SGE add_sge; ++ /* Pointer to add_chain function */ ++ MPT_ADD_CHAIN add_chain; + /* Pool of buffers for chaining. ReqToChain + * and ChainToChain track index of chain buffers. + * ChainBuffer (DMA) virt/phys addresses. +@@ -646,7 +651,8 @@ typedef struct _MPT_ADAPTER + dma_addr_t HostPageBuffer_dma; + int mtrr_reg; + struct pci_dev *pcidev; /* struct pci_dev pointer */ +- int bars; /* bitmask of BAR's that must be configured */ ++ /* bitmask of BAR's that must be configured */ ++ int bars; + int msi_enable; + u8 __iomem *memmap; /* mmap address */ + struct Scsi_Host *sh; /* Scsi Host pointer */ +@@ -680,7 +686,8 @@ typedef struct _MPT_ADAPTER + #if defined(CPQ_CIM) + u32 csmi_change_count; /* count to track all IR + events for CSMI */ +- u8 pci_slot_number; /* ioc page 1 - pci slot number */ ++ /* ioc page 1 - pci slot number */ ++ u8 pci_slot_number; + #endif + + u8 ir_firmware; /* =1 if IR firmware detected */ +@@ -711,11 +718,12 @@ typedef struct _MPT_ADAPTER + u8 fw_events_off; /* if '1', then ignore events */ + char fw_event_q_name[20]; + +- struct mptsas_portinfo *hba_port_info; /* port_info object for the host */ ++ /* port_info object for the host */ ++ struct mptsas_portinfo *hba_port_info; + u64 hba_port_sas_addr; + u16 hba_port_num_phy; + struct list_head sas_device_info_list; +- struct semaphore sas_device_info_mutex; ++ struct mutex sas_device_info_mutex; + u8 old_sas_discovery_protocal; + u8 sas_discovery_quiesce_io; + int sas_index; /* index refrencing */ +@@ -735,6 +743,7 @@ typedef struct _MPT_ADAPTER + char reset_work_q_name[20]; + struct workqueue_struct *reset_work_q; + struct delayed_work fault_reset_work; ++ spinlock_t fault_reset_work_lock; + struct work_struct fc_setup_reset_work; + struct list_head fc_rports; + struct work_struct fc_lsc_work; +@@ -743,9 +752,12 @@ typedef struct _MPT_ADAPTER + struct work_struct fc_rescan_work; + char fc_rescan_work_q_name[20]; + struct workqueue_struct *fc_rescan_work_q; +- unsigned long hard_resets; /* driver forced bus resets count */ +- unsigned long soft_resets; /* fw/external bus resets count */ +- unsigned long timeouts; /* cmd timeouts */ ++ /* driver forced bus resets count */ ++ unsigned long hard_resets; ++ /* fw/external bus resets count */ ++ unsigned long soft_resets; ++ /* cmd timeouts */ ++ unsigned long timeouts; + struct scsi_cmnd **ScsiLookup; + spinlock_t scsi_lookup_lock; + int sdev_queue_depth; /* sdev queue depth */ +@@ -907,10 +919,14 @@ extern int mpt_config(MPT_ADAPTER *ioc, + extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size); + extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); + extern int mpt_findImVolumes(MPT_ADAPTER *ioc); +-extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); +-extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk); +-extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage1_t phys_disk); +-extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num); ++extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, ++ u8 persist_opcode); ++extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, ++ pRaidPhysDiskPage0_t phys_disk); ++extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, ++ pRaidPhysDiskPage1_t phys_disk); ++extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, ++ u8 phys_disk_num); + + extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); + extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); +@@ -920,7 +936,6 @@ extern void mpt_halt_firmware(MPT_ADAPT + * Public data decl's... + */ + extern struct list_head ioc_list; +-extern struct proc_dir_entry *mpt_proc_root_dir; + extern int mpt_debug_level; + extern int mpt_fwfault_debug; + +Index: linux-2.6.27/drivers/message/fusion/mptctl.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptctl.c ++++ linux-2.6.27/drivers/message/fusion/mptctl.c +@@ -75,7 +75,7 @@ + #if defined(CPQ_CIM) + #include "mptsas.h" + #include "csmi/csmisas.h" +-#endif // CPQ_CIM ++#endif + + #if defined(DIAG_BUFFER_SUPPORT) + #include "rejected_ioctls/diag_buffer.h" +@@ -148,7 +148,7 @@ static int csmisas_task_managment(unsign + static int csmisas_phy_control(unsigned long arg); + static int csmisas_get_connector_info(unsigned long arg); + static int csmisas_get_location(unsigned long arg); +-#endif // CPQ_CIM ++#endif + + #if defined(DIAG_BUFFER_SUPPORT) + /* diag_buffer proto's */ +@@ -157,7 +157,7 @@ static int mptctl_release_diag_buffer(un + static int mptctl_unregister_diag_buffer(unsigned long arg); + static int mptctl_query_diag_buffer(unsigned long arg); + static int mptctl_read_diag_buffer(unsigned long arg); +-#endif // DIAG_BUFFER_SUPPORT ++#endif + + static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); + static void mptctl_remove(struct pci_dev *); +@@ -279,7 +279,8 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME + le32_to_cpu(reply->u.reply.IOCLogInfo))); + + if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) || +- (req->u.hdr.Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { ++ (req->u.hdr.Function ++ == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + + if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT +@@ -290,7 +291,8 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME + le16_to_cpu(reply->u.sreply.TaskTag), + le32_to_cpu(reply->u.sreply.TransferCount))); + +- if (reply->u.sreply.SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { ++ if (reply->u.sreply.SCSIState ++ & MPI_SCSI_STATE_AUTOSENSE_VALID) { + sz = req->u.scsireq.SenseBufferLength; + req_index = + le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); +@@ -324,7 +326,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, + if (!mf) + return 0; + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n", ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt completed (mf=%p, mr=%p)\n", + ioc->name, mf, mr)); + + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; +@@ -365,8 +368,8 @@ mptctl_bus_reset(MPT_ADAPTER *ioc, u8 fu + /* bus reset is only good for SCSI IO, RAID PASSTHRU */ + if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) || + (function == MPI_FUNCTION_SCSI_IO_REQUEST)) { +- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, not SCSI_IO!!\n", +- ioc->name)); ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "TaskMgmt, not SCSI_IO!!\n", ioc->name)); + return -EPERM; + } + +@@ -381,8 +384,8 @@ mptctl_bus_reset(MPT_ADAPTER *ioc, u8 fu + /* Send request + */ + if ((mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc)) == NULL) { +- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", +- ioc->name)); ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "TaskMgmt, no msg frames!!\n", ioc->name)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + retval = -ENOMEM; + goto mptctl_bus_reset_done; +@@ -408,20 +411,21 @@ mptctl_bus_reset(MPT_ADAPTER *ioc, u8 fu + pScsiTm->Reserved2[ii] = 0; + + switch (ioc->bus_type) { +- case FC: +- timeout = 40; +- break; +- case SAS: +- timeout = 30; +- break; +- case SPI: +- default: +- timeout = 2; +- break; ++ case FC: ++ timeout = 40; ++ break; ++ case SAS: ++ timeout = 30; ++ break; ++ case SPI: ++ default: ++ timeout = 10; ++ break; + } + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", +- ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt type=%d timeout=%ld\n", ioc->name, ++ MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); + + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) +@@ -431,9 +435,10 @@ mptctl_bus_reset(MPT_ADAPTER *ioc, u8 fu + mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); + else { + retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); ++ sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP); + if (retval != 0) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!" ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "TaskMgmt send_handshake FAILED!" + " (ioc %p, mf %p, rc=%d) \n", ioc->name, + ioc, mf, retval)); + mpt_clear_taskmgmt_in_progress_flag(ioc); +@@ -498,11 +503,10 @@ mptctl_timeout_expired(MPT_ADAPTER *ioc, + unsigned long flags; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", +- ioc->name, __FUNCTION__)); ++ ioc->name, __func__)); + +- if(mpt_fwfault_debug) ++ if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); +- + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +@@ -540,15 +544,15 @@ mptctl_ioc_reset(MPT_ADAPTER *ioc, int r + switch(reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->ioctl_cmds.done); +@@ -571,13 +575,11 @@ mptctl_event_process(MPT_ADAPTER *ioc, E + event = le32_to_cpu(pEvReply->Event) & 0xFF; + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n", +- ioc->name, __FUNCTION__)); ++ ioc->name, __func__)); + if(async_queue == NULL) + return 1; + + /* Raise SIGIO for persistent events. +- * TODO - this define is not in MPI spec yet, +- * but they plan to set it to 0x21 + */ + if (event == 0x21 ) { + ioc->aen_event_read_flag=1; +@@ -660,8 +662,9 @@ __mptctl_ioctl(struct file *file, unsign + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnumX); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnumX); + return -ENODEV; + } + +@@ -700,9 +703,9 @@ __mptctl_ioctl(struct file *file, unsign + return csmisas_get_cntlr_status(arg); + } else if (cmd == CC_CSMI_SAS_GET_SCSI_ADDRESS) { + return csmisas_get_scsi_address(arg); +- } else if (cmd == CC_CSMI_SAS_GET_DEVICE_ADDRESS){ ++ } else if (cmd == CC_CSMI_SAS_GET_DEVICE_ADDRESS) { + return csmisas_get_device_address(arg); +-#endif // CPQ_CIM ++#endif + } + + /* All of these commands require an interrupt or +@@ -711,8 +714,6 @@ __mptctl_ioctl(struct file *file, unsign + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + +-// dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT ": mptctl_ioctl()\n", iocp->name)); +- + if (cmd == MPTFWDOWNLOAD) + ret = mptctl_fw_download(arg); + else if (cmd == MPTCOMMAND) +@@ -763,7 +764,7 @@ __mptctl_ioctl(struct file *file, unsign + ret = csmisas_get_connector_info(arg); + else if (cmd == CC_CSMI_SAS_GET_LOCATION) + ret = csmisas_get_location(arg); +-#endif // CPQ_CIM ++#endif + + #if defined(DIAG_BUFFER_SUPPORT) + /* diag_buffer requiring fw calls*/ +@@ -773,7 +774,7 @@ __mptctl_ioctl(struct file *file, unsign + ret = mptctl_release_diag_buffer(arg); + else if (cmd == MPTDIAGREADBUFFER) + ret = mptctl_read_diag_buffer(arg); +-#endif // DIAG_BUFFER_SUPPORT ++#endif + else + ret = -EINVAL; + +@@ -807,8 +808,9 @@ static int mptctl_do_reset(unsigned long + + if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n", +- __FILE__, __LINE__, krinfo.hdr.iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s@%d::%s - ioc%d not found!\n", ++ __FILE__, __LINE__, __func__, krinfo.hdr.iocnum); + return -ENODEV; /* (-6) No such device or address */ + } + +@@ -898,7 +900,8 @@ mptctl_do_fw_download(int ioc, char __us + + if (mpt_verify_adapter(ioc, &iocp) < 0) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", ioc); ++ printk(KERN_DEBUG MYNAM ++ "ioctl_fwdl - ioc%d not found!\n", ioc); + return -ENODEV; /* (-6) No such device or address */ + } else { + +@@ -982,7 +985,7 @@ mptctl_do_fw_download(int ioc, char __us + / iocp->SGE_size; + if (numfrags > maxfrags) { + ret = -EMLINK; +- goto fwdl_out; ++ goto fwdl_out; + } + + dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n", +@@ -1036,7 +1039,7 @@ mptctl_do_fw_download(int ioc, char __us + timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60); + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; +- printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(iocp, mf); + goto fwdl_out; +@@ -1047,7 +1050,7 @@ mptctl_do_fw_download(int ioc, char __us + } + + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { +- printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __FUNCTION__); ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + mpt_free_msg_frame(iocp, mf); + ret = -ENODATA; + goto fwdl_out; +@@ -1059,10 +1062,12 @@ mptctl_do_fw_download(int ioc, char __us + ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; + iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; + if (iocstat == MPI_IOCSTATUS_SUCCESS) { +- printk(MYIOC_s_INFO_FMT ": F/W update successfully sent!\n", iocp->name); ++ printk(MYIOC_s_INFO_FMT ++ ": F/W update successfully sent!\n", iocp->name); + return 0; + } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { +- printk(MYIOC_s_WARN_FMT "Hmmm... doesn't support F/W download?\n", ++ printk(MYIOC_s_WARN_FMT ++ "Hmmm... doesn't support F/W download?\n", + iocp->name); + printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n", + iocp->name); +@@ -1177,7 +1182,8 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, i + bytes_allocd += this_alloc; + sgl->FlagsLength = (0x10000000|sgdir|this_alloc); + if (ioc->sg_addr_size == sizeof(u64)) +- sgl->FlagsLength |= MPT_SGE_FLAGS_64_BIT_ADDRESSING; ++ sgl->FlagsLength ++ |= MPT_SGE_FLAGS_64_BIT_ADDRESSING; + dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); + sgl->Address = dma_addr; + +@@ -1362,8 +1368,9 @@ mptctl_getiocinfo (unsigned long arg, un + if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + kfree(karg); + return -ENODEV; + } +@@ -1498,8 +1505,9 @@ mptctl_gettargetinfo (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1514,7 +1522,8 @@ mptctl_gettargetinfo (unsigned long arg) + port = karg.hdr.port; + + if (maxWordsLeft <= 0) { +- printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n", ++ printk(MYIOC_s_ERR_FMT ++ "%s::mptctl_gettargetinfo() @%d - no memory available!\n", + ioc->name, __FILE__, __LINE__); + return -ENOMEM; + } +@@ -1535,7 +1544,8 @@ mptctl_gettargetinfo (unsigned long arg) + */ + pmem = kzalloc(numBytes, GFP_KERNEL); + if (!pmem) { +- printk(MYIOC_s_ERR_FMT "%s::mptctl_gettargetinfo() @%d - no memory available!\n", ++ printk(MYIOC_s_ERR_FMT ++ "%s::mptctl_gettargetinfo() @%d - no memory available!\n", + ioc->name, __FILE__, __LINE__); + return -ENOMEM; + } +@@ -1615,8 +1625,9 @@ mptctl_readtest (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1677,8 +1688,9 @@ mptctl_eventquery (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1717,8 +1729,9 @@ mptctl_eventenable (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1730,7 +1743,8 @@ mptctl_eventenable (unsigned long arg) + int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + ioc->events = kzalloc(sz, GFP_KERNEL); + if (!ioc->events) { +- printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", ++ printk(MYIOC_s_ERR_FMT ++ "Insufficient memory to add adapter!\n", + ioc->name); + return -ENOMEM; + } +@@ -1766,8 +1780,9 @@ mptctl_eventreport (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1821,8 +1836,9 @@ mptctl_replace_fw (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1870,7 +1886,8 @@ mptctl_replace_fw (unsigned long arg) + * + * Outputs: None. + * Return: 0 if successful +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is ++ * not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires +@@ -1896,8 +1913,9 @@ mptctl_mpt_command (unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -1911,7 +1929,8 @@ mptctl_mpt_command (unsigned long arg) + * + * Outputs: None. + * Return: 0 if successful +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is ++ * not complete. + * -EFAULT if data unavailable + * -ENODEV if no such device/adapter + * -ETIME if timer expires +@@ -1948,8 +1967,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -2194,10 +2214,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + { + SCSITaskMgmt_t *pScsiTm; + pScsiTm = (SCSITaskMgmt_t *)mf; +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tTaskType=0x%x MsgFlags=0x%x " +- "TaskMsgContext=0x%x id=%d channel=%d\n", ioc->name, pScsiTm->TaskType, +- le32_to_cpu(pScsiTm->TaskMsgContext), pScsiTm->MsgFlags, +- pScsiTm->TargetID, pScsiTm->Bus)); ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "\tTaskType=0x%x MsgFlags=0x%x " ++ "TaskMsgContext=0x%x id=%d channel=%d\n", ++ ioc->name, pScsiTm->TaskType, ++ le32_to_cpu(pScsiTm->TaskMsgContext), ++ pScsiTm->MsgFlags, pScsiTm->TargetID, pScsiTm->Bus)); + break; + } + +@@ -2286,9 +2308,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + /* Set up the dataOut memory allocation */ + if (karg.dataOutSize > 0) { + if (karg.dataInSize > 0) { +- flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | +- MPI_SGE_FLAGS_DIRECTION ) ++ MPI_SGE_FLAGS_DIRECTION) + << MPI_SGE_FLAGS_SHIFT; + } else { + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; +@@ -2365,7 +2387,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf); + else { + rc = mpt_send_handshake_request(mptctl_id, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); ++ sizeof(SCSITaskMgmt_t), (u32 *)mf, CAN_SLEEP); + if (rc != 0) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "send_handshake FAILED! (ioc %p, mf %p)\n", +@@ -2381,16 +2403,16 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + + /* Now wait for the command to complete */ + timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT; +- timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout); ++ timeleft = ++ wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*timeout); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n", +- ioc->name, __FUNCTION__)); ++ ioc->name, __func__)); + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); +- if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { ++ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto done_free_mem; +- } + if (!timeleft) { + mptctl_timeout_expired(ioc, mf); + mf = NULL; +@@ -2408,7 +2430,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { + if (karg.maxReplyBytes < ioc->reply_sz) { +- sz = min(karg.maxReplyBytes, 4*ioc->ioctl_cmds.reply[2]); ++ sz = min(karg.maxReplyBytes, ++ 4*ioc->ioctl_cmds.reply[2]); + } else { + sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]); + } +@@ -2430,7 +2453,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) { + sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); + if (sz > 0) { +- if (copy_to_user(karg.senseDataPtr, ioc->ioctl_cmds.sense, sz)) { ++ if (copy_to_user(karg.senseDataPtr, ++ ioc->ioctl_cmds.sense, sz)) { + printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " + "Unable to write sense data to user %p\n", + ioc->name, __FILE__, __LINE__, +@@ -2488,7 +2512,8 @@ done_free_mem: + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is ++ * not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error +@@ -2499,7 +2524,7 @@ mptctl_hp_hostinfo(unsigned long arg, un + hp_host_info_t __user *uarg = (void __user *) arg; + MPT_ADAPTER *ioc; + struct pci_dev *pdev; +- char *pbuf=NULL; ++ char *pbuf = NULL; + dma_addr_t buf_dma; + hp_host_info_t karg; + int iocnum; +@@ -2530,8 +2555,9 @@ mptctl_hp_hostinfo(unsigned long arg, un + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +@@ -2619,7 +2645,7 @@ mptctl_hp_hostinfo(unsigned long arg, un + */ + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", +- ioc->name,__FUNCTION__)); ++ ioc->name,__func__)); + retval = -ENOMEM; + goto out; + } +@@ -2644,16 +2670,19 @@ mptctl_hp_hostinfo(unsigned long arg, un + retval = -ENOMEM; + goto out; + } +- ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4),buf_dma); ++ ioc->add_sge((char *)&IstwiRWRequest->SGL, ++ (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma); + + retval = 0; +- SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, IstwiRWRequest->MsgContext); ++ SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, ++ IstwiRWRequest->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) + mpt_put_msg_frame(mptctl_id, ioc, mf); +- timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, HZ*MPT_IOCTL_DEFAULT_TIMEOUT); ++ timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, ++ HZ*MPT_IOCTL_DEFAULT_TIMEOUT); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -ETIME; +- printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __FUNCTION__); ++ printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; +@@ -2701,7 +2730,8 @@ mptctl_hp_hostinfo(unsigned long arg, un + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is ++ * not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error +@@ -2732,12 +2762,14 @@ mptctl_hp_targetinfo(unsigned long arg) + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", +- __FILE__, __LINE__, iocnum); ++ printk(KERN_DEBUG MYNAM ++ "%s::%s @%d - ioc%d not found!\n", ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + +- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n", ++ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ ": mptctl_hp_targetinfo called.\n", + ioc->name)); + /* There is nothing to do for FCP parts. + */ +@@ -2889,8 +2921,9 @@ compat_mptfwxfer_ioctl(struct file *filp + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n", +- __LINE__, iocnumX); ++ printk(KERN_DEBUG MYNAM ++ "::%s @%d - ioc%d not found!\n", __func__, ++ __LINE__, iocnumX); + return -ENODEV; + } + +@@ -2930,8 +2963,9 @@ compat_mpt_command(struct file *filp, un + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + if (mpt_debug_level & MPT_DEBUG_IOCTL) +- printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n", +- __LINE__, iocnumX); ++ printk(KERN_DEBUG MYNAM ++ "::%s @%d - ioc%d not found!\n", ++ __func__, __LINE__, iocnumX); + return -ENODEV; + } + +@@ -3144,7 +3178,7 @@ static void mptctl_exit(void) + + #if defined(CPQ_CIM) + #include "csmi/csmisas.c" +-#endif // CPQ_CIM ++#endif + + #if defined(DIAG_BUFFER_SUPPORT) + #include "rejected_ioctls/diag_buffer.c" +Index: linux-2.6.27/drivers/message/fusion/mptfc.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptfc.c ++++ linux-2.6.27/drivers/message/fusion/mptfc.c +@@ -270,28 +270,28 @@ static int + mptfc_abort(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__); ++ mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__); + } + + static int + mptfc_dev_reset(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__); ++ mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__); + } + + static int + mptfc_bus_reset(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__); ++ mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__); + } + + static int + mptfc_host_reset(struct scsi_cmnd *SCpnt) + { + return +- mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__); ++ mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__); + } + + static void +@@ -553,7 +553,6 @@ mptfc_target_destroy(struct scsi_target + struct fc_rport *rport; + struct mptfc_rport_info *ri; + +- printk("%s - starget=%p\n", __FUNCTION__, starget); + rport = starget_to_rport(starget); + if (rport) { + ri = *((struct mptfc_rport_info **)rport->dd_data); +@@ -994,7 +993,8 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE + #define OFF_FLAGS (MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS) + + for (ii=0; iifacts.NumberOfPorts; ii++) { +- if ((rc = mptfc_GetFcPortPage1(ioc, ii)) < 0) ++ rc = mptfc_GetFcPortPage1(ioc, ii); ++ if (rc < 0) + return rc; + pp1 = ioc->fc_data.fc_port_page1[ii].data; + if ((pp1->InitiatorDeviceTimeout == MPTFC_FW_DEVICE_TIMEOUT) +@@ -1006,7 +1006,8 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTE + pp1->InitiatorIoPendTimeout = MPTFC_FW_IO_PEND_TIMEOUT; + pp1->Flags &= ~OFF_FLAGS; + pp1->Flags |= ON_FLAGS; +- if ((rc = mptfc_WriteFcPortPage1(ioc, ii)) < 0) ++ rc = mptfc_WriteFcPortPage1(ioc, ii); ++ if (rc < 0) + return rc; + } + return 0; +@@ -1170,8 +1171,9 @@ mptfc_rescan_devices(struct work_struct + * if cannot set defaults, something's really wrong, bail out + */ + +- if ((rc = mptfc_SetFcPortPage1_defaults(ioc)) < 0) { +- dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT ++ rc = mptfc_SetFcPortPage1_defaults(ioc); ++ if (rc < 0) { ++ dfcprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "mptfc_rescan.%d: unable to set PP1 defaults, rc %d.\n", + ioc->name, ioc->sh->host_no, rc)); + return; +@@ -1373,8 +1375,9 @@ mptfc_probe(struct pci_dev *pdev, const + + /* initialize workqueue */ + +- snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name), "mptfc_wq_%d", +- sh->host_no); ++ snprintf(ioc->fc_rescan_work_q_name, ++ sizeof(ioc->fc_rescan_work_q_name), "mptfc_wq_%d", ++ sh->host_no); + ioc->fc_rescan_work_q = + create_singlethread_workqueue(ioc->fc_rescan_work_q_name); + if (!ioc->fc_rescan_work_q) +@@ -1462,10 +1465,10 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int re + if ((ioc->bus_type != FC) || (!rc)) + return rc; + +- switch(reset_phase) { ++ switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + if (ioc->fc_rescan_work_q) { + queue_work(ioc->fc_rescan_work_q, +@@ -1475,11 +1478,11 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int re + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); + if (ioc->fc_rescan_work_q) { + queue_work(ioc->fc_rescan_work_q, +@@ -1493,11 +1496,12 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int re + return 1; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptfc_init - Register MPT adapter(s) as SCSI host(s) with SCSI mid-layer. + * + * Returns 0 for success, non-zero for failure. +- **/ ++ */ + static int __init + mptfc_init(void) + { +@@ -1529,11 +1533,12 @@ mptfc_init(void) + return error; + } + ++/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptfc_remove - Remove fc infrastructure for devices + * @pdev: Pointer to pci_dev structure + * +- **/ ++ */ + static void __devexit + mptfc_remove(struct pci_dev *pdev) + { +@@ -1543,8 +1548,6 @@ mptfc_remove(struct pci_dev *pdev) + unsigned long flags; + int ii; + +- printk("%s -pdev=%p\n", __FUNCTION__, pdev); +- + /* destroy workqueue */ + if ((work_q=ioc->fc_rescan_work_q)) { + spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); +Index: linux-2.6.27/drivers/message/fusion/mptlan.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptlan.c ++++ linux-2.6.27/drivers/message/fusion/mptlan.c +@@ -614,7 +614,7 @@ mpt_lan_send_turbo(struct net_device *de + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), +- __FUNCTION__, sent)); ++ __func__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, +@@ -680,7 +680,7 @@ mpt_lan_send_reply(struct net_device *de + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), +- __FUNCTION__, sent)); ++ __func__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, +@@ -719,7 +719,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + u16 cur_naa = 0x1000; + + dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", +- __FUNCTION__, skb)); ++ __func__, skb)); + + spin_lock_irqsave(&priv->txfidx_lock, flags); + if (priv->mpt_txfidx_tail < 0) { +@@ -727,7 +727,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: no tx context available: %u\n", +- __FUNCTION__, priv->mpt_txfidx_tail); ++ __func__, priv->mpt_txfidx_tail); + return 1; + } + +@@ -737,7 +737,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: Unable to alloc request frame\n", +- __FUNCTION__); ++ __func__); + return 1; + } + +@@ -1213,7 +1213,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", + IOC_AND_NETDEV_NAMES_s_s(dev), +- __FUNCTION__, buckets, curr)); ++ __func__, buckets, curr)); + + max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / + (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); +@@ -1222,9 +1222,9 @@ mpt_lan_post_receive_buckets(struct mpt_ + mf = mpt_get_msg_frame(LanCtx, mpt_dev); + if (mf == NULL) { + printk (KERN_ERR "%s: Unable to alloc request frame\n", +- __FUNCTION__); ++ __func__); + dioprintk((KERN_ERR "%s: %u buckets remaining\n", +- __FUNCTION__, buckets)); ++ __func__, buckets)); + goto out; + } + pRecvReq = (LANReceivePostRequest_t *) mf; +@@ -1249,7 +1249,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + spin_lock_irqsave(&priv->rxfidx_lock, flags); + if (priv->mpt_rxfidx_tail < 0) { + printk (KERN_ERR "%s: Can't alloc context\n", +- __FUNCTION__); ++ __func__); + spin_unlock_irqrestore(&priv->rxfidx_lock, + flags); + break; +@@ -1272,7 +1272,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + if (skb == NULL) { + printk (KERN_WARNING + MYNAM "/%s: Can't alloc skb\n", +- __FUNCTION__); ++ __func__); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + break; +@@ -1310,7 +1310,7 @@ mpt_lan_post_receive_buckets(struct mpt_ + + if (pSimple == NULL) { + /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", +-/**/ __FUNCTION__); ++/**/ __func__); + mpt_free_msg_frame(mpt_dev, mf); + goto out; + } +@@ -1334,9 +1334,9 @@ mpt_lan_post_receive_buckets(struct mpt_ + + out: + dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", +- __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); ++ __func__, buckets, atomic_read(&priv->buckets_out))); + dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", +- __FUNCTION__, priv->total_posted, priv->total_received)); ++ __func__, priv->total_posted, priv->total_received)); + + clear_bit(0, &priv->post_buckets_active); + } +Index: linux-2.6.27/drivers/message/fusion/mptsas.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptsas.c ++++ linux-2.6.27/drivers/message/fusion/mptsas.c +@@ -117,19 +117,23 @@ static u8 mptsasInternalCtx = MPT_MAX_PR + static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; + static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; + +-static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); +-static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, +- u64 sas_address); +-static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, +- u32 form, u32 form_specific); +-static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, +- u32 form, u32 form_specific); +- +-static int mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info); +-static void mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info); +-static void mptsas_expander_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info); +-static int mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, +- u32 form, u32 form_specific); ++static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, ++ struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); ++static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address( ++ MPT_ADAPTER *ioc, u64 sas_address); ++static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, ++ struct mptsas_devinfo *device_info, u32 form, u32 form_specific); ++static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, ++ struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); ++ ++static int mptsas_add_end_device(MPT_ADAPTER *ioc, ++ struct mptsas_phyinfo *phy_info); ++static void mptsas_del_end_device(MPT_ADAPTER *ioc, ++ struct mptsas_phyinfo *phy_info); ++static void mptsas_expander_delete(MPT_ADAPTER *ioc, ++ struct mptsas_portinfo *port_info); ++static int mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, ++ struct mptsas_portinfo *port_info, u32 form, u32 form_specific); + static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); + static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); + +@@ -323,7 +327,7 @@ mptsas_add_fw_event(MPT_ADAPTER *ioc, st + list_add_tail(&fw_event->list, &ioc->fw_event_list); + INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: add (fw_event=0x%p)\n", +- ioc->name,__FUNCTION__, fw_event)); ++ ioc->name, __func__, fw_event)); + queue_delayed_work(ioc->fw_event_q, &fw_event->work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +@@ -337,7 +341,7 @@ mptsas_requeue_fw_event(MPT_ADAPTER *ioc + unsigned long flags; + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: reschedule task " +- "(fw_event=0x%p)\n", ioc->name,__FUNCTION__, fw_event)); ++ "(fw_event=0x%p)\n", ioc->name, __func__, fw_event)); + fw_event->retries++; + queue_delayed_work(ioc->fw_event_q, &fw_event->work, + msecs_to_jiffies(delay)); +@@ -352,13 +356,14 @@ mptsas_free_fw_event(MPT_ADAPTER *ioc, s + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: kfree (fw_event=0x%p)\n", +- ioc->name,__FUNCTION__, fw_event)); ++ ioc->name, __func__, fw_event)); + list_del(&fw_event->list); + kfree(fw_event); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + } + +-/* walk the firmware event queue, and either stop or wait for outstanding events to complete */ ++/* walk the firmware event queue, and either stop or wait for ++ * outstanding events to complete */ + static void + mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) + { +@@ -373,7 +378,7 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *i + &hd->target_reset_list, list) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: removing target reset for id=%d\n", +- ioc->name, __FUNCTION__, ++ ioc->name, __func__, + target_reset_list->sas_event_data.TargetID)); + list_del(&target_reset_list->list); + kfree(target_reset_list); +@@ -433,7 +438,7 @@ rphy_to_ioc(struct sas_rphy *rphy) + static struct mptsas_portinfo * + mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) + { +- struct mptsas_portinfo *port_info, *rc=NULL; ++ struct mptsas_portinfo *port_info, *rc = NULL; + int i; + + if (sas_address >= ioc->hba_port_sas_addr && +@@ -523,7 +528,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, str + phy_info = port_info->phy_info; + + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " +- "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, ++ "bitmask=0x%016llX\n", ioc->name, __func__, port_details, + port_details->num_phys, (unsigned long long) + port_details->phy_bitmask)); + +@@ -659,7 +664,7 @@ mptsas_add_device_component(MPT_ADAPTER + /* + * Delete all matching devices out of the list + */ +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && +@@ -700,7 +705,7 @@ mptsas_add_device_component(MPT_ADAPTER + } + + out: +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + return; + } + +@@ -745,7 +750,8 @@ mptsas_add_device_component_by_fw(MPT_AD + * + **/ + static void +-mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, struct scsi_target *starget) ++mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, ++ struct scsi_target *starget) + { + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; +@@ -790,14 +796,14 @@ mptsas_add_device_component_starget_ir(M + */ + for (i = 0; i < buffer->NumPhysDisks; i++) { + +- if(mpt_raid_phys_disk_pg0(ioc, ++ if (mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) + continue; + + mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, + phys_disk.PhysDiskID); + +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && +@@ -807,13 +813,13 @@ mptsas_add_device_component_starget_ir(M + sas_info->volume_id = starget->id; + } + } +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + } + + /* + * Delete all matching devices out of the list + */ +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->is_logical_volume && sas_info->fw.id == +@@ -832,7 +838,7 @@ mptsas_add_device_component_starget_ir(M + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + } +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + + out: + if (buffer) +@@ -847,7 +853,8 @@ mptsas_add_device_component_starget_ir(M + * + **/ + static void +-mptsas_add_device_component_starget(MPT_ADAPTER *ioc, struct scsi_target *starget) ++mptsas_add_device_component_starget(MPT_ADAPTER *ioc, ++ struct scsi_target *starget) + { + VirtTarget *vtarget; + struct sas_rphy *rphy; +@@ -906,13 +913,13 @@ mptsas_del_device_components(MPT_ADAPTER + { + struct sas_device_info *sas_info, *next; + +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + list_del(&sas_info->list); + kfree(sas_info); + } +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + } + + /** +@@ -926,7 +933,7 @@ mptsas_del_device_components(MPT_ADAPTER + static void + mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) + { +- struct mptsas_portinfo_details * port_details; ++ struct mptsas_portinfo_details *port_details; + struct mptsas_phyinfo *phy_info, *phy_info_cmp; + u64 sas_address; + int i, j; +@@ -949,9 +956,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc + */ + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: [%p]: deleting phy = %d\n", +- ioc->name, __FUNCTION__, port_details, i)); ++ ioc->name, __func__, port_details, i)); + port_details->num_phys--; +- port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); ++ port_details->phy_bitmask &= ~(1 << phy_info->phy_id); + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, +@@ -966,8 +973,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + sas_address = phy_info->attached.sas_address; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n", +- ioc->name, i, (unsigned long long)sas_address)); ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "phy_id=%d sas_address=0x%018llX\n", ++ ioc->name, i, (unsigned long long)sas_address)); + if (!sas_address) + continue; + port_details = phy_info->port_details; +@@ -981,13 +989,14 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc + goto out; + port_details->num_phys = 1; + port_details->port_info = port_info; +- if (phy_info->phy_id < 64 ) ++ if (phy_info->phy_id < 64) + port_details->phy_bitmask |= + (1 << phy_info->phy_id); +- phy_info->sas_port_add_phy=1; +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" +- "phy_id=%d sas_address=0x%018llX\n", ioc->name, i, +- (unsigned long long) sas_address)); ++ phy_info->sas_port_add_phy = 1; ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "\t\tForming port\n\t\t" ++ "phy_id=%d sas_address=0x%018llX\n", ioc->name, ++ i, (unsigned long long) sas_address)); + phy_info->port_details = port_details; + } + +@@ -1000,7 +1009,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc + continue; + if (sas_address != phy_info_cmp->attached.sas_address) + continue; +- if (phy_info_cmp->port_details == port_details ) ++ if (phy_info_cmp->port_details == port_details) + continue; + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\t\tphy_id=%d sas_address=0x%018llX\n", +@@ -1018,12 +1027,12 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc + if (!phy_info_cmp->port_details->num_phys) + kfree(phy_info_cmp->port_details); + } else +- phy_info_cmp->sas_port_add_phy=1; ++ phy_info_cmp->sas_port_add_phy = 1; + /* + * Adding a phy to a port + */ + phy_info_cmp->port_details = port_details; +- if (phy_info_cmp->phy_id < 64 ) ++ if (phy_info_cmp->phy_id < 64) + port_details->phy_bitmask |= + (1 << phy_info_cmp->phy_id); + port_details->num_phys++; +@@ -1038,11 +1047,12 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc + continue; + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: [%p]: phy_id=%02d num_phys=%02d " +- "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, ++ "bitmask=0x%016llX\n", ioc->name, __func__, + port_details, i, port_details->num_phys, + (unsigned long long)port_details->phy_bitmask)); +- dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", +- ioc->name, port_details->port, port_details->rphy)); ++ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "\t\tport = %p rphy=%p\n", ++ ioc->name, port_details->port, port_details->rphy)); + } + dsaswideprintk(ioc, printk("\n")); + mutex_unlock(&ioc->sas_topology_mutex); +@@ -1089,7 +1099,7 @@ mptsas_queue_device_delete(MPT_ADAPTER * + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", +- ioc->name, __FUNCTION__, __LINE__); ++ ioc->name, __func__, __LINE__); + return; + } + memcpy(fw_event->event_data, sas_event_data, +@@ -1109,7 +1119,7 @@ mptsas_queue_rescan(MPT_ADAPTER *ioc) + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", +- ioc->name, __FUNCTION__, __LINE__); ++ ioc->name, __func__, __LINE__); + return; + } + fw_event->event = -1; +@@ -1139,8 +1149,9 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 + return 0; + + if ((mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc)) == NULL) { +- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", +- ioc->name,__FUNCTION__, __LINE__)); ++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "%s, no msg frames @%d!!\n", ++ ioc->name, __func__, __LINE__)); + goto out_fail; + } + +@@ -1150,7 +1161,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 + /* Format the Request + */ + pScsiTm = (SCSITaskMgmt_t *) mf; +- memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); ++ memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->TargetID = id; + pScsiTm->Bus = channel; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; +@@ -1201,8 +1212,9 @@ mptsas_target_reset_queue(MPT_ADAPTER *i + target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), + GFP_ATOMIC); + if (!target_reset_list) { +- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", +- ioc->name,__FUNCTION__, __LINE__)); ++ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "%s, failed to allocate mem @%d..!!\n", ++ ioc->name, __func__, __LINE__)); + return; + } + +@@ -1227,7 +1239,7 @@ static int + mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) + { + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); +- struct list_head *head = &hd->target_reset_list; ++ struct list_head *head = &hd->target_reset_list; + struct mptsas_target_reset_event *target_reset_list; + u8 id, channel; + SCSITaskMgmtReply_t *pScsiTmReply; +@@ -1300,7 +1312,8 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *io + */ + list_del(&target_reset_list->list); + if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) +- mptsas_queue_device_delete(ioc, &target_reset_list->sas_event_data); ++ mptsas_queue_device_delete(ioc, ++ &target_reset_list->sas_event_data); + + + /* +@@ -1311,8 +1324,8 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *io + if (list_empty(head)) + return 1; + +- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, +- list); ++ target_reset_list = list_entry(head->next, ++ struct mptsas_target_reset_event, list); + + id = target_reset_list->sas_event_data.TargetID; + channel = target_reset_list->sas_event_data.Bus; +@@ -1344,19 +1357,19 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int r + if (!hd->ioc) + goto out; + +- switch(reset_phase) { ++ switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + mptsas_fw_event_off(ioc); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->sas_mgmt.done); +@@ -1473,7 +1486,7 @@ mptsas_get_lun_number(MPT_ADAPTER *ioc, + &lun_data_dma); + if (!lun_data) { + printk(MYIOC_s_ERR_FMT "%s: pci_alloc_consistent(%d) FAILED!\n", +- ioc->name, __FUNCTION__, lun_data_len); ++ ioc->name, __func__, lun_data_len); + rc = -ENOMEM; + goto out; + } +@@ -1481,7 +1494,7 @@ mptsas_get_lun_number(MPT_ADAPTER *ioc, + iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); + if (!iocmd) { + printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", +- ioc->name, __FUNCTION__, sizeof(INTERNAL_CMD)); ++ ioc->name, __func__, sizeof(INTERNAL_CMD)); + rc = -ENOMEM; + goto out; + } +@@ -1499,14 +1512,14 @@ mptsas_get_lun_number(MPT_ADAPTER *ioc, + if ((rc = mptscsih_do_cmd(hd, iocmd)) < 0) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "report_luns failed due to rc=0x%x\n", ioc->name, +- __FUNCTION__, channel, id, rc); ++ __func__, channel, id, rc); + goto out; + } + + if (rc != MPT_SCANDV_GOOD) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "report_luns failed due to rc=0x%x\n", ioc->name, +- __FUNCTION__, channel, id, rc); ++ __func__, channel, id, rc); + rc = -rc; + goto out; + } +@@ -1576,7 +1589,7 @@ mptsas_test_unit_ready(MPT_ADAPTER *ioc, + iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); + if (!iocmd) { + printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", +- __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD)); ++ __func__, ioc->name, sizeof(INTERNAL_CMD)); + return DEVICE_ERROR; + } + +@@ -1595,31 +1608,31 @@ mptsas_test_unit_ready(MPT_ADAPTER *ioc, + + retry: + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_channel=%d " +- "fw_id=%d retry=%d\n", ioc->name, __FUNCTION__, channel, id, count)); ++ "fw_id=%d retry=%d\n", ioc->name, __func__, channel, id, count)); + rc = mptscsih_do_cmd(hd, iocmd); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rc=0x%02x\n", +- ioc->name, __FUNCTION__, rc)); ++ ioc->name, __func__, rc)); + if (rc < 0) { + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "tur failed due to timeout\n", ioc->name, +- __FUNCTION__, channel, id); ++ __func__, channel, id); + goto tur_done; + } + +- switch(rc) { ++ switch (rc) { + case MPT_SCANDV_GOOD: + state = DEVICE_READY; + goto tur_done; + case MPT_SCANDV_BUSY: + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " + "fw_channel=%d fw_id=%d : device busy\n", +- ioc->name, __FUNCTION__, channel, id)); ++ ioc->name, __func__, channel, id)); + state = DEVICE_RETRY; + break; + case MPT_SCANDV_DID_RESET: + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " + "fw_channel=%d fw_id=%d : did reset\n", +- ioc->name, __FUNCTION__, channel, id)); ++ ioc->name, __func__, channel, id)); + state = DEVICE_RETRY; + break; + case MPT_SCANDV_SENSE: +@@ -1630,7 +1643,7 @@ mptsas_test_unit_ready(MPT_ADAPTER *ioc, + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: " + "fw_channel=%d fw_id=%d : [sense_key,asc," + "ascq]: [0x%02x,0x%02x,0x%02x]\n", ioc->name, +- __FUNCTION__, channel, id, skey, asc, ascq)); ++ __func__, channel, id, skey, asc, ascq)); + + if (skey == UNIT_ATTENTION) { + if (!retry_ua) { +@@ -1656,7 +1669,7 @@ mptsas_test_unit_ready(MPT_ADAPTER *ioc, + break; + } + } else if (skey == ILLEGAL_REQUEST) { +- /* try sending a tur to a non-zero lun number */ ++ /* try sending a tur to a non-zero lun number */ + if (!iocmd->lun && !mptsas_get_lun_number(ioc, + channel, id, &iocmd->lun) && iocmd->lun) + goto retry; +@@ -1664,25 +1677,25 @@ mptsas_test_unit_ready(MPT_ADAPTER *ioc, + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d : " + "tur failed due to [sense_key,asc,ascq]: " + "[0x%02x,0x%02x,0x%02x]\n", ioc->name, +- __FUNCTION__, channel, id, skey, asc, ascq); ++ __func__, channel, id, skey, asc, ascq); + goto tur_done; + case MPT_SCANDV_SELECTION_TIMEOUT: + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "tur failed due to no device\n", ioc->name, +- __FUNCTION__, channel, ++ __func__, channel, + id); + goto tur_done; + case MPT_SCANDV_SOME_ERROR: + printk(MYIOC_s_ERR_FMT "%s: fw_channel=%d fw_id=%d: " + "tur failed due to some error\n", ioc->name, +- __FUNCTION__, ++ __func__, + channel, id); + goto tur_done; + default: + printk(MYIOC_s_ERR_FMT + "%s: fw_channel=%d fw_id=%d: tur failed due to " +- "unknown rc=0x%02x\n", ioc->name, __FUNCTION__, +- channel, id, rc ); ++ "unknown rc=0x%02x\n", ioc->name, __func__, ++ channel, id, rc); + goto tur_done; + } + tur_done: +@@ -1705,19 +1718,19 @@ mptsas_issue_tlr(MPT_SCSI_HOST *hd, stru + u8 rc; + MPT_ADAPTER *ioc = hd->ioc; + +- if ( sdev->inquiry[8] == 'H' && ++ if (sdev->inquiry[8] == 'H' && + sdev->inquiry[9] == 'P' && + sdev->inquiry[10] == ' ' && + sdev->inquiry[11] == ' ' && + sdev->inquiry[12] == ' ' && + sdev->inquiry[13] == ' ' && + sdev->inquiry[14] == ' ' && +- sdev->inquiry[15] == ' ' ) { ++ sdev->inquiry[15] == ' ') { + + iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); + if (!iocmd) { + printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", +- __FUNCTION__, ioc->name, sizeof(INTERNAL_CMD)); ++ __func__, ioc->name, sizeof(INTERNAL_CMD)); + return; + } + iocmd->id = vdevice->vtarget->id; +@@ -1773,7 +1786,7 @@ mptsas_slave_configure(struct scsi_devic + mptsas_add_device_component_starget(ioc, scsi_target(sdev)); + + if (sdev->type == TYPE_TAPE && +- (ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_TLR )) ++ (ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_TLR)) + mptsas_issue_tlr(hd, sdev); + out: + +@@ -1815,7 +1828,7 @@ mptsas_target_alloc(struct scsi_target * + kfree(vtarget); + return -ENXIO; + } +- for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) ++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) + channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + vtarget->raidVolume = 1; +@@ -1834,9 +1847,11 @@ mptsas_target_alloc(struct scsi_target * + mptsas_set_starget(&p->phy_info[i], starget); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT +- "add device: fw_channel %d, fw_id %d, phy %d, sas_addr 0x%llx\n", ++ "add device: fw_channel %d, fw_id %d, phy %d," ++ " sas_addr 0x%llx\n", + ioc->name, p->phy_info[i].attached.channel, +- p->phy_info[i].attached.id, p->phy_info[i].attached.phy_id, ++ p->phy_info[i].attached.id, ++ p->phy_info[i].attached.phy_id, + (unsigned long long)p->phy_info[i].attached.sas_address); + + /* +@@ -1899,9 +1914,9 @@ mptsas_target_destroy(struct scsi_target + starget_printk(KERN_INFO, starget, MYIOC_s_FMT + "delete device: fw_channel %d, fw_id %d, phy %d, " + "sas_addr 0x%llx\n", ioc->name, +- p->phy_info[i].attached.channel, ++ p->phy_info[i].attached.channel, + p->phy_info[i].attached.id, +- p->phy_info[i].attached.phy_id, (unsigned long long) ++ p->phy_info[i].attached.phy_id, (unsigned long long) + p->phy_info[i].attached.sas_address); + + mptsas_port_delete(ioc, p->phy_info[i].port_details); +@@ -2000,8 +2015,7 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, voi + if (ioc->sas_discovery_quiesce_io) + return SCSI_MLQUEUE_HOST_BUSY; + +-// scsi_print_command(SCpnt); +- return mptscsih_qcmd(SCpnt,done); ++ return mptscsih_qcmd(SCpnt, done); + } + + +@@ -2046,7 +2060,6 @@ static int mptsas_get_linkerrors(struct + dma_addr_t dma_handle; + int error; + +- /* FIXME: only have link errors on local phys */ + if (!scsi_is_sas_phy_local(phy)) + return -EINVAL; + +@@ -2140,7 +2153,6 @@ static int mptsas_phy_reset(struct sas_p + unsigned long timeleft; + int error = -ERESTARTSYS; + +- /* FIXME: fusion doesn't allow non-local phy reset */ + if (!scsi_is_sas_phy_local(phy)) + return -EINVAL; + +@@ -2192,7 +2204,7 @@ static int mptsas_phy_reset(struct sas_p + reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; + if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { + printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", +- ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); ++ ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); + error = -ENXIO; + goto out_unlock; + } +@@ -2275,11 +2287,160 @@ mptsas_get_bay_identifier(struct sas_rph + return rc; + } + ++static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, ++ struct request *req) ++{ ++ MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; ++ MPT_FRAME_HDR *mf; ++ SmpPassthroughRequest_t *smpreq; ++ struct request *rsp = req->next_rq; ++ int ret; ++ int flagsLength; ++ unsigned long timeleft; ++ char *psge; ++ dma_addr_t dma_addr_in = 0; ++ dma_addr_t dma_addr_out = 0; ++ u64 sas_address = 0; ++ ++ if (!rsp) { ++ printk(MYIOC_s_ERR_FMT ++ "%s: the smp response space is missing\n", ++ ioc->name, __func__); ++ return -EINVAL; ++ } ++ ++ /* do we need to support multiple segments? */ ++ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { ++ printk(MYIOC_s_ERR_FMT ++ "%s: multiple segments req %u %u, rsp %u %u\n", ++ ioc->name, __func__, req->bio->bi_vcnt, req->data_len, ++ rsp->bio->bi_vcnt, rsp->data_len); ++ return -EINVAL; ++ } ++ ++ ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); ++ if (ret) ++ goto out; ++ ++ mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); ++ if (!mf) { ++ ret = -ENOMEM; ++ goto out_unlock; ++ } ++ ++ smpreq = (SmpPassthroughRequest_t *)mf; ++ memset(smpreq, 0, sizeof(*smpreq)); ++ ++ smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); ++ smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; ++ ++ if (rphy) ++ sas_address = rphy->identify.sas_address; ++ else { ++ struct mptsas_portinfo *port_info; ++ ++ mutex_lock(&ioc->sas_topology_mutex); ++ port_info = ioc->hba_port_info; ++ if (port_info && port_info->phy_info) ++ sas_address = ++ port_info->phy_info[0].phy->identify.sas_address; ++ mutex_unlock(&ioc->sas_topology_mutex); ++ } ++ ++ *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); ++ ++ psge = (char *) ++ (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); ++ ++ /* request */ ++ ++ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_SYSTEM_ADDRESS | ++ MPI_SGE_FLAGS_HOST_TO_IOC | ++ MPI_SGE_FLAGS_END_OF_BUFFER; ++ ++ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; ++ ++ flagsLength |= (req->data_len - 4); ++ ++ dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), ++ req->data_len, PCI_DMA_BIDIRECTIONAL); ++ if (!dma_addr_out) ++ goto put_mf; ++ ioc->add_sge(psge, flagsLength, dma_addr_out); ++ psge += ioc->SGE_size; ++ ++ /* response */ ++ flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | ++ MPI_SGE_FLAGS_SYSTEM_ADDRESS | ++ MPI_SGE_FLAGS_IOC_TO_HOST | ++ MPI_SGE_FLAGS_END_OF_BUFFER; ++ ++ flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; ++ flagsLength |= rsp->data_len + 4; ++ dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), ++ rsp->data_len, PCI_DMA_BIDIRECTIONAL); ++ if (!dma_addr_in) ++ goto out_unmap; ++ ++ ioc->add_sge(psge, flagsLength, dma_addr_in); ++ ++ INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) ++ mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); ++ ++ timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); ++ if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { ++ ret = -ETIME; ++ mpt_free_msg_frame(ioc, mf); ++ mf = NULL; ++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) ++ goto out_unmap; ++ if (!timeleft) { ++ if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) ++ mpt_HardResetHandler(ioc, CAN_SLEEP); ++ } ++ goto out_unmap; ++ } ++ ++ mf = NULL; ++ ++ if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { ++ SmpPassthroughReply_t *smprep; ++ ++ smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; ++ memcpy(req->sense, smprep, sizeof(*smprep)); ++ req->sense_len = sizeof(*smprep); ++ req->data_len = 0; ++ rsp->data_len -= smprep->ResponseDataLength; ++ } else { ++ printk(MYIOC_s_ERR_FMT ++ "%s: smp passthru reply failed to be returned\n", ++ ioc->name, __func__); ++ ret = -ENXIO; ++ } ++out_unmap: ++ if (dma_addr_out) ++ pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, ++ PCI_DMA_BIDIRECTIONAL); ++ if (dma_addr_in) ++ pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, ++ PCI_DMA_BIDIRECTIONAL); ++put_mf: ++ if (mf) ++ mpt_free_msg_frame(ioc, mf); ++out_unlock: ++ CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) ++ mutex_unlock(&ioc->sas_mgmt.mutex); ++out: ++ return ret; ++} ++ + static struct sas_function_template mptsas_transport_functions = { + .get_linkerrors = mptsas_get_linkerrors, + .get_enclosure_identifier = mptsas_get_enclosure_identifier, + .get_bay_identifier = mptsas_get_bay_identifier, + .phy_reset = mptsas_phy_reset, ++ .smp_handler = mptsas_smp_handler, + }; + + static struct scsi_transport_template *mptsas_transport_template; +@@ -2338,7 +2499,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, + + port_info->num_phys = buffer->NumPhys; + port_info->phy_info = kcalloc(port_info->num_phys, +- sizeof(struct mptsas_phyinfo),GFP_KERNEL); ++ sizeof(struct mptsas_phyinfo), GFP_KERNEL); + if (!port_info->phy_info) { + error = -ENOMEM; + goto out_free_consistent; +@@ -2659,7 +2820,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc + /* save config data */ + port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; + port_info->phy_info = kcalloc(port_info->num_phys, +- sizeof(struct mptsas_phyinfo),GFP_KERNEL); ++ sizeof(struct mptsas_phyinfo), GFP_KERNEL); + if (!port_info->phy_info) { + error = -ENOMEM; + goto out_free_consistent; +@@ -2970,7 +3131,7 @@ static int mptsas_probe_one_phy(struct d + if (error) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, +- __FUNCTION__, __LINE__)); ++ __func__, __LINE__)); + goto out; + } + mptsas_set_port(ioc, phy_info, port); +@@ -3036,7 +3197,7 @@ static int mptsas_probe_one_phy(struct d + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, +- __FUNCTION__, __LINE__)); ++ __func__, __LINE__)); + goto out; + } + +@@ -3045,7 +3206,7 @@ static int mptsas_probe_one_phy(struct d + if (error) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, +- __FUNCTION__, __LINE__)); ++ __func__, __LINE__)); + sas_rphy_free(rphy); + goto out; + } +@@ -3069,7 +3230,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) + int error = -ENOMEM, i; + + hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); +- if (! hba) ++ if (!hba) + goto out; + + error = mptsas_sas_io_unit_pg0(ioc, hba); +@@ -3195,7 +3356,7 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); + if (!num_paths) + goto out; +- phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + goto out; +@@ -3208,7 +3369,8 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT + (channel == phys_disk->Path[i].PhysDiskBus)) { + memcpy(&sas_address, &phys_disk->Path[i].WWID, + sizeof(u64)); +- phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_address); ++ phy_info = mptsas_find_phyinfo_by_sas_address(ioc, ++ sas_address); + goto out; + } + } +@@ -3230,7 +3392,8 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT + continue; + if (port_info->phy_info[i].attached.phys_disk_num == ~0) + continue; +- if (port_info->phy_info[i].attached.phys_disk_num == phys_disk_num && ++ if (port_info->phy_info[i].attached.phys_disk_num == ++ phys_disk_num && + port_info->phy_info[i].attached.id == id && + port_info->phy_info[i].attached.channel == channel) + phy_info = &port_info->phy_info[i]; +@@ -3275,7 +3438,6 @@ mptsas_reprobe_target(struct scsi_target + * @id: + * + * +- * TODO: check for hotspares + **/ + static void + mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) +@@ -3363,10 +3525,10 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, + char *ds = NULL; + u8 fw_id; + +- if (!phy_info){ ++ if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, +- __FUNCTION__, __LINE__)); ++ __func__, __LINE__)); + return 1; + } + +@@ -3375,7 +3537,7 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, + if (mptsas_get_rphy(phy_info)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + return 2; + } + +@@ -3383,7 +3545,7 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + return 3; + } + +@@ -3408,7 +3570,7 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + return 5; /* non-fatal: an rphy can be added later */ + } + +@@ -3416,7 +3578,7 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, + if (sas_rphy_add(rphy)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + sas_rphy_free(rphy); + return 6; + } +@@ -3439,7 +3601,7 @@ mptsas_del_end_device(MPT_ADAPTER *ioc, + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info_parent; + int i; +- struct scsi_target * starget; ++ struct scsi_target *starget; + char *ds = NULL; + u8 fw_id; + u64 sas_address; +@@ -3453,14 +3615,14 @@ mptsas_del_end_device(MPT_ADAPTER *ioc, + if (!phy_info->port_details) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + return; + } + rphy = mptsas_get_rphy(phy_info); + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + return; + } + if (phy_info->attached.device_info & +@@ -3485,13 +3647,13 @@ mptsas_del_end_device(MPT_ADAPTER *ioc, + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, fw_id, __LINE__)); ++ __func__, fw_id, __LINE__)); + return; + } + port_info = phy_info->portinfo; + phy_info_parent = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { +- if(!phy_info_parent->phy) ++ if (!phy_info_parent->phy) + continue; + if (phy_info_parent->attached.sas_address != + sas_address) +@@ -3507,11 +3669,11 @@ mptsas_del_end_device(MPT_ADAPTER *ioc, + "delete port %d, sas_addr (0x%llx)\n", ioc->name, + port->port_identifier, (unsigned long long)sas_address); + sas_port_delete(port); +-// mptsas_port_delete(ioc, phy_info->port_details); + } + + struct mptsas_phyinfo * +-mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, struct mptsas_devinfo *sas_device) ++mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, ++ struct mptsas_devinfo *sas_device) + { + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; +@@ -3526,7 +3688,7 @@ mptsas_refreshing_device_handles(MPT_ADA + goto out; + mutex_lock(&ioc->sas_topology_mutex); + for (i = 0; i < port_info->num_phys; i++) { +- if(port_info->phy_info[i].attached.sas_address != ++ if (port_info->phy_info[i].attached.sas_address != + sas_device->sas_address) + continue; + port_info->phy_info[i].attached.channel = sas_device->channel; +@@ -3555,7 +3717,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + struct mptsas_hotplug_event *hot_plug_info) + { + struct mptsas_phyinfo *phy_info; +- struct scsi_target * starget; ++ struct scsi_target *starget; + struct mptsas_devinfo sas_device; + VirtTarget *vtarget; + enum device_state state; +@@ -3636,17 +3798,17 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + (hot_plug_info->channel << 8) + hot_plug_info->id)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + + phy_info = mptsas_find_phyinfo_by_sas_address( + ioc, sas_device.sas_address); + +- if (!phy_info){ ++ if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + +@@ -3654,7 +3816,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + if (!starget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + +@@ -3662,7 +3824,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + if (!vtarget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + +@@ -3688,7 +3850,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + (hot_plug_info->channel << 8) + hot_plug_info->id)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", +- ioc->name, __FUNCTION__, ++ ioc->name, __func__, + hot_plug_info->id, __LINE__)); + break; + } +@@ -3698,7 +3860,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + +@@ -3706,7 +3868,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + if (!starget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + +@@ -3714,14 +3876,14 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, st + if (!vtarget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + + if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, +- __FUNCTION__, hot_plug_info->id, __LINE__)); ++ __func__, hot_plug_info->id, __LINE__)); + break; + } + +@@ -3800,7 +3962,7 @@ mptsas_send_sas_event(struct fw_event_wo + if ((device_info & + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | +- MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) { ++ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { + mptsas_free_fw_event(ioc, fw_event); + return; + } +@@ -3840,9 +4002,7 @@ mptsas_send_sas_event(struct fw_event_wo + break; + + case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: +- /* TODO */ + case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: +- /* TODO */ + default: + mptsas_free_fw_event(ioc, fw_event); + break; +@@ -3892,7 +4052,7 @@ mptsas_send_raid_event(struct fw_event_w + } + + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: " +- "ReasonCode=%02x\n", ioc->name, __FUNCTION__, ++ "ReasonCode=%02x\n", ioc->name, __func__, + raid_event_data->ReasonCode)); + + switch (raid_event_data->ReasonCode) { +@@ -3988,8 +4148,8 @@ mptsas_send_raid_event(struct fw_event_w + * + **/ + static int +-mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, int task_context, ulong timeout, +- u8 *issue_reset) ++mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, ++ int task_context, ulong timeout, u8 *issue_reset) + { + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; +@@ -4068,7 +4228,7 @@ mptsas_broadcast_primative_work(struct f + VirtDevice *vdevice; + int ii; + struct scsi_cmnd *sc; +- SCSITaskMgmtReply_t * pScsiTmReply; ++ SCSITaskMgmtReply_t *pScsiTmReply; + u8 issue_reset; + int task_context; + u8 channel, id; +@@ -4077,7 +4237,7 @@ mptsas_broadcast_primative_work(struct f + u32 query_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s - enter\n", ioc->name, __FUNCTION__)); ++ "%s - enter\n", ioc->name, __func__)); + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { +@@ -4133,7 +4293,7 @@ mptsas_broadcast_primative_work(struct f + out: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - exit, query_count = %d termination_count = %d\n", +- ioc->name, __FUNCTION__, query_count, termination_count)); ++ ioc->name, __func__, query_count, termination_count)); + + ioc->broadcast_aen_busy = 0; + mpt_clear_taskmgmt_in_progress_flag(ioc); +@@ -4141,7 +4301,7 @@ mptsas_broadcast_primative_work(struct f + + if (issue_reset) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP)) + mpt_HardResetHandler(ioc, CAN_SLEEP); + } +@@ -4159,7 +4319,7 @@ mptsas_send_ir2_event(struct fw_event_wo + { + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; +- MPI_EVENT_DATA_IR2 * ir2_data; ++ MPI_EVENT_DATA_IR2 *ir2_data; + u8 reasonCode; + RaidPhysDiskPage0_t phys_disk; + +@@ -4168,7 +4328,7 @@ mptsas_send_ir2_event(struct fw_event_wo + reasonCode = ir2_data->ReasonCode; + + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "Entering %s: " +- "ReasonCode=%02x\n", ioc->name,__FUNCTION__, reasonCode)); ++ "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); + + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = ir2_data->TargetID; +@@ -4255,7 +4415,7 @@ mptsas_expander_refresh(MPT_ADAPTER *ioc + + static void + mptsas_expander_event_add(MPT_ADAPTER *ioc, +- MpiEventDataSasExpanderStatusChange_t* expander_data) ++ MpiEventDataSasExpanderStatusChange_t *expander_data) + { + struct mptsas_portinfo *port_info; + int i; +@@ -4267,7 +4427,7 @@ mptsas_expander_event_add(MPT_ADAPTER *i + port_info->num_phys = (expander_data->NumPhys) ? + expander_data->NumPhys : 1; + port_info->phy_info = kcalloc(port_info->num_phys, +- sizeof(struct mptsas_phyinfo),GFP_KERNEL); ++ sizeof(struct mptsas_phyinfo), GFP_KERNEL); + if (!port_info->phy_info) + BUG(); + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); +@@ -4351,8 +4511,8 @@ mptsas_expander_delete(MPT_ADAPTER *ioc, + u64 expander_sas_address; + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo buffer; +- struct mptsas_portinfo_details * port_details; +- struct sas_port * port; ++ struct mptsas_portinfo_details *port_details; ++ struct sas_port *port; + + if (!port_info) + return; +@@ -4388,7 +4548,7 @@ mptsas_expander_delete(MPT_ADAPTER *ioc, + phy_info = parent->phy_info; + port = NULL; + for (i = 0; i < parent->num_phys; i++, phy_info++) { +- if(!phy_info->phy) ++ if (!phy_info->phy) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) +@@ -4438,7 +4598,7 @@ static void + mptsas_send_expander_event(struct fw_event_work *fw_event) + { + MPT_ADAPTER *ioc; +- MpiEventDataSasExpanderStatusChange_t* expander_data; ++ MpiEventDataSasExpanderStatusChange_t *expander_data; + struct mptsas_portinfo *port_info; + __le64 sas_address; + int i; +@@ -4492,7 +4652,7 @@ mptsas_expander_add(MPT_ADAPTER *ioc, u1 + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, +- __FUNCTION__, __LINE__)); ++ __func__, __LINE__)); + return NULL; + } + port_info->num_phys = buffer.num_phys; +@@ -4589,7 +4749,7 @@ mptsas_handle_queue_full_event(struct fw + current_depth = le16_to_cpu(qfull_data->CurrentDepth); + + /* if hidden raid component, look for the volume id */ +- down(&ioc->sas_device_info_mutex); ++ mutex_lock(&ioc->sas_device_info_mutex); + if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { +@@ -4622,7 +4782,7 @@ mptsas_handle_queue_full_event(struct fw + } + + out: +- up(&ioc->sas_device_info_mutex); ++ mutex_unlock(&ioc->sas_device_info_mutex); + + if (id != -1) { + shost_for_each_device(sdev, ioc->sh) { +@@ -4643,8 +4803,8 @@ mptsas_handle_queue_full_event(struct fw + depth); + else if (depth < 0) + sdev_printk(KERN_INFO, sdev, +- "Tagged Command Queueing is being " +- "disabled\n"); ++ "Tagged Command Queueing is being " ++ "disabled\n"); + else if (depth == 0) + sdev_printk(KERN_INFO, sdev, + "Queue depth not changed yet\n"); +@@ -4671,7 +4831,7 @@ mptsas_firmware_event_work(struct work_s + /* special rescan topology handling */ + if (fw_event->event == -1) { + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: rescan after " +- "reset\n", ioc->name,__FUNCTION__)); ++ "reset\n", ioc->name, __func__)); + mptsas_not_responding_devices(ioc); + mptsas_scan_sas_topology(ioc); + mptsas_free_fw_event(ioc, fw_event); +@@ -4685,7 +4845,7 @@ mptsas_firmware_event_work(struct work_s + } + + devtprintk(ioc, printk(MYIOC_s_INFO_FMT "%s: fw_event=(0x%p), " +- "event = (0x%02x)\n", ioc->name,__FUNCTION__, fw_event, ++ "event = (0x%02x)\n", ioc->name, __func__, fw_event, + (fw_event->event & 0xFF))); + + switch (fw_event->event) { +@@ -4805,7 +4965,7 @@ mptsas_event_process(MPT_ADAPTER *ioc, E + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, +- __FUNCTION__, __LINE__); ++ __func__, __LINE__); + return 0; + } + memcpy(fw_event->event_data, reply->Data, event_data_sz); +@@ -4835,7 +4995,7 @@ static void mptsas_volume_delete(MPT_ADA + goto release_sdev; + out: + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " +- "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,id); ++ "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); + scsi_remove_device(sdev); + release_sdev: + scsi_device_put(sdev); +@@ -4953,7 +5113,7 @@ mptsas_probe_expanders(MPT_ADAPTER *ioc) + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, +- __FUNCTION__, __LINE__)); ++ __func__, __LINE__)); + return; + } + port_info->num_phys = buffer.num_phys; +@@ -5000,7 +5160,7 @@ mptsas_probe_devices(MPT_ADAPTER *ioc) + + state = DEVICE_RETRY; + retry_count = 0; +- while(state == DEVICE_RETRY) { ++ while (state == DEVICE_RETRY) { + state = mptsas_test_unit_ready(ioc, sas_device.channel, + sas_device.id, retry_count++); + ssleep(1); +@@ -5032,7 +5192,7 @@ mptsas_scan_sas_topology(MPT_ADAPTER *io + if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || + !ioc->raid_data.pIocPg2->NumActiveVolumes) + return; +- for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { ++ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if ((sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0))) { + scsi_device_put(sdev); +@@ -5196,11 +5356,12 @@ mptsas_probe(struct pci_dev *pdev, const + hd->last_queue_full = 0; + ioc->disable_hotplug_remove = mpt_disable_hotplug_remove; + if (ioc->disable_hotplug_remove) +- printk(MYIOC_s_INFO_FMT "disabling hotplug remove\n", ioc->name); ++ printk(MYIOC_s_INFO_FMT ++ "disabling hotplug remove\n", ioc->name); + + INIT_LIST_HEAD(&hd->target_reset_list); + INIT_LIST_HEAD(&ioc->sas_device_info_list); +- init_MUTEX(&ioc->sas_device_info_mutex); ++ mutex_init(&ioc->sas_device_info_mutex); + + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + +Index: linux-2.6.27/drivers/message/fusion/mptsas.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptsas.h ++++ linux-2.6.27/drivers/message/fusion/mptsas.h +@@ -84,9 +84,12 @@ struct sas_device_info { + u16 slot; /* enclosure slot id */ + u64 enclosure_logical_id; /*enclosure address */ + u8 is_logical_volume; /* is this logical volume */ +- u8 is_hidden_raid_component; /* this belongs to volume */ +- u8 volume_id; /* this valid when is_hidden_raid_component set */ +- u8 is_cached; /* cached data for a removed device */ ++ /* this belongs to volume */ ++ u8 is_hidden_raid_component; ++ /* this valid when is_hidden_raid_component set */ ++ u8 volume_id; ++ /* cached data for a removed device */ ++ u8 is_cached; + }; + + struct mptsas_hotplug_event { +Index: linux-2.6.27/drivers/message/fusion/mptscsih.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptscsih.c ++++ linux-2.6.27/drivers/message/fusion/mptscsih.c +@@ -102,7 +102,8 @@ static void mptscsih_copy_sense_data(str + + int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); + int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +-static void mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice); ++static void mptscsih_synchronize_cache(struct scsi_device *sdev, ++ MPT_SCSI_HOST *hd, VirtDevice *vdevice); + + void mptscsih_remove(struct pci_dev *); + void mptscsih_shutdown(struct pci_dev *); +@@ -142,12 +143,16 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER + offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; + chain_idx = offset / ioc->req_sz; + rc = SUCCESS; +- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", +- ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); ++ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "getFreeChainBuffer chainBuf=%p ChainBuffer=%p" ++ " offset=%d chain_idx=%d\n", ++ ioc->name, chainBuf, ioc->ChainBuffer, offset, ++ chain_idx)); + } else { + rc = FAILED; + chain_idx = MPT_HOST_NO_CHAIN; +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "getFreeChainBuffer failed\n", + ioc->name)); + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); +@@ -216,7 +221,7 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct + */ + + nextSGEset: +- numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size ); ++ numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size); + numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; + + sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir; +@@ -265,7 +270,8 @@ nextSGEset: + * Update the chain element + * Offset and Length fields. + */ +- ioc->add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); ++ ioc->add_chain((char *)chainSge, 0, sgeOffset, ++ ioc->ChainBufferDMA + chain_dma_off); + } else { + /* The current buffer is the original MF + * and there is no Chain buffer. +@@ -313,7 +319,8 @@ nextSGEset: + */ + u8 nextChain = (u8) (sgeOffset >> 2); + sgeOffset += ioc->SGE_size; +- ioc->add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); ++ ioc->add_chain((char *)chainSge, nextChain, sgeOffset, ++ ioc->ChainBufferDMA + chain_dma_off); + } else { + /* The original MF buffer requires a chain buffer - + * set the offset. +@@ -392,7 +399,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER * + + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", +- ioc->name,__FUNCTION__)); ++ ioc->name,__func__)); + return; + } + +@@ -525,9 +532,11 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, s + scsi_print_command(sc); + printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n", + ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun); +- printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, resid = %d\n", ++ printk(MYIOC_s_DEBUG_FMT ++ "\trequest_len = %d, underflow = %d, resid = %d\n", + ioc->name, scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc)); +- printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, sc->result = %08X\n", ++ printk(MYIOC_s_DEBUG_FMT ++ "\ttag = %d, transfer_count = %d, sc->result = %08X\n", + ioc->name, le16_to_cpu(pScsiReply->TaskTag), + le32_to_cpu(pScsiReply->TransferCount), sc->result); + +@@ -590,7 +599,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) { + printk(MYIOC_s_WARN_FMT + "Received a mf that was already freed\n", ioc->name); +- printk (MYIOC_s_WARN_FMT ++ printk(MYIOC_s_WARN_FMT + "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", + ioc->name, req_idx, req_idx_MR, mf, mr, + mptscsih_get_scsi_lookup(ioc, req_idx_MR)); +@@ -715,11 +724,12 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + } + } + } else if (ioc->bus_type == FC) { +- /* The FC IOC may kill a request for variety of reasons, +- some of which may be recovered by a retry, some which +- are unlikely to be recovered. Return DID_ERROR instead +- of DID_RESET to permit retry of the command, just not +- an infinite number of them */ ++ /* The FC IOC may kill a request for variety ++ * of reasons, some of which may be recovered ++ * by a retry, some which are unlikely to be ++ * recovered. Return DID_ERROR instead of ++ * DID_RESET to permit retry of the command, ++ * just not an infinite number of them */ + sc->result = DID_ERROR << 16; + break; + } +@@ -735,7 +745,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F + sc->result = DID_RESET << 16; + + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ +- if ( ioc->bus_type == FC ) ++ if (ioc->bus_type == FC) + sc->result = DID_ERROR << 16; + else + sc->result = DID_RESET << 16; +@@ -1421,8 +1431,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, v + */ + if (datalen == 0) { + /* Add a NULL SGE */ +- ioc->add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, +- (dma_addr_t) -1); ++ ioc->add_sge((char *)&pScsiReq->SGL, ++ MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); + } else { + /* Add a 32 or 64 bit SGE */ + if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) +@@ -1523,8 +1533,8 @@ mptscsih_scandv_bus_reset(MPT_ADAPTER *i + /* Send request + */ + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { +- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", +- ioc->name)); ++ dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ++ "TaskMgmt, no msg frames!!\n", ioc->name)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + retval = -ENOMEM; + goto out; +@@ -1544,26 +1554,27 @@ mptscsih_scandv_bus_reset(MPT_ADAPTER *i + pScsiTm->Reserved = 0; + pScsiTm->Reserved1 = 0; + pScsiTm->TaskMsgContext = 0; +- for (ii= 0; ii < 8; ii++) ++ for (ii = 0; ii < 8; ii++) + pScsiTm->LUN[ii] = 0; +- for (ii=0; ii < 7; ii++) ++ for (ii = 0; ii < 7; ii++) + pScsiTm->Reserved2[ii] = 0; + + switch (ioc->bus_type) { +- case FC: +- timeout = 40; +- break; +- case SAS: +- timeout = 30; +- break; +- case SPI: +- default: +- timeout = 2; +- break; ++ case FC: ++ timeout = 40; ++ break; ++ case SAS: ++ timeout = 30; ++ break; ++ case SPI: ++ default: ++ timeout = 10; ++ break; + } + +- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", +- ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); ++ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "TaskMgmt type=%d timeout=%ld\n", ioc->name, ++ MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout)); + + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) +@@ -1576,7 +1587,8 @@ mptscsih_scandv_bus_reset(MPT_ADAPTER *i + retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, + sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + if (retval != 0) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt send_handshake FAILED!" ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "TaskMgmt send_handshake FAILED!" + " (ioc %p, mf %p, rc=%d) \n", ioc->name, + ioc, mf, retval)); + mpt_clear_taskmgmt_in_progress_flag(ioc); +@@ -1642,19 +1654,20 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_PRE_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + hd = shost_priv(ioc->sh); + mptscsih_flush_running_cmds(hd); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: MPT_IOC_POST_RESET\n", ioc->name, __FUNCTION__)); ++ "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) { +- ioc->internal_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; ++ ioc->internal_cmds.status ++ |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->internal_cmds.done); + } + break; +@@ -1700,7 +1713,8 @@ mptscsih_taskmgmt_response_code(MPT_ADAP + } + + static int +-mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, SCSITaskMgmtReply_t *pScsiTmReply) ++mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, ++ SCSITaskMgmtReply_t *pScsiTmReply) + { + u16 iocstatus; + u32 termination_count; +@@ -1764,7 +1778,8 @@ mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc + * Returns 1 indicating alloc'd request frame ptr should be freed. + **/ + int +-mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ++mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, ++ MPT_FRAME_HDR *mr) + { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p, mr=%p)\n", + ioc->name, mf, mr)); +@@ -1807,7 +1822,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER * + * + **/ + int +-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) ++mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, ++ int ctx2abort, ulong timeout) + { + MPT_FRAME_HDR *mf = NULL; + SCSITaskMgmt_t *pScsiTm; +@@ -1827,7 +1843,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd + "TaskMgmt type=%x: IOC Not operational (0x%x)!\n", + ioc->name, type, ioc_raw_state); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) + printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset " + "FAILED!!\n", ioc->name); +@@ -1844,7 +1860,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { +- mutex_unlock(&ioc->taskmgmt_cmds.mutex); ++ mutex_unlock(&ioc->taskmgmt_cmds.mutex); + retval = FAILED; + goto out; + } +@@ -1852,8 +1868,9 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd + /* Return Fail to calling function if no message frames available. + */ + if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt no msg frames!!\n", +- ioc->name)); ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "TaskMgmt no msg frames!!\n", ++ ioc->name)); + retval = FAILED; + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; +@@ -1873,11 +1890,11 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd + pScsiTm->TaskType = type; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) +- ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; ++ ? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0; + + int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); + +- for (ii=0; ii < 7; ii++) ++ for (ii = 0; ii < 7; ii++) + pScsiTm->Reserved2[ii] = 0; + + pScsiTm->TaskMsgContext = ctx2abort; +@@ -1895,17 +1912,19 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd + mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); + else { + retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, +- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); ++ sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP); + if (retval) { +- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "TaskMgmt handshake FAILED!" +- " (mf=%p, rc=%d) \n", ioc->name, mf, retval)); ++ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ++ "TaskMgmt handshake FAILED!" ++ " (mf=%p, rc=%d) \n", ioc->name, mf, retval)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; + } + } + +- timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); ++ timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, ++ timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = FAILED; + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT +@@ -1927,9 +1946,9 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd + out: + + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) +- if(issue_hard_reset) { ++ if (issue_hard_reset) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if ((retval = mpt_SoftResetHandler(ioc, CAN_SLEEP)) != 0) + retval = mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); +@@ -2037,7 +2056,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) + goto out; + } + +- if(mpt_fwfault_debug) ++ if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + if (ioc->timeouts < -1) +@@ -2075,7 +2094,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) + + out: + printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", +- ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED" ), SCpnt); ++ ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt); + + return retval; + } +@@ -2306,7 +2325,7 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; +- phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; +@@ -2339,14 +2358,14 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + +- down(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = 1; + } +- up(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +@@ -2357,7 +2376,7 @@ u8 + mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) + { + struct inactive_raid_component_info *component_info; +- int i,j; ++ int i, j; + RaidPhysDiskPage1_t *phys_disk; + int rc = -ENXIO; + u8 num_paths; +@@ -2384,7 +2403,7 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; +- phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t,Path) + ++ phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; +@@ -2417,14 +2436,14 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc + if (list_empty(&ioc->raid_data.inactive_list)) + goto out; + +- down(&ioc->raid_data.inactive_list_mutex); ++ mutex_lock(&ioc->raid_data.inactive_list_mutex); + list_for_each_entry(component_info, &ioc->raid_data.inactive_list, + list) { + if ((component_info->d.PhysDiskID == id) && + (component_info->d.PhysDiskBus == channel)) + rc = component_info->d.PhysDiskNum; + } +- up(&ioc->raid_data.inactive_list_mutex); ++ mutex_unlock(&ioc->raid_data.inactive_list_mutex); + + out: + return rc; +@@ -2595,9 +2614,11 @@ mptscsih_copy_sense_data(struct scsi_cmn + + ioc->eventContext++; + if (ioc->pcidev->vendor == PCI_VENDOR_ID_IBM) { +- mptscsih_issue_sep_command(ioc, vdevice->vtarget, ++ mptscsih_issue_sep_command(ioc, ++ vdevice->vtarget, + MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); +- vdevice->vtarget->tflags |= MPT_TARGET_FLAGS_LED_ON; ++ vdevice->vtarget->tflags |= ++ MPT_TARGET_FLAGS_LED_ON; + } + } + } +@@ -2736,8 +2757,9 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { +- dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!\n", +- ioc->name, __FUNCTION__)); ++ dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT ++ "%s: no msg frames!\n", ++ ioc->name, __func__)); + ret = -EAGAIN; + goto out; + } +@@ -2759,8 +2781,9 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, + ioc->add_sge((char *)&pReq->ActionDataSGE, + MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); + +- ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", +- ioc->name, pReq->Action, channel, id)); ++ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT ++ "RAID Volume action=%x channel=%d id=%d\n", ++ ioc->name, pReq->Action, channel, id)); + + INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) + mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); +@@ -2768,12 +2791,12 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n", +- ioc->name, __FUNCTION__)); ++ ioc->name, __func__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); +@@ -2797,7 +2820,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, + * + **/ + static int +-mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) ++mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, ++ MPT_FRAME_HDR *reply) + { + SCSIIOReply_t *pReply; + MpiRaidActionReply_t *pr; +@@ -2810,10 +2834,12 @@ mptscsih_get_completion_code(MPT_ADAPTER + scsi_status = pReply->SCSIStatus; + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n", +- ioc->name, status, pReply->SCSIState, scsi_status, le32_to_cpu(pReply->IOCLogInfo))); ++ "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh," ++ " IOCLogInfo=%08xh\n", ++ ioc->name, status, pReply->SCSIState, scsi_status, ++ le32_to_cpu(pReply->IOCLogInfo))); + +- switch(status) { ++ switch (status) { + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + completion_code = MPT_SCANDV_SELECTION_TIMEOUT; +@@ -2836,9 +2862,11 @@ mptscsih_get_completion_code(MPT_ADAPTER + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + if (pReply->Function == MPI_FUNCTION_CONFIG) { + completion_code = MPT_SCANDV_GOOD; +- } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { ++ } else if (pReply->Function == ++ MPI_FUNCTION_RAID_ACTION) { + pr = (MpiRaidActionReply_t *)reply; +- if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) ++ if (le16_to_cpu(pr->ActionStatus) == ++ MPI_RAID_ACTION_ASTATUS_SUCCESS) + completion_code = MPT_SCANDV_GOOD; + else + completion_code = MPT_SCANDV_SOME_ERROR; +@@ -2849,8 +2877,7 @@ mptscsih_get_completion_code(MPT_ADAPTER + completion_code = MPT_SCANDV_ISSUE_SENSE; + else + completion_code = MPT_SCANDV_DID_RESET; +- } +- else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) ++ } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) + completion_code = MPT_SCANDV_DID_RESET; + else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; +@@ -2885,7 +2912,8 @@ mptscsih_get_completion_code(MPT_ADAPTER + * + **/ + int +-mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) ++mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, ++ MPT_FRAME_HDR *reply) + { + SCSIIORequest_t *pReq; + SCSIIOReply_t *pReply; +@@ -2965,7 +2993,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: busy with host reset\n", ioc->name, __FUNCTION__)); ++ "%s: busy with host reset\n", ioc->name, __func__)); + return MPT_SCANDV_BUSY; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +@@ -3091,7 +3119,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + */ + if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n", +- ioc->name, __FUNCTION__)); ++ ioc->name, __func__)); + ret = MPT_SCANDV_BUSY; + goto out; + } +@@ -3128,11 +3156,11 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + if (cmd == REQUEST_SENSE) { + pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: Untagged! 0x%02x\n", ioc->name, __FUNCTION__, cmd)); ++ "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd)); + } + + for (ii = 0; ii < 16; ii++) +- pScsiReq->CDB[ii] = CDB[ii]; ++ pScsiReq->CDB[ii] = CDB[ii]; + + pScsiReq->DataLength = cpu_to_le32(io->size); + pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma +@@ -3140,7 +3168,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n", +- ioc->name, __FUNCTION__, cmd, io->channel, io->id, io->lun)); ++ ioc->name, __func__, cmd, io->channel, io->id, io->lun)); + + if (dir == MPI_SCSIIO_CONTROL_READ) + ioc->add_sge((char *) &pScsiReq->SGL, +@@ -3156,7 +3184,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = MPT_SCANDV_DID_RESET; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __FUNCTION__, ++ "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__, + cmd)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); +@@ -3166,7 +3194,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + if (!mptscsih_scandv_bus_reset(ioc)) + goto out; + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", +- ioc->name, __FUNCTION__); ++ ioc->name, __func__); + if (mpt_SoftResetHandler(ioc, CAN_SLEEP) != 0) + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); +@@ -3176,7 +3204,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + + ret = ioc->internal_cmds.completion_code; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n", +- ioc->name, __FUNCTION__, ret)); ++ ioc->name, __func__, ret)); + + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) +@@ -3195,7 +3223,8 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTER + * + */ + static void +-mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, VirtDevice *vdevice) ++mptscsih_synchronize_cache(struct scsi_device *sdev, MPT_SCSI_HOST *hd, ++ VirtDevice *vdevice) + { + INTERNAL_CMD iocmd; + MPT_ADAPTER *ioc = hd->ioc; +@@ -3219,8 +3248,9 @@ mptscsih_synchronize_cache(struct scsi_d + iocmd.id = vdevice->vtarget->id; + iocmd.lun = vdevice->lun; + +- sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT "SYNCHRONIZE_CACHE: fw_channel %d," +- " fw_id %d\n", ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id); ++ sdev_printk(KERN_INFO, sdev, MYIOC_s_FMT ++ "SYNCHRONIZE_CACHE: fw_channel %d, fw_id %d\n", ++ ioc->name, vdevice->vtarget->channel, vdevice->vtarget->id); + mptscsih_do_cmd(hd, &iocmd); + } + +@@ -3408,7 +3438,8 @@ static DEVICE_ATTR(debug_level, S_IRUGO + mptscsih_debug_level_show, mptscsih_debug_level_store); + + static ssize_t +-mptscsih_disable_hotplug_remove_show(struct device *dev, struct device_attribute *attr, char *buf) ++mptscsih_disable_hotplug_remove_show(struct device *dev, ++ struct device_attribute *attr, char *buf) + { + struct Scsi_Host *host = class_to_shost(dev); + MPT_SCSI_HOST *hd = shost_priv(host); +@@ -3417,7 +3448,8 @@ mptscsih_disable_hotplug_remove_show(str + return snprintf(buf, PAGE_SIZE, "%02xh\n", ioc->disable_hotplug_remove); + } + static ssize_t +-mptscsih_disable_hotplug_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++mptscsih_disable_hotplug_remove_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) + { + struct Scsi_Host *host = class_to_shost(dev); + MPT_SCSI_HOST *hd = shost_priv(host); +@@ -3436,7 +3468,8 @@ mptscsih_disable_hotplug_remove_store(st + return strlen(buf); + } + static DEVICE_ATTR(disable_hotplug_remove, S_IRUGO | S_IWUSR, +- mptscsih_disable_hotplug_remove_show, mptscsih_disable_hotplug_remove_store); ++ mptscsih_disable_hotplug_remove_show, ++ mptscsih_disable_hotplug_remove_store); + + struct device_attribute *mptscsih_host_attrs[] = { + &dev_attr_version_fw, +Index: linux-2.6.27/drivers/message/fusion/mptscsih.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptscsih.h ++++ linux-2.6.27/drivers/message/fusion/mptscsih.h +@@ -129,11 +129,13 @@ extern int mptscsih_scandv_complete(MPT_ + extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); + extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); + extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); +-extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); ++extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, ++ u8 id, int lun, int ctx2abort, ulong timeout); + extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); + extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); + extern int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); + extern struct device_attribute *mptscsih_host_attrs[]; +-extern int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id); ++extern int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, ++ u8 id); + extern struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); + extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); +Index: linux-2.6.27/drivers/message/fusion/mptspi.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/mptspi.c ++++ linux-2.6.27/drivers/message/fusion/mptspi.c +@@ -87,7 +87,8 @@ MODULE_PARM_DESC(mpt_saf_te, " Force ena + + static int mpt_qas = MPTSCSIH_QAS; + module_param(mpt_qas, int, 1); +-MODULE_PARM_DESC(mpt_qas, " Quick Arbitration and Selection (QAS) enabled=1, disabled=0 (default=MPTSCSIH_QAS=1)"); ++MODULE_PARM_DESC(mpt_qas, " Quick Arbitration and Selection (QAS) enabled=1," ++ " disabled= (default=MPTSCSIH_QAS=1)"); + + static void mptspi_write_offset(struct scsi_target *, int); + static void mptspi_write_width(struct scsi_target *, int); +@@ -240,7 +241,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST + */ + + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT +- "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); ++ "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id)); + } + } + +@@ -314,7 +315,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, + + ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", +- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); ++ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel)); + + mpt_put_msg_frame(ioc->DoneCtx, ioc, mf); + +@@ -495,7 +496,7 @@ mptspi_print_write_nego(struct _MPT_SCSI + ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", + ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", + ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", +- ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""); ++ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP " : ""); + } + + /** +@@ -523,7 +524,7 @@ mptspi_print_read_nego(struct _MPT_SCSI_ + ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "", + ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "", + ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "", +- ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""); ++ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP " : ""); + } + + static int mptspi_read_spi_device_pg0(struct scsi_target *starget, +@@ -822,8 +823,8 @@ static int mptspi_write_spi_device_pg1(s + + pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL); + if (pg1 == NULL) { +- starget_printk(KERN_ERR, starget, +- MYIOC_s_FMT "dma_alloc_coherent for parameters failed\n", ioc->name); ++ starget_printk(KERN_ERR, starget, MYIOC_s_FMT ++ "dma_alloc_coherent for parameters failed\n", ioc->name); + return -EINVAL; + } + +@@ -1071,12 +1072,12 @@ mpt_work_wrapper(struct work_struct *wor + if(vtarget->id != disk) + continue; + +- starget_printk(KERN_INFO, vtarget->starget, +- MYIOC_s_FMT "Integrated RAID requests DV of new device\n", ioc->name); ++ starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT ++ "Integrated RAID requests DV of new device\n", ioc->name); + mptspi_dv_device(hd, sdev); + } +- shost_printk(KERN_INFO, shost, +- MYIOC_s_FMT "Integrated RAID detects new device %d\n", ioc->name, disk); ++ shost_printk(KERN_INFO, shost, MYIOC_s_FMT ++ "Integrated RAID detects new device %d\n", ioc->name, disk); + scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1); + } + +@@ -1087,8 +1088,8 @@ static void mpt_dv_raid(struct _MPT_SCSI + MPT_ADAPTER *ioc = hd->ioc; + + if (!wqw) { +- shost_printk(KERN_ERR, ioc->sh, +- MYIOC_s_FMT "Failed to act on RAID event for physical disk %d\n", ++ shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT ++ "Failed to act on RAID event for physical disk %d\n", + ioc->name, disk); + return; + } +Index: linux-2.6.27/drivers/message/fusion/rejected_ioctls/diag_buffer.c +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/rejected_ioctls/diag_buffer.c ++++ linux-2.6.27/drivers/message/fusion/rejected_ioctls/diag_buffer.c +@@ -4,19 +4,20 @@ + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is not ++ * complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ + static int +-mptctl_register_diag_buffer (unsigned long arg) ++mptctl_register_diag_buffer(unsigned long arg) + { + mpt_diag_register_t __user *uarg = (void __user *) arg; + mpt_diag_register_t karg; + MPT_ADAPTER *ioc; + int iocnum, rc, ii; +- void * request_data; ++ void *request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + MPT_FRAME_HDR *mf; +@@ -30,37 +31,39 @@ mptctl_register_diag_buffer (unsigned lo + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_register_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_register_t struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || +- (ioc == NULL)) { ++ iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc); ++ ++ if ((iocnum < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, +- __FUNCTION__)); ++ __func__)); + buffer_type = karg.data.BufferType; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + return -ENODEV; + } + + if (ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_REGISTERED) { + printk(MYIOC_s_DEBUG_FMT "%s: already has a Registered " +- "buffer for buffer_type=%x\n", ioc->name, __FUNCTION__, ++ "buffer for buffer_type=%x\n", ioc->name, __func__, + buffer_type); + return -EFAULT; + } + + /* Get a free request frame and save the message context. + */ +- if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) ++ mf = mpt_get_msg_frame(mptctl_id, ioc); ++ if (mf == NULL) + return -EAGAIN; + + request_data = ioc->DiagBuffer[buffer_type]; +@@ -85,9 +88,9 @@ mptctl_register_diag_buffer (unsigned lo + if (request_data == NULL) { + printk(MYIOC_s_DEBUG_FMT "%s: pci_alloc_consistent" + " FAILED, (request_sz=%d)\n", ioc->name, +- __FUNCTION__, request_data_sz); ++ __func__, request_data_sz); + mpt_free_msg_frame(ioc, mf); +- return -EAGAIN; ++ return -EAGAIN; + } + ioc->DiagBuffer[buffer_type] = request_data; + ioc->DiagBuffer_sz[buffer_type] = request_data_sz; +@@ -95,7 +98,7 @@ mptctl_register_diag_buffer (unsigned lo + } + + ioc->DiagBuffer_Status[buffer_type] = 0; +- diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; ++ diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; + diag_buffer_post_request->Function = MPI_FUNCTION_DIAG_BUFFER_POST; + diag_buffer_post_request->ChainOffset = 0; + diag_buffer_post_request->BufferType = karg.data.BufferType; +@@ -137,7 +140,7 @@ mptctl_register_diag_buffer (unsigned lo + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, +- __FUNCTION__); ++ __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; +@@ -150,7 +153,7 @@ mptctl_register_diag_buffer (unsigned lo + /* process the completed Reply Message Frame */ + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", +- ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); ++ ioc->name, __func__, ioc->ioctl_cmds.status)); + rc = -EFAULT; + goto out; + } +@@ -160,12 +163,13 @@ mptctl_register_diag_buffer (unsigned lo + MPI_IOCSTATUS_SUCCESS) { + if (diag_buffer_post_reply->MsgLength > 5) + ioc->DataSize[buffer_type] = +- le32_to_cpu(diag_buffer_post_reply->TransferLength); ++ le32_to_cpu ++ (diag_buffer_post_reply->TransferLength); + ioc->DiagBuffer_Status[buffer_type] |= + MPT_DIAG_BUFFER_IS_REGISTERED; + } else { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " +- "IOCLogInfo=%x\n", ioc->name, __FUNCTION__, ++ "IOCLogInfo=%x\n", ioc->name, __func__, + diag_buffer_post_reply->IOCStatus, + diag_buffer_post_reply->IOCLogInfo)); + rc = -EFAULT; +@@ -187,18 +191,19 @@ mptctl_register_diag_buffer (unsigned lo + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is ++ * not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ + static int +-mptctl_release_diag_buffer (unsigned long arg) ++mptctl_release_diag_buffer(unsigned long arg) + { + mpt_diag_release_t __user *uarg = (void __user *) arg; + mpt_diag_release_t karg; + MPT_ADAPTER *ioc; +- void * request_data; ++ void *request_data; + int iocnum, rc; + MPT_FRAME_HDR *mf; + DiagReleaseRequest_t *diag_release; +@@ -210,42 +215,42 @@ mptctl_release_diag_buffer (unsigned lon + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_release_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_release_t struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + +- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || +- (ioc == NULL)) { ++ iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc); ++ if ((iocnum < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, +- __FUNCTION__)); ++ __func__)); + buffer_type = karg.data.UniqueId & 0x000000ff; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + return -ENODEV; + } + + if ((ioc->DiagBuffer_Status[buffer_type] & +- MPT_DIAG_BUFFER_IS_REGISTERED) == 0 ) { ++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " +- "registered\n", ioc->name, __FUNCTION__, buffer_type); ++ "registered\n", ioc->name, __func__, buffer_type); + return -EFAULT; + } + + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", +- ioc->name, __FUNCTION__, karg.data.UniqueId); ++ ioc->name, __func__, karg.data.UniqueId); + return -EFAULT; + } + + if (ioc->DiagBuffer_Status[buffer_type] & MPT_DIAG_BUFFER_IS_RELEASED) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x " +- "is already released\n", ioc->name, __FUNCTION__, ++ "is already released\n", ioc->name, __func__, + buffer_type)); + return rc; + } +@@ -254,13 +259,14 @@ mptctl_release_diag_buffer (unsigned lon + + if (request_data == NULL) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + return -ENODEV; + } + + /* Get a free request frame and save the message context. + */ +- if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) ++ mf = mpt_get_msg_frame(mptctl_id, ioc); ++ if (mf == NULL) + return -EAGAIN; + + diag_release = (DiagReleaseRequest_t *)mf; +@@ -281,7 +287,7 @@ mptctl_release_diag_buffer (unsigned lon + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, +- __FUNCTION__); ++ __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; +@@ -294,7 +300,7 @@ mptctl_release_diag_buffer (unsigned lon + /* process the completed Reply Message Frame */ + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", +- ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); ++ ioc->name, __func__, ioc->ioctl_cmds.status)); + rc = -EFAULT; + goto out; + } +@@ -304,7 +310,7 @@ mptctl_release_diag_buffer (unsigned lon + MPI_IOCSTATUS_SUCCESS) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " + "IOCLogInfo=%x\n", +- ioc->name, __FUNCTION__, diag_release_reply->IOCStatus, ++ ioc->name, __func__, diag_release_reply->IOCStatus, + diag_release_reply->IOCLogInfo)); + rc = -EFAULT; + } else +@@ -324,19 +330,20 @@ mptctl_release_diag_buffer (unsigned lon + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset is ++ * not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ + static int +-mptctl_unregister_diag_buffer (unsigned long arg) ++mptctl_unregister_diag_buffer(unsigned long arg) + { + mpt_diag_unregister_t __user *uarg = (void __user *) arg; + mpt_diag_unregister_t karg; + MPT_ADAPTER *ioc; + int iocnum; +- void * request_data; ++ void *request_data; + dma_addr_t request_data_dma; + u32 request_data_sz; + u8 buffer_type; +@@ -344,49 +351,48 @@ mptctl_unregister_diag_buffer (unsigned + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_unregister_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_unregister_t struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } +- +- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || +- (ioc == NULL)) { ++ iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc); ++ if ((iocnum < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, +- __FUNCTION__)); ++ __func__)); + buffer_type = karg.data.UniqueId & 0x000000ff; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + return -ENODEV; + } + + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " +- "registered\n", ioc->name, __FUNCTION__, buffer_type); ++ "registered\n", ioc->name, __func__, buffer_type); + return -EFAULT; + } + if ((ioc->DiagBuffer_Status[buffer_type] & + MPT_DIAG_BUFFER_IS_RELEASED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x has not been " +- "released\n", ioc->name, __FUNCTION__, buffer_type); ++ "released\n", ioc->name, __func__, buffer_type); + return -EFAULT; + } + + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", +- ioc->name, __FUNCTION__, karg.data.UniqueId); ++ ioc->name, __func__, karg.data.UniqueId); + return -EFAULT; + } + + request_data = ioc->DiagBuffer[buffer_type]; + if (!request_data) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + return -ENODEV; + } + +@@ -405,18 +411,19 @@ mptctl_unregister_diag_buffer (unsigned + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset ++ * is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ + static int +-mptctl_query_diag_buffer (unsigned long arg) ++mptctl_query_diag_buffer(unsigned long arg) + { + mpt_diag_query_t __user *uarg = (void __user *)arg; + mpt_diag_query_t karg; + MPT_ADAPTER *ioc; +- void * request_data; ++ void *request_data; + int iocnum, ii, rc; + u8 buffer_type; + +@@ -424,38 +431,38 @@ mptctl_query_diag_buffer (unsigned long + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_query_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_query_t struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } + + karg.data.Flags = 0; +- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || +- (ioc == NULL)) { ++ iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc); ++ if ((iocnum < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + goto out; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, +- __FUNCTION__)); ++ __func__)); + buffer_type = karg.data.BufferType; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + goto out; + } + + if ((ioc->DiagBuffer_Status[buffer_type] & +- MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { ++ MPT_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x is not " +- "registered\n", ioc->name, __FUNCTION__, buffer_type); ++ "registered\n", ioc->name, __func__, buffer_type); + goto out; + } + + if (karg.data.UniqueId & 0xffffff00) { + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not " +- "registered\n", ioc->name, __FUNCTION__, ++ "registered\n", ioc->name, __func__, + karg.data.UniqueId); + goto out; + } +@@ -464,7 +471,7 @@ mptctl_query_diag_buffer (unsigned long + request_data = ioc->DiagBuffer[buffer_type]; + if (!request_data) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + goto out; + } + +@@ -490,7 +497,7 @@ mptctl_query_diag_buffer (unsigned long + out: + if (copy_to_user(uarg, &karg, sizeof(mpt_diag_query_t))) { + printk(MYIOC_s_ERR_FMT "%s Unable to write mpt_diag_query_t " +- "data @ %p\n", ioc->name, __FUNCTION__, uarg); ++ "data @ %p\n", ioc->name, __func__, uarg); + return -EFAULT; + } + return rc; +@@ -502,13 +509,14 @@ mptctl_query_diag_buffer (unsigned long + * Outputs: None. + * Return: 0 if successful + * -EFAULT if data unavailable +- * -EBUSY if previous command timout and IOC reset is not complete. ++ * -EBUSY if previous command timout and IOC reset ++ * is not complete. + * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error + */ + static int +-mptctl_read_diag_buffer (unsigned long arg) ++mptctl_read_diag_buffer(unsigned long arg) + { + mpt_diag_read_buffer_t __user *uarg = (void __user *) arg; + mpt_diag_read_buffer_t karg; +@@ -527,50 +535,49 @@ mptctl_read_diag_buffer (unsigned long a + if (copy_from_user(&karg, uarg, sizeof(mpt_diag_read_buffer_t))) { + printk(KERN_ERR "%s@%d::%s - " + "Unable to read in mpt_diag_read_buffer_t struct @ %p\n", +- __FILE__, __LINE__, __FUNCTION__, uarg); ++ __FILE__, __LINE__, __func__, uarg); + return -EFAULT; + } +- +- if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || +- (ioc == NULL)) { ++ iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc); ++ if ((iocnum < 0) || (ioc == NULL)) { + printk(KERN_ERR "%s::%s() @%d - ioc%d not found!\n", +- __FILE__, __FUNCTION__, __LINE__, iocnum); ++ __FILE__, __func__, __LINE__, iocnum); + return -ENODEV; + } + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s enter.\n", ioc->name, +- __FUNCTION__)); ++ __func__)); + buffer_type = karg.data.UniqueId & 0x000000ff; + if (!(ioc->facts.IOCCapabilities & MPT_DIAG_CAPABILITY(buffer_type))) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have Capability " +- "for buffer_type=%x\n", ioc->name, __FUNCTION__, ++ "for buffer_type=%x\n", ioc->name, __func__, + buffer_type); + return -EFAULT; + } + + if (karg.data.UniqueId != ioc->UniqueId[buffer_type]) { + printk(MYIOC_s_DEBUG_FMT "%s: unique_id=%x is not registered\n", +- ioc->name, __FUNCTION__, karg.data.UniqueId); ++ ioc->name, __func__, karg.data.UniqueId); + return -EFAULT; + } + + request_data = ioc->DiagBuffer[buffer_type]; + if (!request_data) { + printk(MYIOC_s_DEBUG_FMT "%s: doesn't have buffer for " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type); + return -EFAULT; + } + + diagData = (void *)(request_data + karg.data.StartingOffset); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: diagData=%p " +- "request_data=%p StartingOffset=%x\n", ioc->name, __FUNCTION__, ++ "request_data=%p StartingOffset=%x\n", ioc->name, __func__, + diagData, request_data, karg.data.StartingOffset)); + + if (copy_to_user((void __user *)&uarg->data.DiagnosticData[0], + diagData, karg.data.BytesToRead)) { + printk(MYIOC_s_ERR_FMT "%s: Unable to write " + "mpt_diag_read_buffer_t data @ %p\n", ioc->name, +- __FUNCTION__, diagData); ++ __func__, diagData); + return -EFAULT; + } + +@@ -578,17 +585,18 @@ mptctl_read_diag_buffer (unsigned long a + goto out; + + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Reregister " +- "buffer_type=%x\n", ioc->name, __FUNCTION__, buffer_type)); ++ "buffer_type=%x\n", ioc->name, __func__, buffer_type)); + if ((ioc->DiagBuffer_Status[buffer_type] & +- MPT_DIAG_BUFFER_IS_RELEASED) == 0) { ++ MPT_DIAG_BUFFER_IS_RELEASED) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: buffer_type=%x " +- "is still registered\n", ioc->name, __FUNCTION__, ++ "is still registered\n", ioc->name, __func__, + buffer_type)); + return rc; + } + /* Get a free request frame and save the message context. + */ +- if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) ++ mf = mpt_get_msg_frame(mptctl_id, ioc); ++ if (mf == NULL) + return -EAGAIN; + + diag_buffer_post_request = (DiagBufferPostRequest_t *)mf; +@@ -602,7 +610,7 @@ mptctl_read_diag_buffer (unsigned long a + diag_buffer_post_request->Reserved2 = 0; + diag_buffer_post_request->Reserved3 = 0; + diag_buffer_post_request->BufferAddress.High = 0; +- if ( buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED ) ++ if (buffer_type == MPI_DIAG_BUF_TYPE_EXTENDED) + diag_buffer_post_request->ExtendedType = + cpu_to_le32(ioc->ExtendedType[buffer_type]); + diag_buffer_post_request->BufferLength = +@@ -627,7 +635,7 @@ mptctl_read_diag_buffer (unsigned long a + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, +- __FUNCTION__); ++ __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; +@@ -640,7 +648,7 @@ mptctl_read_diag_buffer (unsigned long a + /* process the completed Reply Message Frame */ + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) == 0) { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: status=%x\n", +- ioc->name, __FUNCTION__, ioc->ioctl_cmds.status)); ++ ioc->name, __func__, ioc->ioctl_cmds.status)); + rc = -EFAULT; + } + +@@ -654,7 +662,7 @@ mptctl_read_diag_buffer (unsigned long a + MPT_DIAG_BUFFER_IS_REGISTERED; + } else { + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: IOCStatus=%x " +- "IOCLogInfo=%x\n", ioc->name, __FUNCTION__, ++ "IOCLogInfo=%x\n", ioc->name, __func__, + diag_buffer_post_reply->IOCStatus, + diag_buffer_post_reply->IOCLogInfo)); + rc = -EFAULT; +Index: linux-2.6.27/drivers/message/fusion/rejected_ioctls/diag_buffer.h +=================================================================== +--- linux-2.6.27.orig/drivers/message/fusion/rejected_ioctls/diag_buffer.h ++++ linux-2.6.27/drivers/message/fusion/rejected_ioctls/diag_buffer.h +@@ -1,8 +1,13 @@ +-#define MPTDIAGREGISTER _IOWR(MPT_MAGIC_NUMBER,26,mpt_diag_register_t) +-#define MPTDIAGRELEASE _IOWR(MPT_MAGIC_NUMBER,27,mpt_diag_release_t) +-#define MPTDIAGUNREGISTER _IOWR(MPT_MAGIC_NUMBER,28,mpt_diag_unregister_t) +-#define MPTDIAGQUERY _IOWR(MPT_MAGIC_NUMBER,29,mpt_diag_query_t) +-#define MPTDIAGREADBUFFER _IOWR(MPT_MAGIC_NUMBER,30,mpt_diag_read_buffer_t) ++#define MPTDIAGREGISTER \ ++ _IOWR(MPT_MAGIC_NUMBER, 26, mpt_diag_register_t) ++#define MPTDIAGRELEASE \ ++ _IOWR(MPT_MAGIC_NUMBER, 27, mpt_diag_release_t) ++#define MPTDIAGUNREGISTER \ ++ _IOWR(MPT_MAGIC_NUMBER, 28, mpt_diag_unregister_t) ++#define MPTDIAGQUERY \ ++ _IOWR(MPT_MAGIC_NUMBER, 29, mpt_diag_query_t) ++#define MPTDIAGREADBUFFER \ ++ _IOWR(MPT_MAGIC_NUMBER, 30, mpt_diag_read_buffer_t) + + #define MPI_FW_DIAG_IOCTL (0x80646961) + #define MPI_FW_DIAG_TYPE_REGISTER (0x00000001) +@@ -25,7 +30,8 @@ + #define MPI_FW_DIAG_ERROR_NO_BUFFER (0x00000013) + #define MPI_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014) + +-#define MPT_DIAG_CAPABILITY(bufftype) (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER << bufftype) ++#define MPT_DIAG_CAPABILITY(bufftype) \ ++ (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER << bufftype) + + #define MPT_DIAG_BUFFER_IS_REGISTERED 1 + #define MPT_DIAG_BUFFER_IS_RELEASED 2 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/mpt-return-all-sense-data b/src/patches/suse-2.6.27.31/patches.drivers/mpt-return-all-sense-data new file mode 100644 index 000000000..1187e5937 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/mpt-return-all-sense-data @@ -0,0 +1,35 @@ +From: Mike Reed +Subject: MPT Fusion doesn't return all sense data +References: bnc#466179 + +This patch removes an inappropriate sizeof() test which truncated the amount of +sense data returned to the size of a pointer. + +Signed-off-by: Mike Reed +Signed-off-by: Sathya Prakash +Signed-off-by: Hannes Reinecke + +--- a/drivers/message/fusion/mptscsih.c 2009-01-08 12:46:11.000000000 -0600 ++++ b/drivers/message/fusion/mptscsih.c 2009-01-13 13:33:16.239522030 -0600 +@@ -112,8 +112,6 @@ int mptscsih_suspend(struct pci_dev *p + int mptscsih_resume(struct pci_dev *pdev); + #endif + +-#define SNS_LEN(scp) sizeof((scp)->sense_buffer) +- + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + /** + * mptscsih_getFreeChainBuffer - Function to get a free chain +@@ -2594,7 +2592,11 @@ mptscsih_copy_sense_data(struct scsi_cmn + /* Copy the sense received into the scsi command block. */ + req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); +- memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); ++ ++ if (sense_count > SCSI_SENSE_BUFFERSIZE) ++ sense_count = SCSI_SENSE_BUFFERSIZE; ++ ++ memcpy(sc->sense_buffer, sense_data, sense_count); + + /* Log SMART data (asc = 0x5D, non-IM case only) if required. + */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/mptsas-discover-all-devices b/src/patches/suse-2.6.27.31/patches.drivers/mptsas-discover-all-devices new file mode 100644 index 000000000..d37a2dfc5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/mptsas-discover-all-devices @@ -0,0 +1,56 @@ +From: Jeremy Higdon +Subject: mptsas driver fails to discover devices +References: bnc#459932 + +The mptsas driver has a serious regression in sles11rc1 in that it fails to +discover devices that work fine with sles10sp2. + +I discovered that part of the problem was that the target number of the RAID +volume was too high for the driver to discover it. + +The problem with the IS220 (LSI 1333 RAID) is that the driver is issuing its +own Test Unit Read and that's apparently being considered a failure from the +Unit Attention statuses. + +With this patch the system boots okay. + +Signed-off-by: Jeremy Higdon +Signed-off-by: Sathya Prakash +Signed-off-by: Hannes Reinecke + +--- /mnt/usr/src/linux/drivers/message/fusion/mptsas.c 2008-12-08 06:54:50.000000000 -0800 ++++ linux/drivers/message/fusion/mptsas.c 2009-01-18 22:16:30.456811758 -0800 +@@ -1580,12 +1580,10 @@ + enum device_state state; + int rc; + u8 skey, asc, ascq; +- u8 retry_ua; + + if (count >= mpt_cmd_retry_count) + return DEVICE_ERROR; + +- retry_ua = 0; + iocmd = kzalloc(sizeof(INTERNAL_CMD), GFP_KERNEL); + if (!iocmd) { + printk(MYIOC_s_ERR_FMT "%s: kzalloc(%zd) FAILED!\n", +@@ -1646,10 +1644,8 @@ + __func__, channel, id, skey, asc, ascq)); + + if (skey == UNIT_ATTENTION) { +- if (!retry_ua) { +- retry_ua++; +- goto retry; +- } ++ state = DEVICE_RETRY; ++ break; + } else if (skey == NOT_READY) { + /* + * medium isn't present +@@ -3740,6 +3736,7 @@ + return; + } + } ++ mpt_findImVolumes(ioc); + + case MPTSAS_ADD_DEVICE: + memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-avoid-invalid-iounmap.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-avoid-invalid-iounmap.patch new file mode 100644 index 000000000..ec09e275e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-avoid-invalid-iounmap.patch @@ -0,0 +1,36 @@ +From 3bfafd6b136bea2de9bd96c01b7e3808635a15b2 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Fri, 16 Jan 2009 11:03:01 -0800 +Subject: netxen: avoid invalid iounmap +Acked-by: Karsten Keil +Reference: bnc#472416 + +For NX3031 only one I/O range is mapped, so unmapping other +two which are used by older chips, causes this warning on +ppc64. + +"Attempt to iounmap early bolted mapping at 0x0000000000000000" + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic_main.c | 6 ++++-- + 1 files changed, 4 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -993,8 +993,10 @@ static void __devexit netxen_nic_remove( + + iounmap(adapter->ahw.db_base); + iounmap(adapter->ahw.pci_base0); +- iounmap(adapter->ahw.pci_base1); +- iounmap(adapter->ahw.pci_base2); ++ if (adapter->ahw.pci_base1 != NULL) ++ iounmap(adapter->ahw.pci_base1); ++ if (adapter->ahw.pci_base2 != NULL) ++ iounmap(adapter->ahw.pci_base2); + + pci_release_regions(pdev); + pci_disable_device(pdev); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-cleanup-mac-list-on-driver-unload.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-cleanup-mac-list-on-driver-unload.patch new file mode 100644 index 000000000..af58b225a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-cleanup-mac-list-on-driver-unload.patch @@ -0,0 +1,69 @@ +From 06e9d9f9783860fe4c602ef491f47211804ccc96 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:49:22 -0800 +Subject: netxen: cleanup mac list on driver unload +Acked-by: Karsten Keil +Reference: bnc#472416 + +This fixes a tiny memory leak when driver is unloaded. The mac +address list maintained in netxen_adapter needs to deleted when +driver is going down. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 1 + + drivers/net/netxen/netxen_nic_hw.c | 13 +++++++++++++ + drivers/net/netxen/netxen_nic_main.c | 3 +++ + 3 files changed, 17 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic.h ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +@@ -1478,6 +1478,7 @@ int netxen_process_cmd_ring(struct netxe + u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max); + void netxen_p2_nic_set_multi(struct net_device *netdev); + void netxen_p3_nic_set_multi(struct net_device *netdev); ++void netxen_p3_free_mac_list(struct netxen_adapter *adapter); + int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); + int netxen_config_intr_coalesce(struct netxen_adapter *adapter); + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_hw.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +@@ -627,6 +627,19 @@ int netxen_p3_nic_set_promisc(struct net + (struct cmd_desc_type0 *)&req, 1); + } + ++void netxen_p3_free_mac_list(struct netxen_adapter *adapter) ++{ ++ nx_mac_list_t *cur, *next; ++ ++ cur = adapter->mac_list; ++ ++ while (cur) { ++ next = cur->next; ++ kfree(cur); ++ cur = next; ++ } ++} ++ + #define NETXEN_CONFIG_INTR_COALESCE 3 + + /* +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -975,6 +975,9 @@ static void __devexit netxen_nic_remove( + netxen_free_hw_resources(adapter); + netxen_release_rx_buffers(adapter); + netxen_free_sw_resources(adapter); ++ ++ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) ++ netxen_p3_free_mac_list(adapter); + } + + if (adapter->portnum == 0) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-enable-msi-x-for-quad-gig-boards.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-enable-msi-x-for-quad-gig-boards.patch new file mode 100644 index 000000000..08b912afc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-enable-msi-x-for-quad-gig-boards.patch @@ -0,0 +1,31 @@ +From ec68db6930635b25ef5ba4983053635f5b4bf35e Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 20 Aug 2008 13:52:48 -0700 +Subject: netxen: enable msi-x for quad-gig boards +Acked-by: Karsten Keil +Reference: bnc#472416 + +NX3031 firmware now supports MSI-X interrupts on Quad GbE boards. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: Jeff Garzik +--- + drivers/net/netxen/netxen_nic_main.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c +index 0f8ea2c..6ef3f0d 100644 +--- a/drivers/net/netxen/netxen_nic_main.c ++++ b/drivers/net/netxen/netxen_nic_main.c +@@ -241,7 +241,7 @@ static void netxen_check_options(struct netxen_adapter *adapter) + case NETXEN_BRDTYPE_P3_REF_QG: + case NETXEN_BRDTYPE_P3_4_GB: + case NETXEN_BRDTYPE_P3_4_GB_MM: +- adapter->msix_supported = 0; ++ adapter->msix_supported = !!use_msi_x; + adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G; + break; + +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-firmware-init-fix.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-firmware-init-fix.patch new file mode 100644 index 000000000..64b7cb9f6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-firmware-init-fix.patch @@ -0,0 +1,255 @@ +From 27c915a4d843b90eb4065298969578d15e5e6ab0 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:49:00 -0800 +Subject: netxen: firmware init fix +Acked-by: Karsten Keil +Reference: bnc#472416 + +o Fix order or rom register writes. +o Reduce udelays when writing rom registers. + +This cuts the firmware init time by 40%. + +o Do not reset core/memory clocks when reinitializing driver. + Firmware willl handle this when initialized. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic_hw.c | 6 +--- + drivers/net/netxen/netxen_nic_init.c | 35 +++++++++++++++---------- + drivers/net/netxen/netxen_nic_main.c | 47 ++++++++++++++++++++------------- + 3 files changed, 51 insertions(+), 37 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_hw.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +@@ -939,7 +939,7 @@ int netxen_load_firmware(struct netxen_a + { + int i; + u32 data, size = 0; +- u32 flashaddr = NETXEN_BOOTLD_START, memaddr = NETXEN_BOOTLD_START; ++ u32 flashaddr = NETXEN_BOOTLD_START; + + size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START)/4; + +@@ -951,10 +951,8 @@ int netxen_load_firmware(struct netxen_a + if (netxen_rom_fast_read(adapter, flashaddr, (int *)&data) != 0) + return -EIO; + +- adapter->pci_mem_write(adapter, memaddr, &data, 4); ++ adapter->pci_mem_write(adapter, flashaddr, &data, 4); + flashaddr += 4; +- memaddr += 4; +- cond_resched(); + } + msleep(1); + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_init.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_init.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_init.c +@@ -439,6 +439,8 @@ static int netxen_wait_rom_done(struct n + long timeout = 0; + long done = 0; + ++ cond_resched(); ++ + while (done == 0) { + done = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_GLB_STATUS); + done &= 2; +@@ -533,12 +535,9 @@ static int do_rom_fast_write(struct netx + static int do_rom_fast_read(struct netxen_adapter *adapter, + int addr, int *valp) + { +- cond_resched(); +- + netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); +- netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); +- udelay(100); /* prevent bursting on CRB */ + netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); ++ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); + netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); + if (netxen_wait_rom_done(adapter)) { + printk("Error waiting for rom done\n"); +@@ -546,7 +545,7 @@ static int do_rom_fast_read(struct netxe + } + /* reset abyte_cnt and dummy_byte_cnt */ + netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); +- udelay(100); /* prevent bursting on CRB */ ++ udelay(10); + netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + + *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA); +@@ -884,14 +883,16 @@ int netxen_flash_unlock(struct netxen_ad + int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) + { + int addr, val; +- int i, init_delay = 0; ++ int i, n, init_delay = 0; + struct crb_addr_pair *buf; +- unsigned offset, n; ++ unsigned offset; + u32 off; + + /* resetall */ ++ rom_lock(adapter); + netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET, + 0xffffffff); ++ netxen_rom_unlock(adapter); + + if (verbose) { + if (netxen_rom_fast_read(adapter, NETXEN_BOARDTYPE, &val) == 0) +@@ -910,7 +911,7 @@ int netxen_pinit_from_rom(struct netxen_ + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { + if (netxen_rom_fast_read(adapter, 0, &n) != 0 || +- (n != 0xcafecafeUL) || ++ (n != 0xcafecafe) || + netxen_rom_fast_read(adapter, 4, &n) != 0) { + printk(KERN_ERR "%s: ERROR Reading crb_init area: " + "n: %08x\n", netxen_nic_driver_name, n); +@@ -975,6 +976,14 @@ int netxen_pinit_from_rom(struct netxen_ + /* do not reset PCI */ + if (off == (ROMUSB_GLB + 0xbc)) + continue; ++ if (off == (ROMUSB_GLB + 0xa8)) ++ continue; ++ if (off == (ROMUSB_GLB + 0xc8)) /* core clock */ ++ continue; ++ if (off == (ROMUSB_GLB + 0x24)) /* MN clock */ ++ continue; ++ if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */ ++ continue; + if (off == (NETXEN_CRB_PEG_NET_1 + 0x18)) + buf[i].data = 0x1020; + /* skip the function enable register */ +@@ -992,23 +1001,21 @@ int netxen_pinit_from_rom(struct netxen_ + continue; + } + ++ init_delay = 1; + /* After writing this register, HW needs time for CRB */ + /* to quiet down (else crb_window returns 0xffffffff) */ + if (off == NETXEN_ROMUSB_GLB_SW_RESET) { +- init_delay = 1; ++ init_delay = 1000; + if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { + /* hold xdma in reset also */ + buf[i].data = NETXEN_NIC_XDMA_RESET; ++ buf[i].data = 0x8000ff; + } + } + + adapter->hw_write_wx(adapter, off, &buf[i].data, 4); + +- if (init_delay == 1) { +- msleep(1000); +- init_delay = 0; +- } +- msleep(1); ++ msleep(init_delay); + } + kfree(buf); + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -280,10 +280,15 @@ static void netxen_check_options(struct + static int + netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot) + { +- int ret = 0; ++ u32 val, timeout; + + if (first_boot == 0x55555555) { + /* This is the first boot after power up */ ++ adapter->pci_write_normalize(adapter, ++ NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); ++ ++ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) ++ return 0; + + /* PCI bus master workaround */ + adapter->hw_read_wx(adapter, +@@ -303,18 +308,26 @@ netxen_check_hw_init(struct netxen_adapt + /* clear the register for future unloads/loads */ + adapter->pci_write_normalize(adapter, + NETXEN_CAM_RAM(0x1fc), 0); +- ret = -1; ++ return -EIO; + } + +- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { +- /* Start P2 boot loader */ +- adapter->pci_write_normalize(adapter, +- NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC); +- adapter->pci_write_normalize(adapter, +- NETXEN_ROMUSB_GLB_PEGTUNE_DONE, 1); +- } ++ /* Start P2 boot loader */ ++ val = adapter->pci_read_normalize(adapter, ++ NETXEN_ROMUSB_GLB_PEGTUNE_DONE); ++ adapter->pci_write_normalize(adapter, ++ NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1); ++ timeout = 0; ++ do { ++ msleep(1); ++ val = adapter->pci_read_normalize(adapter, ++ NETXEN_CAM_RAM(0x1fc)); ++ ++ if (++timeout > 5000) ++ return -EIO; ++ ++ } while (val == NETXEN_BDINFO_MAGIC); + } +- return ret; ++ return 0; + } + + static void netxen_set_port_mode(struct netxen_adapter *adapter) +@@ -782,8 +795,8 @@ netxen_nic_probe(struct pci_dev *pdev, c + CRB_CMDPEG_STATE, 0); + netxen_pinit_from_rom(adapter, 0); + msleep(1); +- netxen_load_firmware(adapter); + } ++ netxen_load_firmware(adapter); + + if (NX_IS_REVISION_P3(revision_id)) + netxen_pcie_strap_init(adapter); +@@ -799,13 +812,6 @@ netxen_nic_probe(struct pci_dev *pdev, c + + } + +- if ((first_boot == 0x55555555) && +- (NX_IS_REVISION_P2(revision_id))) { +- /* Unlock the HW, prompting the boot sequence */ +- adapter->pci_write_normalize(adapter, +- NETXEN_ROMUSB_GLB_PEGTUNE_DONE, 1); +- } +- + err = netxen_initialize_adapter_offload(adapter); + if (err) + goto err_out_iounmap; +@@ -819,7 +825,9 @@ netxen_nic_probe(struct pci_dev *pdev, c + adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, i); + + /* Handshake with the card before we register the devices. */ +- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); ++ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); ++ if (err) ++ goto err_out_free_offload; + + } /* first_driver */ + +@@ -923,6 +931,7 @@ err_out_disable_msi: + if (adapter->flags & NETXEN_NIC_MSI_ENABLED) + pci_disable_msi(pdev); + ++err_out_free_offload: + if (first_driver) + netxen_free_adapter_offload(adapter); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-endianness-in-firmware-commands.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-endianness-in-firmware-commands.patch new file mode 100644 index 000000000..6ffceef58 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-endianness-in-firmware-commands.patch @@ -0,0 +1,411 @@ +From 2edbb454428729f450f7a0aabbf95ac62b46b78a Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:47:30 -0800 +Subject: netxen: fix endianness in firmware commands +Acked-by: Karsten Keil +Reference: bnc#472416 + +o Set restricted (little endian) data types in firmware command + requests and responses. +o Remove unnecessary conversion to LE when writing registers. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 98 +++++++++++++++++----------------- + drivers/net/netxen/netxen_nic_ctx.c | 50 +++++++---------- + drivers/net/netxen/netxen_nic_hw.c | 42 ++++++++------ + drivers/net/netxen/netxen_nic_init.c | 2 +- + 4 files changed, 95 insertions(+), 97 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic.h ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +@@ -995,31 +995,31 @@ struct netxen_recv_context { + */ + + typedef struct { +- u64 host_phys_addr; /* Ring base addr */ +- u32 ring_size; /* Ring entries */ +- u16 msi_index; +- u16 rsvd; /* Padding */ ++ __le64 host_phys_addr; /* Ring base addr */ ++ __le32 ring_size; /* Ring entries */ ++ __le16 msi_index; ++ __le16 rsvd; /* Padding */ + } nx_hostrq_sds_ring_t; + + typedef struct { +- u64 host_phys_addr; /* Ring base addr */ +- u64 buff_size; /* Packet buffer size */ +- u32 ring_size; /* Ring entries */ +- u32 ring_kind; /* Class of ring */ ++ __le64 host_phys_addr; /* Ring base addr */ ++ __le64 buff_size; /* Packet buffer size */ ++ __le32 ring_size; /* Ring entries */ ++ __le32 ring_kind; /* Class of ring */ + } nx_hostrq_rds_ring_t; + + typedef struct { +- u64 host_rsp_dma_addr; /* Response dma'd here */ +- u32 capabilities[4]; /* Flag bit vector */ +- u32 host_int_crb_mode; /* Interrupt crb usage */ +- u32 host_rds_crb_mode; /* RDS crb usage */ ++ __le64 host_rsp_dma_addr; /* Response dma'd here */ ++ __le32 capabilities[4]; /* Flag bit vector */ ++ __le32 host_int_crb_mode; /* Interrupt crb usage */ ++ __le32 host_rds_crb_mode; /* RDS crb usage */ + /* These ring offsets are relative to data[0] below */ +- u32 rds_ring_offset; /* Offset to RDS config */ +- u32 sds_ring_offset; /* Offset to SDS config */ +- u16 num_rds_rings; /* Count of RDS rings */ +- u16 num_sds_rings; /* Count of SDS rings */ +- u16 rsvd1; /* Padding */ +- u16 rsvd2; /* Padding */ ++ __le32 rds_ring_offset; /* Offset to RDS config */ ++ __le32 sds_ring_offset; /* Offset to SDS config */ ++ __le16 num_rds_rings; /* Count of RDS rings */ ++ __le16 num_sds_rings; /* Count of SDS rings */ ++ __le16 rsvd1; /* Padding */ ++ __le16 rsvd2; /* Padding */ + u8 reserved[128]; /* reserve space for future expansion*/ + /* MUST BE 64-bit aligned. + The following is packed: +@@ -1029,24 +1029,24 @@ typedef struct { + } nx_hostrq_rx_ctx_t; + + typedef struct { +- u32 host_producer_crb; /* Crb to use */ +- u32 rsvd1; /* Padding */ ++ __le32 host_producer_crb; /* Crb to use */ ++ __le32 rsvd1; /* Padding */ + } nx_cardrsp_rds_ring_t; + + typedef struct { +- u32 host_consumer_crb; /* Crb to use */ +- u32 interrupt_crb; /* Crb to use */ ++ __le32 host_consumer_crb; /* Crb to use */ ++ __le32 interrupt_crb; /* Crb to use */ + } nx_cardrsp_sds_ring_t; + + typedef struct { + /* These ring offsets are relative to data[0] below */ +- u32 rds_ring_offset; /* Offset to RDS config */ +- u32 sds_ring_offset; /* Offset to SDS config */ +- u32 host_ctx_state; /* Starting State */ +- u32 num_fn_per_port; /* How many PCI fn share the port */ +- u16 num_rds_rings; /* Count of RDS rings */ +- u16 num_sds_rings; /* Count of SDS rings */ +- u16 context_id; /* Handle for context */ ++ __le32 rds_ring_offset; /* Offset to RDS config */ ++ __le32 sds_ring_offset; /* Offset to SDS config */ ++ __le32 host_ctx_state; /* Starting State */ ++ __le32 num_fn_per_port; /* How many PCI fn share the port */ ++ __le16 num_rds_rings; /* Count of RDS rings */ ++ __le16 num_sds_rings; /* Count of SDS rings */ ++ __le16 context_id; /* Handle for context */ + u8 phys_port; /* Physical id of port */ + u8 virt_port; /* Virtual/Logical id of port */ + u8 reserved[128]; /* save space for future expansion */ +@@ -1072,34 +1072,34 @@ typedef struct { + */ + + typedef struct { +- u64 host_phys_addr; /* Ring base addr */ +- u32 ring_size; /* Ring entries */ +- u32 rsvd; /* Padding */ ++ __le64 host_phys_addr; /* Ring base addr */ ++ __le32 ring_size; /* Ring entries */ ++ __le32 rsvd; /* Padding */ + } nx_hostrq_cds_ring_t; + + typedef struct { +- u64 host_rsp_dma_addr; /* Response dma'd here */ +- u64 cmd_cons_dma_addr; /* */ +- u64 dummy_dma_addr; /* */ +- u32 capabilities[4]; /* Flag bit vector */ +- u32 host_int_crb_mode; /* Interrupt crb usage */ +- u32 rsvd1; /* Padding */ +- u16 rsvd2; /* Padding */ +- u16 interrupt_ctl; +- u16 msi_index; +- u16 rsvd3; /* Padding */ ++ __le64 host_rsp_dma_addr; /* Response dma'd here */ ++ __le64 cmd_cons_dma_addr; /* */ ++ __le64 dummy_dma_addr; /* */ ++ __le32 capabilities[4]; /* Flag bit vector */ ++ __le32 host_int_crb_mode; /* Interrupt crb usage */ ++ __le32 rsvd1; /* Padding */ ++ __le16 rsvd2; /* Padding */ ++ __le16 interrupt_ctl; ++ __le16 msi_index; ++ __le16 rsvd3; /* Padding */ + nx_hostrq_cds_ring_t cds_ring; /* Desc of cds ring */ + u8 reserved[128]; /* future expansion */ + } nx_hostrq_tx_ctx_t; + + typedef struct { +- u32 host_producer_crb; /* Crb to use */ +- u32 interrupt_crb; /* Crb to use */ ++ __le32 host_producer_crb; /* Crb to use */ ++ __le32 interrupt_crb; /* Crb to use */ + } nx_cardrsp_cds_ring_t; + + typedef struct { +- u32 host_ctx_state; /* Starting state */ +- u16 context_id; /* Handle for context */ ++ __le32 host_ctx_state; /* Starting state */ ++ __le16 context_id; /* Handle for context */ + u8 phys_port; /* Physical id of port */ + u8 virt_port; /* Virtual/Logical id of port */ + nx_cardrsp_cds_ring_t cds_ring; /* Card cds settings */ +@@ -1202,9 +1202,9 @@ enum { + #define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ + + typedef struct { +- u64 qhdr; +- u64 req_hdr; +- u64 words[6]; ++ __le64 qhdr; ++ __le64 req_hdr; ++ __le64 words[6]; + } nx_nic_req_t; + + typedef struct { +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_ctx.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_ctx.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_ctx.c +@@ -76,7 +76,7 @@ netxen_api_unlock(struct netxen_adapter + static u32 + netxen_poll_rsp(struct netxen_adapter *adapter) + { +- u32 raw_rsp, rsp = NX_CDRP_RSP_OK; ++ u32 rsp = NX_CDRP_RSP_OK; + int timeout = 0; + + do { +@@ -86,10 +86,7 @@ netxen_poll_rsp(struct netxen_adapter *a + if (++timeout > NX_OS_CRB_RETRY_COUNT) + return NX_CDRP_RSP_TIMEOUT; + +- netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET, +- &raw_rsp); +- +- rsp = le32_to_cpu(raw_rsp); ++ netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET, &rsp); + } while (!NX_CDRP_IS_RSP(rsp)); + + return rsp; +@@ -109,20 +106,16 @@ netxen_issue_cmd(struct netxen_adapter * + if (netxen_api_lock(adapter)) + return NX_RCODE_TIMEOUT; + +- netxen_nic_write_w1(adapter, NX_SIGN_CRB_OFFSET, +- cpu_to_le32(signature)); ++ netxen_nic_write_w1(adapter, NX_SIGN_CRB_OFFSET, signature); + +- netxen_nic_write_w1(adapter, NX_ARG1_CRB_OFFSET, +- cpu_to_le32(arg1)); ++ netxen_nic_write_w1(adapter, NX_ARG1_CRB_OFFSET, arg1); + +- netxen_nic_write_w1(adapter, NX_ARG2_CRB_OFFSET, +- cpu_to_le32(arg2)); ++ netxen_nic_write_w1(adapter, NX_ARG2_CRB_OFFSET, arg2); + +- netxen_nic_write_w1(adapter, NX_ARG3_CRB_OFFSET, +- cpu_to_le32(arg3)); ++ netxen_nic_write_w1(adapter, NX_ARG3_CRB_OFFSET, arg3); + + netxen_nic_write_w1(adapter, NX_CDRP_CRB_OFFSET, +- cpu_to_le32(NX_CDRP_FORM_CMD(cmd))); ++ NX_CDRP_FORM_CMD(cmd)); + + rsp = netxen_poll_rsp(adapter); + +@@ -133,7 +126,6 @@ netxen_issue_cmd(struct netxen_adapter * + rcode = NX_RCODE_TIMEOUT; + } else if (rsp == NX_CDRP_RSP_FAIL) { + netxen_nic_read_w1(adapter, NX_ARG1_CRB_OFFSET, &rcode); +- rcode = le32_to_cpu(rcode); + + printk(KERN_ERR "%s: failed card response code:0x%x\n", + netxen_nic_driver_name, rcode); +@@ -183,7 +175,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_ad + + int i, nrds_rings, nsds_rings; + size_t rq_size, rsp_size; +- u32 cap, reg; ++ u32 cap, reg, val; + + int err; + +@@ -225,11 +217,14 @@ nx_fw_cmd_create_rx_ctx(struct netxen_ad + + prq->num_rds_rings = cpu_to_le16(nrds_rings); + prq->num_sds_rings = cpu_to_le16(nsds_rings); +- prq->rds_ring_offset = 0; +- prq->sds_ring_offset = prq->rds_ring_offset + ++ prq->rds_ring_offset = cpu_to_le32(0); ++ ++ val = le32_to_cpu(prq->rds_ring_offset) + + (sizeof(nx_hostrq_rds_ring_t) * nrds_rings); ++ prq->sds_ring_offset = cpu_to_le32(val); + +- prq_rds = (nx_hostrq_rds_ring_t *)(prq->data + prq->rds_ring_offset); ++ prq_rds = (nx_hostrq_rds_ring_t *)(prq->data + ++ le32_to_cpu(prq->rds_ring_offset)); + + for (i = 0; i < nrds_rings; i++) { + +@@ -241,17 +236,14 @@ nx_fw_cmd_create_rx_ctx(struct netxen_ad + prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size); + } + +- prq_sds = (nx_hostrq_sds_ring_t *)(prq->data + prq->sds_ring_offset); ++ prq_sds = (nx_hostrq_sds_ring_t *)(prq->data + ++ le32_to_cpu(prq->sds_ring_offset)); + + prq_sds[0].host_phys_addr = + cpu_to_le64(recv_ctx->rcv_status_desc_phys_addr); + prq_sds[0].ring_size = cpu_to_le32(adapter->max_rx_desc_count); + /* only one msix vector for now */ +- prq_sds[0].msi_index = cpu_to_le32(0); +- +- /* now byteswap offsets */ +- prq->rds_ring_offset = cpu_to_le32(prq->rds_ring_offset); +- prq->sds_ring_offset = cpu_to_le32(prq->sds_ring_offset); ++ prq_sds[0].msi_index = cpu_to_le16(0); + + phys_addr = hostrq_phys_addr; + err = netxen_issue_cmd(adapter, +@@ -269,9 +261,9 @@ nx_fw_cmd_create_rx_ctx(struct netxen_ad + + + prsp_rds = ((nx_cardrsp_rds_ring_t *) +- &prsp->data[prsp->rds_ring_offset]); ++ &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]); + +- for (i = 0; i < le32_to_cpu(prsp->num_rds_rings); i++) { ++ for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) { + rds_ring = &recv_ctx->rds_rings[i]; + + reg = le32_to_cpu(prsp_rds[i].host_producer_crb); +@@ -279,7 +271,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_ad + } + + prsp_sds = ((nx_cardrsp_sds_ring_t *) +- &prsp->data[prsp->sds_ring_offset]); ++ &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]); + reg = le32_to_cpu(prsp_sds[0].host_consumer_crb); + recv_ctx->crb_sts_consumer = NETXEN_NIC_REG(reg - 0x200); + +@@ -288,7 +280,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_ad + + recv_ctx->state = le32_to_cpu(prsp->host_ctx_state); + recv_ctx->context_id = le16_to_cpu(prsp->context_id); +- recv_ctx->virt_port = le16_to_cpu(prsp->virt_port); ++ recv_ctx->virt_port = prsp->virt_port; + + out_free_rsp: + pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr); +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_hw.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +@@ -539,16 +539,19 @@ static int nx_p3_sre_macaddr_change(stru + { + struct netxen_adapter *adapter = (struct netxen_adapter *)dev->priv; + nx_nic_req_t req; +- nx_mac_req_t mac_req; ++ nx_mac_req_t *mac_req; ++ u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); +- req.qhdr |= (NX_NIC_REQUEST << 23); +- req.req_hdr |= NX_MAC_EVENT; +- req.req_hdr |= ((u64)adapter->portnum << 16); +- mac_req.op = op; +- memcpy(&mac_req.mac_addr, addr, 6); +- req.words[0] = cpu_to_le64(*(u64 *)&mac_req); ++ req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23); ++ ++ word = NX_MAC_EVENT | ((u64)adapter->portnum << 16); ++ req.req_hdr = cpu_to_le64(word); ++ ++ mac_req = (nx_mac_req_t *)&req.words[0]; ++ mac_req->op = op; ++ memcpy(mac_req->mac_addr, addr, 6); + + rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); + if (rv != 0) { +@@ -612,12 +615,16 @@ send_fw_cmd: + int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode) + { + nx_nic_req_t req; ++ u64 word; + + memset(&req, 0, sizeof(nx_nic_req_t)); + +- req.qhdr |= (NX_HOST_REQUEST << 23); +- req.req_hdr |= NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE; +- req.req_hdr |= ((u64)adapter->portnum << 16); ++ req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); ++ ++ word = NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | ++ ((u64)adapter->portnum << 16); ++ req.req_hdr = cpu_to_le64(word); ++ + req.words[0] = cpu_to_le64(mode); + + return netxen_send_cmd_descs(adapter, +@@ -632,13 +639,15 @@ int netxen_p3_nic_set_promisc(struct net + int netxen_config_intr_coalesce(struct netxen_adapter *adapter) + { + nx_nic_req_t req; ++ u64 word; + int rv; + + memset(&req, 0, sizeof(nx_nic_req_t)); + +- req.qhdr |= (NX_NIC_REQUEST << 23); +- req.req_hdr |= NETXEN_CONFIG_INTR_COALESCE; +- req.req_hdr |= ((u64)adapter->portnum << 16); ++ req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23); ++ ++ word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); ++ req.req_hdr = cpu_to_le64(word); + + memcpy(&req.words[0], &adapter->coal, sizeof(adapter->coal)); + +@@ -772,13 +781,10 @@ int netxen_p3_get_mac_addr(struct netxen + adapter->hw_read_wx(adapter, crbaddr, &mac_lo, 4); + adapter->hw_read_wx(adapter, crbaddr+4, &mac_hi, 4); + +- mac_hi = cpu_to_le32(mac_hi); +- mac_lo = cpu_to_le32(mac_lo); +- + if (pci_func & 1) +- *mac = ((mac_lo >> 16) | ((u64)mac_hi << 16)); ++ *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16)); + else +- *mac = ((mac_lo) | ((u64)mac_hi << 32)); ++ *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32)); + + return 0; + } +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_init.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_init.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_init.c +@@ -1277,7 +1277,7 @@ static void netxen_process_rcv(struct ne + + dev_kfree_skb_any(skb); + for (i = 0; i < nr_frags; i++) { +- index = frag_desc->frag_handles[i]; ++ index = le16_to_cpu(frag_desc->frag_handles[i]); + skb = netxen_process_rxbuf(adapter, + rds_ring, index, cksum); + if (skb) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-ipv6-offload-and-tx-cleanup.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-ipv6-offload-and-tx-cleanup.patch new file mode 100644 index 000000000..8e15221bb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-ipv6-offload-and-tx-cleanup.patch @@ -0,0 +1,285 @@ +From 391587c3447d99b842a647f8e701895c9eea050b Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:48:11 -0800 +Subject: netxen: fix ipv6 offload and tx cleanup +Acked-by: Karsten Keil +Reference: bnc#472416 + +o fix the ip/tcp hdr offset in tx descriptors for ipv6. +o cleanup xmit function, move the tso checks into separate function, + this reduces unnecessary endian conversions back and forth. +o optimize macros to initialize tx descriptors. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 43 ++++---------- + drivers/net/netxen/netxen_nic_hw.c | 4 - + drivers/net/netxen/netxen_nic_main.c | 101 +++++++++++++++------------------- + 3 files changed, 57 insertions(+), 91 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic.h ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +@@ -308,27 +308,16 @@ struct netxen_ring_ctx { + #define netxen_set_cmd_desc_ctxid(cmd_desc, var) \ + ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0)) + +-#define netxen_set_cmd_desc_flags(cmd_desc, val) \ +- (cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \ +- ~cpu_to_le16(0x7f)) | cpu_to_le16((val) & 0x7f) +-#define netxen_set_cmd_desc_opcode(cmd_desc, val) \ +- (cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \ +- ~cpu_to_le16((u16)0x3f << 7)) | cpu_to_le16(((val) & 0x3f) << 7) +- +-#define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \ +- (cmd_desc)->num_of_buffers_total_length = \ +- ((cmd_desc)->num_of_buffers_total_length & \ +- ~cpu_to_le32(0xff)) | cpu_to_le32((val) & 0xff) +-#define netxen_set_cmd_desc_totallength(cmd_desc, val) \ +- (cmd_desc)->num_of_buffers_total_length = \ +- ((cmd_desc)->num_of_buffers_total_length & \ +- ~cpu_to_le32((u32)0xffffff << 8)) | \ +- cpu_to_le32(((val) & 0xffffff) << 8) +- +-#define netxen_get_cmd_desc_opcode(cmd_desc) \ +- ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003f) +-#define netxen_get_cmd_desc_totallength(cmd_desc) \ +- ((le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8) & 0xffffff) ++#define netxen_set_tx_port(_desc, _port) \ ++ (_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0) ++ ++#define netxen_set_tx_flags_opcode(_desc, _flags, _opcode) \ ++ (_desc)->flags_opcode = \ ++ cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)) ++ ++#define netxen_set_tx_frags_len(_desc, _frags, _len) \ ++ (_desc)->num_of_buffers_total_length = \ ++ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)) + + struct cmd_desc_type0 { + u8 tcp_hdr_offset; /* For LSO only */ +@@ -757,7 +746,7 @@ extern char netxen_nic_driver_name[]; + */ + struct netxen_skb_frag { + u64 dma; +- u32 length; ++ ulong length; + }; + + #define _netxen_set_bits(config_word, start, bits, val) {\ +@@ -783,13 +772,7 @@ struct netxen_skb_frag { + struct netxen_cmd_buffer { + struct sk_buff *skb; + struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; +- u32 total_length; +- u32 mss; +- u16 port; +- u8 cmd; +- u8 frag_count; +- unsigned long time_stamp; +- u32 state; ++ u32 frag_count; + }; + + /* In rx_buffer, we do not need multiple fragments as is a single buffer */ +@@ -1486,8 +1469,6 @@ void netxen_release_tx_buffers(struct ne + + void netxen_initialize_adapter_ops(struct netxen_adapter *adapter); + int netxen_init_firmware(struct netxen_adapter *adapter); +-void netxen_tso_check(struct netxen_adapter *adapter, +- struct cmd_desc_type0 *desc, struct sk_buff *skb); + void netxen_nic_clear_stats(struct netxen_adapter *adapter); + void netxen_watchdog_task(struct work_struct *work); + void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_hw.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +@@ -508,12 +508,8 @@ netxen_send_cmd_descs(struct netxen_adap + cmd_desc = &cmd_desc_arr[i]; + + pbuf = &adapter->cmd_buf_arr[producer]; +- pbuf->mss = 0; +- pbuf->total_length = 0; + pbuf->skb = NULL; +- pbuf->cmd = 0; + pbuf->frag_count = 0; +- pbuf->port = 0; + + /* adapter->ahw.cmd_desc_head[producer] = *cmd_desc; */ + memcpy(&adapter->ahw.cmd_desc_head[producer], +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -39,6 +39,7 @@ + #include "netxen_nic_phan_reg.h" + + #include ++#include + #include + + MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); +@@ -1126,29 +1127,46 @@ static int netxen_nic_close(struct net_d + return 0; + } + +-void netxen_tso_check(struct netxen_adapter *adapter, ++static bool netxen_tso_check(struct net_device *netdev, + struct cmd_desc_type0 *desc, struct sk_buff *skb) + { +- if (desc->mss) { +- desc->total_hdr_length = (sizeof(struct ethhdr) + +- ip_hdrlen(skb) + tcp_hdrlen(skb)); +- +- if ((NX_IS_REVISION_P3(adapter->ahw.revision_id)) && +- (skb->protocol == htons(ETH_P_IPV6))) +- netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO6); +- else +- netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO); ++ bool tso = false; ++ u8 opcode = TX_ETHER_PKT; ++ ++ if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && ++ skb_shinfo(skb)->gso_size > 0) { ++ ++ desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); ++ desc->total_hdr_length = ++ skb_transport_offset(skb) + tcp_hdrlen(skb); ++ ++ opcode = (skb->protocol == htons(ETH_P_IPV6)) ? ++ TX_TCP_LSO6 : TX_TCP_LSO; ++ tso = true; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { +- if (ip_hdr(skb)->protocol == IPPROTO_TCP) +- netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT); +- else if (ip_hdr(skb)->protocol == IPPROTO_UDP) +- netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT); +- else +- return; ++ u8 l4proto; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ l4proto = ip_hdr(skb)->protocol; ++ ++ if (l4proto == IPPROTO_TCP) ++ opcode = TX_TCP_PKT; ++ else if(l4proto == IPPROTO_UDP) ++ opcode = TX_UDP_PKT; ++ } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ l4proto = ipv6_hdr(skb)->nexthdr; ++ ++ if (l4proto == IPPROTO_TCP) ++ opcode = TX_TCPV6_PKT; ++ else if(l4proto == IPPROTO_UDP) ++ opcode = TX_UDPV6_PKT; ++ } + } + desc->tcp_hdr_offset = skb_transport_offset(skb); + desc->ip_hdr_offset = skb_network_offset(skb); ++ netxen_set_tx_flags_opcode(desc, 0, opcode); ++ return tso; + } + + static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +@@ -1156,33 +1174,20 @@ static int netxen_nic_xmit_frame(struct + struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_hardware_context *hw = &adapter->ahw; + unsigned int first_seg_len = skb->len - skb->data_len; ++ struct netxen_cmd_buffer *pbuf; + struct netxen_skb_frag *buffrag; +- unsigned int i; ++ struct cmd_desc_type0 *hwdesc; ++ int i, k; + + u32 producer, consumer; +- u32 saved_producer = 0; +- struct cmd_desc_type0 *hwdesc; +- int k; +- struct netxen_cmd_buffer *pbuf = NULL; +- int frag_count; +- int no_of_desc; ++ int frag_count, no_of_desc; + u32 num_txd = adapter->max_tx_desc_count; ++ bool is_tso = false; + + frag_count = skb_shinfo(skb)->nr_frags + 1; + + /* There 4 fragments per descriptor */ + no_of_desc = (frag_count + 3) >> 2; +- if (netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) { +- if (skb_shinfo(skb)->gso_size > 0) { +- +- no_of_desc++; +- if ((ip_hdrlen(skb) + tcp_hdrlen(skb) + +- sizeof(struct ethhdr)) > +- (sizeof(struct cmd_desc_type0) - 2)) { +- no_of_desc++; +- } +- } +- } + + producer = adapter->cmd_producer; + smp_mb(); +@@ -1194,34 +1199,22 @@ static int netxen_nic_xmit_frame(struct + } + + /* Copy the descriptors into the hardware */ +- saved_producer = producer; + hwdesc = &hw->cmd_desc_head[producer]; + memset(hwdesc, 0, sizeof(struct cmd_desc_type0)); + /* Take skb->data itself */ + pbuf = &adapter->cmd_buf_arr[producer]; +- if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && +- skb_shinfo(skb)->gso_size > 0) { +- pbuf->mss = skb_shinfo(skb)->gso_size; +- hwdesc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); +- } else { +- pbuf->mss = 0; +- hwdesc->mss = 0; +- } +- pbuf->total_length = skb->len; ++ ++ is_tso = netxen_tso_check(netdev, hwdesc, skb); ++ + pbuf->skb = skb; +- pbuf->cmd = TX_ETHER_PKT; + pbuf->frag_count = frag_count; +- pbuf->port = adapter->portnum; + buffrag = &pbuf->frag_array[0]; + buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len, + PCI_DMA_TODEVICE); + buffrag->length = first_seg_len; +- netxen_set_cmd_desc_totallength(hwdesc, skb->len); +- netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count); +- netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT); ++ netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); ++ netxen_set_tx_port(hwdesc, adapter->portnum); + +- netxen_set_cmd_desc_port(hwdesc, adapter->portnum); +- netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum); + hwdesc->buffer1_length = cpu_to_le16(first_seg_len); + hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); + +@@ -1274,16 +1267,12 @@ static int netxen_nic_xmit_frame(struct + } + producer = get_next_index(producer, num_txd); + +- /* might change opcode to TX_TCP_LSO */ +- netxen_tso_check(adapter, &hw->cmd_desc_head[saved_producer], skb); +- + /* For LSO, we need to copy the MAC/IP/TCP headers into + * the descriptor ring + */ +- if (netxen_get_cmd_desc_opcode(&hw->cmd_desc_head[saved_producer]) +- == TX_TCP_LSO) { ++ if (is_tso) { + int hdr_len, first_hdr_len, more_hdr; +- hdr_len = hw->cmd_desc_head[saved_producer].total_hdr_length; ++ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) { + first_hdr_len = sizeof(struct cmd_desc_type0) - 2; + more_hdr = 1; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-link-speed-reporting-for-some-boards.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-link-speed-reporting-for-some-boards.patch new file mode 100644 index 000000000..a16b06ae4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-link-speed-reporting-for-some-boards.patch @@ -0,0 +1,237 @@ +From c7860a2aec571ea95d3ad19b8d9775b27828baac Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:48:32 -0800 +Subject: netxen: fix link speed reporting for some boards +Acked-by: Karsten Keil +Reference: bnc#472416 + +o Read negotiated link speed when link state changes. +o Fix link speed reporting for hybrid nic boards, which have both 1Gbps and + 10Gbps ports. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 3 ++- + drivers/net/netxen/netxen_nic_ethtool.c | 31 +++++++++++++++++++++++-------- + drivers/net/netxen/netxen_nic_hw.c | 28 ++++++++++++++++++++-------- + drivers/net/netxen/netxen_nic_main.c | 14 +++++++++++++- + 4 files changed, 58 insertions(+), 18 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic.h ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +@@ -499,7 +499,8 @@ typedef enum { + NETXEN_BRDTYPE_P3_10G_SFP_CT = 0x002a, + NETXEN_BRDTYPE_P3_10G_SFP_QT = 0x002b, + NETXEN_BRDTYPE_P3_10G_CX4 = 0x0031, +- NETXEN_BRDTYPE_P3_10G_XFP = 0x0032 ++ NETXEN_BRDTYPE_P3_10G_XFP = 0x0032, ++ NETXEN_BRDTYPE_P3_10G_TP = 0x0080 + + } netxen_brdtype_t; + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_ethtool.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_ethtool.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_ethtool.c +@@ -136,11 +136,9 @@ netxen_nic_get_settings(struct net_devic + + ecmd->port = PORT_TP; + +- if (netif_running(dev)) { +- ecmd->speed = adapter->link_speed; +- ecmd->duplex = adapter->link_duplex; +- ecmd->autoneg = adapter->link_autoneg; +- } ++ ecmd->speed = adapter->link_speed; ++ ecmd->duplex = adapter->link_duplex; ++ ecmd->autoneg = adapter->link_autoneg; + + } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { + u32 val; +@@ -171,7 +169,7 @@ netxen_nic_get_settings(struct net_devic + } else + return -EIO; + +- ecmd->phy_address = adapter->portnum; ++ ecmd->phy_address = adapter->physical_port; + ecmd->transceiver = XCVR_EXTERNAL; + + switch ((netxen_brdtype_t) boardinfo->board_type) { +@@ -180,13 +178,13 @@ netxen_nic_get_settings(struct net_devic + case NETXEN_BRDTYPE_P3_REF_QG: + case NETXEN_BRDTYPE_P3_4_GB: + case NETXEN_BRDTYPE_P3_4_GB_MM: +- case NETXEN_BRDTYPE_P3_10000_BASE_T: + + ecmd->supported |= SUPPORTED_Autoneg; + ecmd->advertising |= ADVERTISED_Autoneg; + case NETXEN_BRDTYPE_P2_SB31_10G_CX4: + case NETXEN_BRDTYPE_P3_10G_CX4: + case NETXEN_BRDTYPE_P3_10G_CX4_LP: ++ case NETXEN_BRDTYPE_P3_10000_BASE_T: + ecmd->supported |= SUPPORTED_TP; + ecmd->advertising |= ADVERTISED_TP; + ecmd->port = PORT_TP; +@@ -204,16 +202,33 @@ netxen_nic_get_settings(struct net_devic + ecmd->port = PORT_FIBRE; + ecmd->autoneg = AUTONEG_DISABLE; + break; +- case NETXEN_BRDTYPE_P2_SB31_10G: + case NETXEN_BRDTYPE_P3_10G_SFP_PLUS: + case NETXEN_BRDTYPE_P3_10G_SFP_CT: + case NETXEN_BRDTYPE_P3_10G_SFP_QT: ++ ecmd->advertising |= ADVERTISED_TP; ++ ecmd->supported |= SUPPORTED_TP; ++ case NETXEN_BRDTYPE_P2_SB31_10G: + case NETXEN_BRDTYPE_P3_10G_XFP: + ecmd->supported |= SUPPORTED_FIBRE; + ecmd->advertising |= ADVERTISED_FIBRE; + ecmd->port = PORT_FIBRE; + ecmd->autoneg = AUTONEG_DISABLE; + break; ++ case NETXEN_BRDTYPE_P3_10G_TP: ++ if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { ++ ecmd->autoneg = AUTONEG_DISABLE; ++ ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP); ++ ecmd->advertising |= ++ (ADVERTISED_FIBRE | ADVERTISED_TP); ++ ecmd->port = PORT_FIBRE; ++ } else { ++ ecmd->autoneg = AUTONEG_ENABLE; ++ ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg); ++ ecmd->advertising |= ++ (ADVERTISED_TP | ADVERTISED_Autoneg); ++ ecmd->port = PORT_TP; ++ } ++ break; + default: + printk(KERN_ERR "netxen-nic: Unsupported board model %d\n", + (netxen_brdtype_t) boardinfo->board_type); +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_hw.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_hw.c +@@ -2036,7 +2036,13 @@ int netxen_nic_get_board_info(struct net + rv = -1; + } + +- DPRINTK(INFO, "Discovered board type:0x%x ", boardinfo->board_type); ++ if (boardinfo->board_type == NETXEN_BRDTYPE_P3_4_GB_MM) { ++ u32 gpio = netxen_nic_reg_read(adapter, ++ NETXEN_ROMUSB_GLB_PAD_GPIO_I); ++ if ((gpio & 0x8000) == 0) ++ boardinfo->board_type = NETXEN_BRDTYPE_P3_10G_TP; ++ } ++ + switch ((netxen_brdtype_t) boardinfo->board_type) { + case NETXEN_BRDTYPE_P2_SB35_4G: + adapter->ahw.board_type = NETXEN_NIC_GBE; +@@ -2055,7 +2061,6 @@ int netxen_nic_get_board_info(struct net + case NETXEN_BRDTYPE_P3_10G_SFP_QT: + case NETXEN_BRDTYPE_P3_10G_XFP: + case NETXEN_BRDTYPE_P3_10000_BASE_T: +- + adapter->ahw.board_type = NETXEN_NIC_XGBE; + break; + case NETXEN_BRDTYPE_P1_BD: +@@ -2065,9 +2070,12 @@ int netxen_nic_get_board_info(struct net + case NETXEN_BRDTYPE_P3_REF_QG: + case NETXEN_BRDTYPE_P3_4_GB: + case NETXEN_BRDTYPE_P3_4_GB_MM: +- + adapter->ahw.board_type = NETXEN_NIC_GBE; + break; ++ case NETXEN_BRDTYPE_P3_10G_TP: ++ adapter->ahw.board_type = (adapter->portnum < 2) ? ++ NETXEN_NIC_XGBE : NETXEN_NIC_GBE; ++ break; + default: + printk("%s: Unknown(%x)\n", netxen_nic_driver_name, + boardinfo->board_type); +@@ -2112,12 +2120,16 @@ void netxen_nic_set_link_parameters(stru + { + __u32 status; + __u32 autoneg; +- __u32 mode; + __u32 port_mode; + +- netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); +- if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ ++ if (!netif_carrier_ok(adapter->netdev)) { ++ adapter->link_speed = 0; ++ adapter->link_duplex = -1; ++ adapter->link_autoneg = AUTONEG_ENABLE; ++ return; ++ } + ++ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { + adapter->hw_read_wx(adapter, + NETXEN_PORT_MODE_ADDR, &port_mode, 4); + if (port_mode == NETXEN_PORT_MODE_802_3_AP) { +@@ -2143,7 +2155,7 @@ void netxen_nic_set_link_parameters(stru + adapter->link_speed = SPEED_1000; + break; + default: +- adapter->link_speed = -1; ++ adapter->link_speed = 0; + break; + } + switch (netxen_get_phy_duplex(status)) { +@@ -2166,7 +2178,7 @@ void netxen_nic_set_link_parameters(stru + goto link_down; + } else { + link_down: +- adapter->link_speed = -1; ++ adapter->link_speed = 0; + adapter->link_duplex = -1; + } + } +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -243,7 +243,7 @@ static void netxen_check_options(struct + case NETXEN_BRDTYPE_P3_4_GB: + case NETXEN_BRDTYPE_P3_4_GB_MM: + adapter->msix_supported = !!use_msi_x; +- adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G; ++ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; + break; + + case NETXEN_BRDTYPE_P2_SB35_4G: +@@ -252,6 +252,14 @@ static void netxen_check_options(struct + adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; + break; + ++ case NETXEN_BRDTYPE_P3_10G_TP: ++ adapter->msix_supported = !!use_msi_x; ++ if (adapter->ahw.board_type == NETXEN_NIC_XGBE) ++ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G; ++ else ++ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; ++ break; ++ + default: + adapter->msix_supported = 0; + adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; +@@ -1385,6 +1393,8 @@ static void netxen_nic_handle_phy_intr(s + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } ++ ++ netxen_nic_set_link_parameters(adapter); + } else if (!adapter->ahw.linkup && linkup) { + printk(KERN_INFO "%s: %s NIC Link is up\n", + netxen_nic_driver_name, netdev->name); +@@ -1393,6 +1403,8 @@ static void netxen_nic_handle_phy_intr(s + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } ++ ++ netxen_nic_set_link_parameters(adapter); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-memory-leak-in-drivers-net-netxen_nic_in.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-memory-leak-in-drivers-net-netxen_nic_in.patch new file mode 100644 index 000000000..71988fa15 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-memory-leak-in-drivers-net-netxen_nic_in.patch @@ -0,0 +1,40 @@ +From 584dbe9475313e117abf9d2af88164edfd429c9a Mon Sep 17 00:00:00 2001 +From: =?utf-8?q?Daniel=20Marjam=C3=A4ki?= +Date: Thu, 29 Jan 2009 08:55:56 +0000 +Subject: netxen: fix memory leak in drivers/net/netxen_nic_init.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit +Acked-by: Karsten Keil +Reference: bnc#472416 + +For kernel bugzilla #12537: +http://bugzilla.kernel.org/show_bug.cgi?id=12537 + +Free memory. + +Signed-off-by: Daniel Marjamäki +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic_init.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c +index ca7c8d8..ffd37be 100644 +--- a/drivers/net/netxen/netxen_nic_init.c ++++ b/drivers/net/netxen/netxen_nic_init.c +@@ -947,8 +947,10 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) + } + for (i = 0; i < n; i++) { + if (netxen_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 || +- netxen_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) ++ netxen_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) { ++ kfree(buf); + return -EIO; ++ } + + buf[i].addr = addr; + buf[i].data = val; +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-vlan-tso-checksum-offload.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-vlan-tso-checksum-offload.patch new file mode 100644 index 000000000..ea8fa6148 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-fix-vlan-tso-checksum-offload.patch @@ -0,0 +1,69 @@ +From cdff1036492ac97b4213aeab2546914a633a7de7 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Mon, 26 Jan 2009 12:34:57 -0800 +Subject: netxen: fix vlan tso/checksum offload +Acked-by: Karsten Keil +Reference: bnc#472416 + +o set netdev->vlan_features appropriately. +o fix tso descriptor initialization for vlan case. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic_main.c | 31 ++++++++++++++++++++----------- + 1 files changed, 20 insertions(+), 11 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -1155,6 +1155,14 @@ static bool netxen_tso_check(struct net_ + { + bool tso = false; + u8 opcode = TX_ETHER_PKT; ++ __be16 protocol = skb->protocol; ++ u16 flags = 0; ++ ++ if (protocol == __constant_htons(ETH_P_8021Q)) { ++ struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; ++ protocol = vh->h_vlan_encapsulated_proto; ++ flags = FLAGS_VLAN_TAGGED; ++ } + + if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && + skb_shinfo(skb)->gso_size > 0) { +@@ -1163,21 +1171,21 @@ static bool netxen_tso_check(struct net_ + desc->total_hdr_length = + skb_transport_offset(skb) + tcp_hdrlen(skb); + +- opcode = (skb->protocol == htons(ETH_P_IPV6)) ? ++ opcode = (protocol == __constant_htons(ETH_P_IPV6)) ? + TX_TCP_LSO6 : TX_TCP_LSO; + tso = true; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + u8 l4proto; + +- if (skb->protocol == htons(ETH_P_IP)) { ++ if (protocol == __constant_htons(ETH_P_IP)) { + l4proto = ip_hdr(skb)->protocol; + + if (l4proto == IPPROTO_TCP) + opcode = TX_TCP_PKT; + else if(l4proto == IPPROTO_UDP) + opcode = TX_UDP_PKT; +- } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ } else if (protocol == __constant_htons(ETH_P_IPV6)) { + l4proto = ipv6_hdr(skb)->nexthdr; + + if (l4proto == IPPROTO_TCP) +@@ -1188,7 +1196,7 @@ static bool netxen_tso_check(struct net_ + } + desc->tcp_hdr_offset = skb_transport_offset(skb); + desc->ip_hdr_offset = skb_network_offset(skb); +- netxen_set_tx_flags_opcode(desc, 0, opcode); ++ netxen_set_tx_flags_opcode(desc, flags, opcode); + return tso; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-handle-dma-mapping-failures.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-handle-dma-mapping-failures.patch new file mode 100644 index 000000000..7000e2fdb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-handle-dma-mapping-failures.patch @@ -0,0 +1,266 @@ +From 6f70340698333f14b1d9c9e913c5de8f66b72c55 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:50:00 -0800 +Subject: netxen: handle dma mapping failures +Acked-by: Karsten Keil +Reference: bnc#472416 + +o Bail out if pci_map_single() fails while replenishing rx ring. +o Drop packet if pci_map_{single,page}() fail in tx. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 1 - + drivers/net/netxen/netxen_nic_init.c | 68 ++++++++++++++++------------------ + drivers/net/netxen/netxen_nic_main.c | 38 +++++++++++++++++- + 3 files changed, 67 insertions(+), 40 deletions(-) + +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic.h ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic.h +@@ -860,7 +860,6 @@ struct nx_host_rds_ring { + u32 skb_size; + struct netxen_rx_buffer *rx_buf_arr; /* rx buffers for receive */ + struct list_head free_list; +- int begin_alloc; + }; + + /* +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_init.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_init.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_init.c +@@ -308,7 +308,6 @@ int netxen_alloc_sw_resources(struct net + } + memset(rds_ring->rx_buf_arr, 0, RCV_BUFFSIZE); + INIT_LIST_HEAD(&rds_ring->free_list); +- rds_ring->begin_alloc = 0; + /* + * Now go through all of them, set reference handles + * and put them in the queues. +@@ -1437,7 +1436,6 @@ void netxen_post_rx_buffers(struct netxe + struct rcv_desc *pdesc; + struct netxen_rx_buffer *buffer; + int count = 0; +- int index = 0; + netxen_ctx_msg msg = 0; + dma_addr_t dma; + struct list_head *head; +@@ -1445,7 +1443,6 @@ void netxen_post_rx_buffers(struct netxe + rds_ring = &recv_ctx->rds_rings[ringid]; + + producer = rds_ring->producer; +- index = rds_ring->begin_alloc; + head = &rds_ring->free_list; + + /* We can start writing rx descriptors into the phantom memory. */ +@@ -1453,39 +1450,37 @@ void netxen_post_rx_buffers(struct netxe + + skb = dev_alloc_skb(rds_ring->skb_size); + if (unlikely(!skb)) { +- rds_ring->begin_alloc = index; + break; + } + ++ if (!adapter->ahw.cut_through) ++ skb_reserve(skb, 2); ++ ++ dma = pci_map_single(pdev, skb->data, ++ rds_ring->dma_size, PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(pdev, dma)) { ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ ++ count++; + buffer = list_entry(head->next, struct netxen_rx_buffer, list); + list_del(&buffer->list); + +- count++; /* now there should be no failure */ +- pdesc = &rds_ring->desc_head[producer]; +- +- if (!adapter->ahw.cut_through) +- skb_reserve(skb, 2); +- /* This will be setup when we receive the +- * buffer after it has been filled FSL TBD TBD +- * skb->dev = netdev; +- */ +- dma = pci_map_single(pdev, skb->data, rds_ring->dma_size, +- PCI_DMA_FROMDEVICE); +- pdesc->addr_buffer = cpu_to_le64(dma); + buffer->skb = skb; + buffer->state = NETXEN_BUFFER_BUSY; + buffer->dma = dma; ++ + /* make a rcv descriptor */ ++ pdesc = &rds_ring->desc_head[producer]; ++ pdesc->addr_buffer = cpu_to_le64(dma); + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); +- DPRINTK(INFO, "done writing descripter\n"); +- producer = +- get_next_index(producer, rds_ring->max_rx_desc_count); +- index = get_next_index(index, rds_ring->max_rx_desc_count); ++ ++ producer = get_next_index(producer, rds_ring->max_rx_desc_count); + } + /* if we did allocate buffers, then write the count to Phantom */ + if (count) { +- rds_ring->begin_alloc = index; + rds_ring->producer = producer; + /* Window = 1 */ + adapter->pci_write_normalize(adapter, +@@ -1524,49 +1519,50 @@ static void netxen_post_rx_buffers_nodb( + struct rcv_desc *pdesc; + struct netxen_rx_buffer *buffer; + int count = 0; +- int index = 0; + struct list_head *head; ++ dma_addr_t dma; + + rds_ring = &recv_ctx->rds_rings[ringid]; + + producer = rds_ring->producer; +- index = rds_ring->begin_alloc; + head = &rds_ring->free_list; + /* We can start writing rx descriptors into the phantom memory. */ + while (!list_empty(head)) { + + skb = dev_alloc_skb(rds_ring->skb_size); + if (unlikely(!skb)) { +- rds_ring->begin_alloc = index; + break; + } + ++ if (!adapter->ahw.cut_through) ++ skb_reserve(skb, 2); ++ ++ dma = pci_map_single(pdev, skb->data, ++ rds_ring->dma_size, PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(pdev, dma)) { ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ ++ count++; + buffer = list_entry(head->next, struct netxen_rx_buffer, list); + list_del(&buffer->list); + +- count++; /* now there should be no failure */ +- pdesc = &rds_ring->desc_head[producer]; +- if (!adapter->ahw.cut_through) +- skb_reserve(skb, 2); + buffer->skb = skb; + buffer->state = NETXEN_BUFFER_BUSY; +- buffer->dma = pci_map_single(pdev, skb->data, +- rds_ring->dma_size, +- PCI_DMA_FROMDEVICE); ++ buffer->dma = dma; + + /* make a rcv descriptor */ ++ pdesc = &rds_ring->desc_head[producer]; + pdesc->reference_handle = cpu_to_le16(buffer->ref_handle); + pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size); + pdesc->addr_buffer = cpu_to_le64(buffer->dma); +- producer = +- get_next_index(producer, rds_ring->max_rx_desc_count); +- index = get_next_index(index, rds_ring->max_rx_desc_count); +- buffer = &rds_ring->rx_buf_arr[index]; ++ ++ producer = get_next_index(producer, rds_ring->max_rx_desc_count); + } + + /* if we did allocate buffers, then write the count to Phantom */ + if (count) { +- rds_ring->begin_alloc = index; + rds_ring->producer = producer; + /* Window = 1 */ + adapter->pci_write_normalize(adapter, +Index: linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +=================================================================== +--- linux-2.6.27-kketmp.orig/drivers/net/netxen/netxen_nic_main.c ++++ linux-2.6.27-kketmp/drivers/net/netxen/netxen_nic_main.c +@@ -1189,6 +1189,24 @@ static bool netxen_tso_check(struct net_ + return tso; + } + ++static void ++netxen_clean_tx_dma_mapping(struct pci_dev *pdev, ++ struct netxen_cmd_buffer *pbuf, int last) ++{ ++ int k; ++ struct netxen_skb_frag *buffrag; ++ ++ buffrag = &pbuf->frag_array[0]; ++ pci_unmap_single(pdev, buffrag->dma, ++ buffrag->length, PCI_DMA_TODEVICE); ++ ++ for (k = 1; k < last; k++) { ++ buffrag = &pbuf->frag_array[k]; ++ pci_unmap_page(pdev, buffrag->dma, ++ buffrag->length, PCI_DMA_TODEVICE); ++ } ++} ++ + static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) + { + struct netxen_adapter *adapter = netdev_priv(netdev); +@@ -1197,6 +1215,8 @@ static int netxen_nic_xmit_frame(struct + struct netxen_cmd_buffer *pbuf; + struct netxen_skb_frag *buffrag; + struct cmd_desc_type0 *hwdesc; ++ struct pci_dev *pdev = adapter->pdev; ++ dma_addr_t temp_dma; + int i, k; + + u32 producer, consumer; +@@ -1229,8 +1249,12 @@ static int netxen_nic_xmit_frame(struct + pbuf->skb = skb; + pbuf->frag_count = frag_count; + buffrag = &pbuf->frag_array[0]; +- buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len, ++ temp_dma = pci_map_single(pdev, skb->data, first_seg_len, + PCI_DMA_TODEVICE); ++ if (pci_dma_mapping_error(pdev, temp_dma)) ++ goto drop_packet; ++ ++ buffrag->dma = temp_dma; + buffrag->length = first_seg_len; + netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); + netxen_set_tx_port(hwdesc, adapter->portnum); +@@ -1242,7 +1266,6 @@ static int netxen_nic_xmit_frame(struct + struct skb_frag_struct *frag; + int len, temp_len; + unsigned long offset; +- dma_addr_t temp_dma; + + /* move to next desc. if there is a need */ + if ((i & 0x3) == 0) { +@@ -1258,8 +1281,12 @@ static int netxen_nic_xmit_frame(struct + offset = frag->page_offset; + + temp_len = len; +- temp_dma = pci_map_page(adapter->pdev, frag->page, offset, ++ temp_dma = pci_map_page(pdev, frag->page, offset, + len, PCI_DMA_TODEVICE); ++ if (pci_dma_mapping_error(pdev, temp_dma)) { ++ netxen_clean_tx_dma_mapping(pdev, pbuf, i); ++ goto drop_packet; ++ } + + buffrag++; + buffrag->dma = temp_dma; +@@ -1334,6 +1361,11 @@ static int netxen_nic_xmit_frame(struct + netdev->trans_start = jiffies; + + return NETDEV_TX_OK; ++ ++drop_packet: ++ adapter->stats.txdropped++; ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; + } + + static int netxen_nic_check_temp(struct netxen_adapter *adapter) diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-hold-tx-lock-while-sending-firmware-commands.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-hold-tx-lock-while-sending-firmware-commands.patch new file mode 100644 index 000000000..1a1e04aa9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-hold-tx-lock-while-sending-firmware-commands.patch @@ -0,0 +1,42 @@ +From 03e678ee968ae54b79c1580c2935895bd863ad95 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Wed, 14 Jan 2009 20:49:43 -0800 +Subject: netxen: hold tx lock while sending firmware commands +Acked-by: Karsten Keil +Reference: bnc#472416 + +Some firmware commands like mac address addition/deletion are sent +on the transmit ring. So need to hold the tx lock before touching +tx producer/consumer indices. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic_hw.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c +index e2d2a2f..821cff6 100644 +--- a/drivers/net/netxen/netxen_nic_hw.c ++++ b/drivers/net/netxen/netxen_nic_hw.c +@@ -503,6 +503,8 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, + + i = 0; + ++ netif_tx_lock_bh(adapter->netdev); ++ + producer = adapter->cmd_producer; + do { + cmd_desc = &cmd_desc_arr[i]; +@@ -527,6 +529,8 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, + + netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer); + ++ netif_tx_unlock_bh(adapter->netdev); ++ + return 0; + } + +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-include-ipv6.h-fixes-build-failure.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-include-ipv6.h-fixes-build-failure.patch new file mode 100644 index 000000000..bbfe0dbf1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-include-ipv6.h-fixes-build-failure.patch @@ -0,0 +1,35 @@ +From 009777846165fcc49352c0f1487e3a96102884c3 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Fri, 16 Jan 2009 11:03:25 -0800 +Subject: netxen: include ipv6.h (fixes build failure) +Acked-by: Karsten Keil +Reference: bnc#472416 + +Fixes a build error in absence of CONFIG_IPV6: + +drivers/net/netxen/netxen_nic_main.c:1189: error: implicit declaration of function 'ipv6_hdr' +drivers/net/netxen/netxen_nic_main.c:1189: error: invalid type argument of '->' + +Reported-by: Ingo Molnar + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic_main.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c +index f8e2629..d854f07 100644 +--- a/drivers/net/netxen/netxen_nic_main.c ++++ b/drivers/net/netxen/netxen_nic_main.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); + MODULE_LICENSE("GPL"); +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-reduce-memory-footprint.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-reduce-memory-footprint.patch new file mode 100644 index 000000000..9fc6dbd7b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-reduce-memory-footprint.patch @@ -0,0 +1,66 @@ +From 32ec803348b4d5f1353e1d7feae30880b8b3e342 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Mon, 26 Jan 2009 12:35:19 -0800 +Subject: netxen: reduce memory footprint +Acked-by: Karsten Keil +Reference: bnc#472416 + +o reduce rx ring size from 8192 to 4096. +o cut down old huge lro buffers. + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 12 ++++++------ + drivers/net/netxen/netxen_nic_ethtool.c | 5 ++++- + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h +index c11c568..a75a310 100644 +--- a/drivers/net/netxen/netxen_nic.h ++++ b/drivers/net/netxen/netxen_nic.h +@@ -146,7 +146,7 @@ + + #define MAX_RX_BUFFER_LENGTH 1760 + #define MAX_RX_JUMBO_BUFFER_LENGTH 8062 +-#define MAX_RX_LRO_BUFFER_LENGTH ((48*1024)-512) ++#define MAX_RX_LRO_BUFFER_LENGTH (8062) + #define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2) + #define RX_JUMBO_DMA_MAP_LEN \ + (MAX_RX_JUMBO_BUFFER_LENGTH - 2) +@@ -207,11 +207,11 @@ + + #define MAX_CMD_DESCRIPTORS 4096 + #define MAX_RCV_DESCRIPTORS 16384 +-#define MAX_CMD_DESCRIPTORS_HOST (MAX_CMD_DESCRIPTORS / 4) +-#define MAX_RCV_DESCRIPTORS_1G (MAX_RCV_DESCRIPTORS / 4) +-#define MAX_RCV_DESCRIPTORS_10G 8192 +-#define MAX_JUMBO_RCV_DESCRIPTORS 1024 +-#define MAX_LRO_RCV_DESCRIPTORS 64 ++#define MAX_CMD_DESCRIPTORS_HOST 1024 ++#define MAX_RCV_DESCRIPTORS_1G 2048 ++#define MAX_RCV_DESCRIPTORS_10G 4096 ++#define MAX_JUMBO_RCV_DESCRIPTORS 512 ++#define MAX_LRO_RCV_DESCRIPTORS 8 + #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS + #define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS + #define MAX_RCV_DESC MAX_RCV_DESCRIPTORS +diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c +index c0bd40f..0894a7b 100644 +--- a/drivers/net/netxen/netxen_nic_ethtool.c ++++ b/drivers/net/netxen/netxen_nic_ethtool.c +@@ -561,7 +561,10 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) + } + ring->tx_pending = adapter->max_tx_desc_count; + +- ring->rx_max_pending = MAX_RCV_DESCRIPTORS; ++ if (adapter->ahw.board_type == NETXEN_NIC_GBE) ++ ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G; ++ else ++ ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G; + ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST; + ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS; + ring->rx_mini_max_pending = 0; +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/netxen-revert-jumbo-ringsize.patch b/src/patches/suse-2.6.27.31/patches.drivers/netxen-revert-jumbo-ringsize.patch new file mode 100644 index 000000000..8b0c451f8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/netxen-revert-jumbo-ringsize.patch @@ -0,0 +1,39 @@ +From e125646ab56b490d0390b158e0afa9cccfc1f897 Mon Sep 17 00:00:00 2001 +From: Dhananjay Phadke +Date: Thu, 29 Jan 2009 16:05:19 -0800 +Subject: netxen: revert jumbo ringsize +Acked-by: Karsten Keil +Reference: bnc#472416 + +Reducing jumbo ring size below 1024 reduces throughput for old +firmwares (3.4.216 and older) running on older (NX2031) chip, +so restore it back to 1024. + +This was reduced in commit 32ec803348b4d5f1353e1d7feae30880b8b3e342 +("netxen: reduce memory footprint"). + +Raising jumbo ring size from 512 to 1024, adds ~4MB per port, but +there's still big saving because of original patch (~20MB per port). + +Signed-off-by: Dhananjay Phadke +Signed-off-by: David S. Miller +--- + drivers/net/netxen/netxen_nic.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h +index a75a310..9c78c96 100644 +--- a/drivers/net/netxen/netxen_nic.h ++++ b/drivers/net/netxen/netxen_nic.h +@@ -210,7 +210,7 @@ + #define MAX_CMD_DESCRIPTORS_HOST 1024 + #define MAX_RCV_DESCRIPTORS_1G 2048 + #define MAX_RCV_DESCRIPTORS_10G 4096 +-#define MAX_JUMBO_RCV_DESCRIPTORS 512 ++#define MAX_JUMBO_RCV_DESCRIPTORS 1024 + #define MAX_LRO_RCV_DESCRIPTORS 8 + #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS + #define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta3-update b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta3-update new file mode 100644 index 000000000..737122d35 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta3-update @@ -0,0 +1,6688 @@ +Subject: Open-FCoE update for Beta3 +From: John Fastabend +Date: Thu Nov 6 13:01:32 2008 +0100: +Git: 2d8ac46f55c5f06ac3fe9830c899386789aa8900 +References: bnc#438954 + +Incremental Open-FCoE update for Beta3. + +Signed-off-by: John Fastabend +Acked-by: Hannes Reinecke + +diff --git a/drivers/scsi/fcoe/fcoe_if.c b/drivers/scsi/fcoe/fcoe_if.c +index 7f983e2..73b83ce 100644 +--- a/drivers/scsi/fcoe/fcoe_if.c ++++ b/drivers/scsi/fcoe/fcoe_if.c +@@ -155,18 +155,18 @@ int fcoe_destroy_interface(const char *ifname) + list_del(&fc->list); + write_unlock_bh(&fci->fcoe_hostlist_lock); + +- /* Cleanup the fc_lport */ +- fc_lport_destroy(lp); +- fc_fcp_destroy(lp); +- if (lp->emp) +- fc_exch_mgr_free(lp->emp); ++ /* Don't listen for Ethernet packets anymore */ ++ dev_remove_pack(&fc->fcoe_packet_type); + + /* Detach from the scsi-ml */ + fc_remove_host(lp->host); + scsi_remove_host(lp->host); + +- /* Don't listen for Ethernet packets anymore */ +- dev_remove_pack(&fc->fcoe_packet_type); ++ /* Cleanup the fc_lport */ ++ fc_lport_destroy(lp); ++ fc_fcp_destroy(lp); ++ if (lp->emp) ++ fc_exch_mgr_free(lp->emp); + + /* Delete secondary MAC addresses */ + rtnl_lock(); +@@ -388,8 +388,7 @@ static int libfc_config(struct fc_lport *lp) + fc_exch_init(lp); + fc_lport_init(lp); + fc_rport_init(lp); +- fc_ns_init(lp); +- fc_attr_init(lp); ++ fc_disc_init(lp); + + return 0; + } +diff --git a/drivers/scsi/fcoe/fcoeinit.c b/drivers/scsi/fcoe/fcoeinit.c +index e069835..7d52ed5 100644 +--- a/drivers/scsi/fcoe/fcoeinit.c ++++ b/drivers/scsi/fcoe/fcoeinit.c +@@ -53,8 +53,8 @@ struct scsi_transport_template *fcoe_transport_template; + + static int fcoe_reset(struct Scsi_Host *shost) + { +- struct fc_lport *lp = shost_priv(shost); +- fc_lport_enter_reset(lp); ++ struct fc_lport *lport = shost_priv(shost); ++ fc_lport_reset(lport); + return 0; + } + +@@ -66,11 +66,10 @@ struct fc_function_template fcoe_transport_function = { + .show_host_active_fc4s = 1, + .show_host_maxframe_size = 1, + +- .get_host_port_id = fc_get_host_port_id, + .show_host_port_id = 1, ++ .show_host_supported_speeds = 1, + .get_host_speed = fc_get_host_speed, + .show_host_speed = 1, +- .get_host_port_type = fc_get_host_port_type, + .show_host_port_type = 1, + .get_host_port_state = fc_get_host_port_state, + .show_host_port_state = 1, +@@ -80,7 +79,6 @@ struct fc_function_template fcoe_transport_function = { + .show_rport_maxframe_size = 1, + .show_rport_supported_classes = 1, + +- .get_host_fabric_name = fc_get_host_fabric_name, + .show_host_fabric_name = 1, + .show_starget_node_name = 1, + .show_starget_port_name = 1, +@@ -89,6 +87,8 @@ struct fc_function_template fcoe_transport_function = { + .show_rport_dev_loss_tmo = 1, + .get_fc_host_stats = fc_get_host_stats, + .issue_fc_host_lip = fcoe_reset, ++ ++ .terminate_rport_io = fc_rport_terminate_io, + }; + + struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; +diff --git a/drivers/scsi/libfc/Makefile b/drivers/scsi/libfc/Makefile +index 0a31ca2..e6d4086 100644 +--- a/drivers/scsi/libfc/Makefile ++++ b/drivers/scsi/libfc/Makefile +@@ -3,10 +3,9 @@ + obj-$(CONFIG_LIBFC) += libfc.o + + libfc-objs := \ +- fc_ns.o \ ++ fc_disc.o \ + fc_exch.o \ + fc_frame.o \ + fc_lport.o \ + fc_rport.o \ +- fc_attr.o \ + fc_fcp.o +diff --git a/drivers/scsi/libfc/fc_attr.c b/drivers/scsi/libfc/fc_attr.c +deleted file mode 100644 +index d73f39e..0000000 +--- a/drivers/scsi/libfc/fc_attr.c ++++ /dev/null +@@ -1,129 +0,0 @@ +-/* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-#include +-#include +- +-#include +- +-#include +- +-MODULE_AUTHOR("Open-FCoE.org"); +-MODULE_DESCRIPTION("libfc"); +-MODULE_LICENSE("GPL"); +- +-void fc_get_host_port_id(struct Scsi_Host *shost) +-{ +- struct fc_lport *lp = shost_priv(shost); +- +- fc_host_port_id(shost) = fc_lport_get_fid(lp); +-} +-EXPORT_SYMBOL(fc_get_host_port_id); +- +-void fc_get_host_speed(struct Scsi_Host *shost) +-{ +- /* +- * should be obtain from DEC or Enet Driver +- */ +- fc_host_speed(shost) = 1; /* for now it is 1g */ +-} +-EXPORT_SYMBOL(fc_get_host_speed); +- +-void fc_get_host_port_type(struct Scsi_Host *shost) +-{ +- fc_host_port_type(shost) = FC_PORTTYPE_NPORT; +-} +-EXPORT_SYMBOL(fc_get_host_port_type); +- +-void fc_get_host_fabric_name(struct Scsi_Host *shost) +-{ +- struct fc_lport *lp = shost_priv(shost); +- +- fc_host_fabric_name(shost) = lp->wwnn; +-} +-EXPORT_SYMBOL(fc_get_host_fabric_name); +- +-void fc_attr_init(struct fc_lport *lp) +-{ +- fc_host_node_name(lp->host) = lp->wwnn; +- fc_host_port_name(lp->host) = lp->wwpn; +- fc_host_supported_classes(lp->host) = FC_COS_CLASS3; +- memset(fc_host_supported_fc4s(lp->host), 0, +- sizeof(fc_host_supported_fc4s(lp->host))); +- fc_host_supported_fc4s(lp->host)[2] = 1; +- fc_host_supported_fc4s(lp->host)[7] = 1; +- /* This value is also unchanging */ +- memset(fc_host_active_fc4s(lp->host), 0, +- sizeof(fc_host_active_fc4s(lp->host))); +- fc_host_active_fc4s(lp->host)[2] = 1; +- fc_host_active_fc4s(lp->host)[7] = 1; +- fc_host_maxframe_size(lp->host) = lp->mfs; +-} +-EXPORT_SYMBOL(fc_attr_init); +- +-void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) +-{ +- if (timeout) +- rport->dev_loss_tmo = timeout + 5; +- else +- rport->dev_loss_tmo = 30; +- +-} +-EXPORT_SYMBOL(fc_set_rport_loss_tmo); +- +-struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) +-{ +- int i; +- struct fc_host_statistics *fcoe_stats; +- struct fc_lport *lp = shost_priv(shost); +- struct timespec v0, v1; +- +- fcoe_stats = &lp->host_stats; +- memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); +- +- jiffies_to_timespec(jiffies, &v0); +- jiffies_to_timespec(lp->boot_time, &v1); +- fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); +- +- for_each_online_cpu(i) { +- struct fcoe_dev_stats *stats = lp->dev_stats[i]; +- if (stats == NULL) +- continue; +- fcoe_stats->tx_frames += stats->TxFrames; +- fcoe_stats->tx_words += stats->TxWords; +- fcoe_stats->rx_frames += stats->RxFrames; +- fcoe_stats->rx_words += stats->RxWords; +- fcoe_stats->error_frames += stats->ErrorFrames; +- fcoe_stats->invalid_crc_count += stats->InvalidCRCCount; +- fcoe_stats->fcp_input_requests += stats->InputRequests; +- fcoe_stats->fcp_output_requests += stats->OutputRequests; +- fcoe_stats->fcp_control_requests += stats->ControlRequests; +- fcoe_stats->fcp_input_megabytes += stats->InputMegabytes; +- fcoe_stats->fcp_output_megabytes += stats->OutputMegabytes; +- fcoe_stats->link_failure_count += stats->LinkFailureCount; +- } +- fcoe_stats->lip_count = -1; +- fcoe_stats->nos_count = -1; +- fcoe_stats->loss_of_sync_count = -1; +- fcoe_stats->loss_of_signal_count = -1; +- fcoe_stats->prim_seq_protocol_err_count = -1; +- fcoe_stats->dumped_frames = -1; +- return fcoe_stats; +-} +-EXPORT_SYMBOL(fc_get_host_stats); +diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c +new file mode 100644 +index 0000000..30403aa +--- /dev/null ++++ b/drivers/scsi/libfc/fc_disc.c +@@ -0,0 +1,599 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Target Discovery ++ * Actually, this discovers all FC-4 remote ports, including FCP initiators. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define FC_DISC_RETRY_LIMIT 3 /* max retries */ ++#define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ ++ ++int fc_disc_debug; ++ ++static void fc_disc_gpn_ft_req(struct fc_lport *); ++static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); ++static int fc_disc_new_target(struct fc_lport *, struct fc_rport *, ++ struct fc_rport_identifiers *); ++static void fc_disc_del_target(struct fc_lport *, struct fc_rport *); ++static void fc_disc_done(struct fc_lport *); ++static void fc_disc_error(struct fc_lport *, struct fc_frame *); ++static void fc_disc_timeout(struct work_struct *); ++static void fc_disc_single(struct fc_lport *, struct fc_disc_port *); ++static int fc_disc_restart(struct fc_lport *); ++ ++/** ++ * fc_disc_rscn_req - Handle Registered State Change Notification (RSCN) ++ * @sp: Current sequence of the RSCN exchange ++ * @fp: RSCN Frame ++ * @lp: Fibre Channel host port instance ++ */ ++static void fc_disc_rscn_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lp) ++{ ++ struct fc_els_rscn *rp; ++ struct fc_els_rscn_page *pp; ++ struct fc_seq_els_data rjt_data; ++ unsigned int len; ++ int redisc = 0; ++ enum fc_els_rscn_ev_qual ev_qual; ++ enum fc_els_rscn_addr_fmt fmt; ++ LIST_HEAD(disc_list); ++ struct fc_disc_port *dp, *next; ++ ++ rp = fc_frame_payload_get(fp, sizeof(*rp)); ++ ++ if (!rp || rp->rscn_page_len != sizeof(*pp)) ++ goto reject; ++ ++ len = ntohs(rp->rscn_plen); ++ if (len < sizeof(*rp)) ++ goto reject; ++ len -= sizeof(*rp); ++ ++ for (pp = (void *)(rp + 1); len; len -= sizeof(*pp), pp++) { ++ ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT; ++ ev_qual &= ELS_RSCN_EV_QUAL_MASK; ++ fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT; ++ fmt &= ELS_RSCN_ADDR_FMT_MASK; ++ /* ++ * if we get an address format other than port ++ * (area, domain, fabric), then do a full discovery ++ */ ++ switch (fmt) { ++ case ELS_ADDR_FMT_PORT: ++ dp = kzalloc(sizeof(*dp), GFP_KERNEL); ++ if (!dp) { ++ redisc = 1; ++ break; ++ } ++ dp->lp = lp; ++ dp->ids.port_id = ntoh24(pp->rscn_fid); ++ dp->ids.port_name = -1; ++ dp->ids.node_name = -1; ++ dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ list_add_tail(&dp->peers, &disc_list); ++ break; ++ case ELS_ADDR_FMT_AREA: ++ case ELS_ADDR_FMT_DOM: ++ case ELS_ADDR_FMT_FAB: ++ default: ++ redisc = 1; ++ break; ++ } ++ } ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ if (redisc) { ++ if (fc_disc_debug) ++ FC_DBG("RSCN received: rediscovering\n"); ++ list_for_each_entry_safe(dp, next, &disc_list, peers) { ++ list_del(&dp->peers); ++ kfree(dp); ++ } ++ fc_disc_restart(lp); ++ } else { ++ if (fc_disc_debug) ++ FC_DBG("RSCN received: not rediscovering. " ++ "redisc %d state %d in_prog %d\n", ++ redisc, lp->state, lp->disc_pending); ++ list_for_each_entry_safe(dp, next, &disc_list, peers) { ++ list_del(&dp->peers); ++ fc_disc_single(lp, dp); ++ } ++ } ++ fc_frame_free(fp); ++ return; ++reject: ++ rjt_data.fp = NULL; ++ rjt_data.reason = ELS_RJT_LOGIC; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ fc_frame_free(fp); ++} ++ ++static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lp) ++{ ++ switch (fc_frame_payload_op(fp)) { ++ case ELS_RSCN: ++ fc_disc_rscn_req(sp, fp, lp); ++ break; ++ default: ++ FC_DBG("fc_disc recieved an unexpected request\n"); ++ break; ++ } ++} ++ ++/* ++ * Refresh target discovery, perhaps due to an RSCN. ++ * A configurable delay is introduced to collect any subsequent RSCNs. ++ */ ++static int fc_disc_restart(struct fc_lport *lp) ++{ ++ if (!lp->disc_requested && !lp->disc_pending) { ++ schedule_delayed_work(&lp->disc_work, ++ msecs_to_jiffies(lp->disc_delay * 1000)); ++ } ++ lp->disc_requested = 1; ++ return 0; ++} ++ ++/* ++ * Fibre Channel Target discovery. ++ * ++ * Returns non-zero if discovery cannot be started. ++ * ++ * Callback is called for each target remote port found in discovery. ++ * When discovery is complete, the callback is called with a NULL remote port. ++ * Discovery may be restarted after an RSCN is received, causing the ++ * callback to be called after discovery complete is indicated. ++ */ ++int fc_disc_start(struct fc_lport *lp) ++{ ++ struct fc_rport *rport; ++ int error; ++ struct fc_rport_identifiers ids; ++ ++ /* ++ * If not ready, or already running discovery, just set request flag. ++ */ ++ if (!fc_lport_test_ready(lp) || lp->disc_pending) { ++ lp->disc_requested = 1; ++ ++ return 0; ++ } ++ lp->disc_pending = 1; ++ lp->disc_requested = 0; ++ lp->disc_retry_count = 0; ++ ++ /* ++ * Handle point-to-point mode as a simple discovery ++ * of the remote port. ++ */ ++ rport = lp->ptp_rp; ++ if (rport) { ++ ids.port_id = rport->port_id; ++ ids.port_name = rport->port_name; ++ ids.node_name = rport->node_name; ++ ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ get_device(&rport->dev); ++ ++ error = fc_disc_new_target(lp, rport, &ids); ++ put_device(&rport->dev); ++ if (!error) ++ fc_disc_done(lp); ++ } else { ++ fc_block_rports(lp); ++ fc_disc_gpn_ft_req(lp); /* get ports by FC-4 type */ ++ error = 0; ++ } ++ return error; ++} ++ ++/* ++ * Restart discovery after a delay due to resource shortages. ++ * If the error persists, the discovery will be abandoned. ++ */ ++static void fc_disc_retry(struct fc_lport *lp) ++{ ++ unsigned long delay = FC_DISC_RETRY_DELAY; ++ ++ if (!lp->disc_retry_count) ++ delay /= 4; /* timeout faster first time */ ++ if (lp->disc_retry_count++ < FC_DISC_RETRY_LIMIT) ++ schedule_delayed_work(&lp->disc_work, ++ msecs_to_jiffies(delay)); ++ else ++ fc_disc_done(lp); ++} ++ ++/* ++ * Handle new target found by discovery. ++ * Create remote port and session if needed. ++ * Ignore returns of our own FID & WWPN. ++ * ++ * If a non-NULL rp is passed in, it is held for the caller, but not for us. ++ * ++ * Events delivered are: ++ * FC_EV_READY, when remote port is rediscovered. ++ */ ++static int fc_disc_new_target(struct fc_lport *lp, ++ struct fc_rport *rport, ++ struct fc_rport_identifiers *ids) ++{ ++ struct fc_rport_libfc_priv *rp; ++ int error = 0; ++ ++ if (rport && ids->port_name) { ++ if (rport->port_name == -1) { ++ /* ++ * Set WWN and fall through to notify of create. ++ */ ++ fc_rport_set_name(rport, ids->port_name, ++ rport->node_name); ++ } else if (rport->port_name != ids->port_name) { ++ /* ++ * This is a new port with the same FCID as ++ * a previously-discovered port. Presumably the old ++ * port logged out and a new port logged in and was ++ * assigned the same FCID. This should be rare. ++ * Delete the old one and fall thru to re-create. ++ */ ++ fc_disc_del_target(lp, rport); ++ rport = NULL; ++ } ++ } ++ if (((ids->port_name != -1) || (ids->port_id != -1)) && ++ ids->port_id != lp->fid && ids->port_name != lp->wwpn) { ++ if (!rport) { ++ rport = lp->tt.rport_lookup(lp, ids->port_id); ++ if (!rport) { ++ struct fc_disc_port dp; ++ dp.lp = lp; ++ dp.ids.port_id = ids->port_id; ++ dp.ids.port_name = ids->port_name; ++ dp.ids.node_name = ids->node_name; ++ dp.ids.roles = ids->roles; ++ rport = fc_rport_dummy_create(&dp); ++ } ++ if (!rport) ++ error = ENOMEM; ++ } ++ if (rport) { ++ rp = rport->dd_data; ++ rp->event_callback = lp->tt.event_callback; ++ rp->rp_state = RPORT_ST_INIT; ++ lp->tt.rport_login(rport); ++ } ++ } ++ return error; ++} ++ ++/* ++ * Delete the remote port. ++ */ ++static void fc_disc_del_target(struct fc_lport *lp, struct fc_rport *rport) ++{ ++ lp->tt.rport_reset(rport); ++ fc_remote_port_delete(rport); /* release hold from create */ ++} ++ ++/* ++ * Done with discovery ++ */ ++static void fc_disc_done(struct fc_lport *lp) ++{ ++ lp->disc_done = 1; ++ lp->disc_pending = 0; ++ if (lp->disc_requested) ++ lp->tt.disc_start(lp); ++} ++ ++/** ++ * fc_disc_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request ++ * @lp: Fibre Channel host port instance ++ */ ++static void fc_disc_gpn_ft_req(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_seq *sp = NULL; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_gid_ft gid; ++ } *rp; ++ int error = 0; ++ ++ lp->disc_buf_len = 0; ++ lp->disc_seq_count = 0; ++ fp = fc_frame_alloc(lp, sizeof(*rp)); ++ if (fp == NULL) { ++ error = ENOMEM; ++ } else { ++ rp = fc_frame_payload_get(fp, sizeof(*rp)); ++ fc_fill_dns_hdr(lp, &rp->ct, FC_NS_GPN_FT, sizeof(rp->gid)); ++ rp->gid.fn_fc4_type = FC_TYPE_FCP; ++ ++ WARN_ON(!fc_lport_test_ready(lp)); ++ ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ sp = lp->tt.exch_seq_send(lp, fp, ++ fc_disc_gpn_ft_resp, NULL, ++ lp, lp->e_d_tov, ++ lp->fid, ++ FC_FID_DIR_SERV, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ } ++ if (error || sp == NULL) ++ fc_disc_retry(lp); ++} ++ ++/* ++ * Handle error on dNS request. ++ */ ++static void fc_disc_error(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ int err = PTR_ERR(fp); ++ ++ switch (err) { ++ case -FC_EX_TIMEOUT: ++ if (lp->disc_retry_count++ < FC_DISC_RETRY_LIMIT) { ++ fc_disc_gpn_ft_req(lp); ++ } else { ++ FC_DBG("err %d - ending\n", err); ++ fc_disc_done(lp); ++ } ++ break; ++ default: ++ FC_DBG("err %d - ending\n", err); ++ fc_disc_done(lp); ++ break; ++ } ++} ++ ++/** ++ * fc_disc_gpn_ft_parse - Parse the list of IDs and names resulting from a request ++ * @lp: Fibre Channel host port instance ++ * @buf: GPN_FT response buffer ++ * @len: size of response buffer ++ */ ++static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) ++{ ++ struct fc_gpn_ft_resp *np; ++ char *bp; ++ size_t plen; ++ size_t tlen; ++ int error = 0; ++ struct fc_disc_port dp; ++ struct fc_rport *rp; ++ struct fc_rport_libfc_priv *rpp; ++ ++ /* ++ * Handle partial name record left over from previous call. ++ */ ++ bp = buf; ++ plen = len; ++ np = (struct fc_gpn_ft_resp *)bp; ++ tlen = lp->disc_buf_len; ++ if (tlen) { ++ WARN_ON(tlen >= sizeof(*np)); ++ plen = sizeof(*np) - tlen; ++ WARN_ON(plen <= 0); ++ WARN_ON(plen >= sizeof(*np)); ++ if (plen > len) ++ plen = len; ++ np = &lp->disc_buf; ++ memcpy((char *)np + tlen, bp, plen); ++ ++ /* ++ * Set bp so that the loop below will advance it to the ++ * first valid full name element. ++ */ ++ bp -= tlen; ++ len += tlen; ++ plen += tlen; ++ lp->disc_buf_len = (unsigned char) plen; ++ if (plen == sizeof(*np)) ++ lp->disc_buf_len = 0; ++ } ++ ++ /* ++ * Handle full name records, including the one filled from above. ++ * Normally, np == bp and plen == len, but from the partial case above, ++ * bp, len describe the overall buffer, and np, plen describe the ++ * partial buffer, which if would usually be full now. ++ * After the first time through the loop, things return to "normal". ++ */ ++ while (plen >= sizeof(*np)) { ++ dp.lp = lp; ++ dp.ids.port_id = ntoh24(np->fp_fid); ++ dp.ids.port_name = ntohll(np->fp_wwpn); ++ dp.ids.node_name = -1; ++ dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ ++ if ((dp.ids.port_id != lp->fid) && ++ (dp.ids.port_name != lp->wwpn)) { ++ rp = fc_rport_dummy_create(&dp); ++ if (rp) { ++ rpp = rp->dd_data; ++ rpp->local_port = lp; ++ lp->tt.rport_login(rp); ++ } else ++ FC_DBG("Failed to allocate memory for " ++ "the newly discovered port (%6x)\n", ++ dp.ids.port_id); ++ } ++ ++ if (np->fp_flags & FC_NS_FID_LAST) { ++ fc_disc_done(lp); ++ len = 0; ++ break; ++ } ++ len -= sizeof(*np); ++ bp += sizeof(*np); ++ np = (struct fc_gpn_ft_resp *)bp; ++ plen = len; ++ } ++ ++ /* ++ * Save any partial record at the end of the buffer for next time. ++ */ ++ if (error == 0 && len > 0 && len < sizeof(*np)) { ++ if (np != &lp->disc_buf) ++ memcpy(&lp->disc_buf, np, len); ++ lp->disc_buf_len = (unsigned char) len; ++ } else { ++ lp->disc_buf_len = 0; ++ } ++ return error; ++} ++ ++/* ++ * Handle retry of memory allocation for remote ports. ++ */ ++static void fc_disc_timeout(struct work_struct *work) ++{ ++ struct fc_lport *lp; ++ ++ lp = container_of(work, struct fc_lport, disc_work.work); ++ ++ if (lp->disc_pending) ++ fc_disc_gpn_ft_req(lp); ++ else ++ lp->tt.disc_start(lp); ++} ++ ++/** ++ * fc_disc_gpn_ft_resp - Handle a response frame from Get Port Names (GPN_FT) ++ * @sp: Current sequence of GPN_FT exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel host port instance ++ * ++ * The response may be in multiple frames ++ */ ++static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) ++{ ++ struct fc_lport *lp = lp_arg; ++ struct fc_ct_hdr *cp; ++ struct fc_frame_header *fh; ++ unsigned int seq_cnt; ++ void *buf = NULL; ++ unsigned int len; ++ int error; ++ ++ if (IS_ERR(fp)) { ++ fc_disc_error(lp, fp); ++ return; ++ } ++ ++ WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ ++ fh = fc_frame_header_get(fp); ++ len = fr_len(fp) - sizeof(*fh); ++ seq_cnt = ntohs(fh->fh_seq_cnt); ++ if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && ++ lp->disc_seq_count == 0) { ++ cp = fc_frame_payload_get(fp, sizeof(*cp)); ++ if (cp == NULL) { ++ FC_DBG("GPN_FT response too short, len %d\n", ++ fr_len(fp)); ++ } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { ++ ++ /* ++ * Accepted. Parse response. ++ */ ++ buf = cp + 1; ++ len -= sizeof(*cp); ++ } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { ++ FC_DBG("GPN_FT rejected reason %x exp %x " ++ "(check zoning)\n", cp->ct_reason, ++ cp->ct_explan); ++ fc_disc_done(lp); ++ } else { ++ FC_DBG("GPN_FT unexpected response code %x\n", ++ ntohs(cp->ct_cmd)); ++ } ++ } else if (fr_sof(fp) == FC_SOF_N3 && ++ seq_cnt == lp->disc_seq_count) { ++ buf = fh + 1; ++ } else { ++ FC_DBG("GPN_FT unexpected frame - out of sequence? " ++ "seq_cnt %x expected %x sof %x eof %x\n", ++ seq_cnt, lp->disc_seq_count, fr_sof(fp), fr_eof(fp)); ++ } ++ if (buf) { ++ error = fc_disc_gpn_ft_parse(lp, buf, len); ++ if (error) ++ fc_disc_retry(lp); ++ else ++ lp->disc_seq_count++; ++ } ++ fc_frame_free(fp); ++} ++ ++/* ++ * Discover the directory information for a single target. ++ * This could be from an RSCN that reported a change for the target. ++ */ ++static void fc_disc_single(struct fc_lport *lp, struct fc_disc_port *dp) ++{ ++ struct fc_rport *rport; ++ struct fc_rport *rp; ++ struct fc_rport_libfc_priv *rpp; ++ ++ if (dp->ids.port_id == lp->fid) ++ goto out; ++ ++ rport = lp->tt.rport_lookup(lp, dp->ids.port_id); ++ if (rport) { ++ fc_disc_del_target(lp, rport); ++ put_device(&rport->dev); /* hold from lookup */ ++ } ++ ++ rp = fc_rport_dummy_create(dp); ++ if (rp) { ++ rpp = rp->dd_data; ++ kfree(dp); ++ lp->tt.rport_login(rp); ++ } ++ return; ++out: ++ kfree(dp); ++} ++ ++int fc_disc_init(struct fc_lport *lp) ++{ ++ INIT_DELAYED_WORK(&lp->disc_work, fc_disc_timeout); ++ ++ if (!lp->tt.disc_start) ++ lp->tt.disc_start = fc_disc_start; ++ ++ if (!lp->tt.disc_recv_req) ++ lp->tt.disc_recv_req = fc_disc_recv_req; ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_disc_init); +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +index 11a03bd..ed74d95 100644 +--- a/drivers/scsi/libfc/fc_exch.c ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -1,5 +1,7 @@ + /* + * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 Red Hat, Inc. All rights reserved. ++ * Copyright(c) 2008 Mike Christie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, +@@ -73,6 +75,9 @@ struct fc_exch; + * esb_stat, f_ctl, seq.ssb_stat, seq.f_ctl. + * seq_id + * sequence allocation ++ * ++ * If the em_lock and ex_lock must be taken at the same time, the ++ * em_lock must be taken before the ex_lock. + */ + struct fc_exch { + struct fc_exch_mgr *em; /* exchange manager */ +@@ -95,13 +100,16 @@ struct fc_exch { + u8 fh_type; /* frame type */ + enum fc_class class; /* class of service */ + struct fc_seq seq; /* single sequence */ +- struct fc_exch *aborted_ep; /* ref to ep rrq is cleaning up */ +- + /* + * Handler for responses to this current exchange. + */ + void (*resp)(struct fc_seq *, struct fc_frame *, void *); +- void *resp_arg; /* 3rd arg for exchange resp handler */ ++ void (*destructor)(struct fc_seq *, void *); ++ /* ++ * arg is passed as void pointer to exchange ++ * resp and destructor handlers ++ */ ++ void *arg; + }; + + /* +@@ -297,6 +305,8 @@ static void fc_exch_release(struct fc_exch *ep) + + if (atomic_dec_and_test(&ep->ex_refcnt)) { + mp = ep->em; ++ if (ep->destructor) ++ ep->destructor(&ep->seq, ep->arg); + if (ep->lp->tt.exch_put) + ep->lp->tt.exch_put(ep->lp, mp, ep->xid); + WARN_ON(!ep->esb_stat & ESB_ST_COMPLETE); +@@ -324,7 +334,6 @@ static int fc_exch_done_locked(struct fc_exch *ep) + ep->state |= FC_EX_DONE; + if (del_timer(&ep->ex_timer)) + atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ +- atomic_dec(&ep->ex_refcnt); /* drop hold from alloc */ + rc = 0; + } + return rc; +@@ -341,6 +350,7 @@ static void fc_exch_mgr_delete_ep(struct fc_exch *ep) + mp->exches[ep->xid - mp->min_xid] = NULL; + list_del(&ep->ex_list); + spin_unlock_bh(&mp->em_lock); ++ fc_exch_release(ep); /* drop hold for exch in mp */ + } + + /* +@@ -441,13 +451,13 @@ static void fc_exch_timeout(unsigned long ep_arg) + e_stat = ep->esb_stat; + if (e_stat & ESB_ST_COMPLETE) { + ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL; +- spin_unlock_bh(&ep->ex_lock); + if (e_stat & ESB_ST_REC_QUAL) + fc_exch_rrq(ep); ++ spin_unlock_bh(&ep->ex_lock); + goto done; + } else { + resp = ep->resp; +- arg = ep->resp_arg; ++ arg = ep->arg; + ep->resp = NULL; + if (e_stat & ESB_ST_ABNORMAL) + rc = fc_exch_done_locked(ep); +@@ -492,6 +502,7 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) + * + * if xid is supplied zero then assign next free exchange ID + * from exchange manager, otherwise use supplied xid. ++ * Returns with exch lock held. + */ + struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) + { +@@ -540,16 +551,24 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) + xid = fc_exch_next_xid(mp, xid); + } + +- if (likely(mp->exches[xid - min_xid] == NULL)) { +- mp->last_xid = xid; +- } else { +- spin_unlock_bh(&mp->em_lock); +- atomic_inc(&mp->stats.no_free_exch_xid); +- mempool_free(ep, mp->ep_pool); +- goto out; +- } ++ if (unlikely(mp->exches[xid - min_xid] != NULL)) ++ goto err; ++ mp->last_xid = xid; + } + ++ /* lport lock ? */ ++ if (mp->lp->state == LPORT_ST_RESET) ++ goto err; /* don't add new ep during local port reset */ ++ ++ fc_exch_hold(ep); /* hold for exch in mp */ ++ spin_lock_init(&ep->ex_lock); ++ /* ++ * Hold exch lock for caller to prevent fc_exch_reset() ++ * from releasing exch while fc_exch_alloc() caller is ++ * still working on exch. ++ */ ++ spin_lock_bh(&ep->ex_lock); ++ + mp->exches[xid - min_xid] = ep; + list_add_tail(&ep->ex_list, &mp->ex_list); + fc_seq_alloc(ep, ep->seq_id++); +@@ -565,13 +584,14 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) + ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ + ep->rxid = FC_XID_UNKNOWN; + ep->class = mp->class; +- +- spin_lock_init(&ep->ex_lock); + setup_timer(&ep->ex_timer, fc_exch_timeout, (unsigned long)ep); +- +- fc_exch_hold(ep); /* hold for caller */ + out: + return ep; ++err: ++ spin_unlock_bh(&mp->em_lock); ++ atomic_inc(&mp->stats.no_free_exch_xid); ++ mempool_free(ep, mp->ep_pool); ++ return NULL; + } + EXPORT_SYMBOL(fc_exch_alloc); + +@@ -654,6 +674,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) + WARN_ON(rxid != FC_XID_UNKNOWN); + fh->fh_rx_id = htons(ep->rxid); + } ++ fc_exch_hold(ep); /* hold for caller */ ++ spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */ + } + return ep; + } +@@ -667,7 +689,7 @@ static enum fc_pf_rjt_reason + fc_seq_lookup_recip(struct fc_exch_mgr *mp, struct fc_frame *fp) + { + struct fc_frame_header *fh = fc_frame_header_get(fp); +- struct fc_exch *ep = NULL, *new_ep = NULL; ++ struct fc_exch *ep = NULL; + struct fc_seq *sp = NULL; + enum fc_pf_rjt_reason reject = FC_RJT_NONE; + u32 f_ctl; +@@ -717,12 +739,11 @@ fc_seq_lookup_recip(struct fc_exch_mgr *mp, struct fc_frame *fp) + reject = FC_RJT_RX_ID; + goto rel; + } +- new_ep = ep = fc_exch_resp(mp, fp); ++ ep = fc_exch_resp(mp, fp); + if (!ep) { + reject = FC_RJT_EXCH_EST; /* XXX */ + goto out; + } +- fc_exch_hold(ep); /* Additional hold for caller */ + xid = ep->xid; /* get our XID */ + } else if (!ep) { + atomic_inc(&mp->stats.xid_not_found); +@@ -760,9 +781,8 @@ fc_seq_lookup_recip(struct fc_exch_mgr *mp, struct fc_frame *fp) + out: + return reject; + rel: +- fc_exch_release(ep); +- if (new_ep) +- fc_exch_release(new_ep); ++ fc_exch_done(&ep->seq); ++ fc_exch_release(ep); /* hold from fc_exch_find/fc_exch_resp */ + return reject; + } + +@@ -1160,7 +1180,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, + * first. + */ + if (ep->resp) +- ep->resp(sp, fp, ep->resp_arg); ++ ep->resp(sp, fp, ep->arg); + else + lp->tt.lport_recv(lp, sp, fp); + fc_exch_release(ep); /* release from lookup */ +@@ -1222,7 +1242,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) + if (fc_sof_needs_ack(sof)) + fc_seq_send_ack(sp, fp); + resp = ep->resp; +- ex_resp_arg = ep->resp_arg; ++ ex_resp_arg = ep->arg; + + if (fh->fh_type != FC_TYPE_FCP && fr_eof(fp) == FC_EOF_T && + (f_ctl & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == +@@ -1332,7 +1352,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) + } + + resp = ep->resp; +- ex_resp_arg = ep->resp_arg; ++ ex_resp_arg = ep->arg; + + /* do we need to do some other checks here. Can we reuse more of + * fc_exch_recv_seq_resp +@@ -1341,7 +1361,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) + /* + * do we want to check END_SEQ as well as LAST_SEQ here? + */ +- if (fh->fh_type != FC_TYPE_FCP && ++ if (ep->fh_type != FC_TYPE_FCP && + ntoh24(fh->fh_f_ctl) & FC_FC_LAST_SEQ) + rc = fc_exch_done_locked(ep); + spin_unlock_bh(&ep->ex_lock); +@@ -1485,11 +1505,9 @@ static void fc_exch_reset(struct fc_exch *ep) + if (ep->esb_stat & ESB_ST_REC_QUAL) + atomic_dec(&ep->ex_refcnt); /* drop hold for rec_qual */ + ep->esb_stat &= ~ESB_ST_REC_QUAL; +- arg = ep->resp_arg; ++ arg = ep->arg; + sp = &ep->seq; +- +- if (ep->fh_type != FC_TYPE_FCP) +- rc = fc_exch_done_locked(ep); ++ rc = fc_exch_done_locked(ep); + spin_unlock_bh(&ep->ex_lock); + if (!rc) + fc_exch_mgr_delete_ep(ep); +@@ -1640,9 +1658,7 @@ reject: + */ + static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) + { +- struct fc_exch *ep = fc_seq_exch(sp); +- struct fc_exch *aborted_ep; +- ++ struct fc_exch *aborted_ep = arg; + unsigned int op; + + if (IS_ERR(fp)) { +@@ -1669,16 +1685,9 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) + } + + cleanup: +- spin_lock_bh(&ep->ex_lock); +- aborted_ep = ep->aborted_ep; +- ep->aborted_ep = NULL; +- spin_unlock_bh(&ep->ex_lock); +- +- if (aborted_ep) { +- fc_exch_done(&aborted_ep->seq); +- /* drop hold for rec qual */ +- fc_exch_release(aborted_ep); +- } ++ fc_exch_done(&aborted_ep->seq); ++ /* drop hold for rec qual */ ++ fc_exch_release(aborted_ep); + } + + /* +@@ -1692,7 +1701,6 @@ static void fc_exch_rrq(struct fc_exch *ep) + struct fc_els_rrq *rrq; + struct fc_frame *fp; + struct fc_seq *rrq_sp; +- struct fc_exch *rrq_ep; + u32 did; + + lp = ep->lp; +@@ -1711,18 +1719,14 @@ static void fc_exch_rrq(struct fc_exch *ep) + did = ep->did; + if (ep->esb_stat & ESB_ST_RESP) + did = ep->sid; +- rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, ep, lp->e_d_tov, +- lp->fid, did, FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, ++ lp->e_d_tov, lp->fid, did, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); + if (!rrq_sp) { +- spin_lock_bh(&ep->ex_lock); + ep->esb_stat |= ESB_ST_REC_QUAL; + fc_exch_timer_set_locked(ep, ep->r_a_tov); +- spin_unlock_bh(&ep->ex_lock); + return; + } +- +- rrq_ep = fc_seq_exch(rrq_sp); +- rrq_ep->aborted_ep = ep; + } + + +@@ -1860,13 +1864,15 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + void (*resp)(struct fc_seq *, + struct fc_frame *fp, + void *arg), +- void *resp_arg, u32 timer_msec, ++ void (*destructor)(struct fc_seq *, void *), ++ void *arg, u32 timer_msec, + u32 sid, u32 did, u32 f_ctl) + { + struct fc_exch *ep; + struct fc_seq *sp = NULL; + struct fc_frame_header *fh; + u16 fill; ++ int rc = 1; + + ep = lp->tt.exch_get(lp, fp); + if (!ep) { +@@ -1876,7 +1882,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + ep->esb_stat |= ESB_ST_SEQ_INIT; + fc_exch_set_addr(ep, sid, did); + ep->resp = resp; +- ep->resp_arg = resp_arg; ++ ep->destructor = destructor; ++ ep->arg = arg; + ep->r_a_tov = FC_DEF_R_A_TOV; + ep->lp = lp; + sp = &ep->seq; +@@ -1912,7 +1919,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + if (unlikely(lp->tt.frame_send(lp, fp))) + goto err; + +- spin_lock_bh(&ep->ex_lock); + if (timer_msec) + fc_exch_timer_set_locked(ep, timer_msec); + sp->f_ctl = f_ctl; /* save for possible abort */ +@@ -1924,7 +1930,10 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + spin_unlock_bh(&ep->ex_lock); + return sp; + err: +- fc_exch_done(sp); ++ rc = fc_exch_done_locked(ep); ++ spin_unlock_bh(&ep->ex_lock); ++ if (!rc) ++ fc_exch_mgr_delete_ep(ep); + return NULL; + } + EXPORT_SYMBOL(fc_exch_seq_send); +@@ -1938,6 +1947,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, + struct fc_frame_header *fh = fc_frame_header_get(fp); + u32 f_ctl; + ++ /* lport lock ? */ + if (!lp || !mp || (lp->state == LPORT_ST_NONE)) { + FC_DBG("fc_lport or EM is not allocated and configured"); + fc_frame_free(fp); +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +index 97da731..2566eed 100644 +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -38,6 +38,10 @@ + + #include + ++MODULE_AUTHOR("Open-FCoE.org"); ++MODULE_DESCRIPTION("libfc"); ++MODULE_LICENSE("GPL"); ++ + int fc_fcp_debug; + static struct kmem_cache *scsi_pkt_cachep; + +@@ -206,6 +210,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lp, gfp_t gfp) + atomic_set(&sp->ref_cnt, 1); + init_timer(&sp->timer); + INIT_LIST_HEAD(&sp->list); ++ spin_lock_init(&sp->scsi_pkt_lock); + } + return sp; + } +@@ -233,6 +238,22 @@ static void fc_fcp_pkt_hold(struct fc_fcp_pkt *sp) + } + + /** ++ * fc_fcp_pkt_destory - release hold on scsi_pkt packet ++ * ++ * @sp: exchange sequence ++ * @fsp: fcp packet struct ++ * ++ * Release hold on scsi_pkt packet set to keep scsi_pkt ++ * till EM layer exch resource is not freed. ++ * Context : called from from EM layer. ++ * no locking required ++ */ ++static void fc_fcp_pkt_destroy(struct fc_seq *sp, void *arg) ++{ ++ fc_fcp_pkt_release(arg); ++} ++ ++/** + * fc_fcp_lock_pkt - lock a packet and get a ref to it. + * @fsp: fcp packet + * +@@ -604,13 +625,31 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, + return 0; + } + +-static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame_header *fh) ++static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + { +- /* +- * we will let the command timeout and scsi-ml escalate if +- * the abort was rejected +- */ +- if (fh->fh_r_ctl == FC_RCTL_BA_ACC) { ++ int ba_done = 1; ++ struct fc_ba_rjt *brp; ++ struct fc_frame_header *fh; ++ ++ fh = fc_frame_header_get(fp); ++ switch (fh->fh_r_ctl) { ++ case FC_RCTL_BA_ACC: ++ break; ++ case FC_RCTL_BA_RJT: ++ brp = fc_frame_payload_get(fp, sizeof(*brp)); ++ if (brp && brp->br_reason == FC_BA_RJT_LOG_ERR) ++ break; ++ /* fall thru */ ++ default: ++ /* ++ * we will let the command timeout ++ * and scsi-ml recover in this case, ++ * therefore cleared the ba_done flag. ++ */ ++ ba_done = 0; ++ } ++ ++ if (ba_done) { + fsp->state |= FC_SRB_ABORTED; + fsp->state &= ~FC_SRB_ABORT_PENDING; + +@@ -666,7 +705,7 @@ static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) + struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; + struct fc_lport *lp; + struct fc_frame_header *fh; +- struct fc_data_desc *dd; ++ struct fcp_txrdy *dd; + u8 r_ctl; + int rc = 0; + +@@ -684,7 +723,7 @@ static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) + fsp->last_pkt_time = jiffies; + + if (fh->fh_type == FC_TYPE_BLS) { +- fc_fcp_abts_resp(fsp, fh); ++ fc_fcp_abts_resp(fsp, fp); + goto unlock; + } + +@@ -701,8 +740,8 @@ static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) + WARN_ON(!dd); + + rc = fc_fcp_send_data(fsp, sp, +- (size_t) ntohl(dd->dd_offset), +- (size_t) ntohl(dd->dd_len), fp, ++ (size_t) ntohl(dd->ft_data_ro), ++ (size_t) ntohl(dd->ft_burst_len), fp, + lp->capabilities & TRANS_C_SG); + if (!rc) + lp->tt.seq_set_rec_data(sp, fsp->xfer_len); +@@ -1025,6 +1064,7 @@ static int fc_fcp_send_cmd(struct fc_fcp_pkt *fsp) + rp = rport->dd_data; + sp = lp->tt.exch_seq_send(lp, fp, + fc_fcp_recv, ++ fc_fcp_pkt_destroy, + fsp, 0, + rp->local_port->fid, + rport->port_id, +@@ -1034,7 +1074,9 @@ static int fc_fcp_send_cmd(struct fc_fcp_pkt *fsp) + rc = -1; + goto unlock; + } ++ fsp->last_pkt_time = jiffies; + fsp->seq_ptr = sp; ++ fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ + + setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); + fc_fcp_timer_set(fsp, +@@ -1131,6 +1173,7 @@ static void fc_lun_reset_send(unsigned long data) + rp = rport->dd_data; + sp = lp->tt.exch_seq_send(lp, fp, + fc_tm_done, ++ fc_fcp_pkt_destroy, + fsp, 0, + rp->local_port->fid, + rport->port_id, +@@ -1138,6 +1181,7 @@ static void fc_lun_reset_send(unsigned long data) + + if (sp) { + fsp->seq_ptr = sp; ++ fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ + goto unlock; + } + /* +@@ -1183,12 +1227,6 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp, + + spin_lock_bh(&fsp->scsi_pkt_lock); + if (fsp->seq_ptr) { +- /* TODO: +- * if the exch resp function is running and trying to grab +- * the scsi_pkt_lock, this could free the exch from under +- * it and it could allow the fsp to be freed from under +- * fc_tm_done. +- */ + lp->tt.exch_done(fsp->seq_ptr); + fsp->seq_ptr = NULL; + } +@@ -1231,9 +1269,6 @@ static void fc_tm_done(struct fc_seq *sp, struct fc_frame *fp, void *arg) + + /* + * raced with eh timeout handler. +- * +- * TODO: If this happens we could be freeing the fsp right now and +- * would oops. Next patches will fix this race. + */ + if ((fsp->state & FC_SRB_COMPL) || !fsp->seq_ptr || + !fsp->wait_for_comp) { +@@ -1288,14 +1323,13 @@ static void fc_fcp_timeout(unsigned long data) + + if (rp->flags & FC_RP_FLAGS_REC_SUPPORTED) + fc_fcp_rec(fsp); +- /* TODO: change this to time_before/after */ +- else if (jiffies - fsp->last_pkt_time < FC_SCSI_ER_TIMEOUT / 2) ++ else if (time_after_eq(fsp->last_pkt_time + (FC_SCSI_ER_TIMEOUT / 2), ++ jiffies)) + fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT); + else if (fsp->state & FC_SRB_RCV_STATUS) + fc_fcp_complete(fsp); + else + fc_timeout_error(fsp); +- + fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; + unlock: + fc_fcp_unlock_pkt(fsp); +@@ -1340,7 +1374,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + fc_frame_set_offset(fp, 0); + sp = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_rec_resp, ++ fc_fcp_rec_resp, NULL, + fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), + rp->local_port->fid, + rport->port_id, +@@ -1402,9 +1436,14 @@ static void fc_fcp_rec_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) + if (fc_fcp_debug) + FC_DBG("device does not support REC\n"); + rp = fsp->rport->dd_data; ++ /* ++ * if we do not spport RECs or got some bogus ++ * reason then resetup timer so we check for ++ * making progress. ++ */ + rp->flags &= ~FC_RP_FLAGS_REC_SUPPORTED; +- /* fall through */ +- ++ fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT); ++ break; + case ELS_RJT_LOGIC: + case ELS_RJT_UNAB: + /* +@@ -1595,7 +1634,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) + fc_frame_setup(fp, FC_RCTL_ELS4_REQ, FC_TYPE_FCP); + fc_frame_set_offset(fp, 0); + sp = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_srr_resp, ++ fc_fcp_srr_resp, NULL, + fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), + rp->local_port->fid, + rport->port_id, +@@ -2048,7 +2087,7 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) + shost_printk(KERN_INFO, shost, "Host reset succeeded.\n"); + return SUCCESS; + } else { +- shost_printk(KERN_INFO, shost, "Host reset succeeded failed." ++ shost_printk(KERN_INFO, shost, "Host reset failed. " + "lport not ready.\n"); + return FAILED; + } +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index b390a32..b1854b9 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -36,76 +36,130 @@ + + static int fc_lport_debug; + ++static void fc_lport_error(struct fc_lport *, struct fc_frame *); ++ ++static void fc_lport_enter_reset(struct fc_lport *); + static void fc_lport_enter_flogi(struct fc_lport *); ++static void fc_lport_enter_dns(struct fc_lport *); ++static void fc_lport_enter_rpn_id(struct fc_lport *); ++static void fc_lport_enter_rft_id(struct fc_lport *); ++static void fc_lport_enter_scr(struct fc_lport *); ++static void fc_lport_enter_ready(struct fc_lport *); + static void fc_lport_enter_logo(struct fc_lport *); + + static const char *fc_lport_state_names[] = { + [LPORT_ST_NONE] = "none", + [LPORT_ST_FLOGI] = "FLOGI", + [LPORT_ST_DNS] = "dNS", +- [LPORT_ST_REG_PN] = "REG_PN", +- [LPORT_ST_REG_FT] = "REG_FT", ++ [LPORT_ST_RPN_ID] = "RPN_ID", ++ [LPORT_ST_RFT_ID] = "RFT_ID", + [LPORT_ST_SCR] = "SCR", +- [LPORT_ST_READY] = "ready", +- [LPORT_ST_DNS_STOP] = "stop", ++ [LPORT_ST_READY] = "Ready", + [LPORT_ST_LOGO] = "LOGO", + [LPORT_ST_RESET] = "reset", + }; + +-static int fc_frame_drop(struct fc_lport *lp, struct fc_frame *fp) ++static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) + { + fc_frame_free(fp); + return 0; + } + +-static const char *fc_lport_state(struct fc_lport *lp) ++/** ++ * fc_lport_rport_event - Event handler for rport events ++ * @lport: The lport which is receiving the event ++ * @port_id: The FID of the rport which the event has occured on ++ * @event: The event that occured ++ * ++ * Locking Note: The rport lock should not be held when calling ++ * this function. ++ */ ++static void fc_lport_rport_event(struct fc_lport *lport, u32 port_id, ++ enum fc_lport_event event) ++{ ++ struct fc_rport *rport = lport->tt.rport_lookup(lport, port_id); ++ ++ if (fc_lport_debug) ++ FC_DBG("Received a %d event for port (%6x)\n", event, port_id); ++ ++ if (port_id == FC_FID_DIR_SERV) { ++ mutex_lock(&lport->lp_mutex); ++ switch (event) { ++ case LPORT_EV_RPORT_CREATED: ++ if (rport) { ++ lport->dns_rp = rport; ++ fc_lport_enter_rpn_id(lport); ++ } ++ break; ++ case LPORT_EV_RPORT_LOGO: ++ case LPORT_EV_RPORT_FAILED: ++ lport->dns_rp = NULL; ++ fc_lport_enter_dns(lport); ++ break; ++ case LPORT_EV_RPORT_NONE: ++ break; ++ } ++ mutex_unlock(&lport->lp_mutex); ++ } ++} ++ ++/** ++ * fc_lport_state - Return a string which represents the lport's state ++ * @lport: The lport whose state is to converted to a string ++ */ ++static const char *fc_lport_state(struct fc_lport *lport) + { + const char *cp; + +- cp = fc_lport_state_names[lp->state]; ++ cp = fc_lport_state_names[lport->state]; + if (!cp) + cp = "unknown"; + return cp; + } + +-static void fc_lport_ptp_setup(struct fc_lport *lp, +- u32 remote_fid, u64 remote_wwpn, +- u64 remote_wwnn) ++/** ++ * fc_lport_ptp_clear - Delete the ptp rport ++ * @lport: The lport whose ptp rport should be removed ++ */ ++static void fc_lport_ptp_clear(struct fc_lport *lport) + { +- struct fc_rport *rport; +- struct fc_rport_identifiers ids = { +- .port_id = remote_fid, +- .port_name = remote_wwpn, +- .node_name = remote_wwnn, +- }; +- +- /* +- * if we have to create a rport the fc class can sleep so we must +- * drop the lock here +- */ +- fc_lport_unlock(lp); +- rport = lp->tt.rport_lookup(lp, ids.port_id); /* lookup and hold */ +- if (rport == NULL) +- rport = lp->tt.rport_create(lp, &ids); /* create and hold */ +- fc_lport_lock(lp); +- if (rport) { +- if (lp->ptp_rp) +- fc_remote_port_delete(lp->ptp_rp); +- lp->ptp_rp = rport; +- fc_lport_state_enter(lp, LPORT_ST_READY); ++ if (lport->ptp_rp) { ++ fc_remote_port_delete(lport->ptp_rp); ++ lport->ptp_rp = NULL; + } + } + +-static void fc_lport_ptp_clear(struct fc_lport *lp) ++/** ++ * fc_lport_ptp_setup - Create an rport for point-to-point mode ++ * @lport: The lport to attach the ptp rport to ++ * @fid: The FID of the ptp rport ++ * @remote_wwpn: The WWPN of the ptp rport ++ * @remote_wwnn: The WWNN of the ptp rport ++ */ ++static void fc_lport_ptp_setup(struct fc_lport *lport, ++ u32 remote_fid, u64 remote_wwpn, ++ u64 remote_wwnn) + { +- if (lp->ptp_rp) { +- fc_remote_port_delete(lp->ptp_rp); +- lp->ptp_rp = NULL; +- } ++ struct fc_disc_port dp; ++ ++ dp.lp = lport; ++ dp.ids.port_id = remote_fid; ++ dp.ids.port_name = remote_wwpn; ++ dp.ids.node_name = remote_wwnn; ++ dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ ++ fc_lport_ptp_clear(lport); ++ ++ lport->ptp_rp = fc_rport_dummy_create(&dp); ++ ++ lport->tt.rport_login(lport->ptp_rp); ++ ++ fc_lport_enter_ready(lport); + } + +-/* +- * Routines to support struct fc_function_template ++/** ++ * fc_get_host_port_state - supports fc_function_template ++ * @shost: The host whose port state should be returned + */ + void fc_get_host_port_state(struct Scsi_Host *shost) + { +@@ -118,82 +172,130 @@ void fc_get_host_port_state(struct Scsi_Host *shost) + } + EXPORT_SYMBOL(fc_get_host_port_state); + ++void fc_get_host_speed(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lport = shost_priv(shost); ++ ++ fc_host_speed(shost) = lport->link_speed; ++} ++EXPORT_SYMBOL(fc_get_host_speed); ++ ++struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) ++{ ++ int i; ++ struct fc_host_statistics *fcoe_stats; ++ struct fc_lport *lp = shost_priv(shost); ++ struct timespec v0, v1; ++ ++ fcoe_stats = &lp->host_stats; ++ memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); ++ ++ jiffies_to_timespec(jiffies, &v0); ++ jiffies_to_timespec(lp->boot_time, &v1); ++ fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); ++ ++ for_each_online_cpu(i) { ++ struct fcoe_dev_stats *stats = lp->dev_stats[i]; ++ if (stats == NULL) ++ continue; ++ fcoe_stats->tx_frames += stats->TxFrames; ++ fcoe_stats->tx_words += stats->TxWords; ++ fcoe_stats->rx_frames += stats->RxFrames; ++ fcoe_stats->rx_words += stats->RxWords; ++ fcoe_stats->error_frames += stats->ErrorFrames; ++ fcoe_stats->invalid_crc_count += stats->InvalidCRCCount; ++ fcoe_stats->fcp_input_requests += stats->InputRequests; ++ fcoe_stats->fcp_output_requests += stats->OutputRequests; ++ fcoe_stats->fcp_control_requests += stats->ControlRequests; ++ fcoe_stats->fcp_input_megabytes += stats->InputMegabytes; ++ fcoe_stats->fcp_output_megabytes += stats->OutputMegabytes; ++ fcoe_stats->link_failure_count += stats->LinkFailureCount; ++ } ++ fcoe_stats->lip_count = -1; ++ fcoe_stats->nos_count = -1; ++ fcoe_stats->loss_of_sync_count = -1; ++ fcoe_stats->loss_of_signal_count = -1; ++ fcoe_stats->prim_seq_protocol_err_count = -1; ++ fcoe_stats->dumped_frames = -1; ++ return fcoe_stats; ++} ++EXPORT_SYMBOL(fc_get_host_stats); ++ + /* + * Fill in FLOGI command for request. + */ + static void +-fc_lport_flogi_fill(struct fc_lport *lp, +- struct fc_els_flogi *flogi, unsigned int op) ++fc_lport_flogi_fill(struct fc_lport *lport, struct fc_els_flogi *flogi, ++ unsigned int op) + { + struct fc_els_csp *sp; + struct fc_els_cssp *cp; + + memset(flogi, 0, sizeof(*flogi)); + flogi->fl_cmd = (u8) op; +- put_unaligned_be64(lp->wwpn, &flogi->fl_wwpn); +- put_unaligned_be64(lp->wwnn, &flogi->fl_wwnn); ++ put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn); ++ put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn); + sp = &flogi->fl_csp; + sp->sp_hi_ver = 0x20; + sp->sp_lo_ver = 0x20; + sp->sp_bb_cred = htons(10); /* this gets set by gateway */ +- sp->sp_bb_data = htons((u16) lp->mfs); ++ sp->sp_bb_data = htons((u16) lport->mfs); + cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ + cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); + if (op != ELS_FLOGI) { + sp->sp_features = htons(FC_SP_FT_CIRO); + sp->sp_tot_seq = htons(255); /* seq. we accept */ + sp->sp_rel_off = htons(0x1f); +- sp->sp_e_d_tov = htonl(lp->e_d_tov); ++ sp->sp_e_d_tov = htonl(lport->e_d_tov); + +- cp->cp_rdfs = htons((u16) lp->mfs); ++ cp->cp_rdfs = htons((u16) lport->mfs); + cp->cp_con_seq = htons(255); + cp->cp_open_seq = 1; + } + } + + /* +- * Set the fid. This indicates that we have a new connection to the +- * fabric so we should reset our list of fc_rports. Passing a fid of +- * 0 will also reset the rport list regardless of the previous fid. +- */ +-static void fc_lport_set_fid(struct fc_lport *lp, u32 fid) +-{ +- if (fid != 0 && lp->fid == fid) +- return; +- +- if (fc_lport_debug) +- FC_DBG("changing local port fid from %x to %x\n", +- lp->fid, fid); +- lp->fid = fid; +- lp->tt.rport_reset_list(lp); +-} +- +-/* + * Add a supported FC-4 type. + */ +-static void fc_lport_add_fc4_type(struct fc_lport *lp, enum fc_fh_type type) ++static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) + { + __be32 *mp; + +- mp = &lp->fcts.ff_type_map[type / FC_NS_BPW]; ++ mp = &lport->fcts.ff_type_map[type / FC_NS_BPW]; + *mp = htonl(ntohl(*mp) | 1UL << (type % FC_NS_BPW)); + } + +-/* +- * Handle received RLIR - registered link incident report. ++/** ++ * fc_lport_recv_rlir_req - Handle received Registered Link Incident Report. ++ * @lport: Fibre Channel local port recieving the RLIR ++ * @sp: current sequence in the RLIR exchange ++ * @fp: RLIR request frame ++ * ++ * Locking Note: The lport lock is exected to be held before calling ++ * this function. + */ +-static void fc_lport_rlir_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lp) ++static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lport) + { +- lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ if (fc_lport_debug) ++ FC_DBG("Received RLIR request while in state %s\n", ++ fc_lport_state(lport)); ++ ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + fc_frame_free(fp); + } + +-/* +- * Handle received ECHO. ++/** ++ * fc_lport_recv_echo_req - Handle received ECHO request ++ * @lport: Fibre Channel local port recieving the ECHO ++ * @sp: current sequence in the ECHO exchange ++ * @fp: ECHO request frame ++ * ++ * Locking Note: The lport lock is exected to be held before calling ++ * this function. + */ +-static void fc_lport_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, +- struct fc_lport *lp) ++static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, ++ struct fc_lport *lport) + { + struct fc_frame *fp; + unsigned int len; +@@ -201,29 +303,40 @@ static void fc_lport_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, + void *dp; + u32 f_ctl; + ++ if (fc_lport_debug) ++ FC_DBG("Received RLIR request while in state %s\n", ++ fc_lport_state(lport)); ++ + len = fr_len(in_fp) - sizeof(struct fc_frame_header); + pp = fc_frame_payload_get(in_fp, len); + + if (len < sizeof(__be32)) + len = sizeof(__be32); +- fp = fc_frame_alloc(lp, len); ++ ++ fp = fc_frame_alloc(lport, len); + if (fp) { + dp = fc_frame_payload_get(fp, len); + memcpy(dp, pp, len); + *((u32 *)dp) = htonl(ELS_LS_ACC << 24); +- sp = lp->tt.seq_start_next(sp); ++ sp = lport->tt.seq_start_next(sp); + f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ; + fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lp->tt.seq_send(lp, sp, fp, f_ctl); ++ lport->tt.seq_send(lport, sp, fp, f_ctl); + } + fc_frame_free(in_fp); + } + +-/* +- * Handle received RNID. ++/** ++ * fc_lport_recv_echo_req - Handle received Request Node ID data request ++ * @lport: Fibre Channel local port recieving the RNID ++ * @sp: current sequence in the RNID exchange ++ * @fp: RNID request frame ++ * ++ * Locking Note: The lport lock is exected to be held before calling ++ * this function. + */ +-static void fc_lport_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, +- struct fc_lport *lp) ++static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, ++ struct fc_lport *lport) + { + struct fc_frame *fp; + struct fc_els_rnid *req; +@@ -237,146 +350,165 @@ static void fc_lport_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, + size_t len; + u32 f_ctl; + ++ if (fc_lport_debug) ++ FC_DBG("Received RNID request while in state %s\n", ++ fc_lport_state(lport)); ++ + req = fc_frame_payload_get(in_fp, sizeof(*req)); + if (!req) { + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_LOGIC; + rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + } else { + fmt = req->rnid_fmt; + len = sizeof(*rp); + if (fmt != ELS_RNIDF_GEN || +- ntohl(lp->rnid_gen.rnid_atype) == 0) { ++ ntohl(lport->rnid_gen.rnid_atype) == 0) { + fmt = ELS_RNIDF_NONE; /* nothing to provide */ + len -= sizeof(rp->gen); + } +- fp = fc_frame_alloc(lp, len); ++ fp = fc_frame_alloc(lport, len); + if (fp) { + rp = fc_frame_payload_get(fp, len); + memset(rp, 0, len); + rp->rnid.rnid_cmd = ELS_LS_ACC; + rp->rnid.rnid_fmt = fmt; + rp->rnid.rnid_cid_len = sizeof(rp->cid); +- rp->cid.rnid_wwpn = htonll(lp->wwpn); +- rp->cid.rnid_wwnn = htonll(lp->wwnn); ++ rp->cid.rnid_wwpn = htonll(lport->wwpn); ++ rp->cid.rnid_wwnn = htonll(lport->wwnn); + if (fmt == ELS_RNIDF_GEN) { + rp->rnid.rnid_sid_len = sizeof(rp->gen); +- memcpy(&rp->gen, &lp->rnid_gen, ++ memcpy(&rp->gen, &lport->rnid_gen, + sizeof(rp->gen)); + } +- sp = lp->tt.seq_start_next(sp); ++ sp = lport->tt.seq_start_next(sp); + f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; + fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lp->tt.seq_send(lp, sp, fp, f_ctl); ++ lport->tt.seq_send(lport, sp, fp, f_ctl); + } + } + fc_frame_free(in_fp); + } + +-/* +- * Handle received fabric logout request. ++/** ++ * fc_lport_recv_logo_req - Handle received fabric LOGO request ++ * @lport: Fibre Channel local port recieving the LOGO ++ * @sp: current sequence in the LOGO exchange ++ * @fp: LOGO request frame ++ * ++ * Locking Note: The lport lock is exected to be held before calling ++ * this function. + */ + static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lp) ++ struct fc_lport *lport) + { +- lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); +- fc_lport_enter_reset(lp); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ fc_lport_enter_reset(lport); + fc_frame_free(fp); + } + +-/* +- * Receive request frame ++/** ++ * fc_fabric_login - Start the lport state machine ++ * @lport: The lport that should log into the fabric ++ * ++ * Locking Note: This function should not be called ++ * with the lport lock held. + */ +- +-int fc_fabric_login(struct fc_lport *lp) ++int fc_fabric_login(struct fc_lport *lport) + { + int rc = -1; + +- if (lp->state == LPORT_ST_NONE) { +- fc_lport_lock(lp); +- fc_lport_enter_reset(lp); +- fc_lport_unlock(lp); ++ mutex_lock(&lport->lp_mutex); ++ if (lport->state == LPORT_ST_NONE) { ++ fc_lport_enter_reset(lport); + rc = 0; + } ++ mutex_unlock(&lport->lp_mutex); ++ + return rc; + } + EXPORT_SYMBOL(fc_fabric_login); + + /** +- * fc_linkup - link up notification +- * @dev: Pointer to fc_lport . +- **/ +-void fc_linkup(struct fc_lport *lp) ++ * fc_linkup - Handler for transport linkup events ++ * @lport: The lport whose link is up ++ */ ++void fc_linkup(struct fc_lport *lport) + { +- if ((lp->link_status & FC_LINK_UP) != FC_LINK_UP) { +- lp->link_status |= FC_LINK_UP; +- fc_lport_lock(lp); +- if (lp->state == LPORT_ST_RESET) +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); ++ mutex_lock(&lport->lp_mutex); ++ if ((lport->link_status & FC_LINK_UP) != FC_LINK_UP) { ++ lport->link_status |= FC_LINK_UP; ++ ++ if (lport->state == LPORT_ST_RESET) ++ fc_lport_enter_flogi(lport); + } ++ mutex_unlock(&lport->lp_mutex); + } + EXPORT_SYMBOL(fc_linkup); + + /** +- * fc_linkdown - link down notification +- * @dev: Pointer to fc_lport . +- **/ +-void fc_linkdown(struct fc_lport *lp) ++ * fc_linkdown - Handler for transport linkdown events ++ * @lport: The lport whose link is down ++ */ ++void fc_linkdown(struct fc_lport *lport) + { +- if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP) { +- lp->link_status &= ~(FC_LINK_UP); +- fc_lport_enter_reset(lp); +- lp->tt.scsi_cleanup(lp); ++ mutex_lock(&lport->lp_mutex); ++ ++ if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) { ++ lport->link_status &= ~(FC_LINK_UP); ++ fc_lport_enter_reset(lport); ++ lport->tt.scsi_cleanup(lport); + } ++ ++ mutex_unlock(&lport->lp_mutex); + } + EXPORT_SYMBOL(fc_linkdown); + +-void fc_pause(struct fc_lport *lp) ++/** ++ * fc_pause - Pause the flow of frames ++ * @lport: The lport to be paused ++ */ ++void fc_pause(struct fc_lport *lport) + { +- lp->link_status |= FC_PAUSE; ++ mutex_lock(&lport->lp_mutex); ++ lport->link_status |= FC_PAUSE; ++ mutex_unlock(&lport->lp_mutex); + } + EXPORT_SYMBOL(fc_pause); + +-void fc_unpause(struct fc_lport *lp) ++/** ++ * fc_unpause - Unpause the flow of frames ++ * @lport: The lport to be unpaused ++ */ ++void fc_unpause(struct fc_lport *lport) + { +- lp->link_status &= ~(FC_PAUSE); ++ mutex_lock(&lport->lp_mutex); ++ lport->link_status &= ~(FC_PAUSE); ++ mutex_unlock(&lport->lp_mutex); + } + EXPORT_SYMBOL(fc_unpause); + +-int fc_fabric_logoff(struct fc_lport *lp) ++/** ++ * fc_fabric_logoff - Logout of the fabric ++ * @lport: fc_lport pointer to logoff the fabric ++ * ++ * Return value: ++ * 0 for success, -1 for failure ++ **/ ++int fc_fabric_logoff(struct fc_lport *lport) + { +- fc_lport_lock(lp); +- switch (lp->state) { +- case LPORT_ST_NONE: +- break; +- case LPORT_ST_FLOGI: +- case LPORT_ST_LOGO: +- case LPORT_ST_RESET: +- fc_lport_enter_reset(lp); +- break; +- case LPORT_ST_DNS: +- case LPORT_ST_DNS_STOP: +- fc_lport_enter_logo(lp); +- break; +- case LPORT_ST_REG_PN: +- case LPORT_ST_REG_FT: +- case LPORT_ST_SCR: +- case LPORT_ST_READY: +- lp->tt.disc_stop(lp); +- break; +- } +- fc_lport_unlock(lp); +- lp->tt.scsi_cleanup(lp); +- ++ mutex_lock(&lport->lp_mutex); ++ fc_lport_enter_logo(lport); ++ lport->tt.scsi_cleanup(lport); ++ mutex_unlock(&lport->lp_mutex); + return 0; + } + EXPORT_SYMBOL(fc_fabric_logoff); + + /** + * fc_lport_destroy - unregister a fc_lport +- * @lp: fc_lport pointer to unregister ++ * @lport: fc_lport pointer to unregister + * + * Return value: + * None +@@ -386,30 +518,26 @@ EXPORT_SYMBOL(fc_fabric_logoff); + * and free up other system resources. + * + **/ +-int fc_lport_destroy(struct fc_lport *lp) ++int fc_lport_destroy(struct fc_lport *lport) + { +- fc_lport_lock(lp); +- fc_lport_state_enter(lp, LPORT_ST_LOGO); +- fc_lport_unlock(lp); +- +- cancel_delayed_work_sync(&lp->ns_disc_work); +- +- lp->tt.scsi_abort_io(lp); +- +- lp->tt.frame_send = fc_frame_drop; +- +- lp->tt.exch_mgr_reset(lp->emp, 0, 0); +- ++ mutex_lock(&lport->lp_mutex); ++ cancel_delayed_work_sync(&lport->disc_work); ++ lport->tt.scsi_abort_io(lport); ++ lport->tt.frame_send = fc_frame_drop; ++ lport->tt.exch_mgr_reset(lport->emp, 0, 0); ++ mutex_unlock(&lport->lp_mutex); + return 0; + } + EXPORT_SYMBOL(fc_lport_destroy); + +-int fc_set_mfs(struct fc_lport *lp, u32 mfs) ++int fc_set_mfs(struct fc_lport *lport, u32 mfs) + { + unsigned int old_mfs; + int rc = -1; + +- old_mfs = lp->mfs; ++ mutex_lock(&lport->lp_mutex); ++ ++ old_mfs = lport->mfs; + + if (mfs >= FC_MIN_MAX_FRAME) { + mfs &= ~3; +@@ -417,97 +545,55 @@ int fc_set_mfs(struct fc_lport *lp, u32 mfs) + if (mfs > FC_MAX_FRAME) + mfs = FC_MAX_FRAME; + mfs -= sizeof(struct fc_frame_header); +- lp->mfs = mfs; ++ lport->mfs = mfs; + rc = 0; + } + + if (!rc && mfs < old_mfs) { +- lp->ns_disc_done = 0; +- fc_lport_enter_reset(lp); ++ lport->disc_done = 0; ++ fc_lport_enter_reset(lport); + } ++ ++ mutex_unlock(&lport->lp_mutex); ++ + return rc; + } + EXPORT_SYMBOL(fc_set_mfs); + +-/* +- * re-enter state for retrying a request after a timeout or alloc failure. ++/** ++ * fc_rport_enter_ready - Enter the ready state and start discovery ++ * @lport: Fibre Channel local port that is ready ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. + */ +-static void fc_lport_enter_retry(struct fc_lport *lp) ++static void fc_lport_enter_ready(struct fc_lport *lport) + { +- switch (lp->state) { +- case LPORT_ST_NONE: +- case LPORT_ST_READY: +- case LPORT_ST_RESET: +- case LPORT_ST_DNS: +- case LPORT_ST_DNS_STOP: +- case LPORT_ST_REG_PN: +- case LPORT_ST_REG_FT: +- case LPORT_ST_SCR: +- WARN_ON(1); +- break; +- case LPORT_ST_FLOGI: +- fc_lport_enter_flogi(lp); +- break; +- case LPORT_ST_LOGO: +- fc_lport_enter_logo(lp); +- break; +- } +-} ++ if (fc_lport_debug) ++ FC_DBG("Port (%6x) entered Ready from state %s\n", ++ lport->fid, fc_lport_state(lport)); + +-/* +- * enter next state for handling an exchange reject or retry exhaustion +- * in the current state. +- */ +-static void fc_lport_enter_reject(struct fc_lport *lp) +-{ +- switch (lp->state) { +- case LPORT_ST_NONE: +- case LPORT_ST_READY: +- case LPORT_ST_RESET: +- case LPORT_ST_REG_PN: +- case LPORT_ST_REG_FT: +- case LPORT_ST_SCR: +- case LPORT_ST_DNS_STOP: +- case LPORT_ST_DNS: +- WARN_ON(1); +- break; +- case LPORT_ST_FLOGI: +- fc_lport_enter_flogi(lp); +- break; +- case LPORT_ST_LOGO: +- fc_lport_enter_reset(lp); +- break; +- } +-} ++ fc_lport_state_enter(lport, LPORT_ST_READY); + +-/* +- * Handle resource allocation problem by retrying in a bit. +- */ +-static void fc_lport_retry(struct fc_lport *lp) +-{ +- if (lp->retry_count == 0) +- FC_DBG("local port %6x alloc failure in state %s " +- "- will retry\n", lp->fid, fc_lport_state(lp)); +- if (lp->retry_count < lp->max_retry_count) { +- lp->retry_count++; +- mod_timer(&lp->state_timer, +- jiffies + msecs_to_jiffies(lp->e_d_tov)); +- } else { +- FC_DBG("local port %6x alloc failure in state %s " +- "- retries exhausted\n", lp->fid, +- fc_lport_state(lp)); +- fc_lport_enter_reject(lp); +- } ++ lport->tt.disc_start(lport); + } + +-/* ++/** ++ * fc_lport_recv_flogi_req - Receive a FLOGI request ++ * @sp_in: The sequence the FLOGI is on ++ * @rx_fp: The frame the FLOGI is in ++ * @lport: The lport that recieved the request ++ * + * A received FLOGI request indicates a point-to-point connection. + * Accept it with the common service parameters indicating our N port. + * Set up to do a PLOGI if we have the higher-number WWPN. ++ * ++ * Locking Note: The lport lock is exected to be held before calling ++ * this function. + */ + static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + struct fc_frame *rx_fp, +- struct fc_lport *lp) ++ struct fc_lport *lport) + { + struct fc_frame *fp; + struct fc_frame_header *fh; +@@ -519,19 +605,22 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + u32 local_fid; + u32 f_ctl; + ++ if (fc_lport_debug) ++ FC_DBG("Received FLOGI request while in state %s\n", ++ fc_lport_state(lport)); ++ + fh = fc_frame_header_get(rx_fp); + remote_fid = ntoh24(fh->fh_s_id); + flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); + if (!flp) + goto out; + remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); +- if (remote_wwpn == lp->wwpn) { ++ if (remote_wwpn == lport->wwpn) { + FC_DBG("FLOGI from port with same WWPN %llx " + "possible configuration error\n", remote_wwpn); + goto out; + } + FC_DBG("FLOGI from port WWPN %llx\n", remote_wwpn); +- fc_lport_lock(lp); + + /* + * XXX what is the right thing to do for FIDs? +@@ -539,20 +628,21 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + * But if so, both of us could end up with the same FID. + */ + local_fid = FC_LOCAL_PTP_FID_LO; +- if (remote_wwpn < lp->wwpn) { ++ if (remote_wwpn < lport->wwpn) { + local_fid = FC_LOCAL_PTP_FID_HI; + if (!remote_fid || remote_fid == local_fid) + remote_fid = FC_LOCAL_PTP_FID_LO; + } else if (!remote_fid) { + remote_fid = FC_LOCAL_PTP_FID_HI; + } +- fc_lport_set_fid(lp, local_fid); + +- fp = fc_frame_alloc(lp, sizeof(*flp)); ++ lport->fid = local_fid; ++ ++ fp = fc_frame_alloc(lport, sizeof(*flp)); + if (fp) { +- sp = lp->tt.seq_start_next(fr_seq(rx_fp)); ++ sp = lport->tt.seq_start_next(fr_seq(rx_fp)); + new_flp = fc_frame_payload_get(fp, sizeof(*flp)); +- fc_lport_flogi_fill(lp, new_flp, ELS_FLOGI); ++ fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); + new_flp->fl_cmd = (u8) ELS_LS_ACC; + + /* +@@ -561,23 +651,35 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + */ + f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ; + fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lp->tt.seq_send(lp, sp, fp, f_ctl); ++ lport->tt.seq_send(lport, sp, fp, f_ctl); + + } else { +- fc_lport_retry(lp); ++ fc_lport_error(lport, fp); + } +- fc_lport_ptp_setup(lp, remote_fid, remote_wwpn, ++ fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, + get_unaligned_be64(&flp->fl_wwnn)); +- fc_lport_unlock(lp); +- if (lp->tt.disc_start(lp)) ++ ++ if (lport->tt.disc_start(lport)) + FC_DBG("target discovery start error\n"); + out: + sp = fr_seq(rx_fp); + fc_frame_free(rx_fp); + } + +-static void fc_lport_recv(struct fc_lport *lp, struct fc_seq *sp, +- struct fc_frame *fp) ++/** ++ * fc_lport_recv_req - The generic lport request handler ++ * @lport: The lport that received the request ++ * @sp: The sequence the request is on ++ * @fp: The frame the request is in ++ * ++ * This function will see if the lport handles the request or ++ * if an rport should handle the request. ++ * ++ * Locking Note: This function should not be called with the lport ++ * lock held becuase it will grab the lock. ++ */ ++static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, ++ struct fc_frame *fp) + { + struct fc_frame_header *fh = fc_frame_header_get(fp); + void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); +@@ -586,6 +688,8 @@ static void fc_lport_recv(struct fc_lport *lp, struct fc_seq *sp, + u32 d_id; + struct fc_seq_els_data rjt_data; + ++ mutex_lock(&lport->lp_mutex); ++ + /* + * Handle special ELS cases like FLOGI, LOGO, and + * RSCN here. These don't require a session. +@@ -606,21 +710,21 @@ static void fc_lport_recv(struct fc_lport *lp, struct fc_seq *sp, + recv = fc_lport_recv_logo_req; + break; + case ELS_RSCN: +- recv = lp->tt.disc_recv_req; ++ recv = lport->tt.disc_recv_req; + break; + case ELS_ECHO: +- recv = fc_lport_echo_req; ++ recv = fc_lport_recv_echo_req; + break; + case ELS_RLIR: +- recv = fc_lport_rlir_req; ++ recv = fc_lport_recv_rlir_req; + break; + case ELS_RNID: +- recv = fc_lport_rnid_req; ++ recv = fc_lport_recv_rnid_req; + break; + } + + if (recv) +- recv(sp, fp, lp); ++ recv(sp, fp, lport); + else { + /* + * Find session. +@@ -629,16 +733,17 @@ static void fc_lport_recv(struct fc_lport *lp, struct fc_seq *sp, + s_id = ntoh24(fh->fh_s_id); + d_id = ntoh24(fh->fh_d_id); + +- rport = lp->tt.rport_lookup(lp, s_id); ++ rport = lport->tt.rport_lookup(lport, s_id); + if (rport) { +- lp->tt.rport_recv_req(sp, fp, rport); ++ lport->tt.rport_recv_req(sp, fp, rport); + put_device(&rport->dev); /* hold from lookup */ + } else { + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_UNAB; + rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, +- ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ++ ELS_LS_RJT, ++ &rjt_data); + fc_frame_free(fp); + } + } +@@ -646,151 +751,572 @@ static void fc_lport_recv(struct fc_lport *lp, struct fc_seq *sp, + FC_DBG("dropping invalid frame (eof %x)\n", fr_eof(fp)); + fc_frame_free(fp); + } ++ mutex_unlock(&lport->lp_mutex); ++} + +- /* +- * The common exch_done for all request may not be good +- * if any request requires longer hold on exhange. XXX +- */ +- lp->tt.exch_done(sp); ++/** ++ * fc_lport_reset - Reset an lport ++ * @lport: The lport which should be reset ++ * ++ * Locking Note: This functions should not be called with the ++ * lport lock held. ++ */ ++int fc_lport_reset(struct fc_lport *lport) ++{ ++ mutex_lock(&lport->lp_mutex); ++ fc_lport_enter_reset(lport); ++ mutex_unlock(&lport->lp_mutex); ++ return 0; + } ++EXPORT_SYMBOL(fc_lport_reset); + +-/* +- * Put the local port back into the initial state. Reset all sessions. +- * This is called after a SCSI reset or the driver is unloading +- * or the program is exiting. ++/** ++ * fc_rport_enter_reset - Reset the local port ++ * @lport: Fibre Channel local port to be reset ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. + */ +-int fc_lport_enter_reset(struct fc_lport *lp) ++static void fc_lport_enter_reset(struct fc_lport *lport) + { + if (fc_lport_debug) +- FC_DBG("Processing RESET state\n"); ++ FC_DBG("Port (%6x) entered RESET state from %s state\n", ++ lport->fid, fc_lport_state(lport)); ++ ++ fc_lport_state_enter(lport, LPORT_ST_RESET); + +- if (lp->dns_rp) { +- fc_remote_port_delete(lp->dns_rp); +- lp->dns_rp = NULL; ++ if (lport->dns_rp) { ++ fc_remote_port_delete(lport->dns_rp); ++ lport->dns_rp = NULL; + } +- fc_lport_ptp_clear(lp); ++ fc_lport_ptp_clear(lport); + +- /* +- * Setting state RESET keeps fc_lport_error() callbacks +- * by exch_mgr_reset() from recursing on the lock. +- * It also causes fc_lport_sess_event() to ignore events. +- * The lock is held for the duration of the time in RESET state. +- */ +- fc_lport_state_enter(lp, LPORT_ST_RESET); +- lp->tt.exch_mgr_reset(lp->emp, 0, 0); +- fc_lport_set_fid(lp, 0); +- if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP) +- fc_lport_enter_flogi(lp); +- return 0; ++ fc_block_rports(lport); ++ ++ lport->tt.rport_reset_list(lport); ++ lport->tt.exch_mgr_reset(lport->emp, 0, 0); ++ fc_host_fabric_name(lport->host) = 0; ++ lport->fid = 0; ++ ++ if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) ++ fc_lport_enter_flogi(lport); + } +-EXPORT_SYMBOL(fc_lport_enter_reset); + +-/* +- * Handle errors on local port requests. +- * Don't get locks if in RESET state. +- * The only possible errors so far are exchange TIMEOUT and CLOSED (reset). ++/** ++ * fc_lport_error - Handler for any errors ++ * @lport: The fc_lport object ++ * @fp: The frame pointer ++ * ++ * If the error was caused by a resource allocation failure ++ * then wait for half a second and retry, otherwise retry ++ * after the e_d_tov time. ++ */ ++static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ unsigned long delay = 0; ++ if (fc_lport_debug) ++ FC_DBG("Error %ld in state %s, retries %d\n", ++ PTR_ERR(fp), fc_lport_state(lport), ++ lport->retry_count); ++ ++ if (lport->retry_count < lport->max_retry_count) { ++ lport->retry_count++; ++ if (!fp) ++ delay = msecs_to_jiffies(500); ++ else ++ delay = jiffies + ++ msecs_to_jiffies(lport->e_d_tov); ++ ++ schedule_delayed_work(&lport->retry_work, delay); ++ } else { ++ switch (lport->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_READY: ++ case LPORT_ST_RESET: ++ case LPORT_ST_RPN_ID: ++ case LPORT_ST_RFT_ID: ++ case LPORT_ST_SCR: ++ case LPORT_ST_DNS: ++ case LPORT_ST_FLOGI: ++ case LPORT_ST_LOGO: ++ fc_lport_enter_reset(lport); ++ break; ++ } ++ } ++} ++ ++/** ++ * fc_lport_rft_id_resp - Handle response to Register Fibre ++ * Channel Types by ID (RPN_ID) request ++ * @sp: current sequence in RPN_ID exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel host port instance ++ * ++ * Locking Note: This function will be called without the lport lock ++ * held, but it will lock, call an _enter_* function or fc_lport_error ++ * and then unlock the lport. ++ */ ++static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) ++{ ++ struct fc_lport *lport = lp_arg; ++ struct fc_frame_header *fh; ++ struct fc_ct_hdr *ct; ++ ++ mutex_lock(&lport->lp_mutex); ++ ++ if (fc_lport_debug) ++ FC_DBG("Received a RFT_ID response\n"); ++ ++ if (lport->state != LPORT_ST_RFT_ID) { ++ FC_DBG("Received a RFT_ID response, but in state %s\n", ++ fc_lport_state(lport)); ++ goto out; ++ } ++ ++ if (IS_ERR(fp)) { ++ fc_lport_error(lport, fp); ++ goto out; ++ } ++ ++ fh = fc_frame_header_get(fp); ++ ct = fc_frame_payload_get(fp, sizeof(*ct)); ++ ++ if (fh && ct && fh->fh_type == FC_TYPE_CT && ++ ct->ct_fs_type == FC_FST_DIR && ++ ct->ct_fs_subtype == FC_NS_SUBTYPE && ++ ntohs(ct->ct_cmd) == FC_FS_ACC) ++ fc_lport_enter_scr(lport); ++ else ++ fc_lport_error(lport, fp); ++out: ++ mutex_unlock(&lport->lp_mutex); ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_lport_rpn_id_resp - Handle response to Register Port ++ * Name by ID (RPN_ID) request ++ * @sp: current sequence in RPN_ID exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel host port instance ++ * ++ * Locking Note: This function will be called without the lport lock ++ * held, but it will lock, call an _enter_* function or fc_lport_error ++ * and then unlock the lport. ++ */ ++static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) ++{ ++ struct fc_lport *lport = lp_arg; ++ struct fc_frame_header *fh; ++ struct fc_ct_hdr *ct; ++ ++ mutex_lock(&lport->lp_mutex); ++ ++ if (fc_lport_debug) ++ FC_DBG("Received a RPN_ID response\n"); ++ ++ if (lport->state != LPORT_ST_RPN_ID) { ++ FC_DBG("Received a RPN_ID response, but in state %s\n", ++ fc_lport_state(lport)); ++ goto out; ++ } ++ ++ if (IS_ERR(fp)) { ++ fc_lport_error(lport, fp); ++ goto out; ++ } ++ ++ fh = fc_frame_header_get(fp); ++ ct = fc_frame_payload_get(fp, sizeof(*ct)); ++ if (fh && ct && fh->fh_type == FC_TYPE_CT && ++ ct->ct_fs_type == FC_FST_DIR && ++ ct->ct_fs_subtype == FC_NS_SUBTYPE && ++ ntohs(ct->ct_cmd) == FC_FS_ACC) ++ fc_lport_enter_rft_id(lport); ++ else ++ fc_lport_error(lport, fp); ++ ++out: ++ mutex_unlock(&lport->lp_mutex); ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_lport_scr_resp - Handle response to State Change Register (SCR) request ++ * @sp: current sequence in SCR exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel lport port instance that sent the registration request ++ * ++ * Locking Note: This function will be called without the lport lock ++ * held, but it will lock, call an _enter_* function or fc_lport_error ++ * and then unlock the lport. + */ +-static void fc_lport_error(struct fc_lport *lp, struct fc_frame *fp) ++static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) + { +- if (lp->state == LPORT_ST_RESET) ++ struct fc_lport *lport = lp_arg; ++ u8 op; ++ ++ mutex_lock(&lport->lp_mutex); ++ ++ if (fc_lport_debug) ++ FC_DBG("Received a SCR response\n"); ++ ++ if (lport->state != LPORT_ST_SCR) { ++ FC_DBG("Received a SCR response, but in state %s\n", ++ fc_lport_state(lport)); ++ goto out; ++ } ++ ++ if (IS_ERR(fp)) { ++ fc_lport_error(lport, fp); ++ goto out; ++ } ++ ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC) ++ fc_lport_enter_ready(lport); ++ else ++ fc_lport_error(lport, fp); ++ ++out: ++ mutex_unlock(&lport->lp_mutex); ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_lport_enter_scr - Send a State Change Register (SCR) request ++ * @lport: Fibre Channel local port to register for state changes ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. ++ */ ++static void fc_lport_enter_scr(struct fc_lport *lport) ++{ ++ struct fc_frame *fp; ++ struct fc_els_scr *scr; ++ ++ if (fc_lport_debug) ++ FC_DBG("Port (%6x) entered SCR state from %s state\n", ++ lport->fid, fc_lport_state(lport)); ++ ++ fc_lport_state_enter(lport, LPORT_ST_SCR); ++ ++ fp = fc_frame_alloc(lport, sizeof(*scr)); ++ if (!fp) { ++ fc_lport_error(lport, fp); + return; ++ } + +- fc_lport_lock(lp); +- if (PTR_ERR(fp) == -FC_EX_TIMEOUT) { +- if (lp->retry_count < lp->max_retry_count) { +- lp->retry_count++; +- fc_lport_enter_retry(lp); +- } else { +- fc_lport_enter_reject(lp); ++ scr = fc_frame_payload_get(fp, sizeof(*scr)); ++ memset(scr, 0, sizeof(*scr)); ++ scr->scr_cmd = ELS_SCR; ++ scr->scr_reg_func = ELS_SCRF_FULL; ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ fc_frame_set_offset(fp, 0); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_lport_scr_resp, NULL, ++ lport, lport->e_d_tov, ++ lport->fid, FC_FID_FCTRL, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_lport_error(lport, fp); ++} ++ ++/** ++ * fc_lport_enter_rft_id - Register FC4-types with the name server ++ * @lport: Fibre Channel local port to register ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. ++ */ ++static void fc_lport_enter_rft_id(struct fc_lport *lport) ++{ ++ struct fc_frame *fp; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_fid fid; /* port ID object */ ++ struct fc_ns_fts fts; /* FC4-types object */ ++ } *req; ++ struct fc_ns_fts *lps; ++ int i; ++ ++ if (fc_lport_debug) ++ FC_DBG("Port (%6x) entered RFT_ID state from %s state\n", ++ lport->fid, fc_lport_state(lport)); + ++ fc_lport_state_enter(lport, LPORT_ST_RFT_ID); ++ ++ lps = &lport->fcts; ++ i = sizeof(lps->ff_type_map) / sizeof(lps->ff_type_map[0]); ++ while (--i >= 0) ++ if (ntohl(lps->ff_type_map[i]) != 0) ++ break; ++ if (i < 0) { ++ /* nothing to register, move on to SCR */ ++ fc_lport_enter_scr(lport); ++ } else { ++ fp = fc_frame_alloc(lport, sizeof(*req)); ++ if (!fp) { ++ fc_lport_error(lport, fp); ++ return; + } ++ ++ req = fc_frame_payload_get(fp, sizeof(*req)); ++ fc_fill_dns_hdr(lport, &req->ct, ++ FC_NS_RFT_ID, ++ sizeof(*req) - ++ sizeof(struct fc_ct_hdr)); ++ hton24(req->fid.fp_fid, lport->fid); ++ req->fts = *lps; ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_lport_rft_id_resp, NULL, ++ lport, lport->e_d_tov, ++ lport->fid, ++ FC_FID_DIR_SERV, ++ FC_FC_SEQ_INIT | ++ FC_FC_END_SEQ)) ++ fc_lport_error(lport, fp); ++ } ++} ++ ++/** ++ * fc_rport_enter_rft_id - Register port name with the name server ++ * @lport: Fibre Channel local port to register ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. ++ */ ++static void fc_lport_enter_rpn_id(struct fc_lport *lport) ++{ ++ struct fc_frame *fp; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_rn_id rn; ++ } *req; ++ ++ if (fc_lport_debug) ++ FC_DBG("Port (%6x) entered RPN_ID state from %s state\n", ++ lport->fid, fc_lport_state(lport)); ++ ++ fc_lport_state_enter(lport, LPORT_ST_RPN_ID); ++ ++ fp = fc_frame_alloc(lport, sizeof(*req)); ++ if (!fp) { ++ fc_lport_error(lport, fp); ++ return; + } ++ ++ req = fc_frame_payload_get(fp, sizeof(*req)); ++ memset(req, 0, sizeof(*req)); ++ fc_fill_dns_hdr(lport, &req->ct, FC_NS_RPN_ID, sizeof(req->rn)); ++ hton24(req->rn.fr_fid.fp_fid, lport->fid); ++ put_unaligned_be64(lport->wwpn, &req->rn.fr_wwn); ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_lport_rpn_id_resp, NULL, ++ lport, lport->e_d_tov, ++ lport->fid, ++ FC_FID_DIR_SERV, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_lport_error(lport, fp); ++ ++} ++ ++/** ++ * fc_rport_enter_dns - Create a rport to the name server ++ * @lport: Fibre Channel local port requesting a rport for the name server ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. ++ */ ++static void fc_lport_enter_dns(struct fc_lport *lport) ++{ ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata; ++ struct fc_disc_port dp; ++ ++ dp.ids.port_id = FC_FID_DIR_SERV; ++ dp.ids.port_name = -1; ++ dp.ids.node_name = -1; ++ dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ dp.lp = lport; ++ + if (fc_lport_debug) +- FC_DBG("error %ld retries %d limit %d\n", +- PTR_ERR(fp), lp->retry_count, lp->max_retry_count); +- fc_lport_unlock(lp); ++ FC_DBG("Port (%6x) entered DNS state from %s state\n", ++ lport->fid, fc_lport_state(lport)); ++ ++ fc_lport_state_enter(lport, LPORT_ST_DNS); ++ ++ if (!lport->dns_rp) { ++ /* Set up a dummy rport to directory server */ ++ rport = fc_rport_dummy_create(&dp); ++ ++ if (!rport) ++ goto err; ++ lport->dns_rp = rport; ++ FC_DBG("created an rport for the NS\n"); ++ } ++ ++ rport = lport->dns_rp; ++ rdata = rport->dd_data; ++ rdata->event_callback = fc_lport_rport_event; ++ lport->tt.rport_login(rport); ++ return; ++ ++err: ++ fc_lport_error(lport, NULL); + } + +-static void fc_lport_timeout(unsigned long lp_arg) ++/** ++ * fc_lport_timeout - Handler for the retry_work timer. ++ * @work: The work struct of the fc_lport ++ */ ++static void fc_lport_timeout(struct work_struct *work) + { +- struct fc_lport *lp = (struct fc_lport *)lp_arg; ++ struct fc_lport *lport = ++ container_of(work, struct fc_lport, ++ retry_work.work); + +- fc_lport_lock(lp); +- fc_lport_enter_retry(lp); +- fc_lport_unlock(lp); ++ mutex_lock(&lport->lp_mutex); ++ ++ switch (lport->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_READY: ++ case LPORT_ST_RESET: ++ WARN_ON(1); ++ break; ++ case LPORT_ST_FLOGI: ++ fc_lport_enter_flogi(lport); ++ break; ++ case LPORT_ST_DNS: ++ fc_lport_enter_dns(lport); ++ break; ++ case LPORT_ST_RPN_ID: ++ fc_lport_enter_rpn_id(lport); ++ break; ++ case LPORT_ST_RFT_ID: ++ fc_lport_enter_rft_id(lport); ++ break; ++ case LPORT_ST_SCR: ++ fc_lport_enter_scr(lport); ++ break; ++ case LPORT_ST_LOGO: ++ fc_lport_enter_logo(lport); ++ break; ++ } ++ ++ mutex_unlock(&lport->lp_mutex); + } + ++/** ++ * fc_lport_logo_resp - Handle response to LOGO request ++ * @sp: current sequence in LOGO exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel lport port instance that sent the LOGO request ++ * ++ * Locking Note: This function will be called without the lport lock ++ * held, but it will lock, call an _enter_* function or fc_lport_error ++ * and then unlock the lport. ++ */ + static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + void *lp_arg) + { +- struct fc_lport *lp = lp_arg; ++ struct fc_lport *lport = lp_arg; ++ u8 op; + +- if (IS_ERR(fp)) +- fc_lport_error(lp, fp); +- else { +- fc_frame_free(fp); +- fc_lport_lock(lp); +- fc_lport_enter_reset(lp); +- fc_lport_unlock(lp); ++ mutex_lock(&lport->lp_mutex); ++ ++ if (fc_lport_debug) ++ FC_DBG("Received a LOGO response\n"); ++ ++ if (lport->state != LPORT_ST_LOGO) { ++ FC_DBG("Received a LOGO response, but in state %s\n", ++ fc_lport_state(lport)); ++ goto out; + } ++ ++ if (IS_ERR(fp)) { ++ fc_lport_error(lport, fp); ++ goto out; ++ } ++ ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC) ++ fc_lport_enter_reset(lport); ++ else ++ fc_lport_error(lport, fp); ++ ++out: ++ mutex_unlock(&lport->lp_mutex); ++ fc_frame_free(fp); + } + +-/* Logout of the FC fabric */ +-static void fc_lport_enter_logo(struct fc_lport *lp) ++/** ++ * fc_rport_enter_logo - Logout of the fabric ++ * @lport: Fibre Channel local port to be logged out ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. ++ */ ++static void fc_lport_enter_logo(struct fc_lport *lport) + { + struct fc_frame *fp; + struct fc_els_logo *logo; + + if (fc_lport_debug) +- FC_DBG("Processing LOGO state\n"); ++ FC_DBG("Port (%6x) entered LOGO state from %s state\n", ++ lport->fid, fc_lport_state(lport)); + +- fc_lport_state_enter(lp, LPORT_ST_LOGO); ++ fc_lport_state_enter(lport, LPORT_ST_LOGO); + + /* DNS session should be closed so we can release it here */ +- if (lp->dns_rp) { +- fc_remote_port_delete(lp->dns_rp); +- lp->dns_rp = NULL; ++ if (lport->dns_rp) { ++ fc_remote_port_delete(lport->dns_rp); ++ lport->dns_rp = NULL; + } + +- fp = fc_frame_alloc(lp, sizeof(*logo)); ++ fp = fc_frame_alloc(lport, sizeof(*logo)); + if (!fp) { +- FC_DBG("failed to allocate frame\n"); ++ fc_lport_error(lport, fp); + return; + } + + logo = fc_frame_payload_get(fp, sizeof(*logo)); + memset(logo, 0, sizeof(*logo)); + logo->fl_cmd = ELS_LOGO; +- hton24(logo->fl_n_port_id, lp->fid); +- logo->fl_n_port_wwn = htonll(lp->wwpn); +- ++ hton24(logo->fl_n_port_id, lport->fid); ++ logo->fl_n_port_wwn = htonll(lport->wwpn); + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + fc_frame_set_offset(fp, 0); + +- lp->tt.exch_seq_send(lp, fp, +- fc_lport_logo_resp, +- lp, lp->e_d_tov, +- lp->fid, FC_FID_FLOGI, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +-} +- +-static int fc_lport_logout(struct fc_lport *lp) +-{ +- fc_lport_lock(lp); +- if (lp->state != LPORT_ST_LOGO) +- fc_lport_enter_logo(lp); +- fc_lport_unlock(lp); +- return 0; ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_lport_logo_resp, NULL, ++ lport, lport->e_d_tov, ++ lport->fid, FC_FID_FLOGI, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_lport_error(lport, fp); + } + +-/* +- * Handle incoming ELS FLOGI response. +- * Save parameters of remote switch. Finish exchange. ++/** ++ * fc_lport_flogi_resp - Handle response to FLOGI request ++ * @sp: current sequence in FLOGI exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel lport port instance that sent the FLOGI request ++ * ++ * Locking Note: This function will be called without the lport lock ++ * held, but it will lock, call an _enter_* function or fc_lport_error ++ * and then unlock the lport. + */ +-static void +-fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) ++static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) + { +- struct fc_lport *lp = lp_arg; ++ struct fc_lport *lport = lp_arg; + struct fc_frame_header *fh; + struct fc_els_flogi *flp; + u32 did; +@@ -799,127 +1325,160 @@ fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) + unsigned int e_d_tov; + u16 mfs; + ++ mutex_lock(&lport->lp_mutex); ++ ++ if (fc_lport_debug) ++ FC_DBG("Received a FLOGI response\n"); ++ ++ if (lport->state != LPORT_ST_FLOGI) { ++ FC_DBG("Received a FLOGI response, but in state %s\n", ++ fc_lport_state(lport)); ++ goto out; ++ } ++ + if (IS_ERR(fp)) { +- fc_lport_error(lp, fp); +- return; ++ fc_lport_error(lport, fp); ++ goto out; + } + + fh = fc_frame_header_get(fp); + did = ntoh24(fh->fh_d_id); + if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { + if (fc_lport_debug) +- FC_DBG("assigned fid %x\n", did); +- fc_lport_lock(lp); +- fc_lport_set_fid(lp, did); ++ FC_DBG("Assigned fid %x\n", did); ++ ++ lport->fid = did; + flp = fc_frame_payload_get(fp, sizeof(*flp)); + if (flp) { + mfs = ntohs(flp->fl_csp.sp_bb_data) & + FC_SP_BB_DATA_MASK; + if (mfs >= FC_SP_MIN_MAX_PAYLOAD && +- mfs < lp->mfs) +- lp->mfs = mfs; ++ mfs < lport->mfs) ++ lport->mfs = mfs; + csp_flags = ntohs(flp->fl_csp.sp_features); + r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov); + e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); + if (csp_flags & FC_SP_FT_EDTR) + e_d_tov /= 1000000; + if ((csp_flags & FC_SP_FT_FPORT) == 0) { +- if (e_d_tov > lp->e_d_tov) +- lp->e_d_tov = e_d_tov; +- lp->r_a_tov = 2 * e_d_tov; +- FC_DBG("point-to-point mode\n"); +- fc_lport_ptp_setup(lp, ntoh24(fh->fh_s_id), ++ if (e_d_tov > lport->e_d_tov) ++ lport->e_d_tov = e_d_tov; ++ lport->r_a_tov = 2 * e_d_tov; ++ FC_DBG("Point-to-Point mode\n"); ++ fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), + get_unaligned_be64( + &flp->fl_wwpn), + get_unaligned_be64( + &flp->fl_wwnn)); + } else { +- lp->e_d_tov = e_d_tov; +- lp->r_a_tov = r_a_tov; +- lp->tt.dns_register(lp); ++ lport->e_d_tov = e_d_tov; ++ lport->r_a_tov = r_a_tov; ++ fc_host_fabric_name(lport->host) = ++ get_unaligned_be64(&flp->fl_wwnn); ++ fc_lport_enter_dns(lport); + } + } +- fc_lport_unlock(lp); ++ + if (flp) { + csp_flags = ntohs(flp->fl_csp.sp_features); + if ((csp_flags & FC_SP_FT_FPORT) == 0) { +- if (lp->tt.disc_start(lp)) +- FC_DBG("target disc start error\n"); ++ if (lport->tt.disc_start(lport)) ++ FC_DBG("Target disc start error\n"); + } + } + } else { + FC_DBG("bad FLOGI response\n"); + } ++ ++out: ++ mutex_unlock(&lport->lp_mutex); + fc_frame_free(fp); + } + +-/* +- * Send ELS (extended link service) FLOGI request to peer. ++/** ++ * fc_rport_enter_flogi - Send a FLOGI request to the fabric manager ++ * @lport: Fibre Channel local port to be logged in to the fabric ++ * ++ * Locking Note: The lport lock is expected to be held before calling ++ * this routine. + */ +-static void fc_lport_flogi_send(struct fc_lport *lp) ++void fc_lport_enter_flogi(struct fc_lport *lport) + { + struct fc_frame *fp; + struct fc_els_flogi *flp; + +- fp = fc_frame_alloc(lp, sizeof(*flp)); ++ if (fc_lport_debug) ++ FC_DBG("Processing FLOGI state\n"); ++ ++ fc_lport_state_enter(lport, LPORT_ST_FLOGI); ++ ++ fp = fc_frame_alloc(lport, sizeof(*flp)); + if (!fp) +- return fc_lport_retry(lp); ++ return fc_lport_error(lport, fp); + + flp = fc_frame_payload_get(fp, sizeof(*flp)); +- fc_lport_flogi_fill(lp, flp, ELS_FLOGI); ++ fc_lport_flogi_fill(lport, flp, ELS_FLOGI); + + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + fc_frame_set_offset(fp, 0); + +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_lport_flogi_resp, +- lp, lp->e_d_tov, +- 0, FC_FID_FLOGI, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- fc_lport_retry(lp); +- +-} ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_lport_flogi_resp, NULL, ++ lport, lport->e_d_tov, ++ 0, FC_FID_FLOGI, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_lport_error(lport, fp); + +-void fc_lport_enter_flogi(struct fc_lport *lp) +-{ +- if (fc_lport_debug) +- FC_DBG("Processing FLOGI state\n"); +- fc_lport_state_enter(lp, LPORT_ST_FLOGI); +- fc_lport_flogi_send(lp); + } + + /* Configure a fc_lport */ +-int fc_lport_config(struct fc_lport *lp) ++int fc_lport_config(struct fc_lport *lport) + { +- setup_timer(&lp->state_timer, fc_lport_timeout, (unsigned long)lp); +- spin_lock_init(&lp->state_lock); ++ INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); ++ mutex_init(&lport->lp_mutex); + +- fc_lport_lock(lp); +- fc_lport_state_enter(lp, LPORT_ST_NONE); +- fc_lport_unlock(lp); ++ fc_lport_state_enter(lport, LPORT_ST_NONE); + +- lp->ns_disc_delay = DNS_DELAY; ++ lport->disc_delay = DNS_DELAY; + +- fc_lport_add_fc4_type(lp, FC_TYPE_FCP); +- fc_lport_add_fc4_type(lp, FC_TYPE_CT); ++ fc_lport_add_fc4_type(lport, FC_TYPE_FCP); ++ fc_lport_add_fc4_type(lport, FC_TYPE_CT); + + return 0; + } + EXPORT_SYMBOL(fc_lport_config); + +-int fc_lport_init(struct fc_lport *lp) ++int fc_lport_init(struct fc_lport *lport) + { +- if (!lp->tt.lport_recv) +- lp->tt.lport_recv = fc_lport_recv; +- +- if (!lp->tt.lport_login) +- lp->tt.lport_login = fc_lport_enter_reset; +- +- if (!lp->tt.lport_reset) +- lp->tt.lport_reset = fc_lport_enter_reset; +- +- if (!lp->tt.lport_logout) +- lp->tt.lport_logout = fc_lport_logout; ++ if (!lport->tt.lport_recv) ++ lport->tt.lport_recv = fc_lport_recv_req; ++ ++ if (!lport->tt.lport_reset) ++ lport->tt.lport_reset = fc_lport_reset; ++ ++ if (!lport->tt.event_callback) ++ lport->tt.event_callback = fc_lport_rport_event; ++ ++ fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; ++ fc_host_node_name(lport->host) = lport->wwnn; ++ fc_host_port_name(lport->host) = lport->wwpn; ++ fc_host_supported_classes(lport->host) = FC_COS_CLASS3; ++ memset(fc_host_supported_fc4s(lport->host), 0, ++ sizeof(fc_host_supported_fc4s(lport->host))); ++ fc_host_supported_fc4s(lport->host)[2] = 1; ++ fc_host_supported_fc4s(lport->host)[7] = 1; ++ ++ /* This value is also unchanging */ ++ memset(fc_host_active_fc4s(lport->host), 0, ++ sizeof(fc_host_active_fc4s(lport->host))); ++ fc_host_active_fc4s(lport->host)[2] = 1; ++ fc_host_active_fc4s(lport->host)[7] = 1; ++ fc_host_maxframe_size(lport->host) = lport->mfs; ++ fc_host_supported_speeds(lport->host) = 0; ++ if (lport->link_supported_speeds & FC_PORTSPEED_1GBIT) ++ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT; ++ if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) ++ fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; + + return 0; + } +diff --git a/drivers/scsi/libfc/fc_ns.c b/drivers/scsi/libfc/fc_ns.c +deleted file mode 100644 +index 5c9272c..0000000 +--- a/drivers/scsi/libfc/fc_ns.c ++++ /dev/null +@@ -1,1283 +0,0 @@ +-/* +- * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-/* +- * Target Discovery +- * Actually, this discovers all FC-4 remote ports, including FCP initiators. +- */ +- +-#include +-#include +-#include +- +-#include +- +-#include +- +-#define FC_NS_RETRY_LIMIT 3 /* max retries */ +-#define FC_NS_RETRY_DELAY 500UL /* (msecs) delay */ +- +-int fc_ns_debug; +- +-static void fc_ns_gpn_ft_req(struct fc_lport *); +-static void fc_ns_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); +-static int fc_ns_new_target(struct fc_lport *, struct fc_rport *, +- struct fc_rport_identifiers *); +-static void fc_ns_del_target(struct fc_lport *, struct fc_rport *); +-static void fc_ns_disc_done(struct fc_lport *); +-static void fcdt_ns_error(struct fc_lport *, struct fc_frame *); +-static void fc_ns_timeout(struct work_struct *); +- +-/** +- * struct fc_ns_port - temporary discovery port to hold rport identifiers +- * @lp: Fibre Channel host port instance +- * @peers: node for list management during discovery and RSCN processing +- * @ids: identifiers structure to pass to fc_remote_port_add() +- */ +-struct fc_ns_port { +- struct fc_lport *lp; +- struct list_head peers; +- struct fc_rport_identifiers ids; +-}; +- +-static int fc_ns_gpn_id_req(struct fc_lport *, struct fc_ns_port *); +-static void fc_ns_gpn_id_resp(struct fc_seq *, struct fc_frame *, void *); +-static void fc_ns_gpn_id_error(struct fc_ns_port *rp, struct fc_frame *fp); +- +-static int fc_ns_gnn_id_req(struct fc_lport *, struct fc_ns_port *); +-static void fc_ns_gnn_id_resp(struct fc_seq *, struct fc_frame *, void *); +-static void fc_ns_gnn_id_error(struct fc_ns_port *, struct fc_frame *); +-static void fc_ns_enter_reg_pn(struct fc_lport *lp); +-static void fc_ns_error(struct fc_lport *lp, struct fc_frame *fp); +-static void fc_lport_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, +- unsigned int op, unsigned int req_size); +-static void fc_ns_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *lp_arg); +-static void fc_ns_retry(struct fc_lport *lp); +-static void fc_ns_single(struct fc_lport *, struct fc_ns_port *); +-static int fc_ns_restart(struct fc_lport *); +- +- +-/** +- * fc_ns_rscn_req - Handle Registered State Change Notification (RSCN) +- * @sp: Current sequence of the RSCN exchange +- * @fp: RSCN Frame +- * @lp: Fibre Channel host port instance +- */ +-static void fc_ns_rscn_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lp) +-{ +- struct fc_els_rscn *rp; +- struct fc_els_rscn_page *pp; +- struct fc_seq_els_data rjt_data; +- unsigned int len; +- int redisc = 0; +- enum fc_els_rscn_ev_qual ev_qual; +- enum fc_els_rscn_addr_fmt fmt; +- LIST_HEAD(disc_list); +- struct fc_ns_port *dp, *next; +- +- rp = fc_frame_payload_get(fp, sizeof(*rp)); +- +- if (!rp || rp->rscn_page_len != sizeof(*pp)) +- goto reject; +- +- len = ntohs(rp->rscn_plen); +- if (len < sizeof(*rp)) +- goto reject; +- len -= sizeof(*rp); +- +- for (pp = (void *)(rp + 1); len; len -= sizeof(*pp), pp++) { +- ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT; +- ev_qual &= ELS_RSCN_EV_QUAL_MASK; +- fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT; +- fmt &= ELS_RSCN_ADDR_FMT_MASK; +- /* +- * if we get an address format other than port +- * (area, domain, fabric), then do a full discovery +- */ +- switch (fmt) { +- case ELS_ADDR_FMT_PORT: +- dp = kzalloc(sizeof(*dp), GFP_KERNEL); +- if (!dp) { +- redisc = 1; +- break; +- } +- dp->lp = lp; +- dp->ids.port_id = ntoh24(pp->rscn_fid); +- dp->ids.port_name = -1; +- dp->ids.node_name = -1; +- dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; +- list_add_tail(&dp->peers, &disc_list); +- break; +- case ELS_ADDR_FMT_AREA: +- case ELS_ADDR_FMT_DOM: +- case ELS_ADDR_FMT_FAB: +- default: +- redisc = 1; +- break; +- } +- } +- lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); +- if (redisc) { +- if (fc_ns_debug) +- FC_DBG("RSCN received: rediscovering\n"); +- list_for_each_entry_safe(dp, next, &disc_list, peers) { +- list_del(&dp->peers); +- kfree(dp); +- } +- fc_ns_restart(lp); +- } else { +- if (fc_ns_debug) +- FC_DBG("RSCN received: not rediscovering. " +- "redisc %d state %d in_prog %d\n", +- redisc, lp->state, lp->ns_disc_pending); +- list_for_each_entry_safe(dp, next, &disc_list, peers) { +- list_del(&dp->peers); +- fc_ns_single(lp, dp); +- } +- } +- fc_frame_free(fp); +- return; +-reject: +- rjt_data.fp = NULL; +- rjt_data.reason = ELS_RJT_LOGIC; +- rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); +- fc_frame_free(fp); +-} +- +-static void fc_ns_recv_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lp) +-{ +- switch (fc_frame_payload_op(fp)) { +- case ELS_RSCN: +- fc_ns_rscn_req(sp, fp, lp); +- break; +- default: +- FC_DBG("fc_ns recieved an unexpected request\n"); +- break; +- } +-} +- +-/** +- * fc_ns_scr_resp - Handle response to State Change Register (SCR) request +- * @sp: current sequence in SCR exchange +- * @fp: response frame +- * @lp_arg: Fibre Channel host port instance +- */ +-static void fc_ns_scr_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *lp_arg) +-{ +- struct fc_lport *lp = lp_arg; +- int err; +- +- if (IS_ERR(fp)) +- fc_ns_error(lp, fp); +- else { +- fc_lport_lock(lp); +- fc_lport_state_enter(lp, LPORT_ST_READY); +- fc_lport_unlock(lp); +- err = lp->tt.disc_start(lp); +- if (err) +- FC_DBG("target discovery start error\n"); +- fc_frame_free(fp); +- } +-} +- +-/** +- * fc_ns_enter scr - Send a State Change Register (SCR) request +- * @lp: Fibre Channel host port instance +- */ +-static void fc_ns_enter_scr(struct fc_lport *lp) +-{ +- struct fc_frame *fp; +- struct fc_els_scr *scr; +- +- if (fc_ns_debug) +- FC_DBG("Processing SCR state\n"); +- +- fc_lport_state_enter(lp, LPORT_ST_SCR); +- +- fp = fc_frame_alloc(lp, sizeof(*scr)); +- if (fp) { +- scr = fc_frame_payload_get(fp, sizeof(*scr)); +- memset(scr, 0, sizeof(*scr)); +- scr->scr_cmd = ELS_SCR; +- scr->scr_reg_func = ELS_SCRF_FULL; +- } +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- fc_frame_set_offset(fp, 0); +- +- lp->tt.exch_seq_send(lp, fp, +- fc_ns_scr_resp, +- lp, lp->e_d_tov, +- lp->fid, FC_FID_FCTRL, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +-} +- +-/** +- * fc_ns_enter_reg_ft - Register FC4-types with the name server +- * @lp: Fibre Channel host port instance +- */ +-static void fc_ns_enter_reg_ft(struct fc_lport *lp) +-{ +- struct fc_frame *fp; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_fid fid; /* port ID object */ +- struct fc_ns_fts fts; /* FC4-types object */ +- } *req; +- struct fc_ns_fts *lps; +- int i; +- +- if (fc_ns_debug) +- FC_DBG("Processing REG_FT state\n"); +- +- fc_lport_state_enter(lp, LPORT_ST_REG_FT); +- +- lps = &lp->fcts; +- i = sizeof(lps->ff_type_map) / sizeof(lps->ff_type_map[0]); +- while (--i >= 0) +- if (ntohl(lps->ff_type_map[i]) != 0) +- break; +- if (i >= 0) { +- fp = fc_frame_alloc(lp, sizeof(*req)); +- if (fp) { +- req = fc_frame_payload_get(fp, sizeof(*req)); +- fc_lport_fill_dns_hdr(lp, &req->ct, +- FC_NS_RFT_ID, +- sizeof(*req) - +- sizeof(struct fc_ct_hdr)); +- hton24(req->fid.fp_fid, lp->fid); +- req->fts = *lps; +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_ns_resp, lp, +- lp->e_d_tov, +- lp->fid, +- lp->dns_rp->port_id, +- FC_FC_SEQ_INIT | +- FC_FC_END_SEQ)) +- fc_ns_retry(lp); +- } else { +- fc_ns_retry(lp); +- } +- } else { +- fc_ns_enter_scr(lp); +- } +-} +- +-/* +- * enter next state for handling an exchange reject or retry exhaustion +- * in the current state. +- */ +-static void fc_ns_enter_reject(struct fc_lport *lp) +-{ +- switch (lp->state) { +- case LPORT_ST_NONE: +- case LPORT_ST_READY: +- case LPORT_ST_RESET: +- case LPORT_ST_FLOGI: +- case LPORT_ST_LOGO: +- WARN_ON(1); +- break; +- case LPORT_ST_REG_PN: +- fc_ns_enter_reg_ft(lp); +- break; +- case LPORT_ST_REG_FT: +- fc_ns_enter_scr(lp); +- break; +- case LPORT_ST_SCR: +- case LPORT_ST_DNS_STOP: +- lp->tt.disc_stop(lp); +- break; +- case LPORT_ST_DNS: +- lp->tt.lport_reset(lp); +- break; +- } +-} +- +-static void fc_ns_enter_retry(struct fc_lport *lp) +-{ +- switch (lp->state) { +- case LPORT_ST_NONE: +- case LPORT_ST_RESET: +- case LPORT_ST_READY: +- case LPORT_ST_FLOGI: +- case LPORT_ST_LOGO: +- WARN_ON(1); +- break; +- case LPORT_ST_DNS: +- lp->tt.dns_register(lp); +- break; +- case LPORT_ST_DNS_STOP: +- lp->tt.disc_stop(lp); +- break; +- case LPORT_ST_REG_PN: +- fc_ns_enter_reg_pn(lp); +- break; +- case LPORT_ST_REG_FT: +- fc_ns_enter_reg_ft(lp); +- break; +- case LPORT_ST_SCR: +- fc_ns_enter_scr(lp); +- break; +- } +-} +- +-/* +- * Refresh target discovery, perhaps due to an RSCN. +- * A configurable delay is introduced to collect any subsequent RSCNs. +- */ +-static int fc_ns_restart(struct fc_lport *lp) +-{ +- fc_lport_lock(lp); +- if (!lp->ns_disc_requested && !lp->ns_disc_pending) { +- schedule_delayed_work(&lp->ns_disc_work, +- msecs_to_jiffies(lp->ns_disc_delay * 1000)); +- } +- lp->ns_disc_requested = 1; +- fc_lport_unlock(lp); +- return 0; +-} +- +-/* unlocked varient of scsi_target_block from scsi_lib.c */ +-#include "../scsi_priv.h" +- +-static void __device_block(struct scsi_device *sdev, void *data) +-{ +- scsi_internal_device_block(sdev); +-} +- +-static int __target_block(struct device *dev, void *data) +-{ +- if (scsi_is_target_device(dev)) +- __starget_for_each_device(to_scsi_target(dev), +- NULL, __device_block); +- return 0; +-} +- +-static void __scsi_target_block(struct device *dev) +-{ +- if (scsi_is_target_device(dev)) +- __starget_for_each_device(to_scsi_target(dev), +- NULL, __device_block); +- else +- device_for_each_child(dev, NULL, __target_block); +-} +- +-static void fc_block_rports(struct fc_lport *lp) +-{ +- struct Scsi_Host *shost = lp->host; +- struct fc_rport *rport; +- unsigned long flags; +- +- spin_lock_irqsave(shost->host_lock, flags); +- list_for_each_entry(rport, &fc_host_rports(shost), peers) { +- /* protect the name service remote port */ +- if (rport == lp->dns_rp) +- continue; +- if (rport->port_state != FC_PORTSTATE_ONLINE) +- continue; +- rport->port_state = FC_PORTSTATE_BLOCKED; +- rport->flags |= FC_RPORT_DEVLOSS_PENDING; +- __scsi_target_block(&rport->dev); +- } +- spin_unlock_irqrestore(shost->host_lock, flags); +-} +- +-/* +- * Fibre Channel Target discovery. +- * +- * Returns non-zero if discovery cannot be started. +- * +- * Callback is called for each target remote port found in discovery. +- * When discovery is complete, the callback is called with a NULL remote port. +- * Discovery may be restarted after an RSCN is received, causing the +- * callback to be called after discovery complete is indicated. +- */ +-int fc_ns_disc_start(struct fc_lport *lp) +-{ +- struct fc_rport *rport; +- int error; +- struct fc_rport_identifiers ids; +- +- fc_lport_lock(lp); +- +- /* +- * If not ready, or already running discovery, just set request flag. +- */ +- if (!fc_lport_test_ready(lp) || lp->ns_disc_pending) { +- lp->ns_disc_requested = 1; +- fc_lport_unlock(lp); +- return 0; +- } +- lp->ns_disc_pending = 1; +- lp->ns_disc_requested = 0; +- lp->ns_disc_retry_count = 0; +- +- /* +- * Handle point-to-point mode as a simple discovery +- * of the remote port. +- */ +- rport = lp->ptp_rp; +- if (rport) { +- ids.port_id = rport->port_id; +- ids.port_name = rport->port_name; +- ids.node_name = rport->node_name; +- ids.roles = FC_RPORT_ROLE_UNKNOWN; +- get_device(&rport->dev); +- fc_lport_unlock(lp); +- error = fc_ns_new_target(lp, rport, &ids); +- put_device(&rport->dev); +- if (!error) +- fc_ns_disc_done(lp); +- } else { +- fc_lport_unlock(lp); +- fc_block_rports(lp); +- fc_ns_gpn_ft_req(lp); /* get ports by FC-4 type */ +- error = 0; +- } +- return error; +-} +- +-/* +- * Handle resource allocation problem by retrying in a bit. +- */ +-static void fc_ns_retry(struct fc_lport *lp) +-{ +- if (lp->retry_count == 0) +- FC_DBG("local port %6x alloc failure " +- "- will retry\n", lp->fid); +- if (lp->retry_count < lp->max_retry_count) { +- lp->retry_count++; +- mod_timer(&lp->state_timer, +- jiffies + msecs_to_jiffies(lp->e_d_tov)); +- } else { +- FC_DBG("local port %6x alloc failure " +- "- retries exhausted\n", lp->fid); +- fc_ns_enter_reject(lp); +- } +-} +- +-/* +- * Handle errors on local port requests. +- * Don't get locks if in RESET state. +- * The only possible errors so far are exchange TIMEOUT and CLOSED (reset). +- */ +-static void fc_ns_error(struct fc_lport *lp, struct fc_frame *fp) +-{ +- if (lp->state == LPORT_ST_RESET) +- return; +- +- fc_lport_lock(lp); +- if (PTR_ERR(fp) == -FC_EX_TIMEOUT) { +- if (lp->retry_count < lp->max_retry_count) { +- lp->retry_count++; +- fc_ns_enter_retry(lp); +- } else { +- fc_ns_enter_reject(lp); +- } +- } +- if (fc_ns_debug) +- FC_DBG("error %ld retries %d limit %d\n", +- PTR_ERR(fp), lp->retry_count, lp->max_retry_count); +- fc_lport_unlock(lp); +-} +- +-/* +- * Restart discovery after a delay due to resource shortages. +- * If the error persists, the discovery will be abandoned. +- */ +-static void fcdt_ns_retry(struct fc_lport *lp) +-{ +- unsigned long delay = FC_NS_RETRY_DELAY; +- +- if (!lp->ns_disc_retry_count) +- delay /= 4; /* timeout faster first time */ +- if (lp->ns_disc_retry_count++ < FC_NS_RETRY_LIMIT) +- schedule_delayed_work(&lp->ns_disc_work, +- msecs_to_jiffies(delay)); +- else +- fc_ns_disc_done(lp); +-} +- +-/* +- * Test for dNS accept in response payload. +- */ +-static int fc_lport_dns_acc(struct fc_frame *fp) +-{ +- struct fc_frame_header *fh; +- struct fc_ct_hdr *ct; +- int rc = 0; +- +- fh = fc_frame_header_get(fp); +- ct = fc_frame_payload_get(fp, sizeof(*ct)); +- if (fh && ct && fh->fh_type == FC_TYPE_CT && +- ct->ct_fs_type == FC_FST_DIR && +- ct->ct_fs_subtype == FC_NS_SUBTYPE && +- ntohs(ct->ct_cmd) == FC_FS_ACC) { +- rc = 1; +- } +- return rc; +-} +- +-/* +- * Handle response from name server. +- */ +-static void +-fc_ns_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) +-{ +- struct fc_lport *lp = lp_arg; +- +- if (!IS_ERR(fp)) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- if (fc_lport_dns_acc(fp)) { +- if (lp->state == LPORT_ST_REG_PN) +- fc_ns_enter_reg_ft(lp); +- else +- fc_ns_enter_scr(lp); +- +- } else { +- fc_ns_retry(lp); +- } +- fc_lport_unlock(lp); +- fc_frame_free(fp); +- } else +- fc_ns_error(lp, fp); +-} +- +-/* +- * Handle new target found by discovery. +- * Create remote port and session if needed. +- * Ignore returns of our own FID & WWPN. +- * +- * If a non-NULL rp is passed in, it is held for the caller, but not for us. +- * +- * Events delivered are: +- * FC_EV_READY, when remote port is rediscovered. +- */ +-static int fc_ns_new_target(struct fc_lport *lp, +- struct fc_rport *rport, +- struct fc_rport_identifiers *ids) +-{ +- struct fc_rport_libfc_priv *rp; +- int error = 0; +- +- if (rport && ids->port_name) { +- if (rport->port_name == -1) { +- /* +- * Set WWN and fall through to notify of create. +- */ +- fc_rport_set_name(rport, ids->port_name, +- rport->node_name); +- } else if (rport->port_name != ids->port_name) { +- /* +- * This is a new port with the same FCID as +- * a previously-discovered port. Presumably the old +- * port logged out and a new port logged in and was +- * assigned the same FCID. This should be rare. +- * Delete the old one and fall thru to re-create. +- */ +- fc_ns_del_target(lp, rport); +- rport = NULL; +- } +- } +- if (((ids->port_name != -1) || (ids->port_id != -1)) && +- ids->port_id != lp->fid && ids->port_name != lp->wwpn) { +- if (!rport) { +- rport = lp->tt.rport_lookup(lp, ids->port_id); +- if (rport == NULL) +- rport = lp->tt.rport_create(lp, ids); +- if (!rport) +- error = ENOMEM; +- } +- if (rport) { +- rp = rport->dd_data; +- rp->rp_state = RPORT_ST_INIT; +- lp->tt.rport_login(rport); +- } +- } +- return error; +-} +- +-/* +- * Delete the remote port. +- */ +-static void fc_ns_del_target(struct fc_lport *lp, struct fc_rport *rport) +-{ +- lp->tt.rport_reset(rport); +- fc_remote_port_delete(rport); /* release hold from create */ +-} +- +-/* +- * Done with discovery +- */ +-static void fc_ns_disc_done(struct fc_lport *lp) +-{ +- lp->ns_disc_done = 1; +- lp->ns_disc_pending = 0; +- if (lp->ns_disc_requested) +- lp->tt.disc_start(lp); +-} +- +-/** +- * fc_ns_fill_dns_hdr - Fill in a name service request header +- * @lp: Fibre Channel host port instance +- * @ct: Common Transport (CT) header structure +- * @op: Name Service request code +- * @req_size: Full size of Name Service request +- */ +-static void fc_ns_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, +- unsigned int op, unsigned int req_size) +-{ +- memset(ct, 0, sizeof(*ct) + req_size); +- ct->ct_rev = FC_CT_REV; +- ct->ct_fs_type = FC_FST_DIR; +- ct->ct_fs_subtype = FC_NS_SUBTYPE; +- ct->ct_cmd = htons((u16) op); +-} +- +-/** +- * fc_ns_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request +- * @lp: Fibre Channel host port instance +- */ +-static void fc_ns_gpn_ft_req(struct fc_lport *lp) +-{ +- struct fc_frame *fp; +- struct fc_seq *sp = NULL; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_gid_ft gid; +- } *rp; +- int error = 0; +- +- lp->ns_disc_buf_len = 0; +- lp->ns_disc_seq_count = 0; +- fp = fc_frame_alloc(lp, sizeof(*rp)); +- if (fp == NULL) { +- error = ENOMEM; +- } else { +- rp = fc_frame_payload_get(fp, sizeof(*rp)); +- fc_ns_fill_dns_hdr(lp, &rp->ct, FC_NS_GPN_FT, sizeof(rp->gid)); +- rp->gid.fn_fc4_type = FC_TYPE_FCP; +- +- WARN_ON(!fc_lport_test_ready(lp)); +- +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- sp = lp->tt.exch_seq_send(lp, fp, +- fc_ns_gpn_ft_resp, +- lp, lp->e_d_tov, +- lp->fid, +- lp->dns_rp->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +- } +- if (error || sp == NULL) +- fcdt_ns_retry(lp); +-} +- +-/* +- * Handle error on dNS request. +- */ +-static void fcdt_ns_error(struct fc_lport *lp, struct fc_frame *fp) +-{ +- int err = PTR_ERR(fp); +- +- switch (err) { +- case -FC_EX_TIMEOUT: +- if (lp->ns_disc_retry_count++ < FC_NS_RETRY_LIMIT) { +- fc_ns_gpn_ft_req(lp); +- } else { +- FC_DBG("err %d - ending\n", err); +- fc_ns_disc_done(lp); +- } +- break; +- default: +- FC_DBG("err %d - ending\n", err); +- fc_ns_disc_done(lp); +- break; +- } +-} +- +-/** +- * fc_ns_gpn_ft_parse - Parse the list of IDs and names resulting from a request +- * @lp: Fibre Channel host port instance +- * @buf: GPN_FT response buffer +- * @len: size of response buffer +- */ +-static int fc_ns_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) +-{ +- struct fc_gpn_ft_resp *np; +- char *bp; +- size_t plen; +- size_t tlen; +- int error = 0; +- struct fc_ns_port *dp; +- +- /* +- * Handle partial name record left over from previous call. +- */ +- bp = buf; +- plen = len; +- np = (struct fc_gpn_ft_resp *)bp; +- tlen = lp->ns_disc_buf_len; +- if (tlen) { +- WARN_ON(tlen >= sizeof(*np)); +- plen = sizeof(*np) - tlen; +- WARN_ON(plen <= 0); +- WARN_ON(plen >= sizeof(*np)); +- if (plen > len) +- plen = len; +- np = &lp->ns_disc_buf; +- memcpy((char *)np + tlen, bp, plen); +- +- /* +- * Set bp so that the loop below will advance it to the +- * first valid full name element. +- */ +- bp -= tlen; +- len += tlen; +- plen += tlen; +- lp->ns_disc_buf_len = (unsigned char) plen; +- if (plen == sizeof(*np)) +- lp->ns_disc_buf_len = 0; +- } +- +- /* +- * Handle full name records, including the one filled from above. +- * Normally, np == bp and plen == len, but from the partial case above, +- * bp, len describe the overall buffer, and np, plen describe the +- * partial buffer, which if would usually be full now. +- * After the first time through the loop, things return to "normal". +- */ +- while (plen >= sizeof(*np)) { +- dp = kzalloc(sizeof(*dp), GFP_KERNEL); +- if (!dp) +- break; +- dp->lp = lp; +- dp->ids.port_id = ntoh24(np->fp_fid); +- dp->ids.port_name = ntohll(np->fp_wwpn); +- dp->ids.node_name = -1; +- dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; +- error = fc_ns_gnn_id_req(lp, dp); +- if (error) +- break; +- if (np->fp_flags & FC_NS_FID_LAST) { +- fc_ns_disc_done(lp); +- len = 0; +- break; +- } +- len -= sizeof(*np); +- bp += sizeof(*np); +- np = (struct fc_gpn_ft_resp *)bp; +- plen = len; +- } +- +- /* +- * Save any partial record at the end of the buffer for next time. +- */ +- if (error == 0 && len > 0 && len < sizeof(*np)) { +- if (np != &lp->ns_disc_buf) +- memcpy(&lp->ns_disc_buf, np, len); +- lp->ns_disc_buf_len = (unsigned char) len; +- } else { +- lp->ns_disc_buf_len = 0; +- } +- return error; +-} +- +-/* +- * Handle retry of memory allocation for remote ports. +- */ +-static void fc_ns_timeout(struct work_struct *work) +-{ +- struct fc_lport *lp; +- +- lp = container_of(work, struct fc_lport, ns_disc_work.work); +- +- if (lp->ns_disc_pending) +- fc_ns_gpn_ft_req(lp); +- else +- lp->tt.disc_start(lp); +-} +- +-/** +- * fc_ns_gpn_ft_resp - Handle a response frame from Get Port Names (GPN_FT) +- * @sp: Current sequence of GPN_FT exchange +- * @fp: response frame +- * @lp_arg: Fibre Channel host port instance +- * +- * The response may be in multiple frames +- */ +-static void fc_ns_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *lp_arg) +-{ +- struct fc_lport *lp = lp_arg; +- struct fc_ct_hdr *cp; +- struct fc_frame_header *fh; +- unsigned int seq_cnt; +- void *buf = NULL; +- unsigned int len; +- int error; +- +- if (IS_ERR(fp)) { +- fcdt_ns_error(lp, fp); +- return; +- } +- +- WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ +- fh = fc_frame_header_get(fp); +- len = fr_len(fp) - sizeof(*fh); +- seq_cnt = ntohs(fh->fh_seq_cnt); +- if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && +- lp->ns_disc_seq_count == 0) { +- cp = fc_frame_payload_get(fp, sizeof(*cp)); +- if (cp == NULL) { +- FC_DBG("GPN_FT response too short, len %d\n", +- fr_len(fp)); +- } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { +- +- /* +- * Accepted. Parse response. +- */ +- buf = cp + 1; +- len -= sizeof(*cp); +- } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { +- FC_DBG("GPN_FT rejected reason %x exp %x " +- "(check zoning)\n", cp->ct_reason, +- cp->ct_explan); +- fc_ns_disc_done(lp); +- } else { +- FC_DBG("GPN_FT unexpected response code %x\n", +- ntohs(cp->ct_cmd)); +- } +- } else if (fr_sof(fp) == FC_SOF_N3 && +- seq_cnt == lp->ns_disc_seq_count) { +- buf = fh + 1; +- } else { +- FC_DBG("GPN_FT unexpected frame - out of sequence? " +- "seq_cnt %x expected %x sof %x eof %x\n", +- seq_cnt, lp->ns_disc_seq_count, fr_sof(fp), fr_eof(fp)); +- } +- if (buf) { +- error = fc_ns_gpn_ft_parse(lp, buf, len); +- if (error) +- fcdt_ns_retry(lp); +- else +- lp->ns_disc_seq_count++; +- } +- fc_frame_free(fp); +-} +- +-/* +- * Discover the directory information for a single target. +- * This could be from an RSCN that reported a change for the target. +- */ +-static void fc_ns_single(struct fc_lport *lp, struct fc_ns_port *dp) +-{ +- struct fc_rport *rport; +- +- if (dp->ids.port_id == lp->fid) +- goto out; +- +- rport = lp->tt.rport_lookup(lp, dp->ids.port_id); +- if (rport) { +- fc_ns_del_target(lp, rport); +- put_device(&rport->dev); /* hold from lookup */ +- } +- +- if (fc_ns_gpn_id_req(lp, dp) != 0) +- goto error; +- return; +-error: +- fc_ns_restart(lp); +-out: +- kfree(dp); +-} +- +-/** +- * fc_ns_gpn_id_req - Send Get Port Name by ID (GPN_ID) request +- * @lp: Fibre Channel host port instance +- * @dp: Temporary discovery port for holding IDs and world wide names +- * +- * The remote port is held by the caller for us. +- */ +-static int fc_ns_gpn_id_req(struct fc_lport *lp, struct fc_ns_port *dp) +-{ +- struct fc_frame *fp; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_fid fid; +- } *cp; +- int error = 0; +- +- fp = fc_frame_alloc(lp, sizeof(*cp)); +- if (fp == NULL) +- return -ENOMEM; +- +- cp = fc_frame_payload_get(fp, sizeof(*cp)); +- fc_ns_fill_dns_hdr(lp, &cp->ct, FC_NS_GPN_ID, sizeof(cp->fid)); +- hton24(cp->fid.fp_fid, dp->ids.port_id); +- +- WARN_ON(!fc_lport_test_ready(lp)); +- +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_ns_gpn_id_resp, +- dp, lp->e_d_tov, +- lp->fid, +- lp->dns_rp->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- error = -ENOMEM; +- +- return error; +-} +- +-/** +- * fc_ns_gpn_id_resp - Handle response to GPN_ID +- * @sp: Current sequence of GPN_ID exchange +- * @fp: response frame +- * @dp_arg: Temporary discovery port for holding IDs and world wide names +- */ +-static void fc_ns_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *dp_arg) +-{ +- struct fc_ns_port *dp = dp_arg; +- struct fc_lport *lp; +- struct resp { +- struct fc_ct_hdr ct; +- __be64 wwn; +- } *cp; +- unsigned int cmd; +- +- if (IS_ERR(fp)) { +- fc_ns_gpn_id_error(dp, fp); +- return; +- } +- +- lp = dp->lp; +- WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ +- +- cp = fc_frame_payload_get(fp, sizeof(cp->ct)); +- if (cp == NULL) { +- FC_DBG("GPN_ID response too short, len %d\n", fr_len(fp)); +- return; +- } +- cmd = ntohs(cp->ct.ct_cmd); +- switch (cmd) { +- case FC_FS_ACC: +- cp = fc_frame_payload_get(fp, sizeof(*cp)); +- if (cp == NULL) { +- FC_DBG("GPN_ID response payload too short, len %d\n", +- fr_len(fp)); +- break; +- } +- dp->ids.port_name = ntohll(cp->wwn); +- fc_ns_gnn_id_req(lp, dp); +- break; +- case FC_FS_RJT: +- fc_ns_restart(lp); +- break; +- default: +- FC_DBG("GPN_ID unexpected CT response cmd %x\n", cmd); +- break; +- } +- fc_frame_free(fp); +-} +- +-/** +- * fc_ns_gpn_id_error - Handle error from GPN_ID +- * @dp: Temporary discovery port for holding IDs and world wide names +- * @fp: response frame +- */ +-static void fc_ns_gpn_id_error(struct fc_ns_port *dp, struct fc_frame *fp) +-{ +- struct fc_lport *lp = dp->lp; +- +- switch (PTR_ERR(fp)) { +- case -FC_EX_TIMEOUT: +- fc_ns_restart(lp); +- break; +- case -FC_EX_CLOSED: +- default: +- break; +- } +- kfree(dp); +-} +- +-/* +- * Setup session to dNS if not already set up. +- */ +-static void fc_ns_enter_dns(struct fc_lport *lp) +-{ +- struct fc_rport *rport; +- struct fc_rport_libfc_priv *rp; +- struct fc_rport_identifiers ids = { +- .port_id = FC_FID_DIR_SERV, +- .port_name = -1, +- .node_name = -1, +- .roles = FC_RPORT_ROLE_UNKNOWN, +- }; +- +- if (fc_ns_debug) +- FC_DBG("Processing DNS state\n"); +- +- fc_lport_state_enter(lp, LPORT_ST_DNS); +- +- if (!lp->dns_rp) { +- /* +- * Set up remote port to directory server. +- */ +- +- /* +- * we are called with the state_lock, but if rport_lookup_create +- * needs to create a rport then it will sleep. +- */ +- fc_lport_unlock(lp); +- rport = lp->tt.rport_lookup(lp, ids.port_id); +- if (rport == NULL) +- rport = lp->tt.rport_create(lp, &ids); +- fc_lport_lock(lp); +- if (!rport) +- goto err; +- lp->dns_rp = rport; +- } +- +- rport = lp->dns_rp; +- rp = rport->dd_data; +- +- /* +- * If dNS session isn't ready, start its logon. +- */ +- if (rp->rp_state != RPORT_ST_READY) { +- lp->tt.rport_login(rport); +- } else { +- del_timer(&lp->state_timer); +- fc_ns_enter_reg_pn(lp); +- } +- return; +- +- /* +- * Resource allocation problem (malloc). Try again in 500 mS. +- */ +-err: +- fc_ns_retry(lp); +-} +- +-/* +- * Logoff DNS session. +- * We should get an event call when the session has been logged out. +- */ +-static void fc_ns_enter_dns_stop(struct fc_lport *lp) +-{ +- struct fc_rport *rport = lp->dns_rp; +- +- if (fc_ns_debug) +- FC_DBG("Processing DNS_STOP state\n"); +- +- fc_lport_state_enter(lp, LPORT_ST_DNS_STOP); +- +- if (rport) +- lp->tt.rport_logout(rport); +- else +- lp->tt.lport_logout(lp); +-} +- +-/* +- * Fill in dNS request header. +- */ +-static void +-fc_lport_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, +- unsigned int op, unsigned int req_size) +-{ +- memset(ct, 0, sizeof(*ct) + req_size); +- ct->ct_rev = FC_CT_REV; +- ct->ct_fs_type = FC_FST_DIR; +- ct->ct_fs_subtype = FC_NS_SUBTYPE; +- ct->ct_cmd = htons(op); +-} +- +-/* +- * Register port name with name server. +- */ +-static void fc_ns_enter_reg_pn(struct fc_lport *lp) +-{ +- struct fc_frame *fp; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_rn_id rn; +- } *req; +- +- if (fc_ns_debug) +- FC_DBG("Processing REG_PN state\n"); +- +- fc_lport_state_enter(lp, LPORT_ST_REG_PN); +- fp = fc_frame_alloc(lp, sizeof(*req)); +- if (!fp) { +- fc_ns_retry(lp); +- return; +- } +- req = fc_frame_payload_get(fp, sizeof(*req)); +- memset(req, 0, sizeof(*req)); +- fc_lport_fill_dns_hdr(lp, &req->ct, FC_NS_RPN_ID, sizeof(req->rn)); +- hton24(req->rn.fr_fid.fp_fid, lp->fid); +- put_unaligned_be64(lp->wwpn, &req->rn.fr_wwn); +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_ns_resp, lp, +- lp->e_d_tov, +- lp->fid, +- lp->dns_rp->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- fc_ns_retry(lp); +-} +- +-int fc_ns_init(struct fc_lport *lp) +-{ +- INIT_DELAYED_WORK(&lp->ns_disc_work, fc_ns_timeout); +- +- if (!lp->tt.disc_start) +- lp->tt.disc_start = fc_ns_disc_start; +- +- if (!lp->tt.disc_recv_req) +- lp->tt.disc_recv_req = fc_ns_recv_req; +- +- if (!lp->tt.dns_register) +- lp->tt.dns_register = fc_ns_enter_dns; +- +- if (!lp->tt.disc_stop) +- lp->tt.disc_stop = fc_ns_enter_dns_stop; +- +- return 0; +-} +-EXPORT_SYMBOL(fc_ns_init); +- +-/** +- * fc_ns_gnn_id_req - Send Get Node Name by ID (GNN_ID) request +- * @lp: Fibre Channel host port instance +- * @dp: Temporary discovery port for holding IDs and world wide names +- * +- * The remote port is held by the caller for us. +- */ +-static int fc_ns_gnn_id_req(struct fc_lport *lp, struct fc_ns_port *dp) +-{ +- struct fc_frame *fp; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_fid fid; +- } *cp; +- int error = 0; +- +- fp = fc_frame_alloc(lp, sizeof(*cp)); +- if (fp == NULL) +- return -ENOMEM; +- +- cp = fc_frame_payload_get(fp, sizeof(*cp)); +- fc_ns_fill_dns_hdr(lp, &cp->ct, FC_NS_GNN_ID, sizeof(cp->fid)); +- hton24(cp->fid.fp_fid, dp->ids.port_id); +- +- WARN_ON(!fc_lport_test_ready(lp)); +- +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_ns_gnn_id_resp, +- dp, lp->e_d_tov, +- lp->fid, +- lp->dns_rp->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- error = -ENOMEM; +- +- return error; +-} +- +-/** +- * fc_ns_gnn_id_resp - Handle response to GNN_ID +- * @sp: Current sequence of GNN_ID exchange +- * @fp: response frame +- * @dp_arg: Temporary discovery port for holding IDs and world wide names +- */ +-static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *dp_arg) +-{ +- struct fc_ns_port *dp = dp_arg; +- struct fc_lport *lp; +- struct resp { +- struct fc_ct_hdr ct; +- __be64 wwn; +- } *cp; +- unsigned int cmd; +- +- if (IS_ERR(fp)) { +- fc_ns_gnn_id_error(dp, fp); +- return; +- } +- +- lp = dp->lp; +- WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ +- +- cp = fc_frame_payload_get(fp, sizeof(cp->ct)); +- if (cp == NULL) { +- FC_DBG("GNN_ID response too short, len %d\n", fr_len(fp)); +- return; +- } +- cmd = ntohs(cp->ct.ct_cmd); +- switch (cmd) { +- case FC_FS_ACC: +- cp = fc_frame_payload_get(fp, sizeof(*cp)); +- if (cp == NULL) { +- FC_DBG("GNN_ID response payload too short, len %d\n", +- fr_len(fp)); +- break; +- } +- dp->ids.node_name = ntohll(cp->wwn); +- fc_ns_new_target(lp, NULL, &dp->ids); +- break; +- case FC_FS_RJT: +- fc_ns_restart(lp); +- break; +- default: +- FC_DBG("GNN_ID unexpected CT response cmd %x\n", cmd); +- break; +- } +- kfree(dp); +- fc_frame_free(fp); +-} +- +-/** +- * fc_ns_gnn_id_error - Handle error from GNN_ID +- * @dp: Temporary discovery port for holding IDs and world wide names +- * @fp: response frame +- */ +-static void fc_ns_gnn_id_error(struct fc_ns_port *dp, struct fc_frame *fp) +-{ +- struct fc_lport *lp = dp->lp; +- +- switch (PTR_ERR(fp)) { +- case -FC_EX_TIMEOUT: +- fc_ns_restart(lp); +- break; +- case -FC_EX_CLOSED: +- default: +- break; +- } +- kfree(dp); +-} +- +diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c +index 6d0c970..107b304 100644 +--- a/drivers/scsi/libfc/fc_rport.c ++++ b/drivers/scsi/libfc/fc_rport.c +@@ -36,14 +36,12 @@ + + static int fc_rp_debug; + +-/* +- * static functions. +- */ +-static void fc_rport_enter_start(struct fc_rport *); + static void fc_rport_enter_plogi(struct fc_rport *); + static void fc_rport_enter_prli(struct fc_rport *); + static void fc_rport_enter_rtv(struct fc_rport *); ++static void fc_rport_enter_ready(struct fc_rport *); + static void fc_rport_enter_logo(struct fc_rport *); ++ + static void fc_rport_recv_plogi_req(struct fc_rport *, + struct fc_seq *, struct fc_frame *); + static void fc_rport_recv_prli_req(struct fc_rport *, +@@ -53,9 +51,69 @@ static void fc_rport_recv_prlo_req(struct fc_rport *, + static void fc_rport_recv_logo_req(struct fc_rport *, + struct fc_seq *, struct fc_frame *); + static void fc_rport_timeout(struct work_struct *); ++static void fc_rport_error(struct fc_rport *, struct fc_frame *); ++ ++static const char *fc_rport_state_names[] = { ++ [RPORT_ST_NONE] = "None", ++ [RPORT_ST_INIT] = "Init", ++ [RPORT_ST_PLOGI] = "PLOGI", ++ [RPORT_ST_PRLI] = "PRLI", ++ [RPORT_ST_RTV] = "RTV", ++ [RPORT_ST_READY] = "Ready", ++ [RPORT_ST_LOGO] = "LOGO", ++}; ++ ++struct fc_rport *fc_rport_dummy_create(struct fc_disc_port *dp) ++{ ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata; ++ rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL); + +-static struct fc_rport *fc_remote_port_create(struct fc_lport *, +- struct fc_rport_identifiers *); ++ if (!rport) ++ return NULL; ++ ++ rdata = RPORT_TO_PRIV(rport); ++ ++ rport->dd_data = rdata; ++ rport->port_id = dp->ids.port_id; ++ rport->port_name = dp->ids.port_name; ++ rport->node_name = dp->ids.node_name; ++ rport->roles = dp->ids.roles; ++ rport->maxframe_size = FC_MIN_MAX_PAYLOAD; ++ ++ mutex_init(&rdata->rp_mutex); ++ rdata->local_port = dp->lp; ++ rdata->trans_state = FC_PORTSTATE_ROGUE; ++ rdata->rp_state = RPORT_ST_INIT; ++ rdata->event = LPORT_EV_RPORT_NONE; ++ rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; ++ rdata->event_callback = NULL; ++ rdata->e_d_tov = dp->lp->e_d_tov; ++ rdata->r_a_tov = dp->lp->r_a_tov; ++ INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); ++ ++ return rport; ++} ++ ++void fc_rport_dummy_destroy(struct fc_rport *rport) ++{ ++ kfree(rport); ++} ++ ++/** ++ * fc_rport_state - return a string for the state the rport is in ++ * @rport: The rport whose state we want to get a string for ++ */ ++static const char *fc_rport_state(struct fc_rport *rport) ++{ ++ const char *cp; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ ++ cp = fc_rport_state_names[rdata->rp_state]; ++ if (!cp) ++ cp = "Unknown"; ++ return cp; ++} + + /** + * fc_rport_lookup - lookup a remote port by port_id +@@ -82,48 +140,18 @@ struct fc_rport *fc_rport_lookup(const struct fc_lport *lp, u32 fid) + } + + /** +- * fc_remote_port_create - create a remote port +- * @lp: Fibre Channel host port instance +- * @ids: remote port identifiers (port_id, port_name, and node_name must be set) ++ * fc_set_rport_loss_tmo - Set the remote port loss timeout in seconds. ++ * @rport: Pointer to Fibre Channel remote port structure ++ * @timeout: timeout in seconds + */ +-static struct fc_rport *fc_remote_port_create(struct fc_lport *lp, +- struct fc_rport_identifiers *ids) ++void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) + { +- struct fc_rport_libfc_priv *rp; +- struct fc_rport *rport; +- +- rport = fc_remote_port_add(lp->host, 0, ids); +- if (!rport) +- return NULL; +- +- rp = rport->dd_data; +- rp->local_port = lp; +- +- /* default value until service parameters are exchanged in PLOGI */ +- rport->maxframe_size = FC_MIN_MAX_PAYLOAD; +- +- spin_lock_init(&rp->rp_lock); +- rp->rp_state = RPORT_ST_INIT; +- rp->local_port = lp; +- rp->e_d_tov = lp->e_d_tov; +- rp->r_a_tov = lp->r_a_tov; +- rp->flags = FC_RP_FLAGS_REC_SUPPORTED; +- INIT_DELAYED_WORK(&rp->retry_work, fc_rport_timeout); +- +- return rport; +-} +- +-static inline void fc_rport_lock(struct fc_rport *rport) +-{ +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- spin_lock_bh(&rp->rp_lock); +-} +- +-static inline void fc_rport_unlock(struct fc_rport *rport) +-{ +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- spin_unlock_bh(&rp->rp_lock); ++ if (timeout) ++ rport->dev_loss_tmo = timeout + 5; ++ else ++ rport->dev_loss_tmo = 30; + } ++EXPORT_SYMBOL(fc_set_rport_loss_tmo); + + /** + * fc_plogi_get_maxframe - Get max payload from the common service parameters +@@ -150,12 +178,12 @@ fc_plogi_get_maxframe(struct fc_els_flogi *flp, unsigned int maxval) + + /** + * fc_lport_plogi_fill - Fill in PLOGI command for request +- * @lp: Fibre Channel host port instance ++ * @lport: Fibre Channel host port instance + * @plogi: PLOGI command structure to fill (same structure as FLOGI) + * @op: either ELS_PLOGI for a localy generated request, or ELS_LS_ACC + */ + static void +-fc_lport_plogi_fill(struct fc_lport *lp, ++fc_lport_plogi_fill(struct fc_lport *lport, + struct fc_els_flogi *plogi, unsigned int op) + { + struct fc_els_csp *sp; +@@ -163,266 +191,241 @@ fc_lport_plogi_fill(struct fc_lport *lp, + + memset(plogi, 0, sizeof(*plogi)); + plogi->fl_cmd = (u8) op; +- put_unaligned_be64(lp->wwpn, &plogi->fl_wwpn); +- put_unaligned_be64(lp->wwnn, &plogi->fl_wwnn); ++ put_unaligned_be64(lport->wwpn, &plogi->fl_wwpn); ++ put_unaligned_be64(lport->wwnn, &plogi->fl_wwnn); + + sp = &plogi->fl_csp; + sp->sp_hi_ver = 0x20; + sp->sp_lo_ver = 0x20; + sp->sp_bb_cred = htons(10); /* this gets set by gateway */ +- sp->sp_bb_data = htons((u16) lp->mfs); ++ sp->sp_bb_data = htons((u16) lport->mfs); + cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */ + cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); + if (op != ELS_FLOGI) { + sp->sp_features = htons(FC_SP_FT_CIRO); + sp->sp_tot_seq = htons(255); /* seq. we accept */ + sp->sp_rel_off = htons(0x1f); +- sp->sp_e_d_tov = htonl(lp->e_d_tov); ++ sp->sp_e_d_tov = htonl(lport->e_d_tov); + +- cp->cp_rdfs = htons((u16) lp->mfs); ++ cp->cp_rdfs = htons((u16) lport->mfs); + cp->cp_con_seq = htons(255); + cp->cp_open_seq = 1; + } + } + ++/** ++ * fc_rport_state_enter - Change the rport's state ++ * @rport: The rport whose state should change ++ * @new: The new state of the rport ++ * ++ * Locking Note: Called with the rport lock held ++ */ + static void fc_rport_state_enter(struct fc_rport *rport, + enum fc_rport_state new) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- if (rp->rp_state != new) +- rp->retries = 0; +- rp->rp_state = new; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ if (rdata->rp_state != new) ++ rdata->retries = 0; ++ rdata->rp_state = new; ++} ++ ++static void fc_rport_unlock(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ enum fc_lport_event event = rdata->event; ++ struct fc_lport *lport = rdata->local_port; ++ u32 fid = rport->port_id; ++ void (*event_callback)(struct fc_lport *, u32, ++ enum fc_lport_event) = ++ rdata->event_callback; ++ ++ if (event == LPORT_EV_RPORT_CREATED) { ++ struct fc_rport *new_rport; ++ struct fc_rport_libfc_priv *new_rdata; ++ struct fc_rport_identifiers ids; ++ ++ ids.port_id = rport->port_id; ++ ids.roles = rport->roles; ++ ids.port_name = rport->port_name; ++ ids.node_name = rport->node_name; ++ ++ new_rport = fc_remote_port_add(lport->host, 0, &ids); ++ if (new_rport) { ++ /* ++ * Switch from the dummy rport to the rport ++ * returned by the FC class. ++ */ ++ new_rport->maxframe_size = rport->maxframe_size; ++ ++ new_rdata = new_rport->dd_data; ++ new_rdata->e_d_tov = rdata->e_d_tov; ++ new_rdata->r_a_tov = rdata->r_a_tov; ++ new_rdata->event_callback = rdata->event_callback; ++ new_rdata->local_port = rdata->local_port; ++ new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; ++ new_rdata->trans_state = FC_PORTSTATE_REAL; ++ mutex_init(&new_rdata->rp_mutex); ++ INIT_DELAYED_WORK(&new_rdata->retry_work, ++ fc_rport_timeout); ++ ++ fc_rport_state_enter(new_rport, RPORT_ST_READY); ++ fc_remote_port_rolechg(new_rport, rdata->roles); ++ } else { ++ FC_DBG("Failed to create the rport for port " ++ "(%6x).\n", ids.port_id); ++ event = LPORT_EV_RPORT_FAILED; ++ } ++ ++ mutex_unlock(&rdata->rp_mutex); ++ fc_rport_dummy_destroy(rport); ++ rport = new_rport; ++ rdata = new_rport->dd_data; ++ } else if ((event == LPORT_EV_RPORT_FAILED) || ++ (event == LPORT_EV_RPORT_LOGO)) { ++ if (rdata->trans_state == FC_PORTSTATE_ROGUE) { ++ mutex_unlock(&rdata->rp_mutex); ++ fc_rport_dummy_destroy(rport); ++ } else { ++ mutex_unlock(&rdata->rp_mutex); ++ fc_remote_port_delete(rport); ++ } ++ } else { ++ mutex_unlock(&rdata->rp_mutex); ++ } ++ ++ if (event != LPORT_EV_RPORT_NONE && event_callback) { ++ event_callback(lport, fid, event); ++ rdata->event = LPORT_EV_RPORT_NONE; ++ } + } + + /** + * fc_rport_login - Start the remote port login state machine + * @rport: Fibre Channel remote port ++ * ++ * Locking Note: Called without the rport lock held. This ++ * function will hold the rport lock, call an _enter_* ++ * function and then unlock the rport. + */ + int fc_rport_login(struct fc_rport *rport) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + +- fc_rport_lock(rport); +- if (rp->rp_state == RPORT_ST_INIT) { +- fc_rport_unlock(rport); +- fc_rport_enter_start(rport); +- } else if (rp->rp_state == RPORT_ST_ERROR) { +- fc_rport_state_enter(rport, RPORT_ST_INIT); +- fc_rport_unlock(rport); +- if (fc_rp_debug) +- FC_DBG("remote %6x closed\n", rport->port_id); +- +- if (rport == lp->dns_rp && +- lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } +- } else +- fc_rport_unlock(rport); ++ mutex_lock(&rdata->rp_mutex); ++ ++ if (fc_rp_debug) ++ FC_DBG("Login to port (%6x)\n", rport->port_id); ++ ++ fc_rport_enter_plogi(rport); ++ ++ fc_rport_unlock(rport); + + return 0; + } + +-/* +- * Stop the session - log it off. ++/** ++ * fc_rport_logout - Logout of the remote port and delete it ++ * @rport: Fibre Channel remote port ++ * ++ * Locking Note: Called without the rport lock held. This ++ * function will hold the rport lock, call an _enter_* ++ * function and then unlock the rport. + */ + int fc_rport_logout(struct fc_rport *rport) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + +- fc_rport_lock(rport); +- switch (rp->rp_state) { +- case RPORT_ST_PRLI: +- case RPORT_ST_RTV: +- case RPORT_ST_READY: +- fc_rport_enter_logo(rport); +- fc_rport_unlock(rport); +- break; +- default: +- fc_rport_state_enter(rport, RPORT_ST_INIT); +- fc_rport_unlock(rport); +- if (fc_rp_debug) +- FC_DBG("remote %6x closed\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } ++ mutex_lock(&rdata->rp_mutex); + +- fc_remote_port_delete(rport); +- } +- break; +- } ++ if (fc_rp_debug) ++ FC_DBG("Logout of port (%6x)\n", rport->port_id); ++ ++ fc_rport_enter_logo(rport); ++ fc_rport_unlock(rport); + + return 0; + } + +-/* +- * Reset the session - assume it is logged off. Used after fabric logoff. +- * The local port code takes care of resetting the exchange manager. ++/** ++ * fc_rport_reset - Reset the remote port ++ * @rport: Fibre Channel remote port ++ * ++ * XXX - This functionality is currently broken ++ * ++ * Locking Note: Called without the rport lock held. This ++ * function will hold the rport lock, call an _enter_* ++ * function and then unlock the rport. + */ + void fc_rport_reset(struct fc_rport *rport) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ ++ mutex_lock(&rdata->rp_mutex); + + if (fc_rp_debug) +- FC_DBG("sess to %6x reset\n", rport->port_id); +- fc_rport_lock(rport); ++ FC_DBG("Reset port (%6x)\n", rport->port_id); + +- lp = rp->local_port; +- fc_rport_state_enter(rport, RPORT_ST_INIT); +- fc_rport_unlock(rport); ++ fc_rport_enter_plogi(rport); + +- if (fc_rp_debug) +- FC_DBG("remote %6x closed\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } ++ fc_rport_unlock(rport); + } + +-/* +- * Reset all sessions for a local port session list. ++/** ++ * fc_rport_reset_list - Reset all sessions for a local port session list. ++ * @lport: The lport whose rports should be reset ++ * ++ * Locking Note: TBD + */ +-void fc_rport_reset_list(struct fc_lport *lp) ++void fc_rport_reset_list(struct fc_lport *lport) + { +- struct Scsi_Host *shost = lp->host; ++ struct Scsi_Host *shost = lport->host; + struct fc_rport *rport; + struct fc_rport *next; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + list_for_each_entry_safe(rport, next, &fc_host_rports(shost), peers) { +- lp->tt.rport_reset(rport); ++ lport->tt.rport_reset(rport); + } + spin_unlock_irqrestore(shost->host_lock, flags); + } + +-static void fc_rport_enter_start(struct fc_rport *rport) ++/** ++ * fc_rport_enter_ready - The rport is ready ++ * @rport: Fibre Channel remote port that is ready ++ * ++ * Locking Note: The rport lock is expected to be held before calling ++ * this routine. ++ */ ++static void fc_rport_enter_ready(struct fc_rport *rport) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + +- /* +- * If the local port is already logged on, advance to next state. +- * Otherwise the local port will be logged on by fc_rport_unlock(). +- */ +- fc_rport_state_enter(rport, RPORT_ST_STARTED); ++ fc_rport_state_enter(rport, RPORT_ST_READY); + +- if (rport == lp->dns_rp || fc_lport_test_ready(lp)) +- fc_rport_enter_plogi(rport); +-} ++ if (fc_rp_debug) ++ FC_DBG("Port (%6x) is Ready\n", rport->port_id); + +-/* +- * Handle exchange reject or retry exhaustion in various states. +- */ +-static void fc_rport_reject(struct fc_rport *rport) +-{ +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; +- switch (rp->rp_state) { +- case RPORT_ST_PLOGI: +- case RPORT_ST_PRLI: +- fc_rport_state_enter(rport, RPORT_ST_ERROR); +- if (rport == lp->dns_rp && +- lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } +- break; +- case RPORT_ST_RTV: +- fc_rport_state_enter(rport, RPORT_ST_READY); +- if (fc_rp_debug) +- FC_DBG("remote %6x ready\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state == LPORT_ST_DNS) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->tt.dns_register(lp); +- fc_lport_unlock(lp); +- } +- break; +- case RPORT_ST_LOGO: +- fc_rport_state_enter(rport, RPORT_ST_INIT); +- if (fc_rp_debug) +- FC_DBG("remote %6x closed\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } +- break; +- case RPORT_ST_NONE: +- case RPORT_ST_READY: +- case RPORT_ST_ERROR: +- case RPORT_ST_PLOGI_RECV: +- case RPORT_ST_STARTED: +- case RPORT_ST_INIT: +- BUG(); +- break; +- } +- return; ++ rdata->event = LPORT_EV_RPORT_CREATED; + } + +-/* +- * Timeout handler for retrying after allocation failures or exchange timeout. ++/** ++ * fc_rport_timeout - Handler for the retry_work timer. ++ * @work: The work struct of the fc_rport_libfc_priv ++ * ++ * Locking Note: Called without the rport lock held. This ++ * function will hold the rport lock, call an _enter_* ++ * function and then unlock the rport. + */ + static void fc_rport_timeout(struct work_struct *work) + { +- struct fc_rport_libfc_priv *rp = ++ struct fc_rport_libfc_priv *rdata = + container_of(work, struct fc_rport_libfc_priv, retry_work.work); +- struct fc_rport *rport = (((void *)rp) - sizeof(struct fc_rport)); ++ struct fc_rport *rport = PRIV_TO_RPORT(rdata); + +- switch (rp->rp_state) { ++ mutex_lock(&rdata->rp_mutex); ++ ++ switch (rdata->rp_state) { + case RPORT_ST_PLOGI: + fc_rport_enter_plogi(rport); + break; +@@ -436,149 +439,178 @@ static void fc_rport_timeout(struct work_struct *work) + fc_rport_enter_logo(rport); + break; + case RPORT_ST_READY: +- case RPORT_ST_ERROR: + case RPORT_ST_INIT: + break; + case RPORT_ST_NONE: +- case RPORT_ST_PLOGI_RECV: +- case RPORT_ST_STARTED: + BUG(); + break; + } + put_device(&rport->dev); +-} +- +-/* +- * Handle retry for allocation failure via timeout. +- */ +-static void fc_rport_retry(struct fc_rport *rport) +-{ +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; + +- if (rp->retries < lp->max_retry_count) { +- rp->retries++; +- get_device(&rport->dev); +- schedule_delayed_work(&rp->retry_work, +- msecs_to_jiffies(rp->e_d_tov)); +- } else { +- FC_DBG("sess %6x alloc failure in state %d, " +- "retries exhausted\n", +- rport->port_id, rp->rp_state); +- fc_rport_reject(rport); +- } ++ fc_rport_unlock(rport); + } + +-/* +- * Handle error from a sequence issued by the rport state machine. ++/** ++ * fc_rport_error - Handler for any errors ++ * @rport: The fc_rport object ++ * @fp: The frame pointer ++ * ++ * If the error was caused by a resource allocation failure ++ * then wait for half a second and retry, otherwise retry ++ * immediately. ++ * ++ * Locking Note: The rport lock is expected to be held before ++ * calling this routine + */ + static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- fc_rport_lock(rport); ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ unsigned long delay = 0; ++ + if (fc_rp_debug) +- FC_DBG("state %d error %ld retries %d\n", +- rp->rp_state, PTR_ERR(fp), rp->retries); ++ FC_DBG("Error %ld in state %s, retries %d\n", ++ PTR_ERR(fp), fc_rport_state(rport), rdata->retries); + +- if (PTR_ERR(fp) == -FC_EX_TIMEOUT && +- rp->retries++ >= rp->local_port->max_retry_count) { ++ if (rdata->retries < rdata->local_port->max_retry_count) { ++ rdata->retries++; ++ if (!fp) ++ delay = msecs_to_jiffies(500); + get_device(&rport->dev); +- schedule_delayed_work(&rp->retry_work, 0); +- } else +- fc_rport_reject(rport); ++ schedule_delayed_work(&rdata->retry_work, delay); ++ } else { ++ switch (rdata->rp_state) { ++ case RPORT_ST_PLOGI: ++ case RPORT_ST_PRLI: ++ case RPORT_ST_LOGO: ++ if (fc_rp_debug) ++ FC_DBG("Remote port (%6x) closed.\n", ++ rport->port_id); + +- fc_rport_unlock(rport); ++ fc_remote_port_delete(rport); ++ ++ rdata->event = LPORT_EV_RPORT_FAILED; ++ break; ++ case RPORT_ST_RTV: ++ fc_rport_enter_ready(rport); ++ break; ++ case RPORT_ST_NONE: ++ case RPORT_ST_READY: ++ case RPORT_ST_INIT: ++ BUG(); ++ break; ++ } ++ } + } + + /** +- * fc_rport_plpogi_recv_resp - Handle incoming ELS PLOGI response ++ * fc_rport_plogi_recv_resp - Handle incoming ELS PLOGI response + * @sp: current sequence in the PLOGI exchange + * @fp: response frame + * @rp_arg: Fibre Channel remote port ++ * ++ * Locking Note: This function will be called without the rport lock ++ * held, but it will lock, call an _enter_* function or fc_rport_error ++ * and then unlock the rport. + */ + static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) + { +- struct fc_els_ls_rjt *rjp; ++ struct fc_rport *rport = rp_arg; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + struct fc_els_flogi *plp; +- u64 wwpn, wwnn; + unsigned int tov; + u16 csp_seq; + u16 cssp_seq; + u8 op; +- struct fc_rport *rport = rp_arg; +- struct fc_rport_libfc_priv *rp = rport->dd_data; + +- if (!IS_ERR(fp)) { +- op = fc_frame_payload_op(fp); +- fc_rport_lock(rport); +- if (op == ELS_LS_ACC && +- (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { +- wwpn = get_unaligned_be64(&plp->fl_wwpn); +- wwnn = get_unaligned_be64(&plp->fl_wwnn); ++ mutex_lock(&rdata->rp_mutex); + +- fc_rport_set_name(rport, wwpn, wwnn); +- tov = ntohl(plp->fl_csp.sp_e_d_tov); +- if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) +- tov /= 1000; +- if (tov > rp->e_d_tov) +- rp->e_d_tov = tov; +- csp_seq = ntohs(plp->fl_csp.sp_tot_seq); +- cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); +- if (cssp_seq < csp_seq) +- csp_seq = cssp_seq; +- rp->max_seq = csp_seq; +- rport->maxframe_size = +- fc_plogi_get_maxframe(plp, rp->local_port->mfs); +- if (rp->rp_state == RPORT_ST_PLOGI) +- fc_rport_enter_prli(rport); +- } else { +- if (fc_rp_debug) +- FC_DBG("bad PLOGI response\n"); +- +- rjp = fc_frame_payload_get(fp, sizeof(*rjp)); +- if (op == ELS_LS_RJT && rjp != NULL && +- rjp->er_reason == ELS_RJT_INPROG) +- fc_rport_retry(rport); /* try again */ +- else +- fc_rport_reject(rport); /* error */ +- } +- fc_rport_unlock(rport); +- fc_frame_free(fp); +- } else { ++ if (fc_rp_debug) ++ FC_DBG("Received a PLOGI response\n"); ++ ++ if (rdata->rp_state != RPORT_ST_PLOGI) { ++ FC_DBG("Received a PLOGI response, but in state %s\n", ++ fc_rport_state(rport)); ++ goto out; ++ } ++ ++ if (IS_ERR(fp)) { + fc_rport_error(rport, fp); ++ goto out; + } ++ ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC && ++ (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { ++ tov = ntohl(plp->fl_csp.sp_e_d_tov); ++ if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) ++ tov /= 1000; ++ if (tov > rdata->e_d_tov) ++ rdata->e_d_tov = tov; ++ csp_seq = ntohs(plp->fl_csp.sp_tot_seq); ++ cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); ++ if (cssp_seq < csp_seq) ++ csp_seq = cssp_seq; ++ rdata->max_seq = csp_seq; ++ rport->maxframe_size = ++ fc_plogi_get_maxframe(plp, lport->mfs); ++ ++ /* ++ * If the rport is one of the well known addresses ++ * we skip PRLI and RTV and go straight to READY. ++ */ ++ if (rport->port_id >= FC_FID_DOM_MGR) ++ fc_rport_enter_ready(rport); ++ else ++ fc_rport_enter_prli(rport); ++ } else ++ fc_rport_error(rport, fp); ++ ++out: ++ fc_rport_unlock(rport); ++ fc_frame_free(fp); + } + + /** + * fc_rport_enter_plogi - Send Port Login (PLOGI) request to peer + * @rport: Fibre Channel remote port to send PLOGI to ++ * ++ * Locking Note: The rport lock is expected to be held before calling ++ * this routine. + */ + static void fc_rport_enter_plogi(struct fc_rport *rport) + { ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + struct fc_els_flogi *plogi; +- struct fc_lport *lp; +- struct fc_rport_libfc_priv *rp = rport->dd_data; + +- lp = rp->local_port; ++ if (fc_rp_debug) ++ FC_DBG("Port (%6x) entered PLOGI state from %s state\n", ++ rport->port_id, fc_rport_state(rport)); ++ + fc_rport_state_enter(rport, RPORT_ST_PLOGI); ++ + rport->maxframe_size = FC_MIN_MAX_PAYLOAD; +- fp = fc_frame_alloc(lp, sizeof(*plogi)); +- if (!fp) +- return fc_rport_retry(rport); ++ fp = fc_frame_alloc(lport, sizeof(*plogi)); ++ if (!fp) { ++ fc_rport_error(rport, fp); ++ return; ++ } ++ + plogi = fc_frame_payload_get(fp, sizeof(*plogi)); +- WARN_ON(!plogi); +- fc_lport_plogi_fill(rp->local_port, plogi, ELS_PLOGI); +- rp->e_d_tov = lp->e_d_tov; ++ fc_lport_plogi_fill(rdata->local_port, plogi, ELS_PLOGI); ++ rdata->e_d_tov = lport->e_d_tov; + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_rport_plogi_resp, +- rport, lp->e_d_tov, +- rp->local_port->fid, +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- fc_rport_retry(rport); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_rport_plogi_resp, NULL, ++ rport, lport->e_d_tov, ++ rdata->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_error(rport, fp); + } + + /** +@@ -586,13 +618,16 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) + * @sp: current sequence in the PRLI exchange + * @fp: response frame + * @rp_arg: Fibre Channel remote port ++ * ++ * Locking Note: This function will be called without the rport lock ++ * held, but it will lock, call an _enter_* function or fc_rport_error ++ * and then unlock the rport. + */ + static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) + { + struct fc_rport *rport = rp_arg; +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct { + struct fc_els_prli prli; + struct fc_els_spp spp; +@@ -601,19 +636,29 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + u32 fcp_parm = 0; + u8 op; + ++ mutex_lock(&rdata->rp_mutex); ++ ++ if (fc_rp_debug) ++ FC_DBG("Received a PRLI response\n"); ++ ++ if (rdata->rp_state != RPORT_ST_PRLI) { ++ FC_DBG("Received a PRLI response, but in state %s\n", ++ fc_rport_state(rport)); ++ goto out; ++ } ++ + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- return; ++ goto out; + } + +- fc_rport_lock(rport); + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC) { + pp = fc_frame_payload_get(fp, sizeof(*pp)); + if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) { + fcp_parm = ntohl(pp->spp.spp_params); + if (fcp_parm & FCP_SPPF_RETRY) +- rp->flags |= FC_RP_FLAGS_RETRY; ++ rdata->flags |= FC_RP_FLAGS_RETRY; + } + + rport->supported_classes = FC_COS_CLASS3; +@@ -622,28 +667,17 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + if (fcp_parm & FCP_SPPF_TARG_FCN) + roles |= FC_RPORT_ROLE_FCP_TARGET; + ++ rdata->roles = roles; + fc_rport_enter_rtv(rport); +- fc_rport_unlock(rport); +- fc_remote_port_rolechg(rport, roles); ++ + } else { +- FC_DBG("bad ELS response\n"); +- fc_rport_state_enter(rport, RPORT_ST_ERROR); +- fc_rport_unlock(rport); +- if (rport == lp->dns_rp && lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } ++ FC_DBG("Bad ELS response\n"); ++ rdata->event = LPORT_EV_RPORT_FAILED; ++ fc_remote_port_delete(rport); + } + ++out: ++ fc_rport_unlock(rport); + fc_frame_free(fp); + } + +@@ -652,101 +686,94 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + * @sp: current sequence in the LOGO exchange + * @fp: response frame + * @rp_arg: Fibre Channel remote port ++ * ++ * Locking Note: This function will be called without the rport lock ++ * held, but it will lock, call an _enter_* function or fc_rport_error ++ * and then unlock the rport. + */ + static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) + { + struct fc_rport *rport = rp_arg; +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + u8 op; + ++ mutex_lock(&rdata->rp_mutex); ++ ++ if (fc_rp_debug) ++ FC_DBG("Received a LOGO response\n"); ++ ++ if (rdata->rp_state != RPORT_ST_LOGO) { ++ FC_DBG("Received a LOGO response, but in state %s\n", ++ fc_rport_state(rport)); ++ goto out; ++ } ++ + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- return; ++ goto out; + } + +- fc_rport_lock(rport); + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC) { + fc_rport_enter_rtv(rport); +- fc_rport_unlock(rport); ++ + } else { +- FC_DBG("bad ELS response\n"); +- fc_rport_state_enter(rport, RPORT_ST_ERROR); +- fc_rport_unlock(rport); +- if (rport == lp->dns_rp && lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } ++ FC_DBG("Bad ELS response\n"); ++ rdata->event = LPORT_EV_RPORT_LOGO; ++ fc_remote_port_delete(rport); + } + ++out: ++ fc_rport_unlock(rport); + fc_frame_free(fp); + } + + /** + * fc_rport_enter_prli - Send Process Login (PRLI) request to peer + * @rport: Fibre Channel remote port to send PRLI to ++ * ++ * Locking Note: The rport lock is expected to be held before calling ++ * this routine. + */ + static void fc_rport_enter_prli(struct fc_rport *rport) + { ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + struct { + struct fc_els_prli prli; + struct fc_els_spp spp; + } *pp; + struct fc_frame *fp; +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ ++ if (fc_rp_debug) ++ FC_DBG("Port (%6x) entered PRLI state from %s state\n", ++ rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_PRLI); + +- /* +- * Special case if session is for name server or any other +- * well-known address: Skip the PRLI step. +- * This should be made more general, possibly moved to the FCP layer. +- */ +- if (rport->port_id >= FC_FID_DOM_MGR) { +- fc_rport_state_enter(rport, RPORT_ST_READY); +- if (fc_rp_debug) +- FC_DBG("remote %6x ready\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state == LPORT_ST_DNS) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->tt.dns_register(lp); +- fc_lport_unlock(lp); +- } ++ fp = fc_frame_alloc(lport, sizeof(*pp)); ++ if (!fp) { ++ fc_rport_error(rport, fp); + return; + } +- fp = fc_frame_alloc(lp, sizeof(*pp)); +- if (!fp) +- return fc_rport_retry(rport); ++ + pp = fc_frame_payload_get(fp, sizeof(*pp)); +- WARN_ON(!pp); + memset(pp, 0, sizeof(*pp)); + pp->prli.prli_cmd = ELS_PRLI; + pp->prli.prli_spp_len = sizeof(struct fc_els_spp); + pp->prli.prli_len = htons(sizeof(*pp)); + pp->spp.spp_type = FC_TYPE_FCP; + pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR; +- pp->spp.spp_params = htonl(rp->local_port->service_params); ++ pp->spp.spp_params = htonl(lport->service_params); + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_rport_prli_resp, +- rport, lp->e_d_tov, +- rp->local_port->fid, +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- fc_rport_retry(rport); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_rport_prli_resp, NULL, ++ rport, lport->e_d_tov, ++ lport->fid, rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_error(rport, fp); + } + + /** +@@ -756,21 +783,34 @@ static void fc_rport_enter_prli(struct fc_rport *rport) + * @rp_arg: Fibre Channel remote port + * + * Many targets don't seem to support this. ++ * ++ * Locking Note: This function will be called without the rport lock ++ * held, but it will lock, call an _enter_* function or fc_rport_error ++ * and then unlock the rport. + */ + static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) + { + struct fc_rport *rport = rp_arg; +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + u8 op; + ++ mutex_lock(&rdata->rp_mutex); ++ ++ if (fc_rp_debug) ++ FC_DBG("Received a RTV response\n"); ++ ++ if (rdata->rp_state != RPORT_ST_RTV) { ++ FC_DBG("Received a RTV response, but in state %s\n", ++ fc_rport_state(rport)); ++ goto out; ++ } ++ + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- return; ++ goto out; + } + +- fc_rport_lock(rport); + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC) { + struct fc_els_rtv_acc *rtv; +@@ -783,107 +823,126 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, + tov = ntohl(rtv->rtv_r_a_tov); + if (tov == 0) + tov = 1; +- rp->r_a_tov = tov; ++ rdata->r_a_tov = tov; + tov = ntohl(rtv->rtv_e_d_tov); + if (toq & FC_ELS_RTV_EDRES) + tov /= 1000000; + if (tov == 0) + tov = 1; +- rp->e_d_tov = tov; ++ rdata->e_d_tov = tov; + } + } +- fc_rport_state_enter(rport, RPORT_ST_READY); ++ ++ fc_rport_enter_ready(rport); ++ ++out: + fc_rport_unlock(rport); +- if (fc_rp_debug) +- FC_DBG("remote %6x ready\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state == LPORT_ST_DNS) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->tt.dns_register(lp); +- fc_lport_unlock(lp); +- } + fc_frame_free(fp); + } + + /** + * fc_rport_enter_rtv - Send Request Timeout Value (RTV) request to peer + * @rport: Fibre Channel remote port to send RTV to ++ * ++ * Locking Note: The rport lock is expected to be held before calling ++ * this routine. + */ + static void fc_rport_enter_rtv(struct fc_rport *rport) + { + struct fc_els_rtv *rtv; + struct fc_frame *fp; +- struct fc_lport *lp; +- struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; ++ ++ if (fc_rp_debug) ++ FC_DBG("Port (%6x) entered RTV state from %s state\n", ++ rport->port_id, fc_rport_state(rport)); + +- lp = rp->local_port; + fc_rport_state_enter(rport, RPORT_ST_RTV); + +- fp = fc_frame_alloc(lp, sizeof(*rtv)); +- if (!fp) +- return fc_rport_retry(rport); ++ fp = fc_frame_alloc(lport, sizeof(*rtv)); ++ if (!fp) { ++ fc_rport_error(rport, fp); ++ return; ++ } ++ + rtv = fc_frame_payload_get(fp, sizeof(*rtv)); +- WARN_ON(!rtv); + memset(rtv, 0, sizeof(*rtv)); + rtv->rtv_cmd = ELS_RTV; + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_rport_rtv_resp, +- rport, lp->e_d_tov, +- rp->local_port->fid, +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- fc_rport_retry(rport); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_rport_rtv_resp, NULL, ++ rport, lport->e_d_tov, ++ lport->fid, rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_error(rport, fp); + } + + /** + * fc_rport_enter_logo - Send Logout (LOGO) request to peer + * @rport: Fibre Channel remote port to send LOGO to ++ * ++ * Locking Note: The rport lock is expected to be held before calling ++ * this routine. + */ + static void fc_rport_enter_logo(struct fc_rport *rport) + { ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + struct fc_els_logo *logo; +- struct fc_lport *lp; +- struct fc_rport_libfc_priv *rp = rport->dd_data; ++ ++ if (fc_rp_debug) ++ FC_DBG("Port (%6x) entered LOGO state from %s state\n", ++ rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_LOGO); + +- lp = rp->local_port; +- fp = fc_frame_alloc(lp, sizeof(*logo)); +- if (!fp) +- return fc_rport_retry(rport); ++ fp = fc_frame_alloc(lport, sizeof(*logo)); ++ if (!fp) { ++ fc_rport_error(rport, fp); ++ return; ++ } ++ + logo = fc_frame_payload_get(fp, sizeof(*logo)); + memset(logo, 0, sizeof(*logo)); + logo->fl_cmd = ELS_LOGO; +- hton24(logo->fl_n_port_id, lp->fid); +- logo->fl_n_port_wwn = htonll(lp->wwpn); +- ++ hton24(logo->fl_n_port_id, lport->fid); ++ logo->fl_n_port_wwn = htonll(lport->wwpn); + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- if (!lp->tt.exch_seq_send(lp, fp, +- fc_rport_logo_resp, +- rport, lp->e_d_tov, +- rp->local_port->fid, +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) +- fc_rport_retry(rport); ++ ++ if (!lport->tt.exch_seq_send(lport, fp, ++ fc_rport_logo_resp, NULL, ++ rport, lport->e_d_tov, ++ lport->fid, rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_error(rport, fp); + } + +-/* +- * Handle a request received by the exchange manager for the session. +- * This may be an entirely new session, or a PLOGI or LOGO for an existing one. +- * This will free the frame. ++ ++/** ++ * fc_rport_recv_req - Receive a request from a rport ++ * @sp: current sequence in the PLOGI exchange ++ * @fp: response frame ++ * @rp_arg: Fibre Channel remote port ++ * ++ * Locking Note: Called without the rport lock held. This ++ * function will hold the rport lock, call an _enter_* ++ * function and then unlock the rport. + */ + void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, + struct fc_rport *rport) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; ++ + struct fc_frame_header *fh; +- struct fc_lport *lp = rp->local_port; + struct fc_seq_els_data els_data; + u8 op; + ++ mutex_lock(&rdata->rp_mutex); ++ + els_data.fp = NULL; + els_data.explan = ELS_EXPL_NONE; + els_data.reason = ELS_RJT_NONE; +@@ -907,21 +966,21 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, + break; + case ELS_RRQ: + els_data.fp = fp; +- lp->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); + break; + case ELS_REC: + els_data.fp = fp; +- lp->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); + break; + default: + els_data.reason = ELS_RJT_UNSUP; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); +- fc_frame_free(fp); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + break; + } +- } else { +- fc_frame_free(fp); + } ++ ++ fc_rport_unlock(rport); ++ fc_frame_free(fp); + } + + /** +@@ -929,14 +988,18 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, + * @rport: Fibre Channel remote port that initiated PLOGI + * @sp: current sequence in the PLOGI exchange + * @fp: PLOGI request frame ++ * ++ * Locking Note: The rport lock is exected to be held before calling ++ * this function. + */ + static void fc_rport_recv_plogi_req(struct fc_rport *rport, + struct fc_seq *sp, struct fc_frame *rx_fp) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp = rx_fp; ++ + struct fc_frame_header *fh; +- struct fc_lport *lp; + struct fc_els_flogi *pl; + struct fc_seq_els_data rjt_data; + u32 sid; +@@ -944,9 +1007,15 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + u64 wwnn; + enum fc_els_rjt_reason reject = 0; + u32 f_ctl; +- + rjt_data.fp = NULL; ++ + fh = fc_frame_header_get(fp); ++ ++ if (fc_rp_debug) ++ FC_DBG("Received PLOGI request from port (%6x) " ++ "while in state %s\n", ntoh24(fh->fh_s_id), ++ fc_rport_state(rport)); ++ + sid = ntoh24(fh->fh_s_id); + pl = fc_frame_payload_get(fp, sizeof(*pl)); + if (!pl) { +@@ -958,8 +1027,6 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + } + wwpn = get_unaligned_be64(&pl->fl_wwpn); + wwnn = get_unaligned_be64(&pl->fl_wwnn); +- fc_rport_lock(rport); +- lp = rp->local_port; + + /* + * If the session was just created, possibly due to the incoming PLOGI, +@@ -972,63 +1039,50 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + * XXX TBD: If the session was ready before, the PLOGI should result in + * all outstanding exchanges being reset. + */ +- switch (rp->rp_state) { ++ switch (rdata->rp_state) { + case RPORT_ST_INIT: + if (fc_rp_debug) + FC_DBG("incoming PLOGI from %6x wwpn %llx state INIT " + "- reject\n", sid, wwpn); + reject = ELS_RJT_UNSUP; + break; +- case RPORT_ST_STARTED: +- /* +- * we'll only accept a login if the port name +- * matches or was unknown. +- */ +- if (rport->port_name != -1 && +- rport->port_name != wwpn) { +- FC_DBG("incoming PLOGI from name %llx expected %llx\n", +- wwpn, rport->port_name); +- reject = ELS_RJT_UNAB; +- } +- break; + case RPORT_ST_PLOGI: + if (fc_rp_debug) + FC_DBG("incoming PLOGI from %x in PLOGI state %d\n", +- sid, rp->rp_state); +- if (wwpn < lp->wwpn) ++ sid, rdata->rp_state); ++ if (wwpn < lport->wwpn) + reject = ELS_RJT_INPROG; + break; + case RPORT_ST_PRLI: +- case RPORT_ST_ERROR: + case RPORT_ST_READY: + if (fc_rp_debug) + FC_DBG("incoming PLOGI from %x in logged-in state %d " +- "- ignored for now\n", sid, rp->rp_state); ++ "- ignored for now\n", sid, rdata->rp_state); + /* XXX TBD - should reset */ + break; + case RPORT_ST_NONE: + default: + if (fc_rp_debug) + FC_DBG("incoming PLOGI from %x in unexpected " +- "state %d\n", sid, rp->rp_state); ++ "state %d\n", sid, rdata->rp_state); + break; + } + + if (reject) { + rjt_data.reason = reject; + rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); + } else { +- fp = fc_frame_alloc(lp, sizeof(*pl)); ++ fp = fc_frame_alloc(lport, sizeof(*pl)); + if (fp == NULL) { + fp = rx_fp; + rjt_data.reason = ELS_RJT_UNAB; + rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); + } else { +- sp = lp->tt.seq_start_next(sp); ++ sp = lport->tt.seq_start_next(sp); + WARN_ON(!sp); + fc_rport_set_name(rport, wwpn, wwnn); + +@@ -1036,11 +1090,11 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + * Get session payload size from incoming PLOGI. + */ + rport->maxframe_size = +- fc_plogi_get_maxframe(pl, lp->mfs); ++ fc_plogi_get_maxframe(pl, lport->mfs); + fc_frame_free(rx_fp); + pl = fc_frame_payload_get(fp, sizeof(*pl)); + WARN_ON(!pl); +- fc_lport_plogi_fill(lp, pl, ELS_LS_ACC); ++ fc_lport_plogi_fill(lport, pl, ELS_LS_ACC); + + /* + * Send LS_ACC. If this fails, +@@ -1048,15 +1102,11 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + */ + f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; + fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lp->tt.seq_send(lp, sp, fp, f_ctl); +- if (rp->rp_state == RPORT_ST_PLOGI) ++ lport->tt.seq_send(lport, sp, fp, f_ctl); ++ if (rdata->rp_state == RPORT_ST_PLOGI) + fc_rport_enter_prli(rport); +- else +- fc_rport_state_enter(rport, +- RPORT_ST_PLOGI_RECV); + } + } +- fc_rport_unlock(rport); + } + + /** +@@ -1064,14 +1114,18 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + * @rport: Fibre Channel remote port that initiated PRLI + * @sp: current sequence in the PRLI exchange + * @fp: PRLI request frame ++ * ++ * Locking Note: The rport lock is exected to be held before calling ++ * this function. + */ + static void fc_rport_recv_prli_req(struct fc_rport *rport, + struct fc_seq *sp, struct fc_frame *rx_fp) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; ++ + struct fc_frame *fp; + struct fc_frame_header *fh; +- struct fc_lport *lp; + struct { + struct fc_els_prli prli; + struct fc_els_spp spp; +@@ -1087,12 +1141,16 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + u32 f_ctl; + u32 fcp_parm; + u32 roles = FC_RPORT_ROLE_UNKNOWN; +- + rjt_data.fp = NULL; ++ + fh = fc_frame_header_get(rx_fp); +- lp = rp->local_port; +- switch (rp->rp_state) { +- case RPORT_ST_PLOGI_RECV: ++ ++ if (fc_rp_debug) ++ FC_DBG("Received PRLI request from port (%6x) " ++ "while in state %s\n", ntoh24(fh->fh_s_id), ++ fc_rport_state(rport)); ++ ++ switch (rdata->rp_state) { + case RPORT_ST_PRLI: + case RPORT_ST_READY: + reason = ELS_RJT_NONE; +@@ -1122,12 +1180,12 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + rspp = &pp->spp; + } + if (reason != ELS_RJT_NONE || +- (fp = fc_frame_alloc(lp, len)) == NULL) { ++ (fp = fc_frame_alloc(lport, len)) == NULL) { + rjt_data.reason = reason; + rjt_data.explan = explan; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + } else { +- sp = lp->tt.seq_start_next(sp); ++ sp = lport->tt.seq_start_next(sp); + WARN_ON(!sp); + pp = fc_frame_payload_get(fp, len); + WARN_ON(!pp); +@@ -1156,15 +1214,16 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + case FC_TYPE_FCP: + fcp_parm = ntohl(rspp->spp_params); + if (fcp_parm * FCP_SPPF_RETRY) +- rp->flags |= FC_RP_FLAGS_RETRY; ++ rdata->flags |= FC_RP_FLAGS_RETRY; + rport->supported_classes = FC_COS_CLASS3; + if (fcp_parm & FCP_SPPF_INIT_FCN) + roles |= FC_RPORT_ROLE_FCP_INITIATOR; + if (fcp_parm & FCP_SPPF_TARG_FCN) + roles |= FC_RPORT_ROLE_FCP_TARGET; +- fc_remote_port_rolechg(rport, roles); ++ rdata->roles = roles; ++ + spp->spp_params = +- htonl(rp->local_port->service_params); ++ htonl(lport->service_params); + break; + default: + resp = FC_SPP_RESP_INVL; +@@ -1181,32 +1240,20 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + */ + f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; + fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lp->tt.seq_send(lp, sp, fp, f_ctl); ++ lport->tt.seq_send(lport, sp, fp, f_ctl); + + /* + * Get lock and re-check state. + */ +- fc_rport_lock(rport); +- switch (rp->rp_state) { +- case RPORT_ST_PLOGI_RECV: ++ switch (rdata->rp_state) { + case RPORT_ST_PRLI: +- fc_rport_state_enter(rport, RPORT_ST_READY); +- if (fc_rp_debug) +- FC_DBG("remote %6x ready\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state == LPORT_ST_DNS) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->tt.dns_register(lp); +- fc_lport_unlock(lp); +- } ++ fc_rport_enter_ready(rport); + break; + case RPORT_ST_READY: + break; + default: + break; + } +- fc_rport_unlock(rport); + } + fc_frame_free(rx_fp); + } +@@ -1216,22 +1263,30 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + * @rport: Fibre Channel remote port that initiated PRLO + * @sp: current sequence in the PRLO exchange + * @fp: PRLO request frame ++ * ++ * Locking Note: The rport lock is exected to be held before calling ++ * this function. + */ + static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, + struct fc_frame *fp) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; ++ + struct fc_frame_header *fh; +- struct fc_lport *lp = rp->local_port; + struct fc_seq_els_data rjt_data; + + fh = fc_frame_header_get(fp); +- FC_DBG("incoming PRLO from %x state %d\n", +- ntoh24(fh->fh_s_id), rp->rp_state); ++ ++ if (fc_rp_debug) ++ FC_DBG("Received PRLO request from port (%6x) " ++ "while in state %s\n", ntoh24(fh->fh_s_id), ++ fc_rport_state(rport)); ++ + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_UNAB; + rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); + } + +@@ -1240,62 +1295,95 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, + * @rport: Fibre Channel remote port that initiated LOGO + * @sp: current sequence in the LOGO exchange + * @fp: LOGO request frame ++ * ++ * Locking Note: The rport lock is exected to be held before calling ++ * this function. + */ + static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, + struct fc_frame *fp) + { + struct fc_frame_header *fh; +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + + fh = fc_frame_header_get(fp); +- fc_rport_lock(rport); +- fc_rport_state_enter(rport, RPORT_ST_INIT); +- fc_rport_unlock(rport); ++ + if (fc_rp_debug) +- FC_DBG("remote %6x closed\n", rport->port_id); +- if (rport == lp->dns_rp && +- lp->state != LPORT_ST_RESET) { +- fc_lport_lock(lp); +- del_timer(&lp->state_timer); +- lp->dns_rp = NULL; +- if (lp->state == LPORT_ST_DNS_STOP) { +- fc_lport_unlock(lp); +- lp->tt.lport_logout(lp); +- } else { +- lp->tt.lport_login(lp); +- fc_lport_unlock(lp); +- } +- fc_remote_port_delete(rport); +- } +- lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ FC_DBG("Received LOGO request from port (%6x) " ++ "while in state %s\n", ntoh24(fh->fh_s_id), ++ fc_rport_state(rport)); ++ ++ rdata->event = LPORT_EV_RPORT_LOGO; ++ ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + fc_frame_free(fp); + } + +-int fc_rport_init(struct fc_lport *lp) ++int fc_rport_init(struct fc_lport *lport) + { +- if (!lp->tt.rport_login) +- lp->tt.rport_login = fc_rport_login; +- +- if (!lp->tt.rport_logout) +- lp->tt.rport_logout = fc_rport_logout; ++ if (!lport->tt.rport_login) ++ lport->tt.rport_login = fc_rport_login; + +- if (!lp->tt.rport_recv_req) +- lp->tt.rport_recv_req = fc_rport_recv_req; ++ if (!lport->tt.rport_logout) ++ lport->tt.rport_logout = fc_rport_logout; + +- if (!lp->tt.rport_create) +- lp->tt.rport_create = fc_remote_port_create; ++ if (!lport->tt.rport_recv_req) ++ lport->tt.rport_recv_req = fc_rport_recv_req; + +- if (!lp->tt.rport_lookup) +- lp->tt.rport_lookup = fc_rport_lookup; ++ if (!lport->tt.rport_lookup) ++ lport->tt.rport_lookup = fc_rport_lookup; + +- if (!lp->tt.rport_reset) +- lp->tt.rport_reset = fc_rport_reset; ++ if (!lport->tt.rport_reset) ++ lport->tt.rport_reset = fc_rport_reset; + +- if (!lp->tt.rport_reset_list) +- lp->tt.rport_reset_list = fc_rport_reset_list; ++ if (!lport->tt.rport_reset_list) ++ lport->tt.rport_reset_list = fc_rport_reset_list; + + return 0; + } + EXPORT_SYMBOL(fc_rport_init); + ++/** ++ * fc_block_rports - delete all the remote ports, on reset or link down ++ * @lp: libfc local port instance ++ * ++ * This routine temporarily removes any online remote ports from the fc_host ++ * rport list, then drops the host lock in order to call fc_remote_port_delete() ++ * on each rport in turn, and finally splices the list back onto the fc_host. ++ */ ++void fc_block_rports(struct fc_lport *lp) ++{ ++ struct Scsi_Host *shost = lp->host; ++ struct fc_rport *rport, *next; ++ unsigned long flags; ++ LIST_HEAD(rports); ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_for_each_entry_safe(rport, next, &fc_host_rports(shost), peers) { ++ /* protect the name service remote port */ ++ if (rport->port_id == FC_FID_DIR_SERV) ++ continue; ++ if (rport->port_state != FC_PORTSTATE_ONLINE) ++ continue; ++ list_move_tail(&rport->peers, &rports); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ ++ list_for_each_entry(rport, &rports, peers) { ++ fc_remote_port_delete(rport); ++ } ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_splice(&rports, &fc_host_rports(shost)); ++ spin_unlock_irqrestore(shost->host_lock, flags); ++} ++ ++void fc_rport_terminate_io(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ lp->tt.exch_mgr_reset(lp->emp, 0, rport->port_id); ++ lp->tt.exch_mgr_reset(lp->emp, rport->port_id, 0); ++} ++EXPORT_SYMBOL(fc_rport_terminate_io); +diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h +index b2e07ec..59c9d0c 100644 +--- a/include/scsi/fc/fc_fcoe.h ++++ b/include/scsi/fc/fc_fcoe.h +@@ -93,14 +93,6 @@ static inline void fc_fcoe_set_mac(u8 *mac, u8 *did) + mac[5] = did[2]; + } + +-/* +- * VLAN header. This is also defined in linux/if_vlan.h, but for kernels only. +- */ +-struct fcoe_vlan_hdr { +- __be16 vlan_tag; /* VLAN tag including priority */ +- __be16 vlan_ethertype; /* encapsulated ethertype ETH_P_FCOE */ +-}; +- + #ifndef ETH_P_8021Q + #define ETH_P_8021Q 0x8100 + #endif +diff --git a/include/scsi/fc/fc_fs.h b/include/scsi/fc/fc_fs.h +index ba6df64..3897c6c 100644 +--- a/include/scsi/fc/fc_fs.h ++++ b/include/scsi/fc/fc_fs.h +@@ -329,16 +329,4 @@ enum fc_pf_rjt_reason { + FC_RJT_VENDOR = 0xff, /* vendor specific reject */ + }; + +-/* +- * Data descriptor format (R_CTL == FC_RCTL_DD_DATA_DESC). +- * This is used for FCP SCSI transfer ready. +- */ +-struct fc_data_desc { +- __be32 dd_offset; /* data relative offset in bytes */ +- __be32 dd_len; /* transfer buffer size in bytes */ +- __u8 _dd_resvd[4]; +-}; +- +-#define FC_DATA_DESC_LEN 12 /* expected length of structure */ +- + #endif /* _FC_FS_H_ */ +diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h +index b139aed..24d3fcb 100644 +--- a/include/scsi/libfc/libfc.h ++++ b/include/scsi/libfc/libfc.h +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include + +@@ -91,28 +92,50 @@ enum fc_lport_state { + LPORT_ST_NONE = 0, + LPORT_ST_FLOGI, + LPORT_ST_DNS, +- LPORT_ST_REG_PN, +- LPORT_ST_REG_FT, ++ LPORT_ST_RPN_ID, ++ LPORT_ST_RFT_ID, + LPORT_ST_SCR, + LPORT_ST_READY, +- LPORT_ST_DNS_STOP, + LPORT_ST_LOGO, + LPORT_ST_RESET + }; + ++enum fc_lport_event { ++ LPORT_EV_RPORT_NONE = 0, ++ LPORT_EV_RPORT_CREATED, ++ LPORT_EV_RPORT_FAILED, ++ LPORT_EV_RPORT_LOGO ++}; ++ + enum fc_rport_state { + RPORT_ST_NONE = 0, + RPORT_ST_INIT, /* initialized */ +- RPORT_ST_STARTED, /* started */ + RPORT_ST_PLOGI, /* waiting for PLOGI completion */ +- RPORT_ST_PLOGI_RECV, /* received PLOGI (as target) */ + RPORT_ST_PRLI, /* waiting for PRLI completion */ + RPORT_ST_RTV, /* waiting for RTV completion */ +- RPORT_ST_ERROR, /* error */ + RPORT_ST_READY, /* ready for use */ + RPORT_ST_LOGO, /* port logout sent */ + }; + ++enum fc_rport_trans_state { ++ FC_PORTSTATE_ROGUE, ++ FC_PORTSTATE_REAL, ++}; ++ ++/** ++ * struct fc_disc_port - temporary discovery port to hold rport identifiers ++ * @lp: Fibre Channel host port instance ++ * @peers: node for list management during discovery and RSCN processing ++ * @ids: identifiers structure to pass to fc_remote_port_add() ++ * @rport_work: work struct for starting the rport state machine ++ */ ++struct fc_disc_port { ++ struct fc_lport *lp; ++ struct list_head peers; ++ struct fc_rport_identifiers ids; ++ struct work_struct rport_work; ++}; ++ + /** + * struct fc_rport_libfc_priv - libfc internal information about a remote port + * @local_port: Fibre Channel host port instance +@@ -122,8 +145,9 @@ enum fc_rport_state { + * @retries: retry count in current state + * @e_d_tov: error detect timeout value (in msec) + * @r_a_tov: resource allocation timeout value (in msec) +- * @rp_lock: lock protects state ++ * @rp_mutex: mutex protects rport + * @retry_work: ++ * @event_callback: Callback for rport READY, FAILED or LOGO + */ + struct fc_rport_libfc_priv { + struct fc_lport *local_port; +@@ -135,10 +159,23 @@ struct fc_rport_libfc_priv { + unsigned int retries; + unsigned int e_d_tov; + unsigned int r_a_tov; +- spinlock_t rp_lock; ++ enum fc_rport_trans_state trans_state; ++ struct mutex rp_mutex; + struct delayed_work retry_work; ++ enum fc_lport_event event; ++ void (*event_callback)(struct fc_lport *, u32, ++ enum fc_lport_event); ++ u32 roles; + }; + ++#define PRIV_TO_RPORT(x) \ ++ (struct fc_rport*)((void *)x - sizeof(struct fc_rport)); ++#define RPORT_TO_PRIV(x) \ ++ (struct fc_rport_libfc_priv*)((void *)x + sizeof(struct fc_rport)); ++ ++struct fc_rport *fc_rport_dummy_create(struct fc_disc_port *); ++void fc_rport_dummy_destroy(struct fc_rport *); ++ + static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) + { + rport->node_name = wwnn; +@@ -219,9 +256,12 @@ struct libfc_function_template { + * fc_frame pointer in response handler will also indicate timeout + * as error using IS_ERR related macros. + * +- * The response handler argumemt resp_arg is passed back to resp +- * handler when it is invoked by EM layer in above mentioned +- * two scenarios. ++ * The exchange destructor handler is also set in this routine. ++ * The destructor handler is invoked by EM layer when exchange ++ * is about to free, this can be used by caller to free its ++ * resources along with exchange free. ++ * ++ * The arg is passed back to resp and destructor handler. + * + * The timeout value (in msec) for an exchange is set if non zero + * timer_msec argument is specified. The timer is canceled when +@@ -232,10 +272,12 @@ struct libfc_function_template { + */ + struct fc_seq *(*exch_seq_send)(struct fc_lport *lp, + struct fc_frame *fp, +- void (*resp)(struct fc_seq *, ++ void (*resp)(struct fc_seq *sp, + struct fc_frame *fp, + void *arg), +- void *resp_arg, unsigned int timer_msec, ++ void (*destructor)(struct fc_seq *sp, ++ void *arg), ++ void *arg, unsigned int timer_msec, + u32 sid, u32 did, u32 f_ctl); + + /* +@@ -316,9 +358,10 @@ struct libfc_function_template { + void (*lport_recv)(struct fc_lport *lp, struct fc_seq *sp, + struct fc_frame *fp); + +- int (*lport_login)(struct fc_lport *); + int (*lport_reset)(struct fc_lport *); +- int (*lport_logout)(struct fc_lport *); ++ ++ void (*event_callback)(struct fc_lport *, u32, ++ enum fc_lport_event); + + /** + * Remote Port interfaces +@@ -346,9 +389,6 @@ struct libfc_function_template { + + struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); + +- struct fc_rport *(*rport_create)(struct fc_lport *, +- struct fc_rport_identifiers *); +- + void (*rport_reset)(struct fc_rport *); + + void (*rport_reset_list)(struct fc_lport *); +@@ -378,9 +418,6 @@ struct libfc_function_template { + * Start discovery for a local port. + */ + int (*disc_start)(struct fc_lport *); +- +- void (*dns_register)(struct fc_lport *); +- void (*disc_stop)(struct fc_lport *); + }; + + struct fc_lport { +@@ -396,7 +433,7 @@ struct fc_lport { + /* Operational Information */ + struct libfc_function_template tt; + u16 link_status; +- u8 ns_disc_done; ++ u8 disc_done; + enum fc_lport_state state; + unsigned long boot_time; + +@@ -407,12 +444,12 @@ struct fc_lport { + u64 wwnn; + u32 fid; + u8 retry_count; +- unsigned char ns_disc_retry_count; +- unsigned char ns_disc_delay; +- unsigned char ns_disc_pending; +- unsigned char ns_disc_requested; +- unsigned short ns_disc_seq_count; +- unsigned char ns_disc_buf_len; ++ unsigned char disc_retry_count; ++ unsigned char disc_delay; ++ unsigned char disc_pending; ++ unsigned char disc_requested; ++ unsigned short disc_seq_count; ++ unsigned char disc_buf_len; + + /* Capabilities */ + char ifname[IFNAMSIZ]; +@@ -427,13 +464,13 @@ struct fc_lport { + struct fc_ns_fts fcts; /* FC-4 type masks */ + struct fc_els_rnid_gen rnid_gen; /* RNID information */ + +- /* Locks */ +- spinlock_t state_lock; /* serializes state changes */ ++ /* Semaphores */ ++ struct mutex lp_mutex; + + /* Miscellaneous */ +- struct fc_gpn_ft_resp ns_disc_buf; /* partial name buffer */ +- struct timer_list state_timer; /* timer for state events */ +- struct delayed_work ns_disc_work; ++ struct fc_gpn_ft_resp disc_buf; /* partial name buffer */ ++ struct delayed_work retry_work; ++ struct delayed_work disc_work; + + void *drv_priv; + }; +@@ -462,33 +499,26 @@ static inline void fc_set_wwpn(struct fc_lport *lp, u64 wwnn) + lp->wwpn = wwnn; + } + +-static inline int fc_lport_locked(struct fc_lport *lp) +-{ +-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) +- return spin_is_locked(&lp->state_lock); +-#else +- return 1; +-#endif /* CONFIG_SMP || CONFIG_DEBUG_SPINLOCK */ +-} +- +-/* +- * Locking code. +- */ +-static inline void fc_lport_lock(struct fc_lport *lp) +-{ +- spin_lock_bh(&lp->state_lock); +-} +- +-static inline void fc_lport_unlock(struct fc_lport *lp) ++/** ++ * fc_fill_dns_hdr - Fill in a name service request header ++ * @lp: Fibre Channel host port instance ++ * @ct: Common Transport (CT) header structure ++ * @op: Name Service request code ++ * @req_size: Full size of Name Service request ++ */ ++static inline void fc_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, ++ unsigned int op, unsigned int req_size) + { +- spin_unlock_bh(&lp->state_lock); ++ memset(ct, 0, sizeof(*ct) + req_size); ++ ct->ct_rev = FC_CT_REV; ++ ct->ct_fs_type = FC_FST_DIR; ++ ct->ct_fs_subtype = FC_NS_SUBTYPE; ++ ct->ct_cmd = htons((u16) op); + } + + static inline void fc_lport_state_enter(struct fc_lport *lp, + enum fc_lport_state state) + { +- WARN_ON(!fc_lport_locked(lp)); +- del_timer(&lp->state_timer); + if (state != lp->state) + lp->retry_count = 0; + lp->state = state; +@@ -543,7 +573,7 @@ int fc_lport_config(struct fc_lport *); + /* + * Reset the local port. + */ +-int fc_lport_enter_reset(struct fc_lport *); ++int fc_lport_reset(struct fc_lport *); + + /* + * Set the mfs or reset +@@ -555,12 +585,14 @@ int fc_set_mfs(struct fc_lport *lp, u32 mfs); + * REMOTE PORT LAYER + *****************************/ + int fc_rport_init(struct fc_lport *lp); ++void fc_rport_terminate_io(struct fc_rport *rp); ++void fc_block_rports(struct fc_lport *lp); + + + /** + * DISCOVERY LAYER + *****************************/ +-int fc_ns_init(struct fc_lport *lp); ++int fc_disc_init(struct fc_lport *lp); + + + /** +@@ -670,10 +702,12 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, + */ + struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + struct fc_frame *fp, +- void (*resp)(struct fc_seq *, ++ void (*resp)(struct fc_seq *sp, + struct fc_frame *fp, + void *arg), +- void *resp_arg, u32 timer_msec, ++ void (*destructor)(struct fc_seq *sp, ++ void *arg), ++ void *arg, u32 timer_msec, + u32 sid, u32 did, u32 f_ctl); + + /* +@@ -738,15 +772,11 @@ void fc_seq_get_xids(struct fc_seq *sp, u16 *oxid, u16 *rxid); + */ + void fc_seq_set_rec_data(struct fc_seq *sp, u32 rec_data); + +-/** +- * fc_functions_template +- *****************************/ +-void fc_attr_init(struct fc_lport *); +-void fc_get_host_port_id(struct Scsi_Host *shost); ++/* ++ * Functions for fc_functions_template ++ */ + void fc_get_host_speed(struct Scsi_Host *shost); +-void fc_get_host_port_type(struct Scsi_Host *shost); + void fc_get_host_port_state(struct Scsi_Host *shost); +-void fc_get_host_fabric_name(struct Scsi_Host *shost); + void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout); + struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta4-update b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta4-update new file mode 100644 index 000000000..5d8357c55 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta4-update @@ -0,0 +1,6208 @@ +Subject: Open-FCoE: Update for Beta4 +From: John Fastabend +Date: Thu Nov 6 13:08:49 2008 +0100: +Git: c66b456a7eb389e5f19d5bf23170b47a3e01d755 +References: bnc#438954 + +Incremental Open-FCoE update for Beta4. + +Signed-off-by: John Fastabend +Acked-by: Hannes Reinecke + +diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile +index 342e2ad..b78da06 100644 +--- a/drivers/scsi/fcoe/Makefile ++++ b/drivers/scsi/fcoe/Makefile +@@ -3,6 +3,6 @@ + obj-$(CONFIG_FCOE) += fcoe.o + + fcoe-y := \ +- fcoe_dev.o \ +- fcoe_if.o \ +- fcoeinit.o ++ libfcoe.o \ ++ fcoe_sw.o \ ++ fc_transport_fcoe.o +diff --git a/drivers/scsi/fcoe/fc_transport_fcoe.c b/drivers/scsi/fcoe/fc_transport_fcoe.c +new file mode 100644 +index 0000000..e11d36b +--- /dev/null ++++ b/drivers/scsi/fcoe/fc_transport_fcoe.c +@@ -0,0 +1,396 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "fcoe_def.h" ++ ++MODULE_AUTHOR("Open-FCoE.org"); ++MODULE_DESCRIPTION("FCoE"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Static functions and variables definations ++ */ ++#ifdef CONFIG_HOTPLUG_CPU ++static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); ++#endif /* CONFIG_HOTPLUG_CPU */ ++static int fcoe_device_notification(struct notifier_block *, ulong, void *); ++static void fcoe_dev_setup(void); ++static void fcoe_dev_cleanup(void); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static struct notifier_block fcoe_cpu_notifier = { ++ .notifier_call = fcoe_cpu_callback, ++}; ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* ++ * notification function from net device ++ */ ++static struct notifier_block fcoe_notifier = { ++ .notifier_call = fcoe_device_notification, ++}; ++ ++#ifdef CONFIG_HOTPLUG_CPU ++/* ++ * create percpu stats block ++ * called by cpu add/remove notifier ++ */ ++static void fcoe_create_percpu_data(int cpu) ++{ ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *p; ++ ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ lp = fc->lp; ++ if (lp->dev_stats[cpu] == NULL) { ++ p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); ++ if (p) ++ lp->dev_stats[cpu] = p; ++ } ++ } ++ write_unlock_bh(&fcoe_hostlist_lock); ++} ++ ++/* ++ * destroy percpu stats block ++ * called by cpu add/remove notifier ++ */ ++static void fcoe_destroy_percpu_data(int cpu) ++{ ++ struct fcoe_dev_stats *p; ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ lp = fc->lp; ++ p = lp->dev_stats[cpu]; ++ if (p != NULL) { ++ lp->dev_stats[cpu] = NULL; ++ kfree(p); ++ } ++ } ++ write_unlock_bh(&fcoe_hostlist_lock); ++} ++ ++/* ++ * Get notified when a cpu comes on/off. Be hotplug friendly. ++ */ ++static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action, ++ void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ fcoe_create_percpu_data(cpu); ++ break; ++ case CPU_DEAD: ++ fcoe_destroy_percpu_data(cpu); ++ break; ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* ++ * function to setup link change notification interface ++ */ ++static void fcoe_dev_setup(void) ++{ ++ /* ++ * here setup a interface specific wd time to ++ * monitor the link state ++ */ ++ register_netdevice_notifier(&fcoe_notifier); ++} ++ ++/* ++ * function to cleanup link change notification interface ++ */ ++static void fcoe_dev_cleanup(void) ++{ ++ unregister_netdevice_notifier(&fcoe_notifier); ++} ++ ++/* ++ * This function is called by the ethernet driver ++ * this is called in case of link change event ++ */ ++static int fcoe_device_notification(struct notifier_block *notifier, ++ ulong event, void *ptr) ++{ ++ struct fc_lport *lp = NULL; ++ struct net_device *real_dev = ptr; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *stats; ++ u16 new_status; ++ u32 mfs; ++ int rc = NOTIFY_OK; ++ ++ read_lock(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ if (fc->real_dev == real_dev) { ++ lp = fc->lp; ++ break; ++ } ++ } ++ read_unlock(&fcoe_hostlist_lock); ++ if (lp == NULL) { ++ rc = NOTIFY_DONE; ++ goto out; ++ } ++ ++ new_status = lp->link_status; ++ switch (event) { ++ case NETDEV_DOWN: ++ case NETDEV_GOING_DOWN: ++ new_status &= ~FC_LINK_UP; ++ break; ++ case NETDEV_UP: ++ case NETDEV_CHANGE: ++ new_status &= ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ new_status |= FC_LINK_UP; ++ break; ++ case NETDEV_CHANGEMTU: ++ mfs = fc->real_dev->mtu - ++ (sizeof(struct fcoe_hdr) + ++ sizeof(struct fcoe_crc_eof)); ++ if (fc->user_mfs && fc->user_mfs < mfs) ++ mfs = fc->user_mfs; ++ if (mfs >= FC_MIN_MAX_FRAME) ++ fc_set_mfs(lp, mfs); ++ new_status &= ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ new_status |= FC_LINK_UP; ++ break; ++ case NETDEV_REGISTER: ++ break; ++ default: ++ FC_DBG("unknown event %ld call", event); ++ } ++ if (lp->link_status != new_status) { ++ if ((new_status & FC_LINK_UP) == FC_LINK_UP) ++ fc_linkup(lp); ++ else { ++ stats = lp->dev_stats[smp_processor_id()]; ++ stats->LinkFailureCount++; ++ fc_linkdown(lp); ++ fcoe_clean_pending_queue(lp); ++ } ++ } ++out: ++ return rc; ++} ++ ++static void trimstr(char *str, int len) ++{ ++ char *cp = str + len; ++ while (--cp >= str && *cp == '\n') ++ *cp = '\0'; ++} ++ ++static ssize_t fcoe_destroy(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buffer, size_t size) ++{ ++ struct net_device *netdev; ++ char ifname[IFNAMSIZ + 2]; ++ ++ strlcpy(ifname, buffer, IFNAMSIZ); ++ trimstr(ifname, strlen(ifname)); ++ netdev = dev_get_by_name(&init_net, ifname); ++ if (netdev) { ++ fcoe_destroy_interface(netdev); ++ dev_put(netdev); ++ } ++ return size; ++} ++ ++static ssize_t fcoe_create(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buffer, size_t size) ++{ ++ struct net_device *netdev; ++ char ifname[IFNAMSIZ + 2]; ++ ++ strlcpy(ifname, buffer, IFNAMSIZ); ++ trimstr(ifname, strlen(ifname)); ++ netdev = dev_get_by_name(&init_net, ifname); ++ if (netdev) { ++ fcoe_create_interface(netdev); ++ dev_put(netdev); ++ } ++ return size; ++} ++ ++static const struct kobj_attribute fcoe_destroyattr = \ ++ __ATTR(destroy, S_IWUSR, NULL, fcoe_destroy); ++static const struct kobj_attribute fcoe_createattr = \ ++ __ATTR(create, S_IWUSR, NULL, fcoe_create); ++ ++/* ++ * Initialization routine ++ * 1. Will create fc transport software structure ++ * 2. initialize the link list of port information structure ++ */ ++static int __init fcoe_init(void) ++{ ++ int rc = 0; ++ int cpu; ++ struct fcoe_percpu_s *p; ++ ++ rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, ++ &fcoe_destroyattr.attr); ++ if (!rc) ++ rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, ++ &fcoe_createattr.attr); ++ ++ if (rc) ++ return rc; ++ ++ rwlock_init(&fcoe_hostlist_lock); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ register_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++ /* ++ * initialize per CPU interrupt thread ++ */ ++ for_each_online_cpu(cpu) { ++ p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL); ++ if (p) { ++ p->thread = kthread_create(fcoe_percpu_receive_thread, ++ (void *)p, ++ "fcoethread/%d", cpu); ++ ++ /* ++ * if there is no error then bind the thread to the cpu ++ * initialize the semaphore and skb queue head ++ */ ++ if (likely(!IS_ERR(p->thread))) { ++ p->cpu = cpu; ++ fcoe_percpu[cpu] = p; ++ skb_queue_head_init(&p->fcoe_rx_list); ++ kthread_bind(p->thread, cpu); ++ wake_up_process(p->thread); ++ } else { ++ fcoe_percpu[cpu] = NULL; ++ kfree(p); ++ ++ } ++ } ++ } ++ if (rc < 0) { ++ FC_DBG("failed to initialize proc intrerface\n"); ++ rc = -ENODEV; ++ goto out_chrdev; ++ } ++ ++ /* ++ * setup link change notification ++ */ ++ fcoe_dev_setup(); ++ ++ init_timer(&fcoe_timer); ++ fcoe_timer.data = 0; ++ fcoe_timer.function = fcoe_watchdog; ++ fcoe_timer.expires = (jiffies + (10 * HZ)); ++ add_timer(&fcoe_timer); ++ ++ if (fcoe_sw_init() != 0) { ++ FC_DBG("fail to attach fc transport"); ++ return -1; ++ } ++ ++ return 0; ++ ++out_chrdev: ++#ifdef CONFIG_HOTPLUG_CPU ++ unregister_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ return rc; ++} ++module_init(fcoe_init); ++ ++static void __exit fcoe_exit(void) ++{ ++ u32 idx; ++ struct fcoe_softc *fc, *tmp; ++ struct fcoe_percpu_s *p; ++ struct sk_buff *skb; ++ ++ /* ++ * Stop all call back interfaces ++ */ ++#ifdef CONFIG_HOTPLUG_CPU ++ unregister_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ fcoe_dev_cleanup(); ++ ++ /* ++ * stop timer ++ */ ++ del_timer_sync(&fcoe_timer); ++ ++ /* ++ * assuming that at this time there will be no ++ * ioctl in prograss, therefore we do not need to lock the ++ * list. ++ */ ++ list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) ++ fcoe_destroy_interface(fc->real_dev); ++ ++ for (idx = 0; idx < NR_CPUS; idx++) { ++ if (fcoe_percpu[idx]) { ++ kthread_stop(fcoe_percpu[idx]->thread); ++ p = fcoe_percpu[idx]; ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) ++ kfree_skb(skb); ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ if (fcoe_percpu[idx]->crc_eof_page) ++ put_page(fcoe_percpu[idx]->crc_eof_page); ++ kfree(fcoe_percpu[idx]); ++ } ++ } ++ ++ fcoe_sw_exit(); ++} ++module_exit(fcoe_exit); +diff --git a/drivers/scsi/fcoe/fcoe_def.h b/drivers/scsi/fcoe/fcoe_def.h +index 12bf69c..b00e14b 100644 +--- a/drivers/scsi/fcoe/fcoe_def.h ++++ b/drivers/scsi/fcoe/fcoe_def.h +@@ -1,5 +1,5 @@ + /* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, +@@ -48,16 +48,10 @@ struct fcoe_percpu_s { + int crc_eof_offset; + }; + +-struct fcoe_info { +- struct timer_list timer; +- /* +- * fcoe host list is protected by the following read/write lock +- */ +- rwlock_t fcoe_hostlist_lock; +- struct list_head fcoe_hostlist; +- +- struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; +-}; ++extern struct timer_list fcoe_timer; ++extern rwlock_t fcoe_hostlist_lock; ++extern struct list_head fcoe_hostlist; ++extern struct fcoe_percpu_s *fcoe_percpu[]; + + struct fcoe_softc { + struct list_head list; +@@ -79,22 +73,20 @@ struct fcoe_softc { + u8 address_mode; + }; + +-extern int debug_fcoe; +-extern struct fcoe_percpu_s *fcoe_percpu[]; +-extern struct scsi_transport_template *fcoe_transport_template; + int fcoe_percpu_receive_thread(void *arg); + + /* + * HBA transport ops prototypes + */ +-extern struct fcoe_info fcoei; +- + void fcoe_clean_pending_queue(struct fc_lport *fd); + void fcoe_watchdog(ulong vp); +-int fcoe_destroy_interface(const char *ifname); +-int fcoe_create_interface(const char *ifname); ++int fcoe_destroy_interface(struct net_device *); ++int fcoe_create_interface(struct net_device *); + int fcoe_xmit(struct fc_lport *, struct fc_frame *); + int fcoe_rcv(struct sk_buff *, struct net_device *, + struct packet_type *, struct net_device *); + int fcoe_link_ok(struct fc_lport *); ++ ++int __init fcoe_sw_init(void); ++void __exit fcoe_sw_exit(void); + #endif /* _FCOE_DEF_H_ */ +diff --git a/drivers/scsi/fcoe/fcoe_dev.c b/drivers/scsi/fcoe/fcoe_dev.c +deleted file mode 100644 +index d5a354f..0000000 +--- a/drivers/scsi/fcoe/fcoe_dev.c ++++ /dev/null +@@ -1,633 +0,0 @@ +-/* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-/* +- * FCOE protocol file +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include +-#include +- +-#include +-#include "fcoe_def.h" +- +-#define FCOE_MAX_QUEUE_DEPTH 256 +- +-/* destination address mode */ +-#define FCOE_GW_ADDR_MODE 0x00 +-#define FCOE_FCOUI_ADDR_MODE 0x01 +- +-/* Function Prototyes */ +-static int fcoe_check_wait_queue(struct fc_lport *); +-static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *); +-static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *); +-static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); +- +-/* +- * this is the fcoe receive function +- * called by NET_RX_SOFTIRQ +- * this function will receive the packet and +- * build fc frame and pass it up +- */ +-int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, +- struct packet_type *ptype, struct net_device *olddev) +-{ +- struct fc_lport *lp; +- struct fcoe_rcv_info *fr; +- struct fcoe_softc *fc; +- struct fcoe_dev_stats *stats; +- u8 *data; +- struct fc_frame_header *fh; +- unsigned short oxid; +- int cpu_idx; +- struct fcoe_percpu_s *fps; +- struct fcoe_info *fci = &fcoei; +- +- fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); +- lp = fc->lp; +- if (unlikely(lp == NULL)) { +- FC_DBG("cannot find hba structure"); +- goto err2; +- } +- +- if (unlikely(debug_fcoe)) { +- FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " +- "end:%p sum:%d dev:%s", skb->len, skb->data_len, +- skb->head, skb->data, skb_tail_pointer(skb), +- skb_end_pointer(skb), skb->csum, +- skb->dev ? skb->dev->name : ""); +- +- } +- +- /* check for FCOE packet type */ +- if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { +- FC_DBG("wrong FC type frame"); +- goto err; +- } +- data = skb->data; +- data += sizeof(struct fcoe_hdr); +- fh = (struct fc_frame_header *)data; +- oxid = ntohs(fh->fh_ox_id); +- +- fr = fcoe_dev_from_skb(skb); +- fr->fr_dev = lp; +- fr->ptype = ptype; +- cpu_idx = 0; +-#ifdef CONFIG_SMP +- /* +- * The exchange ID are ANDed with num of online CPUs, +- * so that will have the least lock contention in +- * handling the exchange. if there is no thread +- * for a given idx then use first online cpu. +- */ +- cpu_idx = oxid & (num_online_cpus() >> 1); +- if (fci->fcoe_percpu[cpu_idx] == NULL) +- cpu_idx = first_cpu(cpu_online_map); +-#endif +- fps = fci->fcoe_percpu[cpu_idx]; +- +- spin_lock_bh(&fps->fcoe_rx_list.lock); +- __skb_queue_tail(&fps->fcoe_rx_list, skb); +- if (fps->fcoe_rx_list.qlen == 1) +- wake_up_process(fps->thread); +- +- spin_unlock_bh(&fps->fcoe_rx_list.lock); +- +- return 0; +-err: +-#ifdef CONFIG_SMP +- stats = lp->dev_stats[smp_processor_id()]; +-#else +- stats = lp->dev_stats[0]; +-#endif +- stats->ErrorFrames++; +- +-err2: +- kfree_skb(skb); +- return -1; +-} +- +-static inline int fcoe_start_io(struct sk_buff *skb) +-{ +- int rc; +- +- skb_get(skb); +- rc = dev_queue_xmit(skb); +- if (rc != 0) +- return rc; +- kfree_skb(skb); +- return 0; +-} +- +-static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) +-{ +- struct fcoe_info *fci = &fcoei; +- struct fcoe_percpu_s *fps; +- struct page *page; +- int cpu_idx; +- +- cpu_idx = get_cpu(); +- fps = fci->fcoe_percpu[cpu_idx]; +- page = fps->crc_eof_page; +- if (!page) { +- page = alloc_page(GFP_ATOMIC); +- if (!page) { +- put_cpu(); +- return -ENOMEM; +- } +- fps->crc_eof_page = page; +- WARN_ON(fps->crc_eof_offset != 0); +- } +- +- get_page(page); +- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, +- fps->crc_eof_offset, tlen); +- skb->len += tlen; +- skb->data_len += tlen; +- skb->truesize += tlen; +- fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); +- +- if (fps->crc_eof_offset >= PAGE_SIZE) { +- fps->crc_eof_page = NULL; +- fps->crc_eof_offset = 0; +- put_page(page); +- } +- put_cpu(); +- return 0; +-} +- +-/* +- * this is the frame xmit routine +- */ +-int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) +-{ +- int indx; +- int wlen, rc = 0; +- u32 crc; +- struct ethhdr *eh; +- struct fcoe_crc_eof *cp; +- struct sk_buff *skb; +- struct fcoe_dev_stats *stats; +- struct fc_frame_header *fh; +- unsigned int hlen; /* header length implies the version */ +- unsigned int tlen; /* trailer length */ +- int flogi_in_progress = 0; +- struct fcoe_softc *fc; +- void *data; +- u8 sof, eof; +- struct fcoe_hdr *hp; +- +- WARN_ON((fr_len(fp) % sizeof(u32)) != 0); +- +- fc = (struct fcoe_softc *)lp->drv_priv; +- /* +- * if it is a flogi then we need to learn gw-addr +- * and my own fcid +- */ +- fh = fc_frame_header_get(fp); +- if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { +- if (fc_frame_payload_op(fp) == ELS_FLOGI) { +- fc->flogi_oxid = ntohs(fh->fh_ox_id); +- fc->address_mode = FCOE_FCOUI_ADDR_MODE; +- fc->flogi_progress = 1; +- flogi_in_progress = 1; +- } else if (fc->flogi_progress && ntoh24(fh->fh_s_id) != 0) { +- /* +- * Here we must've gotten an SID by accepting an FLOGI +- * from a point-to-point connection. Switch to using +- * the source mac based on the SID. The destination +- * MAC in this case would have been set by receving the +- * FLOGI. +- */ +- fc_fcoe_set_mac(fc->data_src_addr, fh->fh_s_id); +- fc->flogi_progress = 0; +- } +- } +- +- skb = fp_skb(fp); +- sof = fr_sof(fp); +- eof = fr_eof(fp); +- +- crc = ~0; +- crc = crc32(crc, skb->data, skb_headlen(skb)); +- +- for (indx = 0; indx < skb_shinfo(skb)->nr_frags; indx++) { +- skb_frag_t *frag = &skb_shinfo(skb)->frags[indx]; +- unsigned long off = frag->page_offset; +- unsigned long len = frag->size; +- +- while (len > 0) { +- unsigned long clen; +- +- clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); +- data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), +- KM_SKB_DATA_SOFTIRQ); +- crc = crc32(crc, data + (off & ~PAGE_MASK), +- clen); +- kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); +- off += clen; +- len -= clen; +- } +- } +- +- /* +- * Get header and trailer lengths. +- * This is temporary code until we get rid of the old protocol. +- * Both versions have essentially the same trailer layout but T11 +- * has padding afterwards. +- */ +- hlen = sizeof(struct fcoe_hdr); +- tlen = sizeof(struct fcoe_crc_eof); +- +- /* +- * copy fc crc and eof to the skb buff +- * Use utility buffer in the fc_frame part of the sk_buff for the +- * trailer. +- * We don't do a get_page for this frag, since that page may not be +- * managed that way. So that skb_free() doesn't do that either, we +- * setup the destructor to remove this frag. +- */ +- if (skb_is_nonlinear(skb)) { +- skb_frag_t *frag; +- if (fcoe_get_paged_crc_eof(skb, tlen)) { +- kfree(skb); +- return -ENOMEM; +- } +- frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; +- cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) +- + frag->page_offset; +- } else { +- cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); +- } +- +- cp->fcoe_eof = eof; +- cp->fcoe_crc32 = cpu_to_le32(~crc); +- if (tlen == sizeof(*cp)) +- memset(cp->fcoe_resvd, 0, sizeof(cp->fcoe_resvd)); +- wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; +- +- if (skb_is_nonlinear(skb)) { +- kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); +- cp = NULL; +- } +- +- /* +- * Fill in the control structures +- */ +- skb->ip_summed = CHECKSUM_NONE; +- eh = (struct ethhdr *)skb_push(skb, hlen + sizeof(struct ethhdr)); +- if (fc->address_mode == FCOE_FCOUI_ADDR_MODE) +- fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); +- else +- /* insert GW address */ +- memcpy(eh->h_dest, fc->dest_addr, ETH_ALEN); +- +- if (unlikely(flogi_in_progress)) +- memcpy(eh->h_source, fc->ctl_src_addr, ETH_ALEN); +- else +- memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); +- +- eh->h_proto = htons(ETH_P_FCOE); +- skb->protocol = htons(ETH_P_802_3); +- skb_reset_mac_header(skb); +- skb_reset_network_header(skb); +- +- hp = (struct fcoe_hdr *)(eh + 1); +- memset(hp, 0, sizeof(*hp)); +- if (FC_FCOE_VER) +- FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); +- hp->fcoe_sof = sof; +- +- stats = lp->dev_stats[smp_processor_id()]; +- stats->TxFrames++; +- stats->TxWords += wlen; +- skb->dev = fc->real_dev; +- +- fr_dev(fp) = lp; +- if (fc->fcoe_pending_queue.qlen) +- rc = fcoe_check_wait_queue(lp); +- +- if (rc == 0) +- rc = fcoe_start_io(skb); +- +- if (rc) { +- fcoe_insert_wait_queue(lp, skb); +- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) +- fc_pause(lp); +- } +- +- return 0; +-} +- +-int fcoe_percpu_receive_thread(void *arg) +-{ +- struct fcoe_percpu_s *p = arg; +- u32 fr_len; +- unsigned int hlen; +- unsigned int tlen; +- struct fc_lport *lp; +- struct fcoe_rcv_info *fr; +- struct fcoe_dev_stats *stats; +- struct fc_frame_header *fh; +- struct sk_buff *skb; +- struct fcoe_crc_eof *cp; +- enum fc_sof sof; +- struct fc_frame *fp; +- u8 *mac = NULL; +- struct fcoe_softc *fc; +- struct fcoe_hdr *hp; +- +- set_user_nice(current, 19); +- +- while (!kthread_should_stop()) { +- +- spin_lock_bh(&p->fcoe_rx_list.lock); +- while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) { +- set_current_state(TASK_INTERRUPTIBLE); +- spin_unlock_bh(&p->fcoe_rx_list.lock); +- schedule(); +- set_current_state(TASK_RUNNING); +- if (kthread_should_stop()) +- return 0; +- spin_lock_bh(&p->fcoe_rx_list.lock); +- } +- spin_unlock_bh(&p->fcoe_rx_list.lock); +- fr = fcoe_dev_from_skb(skb); +- lp = fr->fr_dev; +- if (unlikely(lp == NULL)) { +- FC_DBG("invalid HBA Structure"); +- kfree_skb(skb); +- continue; +- } +- +- stats = lp->dev_stats[smp_processor_id()]; +- +- if (unlikely(debug_fcoe)) { +- FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p " +- "tail:%p end:%p sum:%d dev:%s", +- skb->len, skb->data_len, +- skb->head, skb->data, skb_tail_pointer(skb), +- skb_end_pointer(skb), skb->csum, +- skb->dev ? skb->dev->name : ""); +- } +- +- /* +- * Save source MAC address before discarding header. +- */ +- fc = lp->drv_priv; +- if (unlikely(fc->flogi_progress)) +- mac = eth_hdr(skb)->h_source; +- +- if (skb_is_nonlinear(skb)) +- skb_linearize(skb); /* not ideal */ +- +- /* +- * Check the header and pull it off. +- */ +- hlen = sizeof(struct fcoe_hdr); +- +- hp = (struct fcoe_hdr *)skb->data; +- if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { +- if (stats->ErrorFrames < 5) +- FC_DBG("unknown FCoE version %x", +- FC_FCOE_DECAPS_VER(hp)); +- stats->ErrorFrames++; +- kfree_skb(skb); +- continue; +- } +- sof = hp->fcoe_sof; +- skb_pull(skb, sizeof(*hp)); +- fr_len = skb->len - sizeof(struct fcoe_crc_eof); +- skb_trim(skb, fr_len); +- tlen = sizeof(struct fcoe_crc_eof); +- +- if (unlikely(fr_len > skb->len)) { +- if (stats->ErrorFrames < 5) +- FC_DBG("length error fr_len 0x%x skb->len 0x%x", +- fr_len, skb->len); +- stats->ErrorFrames++; +- kfree_skb(skb); +- continue; +- } +- stats->RxFrames++; +- stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; +- +- fp = (struct fc_frame *) skb; +- fc_frame_init(fp); +- cp = (struct fcoe_crc_eof *)(skb->data + fr_len); +- fr_eof(fp) = cp->fcoe_eof; +- fr_sof(fp) = sof; +- fr_dev(fp) = lp; +- +- /* +- * Check the CRC here, unless it's solicited data for SCSI. +- * In that case, the SCSI layer can check it during the copy, +- * and it'll be more cache-efficient. +- */ +- fh = fc_frame_header_get(fp); +- if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && +- fh->fh_type == FC_TYPE_FCP) { +- fr_flags(fp) |= FCPHF_CRC_UNCHECKED; +- fc_exch_recv(lp, lp->emp, fp); +- } else if (le32_to_cpu(cp->fcoe_crc32) == +- ~crc32(~0, skb->data, fr_len)) { +- if (unlikely(fc->flogi_progress)) +- fcoe_recv_flogi(fc, fp, mac); +- fc_exch_recv(lp, lp->emp, fp); +- } else { +- if (debug_fcoe || stats->InvalidCRCCount < 5) { +- printk(KERN_WARNING \ +- "fcoe: dropping frame with CRC error"); +- } +- stats->InvalidCRCCount++; +- stats->ErrorFrames++; +- fc_frame_free(fp); +- } +- } +- return 0; +-} +- +-/* +- * Snoop potential response to FLOGI or even incoming FLOGI. +- */ +-static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) +-{ +- struct fc_frame_header *fh; +- u8 op; +- +- fh = fc_frame_header_get(fp); +- if (fh->fh_type != FC_TYPE_ELS) +- return; +- op = fc_frame_payload_op(fp); +- if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && +- fc->flogi_oxid == ntohs(fh->fh_ox_id)) { +- /* +- * FLOGI accepted. +- * If the src mac addr is FC_OUI-based, then we mark the +- * address_mode flag to use FC_OUI-based Ethernet DA. +- * Otherwise we use the FCoE gateway addr +- */ +- if (!compare_ether_addr(sa, (u8[6]) FC_FCOE_FLOGI_MAC)) { +- fc->address_mode = FCOE_FCOUI_ADDR_MODE; +- } else { +- memcpy(fc->dest_addr, sa, ETH_ALEN); +- fc->address_mode = FCOE_GW_ADDR_MODE; +- } +- +- /* +- * Remove any previously-set unicast MAC filter. +- * Add secondary FCoE MAC address filter for our OUI. +- */ +- rtnl_lock(); +- if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) +- dev_unicast_delete(fc->real_dev, fc->data_src_addr, +- ETH_ALEN); +- fc_fcoe_set_mac(fc->data_src_addr, fh->fh_d_id); +- dev_unicast_add(fc->real_dev, fc->data_src_addr, ETH_ALEN); +- rtnl_unlock(); +- +- fc->flogi_progress = 0; +- } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { +- /* +- * Save source MAC for point-to-point responses. +- */ +- memcpy(fc->dest_addr, sa, ETH_ALEN); +- fc->address_mode = FCOE_GW_ADDR_MODE; +- } +-} +- +-void fcoe_watchdog(ulong vp) +-{ +- struct fc_lport *lp; +- struct fcoe_softc *fc; +- struct fcoe_info *fci = &fcoei; +- int paused = 0; +- +- read_lock(&fci->fcoe_hostlist_lock); +- list_for_each_entry(fc, &fci->fcoe_hostlist, list) { +- lp = fc->lp; +- if (lp) { +- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) +- paused = 1; +- if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) { +- if (paused) +- fc_unpause(lp); +- } +- } +- } +- read_unlock(&fci->fcoe_hostlist_lock); +- +- fci->timer.expires = jiffies + (1 * HZ); +- add_timer(&fci->timer); +-} +- +-/* +- * the wait_queue is used when the skb transmit fails. skb will go +- * in the wait_queue which will be emptied by the time function OR +- * by the next skb transmit. +- * +- */ +- +-/* +- * Function name : fcoe_check_wait_queue() +- * +- * Return Values : 0 or error +- * +- * Description : empties the wait_queue +- * dequeue the head of the wait_queue queue and +- * calls fcoe_start_io() for each packet +- * if all skb have been transmitted, return 0 +- * if a error occurs, then restore wait_queue and try again +- * later +- * +- */ +- +-static int fcoe_check_wait_queue(struct fc_lport *lp) +-{ +- int rc, unpause = 0; +- int paused = 0; +- struct sk_buff *skb; +- struct fcoe_softc *fc; +- +- fc = (struct fcoe_softc *)lp->drv_priv; +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- +- /* +- * is this interface paused? +- */ +- if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) +- paused = 1; +- if (fc->fcoe_pending_queue.qlen) { +- while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +- rc = fcoe_start_io(skb); +- if (rc) { +- fcoe_insert_wait_queue_head(lp, skb); +- return rc; +- } +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- } +- if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH) +- unpause = 1; +- } +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +- if ((unpause) && (paused)) +- fc_unpause(lp); +- return fc->fcoe_pending_queue.qlen; +-} +- +-static void fcoe_insert_wait_queue_head(struct fc_lport *lp, +- struct sk_buff *skb) +-{ +- struct fcoe_softc *fc; +- +- fc = (struct fcoe_softc *)lp->drv_priv; +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- __skb_queue_head(&fc->fcoe_pending_queue, skb); +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +-} +- +-static void fcoe_insert_wait_queue(struct fc_lport *lp, +- struct sk_buff *skb) +-{ +- struct fcoe_softc *fc; +- +- fc = (struct fcoe_softc *)lp->drv_priv; +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- __skb_queue_tail(&fc->fcoe_pending_queue, skb); +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +-} +diff --git a/drivers/scsi/fcoe/fcoe_if.c b/drivers/scsi/fcoe/fcoe_if.c +deleted file mode 100644 +index 73b83ce..0000000 +--- a/drivers/scsi/fcoe/fcoe_if.c ++++ /dev/null +@@ -1,496 +0,0 @@ +-/* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-/* +- * FCOE protocol file +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include +-#include "fcoe_def.h" +- +-#define FCOE_VERSION "0.1" +- +-#define FCOE_MAX_LUN 255 +-#define FCOE_MAX_FCP_TARGET 256 +- +-#define FCOE_MIN_XID 0x0004 +-#define FCOE_MAX_XID 0x07ef +- +-int debug_fcoe; +- +-struct fcoe_info fcoei = { +- .fcoe_hostlist = LIST_HEAD_INIT(fcoei.fcoe_hostlist), +-}; +- +-static struct fcoe_softc *fcoe_find_fc_lport(const char *name) +-{ +- struct fcoe_softc *fc; +- struct fc_lport *lp; +- struct fcoe_info *fci = &fcoei; +- +- read_lock(&fci->fcoe_hostlist_lock); +- list_for_each_entry(fc, &fci->fcoe_hostlist, list) { +- lp = fc->lp; +- if (!strncmp(name, lp->ifname, IFNAMSIZ)) { +- read_unlock(&fci->fcoe_hostlist_lock); +- return fc; +- } +- } +- read_unlock(&fci->fcoe_hostlist_lock); +- return NULL; +-} +- +-/* +- * Convert 48-bit IEEE MAC address to 64-bit FC WWN. +- */ +-static u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], +- unsigned int scheme, unsigned int port) +-{ +- u64 wwn; +- u64 host_mac; +- +- /* The MAC is in NO, so flip only the low 48 bits */ +- host_mac = ((u64) mac[0] << 40) | +- ((u64) mac[1] << 32) | +- ((u64) mac[2] << 24) | +- ((u64) mac[3] << 16) | +- ((u64) mac[4] << 8) | +- (u64) mac[5]; +- +- WARN_ON(host_mac >= (1ULL << 48)); +- wwn = host_mac | ((u64) scheme << 60); +- switch (scheme) { +- case 1: +- WARN_ON(port != 0); +- break; +- case 2: +- WARN_ON(port >= 0xfff); +- wwn |= (u64) port << 48; +- break; +- default: +- WARN_ON(1); +- break; +- } +- +- return wwn; +-} +- +-static struct scsi_host_template fcoe_driver_template = { +- .module = THIS_MODULE, +- .name = "FCoE Driver", +- .proc_name = FCOE_DRIVER_NAME, +- .queuecommand = fc_queuecommand, +- .eh_abort_handler = fc_eh_abort, +- .eh_device_reset_handler = fc_eh_device_reset, +- .eh_host_reset_handler = fc_eh_host_reset, +- .slave_alloc = fc_slave_alloc, +- .change_queue_depth = fc_change_queue_depth, +- .change_queue_type = fc_change_queue_type, +- .this_id = -1, +- .cmd_per_lun = 32, +- .can_queue = FC_MAX_OUTSTANDING_COMMANDS, +- .use_clustering = ENABLE_CLUSTERING, +- .sg_tablesize = 4, +- .max_sectors = 0xffff, +-}; +- +-int fcoe_destroy_interface(const char *ifname) +-{ +- int cpu, idx; +- struct fcoe_dev_stats *p; +- struct fcoe_percpu_s *pp; +- struct fcoe_softc *fc; +- struct fcoe_rcv_info *fr; +- struct fcoe_info *fci = &fcoei; +- struct sk_buff_head *list; +- struct sk_buff *skb, *next; +- struct sk_buff *head; +- struct fc_lport *lp; +- u8 flogi_maddr[ETH_ALEN]; +- +- fc = fcoe_find_fc_lport(ifname); +- if (!fc) +- return -ENODEV; +- +- lp = fc->lp; +- +- /* Remove the instance from fcoe's list */ +- write_lock_bh(&fci->fcoe_hostlist_lock); +- list_del(&fc->list); +- write_unlock_bh(&fci->fcoe_hostlist_lock); +- +- /* Don't listen for Ethernet packets anymore */ +- dev_remove_pack(&fc->fcoe_packet_type); +- +- /* Detach from the scsi-ml */ +- fc_remove_host(lp->host); +- scsi_remove_host(lp->host); +- +- /* Cleanup the fc_lport */ +- fc_lport_destroy(lp); +- fc_fcp_destroy(lp); +- if (lp->emp) +- fc_exch_mgr_free(lp->emp); +- +- /* Delete secondary MAC addresses */ +- rtnl_lock(); +- memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); +- dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); +- if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) +- dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); +- rtnl_unlock(); +- +- /* Free the per-CPU revieve threads */ +- for (idx = 0; idx < NR_CPUS; idx++) { +- if (fci->fcoe_percpu[idx]) { +- pp = fci->fcoe_percpu[idx]; +- spin_lock_bh(&pp->fcoe_rx_list.lock); +- list = &pp->fcoe_rx_list; +- head = list->next; +- for (skb = head; skb != (struct sk_buff *)list; +- skb = next) { +- next = skb->next; +- fr = fcoe_dev_from_skb(skb); +- if (fr->fr_dev == fc->lp) { +- __skb_unlink(skb, list); +- kfree_skb(skb); +- } +- } +- spin_unlock_bh(&pp->fcoe_rx_list.lock); +- } +- } +- +- /* Free existing skbs */ +- fcoe_clean_pending_queue(lp); +- +- /* Free memory used by statistical counters */ +- for_each_online_cpu(cpu) { +- p = lp->dev_stats[cpu]; +- if (p) { +- lp->dev_stats[cpu] = NULL; +- kfree(p); +- } +- } +- +- /* Release the net_device and Scsi_Host */ +- dev_put(fc->real_dev); +- scsi_host_put(lp->host); +- return 0; +-} +- +-/* +- * Return zero if link is OK for use by FCoE. +- * Any permanently-disqualifying conditions have been previously checked. +- * This also updates the speed setting, which may change with link for 100/1000. +- * +- * This function should probably be checking for PAUSE support at some point +- * in the future. Currently Per-priority-pause is not determinable using +- * ethtool, so we shouldn't be restrictive until that problem is resolved. +- */ +-int fcoe_link_ok(struct fc_lport *lp) +-{ +- struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; +- struct net_device *dev = fc->real_dev; +- struct ethtool_cmd ecmd = { ETHTOOL_GSET }; +- int rc = 0; +- +- if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { +- dev = fc->phys_dev; +- if (dev->ethtool_ops->get_settings) { +- dev->ethtool_ops->get_settings(dev, &ecmd); +- lp->link_supported_speeds &= +- ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); +- if (ecmd.supported & (SUPPORTED_1000baseT_Half | +- SUPPORTED_1000baseT_Full)) +- lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; +- if (ecmd.supported & SUPPORTED_10000baseT_Full) +- lp->link_supported_speeds |= +- FC_PORTSPEED_10GBIT; +- if (ecmd.speed == SPEED_1000) +- lp->link_speed = FC_PORTSPEED_1GBIT; +- if (ecmd.speed == SPEED_10000) +- lp->link_speed = FC_PORTSPEED_10GBIT; +- } +- } else +- rc = -1; +- +- return rc; +-} +- +-static struct libfc_function_template fcoe_libfc_fcn_templ = { +- .frame_send = fcoe_xmit, +-}; +- +-static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) +-{ +- int i = 0; +- struct fcoe_dev_stats *p; +- +- lp->host = shost; +- lp->drv_priv = (void *)(lp + 1); +- +- lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, +- FCOE_MIN_XID, FCOE_MAX_XID); +- if (!lp->emp) +- return -ENOMEM; +- +- lp->link_status = 0; +- lp->max_retry_count = 3; +- lp->e_d_tov = 2 * 1000; /* FC-FS default */ +- lp->r_a_tov = 2 * 2 * 1000; +- lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | +- FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); +- +- /* +- * allocate per cpu stats block +- */ +- for_each_online_cpu(i) { +- p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); +- if (p) +- lp->dev_stats[i] = p; +- } +- +- /* Finish fc_lport configuration */ +- fc_lport_config(lp); +- +- return 0; +-} +- +-static int net_config(struct fc_lport *lp) +-{ +- u32 mfs; +- u64 wwnn, wwpn; +- struct net_device *net_dev; +- struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; +- u8 flogi_maddr[ETH_ALEN]; +- +- /* Require support for get_pauseparam ethtool op. */ +- net_dev = fc->real_dev; +- if (!net_dev->ethtool_ops && (net_dev->priv_flags & IFF_802_1Q_VLAN)) +- net_dev = vlan_dev_real_dev(net_dev); +- if (!net_dev->ethtool_ops || !net_dev->ethtool_ops->get_pauseparam) +- return -EOPNOTSUPP; +- +- fc->phys_dev = net_dev; +- +- /* Do not support for bonding device */ +- if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || +- (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || +- (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { +- return -EOPNOTSUPP; +- } +- +- /* +- * Determine max frame size based on underlying device and optional +- * user-configured limit. If the MFS is too low, fcoe_link_ok() +- * will return 0, so do this first. +- */ +- mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + +- sizeof(struct fcoe_crc_eof)); +- fc_set_mfs(lp, mfs); +- +- lp->link_status = ~FC_PAUSE & ~FC_LINK_UP; +- if (!fcoe_link_ok(lp)) +- lp->link_status |= FC_LINK_UP; +- +- if (fc->real_dev->features & NETIF_F_SG) +- lp->capabilities = TRANS_C_SG; +- +- +- skb_queue_head_init(&fc->fcoe_pending_queue); +- +- memcpy(lp->ifname, fc->real_dev->name, IFNAMSIZ); +- +- /* setup Source Mac Address */ +- memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, +- fc->real_dev->addr_len); +- +- wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); +- fc_set_wwnn(lp, wwnn); +- /* XXX - 3rd arg needs to be vlan id */ +- wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); +- fc_set_wwpn(lp, wwpn); +- +- /* +- * Add FCoE MAC address as second unicast MAC address +- * or enter promiscuous mode if not capable of listening +- * for multiple unicast MACs. +- */ +- rtnl_lock(); +- memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); +- dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); +- rtnl_unlock(); +- +- /* +- * setup the receive function from ethernet driver +- * on the ethertype for the given device +- */ +- fc->fcoe_packet_type.func = fcoe_rcv; +- fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); +- fc->fcoe_packet_type.dev = fc->real_dev; +- dev_add_pack(&fc->fcoe_packet_type); +- +- return 0; +-} +- +-static void shost_config(struct fc_lport *lp) +-{ +- lp->host->max_lun = FCOE_MAX_LUN; +- lp->host->max_id = FCOE_MAX_FCP_TARGET; +- lp->host->max_channel = 0; +- lp->host->transportt = fcoe_transport_template; +-} +- +-static int libfc_config(struct fc_lport *lp) +-{ +- /* Set the function pointers set by the LLDD */ +- memcpy(&lp->tt, &fcoe_libfc_fcn_templ, +- sizeof(struct libfc_function_template)); +- +- if (fc_fcp_init(lp)) +- return -ENOMEM; +- fc_exch_init(lp); +- fc_lport_init(lp); +- fc_rport_init(lp); +- fc_disc_init(lp); +- +- return 0; +-} +- +-/* +- * This function creates the fcoe interface +- * create struct fcdev which is a shared structure between opefc +- * and transport level protocol. +- */ +-int fcoe_create_interface(const char *ifname) +-{ +- struct fc_lport *lp = NULL; +- struct fcoe_softc *fc; +- struct net_device *net_dev; +- struct Scsi_Host *shost; +- struct fcoe_info *fci = &fcoei; +- int rc = 0; +- +- net_dev = dev_get_by_name(&init_net, ifname); +- if (net_dev == NULL) { +- FC_DBG("could not get network device for %s", +- ifname); +- return -ENODEV; +- } +- +- if (fcoe_find_fc_lport(net_dev->name) != NULL) { +- rc = -EEXIST; +- goto out_put_dev; +- } +- +- shost = scsi_host_alloc(&fcoe_driver_template, +- sizeof(struct fc_lport) + +- sizeof(struct fcoe_softc)); +- +- if (!shost) { +- FC_DBG("Could not allocate host structure\n"); +- rc = -ENOMEM; +- goto out_put_dev; +- } +- +- lp = shost_priv(shost); +- rc = lport_config(lp, shost); +- if (rc) +- goto out_host_put; +- +- /* Configure the fcoe_softc */ +- fc = (struct fcoe_softc *)lp->drv_priv; +- fc->lp = lp; +- fc->real_dev = net_dev; +- shost_config(lp); +- +- +- /* Add the new host to the SCSI-ml */ +- rc = scsi_add_host(lp->host, NULL); +- if (rc) { +- FC_DBG("error on scsi_add_host\n"); +- goto out_lp_destroy; +- } +- +- sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", +- FCOE_DRIVER_NAME, FCOE_VERSION, +- ifname); +- +- /* Configure netdev and networking properties of the lp */ +- rc = net_config(lp); +- if (rc) +- goto out_lp_destroy; +- +- /* Initialize the library */ +- rc = libfc_config(lp); +- if (rc) +- goto out_lp_destroy; +- +- write_lock_bh(&fci->fcoe_hostlist_lock); +- list_add_tail(&fc->list, &fci->fcoe_hostlist); +- write_unlock_bh(&fci->fcoe_hostlist_lock); +- +- lp->boot_time = jiffies; +- +- fc_fabric_login(lp); +- +- return rc; +- +-out_lp_destroy: +- fc_exch_mgr_free(lp->emp); /* Free the EM */ +-out_host_put: +- scsi_host_put(lp->host); +-out_put_dev: +- dev_put(net_dev); +- return rc; +-} +- +-void fcoe_clean_pending_queue(struct fc_lport *lp) +-{ +- struct fcoe_softc *fc = lp->drv_priv; +- struct sk_buff *skb; +- +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +- kfree_skb(skb); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- } +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +-} +diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c +new file mode 100644 +index 0000000..3cf5ad6 +--- /dev/null ++++ b/drivers/scsi/fcoe/fcoe_sw.c +@@ -0,0 +1,532 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * FCOE protocol file ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include "fcoe_def.h" ++ ++#define FCOE_VERSION "0.1" ++ ++#define FCOE_MAX_LUN 255 ++#define FCOE_MAX_FCP_TARGET 256 ++ ++#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 ++ ++#define FCOE_MIN_XID 0x0004 ++#define FCOE_MAX_XID 0x07ef ++ ++LIST_HEAD(fcoe_hostlist); ++DEFINE_RWLOCK(fcoe_hostlist_lock); ++DEFINE_TIMER(fcoe_timer, NULL, 0, 0); ++struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; ++ ++static struct scsi_transport_template *fcoe_transport_template; ++ ++static int fcoe_reset(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lport = shost_priv(shost); ++ fc_lport_reset(lport); ++ return 0; ++} ++ ++struct fc_function_template fcoe_transport_function = { ++ .show_host_node_name = 1, ++ .show_host_port_name = 1, ++ .show_host_supported_classes = 1, ++ .show_host_supported_fc4s = 1, ++ .show_host_active_fc4s = 1, ++ .show_host_maxframe_size = 1, ++ ++ .show_host_port_id = 1, ++ .show_host_supported_speeds = 1, ++ .get_host_speed = fc_get_host_speed, ++ .show_host_speed = 1, ++ .show_host_port_type = 1, ++ .get_host_port_state = fc_get_host_port_state, ++ .show_host_port_state = 1, ++ .show_host_symbolic_name = 1, ++ ++ .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), ++ .show_rport_maxframe_size = 1, ++ .show_rport_supported_classes = 1, ++ ++ .show_host_fabric_name = 1, ++ .show_starget_node_name = 1, ++ .show_starget_port_name = 1, ++ .show_starget_port_id = 1, ++ .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, ++ .show_rport_dev_loss_tmo = 1, ++ .get_fc_host_stats = fc_get_host_stats, ++ .issue_fc_host_lip = fcoe_reset, ++ ++ .terminate_rport_io = fc_rport_terminate_io, ++}; ++ ++static struct fcoe_softc *fcoe_find_fc_lport(const struct net_device *netdev) ++{ ++ struct fcoe_softc *fc; ++ ++ read_lock(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ if (fc->real_dev == netdev) { ++ read_unlock(&fcoe_hostlist_lock); ++ return fc; ++ } ++ } ++ read_unlock(&fcoe_hostlist_lock); ++ return NULL; ++} ++ ++/* ++ * Convert 48-bit IEEE MAC address to 64-bit FC WWN. ++ */ ++static u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], ++ unsigned int scheme, unsigned int port) ++{ ++ u64 wwn; ++ u64 host_mac; ++ ++ /* The MAC is in NO, so flip only the low 48 bits */ ++ host_mac = ((u64) mac[0] << 40) | ++ ((u64) mac[1] << 32) | ++ ((u64) mac[2] << 24) | ++ ((u64) mac[3] << 16) | ++ ((u64) mac[4] << 8) | ++ (u64) mac[5]; ++ ++ WARN_ON(host_mac >= (1ULL << 48)); ++ wwn = host_mac | ((u64) scheme << 60); ++ switch (scheme) { ++ case 1: ++ WARN_ON(port != 0); ++ break; ++ case 2: ++ WARN_ON(port >= 0xfff); ++ wwn |= (u64) port << 48; ++ break; ++ default: ++ WARN_ON(1); ++ break; ++ } ++ ++ return wwn; ++} ++ ++static struct scsi_host_template fcoe_driver_template = { ++ .module = THIS_MODULE, ++ .name = "FCoE Driver", ++ .proc_name = FCOE_DRIVER_NAME, ++ .queuecommand = fc_queuecommand, ++ .eh_abort_handler = fc_eh_abort, ++ .eh_device_reset_handler = fc_eh_device_reset, ++ .eh_host_reset_handler = fc_eh_host_reset, ++ .slave_alloc = fc_slave_alloc, ++ .change_queue_depth = fc_change_queue_depth, ++ .change_queue_type = fc_change_queue_type, ++ .this_id = -1, ++ .cmd_per_lun = 32, ++ .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, ++ .use_clustering = ENABLE_CLUSTERING, ++ .sg_tablesize = 4, ++ .max_sectors = 0xffff, ++}; ++ ++int fcoe_destroy_interface(struct net_device *netdev) ++{ ++ int cpu, idx; ++ struct fcoe_dev_stats *p; ++ struct fcoe_percpu_s *pp; ++ struct fcoe_softc *fc; ++ struct fcoe_rcv_info *fr; ++ struct sk_buff_head *list; ++ struct sk_buff *skb, *next; ++ struct sk_buff *head; ++ struct fc_lport *lp; ++ u8 flogi_maddr[ETH_ALEN]; ++ ++ fc = fcoe_find_fc_lport(netdev); ++ if (!fc) ++ return -ENODEV; ++ ++ lp = fc->lp; ++ ++ /* Remove the instance from fcoe's list */ ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_del(&fc->list); ++ write_unlock_bh(&fcoe_hostlist_lock); ++ ++ /* Don't listen for Ethernet packets anymore */ ++ dev_remove_pack(&fc->fcoe_packet_type); ++ ++ /* Detach from the scsi-ml */ ++ fc_remove_host(lp->host); ++ scsi_remove_host(lp->host); ++ ++ /* Cleanup the fc_lport */ ++ fc_lport_destroy(lp); ++ fc_fcp_destroy(lp); ++ if (lp->emp) ++ fc_exch_mgr_free(lp->emp); ++ ++ /* Delete secondary MAC addresses */ ++ rtnl_lock(); ++ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); ++ dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); ++ if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) ++ dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ /* Free the per-CPU revieve threads */ ++ for (idx = 0; idx < NR_CPUS; idx++) { ++ if (fcoe_percpu[idx]) { ++ pp = fcoe_percpu[idx]; ++ spin_lock_bh(&pp->fcoe_rx_list.lock); ++ list = &pp->fcoe_rx_list; ++ head = list->next; ++ for (skb = head; skb != (struct sk_buff *)list; ++ skb = next) { ++ next = skb->next; ++ fr = fcoe_dev_from_skb(skb); ++ if (fr->fr_dev == fc->lp) { ++ __skb_unlink(skb, list); ++ kfree_skb(skb); ++ } ++ } ++ spin_unlock_bh(&pp->fcoe_rx_list.lock); ++ } ++ } ++ ++ /* Free existing skbs */ ++ fcoe_clean_pending_queue(lp); ++ ++ /* Free memory used by statistical counters */ ++ for_each_online_cpu(cpu) { ++ p = lp->dev_stats[cpu]; ++ if (p) { ++ lp->dev_stats[cpu] = NULL; ++ kfree(p); ++ } ++ } ++ ++ /* Release the net_device and Scsi_Host */ ++ dev_put(fc->real_dev); ++ scsi_host_put(lp->host); ++ return 0; ++} ++ ++/* ++ * Return zero if link is OK for use by FCoE. ++ * Any permanently-disqualifying conditions have been previously checked. ++ * This also updates the speed setting, which may change with link for 100/1000. ++ * ++ * This function should probably be checking for PAUSE support at some point ++ * in the future. Currently Per-priority-pause is not determinable using ++ * ethtool, so we shouldn't be restrictive until that problem is resolved. ++ */ ++int fcoe_link_ok(struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; ++ struct net_device *dev = fc->real_dev; ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ int rc = 0; ++ ++ if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { ++ dev = fc->phys_dev; ++ if (dev->ethtool_ops->get_settings) { ++ dev->ethtool_ops->get_settings(dev, &ecmd); ++ lp->link_supported_speeds &= ++ ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); ++ if (ecmd.supported & (SUPPORTED_1000baseT_Half | ++ SUPPORTED_1000baseT_Full)) ++ lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; ++ if (ecmd.supported & SUPPORTED_10000baseT_Full) ++ lp->link_supported_speeds |= ++ FC_PORTSPEED_10GBIT; ++ if (ecmd.speed == SPEED_1000) ++ lp->link_speed = FC_PORTSPEED_1GBIT; ++ if (ecmd.speed == SPEED_10000) ++ lp->link_speed = FC_PORTSPEED_10GBIT; ++ } ++ } else ++ rc = -1; ++ ++ return rc; ++} ++ ++static struct libfc_function_template fcoe_libfc_fcn_templ = { ++ .frame_send = fcoe_xmit, ++}; ++ ++static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) ++{ ++ int i = 0; ++ struct fcoe_dev_stats *p; ++ ++ lp->host = shost; ++ lp->drv_priv = (void *)(lp + 1); ++ ++ lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, ++ FCOE_MIN_XID, FCOE_MAX_XID); ++ if (!lp->emp) ++ return -ENOMEM; ++ ++ lp->link_status = 0; ++ lp->max_retry_count = 3; ++ lp->e_d_tov = 2 * 1000; /* FC-FS default */ ++ lp->r_a_tov = 2 * 2 * 1000; ++ lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | ++ FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); ++ ++ /* ++ * allocate per cpu stats block ++ */ ++ for_each_online_cpu(i) { ++ p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); ++ if (p) ++ lp->dev_stats[i] = p; ++ } ++ ++ /* Finish fc_lport configuration */ ++ fc_lport_config(lp); ++ ++ return 0; ++} ++ ++static int net_config(struct fc_lport *lp) ++{ ++ u32 mfs; ++ u64 wwnn, wwpn; ++ struct net_device *net_dev; ++ struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; ++ u8 flogi_maddr[ETH_ALEN]; ++ ++ /* Require support for get_pauseparam ethtool op. */ ++ net_dev = fc->real_dev; ++ if (!net_dev->ethtool_ops && (net_dev->priv_flags & IFF_802_1Q_VLAN)) ++ net_dev = vlan_dev_real_dev(net_dev); ++ if (!net_dev->ethtool_ops || !net_dev->ethtool_ops->get_pauseparam) ++ return -EOPNOTSUPP; ++ ++ fc->phys_dev = net_dev; ++ ++ /* Do not support for bonding device */ ++ if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || ++ (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || ++ (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { ++ return -EOPNOTSUPP; ++ } ++ ++ /* ++ * Determine max frame size based on underlying device and optional ++ * user-configured limit. If the MFS is too low, fcoe_link_ok() ++ * will return 0, so do this first. ++ */ ++ mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + ++ sizeof(struct fcoe_crc_eof)); ++ fc_set_mfs(lp, mfs); ++ ++ lp->link_status = ~FC_PAUSE & ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ lp->link_status |= FC_LINK_UP; ++ ++ if (fc->real_dev->features & NETIF_F_SG) ++ lp->sg_supp = 1; ++ ++ ++ skb_queue_head_init(&fc->fcoe_pending_queue); ++ ++ /* setup Source Mac Address */ ++ memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, ++ fc->real_dev->addr_len); ++ ++ wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); ++ fc_set_wwnn(lp, wwnn); ++ /* XXX - 3rd arg needs to be vlan id */ ++ wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); ++ fc_set_wwpn(lp, wwpn); ++ ++ /* ++ * Add FCoE MAC address as second unicast MAC address ++ * or enter promiscuous mode if not capable of listening ++ * for multiple unicast MACs. ++ */ ++ rtnl_lock(); ++ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); ++ dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ /* ++ * setup the receive function from ethernet driver ++ * on the ethertype for the given device ++ */ ++ fc->fcoe_packet_type.func = fcoe_rcv; ++ fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); ++ fc->fcoe_packet_type.dev = fc->real_dev; ++ dev_add_pack(&fc->fcoe_packet_type); ++ ++ return 0; ++} ++ ++static void shost_config(struct fc_lport *lp) ++{ ++ lp->host->max_lun = FCOE_MAX_LUN; ++ lp->host->max_id = FCOE_MAX_FCP_TARGET; ++ lp->host->max_channel = 0; ++ lp->host->transportt = fcoe_transport_template; ++} ++ ++static int libfc_config(struct fc_lport *lp) ++{ ++ /* Set the function pointers set by the LLDD */ ++ memcpy(&lp->tt, &fcoe_libfc_fcn_templ, ++ sizeof(struct libfc_function_template)); ++ ++ if (fc_fcp_init(lp)) ++ return -ENOMEM; ++ fc_exch_init(lp); ++ fc_lport_init(lp); ++ fc_rport_init(lp); ++ fc_disc_init(lp); ++ ++ return 0; ++} ++ ++/* ++ * This function creates the fcoe interface ++ * create struct fcdev which is a shared structure between opefc ++ * and transport level protocol. ++ */ ++int fcoe_create_interface(struct net_device *netdev) ++{ ++ struct fc_lport *lp = NULL; ++ struct fcoe_softc *fc; ++ struct Scsi_Host *shost; ++ int rc = 0; ++ ++ if (fcoe_find_fc_lport(netdev) != NULL) ++ return -EEXIST; ++ ++ shost = scsi_host_alloc(&fcoe_driver_template, ++ sizeof(struct fc_lport) + ++ sizeof(struct fcoe_softc)); ++ ++ if (!shost) { ++ FC_DBG("Could not allocate host structure\n"); ++ return -ENOMEM; ++ } ++ ++ lp = shost_priv(shost); ++ rc = lport_config(lp, shost); ++ if (rc) ++ goto out_host_put; ++ ++ /* Configure the fcoe_softc */ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ fc->lp = lp; ++ fc->real_dev = netdev; ++ shost_config(lp); ++ ++ ++ /* Add the new host to the SCSI-ml */ ++ rc = scsi_add_host(lp->host, NULL); ++ if (rc) { ++ FC_DBG("error on scsi_add_host\n"); ++ goto out_lp_destroy; ++ } ++ ++ sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", ++ FCOE_DRIVER_NAME, FCOE_VERSION, ++ netdev->name); ++ ++ /* Configure netdev and networking properties of the lp */ ++ rc = net_config(lp); ++ if (rc) ++ goto out_lp_destroy; ++ ++ /* Initialize the library */ ++ rc = libfc_config(lp); ++ if (rc) ++ goto out_lp_destroy; ++ ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_add_tail(&fc->list, &fcoe_hostlist); ++ write_unlock_bh(&fcoe_hostlist_lock); ++ ++ lp->boot_time = jiffies; ++ ++ fc_fabric_login(lp); ++ ++ dev_hold(netdev); ++ return rc; ++ ++out_lp_destroy: ++ fc_exch_mgr_free(lp->emp); /* Free the EM */ ++out_host_put: ++ scsi_host_put(lp->host); ++ return rc; ++} ++ ++void fcoe_clean_pending_queue(struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc = lp->drv_priv; ++ struct sk_buff *skb; ++ ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ kfree_skb(skb); ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ } ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} ++ ++int __init fcoe_sw_init(void) ++{ ++ fcoe_transport_template = ++ fc_attach_transport(&fcoe_transport_function); ++ return fcoe_transport_template ? 0 : -1; ++} ++ ++void __exit fcoe_sw_exit(void) ++{ ++ fc_release_transport(fcoe_transport_template); ++} +diff --git a/drivers/scsi/fcoe/fcoeinit.c b/drivers/scsi/fcoe/fcoeinit.c +deleted file mode 100644 +index 7d52ed5..0000000 +--- a/drivers/scsi/fcoe/fcoeinit.c ++++ /dev/null +@@ -1,440 +0,0 @@ +-/* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include "fcoe_def.h" +- +-MODULE_AUTHOR("Open-FCoE.org"); +-MODULE_DESCRIPTION("FCoE"); +-MODULE_LICENSE("GPL"); +- +-/* +- * Static functions and variables definations +- */ +-#ifdef CONFIG_HOTPLUG_CPU +-static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); +-#endif /* CONFIG_HOTPLUG_CPU */ +-static int fcoe_device_notification(struct notifier_block *, ulong, void *); +-static void fcoe_dev_setup(void); +-static void fcoe_dev_cleanup(void); +- +-struct scsi_transport_template *fcoe_transport_template; +- +-static int fcoe_reset(struct Scsi_Host *shost) +-{ +- struct fc_lport *lport = shost_priv(shost); +- fc_lport_reset(lport); +- return 0; +-} +- +-struct fc_function_template fcoe_transport_function = { +- .show_host_node_name = 1, +- .show_host_port_name = 1, +- .show_host_supported_classes = 1, +- .show_host_supported_fc4s = 1, +- .show_host_active_fc4s = 1, +- .show_host_maxframe_size = 1, +- +- .show_host_port_id = 1, +- .show_host_supported_speeds = 1, +- .get_host_speed = fc_get_host_speed, +- .show_host_speed = 1, +- .show_host_port_type = 1, +- .get_host_port_state = fc_get_host_port_state, +- .show_host_port_state = 1, +- .show_host_symbolic_name = 1, +- +- .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), +- .show_rport_maxframe_size = 1, +- .show_rport_supported_classes = 1, +- +- .show_host_fabric_name = 1, +- .show_starget_node_name = 1, +- .show_starget_port_name = 1, +- .show_starget_port_id = 1, +- .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, +- .show_rport_dev_loss_tmo = 1, +- .get_fc_host_stats = fc_get_host_stats, +- .issue_fc_host_lip = fcoe_reset, +- +- .terminate_rport_io = fc_rport_terminate_io, +-}; +- +-struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; +- +-#ifdef CONFIG_HOTPLUG_CPU +-static struct notifier_block fcoe_cpu_notifier = { +- .notifier_call = fcoe_cpu_callback, +-}; +-#endif /* CONFIG_HOTPLUG_CPU */ +- +-/* +- * notification function from net device +- */ +-static struct notifier_block fcoe_notifier = { +- .notifier_call = fcoe_device_notification, +-}; +- +-#ifdef CONFIG_HOTPLUG_CPU +-/* +- * create percpu stats block +- * called by cpu add/remove notifier +- */ +-static void fcoe_create_percpu_data(int cpu) +-{ +- struct fc_lport *lp; +- struct fcoe_softc *fc; +- struct fcoe_dev_stats *p; +- struct fcoe_info *fci = &fcoei; +- +- write_lock_bh(&fci->fcoe_hostlist_lock); +- list_for_each_entry(fc, &fci->fcoe_hostlist, list) { +- lp = fc->lp; +- if (lp->dev_stats[cpu] == NULL) { +- p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); +- if (p) +- lp->dev_stats[cpu] = p; +- } +- } +- write_unlock_bh(&fci->fcoe_hostlist_lock); +-} +- +-/* +- * destroy percpu stats block +- * called by cpu add/remove notifier +- */ +-static void fcoe_destroy_percpu_data(int cpu) +-{ +- struct fcoe_dev_stats *p; +- struct fc_lport *lp; +- struct fcoe_softc *fc; +- struct fcoe_info *fci = &fcoei; +- +- write_lock_bh(&fci->fcoe_hostlist_lock); +- list_for_each_entry(fc, &fci->fcoe_hostlist, list) { +- lp = fc->lp; +- p = lp->dev_stats[cpu]; +- if (p != NULL) { +- lp->dev_stats[cpu] = NULL; +- kfree(p); +- } +- } +- write_unlock_bh(&fci->fcoe_hostlist_lock); +-} +- +-/* +- * Get notified when a cpu comes on/off. Be hotplug friendly. +- */ +-static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action, +- void *hcpu) +-{ +- unsigned int cpu = (unsigned long)hcpu; +- +- switch (action) { +- case CPU_ONLINE: +- fcoe_create_percpu_data(cpu); +- break; +- case CPU_DEAD: +- fcoe_destroy_percpu_data(cpu); +- break; +- default: +- break; +- } +- return NOTIFY_OK; +-} +-#endif /* CONFIG_HOTPLUG_CPU */ +- +-/* +- * function to setup link change notification interface +- */ +-static void fcoe_dev_setup(void) +-{ +- /* +- * here setup a interface specific wd time to +- * monitor the link state +- */ +- register_netdevice_notifier(&fcoe_notifier); +-} +- +-/* +- * function to cleanup link change notification interface +- */ +-static void fcoe_dev_cleanup(void) +-{ +- unregister_netdevice_notifier(&fcoe_notifier); +-} +- +-/* +- * This function is called by the ethernet driver +- * this is called in case of link change event +- */ +-static int fcoe_device_notification(struct notifier_block *notifier, +- ulong event, void *ptr) +-{ +- struct fc_lport *lp = NULL; +- struct net_device *real_dev = ptr; +- struct fcoe_softc *fc; +- struct fcoe_dev_stats *stats; +- struct fcoe_info *fci = &fcoei; +- u16 new_status; +- u32 mfs; +- int rc = NOTIFY_OK; +- +- read_lock(&fci->fcoe_hostlist_lock); +- list_for_each_entry(fc, &fci->fcoe_hostlist, list) { +- if (fc->real_dev == real_dev) { +- lp = fc->lp; +- break; +- } +- } +- read_unlock(&fci->fcoe_hostlist_lock); +- if (lp == NULL) { +- rc = NOTIFY_DONE; +- goto out; +- } +- +- new_status = lp->link_status; +- switch (event) { +- case NETDEV_DOWN: +- case NETDEV_GOING_DOWN: +- new_status &= ~FC_LINK_UP; +- break; +- case NETDEV_UP: +- case NETDEV_CHANGE: +- new_status &= ~FC_LINK_UP; +- if (!fcoe_link_ok(lp)) +- new_status |= FC_LINK_UP; +- break; +- case NETDEV_CHANGEMTU: +- mfs = fc->real_dev->mtu - +- (sizeof(struct fcoe_hdr) + +- sizeof(struct fcoe_crc_eof)); +- if (fc->user_mfs && fc->user_mfs < mfs) +- mfs = fc->user_mfs; +- if (mfs >= FC_MIN_MAX_FRAME) +- fc_set_mfs(lp, mfs); +- new_status &= ~FC_LINK_UP; +- if (!fcoe_link_ok(lp)) +- new_status |= FC_LINK_UP; +- break; +- case NETDEV_REGISTER: +- break; +- default: +- FC_DBG("unknown event %ld call", event); +- } +- if (lp->link_status != new_status) { +- if ((new_status & FC_LINK_UP) == FC_LINK_UP) +- fc_linkup(lp); +- else { +- stats = lp->dev_stats[smp_processor_id()]; +- stats->LinkFailureCount++; +- fc_linkdown(lp); +- fcoe_clean_pending_queue(lp); +- } +- } +-out: +- return rc; +-} +- +-static void trimstr(char *str, int len) +-{ +- char *cp = str + len; +- while (--cp >= str && *cp == '\n') +- *cp = '\0'; +-} +- +-static ssize_t fcoe_destroy(struct kobject *kobj, struct kobj_attribute *attr, +- const char *buffer, size_t size) +-{ +- char ifname[40]; +- strcpy(ifname, buffer); +- trimstr(ifname, strlen(ifname)); +- fcoe_destroy_interface(ifname); +- return size; +-} +- +-static ssize_t fcoe_create(struct kobject *kobj, struct kobj_attribute *attr, +- const char *buffer, size_t size) +-{ +- char ifname[40]; +- strcpy(ifname, buffer); +- trimstr(ifname, strlen(ifname)); +- fcoe_create_interface(ifname); +- return size; +-} +- +-static const struct kobj_attribute fcoe_destroyattr = \ +- __ATTR(destroy, S_IWUSR, NULL, fcoe_destroy); +-static const struct kobj_attribute fcoe_createattr = \ +- __ATTR(create, S_IWUSR, NULL, fcoe_create); +- +-/* +- * Initialization routine +- * 1. Will create fc transport software structure +- * 2. initialize the link list of port information structure +- */ +-static int __init fcoeinit(void) +-{ +- int rc = 0; +- int cpu; +- struct fcoe_percpu_s *p; +- struct fcoe_info *fci = &fcoei; +- +- rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, +- &fcoe_destroyattr.attr); +- if (!rc) +- rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, +- &fcoe_createattr.attr); +- +- if (rc) +- return rc; +- +- rwlock_init(&fci->fcoe_hostlist_lock); +- +-#ifdef CONFIG_HOTPLUG_CPU +- register_cpu_notifier(&fcoe_cpu_notifier); +-#endif /* CONFIG_HOTPLUG_CPU */ +- +- /* +- * initialize per CPU interrupt thread +- */ +- for_each_online_cpu(cpu) { +- p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL); +- if (p) { +- p->thread = kthread_create(fcoe_percpu_receive_thread, +- (void *)p, +- "fcoethread/%d", cpu); +- +- /* +- * if there is no error then bind the thread to the cpu +- * initialize the semaphore and skb queue head +- */ +- if (likely(!IS_ERR(p->thread))) { +- p->cpu = cpu; +- fci->fcoe_percpu[cpu] = p; +- skb_queue_head_init(&p->fcoe_rx_list); +- kthread_bind(p->thread, cpu); +- wake_up_process(p->thread); +- } else { +- fci->fcoe_percpu[cpu] = NULL; +- kfree(p); +- +- } +- } +- } +- if (rc < 0) { +- FC_DBG("failed to initialize proc intrerface\n"); +- rc = -ENODEV; +- goto out_chrdev; +- } +- +- /* +- * setup link change notification +- */ +- fcoe_dev_setup(); +- +- init_timer(&fci->timer); +- fci->timer.data = (ulong) fci; +- fci->timer.function = fcoe_watchdog; +- fci->timer.expires = (jiffies + (10 * HZ)); +- add_timer(&fci->timer); +- +- fcoe_transport_template = +- fc_attach_transport(&fcoe_transport_function); +- +- if (fcoe_transport_template == NULL) { +- FC_DBG("fail to attach fc transport"); +- return -1; +- } +- +- return 0; +- +-out_chrdev: +-#ifdef CONFIG_HOTPLUG_CPU +- unregister_cpu_notifier(&fcoe_cpu_notifier); +-#endif /* CONFIG_HOTPLUG_CPU */ +- return rc; +-} +- +-static void __exit fcoe_exit(void) +-{ +- u32 idx; +- struct fcoe_softc *fc, *tmp; +- struct fc_lport *lp; +- struct fcoe_info *fci = &fcoei; +- struct fcoe_percpu_s *p; +- struct sk_buff *skb; +- +- /* +- * Stop all call back interfaces +- */ +-#ifdef CONFIG_HOTPLUG_CPU +- unregister_cpu_notifier(&fcoe_cpu_notifier); +-#endif /* CONFIG_HOTPLUG_CPU */ +- fcoe_dev_cleanup(); +- +- /* +- * stop timer +- */ +- del_timer_sync(&fci->timer); +- +- /* +- * assuming that at this time there will be no +- * ioctl in prograss, therefore we do not need to lock the +- * list. +- */ +- list_for_each_entry_safe(fc, tmp, &fci->fcoe_hostlist, list) { +- lp = fc->lp; +- fcoe_destroy_interface(lp->ifname); +- } +- +- for (idx = 0; idx < NR_CPUS; idx++) { +- if (fci->fcoe_percpu[idx]) { +- kthread_stop(fci->fcoe_percpu[idx]->thread); +- p = fci->fcoe_percpu[idx]; +- spin_lock_bh(&p->fcoe_rx_list.lock); +- while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) +- kfree_skb(skb); +- spin_unlock_bh(&p->fcoe_rx_list.lock); +- if (fci->fcoe_percpu[idx]->crc_eof_page) +- put_page(fci->fcoe_percpu[idx]->crc_eof_page); +- kfree(fci->fcoe_percpu[idx]); +- } +- } +- +- fc_release_transport(fcoe_transport_template); +-} +- +-module_init(fcoeinit); +-module_exit(fcoe_exit); +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +new file mode 100644 +index 0000000..93c47aa +--- /dev/null ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -0,0 +1,632 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * FCOE protocol file ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#include ++#include "fcoe_def.h" ++ ++static int debug_fcoe; ++ ++#define FCOE_MAX_QUEUE_DEPTH 256 ++ ++/* destination address mode */ ++#define FCOE_GW_ADDR_MODE 0x00 ++#define FCOE_FCOUI_ADDR_MODE 0x01 ++ ++/* Function Prototyes */ ++static int fcoe_check_wait_queue(struct fc_lport *); ++static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *); ++static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *); ++static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); ++ ++/* ++ * this is the fcoe receive function ++ * called by NET_RX_SOFTIRQ ++ * this function will receive the packet and ++ * build fc frame and pass it up ++ */ ++int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, ++ struct packet_type *ptype, struct net_device *olddev) ++{ ++ struct fc_lport *lp; ++ struct fcoe_rcv_info *fr; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *stats; ++ u8 *data; ++ struct fc_frame_header *fh; ++ unsigned short oxid; ++ int cpu_idx; ++ struct fcoe_percpu_s *fps; ++ ++ fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); ++ lp = fc->lp; ++ if (unlikely(lp == NULL)) { ++ FC_DBG("cannot find hba structure"); ++ goto err2; ++ } ++ ++ if (unlikely(debug_fcoe)) { ++ FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " ++ "end:%p sum:%d dev:%s", skb->len, skb->data_len, ++ skb->head, skb->data, skb_tail_pointer(skb), ++ skb_end_pointer(skb), skb->csum, ++ skb->dev ? skb->dev->name : ""); ++ ++ } ++ ++ /* check for FCOE packet type */ ++ if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { ++ FC_DBG("wrong FC type frame"); ++ goto err; ++ } ++ data = skb->data; ++ data += sizeof(struct fcoe_hdr); ++ fh = (struct fc_frame_header *)data; ++ oxid = ntohs(fh->fh_ox_id); ++ ++ fr = fcoe_dev_from_skb(skb); ++ fr->fr_dev = lp; ++ fr->ptype = ptype; ++ cpu_idx = 0; ++#ifdef CONFIG_SMP ++ /* ++ * The exchange ID are ANDed with num of online CPUs, ++ * so that will have the least lock contention in ++ * handling the exchange. if there is no thread ++ * for a given idx then use first online cpu. ++ */ ++ cpu_idx = oxid & (num_online_cpus() >> 1); ++ if (fcoe_percpu[cpu_idx] == NULL) ++ cpu_idx = first_cpu(cpu_online_map); ++#endif ++ fps = fcoe_percpu[cpu_idx]; ++ ++ spin_lock_bh(&fps->fcoe_rx_list.lock); ++ __skb_queue_tail(&fps->fcoe_rx_list, skb); ++ if (fps->fcoe_rx_list.qlen == 1) ++ wake_up_process(fps->thread); ++ ++ spin_unlock_bh(&fps->fcoe_rx_list.lock); ++ ++ return 0; ++err: ++#ifdef CONFIG_SMP ++ stats = lp->dev_stats[smp_processor_id()]; ++#else ++ stats = lp->dev_stats[0]; ++#endif ++ stats->ErrorFrames++; ++ ++err2: ++ kfree_skb(skb); ++ return -1; ++} ++ ++static inline int fcoe_start_io(struct sk_buff *skb) ++{ ++ int rc; ++ ++ skb_get(skb); ++ rc = dev_queue_xmit(skb); ++ if (rc != 0) ++ return rc; ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) ++{ ++ struct fcoe_percpu_s *fps; ++ struct page *page; ++ int cpu_idx; ++ ++ cpu_idx = get_cpu(); ++ fps = fcoe_percpu[cpu_idx]; ++ page = fps->crc_eof_page; ++ if (!page) { ++ page = alloc_page(GFP_ATOMIC); ++ if (!page) { ++ put_cpu(); ++ return -ENOMEM; ++ } ++ fps->crc_eof_page = page; ++ WARN_ON(fps->crc_eof_offset != 0); ++ } ++ ++ get_page(page); ++ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, ++ fps->crc_eof_offset, tlen); ++ skb->len += tlen; ++ skb->data_len += tlen; ++ skb->truesize += tlen; ++ fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); ++ ++ if (fps->crc_eof_offset >= PAGE_SIZE) { ++ fps->crc_eof_page = NULL; ++ fps->crc_eof_offset = 0; ++ put_page(page); ++ } ++ put_cpu(); ++ return 0; ++} ++ ++/* ++ * this is the frame xmit routine ++ */ ++int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ int indx; ++ int wlen, rc = 0; ++ u32 crc; ++ struct ethhdr *eh; ++ struct fcoe_crc_eof *cp; ++ struct sk_buff *skb; ++ struct fcoe_dev_stats *stats; ++ struct fc_frame_header *fh; ++ unsigned int hlen; /* header length implies the version */ ++ unsigned int tlen; /* trailer length */ ++ int flogi_in_progress = 0; ++ struct fcoe_softc *fc; ++ void *data; ++ u8 sof, eof; ++ struct fcoe_hdr *hp; ++ ++ WARN_ON((fr_len(fp) % sizeof(u32)) != 0); ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ /* ++ * if it is a flogi then we need to learn gw-addr ++ * and my own fcid ++ */ ++ fh = fc_frame_header_get(fp); ++ if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { ++ if (fc_frame_payload_op(fp) == ELS_FLOGI) { ++ fc->flogi_oxid = ntohs(fh->fh_ox_id); ++ fc->address_mode = FCOE_FCOUI_ADDR_MODE; ++ fc->flogi_progress = 1; ++ flogi_in_progress = 1; ++ } else if (fc->flogi_progress && ntoh24(fh->fh_s_id) != 0) { ++ /* ++ * Here we must've gotten an SID by accepting an FLOGI ++ * from a point-to-point connection. Switch to using ++ * the source mac based on the SID. The destination ++ * MAC in this case would have been set by receving the ++ * FLOGI. ++ */ ++ fc_fcoe_set_mac(fc->data_src_addr, fh->fh_s_id); ++ fc->flogi_progress = 0; ++ } ++ } ++ ++ skb = fp_skb(fp); ++ sof = fr_sof(fp); ++ eof = fr_eof(fp); ++ ++ crc = ~0; ++ crc = crc32(crc, skb->data, skb_headlen(skb)); ++ ++ for (indx = 0; indx < skb_shinfo(skb)->nr_frags; indx++) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[indx]; ++ unsigned long off = frag->page_offset; ++ unsigned long len = frag->size; ++ ++ while (len > 0) { ++ unsigned long clen; ++ ++ clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); ++ data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), ++ KM_SKB_DATA_SOFTIRQ); ++ crc = crc32(crc, data + (off & ~PAGE_MASK), ++ clen); ++ kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); ++ off += clen; ++ len -= clen; ++ } ++ } ++ ++ /* ++ * Get header and trailer lengths. ++ * This is temporary code until we get rid of the old protocol. ++ * Both versions have essentially the same trailer layout but T11 ++ * has padding afterwards. ++ */ ++ hlen = sizeof(struct fcoe_hdr); ++ tlen = sizeof(struct fcoe_crc_eof); ++ ++ /* ++ * copy fc crc and eof to the skb buff ++ * Use utility buffer in the fc_frame part of the sk_buff for the ++ * trailer. ++ * We don't do a get_page for this frag, since that page may not be ++ * managed that way. So that skb_free() doesn't do that either, we ++ * setup the destructor to remove this frag. ++ */ ++ if (skb_is_nonlinear(skb)) { ++ skb_frag_t *frag; ++ if (fcoe_get_paged_crc_eof(skb, tlen)) { ++ kfree(skb); ++ return -ENOMEM; ++ } ++ frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; ++ cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) ++ + frag->page_offset; ++ } else { ++ cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); ++ } ++ ++ cp->fcoe_eof = eof; ++ cp->fcoe_crc32 = cpu_to_le32(~crc); ++ if (tlen == sizeof(*cp)) ++ memset(cp->fcoe_resvd, 0, sizeof(cp->fcoe_resvd)); ++ wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; ++ ++ if (skb_is_nonlinear(skb)) { ++ kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); ++ cp = NULL; ++ } ++ ++ /* ++ * Fill in the control structures ++ */ ++ skb->ip_summed = CHECKSUM_NONE; ++ eh = (struct ethhdr *)skb_push(skb, hlen + sizeof(struct ethhdr)); ++ if (fc->address_mode == FCOE_FCOUI_ADDR_MODE) ++ fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); ++ else ++ /* insert GW address */ ++ memcpy(eh->h_dest, fc->dest_addr, ETH_ALEN); ++ ++ if (unlikely(flogi_in_progress)) ++ memcpy(eh->h_source, fc->ctl_src_addr, ETH_ALEN); ++ else ++ memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); ++ ++ eh->h_proto = htons(ETH_P_FCOE); ++ skb->protocol = htons(ETH_P_802_3); ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ ++ hp = (struct fcoe_hdr *)(eh + 1); ++ memset(hp, 0, sizeof(*hp)); ++ if (FC_FCOE_VER) ++ FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); ++ hp->fcoe_sof = sof; ++ ++ stats = lp->dev_stats[smp_processor_id()]; ++ stats->TxFrames++; ++ stats->TxWords += wlen; ++ skb->dev = fc->real_dev; ++ ++ fr_dev(fp) = lp; ++ if (fc->fcoe_pending_queue.qlen) ++ rc = fcoe_check_wait_queue(lp); ++ ++ if (rc == 0) ++ rc = fcoe_start_io(skb); ++ ++ if (rc) { ++ fcoe_insert_wait_queue(lp, skb); ++ if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) ++ fc_pause(lp); ++ } ++ ++ return 0; ++} ++ ++int fcoe_percpu_receive_thread(void *arg) ++{ ++ struct fcoe_percpu_s *p = arg; ++ u32 fr_len; ++ unsigned int hlen; ++ unsigned int tlen; ++ struct fc_lport *lp; ++ struct fcoe_rcv_info *fr; ++ struct fcoe_dev_stats *stats; ++ struct fc_frame_header *fh; ++ struct sk_buff *skb; ++ struct fcoe_crc_eof *cp; ++ enum fc_sof sof; ++ struct fc_frame *fp; ++ u8 *mac = NULL; ++ struct fcoe_softc *fc; ++ struct fcoe_hdr *hp; ++ ++ set_user_nice(current, 19); ++ ++ while (!kthread_should_stop()) { ++ ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ schedule(); ++ set_current_state(TASK_RUNNING); ++ if (kthread_should_stop()) ++ return 0; ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ } ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ fr = fcoe_dev_from_skb(skb); ++ lp = fr->fr_dev; ++ if (unlikely(lp == NULL)) { ++ FC_DBG("invalid HBA Structure"); ++ kfree_skb(skb); ++ continue; ++ } ++ ++ stats = lp->dev_stats[smp_processor_id()]; ++ ++ if (unlikely(debug_fcoe)) { ++ FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p " ++ "tail:%p end:%p sum:%d dev:%s", ++ skb->len, skb->data_len, ++ skb->head, skb->data, skb_tail_pointer(skb), ++ skb_end_pointer(skb), skb->csum, ++ skb->dev ? skb->dev->name : ""); ++ } ++ ++ /* ++ * Save source MAC address before discarding header. ++ */ ++ fc = lp->drv_priv; ++ if (unlikely(fc->flogi_progress)) ++ mac = eth_hdr(skb)->h_source; ++ ++ if (skb_is_nonlinear(skb)) ++ skb_linearize(skb); /* not ideal */ ++ ++ /* ++ * Check the header and pull it off. ++ */ ++ hlen = sizeof(struct fcoe_hdr); ++ ++ hp = (struct fcoe_hdr *)skb->data; ++ if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { ++ if (stats->ErrorFrames < 5) ++ FC_DBG("unknown FCoE version %x", ++ FC_FCOE_DECAPS_VER(hp)); ++ stats->ErrorFrames++; ++ kfree_skb(skb); ++ continue; ++ } ++ sof = hp->fcoe_sof; ++ skb_pull(skb, sizeof(*hp)); ++ fr_len = skb->len - sizeof(struct fcoe_crc_eof); ++ skb_trim(skb, fr_len); ++ tlen = sizeof(struct fcoe_crc_eof); ++ ++ if (unlikely(fr_len > skb->len)) { ++ if (stats->ErrorFrames < 5) ++ FC_DBG("length error fr_len 0x%x skb->len 0x%x", ++ fr_len, skb->len); ++ stats->ErrorFrames++; ++ kfree_skb(skb); ++ continue; ++ } ++ stats->RxFrames++; ++ stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; ++ ++ fp = (struct fc_frame *) skb; ++ fc_frame_init(fp); ++ cp = (struct fcoe_crc_eof *)(skb->data + fr_len); ++ fr_eof(fp) = cp->fcoe_eof; ++ fr_sof(fp) = sof; ++ fr_dev(fp) = lp; ++ ++ /* ++ * Check the CRC here, unless it's solicited data for SCSI. ++ * In that case, the SCSI layer can check it during the copy, ++ * and it'll be more cache-efficient. ++ */ ++ fh = fc_frame_header_get(fp); ++ if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && ++ fh->fh_type == FC_TYPE_FCP) { ++ fr_flags(fp) |= FCPHF_CRC_UNCHECKED; ++ fc_exch_recv(lp, lp->emp, fp); ++ } else if (le32_to_cpu(cp->fcoe_crc32) == ++ ~crc32(~0, skb->data, fr_len)) { ++ if (unlikely(fc->flogi_progress)) ++ fcoe_recv_flogi(fc, fp, mac); ++ fc_exch_recv(lp, lp->emp, fp); ++ } else { ++ if (debug_fcoe || stats->InvalidCRCCount < 5) { ++ printk(KERN_WARNING \ ++ "fcoe: dropping frame with CRC error"); ++ } ++ stats->InvalidCRCCount++; ++ stats->ErrorFrames++; ++ fc_frame_free(fp); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Snoop potential response to FLOGI or even incoming FLOGI. ++ */ ++static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) ++{ ++ struct fc_frame_header *fh; ++ u8 op; ++ ++ fh = fc_frame_header_get(fp); ++ if (fh->fh_type != FC_TYPE_ELS) ++ return; ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && ++ fc->flogi_oxid == ntohs(fh->fh_ox_id)) { ++ /* ++ * FLOGI accepted. ++ * If the src mac addr is FC_OUI-based, then we mark the ++ * address_mode flag to use FC_OUI-based Ethernet DA. ++ * Otherwise we use the FCoE gateway addr ++ */ ++ if (!compare_ether_addr(sa, (u8[6]) FC_FCOE_FLOGI_MAC)) { ++ fc->address_mode = FCOE_FCOUI_ADDR_MODE; ++ } else { ++ memcpy(fc->dest_addr, sa, ETH_ALEN); ++ fc->address_mode = FCOE_GW_ADDR_MODE; ++ } ++ ++ /* ++ * Remove any previously-set unicast MAC filter. ++ * Add secondary FCoE MAC address filter for our OUI. ++ */ ++ rtnl_lock(); ++ if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) ++ dev_unicast_delete(fc->real_dev, fc->data_src_addr, ++ ETH_ALEN); ++ fc_fcoe_set_mac(fc->data_src_addr, fh->fh_d_id); ++ dev_unicast_add(fc->real_dev, fc->data_src_addr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ fc->flogi_progress = 0; ++ } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { ++ /* ++ * Save source MAC for point-to-point responses. ++ */ ++ memcpy(fc->dest_addr, sa, ETH_ALEN); ++ fc->address_mode = FCOE_GW_ADDR_MODE; ++ } ++} ++ ++void fcoe_watchdog(ulong vp) ++{ ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ int paused = 0; ++ ++ read_lock(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ lp = fc->lp; ++ if (lp) { ++ if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) ++ paused = 1; ++ if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) { ++ if (paused) ++ fc_unpause(lp); ++ } ++ } ++ } ++ read_unlock(&fcoe_hostlist_lock); ++ ++ fcoe_timer.expires = jiffies + (1 * HZ); ++ add_timer(&fcoe_timer); ++} ++ ++/* ++ * the wait_queue is used when the skb transmit fails. skb will go ++ * in the wait_queue which will be emptied by the time function OR ++ * by the next skb transmit. ++ * ++ */ ++ ++/* ++ * Function name : fcoe_check_wait_queue() ++ * ++ * Return Values : 0 or error ++ * ++ * Description : empties the wait_queue ++ * dequeue the head of the wait_queue queue and ++ * calls fcoe_start_io() for each packet ++ * if all skb have been transmitted, return 0 ++ * if a error occurs, then restore wait_queue and try again ++ * later ++ * ++ */ ++ ++static int fcoe_check_wait_queue(struct fc_lport *lp) ++{ ++ int rc, unpause = 0; ++ int paused = 0; ++ struct sk_buff *skb; ++ struct fcoe_softc *fc; ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ ++ /* ++ * is this interface paused? ++ */ ++ if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) ++ paused = 1; ++ if (fc->fcoe_pending_queue.qlen) { ++ while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ rc = fcoe_start_io(skb); ++ if (rc) { ++ fcoe_insert_wait_queue_head(lp, skb); ++ return rc; ++ } ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ } ++ if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH) ++ unpause = 1; ++ } ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ if ((unpause) && (paused)) ++ fc_unpause(lp); ++ return fc->fcoe_pending_queue.qlen; ++} ++ ++static void fcoe_insert_wait_queue_head(struct fc_lport *lp, ++ struct sk_buff *skb) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ __skb_queue_head(&fc->fcoe_pending_queue, skb); ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} ++ ++static void fcoe_insert_wait_queue(struct fc_lport *lp, ++ struct sk_buff *skb) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ __skb_queue_tail(&fc->fcoe_pending_queue, skb); ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} +diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c +index 30403aa..f724dd2 100644 +--- a/drivers/scsi/libfc/fc_disc.c ++++ b/drivers/scsi/libfc/fc_disc.c +@@ -19,7 +19,9 @@ + + /* + * Target Discovery +- * Actually, this discovers all FC-4 remote ports, including FCP initiators. ++ * ++ * This block discovers all FC-4 remote ports, including FCP initiators. It ++ * also handles RSCN events and re-discovery if necessary. + */ + + #include +@@ -33,12 +35,18 @@ + #define FC_DISC_RETRY_LIMIT 3 /* max retries */ + #define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ + +-int fc_disc_debug; ++static int fc_disc_debug; ++ ++#define FC_DEBUG_DISC(fmt...) \ ++ do { \ ++ if (fc_disc_debug) \ ++ FC_DBG(fmt); \ ++ } while (0) + + static void fc_disc_gpn_ft_req(struct fc_lport *); + static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); + static int fc_disc_new_target(struct fc_lport *, struct fc_rport *, +- struct fc_rport_identifiers *); ++ struct fc_rport_identifiers *); + static void fc_disc_del_target(struct fc_lport *, struct fc_rport *); + static void fc_disc_done(struct fc_lport *); + static void fc_disc_error(struct fc_lport *, struct fc_frame *); +@@ -47,13 +55,13 @@ static void fc_disc_single(struct fc_lport *, struct fc_disc_port *); + static int fc_disc_restart(struct fc_lport *); + + /** +- * fc_disc_rscn_req - Handle Registered State Change Notification (RSCN) ++ * fc_disc_recv_rscn_req - Handle Registered State Change Notification (RSCN) + * @sp: Current sequence of the RSCN exchange + * @fp: RSCN Frame +- * @lp: Fibre Channel host port instance ++ * @lport: Fibre Channel host port instance + */ +-static void fc_disc_rscn_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lp) ++static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lport) + { + struct fc_els_rscn *rp; + struct fc_els_rscn_page *pp; +@@ -86,12 +94,14 @@ static void fc_disc_rscn_req(struct fc_seq *sp, struct fc_frame *fp, + */ + switch (fmt) { + case ELS_ADDR_FMT_PORT: ++ FC_DEBUG_DISC("Port address format for port (%6x)\n", ++ ntoh24(pp->rscn_fid)); + dp = kzalloc(sizeof(*dp), GFP_KERNEL); + if (!dp) { + redisc = 1; + break; + } +- dp->lp = lp; ++ dp->lp = lport; + dp->ids.port_id = ntoh24(pp->rscn_fid); + dp->ids.port_name = -1; + dp->ids.node_name = -1; +@@ -102,27 +112,26 @@ static void fc_disc_rscn_req(struct fc_seq *sp, struct fc_frame *fp, + case ELS_ADDR_FMT_DOM: + case ELS_ADDR_FMT_FAB: + default: ++ FC_DEBUG_DISC("Address format is (%d)\n", fmt); + redisc = 1; + break; + } + } +- lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + if (redisc) { +- if (fc_disc_debug) +- FC_DBG("RSCN received: rediscovering\n"); ++ FC_DEBUG_DISC("RSCN received: rediscovering\n"); + list_for_each_entry_safe(dp, next, &disc_list, peers) { + list_del(&dp->peers); + kfree(dp); + } +- fc_disc_restart(lp); ++ fc_disc_restart(lport); + } else { +- if (fc_disc_debug) +- FC_DBG("RSCN received: not rediscovering. " +- "redisc %d state %d in_prog %d\n", +- redisc, lp->state, lp->disc_pending); ++ FC_DEBUG_DISC("RSCN received: not rediscovering. " ++ "redisc %d state %d in_prog %d\n", ++ redisc, lport->state, lport->disc_pending); + list_for_each_entry_safe(dp, next, &disc_list, peers) { + list_del(&dp->peers); +- fc_disc_single(lp, dp); ++ fc_disc_single(lport, dp); + } + } + fc_frame_free(fp); +@@ -131,48 +140,53 @@ reject: + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_LOGIC; + rjt_data.explan = ELS_EXPL_NONE; +- lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); + } + ++/** ++ * fc_disc_recv_req - Handle incoming requests ++ * @sp: Current sequence of the request exchange ++ * @fp: The frame ++ * @lport: The FC local port ++ */ + static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lp) ++ struct fc_lport *lport) + { +- switch (fc_frame_payload_op(fp)) { ++ u8 op; ++ ++ op = fc_frame_payload_op(fp); ++ switch (op) { + case ELS_RSCN: +- fc_disc_rscn_req(sp, fp, lp); ++ fc_disc_recv_rscn_req(sp, fp, lport); + break; + default: +- FC_DBG("fc_disc recieved an unexpected request\n"); ++ FC_DBG("Received an unsupported request. opcode (%x)\n", op); + break; + } + } + +-/* +- * Refresh target discovery, perhaps due to an RSCN. +- * A configurable delay is introduced to collect any subsequent RSCNs. ++/** ++ * fc_disc_restart - Restart discovery ++ * @lport: FC local port + */ +-static int fc_disc_restart(struct fc_lport *lp) ++static int fc_disc_restart(struct fc_lport *lport) + { +- if (!lp->disc_requested && !lp->disc_pending) { +- schedule_delayed_work(&lp->disc_work, +- msecs_to_jiffies(lp->disc_delay * 1000)); ++ if (!lport->disc_requested && !lport->disc_pending) { ++ schedule_delayed_work(&lport->disc_work, ++ msecs_to_jiffies(lport->disc_delay * 1000)); + } +- lp->disc_requested = 1; ++ lport->disc_requested = 1; + return 0; + } + +-/* +- * Fibre Channel Target discovery. ++/** ++ * fc_disc_start - Fibre Channel Target discovery ++ * @lport: FC local port + * + * Returns non-zero if discovery cannot be started. +- * +- * Callback is called for each target remote port found in discovery. +- * When discovery is complete, the callback is called with a NULL remote port. +- * Discovery may be restarted after an RSCN is received, causing the +- * callback to be called after discovery complete is indicated. + */ +-int fc_disc_start(struct fc_lport *lp) ++static int fc_disc_start(struct fc_lport *lport) + { + struct fc_rport *rport; + int error; +@@ -181,20 +195,20 @@ int fc_disc_start(struct fc_lport *lp) + /* + * If not ready, or already running discovery, just set request flag. + */ +- if (!fc_lport_test_ready(lp) || lp->disc_pending) { +- lp->disc_requested = 1; ++ if (!fc_lport_test_ready(lport) || lport->disc_pending) { ++ lport->disc_requested = 1; + + return 0; + } +- lp->disc_pending = 1; +- lp->disc_requested = 0; +- lp->disc_retry_count = 0; ++ lport->disc_pending = 1; ++ lport->disc_requested = 0; ++ lport->disc_retry_count = 0; + + /* + * Handle point-to-point mode as a simple discovery + * of the remote port. + */ +- rport = lp->ptp_rp; ++ rport = lport->ptp_rp; + if (rport) { + ids.port_id = rport->port_id; + ids.port_name = rport->port_name; +@@ -202,46 +216,41 @@ int fc_disc_start(struct fc_lport *lp) + ids.roles = FC_RPORT_ROLE_UNKNOWN; + get_device(&rport->dev); + +- error = fc_disc_new_target(lp, rport, &ids); ++ error = fc_disc_new_target(lport, rport, &ids); + put_device(&rport->dev); + if (!error) +- fc_disc_done(lp); ++ fc_disc_done(lport); + } else { +- fc_block_rports(lp); +- fc_disc_gpn_ft_req(lp); /* get ports by FC-4 type */ ++ fc_disc_gpn_ft_req(lport); /* get ports by FC-4 type */ + error = 0; + } + return error; + } + +-/* +- * Restart discovery after a delay due to resource shortages. +- * If the error persists, the discovery will be abandoned. ++/** ++ * fc_disc_retry - Retry discovery ++ * @lport: FC local port + */ +-static void fc_disc_retry(struct fc_lport *lp) ++static void fc_disc_retry(struct fc_lport *lport) + { + unsigned long delay = FC_DISC_RETRY_DELAY; + +- if (!lp->disc_retry_count) ++ if (!lport->disc_retry_count) + delay /= 4; /* timeout faster first time */ +- if (lp->disc_retry_count++ < FC_DISC_RETRY_LIMIT) +- schedule_delayed_work(&lp->disc_work, ++ if (lport->disc_retry_count++ < FC_DISC_RETRY_LIMIT) ++ schedule_delayed_work(&lport->disc_work, + msecs_to_jiffies(delay)); + else +- fc_disc_done(lp); ++ fc_disc_done(lport); + } + +-/* +- * Handle new target found by discovery. +- * Create remote port and session if needed. +- * Ignore returns of our own FID & WWPN. +- * +- * If a non-NULL rp is passed in, it is held for the caller, but not for us. +- * +- * Events delivered are: +- * FC_EV_READY, when remote port is rediscovered. ++/** ++ * fc_disc_new_target - Handle new target found by discovery ++ * @lport: FC local port ++ * @rport: The previous FC remote port (NULL if new remote port) ++ * @ids: Identifiers for the new FC remote port + */ +-static int fc_disc_new_target(struct fc_lport *lp, ++static int fc_disc_new_target(struct fc_lport *lport, + struct fc_rport *rport, + struct fc_rport_identifiers *ids) + { +@@ -263,61 +272,64 @@ static int fc_disc_new_target(struct fc_lport *lp, + * assigned the same FCID. This should be rare. + * Delete the old one and fall thru to re-create. + */ +- fc_disc_del_target(lp, rport); ++ fc_disc_del_target(lport, rport); + rport = NULL; + } + } + if (((ids->port_name != -1) || (ids->port_id != -1)) && +- ids->port_id != lp->fid && ids->port_name != lp->wwpn) { ++ ids->port_id != fc_host_port_id(lport->host) && ++ ids->port_name != lport->wwpn) { + if (!rport) { +- rport = lp->tt.rport_lookup(lp, ids->port_id); ++ rport = lport->tt.rport_lookup(lport, ids->port_id); + if (!rport) { + struct fc_disc_port dp; +- dp.lp = lp; ++ dp.lp = lport; + dp.ids.port_id = ids->port_id; + dp.ids.port_name = ids->port_name; + dp.ids.node_name = ids->node_name; + dp.ids.roles = ids->roles; +- rport = fc_rport_dummy_create(&dp); ++ rport = fc_rport_rogue_create(&dp); + } + if (!rport) + error = ENOMEM; + } + if (rport) { + rp = rport->dd_data; +- rp->event_callback = lp->tt.event_callback; ++ rp->event_callback = lport->tt.event_callback; + rp->rp_state = RPORT_ST_INIT; +- lp->tt.rport_login(rport); ++ lport->tt.rport_login(rport); + } + } + return error; + } + +-/* +- * Delete the remote port. ++/** ++ * fc_disc_del_target - Delete a target ++ * @lport: FC local port ++ * @rport: The remote port to be removed + */ +-static void fc_disc_del_target(struct fc_lport *lp, struct fc_rport *rport) ++static void fc_disc_del_target(struct fc_lport *lport, struct fc_rport *rport) + { +- lp->tt.rport_reset(rport); +- fc_remote_port_delete(rport); /* release hold from create */ ++ lport->tt.rport_stop(rport); + } + +-/* +- * Done with discovery ++/** ++ * fc_disc_done - Discovery has been completed ++ * @lport: FC local port + */ +-static void fc_disc_done(struct fc_lport *lp) ++static void fc_disc_done(struct fc_lport *lport) + { +- lp->disc_done = 1; +- lp->disc_pending = 0; +- if (lp->disc_requested) +- lp->tt.disc_start(lp); ++ lport->disc_done = 1; ++ lport->disc_pending = 0; ++ if (lport->disc_requested) ++ lport->tt.disc_start(lport); + } + + /** + * fc_disc_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request +- * @lp: Fibre Channel host port instance ++ * @lport: FC local port + */ +-static void fc_disc_gpn_ft_req(struct fc_lport *lp) ++static void fc_disc_gpn_ft_req(struct fc_lport *lport) + { + struct fc_frame *fp; + struct fc_seq *sp = NULL; +@@ -327,60 +339,64 @@ static void fc_disc_gpn_ft_req(struct fc_lport *lp) + } *rp; + int error = 0; + +- lp->disc_buf_len = 0; +- lp->disc_seq_count = 0; +- fp = fc_frame_alloc(lp, sizeof(*rp)); +- if (fp == NULL) { ++ lport->disc_buf_len = 0; ++ lport->disc_seq_count = 0; ++ fp = fc_frame_alloc(lport, sizeof(*rp)); ++ if (!fp) { + error = ENOMEM; + } else { + rp = fc_frame_payload_get(fp, sizeof(*rp)); +- fc_fill_dns_hdr(lp, &rp->ct, FC_NS_GPN_FT, sizeof(rp->gid)); ++ fc_fill_dns_hdr(lport, &rp->ct, FC_NS_GPN_FT, sizeof(rp->gid)); + rp->gid.fn_fc4_type = FC_TYPE_FCP; + +- WARN_ON(!fc_lport_test_ready(lp)); ++ WARN_ON(!fc_lport_test_ready(lport)); + + fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- sp = lp->tt.exch_seq_send(lp, fp, +- fc_disc_gpn_ft_resp, NULL, +- lp, lp->e_d_tov, +- lp->fid, +- FC_FID_DIR_SERV, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ sp = lport->tt.exch_seq_send(lport, fp, ++ fc_disc_gpn_ft_resp, NULL, ++ lport, lport->e_d_tov, ++ fc_host_port_id(lport->host), ++ FC_FID_DIR_SERV, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); + } +- if (error || sp == NULL) +- fc_disc_retry(lp); ++ if (error || !sp) ++ fc_disc_retry(lport); + } + +-/* +- * Handle error on dNS request. ++/** ++ * fc_disc_error - Handle error on dNS request ++ * @lport: FC local port ++ * @fp: The frame pointer + */ +-static void fc_disc_error(struct fc_lport *lp, struct fc_frame *fp) ++static void fc_disc_error(struct fc_lport *lport, struct fc_frame *fp) + { +- int err = PTR_ERR(fp); ++ long err = PTR_ERR(fp); + ++ FC_DEBUG_DISC("Error %ld, retries %d/%d\n", PTR_ERR(fp), ++ lport->retry_count, FC_DISC_RETRY_LIMIT); ++ + switch (err) { + case -FC_EX_TIMEOUT: +- if (lp->disc_retry_count++ < FC_DISC_RETRY_LIMIT) { +- fc_disc_gpn_ft_req(lp); ++ if (lport->disc_retry_count++ < FC_DISC_RETRY_LIMIT) { ++ fc_disc_gpn_ft_req(lport); + } else { +- FC_DBG("err %d - ending\n", err); +- fc_disc_done(lp); ++ fc_disc_done(lport); + } + break; + default: +- FC_DBG("err %d - ending\n", err); +- fc_disc_done(lp); ++ FC_DBG("Error code %ld not supported\n", err); ++ fc_disc_done(lport); + break; + } + } + + /** + * fc_disc_gpn_ft_parse - Parse the list of IDs and names resulting from a request +- * @lp: Fibre Channel host port instance ++ * @lport: Fibre Channel host port instance + * @buf: GPN_FT response buffer + * @len: size of response buffer + */ +-static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) ++static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + { + struct fc_gpn_ft_resp *np; + char *bp; +@@ -388,8 +404,8 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + size_t tlen; + int error = 0; + struct fc_disc_port dp; +- struct fc_rport *rp; +- struct fc_rport_libfc_priv *rpp; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata; + + /* + * Handle partial name record left over from previous call. +@@ -397,7 +413,7 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + bp = buf; + plen = len; + np = (struct fc_gpn_ft_resp *)bp; +- tlen = lp->disc_buf_len; ++ tlen = lport->disc_buf_len; + if (tlen) { + WARN_ON(tlen >= sizeof(*np)); + plen = sizeof(*np) - tlen; +@@ -405,7 +421,7 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + WARN_ON(plen >= sizeof(*np)); + if (plen > len) + plen = len; +- np = &lp->disc_buf; ++ np = &lport->disc_buf; + memcpy((char *)np + tlen, bp, plen); + + /* +@@ -415,9 +431,9 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + bp -= tlen; + len += tlen; + plen += tlen; +- lp->disc_buf_len = (unsigned char) plen; ++ lport->disc_buf_len = (unsigned char) plen; + if (plen == sizeof(*np)) +- lp->disc_buf_len = 0; ++ lport->disc_buf_len = 0; + } + + /* +@@ -428,19 +444,20 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + * After the first time through the loop, things return to "normal". + */ + while (plen >= sizeof(*np)) { +- dp.lp = lp; ++ dp.lp = lport; + dp.ids.port_id = ntoh24(np->fp_fid); + dp.ids.port_name = ntohll(np->fp_wwpn); + dp.ids.node_name = -1; + dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; + +- if ((dp.ids.port_id != lp->fid) && +- (dp.ids.port_name != lp->wwpn)) { +- rp = fc_rport_dummy_create(&dp); +- if (rp) { +- rpp = rp->dd_data; +- rpp->local_port = lp; +- lp->tt.rport_login(rp); ++ if ((dp.ids.port_id != fc_host_port_id(lport->host)) && ++ (dp.ids.port_name != lport->wwpn)) { ++ rport = fc_rport_rogue_create(&dp); ++ if (rport) { ++ rdata = rport->dd_data; ++ rdata->event_callback = lport->tt.event_callback; ++ rdata->local_port = lport; ++ lport->tt.rport_login(rport); + } else + FC_DBG("Failed to allocate memory for " + "the newly discovered port (%6x)\n", +@@ -448,7 +465,7 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + } + + if (np->fp_flags & FC_NS_FID_LAST) { +- fc_disc_done(lp); ++ fc_disc_done(lport); + len = 0; + break; + } +@@ -462,11 +479,11 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + * Save any partial record at the end of the buffer for next time. + */ + if (error == 0 && len > 0 && len < sizeof(*np)) { +- if (np != &lp->disc_buf) +- memcpy(&lp->disc_buf, np, len); +- lp->disc_buf_len = (unsigned char) len; ++ if (np != &lport->disc_buf) ++ memcpy(&lport->disc_buf, np, len); ++ lport->disc_buf_len = (unsigned char) len; + } else { +- lp->disc_buf_len = 0; ++ lport->disc_buf_len = 0; + } + return error; + } +@@ -476,14 +493,14 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) + */ + static void fc_disc_timeout(struct work_struct *work) + { +- struct fc_lport *lp; ++ struct fc_lport *lport; + +- lp = container_of(work, struct fc_lport, disc_work.work); ++ lport = container_of(work, struct fc_lport, disc_work.work); + +- if (lp->disc_pending) +- fc_disc_gpn_ft_req(lp); ++ if (lport->disc_pending) ++ fc_disc_gpn_ft_req(lport); + else +- lp->tt.disc_start(lp); ++ lport->tt.disc_start(lport); + } + + /** +@@ -495,9 +512,9 @@ static void fc_disc_timeout(struct work_struct *work) + * The response may be in multiple frames + */ + static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *lp_arg) ++ void *lp_arg) + { +- struct fc_lport *lp = lp_arg; ++ struct fc_lport *lport = lp_arg; + struct fc_ct_hdr *cp; + struct fc_frame_header *fh; + unsigned int seq_cnt; +@@ -506,7 +523,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + int error; + + if (IS_ERR(fp)) { +- fc_disc_error(lp, fp); ++ fc_disc_error(lport, fp); + return; + } + +@@ -515,7 +532,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + len = fr_len(fp) - sizeof(*fh); + seq_cnt = ntohs(fh->fh_seq_cnt); + if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && +- lp->disc_seq_count == 0) { ++ lport->disc_seq_count == 0) { + cp = fc_frame_payload_get(fp, sizeof(*cp)); + if (cp == NULL) { + FC_DBG("GPN_FT response too short, len %d\n", +@@ -531,68 +548,76 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + FC_DBG("GPN_FT rejected reason %x exp %x " + "(check zoning)\n", cp->ct_reason, + cp->ct_explan); +- fc_disc_done(lp); ++ fc_disc_done(lport); + } else { + FC_DBG("GPN_FT unexpected response code %x\n", + ntohs(cp->ct_cmd)); + } + } else if (fr_sof(fp) == FC_SOF_N3 && +- seq_cnt == lp->disc_seq_count) { ++ seq_cnt == lport->disc_seq_count) { + buf = fh + 1; + } else { + FC_DBG("GPN_FT unexpected frame - out of sequence? " + "seq_cnt %x expected %x sof %x eof %x\n", +- seq_cnt, lp->disc_seq_count, fr_sof(fp), fr_eof(fp)); ++ seq_cnt, lport->disc_seq_count, fr_sof(fp), fr_eof(fp)); + } + if (buf) { +- error = fc_disc_gpn_ft_parse(lp, buf, len); ++ error = fc_disc_gpn_ft_parse(lport, buf, len); + if (error) +- fc_disc_retry(lp); ++ fc_disc_retry(lport); + else +- lp->disc_seq_count++; ++ lport->disc_seq_count++; + } + fc_frame_free(fp); + } + +-/* +- * Discover the directory information for a single target. ++/** ++ * fc_disc_single - Discover the directory information for a single target ++ * @lport: FC local port ++ * @dp: The port to rediscover ++ * + * This could be from an RSCN that reported a change for the target. + */ +-static void fc_disc_single(struct fc_lport *lp, struct fc_disc_port *dp) ++static void fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) + { + struct fc_rport *rport; +- struct fc_rport *rp; +- struct fc_rport_libfc_priv *rpp; ++ struct fc_rport *new_rport; ++ struct fc_rport_libfc_priv *rdata; + +- if (dp->ids.port_id == lp->fid) ++ if (dp->ids.port_id == fc_host_port_id(lport->host)) + goto out; + +- rport = lp->tt.rport_lookup(lp, dp->ids.port_id); ++ rport = lport->tt.rport_lookup(lport, dp->ids.port_id); + if (rport) { +- fc_disc_del_target(lp, rport); ++ fc_disc_del_target(lport, rport); + put_device(&rport->dev); /* hold from lookup */ + } + +- rp = fc_rport_dummy_create(dp); +- if (rp) { +- rpp = rp->dd_data; ++ new_rport = fc_rport_rogue_create(dp); ++ if (new_rport) { ++ rdata = new_rport->dd_data; ++ rdata->event_callback = lport->tt.event_callback; + kfree(dp); +- lp->tt.rport_login(rp); ++ lport->tt.rport_login(new_rport); + } + return; + out: + kfree(dp); + } + +-int fc_disc_init(struct fc_lport *lp) ++/** ++ * fc_disc_init - Initialize the discovery block ++ * @lport: FC local port ++ */ ++int fc_disc_init(struct fc_lport *lport) + { +- INIT_DELAYED_WORK(&lp->disc_work, fc_disc_timeout); ++ INIT_DELAYED_WORK(&lport->disc_work, fc_disc_timeout); + +- if (!lp->tt.disc_start) +- lp->tt.disc_start = fc_disc_start; ++ if (!lport->tt.disc_start) ++ lport->tt.disc_start = fc_disc_start; + +- if (!lp->tt.disc_recv_req) +- lp->tt.disc_recv_req = fc_disc_recv_req; ++ if (!lport->tt.disc_recv_req) ++ lport->tt.disc_recv_req = fc_disc_recv_req; + + return 0; + } +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +index ed74d95..80dc1ef 100644 +--- a/drivers/scsi/libfc/fc_exch.c ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -37,6 +37,13 @@ + * fc_exch_debug can be set in debugger or at compile time to get more logs. + */ + static int fc_exch_debug; ++ ++#define FC_DEBUG_EXCH(fmt...) \ ++ do { \ ++ if (fc_exch_debug) \ ++ FC_DBG(fmt); \ ++ } while (0) ++ + static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ + + /* +@@ -86,7 +93,7 @@ struct fc_exch { + struct list_head ex_list; /* free or busy list linkage */ + spinlock_t ex_lock; /* lock covering exchange state */ + atomic_t ex_refcnt; /* reference counter */ +- struct timer_list ex_timer; /* timer for upper level protocols */ ++ struct delayed_work timeout_work; /* timer for upper level protocols */ + struct fc_lport *lp; /* fc device instance */ + u16 oxid; /* originator's exchange ID */ + u16 rxid; /* responder's exchange ID */ +@@ -310,7 +317,6 @@ static void fc_exch_release(struct fc_exch *ep) + if (ep->lp->tt.exch_put) + ep->lp->tt.exch_put(ep->lp, mp, ep->xid); + WARN_ON(!ep->esb_stat & ESB_ST_COMPLETE); +- WARN_ON(timer_pending(&ep->ex_timer)); + mempool_free(ep, mp->ep_pool); + } + } +@@ -332,7 +338,7 @@ static int fc_exch_done_locked(struct fc_exch *ep) + + if (!(ep->esb_stat & ESB_ST_REC_QUAL)) { + ep->state |= FC_EX_DONE; +- if (del_timer(&ep->ex_timer)) ++ if (cancel_delayed_work(&ep->timeout_work)) + atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ + rc = 0; + } +@@ -362,7 +368,10 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep, + if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) + return; + +- if (!mod_timer(&ep->ex_timer, jiffies + msecs_to_jiffies(timer_msec))) ++ FC_DEBUG_EXCH("Exchange (%4x) timed out, notifying the upper layer\n", ++ ep->xid); ++ if (schedule_delayed_work(&ep->timeout_work, ++ jiffies + msecs_to_jiffies(timer_msec))) + fc_exch_hold(ep); /* hold for timer */ + } + +@@ -435,9 +444,10 @@ EXPORT_SYMBOL(fc_seq_exch_abort); + * Exchange timeout - handle exchange timer expiration. + * The timer will have been cancelled before this is called. + */ +-static void fc_exch_timeout(unsigned long ep_arg) ++static void fc_exch_timeout(struct work_struct *work) + { +- struct fc_exch *ep = (struct fc_exch *)ep_arg; ++ struct fc_exch *ep = container_of(work, struct fc_exch, ++ timeout_work.work); + struct fc_seq *sp = &ep->seq; + void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); + void *arg; +@@ -584,7 +594,7 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) + ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ + ep->rxid = FC_XID_UNKNOWN; + ep->class = mp->class; +- setup_timer(&ep->ex_timer, fc_exch_timeout, (unsigned long)ep); ++ INIT_DELAYED_WORK(&ep->timeout_work, fc_exch_timeout); + out: + return ep; + err: +@@ -843,9 +853,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp) + struct fc_exch *ep = fc_seq_exch(sp); + + sp = fc_seq_alloc(ep, ep->seq_id++); +- if (fc_exch_debug) +- FC_DBG("exch %4x f_ctl %6x seq %2x f_ctl %6x\n", +- ep->xid, ep->f_ctl, sp->id, sp->f_ctl); ++ FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x f_ctl %6x\n", ++ ep->xid, ep->f_ctl, sp->id, sp->f_ctl); + return sp; + } + /* +@@ -913,7 +922,18 @@ int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, + } + + hton24(fh->fh_f_ctl, f_ctl | fill); +- fh->fh_seq_cnt = htons(sp->cnt++); ++ fh->fh_seq_cnt = htons(sp->cnt); ++ ++ /* ++ * update sequence count if this frame is carrying ++ * multiple FC frames when sequence offload is enabled ++ * by LLD. ++ */ ++ if (fr_max_payload(fp)) ++ sp->cnt += DIV_ROUND_UP((fr_len(fp) - sizeof(*fh)), ++ fr_max_payload(fp)); ++ else ++ sp->cnt++; + + /* + * Send the frame. +@@ -1185,8 +1205,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, + lp->tt.lport_recv(lp, sp, fp); + fc_exch_release(ep); /* release from lookup */ + } else { +- if (fc_exch_debug) +- FC_DBG("exch/seq lookup failed: reject %x\n", reject); ++ FC_DEBUG_EXCH("exch/seq lookup failed: reject %x\n", reject); + fc_frame_free(fp); + } + } +@@ -1290,12 +1309,10 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) + sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ + if (!sp) { + atomic_inc(&mp->stats.xid_not_found); +- if (fc_exch_debug) +- FC_DBG("seq lookup failed\n"); ++ FC_DEBUG_EXCH("seq lookup failed\n"); + } else { + atomic_inc(&mp->stats.non_bls_resp); +- if (fc_exch_debug) +- FC_DBG("non-BLS response to sequence"); ++ FC_DEBUG_EXCH("non-BLS response to sequence"); + } + fc_frame_free(fp); + } +@@ -1316,11 +1333,10 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) + int rc = 1, has_rec = 0; + + fh = fc_frame_header_get(fp); +- if (fc_exch_debug) +- FC_DBG("exch: BLS rctl %x - %s\n", +- fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl)); ++ FC_DEBUG_EXCH("exch: BLS rctl %x - %s\n", ++ fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl)); + +- if (del_timer_sync(&ep->ex_timer)) ++ if (cancel_delayed_work_sync(&ep->timeout_work)) + fc_exch_release(ep); /* release from pending timer hold */ + + spin_lock_bh(&ep->ex_lock); +@@ -1410,10 +1426,9 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) + case FC_RCTL_ACK_0: + break; + default: +- if (fc_exch_debug) +- FC_DBG("BLS rctl %x - %s received", +- fh->fh_r_ctl, +- fc_exch_rctl_name(fh->fh_r_ctl)); ++ FC_DEBUG_EXCH("BLS rctl %x - %s received", ++ fh->fh_r_ctl, ++ fc_exch_rctl_name(fh->fh_r_ctl)); + break; + } + fc_frame_free(fp); +@@ -1498,7 +1513,7 @@ static void fc_exch_reset(struct fc_exch *ep) + * functions can also grab the lport lock which could cause + * a deadlock). + */ +- if (del_timer(&ep->ex_timer)) ++ if (cancel_delayed_work(&ep->timeout_work)) + atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ + resp = ep->resp; + ep->resp = NULL; +@@ -1720,7 +1735,7 @@ static void fc_exch_rrq(struct fc_exch *ep) + if (ep->esb_stat & ESB_ST_RESP) + did = ep->sid; + rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, +- lp->e_d_tov, lp->fid, did, ++ lp->e_d_tov, fc_host_port_id(lp->host), did, + FC_FC_SEQ_INIT | FC_FC_END_SEQ); + if (!rrq_sp) { + ep->esb_stat |= ESB_ST_REC_QUAL; +@@ -1774,8 +1789,10 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) + ep->esb_stat &= ~ESB_ST_REC_QUAL; + atomic_dec(&ep->ex_refcnt); /* drop hold for rec qual */ + } +- if ((ep->esb_stat & ESB_ST_COMPLETE) && (del_timer(&ep->ex_timer))) +- atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ if (ep->esb_stat & ESB_ST_COMPLETE) { ++ if (cancel_delayed_work(&ep->timeout_work)) ++ atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ } + + spin_unlock_bh(&ep->ex_lock); + +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +index 2566eed..bf8202f 100644 +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -42,22 +42,29 @@ MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("libfc"); + MODULE_LICENSE("GPL"); + +-int fc_fcp_debug; ++static int fc_fcp_debug; ++ ++#define FC_DEBUG_FCP(fmt...) \ ++ do { \ ++ if (fc_fcp_debug) \ ++ FC_DBG(fmt); \ ++ } while (0) ++ + static struct kmem_cache *scsi_pkt_cachep; + + /* SRB state definitions */ +-#define FC_SRB_FREE 0 /* cmd is free */ +-#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */ +-#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */ +-#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */ +-#define FC_SRB_ABORTED (1 << 3) /* abort acknowleged */ +-#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */ +-#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */ ++#define FC_SRB_FREE 0 /* cmd is free */ ++#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */ ++#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */ ++#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */ ++#define FC_SRB_ABORTED (1 << 3) /* abort acknowleged */ ++#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */ ++#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */ + #define FC_SRB_FCP_PROCESSING_TMO (1 << 6) /* timer function processing */ +-#define FC_SRB_NOMEM (1 << 7) /* dropped to out of mem */ ++#define FC_SRB_NOMEM (1 << 7) /* dropped to out of mem */ + +-#define FC_SRB_READ (1 << 1) +-#define FC_SRB_WRITE (1 << 0) ++#define FC_SRB_READ (1 << 1) ++#define FC_SRB_WRITE (1 << 0) + + /* + * scsi request structure, one for each scsi request +@@ -184,8 +191,8 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); + #define FC_SCSI_REC_TOV (2 * HZ) + #define FC_HOST_RESET_TIMEOUT (30 * HZ) + +-#define FC_MAX_ERROR_CNT 5 +-#define FC_MAX_RECOV_RETRY 3 ++#define FC_MAX_ERROR_CNT 5 ++#define FC_MAX_RECOV_RETRY 3 + + #define FC_FCP_DFLT_QUEUE_DEPTH 32 + +@@ -353,11 +360,8 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && + fc_frame_crc_check(fp)) + goto crc_err; +- if (fc_fcp_debug) { +- FC_DBG("data received past end. " +- "len %zx offset %zx " +- "data_len %x\n", len, offset, fsp->data_len); +- } ++ FC_DEBUG_FCP("data received past end. len %zx offset %zx " ++ "data_len %x\n", len, offset, fsp->data_len); + fc_fcp_retry_cmd(fsp); + return; + } +@@ -449,55 +453,54 @@ crc_err: + /* + * Send SCSI data to target. + * Called after receiving a Transfer Ready data descriptor. ++ * if LLD is capable of seq offload then send down seq_blen ++ * size of data in single frame, otherwise send multiple FC ++ * frames of max FC frame payload supported by target port. + */ + static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, +- size_t offset, size_t len, +- struct fc_frame *oldfp, int sg_supp) ++ size_t offset, size_t seq_blen) + { + struct scsi_cmnd *sc; + struct scatterlist *sg; + struct fc_frame *fp = NULL; + struct fc_lport *lp = fsp->lp; + size_t remaining; +- size_t mfs; ++ size_t t_blen; + size_t tlen; + size_t sg_bytes; + size_t frame_offset; + int error; + void *data = NULL; + void *page_addr; +- int using_sg = sg_supp; ++ int using_sg = lp->sg_supp; + u32 f_ctl; + +- if (unlikely(offset + len > fsp->data_len)) { +- /* +- * this should never happen +- */ +- if (fc_fcp_debug) { +- FC_DBG("xfer-ready past end. len %zx offset %zx\n", +- len, offset); +- } ++ WARN_ON(seq_blen <= 0); ++ if (unlikely(offset + seq_blen > fsp->data_len)) { ++ /* this should never happen */ ++ FC_DEBUG_FCP("xfer-ready past end. seq_blen %zx offset %zx\n", ++ seq_blen, offset); + fc_fcp_send_abort(fsp); + return 0; + } else if (offset != fsp->xfer_len) { +- /* +- * Out of Order Data Request - no problem, but unexpected. +- */ +- if (fc_fcp_debug) { +- FC_DBG("xfer-ready non-contiguous. " +- "len %zx offset %zx\n", len, offset); +- } ++ /* Out of Order Data Request - no problem, but unexpected. */ ++ FC_DEBUG_FCP("xfer-ready non-contiguous. " ++ "seq_blen %zx offset %zx\n", seq_blen, offset); + } +- mfs = fsp->max_payload; +- WARN_ON(mfs > FC_MAX_PAYLOAD); +- WARN_ON(mfs < FC_MIN_MAX_PAYLOAD); +- if (mfs > 512) +- mfs &= ~(512 - 1); /* round down to block size */ +- WARN_ON(mfs < FC_MIN_MAX_PAYLOAD); /* won't go below 256 */ +- WARN_ON(len <= 0); ++ ++ /* ++ * if LLD is capable of seq_offload then set transport ++ * burst length (t_blen) to seq_blen, otherwise set t_blen ++ * to max FC frame payload previously set in fsp->max_payload. ++ */ ++ t_blen = lp->seq_offload ? seq_blen : fsp->max_payload; ++ WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); ++ if (t_blen > 512) ++ t_blen &= ~(512 - 1); /* round down to block size */ ++ WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); /* won't go below 256 */ + sc = fsp->cmd; + +- remaining = len; ++ remaining = seq_blen; + frame_offset = offset; + tlen = 0; + sp = lp->tt.seq_start_next(sp); +@@ -540,7 +543,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, + continue; + } + if (!fp) { +- tlen = min(mfs, remaining); ++ tlen = min(t_blen, remaining); + + /* + * TODO. Temporary workaround. fc_seq_send() can't +@@ -563,6 +566,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, + } + fc_frame_setup(fp, FC_RCTL_DD_SOL_DATA, FC_TYPE_FCP); + fc_frame_set_offset(fp, frame_offset); ++ fr_max_payload(fp) = fsp->max_payload; + } + sg_bytes = min(tlen, sg->length - offset); + if (using_sg) { +@@ -621,7 +625,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, + return 0; + } + } +- fsp->xfer_len += len; /* premature count? */ ++ fsp->xfer_len += seq_blen; /* premature count? */ + return 0; + } + +@@ -741,8 +745,7 @@ static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) + + rc = fc_fcp_send_data(fsp, sp, + (size_t) ntohl(dd->ft_data_ro), +- (size_t) ntohl(dd->ft_burst_len), fp, +- lp->capabilities & TRANS_C_SG); ++ (size_t) ntohl(dd->ft_burst_len)); + if (!rc) + lp->tt.seq_set_rec_data(sp, fsp->xfer_len); + else if (rc == -ENOMEM) +@@ -1066,7 +1069,7 @@ static int fc_fcp_send_cmd(struct fc_fcp_pkt *fsp) + fc_fcp_recv, + fc_fcp_pkt_destroy, + fsp, 0, +- rp->local_port->fid, ++ fc_host_port_id(rp->local_port->host), + rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ); + if (!sp) { +@@ -1175,7 +1178,7 @@ static void fc_lun_reset_send(unsigned long data) + fc_tm_done, + fc_fcp_pkt_destroy, + fsp, 0, +- rp->local_port->fid, ++ fc_host_port_id(rp->local_port->host), + rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ); + +@@ -1367,7 +1370,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + rec = fc_frame_payload_get(fp, sizeof(*rec)); + memset(rec, 0, sizeof(*rec)); + rec->rec_cmd = ELS_REC; +- hton24(rec->rec_s_id, lp->fid); ++ hton24(rec->rec_s_id, fc_host_port_id(lp->host)); + rec->rec_ox_id = htons(ox_id); + rec->rec_rx_id = htons(rx_id); + +@@ -1376,7 +1379,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + sp = lp->tt.exch_seq_send(lp, fp, + fc_fcp_rec_resp, NULL, + fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), +- rp->local_port->fid, ++ fc_host_port_id(rp->local_port->host), + rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ); + +@@ -1425,16 +1428,13 @@ static void fc_fcp_rec_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) + rjt = fc_frame_payload_get(fp, sizeof(*rjt)); + switch (rjt->er_reason) { + default: +- if (fc_fcp_debug) +- FC_DBG("device %x unexpected REC reject " +- "reason %d expl %d\n", +- fsp->rport->port_id, rjt->er_reason, +- rjt->er_explan); ++ FC_DEBUG_FCP("device %x unexpected REC reject " ++ "reason %d expl %d\n", ++ fsp->rport->port_id, rjt->er_reason, ++ rjt->er_explan); + /* fall through */ +- + case ELS_RJT_UNSUP: +- if (fc_fcp_debug) +- FC_DBG("device does not support REC\n"); ++ FC_DEBUG_FCP("device does not support REC\n"); + rp = fsp->rport->dd_data; + /* + * if we do not spport RECs or got some bogus +@@ -1636,7 +1636,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) + sp = lp->tt.exch_seq_send(lp, fp, + fc_fcp_srr_resp, NULL, + fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), +- rp->local_port->fid, ++ fc_host_port_id(rp->local_port->host), + rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ); + if (!sp) { +@@ -2199,7 +2199,17 @@ static int __init libfc_init(void) + + rc = fc_setup_exch_mgr(); + if (rc) +- kmem_cache_destroy(scsi_pkt_cachep); ++ goto destroy_pkt_cache; ++ ++ rc = fc_setup_rport(); ++ if (rc) ++ goto destroy_em; ++ ++ return rc; ++destroy_em: ++ fc_destroy_exch_mgr(); ++destroy_pkt_cache: ++ kmem_cache_destroy(scsi_pkt_cachep); + return rc; + } + +@@ -2207,6 +2217,7 @@ static void __exit libfc_exit(void) + { + kmem_cache_destroy(scsi_pkt_cachep); + fc_destroy_exch_mgr(); ++ fc_destroy_rport(); + } + + module_init(libfc_init); +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index b1854b9..bfbc7d4 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -18,7 +18,59 @@ + */ + + /* +- * Logical interface support. ++ * General locking notes: ++ * ++ * The lport and rport blocks both have mutexes that are used to protect ++ * the port objects states. The main motivation for this protection is that ++ * we don't want to be preparing a request/response in one context while ++ * another thread "resets" the port in question. For example, if the lport ++ * block is sending a SCR request to the directory server we don't want ++ * the lport to be reset before we fill out the frame header's port_id. The ++ * problem is that a reset would cause the lport's port_id to reset to 0. ++ * If we don't protect the lport we'd spew incorrect frames. ++ * ++ * At the time of this writing there are two primary mutexes, one for the ++ * lport and one for the rport. Since the lport uses the rport and makes ++ * calls into that block the rport should never make calls that would cause ++ * the lport's mutex to be locked. In other words, the lport's mutex is ++ * considered the outer lock and the rport's lock is considered the inner ++ * lock. The bottom line is that you can hold a lport's mutex and then ++ * hold the rport's mutex, but not the other way around. ++ * ++ * The only complication to this rule is the callbacks from the rport to ++ * the lport's event_callback function. When rports become READY they make ++ * a callback to the lport so that it can track them. In the case of the ++ * directory server that callback might cause the lport to change its ++ * state, implying that the lport mutex would need to be held. This problem ++ * was solved by serializing the rport notifications to the lport and the ++ * callback is made without holding the rport's lock. ++ * ++ * lport locking notes: ++ * ++ * The critical sections protected by the lport's mutex are quite broad and ++ * may be improved upon in the future. The lport code and its locking doesn't ++ * influence the I/O path, so excessive locking doesn't penalize I/O ++ * performance. ++ * ++ * The strategy is to lock whenever processing a request or response. Note ++ * that every _enter_* function corresponds to a state change. They generally ++ * change the lports state and then sends a request out on the wire. We lock ++ * before calling any of these functions to protect that state change. This ++ * means that the entry points into the lport block to manage the locks while ++ * the state machine can transition between states (i.e. _enter_* functions) ++ * while always staying protected. ++ * ++ * When handling responses we also hold the lport mutex broadly. When the ++ * lport receives the response frame it locks the mutex and then calls the ++ * appropriate handler for the particuar response. Generally a response will ++ * trigger a state change and so the lock must already be held. ++ * ++ * Retries also have to consider the locking. The retries occur from a work ++ * context and the work function will lock the lport and then retry the state ++ * (i.e. _enter_* function). ++ * ++ * The implication to all of this is that each lport can only process one ++ * state at a time. + */ + + #include +@@ -36,6 +88,12 @@ + + static int fc_lport_debug; + ++#define FC_DEBUG_LPORT(fmt...) \ ++ do { \ ++ if (fc_lport_debug) \ ++ FC_DBG(fmt); \ ++ } while (0) ++ + static void fc_lport_error(struct fc_lport *, struct fc_frame *); + + static void fc_lport_enter_reset(struct fc_lport *); +@@ -66,41 +124,71 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) + } + + /** ++ * fc_lport_lookup_rport - lookup a remote port by port_id ++ * @lport: Fibre Channel host port instance ++ * @port_id: remote port port_id to match ++ */ ++struct fc_rport *fc_lport_lookup_rport(const struct fc_lport *lport, ++ u32 port_id) ++{ ++ struct fc_rport *rport, *found; ++ struct fc_rport_libfc_priv *rdata; ++ ++ found = NULL; ++ ++ list_for_each_entry(rdata, &lport->rports, peers) { ++ rport = PRIV_TO_RPORT(rdata); ++ if (rport->port_id == port_id) { ++ found = rport; ++ get_device(&found->dev); ++ break; ++ } ++ } ++ return found; ++} ++ ++ ++ ++/** + * fc_lport_rport_event - Event handler for rport events + * @lport: The lport which is receiving the event +- * @port_id: The FID of the rport which the event has occured on ++ * @rport: The rport which the event has occured on + * @event: The event that occured + * + * Locking Note: The rport lock should not be held when calling + * this function. + */ +-static void fc_lport_rport_event(struct fc_lport *lport, u32 port_id, ++static void fc_lport_rport_event(struct fc_lport *lport, ++ struct fc_rport *rport, + enum fc_lport_event event) + { +- struct fc_rport *rport = lport->tt.rport_lookup(lport, port_id); ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; + +- if (fc_lport_debug) +- FC_DBG("Received a %d event for port (%6x)\n", event, port_id); ++ FC_DEBUG_LPORT("Received a %d event for port (%6x)\n", event, ++ rport->port_id); + +- if (port_id == FC_FID_DIR_SERV) { +- mutex_lock(&lport->lp_mutex); +- switch (event) { +- case LPORT_EV_RPORT_CREATED: +- if (rport) { +- lport->dns_rp = rport; +- fc_lport_enter_rpn_id(lport); +- } +- break; +- case LPORT_EV_RPORT_LOGO: +- case LPORT_EV_RPORT_FAILED: +- lport->dns_rp = NULL; +- fc_lport_enter_dns(lport); +- break; +- case LPORT_EV_RPORT_NONE: +- break; ++ mutex_lock(&lport->lp_mutex); ++ switch (event) { ++ case LPORT_EV_RPORT_CREATED: ++ if (rport->port_id == FC_FID_DIR_SERV) { ++ lport->dns_rp = rport; ++ fc_lport_enter_rpn_id(lport); ++ } else { ++ list_add_tail(&rdata->peers, &lport->rports); + } +- mutex_unlock(&lport->lp_mutex); ++ break; ++ case LPORT_EV_RPORT_LOGO: ++ case LPORT_EV_RPORT_FAILED: ++ case LPORT_EV_RPORT_STOP: ++ if (rport->port_id == FC_FID_DIR_SERV) ++ lport->dns_rp = NULL; ++ else ++ list_del(&rdata->peers); ++ break; ++ case LPORT_EV_RPORT_NONE: ++ break; + } ++ mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -118,18 +206,6 @@ static const char *fc_lport_state(struct fc_lport *lport) + } + + /** +- * fc_lport_ptp_clear - Delete the ptp rport +- * @lport: The lport whose ptp rport should be removed +- */ +-static void fc_lport_ptp_clear(struct fc_lport *lport) +-{ +- if (lport->ptp_rp) { +- fc_remote_port_delete(lport->ptp_rp); +- lport->ptp_rp = NULL; +- } +-} +- +-/** + * fc_lport_ptp_setup - Create an rport for point-to-point mode + * @lport: The lport to attach the ptp rport to + * @fid: The FID of the ptp rport +@@ -148,19 +224,25 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, + dp.ids.node_name = remote_wwnn; + dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; + +- fc_lport_ptp_clear(lport); ++ if (lport->ptp_rp) { ++ lport->tt.rport_stop(lport->ptp_rp); ++ lport->ptp_rp = NULL; ++ } + +- lport->ptp_rp = fc_rport_dummy_create(&dp); ++ lport->ptp_rp = fc_rport_rogue_create(&dp); + + lport->tt.rport_login(lport->ptp_rp); + + fc_lport_enter_ready(lport); + } + +-/** +- * fc_get_host_port_state - supports fc_function_template +- * @shost: The host whose port state should be returned +- */ ++void fc_get_host_port_type(struct Scsi_Host *shost) ++{ ++ /* TODO - currently just NPORT */ ++ fc_host_port_type(shost) = FC_PORTTYPE_NPORT; ++} ++EXPORT_SYMBOL(fc_get_host_port_type); ++ + void fc_get_host_port_state(struct Scsi_Host *shost) + { + struct fc_lport *lp = shost_priv(shost); +@@ -277,8 +359,7 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) + static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, + struct fc_lport *lport) + { +- if (fc_lport_debug) +- FC_DBG("Received RLIR request while in state %s\n", ++ FC_DEBUG_LPORT("Received RLIR request while in state %s\n", + fc_lport_state(lport)); + + lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); +@@ -303,8 +384,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, + void *dp; + u32 f_ctl; + +- if (fc_lport_debug) +- FC_DBG("Received RLIR request while in state %s\n", ++ FC_DEBUG_LPORT("Received RLIR request while in state %s\n", + fc_lport_state(lport)); + + len = fr_len(in_fp) - sizeof(struct fc_frame_header); +@@ -350,8 +430,7 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, + size_t len; + u32 f_ctl; + +- if (fc_lport_debug) +- FC_DBG("Received RNID request while in state %s\n", ++ FC_DEBUG_LPORT("Received RNID request while in state %s\n", + fc_lport_state(lport)); + + req = fc_frame_payload_get(in_fp, sizeof(*req)); +@@ -520,12 +599,10 @@ EXPORT_SYMBOL(fc_fabric_logoff); + **/ + int fc_lport_destroy(struct fc_lport *lport) + { +- mutex_lock(&lport->lp_mutex); + cancel_delayed_work_sync(&lport->disc_work); + lport->tt.scsi_abort_io(lport); + lport->tt.frame_send = fc_frame_drop; + lport->tt.exch_mgr_reset(lport->emp, 0, 0); +- mutex_unlock(&lport->lp_mutex); + return 0; + } + EXPORT_SYMBOL(fc_lport_destroy); +@@ -569,9 +646,8 @@ EXPORT_SYMBOL(fc_set_mfs); + */ + static void fc_lport_enter_ready(struct fc_lport *lport) + { +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered Ready from state %s\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered Ready from state %s\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_READY); + +@@ -605,8 +681,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + u32 local_fid; + u32 f_ctl; + +- if (fc_lport_debug) +- FC_DBG("Received FLOGI request while in state %s\n", ++ FC_DEBUG_LPORT("Received FLOGI request while in state %s\n", + fc_lport_state(lport)); + + fh = fc_frame_header_get(rx_fp); +@@ -636,7 +711,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + remote_fid = FC_LOCAL_PTP_FID_HI; + } + +- lport->fid = local_fid; ++ fc_host_port_id(lport->host) = local_fid; + + fp = fc_frame_alloc(lport, sizeof(*flp)); + if (fp) { +@@ -733,7 +808,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + s_id = ntoh24(fh->fh_s_id); + d_id = ntoh24(fh->fh_d_id); + +- rport = lport->tt.rport_lookup(lport, s_id); ++ rport = fc_lport_lookup_rport(lport, s_id); + if (rport) { + lport->tt.rport_recv_req(sp, fp, rport); + put_device(&rport->dev); /* hold from lookup */ +@@ -752,6 +827,12 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + fc_frame_free(fp); + } + mutex_unlock(&lport->lp_mutex); ++ ++ /* ++ * The common exch_done for all request may not be good ++ * if any request requires longer hold on exhange. XXX ++ */ ++ lport->tt.exch_done(sp); + } + + /** +@@ -771,6 +852,24 @@ int fc_lport_reset(struct fc_lport *lport) + EXPORT_SYMBOL(fc_lport_reset); + + /** ++ * fc_lport_stop_rports - delete all the remote ports associated with the lport ++ * @lport: libfc local port instance ++ * ++ * Locking Note: This function expects that the lport mutex is locked before ++ * calling it. ++ */ ++void fc_lport_stop_rports(struct fc_lport *lport) ++{ ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata; ++ ++ list_for_each_entry(rdata, &lport->rports, peers) { ++ rport = PRIV_TO_RPORT(rdata); ++ lport->tt.rport_stop(rport); ++ } ++} ++ ++/** + * fc_rport_enter_reset - Reset the local port + * @lport: Fibre Channel local port to be reset + * +@@ -779,24 +878,26 @@ EXPORT_SYMBOL(fc_lport_reset); + */ + static void fc_lport_enter_reset(struct fc_lport *lport) + { +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered RESET state from %s state\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered RESET state from %s state\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_RESET); + + if (lport->dns_rp) { +- fc_remote_port_delete(lport->dns_rp); ++ lport->tt.rport_stop(lport->dns_rp); + lport->dns_rp = NULL; + } +- fc_lport_ptp_clear(lport); + +- fc_block_rports(lport); ++ if (lport->ptp_rp) { ++ lport->tt.rport_stop(lport->ptp_rp); ++ lport->ptp_rp = NULL; ++ } ++ ++ fc_lport_stop_rports(lport); + +- lport->tt.rport_reset_list(lport); + lport->tt.exch_mgr_reset(lport->emp, 0, 0); + fc_host_fabric_name(lport->host) = 0; +- lport->fid = 0; ++ fc_host_port_id(lport->host) = 0; + + if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) + fc_lport_enter_flogi(lport); +@@ -814,33 +915,38 @@ static void fc_lport_enter_reset(struct fc_lport *lport) + static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) + { + unsigned long delay = 0; +- if (fc_lport_debug) +- FC_DBG("Error %ld in state %s, retries %d\n", ++ FC_DEBUG_LPORT("Error %ld in state %s, retries %d\n", + PTR_ERR(fp), fc_lport_state(lport), + lport->retry_count); + +- if (lport->retry_count < lport->max_retry_count) { +- lport->retry_count++; +- if (!fp) +- delay = msecs_to_jiffies(500); +- else +- delay = jiffies + +- msecs_to_jiffies(lport->e_d_tov); +- +- schedule_delayed_work(&lport->retry_work, delay); +- } else { +- switch (lport->state) { +- case LPORT_ST_NONE: +- case LPORT_ST_READY: +- case LPORT_ST_RESET: +- case LPORT_ST_RPN_ID: +- case LPORT_ST_RFT_ID: +- case LPORT_ST_SCR: +- case LPORT_ST_DNS: +- case LPORT_ST_FLOGI: +- case LPORT_ST_LOGO: +- fc_lport_enter_reset(lport); +- break; ++ if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { ++ /* ++ * Memory allocation failure, or the exchange timed out. ++ * Retry after delay ++ */ ++ if (lport->retry_count < lport->max_retry_count) { ++ lport->retry_count++; ++ if (!fp) ++ delay = msecs_to_jiffies(500); ++ else ++ delay = jiffies + ++ msecs_to_jiffies(lport->e_d_tov); ++ ++ schedule_delayed_work(&lport->retry_work, delay); ++ } else { ++ switch (lport->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_READY: ++ case LPORT_ST_RESET: ++ case LPORT_ST_RPN_ID: ++ case LPORT_ST_RFT_ID: ++ case LPORT_ST_SCR: ++ case LPORT_ST_DNS: ++ case LPORT_ST_FLOGI: ++ case LPORT_ST_LOGO: ++ fc_lport_enter_reset(lport); ++ break; ++ } + } + } + } +@@ -865,8 +971,7 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&lport->lp_mutex); + +- if (fc_lport_debug) +- FC_DBG("Received a RFT_ID response\n"); ++ FC_DEBUG_LPORT("Received a RFT_ID response\n"); + + if (lport->state != LPORT_ST_RFT_ID) { + FC_DBG("Received a RFT_ID response, but in state %s\n", +@@ -876,7 +981,7 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); +- goto out; ++ goto err; + } + + fh = fc_frame_header_get(fp); +@@ -890,8 +995,9 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, + else + fc_lport_error(lport, fp); + out: +- mutex_unlock(&lport->lp_mutex); + fc_frame_free(fp); ++err: ++ mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -914,8 +1020,7 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&lport->lp_mutex); + +- if (fc_lport_debug) +- FC_DBG("Received a RPN_ID response\n"); ++ FC_DEBUG_LPORT("Received a RPN_ID response\n"); + + if (lport->state != LPORT_ST_RPN_ID) { + FC_DBG("Received a RPN_ID response, but in state %s\n", +@@ -925,7 +1030,7 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); +- goto out; ++ goto err; + } + + fh = fc_frame_header_get(fp); +@@ -939,8 +1044,9 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, + fc_lport_error(lport, fp); + + out: +- mutex_unlock(&lport->lp_mutex); + fc_frame_free(fp); ++err: ++ mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -961,8 +1067,7 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&lport->lp_mutex); + +- if (fc_lport_debug) +- FC_DBG("Received a SCR response\n"); ++ FC_DEBUG_LPORT("Received a SCR response\n"); + + if (lport->state != LPORT_ST_SCR) { + FC_DBG("Received a SCR response, but in state %s\n", +@@ -972,7 +1077,7 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); +- goto out; ++ goto err; + } + + op = fc_frame_payload_op(fp); +@@ -982,8 +1087,9 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, + fc_lport_error(lport, fp); + + out: +- mutex_unlock(&lport->lp_mutex); + fc_frame_free(fp); ++err: ++ mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -998,9 +1104,8 @@ static void fc_lport_enter_scr(struct fc_lport *lport) + struct fc_frame *fp; + struct fc_els_scr *scr; + +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered SCR state from %s state\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered SCR state from %s state\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_SCR); + +@@ -1020,7 +1125,8 @@ static void fc_lport_enter_scr(struct fc_lport *lport) + if (!lport->tt.exch_seq_send(lport, fp, + fc_lport_scr_resp, NULL, + lport, lport->e_d_tov, +- lport->fid, FC_FID_FCTRL, ++ fc_host_port_id(lport->host), ++ FC_FID_FCTRL, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_lport_error(lport, fp); + } +@@ -1043,9 +1149,8 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) + struct fc_ns_fts *lps; + int i; + +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered RFT_ID state from %s state\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered RFT_ID state from %s state\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_RFT_ID); + +@@ -1069,14 +1174,14 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) + FC_NS_RFT_ID, + sizeof(*req) - + sizeof(struct fc_ct_hdr)); +- hton24(req->fid.fp_fid, lport->fid); ++ hton24(req->fid.fp_fid, fc_host_port_id(lport->host)); + req->fts = *lps; + fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); + + if (!lport->tt.exch_seq_send(lport, fp, + fc_lport_rft_id_resp, NULL, + lport, lport->e_d_tov, +- lport->fid, ++ fc_host_port_id(lport->host), + FC_FID_DIR_SERV, + FC_FC_SEQ_INIT | + FC_FC_END_SEQ)) +@@ -1099,9 +1204,8 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport) + struct fc_ns_rn_id rn; + } *req; + +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered RPN_ID state from %s state\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered RPN_ID state from %s state\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_RPN_ID); + +@@ -1114,14 +1218,14 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport) + req = fc_frame_payload_get(fp, sizeof(*req)); + memset(req, 0, sizeof(*req)); + fc_fill_dns_hdr(lport, &req->ct, FC_NS_RPN_ID, sizeof(req->rn)); +- hton24(req->rn.fr_fid.fp_fid, lport->fid); ++ hton24(req->rn.fr_fid.fp_fid, fc_host_port_id(lport->host)); + put_unaligned_be64(lport->wwpn, &req->rn.fr_wwn); + fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); + + if (!lport->tt.exch_seq_send(lport, fp, + fc_lport_rpn_id_resp, NULL, + lport, lport->e_d_tov, +- lport->fid, ++ fc_host_port_id(lport->host), + FC_FID_DIR_SERV, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_lport_error(lport, fp); +@@ -1147,20 +1251,18 @@ static void fc_lport_enter_dns(struct fc_lport *lport) + dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; + dp.lp = lport; + +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered DNS state from %s state\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered DNS state from %s state\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_DNS); + + if (!lport->dns_rp) { +- /* Set up a dummy rport to directory server */ +- rport = fc_rport_dummy_create(&dp); ++ /* Set up a rogue rport to directory server */ ++ rport = fc_rport_rogue_create(&dp); + + if (!rport) + goto err; + lport->dns_rp = rport; +- FC_DBG("created an rport for the NS\n"); + } + + rport = lport->dns_rp; +@@ -1232,8 +1334,7 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&lport->lp_mutex); + +- if (fc_lport_debug) +- FC_DBG("Received a LOGO response\n"); ++ FC_DEBUG_LPORT("Received a LOGO response\n"); + + if (lport->state != LPORT_ST_LOGO) { + FC_DBG("Received a LOGO response, but in state %s\n", +@@ -1243,7 +1344,7 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); +- goto out; ++ goto err; + } + + op = fc_frame_payload_op(fp); +@@ -1253,8 +1354,9 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + fc_lport_error(lport, fp); + + out: +- mutex_unlock(&lport->lp_mutex); + fc_frame_free(fp); ++err: ++ mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -1269,15 +1371,14 @@ static void fc_lport_enter_logo(struct fc_lport *lport) + struct fc_frame *fp; + struct fc_els_logo *logo; + +- if (fc_lport_debug) +- FC_DBG("Port (%6x) entered LOGO state from %s state\n", +- lport->fid, fc_lport_state(lport)); ++ FC_DEBUG_LPORT("Port (%6x) entered LOGO state from %s state\n", ++ fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_LOGO); + + /* DNS session should be closed so we can release it here */ + if (lport->dns_rp) { +- fc_remote_port_delete(lport->dns_rp); ++ lport->tt.rport_logout(lport->dns_rp); + lport->dns_rp = NULL; + } + +@@ -1290,7 +1391,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport) + logo = fc_frame_payload_get(fp, sizeof(*logo)); + memset(logo, 0, sizeof(*logo)); + logo->fl_cmd = ELS_LOGO; +- hton24(logo->fl_n_port_id, lport->fid); ++ hton24(logo->fl_n_port_id, fc_host_port_id(lport->host)); + logo->fl_n_port_wwn = htonll(lport->wwpn); + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + fc_frame_set_offset(fp, 0); +@@ -1298,7 +1399,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport) + if (!lport->tt.exch_seq_send(lport, fp, + fc_lport_logo_resp, NULL, + lport, lport->e_d_tov, +- lport->fid, FC_FID_FLOGI, ++ fc_host_port_id(lport->host), FC_FID_FLOGI, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_lport_error(lport, fp); + } +@@ -1327,8 +1428,7 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&lport->lp_mutex); + +- if (fc_lport_debug) +- FC_DBG("Received a FLOGI response\n"); ++ FC_DEBUG_LPORT("Received a FLOGI response\n"); + + if (lport->state != LPORT_ST_FLOGI) { + FC_DBG("Received a FLOGI response, but in state %s\n", +@@ -1338,16 +1438,16 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_lport_error(lport, fp); +- goto out; ++ goto err; + } + + fh = fc_frame_header_get(fp); + did = ntoh24(fh->fh_d_id); + if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { +- if (fc_lport_debug) +- FC_DBG("Assigned fid %x\n", did); + +- lport->fid = did; ++ FC_DEBUG_LPORT("Assigned fid %x\n", did); ++ fc_host_port_id(lport->host) = did; ++ + flp = fc_frame_payload_get(fp, sizeof(*flp)); + if (flp) { + mfs = ntohs(flp->fl_csp.sp_bb_data) & +@@ -1391,8 +1491,9 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + } + + out: +- mutex_unlock(&lport->lp_mutex); + fc_frame_free(fp); ++err: ++ mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -1407,8 +1508,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport) + struct fc_frame *fp; + struct fc_els_flogi *flp; + +- if (fc_lport_debug) +- FC_DBG("Processing FLOGI state\n"); ++ FC_DEBUG_LPORT("Processing FLOGI state\n"); + + fc_lport_state_enter(lport, LPORT_ST_FLOGI); + +@@ -1436,6 +1536,7 @@ int fc_lport_config(struct fc_lport *lport) + { + INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); + mutex_init(&lport->lp_mutex); ++ INIT_LIST_HEAD(&lport->rports); + + fc_lport_state_enter(lport, LPORT_ST_NONE); + +@@ -1456,6 +1557,9 @@ int fc_lport_init(struct fc_lport *lport) + if (!lport->tt.lport_reset) + lport->tt.lport_reset = fc_lport_reset; + ++ if (!lport->tt.rport_lookup) ++ lport->tt.rport_lookup = fc_lport_lookup_rport; ++ + if (!lport->tt.event_callback) + lport->tt.event_callback = fc_lport_rport_event; + +diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c +index 107b304..651a3ed 100644 +--- a/drivers/scsi/libfc/fc_rport.c ++++ b/drivers/scsi/libfc/fc_rport.c +@@ -18,10 +18,27 @@ + */ + + /* +- * Remote Port support. ++ * This file contains all processing regarding fc_rports. It contains the ++ * rport state machine and does all rport interaction with the transport class. ++ * There should be no other places in libfc that interact directly with the ++ * transport class in regards to adding and deleting rports. + * +- * A remote port structure contains information about an N port to which we +- * will create sessions. ++ * fc_rport's represent N_Port's within the fabric. ++ * ++ * rport locking notes: ++ * ++ * The rport should never hold the rport mutex and then lock the lport ++ * mutex. The rport's mutex is considered lesser than the lport's mutex, so ++ * the lport mutex can be held before locking the rport mutex, but not the ++ * other way around. See the comment block at the top of fc_lport.c for more ++ * details. ++ * ++ * The locking strategy is similar to the lport's strategy. The lock protects ++ * the rport's states and is held and released by the entry points to the rport ++ * block. All _enter_* functions correspond to rport states and expect the rport ++ * mutex to be locked before calling them. This means that rports only handle one ++ * request or response at a time, since they're not critical for the I/O path ++ * this potential over-use of the mutex is acceptable. + */ + + #include +@@ -34,7 +51,15 @@ + + #include + +-static int fc_rp_debug; ++static int fc_rport_debug; ++ ++#define FC_DEBUG_RPORT(fmt...) \ ++ do { \ ++ if (fc_rport_debug) \ ++ FC_DBG(fmt); \ ++ } while (0) ++ ++static struct workqueue_struct *rport_event_queue; + + static void fc_rport_enter_plogi(struct fc_rport *); + static void fc_rport_enter_prli(struct fc_rport *); +@@ -52,6 +77,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *, + struct fc_seq *, struct fc_frame *); + static void fc_rport_timeout(struct work_struct *); + static void fc_rport_error(struct fc_rport *, struct fc_frame *); ++static void fc_rport_work(struct work_struct *); + + static const char *fc_rport_state_names[] = { + [RPORT_ST_NONE] = "None", +@@ -63,7 +89,7 @@ static const char *fc_rport_state_names[] = { + [RPORT_ST_LOGO] = "LOGO", + }; + +-struct fc_rport *fc_rport_dummy_create(struct fc_disc_port *dp) ++struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) + { + struct fc_rport *rport; + struct fc_rport_libfc_priv *rdata; +@@ -91,11 +117,17 @@ struct fc_rport *fc_rport_dummy_create(struct fc_disc_port *dp) + rdata->e_d_tov = dp->lp->e_d_tov; + rdata->r_a_tov = dp->lp->r_a_tov; + INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); ++ INIT_WORK(&rdata->event_work, fc_rport_work); ++ /* ++ * For good measure, but not necessary as we should only ++ * add REAL rport to the lport list. ++ */ ++ INIT_LIST_HEAD(&rdata->peers); + + return rport; + } + +-void fc_rport_dummy_destroy(struct fc_rport *rport) ++void fc_rport_rogue_destroy(struct fc_rport *rport) + { + kfree(rport); + } +@@ -116,30 +148,6 @@ static const char *fc_rport_state(struct fc_rport *rport) + } + + /** +- * fc_rport_lookup - lookup a remote port by port_id +- * @lp: Fibre Channel host port instance +- * @fid: remote port port_id to match +- */ +-struct fc_rport *fc_rport_lookup(const struct fc_lport *lp, u32 fid) +-{ +- struct Scsi_Host *shost = lp->host; +- struct fc_rport *rport, *found; +- unsigned long flags; +- +- found = NULL; +- spin_lock_irqsave(shost->host_lock, flags); +- list_for_each_entry(rport, &fc_host_rports(shost), peers) +- if (rport->port_id == fid && +- rport->port_state == FC_PORTSTATE_ONLINE) { +- found = rport; +- get_device(&found->dev); +- break; +- } +- spin_unlock_irqrestore(shost->host_lock, flags); +- return found; +-} +- +-/** + * fc_set_rport_loss_tmo - Set the remote port loss timeout in seconds. + * @rport: Pointer to Fibre Channel remote port structure + * @timeout: timeout in seconds +@@ -229,15 +237,20 @@ static void fc_rport_state_enter(struct fc_rport *rport, + rdata->rp_state = new; + } + +-static void fc_rport_unlock(struct fc_rport *rport) ++static void fc_rport_work(struct work_struct *work) + { +- struct fc_rport_libfc_priv *rdata = rport->dd_data; +- enum fc_lport_event event = rdata->event; ++ struct fc_rport_libfc_priv *rdata = ++ container_of(work, struct fc_rport_libfc_priv, event_work); ++ enum fc_lport_event event; ++ enum fc_rport_trans_state trans_state; + struct fc_lport *lport = rdata->local_port; +- u32 fid = rport->port_id; +- void (*event_callback)(struct fc_lport *, u32, +- enum fc_lport_event) = +- rdata->event_callback; ++ void (*event_callback)(struct fc_lport *, struct fc_rport *, ++ enum fc_lport_event); ++ struct fc_rport *rport = PRIV_TO_RPORT(rdata); ++ ++ mutex_lock(&rdata->rp_mutex); ++ event = rdata->event; ++ event_callback = rdata->event_callback; + + if (event == LPORT_EV_RPORT_CREATED) { + struct fc_rport *new_rport; +@@ -249,10 +262,12 @@ static void fc_rport_unlock(struct fc_rport *rport) + ids.port_name = rport->port_name; + ids.node_name = rport->node_name; + ++ mutex_unlock(&rdata->rp_mutex); ++ + new_rport = fc_remote_port_add(lport->host, 0, &ids); + if (new_rport) { + /* +- * Switch from the dummy rport to the rport ++ * Switch from the rogue rport to the rport + * returned by the FC class. + */ + new_rport->maxframe_size = rport->maxframe_size; +@@ -267,36 +282,32 @@ static void fc_rport_unlock(struct fc_rport *rport) + mutex_init(&new_rdata->rp_mutex); + INIT_DELAYED_WORK(&new_rdata->retry_work, + fc_rport_timeout); ++ INIT_LIST_HEAD(&new_rdata->peers); ++ INIT_WORK(&new_rdata->event_work, fc_rport_work); + + fc_rport_state_enter(new_rport, RPORT_ST_READY); +- fc_remote_port_rolechg(new_rport, rdata->roles); + } else { + FC_DBG("Failed to create the rport for port " + "(%6x).\n", ids.port_id); + event = LPORT_EV_RPORT_FAILED; + } +- +- mutex_unlock(&rdata->rp_mutex); +- fc_rport_dummy_destroy(rport); ++ fc_rport_rogue_destroy(rport); + rport = new_rport; + rdata = new_rport->dd_data; ++ event_callback(lport, rport, event); + } else if ((event == LPORT_EV_RPORT_FAILED) || +- (event == LPORT_EV_RPORT_LOGO)) { +- if (rdata->trans_state == FC_PORTSTATE_ROGUE) { +- mutex_unlock(&rdata->rp_mutex); +- fc_rport_dummy_destroy(rport); +- } else { +- mutex_unlock(&rdata->rp_mutex); ++ (event == LPORT_EV_RPORT_LOGO) || ++ (event == LPORT_EV_RPORT_STOP)) { ++ ++ trans_state = rdata->trans_state; ++ mutex_unlock(&rdata->rp_mutex); ++ event_callback(lport, rport, event); ++ if (trans_state == FC_PORTSTATE_ROGUE) ++ fc_rport_rogue_destroy(rport); ++ else + fc_remote_port_delete(rport); +- } +- } else { ++ } else + mutex_unlock(&rdata->rp_mutex); +- } +- +- if (event != LPORT_EV_RPORT_NONE && event_callback) { +- event_callback(lport, fid, event); +- rdata->event = LPORT_EV_RPORT_NONE; +- } + } + + /** +@@ -313,12 +324,11 @@ int fc_rport_login(struct fc_rport *rport) + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Login to port (%6x)\n", rport->port_id); ++ FC_DEBUG_RPORT("Login to port (%6x)\n", rport->port_id); + + fc_rport_enter_plogi(rport); + +- fc_rport_unlock(rport); ++ mutex_unlock(&rdata->rp_mutex); + + return 0; + } +@@ -337,57 +347,37 @@ int fc_rport_logout(struct fc_rport *rport) + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Logout of port (%6x)\n", rport->port_id); ++ FC_DEBUG_RPORT("Logout of port (%6x)\n", rport->port_id); + + fc_rport_enter_logo(rport); +- fc_rport_unlock(rport); ++ ++ mutex_unlock(&rdata->rp_mutex); + + return 0; + } + + /** +- * fc_rport_reset - Reset the remote port +- * @rport: Fibre Channel remote port +- * +- * XXX - This functionality is currently broken ++ * fc_rport_remove - Remove an rport ++ * @rport: Fibre Channel remote port to be removed + * + * Locking Note: Called without the rport lock held. This + * function will hold the rport lock, call an _enter_* + * function and then unlock the rport. + */ +-void fc_rport_reset(struct fc_rport *rport) ++int fc_rport_stop(struct fc_rport *rport) + { + struct fc_rport_libfc_priv *rdata = rport->dd_data; + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Reset port (%6x)\n", rport->port_id); ++ FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id); + +- fc_rport_enter_plogi(rport); +- +- fc_rport_unlock(rport); +-} ++ rdata->event = LPORT_EV_RPORT_STOP; ++ queue_work(rport_event_queue, &rdata->event_work); + +-/** +- * fc_rport_reset_list - Reset all sessions for a local port session list. +- * @lport: The lport whose rports should be reset +- * +- * Locking Note: TBD +- */ +-void fc_rport_reset_list(struct fc_lport *lport) +-{ +- struct Scsi_Host *shost = lport->host; +- struct fc_rport *rport; +- struct fc_rport *next; +- unsigned long flags; ++ mutex_unlock(&rdata->rp_mutex); + +- spin_lock_irqsave(shost->host_lock, flags); +- list_for_each_entry_safe(rport, next, &fc_host_rports(shost), peers) { +- lport->tt.rport_reset(rport); +- } +- spin_unlock_irqrestore(shost->host_lock, flags); ++ return 0; + } + + /** +@@ -403,10 +393,10 @@ static void fc_rport_enter_ready(struct fc_rport *rport) + + fc_rport_state_enter(rport, RPORT_ST_READY); + +- if (fc_rp_debug) +- FC_DBG("Port (%6x) is Ready\n", rport->port_id); ++ FC_DEBUG_RPORT("Port (%6x) is Ready\n", rport->port_id); + + rdata->event = LPORT_EV_RPORT_CREATED; ++ queue_work(rport_event_queue, &rdata->event_work); + } + + /** +@@ -447,7 +437,7 @@ static void fc_rport_timeout(struct work_struct *work) + } + put_device(&rport->dev); + +- fc_rport_unlock(rport); ++ mutex_unlock(&rdata->rp_mutex); + } + + /** +@@ -467,37 +457,37 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) + struct fc_rport_libfc_priv *rdata = rport->dd_data; + unsigned long delay = 0; + +- if (fc_rp_debug) +- FC_DBG("Error %ld in state %s, retries %d\n", ++ FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n", + PTR_ERR(fp), fc_rport_state(rport), rdata->retries); + +- if (rdata->retries < rdata->local_port->max_retry_count) { +- rdata->retries++; +- if (!fp) +- delay = msecs_to_jiffies(500); +- get_device(&rport->dev); +- schedule_delayed_work(&rdata->retry_work, delay); +- } else { +- switch (rdata->rp_state) { +- case RPORT_ST_PLOGI: +- case RPORT_ST_PRLI: +- case RPORT_ST_LOGO: +- if (fc_rp_debug) +- FC_DBG("Remote port (%6x) closed.\n", +- rport->port_id); +- +- fc_remote_port_delete(rport); +- +- rdata->event = LPORT_EV_RPORT_FAILED; +- break; +- case RPORT_ST_RTV: +- fc_rport_enter_ready(rport); +- break; +- case RPORT_ST_NONE: +- case RPORT_ST_READY: +- case RPORT_ST_INIT: +- BUG(); +- break; ++ if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { ++ /* ++ * Memory allocation failure, or the exchange timed out. ++ * Retry after delay ++ */ ++ if (rdata->retries < rdata->local_port->max_retry_count) { ++ rdata->retries++; ++ if (!fp) ++ delay = msecs_to_jiffies(500); ++ get_device(&rport->dev); ++ schedule_delayed_work(&rdata->retry_work, delay); ++ } else { ++ switch (rdata->rp_state) { ++ case RPORT_ST_PLOGI: ++ case RPORT_ST_PRLI: ++ case RPORT_ST_LOGO: ++ rdata->event = LPORT_EV_RPORT_FAILED; ++ queue_work(rport_event_queue, &rdata->event_work); ++ break; ++ case RPORT_ST_RTV: ++ fc_rport_enter_ready(rport); ++ break; ++ case RPORT_ST_NONE: ++ case RPORT_ST_READY: ++ case RPORT_ST_INIT: ++ BUG(); ++ break; ++ } + } + } + } +@@ -526,8 +516,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Received a PLOGI response\n"); ++ FC_DEBUG_RPORT("Received a PLOGI response\n"); + + if (rdata->rp_state != RPORT_ST_PLOGI) { + FC_DBG("Received a PLOGI response, but in state %s\n", +@@ -537,12 +526,15 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- goto out; ++ goto err; + } + + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC && + (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { ++ rport->port_name = get_unaligned_be64(&plp->fl_wwpn); ++ rport->node_name = get_unaligned_be64(&plp->fl_wwnn); ++ + tov = ntohl(plp->fl_csp.sp_e_d_tov); + if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) + tov /= 1000; +@@ -568,8 +560,9 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, + fc_rport_error(rport, fp); + + out: +- fc_rport_unlock(rport); + fc_frame_free(fp); ++err: ++ mutex_unlock(&rdata->rp_mutex); + } + + /** +@@ -586,8 +579,7 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) + struct fc_frame *fp; + struct fc_els_flogi *plogi; + +- if (fc_rp_debug) +- FC_DBG("Port (%6x) entered PLOGI state from %s state\n", ++ FC_DEBUG_RPORT("Port (%6x) entered PLOGI state from %s state\n", + rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_PLOGI); +@@ -607,7 +599,7 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) + if (!lport->tt.exch_seq_send(lport, fp, + fc_rport_plogi_resp, NULL, + rport, lport->e_d_tov, +- rdata->local_port->fid, ++ fc_host_port_id(rdata->local_port->host), + rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_rport_error(rport, fp); +@@ -638,8 +630,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Received a PRLI response\n"); ++ FC_DEBUG_RPORT("Received a PRLI response\n"); + + if (rdata->rp_state != RPORT_ST_PRLI) { + FC_DBG("Received a PRLI response, but in state %s\n", +@@ -649,7 +640,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- goto out; ++ goto err; + } + + op = fc_frame_payload_op(fp); +@@ -667,18 +658,19 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + if (fcp_parm & FCP_SPPF_TARG_FCN) + roles |= FC_RPORT_ROLE_FCP_TARGET; + +- rdata->roles = roles; ++ rport->roles = roles; + fc_rport_enter_rtv(rport); + + } else { + FC_DBG("Bad ELS response\n"); + rdata->event = LPORT_EV_RPORT_FAILED; +- fc_remote_port_delete(rport); ++ queue_work(rport_event_queue, &rdata->event_work); + } + + out: +- fc_rport_unlock(rport); + fc_frame_free(fp); ++err: ++ mutex_unlock(&rdata->rp_mutex); + } + + /** +@@ -700,8 +692,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Received a LOGO response\n"); ++ FC_DEBUG_RPORT("Received a LOGO response\n"); + + if (rdata->rp_state != RPORT_ST_LOGO) { + FC_DBG("Received a LOGO response, but in state %s\n", +@@ -711,22 +702,22 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- goto out; ++ goto err; + } + + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC) { + fc_rport_enter_rtv(rport); +- + } else { + FC_DBG("Bad ELS response\n"); + rdata->event = LPORT_EV_RPORT_LOGO; +- fc_remote_port_delete(rport); ++ queue_work(rport_event_queue, &rdata->event_work); + } + + out: +- fc_rport_unlock(rport); + fc_frame_free(fp); ++err: ++ mutex_unlock(&rdata->rp_mutex); + } + + /** +@@ -746,8 +737,7 @@ static void fc_rport_enter_prli(struct fc_rport *rport) + } *pp; + struct fc_frame *fp; + +- if (fc_rp_debug) +- FC_DBG("Port (%6x) entered PRLI state from %s state\n", ++ FC_DEBUG_RPORT("Port (%6x) entered PRLI state from %s state\n", + rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_PRLI); +@@ -771,7 +761,8 @@ static void fc_rport_enter_prli(struct fc_rport *rport) + if (!lport->tt.exch_seq_send(lport, fp, + fc_rport_prli_resp, NULL, + rport, lport->e_d_tov, +- lport->fid, rport->port_id, ++ fc_host_port_id(lport->host), ++ rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_rport_error(rport, fp); + } +@@ -797,8 +788,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- if (fc_rp_debug) +- FC_DBG("Received a RTV response\n"); ++ FC_DEBUG_RPORT("Received a RTV response\n"); + + if (rdata->rp_state != RPORT_ST_RTV) { + FC_DBG("Received a RTV response, but in state %s\n", +@@ -808,7 +798,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, + + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); +- goto out; ++ goto err; + } + + op = fc_frame_payload_op(fp); +@@ -836,8 +826,9 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, + fc_rport_enter_ready(rport); + + out: +- fc_rport_unlock(rport); + fc_frame_free(fp); ++err: ++ mutex_unlock(&rdata->rp_mutex); + } + + /** +@@ -854,8 +845,7 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) + struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_lport *lport = rdata->local_port; + +- if (fc_rp_debug) +- FC_DBG("Port (%6x) entered RTV state from %s state\n", ++ FC_DEBUG_RPORT("Port (%6x) entered RTV state from %s state\n", + rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_RTV); +@@ -874,7 +864,8 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) + if (!lport->tt.exch_seq_send(lport, fp, + fc_rport_rtv_resp, NULL, + rport, lport->e_d_tov, +- lport->fid, rport->port_id, ++ fc_host_port_id(lport->host), ++ rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_rport_error(rport, fp); + } +@@ -893,8 +884,7 @@ static void fc_rport_enter_logo(struct fc_rport *rport) + struct fc_frame *fp; + struct fc_els_logo *logo; + +- if (fc_rp_debug) +- FC_DBG("Port (%6x) entered LOGO state from %s state\n", ++ FC_DEBUG_RPORT("Port (%6x) entered LOGO state from %s state\n", + rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_LOGO); +@@ -908,14 +898,15 @@ static void fc_rport_enter_logo(struct fc_rport *rport) + logo = fc_frame_payload_get(fp, sizeof(*logo)); + memset(logo, 0, sizeof(*logo)); + logo->fl_cmd = ELS_LOGO; +- hton24(logo->fl_n_port_id, lport->fid); ++ hton24(logo->fl_n_port_id, fc_host_port_id(lport->host)); + logo->fl_n_port_wwn = htonll(lport->wwpn); + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + + if (!lport->tt.exch_seq_send(lport, fp, + fc_rport_logo_resp, NULL, + rport, lport->e_d_tov, +- lport->fid, rport->port_id, ++ fc_host_port_id(lport->host), ++ rport->port_id, + FC_FC_SEQ_INIT | FC_FC_END_SEQ)) + fc_rport_error(rport, fp); + } +@@ -979,7 +970,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, + } + } + +- fc_rport_unlock(rport); ++ mutex_unlock(&rdata->rp_mutex); + fc_frame_free(fp); + } + +@@ -1011,8 +1002,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + + fh = fc_frame_header_get(fp); + +- if (fc_rp_debug) +- FC_DBG("Received PLOGI request from port (%6x) " ++ FC_DEBUG_RPORT("Received PLOGI request from port (%6x) " + "while in state %s\n", ntoh24(fh->fh_s_id), + fc_rport_state(rport)); + +@@ -1041,29 +1031,25 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + */ + switch (rdata->rp_state) { + case RPORT_ST_INIT: +- if (fc_rp_debug) +- FC_DBG("incoming PLOGI from %6x wwpn %llx state INIT " ++ FC_DEBUG_RPORT("incoming PLOGI from %6x wwpn %llx state INIT " + "- reject\n", sid, wwpn); + reject = ELS_RJT_UNSUP; + break; + case RPORT_ST_PLOGI: +- if (fc_rp_debug) +- FC_DBG("incoming PLOGI from %x in PLOGI state %d\n", ++ FC_DEBUG_RPORT("incoming PLOGI from %x in PLOGI state %d\n", + sid, rdata->rp_state); + if (wwpn < lport->wwpn) + reject = ELS_RJT_INPROG; + break; + case RPORT_ST_PRLI: + case RPORT_ST_READY: +- if (fc_rp_debug) +- FC_DBG("incoming PLOGI from %x in logged-in state %d " ++ FC_DEBUG_RPORT("incoming PLOGI from %x in logged-in state %d " + "- ignored for now\n", sid, rdata->rp_state); + /* XXX TBD - should reset */ + break; + case RPORT_ST_NONE: + default: +- if (fc_rp_debug) +- FC_DBG("incoming PLOGI from %x in unexpected " ++ FC_DEBUG_RPORT("incoming PLOGI from %x in unexpected " + "state %d\n", sid, rdata->rp_state); + break; + } +@@ -1145,8 +1131,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + + fh = fc_frame_header_get(rx_fp); + +- if (fc_rp_debug) +- FC_DBG("Received PRLI request from port (%6x) " ++ FC_DEBUG_RPORT("Received PRLI request from port (%6x) " + "while in state %s\n", ntoh24(fh->fh_s_id), + fc_rport_state(rport)); + +@@ -1220,7 +1205,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + roles |= FC_RPORT_ROLE_FCP_INITIATOR; + if (fcp_parm & FCP_SPPF_TARG_FCN) + roles |= FC_RPORT_ROLE_FCP_TARGET; +- rdata->roles = roles; ++ rport->roles = roles; + + spp->spp_params = + htonl(lport->service_params); +@@ -1278,8 +1263,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, + + fh = fc_frame_header_get(fp); + +- if (fc_rp_debug) +- FC_DBG("Received PRLO request from port (%6x) " ++ FC_DEBUG_RPORT("Received PRLO request from port (%6x) " + "while in state %s\n", ntoh24(fh->fh_s_id), + fc_rport_state(rport)); + +@@ -1308,12 +1292,12 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, + + fh = fc_frame_header_get(fp); + +- if (fc_rp_debug) +- FC_DBG("Received LOGO request from port (%6x) " ++ FC_DEBUG_RPORT("Received LOGO request from port (%6x) " + "while in state %s\n", ntoh24(fh->fh_s_id), + fc_rport_state(rport)); + + rdata->event = LPORT_EV_RPORT_LOGO; ++ queue_work(rport_event_queue, &rdata->event_work); + + lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + fc_frame_free(fp); +@@ -1327,63 +1311,37 @@ int fc_rport_init(struct fc_lport *lport) + if (!lport->tt.rport_logout) + lport->tt.rport_logout = fc_rport_logout; + ++ if (!lport->tt.rport_stop) ++ lport->tt.rport_stop = fc_rport_stop; ++ + if (!lport->tt.rport_recv_req) + lport->tt.rport_recv_req = fc_rport_recv_req; + +- if (!lport->tt.rport_lookup) +- lport->tt.rport_lookup = fc_rport_lookup; +- +- if (!lport->tt.rport_reset) +- lport->tt.rport_reset = fc_rport_reset; +- +- if (!lport->tt.rport_reset_list) +- lport->tt.rport_reset_list = fc_rport_reset_list; +- + return 0; + } + EXPORT_SYMBOL(fc_rport_init); + +-/** +- * fc_block_rports - delete all the remote ports, on reset or link down +- * @lp: libfc local port instance +- * +- * This routine temporarily removes any online remote ports from the fc_host +- * rport list, then drops the host lock in order to call fc_remote_port_delete() +- * on each rport in turn, and finally splices the list back onto the fc_host. +- */ +-void fc_block_rports(struct fc_lport *lp) ++int fc_setup_rport() + { +- struct Scsi_Host *shost = lp->host; +- struct fc_rport *rport, *next; +- unsigned long flags; +- LIST_HEAD(rports); +- +- spin_lock_irqsave(shost->host_lock, flags); +- list_for_each_entry_safe(rport, next, &fc_host_rports(shost), peers) { +- /* protect the name service remote port */ +- if (rport->port_id == FC_FID_DIR_SERV) +- continue; +- if (rport->port_state != FC_PORTSTATE_ONLINE) +- continue; +- list_move_tail(&rport->peers, &rports); +- } +- spin_unlock_irqrestore(shost->host_lock, flags); +- +- list_for_each_entry(rport, &rports, peers) { +- fc_remote_port_delete(rport); +- } ++ rport_event_queue = create_singlethread_workqueue("fc_rport_eq"); ++ if (!rport_event_queue) ++ return -ENOMEM; ++ return 0; ++} ++EXPORT_SYMBOL(fc_setup_rport); + +- spin_lock_irqsave(shost->host_lock, flags); +- list_splice(&rports, &fc_host_rports(shost)); +- spin_unlock_irqrestore(shost->host_lock, flags); ++void fc_destroy_rport() ++{ ++ destroy_workqueue(rport_event_queue); + } ++EXPORT_SYMBOL(fc_destroy_rport); + + void fc_rport_terminate_io(struct fc_rport *rport) + { +- struct fc_rport_libfc_priv *rp = rport->dd_data; +- struct fc_lport *lp = rp->local_port; ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_lport *lport = rdata->local_port; + +- lp->tt.exch_mgr_reset(lp->emp, 0, rport->port_id); +- lp->tt.exch_mgr_reset(lp->emp, rport->port_id, 0); ++ lport->tt.exch_mgr_reset(lport->emp, 0, rport->port_id); ++ lport->tt.exch_mgr_reset(lport->emp, rport->port_id, 0); + } + EXPORT_SYMBOL(fc_rport_terminate_io); +diff --git a/include/scsi/libfc/fc_frame.h b/include/scsi/libfc/fc_frame.h +index c7a52bb..9508e55 100644 +--- a/include/scsi/libfc/fc_frame.h ++++ b/include/scsi/libfc/fc_frame.h +@@ -51,6 +51,7 @@ + #define fr_sof(fp) (fr_cb(fp)->fr_sof) + #define fr_eof(fp) (fr_cb(fp)->fr_eof) + #define fr_flags(fp) (fr_cb(fp)->fr_flags) ++#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) + + struct fc_frame { + struct sk_buff skb; +@@ -63,6 +64,7 @@ struct fcoe_rcv_info { + enum fc_sof fr_sof; /* start of frame delimiter */ + enum fc_eof fr_eof; /* end of frame delimiter */ + u8 fr_flags; /* flags - see below */ ++ u16 fr_max_payload; /* max FC payload */ + }; + + /* +diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h +index 24d3fcb..7e5e6be 100644 +--- a/include/scsi/libfc/libfc.h ++++ b/include/scsi/libfc/libfc.h +@@ -36,12 +36,10 @@ + #define LIBFC_DEBUG + + #ifdef LIBFC_DEBUG +-/* +- * Log message. +- */ ++/* Log messages */ + #define FC_DBG(fmt, args...) \ + do { \ +- printk(KERN_INFO "%s " fmt, __func__, ##args); \ ++ printk(KERN_INFO "%s " fmt, __func__, ##args); \ + } while (0) + #else + #define FC_DBG(fmt, args...) +@@ -59,35 +57,22 @@ + #define ntohll(x) be64_to_cpu(x) + #define htonll(x) cpu_to_be64(x) + +-#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) ++#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) + +-#define hton24(p, v) do { \ +- p[0] = (((v) >> 16) & 0xFF); \ +- p[1] = (((v) >> 8) & 0xFF); \ +- p[2] = ((v) & 0xFF); \ +-} while (0) ++#define hton24(p, v) do { \ ++ p[0] = (((v) >> 16) & 0xFF); \ ++ p[1] = (((v) >> 8) & 0xFF); \ ++ p[2] = ((v) & 0xFF); \ ++ } while (0) + + struct fc_exch_mgr; + + /* +- * tgt_flags +- */ +-#define FC_TGT_REC_SUPPORTED (1 << 0) +- +-/* + * FC HBA status + */ + #define FC_PAUSE (1 << 1) + #define FC_LINK_UP (1 << 0) + +-/* for fc_softc */ +-#define FC_MAX_OUTSTANDING_COMMANDS 1024 +- +-/* +- * Transport Capabilities +- */ +-#define TRANS_C_SG (1 << 0) /* Scatter gather */ +- + enum fc_lport_state { + LPORT_ST_NONE = 0, + LPORT_ST_FLOGI, +@@ -104,6 +89,7 @@ enum fc_lport_event { + LPORT_EV_RPORT_NONE = 0, + LPORT_EV_RPORT_CREATED, + LPORT_EV_RPORT_FAILED, ++ LPORT_EV_RPORT_STOP, + LPORT_EV_RPORT_LOGO + }; + +@@ -163,9 +149,11 @@ struct fc_rport_libfc_priv { + struct mutex rp_mutex; + struct delayed_work retry_work; + enum fc_lport_event event; +- void (*event_callback)(struct fc_lport *, u32, ++ void (*event_callback)(struct fc_lport *, ++ struct fc_rport *, + enum fc_lport_event); +- u32 roles; ++ struct list_head peers; ++ struct work_struct event_work; + }; + + #define PRIV_TO_RPORT(x) \ +@@ -173,8 +161,8 @@ struct fc_rport_libfc_priv { + #define RPORT_TO_PRIV(x) \ + (struct fc_rport_libfc_priv*)((void *)x + sizeof(struct fc_rport)); + +-struct fc_rport *fc_rport_dummy_create(struct fc_disc_port *); +-void fc_rport_dummy_destroy(struct fc_rport *); ++struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *); ++void fc_rport_rogue_destroy(struct fc_rport *); + + static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) + { +@@ -360,7 +348,7 @@ struct libfc_function_template { + + int (*lport_reset)(struct fc_lport *); + +- void (*event_callback)(struct fc_lport *, u32, ++ void (*event_callback)(struct fc_lport *, struct fc_rport *, + enum fc_lport_event); + + /** +@@ -384,15 +372,21 @@ struct libfc_function_template { + */ + int (*rport_logout)(struct fc_rport *rport); + ++ /* ++ * Delete the rport and remove it from the transport if ++ * it had been added. This will not send a LOGO, use ++ * rport_logout for a gracefull logout. ++ */ ++ int (*rport_stop)(struct fc_rport *rport); ++ ++ /* ++ * Recieve a request from a remote port. ++ */ + void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, + struct fc_rport *); + + struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); + +- void (*rport_reset)(struct fc_rport *); +- +- void (*rport_reset_list)(struct fc_lport *); +- + /** + * SCSI interfaces + */ +@@ -429,6 +423,7 @@ struct fc_lport { + struct fc_rport *dns_rp; + struct fc_rport *ptp_rp; + void *scsi_priv; ++ struct list_head rports; + + /* Operational Information */ + struct libfc_function_template tt; +@@ -442,7 +437,6 @@ struct fc_lport { + + u64 wwpn; + u64 wwnn; +- u32 fid; + u8 retry_count; + unsigned char disc_retry_count; + unsigned char disc_delay; +@@ -452,8 +446,8 @@ struct fc_lport { + unsigned char disc_buf_len; + + /* Capabilities */ +- char ifname[IFNAMSIZ]; +- u32 capabilities; ++ u32 sg_supp:1; /* scatter gather supported */ ++ u32 seq_offload:1; /* seq offload supported */ + u32 mfs; /* max FC payload size */ + unsigned int service_params; + unsigned int e_d_tov; +@@ -484,11 +478,6 @@ static inline int fc_lport_test_ready(struct fc_lport *lp) + return lp->state == LPORT_ST_READY; + } + +-static inline u32 fc_lport_get_fid(const struct fc_lport *lp) +-{ +- return lp->fid; +-} +- + static inline void fc_set_wwnn(struct fc_lport *lp, u64 wwnn) + { + lp->wwnn = wwnn; +@@ -586,8 +575,6 @@ int fc_set_mfs(struct fc_lport *lp, u32 mfs); + *****************************/ + int fc_rport_init(struct fc_lport *lp); + void fc_rport_terminate_io(struct fc_rport *rp); +-void fc_block_rports(struct fc_lport *lp); +- + + /** + * DISCOVERY LAYER +@@ -776,6 +763,7 @@ void fc_seq_set_rec_data(struct fc_seq *sp, u32 rec_data); + * Functions for fc_functions_template + */ + void fc_get_host_speed(struct Scsi_Host *shost); ++void fc_get_host_port_type(struct Scsi_Host *shost); + void fc_get_host_port_state(struct Scsi_Host *shost); + void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout); + struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); +@@ -785,6 +773,7 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); + */ + int fc_setup_exch_mgr(void); + void fc_destroy_exch_mgr(void); +- ++int fc_setup_rport(void); ++void fc_destroy_rport(void); + + #endif /* _LIBFC_H_ */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta5-update b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta5-update new file mode 100644 index 000000000..34b5cec75 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta5-update @@ -0,0 +1,1814 @@ +Subject: Open-FCoE: Update for Beta5 +From: John Fastabend +Date: Fri Nov 7 15:38:25 2008 +0100: +Git: 4692e3314fc9ffdb33996bbff7b4aa8916d58f1c +References: bnc#438954 + +Incremental Open-FCoE update for Beta5. + +Signed-off-by: John Fastabend +Acked-by: Hannes Reinecke + +diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig +index f382eea..6f38b13 100644 +--- a/drivers/scsi/Kconfig ++++ b/drivers/scsi/Kconfig +@@ -336,7 +336,8 @@ config LIBFC + + config FCOE + tristate "FCoE module" +- depends on LIBFC ++ depends on SCSI && SCSI_FC_ATTRS ++ select LIBFC + ---help--- + Fibre Channel over Ethernet module + +diff --git a/drivers/scsi/fcoe/fc_transport_fcoe.c b/drivers/scsi/fcoe/fc_transport_fcoe.c +index e11d36b..ff207b2 100644 +--- a/drivers/scsi/fcoe/fc_transport_fcoe.c ++++ b/drivers/scsi/fcoe/fc_transport_fcoe.c +@@ -38,6 +38,7 @@ + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("FCoE"); + MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0.3"); + + /* + * Static functions and variables definations +@@ -71,16 +72,13 @@ static void fcoe_create_percpu_data(int cpu) + { + struct fc_lport *lp; + struct fcoe_softc *fc; +- struct fcoe_dev_stats *p; + + write_lock_bh(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { + lp = fc->lp; +- if (lp->dev_stats[cpu] == NULL) { +- p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); +- if (p) +- lp->dev_stats[cpu] = p; +- } ++ if (lp->dev_stats[cpu] == NULL) ++ lp->dev_stats[cpu] = kzalloc(sizeof(struct fcoe_dev_stats), ++ GFP_KERNEL); + } + write_unlock_bh(&fcoe_hostlist_lock); + } +@@ -91,18 +89,14 @@ static void fcoe_create_percpu_data(int cpu) + */ + static void fcoe_destroy_percpu_data(int cpu) + { +- struct fcoe_dev_stats *p; + struct fc_lport *lp; + struct fcoe_softc *fc; + + write_lock_bh(&fcoe_hostlist_lock); + list_for_each_entry(fc, &fcoe_hostlist, list) { + lp = fc->lp; +- p = lp->dev_stats[cpu]; +- if (p != NULL) { +- lp->dev_stats[cpu] = NULL; +- kfree(p); +- } ++ kfree(lp->dev_stats[cpu]); ++ lp->dev_stats[cpu] = NULL; + } + write_unlock_bh(&fcoe_hostlist_lock); + } +@@ -211,7 +205,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, + fc_linkup(lp); + else { + stats = lp->dev_stats[smp_processor_id()]; +- stats->LinkFailureCount++; ++ if (stats) ++ stats->LinkFailureCount++; + fc_linkdown(lp); + fcoe_clean_pending_queue(lp); + } +@@ -227,42 +222,44 @@ static void trimstr(char *str, int len) + *cp = '\0'; + } + +-static ssize_t fcoe_destroy(struct kobject *kobj, struct kobj_attribute *attr, +- const char *buffer, size_t size) ++static int fcoe_destroy(const char *buffer, struct kernel_param *kp) + { + struct net_device *netdev; + char ifname[IFNAMSIZ + 2]; ++ int rc = -ENODEV; + + strlcpy(ifname, buffer, IFNAMSIZ); + trimstr(ifname, strlen(ifname)); + netdev = dev_get_by_name(&init_net, ifname); + if (netdev) { +- fcoe_destroy_interface(netdev); ++ rc = fcoe_destroy_interface(netdev); + dev_put(netdev); + } +- return size; ++ return rc; + } + +-static ssize_t fcoe_create(struct kobject *kobj, struct kobj_attribute *attr, +- const char *buffer, size_t size) ++static int fcoe_create(const char *buffer, struct kernel_param *kp) + { + struct net_device *netdev; + char ifname[IFNAMSIZ + 2]; ++ int rc = -ENODEV; + + strlcpy(ifname, buffer, IFNAMSIZ); + trimstr(ifname, strlen(ifname)); + netdev = dev_get_by_name(&init_net, ifname); + if (netdev) { +- fcoe_create_interface(netdev); ++ rc = fcoe_create_interface(netdev); + dev_put(netdev); + } +- return size; ++ return rc; + } + +-static const struct kobj_attribute fcoe_destroyattr = \ +- __ATTR(destroy, S_IWUSR, NULL, fcoe_destroy); +-static const struct kobj_attribute fcoe_createattr = \ +- __ATTR(create, S_IWUSR, NULL, fcoe_create); ++module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); ++__MODULE_PARM_TYPE(create, "string"); ++MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); ++module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); ++__MODULE_PARM_TYPE(destroy, "string"); ++MODULE_PARM_DESC(destroy, "Destroy fcoe port"); + + /* + * Initialization routine +@@ -271,19 +268,9 @@ static const struct kobj_attribute fcoe_createattr = \ + */ + static int __init fcoe_init(void) + { +- int rc = 0; + int cpu; + struct fcoe_percpu_s *p; + +- rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, +- &fcoe_destroyattr.attr); +- if (!rc) +- rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, +- &fcoe_createattr.attr); +- +- if (rc) +- return rc; +- + rwlock_init(&fcoe_hostlist_lock); + + #ifdef CONFIG_HOTPLUG_CPU +@@ -317,11 +304,6 @@ static int __init fcoe_init(void) + } + } + } +- if (rc < 0) { +- FC_DBG("failed to initialize proc intrerface\n"); +- rc = -ENODEV; +- goto out_chrdev; +- } + + /* + * setup link change notification +@@ -340,12 +322,6 @@ static int __init fcoe_init(void) + } + + return 0; +- +-out_chrdev: +-#ifdef CONFIG_HOTPLUG_CPU +- unregister_cpu_notifier(&fcoe_cpu_notifier); +-#endif /* CONFIG_HOTPLUG_CPU */ +- return rc; + } + module_init(fcoe_init); + +diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c +index 3cf5ad6..d7ceb1b 100644 +--- a/drivers/scsi/fcoe/fcoe_sw.c ++++ b/drivers/scsi/fcoe/fcoe_sw.c +@@ -46,13 +46,13 @@ + + #define FCOE_VERSION "0.1" + +-#define FCOE_MAX_LUN 255 +-#define FCOE_MAX_FCP_TARGET 256 ++#define FCOE_MAX_LUN 255 ++#define FCOE_MAX_FCP_TARGET 256 + +-#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 ++#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 + +-#define FCOE_MIN_XID 0x0004 +-#define FCOE_MAX_XID 0x07ef ++#define FCOE_MIN_XID 0x0004 ++#define FCOE_MAX_XID 0x07ef + + LIST_HEAD(fcoe_hostlist); + DEFINE_RWLOCK(fcoe_hostlist_lock); +@@ -173,7 +173,6 @@ static struct scsi_host_template fcoe_driver_template = { + int fcoe_destroy_interface(struct net_device *netdev) + { + int cpu, idx; +- struct fcoe_dev_stats *p; + struct fcoe_percpu_s *pp; + struct fcoe_softc *fc; + struct fcoe_rcv_info *fr; +@@ -239,13 +238,8 @@ int fcoe_destroy_interface(struct net_device *netdev) + fcoe_clean_pending_queue(lp); + + /* Free memory used by statistical counters */ +- for_each_online_cpu(cpu) { +- p = lp->dev_stats[cpu]; +- if (p) { +- lp->dev_stats[cpu] = NULL; +- kfree(p); +- } +- } ++ for_each_online_cpu(cpu) ++ kfree(lp->dev_stats[cpu]); + + /* Release the net_device and Scsi_Host */ + dev_put(fc->real_dev); +@@ -299,7 +293,6 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { + static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) + { + int i = 0; +- struct fcoe_dev_stats *p; + + lp->host = shost; + lp->drv_priv = (void *)(lp + 1); +@@ -319,11 +312,9 @@ static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) + /* + * allocate per cpu stats block + */ +- for_each_online_cpu(i) { +- p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); +- if (p) +- lp->dev_stats[i] = p; +- } ++ for_each_online_cpu(i) ++ lp->dev_stats[i] = kzalloc(sizeof(struct fcoe_dev_stats), ++ GFP_KERNEL); + + /* Finish fc_lport configuration */ + fc_lport_config(lp); +@@ -341,11 +332,8 @@ static int net_config(struct fc_lport *lp) + + /* Require support for get_pauseparam ethtool op. */ + net_dev = fc->real_dev; +- if (!net_dev->ethtool_ops && (net_dev->priv_flags & IFF_802_1Q_VLAN)) ++ if (net_dev->priv_flags & IFF_802_1Q_VLAN) + net_dev = vlan_dev_real_dev(net_dev); +- if (!net_dev->ethtool_ops || !net_dev->ethtool_ops->get_pauseparam) +- return -EOPNOTSUPP; +- + fc->phys_dev = net_dev; + + /* Do not support for bonding device */ +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +index 93c47aa..45a7d6f 100644 +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -135,7 +135,8 @@ err: + #else + stats = lp->dev_stats[0]; + #endif +- stats->ErrorFrames++; ++ if (stats) ++ stats->ErrorFrames++; + + err2: + kfree_skb(skb); +@@ -333,8 +334,10 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + hp->fcoe_sof = sof; + + stats = lp->dev_stats[smp_processor_id()]; +- stats->TxFrames++; +- stats->TxWords += wlen; ++ if (stats) { ++ stats->TxFrames++; ++ stats->TxWords += wlen; ++ } + skb->dev = fc->real_dev; + + fr_dev(fp) = lp; +@@ -422,10 +425,12 @@ int fcoe_percpu_receive_thread(void *arg) + + hp = (struct fcoe_hdr *)skb->data; + if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { +- if (stats->ErrorFrames < 5) +- FC_DBG("unknown FCoE version %x", +- FC_FCOE_DECAPS_VER(hp)); +- stats->ErrorFrames++; ++ if (stats) { ++ if (stats->ErrorFrames < 5) ++ FC_DBG("unknown FCoE version %x", ++ FC_FCOE_DECAPS_VER(hp)); ++ stats->ErrorFrames++; ++ } + kfree_skb(skb); + continue; + } +@@ -436,15 +441,20 @@ int fcoe_percpu_receive_thread(void *arg) + tlen = sizeof(struct fcoe_crc_eof); + + if (unlikely(fr_len > skb->len)) { +- if (stats->ErrorFrames < 5) +- FC_DBG("length error fr_len 0x%x skb->len 0x%x", +- fr_len, skb->len); +- stats->ErrorFrames++; ++ if (stats) { ++ if (stats->ErrorFrames < 5) ++ FC_DBG("length error fr_len 0x%x " ++ "skb->len 0x%x", fr_len, ++ skb->len); ++ stats->ErrorFrames++; ++ } + kfree_skb(skb); + continue; + } +- stats->RxFrames++; +- stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; ++ if (stats) { ++ stats->RxFrames++; ++ stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; ++ } + + fp = (struct fc_frame *) skb; + fc_frame_init(fp); +@@ -469,12 +479,15 @@ int fcoe_percpu_receive_thread(void *arg) + fcoe_recv_flogi(fc, fp, mac); + fc_exch_recv(lp, lp->emp, fp); + } else { +- if (debug_fcoe || stats->InvalidCRCCount < 5) { ++ if (debug_fcoe || ++ (stats && stats->InvalidCRCCount < 5)) { + printk(KERN_WARNING \ + "fcoe: dropping frame with CRC error"); + } +- stats->InvalidCRCCount++; +- stats->ErrorFrames++; ++ if (stats) { ++ stats->InvalidCRCCount++; ++ stats->ErrorFrames++; ++ } + fc_frame_free(fp); + } + } +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +index 80dc1ef..67c5bad 100644 +--- a/drivers/scsi/libfc/fc_exch.c ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -371,7 +371,7 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep, + FC_DEBUG_EXCH("Exchange (%4x) timed out, notifying the upper layer\n", + ep->xid); + if (schedule_delayed_work(&ep->timeout_work, +- jiffies + msecs_to_jiffies(timer_msec))) ++ msecs_to_jiffies(timer_msec))) + fc_exch_hold(ep); /* hold for timer */ + } + +@@ -1831,17 +1831,18 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, + len += sizeof(struct fc_exch_mgr); + + mp = kzalloc(len, GFP_ATOMIC); +- if (mp) { +- mp->class = class; +- mp->total_exches = 0; +- mp->exches = (struct fc_exch **)(mp + 1); +- mp->last_xid = min_xid - 1; +- mp->min_xid = min_xid; +- mp->max_xid = max_xid; +- mp->lp = lp; +- INIT_LIST_HEAD(&mp->ex_list); +- spin_lock_init(&mp->em_lock); +- } ++ if (!mp) ++ return NULL; ++ ++ mp->class = class; ++ mp->total_exches = 0; ++ mp->exches = (struct fc_exch **)(mp + 1); ++ mp->last_xid = min_xid - 1; ++ mp->min_xid = min_xid; ++ mp->max_xid = max_xid; ++ mp->lp = lp; ++ INIT_LIST_HEAD(&mp->ex_list); ++ spin_lock_init(&mp->em_lock); + + mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); + if (!mp->ep_pool) +@@ -1932,6 +1933,7 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + fh = fc_frame_header_get(fp); + hton24(fh->fh_f_ctl, f_ctl | fill); + fh->fh_seq_cnt = htons(sp->cnt++); ++ ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ + + if (unlikely(lp->tt.frame_send(lp, fp))) + goto err; +@@ -1940,7 +1942,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + fc_exch_timer_set_locked(ep, timer_msec); + sp->f_ctl = f_ctl; /* save for possible abort */ + ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ +- ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ + + if (f_ctl & FC_FC_SEQ_INIT) + ep->esb_stat &= ~ESB_ST_SEQ_INIT; +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +index bf8202f..01e84dc 100644 +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -41,6 +41,7 @@ + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("libfc"); + MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0.3"); + + static int fc_fcp_debug; + +@@ -53,80 +54,18 @@ static int fc_fcp_debug; + static struct kmem_cache *scsi_pkt_cachep; + + /* SRB state definitions */ +-#define FC_SRB_FREE 0 /* cmd is free */ +-#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */ +-#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */ +-#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */ +-#define FC_SRB_ABORTED (1 << 3) /* abort acknowleged */ +-#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */ +-#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */ ++#define FC_SRB_FREE 0 /* cmd is free */ ++#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */ ++#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */ ++#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */ ++#define FC_SRB_ABORTED (1 << 3) /* abort acknowleged */ ++#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */ ++#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */ + #define FC_SRB_FCP_PROCESSING_TMO (1 << 6) /* timer function processing */ +-#define FC_SRB_NOMEM (1 << 7) /* dropped to out of mem */ ++#define FC_SRB_NOMEM (1 << 7) /* dropped to out of mem */ + +-#define FC_SRB_READ (1 << 1) +-#define FC_SRB_WRITE (1 << 0) +- +-/* +- * scsi request structure, one for each scsi request +- */ +-struct fc_fcp_pkt { +- /* +- * housekeeping stuff +- */ +- struct fc_lport *lp; /* handle to hba struct */ +- u16 state; /* scsi_pkt state state */ +- u16 tgt_flags; /* target flags */ +- atomic_t ref_cnt; /* only used byr REC ELS */ +- spinlock_t scsi_pkt_lock; /* Must be taken before the host lock +- * if both are held at the same time */ +- /* +- * SCSI I/O related stuff +- */ +- struct scsi_cmnd *cmd; /* scsi command pointer. set/clear +- * under host lock */ +- struct list_head list; /* tracks queued commands. access under +- * host lock */ +- /* +- * timeout related stuff +- */ +- struct timer_list timer; /* command timer */ +- struct completion tm_done; +- int wait_for_comp; +- unsigned long start_time; /* start jiffie */ +- unsigned long end_time; /* end jiffie */ +- unsigned long last_pkt_time; /* jiffies of last frame received */ +- +- /* +- * scsi cmd and data transfer information +- */ +- u32 data_len; +- /* +- * transport related veriables +- */ +- struct fcp_cmnd cdb_cmd; +- size_t xfer_len; +- u32 xfer_contig_end; /* offset of end of contiguous xfer */ +- u16 max_payload; /* max payload size in bytes */ +- +- /* +- * scsi/fcp return status +- */ +- u32 io_status; /* SCSI result upper 24 bits */ +- u8 cdb_status; +- u8 status_code; /* FCP I/O status */ +- /* bit 3 Underrun bit 2: overrun */ +- u8 scsi_comp_flags; +- u32 req_flags; /* bit 0: read bit:1 write */ +- u32 scsi_resid; /* residule length */ +- +- struct fc_rport *rport; /* remote port pointer */ +- struct fc_seq *seq_ptr; /* current sequence pointer */ +- /* +- * Error Processing +- */ +- u8 recov_retry; /* count of recovery retries */ +- struct fc_seq *recov_seq; /* sequence for REC or SRR */ +-}; ++#define FC_SRB_READ (1 << 1) ++#define FC_SRB_WRITE (1 << 0) + + /* + * The SCp.ptr should be tested and set under the host lock. NULL indicates +@@ -153,11 +92,10 @@ struct fc_fcp_internal { + static void fc_fcp_recv_data(struct fc_fcp_pkt *, struct fc_frame *); + static void fc_fcp_recv(struct fc_seq *, struct fc_frame *, void *); + static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *); +-static void fc_fcp_complete(struct fc_fcp_pkt *); ++static void fc_fcp_complete_locked(struct fc_fcp_pkt *); + static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *); + static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp); + static void fc_timeout_error(struct fc_fcp_pkt *); +-static int fc_fcp_send_cmd(struct fc_fcp_pkt *); + static void fc_fcp_timeout(unsigned long data); + static void fc_fcp_rec(struct fc_fcp_pkt *); + static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); +@@ -171,17 +109,17 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); + /* + * command status codes + */ +-#define FC_COMPLETE 0 +-#define FC_CMD_ABORTED 1 +-#define FC_CMD_RESET 2 +-#define FC_CMD_PLOGO 3 +-#define FC_SNS_RCV 4 +-#define FC_TRANS_ERR 5 +-#define FC_DATA_OVRRUN 6 +-#define FC_DATA_UNDRUN 7 +-#define FC_ERROR 8 +-#define FC_HRD_ERROR 9 +-#define FC_CMD_TIME_OUT 10 ++#define FC_COMPLETE 0 ++#define FC_CMD_ABORTED 1 ++#define FC_CMD_RESET 2 ++#define FC_CMD_PLOGO 3 ++#define FC_SNS_RCV 4 ++#define FC_TRANS_ERR 5 ++#define FC_DATA_OVRRUN 6 ++#define FC_DATA_UNDRUN 7 ++#define FC_ERROR 8 ++#define FC_HRD_ERROR 9 ++#define FC_CMD_TIME_OUT 10 + + /* + * Error recovery timeout values. +@@ -191,8 +129,8 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); + #define FC_SCSI_REC_TOV (2 * HZ) + #define FC_HOST_RESET_TIMEOUT (30 * HZ) + +-#define FC_MAX_ERROR_CNT 5 +-#define FC_MAX_RECOV_RETRY 3 ++#define FC_MAX_ERROR_CNT 5 ++#define FC_MAX_RECOV_RETRY 3 + + #define FC_FCP_DFLT_QUEUE_DEPTH 32 + +@@ -208,46 +146,46 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); + static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lp, gfp_t gfp) + { + struct fc_fcp_internal *si = fc_get_scsi_internal(lp); +- struct fc_fcp_pkt *sp; +- +- sp = mempool_alloc(si->scsi_pkt_pool, gfp); +- if (sp) { +- memset(sp, 0, sizeof(*sp)); +- sp->lp = lp; +- atomic_set(&sp->ref_cnt, 1); +- init_timer(&sp->timer); +- INIT_LIST_HEAD(&sp->list); +- spin_lock_init(&sp->scsi_pkt_lock); ++ struct fc_fcp_pkt *fsp; ++ ++ fsp = mempool_alloc(si->scsi_pkt_pool, gfp); ++ if (fsp) { ++ memset(fsp, 0, sizeof(*fsp)); ++ fsp->lp = lp; ++ atomic_set(&fsp->ref_cnt, 1); ++ init_timer(&fsp->timer); ++ INIT_LIST_HEAD(&fsp->list); ++ spin_lock_init(&fsp->scsi_pkt_lock); + } +- return sp; ++ return fsp; + } + + /** + * fc_fcp_pkt_release - release hold on scsi_pkt packet +- * @sp: fcp packet struct ++ * @fsp: fcp packet struct + * + * This is used by upper layer scsi driver. + * Context : call from process and interrupt context. + * no locking required + */ +-static void fc_fcp_pkt_release(struct fc_fcp_pkt *sp) ++static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp) + { +- if (atomic_dec_and_test(&sp->ref_cnt)) { +- struct fc_fcp_internal *si = fc_get_scsi_internal(sp->lp); ++ if (atomic_dec_and_test(&fsp->ref_cnt)) { ++ struct fc_fcp_internal *si = fc_get_scsi_internal(fsp->lp); + +- mempool_free(sp, si->scsi_pkt_pool); ++ mempool_free(fsp, si->scsi_pkt_pool); + } + } + +-static void fc_fcp_pkt_hold(struct fc_fcp_pkt *sp) ++static void fc_fcp_pkt_hold(struct fc_fcp_pkt *fsp) + { +- atomic_inc(&sp->ref_cnt); ++ atomic_inc(&fsp->ref_cnt); + } + + /** + * fc_fcp_pkt_destory - release hold on scsi_pkt packet + * +- * @sp: exchange sequence ++ * @seq: exchange sequence + * @fsp: fcp packet struct + * + * Release hold on scsi_pkt packet set to keep scsi_pkt +@@ -255,9 +193,9 @@ static void fc_fcp_pkt_hold(struct fc_fcp_pkt *sp) + * Context : called from from EM layer. + * no locking required + */ +-static void fc_fcp_pkt_destroy(struct fc_seq *sp, void *arg) ++static void fc_fcp_pkt_destroy(struct fc_seq *seq, void *fsp) + { +- fc_fcp_pkt_release(arg); ++ fc_fcp_pkt_release(fsp); + } + + /** +@@ -280,10 +218,9 @@ static void fc_fcp_pkt_destroy(struct fc_seq *sp, void *arg) + static inline int fc_fcp_lock_pkt(struct fc_fcp_pkt *fsp) + { + spin_lock_bh(&fsp->scsi_pkt_lock); +- if (!fsp->cmd) { ++ if (fsp->state & FC_SRB_COMPL) { + spin_unlock_bh(&fsp->scsi_pkt_lock); +- FC_DBG("Invalid scsi cmd pointer on fcp packet.\n"); +- return -EINVAL; ++ return -EPERM; + } + + fc_fcp_pkt_hold(fsp); +@@ -325,7 +262,7 @@ static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp) + fsp->state &= ~FC_SRB_ABORT_PENDING; + fsp->io_status = SUGGEST_RETRY << 24; + fsp->status_code = FC_ERROR; +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + } + + /* +@@ -336,7 +273,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + { + struct scsi_cmnd *sc = fsp->cmd; + struct fc_lport *lp = fsp->lp; +- struct fcoe_dev_stats *sp; ++ struct fcoe_dev_stats *stats; + struct fc_frame_header *fh; + size_t start_offset; + size_t offset; +@@ -420,9 +357,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + + if (~crc != le32_to_cpu(*(__le32 *)(buf + len))) { + crc_err: +- sp = lp->dev_stats[smp_processor_id()]; +- sp->ErrorFrames++; +- if (sp->InvalidCRCCount++ < 5) ++ stats = lp->dev_stats[smp_processor_id()]; ++ stats->ErrorFrames++; ++ if (stats->InvalidCRCCount++ < 5) + FC_DBG("CRC error on data frame\n"); + /* + * Assume the frame is total garbage. +@@ -447,7 +384,7 @@ crc_err: + */ + if (unlikely(fsp->state & FC_SRB_RCV_STATUS) && + fsp->xfer_len == fsp->data_len - fsp->scsi_resid) +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + } + + /* +@@ -457,7 +394,7 @@ crc_err: + * size of data in single frame, otherwise send multiple FC + * frames of max FC frame payload supported by target port. + */ +-static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, ++static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, + size_t offset, size_t seq_blen) + { + struct scsi_cmnd *sc; +@@ -503,9 +440,9 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, + remaining = seq_blen; + frame_offset = offset; + tlen = 0; +- sp = lp->tt.seq_start_next(sp); ++ seq = lp->tt.seq_start_next(seq); + f_ctl = FC_FC_REL_OFF; +- WARN_ON(!sp); ++ WARN_ON(!seq); + + /* + * If a get_page()/put_page() will fail, don't use sg lists +@@ -608,12 +545,12 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, + * transfer sequence initiative. + */ + f_ctl |= FC_FC_SEQ_INIT | FC_FC_END_SEQ; +- error = lp->tt.seq_send(lp, sp, fp, f_ctl); ++ error = lp->tt.seq_send(lp, seq, fp, f_ctl); + } else if (tlen == 0) { + /* + * send fragment using for a sequence. + */ +- error = lp->tt.seq_send(lp, sp, fp, f_ctl); ++ error = lp->tt.seq_send(lp, seq, fp, f_ctl); + } else { + continue; + } +@@ -660,7 +597,7 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + if (fsp->wait_for_comp) + complete(&fsp->tm_done); + else +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + } + } + +@@ -704,7 +641,7 @@ done: + * Context : called from Soft IRQ context + * can not called holding list lock + */ +-static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) + { + struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; + struct fc_lport *lp; +@@ -743,11 +680,11 @@ static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) + dd = fc_frame_payload_get(fp, sizeof(*dd)); + WARN_ON(!dd); + +- rc = fc_fcp_send_data(fsp, sp, ++ rc = fc_fcp_send_data(fsp, seq, + (size_t) ntohl(dd->ft_data_ro), + (size_t) ntohl(dd->ft_burst_len)); + if (!rc) +- lp->tt.seq_set_rec_data(sp, fsp->xfer_len); ++ lp->tt.seq_set_rec_data(seq, fsp->xfer_len); + else if (rc == -ENOMEM) + fsp->state |= FC_SRB_NOMEM; + } else if (r_ctl == FC_RCTL_DD_SOL_DATA) { +@@ -757,7 +694,7 @@ static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) + */ + WARN_ON(fr_len(fp) < sizeof(*fh)); /* len may be 0 */ + fc_fcp_recv_data(fsp, fp); +- lp->tt.seq_set_rec_data(sp, fsp->xfer_contig_end); ++ lp->tt.seq_set_rec_data(seq, fsp->xfer_contig_end); + } else if (r_ctl == FC_RCTL_DD_CMD_STATUS) { + WARN_ON(fr_flags(fp) & FCPHF_CRC_UNCHECKED); + +@@ -874,7 +811,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + fsp->rport->port_id, + fsp->xfer_len, expected_len, fsp->data_len); + } +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + return; + + len_err: +@@ -882,20 +819,20 @@ len_err: + flags, fr_len(fp), respl, snsl); + err: + fsp->status_code = FC_ERROR; +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + } + + /** +- * fc_fcp_complete - complete processing of a fcp packet ++ * fc_fcp_complete_locked - complete processing of a fcp packet + * @fsp: fcp packet + * + * This function may sleep if a timer is pending. The packet lock must be + * held, and the host lock must not be held. + */ +-static void fc_fcp_complete(struct fc_fcp_pkt *fsp) ++static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp) + { + struct fc_lport *lp = fsp->lp; +- struct fc_seq *sp; ++ struct fc_seq *seq; + u32 f_ctl; + + if (fsp->state & FC_SRB_ABORT_PENDING) +@@ -917,14 +854,14 @@ static void fc_fcp_complete(struct fc_fcp_pkt *fsp) + } + } + +- sp = fsp->seq_ptr; +- if (sp) { ++ seq = fsp->seq_ptr; ++ if (seq) { + fsp->seq_ptr = NULL; + if (unlikely(fsp->scsi_comp_flags & FCP_CONF_REQ)) { + struct fc_frame *conf_frame; + struct fc_seq *csp; + +- csp = lp->tt.seq_start_next(sp); ++ csp = lp->tt.seq_start_next(seq); + conf_frame = fc_frame_alloc(fsp->lp, 0); + if (conf_frame) { + fc_frame_setup(conf_frame, +@@ -934,7 +871,7 @@ static void fc_fcp_complete(struct fc_fcp_pkt *fsp) + lp->tt.seq_send(lp, csp, conf_frame, f_ctl); + } + } +- lp->tt.exch_done(sp); ++ lp->tt.exch_done(seq); + } + fc_io_compl(fsp); + } +@@ -1028,7 +965,7 @@ static int fc_fcp_pkt_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp) + list_add_tail(&fsp->list, &si->scsi_pkt_queue); + + spin_unlock_irq(lp->host->host_lock); +- rc = fc_fcp_send_cmd(fsp); ++ rc = lp->tt.fcp_cmd_send(lp, fsp, fc_fcp_recv); + spin_lock_irq(lp->host->host_lock); + if (rc) + list_del(&fsp->list); +@@ -1036,49 +973,47 @@ static int fc_fcp_pkt_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp) + return rc; + } + +-static int fc_fcp_send_cmd(struct fc_fcp_pkt *fsp) ++static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp, ++ void (*resp)(struct fc_seq *, ++ struct fc_frame *fp, ++ void *arg)) + { +- struct fc_lport *lp; + struct fc_frame *fp; +- struct fc_seq *sp; ++ struct fc_seq *seq; + struct fc_rport *rport; + struct fc_rport_libfc_priv *rp; ++ const size_t len = sizeof(fsp->cdb_cmd); + int rc = 0; + + if (fc_fcp_lock_pkt(fsp)) + return 0; + +- if (fsp->state & FC_SRB_COMPL) +- goto unlock; +- +- lp = fsp->lp; + fp = fc_frame_alloc(lp, sizeof(fsp->cdb_cmd)); + if (!fp) { + rc = -1; + goto unlock; + } + +- memcpy(fc_frame_payload_get(fp, sizeof(fsp->cdb_cmd)), +- &fsp->cdb_cmd, sizeof(fsp->cdb_cmd)); ++ memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); + fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CMD, FC_TYPE_FCP); + fc_frame_set_offset(fp, 0); + rport = fsp->rport; + fsp->max_payload = rport->maxframe_size; + rp = rport->dd_data; +- sp = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_recv, +- fc_fcp_pkt_destroy, +- fsp, 0, +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +- if (!sp) { ++ seq = lp->tt.exch_seq_send(lp, fp, ++ resp, ++ fc_fcp_pkt_destroy, ++ fsp, 0, ++ fc_host_port_id(rp->local_port->host), ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ if (!seq) { + fc_frame_free(fp); + rc = -1; + goto unlock; + } + fsp->last_pkt_time = jiffies; +- fsp->seq_ptr = sp; ++ fsp->seq_ptr = seq; + fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ + + setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); +@@ -1113,7 +1048,7 @@ static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) + */ + fsp->state &= ~FC_SRB_ABORT_PENDING; + fsp->status_code = FC_CMD_PLOGO; +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + unlock: + fc_fcp_unlock_pkt(fsp); + } +@@ -1143,7 +1078,7 @@ static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp) + } else if (fsp->state & FC_SRB_ABORTED) { + FC_DBG("target abort cmd passed\n"); + rc = SUCCESS; +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + } + + return rc; +@@ -1155,47 +1090,16 @@ static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp) + static void fc_lun_reset_send(unsigned long data) + { + struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; +- const size_t len = sizeof(fsp->cdb_cmd); + struct fc_lport *lp = fsp->lp; +- struct fc_frame *fp; +- struct fc_seq *sp; +- struct fc_rport *rport; +- struct fc_rport_libfc_priv *rp; +- +- spin_lock_bh(&fsp->scsi_pkt_lock); +- if (fsp->state & FC_SRB_COMPL) +- goto unlock; +- +- fp = fc_frame_alloc(lp, len); +- if (!fp) +- goto retry; +- memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CMD, FC_TYPE_FCP); +- fc_frame_set_offset(fp, 0); +- rport = fsp->rport; +- rp = rport->dd_data; +- sp = lp->tt.exch_seq_send(lp, fp, +- fc_tm_done, +- fc_fcp_pkt_destroy, +- fsp, 0, +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +- +- if (sp) { +- fsp->seq_ptr = sp; +- fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ +- goto unlock; ++ if (lp->tt.fcp_cmd_send(lp, fsp, fc_tm_done)) { ++ if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY) ++ return; ++ if (fc_fcp_lock_pkt(fsp)) ++ return; ++ setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp); ++ fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); ++ fc_fcp_unlock_pkt(fsp); + } +- /* +- * Exchange or frame allocation failed. Set timer and retry. +- */ +- fc_frame_free(fp); +-retry: +- setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp); +- fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); +-unlock: +- spin_unlock_bh(&fsp->scsi_pkt_lock); + } + + /* +@@ -1253,12 +1157,11 @@ static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp, + /* + * Task Managment response handler + */ +-static void fc_tm_done(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg) + { + struct fc_fcp_pkt *fsp = arg; + struct fc_frame_header *fh; + +- spin_lock_bh(&fsp->scsi_pkt_lock); + if (IS_ERR(fp)) { + /* + * If there is an error just let it timeout or wait +@@ -1266,15 +1169,16 @@ static void fc_tm_done(struct fc_seq *sp, struct fc_frame *fp, void *arg) + * + * scsi-eh will escalate for when either happens. + */ +- spin_unlock_bh(&fsp->scsi_pkt_lock); + return; + } + ++ if (fc_fcp_lock_pkt(fsp)) ++ return; ++ + /* + * raced with eh timeout handler. + */ +- if ((fsp->state & FC_SRB_COMPL) || !fsp->seq_ptr || +- !fsp->wait_for_comp) { ++ if (!fsp->seq_ptr || !fsp->wait_for_comp) { + spin_unlock_bh(&fsp->scsi_pkt_lock); + return; + } +@@ -1283,9 +1187,9 @@ static void fc_tm_done(struct fc_seq *sp, struct fc_frame *fp, void *arg) + if (fh->fh_type != FC_TYPE_BLS) + fc_fcp_resp(fsp, fp); + fsp->seq_ptr = NULL; +- fsp->lp->tt.exch_done(sp); ++ fsp->lp->tt.exch_done(seq); + fc_frame_free(fp); +- spin_unlock_bh(&fsp->scsi_pkt_lock); ++ fc_fcp_unlock_pkt(fsp); + } + + static void fc_fcp_cleanup(struct fc_lport *lp) +@@ -1320,8 +1224,9 @@ static void fc_fcp_timeout(unsigned long data) + if (fc_fcp_lock_pkt(fsp)) + return; + +- if (fsp->state & FC_SRB_COMPL) ++ if (fsp->cdb_cmd.fc_tm_flags) + goto unlock; ++ + fsp->state |= FC_SRB_FCP_PROCESSING_TMO; + + if (rp->flags & FC_RP_FLAGS_REC_SUPPORTED) +@@ -1330,7 +1235,7 @@ static void fc_fcp_timeout(unsigned long data) + jiffies)) + fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT); + else if (fsp->state & FC_SRB_RCV_STATUS) +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + else + fc_timeout_error(fsp); + fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; +@@ -1344,7 +1249,7 @@ unlock: + static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + { + struct fc_lport *lp; +- struct fc_seq *sp; ++ struct fc_seq *seq; + struct fc_frame *fp; + struct fc_els_rec *rec; + struct fc_rport *rport; +@@ -1355,14 +1260,14 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + lp = fsp->lp; + rport = fsp->rport; + rp = rport->dd_data; +- sp = fsp->seq_ptr; +- if (!sp || rp->rp_state != RPORT_ST_READY) { ++ seq = fsp->seq_ptr; ++ if (!seq || rp->rp_state != RPORT_ST_READY) { + fsp->status_code = FC_HRD_ERROR; + fsp->io_status = SUGGEST_RETRY << 24; +- fc_fcp_complete(fsp); ++ fc_fcp_complete_locked(fsp); + return; + } +- lp->tt.seq_get_xids(sp, &ox_id, &rx_id); ++ lp->tt.seq_get_xids(seq, &ox_id, &rx_id); + fp = fc_frame_alloc(lp, sizeof(*rec)); + if (!fp) + goto retry; +@@ -1376,14 +1281,14 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + + fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + fc_frame_set_offset(fp, 0); +- sp = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_rec_resp, NULL, +- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +- +- if (sp) { ++ seq = lp->tt.exch_seq_send(lp, fp, ++ fc_fcp_rec_resp, NULL, ++ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), ++ fc_host_port_id(rp->local_port->host), ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ ++ if (seq) { + fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ + return; + } else +@@ -1402,7 +1307,7 @@ retry: + * then set the timeout and return otherwise complete the exchange + * and tell the scsi layer to restart the I/O. + */ +-static void fc_fcp_rec_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) + { + struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; + struct fc_els_rec_acc *recp; +@@ -1605,7 +1510,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) + struct fc_lport *lp = fsp->lp; + struct fc_rport *rport; + struct fc_rport_libfc_priv *rp; +- struct fc_seq *sp; ++ struct fc_seq *seq; + struct fcp_srr *srr; + struct fc_frame *fp; + u8 cdb_op; +@@ -1633,17 +1538,17 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) + + fc_frame_setup(fp, FC_RCTL_ELS4_REQ, FC_TYPE_FCP); + fc_frame_set_offset(fp, 0); +- sp = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_srr_resp, NULL, +- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +- if (!sp) { ++ seq = lp->tt.exch_seq_send(lp, fp, ++ fc_fcp_srr_resp, NULL, ++ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), ++ fc_host_port_id(rp->local_port->host), ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ if (!seq) { + fc_frame_free(fp); + goto retry; + } +- fsp->recov_seq = sp; ++ fsp->recov_seq = seq; + fsp->xfer_len = offset; + fsp->xfer_contig_end = offset; + fsp->state &= ~FC_SRB_RCV_STATUS; +@@ -1656,7 +1561,7 @@ retry: + /* + * Handle response from SRR. + */ +-static void fc_fcp_srr_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) + { + struct fc_fcp_pkt *fsp = arg; + struct fc_frame_header *fh; +@@ -1698,7 +1603,7 @@ static void fc_fcp_srr_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) + break; + } + fc_fcp_unlock_pkt(fsp); +- fsp->lp->tt.exch_done(sp); ++ fsp->lp->tt.exch_done(seq); + out: + fc_frame_free(fp); + fc_fcp_pkt_release(fsp); /* drop hold for outstanding SRR */ +@@ -1746,7 +1651,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) + { + struct fc_lport *lp; + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); +- struct fc_fcp_pkt *sp; ++ struct fc_fcp_pkt *fsp; + struct fc_rport_libfc_priv *rp; + int rval; + int rc = 0; +@@ -1778,8 +1683,8 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) + goto out; + } + +- sp = fc_fcp_pkt_alloc(lp, GFP_ATOMIC); +- if (sp == NULL) { ++ fsp = fc_fcp_pkt_alloc(lp, GFP_ATOMIC); ++ if (fsp == NULL) { + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } +@@ -1787,48 +1692,48 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) + /* + * build the libfc request pkt + */ +- sp->cmd = sc_cmd; /* save the cmd */ +- sp->lp = lp; /* save the softc ptr */ +- sp->rport = rport; /* set the remote port ptr */ ++ fsp->cmd = sc_cmd; /* save the cmd */ ++ fsp->lp = lp; /* save the softc ptr */ ++ fsp->rport = rport; /* set the remote port ptr */ + sc_cmd->scsi_done = done; + + /* + * set up the transfer length + */ +- sp->data_len = scsi_bufflen(sc_cmd); +- sp->xfer_len = 0; ++ fsp->data_len = scsi_bufflen(sc_cmd); ++ fsp->xfer_len = 0; + + /* + * setup the data direction + */ + stats = lp->dev_stats[smp_processor_id()]; + if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { +- sp->req_flags = FC_SRB_READ; ++ fsp->req_flags = FC_SRB_READ; + stats->InputRequests++; +- stats->InputMegabytes = sp->data_len; ++ stats->InputMegabytes = fsp->data_len; + } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { +- sp->req_flags = FC_SRB_WRITE; ++ fsp->req_flags = FC_SRB_WRITE; + stats->OutputRequests++; +- stats->OutputMegabytes = sp->data_len; ++ stats->OutputMegabytes = fsp->data_len; + } else { +- sp->req_flags = 0; ++ fsp->req_flags = 0; + stats->ControlRequests++; + } + +- sp->tgt_flags = rp->flags; ++ fsp->tgt_flags = rp->flags; + +- init_timer(&sp->timer); +- sp->timer.data = (unsigned long)sp; ++ init_timer(&fsp->timer); ++ fsp->timer.data = (unsigned long)fsp; + + /* + * send it to the lower layer + * if we get -1 return then put the request in the pending + * queue. + */ +- rval = fc_fcp_pkt_send(lp, sp); ++ rval = fc_fcp_pkt_send(lp, fsp); + if (rval != 0) { +- sp->state = FC_SRB_FREE; +- fc_fcp_pkt_release(sp); ++ fsp->state = FC_SRB_FREE; ++ fc_fcp_pkt_release(fsp); + rc = SCSI_MLQUEUE_HOST_BUSY; + } + out: +@@ -1838,30 +1743,30 @@ EXPORT_SYMBOL(fc_queuecommand); + + /** + * fc_io_compl - Handle responses for completed commands +- * @sp: scsi packet ++ * @fsp: scsi packet + * + * Translates a error to a Linux SCSI error. + * + * The fcp packet lock must be held when calling. + */ +-static void fc_io_compl(struct fc_fcp_pkt *sp) ++static void fc_io_compl(struct fc_fcp_pkt *fsp) + { + struct fc_fcp_internal *si; + struct scsi_cmnd *sc_cmd; + struct fc_lport *lp; + unsigned long flags; + +- sp->state |= FC_SRB_COMPL; +- if (!(sp->state & FC_SRB_FCP_PROCESSING_TMO)) { +- spin_unlock_bh(&sp->scsi_pkt_lock); +- del_timer_sync(&sp->timer); +- spin_lock_bh(&sp->scsi_pkt_lock); ++ fsp->state |= FC_SRB_COMPL; ++ if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) { ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ del_timer_sync(&fsp->timer); ++ spin_lock_bh(&fsp->scsi_pkt_lock); + } + +- lp = sp->lp; ++ lp = fsp->lp; + si = fc_get_scsi_internal(lp); + spin_lock_irqsave(lp->host->host_lock, flags); +- if (!sp->cmd) { ++ if (!fsp->cmd) { + spin_unlock_irqrestore(lp->host->host_lock, flags); + return; + } +@@ -1872,28 +1777,28 @@ static void fc_io_compl(struct fc_fcp_pkt *sp) + * try again so clear the throttled flag incase we get more + * time outs. + */ +- if (si->throttled && sp->state & FC_SRB_NOMEM) ++ if (si->throttled && fsp->state & FC_SRB_NOMEM) + si->throttled = 0; + +- sc_cmd = sp->cmd; +- sp->cmd = NULL; ++ sc_cmd = fsp->cmd; ++ fsp->cmd = NULL; + + if (!sc_cmd->SCp.ptr) { + spin_unlock_irqrestore(lp->host->host_lock, flags); + return; + } + +- CMD_SCSI_STATUS(sc_cmd) = sp->cdb_status; +- switch (sp->status_code) { ++ CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status; ++ switch (fsp->status_code) { + case FC_COMPLETE: +- if (sp->cdb_status == 0) { ++ if (fsp->cdb_status == 0) { + /* + * good I/O status + */ + sc_cmd->result = DID_OK << 16; +- if (sp->scsi_resid) +- CMD_RESID_LEN(sc_cmd) = sp->scsi_resid; +- } else if (sp->cdb_status == QUEUE_FULL) { ++ if (fsp->scsi_resid) ++ CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid; ++ } else if (fsp->cdb_status == QUEUE_FULL) { + struct scsi_device *tmp_sdev; + struct scsi_device *sdev = sc_cmd->device; + +@@ -1907,47 +1812,44 @@ static void fc_io_compl(struct fc_fcp_pkt *sp) + queue_depth - 1); + } + } +- sc_cmd->result = (DID_OK << 16) | sp->cdb_status; ++ sc_cmd->result = (DID_OK << 16) | fsp->cdb_status; + } else { + /* + * transport level I/O was ok but scsi + * has non zero status + */ +- sc_cmd->result = (DID_OK << 16) | sp->cdb_status; ++ sc_cmd->result = (DID_OK << 16) | fsp->cdb_status; + } + break; + case FC_ERROR: +- if (sp->io_status & (SUGGEST_RETRY << 24)) +- sc_cmd->result = DID_IMM_RETRY << 16; +- else +- sc_cmd->result = (DID_ERROR << 16) | sp->io_status; ++ sc_cmd->result = DID_ERROR << 16; + break; + case FC_DATA_UNDRUN: +- if (sp->cdb_status == 0) { ++ if (fsp->cdb_status == 0) { + /* + * scsi status is good but transport level + * underrun. for read it should be an error?? + */ +- sc_cmd->result = (DID_OK << 16) | sp->cdb_status; ++ sc_cmd->result = (DID_OK << 16) | fsp->cdb_status; + } else { + /* + * scsi got underrun, this is an error + */ +- CMD_RESID_LEN(sc_cmd) = sp->scsi_resid; +- sc_cmd->result = (DID_ERROR << 16) | sp->cdb_status; ++ CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid; ++ sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status; + } + break; + case FC_DATA_OVRRUN: + /* + * overrun is an error + */ +- sc_cmd->result = (DID_ERROR << 16) | sp->cdb_status; ++ sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status; + break; + case FC_CMD_ABORTED: +- sc_cmd->result = (DID_ABORT << 16) | sp->io_status; ++ sc_cmd->result = (DID_ABORT << 16) | fsp->io_status; + break; + case FC_CMD_TIME_OUT: +- sc_cmd->result = (DID_BUS_BUSY << 16) | sp->io_status; ++ sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; + break; + case FC_CMD_RESET: + sc_cmd->result = (DID_RESET << 16); +@@ -1960,16 +1862,33 @@ static void fc_io_compl(struct fc_fcp_pkt *sp) + break; + } + +- list_del(&sp->list); ++ list_del(&fsp->list); + sc_cmd->SCp.ptr = NULL; + sc_cmd->scsi_done(sc_cmd); + spin_unlock_irqrestore(lp->host->host_lock, flags); + + /* release ref from initial allocation in queue command */ +- fc_fcp_pkt_release(sp); ++ fc_fcp_pkt_release(fsp); + } + + /** ++ * fc_fcp_complete - complete processing of a fcp packet ++ * @fsp: fcp packet ++ * ++ * This function may sleep if a fsp timer is pending. ++ * The host lock must not be held by caller. ++ */ ++void fc_fcp_complete(struct fc_fcp_pkt *fsp) ++{ ++ if (fc_fcp_lock_pkt(fsp)) ++ return; ++ ++ fc_fcp_complete_locked(fsp); ++ fc_fcp_unlock_pkt(fsp); ++} ++EXPORT_SYMBOL(fc_fcp_complete); ++ ++/** + * fc_eh_abort - Abort a command...from scsi host template + * @sc_cmd: scsi command to abort + * +@@ -1978,7 +1897,7 @@ static void fc_io_compl(struct fc_fcp_pkt *sp) + */ + int fc_eh_abort(struct scsi_cmnd *sc_cmd) + { +- struct fc_fcp_pkt *sp; ++ struct fc_fcp_pkt *fsp; + struct fc_lport *lp; + int rc = FAILED; + unsigned long flags; +@@ -1990,27 +1909,27 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd) + return rc; + + spin_lock_irqsave(lp->host->host_lock, flags); +- sp = CMD_SP(sc_cmd); +- if (!sp) { ++ fsp = CMD_SP(sc_cmd); ++ if (!fsp) { + /* command completed while scsi eh was setting up */ + spin_unlock_irqrestore(lp->host->host_lock, flags); + return SUCCESS; + } +- /* grab a ref so the sp and sc_cmd cannot be relased from under us */ +- fc_fcp_pkt_hold(sp); ++ /* grab a ref so the fsp and sc_cmd cannot be relased from under us */ ++ fc_fcp_pkt_hold(fsp); + spin_unlock_irqrestore(lp->host->host_lock, flags); + +- if (fc_fcp_lock_pkt(sp)) { ++ if (fc_fcp_lock_pkt(fsp)) { + /* completed while we were waiting for timer to be deleted */ + rc = SUCCESS; + goto release_pkt; + } + +- rc = fc_fcp_pkt_abort(lp, sp); +- fc_fcp_unlock_pkt(sp); ++ rc = fc_fcp_pkt_abort(lp, fsp); ++ fc_fcp_unlock_pkt(fsp); + + release_pkt: +- fc_fcp_pkt_release(sp); ++ fc_fcp_pkt_release(fsp); + return rc; + } + EXPORT_SYMBOL(fc_eh_abort); +@@ -2025,7 +1944,7 @@ EXPORT_SYMBOL(fc_eh_abort); + int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) + { + struct fc_lport *lp; +- struct fc_fcp_pkt *sp; ++ struct fc_fcp_pkt *fsp; + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); + int rc = FAILED; + struct fc_rport_libfc_priv *rp; +@@ -2041,8 +1960,8 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) + if (lp->state != LPORT_ST_READY) + return rc; + +- sp = fc_fcp_pkt_alloc(lp, GFP_NOIO); +- if (sp == NULL) { ++ fsp = fc_fcp_pkt_alloc(lp, GFP_NOIO); ++ if (fsp == NULL) { + FC_DBG("could not allocate scsi_pkt\n"); + sc_cmd->result = DID_NO_CONNECT << 16; + goto out; +@@ -2053,15 +1972,15 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) + * the sc passed in is not setup for execution like when sent + * through the queuecommand callout. + */ +- sp->lp = lp; /* save the softc ptr */ +- sp->rport = rport; /* set the remote port ptr */ ++ fsp->lp = lp; /* save the softc ptr */ ++ fsp->rport = rport; /* set the remote port ptr */ + + /* + * flush outstanding commands + */ +- rc = fc_lun_reset(lp, sp, scmd_id(sc_cmd), sc_cmd->device->lun); +- sp->state = FC_SRB_FREE; +- fc_fcp_pkt_release(sp); ++ rc = fc_lun_reset(lp, fsp, scmd_id(sc_cmd), sc_cmd->device->lun); ++ fsp->state = FC_SRB_FREE; ++ fc_fcp_pkt_release(fsp); + + out: + return rc; +@@ -2160,11 +2079,14 @@ int fc_fcp_init(struct fc_lport *lp) + int rc; + struct fc_fcp_internal *si; + +- if (!lp->tt.scsi_cleanup) +- lp->tt.scsi_cleanup = fc_fcp_cleanup; ++ if (!lp->tt.fcp_cmd_send) ++ lp->tt.fcp_cmd_send = fc_fcp_cmd_send; ++ ++ if (!lp->tt.fcp_cleanup) ++ lp->tt.fcp_cleanup = fc_fcp_cleanup; + +- if (!lp->tt.scsi_abort_io) +- lp->tt.scsi_abort_io = fc_fcp_abort_io; ++ if (!lp->tt.fcp_abort_io) ++ lp->tt.fcp_abort_io = fc_fcp_abort_io; + + si = kzalloc(sizeof(struct fc_fcp_internal), GFP_KERNEL); + if (!si) +diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c +index 7ba241e..388dc6c 100644 +--- a/drivers/scsi/libfc/fc_frame.c ++++ b/drivers/scsi/libfc/fc_frame.c +@@ -82,7 +82,7 @@ struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) + if (fp) { + memset((char *) fr_hdr(fp) + payload_len, 0, fill); + /* trim is OK, we just allocated it so there are no fragments */ +- skb_trim(fp_skb(fp), payload_len); ++ skb_trim(fp_skb(fp), payload_len + sizeof(struct fc_frame_header)); + } + return fp; + } +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index bfbc7d4..7e7c060 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -28,7 +28,7 @@ + * the lport to be reset before we fill out the frame header's port_id. The + * problem is that a reset would cause the lport's port_id to reset to 0. + * If we don't protect the lport we'd spew incorrect frames. +- * ++ * + * At the time of this writing there are two primary mutexes, one for the + * lport and one for the rport. Since the lport uses the rport and makes + * calls into that block the rport should never make calls that would cause +@@ -537,7 +537,7 @@ void fc_linkdown(struct fc_lport *lport) + if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) { + lport->link_status &= ~(FC_LINK_UP); + fc_lport_enter_reset(lport); +- lport->tt.scsi_cleanup(lport); ++ lport->tt.fcp_cleanup(lport); + } + + mutex_unlock(&lport->lp_mutex); +@@ -579,7 +579,7 @@ int fc_fabric_logoff(struct fc_lport *lport) + { + mutex_lock(&lport->lp_mutex); + fc_lport_enter_logo(lport); +- lport->tt.scsi_cleanup(lport); ++ lport->tt.fcp_cleanup(lport); + mutex_unlock(&lport->lp_mutex); + return 0; + } +@@ -600,7 +600,7 @@ EXPORT_SYMBOL(fc_fabric_logoff); + int fc_lport_destroy(struct fc_lport *lport) + { + cancel_delayed_work_sync(&lport->disc_work); +- lport->tt.scsi_abort_io(lport); ++ lport->tt.fcp_abort_io(lport); + lport->tt.frame_send = fc_frame_drop; + lport->tt.exch_mgr_reset(lport->emp, 0, 0); + return 0; +@@ -929,8 +929,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) + if (!fp) + delay = msecs_to_jiffies(500); + else +- delay = jiffies + +- msecs_to_jiffies(lport->e_d_tov); ++ delay = msecs_to_jiffies(lport->e_d_tov); + + schedule_delayed_work(&lport->retry_work, delay); + } else { +@@ -969,6 +968,9 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp, + struct fc_frame_header *fh; + struct fc_ct_hdr *ct; + ++ if (fp == ERR_PTR(-FC_EX_CLOSED)) ++ return; ++ + mutex_lock(&lport->lp_mutex); + + FC_DEBUG_LPORT("Received a RFT_ID response\n"); +@@ -1018,6 +1020,9 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, + struct fc_frame_header *fh; + struct fc_ct_hdr *ct; + ++ if (fp == ERR_PTR(-FC_EX_CLOSED)) ++ return; ++ + mutex_lock(&lport->lp_mutex); + + FC_DEBUG_LPORT("Received a RPN_ID response\n"); +@@ -1065,6 +1070,9 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, + struct fc_lport *lport = lp_arg; + u8 op; + ++ if (fp == ERR_PTR(-FC_EX_CLOSED)) ++ return; ++ + mutex_lock(&lport->lp_mutex); + + FC_DEBUG_LPORT("Received a SCR response\n"); +@@ -1332,6 +1340,9 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + struct fc_lport *lport = lp_arg; + u8 op; + ++ if (fp == ERR_PTR(-FC_EX_CLOSED)) ++ return; ++ + mutex_lock(&lport->lp_mutex); + + FC_DEBUG_LPORT("Received a LOGO response\n"); +@@ -1426,6 +1437,9 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + unsigned int e_d_tov; + u16 mfs; + ++ if (fp == ERR_PTR(-FC_EX_CLOSED)) ++ return; ++ + mutex_lock(&lport->lp_mutex); + + FC_DEBUG_LPORT("Received a FLOGI response\n"); +diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c +index 651a3ed..42da6ed 100644 +--- a/drivers/scsi/libfc/fc_rport.c ++++ b/drivers/scsi/libfc/fc_rport.c +@@ -106,6 +106,17 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) + rport->node_name = dp->ids.node_name; + rport->roles = dp->ids.roles; + rport->maxframe_size = FC_MIN_MAX_PAYLOAD; ++ /* ++ * init the device, so other code can manipulate the rport as if ++ * it came from the fc class. We also do an extra get because ++ * libfc will free this rport instead of relying on the normal ++ * refcounting. ++ * ++ * Note: all this libfc rogue rport code will be removed for ++ * upstream so it fine that this is really ugly and hacky right now. ++ */ ++ device_initialize(&rport->dev); ++ get_device(&rport->dev); + + mutex_init(&rdata->rp_mutex); + rdata->local_port = dp->lp; +diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h +index 7e5e6be..237abd3 100644 +--- a/include/scsi/libfc/libfc.h ++++ b/include/scsi/libfc/libfc.h +@@ -157,9 +157,9 @@ struct fc_rport_libfc_priv { + }; + + #define PRIV_TO_RPORT(x) \ +- (struct fc_rport*)((void *)x - sizeof(struct fc_rport)); ++ (struct fc_rport *)((void *)x - sizeof(struct fc_rport)); + #define RPORT_TO_PRIV(x) \ +- (struct fc_rport_libfc_priv*)((void *)x + sizeof(struct fc_rport)); ++ (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); + + struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *); + void fc_rport_rogue_destroy(struct fc_rport *); +@@ -203,6 +203,68 @@ struct fc_seq_els_data { + enum fc_els_rjt_explan explan; + }; + ++/* ++ * FCP request structure, one for each scsi cmd request ++ */ ++struct fc_fcp_pkt { ++ /* ++ * housekeeping stuff ++ */ ++ struct fc_lport *lp; /* handle to hba struct */ ++ u16 state; /* scsi_pkt state state */ ++ u16 tgt_flags; /* target flags */ ++ atomic_t ref_cnt; /* fcp pkt ref count */ ++ spinlock_t scsi_pkt_lock; /* Must be taken before the host lock ++ * if both are held at the same time */ ++ /* ++ * SCSI I/O related stuff ++ */ ++ struct scsi_cmnd *cmd; /* scsi command pointer. set/clear ++ * under host lock */ ++ struct list_head list; /* tracks queued commands. access under ++ * host lock */ ++ /* ++ * timeout related stuff ++ */ ++ struct timer_list timer; /* command timer */ ++ struct completion tm_done; ++ int wait_for_comp; ++ unsigned long start_time; /* start jiffie */ ++ unsigned long end_time; /* end jiffie */ ++ unsigned long last_pkt_time; /* jiffies of last frame received */ ++ ++ /* ++ * scsi cmd and data transfer information ++ */ ++ u32 data_len; ++ /* ++ * transport related veriables ++ */ ++ struct fcp_cmnd cdb_cmd; ++ size_t xfer_len; ++ u32 xfer_contig_end; /* offset of end of contiguous xfer */ ++ u16 max_payload; /* max payload size in bytes */ ++ ++ /* ++ * scsi/fcp return status ++ */ ++ u32 io_status; /* SCSI result upper 24 bits */ ++ u8 cdb_status; ++ u8 status_code; /* FCP I/O status */ ++ /* bit 3 Underrun bit 2: overrun */ ++ u8 scsi_comp_flags; ++ u32 req_flags; /* bit 0: read bit:1 write */ ++ u32 scsi_resid; /* residule length */ ++ ++ struct fc_rport *rport; /* remote port pointer */ ++ struct fc_seq *seq_ptr; /* current sequence pointer */ ++ /* ++ * Error Processing ++ */ ++ u8 recov_retry; /* count of recovery retries */ ++ struct fc_seq *recov_seq; /* sequence for REC or SRR */ ++}; ++ + struct libfc_function_template { + + /** +@@ -372,7 +434,7 @@ struct libfc_function_template { + */ + int (*rport_logout)(struct fc_rport *rport); + +- /* ++ /* + * Delete the rport and remove it from the transport if + * it had been added. This will not send a LOGO, use + * rport_logout for a gracefull logout. +@@ -388,18 +450,29 @@ struct libfc_function_template { + struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); + + /** +- * SCSI interfaces ++ * FCP interfaces + */ + + /* ++ * Send a fcp cmd from fsp pkt. ++ * Called with the SCSI host lock unlocked and irqs disabled. ++ * ++ * The resp handler is called when FCP_RSP received. ++ * ++ */ ++ int (*fcp_cmd_send)(struct fc_lport *lp, struct fc_fcp_pkt *fsp, ++ void (*resp)(struct fc_seq *, struct fc_frame *fp, ++ void *arg)); ++ ++ /* + * Used at least durring linkdown and reset + */ +- void (*scsi_cleanup)(struct fc_lport *); ++ void (*fcp_cleanup)(struct fc_lport *lp); + + /* + * Abort all I/O on a local port + */ +- void (*scsi_abort_io)(struct fc_lport *); ++ void (*fcp_abort_io)(struct fc_lport *lp); + + /** + * Discovery interfaces +@@ -600,6 +673,14 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, + void (*done)(struct scsi_cmnd *)); + + /* ++ * complete processing of a fcp packet ++ * ++ * This function may sleep if a fsp timer is pending. ++ * The host lock must not be held by caller. ++ */ ++void fc_fcp_complete(struct fc_fcp_pkt *fsp); ++ ++/* + * Send an ABTS frame to the target device. The sc_cmd argument + * is a pointer to the SCSI command to be aborted. + */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta6-update b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta6-update new file mode 100644 index 000000000..10c01e41f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-beta6-update @@ -0,0 +1,9053 @@ +From: Vasu Dev +Subject: Incremental Open-FCoE for Beta6 +References: bnc#438954 + +Incremental Open-FCoE update for Beta6. + +Signed-off-by: Vasu Dev +Acked-by: Hannes Reinecke +--- +diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig +index 6f38b13..4922958 100644 +--- a/drivers/scsi/Kconfig ++++ b/drivers/scsi/Kconfig +@@ -328,19 +328,6 @@ menuconfig SCSI_LOWLEVEL + + if SCSI_LOWLEVEL && SCSI + +-config LIBFC +- tristate "LibFC module" +- depends on SCSI && SCSI_FC_ATTRS +- ---help--- +- Fibre Channel library module +- +-config FCOE +- tristate "FCoE module" +- depends on SCSI && SCSI_FC_ATTRS +- select LIBFC +- ---help--- +- Fibre Channel over Ethernet module +- + config ISCSI_TCP + tristate "iSCSI Initiator over TCP/IP" + depends on SCSI && INET +@@ -616,6 +603,20 @@ config SCSI_FLASHPOINT + substantial, so users of MultiMaster Host Adapters may not + wish to include it. + ++config LIBFC ++ tristate "LibFC module" ++ depends on SCSI && SCSI_FC_ATTRS ++ ---help--- ++ Fibre Channel library module ++ ++config FCOE ++ tristate "FCoE module" ++ depends on SCSI ++ select LIBFC ++ ---help--- ++ Fibre Channel over Ethernet module ++ ++ + config SCSI_DMX3191D + tristate "DMX3191D SCSI support" + depends on PCI && SCSI +diff --git a/drivers/scsi/fcoe/fc_transport_fcoe.c b/drivers/scsi/fcoe/fc_transport_fcoe.c +index ff207b2..bf7fe6f 100644 +--- a/drivers/scsi/fcoe/fc_transport_fcoe.c ++++ b/drivers/scsi/fcoe/fc_transport_fcoe.c +@@ -17,356 +17,430 @@ + * Maintained at www.Open-FCoE.org + */ + +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +- +-#include "fcoe_def.h" +- +-MODULE_AUTHOR("Open-FCoE.org"); +-MODULE_DESCRIPTION("FCoE"); +-MODULE_LICENSE("GPL"); +-MODULE_VERSION("1.0.3"); ++#include ++#include ++#include + +-/* +- * Static functions and variables definations +- */ +-#ifdef CONFIG_HOTPLUG_CPU +-static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); +-#endif /* CONFIG_HOTPLUG_CPU */ +-static int fcoe_device_notification(struct notifier_block *, ulong, void *); +-static void fcoe_dev_setup(void); +-static void fcoe_dev_cleanup(void); +- +-#ifdef CONFIG_HOTPLUG_CPU +-static struct notifier_block fcoe_cpu_notifier = { +- .notifier_call = fcoe_cpu_callback, ++/* internal fcoe transport */ ++struct fcoe_transport_internal { ++ struct fcoe_transport *t; ++ struct net_device *netdev; ++ struct list_head list; + }; +-#endif /* CONFIG_HOTPLUG_CPU */ + +-/* +- * notification function from net device +- */ +-static struct notifier_block fcoe_notifier = { +- .notifier_call = fcoe_device_notification, +-}; ++/* fcoe transports list and its lock */ ++static LIST_HEAD(fcoe_transports); ++static DEFINE_MUTEX(fcoe_transports_lock); + +-#ifdef CONFIG_HOTPLUG_CPU +-/* +- * create percpu stats block +- * called by cpu add/remove notifier +- */ +-static void fcoe_create_percpu_data(int cpu) ++/** ++ * fcoe_transport_default - returns ptr to the default transport fcoe_sw ++ **/ ++struct fcoe_transport *fcoe_transport_default(void) + { +- struct fc_lport *lp; +- struct fcoe_softc *fc; +- +- write_lock_bh(&fcoe_hostlist_lock); +- list_for_each_entry(fc, &fcoe_hostlist, list) { +- lp = fc->lp; +- if (lp->dev_stats[cpu] == NULL) +- lp->dev_stats[cpu] = kzalloc(sizeof(struct fcoe_dev_stats), +- GFP_KERNEL); +- } +- write_unlock_bh(&fcoe_hostlist_lock); ++ return &fcoe_sw_transport; + } + +-/* +- * destroy percpu stats block +- * called by cpu add/remove notifier +- */ +-static void fcoe_destroy_percpu_data(int cpu) ++/** ++ * fcoe_transport_to_pcidev - get the pci dev from a netdev ++ * @netdev: the netdev that pci dev will be retrived from ++ * ++ * Returns: NULL or the corrsponding pci_dev ++ **/ ++struct pci_dev *fcoe_transport_pcidev(const struct net_device *netdev) + { +- struct fc_lport *lp; +- struct fcoe_softc *fc; +- +- write_lock_bh(&fcoe_hostlist_lock); +- list_for_each_entry(fc, &fcoe_hostlist, list) { +- lp = fc->lp; +- kfree(lp->dev_stats[cpu]); +- lp->dev_stats[cpu] = NULL; +- } +- write_unlock_bh(&fcoe_hostlist_lock); ++ if (!netdev->dev.parent) ++ return NULL; ++ return to_pci_dev(netdev->dev.parent); + } + +-/* +- * Get notified when a cpu comes on/off. Be hotplug friendly. +- */ +-static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action, +- void *hcpu) ++/** ++ * fcoe_transport_device_lookup - find out netdev is managed by the ++ * transport ++ * assign a transport to a device ++ * @netdev: the netdev the transport to be attached to ++ * ++ * This will look for existing offload driver, if not found, it falls back to ++ * the default sw hba (fcoe_sw) as its fcoe transport. ++ * ++ * Returns: 0 for success ++ **/ ++static struct fcoe_transport_internal *fcoe_transport_device_lookup( ++ struct fcoe_transport *t, struct net_device *netdev) + { +- unsigned int cpu = (unsigned long)hcpu; +- +- switch (action) { +- case CPU_ONLINE: +- fcoe_create_percpu_data(cpu); +- break; +- case CPU_DEAD: +- fcoe_destroy_percpu_data(cpu); +- break; +- default: +- break; ++ struct fcoe_transport_internal *ti; ++ ++ /* assign the transpor to this device */ ++ mutex_lock(&t->devlock); ++ list_for_each_entry(ti, &t->devlist, list) { ++ if (ti->netdev == netdev) { ++ mutex_unlock(&t->devlock); ++ return ti; ++ } + } +- return NOTIFY_OK; ++ mutex_unlock(&t->devlock); ++ return NULL; + } +-#endif /* CONFIG_HOTPLUG_CPU */ +- +-/* +- * function to setup link change notification interface +- */ +-static void fcoe_dev_setup(void) ++/** ++ * fcoe_transport_device_add - assign a transport to a device ++ * @netdev: the netdev the transport to be attached to ++ * ++ * This will look for existing offload driver, if not found, it falls back to ++ * the default sw hba (fcoe_sw) as its fcoe transport. ++ * ++ * Returns: 0 for success ++ **/ ++static int fcoe_transport_device_add(struct fcoe_transport *t, ++ struct net_device *netdev) + { +- /* +- * here setup a interface specific wd time to +- * monitor the link state +- */ +- register_netdevice_notifier(&fcoe_notifier); ++ struct fcoe_transport_internal *ti; ++ ++ ti = fcoe_transport_device_lookup(t, netdev); ++ if (ti) { ++ printk(KERN_DEBUG "fcoe_transport_device_add:" ++ "device %s is already added to transport %s\n", ++ netdev->name, t->name); ++ return -EEXIST; ++ } ++ /* allocate an internal struct to host the netdev and the list */ ++ ti = kzalloc(sizeof(*ti), GFP_KERNEL); ++ if (!ti) ++ return -ENOMEM; ++ ++ ti->t = t; ++ ti->netdev = netdev; ++ INIT_LIST_HEAD(&ti->list); ++ dev_hold(ti->netdev); ++ ++ mutex_lock(&t->devlock); ++ list_add(&ti->list, &t->devlist); ++ mutex_unlock(&t->devlock); ++ ++ printk(KERN_DEBUG "fcoe_transport_device_add:" ++ "device %s added to transport %s\n", ++ netdev->name, t->name); ++ ++ return 0; + } + +-/* +- * function to cleanup link change notification interface +- */ +-static void fcoe_dev_cleanup(void) ++/** ++ * fcoe_transport_device_remove - remove a device from its transport ++ * @netdev: the netdev the transport to be attached to ++ * ++ * this removes the device from the transport so the given transport will ++ * not manage this device any more ++ * ++ * Returns: 0 for success ++ **/ ++static int fcoe_transport_device_remove(struct fcoe_transport *t, ++ struct net_device *netdev) + { +- unregister_netdevice_notifier(&fcoe_notifier); ++ struct fcoe_transport_internal *ti; ++ ++ ti = fcoe_transport_device_lookup(t, netdev); ++ if (!ti) { ++ printk(KERN_DEBUG "fcoe_transport_device_remove:" ++ "device %s is not managed by transport %s\n", ++ netdev->name, t->name); ++ return -ENODEV; ++ } ++ mutex_lock(&t->devlock); ++ list_del(&ti->list); ++ mutex_unlock(&t->devlock); ++ printk(KERN_DEBUG "fcoe_transport_device_remove:" ++ "device %s removed from transport %s\n", ++ netdev->name, t->name); ++ dev_put(ti->netdev); ++ kfree(ti); ++ return 0; + } + +-/* +- * This function is called by the ethernet driver +- * this is called in case of link change event +- */ +-static int fcoe_device_notification(struct notifier_block *notifier, +- ulong event, void *ptr) ++/** ++ * fcoe_transport_device_remove_all - remove all from transport devlist ++ * ++ * this removes the device from the transport so the given transport will ++ * not manage this device any more ++ * ++ * Returns: 0 for success ++ **/ ++static void fcoe_transport_device_remove_all(struct fcoe_transport *t) + { +- struct fc_lport *lp = NULL; +- struct net_device *real_dev = ptr; +- struct fcoe_softc *fc; +- struct fcoe_dev_stats *stats; +- u16 new_status; +- u32 mfs; +- int rc = NOTIFY_OK; +- +- read_lock(&fcoe_hostlist_lock); +- list_for_each_entry(fc, &fcoe_hostlist, list) { +- if (fc->real_dev == real_dev) { +- lp = fc->lp; +- break; +- } +- } +- read_unlock(&fcoe_hostlist_lock); +- if (lp == NULL) { +- rc = NOTIFY_DONE; +- goto out; +- } ++ struct fcoe_transport_internal *ti, *tmp; + +- new_status = lp->link_status; +- switch (event) { +- case NETDEV_DOWN: +- case NETDEV_GOING_DOWN: +- new_status &= ~FC_LINK_UP; +- break; +- case NETDEV_UP: +- case NETDEV_CHANGE: +- new_status &= ~FC_LINK_UP; +- if (!fcoe_link_ok(lp)) +- new_status |= FC_LINK_UP; +- break; +- case NETDEV_CHANGEMTU: +- mfs = fc->real_dev->mtu - +- (sizeof(struct fcoe_hdr) + +- sizeof(struct fcoe_crc_eof)); +- if (fc->user_mfs && fc->user_mfs < mfs) +- mfs = fc->user_mfs; +- if (mfs >= FC_MIN_MAX_FRAME) +- fc_set_mfs(lp, mfs); +- new_status &= ~FC_LINK_UP; +- if (!fcoe_link_ok(lp)) +- new_status |= FC_LINK_UP; +- break; +- case NETDEV_REGISTER: +- break; +- default: +- FC_DBG("unknown event %ld call", event); +- } +- if (lp->link_status != new_status) { +- if ((new_status & FC_LINK_UP) == FC_LINK_UP) +- fc_linkup(lp); +- else { +- stats = lp->dev_stats[smp_processor_id()]; +- if (stats) +- stats->LinkFailureCount++; +- fc_linkdown(lp); +- fcoe_clean_pending_queue(lp); +- } ++ mutex_lock(&t->devlock); ++ list_for_each_entry_safe(ti, tmp, &t->devlist, list) { ++ list_del(&ti->list); ++ kfree(ti); + } +-out: +- return rc; ++ mutex_unlock(&t->devlock); + } + +-static void trimstr(char *str, int len) ++/** ++ * fcoe_transport_match - use the bus device match function to match the hw ++ * @t: the fcoe transport ++ * @netdev: ++ * ++ * This function is used to check if the givne transport wants to manage the ++ * input netdev. if the transports implements the match function, it will be ++ * called, o.w. we just compare the pci vendor and device id. ++ * ++ * Returns: true for match up ++ **/ ++static bool fcoe_transport_match(struct fcoe_transport *t, ++ struct net_device *netdev) + { +- char *cp = str + len; +- while (--cp >= str && *cp == '\n') +- *cp = '\0'; ++ /* match transport by vendor and device id */ ++ struct pci_dev *pci; ++ ++ pci = fcoe_transport_pcidev(netdev); ++ ++ if (pci) { ++ printk(KERN_DEBUG "fcoe_transport_match:" ++ "%s:%x:%x -- %s:%x:%x\n", ++ t->name, t->vendor, t->device, ++ netdev->name, pci->vendor, pci->device); ++ ++ /* if transport supports match */ ++ if (t->match) ++ return t->match(netdev); ++ ++ /* else just compare the vendor and device id: pci only */ ++ return (t->vendor == pci->vendor) && (t->device == pci->device); ++ } ++ return false; + } + +-static int fcoe_destroy(const char *buffer, struct kernel_param *kp) ++/** ++ * fcoe_transport_lookup - check if the transport is already registered ++ * @t: the transport to be looked up ++ * ++ * This compares the parent device (pci) vendor and device id ++ * ++ * Returns: NULL if not found ++ * ++ * TODO - return default sw transport if no other transport is found ++ **/ ++static struct fcoe_transport *fcoe_transport_lookup( ++ struct net_device *netdev) + { +- struct net_device *netdev; +- char ifname[IFNAMSIZ + 2]; +- int rc = -ENODEV; +- +- strlcpy(ifname, buffer, IFNAMSIZ); +- trimstr(ifname, strlen(ifname)); +- netdev = dev_get_by_name(&init_net, ifname); +- if (netdev) { +- rc = fcoe_destroy_interface(netdev); +- dev_put(netdev); ++ struct fcoe_transport *t; ++ ++ mutex_lock(&fcoe_transports_lock); ++ list_for_each_entry(t, &fcoe_transports, list) { ++ if (fcoe_transport_match(t, netdev)) { ++ mutex_unlock(&fcoe_transports_lock); ++ return t; ++ } + } +- return rc; ++ mutex_unlock(&fcoe_transports_lock); ++ ++ printk(KERN_DEBUG "fcoe_transport_lookup:" ++ "use default transport for %s\n", netdev->name); ++ return fcoe_transport_default(); + } + +-static int fcoe_create(const char *buffer, struct kernel_param *kp) ++/** ++ * fcoe_transport_register - adds a fcoe transport to the fcoe transports list ++ * @t: ptr to the fcoe transport to be added ++ * ++ * Returns: 0 for success ++ **/ ++int fcoe_transport_register(struct fcoe_transport *t) + { +- struct net_device *netdev; +- char ifname[IFNAMSIZ + 2]; +- int rc = -ENODEV; +- +- strlcpy(ifname, buffer, IFNAMSIZ); +- trimstr(ifname, strlen(ifname)); +- netdev = dev_get_by_name(&init_net, ifname); +- if (netdev) { +- rc = fcoe_create_interface(netdev); +- dev_put(netdev); ++ struct fcoe_transport *tt; ++ ++ /* TODO - add fcoe_transport specific initialization here */ ++ mutex_lock(&fcoe_transports_lock); ++ list_for_each_entry(tt, &fcoe_transports, list) { ++ if (tt == t) { ++ mutex_unlock(&fcoe_transports_lock); ++ return -EEXIST; ++ } + } +- return rc; ++ list_add_tail(&t->list, &fcoe_transports); ++ mutex_unlock(&fcoe_transports_lock); ++ ++ mutex_init(&t->devlock); ++ INIT_LIST_HEAD(&t->devlist); ++ ++ printk(KERN_DEBUG "fcoe_transport_register:%s\n", t->name); ++ ++ return 0; + } ++EXPORT_SYMBOL_GPL(fcoe_transport_register); + +-module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); +-__MODULE_PARM_TYPE(create, "string"); +-MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); +-module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); +-__MODULE_PARM_TYPE(destroy, "string"); +-MODULE_PARM_DESC(destroy, "Destroy fcoe port"); ++/** ++ * fcoe_transport_unregister - remove the tranport fro the fcoe transports list ++ * @t: ptr to the fcoe transport to be removed ++ * ++ * Returns: 0 for success ++ **/ ++int fcoe_transport_unregister(struct fcoe_transport *t) ++{ ++ struct fcoe_transport *tt, *tmp; ++ ++ mutex_lock(&fcoe_transports_lock); ++ list_for_each_entry_safe(tt, tmp, &fcoe_transports, list) { ++ if (tt == t) { ++ list_del(&t->list); ++ mutex_unlock(&fcoe_transports_lock); ++ fcoe_transport_device_remove_all(t); ++ printk(KERN_DEBUG "fcoe_transport_unregister:%s\n", ++ t->name); ++ return 0; ++ } ++ } ++ mutex_unlock(&fcoe_transports_lock); ++ return -ENODEV; ++} ++EXPORT_SYMBOL_GPL(fcoe_transport_unregister); + + /* +- * Initialization routine +- * 1. Will create fc transport software structure +- * 2. initialize the link list of port information structure +- */ +-static int __init fcoe_init(void) ++ * fcoe_load_transport_driver - load an offload driver by alias name ++ * @netdev: the target net device ++ * ++ * Requests for an offload driver module as the fcoe transport, if fails, it ++ * falls back to use the SW HBA (fcoe_sw) as its transport ++ * ++ * TODO - ++ * 1. supports only PCI device ++ * 2. needs fix for VLAn and bonding ++ * 3. pure hw fcoe hba may not have netdev ++ * ++ * Returns: 0 for success ++ **/ ++int fcoe_load_transport_driver(struct net_device *netdev) + { +- int cpu; +- struct fcoe_percpu_s *p; +- +- rwlock_init(&fcoe_hostlist_lock); +- +-#ifdef CONFIG_HOTPLUG_CPU +- register_cpu_notifier(&fcoe_cpu_notifier); +-#endif /* CONFIG_HOTPLUG_CPU */ +- +- /* +- * initialize per CPU interrupt thread +- */ +- for_each_online_cpu(cpu) { +- p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL); +- if (p) { +- p->thread = kthread_create(fcoe_percpu_receive_thread, +- (void *)p, +- "fcoethread/%d", cpu); +- +- /* +- * if there is no error then bind the thread to the cpu +- * initialize the semaphore and skb queue head +- */ +- if (likely(!IS_ERR(p->thread))) { +- p->cpu = cpu; +- fcoe_percpu[cpu] = p; +- skb_queue_head_init(&p->fcoe_rx_list); +- kthread_bind(p->thread, cpu); +- wake_up_process(p->thread); +- } else { +- fcoe_percpu[cpu] = NULL; +- kfree(p); +- +- } +- } ++ struct pci_dev *pci; ++ struct device *dev = netdev->dev.parent; ++ ++ if (fcoe_transport_lookup(netdev)) { ++ /* load default transport */ ++ printk(KERN_DEBUG "fcoe: already loaded transport for %s\n", ++ netdev->name); ++ return -EEXIST; + } + +- /* +- * setup link change notification +- */ +- fcoe_dev_setup(); ++ pci = to_pci_dev(dev); ++ if (dev->bus != &pci_bus_type) { ++ printk(KERN_DEBUG "fcoe: support noly PCI device\n"); ++ return -ENODEV; ++ } ++ printk(KERN_DEBUG "fcoe: loading driver fcoe-pci-0x%04x-0x%04x\n", ++ pci->vendor, pci->device); ++ ++ return request_module("fcoe-pci-0x%04x-0x%04x", ++ pci->vendor, pci->device); + +- init_timer(&fcoe_timer); +- fcoe_timer.data = 0; +- fcoe_timer.function = fcoe_watchdog; +- fcoe_timer.expires = (jiffies + (10 * HZ)); +- add_timer(&fcoe_timer); ++} ++EXPORT_SYMBOL_GPL(fcoe_load_transport_driver); + +- if (fcoe_sw_init() != 0) { +- FC_DBG("fail to attach fc transport"); +- return -1; ++/** ++ * fcoe_transport_attach - load transport to fcoe ++ * @netdev: the netdev the transport to be attached to ++ * ++ * This will look for existing offload driver, if not found, it falls back to ++ * the default sw hba (fcoe_sw) as its fcoe transport. ++ * ++ * Returns: 0 for success ++ **/ ++int fcoe_transport_attach(struct net_device *netdev) ++{ ++ struct fcoe_transport *t; ++ ++ /* find the corresponding transport */ ++ t = fcoe_transport_lookup(netdev); ++ if (!t) { ++ printk(KERN_DEBUG "fcoe_transport_attach" ++ ":no transport for %s:use %s\n", ++ netdev->name, t->name); ++ return -ENODEV; + } ++ /* add to the transport */ ++ if (fcoe_transport_device_add(t, netdev)) { ++ printk(KERN_DEBUG "fcoe_transport_attach" ++ ":failed to add %s to tramsport %s\n", ++ netdev->name, t->name); ++ return -EIO; ++ } ++ /* transport create function */ ++ if (t->create) ++ t->create(netdev); + ++ printk(KERN_DEBUG "fcoe_transport_attach:transport %s for %s\n", ++ t->name, netdev->name); + return 0; + } +-module_init(fcoe_init); ++EXPORT_SYMBOL_GPL(fcoe_transport_attach); + +-static void __exit fcoe_exit(void) ++/** ++ * fcoe_transport_release - unload transport from fcoe ++ * @netdev: the net device on which fcoe is to be released ++ * ++ * Returns: 0 for success ++ **/ ++int fcoe_transport_release(struct net_device *netdev) + { +- u32 idx; +- struct fcoe_softc *fc, *tmp; +- struct fcoe_percpu_s *p; +- struct sk_buff *skb; +- +- /* +- * Stop all call back interfaces +- */ +-#ifdef CONFIG_HOTPLUG_CPU +- unregister_cpu_notifier(&fcoe_cpu_notifier); +-#endif /* CONFIG_HOTPLUG_CPU */ +- fcoe_dev_cleanup(); +- +- /* +- * stop timer +- */ +- del_timer_sync(&fcoe_timer); +- +- /* +- * assuming that at this time there will be no +- * ioctl in prograss, therefore we do not need to lock the +- * list. +- */ +- list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) +- fcoe_destroy_interface(fc->real_dev); +- +- for (idx = 0; idx < NR_CPUS; idx++) { +- if (fcoe_percpu[idx]) { +- kthread_stop(fcoe_percpu[idx]->thread); +- p = fcoe_percpu[idx]; +- spin_lock_bh(&p->fcoe_rx_list.lock); +- while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) +- kfree_skb(skb); +- spin_unlock_bh(&p->fcoe_rx_list.lock); +- if (fcoe_percpu[idx]->crc_eof_page) +- put_page(fcoe_percpu[idx]->crc_eof_page); +- kfree(fcoe_percpu[idx]); +- } ++ struct fcoe_transport *t; ++ ++ /* find the corresponding transport */ ++ t = fcoe_transport_lookup(netdev); ++ if (!t) { ++ printk(KERN_DEBUG "fcoe_transport_release:" ++ "no transport for %s:use %s\n", ++ netdev->name, t->name); ++ return -ENODEV; + } ++ /* remove the device from the transport */ ++ if (fcoe_transport_device_remove(t, netdev)) { ++ printk(KERN_DEBUG "fcoe_transport_release:" ++ "failed to add %s to tramsport %s\n", ++ netdev->name, t->name); ++ return -EIO; ++ } ++ /* transport destroy function */ ++ if (t->destroy) ++ t->destroy(netdev); ++ ++ printk(KERN_DEBUG "fcoe_transport_release:" ++ "device %s dettached from transport %s\n", ++ netdev->name, t->name); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(fcoe_transport_release); ++ ++/** ++ * fcoe_transport_init - initializes fcoe transport layer ++ * ++ * This prepares for the fcoe transport layer ++ * ++ * Returns: none ++ **/ ++int __init fcoe_transport_init(void) ++{ ++ INIT_LIST_HEAD(&fcoe_transports); ++ mutex_init(&fcoe_transports_lock); ++ return 0; ++} + +- fcoe_sw_exit(); ++/** ++ * fcoe_transport_exit - cleans up the fcoe transport layer ++ * This cleans up the fcoe transport layer. removing any transport on the list, ++ * note that the transport destroy func is not called here. ++ * ++ * Returns: none ++ **/ ++int __exit fcoe_transport_exit(void) ++{ ++ struct fcoe_transport *t, *tmp; ++ ++ mutex_lock(&fcoe_transports_lock); ++ list_for_each_entry_safe(t, tmp, &fcoe_transports, list) { ++ list_del(&t->list); ++ mutex_unlock(&fcoe_transports_lock); ++ fcoe_transport_device_remove_all(t); ++ mutex_lock(&fcoe_transports_lock); ++ } ++ mutex_unlock(&fcoe_transports_lock); ++ return 0; + } +-module_exit(fcoe_exit); +diff --git a/drivers/scsi/fcoe/fcoe_def.h b/drivers/scsi/fcoe/fcoe_def.h +deleted file mode 100644 +index b00e14b..0000000 +--- a/drivers/scsi/fcoe/fcoe_def.h ++++ /dev/null +@@ -1,92 +0,0 @@ +-/* +- * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-#ifndef _FCOE_DEF_H_ +-#define _FCOE_DEF_H_ +- +-#include +-#include +- +-#include +- +-#include +- +-#define FCOE_DRIVER_NAME "fcoe" /* driver name for ioctls */ +-#define FCOE_DRIVER_VENDOR "Open-FC.org" /* vendor name for ioctls */ +- +-#define FCOE_MIN_FRAME 36 +-#define FCOE_WORD_TO_BYTE 4 +- +-/* +- * this is the main common structure across all instance of fcoe driver. +- * There is one to one mapping between hba struct and ethernet nic. +- * list of hbas contains pointer to the hba struct, these structures are +- * stored in this array using there corresponding if_index. +- */ +- +-struct fcoe_percpu_s { +- int cpu; +- struct task_struct *thread; +- struct sk_buff_head fcoe_rx_list; +- struct page *crc_eof_page; +- int crc_eof_offset; +-}; +- +-extern struct timer_list fcoe_timer; +-extern rwlock_t fcoe_hostlist_lock; +-extern struct list_head fcoe_hostlist; +-extern struct fcoe_percpu_s *fcoe_percpu[]; +- +-struct fcoe_softc { +- struct list_head list; +- struct fc_lport *lp; +- struct net_device *real_dev; +- struct net_device *phys_dev; /* device with ethtool_ops */ +- struct packet_type fcoe_packet_type; +- struct sk_buff_head fcoe_pending_queue; +- u16 user_mfs; /* configured max frame size */ +- +- u8 dest_addr[ETH_ALEN]; +- u8 ctl_src_addr[ETH_ALEN]; +- u8 data_src_addr[ETH_ALEN]; +- /* +- * fcoe protocol address learning related stuff +- */ +- u16 flogi_oxid; +- u8 flogi_progress; +- u8 address_mode; +-}; +- +-int fcoe_percpu_receive_thread(void *arg); +- +-/* +- * HBA transport ops prototypes +- */ +-void fcoe_clean_pending_queue(struct fc_lport *fd); +-void fcoe_watchdog(ulong vp); +-int fcoe_destroy_interface(struct net_device *); +-int fcoe_create_interface(struct net_device *); +-int fcoe_xmit(struct fc_lport *, struct fc_frame *); +-int fcoe_rcv(struct sk_buff *, struct net_device *, +- struct packet_type *, struct net_device *); +-int fcoe_link_ok(struct fc_lport *); +- +-int __init fcoe_sw_init(void); +-void __exit fcoe_sw_exit(void); +-#endif /* _FCOE_DEF_H_ */ +diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c +index d7ceb1b..33aebe5 100644 +--- a/drivers/scsi/fcoe/fcoe_sw.c ++++ b/drivers/scsi/fcoe/fcoe_sw.c +@@ -17,19 +17,14 @@ + * Maintained at www.Open-FCoE.org + */ + +-/* +- * FCOE protocol file +- */ +- + #include + #include + #include ++#include + #include + #include + #include + #include +-#include +-#include + #include + #include + +@@ -39,36 +34,25 @@ + #include + #include + +-#include +- +-#include +-#include "fcoe_def.h" ++#include ++#include ++#include + +-#define FCOE_VERSION "0.1" ++#define FCOE_SW_VERSION "0.1" ++#define FCOE_SW_NAME "fcoesw" ++#define FCOE_SW_VENDOR "Open-FCoE.org" + + #define FCOE_MAX_LUN 255 + #define FCOE_MAX_FCP_TARGET 256 + + #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 + +-#define FCOE_MIN_XID 0x0004 +-#define FCOE_MAX_XID 0x07ef ++#define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ ++#define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ + +-LIST_HEAD(fcoe_hostlist); +-DEFINE_RWLOCK(fcoe_hostlist_lock); +-DEFINE_TIMER(fcoe_timer, NULL, 0, 0); +-struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; +- +-static struct scsi_transport_template *fcoe_transport_template; +- +-static int fcoe_reset(struct Scsi_Host *shost) +-{ +- struct fc_lport *lport = shost_priv(shost); +- fc_lport_reset(lport); +- return 0; +-} ++static struct scsi_transport_template *scsi_transport_fcoe_sw; + +-struct fc_function_template fcoe_transport_function = { ++struct fc_function_template fcoe_sw_transport_function = { + .show_host_node_name = 1, + .show_host_port_name = 1, + .show_host_supported_classes = 1, +@@ -101,60 +85,10 @@ struct fc_function_template fcoe_transport_function = { + .terminate_rport_io = fc_rport_terminate_io, + }; + +-static struct fcoe_softc *fcoe_find_fc_lport(const struct net_device *netdev) +-{ +- struct fcoe_softc *fc; +- +- read_lock(&fcoe_hostlist_lock); +- list_for_each_entry(fc, &fcoe_hostlist, list) { +- if (fc->real_dev == netdev) { +- read_unlock(&fcoe_hostlist_lock); +- return fc; +- } +- } +- read_unlock(&fcoe_hostlist_lock); +- return NULL; +-} +- +-/* +- * Convert 48-bit IEEE MAC address to 64-bit FC WWN. +- */ +-static u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], +- unsigned int scheme, unsigned int port) +-{ +- u64 wwn; +- u64 host_mac; +- +- /* The MAC is in NO, so flip only the low 48 bits */ +- host_mac = ((u64) mac[0] << 40) | +- ((u64) mac[1] << 32) | +- ((u64) mac[2] << 24) | +- ((u64) mac[3] << 16) | +- ((u64) mac[4] << 8) | +- (u64) mac[5]; +- +- WARN_ON(host_mac >= (1ULL << 48)); +- wwn = host_mac | ((u64) scheme << 60); +- switch (scheme) { +- case 1: +- WARN_ON(port != 0); +- break; +- case 2: +- WARN_ON(port >= 0xfff); +- wwn |= (u64) port << 48; +- break; +- default: +- WARN_ON(1); +- break; +- } +- +- return wwn; +-} +- +-static struct scsi_host_template fcoe_driver_template = { ++static struct scsi_host_template fcoe_sw_shost_template = { + .module = THIS_MODULE, + .name = "FCoE Driver", +- .proc_name = FCOE_DRIVER_NAME, ++ .proc_name = FCOE_SW_NAME, + .queuecommand = fc_queuecommand, + .eh_abort_handler = fc_eh_abort, + .eh_device_reset_handler = fc_eh_device_reset, +@@ -170,138 +104,18 @@ static struct scsi_host_template fcoe_driver_template = { + .max_sectors = 0xffff, + }; + +-int fcoe_destroy_interface(struct net_device *netdev) +-{ +- int cpu, idx; +- struct fcoe_percpu_s *pp; +- struct fcoe_softc *fc; +- struct fcoe_rcv_info *fr; +- struct sk_buff_head *list; +- struct sk_buff *skb, *next; +- struct sk_buff *head; +- struct fc_lport *lp; +- u8 flogi_maddr[ETH_ALEN]; +- +- fc = fcoe_find_fc_lport(netdev); +- if (!fc) +- return -ENODEV; +- +- lp = fc->lp; +- +- /* Remove the instance from fcoe's list */ +- write_lock_bh(&fcoe_hostlist_lock); +- list_del(&fc->list); +- write_unlock_bh(&fcoe_hostlist_lock); +- +- /* Don't listen for Ethernet packets anymore */ +- dev_remove_pack(&fc->fcoe_packet_type); +- +- /* Detach from the scsi-ml */ +- fc_remove_host(lp->host); +- scsi_remove_host(lp->host); +- +- /* Cleanup the fc_lport */ +- fc_lport_destroy(lp); +- fc_fcp_destroy(lp); +- if (lp->emp) +- fc_exch_mgr_free(lp->emp); +- +- /* Delete secondary MAC addresses */ +- rtnl_lock(); +- memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); +- dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); +- if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) +- dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); +- rtnl_unlock(); +- +- /* Free the per-CPU revieve threads */ +- for (idx = 0; idx < NR_CPUS; idx++) { +- if (fcoe_percpu[idx]) { +- pp = fcoe_percpu[idx]; +- spin_lock_bh(&pp->fcoe_rx_list.lock); +- list = &pp->fcoe_rx_list; +- head = list->next; +- for (skb = head; skb != (struct sk_buff *)list; +- skb = next) { +- next = skb->next; +- fr = fcoe_dev_from_skb(skb); +- if (fr->fr_dev == fc->lp) { +- __skb_unlink(skb, list); +- kfree_skb(skb); +- } +- } +- spin_unlock_bh(&pp->fcoe_rx_list.lock); +- } +- } +- +- /* Free existing skbs */ +- fcoe_clean_pending_queue(lp); +- +- /* Free memory used by statistical counters */ +- for_each_online_cpu(cpu) +- kfree(lp->dev_stats[cpu]); +- +- /* Release the net_device and Scsi_Host */ +- dev_put(fc->real_dev); +- scsi_host_put(lp->host); +- return 0; +-} +- + /* +- * Return zero if link is OK for use by FCoE. +- * Any permanently-disqualifying conditions have been previously checked. +- * This also updates the speed setting, which may change with link for 100/1000. ++ * fcoe_sw_lport_config - sets up the fc_lport ++ * @lp: ptr to the fc_lport ++ * @shost: ptr to the parent scsi host ++ * ++ * Returns: 0 for success + * +- * This function should probably be checking for PAUSE support at some point +- * in the future. Currently Per-priority-pause is not determinable using +- * ethtool, so we shouldn't be restrictive until that problem is resolved. + */ +-int fcoe_link_ok(struct fc_lport *lp) +-{ +- struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; +- struct net_device *dev = fc->real_dev; +- struct ethtool_cmd ecmd = { ETHTOOL_GSET }; +- int rc = 0; +- +- if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { +- dev = fc->phys_dev; +- if (dev->ethtool_ops->get_settings) { +- dev->ethtool_ops->get_settings(dev, &ecmd); +- lp->link_supported_speeds &= +- ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); +- if (ecmd.supported & (SUPPORTED_1000baseT_Half | +- SUPPORTED_1000baseT_Full)) +- lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; +- if (ecmd.supported & SUPPORTED_10000baseT_Full) +- lp->link_supported_speeds |= +- FC_PORTSPEED_10GBIT; +- if (ecmd.speed == SPEED_1000) +- lp->link_speed = FC_PORTSPEED_1GBIT; +- if (ecmd.speed == SPEED_10000) +- lp->link_speed = FC_PORTSPEED_10GBIT; +- } +- } else +- rc = -1; +- +- return rc; +-} +- +-static struct libfc_function_template fcoe_libfc_fcn_templ = { +- .frame_send = fcoe_xmit, +-}; +- +-static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) ++static int fcoe_sw_lport_config(struct fc_lport *lp) + { + int i = 0; + +- lp->host = shost; +- lp->drv_priv = (void *)(lp + 1); +- +- lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, +- FCOE_MIN_XID, FCOE_MAX_XID); +- if (!lp->emp) +- return -ENOMEM; +- + lp->link_status = 0; + lp->max_retry_count = 3; + lp->e_d_tov = 2 * 1000; /* FC-FS default */ +@@ -316,25 +130,39 @@ static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) + lp->dev_stats[i] = kzalloc(sizeof(struct fcoe_dev_stats), + GFP_KERNEL); + +- /* Finish fc_lport configuration */ ++ /* lport fc_lport related configuration */ + fc_lport_config(lp); + + return 0; + } + +-static int net_config(struct fc_lport *lp) ++/* ++ * fcoe_sw_netdev_config - sets up fcoe_softc for lport and network ++ * related properties ++ * @lp : ptr to the fc_lport ++ * @netdev : ptr to the associated netdevice struct ++ * ++ * Must be called after fcoe_sw_lport_config() as it will use lport mutex ++ * ++ * Returns : 0 for success ++ * ++ */ ++static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev) + { + u32 mfs; + u64 wwnn, wwpn; +- struct net_device *net_dev; +- struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; ++ struct fcoe_softc *fc; + u8 flogi_maddr[ETH_ALEN]; + ++ /* Setup lport private data to point to fcoe softc */ ++ fc = lport_priv(lp); ++ fc->lp = lp; ++ fc->real_dev = netdev; ++ fc->phys_dev = netdev; ++ + /* Require support for get_pauseparam ethtool op. */ +- net_dev = fc->real_dev; +- if (net_dev->priv_flags & IFF_802_1Q_VLAN) +- net_dev = vlan_dev_real_dev(net_dev); +- fc->phys_dev = net_dev; ++ if (netdev->priv_flags & IFF_802_1Q_VLAN) ++ fc->phys_dev = vlan_dev_real_dev(netdev); + + /* Do not support for bonding device */ + if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || +@@ -356,6 +184,7 @@ static int net_config(struct fc_lport *lp) + if (!fcoe_link_ok(lp)) + lp->link_status |= FC_LINK_UP; + ++ /* offload features support */ + if (fc->real_dev->features & NETIF_F_SG) + lp->sg_supp = 1; + +@@ -394,96 +223,210 @@ static int net_config(struct fc_lport *lp) + return 0; + } + +-static void shost_config(struct fc_lport *lp) ++/* ++ * fcoe_sw_shost_config - sets up fc_lport->host ++ * @lp : ptr to the fc_lport ++ * @shost : ptr to the associated scsi host ++ * @dev : device associated to scsi host ++ * ++ * Must be called after fcoe_sw_lport_config) and fcoe_sw_netdev_config() ++ * ++ * Returns : 0 for success ++ * ++ */ ++static int fcoe_sw_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, ++ struct device *dev) + { ++ int rc = 0; ++ ++ /* lport scsi host config */ ++ lp->host = shost; ++ + lp->host->max_lun = FCOE_MAX_LUN; + lp->host->max_id = FCOE_MAX_FCP_TARGET; + lp->host->max_channel = 0; +- lp->host->transportt = fcoe_transport_template; ++ lp->host->transportt = scsi_transport_fcoe_sw; ++ ++ /* add the new host to the SCSI-ml */ ++ rc = scsi_add_host(lp->host, dev); ++ if (rc) { ++ FC_DBG("fcoe_sw_shost_config:error on scsi_add_host\n"); ++ return rc; ++ } ++ sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", ++ FCOE_SW_NAME, FCOE_SW_VERSION, ++ fcoe_netdev(lp)->name); ++ ++ return 0; + } + +-static int libfc_config(struct fc_lport *lp) ++/* ++ * fcoe_sw_em_config - allocates em for this lport ++ * @lp: the port that em is to allocated for ++ * ++ * Returns : 0 on success ++ */ ++static inline int fcoe_sw_em_config(struct fc_lport *lp) + { +- /* Set the function pointers set by the LLDD */ +- memcpy(&lp->tt, &fcoe_libfc_fcn_templ, +- sizeof(struct libfc_function_template)); ++ BUG_ON(lp->emp); + +- if (fc_fcp_init(lp)) ++ lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, ++ FCOE_MIN_XID, FCOE_MAX_XID); ++ if (!lp->emp) + return -ENOMEM; +- fc_exch_init(lp); +- fc_lport_init(lp); +- fc_rport_init(lp); +- fc_disc_init(lp); + + return 0; + } + + /* +- * This function creates the fcoe interface +- * create struct fcdev which is a shared structure between opefc +- * and transport level protocol. ++ * fcoe_sw_destroy - FCoE software HBA tear-down function ++ * @netdev: ptr to the associated net_device ++ * ++ * Returns: 0 if link is OK for use by FCoE. + */ +-int fcoe_create_interface(struct net_device *netdev) ++static int fcoe_sw_destroy(struct net_device *netdev) + { ++ int cpu; ++ struct fc_lport *lp = NULL; ++ struct fcoe_softc *fc; ++ u8 flogi_maddr[ETH_ALEN]; ++ ++ BUG_ON(!netdev); ++ ++ printk(KERN_DEBUG "fcoe_sw_destroy:interface on %s\n", ++ netdev->name); ++ ++ lp = fcoe_hostlist_lookup(netdev); ++ if (!lp) ++ return -ENODEV; ++ ++ fc = fcoe_softc(lp); ++ ++ /* Remove the instance from fcoe's list */ ++ fcoe_hostlist_remove(lp); ++ ++ /* Don't listen for Ethernet packets anymore */ ++ dev_remove_pack(&fc->fcoe_packet_type); ++ ++ /* Cleanup the fc_lport */ ++ fc_lport_destroy(lp); ++ fc_fcp_destroy(lp); ++ ++ /* Detach from the scsi-ml */ ++ fc_remove_host(lp->host); ++ scsi_remove_host(lp->host); ++ ++ /* There are no more rports or I/O, free the EM */ ++ if (lp->emp) ++ fc_exch_mgr_free(lp->emp); ++ ++ /* Delete secondary MAC addresses */ ++ rtnl_lock(); ++ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); ++ dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); ++ if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) ++ dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ /* Free the per-CPU revieve threads */ ++ fcoe_percpu_clean(lp); ++ ++ /* Free existing skbs */ ++ fcoe_clean_pending_queue(lp); ++ ++ /* Free memory used by statistical counters */ ++ for_each_online_cpu(cpu) ++ kfree(lp->dev_stats[cpu]); ++ ++ /* Release the net_device and Scsi_Host */ ++ dev_put(fc->real_dev); ++ scsi_host_put(lp->host); ++ ++ return 0; ++} ++ ++static struct libfc_function_template fcoe_sw_libfc_fcn_templ = { ++ .frame_send = fcoe_xmit, ++}; ++ ++/* ++ * fcoe_sw_create - this function creates the fcoe interface ++ * @netdev: pointer the associated netdevice ++ * ++ * Creates fc_lport struct and scsi_host for lport, configures lport ++ * and starts fabric login. ++ * ++ * Returns : 0 on success ++ */ ++static int fcoe_sw_create(struct net_device *netdev) ++{ ++ int rc; + struct fc_lport *lp = NULL; + struct fcoe_softc *fc; + struct Scsi_Host *shost; +- int rc = 0; + +- if (fcoe_find_fc_lport(netdev) != NULL) ++ BUG_ON(!netdev); ++ ++ printk(KERN_DEBUG "fcoe_sw_create:interface on %s\n", ++ netdev->name); ++ ++ lp = fcoe_hostlist_lookup(netdev); ++ if (lp) + return -EEXIST; + +- shost = scsi_host_alloc(&fcoe_driver_template, +- sizeof(struct fc_lport) + ++ shost = fcoe_host_alloc(&fcoe_sw_shost_template, + sizeof(struct fcoe_softc)); +- + if (!shost) { + FC_DBG("Could not allocate host structure\n"); + return -ENOMEM; + } +- + lp = shost_priv(shost); +- rc = lport_config(lp, shost); +- if (rc) +- goto out_host_put; +- +- /* Configure the fcoe_softc */ +- fc = (struct fcoe_softc *)lp->drv_priv; +- fc->lp = lp; +- fc->real_dev = netdev; +- shost_config(lp); ++ fc = lport_priv(lp); + ++ /* configure fc_lport, e.g., em */ ++ rc = fcoe_sw_lport_config(lp); ++ if (rc) { ++ FC_DBG("Could not configure lport\n"); ++ goto out_host_put; ++ } + +- /* Add the new host to the SCSI-ml */ +- rc = scsi_add_host(lp->host, NULL); ++ /* configure lport network properties */ ++ rc = fcoe_sw_netdev_config(lp, netdev); + if (rc) { +- FC_DBG("error on scsi_add_host\n"); +- goto out_lp_destroy; ++ FC_DBG("Could not configure netdev for lport\n"); ++ goto out_host_put; + } + +- sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", +- FCOE_DRIVER_NAME, FCOE_VERSION, +- netdev->name); ++ /* configure lport scsi host properties */ ++ rc = fcoe_sw_shost_config(lp, shost, &netdev->dev); ++ if (rc) { ++ FC_DBG("Could not configure shost for lport\n"); ++ goto out_host_put; ++ } + +- /* Configure netdev and networking properties of the lp */ +- rc = net_config(lp); +- if (rc) +- goto out_lp_destroy; ++ /* lport exch manager allocation */ ++ rc = fcoe_sw_em_config(lp); ++ if (rc) { ++ FC_DBG("Could not configure em for lport\n"); ++ goto out_host_put; ++ } + + /* Initialize the library */ +- rc = libfc_config(lp); +- if (rc) ++ rc = fcoe_libfc_config(lp, &fcoe_sw_libfc_fcn_templ); ++ if (rc) { ++ FC_DBG("Could not configure libfc for lport!\n"); + goto out_lp_destroy; ++ } + +- write_lock_bh(&fcoe_hostlist_lock); +- list_add_tail(&fc->list, &fcoe_hostlist); +- write_unlock_bh(&fcoe_hostlist_lock); ++ /* add to lports list */ ++ fcoe_hostlist_add(lp); + + lp->boot_time = jiffies; + + fc_fabric_login(lp); + + dev_hold(netdev); ++ + return rc; + + out_lp_destroy: +@@ -493,28 +436,55 @@ out_host_put: + return rc; + } + +-void fcoe_clean_pending_queue(struct fc_lport *lp) ++/* ++ * fcoe_sw_match - the fcoe sw transport match function ++ * ++ * Returns : false always ++ */ ++static bool fcoe_sw_match(struct net_device *netdev) + { +- struct fcoe_softc *fc = lp->drv_priv; +- struct sk_buff *skb; +- +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); +- kfree_skb(skb); +- spin_lock_bh(&fc->fcoe_pending_queue.lock); +- } +- spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ /* FIXME - for sw transport, always return false */ ++ return false; + } + ++/* the sw hba fcoe transport */ ++struct fcoe_transport fcoe_sw_transport = { ++ .name = "fcoesw", ++ .create = fcoe_sw_create, ++ .destroy = fcoe_sw_destroy, ++ .match = fcoe_sw_match, ++ .vendor = 0x0, ++ .device = 0xffff, ++}; ++ ++/* ++ * fcoe_sw_init - registers fcoe_sw_transport ++ * ++ * Returns : 0 on success ++ */ + int __init fcoe_sw_init(void) + { +- fcoe_transport_template = +- fc_attach_transport(&fcoe_transport_function); +- return fcoe_transport_template ? 0 : -1; ++ /* attach to scsi transport */ ++ scsi_transport_fcoe_sw = ++ fc_attach_transport(&fcoe_sw_transport_function); ++ if (!scsi_transport_fcoe_sw) { ++ printk(KERN_ERR "fcoe_sw_init:fc_attach_transport() failed\n"); ++ return -ENODEV; ++ } ++ /* register sw transport */ ++ fcoe_transport_register(&fcoe_sw_transport); ++ return 0; + } + +-void __exit fcoe_sw_exit(void) ++/* ++ * fcoe_sw_exit - unregisters fcoe_sw_transport ++ * ++ * Returns : 0 on success ++ */ ++int __exit fcoe_sw_exit(void) + { +- fc_release_transport(fcoe_transport_template); ++ /* dettach the transport */ ++ fc_release_transport(scsi_transport_fcoe_sw); ++ fcoe_transport_unregister(&fcoe_sw_transport); ++ return 0; + } +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +index 45a7d6f..de29ccd 100644 +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -17,10 +17,6 @@ + * Maintained at www.Open-FCoE.org + */ + +-/* +- * FCOE protocol file +- */ +- + #include + #include + #include +@@ -28,9 +24,15 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -39,11 +41,10 @@ + + #include + +-#include +-#include +- +-#include +-#include "fcoe_def.h" ++#include ++#include ++#include ++#include + + static int debug_fcoe; + +@@ -53,18 +54,129 @@ static int debug_fcoe; + #define FCOE_GW_ADDR_MODE 0x00 + #define FCOE_FCOUI_ADDR_MODE 0x01 + ++#define FCOE_WORD_TO_BYTE 4 ++ ++MODULE_AUTHOR("Open-FCoE.org"); ++MODULE_DESCRIPTION("FCoE"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0.4"); ++ ++/* fcoe host list */ ++LIST_HEAD(fcoe_hostlist); ++DEFINE_RWLOCK(fcoe_hostlist_lock); ++DEFINE_TIMER(fcoe_timer, NULL, 0, 0); ++struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; ++ ++ + /* Function Prototyes */ + static int fcoe_check_wait_queue(struct fc_lport *); + static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *); + static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *); + static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); ++#ifdef CONFIG_HOTPLUG_CPU ++static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); ++#endif /* CONFIG_HOTPLUG_CPU */ ++static int fcoe_device_notification(struct notifier_block *, ulong, void *); ++static void fcoe_dev_setup(void); ++static void fcoe_dev_cleanup(void); ++ ++/* notification function from net device */ ++static struct notifier_block fcoe_notifier = { ++ .notifier_call = fcoe_device_notification, ++}; ++ ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static struct notifier_block fcoe_cpu_notifier = { ++ .notifier_call = fcoe_cpu_callback, ++}; ++ ++/** ++ * fcoe_create_percpu_data - creates the associated cpu data ++ * @cpu: index for the cpu where fcoe cpu data will be created ++ * ++ * create percpu stats block, from cpu add notifier ++ * ++ * Returns: none ++ **/ ++static void fcoe_create_percpu_data(int cpu) ++{ ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; + +-/* +- * this is the fcoe receive function +- * called by NET_RX_SOFTIRQ +- * this function will receive the packet and +- * build fc frame and pass it up +- */ ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ lp = fc->lp; ++ if (lp->dev_stats[cpu] == NULL) ++ lp->dev_stats[cpu] = ++ kzalloc(sizeof(struct fcoe_dev_stats), ++ GFP_KERNEL); ++ } ++ write_unlock_bh(&fcoe_hostlist_lock); ++} ++ ++/** ++ * fcoe_destroy_percpu_data - destroys the associated cpu data ++ * @cpu: index for the cpu where fcoe cpu data will destroyed ++ * ++ * destroy percpu stats block called by cpu add/remove notifier ++ * ++ * Retuns: none ++ **/ ++static void fcoe_destroy_percpu_data(int cpu) ++{ ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ lp = fc->lp; ++ kfree(lp->dev_stats[cpu]); ++ lp->dev_stats[cpu] = NULL; ++ } ++ write_unlock_bh(&fcoe_hostlist_lock); ++} ++ ++/** ++ * fcoe_cpu_callback - fcoe cpu hotplug event callback ++ * @nfb: callback data block ++ * @action: event triggering the callback ++ * @hcpu: index for the cpu of this event ++ * ++ * this creates or destroys per cpu data for fcoe ++ * ++ * Returns NOTIFY_OK always. ++ **/ ++static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action, ++ void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ fcoe_create_percpu_data(cpu); ++ break; ++ case CPU_DEAD: ++ fcoe_destroy_percpu_data(cpu); ++ break; ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/** ++ * foce_rcv - this is the fcoe receive function called by NET_RX_SOFTIRQ ++ * @skb: the receive skb ++ * @dev: associated net device ++ * @ptype: context ++ * @odldev: last device ++ * ++ * this function will receive the packet and build fc frame and pass it up ++ * ++ * Returns: 0 for success ++ **/ + int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, struct net_device *olddev) + { +@@ -142,7 +254,14 @@ err2: + kfree_skb(skb); + return -1; + } ++EXPORT_SYMBOL_GPL(fcoe_rcv); + ++/** ++ * fcoe_start_io - pass to netdev to start xmit for fcoe ++ * @skb: the skb to be xmitted ++ * ++ * Returns: 0 for success ++ **/ + static inline int fcoe_start_io(struct sk_buff *skb) + { + int rc; +@@ -155,6 +274,13 @@ static inline int fcoe_start_io(struct sk_buff *skb) + return 0; + } + ++/** ++ * fcoe_get_paged_crc_eof - in case we need alloc a page for crc_eof ++ * @skb: the skb to be xmitted ++ * @tlen: total len ++ * ++ * Returns: 0 for success ++ **/ + static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) + { + struct fcoe_percpu_s *fps; +@@ -191,12 +317,53 @@ static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) + return 0; + } + +-/* +- * this is the frame xmit routine +- */ ++/** ++ * fcoe_fc_crc - calculates FC CRC in this fcoe skb ++ * @fp: the fc_frame containg data to be checksummed ++ * ++ * This uses crc32() to calculate the crc for fc frame ++ * Return : 32 bit crc ++ * ++ **/ ++u32 fcoe_fc_crc(struct fc_frame *fp) ++{ ++ struct sk_buff *skb = fp_skb(fp); ++ struct skb_frag_struct *frag; ++ unsigned char *data; ++ unsigned long off, len, clen; ++ u32 crc; ++ unsigned i; ++ ++ crc = crc32(~0, skb->data, skb_headlen(skb)); ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ frag = &skb_shinfo(skb)->frags[i]; ++ off = frag->page_offset; ++ len = frag->size; ++ while (len > 0) { ++ clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); ++ data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), ++ KM_SKB_DATA_SOFTIRQ); ++ crc = crc32(crc, data + (off & ~PAGE_MASK), clen); ++ kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); ++ off += clen; ++ len -= clen; ++ } ++ } ++ return crc; ++} ++EXPORT_SYMBOL_GPL(fcoe_fc_crc); ++ ++/** ++ * fcoe_xmit - FCoE frame transmit function ++ * @lp: the associated local port ++ * @fp: the fc_frame to be transmitted ++ * ++ * Return : 0 for success ++ * ++ **/ + int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + { +- int indx; + int wlen, rc = 0; + u32 crc; + struct ethhdr *eh; +@@ -206,15 +373,15 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + struct fc_frame_header *fh; + unsigned int hlen; /* header length implies the version */ + unsigned int tlen; /* trailer length */ ++ unsigned int elen; /* eth header, may include vlan */ + int flogi_in_progress = 0; + struct fcoe_softc *fc; +- void *data; + u8 sof, eof; + struct fcoe_hdr *hp; + + WARN_ON((fr_len(fp) % sizeof(u32)) != 0); + +- fc = (struct fcoe_softc *)lp->drv_priv; ++ fc = fcoe_softc(lp); + /* + * if it is a flogi then we need to learn gw-addr + * and my own fcid +@@ -243,45 +410,24 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + sof = fr_sof(fp); + eof = fr_eof(fp); + +- crc = ~0; +- crc = crc32(crc, skb->data, skb_headlen(skb)); +- +- for (indx = 0; indx < skb_shinfo(skb)->nr_frags; indx++) { +- skb_frag_t *frag = &skb_shinfo(skb)->frags[indx]; +- unsigned long off = frag->page_offset; +- unsigned long len = frag->size; +- +- while (len > 0) { +- unsigned long clen; +- +- clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); +- data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), +- KM_SKB_DATA_SOFTIRQ); +- crc = crc32(crc, data + (off & ~PAGE_MASK), +- clen); +- kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); +- off += clen; +- len -= clen; +- } +- } +- +- /* +- * Get header and trailer lengths. +- * This is temporary code until we get rid of the old protocol. +- * Both versions have essentially the same trailer layout but T11 +- * has padding afterwards. +- */ ++ elen = (fc->real_dev->priv_flags & IFF_802_1Q_VLAN) ? ++ sizeof(struct vlan_ethhdr) : sizeof(struct ethhdr); + hlen = sizeof(struct fcoe_hdr); + tlen = sizeof(struct fcoe_crc_eof); ++ wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; + +- /* +- * copy fc crc and eof to the skb buff +- * Use utility buffer in the fc_frame part of the sk_buff for the +- * trailer. +- * We don't do a get_page for this frag, since that page may not be +- * managed that way. So that skb_free() doesn't do that either, we +- * setup the destructor to remove this frag. +- */ ++ /* crc offload */ ++ if (likely(lp->crc_offload)) { ++ skb->ip_summed = CHECKSUM_COMPLETE; ++ skb->csum_start = skb_headroom(skb); ++ skb->csum_offset = skb->len; ++ crc = 0; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++ crc = fcoe_fc_crc(fp); ++ } ++ ++ /* copy fc crc and eof to the skb buff */ + if (skb_is_nonlinear(skb)) { + skb_frag_t *frag; + if (fcoe_get_paged_crc_eof(skb, tlen)) { +@@ -295,22 +441,27 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); + } + ++ memset(cp, 0, sizeof(*cp)); + cp->fcoe_eof = eof; + cp->fcoe_crc32 = cpu_to_le32(~crc); +- if (tlen == sizeof(*cp)) +- memset(cp->fcoe_resvd, 0, sizeof(cp->fcoe_resvd)); +- wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; + + if (skb_is_nonlinear(skb)) { + kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); + cp = NULL; + } + +- /* +- * Fill in the control structures +- */ +- skb->ip_summed = CHECKSUM_NONE; +- eh = (struct ethhdr *)skb_push(skb, hlen + sizeof(struct ethhdr)); ++ /* adjust skb netowrk/transport offsets to match mac/fcoe/fc */ ++ skb_push(skb, elen + hlen); ++ skb_reset_mac_header(skb); ++ skb_set_network_header(skb, elen); ++ skb_set_transport_header(skb, elen + hlen); ++ skb->mac_len = elen; ++ skb->protocol = htons(ETH_P_FCOE); ++ skb->dev = fc->real_dev; ++ ++ /* fill up mac and fcoe headers */ ++ eh = eth_hdr(skb); ++ eh->h_proto = htons(ETH_P_FCOE); + if (fc->address_mode == FCOE_FCOUI_ADDR_MODE) + fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); + else +@@ -322,24 +473,20 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + else + memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); + +- eh->h_proto = htons(ETH_P_FCOE); +- skb->protocol = htons(ETH_P_802_3); +- skb_reset_mac_header(skb); +- skb_reset_network_header(skb); +- +- hp = (struct fcoe_hdr *)(eh + 1); ++ hp = (struct fcoe_hdr *)skb_network_header(skb); + memset(hp, 0, sizeof(*hp)); + if (FC_FCOE_VER) + FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); + hp->fcoe_sof = sof; + ++ /* update tx stats: regardless if LLD fails */ + stats = lp->dev_stats[smp_processor_id()]; + if (stats) { + stats->TxFrames++; + stats->TxWords += wlen; + } +- skb->dev = fc->real_dev; + ++ /* send down to lld */ + fr_dev(fp) = lp; + if (fc->fcoe_pending_queue.qlen) + rc = fcoe_check_wait_queue(lp); +@@ -355,7 +502,15 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + + return 0; + } ++EXPORT_SYMBOL_GPL(fcoe_xmit); + ++/* ++ * fcoe_percpu_receive_thread - recv thread per cpu ++ * @arg: ptr to the fcoe per cpu struct ++ * ++ * Return: 0 for success ++ * ++ */ + int fcoe_percpu_receive_thread(void *arg) + { + struct fcoe_percpu_s *p = arg; +@@ -368,7 +523,6 @@ int fcoe_percpu_receive_thread(void *arg) + struct fc_frame_header *fh; + struct sk_buff *skb; + struct fcoe_crc_eof *cp; +- enum fc_sof sof; + struct fc_frame *fp; + u8 *mac = NULL; + struct fcoe_softc *fc; +@@ -411,7 +565,7 @@ int fcoe_percpu_receive_thread(void *arg) + /* + * Save source MAC address before discarding header. + */ +- fc = lp->drv_priv; ++ fc = lport_priv(lp); + if (unlikely(fc->flogi_progress)) + mac = eth_hdr(skb)->h_source; + +@@ -422,7 +576,6 @@ int fcoe_percpu_receive_thread(void *arg) + * Check the header and pull it off. + */ + hlen = sizeof(struct fcoe_hdr); +- + hp = (struct fcoe_hdr *)skb->data; + if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { + if (stats) { +@@ -434,11 +587,10 @@ int fcoe_percpu_receive_thread(void *arg) + kfree_skb(skb); + continue; + } +- sof = hp->fcoe_sof; +- skb_pull(skb, sizeof(*hp)); +- fr_len = skb->len - sizeof(struct fcoe_crc_eof); +- skb_trim(skb, fr_len); ++ skb_pull(skb, sizeof(struct fcoe_hdr)); + tlen = sizeof(struct fcoe_crc_eof); ++ fr_len = skb->len - tlen; ++ skb_trim(skb, fr_len); + + if (unlikely(fr_len > skb->len)) { + if (stats) { +@@ -456,47 +608,61 @@ int fcoe_percpu_receive_thread(void *arg) + stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; + } + +- fp = (struct fc_frame *) skb; +- fc_frame_init(fp); ++ fp = (struct fc_frame *)skb; + cp = (struct fcoe_crc_eof *)(skb->data + fr_len); ++ fc_frame_init(fp); + fr_eof(fp) = cp->fcoe_eof; +- fr_sof(fp) = sof; ++ fr_sof(fp) = hp->fcoe_sof; + fr_dev(fp) = lp; + + /* +- * Check the CRC here, unless it's solicited data for SCSI. +- * In that case, the SCSI layer can check it during the copy, +- * and it'll be more cache-efficient. ++ * We only check CRC if no offload is available and if it is ++ * it's solicited data, in which case, the FCP layer would ++ * check it during the copy. + */ ++ if (lp->crc_offload) ++ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; ++ else ++ fr_flags(fp) |= FCPHF_CRC_UNCHECKED; ++ + fh = fc_frame_header_get(fp); + if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && + fh->fh_type == FC_TYPE_FCP) { +- fr_flags(fp) |= FCPHF_CRC_UNCHECKED; + fc_exch_recv(lp, lp->emp, fp); +- } else if (le32_to_cpu(cp->fcoe_crc32) == +- ~crc32(~0, skb->data, fr_len)) { +- if (unlikely(fc->flogi_progress)) +- fcoe_recv_flogi(fc, fp, mac); +- fc_exch_recv(lp, lp->emp, fp); +- } else { +- if (debug_fcoe || +- (stats && stats->InvalidCRCCount < 5)) { +- printk(KERN_WARNING \ +- "fcoe: dropping frame with CRC error"); +- } +- if (stats) { ++ continue; ++ } ++ if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { ++ if (le32_to_cpu(cp->fcoe_crc32) != ++ ~crc32(~0, skb->data, fr_len)) { ++ if (debug_fcoe || stats->InvalidCRCCount < 5) ++ printk(KERN_WARNING "fcoe: dropping " ++ "frame with CRC error\n"); + stats->InvalidCRCCount++; + stats->ErrorFrames++; ++ fc_frame_free(fp); ++ continue; + } +- fc_frame_free(fp); ++ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; + } ++ /* non flogi and non data exchanges are handled here */ ++ if (unlikely(fc->flogi_progress)) ++ fcoe_recv_flogi(fc, fp, mac); ++ fc_exch_recv(lp, lp->emp, fp); + } + return 0; + } + +-/* +- * Snoop potential response to FLOGI or even incoming FLOGI. +- */ ++/** ++ * fcoe_recv_flogi - flogi receive function ++ * @fc: associated fcoe_softc ++ * @fp: the recieved frame ++ * @sa: the source address of this flogi ++ * ++ * This is responsible to parse the flogi response and sets the corresponding ++ * mac address for the initiator, eitehr OUI based or GW based. ++ * ++ * Returns: none ++ **/ + static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) + { + struct fc_frame_header *fh; +@@ -543,6 +709,16 @@ static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) + } + } + ++/** ++ * fcoe_watchdog - fcoe timer callback ++ * @vp: ++ * ++ * This checks the pending queue length for fcoe and put fcoe to be paused state ++ * if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the ++ * fcoe_hostlist. ++ * ++ * Returns: 0 for success ++ **/ + void fcoe_watchdog(ulong vp) + { + struct fc_lport *lp; +@@ -567,27 +743,23 @@ void fcoe_watchdog(ulong vp) + add_timer(&fcoe_timer); + } + +-/* +- * the wait_queue is used when the skb transmit fails. skb will go +- * in the wait_queue which will be emptied by the time function OR +- * by the next skb transmit. +- * +- */ + +-/* +- * Function name : fcoe_check_wait_queue() ++/** ++ * fcoe_check_wait_queue - put the skb into fcoe pending xmit queue ++ * @lp: the fc_port for this skb ++ * @skb: the associated skb to be xmitted + * +- * Return Values : 0 or error ++ * This empties the wait_queue, dequeue the head of the wait_queue queue ++ * and calls fcoe_start_io() for each packet, if all skb have been ++ * transmitted, return 0 if a error occurs, then restore wait_queue and ++ * try again later. + * +- * Description : empties the wait_queue +- * dequeue the head of the wait_queue queue and +- * calls fcoe_start_io() for each packet +- * if all skb have been transmitted, return 0 +- * if a error occurs, then restore wait_queue and try again +- * later ++ * The wait_queue is used when the skb transmit fails. skb will go ++ * in the wait_queue which will be emptied by the time function OR ++ * by the next skb transmit. + * +- */ +- ++ * Returns: 0 for success ++ **/ + static int fcoe_check_wait_queue(struct fc_lport *lp) + { + int rc, unpause = 0; +@@ -595,7 +767,7 @@ static int fcoe_check_wait_queue(struct fc_lport *lp) + struct sk_buff *skb; + struct fcoe_softc *fc; + +- fc = (struct fcoe_softc *)lp->drv_priv; ++ fc = fcoe_softc(lp); + spin_lock_bh(&fc->fcoe_pending_queue.lock); + + /* +@@ -622,24 +794,714 @@ static int fcoe_check_wait_queue(struct fc_lport *lp) + return fc->fcoe_pending_queue.qlen; + } + ++/** ++ * fcoe_insert_wait_queue_head - puts skb to fcoe pending queue head ++ * @lp: the fc_port for this skb ++ * @skb: the associated skb to be xmitted ++ * ++ * Returns: none ++ **/ + static void fcoe_insert_wait_queue_head(struct fc_lport *lp, + struct sk_buff *skb) + { + struct fcoe_softc *fc; + +- fc = (struct fcoe_softc *)lp->drv_priv; ++ fc = fcoe_softc(lp); + spin_lock_bh(&fc->fcoe_pending_queue.lock); + __skb_queue_head(&fc->fcoe_pending_queue, skb); + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + } + ++/** ++ * fcoe_insert_wait_queue - put the skb into fcoe pending queue tail ++ * @lp: the fc_port for this skb ++ * @skb: the associated skb to be xmitted ++ * ++ * Returns: none ++ **/ + static void fcoe_insert_wait_queue(struct fc_lport *lp, + struct sk_buff *skb) + { + struct fcoe_softc *fc; + +- fc = (struct fcoe_softc *)lp->drv_priv; ++ fc = fcoe_softc(lp); + spin_lock_bh(&fc->fcoe_pending_queue.lock); + __skb_queue_tail(&fc->fcoe_pending_queue, skb); + spin_unlock_bh(&fc->fcoe_pending_queue.lock); + } ++ ++/** ++ * fcoe_dev_setup - setup link change notification interface ++ * ++ **/ ++static void fcoe_dev_setup(void) ++{ ++ /* ++ * here setup a interface specific wd time to ++ * monitor the link state ++ */ ++ register_netdevice_notifier(&fcoe_notifier); ++} ++ ++/** ++ * fcoe_dev_setup - cleanup link change notification interface ++ **/ ++static void fcoe_dev_cleanup(void) ++{ ++ unregister_netdevice_notifier(&fcoe_notifier); ++} ++ ++/** ++ * fcoe_device_notification - netdev event notification callback ++ * @notifier: context of the notification ++ * @event: type of event ++ * @ptr: fixed array for output parsed ifname ++ * ++ * This function is called by the ethernet driver in case of link change event ++ * ++ * Returns: 0 for success ++ **/ ++static int fcoe_device_notification(struct notifier_block *notifier, ++ ulong event, void *ptr) ++{ ++ struct fc_lport *lp = NULL; ++ struct net_device *real_dev = ptr; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *stats; ++ u16 new_status; ++ u32 mfs; ++ int rc = NOTIFY_OK; ++ ++ read_lock(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ if (fc->real_dev == real_dev) { ++ lp = fc->lp; ++ break; ++ } ++ } ++ read_unlock(&fcoe_hostlist_lock); ++ if (lp == NULL) { ++ rc = NOTIFY_DONE; ++ goto out; ++ } ++ ++ new_status = lp->link_status; ++ switch (event) { ++ case NETDEV_DOWN: ++ case NETDEV_GOING_DOWN: ++ new_status &= ~FC_LINK_UP; ++ break; ++ case NETDEV_UP: ++ case NETDEV_CHANGE: ++ new_status &= ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ new_status |= FC_LINK_UP; ++ break; ++ case NETDEV_CHANGEMTU: ++ mfs = fc->real_dev->mtu - ++ (sizeof(struct fcoe_hdr) + ++ sizeof(struct fcoe_crc_eof)); ++ if (fc->user_mfs && fc->user_mfs < mfs) ++ mfs = fc->user_mfs; ++ if (mfs >= FC_MIN_MAX_FRAME) ++ fc_set_mfs(lp, mfs); ++ new_status &= ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ new_status |= FC_LINK_UP; ++ break; ++ case NETDEV_REGISTER: ++ break; ++ default: ++ FC_DBG("unknown event %ld call", event); ++ } ++ if (lp->link_status != new_status) { ++ if ((new_status & FC_LINK_UP) == FC_LINK_UP) ++ fc_linkup(lp); ++ else { ++ stats = lp->dev_stats[smp_processor_id()]; ++ if (stats) ++ stats->LinkFailureCount++; ++ fc_linkdown(lp); ++ fcoe_clean_pending_queue(lp); ++ } ++ } ++out: ++ return rc; ++} ++ ++/** ++ * fcoe_if_to_netdev - parse a name buffer to get netdev ++ * @ifname: fixed array for output parsed ifname ++ * @buffer: incoming buffer to be copied ++ * ++ * Returns: NULL or ptr to netdeive ++ **/ ++static struct net_device *fcoe_if_to_netdev(const char *buffer) ++{ ++ char *cp; ++ char ifname[IFNAMSIZ + 2]; ++ ++ if (buffer) { ++ strlcpy(ifname, buffer, IFNAMSIZ); ++ cp = ifname + strlen(ifname); ++ while (--cp >= ifname && *cp == '\n') ++ *cp = '\0'; ++ return dev_get_by_name(&init_net, ifname); ++ } ++ return NULL; ++} ++ ++/** ++ * fcoe_netdev_to_module_owner - finds out the nic drive moddule of the netdev ++ * @netdev: the target netdev ++ * ++ * Returns: ptr to the struct module, NULL for failure ++ **/ ++static struct module *fcoe_netdev_to_module_owner( ++ const struct net_device *netdev) ++{ ++ struct device *dev; ++ ++ if (!netdev) ++ return NULL; ++ ++ dev = netdev->dev.parent; ++ if (!dev) ++ return NULL; ++ ++ if (!dev->driver) ++ return NULL; ++ ++ return dev->driver->owner; ++} ++ ++/** ++ * fcoe_ethdrv_get - holds the nic driver module by try_module_get() for ++ * the corresponding netdev. ++ * @netdev: the target netdev ++ * ++ * Returns: 0 for succsss ++ **/ ++static int fcoe_ethdrv_get(const struct net_device *netdev) ++{ ++ struct module *owner; ++ ++ owner = fcoe_netdev_to_module_owner(netdev); ++ if (owner) { ++ printk(KERN_DEBUG "foce:hold driver module %s for %s\n", ++ owner->name, netdev->name); ++ return try_module_get(owner); ++ } ++ return -ENODEV; ++} ++ ++/** ++ * fcoe_ethdrv_get - releases the nic driver module by module_put for ++ * the corresponding netdev. ++ * @netdev: the target netdev ++ * ++ * Returns: 0 for succsss ++ **/ ++static int fcoe_ethdrv_put(const struct net_device *netdev) ++{ ++ struct module *owner; ++ ++ owner = fcoe_netdev_to_module_owner(netdev); ++ if (owner) { ++ printk(KERN_DEBUG "foce:release driver module %s for %s\n", ++ owner->name, netdev->name); ++ module_put(owner); ++ return 0; ++ } ++ return -ENODEV; ++} ++ ++/** ++ * fcoe_destroy- handles the destroy from sysfs ++ * @buffer: expcted to be a eth if name ++ * @kp: associated kernel param ++ * ++ * Returns: 0 for success ++ **/ ++static int fcoe_destroy(const char *buffer, struct kernel_param *kp) ++{ ++ int rc; ++ struct net_device *netdev; ++ ++ netdev = fcoe_if_to_netdev(buffer); ++ if (!netdev) { ++ rc = -ENODEV; ++ goto out_nodev; ++ } ++ /* look for existing lport */ ++ if (!fcoe_hostlist_lookup(netdev)) { ++ rc = -ENODEV; ++ goto out_putdev; ++ } ++ /* pass to transport */ ++ rc = fcoe_transport_release(netdev); ++ if (rc) { ++ printk(KERN_ERR "fcoe: fcoe_transport_release(%s) failed\n", ++ netdev->name); ++ rc = -EIO; ++ goto out_putdev; ++ } ++ fcoe_ethdrv_put(netdev); ++ rc = 0; ++out_putdev: ++ dev_put(netdev); ++out_nodev: ++ return rc; ++} ++ ++/** ++ * fcoe_create - handles the create call from sysfs ++ * @buffer: expcted to be a eth if name ++ * @kp: associated kernel param ++ * ++ * Returns: 0 for success ++ **/ ++static int fcoe_create(const char *buffer, struct kernel_param *kp) ++{ ++ int rc; ++ struct net_device *netdev; ++ ++ netdev = fcoe_if_to_netdev(buffer); ++ if (!netdev) { ++ rc = -ENODEV; ++ goto out_nodev; ++ } ++ /* look for existing lport */ ++ if (fcoe_hostlist_lookup(netdev)) { ++ rc = -EEXIST; ++ goto out_putdev; ++ } ++ fcoe_ethdrv_get(netdev); ++ ++ /* pass to transport */ ++ rc = fcoe_transport_attach(netdev); ++ if (rc) { ++ printk(KERN_ERR "fcoe: fcoe_transport_attach(%s) failed\n", ++ netdev->name); ++ fcoe_ethdrv_put(netdev); ++ rc = -EIO; ++ goto out_putdev; ++ } ++ rc = 0; ++out_putdev: ++ dev_put(netdev); ++out_nodev: ++ return rc; ++} ++ ++module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); ++__MODULE_PARM_TYPE(create, "string"); ++MODULE_PARM_DESC(create, "Create fcoe port using net device passed in."); ++module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); ++__MODULE_PARM_TYPE(destroy, "string"); ++MODULE_PARM_DESC(destroy, "Destroy fcoe port"); ++ ++/* ++ * fcoe_link_ok - check if link is ok for the fc_lport ++ * @lp: ptr to the fc_lport ++ * ++ * Any permanently-disqualifying conditions have been previously checked. ++ * This also updates the speed setting, which may change with link for 100/1000. ++ * ++ * This function should probably be checking for PAUSE support at some point ++ * in the future. Currently Per-priority-pause is not determinable using ++ * ethtool, so we shouldn't be restrictive until that problem is resolved. ++ * ++ * Returns: 0 if link is OK for use by FCoE. ++ * ++ */ ++int fcoe_link_ok(struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc = fcoe_softc(lp); ++ struct net_device *dev = fc->real_dev; ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ int rc = 0; ++ ++ if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { ++ dev = fc->phys_dev; ++ if (dev->ethtool_ops->get_settings) { ++ dev->ethtool_ops->get_settings(dev, &ecmd); ++ lp->link_supported_speeds &= ++ ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); ++ if (ecmd.supported & (SUPPORTED_1000baseT_Half | ++ SUPPORTED_1000baseT_Full)) ++ lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; ++ if (ecmd.supported & SUPPORTED_10000baseT_Full) ++ lp->link_supported_speeds |= ++ FC_PORTSPEED_10GBIT; ++ if (ecmd.speed == SPEED_1000) ++ lp->link_speed = FC_PORTSPEED_1GBIT; ++ if (ecmd.speed == SPEED_10000) ++ lp->link_speed = FC_PORTSPEED_10GBIT; ++ } ++ } else ++ rc = -1; ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(fcoe_link_ok); ++ ++/* ++ * fcoe_percpu_clean - frees skb of the corresponding lport from the per ++ * cpu queue. ++ * @lp: the fc_lport ++ */ ++void fcoe_percpu_clean(struct fc_lport *lp) ++{ ++ int idx; ++ struct fcoe_percpu_s *pp; ++ struct fcoe_rcv_info *fr; ++ struct sk_buff_head *list; ++ struct sk_buff *skb, *next; ++ struct sk_buff *head; ++ ++ for (idx = 0; idx < NR_CPUS; idx++) { ++ if (fcoe_percpu[idx]) { ++ pp = fcoe_percpu[idx]; ++ spin_lock_bh(&pp->fcoe_rx_list.lock); ++ list = &pp->fcoe_rx_list; ++ head = list->next; ++ for (skb = head; skb != (struct sk_buff *)list; ++ skb = next) { ++ next = skb->next; ++ fr = fcoe_dev_from_skb(skb); ++ if (fr->fr_dev == lp) { ++ __skb_unlink(skb, list); ++ kfree_skb(skb); ++ } ++ } ++ spin_unlock_bh(&pp->fcoe_rx_list.lock); ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(fcoe_percpu_clean); ++ ++/** ++ * fcoe_clean_pending_queue - dequeue skb and free it ++ * @lp: the corresponding fc_lport ++ * ++ * Returns: none ++ **/ ++void fcoe_clean_pending_queue(struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc = lport_priv(lp); ++ struct sk_buff *skb; ++ ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ kfree_skb(skb); ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ } ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} ++EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); ++ ++/** ++ * libfc_host_alloc - allocate a Scsi_Host with room for the fc_lport ++ * @sht: ptr to the scsi host templ ++ * @priv_size: size of private data after fc_lport ++ * ++ * Returns: ptr to Scsi_Host ++ * TODO - to libfc? ++ */ ++static inline struct Scsi_Host *libfc_host_alloc( ++ struct scsi_host_template *sht, int priv_size) ++{ ++ return scsi_host_alloc(sht, sizeof(struct fc_lport) + priv_size); ++} ++ ++/** ++ * fcoe_host_alloc - allocate a Scsi_Host with room for the fcoe_softc ++ * @sht: ptr to the scsi host templ ++ * @priv_size: size of private data after fc_lport ++ * ++ * Returns: ptr to Scsi_Host ++ */ ++struct Scsi_Host *fcoe_host_alloc(struct scsi_host_template *sht, int priv_size) ++{ ++ return libfc_host_alloc(sht, sizeof(struct fcoe_softc) + priv_size); ++} ++EXPORT_SYMBOL_GPL(fcoe_host_alloc); ++ ++/* ++ * fcoe_reset - resets the fcoe ++ * @shost: shost the reset is from ++ * ++ * Returns: always 0 ++ */ ++int fcoe_reset(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lport = shost_priv(shost); ++ fc_lport_reset(lport); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(fcoe_reset); ++ ++/* ++ * fcoe_wwn_from_mac - converts 48-bit IEEE MAC address to 64-bit FC WWN. ++ * @mac: mac address ++ * @scheme: check port ++ * @port: port indicator for converting ++ * ++ * Returns: u64 fc world wide name ++ */ ++u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], ++ unsigned int scheme, unsigned int port) ++{ ++ u64 wwn; ++ u64 host_mac; ++ ++ /* The MAC is in NO, so flip only the low 48 bits */ ++ host_mac = ((u64) mac[0] << 40) | ++ ((u64) mac[1] << 32) | ++ ((u64) mac[2] << 24) | ++ ((u64) mac[3] << 16) | ++ ((u64) mac[4] << 8) | ++ (u64) mac[5]; ++ ++ WARN_ON(host_mac >= (1ULL << 48)); ++ wwn = host_mac | ((u64) scheme << 60); ++ switch (scheme) { ++ case 1: ++ WARN_ON(port != 0); ++ break; ++ case 2: ++ WARN_ON(port >= 0xfff); ++ wwn |= (u64) port << 48; ++ break; ++ default: ++ WARN_ON(1); ++ break; ++ } ++ ++ return wwn; ++} ++EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); ++/* ++ * fcoe_hostlist_lookup_softc - find the corresponding lport by a given device ++ * @device: this is currently ptr to net_device ++ * ++ * Returns: NULL or the located fcoe_softc ++ */ ++static struct fcoe_softc *fcoe_hostlist_lookup_softc( ++ const struct net_device *dev) ++{ ++ struct fcoe_softc *fc; ++ ++ read_lock(&fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fcoe_hostlist, list) { ++ if (fc->real_dev == dev) { ++ read_unlock(&fcoe_hostlist_lock); ++ return fc; ++ } ++ } ++ read_unlock(&fcoe_hostlist_lock); ++ return NULL; ++} ++ ++/* ++ * fcoe_hostlist_lookup - find the corresponding lport by netdev ++ * @netdev: ptr to net_device ++ * ++ * Returns: 0 for success ++ */ ++struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = fcoe_hostlist_lookup_softc(netdev); ++ ++ return (fc) ? fc->lp : NULL; ++} ++EXPORT_SYMBOL_GPL(fcoe_hostlist_lookup); ++ ++/* ++ * fcoe_hostlist_add - add a lport to lports list ++ * @lp: ptr to the fc_lport to badded ++ * ++ * Returns: 0 for success ++ */ ++int fcoe_hostlist_add(const struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); ++ if (!fc) { ++ fc = fcoe_softc(lp); ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_add_tail(&fc->list, &fcoe_hostlist); ++ write_unlock_bh(&fcoe_hostlist_lock); ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(fcoe_hostlist_add); ++ ++/* ++ * fcoe_hostlist_remove - remove a lport from lports list ++ * @lp: ptr to the fc_lport to badded ++ * ++ * Returns: 0 for success ++ */ ++int fcoe_hostlist_remove(const struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = fcoe_hostlist_lookup_softc(fcoe_netdev(lp)); ++ BUG_ON(!fc); ++ write_lock_bh(&fcoe_hostlist_lock); ++ list_del(&fc->list); ++ write_unlock_bh(&fcoe_hostlist_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(fcoe_hostlist_remove); ++ ++/** ++ * fcoe_libfc_config - sets up libfc related properties for lport ++ * @lp: ptr to the fc_lport ++ * @tt: libfc function template ++ * ++ * Returns : 0 for success ++ **/ ++int fcoe_libfc_config(struct fc_lport *lp, struct libfc_function_template *tt) ++{ ++ /* Set the function pointers set by the LLDD */ ++ memcpy(&lp->tt, tt, sizeof(*tt)); ++ if (fc_fcp_init(lp)) ++ return -ENOMEM; ++ fc_exch_init(lp); ++ fc_elsct_init(lp); ++ fc_lport_init(lp); ++ fc_rport_init(lp); ++ fc_disc_init(lp); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(fcoe_libfc_config); ++ ++/** ++ * fcoe_init - fcoe module loading initialization ++ * ++ * Initialization routine ++ * 1. Will create fc transport software structure ++ * 2. initialize the link list of port information structure ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++static int __init fcoe_init(void) ++{ ++ int cpu; ++ struct fcoe_percpu_s *p; ++ ++ ++ INIT_LIST_HEAD(&fcoe_hostlist); ++ rwlock_init(&fcoe_hostlist_lock); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ register_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++ /* ++ * initialize per CPU interrupt thread ++ */ ++ for_each_online_cpu(cpu) { ++ p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL); ++ if (p) { ++ p->thread = kthread_create(fcoe_percpu_receive_thread, ++ (void *)p, ++ "fcoethread/%d", cpu); ++ ++ /* ++ * if there is no error then bind the thread to the cpu ++ * initialize the semaphore and skb queue head ++ */ ++ if (likely(!IS_ERR(p->thread))) { ++ p->cpu = cpu; ++ fcoe_percpu[cpu] = p; ++ skb_queue_head_init(&p->fcoe_rx_list); ++ kthread_bind(p->thread, cpu); ++ wake_up_process(p->thread); ++ } else { ++ fcoe_percpu[cpu] = NULL; ++ kfree(p); ++ ++ } ++ } ++ } ++ ++ /* ++ * setup link change notification ++ */ ++ fcoe_dev_setup(); ++ ++ init_timer(&fcoe_timer); ++ fcoe_timer.data = 0; ++ fcoe_timer.function = fcoe_watchdog; ++ fcoe_timer.expires = (jiffies + (10 * HZ)); ++ add_timer(&fcoe_timer); ++ ++ /* initiatlize the fcoe transport */ ++ fcoe_transport_init(); ++ ++ fcoe_sw_init(); ++ ++ return 0; ++} ++module_init(fcoe_init); ++ ++/** ++ * fcoe_exit - fcoe module unloading cleanup ++ * ++ * Returns 0 on success, negative on failure ++ **/ ++static void __exit fcoe_exit(void) ++{ ++ u32 idx; ++ struct fcoe_softc *fc, *tmp; ++ struct fcoe_percpu_s *p; ++ struct sk_buff *skb; ++ ++ /* ++ * Stop all call back interfaces ++ */ ++#ifdef CONFIG_HOTPLUG_CPU ++ unregister_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ fcoe_dev_cleanup(); ++ ++ /* ++ * stop timer ++ */ ++ del_timer_sync(&fcoe_timer); ++ ++ /* releases the assocaited fcoe transport for each lport */ ++ list_for_each_entry_safe(fc, tmp, &fcoe_hostlist, list) ++ fcoe_transport_release(fc->real_dev); ++ ++ for (idx = 0; idx < NR_CPUS; idx++) { ++ if (fcoe_percpu[idx]) { ++ kthread_stop(fcoe_percpu[idx]->thread); ++ p = fcoe_percpu[idx]; ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) ++ kfree_skb(skb); ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ if (fcoe_percpu[idx]->crc_eof_page) ++ put_page(fcoe_percpu[idx]->crc_eof_page); ++ kfree(fcoe_percpu[idx]); ++ } ++ } ++ ++ /* remove sw trasnport */ ++ fcoe_sw_exit(); ++ ++ /* detach the transport */ ++ fcoe_transport_exit(); ++} ++module_exit(fcoe_exit); +diff --git a/drivers/scsi/libfc/Makefile b/drivers/scsi/libfc/Makefile +index e6d4086..55f982d 100644 +--- a/drivers/scsi/libfc/Makefile ++++ b/drivers/scsi/libfc/Makefile +@@ -5,6 +5,7 @@ obj-$(CONFIG_LIBFC) += libfc.o + libfc-objs := \ + fc_disc.o \ + fc_exch.o \ ++ fc_elsct.o \ + fc_frame.o \ + fc_lport.o \ + fc_rport.o \ +diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c +index d50f1a5..aee2f9c 100644 +--- a/drivers/scsi/libfc/fc_disc.c ++++ b/drivers/scsi/libfc/fc_disc.c +@@ -30,11 +30,13 @@ + + #include + +-#include ++#include + + #define FC_DISC_RETRY_LIMIT 3 /* max retries */ + #define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ + ++#define FC_DISC_DELAY 3 ++ + static int fc_disc_debug; + + #define FC_DEBUG_DISC(fmt...) \ +@@ -43,26 +45,182 @@ static int fc_disc_debug; + FC_DBG(fmt); \ + } while (0) + +-static void fc_disc_gpn_ft_req(struct fc_lport *); ++static struct mutex disc_list_lock; ++static struct list_head disc_list; ++ ++struct fc_disc { ++ unsigned char retry_count; ++ unsigned char delay; ++ unsigned char pending; ++ unsigned char requested; ++ unsigned short seq_count; ++ unsigned char buf_len; ++ enum fc_disc_event event; ++ ++ void (*disc_callback)(struct fc_lport *, ++ enum fc_disc_event); ++ ++ struct list_head rports; ++ struct fc_lport *lport; ++ struct mutex disc_mutex; ++ struct fc_gpn_ft_resp partial_buf; /* partial name buffer */ ++ struct delayed_work disc_work; ++ ++ struct list_head list; ++}; ++ ++static void fc_disc_gpn_ft_req(struct fc_disc *); + static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); +-static int fc_disc_new_target(struct fc_lport *, struct fc_rport *, ++static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, + struct fc_rport_identifiers *); +-static void fc_disc_del_target(struct fc_lport *, struct fc_rport *); +-static void fc_disc_done(struct fc_lport *); +-static void fc_disc_error(struct fc_lport *, struct fc_frame *); ++static void fc_disc_del_target(struct fc_disc *, struct fc_rport *); ++static void fc_disc_done(struct fc_disc *); + static void fc_disc_timeout(struct work_struct *); +-static void fc_disc_single(struct fc_lport *, struct fc_disc_port *); +-static int fc_disc_restart(struct fc_lport *); ++static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); ++static void fc_disc_restart(struct fc_disc *); ++ ++/** ++ * fc_disc_lookup_rport - lookup a remote port by port_id ++ * @lport: Fibre Channel host port instance ++ * @port_id: remote port port_id to match ++ */ ++struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, ++ u32 port_id) ++{ ++ struct fc_disc *disc; ++ struct fc_rport *rport, *found = NULL; ++ struct fc_rport_libfc_priv *rdata; ++ int disc_found = 0; ++ ++ mutex_lock(&disc_list_lock); ++ list_for_each_entry(disc, &disc_list, list) { ++ if (disc->lport == lport) { ++ list_for_each_entry(rdata, &disc->rports, peers) { ++ rport = PRIV_TO_RPORT(rdata); ++ if (rport->port_id == port_id) { ++ disc_found = 1; ++ found = rport; ++ get_device(&found->dev); ++ break; ++ } ++ } ++ } ++ } ++ mutex_unlock(&disc_list_lock); ++ ++ if (!disc_found) { ++ FC_DEBUG_DISC("The rport (%6x) for lport (%6x) " ++ "is not maintained by the discovery layer\n", ++ port_id, fc_host_port_id(lport->host)); ++ found = NULL; ++ } ++ ++ return found; ++} ++ ++/** ++ * fc_disc_alloc - Allocate a discovery work object ++ * @lport: The FC lport associated with the discovery job ++ */ ++static inline struct fc_disc *fc_disc_alloc(struct fc_lport *lport) ++{ ++ struct fc_disc *disc; ++ ++ disc = kzalloc(sizeof(struct fc_disc), GFP_KERNEL); ++ INIT_LIST_HEAD(&disc->list); ++ INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); ++ mutex_init(&disc->disc_mutex); ++ INIT_LIST_HEAD(&disc->rports); ++ ++ disc->lport = lport; ++ disc->delay = FC_DISC_DELAY; ++ disc->event = DISC_EV_NONE; ++ ++ mutex_lock(&disc_list_lock); ++ list_add_tail(&disc->list, &disc_list); ++ mutex_unlock(&disc_list_lock); ++ ++ return disc; ++} ++ ++/** ++ * fc_disc_stop_rports - delete all the remote ports associated with the lport ++ * @disc: The discovery job to stop rports on ++ * ++ * Locking Note: This function expects that the lport mutex is locked before ++ * calling it. ++ */ ++void fc_disc_stop_rports(struct fc_disc *disc) ++{ ++ struct fc_lport *lport; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata, *next; ++ ++ lport = disc->lport; ++ ++ mutex_lock(&disc->disc_mutex); ++ list_for_each_entry_safe(rdata, next, &disc->rports, peers) { ++ rport = PRIV_TO_RPORT(rdata); ++ list_del(&rdata->peers); ++ lport->tt.rport_logoff(rport); ++ } ++ ++ mutex_unlock(&disc->disc_mutex); ++} ++ ++/** ++ * fc_disc_rport_event - Event handler for rport events ++ * @lport: The lport which is receiving the event ++ * @rport: The rport which the event has occured on ++ * @event: The event that occured ++ * ++ * Locking Note: The rport lock should not be held when calling ++ * this function. ++ */ ++static void fc_disc_rport_event(struct fc_lport *lport, ++ struct fc_rport *rport, ++ enum fc_lport_event event) ++{ ++ struct fc_rport_libfc_priv *rdata = rport->dd_data; ++ struct fc_disc *disc; ++ int found = 0; ++ ++ FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event, ++ rport->port_id); ++ ++ if (event == RPORT_EV_CREATED) { ++ mutex_lock(&disc_list_lock); ++ list_for_each_entry(disc, &disc_list, list) { ++ if (disc->lport == lport) { ++ found = 1; ++ mutex_lock(&disc->disc_mutex); ++ list_add_tail(&rdata->peers, &disc->rports); ++ mutex_unlock(&disc->disc_mutex); ++ } ++ } ++ mutex_unlock(&disc_list_lock); ++ } ++ ++ if (!found) ++ FC_DEBUG_DISC("The rport (%6x) is not maintained " ++ "by the discovery layer\n", rport->port_id); ++} + + /** + * fc_disc_recv_rscn_req - Handle Registered State Change Notification (RSCN) + * @sp: Current sequence of the RSCN exchange + * @fp: RSCN Frame + * @lport: Fibre Channel host port instance ++ * ++ * Locking Note: This function expects that the disc_mutex is locked ++ * before it is called. + */ + static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, +- struct fc_lport *lport) ++ struct fc_disc *disc) + { ++ struct fc_lport *lport; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata; + struct fc_els_rscn *rp; + struct fc_els_rscn_page *pp; + struct fc_seq_els_data rjt_data; +@@ -70,9 +228,14 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, + int redisc = 0; + enum fc_els_rscn_ev_qual ev_qual; + enum fc_els_rscn_addr_fmt fmt; +- LIST_HEAD(disc_list); ++ LIST_HEAD(disc_ports); + struct fc_disc_port *dp, *next; + ++ lport = disc->lport; ++ ++ FC_DEBUG_DISC("Received an RSCN event on port (%6x)\n", ++ fc_host_port_id(lport->host)); ++ + rp = fc_frame_payload_get(fp, sizeof(*rp)); + + if (!rp || rp->rscn_page_len != sizeof(*pp)) +@@ -106,7 +269,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, + dp->ids.port_name = -1; + dp->ids.node_name = -1; + dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; +- list_add_tail(&dp->peers, &disc_list); ++ list_add_tail(&dp->peers, &disc_ports); + break; + case ELS_ADDR_FMT_AREA: + case ELS_ADDR_FMT_DOM: +@@ -120,18 +283,20 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, + lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + if (redisc) { + FC_DEBUG_DISC("RSCN received: rediscovering\n"); +- list_for_each_entry_safe(dp, next, &disc_list, peers) { +- list_del(&dp->peers); +- kfree(dp); +- } +- fc_disc_restart(lport); ++ fc_disc_restart(disc); + } else { + FC_DEBUG_DISC("RSCN received: not rediscovering. " + "redisc %d state %d in_prog %d\n", +- redisc, lport->state, lport->disc_pending); +- list_for_each_entry_safe(dp, next, &disc_list, peers) { ++ redisc, lport->state, disc->pending); ++ list_for_each_entry_safe(dp, next, &disc_ports, peers) { + list_del(&dp->peers); +- fc_disc_single(lport, dp); ++ rport = lport->tt.rport_lookup(lport, dp->ids.port_id); ++ if (rport) { ++ rdata = RPORT_TO_PRIV(rport); ++ list_del(&rdata->peers); ++ lport->tt.rport_logoff(rport); ++ } ++ fc_disc_single(disc, dp); + } + } + fc_frame_free(fp); +@@ -149,16 +314,39 @@ reject: + * @sp: Current sequence of the request exchange + * @fp: The frame + * @lport: The FC local port ++ * ++ * Locking Note: This function is called from the EM and will lock ++ * the disc_mutex before calling the handler for the ++ * request. + */ + static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, + struct fc_lport *lport) + { + u8 op; ++ struct fc_disc *disc; ++ int found = 0; ++ ++ mutex_lock(&disc_list_lock); ++ list_for_each_entry(disc, &disc_list, list) { ++ if (disc->lport == lport) { ++ found = 1; ++ break; ++ } ++ } ++ mutex_unlock(&disc_list_lock); ++ ++ if (!found) { ++ FC_DBG("Received a request for an lport not managed " ++ "by the discovery engine\n"); ++ return; ++ } + + op = fc_frame_payload_op(fp); + switch (op) { + case ELS_RSCN: +- fc_disc_recv_rscn_req(sp, fp, lport); ++ mutex_lock(&disc->disc_mutex); ++ fc_disc_recv_rscn_req(sp, fp, disc); ++ mutex_unlock(&disc->disc_mutex); + break; + default: + FC_DBG("Received an unsupported request. opcode (%x)\n", op); +@@ -168,16 +356,30 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, + + /** + * fc_disc_restart - Restart discovery +- * @lport: FC local port ++ * @lport: FC discovery context ++ * ++ * Locking Note: This function expects that the disc mutex ++ * is already locked. + */ +-static int fc_disc_restart(struct fc_lport *lport) ++static void fc_disc_restart(struct fc_disc *disc) + { +- if (!lport->disc_requested && !lport->disc_pending) { +- schedule_delayed_work(&lport->disc_work, +- msecs_to_jiffies(lport->disc_delay * 1000)); ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rdata, *next; ++ struct fc_lport *lport = disc->lport; ++ ++ FC_DEBUG_DISC("Restarting discovery for port (%6x)\n", ++ fc_host_port_id(lport->host)); ++ ++ list_for_each_entry_safe(rdata, next, &disc->rports, peers) { ++ rport = PRIV_TO_RPORT(rdata); ++ FC_DEBUG_DISC("list_del(%6x)\n", rport->port_id); ++ list_del(&rdata->peers); ++ lport->tt.rport_logoff(rport); + } +- lport->disc_requested = 1; +- return 0; ++ ++ disc->requested = 1; ++ if (!disc->pending) ++ fc_disc_gpn_ft_req(disc); + } + + /** +@@ -186,29 +388,58 @@ static int fc_disc_restart(struct fc_lport *lport) + * + * Returns non-zero if discovery cannot be started. + */ +-static int fc_disc_start(struct fc_lport *lport) ++static void fc_disc_start(void (*disc_callback)(struct fc_lport *, ++ enum fc_disc_event), ++ struct fc_lport *lport) + { + struct fc_rport *rport; +- int error; + struct fc_rport_identifiers ids; ++ struct fc_disc *disc; ++ int found = 0; ++ ++ mutex_lock(&disc_list_lock); ++ list_for_each_entry(disc, &disc_list, list) { ++ if (disc->lport == lport) { ++ found = 1; ++ break; ++ } ++ } ++ mutex_unlock(&disc_list_lock); ++ ++ if (!found) { ++ FC_DEBUG_DISC("No existing discovery job, " ++ "creating one for lport (%6x)\n", ++ fc_host_port_id(lport->host)); ++ disc = fc_disc_alloc(lport); ++ } else ++ FC_DEBUG_DISC("Found an existing discovery job " ++ "for lport (%6x)\n", ++ fc_host_port_id(lport->host)); ++ ++ /* ++ * At this point we may have a new disc job or an existing ++ * one. Either way, let's lock when we make changes to it ++ * and send the GPN_FT request. ++ */ ++ mutex_lock(&disc->disc_mutex); ++ ++ disc->disc_callback = disc_callback; + + /* + * If not ready, or already running discovery, just set request flag. + */ +- if (!fc_lport_test_ready(lport) || lport->disc_pending) { +- lport->disc_requested = 1; ++ disc->requested = 1; + +- return 0; ++ if (disc->pending) { ++ mutex_unlock(&disc->disc_mutex); ++ return; + } +- lport->disc_pending = 1; +- lport->disc_requested = 0; +- lport->disc_retry_count = 0; + + /* + * Handle point-to-point mode as a simple discovery +- * of the remote port. ++ * of the remote port. Yucky, yucky, yuck, yuck! + */ +- rport = lport->ptp_rp; ++ rport = disc->lport->ptp_rp; + if (rport) { + ids.port_id = rport->port_id; + ids.port_name = rport->port_name; +@@ -216,32 +447,16 @@ static int fc_disc_start(struct fc_lport *lport) + ids.roles = FC_RPORT_ROLE_UNKNOWN; + get_device(&rport->dev); + +- error = fc_disc_new_target(lport, rport, &ids); ++ if (!fc_disc_new_target(disc, rport, &ids)) { ++ disc->event = DISC_EV_SUCCESS; ++ fc_disc_done(disc); ++ } + put_device(&rport->dev); +- if (!error) +- fc_disc_done(lport); + } else { +- fc_disc_gpn_ft_req(lport); /* get ports by FC-4 type */ +- error = 0; ++ fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ + } +- return error; +-} +- +-/** +- * fc_disc_retry - Retry discovery +- * @lport: FC local port +- */ +-static void fc_disc_retry(struct fc_lport *lport) +-{ +- unsigned long delay = FC_DISC_RETRY_DELAY; + +- if (!lport->disc_retry_count) +- delay /= 4; /* timeout faster first time */ +- if (lport->disc_retry_count++ < FC_DISC_RETRY_LIMIT) +- schedule_delayed_work(&lport->disc_work, +- msecs_to_jiffies(delay)); +- else +- fc_disc_done(lport); ++ mutex_unlock(&disc->disc_mutex); + } + + /** +@@ -249,11 +464,15 @@ static void fc_disc_retry(struct fc_lport *lport) + * @lport: FC local port + * @rport: The previous FC remote port (NULL if new remote port) + * @ids: Identifiers for the new FC remote port ++ * ++ * Locking Note: This function expects that the disc_mutex is locked ++ * before it is called. + */ +-static int fc_disc_new_target(struct fc_lport *lport, ++static int fc_disc_new_target(struct fc_disc *disc, + struct fc_rport *rport, + struct fc_rport_identifiers *ids) + { ++ struct fc_lport *lport = disc->lport; + struct fc_rport_libfc_priv *rp; + int error = 0; + +@@ -272,7 +491,7 @@ static int fc_disc_new_target(struct fc_lport *lport, + * assigned the same FCID. This should be rare. + * Delete the old one and fall thru to re-create. + */ +- fc_disc_del_target(lport, rport); ++ fc_disc_del_target(disc, rport); + rport = NULL; + } + } +@@ -295,7 +514,7 @@ static int fc_disc_new_target(struct fc_lport *lport, + } + if (rport) { + rp = rport->dd_data; +- rp->event_callback = lport->tt.event_callback; ++ rp->event_callback = fc_disc_rport_event; + rp->rp_state = RPORT_ST_INIT; + lport->tt.rport_login(rport); + } +@@ -305,89 +524,111 @@ static int fc_disc_new_target(struct fc_lport *lport, + + /** + * fc_disc_del_target - Delete a target +- * @lport: FC local port ++ * @disc: FC discovery context + * @rport: The remote port to be removed + */ +-static void fc_disc_del_target(struct fc_lport *lport, struct fc_rport *rport) ++static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) + { +- lport->tt.rport_stop(rport); ++ struct fc_lport *lport = disc->lport; ++ struct fc_rport_libfc_priv *rdata = RPORT_TO_PRIV(rport); ++ list_del(&rdata->peers); ++ lport->tt.rport_logoff(rport); + } + + /** + * fc_disc_done - Discovery has been completed +- * @lport: FC local port ++ * @disc: FC discovery context + */ +-static void fc_disc_done(struct fc_lport *lport) ++static void fc_disc_done(struct fc_disc *disc) + { +- lport->disc_done = 1; +- lport->disc_pending = 0; +- if (lport->disc_requested) +- lport->tt.disc_start(lport); ++ struct fc_lport *lport = disc->lport; ++ ++ FC_DEBUG_DISC("Discovery complete for port (%6x)\n", ++ fc_host_port_id(lport->host)); ++ ++ disc->disc_callback(lport, disc->event); ++ disc->event = DISC_EV_NONE; ++ ++ if (disc->requested) ++ fc_disc_gpn_ft_req(disc); ++ else ++ disc->pending = 0; + } + + /** +- * fc_disc_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request +- * @lport: FC local port ++ * fc_disc_error - Handle error on dNS request ++ * @disc: FC discovery context ++ * @fp: The frame pointer + */ +-static void fc_disc_gpn_ft_req(struct fc_lport *lport) ++static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) + { +- struct fc_frame *fp; +- struct fc_seq *sp = NULL; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_gid_ft gid; +- } *rp; +- int error = 0; +- +- lport->disc_buf_len = 0; +- lport->disc_seq_count = 0; +- fp = fc_frame_alloc(lport, sizeof(*rp)); +- if (!fp) { +- error = ENOMEM; +- } else { +- rp = fc_frame_payload_get(fp, sizeof(*rp)); +- fc_fill_dns_hdr(lport, &rp->ct, FC_NS_GPN_FT, sizeof(rp->gid)); +- rp->gid.fn_fc4_type = FC_TYPE_FCP; +- +- WARN_ON(!fc_lport_test_ready(lport)); +- +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- sp = lport->tt.exch_seq_send(lport, fp, +- fc_disc_gpn_ft_resp, NULL, +- lport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- FC_FID_DIR_SERV, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ struct fc_lport *lport = disc->lport; ++ unsigned long delay = 0; ++ if (fc_disc_debug) ++ FC_DBG("Error %ld, retries %d/%d\n", ++ PTR_ERR(fp), disc->retry_count, ++ FC_DISC_RETRY_LIMIT); ++ ++ if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { ++ /* ++ * Memory allocation failure, or the exchange timed out, ++ * retry after delay. ++ */ ++ if (disc->retry_count < FC_DISC_RETRY_LIMIT) { ++ /* go ahead and retry */ ++ if (!fp) ++ delay = msecs_to_jiffies(500); ++ else { ++ delay = jiffies + ++ msecs_to_jiffies(lport->e_d_tov); ++ ++ /* timeout faster first time */ ++ if (!disc->retry_count) ++ delay /= 4; ++ } ++ disc->retry_count++; ++ schedule_delayed_work(&disc->disc_work, ++ delay); ++ } else { ++ /* exceeded retries */ ++ disc->event = DISC_EV_FAILED; ++ fc_disc_done(disc); ++ } + } +- if (error || !sp) +- fc_disc_retry(lport); + } + + /** +- * fc_disc_error - Handle error on dNS request +- * @lport: FC local port +- * @fp: The frame pointer ++ * fc_disc_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request ++ * @lport: FC discovery context ++ * ++ * Locking Note: This function expects that the disc_mutex is locked ++ * before it is called. + */ +-static void fc_disc_error(struct fc_lport *lport, struct fc_frame *fp) ++static void fc_disc_gpn_ft_req(struct fc_disc *disc) + { +- long err = PTR_ERR(fp); ++ struct fc_frame *fp; ++ struct fc_lport *lport = disc->lport; + +- FC_DEBUG_DISC("Error %ld, retries %d/%d\n", PTR_ERR(fp), +- lport->retry_count, FC_DISC_RETRY_LIMIT); ++ WARN_ON(!fc_lport_test_ready(lport)); + +- switch (err) { +- case -FC_EX_TIMEOUT: +- if (lport->disc_retry_count++ < FC_DISC_RETRY_LIMIT) { +- fc_disc_gpn_ft_req(lport); +- } else { +- fc_disc_done(lport); +- } +- break; +- default: +- FC_DBG("Error code %ld not supported\n", err); +- fc_disc_done(lport); +- break; +- } ++ disc->pending = 1; ++ disc->requested = 0; ++ ++ disc->buf_len = 0; ++ disc->seq_count = 0; ++ fp = fc_frame_alloc(lport, ++ sizeof(struct fc_ct_hdr) + ++ sizeof(struct fc_ns_gid_ft)); ++ if (!fp) ++ goto err; ++ ++ if (lport->tt.elsct_send(lport, NULL, fp, ++ FC_NS_GPN_FT, ++ fc_disc_gpn_ft_resp, ++ disc, lport->e_d_tov)) ++ return; ++err: ++ fc_disc_error(disc, fp); + } + + /** +@@ -396,8 +637,9 @@ static void fc_disc_error(struct fc_lport *lport, struct fc_frame *fp) + * @buf: GPN_FT response buffer + * @len: size of response buffer + */ +-static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) ++static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) + { ++ struct fc_lport *lport; + struct fc_gpn_ft_resp *np; + char *bp; + size_t plen; +@@ -407,13 +649,15 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + struct fc_rport *rport; + struct fc_rport_libfc_priv *rdata; + ++ lport = disc->lport; ++ + /* + * Handle partial name record left over from previous call. + */ + bp = buf; + plen = len; + np = (struct fc_gpn_ft_resp *)bp; +- tlen = lport->disc_buf_len; ++ tlen = disc->buf_len; + if (tlen) { + WARN_ON(tlen >= sizeof(*np)); + plen = sizeof(*np) - tlen; +@@ -421,7 +665,7 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + WARN_ON(plen >= sizeof(*np)); + if (plen > len) + plen = len; +- np = &lport->disc_buf; ++ np = &disc->partial_buf; + memcpy((char *)np + tlen, bp, plen); + + /* +@@ -431,9 +675,9 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + bp -= tlen; + len += tlen; + plen += tlen; +- lport->disc_buf_len = (unsigned char) plen; ++ disc->buf_len = (unsigned char) plen; + if (plen == sizeof(*np)) +- lport->disc_buf_len = 0; ++ disc->buf_len = 0; + } + + /* +@@ -455,7 +699,7 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + rport = fc_rport_rogue_create(&dp); + if (rport) { + rdata = rport->dd_data; +- rdata->event_callback = lport->tt.event_callback; ++ rdata->event_callback = fc_disc_rport_event; + rdata->local_port = lport; + lport->tt.rport_login(rport); + } else +@@ -465,7 +709,8 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + } + + if (np->fp_flags & FC_NS_FID_LAST) { +- fc_disc_done(lport); ++ disc->event = DISC_EV_SUCCESS; ++ fc_disc_done(disc); + len = 0; + break; + } +@@ -479,11 +724,15 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + * Save any partial record at the end of the buffer for next time. + */ + if (error == 0 && len > 0 && len < sizeof(*np)) { +- if (np != &lport->disc_buf) +- memcpy(&lport->disc_buf, np, len); +- lport->disc_buf_len = (unsigned char) len; ++ if (np != &disc->partial_buf) { ++ FC_DEBUG_DISC("Partial buffer remains " ++ "for discovery by (%6x)\n", ++ fc_host_port_id(lport->host)); ++ memcpy(&disc->partial_buf, np, len); ++ } ++ disc->buf_len = (unsigned char) len; + } else { +- lport->disc_buf_len = 0; ++ disc->buf_len = 0; + } + return error; + } +@@ -493,14 +742,13 @@ static int fc_disc_gpn_ft_parse(struct fc_lport *lport, void *buf, size_t len) + */ + static void fc_disc_timeout(struct work_struct *work) + { +- struct fc_lport *lport; +- +- lport = container_of(work, struct fc_lport, disc_work.work); +- +- if (lport->disc_pending) +- fc_disc_gpn_ft_req(lport); +- else +- lport->tt.disc_start(lport); ++ struct fc_disc *disc = container_of(work, ++ struct fc_disc, ++ disc_work.work); ++ mutex_lock(&disc->disc_mutex); ++ if (disc->requested && !disc->pending) ++ fc_disc_gpn_ft_req(disc); ++ mutex_unlock(&disc->disc_mutex); + } + + /** +@@ -509,12 +757,13 @@ static void fc_disc_timeout(struct work_struct *work) + * @fp: response frame + * @lp_arg: Fibre Channel host port instance + * +- * The response may be in multiple frames ++ * Locking Note: This function expects that the disc_mutex is locked ++ * before it is called. + */ + static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, +- void *lp_arg) ++ void *disc_arg) + { +- struct fc_lport *lport = lp_arg; ++ struct fc_disc *disc = disc_arg; + struct fc_ct_hdr *cp; + struct fc_frame_header *fh; + unsigned int seq_cnt; +@@ -522,8 +771,11 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + unsigned int len; + int error; + ++ FC_DEBUG_DISC("Received a GPN_FT response on port (%6x)\n", ++ fc_host_port_id(disc->lport->host)); ++ + if (IS_ERR(fp)) { +- fc_disc_error(lport, fp); ++ fc_disc_error(disc, fp); + return; + } + +@@ -532,9 +784,9 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + len = fr_len(fp) - sizeof(*fh); + seq_cnt = ntohs(fh->fh_seq_cnt); + if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && +- lport->disc_seq_count == 0) { ++ disc->seq_count == 0) { + cp = fc_frame_payload_get(fp, sizeof(*cp)); +- if (cp == NULL) { ++ if (!cp) { + FC_DBG("GPN_FT response too short, len %d\n", + fr_len(fp)); + } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { +@@ -548,25 +800,26 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + FC_DBG("GPN_FT rejected reason %x exp %x " + "(check zoning)\n", cp->ct_reason, + cp->ct_explan); +- fc_disc_done(lport); ++ disc->event = DISC_EV_FAILED; ++ fc_disc_done(disc); + } else { + FC_DBG("GPN_FT unexpected response code %x\n", + ntohs(cp->ct_cmd)); + } + } else if (fr_sof(fp) == FC_SOF_N3 && +- seq_cnt == lport->disc_seq_count) { ++ seq_cnt == disc->seq_count) { + buf = fh + 1; + } else { + FC_DBG("GPN_FT unexpected frame - out of sequence? " + "seq_cnt %x expected %x sof %x eof %x\n", +- seq_cnt, lport->disc_seq_count, fr_sof(fp), fr_eof(fp)); ++ seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); + } + if (buf) { +- error = fc_disc_gpn_ft_parse(lport, buf, len); ++ error = fc_disc_gpn_ft_parse(disc, buf, len); + if (error) +- fc_disc_retry(lport); ++ fc_disc_error(disc, fp); + else +- lport->disc_seq_count++; ++ disc->seq_count++; + } + fc_frame_free(fp); + } +@@ -576,27 +829,31 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, + * @lport: FC local port + * @dp: The port to rediscover + * +- * This could be from an RSCN that reported a change for the target. ++ * Locking Note: This function expects that the disc_mutex is locked ++ * before it is called. + */ +-static void fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) ++static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) + { ++ struct fc_lport *lport; + struct fc_rport *rport; + struct fc_rport *new_rport; + struct fc_rport_libfc_priv *rdata; + ++ lport = disc->lport; ++ + if (dp->ids.port_id == fc_host_port_id(lport->host)) + goto out; + + rport = lport->tt.rport_lookup(lport, dp->ids.port_id); + if (rport) { +- fc_disc_del_target(lport, rport); ++ fc_disc_del_target(disc, rport); + put_device(&rport->dev); /* hold from lookup */ + } + + new_rport = fc_rport_rogue_create(dp); + if (new_rport) { + rdata = new_rport->dd_data; +- rdata->event_callback = lport->tt.event_callback; ++ rdata->event_callback = fc_disc_rport_event; + kfree(dp); + lport->tt.rport_login(new_rport); + } +@@ -606,19 +863,70 @@ out: + } + + /** ++ * fc_disc_stop - Stop discovery for a given lport ++ * @lport: The lport that discovery should stop for ++ */ ++void fc_disc_stop(struct fc_lport *lport) ++{ ++ struct fc_disc *disc, *next; ++ ++ mutex_lock(&disc_list_lock); ++ list_for_each_entry_safe(disc, next, &disc_list, list) { ++ if (disc->lport == lport) { ++ cancel_delayed_work_sync(&disc->disc_work); ++ fc_disc_stop_rports(disc); ++ } ++ } ++ mutex_unlock(&disc_list_lock); ++} ++ ++/** ++ * fc_disc_stop_final - Stop discovery for a given lport ++ * @lport: The lport that discovery should stop for ++ * ++ * This function will block until discovery has been ++ * completely stopped and all rports have been deleted. ++ */ ++void fc_disc_stop_final(struct fc_lport *lport) ++{ ++ struct fc_disc *disc, *next; ++ fc_disc_stop(lport); ++ lport->tt.rport_flush_queue(); ++ ++ mutex_lock(&disc_list_lock); ++ list_for_each_entry_safe(disc, next, &disc_list, list) { ++ if (disc->lport == lport) { ++ list_del(&disc->list); ++ kfree(disc); ++ } ++ } ++ mutex_unlock(&disc_list_lock); ++} ++ ++/** + * fc_disc_init - Initialize the discovery block + * @lport: FC local port + */ + int fc_disc_init(struct fc_lport *lport) + { +- INIT_DELAYED_WORK(&lport->disc_work, fc_disc_timeout); ++ INIT_LIST_HEAD(&disc_list); ++ mutex_init(&disc_list_lock); + + if (!lport->tt.disc_start) + lport->tt.disc_start = fc_disc_start; + ++ if (!lport->tt.disc_stop) ++ lport->tt.disc_stop = fc_disc_stop; ++ ++ if (!lport->tt.disc_stop_final) ++ lport->tt.disc_stop_final = fc_disc_stop_final; ++ + if (!lport->tt.disc_recv_req) + lport->tt.disc_recv_req = fc_disc_recv_req; + ++ if (!lport->tt.rport_lookup) ++ lport->tt.rport_lookup = fc_disc_lookup_rport; ++ + return 0; + } + EXPORT_SYMBOL(fc_disc_init); +diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c +new file mode 100644 +index 0000000..dd47fe6 +--- /dev/null ++++ b/drivers/scsi/libfc/fc_elsct.c +@@ -0,0 +1,71 @@ ++/* ++ * Copyright(c) 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Provide interface to send ELS/CT FC frames ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * fc_elsct_send - sends ELS/CT frame ++ */ ++static struct fc_seq *fc_elsct_send(struct fc_lport *lport, ++ struct fc_rport *rport, ++ struct fc_frame *fp, ++ unsigned int op, ++ void (*resp)(struct fc_seq *, ++ struct fc_frame *fp, ++ void *arg), ++ void *arg, u32 timer_msec) ++{ ++ enum fc_rctl r_ctl; ++ u32 did; ++ enum fc_fh_type fh_type; ++ int rc; ++ ++ /* ELS requests */ ++ if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) ++ rc = fc_els_fill(lport, rport, fp, op, &r_ctl, &did, &fh_type); ++ else ++ /* CT requests */ ++ rc = fc_ct_fill(lport, fp, op, &r_ctl, &did, &fh_type); ++ ++ if (rc) ++ return NULL; ++ ++ fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type, ++ FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); ++ ++ return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); ++} ++ ++int fc_elsct_init(struct fc_lport *lport) ++{ ++ if (!lport->tt.elsct_send) ++ lport->tt.elsct_send = fc_elsct_send; ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_elsct_init); +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +index 67c5bad..12a1196 100644 +--- a/drivers/scsi/libfc/fc_exch.c ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -29,7 +29,8 @@ + + #include + +-#include ++#include ++#include + + #define FC_DEF_R_A_TOV (10 * 1000) /* resource allocation timeout */ + +@@ -60,66 +61,6 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ + */ + + /* +- * Sequence. +- */ +-struct fc_seq { +- u8 id; /* seq ID */ +- u16 ssb_stat; /* status flags for sequence status block */ +- u16 cnt; /* frames sent so far on sequence */ +- u32 f_ctl; /* F_CTL flags for frames */ +- u32 rec_data; /* FC-4 value for REC */ +-}; +- +-struct fc_exch; +- +-#define FC_EX_DONE (1 << 0) /* ep is completed */ +-#define FC_EX_RST_CLEANUP (1 << 1) /* reset is forcing completion */ +- +-/* +- * Exchange. +- * +- * Locking notes: The ex_lock protects changes to the following fields: +- * esb_stat, f_ctl, seq.ssb_stat, seq.f_ctl. +- * seq_id +- * sequence allocation +- * +- * If the em_lock and ex_lock must be taken at the same time, the +- * em_lock must be taken before the ex_lock. +- */ +-struct fc_exch { +- struct fc_exch_mgr *em; /* exchange manager */ +- u32 state; /* internal driver state */ +- u16 xid; /* our exchange ID */ +- struct list_head ex_list; /* free or busy list linkage */ +- spinlock_t ex_lock; /* lock covering exchange state */ +- atomic_t ex_refcnt; /* reference counter */ +- struct delayed_work timeout_work; /* timer for upper level protocols */ +- struct fc_lport *lp; /* fc device instance */ +- u16 oxid; /* originator's exchange ID */ +- u16 rxid; /* responder's exchange ID */ +- u32 oid; /* originator's FCID */ +- u32 sid; /* source FCID */ +- u32 did; /* destination FCID */ +- u32 esb_stat; /* exchange status for ESB */ +- u32 r_a_tov; /* r_a_tov from rport (msec) */ +- u8 seq_id; /* next sequence ID to use */ +- u32 f_ctl; /* F_CTL flags for sequences */ +- u8 fh_type; /* frame type */ +- enum fc_class class; /* class of service */ +- struct fc_seq seq; /* single sequence */ +- /* +- * Handler for responses to this current exchange. +- */ +- void (*resp)(struct fc_seq *, struct fc_frame *, void *); +- void (*destructor)(struct fc_seq *, void *); +- /* +- * arg is passed as void pointer to exchange +- * resp and destructor handlers +- */ +- void *arg; +-}; +- +-/* + * Exchange manager. + * + * This structure is the center for creating exchanges and sequences. +@@ -131,6 +72,8 @@ struct fc_exch_mgr { + u16 last_xid; /* last allocated exchange ID */ + u16 min_xid; /* min exchange ID */ + u16 max_xid; /* max exchange ID */ ++ u16 max_read; /* max exchange ID for read */ ++ u16 last_read; /* last xid allocated for read */ + u32 total_exches; /* total allocated exchanges */ + struct list_head ex_list; /* allocated exchanges list */ + struct fc_lport *lp; /* fc device instance */ +@@ -151,14 +94,12 @@ struct fc_exch_mgr { + } stats; + struct fc_exch **exches; /* for exch pointers indexed by xid */ + }; +- + #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) +-#define fc_exch_next_xid(mp, id) ((id == mp->max_xid) ? mp->min_xid : id + 1) + + static void fc_exch_rrq(struct fc_exch *); + static void fc_seq_ls_acc(struct fc_seq *); + static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, +- enum fc_els_rjt_explan); ++ enum fc_els_rjt_explan); + static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *); + static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *); + static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp); +@@ -274,34 +215,57 @@ static void fc_exch_hold(struct fc_exch *ep) + } + + /* +- * Fill in frame header. +- * +- * The following fields are the responsibility of this routine: +- * d_id, s_id, df_ctl, oxid, rxid, cs_ctl, seq_id +- * +- * The following fields are handled by the caller. +- * r_ctl, type, f_ctl, seq_cnt, parm_offset +- * +- * That should be a complete list. +- * +- * We may be the originator or responder to the sequence. ++ * setup fc hdr by initializing few more FC header fields and sof/eof. ++ * Initialized fields by this func: ++ * - fh_ox_id, fh_rx_id, fh_seq_id, fh_seq_cnt ++ * - sof and eof + */ +-static void fc_seq_fill_hdr(struct fc_seq *sp, struct fc_frame *fp) ++static void fc_exch_setup_hdr(struct fc_exch *ep, struct fc_frame *fp, ++ u32 f_ctl) + { + struct fc_frame_header *fh = fc_frame_header_get(fp); +- struct fc_exch *ep; ++ u16 fill; + +- ep = fc_seq_exch(sp); ++ fr_sof(fp) = ep->class; ++ if (ep->seq.cnt) ++ fr_sof(fp) = fc_sof_normal(ep->class); ++ ++ if (f_ctl & FC_FC_END_SEQ) { ++ fr_eof(fp) = FC_EOF_T; ++ if (fc_sof_needs_ack(ep->class)) ++ fr_eof(fp) = FC_EOF_N; ++ /* ++ * Form f_ctl. ++ * The number of fill bytes to make the length a 4-byte ++ * multiple is the low order 2-bits of the f_ctl. ++ * The fill itself will have been cleared by the frame ++ * allocation. ++ * After this, the length will be even, as expected by ++ * the transport. ++ */ ++ fill = fr_len(fp) & 3; ++ if (fill) { ++ fill = 4 - fill; ++ /* TODO, this may be a problem with fragmented skb */ ++ skb_put(fp_skb(fp), fill); ++ hton24(fh->fh_f_ctl, f_ctl | fill); ++ } ++ } else { ++ WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ ++ fr_eof(fp) = FC_EOF_N; ++ } + +- hton24(fh->fh_s_id, ep->sid); +- hton24(fh->fh_d_id, ep->did); ++ /* ++ * Initialize remainig fh fields ++ * from fc_fill_fc_hdr ++ */ + fh->fh_ox_id = htons(ep->oxid); + fh->fh_rx_id = htons(ep->rxid); +- fh->fh_seq_id = sp->id; +- fh->fh_cs_ctl = 0; +- fh->fh_df_ctl = 0; ++ fh->fh_seq_id = ep->seq.id; ++ fh->fh_seq_cnt = htons(ep->seq.cnt); + } + ++ + /* + * Release a reference to an exchange. + * If the refcnt goes to zero and the exchange is complete, it is freed. +@@ -432,8 +396,9 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec) + */ + fp = fc_frame_alloc(ep->lp, 0); + if (fp) { +- fc_frame_setup(fp, FC_RCTL_BA_ABTS, FC_TYPE_BLS); +- error = fc_seq_send(ep->lp, sp, fp, FC_FC_END_SEQ); ++ fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid, ++ FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); ++ error = fc_seq_send(ep->lp, sp, fp); + } else + error = -ENOBUFS; + return error; +@@ -508,36 +473,66 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) + } + + /* +- * Allocate an exchange. ++ * fc_em_alloc_xid - returns an xid based on request type ++ * @lp : ptr to associated lport ++ * @fp : ptr to the assocated frame + * +- * if xid is supplied zero then assign next free exchange ID +- * from exchange manager, otherwise use supplied xid. +- * Returns with exch lock held. ++ * check the associated fc_fsp_pkt to get scsi command type and ++ * command direction to decide from which range this exch id ++ * will be allocated from. ++ * ++ * Returns : 0 or an valid xid + */ +-struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) ++static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) + { ++ u16 xid, min, max; ++ u16 *plast; + struct fc_exch *ep = NULL; +- u16 min_xid, max_xid; + +- min_xid = mp->min_xid; +- max_xid = mp->max_xid; +- /* +- * if xid is supplied then verify its xid range +- */ +- if (xid) { +- if (unlikely((xid < min_xid) || (xid > max_xid))) { +- FC_DBG("Invalid xid 0x:%x\n", xid); +- goto out; +- } +- if (unlikely(mp->exches[xid - min_xid] != NULL)) { +- FC_DBG("xid 0x:%x is already in use\n", xid); +- goto out; ++ if (mp->max_read) { ++ if (fc_frame_is_read(fp)) { ++ min = mp->min_xid; ++ max = mp->max_read; ++ plast = &mp->last_read; ++ } else { ++ min = mp->max_read + 1; ++ max = mp->max_xid; ++ plast = &mp->last_xid; + } ++ } else { ++ min = mp->min_xid; ++ max = mp->max_xid; ++ plast = &mp->last_xid; + } ++ xid = *plast; ++ do { ++ xid = (xid == max) ? min : xid + 1; ++ ep = mp->exches[xid - mp->min_xid]; ++ } while ((ep != NULL) && (xid != *plast)); + +- /* +- * Allocate new exchange +- */ ++ if (unlikely(ep)) ++ xid = 0; ++ else ++ *plast = xid; ++ ++ return xid; ++} ++ ++/* ++ * fc_exch_alloc - allocate an exchange. ++ * @mp : ptr to the exchange manager ++ * @xid: input xid ++ * ++ * if xid is supplied zero then assign next free exchange ID ++ * from exchange manager, otherwise use supplied xid. ++ * Returns with exch lock held. ++ */ ++struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, ++ struct fc_frame *fp, u16 xid) ++{ ++ struct fc_exch *ep = NULL; ++ ++ /* allocate memory for exchange */ + ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); + if (!ep) { + atomic_inc(&mp->stats.no_free_exch); +@@ -546,40 +541,26 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) + memset(ep, 0, sizeof(*ep)); + + spin_lock_bh(&mp->em_lock); +- +- /* +- * if xid is zero then assign next free exchange ID +- */ ++ /* alloc xid if input xid 0 */ + if (!xid) { +- xid = fc_exch_next_xid(mp, mp->last_xid); +- /* +- * find next free xid using linear search +- */ +- while (mp->exches[xid - min_xid] != NULL) { +- if (xid == mp->last_xid) +- break; +- xid = fc_exch_next_xid(mp, xid); +- } +- +- if (unlikely(mp->exches[xid - min_xid] != NULL)) ++ /* alloc a new xid */ ++ xid = fc_em_alloc_xid(mp, fp); ++ if (!xid) { ++ printk(KERN_ERR "fc_em_alloc_xid() failed\n"); + goto err; +- mp->last_xid = xid; ++ } + } + +- /* lport lock ? */ +- if (mp->lp->state == LPORT_ST_RESET) +- goto err; /* don't add new ep during local port reset */ +- + fc_exch_hold(ep); /* hold for exch in mp */ + spin_lock_init(&ep->ex_lock); + /* + * Hold exch lock for caller to prevent fc_exch_reset() +- * from releasing exch while fc_exch_alloc() caller is ++ * from releasing exch while fc_exch_alloc() caller is + * still working on exch. + */ + spin_lock_bh(&ep->ex_lock); + +- mp->exches[xid - min_xid] = ep; ++ mp->exches[xid - mp->min_xid] = ep; + list_add_tail(&ep->ex_list, &mp->ex_list); + fc_seq_alloc(ep, ep->seq_id++); + mp->total_exches++; +@@ -874,55 +855,17 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp) + } + EXPORT_SYMBOL(fc_seq_start_next); + +-int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, +- struct fc_frame *fp, u32 f_ctl) ++int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp) + { + struct fc_exch *ep; +- struct fc_frame_header *fh; +- enum fc_class class; +- u16 fill = 0; ++ struct fc_frame_header *fh = fc_frame_header_get(fp); + int error; + + ep = fc_seq_exch(sp); + WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); + +- fc_seq_fill_hdr(sp, fp); +- fh = fc_frame_header_get(fp); +- class = ep->class; +- fr_sof(fp) = class; +- if (sp->cnt) +- fr_sof(fp) = fc_sof_normal(class); +- +- if (f_ctl & FC_FC_END_SEQ) { +- fr_eof(fp) = FC_EOF_T; +- if (fc_sof_needs_ack(class)) +- fr_eof(fp) = FC_EOF_N; +- /* +- * Form f_ctl. +- * The number of fill bytes to make the length a 4-byte +- * multiple is the low order 2-bits of the f_ctl. +- * The fill itself will have been cleared by the frame +- * allocation. +- * After this, the length will be even, as expected by +- * the transport. Don't include the fill in the f_ctl +- * saved in the sequence. +- */ +- fill = fr_len(fp) & 3; +- if (fill) { +- fill = 4 - fill; +- /* TODO, this may be a problem with fragmented skb */ +- skb_put(fp_skb(fp), fill); +- } +- f_ctl |= sp->f_ctl | ep->f_ctl; +- } else { +- WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ +- f_ctl |= sp->f_ctl | ep->f_ctl; +- f_ctl &= ~FC_FC_SEQ_INIT; +- fr_eof(fp) = FC_EOF_N; +- } +- +- hton24(fh->fh_f_ctl, f_ctl | fill); +- fh->fh_seq_cnt = htons(sp->cnt); ++ sp->f_ctl = ntoh24(fh->fh_f_ctl); ++ fc_exch_setup_hdr(ep, fp, sp->f_ctl); + + /* + * update sequence count if this frame is carrying +@@ -946,12 +889,10 @@ int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, + * We can only be called to send once for each sequence. + */ + spin_lock_bh(&ep->ex_lock); +- sp->f_ctl = f_ctl; /* save for possible abort */ + ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ +- if (f_ctl & FC_FC_END_SEQ) { +- if (f_ctl & FC_FC_SEQ_INIT) +- ep->esb_stat &= ~ESB_ST_SEQ_INIT; +- } ++ sp->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ ++ if (sp->f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT)) ++ ep->esb_stat &= ~ESB_ST_SEQ_INIT; + spin_unlock_bh(&ep->ex_lock); + return error; + } +@@ -986,10 +927,11 @@ static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp, + enum fc_rctl rctl, enum fc_fh_type fh_type) + { + u32 f_ctl; ++ struct fc_exch *ep = fc_seq_exch(sp); + +- fc_frame_setup(fp, rctl, fh_type); +- f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- fc_seq_send(fc_seq_exch(sp)->lp, sp, fp, f_ctl); ++ f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; ++ fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0); ++ fc_seq_send(fc_seq_exch(sp)->lp, sp, fp); + } + + /* +@@ -1001,7 +943,8 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) + struct fc_frame *fp; + struct fc_frame_header *rx_fh; + struct fc_frame_header *fh; +- struct fc_lport *lp = fc_seq_exch(sp)->lp; ++ struct fc_exch *ep = fc_seq_exch(sp); ++ struct fc_lport *lp = ep->lp; + unsigned int f_ctl; + + /* +@@ -1013,7 +956,6 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) + if (!fp) + return; + +- fc_seq_fill_hdr(sp, fp); + fh = fc_frame_header_get(fp); + fh->fh_r_ctl = FC_RCTL_ACK_1; + fh->fh_type = FC_TYPE_BLS; +@@ -1034,6 +976,7 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) + f_ctl ^= FC_FC_EX_CTX | FC_FC_SEQ_CTX; + hton24(fh->fh_f_ctl, f_ctl); + ++ fc_exch_setup_hdr(ep, fp, f_ctl); + fh->fh_seq_id = rx_fh->fh_seq_id; + fh->fh_seq_cnt = rx_fh->fh_seq_cnt; + fh->fh_parm_offset = htonl(1); /* ack single frame */ +@@ -1514,7 +1457,7 @@ static void fc_exch_reset(struct fc_exch *ep) + * a deadlock). + */ + if (cancel_delayed_work(&ep->timeout_work)) +- atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ + resp = ep->resp; + ep->resp = NULL; + if (ep->esb_stat & ESB_ST_REC_QUAL) +@@ -1565,22 +1508,6 @@ restart: + } + EXPORT_SYMBOL(fc_exch_mgr_reset); + +-void fc_seq_get_xids(struct fc_seq *sp, u16 *oxid, u16 *rxid) +-{ +- struct fc_exch *ep; +- +- ep = fc_seq_exch(sp); +- *oxid = ep->oxid; +- *rxid = ep->rxid; +-} +-EXPORT_SYMBOL(fc_seq_get_xids); +- +-void fc_seq_set_rec_data(struct fc_seq *sp, u32 rec_data) +-{ +- sp->rec_data = rec_data; +-} +-EXPORT_SYMBOL(fc_seq_set_rec_data); +- + /* + * Handle incoming ELS REC - Read Exchange Concise. + * Note that the requesting port may be different than the S_ID in the request. +@@ -1648,8 +1575,8 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) + hton24(acc->reca_rfid, ep->sid); + acc->reca_fc4value = htonl(ep->seq.rec_data); + acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | +- ESB_ST_SEQ_INIT | +- ESB_ST_COMPLETE)); ++ ESB_ST_SEQ_INIT | ++ ESB_ST_COMPLETE)); + sp = fc_seq_start_next(sp); + fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); + out: +@@ -1723,7 +1650,6 @@ static void fc_exch_rrq(struct fc_exch *ep) + fp = fc_frame_alloc(lp, sizeof(*rrq)); + if (!fp) + return; +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); + rrq = fc_frame_payload_get(fp, sizeof(*rrq)); + memset(rrq, 0, sizeof(*rrq)); + rrq->rrq_cmd = ELS_RRQ; +@@ -1734,9 +1660,13 @@ static void fc_exch_rrq(struct fc_exch *ep) + did = ep->did; + if (ep->esb_stat & ESB_ST_RESP) + did = ep->sid; ++ ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did, ++ fc_host_port_id(lp->host), FC_TYPE_ELS, ++ FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); ++ + rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, +- lp->e_d_tov, fc_host_port_id(lp->host), did, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ lp->e_d_tov); + if (!rrq_sp) { + ep->esb_stat |= ESB_ST_REC_QUAL; + fc_exch_timer_set_locked(ep, ep->r_a_tov); +@@ -1791,7 +1721,7 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) + } + if (ep->esb_stat & ESB_ST_COMPLETE) { + if (cancel_delayed_work(&ep->timeout_work)) +- atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ atomic_dec(&ep->ex_refcnt); /* drop timer hold */ + } + + spin_unlock_bh(&ep->ex_lock); +@@ -1827,6 +1757,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, + /* + * Memory need for EM + */ ++#define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2))) + len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); + len += sizeof(struct fc_exch_mgr); + +@@ -1837,10 +1768,22 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, + mp->class = class; + mp->total_exches = 0; + mp->exches = (struct fc_exch **)(mp + 1); +- mp->last_xid = min_xid - 1; ++ mp->lp = lp; ++ /* adjust em exch xid range for offload */ + mp->min_xid = min_xid; + mp->max_xid = max_xid; +- mp->lp = lp; ++ mp->last_xid = min_xid - 1; ++ mp->max_read = 0; ++ mp->last_read = 0; ++ if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) { ++ mp->max_read = lp->lro_xid; ++ mp->last_read = min_xid - 1; ++ mp->last_xid = mp->max_read; ++ } else { ++ /* disable lro if no xid control over read */ ++ lp->lro_enabled = 0; ++ } ++ + INIT_LIST_HEAD(&mp->ex_list); + spin_lock_init(&mp->em_lock); + +@@ -1873,7 +1816,8 @@ struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp) + { + if (!lp || !lp->emp) + return NULL; +- return fc_exch_alloc(lp->emp, 0); ++ ++ return fc_exch_alloc(lp->emp, fp, 0); + } + EXPORT_SYMBOL(fc_exch_get); + +@@ -1883,13 +1827,11 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + struct fc_frame *fp, + void *arg), + void (*destructor)(struct fc_seq *, void *), +- void *arg, u32 timer_msec, +- u32 sid, u32 did, u32 f_ctl) ++ void *arg, u32 timer_msec) + { + struct fc_exch *ep; + struct fc_seq *sp = NULL; + struct fc_frame_header *fh; +- u16 fill; + int rc = 1; + + ep = lp->tt.exch_get(lp, fp); +@@ -1898,7 +1840,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + return NULL; + } + ep->esb_stat |= ESB_ST_SEQ_INIT; +- fc_exch_set_addr(ep, sid, did); ++ fh = fc_frame_header_get(fp); ++ fc_exch_set_addr(ep, ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id)); + ep->resp = resp; + ep->destructor = destructor; + ep->arg = arg; +@@ -1907,43 +1850,20 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + sp = &ep->seq; + WARN_ON((sp->f_ctl & FC_FC_END_SEQ) != 0); + +- fr_sof(fp) = ep->class; +- if (sp->cnt) +- fr_sof(fp) = fc_sof_normal(ep->class); +- fr_eof(fp) = FC_EOF_T; +- if (fc_sof_needs_ack(ep->class)) +- fr_eof(fp) = FC_EOF_N; +- +- fc_seq_fill_hdr(sp, fp); +- /* +- * Form f_ctl. +- * The number of fill bytes to make the length a 4-byte multiple is +- * the low order 2-bits of the f_ctl. The fill itself will have been +- * cleared by the frame allocation. +- * After this, the length will be even, as expected by the transport. +- * Don't include the fill in the f_ctl saved in the sequence. +- */ +- fill = fr_len(fp) & 3; +- if (fill) { +- fill = 4 - fill; +- /* TODO, this may be a problem with fragmented skb */ +- skb_put(fp_skb(fp), fill); +- } +- f_ctl |= ep->f_ctl; +- fh = fc_frame_header_get(fp); +- hton24(fh->fh_f_ctl, f_ctl | fill); +- fh->fh_seq_cnt = htons(sp->cnt++); + ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ ++ ep->f_ctl = ntoh24(fh->fh_f_ctl); ++ fc_exch_setup_hdr(ep, fp, ep->f_ctl); ++ sp->cnt++; + + if (unlikely(lp->tt.frame_send(lp, fp))) + goto err; + + if (timer_msec) + fc_exch_timer_set_locked(ep, timer_msec); +- sp->f_ctl = f_ctl; /* save for possible abort */ + ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ ++ sp->f_ctl = ep->f_ctl; /* save for possible abort */ + +- if (f_ctl & FC_FC_SEQ_INIT) ++ if (ep->f_ctl & FC_FC_SEQ_INIT) + ep->esb_stat &= ~ESB_ST_SEQ_INIT; + spin_unlock_bh(&ep->ex_lock); + return sp; +@@ -2032,11 +1952,6 @@ int fc_exch_init(struct fc_lport *lp) + if (!lp->tt.seq_exch_abort) + lp->tt.seq_exch_abort = fc_seq_exch_abort; + +- if (!lp->tt.seq_get_xids) +- lp->tt.seq_get_xids = fc_seq_get_xids; +- +- if (!lp->tt.seq_set_rec_data) +- lp->tt.seq_set_rec_data = fc_seq_set_rec_data; + return 0; + } + EXPORT_SYMBOL(fc_exch_init); +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +index 01e84dc..04ced7f 100644 +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -36,12 +36,12 @@ + + #include + +-#include ++#include ++#include + + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("libfc"); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("1.0.3"); + + static int fc_fcp_debug; + +@@ -388,15 +388,23 @@ crc_err: + } + + /* +- * Send SCSI data to target. ++ * fc_fcp_send_data - Send SCSI data to target. ++ * @fsp: ptr to fc_fcp_pkt ++ * @sp: ptr to this sequence ++ * @offset: starting offset for this data request ++ * @seq_blen: the burst length for this data request ++ * + * Called after receiving a Transfer Ready data descriptor. + * if LLD is capable of seq offload then send down seq_blen + * size of data in single frame, otherwise send multiple FC + * frames of max FC frame payload supported by target port. ++ * ++ * Returns : 0 for success. + */ + static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, + size_t offset, size_t seq_blen) + { ++ struct fc_exch *ep; + struct scsi_cmnd *sc; + struct scatterlist *sg; + struct fc_frame *fp = NULL; +@@ -405,7 +413,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, + size_t t_blen; + size_t tlen; + size_t sg_bytes; +- size_t frame_offset; ++ size_t frame_offset, fh_parm_offset; + int error; + void *data = NULL; + void *page_addr; +@@ -438,7 +446,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, + sc = fsp->cmd; + + remaining = seq_blen; +- frame_offset = offset; ++ fh_parm_offset = frame_offset = offset; + tlen = 0; + seq = lp->tt.seq_start_next(seq); + f_ctl = FC_FC_REL_OFF; +@@ -501,8 +509,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, + data = (void *)(fr_hdr(fp)) + + sizeof(struct fc_frame_header); + } +- fc_frame_setup(fp, FC_RCTL_DD_SOL_DATA, FC_TYPE_FCP); +- fc_frame_set_offset(fp, frame_offset); ++ fh_parm_offset = frame_offset; + fr_max_payload(fp) = fsp->max_payload; + } + sg_bytes = min(tlen, sg->length - offset); +@@ -539,28 +546,30 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, + tlen -= sg_bytes; + remaining -= sg_bytes; + +- if (remaining == 0) { +- /* +- * Send a request sequence with +- * transfer sequence initiative. +- */ +- f_ctl |= FC_FC_SEQ_INIT | FC_FC_END_SEQ; +- error = lp->tt.seq_send(lp, seq, fp, f_ctl); +- } else if (tlen == 0) { +- /* +- * send fragment using for a sequence. +- */ +- error = lp->tt.seq_send(lp, seq, fp, f_ctl); +- } else { ++ if (tlen) + continue; +- } +- fp = NULL; + ++ /* ++ * Send sequence with transfer sequence initiative in case ++ * this is last FCP frame of the sequence. ++ */ ++ if (remaining == 0) ++ f_ctl |= FC_FC_SEQ_INIT | FC_FC_END_SEQ; ++ ++ ep = fc_seq_exch(seq); ++ fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, ++ FC_TYPE_FCP, f_ctl, fh_parm_offset); ++ ++ /* ++ * send fragment using for a sequence. ++ */ ++ error = lp->tt.seq_send(lp, seq, fp); + if (error) { + WARN_ON(1); /* send error should be rare */ + fc_fcp_retry_cmd(fsp); + return 0; + } ++ fp = NULL; + } + fsp->xfer_len += seq_blen; /* premature count? */ + return 0; +@@ -684,7 +693,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) + (size_t) ntohl(dd->ft_data_ro), + (size_t) ntohl(dd->ft_burst_len)); + if (!rc) +- lp->tt.seq_set_rec_data(seq, fsp->xfer_len); ++ seq->rec_data = fsp->xfer_len; + else if (rc == -ENOMEM) + fsp->state |= FC_SRB_NOMEM; + } else if (r_ctl == FC_RCTL_DD_SOL_DATA) { +@@ -694,7 +703,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) + */ + WARN_ON(fr_len(fp) < sizeof(*fh)); /* len may be 0 */ + fc_fcp_recv_data(fsp, fp); +- lp->tt.seq_set_rec_data(seq, fsp->xfer_contig_end); ++ seq->rec_data = fsp->xfer_contig_end; + } else if (r_ctl == FC_RCTL_DD_CMD_STATUS) { + WARN_ON(fr_flags(fp) & FCPHF_CRC_UNCHECKED); + +@@ -833,6 +842,7 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp) + { + struct fc_lport *lp = fsp->lp; + struct fc_seq *seq; ++ struct fc_exch *ep; + u32 f_ctl; + + if (fsp->state & FC_SRB_ABORT_PENDING) +@@ -864,11 +874,13 @@ static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp) + csp = lp->tt.seq_start_next(seq); + conf_frame = fc_frame_alloc(fsp->lp, 0); + if (conf_frame) { +- fc_frame_setup(conf_frame, +- FC_RCTL_DD_SOL_CTL, FC_TYPE_FCP); + f_ctl = FC_FC_SEQ_INIT; + f_ctl |= FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- lp->tt.seq_send(lp, csp, conf_frame, f_ctl); ++ ep = fc_seq_exch(seq); ++ fc_fill_fc_hdr(conf_frame, FC_RCTL_DD_SOL_CTL, ++ ep->did, ep->sid, ++ FC_TYPE_FCP, f_ctl, 0); ++ lp->tt.seq_send(lp, csp, conf_frame); + } + } + lp->tt.exch_done(seq); +@@ -947,7 +959,7 @@ static void fc_fcp_abort_io(struct fc_lport *lp) + * This is called by upper layer protocol. + * Return : zero for success and -1 for failure + * Context : called from queuecommand which can be called from process +- * or scsi soft irq. ++ * or scsi soft irq. + * Locks : called with the host lock and irqs disabled. + */ + static int fc_fcp_pkt_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp) +@@ -995,18 +1007,16 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp, + } + + memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CMD, FC_TYPE_FCP); +- fc_frame_set_offset(fp, 0); ++ fr_cmd(fp) = fsp->cmd; + rport = fsp->rport; + fsp->max_payload = rport->maxframe_size; + rp = rport->dd_data; +- seq = lp->tt.exch_seq_send(lp, fp, +- resp, +- fc_fcp_pkt_destroy, +- fsp, 0, +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ ++ fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id, ++ fc_host_port_id(rp->local_port->host), FC_TYPE_FCP, ++ FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); ++ ++ seq = lp->tt.exch_seq_send(lp, fp, resp, fc_fcp_pkt_destroy, fsp, 0); + if (!seq) { + fc_frame_free(fp); + rc = -1; +@@ -1018,8 +1028,8 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp, + + setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); + fc_fcp_timer_set(fsp, +- (fsp->tgt_flags & FC_RP_FLAGS_REC_SUPPORTED) ? +- FC_SCSI_REC_TOV : FC_SCSI_ER_TIMEOUT); ++ (fsp->tgt_flags & FC_RP_FLAGS_REC_SUPPORTED) ? ++ FC_SCSI_REC_TOV : FC_SCSI_ER_TIMEOUT); + unlock: + fc_fcp_unlock_pkt(fsp); + return rc; +@@ -1249,50 +1259,33 @@ unlock: + static void fc_fcp_rec(struct fc_fcp_pkt *fsp) + { + struct fc_lport *lp; +- struct fc_seq *seq; + struct fc_frame *fp; +- struct fc_els_rec *rec; + struct fc_rport *rport; + struct fc_rport_libfc_priv *rp; +- u16 ox_id; +- u16 rx_id; + + lp = fsp->lp; + rport = fsp->rport; + rp = rport->dd_data; +- seq = fsp->seq_ptr; +- if (!seq || rp->rp_state != RPORT_ST_READY) { ++ if (!fsp->seq_ptr || rp->rp_state != RPORT_ST_READY) { + fsp->status_code = FC_HRD_ERROR; + fsp->io_status = SUGGEST_RETRY << 24; + fc_fcp_complete_locked(fsp); + return; + } +- lp->tt.seq_get_xids(seq, &ox_id, &rx_id); +- fp = fc_frame_alloc(lp, sizeof(*rec)); ++ fp = fc_frame_alloc(lp, sizeof(struct fc_els_rec)); + if (!fp) + goto retry; + +- rec = fc_frame_payload_get(fp, sizeof(*rec)); +- memset(rec, 0, sizeof(*rec)); +- rec->rec_cmd = ELS_REC; +- hton24(rec->rec_s_id, fc_host_port_id(lp->host)); +- rec->rec_ox_id = htons(ox_id); +- rec->rec_rx_id = htons(rx_id); +- +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- fc_frame_set_offset(fp, 0); +- seq = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_rec_resp, NULL, +- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); +- +- if (seq) { ++ fr_seq(fp) = fsp->seq_ptr; ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, ++ fc_host_port_id(rp->local_port->host), FC_TYPE_ELS, ++ FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); ++ if (lp->tt.elsct_send(lp, rport, fp, ELS_REC, fc_fcp_rec_resp, ++ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) { + fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ + return; +- } else +- fc_frame_free(fp); ++ } ++ fc_frame_free(fp); + retry: + if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) + fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); +@@ -1510,17 +1503,15 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) + struct fc_lport *lp = fsp->lp; + struct fc_rport *rport; + struct fc_rport_libfc_priv *rp; ++ struct fc_exch *ep = fc_seq_exch(fsp->seq_ptr); + struct fc_seq *seq; + struct fcp_srr *srr; + struct fc_frame *fp; + u8 cdb_op; +- u16 ox_id; +- u16 rx_id; + + rport = fsp->rport; + rp = rport->dd_data; + cdb_op = fsp->cdb_cmd.fc_cdb[0]; +- lp->tt.seq_get_xids(fsp->seq_ptr, &ox_id, &rx_id); + + if (!(rp->flags & FC_RP_FLAGS_RETRY) || rp->rp_state != RPORT_ST_READY) + goto retry; /* shouldn't happen */ +@@ -1531,19 +1522,17 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) + srr = fc_frame_payload_get(fp, sizeof(*srr)); + memset(srr, 0, sizeof(*srr)); + srr->srr_op = ELS_SRR; +- srr->srr_ox_id = htons(ox_id); +- srr->srr_rx_id = htons(rx_id); ++ srr->srr_ox_id = htons(ep->oxid); ++ srr->srr_rx_id = htons(ep->rxid); + srr->srr_r_ctl = r_ctl; + srr->srr_rel_off = htonl(offset); + +- fc_frame_setup(fp, FC_RCTL_ELS4_REQ, FC_TYPE_FCP); +- fc_frame_set_offset(fp, 0); +- seq = lp->tt.exch_seq_send(lp, fp, +- fc_fcp_srr_resp, NULL, +- fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), +- fc_host_port_id(rp->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id, ++ fc_host_port_id(rp->local_port->host), FC_TYPE_FCP, ++ FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); ++ ++ seq = lp->tt.exch_seq_send(lp, fp, fc_fcp_srr_resp, NULL, ++ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV)); + if (!seq) { + fc_frame_free(fp); + goto retry; +@@ -1565,8 +1554,6 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) + { + struct fc_fcp_pkt *fsp = arg; + struct fc_frame_header *fh; +- u16 ox_id; +- u16 rx_id; + + if (IS_ERR(fp)) { + fc_fcp_srr_error(fsp, fp); +@@ -1590,8 +1577,6 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) + } + + fsp->recov_seq = NULL; +- +- fsp->lp->tt.seq_get_xids(fsp->seq_ptr, &ox_id, &rx_id); + switch (fc_frame_payload_op(fp)) { + case ELS_LS_ACC: + fsp->recov_retry = 0; +@@ -2007,7 +1992,7 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) + return SUCCESS; + } else { + shost_printk(KERN_INFO, shost, "Host reset failed. " +- "lport not ready.\n"); ++ "lport not ready.\n"); + return FAILED; + } + } +diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c +index 388dc6c..0bbeff2 100644 +--- a/drivers/scsi/libfc/fc_frame.c ++++ b/drivers/scsi/libfc/fc_frame.c +@@ -25,7 +25,7 @@ + #include + #include + +-#include ++#include + + /* + * Check the CRC in a frame. +@@ -82,7 +82,8 @@ struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) + if (fp) { + memset((char *) fr_hdr(fp) + payload_len, 0, fill); + /* trim is OK, we just allocated it so there are no fragments */ +- skb_trim(fp_skb(fp), payload_len + sizeof(struct fc_frame_header)); ++ skb_trim(fp_skb(fp), ++ payload_len + sizeof(struct fc_frame_header)); + } + return fp; + } +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index 7e7c060..083d57b 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -78,7 +78,8 @@ + + #include + +-#include ++#include ++#include + + /* Fabric IDs to use for point-to-point mode, chosen on whims. */ + #define FC_LOCAL_PTP_FID_LO 0x010101 +@@ -124,71 +125,59 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) + } + + /** +- * fc_lport_lookup_rport - lookup a remote port by port_id +- * @lport: Fibre Channel host port instance +- * @port_id: remote port port_id to match +- */ +-struct fc_rport *fc_lport_lookup_rport(const struct fc_lport *lport, +- u32 port_id) +-{ +- struct fc_rport *rport, *found; +- struct fc_rport_libfc_priv *rdata; +- +- found = NULL; +- +- list_for_each_entry(rdata, &lport->rports, peers) { +- rport = PRIV_TO_RPORT(rdata); +- if (rport->port_id == port_id) { +- found = rport; +- get_device(&found->dev); +- break; +- } +- } +- return found; +-} +- +- +- +-/** + * fc_lport_rport_event - Event handler for rport events + * @lport: The lport which is receiving the event + * @rport: The rport which the event has occured on + * @event: The event that occured + * + * Locking Note: The rport lock should not be held when calling +- * this function. ++ * this function. + */ + static void fc_lport_rport_event(struct fc_lport *lport, + struct fc_rport *rport, + enum fc_lport_event event) + { +- struct fc_rport_libfc_priv *rdata = rport->dd_data; +- + FC_DEBUG_LPORT("Received a %d event for port (%6x)\n", event, + rport->port_id); + +- mutex_lock(&lport->lp_mutex); + switch (event) { +- case LPORT_EV_RPORT_CREATED: ++ case RPORT_EV_CREATED: + if (rport->port_id == FC_FID_DIR_SERV) { +- lport->dns_rp = rport; +- fc_lport_enter_rpn_id(lport); +- } else { +- list_add_tail(&rdata->peers, &lport->rports); +- } ++ mutex_lock(&lport->lp_mutex); ++ if (lport->state == LPORT_ST_DNS) { ++ lport->dns_rp = rport; ++ fc_lport_enter_rpn_id(lport); ++ } else { ++ FC_DEBUG_LPORT("Received an CREATED event on " ++ "port (%6x) for the directory " ++ "server, but the lport is not " ++ "in the DNS state, it's in the " ++ "%d state", rport->port_id, ++ lport->state); ++ lport->tt.rport_logoff(rport); ++ } ++ mutex_unlock(&lport->lp_mutex); ++ } else ++ FC_DEBUG_LPORT("Received an event for port (%6x) " ++ "which is not the directory server\n", ++ rport->port_id); + break; +- case LPORT_EV_RPORT_LOGO: +- case LPORT_EV_RPORT_FAILED: +- case LPORT_EV_RPORT_STOP: +- if (rport->port_id == FC_FID_DIR_SERV) ++ case RPORT_EV_LOGO: ++ case RPORT_EV_FAILED: ++ case RPORT_EV_STOP: ++ if (rport->port_id == FC_FID_DIR_SERV) { ++ mutex_lock(&lport->lp_mutex); + lport->dns_rp = NULL; +- else +- list_del(&rdata->peers); ++ mutex_unlock(&lport->lp_mutex); ++ ++ } else ++ FC_DEBUG_LPORT("Received an event for port (%6x) " ++ "which is not the directory server\n", ++ rport->port_id); + break; +- case LPORT_EV_RPORT_NONE: ++ case RPORT_EV_NONE: + break; + } +- mutex_unlock(&lport->lp_mutex); + } + + /** +@@ -225,7 +214,7 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, + dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; + + if (lport->ptp_rp) { +- lport->tt.rport_stop(lport->ptp_rp); ++ lport->tt.rport_logoff(lport->ptp_rp); + lport->ptp_rp = NULL; + } + +@@ -379,6 +368,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, + struct fc_lport *lport) + { + struct fc_frame *fp; ++ struct fc_exch *ep = fc_seq_exch(sp); + unsigned int len; + void *pp; + void *dp; +@@ -399,9 +389,10 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, + memcpy(dp, pp, len); + *((u32 *)dp) = htonl(ELS_LS_ACC << 24); + sp = lport->tt.seq_start_next(sp); +- f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lport->tt.seq_send(lport, sp, fp, f_ctl); ++ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, ++ FC_TYPE_ELS, f_ctl, 0); ++ lport->tt.seq_send(lport, sp, fp); + } + fc_frame_free(in_fp); + } +@@ -419,6 +410,7 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, + struct fc_lport *lport) + { + struct fc_frame *fp; ++ struct fc_exch *ep = fc_seq_exch(sp); + struct fc_els_rnid *req; + struct { + struct fc_els_rnid_resp rnid; +@@ -462,9 +454,11 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, + sizeof(rp->gen)); + } + sp = lport->tt.seq_start_next(sp); +- f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lport->tt.seq_send(lport, sp, fp, f_ctl); ++ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; ++ f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, ++ FC_TYPE_ELS, f_ctl, 0); ++ lport->tt.seq_send(lport, sp, fp); + } + } + fc_frame_free(in_fp); +@@ -492,7 +486,7 @@ static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, + * @lport: The lport that should log into the fabric + * + * Locking Note: This function should not be called +- * with the lport lock held. ++ * with the lport lock held. + */ + int fc_fabric_login(struct fc_lport *lport) + { +@@ -515,6 +509,9 @@ EXPORT_SYMBOL(fc_fabric_login); + */ + void fc_linkup(struct fc_lport *lport) + { ++ FC_DEBUG_LPORT("Link is up for port (%6x)\n", ++ fc_host_port_id(lport->host)); ++ + mutex_lock(&lport->lp_mutex); + if ((lport->link_status & FC_LINK_UP) != FC_LINK_UP) { + lport->link_status |= FC_LINK_UP; +@@ -533,13 +530,14 @@ EXPORT_SYMBOL(fc_linkup); + void fc_linkdown(struct fc_lport *lport) + { + mutex_lock(&lport->lp_mutex); ++ FC_DEBUG_LPORT("Link is down for port (%6x)\n", ++ fc_host_port_id(lport->host)); + + if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) { + lport->link_status &= ~(FC_LINK_UP); + fc_lport_enter_reset(lport); + lport->tt.fcp_cleanup(lport); + } +- + mutex_unlock(&lport->lp_mutex); + } + EXPORT_SYMBOL(fc_linkdown); +@@ -577,9 +575,9 @@ EXPORT_SYMBOL(fc_unpause); + **/ + int fc_fabric_logoff(struct fc_lport *lport) + { ++ lport->tt.disc_stop_final(lport); + mutex_lock(&lport->lp_mutex); + fc_lport_enter_logo(lport); +- lport->tt.fcp_cleanup(lport); + mutex_unlock(&lport->lp_mutex); + return 0; + } +@@ -599,9 +597,8 @@ EXPORT_SYMBOL(fc_fabric_logoff); + **/ + int fc_lport_destroy(struct fc_lport *lport) + { +- cancel_delayed_work_sync(&lport->disc_work); +- lport->tt.fcp_abort_io(lport); + lport->tt.frame_send = fc_frame_drop; ++ lport->tt.fcp_abort_io(lport); + lport->tt.exch_mgr_reset(lport->emp, 0, 0); + return 0; + } +@@ -626,10 +623,8 @@ int fc_set_mfs(struct fc_lport *lport, u32 mfs) + rc = 0; + } + +- if (!rc && mfs < old_mfs) { +- lport->disc_done = 0; ++ if (!rc && mfs < old_mfs) + fc_lport_enter_reset(lport); +- } + + mutex_unlock(&lport->lp_mutex); + +@@ -638,6 +633,31 @@ int fc_set_mfs(struct fc_lport *lport, u32 mfs) + EXPORT_SYMBOL(fc_set_mfs); + + /** ++ * fc_lport_disc_callback - Callback for discovery events ++ * @lport: FC local port ++ * @event: The discovery event ++ */ ++void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) ++{ ++ switch (event) { ++ case DISC_EV_SUCCESS: ++ FC_DEBUG_LPORT("Got a SUCCESS event for port (%6x)\n", ++ fc_host_port_id(lport->host)); ++ break; ++ case DISC_EV_FAILED: ++ FC_DEBUG_LPORT("Got a FAILED event for port (%6x)\n", ++ fc_host_port_id(lport->host)); ++ mutex_lock(&lport->lp_mutex); ++ fc_lport_enter_reset(lport); ++ mutex_unlock(&lport->lp_mutex); ++ break; ++ case DISC_EV_NONE: ++ WARN_ON(1); ++ break; ++ } ++} ++ ++/** + * fc_rport_enter_ready - Enter the ready state and start discovery + * @lport: Fibre Channel local port that is ready + * +@@ -651,7 +671,7 @@ static void fc_lport_enter_ready(struct fc_lport *lport) + + fc_lport_state_enter(lport, LPORT_ST_READY); + +- lport->tt.disc_start(lport); ++ lport->tt.disc_start(fc_lport_disc_callback, lport); + } + + /** +@@ -674,6 +694,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + struct fc_frame *fp; + struct fc_frame_header *fh; + struct fc_seq *sp; ++ struct fc_exch *ep; + struct fc_els_flogi *flp; + struct fc_els_flogi *new_flp; + u64 remote_wwpn; +@@ -724,9 +745,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + * Send the response. If this fails, the originator should + * repeat the sequence. + */ +- f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lport->tt.seq_send(lport, sp, fp, f_ctl); ++ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ ep = fc_seq_exch(sp); ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, ++ FC_TYPE_ELS, f_ctl, 0); ++ lport->tt.seq_send(lport, sp, fp); + + } else { + fc_lport_error(lport, fp); +@@ -734,8 +757,8 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, + fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, + get_unaligned_be64(&flp->fl_wwnn)); + +- if (lport->tt.disc_start(lport)) +- FC_DBG("target discovery start error\n"); ++ lport->tt.disc_start(fc_lport_disc_callback, lport); ++ + out: + sp = fr_seq(rx_fp); + fc_frame_free(rx_fp); +@@ -751,7 +774,7 @@ out: + * if an rport should handle the request. + * + * Locking Note: This function should not be called with the lport +- * lock held becuase it will grab the lock. ++ * lock held becuase it will grab the lock. + */ + static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + struct fc_frame *fp) +@@ -808,7 +831,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + s_id = ntoh24(fh->fh_s_id); + d_id = ntoh24(fh->fh_d_id); + +- rport = fc_lport_lookup_rport(lport, s_id); ++ rport = lport->tt.rport_lookup(lport, s_id); + if (rport) { + lport->tt.rport_recv_req(sp, fp, rport); + put_device(&rport->dev); /* hold from lookup */ +@@ -840,7 +863,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + * @lport: The lport which should be reset + * + * Locking Note: This functions should not be called with the +- * lport lock held. ++ * lport lock held. + */ + int fc_lport_reset(struct fc_lport *lport) + { +@@ -852,24 +875,6 @@ int fc_lport_reset(struct fc_lport *lport) + EXPORT_SYMBOL(fc_lport_reset); + + /** +- * fc_lport_stop_rports - delete all the remote ports associated with the lport +- * @lport: libfc local port instance +- * +- * Locking Note: This function expects that the lport mutex is locked before +- * calling it. +- */ +-void fc_lport_stop_rports(struct fc_lport *lport) +-{ +- struct fc_rport *rport; +- struct fc_rport_libfc_priv *rdata; +- +- list_for_each_entry(rdata, &lport->rports, peers) { +- rport = PRIV_TO_RPORT(rdata); +- lport->tt.rport_stop(rport); +- } +-} +- +-/** + * fc_rport_enter_reset - Reset the local port + * @lport: Fibre Channel local port to be reset + * +@@ -883,17 +888,15 @@ static void fc_lport_enter_reset(struct fc_lport *lport) + + fc_lport_state_enter(lport, LPORT_ST_RESET); + +- if (lport->dns_rp) { +- lport->tt.rport_stop(lport->dns_rp); +- lport->dns_rp = NULL; +- } ++ if (lport->dns_rp) ++ lport->tt.rport_logoff(lport->dns_rp); + + if (lport->ptp_rp) { +- lport->tt.rport_stop(lport->ptp_rp); ++ lport->tt.rport_logoff(lport->ptp_rp); + lport->ptp_rp = NULL; + } + +- fc_lport_stop_rports(lport); ++ lport->tt.disc_stop(lport); + + lport->tt.exch_mgr_reset(lport->emp, 0, 0); + fc_host_fabric_name(lport->host) = 0; +@@ -952,7 +955,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) + + /** + * fc_lport_rft_id_resp - Handle response to Register Fibre +- * Channel Types by ID (RPN_ID) request ++ * Channel Types by ID (RPN_ID) request + * @sp: current sequence in RPN_ID exchange + * @fp: response frame + * @lp_arg: Fibre Channel host port instance +@@ -1004,7 +1007,7 @@ err: + + /** + * fc_lport_rpn_id_resp - Handle response to Register Port +- * Name by ID (RPN_ID) request ++ * Name by ID (RPN_ID) request + * @sp: current sequence in RPN_ID exchange + * @fp: response frame + * @lp_arg: Fibre Channel host port instance +@@ -1110,32 +1113,20 @@ err: + static void fc_lport_enter_scr(struct fc_lport *lport) + { + struct fc_frame *fp; +- struct fc_els_scr *scr; + + FC_DEBUG_LPORT("Port (%6x) entered SCR state from %s state\n", + fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_SCR); + +- fp = fc_frame_alloc(lport, sizeof(*scr)); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_els_scr)); + if (!fp) { + fc_lport_error(lport, fp); + return; + } + +- scr = fc_frame_payload_get(fp, sizeof(*scr)); +- memset(scr, 0, sizeof(*scr)); +- scr->scr_cmd = ELS_SCR; +- scr->scr_reg_func = ELS_SCRF_FULL; +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- fc_frame_set_offset(fp, 0); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_lport_scr_resp, NULL, +- lport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- FC_FID_FCTRL, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, NULL, fp, ELS_SCR, ++ fc_lport_scr_resp, lport, lport->e_d_tov)) + fc_lport_error(lport, fp); + } + +@@ -1149,11 +1140,6 @@ static void fc_lport_enter_scr(struct fc_lport *lport) + static void fc_lport_enter_rft_id(struct fc_lport *lport) + { + struct fc_frame *fp; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_fid fid; /* port ID object */ +- struct fc_ns_fts fts; /* FC4-types object */ +- } *req; + struct fc_ns_fts *lps; + int i; + +@@ -1170,31 +1156,20 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) + if (i < 0) { + /* nothing to register, move on to SCR */ + fc_lport_enter_scr(lport); +- } else { +- fp = fc_frame_alloc(lport, sizeof(*req)); +- if (!fp) { +- fc_lport_error(lport, fp); +- return; +- } ++ return; ++ } + +- req = fc_frame_payload_get(fp, sizeof(*req)); +- fc_fill_dns_hdr(lport, &req->ct, +- FC_NS_RFT_ID, +- sizeof(*req) - +- sizeof(struct fc_ct_hdr)); +- hton24(req->fid.fp_fid, fc_host_port_id(lport->host)); +- req->fts = *lps; +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_lport_rft_id_resp, NULL, +- lport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- FC_FID_DIR_SERV, +- FC_FC_SEQ_INIT | +- FC_FC_END_SEQ)) +- fc_lport_error(lport, fp); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + ++ sizeof(struct fc_ns_rft)); ++ if (!fp) { ++ fc_lport_error(lport, fp); ++ return; + } ++ ++ if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RFT_ID, ++ fc_lport_rft_id_resp, ++ lport, lport->e_d_tov)) ++ fc_lport_error(lport, fp); + } + + /** +@@ -1207,37 +1182,23 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport) + static void fc_lport_enter_rpn_id(struct fc_lport *lport) + { + struct fc_frame *fp; +- struct req { +- struct fc_ct_hdr ct; +- struct fc_ns_rn_id rn; +- } *req; + + FC_DEBUG_LPORT("Port (%6x) entered RPN_ID state from %s state\n", + fc_host_port_id(lport->host), fc_lport_state(lport)); + + fc_lport_state_enter(lport, LPORT_ST_RPN_ID); + +- fp = fc_frame_alloc(lport, sizeof(*req)); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + ++ sizeof(struct fc_ns_rn_id)); + if (!fp) { + fc_lport_error(lport, fp); + return; + } + +- req = fc_frame_payload_get(fp, sizeof(*req)); +- memset(req, 0, sizeof(*req)); +- fc_fill_dns_hdr(lport, &req->ct, FC_NS_RPN_ID, sizeof(req->rn)); +- hton24(req->rn.fr_fid.fp_fid, fc_host_port_id(lport->host)); +- put_unaligned_be64(lport->wwpn, &req->rn.fr_wwn); +- fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_lport_rpn_id_resp, NULL, +- lport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- FC_FID_DIR_SERV, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RPN_ID, ++ fc_lport_rpn_id_resp, ++ lport, lport->e_d_tov)) + fc_lport_error(lport, fp); +- + } + + /** +@@ -1264,16 +1225,10 @@ static void fc_lport_enter_dns(struct fc_lport *lport) + + fc_lport_state_enter(lport, LPORT_ST_DNS); + +- if (!lport->dns_rp) { +- /* Set up a rogue rport to directory server */ +- rport = fc_rport_rogue_create(&dp); +- +- if (!rport) +- goto err; +- lport->dns_rp = rport; +- } ++ rport = fc_rport_rogue_create(&dp); ++ if (!rport) ++ goto err; + +- rport = lport->dns_rp; + rdata = rport->dd_data; + rdata->event_callback = fc_lport_rport_event; + lport->tt.rport_login(rport); +@@ -1388,10 +1343,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport) + fc_lport_state_enter(lport, LPORT_ST_LOGO); + + /* DNS session should be closed so we can release it here */ +- if (lport->dns_rp) { +- lport->tt.rport_logout(lport->dns_rp); +- lport->dns_rp = NULL; +- } ++ if (lport->dns_rp) ++ lport->tt.rport_logoff(lport->dns_rp); + + fp = fc_frame_alloc(lport, sizeof(*logo)); + if (!fp) { +@@ -1399,19 +1352,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport) + return; + } + +- logo = fc_frame_payload_get(fp, sizeof(*logo)); +- memset(logo, 0, sizeof(*logo)); +- logo->fl_cmd = ELS_LOGO; +- hton24(logo->fl_n_port_id, fc_host_port_id(lport->host)); +- logo->fl_n_port_wwn = htonll(lport->wwpn); +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- fc_frame_set_offset(fp, 0); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_lport_logo_resp, NULL, +- lport, lport->e_d_tov, +- fc_host_port_id(lport->host), FC_FID_FLOGI, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, NULL, fp, ELS_LOGO, fc_lport_logo_resp, ++ lport, lport->e_d_tov)) + fc_lport_error(lport, fp); + } + +@@ -1496,8 +1438,8 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + if (flp) { + csp_flags = ntohs(flp->fl_csp.sp_features); + if ((csp_flags & FC_SP_FT_FPORT) == 0) { +- if (lport->tt.disc_start(lport)) +- FC_DBG("Target disc start error\n"); ++ lport->tt.disc_start(fc_lport_disc_callback, ++ lport); + } + } + } else { +@@ -1520,29 +1462,18 @@ err: + void fc_lport_enter_flogi(struct fc_lport *lport) + { + struct fc_frame *fp; +- struct fc_els_flogi *flp; + + FC_DEBUG_LPORT("Processing FLOGI state\n"); + + fc_lport_state_enter(lport, LPORT_ST_FLOGI); + +- fp = fc_frame_alloc(lport, sizeof(*flp)); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); + if (!fp) + return fc_lport_error(lport, fp); + +- flp = fc_frame_payload_get(fp, sizeof(*flp)); +- fc_lport_flogi_fill(lport, flp, ELS_FLOGI); +- +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- fc_frame_set_offset(fp, 0); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_lport_flogi_resp, NULL, +- lport, lport->e_d_tov, +- 0, FC_FID_FLOGI, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, NULL, fp, ELS_FLOGI, ++ fc_lport_flogi_resp, lport, lport->e_d_tov)) + fc_lport_error(lport, fp); +- + } + + /* Configure a fc_lport */ +@@ -1550,12 +1481,9 @@ int fc_lport_config(struct fc_lport *lport) + { + INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); + mutex_init(&lport->lp_mutex); +- INIT_LIST_HEAD(&lport->rports); + + fc_lport_state_enter(lport, LPORT_ST_NONE); + +- lport->disc_delay = DNS_DELAY; +- + fc_lport_add_fc4_type(lport, FC_TYPE_FCP); + fc_lport_add_fc4_type(lport, FC_TYPE_CT); + +@@ -1571,12 +1499,6 @@ int fc_lport_init(struct fc_lport *lport) + if (!lport->tt.lport_reset) + lport->tt.lport_reset = fc_lport_reset; + +- if (!lport->tt.rport_lookup) +- lport->tt.rport_lookup = fc_lport_lookup_rport; +- +- if (!lport->tt.event_callback) +- lport->tt.event_callback = fc_lport_rport_event; +- + fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; + fc_host_node_name(lport->host) = lport->wwnn; + fc_host_port_name(lport->host) = lport->wwpn; +diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c +index 2d0bd85..d081af5 100644 +--- a/drivers/scsi/libfc/fc_rport.c ++++ b/drivers/scsi/libfc/fc_rport.c +@@ -36,9 +36,9 @@ + * The locking strategy is similar to the lport's strategy. The lock protects + * the rport's states and is held and released by the entry points to the rport + * block. All _enter_* functions correspond to rport states and expect the rport +- * mutex to be locked before calling them. This means that rports only handle one +- * request or response at a time, since they're not critical for the I/O path +- * this potential over-use of the mutex is acceptable. ++ * mutex to be locked before calling them. This means that rports only handle ++ * one request or response at a time, since they're not critical for the I/O ++ * path this potential over-use of the mutex is acceptable. + */ + + #include +@@ -49,7 +49,8 @@ + #include + #include + +-#include ++#include ++#include + + static int fc_rport_debug; + +@@ -59,7 +60,7 @@ static int fc_rport_debug; + FC_DBG(fmt); \ + } while (0) + +-static struct workqueue_struct *rport_event_queue; ++struct workqueue_struct *rport_event_queue; + + static void fc_rport_enter_plogi(struct fc_rport *); + static void fc_rport_enter_prli(struct fc_rport *); +@@ -122,7 +123,7 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) + rdata->local_port = dp->lp; + rdata->trans_state = FC_PORTSTATE_ROGUE; + rdata->rp_state = RPORT_ST_INIT; +- rdata->event = LPORT_EV_RPORT_NONE; ++ rdata->event = RPORT_EV_NONE; + rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; + rdata->event_callback = NULL; + rdata->e_d_tov = dp->lp->e_d_tov; +@@ -196,43 +197,6 @@ fc_plogi_get_maxframe(struct fc_els_flogi *flp, unsigned int maxval) + } + + /** +- * fc_lport_plogi_fill - Fill in PLOGI command for request +- * @lport: Fibre Channel host port instance +- * @plogi: PLOGI command structure to fill (same structure as FLOGI) +- * @op: either ELS_PLOGI for a localy generated request, or ELS_LS_ACC +- */ +-static void +-fc_lport_plogi_fill(struct fc_lport *lport, +- struct fc_els_flogi *plogi, unsigned int op) +-{ +- struct fc_els_csp *sp; +- struct fc_els_cssp *cp; +- +- memset(plogi, 0, sizeof(*plogi)); +- plogi->fl_cmd = (u8) op; +- put_unaligned_be64(lport->wwpn, &plogi->fl_wwpn); +- put_unaligned_be64(lport->wwnn, &plogi->fl_wwnn); +- +- sp = &plogi->fl_csp; +- sp->sp_hi_ver = 0x20; +- sp->sp_lo_ver = 0x20; +- sp->sp_bb_cred = htons(10); /* this gets set by gateway */ +- sp->sp_bb_data = htons((u16) lport->mfs); +- cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */ +- cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); +- if (op != ELS_FLOGI) { +- sp->sp_features = htons(FC_SP_FT_CIRO); +- sp->sp_tot_seq = htons(255); /* seq. we accept */ +- sp->sp_rel_off = htons(0x1f); +- sp->sp_e_d_tov = htonl(lport->e_d_tov); +- +- cp->cp_rdfs = htons((u16) lport->mfs); +- cp->cp_con_seq = htons(255); +- cp->cp_open_seq = 1; +- } +-} +- +-/** + * fc_rport_state_enter - Change the rport's state + * @rport: The rport whose state should change + * @new: The new state of the rport +@@ -263,7 +227,7 @@ static void fc_rport_work(struct work_struct *work) + event = rdata->event; + event_callback = rdata->event_callback; + +- if (event == LPORT_EV_RPORT_CREATED) { ++ if (event == RPORT_EV_CREATED) { + struct fc_rport *new_rport; + struct fc_rport_libfc_priv *new_rdata; + struct fc_rport_identifiers ids; +@@ -300,19 +264,20 @@ static void fc_rport_work(struct work_struct *work) + } else { + FC_DBG("Failed to create the rport for port " + "(%6x).\n", ids.port_id); +- event = LPORT_EV_RPORT_FAILED; ++ event = RPORT_EV_FAILED; + } + fc_rport_rogue_destroy(rport); + rport = new_rport; + rdata = new_rport->dd_data; +- event_callback(lport, rport, event); +- } else if ((event == LPORT_EV_RPORT_FAILED) || +- (event == LPORT_EV_RPORT_LOGO) || +- (event == LPORT_EV_RPORT_STOP)) { +- ++ if (event_callback) ++ event_callback(lport, rport, event); ++ } else if ((event == RPORT_EV_FAILED) || ++ (event == RPORT_EV_LOGO) || ++ (event == RPORT_EV_STOP)) { + trans_state = rdata->trans_state; + mutex_unlock(&rdata->rp_mutex); +- event_callback(lport, rport, event); ++ if (event_callback) ++ event_callback(lport, rport, event); + if (trans_state == FC_PORTSTATE_ROGUE) + fc_rport_rogue_destroy(rport); + else +@@ -345,45 +310,32 @@ int fc_rport_login(struct fc_rport *rport) + } + + /** +- * fc_rport_logout - Logout of the remote port and delete it +- * @rport: Fibre Channel remote port ++ * fc_rport_logoff - Logoff and remove an rport ++ * @rport: Fibre Channel remote port to be removed + * + * Locking Note: Called without the rport lock held. This + * function will hold the rport lock, call an _enter_* + * function and then unlock the rport. + */ +-int fc_rport_logout(struct fc_rport *rport) ++int fc_rport_logoff(struct fc_rport *rport) + { + struct fc_rport_libfc_priv *rdata = rport->dd_data; + + mutex_lock(&rdata->rp_mutex); + +- FC_DEBUG_RPORT("Logout of port (%6x)\n", rport->port_id); ++ FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id); + + fc_rport_enter_logo(rport); + +- mutex_unlock(&rdata->rp_mutex); +- +- return 0; +-} +- +-/** +- * fc_rport_remove - Remove an rport +- * @rport: Fibre Channel remote port to be removed +- * +- * Locking Note: Called without the rport lock held. This +- * function will hold the rport lock, call an _enter_* +- * function and then unlock the rport. +- */ +-int fc_rport_stop(struct fc_rport *rport) +-{ +- struct fc_rport_libfc_priv *rdata = rport->dd_data; +- +- mutex_lock(&rdata->rp_mutex); ++ /* ++ * Change the state to NONE so that we discard ++ * the response. ++ */ ++ fc_rport_state_enter(rport, RPORT_ST_NONE); + +- FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id); ++ cancel_delayed_work_sync(&rdata->retry_work); + +- rdata->event = LPORT_EV_RPORT_STOP; ++ rdata->event = RPORT_EV_STOP; + queue_work(rport_event_queue, &rdata->event_work); + + mutex_unlock(&rdata->rp_mutex); +@@ -406,7 +358,7 @@ static void fc_rport_enter_ready(struct fc_rport *rport) + + FC_DEBUG_RPORT("Port (%6x) is Ready\n", rport->port_id); + +- rdata->event = LPORT_EV_RPORT_CREATED; ++ rdata->event = RPORT_EV_CREATED; + queue_work(rport_event_queue, &rdata->event_work); + } + +@@ -441,9 +393,7 @@ static void fc_rport_timeout(struct work_struct *work) + break; + case RPORT_ST_READY: + case RPORT_ST_INIT: +- break; + case RPORT_ST_NONE: +- BUG(); + break; + } + put_device(&rport->dev); +@@ -487,8 +437,9 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) + case RPORT_ST_PLOGI: + case RPORT_ST_PRLI: + case RPORT_ST_LOGO: +- rdata->event = LPORT_EV_RPORT_FAILED; +- queue_work(rport_event_queue, &rdata->event_work); ++ rdata->event = RPORT_EV_FAILED; ++ queue_work(rport_event_queue, ++ &rdata->event_work); + break; + case RPORT_ST_RTV: + fc_rport_enter_ready(rport); +@@ -496,7 +447,6 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) + case RPORT_ST_NONE: + case RPORT_ST_READY: + case RPORT_ST_INIT: +- BUG(); + break; + } + } +@@ -527,7 +477,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- FC_DEBUG_RPORT("Received a PLOGI response\n"); ++ FC_DEBUG_RPORT("Received a PLOGI response from port (%6x)\n", ++ rport->port_id); + + if (rdata->rp_state != RPORT_ST_PLOGI) { + FC_DBG("Received a PLOGI response, but in state %s\n", +@@ -588,7 +539,6 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) + struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; +- struct fc_els_flogi *plogi; + + FC_DEBUG_RPORT("Port (%6x) entered PLOGI state from %s state\n", + rport->port_id, fc_rport_state(rport)); +@@ -596,23 +546,15 @@ static void fc_rport_enter_plogi(struct fc_rport *rport) + fc_rport_state_enter(rport, RPORT_ST_PLOGI); + + rport->maxframe_size = FC_MIN_MAX_PAYLOAD; +- fp = fc_frame_alloc(lport, sizeof(*plogi)); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); + if (!fp) { + fc_rport_error(rport, fp); + return; + } +- +- plogi = fc_frame_payload_get(fp, sizeof(*plogi)); +- fc_lport_plogi_fill(rdata->local_port, plogi, ELS_PLOGI); + rdata->e_d_tov = lport->e_d_tov; +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_rport_plogi_resp, NULL, +- rport, lport->e_d_tov, +- fc_host_port_id(rdata->local_port->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ ++ if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI, ++ fc_rport_plogi_resp, rport, lport->e_d_tov)) + fc_rport_error(rport, fp); + } + +@@ -641,7 +583,8 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- FC_DEBUG_RPORT("Received a PRLI response\n"); ++ FC_DEBUG_RPORT("Received a PRLI response from port (%6x)\n", ++ rport->port_id); + + if (rdata->rp_state != RPORT_ST_PRLI) { + FC_DBG("Received a PRLI response, but in state %s\n", +@@ -674,7 +617,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, + + } else { + FC_DBG("Bad ELS response\n"); +- rdata->event = LPORT_EV_RPORT_FAILED; ++ rdata->event = RPORT_EV_FAILED; + queue_work(rport_event_queue, &rdata->event_work); + } + +@@ -703,25 +646,26 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- FC_DEBUG_RPORT("Received a LOGO response\n"); +- +- if (rdata->rp_state != RPORT_ST_LOGO) { +- FC_DBG("Received a LOGO response, but in state %s\n", +- fc_rport_state(rport)); +- goto out; +- } ++ FC_DEBUG_RPORT("Received a LOGO response from port (%6x)\n", ++ rport->port_id); + + if (IS_ERR(fp)) { + fc_rport_error(rport, fp); + goto err; + } + ++ if (rdata->rp_state != RPORT_ST_LOGO) { ++ FC_DEBUG_RPORT("Received a LOGO response, but in state %s\n", ++ fc_rport_state(rport)); ++ goto out; ++ } ++ + op = fc_frame_payload_op(fp); + if (op == ELS_LS_ACC) { + fc_rport_enter_rtv(rport); + } else { + FC_DBG("Bad ELS response\n"); +- rdata->event = LPORT_EV_RPORT_LOGO; ++ rdata->event = RPORT_EV_LOGO; + queue_work(rport_event_queue, &rdata->event_work); + } + +@@ -759,22 +703,8 @@ static void fc_rport_enter_prli(struct fc_rport *rport) + return; + } + +- pp = fc_frame_payload_get(fp, sizeof(*pp)); +- memset(pp, 0, sizeof(*pp)); +- pp->prli.prli_cmd = ELS_PRLI; +- pp->prli.prli_spp_len = sizeof(struct fc_els_spp); +- pp->prli.prli_len = htons(sizeof(*pp)); +- pp->spp.spp_type = FC_TYPE_FCP; +- pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR; +- pp->spp.spp_params = htonl(lport->service_params); +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_rport_prli_resp, NULL, +- rport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI, ++ fc_rport_prli_resp, rport, lport->e_d_tov)) + fc_rport_error(rport, fp); + } + +@@ -799,7 +729,8 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, + + mutex_lock(&rdata->rp_mutex); + +- FC_DEBUG_RPORT("Received a RTV response\n"); ++ FC_DEBUG_RPORT("Received a RTV response from port (%6x)\n", ++ rport->port_id); + + if (rdata->rp_state != RPORT_ST_RTV) { + FC_DBG("Received a RTV response, but in state %s\n", +@@ -851,7 +782,6 @@ err: + */ + static void fc_rport_enter_rtv(struct fc_rport *rport) + { +- struct fc_els_rtv *rtv; + struct fc_frame *fp; + struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_lport *lport = rdata->local_port; +@@ -861,23 +791,14 @@ static void fc_rport_enter_rtv(struct fc_rport *rport) + + fc_rport_state_enter(rport, RPORT_ST_RTV); + +- fp = fc_frame_alloc(lport, sizeof(*rtv)); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv)); + if (!fp) { + fc_rport_error(rport, fp); + return; + } + +- rtv = fc_frame_payload_get(fp, sizeof(*rtv)); +- memset(rtv, 0, sizeof(*rtv)); +- rtv->rtv_cmd = ELS_RTV; +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_rport_rtv_resp, NULL, +- rport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV, ++ fc_rport_rtv_resp, rport, lport->e_d_tov)) + fc_rport_error(rport, fp); + } + +@@ -893,32 +814,20 @@ static void fc_rport_enter_logo(struct fc_rport *rport) + struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; +- struct fc_els_logo *logo; + + FC_DEBUG_RPORT("Port (%6x) entered LOGO state from %s state\n", + rport->port_id, fc_rport_state(rport)); + + fc_rport_state_enter(rport, RPORT_ST_LOGO); + +- fp = fc_frame_alloc(lport, sizeof(*logo)); ++ fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); + if (!fp) { + fc_rport_error(rport, fp); + return; + } + +- logo = fc_frame_payload_get(fp, sizeof(*logo)); +- memset(logo, 0, sizeof(*logo)); +- logo->fl_cmd = ELS_LOGO; +- hton24(logo->fl_n_port_id, fc_host_port_id(lport->host)); +- logo->fl_n_port_wwn = htonll(lport->wwpn); +- fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); +- +- if (!lport->tt.exch_seq_send(lport, fp, +- fc_rport_logo_resp, NULL, +- rport, lport->e_d_tov, +- fc_host_port_id(lport->host), +- rport->port_id, +- FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO, ++ fc_rport_logo_resp, rport, lport->e_d_tov)) + fc_rport_error(rport, fp); + } + +@@ -982,7 +891,6 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, + } + + mutex_unlock(&rdata->rp_mutex); +- fc_frame_free(fp); + } + + /** +@@ -1000,7 +908,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp = rx_fp; +- ++ struct fc_exch *ep; + struct fc_frame_header *fh; + struct fc_els_flogi *pl; + struct fc_seq_els_data rjt_data; +@@ -1089,17 +997,18 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, + rport->maxframe_size = + fc_plogi_get_maxframe(pl, lport->mfs); + fc_frame_free(rx_fp); +- pl = fc_frame_payload_get(fp, sizeof(*pl)); +- WARN_ON(!pl); +- fc_lport_plogi_fill(lport, pl, ELS_LS_ACC); ++ fc_plogi_fill(lport, fp, ELS_LS_ACC); + + /* + * Send LS_ACC. If this fails, + * the originator should retry. + */ +- f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lport->tt.seq_send(lport, sp, fp, f_ctl); ++ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; ++ f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; ++ ep = fc_seq_exch(sp); ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, ++ FC_TYPE_ELS, f_ctl, 0); ++ lport->tt.seq_send(lport, sp, fp); + if (rdata->rp_state == RPORT_ST_PLOGI) + fc_rport_enter_prli(rport); + } +@@ -1120,7 +1029,7 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + { + struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_lport *lport = rdata->local_port; +- ++ struct fc_exch *ep; + struct fc_frame *fp; + struct fc_frame_header *fh; + struct { +@@ -1234,9 +1143,12 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport, + /* + * Send LS_ACC. If this fails, the originator should retry. + */ +- f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; +- fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); +- lport->tt.seq_send(lport, sp, fp, f_ctl); ++ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; ++ f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; ++ ep = fc_seq_exch(sp); ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, ++ FC_TYPE_ELS, f_ctl, 0); ++ lport->tt.seq_send(lport, sp, fp); + + /* + * Get lock and re-check state. +@@ -1307,27 +1219,33 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, + "while in state %s\n", ntoh24(fh->fh_s_id), + fc_rport_state(rport)); + +- rdata->event = LPORT_EV_RPORT_LOGO; ++ rdata->event = RPORT_EV_LOGO; + queue_work(rport_event_queue, &rdata->event_work); + + lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + fc_frame_free(fp); + } + ++static void fc_rport_flush_queue(void) ++{ ++ flush_workqueue(rport_event_queue); ++} ++ ++ + int fc_rport_init(struct fc_lport *lport) + { + if (!lport->tt.rport_login) + lport->tt.rport_login = fc_rport_login; + +- if (!lport->tt.rport_logout) +- lport->tt.rport_logout = fc_rport_logout; +- +- if (!lport->tt.rport_stop) +- lport->tt.rport_stop = fc_rport_stop; ++ if (!lport->tt.rport_logoff) ++ lport->tt.rport_logoff = fc_rport_logoff; + + if (!lport->tt.rport_recv_req) + lport->tt.rport_recv_req = fc_rport_recv_req; + ++ if (!lport->tt.rport_flush_queue) ++ lport->tt.rport_flush_queue = fc_rport_flush_queue; ++ + return 0; + } + EXPORT_SYMBOL(fc_rport_init); +diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h +index 59c9d0c..a6118a2 100644 +--- a/include/scsi/fc/fc_fcoe.h ++++ b/include/scsi/fc/fc_fcoe.h +@@ -31,6 +31,10 @@ + #define ETH_P_FCOE 0x8906 /* FCOE ether type */ + #endif + ++#ifndef ETH_P_8021Q ++#define ETH_P_8021Q 0x8100 ++#endif ++ + /* + * FC_FCOE_OUI hasn't been standardized yet. XXX TBD. + */ +@@ -81,7 +85,9 @@ struct fcoe_crc_eof { + } __attribute__((packed)); + + /* +- * Store OUI + DID into MAC address field. ++ * fc_fcoe_set_mac - Store OUI + DID into MAC address field. ++ * @mac: mac address to be set ++ * @did: fc dest id to use + */ + static inline void fc_fcoe_set_mac(u8 *mac, u8 *did) + { +@@ -93,8 +99,4 @@ static inline void fc_fcoe_set_mac(u8 *mac, u8 *did) + mac[5] = did[2]; + } + +-#ifndef ETH_P_8021Q +-#define ETH_P_8021Q 0x8100 +-#endif +- + #endif /* _FC_FCOE_H_ */ +diff --git a/include/scsi/fc/fc_fs.h b/include/scsi/fc/fc_fs.h +index 3897c6c..3e4801d 100644 +--- a/include/scsi/fc/fc_fs.h ++++ b/include/scsi/fc/fc_fs.h +@@ -82,6 +82,12 @@ enum fc_rctl { + FC_RCTL_ELS4_REQ = 0x32, /* FC-4 ELS request */ + FC_RCTL_ELS4_REP = 0x33, /* FC-4 ELS reply */ + /* ++ * Optional Extended Headers ++ */ ++ FC_RCTL_VFTH = 0x50, /* virtual fabric tagging header */ ++ FC_RCTL_IFRH = 0x51, /* inter-fabric routing header */ ++ FC_RCTL_ENCH = 0x52, /* encapsulation header */ ++ /* + * Basic Link Services fh_r_ctl values. + */ + FC_RCTL_BA_NOP = 0x80, /* basic link service NOP */ +@@ -200,6 +206,8 @@ enum fc_fh_type { + * Exchange IDs. + */ + #define FC_XID_UNKNOWN 0xffff /* unknown exchange ID */ ++#define FC_XID_MIN 0x0 /* supported min exchange ID */ ++#define FC_XID_MAX 0xfffe /* supported max exchange ID */ + + /* + * fh_f_ctl - Frame control flags. +diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h +new file mode 100644 +index 0000000..6300f55 +--- /dev/null ++++ b/include/scsi/fc_encode.h +@@ -0,0 +1,309 @@ ++/* ++ * Copyright(c) 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_ENCODE_H_ ++#define _FC_ENCODE_H_ ++#include ++ ++struct fc_ns_rft { ++ struct fc_ns_fid fid; /* port ID object */ ++ struct fc_ns_fts fts; /* FC4-types object */ ++}; ++ ++struct fc_ct_req { ++ struct fc_ct_hdr hdr; ++ union { ++ struct fc_ns_gid_ft gid; ++ struct fc_ns_rn_id rn; ++ struct fc_ns_rft rft; ++ } payload; ++}; ++ ++/** ++ * fill FC header fields in specified fc_frame ++ */ ++static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl, ++ u32 did, u32 sid, enum fc_fh_type type, ++ u32 f_ctl, u32 parm_offset) ++{ ++ struct fc_frame_header *fh; ++ ++ fh = fc_frame_header_get(fp); ++ WARN_ON(r_ctl == 0); ++ fh->fh_r_ctl = r_ctl; ++ hton24(fh->fh_d_id, did); ++ hton24(fh->fh_s_id, sid); ++ fh->fh_type = type; ++ hton24(fh->fh_f_ctl, f_ctl); ++ fh->fh_cs_ctl = 0; ++ fh->fh_df_ctl = 0; ++ fh->fh_parm_offset = htonl(parm_offset); ++} ++ ++/** ++ * fc_ct_hdr_fill- fills ct header and reset ct payload ++ * returns pointer to ct request. ++ */ ++static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp, ++ unsigned int op, size_t req_size) ++{ ++ struct fc_ct_req *ct; ++ size_t ct_plen; ++ ++ ct_plen = sizeof(struct fc_ct_hdr) + req_size; ++ ct = fc_frame_payload_get(fp, ct_plen); ++ memset(ct, 0, ct_plen); ++ ct->hdr.ct_rev = FC_CT_REV; ++ ct->hdr.ct_fs_type = FC_FST_DIR; ++ ct->hdr.ct_fs_subtype = FC_NS_SUBTYPE; ++ ct->hdr.ct_cmd = htons((u16) op); ++ return ct; ++} ++ ++/** ++ * fc_ct_fill - Fill in a name service request frame ++ */ ++static inline int fc_ct_fill(struct fc_lport *lport, struct fc_frame *fp, ++ unsigned int op, enum fc_rctl *r_ctl, u32 *did, ++ enum fc_fh_type *fh_type) ++{ ++ struct fc_ct_req *ct; ++ ++ switch (op) { ++ case FC_NS_GPN_FT: ++ ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft)); ++ ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; ++ break; ++ ++ case FC_NS_RFT_ID: ++ ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft)); ++ hton24(ct->payload.rft.fid.fp_fid, ++ fc_host_port_id(lport->host)); ++ ct->payload.rft.fts = lport->fcts; ++ break; ++ ++ case FC_NS_RPN_ID: ++ ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id)); ++ hton24(ct->payload.rn.fr_fid.fp_fid, ++ fc_host_port_id(lport->host)); ++ ct->payload.rft.fts = lport->fcts; ++ put_unaligned_be64(lport->wwpn, &ct->payload.rn.fr_wwn); ++ break; ++ ++ default: ++ FC_DBG("Invalid op code %x \n", op); ++ return -EINVAL; ++ } ++ *r_ctl = FC_RCTL_DD_UNSOL_CTL; ++ *did = FC_FID_DIR_SERV; ++ *fh_type = FC_TYPE_CT; ++ return 0; ++} ++ ++/** ++ * fc_plogi_fill - Fill in plogi request frame ++ */ ++static inline void fc_plogi_fill(struct fc_lport *lport, struct fc_frame *fp, ++ unsigned int op) ++{ ++ struct fc_els_flogi *plogi; ++ struct fc_els_csp *csp; ++ struct fc_els_cssp *cp; ++ ++ plogi = fc_frame_payload_get(fp, sizeof(*plogi)); ++ memset(plogi, 0, sizeof(*plogi)); ++ plogi->fl_cmd = (u8) op; ++ put_unaligned_be64(lport->wwpn, &plogi->fl_wwpn); ++ put_unaligned_be64(lport->wwnn, &plogi->fl_wwnn); ++ ++ csp = &plogi->fl_csp; ++ csp->sp_hi_ver = 0x20; ++ csp->sp_lo_ver = 0x20; ++ csp->sp_bb_cred = htons(10); /* this gets set by gateway */ ++ csp->sp_bb_data = htons((u16) lport->mfs); ++ cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */ ++ cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); ++ csp->sp_features = htons(FC_SP_FT_CIRO); ++ csp->sp_tot_seq = htons(255); /* seq. we accept */ ++ csp->sp_rel_off = htons(0x1f); ++ csp->sp_e_d_tov = htonl(lport->e_d_tov); ++ ++ cp->cp_rdfs = htons((u16) lport->mfs); ++ cp->cp_con_seq = htons(255); ++ cp->cp_open_seq = 1; ++} ++ ++/** ++ * fc_flogi_fill - Fill in a flogi request frame. ++ */ ++static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ struct fc_els_csp *sp; ++ struct fc_els_cssp *cp; ++ struct fc_els_flogi *flogi; ++ ++ flogi = fc_frame_payload_get(fp, sizeof(*flogi)); ++ memset(flogi, 0, sizeof(*flogi)); ++ flogi->fl_cmd = (u8) ELS_FLOGI; ++ put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn); ++ put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn); ++ sp = &flogi->fl_csp; ++ sp->sp_hi_ver = 0x20; ++ sp->sp_lo_ver = 0x20; ++ sp->sp_bb_cred = htons(10); /* this gets set by gateway */ ++ sp->sp_bb_data = htons((u16) lport->mfs); ++ cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ ++ cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); ++} ++ ++/** ++ * fc_logo_fill - Fill in a logo request frame. ++ */ ++static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ struct fc_els_logo *logo; ++ ++ logo = fc_frame_payload_get(fp, sizeof(*logo)); ++ memset(logo, 0, sizeof(*logo)); ++ logo->fl_cmd = ELS_LOGO; ++ hton24(logo->fl_n_port_id, fc_host_port_id(lport->host)); ++ logo->fl_n_port_wwn = htonll(lport->wwpn); ++} ++ ++/** ++ * fc_rtv_fill - Fill in RTV (read timeout value) request frame. ++ */ ++static inline void fc_rtv_fill(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ struct fc_els_rtv *rtv; ++ ++ rtv = fc_frame_payload_get(fp, sizeof(*rtv)); ++ memset(rtv, 0, sizeof(*rtv)); ++ rtv->rtv_cmd = ELS_RTV; ++} ++ ++/** ++ * fc_rec_fill - Fill in rec request frame ++ */ ++static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ struct fc_els_rec *rec; ++ struct fc_exch *ep = fc_seq_exch(fr_seq(fp)); ++ ++ rec = fc_frame_payload_get(fp, sizeof(*rec)); ++ memset(rec, 0, sizeof(*rec)); ++ rec->rec_cmd = ELS_REC; ++ hton24(rec->rec_s_id, fc_host_port_id(lport->host)); ++ rec->rec_ox_id = htons(ep->oxid); ++ rec->rec_rx_id = htons(ep->rxid); ++} ++ ++/** ++ * fc_prli_fill - Fill in prli request frame ++ */ ++static inline void fc_prli_fill(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ struct { ++ struct fc_els_prli prli; ++ struct fc_els_spp spp; ++ } *pp; ++ ++ pp = fc_frame_payload_get(fp, sizeof(*pp)); ++ memset(pp, 0, sizeof(*pp)); ++ pp->prli.prli_cmd = ELS_PRLI; ++ pp->prli.prli_spp_len = sizeof(struct fc_els_spp); ++ pp->prli.prli_len = htons(sizeof(*pp)); ++ pp->spp.spp_type = FC_TYPE_FCP; ++ pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR; ++ pp->spp.spp_params = htonl(lport->service_params); ++} ++ ++/** ++ * fc_scr_fill - Fill in a scr request frame. ++ */ ++static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp) ++{ ++ struct fc_els_scr *scr; ++ ++ scr = fc_frame_payload_get(fp, sizeof(*scr)); ++ memset(scr, 0, sizeof(*scr)); ++ scr->scr_cmd = ELS_SCR; ++ scr->scr_reg_func = ELS_SCRF_FULL; ++} ++ ++/** ++ * fc_els_fill - Fill in an ELS request frame ++ */ ++static inline int fc_els_fill(struct fc_lport *lport, struct fc_rport *rport, ++ struct fc_frame *fp, unsigned int op, ++ enum fc_rctl *r_ctl, u32 *did, enum fc_fh_type *fh_type) ++{ ++ switch (op) { ++ case ELS_PLOGI: ++ fc_plogi_fill(lport, fp, ELS_PLOGI); ++ *did = rport->port_id; ++ break; ++ ++ case ELS_FLOGI: ++ fc_flogi_fill(lport, fp); ++ *did = FC_FID_FLOGI; ++ break; ++ ++ case ELS_LOGO: ++ fc_logo_fill(lport, fp); ++ *did = FC_FID_FLOGI; ++ /* ++ * if rport is valid then it ++ * is port logo, therefore ++ * set did to rport id. ++ */ ++ if (rport) ++ *did = rport->port_id; ++ break; ++ ++ case ELS_RTV: ++ fc_rtv_fill(lport, fp); ++ *did = rport->port_id; ++ break; ++ ++ case ELS_REC: ++ fc_rec_fill(lport, fp); ++ *did = rport->port_id; ++ break; ++ ++ case ELS_PRLI: ++ fc_prli_fill(lport, fp); ++ *did = rport->port_id; ++ break; ++ ++ case ELS_SCR: ++ fc_scr_fill(lport, fp); ++ *did = FC_FID_FCTRL; ++ break; ++ ++ default: ++ FC_DBG("Invalid op code %x \n", op); ++ return -EINVAL; ++ } ++ ++ *r_ctl = FC_RCTL_ELS_REQ; ++ *fh_type = FC_TYPE_ELS; ++ return 0; ++} ++#endif /* _FC_ENCODE_H_ */ +diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h +new file mode 100644 +index 0000000..dc5f734 +--- /dev/null ++++ b/include/scsi/fc_frame.h +@@ -0,0 +1,239 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_FRAME_H_ ++#define _FC_FRAME_H_ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * The fc_frame interface is used to pass frame data between functions. ++ * The frame includes the data buffer, length, and SOF / EOF delimiter types. ++ * A pointer to the port structure of the receiving port is also includeded. ++ */ ++ ++#define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */ ++#define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */ ++ ++/* ++ * Information about an individual fibre channel frame received or to be sent. ++ * The buffer may be in up to 4 additional non-contiguous sections, ++ * but the linear section must hold the frame header. ++ */ ++#define FC_FRAME_SG_LEN 4 /* scatter/gather list maximum length */ ++ ++#define fp_skb(fp) (&((fp)->skb)) ++#define fr_hdr(fp) ((fp)->skb.data) ++#define fr_len(fp) ((fp)->skb.len) ++#define fr_cb(fp) ((struct fcoe_rcv_info *)&((fp)->skb.cb[0])) ++#define fr_dev(fp) (fr_cb(fp)->fr_dev) ++#define fr_seq(fp) (fr_cb(fp)->fr_seq) ++#define fr_sof(fp) (fr_cb(fp)->fr_sof) ++#define fr_eof(fp) (fr_cb(fp)->fr_eof) ++#define fr_flags(fp) (fr_cb(fp)->fr_flags) ++#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) ++#define fr_cmd(fp) (fr_cb(fp)->fr_cmd) ++#define fr_dir(fp) (fr_cmd(fp)->sc_data_direction) ++ ++struct fc_frame { ++ struct sk_buff skb; ++}; ++ ++struct fcoe_rcv_info { ++ struct packet_type *ptype; ++ struct fc_lport *fr_dev; /* transport layer private pointer */ ++ struct fc_seq *fr_seq; /* for use with exchange manager */ ++ struct scsi_cmnd *fr_cmd; /* for use of scsi command */ ++ enum fc_sof fr_sof; /* start of frame delimiter */ ++ enum fc_eof fr_eof; /* end of frame delimiter */ ++ u8 fr_flags; /* flags - see below */ ++ u16 fr_max_payload; /* max FC payload */ ++}; ++ ++/* ++ * Get fc_frame pointer for an skb that's already been imported. ++ */ ++static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb) ++{ ++ BUILD_BUG_ON(sizeof(struct fcoe_rcv_info) > sizeof(skb->cb)); ++ return (struct fcoe_rcv_info *) skb->cb; ++} ++ ++/* ++ * fr_flags. ++ */ ++#define FCPHF_CRC_UNCHECKED 0x01 /* CRC not computed, still appended */ ++ ++/* ++ * Initialize a frame. ++ * We don't do a complete memset here for performance reasons. ++ * The caller must set fr_free, fr_hdr, fr_len, fr_sof, and fr_eof eventually. ++ */ ++static inline void fc_frame_init(struct fc_frame *fp) ++{ ++ fr_dev(fp) = NULL; ++ fr_seq(fp) = NULL; ++ fr_flags(fp) = 0; ++} ++ ++struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len); ++ ++struct fc_frame *__fc_frame_alloc(size_t payload_len); ++ ++/* ++ * Get frame for sending via port. ++ */ ++static inline struct fc_frame *_fc_frame_alloc(struct fc_lport *dev, ++ size_t payload_len) ++{ ++ return __fc_frame_alloc(payload_len); ++} ++ ++/* ++ * Allocate fc_frame structure and buffer. Set the initial length to ++ * payload_size + sizeof (struct fc_frame_header). ++ */ ++static inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len) ++{ ++ struct fc_frame *fp; ++ ++ /* ++ * Note: Since len will often be a constant multiple of 4, ++ * this check will usually be evaluated and eliminated at compile time. ++ */ ++ if ((len % 4) != 0) ++ fp = fc_frame_alloc_fill(dev, len); ++ else ++ fp = _fc_frame_alloc(dev, len); ++ return fp; ++} ++ ++/* ++ * Free the fc_frame structure and buffer. ++ */ ++static inline void fc_frame_free(struct fc_frame *fp) ++{ ++ kfree_skb(fp_skb(fp)); ++} ++ ++static inline int fc_frame_is_linear(struct fc_frame *fp) ++{ ++ return !skb_is_nonlinear(fp_skb(fp)); ++} ++ ++/* ++ * Get frame header from message in fc_frame structure. ++ * This hides a cast and provides a place to add some checking. ++ */ ++static inline ++struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp) ++{ ++ WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header)); ++ return (struct fc_frame_header *) fr_hdr(fp); ++} ++ ++/* ++ * Get frame payload from message in fc_frame structure. ++ * This hides a cast and provides a place to add some checking. ++ * The len parameter is the minimum length for the payload portion. ++ * Returns NULL if the frame is too short. ++ * ++ * This assumes the interesting part of the payload is in the first part ++ * of the buffer for received data. This may not be appropriate to use for ++ * buffers being transmitted. ++ */ ++static inline void *fc_frame_payload_get(const struct fc_frame *fp, ++ size_t len) ++{ ++ void *pp = NULL; ++ ++ if (fr_len(fp) >= sizeof(struct fc_frame_header) + len) ++ pp = fc_frame_header_get(fp) + 1; ++ return pp; ++} ++ ++/* ++ * Get frame payload opcode (first byte) from message in fc_frame structure. ++ * This hides a cast and provides a place to add some checking. Return 0 ++ * if the frame has no payload. ++ */ ++static inline u8 fc_frame_payload_op(const struct fc_frame *fp) ++{ ++ u8 *cp; ++ ++ cp = fc_frame_payload_get(fp, sizeof(u8)); ++ if (!cp) ++ return 0; ++ return *cp; ++ ++} ++ ++/* ++ * Get FC class from frame. ++ */ ++static inline enum fc_class fc_frame_class(const struct fc_frame *fp) ++{ ++ return fc_sof_class(fr_sof(fp)); ++} ++ ++/* ++ * Check the CRC in a frame. ++ * The CRC immediately follows the last data item *AFTER* the length. ++ * The return value is zero if the CRC matches. ++ */ ++u32 fc_frame_crc_check(struct fc_frame *); ++ ++static inline u8 fc_frame_rctl(const struct fc_frame *fp) ++{ ++ return fc_frame_header_get(fp)->fh_r_ctl; ++} ++ ++static inline bool fc_frame_is_cmd(const struct fc_frame *fp) ++{ ++ return fc_frame_rctl(fp) == FC_RCTL_DD_UNSOL_CMD; ++} ++ ++static inline bool fc_frame_is_read(const struct fc_frame *fp) ++{ ++ if (fc_frame_is_cmd(fp) && fr_cmd(fp)) ++ return fr_dir(fp) == DMA_FROM_DEVICE; ++ return false; ++} ++ ++static inline bool fc_frame_is_write(const struct fc_frame *fp) ++{ ++ if (fc_frame_is_cmd(fp) && fr_cmd(fp)) ++ return fr_dir(fp) == DMA_TO_DEVICE; ++ return false; ++} ++ ++/* ++ * Check for leaks. ++ * Print the frame header of any currently allocated frame, assuming there ++ * should be none at this point. ++ */ ++void fc_frame_leak_check(void); ++ ++#endif /* _FC_FRAME_H_ */ +diff --git a/include/scsi/fc_transport_fcoe.h b/include/scsi/fc_transport_fcoe.h +new file mode 100644 +index 0000000..8dca2af +--- /dev/null ++++ b/include/scsi/fc_transport_fcoe.h +@@ -0,0 +1,54 @@ ++#ifndef FC_TRANSPORT_FCOE_H ++#define FC_TRANSPORT_FCOE_H ++ ++#include ++#include ++#include ++#include ++ ++/** ++ * struct fcoe_transport - FCoE transport struct for generic transport ++ * for Ethernet devices as well as pure HBAs ++ * ++ * @name: name for thsi transport ++ * @bus: physical bus type (pci_bus_type) ++ * @driver: physical bus driver for network device ++ * @create: entry create function ++ * @destroy: exit destroy function ++ * @list: list of transports ++ */ ++struct fcoe_transport { ++ char *name; ++ unsigned short vendor; ++ unsigned short device; ++ struct bus_type *bus; ++ struct device_driver *driver; ++ int (*create)(struct net_device *device); ++ int (*destroy)(struct net_device *device); ++ bool (*match)(struct net_device *device); ++ struct list_head list; ++ struct list_head devlist; ++ struct mutex devlock; ++}; ++ ++/** ++ * MODULE_ALIAS_FCOE_PCI ++ * ++ * some care must be taken with this, vendor and device MUST be a hex value ++ * preceded with 0x and with letters in lower case (0x12ab, not 0x12AB or 12AB) ++ */ ++#define MODULE_ALIAS_FCOE_PCI(vendor, device) \ ++ MODULE_ALIAS("fcoe-pci-" __stringify(vendor) "-" __stringify(device)) ++ ++/* exported funcs */ ++int fcoe_transport_attach(struct net_device *netdev); ++int fcoe_transport_release(struct net_device *netdev); ++int fcoe_transport_register(struct fcoe_transport *t); ++int fcoe_transport_unregister(struct fcoe_transport *t); ++int fcoe_load_transport_driver(struct net_device *netdev); ++int __init fcoe_transport_init(void); ++int __exit fcoe_transport_exit(void); ++ ++/* fcow_sw is the default transport */ ++extern struct fcoe_transport fcoe_sw_transport; ++#endif /* FC_TRANSPORT_FCOE_H */ +diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h +new file mode 100644 +index 0000000..dac03e2 +--- /dev/null ++++ b/include/scsi/libfc.h +@@ -0,0 +1,917 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _LIBFC_H_ ++#define _LIBFC_H_ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define LIBFC_DEBUG ++ ++#ifdef LIBFC_DEBUG ++/* Log messages */ ++#define FC_DBG(fmt, args...) \ ++ do { \ ++ printk(KERN_INFO "%s " fmt, __func__, ##args); \ ++ } while (0) ++#else ++#define FC_DBG(fmt, args...) ++#endif ++ ++/* ++ * libfc error codes ++ */ ++#define FC_NO_ERR 0 /* no error */ ++#define FC_EX_TIMEOUT 1 /* Exchange timeout */ ++#define FC_EX_CLOSED 2 /* Exchange closed */ ++ ++/* some helpful macros */ ++ ++#define ntohll(x) be64_to_cpu(x) ++#define htonll(x) cpu_to_be64(x) ++ ++#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) ++ ++#define hton24(p, v) do { \ ++ p[0] = (((v) >> 16) & 0xFF); \ ++ p[1] = (((v) >> 8) & 0xFF); \ ++ p[2] = ((v) & 0xFF); \ ++ } while (0) ++ ++/* ++ * FC HBA status ++ */ ++#define FC_PAUSE (1 << 1) ++#define FC_LINK_UP (1 << 0) ++ ++enum fc_lport_state { ++ LPORT_ST_NONE = 0, ++ LPORT_ST_FLOGI, ++ LPORT_ST_DNS, ++ LPORT_ST_RPN_ID, ++ LPORT_ST_RFT_ID, ++ LPORT_ST_SCR, ++ LPORT_ST_READY, ++ LPORT_ST_LOGO, ++ LPORT_ST_RESET ++}; ++ ++enum fc_disc_event { ++ DISC_EV_NONE = 0, ++ DISC_EV_SUCCESS, ++ DISC_EV_FAILED ++}; ++ ++enum fc_lport_event { ++ RPORT_EV_NONE = 0, ++ RPORT_EV_CREATED, ++ RPORT_EV_FAILED, ++ RPORT_EV_STOP, ++ RPORT_EV_LOGO ++}; ++ ++enum fc_rport_state { ++ RPORT_ST_NONE = 0, ++ RPORT_ST_INIT, /* initialized */ ++ RPORT_ST_PLOGI, /* waiting for PLOGI completion */ ++ RPORT_ST_PRLI, /* waiting for PRLI completion */ ++ RPORT_ST_RTV, /* waiting for RTV completion */ ++ RPORT_ST_READY, /* ready for use */ ++ RPORT_ST_LOGO, /* port logout sent */ ++}; ++ ++enum fc_rport_trans_state { ++ FC_PORTSTATE_ROGUE, ++ FC_PORTSTATE_REAL, ++}; ++ ++/** ++ * struct fc_disc_port - temporary discovery port to hold rport identifiers ++ * @lp: Fibre Channel host port instance ++ * @peers: node for list management during discovery and RSCN processing ++ * @ids: identifiers structure to pass to fc_remote_port_add() ++ * @rport_work: work struct for starting the rport state machine ++ */ ++struct fc_disc_port { ++ struct fc_lport *lp; ++ struct list_head peers; ++ struct fc_rport_identifiers ids; ++ struct work_struct rport_work; ++}; ++ ++/** ++ * struct fc_rport_libfc_priv - libfc internal information about a remote port ++ * @local_port: Fibre Channel host port instance ++ * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges ++ * @flags: REC and RETRY supported flags ++ * @max_seq: maximum number of concurrent sequences ++ * @retries: retry count in current state ++ * @e_d_tov: error detect timeout value (in msec) ++ * @r_a_tov: resource allocation timeout value (in msec) ++ * @rp_mutex: mutex protects rport ++ * @retry_work: ++ * @event_callback: Callback for rport READY, FAILED or LOGO ++ */ ++struct fc_rport_libfc_priv { ++ struct fc_lport *local_port; ++ enum fc_rport_state rp_state; ++ u16 flags; ++ #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) ++ #define FC_RP_FLAGS_RETRY (1 << 1) ++ u16 max_seq; ++ unsigned int retries; ++ unsigned int e_d_tov; ++ unsigned int r_a_tov; ++ enum fc_rport_trans_state trans_state; ++ struct mutex rp_mutex; ++ struct delayed_work retry_work; ++ enum fc_lport_event event; ++ void (*event_callback)(struct fc_lport *, ++ struct fc_rport *, ++ enum fc_lport_event); ++ struct list_head peers; ++ struct work_struct event_work; ++}; ++ ++#define PRIV_TO_RPORT(x) \ ++ (struct fc_rport *)((void *)x - sizeof(struct fc_rport)); ++#define RPORT_TO_PRIV(x) \ ++ (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); ++ ++struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *); ++void fc_rport_rogue_destroy(struct fc_rport *); ++ ++static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) ++{ ++ rport->node_name = wwnn; ++ rport->port_name = wwpn; ++} ++ ++/* ++ * fcoe stats structure ++ */ ++struct fcoe_dev_stats { ++ u64 SecondsSinceLastReset; ++ u64 TxFrames; ++ u64 TxWords; ++ u64 RxFrames; ++ u64 RxWords; ++ u64 ErrorFrames; ++ u64 DumpedFrames; ++ u64 LinkFailureCount; ++ u64 LossOfSignalCount; ++ u64 InvalidTxWordCount; ++ u64 InvalidCRCCount; ++ u64 InputRequests; ++ u64 OutputRequests; ++ u64 ControlRequests; ++ u64 InputMegabytes; ++ u64 OutputMegabytes; ++}; ++ ++/* ++ * els data is used for passing ELS respone specific ++ * data to send ELS response mainly using infomation ++ * in exchange and sequence in EM layer. ++ */ ++struct fc_seq_els_data { ++ struct fc_frame *fp; ++ enum fc_els_rjt_reason reason; ++ enum fc_els_rjt_explan explan; ++}; ++ ++/* ++ * FCP request structure, one for each scsi cmd request ++ */ ++struct fc_fcp_pkt { ++ /* ++ * housekeeping stuff ++ */ ++ struct fc_lport *lp; /* handle to hba struct */ ++ u16 state; /* scsi_pkt state state */ ++ u16 tgt_flags; /* target flags */ ++ atomic_t ref_cnt; /* fcp pkt ref count */ ++ spinlock_t scsi_pkt_lock; /* Must be taken before the host lock ++ * if both are held at the same time */ ++ /* ++ * SCSI I/O related stuff ++ */ ++ struct scsi_cmnd *cmd; /* scsi command pointer. set/clear ++ * under host lock */ ++ struct list_head list; /* tracks queued commands. access under ++ * host lock */ ++ /* ++ * timeout related stuff ++ */ ++ struct timer_list timer; /* command timer */ ++ struct completion tm_done; ++ int wait_for_comp; ++ unsigned long start_time; /* start jiffie */ ++ unsigned long end_time; /* end jiffie */ ++ unsigned long last_pkt_time; /* jiffies of last frame received */ ++ ++ /* ++ * scsi cmd and data transfer information ++ */ ++ u32 data_len; ++ /* ++ * transport related veriables ++ */ ++ struct fcp_cmnd cdb_cmd; ++ size_t xfer_len; ++ u32 xfer_contig_end; /* offset of end of contiguous xfer */ ++ u16 max_payload; /* max payload size in bytes */ ++ ++ /* ++ * scsi/fcp return status ++ */ ++ u32 io_status; /* SCSI result upper 24 bits */ ++ u8 cdb_status; ++ u8 status_code; /* FCP I/O status */ ++ /* bit 3 Underrun bit 2: overrun */ ++ u8 scsi_comp_flags; ++ u32 req_flags; /* bit 0: read bit:1 write */ ++ u32 scsi_resid; /* residule length */ ++ ++ struct fc_rport *rport; /* remote port pointer */ ++ struct fc_seq *seq_ptr; /* current sequence pointer */ ++ /* ++ * Error Processing ++ */ ++ u8 recov_retry; /* count of recovery retries */ ++ struct fc_seq *recov_seq; /* sequence for REC or SRR */ ++}; ++ ++/* ++ * Structure and function definitions for managing Fibre Channel Exchanges ++ * and Sequences ++ * ++ * fc_exch holds state for one exchange and links to its active sequence. ++ * ++ * fc_seq holds the state for an individual sequence. ++ */ ++ ++struct fc_exch_mgr; ++ ++/* ++ * Sequence. ++ */ ++struct fc_seq { ++ u8 id; /* seq ID */ ++ u16 ssb_stat; /* status flags for sequence status block */ ++ u16 cnt; /* frames sent so far on sequence */ ++ u32 f_ctl; /* F_CTL flags for frames */ ++ u32 rec_data; /* FC-4 value for REC */ ++}; ++ ++#define FC_EX_DONE (1 << 0) /* ep is completed */ ++#define FC_EX_RST_CLEANUP (1 << 1) /* reset is forcing completion */ ++ ++/* ++ * Exchange. ++ * ++ * Locking notes: The ex_lock protects changes to the following fields: ++ * esb_stat, f_ctl, seq.ssb_stat, seq.f_ctl. ++ * seq_id ++ * sequence allocation ++ * ++ */ ++struct fc_exch { ++ struct fc_exch_mgr *em; /* exchange manager */ ++ u32 state; /* internal driver state */ ++ u16 xid; /* our exchange ID */ ++ struct list_head ex_list; /* free or busy list linkage */ ++ spinlock_t ex_lock; /* lock covering exchange state */ ++ atomic_t ex_refcnt; /* reference counter */ ++ struct delayed_work timeout_work; /* timer for upper level protocols */ ++ struct fc_lport *lp; /* fc device instance */ ++ u16 oxid; /* originator's exchange ID */ ++ u16 rxid; /* responder's exchange ID */ ++ u32 oid; /* originator's FCID */ ++ u32 sid; /* source FCID */ ++ u32 did; /* destination FCID */ ++ u32 esb_stat; /* exchange status for ESB */ ++ u32 r_a_tov; /* r_a_tov from rport (msec) */ ++ u8 seq_id; /* next sequence ID to use */ ++ u32 f_ctl; /* F_CTL flags for sequences */ ++ u8 fh_type; /* frame type */ ++ enum fc_class class; /* class of service */ ++ struct fc_seq seq; /* single sequence */ ++ /* ++ * Handler for responses to this current exchange. ++ */ ++ void (*resp)(struct fc_seq *, struct fc_frame *, void *); ++ void (*destructor)(struct fc_seq *, void *); ++ /* ++ * arg is passed as void pointer to exchange ++ * resp and destructor handlers ++ */ ++ void *arg; ++}; ++#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) ++ ++struct libfc_function_template { ++ ++ /** ++ * Mandatory Fields ++ * ++ * These handlers must be implemented by the LLD. ++ */ ++ ++ /* ++ * Interface to send a FC frame ++ */ ++ int (*frame_send)(struct fc_lport *lp, struct fc_frame *fp); ++ ++ /** ++ * Optional Fields ++ * ++ * The LLD may choose to implement any of the following handlers. ++ * If LLD doesn't specify hander and leaves its pointer NULL then ++ * the default libfc function will be used for that handler. ++ */ ++ ++ /** ++ * ELS/CT interfaces ++ */ ++ ++ /* ++ * elsct_send - sends ELS/CT frame ++ */ ++ struct fc_seq *(*elsct_send)(struct fc_lport *lport, ++ struct fc_rport *rport, ++ struct fc_frame *fp, ++ unsigned int op, ++ void (*resp)(struct fc_seq *, ++ struct fc_frame *fp, ++ void *arg), ++ void *arg, u32 timer_msec); ++ /** ++ * Exhance Manager interfaces ++ */ ++ ++ /* ++ * Send the FC frame payload using a new exchange and sequence. ++ * ++ * The frame pointer with some of the header's fields must be ++ * filled before calling exch_seq_send(), those fields are, ++ * ++ * - routing control ++ * - FC port did ++ * - FC port sid ++ * - FC header type ++ * - frame control ++ * - parameter or relative offset ++ * ++ * The exchange response handler is set in this routine to resp() ++ * function pointer. It can be called in two scenarios: if a timeout ++ * occurs or if a response frame is received for the exchange. The ++ * fc_frame pointer in response handler will also indicate timeout ++ * as error using IS_ERR related macros. ++ * ++ * The exchange destructor handler is also set in this routine. ++ * The destructor handler is invoked by EM layer when exchange ++ * is about to free, this can be used by caller to free its ++ * resources along with exchange free. ++ * ++ * The arg is passed back to resp and destructor handler. ++ * ++ * The timeout value (in msec) for an exchange is set if non zero ++ * timer_msec argument is specified. The timer is canceled when ++ * it fires or when the exchange is done. The exchange timeout handler ++ * is registered by EM layer. ++ */ ++ struct fc_seq *(*exch_seq_send)(struct fc_lport *lp, ++ struct fc_frame *fp, ++ void (*resp)(struct fc_seq *sp, ++ struct fc_frame *fp, ++ void *arg), ++ void (*destructor)(struct fc_seq *sp, ++ void *arg), ++ void *arg, unsigned int timer_msec); ++ ++ /* ++ * send a frame using existing sequence and exchange. ++ */ ++ int (*seq_send)(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp); ++ ++ /* ++ * Send ELS response using mainly infomation ++ * in exchange and sequence in EM layer. ++ */ ++ void (*seq_els_rsp_send)(struct fc_seq *sp, enum fc_els_cmd els_cmd, ++ struct fc_seq_els_data *els_data); ++ ++ /* ++ * Abort an exchange and sequence. Generally called because of a ++ * exchange timeout or an abort from the upper layer. ++ * ++ * A timer_msec can be specified for abort timeout, if non-zero ++ * timer_msec value is specified then exchange resp handler ++ * will be called with timeout error if no response to abort. ++ */ ++ int (*seq_exch_abort)(const struct fc_seq *req_sp, ++ unsigned int timer_msec); ++ ++ /* ++ * Indicate that an exchange/sequence tuple is complete and the memory ++ * allocated for the related objects may be freed. ++ */ ++ void (*exch_done)(struct fc_seq *sp); ++ ++ /* ++ * Assigns a EM and a free XID for an new exchange and then ++ * allocates a new exchange and sequence pair. ++ * The fp can be used to determine free XID. ++ */ ++ struct fc_exch *(*exch_get)(struct fc_lport *lp, struct fc_frame *fp); ++ ++ /* ++ * Release previously assigned XID by exch_get API. ++ * The LLD may implement this if XID is assigned by LLD ++ * in exch_get(). ++ */ ++ void (*exch_put)(struct fc_lport *lp, struct fc_exch_mgr *mp, ++ u16 ex_id); ++ ++ /* ++ * Start a new sequence on the same exchange/sequence tuple. ++ */ ++ struct fc_seq *(*seq_start_next)(struct fc_seq *sp); ++ ++ /* ++ * Reset an exchange manager, completing all sequences and exchanges. ++ * If s_id is non-zero, reset only exchanges originating from that FID. ++ * If d_id is non-zero, reset only exchanges sending to that FID. ++ */ ++ void (*exch_mgr_reset)(struct fc_exch_mgr *, ++ u32 s_id, u32 d_id); ++ ++ void (*rport_flush_queue)(void); ++ /** ++ * Local Port interfaces ++ */ ++ ++ /* ++ * Receive a frame to a local port. ++ */ ++ void (*lport_recv)(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp); ++ ++ int (*lport_reset)(struct fc_lport *); ++ ++ /** ++ * Remote Port interfaces ++ */ ++ ++ /* ++ * Initiates the RP state machine. It is called from the LP module. ++ * This function will issue the following commands to the N_Port ++ * identified by the FC ID provided. ++ * ++ * - PLOGI ++ * - PRLI ++ * - RTV ++ */ ++ int (*rport_login)(struct fc_rport *rport); ++ ++ /* ++ * Logoff, and remove the rport from the transport if ++ * it had been added. This will send a LOGO to the target. ++ */ ++ int (*rport_logoff)(struct fc_rport *rport); ++ ++ /* ++ * Recieve a request from a remote port. ++ */ ++ void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, ++ struct fc_rport *); ++ ++ struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); ++ ++ /** ++ * FCP interfaces ++ */ ++ ++ /* ++ * Send a fcp cmd from fsp pkt. ++ * Called with the SCSI host lock unlocked and irqs disabled. ++ * ++ * The resp handler is called when FCP_RSP received. ++ * ++ */ ++ int (*fcp_cmd_send)(struct fc_lport *lp, struct fc_fcp_pkt *fsp, ++ void (*resp)(struct fc_seq *, struct fc_frame *fp, ++ void *arg)); ++ ++ /* ++ * Used at least durring linkdown and reset ++ */ ++ void (*fcp_cleanup)(struct fc_lport *lp); ++ ++ /* ++ * Abort all I/O on a local port ++ */ ++ void (*fcp_abort_io)(struct fc_lport *lp); ++ ++ /** ++ * Discovery interfaces ++ */ ++ ++ void (*disc_recv_req)(struct fc_seq *, ++ struct fc_frame *, struct fc_lport *); ++ ++ /* ++ * Start discovery for a local port. ++ */ ++ void (*disc_start)(void (*disc_callback)(struct fc_lport *, ++ enum fc_disc_event), ++ struct fc_lport *); ++ ++ /* ++ * Stop discovery for a given lport. This will remove ++ * all discovered rports ++ */ ++ void (*disc_stop) (struct fc_lport *); ++ ++ /* ++ * Stop discovery for a given lport. This will block ++ * until all discovered rports are deleted from the ++ * FC transport class ++ */ ++ void (*disc_stop_final) (struct fc_lport *); ++}; ++ ++struct fc_lport { ++ struct list_head list; ++ ++ /* Associations */ ++ struct Scsi_Host *host; ++ struct fc_exch_mgr *emp; ++ struct fc_rport *dns_rp; ++ struct fc_rport *ptp_rp; ++ void *scsi_priv; ++ ++ /* Operational Information */ ++ struct libfc_function_template tt; ++ u16 link_status; ++ enum fc_lport_state state; ++ unsigned long boot_time; ++ ++ struct fc_host_statistics host_stats; ++ struct fcoe_dev_stats *dev_stats[NR_CPUS]; ++ u64 wwpn; ++ u64 wwnn; ++ u8 retry_count; ++ ++ /* Capabilities */ ++ u32 sg_supp:1; /* scatter gather supported */ ++ u32 seq_offload:1; /* seq offload supported */ ++ u32 crc_offload:1; /* crc offload supported */ ++ u32 lro_enabled:1; /* large receive offload */ ++ u32 mfs; /* max FC payload size */ ++ unsigned int service_params; ++ unsigned int e_d_tov; ++ unsigned int r_a_tov; ++ u8 max_retry_count; ++ u16 link_speed; ++ u16 link_supported_speeds; ++ u16 lro_xid; /* max xid for fcoe lro */ ++ struct fc_ns_fts fcts; /* FC-4 type masks */ ++ struct fc_els_rnid_gen rnid_gen; /* RNID information */ ++ ++ /* Semaphores */ ++ struct mutex lp_mutex; ++ ++ /* Miscellaneous */ ++ struct delayed_work retry_work; ++ struct delayed_work disc_work; ++}; ++ ++/** ++ * FC_LPORT HELPER FUNCTIONS ++ *****************************/ ++static inline void *lport_priv(const struct fc_lport *lp) ++{ ++ return (void *)(lp + 1); ++} ++ ++static inline int fc_lport_test_ready(struct fc_lport *lp) ++{ ++ return lp->state == LPORT_ST_READY; ++} ++ ++static inline void fc_set_wwnn(struct fc_lport *lp, u64 wwnn) ++{ ++ lp->wwnn = wwnn; ++} ++ ++static inline void fc_set_wwpn(struct fc_lport *lp, u64 wwnn) ++{ ++ lp->wwpn = wwnn; ++} ++ ++static inline void fc_lport_state_enter(struct fc_lport *lp, ++ enum fc_lport_state state) ++{ ++ if (state != lp->state) ++ lp->retry_count = 0; ++ lp->state = state; ++} ++ ++ ++/** ++ * LOCAL PORT LAYER ++ *****************************/ ++int fc_lport_init(struct fc_lport *lp); ++ ++/* ++ * Destroy the specified local port by finding and freeing all ++ * fc_rports associated with it and then by freeing the fc_lport ++ * itself. ++ */ ++int fc_lport_destroy(struct fc_lport *lp); ++ ++/* ++ * Logout the specified local port from the fabric ++ */ ++int fc_fabric_logoff(struct fc_lport *lp); ++ ++/* ++ * Initiate the LP state machine. This handler will use fc_host_attr ++ * to store the FLOGI service parameters, so fc_host_attr must be ++ * initialized before calling this handler. ++ */ ++int fc_fabric_login(struct fc_lport *lp); ++ ++/* ++ * The link is up for the given local port. ++ */ ++void fc_linkup(struct fc_lport *); ++ ++/* ++ * Link is down for the given local port. ++ */ ++void fc_linkdown(struct fc_lport *); ++ ++/* ++ * Pause and unpause traffic. ++ */ ++void fc_pause(struct fc_lport *); ++void fc_unpause(struct fc_lport *); ++ ++/* ++ * Configure the local port. ++ */ ++int fc_lport_config(struct fc_lport *); ++ ++/* ++ * Reset the local port. ++ */ ++int fc_lport_reset(struct fc_lport *); ++ ++/* ++ * Set the mfs or reset ++ */ ++int fc_set_mfs(struct fc_lport *lp, u32 mfs); ++ ++ ++/** ++ * REMOTE PORT LAYER ++ *****************************/ ++int fc_rport_init(struct fc_lport *lp); ++void fc_rport_terminate_io(struct fc_rport *rp); ++ ++/** ++ * DISCOVERY LAYER ++ *****************************/ ++int fc_disc_init(struct fc_lport *lp); ++ ++ ++/** ++ * SCSI LAYER ++ *****************************/ ++/* ++ * Initialize the SCSI block of libfc ++ */ ++int fc_fcp_init(struct fc_lport *); ++ ++/* ++ * This section provides an API which allows direct interaction ++ * with the SCSI-ml. Each of these functions satisfies a function ++ * pointer defined in Scsi_Host and therefore is always called ++ * directly from the SCSI-ml. ++ */ ++int fc_queuecommand(struct scsi_cmnd *sc_cmd, ++ void (*done)(struct scsi_cmnd *)); ++ ++/* ++ * complete processing of a fcp packet ++ * ++ * This function may sleep if a fsp timer is pending. ++ * The host lock must not be held by caller. ++ */ ++void fc_fcp_complete(struct fc_fcp_pkt *fsp); ++ ++/* ++ * Send an ABTS frame to the target device. The sc_cmd argument ++ * is a pointer to the SCSI command to be aborted. ++ */ ++int fc_eh_abort(struct scsi_cmnd *sc_cmd); ++ ++/* ++ * Reset a LUN by sending send the tm cmd to the target. ++ */ ++int fc_eh_device_reset(struct scsi_cmnd *sc_cmd); ++ ++/* ++ * Reset the host adapter. ++ */ ++int fc_eh_host_reset(struct scsi_cmnd *sc_cmd); ++ ++/* ++ * Check rport status. ++ */ ++int fc_slave_alloc(struct scsi_device *sdev); ++ ++/* ++ * Adjust the queue depth. ++ */ ++int fc_change_queue_depth(struct scsi_device *sdev, int qdepth); ++ ++/* ++ * Change the tag type. ++ */ ++int fc_change_queue_type(struct scsi_device *sdev, int tag_type); ++ ++/* ++ * Free memory pools used by the FCP layer. ++ */ ++void fc_fcp_destroy(struct fc_lport *); ++ ++/** ++ * ELS/CT interface ++ *****************************/ ++/* ++ * Initializes ELS/CT interface ++ */ ++int fc_elsct_init(struct fc_lport *lp); ++ ++ ++/** ++ * EXCHANGE MANAGER LAYER ++ *****************************/ ++/* ++ * Initializes Exchange Manager related ++ * function pointers in struct libfc_function_template. ++ */ ++int fc_exch_init(struct fc_lport *lp); ++ ++/* ++ * Allocates an Exchange Manager (EM). ++ * ++ * The EM manages exchanges for their allocation and ++ * free, also allows exchange lookup for received ++ * frame. ++ * ++ * The class is used for initializing FC class of ++ * allocated exchange from EM. ++ * ++ * The min_xid and max_xid will limit new ++ * exchange ID (XID) within this range for ++ * a new exchange. ++ * The LLD may choose to have multiple EMs, ++ * e.g. one EM instance per CPU receive thread in LLD. ++ * The LLD can use exch_get() of struct libfc_function_template ++ * to specify XID for a new exchange within ++ * a specified EM instance. ++ * ++ * The em_idx to uniquely identify an EM instance. ++ */ ++struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, ++ enum fc_class class, ++ u16 min_xid, ++ u16 max_xid); ++ ++/* ++ * Free an exchange manager. ++ */ ++void fc_exch_mgr_free(struct fc_exch_mgr *mp); ++ ++/* ++ * Receive a frame on specified local port and exchange manager. ++ */ ++void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, ++ struct fc_frame *fp); ++ ++/* ++ * This function is for exch_seq_send function pointer in ++ * struct libfc_function_template, see comment block on ++ * exch_seq_send for description of this function. ++ */ ++struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, ++ struct fc_frame *fp, ++ void (*resp)(struct fc_seq *sp, ++ struct fc_frame *fp, ++ void *arg), ++ void (*destructor)(struct fc_seq *sp, ++ void *arg), ++ void *arg, u32 timer_msec); ++ ++/* ++ * send a frame using existing sequence and exchange. ++ */ ++int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp); ++ ++/* ++ * Send ELS response using mainly infomation ++ * in exchange and sequence in EM layer. ++ */ ++void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, ++ struct fc_seq_els_data *els_data); ++ ++/* ++ * This function is for seq_exch_abort function pointer in ++ * struct libfc_function_template, see comment block on ++ * seq_exch_abort for description of this function. ++ */ ++int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec); ++ ++/* ++ * Indicate that an exchange/sequence tuple is complete and the memory ++ * allocated for the related objects may be freed. ++ */ ++void fc_exch_done(struct fc_seq *sp); ++ ++/* ++ * Assigns a EM and XID for a frame and then allocates ++ * a new exchange and sequence pair. ++ * The fp can be used to determine free XID. ++ */ ++struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp); ++ ++/* ++ * Allocate a new exchange and sequence pair. ++ * if ex_id is zero then next free exchange id ++ * from specified exchange manger mp will be assigned. ++ */ ++struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, ++ struct fc_frame *fp, u16 ex_id); ++/* ++ * Start a new sequence on the same exchange as the supplied sequence. ++ */ ++struct fc_seq *fc_seq_start_next(struct fc_seq *sp); ++ ++/* ++ * Reset an exchange manager, completing all sequences and exchanges. ++ * If s_id is non-zero, reset only exchanges originating from that FID. ++ * If d_id is non-zero, reset only exchanges sending to that FID. ++ */ ++void fc_exch_mgr_reset(struct fc_exch_mgr *, u32 s_id, u32 d_id); ++ ++/* ++ * Functions for fc_functions_template ++ */ ++void fc_get_host_speed(struct Scsi_Host *shost); ++void fc_get_host_port_type(struct Scsi_Host *shost); ++void fc_get_host_port_state(struct Scsi_Host *shost); ++void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout); ++struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); ++ ++/* ++ * module setup functions. ++ */ ++int fc_setup_exch_mgr(void); ++void fc_destroy_exch_mgr(void); ++int fc_setup_rport(void); ++void fc_destroy_rport(void); ++ ++#endif /* _LIBFC_H_ */ +diff --git a/include/scsi/libfc/fc_frame.h b/include/scsi/libfc/fc_frame.h +deleted file mode 100644 +index 9508e55..0000000 +--- a/include/scsi/libfc/fc_frame.h ++++ /dev/null +@@ -1,238 +0,0 @@ +-/* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-#ifndef _FC_FRAME_H_ +-#define _FC_FRAME_H_ +- +-#include +-#include +- +-#include +-#include +- +-/* +- * The fc_frame interface is used to pass frame data between functions. +- * The frame includes the data buffer, length, and SOF / EOF delimiter types. +- * A pointer to the port structure of the receiving port is also includeded. +- */ +- +-#define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */ +-#define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */ +- +-/* +- * Information about an individual fibre channel frame received or to be sent. +- * The buffer may be in up to 4 additional non-contiguous sections, +- * but the linear section must hold the frame header. +- */ +-#define FC_FRAME_SG_LEN 4 /* scatter/gather list maximum length */ +- +-#define fp_skb(fp) (&((fp)->skb)) +-#define fr_hdr(fp) ((fp)->skb.data) +-#define fr_len(fp) ((fp)->skb.len) +-#define fr_cb(fp) ((struct fcoe_rcv_info *)&((fp)->skb.cb[0])) +-#define fr_dev(fp) (fr_cb(fp)->fr_dev) +-#define fr_seq(fp) (fr_cb(fp)->fr_seq) +-#define fr_sof(fp) (fr_cb(fp)->fr_sof) +-#define fr_eof(fp) (fr_cb(fp)->fr_eof) +-#define fr_flags(fp) (fr_cb(fp)->fr_flags) +-#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) +- +-struct fc_frame { +- struct sk_buff skb; +-}; +- +-struct fcoe_rcv_info { +- struct packet_type *ptype; +- struct fc_lport *fr_dev; /* transport layer private pointer */ +- struct fc_seq *fr_seq; /* for use with exchange manager */ +- enum fc_sof fr_sof; /* start of frame delimiter */ +- enum fc_eof fr_eof; /* end of frame delimiter */ +- u8 fr_flags; /* flags - see below */ +- u16 fr_max_payload; /* max FC payload */ +-}; +- +-/* +- * Get fc_frame pointer for an skb that's already been imported. +- */ +-static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb) +-{ +- BUILD_BUG_ON(sizeof(struct fcoe_rcv_info) > sizeof(skb->cb)); +- return (struct fcoe_rcv_info *) skb->cb; +-} +- +-/* +- * fr_flags. +- */ +-#define FCPHF_CRC_UNCHECKED 0x01 /* CRC not computed, still appended */ +- +-/* +- * Initialize a frame. +- * We don't do a complete memset here for performance reasons. +- * The caller must set fr_free, fr_hdr, fr_len, fr_sof, and fr_eof eventually. +- */ +-static inline void fc_frame_init(struct fc_frame *fp) +-{ +- fr_dev(fp) = NULL; +- fr_seq(fp) = NULL; +- fr_flags(fp) = 0; +-} +- +-struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len); +- +-struct fc_frame *__fc_frame_alloc(size_t payload_len); +- +-/* +- * Get frame for sending via port. +- */ +-static inline struct fc_frame *_fc_frame_alloc(struct fc_lport *dev, +- size_t payload_len) +-{ +- return __fc_frame_alloc(payload_len); +-} +- +-/* +- * Allocate fc_frame structure and buffer. Set the initial length to +- * payload_size + sizeof (struct fc_frame_header). +- */ +-static inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len) +-{ +- struct fc_frame *fp; +- +- /* +- * Note: Since len will often be a constant multiple of 4, +- * this check will usually be evaluated and eliminated at compile time. +- */ +- if ((len % 4) != 0) +- fp = fc_frame_alloc_fill(dev, len); +- else +- fp = _fc_frame_alloc(dev, len); +- return fp; +-} +- +-/* +- * Free the fc_frame structure and buffer. +- */ +-static inline void fc_frame_free(struct fc_frame *fp) +-{ +- kfree_skb(fp_skb(fp)); +-} +- +-static inline int fc_frame_is_linear(struct fc_frame *fp) +-{ +- return !skb_is_nonlinear(fp_skb(fp)); +-} +- +-/* +- * Get frame header from message in fc_frame structure. +- * This hides a cast and provides a place to add some checking. +- */ +-static inline +-struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp) +-{ +- WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header)); +- return (struct fc_frame_header *) fr_hdr(fp); +-} +- +-/* +- * Get frame payload from message in fc_frame structure. +- * This hides a cast and provides a place to add some checking. +- * The len parameter is the minimum length for the payload portion. +- * Returns NULL if the frame is too short. +- * +- * This assumes the interesting part of the payload is in the first part +- * of the buffer for received data. This may not be appropriate to use for +- * buffers being transmitted. +- */ +-static inline void *fc_frame_payload_get(const struct fc_frame *fp, +- size_t len) +-{ +- void *pp = NULL; +- +- if (fr_len(fp) >= sizeof(struct fc_frame_header) + len) +- pp = fc_frame_header_get(fp) + 1; +- return pp; +-} +- +-/* +- * Get frame payload opcode (first byte) from message in fc_frame structure. +- * This hides a cast and provides a place to add some checking. Return 0 +- * if the frame has no payload. +- */ +-static inline u8 fc_frame_payload_op(const struct fc_frame *fp) +-{ +- u8 *cp; +- +- cp = fc_frame_payload_get(fp, sizeof(u8)); +- if (!cp) +- return 0; +- return *cp; +- +-} +- +-/* +- * Get FC class from frame. +- */ +-static inline enum fc_class fc_frame_class(const struct fc_frame *fp) +-{ +- return fc_sof_class(fr_sof(fp)); +-} +- +-/* +- * Set r_ctl and type in preparation for sending frame. +- * This also clears fh_parm_offset. +- */ +-static inline void fc_frame_setup(struct fc_frame *fp, enum fc_rctl r_ctl, +- enum fc_fh_type type) +-{ +- struct fc_frame_header *fh; +- +- fh = fc_frame_header_get(fp); +- WARN_ON(r_ctl == 0); +- fh->fh_r_ctl = r_ctl; +- fh->fh_type = type; +- fh->fh_parm_offset = htonl(0); +-} +- +-/* +- * Set offset in preparation for sending frame. +- */ +-static inline void +-fc_frame_set_offset(struct fc_frame *fp, u32 offset) +-{ +- struct fc_frame_header *fh; +- +- fh = fc_frame_header_get(fp); +- fh->fh_parm_offset = htonl(offset); +-} +- +-/* +- * Check the CRC in a frame. +- * The CRC immediately follows the last data item *AFTER* the length. +- * The return value is zero if the CRC matches. +- */ +-u32 fc_frame_crc_check(struct fc_frame *); +- +-/* +- * Check for leaks. +- * Print the frame header of any currently allocated frame, assuming there +- * should be none at this point. +- */ +-void fc_frame_leak_check(void); +- +-#endif /* _FC_FRAME_H_ */ +diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h +deleted file mode 100644 +index 237abd3..0000000 +--- a/include/scsi/libfc/libfc.h ++++ /dev/null +@@ -1,860 +0,0 @@ +-/* +- * Copyright(c) 2007 Intel Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms and conditions of the GNU General Public License, +- * version 2, as published by the Free Software Foundation. +- * +- * This program is distributed in the hope it will be useful, but WITHOUT +- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +- * more details. +- * +- * You should have received a copy of the GNU General Public License along with +- * this program; if not, write to the Free Software Foundation, Inc., +- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +- * +- * Maintained at www.Open-FCoE.org +- */ +- +-#ifndef _LIBFC_H_ +-#define _LIBFC_H_ +- +-#include +-#include +- +-#include +-#include +- +-#include +-#include +-#include +-#include +- +-#include +- +-#define LIBFC_DEBUG +- +-#ifdef LIBFC_DEBUG +-/* Log messages */ +-#define FC_DBG(fmt, args...) \ +- do { \ +- printk(KERN_INFO "%s " fmt, __func__, ##args); \ +- } while (0) +-#else +-#define FC_DBG(fmt, args...) +-#endif +- +-/* +- * libfc error codes +- */ +-#define FC_NO_ERR 0 /* no error */ +-#define FC_EX_TIMEOUT 1 /* Exchange timeout */ +-#define FC_EX_CLOSED 2 /* Exchange closed */ +- +-/* some helpful macros */ +- +-#define ntohll(x) be64_to_cpu(x) +-#define htonll(x) cpu_to_be64(x) +- +-#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) +- +-#define hton24(p, v) do { \ +- p[0] = (((v) >> 16) & 0xFF); \ +- p[1] = (((v) >> 8) & 0xFF); \ +- p[2] = ((v) & 0xFF); \ +- } while (0) +- +-struct fc_exch_mgr; +- +-/* +- * FC HBA status +- */ +-#define FC_PAUSE (1 << 1) +-#define FC_LINK_UP (1 << 0) +- +-enum fc_lport_state { +- LPORT_ST_NONE = 0, +- LPORT_ST_FLOGI, +- LPORT_ST_DNS, +- LPORT_ST_RPN_ID, +- LPORT_ST_RFT_ID, +- LPORT_ST_SCR, +- LPORT_ST_READY, +- LPORT_ST_LOGO, +- LPORT_ST_RESET +-}; +- +-enum fc_lport_event { +- LPORT_EV_RPORT_NONE = 0, +- LPORT_EV_RPORT_CREATED, +- LPORT_EV_RPORT_FAILED, +- LPORT_EV_RPORT_STOP, +- LPORT_EV_RPORT_LOGO +-}; +- +-enum fc_rport_state { +- RPORT_ST_NONE = 0, +- RPORT_ST_INIT, /* initialized */ +- RPORT_ST_PLOGI, /* waiting for PLOGI completion */ +- RPORT_ST_PRLI, /* waiting for PRLI completion */ +- RPORT_ST_RTV, /* waiting for RTV completion */ +- RPORT_ST_READY, /* ready for use */ +- RPORT_ST_LOGO, /* port logout sent */ +-}; +- +-enum fc_rport_trans_state { +- FC_PORTSTATE_ROGUE, +- FC_PORTSTATE_REAL, +-}; +- +-/** +- * struct fc_disc_port - temporary discovery port to hold rport identifiers +- * @lp: Fibre Channel host port instance +- * @peers: node for list management during discovery and RSCN processing +- * @ids: identifiers structure to pass to fc_remote_port_add() +- * @rport_work: work struct for starting the rport state machine +- */ +-struct fc_disc_port { +- struct fc_lport *lp; +- struct list_head peers; +- struct fc_rport_identifiers ids; +- struct work_struct rport_work; +-}; +- +-/** +- * struct fc_rport_libfc_priv - libfc internal information about a remote port +- * @local_port: Fibre Channel host port instance +- * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges +- * @flags: REC and RETRY supported flags +- * @max_seq: maximum number of concurrent sequences +- * @retries: retry count in current state +- * @e_d_tov: error detect timeout value (in msec) +- * @r_a_tov: resource allocation timeout value (in msec) +- * @rp_mutex: mutex protects rport +- * @retry_work: +- * @event_callback: Callback for rport READY, FAILED or LOGO +- */ +-struct fc_rport_libfc_priv { +- struct fc_lport *local_port; +- enum fc_rport_state rp_state; +- u16 flags; +- #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) +- #define FC_RP_FLAGS_RETRY (1 << 1) +- u16 max_seq; +- unsigned int retries; +- unsigned int e_d_tov; +- unsigned int r_a_tov; +- enum fc_rport_trans_state trans_state; +- struct mutex rp_mutex; +- struct delayed_work retry_work; +- enum fc_lport_event event; +- void (*event_callback)(struct fc_lport *, +- struct fc_rport *, +- enum fc_lport_event); +- struct list_head peers; +- struct work_struct event_work; +-}; +- +-#define PRIV_TO_RPORT(x) \ +- (struct fc_rport *)((void *)x - sizeof(struct fc_rport)); +-#define RPORT_TO_PRIV(x) \ +- (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); +- +-struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *); +-void fc_rport_rogue_destroy(struct fc_rport *); +- +-static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) +-{ +- rport->node_name = wwnn; +- rport->port_name = wwpn; +-} +- +-/* +- * fcoe stats structure +- */ +-struct fcoe_dev_stats { +- u64 SecondsSinceLastReset; +- u64 TxFrames; +- u64 TxWords; +- u64 RxFrames; +- u64 RxWords; +- u64 ErrorFrames; +- u64 DumpedFrames; +- u64 LinkFailureCount; +- u64 LossOfSignalCount; +- u64 InvalidTxWordCount; +- u64 InvalidCRCCount; +- u64 InputRequests; +- u64 OutputRequests; +- u64 ControlRequests; +- u64 InputMegabytes; +- u64 OutputMegabytes; +-}; +- +-/* +- * els data is used for passing ELS respone specific +- * data to send ELS response mainly using infomation +- * in exchange and sequence in EM layer. +- */ +-struct fc_seq_els_data { +- struct fc_frame *fp; +- enum fc_els_rjt_reason reason; +- enum fc_els_rjt_explan explan; +-}; +- +-/* +- * FCP request structure, one for each scsi cmd request +- */ +-struct fc_fcp_pkt { +- /* +- * housekeeping stuff +- */ +- struct fc_lport *lp; /* handle to hba struct */ +- u16 state; /* scsi_pkt state state */ +- u16 tgt_flags; /* target flags */ +- atomic_t ref_cnt; /* fcp pkt ref count */ +- spinlock_t scsi_pkt_lock; /* Must be taken before the host lock +- * if both are held at the same time */ +- /* +- * SCSI I/O related stuff +- */ +- struct scsi_cmnd *cmd; /* scsi command pointer. set/clear +- * under host lock */ +- struct list_head list; /* tracks queued commands. access under +- * host lock */ +- /* +- * timeout related stuff +- */ +- struct timer_list timer; /* command timer */ +- struct completion tm_done; +- int wait_for_comp; +- unsigned long start_time; /* start jiffie */ +- unsigned long end_time; /* end jiffie */ +- unsigned long last_pkt_time; /* jiffies of last frame received */ +- +- /* +- * scsi cmd and data transfer information +- */ +- u32 data_len; +- /* +- * transport related veriables +- */ +- struct fcp_cmnd cdb_cmd; +- size_t xfer_len; +- u32 xfer_contig_end; /* offset of end of contiguous xfer */ +- u16 max_payload; /* max payload size in bytes */ +- +- /* +- * scsi/fcp return status +- */ +- u32 io_status; /* SCSI result upper 24 bits */ +- u8 cdb_status; +- u8 status_code; /* FCP I/O status */ +- /* bit 3 Underrun bit 2: overrun */ +- u8 scsi_comp_flags; +- u32 req_flags; /* bit 0: read bit:1 write */ +- u32 scsi_resid; /* residule length */ +- +- struct fc_rport *rport; /* remote port pointer */ +- struct fc_seq *seq_ptr; /* current sequence pointer */ +- /* +- * Error Processing +- */ +- u8 recov_retry; /* count of recovery retries */ +- struct fc_seq *recov_seq; /* sequence for REC or SRR */ +-}; +- +-struct libfc_function_template { +- +- /** +- * Mandatory Fields +- * +- * These handlers must be implemented by the LLD. +- */ +- +- /* +- * Interface to send a FC frame +- */ +- int (*frame_send)(struct fc_lport *lp, struct fc_frame *fp); +- +- /** +- * Optional Fields +- * +- * The LLD may choose to implement any of the following handlers. +- * If LLD doesn't specify hander and leaves its pointer NULL then +- * the default libfc function will be used for that handler. +- */ +- +- /** +- * Exhance Manager interfaces +- */ +- +- /* +- * Send the FC frame payload using a new exchange and sequence. +- * +- * The frame pointer with some of the header's fields must be +- * filled before calling exch_seq_send(), those fields are, +- * +- * - routing control +- * - FC header type +- * - parameter or relative offset +- * +- * The exchange response handler is set in this routine to resp() +- * function pointer. It can be called in two scenarios: if a timeout +- * occurs or if a response frame is received for the exchange. The +- * fc_frame pointer in response handler will also indicate timeout +- * as error using IS_ERR related macros. +- * +- * The exchange destructor handler is also set in this routine. +- * The destructor handler is invoked by EM layer when exchange +- * is about to free, this can be used by caller to free its +- * resources along with exchange free. +- * +- * The arg is passed back to resp and destructor handler. +- * +- * The timeout value (in msec) for an exchange is set if non zero +- * timer_msec argument is specified. The timer is canceled when +- * it fires or when the exchange is done. The exchange timeout handler +- * is registered by EM layer. +- * +- * The caller also need to specify FC sid, did and frame control field. +- */ +- struct fc_seq *(*exch_seq_send)(struct fc_lport *lp, +- struct fc_frame *fp, +- void (*resp)(struct fc_seq *sp, +- struct fc_frame *fp, +- void *arg), +- void (*destructor)(struct fc_seq *sp, +- void *arg), +- void *arg, unsigned int timer_msec, +- u32 sid, u32 did, u32 f_ctl); +- +- /* +- * send a frame using existing sequence and exchange. +- */ +- int (*seq_send)(struct fc_lport *lp, struct fc_seq *sp, +- struct fc_frame *fp, u32 f_ctl); +- +- /* +- * Send ELS response using mainly infomation +- * in exchange and sequence in EM layer. +- */ +- void (*seq_els_rsp_send)(struct fc_seq *sp, enum fc_els_cmd els_cmd, +- struct fc_seq_els_data *els_data); +- +- /* +- * Abort an exchange and sequence. Generally called because of a +- * exchange timeout or an abort from the upper layer. +- * +- * A timer_msec can be specified for abort timeout, if non-zero +- * timer_msec value is specified then exchange resp handler +- * will be called with timeout error if no response to abort. +- */ +- int (*seq_exch_abort)(const struct fc_seq *req_sp, +- unsigned int timer_msec); +- +- /* +- * Indicate that an exchange/sequence tuple is complete and the memory +- * allocated for the related objects may be freed. +- */ +- void (*exch_done)(struct fc_seq *sp); +- +- /* +- * Assigns a EM and a free XID for an new exchange and then +- * allocates a new exchange and sequence pair. +- * The fp can be used to determine free XID. +- */ +- struct fc_exch *(*exch_get)(struct fc_lport *lp, struct fc_frame *fp); +- +- /* +- * Release previously assigned XID by exch_get API. +- * The LLD may implement this if XID is assigned by LLD +- * in exch_get(). +- */ +- void (*exch_put)(struct fc_lport *lp, struct fc_exch_mgr *mp, +- u16 ex_id); +- +- /* +- * Start a new sequence on the same exchange/sequence tuple. +- */ +- struct fc_seq *(*seq_start_next)(struct fc_seq *sp); +- +- /* +- * Reset an exchange manager, completing all sequences and exchanges. +- * If s_id is non-zero, reset only exchanges originating from that FID. +- * If d_id is non-zero, reset only exchanges sending to that FID. +- */ +- void (*exch_mgr_reset)(struct fc_exch_mgr *, +- u32 s_id, u32 d_id); +- +- /* +- * Get exchange Ids of a sequence +- */ +- void (*seq_get_xids)(struct fc_seq *sp, u16 *oxid, u16 *rxid); +- +- /* +- * Set REC data to a sequence +- */ +- void (*seq_set_rec_data)(struct fc_seq *sp, u32 rec_data); +- +- /** +- * Local Port interfaces +- */ +- +- /* +- * Receive a frame to a local port. +- */ +- void (*lport_recv)(struct fc_lport *lp, struct fc_seq *sp, +- struct fc_frame *fp); +- +- int (*lport_reset)(struct fc_lport *); +- +- void (*event_callback)(struct fc_lport *, struct fc_rport *, +- enum fc_lport_event); +- +- /** +- * Remote Port interfaces +- */ +- +- /* +- * Initiates the RP state machine. It is called from the LP module. +- * This function will issue the following commands to the N_Port +- * identified by the FC ID provided. +- * +- * - PLOGI +- * - PRLI +- * - RTV +- */ +- int (*rport_login)(struct fc_rport *rport); +- +- /* +- * Logs the specified local port out of a N_Port identified +- * by the ID provided. +- */ +- int (*rport_logout)(struct fc_rport *rport); +- +- /* +- * Delete the rport and remove it from the transport if +- * it had been added. This will not send a LOGO, use +- * rport_logout for a gracefull logout. +- */ +- int (*rport_stop)(struct fc_rport *rport); +- +- /* +- * Recieve a request from a remote port. +- */ +- void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, +- struct fc_rport *); +- +- struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); +- +- /** +- * FCP interfaces +- */ +- +- /* +- * Send a fcp cmd from fsp pkt. +- * Called with the SCSI host lock unlocked and irqs disabled. +- * +- * The resp handler is called when FCP_RSP received. +- * +- */ +- int (*fcp_cmd_send)(struct fc_lport *lp, struct fc_fcp_pkt *fsp, +- void (*resp)(struct fc_seq *, struct fc_frame *fp, +- void *arg)); +- +- /* +- * Used at least durring linkdown and reset +- */ +- void (*fcp_cleanup)(struct fc_lport *lp); +- +- /* +- * Abort all I/O on a local port +- */ +- void (*fcp_abort_io)(struct fc_lport *lp); +- +- /** +- * Discovery interfaces +- */ +- +- void (*disc_recv_req)(struct fc_seq *, +- struct fc_frame *, struct fc_lport *); +- +- /* +- * Start discovery for a local port. +- */ +- int (*disc_start)(struct fc_lport *); +-}; +- +-struct fc_lport { +- struct list_head list; +- +- /* Associations */ +- struct Scsi_Host *host; +- struct fc_exch_mgr *emp; +- struct fc_rport *dns_rp; +- struct fc_rport *ptp_rp; +- void *scsi_priv; +- struct list_head rports; +- +- /* Operational Information */ +- struct libfc_function_template tt; +- u16 link_status; +- u8 disc_done; +- enum fc_lport_state state; +- unsigned long boot_time; +- +- struct fc_host_statistics host_stats; +- struct fcoe_dev_stats *dev_stats[NR_CPUS]; +- +- u64 wwpn; +- u64 wwnn; +- u8 retry_count; +- unsigned char disc_retry_count; +- unsigned char disc_delay; +- unsigned char disc_pending; +- unsigned char disc_requested; +- unsigned short disc_seq_count; +- unsigned char disc_buf_len; +- +- /* Capabilities */ +- u32 sg_supp:1; /* scatter gather supported */ +- u32 seq_offload:1; /* seq offload supported */ +- u32 mfs; /* max FC payload size */ +- unsigned int service_params; +- unsigned int e_d_tov; +- unsigned int r_a_tov; +- u8 max_retry_count; +- u16 link_speed; +- u16 link_supported_speeds; +- struct fc_ns_fts fcts; /* FC-4 type masks */ +- struct fc_els_rnid_gen rnid_gen; /* RNID information */ +- +- /* Semaphores */ +- struct mutex lp_mutex; +- +- /* Miscellaneous */ +- struct fc_gpn_ft_resp disc_buf; /* partial name buffer */ +- struct delayed_work retry_work; +- struct delayed_work disc_work; +- +- void *drv_priv; +-}; +- +-/** +- * FC_LPORT HELPER FUNCTIONS +- *****************************/ +- +-static inline int fc_lport_test_ready(struct fc_lport *lp) +-{ +- return lp->state == LPORT_ST_READY; +-} +- +-static inline void fc_set_wwnn(struct fc_lport *lp, u64 wwnn) +-{ +- lp->wwnn = wwnn; +-} +- +-static inline void fc_set_wwpn(struct fc_lport *lp, u64 wwnn) +-{ +- lp->wwpn = wwnn; +-} +- +-/** +- * fc_fill_dns_hdr - Fill in a name service request header +- * @lp: Fibre Channel host port instance +- * @ct: Common Transport (CT) header structure +- * @op: Name Service request code +- * @req_size: Full size of Name Service request +- */ +-static inline void fc_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, +- unsigned int op, unsigned int req_size) +-{ +- memset(ct, 0, sizeof(*ct) + req_size); +- ct->ct_rev = FC_CT_REV; +- ct->ct_fs_type = FC_FST_DIR; +- ct->ct_fs_subtype = FC_NS_SUBTYPE; +- ct->ct_cmd = htons((u16) op); +-} +- +-static inline void fc_lport_state_enter(struct fc_lport *lp, +- enum fc_lport_state state) +-{ +- if (state != lp->state) +- lp->retry_count = 0; +- lp->state = state; +-} +- +- +-/** +- * LOCAL PORT LAYER +- *****************************/ +-int fc_lport_init(struct fc_lport *lp); +- +-/* +- * Destroy the specified local port by finding and freeing all +- * fc_rports associated with it and then by freeing the fc_lport +- * itself. +- */ +-int fc_lport_destroy(struct fc_lport *lp); +- +-/* +- * Logout the specified local port from the fabric +- */ +-int fc_fabric_logoff(struct fc_lport *lp); +- +-/* +- * Initiate the LP state machine. This handler will use fc_host_attr +- * to store the FLOGI service parameters, so fc_host_attr must be +- * initialized before calling this handler. +- */ +-int fc_fabric_login(struct fc_lport *lp); +- +-/* +- * The link is up for the given local port. +- */ +-void fc_linkup(struct fc_lport *); +- +-/* +- * Link is down for the given local port. +- */ +-void fc_linkdown(struct fc_lport *); +- +-/* +- * Pause and unpause traffic. +- */ +-void fc_pause(struct fc_lport *); +-void fc_unpause(struct fc_lport *); +- +-/* +- * Configure the local port. +- */ +-int fc_lport_config(struct fc_lport *); +- +-/* +- * Reset the local port. +- */ +-int fc_lport_reset(struct fc_lport *); +- +-/* +- * Set the mfs or reset +- */ +-int fc_set_mfs(struct fc_lport *lp, u32 mfs); +- +- +-/** +- * REMOTE PORT LAYER +- *****************************/ +-int fc_rport_init(struct fc_lport *lp); +-void fc_rport_terminate_io(struct fc_rport *rp); +- +-/** +- * DISCOVERY LAYER +- *****************************/ +-int fc_disc_init(struct fc_lport *lp); +- +- +-/** +- * SCSI LAYER +- *****************************/ +-/* +- * Initialize the SCSI block of libfc +- */ +-int fc_fcp_init(struct fc_lport *); +- +-/* +- * This section provides an API which allows direct interaction +- * with the SCSI-ml. Each of these functions satisfies a function +- * pointer defined in Scsi_Host and therefore is always called +- * directly from the SCSI-ml. +- */ +-int fc_queuecommand(struct scsi_cmnd *sc_cmd, +- void (*done)(struct scsi_cmnd *)); +- +-/* +- * complete processing of a fcp packet +- * +- * This function may sleep if a fsp timer is pending. +- * The host lock must not be held by caller. +- */ +-void fc_fcp_complete(struct fc_fcp_pkt *fsp); +- +-/* +- * Send an ABTS frame to the target device. The sc_cmd argument +- * is a pointer to the SCSI command to be aborted. +- */ +-int fc_eh_abort(struct scsi_cmnd *sc_cmd); +- +-/* +- * Reset a LUN by sending send the tm cmd to the target. +- */ +-int fc_eh_device_reset(struct scsi_cmnd *sc_cmd); +- +-/* +- * Reset the host adapter. +- */ +-int fc_eh_host_reset(struct scsi_cmnd *sc_cmd); +- +-/* +- * Check rport status. +- */ +-int fc_slave_alloc(struct scsi_device *sdev); +- +-/* +- * Adjust the queue depth. +- */ +-int fc_change_queue_depth(struct scsi_device *sdev, int qdepth); +- +-/* +- * Change the tag type. +- */ +-int fc_change_queue_type(struct scsi_device *sdev, int tag_type); +- +-/* +- * Free memory pools used by the FCP layer. +- */ +-void fc_fcp_destroy(struct fc_lport *); +- +- +-/** +- * EXCHANGE MANAGER LAYER +- *****************************/ +-/* +- * Initializes Exchange Manager related +- * function pointers in struct libfc_function_template. +- */ +-int fc_exch_init(struct fc_lport *lp); +- +-/* +- * Allocates an Exchange Manager (EM). +- * +- * The EM manages exchanges for their allocation and +- * free, also allows exchange lookup for received +- * frame. +- * +- * The class is used for initializing FC class of +- * allocated exchange from EM. +- * +- * The min_xid and max_xid will limit new +- * exchange ID (XID) within this range for +- * a new exchange. +- * The LLD may choose to have multiple EMs, +- * e.g. one EM instance per CPU receive thread in LLD. +- * The LLD can use exch_get() of struct libfc_function_template +- * to specify XID for a new exchange within +- * a specified EM instance. +- * +- * The em_idx to uniquely identify an EM instance. +- */ +-struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, +- enum fc_class class, +- u16 min_xid, +- u16 max_xid); +- +-/* +- * Free an exchange manager. +- */ +-void fc_exch_mgr_free(struct fc_exch_mgr *mp); +- +-/* +- * Receive a frame on specified local port and exchange manager. +- */ +-void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, +- struct fc_frame *fp); +- +-/* +- * This function is for exch_seq_send function pointer in +- * struct libfc_function_template, see comment block on +- * exch_seq_send for description of this function. +- */ +-struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, +- struct fc_frame *fp, +- void (*resp)(struct fc_seq *sp, +- struct fc_frame *fp, +- void *arg), +- void (*destructor)(struct fc_seq *sp, +- void *arg), +- void *arg, u32 timer_msec, +- u32 sid, u32 did, u32 f_ctl); +- +-/* +- * send a frame using existing sequence and exchange. +- */ +-int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, +- struct fc_frame *fp, u32 f_ctl); +- +-/* +- * Send ELS response using mainly infomation +- * in exchange and sequence in EM layer. +- */ +-void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, +- struct fc_seq_els_data *els_data); +- +-/* +- * This function is for seq_exch_abort function pointer in +- * struct libfc_function_template, see comment block on +- * seq_exch_abort for description of this function. +- */ +-int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec); +- +-/* +- * Indicate that an exchange/sequence tuple is complete and the memory +- * allocated for the related objects may be freed. +- */ +-void fc_exch_done(struct fc_seq *sp); +- +-/* +- * Assigns a EM and XID for a frame and then allocates +- * a new exchange and sequence pair. +- * The fp can be used to determine free XID. +- */ +-struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp); +- +-/* +- * Allocate a new exchange and sequence pair. +- * if ex_id is zero then next free exchange id +- * from specified exchange manger mp will be assigned. +- */ +-struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 ex_id); +- +-/* +- * Start a new sequence on the same exchange as the supplied sequence. +- */ +-struct fc_seq *fc_seq_start_next(struct fc_seq *sp); +- +-/* +- * Reset an exchange manager, completing all sequences and exchanges. +- * If s_id is non-zero, reset only exchanges originating from that FID. +- * If d_id is non-zero, reset only exchanges sending to that FID. +- */ +-void fc_exch_mgr_reset(struct fc_exch_mgr *, u32 s_id, u32 d_id); +- +-/* +- * Get exchange Ids of a sequence +- */ +-void fc_seq_get_xids(struct fc_seq *sp, u16 *oxid, u16 *rxid); +- +-/* +- * Set REC data to a sequence +- */ +-void fc_seq_set_rec_data(struct fc_seq *sp, u32 rec_data); +- +-/* +- * Functions for fc_functions_template +- */ +-void fc_get_host_speed(struct Scsi_Host *shost); +-void fc_get_host_port_type(struct Scsi_Host *shost); +-void fc_get_host_port_state(struct Scsi_Host *shost); +-void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout); +-struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); +- +-/* +- * module setup functions. +- */ +-int fc_setup_exch_mgr(void); +-void fc_destroy_exch_mgr(void); +-int fc_setup_rport(void); +-void fc_destroy_rport(void); +- +-#endif /* _LIBFC_H_ */ +diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h +new file mode 100644 +index 0000000..4ca5902 +--- /dev/null ++++ b/include/scsi/libfcoe.h +@@ -0,0 +1,177 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _LIBFCOE_H ++#define _LIBFCOE_H ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * this percpu struct for fcoe ++ */ ++struct fcoe_percpu_s { ++ int cpu; ++ struct task_struct *thread; ++ struct sk_buff_head fcoe_rx_list; ++ struct page *crc_eof_page; ++ int crc_eof_offset; ++}; ++ ++/* ++ * the fcoe sw transport private data ++ */ ++struct fcoe_softc { ++ struct list_head list; ++ struct fc_lport *lp; ++ struct net_device *real_dev; ++ struct net_device *phys_dev; /* device with ethtool_ops */ ++ struct packet_type fcoe_packet_type; ++ struct sk_buff_head fcoe_pending_queue; ++ u16 user_mfs; /* configured max frame size */ ++ ++ u8 dest_addr[ETH_ALEN]; ++ u8 ctl_src_addr[ETH_ALEN]; ++ u8 data_src_addr[ETH_ALEN]; ++ /* ++ * fcoe protocol address learning related stuff ++ */ ++ u16 flogi_oxid; ++ u8 flogi_progress; ++ u8 address_mode; ++}; ++ ++static inline struct fcoe_softc *fcoe_softc( ++ const struct fc_lport *lp) ++{ ++ return (struct fcoe_softc *)lport_priv(lp); ++} ++ ++static inline struct net_device *fcoe_netdev( ++ const struct fc_lport *lp) ++{ ++ return fcoe_softc(lp)->real_dev; ++} ++ ++static inline struct fcoe_hdr *skb_fcoe_header(const struct sk_buff *skb) ++{ ++ return (struct fcoe_hdr *)skb_network_header(skb); ++} ++ ++static inline int skb_fcoe_offset(const struct sk_buff *skb) ++{ ++ return skb_network_offset(skb); ++} ++ ++static inline struct fc_frame_header *skb_fc_header(const struct sk_buff *skb) ++{ ++ return (struct fc_frame_header *)skb_transport_header(skb); ++} ++ ++static inline int skb_fc_offset(const struct sk_buff *skb) ++{ ++ return skb_transport_offset(skb); ++} ++ ++static inline void skb_reset_fc_header(struct sk_buff *skb) ++{ ++ skb_reset_network_header(skb); ++ skb_set_transport_header(skb, skb_network_offset(skb) + ++ sizeof(struct fcoe_hdr)); ++} ++ ++static inline bool skb_fc_is_data(const struct sk_buff *skb) ++{ ++ return skb_fc_header(skb)->fh_r_ctl == FC_RCTL_DD_SOL_DATA; ++} ++ ++static inline bool skb_fc_is_cmd(const struct sk_buff *skb) ++{ ++ return skb_fc_header(skb)->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD; ++} ++ ++static inline bool skb_fc_has_exthdr(const struct sk_buff *skb) ++{ ++ return (skb_fc_header(skb)->fh_r_ctl == FC_RCTL_VFTH) || ++ (skb_fc_header(skb)->fh_r_ctl == FC_RCTL_IFRH) || ++ (skb_fc_header(skb)->fh_r_ctl == FC_RCTL_ENCH); ++} ++ ++static inline bool skb_fc_is_roff(const struct sk_buff *skb) ++{ ++ return skb_fc_header(skb)->fh_f_ctl[2] & FC_FC_REL_OFF; ++} ++ ++static inline u16 skb_fc_oxid(const struct sk_buff *skb) ++{ ++ return be16_to_cpu(skb_fc_header(skb)->fh_ox_id); ++} ++ ++static inline u16 skb_fc_rxid(const struct sk_buff *skb) ++{ ++ return be16_to_cpu(skb_fc_header(skb)->fh_rx_id); ++} ++ ++/* FIXME - DMA_BIDIRECTIONAL ? */ ++#define skb_cb(skb) ((struct fcoe_rcv_info *)&((skb)->cb[0])) ++#define skb_cmd(skb) (skb_cb(skb)->fr_cmd) ++#define skb_dir(skb) (skb_cmd(skb)->sc_data_direction) ++static inline bool skb_fc_is_read(const struct sk_buff *skb) ++{ ++ if (skb_fc_is_cmd(skb) && skb_cmd(skb)) ++ return skb_dir(skb) == DMA_FROM_DEVICE; ++ return false; ++} ++ ++static inline bool skb_fc_is_write(const struct sk_buff *skb) ++{ ++ if (skb_fc_is_cmd(skb) && skb_cmd(skb)) ++ return skb_dir(skb) == DMA_TO_DEVICE; ++ return false; ++} ++ ++/* libfcoe funcs */ ++int fcoe_reset(struct Scsi_Host *shost); ++u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], ++ unsigned int scheme, unsigned int port); ++ ++u32 fcoe_fc_crc(struct fc_frame *fp); ++int fcoe_xmit(struct fc_lport *, struct fc_frame *); ++int fcoe_rcv(struct sk_buff *, struct net_device *, ++ struct packet_type *, struct net_device *); ++ ++int fcoe_percpu_receive_thread(void *arg); ++void fcoe_clean_pending_queue(struct fc_lport *lp); ++void fcoe_percpu_clean(struct fc_lport *lp); ++void fcoe_watchdog(ulong vp); ++int fcoe_link_ok(struct fc_lport *lp); ++ ++struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); ++int fcoe_hostlist_add(const struct fc_lport *); ++int fcoe_hostlist_remove(const struct fc_lport *); ++ ++struct Scsi_Host *fcoe_host_alloc(struct scsi_host_template *, int); ++int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *); ++ ++/* fcoe sw hba */ ++int __init fcoe_sw_init(void); ++int __exit fcoe_sw_exit(void); ++#endif /* _LIBFCOE_H */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-dcb-support b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-dcb-support new file mode 100644 index 000000000..76200cb28 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-dcb-support @@ -0,0 +1,3782 @@ +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:49:40 +0200 +Subject: FCoE: Add DCB support +References: FATE#303913 + +Signed-off-by: Hannes Reinecke +--- + drivers/net/ixgbe/Makefile | 3 + drivers/net/ixgbe/ixgbe.h | 26 + drivers/net/ixgbe/ixgbe_dcb.c | 332 ++++++++++ + drivers/net/ixgbe/ixgbe_dcb.h | 189 ++++++ + drivers/net/ixgbe/ixgbe_dcb_82598.c | 398 +++++++++++++ + drivers/net/ixgbe/ixgbe_dcb_82598.h | 98 +++ + drivers/net/ixgbe/ixgbe_dcb_nl.c | 611 ++++++++++++++++++++ + drivers/net/ixgbe/ixgbe_ethtool.c | 37 + + drivers/net/ixgbe/ixgbe_main.c | 192 +++++- + include/linux/dcbnl.h | 324 ++++++++++ + include/linux/netdevice.h | 8 + include/linux/rtnetlink.h | 5 + include/net/dcbnl.h | 40 + + net/Kconfig | 1 + net/Makefile | 3 + net/dcb/Kconfig | 12 + net/dcb/Makefile | 1 + net/dcb/dcbnl.c | 1091 ++++++++++++++++++++++++++++++++++++ + 18 files changed, 3349 insertions(+), 22 deletions(-) + create mode 100644 drivers/net/ixgbe/ixgbe_dcb.c + create mode 100644 drivers/net/ixgbe/ixgbe_dcb.h + create mode 100644 drivers/net/ixgbe/ixgbe_dcb_82598.c + create mode 100644 drivers/net/ixgbe/ixgbe_dcb_82598.h + create mode 100644 drivers/net/ixgbe/ixgbe_dcb_nl.c + create mode 100644 include/linux/dcbnl.h + create mode 100644 include/net/dcbnl.h + create mode 100644 net/dcb/Kconfig + create mode 100644 net/dcb/Makefile + create mode 100644 net/dcb/dcbnl.c + +--- /dev/null ++++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c +@@ -0,0 +1,398 @@ ++/******************************************************************************* ++ ++ Intel 10 Gigabit PCI Express Linux driver ++ Copyright(c) 1999 - 2007 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include "ixgbe.h" ++#include "ixgbe_type.h" ++#include "ixgbe_dcb.h" ++#include "ixgbe_dcb_82598.h" ++ ++/** ++ * ixgbe_dcb_get_tc_stats_82598 - Return status data for each traffic class ++ * @hw: pointer to hardware structure ++ * @stats: pointer to statistics structure ++ * @tc_count: Number of elements in bwg_array. ++ * ++ * This function returns the status data for each of the Traffic Classes in use. ++ */ ++s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw, ++ struct ixgbe_hw_stats *stats, ++ u8 tc_count) ++{ ++ int tc; ++ ++ if (tc_count > MAX_TRAFFIC_CLASS) ++ return DCB_ERR_PARAM; ++ ++ /* Statistics pertaining to each traffic class */ ++ for (tc = 0; tc < tc_count; tc++) { ++ /* Transmitted Packets */ ++ stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc)); ++ /* Transmitted Bytes */ ++ stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc)); ++ /* Received Packets */ ++ stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc)); ++ /* Received Bytes */ ++ stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc)); ++ } ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_get_pfc_stats_82598 - Returns CBFC status data ++ * @hw: pointer to hardware structure ++ * @stats: pointer to statistics structure ++ * @tc_count: Number of elements in bwg_array. ++ * ++ * This function returns the CBFC status data for each of the Traffic Classes. ++ */ ++s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw, ++ struct ixgbe_hw_stats *stats, ++ u8 tc_count) ++{ ++ int tc; ++ ++ if (tc_count > MAX_TRAFFIC_CLASS) ++ return DCB_ERR_PARAM; ++ ++ for (tc = 0; tc < tc_count; tc++) { ++ /* Priority XOFF Transmitted */ ++ stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc)); ++ /* Priority XOFF Received */ ++ stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(tc)); ++ } ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_config_packet_buffers_82598 - Configure packet buffers ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure packet buffers for DCB mode. ++ */ ++s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ s32 ret_val = 0; ++ u32 value = IXGBE_RXPBSIZE_64KB; ++ u8 i = 0; ++ ++ /* Setup Rx packet buffer sizes */ ++ switch (dcb_config->rx_pba_cfg) { ++ case pba_80_48: ++ /* Setup the first four at 80KB */ ++ value = IXGBE_RXPBSIZE_80KB; ++ for (; i < 4; i++) ++ IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); ++ /* Setup the last four at 48KB...don't re-init i */ ++ value = IXGBE_RXPBSIZE_48KB; ++ /* Fall Through */ ++ case pba_equal: ++ default: ++ for (; i < IXGBE_MAX_PACKET_BUFFERS; i++) ++ IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); ++ ++ /* Setup Tx packet buffer sizes */ ++ for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { ++ IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), ++ IXGBE_TXPBSIZE_40KB); ++ } ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * ixgbe_dcb_config_rx_arbiter_82598 - Config Rx data arbiter ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Rx Data Arbiter and credits for each traffic class. ++ */ ++s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ struct tc_bw_alloc *p; ++ u32 reg = 0; ++ u32 credit_refill = 0; ++ u32 credit_max = 0; ++ u8 i = 0; ++ ++ reg = IXGBE_READ_REG(hw, IXGBE_RUPPBMR) | IXGBE_RUPPBMR_MQA; ++ IXGBE_WRITE_REG(hw, IXGBE_RUPPBMR, reg); ++ ++ reg = IXGBE_READ_REG(hw, IXGBE_RMCS); ++ /* Enable Arbiter */ ++ reg &= ~IXGBE_RMCS_ARBDIS; ++ /* Enable Receive Recycle within the BWG */ ++ reg |= IXGBE_RMCS_RRM; ++ /* Enable Deficit Fixed Priority arbitration*/ ++ reg |= IXGBE_RMCS_DFP; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); ++ ++ /* Configure traffic class credits and priority */ ++ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { ++ p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG]; ++ credit_refill = p->data_credits_refill; ++ credit_max = p->data_credits_max; ++ ++ reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT); ++ ++ if (p->prio_type == prio_link) ++ reg |= IXGBE_RT2CR_LSP; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg); ++ } ++ ++ reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); ++ reg |= IXGBE_RDRXCTL_RDMTS_1_2; ++ reg |= IXGBE_RDRXCTL_MPBEN; ++ reg |= IXGBE_RDRXCTL_MCEN; ++ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg); ++ ++ reg = IXGBE_READ_REG(hw, IXGBE_RXCTRL); ++ /* Make sure there is enough descriptors before arbitration */ ++ reg &= ~IXGBE_RXCTRL_DMBYPS; ++ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_config_tx_desc_arbiter_82598 - Config Tx Desc. arbiter ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Tx Descriptor Arbiter and credits for each traffic class. ++ */ ++s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ struct tc_bw_alloc *p; ++ u32 reg, max_credits; ++ u8 i; ++ ++ reg = IXGBE_READ_REG(hw, IXGBE_DPMCS); ++ ++ /* Enable arbiter */ ++ reg &= ~IXGBE_DPMCS_ARBDIS; ++ if (!(dcb_config->round_robin_enable)) { ++ /* Enable DFP and Recycle mode */ ++ reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); ++ } ++ reg |= IXGBE_DPMCS_TSOEF; ++ /* Configure Max TSO packet size 34KB including payload and headers */ ++ reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); ++ ++ IXGBE_WRITE_REG(hw, IXGBE_DPMCS, reg); ++ ++ /* Configure traffic class credits and priority */ ++ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { ++ p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; ++ max_credits = dcb_config->tc_config[i].desc_credits_max; ++ reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT; ++ reg |= p->data_credits_refill; ++ reg |= (u32)(p->bwg_id) << IXGBE_TDTQ2TCCR_BWG_SHIFT; ++ ++ if (p->prio_type == prio_group) ++ reg |= IXGBE_TDTQ2TCCR_GSP; ++ ++ if (p->prio_type == prio_link) ++ reg |= IXGBE_TDTQ2TCCR_LSP; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg); ++ } ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_config_tx_data_arbiter_82598 - Config Tx data arbiter ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Tx Data Arbiter and credits for each traffic class. ++ */ ++s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ struct tc_bw_alloc *p; ++ u32 reg; ++ u8 i; ++ ++ reg = IXGBE_READ_REG(hw, IXGBE_PDPMCS); ++ /* Enable Data Plane Arbiter */ ++ reg &= ~IXGBE_PDPMCS_ARBDIS; ++ /* Enable DFP and Transmit Recycle Mode */ ++ reg |= (IXGBE_PDPMCS_TPPAC | IXGBE_PDPMCS_TRM); ++ ++ IXGBE_WRITE_REG(hw, IXGBE_PDPMCS, reg); ++ ++ /* Configure traffic class credits and priority */ ++ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { ++ p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; ++ reg = p->data_credits_refill; ++ reg |= (u32)(p->data_credits_max) << IXGBE_TDPT2TCCR_MCL_SHIFT; ++ reg |= (u32)(p->bwg_id) << IXGBE_TDPT2TCCR_BWG_SHIFT; ++ ++ if (p->prio_type == prio_group) ++ reg |= IXGBE_TDPT2TCCR_GSP; ++ ++ if (p->prio_type == prio_link) ++ reg |= IXGBE_TDPT2TCCR_LSP; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg); ++ } ++ ++ /* Enable Tx packet buffer division */ ++ reg = IXGBE_READ_REG(hw, IXGBE_DTXCTL); ++ reg |= IXGBE_DTXCTL_ENDBUBD; ++ IXGBE_WRITE_REG(hw, IXGBE_DTXCTL, reg); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_config_pfc_82598 - Config priority flow control ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Priority Flow Control for each traffic class. ++ */ ++s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ u32 reg, rx_pba_size; ++ u8 i; ++ ++ /* Enable Transmit Priority Flow Control */ ++ reg = IXGBE_READ_REG(hw, IXGBE_RMCS); ++ reg &= ~IXGBE_RMCS_TFCE_802_3X; ++ /* correct the reporting of our flow control status */ ++ hw->fc.type = ixgbe_fc_none; ++ reg |= IXGBE_RMCS_TFCE_PRIORITY; ++ IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); ++ ++ /* Enable Receive Priority Flow Control */ ++ reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); ++ reg &= ~IXGBE_FCTRL_RFCE; ++ reg |= IXGBE_FCTRL_RPFCE; ++ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); ++ ++ /* ++ * Configure flow control thresholds and enable priority flow control ++ * for each traffic class. ++ */ ++ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { ++ if (dcb_config->rx_pba_cfg == pba_equal) { ++ rx_pba_size = IXGBE_RXPBSIZE_64KB; ++ } else { ++ rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB ++ : IXGBE_RXPBSIZE_48KB; ++ } ++ ++ reg = ((rx_pba_size >> 5) & 0xFFF0); ++ if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || ++ dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) ++ reg |= IXGBE_FCRTL_XONE; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg); ++ ++ reg = ((rx_pba_size >> 2) & 0xFFF0); ++ if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || ++ dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) ++ reg |= IXGBE_FCRTH_FCEN; ++ ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); ++ } ++ ++ /* Configure pause time */ ++ for (i = 0; i < (MAX_TRAFFIC_CLASS >> 1); i++) ++ IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), 0x68006800); ++ ++ /* Configure flow control refresh threshold value */ ++ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400); ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_config_tc_stats_82598 - Configure traffic class statistics ++ * @hw: pointer to hardware structure ++ * ++ * Configure queue statistics registers, all queues belonging to same traffic ++ * class uses a single set of queue statistics counters. ++ */ ++s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) ++{ ++ u32 reg = 0; ++ u8 i = 0; ++ u8 j = 0; ++ ++ /* Receive Queues stats setting - 8 queues per statistics reg */ ++ for (i = 0, j = 0; i < 15 && j < 8; i = i + 2, j++) { ++ reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i)); ++ reg |= ((0x1010101) * j); ++ IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg); ++ reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i + 1)); ++ reg |= ((0x1010101) * j); ++ IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i + 1), reg); ++ } ++ /* Transmit Queues stats setting - 4 queues per statistics reg */ ++ for (i = 0; i < 8; i++) { ++ reg = IXGBE_READ_REG(hw, IXGBE_TQSMR(i)); ++ reg |= ((0x1010101) * i); ++ IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i), reg); ++ } ++ ++ return 0; ++} ++ ++/** ++ * ixgbe_dcb_hw_config_82598 - Config and enable DCB ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure dcb settings and enable dcb mode. ++ */ ++s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ ixgbe_dcb_config_packet_buffers_82598(hw, dcb_config); ++ ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); ++ ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); ++ ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); ++ ixgbe_dcb_config_pfc_82598(hw, dcb_config); ++ ixgbe_dcb_config_tc_stats_82598(hw); ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h +@@ -0,0 +1,98 @@ ++/******************************************************************************* ++ ++ Intel 10 Gigabit PCI Express Linux driver ++ Copyright(c) 1999 - 2007 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _DCB_82598_CONFIG_H_ ++#define _DCB_82598_CONFIG_H_ ++ ++/* DCB register definitions */ ++ ++#define IXGBE_DPMCS_MTSOS_SHIFT 16 ++#define IXGBE_DPMCS_TDPAC 0x00000001 /* 0 Round Robin, 1 DFP - Deficit Fixed Priority */ ++#define IXGBE_DPMCS_TRM 0x00000010 /* Transmit Recycle Mode */ ++#define IXGBE_DPMCS_ARBDIS 0x00000040 /* DCB arbiter disable */ ++#define IXGBE_DPMCS_TSOEF 0x00080000 /* TSO Expand Factor: 0=x4, 1=x2 */ ++ ++#define IXGBE_RUPPBMR_MQA 0x80000000 /* Enable UP to queue mapping */ ++ ++#define IXGBE_RT2CR_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */ ++#define IXGBE_RT2CR_LSP 0x80000000 /* LSP enable bit */ ++ ++#define IXGBE_RDRXCTL_MPBEN 0x00000010 /* DMA config for multiple packet buffers enable */ ++#define IXGBE_RDRXCTL_MCEN 0x00000040 /* DMA config for multiple cores (RSS) enable */ ++ ++#define IXGBE_TDTQ2TCCR_MCL_SHIFT 12 ++#define IXGBE_TDTQ2TCCR_BWG_SHIFT 9 ++#define IXGBE_TDTQ2TCCR_GSP 0x40000000 ++#define IXGBE_TDTQ2TCCR_LSP 0x80000000 ++ ++#define IXGBE_TDPT2TCCR_MCL_SHIFT 12 ++#define IXGBE_TDPT2TCCR_BWG_SHIFT 9 ++#define IXGBE_TDPT2TCCR_GSP 0x40000000 ++#define IXGBE_TDPT2TCCR_LSP 0x80000000 ++ ++#define IXGBE_PDPMCS_TPPAC 0x00000020 /* 0 Round Robin, 1 for DFP - Deficit Fixed Priority */ ++#define IXGBE_PDPMCS_ARBDIS 0x00000040 /* Arbiter disable */ ++#define IXGBE_PDPMCS_TRM 0x00000100 /* Transmit Recycle Mode enable */ ++ ++#define IXGBE_DTXCTL_ENDBUBD 0x00000004 /* Enable DBU buffer division */ ++ ++#define IXGBE_TXPBSIZE_40KB 0x0000A000 /* 40KB Packet Buffer */ ++#define IXGBE_RXPBSIZE_48KB 0x0000C000 /* 48KB Packet Buffer */ ++#define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ ++#define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ ++ ++#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 ++ ++/* DCB hardware-specific driver APIs */ ++ ++/* DCB PFC functions */ ++s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw, ++ struct ixgbe_hw_stats *stats, ++ u8 tc_count); ++ ++/* DCB traffic class stats */ ++s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw); ++s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw, ++ struct ixgbe_hw_stats *stats, ++ u8 tc_count); ++ ++/* DCB config arbiters */ ++s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++ ++/* DCB hw initialization */ ++s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *config); ++ ++#endif /* _DCB_82598_CONFIG_H */ +--- /dev/null ++++ b/drivers/net/ixgbe/ixgbe_dcb.c +@@ -0,0 +1,332 @@ ++/******************************************************************************* ++ ++ Intel 10 Gigabit PCI Express Linux driver ++ Copyright(c) 1999 - 2007 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++ ++#include "ixgbe.h" ++#include "ixgbe_type.h" ++#include "ixgbe_dcb.h" ++#include "ixgbe_dcb_82598.h" ++ ++/** ++ * ixgbe_dcb_config - Struct containing DCB settings. ++ * @dcb_config: Pointer to DCB config structure ++ * ++ * This function checks DCB rules for DCB settings. ++ * The following rules are checked: ++ * 1. The sum of bandwidth percentages of all Bandwidth Groups must total 100%. ++ * 2. The sum of bandwidth percentages of all Traffic Classes within a Bandwidth ++ * Group must total 100. ++ * 3. A Traffic Class should not be set to both Link Strict Priority ++ * and Group Strict Priority. ++ * 4. Link strict Bandwidth Groups can only have link strict traffic classes ++ * with zero bandwidth. ++ */ ++s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *dcb_config) ++{ ++ struct tc_bw_alloc *p; ++ s32 ret_val = 0; ++ u8 i, j, bw = 0, bw_id; ++ u8 bw_sum[2][MAX_BW_GROUP]; ++ bool link_strict[2][MAX_BW_GROUP]; ++ ++ memset(bw_sum, 0, sizeof(bw_sum)); ++ memset(link_strict, 0, sizeof(link_strict)); ++ ++ /* First Tx, then Rx */ ++ for (i = 0; i < 2; i++) { ++ /* Check each traffic class for rule violation */ ++ for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { ++ p = &dcb_config->tc_config[j].path[i]; ++ ++ bw = p->bwg_percent; ++ bw_id = p->bwg_id; ++ ++ if (bw_id >= MAX_BW_GROUP) { ++ ret_val = DCB_ERR_CONFIG; ++ goto err_config; ++ } ++ if (p->prio_type == prio_link) { ++ link_strict[i][bw_id] = true; ++ /* Link strict should have zero bandwidth */ ++ if (bw) { ++ ret_val = DCB_ERR_LS_BW_NONZERO; ++ goto err_config; ++ } ++ } else if (!bw) { ++ /* ++ * Traffic classes without link strict ++ * should have non-zero bandwidth. ++ */ ++ ret_val = DCB_ERR_TC_BW_ZERO; ++ goto err_config; ++ } ++ bw_sum[i][bw_id] += bw; ++ } ++ ++ bw = 0; ++ ++ /* Check each bandwidth group for rule violation */ ++ for (j = 0; j < MAX_BW_GROUP; j++) { ++ bw += dcb_config->bw_percentage[i][j]; ++ /* ++ * Sum of bandwidth percentages of all traffic classes ++ * within a Bandwidth Group must total 100 except for ++ * link strict group (zero bandwidth). ++ */ ++ if (link_strict[i][j]) { ++ if (bw_sum[i][j]) { ++ /* ++ * Link strict group should have zero ++ * bandwidth. ++ */ ++ ret_val = DCB_ERR_LS_BWG_NONZERO; ++ goto err_config; ++ } ++ } else if (bw_sum[i][j] != BW_PERCENT && ++ bw_sum[i][j] != 0) { ++ ret_val = DCB_ERR_TC_BW; ++ goto err_config; ++ } ++ } ++ ++ if (bw != BW_PERCENT) { ++ ret_val = DCB_ERR_BW_GROUP; ++ goto err_config; ++ } ++ } ++ ++err_config: ++ return ret_val; ++} ++ ++/** ++ * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits ++ * @ixgbe_dcb_config: Struct containing DCB settings. ++ * @direction: Configuring either Tx or Rx. ++ * ++ * This function calculates the credits allocated to each traffic class. ++ * It should be called only after the rules are checked by ++ * ixgbe_dcb_check_config(). ++ */ ++s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, ++ u8 direction) ++{ ++ struct tc_bw_alloc *p; ++ s32 ret_val = 0; ++ /* Initialization values default for Tx settings */ ++ u32 credit_refill = 0; ++ u32 credit_max = 0; ++ u16 link_percentage = 0; ++ u8 bw_percent = 0; ++ u8 i; ++ ++ if (dcb_config == NULL) { ++ ret_val = DCB_ERR_CONFIG; ++ goto out; ++ } ++ ++ /* Find out the link percentage for each TC first */ ++ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { ++ p = &dcb_config->tc_config[i].path[direction]; ++ bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; ++ ++ link_percentage = p->bwg_percent; ++ /* Must be careful of integer division for very small nums */ ++ link_percentage = (link_percentage * bw_percent) / 100; ++ if (p->bwg_percent > 0 && link_percentage == 0) ++ link_percentage = 1; ++ ++ /* Save link_percentage for reference */ ++ p->link_percent = (u8)link_percentage; ++ ++ /* Calculate credit refill and save it */ ++ credit_refill = link_percentage * MINIMUM_CREDIT_REFILL; ++ p->data_credits_refill = (u16)credit_refill; ++ ++ /* Calculate maximum credit for the TC */ ++ credit_max = (link_percentage * MAX_CREDIT) / 100; ++ ++ /* ++ * Adjustment based on rule checking, if the percentage ++ * of a TC is too small, the maximum credit may not be ++ * enough to send out a jumbo frame in data plane arbitration. ++ */ ++ if (credit_max && (credit_max < MINIMUM_CREDIT_FOR_JUMBO)) ++ credit_max = MINIMUM_CREDIT_FOR_JUMBO; ++ ++ if (direction == DCB_TX_CONFIG) { ++ /* ++ * Adjustment based on rule checking, if the ++ * percentage of a TC is too small, the maximum ++ * credit may not be enough to send out a TSO ++ * packet in descriptor plane arbitration. ++ */ ++ if (credit_max && ++ (credit_max < MINIMUM_CREDIT_FOR_TSO)) ++ credit_max = MINIMUM_CREDIT_FOR_TSO; ++ ++ dcb_config->tc_config[i].desc_credits_max = ++ (u16)credit_max; ++ } ++ ++ p->data_credits_max = (u16)credit_max; ++ } ++ ++out: ++ return ret_val; ++} ++ ++/** ++ * ixgbe_dcb_get_tc_stats - Returns status of each traffic class ++ * @hw: pointer to hardware structure ++ * @stats: pointer to statistics structure ++ * @tc_count: Number of elements in bwg_array. ++ * ++ * This function returns the status data for each of the Traffic Classes in use. ++ */ ++s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, ++ u8 tc_count) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_get_pfc_stats - Returns CBFC status of each traffic class ++ * hw - pointer to hardware structure ++ * stats - pointer to statistics structure ++ * tc_count - Number of elements in bwg_array. ++ * ++ * This function returns the CBFC status data for each of the Traffic Classes. ++ */ ++s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, ++ u8 tc_count) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_config_rx_arbiter - Config Rx arbiter ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Rx Data Arbiter and credits for each traffic class. ++ */ ++s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_config_tx_desc_arbiter - Config Tx Desc arbiter ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Tx Descriptor Arbiter and credits for each traffic class. ++ */ ++s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_config_tx_data_arbiter - Config Tx data arbiter ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Tx Data Arbiter and credits for each traffic class. ++ */ ++s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_config_pfc - Config priority flow control ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure Priority Flow Control for each traffic class. ++ */ ++s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_config_pfc_82598(hw, dcb_config); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_config_tc_stats - Config traffic class statistics ++ * @hw: pointer to hardware structure ++ * ++ * Configure queue statistics registers, all queues belonging to same traffic ++ * class uses a single set of queue statistics counters. ++ */ ++s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_config_tc_stats_82598(hw); ++ return ret; ++} ++ ++/** ++ * ixgbe_dcb_hw_config - Config and enable DCB ++ * @hw: pointer to hardware structure ++ * @dcb_config: pointer to ixgbe_dcb_config structure ++ * ++ * Configure dcb settings and enable dcb mode. ++ */ ++s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config) ++{ ++ s32 ret = 0; ++ if (hw->mac.type == ixgbe_mac_82598EB) ++ ret = ixgbe_dcb_hw_config_82598(hw, dcb_config); ++ return ret; ++} ++ +--- /dev/null ++++ b/drivers/net/ixgbe/ixgbe_dcb.h +@@ -0,0 +1,189 @@ ++/******************************************************************************* ++ ++ Intel 10 Gigabit PCI Express Linux driver ++ Copyright(c) 1999 - 2007 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#ifndef _DCB_CONFIG_H_ ++#define _DCB_CONFIG_H_ ++ ++#include "ixgbe_type.h" ++ ++/* DCB data structures */ ++ ++#define IXGBE_MAX_PACKET_BUFFERS 8 ++#define MAX_USER_PRIORITY 8 ++#define MAX_TRAFFIC_CLASS 8 ++#define MAX_BW_GROUP 8 ++#define BW_PERCENT 100 ++ ++#define DCB_TX_CONFIG 0 ++#define DCB_RX_CONFIG 1 ++ ++/* DCB error Codes */ ++#define DCB_SUCCESS 0 ++#define DCB_ERR_CONFIG -1 ++#define DCB_ERR_PARAM -2 ++ ++/* Transmit and receive Errors */ ++/* Error in bandwidth group allocation */ ++#define DCB_ERR_BW_GROUP -3 ++/* Error in traffic class bandwidth allocation */ ++#define DCB_ERR_TC_BW -4 ++/* Traffic class has both link strict and group strict enabled */ ++#define DCB_ERR_LS_GS -5 ++/* Link strict traffic class has non zero bandwidth */ ++#define DCB_ERR_LS_BW_NONZERO -6 ++/* Link strict bandwidth group has non zero bandwidth */ ++#define DCB_ERR_LS_BWG_NONZERO -7 ++/* Traffic class has zero bandwidth */ ++#define DCB_ERR_TC_BW_ZERO -8 ++ ++#define DCB_NOT_IMPLEMENTED 0x7FFFFFFF ++ ++struct dcb_pfc_tc_debug { ++ u8 tc; ++ u8 pause_status; ++ u64 pause_quanta; ++}; ++ ++enum strict_prio_type { ++ prio_none = 0, ++ prio_group, ++ prio_link ++}; ++ ++/* Traffic class bandwidth allocation per direction */ ++struct tc_bw_alloc { ++ u8 bwg_id; /* Bandwidth Group (BWG) ID */ ++ u8 bwg_percent; /* % of BWG's bandwidth */ ++ u8 link_percent; /* % of link bandwidth */ ++ u8 up_to_tc_bitmap; /* User Priority to Traffic Class mapping */ ++ u16 data_credits_refill; /* Credit refill amount in 64B granularity */ ++ u16 data_credits_max; /* Max credits for a configured packet buffer ++ * in 64B granularity.*/ ++ enum strict_prio_type prio_type; /* Link or Group Strict Priority */ ++}; ++ ++enum dcb_pfc_type { ++ pfc_disabled = 0, ++ pfc_enabled_full, ++ pfc_enabled_tx, ++ pfc_enabled_rx ++}; ++ ++/* Traffic class configuration */ ++struct tc_configuration { ++ struct tc_bw_alloc path[2]; /* One each for Tx/Rx */ ++ enum dcb_pfc_type dcb_pfc; /* Class based flow control setting */ ++ ++ u16 desc_credits_max; /* For Tx Descriptor arbitration */ ++ u8 tc; /* Traffic class (TC) */ ++}; ++ ++enum dcb_rx_pba_cfg { ++ pba_equal, /* PBA[0-7] each use 64KB FIFO */ ++ pba_80_48 /* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */ ++}; ++ ++/* ++ * This structure contains many values encoded as fixed-point ++ * numbers, meaning that some of bits are dedicated to the ++ * magnitude and others to the fraction part. In the comments ++ * this is shown as f=n, where n is the number of fraction bits. ++ * These fraction bits are always the low-order bits. The size ++ * of the magnitude is not specified. ++ */ ++struct bcn_config { ++ u32 rp_admin_mode[MAX_TRAFFIC_CLASS]; /* BCN enabled, per TC */ ++ u32 bcna_option[2]; /* BCNA Port + MAC Addr */ ++ u32 rp_w; /* Derivative Weight, f=3 */ ++ u32 rp_gi; /* Increase Gain, f=12 */ ++ u32 rp_gd; /* Decrease Gain, f=12 */ ++ u32 rp_ru; /* Rate Unit */ ++ u32 rp_alpha; /* Max Decrease Factor, f=12 */ ++ u32 rp_beta; /* Max Increase Factor, f=12 */ ++ u32 rp_ri; /* Initial Rate */ ++ u32 rp_td; /* Drift Interval Timer */ ++ u32 rp_rd; /* Drift Increase */ ++ u32 rp_tmax; /* Severe Congestion Backoff Timer Range */ ++ u32 rp_rmin; /* Severe Congestion Restart Rate */ ++ u32 rp_wrtt; /* RTT Moving Average Weight */ ++}; ++ ++struct ixgbe_dcb_config { ++ struct bcn_config bcn; ++ ++ struct tc_configuration tc_config[MAX_TRAFFIC_CLASS]; ++ u8 bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */ ++ ++ bool round_robin_enable; ++ ++ enum dcb_rx_pba_cfg rx_pba_cfg; ++ ++ u32 dcb_cfg_version; /* Not used...OS-specific? */ ++ u32 link_speed; /* For bandwidth allocation validation purpose */ ++}; ++ ++/* DCB driver APIs */ ++ ++/* DCB rule checking function.*/ ++s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *config); ++ ++/* DCB credits calculation */ ++s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *config, ++ u8 direction); ++ ++/* DCB PFC functions */ ++s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, ++ u8 tc_count); ++ ++/* DCB traffic class stats */ ++s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *); ++s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, ++ u8 tc_count); ++ ++/* DCB config arbiters */ ++s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw, ++ struct ixgbe_dcb_config *dcb_config); ++ ++/* DCB hw initialization */ ++s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, struct ixgbe_dcb_config *config); ++ ++/* DCB definitions for credit calculation */ ++#define MAX_CREDIT_REFILL 511 /* 0x1FF * 64B = 32704B */ ++#define MINIMUM_CREDIT_REFILL 5 /* 5*64B = 320B */ ++#define MINIMUM_CREDIT_FOR_JUMBO 145 /* 145= UpperBound((9*1024+54)/64B) for 9KB jumbo frame */ ++#define DCB_MAX_TSO_SIZE (32*1024) /* MAX TSO packet size supported in DCB mode */ ++#define MINIMUM_CREDIT_FOR_TSO (DCB_MAX_TSO_SIZE/64 + 1) /* 513 for 32KB TSO packet */ ++#define MAX_CREDIT 4095 /* Maximum credit supported: 256KB * 1204 / 64B */ ++ ++#endif /* _DCB_CONFIG_H */ +--- /dev/null ++++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c +@@ -0,0 +1,611 @@ ++/******************************************************************************* ++ ++ Intel 10 Gigabit PCI Express Linux driver ++ Copyright(c) 1999 - 2008 Intel Corporation. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms and conditions of the GNU General Public License, ++ version 2, as published by the Free Software Foundation. ++ ++ This program is distributed in the hope it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., ++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ ++ The full GNU General Public License is included in this distribution in ++ the file called "COPYING". ++ ++ Contact Information: ++ Linux NICS ++ e1000-devel Mailing List ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include "ixgbe.h" ++#include ++ ++/* Callbacks for DCB netlink in the kernel */ ++#define BIT_DCB_MODE 0x01 ++#define BIT_PFC 0x02 ++#define BIT_PG_RX 0x04 ++#define BIT_PG_TX 0x08 ++#define BIT_BCN 0x10 ++ ++int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, ++ struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max) ++{ ++ struct tc_configuration *src_tc_cfg = NULL; ++ struct tc_configuration *dst_tc_cfg = NULL; ++ int i; ++ ++ if (!src_dcb_cfg || !dst_dcb_cfg) ++ return -EINVAL; ++ ++ for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) { ++ src_tc_cfg = &src_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; ++ dst_tc_cfg = &dst_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; ++ ++ dst_tc_cfg->path[DCB_TX_CONFIG].prio_type = ++ src_tc_cfg->path[DCB_TX_CONFIG].prio_type; ++ ++ dst_tc_cfg->path[DCB_TX_CONFIG].bwg_id = ++ src_tc_cfg->path[DCB_TX_CONFIG].bwg_id; ++ ++ dst_tc_cfg->path[DCB_TX_CONFIG].bwg_percent = ++ src_tc_cfg->path[DCB_TX_CONFIG].bwg_percent; ++ ++ dst_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap = ++ src_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap; ++ ++ dst_tc_cfg->path[DCB_RX_CONFIG].prio_type = ++ src_tc_cfg->path[DCB_RX_CONFIG].prio_type; ++ ++ dst_tc_cfg->path[DCB_RX_CONFIG].bwg_id = ++ src_tc_cfg->path[DCB_RX_CONFIG].bwg_id; ++ ++ dst_tc_cfg->path[DCB_RX_CONFIG].bwg_percent = ++ src_tc_cfg->path[DCB_RX_CONFIG].bwg_percent; ++ ++ dst_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap = ++ src_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap; ++ } ++ ++ for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) { ++ dst_dcb_cfg->bw_percentage[DCB_TX_CONFIG] ++ [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage ++ [DCB_TX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; ++ dst_dcb_cfg->bw_percentage[DCB_RX_CONFIG] ++ [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage ++ [DCB_RX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; ++ } ++ ++ for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) { ++ dst_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc = ++ src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc; ++ } ++ ++ for (i = DCB_BCN_ATTR_RP_0; i < DCB_BCN_ATTR_RP_ALL; i++) { ++ dst_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0] = ++ src_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0]; ++ } ++ dst_dcb_cfg->bcn.rp_alpha = src_dcb_cfg->bcn.rp_alpha; ++ dst_dcb_cfg->bcn.rp_beta = src_dcb_cfg->bcn.rp_beta; ++ dst_dcb_cfg->bcn.rp_gd = src_dcb_cfg->bcn.rp_gd; ++ dst_dcb_cfg->bcn.rp_gi = src_dcb_cfg->bcn.rp_gi; ++ dst_dcb_cfg->bcn.rp_tmax = src_dcb_cfg->bcn.rp_tmax; ++ dst_dcb_cfg->bcn.rp_td = src_dcb_cfg->bcn.rp_td; ++ dst_dcb_cfg->bcn.rp_rmin = src_dcb_cfg->bcn.rp_rmin; ++ dst_dcb_cfg->bcn.rp_w = src_dcb_cfg->bcn.rp_w; ++ dst_dcb_cfg->bcn.rp_rd = src_dcb_cfg->bcn.rp_rd; ++ dst_dcb_cfg->bcn.rp_ru = src_dcb_cfg->bcn.rp_ru; ++ dst_dcb_cfg->bcn.rp_wrtt = src_dcb_cfg->bcn.rp_wrtt; ++ dst_dcb_cfg->bcn.rp_ri = src_dcb_cfg->bcn.rp_ri; ++ ++ return 0; ++} ++ ++static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ DPRINTK(DRV, INFO, "Get DCB Admin Mode.\n"); ++ ++ return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); ++} ++ ++static u16 ixgbe_dcb_select_queue(struct net_device *dev, struct sk_buff *skb) ++{ ++ /* All traffic should default to class 0 */ ++ return 0; ++} ++ ++static void ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ DPRINTK(DRV, INFO, "Set DCB Admin Mode.\n"); ++ ++ if (state > 0) { ++ /* Turn on DCB */ ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ return; ++ } else { ++ if (netdev->flags & IFF_UP) ++ netdev->stop(netdev); ++ ixgbe_reset_interrupt_capability(adapter); ++ ixgbe_napi_del_all(adapter); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ adapter->tx_ring = NULL; ++ adapter->rx_ring = NULL; ++ netdev->select_queue = &ixgbe_dcb_select_queue; ++ ++ adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ++ adapter->flags |= IXGBE_FLAG_DCB_ENABLED; ++ ixgbe_init_interrupt_scheme(adapter); ++ ixgbe_napi_add_all(adapter); ++ if (netdev->flags & IFF_UP) ++ netdev->open(netdev); ++ } ++ } else { ++ /* Turn off DCB */ ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ if (netdev->flags & IFF_UP) ++ netdev->stop(netdev); ++ ixgbe_reset_interrupt_capability(adapter); ++ ixgbe_napi_del_all(adapter); ++ kfree(adapter->tx_ring); ++ kfree(adapter->rx_ring); ++ adapter->tx_ring = NULL; ++ adapter->rx_ring = NULL; ++ netdev->select_queue = NULL; ++ ++ adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; ++ adapter->flags |= IXGBE_FLAG_RSS_ENABLED; ++ ixgbe_init_interrupt_scheme(adapter); ++ ixgbe_napi_add_all(adapter); ++ if (netdev->flags & IFF_UP) ++ netdev->open(netdev); ++ } else { ++ return; ++ } ++ } ++} ++ ++static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, ++ u8 *perm_addr) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ int i; ++ ++ for (i = 0; i < netdev->addr_len; i++) ++ perm_addr[i] = adapter->hw.mac.perm_addr[i]; ++} ++ ++static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, ++ u8 prio, u8 bwg_id, u8 bw_pct, ++ u8 up_map) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ if (prio != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio; ++ if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id = bwg_id; ++ if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent = ++ bw_pct; ++ if (up_map != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap = ++ up_map; ++ ++ if ((adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type != ++ adapter->dcb_cfg.tc_config[tc].path[0].prio_type) || ++ (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id != ++ adapter->dcb_cfg.tc_config[tc].path[0].bwg_id) || ++ (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != ++ adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || ++ (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != ++ adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) ++ adapter->dcb_set_bitmap |= BIT_PG_TX; ++} ++ ++static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, ++ u8 bw_pct) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; ++ ++ if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != ++ adapter->dcb_cfg.bw_percentage[0][bwg_id]) ++ adapter->dcb_set_bitmap |= BIT_PG_RX; ++} ++ ++static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, ++ u8 prio, u8 bwg_id, u8 bw_pct, ++ u8 up_map) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ if (prio != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio; ++ if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id = bwg_id; ++ if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent = ++ bw_pct; ++ if (up_map != DCB_ATTR_VALUE_UNDEFINED) ++ adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap = ++ up_map; ++ ++ if ((adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type != ++ adapter->dcb_cfg.tc_config[tc].path[1].prio_type) || ++ (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id != ++ adapter->dcb_cfg.tc_config[tc].path[1].bwg_id) || ++ (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != ++ adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || ++ (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != ++ adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) ++ adapter->dcb_set_bitmap |= BIT_PG_RX; ++} ++ ++static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, ++ u8 bw_pct) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; ++ ++ if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != ++ adapter->dcb_cfg.bw_percentage[1][bwg_id]) ++ adapter->dcb_set_bitmap |= BIT_PG_RX; ++} ++ ++static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, ++ u8 *prio, u8 *bwg_id, u8 *bw_pct, ++ u8 *up_map) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ *prio = adapter->dcb_cfg.tc_config[tc].path[0].prio_type; ++ *bwg_id = adapter->dcb_cfg.tc_config[tc].path[0].bwg_id; ++ *bw_pct = adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent; ++ *up_map = adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap; ++} ++ ++static void ixgbe_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, ++ u8 *bw_pct) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ *bw_pct = adapter->dcb_cfg.bw_percentage[0][bwg_id]; ++} ++ ++static void ixgbe_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int tc, ++ u8 *prio, u8 *bwg_id, u8 *bw_pct, ++ u8 *up_map) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ *prio = adapter->dcb_cfg.tc_config[tc].path[1].prio_type; ++ *bwg_id = adapter->dcb_cfg.tc_config[tc].path[1].bwg_id; ++ *bw_pct = adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent; ++ *up_map = adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap; ++} ++ ++static void ixgbe_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, ++ u8 *bw_pct) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ *bw_pct = adapter->dcb_cfg.bw_percentage[1][bwg_id]; ++} ++ ++static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, ++ u8 setting) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting; ++ if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc != ++ adapter->dcb_cfg.tc_config[priority].dcb_pfc) ++ adapter->dcb_set_bitmap |= BIT_PFC; ++} ++ ++static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, ++ u8 *setting) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ *setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc; ++} ++ ++static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ int ret; ++ ++ adapter->dcb_set_bitmap &= ~BIT_BCN; /* no set for BCN */ ++ if (!adapter->dcb_set_bitmap) ++ return 1; ++ ++ while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) ++ msleep(1); ++ ++ ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, ++ adapter->ring_feature[RING_F_DCB].indices); ++ if (ret) { ++ clear_bit(__IXGBE_RESETTING, &adapter->state); ++ return ret; ++ } ++ ++ ixgbe_down(adapter); ++ ixgbe_up(adapter); ++ adapter->dcb_set_bitmap = 0x00; ++ clear_bit(__IXGBE_RESETTING, &adapter->state); ++ return ret; ++} ++ ++static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ u8 rval = 0; ++ ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ switch (capid) { ++ case DCB_CAP_ATTR_PG: ++ *cap = true; ++ break; ++ case DCB_CAP_ATTR_PFC: ++ *cap = true; ++ break; ++ case DCB_CAP_ATTR_UP2TC: ++ *cap = false; ++ break; ++ case DCB_CAP_ATTR_PG_TCS: ++ *cap = 0x80; ++ break; ++ case DCB_CAP_ATTR_PFC_TCS: ++ *cap = 0x80; ++ break; ++ case DCB_CAP_ATTR_GSP: ++ *cap = true; ++ break; ++ case DCB_CAP_ATTR_BCN: ++ *cap = false; ++ break; ++ default: ++ rval = -EINVAL; ++ break; ++ } ++ } else { ++ rval = -EINVAL; ++ } ++ ++ return rval; ++} ++ ++static u8 ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ u8 rval = 0; ++ ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ switch (tcid) { ++ case DCB_NUMTCS_ATTR_PG: ++ *num = MAX_TRAFFIC_CLASS; ++ break; ++ case DCB_NUMTCS_ATTR_PFC: ++ *num = MAX_TRAFFIC_CLASS; ++ break; ++ default: ++ rval = -EINVAL; ++ break; ++ } ++ } else { ++ rval = -EINVAL; ++ } ++ ++ return rval; ++} ++ ++static u8 ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num) ++{ ++ return -EINVAL; ++} ++ ++static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); ++} ++ ++static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) ++{ ++ return; ++} ++ ++static void ixgbe_dcbnl_getbcnrp(struct net_device *netdev, int priority, ++ u8 *setting) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ *setting = adapter->dcb_cfg.bcn.rp_admin_mode[priority]; ++} ++ ++ ++static void ixgbe_dcbnl_getbcncfg(struct net_device *netdev, int enum_index, ++ u32 *setting) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ switch (enum_index) { ++ case DCB_BCN_ATTR_ALPHA: ++ *setting = adapter->dcb_cfg.bcn.rp_alpha; ++ break; ++ case DCB_BCN_ATTR_BETA: ++ *setting = adapter->dcb_cfg.bcn.rp_beta; ++ break; ++ case DCB_BCN_ATTR_GD: ++ *setting = adapter->dcb_cfg.bcn.rp_gd; ++ break; ++ case DCB_BCN_ATTR_GI: ++ *setting = adapter->dcb_cfg.bcn.rp_gi; ++ break; ++ case DCB_BCN_ATTR_TMAX: ++ *setting = adapter->dcb_cfg.bcn.rp_tmax; ++ break; ++ case DCB_BCN_ATTR_TD: ++ *setting = adapter->dcb_cfg.bcn.rp_td; ++ break; ++ case DCB_BCN_ATTR_RMIN: ++ *setting = adapter->dcb_cfg.bcn.rp_rmin; ++ break; ++ case DCB_BCN_ATTR_W: ++ *setting = adapter->dcb_cfg.bcn.rp_w; ++ break; ++ case DCB_BCN_ATTR_RD: ++ *setting = adapter->dcb_cfg.bcn.rp_rd; ++ break; ++ case DCB_BCN_ATTR_RU: ++ *setting = adapter->dcb_cfg.bcn.rp_ru; ++ break; ++ case DCB_BCN_ATTR_WRTT: ++ *setting = adapter->dcb_cfg.bcn.rp_wrtt; ++ break; ++ case DCB_BCN_ATTR_RI: ++ *setting = adapter->dcb_cfg.bcn.rp_ri; ++ break; ++ default: ++ *setting = -1; ++ } ++} ++ ++static void ixgbe_dcbnl_setbcnrp(struct net_device *netdev, int priority, ++ u8 setting) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] = setting; ++ ++ if (adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] != ++ adapter->dcb_cfg.bcn.rp_admin_mode[priority]) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++} ++ ++static void ixgbe_dcbnl_setbcncfg(struct net_device *netdev, int enum_index, ++ u32 setting) ++{ ++ struct ixgbe_adapter *adapter = netdev_priv(netdev); ++ ++ switch (enum_index) { ++ case DCB_BCN_ATTR_ALPHA: ++ adapter->temp_dcb_cfg.bcn.rp_alpha = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_alpha != ++ adapter->dcb_cfg.bcn.rp_alpha) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_BETA: ++ adapter->temp_dcb_cfg.bcn.rp_beta = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_beta != ++ adapter->dcb_cfg.bcn.rp_beta) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_GD: ++ adapter->temp_dcb_cfg.bcn.rp_gd = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_gd != ++ adapter->dcb_cfg.bcn.rp_gd) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_GI: ++ adapter->temp_dcb_cfg.bcn.rp_gi = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_gi != ++ adapter->dcb_cfg.bcn.rp_gi) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_TMAX: ++ adapter->temp_dcb_cfg.bcn.rp_tmax = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_tmax != ++ adapter->dcb_cfg.bcn.rp_tmax) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_TD: ++ adapter->temp_dcb_cfg.bcn.rp_td = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_td != ++ adapter->dcb_cfg.bcn.rp_td) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_RMIN: ++ adapter->temp_dcb_cfg.bcn.rp_rmin = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_rmin != ++ adapter->dcb_cfg.bcn.rp_rmin) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_W: ++ adapter->temp_dcb_cfg.bcn.rp_w = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_w != ++ adapter->dcb_cfg.bcn.rp_w) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_RD: ++ adapter->temp_dcb_cfg.bcn.rp_rd = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_rd != ++ adapter->dcb_cfg.bcn.rp_rd) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_RU: ++ adapter->temp_dcb_cfg.bcn.rp_ru = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_ru != ++ adapter->dcb_cfg.bcn.rp_ru) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_WRTT: ++ adapter->temp_dcb_cfg.bcn.rp_wrtt = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_wrtt != ++ adapter->dcb_cfg.bcn.rp_wrtt) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ case DCB_BCN_ATTR_RI: ++ adapter->temp_dcb_cfg.bcn.rp_ri = setting; ++ if (adapter->temp_dcb_cfg.bcn.rp_ri != ++ adapter->dcb_cfg.bcn.rp_ri) ++ adapter->dcb_set_bitmap |= BIT_BCN; ++ break; ++ default: ++ break; ++ } ++} ++ ++struct dcbnl_rtnl_ops dcbnl_ops = { ++ .getstate = ixgbe_dcbnl_get_state, ++ .setstate = ixgbe_dcbnl_set_state, ++ .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, ++ .setpgtccfgtx = ixgbe_dcbnl_set_pg_tc_cfg_tx, ++ .setpgbwgcfgtx = ixgbe_dcbnl_set_pg_bwg_cfg_tx, ++ .setpgtccfgrx = ixgbe_dcbnl_set_pg_tc_cfg_rx, ++ .setpgbwgcfgrx = ixgbe_dcbnl_set_pg_bwg_cfg_rx, ++ .getpgtccfgtx = ixgbe_dcbnl_get_pg_tc_cfg_tx, ++ .getpgbwgcfgtx = ixgbe_dcbnl_get_pg_bwg_cfg_tx, ++ .getpgtccfgrx = ixgbe_dcbnl_get_pg_tc_cfg_rx, ++ .getpgbwgcfgrx = ixgbe_dcbnl_get_pg_bwg_cfg_rx, ++ .setpfccfg = ixgbe_dcbnl_set_pfc_cfg, ++ .getpfccfg = ixgbe_dcbnl_get_pfc_cfg, ++ .setall = ixgbe_dcbnl_set_all, ++ .getcap = ixgbe_dcbnl_getcap, ++ .getnumtcs = ixgbe_dcbnl_getnumtcs, ++ .setnumtcs = ixgbe_dcbnl_setnumtcs, ++ .getpfcstate = ixgbe_dcbnl_getpfcstate, ++ .setpfcstate = ixgbe_dcbnl_setpfcstate, ++ .getbcncfg = ixgbe_dcbnl_getbcncfg, ++ .getbcnrp = ixgbe_dcbnl_getbcnrp, ++ .setbcncfg = ixgbe_dcbnl_setbcncfg, ++ .setbcnrp = ixgbe_dcbnl_setbcnrp ++}; ++ +--- a/drivers/net/ixgbe/ixgbe_ethtool.c ++++ b/drivers/net/ixgbe/ixgbe_ethtool.c +@@ -99,9 +99,18 @@ static struct ixgbe_stats ixgbe_gstrings + ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ + ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ + (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) +-#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) + #define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) +-#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) ++#define IXGBE_PB_STATS_LEN ( \ ++ (((struct ixgbe_adapter *)netdev->priv)->flags & \ ++ IXGBE_FLAG_DCB_ENABLED) ? \ ++ (sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \ ++ sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \ ++ sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \ ++ sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \ ++ / sizeof(u64) : 0) ++#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \ ++ IXGBE_PB_STATS_LEN + \ ++ IXGBE_QUEUE_STATS_LEN) + + static int ixgbe_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +@@ -809,6 +818,16 @@ static void ixgbe_get_ethtool_stats(stru + data[i + k] = queue_stat[k]; + i += k; + } ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ for (j = 0; j < MAX_TX_PACKET_BUFFERS; j++) { ++ data[i++] = adapter->stats.pxontxc[j]; ++ data[i++] = adapter->stats.pxofftxc[j]; ++ } ++ for (j = 0; j < MAX_RX_PACKET_BUFFERS; j++) { ++ data[i++] = adapter->stats.pxonrxc[j]; ++ data[i++] = adapter->stats.pxoffrxc[j]; ++ } ++ } + } + + static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, +@@ -837,6 +856,20 @@ static void ixgbe_get_strings(struct net + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) { ++ sprintf(p, "tx_pb_%u_pxon", i); ++ p += ETH_GSTRING_LEN; ++ sprintf(p, "tx_pb_%u_pxoff", i); ++ p += ETH_GSTRING_LEN; ++ } ++ for (i = 0; i < MAX_RX_PACKET_BUFFERS; i++) { ++ sprintf(p, "rx_pb_%u_pxon", i); ++ p += ETH_GSTRING_LEN; ++ sprintf(p, "rx_pb_%u_pxoff", i); ++ p += ETH_GSTRING_LEN; ++ } ++ } + /* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ + break; + } +--- a/drivers/net/ixgbe/ixgbe.h ++++ b/drivers/net/ixgbe/ixgbe.h +@@ -40,6 +40,7 @@ + + #include "ixgbe_type.h" + #include "ixgbe_common.h" ++#include "ixgbe_dcb.h" + + #if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + #include +@@ -89,6 +90,7 @@ + #define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) + #define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) + #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 ++#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 + #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 + + /* wrapper around a pointer to a socket buffer, +@@ -136,7 +138,7 @@ struct ixgbe_ring { + + u16 reg_idx; /* holds the special value that gets the hardware register + * offset associated with this ring, which is different +- * for DCE and RSS modes */ ++ * for DCB and RSS modes */ + + #if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) + /* cpu for tx queue */ +@@ -156,8 +158,10 @@ struct ixgbe_ring { + u16 rx_buf_len; + }; + ++#define RING_F_DCB 0 + #define RING_F_VMDQ 1 + #define RING_F_RSS 2 ++#define IXGBE_MAX_DCB_INDICES 8 + #define IXGBE_MAX_RSS_INDICES 16 + #define IXGBE_MAX_VMDQ_INDICES 16 + struct ixgbe_ring_feature { +@@ -168,6 +172,10 @@ struct ixgbe_ring_feature { + #define MAX_RX_QUEUES 64 + #define MAX_TX_QUEUES 32 + ++#define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \ ++ ? 8 : 1) ++#define MAX_TX_PACKET_BUFFERS MAX_RX_PACKET_BUFFERS ++ + /* MAX_MSIX_Q_VECTORS of these are allocated, + * but we only use one per queue-specific vector. + */ +@@ -219,6 +227,9 @@ struct ixgbe_adapter { + struct work_struct reset_task; + struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; + char name[MAX_MSIX_COUNT][IFNAMSIZ + 5]; ++ struct ixgbe_dcb_config dcb_cfg; ++ struct ixgbe_dcb_config temp_dcb_cfg; ++ u8 dcb_set_bitmap; + + /* Interrupt Throttle Rate */ + u32 itr_setting; +@@ -273,6 +284,7 @@ struct ixgbe_adapter { + #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) + #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) + #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) ++#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 24) + + /* default to trying for four seconds */ + #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) +@@ -318,6 +330,13 @@ enum ixgbe_boards { + }; + + extern struct ixgbe_info ixgbe_82598_info; ++#ifdef CONFIG_DCBNL ++extern struct dcbnl_rtnl_ops dcbnl_ops; ++extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, ++ struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max); ++#endif ++ ++ + + extern char ixgbe_driver_name[]; + extern const char ixgbe_driver_version[]; +@@ -332,5 +351,8 @@ extern int ixgbe_setup_tx_resources(stru + extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); + extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); + extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); +- ++extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter); ++extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); ++void ixgbe_napi_add_all(struct ixgbe_adapter *adapter); ++void ixgbe_napi_del_all(struct ixgbe_adapter *adapter); + #endif /* _IXGBE_H_ */ +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -403,7 +403,7 @@ static void ixgbe_receive_skb(struct ixg + #ifdef CONFIG_IXGBE_LRO + if (adapter->netdev->features & NETIF_F_LRO && + skb->ip_summed == CHECKSUM_UNNECESSARY) { +- if (adapter->vlgrp && is_vlan) ++ if (adapter->vlgrp && is_vlan && (tag != 0)) + lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, + adapter->vlgrp, tag, + rx_desc); +@@ -413,12 +413,12 @@ static void ixgbe_receive_skb(struct ixg + } else { + #endif + if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { +- if (adapter->vlgrp && is_vlan) ++ if (adapter->vlgrp && is_vlan && (tag != 0)) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); + else + netif_receive_skb(skb); + } else { +- if (adapter->vlgrp && is_vlan) ++ if (adapter->vlgrp && is_vlan && (tag != 0)) + vlan_hwaccel_rx(skb, adapter->vlgrp, tag); + else + netif_rx(skb); +@@ -1656,10 +1656,12 @@ static void ixgbe_configure_rx(struct ix + * effects of setting this bit are only that SRRCTL must be + * fully programmed [0..15] + */ +- rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); +- rdrxctl |= IXGBE_RDRXCTL_MVMEN; +- IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); +- ++ if (adapter->flags & ++ (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) { ++ rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); ++ rdrxctl |= IXGBE_RDRXCTL_MVMEN; ++ IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); ++ } + + if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { + /* Fill out redirection table */ +@@ -1718,6 +1720,16 @@ static void ixgbe_vlan_rx_register(struc + ixgbe_irq_disable(adapter); + adapter->vlgrp = grp; + ++ /* ++ * For a DCB driver, always enable VLAN tag stripping so we can ++ * still receive traffic from a DCB-enabled host even if we're ++ * not in DCB mode. ++ */ ++ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); ++ ctrl |= IXGBE_VLNCTRL_VME; ++ ctrl &= ~IXGBE_VLNCTRL_CFIEN; ++ IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); ++ + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); +@@ -1882,6 +1894,42 @@ static void ixgbe_napi_disable_all(struc + } + } + ++/* ++ * ixgbe_configure_dcb - Configure DCB hardware ++ * @adapter: ixgbe adapter struct ++ * ++ * This is called by the driver on open to configure the DCB hardware. ++ * This is also called by the gennetlink interface when reconfiguring ++ * the DCB state. ++ */ ++static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) ++{ ++ struct ixgbe_hw *hw = &adapter->hw; ++ u32 txdctl, vlnctrl; ++ int i, j; ++ ++ ixgbe_dcb_check_config(&adapter->dcb_cfg); ++ ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG); ++ ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG); ++ ++ /* reconfigure the hardware */ ++ ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg); ++ ++ for (i = 0; i < adapter->num_tx_queues; i++) { ++ j = adapter->tx_ring[i].reg_idx; ++ txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); ++ /* PThresh workaround for Tx hang with DFP enabled. */ ++ txdctl |= 32; ++ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); ++ } ++ /* Enable VLAN tag insert/strip */ ++ vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); ++ vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; ++ vlnctrl &= ~IXGBE_VLNCTRL_CFIEN; ++ IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); ++ hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true); ++} ++ + static void ixgbe_configure(struct ixgbe_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +@@ -1890,6 +1938,12 @@ static void ixgbe_configure(struct ixgbe + ixgbe_set_rx_mode(netdev); + + ixgbe_restore_vlan(adapter); ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ netif_set_gso_max_size(netdev, 32768); ++ ixgbe_configure_dcb(adapter); ++ } else { ++ netif_set_gso_max_size(netdev, 65536); ++ } + + ixgbe_configure_tx(adapter); + ixgbe_configure_rx(adapter); +@@ -2236,6 +2290,11 @@ static void ixgbe_reset_task(struct work + struct ixgbe_adapter *adapter; + adapter = container_of(work, struct ixgbe_adapter, reset_task); + ++ /* If we're already down or resetting, just bail */ ++ if (test_bit(__IXGBE_DOWN, &adapter->state) || ++ test_bit(__IXGBE_RESETTING, &adapter->state)) ++ return; ++ + adapter->tx_timeout_count++; + + ixgbe_reinit_locked(adapter); +@@ -2245,15 +2304,31 @@ static void ixgbe_set_num_queues(struct + { + int nrq = 1, ntq = 1; + int feature_mask = 0, rss_i, rss_m; ++ int dcb_i, dcb_m; + + /* Number of supported queues */ + switch (adapter->hw.mac.type) { + case ixgbe_mac_82598EB: ++ dcb_i = adapter->ring_feature[RING_F_DCB].indices; ++ dcb_m = 0; + rss_i = adapter->ring_feature[RING_F_RSS].indices; + rss_m = 0; + feature_mask |= IXGBE_FLAG_RSS_ENABLED; ++ feature_mask |= IXGBE_FLAG_DCB_ENABLED; + + switch (adapter->flags & feature_mask) { ++ case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED): ++ dcb_m = 0x7 << 3; ++ rss_i = min(8, rss_i); ++ rss_m = 0x7; ++ nrq = dcb_i * rss_i; ++ ntq = min(MAX_TX_QUEUES, dcb_i * rss_i); ++ break; ++ case (IXGBE_FLAG_DCB_ENABLED): ++ dcb_m = 0x7 << 3; ++ nrq = dcb_i; ++ ntq = dcb_i; ++ break; + case (IXGBE_FLAG_RSS_ENABLED): + rss_m = 0xF; + nrq = rss_i; +@@ -2261,6 +2336,8 @@ static void ixgbe_set_num_queues(struct + break; + case 0: + default: ++ dcb_i = 0; ++ dcb_m = 0; + rss_i = 0; + rss_m = 0; + nrq = 1; +@@ -2268,6 +2345,12 @@ static void ixgbe_set_num_queues(struct + break; + } + ++ /* Sanity check, we should never have zero queues */ ++ nrq = (nrq ?:1); ++ ntq = (ntq ?:1); ++ ++ adapter->ring_feature[RING_F_DCB].indices = dcb_i; ++ adapter->ring_feature[RING_F_DCB].mask = dcb_m; + adapter->ring_feature[RING_F_RSS].indices = rss_i; + adapter->ring_feature[RING_F_RSS].mask = rss_m; + break; +@@ -2319,6 +2402,7 @@ static void ixgbe_acquire_msix_vectors(s + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; ++ adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + ixgbe_set_num_queues(adapter); + } else { +@@ -2338,15 +2422,42 @@ static void __devinit ixgbe_cache_ring_r + { + int feature_mask = 0, rss_i; + int i, txr_idx, rxr_idx; ++ int dcb_i; + + /* Number of supported queues */ + switch (adapter->hw.mac.type) { + case ixgbe_mac_82598EB: ++ dcb_i = adapter->ring_feature[RING_F_DCB].indices; + rss_i = adapter->ring_feature[RING_F_RSS].indices; + txr_idx = 0; + rxr_idx = 0; ++ feature_mask |= IXGBE_FLAG_DCB_ENABLED; + feature_mask |= IXGBE_FLAG_RSS_ENABLED; + switch (adapter->flags & feature_mask) { ++ case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED): ++ for (i = 0; i < dcb_i; i++) { ++ int j; ++ /* Rx first */ ++ for (j = 0; j < adapter->num_rx_queues; j++) { ++ adapter->rx_ring[rxr_idx].reg_idx = ++ i << 3 | j; ++ rxr_idx++; ++ } ++ /* Tx now */ ++ for (j = 0; j < adapter->num_tx_queues; j++) { ++ adapter->tx_ring[txr_idx].reg_idx = ++ i << 2 | (j >> 1); ++ if (j & 1) ++ txr_idx++; ++ } ++ } ++ case (IXGBE_FLAG_DCB_ENABLED): ++ /* the number of queues is assumed to be symmetric */ ++ for (i = 0; i < dcb_i; i++) { ++ adapter->rx_ring[i].reg_idx = i << 3; ++ adapter->tx_ring[i].reg_idx = i << 2; ++ } ++ break; + case (IXGBE_FLAG_RSS_ENABLED): + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = i; +@@ -2371,7 +2482,7 @@ static void __devinit ixgbe_cache_ring_r + * number of queues at compile-time. The polling_netdev array is + * intended for Multiqueue, but should work fine with a single queue. + **/ +-static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter) ++static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter) + { + int i; + +@@ -2412,8 +2523,7 @@ err_tx_ring_allocation: + * Attempt to configure the interrupts using the best available + * capabilities of the hardware and the kernel. + **/ +-static int __devinit ixgbe_set_interrupt_capability(struct ixgbe_adapter +- *adapter) ++static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) + { + int err = 0; + int vector, v_budget; +@@ -2441,6 +2551,7 @@ static int __devinit ixgbe_set_interrupt + adapter->msix_entries = kcalloc(v_budget, + sizeof(struct msix_entry), GFP_KERNEL); + if (!adapter->msix_entries) { ++ adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + ixgbe_set_num_queues(adapter); + kfree(adapter->tx_ring); +@@ -2481,7 +2592,7 @@ out: + return err; + } + +-static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) ++void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) + { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; +@@ -2505,7 +2616,7 @@ static void ixgbe_reset_interrupt_capabi + * - Hardware queue count (num_*_queues) + * - defined by miscellaneous hardware support/features (RSS, etc.) + **/ +-static int __devinit ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) ++int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) + { + int err; + +@@ -2553,6 +2664,8 @@ static int __devinit ixgbe_sw_init(struc + struct ixgbe_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + unsigned int rss; ++ int j; ++ struct tc_configuration *tc; + + /* PCI config space info */ + +@@ -2566,6 +2679,26 @@ static int __devinit ixgbe_sw_init(struc + rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus()); + adapter->ring_feature[RING_F_RSS].indices = rss; + adapter->flags |= IXGBE_FLAG_RSS_ENABLED; ++ adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; ++ ++ /* Configure DCB traffic classes */ ++ for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { ++ tc = &adapter->dcb_cfg.tc_config[j]; ++ tc->path[DCB_TX_CONFIG].bwg_id = 0; ++ tc->path[DCB_TX_CONFIG].bwg_percent = 12 + (j & 1); ++ tc->path[DCB_RX_CONFIG].bwg_id = 0; ++ tc->path[DCB_RX_CONFIG].bwg_percent = 12 + (j & 1); ++ tc->dcb_pfc = pfc_disabled; ++ } ++ adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100; ++ adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100; ++ adapter->dcb_cfg.rx_pba_cfg = pba_equal; ++ adapter->dcb_cfg.round_robin_enable = false; ++ adapter->dcb_set_bitmap = 0x00; ++#ifdef CONFIG_DCBNL ++ ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, ++ adapter->ring_feature[RING_F_DCB].indices); ++#endif + + /* default flow control settings */ + hw->fc.original_type = ixgbe_fc_none; +@@ -2945,7 +3078,7 @@ static int ixgbe_close(struct net_device + * @adapter: private struct + * helper function to napi_add each possible q_vector->napi + */ +-static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) ++void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) + { + int q_idx, q_vectors; + int (*poll)(struct napi_struct *, int); +@@ -2966,7 +3099,7 @@ static void ixgbe_napi_add_all(struct ix + } + } + +-static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) ++void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) + { + int q_idx; + int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; +@@ -3087,6 +3220,18 @@ void ixgbe_update_stats(struct ixgbe_ada + adapter->stats.mpc[i] += mpc; + total_mpc += adapter->stats.mpc[i]; + adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); ++ adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); ++ adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i)); ++ adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); ++ adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i)); ++ adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw, ++ IXGBE_PXONRXC(i)); ++ adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw, ++ IXGBE_PXONTXC(i)); ++ adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw, ++ IXGBE_PXOFFRXC(i)); ++ adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw, ++ IXGBE_PXOFFTXC(i)); + } + adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); + /* work around hardware counting issue */ +@@ -3584,6 +3729,14 @@ static int ixgbe_xmit_frame(struct sk_bu + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= vlan_tx_tag_get(skb); ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK; ++ tx_flags |= (skb->queue_mapping << 13); ++ } ++ tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; ++ tx_flags |= IXGBE_TX_FLAGS_VLAN; ++ } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { ++ tx_flags |= (skb->queue_mapping << 13); + tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IXGBE_TX_FLAGS_VLAN; + } +@@ -3852,6 +4005,13 @@ static int __devinit ixgbe_probe(struct + netdev->vlan_features |= NETIF_F_IP_CSUM; + netdev->vlan_features |= NETIF_F_SG; + ++ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) ++ adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ++ ++#ifdef CONFIG_DCBNL ++ netdev->dcbnl_ops = &dcbnl_ops; ++#endif ++ + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + +@@ -4108,7 +4268,6 @@ static struct pci_driver ixgbe_driver = + **/ + static int __init ixgbe_init_module(void) + { +- int ret; + printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name, + ixgbe_driver_string, ixgbe_driver_version); + +@@ -4118,8 +4277,7 @@ static int __init ixgbe_init_module(void + dca_register_notify(&dca_notifier); + + #endif +- ret = pci_register_driver(&ixgbe_driver); +- return ret; ++ return pci_register_driver(&ixgbe_driver); + } + + module_init(ixgbe_init_module); +--- a/drivers/net/ixgbe/Makefile ++++ b/drivers/net/ixgbe/Makefile +@@ -33,4 +33,5 @@ + obj-$(CONFIG_IXGBE) += ixgbe.o + + ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ +- ixgbe_82598.o ixgbe_phy.o ++ ixgbe_82598.o ixgbe_phy.o ixgbe_dcb.o ixgbe_dcb_82598.o \ ++ ixgbe_dcb_nl.o +--- /dev/null ++++ b/include/linux/dcbnl.h +@@ -0,0 +1,324 @@ ++#ifndef __LINUX_DCBNL_H__ ++#define __LINUX_DCBNL_H__ ++/* ++ * Data Center Bridging (DCB) netlink header ++ * ++ * Copyright 2008, Lucy Liu ++ */ ++ ++#define DCB_PROTO_VERSION 1 ++ ++struct dcbmsg { ++ unsigned char dcb_family; ++ __u8 cmd; ++ __u16 dcb_pad; ++}; ++ ++/** ++ * enum dcbnl_commands - supported DCB commands ++ * ++ * @DCB_CMD_UNDEFINED: unspecified command to catch errors ++ * @DCB_CMD_GSTATE: request the state of DCB in the device ++ * @DCB_CMD_SSTATE: set the state of DCB in the device ++ * @DCB_CMD_PGTX_GCFG: request the priority group configuration for Tx ++ * @DCB_CMD_PGTX_SCFG: set the priority group configuration for Tx ++ * @DCB_CMD_PGRX_GCFG: request the priority group configuration for Rx ++ * @DCB_CMD_PGRX_SCFG: set the priority group configuration for Rx ++ * @DCB_CMD_PFC_GCFG: request the priority flow control configuration ++ * @DCB_CMD_PFC_SCFG: set the priority flow control configuration ++ * @DCB_CMD_SET_ALL: apply all changes to the underlying device ++ * @DCB_CMD_GPERM_HWADDR: get the permanent MAC address of the underlying ++ * device. Only useful when using bonding. ++ * @DCB_CMD_GCAP: request the DCB capabilities of the device ++ * @DCB_CMD_GNUMTCS: get the number of traffic classes currently supported ++ * @DCB_CMD_SNUMTCS: set the number of traffic classes ++ * @DCB_CMD_GBCN: set backward congestion notification configuration ++ * @DCB_CMD_SBCN: get backward congestion notification configration. ++ */ ++enum dcbnl_commands { ++ DCB_CMD_UNDEFINED, ++ ++ DCB_CMD_GSTATE, ++ DCB_CMD_SSTATE, ++ ++ DCB_CMD_PGTX_GCFG, ++ DCB_CMD_PGTX_SCFG, ++ DCB_CMD_PGRX_GCFG, ++ DCB_CMD_PGRX_SCFG, ++ ++ DCB_CMD_PFC_GCFG, ++ DCB_CMD_PFC_SCFG, ++ ++ DCB_CMD_SET_ALL, ++ ++ DCB_CMD_GPERM_HWADDR, ++ ++ DCB_CMD_GCAP, ++ ++ DCB_CMD_GNUMTCS, ++ DCB_CMD_SNUMTCS, ++ ++ DCB_CMD_PFC_GSTATE, ++ DCB_CMD_PFC_SSTATE, ++ ++ DCB_CMD_BCN_GCFG, ++ DCB_CMD_BCN_SCFG, ++ ++ __DCB_CMD_ENUM_MAX, ++ DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcbnl_attrs - DCB top-level netlink attributes ++ * ++ * @DCB_ATTR_UNDEFINED: unspecified attribute to catch errors ++ * @DCB_ATTR_IFNAME: interface name of the underlying device (NLA_STRING) ++ * @DCB_ATTR_STATE: enable state of DCB in the device (NLA_U8) ++ * @DCB_ATTR_PFC_STATE: enable state of PFC in the device (NLA_U8) ++ * @DCB_ATTR_PFC_CFG: priority flow control configuration (NLA_NESTED) ++ * @DCB_ATTR_NUM_TC: number of traffic classes supported in the device (NLA_U8) ++ * @DCB_ATTR_PG_CFG: priority group configuration (NLA_NESTED) ++ * @DCB_ATTR_SET_ALL: bool to commit changes to hardware or not (NLA_U8) ++ * @DCB_ATTR_PERM_HWADDR: MAC address of the physical device (NLA_NESTED) ++ * @DCB_ATTR_CAP: DCB capabilities of the device (NLA_NESTED) ++ * @DCB_ATTR_NUMTCS: number of traffic classes supported (NLA_NESTED) ++ * @DCB_ATTR_BCN: backward congestion notification configuration (NLA_NESTED) ++ */ ++enum dcbnl_attrs { ++ DCB_ATTR_UNDEFINED, ++ ++ DCB_ATTR_IFNAME, ++ DCB_ATTR_STATE, ++ DCB_ATTR_PFC_STATE, ++ DCB_ATTR_PFC_CFG, ++ DCB_ATTR_NUM_TC, ++ DCB_ATTR_PG_CFG, ++ DCB_ATTR_SET_ALL, ++ DCB_ATTR_PERM_HWADDR, ++ DCB_ATTR_CAP, ++ DCB_ATTR_NUMTCS, ++ DCB_ATTR_BCN, ++ ++ __DCB_ATTR_ENUM_MAX, ++ DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcbnl_pfc_attrs - DCB Priority Flow Control user priority nested attrs ++ * ++ * @DCB_PFC_UP_ATTR_UNDEFINED: unspecified attribute to catch errors ++ * @DCB_PFC_UP_ATTR_0: Priority Flow Control value for User Priority 0 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_1: Priority Flow Control value for User Priority 1 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_2: Priority Flow Control value for User Priority 2 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_3: Priority Flow Control value for User Priority 3 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_4: Priority Flow Control value for User Priority 4 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_5: Priority Flow Control value for User Priority 5 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_6: Priority Flow Control value for User Priority 6 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_7: Priority Flow Control value for User Priority 7 (NLA_U8) ++ * @DCB_PFC_UP_ATTR_MAX: highest attribute number currently defined ++ * @DCB_PFC_UP_ATTR_ALL: apply to all priority flow control attrs (NLA_FLAG) ++ * ++ */ ++enum dcbnl_pfc_up_attrs { ++ DCB_PFC_UP_ATTR_UNDEFINED, ++ ++ DCB_PFC_UP_ATTR_0, ++ DCB_PFC_UP_ATTR_1, ++ DCB_PFC_UP_ATTR_2, ++ DCB_PFC_UP_ATTR_3, ++ DCB_PFC_UP_ATTR_4, ++ DCB_PFC_UP_ATTR_5, ++ DCB_PFC_UP_ATTR_6, ++ DCB_PFC_UP_ATTR_7, ++ DCB_PFC_UP_ATTR_ALL, ++ ++ __DCB_PFC_UP_ATTR_ENUM_MAX, ++ DCB_PFC_UP_ATTR_MAX = __DCB_PFC_UP_ATTR_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcbnl_pg_attrs - DCB Priority Group attributes ++ * ++ * @DCB_PG_ATTR_UNDEFINED: unspecified attribute to catch errors ++ * @DCB_PG_ATTR_TC_0: Priority Group Traffic Class 0 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_1: Priority Group Traffic Class 1 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_2: Priority Group Traffic Class 2 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_3: Priority Group Traffic Class 3 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_4: Priority Group Traffic Class 4 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_5: Priority Group Traffic Class 5 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_6: Priority Group Traffic Class 6 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_7: Priority Group Traffic Class 7 configuration (NLA_NESTED) ++ * @DCB_PG_ATTR_TC_MAX: highest attribute number currently defined ++ * @DCB_PG_ATTR_TC_ALL: apply to all traffic classes (NLA_NESTED) ++ * @DCB_PG_ATTR_BW_ID_0: Percent of link bandwidth for Priority Group 0 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_1: Percent of link bandwidth for Priority Group 1 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_2: Percent of link bandwidth for Priority Group 2 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_3: Percent of link bandwidth for Priority Group 3 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_4: Percent of link bandwidth for Priority Group 4 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_5: Percent of link bandwidth for Priority Group 5 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_6: Percent of link bandwidth for Priority Group 6 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_7: Percent of link bandwidth for Priority Group 7 (NLA_U8) ++ * @DCB_PG_ATTR_BW_ID_MAX: highest attribute number currently defined ++ * @DCB_PG_ATTR_BW_ID_ALL: apply to all priority groups (NLA_FLAG) ++ * ++ */ ++enum dcbnl_pg_attrs { ++ DCB_PG_ATTR_UNDEFINED, ++ ++ DCB_PG_ATTR_TC_0, ++ DCB_PG_ATTR_TC_1, ++ DCB_PG_ATTR_TC_2, ++ DCB_PG_ATTR_TC_3, ++ DCB_PG_ATTR_TC_4, ++ DCB_PG_ATTR_TC_5, ++ DCB_PG_ATTR_TC_6, ++ DCB_PG_ATTR_TC_7, ++ DCB_PG_ATTR_TC_MAX, ++ DCB_PG_ATTR_TC_ALL, ++ ++ DCB_PG_ATTR_BW_ID_0, ++ DCB_PG_ATTR_BW_ID_1, ++ DCB_PG_ATTR_BW_ID_2, ++ DCB_PG_ATTR_BW_ID_3, ++ DCB_PG_ATTR_BW_ID_4, ++ DCB_PG_ATTR_BW_ID_5, ++ DCB_PG_ATTR_BW_ID_6, ++ DCB_PG_ATTR_BW_ID_7, ++ DCB_PG_ATTR_BW_ID_MAX, ++ DCB_PG_ATTR_BW_ID_ALL, ++ ++ __DCB_PG_ATTR_ENUM_MAX, ++ DCB_PG_ATTR_MAX = __DCB_PG_ATTR_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcbnl_tc_attrs - DCB Traffic Class attributes ++ * ++ * @DCB_TC_ATTR_PARAM_UNDEFINED: unspecified attribute to catch errors ++ * @DCB_TC_ATTR_PARAM_PGID: (NLA_U8) Priority group the traffic class belongs to ++ * Valid values are: 0-7 ++ * @DCB_TC_ATTR_PARAM_UP_MAPPING: (NLA_U8) Traffic class to user priority map ++ * Some devices may not support changing the ++ * user priority map of a TC. ++ * @DCB_TC_ATTR_PARAM_STRICT_PRIO: (NLA_U8) Strict priority setting ++ * 0 - none ++ * 1 - group strict ++ * 2 - link strict ++ * @DCB_TC_ATTR_PARAM_BW_PCT: optional - (NLA_U8) If supported by the device and ++ * not configured to use link strict priority, ++ * this is the percentage of bandwidth of the ++ * priority group this traffic class belongs to ++ * @DCB_TC_ATTR_PARAM_ALL: (NLA_FLAG) all traffic class parameters ++ * ++ */ ++enum dcbnl_tc_attrs { ++ DCB_TC_ATTR_PARAM_UNDEFINED, ++ ++ DCB_TC_ATTR_PARAM_PGID, ++ DCB_TC_ATTR_PARAM_UP_MAPPING, ++ DCB_TC_ATTR_PARAM_STRICT_PRIO, ++ DCB_TC_ATTR_PARAM_BW_PCT, ++ DCB_TC_ATTR_PARAM_ALL, ++ ++ __DCB_TC_ATTR_PARAM_ENUM_MAX, ++ DCB_TC_ATTR_PARAM_MAX = __DCB_TC_ATTR_PARAM_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcbnl_cap_attrs - DCB Capability attributes ++ * ++ * @DCB_CAP_ATTR_UNDEFINED: unspecified attribute to catch errors ++ * @DCB_CAP_ATTR_ALL: (NLA_FLAG) all capability parameters ++ * @DCB_CAP_ATTR_PG: (NLA_U8) device supports Priority Groups ++ * @DCB_CAP_ATTR_PFC: (NLA_U8) device supports Priority Flow Control ++ * @DCB_CAP_ATTR_UP2TC: (NLA_U8) device supports user priority to ++ * traffic class mapping ++ * @DCB_CAP_ATTR_PG_TCS: (NLA_U8) bitmap where each bit represents a ++ * number of traffic classes the device ++ * can be configured to use for Priority Groups ++ * @DCB_CAP_ATTR_PFC_TCS: (NLA_U8) bitmap where each bit represents a ++ * number of traffic classes the device can be ++ * configured to use for Priority Flow Control ++ * @DCB_CAP_ATTR_GSP: (NLA_U8) device supports group strict priority ++ * @DCB_CAP_ATTR_BCN: (NLA_U8) device supports Backwards Congestion ++ * Notification ++ */ ++enum dcbnl_cap_attrs { ++ DCB_CAP_ATTR_UNDEFINED, ++ DCB_CAP_ATTR_ALL, ++ DCB_CAP_ATTR_PG, ++ DCB_CAP_ATTR_PFC, ++ DCB_CAP_ATTR_UP2TC, ++ DCB_CAP_ATTR_PG_TCS, ++ DCB_CAP_ATTR_PFC_TCS, ++ DCB_CAP_ATTR_GSP, ++ DCB_CAP_ATTR_BCN, ++ ++ __DCB_CAP_ATTR_ENUM_MAX, ++ DCB_CAP_ATTR_MAX = __DCB_CAP_ATTR_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcbnl_numtcs_attrs - number of traffic classes ++ * ++ * @DCB_NUMTCS_ATTR_UNDEFINED: unspecified attribute to catch errors ++ * @DCB_NUMTCS_ATTR_ALL: (NLA_FLAG) all traffic class attributes ++ * @DCB_NUMTCS_ATTR_PG: (NLA_U8) number of traffic classes used for ++ * priority groups ++ * @DCB_NUMTCS_ATTR_PFC: (NLA_U8) number of traffic classes which can ++ * support priority flow control ++ */ ++enum dcbnl_numtcs_attrs { ++ DCB_NUMTCS_ATTR_UNDEFINED, ++ DCB_NUMTCS_ATTR_ALL, ++ DCB_NUMTCS_ATTR_PG, ++ DCB_NUMTCS_ATTR_PFC, ++ ++ __DCB_NUMTCS_ATTR_ENUM_MAX, ++ DCB_NUMTCS_ATTR_MAX = __DCB_NUMTCS_ATTR_ENUM_MAX - 1, ++}; ++ ++enum dcbnl_bcn_attrs{ ++ DCB_BCN_ATTR_UNDEFINED = 0, ++ ++ DCB_BCN_ATTR_RP_0, ++ DCB_BCN_ATTR_RP_1, ++ DCB_BCN_ATTR_RP_2, ++ DCB_BCN_ATTR_RP_3, ++ DCB_BCN_ATTR_RP_4, ++ DCB_BCN_ATTR_RP_5, ++ DCB_BCN_ATTR_RP_6, ++ DCB_BCN_ATTR_RP_7, ++ DCB_BCN_ATTR_RP_ALL, ++ ++ DCB_BCN_ATTR_ALPHA, ++ DCB_BCN_ATTR_BETA, ++ DCB_BCN_ATTR_GD, ++ DCB_BCN_ATTR_GI, ++ DCB_BCN_ATTR_TMAX, ++ DCB_BCN_ATTR_TD, ++ DCB_BCN_ATTR_RMIN, ++ DCB_BCN_ATTR_W, ++ DCB_BCN_ATTR_RD, ++ DCB_BCN_ATTR_RU, ++ DCB_BCN_ATTR_WRTT, ++ DCB_BCN_ATTR_RI, ++ DCB_BCN_ATTR_C, ++ DCB_BCN_ATTR_ALL, ++ ++ __DCB_BCN_ATTR_ENUM_MAX, ++ DCB_BCN_ATTR_MAX = __DCB_BCN_ATTR_ENUM_MAX - 1, ++}; ++ ++/** ++ * enum dcb_general_attr_values - general DCB attribute values ++ * ++ * @DCB_ATTR_UNDEFINED: value used to indicate an attribute is not supported ++ * ++ */ ++enum dcb_general_attr_values { ++ DCB_ATTR_VALUE_UNDEFINED = 0xff ++}; ++ ++ ++#endif /* __LINUX_DCBNL_H__ */ +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -42,6 +42,9 @@ + #include + + #include ++#ifdef CONFIG_DCBNL ++#include ++#endif + + struct vlan_group; + struct ethtool_ops; +@@ -749,6 +752,11 @@ struct net_device + /* for setting kernel sock attribute on TCP connection setup */ + #define GSO_MAX_SIZE 65536 + unsigned int gso_max_size; ++ ++#ifdef CONFIG_DCBNL ++ /* Data Center Bridging netlink ops */ ++ struct dcbnl_rtnl_ops *dcbnl_ops; ++#endif + }; + #define to_net_dev(d) container_of(d, struct net_device, dev) + +--- a/include/linux/rtnetlink.h ++++ b/include/linux/rtnetlink.h +@@ -107,6 +107,11 @@ enum { + RTM_GETADDRLABEL, + #define RTM_GETADDRLABEL RTM_GETADDRLABEL + ++ RTM_GETDCB = 78, ++#define RTM_GETDCB RTM_GETDCB ++ RTM_SETDCB, ++#define RTM_SETDCB RTM_SETDCB ++ + __RTM_MAX, + #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) + }; +--- /dev/null ++++ b/include/net/dcbnl.h +@@ -0,0 +1,40 @@ ++#ifndef __NET_DCBNL_H__ ++#define __NET_DCBNL_H__ ++/* ++ * Data Center Bridging (DCB) netlink operations ++ * ++ * Copyright 2008, Lucy Liu ++ */ ++ ++ ++/* ++ * Ops struct for the netlink callbacks. Used by DCB-enabled drivers through ++ * the netdevice struct. ++ */ ++struct dcbnl_rtnl_ops { ++ u8 (*getstate)(struct net_device *); ++ void (*setstate)(struct net_device *, u8); ++ void (*getpermhwaddr)(struct net_device *, u8 *); ++ void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8); ++ void (*setpgbwgcfgtx)(struct net_device *, int, u8); ++ void (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8); ++ void (*setpgbwgcfgrx)(struct net_device *, int, u8); ++ void (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); ++ void (*getpgbwgcfgtx)(struct net_device *, int, u8 *); ++ void (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); ++ void (*getpgbwgcfgrx)(struct net_device *, int, u8 *); ++ void (*setpfccfg)(struct net_device *, int, u8); ++ void (*getpfccfg)(struct net_device *, int, u8 *); ++ u8 (*setall)(struct net_device *); ++ u8 (*getcap)(struct net_device *, int, u8 *); ++ u8 (*getnumtcs)(struct net_device *, int, u8 *); ++ u8 (*setnumtcs)(struct net_device *, int, u8); ++ u8 (*getpfcstate)(struct net_device *); ++ void (*setpfcstate)(struct net_device *, u8); ++ void (*getbcncfg)(struct net_device *, int, u32 *); ++ void (*setbcncfg)(struct net_device *, int, u32); ++ void (*getbcnrp)(struct net_device *, int, u8 *); ++ void (*setbcnrp)(struct net_device *, int, u8); ++}; ++ ++#endif /* __NET_DCBNL_H__ */ +--- /dev/null ++++ b/net/dcb/dcbnl.c +@@ -0,0 +1,1091 @@ ++/* ++ * This is the Data Center Bridging configuration interface. ++ * ++ * Copyright 2008, Lucy Liu ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Lucy Liu, "); ++MODULE_DESCRIPTION("Data Center Bridging generic netlink interface"); ++MODULE_LICENSE("GPL"); ++ ++/**************** DCB attribute policies *************************************/ ++ ++/* DCB netlink attributes policy */ ++static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { ++ [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, ++ [DCB_ATTR_STATE] = {.type = NLA_U8}, ++ [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, ++ [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, ++ [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, ++ [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, ++ [DCB_ATTR_CAP] = {.type = NLA_NESTED}, ++ [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, ++ [DCB_ATTR_BCN] = {.type = NLA_NESTED}, ++}; ++ ++/* DCB priority flow control to User Priority nested attributes */ ++static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { ++ [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, ++ [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, ++}; ++ ++/* DCB priority grouping nested attributes */ ++static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { ++ [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, ++ [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, ++ [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, ++}; ++ ++/* DCB traffic class nested attributes. */ ++static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { ++ [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, ++ [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, ++ [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, ++ [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, ++ [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, ++}; ++ ++/* DCB capabilities nested attributes. */ ++static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { ++ [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, ++ [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, ++ [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, ++ [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, ++ [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, ++ [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, ++ [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, ++ [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, ++}; ++ ++/* DCB capabilities nested attributes. */ ++static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { ++ [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, ++ [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, ++ [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, ++}; ++ ++/* DCB BCN nested attributes. */ ++static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { ++ [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, ++ [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, ++ [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_W] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_C] = {.type = NLA_U32}, ++ [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, ++}; ++ ++/* standard netlink reply call */ ++static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, ++ u32 seq, u16 flags) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct dcbmsg *dcb; ++ struct nlmsghdr *nlh; ++ int ret = -EINVAL; ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) ++ return ret; ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = cmd; ++ dcb->dcb_pad = 0; ++ ++ ret = nla_put_u8(dcbnl_skb, attr, value); ++ if (ret) ++ goto err; ++ ++ /* end the message, assign the nlmsg_len. */ ++ nlmsg_end(dcbnl_skb, nlh); ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) ++ goto err; ++ ++ return 0; ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++ return ret; ++} ++ ++static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ int ret = -EINVAL; ++ ++ /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ ++ if (!netdev->dcbnl_ops->getstate) ++ return ret; ++ ++ ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, ++ DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); ++ ++ return ret; ++} ++ ++static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct nlmsghdr *nlh; ++ struct dcbmsg *dcb; ++ struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; ++ u8 value; ++ int ret = -EINVAL; ++ int i; ++ int getall = 0; ++ ++ if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) ++ return ret; ++ ++ ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, ++ tb[DCB_ATTR_PFC_CFG], ++ dcbnl_pfc_up_nest); ++ if (ret) ++ goto err_out; ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) ++ goto err_out; ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = DCB_CMD_PFC_GCFG; ++ ++ nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); ++ if (!nest) ++ goto err; ++ ++ if (data[DCB_PFC_UP_ATTR_ALL]) ++ getall = 1; ++ ++ for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { ++ if (!getall && !data[i]) ++ continue; ++ ++ netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, ++ &value); ++ ret = nla_put_u8(dcbnl_skb, i, value); ++ ++ if (ret) { ++ nla_nest_cancel(dcbnl_skb, nest); ++ goto err; ++ } ++ } ++ nla_nest_end(dcbnl_skb, nest); ++ ++ nlmsg_end(dcbnl_skb, nlh); ++ ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) ++ goto err; ++ ++ return 0; ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++err_out: ++ return -EINVAL; ++} ++ ++static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct nlmsghdr *nlh; ++ struct dcbmsg *dcb; ++ u8 perm_addr[MAX_ADDR_LEN]; ++ int ret = -EINVAL; ++ ++ if (!netdev->dcbnl_ops->getpermhwaddr) ++ return ret; ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) ++ goto err_out; ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = DCB_CMD_GPERM_HWADDR; ++ ++ netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); ++ ++ ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), ++ perm_addr); ++ ++ nlmsg_end(dcbnl_skb, nlh); ++ ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) ++ goto err; ++ ++ return 0; ++ ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++err_out: ++ return -EINVAL; ++} ++ ++static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct nlmsghdr *nlh; ++ struct dcbmsg *dcb; ++ struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; ++ u8 value; ++ int ret = -EINVAL; ++ int i; ++ int getall = 0; ++ ++ if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) ++ return ret; ++ ++ ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], ++ dcbnl_cap_nest); ++ if (ret) ++ goto err_out; ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) ++ goto err_out; ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = DCB_CMD_GCAP; ++ ++ nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); ++ if (!nest) ++ goto err; ++ ++ if (data[DCB_CAP_ATTR_ALL]) ++ getall = 1; ++ ++ for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { ++ if (!getall && !data[i]) ++ continue; ++ ++ if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { ++ ret = nla_put_u8(dcbnl_skb, i, value); ++ ++ if (ret) { ++ nla_nest_cancel(dcbnl_skb, nest); ++ goto err; ++ } ++ } ++ } ++ nla_nest_end(dcbnl_skb, nest); ++ ++ nlmsg_end(dcbnl_skb, nlh); ++ ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) ++ goto err; ++ ++ return 0; ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++err_out: ++ return -EINVAL; ++} ++ ++static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct nlmsghdr *nlh; ++ struct dcbmsg *dcb; ++ struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; ++ u8 value; ++ int ret = -EINVAL; ++ int i; ++ int getall = 0; ++ ++ if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) ++ return ret; ++ ++ ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], ++ dcbnl_numtcs_nest); ++ if (ret) { ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) { ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = DCB_CMD_GNUMTCS; ++ ++ nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); ++ if (!nest) { ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ if (data[DCB_NUMTCS_ATTR_ALL]) ++ getall = 1; ++ ++ for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { ++ if (!getall && !data[i]) ++ continue; ++ ++ ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); ++ if (!ret) { ++ ret = nla_put_u8(dcbnl_skb, i, value); ++ ++ if (ret) { ++ nla_nest_cancel(dcbnl_skb, nest); ++ ret = -EINVAL; ++ goto err; ++ } ++ } else { ++ goto err; ++ } ++ } ++ nla_nest_end(dcbnl_skb, nest); ++ ++ nlmsg_end(dcbnl_skb, nlh); ++ ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) { ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ return 0; ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++err_out: ++ return ret; ++} ++ ++static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; ++ int ret = -EINVAL; ++ u8 value; ++ u8 status; ++ int i; ++ ++ if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setstate) ++ return ret; ++ ++ ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], ++ dcbnl_numtcs_nest); ++ ++ if (ret) { ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { ++ if (data[i] == NULL) ++ continue; ++ ++ value = nla_get_u8(data[i]); ++ ++ ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); ++ ++ if (ret) ++ goto err; ++ } ++ ++ value = nla_get_u8(tb[DCB_ATTR_STATE]); ++ ++ status = netdev->dcbnl_ops->setnumtcs(netdev, i, value); ++ ++ ret = dcbnl_reply(!!status, RTM_SETDCB, DCB_CMD_SNUMTCS, ++ DCB_ATTR_NUMTCS, pid, seq, flags); ++ ++err: ++ return ret; ++} ++ ++static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ int ret = -EINVAL; ++ ++ if (!netdev->dcbnl_ops->getpfcstate) ++ return ret; ++ ++ ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, ++ DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, ++ pid, seq, flags); ++ ++ return ret; ++} ++ ++static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ int ret = -EINVAL; ++ u8 value; ++ ++ if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) ++ return ret; ++ ++ value = nla_get_u8(tb[DCB_ATTR_STATE]); ++ ++ netdev->dcbnl_ops->setstate(netdev, value); ++ ++ ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, ++ pid, seq, flags); ++ ++ return ret; ++} ++ ++static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags, int dir) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct nlmsghdr *nlh; ++ struct dcbmsg *dcb; ++ struct nlattr *pg_nest, *param_nest, *data; ++ struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; ++ struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; ++ u8 prio, pgid, tc_pct, up_map; ++ int ret = -EINVAL; ++ int getall = 0; ++ int i; ++ ++ if (!tb[DCB_ATTR_PG_CFG] || ++ !netdev->dcbnl_ops->getpgtccfgtx || ++ !netdev->dcbnl_ops->getpgtccfgrx || ++ !netdev->dcbnl_ops->getpgbwgcfgtx || ++ !netdev->dcbnl_ops->getpgbwgcfgrx) ++ return ret; ++ ++ ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, ++ tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); ++ ++ if (ret) ++ goto err_out; ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) ++ goto err_out; ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; ++ ++ pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); ++ if (!pg_nest) ++ goto err; ++ ++ if (pg_tb[DCB_PG_ATTR_TC_ALL]) ++ getall = 1; ++ ++ for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { ++ if (!getall && !pg_tb[i]) ++ continue; ++ ++ if (pg_tb[DCB_PG_ATTR_TC_ALL]) ++ data = pg_tb[DCB_PG_ATTR_TC_ALL]; ++ else ++ data = pg_tb[i]; ++ ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, ++ data, dcbnl_tc_param_nest); ++ if (ret) ++ goto err_pg; ++ ++ param_nest = nla_nest_start(dcbnl_skb, i); ++ if (!param_nest) ++ goto err_pg; ++ ++ pgid = DCB_ATTR_VALUE_UNDEFINED; ++ prio = DCB_ATTR_VALUE_UNDEFINED; ++ tc_pct = DCB_ATTR_VALUE_UNDEFINED; ++ up_map = DCB_ATTR_VALUE_UNDEFINED; ++ ++ if (dir) { ++ /* Rx */ ++ netdev->dcbnl_ops->getpgtccfgrx(netdev, ++ i - DCB_PG_ATTR_TC_0, &prio, ++ &pgid, &tc_pct, &up_map); ++ } else { ++ /* Tx */ ++ netdev->dcbnl_ops->getpgtccfgtx(netdev, ++ i - DCB_PG_ATTR_TC_0, &prio, ++ &pgid, &tc_pct, &up_map); ++ } ++ ++ if (param_tb[DCB_TC_ATTR_PARAM_PGID] || ++ param_tb[DCB_TC_ATTR_PARAM_ALL]) { ++ ret = nla_put_u8(dcbnl_skb, ++ DCB_TC_ATTR_PARAM_PGID, pgid); ++ if (ret) ++ goto err_param; ++ } ++ if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || ++ param_tb[DCB_TC_ATTR_PARAM_ALL]) { ++ ret = nla_put_u8(dcbnl_skb, ++ DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); ++ if (ret) ++ goto err_param; ++ } ++ if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || ++ param_tb[DCB_TC_ATTR_PARAM_ALL]) { ++ ret = nla_put_u8(dcbnl_skb, ++ DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); ++ if (ret) ++ goto err_param; ++ } ++ if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || ++ param_tb[DCB_TC_ATTR_PARAM_ALL]) { ++ ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, ++ tc_pct); ++ if (ret) ++ goto err_param; ++ } ++ nla_nest_end(dcbnl_skb, param_nest); ++ } ++ ++ if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) ++ getall = 1; ++ else ++ getall = 0; ++ ++ for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { ++ if (!getall && !pg_tb[i]) ++ continue; ++ ++ tc_pct = DCB_ATTR_VALUE_UNDEFINED; ++ ++ if (dir) { ++ /* Rx */ ++ netdev->dcbnl_ops->getpgbwgcfgrx(netdev, ++ i - DCB_PG_ATTR_BW_ID_0, &tc_pct); ++ } else { ++ /* Tx */ ++ netdev->dcbnl_ops->getpgbwgcfgtx(netdev, ++ i - DCB_PG_ATTR_BW_ID_0, &tc_pct); ++ } ++ ret = nla_put_u8(dcbnl_skb, i, tc_pct); ++ ++ if (ret) ++ goto err_pg; ++ } ++ ++ nla_nest_end(dcbnl_skb, pg_nest); ++ ++ nlmsg_end(dcbnl_skb, nlh); ++ ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) ++ goto err; ++ ++ return 0; ++ ++err_param: ++ nla_nest_cancel(dcbnl_skb, param_nest); ++err_pg: ++ nla_nest_cancel(dcbnl_skb, pg_nest); ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++err_out: ++ ret = -EINVAL; ++ return ret; ++} ++ ++static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); ++} ++ ++static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); ++} ++ ++static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ int ret = -EINVAL; ++ u8 value; ++ ++ if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) ++ return ret; ++ ++ value = nla_get_u8(tb[DCB_ATTR_STATE]); ++ ++ netdev->dcbnl_ops->setstate(netdev, value); ++ ++ ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, ++ pid, seq, flags); ++ ++ return ret; ++} ++ ++static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; ++ int i; ++ int ret = -EINVAL; ++ u8 value; ++ ++ if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) ++ return ret; ++ ++ ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, ++ tb[DCB_ATTR_PFC_CFG], ++ dcbnl_pfc_up_nest); ++ if (ret) ++ goto err; ++ ++ for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { ++ if (data[i] == NULL) ++ continue; ++ value = nla_get_u8(data[i]); ++ netdev->dcbnl_ops->setpfccfg(netdev, ++ data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); ++ } ++ ++ ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, ++ pid, seq, flags); ++err: ++ return ret; ++} ++ ++static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ int ret = -EINVAL; ++ ++ if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) ++ return ret; ++ ++ ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, ++ DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); ++ ++ return ret; ++} ++ ++static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags, int dir) ++{ ++ struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; ++ struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; ++ int ret = -EINVAL; ++ int i; ++ u8 pgid; ++ u8 up_map; ++ u8 prio; ++ u8 tc_pct; ++ ++ if (!tb[DCB_ATTR_PG_CFG] || ++ !netdev->dcbnl_ops->setpgtccfgtx || ++ !netdev->dcbnl_ops->setpgtccfgrx || ++ !netdev->dcbnl_ops->setpgbwgcfgtx || ++ !netdev->dcbnl_ops->setpgbwgcfgrx) ++ return ret; ++ ++ ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, ++ tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); ++ if (ret) ++ goto err; ++ ++ for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { ++ if (!pg_tb[i]) ++ continue; ++ ++ ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, ++ pg_tb[i], dcbnl_tc_param_nest); ++ if (ret) ++ goto err; ++ ++ pgid = DCB_ATTR_VALUE_UNDEFINED; ++ prio = DCB_ATTR_VALUE_UNDEFINED; ++ tc_pct = DCB_ATTR_VALUE_UNDEFINED; ++ up_map = DCB_ATTR_VALUE_UNDEFINED; ++ ++ if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) ++ prio = ++ nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); ++ ++ if (param_tb[DCB_TC_ATTR_PARAM_PGID]) ++ pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); ++ ++ if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) ++ tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); ++ ++ if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) ++ up_map = ++ nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); ++ ++ /* dir: Tx = 0, Rx = 1 */ ++ if (dir) { ++ /* Rx */ ++ netdev->dcbnl_ops->setpgtccfgrx(netdev, ++ i - DCB_PG_ATTR_TC_0, ++ prio, pgid, tc_pct, up_map); ++ } else { ++ /* Tx */ ++ netdev->dcbnl_ops->setpgtccfgtx(netdev, ++ i - DCB_PG_ATTR_TC_0, ++ prio, pgid, tc_pct, up_map); ++ } ++ } ++ ++ for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { ++ if (!pg_tb[i]) ++ continue; ++ ++ tc_pct = nla_get_u8(pg_tb[i]); ++ ++ /* dir: Tx = 0, Rx = 1 */ ++ if (dir) { ++ /* Rx */ ++ netdev->dcbnl_ops->setpgbwgcfgrx(netdev, ++ i - DCB_PG_ATTR_BW_ID_0, tc_pct); ++ } else { ++ /* Tx */ ++ netdev->dcbnl_ops->setpgbwgcfgtx(netdev, ++ i - DCB_PG_ATTR_BW_ID_0, tc_pct); ++ } ++ } ++ ++ ret = dcbnl_reply(0, RTM_SETDCB, ++ (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), ++ DCB_ATTR_PG_CFG, pid, seq, flags); ++ ++err: ++ return ret; ++} ++ ++static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); ++} ++ ++static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); ++} ++ ++static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct sk_buff *dcbnl_skb; ++ struct nlmsghdr *nlh; ++ struct dcbmsg *dcb; ++ struct nlattr *bcn_nest; ++ struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; ++ u8 value_byte; ++ u32 value_integer; ++ int ret = -EINVAL; ++ bool getall = false; ++ int i; ++ ++ if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || ++ !netdev->dcbnl_ops->getbcncfg) ++ return ret; ++ ++ ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, ++ tb[DCB_ATTR_BCN], dcbnl_bcn_nest); ++ ++ if (ret) ++ goto err_out; ++ ++ dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!dcbnl_skb) ++ goto err_out; ++ ++ nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); ++ ++ dcb = NLMSG_DATA(nlh); ++ dcb->dcb_family = AF_UNSPEC; ++ dcb->cmd = DCB_CMD_BCN_GCFG; ++ ++ bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); ++ if (!bcn_nest) ++ goto err; ++ ++ if (bcn_tb[DCB_BCN_ATTR_ALL]) ++ getall = true; ++ ++ for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { ++ if (!getall && !bcn_tb[i]) ++ continue; ++ ++ netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, ++ &value_byte); ++ ret = nla_put_u8(dcbnl_skb, i, value_byte); ++ if (ret) ++ goto err_bcn; ++ } ++ ++ for (i = DCB_BCN_ATTR_ALPHA; i <= DCB_BCN_ATTR_RI; i++) { ++ if (!getall && !bcn_tb[i]) ++ continue; ++ ++ netdev->dcbnl_ops->getbcncfg(netdev, i, ++ &value_integer); ++ ret = nla_put_u32(dcbnl_skb, i, value_integer); ++ if (ret) ++ goto err_bcn; ++ } ++ ++ nla_nest_end(dcbnl_skb, bcn_nest); ++ ++ nlmsg_end(dcbnl_skb, nlh); ++ ++ ret = rtnl_unicast(dcbnl_skb, &init_net, pid); ++ if (ret) ++ goto err; ++ ++ return 0; ++ ++err_bcn: ++ nla_nest_cancel(dcbnl_skb, bcn_nest); ++nlmsg_failure: ++err: ++ kfree(dcbnl_skb); ++err_out: ++ ret = -EINVAL; ++ return ret; ++} ++ ++static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, ++ u32 pid, u32 seq, u16 flags) ++{ ++ struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; ++ int i; ++ int ret = -EINVAL; ++ u8 value_byte; ++ u32 value_int; ++ ++ if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg ++ || !netdev->dcbnl_ops->setbcnrp) ++ return ret; ++ ++ ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, ++ tb[DCB_ATTR_BCN], ++ dcbnl_pfc_up_nest); ++ if (ret) ++ goto err; ++ ++ for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { ++ if (data[i] == NULL) ++ continue; ++ value_byte = nla_get_u8(data[i]); ++ netdev->dcbnl_ops->setbcnrp(netdev, ++ data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); ++ } ++ ++ for (i = DCB_BCN_ATTR_ALPHA; i <= DCB_BCN_ATTR_RI; i++) { ++ if (data[i] == NULL) ++ continue; ++ value_int = nla_get_u32(data[i]); ++ netdev->dcbnl_ops->setbcncfg(netdev, ++ i, value_int); ++ } ++ ++ ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, ++ pid, seq, flags); ++err: ++ return ret; ++} ++ ++static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ++{ ++ struct net *net = sock_net(skb->sk); ++ struct net_device *netdev; ++ struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); ++ struct nlattr *tb[DCB_ATTR_MAX + 1]; ++ u32 pid = skb ? NETLINK_CB(skb).pid : 0; ++ int ret = -EINVAL; ++ ++ if (net != &init_net) ++ return -EINVAL; ++ ++ ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, ++ dcbnl_rtnl_policy); ++ if (ret < 0) ++ return ret; ++ ++ if (!tb[DCB_ATTR_IFNAME]) ++ return -EINVAL; ++ ++ netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); ++ if (!netdev) ++ return -EINVAL; ++ ++ if (!netdev->dcbnl_ops) ++ goto errout; ++ ++ switch (dcb->cmd) { ++ case DCB_CMD_GSTATE: ++ ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PFC_GCFG: ++ ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_GPERM_HWADDR: ++ ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PGTX_GCFG: ++ ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PGRX_GCFG: ++ ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_BCN_GCFG: ++ ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_SSTATE: ++ ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PFC_SCFG: ++ ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ ++ case DCB_CMD_SET_ALL: ++ ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PGTX_SCFG: ++ ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PGRX_SCFG: ++ ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_GCAP: ++ ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_GNUMTCS: ++ ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_SNUMTCS: ++ ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PFC_GSTATE: ++ ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_PFC_SSTATE: ++ ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ case DCB_CMD_BCN_SCFG: ++ ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, ++ nlh->nlmsg_flags); ++ goto out; ++ default: ++ goto errout; ++ } ++errout: ++ ret = -EINVAL; ++out: ++ dev_put(netdev); ++ return ret; ++} ++ ++static int __init dcbnl_init(void) ++{ ++ rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); ++ rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); ++ ++ return 0; ++} ++module_init(dcbnl_init); ++ ++static void __exit dcbnl_exit(void) ++{ ++ rtnl_unregister(PF_UNSPEC, RTM_GETDCB); ++ rtnl_unregister(PF_UNSPEC, RTM_SETDCB); ++} ++module_exit(dcbnl_exit); ++ ++ +--- /dev/null ++++ b/net/dcb/Kconfig +@@ -0,0 +1,12 @@ ++config DCB ++ tristate "Data Center Bridging support" ++ ++config DCBNL ++ bool "Data Center Bridging netlink interface support" ++ depends on DCB ++ default n ++ ---help--- ++ This option turns on the netlink interface ++ (dcbnl) for Data Center Bridging capable devices. ++ ++ If unsure, say N. +--- /dev/null ++++ b/net/dcb/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_DCB) += dcbnl.o +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -190,6 +190,7 @@ source "net/lapb/Kconfig" + source "net/econet/Kconfig" + source "net/wanrouter/Kconfig" + source "net/sched/Kconfig" ++source "net/dcb/Kconfig" + + menu "Network testing" + +--- a/net/Makefile ++++ b/net/Makefile +@@ -55,6 +55,9 @@ obj-$(CONFIG_NETLABEL) += netlabel/ + obj-$(CONFIG_IUCV) += iucv/ + obj-$(CONFIG_RFKILL) += rfkill/ + obj-$(CONFIG_NET_9P) += 9p/ ++ifeq ($(CONFIG_DCBNL),y) ++obj-$(CONFIG_DCB) += dcb/ ++endif + + ifeq ($(CONFIG_NET),y) + obj-$(CONFIG_SYSCTL) += sysctl_net.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-driver b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-driver new file mode 100644 index 000000000..7a7a29cf0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-driver @@ -0,0 +1,1769 @@ +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:25:23 +0200 +Subject: fcoe: Fibre Channel over Ethernet driver +References: FATE#303913 + +Encapsulation protocol for running Fibre Channel over Ethernet interfaces. +Creates virtual Fibre Channel host adapters using libfc. + +Signed-off-by: Robert Love +Signed-off-by: Chris Leech +Signed-off-by: Vasu Dev +Signed-off-by: Yi Zou +Signed-off-by: Steve Ma +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/Kconfig | 6 + + drivers/scsi/Makefile | 1 + + drivers/scsi/fcoe/Makefile | 8 + + drivers/scsi/fcoe/fcoe_def.h | 100 +++++++ + drivers/scsi/fcoe/fcoe_dev.c | 633 ++++++++++++++++++++++++++++++++++++++++++ + drivers/scsi/fcoe/fcoe_if.c | 497 +++++++++++++++++++++++++++++++++ + drivers/scsi/fcoe/fcoeinit.c | 440 +++++++++++++++++++++++++++++ + 7 files changed, 1685 insertions(+), 0 deletions(-) + create mode 100644 drivers/scsi/fcoe/Makefile + create mode 100644 drivers/scsi/fcoe/fcoe_def.h + create mode 100644 drivers/scsi/fcoe/fcoe_dev.c + create mode 100644 drivers/scsi/fcoe/fcoe_if.c + create mode 100644 drivers/scsi/fcoe/fcoeinit.c + +diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig +index bd480d2..f382eea 100644 +--- a/drivers/scsi/Kconfig ++++ b/drivers/scsi/Kconfig +@@ -334,6 +334,12 @@ config LIBFC + ---help--- + Fibre Channel library module + ++config FCOE ++ tristate "FCoE module" ++ depends on LIBFC ++ ---help--- ++ Fibre Channel over Ethernet module ++ + config ISCSI_TCP + tristate "iSCSI Initiator over TCP/IP" + depends on SCSI && INET +diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile +index 9158dc6..22c01e5 100644 +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o + obj-$(CONFIG_SCSI_DH) += device_handler/ + + obj-$(CONFIG_LIBFC) += libfc/ ++obj-$(CONFIG_FCOE) += fcoe/ + obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o + obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o + obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o +diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile +new file mode 100644 +index 0000000..342e2ad +--- /dev/null ++++ b/drivers/scsi/fcoe/Makefile +@@ -0,0 +1,8 @@ ++# $Id: Makefile ++ ++obj-$(CONFIG_FCOE) += fcoe.o ++ ++fcoe-y := \ ++ fcoe_dev.o \ ++ fcoe_if.o \ ++ fcoeinit.o +diff --git a/drivers/scsi/fcoe/fcoe_def.h b/drivers/scsi/fcoe/fcoe_def.h +new file mode 100644 +index 0000000..12bf69c +--- /dev/null ++++ b/drivers/scsi/fcoe/fcoe_def.h +@@ -0,0 +1,100 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FCOE_DEF_H_ ++#define _FCOE_DEF_H_ ++ ++#include ++#include ++ ++#include ++ ++#include ++ ++#define FCOE_DRIVER_NAME "fcoe" /* driver name for ioctls */ ++#define FCOE_DRIVER_VENDOR "Open-FC.org" /* vendor name for ioctls */ ++ ++#define FCOE_MIN_FRAME 36 ++#define FCOE_WORD_TO_BYTE 4 ++ ++/* ++ * this is the main common structure across all instance of fcoe driver. ++ * There is one to one mapping between hba struct and ethernet nic. ++ * list of hbas contains pointer to the hba struct, these structures are ++ * stored in this array using there corresponding if_index. ++ */ ++ ++struct fcoe_percpu_s { ++ int cpu; ++ struct task_struct *thread; ++ struct sk_buff_head fcoe_rx_list; ++ struct page *crc_eof_page; ++ int crc_eof_offset; ++}; ++ ++struct fcoe_info { ++ struct timer_list timer; ++ /* ++ * fcoe host list is protected by the following read/write lock ++ */ ++ rwlock_t fcoe_hostlist_lock; ++ struct list_head fcoe_hostlist; ++ ++ struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; ++}; ++ ++struct fcoe_softc { ++ struct list_head list; ++ struct fc_lport *lp; ++ struct net_device *real_dev; ++ struct net_device *phys_dev; /* device with ethtool_ops */ ++ struct packet_type fcoe_packet_type; ++ struct sk_buff_head fcoe_pending_queue; ++ u16 user_mfs; /* configured max frame size */ ++ ++ u8 dest_addr[ETH_ALEN]; ++ u8 ctl_src_addr[ETH_ALEN]; ++ u8 data_src_addr[ETH_ALEN]; ++ /* ++ * fcoe protocol address learning related stuff ++ */ ++ u16 flogi_oxid; ++ u8 flogi_progress; ++ u8 address_mode; ++}; ++ ++extern int debug_fcoe; ++extern struct fcoe_percpu_s *fcoe_percpu[]; ++extern struct scsi_transport_template *fcoe_transport_template; ++int fcoe_percpu_receive_thread(void *arg); ++ ++/* ++ * HBA transport ops prototypes ++ */ ++extern struct fcoe_info fcoei; ++ ++void fcoe_clean_pending_queue(struct fc_lport *fd); ++void fcoe_watchdog(ulong vp); ++int fcoe_destroy_interface(const char *ifname); ++int fcoe_create_interface(const char *ifname); ++int fcoe_xmit(struct fc_lport *, struct fc_frame *); ++int fcoe_rcv(struct sk_buff *, struct net_device *, ++ struct packet_type *, struct net_device *); ++int fcoe_link_ok(struct fc_lport *); ++#endif /* _FCOE_DEF_H_ */ +diff --git a/drivers/scsi/fcoe/fcoe_dev.c b/drivers/scsi/fcoe/fcoe_dev.c +new file mode 100644 +index 0000000..d5a354f +--- /dev/null ++++ b/drivers/scsi/fcoe/fcoe_dev.c +@@ -0,0 +1,633 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * FCOE protocol file ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#include ++#include "fcoe_def.h" ++ ++#define FCOE_MAX_QUEUE_DEPTH 256 ++ ++/* destination address mode */ ++#define FCOE_GW_ADDR_MODE 0x00 ++#define FCOE_FCOUI_ADDR_MODE 0x01 ++ ++/* Function Prototyes */ ++static int fcoe_check_wait_queue(struct fc_lport *); ++static void fcoe_insert_wait_queue_head(struct fc_lport *, struct sk_buff *); ++static void fcoe_insert_wait_queue(struct fc_lport *, struct sk_buff *); ++static void fcoe_recv_flogi(struct fcoe_softc *, struct fc_frame *, u8 *); ++ ++/* ++ * this is the fcoe receive function ++ * called by NET_RX_SOFTIRQ ++ * this function will receive the packet and ++ * build fc frame and pass it up ++ */ ++int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, ++ struct packet_type *ptype, struct net_device *olddev) ++{ ++ struct fc_lport *lp; ++ struct fcoe_rcv_info *fr; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *stats; ++ u8 *data; ++ struct fc_frame_header *fh; ++ unsigned short oxid; ++ int cpu_idx; ++ struct fcoe_percpu_s *fps; ++ struct fcoe_info *fci = &fcoei; ++ ++ fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); ++ lp = fc->lp; ++ if (unlikely(lp == NULL)) { ++ FC_DBG("cannot find hba structure"); ++ goto err2; ++ } ++ ++ if (unlikely(debug_fcoe)) { ++ FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p tail:%p " ++ "end:%p sum:%d dev:%s", skb->len, skb->data_len, ++ skb->head, skb->data, skb_tail_pointer(skb), ++ skb_end_pointer(skb), skb->csum, ++ skb->dev ? skb->dev->name : ""); ++ ++ } ++ ++ /* check for FCOE packet type */ ++ if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { ++ FC_DBG("wrong FC type frame"); ++ goto err; ++ } ++ data = skb->data; ++ data += sizeof(struct fcoe_hdr); ++ fh = (struct fc_frame_header *)data; ++ oxid = ntohs(fh->fh_ox_id); ++ ++ fr = fcoe_dev_from_skb(skb); ++ fr->fr_dev = lp; ++ fr->ptype = ptype; ++ cpu_idx = 0; ++#ifdef CONFIG_SMP ++ /* ++ * The exchange ID are ANDed with num of online CPUs, ++ * so that will have the least lock contention in ++ * handling the exchange. if there is no thread ++ * for a given idx then use first online cpu. ++ */ ++ cpu_idx = oxid & (num_online_cpus() >> 1); ++ if (fci->fcoe_percpu[cpu_idx] == NULL) ++ cpu_idx = first_cpu(cpu_online_map); ++#endif ++ fps = fci->fcoe_percpu[cpu_idx]; ++ ++ spin_lock_bh(&fps->fcoe_rx_list.lock); ++ __skb_queue_tail(&fps->fcoe_rx_list, skb); ++ if (fps->fcoe_rx_list.qlen == 1) ++ wake_up_process(fps->thread); ++ ++ spin_unlock_bh(&fps->fcoe_rx_list.lock); ++ ++ return 0; ++err: ++#ifdef CONFIG_SMP ++ stats = lp->dev_stats[smp_processor_id()]; ++#else ++ stats = lp->dev_stats[0]; ++#endif ++ stats->ErrorFrames++; ++ ++err2: ++ kfree_skb(skb); ++ return -1; ++} ++ ++static inline int fcoe_start_io(struct sk_buff *skb) ++{ ++ int rc; ++ ++ skb_get(skb); ++ rc = dev_queue_xmit(skb); ++ if (rc != 0) ++ return rc; ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen) ++{ ++ struct fcoe_info *fci = &fcoei; ++ struct fcoe_percpu_s *fps; ++ struct page *page; ++ int cpu_idx; ++ ++ cpu_idx = get_cpu(); ++ fps = fci->fcoe_percpu[cpu_idx]; ++ page = fps->crc_eof_page; ++ if (!page) { ++ page = alloc_page(GFP_ATOMIC); ++ if (!page) { ++ put_cpu(); ++ return -ENOMEM; ++ } ++ fps->crc_eof_page = page; ++ WARN_ON(fps->crc_eof_offset != 0); ++ } ++ ++ get_page(page); ++ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, ++ fps->crc_eof_offset, tlen); ++ skb->len += tlen; ++ skb->data_len += tlen; ++ skb->truesize += tlen; ++ fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); ++ ++ if (fps->crc_eof_offset >= PAGE_SIZE) { ++ fps->crc_eof_page = NULL; ++ fps->crc_eof_offset = 0; ++ put_page(page); ++ } ++ put_cpu(); ++ return 0; ++} ++ ++/* ++ * this is the frame xmit routine ++ */ ++int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ int indx; ++ int wlen, rc = 0; ++ u32 crc; ++ struct ethhdr *eh; ++ struct fcoe_crc_eof *cp; ++ struct sk_buff *skb; ++ struct fcoe_dev_stats *stats; ++ struct fc_frame_header *fh; ++ unsigned int hlen; /* header length implies the version */ ++ unsigned int tlen; /* trailer length */ ++ int flogi_in_progress = 0; ++ struct fcoe_softc *fc; ++ void *data; ++ u8 sof, eof; ++ struct fcoe_hdr *hp; ++ ++ WARN_ON((fr_len(fp) % sizeof(u32)) != 0); ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ /* ++ * if it is a flogi then we need to learn gw-addr ++ * and my own fcid ++ */ ++ fh = fc_frame_header_get(fp); ++ if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { ++ if (fc_frame_payload_op(fp) == ELS_FLOGI) { ++ fc->flogi_oxid = ntohs(fh->fh_ox_id); ++ fc->address_mode = FCOE_FCOUI_ADDR_MODE; ++ fc->flogi_progress = 1; ++ flogi_in_progress = 1; ++ } else if (fc->flogi_progress && ntoh24(fh->fh_s_id) != 0) { ++ /* ++ * Here we must've gotten an SID by accepting an FLOGI ++ * from a point-to-point connection. Switch to using ++ * the source mac based on the SID. The destination ++ * MAC in this case would have been set by receving the ++ * FLOGI. ++ */ ++ fc_fcoe_set_mac(fc->data_src_addr, fh->fh_s_id); ++ fc->flogi_progress = 0; ++ } ++ } ++ ++ skb = fp_skb(fp); ++ sof = fr_sof(fp); ++ eof = fr_eof(fp); ++ ++ crc = ~0; ++ crc = crc32(crc, skb->data, skb_headlen(skb)); ++ ++ for (indx = 0; indx < skb_shinfo(skb)->nr_frags; indx++) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[indx]; ++ unsigned long off = frag->page_offset; ++ unsigned long len = frag->size; ++ ++ while (len > 0) { ++ unsigned long clen; ++ ++ clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); ++ data = kmap_atomic(frag->page + (off >> PAGE_SHIFT), ++ KM_SKB_DATA_SOFTIRQ); ++ crc = crc32(crc, data + (off & ~PAGE_MASK), ++ clen); ++ kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); ++ off += clen; ++ len -= clen; ++ } ++ } ++ ++ /* ++ * Get header and trailer lengths. ++ * This is temporary code until we get rid of the old protocol. ++ * Both versions have essentially the same trailer layout but T11 ++ * has padding afterwards. ++ */ ++ hlen = sizeof(struct fcoe_hdr); ++ tlen = sizeof(struct fcoe_crc_eof); ++ ++ /* ++ * copy fc crc and eof to the skb buff ++ * Use utility buffer in the fc_frame part of the sk_buff for the ++ * trailer. ++ * We don't do a get_page for this frag, since that page may not be ++ * managed that way. So that skb_free() doesn't do that either, we ++ * setup the destructor to remove this frag. ++ */ ++ if (skb_is_nonlinear(skb)) { ++ skb_frag_t *frag; ++ if (fcoe_get_paged_crc_eof(skb, tlen)) { ++ kfree(skb); ++ return -ENOMEM; ++ } ++ frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; ++ cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) ++ + frag->page_offset; ++ } else { ++ cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); ++ } ++ ++ cp->fcoe_eof = eof; ++ cp->fcoe_crc32 = cpu_to_le32(~crc); ++ if (tlen == sizeof(*cp)) ++ memset(cp->fcoe_resvd, 0, sizeof(cp->fcoe_resvd)); ++ wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; ++ ++ if (skb_is_nonlinear(skb)) { ++ kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); ++ cp = NULL; ++ } ++ ++ /* ++ * Fill in the control structures ++ */ ++ skb->ip_summed = CHECKSUM_NONE; ++ eh = (struct ethhdr *)skb_push(skb, hlen + sizeof(struct ethhdr)); ++ if (fc->address_mode == FCOE_FCOUI_ADDR_MODE) ++ fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); ++ else ++ /* insert GW address */ ++ memcpy(eh->h_dest, fc->dest_addr, ETH_ALEN); ++ ++ if (unlikely(flogi_in_progress)) ++ memcpy(eh->h_source, fc->ctl_src_addr, ETH_ALEN); ++ else ++ memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); ++ ++ eh->h_proto = htons(ETH_P_FCOE); ++ skb->protocol = htons(ETH_P_802_3); ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ ++ hp = (struct fcoe_hdr *)(eh + 1); ++ memset(hp, 0, sizeof(*hp)); ++ if (FC_FCOE_VER) ++ FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); ++ hp->fcoe_sof = sof; ++ ++ stats = lp->dev_stats[smp_processor_id()]; ++ stats->TxFrames++; ++ stats->TxWords += wlen; ++ skb->dev = fc->real_dev; ++ ++ fr_dev(fp) = lp; ++ if (fc->fcoe_pending_queue.qlen) ++ rc = fcoe_check_wait_queue(lp); ++ ++ if (rc == 0) ++ rc = fcoe_start_io(skb); ++ ++ if (rc) { ++ fcoe_insert_wait_queue(lp, skb); ++ if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) ++ fc_pause(lp); ++ } ++ ++ return 0; ++} ++ ++int fcoe_percpu_receive_thread(void *arg) ++{ ++ struct fcoe_percpu_s *p = arg; ++ u32 fr_len; ++ unsigned int hlen; ++ unsigned int tlen; ++ struct fc_lport *lp; ++ struct fcoe_rcv_info *fr; ++ struct fcoe_dev_stats *stats; ++ struct fc_frame_header *fh; ++ struct sk_buff *skb; ++ struct fcoe_crc_eof *cp; ++ enum fc_sof sof; ++ struct fc_frame *fp; ++ u8 *mac = NULL; ++ struct fcoe_softc *fc; ++ struct fcoe_hdr *hp; ++ ++ set_user_nice(current, 19); ++ ++ while (!kthread_should_stop()) { ++ ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ while ((skb = __skb_dequeue(&p->fcoe_rx_list)) == NULL) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ schedule(); ++ set_current_state(TASK_RUNNING); ++ if (kthread_should_stop()) ++ return 0; ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ } ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ fr = fcoe_dev_from_skb(skb); ++ lp = fr->fr_dev; ++ if (unlikely(lp == NULL)) { ++ FC_DBG("invalid HBA Structure"); ++ kfree_skb(skb); ++ continue; ++ } ++ ++ stats = lp->dev_stats[smp_processor_id()]; ++ ++ if (unlikely(debug_fcoe)) { ++ FC_DBG("skb_info: len:%d data_len:%d head:%p data:%p " ++ "tail:%p end:%p sum:%d dev:%s", ++ skb->len, skb->data_len, ++ skb->head, skb->data, skb_tail_pointer(skb), ++ skb_end_pointer(skb), skb->csum, ++ skb->dev ? skb->dev->name : ""); ++ } ++ ++ /* ++ * Save source MAC address before discarding header. ++ */ ++ fc = lp->drv_priv; ++ if (unlikely(fc->flogi_progress)) ++ mac = eth_hdr(skb)->h_source; ++ ++ if (skb_is_nonlinear(skb)) ++ skb_linearize(skb); /* not ideal */ ++ ++ /* ++ * Check the header and pull it off. ++ */ ++ hlen = sizeof(struct fcoe_hdr); ++ ++ hp = (struct fcoe_hdr *)skb->data; ++ if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { ++ if (stats->ErrorFrames < 5) ++ FC_DBG("unknown FCoE version %x", ++ FC_FCOE_DECAPS_VER(hp)); ++ stats->ErrorFrames++; ++ kfree_skb(skb); ++ continue; ++ } ++ sof = hp->fcoe_sof; ++ skb_pull(skb, sizeof(*hp)); ++ fr_len = skb->len - sizeof(struct fcoe_crc_eof); ++ skb_trim(skb, fr_len); ++ tlen = sizeof(struct fcoe_crc_eof); ++ ++ if (unlikely(fr_len > skb->len)) { ++ if (stats->ErrorFrames < 5) ++ FC_DBG("length error fr_len 0x%x skb->len 0x%x", ++ fr_len, skb->len); ++ stats->ErrorFrames++; ++ kfree_skb(skb); ++ continue; ++ } ++ stats->RxFrames++; ++ stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; ++ ++ fp = (struct fc_frame *) skb; ++ fc_frame_init(fp); ++ cp = (struct fcoe_crc_eof *)(skb->data + fr_len); ++ fr_eof(fp) = cp->fcoe_eof; ++ fr_sof(fp) = sof; ++ fr_dev(fp) = lp; ++ ++ /* ++ * Check the CRC here, unless it's solicited data for SCSI. ++ * In that case, the SCSI layer can check it during the copy, ++ * and it'll be more cache-efficient. ++ */ ++ fh = fc_frame_header_get(fp); ++ if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && ++ fh->fh_type == FC_TYPE_FCP) { ++ fr_flags(fp) |= FCPHF_CRC_UNCHECKED; ++ fc_exch_recv(lp, lp->emp, fp); ++ } else if (le32_to_cpu(cp->fcoe_crc32) == ++ ~crc32(~0, skb->data, fr_len)) { ++ if (unlikely(fc->flogi_progress)) ++ fcoe_recv_flogi(fc, fp, mac); ++ fc_exch_recv(lp, lp->emp, fp); ++ } else { ++ if (debug_fcoe || stats->InvalidCRCCount < 5) { ++ printk(KERN_WARNING \ ++ "fcoe: dropping frame with CRC error"); ++ } ++ stats->InvalidCRCCount++; ++ stats->ErrorFrames++; ++ fc_frame_free(fp); ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Snoop potential response to FLOGI or even incoming FLOGI. ++ */ ++static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa) ++{ ++ struct fc_frame_header *fh; ++ u8 op; ++ ++ fh = fc_frame_header_get(fp); ++ if (fh->fh_type != FC_TYPE_ELS) ++ return; ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && ++ fc->flogi_oxid == ntohs(fh->fh_ox_id)) { ++ /* ++ * FLOGI accepted. ++ * If the src mac addr is FC_OUI-based, then we mark the ++ * address_mode flag to use FC_OUI-based Ethernet DA. ++ * Otherwise we use the FCoE gateway addr ++ */ ++ if (!compare_ether_addr(sa, (u8[6]) FC_FCOE_FLOGI_MAC)) { ++ fc->address_mode = FCOE_FCOUI_ADDR_MODE; ++ } else { ++ memcpy(fc->dest_addr, sa, ETH_ALEN); ++ fc->address_mode = FCOE_GW_ADDR_MODE; ++ } ++ ++ /* ++ * Remove any previously-set unicast MAC filter. ++ * Add secondary FCoE MAC address filter for our OUI. ++ */ ++ rtnl_lock(); ++ if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) ++ dev_unicast_delete(fc->real_dev, fc->data_src_addr, ++ ETH_ALEN); ++ fc_fcoe_set_mac(fc->data_src_addr, fh->fh_d_id); ++ dev_unicast_add(fc->real_dev, fc->data_src_addr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ fc->flogi_progress = 0; ++ } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { ++ /* ++ * Save source MAC for point-to-point responses. ++ */ ++ memcpy(fc->dest_addr, sa, ETH_ALEN); ++ fc->address_mode = FCOE_GW_ADDR_MODE; ++ } ++} ++ ++void fcoe_watchdog(ulong vp) ++{ ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ struct fcoe_info *fci = &fcoei; ++ int paused = 0; ++ ++ read_lock(&fci->fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fci->fcoe_hostlist, list) { ++ lp = fc->lp; ++ if (lp) { ++ if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) ++ paused = 1; ++ if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) { ++ if (paused) ++ fc_unpause(lp); ++ } ++ } ++ } ++ read_unlock(&fci->fcoe_hostlist_lock); ++ ++ fci->timer.expires = jiffies + (1 * HZ); ++ add_timer(&fci->timer); ++} ++ ++/* ++ * the wait_queue is used when the skb transmit fails. skb will go ++ * in the wait_queue which will be emptied by the time function OR ++ * by the next skb transmit. ++ * ++ */ ++ ++/* ++ * Function name : fcoe_check_wait_queue() ++ * ++ * Return Values : 0 or error ++ * ++ * Description : empties the wait_queue ++ * dequeue the head of the wait_queue queue and ++ * calls fcoe_start_io() for each packet ++ * if all skb have been transmitted, return 0 ++ * if a error occurs, then restore wait_queue and try again ++ * later ++ * ++ */ ++ ++static int fcoe_check_wait_queue(struct fc_lport *lp) ++{ ++ int rc, unpause = 0; ++ int paused = 0; ++ struct sk_buff *skb; ++ struct fcoe_softc *fc; ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ ++ /* ++ * is this interface paused? ++ */ ++ if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH) ++ paused = 1; ++ if (fc->fcoe_pending_queue.qlen) { ++ while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ rc = fcoe_start_io(skb); ++ if (rc) { ++ fcoe_insert_wait_queue_head(lp, skb); ++ return rc; ++ } ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ } ++ if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH) ++ unpause = 1; ++ } ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ if ((unpause) && (paused)) ++ fc_unpause(lp); ++ return fc->fcoe_pending_queue.qlen; ++} ++ ++static void fcoe_insert_wait_queue_head(struct fc_lport *lp, ++ struct sk_buff *skb) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ __skb_queue_head(&fc->fcoe_pending_queue, skb); ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} ++ ++static void fcoe_insert_wait_queue(struct fc_lport *lp, ++ struct sk_buff *skb) ++{ ++ struct fcoe_softc *fc; ++ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ __skb_queue_tail(&fc->fcoe_pending_queue, skb); ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} +diff --git a/drivers/scsi/fcoe/fcoe_if.c b/drivers/scsi/fcoe/fcoe_if.c +new file mode 100644 +index 0000000..7f983e2 +--- /dev/null ++++ b/drivers/scsi/fcoe/fcoe_if.c +@@ -0,0 +1,497 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * FCOE protocol file ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include "fcoe_def.h" ++ ++#define FCOE_VERSION "0.1" ++ ++#define FCOE_MAX_LUN 255 ++#define FCOE_MAX_FCP_TARGET 256 ++ ++#define FCOE_MIN_XID 0x0004 ++#define FCOE_MAX_XID 0x07ef ++ ++int debug_fcoe; ++ ++struct fcoe_info fcoei = { ++ .fcoe_hostlist = LIST_HEAD_INIT(fcoei.fcoe_hostlist), ++}; ++ ++static struct fcoe_softc *fcoe_find_fc_lport(const char *name) ++{ ++ struct fcoe_softc *fc; ++ struct fc_lport *lp; ++ struct fcoe_info *fci = &fcoei; ++ ++ read_lock(&fci->fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fci->fcoe_hostlist, list) { ++ lp = fc->lp; ++ if (!strncmp(name, lp->ifname, IFNAMSIZ)) { ++ read_unlock(&fci->fcoe_hostlist_lock); ++ return fc; ++ } ++ } ++ read_unlock(&fci->fcoe_hostlist_lock); ++ return NULL; ++} ++ ++/* ++ * Convert 48-bit IEEE MAC address to 64-bit FC WWN. ++ */ ++static u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], ++ unsigned int scheme, unsigned int port) ++{ ++ u64 wwn; ++ u64 host_mac; ++ ++ /* The MAC is in NO, so flip only the low 48 bits */ ++ host_mac = ((u64) mac[0] << 40) | ++ ((u64) mac[1] << 32) | ++ ((u64) mac[2] << 24) | ++ ((u64) mac[3] << 16) | ++ ((u64) mac[4] << 8) | ++ (u64) mac[5]; ++ ++ WARN_ON(host_mac >= (1ULL << 48)); ++ wwn = host_mac | ((u64) scheme << 60); ++ switch (scheme) { ++ case 1: ++ WARN_ON(port != 0); ++ break; ++ case 2: ++ WARN_ON(port >= 0xfff); ++ wwn |= (u64) port << 48; ++ break; ++ default: ++ WARN_ON(1); ++ break; ++ } ++ ++ return wwn; ++} ++ ++static struct scsi_host_template fcoe_driver_template = { ++ .module = THIS_MODULE, ++ .name = "FCoE Driver", ++ .proc_name = FCOE_DRIVER_NAME, ++ .queuecommand = fc_queuecommand, ++ .eh_abort_handler = fc_eh_abort, ++ .eh_device_reset_handler = fc_eh_device_reset, ++ .eh_host_reset_handler = fc_eh_host_reset, ++ .slave_alloc = fc_slave_alloc, ++ .change_queue_depth = fc_change_queue_depth, ++ .change_queue_type = fc_change_queue_type, ++ .this_id = -1, ++ .cmd_per_lun = 32, ++ .can_queue = FC_MAX_OUTSTANDING_COMMANDS, ++ .use_clustering = ENABLE_CLUSTERING, ++ .sg_tablesize = 4, ++ .max_sectors = 0xffff, ++}; ++ ++int fcoe_destroy_interface(const char *ifname) ++{ ++ int cpu, idx; ++ struct fcoe_dev_stats *p; ++ struct fcoe_percpu_s *pp; ++ struct fcoe_softc *fc; ++ struct fcoe_rcv_info *fr; ++ struct fcoe_info *fci = &fcoei; ++ struct sk_buff_head *list; ++ struct sk_buff *skb, *next; ++ struct sk_buff *head; ++ struct fc_lport *lp; ++ u8 flogi_maddr[ETH_ALEN]; ++ ++ fc = fcoe_find_fc_lport(ifname); ++ if (!fc) ++ return -ENODEV; ++ ++ lp = fc->lp; ++ ++ /* Remove the instance from fcoe's list */ ++ write_lock_bh(&fci->fcoe_hostlist_lock); ++ list_del(&fc->list); ++ write_unlock_bh(&fci->fcoe_hostlist_lock); ++ ++ /* Cleanup the fc_lport */ ++ fc_lport_destroy(lp); ++ fc_fcp_destroy(lp); ++ if (lp->emp) ++ fc_exch_mgr_free(lp->emp); ++ ++ /* Detach from the scsi-ml */ ++ fc_remove_host(lp->host); ++ scsi_remove_host(lp->host); ++ ++ /* Don't listen for Ethernet packets anymore */ ++ dev_remove_pack(&fc->fcoe_packet_type); ++ ++ /* Delete secondary MAC addresses */ ++ rtnl_lock(); ++ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); ++ dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN); ++ if (compare_ether_addr(fc->data_src_addr, (u8[6]) { 0 })) ++ dev_unicast_delete(fc->real_dev, fc->data_src_addr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ /* Free the per-CPU revieve threads */ ++ for (idx = 0; idx < NR_CPUS; idx++) { ++ if (fci->fcoe_percpu[idx]) { ++ pp = fci->fcoe_percpu[idx]; ++ spin_lock_bh(&pp->fcoe_rx_list.lock); ++ list = &pp->fcoe_rx_list; ++ head = list->next; ++ for (skb = head; skb != (struct sk_buff *)list; ++ skb = next) { ++ next = skb->next; ++ fr = fcoe_dev_from_skb(skb); ++ if (fr->fr_dev == fc->lp) { ++ __skb_unlink(skb, list); ++ kfree_skb(skb); ++ } ++ } ++ spin_unlock_bh(&pp->fcoe_rx_list.lock); ++ } ++ } ++ ++ /* Free existing skbs */ ++ fcoe_clean_pending_queue(lp); ++ ++ /* Free memory used by statistical counters */ ++ for_each_online_cpu(cpu) { ++ p = lp->dev_stats[cpu]; ++ if (p) { ++ lp->dev_stats[cpu] = NULL; ++ kfree(p); ++ } ++ } ++ ++ /* Release the net_device and Scsi_Host */ ++ dev_put(fc->real_dev); ++ scsi_host_put(lp->host); ++ return 0; ++} ++ ++/* ++ * Return zero if link is OK for use by FCoE. ++ * Any permanently-disqualifying conditions have been previously checked. ++ * This also updates the speed setting, which may change with link for 100/1000. ++ * ++ * This function should probably be checking for PAUSE support at some point ++ * in the future. Currently Per-priority-pause is not determinable using ++ * ethtool, so we shouldn't be restrictive until that problem is resolved. ++ */ ++int fcoe_link_ok(struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; ++ struct net_device *dev = fc->real_dev; ++ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; ++ int rc = 0; ++ ++ if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) { ++ dev = fc->phys_dev; ++ if (dev->ethtool_ops->get_settings) { ++ dev->ethtool_ops->get_settings(dev, &ecmd); ++ lp->link_supported_speeds &= ++ ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); ++ if (ecmd.supported & (SUPPORTED_1000baseT_Half | ++ SUPPORTED_1000baseT_Full)) ++ lp->link_supported_speeds |= FC_PORTSPEED_1GBIT; ++ if (ecmd.supported & SUPPORTED_10000baseT_Full) ++ lp->link_supported_speeds |= ++ FC_PORTSPEED_10GBIT; ++ if (ecmd.speed == SPEED_1000) ++ lp->link_speed = FC_PORTSPEED_1GBIT; ++ if (ecmd.speed == SPEED_10000) ++ lp->link_speed = FC_PORTSPEED_10GBIT; ++ } ++ } else ++ rc = -1; ++ ++ return rc; ++} ++ ++static struct libfc_function_template fcoe_libfc_fcn_templ = { ++ .frame_send = fcoe_xmit, ++}; ++ ++static int lport_config(struct fc_lport *lp, struct Scsi_Host *shost) ++{ ++ int i = 0; ++ struct fcoe_dev_stats *p; ++ ++ lp->host = shost; ++ lp->drv_priv = (void *)(lp + 1); ++ ++ lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, ++ FCOE_MIN_XID, FCOE_MAX_XID); ++ if (!lp->emp) ++ return -ENOMEM; ++ ++ lp->link_status = 0; ++ lp->max_retry_count = 3; ++ lp->e_d_tov = 2 * 1000; /* FC-FS default */ ++ lp->r_a_tov = 2 * 2 * 1000; ++ lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | ++ FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); ++ ++ /* ++ * allocate per cpu stats block ++ */ ++ for_each_online_cpu(i) { ++ p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); ++ if (p) ++ lp->dev_stats[i] = p; ++ } ++ ++ /* Finish fc_lport configuration */ ++ fc_lport_config(lp); ++ ++ return 0; ++} ++ ++static int net_config(struct fc_lport *lp) ++{ ++ u32 mfs; ++ u64 wwnn, wwpn; ++ struct net_device *net_dev; ++ struct fcoe_softc *fc = (struct fcoe_softc *)lp->drv_priv; ++ u8 flogi_maddr[ETH_ALEN]; ++ ++ /* Require support for get_pauseparam ethtool op. */ ++ net_dev = fc->real_dev; ++ if (!net_dev->ethtool_ops && (net_dev->priv_flags & IFF_802_1Q_VLAN)) ++ net_dev = vlan_dev_real_dev(net_dev); ++ if (!net_dev->ethtool_ops || !net_dev->ethtool_ops->get_pauseparam) ++ return -EOPNOTSUPP; ++ ++ fc->phys_dev = net_dev; ++ ++ /* Do not support for bonding device */ ++ if ((fc->real_dev->priv_flags & IFF_MASTER_ALB) || ++ (fc->real_dev->priv_flags & IFF_SLAVE_INACTIVE) || ++ (fc->real_dev->priv_flags & IFF_MASTER_8023AD)) { ++ return -EOPNOTSUPP; ++ } ++ ++ /* ++ * Determine max frame size based on underlying device and optional ++ * user-configured limit. If the MFS is too low, fcoe_link_ok() ++ * will return 0, so do this first. ++ */ ++ mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) + ++ sizeof(struct fcoe_crc_eof)); ++ fc_set_mfs(lp, mfs); ++ ++ lp->link_status = ~FC_PAUSE & ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ lp->link_status |= FC_LINK_UP; ++ ++ if (fc->real_dev->features & NETIF_F_SG) ++ lp->capabilities = TRANS_C_SG; ++ ++ ++ skb_queue_head_init(&fc->fcoe_pending_queue); ++ ++ memcpy(lp->ifname, fc->real_dev->name, IFNAMSIZ); ++ ++ /* setup Source Mac Address */ ++ memcpy(fc->ctl_src_addr, fc->real_dev->dev_addr, ++ fc->real_dev->addr_len); ++ ++ wwnn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 1, 0); ++ fc_set_wwnn(lp, wwnn); ++ /* XXX - 3rd arg needs to be vlan id */ ++ wwpn = fcoe_wwn_from_mac(fc->real_dev->dev_addr, 2, 0); ++ fc_set_wwpn(lp, wwpn); ++ ++ /* ++ * Add FCoE MAC address as second unicast MAC address ++ * or enter promiscuous mode if not capable of listening ++ * for multiple unicast MACs. ++ */ ++ rtnl_lock(); ++ memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); ++ dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN); ++ rtnl_unlock(); ++ ++ /* ++ * setup the receive function from ethernet driver ++ * on the ethertype for the given device ++ */ ++ fc->fcoe_packet_type.func = fcoe_rcv; ++ fc->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); ++ fc->fcoe_packet_type.dev = fc->real_dev; ++ dev_add_pack(&fc->fcoe_packet_type); ++ ++ return 0; ++} ++ ++static void shost_config(struct fc_lport *lp) ++{ ++ lp->host->max_lun = FCOE_MAX_LUN; ++ lp->host->max_id = FCOE_MAX_FCP_TARGET; ++ lp->host->max_channel = 0; ++ lp->host->transportt = fcoe_transport_template; ++} ++ ++static int libfc_config(struct fc_lport *lp) ++{ ++ /* Set the function pointers set by the LLDD */ ++ memcpy(&lp->tt, &fcoe_libfc_fcn_templ, ++ sizeof(struct libfc_function_template)); ++ ++ if (fc_fcp_init(lp)) ++ return -ENOMEM; ++ fc_exch_init(lp); ++ fc_lport_init(lp); ++ fc_rport_init(lp); ++ fc_ns_init(lp); ++ fc_attr_init(lp); ++ ++ return 0; ++} ++ ++/* ++ * This function creates the fcoe interface ++ * create struct fcdev which is a shared structure between opefc ++ * and transport level protocol. ++ */ ++int fcoe_create_interface(const char *ifname) ++{ ++ struct fc_lport *lp = NULL; ++ struct fcoe_softc *fc; ++ struct net_device *net_dev; ++ struct Scsi_Host *shost; ++ struct fcoe_info *fci = &fcoei; ++ int rc = 0; ++ ++ net_dev = dev_get_by_name(&init_net, ifname); ++ if (net_dev == NULL) { ++ FC_DBG("could not get network device for %s", ++ ifname); ++ return -ENODEV; ++ } ++ ++ if (fcoe_find_fc_lport(net_dev->name) != NULL) { ++ rc = -EEXIST; ++ goto out_put_dev; ++ } ++ ++ shost = scsi_host_alloc(&fcoe_driver_template, ++ sizeof(struct fc_lport) + ++ sizeof(struct fcoe_softc)); ++ ++ if (!shost) { ++ FC_DBG("Could not allocate host structure\n"); ++ rc = -ENOMEM; ++ goto out_put_dev; ++ } ++ ++ lp = shost_priv(shost); ++ rc = lport_config(lp, shost); ++ if (rc) ++ goto out_host_put; ++ ++ /* Configure the fcoe_softc */ ++ fc = (struct fcoe_softc *)lp->drv_priv; ++ fc->lp = lp; ++ fc->real_dev = net_dev; ++ shost_config(lp); ++ ++ ++ /* Add the new host to the SCSI-ml */ ++ rc = scsi_add_host(lp->host, NULL); ++ if (rc) { ++ FC_DBG("error on scsi_add_host\n"); ++ goto out_lp_destroy; ++ } ++ ++ sprintf(fc_host_symbolic_name(lp->host), "%s v%s over %s", ++ FCOE_DRIVER_NAME, FCOE_VERSION, ++ ifname); ++ ++ /* Configure netdev and networking properties of the lp */ ++ rc = net_config(lp); ++ if (rc) ++ goto out_lp_destroy; ++ ++ /* Initialize the library */ ++ rc = libfc_config(lp); ++ if (rc) ++ goto out_lp_destroy; ++ ++ write_lock_bh(&fci->fcoe_hostlist_lock); ++ list_add_tail(&fc->list, &fci->fcoe_hostlist); ++ write_unlock_bh(&fci->fcoe_hostlist_lock); ++ ++ lp->boot_time = jiffies; ++ ++ fc_fabric_login(lp); ++ ++ return rc; ++ ++out_lp_destroy: ++ fc_exch_mgr_free(lp->emp); /* Free the EM */ ++out_host_put: ++ scsi_host_put(lp->host); ++out_put_dev: ++ dev_put(net_dev); ++ return rc; ++} ++ ++void fcoe_clean_pending_queue(struct fc_lport *lp) ++{ ++ struct fcoe_softc *fc = lp->drv_priv; ++ struct sk_buff *skb; ++ ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) { ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++ kfree_skb(skb); ++ spin_lock_bh(&fc->fcoe_pending_queue.lock); ++ } ++ spin_unlock_bh(&fc->fcoe_pending_queue.lock); ++} +diff --git a/drivers/scsi/fcoe/fcoeinit.c b/drivers/scsi/fcoe/fcoeinit.c +new file mode 100644 +index 0000000..e069835 +--- /dev/null ++++ b/drivers/scsi/fcoe/fcoeinit.c +@@ -0,0 +1,440 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "fcoe_def.h" ++ ++MODULE_AUTHOR("Open-FCoE.org"); ++MODULE_DESCRIPTION("FCoE"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Static functions and variables definations ++ */ ++#ifdef CONFIG_HOTPLUG_CPU ++static int fcoe_cpu_callback(struct notifier_block *, ulong, void *); ++#endif /* CONFIG_HOTPLUG_CPU */ ++static int fcoe_device_notification(struct notifier_block *, ulong, void *); ++static void fcoe_dev_setup(void); ++static void fcoe_dev_cleanup(void); ++ ++struct scsi_transport_template *fcoe_transport_template; ++ ++static int fcoe_reset(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lp = shost_priv(shost); ++ fc_lport_enter_reset(lp); ++ return 0; ++} ++ ++struct fc_function_template fcoe_transport_function = { ++ .show_host_node_name = 1, ++ .show_host_port_name = 1, ++ .show_host_supported_classes = 1, ++ .show_host_supported_fc4s = 1, ++ .show_host_active_fc4s = 1, ++ .show_host_maxframe_size = 1, ++ ++ .get_host_port_id = fc_get_host_port_id, ++ .show_host_port_id = 1, ++ .get_host_speed = fc_get_host_speed, ++ .show_host_speed = 1, ++ .get_host_port_type = fc_get_host_port_type, ++ .show_host_port_type = 1, ++ .get_host_port_state = fc_get_host_port_state, ++ .show_host_port_state = 1, ++ .show_host_symbolic_name = 1, ++ ++ .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), ++ .show_rport_maxframe_size = 1, ++ .show_rport_supported_classes = 1, ++ ++ .get_host_fabric_name = fc_get_host_fabric_name, ++ .show_host_fabric_name = 1, ++ .show_starget_node_name = 1, ++ .show_starget_port_name = 1, ++ .show_starget_port_id = 1, ++ .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, ++ .show_rport_dev_loss_tmo = 1, ++ .get_fc_host_stats = fc_get_host_stats, ++ .issue_fc_host_lip = fcoe_reset, ++}; ++ ++struct fcoe_percpu_s *fcoe_percpu[NR_CPUS]; ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static struct notifier_block fcoe_cpu_notifier = { ++ .notifier_call = fcoe_cpu_callback, ++}; ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* ++ * notification function from net device ++ */ ++static struct notifier_block fcoe_notifier = { ++ .notifier_call = fcoe_device_notification, ++}; ++ ++#ifdef CONFIG_HOTPLUG_CPU ++/* ++ * create percpu stats block ++ * called by cpu add/remove notifier ++ */ ++static void fcoe_create_percpu_data(int cpu) ++{ ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *p; ++ struct fcoe_info *fci = &fcoei; ++ ++ write_lock_bh(&fci->fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fci->fcoe_hostlist, list) { ++ lp = fc->lp; ++ if (lp->dev_stats[cpu] == NULL) { ++ p = kzalloc(sizeof(struct fcoe_dev_stats), GFP_KERNEL); ++ if (p) ++ lp->dev_stats[cpu] = p; ++ } ++ } ++ write_unlock_bh(&fci->fcoe_hostlist_lock); ++} ++ ++/* ++ * destroy percpu stats block ++ * called by cpu add/remove notifier ++ */ ++static void fcoe_destroy_percpu_data(int cpu) ++{ ++ struct fcoe_dev_stats *p; ++ struct fc_lport *lp; ++ struct fcoe_softc *fc; ++ struct fcoe_info *fci = &fcoei; ++ ++ write_lock_bh(&fci->fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fci->fcoe_hostlist, list) { ++ lp = fc->lp; ++ p = lp->dev_stats[cpu]; ++ if (p != NULL) { ++ lp->dev_stats[cpu] = NULL; ++ kfree(p); ++ } ++ } ++ write_unlock_bh(&fci->fcoe_hostlist_lock); ++} ++ ++/* ++ * Get notified when a cpu comes on/off. Be hotplug friendly. ++ */ ++static int fcoe_cpu_callback(struct notifier_block *nfb, unsigned long action, ++ void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ fcoe_create_percpu_data(cpu); ++ break; ++ case CPU_DEAD: ++ fcoe_destroy_percpu_data(cpu); ++ break; ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* ++ * function to setup link change notification interface ++ */ ++static void fcoe_dev_setup(void) ++{ ++ /* ++ * here setup a interface specific wd time to ++ * monitor the link state ++ */ ++ register_netdevice_notifier(&fcoe_notifier); ++} ++ ++/* ++ * function to cleanup link change notification interface ++ */ ++static void fcoe_dev_cleanup(void) ++{ ++ unregister_netdevice_notifier(&fcoe_notifier); ++} ++ ++/* ++ * This function is called by the ethernet driver ++ * this is called in case of link change event ++ */ ++static int fcoe_device_notification(struct notifier_block *notifier, ++ ulong event, void *ptr) ++{ ++ struct fc_lport *lp = NULL; ++ struct net_device *real_dev = ptr; ++ struct fcoe_softc *fc; ++ struct fcoe_dev_stats *stats; ++ struct fcoe_info *fci = &fcoei; ++ u16 new_status; ++ u32 mfs; ++ int rc = NOTIFY_OK; ++ ++ read_lock(&fci->fcoe_hostlist_lock); ++ list_for_each_entry(fc, &fci->fcoe_hostlist, list) { ++ if (fc->real_dev == real_dev) { ++ lp = fc->lp; ++ break; ++ } ++ } ++ read_unlock(&fci->fcoe_hostlist_lock); ++ if (lp == NULL) { ++ rc = NOTIFY_DONE; ++ goto out; ++ } ++ ++ new_status = lp->link_status; ++ switch (event) { ++ case NETDEV_DOWN: ++ case NETDEV_GOING_DOWN: ++ new_status &= ~FC_LINK_UP; ++ break; ++ case NETDEV_UP: ++ case NETDEV_CHANGE: ++ new_status &= ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ new_status |= FC_LINK_UP; ++ break; ++ case NETDEV_CHANGEMTU: ++ mfs = fc->real_dev->mtu - ++ (sizeof(struct fcoe_hdr) + ++ sizeof(struct fcoe_crc_eof)); ++ if (fc->user_mfs && fc->user_mfs < mfs) ++ mfs = fc->user_mfs; ++ if (mfs >= FC_MIN_MAX_FRAME) ++ fc_set_mfs(lp, mfs); ++ new_status &= ~FC_LINK_UP; ++ if (!fcoe_link_ok(lp)) ++ new_status |= FC_LINK_UP; ++ break; ++ case NETDEV_REGISTER: ++ break; ++ default: ++ FC_DBG("unknown event %ld call", event); ++ } ++ if (lp->link_status != new_status) { ++ if ((new_status & FC_LINK_UP) == FC_LINK_UP) ++ fc_linkup(lp); ++ else { ++ stats = lp->dev_stats[smp_processor_id()]; ++ stats->LinkFailureCount++; ++ fc_linkdown(lp); ++ fcoe_clean_pending_queue(lp); ++ } ++ } ++out: ++ return rc; ++} ++ ++static void trimstr(char *str, int len) ++{ ++ char *cp = str + len; ++ while (--cp >= str && *cp == '\n') ++ *cp = '\0'; ++} ++ ++static ssize_t fcoe_destroy(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buffer, size_t size) ++{ ++ char ifname[40]; ++ strcpy(ifname, buffer); ++ trimstr(ifname, strlen(ifname)); ++ fcoe_destroy_interface(ifname); ++ return size; ++} ++ ++static ssize_t fcoe_create(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buffer, size_t size) ++{ ++ char ifname[40]; ++ strcpy(ifname, buffer); ++ trimstr(ifname, strlen(ifname)); ++ fcoe_create_interface(ifname); ++ return size; ++} ++ ++static const struct kobj_attribute fcoe_destroyattr = \ ++ __ATTR(destroy, S_IWUSR, NULL, fcoe_destroy); ++static const struct kobj_attribute fcoe_createattr = \ ++ __ATTR(create, S_IWUSR, NULL, fcoe_create); ++ ++/* ++ * Initialization routine ++ * 1. Will create fc transport software structure ++ * 2. initialize the link list of port information structure ++ */ ++static int __init fcoeinit(void) ++{ ++ int rc = 0; ++ int cpu; ++ struct fcoe_percpu_s *p; ++ struct fcoe_info *fci = &fcoei; ++ ++ rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, ++ &fcoe_destroyattr.attr); ++ if (!rc) ++ rc = sysfs_create_file(&THIS_MODULE->mkobj.kobj, ++ &fcoe_createattr.attr); ++ ++ if (rc) ++ return rc; ++ ++ rwlock_init(&fci->fcoe_hostlist_lock); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ register_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++ /* ++ * initialize per CPU interrupt thread ++ */ ++ for_each_online_cpu(cpu) { ++ p = kzalloc(sizeof(struct fcoe_percpu_s), GFP_KERNEL); ++ if (p) { ++ p->thread = kthread_create(fcoe_percpu_receive_thread, ++ (void *)p, ++ "fcoethread/%d", cpu); ++ ++ /* ++ * if there is no error then bind the thread to the cpu ++ * initialize the semaphore and skb queue head ++ */ ++ if (likely(!IS_ERR(p->thread))) { ++ p->cpu = cpu; ++ fci->fcoe_percpu[cpu] = p; ++ skb_queue_head_init(&p->fcoe_rx_list); ++ kthread_bind(p->thread, cpu); ++ wake_up_process(p->thread); ++ } else { ++ fci->fcoe_percpu[cpu] = NULL; ++ kfree(p); ++ ++ } ++ } ++ } ++ if (rc < 0) { ++ FC_DBG("failed to initialize proc intrerface\n"); ++ rc = -ENODEV; ++ goto out_chrdev; ++ } ++ ++ /* ++ * setup link change notification ++ */ ++ fcoe_dev_setup(); ++ ++ init_timer(&fci->timer); ++ fci->timer.data = (ulong) fci; ++ fci->timer.function = fcoe_watchdog; ++ fci->timer.expires = (jiffies + (10 * HZ)); ++ add_timer(&fci->timer); ++ ++ fcoe_transport_template = ++ fc_attach_transport(&fcoe_transport_function); ++ ++ if (fcoe_transport_template == NULL) { ++ FC_DBG("fail to attach fc transport"); ++ return -1; ++ } ++ ++ return 0; ++ ++out_chrdev: ++#ifdef CONFIG_HOTPLUG_CPU ++ unregister_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ return rc; ++} ++ ++static void __exit fcoe_exit(void) ++{ ++ u32 idx; ++ struct fcoe_softc *fc, *tmp; ++ struct fc_lport *lp; ++ struct fcoe_info *fci = &fcoei; ++ struct fcoe_percpu_s *p; ++ struct sk_buff *skb; ++ ++ /* ++ * Stop all call back interfaces ++ */ ++#ifdef CONFIG_HOTPLUG_CPU ++ unregister_cpu_notifier(&fcoe_cpu_notifier); ++#endif /* CONFIG_HOTPLUG_CPU */ ++ fcoe_dev_cleanup(); ++ ++ /* ++ * stop timer ++ */ ++ del_timer_sync(&fci->timer); ++ ++ /* ++ * assuming that at this time there will be no ++ * ioctl in prograss, therefore we do not need to lock the ++ * list. ++ */ ++ list_for_each_entry_safe(fc, tmp, &fci->fcoe_hostlist, list) { ++ lp = fc->lp; ++ fcoe_destroy_interface(lp->ifname); ++ } ++ ++ for (idx = 0; idx < NR_CPUS; idx++) { ++ if (fci->fcoe_percpu[idx]) { ++ kthread_stop(fci->fcoe_percpu[idx]->thread); ++ p = fci->fcoe_percpu[idx]; ++ spin_lock_bh(&p->fcoe_rx_list.lock); ++ while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) ++ kfree_skb(skb); ++ spin_unlock_bh(&p->fcoe_rx_list.lock); ++ if (fci->fcoe_percpu[idx]->crc_eof_page) ++ put_page(fci->fcoe_percpu[idx]->crc_eof_page); ++ kfree(fci->fcoe_percpu[idx]); ++ } ++ } ++ ++ fc_release_transport(fcoe_transport_template); ++} ++ ++module_init(fcoeinit); ++module_exit(fcoe_exit); +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-fnic-patches b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-fnic-patches new file mode 100644 index 000000000..15aaa627e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-fnic-patches @@ -0,0 +1,255 @@ +Subject: Open-FCoE bugfixes for fnic +From: Hannes Reinecke +Date: Fri Dec 5 16:40:29 2008 +0100: + +The fnic driver requires some bugfixes for the open-FCoE stack. + +Signed-off-by: Abhijeet Joglekar +Acked-by: Hannes Reinecke + +diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c +index 0cd8d0c..2b13e7b 100644 +--- a/drivers/scsi/libfc/fc_disc.c ++++ b/drivers/scsi/libfc/fc_disc.c +@@ -101,12 +101,8 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, + } + } + +- if (!disc_found) { +- FC_DEBUG_DISC("The rport (%6x) for lport (%6x) " +- "is not maintained by the discovery layer\n", +- port_id, fc_host_port_id(lport->host)); ++ if (!disc_found) + found = NULL; +- } + + return found; + } +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +index 12a1196..d81ed95 100644 +--- a/drivers/scsi/libfc/fc_exch.c ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -378,7 +378,6 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec) + return -ENOMEM; + } + +- sp->f_ctl |= FC_FC_SEQ_INIT; + ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL; + if (timer_msec) + fc_exch_timer_set_locked(ep, timer_msec); +@@ -466,7 +465,6 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) + + sp = &ep->seq; + sp->ssb_stat = 0; +- sp->f_ctl = 0; + sp->cnt = 0; + sp->id = seq_id; + return sp; +@@ -530,7 +528,7 @@ static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) + struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, + struct fc_frame *fp, u16 xid) + { +- struct fc_exch *ep = NULL; ++ struct fc_exch *ep; + + /* allocate memory for exchange */ + ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); +@@ -834,8 +832,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp) + struct fc_exch *ep = fc_seq_exch(sp); + + sp = fc_seq_alloc(ep, ep->seq_id++); +- FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x f_ctl %6x\n", +- ep->xid, ep->f_ctl, sp->id, sp->f_ctl); ++ FC_DEBUG_EXCH("exch %4x f_ctl %6x seq %2x\n", ++ ep->xid, ep->f_ctl, sp->id); + return sp; + } + /* +@@ -860,12 +858,13 @@ int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp) + struct fc_exch *ep; + struct fc_frame_header *fh = fc_frame_header_get(fp); + int error; ++ u32 f_ctl; + + ep = fc_seq_exch(sp); + WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); + +- sp->f_ctl = ntoh24(fh->fh_f_ctl); +- fc_exch_setup_hdr(ep, fp, sp->f_ctl); ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ fc_exch_setup_hdr(ep, fp, f_ctl); + + /* + * update sequence count if this frame is carrying +@@ -889,9 +888,8 @@ int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, struct fc_frame *fp) + * We can only be called to send once for each sequence. + */ + spin_lock_bh(&ep->ex_lock); +- ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ +- sp->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ +- if (sp->f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT)) ++ ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */ ++ if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT)) + ep->esb_stat &= ~ESB_ST_SEQ_INIT; + spin_unlock_bh(&ep->ex_lock); + return error; +@@ -930,8 +928,9 @@ static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp, + struct fc_exch *ep = fc_seq_exch(sp); + + f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; ++ f_ctl |= ep->f_ctl; + fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0); +- fc_seq_send(fc_seq_exch(sp)->lp, sp, fp); ++ fc_seq_send(ep->lp, sp, fp); + } + + /* +@@ -952,7 +951,6 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) + */ + if (fc_sof_needs_ack(fr_sof(rx_fp))) { + fp = fc_frame_alloc(lp, 0); +- BUG_ON(!fp); + if (!fp) + return; + +@@ -1848,7 +1846,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + ep->r_a_tov = FC_DEF_R_A_TOV; + ep->lp = lp; + sp = &ep->seq; +- WARN_ON((sp->f_ctl & FC_FC_END_SEQ) != 0); + + ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ + ep->f_ctl = ntoh24(fh->fh_f_ctl); +@@ -1861,7 +1858,6 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, + if (timer_msec) + fc_exch_timer_set_locked(ep, timer_msec); + ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ +- sp->f_ctl = ep->f_ctl; /* save for possible abort */ + + if (ep->f_ctl & FC_FC_SEQ_INIT) + ep->esb_stat &= ~ESB_ST_SEQ_INIT; +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index de16203..591d160 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -465,6 +465,56 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, + } + + /** ++ * fc_lport_recv_adisc_req - Handle received Address Discovery Request ++ * @lport: Fibre Channel local port recieving the ADISC ++ * @sp: current sequence in the ADISC exchange ++ * @fp: ADISC request frame ++ * ++ * Locking Note: The lport lock is exected to be held before calling ++ * this function. ++ */ ++static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp, ++ struct fc_lport *lport) ++{ ++ struct fc_frame *fp; ++ struct fc_exch *ep = fc_seq_exch(sp); ++ struct fc_els_adisc *req, *rp; ++ struct fc_seq_els_data rjt_data; ++ size_t len; ++ u32 f_ctl; ++ ++ FC_DEBUG_LPORT("Received ADISC request while in state %s\n", ++ fc_lport_state(lport)); ++ ++ req = fc_frame_payload_get(in_fp, sizeof(*req)); ++ if (!req) { ++ rjt_data.fp = NULL; ++ rjt_data.reason = ELS_RJT_LOGIC; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ } else { ++ len = sizeof(*rp); ++ fp = fc_frame_alloc(lport, len); ++ if (fp) { ++ rp = fc_frame_payload_get(fp, len); ++ memset(rp, 0, len); ++ rp->adisc_cmd = ELS_LS_ACC; ++ rp->adisc_wwpn = htonll(lport->wwpn); ++ rp->adisc_wwnn = htonll(lport->wwnn); ++ hton24(rp->adisc_port_id, ++ fc_host_port_id(lport->host)); ++ sp = lport->tt.seq_start_next(sp); ++ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; ++ f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; ++ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, ++ FC_TYPE_ELS, f_ctl, 0); ++ lport->tt.seq_send(lport, sp, fp); ++ } ++ } ++ fc_frame_free(in_fp); ++} ++ ++/** + * fc_lport_recv_logo_req - Handle received fabric LOGO request + * @lport: Fibre Channel local port recieving the LOGO + * @sp: current sequence in the LOGO exchange +@@ -821,6 +871,9 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, + case ELS_RNID: + recv = fc_lport_recv_rnid_req; + break; ++ case ELS_ADISC: ++ recv = fc_lport_recv_adisc_req; ++ break; + } + + if (recv) +diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c +index d081af5..3ea7fc9 100644 +--- a/drivers/scsi/libfc/fc_rport.c ++++ b/drivers/scsi/libfc/fc_rport.c +@@ -333,8 +333,12 @@ int fc_rport_logoff(struct fc_rport *rport) + */ + fc_rport_state_enter(rport, RPORT_ST_NONE); + ++ mutex_unlock(&rdata->rp_mutex); ++ + cancel_delayed_work_sync(&rdata->retry_work); + ++ mutex_lock(&rdata->rp_mutex); ++ + rdata->event = RPORT_EV_STOP; + queue_work(rport_event_queue, &rdata->event_work); + +diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h +index af4bf0c..195ca01 100644 +--- a/include/scsi/fc/fc_els.h ++++ b/include/scsi/fc/fc_els.h +@@ -401,6 +401,20 @@ struct fc_els_prli { + }; + + /* ++ * ELS_ADISC payload ++ */ ++struct fc_els_adisc { ++ __u8 adisc_cmd; ++ __u8 adisc_resv[3]; ++ __u8 adisc_resv1; ++ __u8 adisc_hard_addr[3]; ++ __be64 adisc_wwpn; ++ __be64 adisc_wwnn; ++ __u8 adisc_resv2; ++ __u8 adisc_port_id[3]; ++} __attribute__((__packed__)); ++ ++/* + * ELS_LOGO - process or fabric logout. + */ + struct fc_els_logo { +diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h +index 587be50..a7095cb 100644 +--- a/include/scsi/libfc.h ++++ b/include/scsi/libfc.h +@@ -287,7 +287,6 @@ struct fc_seq { + u8 id; /* seq ID */ + u16 ssb_stat; /* status flags for sequence status block */ + u16 cnt; /* frames sent so far on sequence */ +- u32 f_ctl; /* F_CTL flags for frames */ + u32 rec_data; /* FC-4 value for REC */ + }; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-header-files b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-header-files new file mode 100644 index 000000000..6b5ebac16 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-header-files @@ -0,0 +1,3060 @@ +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:23:43 +0200 +Subject: FC protocol definition header files +References: FATE#303913 + +Signed-off-by: Robert Love +Signed-off-by: Chris Leech +Signed-off-by: Vasu Dev +Signed-off-by: Yi Zou +Signed-off-by: Steve Ma +Signed-off-by: Hannes Reinecke +--- + include/scsi/fc/fc_els.h | 802 +++++++++++++++++++++++++++++++++++++++++ + include/scsi/fc/fc_encaps.h | 138 +++++++ + include/scsi/fc/fc_fc2.h | 124 +++++++ + include/scsi/fc/fc_fcoe.h | 108 ++++++ + include/scsi/fc/fc_fcp.h | 199 ++++++++++ + include/scsi/fc/fc_fs.h | 344 ++++++++++++++++++ + include/scsi/fc/fc_gs.h | 93 +++++ + include/scsi/fc/fc_ns.h | 159 ++++++++ + include/scsi/libfc/fc_frame.h | 236 ++++++++++++ + include/scsi/libfc/libfc.h | 760 ++++++++++++++++++++++++++++++++++++++ + 10 files changed, 2963 insertions(+), 0 deletions(-) + create mode 100644 include/scsi/fc/fc_els.h + create mode 100644 include/scsi/fc/fc_encaps.h + create mode 100644 include/scsi/fc/fc_fc2.h + create mode 100644 include/scsi/fc/fc_fcoe.h + create mode 100644 include/scsi/fc/fc_fcp.h + create mode 100644 include/scsi/fc/fc_fs.h + create mode 100644 include/scsi/fc/fc_gs.h + create mode 100644 include/scsi/fc/fc_ns.h + create mode 100644 include/scsi/libfc/fc_frame.h + create mode 100644 include/scsi/libfc/libfc.h + +diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h +new file mode 100644 +index 0000000..af4bf0c +--- /dev/null ++++ b/include/scsi/fc/fc_els.h +@@ -0,0 +1,802 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_ELS_H_ ++#define _FC_ELS_H_ ++ ++/* ++ * Fibre Channel Switch - Enhanced Link Services definitions. ++ * From T11 FC-LS Rev 1.2 June 7, 2005. ++ */ ++ ++/* ++ * ELS Command codes - byte 0 of the frame payload ++ */ ++enum fc_els_cmd { ++ ELS_LS_RJT = 0x01, /* ESL reject */ ++ ELS_LS_ACC = 0x02, /* ESL Accept */ ++ ELS_PLOGI = 0x03, /* N_Port login */ ++ ELS_FLOGI = 0x04, /* F_Port login */ ++ ELS_LOGO = 0x05, /* Logout */ ++ ELS_ABTX = 0x06, /* Abort exchange - obsolete */ ++ ELS_RCS = 0x07, /* read connection status */ ++ ELS_RES = 0x08, /* read exchange status block */ ++ ELS_RSS = 0x09, /* read sequence status block */ ++ ELS_RSI = 0x0a, /* read sequence initiative */ ++ ELS_ESTS = 0x0b, /* establish streaming */ ++ ELS_ESTC = 0x0c, /* estimate credit */ ++ ELS_ADVC = 0x0d, /* advise credit */ ++ ELS_RTV = 0x0e, /* read timeout value */ ++ ELS_RLS = 0x0f, /* read link error status block */ ++ ELS_ECHO = 0x10, /* echo */ ++ ELS_TEST = 0x11, /* test */ ++ ELS_RRQ = 0x12, /* reinstate recovery qualifier */ ++ ELS_REC = 0x13, /* read exchange concise */ ++ ELS_SRR = 0x14, /* sequence retransmission request */ ++ ELS_PRLI = 0x20, /* process login */ ++ ELS_PRLO = 0x21, /* process logout */ ++ ELS_SCN = 0x22, /* state change notification */ ++ ELS_TPLS = 0x23, /* test process login state */ ++ ELS_TPRLO = 0x24, /* third party process logout */ ++ ELS_LCLM = 0x25, /* login control list mgmt (obs) */ ++ ELS_GAID = 0x30, /* get alias_ID */ ++ ELS_FACT = 0x31, /* fabric activate alias_id */ ++ ELS_FDACDT = 0x32, /* fabric deactivate alias_id */ ++ ELS_NACT = 0x33, /* N-port activate alias_id */ ++ ELS_NDACT = 0x34, /* N-port deactivate alias_id */ ++ ELS_QOSR = 0x40, /* quality of service request */ ++ ELS_RVCS = 0x41, /* read virtual circuit status */ ++ ELS_PDISC = 0x50, /* discover N_port service params */ ++ ELS_FDISC = 0x51, /* discover F_port service params */ ++ ELS_ADISC = 0x52, /* discover address */ ++ ELS_RNC = 0x53, /* report node cap (obs) */ ++ ELS_FARP_REQ = 0x54, /* FC ARP request */ ++ ELS_FARP_REPL = 0x55, /* FC ARP reply */ ++ ELS_RPS = 0x56, /* read port status block */ ++ ELS_RPL = 0x57, /* read port list */ ++ ELS_RPBC = 0x58, /* read port buffer condition */ ++ ELS_FAN = 0x60, /* fabric address notification */ ++ ELS_RSCN = 0x61, /* registered state change notification */ ++ ELS_SCR = 0x62, /* state change registration */ ++ ELS_RNFT = 0x63, /* report node FC-4 types */ ++ ELS_CSR = 0x68, /* clock synch. request */ ++ ELS_CSU = 0x69, /* clock synch. update */ ++ ELS_LINIT = 0x70, /* loop initialize */ ++ ELS_LSTS = 0x72, /* loop status */ ++ ELS_RNID = 0x78, /* request node ID data */ ++ ELS_RLIR = 0x79, /* registered link incident report */ ++ ELS_LIRR = 0x7a, /* link incident record registration */ ++ ELS_SRL = 0x7b, /* scan remote loop */ ++ ELS_SBRP = 0x7c, /* set bit-error reporting params */ ++ ELS_RPSC = 0x7d, /* report speed capabilities */ ++ ELS_QSA = 0x7e, /* query security attributes */ ++ ELS_EVFP = 0x7f, /* exchange virt. fabrics params */ ++ ELS_LKA = 0x80, /* link keep-alive */ ++ ELS_AUTH_ELS = 0x90, /* authentication ELS */ ++}; ++ ++/* ++ * Initializer useful for decoding table. ++ * Please keep this in sync with the above definitions. ++ */ ++#define FC_ELS_CMDS_INIT { \ ++ [ELS_LS_RJT] = "LS_RJT", \ ++ [ELS_LS_ACC] = "LS_ACC", \ ++ [ELS_PLOGI] = "PLOGI", \ ++ [ELS_FLOGI] = "FLOGI", \ ++ [ELS_LOGO] = "LOGO", \ ++ [ELS_ABTX] = "ABTX", \ ++ [ELS_RCS] = "RCS", \ ++ [ELS_RES] = "RES", \ ++ [ELS_RSS] = "RSS", \ ++ [ELS_RSI] = "RSI", \ ++ [ELS_ESTS] = "ESTS", \ ++ [ELS_ESTC] = "ESTC", \ ++ [ELS_ADVC] = "ADVC", \ ++ [ELS_RTV] = "RTV", \ ++ [ELS_RLS] = "RLS", \ ++ [ELS_ECHO] = "ECHO", \ ++ [ELS_TEST] = "TEST", \ ++ [ELS_RRQ] = "RRQ", \ ++ [ELS_REC] = "REC", \ ++ [ELS_SRR] = "SRR", \ ++ [ELS_PRLI] = "PRLI", \ ++ [ELS_PRLO] = "PRLO", \ ++ [ELS_SCN] = "SCN", \ ++ [ELS_TPLS] = "TPLS", \ ++ [ELS_TPRLO] = "TPRLO", \ ++ [ELS_LCLM] = "LCLM", \ ++ [ELS_GAID] = "GAID", \ ++ [ELS_FACT] = "FACT", \ ++ [ELS_FDACDT] = "FDACDT", \ ++ [ELS_NACT] = "NACT", \ ++ [ELS_NDACT] = "NDACT", \ ++ [ELS_QOSR] = "QOSR", \ ++ [ELS_RVCS] = "RVCS", \ ++ [ELS_PDISC] = "PDISC", \ ++ [ELS_FDISC] = "FDISC", \ ++ [ELS_ADISC] = "ADISC", \ ++ [ELS_RNC] = "RNC", \ ++ [ELS_FARP_REQ] = "FARP_REQ", \ ++ [ELS_FARP_REPL] = "FARP_REPL", \ ++ [ELS_RPS] = "RPS", \ ++ [ELS_RPL] = "RPL", \ ++ [ELS_RPBC] = "RPBC", \ ++ [ELS_FAN] = "FAN", \ ++ [ELS_RSCN] = "RSCN", \ ++ [ELS_SCR] = "SCR", \ ++ [ELS_RNFT] = "RNFT", \ ++ [ELS_CSR] = "CSR", \ ++ [ELS_CSU] = "CSU", \ ++ [ELS_LINIT] = "LINIT", \ ++ [ELS_LSTS] = "LSTS", \ ++ [ELS_RNID] = "RNID", \ ++ [ELS_RLIR] = "RLIR", \ ++ [ELS_LIRR] = "LIRR", \ ++ [ELS_SRL] = "SRL", \ ++ [ELS_SBRP] = "SBRP", \ ++ [ELS_RPSC] = "RPSC", \ ++ [ELS_QSA] = "QSA", \ ++ [ELS_EVFP] = "EVFP", \ ++ [ELS_LKA] = "LKA", \ ++ [ELS_AUTH_ELS] = "AUTH_ELS", \ ++} ++ ++/* ++ * LS_ACC payload. ++ */ ++struct fc_els_ls_acc { ++ __u8 la_cmd; /* command code ELS_LS_ACC */ ++ __u8 la_resv[3]; /* reserved */ ++}; ++ ++/* ++ * ELS reject payload. ++ */ ++struct fc_els_ls_rjt { ++ __u8 er_cmd; /* command code ELS_LS_RJT */ ++ __u8 er_resv[4]; /* reserved must be zero */ ++ __u8 er_reason; /* reason (enum fc_els_rjt_reason below) */ ++ __u8 er_explan; /* explanation (enum fc_els_rjt_explan below) */ ++ __u8 er_vendor; /* vendor specific code */ ++}; ++ ++/* ++ * ELS reject reason codes (er_reason). ++ */ ++enum fc_els_rjt_reason { ++ ELS_RJT_NONE = 0, /* no reject - not to be sent */ ++ ELS_RJT_INVAL = 0x01, /* invalid ELS command code */ ++ ELS_RJT_LOGIC = 0x03, /* logical error */ ++ ELS_RJT_BUSY = 0x05, /* logical busy */ ++ ELS_RJT_PROT = 0x07, /* protocol error */ ++ ELS_RJT_UNAB = 0x09, /* unable to perform command request */ ++ ELS_RJT_UNSUP = 0x0b, /* command not supported */ ++ ELS_RJT_INPROG = 0x0e, /* command already in progress */ ++ ELS_RJT_VENDOR = 0xff, /* vendor specific error */ ++}; ++ ++ ++/* ++ * reason code explanation (er_explan). ++ */ ++enum fc_els_rjt_explan { ++ ELS_EXPL_NONE = 0x00, /* No additional explanation */ ++ ELS_EXPL_SPP_OPT_ERR = 0x01, /* service parameter error - options */ ++ ELS_EXPL_SPP_ICTL_ERR = 0x03, /* service parm error - initiator ctl */ ++ ELS_EXPL_AH = 0x11, /* invalid association header */ ++ ELS_EXPL_AH_REQ = 0x13, /* association_header required */ ++ ELS_EXPL_SID = 0x15, /* invalid originator S_ID */ ++ ELS_EXPL_OXID_RXID = 0x17, /* invalid OX_ID-RX_ID combination */ ++ ELS_EXPL_INPROG = 0x19, /* Request already in progress */ ++ ELS_EXPL_PLOGI_REQD = 0x1e, /* N_Port login required */ ++ ELS_EXPL_INSUF_RES = 0x29, /* insufficient resources */ ++ ELS_EXPL_UNAB_DATA = 0x2a, /* unable to supply requested data */ ++ ELS_EXPL_UNSUPR = 0x2c, /* Request not supported */ ++ ELS_EXPL_INV_LEN = 0x2d, /* Invalid payload length */ ++ /* TBD - above definitions incomplete */ ++}; ++ ++/* ++ * Common service parameters (N ports). ++ */ ++struct fc_els_csp { ++ __u8 sp_hi_ver; /* highest version supported (obs.) */ ++ __u8 sp_lo_ver; /* highest version supported (obs.) */ ++ __be16 sp_bb_cred; /* buffer-to-buffer credits */ ++ __be16 sp_features; /* common feature flags */ ++ __be16 sp_bb_data; /* b-b state number and data field sz */ ++ union { ++ struct { ++ __be16 _sp_tot_seq; /* total concurrent sequences */ ++ __be16 _sp_rel_off; /* rel. offset by info cat */ ++ } sp_plogi; ++ struct { ++ __be32 _sp_r_a_tov; /* resource alloc. timeout msec */ ++ } sp_flogi_acc; ++ } sp_u; ++ __be32 sp_e_d_tov; /* error detect timeout value */ ++}; ++#define sp_tot_seq sp_u.sp_plogi._sp_tot_seq ++#define sp_rel_off sp_u.sp_plogi._sp_rel_off ++#define sp_r_a_tov sp_u.sp_flogi_acc._sp_r_a_tov ++ ++#define FC_SP_BB_DATA_MASK 0xfff /* mask for data field size in sp_bb_data */ ++ ++/* ++ * Minimum and maximum values for max data field size in service parameters. ++ */ ++#define FC_SP_MIN_MAX_PAYLOAD FC_MIN_MAX_PAYLOAD ++#define FC_SP_MAX_MAX_PAYLOAD FC_MAX_PAYLOAD ++ ++/* ++ * sp_features ++ */ ++#define FC_SP_FT_CIRO 0x8000 /* continuously increasing rel. off. */ ++#define FC_SP_FT_CLAD 0x8000 /* clean address (in FLOGI LS_ACC) */ ++#define FC_SP_FT_RAND 0x4000 /* random relative offset */ ++#define FC_SP_FT_VAL 0x2000 /* valid vendor version level */ ++#define FC_SP_FT_FPORT 0x1000 /* F port (1) vs. N port (0) */ ++#define FC_SP_FT_ABB 0x0800 /* alternate BB_credit management */ ++#define FC_SP_FT_EDTR 0x0400 /* E_D_TOV Resolution is nanoseconds */ ++#define FC_SP_FT_MCAST 0x0200 /* multicast */ ++#define FC_SP_FT_BCAST 0x0100 /* broadcast */ ++#define FC_SP_FT_HUNT 0x0080 /* hunt group */ ++#define FC_SP_FT_SIMP 0x0040 /* dedicated simplex */ ++#define FC_SP_FT_SEC 0x0020 /* reserved for security */ ++#define FC_SP_FT_CSYN 0x0010 /* clock synch. supported */ ++#define FC_SP_FT_RTTOV 0x0008 /* R_T_TOV value 100 uS, else 100 mS */ ++#define FC_SP_FT_HALF 0x0004 /* dynamic half duplex */ ++#define FC_SP_FT_SEQC 0x0002 /* SEQ_CNT */ ++#define FC_SP_FT_PAYL 0x0001 /* FLOGI payload length 256, else 116 */ ++ ++/* ++ * Class-specific service parameters. ++ */ ++struct fc_els_cssp { ++ __be16 cp_class; /* class flags */ ++ __be16 cp_init; /* initiator flags */ ++ __be16 cp_recip; /* recipient flags */ ++ __be16 cp_rdfs; /* receive data field size */ ++ __be16 cp_con_seq; /* concurrent sequences */ ++ __be16 cp_ee_cred; /* N-port end-to-end credit */ ++ __u8 cp_resv1; /* reserved */ ++ __u8 cp_open_seq; /* open sequences per exchange */ ++ __u8 _cp_resv2[2]; /* reserved */ ++}; ++ ++/* ++ * cp_class flags. ++ */ ++#define FC_CPC_VALID 0x8000 /* class valid */ ++#define FC_CPC_IMIX 0x4000 /* intermix mode */ ++#define FC_CPC_SEQ 0x0800 /* sequential delivery */ ++#define FC_CPC_CAMP 0x0200 /* camp-on */ ++#define FC_CPC_PRI 0x0080 /* priority */ ++ ++/* ++ * cp_init flags. ++ * (TBD: not all flags defined here). ++ */ ++#define FC_CPI_CSYN 0x0010 /* clock synch. capable */ ++ ++/* ++ * cp_recip flags. ++ */ ++#define FC_CPR_CSYN 0x0008 /* clock synch. capable */ ++ ++/* ++ * NFC_ELS_FLOGI: Fabric login request. ++ * NFC_ELS_PLOGI: Port login request (same format). ++ */ ++struct fc_els_flogi { ++ __u8 fl_cmd; /* command */ ++ __u8 _fl_resvd[3]; /* must be zero */ ++ struct fc_els_csp fl_csp; /* common service parameters */ ++ __be64 fl_wwpn; /* port name */ ++ __be64 fl_wwnn; /* node name */ ++ struct fc_els_cssp fl_cssp[4]; /* class 1-4 service parameters */ ++ __u8 fl_vend[16]; /* vendor version level */ ++} __attribute__((__packed__)); ++ ++/* ++ * Process login service parameter page. ++ */ ++struct fc_els_spp { ++ __u8 spp_type; /* type code or common service params */ ++ __u8 spp_type_ext; /* type code extension */ ++ __u8 spp_flags; ++ __u8 _spp_resvd; ++ __be32 spp_orig_pa; /* originator process associator */ ++ __be32 spp_resp_pa; /* responder process associator */ ++ __be32 spp_params; /* service parameters */ ++}; ++ ++/* ++ * spp_flags. ++ */ ++#define FC_SPP_OPA_VAL 0x80 /* originator proc. assoc. valid */ ++#define FC_SPP_RPA_VAL 0x40 /* responder proc. assoc. valid */ ++#define FC_SPP_EST_IMG_PAIR 0x20 /* establish image pair */ ++#define FC_SPP_RESP_MASK 0x0f /* mask for response code (below) */ ++ ++/* ++ * SPP response code in spp_flags - lower 4 bits. ++ */ ++enum fc_els_spp_resp { ++ FC_SPP_RESP_ACK = 1, /* request executed */ ++ FC_SPP_RESP_RES = 2, /* unable due to lack of resources */ ++ FC_SPP_RESP_INIT = 3, /* initialization not complete */ ++ FC_SPP_RESP_NO_PA = 4, /* unknown process associator */ ++ FC_SPP_RESP_CONF = 5, /* configuration precludes image pair */ ++ FC_SPP_RESP_COND = 6, /* request completed conditionally */ ++ FC_SPP_RESP_MULT = 7, /* unable to handle multiple SPPs */ ++ FC_SPP_RESP_INVL = 8, /* SPP is invalid */ ++}; ++ ++/* ++ * ELS_RRQ - Reinstate Recovery Qualifier ++ */ ++struct fc_els_rrq { ++ __u8 rrq_cmd; /* command (0x12) */ ++ __u8 rrq_zero[3]; /* specified as zero - part of cmd */ ++ __u8 rrq_resvd; /* reserved */ ++ __u8 rrq_s_id[3]; /* originator FID */ ++ __be16 rrq_ox_id; /* originator exchange ID */ ++ __be16 rrq_rx_id; /* responders exchange ID */ ++}; ++ ++/* ++ * ELS_REC - Read exchange concise. ++ */ ++struct fc_els_rec { ++ __u8 rec_cmd; /* command (0x13) */ ++ __u8 rec_zero[3]; /* specified as zero - part of cmd */ ++ __u8 rec_resvd; /* reserved */ ++ __u8 rec_s_id[3]; /* originator FID */ ++ __be16 rec_ox_id; /* originator exchange ID */ ++ __be16 rec_rx_id; /* responders exchange ID */ ++}; ++ ++/* ++ * ELS_REC LS_ACC payload. ++ */ ++struct fc_els_rec_acc { ++ __u8 reca_cmd; /* accept (0x02) */ ++ __u8 reca_zero[3]; /* specified as zero - part of cmd */ ++ __be16 reca_ox_id; /* originator exchange ID */ ++ __be16 reca_rx_id; /* responders exchange ID */ ++ __u8 reca_resvd1; /* reserved */ ++ __u8 reca_ofid[3]; /* originator FID */ ++ __u8 reca_resvd2; /* reserved */ ++ __u8 reca_rfid[3]; /* responder FID */ ++ __be32 reca_fc4value; /* FC4 value */ ++ __be32 reca_e_stat; /* ESB (exchange status block) status */ ++}; ++ ++/* ++ * ELS_PRLI - Process login request and response. ++ */ ++struct fc_els_prli { ++ __u8 prli_cmd; /* command */ ++ __u8 prli_spp_len; /* length of each serv. parm. page */ ++ __be16 prli_len; /* length of entire payload */ ++ /* service parameter pages follow */ ++}; ++ ++/* ++ * ELS_LOGO - process or fabric logout. ++ */ ++struct fc_els_logo { ++ __u8 fl_cmd; /* command code */ ++ __u8 fl_zero[3]; /* specified as zero - part of cmd */ ++ __u8 fl_resvd; /* reserved */ ++ __u8 fl_n_port_id[3];/* N port ID */ ++ __be64 fl_n_port_wwn; /* port name */ ++}; ++ ++/* ++ * ELS_RTV - read timeout value. ++ */ ++struct fc_els_rtv { ++ __u8 rtv_cmd; /* command code 0x0e */ ++ __u8 rtv_zero[3]; /* specified as zero - part of cmd */ ++}; ++ ++/* ++ * LS_ACC for ELS_RTV - read timeout value. ++ */ ++struct fc_els_rtv_acc { ++ __u8 rtv_cmd; /* command code 0x02 */ ++ __u8 rtv_zero[3]; /* specified as zero - part of cmd */ ++ __be32 rtv_r_a_tov; /* resource allocation timeout value */ ++ __be32 rtv_e_d_tov; /* error detection timeout value */ ++ __be32 rtv_toq; /* timeout qualifier (see below) */ ++}; ++ ++/* ++ * rtv_toq bits. ++ */ ++#define FC_ELS_RTV_EDRES (1 << 26) /* E_D_TOV resolution is nS else mS */ ++#define FC_ELS_RTV_RTTOV (1 << 19) /* R_T_TOV is 100 uS else 100 mS */ ++ ++/* ++ * ELS_SCR - state change registration payload. ++ */ ++struct fc_els_scr { ++ __u8 scr_cmd; /* command code */ ++ __u8 scr_resv[6]; /* reserved */ ++ __u8 scr_reg_func; /* registration function (see below) */ ++}; ++ ++enum fc_els_scr_func { ++ ELS_SCRF_FAB = 1, /* fabric-detected registration */ ++ ELS_SCRF_NPORT = 2, /* Nx_Port-detected registration */ ++ ELS_SCRF_FULL = 3, /* full registration */ ++ ELS_SCRF_CLEAR = 255, /* remove any current registrations */ ++}; ++ ++/* ++ * ELS_RSCN - registered state change notification payload. ++ */ ++struct fc_els_rscn { ++ __u8 rscn_cmd; /* RSCN opcode (0x61) */ ++ __u8 rscn_page_len; /* page length (4) */ ++ __be16 rscn_plen; /* payload length including this word */ ++ ++ /* followed by 4-byte generic affected Port_ID pages */ ++}; ++ ++struct fc_els_rscn_page { ++ __u8 rscn_page_flags; /* event and address format */ ++ __u8 rscn_fid[3]; /* fabric ID */ ++}; ++ ++#define ELS_RSCN_EV_QUAL_BIT 2 /* shift count for event qualifier */ ++#define ELS_RSCN_EV_QUAL_MASK 0xf /* mask for event qualifier */ ++#define ELS_RSCN_ADDR_FMT_BIT 0 /* shift count for address format */ ++#define ELS_RSCN_ADDR_FMT_MASK 0x3 /* mask for address format */ ++ ++enum fc_els_rscn_ev_qual { ++ ELS_EV_QUAL_NONE = 0, /* unspecified */ ++ ELS_EV_QUAL_NS_OBJ = 1, /* changed name server object */ ++ ELS_EV_QUAL_PORT_ATTR = 2, /* changed port attribute */ ++ ELS_EV_QUAL_SERV_OBJ = 3, /* changed service object */ ++ ELS_EV_QUAL_SW_CONFIG = 4, /* changed switch configuration */ ++ ELS_EV_QUAL_REM_OBJ = 5, /* removed object */ ++}; ++ ++enum fc_els_rscn_addr_fmt { ++ ELS_ADDR_FMT_PORT = 0, /* rscn_fid is a port address */ ++ ELS_ADDR_FMT_AREA = 1, /* rscn_fid is a area address */ ++ ELS_ADDR_FMT_DOM = 2, /* rscn_fid is a domain address */ ++ ELS_ADDR_FMT_FAB = 3, /* anything on fabric may have changed */ ++}; ++ ++/* ++ * ELS_RNID - request Node ID. ++ */ ++struct fc_els_rnid { ++ __u8 rnid_cmd; /* RNID opcode (0x78) */ ++ __u8 rnid_resv[3]; /* reserved */ ++ __u8 rnid_fmt; /* data format */ ++ __u8 rnid_resv2[3]; /* reserved */ ++}; ++ ++/* ++ * Node Identification Data formats (rnid_fmt) ++ */ ++enum fc_els_rnid_fmt { ++ ELS_RNIDF_NONE = 0, /* no specific identification data */ ++ ELS_RNIDF_GEN = 0xdf, /* general topology discovery format */ ++}; ++ ++/* ++ * ELS_RNID response. ++ */ ++struct fc_els_rnid_resp { ++ __u8 rnid_cmd; /* response code (LS_ACC) */ ++ __u8 rnid_resv[3]; /* reserved */ ++ __u8 rnid_fmt; /* data format */ ++ __u8 rnid_cid_len; /* common ID data length */ ++ __u8 rnid_resv2; /* reserved */ ++ __u8 rnid_sid_len; /* specific ID data length */ ++}; ++ ++struct fc_els_rnid_cid { ++ __be64 rnid_wwpn; /* N port name */ ++ __be64 rnid_wwnn; /* node name */ ++}; ++ ++struct fc_els_rnid_gen { ++ __u8 rnid_vend_id[16]; /* vendor-unique ID */ ++ __be32 rnid_atype; /* associated type (see below) */ ++ __be32 rnid_phys_port; /* physical port number */ ++ __be32 rnid_att_nodes; /* number of attached nodes */ ++ __u8 rnid_node_mgmt; /* node management (see below) */ ++ __u8 rnid_ip_ver; /* IP version (see below) */ ++ __be16 rnid_prot_port; /* UDP / TCP port number */ ++ __be32 rnid_ip_addr[4]; /* IP address */ ++ __u8 rnid_resvd[2]; /* reserved */ ++ __be16 rnid_vend_spec; /* vendor-specific field */ ++}; ++ ++enum fc_els_rnid_atype { ++ ELS_RNIDA_UNK = 0x01, /* unknown */ ++ ELS_RNIDA_OTHER = 0x02, /* none of the following */ ++ ELS_RNIDA_HUB = 0x03, ++ ELS_RNIDA_SWITCH = 0x04, ++ ELS_RNIDA_GATEWAY = 0x05, ++ ELS_RNIDA_CONV = 0x06, /* Obsolete, do not use this value */ ++ ELS_RNIDA_HBA = 0x07, /* Obsolete, do not use this value */ ++ ELS_RNIDA_PROXY = 0x08, /* Obsolete, do not use this value */ ++ ELS_RNIDA_STORAGE = 0x09, ++ ELS_RNIDA_HOST = 0x0a, ++ ELS_RNIDA_SUBSYS = 0x0b, /* storage subsystem (e.g., RAID) */ ++ ELS_RNIDA_ACCESS = 0x0e, /* access device (e.g. media changer) */ ++ ELS_RNIDA_NAS = 0x11, /* NAS server */ ++ ELS_RNIDA_BRIDGE = 0x12, /* bridge */ ++ ELS_RNIDA_VIRT = 0x13, /* virtualization device */ ++ ELS_RNIDA_MF = 0xff, /* multifunction device (bits below) */ ++ ELS_RNIDA_MF_HUB = 1UL << 31, /* hub */ ++ ELS_RNIDA_MF_SW = 1UL << 30, /* switch */ ++ ELS_RNIDA_MF_GW = 1UL << 29, /* gateway */ ++ ELS_RNIDA_MF_ST = 1UL << 28, /* storage */ ++ ELS_RNIDA_MF_HOST = 1UL << 27, /* host */ ++ ELS_RNIDA_MF_SUB = 1UL << 26, /* storage subsystem */ ++ ELS_RNIDA_MF_ACC = 1UL << 25, /* storage access dev */ ++ ELS_RNIDA_MF_WDM = 1UL << 24, /* wavelength division mux */ ++ ELS_RNIDA_MF_NAS = 1UL << 23, /* NAS server */ ++ ELS_RNIDA_MF_BR = 1UL << 22, /* bridge */ ++ ELS_RNIDA_MF_VIRT = 1UL << 21, /* virtualization device */ ++}; ++ ++enum fc_els_rnid_mgmt { ++ ELS_RNIDM_SNMP = 0, ++ ELS_RNIDM_TELNET = 1, ++ ELS_RNIDM_HTTP = 2, ++ ELS_RNIDM_HTTPS = 3, ++ ELS_RNIDM_XML = 4, /* HTTP + XML */ ++}; ++ ++enum fc_els_rnid_ipver { ++ ELS_RNIDIP_NONE = 0, /* no IP support or node mgmt. */ ++ ELS_RNIDIP_V4 = 1, /* IPv4 */ ++ ELS_RNIDIP_V6 = 2, /* IPv6 */ ++}; ++ ++/* ++ * ELS RPL - Read Port List. ++ */ ++struct fc_els_rpl { ++ __u8 rpl_cmd; /* command */ ++ __u8 rpl_resv[5]; /* reserved - must be zero */ ++ __be16 rpl_max_size; /* maximum response size or zero */ ++ __u8 rpl_resv1; /* reserved - must be zero */ ++ __u8 rpl_index[3]; /* starting index */ ++}; ++ ++/* ++ * Port number block in RPL response. ++ */ ++struct fc_els_pnb { ++ __be32 pnb_phys_pn; /* physical port number */ ++ __u8 pnb_resv; /* reserved */ ++ __u8 pnb_port_id[3]; /* port ID */ ++ __be64 pnb_wwpn; /* port name */ ++}; ++ ++/* ++ * RPL LS_ACC response. ++ */ ++struct fc_els_rpl_resp { ++ __u8 rpl_cmd; /* ELS_LS_ACC */ ++ __u8 rpl_resv1; /* reserved - must be zero */ ++ __be16 rpl_plen; /* payload length */ ++ __u8 rpl_resv2; /* reserved - must be zero */ ++ __u8 rpl_llen[3]; /* list length */ ++ __u8 rpl_resv3; /* reserved - must be zero */ ++ __u8 rpl_index[3]; /* starting index */ ++ struct fc_els_pnb rpl_pnb[1]; /* variable number of PNBs */ ++}; ++ ++/* ++ * Link Error Status Block. ++ */ ++struct fc_els_lesb { ++ __be32 lesb_link_fail; /* link failure count */ ++ __be32 lesb_sync_loss; /* loss of synchronization count */ ++ __be32 lesb_sig_loss; /* loss of signal count */ ++ __be32 lesb_prim_err; /* primitive sequence error count */ ++ __be32 lesb_inv_word; /* invalid transmission word count */ ++ __be32 lesb_inv_crc; /* invalid CRC count */ ++}; ++ ++/* ++ * ELS RPS - Read Port Status Block request. ++ */ ++struct fc_els_rps { ++ __u8 rps_cmd; /* command */ ++ __u8 rps_resv[2]; /* reserved - must be zero */ ++ __u8 rps_flag; /* flag - see below */ ++ __be64 rps_port_spec; /* port selection */ ++}; ++ ++enum fc_els_rps_flag { ++ FC_ELS_RPS_DID = 0x00, /* port identified by D_ID of req. */ ++ FC_ELS_RPS_PPN = 0x01, /* port_spec is physical port number */ ++ FC_ELS_RPS_WWPN = 0x02, /* port_spec is port WWN */ ++}; ++ ++/* ++ * ELS RPS LS_ACC response. ++ */ ++struct fc_els_rps_resp { ++ __u8 rps_cmd; /* command - LS_ACC */ ++ __u8 rps_resv[2]; /* reserved - must be zero */ ++ __u8 rps_flag; /* flag - see below */ ++ __u8 rps_resv2[2]; /* reserved */ ++ __be16 rps_status; /* port status - see below */ ++ struct fc_els_lesb rps_lesb; /* link error status block */ ++}; ++ ++enum fc_els_rps_resp_flag { ++ FC_ELS_RPS_LPEV = 0x01, /* L_port extension valid */ ++}; ++ ++enum fc_els_rps_resp_status { ++ FC_ELS_RPS_PTP = 1 << 5, /* point-to-point connection */ ++ FC_ELS_RPS_LOOP = 1 << 4, /* loop mode */ ++ FC_ELS_RPS_FAB = 1 << 3, /* fabric present */ ++ FC_ELS_RPS_NO_SIG = 1 << 2, /* loss of signal */ ++ FC_ELS_RPS_NO_SYNC = 1 << 1, /* loss of synchronization */ ++ FC_ELS_RPS_RESET = 1 << 0, /* in link reset protocol */ ++}; ++ ++/* ++ * ELS LIRR - Link Incident Record Registration request. ++ */ ++struct fc_els_lirr { ++ __u8 lirr_cmd; /* command */ ++ __u8 lirr_resv[3]; /* reserved - must be zero */ ++ __u8 lirr_func; /* registration function */ ++ __u8 lirr_fmt; /* FC-4 type of RLIR requested */ ++ __u8 lirr_resv2[2]; /* reserved - must be zero */ ++}; ++ ++enum fc_els_lirr_func { ++ ELS_LIRR_SET_COND = 0x01, /* set - conditionally receive */ ++ ELS_LIRR_SET_UNCOND = 0x02, /* set - unconditionally receive */ ++ ELS_LIRR_CLEAR = 0xff /* clear registration */ ++}; ++ ++/* ++ * ELS SRL - Scan Remote Loop request. ++ */ ++struct fc_els_srl { ++ __u8 srl_cmd; /* command */ ++ __u8 srl_resv[3]; /* reserved - must be zero */ ++ __u8 srl_flag; /* flag - see below */ ++ __u8 srl_flag_param[3]; /* flag parameter */ ++}; ++ ++enum fc_els_srl_flag { ++ FC_ELS_SRL_ALL = 0x00, /* scan all FL ports */ ++ FC_ELS_SRL_ONE = 0x01, /* scan specified loop */ ++ FC_ELS_SRL_EN_PER = 0x02, /* enable periodic scanning (param) */ ++ FC_ELS_SRL_DIS_PER = 0x03, /* disable periodic scanning */ ++}; ++ ++/* ++ * ELS RLS - Read Link Error Status Block request. ++ */ ++struct fc_els_rls { ++ __u8 rls_cmd; /* command */ ++ __u8 rls_resv[4]; /* reserved - must be zero */ ++ __u8 rls_port_id[3]; /* port ID */ ++}; ++ ++/* ++ * ELS RLS LS_ACC Response. ++ */ ++struct fc_els_rls_resp { ++ __u8 rls_cmd; /* ELS_LS_ACC */ ++ __u8 rls_resv[3]; /* reserved - must be zero */ ++ struct fc_els_lesb rls_lesb; /* link error status block */ ++}; ++ ++/* ++ * ELS RLIR - Registered Link Incident Report. ++ * This is followed by the CLIR and the CLID, described below. ++ */ ++struct fc_els_rlir { ++ __u8 rlir_cmd; /* command */ ++ __u8 rlir_resv[3]; /* reserved - must be zero */ ++ __u8 rlir_fmt; /* format (FC4-type if type specific) */ ++ __u8 rlir_clr_len; /* common link incident record length */ ++ __u8 rlir_cld_len; /* common link incident desc. length */ ++ __u8 rlir_slr_len; /* spec. link incident record length */ ++}; ++ ++/* ++ * CLIR - Common Link Incident Record Data. - Sent via RLIR. ++ */ ++struct fc_els_clir { ++ __be64 clir_wwpn; /* incident port name */ ++ __be64 clir_wwnn; /* incident port node name */ ++ __u8 clir_port_type; /* incident port type */ ++ __u8 clir_port_id[3]; /* incident port ID */ ++ ++ __be64 clir_conn_wwpn; /* connected port name */ ++ __be64 clir_conn_wwnn; /* connected node name */ ++ __be64 clir_fab_name; /* fabric name */ ++ __be32 clir_phys_port; /* physical port number */ ++ __be32 clir_trans_id; /* transaction ID */ ++ __u8 clir_resv[3]; /* reserved */ ++ __u8 clir_ts_fmt; /* time stamp format */ ++ __be64 clir_timestamp; /* time stamp */ ++}; ++ ++/* ++ * CLIR clir_ts_fmt - time stamp format values. ++ */ ++enum fc_els_clir_ts_fmt { ++ ELS_CLIR_TS_UNKNOWN = 0, /* time stamp field unknown */ ++ ELS_CLIR_TS_SEC_FRAC = 1, /* time in seconds and fractions */ ++ ELS_CLIR_TS_CSU = 2, /* time in clock synch update format */ ++}; ++ ++/* ++ * Common Link Incident Descriptor - sent via RLIR. ++ */ ++struct fc_els_clid { ++ __u8 clid_iq; /* incident qualifier flags */ ++ __u8 clid_ic; /* incident code */ ++ __be16 clid_epai; /* domain/area of ISL */ ++}; ++ ++/* ++ * CLID incident qualifier flags. ++ */ ++enum fc_els_clid_iq { ++ ELS_CLID_SWITCH = 0x20, /* incident port is a switch node */ ++ ELS_CLID_E_PORT = 0x10, /* incident is an ISL (E) port */ ++ ELS_CLID_SEV_MASK = 0x0c, /* severity 2-bit field mask */ ++ ELS_CLID_SEV_INFO = 0x00, /* report is informational */ ++ ELS_CLID_SEV_INOP = 0x08, /* link not operational */ ++ ELS_CLID_SEV_DEG = 0x04, /* link degraded but operational */ ++ ELS_CLID_LASER = 0x02, /* subassembly is a laser */ ++ ELS_CLID_FRU = 0x01, /* format can identify a FRU */ ++}; ++ ++/* ++ * CLID incident code. ++ */ ++enum fc_els_clid_ic { ++ ELS_CLID_IC_IMPL = 1, /* implicit incident */ ++ ELS_CLID_IC_BER = 2, /* bit-error-rate threshold exceeded */ ++ ELS_CLID_IC_LOS = 3, /* loss of synch or signal */ ++ ELS_CLID_IC_NOS = 4, /* non-operational primitive sequence */ ++ ELS_CLID_IC_PST = 5, /* primitive sequence timeout */ ++ ELS_CLID_IC_INVAL = 6, /* invalid primitive sequence */ ++ ELS_CLID_IC_LOOP_TO = 7, /* loop initialization time out */ ++ ELS_CLID_IC_LIP = 8, /* receiving LIP */ ++}; ++ ++#endif /* _FC_ELS_H_ */ +diff --git a/include/scsi/fc/fc_encaps.h b/include/scsi/fc/fc_encaps.h +new file mode 100644 +index 0000000..f180c3e +--- /dev/null ++++ b/include/scsi/fc/fc_encaps.h +@@ -0,0 +1,138 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++#ifndef _FC_ENCAPS_H_ ++#define _FC_ENCAPS_H_ ++ ++/* ++ * Protocol definitions from RFC 3643 - Fibre Channel Frame Encapsulation. ++ * ++ * Note: The frame length field is the number of 32-bit words in ++ * the encapsulation including the fcip_encaps_header, CRC and EOF words. ++ * The minimum frame length value in bytes is (32 + 24 + 4 + 4) * 4 = 64. ++ * The maximum frame length value in bytes is (32 + 24 + 2112 + 4 + 4) = 2172. ++ */ ++#define FC_ENCAPS_MIN_FRAME_LEN 64 /* min frame len (bytes) (see above) */ ++#define FC_ENCAPS_MAX_FRAME_LEN (FC_ENCAPS_MIN_FRAME_LEN + FC_MAX_PAYLOAD) ++ ++#define FC_ENCAPS_VER 1 /* current version number */ ++ ++struct fc_encaps_hdr { ++ __u8 fc_proto; /* protocol number */ ++ __u8 fc_ver; /* version of encapsulation */ ++ __u8 fc_proto_n; /* ones complement of protocol */ ++ __u8 fc_ver_n; /* ones complement of version */ ++ ++ unsigned char fc_proto_data[8]; /* protocol specific data */ ++ ++ __be16 fc_len_flags; /* 10-bit length/4 w/ 6 flag bits */ ++ __be16 fc_len_flags_n; /* ones complement of length / flags */ ++ ++ /* ++ * Offset 0x10 ++ */ ++ __be32 fc_time[2]; /* time stamp: seconds and fraction */ ++ __be32 fc_crc; /* CRC */ ++ __be32 fc_sof; /* start of frame (see FC_SOF below) */ ++ ++ /* 0x20 - FC frame content followed by EOF word */ ++}; ++ ++#define FCIP_ENCAPS_HDR_LEN 0x20 /* expected length for asserts */ ++ ++/* ++ * Macro's for making redundant copies of EOF and SOF. ++ */ ++#define FC_XY(x, y) ((((x) & 0xff) << 8) | ((y) & 0xff)) ++#define FC_XYXY(x, y) ((FCIP_XY(x, y) << 16) | FCIP_XY(x, y)) ++#define FC_XYNN(x, y) (FCIP_XYXY(x, y) ^ 0xffff) ++ ++#define FC_SOF_ENCODE(n) FC_XYNN(n, n) ++#define FC_EOF_ENCODE(n) FC_XYNN(n, n) ++ ++/* ++ * SOF / EOF bytes. ++ */ ++enum fc_sof { ++ FC_SOF_F = 0x28, /* fabric */ ++ FC_SOF_I4 = 0x29, /* initiate class 4 */ ++ FC_SOF_I2 = 0x2d, /* initiate class 2 */ ++ FC_SOF_I3 = 0x2e, /* initiate class 3 */ ++ FC_SOF_N4 = 0x31, /* normal class 4 */ ++ FC_SOF_N2 = 0x35, /* normal class 2 */ ++ FC_SOF_N3 = 0x36, /* normal class 3 */ ++ FC_SOF_C4 = 0x39, /* activate class 4 */ ++} __attribute__((packed)); ++ ++enum fc_eof { ++ FC_EOF_N = 0x41, /* normal (not last frame of seq) */ ++ FC_EOF_T = 0x42, /* terminate (last frame of sequence) */ ++ FC_EOF_RT = 0x44, ++ FC_EOF_DT = 0x46, /* disconnect-terminate class-1 */ ++ FC_EOF_NI = 0x49, /* normal-invalid */ ++ FC_EOF_DTI = 0x4e, /* disconnect-terminate-invalid */ ++ FC_EOF_RTI = 0x4f, ++ FC_EOF_A = 0x50, /* abort */ ++} __attribute__((packed)); ++ ++#define FC_SOF_CLASS_MASK 0x06 /* mask for class of service in SOF */ ++ ++/* ++ * Define classes in terms of the SOF code (initial). ++ */ ++enum fc_class { ++ FC_CLASS_NONE = 0, /* software value indicating no class */ ++ FC_CLASS_2 = FC_SOF_I2, ++ FC_CLASS_3 = FC_SOF_I3, ++ FC_CLASS_4 = FC_SOF_I4, ++ FC_CLASS_F = FC_SOF_F, ++}; ++ ++/* ++ * Determine whether SOF code indicates the need for a BLS ACK. ++ */ ++static inline int fc_sof_needs_ack(enum fc_sof sof) ++{ ++ return (~sof) & 0x02; /* true for class 1, 2, 4, 6, or F */ ++} ++ ++/* ++ * Given an fc_class, return the normal (non-initial) SOF value. ++ */ ++static inline enum fc_sof fc_sof_normal(enum fc_class class) ++{ ++ return class + FC_SOF_N3 - FC_SOF_I3; /* diff is always 8 */ ++} ++ ++/* ++ * Compute class from SOF value. ++ */ ++static inline enum fc_class fc_sof_class(enum fc_sof sof) ++{ ++ return (sof & 0x7) | FC_SOF_F; ++} ++ ++/* ++ * Determine whether SOF is for the initial frame of a sequence. ++ */ ++static inline int fc_sof_is_init(enum fc_sof sof) ++{ ++ return sof < 0x30; ++} ++ ++#endif /* _FC_ENCAPS_H_ */ +diff --git a/include/scsi/fc/fc_fc2.h b/include/scsi/fc/fc_fc2.h +new file mode 100644 +index 0000000..cff8a8c +--- /dev/null ++++ b/include/scsi/fc/fc_fc2.h +@@ -0,0 +1,124 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_FC2_H_ ++#define _FC_FC2_H_ ++ ++/* ++ * Fibre Channel Exchanges and Sequences. ++ */ ++#ifndef PACKED ++#define PACKED __attribute__ ((__packed__)) ++#endif /* PACKED */ ++ ++ ++/* ++ * Sequence Status Block. ++ * This format is set by the FC-FS standard and is sent over the wire. ++ * Note that the fields aren't all naturally aligned. ++ */ ++struct fc_ssb { ++ __u8 ssb_seq_id; /* sequence ID */ ++ __u8 _ssb_resvd; ++ __be16 ssb_low_seq_cnt; /* lowest SEQ_CNT */ ++ ++ __be16 ssb_high_seq_cnt; /* highest SEQ_CNT */ ++ __be16 ssb_s_stat; /* sequence status flags */ ++ ++ __be16 ssb_err_seq_cnt; /* error SEQ_CNT */ ++ __u8 ssb_fh_cs_ctl; /* frame header CS_CTL */ ++ __be16 ssb_fh_ox_id; /* frame header OX_ID */ ++ __be16 ssb_rx_id; /* responder's exchange ID */ ++ __u8 _ssb_resvd2[2]; ++} PACKED; ++ ++/* ++ * The SSB should be 17 bytes. Since it's layout is somewhat strange, ++ * we define the size here so that code can ASSERT that the size comes out ++ * correct. ++ */ ++#define FC_SSB_SIZE 17 /* length of fc_ssb for assert */ ++ ++/* ++ * ssb_s_stat - flags from FC-FS-2 T11/1619-D Rev 0.90. ++ */ ++#define SSB_ST_RESP (1 << 15) /* sequence responder */ ++#define SSB_ST_ACTIVE (1 << 14) /* sequence is active */ ++#define SSB_ST_ABNORMAL (1 << 12) /* abnormal ending condition */ ++ ++#define SSB_ST_REQ_MASK (3 << 10) /* ACK, abort sequence condition */ ++#define SSB_ST_REQ_CONT (0 << 10) ++#define SSB_ST_REQ_ABORT (1 << 10) ++#define SSB_ST_REQ_STOP (2 << 10) ++#define SSB_ST_REQ_RETRANS (3 << 10) ++ ++#define SSB_ST_ABTS (1 << 9) /* ABTS protocol completed */ ++#define SSB_ST_RETRANS (1 << 8) /* retransmission completed */ ++#define SSB_ST_TIMEOUT (1 << 7) /* sequence timed out by recipient */ ++#define SSB_ST_P_RJT (1 << 6) /* P_RJT transmitted */ ++ ++#define SSB_ST_CLASS_BIT 4 /* class of service field LSB */ ++#define SSB_ST_CLASS_MASK 3 /* class of service mask */ ++#define SSB_ST_ACK (1 << 3) /* ACK (EOFt or EOFdt) transmitted */ ++ ++/* ++ * Exchange Status Block. ++ * This format is set by the FC-FS standard and is sent over the wire. ++ * Note that the fields aren't all naturally aligned. ++ */ ++struct fc_esb { ++ __u8 esb_cs_ctl; /* CS_CTL for frame header */ ++ __be16 esb_ox_id; /* originator exchange ID */ ++ __be16 esb_rx_id; /* responder exchange ID */ ++ __be32 esb_orig_fid; /* fabric ID of originator */ ++ __be32 esb_resp_fid; /* fabric ID of responder */ ++ __be32 esb_e_stat; /* status */ ++ __u8 _esb_resvd[4]; ++ __u8 esb_service_params[112]; /* TBD */ ++ __u8 esb_seq_status[8]; /* sequence statuses, 8 bytes each */ ++} __attribute__((packed));; ++ ++ ++/* ++ * Define expected size for ASSERTs. ++ * See comments on FC_SSB_SIZE. ++ */ ++#define FC_ESB_SIZE (1 + 5*4 + 112 + 8) /* expected size */ ++ ++/* ++ * esb_e_stat - flags from FC-FS-2 T11/1619-D Rev 0.90. ++ */ ++#define ESB_ST_RESP (1 << 31) /* responder to exchange */ ++#define ESB_ST_SEQ_INIT (1 << 30) /* port holds sequence initiaive */ ++#define ESB_ST_COMPLETE (1 << 29) /* exchange is complete */ ++#define ESB_ST_ABNORMAL (1 << 28) /* abnormal ending condition */ ++#define ESB_ST_REC_QUAL (1 << 26) /* recovery qualifier active */ ++ ++#define ESB_ST_ERRP_BIT 24 /* LSB for error policy */ ++#define ESB_ST_ERRP_MASK (3 << 24) /* mask for error policy */ ++#define ESB_ST_ERRP_MULT (0 << 24) /* abort, discard multiple sequences */ ++#define ESB_ST_ERRP_SING (1 << 24) /* abort, discard single sequence */ ++#define ESB_ST_ERRP_INF (2 << 24) /* process with infinite buffers */ ++#define ESB_ST_ERRP_IMM (3 << 24) /* discard mult. with immed. retran. */ ++ ++#define ESB_ST_OX_ID_INVL (1 << 23) /* originator XID invalid */ ++#define ESB_ST_RX_ID_INVL (1 << 22) /* responder XID invalid */ ++#define ESB_ST_PRI_INUSE (1 << 21) /* priority / preemption in use */ ++ ++#endif /* _FC_FC2_H_ */ +diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h +new file mode 100644 +index 0000000..b2e07ec +--- /dev/null ++++ b/include/scsi/fc/fc_fcoe.h +@@ -0,0 +1,108 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_FCOE_H_ ++#define _FC_FCOE_H_ ++ ++/* ++ * FCoE - Fibre Channel over Ethernet. ++ */ ++ ++/* ++ * The FCoE ethertype eventually goes in net/if_ether.h. ++ */ ++#ifndef ETH_P_FCOE ++#define ETH_P_FCOE 0x8906 /* FCOE ether type */ ++#endif ++ ++/* ++ * FC_FCOE_OUI hasn't been standardized yet. XXX TBD. ++ */ ++#ifndef FC_FCOE_OUI ++#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE dest MAC TBD */ ++#endif ++ ++/* ++ * The destination MAC address for the fabric login may get a different OUI. ++ * This isn't standardized yet. ++ */ ++#ifndef FC_FCOE_FLOGI_MAC ++/* gateway MAC - TBD */ ++#define FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe } ++#endif ++ ++#define FC_FCOE_VER 0 /* version */ ++ ++/* ++ * Ethernet Addresses based on FC S_ID and D_ID. ++ * Generated by FC_FCOE_OUI | S_ID/D_ID ++ */ ++#define FC_FCOE_ENCAPS_ID(n) (((u64) FC_FCOE_OUI << 24) | (n)) ++#define FC_FCOE_DECAPS_ID(n) ((n) >> 24) ++ ++/* ++ * FCoE frame header - 14 bytes ++ * ++ * This is the August 2007 version of the FCoE header as defined by T11. ++ * This follows the VLAN header, which includes the ethertype. ++ */ ++struct fcoe_hdr { ++ __u8 fcoe_ver; /* version field - upper 4 bits */ ++ __u8 fcoe_resvd[12]; /* reserved - send zero and ignore */ ++ __u8 fcoe_sof; /* start of frame per RFC 3643 */ ++}; ++ ++#define FC_FCOE_DECAPS_VER(hp) ((hp)->fcoe_ver >> 4) ++#define FC_FCOE_ENCAPS_VER(hp, ver) ((hp)->fcoe_ver = (ver) << 4) ++ ++/* ++ * FCoE CRC & EOF - 8 bytes. ++ */ ++struct fcoe_crc_eof { ++ __le32 fcoe_crc32; /* CRC for FC packet */ ++ __u8 fcoe_eof; /* EOF from RFC 3643 */ ++ __u8 fcoe_resvd[3]; /* reserved - send zero and ignore */ ++} __attribute__((packed)); ++ ++/* ++ * Store OUI + DID into MAC address field. ++ */ ++static inline void fc_fcoe_set_mac(u8 *mac, u8 *did) ++{ ++ mac[0] = (u8) (FC_FCOE_OUI >> 16); ++ mac[1] = (u8) (FC_FCOE_OUI >> 8); ++ mac[2] = (u8) FC_FCOE_OUI; ++ mac[3] = did[0]; ++ mac[4] = did[1]; ++ mac[5] = did[2]; ++} ++ ++/* ++ * VLAN header. This is also defined in linux/if_vlan.h, but for kernels only. ++ */ ++struct fcoe_vlan_hdr { ++ __be16 vlan_tag; /* VLAN tag including priority */ ++ __be16 vlan_ethertype; /* encapsulated ethertype ETH_P_FCOE */ ++}; ++ ++#ifndef ETH_P_8021Q ++#define ETH_P_8021Q 0x8100 ++#endif ++ ++#endif /* _FC_FCOE_H_ */ +diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h +new file mode 100644 +index 0000000..5d38f19 +--- /dev/null ++++ b/include/scsi/fc/fc_fcp.h +@@ -0,0 +1,199 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_FCP_H_ ++#define _FC_FCP_H_ ++ ++/* ++ * Fibre Channel Protocol for SCSI. ++ * From T10 FCP-3, T10 project 1560-D Rev 4, Sept. 13, 2005. ++ */ ++ ++/* ++ * fc/fs.h defines FC_TYPE_FCP. ++ */ ++ ++/* ++ * Service parameter page parameters (word 3 bits) for Process Login. ++ */ ++#define FCP_SPPF_TASK_RETRY_ID 0x0200 /* task retry ID requested */ ++#define FCP_SPPF_RETRY 0x0100 /* retry supported */ ++#define FCP_SPPF_CONF_COMPL 0x0080 /* confirmed completion allowed */ ++#define FCP_SPPF_OVLY_ALLOW 0x0040 /* data overlay allowed */ ++#define FCP_SPPF_INIT_FCN 0x0020 /* initiator function */ ++#define FCP_SPPF_TARG_FCN 0x0010 /* target function */ ++#define FCP_SPPF_RD_XRDY_DIS 0x0002 /* disable XFER_RDY for reads */ ++#define FCP_SPPF_WR_XRDY_DIS 0x0001 /* disable XFER_RDY for writes */ ++ ++/* ++ * FCP_CMND IU Payload. ++ */ ++struct fcp_cmnd { ++ __u8 fc_lun[8]; /* logical unit number */ ++ __u8 fc_cmdref; /* commmand reference number */ ++ __u8 fc_pri_ta; /* priority and task attribute */ ++ __u8 fc_tm_flags; /* task management flags */ ++ __u8 fc_flags; /* additional len & flags */ ++ __u8 fc_cdb[16]; /* base CDB */ ++ __be32 fc_dl; /* data length (must follow fc_cdb) */ ++}; ++ ++#define FCP_CMND_LEN 32 /* expected length of structure */ ++ ++struct fcp_cmnd32 { ++ __u8 fc_lun[8]; /* logical unit number */ ++ __u8 fc_cmdref; /* commmand reference number */ ++ __u8 fc_pri_ta; /* priority and task attribute */ ++ __u8 fc_tm_flags; /* task management flags */ ++ __u8 fc_flags; /* additional len & flags */ ++ __u8 fc_cdb[32]; /* base CDB */ ++ __be32 fc_dl; /* data length (must follow fc_cdb) */ ++}; ++ ++#define FCP_CMND32_LEN 48 /* expected length of structure */ ++#define FCP_CMND32_ADD_LEN (16 / 4) /* Additional cdb length */ ++ ++/* ++ * fc_pri_ta. ++ */ ++#define FCP_PTA_SIMPLE 0 /* simple task attribute */ ++#define FCP_PTA_HEADQ 1 /* head of queue task attribute */ ++#define FCP_PTA_ORDERED 2 /* ordered task attribute */ ++#define FCP_PTA_ACA 4 /* auto. contigent allegiance */ ++#define FCP_PRI_SHIFT 3 /* priority field starts in bit 3 */ ++#define FCP_PRI_RESVD_MASK 0x80 /* reserved bits in priority field */ ++ ++/* ++ * fc_tm_flags - task management flags field. ++ */ ++#define FCP_TMF_CLR_ACA 0x40 /* clear ACA condition */ ++#define FCP_TMF_LUN_RESET 0x10 /* logical unit reset task management */ ++#define FCP_TMF_CLR_TASK_SET 0x04 /* clear task set */ ++#define FCP_TMF_ABT_TASK_SET 0x02 /* abort task set */ ++ ++/* ++ * fc_flags. ++ * Bits 7:2 are the additional FCP_CDB length / 4. ++ */ ++#define FCP_CFL_LEN_MASK 0xfc /* mask for additional length */ ++#define FCP_CFL_LEN_SHIFT 2 /* shift bits for additional length */ ++#define FCP_CFL_RDDATA 0x02 /* read data */ ++#define FCP_CFL_WRDATA 0x01 /* write data */ ++ ++/* ++ * FCP_TXRDY IU - transfer ready payload. ++ */ ++struct fcp_txrdy { ++ __be32 ft_data_ro; /* data relative offset */ ++ __be32 ft_burst_len; /* burst length */ ++ __u8 _ft_resvd[4]; /* reserved */ ++}; ++ ++#define FCP_TXRDY_LEN 12 /* expected length of structure */ ++ ++/* ++ * FCP_RESP IU - response payload. ++ * ++ * The response payload comes in three parts: the flags/status, the ++ * sense/response lengths and the sense data/response info section. ++ * ++ * From FCP3r04, note 6 of section 9.5.13: ++ * ++ * Some early implementations presented the FCP_RSP IU without the FCP_RESID, ++ * FCP_SNS_LEN, and FCP_RSP_LEN fields if the FCP_RESID_UNDER, FCP_RESID_OVER, ++ * FCP_SNS_LEN_VALID, and FCP_RSP_LEN_VALID bits were all set to zero. This ++ * non-standard behavior should be tolerated. ++ * ++ * All response frames will always contain the fcp_resp template. Some ++ * will also include the fcp_resp_len template. ++ */ ++struct fcp_resp { ++ __u8 _fr_resvd[8]; /* reserved */ ++ __be16 fr_retry_delay; /* retry delay timer */ ++ __u8 fr_flags; /* flags */ ++ __u8 fr_status; /* SCSI status code */ ++}; ++ ++#define FCP_RESP_LEN 12 /* expected length of structure */ ++ ++struct fcp_resp_ext { ++ __be32 fr_resid; /* Residual value */ ++ __be32 fr_sns_len; /* SCSI Sense length */ ++ __be32 fr_rsp_len; /* Response Info length */ ++ ++ /* ++ * Optionally followed by RSP info and/or SNS info and/or ++ * bidirectional read residual length, if any. ++ */ ++}; ++ ++#define FCP_RESP_EXT_LEN 12 /* expected length of the structure */ ++ ++struct fcp_resp_rsp_info { ++ __u8 _fr_resvd[3]; /* reserved */ ++ __u8 rsp_code; /* Response Info Code */ ++ __u8 _fr_resvd2[4]; /* reserved */ ++}; ++ ++struct fcp_resp_with_ext { ++ struct fcp_resp resp; ++ struct fcp_resp_ext ext; ++}; ++ ++#define FCP_RESP_WITH_EXT (FCP_RESP_LEN + FCP_RESP_EXT_LEN) ++ ++/* ++ * fr_flags. ++ */ ++#define FCP_BIDI_RSP 0x80 /* bidirectional read response */ ++#define FCP_BIDI_READ_UNDER 0x40 /* bidir. read less than requested */ ++#define FCP_BIDI_READ_OVER 0x20 /* DL insufficient for full transfer */ ++#define FCP_CONF_REQ 0x10 /* confirmation requested */ ++#define FCP_RESID_UNDER 0x08 /* transfer shorter than expected */ ++#define FCP_RESID_OVER 0x04 /* DL insufficient for full transfer */ ++#define FCP_SNS_LEN_VAL 0x02 /* SNS_LEN field is valid */ ++#define FCP_RSP_LEN_VAL 0x01 /* RSP_LEN field is valid */ ++ ++/* ++ * rsp_codes ++ */ ++enum fcp_resp_rsp_codes { ++ FCP_TMF_CMPL = 0, ++ FCP_DATA_LEN_INVALID = 1, ++ FCP_CMND_FIELDS_INVALID = 2, ++ FCP_DATA_PARAM_MISMATCH = 3, ++ FCP_TMF_REJECTED = 4, ++ FCP_TMF_FAILED = 5, ++ FCP_TMF_INVALID_LUN = 9, ++}; ++ ++/* ++ * FCP SRR Link Service request - Sequence Retransmission Request. ++ */ ++struct fcp_srr { ++ __u8 srr_op; /* opcode ELS_SRR */ ++ __u8 srr_resvd[3]; /* opcode / reserved - must be zero */ ++ __be16 srr_ox_id; /* OX_ID of failed command */ ++ __be16 srr_rx_id; /* RX_ID of failed command */ ++ __be32 srr_rel_off; /* relative offset */ ++ __u8 srr_r_ctl; /* r_ctl for the information unit */ ++ __u8 srr_resvd2[3]; /* reserved */ ++}; ++ ++#endif /* _FC_FCP_H_ */ +diff --git a/include/scsi/fc/fc_fs.h b/include/scsi/fc/fc_fs.h +new file mode 100644 +index 0000000..ba6df64 +--- /dev/null ++++ b/include/scsi/fc/fc_fs.h +@@ -0,0 +1,344 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_FS_H_ ++#define _FC_FS_H_ ++ ++/* ++ * Fibre Channel Framing and Signalling definitions. ++ * From T11 FC-FS-2 Rev 0.90 - 9 August 2005. ++ */ ++ ++/* ++ * Frame header ++ */ ++struct fc_frame_header { ++ __u8 fh_r_ctl; /* routing control */ ++ __u8 fh_d_id[3]; /* Destination ID */ ++ ++ __u8 fh_cs_ctl; /* class of service control / pri */ ++ __u8 fh_s_id[3]; /* Source ID */ ++ ++ __u8 fh_type; /* see enum fc_fh_type below */ ++ __u8 fh_f_ctl[3]; /* frame control */ ++ ++ __u8 fh_seq_id; /* sequence ID */ ++ __u8 fh_df_ctl; /* data field control */ ++ __be16 fh_seq_cnt; /* sequence count */ ++ ++ __be16 fh_ox_id; /* originator exchange ID */ ++ __be16 fh_rx_id; /* responder exchange ID */ ++ __be32 fh_parm_offset; /* parameter or relative offset */ ++}; ++ ++#define FC_FRAME_HEADER_LEN 24 /* expected length of structure */ ++ ++#define FC_MAX_PAYLOAD 2112U /* max payload length in bytes */ ++#define FC_MIN_MAX_PAYLOAD 256U /* lower limit on max payload */ ++ ++#define FC_MAX_FRAME (FC_MAX_PAYLOAD + FC_FRAME_HEADER_LEN) ++#define FC_MIN_MAX_FRAME (FC_MIN_MAX_PAYLOAD + FC_FRAME_HEADER_LEN) ++ ++/* ++ * fh_r_ctl - Routing control definitions. ++ */ ++ /* ++ * FC-4 device_data. ++ */ ++enum fc_rctl { ++ FC_RCTL_DD_UNCAT = 0x00, /* uncategorized information */ ++ FC_RCTL_DD_SOL_DATA = 0x01, /* solicited data */ ++ FC_RCTL_DD_UNSOL_CTL = 0x02, /* unsolicited control */ ++ FC_RCTL_DD_SOL_CTL = 0x03, /* solicited control or reply */ ++ FC_RCTL_DD_UNSOL_DATA = 0x04, /* unsolicited data */ ++ FC_RCTL_DD_DATA_DESC = 0x05, /* data descriptor */ ++ FC_RCTL_DD_UNSOL_CMD = 0x06, /* unsolicited command */ ++ FC_RCTL_DD_CMD_STATUS = 0x07, /* command status */ ++ ++#define FC_RCTL_ILS_REQ FC_RCTL_DD_UNSOL_CTL /* ILS request */ ++#define FC_RCTL_ILS_REP FC_RCTL_DD_SOL_CTL /* ILS reply */ ++ ++ /* ++ * Extended Link_Data ++ */ ++ FC_RCTL_ELS_REQ = 0x22, /* extended link services request */ ++ FC_RCTL_ELS_REP = 0x23, /* extended link services reply */ ++ FC_RCTL_ELS4_REQ = 0x32, /* FC-4 ELS request */ ++ FC_RCTL_ELS4_REP = 0x33, /* FC-4 ELS reply */ ++ /* ++ * Basic Link Services fh_r_ctl values. ++ */ ++ FC_RCTL_BA_NOP = 0x80, /* basic link service NOP */ ++ FC_RCTL_BA_ABTS = 0x81, /* basic link service abort */ ++ FC_RCTL_BA_RMC = 0x82, /* remove connection */ ++ FC_RCTL_BA_ACC = 0x84, /* basic accept */ ++ FC_RCTL_BA_RJT = 0x85, /* basic reject */ ++ FC_RCTL_BA_PRMT = 0x86, /* dedicated connection preempted */ ++ /* ++ * Link Control Information. ++ */ ++ FC_RCTL_ACK_1 = 0xc0, /* acknowledge_1 */ ++ FC_RCTL_ACK_0 = 0xc1, /* acknowledge_0 */ ++ FC_RCTL_P_RJT = 0xc2, /* port reject */ ++ FC_RCTL_F_RJT = 0xc3, /* fabric reject */ ++ FC_RCTL_P_BSY = 0xc4, /* port busy */ ++ FC_RCTL_F_BSY = 0xc5, /* fabric busy to data frame */ ++ FC_RCTL_F_BSYL = 0xc6, /* fabric busy to link control frame */ ++ FC_RCTL_LCR = 0xc7, /* link credit reset */ ++ FC_RCTL_END = 0xc9, /* end */ ++}; ++ /* incomplete list of definitions */ ++ ++/* ++ * R_CTL names initializer. ++ * Please keep this matching the above definitions. ++ */ ++#define FC_RCTL_NAMES_INIT { \ ++ [FC_RCTL_DD_UNCAT] = "uncat", \ ++ [FC_RCTL_DD_SOL_DATA] = "sol data", \ ++ [FC_RCTL_DD_UNSOL_CTL] = "unsol ctl", \ ++ [FC_RCTL_DD_SOL_CTL] = "sol ctl/reply", \ ++ [FC_RCTL_DD_UNSOL_DATA] = "unsol data", \ ++ [FC_RCTL_DD_DATA_DESC] = "data desc", \ ++ [FC_RCTL_DD_UNSOL_CMD] = "unsol cmd", \ ++ [FC_RCTL_DD_CMD_STATUS] = "cmd status", \ ++ [FC_RCTL_ELS_REQ] = "ELS req", \ ++ [FC_RCTL_ELS_REP] = "ELS rep", \ ++ [FC_RCTL_ELS4_REQ] = "FC-4 ELS req", \ ++ [FC_RCTL_ELS4_REP] = "FC-4 ELS rep", \ ++ [FC_RCTL_BA_NOP] = "BLS NOP", \ ++ [FC_RCTL_BA_ABTS] = "BLS abort", \ ++ [FC_RCTL_BA_RMC] = "BLS remove connection", \ ++ [FC_RCTL_BA_ACC] = "BLS accept", \ ++ [FC_RCTL_BA_RJT] = "BLS reject", \ ++ [FC_RCTL_BA_PRMT] = "BLS dedicated connection preempted", \ ++ [FC_RCTL_ACK_1] = "LC ACK_1", \ ++ [FC_RCTL_ACK_0] = "LC ACK_0", \ ++ [FC_RCTL_P_RJT] = "LC port reject", \ ++ [FC_RCTL_F_RJT] = "LC fabric reject", \ ++ [FC_RCTL_P_BSY] = "LC port busy", \ ++ [FC_RCTL_F_BSY] = "LC fabric busy to data frame", \ ++ [FC_RCTL_F_BSYL] = "LC fabric busy to link control frame",\ ++ [FC_RCTL_LCR] = "LC link credit reset", \ ++ [FC_RCTL_END] = "LC end", \ ++} ++ ++/* ++ * Well-known fabric addresses. ++ */ ++enum fc_well_known_fid { ++ FC_FID_BCAST = 0xffffff, /* broadcast */ ++ FC_FID_FLOGI = 0xfffffe, /* fabric login */ ++ FC_FID_FCTRL = 0xfffffd, /* fabric controller */ ++ FC_FID_DIR_SERV = 0xfffffc, /* directory server */ ++ FC_FID_TIME_SERV = 0xfffffb, /* time server */ ++ FC_FID_MGMT_SERV = 0xfffffa, /* management server */ ++ FC_FID_QOS = 0xfffff9, /* QoS Facilitator */ ++ FC_FID_ALIASES = 0xfffff8, /* alias server (FC-PH2) */ ++ FC_FID_SEC_KEY = 0xfffff7, /* Security key dist. server */ ++ FC_FID_CLOCK = 0xfffff6, /* clock synch server */ ++ FC_FID_MCAST_SERV = 0xfffff5, /* multicast server */ ++}; ++ ++#define FC_FID_WELL_KNOWN_MAX 0xffffff /* highest well-known fabric ID */ ++#define FC_FID_WELL_KNOWN_BASE 0xfffff5 /* start of well-known fabric ID */ ++ ++/* ++ * Other well-known addresses, outside the above contiguous range. ++ */ ++#define FC_FID_DOM_MGR 0xfffc00 /* domain manager base */ ++ ++/* ++ * Fabric ID bytes. ++ */ ++#define FC_FID_DOMAIN 0 ++#define FC_FID_PORT 1 ++#define FC_FID_LINK 2 ++ ++/* ++ * fh_type codes ++ */ ++enum fc_fh_type { ++ FC_TYPE_BLS = 0x00, /* basic link service */ ++ FC_TYPE_ELS = 0x01, /* extended link service */ ++ FC_TYPE_IP = 0x05, /* IP over FC, RFC 4338 */ ++ FC_TYPE_FCP = 0x08, /* SCSI FCP */ ++ FC_TYPE_CT = 0x20, /* Fibre Channel Services (FC-CT) */ ++ FC_TYPE_ILS = 0x22, /* internal link service */ ++}; ++ ++/* ++ * FC_TYPE names initializer. ++ * Please keep this matching the above definitions. ++ */ ++#define FC_TYPE_NAMES_INIT { \ ++ [FC_TYPE_BLS] = "BLS", \ ++ [FC_TYPE_ELS] = "ELS", \ ++ [FC_TYPE_IP] = "IP", \ ++ [FC_TYPE_FCP] = "FCP", \ ++ [FC_TYPE_CT] = "CT", \ ++ [FC_TYPE_ILS] = "ILS", \ ++} ++ ++/* ++ * Exchange IDs. ++ */ ++#define FC_XID_UNKNOWN 0xffff /* unknown exchange ID */ ++ ++/* ++ * fh_f_ctl - Frame control flags. ++ */ ++#define FC_FC_EX_CTX (1 << 23) /* sent by responder to exchange */ ++#define FC_FC_SEQ_CTX (1 << 22) /* sent by responder to sequence */ ++#define FC_FC_FIRST_SEQ (1 << 21) /* first sequence of this exchange */ ++#define FC_FC_LAST_SEQ (1 << 20) /* last sequence of this exchange */ ++#define FC_FC_END_SEQ (1 << 19) /* last frame of sequence */ ++#define FC_FC_END_CONN (1 << 18) /* end of class 1 connection pending */ ++#define FC_FC_RES_B17 (1 << 17) /* reserved */ ++#define FC_FC_SEQ_INIT (1 << 16) /* transfer of sequence initiative */ ++#define FC_FC_X_ID_REASS (1 << 15) /* exchange ID has been changed */ ++#define FC_FC_X_ID_INVAL (1 << 14) /* exchange ID invalidated */ ++ ++#define FC_FC_ACK_1 (1 << 12) /* 13:12 = 1: ACK_1 expected */ ++#define FC_FC_ACK_N (2 << 12) /* 13:12 = 2: ACK_N expected */ ++#define FC_FC_ACK_0 (3 << 12) /* 13:12 = 3: ACK_0 expected */ ++ ++#define FC_FC_RES_B11 (1 << 11) /* reserved */ ++#define FC_FC_RES_B10 (1 << 10) /* reserved */ ++#define FC_FC_RETX_SEQ (1 << 9) /* retransmitted sequence */ ++#define FC_FC_UNI_TX (1 << 8) /* unidirectional transmit (class 1) */ ++#define FC_FC_CONT_SEQ(i) ((i) << 6) ++#define FC_FC_ABT_SEQ(i) ((i) << 4) ++#define FC_FC_REL_OFF (1 << 3) /* parameter is relative offset */ ++#define FC_FC_RES2 (1 << 2) /* reserved */ ++#define FC_FC_FILL(i) ((i) & 3) /* 1:0: bytes of trailing fill */ ++ ++/* ++ * BA_ACC payload. ++ */ ++struct fc_ba_acc { ++ __u8 ba_seq_id_val; /* SEQ_ID validity */ ++#define FC_BA_SEQ_ID_VAL 0x80 ++ __u8 ba_seq_id; /* SEQ_ID of seq last deliverable */ ++ __u8 ba_resvd[2]; /* reserved */ ++ __be16 ba_ox_id; /* OX_ID for aborted seq or exch */ ++ __be16 ba_rx_id; /* RX_ID for aborted seq or exch */ ++ __be16 ba_low_seq_cnt; /* low SEQ_CNT of aborted seq */ ++ __be16 ba_high_seq_cnt; /* high SEQ_CNT of aborted seq */ ++}; ++ ++/* ++ * BA_RJT: Basic Reject payload. ++ */ ++struct fc_ba_rjt { ++ __u8 br_resvd; /* reserved */ ++ __u8 br_reason; /* reason code */ ++ __u8 br_explan; /* reason explanation */ ++ __u8 br_vendor; /* vendor unique code */ ++}; ++ ++/* ++ * BA_RJT reason codes. ++ * From FS-2. ++ */ ++enum fc_ba_rjt_reason { ++ FC_BA_RJT_NONE = 0, /* in software this means no reject */ ++ FC_BA_RJT_INVL_CMD = 0x01, /* invalid command code */ ++ FC_BA_RJT_LOG_ERR = 0x03, /* logical error */ ++ FC_BA_RJT_LOG_BUSY = 0x05, /* logical busy */ ++ FC_BA_RJT_PROTO_ERR = 0x07, /* protocol error */ ++ FC_BA_RJT_UNABLE = 0x09, /* unable to perform request */ ++ FC_BA_RJT_VENDOR = 0xff, /* vendor-specific (see br_vendor) */ ++}; ++ ++/* ++ * BA_RJT reason code explanations. ++ */ ++enum fc_ba_rjt_explan { ++ FC_BA_RJT_EXP_NONE = 0x00, /* no additional expanation */ ++ FC_BA_RJT_INV_XID = 0x03, /* invalid OX_ID-RX_ID combination */ ++ FC_BA_RJT_ABT = 0x05, /* sequence aborted, no seq info */ ++}; ++ ++/* ++ * P_RJT or F_RJT: Port Reject or Fabric Reject parameter field. ++ */ ++struct fc_pf_rjt { ++ __u8 rj_action; /* reserved */ ++ __u8 rj_reason; /* reason code */ ++ __u8 rj_resvd; /* reserved */ ++ __u8 rj_vendor; /* vendor unique code */ ++}; ++ ++/* ++ * P_RJT and F_RJT reject reason codes. ++ */ ++enum fc_pf_rjt_reason { ++ FC_RJT_NONE = 0, /* non-reject (reserved by standard) */ ++ FC_RJT_INVL_DID = 0x01, /* invalid destination ID */ ++ FC_RJT_INVL_SID = 0x02, /* invalid source ID */ ++ FC_RJT_P_UNAV_T = 0x03, /* port unavailable, temporary */ ++ FC_RJT_P_UNAV = 0x04, /* port unavailable, permanent */ ++ FC_RJT_CLS_UNSUP = 0x05, /* class not supported */ ++ FC_RJT_DEL_USAGE = 0x06, /* delimiter usage error */ ++ FC_RJT_TYPE_UNSUP = 0x07, /* type not supported */ ++ FC_RJT_LINK_CTL = 0x08, /* invalid link control */ ++ FC_RJT_R_CTL = 0x09, /* invalid R_CTL field */ ++ FC_RJT_F_CTL = 0x0a, /* invalid F_CTL field */ ++ FC_RJT_OX_ID = 0x0b, /* invalid originator exchange ID */ ++ FC_RJT_RX_ID = 0x0c, /* invalid responder exchange ID */ ++ FC_RJT_SEQ_ID = 0x0d, /* invalid sequence ID */ ++ FC_RJT_DF_CTL = 0x0e, /* invalid DF_CTL field */ ++ FC_RJT_SEQ_CNT = 0x0f, /* invalid SEQ_CNT field */ ++ FC_RJT_PARAM = 0x10, /* invalid parameter field */ ++ FC_RJT_EXCH_ERR = 0x11, /* exchange error */ ++ FC_RJT_PROTO = 0x12, /* protocol error */ ++ FC_RJT_LEN = 0x13, /* incorrect length */ ++ FC_RJT_UNEXP_ACK = 0x14, /* unexpected ACK */ ++ FC_RJT_FAB_CLASS = 0x15, /* class unsupported by fabric entity */ ++ FC_RJT_LOGI_REQ = 0x16, /* login required */ ++ FC_RJT_SEQ_XS = 0x17, /* excessive sequences attempted */ ++ FC_RJT_EXCH_EST = 0x18, /* unable to establish exchange */ ++ FC_RJT_FAB_UNAV = 0x1a, /* fabric unavailable */ ++ FC_RJT_VC_ID = 0x1b, /* invalid VC_ID (class 4) */ ++ FC_RJT_CS_CTL = 0x1c, /* invalid CS_CTL field */ ++ FC_RJT_INSUF_RES = 0x1d, /* insuff. resources for VC (Class 4) */ ++ FC_RJT_INVL_CLS = 0x1f, /* invalid class of service */ ++ FC_RJT_PREEMT_RJT = 0x20, /* preemption request rejected */ ++ FC_RJT_PREEMT_DIS = 0x21, /* preemption not enabled */ ++ FC_RJT_MCAST_ERR = 0x22, /* multicast error */ ++ FC_RJT_MCAST_ET = 0x23, /* multicast error terminate */ ++ FC_RJT_PRLI_REQ = 0x24, /* process login required */ ++ FC_RJT_INVL_ATT = 0x25, /* invalid attachment */ ++ FC_RJT_VENDOR = 0xff, /* vendor specific reject */ ++}; ++ ++/* ++ * Data descriptor format (R_CTL == FC_RCTL_DD_DATA_DESC). ++ * This is used for FCP SCSI transfer ready. ++ */ ++struct fc_data_desc { ++ __be32 dd_offset; /* data relative offset in bytes */ ++ __be32 dd_len; /* transfer buffer size in bytes */ ++ __u8 _dd_resvd[4]; ++}; ++ ++#define FC_DATA_DESC_LEN 12 /* expected length of structure */ ++ ++#endif /* _FC_FS_H_ */ +diff --git a/include/scsi/fc/fc_gs.h b/include/scsi/fc/fc_gs.h +new file mode 100644 +index 0000000..ffab027 +--- /dev/null ++++ b/include/scsi/fc/fc_gs.h +@@ -0,0 +1,93 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_GS_H_ ++#define _FC_GS_H_ ++ ++/* ++ * Fibre Channel Services - Common Transport. ++ * From T11.org FC-GS-2 Rev 5.3 November 1998. ++ */ ++ ++struct fc_ct_hdr { ++ __u8 ct_rev; /* revision */ ++ __u8 ct_in_id[3]; /* N_Port ID of original requestor */ ++ __u8 ct_fs_type; /* type of fibre channel service */ ++ __u8 ct_fs_subtype; /* subtype */ ++ __u8 ct_options; ++ __u8 _ct_resvd1; ++ __be16 ct_cmd; /* command / response code */ ++ __be16 ct_mr_size; /* maximum / residual size */ ++ __u8 _ct_resvd2; ++ __u8 ct_reason; /* reject reason */ ++ __u8 ct_explan; /* reason code explanation */ ++ __u8 ct_vendor; /* vendor unique data */ ++}; ++ ++#define FC_CT_HDR_LEN 16 /* expected sizeof (struct fc_ct_hdr) */ ++ ++enum fc_ct_rev { ++ FC_CT_REV = 1 /* common transport revision */ ++}; ++ ++/* ++ * ct_fs_type values. ++ */ ++enum fc_ct_fs_type { ++ FC_FST_ALIAS = 0xf8, /* alias service */ ++ FC_FST_MGMT = 0xfa, /* management service */ ++ FC_FST_TIME = 0xfb, /* time service */ ++ FC_FST_DIR = 0xfc, /* directory service */ ++}; ++ ++/* ++ * ct_cmd: Command / response codes ++ */ ++enum fc_ct_cmd { ++ FC_FS_RJT = 0x8001, /* reject */ ++ FC_FS_ACC = 0x8002, /* accept */ ++}; ++ ++/* ++ * FS_RJT reason codes. ++ */ ++enum fc_ct_reason { ++ FC_FS_RJT_CMD = 0x01, /* invalid command code */ ++ FC_FS_RJT_VER = 0x02, /* invalid version level */ ++ FC_FS_RJT_LOG = 0x03, /* logical error */ ++ FC_FS_RJT_IUSIZ = 0x04, /* invalid IU size */ ++ FC_FS_RJT_BSY = 0x05, /* logical busy */ ++ FC_FS_RJT_PROTO = 0x07, /* protocol error */ ++ FC_FS_RJT_UNABL = 0x09, /* unable to perform command request */ ++ FC_FS_RJT_UNSUP = 0x0b, /* command not supported */ ++}; ++ ++/* ++ * FS_RJT reason code explanations. ++ */ ++enum fc_ct_explan { ++ FC_FS_EXP_NONE = 0x00, /* no additional explanation */ ++ FC_FS_EXP_PID = 0x01, /* port ID not registered */ ++ FC_FS_EXP_PNAM = 0x02, /* port name not registered */ ++ FC_FS_EXP_NNAM = 0x03, /* node name not registered */ ++ FC_FS_EXP_COS = 0x04, /* class of service not registered */ ++ /* definitions not complete */ ++}; ++ ++#endif /* _FC_GS_H_ */ +diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h +new file mode 100644 +index 0000000..790d7b9 +--- /dev/null ++++ b/include/scsi/fc/fc_ns.h +@@ -0,0 +1,159 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_NS_H_ ++#define _FC_NS_H_ ++ ++/* ++ * Fibre Channel Services - Name Service (dNS) ++ * From T11.org FC-GS-2 Rev 5.3 November 1998. ++ */ ++ ++/* ++ * Common-transport sub-type for Name Server. ++ */ ++#define FC_NS_SUBTYPE 2 /* fs_ct_hdr.ct_fs_subtype */ ++ ++/* ++ * Name server Requests. ++ * Note: this is an incomplete list, some unused requests are omitted. ++ */ ++enum fc_ns_req { ++ FC_NS_GA_NXT = 0x0100, /* get all next */ ++ FC_NS_GI_A = 0x0101, /* get identifiers - scope */ ++ FC_NS_GPN_ID = 0x0112, /* get port name by ID */ ++ FC_NS_GNN_ID = 0x0113, /* get node name by ID */ ++ FC_NS_GID_PN = 0x0121, /* get ID for port name */ ++ FC_NS_GID_NN = 0x0131, /* get IDs for node name */ ++ FC_NS_GID_FT = 0x0171, /* get IDs by FC4 type */ ++ FC_NS_GPN_FT = 0x0172, /* get port names by FC4 type */ ++ FC_NS_GID_PT = 0x01a1, /* get IDs by port type */ ++ FC_NS_RFT_ID = 0x0217, /* reg FC4 type for ID */ ++ FC_NS_RPN_ID = 0x0212, /* reg port name for ID */ ++ FC_NS_RNN_ID = 0x0213, /* reg node name for ID */ ++}; ++ ++/* ++ * Port type values. ++ */ ++enum fc_ns_pt { ++ FC_NS_UNID_PORT = 0x00, /* unidentified */ ++ FC_NS_N_PORT = 0x01, /* N port */ ++ FC_NS_NL_PORT = 0x02, /* NL port */ ++ FC_NS_FNL_PORT = 0x03, /* F/NL port */ ++ FC_NS_NX_PORT = 0x7f, /* Nx port */ ++ FC_NS_F_PORT = 0x81, /* F port */ ++ FC_NS_FL_PORT = 0x82, /* FL port */ ++ FC_NS_E_PORT = 0x84, /* E port */ ++ FC_NS_B_PORT = 0x85, /* B port */ ++}; ++ ++/* ++ * Port type object. ++ */ ++struct fc_ns_pt_obj { ++ __u8 pt_type; ++}; ++ ++/* ++ * Port ID object ++ */ ++struct fc_ns_fid { ++ __u8 fp_flags; /* flags for responses only */ ++ __u8 fp_fid[3]; ++}; ++ ++/* ++ * fp_flags in port ID object, for responses only. ++ */ ++#define FC_NS_FID_LAST 0x80 /* last object */ ++ ++/* ++ * FC4-types object. ++ */ ++#define FC_NS_TYPES 256 /* number of possible FC-4 types */ ++#define FC_NS_BPW 32 /* bits per word in bitmap */ ++ ++struct fc_ns_fts { ++ __be32 ff_type_map[FC_NS_TYPES / FC_NS_BPW]; /* bitmap of FC-4 types */ ++}; ++ ++/* ++ * GID_PT request. ++ */ ++struct fc_ns_gid_pt { ++ __u8 fn_pt_type; ++ __u8 fn_domain_id_scope; ++ __u8 fn_area_id_scope; ++ __u8 fn_resvd; ++}; ++ ++/* ++ * GID_FT or GPN_FT request. ++ */ ++struct fc_ns_gid_ft { ++ __u8 fn_resvd; ++ __u8 fn_domain_id_scope; ++ __u8 fn_area_id_scope; ++ __u8 fn_fc4_type; ++}; ++ ++/* ++ * GPN_FT response. ++ */ ++struct fc_gpn_ft_resp { ++ __u8 fp_flags; /* see fp_flags definitions above */ ++ __u8 fp_fid[3]; /* port ID */ ++ __be32 fp_resvd; ++ __be64 fp_wwpn; /* port name */ ++}; ++ ++/* ++ * GID_PN request ++ */ ++struct fc_ns_gid_pn { ++ __be64 fn_wwpn; /* port name */ ++}; ++ ++/* ++ * GID_PN response ++ */ ++struct fc_gid_pn_resp { ++ __u8 fp_resvd; ++ __u8 fp_fid[3]; /* port ID */ ++}; ++ ++/* ++ * RFT_ID request - register FC-4 types for ID. ++ */ ++struct fc_ns_rft_id { ++ struct fc_ns_fid fr_fid; /* port ID object */ ++ struct fc_ns_fts fr_fts; /* FC-4 types object */ ++}; ++ ++/* ++ * RPN_ID request - register port name for ID. ++ * RNN_ID request - register node name for ID. ++ */ ++struct fc_ns_rn_id { ++ struct fc_ns_fid fr_fid; /* port ID object */ ++ __be64 fr_wwn; /* node name or port name */ ++} __attribute__((__packed__)); ++ ++#endif /* _FC_NS_H_ */ +diff --git a/include/scsi/libfc/fc_frame.h b/include/scsi/libfc/fc_frame.h +new file mode 100644 +index 0000000..c7a52bb +--- /dev/null ++++ b/include/scsi/libfc/fc_frame.h +@@ -0,0 +1,236 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _FC_FRAME_H_ ++#define _FC_FRAME_H_ ++ ++#include ++#include ++ ++#include ++#include ++ ++/* ++ * The fc_frame interface is used to pass frame data between functions. ++ * The frame includes the data buffer, length, and SOF / EOF delimiter types. ++ * A pointer to the port structure of the receiving port is also includeded. ++ */ ++ ++#define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */ ++#define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */ ++ ++/* ++ * Information about an individual fibre channel frame received or to be sent. ++ * The buffer may be in up to 4 additional non-contiguous sections, ++ * but the linear section must hold the frame header. ++ */ ++#define FC_FRAME_SG_LEN 4 /* scatter/gather list maximum length */ ++ ++#define fp_skb(fp) (&((fp)->skb)) ++#define fr_hdr(fp) ((fp)->skb.data) ++#define fr_len(fp) ((fp)->skb.len) ++#define fr_cb(fp) ((struct fcoe_rcv_info *)&((fp)->skb.cb[0])) ++#define fr_dev(fp) (fr_cb(fp)->fr_dev) ++#define fr_seq(fp) (fr_cb(fp)->fr_seq) ++#define fr_sof(fp) (fr_cb(fp)->fr_sof) ++#define fr_eof(fp) (fr_cb(fp)->fr_eof) ++#define fr_flags(fp) (fr_cb(fp)->fr_flags) ++ ++struct fc_frame { ++ struct sk_buff skb; ++}; ++ ++struct fcoe_rcv_info { ++ struct packet_type *ptype; ++ struct fc_lport *fr_dev; /* transport layer private pointer */ ++ struct fc_seq *fr_seq; /* for use with exchange manager */ ++ enum fc_sof fr_sof; /* start of frame delimiter */ ++ enum fc_eof fr_eof; /* end of frame delimiter */ ++ u8 fr_flags; /* flags - see below */ ++}; ++ ++/* ++ * Get fc_frame pointer for an skb that's already been imported. ++ */ ++static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb) ++{ ++ BUILD_BUG_ON(sizeof(struct fcoe_rcv_info) > sizeof(skb->cb)); ++ return (struct fcoe_rcv_info *) skb->cb; ++} ++ ++/* ++ * fr_flags. ++ */ ++#define FCPHF_CRC_UNCHECKED 0x01 /* CRC not computed, still appended */ ++ ++/* ++ * Initialize a frame. ++ * We don't do a complete memset here for performance reasons. ++ * The caller must set fr_free, fr_hdr, fr_len, fr_sof, and fr_eof eventually. ++ */ ++static inline void fc_frame_init(struct fc_frame *fp) ++{ ++ fr_dev(fp) = NULL; ++ fr_seq(fp) = NULL; ++ fr_flags(fp) = 0; ++} ++ ++struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len); ++ ++struct fc_frame *__fc_frame_alloc(size_t payload_len); ++ ++/* ++ * Get frame for sending via port. ++ */ ++static inline struct fc_frame *_fc_frame_alloc(struct fc_lport *dev, ++ size_t payload_len) ++{ ++ return __fc_frame_alloc(payload_len); ++} ++ ++/* ++ * Allocate fc_frame structure and buffer. Set the initial length to ++ * payload_size + sizeof (struct fc_frame_header). ++ */ ++static inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len) ++{ ++ struct fc_frame *fp; ++ ++ /* ++ * Note: Since len will often be a constant multiple of 4, ++ * this check will usually be evaluated and eliminated at compile time. ++ */ ++ if ((len % 4) != 0) ++ fp = fc_frame_alloc_fill(dev, len); ++ else ++ fp = _fc_frame_alloc(dev, len); ++ return fp; ++} ++ ++/* ++ * Free the fc_frame structure and buffer. ++ */ ++static inline void fc_frame_free(struct fc_frame *fp) ++{ ++ kfree_skb(fp_skb(fp)); ++} ++ ++static inline int fc_frame_is_linear(struct fc_frame *fp) ++{ ++ return !skb_is_nonlinear(fp_skb(fp)); ++} ++ ++/* ++ * Get frame header from message in fc_frame structure. ++ * This hides a cast and provides a place to add some checking. ++ */ ++static inline ++struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp) ++{ ++ WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header)); ++ return (struct fc_frame_header *) fr_hdr(fp); ++} ++ ++/* ++ * Get frame payload from message in fc_frame structure. ++ * This hides a cast and provides a place to add some checking. ++ * The len parameter is the minimum length for the payload portion. ++ * Returns NULL if the frame is too short. ++ * ++ * This assumes the interesting part of the payload is in the first part ++ * of the buffer for received data. This may not be appropriate to use for ++ * buffers being transmitted. ++ */ ++static inline void *fc_frame_payload_get(const struct fc_frame *fp, ++ size_t len) ++{ ++ void *pp = NULL; ++ ++ if (fr_len(fp) >= sizeof(struct fc_frame_header) + len) ++ pp = fc_frame_header_get(fp) + 1; ++ return pp; ++} ++ ++/* ++ * Get frame payload opcode (first byte) from message in fc_frame structure. ++ * This hides a cast and provides a place to add some checking. Return 0 ++ * if the frame has no payload. ++ */ ++static inline u8 fc_frame_payload_op(const struct fc_frame *fp) ++{ ++ u8 *cp; ++ ++ cp = fc_frame_payload_get(fp, sizeof(u8)); ++ if (!cp) ++ return 0; ++ return *cp; ++ ++} ++ ++/* ++ * Get FC class from frame. ++ */ ++static inline enum fc_class fc_frame_class(const struct fc_frame *fp) ++{ ++ return fc_sof_class(fr_sof(fp)); ++} ++ ++/* ++ * Set r_ctl and type in preparation for sending frame. ++ * This also clears fh_parm_offset. ++ */ ++static inline void fc_frame_setup(struct fc_frame *fp, enum fc_rctl r_ctl, ++ enum fc_fh_type type) ++{ ++ struct fc_frame_header *fh; ++ ++ fh = fc_frame_header_get(fp); ++ WARN_ON(r_ctl == 0); ++ fh->fh_r_ctl = r_ctl; ++ fh->fh_type = type; ++ fh->fh_parm_offset = htonl(0); ++} ++ ++/* ++ * Set offset in preparation for sending frame. ++ */ ++static inline void ++fc_frame_set_offset(struct fc_frame *fp, u32 offset) ++{ ++ struct fc_frame_header *fh; ++ ++ fh = fc_frame_header_get(fp); ++ fh->fh_parm_offset = htonl(offset); ++} ++ ++/* ++ * Check the CRC in a frame. ++ * The CRC immediately follows the last data item *AFTER* the length. ++ * The return value is zero if the CRC matches. ++ */ ++u32 fc_frame_crc_check(struct fc_frame *); ++ ++/* ++ * Check for leaks. ++ * Print the frame header of any currently allocated frame, assuming there ++ * should be none at this point. ++ */ ++void fc_frame_leak_check(void); ++ ++#endif /* _FC_FRAME_H_ */ +diff --git a/include/scsi/libfc/libfc.h b/include/scsi/libfc/libfc.h +new file mode 100644 +index 0000000..b139aed +--- /dev/null ++++ b/include/scsi/libfc/libfc.h +@@ -0,0 +1,760 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#ifndef _LIBFC_H_ ++#define _LIBFC_H_ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#define LIBFC_DEBUG ++ ++#ifdef LIBFC_DEBUG ++/* ++ * Log message. ++ */ ++#define FC_DBG(fmt, args...) \ ++ do { \ ++ printk(KERN_INFO "%s " fmt, __func__, ##args); \ ++ } while (0) ++#else ++#define FC_DBG(fmt, args...) ++#endif ++ ++/* ++ * libfc error codes ++ */ ++#define FC_NO_ERR 0 /* no error */ ++#define FC_EX_TIMEOUT 1 /* Exchange timeout */ ++#define FC_EX_CLOSED 2 /* Exchange closed */ ++ ++/* some helpful macros */ ++ ++#define ntohll(x) be64_to_cpu(x) ++#define htonll(x) cpu_to_be64(x) ++ ++#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2])) ++ ++#define hton24(p, v) do { \ ++ p[0] = (((v) >> 16) & 0xFF); \ ++ p[1] = (((v) >> 8) & 0xFF); \ ++ p[2] = ((v) & 0xFF); \ ++} while (0) ++ ++struct fc_exch_mgr; ++ ++/* ++ * tgt_flags ++ */ ++#define FC_TGT_REC_SUPPORTED (1 << 0) ++ ++/* ++ * FC HBA status ++ */ ++#define FC_PAUSE (1 << 1) ++#define FC_LINK_UP (1 << 0) ++ ++/* for fc_softc */ ++#define FC_MAX_OUTSTANDING_COMMANDS 1024 ++ ++/* ++ * Transport Capabilities ++ */ ++#define TRANS_C_SG (1 << 0) /* Scatter gather */ ++ ++enum fc_lport_state { ++ LPORT_ST_NONE = 0, ++ LPORT_ST_FLOGI, ++ LPORT_ST_DNS, ++ LPORT_ST_REG_PN, ++ LPORT_ST_REG_FT, ++ LPORT_ST_SCR, ++ LPORT_ST_READY, ++ LPORT_ST_DNS_STOP, ++ LPORT_ST_LOGO, ++ LPORT_ST_RESET ++}; ++ ++enum fc_rport_state { ++ RPORT_ST_NONE = 0, ++ RPORT_ST_INIT, /* initialized */ ++ RPORT_ST_STARTED, /* started */ ++ RPORT_ST_PLOGI, /* waiting for PLOGI completion */ ++ RPORT_ST_PLOGI_RECV, /* received PLOGI (as target) */ ++ RPORT_ST_PRLI, /* waiting for PRLI completion */ ++ RPORT_ST_RTV, /* waiting for RTV completion */ ++ RPORT_ST_ERROR, /* error */ ++ RPORT_ST_READY, /* ready for use */ ++ RPORT_ST_LOGO, /* port logout sent */ ++}; ++ ++/** ++ * struct fc_rport_libfc_priv - libfc internal information about a remote port ++ * @local_port: Fibre Channel host port instance ++ * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges ++ * @flags: REC and RETRY supported flags ++ * @max_seq: maximum number of concurrent sequences ++ * @retries: retry count in current state ++ * @e_d_tov: error detect timeout value (in msec) ++ * @r_a_tov: resource allocation timeout value (in msec) ++ * @rp_lock: lock protects state ++ * @retry_work: ++ */ ++struct fc_rport_libfc_priv { ++ struct fc_lport *local_port; ++ enum fc_rport_state rp_state; ++ u16 flags; ++ #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) ++ #define FC_RP_FLAGS_RETRY (1 << 1) ++ u16 max_seq; ++ unsigned int retries; ++ unsigned int e_d_tov; ++ unsigned int r_a_tov; ++ spinlock_t rp_lock; ++ struct delayed_work retry_work; ++}; ++ ++static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) ++{ ++ rport->node_name = wwnn; ++ rport->port_name = wwpn; ++} ++ ++/* ++ * fcoe stats structure ++ */ ++struct fcoe_dev_stats { ++ u64 SecondsSinceLastReset; ++ u64 TxFrames; ++ u64 TxWords; ++ u64 RxFrames; ++ u64 RxWords; ++ u64 ErrorFrames; ++ u64 DumpedFrames; ++ u64 LinkFailureCount; ++ u64 LossOfSignalCount; ++ u64 InvalidTxWordCount; ++ u64 InvalidCRCCount; ++ u64 InputRequests; ++ u64 OutputRequests; ++ u64 ControlRequests; ++ u64 InputMegabytes; ++ u64 OutputMegabytes; ++}; ++ ++/* ++ * els data is used for passing ELS respone specific ++ * data to send ELS response mainly using infomation ++ * in exchange and sequence in EM layer. ++ */ ++struct fc_seq_els_data { ++ struct fc_frame *fp; ++ enum fc_els_rjt_reason reason; ++ enum fc_els_rjt_explan explan; ++}; ++ ++struct libfc_function_template { ++ ++ /** ++ * Mandatory Fields ++ * ++ * These handlers must be implemented by the LLD. ++ */ ++ ++ /* ++ * Interface to send a FC frame ++ */ ++ int (*frame_send)(struct fc_lport *lp, struct fc_frame *fp); ++ ++ /** ++ * Optional Fields ++ * ++ * The LLD may choose to implement any of the following handlers. ++ * If LLD doesn't specify hander and leaves its pointer NULL then ++ * the default libfc function will be used for that handler. ++ */ ++ ++ /** ++ * Exhance Manager interfaces ++ */ ++ ++ /* ++ * Send the FC frame payload using a new exchange and sequence. ++ * ++ * The frame pointer with some of the header's fields must be ++ * filled before calling exch_seq_send(), those fields are, ++ * ++ * - routing control ++ * - FC header type ++ * - parameter or relative offset ++ * ++ * The exchange response handler is set in this routine to resp() ++ * function pointer. It can be called in two scenarios: if a timeout ++ * occurs or if a response frame is received for the exchange. The ++ * fc_frame pointer in response handler will also indicate timeout ++ * as error using IS_ERR related macros. ++ * ++ * The response handler argumemt resp_arg is passed back to resp ++ * handler when it is invoked by EM layer in above mentioned ++ * two scenarios. ++ * ++ * The timeout value (in msec) for an exchange is set if non zero ++ * timer_msec argument is specified. The timer is canceled when ++ * it fires or when the exchange is done. The exchange timeout handler ++ * is registered by EM layer. ++ * ++ * The caller also need to specify FC sid, did and frame control field. ++ */ ++ struct fc_seq *(*exch_seq_send)(struct fc_lport *lp, ++ struct fc_frame *fp, ++ void (*resp)(struct fc_seq *, ++ struct fc_frame *fp, ++ void *arg), ++ void *resp_arg, unsigned int timer_msec, ++ u32 sid, u32 did, u32 f_ctl); ++ ++ /* ++ * send a frame using existing sequence and exchange. ++ */ ++ int (*seq_send)(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp, u32 f_ctl); ++ ++ /* ++ * Send ELS response using mainly infomation ++ * in exchange and sequence in EM layer. ++ */ ++ void (*seq_els_rsp_send)(struct fc_seq *sp, enum fc_els_cmd els_cmd, ++ struct fc_seq_els_data *els_data); ++ ++ /* ++ * Abort an exchange and sequence. Generally called because of a ++ * exchange timeout or an abort from the upper layer. ++ * ++ * A timer_msec can be specified for abort timeout, if non-zero ++ * timer_msec value is specified then exchange resp handler ++ * will be called with timeout error if no response to abort. ++ */ ++ int (*seq_exch_abort)(const struct fc_seq *req_sp, ++ unsigned int timer_msec); ++ ++ /* ++ * Indicate that an exchange/sequence tuple is complete and the memory ++ * allocated for the related objects may be freed. ++ */ ++ void (*exch_done)(struct fc_seq *sp); ++ ++ /* ++ * Assigns a EM and a free XID for an new exchange and then ++ * allocates a new exchange and sequence pair. ++ * The fp can be used to determine free XID. ++ */ ++ struct fc_exch *(*exch_get)(struct fc_lport *lp, struct fc_frame *fp); ++ ++ /* ++ * Release previously assigned XID by exch_get API. ++ * The LLD may implement this if XID is assigned by LLD ++ * in exch_get(). ++ */ ++ void (*exch_put)(struct fc_lport *lp, struct fc_exch_mgr *mp, ++ u16 ex_id); ++ ++ /* ++ * Start a new sequence on the same exchange/sequence tuple. ++ */ ++ struct fc_seq *(*seq_start_next)(struct fc_seq *sp); ++ ++ /* ++ * Reset an exchange manager, completing all sequences and exchanges. ++ * If s_id is non-zero, reset only exchanges originating from that FID. ++ * If d_id is non-zero, reset only exchanges sending to that FID. ++ */ ++ void (*exch_mgr_reset)(struct fc_exch_mgr *, ++ u32 s_id, u32 d_id); ++ ++ /* ++ * Get exchange Ids of a sequence ++ */ ++ void (*seq_get_xids)(struct fc_seq *sp, u16 *oxid, u16 *rxid); ++ ++ /* ++ * Set REC data to a sequence ++ */ ++ void (*seq_set_rec_data)(struct fc_seq *sp, u32 rec_data); ++ ++ /** ++ * Local Port interfaces ++ */ ++ ++ /* ++ * Receive a frame to a local port. ++ */ ++ void (*lport_recv)(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp); ++ ++ int (*lport_login)(struct fc_lport *); ++ int (*lport_reset)(struct fc_lport *); ++ int (*lport_logout)(struct fc_lport *); ++ ++ /** ++ * Remote Port interfaces ++ */ ++ ++ /* ++ * Initiates the RP state machine. It is called from the LP module. ++ * This function will issue the following commands to the N_Port ++ * identified by the FC ID provided. ++ * ++ * - PLOGI ++ * - PRLI ++ * - RTV ++ */ ++ int (*rport_login)(struct fc_rport *rport); ++ ++ /* ++ * Logs the specified local port out of a N_Port identified ++ * by the ID provided. ++ */ ++ int (*rport_logout)(struct fc_rport *rport); ++ ++ void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, ++ struct fc_rport *); ++ ++ struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32); ++ ++ struct fc_rport *(*rport_create)(struct fc_lport *, ++ struct fc_rport_identifiers *); ++ ++ void (*rport_reset)(struct fc_rport *); ++ ++ void (*rport_reset_list)(struct fc_lport *); ++ ++ /** ++ * SCSI interfaces ++ */ ++ ++ /* ++ * Used at least durring linkdown and reset ++ */ ++ void (*scsi_cleanup)(struct fc_lport *); ++ ++ /* ++ * Abort all I/O on a local port ++ */ ++ void (*scsi_abort_io)(struct fc_lport *); ++ ++ /** ++ * Discovery interfaces ++ */ ++ ++ void (*disc_recv_req)(struct fc_seq *, ++ struct fc_frame *, struct fc_lport *); ++ ++ /* ++ * Start discovery for a local port. ++ */ ++ int (*disc_start)(struct fc_lport *); ++ ++ void (*dns_register)(struct fc_lport *); ++ void (*disc_stop)(struct fc_lport *); ++}; ++ ++struct fc_lport { ++ struct list_head list; ++ ++ /* Associations */ ++ struct Scsi_Host *host; ++ struct fc_exch_mgr *emp; ++ struct fc_rport *dns_rp; ++ struct fc_rport *ptp_rp; ++ void *scsi_priv; ++ ++ /* Operational Information */ ++ struct libfc_function_template tt; ++ u16 link_status; ++ u8 ns_disc_done; ++ enum fc_lport_state state; ++ unsigned long boot_time; ++ ++ struct fc_host_statistics host_stats; ++ struct fcoe_dev_stats *dev_stats[NR_CPUS]; ++ ++ u64 wwpn; ++ u64 wwnn; ++ u32 fid; ++ u8 retry_count; ++ unsigned char ns_disc_retry_count; ++ unsigned char ns_disc_delay; ++ unsigned char ns_disc_pending; ++ unsigned char ns_disc_requested; ++ unsigned short ns_disc_seq_count; ++ unsigned char ns_disc_buf_len; ++ ++ /* Capabilities */ ++ char ifname[IFNAMSIZ]; ++ u32 capabilities; ++ u32 mfs; /* max FC payload size */ ++ unsigned int service_params; ++ unsigned int e_d_tov; ++ unsigned int r_a_tov; ++ u8 max_retry_count; ++ u16 link_speed; ++ u16 link_supported_speeds; ++ struct fc_ns_fts fcts; /* FC-4 type masks */ ++ struct fc_els_rnid_gen rnid_gen; /* RNID information */ ++ ++ /* Locks */ ++ spinlock_t state_lock; /* serializes state changes */ ++ ++ /* Miscellaneous */ ++ struct fc_gpn_ft_resp ns_disc_buf; /* partial name buffer */ ++ struct timer_list state_timer; /* timer for state events */ ++ struct delayed_work ns_disc_work; ++ ++ void *drv_priv; ++}; ++ ++/** ++ * FC_LPORT HELPER FUNCTIONS ++ *****************************/ ++ ++static inline int fc_lport_test_ready(struct fc_lport *lp) ++{ ++ return lp->state == LPORT_ST_READY; ++} ++ ++static inline u32 fc_lport_get_fid(const struct fc_lport *lp) ++{ ++ return lp->fid; ++} ++ ++static inline void fc_set_wwnn(struct fc_lport *lp, u64 wwnn) ++{ ++ lp->wwnn = wwnn; ++} ++ ++static inline void fc_set_wwpn(struct fc_lport *lp, u64 wwnn) ++{ ++ lp->wwpn = wwnn; ++} ++ ++static inline int fc_lport_locked(struct fc_lport *lp) ++{ ++#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) ++ return spin_is_locked(&lp->state_lock); ++#else ++ return 1; ++#endif /* CONFIG_SMP || CONFIG_DEBUG_SPINLOCK */ ++} ++ ++/* ++ * Locking code. ++ */ ++static inline void fc_lport_lock(struct fc_lport *lp) ++{ ++ spin_lock_bh(&lp->state_lock); ++} ++ ++static inline void fc_lport_unlock(struct fc_lport *lp) ++{ ++ spin_unlock_bh(&lp->state_lock); ++} ++ ++static inline void fc_lport_state_enter(struct fc_lport *lp, ++ enum fc_lport_state state) ++{ ++ WARN_ON(!fc_lport_locked(lp)); ++ del_timer(&lp->state_timer); ++ if (state != lp->state) ++ lp->retry_count = 0; ++ lp->state = state; ++} ++ ++ ++/** ++ * LOCAL PORT LAYER ++ *****************************/ ++int fc_lport_init(struct fc_lport *lp); ++ ++/* ++ * Destroy the specified local port by finding and freeing all ++ * fc_rports associated with it and then by freeing the fc_lport ++ * itself. ++ */ ++int fc_lport_destroy(struct fc_lport *lp); ++ ++/* ++ * Logout the specified local port from the fabric ++ */ ++int fc_fabric_logoff(struct fc_lport *lp); ++ ++/* ++ * Initiate the LP state machine. This handler will use fc_host_attr ++ * to store the FLOGI service parameters, so fc_host_attr must be ++ * initialized before calling this handler. ++ */ ++int fc_fabric_login(struct fc_lport *lp); ++ ++/* ++ * The link is up for the given local port. ++ */ ++void fc_linkup(struct fc_lport *); ++ ++/* ++ * Link is down for the given local port. ++ */ ++void fc_linkdown(struct fc_lport *); ++ ++/* ++ * Pause and unpause traffic. ++ */ ++void fc_pause(struct fc_lport *); ++void fc_unpause(struct fc_lport *); ++ ++/* ++ * Configure the local port. ++ */ ++int fc_lport_config(struct fc_lport *); ++ ++/* ++ * Reset the local port. ++ */ ++int fc_lport_enter_reset(struct fc_lport *); ++ ++/* ++ * Set the mfs or reset ++ */ ++int fc_set_mfs(struct fc_lport *lp, u32 mfs); ++ ++ ++/** ++ * REMOTE PORT LAYER ++ *****************************/ ++int fc_rport_init(struct fc_lport *lp); ++ ++ ++/** ++ * DISCOVERY LAYER ++ *****************************/ ++int fc_ns_init(struct fc_lport *lp); ++ ++ ++/** ++ * SCSI LAYER ++ *****************************/ ++/* ++ * Initialize the SCSI block of libfc ++ */ ++int fc_fcp_init(struct fc_lport *); ++ ++/* ++ * This section provides an API which allows direct interaction ++ * with the SCSI-ml. Each of these functions satisfies a function ++ * pointer defined in Scsi_Host and therefore is always called ++ * directly from the SCSI-ml. ++ */ ++int fc_queuecommand(struct scsi_cmnd *sc_cmd, ++ void (*done)(struct scsi_cmnd *)); ++ ++/* ++ * Send an ABTS frame to the target device. The sc_cmd argument ++ * is a pointer to the SCSI command to be aborted. ++ */ ++int fc_eh_abort(struct scsi_cmnd *sc_cmd); ++ ++/* ++ * Reset a LUN by sending send the tm cmd to the target. ++ */ ++int fc_eh_device_reset(struct scsi_cmnd *sc_cmd); ++ ++/* ++ * Reset the host adapter. ++ */ ++int fc_eh_host_reset(struct scsi_cmnd *sc_cmd); ++ ++/* ++ * Check rport status. ++ */ ++int fc_slave_alloc(struct scsi_device *sdev); ++ ++/* ++ * Adjust the queue depth. ++ */ ++int fc_change_queue_depth(struct scsi_device *sdev, int qdepth); ++ ++/* ++ * Change the tag type. ++ */ ++int fc_change_queue_type(struct scsi_device *sdev, int tag_type); ++ ++/* ++ * Free memory pools used by the FCP layer. ++ */ ++void fc_fcp_destroy(struct fc_lport *); ++ ++ ++/** ++ * EXCHANGE MANAGER LAYER ++ *****************************/ ++/* ++ * Initializes Exchange Manager related ++ * function pointers in struct libfc_function_template. ++ */ ++int fc_exch_init(struct fc_lport *lp); ++ ++/* ++ * Allocates an Exchange Manager (EM). ++ * ++ * The EM manages exchanges for their allocation and ++ * free, also allows exchange lookup for received ++ * frame. ++ * ++ * The class is used for initializing FC class of ++ * allocated exchange from EM. ++ * ++ * The min_xid and max_xid will limit new ++ * exchange ID (XID) within this range for ++ * a new exchange. ++ * The LLD may choose to have multiple EMs, ++ * e.g. one EM instance per CPU receive thread in LLD. ++ * The LLD can use exch_get() of struct libfc_function_template ++ * to specify XID for a new exchange within ++ * a specified EM instance. ++ * ++ * The em_idx to uniquely identify an EM instance. ++ */ ++struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, ++ enum fc_class class, ++ u16 min_xid, ++ u16 max_xid); ++ ++/* ++ * Free an exchange manager. ++ */ ++void fc_exch_mgr_free(struct fc_exch_mgr *mp); ++ ++/* ++ * Receive a frame on specified local port and exchange manager. ++ */ ++void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, ++ struct fc_frame *fp); ++ ++/* ++ * This function is for exch_seq_send function pointer in ++ * struct libfc_function_template, see comment block on ++ * exch_seq_send for description of this function. ++ */ ++struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, ++ struct fc_frame *fp, ++ void (*resp)(struct fc_seq *, ++ struct fc_frame *fp, ++ void *arg), ++ void *resp_arg, u32 timer_msec, ++ u32 sid, u32 did, u32 f_ctl); ++ ++/* ++ * send a frame using existing sequence and exchange. ++ */ ++int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp, u32 f_ctl); ++ ++/* ++ * Send ELS response using mainly infomation ++ * in exchange and sequence in EM layer. ++ */ ++void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, ++ struct fc_seq_els_data *els_data); ++ ++/* ++ * This function is for seq_exch_abort function pointer in ++ * struct libfc_function_template, see comment block on ++ * seq_exch_abort for description of this function. ++ */ ++int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec); ++ ++/* ++ * Indicate that an exchange/sequence tuple is complete and the memory ++ * allocated for the related objects may be freed. ++ */ ++void fc_exch_done(struct fc_seq *sp); ++ ++/* ++ * Assigns a EM and XID for a frame and then allocates ++ * a new exchange and sequence pair. ++ * The fp can be used to determine free XID. ++ */ ++struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp); ++ ++/* ++ * Allocate a new exchange and sequence pair. ++ * if ex_id is zero then next free exchange id ++ * from specified exchange manger mp will be assigned. ++ */ ++struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 ex_id); ++ ++/* ++ * Start a new sequence on the same exchange as the supplied sequence. ++ */ ++struct fc_seq *fc_seq_start_next(struct fc_seq *sp); ++ ++/* ++ * Reset an exchange manager, completing all sequences and exchanges. ++ * If s_id is non-zero, reset only exchanges originating from that FID. ++ * If d_id is non-zero, reset only exchanges sending to that FID. ++ */ ++void fc_exch_mgr_reset(struct fc_exch_mgr *, u32 s_id, u32 d_id); ++ ++/* ++ * Get exchange Ids of a sequence ++ */ ++void fc_seq_get_xids(struct fc_seq *sp, u16 *oxid, u16 *rxid); ++ ++/* ++ * Set REC data to a sequence ++ */ ++void fc_seq_set_rec_data(struct fc_seq *sp, u32 rec_data); ++ ++/** ++ * fc_functions_template ++ *****************************/ ++void fc_attr_init(struct fc_lport *); ++void fc_get_host_port_id(struct Scsi_Host *shost); ++void fc_get_host_speed(struct Scsi_Host *shost); ++void fc_get_host_port_type(struct Scsi_Host *shost); ++void fc_get_host_port_state(struct Scsi_Host *shost); ++void fc_get_host_fabric_name(struct Scsi_Host *shost); ++void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout); ++struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); ++ ++/* ++ * module setup functions. ++ */ ++int fc_setup_exch_mgr(void); ++void fc_destroy_exch_mgr(void); ++ ++ ++#endif /* _LIBFC_H_ */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-libfc b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-libfc new file mode 100644 index 000000000..97084c2da --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-libfc @@ -0,0 +1,8053 @@ +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:24:37 +0200 +Subject: libfc: a modular software Fibre Channel implementation +References: FATE#303913 + +Signed-off-by: Robert Love +Signed-off-by: Chris Leech +Signed-off-by: Vasu Dev +Signed-off-by: Yi Zou +Signed-off-by: Steve Ma +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/Kconfig | 6 + + drivers/scsi/Makefile | 1 + + drivers/scsi/libfc/Makefile | 12 + + drivers/scsi/libfc/fc_attr.c | 129 +++ + drivers/scsi/libfc/fc_exch.c | 2028 ++++++++++++++++++++++++++++++++++++++ + drivers/scsi/libfc/fc_fcp.c | 2173 +++++++++++++++++++++++++++++++++++++++++ + drivers/scsi/libfc/fc_frame.c | 88 ++ + drivers/scsi/libfc/fc_lport.c | 926 ++++++++++++++++++ + drivers/scsi/libfc/fc_ns.c | 1283 ++++++++++++++++++++++++ + drivers/scsi/libfc/fc_rport.c | 1301 ++++++++++++++++++++++++ + 10 files changed, 7947 insertions(+), 0 deletions(-) + create mode 100644 drivers/scsi/libfc/Makefile + create mode 100644 drivers/scsi/libfc/fc_attr.c + create mode 100644 drivers/scsi/libfc/fc_exch.c + create mode 100644 drivers/scsi/libfc/fc_fcp.c + create mode 100644 drivers/scsi/libfc/fc_frame.c + create mode 100644 drivers/scsi/libfc/fc_lport.c + create mode 100644 drivers/scsi/libfc/fc_ns.c + create mode 100644 drivers/scsi/libfc/fc_rport.c + +diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig +index 4e0322b..bd480d2 100644 +--- a/drivers/scsi/Kconfig ++++ b/drivers/scsi/Kconfig +@@ -328,6 +328,12 @@ menuconfig SCSI_LOWLEVEL + + if SCSI_LOWLEVEL && SCSI + ++config LIBFC ++ tristate "LibFC module" ++ depends on SCSI && SCSI_FC_ATTRS ++ ---help--- ++ Fibre Channel library module ++ + config ISCSI_TCP + tristate "iSCSI Initiator over TCP/IP" + depends on SCSI && INET +diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile +index 72fd504..9158dc6 100644 +--- a/drivers/scsi/Makefile ++++ b/drivers/scsi/Makefile +@@ -36,6 +36,7 @@ obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ + obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o + obj-$(CONFIG_SCSI_DH) += device_handler/ + ++obj-$(CONFIG_LIBFC) += libfc/ + obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o + obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o + obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o +diff --git a/drivers/scsi/libfc/Makefile b/drivers/scsi/libfc/Makefile +new file mode 100644 +index 0000000..0a31ca2 +--- /dev/null ++++ b/drivers/scsi/libfc/Makefile +@@ -0,0 +1,12 @@ ++# $Id: Makefile ++ ++obj-$(CONFIG_LIBFC) += libfc.o ++ ++libfc-objs := \ ++ fc_ns.o \ ++ fc_exch.o \ ++ fc_frame.o \ ++ fc_lport.o \ ++ fc_rport.o \ ++ fc_attr.o \ ++ fc_fcp.o +diff --git a/drivers/scsi/libfc/fc_attr.c b/drivers/scsi/libfc/fc_attr.c +new file mode 100644 +index 0000000..d73f39e +--- /dev/null ++++ b/drivers/scsi/libfc/fc_attr.c +@@ -0,0 +1,129 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#include ++#include ++ ++#include ++ ++#include ++ ++MODULE_AUTHOR("Open-FCoE.org"); ++MODULE_DESCRIPTION("libfc"); ++MODULE_LICENSE("GPL"); ++ ++void fc_get_host_port_id(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lp = shost_priv(shost); ++ ++ fc_host_port_id(shost) = fc_lport_get_fid(lp); ++} ++EXPORT_SYMBOL(fc_get_host_port_id); ++ ++void fc_get_host_speed(struct Scsi_Host *shost) ++{ ++ /* ++ * should be obtain from DEC or Enet Driver ++ */ ++ fc_host_speed(shost) = 1; /* for now it is 1g */ ++} ++EXPORT_SYMBOL(fc_get_host_speed); ++ ++void fc_get_host_port_type(struct Scsi_Host *shost) ++{ ++ fc_host_port_type(shost) = FC_PORTTYPE_NPORT; ++} ++EXPORT_SYMBOL(fc_get_host_port_type); ++ ++void fc_get_host_fabric_name(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lp = shost_priv(shost); ++ ++ fc_host_fabric_name(shost) = lp->wwnn; ++} ++EXPORT_SYMBOL(fc_get_host_fabric_name); ++ ++void fc_attr_init(struct fc_lport *lp) ++{ ++ fc_host_node_name(lp->host) = lp->wwnn; ++ fc_host_port_name(lp->host) = lp->wwpn; ++ fc_host_supported_classes(lp->host) = FC_COS_CLASS3; ++ memset(fc_host_supported_fc4s(lp->host), 0, ++ sizeof(fc_host_supported_fc4s(lp->host))); ++ fc_host_supported_fc4s(lp->host)[2] = 1; ++ fc_host_supported_fc4s(lp->host)[7] = 1; ++ /* This value is also unchanging */ ++ memset(fc_host_active_fc4s(lp->host), 0, ++ sizeof(fc_host_active_fc4s(lp->host))); ++ fc_host_active_fc4s(lp->host)[2] = 1; ++ fc_host_active_fc4s(lp->host)[7] = 1; ++ fc_host_maxframe_size(lp->host) = lp->mfs; ++} ++EXPORT_SYMBOL(fc_attr_init); ++ ++void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) ++{ ++ if (timeout) ++ rport->dev_loss_tmo = timeout + 5; ++ else ++ rport->dev_loss_tmo = 30; ++ ++} ++EXPORT_SYMBOL(fc_set_rport_loss_tmo); ++ ++struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) ++{ ++ int i; ++ struct fc_host_statistics *fcoe_stats; ++ struct fc_lport *lp = shost_priv(shost); ++ struct timespec v0, v1; ++ ++ fcoe_stats = &lp->host_stats; ++ memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); ++ ++ jiffies_to_timespec(jiffies, &v0); ++ jiffies_to_timespec(lp->boot_time, &v1); ++ fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); ++ ++ for_each_online_cpu(i) { ++ struct fcoe_dev_stats *stats = lp->dev_stats[i]; ++ if (stats == NULL) ++ continue; ++ fcoe_stats->tx_frames += stats->TxFrames; ++ fcoe_stats->tx_words += stats->TxWords; ++ fcoe_stats->rx_frames += stats->RxFrames; ++ fcoe_stats->rx_words += stats->RxWords; ++ fcoe_stats->error_frames += stats->ErrorFrames; ++ fcoe_stats->invalid_crc_count += stats->InvalidCRCCount; ++ fcoe_stats->fcp_input_requests += stats->InputRequests; ++ fcoe_stats->fcp_output_requests += stats->OutputRequests; ++ fcoe_stats->fcp_control_requests += stats->ControlRequests; ++ fcoe_stats->fcp_input_megabytes += stats->InputMegabytes; ++ fcoe_stats->fcp_output_megabytes += stats->OutputMegabytes; ++ fcoe_stats->link_failure_count += stats->LinkFailureCount; ++ } ++ fcoe_stats->lip_count = -1; ++ fcoe_stats->nos_count = -1; ++ fcoe_stats->loss_of_sync_count = -1; ++ fcoe_stats->loss_of_signal_count = -1; ++ fcoe_stats->prim_seq_protocol_err_count = -1; ++ fcoe_stats->dumped_frames = -1; ++ return fcoe_stats; ++} ++EXPORT_SYMBOL(fc_get_host_stats); +diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c +new file mode 100644 +index 0000000..11a03bd +--- /dev/null ++++ b/drivers/scsi/libfc/fc_exch.c +@@ -0,0 +1,2028 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Fibre Channel exchange and sequence handling. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define FC_DEF_R_A_TOV (10 * 1000) /* resource allocation timeout */ ++ ++/* ++ * fc_exch_debug can be set in debugger or at compile time to get more logs. ++ */ ++static int fc_exch_debug; ++static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ ++ ++/* ++ * Structure and function definitions for managing Fibre Channel Exchanges ++ * and Sequences. ++ * ++ * The three primary structures used here are fc_exch_mgr, fc_exch, and fc_seq. ++ * ++ * fc_exch_mgr holds the exchange state for an N port ++ * ++ * fc_exch holds state for one exchange and links to its active sequence. ++ * ++ * fc_seq holds the state for an individual sequence. ++ */ ++ ++/* ++ * Sequence. ++ */ ++struct fc_seq { ++ u8 id; /* seq ID */ ++ u16 ssb_stat; /* status flags for sequence status block */ ++ u16 cnt; /* frames sent so far on sequence */ ++ u32 f_ctl; /* F_CTL flags for frames */ ++ u32 rec_data; /* FC-4 value for REC */ ++}; ++ ++struct fc_exch; ++ ++#define FC_EX_DONE (1 << 0) /* ep is completed */ ++#define FC_EX_RST_CLEANUP (1 << 1) /* reset is forcing completion */ ++ ++/* ++ * Exchange. ++ * ++ * Locking notes: The ex_lock protects changes to the following fields: ++ * esb_stat, f_ctl, seq.ssb_stat, seq.f_ctl. ++ * seq_id ++ * sequence allocation ++ */ ++struct fc_exch { ++ struct fc_exch_mgr *em; /* exchange manager */ ++ u32 state; /* internal driver state */ ++ u16 xid; /* our exchange ID */ ++ struct list_head ex_list; /* free or busy list linkage */ ++ spinlock_t ex_lock; /* lock covering exchange state */ ++ atomic_t ex_refcnt; /* reference counter */ ++ struct timer_list ex_timer; /* timer for upper level protocols */ ++ struct fc_lport *lp; /* fc device instance */ ++ u16 oxid; /* originator's exchange ID */ ++ u16 rxid; /* responder's exchange ID */ ++ u32 oid; /* originator's FCID */ ++ u32 sid; /* source FCID */ ++ u32 did; /* destination FCID */ ++ u32 esb_stat; /* exchange status for ESB */ ++ u32 r_a_tov; /* r_a_tov from rport (msec) */ ++ u8 seq_id; /* next sequence ID to use */ ++ u32 f_ctl; /* F_CTL flags for sequences */ ++ u8 fh_type; /* frame type */ ++ enum fc_class class; /* class of service */ ++ struct fc_seq seq; /* single sequence */ ++ struct fc_exch *aborted_ep; /* ref to ep rrq is cleaning up */ ++ ++ /* ++ * Handler for responses to this current exchange. ++ */ ++ void (*resp)(struct fc_seq *, struct fc_frame *, void *); ++ void *resp_arg; /* 3rd arg for exchange resp handler */ ++}; ++ ++/* ++ * Exchange manager. ++ * ++ * This structure is the center for creating exchanges and sequences. ++ * It manages the allocation of exchange IDs. ++ */ ++struct fc_exch_mgr { ++ enum fc_class class; /* default class for sequences */ ++ spinlock_t em_lock; /* exchange manager lock */ ++ u16 last_xid; /* last allocated exchange ID */ ++ u16 min_xid; /* min exchange ID */ ++ u16 max_xid; /* max exchange ID */ ++ u32 total_exches; /* total allocated exchanges */ ++ struct list_head ex_list; /* allocated exchanges list */ ++ struct fc_lport *lp; /* fc device instance */ ++ mempool_t *ep_pool; /* reserve ep's */ ++ ++ /* ++ * currently exchange mgr stats are updated but not used. ++ * either stats can be expose via sysfs or remove them ++ * all together if not used XXX ++ */ ++ struct { ++ atomic_t no_free_exch; ++ atomic_t no_free_exch_xid; ++ atomic_t xid_not_found; ++ atomic_t xid_busy; ++ atomic_t seq_not_found; ++ atomic_t non_bls_resp; ++ } stats; ++ struct fc_exch **exches; /* for exch pointers indexed by xid */ ++}; ++ ++#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) ++#define fc_exch_next_xid(mp, id) ((id == mp->max_xid) ? mp->min_xid : id + 1) ++ ++static void fc_exch_rrq(struct fc_exch *); ++static void fc_seq_ls_acc(struct fc_seq *); ++static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, ++ enum fc_els_rjt_explan); ++static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *); ++static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *); ++static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp); ++ ++/* ++ * Internal implementation notes. ++ * ++ * The exchange manager is one by default in libfc but LLD may choose ++ * to have one per CPU. The sequence manager is one per exchange manager ++ * and currently never separated. ++ * ++ * Section 9.8 in FC-FS-2 specifies: "The SEQ_ID is a one-byte field ++ * assigned by the Sequence Initiator that shall be unique for a specific ++ * D_ID and S_ID pair while the Sequence is open." Note that it isn't ++ * qualified by exchange ID, which one might think it would be. ++ * In practice this limits the number of open sequences and exchanges to 256 ++ * per session. For most targets we could treat this limit as per exchange. ++ * ++ * The exchange and its sequence are freed when the last sequence is received. ++ * It's possible for the remote port to leave an exchange open without ++ * sending any sequences. ++ * ++ * Notes on reference counts: ++ * ++ * Exchanges are reference counted and exchange gets freed when the reference ++ * count becomes zero. ++ * ++ * Timeouts: ++ * Sequences are timed out for E_D_TOV and R_A_TOV. ++ * ++ * Sequence event handling: ++ * ++ * The following events may occur on initiator sequences: ++ * ++ * Send. ++ * For now, the whole thing is sent. ++ * Receive ACK ++ * This applies only to class F. ++ * The sequence is marked complete. ++ * ULP completion. ++ * The upper layer calls fc_exch_done() when done ++ * with exchange and sequence tuple. ++ * RX-inferred completion. ++ * When we receive the next sequence on the same exchange, we can ++ * retire the previous sequence ID. (XXX not implemented). ++ * Timeout. ++ * R_A_TOV frees the sequence ID. If we're waiting for ACK, ++ * E_D_TOV causes abort and calls upper layer response handler ++ * with FC_EX_TIMEOUT error. ++ * Receive RJT ++ * XXX defer. ++ * Send ABTS ++ * On timeout. ++ * ++ * The following events may occur on recipient sequences: ++ * ++ * Receive ++ * Allocate sequence for first frame received. ++ * Hold during receive handler. ++ * Release when final frame received. ++ * Keep status of last N of these for the ELS RES command. XXX TBD. ++ * Receive ABTS ++ * Deallocate sequence ++ * Send RJT ++ * Deallocate ++ * ++ * For now, we neglect conditions where only part of a sequence was ++ * received or transmitted, or where out-of-order receipt is detected. ++ */ ++ ++/* ++ * Locking notes: ++ * ++ * The EM code run in a per-CPU worker thread. ++ * ++ * To protect against concurrency between a worker thread code and timers, ++ * sequence allocation and deallocation must be locked. ++ * - exchange refcnt can be done atomicly without locks. ++ * - sequence allocation must be locked by exch lock. ++ */ ++ ++/* ++ * opcode names for debugging. ++ */ ++static char *fc_exch_rctl_names[] = FC_RCTL_NAMES_INIT; ++ ++#define FC_TABLE_SIZE(x) (sizeof(x) / sizeof(x[0])) ++ ++static inline const char *fc_exch_name_lookup(unsigned int op, char **table, ++ unsigned int max_index) ++{ ++ const char *name = NULL; ++ ++ if (op < max_index) ++ name = table[op]; ++ if (!name) ++ name = "unknown"; ++ return name; ++} ++ ++static const char *fc_exch_rctl_name(unsigned int op) ++{ ++ return fc_exch_name_lookup(op, fc_exch_rctl_names, ++ FC_TABLE_SIZE(fc_exch_rctl_names)); ++} ++ ++/* ++ * Hold an exchange - keep it from being freed. ++ */ ++static void fc_exch_hold(struct fc_exch *ep) ++{ ++ atomic_inc(&ep->ex_refcnt); ++} ++ ++/* ++ * Fill in frame header. ++ * ++ * The following fields are the responsibility of this routine: ++ * d_id, s_id, df_ctl, oxid, rxid, cs_ctl, seq_id ++ * ++ * The following fields are handled by the caller. ++ * r_ctl, type, f_ctl, seq_cnt, parm_offset ++ * ++ * That should be a complete list. ++ * ++ * We may be the originator or responder to the sequence. ++ */ ++static void fc_seq_fill_hdr(struct fc_seq *sp, struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ struct fc_exch *ep; ++ ++ ep = fc_seq_exch(sp); ++ ++ hton24(fh->fh_s_id, ep->sid); ++ hton24(fh->fh_d_id, ep->did); ++ fh->fh_ox_id = htons(ep->oxid); ++ fh->fh_rx_id = htons(ep->rxid); ++ fh->fh_seq_id = sp->id; ++ fh->fh_cs_ctl = 0; ++ fh->fh_df_ctl = 0; ++} ++ ++/* ++ * Release a reference to an exchange. ++ * If the refcnt goes to zero and the exchange is complete, it is freed. ++ */ ++static void fc_exch_release(struct fc_exch *ep) ++{ ++ struct fc_exch_mgr *mp; ++ ++ if (atomic_dec_and_test(&ep->ex_refcnt)) { ++ mp = ep->em; ++ if (ep->lp->tt.exch_put) ++ ep->lp->tt.exch_put(ep->lp, mp, ep->xid); ++ WARN_ON(!ep->esb_stat & ESB_ST_COMPLETE); ++ WARN_ON(timer_pending(&ep->ex_timer)); ++ mempool_free(ep, mp->ep_pool); ++ } ++} ++ ++static int fc_exch_done_locked(struct fc_exch *ep) ++{ ++ int rc = 1; ++ ++ /* ++ * We must check for completion in case there are two threads ++ * tyring to complete this. But the rrq code will reuse the ++ * ep, and in that case we only clear the resp and set it as ++ * complete, so it can be reused by the timer to send the rrq. ++ */ ++ ep->resp = NULL; ++ if (ep->state & FC_EX_DONE) ++ return rc; ++ ep->esb_stat |= ESB_ST_COMPLETE; ++ ++ if (!(ep->esb_stat & ESB_ST_REC_QUAL)) { ++ ep->state |= FC_EX_DONE; ++ if (del_timer(&ep->ex_timer)) ++ atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ atomic_dec(&ep->ex_refcnt); /* drop hold from alloc */ ++ rc = 0; ++ } ++ return rc; ++} ++ ++static void fc_exch_mgr_delete_ep(struct fc_exch *ep) ++{ ++ struct fc_exch_mgr *mp; ++ ++ mp = ep->em; ++ spin_lock_bh(&mp->em_lock); ++ WARN_ON(mp->total_exches <= 0); ++ mp->total_exches--; ++ mp->exches[ep->xid - mp->min_xid] = NULL; ++ list_del(&ep->ex_list); ++ spin_unlock_bh(&mp->em_lock); ++} ++ ++/* ++ * Internal version of fc_exch_timer_set - used with lock held. ++ */ ++static inline void fc_exch_timer_set_locked(struct fc_exch *ep, ++ unsigned int timer_msec) ++{ ++ if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) ++ return; ++ ++ if (!mod_timer(&ep->ex_timer, jiffies + msecs_to_jiffies(timer_msec))) ++ fc_exch_hold(ep); /* hold for timer */ ++} ++ ++/* ++ * Set timer for an exchange. ++ * The time is a minimum delay in milliseconds until the timer fires. ++ * Used for upper level protocols to time out the exchange. ++ * The timer is cancelled when it fires or when the exchange completes. ++ * Returns non-zero if a timer couldn't be allocated. ++ */ ++static void fc_exch_timer_set(struct fc_exch *ep, unsigned int timer_msec) ++{ ++ spin_lock_bh(&ep->ex_lock); ++ fc_exch_timer_set_locked(ep, timer_msec); ++ spin_unlock_bh(&ep->ex_lock); ++} ++ ++int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec) ++{ ++ struct fc_seq *sp; ++ struct fc_exch *ep; ++ struct fc_frame *fp; ++ int error; ++ ++ ep = fc_seq_exch(req_sp); ++ ++ spin_lock_bh(&ep->ex_lock); ++ if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL) || ++ ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP)) { ++ spin_unlock_bh(&ep->ex_lock); ++ return -ENXIO; ++ } ++ ++ /* ++ * Send the abort on a new sequence if possible. ++ */ ++ sp = fc_seq_start_next_locked(&ep->seq); ++ if (!sp) { ++ spin_unlock_bh(&ep->ex_lock); ++ return -ENOMEM; ++ } ++ ++ sp->f_ctl |= FC_FC_SEQ_INIT; ++ ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL; ++ if (timer_msec) ++ fc_exch_timer_set_locked(ep, timer_msec); ++ spin_unlock_bh(&ep->ex_lock); ++ ++ /* ++ * If not logged into the fabric, don't send ABTS but leave ++ * sequence active until next timeout. ++ */ ++ if (!ep->sid) ++ return 0; ++ ++ /* ++ * Send an abort for the sequence that timed out. ++ */ ++ fp = fc_frame_alloc(ep->lp, 0); ++ if (fp) { ++ fc_frame_setup(fp, FC_RCTL_BA_ABTS, FC_TYPE_BLS); ++ error = fc_seq_send(ep->lp, sp, fp, FC_FC_END_SEQ); ++ } else ++ error = -ENOBUFS; ++ return error; ++} ++EXPORT_SYMBOL(fc_seq_exch_abort); ++ ++/* ++ * Exchange timeout - handle exchange timer expiration. ++ * The timer will have been cancelled before this is called. ++ */ ++static void fc_exch_timeout(unsigned long ep_arg) ++{ ++ struct fc_exch *ep = (struct fc_exch *)ep_arg; ++ struct fc_seq *sp = &ep->seq; ++ void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); ++ void *arg; ++ u32 e_stat; ++ int rc = 1; ++ ++ spin_lock_bh(&ep->ex_lock); ++ if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) ++ goto unlock; ++ ++ e_stat = ep->esb_stat; ++ if (e_stat & ESB_ST_COMPLETE) { ++ ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL; ++ spin_unlock_bh(&ep->ex_lock); ++ if (e_stat & ESB_ST_REC_QUAL) ++ fc_exch_rrq(ep); ++ goto done; ++ } else { ++ resp = ep->resp; ++ arg = ep->resp_arg; ++ ep->resp = NULL; ++ if (e_stat & ESB_ST_ABNORMAL) ++ rc = fc_exch_done_locked(ep); ++ spin_unlock_bh(&ep->ex_lock); ++ if (!rc) ++ fc_exch_mgr_delete_ep(ep); ++ if (resp) ++ resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); ++ fc_seq_exch_abort(sp, 2 * ep->r_a_tov); ++ goto done; ++ } ++unlock: ++ spin_unlock_bh(&ep->ex_lock); ++done: ++ /* ++ * This release matches the hold taken when the timer was set. ++ */ ++ fc_exch_release(ep); ++} ++ ++/* ++ * Allocate a sequence. ++ * ++ * We don't support multiple originated sequences on the same exchange. ++ * By implication, any previously originated sequence on this exchange ++ * is complete, and we reallocate the same sequence. ++ */ ++static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) ++{ ++ struct fc_seq *sp; ++ ++ sp = &ep->seq; ++ sp->ssb_stat = 0; ++ sp->f_ctl = 0; ++ sp->cnt = 0; ++ sp->id = seq_id; ++ return sp; ++} ++ ++/* ++ * Allocate an exchange. ++ * ++ * if xid is supplied zero then assign next free exchange ID ++ * from exchange manager, otherwise use supplied xid. ++ */ ++struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, u16 xid) ++{ ++ struct fc_exch *ep = NULL; ++ u16 min_xid, max_xid; ++ ++ min_xid = mp->min_xid; ++ max_xid = mp->max_xid; ++ /* ++ * if xid is supplied then verify its xid range ++ */ ++ if (xid) { ++ if (unlikely((xid < min_xid) || (xid > max_xid))) { ++ FC_DBG("Invalid xid 0x:%x\n", xid); ++ goto out; ++ } ++ if (unlikely(mp->exches[xid - min_xid] != NULL)) { ++ FC_DBG("xid 0x:%x is already in use\n", xid); ++ goto out; ++ } ++ } ++ ++ /* ++ * Allocate new exchange ++ */ ++ ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); ++ if (!ep) { ++ atomic_inc(&mp->stats.no_free_exch); ++ goto out; ++ } ++ memset(ep, 0, sizeof(*ep)); ++ ++ spin_lock_bh(&mp->em_lock); ++ ++ /* ++ * if xid is zero then assign next free exchange ID ++ */ ++ if (!xid) { ++ xid = fc_exch_next_xid(mp, mp->last_xid); ++ /* ++ * find next free xid using linear search ++ */ ++ while (mp->exches[xid - min_xid] != NULL) { ++ if (xid == mp->last_xid) ++ break; ++ xid = fc_exch_next_xid(mp, xid); ++ } ++ ++ if (likely(mp->exches[xid - min_xid] == NULL)) { ++ mp->last_xid = xid; ++ } else { ++ spin_unlock_bh(&mp->em_lock); ++ atomic_inc(&mp->stats.no_free_exch_xid); ++ mempool_free(ep, mp->ep_pool); ++ goto out; ++ } ++ } ++ ++ mp->exches[xid - min_xid] = ep; ++ list_add_tail(&ep->ex_list, &mp->ex_list); ++ fc_seq_alloc(ep, ep->seq_id++); ++ mp->total_exches++; ++ spin_unlock_bh(&mp->em_lock); ++ ++ /* ++ * update exchange ++ */ ++ ep->oxid = ep->xid = xid; ++ ep->em = mp; ++ ep->lp = mp->lp; ++ ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ ++ ep->rxid = FC_XID_UNKNOWN; ++ ep->class = mp->class; ++ ++ spin_lock_init(&ep->ex_lock); ++ setup_timer(&ep->ex_timer, fc_exch_timeout, (unsigned long)ep); ++ ++ fc_exch_hold(ep); /* hold for caller */ ++out: ++ return ep; ++} ++EXPORT_SYMBOL(fc_exch_alloc); ++ ++/* ++ * Lookup and hold an exchange. ++ */ ++static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) ++{ ++ struct fc_exch *ep = NULL; ++ ++ if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { ++ spin_lock_bh(&mp->em_lock); ++ ep = mp->exches[xid - mp->min_xid]; ++ if (ep) { ++ fc_exch_hold(ep); ++ WARN_ON(ep->xid != xid); ++ } ++ spin_unlock_bh(&mp->em_lock); ++ } ++ return ep; ++} ++ ++void fc_exch_done(struct fc_seq *sp) ++{ ++ struct fc_exch *ep = fc_seq_exch(sp); ++ int rc; ++ ++ spin_lock_bh(&ep->ex_lock); ++ rc = fc_exch_done_locked(ep); ++ spin_unlock_bh(&ep->ex_lock); ++ if (!rc) ++ fc_exch_mgr_delete_ep(ep); ++} ++EXPORT_SYMBOL(fc_exch_done); ++ ++/* ++ * Allocate a new exchange as responder. ++ * Sets the responder ID in the frame header. ++ */ ++static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) ++{ ++ struct fc_exch *ep; ++ struct fc_frame_header *fh; ++ u16 rxid; ++ ++ ep = mp->lp->tt.exch_get(mp->lp, fp); ++ if (ep) { ++ ep->class = fc_frame_class(fp); ++ ++ /* ++ * Set EX_CTX indicating we're responding on this exchange. ++ */ ++ ep->f_ctl |= FC_FC_EX_CTX; /* we're responding */ ++ ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not new */ ++ fh = fc_frame_header_get(fp); ++ ep->sid = ntoh24(fh->fh_d_id); ++ ep->did = ntoh24(fh->fh_s_id); ++ ep->oid = ep->did; ++ ++ /* ++ * Allocated exchange has placed the XID in the ++ * originator field. Move it to the responder field, ++ * and set the originator XID from the frame. ++ */ ++ ep->rxid = ep->xid; ++ ep->oxid = ntohs(fh->fh_ox_id); ++ ep->esb_stat |= ESB_ST_RESP | ESB_ST_SEQ_INIT; ++ if ((ntoh24(fh->fh_f_ctl) & FC_FC_SEQ_INIT) == 0) ++ ep->esb_stat &= ~ESB_ST_SEQ_INIT; ++ ++ /* ++ * Set the responder ID in the frame header. ++ * The old one should've been 0xffff. ++ * If it isn't, don't assign one. ++ * Incoming basic link service frames may specify ++ * a referenced RX_ID. ++ */ ++ if (fh->fh_type != FC_TYPE_BLS) { ++ rxid = ntohs(fh->fh_rx_id); ++ WARN_ON(rxid != FC_XID_UNKNOWN); ++ fh->fh_rx_id = htons(ep->rxid); ++ } ++ } ++ return ep; ++} ++ ++/* ++ * Find a sequence for receive where the other end is originating the sequence. ++ * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold ++ * on the ep that should be released by the caller. ++ */ ++static enum fc_pf_rjt_reason ++fc_seq_lookup_recip(struct fc_exch_mgr *mp, struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ struct fc_exch *ep = NULL, *new_ep = NULL; ++ struct fc_seq *sp = NULL; ++ enum fc_pf_rjt_reason reject = FC_RJT_NONE; ++ u32 f_ctl; ++ u16 xid; ++ ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ WARN_ON((f_ctl & FC_FC_SEQ_CTX) != 0); ++ ++ /* ++ * Lookup or create the exchange if we will be creating the sequence. ++ */ ++ if (f_ctl & FC_FC_EX_CTX) { ++ xid = ntohs(fh->fh_ox_id); /* we originated exch */ ++ ep = fc_exch_find(mp, xid); ++ if (!ep) { ++ atomic_inc(&mp->stats.xid_not_found); ++ reject = FC_RJT_OX_ID; ++ goto out; ++ } ++ if (ep->rxid == FC_XID_UNKNOWN) ++ ep->rxid = ntohs(fh->fh_rx_id); ++ else if (ep->rxid != ntohs(fh->fh_rx_id)) { ++ reject = FC_RJT_OX_ID; ++ goto rel; ++ } ++ } else { ++ xid = ntohs(fh->fh_rx_id); /* we are the responder */ ++ ++ /* ++ * Special case for MDS issuing an ELS TEST with a ++ * bad rxid of 0. ++ * XXX take this out once we do the proper reject. ++ */ ++ if (xid == 0 && fh->fh_r_ctl == FC_RCTL_ELS_REQ && ++ fc_frame_payload_op(fp) == ELS_TEST) { ++ fh->fh_rx_id = htons(FC_XID_UNKNOWN); ++ xid = FC_XID_UNKNOWN; ++ } ++ ++ /* ++ * new sequence - find the exchange ++ */ ++ ep = fc_exch_find(mp, xid); ++ if ((f_ctl & FC_FC_FIRST_SEQ) && fc_sof_is_init(fr_sof(fp))) { ++ if (ep) { ++ atomic_inc(&mp->stats.xid_busy); ++ reject = FC_RJT_RX_ID; ++ goto rel; ++ } ++ new_ep = ep = fc_exch_resp(mp, fp); ++ if (!ep) { ++ reject = FC_RJT_EXCH_EST; /* XXX */ ++ goto out; ++ } ++ fc_exch_hold(ep); /* Additional hold for caller */ ++ xid = ep->xid; /* get our XID */ ++ } else if (!ep) { ++ atomic_inc(&mp->stats.xid_not_found); ++ reject = FC_RJT_RX_ID; /* XID not found */ ++ goto out; ++ } ++ } ++ ++ /* ++ * At this point, we have the exchange held. ++ * Find or create the sequence. ++ */ ++ if (fc_sof_is_init(fr_sof(fp))) { ++ sp = fc_seq_start_next(&ep->seq); ++ if (!sp) { ++ reject = FC_RJT_SEQ_XS; /* exchange shortage */ ++ goto rel; ++ } ++ sp->id = fh->fh_seq_id; ++ sp->ssb_stat |= SSB_ST_RESP; ++ } else { ++ sp = &ep->seq; ++ if (sp->id != fh->fh_seq_id) { ++ atomic_inc(&mp->stats.seq_not_found); ++ reject = FC_RJT_SEQ_ID; /* sequence/exch should exist */ ++ goto rel; ++ } ++ } ++ WARN_ON(ep != fc_seq_exch(sp)); ++ ++ if (f_ctl & FC_FC_SEQ_INIT) ++ ep->esb_stat |= ESB_ST_SEQ_INIT; ++ ++ fr_seq(fp) = sp; ++out: ++ return reject; ++rel: ++ fc_exch_release(ep); ++ if (new_ep) ++ fc_exch_release(new_ep); ++ return reject; ++} ++ ++/* ++ * Find the sequence for a frame being received. ++ * We originated the sequence, so it should be found. ++ * We may or may not have originated the exchange. ++ * Does not hold the sequence for the caller. ++ */ ++static struct fc_seq *fc_seq_lookup_orig(struct fc_exch_mgr *mp, ++ struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ struct fc_exch *ep; ++ struct fc_seq *sp = NULL; ++ u32 f_ctl; ++ u16 xid; ++ ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ WARN_ON((f_ctl & FC_FC_SEQ_CTX) != FC_FC_SEQ_CTX); ++ xid = ntohs((f_ctl & FC_FC_EX_CTX) ? fh->fh_ox_id : fh->fh_rx_id); ++ ep = fc_exch_find(mp, xid); ++ if (!ep) ++ return NULL; ++ if (ep->seq.id == fh->fh_seq_id) { ++ /* ++ * Save the RX_ID if we didn't previously know it. ++ */ ++ sp = &ep->seq; ++ if ((f_ctl & FC_FC_EX_CTX) != 0 && ++ ep->rxid == FC_XID_UNKNOWN) { ++ ep->rxid = ntohs(fh->fh_rx_id); ++ } ++ } ++ fc_exch_release(ep); ++ return sp; ++} ++ ++/* ++ * Set addresses for an exchange. ++ * Note this must be done before the first sequence of the exchange is sent. ++ */ ++static void fc_exch_set_addr(struct fc_exch *ep, ++ u32 orig_id, u32 resp_id) ++{ ++ ep->oid = orig_id; ++ if (ep->esb_stat & ESB_ST_RESP) { ++ ep->sid = resp_id; ++ ep->did = orig_id; ++ } else { ++ ep->sid = orig_id; ++ ep->did = resp_id; ++ } ++} ++ ++static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp) ++{ ++ struct fc_exch *ep = fc_seq_exch(sp); ++ ++ sp = fc_seq_alloc(ep, ep->seq_id++); ++ if (fc_exch_debug) ++ FC_DBG("exch %4x f_ctl %6x seq %2x f_ctl %6x\n", ++ ep->xid, ep->f_ctl, sp->id, sp->f_ctl); ++ return sp; ++} ++/* ++ * Allocate a new sequence on the same exchange as the supplied sequence. ++ * This will never return NULL. ++ */ ++struct fc_seq *fc_seq_start_next(struct fc_seq *sp) ++{ ++ struct fc_exch *ep = fc_seq_exch(sp); ++ ++ spin_lock_bh(&ep->ex_lock); ++ WARN_ON((ep->esb_stat & ESB_ST_COMPLETE) != 0); ++ sp = fc_seq_start_next_locked(sp); ++ spin_unlock_bh(&ep->ex_lock); ++ ++ return sp; ++} ++EXPORT_SYMBOL(fc_seq_start_next); ++ ++int fc_seq_send(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp, u32 f_ctl) ++{ ++ struct fc_exch *ep; ++ struct fc_frame_header *fh; ++ enum fc_class class; ++ u16 fill = 0; ++ int error; ++ ++ ep = fc_seq_exch(sp); ++ WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); ++ ++ fc_seq_fill_hdr(sp, fp); ++ fh = fc_frame_header_get(fp); ++ class = ep->class; ++ fr_sof(fp) = class; ++ if (sp->cnt) ++ fr_sof(fp) = fc_sof_normal(class); ++ ++ if (f_ctl & FC_FC_END_SEQ) { ++ fr_eof(fp) = FC_EOF_T; ++ if (fc_sof_needs_ack(class)) ++ fr_eof(fp) = FC_EOF_N; ++ /* ++ * Form f_ctl. ++ * The number of fill bytes to make the length a 4-byte ++ * multiple is the low order 2-bits of the f_ctl. ++ * The fill itself will have been cleared by the frame ++ * allocation. ++ * After this, the length will be even, as expected by ++ * the transport. Don't include the fill in the f_ctl ++ * saved in the sequence. ++ */ ++ fill = fr_len(fp) & 3; ++ if (fill) { ++ fill = 4 - fill; ++ /* TODO, this may be a problem with fragmented skb */ ++ skb_put(fp_skb(fp), fill); ++ } ++ f_ctl |= sp->f_ctl | ep->f_ctl; ++ } else { ++ WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ ++ f_ctl |= sp->f_ctl | ep->f_ctl; ++ f_ctl &= ~FC_FC_SEQ_INIT; ++ fr_eof(fp) = FC_EOF_N; ++ } ++ ++ hton24(fh->fh_f_ctl, f_ctl | fill); ++ fh->fh_seq_cnt = htons(sp->cnt++); ++ ++ /* ++ * Send the frame. ++ */ ++ error = lp->tt.frame_send(lp, fp); ++ ++ /* ++ * Update the exchange and sequence flags, ++ * assuming all frames for the sequence have been sent. ++ * We can only be called to send once for each sequence. ++ */ ++ spin_lock_bh(&ep->ex_lock); ++ sp->f_ctl = f_ctl; /* save for possible abort */ ++ ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ ++ if (f_ctl & FC_FC_END_SEQ) { ++ if (f_ctl & FC_FC_SEQ_INIT) ++ ep->esb_stat &= ~ESB_ST_SEQ_INIT; ++ } ++ spin_unlock_bh(&ep->ex_lock); ++ return error; ++} ++EXPORT_SYMBOL(fc_seq_send); ++ ++void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, ++ struct fc_seq_els_data *els_data) ++{ ++ switch (els_cmd) { ++ case ELS_LS_RJT: ++ fc_seq_ls_rjt(sp, els_data->reason, els_data->explan); ++ break; ++ case ELS_LS_ACC: ++ fc_seq_ls_acc(sp); ++ break; ++ case ELS_RRQ: ++ fc_exch_els_rrq(sp, els_data->fp); ++ break; ++ case ELS_REC: ++ fc_exch_els_rec(sp, els_data->fp); ++ break; ++ default: ++ FC_DBG("Invalid ELS CMD:%x\n", els_cmd); ++ } ++} ++EXPORT_SYMBOL(fc_seq_els_rsp_send); ++ ++/* ++ * Send a sequence, which is also the last sequence in the exchange. ++ */ ++static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp, ++ enum fc_rctl rctl, enum fc_fh_type fh_type) ++{ ++ u32 f_ctl; ++ ++ fc_frame_setup(fp, rctl, fh_type); ++ f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_seq_send(fc_seq_exch(sp)->lp, sp, fp, f_ctl); ++} ++ ++/* ++ * Send ACK_1 (or equiv.) indicating we received something. ++ * The frame we're acking is supplied. ++ */ ++static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) ++{ ++ struct fc_frame *fp; ++ struct fc_frame_header *rx_fh; ++ struct fc_frame_header *fh; ++ struct fc_lport *lp = fc_seq_exch(sp)->lp; ++ unsigned int f_ctl; ++ ++ /* ++ * Don't send ACKs for class 3. ++ */ ++ if (fc_sof_needs_ack(fr_sof(rx_fp))) { ++ fp = fc_frame_alloc(lp, 0); ++ BUG_ON(!fp); ++ if (!fp) ++ return; ++ ++ fc_seq_fill_hdr(sp, fp); ++ fh = fc_frame_header_get(fp); ++ fh->fh_r_ctl = FC_RCTL_ACK_1; ++ fh->fh_type = FC_TYPE_BLS; ++ ++ /* ++ * Form f_ctl by inverting EX_CTX and SEQ_CTX (bits 23, 22). ++ * Echo FIRST_SEQ, LAST_SEQ, END_SEQ, END_CONN, SEQ_INIT. ++ * Bits 9-8 are meaningful (retransmitted or unidirectional). ++ * Last ACK uses bits 7-6 (continue sequence), ++ * bits 5-4 are meaningful (what kind of ACK to use). ++ */ ++ rx_fh = fc_frame_header_get(rx_fp); ++ f_ctl = ntoh24(rx_fh->fh_f_ctl); ++ f_ctl &= FC_FC_EX_CTX | FC_FC_SEQ_CTX | ++ FC_FC_FIRST_SEQ | FC_FC_LAST_SEQ | ++ FC_FC_END_SEQ | FC_FC_END_CONN | FC_FC_SEQ_INIT | ++ FC_FC_RETX_SEQ | FC_FC_UNI_TX; ++ f_ctl ^= FC_FC_EX_CTX | FC_FC_SEQ_CTX; ++ hton24(fh->fh_f_ctl, f_ctl); ++ ++ fh->fh_seq_id = rx_fh->fh_seq_id; ++ fh->fh_seq_cnt = rx_fh->fh_seq_cnt; ++ fh->fh_parm_offset = htonl(1); /* ack single frame */ ++ ++ fr_sof(fp) = fr_sof(rx_fp); ++ if (f_ctl & FC_FC_END_SEQ) ++ fr_eof(fp) = FC_EOF_T; ++ else ++ fr_eof(fp) = FC_EOF_N; ++ ++ (void) lp->tt.frame_send(lp, fp); ++ } ++} ++ ++/* ++ * Send BLS Reject. ++ * This is for rejecting BA_ABTS only. ++ */ ++static void ++fc_exch_send_ba_rjt(struct fc_frame *rx_fp, enum fc_ba_rjt_reason reason, ++ enum fc_ba_rjt_explan explan) ++{ ++ struct fc_frame *fp; ++ struct fc_frame_header *rx_fh; ++ struct fc_frame_header *fh; ++ struct fc_ba_rjt *rp; ++ struct fc_lport *lp; ++ unsigned int f_ctl; ++ ++ lp = fr_dev(rx_fp); ++ fp = fc_frame_alloc(lp, sizeof(*rp)); ++ if (!fp) ++ return; ++ fh = fc_frame_header_get(fp); ++ rx_fh = fc_frame_header_get(rx_fp); ++ ++ memset(fh, 0, sizeof(*fh) + sizeof(*rp)); ++ ++ rp = fc_frame_payload_get(fp, sizeof(*rp)); ++ rp->br_reason = reason; ++ rp->br_explan = explan; ++ ++ /* ++ * seq_id, cs_ctl, df_ctl and param/offset are zero. ++ */ ++ memcpy(fh->fh_s_id, rx_fh->fh_d_id, 3); ++ memcpy(fh->fh_d_id, rx_fh->fh_s_id, 3); ++ fh->fh_ox_id = rx_fh->fh_rx_id; ++ fh->fh_rx_id = rx_fh->fh_ox_id; ++ fh->fh_seq_cnt = rx_fh->fh_seq_cnt; ++ fh->fh_r_ctl = FC_RCTL_BA_RJT; ++ fh->fh_type = FC_TYPE_BLS; ++ ++ /* ++ * Form f_ctl by inverting EX_CTX and SEQ_CTX (bits 23, 22). ++ * Echo FIRST_SEQ, LAST_SEQ, END_SEQ, END_CONN, SEQ_INIT. ++ * Bits 9-8 are meaningful (retransmitted or unidirectional). ++ * Last ACK uses bits 7-6 (continue sequence), ++ * bits 5-4 are meaningful (what kind of ACK to use). ++ * Always set LAST_SEQ, END_SEQ. ++ */ ++ f_ctl = ntoh24(rx_fh->fh_f_ctl); ++ f_ctl &= FC_FC_EX_CTX | FC_FC_SEQ_CTX | ++ FC_FC_END_CONN | FC_FC_SEQ_INIT | ++ FC_FC_RETX_SEQ | FC_FC_UNI_TX; ++ f_ctl ^= FC_FC_EX_CTX | FC_FC_SEQ_CTX; ++ f_ctl |= FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ f_ctl &= ~FC_FC_FIRST_SEQ; ++ hton24(fh->fh_f_ctl, f_ctl); ++ ++ fr_sof(fp) = fc_sof_class(fr_sof(rx_fp)); ++ fr_eof(fp) = FC_EOF_T; ++ if (fc_sof_needs_ack(fr_sof(fp))) ++ fr_eof(fp) = FC_EOF_N; ++ ++ (void) lp->tt.frame_send(lp, fp); ++} ++ ++/* ++ * Handle an incoming ABTS. This would be for target mode usually, ++ * but could be due to lost FCP transfer ready, confirm or RRQ. ++ * We always handle this as an exchange abort, ignoring the parameter. ++ */ ++static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp) ++{ ++ struct fc_frame *fp; ++ struct fc_ba_acc *ap; ++ struct fc_frame_header *fh; ++ struct fc_seq *sp; ++ ++ if (!ep) ++ goto reject; ++ spin_lock_bh(&ep->ex_lock); ++ if (ep->esb_stat & ESB_ST_COMPLETE) { ++ spin_unlock_bh(&ep->ex_lock); ++ goto reject; ++ } ++ if (!(ep->esb_stat & ESB_ST_REC_QUAL)) ++ fc_exch_hold(ep); /* hold for REC_QUAL */ ++ ep->esb_stat |= ESB_ST_ABNORMAL | ESB_ST_REC_QUAL; ++ fc_exch_timer_set_locked(ep, ep->r_a_tov); ++ ++ fp = fc_frame_alloc(ep->lp, sizeof(*ap)); ++ if (!fp) { ++ spin_unlock_bh(&ep->ex_lock); ++ goto free; ++ } ++ fh = fc_frame_header_get(fp); ++ ap = fc_frame_payload_get(fp, sizeof(*ap)); ++ memset(ap, 0, sizeof(*ap)); ++ sp = &ep->seq; ++ ap->ba_high_seq_cnt = htons(0xffff); ++ if (sp->ssb_stat & SSB_ST_RESP) { ++ ap->ba_seq_id = sp->id; ++ ap->ba_seq_id_val = FC_BA_SEQ_ID_VAL; ++ ap->ba_high_seq_cnt = fh->fh_seq_cnt; ++ ap->ba_low_seq_cnt = htons(sp->cnt); ++ } ++ sp = fc_seq_start_next(sp); ++ spin_unlock_bh(&ep->ex_lock); ++ fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS); ++ fc_frame_free(rx_fp); ++ return; ++ ++reject: ++ fc_exch_send_ba_rjt(rx_fp, FC_BA_RJT_UNABLE, FC_BA_RJT_INV_XID); ++free: ++ fc_frame_free(rx_fp); ++} ++ ++/* ++ * Handle receive where the other end is originating the sequence. ++ */ ++static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, ++ struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ struct fc_seq *sp = NULL; ++ struct fc_exch *ep = NULL; ++ enum fc_sof sof; ++ enum fc_eof eof; ++ u32 f_ctl; ++ enum fc_pf_rjt_reason reject; ++ ++ fr_seq(fp) = NULL; ++ reject = fc_seq_lookup_recip(mp, fp); ++ if (reject == FC_RJT_NONE) { ++ sp = fr_seq(fp); /* sequence will be held */ ++ ep = fc_seq_exch(sp); ++ sof = fr_sof(fp); ++ eof = fr_eof(fp); ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ fc_seq_send_ack(sp, fp); ++ ++ /* ++ * Call the receive function. ++ * ++ * The receive function may allocate a new sequence ++ * over the old one, so we shouldn't change the ++ * sequence after this. ++ * ++ * The frame will be freed by the receive function. ++ * If new exch resp handler is valid then call that ++ * first. ++ */ ++ if (ep->resp) ++ ep->resp(sp, fp, ep->resp_arg); ++ else ++ lp->tt.lport_recv(lp, sp, fp); ++ fc_exch_release(ep); /* release from lookup */ ++ } else { ++ if (fc_exch_debug) ++ FC_DBG("exch/seq lookup failed: reject %x\n", reject); ++ fc_frame_free(fp); ++ } ++} ++ ++/* ++ * Handle receive where the other end is originating the sequence in ++ * response to our exchange. ++ */ ++static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ struct fc_seq *sp; ++ struct fc_exch *ep; ++ enum fc_sof sof; ++ u32 f_ctl; ++ void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); ++ void *ex_resp_arg; ++ int rc; ++ ++ ep = fc_exch_find(mp, ntohs(fh->fh_ox_id)); ++ if (!ep) { ++ atomic_inc(&mp->stats.xid_not_found); ++ goto out; ++ } ++ if (ep->rxid == FC_XID_UNKNOWN) ++ ep->rxid = ntohs(fh->fh_rx_id); ++ if (ep->sid != 0 && ep->sid != ntoh24(fh->fh_d_id)) { ++ atomic_inc(&mp->stats.xid_not_found); ++ goto rel; ++ } ++ if (ep->did != ntoh24(fh->fh_s_id) && ++ ep->did != FC_FID_FLOGI) { ++ atomic_inc(&mp->stats.xid_not_found); ++ goto rel; ++ } ++ sof = fr_sof(fp); ++ if (fc_sof_is_init(sof)) { ++ sp = fc_seq_start_next(&ep->seq); ++ sp->id = fh->fh_seq_id; ++ sp->ssb_stat |= SSB_ST_RESP; ++ } else { ++ sp = &ep->seq; ++ if (sp->id != fh->fh_seq_id) { ++ atomic_inc(&mp->stats.seq_not_found); ++ goto rel; ++ } ++ } ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ fr_seq(fp) = sp; ++ if (f_ctl & FC_FC_SEQ_INIT) ++ ep->esb_stat |= ESB_ST_SEQ_INIT; ++ ++ if (fc_sof_needs_ack(sof)) ++ fc_seq_send_ack(sp, fp); ++ resp = ep->resp; ++ ex_resp_arg = ep->resp_arg; ++ ++ if (fh->fh_type != FC_TYPE_FCP && fr_eof(fp) == FC_EOF_T && ++ (f_ctl & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == ++ (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) { ++ spin_lock_bh(&ep->ex_lock); ++ rc = fc_exch_done_locked(ep); ++ WARN_ON(fc_seq_exch(sp) != ep); ++ spin_unlock_bh(&ep->ex_lock); ++ if (!rc) ++ fc_exch_mgr_delete_ep(ep); ++ } ++ ++ /* ++ * Call the receive function. ++ * The sequence is held (has a refcnt) for us, ++ * but not for the receive function. ++ * ++ * The receive function may allocate a new sequence ++ * over the old one, so we shouldn't change the ++ * sequence after this. ++ * ++ * The frame will be freed by the receive function. ++ * If new exch resp handler is valid then call that ++ * first. ++ */ ++ if (resp) ++ resp(sp, fp, ex_resp_arg); ++ else ++ fc_frame_free(fp); ++ fc_exch_release(ep); ++ return; ++rel: ++ fc_exch_release(ep); ++out: ++ fc_frame_free(fp); ++} ++ ++/* ++ * Handle receive for a sequence where other end is responding to our sequence. ++ */ ++static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) ++{ ++ struct fc_seq *sp; ++ ++ sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ ++ if (!sp) { ++ atomic_inc(&mp->stats.xid_not_found); ++ if (fc_exch_debug) ++ FC_DBG("seq lookup failed\n"); ++ } else { ++ atomic_inc(&mp->stats.non_bls_resp); ++ if (fc_exch_debug) ++ FC_DBG("non-BLS response to sequence"); ++ } ++ fc_frame_free(fp); ++} ++ ++/* ++ * Handle the response to an ABTS for exchange or sequence. ++ * This can be BA_ACC or BA_RJT. ++ */ ++static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) ++{ ++ void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); ++ void *ex_resp_arg; ++ struct fc_frame_header *fh; ++ struct fc_ba_acc *ap; ++ struct fc_seq *sp; ++ u16 low; ++ u16 high; ++ int rc = 1, has_rec = 0; ++ ++ fh = fc_frame_header_get(fp); ++ if (fc_exch_debug) ++ FC_DBG("exch: BLS rctl %x - %s\n", ++ fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl)); ++ ++ if (del_timer_sync(&ep->ex_timer)) ++ fc_exch_release(ep); /* release from pending timer hold */ ++ ++ spin_lock_bh(&ep->ex_lock); ++ switch (fh->fh_r_ctl) { ++ case FC_RCTL_BA_ACC: ++ ap = fc_frame_payload_get(fp, sizeof(*ap)); ++ if (!ap) ++ break; ++ ++ /* ++ * Decide whether to establish a Recovery Qualifier. ++ * We do this if there is a non-empty SEQ_CNT range and ++ * SEQ_ID is the same as the one we aborted. ++ */ ++ low = ntohs(ap->ba_low_seq_cnt); ++ high = ntohs(ap->ba_high_seq_cnt); ++ if ((ep->esb_stat & ESB_ST_REC_QUAL) == 0 && ++ (ap->ba_seq_id_val != FC_BA_SEQ_ID_VAL || ++ ap->ba_seq_id == ep->seq_id) && low != high) { ++ ep->esb_stat |= ESB_ST_REC_QUAL; ++ fc_exch_hold(ep); /* hold for recovery qualifier */ ++ has_rec = 1; ++ } ++ break; ++ case FC_RCTL_BA_RJT: ++ break; ++ default: ++ break; ++ } ++ ++ resp = ep->resp; ++ ex_resp_arg = ep->resp_arg; ++ ++ /* do we need to do some other checks here. Can we reuse more of ++ * fc_exch_recv_seq_resp ++ */ ++ sp = &ep->seq; ++ /* ++ * do we want to check END_SEQ as well as LAST_SEQ here? ++ */ ++ if (fh->fh_type != FC_TYPE_FCP && ++ ntoh24(fh->fh_f_ctl) & FC_FC_LAST_SEQ) ++ rc = fc_exch_done_locked(ep); ++ spin_unlock_bh(&ep->ex_lock); ++ if (!rc) ++ fc_exch_mgr_delete_ep(ep); ++ ++ if (resp) ++ resp(sp, fp, ex_resp_arg); ++ else ++ fc_frame_free(fp); ++ ++ if (has_rec) ++ fc_exch_timer_set(ep, ep->r_a_tov); ++ ++} ++ ++/* ++ * Receive BLS sequence. ++ * This is always a sequence initiated by the remote side. ++ * We may be either the originator or recipient of the exchange. ++ */ ++static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh; ++ struct fc_exch *ep; ++ u32 f_ctl; ++ ++ fh = fc_frame_header_get(fp); ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ fr_seq(fp) = NULL; ++ ++ ep = fc_exch_find(mp, (f_ctl & FC_FC_EX_CTX) ? ++ ntohs(fh->fh_ox_id) : ntohs(fh->fh_rx_id)); ++ if (ep && (f_ctl & FC_FC_SEQ_INIT)) { ++ spin_lock_bh(&ep->ex_lock); ++ ep->esb_stat |= ESB_ST_SEQ_INIT; ++ spin_unlock_bh(&ep->ex_lock); ++ } ++ if (f_ctl & FC_FC_SEQ_CTX) { ++ /* ++ * A response to a sequence we initiated. ++ * This should only be ACKs for class 2 or F. ++ */ ++ switch (fh->fh_r_ctl) { ++ case FC_RCTL_ACK_1: ++ case FC_RCTL_ACK_0: ++ break; ++ default: ++ if (fc_exch_debug) ++ FC_DBG("BLS rctl %x - %s received", ++ fh->fh_r_ctl, ++ fc_exch_rctl_name(fh->fh_r_ctl)); ++ break; ++ } ++ fc_frame_free(fp); ++ } else { ++ switch (fh->fh_r_ctl) { ++ case FC_RCTL_BA_RJT: ++ case FC_RCTL_BA_ACC: ++ if (ep) ++ fc_exch_abts_resp(ep, fp); ++ else ++ fc_frame_free(fp); ++ break; ++ case FC_RCTL_BA_ABTS: ++ fc_exch_recv_abts(ep, fp); ++ break; ++ default: /* ignore junk */ ++ fc_frame_free(fp); ++ break; ++ } ++ } ++ if (ep) ++ fc_exch_release(ep); /* release hold taken by fc_exch_find */ ++} ++ ++/* ++ * Accept sequence with LS_ACC. ++ * If this fails due to allocation or transmit congestion, assume the ++ * originator will repeat the sequence. ++ */ ++static void fc_seq_ls_acc(struct fc_seq *req_sp) ++{ ++ struct fc_seq *sp; ++ struct fc_els_ls_acc *acc; ++ struct fc_frame *fp; ++ ++ sp = fc_seq_start_next(req_sp); ++ fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); ++ if (fp) { ++ acc = fc_frame_payload_get(fp, sizeof(*acc)); ++ memset(acc, 0, sizeof(*acc)); ++ acc->la_cmd = ELS_LS_ACC; ++ fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ } ++} ++ ++/* ++ * Reject sequence with ELS LS_RJT. ++ * If this fails due to allocation or transmit congestion, assume the ++ * originator will repeat the sequence. ++ */ ++static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason, ++ enum fc_els_rjt_explan explan) ++{ ++ struct fc_seq *sp; ++ struct fc_els_ls_rjt *rjt; ++ struct fc_frame *fp; ++ ++ sp = fc_seq_start_next(req_sp); ++ fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt)); ++ if (fp) { ++ rjt = fc_frame_payload_get(fp, sizeof(*rjt)); ++ memset(rjt, 0, sizeof(*rjt)); ++ rjt->er_cmd = ELS_LS_RJT; ++ rjt->er_reason = reason; ++ rjt->er_explan = explan; ++ fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ } ++} ++ ++static void fc_exch_reset(struct fc_exch *ep) ++{ ++ struct fc_seq *sp; ++ void (*resp)(struct fc_seq *, struct fc_frame *, void *); ++ void *arg; ++ int rc = 1; ++ ++ spin_lock_bh(&ep->ex_lock); ++ ep->state |= FC_EX_RST_CLEANUP; ++ /* ++ * we really want to call del_timer_sync, but cannot due ++ * to the lport calling with the lport lock held (some resp ++ * functions can also grab the lport lock which could cause ++ * a deadlock). ++ */ ++ if (del_timer(&ep->ex_timer)) ++ atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ resp = ep->resp; ++ ep->resp = NULL; ++ if (ep->esb_stat & ESB_ST_REC_QUAL) ++ atomic_dec(&ep->ex_refcnt); /* drop hold for rec_qual */ ++ ep->esb_stat &= ~ESB_ST_REC_QUAL; ++ arg = ep->resp_arg; ++ sp = &ep->seq; ++ ++ if (ep->fh_type != FC_TYPE_FCP) ++ rc = fc_exch_done_locked(ep); ++ spin_unlock_bh(&ep->ex_lock); ++ if (!rc) ++ fc_exch_mgr_delete_ep(ep); ++ ++ if (resp) ++ resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); ++} ++ ++/* ++ * Reset an exchange manager, releasing all sequences and exchanges. ++ * If sid is non-zero, reset only exchanges we source from that FID. ++ * If did is non-zero, reset only exchanges destined to that FID. ++ */ ++void fc_exch_mgr_reset(struct fc_exch_mgr *mp, u32 sid, u32 did) ++{ ++ struct fc_exch *ep; ++ struct fc_exch *next; ++ ++ spin_lock_bh(&mp->em_lock); ++restart: ++ list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { ++ if ((sid == 0 || sid == ep->sid) && ++ (did == 0 || did == ep->did)) { ++ fc_exch_hold(ep); ++ spin_unlock_bh(&mp->em_lock); ++ ++ fc_exch_reset(ep); ++ ++ fc_exch_release(ep); ++ spin_lock_bh(&mp->em_lock); ++ ++ /* ++ * must restart loop incase while lock was down ++ * multiple eps were released. ++ */ ++ goto restart; ++ } ++ } ++ spin_unlock_bh(&mp->em_lock); ++} ++EXPORT_SYMBOL(fc_exch_mgr_reset); ++ ++void fc_seq_get_xids(struct fc_seq *sp, u16 *oxid, u16 *rxid) ++{ ++ struct fc_exch *ep; ++ ++ ep = fc_seq_exch(sp); ++ *oxid = ep->oxid; ++ *rxid = ep->rxid; ++} ++EXPORT_SYMBOL(fc_seq_get_xids); ++ ++void fc_seq_set_rec_data(struct fc_seq *sp, u32 rec_data) ++{ ++ sp->rec_data = rec_data; ++} ++EXPORT_SYMBOL(fc_seq_set_rec_data); ++ ++/* ++ * Handle incoming ELS REC - Read Exchange Concise. ++ * Note that the requesting port may be different than the S_ID in the request. ++ */ ++static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) ++{ ++ struct fc_frame *fp; ++ struct fc_exch *ep; ++ struct fc_exch_mgr *em; ++ struct fc_els_rec *rp; ++ struct fc_els_rec_acc *acc; ++ enum fc_els_rjt_reason reason = ELS_RJT_LOGIC; ++ enum fc_els_rjt_explan explan; ++ u32 sid; ++ u16 rxid; ++ u16 oxid; ++ ++ rp = fc_frame_payload_get(rfp, sizeof(*rp)); ++ explan = ELS_EXPL_INV_LEN; ++ if (!rp) ++ goto reject; ++ sid = ntoh24(rp->rec_s_id); ++ rxid = ntohs(rp->rec_rx_id); ++ oxid = ntohs(rp->rec_ox_id); ++ ++ /* ++ * Currently it's hard to find the local S_ID from the exchange ++ * manager. This will eventually be fixed, but for now it's easier ++ * to lookup the subject exchange twice, once as if we were ++ * the initiator, and then again if we weren't. ++ */ ++ em = fc_seq_exch(sp)->em; ++ ep = fc_exch_find(em, oxid); ++ explan = ELS_EXPL_OXID_RXID; ++ if (ep && ep->oid == sid) { ++ if (ep->rxid != FC_XID_UNKNOWN && ++ rxid != FC_XID_UNKNOWN && ++ ep->rxid != rxid) ++ goto rel; ++ } else { ++ if (ep) ++ fc_exch_release(ep); ++ ep = NULL; ++ if (rxid != FC_XID_UNKNOWN) ++ ep = fc_exch_find(em, rxid); ++ if (!ep) ++ goto reject; ++ } ++ ++ fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); ++ if (!fp) { ++ fc_exch_done(sp); ++ goto out; ++ } ++ sp = fc_seq_start_next(sp); ++ acc = fc_frame_payload_get(fp, sizeof(*acc)); ++ memset(acc, 0, sizeof(*acc)); ++ acc->reca_cmd = ELS_LS_ACC; ++ acc->reca_ox_id = rp->rec_ox_id; ++ memcpy(acc->reca_ofid, rp->rec_s_id, 3); ++ acc->reca_rx_id = htons(ep->rxid); ++ if (ep->sid == ep->oid) ++ hton24(acc->reca_rfid, ep->did); ++ else ++ hton24(acc->reca_rfid, ep->sid); ++ acc->reca_fc4value = htonl(ep->seq.rec_data); ++ acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | ++ ESB_ST_SEQ_INIT | ++ ESB_ST_COMPLETE)); ++ sp = fc_seq_start_next(sp); ++ fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++out: ++ fc_exch_release(ep); ++ fc_frame_free(rfp); ++ return; ++ ++rel: ++ fc_exch_release(ep); ++reject: ++ fc_seq_ls_rjt(sp, reason, explan); ++ fc_frame_free(rfp); ++} ++ ++/* ++ * Handle response from RRQ. ++ * Not much to do here, really. ++ * Should report errors. ++ * ++ * TODO: fix error handler. ++ */ ++static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++{ ++ struct fc_exch *ep = fc_seq_exch(sp); ++ struct fc_exch *aborted_ep; ++ ++ unsigned int op; ++ ++ if (IS_ERR(fp)) { ++ int err = PTR_ERR(fp); ++ ++ if (err == -FC_EX_CLOSED) ++ goto cleanup; ++ FC_DBG("Cannot process RRQ, because of frame error %d\n", err); ++ return; ++ } ++ ++ op = fc_frame_payload_op(fp); ++ fc_frame_free(fp); ++ ++ switch (op) { ++ case ELS_LS_RJT: ++ FC_DBG("LS_RJT for RRQ"); ++ /* fall through */ ++ case ELS_LS_ACC: ++ goto cleanup; ++ default: ++ FC_DBG("unexpected response op %x for RRQ", op); ++ return; ++ } ++ ++cleanup: ++ spin_lock_bh(&ep->ex_lock); ++ aborted_ep = ep->aborted_ep; ++ ep->aborted_ep = NULL; ++ spin_unlock_bh(&ep->ex_lock); ++ ++ if (aborted_ep) { ++ fc_exch_done(&aborted_ep->seq); ++ /* drop hold for rec qual */ ++ fc_exch_release(aborted_ep); ++ } ++} ++ ++/* ++ * Send ELS RRQ - Reinstate Recovery Qualifier. ++ * This tells the remote port to stop blocking the use of ++ * the exchange and the seq_cnt range. ++ */ ++static void fc_exch_rrq(struct fc_exch *ep) ++{ ++ struct fc_lport *lp; ++ struct fc_els_rrq *rrq; ++ struct fc_frame *fp; ++ struct fc_seq *rrq_sp; ++ struct fc_exch *rrq_ep; ++ u32 did; ++ ++ lp = ep->lp; ++ ++ fp = fc_frame_alloc(lp, sizeof(*rrq)); ++ if (!fp) ++ return; ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ rrq = fc_frame_payload_get(fp, sizeof(*rrq)); ++ memset(rrq, 0, sizeof(*rrq)); ++ rrq->rrq_cmd = ELS_RRQ; ++ hton24(rrq->rrq_s_id, ep->sid); ++ rrq->rrq_ox_id = htons(ep->oxid); ++ rrq->rrq_rx_id = htons(ep->rxid); ++ ++ did = ep->did; ++ if (ep->esb_stat & ESB_ST_RESP) ++ did = ep->sid; ++ rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, ep, lp->e_d_tov, ++ lp->fid, did, FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ if (!rrq_sp) { ++ spin_lock_bh(&ep->ex_lock); ++ ep->esb_stat |= ESB_ST_REC_QUAL; ++ fc_exch_timer_set_locked(ep, ep->r_a_tov); ++ spin_unlock_bh(&ep->ex_lock); ++ return; ++ } ++ ++ rrq_ep = fc_seq_exch(rrq_sp); ++ rrq_ep->aborted_ep = ep; ++} ++ ++ ++/* ++ * Handle incoming ELS RRQ - Reset Recovery Qualifier. ++ */ ++static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) ++{ ++ struct fc_exch *ep; /* request or subject exchange */ ++ struct fc_els_rrq *rp; ++ u32 sid; ++ u16 xid; ++ enum fc_els_rjt_explan explan; ++ ++ rp = fc_frame_payload_get(fp, sizeof(*rp)); ++ explan = ELS_EXPL_INV_LEN; ++ if (!rp) ++ goto reject; ++ ++ /* ++ * lookup subject exchange. ++ */ ++ ep = fc_seq_exch(sp); ++ sid = ntoh24(rp->rrq_s_id); /* subject source */ ++ xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); ++ ep = fc_exch_find(ep->em, xid); ++ ++ explan = ELS_EXPL_OXID_RXID; ++ if (!ep) ++ goto reject; ++ spin_lock_bh(&ep->ex_lock); ++ if (ep->oxid != ntohs(rp->rrq_ox_id)) ++ goto unlock_reject; ++ if (ep->rxid != ntohs(rp->rrq_rx_id) && ++ ep->rxid != FC_XID_UNKNOWN) ++ goto unlock_reject; ++ explan = ELS_EXPL_SID; ++ if (ep->sid != sid) ++ goto unlock_reject; ++ ++ /* ++ * Clear Recovery Qualifier state, and cancel timer if complete. ++ */ ++ if (ep->esb_stat & ESB_ST_REC_QUAL) { ++ ep->esb_stat &= ~ESB_ST_REC_QUAL; ++ atomic_dec(&ep->ex_refcnt); /* drop hold for rec qual */ ++ } ++ if ((ep->esb_stat & ESB_ST_COMPLETE) && (del_timer(&ep->ex_timer))) ++ atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ ++ ++ spin_unlock_bh(&ep->ex_lock); ++ ++ /* ++ * Send LS_ACC. ++ */ ++ fc_seq_ls_acc(sp); ++ fc_frame_free(fp); ++ return; ++ ++unlock_reject: ++ spin_unlock_bh(&ep->ex_lock); ++ fc_exch_release(ep); /* drop hold from fc_exch_find */ ++reject: ++ fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan); ++ fc_frame_free(fp); ++} ++ ++struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, ++ enum fc_class class, ++ u16 min_xid, u16 max_xid) ++{ ++ struct fc_exch_mgr *mp; ++ size_t len; ++ ++ if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) { ++ FC_DBG("Invalid min_xid 0x:%x and max_xid 0x:%x\n", ++ min_xid, max_xid); ++ return NULL; ++ } ++ ++ /* ++ * Memory need for EM ++ */ ++ len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); ++ len += sizeof(struct fc_exch_mgr); ++ ++ mp = kzalloc(len, GFP_ATOMIC); ++ if (mp) { ++ mp->class = class; ++ mp->total_exches = 0; ++ mp->exches = (struct fc_exch **)(mp + 1); ++ mp->last_xid = min_xid - 1; ++ mp->min_xid = min_xid; ++ mp->max_xid = max_xid; ++ mp->lp = lp; ++ INIT_LIST_HEAD(&mp->ex_list); ++ spin_lock_init(&mp->em_lock); ++ } ++ ++ mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); ++ if (!mp->ep_pool) ++ goto free_mp; ++ ++ return mp; ++ ++free_mp: ++ kfree(mp); ++ return NULL; ++} ++EXPORT_SYMBOL(fc_exch_mgr_alloc); ++ ++void fc_exch_mgr_free(struct fc_exch_mgr *mp) ++{ ++ WARN_ON(!mp); ++ /* ++ * The total exch count must be zero ++ * before freeing exchange manager. ++ */ ++ WARN_ON(mp->total_exches != 0); ++ mempool_destroy(mp->ep_pool); ++ kfree(mp); ++} ++EXPORT_SYMBOL(fc_exch_mgr_free); ++ ++struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ if (!lp || !lp->emp) ++ return NULL; ++ return fc_exch_alloc(lp->emp, 0); ++} ++EXPORT_SYMBOL(fc_exch_get); ++ ++struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, ++ struct fc_frame *fp, ++ void (*resp)(struct fc_seq *, ++ struct fc_frame *fp, ++ void *arg), ++ void *resp_arg, u32 timer_msec, ++ u32 sid, u32 did, u32 f_ctl) ++{ ++ struct fc_exch *ep; ++ struct fc_seq *sp = NULL; ++ struct fc_frame_header *fh; ++ u16 fill; ++ ++ ep = lp->tt.exch_get(lp, fp); ++ if (!ep) { ++ fc_frame_free(fp); ++ return NULL; ++ } ++ ep->esb_stat |= ESB_ST_SEQ_INIT; ++ fc_exch_set_addr(ep, sid, did); ++ ep->resp = resp; ++ ep->resp_arg = resp_arg; ++ ep->r_a_tov = FC_DEF_R_A_TOV; ++ ep->lp = lp; ++ sp = &ep->seq; ++ WARN_ON((sp->f_ctl & FC_FC_END_SEQ) != 0); ++ ++ fr_sof(fp) = ep->class; ++ if (sp->cnt) ++ fr_sof(fp) = fc_sof_normal(ep->class); ++ fr_eof(fp) = FC_EOF_T; ++ if (fc_sof_needs_ack(ep->class)) ++ fr_eof(fp) = FC_EOF_N; ++ ++ fc_seq_fill_hdr(sp, fp); ++ /* ++ * Form f_ctl. ++ * The number of fill bytes to make the length a 4-byte multiple is ++ * the low order 2-bits of the f_ctl. The fill itself will have been ++ * cleared by the frame allocation. ++ * After this, the length will be even, as expected by the transport. ++ * Don't include the fill in the f_ctl saved in the sequence. ++ */ ++ fill = fr_len(fp) & 3; ++ if (fill) { ++ fill = 4 - fill; ++ /* TODO, this may be a problem with fragmented skb */ ++ skb_put(fp_skb(fp), fill); ++ } ++ f_ctl |= ep->f_ctl; ++ fh = fc_frame_header_get(fp); ++ hton24(fh->fh_f_ctl, f_ctl | fill); ++ fh->fh_seq_cnt = htons(sp->cnt++); ++ ++ if (unlikely(lp->tt.frame_send(lp, fp))) ++ goto err; ++ ++ spin_lock_bh(&ep->ex_lock); ++ if (timer_msec) ++ fc_exch_timer_set_locked(ep, timer_msec); ++ sp->f_ctl = f_ctl; /* save for possible abort */ ++ ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ ++ ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ ++ ++ if (f_ctl & FC_FC_SEQ_INIT) ++ ep->esb_stat &= ~ESB_ST_SEQ_INIT; ++ spin_unlock_bh(&ep->ex_lock); ++ return sp; ++err: ++ fc_exch_done(sp); ++ return NULL; ++} ++EXPORT_SYMBOL(fc_exch_seq_send); ++ ++/* ++ * Receive a frame ++ */ ++void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, ++ struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ u32 f_ctl; ++ ++ if (!lp || !mp || (lp->state == LPORT_ST_NONE)) { ++ FC_DBG("fc_lport or EM is not allocated and configured"); ++ fc_frame_free(fp); ++ return; ++ } ++ ++ /* ++ * If frame is marked invalid, just drop it. ++ */ ++ f_ctl = ntoh24(fh->fh_f_ctl); ++ switch (fr_eof(fp)) { ++ case FC_EOF_T: ++ if (f_ctl & FC_FC_END_SEQ) ++ skb_trim(fp_skb(fp), fr_len(fp) - FC_FC_FILL(f_ctl)); ++ /* fall through */ ++ case FC_EOF_N: ++ if (fh->fh_type == FC_TYPE_BLS) ++ fc_exch_recv_bls(mp, fp); ++ else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == ++ FC_FC_EX_CTX) ++ fc_exch_recv_seq_resp(mp, fp); ++ else if (f_ctl & FC_FC_SEQ_CTX) ++ fc_exch_recv_resp(mp, fp); ++ else ++ fc_exch_recv_req(lp, mp, fp); ++ break; ++ default: ++ FC_DBG("dropping invalid frame (eof %x)", fr_eof(fp)); ++ fc_frame_free(fp); ++ break; ++ } ++} ++EXPORT_SYMBOL(fc_exch_recv); ++ ++int fc_exch_init(struct fc_lport *lp) ++{ ++ if (!lp->tt.exch_get) { ++ /* ++ * exch_put() should be NULL if ++ * exch_get() is NULL ++ */ ++ WARN_ON(lp->tt.exch_put); ++ lp->tt.exch_get = fc_exch_get; ++ } ++ ++ if (!lp->tt.seq_start_next) ++ lp->tt.seq_start_next = fc_seq_start_next; ++ ++ if (!lp->tt.exch_seq_send) ++ lp->tt.exch_seq_send = fc_exch_seq_send; ++ ++ if (!lp->tt.seq_send) ++ lp->tt.seq_send = fc_seq_send; ++ ++ if (!lp->tt.seq_els_rsp_send) ++ lp->tt.seq_els_rsp_send = fc_seq_els_rsp_send; ++ ++ if (!lp->tt.exch_done) ++ lp->tt.exch_done = fc_exch_done; ++ ++ if (!lp->tt.exch_mgr_reset) ++ lp->tt.exch_mgr_reset = fc_exch_mgr_reset; ++ ++ if (!lp->tt.seq_exch_abort) ++ lp->tt.seq_exch_abort = fc_seq_exch_abort; ++ ++ if (!lp->tt.seq_get_xids) ++ lp->tt.seq_get_xids = fc_seq_get_xids; ++ ++ if (!lp->tt.seq_set_rec_data) ++ lp->tt.seq_set_rec_data = fc_seq_set_rec_data; ++ return 0; ++} ++EXPORT_SYMBOL(fc_exch_init); ++ ++int fc_setup_exch_mgr(void) ++{ ++ fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch), ++ 0, SLAB_HWCACHE_ALIGN, NULL); ++ if (!fc_em_cachep) ++ return -ENOMEM; ++ return 0; ++} ++ ++void fc_destroy_exch_mgr(void) ++{ ++ kmem_cache_destroy(fc_em_cachep); ++} +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +new file mode 100644 +index 0000000..9402eba +--- /dev/null ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -0,0 +1,2174 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * Copyright(c) 2008 Red Hat, Inc. All rights reserved. ++ * Copyright(c) 2008 Mike Christie ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++int fc_fcp_debug; ++static struct kmem_cache *scsi_pkt_cachep; ++ ++/* SRB state definitions */ ++#define FC_SRB_FREE 0 /* cmd is free */ ++#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */ ++#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */ ++#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */ ++#define FC_SRB_ABORTED (1 << 3) /* abort acknowleged */ ++#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */ ++#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */ ++#define FC_SRB_FCP_PROCESSING_TMO (1 << 6) /* timer function processing */ ++#define FC_SRB_NOMEM (1 << 7) /* dropped to out of mem */ ++ ++#define FC_SRB_READ (1 << 1) ++#define FC_SRB_WRITE (1 << 0) ++ ++/* ++ * scsi request structure, one for each scsi request ++ */ ++struct fc_fcp_pkt { ++ /* ++ * housekeeping stuff ++ */ ++ struct fc_lport *lp; /* handle to hba struct */ ++ u16 state; /* scsi_pkt state state */ ++ u16 tgt_flags; /* target flags */ ++ atomic_t ref_cnt; /* only used byr REC ELS */ ++ spinlock_t scsi_pkt_lock; /* Must be taken before the host lock ++ * if both are held at the same time */ ++ /* ++ * SCSI I/O related stuff ++ */ ++ struct scsi_cmnd *cmd; /* scsi command pointer. set/clear ++ * under host lock */ ++ struct list_head list; /* tracks queued commands. access under ++ * host lock */ ++ /* ++ * timeout related stuff ++ */ ++ struct timer_list timer; /* command timer */ ++ struct completion tm_done; ++ int wait_for_comp; ++ unsigned long start_time; /* start jiffie */ ++ unsigned long end_time; /* end jiffie */ ++ unsigned long last_pkt_time; /* jiffies of last frame received */ ++ ++ /* ++ * scsi cmd and data transfer information ++ */ ++ u32 data_len; ++ /* ++ * transport related veriables ++ */ ++ struct fcp_cmnd cdb_cmd; ++ size_t xfer_len; ++ u32 xfer_contig_end; /* offset of end of contiguous xfer */ ++ u16 max_payload; /* max payload size in bytes */ ++ ++ /* ++ * scsi/fcp return status ++ */ ++ u32 io_status; /* SCSI result upper 24 bits */ ++ u8 cdb_status; ++ u8 status_code; /* FCP I/O status */ ++ /* bit 3 Underrun bit 2: overrun */ ++ u8 scsi_comp_flags; ++ u32 req_flags; /* bit 0: read bit:1 write */ ++ u32 scsi_resid; /* residule length */ ++ ++ struct fc_rport *rport; /* remote port pointer */ ++ struct fc_seq *seq_ptr; /* current sequence pointer */ ++ /* ++ * Error Processing ++ */ ++ u8 recov_retry; /* count of recovery retries */ ++ struct fc_seq *recov_seq; /* sequence for REC or SRR */ ++}; ++ ++/* ++ * The SCp.ptr should be tested and set under the host lock. NULL indicates ++ * that the command has been retruned to the scsi layer. ++ */ ++#define CMD_SP(Cmnd) ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr) ++#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) ++#define CMD_COMPL_STATUS(Cmnd) ((Cmnd)->SCp.this_residual) ++#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) ++#define CMD_RESID_LEN(Cmnd) ((Cmnd)->SCp.buffers_residual) ++ ++struct fc_fcp_internal { ++ mempool_t *scsi_pkt_pool; ++ struct list_head scsi_pkt_queue; ++ u8 throttled; ++}; ++ ++#define fc_get_scsi_internal(x) ((struct fc_fcp_internal *)(x)->scsi_priv) ++ ++/* ++ * function prototypes ++ * FC scsi I/O related functions ++ */ ++static void fc_fcp_recv_data(struct fc_fcp_pkt *, struct fc_frame *); ++static void fc_fcp_recv(struct fc_seq *, struct fc_frame *, void *); ++static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *); ++static void fc_fcp_complete(struct fc_fcp_pkt *); ++static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *); ++static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp); ++static void fc_timeout_error(struct fc_fcp_pkt *); ++static int fc_fcp_send_cmd(struct fc_fcp_pkt *); ++static void fc_fcp_timeout(unsigned long data); ++static void fc_fcp_rec(struct fc_fcp_pkt *); ++static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); ++static void fc_fcp_rec_resp(struct fc_seq *, struct fc_frame *, void *); ++static void fc_io_compl(struct fc_fcp_pkt *); ++ ++static void fc_fcp_srr(struct fc_fcp_pkt *, enum fc_rctl, u32); ++static void fc_fcp_srr_resp(struct fc_seq *, struct fc_frame *, void *); ++static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); ++ ++/* ++ * command status codes ++ */ ++#define FC_COMPLETE 0 ++#define FC_CMD_ABORTED 1 ++#define FC_CMD_RESET 2 ++#define FC_CMD_PLOGO 3 ++#define FC_SNS_RCV 4 ++#define FC_TRANS_ERR 5 ++#define FC_DATA_OVRRUN 6 ++#define FC_DATA_UNDRUN 7 ++#define FC_ERROR 8 ++#define FC_HRD_ERROR 9 ++#define FC_CMD_TIME_OUT 10 ++ ++/* ++ * Error recovery timeout values. ++ */ ++#define FC_SCSI_ER_TIMEOUT (10 * HZ) ++#define FC_SCSI_TM_TOV (10 * HZ) ++#define FC_SCSI_REC_TOV (2 * HZ) ++#define FC_HOST_RESET_TIMEOUT (30 * HZ) ++ ++#define FC_MAX_ERROR_CNT 5 ++#define FC_MAX_RECOV_RETRY 3 ++ ++#define FC_FCP_DFLT_QUEUE_DEPTH 32 ++ ++/** ++ * fc_fcp_pkt_alloc - allocation routine for scsi_pkt packet ++ * @lp: fc lport struct ++ * @gfp: gfp flags for allocation ++ * ++ * This is used by upper layer scsi driver. ++ * Return Value : scsi_pkt structure or null on allocation failure. ++ * Context : call from process context. no locking required. ++ */ ++static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lp, gfp_t gfp) ++{ ++ struct fc_fcp_internal *si = fc_get_scsi_internal(lp); ++ struct fc_fcp_pkt *sp; ++ ++ sp = mempool_alloc(si->scsi_pkt_pool, gfp); ++ if (sp) { ++ memset(sp, 0, sizeof(*sp)); ++ sp->lp = lp; ++ atomic_set(&sp->ref_cnt, 1); ++ init_timer(&sp->timer); ++ INIT_LIST_HEAD(&sp->list); ++ } ++ return sp; ++} ++ ++/** ++ * fc_fcp_pkt_release - release hold on scsi_pkt packet ++ * @sp: fcp packet struct ++ * ++ * This is used by upper layer scsi driver. ++ * Context : call from process and interrupt context. ++ * no locking required ++ */ ++static void fc_fcp_pkt_release(struct fc_fcp_pkt *sp) ++{ ++ if (atomic_dec_and_test(&sp->ref_cnt)) { ++ struct fc_fcp_internal *si = fc_get_scsi_internal(sp->lp); ++ ++ mempool_free(sp, si->scsi_pkt_pool); ++ } ++} ++ ++static void fc_fcp_pkt_hold(struct fc_fcp_pkt *sp) ++{ ++ atomic_inc(&sp->ref_cnt); ++} ++ ++/** ++ * fc_fcp_lock_pkt - lock a packet and get a ref to it. ++ * @fsp: fcp packet ++ * ++ * We should only return error if we return a command to scsi-ml before ++ * getting a response. This can happen in cases where we send a abort, but ++ * do not wait for the response and the abort and command can be passing ++ * each other on the wire/network-layer. ++ * ++ * Note: this function locks the packet and gets a reference to allow ++ * callers to call the completion function while the lock is held and ++ * not have to worry about the packets refcount. ++ * ++ * TODO: Maybe we should just have callers grab/release the lock and ++ * have a function that they call to verify the fsp and grab a ref if ++ * needed. ++ */ ++static inline int fc_fcp_lock_pkt(struct fc_fcp_pkt *fsp) ++{ ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ if (!fsp->cmd) { ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ FC_DBG("Invalid scsi cmd pointer on fcp packet.\n"); ++ return -EINVAL; ++ } ++ ++ fc_fcp_pkt_hold(fsp); ++ return 0; ++} ++ ++static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp) ++{ ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ fc_fcp_pkt_release(fsp); ++} ++ ++static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay) ++{ ++ if (!(fsp->state & FC_SRB_COMPL)) ++ mod_timer(&fsp->timer, jiffies + delay); ++} ++ ++static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp) ++{ ++ if (!fsp->seq_ptr) ++ return -EINVAL; ++ ++ fsp->state |= FC_SRB_ABORT_PENDING; ++ return fsp->lp->tt.seq_exch_abort(fsp->seq_ptr, 0); ++} ++ ++/* ++ * Retry command. ++ * An abort isn't needed. ++ */ ++static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp) ++{ ++ if (fsp->seq_ptr) { ++ fsp->lp->tt.exch_done(fsp->seq_ptr); ++ fsp->seq_ptr = NULL; ++ } ++ ++ fsp->state &= ~FC_SRB_ABORT_PENDING; ++ fsp->io_status = SUGGEST_RETRY << 24; ++ fsp->status_code = FC_ERROR; ++ fc_fcp_complete(fsp); ++} ++ ++/* ++ * Receive SCSI data from target. ++ * Called after receiving solicited data. ++ */ ++static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) ++{ ++ struct scsi_cmnd *sc = fsp->cmd; ++ struct fc_lport *lp = fsp->lp; ++ struct fcoe_dev_stats *sp; ++ struct fc_frame_header *fh; ++ size_t start_offset; ++ size_t offset; ++ u32 crc; ++ u32 copy_len = 0; ++ size_t len; ++ void *buf; ++ struct scatterlist *sg; ++ size_t remaining; ++ ++ fh = fc_frame_header_get(fp); ++ offset = ntohl(fh->fh_parm_offset); ++ start_offset = offset; ++ len = fr_len(fp) - sizeof(*fh); ++ buf = fc_frame_payload_get(fp, 0); ++ ++ if (offset + len > fsp->data_len) { ++ /* ++ * this should never happen ++ */ ++ if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && ++ fc_frame_crc_check(fp)) ++ goto crc_err; ++ if (fc_fcp_debug) { ++ FC_DBG("data received past end. " ++ "len %zx offset %zx " ++ "data_len %x\n", len, offset, fsp->data_len); ++ } ++ fc_fcp_retry_cmd(fsp); ++ return; ++ } ++ if (offset != fsp->xfer_len) ++ fsp->state |= FC_SRB_DISCONTIG; ++ ++ crc = 0; ++ if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) ++ crc = crc32(~0, (u8 *) fh, sizeof(*fh)); ++ ++ sg = scsi_sglist(sc); ++ remaining = len; ++ ++ while (remaining > 0 && sg) { ++ size_t off; ++ void *page_addr; ++ size_t sg_bytes; ++ ++ if (offset >= sg->length) { ++ offset -= sg->length; ++ sg = sg_next(sg); ++ continue; ++ } ++ sg_bytes = min(remaining, sg->length - offset); ++ ++ /* ++ * The scatterlist item may be bigger than PAGE_SIZE, ++ * but we are limited to mapping PAGE_SIZE at a time. ++ */ ++ off = offset + sg->offset; ++ sg_bytes = min(sg_bytes, (size_t) ++ (PAGE_SIZE - (off & ~PAGE_MASK))); ++ page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT), ++ KM_SOFTIRQ0); ++ if (!page_addr) ++ break; /* XXX panic? */ ++ ++ if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) ++ crc = crc32(crc, buf, sg_bytes); ++ memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, ++ sg_bytes); ++ ++ kunmap_atomic(page_addr, KM_SOFTIRQ0); ++ buf += sg_bytes; ++ offset += sg_bytes; ++ remaining -= sg_bytes; ++ copy_len += sg_bytes; ++ } ++ ++ if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) { ++ buf = fc_frame_payload_get(fp, 0); ++ if (len % 4) { ++ crc = crc32(crc, buf + len, 4 - (len % 4)); ++ len += 4 - (len % 4); ++ } ++ ++ if (~crc != le32_to_cpu(*(__le32 *)(buf + len))) { ++crc_err: ++ sp = lp->dev_stats[smp_processor_id()]; ++ sp->ErrorFrames++; ++ if (sp->InvalidCRCCount++ < 5) ++ FC_DBG("CRC error on data frame\n"); ++ /* ++ * Assume the frame is total garbage. ++ * We may have copied it over the good part ++ * of the buffer. ++ * If so, we need to retry the entire operation. ++ * Otherwise, ignore it. ++ */ ++ if (fsp->state & FC_SRB_DISCONTIG) ++ fc_fcp_retry_cmd(fsp); ++ return; ++ } ++ } ++ ++ if (fsp->xfer_contig_end == start_offset) ++ fsp->xfer_contig_end += copy_len; ++ fsp->xfer_len += copy_len; ++ ++ /* ++ * In the very rare event that this data arrived after the response ++ * and completes the transfer, call the completion handler. ++ */ ++ if (unlikely(fsp->state & FC_SRB_RCV_STATUS) && ++ fsp->xfer_len == fsp->data_len - fsp->scsi_resid) ++ fc_fcp_complete(fsp); ++} ++ ++/* ++ * Send SCSI data to target. ++ * Called after receiving a Transfer Ready data descriptor. ++ */ ++static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *sp, ++ size_t offset, size_t len, ++ struct fc_frame *oldfp, int sg_supp) ++{ ++ struct scsi_cmnd *sc; ++ struct scatterlist *sg; ++ struct fc_frame *fp = NULL; ++ struct fc_lport *lp = fsp->lp; ++ size_t remaining; ++ size_t mfs; ++ size_t tlen; ++ size_t sg_bytes; ++ size_t frame_offset; ++ int error; ++ void *data = NULL; ++ void *page_addr; ++ int using_sg = sg_supp; ++ u32 f_ctl; ++ ++ if (unlikely(offset + len > fsp->data_len)) { ++ /* ++ * this should never happen ++ */ ++ if (fc_fcp_debug) { ++ FC_DBG("xfer-ready past end. len %zx offset %zx\n", ++ len, offset); ++ } ++ fc_fcp_send_abort(fsp); ++ return 0; ++ } else if (offset != fsp->xfer_len) { ++ /* ++ * Out of Order Data Request - no problem, but unexpected. ++ */ ++ if (fc_fcp_debug) { ++ FC_DBG("xfer-ready non-contiguous. " ++ "len %zx offset %zx\n", len, offset); ++ } ++ } ++ mfs = fsp->max_payload; ++ WARN_ON(mfs > FC_MAX_PAYLOAD); ++ WARN_ON(mfs < FC_MIN_MAX_PAYLOAD); ++ if (mfs > 512) ++ mfs &= ~(512 - 1); /* round down to block size */ ++ WARN_ON(mfs < FC_MIN_MAX_PAYLOAD); /* won't go below 256 */ ++ WARN_ON(len <= 0); ++ sc = fsp->cmd; ++ ++ remaining = len; ++ frame_offset = offset; ++ tlen = 0; ++ sp = lp->tt.seq_start_next(sp); ++ f_ctl = FC_FC_REL_OFF; ++ WARN_ON(!sp); ++ ++ /* ++ * If a get_page()/put_page() will fail, don't use sg lists ++ * in the fc_frame structure. ++ * ++ * The put_page() may be long after the I/O has completed ++ * in the case of FCoE, since the network driver does it ++ * via free_skb(). See the test in free_pages_check(). ++ * ++ * Test this case with 'dd /dev/st0 bs=64k'. ++ */ ++ if (using_sg) { ++ for (sg = scsi_sglist(sc); sg; sg = sg_next(sg)) { ++ if (page_count(sg_page(sg)) == 0 || ++ (sg_page(sg)->flags & (1 << PG_lru | ++ 1 << PG_private | ++ 1 << PG_locked | ++ 1 << PG_active | ++ 1 << PG_slab | ++ 1 << PG_swapcache | ++ 1 << PG_writeback | ++ 1 << PG_reserved | ++ 1 << PG_buddy))) { ++ using_sg = 0; ++ break; ++ } ++ } ++ } ++ sg = scsi_sglist(sc); ++ ++ while (remaining > 0 && sg) { ++ if (offset >= sg->length) { ++ offset -= sg->length; ++ sg = sg_next(sg); ++ continue; ++ } ++ if (!fp) { ++ tlen = min(mfs, remaining); ++ ++ /* ++ * TODO. Temporary workaround. fc_seq_send() can't ++ * handle odd lengths in non-linear skbs. ++ * This will be the final fragment only. ++ */ ++ if (tlen % 4) ++ using_sg = 0; ++ if (using_sg) { ++ fp = _fc_frame_alloc(lp, 0); ++ if (!fp) ++ return -ENOMEM; ++ } else { ++ fp = fc_frame_alloc(lp, tlen); ++ if (!fp) ++ return -ENOMEM; ++ ++ data = (void *)(fr_hdr(fp)) + ++ sizeof(struct fc_frame_header); ++ } ++ fc_frame_setup(fp, FC_RCTL_DD_SOL_DATA, FC_TYPE_FCP); ++ fc_frame_set_offset(fp, frame_offset); ++ } ++ sg_bytes = min(tlen, sg->length - offset); ++ if (using_sg) { ++ WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > ++ FC_FRAME_SG_LEN); ++ get_page(sg_page(sg)); ++ skb_fill_page_desc(fp_skb(fp), ++ skb_shinfo(fp_skb(fp))->nr_frags, ++ sg_page(sg), sg->offset + offset, ++ sg_bytes); ++ fp_skb(fp)->data_len += sg_bytes; ++ fr_len(fp) += sg_bytes; ++ fp_skb(fp)->truesize += PAGE_SIZE; ++ } else { ++ size_t off = offset + sg->offset; ++ ++ /* ++ * The scatterlist item may be bigger than PAGE_SIZE, ++ * but we must not cross pages inside the kmap. ++ */ ++ sg_bytes = min(sg_bytes, (size_t) (PAGE_SIZE - ++ (off & ~PAGE_MASK))); ++ page_addr = kmap_atomic(sg_page(sg) + ++ (off >> PAGE_SHIFT), ++ KM_SOFTIRQ0); ++ memcpy(data, (char *)page_addr + (off & ~PAGE_MASK), ++ sg_bytes); ++ kunmap_atomic(page_addr, KM_SOFTIRQ0); ++ data += sg_bytes; ++ } ++ offset += sg_bytes; ++ frame_offset += sg_bytes; ++ tlen -= sg_bytes; ++ remaining -= sg_bytes; ++ ++ if (remaining == 0) { ++ /* ++ * Send a request sequence with ++ * transfer sequence initiative. ++ */ ++ f_ctl |= FC_FC_SEQ_INIT | FC_FC_END_SEQ; ++ error = lp->tt.seq_send(lp, sp, fp, f_ctl); ++ } else if (tlen == 0) { ++ /* ++ * send fragment using for a sequence. ++ */ ++ error = lp->tt.seq_send(lp, sp, fp, f_ctl); ++ } else { ++ continue; ++ } ++ fp = NULL; ++ ++ if (error) { ++ WARN_ON(1); /* send error should be rare */ ++ fc_fcp_retry_cmd(fsp); ++ return 0; ++ } ++ } ++ fsp->xfer_len += len; /* premature count? */ ++ return 0; ++} ++ ++static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame_header *fh) ++{ ++ /* ++ * we will let the command timeout and scsi-ml escalate if ++ * the abort was rejected ++ */ ++ if (fh->fh_r_ctl == FC_RCTL_BA_ACC) { ++ fsp->state |= FC_SRB_ABORTED; ++ fsp->state &= ~FC_SRB_ABORT_PENDING; ++ ++ if (fsp->wait_for_comp) ++ complete(&fsp->tm_done); ++ else ++ fc_fcp_complete(fsp); ++ } ++} ++ ++/* ++ * fc_fcp_reduce_can_queue - drop can_queue ++ * @lp: lport to drop queueing for ++ * ++ * If we are getting memory allocation failures, then we may ++ * be trying to execute too many commands. We let the running ++ * commands complete or timeout, then try again with a reduced ++ * can_queue. Eventually we will hit the point where we run ++ * on all reserved structs. ++ */ ++static void fc_fcp_reduce_can_queue(struct fc_lport *lp) ++{ ++ struct fc_fcp_internal *si = fc_get_scsi_internal(lp); ++ unsigned long flags; ++ int can_queue; ++ ++ spin_lock_irqsave(lp->host->host_lock, flags); ++ if (si->throttled) ++ goto done; ++ si->throttled = 1; ++ ++ can_queue = lp->host->can_queue; ++ can_queue >>= 1; ++ if (!can_queue) ++ can_queue = 1; ++ lp->host->can_queue = can_queue; ++ shost_printk(KERN_ERR, lp->host, "Could not allocate frame.\n" ++ "Reducing can_queue to %d.\n", can_queue); ++done: ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++} ++ ++/* ++ * exch mgr calls this routine to process scsi ++ * exchanges. ++ * ++ * Return : None ++ * Context : called from Soft IRQ context ++ * can not called holding list lock ++ */ ++static void fc_fcp_recv(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++{ ++ struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; ++ struct fc_lport *lp; ++ struct fc_frame_header *fh; ++ struct fc_data_desc *dd; ++ u8 r_ctl; ++ int rc = 0; ++ ++ if (IS_ERR(fp)) ++ goto errout; ++ ++ fh = fc_frame_header_get(fp); ++ r_ctl = fh->fh_r_ctl; ++ lp = fsp->lp; ++ ++ if (!(lp->state & LPORT_ST_READY)) ++ goto out; ++ if (fc_fcp_lock_pkt(fsp)) ++ goto out; ++ fsp->last_pkt_time = jiffies; ++ ++ if (fh->fh_type == FC_TYPE_BLS) { ++ fc_fcp_abts_resp(fsp, fh); ++ goto unlock; ++ } ++ ++ if (fsp->state & (FC_SRB_ABORTED | FC_SRB_ABORT_PENDING)) ++ goto unlock; ++ ++ if (r_ctl == FC_RCTL_DD_DATA_DESC) { ++ /* ++ * received XFER RDY from the target ++ * need to send data to the target ++ */ ++ WARN_ON(fr_flags(fp) & FCPHF_CRC_UNCHECKED); ++ dd = fc_frame_payload_get(fp, sizeof(*dd)); ++ WARN_ON(!dd); ++ ++ rc = fc_fcp_send_data(fsp, sp, ++ (size_t) ntohl(dd->dd_offset), ++ (size_t) ntohl(dd->dd_len), fp, ++ lp->capabilities & TRANS_C_SG); ++ if (!rc) ++ lp->tt.seq_set_rec_data(sp, fsp->xfer_len); ++ else if (rc == -ENOMEM) ++ fsp->state |= FC_SRB_NOMEM; ++ } else if (r_ctl == FC_RCTL_DD_SOL_DATA) { ++ /* ++ * received a DATA frame ++ * next we will copy the data to the system buffer ++ */ ++ WARN_ON(fr_len(fp) < sizeof(*fh)); /* len may be 0 */ ++ fc_fcp_recv_data(fsp, fp); ++ lp->tt.seq_set_rec_data(sp, fsp->xfer_contig_end); ++ } else if (r_ctl == FC_RCTL_DD_CMD_STATUS) { ++ WARN_ON(fr_flags(fp) & FCPHF_CRC_UNCHECKED); ++ ++ fc_fcp_resp(fsp, fp); ++ } else { ++ FC_DBG("unexpected frame. r_ctl %x\n", r_ctl); ++ } ++unlock: ++ fc_fcp_unlock_pkt(fsp); ++out: ++ fc_frame_free(fp); ++errout: ++ if (IS_ERR(fp)) ++ fc_fcp_error(fsp, fp); ++ else if (rc == -ENOMEM) ++ fc_fcp_reduce_can_queue(lp); ++} ++ ++static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh; ++ struct fcp_resp *fc_rp; ++ struct fcp_resp_ext *rp_ex; ++ struct fcp_resp_rsp_info *fc_rp_info; ++ u32 plen; ++ u32 expected_len; ++ u32 respl = 0; ++ u32 snsl = 0; ++ u8 flags = 0; ++ ++ plen = fr_len(fp); ++ fh = (struct fc_frame_header *)fr_hdr(fp); ++ if (unlikely(plen < sizeof(*fh) + sizeof(*fc_rp))) ++ goto len_err; ++ plen -= sizeof(*fh); ++ fc_rp = (struct fcp_resp *)(fh + 1); ++ fsp->cdb_status = fc_rp->fr_status; ++ flags = fc_rp->fr_flags; ++ fsp->scsi_comp_flags = flags; ++ expected_len = fsp->data_len; ++ ++ if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) { ++ rp_ex = (void *)(fc_rp + 1); ++ if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) { ++ if (plen < sizeof(*fc_rp) + sizeof(*rp_ex)) ++ goto len_err; ++ fc_rp_info = (struct fcp_resp_rsp_info *)(rp_ex + 1); ++ if (flags & FCP_RSP_LEN_VAL) { ++ respl = ntohl(rp_ex->fr_rsp_len); ++ if (respl != sizeof(*fc_rp_info)) ++ goto len_err; ++ if (fsp->wait_for_comp) { ++ /* Abuse cdb_status for rsp code */ ++ fsp->cdb_status = fc_rp_info->rsp_code; ++ complete(&fsp->tm_done); ++ /* ++ * tmfs will not have any scsi cmd so ++ * exit here ++ */ ++ return; ++ } else ++ goto err; ++ } ++ if (flags & FCP_SNS_LEN_VAL) { ++ snsl = ntohl(rp_ex->fr_sns_len); ++ if (snsl > SCSI_SENSE_BUFFERSIZE) ++ snsl = SCSI_SENSE_BUFFERSIZE; ++ memcpy(fsp->cmd->sense_buffer, ++ (char *)fc_rp_info + respl, snsl); ++ } ++ } ++ if (flags & (FCP_RESID_UNDER | FCP_RESID_OVER)) { ++ if (plen < sizeof(*fc_rp) + sizeof(rp_ex->fr_resid)) ++ goto len_err; ++ if (flags & FCP_RESID_UNDER) { ++ fsp->scsi_resid = ntohl(rp_ex->fr_resid); ++ /* ++ * The cmnd->underflow is the minimum number of ++ * bytes that must be transfered for this ++ * command. Provided a sense condition is not ++ * present, make sure the actual amount ++ * transferred is at least the underflow value ++ * or fail. ++ */ ++ if (!(flags & FCP_SNS_LEN_VAL) && ++ (fc_rp->fr_status == 0) && ++ (scsi_bufflen(fsp->cmd) - ++ fsp->scsi_resid) < fsp->cmd->underflow) ++ goto err; ++ expected_len -= fsp->scsi_resid; ++ } else { ++ fsp->status_code = FC_ERROR; ++ } ++ } ++ } ++ fsp->state |= FC_SRB_RCV_STATUS; ++ ++ /* ++ * Check for missing or extra data frames. ++ */ ++ if (unlikely(fsp->xfer_len != expected_len)) { ++ if (fsp->xfer_len < expected_len) { ++ /* ++ * Some data may be queued locally, ++ * Wait a at least one jiffy to see if it is delivered. ++ * If this expires without data, we may do SRR. ++ */ ++ fc_fcp_timer_set(fsp, 2); ++ return; ++ } ++ fsp->status_code = FC_DATA_OVRRUN; ++ FC_DBG("tgt %6x xfer len %zx greater than expected len %x. " ++ "data len %x\n", ++ fsp->rport->port_id, ++ fsp->xfer_len, expected_len, fsp->data_len); ++ } ++ fc_fcp_complete(fsp); ++ return; ++ ++len_err: ++ FC_DBG("short FCP response. flags 0x%x len %u respl %u snsl %u\n", ++ flags, fr_len(fp), respl, snsl); ++err: ++ fsp->status_code = FC_ERROR; ++ fc_fcp_complete(fsp); ++} ++ ++/** ++ * fc_fcp_complete - complete processing of a fcp packet ++ * @fsp: fcp packet ++ * ++ * This function may sleep if a timer is pending. The packet lock must be ++ * held, and the host lock must not be held. ++ */ ++static void fc_fcp_complete(struct fc_fcp_pkt *fsp) ++{ ++ struct fc_lport *lp = fsp->lp; ++ struct fc_seq *sp; ++ u32 f_ctl; ++ ++ if (fsp->state & FC_SRB_ABORT_PENDING) ++ return; ++ ++ if (fsp->state & FC_SRB_ABORTED) { ++ if (!fsp->status_code) ++ fsp->status_code = FC_CMD_ABORTED; ++ } else { ++ /* ++ * Test for transport underrun, independent of response ++ * underrun status. ++ */ ++ if (fsp->xfer_len < fsp->data_len && !fsp->io_status && ++ (!(fsp->scsi_comp_flags & FCP_RESID_UNDER) || ++ fsp->xfer_len < fsp->data_len - fsp->scsi_resid)) { ++ fsp->status_code = FC_DATA_UNDRUN; ++ fsp->io_status = SUGGEST_RETRY << 24; ++ } ++ } ++ ++ sp = fsp->seq_ptr; ++ if (sp) { ++ fsp->seq_ptr = NULL; ++ if (unlikely(fsp->scsi_comp_flags & FCP_CONF_REQ)) { ++ struct fc_frame *conf_frame; ++ struct fc_seq *csp; ++ ++ csp = lp->tt.seq_start_next(sp); ++ conf_frame = fc_frame_alloc(fsp->lp, 0); ++ if (conf_frame) { ++ fc_frame_setup(conf_frame, ++ FC_RCTL_DD_SOL_CTL, FC_TYPE_FCP); ++ f_ctl = FC_FC_SEQ_INIT; ++ f_ctl |= FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ lp->tt.seq_send(lp, csp, conf_frame, f_ctl); ++ } ++ } ++ lp->tt.exch_done(sp); ++ } ++ fc_io_compl(fsp); ++} ++ ++static void fc_fcp_cleanup_cmd(struct fc_fcp_pkt *fsp, int error) ++{ ++ struct fc_lport *lp = fsp->lp; ++ ++ if (fsp->seq_ptr) { ++ lp->tt.exch_done(fsp->seq_ptr); ++ fsp->seq_ptr = NULL; ++ } ++ fsp->status_code = error; ++} ++ ++/** ++ * fc_fcp_cleanup_each_cmd - run fn on each active command ++ * @lp: logical port ++ * @id: target id ++ * @lun: lun ++ * @error: fsp status code ++ * ++ * If lun or id is -1, they are ignored. ++ */ ++static void fc_fcp_cleanup_each_cmd(struct fc_lport *lp, unsigned int id, ++ unsigned int lun, int error) ++{ ++ struct fc_fcp_internal *si = fc_get_scsi_internal(lp); ++ struct fc_fcp_pkt *fsp; ++ struct scsi_cmnd *sc_cmd; ++ unsigned long flags; ++ ++ spin_lock_irqsave(lp->host->host_lock, flags); ++restart: ++ list_for_each_entry(fsp, &si->scsi_pkt_queue, list) { ++ sc_cmd = fsp->cmd; ++ if (id != -1 && scmd_id(sc_cmd) != id) ++ continue; ++ ++ if (lun != -1 && sc_cmd->device->lun != lun) ++ continue; ++ ++ fc_fcp_pkt_hold(fsp); ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++ ++ if (!fc_fcp_lock_pkt(fsp)) { ++ fc_fcp_cleanup_cmd(fsp, error); ++ fc_io_compl(fsp); ++ fc_fcp_unlock_pkt(fsp); ++ } ++ ++ fc_fcp_pkt_release(fsp); ++ spin_lock_irqsave(lp->host->host_lock, flags); ++ /* ++ * while we dropped the lock multiple pkts could ++ * have been released, so we have to start over. ++ */ ++ goto restart; ++ } ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++} ++ ++static void fc_fcp_abort_io(struct fc_lport *lp) ++{ ++ fc_fcp_cleanup_each_cmd(lp, -1, -1, FC_HRD_ERROR); ++} ++ ++/** ++ * fc_fcp_pkt_send - send a fcp packet to the lower level. ++ * @lp: fc lport ++ * @fsp: fc packet. ++ * ++ * This is called by upper layer protocol. ++ * Return : zero for success and -1 for failure ++ * Context : called from queuecommand which can be called from process ++ * or scsi soft irq. ++ * Locks : called with the host lock and irqs disabled. ++ */ ++static int fc_fcp_pkt_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp) ++{ ++ struct fc_fcp_internal *si = fc_get_scsi_internal(lp); ++ int rc; ++ ++ fsp->cmd->SCp.ptr = (char *)fsp; ++ fsp->cdb_cmd.fc_dl = htonl(fsp->data_len); ++ fsp->cdb_cmd.fc_flags = fsp->req_flags & ~FCP_CFL_LEN_MASK; ++ ++ int_to_scsilun(fsp->cmd->device->lun, ++ (struct scsi_lun *)fsp->cdb_cmd.fc_lun); ++ memcpy(fsp->cdb_cmd.fc_cdb, fsp->cmd->cmnd, fsp->cmd->cmd_len); ++ list_add_tail(&fsp->list, &si->scsi_pkt_queue); ++ ++ spin_unlock_irq(lp->host->host_lock); ++ rc = fc_fcp_send_cmd(fsp); ++ spin_lock_irq(lp->host->host_lock); ++ if (rc) ++ list_del(&fsp->list); ++ ++ return rc; ++} ++ ++static int fc_fcp_send_cmd(struct fc_fcp_pkt *fsp) ++{ ++ struct fc_lport *lp; ++ struct fc_frame *fp; ++ struct fc_seq *sp; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rp; ++ int rc = 0; ++ ++ if (fc_fcp_lock_pkt(fsp)) ++ return 0; ++ ++ if (fsp->state & FC_SRB_COMPL) ++ goto unlock; ++ ++ lp = fsp->lp; ++ fp = fc_frame_alloc(lp, sizeof(fsp->cdb_cmd)); ++ if (!fp) { ++ rc = -1; ++ goto unlock; ++ } ++ ++ memcpy(fc_frame_payload_get(fp, sizeof(fsp->cdb_cmd)), ++ &fsp->cdb_cmd, sizeof(fsp->cdb_cmd)); ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CMD, FC_TYPE_FCP); ++ fc_frame_set_offset(fp, 0); ++ rport = fsp->rport; ++ fsp->max_payload = rport->maxframe_size; ++ rp = rport->dd_data; ++ sp = lp->tt.exch_seq_send(lp, fp, ++ fc_fcp_recv, ++ fsp, 0, ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ if (!sp) { ++ fc_frame_free(fp); ++ rc = -1; ++ goto unlock; ++ } ++ fsp->seq_ptr = sp; ++ ++ setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); ++ fc_fcp_timer_set(fsp, ++ (fsp->tgt_flags & FC_RP_FLAGS_REC_SUPPORTED) ? ++ FC_SCSI_REC_TOV : FC_SCSI_ER_TIMEOUT); ++unlock: ++ fc_fcp_unlock_pkt(fsp); ++ return rc; ++} ++ ++/* ++ * transport error handler ++ */ ++static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) ++{ ++ int error = PTR_ERR(fp); ++ ++ if (fc_fcp_lock_pkt(fsp)) ++ return; ++ ++ switch (error) { ++ case -FC_EX_CLOSED: ++ fc_fcp_retry_cmd(fsp); ++ goto unlock; ++ default: ++ FC_DBG("unknown error %ld\n", PTR_ERR(fp)); ++ } ++ /* ++ * clear abort pending, because the lower layer ++ * decided to force completion. ++ */ ++ fsp->state &= ~FC_SRB_ABORT_PENDING; ++ fsp->status_code = FC_CMD_PLOGO; ++ fc_fcp_complete(fsp); ++unlock: ++ fc_fcp_unlock_pkt(fsp); ++} ++ ++/* ++ * Scsi abort handler- calls to send an abort ++ * and then wait for abort completion ++ */ ++static int fc_fcp_pkt_abort(struct fc_lport *lp, struct fc_fcp_pkt *fsp) ++{ ++ int rc = FAILED; ++ ++ if (fc_fcp_send_abort(fsp)) ++ return FAILED; ++ ++ init_completion(&fsp->tm_done); ++ fsp->wait_for_comp = 1; ++ ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ rc = wait_for_completion_timeout(&fsp->tm_done, FC_SCSI_TM_TOV); ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ fsp->wait_for_comp = 0; ++ ++ if (!rc) { ++ FC_DBG("target abort cmd failed\n"); ++ rc = FAILED; ++ } else if (fsp->state & FC_SRB_ABORTED) { ++ FC_DBG("target abort cmd passed\n"); ++ rc = SUCCESS; ++ fc_fcp_complete(fsp); ++ } ++ ++ return rc; ++} ++ ++/* ++ * Retry LUN reset after resource allocation failed. ++ */ ++static void fc_lun_reset_send(unsigned long data) ++{ ++ struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; ++ const size_t len = sizeof(fsp->cdb_cmd); ++ struct fc_lport *lp = fsp->lp; ++ struct fc_frame *fp; ++ struct fc_seq *sp; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rp; ++ ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ if (fsp->state & FC_SRB_COMPL) ++ goto unlock; ++ ++ fp = fc_frame_alloc(lp, len); ++ if (!fp) ++ goto retry; ++ memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CMD, FC_TYPE_FCP); ++ fc_frame_set_offset(fp, 0); ++ rport = fsp->rport; ++ rp = rport->dd_data; ++ sp = lp->tt.exch_seq_send(lp, fp, ++ fc_tm_done, ++ fsp, 0, ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ ++ if (sp) { ++ fsp->seq_ptr = sp; ++ goto unlock; ++ } ++ /* ++ * Exchange or frame allocation failed. Set timer and retry. ++ */ ++ fc_frame_free(fp); ++retry: ++ setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp); ++ fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); ++unlock: ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++} ++ ++/* ++ * Scsi device reset handler- send a LUN RESET to the device ++ * and wait for reset reply ++ */ ++static int fc_lun_reset(struct fc_lport *lp, struct fc_fcp_pkt *fsp, ++ unsigned int id, unsigned int lun) ++{ ++ int rc; ++ ++ fsp->cdb_cmd.fc_dl = htonl(fsp->data_len); ++ fsp->cdb_cmd.fc_tm_flags = FCP_TMF_LUN_RESET; ++ int_to_scsilun(lun, (struct scsi_lun *)fsp->cdb_cmd.fc_lun); ++ ++ fsp->wait_for_comp = 1; ++ init_completion(&fsp->tm_done); ++ ++ fc_lun_reset_send((unsigned long)fsp); ++ ++ /* ++ * wait for completion of reset ++ * after that make sure all commands are terminated ++ */ ++ rc = wait_for_completion_timeout(&fsp->tm_done, FC_SCSI_TM_TOV); ++ ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ fsp->state |= FC_SRB_COMPL; ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ ++ del_timer_sync(&fsp->timer); ++ ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ if (fsp->seq_ptr) { ++ /* TODO: ++ * if the exch resp function is running and trying to grab ++ * the scsi_pkt_lock, this could free the exch from under ++ * it and it could allow the fsp to be freed from under ++ * fc_tm_done. ++ */ ++ lp->tt.exch_done(fsp->seq_ptr); ++ fsp->seq_ptr = NULL; ++ } ++ fsp->wait_for_comp = 0; ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ ++ if (!rc) { ++ FC_DBG("lun reset failed\n"); ++ return FAILED; ++ } ++ ++ /* cdb_status holds the tmf's rsp code */ ++ if (fsp->cdb_status != FCP_TMF_CMPL) ++ return FAILED; ++ ++ FC_DBG("lun reset to lun %u completed\n", lun); ++ fc_fcp_cleanup_each_cmd(lp, id, lun, FC_CMD_ABORTED); ++ return SUCCESS; ++} ++ ++/* ++ * Task Managment response handler ++ */ ++static void fc_tm_done(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++{ ++ struct fc_fcp_pkt *fsp = arg; ++ struct fc_frame_header *fh; ++ ++ spin_lock_bh(&fsp->scsi_pkt_lock); ++ if (IS_ERR(fp)) { ++ /* ++ * If there is an error just let it timeout or wait ++ * for TMF to be aborted if it timedout. ++ * ++ * scsi-eh will escalate for when either happens. ++ */ ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ return; ++ } ++ ++ /* ++ * raced with eh timeout handler. ++ * ++ * TODO: If this happens we could be freeing the fsp right now and ++ * would oops. Next patches will fix this race. ++ */ ++ if ((fsp->state & FC_SRB_COMPL) || !fsp->seq_ptr || ++ !fsp->wait_for_comp) { ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++ return; ++ } ++ ++ fh = fc_frame_header_get(fp); ++ if (fh->fh_type != FC_TYPE_BLS) ++ fc_fcp_resp(fsp, fp); ++ fsp->seq_ptr = NULL; ++ fsp->lp->tt.exch_done(sp); ++ fc_frame_free(fp); ++ spin_unlock_bh(&fsp->scsi_pkt_lock); ++} ++ ++static void fc_fcp_cleanup(struct fc_lport *lp) ++{ ++ fc_fcp_cleanup_each_cmd(lp, -1, -1, FC_ERROR); ++} ++ ++/* ++ * fc_fcp_timeout: called by OS timer function. ++ * ++ * The timer has been inactivated and must be reactivated if desired ++ * using fc_fcp_timer_set(). ++ * ++ * Algorithm: ++ * ++ * If REC is supported, just issue it, and return. The REC exchange will ++ * complete or time out, and recovery can continue at that point. ++ * ++ * Otherwise, if the response has been received without all the data, ++ * it has been ER_TIMEOUT since the response was received. ++ * ++ * If the response has not been received, ++ * we see if data was received recently. If it has been, we continue waiting, ++ * otherwise, we abort the command. ++ */ ++static void fc_fcp_timeout(unsigned long data) ++{ ++ struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; ++ struct fc_rport *rport = fsp->rport; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ ++ if (fc_fcp_lock_pkt(fsp)) ++ return; ++ ++ if (fsp->state & FC_SRB_COMPL) ++ goto unlock; ++ fsp->state |= FC_SRB_FCP_PROCESSING_TMO; ++ ++ if (rp->flags & FC_RP_FLAGS_REC_SUPPORTED) ++ fc_fcp_rec(fsp); ++ /* TODO: change this to time_before/after */ ++ else if (jiffies - fsp->last_pkt_time < FC_SCSI_ER_TIMEOUT / 2) ++ fc_fcp_timer_set(fsp, FC_SCSI_ER_TIMEOUT); ++ else if (fsp->state & FC_SRB_RCV_STATUS) ++ fc_fcp_complete(fsp); ++ else ++ fc_timeout_error(fsp); ++ ++ fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; ++unlock: ++ fc_fcp_unlock_pkt(fsp); ++} ++ ++/* ++ * Send a REC ELS request ++ */ ++static void fc_fcp_rec(struct fc_fcp_pkt *fsp) ++{ ++ struct fc_lport *lp; ++ struct fc_seq *sp; ++ struct fc_frame *fp; ++ struct fc_els_rec *rec; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rp; ++ u16 ox_id; ++ u16 rx_id; ++ ++ lp = fsp->lp; ++ rport = fsp->rport; ++ rp = rport->dd_data; ++ sp = fsp->seq_ptr; ++ if (!sp || rp->rp_state != RPORT_ST_READY) { ++ fsp->status_code = FC_HRD_ERROR; ++ fsp->io_status = SUGGEST_RETRY << 24; ++ fc_fcp_complete(fsp); ++ return; ++ } ++ lp->tt.seq_get_xids(sp, &ox_id, &rx_id); ++ fp = fc_frame_alloc(lp, sizeof(*rec)); ++ if (!fp) ++ goto retry; ++ ++ rec = fc_frame_payload_get(fp, sizeof(*rec)); ++ memset(rec, 0, sizeof(*rec)); ++ rec->rec_cmd = ELS_REC; ++ hton24(rec->rec_s_id, lp->fid); ++ rec->rec_ox_id = htons(ox_id); ++ rec->rec_rx_id = htons(rx_id); ++ ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ fc_frame_set_offset(fp, 0); ++ sp = lp->tt.exch_seq_send(lp, fp, ++ fc_fcp_rec_resp, ++ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ ++ if (sp) { ++ fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ ++ return; ++ } else ++ fc_frame_free(fp); ++retry: ++ if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) ++ fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); ++ else ++ fc_timeout_error(fsp); ++} ++ ++/* ++ * Receive handler for REC ELS frame ++ * if it is a reject then let the scsi layer to handle ++ * the timeout. if it is a LS_ACC then if the io was not completed ++ * then set the timeout and return otherwise complete the exchange ++ * and tell the scsi layer to restart the I/O. ++ */ ++static void fc_fcp_rec_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++{ ++ struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; ++ struct fc_els_rec_acc *recp; ++ struct fc_els_ls_rjt *rjt; ++ u32 e_stat; ++ u8 opcode; ++ u32 offset; ++ enum dma_data_direction data_dir; ++ enum fc_rctl r_ctl; ++ struct fc_rport_libfc_priv *rp; ++ ++ if (IS_ERR(fp)) { ++ fc_fcp_rec_error(fsp, fp); ++ return; ++ } ++ ++ if (fc_fcp_lock_pkt(fsp)) ++ goto out; ++ ++ fsp->recov_retry = 0; ++ opcode = fc_frame_payload_op(fp); ++ if (opcode == ELS_LS_RJT) { ++ rjt = fc_frame_payload_get(fp, sizeof(*rjt)); ++ switch (rjt->er_reason) { ++ default: ++ if (fc_fcp_debug) ++ FC_DBG("device %x unexpected REC reject " ++ "reason %d expl %d\n", ++ fsp->rport->port_id, rjt->er_reason, ++ rjt->er_explan); ++ /* fall through */ ++ ++ case ELS_RJT_UNSUP: ++ if (fc_fcp_debug) ++ FC_DBG("device does not support REC\n"); ++ rp = fsp->rport->dd_data; ++ rp->flags &= ~FC_RP_FLAGS_REC_SUPPORTED; ++ /* fall through */ ++ ++ case ELS_RJT_LOGIC: ++ case ELS_RJT_UNAB: ++ /* ++ * If no data transfer, the command frame got dropped ++ * so we just retry. If data was transferred, we ++ * lost the response but the target has no record, ++ * so we abort and retry. ++ */ ++ if (rjt->er_explan == ELS_EXPL_OXID_RXID && ++ fsp->xfer_len == 0) { ++ fc_fcp_retry_cmd(fsp); ++ break; ++ } ++ fc_timeout_error(fsp); ++ break; ++ } ++ } else if (opcode == ELS_LS_ACC) { ++ if (fsp->state & FC_SRB_ABORTED) ++ goto unlock_out; ++ ++ data_dir = fsp->cmd->sc_data_direction; ++ recp = fc_frame_payload_get(fp, sizeof(*recp)); ++ offset = ntohl(recp->reca_fc4value); ++ e_stat = ntohl(recp->reca_e_stat); ++ ++ if (e_stat & ESB_ST_COMPLETE) { ++ ++ /* ++ * The exchange is complete. ++ * ++ * For output, we must've lost the response. ++ * For input, all data must've been sent. ++ * We lost may have lost the response ++ * (and a confirmation was requested) and maybe ++ * some data. ++ * ++ * If all data received, send SRR ++ * asking for response. If partial data received, ++ * or gaps, SRR requests data at start of gap. ++ * Recovery via SRR relies on in-order-delivery. ++ */ ++ if (data_dir == DMA_TO_DEVICE) { ++ r_ctl = FC_RCTL_DD_CMD_STATUS; ++ } else if (fsp->xfer_contig_end == offset) { ++ r_ctl = FC_RCTL_DD_CMD_STATUS; ++ } else { ++ offset = fsp->xfer_contig_end; ++ r_ctl = FC_RCTL_DD_SOL_DATA; ++ } ++ fc_fcp_srr(fsp, r_ctl, offset); ++ } else if (e_stat & ESB_ST_SEQ_INIT) { ++ ++ /* ++ * The remote port has the initiative, so just ++ * keep waiting for it to complete. ++ */ ++ fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); ++ } else { ++ ++ /* ++ * The exchange is incomplete, we have seq. initiative. ++ * Lost response with requested confirmation, ++ * lost confirmation, lost transfer ready or ++ * lost write data. ++ * ++ * For output, if not all data was received, ask ++ * for transfer ready to be repeated. ++ * ++ * If we received or sent all the data, send SRR to ++ * request response. ++ * ++ * If we lost a response, we may have lost some read ++ * data as well. ++ */ ++ r_ctl = FC_RCTL_DD_SOL_DATA; ++ if (data_dir == DMA_TO_DEVICE) { ++ r_ctl = FC_RCTL_DD_CMD_STATUS; ++ if (offset < fsp->data_len) ++ r_ctl = FC_RCTL_DD_DATA_DESC; ++ } else if (offset == fsp->xfer_contig_end) { ++ r_ctl = FC_RCTL_DD_CMD_STATUS; ++ } else if (fsp->xfer_contig_end < offset) { ++ offset = fsp->xfer_contig_end; ++ } ++ fc_fcp_srr(fsp, r_ctl, offset); ++ } ++ } ++unlock_out: ++ fc_fcp_unlock_pkt(fsp); ++out: ++ fc_fcp_pkt_release(fsp); /* drop hold for outstanding REC */ ++ fc_frame_free(fp); ++} ++ ++/* ++ * Handle error response or timeout for REC exchange. ++ */ ++static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) ++{ ++ int error = PTR_ERR(fp); ++ ++ if (fc_fcp_lock_pkt(fsp)) ++ goto out; ++ ++ switch (error) { ++ case -FC_EX_CLOSED: ++ fc_fcp_retry_cmd(fsp); ++ break; ++ ++ default: ++ FC_DBG("REC %p fid %x error unexpected error %d\n", ++ fsp, fsp->rport->port_id, error); ++ fsp->status_code = FC_CMD_PLOGO; ++ /* fall through */ ++ ++ case -FC_EX_TIMEOUT: ++ /* ++ * Assume REC or LS_ACC was lost. ++ * The exchange manager will have aborted REC, so retry. ++ */ ++ FC_DBG("REC fid %x error error %d retry %d/%d\n", ++ fsp->rport->port_id, error, fsp->recov_retry, ++ FC_MAX_RECOV_RETRY); ++ if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) ++ fc_fcp_rec(fsp); ++ else ++ fc_timeout_error(fsp); ++ break; ++ } ++ fc_fcp_unlock_pkt(fsp); ++out: ++ fc_fcp_pkt_release(fsp); /* drop hold for outstanding REC */ ++} ++ ++/* ++ * Time out error routine: ++ * abort's the I/O close the exchange and ++ * send completion notification to scsi layer ++ */ ++static void fc_timeout_error(struct fc_fcp_pkt *fsp) ++{ ++ fsp->status_code = FC_CMD_TIME_OUT; ++ fsp->cdb_status = 0; ++ fsp->io_status = 0; ++ /* ++ * if this fails then we let the scsi command timer fire and ++ * scsi-ml escalate. ++ */ ++ fc_fcp_send_abort(fsp); ++} ++ ++/* ++ * Sequence retransmission request. ++ * This is called after receiving status but insufficient data, or ++ * when expecting status but the request has timed out. ++ */ ++static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) ++{ ++ struct fc_lport *lp = fsp->lp; ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rp; ++ struct fc_seq *sp; ++ struct fcp_srr *srr; ++ struct fc_frame *fp; ++ u8 cdb_op; ++ u16 ox_id; ++ u16 rx_id; ++ ++ rport = fsp->rport; ++ rp = rport->dd_data; ++ cdb_op = fsp->cdb_cmd.fc_cdb[0]; ++ lp->tt.seq_get_xids(fsp->seq_ptr, &ox_id, &rx_id); ++ ++ if (!(rp->flags & FC_RP_FLAGS_RETRY) || rp->rp_state != RPORT_ST_READY) ++ goto retry; /* shouldn't happen */ ++ fp = fc_frame_alloc(lp, sizeof(*srr)); ++ if (!fp) ++ goto retry; ++ ++ srr = fc_frame_payload_get(fp, sizeof(*srr)); ++ memset(srr, 0, sizeof(*srr)); ++ srr->srr_op = ELS_SRR; ++ srr->srr_ox_id = htons(ox_id); ++ srr->srr_rx_id = htons(rx_id); ++ srr->srr_r_ctl = r_ctl; ++ srr->srr_rel_off = htonl(offset); ++ ++ fc_frame_setup(fp, FC_RCTL_ELS4_REQ, FC_TYPE_FCP); ++ fc_frame_set_offset(fp, 0); ++ sp = lp->tt.exch_seq_send(lp, fp, ++ fc_fcp_srr_resp, ++ fsp, jiffies_to_msecs(FC_SCSI_REC_TOV), ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ if (!sp) { ++ fc_frame_free(fp); ++ goto retry; ++ } ++ fsp->recov_seq = sp; ++ fsp->xfer_len = offset; ++ fsp->xfer_contig_end = offset; ++ fsp->state &= ~FC_SRB_RCV_STATUS; ++ fc_fcp_pkt_hold(fsp); /* hold for outstanding SRR */ ++ return; ++retry: ++ fc_fcp_retry_cmd(fsp); ++} ++ ++/* ++ * Handle response from SRR. ++ */ ++static void fc_fcp_srr_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) ++{ ++ struct fc_fcp_pkt *fsp = arg; ++ struct fc_frame_header *fh; ++ u16 ox_id; ++ u16 rx_id; ++ ++ if (IS_ERR(fp)) { ++ fc_fcp_srr_error(fsp, fp); ++ return; ++ } ++ ++ if (fc_fcp_lock_pkt(fsp)) ++ goto out; ++ ++ fh = fc_frame_header_get(fp); ++ /* ++ * BUG? fc_fcp_srr_error calls exch_done which would release ++ * the ep. But if fc_fcp_srr_error had got -FC_EX_TIMEOUT, ++ * then fc_exch_timeout would be sending an abort. The exch_done ++ * call by fc_fcp_srr_error would prevent fc_exch.c from seeing ++ * an abort response though. ++ */ ++ if (fh->fh_type == FC_TYPE_BLS) { ++ fc_fcp_unlock_pkt(fsp); ++ return; ++ } ++ ++ fsp->recov_seq = NULL; ++ ++ fsp->lp->tt.seq_get_xids(fsp->seq_ptr, &ox_id, &rx_id); ++ switch (fc_frame_payload_op(fp)) { ++ case ELS_LS_ACC: ++ fsp->recov_retry = 0; ++ fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); ++ break; ++ case ELS_LS_RJT: ++ default: ++ fc_timeout_error(fsp); ++ break; ++ } ++ fc_fcp_unlock_pkt(fsp); ++ fsp->lp->tt.exch_done(sp); ++out: ++ fc_frame_free(fp); ++ fc_fcp_pkt_release(fsp); /* drop hold for outstanding SRR */ ++} ++ ++static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) ++{ ++ if (fc_fcp_lock_pkt(fsp)) ++ goto out; ++ fsp->lp->tt.exch_done(fsp->recov_seq); ++ fsp->recov_seq = NULL; ++ switch (PTR_ERR(fp)) { ++ case -FC_EX_TIMEOUT: ++ if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) ++ fc_fcp_rec(fsp); ++ else ++ fc_timeout_error(fsp); ++ break; ++ case -FC_EX_CLOSED: /* e.g., link failure */ ++ /* fall through */ ++ default: ++ fc_fcp_retry_cmd(fsp); ++ break; ++ } ++ fc_fcp_unlock_pkt(fsp); ++out: ++ fc_fcp_pkt_release(fsp); /* drop hold for outstanding SRR */ ++} ++ ++static inline int fc_fcp_lport_queue_ready(struct fc_lport *lp) ++{ ++ /* lock ? */ ++ return (lp->state == LPORT_ST_READY) && (lp->link_status & FC_LINK_UP); ++} ++ ++/** ++ * fc_queuecommand - The queuecommand function of the scsi template ++ * @cmd: struct scsi_cmnd to be executed ++ * @done: Callback function to be called when cmd is completed ++ * ++ * this is the i/o strategy routine, called by the scsi layer ++ * this routine is called with holding the host_lock. ++ */ ++int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) ++{ ++ struct fc_lport *lp; ++ struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); ++ struct fc_fcp_pkt *sp; ++ struct fc_rport_libfc_priv *rp; ++ int rval; ++ int rc = 0; ++ struct fcoe_dev_stats *stats; ++ ++ lp = shost_priv(sc_cmd->device->host); ++ ++ rval = fc_remote_port_chkready(rport); ++ if (rval) { ++ sc_cmd->result = rval; ++ done(sc_cmd); ++ goto out; ++ } ++ ++ if (!*(struct fc_remote_port **)rport->dd_data) { ++ /* ++ * rport is transitioning from blocked/deleted to ++ * online ++ */ ++ sc_cmd->result = DID_IMM_RETRY << 16; ++ done(sc_cmd); ++ goto out; ++ } ++ ++ rp = rport->dd_data; ++ ++ if (!fc_fcp_lport_queue_ready(lp)) { ++ rc = SCSI_MLQUEUE_HOST_BUSY; ++ goto out; ++ } ++ ++ sp = fc_fcp_pkt_alloc(lp, GFP_ATOMIC); ++ if (sp == NULL) { ++ rc = SCSI_MLQUEUE_HOST_BUSY; ++ goto out; ++ } ++ ++ /* ++ * build the libfc request pkt ++ */ ++ sp->cmd = sc_cmd; /* save the cmd */ ++ sp->lp = lp; /* save the softc ptr */ ++ sp->rport = rport; /* set the remote port ptr */ ++ sc_cmd->scsi_done = done; ++ ++ /* ++ * set up the transfer length ++ */ ++ sp->data_len = scsi_bufflen(sc_cmd); ++ sp->xfer_len = 0; ++ ++ /* ++ * setup the data direction ++ */ ++ stats = lp->dev_stats[smp_processor_id()]; ++ if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { ++ sp->req_flags = FC_SRB_READ; ++ stats->InputRequests++; ++ stats->InputMegabytes = sp->data_len; ++ } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { ++ sp->req_flags = FC_SRB_WRITE; ++ stats->OutputRequests++; ++ stats->OutputMegabytes = sp->data_len; ++ } else { ++ sp->req_flags = 0; ++ stats->ControlRequests++; ++ } ++ ++ sp->tgt_flags = rp->flags; ++ ++ init_timer(&sp->timer); ++ sp->timer.data = (unsigned long)sp; ++ ++ /* ++ * send it to the lower layer ++ * if we get -1 return then put the request in the pending ++ * queue. ++ */ ++ rval = fc_fcp_pkt_send(lp, sp); ++ if (rval != 0) { ++ sp->state = FC_SRB_FREE; ++ fc_fcp_pkt_release(sp); ++ rc = SCSI_MLQUEUE_HOST_BUSY; ++ } ++out: ++ return rc; ++} ++EXPORT_SYMBOL(fc_queuecommand); ++ ++/** ++ * fc_io_compl - Handle responses for completed commands ++ * @sp: scsi packet ++ * ++ * Translates a error to a Linux SCSI error. ++ * ++ * The fcp packet lock must be held when calling. ++ */ ++static void fc_io_compl(struct fc_fcp_pkt *sp) ++{ ++ struct fc_fcp_internal *si; ++ struct scsi_cmnd *sc_cmd; ++ struct fc_lport *lp; ++ unsigned long flags; ++ ++ sp->state |= FC_SRB_COMPL; ++ if (!(sp->state & FC_SRB_FCP_PROCESSING_TMO)) { ++ spin_unlock_bh(&sp->scsi_pkt_lock); ++ del_timer_sync(&sp->timer); ++ spin_lock_bh(&sp->scsi_pkt_lock); ++ } ++ ++ lp = sp->lp; ++ si = fc_get_scsi_internal(lp); ++ spin_lock_irqsave(lp->host->host_lock, flags); ++ if (!sp->cmd) { ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++ return; ++ } ++ ++ /* ++ * if a command timed out while we had to try and throttle IO ++ * and it is now getting cleaned up, then we are about to ++ * try again so clear the throttled flag incase we get more ++ * time outs. ++ */ ++ if (si->throttled && sp->state & FC_SRB_NOMEM) ++ si->throttled = 0; ++ ++ sc_cmd = sp->cmd; ++ sp->cmd = NULL; ++ ++ if (!sc_cmd->SCp.ptr) { ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++ return; ++ } ++ ++ CMD_SCSI_STATUS(sc_cmd) = sp->cdb_status; ++ switch (sp->status_code) { ++ case FC_COMPLETE: ++ if (sp->cdb_status == 0) { ++ /* ++ * good I/O status ++ */ ++ sc_cmd->result = DID_OK << 16; ++ if (sp->scsi_resid) ++ CMD_RESID_LEN(sc_cmd) = sp->scsi_resid; ++ } else if (sp->cdb_status == QUEUE_FULL) { ++ struct scsi_device *tmp_sdev; ++ struct scsi_device *sdev = sc_cmd->device; ++ ++ shost_for_each_device(tmp_sdev, sdev->host) { ++ if (tmp_sdev->id != sdev->id) ++ continue; ++ ++ if (tmp_sdev->queue_depth > 1) { ++ scsi_track_queue_full(tmp_sdev, ++ tmp_sdev-> ++ queue_depth - 1); ++ } ++ } ++ sc_cmd->result = (DID_OK << 16) | sp->cdb_status; ++ } else { ++ /* ++ * transport level I/O was ok but scsi ++ * has non zero status ++ */ ++ sc_cmd->result = (DID_OK << 16) | sp->cdb_status; ++ } ++ break; ++ case FC_ERROR: ++ if (sp->io_status & (SUGGEST_RETRY << 24)) ++ sc_cmd->result = DID_IMM_RETRY << 16; ++ else ++ sc_cmd->result = (DID_ERROR << 16) | sp->io_status; ++ break; ++ case FC_DATA_UNDRUN: ++ if (sp->cdb_status == 0) { ++ /* ++ * scsi status is good but transport level ++ * underrun. for read it should be an error?? ++ */ ++ sc_cmd->result = (DID_OK << 16) | sp->cdb_status; ++ } else { ++ /* ++ * scsi got underrun, this is an error ++ */ ++ CMD_RESID_LEN(sc_cmd) = sp->scsi_resid; ++ sc_cmd->result = (DID_ERROR << 16) | sp->cdb_status; ++ } ++ break; ++ case FC_DATA_OVRRUN: ++ /* ++ * overrun is an error ++ */ ++ sc_cmd->result = (DID_ERROR << 16) | sp->cdb_status; ++ break; ++ case FC_CMD_ABORTED: ++ sc_cmd->result = (DID_ABORT << 16) | sp->io_status; ++ break; ++ case FC_CMD_TIME_OUT: ++ sc_cmd->result = (DID_BUS_BUSY << 16) | sp->io_status; ++ break; ++ case FC_CMD_RESET: ++ sc_cmd->result = (DID_RESET << 16); ++ break; ++ case FC_HRD_ERROR: ++ sc_cmd->result = (DID_NO_CONNECT << 16); ++ break; ++ default: ++ sc_cmd->result = (DID_ERROR << 16); ++ break; ++ } ++ ++ list_del(&sp->list); ++ sc_cmd->SCp.ptr = NULL; ++ sc_cmd->scsi_done(sc_cmd); ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++ ++ /* release ref from initial allocation in queue command */ ++ fc_fcp_pkt_release(sp); ++} ++ ++/** ++ * fc_eh_abort - Abort a command...from scsi host template ++ * @sc_cmd: scsi command to abort ++ * ++ * send ABTS to the target device and wait for the response ++ * sc_cmd is the pointer to the command to be aborted. ++ */ ++int fc_eh_abort(struct scsi_cmnd *sc_cmd) ++{ ++ struct fc_fcp_pkt *sp; ++ struct fc_lport *lp; ++ int rc = FAILED; ++ unsigned long flags; ++ ++ lp = shost_priv(sc_cmd->device->host); ++ if (lp->state != LPORT_ST_READY) ++ return rc; ++ else if (!(lp->link_status & FC_LINK_UP)) ++ return rc; ++ ++ spin_lock_irqsave(lp->host->host_lock, flags); ++ sp = CMD_SP(sc_cmd); ++ if (!sp) { ++ /* command completed while scsi eh was setting up */ ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++ return SUCCESS; ++ } ++ /* grab a ref so the sp and sc_cmd cannot be relased from under us */ ++ fc_fcp_pkt_hold(sp); ++ spin_unlock_irqrestore(lp->host->host_lock, flags); ++ ++ if (fc_fcp_lock_pkt(sp)) { ++ /* completed while we were waiting for timer to be deleted */ ++ rc = SUCCESS; ++ goto release_pkt; ++ } ++ ++ rc = fc_fcp_pkt_abort(lp, sp); ++ fc_fcp_unlock_pkt(sp); ++ ++release_pkt: ++ fc_fcp_pkt_release(sp); ++ return rc; ++} ++EXPORT_SYMBOL(fc_eh_abort); ++ ++/** ++ * fc_eh_device_reset: Reset a single LUN ++ * @sc_cmd: scsi command ++ * ++ * Set from scsi host template to send tm cmd to the target and wait for the ++ * response. ++ */ ++int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) ++{ ++ struct fc_lport *lp; ++ struct fc_fcp_pkt *sp; ++ struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); ++ int rc = FAILED; ++ struct fc_rport_libfc_priv *rp; ++ int rval; ++ ++ rval = fc_remote_port_chkready(rport); ++ if (rval) ++ goto out; ++ ++ rp = rport->dd_data; ++ lp = shost_priv(sc_cmd->device->host); ++ ++ if (lp->state != LPORT_ST_READY) ++ return rc; ++ ++ sp = fc_fcp_pkt_alloc(lp, GFP_NOIO); ++ if (sp == NULL) { ++ FC_DBG("could not allocate scsi_pkt\n"); ++ sc_cmd->result = DID_NO_CONNECT << 16; ++ goto out; ++ } ++ ++ /* ++ * Build the libfc request pkt. Do not set the scsi cmnd, because ++ * the sc passed in is not setup for execution like when sent ++ * through the queuecommand callout. ++ */ ++ sp->lp = lp; /* save the softc ptr */ ++ sp->rport = rport; /* set the remote port ptr */ ++ ++ /* ++ * flush outstanding commands ++ */ ++ rc = fc_lun_reset(lp, sp, scmd_id(sc_cmd), sc_cmd->device->lun); ++ sp->state = FC_SRB_FREE; ++ fc_fcp_pkt_release(sp); ++ ++out: ++ return rc; ++} ++EXPORT_SYMBOL(fc_eh_device_reset); ++ ++/** ++ * fc_eh_host_reset - The reset function will reset the ports on the host. ++ * @sc_cmd: scsi command ++ */ ++int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) ++{ ++ struct Scsi_Host *shost = sc_cmd->device->host; ++ struct fc_lport *lp = shost_priv(shost); ++ unsigned long wait_tmo; ++ ++ lp->tt.lport_reset(lp); ++ wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT; ++ while (!fc_fcp_lport_queue_ready(lp) && time_before(jiffies, wait_tmo)) ++ msleep(1000); ++ ++ if (fc_fcp_lport_queue_ready(lp)) { ++ shost_printk(KERN_INFO, shost, "Host reset succeeded.\n"); ++ return SUCCESS; ++ } else { ++ shost_printk(KERN_INFO, shost, "Host reset succeeded failed." ++ "lport not ready.\n"); ++ return FAILED; ++ } ++} ++EXPORT_SYMBOL(fc_eh_host_reset); ++ ++/** ++ * fc_slave_alloc - configure queue depth ++ * @sdev: scsi device ++ * ++ * Configures queue depth based on host's cmd_per_len. If not set ++ * then we use the libfc default. ++ */ ++int fc_slave_alloc(struct scsi_device *sdev) ++{ ++ struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); ++ int queue_depth; ++ ++ if (!rport || fc_remote_port_chkready(rport)) ++ return -ENXIO; ++ ++ if (sdev->tagged_supported) { ++ if (sdev->host->hostt->cmd_per_lun) ++ queue_depth = sdev->host->hostt->cmd_per_lun; ++ else ++ queue_depth = FC_FCP_DFLT_QUEUE_DEPTH; ++ scsi_activate_tcq(sdev, queue_depth); ++ } ++ return 0; ++} ++EXPORT_SYMBOL(fc_slave_alloc); ++ ++int fc_change_queue_depth(struct scsi_device *sdev, int qdepth) ++{ ++ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); ++ return sdev->queue_depth; ++} ++EXPORT_SYMBOL(fc_change_queue_depth); ++ ++int fc_change_queue_type(struct scsi_device *sdev, int tag_type) ++{ ++ if (sdev->tagged_supported) { ++ scsi_set_tag_type(sdev, tag_type); ++ if (tag_type) ++ scsi_activate_tcq(sdev, sdev->queue_depth); ++ else ++ scsi_deactivate_tcq(sdev, sdev->queue_depth); ++ } else ++ tag_type = 0; ++ ++ return tag_type; ++} ++EXPORT_SYMBOL(fc_change_queue_type); ++ ++void fc_fcp_destroy(struct fc_lport *lp) ++{ ++ struct fc_fcp_internal *si = fc_get_scsi_internal(lp); ++ ++ if (!list_empty(&si->scsi_pkt_queue)) ++ printk(KERN_ERR "Leaked scsi packets.\n"); ++ ++ mempool_destroy(si->scsi_pkt_pool); ++ kfree(si); ++ lp->scsi_priv = NULL; ++} ++EXPORT_SYMBOL(fc_fcp_destroy); ++ ++int fc_fcp_init(struct fc_lport *lp) ++{ ++ int rc; ++ struct fc_fcp_internal *si; ++ ++ if (!lp->tt.scsi_cleanup) ++ lp->tt.scsi_cleanup = fc_fcp_cleanup; ++ ++ if (!lp->tt.scsi_abort_io) ++ lp->tt.scsi_abort_io = fc_fcp_abort_io; ++ ++ si = kzalloc(sizeof(struct fc_fcp_internal), GFP_KERNEL); ++ if (!si) ++ return -ENOMEM; ++ lp->scsi_priv = si; ++ INIT_LIST_HEAD(&si->scsi_pkt_queue); ++ ++ si->scsi_pkt_pool = mempool_create_slab_pool(2, scsi_pkt_cachep); ++ if (!si->scsi_pkt_pool) { ++ rc = -ENOMEM; ++ goto free_internal; ++ } ++ return 0; ++ ++free_internal: ++ kfree(si); ++ return rc; ++} ++EXPORT_SYMBOL(fc_fcp_init); ++ ++static int __init libfc_init(void) ++{ ++ int rc; ++ ++ scsi_pkt_cachep = kmem_cache_create("libfc_fcp_pkt", ++ sizeof(struct fc_fcp_pkt), ++ 0, SLAB_HWCACHE_ALIGN, NULL); ++ if (scsi_pkt_cachep == NULL) { ++ FC_DBG("Unable to allocate SRB cache...module load failed!"); ++ return -ENOMEM; ++ } ++ ++ rc = fc_setup_exch_mgr(); ++ if (rc) ++ kmem_cache_destroy(scsi_pkt_cachep); ++ return rc; ++} ++ ++static void __exit libfc_exit(void) ++{ ++ kmem_cache_destroy(scsi_pkt_cachep); ++ fc_destroy_exch_mgr(); ++} ++ ++module_init(libfc_init); ++module_exit(libfc_exit); +diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c +new file mode 100644 +index 0000000..7ba241e +--- /dev/null ++++ b/drivers/scsi/libfc/fc_frame.c +@@ -0,0 +1,88 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Frame allocation. ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* ++ * Check the CRC in a frame. ++ */ ++u32 fc_frame_crc_check(struct fc_frame *fp) ++{ ++ u32 crc; ++ u32 error; ++ const u8 *bp; ++ unsigned int len; ++ ++ WARN_ON(!fc_frame_is_linear(fp)); ++ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; ++ len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */ ++ bp = (const u8 *) fr_hdr(fp); ++ crc = ~crc32(~0, bp, len); ++ error = crc ^ *(u32 *) (bp + len); ++ return error; ++} ++EXPORT_SYMBOL(fc_frame_crc_check); ++ ++/* ++ * Allocate a frame intended to be sent via fcoe_xmit. ++ * Get an sk_buff for the frame and set the length. ++ */ ++struct fc_frame *__fc_frame_alloc(size_t len) ++{ ++ struct fc_frame *fp; ++ struct sk_buff *skb; ++ ++ WARN_ON((len % sizeof(u32)) != 0); ++ len += sizeof(struct fc_frame_header); ++ skb = dev_alloc_skb(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM); ++ if (!skb) ++ return NULL; ++ fp = (struct fc_frame *) skb; ++ fc_frame_init(fp); ++ skb_reserve(skb, FC_FRAME_HEADROOM); ++ skb_put(skb, len); ++ return fp; ++} ++EXPORT_SYMBOL(__fc_frame_alloc); ++ ++ ++struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) ++{ ++ struct fc_frame *fp; ++ size_t fill; ++ ++ fill = payload_len % 4; ++ if (fill != 0) ++ fill = 4 - fill; ++ fp = __fc_frame_alloc(payload_len + fill); ++ if (fp) { ++ memset((char *) fr_hdr(fp) + payload_len, 0, fill); ++ /* trim is OK, we just allocated it so there are no fragments */ ++ skb_trim(fp_skb(fp), payload_len); ++ } ++ return fp; ++} +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +new file mode 100644 +index 0000000..b390a32 +--- /dev/null ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -0,0 +1,926 @@ ++/* ++ * Copyright(c) 2007 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Logical interface support. ++ */ ++ ++#include ++#include ++ ++#include ++ ++#include ++ ++/* Fabric IDs to use for point-to-point mode, chosen on whims. */ ++#define FC_LOCAL_PTP_FID_LO 0x010101 ++#define FC_LOCAL_PTP_FID_HI 0x010102 ++ ++#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/ ++ ++static int fc_lport_debug; ++ ++static void fc_lport_enter_flogi(struct fc_lport *); ++static void fc_lport_enter_logo(struct fc_lport *); ++ ++static const char *fc_lport_state_names[] = { ++ [LPORT_ST_NONE] = "none", ++ [LPORT_ST_FLOGI] = "FLOGI", ++ [LPORT_ST_DNS] = "dNS", ++ [LPORT_ST_REG_PN] = "REG_PN", ++ [LPORT_ST_REG_FT] = "REG_FT", ++ [LPORT_ST_SCR] = "SCR", ++ [LPORT_ST_READY] = "ready", ++ [LPORT_ST_DNS_STOP] = "stop", ++ [LPORT_ST_LOGO] = "LOGO", ++ [LPORT_ST_RESET] = "reset", ++}; ++ ++static int fc_frame_drop(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ fc_frame_free(fp); ++ return 0; ++} ++ ++static const char *fc_lport_state(struct fc_lport *lp) ++{ ++ const char *cp; ++ ++ cp = fc_lport_state_names[lp->state]; ++ if (!cp) ++ cp = "unknown"; ++ return cp; ++} ++ ++static void fc_lport_ptp_setup(struct fc_lport *lp, ++ u32 remote_fid, u64 remote_wwpn, ++ u64 remote_wwnn) ++{ ++ struct fc_rport *rport; ++ struct fc_rport_identifiers ids = { ++ .port_id = remote_fid, ++ .port_name = remote_wwpn, ++ .node_name = remote_wwnn, ++ }; ++ ++ /* ++ * if we have to create a rport the fc class can sleep so we must ++ * drop the lock here ++ */ ++ fc_lport_unlock(lp); ++ rport = lp->tt.rport_lookup(lp, ids.port_id); /* lookup and hold */ ++ if (rport == NULL) ++ rport = lp->tt.rport_create(lp, &ids); /* create and hold */ ++ fc_lport_lock(lp); ++ if (rport) { ++ if (lp->ptp_rp) ++ fc_remote_port_delete(lp->ptp_rp); ++ lp->ptp_rp = rport; ++ fc_lport_state_enter(lp, LPORT_ST_READY); ++ } ++} ++ ++static void fc_lport_ptp_clear(struct fc_lport *lp) ++{ ++ if (lp->ptp_rp) { ++ fc_remote_port_delete(lp->ptp_rp); ++ lp->ptp_rp = NULL; ++ } ++} ++ ++/* ++ * Routines to support struct fc_function_template ++ */ ++void fc_get_host_port_state(struct Scsi_Host *shost) ++{ ++ struct fc_lport *lp = shost_priv(shost); ++ ++ if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP) ++ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; ++ else ++ fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; ++} ++EXPORT_SYMBOL(fc_get_host_port_state); ++ ++/* ++ * Fill in FLOGI command for request. ++ */ ++static void ++fc_lport_flogi_fill(struct fc_lport *lp, ++ struct fc_els_flogi *flogi, unsigned int op) ++{ ++ struct fc_els_csp *sp; ++ struct fc_els_cssp *cp; ++ ++ memset(flogi, 0, sizeof(*flogi)); ++ flogi->fl_cmd = (u8) op; ++ put_unaligned_be64(lp->wwpn, &flogi->fl_wwpn); ++ put_unaligned_be64(lp->wwnn, &flogi->fl_wwnn); ++ sp = &flogi->fl_csp; ++ sp->sp_hi_ver = 0x20; ++ sp->sp_lo_ver = 0x20; ++ sp->sp_bb_cred = htons(10); /* this gets set by gateway */ ++ sp->sp_bb_data = htons((u16) lp->mfs); ++ cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ ++ cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); ++ if (op != ELS_FLOGI) { ++ sp->sp_features = htons(FC_SP_FT_CIRO); ++ sp->sp_tot_seq = htons(255); /* seq. we accept */ ++ sp->sp_rel_off = htons(0x1f); ++ sp->sp_e_d_tov = htonl(lp->e_d_tov); ++ ++ cp->cp_rdfs = htons((u16) lp->mfs); ++ cp->cp_con_seq = htons(255); ++ cp->cp_open_seq = 1; ++ } ++} ++ ++/* ++ * Set the fid. This indicates that we have a new connection to the ++ * fabric so we should reset our list of fc_rports. Passing a fid of ++ * 0 will also reset the rport list regardless of the previous fid. ++ */ ++static void fc_lport_set_fid(struct fc_lport *lp, u32 fid) ++{ ++ if (fid != 0 && lp->fid == fid) ++ return; ++ ++ if (fc_lport_debug) ++ FC_DBG("changing local port fid from %x to %x\n", ++ lp->fid, fid); ++ lp->fid = fid; ++ lp->tt.rport_reset_list(lp); ++} ++ ++/* ++ * Add a supported FC-4 type. ++ */ ++static void fc_lport_add_fc4_type(struct fc_lport *lp, enum fc_fh_type type) ++{ ++ __be32 *mp; ++ ++ mp = &lp->fcts.ff_type_map[type / FC_NS_BPW]; ++ *mp = htonl(ntohl(*mp) | 1UL << (type % FC_NS_BPW)); ++} ++ ++/* ++ * Handle received RLIR - registered link incident report. ++ */ ++static void fc_lport_rlir_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lp) ++{ ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ fc_frame_free(fp); ++} ++ ++/* ++ * Handle received ECHO. ++ */ ++static void fc_lport_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, ++ struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ unsigned int len; ++ void *pp; ++ void *dp; ++ u32 f_ctl; ++ ++ len = fr_len(in_fp) - sizeof(struct fc_frame_header); ++ pp = fc_frame_payload_get(in_fp, len); ++ ++ if (len < sizeof(__be32)) ++ len = sizeof(__be32); ++ fp = fc_frame_alloc(lp, len); ++ if (fp) { ++ dp = fc_frame_payload_get(fp, len); ++ memcpy(dp, pp, len); ++ *((u32 *)dp) = htonl(ELS_LS_ACC << 24); ++ sp = lp->tt.seq_start_next(sp); ++ f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ lp->tt.seq_send(lp, sp, fp, f_ctl); ++ } ++ fc_frame_free(in_fp); ++} ++ ++/* ++ * Handle received RNID. ++ */ ++static void fc_lport_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, ++ struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_els_rnid *req; ++ struct { ++ struct fc_els_rnid_resp rnid; ++ struct fc_els_rnid_cid cid; ++ struct fc_els_rnid_gen gen; ++ } *rp; ++ struct fc_seq_els_data rjt_data; ++ u8 fmt; ++ size_t len; ++ u32 f_ctl; ++ ++ req = fc_frame_payload_get(in_fp, sizeof(*req)); ++ if (!req) { ++ rjt_data.fp = NULL; ++ rjt_data.reason = ELS_RJT_LOGIC; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ } else { ++ fmt = req->rnid_fmt; ++ len = sizeof(*rp); ++ if (fmt != ELS_RNIDF_GEN || ++ ntohl(lp->rnid_gen.rnid_atype) == 0) { ++ fmt = ELS_RNIDF_NONE; /* nothing to provide */ ++ len -= sizeof(rp->gen); ++ } ++ fp = fc_frame_alloc(lp, len); ++ if (fp) { ++ rp = fc_frame_payload_get(fp, len); ++ memset(rp, 0, len); ++ rp->rnid.rnid_cmd = ELS_LS_ACC; ++ rp->rnid.rnid_fmt = fmt; ++ rp->rnid.rnid_cid_len = sizeof(rp->cid); ++ rp->cid.rnid_wwpn = htonll(lp->wwpn); ++ rp->cid.rnid_wwnn = htonll(lp->wwnn); ++ if (fmt == ELS_RNIDF_GEN) { ++ rp->rnid.rnid_sid_len = sizeof(rp->gen); ++ memcpy(&rp->gen, &lp->rnid_gen, ++ sizeof(rp->gen)); ++ } ++ sp = lp->tt.seq_start_next(sp); ++ f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ lp->tt.seq_send(lp, sp, fp, f_ctl); ++ } ++ } ++ fc_frame_free(in_fp); ++} ++ ++/* ++ * Handle received fabric logout request. ++ */ ++static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lp) ++{ ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ fc_lport_enter_reset(lp); ++ fc_frame_free(fp); ++} ++ ++/* ++ * Receive request frame ++ */ ++ ++int fc_fabric_login(struct fc_lport *lp) ++{ ++ int rc = -1; ++ ++ if (lp->state == LPORT_ST_NONE) { ++ fc_lport_lock(lp); ++ fc_lport_enter_reset(lp); ++ fc_lport_unlock(lp); ++ rc = 0; ++ } ++ return rc; ++} ++EXPORT_SYMBOL(fc_fabric_login); ++ ++/** ++ * fc_linkup - link up notification ++ * @dev: Pointer to fc_lport . ++ **/ ++void fc_linkup(struct fc_lport *lp) ++{ ++ if ((lp->link_status & FC_LINK_UP) != FC_LINK_UP) { ++ lp->link_status |= FC_LINK_UP; ++ fc_lport_lock(lp); ++ if (lp->state == LPORT_ST_RESET) ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++} ++EXPORT_SYMBOL(fc_linkup); ++ ++/** ++ * fc_linkdown - link down notification ++ * @dev: Pointer to fc_lport . ++ **/ ++void fc_linkdown(struct fc_lport *lp) ++{ ++ if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP) { ++ lp->link_status &= ~(FC_LINK_UP); ++ fc_lport_enter_reset(lp); ++ lp->tt.scsi_cleanup(lp); ++ } ++} ++EXPORT_SYMBOL(fc_linkdown); ++ ++void fc_pause(struct fc_lport *lp) ++{ ++ lp->link_status |= FC_PAUSE; ++} ++EXPORT_SYMBOL(fc_pause); ++ ++void fc_unpause(struct fc_lport *lp) ++{ ++ lp->link_status &= ~(FC_PAUSE); ++} ++EXPORT_SYMBOL(fc_unpause); ++ ++int fc_fabric_logoff(struct fc_lport *lp) ++{ ++ fc_lport_lock(lp); ++ switch (lp->state) { ++ case LPORT_ST_NONE: ++ break; ++ case LPORT_ST_FLOGI: ++ case LPORT_ST_LOGO: ++ case LPORT_ST_RESET: ++ fc_lport_enter_reset(lp); ++ break; ++ case LPORT_ST_DNS: ++ case LPORT_ST_DNS_STOP: ++ fc_lport_enter_logo(lp); ++ break; ++ case LPORT_ST_REG_PN: ++ case LPORT_ST_REG_FT: ++ case LPORT_ST_SCR: ++ case LPORT_ST_READY: ++ lp->tt.disc_stop(lp); ++ break; ++ } ++ fc_lport_unlock(lp); ++ lp->tt.scsi_cleanup(lp); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_fabric_logoff); ++ ++/** ++ * fc_lport_destroy - unregister a fc_lport ++ * @lp: fc_lport pointer to unregister ++ * ++ * Return value: ++ * None ++ * Note: ++ * exit routine for fc_lport instance ++ * clean-up all the allocated memory ++ * and free up other system resources. ++ * ++ **/ ++int fc_lport_destroy(struct fc_lport *lp) ++{ ++ fc_lport_lock(lp); ++ fc_lport_state_enter(lp, LPORT_ST_LOGO); ++ fc_lport_unlock(lp); ++ ++ cancel_delayed_work_sync(&lp->ns_disc_work); ++ ++ lp->tt.scsi_abort_io(lp); ++ ++ lp->tt.frame_send = fc_frame_drop; ++ ++ lp->tt.exch_mgr_reset(lp->emp, 0, 0); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_lport_destroy); ++ ++int fc_set_mfs(struct fc_lport *lp, u32 mfs) ++{ ++ unsigned int old_mfs; ++ int rc = -1; ++ ++ old_mfs = lp->mfs; ++ ++ if (mfs >= FC_MIN_MAX_FRAME) { ++ mfs &= ~3; ++ WARN_ON((size_t) mfs < FC_MIN_MAX_FRAME); ++ if (mfs > FC_MAX_FRAME) ++ mfs = FC_MAX_FRAME; ++ mfs -= sizeof(struct fc_frame_header); ++ lp->mfs = mfs; ++ rc = 0; ++ } ++ ++ if (!rc && mfs < old_mfs) { ++ lp->ns_disc_done = 0; ++ fc_lport_enter_reset(lp); ++ } ++ return rc; ++} ++EXPORT_SYMBOL(fc_set_mfs); ++ ++/* ++ * re-enter state for retrying a request after a timeout or alloc failure. ++ */ ++static void fc_lport_enter_retry(struct fc_lport *lp) ++{ ++ switch (lp->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_READY: ++ case LPORT_ST_RESET: ++ case LPORT_ST_DNS: ++ case LPORT_ST_DNS_STOP: ++ case LPORT_ST_REG_PN: ++ case LPORT_ST_REG_FT: ++ case LPORT_ST_SCR: ++ WARN_ON(1); ++ break; ++ case LPORT_ST_FLOGI: ++ fc_lport_enter_flogi(lp); ++ break; ++ case LPORT_ST_LOGO: ++ fc_lport_enter_logo(lp); ++ break; ++ } ++} ++ ++/* ++ * enter next state for handling an exchange reject or retry exhaustion ++ * in the current state. ++ */ ++static void fc_lport_enter_reject(struct fc_lport *lp) ++{ ++ switch (lp->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_READY: ++ case LPORT_ST_RESET: ++ case LPORT_ST_REG_PN: ++ case LPORT_ST_REG_FT: ++ case LPORT_ST_SCR: ++ case LPORT_ST_DNS_STOP: ++ case LPORT_ST_DNS: ++ WARN_ON(1); ++ break; ++ case LPORT_ST_FLOGI: ++ fc_lport_enter_flogi(lp); ++ break; ++ case LPORT_ST_LOGO: ++ fc_lport_enter_reset(lp); ++ break; ++ } ++} ++ ++/* ++ * Handle resource allocation problem by retrying in a bit. ++ */ ++static void fc_lport_retry(struct fc_lport *lp) ++{ ++ if (lp->retry_count == 0) ++ FC_DBG("local port %6x alloc failure in state %s " ++ "- will retry\n", lp->fid, fc_lport_state(lp)); ++ if (lp->retry_count < lp->max_retry_count) { ++ lp->retry_count++; ++ mod_timer(&lp->state_timer, ++ jiffies + msecs_to_jiffies(lp->e_d_tov)); ++ } else { ++ FC_DBG("local port %6x alloc failure in state %s " ++ "- retries exhausted\n", lp->fid, ++ fc_lport_state(lp)); ++ fc_lport_enter_reject(lp); ++ } ++} ++ ++/* ++ * A received FLOGI request indicates a point-to-point connection. ++ * Accept it with the common service parameters indicating our N port. ++ * Set up to do a PLOGI if we have the higher-number WWPN. ++ */ ++static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, ++ struct fc_frame *rx_fp, ++ struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_frame_header *fh; ++ struct fc_seq *sp; ++ struct fc_els_flogi *flp; ++ struct fc_els_flogi *new_flp; ++ u64 remote_wwpn; ++ u32 remote_fid; ++ u32 local_fid; ++ u32 f_ctl; ++ ++ fh = fc_frame_header_get(rx_fp); ++ remote_fid = ntoh24(fh->fh_s_id); ++ flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); ++ if (!flp) ++ goto out; ++ remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); ++ if (remote_wwpn == lp->wwpn) { ++ FC_DBG("FLOGI from port with same WWPN %llx " ++ "possible configuration error\n", remote_wwpn); ++ goto out; ++ } ++ FC_DBG("FLOGI from port WWPN %llx\n", remote_wwpn); ++ fc_lport_lock(lp); ++ ++ /* ++ * XXX what is the right thing to do for FIDs? ++ * The originator might expect our S_ID to be 0xfffffe. ++ * But if so, both of us could end up with the same FID. ++ */ ++ local_fid = FC_LOCAL_PTP_FID_LO; ++ if (remote_wwpn < lp->wwpn) { ++ local_fid = FC_LOCAL_PTP_FID_HI; ++ if (!remote_fid || remote_fid == local_fid) ++ remote_fid = FC_LOCAL_PTP_FID_LO; ++ } else if (!remote_fid) { ++ remote_fid = FC_LOCAL_PTP_FID_HI; ++ } ++ fc_lport_set_fid(lp, local_fid); ++ ++ fp = fc_frame_alloc(lp, sizeof(*flp)); ++ if (fp) { ++ sp = lp->tt.seq_start_next(fr_seq(rx_fp)); ++ new_flp = fc_frame_payload_get(fp, sizeof(*flp)); ++ fc_lport_flogi_fill(lp, new_flp, ELS_FLOGI); ++ new_flp->fl_cmd = (u8) ELS_LS_ACC; ++ ++ /* ++ * Send the response. If this fails, the originator should ++ * repeat the sequence. ++ */ ++ f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ lp->tt.seq_send(lp, sp, fp, f_ctl); ++ ++ } else { ++ fc_lport_retry(lp); ++ } ++ fc_lport_ptp_setup(lp, remote_fid, remote_wwpn, ++ get_unaligned_be64(&flp->fl_wwnn)); ++ fc_lport_unlock(lp); ++ if (lp->tt.disc_start(lp)) ++ FC_DBG("target discovery start error\n"); ++out: ++ sp = fr_seq(rx_fp); ++ fc_frame_free(rx_fp); ++} ++ ++static void fc_lport_recv(struct fc_lport *lp, struct fc_seq *sp, ++ struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh = fc_frame_header_get(fp); ++ void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); ++ struct fc_rport *rport; ++ u32 s_id; ++ u32 d_id; ++ struct fc_seq_els_data rjt_data; ++ ++ /* ++ * Handle special ELS cases like FLOGI, LOGO, and ++ * RSCN here. These don't require a session. ++ * Even if we had a session, it might not be ready. ++ */ ++ if (fh->fh_type == FC_TYPE_ELS && fh->fh_r_ctl == FC_RCTL_ELS_REQ) { ++ /* ++ * Check opcode. ++ */ ++ recv = NULL; ++ switch (fc_frame_payload_op(fp)) { ++ case ELS_FLOGI: ++ recv = fc_lport_recv_flogi_req; ++ break; ++ case ELS_LOGO: ++ fh = fc_frame_header_get(fp); ++ if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) ++ recv = fc_lport_recv_logo_req; ++ break; ++ case ELS_RSCN: ++ recv = lp->tt.disc_recv_req; ++ break; ++ case ELS_ECHO: ++ recv = fc_lport_echo_req; ++ break; ++ case ELS_RLIR: ++ recv = fc_lport_rlir_req; ++ break; ++ case ELS_RNID: ++ recv = fc_lport_rnid_req; ++ break; ++ } ++ ++ if (recv) ++ recv(sp, fp, lp); ++ else { ++ /* ++ * Find session. ++ * If this is a new incoming PLOGI, we won't find it. ++ */ ++ s_id = ntoh24(fh->fh_s_id); ++ d_id = ntoh24(fh->fh_d_id); ++ ++ rport = lp->tt.rport_lookup(lp, s_id); ++ if (rport) { ++ lp->tt.rport_recv_req(sp, fp, rport); ++ put_device(&rport->dev); /* hold from lookup */ ++ } else { ++ rjt_data.fp = NULL; ++ rjt_data.reason = ELS_RJT_UNAB; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ++ ELS_LS_RJT, &rjt_data); ++ fc_frame_free(fp); ++ } ++ } ++ } else { ++ FC_DBG("dropping invalid frame (eof %x)\n", fr_eof(fp)); ++ fc_frame_free(fp); ++ } ++ ++ /* ++ * The common exch_done for all request may not be good ++ * if any request requires longer hold on exhange. XXX ++ */ ++ lp->tt.exch_done(sp); ++} ++ ++/* ++ * Put the local port back into the initial state. Reset all sessions. ++ * This is called after a SCSI reset or the driver is unloading ++ * or the program is exiting. ++ */ ++int fc_lport_enter_reset(struct fc_lport *lp) ++{ ++ if (fc_lport_debug) ++ FC_DBG("Processing RESET state\n"); ++ ++ if (lp->dns_rp) { ++ fc_remote_port_delete(lp->dns_rp); ++ lp->dns_rp = NULL; ++ } ++ fc_lport_ptp_clear(lp); ++ ++ /* ++ * Setting state RESET keeps fc_lport_error() callbacks ++ * by exch_mgr_reset() from recursing on the lock. ++ * It also causes fc_lport_sess_event() to ignore events. ++ * The lock is held for the duration of the time in RESET state. ++ */ ++ fc_lport_state_enter(lp, LPORT_ST_RESET); ++ lp->tt.exch_mgr_reset(lp->emp, 0, 0); ++ fc_lport_set_fid(lp, 0); ++ if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP) ++ fc_lport_enter_flogi(lp); ++ return 0; ++} ++EXPORT_SYMBOL(fc_lport_enter_reset); ++ ++/* ++ * Handle errors on local port requests. ++ * Don't get locks if in RESET state. ++ * The only possible errors so far are exchange TIMEOUT and CLOSED (reset). ++ */ ++static void fc_lport_error(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ if (lp->state == LPORT_ST_RESET) ++ return; ++ ++ fc_lport_lock(lp); ++ if (PTR_ERR(fp) == -FC_EX_TIMEOUT) { ++ if (lp->retry_count < lp->max_retry_count) { ++ lp->retry_count++; ++ fc_lport_enter_retry(lp); ++ } else { ++ fc_lport_enter_reject(lp); ++ ++ } ++ } ++ if (fc_lport_debug) ++ FC_DBG("error %ld retries %d limit %d\n", ++ PTR_ERR(fp), lp->retry_count, lp->max_retry_count); ++ fc_lport_unlock(lp); ++} ++ ++static void fc_lport_timeout(unsigned long lp_arg) ++{ ++ struct fc_lport *lp = (struct fc_lport *)lp_arg; ++ ++ fc_lport_lock(lp); ++ fc_lport_enter_retry(lp); ++ fc_lport_unlock(lp); ++} ++ ++static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) ++{ ++ struct fc_lport *lp = lp_arg; ++ ++ if (IS_ERR(fp)) ++ fc_lport_error(lp, fp); ++ else { ++ fc_frame_free(fp); ++ fc_lport_lock(lp); ++ fc_lport_enter_reset(lp); ++ fc_lport_unlock(lp); ++ } ++} ++ ++/* Logout of the FC fabric */ ++static void fc_lport_enter_logo(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_els_logo *logo; ++ ++ if (fc_lport_debug) ++ FC_DBG("Processing LOGO state\n"); ++ ++ fc_lport_state_enter(lp, LPORT_ST_LOGO); ++ ++ /* DNS session should be closed so we can release it here */ ++ if (lp->dns_rp) { ++ fc_remote_port_delete(lp->dns_rp); ++ lp->dns_rp = NULL; ++ } ++ ++ fp = fc_frame_alloc(lp, sizeof(*logo)); ++ if (!fp) { ++ FC_DBG("failed to allocate frame\n"); ++ return; ++ } ++ ++ logo = fc_frame_payload_get(fp, sizeof(*logo)); ++ memset(logo, 0, sizeof(*logo)); ++ logo->fl_cmd = ELS_LOGO; ++ hton24(logo->fl_n_port_id, lp->fid); ++ logo->fl_n_port_wwn = htonll(lp->wwpn); ++ ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ fc_frame_set_offset(fp, 0); ++ ++ lp->tt.exch_seq_send(lp, fp, ++ fc_lport_logo_resp, ++ lp, lp->e_d_tov, ++ lp->fid, FC_FID_FLOGI, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++} ++ ++static int fc_lport_logout(struct fc_lport *lp) ++{ ++ fc_lport_lock(lp); ++ if (lp->state != LPORT_ST_LOGO) ++ fc_lport_enter_logo(lp); ++ fc_lport_unlock(lp); ++ return 0; ++} ++ ++/* ++ * Handle incoming ELS FLOGI response. ++ * Save parameters of remote switch. Finish exchange. ++ */ ++static void ++fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) ++{ ++ struct fc_lport *lp = lp_arg; ++ struct fc_frame_header *fh; ++ struct fc_els_flogi *flp; ++ u32 did; ++ u16 csp_flags; ++ unsigned int r_a_tov; ++ unsigned int e_d_tov; ++ u16 mfs; ++ ++ if (IS_ERR(fp)) { ++ fc_lport_error(lp, fp); ++ return; ++ } ++ ++ fh = fc_frame_header_get(fp); ++ did = ntoh24(fh->fh_d_id); ++ if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { ++ if (fc_lport_debug) ++ FC_DBG("assigned fid %x\n", did); ++ fc_lport_lock(lp); ++ fc_lport_set_fid(lp, did); ++ flp = fc_frame_payload_get(fp, sizeof(*flp)); ++ if (flp) { ++ mfs = ntohs(flp->fl_csp.sp_bb_data) & ++ FC_SP_BB_DATA_MASK; ++ if (mfs >= FC_SP_MIN_MAX_PAYLOAD && ++ mfs < lp->mfs) ++ lp->mfs = mfs; ++ csp_flags = ntohs(flp->fl_csp.sp_features); ++ r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov); ++ e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); ++ if (csp_flags & FC_SP_FT_EDTR) ++ e_d_tov /= 1000000; ++ if ((csp_flags & FC_SP_FT_FPORT) == 0) { ++ if (e_d_tov > lp->e_d_tov) ++ lp->e_d_tov = e_d_tov; ++ lp->r_a_tov = 2 * e_d_tov; ++ FC_DBG("point-to-point mode\n"); ++ fc_lport_ptp_setup(lp, ntoh24(fh->fh_s_id), ++ get_unaligned_be64( ++ &flp->fl_wwpn), ++ get_unaligned_be64( ++ &flp->fl_wwnn)); ++ } else { ++ lp->e_d_tov = e_d_tov; ++ lp->r_a_tov = r_a_tov; ++ lp->tt.dns_register(lp); ++ } ++ } ++ fc_lport_unlock(lp); ++ if (flp) { ++ csp_flags = ntohs(flp->fl_csp.sp_features); ++ if ((csp_flags & FC_SP_FT_FPORT) == 0) { ++ if (lp->tt.disc_start(lp)) ++ FC_DBG("target disc start error\n"); ++ } ++ } ++ } else { ++ FC_DBG("bad FLOGI response\n"); ++ } ++ fc_frame_free(fp); ++} ++ ++/* ++ * Send ELS (extended link service) FLOGI request to peer. ++ */ ++static void fc_lport_flogi_send(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_els_flogi *flp; ++ ++ fp = fc_frame_alloc(lp, sizeof(*flp)); ++ if (!fp) ++ return fc_lport_retry(lp); ++ ++ flp = fc_frame_payload_get(fp, sizeof(*flp)); ++ fc_lport_flogi_fill(lp, flp, ELS_FLOGI); ++ ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ fc_frame_set_offset(fp, 0); ++ ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_lport_flogi_resp, ++ lp, lp->e_d_tov, ++ 0, FC_FID_FLOGI, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_lport_retry(lp); ++ ++} ++ ++void fc_lport_enter_flogi(struct fc_lport *lp) ++{ ++ if (fc_lport_debug) ++ FC_DBG("Processing FLOGI state\n"); ++ fc_lport_state_enter(lp, LPORT_ST_FLOGI); ++ fc_lport_flogi_send(lp); ++} ++ ++/* Configure a fc_lport */ ++int fc_lport_config(struct fc_lport *lp) ++{ ++ setup_timer(&lp->state_timer, fc_lport_timeout, (unsigned long)lp); ++ spin_lock_init(&lp->state_lock); ++ ++ fc_lport_lock(lp); ++ fc_lport_state_enter(lp, LPORT_ST_NONE); ++ fc_lport_unlock(lp); ++ ++ lp->ns_disc_delay = DNS_DELAY; ++ ++ fc_lport_add_fc4_type(lp, FC_TYPE_FCP); ++ fc_lport_add_fc4_type(lp, FC_TYPE_CT); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_lport_config); ++ ++int fc_lport_init(struct fc_lport *lp) ++{ ++ if (!lp->tt.lport_recv) ++ lp->tt.lport_recv = fc_lport_recv; ++ ++ if (!lp->tt.lport_login) ++ lp->tt.lport_login = fc_lport_enter_reset; ++ ++ if (!lp->tt.lport_reset) ++ lp->tt.lport_reset = fc_lport_enter_reset; ++ ++ if (!lp->tt.lport_logout) ++ lp->tt.lport_logout = fc_lport_logout; ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_lport_init); +diff --git a/drivers/scsi/libfc/fc_ns.c b/drivers/scsi/libfc/fc_ns.c +new file mode 100644 +index 0000000..5c9272c +--- /dev/null ++++ b/drivers/scsi/libfc/fc_ns.c +@@ -0,0 +1,1283 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Target Discovery ++ * Actually, this discovers all FC-4 remote ports, including FCP initiators. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#define FC_NS_RETRY_LIMIT 3 /* max retries */ ++#define FC_NS_RETRY_DELAY 500UL /* (msecs) delay */ ++ ++int fc_ns_debug; ++ ++static void fc_ns_gpn_ft_req(struct fc_lport *); ++static void fc_ns_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); ++static int fc_ns_new_target(struct fc_lport *, struct fc_rport *, ++ struct fc_rport_identifiers *); ++static void fc_ns_del_target(struct fc_lport *, struct fc_rport *); ++static void fc_ns_disc_done(struct fc_lport *); ++static void fcdt_ns_error(struct fc_lport *, struct fc_frame *); ++static void fc_ns_timeout(struct work_struct *); ++ ++/** ++ * struct fc_ns_port - temporary discovery port to hold rport identifiers ++ * @lp: Fibre Channel host port instance ++ * @peers: node for list management during discovery and RSCN processing ++ * @ids: identifiers structure to pass to fc_remote_port_add() ++ */ ++struct fc_ns_port { ++ struct fc_lport *lp; ++ struct list_head peers; ++ struct fc_rport_identifiers ids; ++}; ++ ++static int fc_ns_gpn_id_req(struct fc_lport *, struct fc_ns_port *); ++static void fc_ns_gpn_id_resp(struct fc_seq *, struct fc_frame *, void *); ++static void fc_ns_gpn_id_error(struct fc_ns_port *rp, struct fc_frame *fp); ++ ++static int fc_ns_gnn_id_req(struct fc_lport *, struct fc_ns_port *); ++static void fc_ns_gnn_id_resp(struct fc_seq *, struct fc_frame *, void *); ++static void fc_ns_gnn_id_error(struct fc_ns_port *, struct fc_frame *); ++static void fc_ns_enter_reg_pn(struct fc_lport *lp); ++static void fc_ns_error(struct fc_lport *lp, struct fc_frame *fp); ++static void fc_lport_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, ++ unsigned int op, unsigned int req_size); ++static void fc_ns_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg); ++static void fc_ns_retry(struct fc_lport *lp); ++static void fc_ns_single(struct fc_lport *, struct fc_ns_port *); ++static int fc_ns_restart(struct fc_lport *); ++ ++ ++/** ++ * fc_ns_rscn_req - Handle Registered State Change Notification (RSCN) ++ * @sp: Current sequence of the RSCN exchange ++ * @fp: RSCN Frame ++ * @lp: Fibre Channel host port instance ++ */ ++static void fc_ns_rscn_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lp) ++{ ++ struct fc_els_rscn *rp; ++ struct fc_els_rscn_page *pp; ++ struct fc_seq_els_data rjt_data; ++ unsigned int len; ++ int redisc = 0; ++ enum fc_els_rscn_ev_qual ev_qual; ++ enum fc_els_rscn_addr_fmt fmt; ++ LIST_HEAD(disc_list); ++ struct fc_ns_port *dp, *next; ++ ++ rp = fc_frame_payload_get(fp, sizeof(*rp)); ++ ++ if (!rp || rp->rscn_page_len != sizeof(*pp)) ++ goto reject; ++ ++ len = ntohs(rp->rscn_plen); ++ if (len < sizeof(*rp)) ++ goto reject; ++ len -= sizeof(*rp); ++ ++ for (pp = (void *)(rp + 1); len; len -= sizeof(*pp), pp++) { ++ ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT; ++ ev_qual &= ELS_RSCN_EV_QUAL_MASK; ++ fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT; ++ fmt &= ELS_RSCN_ADDR_FMT_MASK; ++ /* ++ * if we get an address format other than port ++ * (area, domain, fabric), then do a full discovery ++ */ ++ switch (fmt) { ++ case ELS_ADDR_FMT_PORT: ++ dp = kzalloc(sizeof(*dp), GFP_KERNEL); ++ if (!dp) { ++ redisc = 1; ++ break; ++ } ++ dp->lp = lp; ++ dp->ids.port_id = ntoh24(pp->rscn_fid); ++ dp->ids.port_name = -1; ++ dp->ids.node_name = -1; ++ dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ list_add_tail(&dp->peers, &disc_list); ++ break; ++ case ELS_ADDR_FMT_AREA: ++ case ELS_ADDR_FMT_DOM: ++ case ELS_ADDR_FMT_FAB: ++ default: ++ redisc = 1; ++ break; ++ } ++ } ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ if (redisc) { ++ if (fc_ns_debug) ++ FC_DBG("RSCN received: rediscovering\n"); ++ list_for_each_entry_safe(dp, next, &disc_list, peers) { ++ list_del(&dp->peers); ++ kfree(dp); ++ } ++ fc_ns_restart(lp); ++ } else { ++ if (fc_ns_debug) ++ FC_DBG("RSCN received: not rediscovering. " ++ "redisc %d state %d in_prog %d\n", ++ redisc, lp->state, lp->ns_disc_pending); ++ list_for_each_entry_safe(dp, next, &disc_list, peers) { ++ list_del(&dp->peers); ++ fc_ns_single(lp, dp); ++ } ++ } ++ fc_frame_free(fp); ++ return; ++reject: ++ rjt_data.fp = NULL; ++ rjt_data.reason = ELS_RJT_LOGIC; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ fc_frame_free(fp); ++} ++ ++static void fc_ns_recv_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_lport *lp) ++{ ++ switch (fc_frame_payload_op(fp)) { ++ case ELS_RSCN: ++ fc_ns_rscn_req(sp, fp, lp); ++ break; ++ default: ++ FC_DBG("fc_ns recieved an unexpected request\n"); ++ break; ++ } ++} ++ ++/** ++ * fc_ns_scr_resp - Handle response to State Change Register (SCR) request ++ * @sp: current sequence in SCR exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel host port instance ++ */ ++static void fc_ns_scr_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) ++{ ++ struct fc_lport *lp = lp_arg; ++ int err; ++ ++ if (IS_ERR(fp)) ++ fc_ns_error(lp, fp); ++ else { ++ fc_lport_lock(lp); ++ fc_lport_state_enter(lp, LPORT_ST_READY); ++ fc_lport_unlock(lp); ++ err = lp->tt.disc_start(lp); ++ if (err) ++ FC_DBG("target discovery start error\n"); ++ fc_frame_free(fp); ++ } ++} ++ ++/** ++ * fc_ns_enter scr - Send a State Change Register (SCR) request ++ * @lp: Fibre Channel host port instance ++ */ ++static void fc_ns_enter_scr(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_els_scr *scr; ++ ++ if (fc_ns_debug) ++ FC_DBG("Processing SCR state\n"); ++ ++ fc_lport_state_enter(lp, LPORT_ST_SCR); ++ ++ fp = fc_frame_alloc(lp, sizeof(*scr)); ++ if (fp) { ++ scr = fc_frame_payload_get(fp, sizeof(*scr)); ++ memset(scr, 0, sizeof(*scr)); ++ scr->scr_cmd = ELS_SCR; ++ scr->scr_reg_func = ELS_SCRF_FULL; ++ } ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ fc_frame_set_offset(fp, 0); ++ ++ lp->tt.exch_seq_send(lp, fp, ++ fc_ns_scr_resp, ++ lp, lp->e_d_tov, ++ lp->fid, FC_FID_FCTRL, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++} ++ ++/** ++ * fc_ns_enter_reg_ft - Register FC4-types with the name server ++ * @lp: Fibre Channel host port instance ++ */ ++static void fc_ns_enter_reg_ft(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_fid fid; /* port ID object */ ++ struct fc_ns_fts fts; /* FC4-types object */ ++ } *req; ++ struct fc_ns_fts *lps; ++ int i; ++ ++ if (fc_ns_debug) ++ FC_DBG("Processing REG_FT state\n"); ++ ++ fc_lport_state_enter(lp, LPORT_ST_REG_FT); ++ ++ lps = &lp->fcts; ++ i = sizeof(lps->ff_type_map) / sizeof(lps->ff_type_map[0]); ++ while (--i >= 0) ++ if (ntohl(lps->ff_type_map[i]) != 0) ++ break; ++ if (i >= 0) { ++ fp = fc_frame_alloc(lp, sizeof(*req)); ++ if (fp) { ++ req = fc_frame_payload_get(fp, sizeof(*req)); ++ fc_lport_fill_dns_hdr(lp, &req->ct, ++ FC_NS_RFT_ID, ++ sizeof(*req) - ++ sizeof(struct fc_ct_hdr)); ++ hton24(req->fid.fp_fid, lp->fid); ++ req->fts = *lps; ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_ns_resp, lp, ++ lp->e_d_tov, ++ lp->fid, ++ lp->dns_rp->port_id, ++ FC_FC_SEQ_INIT | ++ FC_FC_END_SEQ)) ++ fc_ns_retry(lp); ++ } else { ++ fc_ns_retry(lp); ++ } ++ } else { ++ fc_ns_enter_scr(lp); ++ } ++} ++ ++/* ++ * enter next state for handling an exchange reject or retry exhaustion ++ * in the current state. ++ */ ++static void fc_ns_enter_reject(struct fc_lport *lp) ++{ ++ switch (lp->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_READY: ++ case LPORT_ST_RESET: ++ case LPORT_ST_FLOGI: ++ case LPORT_ST_LOGO: ++ WARN_ON(1); ++ break; ++ case LPORT_ST_REG_PN: ++ fc_ns_enter_reg_ft(lp); ++ break; ++ case LPORT_ST_REG_FT: ++ fc_ns_enter_scr(lp); ++ break; ++ case LPORT_ST_SCR: ++ case LPORT_ST_DNS_STOP: ++ lp->tt.disc_stop(lp); ++ break; ++ case LPORT_ST_DNS: ++ lp->tt.lport_reset(lp); ++ break; ++ } ++} ++ ++static void fc_ns_enter_retry(struct fc_lport *lp) ++{ ++ switch (lp->state) { ++ case LPORT_ST_NONE: ++ case LPORT_ST_RESET: ++ case LPORT_ST_READY: ++ case LPORT_ST_FLOGI: ++ case LPORT_ST_LOGO: ++ WARN_ON(1); ++ break; ++ case LPORT_ST_DNS: ++ lp->tt.dns_register(lp); ++ break; ++ case LPORT_ST_DNS_STOP: ++ lp->tt.disc_stop(lp); ++ break; ++ case LPORT_ST_REG_PN: ++ fc_ns_enter_reg_pn(lp); ++ break; ++ case LPORT_ST_REG_FT: ++ fc_ns_enter_reg_ft(lp); ++ break; ++ case LPORT_ST_SCR: ++ fc_ns_enter_scr(lp); ++ break; ++ } ++} ++ ++/* ++ * Refresh target discovery, perhaps due to an RSCN. ++ * A configurable delay is introduced to collect any subsequent RSCNs. ++ */ ++static int fc_ns_restart(struct fc_lport *lp) ++{ ++ fc_lport_lock(lp); ++ if (!lp->ns_disc_requested && !lp->ns_disc_pending) { ++ schedule_delayed_work(&lp->ns_disc_work, ++ msecs_to_jiffies(lp->ns_disc_delay * 1000)); ++ } ++ lp->ns_disc_requested = 1; ++ fc_lport_unlock(lp); ++ return 0; ++} ++ ++/* unlocked varient of scsi_target_block from scsi_lib.c */ ++#include "../scsi_priv.h" ++ ++static void __device_block(struct scsi_device *sdev, void *data) ++{ ++ scsi_internal_device_block(sdev); ++} ++ ++static int __target_block(struct device *dev, void *data) ++{ ++ if (scsi_is_target_device(dev)) ++ __starget_for_each_device(to_scsi_target(dev), ++ NULL, __device_block); ++ return 0; ++} ++ ++static void __scsi_target_block(struct device *dev) ++{ ++ if (scsi_is_target_device(dev)) ++ __starget_for_each_device(to_scsi_target(dev), ++ NULL, __device_block); ++ else ++ device_for_each_child(dev, NULL, __target_block); ++} ++ ++static void fc_block_rports(struct fc_lport *lp) ++{ ++ struct Scsi_Host *shost = lp->host; ++ struct fc_rport *rport; ++ unsigned long flags; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_for_each_entry(rport, &fc_host_rports(shost), peers) { ++ /* protect the name service remote port */ ++ if (rport == lp->dns_rp) ++ continue; ++ if (rport->port_state != FC_PORTSTATE_ONLINE) ++ continue; ++ rport->port_state = FC_PORTSTATE_BLOCKED; ++ rport->flags |= FC_RPORT_DEVLOSS_PENDING; ++ __scsi_target_block(&rport->dev); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++} ++ ++/* ++ * Fibre Channel Target discovery. ++ * ++ * Returns non-zero if discovery cannot be started. ++ * ++ * Callback is called for each target remote port found in discovery. ++ * When discovery is complete, the callback is called with a NULL remote port. ++ * Discovery may be restarted after an RSCN is received, causing the ++ * callback to be called after discovery complete is indicated. ++ */ ++int fc_ns_disc_start(struct fc_lport *lp) ++{ ++ struct fc_rport *rport; ++ int error; ++ struct fc_rport_identifiers ids; ++ ++ fc_lport_lock(lp); ++ ++ /* ++ * If not ready, or already running discovery, just set request flag. ++ */ ++ if (!fc_lport_test_ready(lp) || lp->ns_disc_pending) { ++ lp->ns_disc_requested = 1; ++ fc_lport_unlock(lp); ++ return 0; ++ } ++ lp->ns_disc_pending = 1; ++ lp->ns_disc_requested = 0; ++ lp->ns_disc_retry_count = 0; ++ ++ /* ++ * Handle point-to-point mode as a simple discovery ++ * of the remote port. ++ */ ++ rport = lp->ptp_rp; ++ if (rport) { ++ ids.port_id = rport->port_id; ++ ids.port_name = rport->port_name; ++ ids.node_name = rport->node_name; ++ ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ get_device(&rport->dev); ++ fc_lport_unlock(lp); ++ error = fc_ns_new_target(lp, rport, &ids); ++ put_device(&rport->dev); ++ if (!error) ++ fc_ns_disc_done(lp); ++ } else { ++ fc_lport_unlock(lp); ++ fc_block_rports(lp); ++ fc_ns_gpn_ft_req(lp); /* get ports by FC-4 type */ ++ error = 0; ++ } ++ return error; ++} ++ ++/* ++ * Handle resource allocation problem by retrying in a bit. ++ */ ++static void fc_ns_retry(struct fc_lport *lp) ++{ ++ if (lp->retry_count == 0) ++ FC_DBG("local port %6x alloc failure " ++ "- will retry\n", lp->fid); ++ if (lp->retry_count < lp->max_retry_count) { ++ lp->retry_count++; ++ mod_timer(&lp->state_timer, ++ jiffies + msecs_to_jiffies(lp->e_d_tov)); ++ } else { ++ FC_DBG("local port %6x alloc failure " ++ "- retries exhausted\n", lp->fid); ++ fc_ns_enter_reject(lp); ++ } ++} ++ ++/* ++ * Handle errors on local port requests. ++ * Don't get locks if in RESET state. ++ * The only possible errors so far are exchange TIMEOUT and CLOSED (reset). ++ */ ++static void fc_ns_error(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ if (lp->state == LPORT_ST_RESET) ++ return; ++ ++ fc_lport_lock(lp); ++ if (PTR_ERR(fp) == -FC_EX_TIMEOUT) { ++ if (lp->retry_count < lp->max_retry_count) { ++ lp->retry_count++; ++ fc_ns_enter_retry(lp); ++ } else { ++ fc_ns_enter_reject(lp); ++ } ++ } ++ if (fc_ns_debug) ++ FC_DBG("error %ld retries %d limit %d\n", ++ PTR_ERR(fp), lp->retry_count, lp->max_retry_count); ++ fc_lport_unlock(lp); ++} ++ ++/* ++ * Restart discovery after a delay due to resource shortages. ++ * If the error persists, the discovery will be abandoned. ++ */ ++static void fcdt_ns_retry(struct fc_lport *lp) ++{ ++ unsigned long delay = FC_NS_RETRY_DELAY; ++ ++ if (!lp->ns_disc_retry_count) ++ delay /= 4; /* timeout faster first time */ ++ if (lp->ns_disc_retry_count++ < FC_NS_RETRY_LIMIT) ++ schedule_delayed_work(&lp->ns_disc_work, ++ msecs_to_jiffies(delay)); ++ else ++ fc_ns_disc_done(lp); ++} ++ ++/* ++ * Test for dNS accept in response payload. ++ */ ++static int fc_lport_dns_acc(struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh; ++ struct fc_ct_hdr *ct; ++ int rc = 0; ++ ++ fh = fc_frame_header_get(fp); ++ ct = fc_frame_payload_get(fp, sizeof(*ct)); ++ if (fh && ct && fh->fh_type == FC_TYPE_CT && ++ ct->ct_fs_type == FC_FST_DIR && ++ ct->ct_fs_subtype == FC_NS_SUBTYPE && ++ ntohs(ct->ct_cmd) == FC_FS_ACC) { ++ rc = 1; ++ } ++ return rc; ++} ++ ++/* ++ * Handle response from name server. ++ */ ++static void ++fc_ns_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) ++{ ++ struct fc_lport *lp = lp_arg; ++ ++ if (!IS_ERR(fp)) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ if (fc_lport_dns_acc(fp)) { ++ if (lp->state == LPORT_ST_REG_PN) ++ fc_ns_enter_reg_ft(lp); ++ else ++ fc_ns_enter_scr(lp); ++ ++ } else { ++ fc_ns_retry(lp); ++ } ++ fc_lport_unlock(lp); ++ fc_frame_free(fp); ++ } else ++ fc_ns_error(lp, fp); ++} ++ ++/* ++ * Handle new target found by discovery. ++ * Create remote port and session if needed. ++ * Ignore returns of our own FID & WWPN. ++ * ++ * If a non-NULL rp is passed in, it is held for the caller, but not for us. ++ * ++ * Events delivered are: ++ * FC_EV_READY, when remote port is rediscovered. ++ */ ++static int fc_ns_new_target(struct fc_lport *lp, ++ struct fc_rport *rport, ++ struct fc_rport_identifiers *ids) ++{ ++ struct fc_rport_libfc_priv *rp; ++ int error = 0; ++ ++ if (rport && ids->port_name) { ++ if (rport->port_name == -1) { ++ /* ++ * Set WWN and fall through to notify of create. ++ */ ++ fc_rport_set_name(rport, ids->port_name, ++ rport->node_name); ++ } else if (rport->port_name != ids->port_name) { ++ /* ++ * This is a new port with the same FCID as ++ * a previously-discovered port. Presumably the old ++ * port logged out and a new port logged in and was ++ * assigned the same FCID. This should be rare. ++ * Delete the old one and fall thru to re-create. ++ */ ++ fc_ns_del_target(lp, rport); ++ rport = NULL; ++ } ++ } ++ if (((ids->port_name != -1) || (ids->port_id != -1)) && ++ ids->port_id != lp->fid && ids->port_name != lp->wwpn) { ++ if (!rport) { ++ rport = lp->tt.rport_lookup(lp, ids->port_id); ++ if (rport == NULL) ++ rport = lp->tt.rport_create(lp, ids); ++ if (!rport) ++ error = ENOMEM; ++ } ++ if (rport) { ++ rp = rport->dd_data; ++ rp->rp_state = RPORT_ST_INIT; ++ lp->tt.rport_login(rport); ++ } ++ } ++ return error; ++} ++ ++/* ++ * Delete the remote port. ++ */ ++static void fc_ns_del_target(struct fc_lport *lp, struct fc_rport *rport) ++{ ++ lp->tt.rport_reset(rport); ++ fc_remote_port_delete(rport); /* release hold from create */ ++} ++ ++/* ++ * Done with discovery ++ */ ++static void fc_ns_disc_done(struct fc_lport *lp) ++{ ++ lp->ns_disc_done = 1; ++ lp->ns_disc_pending = 0; ++ if (lp->ns_disc_requested) ++ lp->tt.disc_start(lp); ++} ++ ++/** ++ * fc_ns_fill_dns_hdr - Fill in a name service request header ++ * @lp: Fibre Channel host port instance ++ * @ct: Common Transport (CT) header structure ++ * @op: Name Service request code ++ * @req_size: Full size of Name Service request ++ */ ++static void fc_ns_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, ++ unsigned int op, unsigned int req_size) ++{ ++ memset(ct, 0, sizeof(*ct) + req_size); ++ ct->ct_rev = FC_CT_REV; ++ ct->ct_fs_type = FC_FST_DIR; ++ ct->ct_fs_subtype = FC_NS_SUBTYPE; ++ ct->ct_cmd = htons((u16) op); ++} ++ ++/** ++ * fc_ns_gpn_ft_req - Send Get Port Names by FC-4 type (GPN_FT) request ++ * @lp: Fibre Channel host port instance ++ */ ++static void fc_ns_gpn_ft_req(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct fc_seq *sp = NULL; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_gid_ft gid; ++ } *rp; ++ int error = 0; ++ ++ lp->ns_disc_buf_len = 0; ++ lp->ns_disc_seq_count = 0; ++ fp = fc_frame_alloc(lp, sizeof(*rp)); ++ if (fp == NULL) { ++ error = ENOMEM; ++ } else { ++ rp = fc_frame_payload_get(fp, sizeof(*rp)); ++ fc_ns_fill_dns_hdr(lp, &rp->ct, FC_NS_GPN_FT, sizeof(rp->gid)); ++ rp->gid.fn_fc4_type = FC_TYPE_FCP; ++ ++ WARN_ON(!fc_lport_test_ready(lp)); ++ ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ sp = lp->tt.exch_seq_send(lp, fp, ++ fc_ns_gpn_ft_resp, ++ lp, lp->e_d_tov, ++ lp->fid, ++ lp->dns_rp->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ); ++ } ++ if (error || sp == NULL) ++ fcdt_ns_retry(lp); ++} ++ ++/* ++ * Handle error on dNS request. ++ */ ++static void fcdt_ns_error(struct fc_lport *lp, struct fc_frame *fp) ++{ ++ int err = PTR_ERR(fp); ++ ++ switch (err) { ++ case -FC_EX_TIMEOUT: ++ if (lp->ns_disc_retry_count++ < FC_NS_RETRY_LIMIT) { ++ fc_ns_gpn_ft_req(lp); ++ } else { ++ FC_DBG("err %d - ending\n", err); ++ fc_ns_disc_done(lp); ++ } ++ break; ++ default: ++ FC_DBG("err %d - ending\n", err); ++ fc_ns_disc_done(lp); ++ break; ++ } ++} ++ ++/** ++ * fc_ns_gpn_ft_parse - Parse the list of IDs and names resulting from a request ++ * @lp: Fibre Channel host port instance ++ * @buf: GPN_FT response buffer ++ * @len: size of response buffer ++ */ ++static int fc_ns_gpn_ft_parse(struct fc_lport *lp, void *buf, size_t len) ++{ ++ struct fc_gpn_ft_resp *np; ++ char *bp; ++ size_t plen; ++ size_t tlen; ++ int error = 0; ++ struct fc_ns_port *dp; ++ ++ /* ++ * Handle partial name record left over from previous call. ++ */ ++ bp = buf; ++ plen = len; ++ np = (struct fc_gpn_ft_resp *)bp; ++ tlen = lp->ns_disc_buf_len; ++ if (tlen) { ++ WARN_ON(tlen >= sizeof(*np)); ++ plen = sizeof(*np) - tlen; ++ WARN_ON(plen <= 0); ++ WARN_ON(plen >= sizeof(*np)); ++ if (plen > len) ++ plen = len; ++ np = &lp->ns_disc_buf; ++ memcpy((char *)np + tlen, bp, plen); ++ ++ /* ++ * Set bp so that the loop below will advance it to the ++ * first valid full name element. ++ */ ++ bp -= tlen; ++ len += tlen; ++ plen += tlen; ++ lp->ns_disc_buf_len = (unsigned char) plen; ++ if (plen == sizeof(*np)) ++ lp->ns_disc_buf_len = 0; ++ } ++ ++ /* ++ * Handle full name records, including the one filled from above. ++ * Normally, np == bp and plen == len, but from the partial case above, ++ * bp, len describe the overall buffer, and np, plen describe the ++ * partial buffer, which if would usually be full now. ++ * After the first time through the loop, things return to "normal". ++ */ ++ while (plen >= sizeof(*np)) { ++ dp = kzalloc(sizeof(*dp), GFP_KERNEL); ++ if (!dp) ++ break; ++ dp->lp = lp; ++ dp->ids.port_id = ntoh24(np->fp_fid); ++ dp->ids.port_name = ntohll(np->fp_wwpn); ++ dp->ids.node_name = -1; ++ dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; ++ error = fc_ns_gnn_id_req(lp, dp); ++ if (error) ++ break; ++ if (np->fp_flags & FC_NS_FID_LAST) { ++ fc_ns_disc_done(lp); ++ len = 0; ++ break; ++ } ++ len -= sizeof(*np); ++ bp += sizeof(*np); ++ np = (struct fc_gpn_ft_resp *)bp; ++ plen = len; ++ } ++ ++ /* ++ * Save any partial record at the end of the buffer for next time. ++ */ ++ if (error == 0 && len > 0 && len < sizeof(*np)) { ++ if (np != &lp->ns_disc_buf) ++ memcpy(&lp->ns_disc_buf, np, len); ++ lp->ns_disc_buf_len = (unsigned char) len; ++ } else { ++ lp->ns_disc_buf_len = 0; ++ } ++ return error; ++} ++ ++/* ++ * Handle retry of memory allocation for remote ports. ++ */ ++static void fc_ns_timeout(struct work_struct *work) ++{ ++ struct fc_lport *lp; ++ ++ lp = container_of(work, struct fc_lport, ns_disc_work.work); ++ ++ if (lp->ns_disc_pending) ++ fc_ns_gpn_ft_req(lp); ++ else ++ lp->tt.disc_start(lp); ++} ++ ++/** ++ * fc_ns_gpn_ft_resp - Handle a response frame from Get Port Names (GPN_FT) ++ * @sp: Current sequence of GPN_FT exchange ++ * @fp: response frame ++ * @lp_arg: Fibre Channel host port instance ++ * ++ * The response may be in multiple frames ++ */ ++static void fc_ns_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *lp_arg) ++{ ++ struct fc_lport *lp = lp_arg; ++ struct fc_ct_hdr *cp; ++ struct fc_frame_header *fh; ++ unsigned int seq_cnt; ++ void *buf = NULL; ++ unsigned int len; ++ int error; ++ ++ if (IS_ERR(fp)) { ++ fcdt_ns_error(lp, fp); ++ return; ++ } ++ ++ WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ ++ fh = fc_frame_header_get(fp); ++ len = fr_len(fp) - sizeof(*fh); ++ seq_cnt = ntohs(fh->fh_seq_cnt); ++ if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && ++ lp->ns_disc_seq_count == 0) { ++ cp = fc_frame_payload_get(fp, sizeof(*cp)); ++ if (cp == NULL) { ++ FC_DBG("GPN_FT response too short, len %d\n", ++ fr_len(fp)); ++ } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { ++ ++ /* ++ * Accepted. Parse response. ++ */ ++ buf = cp + 1; ++ len -= sizeof(*cp); ++ } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { ++ FC_DBG("GPN_FT rejected reason %x exp %x " ++ "(check zoning)\n", cp->ct_reason, ++ cp->ct_explan); ++ fc_ns_disc_done(lp); ++ } else { ++ FC_DBG("GPN_FT unexpected response code %x\n", ++ ntohs(cp->ct_cmd)); ++ } ++ } else if (fr_sof(fp) == FC_SOF_N3 && ++ seq_cnt == lp->ns_disc_seq_count) { ++ buf = fh + 1; ++ } else { ++ FC_DBG("GPN_FT unexpected frame - out of sequence? " ++ "seq_cnt %x expected %x sof %x eof %x\n", ++ seq_cnt, lp->ns_disc_seq_count, fr_sof(fp), fr_eof(fp)); ++ } ++ if (buf) { ++ error = fc_ns_gpn_ft_parse(lp, buf, len); ++ if (error) ++ fcdt_ns_retry(lp); ++ else ++ lp->ns_disc_seq_count++; ++ } ++ fc_frame_free(fp); ++} ++ ++/* ++ * Discover the directory information for a single target. ++ * This could be from an RSCN that reported a change for the target. ++ */ ++static void fc_ns_single(struct fc_lport *lp, struct fc_ns_port *dp) ++{ ++ struct fc_rport *rport; ++ ++ if (dp->ids.port_id == lp->fid) ++ goto out; ++ ++ rport = lp->tt.rport_lookup(lp, dp->ids.port_id); ++ if (rport) { ++ fc_ns_del_target(lp, rport); ++ put_device(&rport->dev); /* hold from lookup */ ++ } ++ ++ if (fc_ns_gpn_id_req(lp, dp) != 0) ++ goto error; ++ return; ++error: ++ fc_ns_restart(lp); ++out: ++ kfree(dp); ++} ++ ++/** ++ * fc_ns_gpn_id_req - Send Get Port Name by ID (GPN_ID) request ++ * @lp: Fibre Channel host port instance ++ * @dp: Temporary discovery port for holding IDs and world wide names ++ * ++ * The remote port is held by the caller for us. ++ */ ++static int fc_ns_gpn_id_req(struct fc_lport *lp, struct fc_ns_port *dp) ++{ ++ struct fc_frame *fp; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_fid fid; ++ } *cp; ++ int error = 0; ++ ++ fp = fc_frame_alloc(lp, sizeof(*cp)); ++ if (fp == NULL) ++ return -ENOMEM; ++ ++ cp = fc_frame_payload_get(fp, sizeof(*cp)); ++ fc_ns_fill_dns_hdr(lp, &cp->ct, FC_NS_GPN_ID, sizeof(cp->fid)); ++ hton24(cp->fid.fp_fid, dp->ids.port_id); ++ ++ WARN_ON(!fc_lport_test_ready(lp)); ++ ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_ns_gpn_id_resp, ++ dp, lp->e_d_tov, ++ lp->fid, ++ lp->dns_rp->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ error = -ENOMEM; ++ ++ return error; ++} ++ ++/** ++ * fc_ns_gpn_id_resp - Handle response to GPN_ID ++ * @sp: Current sequence of GPN_ID exchange ++ * @fp: response frame ++ * @dp_arg: Temporary discovery port for holding IDs and world wide names ++ */ ++static void fc_ns_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *dp_arg) ++{ ++ struct fc_ns_port *dp = dp_arg; ++ struct fc_lport *lp; ++ struct resp { ++ struct fc_ct_hdr ct; ++ __be64 wwn; ++ } *cp; ++ unsigned int cmd; ++ ++ if (IS_ERR(fp)) { ++ fc_ns_gpn_id_error(dp, fp); ++ return; ++ } ++ ++ lp = dp->lp; ++ WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ ++ ++ cp = fc_frame_payload_get(fp, sizeof(cp->ct)); ++ if (cp == NULL) { ++ FC_DBG("GPN_ID response too short, len %d\n", fr_len(fp)); ++ return; ++ } ++ cmd = ntohs(cp->ct.ct_cmd); ++ switch (cmd) { ++ case FC_FS_ACC: ++ cp = fc_frame_payload_get(fp, sizeof(*cp)); ++ if (cp == NULL) { ++ FC_DBG("GPN_ID response payload too short, len %d\n", ++ fr_len(fp)); ++ break; ++ } ++ dp->ids.port_name = ntohll(cp->wwn); ++ fc_ns_gnn_id_req(lp, dp); ++ break; ++ case FC_FS_RJT: ++ fc_ns_restart(lp); ++ break; ++ default: ++ FC_DBG("GPN_ID unexpected CT response cmd %x\n", cmd); ++ break; ++ } ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_ns_gpn_id_error - Handle error from GPN_ID ++ * @dp: Temporary discovery port for holding IDs and world wide names ++ * @fp: response frame ++ */ ++static void fc_ns_gpn_id_error(struct fc_ns_port *dp, struct fc_frame *fp) ++{ ++ struct fc_lport *lp = dp->lp; ++ ++ switch (PTR_ERR(fp)) { ++ case -FC_EX_TIMEOUT: ++ fc_ns_restart(lp); ++ break; ++ case -FC_EX_CLOSED: ++ default: ++ break; ++ } ++ kfree(dp); ++} ++ ++/* ++ * Setup session to dNS if not already set up. ++ */ ++static void fc_ns_enter_dns(struct fc_lport *lp) ++{ ++ struct fc_rport *rport; ++ struct fc_rport_libfc_priv *rp; ++ struct fc_rport_identifiers ids = { ++ .port_id = FC_FID_DIR_SERV, ++ .port_name = -1, ++ .node_name = -1, ++ .roles = FC_RPORT_ROLE_UNKNOWN, ++ }; ++ ++ if (fc_ns_debug) ++ FC_DBG("Processing DNS state\n"); ++ ++ fc_lport_state_enter(lp, LPORT_ST_DNS); ++ ++ if (!lp->dns_rp) { ++ /* ++ * Set up remote port to directory server. ++ */ ++ ++ /* ++ * we are called with the state_lock, but if rport_lookup_create ++ * needs to create a rport then it will sleep. ++ */ ++ fc_lport_unlock(lp); ++ rport = lp->tt.rport_lookup(lp, ids.port_id); ++ if (rport == NULL) ++ rport = lp->tt.rport_create(lp, &ids); ++ fc_lport_lock(lp); ++ if (!rport) ++ goto err; ++ lp->dns_rp = rport; ++ } ++ ++ rport = lp->dns_rp; ++ rp = rport->dd_data; ++ ++ /* ++ * If dNS session isn't ready, start its logon. ++ */ ++ if (rp->rp_state != RPORT_ST_READY) { ++ lp->tt.rport_login(rport); ++ } else { ++ del_timer(&lp->state_timer); ++ fc_ns_enter_reg_pn(lp); ++ } ++ return; ++ ++ /* ++ * Resource allocation problem (malloc). Try again in 500 mS. ++ */ ++err: ++ fc_ns_retry(lp); ++} ++ ++/* ++ * Logoff DNS session. ++ * We should get an event call when the session has been logged out. ++ */ ++static void fc_ns_enter_dns_stop(struct fc_lport *lp) ++{ ++ struct fc_rport *rport = lp->dns_rp; ++ ++ if (fc_ns_debug) ++ FC_DBG("Processing DNS_STOP state\n"); ++ ++ fc_lport_state_enter(lp, LPORT_ST_DNS_STOP); ++ ++ if (rport) ++ lp->tt.rport_logout(rport); ++ else ++ lp->tt.lport_logout(lp); ++} ++ ++/* ++ * Fill in dNS request header. ++ */ ++static void ++fc_lport_fill_dns_hdr(struct fc_lport *lp, struct fc_ct_hdr *ct, ++ unsigned int op, unsigned int req_size) ++{ ++ memset(ct, 0, sizeof(*ct) + req_size); ++ ct->ct_rev = FC_CT_REV; ++ ct->ct_fs_type = FC_FST_DIR; ++ ct->ct_fs_subtype = FC_NS_SUBTYPE; ++ ct->ct_cmd = htons(op); ++} ++ ++/* ++ * Register port name with name server. ++ */ ++static void fc_ns_enter_reg_pn(struct fc_lport *lp) ++{ ++ struct fc_frame *fp; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_rn_id rn; ++ } *req; ++ ++ if (fc_ns_debug) ++ FC_DBG("Processing REG_PN state\n"); ++ ++ fc_lport_state_enter(lp, LPORT_ST_REG_PN); ++ fp = fc_frame_alloc(lp, sizeof(*req)); ++ if (!fp) { ++ fc_ns_retry(lp); ++ return; ++ } ++ req = fc_frame_payload_get(fp, sizeof(*req)); ++ memset(req, 0, sizeof(*req)); ++ fc_lport_fill_dns_hdr(lp, &req->ct, FC_NS_RPN_ID, sizeof(req->rn)); ++ hton24(req->rn.fr_fid.fp_fid, lp->fid); ++ put_unaligned_be64(lp->wwpn, &req->rn.fr_wwn); ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_ns_resp, lp, ++ lp->e_d_tov, ++ lp->fid, ++ lp->dns_rp->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_ns_retry(lp); ++} ++ ++int fc_ns_init(struct fc_lport *lp) ++{ ++ INIT_DELAYED_WORK(&lp->ns_disc_work, fc_ns_timeout); ++ ++ if (!lp->tt.disc_start) ++ lp->tt.disc_start = fc_ns_disc_start; ++ ++ if (!lp->tt.disc_recv_req) ++ lp->tt.disc_recv_req = fc_ns_recv_req; ++ ++ if (!lp->tt.dns_register) ++ lp->tt.dns_register = fc_ns_enter_dns; ++ ++ if (!lp->tt.disc_stop) ++ lp->tt.disc_stop = fc_ns_enter_dns_stop; ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_ns_init); ++ ++/** ++ * fc_ns_gnn_id_req - Send Get Node Name by ID (GNN_ID) request ++ * @lp: Fibre Channel host port instance ++ * @dp: Temporary discovery port for holding IDs and world wide names ++ * ++ * The remote port is held by the caller for us. ++ */ ++static int fc_ns_gnn_id_req(struct fc_lport *lp, struct fc_ns_port *dp) ++{ ++ struct fc_frame *fp; ++ struct req { ++ struct fc_ct_hdr ct; ++ struct fc_ns_fid fid; ++ } *cp; ++ int error = 0; ++ ++ fp = fc_frame_alloc(lp, sizeof(*cp)); ++ if (fp == NULL) ++ return -ENOMEM; ++ ++ cp = fc_frame_payload_get(fp, sizeof(*cp)); ++ fc_ns_fill_dns_hdr(lp, &cp->ct, FC_NS_GNN_ID, sizeof(cp->fid)); ++ hton24(cp->fid.fp_fid, dp->ids.port_id); ++ ++ WARN_ON(!fc_lport_test_ready(lp)); ++ ++ fc_frame_setup(fp, FC_RCTL_DD_UNSOL_CTL, FC_TYPE_CT); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_ns_gnn_id_resp, ++ dp, lp->e_d_tov, ++ lp->fid, ++ lp->dns_rp->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ error = -ENOMEM; ++ ++ return error; ++} ++ ++/** ++ * fc_ns_gnn_id_resp - Handle response to GNN_ID ++ * @sp: Current sequence of GNN_ID exchange ++ * @fp: response frame ++ * @dp_arg: Temporary discovery port for holding IDs and world wide names ++ */ ++static void fc_ns_gnn_id_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *dp_arg) ++{ ++ struct fc_ns_port *dp = dp_arg; ++ struct fc_lport *lp; ++ struct resp { ++ struct fc_ct_hdr ct; ++ __be64 wwn; ++ } *cp; ++ unsigned int cmd; ++ ++ if (IS_ERR(fp)) { ++ fc_ns_gnn_id_error(dp, fp); ++ return; ++ } ++ ++ lp = dp->lp; ++ WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ ++ ++ cp = fc_frame_payload_get(fp, sizeof(cp->ct)); ++ if (cp == NULL) { ++ FC_DBG("GNN_ID response too short, len %d\n", fr_len(fp)); ++ return; ++ } ++ cmd = ntohs(cp->ct.ct_cmd); ++ switch (cmd) { ++ case FC_FS_ACC: ++ cp = fc_frame_payload_get(fp, sizeof(*cp)); ++ if (cp == NULL) { ++ FC_DBG("GNN_ID response payload too short, len %d\n", ++ fr_len(fp)); ++ break; ++ } ++ dp->ids.node_name = ntohll(cp->wwn); ++ fc_ns_new_target(lp, NULL, &dp->ids); ++ break; ++ case FC_FS_RJT: ++ fc_ns_restart(lp); ++ break; ++ default: ++ FC_DBG("GNN_ID unexpected CT response cmd %x\n", cmd); ++ break; ++ } ++ kfree(dp); ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_ns_gnn_id_error - Handle error from GNN_ID ++ * @dp: Temporary discovery port for holding IDs and world wide names ++ * @fp: response frame ++ */ ++static void fc_ns_gnn_id_error(struct fc_ns_port *dp, struct fc_frame *fp) ++{ ++ struct fc_lport *lp = dp->lp; ++ ++ switch (PTR_ERR(fp)) { ++ case -FC_EX_TIMEOUT: ++ fc_ns_restart(lp); ++ break; ++ case -FC_EX_CLOSED: ++ default: ++ break; ++ } ++ kfree(dp); ++} ++ +diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c +new file mode 100644 +index 0000000..6d0c970 +--- /dev/null ++++ b/drivers/scsi/libfc/fc_rport.c +@@ -0,0 +1,1301 @@ ++/* ++ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Maintained at www.Open-FCoE.org ++ */ ++ ++/* ++ * Remote Port support. ++ * ++ * A remote port structure contains information about an N port to which we ++ * will create sessions. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static int fc_rp_debug; ++ ++/* ++ * static functions. ++ */ ++static void fc_rport_enter_start(struct fc_rport *); ++static void fc_rport_enter_plogi(struct fc_rport *); ++static void fc_rport_enter_prli(struct fc_rport *); ++static void fc_rport_enter_rtv(struct fc_rport *); ++static void fc_rport_enter_logo(struct fc_rport *); ++static void fc_rport_recv_plogi_req(struct fc_rport *, ++ struct fc_seq *, struct fc_frame *); ++static void fc_rport_recv_prli_req(struct fc_rport *, ++ struct fc_seq *, struct fc_frame *); ++static void fc_rport_recv_prlo_req(struct fc_rport *, ++ struct fc_seq *, struct fc_frame *); ++static void fc_rport_recv_logo_req(struct fc_rport *, ++ struct fc_seq *, struct fc_frame *); ++static void fc_rport_timeout(struct work_struct *); ++ ++static struct fc_rport *fc_remote_port_create(struct fc_lport *, ++ struct fc_rport_identifiers *); ++ ++/** ++ * fc_rport_lookup - lookup a remote port by port_id ++ * @lp: Fibre Channel host port instance ++ * @fid: remote port port_id to match ++ */ ++struct fc_rport *fc_rport_lookup(const struct fc_lport *lp, u32 fid) ++{ ++ struct Scsi_Host *shost = lp->host; ++ struct fc_rport *rport, *found; ++ unsigned long flags; ++ ++ found = NULL; ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_for_each_entry(rport, &fc_host_rports(shost), peers) ++ if (rport->port_id == fid && ++ rport->port_state == FC_PORTSTATE_ONLINE) { ++ found = rport; ++ get_device(&found->dev); ++ break; ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++ return found; ++} ++ ++/** ++ * fc_remote_port_create - create a remote port ++ * @lp: Fibre Channel host port instance ++ * @ids: remote port identifiers (port_id, port_name, and node_name must be set) ++ */ ++static struct fc_rport *fc_remote_port_create(struct fc_lport *lp, ++ struct fc_rport_identifiers *ids) ++{ ++ struct fc_rport_libfc_priv *rp; ++ struct fc_rport *rport; ++ ++ rport = fc_remote_port_add(lp->host, 0, ids); ++ if (!rport) ++ return NULL; ++ ++ rp = rport->dd_data; ++ rp->local_port = lp; ++ ++ /* default value until service parameters are exchanged in PLOGI */ ++ rport->maxframe_size = FC_MIN_MAX_PAYLOAD; ++ ++ spin_lock_init(&rp->rp_lock); ++ rp->rp_state = RPORT_ST_INIT; ++ rp->local_port = lp; ++ rp->e_d_tov = lp->e_d_tov; ++ rp->r_a_tov = lp->r_a_tov; ++ rp->flags = FC_RP_FLAGS_REC_SUPPORTED; ++ INIT_DELAYED_WORK(&rp->retry_work, fc_rport_timeout); ++ ++ return rport; ++} ++ ++static inline void fc_rport_lock(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ spin_lock_bh(&rp->rp_lock); ++} ++ ++static inline void fc_rport_unlock(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ spin_unlock_bh(&rp->rp_lock); ++} ++ ++/** ++ * fc_plogi_get_maxframe - Get max payload from the common service parameters ++ * @flp: FLOGI payload structure ++ * @maxval: upper limit, may be less than what is in the service parameters ++ */ ++static unsigned int ++fc_plogi_get_maxframe(struct fc_els_flogi *flp, unsigned int maxval) ++{ ++ unsigned int mfs; ++ ++ /* ++ * Get max payload from the common service parameters and the ++ * class 3 receive data field size. ++ */ ++ mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK; ++ if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval) ++ maxval = mfs; ++ mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs); ++ if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval) ++ maxval = mfs; ++ return maxval; ++} ++ ++/** ++ * fc_lport_plogi_fill - Fill in PLOGI command for request ++ * @lp: Fibre Channel host port instance ++ * @plogi: PLOGI command structure to fill (same structure as FLOGI) ++ * @op: either ELS_PLOGI for a localy generated request, or ELS_LS_ACC ++ */ ++static void ++fc_lport_plogi_fill(struct fc_lport *lp, ++ struct fc_els_flogi *plogi, unsigned int op) ++{ ++ struct fc_els_csp *sp; ++ struct fc_els_cssp *cp; ++ ++ memset(plogi, 0, sizeof(*plogi)); ++ plogi->fl_cmd = (u8) op; ++ put_unaligned_be64(lp->wwpn, &plogi->fl_wwpn); ++ put_unaligned_be64(lp->wwnn, &plogi->fl_wwnn); ++ ++ sp = &plogi->fl_csp; ++ sp->sp_hi_ver = 0x20; ++ sp->sp_lo_ver = 0x20; ++ sp->sp_bb_cred = htons(10); /* this gets set by gateway */ ++ sp->sp_bb_data = htons((u16) lp->mfs); ++ cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */ ++ cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); ++ if (op != ELS_FLOGI) { ++ sp->sp_features = htons(FC_SP_FT_CIRO); ++ sp->sp_tot_seq = htons(255); /* seq. we accept */ ++ sp->sp_rel_off = htons(0x1f); ++ sp->sp_e_d_tov = htonl(lp->e_d_tov); ++ ++ cp->cp_rdfs = htons((u16) lp->mfs); ++ cp->cp_con_seq = htons(255); ++ cp->cp_open_seq = 1; ++ } ++} ++ ++static void fc_rport_state_enter(struct fc_rport *rport, ++ enum fc_rport_state new) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ if (rp->rp_state != new) ++ rp->retries = 0; ++ rp->rp_state = new; ++} ++ ++/** ++ * fc_rport_login - Start the remote port login state machine ++ * @rport: Fibre Channel remote port ++ */ ++int fc_rport_login(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ fc_rport_lock(rport); ++ if (rp->rp_state == RPORT_ST_INIT) { ++ fc_rport_unlock(rport); ++ fc_rport_enter_start(rport); ++ } else if (rp->rp_state == RPORT_ST_ERROR) { ++ fc_rport_state_enter(rport, RPORT_ST_INIT); ++ fc_rport_unlock(rport); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x closed\n", rport->port_id); ++ ++ if (rport == lp->dns_rp && ++ lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++ } else ++ fc_rport_unlock(rport); ++ ++ return 0; ++} ++ ++/* ++ * Stop the session - log it off. ++ */ ++int fc_rport_logout(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ fc_rport_lock(rport); ++ switch (rp->rp_state) { ++ case RPORT_ST_PRLI: ++ case RPORT_ST_RTV: ++ case RPORT_ST_READY: ++ fc_rport_enter_logo(rport); ++ fc_rport_unlock(rport); ++ break; ++ default: ++ fc_rport_state_enter(rport, RPORT_ST_INIT); ++ fc_rport_unlock(rport); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x closed\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ ++ fc_remote_port_delete(rport); ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Reset the session - assume it is logged off. Used after fabric logoff. ++ * The local port code takes care of resetting the exchange manager. ++ */ ++void fc_rport_reset(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp; ++ ++ if (fc_rp_debug) ++ FC_DBG("sess to %6x reset\n", rport->port_id); ++ fc_rport_lock(rport); ++ ++ lp = rp->local_port; ++ fc_rport_state_enter(rport, RPORT_ST_INIT); ++ fc_rport_unlock(rport); ++ ++ if (fc_rp_debug) ++ FC_DBG("remote %6x closed\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++} ++ ++/* ++ * Reset all sessions for a local port session list. ++ */ ++void fc_rport_reset_list(struct fc_lport *lp) ++{ ++ struct Scsi_Host *shost = lp->host; ++ struct fc_rport *rport; ++ struct fc_rport *next; ++ unsigned long flags; ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ list_for_each_entry_safe(rport, next, &fc_host_rports(shost), peers) { ++ lp->tt.rport_reset(rport); ++ } ++ spin_unlock_irqrestore(shost->host_lock, flags); ++} ++ ++static void fc_rport_enter_start(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ /* ++ * If the local port is already logged on, advance to next state. ++ * Otherwise the local port will be logged on by fc_rport_unlock(). ++ */ ++ fc_rport_state_enter(rport, RPORT_ST_STARTED); ++ ++ if (rport == lp->dns_rp || fc_lport_test_ready(lp)) ++ fc_rport_enter_plogi(rport); ++} ++ ++/* ++ * Handle exchange reject or retry exhaustion in various states. ++ */ ++static void fc_rport_reject(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ switch (rp->rp_state) { ++ case RPORT_ST_PLOGI: ++ case RPORT_ST_PRLI: ++ fc_rport_state_enter(rport, RPORT_ST_ERROR); ++ if (rport == lp->dns_rp && ++ lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++ break; ++ case RPORT_ST_RTV: ++ fc_rport_state_enter(rport, RPORT_ST_READY); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x ready\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state == LPORT_ST_DNS) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->tt.dns_register(lp); ++ fc_lport_unlock(lp); ++ } ++ break; ++ case RPORT_ST_LOGO: ++ fc_rport_state_enter(rport, RPORT_ST_INIT); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x closed\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++ break; ++ case RPORT_ST_NONE: ++ case RPORT_ST_READY: ++ case RPORT_ST_ERROR: ++ case RPORT_ST_PLOGI_RECV: ++ case RPORT_ST_STARTED: ++ case RPORT_ST_INIT: ++ BUG(); ++ break; ++ } ++ return; ++} ++ ++/* ++ * Timeout handler for retrying after allocation failures or exchange timeout. ++ */ ++static void fc_rport_timeout(struct work_struct *work) ++{ ++ struct fc_rport_libfc_priv *rp = ++ container_of(work, struct fc_rport_libfc_priv, retry_work.work); ++ struct fc_rport *rport = (((void *)rp) - sizeof(struct fc_rport)); ++ ++ switch (rp->rp_state) { ++ case RPORT_ST_PLOGI: ++ fc_rport_enter_plogi(rport); ++ break; ++ case RPORT_ST_PRLI: ++ fc_rport_enter_prli(rport); ++ break; ++ case RPORT_ST_RTV: ++ fc_rport_enter_rtv(rport); ++ break; ++ case RPORT_ST_LOGO: ++ fc_rport_enter_logo(rport); ++ break; ++ case RPORT_ST_READY: ++ case RPORT_ST_ERROR: ++ case RPORT_ST_INIT: ++ break; ++ case RPORT_ST_NONE: ++ case RPORT_ST_PLOGI_RECV: ++ case RPORT_ST_STARTED: ++ BUG(); ++ break; ++ } ++ put_device(&rport->dev); ++} ++ ++/* ++ * Handle retry for allocation failure via timeout. ++ */ ++static void fc_rport_retry(struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ if (rp->retries < lp->max_retry_count) { ++ rp->retries++; ++ get_device(&rport->dev); ++ schedule_delayed_work(&rp->retry_work, ++ msecs_to_jiffies(rp->e_d_tov)); ++ } else { ++ FC_DBG("sess %6x alloc failure in state %d, " ++ "retries exhausted\n", ++ rport->port_id, rp->rp_state); ++ fc_rport_reject(rport); ++ } ++} ++ ++/* ++ * Handle error from a sequence issued by the rport state machine. ++ */ ++static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ fc_rport_lock(rport); ++ if (fc_rp_debug) ++ FC_DBG("state %d error %ld retries %d\n", ++ rp->rp_state, PTR_ERR(fp), rp->retries); ++ ++ if (PTR_ERR(fp) == -FC_EX_TIMEOUT && ++ rp->retries++ >= rp->local_port->max_retry_count) { ++ get_device(&rport->dev); ++ schedule_delayed_work(&rp->retry_work, 0); ++ } else ++ fc_rport_reject(rport); ++ ++ fc_rport_unlock(rport); ++} ++ ++/** ++ * fc_rport_plpogi_recv_resp - Handle incoming ELS PLOGI response ++ * @sp: current sequence in the PLOGI exchange ++ * @fp: response frame ++ * @rp_arg: Fibre Channel remote port ++ */ ++static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *rp_arg) ++{ ++ struct fc_els_ls_rjt *rjp; ++ struct fc_els_flogi *plp; ++ u64 wwpn, wwnn; ++ unsigned int tov; ++ u16 csp_seq; ++ u16 cssp_seq; ++ u8 op; ++ struct fc_rport *rport = rp_arg; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ ++ if (!IS_ERR(fp)) { ++ op = fc_frame_payload_op(fp); ++ fc_rport_lock(rport); ++ if (op == ELS_LS_ACC && ++ (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { ++ wwpn = get_unaligned_be64(&plp->fl_wwpn); ++ wwnn = get_unaligned_be64(&plp->fl_wwnn); ++ ++ fc_rport_set_name(rport, wwpn, wwnn); ++ tov = ntohl(plp->fl_csp.sp_e_d_tov); ++ if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) ++ tov /= 1000; ++ if (tov > rp->e_d_tov) ++ rp->e_d_tov = tov; ++ csp_seq = ntohs(plp->fl_csp.sp_tot_seq); ++ cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); ++ if (cssp_seq < csp_seq) ++ csp_seq = cssp_seq; ++ rp->max_seq = csp_seq; ++ rport->maxframe_size = ++ fc_plogi_get_maxframe(plp, rp->local_port->mfs); ++ if (rp->rp_state == RPORT_ST_PLOGI) ++ fc_rport_enter_prli(rport); ++ } else { ++ if (fc_rp_debug) ++ FC_DBG("bad PLOGI response\n"); ++ ++ rjp = fc_frame_payload_get(fp, sizeof(*rjp)); ++ if (op == ELS_LS_RJT && rjp != NULL && ++ rjp->er_reason == ELS_RJT_INPROG) ++ fc_rport_retry(rport); /* try again */ ++ else ++ fc_rport_reject(rport); /* error */ ++ } ++ fc_rport_unlock(rport); ++ fc_frame_free(fp); ++ } else { ++ fc_rport_error(rport, fp); ++ } ++} ++ ++/** ++ * fc_rport_enter_plogi - Send Port Login (PLOGI) request to peer ++ * @rport: Fibre Channel remote port to send PLOGI to ++ */ ++static void fc_rport_enter_plogi(struct fc_rport *rport) ++{ ++ struct fc_frame *fp; ++ struct fc_els_flogi *plogi; ++ struct fc_lport *lp; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ ++ lp = rp->local_port; ++ fc_rport_state_enter(rport, RPORT_ST_PLOGI); ++ rport->maxframe_size = FC_MIN_MAX_PAYLOAD; ++ fp = fc_frame_alloc(lp, sizeof(*plogi)); ++ if (!fp) ++ return fc_rport_retry(rport); ++ plogi = fc_frame_payload_get(fp, sizeof(*plogi)); ++ WARN_ON(!plogi); ++ fc_lport_plogi_fill(rp->local_port, plogi, ELS_PLOGI); ++ rp->e_d_tov = lp->e_d_tov; ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_rport_plogi_resp, ++ rport, lp->e_d_tov, ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_retry(rport); ++} ++ ++/** ++ * fc_rport_prli_resp - Process Login (PRLI) response handler ++ * @sp: current sequence in the PRLI exchange ++ * @fp: response frame ++ * @rp_arg: Fibre Channel remote port ++ */ ++static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *rp_arg) ++{ ++ struct fc_rport *rport = rp_arg; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ struct { ++ struct fc_els_prli prli; ++ struct fc_els_spp spp; ++ } *pp; ++ u32 roles = FC_RPORT_ROLE_UNKNOWN; ++ u32 fcp_parm = 0; ++ u8 op; ++ ++ if (IS_ERR(fp)) { ++ fc_rport_error(rport, fp); ++ return; ++ } ++ ++ fc_rport_lock(rport); ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC) { ++ pp = fc_frame_payload_get(fp, sizeof(*pp)); ++ if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) { ++ fcp_parm = ntohl(pp->spp.spp_params); ++ if (fcp_parm & FCP_SPPF_RETRY) ++ rp->flags |= FC_RP_FLAGS_RETRY; ++ } ++ ++ rport->supported_classes = FC_COS_CLASS3; ++ if (fcp_parm & FCP_SPPF_INIT_FCN) ++ roles |= FC_RPORT_ROLE_FCP_INITIATOR; ++ if (fcp_parm & FCP_SPPF_TARG_FCN) ++ roles |= FC_RPORT_ROLE_FCP_TARGET; ++ ++ fc_rport_enter_rtv(rport); ++ fc_rport_unlock(rport); ++ fc_remote_port_rolechg(rport, roles); ++ } else { ++ FC_DBG("bad ELS response\n"); ++ fc_rport_state_enter(rport, RPORT_ST_ERROR); ++ fc_rport_unlock(rport); ++ if (rport == lp->dns_rp && lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++ } ++ ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_rport_logo_resp - Logout (LOGO) response handler ++ * @sp: current sequence in the LOGO exchange ++ * @fp: response frame ++ * @rp_arg: Fibre Channel remote port ++ */ ++static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *rp_arg) ++{ ++ struct fc_rport *rport = rp_arg; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ u8 op; ++ ++ if (IS_ERR(fp)) { ++ fc_rport_error(rport, fp); ++ return; ++ } ++ ++ fc_rport_lock(rport); ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC) { ++ fc_rport_enter_rtv(rport); ++ fc_rport_unlock(rport); ++ } else { ++ FC_DBG("bad ELS response\n"); ++ fc_rport_state_enter(rport, RPORT_ST_ERROR); ++ fc_rport_unlock(rport); ++ if (rport == lp->dns_rp && lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++ } ++ ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_rport_enter_prli - Send Process Login (PRLI) request to peer ++ * @rport: Fibre Channel remote port to send PRLI to ++ */ ++static void fc_rport_enter_prli(struct fc_rport *rport) ++{ ++ struct { ++ struct fc_els_prli prli; ++ struct fc_els_spp spp; ++ } *pp; ++ struct fc_frame *fp; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ fc_rport_state_enter(rport, RPORT_ST_PRLI); ++ ++ /* ++ * Special case if session is for name server or any other ++ * well-known address: Skip the PRLI step. ++ * This should be made more general, possibly moved to the FCP layer. ++ */ ++ if (rport->port_id >= FC_FID_DOM_MGR) { ++ fc_rport_state_enter(rport, RPORT_ST_READY); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x ready\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state == LPORT_ST_DNS) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->tt.dns_register(lp); ++ fc_lport_unlock(lp); ++ } ++ return; ++ } ++ fp = fc_frame_alloc(lp, sizeof(*pp)); ++ if (!fp) ++ return fc_rport_retry(rport); ++ pp = fc_frame_payload_get(fp, sizeof(*pp)); ++ WARN_ON(!pp); ++ memset(pp, 0, sizeof(*pp)); ++ pp->prli.prli_cmd = ELS_PRLI; ++ pp->prli.prli_spp_len = sizeof(struct fc_els_spp); ++ pp->prli.prli_len = htons(sizeof(*pp)); ++ pp->spp.spp_type = FC_TYPE_FCP; ++ pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR; ++ pp->spp.spp_params = htonl(rp->local_port->service_params); ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_rport_prli_resp, ++ rport, lp->e_d_tov, ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_retry(rport); ++} ++ ++/** ++ * fc_rport_els_rtv_resp - Request Timeout Value response handler ++ * @sp: current sequence in the RTV exchange ++ * @fp: response frame ++ * @rp_arg: Fibre Channel remote port ++ * ++ * Many targets don't seem to support this. ++ */ ++static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, ++ void *rp_arg) ++{ ++ struct fc_rport *rport = rp_arg; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ u8 op; ++ ++ if (IS_ERR(fp)) { ++ fc_rport_error(rport, fp); ++ return; ++ } ++ ++ fc_rport_lock(rport); ++ op = fc_frame_payload_op(fp); ++ if (op == ELS_LS_ACC) { ++ struct fc_els_rtv_acc *rtv; ++ u32 toq; ++ u32 tov; ++ ++ rtv = fc_frame_payload_get(fp, sizeof(*rtv)); ++ if (rtv) { ++ toq = ntohl(rtv->rtv_toq); ++ tov = ntohl(rtv->rtv_r_a_tov); ++ if (tov == 0) ++ tov = 1; ++ rp->r_a_tov = tov; ++ tov = ntohl(rtv->rtv_e_d_tov); ++ if (toq & FC_ELS_RTV_EDRES) ++ tov /= 1000000; ++ if (tov == 0) ++ tov = 1; ++ rp->e_d_tov = tov; ++ } ++ } ++ fc_rport_state_enter(rport, RPORT_ST_READY); ++ fc_rport_unlock(rport); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x ready\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state == LPORT_ST_DNS) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->tt.dns_register(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_rport_enter_rtv - Send Request Timeout Value (RTV) request to peer ++ * @rport: Fibre Channel remote port to send RTV to ++ */ ++static void fc_rport_enter_rtv(struct fc_rport *rport) ++{ ++ struct fc_els_rtv *rtv; ++ struct fc_frame *fp; ++ struct fc_lport *lp; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ ++ lp = rp->local_port; ++ fc_rport_state_enter(rport, RPORT_ST_RTV); ++ ++ fp = fc_frame_alloc(lp, sizeof(*rtv)); ++ if (!fp) ++ return fc_rport_retry(rport); ++ rtv = fc_frame_payload_get(fp, sizeof(*rtv)); ++ WARN_ON(!rtv); ++ memset(rtv, 0, sizeof(*rtv)); ++ rtv->rtv_cmd = ELS_RTV; ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_rport_rtv_resp, ++ rport, lp->e_d_tov, ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_retry(rport); ++} ++ ++/** ++ * fc_rport_enter_logo - Send Logout (LOGO) request to peer ++ * @rport: Fibre Channel remote port to send LOGO to ++ */ ++static void fc_rport_enter_logo(struct fc_rport *rport) ++{ ++ struct fc_frame *fp; ++ struct fc_els_logo *logo; ++ struct fc_lport *lp; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ ++ fc_rport_state_enter(rport, RPORT_ST_LOGO); ++ ++ lp = rp->local_port; ++ fp = fc_frame_alloc(lp, sizeof(*logo)); ++ if (!fp) ++ return fc_rport_retry(rport); ++ logo = fc_frame_payload_get(fp, sizeof(*logo)); ++ memset(logo, 0, sizeof(*logo)); ++ logo->fl_cmd = ELS_LOGO; ++ hton24(logo->fl_n_port_id, lp->fid); ++ logo->fl_n_port_wwn = htonll(lp->wwpn); ++ ++ fc_frame_setup(fp, FC_RCTL_ELS_REQ, FC_TYPE_ELS); ++ if (!lp->tt.exch_seq_send(lp, fp, ++ fc_rport_logo_resp, ++ rport, lp->e_d_tov, ++ rp->local_port->fid, ++ rport->port_id, ++ FC_FC_SEQ_INIT | FC_FC_END_SEQ)) ++ fc_rport_retry(rport); ++} ++ ++/* ++ * Handle a request received by the exchange manager for the session. ++ * This may be an entirely new session, or a PLOGI or LOGO for an existing one. ++ * This will free the frame. ++ */ ++void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, ++ struct fc_rport *rport) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_frame_header *fh; ++ struct fc_lport *lp = rp->local_port; ++ struct fc_seq_els_data els_data; ++ u8 op; ++ ++ els_data.fp = NULL; ++ els_data.explan = ELS_EXPL_NONE; ++ els_data.reason = ELS_RJT_NONE; ++ ++ fh = fc_frame_header_get(fp); ++ ++ if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) { ++ op = fc_frame_payload_op(fp); ++ switch (op) { ++ case ELS_PLOGI: ++ fc_rport_recv_plogi_req(rport, sp, fp); ++ break; ++ case ELS_PRLI: ++ fc_rport_recv_prli_req(rport, sp, fp); ++ break; ++ case ELS_PRLO: ++ fc_rport_recv_prlo_req(rport, sp, fp); ++ break; ++ case ELS_LOGO: ++ fc_rport_recv_logo_req(rport, sp, fp); ++ break; ++ case ELS_RRQ: ++ els_data.fp = fp; ++ lp->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); ++ break; ++ case ELS_REC: ++ els_data.fp = fp; ++ lp->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); ++ break; ++ default: ++ els_data.reason = ELS_RJT_UNSUP; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); ++ fc_frame_free(fp); ++ break; ++ } ++ } else { ++ fc_frame_free(fp); ++ } ++} ++ ++/** ++ * fc_rport_recv_plogi_req - Handle incoming Port Login (PLOGI) request ++ * @rport: Fibre Channel remote port that initiated PLOGI ++ * @sp: current sequence in the PLOGI exchange ++ * @fp: PLOGI request frame ++ */ ++static void fc_rport_recv_plogi_req(struct fc_rport *rport, ++ struct fc_seq *sp, struct fc_frame *rx_fp) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_frame *fp = rx_fp; ++ struct fc_frame_header *fh; ++ struct fc_lport *lp; ++ struct fc_els_flogi *pl; ++ struct fc_seq_els_data rjt_data; ++ u32 sid; ++ u64 wwpn; ++ u64 wwnn; ++ enum fc_els_rjt_reason reject = 0; ++ u32 f_ctl; ++ ++ rjt_data.fp = NULL; ++ fh = fc_frame_header_get(fp); ++ sid = ntoh24(fh->fh_s_id); ++ pl = fc_frame_payload_get(fp, sizeof(*pl)); ++ if (!pl) { ++ FC_DBG("incoming PLOGI from %x too short\n", sid); ++ WARN_ON(1); ++ /* XXX TBD: send reject? */ ++ fc_frame_free(fp); ++ return; ++ } ++ wwpn = get_unaligned_be64(&pl->fl_wwpn); ++ wwnn = get_unaligned_be64(&pl->fl_wwnn); ++ fc_rport_lock(rport); ++ lp = rp->local_port; ++ ++ /* ++ * If the session was just created, possibly due to the incoming PLOGI, ++ * set the state appropriately and accept the PLOGI. ++ * ++ * If we had also sent a PLOGI, and if the received PLOGI is from a ++ * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason ++ * "command already in progress". ++ * ++ * XXX TBD: If the session was ready before, the PLOGI should result in ++ * all outstanding exchanges being reset. ++ */ ++ switch (rp->rp_state) { ++ case RPORT_ST_INIT: ++ if (fc_rp_debug) ++ FC_DBG("incoming PLOGI from %6x wwpn %llx state INIT " ++ "- reject\n", sid, wwpn); ++ reject = ELS_RJT_UNSUP; ++ break; ++ case RPORT_ST_STARTED: ++ /* ++ * we'll only accept a login if the port name ++ * matches or was unknown. ++ */ ++ if (rport->port_name != -1 && ++ rport->port_name != wwpn) { ++ FC_DBG("incoming PLOGI from name %llx expected %llx\n", ++ wwpn, rport->port_name); ++ reject = ELS_RJT_UNAB; ++ } ++ break; ++ case RPORT_ST_PLOGI: ++ if (fc_rp_debug) ++ FC_DBG("incoming PLOGI from %x in PLOGI state %d\n", ++ sid, rp->rp_state); ++ if (wwpn < lp->wwpn) ++ reject = ELS_RJT_INPROG; ++ break; ++ case RPORT_ST_PRLI: ++ case RPORT_ST_ERROR: ++ case RPORT_ST_READY: ++ if (fc_rp_debug) ++ FC_DBG("incoming PLOGI from %x in logged-in state %d " ++ "- ignored for now\n", sid, rp->rp_state); ++ /* XXX TBD - should reset */ ++ break; ++ case RPORT_ST_NONE: ++ default: ++ if (fc_rp_debug) ++ FC_DBG("incoming PLOGI from %x in unexpected " ++ "state %d\n", sid, rp->rp_state); ++ break; ++ } ++ ++ if (reject) { ++ rjt_data.reason = reject; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ fc_frame_free(fp); ++ } else { ++ fp = fc_frame_alloc(lp, sizeof(*pl)); ++ if (fp == NULL) { ++ fp = rx_fp; ++ rjt_data.reason = ELS_RJT_UNAB; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ fc_frame_free(fp); ++ } else { ++ sp = lp->tt.seq_start_next(sp); ++ WARN_ON(!sp); ++ fc_rport_set_name(rport, wwpn, wwnn); ++ ++ /* ++ * Get session payload size from incoming PLOGI. ++ */ ++ rport->maxframe_size = ++ fc_plogi_get_maxframe(pl, lp->mfs); ++ fc_frame_free(rx_fp); ++ pl = fc_frame_payload_get(fp, sizeof(*pl)); ++ WARN_ON(!pl); ++ fc_lport_plogi_fill(lp, pl, ELS_LS_ACC); ++ ++ /* ++ * Send LS_ACC. If this fails, ++ * the originator should retry. ++ */ ++ f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ lp->tt.seq_send(lp, sp, fp, f_ctl); ++ if (rp->rp_state == RPORT_ST_PLOGI) ++ fc_rport_enter_prli(rport); ++ else ++ fc_rport_state_enter(rport, ++ RPORT_ST_PLOGI_RECV); ++ } ++ } ++ fc_rport_unlock(rport); ++} ++ ++/** ++ * fc_rport_recv_prli_req - Handle incoming Process Login (PRLI) request ++ * @rport: Fibre Channel remote port that initiated PRLI ++ * @sp: current sequence in the PRLI exchange ++ * @fp: PRLI request frame ++ */ ++static void fc_rport_recv_prli_req(struct fc_rport *rport, ++ struct fc_seq *sp, struct fc_frame *rx_fp) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_frame *fp; ++ struct fc_frame_header *fh; ++ struct fc_lport *lp; ++ struct { ++ struct fc_els_prli prli; ++ struct fc_els_spp spp; ++ } *pp; ++ struct fc_els_spp *rspp; /* request service param page */ ++ struct fc_els_spp *spp; /* response spp */ ++ unsigned int len; ++ unsigned int plen; ++ enum fc_els_rjt_reason reason = ELS_RJT_UNAB; ++ enum fc_els_rjt_explan explan = ELS_EXPL_NONE; ++ enum fc_els_spp_resp resp; ++ struct fc_seq_els_data rjt_data; ++ u32 f_ctl; ++ u32 fcp_parm; ++ u32 roles = FC_RPORT_ROLE_UNKNOWN; ++ ++ rjt_data.fp = NULL; ++ fh = fc_frame_header_get(rx_fp); ++ lp = rp->local_port; ++ switch (rp->rp_state) { ++ case RPORT_ST_PLOGI_RECV: ++ case RPORT_ST_PRLI: ++ case RPORT_ST_READY: ++ reason = ELS_RJT_NONE; ++ break; ++ default: ++ break; ++ } ++ len = fr_len(rx_fp) - sizeof(*fh); ++ pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); ++ if (pp == NULL) { ++ reason = ELS_RJT_PROT; ++ explan = ELS_EXPL_INV_LEN; ++ } else { ++ plen = ntohs(pp->prli.prli_len); ++ if ((plen % 4) != 0 || plen > len) { ++ reason = ELS_RJT_PROT; ++ explan = ELS_EXPL_INV_LEN; ++ } else if (plen < len) { ++ len = plen; ++ } ++ plen = pp->prli.prli_spp_len; ++ if ((plen % 4) != 0 || plen < sizeof(*spp) || ++ plen > len || len < sizeof(*pp)) { ++ reason = ELS_RJT_PROT; ++ explan = ELS_EXPL_INV_LEN; ++ } ++ rspp = &pp->spp; ++ } ++ if (reason != ELS_RJT_NONE || ++ (fp = fc_frame_alloc(lp, len)) == NULL) { ++ rjt_data.reason = reason; ++ rjt_data.explan = explan; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ } else { ++ sp = lp->tt.seq_start_next(sp); ++ WARN_ON(!sp); ++ pp = fc_frame_payload_get(fp, len); ++ WARN_ON(!pp); ++ memset(pp, 0, len); ++ pp->prli.prli_cmd = ELS_LS_ACC; ++ pp->prli.prli_spp_len = plen; ++ pp->prli.prli_len = htons(len); ++ len -= sizeof(struct fc_els_prli); ++ ++ /* ++ * Go through all the service parameter pages and build ++ * response. If plen indicates longer SPP than standard, ++ * use that. The entire response has been pre-cleared above. ++ */ ++ spp = &pp->spp; ++ while (len >= plen) { ++ spp->spp_type = rspp->spp_type; ++ spp->spp_type_ext = rspp->spp_type_ext; ++ spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR; ++ resp = FC_SPP_RESP_ACK; ++ if (rspp->spp_flags & FC_SPP_RPA_VAL) ++ resp = FC_SPP_RESP_NO_PA; ++ switch (rspp->spp_type) { ++ case 0: /* common to all FC-4 types */ ++ break; ++ case FC_TYPE_FCP: ++ fcp_parm = ntohl(rspp->spp_params); ++ if (fcp_parm * FCP_SPPF_RETRY) ++ rp->flags |= FC_RP_FLAGS_RETRY; ++ rport->supported_classes = FC_COS_CLASS3; ++ if (fcp_parm & FCP_SPPF_INIT_FCN) ++ roles |= FC_RPORT_ROLE_FCP_INITIATOR; ++ if (fcp_parm & FCP_SPPF_TARG_FCN) ++ roles |= FC_RPORT_ROLE_FCP_TARGET; ++ fc_remote_port_rolechg(rport, roles); ++ spp->spp_params = ++ htonl(rp->local_port->service_params); ++ break; ++ default: ++ resp = FC_SPP_RESP_INVL; ++ break; ++ } ++ spp->spp_flags |= resp; ++ len -= plen; ++ rspp = (struct fc_els_spp *)((char *)rspp + plen); ++ spp = (struct fc_els_spp *)((char *)spp + plen); ++ } ++ ++ /* ++ * Send LS_ACC. If this fails, the originator should retry. ++ */ ++ f_ctl = FC_FC_SEQ_INIT | FC_FC_LAST_SEQ | FC_FC_END_SEQ; ++ fc_frame_setup(fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); ++ lp->tt.seq_send(lp, sp, fp, f_ctl); ++ ++ /* ++ * Get lock and re-check state. ++ */ ++ fc_rport_lock(rport); ++ switch (rp->rp_state) { ++ case RPORT_ST_PLOGI_RECV: ++ case RPORT_ST_PRLI: ++ fc_rport_state_enter(rport, RPORT_ST_READY); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x ready\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state == LPORT_ST_DNS) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->tt.dns_register(lp); ++ fc_lport_unlock(lp); ++ } ++ break; ++ case RPORT_ST_READY: ++ break; ++ default: ++ break; ++ } ++ fc_rport_unlock(rport); ++ } ++ fc_frame_free(rx_fp); ++} ++ ++/** ++ * fc_rport_recv_prlo_req - Handle incoming Process Logout (PRLO) request ++ * @rport: Fibre Channel remote port that initiated PRLO ++ * @sp: current sequence in the PRLO exchange ++ * @fp: PRLO request frame ++ */ ++static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp, ++ struct fc_frame *fp) ++{ ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_frame_header *fh; ++ struct fc_lport *lp = rp->local_port; ++ struct fc_seq_els_data rjt_data; ++ ++ fh = fc_frame_header_get(fp); ++ FC_DBG("incoming PRLO from %x state %d\n", ++ ntoh24(fh->fh_s_id), rp->rp_state); ++ rjt_data.fp = NULL; ++ rjt_data.reason = ELS_RJT_UNAB; ++ rjt_data.explan = ELS_EXPL_NONE; ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); ++ fc_frame_free(fp); ++} ++ ++/** ++ * fc_rport_recv_logo_req - Handle incoming Logout (LOGO) request ++ * @rport: Fibre Channel remote port that initiated LOGO ++ * @sp: current sequence in the LOGO exchange ++ * @fp: LOGO request frame ++ */ ++static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp, ++ struct fc_frame *fp) ++{ ++ struct fc_frame_header *fh; ++ struct fc_rport_libfc_priv *rp = rport->dd_data; ++ struct fc_lport *lp = rp->local_port; ++ ++ fh = fc_frame_header_get(fp); ++ fc_rport_lock(rport); ++ fc_rport_state_enter(rport, RPORT_ST_INIT); ++ fc_rport_unlock(rport); ++ if (fc_rp_debug) ++ FC_DBG("remote %6x closed\n", rport->port_id); ++ if (rport == lp->dns_rp && ++ lp->state != LPORT_ST_RESET) { ++ fc_lport_lock(lp); ++ del_timer(&lp->state_timer); ++ lp->dns_rp = NULL; ++ if (lp->state == LPORT_ST_DNS_STOP) { ++ fc_lport_unlock(lp); ++ lp->tt.lport_logout(lp); ++ } else { ++ lp->tt.lport_login(lp); ++ fc_lport_unlock(lp); ++ } ++ fc_remote_port_delete(rport); ++ } ++ lp->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); ++ fc_frame_free(fp); ++} ++ ++int fc_rport_init(struct fc_lport *lp) ++{ ++ if (!lp->tt.rport_login) ++ lp->tt.rport_login = fc_rport_login; ++ ++ if (!lp->tt.rport_logout) ++ lp->tt.rport_logout = fc_rport_logout; ++ ++ if (!lp->tt.rport_recv_req) ++ lp->tt.rport_recv_req = fc_rport_recv_req; ++ ++ if (!lp->tt.rport_create) ++ lp->tt.rport_create = fc_remote_port_create; ++ ++ if (!lp->tt.rport_lookup) ++ lp->tt.rport_lookup = fc_rport_lookup; ++ ++ if (!lp->tt.rport_reset) ++ lp->tt.rport_reset = fc_rport_reset; ++ ++ if (!lp->tt.rport_reset_list) ++ lp->tt.rport_reset_list = fc_rport_reset_list; ++ ++ return 0; ++} ++EXPORT_SYMBOL(fc_rport_init); ++ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-rc1-update b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-rc1-update new file mode 100644 index 000000000..f140e2dd7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-fcoe-rc1-update @@ -0,0 +1,326 @@ +Subject: Update open-FCoE with latest patches from Intel +From: John Fastabend +Date: Fri Dec 5 16:35:38 2008 +0100: +References: bnc#438954 + +This updates the open-FCoE stack to version 1.0.5. + +Signed-off-by: John Fastabend +Acked-by: Hannes Reinecke + +diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c +index de29ccd..77f8857 100644 +--- a/drivers/scsi/fcoe/libfcoe.c ++++ b/drivers/scsi/fcoe/libfcoe.c +@@ -59,7 +59,7 @@ static int debug_fcoe; + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("FCoE"); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("1.0.4"); ++MODULE_VERSION("1.0.5"); + + /* fcoe host list */ + LIST_HEAD(fcoe_hostlist); +@@ -453,10 +453,9 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + /* adjust skb netowrk/transport offsets to match mac/fcoe/fc */ + skb_push(skb, elen + hlen); + skb_reset_mac_header(skb); +- skb_set_network_header(skb, elen); +- skb_set_transport_header(skb, elen + hlen); ++ skb_reset_network_header(skb); + skb->mac_len = elen; +- skb->protocol = htons(ETH_P_FCOE); ++ skb->protocol = htons(ETH_P_802_3); + skb->dev = fc->real_dev; + + /* fill up mac and fcoe headers */ +@@ -473,7 +472,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) + else + memcpy(eh->h_source, fc->data_src_addr, ETH_ALEN); + +- hp = (struct fcoe_hdr *)skb_network_header(skb); ++ hp = (struct fcoe_hdr *)(eh + 1); + memset(hp, 0, sizeof(*hp)); + if (FC_FCOE_VER) + FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); +diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c +index aee2f9c..0cd8d0c 100644 +--- a/drivers/scsi/libfc/fc_disc.c ++++ b/drivers/scsi/libfc/fc_disc.c +@@ -45,9 +45,6 @@ static int fc_disc_debug; + FC_DBG(fmt); \ + } while (0) + +-static struct mutex disc_list_lock; +-static struct list_head disc_list; +- + struct fc_disc { + unsigned char retry_count; + unsigned char delay; +@@ -66,7 +63,6 @@ struct fc_disc { + struct fc_gpn_ft_resp partial_buf; /* partial name buffer */ + struct delayed_work disc_work; + +- struct list_head list; + }; + + static void fc_disc_gpn_ft_req(struct fc_disc *); +@@ -87,26 +83,23 @@ static void fc_disc_restart(struct fc_disc *); + struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, + u32 port_id) + { +- struct fc_disc *disc; ++ struct fc_disc *disc = lport->disc; + struct fc_rport *rport, *found = NULL; + struct fc_rport_libfc_priv *rdata; + int disc_found = 0; + +- mutex_lock(&disc_list_lock); +- list_for_each_entry(disc, &disc_list, list) { +- if (disc->lport == lport) { +- list_for_each_entry(rdata, &disc->rports, peers) { +- rport = PRIV_TO_RPORT(rdata); +- if (rport->port_id == port_id) { +- disc_found = 1; +- found = rport; +- get_device(&found->dev); +- break; +- } +- } ++ if (!disc) ++ return NULL; ++ ++ list_for_each_entry(rdata, &disc->rports, peers) { ++ rport = PRIV_TO_RPORT(rdata); ++ if (rport->port_id == port_id) { ++ disc_found = 1; ++ found = rport; ++ get_device(&found->dev); ++ break; + } + } +- mutex_unlock(&disc_list_lock); + + if (!disc_found) { + FC_DEBUG_DISC("The rport (%6x) for lport (%6x) " +@@ -127,19 +120,15 @@ static inline struct fc_disc *fc_disc_alloc(struct fc_lport *lport) + struct fc_disc *disc; + + disc = kzalloc(sizeof(struct fc_disc), GFP_KERNEL); +- INIT_LIST_HEAD(&disc->list); + INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); + mutex_init(&disc->disc_mutex); + INIT_LIST_HEAD(&disc->rports); + + disc->lport = lport; ++ lport->disc = disc; + disc->delay = FC_DISC_DELAY; + disc->event = DISC_EV_NONE; + +- mutex_lock(&disc_list_lock); +- list_add_tail(&disc->list, &disc_list); +- mutex_unlock(&disc_list_lock); +- + return disc; + } + +@@ -182,23 +171,19 @@ static void fc_disc_rport_event(struct fc_lport *lport, + enum fc_lport_event event) + { + struct fc_rport_libfc_priv *rdata = rport->dd_data; +- struct fc_disc *disc; ++ struct fc_disc *disc = lport->disc; + int found = 0; + + FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event, + rport->port_id); + + if (event == RPORT_EV_CREATED) { +- mutex_lock(&disc_list_lock); +- list_for_each_entry(disc, &disc_list, list) { +- if (disc->lport == lport) { +- found = 1; +- mutex_lock(&disc->disc_mutex); +- list_add_tail(&rdata->peers, &disc->rports); +- mutex_unlock(&disc->disc_mutex); +- } ++ if (disc) { ++ found = 1; ++ mutex_lock(&disc->disc_mutex); ++ list_add_tail(&rdata->peers, &disc->rports); ++ mutex_unlock(&disc->disc_mutex); + } +- mutex_unlock(&disc_list_lock); + } + + if (!found) +@@ -323,19 +308,9 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, + struct fc_lport *lport) + { + u8 op; +- struct fc_disc *disc; +- int found = 0; +- +- mutex_lock(&disc_list_lock); +- list_for_each_entry(disc, &disc_list, list) { +- if (disc->lport == lport) { +- found = 1; +- break; +- } +- } +- mutex_unlock(&disc_list_lock); ++ struct fc_disc *disc = lport->disc; + +- if (!found) { ++ if (!disc) { + FC_DBG("Received a request for an lport not managed " + "by the discovery engine\n"); + return; +@@ -394,19 +369,9 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, + { + struct fc_rport *rport; + struct fc_rport_identifiers ids; +- struct fc_disc *disc; +- int found = 0; +- +- mutex_lock(&disc_list_lock); +- list_for_each_entry(disc, &disc_list, list) { +- if (disc->lport == lport) { +- found = 1; +- break; +- } +- } +- mutex_unlock(&disc_list_lock); ++ struct fc_disc *disc = lport->disc; + +- if (!found) { ++ if (!disc) { + FC_DEBUG_DISC("No existing discovery job, " + "creating one for lport (%6x)\n", + fc_host_port_id(lport->host)); +@@ -510,7 +475,7 @@ static int fc_disc_new_target(struct fc_disc *disc, + rport = fc_rport_rogue_create(&dp); + } + if (!rport) +- error = ENOMEM; ++ error = -ENOMEM; + } + if (rport) { + rp = rport->dd_data; +@@ -577,18 +542,16 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) + if (disc->retry_count < FC_DISC_RETRY_LIMIT) { + /* go ahead and retry */ + if (!fp) +- delay = msecs_to_jiffies(500); ++ delay = msecs_to_jiffies(FC_DISC_RETRY_DELAY); + else { +- delay = jiffies + +- msecs_to_jiffies(lport->e_d_tov); ++ delay = msecs_to_jiffies(lport->e_d_tov); + + /* timeout faster first time */ + if (!disc->retry_count) + delay /= 4; + } + disc->retry_count++; +- schedule_delayed_work(&disc->disc_work, +- delay); ++ schedule_delayed_work(&disc->disc_work, delay); + } else { + /* exceeded retries */ + disc->event = DISC_EV_FAILED; +@@ -868,16 +831,12 @@ out: + */ + void fc_disc_stop(struct fc_lport *lport) + { +- struct fc_disc *disc, *next; ++ struct fc_disc *disc = lport->disc; + +- mutex_lock(&disc_list_lock); +- list_for_each_entry_safe(disc, next, &disc_list, list) { +- if (disc->lport == lport) { +- cancel_delayed_work_sync(&disc->disc_work); +- fc_disc_stop_rports(disc); +- } ++ if (disc) { ++ cancel_delayed_work_sync(&disc->disc_work); ++ fc_disc_stop_rports(disc); + } +- mutex_unlock(&disc_list_lock); + } + + /** +@@ -889,18 +848,8 @@ void fc_disc_stop(struct fc_lport *lport) + */ + void fc_disc_stop_final(struct fc_lport *lport) + { +- struct fc_disc *disc, *next; + fc_disc_stop(lport); + lport->tt.rport_flush_queue(); +- +- mutex_lock(&disc_list_lock); +- list_for_each_entry_safe(disc, next, &disc_list, list) { +- if (disc->lport == lport) { +- list_del(&disc->list); +- kfree(disc); +- } +- } +- mutex_unlock(&disc_list_lock); + } + + /** +@@ -909,8 +858,6 @@ void fc_disc_stop_final(struct fc_lport *lport) + */ + int fc_disc_init(struct fc_lport *lport) + { +- INIT_LIST_HEAD(&disc_list); +- mutex_init(&disc_list_lock); + + if (!lport->tt.disc_start) + lport->tt.disc_start = fc_disc_start; +diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c +index 04ced7f..2426501 100644 +--- a/drivers/scsi/libfc/fc_fcp.c ++++ b/drivers/scsi/libfc/fc_fcp.c +@@ -42,6 +42,7 @@ + MODULE_AUTHOR("Open-FCoE.org"); + MODULE_DESCRIPTION("libfc"); + MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0.5"); + + static int fc_fcp_debug; + +diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c +index 083d57b..de16203 100644 +--- a/drivers/scsi/libfc/fc_lport.c ++++ b/drivers/scsi/libfc/fc_lport.c +@@ -577,6 +577,8 @@ int fc_fabric_logoff(struct fc_lport *lport) + { + lport->tt.disc_stop_final(lport); + mutex_lock(&lport->lp_mutex); ++ kfree(lport->disc); ++ lport->disc = NULL; + fc_lport_enter_logo(lport); + mutex_unlock(&lport->lp_mutex); + return 0; +diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h +index dac03e2..587be50 100644 +--- a/include/scsi/libfc.h ++++ b/include/scsi/libfc.h +@@ -570,6 +570,8 @@ struct libfc_function_template { + void (*disc_stop_final) (struct fc_lport *); + }; + ++struct fc_disc; ++ + struct fc_lport { + struct list_head list; + +@@ -578,6 +580,7 @@ struct fc_lport { + struct fc_exch_mgr *emp; + struct fc_rport *dns_rp; + struct fc_rport *ptp_rp; ++ struct fc_disc *disc; + void *scsi_priv; + + /* Operational Information */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/open-iscsi-offloading-support b/src/patches/suse-2.6.27.31/patches.drivers/open-iscsi-offloading-support new file mode 100644 index 000000000..f425cf5eb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/open-iscsi-offloading-support @@ -0,0 +1,675 @@ +Subject: support for iscsi pdu digest offload and payload DDP. +From: Karen Xie +References: FATE#304154,bnc#433500 + +Added PDU digest offload and payload direct-placement support in open-iscsi. + +Signed-off-by: Karen Xie +Signed-off-by: Chandra Seetharaman +Signed-off-by: Hannes Reinecke +--- + +--- + drivers/scsi/iscsi_tcp.c | 55 ++++++++++++----- + drivers/scsi/iscsi_tcp.h | 16 +++++ + drivers/scsi/libiscsi.c | 111 ++++++++++++++++++++++++++++-------- + drivers/scsi/scsi_transport_iscsi.c | 8 +- + include/scsi/iscsi_if.h | 1 + include/scsi/libiscsi.h | 12 +++ + include/scsi/scsi_transport_iscsi.h | 9 ++ + 7 files changed, 166 insertions(+), 46 deletions(-) + +--- a/drivers/scsi/iscsi_tcp.c ++++ b/drivers/scsi/iscsi_tcp.c +@@ -97,7 +97,7 @@ static int iscsi_tcp_hdr_recv_done(struc + * data is copied to the indicated sg entry, at the given + * offset. + */ +-static inline void ++void + iscsi_tcp_segment_init_sg(struct iscsi_segment *segment, + struct scatterlist *sg, unsigned int offset) + { +@@ -107,6 +107,7 @@ iscsi_tcp_segment_init_sg(struct iscsi_s + segment->total_size - segment->total_copied); + segment->data = NULL; + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_segment_init_sg); + + /** + * iscsi_tcp_segment_map - map the current S/G page +@@ -117,7 +118,7 @@ iscsi_tcp_segment_init_sg(struct iscsi_s + * because the iscsi passthrough and internal IO paths will never use high + * mem pages. + */ +-static inline void ++void + iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) + { + struct scatterlist *sg; +@@ -143,8 +144,9 @@ iscsi_tcp_segment_map(struct iscsi_segme + segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_segment_map); + +-static inline void ++void + iscsi_tcp_segment_unmap(struct iscsi_segment *segment) + { + debug_tcp("iscsi_tcp_segment_unmap %p\n", segment); +@@ -156,6 +158,7 @@ iscsi_tcp_segment_unmap(struct iscsi_seg + segment->data = NULL; + } + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_segment_unmap); + + /* + * Splice the digest buffer into the buffer +@@ -376,6 +379,9 @@ static inline int + iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) + { ++ if (tcp_conn->iscsi_conn->session->tt->caps & CAP_DIGEST_OFFLOAD) ++ return (segment->status & ISCSI_SEGMENT_DGST_ERR) ? 0 : 1; ++ + if (!segment->digest_len) + return 1; + +@@ -448,7 +454,7 @@ iscsi_segment_seek_sg(struct iscsi_segme + * function is called we do not yet know the final size of the header and want + * to delay the digest processing until we know that. + */ +-static void ++void + iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn) + { + debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn, +@@ -457,6 +463,7 @@ iscsi_tcp_hdr_recv_prep(struct iscsi_tcp + tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr), + iscsi_tcp_hdr_recv_done, NULL); + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_recv_prep); + + /* + * Handle incoming reply to any other type of command +@@ -486,7 +493,8 @@ iscsi_tcp_data_recv_prep(struct iscsi_tc + struct iscsi_conn *conn = tcp_conn->iscsi_conn; + struct hash_desc *rx_hash = NULL; + +- if (conn->datadgst_en) ++ if (conn->datadgst_en && ++ !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) + rx_hash = &tcp_conn->rx_hash; + + iscsi_segment_init_linear(&tcp_conn->in.segment, +@@ -497,7 +505,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tc + /* + * must be called with session lock + */ +-static void ++void + iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) + { + struct iscsi_tcp_task *tcp_task = task->dd_data; +@@ -521,6 +529,7 @@ iscsi_tcp_cleanup_task(struct iscsi_conn + tcp_task->r2t = NULL; + } + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task); + + /** + * iscsi_data_rsp - SCSI Data-In Response processing +@@ -737,7 +746,7 @@ iscsi_tcp_process_data_in(struct iscsi_t + * by data, the receive buffer is set up to copy the incoming data + * to the correct location. + */ +-static int ++int + iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) + { + int rc = 0, opcode, ahslen; +@@ -793,7 +802,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn + * we move on to the next scatterlist entry and + * update the digest per-entry. + */ +- if (conn->datadgst_en) ++ if (conn->datadgst_en && ++ !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) + rx_hash = &tcp_conn->rx_hash; + + debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " +@@ -881,6 +891,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn + + return rc; + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_dissect); + + /** + * iscsi_tcp_hdr_recv_done - process PDU header +@@ -919,7 +930,8 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp + /* We're done processing the header. See if we're doing + * header digests; if so, set up the recv_digest buffer + * and go back for more. */ +- if (conn->hdrdgst_en) { ++ if (conn->hdrdgst_en && ++ !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) { + if (segment->digest_len == 0) { + iscsi_tcp_segment_splice_digest(segment, + segment->recv_digest); +@@ -1161,10 +1173,11 @@ iscsi_tcp_xmit_qlen(struct iscsi_conn *c + static inline int + iscsi_tcp_flush(struct iscsi_conn *conn) + { ++ struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + int rc; + + while (iscsi_tcp_xmit_qlen(conn)) { +- rc = iscsi_xmit(conn); ++ rc = tcp_conn->xmit_segment(conn); + if (rc == 0) + return -EAGAIN; + if (rc < 0) +@@ -1205,7 +1218,8 @@ iscsi_tcp_send_hdr_prep(struct iscsi_con + * sure that both iscsi_tcp_task and mtask have + * sufficient room. + */ +- if (conn->hdrdgst_en) { ++ if (conn->hdrdgst_en && ++ !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) { + iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen, + hdr + hdrlen); + hdrlen += ISCSI_DIGEST_SIZE; +@@ -1243,7 +1257,8 @@ iscsi_tcp_send_data_prep(struct iscsi_co + hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength); + WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); + +- if (conn->datadgst_en) ++ if (conn->datadgst_en && ++ !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) + tx_hash = &tcp_conn->tx_hash; + + return iscsi_segment_seek_sg(&tcp_conn->out.data_segment, +@@ -1267,7 +1282,8 @@ iscsi_tcp_send_linear_data_prepare(struc + hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength); + WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); + +- if (conn->datadgst_en) ++ if (conn->datadgst_en && ++ !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) + tx_hash = &tcp_conn->tx_hash; + + iscsi_segment_init_linear(&tcp_conn->out.data_segment, +@@ -1329,7 +1345,7 @@ iscsi_solicit_data_cont(struct iscsi_con + * @task: scsi command task + * @sc: scsi command + **/ +-static int ++int + iscsi_tcp_task_init(struct iscsi_task *task) + { + struct iscsi_tcp_task *tcp_task = task->dd_data; +@@ -1378,6 +1394,7 @@ iscsi_tcp_task_init(struct iscsi_task *t + task->imm_count = 0; + return 0; + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_task_init); + + /* + * iscsi_tcp_task_xmit - xmit normal PDU task +@@ -1387,7 +1404,7 @@ iscsi_tcp_task_init(struct iscsi_task *t + * -EAGAIN if there's still data in the queue, or != 0 for any other kind + * of error. + */ +-static int ++int + iscsi_tcp_task_xmit(struct iscsi_task *task) + { + struct iscsi_conn *conn = task->conn; +@@ -1490,6 +1507,7 @@ fail: + iscsi_conn_failure(conn, rc); + return -EIO; + } ++EXPORT_SYMBOL_GPL(iscsi_tcp_task_xmit); + + static struct iscsi_cls_conn * + iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) +@@ -1685,6 +1703,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_ses + + iscsi_conn_set_callbacks(conn); + tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; ++ tcp_conn->xmit_segment = iscsi_xmit; + /* + * set receive state machine into initial state + */ +@@ -1696,7 +1715,7 @@ free_socket: + return err; + } + +-static int ++int + iscsi_r2tpool_alloc(struct iscsi_session *session) + { + int i; +@@ -1742,8 +1761,9 @@ r2t_alloc_fail: + } + return -ENOMEM; + } ++EXPORT_SYMBOL_GPL(iscsi_r2tpool_alloc); + +-static void ++void + iscsi_r2tpool_free(struct iscsi_session *session) + { + int i; +@@ -1756,6 +1776,7 @@ iscsi_r2tpool_free(struct iscsi_session + iscsi_pool_free(&tcp_task->r2tpool); + } + } ++EXPORT_SYMBOL_GPL(iscsi_r2tpool_free); + + static int + iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, +--- a/drivers/scsi/iscsi_tcp.h ++++ b/drivers/scsi/iscsi_tcp.h +@@ -32,7 +32,9 @@ struct iscsi_segment; + typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *, + struct iscsi_segment *); + ++#define ISCSI_SEGMENT_DGST_ERR 0x1 + struct iscsi_segment { ++ unsigned int status; + unsigned char *data; + unsigned int size; + unsigned int copied; +@@ -95,6 +97,8 @@ struct iscsi_tcp_conn { + + int error; + ++ /* segment transmit */ ++ int (*xmit_segment)(struct iscsi_conn *); + ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); + }; + +@@ -130,4 +134,16 @@ struct iscsi_tcp_task { + struct iscsi_data_task unsol_dtask; /* Data-Out header buf */ + }; + ++void iscsi_tcp_segment_init_sg(struct iscsi_segment *, struct scatterlist *, ++ unsigned int); ++void iscsi_tcp_segment_map(struct iscsi_segment *, int); ++void iscsi_tcp_segment_unmap(struct iscsi_segment *); ++void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *); ++void iscsi_tcp_cleanup_task(struct iscsi_conn *, struct iscsi_task *); ++int iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *); ++int iscsi_tcp_task_init(struct iscsi_task *); ++int iscsi_tcp_task_xmit(struct iscsi_task *); ++int iscsi_r2tpool_alloc(struct iscsi_session *); ++void iscsi_r2tpool_free(struct iscsi_session *); ++ + #endif /* ISCSI_H */ +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -218,7 +218,12 @@ static int iscsi_prep_scsi_cmd_pdu(struc + hdr->opcode = ISCSI_OP_SCSI_CMD; + hdr->flags = ISCSI_ATTR_SIMPLE; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); +- hdr->itt = build_itt(task->itt, session->age); ++ if (session->tt->reserve_itt) { ++ rc = session->tt->reserve_itt(task, &hdr->itt); ++ if (rc) ++ return rc; ++ } else ++ hdr->itt = build_itt(task->itt, session->age); + hdr->cmdsn = cpu_to_be32(session->cmdsn); + session->cmdsn++; + hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); +@@ -332,6 +337,9 @@ static void iscsi_complete_command(struc + struct iscsi_session *session = conn->session; + struct scsi_cmnd *sc = task->sc; + ++ if (session->tt->release_itt) ++ session->tt->release_itt(task, task->hdr->itt); ++ + list_del_init(&task->running); + task->state = ISCSI_TASK_COMPLETED; + task->sc = NULL; +@@ -443,7 +451,12 @@ static int iscsi_prep_mgmt_task(struct i + */ + nop->cmdsn = cpu_to_be32(session->cmdsn); + if (hdr->itt != RESERVED_ITT) { +- hdr->itt = build_itt(task->itt, session->age); ++ if (session->tt->reserve_itt) { ++ int rc = session->tt->reserve_itt(task, &hdr->itt); ++ if (rc) ++ return rc; ++ } else ++ hdr->itt = build_itt(task->itt, session->age); + /* + * TODO: We always use immediate, so we never hit this. + * If we start to send tmfs or nops as non-immediate then +@@ -692,7 +705,13 @@ static int iscsi_handle_reject(struct is + + if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { + memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); +- itt = get_itt(rejected_pdu.itt); ++ if (conn->session->tt->parse_itt) ++ conn->session->tt->parse_itt(conn, ++ rejected_pdu.itt, ++ &itt, ++ NULL); ++ else ++ itt = get_itt(rejected_pdu.itt); + iscsi_conn_printk(KERN_ERR, conn, + "itt 0x%x had pdu (op 0x%x) rejected " + "due to DataDigest error.\n", itt, +@@ -720,7 +739,10 @@ struct iscsi_task *iscsi_itt_to_task(str + if (itt == RESERVED_ITT) + return NULL; + +- i = get_itt(itt); ++ if (conn->session->tt->parse_itt) ++ conn->session->tt->parse_itt(conn, itt, &i, NULL); ++ else ++ i = get_itt(itt); + if (i >= session->cmds_max) + return NULL; + +@@ -752,9 +774,13 @@ int __iscsi_complete_pdu(struct iscsi_co + if (rc) + return rc; + +- if (hdr->itt != RESERVED_ITT) +- itt = get_itt(hdr->itt); +- else ++ if (hdr->itt != RESERVED_ITT) { ++ if (conn->session->tt->parse_itt) ++ conn->session->tt->parse_itt(conn, hdr->itt, ++ &itt, NULL); ++ else ++ itt = get_itt(hdr->itt); ++ } else + itt = ~0U; + + debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n", +@@ -901,20 +927,25 @@ EXPORT_SYMBOL_GPL(iscsi_complete_pdu); + int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt) + { + struct iscsi_session *session = conn->session; +- uint32_t i; ++ uint32_t i, age; + + if (itt == RESERVED_ITT) + return 0; + +- if (((__force u32)itt & ISCSI_AGE_MASK) != +- (session->age << ISCSI_AGE_SHIFT)) { ++ if (conn->session->tt->parse_itt) ++ conn->session->tt->parse_itt(conn, itt, &i, &age); ++ else { ++ i = get_itt(itt); ++ age = ((__force u32)itt >> ISCSI_AGE_SHIFT) & ISCSI_AGE_MASK; ++ } ++ ++ if (age != session->age) { + iscsi_conn_printk(KERN_ERR, conn, + "received itt %x expected session age (%x)\n", + (__force u32)itt, session->age); + return ISCSI_ERR_BAD_ITT; + } + +- i = get_itt(itt); + if (i >= session->cmds_max) { + iscsi_conn_printk(KERN_ERR, conn, + "received invalid itt index %u (max cmds " +@@ -1930,13 +1961,15 @@ struct Scsi_Host *iscsi_host_alloc(struc + shost->cmd_per_lun = qdepth; + + ihost = shost_priv(shost); +- atomic_set(&ihost->num_sessions, 0); ++ spin_lock_init(&ihost->lock); ++ ihost->state = ISCSI_HOST_SETUP; ++ ihost->num_sessions = 0; + init_waitqueue_head(&ihost->session_removal_wq); + return shost; + } + EXPORT_SYMBOL_GPL(iscsi_host_alloc); + +-static void iscsi_kill_session(struct iscsi_cls_session *cls_session) ++static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session) + { + iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST); + } +@@ -1951,10 +1984,15 @@ static void iscsi_kill_session(struct is + void iscsi_host_remove(struct Scsi_Host *shost) + { + struct iscsi_host *ihost = shost_priv(shost); ++ unsigned long flags; + +- iscsi_host_for_each_session(shost, iscsi_kill_session); ++ spin_lock_irqsave(&ihost->lock, flags); ++ ihost->state = ISCSI_HOST_REMOVED; ++ spin_unlock_irqrestore(&ihost->lock, flags); ++ ++ iscsi_host_for_each_session(shost, iscsi_notify_host_removed); + wait_event_interruptible(ihost->session_removal_wq, +- atomic_read(&ihost->num_sessions) == 0); ++ ihost->num_sessions == 0); + if (signal_pending(current)) + flush_signals(current); + +@@ -1973,6 +2011,27 @@ void iscsi_host_free(struct Scsi_Host *s + } + EXPORT_SYMBOL_GPL(iscsi_host_free); + ++static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost) ++{ ++ struct iscsi_host *ihost = shost_priv(shost); ++ unsigned long flags; ++ ++ shost = scsi_host_get(shost); ++ if (!shost) { ++ printk(KERN_ERR "Invalid state. Cannot notify host removal " ++ "of session teardown event because host already " ++ "removed.\n"); ++ return; ++ } ++ ++ spin_lock_irqsave(&ihost->lock, flags); ++ ihost->num_sessions--; ++ if (ihost->num_sessions == 0) ++ wake_up(&ihost->session_removal_wq); ++ spin_unlock_irqrestore(&ihost->lock, flags); ++ scsi_host_put(shost); ++} ++ + /** + * iscsi_session_setup - create iscsi cls session and host and session + * @iscsit: iscsi transport template +@@ -1997,6 +2056,15 @@ iscsi_session_setup(struct iscsi_transpo + struct iscsi_session *session; + struct iscsi_cls_session *cls_session; + int cmd_i, scsi_cmds, total_cmds = cmds_max; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ihost->lock, flags); ++ if (ihost->state == ISCSI_HOST_REMOVED) { ++ spin_unlock_irqrestore(&ihost->lock, flags); ++ return NULL; ++ } ++ ihost->num_sessions++; ++ spin_unlock_irqrestore(&ihost->lock, flags); + + if (!total_cmds) + total_cmds = ISCSI_DEF_XMIT_CMDS_MAX; +@@ -2009,7 +2077,7 @@ iscsi_session_setup(struct iscsi_transpo + printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " + "must be a power of two that is at least %d.\n", + total_cmds, ISCSI_TOTAL_CMDS_MIN); +- return NULL; ++ goto dec_session_count; + } + + if (total_cmds > ISCSI_TOTAL_CMDS_MAX) { +@@ -2033,7 +2101,7 @@ iscsi_session_setup(struct iscsi_transpo + cls_session = iscsi_alloc_session(shost, iscsit, + sizeof(struct iscsi_session)); + if (!cls_session) +- return NULL; ++ goto dec_session_count; + session = cls_session->dd_data; + session->cls_session = cls_session; + session->host = shost; +@@ -2073,7 +2141,6 @@ iscsi_session_setup(struct iscsi_transpo + if (iscsi_add_session(cls_session, id)) + goto cls_session_fail; + +- atomic_inc(&ihost->num_sessions); + return cls_session; + + cls_session_fail: +@@ -2082,6 +2149,8 @@ module_get_fail: + iscsi_pool_free(&session->cmdpool); + cmdpool_alloc_fail: + iscsi_free_session(cls_session); ++dec_session_count: ++ iscsi_host_dec_session_cnt(shost); + return NULL; + } + EXPORT_SYMBOL_GPL(iscsi_session_setup); +@@ -2096,8 +2165,8 @@ EXPORT_SYMBOL_GPL(iscsi_session_setup); + void iscsi_session_teardown(struct iscsi_cls_session *cls_session) + { + struct iscsi_session *session = cls_session->dd_data; +- struct iscsi_host *ihost = shost_priv(session->host); + struct module *owner = cls_session->transport->owner; ++ struct Scsi_Host *shost = session->host; + + iscsi_pool_free(&session->cmdpool); + +@@ -2111,9 +2180,7 @@ void iscsi_session_teardown(struct iscsi + + iscsi_destroy_session(cls_session); + +- atomic_dec(&ihost->num_sessions); +- wake_up(&ihost->session_removal_wq); +- ++ iscsi_host_dec_session_cnt(shost); + module_put(owner); + } + EXPORT_SYMBOL_GPL(iscsi_session_teardown); +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -138,7 +138,7 @@ static ssize_t + show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf) + { + struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); +- return sprintf(buf, "%u\n", ep->id); ++ return sprintf(buf, "%llu\n", (unsigned long long)ep->id); + } + static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); + +@@ -156,7 +156,7 @@ static struct attribute_group iscsi_endp + static int iscsi_match_epid(struct device *dev, void *data) + { + struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); +- unsigned int *epid = (unsigned int *) data; ++ uint64_t *epid = (uint64_t *) data; + + return *epid == ep->id; + } +@@ -166,7 +166,7 @@ iscsi_create_endpoint(int dd_size) + { + struct device *dev; + struct iscsi_endpoint *ep; +- unsigned int id; ++ uint64_t id; + int err; + + for (id = 1; id < ISCSI_MAX_EPID; id++) { +@@ -187,7 +187,7 @@ iscsi_create_endpoint(int dd_size) + + ep->id = id; + ep->dev.class = &iscsi_endpoint_class; +- snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%u", id); ++ snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%llu", id); + err = device_register(&ep->dev); + if (err) + goto free_ep; +--- a/include/scsi/iscsi_if.h ++++ b/include/scsi/iscsi_if.h +@@ -334,6 +334,7 @@ enum iscsi_host_param { + #define CAP_FW_DB 0x200 + #define CAP_SENDTARGETS_OFFLOAD 0x400 + #define CAP_DATA_PATH_OFFLOAD 0x800 ++#define CAP_DIGEST_OFFLOAD 0x1000 + + /* + * These flags describes reason of stop_conn() call +--- a/include/scsi/libiscsi.h ++++ b/include/scsi/libiscsi.h +@@ -75,7 +75,7 @@ enum { + /* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */ + #define ISCSI_TOTAL_CMDS_MIN 16 + #define ISCSI_AGE_SHIFT 28 +-#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) ++#define ISCSI_AGE_MASK 0xf + + #define ISCSI_ADDRESS_BUF_LEN 64 + +@@ -287,6 +287,10 @@ struct iscsi_session { + struct iscsi_pool cmdpool; /* PDU's pool */ + }; + ++enum { ++ ISCSI_HOST_SETUP, ++ ISCSI_HOST_REMOVED, ++}; + struct iscsi_host { + char *initiatorname; + /* hw address or netdev iscsi connection is bound to */ +@@ -297,7 +301,11 @@ struct iscsi_host { + char local_address[ISCSI_ADDRESS_BUF_LEN]; + + wait_queue_head_t session_removal_wq; +- atomic_t num_sessions; ++ ++ /* protects sessions and state */ ++ spinlock_t lock; ++ int num_sessions; ++ int state; + }; + + /* +--- a/include/scsi/scsi_transport_iscsi.h ++++ b/include/scsi/scsi_transport_iscsi.h +@@ -56,6 +56,9 @@ struct sockaddr; + * is not supported, and a -Exx value on other error + * @start_conn: set connection to be operational + * @stop_conn: suspend/recover/terminate connection ++ * @parse_itt: parse the itt rcv'ed in BHS ++ * @reserve_itt: construct a task itt to be sent in BHS ++ * @release_itt: release a itt (constructed by reserve_itt) + * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. + * @session_recovery_timedout: notify LLD a block during recovery timed out + * @init_task: Initialize a iscsi_task and any internal structs. +@@ -109,6 +112,10 @@ struct iscsi_transport { + int (*set_host_param) (struct Scsi_Host *shost, + enum iscsi_host_param param, char *buf, + int buflen); ++ void (*parse_itt)(struct iscsi_conn *conn, itt_t hdr_itt, ++ int *idx, int *age); ++ int (*reserve_itt)(struct iscsi_task *task, itt_t *hdr_itt); ++ void (*release_itt)(struct iscsi_task *task, itt_t hdr_itt); + int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size); + void (*get_stats) (struct iscsi_cls_conn *conn, +@@ -207,7 +214,7 @@ extern void iscsi_host_for_each_session( + struct iscsi_endpoint { + void *dd_data; /* LLD private data */ + struct device dev; +- unsigned int id; ++ uint64_t id; + }; + + /* diff --git a/src/patches/suse-2.6.27.31/patches.drivers/panasonic-laptop-add-panasonic-let-s-note-laptop-extras-driver-v0.94.patch b/src/patches/suse-2.6.27.31/patches.drivers/panasonic-laptop-add-panasonic-let-s-note-laptop-extras-driver-v0.94.patch new file mode 100644 index 000000000..65966227b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/panasonic-laptop-add-panasonic-let-s-note-laptop-extras-driver-v0.94.patch @@ -0,0 +1,853 @@ +From 709ee531c153038d81b30649b9eeed3c44a4d5cc Mon Sep 17 00:00:00 2001 +From: Harald Welte +Date: Tue, 23 Sep 2008 17:46:57 +0200 +Subject: panasonic-laptop: add Panasonic Let's Note laptop extras driver v0.94 +Patch-mainline: 2.6.28 + +This is a driver for ACPI extras such as hotkeys and backlight +brightness control on various Panasonic "Let's Note" series laptop +computers. + +It exports the backlight via the backlight class device API, +and the hotkeys as input event device. Some more esoteric +items like number of installed batteries are exported via sysfs +device attributes. + +Hotkey events also generate old-style ACPI enents through +/proc/acpi/event to interoperate with current versions of acpid. + +Signed-off-by: Harald Welte +Acked-by: Henrique de Moraes Holschuh +Acked-by: Matthew Garrett +Signed-off-by: Len Brown +Signed-off-by: Greg Kroah-Hartman + +--- + MAINTAINERS | 5 + drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 1 + drivers/misc/panasonic-laptop.c | 767 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 784 insertions(+) + +Index: linux-2.6.27-sles11/drivers/misc/Kconfig +=================================================================== +--- linux-2.6.27-sles11.orig/drivers/misc/Kconfig ++++ linux-2.6.27-sles11/drivers/misc/Kconfig +@@ -245,6 +245,17 @@ config MSI_LAPTOP + + If you have an MSI S270 laptop, say Y or M here. + ++config PANASONIC_LAPTOP ++ tristate "Panasonic Laptop Extras" ++ depends on X86 && INPUT ++ depends on BACKLIGHT_CLASS_DEVICE ++ ---help--- ++ This driver adds support for access to backlight control and hotkeys ++ on Panasonic Let's Note laptops. ++ ++ If you have a Panasonic Let's note laptop (such as the R1(N variant), ++ R2, R3, R5, T2, W2 and Y2 series), say Y. ++ + config COMPAL_LAPTOP + tristate "Compal Laptop Extras" + depends on X86 +Index: linux-2.6.27-sles11/drivers/misc/Makefile +=================================================================== +--- linux-2.6.27-sles11.orig/drivers/misc/Makefile ++++ linux-2.6.27-sles11/drivers/misc/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_SGI_IOC4) += ioc4.o + obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o + obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o + obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o ++obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o + obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o + obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o + obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o +Index: linux-2.6.27-sles11/drivers/misc/panasonic-laptop.c +=================================================================== +--- /dev/null ++++ linux-2.6.27-sles11/drivers/misc/panasonic-laptop.c +@@ -0,0 +1,767 @@ ++/* ++ * Panasonic HotKey and LCD brightness control driver ++ * (C) 2004 Hiroshi Miura ++ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/ ++ * (C) YOKOTA Hiroshi ++ * (C) 2004 David Bronaugh ++ * (C) 2006-2008 Harald Welte ++ * ++ * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte ++ * ++ * 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 ++ * publicshed by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ *--------------------------------------------------------------------------- ++ * ++ * ChangeLog: ++ * Sep.23, 2008 Harald Welte ++ * -v0.95 rename driver from drivers/acpi/pcc_acpi.c to ++ * drivers/misc/panasonic-laptop.c ++ * ++ * Jul.04, 2008 Harald Welte ++ * -v0.94 replace /proc interface with device attributes ++ * support {set,get}keycode on th input device ++ * ++ * Jun.27, 2008 Harald Welte ++ * -v0.92 merge with 2.6.26-rc6 input API changes ++ * remove broken <= 2.6.15 kernel support ++ * resolve all compiler warnings ++ * various coding style fixes (checkpatch.pl) ++ * add support for backlight api ++ * major code restructuring ++ * ++ * Dac.28, 2007 Harald Welte ++ * -v0.91 merge with 2.6.24-rc6 ACPI changes ++ * ++ * Nov.04, 2006 Hiroshi Miura ++ * -v0.9 remove warning about section reference. ++ * remove acpi_os_free ++ * add /proc/acpi/pcc/brightness interface for HAL access ++ * merge dbronaugh's enhancement ++ * Aug.17, 2004 David Bronaugh (dbronaugh) ++ * - Added screen brightness setting interface ++ * Thanks to FreeBSD crew (acpi_panasonic.c) ++ * for the ideas I needed to accomplish it ++ * ++ * May.29, 2006 Hiroshi Miura ++ * -v0.8.4 follow to change keyinput structure ++ * thanks Fabian Yamaguchi , ++ * Jacob Bower and ++ * Hiroshi Yokota for providing solutions. ++ * ++ * Oct.02, 2004 Hiroshi Miura ++ * -v0.8.2 merge code of YOKOTA Hiroshi ++ * . ++ * Add sticky key mode interface. ++ * Refactoring acpi_pcc_generate_keyinput(). ++ * ++ * Sep.15, 2004 Hiroshi Miura ++ * -v0.8 Generate key input event on input subsystem. ++ * This is based on yet another driver written by ++ * Ryuta Nakanishi. ++ * ++ * Sep.10, 2004 Hiroshi Miura ++ * -v0.7 Change proc interface functions using seq_file ++ * facility as same as other ACPI drivers. ++ * ++ * Aug.28, 2004 Hiroshi Miura ++ * -v0.6.4 Fix a silly error with status checking ++ * ++ * Aug.25, 2004 Hiroshi Miura ++ * -v0.6.3 replace read_acpi_int by standard function ++ * acpi_evaluate_integer ++ * some clean up and make smart copyright notice. ++ * fix return value of pcc_acpi_get_key() ++ * fix checking return value of acpi_bus_register_driver() ++ * ++ * Aug.22, 2004 David Bronaugh ++ * -v0.6.2 Add check on ACPI data (num_sifr) ++ * Coding style cleanups, better error messages/handling ++ * Fixed an off-by-one error in memory allocation ++ * ++ * Aug.21, 2004 David Bronaugh ++ * -v0.6.1 Fix a silly error with status checking ++ * ++ * Aug.20, 2004 David Bronaugh ++ * - v0.6 Correct brightness controls to reflect reality ++ * based on information gleaned by Hiroshi Miura ++ * and discussions with Hiroshi Miura ++ * ++ * Aug.10, 2004 Hiroshi Miura ++ * - v0.5 support LCD brightness control ++ * based on the disclosed information by MEI. ++ * ++ * Jul.25, 2004 Hiroshi Miura ++ * - v0.4 first post version ++ * add function to retrive SIFR ++ * ++ * Jul.24, 2004 Hiroshi Miura ++ * - v0.3 get proper status of hotkey ++ * ++ * Jul.22, 2004 Hiroshi Miura ++ * - v0.2 add HotKey handler ++ * ++ * Jul.17, 2004 Hiroshi Miura ++ * - v0.1 start from toshiba_acpi driver written by John Belmonte ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifndef ACPI_HOTKEY_COMPONENT ++#define ACPI_HOTKEY_COMPONENT 0x10000000 ++#endif ++ ++#define _COMPONENT ACPI_HOTKEY_COMPONENT ++ ++MODULE_AUTHOR("Hiroshi Miura, David Bronaugh and Harald Welte"); ++MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops"); ++MODULE_LICENSE("GPL"); ++ ++#define LOGPREFIX "pcc_acpi: " ++ ++/* Define ACPI PATHs */ ++/* Lets note hotkeys */ ++#define METHOD_HKEY_QUERY "HINF" ++#define METHOD_HKEY_SQTY "SQTY" ++#define METHOD_HKEY_SINF "SINF" ++#define METHOD_HKEY_SSET "SSET" ++#define HKEY_NOTIFY 0x80 ++ ++#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support" ++#define ACPI_PCC_DEVICE_NAME "Hotkey" ++#define ACPI_PCC_CLASS "pcc" ++ ++#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0" ++ ++/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent ++ ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00 ++*/ ++enum SINF_BITS { SINF_NUM_BATTERIES = 0, ++ SINF_LCD_TYPE, ++ SINF_AC_MAX_BRIGHT, ++ SINF_AC_MIN_BRIGHT, ++ SINF_AC_CUR_BRIGHT, ++ SINF_DC_MAX_BRIGHT, ++ SINF_DC_MIN_BRIGHT, ++ SINF_DC_CUR_BRIGHT, ++ SINF_MUTE, ++ SINF_RESERVED, ++ SINF_ENV_STATE, ++ SINF_STICKY_KEY = 0x80, ++ }; ++/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */ ++ ++static int acpi_pcc_hotkey_add(struct acpi_device *device); ++static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type); ++static int acpi_pcc_hotkey_resume(struct acpi_device *device); ++ ++static const struct acpi_device_id pcc_device_ids[] = { ++ { "MAT0012", 0}, ++ { "MAT0013", 0}, ++ { "MAT0018", 0}, ++ { "MAT0019", 0}, ++ { "", 0}, ++}; ++ ++static struct acpi_driver acpi_pcc_driver = { ++ .name = ACPI_PCC_DRIVER_NAME, ++ .class = ACPI_PCC_CLASS, ++ .ids = pcc_device_ids, ++ .ops = { ++ .add = acpi_pcc_hotkey_add, ++ .remove = acpi_pcc_hotkey_remove, ++ .resume = acpi_pcc_hotkey_resume, ++ }, ++}; ++ ++#define KEYMAP_SIZE 11 ++static const int initial_keymap[KEYMAP_SIZE] = { ++ /* 0 */ KEY_RESERVED, ++ /* 1 */ KEY_BRIGHTNESSDOWN, ++ /* 2 */ KEY_BRIGHTNESSUP, ++ /* 3 */ KEY_DISPLAYTOGGLE, ++ /* 4 */ KEY_MUTE, ++ /* 5 */ KEY_VOLUMEDOWN, ++ /* 6 */ KEY_VOLUMEUP, ++ /* 7 */ KEY_SLEEP, ++ /* 8 */ KEY_PROG1, /* Change CPU boost */ ++ /* 9 */ KEY_BATTERY, ++ /* 10 */ KEY_SUSPEND, ++}; ++ ++struct pcc_acpi { ++ acpi_handle handle; ++ unsigned long num_sifr; ++ int sticky_mode; ++ u32 *sinf; ++ struct acpi_device *device; ++ struct input_dev *input_dev; ++ struct backlight_device *backlight; ++ int keymap[KEYMAP_SIZE]; ++}; ++ ++struct pcc_keyinput { ++ struct acpi_hotkey *hotkey; ++}; ++ ++/* method access functions */ ++static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) ++{ ++ union acpi_object in_objs[] = { ++ { .integer.type = ACPI_TYPE_INTEGER, ++ .integer.value = func, }, ++ { .integer.type = ACPI_TYPE_INTEGER, ++ .integer.value = val, }, ++ }; ++ struct acpi_object_list params = { ++ .count = ARRAY_SIZE(in_objs), ++ .pointer = in_objs, ++ }; ++ acpi_status status = AE_OK; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_write_sset"); ++ ++ status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET, ++ ¶ms, NULL); ++ ++ return status == AE_OK; ++} ++ ++static inline int acpi_pcc_get_sqty(struct acpi_device *device) ++{ ++ unsigned long long s; ++ acpi_status status; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty"); ++ ++ status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY, ++ NULL, &s); ++ if (ACPI_SUCCESS(status)) ++ return s; ++ else { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "evaluation error HKEY.SQTY\n")); ++ return -EINVAL; ++ } ++} ++ ++static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf) ++{ ++ acpi_status status; ++ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; ++ union acpi_object *hkey = NULL; ++ int i; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata"); ++ ++ status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, 0, ++ &buffer); ++ if (ACPI_FAILURE(status)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "evaluation error HKEY.SINF\n")); ++ return 0; ++ } ++ ++ hkey = buffer.pointer; ++ if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n")); ++ goto end; ++ } ++ ++ if (pcc->num_sifr < hkey->package.count) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "SQTY reports bad SINF length\n")); ++ status = AE_ERROR; ++ goto end; ++ } ++ ++ for (i = 0; i < hkey->package.count; i++) { ++ union acpi_object *element = &(hkey->package.elements[i]); ++ if (likely(element->type == ACPI_TYPE_INTEGER)) { ++ sinf[i] = element->integer.value; ++ } else ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Invalid HKEY.SINF data\n")); ++ } ++ sinf[hkey->package.count] = -1; ++ ++end: ++ kfree(buffer.pointer); ++ return status == AE_OK; ++} ++ ++/* backlight API interface functions */ ++ ++/* This driver currently treats AC and DC brightness identical, ++ * since we don't need to invent an interface to the core ACPI ++ * logic to receive events in case a power supply is plugged in ++ * or removed */ ++ ++static int bl_get(struct backlight_device *bd) ++{ ++ struct pcc_acpi *pcc = bl_get_data(bd); ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) ++ return -EIO; ++ ++ return pcc->sinf[SINF_AC_CUR_BRIGHT]; ++} ++ ++static int bl_set_status(struct backlight_device *bd) ++{ ++ struct pcc_acpi *pcc = bl_get_data(bd); ++ int bright = bd->props.brightness; ++ int rc; ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) ++ return -EIO; ++ ++ if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT]) ++ bright = pcc->sinf[SINF_AC_MIN_BRIGHT]; ++ ++ if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT]) ++ bright = pcc->sinf[SINF_DC_MIN_BRIGHT]; ++ ++ if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] || ++ bright > pcc->sinf[SINF_AC_MAX_BRIGHT]) ++ return -EINVAL; ++ ++ rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright); ++ if (rc < 0) ++ return rc; ++ ++ return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright); ++} ++ ++static struct backlight_ops pcc_backlight_ops = { ++ .get_brightness = bl_get, ++ .update_status = bl_set_status, ++}; ++ ++ ++/* sysfs user interface functions */ ++ ++static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct acpi_device *acpi = to_acpi_device(dev); ++ struct pcc_acpi *pcc = acpi_driver_data(acpi); ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) ++ return -EIO; ++ ++ return sprintf(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]); ++} ++ ++static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct acpi_device *acpi = to_acpi_device(dev); ++ struct pcc_acpi *pcc = acpi_driver_data(acpi); ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) ++ return -EIO; ++ ++ return sprintf(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]); ++} ++ ++static ssize_t show_mute(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct acpi_device *acpi = to_acpi_device(dev); ++ struct pcc_acpi *pcc = acpi_driver_data(acpi); ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) ++ return -EIO; ++ ++ return sprintf(buf, "%u\n", pcc->sinf[SINF_MUTE]); ++} ++ ++static ssize_t show_sticky(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct acpi_device *acpi = to_acpi_device(dev); ++ struct pcc_acpi *pcc = acpi_driver_data(acpi); ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) ++ return -EIO; ++ ++ return sprintf(buf, "%u\n", pcc->sinf[SINF_STICKY_KEY]); ++} ++ ++static ssize_t set_sticky(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct acpi_device *acpi = to_acpi_device(dev); ++ struct pcc_acpi *pcc = acpi_driver_data(acpi); ++ int val; ++ ++ if (count && sscanf(buf, "%i", &val) == 1 && ++ (val == 0 || val == 1)) { ++ acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val); ++ pcc->sticky_mode = val; ++ } ++ ++ return count; ++} ++ ++static DEVICE_ATTR(numbatt, S_IRUGO, show_numbatt, NULL); ++static DEVICE_ATTR(lcdtype, S_IRUGO, show_lcdtype, NULL); ++static DEVICE_ATTR(mute, S_IRUGO, show_mute, NULL); ++static DEVICE_ATTR(sticky_key, S_IRUGO | S_IWUSR, show_sticky, set_sticky); ++ ++static struct attribute *pcc_sysfs_entries[] = { ++ &dev_attr_numbatt.attr, ++ &dev_attr_lcdtype.attr, ++ &dev_attr_mute.attr, ++ &dev_attr_sticky_key.attr, ++ NULL, ++}; ++ ++static struct attribute_group pcc_attr_group = { ++ .name = NULL, /* put in device directory */ ++ .attrs = pcc_sysfs_entries, ++}; ++ ++ ++/* hotkey input device driver */ ++ ++static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode) ++{ ++ struct pcc_acpi *pcc = input_get_drvdata(dev); ++ ++ if (scancode >= ARRAY_SIZE(pcc->keymap)) ++ return -EINVAL; ++ ++ *keycode = pcc->keymap[scancode]; ++ ++ return 0; ++} ++ ++static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) { ++ if (pcc->keymap[i] == keycode) ++ return i+1; ++ } ++ ++ return 0; ++} ++ ++static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode) ++{ ++ struct pcc_acpi *pcc = input_get_drvdata(dev); ++ int oldkeycode; ++ ++ if (scancode >= ARRAY_SIZE(pcc->keymap)) ++ return -EINVAL; ++ ++ if (keycode < 0 || keycode > KEY_MAX) ++ return -EINVAL; ++ ++ oldkeycode = pcc->keymap[scancode]; ++ pcc->keymap[scancode] = keycode; ++ ++ set_bit(keycode, dev->keybit); ++ ++ if (!keymap_get_by_keycode(pcc, oldkeycode)) ++ clear_bit(oldkeycode, dev->keybit); ++ ++ return 0; ++} ++ ++static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) ++{ ++ struct input_dev *hotk_input_dev = pcc->input_dev; ++ int rc; ++ int key_code, hkey_num; ++ unsigned long long result; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput"); ++ ++ rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, ++ NULL, &result); ++ if (!ACPI_SUCCESS(rc)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "error getting hotkey status\n")); ++ return; ++ } ++ ++ acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); ++ ++ hkey_num = result & 0xf; ++ ++ if (hkey_num < 0 || hkey_num > ARRAY_SIZE(pcc->keymap)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "hotkey number out of range: %d\n", ++ hkey_num)); ++ return; ++ } ++ ++ key_code = pcc->keymap[hkey_num]; ++ ++ if (key_code != KEY_RESERVED) { ++ int pushed = (result & 0x80) ? TRUE : FALSE; ++ ++ input_report_key(hotk_input_dev, key_code, pushed); ++ input_sync(hotk_input_dev); ++ } ++ ++ return; ++} ++ ++static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data) ++{ ++ struct pcc_acpi *pcc = (struct pcc_acpi *) data; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify"); ++ ++ switch (event) { ++ case HKEY_NOTIFY: ++ acpi_pcc_generate_keyinput(pcc); ++ break; ++ default: ++ /* nothing to do */ ++ break; ++ } ++} ++ ++static int acpi_pcc_init_input(struct pcc_acpi *pcc) ++{ ++ int i, rc; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_init_input"); ++ ++ pcc->input_dev = input_allocate_device(); ++ if (!pcc->input_dev) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Couldn't allocate input device for hotkey")); ++ return -ENOMEM; ++ } ++ ++ pcc->input_dev->evbit[0] = BIT(EV_KEY); ++ ++ pcc->input_dev->name = ACPI_PCC_DRIVER_NAME; ++ pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS; ++ pcc->input_dev->id.bustype = BUS_HOST; ++ pcc->input_dev->id.vendor = 0x0001; ++ pcc->input_dev->id.product = 0x0001; ++ pcc->input_dev->id.version = 0x0100; ++ pcc->input_dev->getkeycode = pcc_getkeycode; ++ pcc->input_dev->setkeycode = pcc_setkeycode; ++ ++ /* load initial keymap */ ++ memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap)); ++ ++ for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) ++ __set_bit(pcc->keymap[i], pcc->input_dev->keybit); ++ __clear_bit(KEY_RESERVED, pcc->input_dev->keybit); ++ ++ input_set_drvdata(pcc->input_dev, pcc); ++ ++ rc = input_register_device(pcc->input_dev); ++ if (rc < 0) ++ input_free_device(pcc->input_dev); ++ ++ return rc; ++} ++ ++/* kernel module interface */ ++ ++static int acpi_pcc_hotkey_resume(struct acpi_device *device) ++{ ++ struct pcc_acpi *pcc = acpi_driver_data(device); ++ acpi_status status = AE_OK; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume"); ++ ++ if (device == NULL || pcc == NULL) ++ return -EINVAL; ++ ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n", ++ pcc->sticky_mode)); ++ ++ status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode); ++ ++ return status == AE_OK ? 0 : -EINVAL; ++} ++ ++static int acpi_pcc_hotkey_add(struct acpi_device *device) ++{ ++ acpi_status status; ++ struct pcc_acpi *pcc; ++ int num_sifr, result; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add"); ++ ++ if (!device) ++ return -EINVAL; ++ ++ num_sifr = acpi_pcc_get_sqty(device); ++ ++ if (num_sifr > 255) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large")); ++ return -ENODEV; ++ } ++ ++ pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL); ++ if (!pcc) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Couldn't allocate mem for pcc")); ++ return -ENOMEM; ++ } ++ ++ pcc->sinf = kzalloc(sizeof(u32) * (num_sifr + 1), GFP_KERNEL); ++ if (!pcc->sinf) { ++ result = -ENOMEM; ++ goto out_hotkey; ++ } ++ ++ pcc->device = device; ++ pcc->handle = device->handle; ++ pcc->num_sifr = num_sifr; ++ acpi_driver_data(device) = pcc; ++ strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME); ++ strcpy(acpi_device_class(device), ACPI_PCC_CLASS); ++ ++ result = acpi_pcc_init_input(pcc); ++ if (result) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Error installing keyinput handler\n")); ++ goto out_sinf; ++ } ++ ++ /* initialize hotkey input device */ ++ status = acpi_install_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY, ++ acpi_pcc_hotkey_notify, pcc); ++ ++ if (ACPI_FAILURE(status)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Error installing notify handler\n")); ++ result = -ENODEV; ++ goto out_input; ++ } ++ ++ /* initialize backlight */ ++ pcc->backlight = backlight_device_register("panasonic", NULL, pcc, ++ &pcc_backlight_ops); ++ if (IS_ERR(pcc->backlight)) ++ goto out_notify; ++ ++ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Couldn't retrieve BIOS data\n")); ++ goto out_backlight; ++ } ++ ++ /* read the initial brightness setting from the hardware */ ++ pcc->backlight->props.max_brightness = ++ pcc->sinf[SINF_AC_MAX_BRIGHT]; ++ pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; ++ ++ /* read the initial sticky key mode from the hardware */ ++ pcc->sticky_mode = pcc->sinf[SINF_STICKY_KEY]; ++ ++ /* add sysfs attributes */ ++ result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group); ++ if (result) ++ goto out_backlight; ++ ++ return 0; ++ ++out_backlight: ++ backlight_device_unregister(pcc->backlight); ++out_notify: ++ acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY, ++ acpi_pcc_hotkey_notify); ++out_input: ++ input_unregister_device(pcc->input_dev); ++ /* no need to input_free_device() since core input API refcount and ++ * free()s the device */ ++out_sinf: ++ kfree(pcc->sinf); ++out_hotkey: ++ kfree(pcc); ++ ++ return result; ++} ++ ++static int __init acpi_pcc_init(void) ++{ ++ int result = 0; ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_init"); ++ ++ if (acpi_disabled) ++ return -ENODEV; ++ ++ result = acpi_bus_register_driver(&acpi_pcc_driver); ++ if (result < 0) { ++ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ++ "Error registering hotkey driver\n")); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) ++{ ++ struct pcc_acpi *pcc = acpi_driver_data(device); ++ ++ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove"); ++ ++ if (!device || !pcc) ++ return -EINVAL; ++ ++ sysfs_remove_group(&device->dev.kobj, &pcc_attr_group); ++ ++ backlight_device_unregister(pcc->backlight); ++ ++ acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY, ++ acpi_pcc_hotkey_notify); ++ ++ input_unregister_device(pcc->input_dev); ++ /* no need to input_free_device() since core input API refcount and ++ * free()s the device */ ++ ++ kfree(pcc->sinf); ++ kfree(pcc); ++ ++ return 0; ++} ++ ++static void __exit acpi_pcc_exit(void) ++{ ++ ACPI_FUNCTION_TRACE("acpi_pcc_exit"); ++ ++ acpi_bus_unregister_driver(&acpi_pcc_driver); ++} ++ ++module_init(acpi_pcc_init); ++module_exit(acpi_pcc_exit); +Index: linux-2.6.27-sles11/MAINTAINERS +=================================================================== +--- linux-2.6.27-sles11.orig/MAINTAINERS ++++ linux-2.6.27-sles11/MAINTAINERS +@@ -3147,6 +3147,11 @@ M: olof@lixom.net + L: linux-i2c@vger.kernel.org + S: Maintained + ++PANASONIC LAPTOP ACPI EXTRAS DRIVER ++P: Harald Welte ++M: laforge@gnumonks.org ++S: Maintained ++ + PARALLEL PORT SUPPORT + L: linux-parport@lists.infradead.org (subscribers-only) + S: Orphan diff --git a/src/patches/suse-2.6.27.31/patches.drivers/power-introduce-system_entering_hibernation b/src/patches/suse-2.6.27.31/patches.drivers/power-introduce-system_entering_hibernation new file mode 100644 index 000000000..ee067b4cd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/power-introduce-system_entering_hibernation @@ -0,0 +1,81 @@ +From f45eb74cf9936d37dd91d28ccca865daa603eaae Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Mon, 3 Nov 2008 19:01:02 +0900 +Subject: [PATCH] Hibernation: Introduce system_entering_hibernation +References: bnc#441721 + +Introduce boolean function system_entering_hibernation() returning +'true' during the last phase of hibernation, in which devices are +being put into low power states and the sleep state (for example, +ACPI S4) is finally entered. + +Some device drivers need such a function to check if the system is +in the final phase of hibernation. In particular, some SATA drivers +are going to use it for blacklisting systems in which the disks +should not be spun down during the last phase of hibernation (the +BIOS will do that anyway). + +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Tejun Heo +Signed-off-by: Jeff Garzik +Signed-off-by: Tejun Heo +--- + include/linux/suspend.h | 2 ++ + kernel/power/disk.c | 10 ++++++++++ + 2 files changed, 12 insertions(+) + +Index: linux-2.6.27/include/linux/suspend.h +=================================================================== +--- linux-2.6.27.orig/include/linux/suspend.h ++++ linux-2.6.27/include/linux/suspend.h +@@ -232,6 +232,7 @@ extern unsigned long get_safe_page(gfp_t + + extern void hibernation_set_ops(struct platform_hibernation_ops *ops); + extern int hibernate(void); ++extern bool system_entering_hibernation(void); + #else /* CONFIG_HIBERNATION */ + static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } + static inline void swsusp_set_page_free(struct page *p) {} +@@ -239,6 +240,7 @@ static inline void swsusp_unset_page_fre + + static inline void hibernation_set_ops(struct platform_hibernation_ops *ops) {} + static inline int hibernate(void) { return -ENOSYS; } ++static inline bool system_entering_hibernation(void) { return false; } + #endif /* CONFIG_HIBERNATION */ + + #ifdef CONFIG_PM_SLEEP +Index: linux-2.6.27/kernel/power/disk.c +=================================================================== +--- linux-2.6.27.orig/kernel/power/disk.c ++++ linux-2.6.27/kernel/power/disk.c +@@ -71,6 +71,14 @@ void hibernation_set_ops(struct platform + mutex_unlock(&pm_mutex); + } + ++static bool entering_platform_hibernation; ++ ++bool system_entering_hibernation(void) ++{ ++ return entering_platform_hibernation; ++} ++EXPORT_SYMBOL_GPL(system_entering_hibernation); ++ + #ifdef CONFIG_PM_DEBUG + static void hibernation_debug_sleep(void) + { +@@ -415,6 +423,7 @@ int hibernation_platform_enter(void) + if (error) + goto Close; + ++ entering_platform_hibernation = true; + suspend_console(); + ftrace_save = __ftrace_enabled_save(); + error = device_suspend(PMSG_HIBERNATE); +@@ -450,6 +459,7 @@ int hibernation_platform_enter(void) + Finish: + hibernation_ops->finish(); + Resume_devices: ++ entering_platform_hibernation = false; + device_resume(PMSG_RESTORE); + __ftrace_enabled_restore(ftrace_save); + resume_console(); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/ppc64-adb b/src/patches/suse-2.6.27.31/patches.drivers/ppc64-adb new file mode 100644 index 000000000..fe87d3127 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/ppc64-adb @@ -0,0 +1,53 @@ +From: Olaf Hering +Subject: enable mouse button emulation also for G5 +Patch-mainline: never + +fix compile errors + + drivers/macintosh/Kconfig | 2 +- + drivers/macintosh/adb.c | 4 ++++ + drivers/macintosh/adbhid.c | 6 +++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/macintosh/Kconfig ++++ b/drivers/macintosh/Kconfig +@@ -13,7 +13,7 @@ if MACINTOSH_DRIVERS + + config ADB + bool "Apple Desktop Bus (ADB) support" +- depends on MAC || (PPC_PMAC && PPC32) ++ depends on MAC || PPC_PMAC + help + Apple Desktop Bus (ADB) support is for support of devices which + are connected to an ADB port. ADB devices tend to have 4 pins. +--- a/drivers/macintosh/adb.c ++++ b/drivers/macintosh/adb.c +@@ -298,6 +298,10 @@ static int __init adb_init(void) + if (!machine_is(chrp) && !machine_is(powermac)) + return 0; + #endif ++#ifdef CONFIG_PPC64 ++ if (!machine_is(powermac)) ++ return 0; ++#endif + #ifdef CONFIG_MAC + if (!MACH_IS_MAC) + return 0; +--- a/drivers/macintosh/adbhid.c ++++ b/drivers/macintosh/adbhid.c +@@ -1264,10 +1264,14 @@ init_ms_a3(int id) + + static int __init adbhid_init(void) + { +-#ifndef CONFIG_MAC ++#ifdef CONFIG_PPC32 + if (!machine_is(chrp) && !machine_is(powermac)) + return 0; + #endif ++#ifdef CONFIG_PPC64 ++ if (!machine_is(powermac)) ++ return 0; ++#endif + + led_request.complete = 1; + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla1280-eh-update b/src/patches/suse-2.6.27.31/patches.drivers/qla1280-eh-update new file mode 100644 index 000000000..650e97fc3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla1280-eh-update @@ -0,0 +1,658 @@ +From: Mike Reed +Subject: panic in qla_1280_done following adapter reset +References: bnc#493991 + +Customer has had repeated crashes after a scsi adapter reset. This looks like +the same issue as bug 232908. Unfortunately, the customer's solution to this +was to replace the Qlogic card with an LSI card (just like the customer did in +bug 232908). + +Mike Reed has submitted a patch upstream to fix this problem. We would like to +see this patch in a SLES10 SP2 update (and SLES11 update) so that other +customers with this Qlogic card won't hit it. + +Signed-off-by: Hannes Reinecke + +--- linux-2.6.27.19-5/drivers/scsi/qla1280.h 2008-10-09 17:13:53.000000000 -0500 ++++ linux-2.6.27.19-5-modified/drivers/scsi/qla1280.h 2009-03-30 13:19:03.447145988 -0500 +@@ -88,7 +88,8 @@ + + /* Maximum outstanding commands in ISP queues */ + #define MAX_OUTSTANDING_COMMANDS 512 +-#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS + 2) ++#define COMPLETED_HANDLE ((unsigned char *) \ ++ (MAX_OUTSTANDING_COMMANDS + 2)) + + /* ISP request and response entry counts (37-65535) */ + #define REQUEST_ENTRY_CNT 255 /* Number of request entries. */ +--- linux-2.6.27.19-5/drivers/scsi/qla1280.c 2009-02-28 01:19:41.000000000 -0600 ++++ linux-2.6.27.19-5-modified/drivers/scsi/qla1280.c 2009-04-17 12:46:11.810488760 -0500 +@@ -17,9 +17,12 @@ + * General Public License for more details. + * + ******************************************************************************/ +-#define QLA1280_VERSION "3.26" ++#define QLA1280_VERSION "3.27" + /***************************************************************************** + Revision History: ++ Rev 3.27, February 10, 2009, Michael Reed ++ - General code cleanup. ++ - Improve error recovery. + Rev 3.26, January 16, 2006 Jes Sorensen + - Ditch all < 2.6 support + Rev 3.25.1, February 10, 2005 Christoph Hellwig +@@ -438,7 +441,6 @@ static int qla1280_mailbox_command(struc + uint8_t, uint16_t *); + static int qla1280_bus_reset(struct scsi_qla_host *, int); + static int qla1280_device_reset(struct scsi_qla_host *, int, int); +-static int qla1280_abort_device(struct scsi_qla_host *, int, int, int); + static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int); + static int qla1280_abort_isp(struct scsi_qla_host *); + #ifdef QLA_64BIT_PTR +@@ -710,7 +712,7 @@ qla1280_info(struct Scsi_Host *host) + } + + /************************************************************************** +- * qla1200_queuecommand ++ * qla1280_queuecommand + * Queue a command to the controller. + * + * Note: +@@ -725,12 +727,14 @@ qla1280_queuecommand(struct scsi_cmnd *c + { + struct Scsi_Host *host = cmd->device->host; + struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; +- struct srb *sp = (struct srb *)&cmd->SCp; ++ struct srb *sp = (struct srb *)CMD_SP(cmd); + int status; + + cmd->scsi_done = fn; + sp->cmd = cmd; + sp->flags = 0; ++ sp->wait = NULL; ++ CMD_HANDLE(cmd) = (unsigned char *)NULL; + + qla1280_print_scsi_cmd(5, cmd); + +@@ -750,21 +754,11 @@ qla1280_queuecommand(struct scsi_cmnd *c + + enum action { + ABORT_COMMAND, +- ABORT_DEVICE, + DEVICE_RESET, + BUS_RESET, + ADAPTER_RESET, +- FAIL + }; + +-/* timer action for error action processor */ +-static void qla1280_error_wait_timeout(unsigned long __data) +-{ +- struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data; +- struct srb *sp = (struct srb *)CMD_SP(cmd); +- +- complete(sp->wait); +-} + + static void qla1280_mailbox_timeout(unsigned long __data) + { +@@ -779,8 +773,67 @@ static void qla1280_mailbox_timeout(unsi + complete(ha->mailbox_wait); + } + ++static int ++_qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp, ++ struct completion *wait) ++{ ++ int status = FAILED; ++ struct scsi_cmnd *cmd = sp->cmd; ++ ++ spin_unlock_irq(ha->host->host_lock); ++ wait_for_completion_timeout(wait, 4*HZ); ++ spin_lock_irq(ha->host->host_lock); ++ sp->wait = NULL; ++ if(CMD_HANDLE(cmd) == COMPLETED_HANDLE) { ++ status = SUCCESS; ++ (*cmd->scsi_done)(cmd); ++ } ++ return status; ++} ++ ++static int ++qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp) ++{ ++ DECLARE_COMPLETION_ONSTACK(wait); ++ ++ sp->wait = &wait; ++ return _qla1280_wait_for_single_command(ha, sp, &wait); ++} ++ ++static int ++qla1280_wait_for_pending_commands(struct scsi_qla_host *ha, int bus, int target) ++{ ++ int cnt; ++ int status; ++ struct srb *sp; ++ struct scsi_cmnd *cmd; ++ ++ status = SUCCESS; ++ ++ /* ++ * Wait for all commands with the designated bus/target ++ * to be completed by the firmware ++ */ ++ for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { ++ sp = ha->outstanding_cmds[cnt]; ++ if (sp) { ++ cmd = sp->cmd; ++ ++ if (bus >= 0 && SCSI_BUS_32(cmd) != bus) ++ continue; ++ if (target >= 0 && SCSI_TCN_32(cmd) != target) ++ continue; ++ ++ status = qla1280_wait_for_single_command(ha, sp); ++ if (status == FAILED) ++ break; ++ } ++ } ++ return status; ++} ++ + /************************************************************************** +- * qla1200_error_action ++ * qla1280_error_action + * The function will attempt to perform a specified error action and + * wait for the results (or time out). + * +@@ -792,11 +845,6 @@ static void qla1280_mailbox_timeout(unsi + * Returns: + * SUCCESS or FAILED + * +- * Note: +- * Resetting the bus always succeeds - is has to, otherwise the +- * kernel will panic! Try a surgical technique - sending a BUS +- * DEVICE RESET message - on the offending target before pulling +- * the SCSI bus reset line. + **************************************************************************/ + static int + qla1280_error_action(struct scsi_cmnd *cmd, enum action action) +@@ -804,13 +852,19 @@ qla1280_error_action(struct scsi_cmnd *c + struct scsi_qla_host *ha; + int bus, target, lun; + struct srb *sp; +- uint16_t data; +- unsigned char *handle; +- int result, i; ++ int i, found; ++ int result=FAILED; ++ int wait_for_bus=-1; ++ int wait_for_target = -1; + DECLARE_COMPLETION_ONSTACK(wait); +- struct timer_list timer; ++ ++ ENTER("qla1280_error_action"); + + ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata); ++ sp = (struct srb *)CMD_SP(cmd); ++ bus = SCSI_BUS_32(cmd); ++ target = SCSI_TCN_32(cmd); ++ lun = SCSI_LUN_32(cmd); + + dprintk(4, "error_action %i, istatus 0x%04x\n", action, + RD_REG_WORD(&ha->iobase->istatus)); +@@ -819,99 +873,47 @@ qla1280_error_action(struct scsi_cmnd *c + RD_REG_WORD(&ha->iobase->host_cmd), + RD_REG_WORD(&ha->iobase->ictrl), jiffies); + +- ENTER("qla1280_error_action"); + if (qla1280_verbose) + printk(KERN_INFO "scsi(%li): Resetting Cmnd=0x%p, " + "Handle=0x%p, action=0x%x\n", + ha->host_no, cmd, CMD_HANDLE(cmd), action); + +- if (cmd == NULL) { +- printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL " +- "si_Cmnd pointer, failing.\n"); +- LEAVE("qla1280_error_action"); +- return FAILED; +- } +- +- ha = (struct scsi_qla_host *)cmd->device->host->hostdata; +- sp = (struct srb *)CMD_SP(cmd); +- handle = CMD_HANDLE(cmd); +- +- /* Check for pending interrupts. */ +- data = qla1280_debounce_register(&ha->iobase->istatus); +- /* +- * The io_request_lock is held when the reset handler is called, hence +- * the interrupt handler cannot be running in parallel as it also +- * grabs the lock. /Jes +- */ +- if (data & RISC_INT) +- qla1280_isr(ha, &ha->done_q); +- + /* +- * Determine the suggested action that the mid-level driver wants +- * us to perform. ++ * Check to see if we have the command in the outstanding_cmds[] ++ * array. If not then it must have completed before this error ++ * action was initiated. If the error_action isn't ABORT_COMMAND ++ * then the driver must proceed with the requested action. + */ +- if (handle == (unsigned char *)INVALID_HANDLE || handle == NULL) { +- if(action == ABORT_COMMAND) { +- /* we never got this command */ +- printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); +- return SUCCESS; /* no action - we don't have command */ ++ found = -1; ++ for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { ++ if (sp == ha->outstanding_cmds[i]) { ++ found = i; ++ sp->wait = &wait; /* we'll wait for it to complete */ ++ break; + } +- } else { +- sp->wait = &wait; + } + +- bus = SCSI_BUS_32(cmd); +- target = SCSI_TCN_32(cmd); +- lun = SCSI_LUN_32(cmd); ++ if (found < 0) { /* driver doesn't have command */ ++ result = SUCCESS; ++ if (qla1280_verbose) { ++ printk(KERN_INFO ++ "scsi(%ld:%d:%d:%d): specified command has " ++ "already completed.\n", ha->host_no, bus, ++ target, lun); ++ } ++ } + +- /* Overloading result. Here it means the success or fail of the +- * *issue* of the action. When we return from the routine, it must +- * mean the actual success or fail of the action */ +- result = FAILED; + switch (action) { +- case FAIL: +- break; + + case ABORT_COMMAND: +- if ((sp->flags & SRB_ABORT_PENDING)) { +- printk(KERN_WARNING +- "scsi(): Command has a pending abort " +- "message - ABORT_PENDING.\n"); +- /* This should technically be impossible since we +- * now wait for abort completion */ +- break; +- } +- +- for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { +- if (sp == ha->outstanding_cmds[i]) { +- dprintk(1, "qla1280: RISC aborting command\n"); +- if (qla1280_abort_command(ha, sp, i) == 0) +- result = SUCCESS; +- else { +- /* +- * Since we don't know what might +- * have happend to the command, it +- * is unsafe to remove it from the +- * device's queue at this point. +- * Wait and let the escalation +- * process take care of it. +- */ +- printk(KERN_WARNING +- "scsi(%li:%i:%i:%i): Unable" +- " to abort command!\n", +- ha->host_no, bus, target, lun); +- } +- } +- } +- break; +- +- case ABORT_DEVICE: +- if (qla1280_verbose) +- printk(KERN_INFO +- "scsi(%ld:%d:%d:%d): Queueing abort device " +- "command.\n", ha->host_no, bus, target, lun); +- if (qla1280_abort_device(ha, bus, target, lun) == 0) +- result = SUCCESS; ++ dprintk(1, "qla1280: RISC aborting command\n"); ++ /* ++ * The abort might fail due to race when the host_lock ++ * is released to issue the abort. As such, we ++ * don't bother to check the return status. ++ */ ++ if (found >= 0) ++ qla1280_abort_command(ha, sp, found); + break; + + case DEVICE_RESET: +@@ -919,16 +921,21 @@ qla1280_error_action(struct scsi_cmnd *c + printk(KERN_INFO + "scsi(%ld:%d:%d:%d): Queueing device reset " + "command.\n", ha->host_no, bus, target, lun); +- if (qla1280_device_reset(ha, bus, target) == 0) +- result = SUCCESS; ++ if (qla1280_device_reset(ha, bus, target) == 0) { ++ /* issued device reset, set wait conditions */ ++ wait_for_bus = bus; ++ wait_for_target = target; ++ } + break; + + case BUS_RESET: + if (qla1280_verbose) + printk(KERN_INFO "qla1280(%ld:%d): Issued bus " + "reset.\n", ha->host_no, bus); +- if (qla1280_bus_reset(ha, bus) == 0) +- result = SUCCESS; ++ if (qla1280_bus_reset(ha, bus) == 0) { ++ /* issued bus reset, set wait conditions */ ++ wait_for_bus = bus; ++ } + break; + + case ADAPTER_RESET: +@@ -941,55 +948,48 @@ qla1280_error_action(struct scsi_cmnd *c + "continue automatically\n", ha->host_no); + } + ha->flags.reset_active = 1; +- /* +- * We restarted all of the commands automatically, so the +- * mid-level code can expect completions momentitarily. +- */ +- if (qla1280_abort_isp(ha) == 0) +- result = SUCCESS; ++ ++ if (qla1280_abort_isp(ha) != 0) { /* it's dead */ ++ result = FAILED; ++ } + + ha->flags.reset_active = 0; + } + +- if (!list_empty(&ha->done_q)) +- qla1280_done(ha); ++ /* ++ * At this point, the host_lock has been released and retaken ++ * by the issuance of the mailbox command. ++ * Wait for the command passed in by the mid-layer if it ++ * was found by the driver. It might have been returned ++ * between eh recovery steps, hence the check of the "found" ++ * variable. ++ */ + +- /* If we didn't manage to issue the action, or we have no +- * command to wait for, exit here */ +- if (result == FAILED || handle == NULL || +- handle == (unsigned char *)INVALID_HANDLE) { +- /* +- * Clear completion queue to avoid qla1280_done() trying +- * to complete the command at a later stage after we +- * have exited the current context +- */ +- sp->wait = NULL; +- goto leave; +- } ++ if (found >= 0) ++ result = _qla1280_wait_for_single_command(ha, sp, &wait); + +- /* set up a timer just in case we're really jammed */ +- init_timer(&timer); +- timer.expires = jiffies + 4*HZ; +- timer.data = (unsigned long)cmd; +- timer.function = qla1280_error_wait_timeout; +- add_timer(&timer); +- +- /* wait for the action to complete (or the timer to expire) */ +- spin_unlock_irq(ha->host->host_lock); +- wait_for_completion(&wait); +- del_timer_sync(&timer); +- spin_lock_irq(ha->host->host_lock); +- sp->wait = NULL; ++ if (action == ABORT_COMMAND && result != SUCCESS) { ++ printk(KERN_WARNING ++ "scsi(%li:%i:%i:%i): " ++ "Unable to abort command!\n", ++ ha->host_no, bus, target, lun); ++ } + +- /* the only action we might get a fail for is abort */ +- if (action == ABORT_COMMAND) { +- if(sp->flags & SRB_ABORTED) +- result = SUCCESS; +- else +- result = FAILED; ++ /* ++ * If the command passed in by the mid-layer has been ++ * returned by the board, then wait for any additional ++ * commands which are supposed to complete based upon ++ * the error action. ++ * ++ * All commands are unconditionally returned during a ++ * call to qla1280_abort_isp(), ADAPTER_RESET. No need ++ * to wait for them. ++ */ ++ if (result == SUCCESS && wait_for_bus >= 0) { ++ result = qla1280_wait_for_pending_commands(ha, ++ wait_for_bus, wait_for_target); + } + +- leave: + dprintk(1, "RESET returning %d\n", result); + + LEAVE("qla1280_error_action"); +@@ -1292,13 +1292,12 @@ qla1280_done(struct scsi_qla_host *ha) + switch ((CMD_RESULT(cmd) >> 16)) { + case DID_RESET: + /* Issue marker command. */ +- qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); ++ if (!ha->flags.abort_isp_active) ++ qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); + break; + case DID_ABORT: + sp->flags &= ~SRB_ABORT_PENDING; + sp->flags |= SRB_ABORTED; +- if (sp->flags & SRB_TIMEOUT) +- CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16; + break; + default: + break; +@@ -1308,12 +1307,11 @@ qla1280_done(struct scsi_qla_host *ha) + scsi_dma_unmap(cmd); + + /* Call the mid-level driver interrupt handler */ +- CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE; + ha->actthreads--; + +- (*(cmd)->scsi_done)(cmd); +- +- if(sp->wait != NULL) ++ if (sp->wait == NULL) ++ (*(cmd)->scsi_done)(cmd); ++ else + complete(sp->wait); + } + LEAVE("qla1280_done"); +@@ -2386,9 +2384,6 @@ static int + qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb) + { + struct device_reg __iomem *reg = ha->iobase; +-#if 0 +- LIST_HEAD(done_q); +-#endif + int status = 0; + int cnt; + uint16_t *optr, *iptr; +@@ -2462,19 +2457,9 @@ qla1280_mailbox_command(struct scsi_qla_ + mr = MAILBOX_REGISTER_COUNT; + memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t)); + +-#if 0 +- /* Go check for any response interrupts pending. */ +- qla1280_isr(ha, &done_q); +-#endif +- + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + +-#if 0 +- if (!list_empty(&done_q)) +- qla1280_done(ha, &done_q); +-#endif +- + if (status) + dprintk(2, "qla1280_mailbox_command: **** FAILED, mailbox0 = " + "0x%x ****\n", mb[0]); +@@ -2610,41 +2595,6 @@ qla1280_device_reset(struct scsi_qla_hos + } + + /* +- * qla1280_abort_device +- * Issue an abort message to the device +- * +- * Input: +- * ha = adapter block pointer. +- * bus = SCSI BUS. +- * target = SCSI ID. +- * lun = SCSI LUN. +- * +- * Returns: +- * 0 = success +- */ +-static int +-qla1280_abort_device(struct scsi_qla_host *ha, int bus, int target, int lun) +-{ +- uint16_t mb[MAILBOX_REGISTER_COUNT]; +- int status; +- +- ENTER("qla1280_abort_device"); +- +- mb[0] = MBC_ABORT_DEVICE; +- mb[1] = (bus ? target | BIT_7 : target) << 8 | lun; +- status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); +- +- /* Issue marker command. */ +- qla1280_marker(ha, bus, target, lun, MK_SYNC_ID_LUN); +- +- if (status) +- dprintk(2, "qla1280_abort_device: **** FAILED ****\n"); +- +- LEAVE("qla1280_abort_device"); +- return status; +-} +- +-/* + * qla1280_abort_command + * Abort command aborts a specified IOCB. + * +@@ -2802,7 +2752,7 @@ qla1280_64bit_start_scsi(struct scsi_qla + + /* If room for request in request ring. */ + if ((req_cnt + 2) >= ha->req_q_cnt) { +- status = 1; ++ status = SCSI_MLQUEUE_HOST_BUSY; + dprintk(2, "qla1280_start_scsi: in-ptr=0x%x req_q_cnt=" + "0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, + req_cnt); +@@ -2814,7 +2764,7 @@ qla1280_64bit_start_scsi(struct scsi_qla + ha->outstanding_cmds[cnt] != NULL; cnt++); + + if (cnt >= MAX_OUTSTANDING_COMMANDS) { +- status = 1; ++ status = SCSI_MLQUEUE_HOST_BUSY; + dprintk(2, "qla1280_start_scsi: NO ROOM IN " + "OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt); + goto out; +@@ -3077,7 +3027,7 @@ qla1280_32bit_start_scsi(struct scsi_qla + ha->req_q_cnt, seg_cnt); + /* If room for request in request ring. */ + if ((req_cnt + 2) >= ha->req_q_cnt) { +- status = 1; ++ status = SCSI_MLQUEUE_HOST_BUSY; + dprintk(2, "qla1280_32bit_start_scsi: in-ptr=0x%x, " + "req_q_cnt=0x%x, req_cnt=0x%x", ha->req_ring_index, + ha->req_q_cnt, req_cnt); +@@ -3089,7 +3039,7 @@ qla1280_32bit_start_scsi(struct scsi_qla + (ha->outstanding_cmds[cnt] != 0); cnt++) ; + + if (cnt >= MAX_OUTSTANDING_COMMANDS) { +- status = 1; ++ status = SCSI_MLQUEUE_HOST_BUSY; + dprintk(2, "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING " + "ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt); + goto out; +@@ -3456,6 +3406,7 @@ qla1280_isr(struct scsi_qla_host *ha, st + + /* Save ISP completion status */ + CMD_RESULT(sp->cmd) = 0; ++ CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; + + /* Place block on done queue */ + list_add_tail(&sp->list, done_q); +@@ -3464,7 +3415,7 @@ qla1280_isr(struct scsi_qla_host *ha, st + * If we get here we have a real problem! + */ + printk(KERN_WARNING +- "qla1280: ISP invalid handle"); ++ "qla1280: ISP invalid handle\n"); + } + } + break; +@@ -3722,6 +3673,8 @@ qla1280_status_entry(struct scsi_qla_hos + } + } + ++ CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; ++ + /* Place command on done queue. */ + list_add_tail(&sp->list, done_q); + out: +@@ -3777,6 +3730,8 @@ qla1280_error_entry(struct scsi_qla_host + CMD_RESULT(sp->cmd) = DID_ERROR << 16; + } + ++ CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; ++ + /* Place command on done queue. */ + list_add_tail(&sp->list, done_q); + } +@@ -3827,19 +3782,16 @@ qla1280_abort_isp(struct scsi_qla_host * + struct scsi_cmnd *cmd; + sp = ha->outstanding_cmds[cnt]; + if (sp) { +- + cmd = sp->cmd; + CMD_RESULT(cmd) = DID_RESET << 16; +- +- sp->cmd = NULL; ++ CMD_HANDLE(cmd) = COMPLETED_HANDLE; + ha->outstanding_cmds[cnt] = NULL; +- +- (*cmd->scsi_done)(cmd); +- +- sp->flags = 0; ++ list_add_tail(&sp->list, &ha->done_q); + } + } + ++ qla1280_done(ha); ++ + status = qla1280_load_firmware(ha); + if (status) + goto out; +@@ -3924,13 +3876,6 @@ qla1280_check_for_dead_scsi_bus(struct s + + if (scsi_control == SCSI_PHASE_INVALID) { + ha->bus_settings[bus].scsi_bus_dead = 1; +-#if 0 +- CMD_RESULT(cp) = DID_NO_CONNECT << 16; +- CMD_HANDLE(cp) = INVALID_HANDLE; +- /* ha->actthreads--; */ +- +- (*(cp)->scsi_done)(cp); +-#endif + return 1; /* bus is dead */ + } else { + ha->bus_settings[bus].scsi_bus_dead = 0; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01-k8-update b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01-k8-update new file mode 100644 index 000000000..79392f996 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01-k8-update @@ -0,0 +1,959 @@ +From: Andrew Vasquez +Subject: Update qla2xxx to 8.02.01-k8 +References: FATE#304113 + +This patch updates the qla2xxx driver to version 8.02.01-k8. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/qla2xxx/qla_attr.c | 9 + drivers/scsi/qla2xxx/qla_def.h | 12 + + drivers/scsi/qla2xxx/qla_fw.h | 71 +++++++ + drivers/scsi/qla2xxx/qla_gbl.h | 4 + drivers/scsi/qla2xxx/qla_init.c | 14 + + drivers/scsi/qla2xxx/qla_inline.h | 2 + drivers/scsi/qla2xxx/qla_iocb.c | 30 ++- + drivers/scsi/qla2xxx/qla_isr.c | 17 + + drivers/scsi/qla2xxx/qla_mbx.c | 6 + drivers/scsi/qla2xxx/qla_os.c | 9 + drivers/scsi/qla2xxx/qla_sup.c | 336 +++++++++++++++++++++++++++++++++---- + drivers/scsi/qla2xxx/qla_version.h | 2 + 12 files changed, 444 insertions(+), 68 deletions(-) + +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -292,10 +292,11 @@ qla2x00_sysfs_write_optrom_ctl(struct ko + valid = 0; + if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) + valid = 1; +- else if (start == (FA_BOOT_CODE_ADDR*4) || +- start == (FA_RISC_CODE_ADDR*4)) ++ else if (start == (ha->flt_region_boot * 4) || ++ start == (ha->flt_region_fw * 4)) + valid = 1; +- else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4)) ++ else if (IS_QLA25XX(ha) && ++ start == (ha->flt_region_vpd_nvram * 4)) + valid = 1; + if (!valid) { + qla_printk(KERN_WARNING, ha, +@@ -1064,6 +1065,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Ho + pfc_host_stat->dumped_frames = stats->dumped_frames; + pfc_host_stat->nos_count = stats->nos_rcvd; + } ++ pfc_host_stat->fcp_input_megabytes = ha->qla_stats.input_bytes >> 20; ++ pfc_host_stat->fcp_output_megabytes = ha->qla_stats.output_bytes >> 20; + + done_free: + dma_pool_free(ha->s_dma_pool, stats, stats_dma); +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -2157,6 +2157,8 @@ struct qla_chip_state_84xx { + + struct qla_statistics { + uint32_t total_isp_aborts; ++ uint64_t input_bytes; ++ uint64_t output_bytes; + }; + + /* +@@ -2238,6 +2240,7 @@ typedef struct scsi_qla_host { + #define FCPORT_UPDATE_NEEDED 27 + #define VP_DPC_NEEDED 28 /* wake up for VP dpc handling */ + #define UNLOADING 29 ++#define NPIV_CONFIG_NEEDED 30 + + uint32_t device_flags; + #define DFLG_LOCAL_DEVICES BIT_0 +@@ -2507,7 +2510,6 @@ typedef struct scsi_qla_host { + uint64_t fce_wr, fce_rd; + struct mutex fce_mutex; + +- uint32_t hw_event_start; + uint32_t hw_event_ptr; + uint32_t hw_event_pause_errors; + +@@ -2553,6 +2555,14 @@ typedef struct scsi_qla_host { + uint32_t fdt_unprotect_sec_cmd; + uint32_t fdt_protect_sec_cmd; + ++ uint32_t flt_region_flt; ++ uint32_t flt_region_fdt; ++ uint32_t flt_region_boot; ++ uint32_t flt_region_fw; ++ uint32_t flt_region_vpd_nvram; ++ uint32_t flt_region_hw_event; ++ uint32_t flt_region_npiv_conf; ++ + /* Needed for BEACON */ + uint16_t beacon_blink_led; + uint8_t beacon_color_state; +--- a/drivers/scsi/qla2xxx/qla_fw.h ++++ b/drivers/scsi/qla2xxx/qla_fw.h +@@ -789,14 +789,23 @@ struct device_reg_24xx { + #define FA_RISC_CODE_ADDR 0x20000 + #define FA_RISC_CODE_SEGMENTS 2 + ++#define FA_FLASH_DESCR_ADDR_24 0x11000 ++#define FA_FLASH_LAYOUT_ADDR_24 0x11400 ++#define FA_NPIV_CONF0_ADDR_24 0x16000 ++#define FA_NPIV_CONF1_ADDR_24 0x17000 ++ + #define FA_FW_AREA_ADDR 0x40000 + #define FA_VPD_NVRAM_ADDR 0x48000 + #define FA_FEATURE_ADDR 0x4C000 + #define FA_FLASH_DESCR_ADDR 0x50000 ++#define FA_FLASH_LAYOUT_ADDR 0x50400 + #define FA_HW_EVENT0_ADDR 0x54000 +-#define FA_HW_EVENT1_ADDR 0x54200 ++#define FA_HW_EVENT1_ADDR 0x54400 + #define FA_HW_EVENT_SIZE 0x200 + #define FA_HW_EVENT_ENTRY_SIZE 4 ++#define FA_NPIV_CONF0_ADDR 0x5C000 ++#define FA_NPIV_CONF1_ADDR 0x5D000 ++ + /* + * Flash Error Log Event Codes. + */ +@@ -806,10 +815,6 @@ struct device_reg_24xx { + #define HW_EVENT_NVRAM_CHKSUM_ERR 0xF023 + #define HW_EVENT_FLASH_FW_ERR 0xF024 + +-#define FA_BOOT_LOG_ADDR 0x58000 +-#define FA_FW_DUMP0_ADDR 0x60000 +-#define FA_FW_DUMP1_ADDR 0x70000 +- + uint32_t flash_data; /* Flash/NVRAM BIOS data. */ + + uint32_t ctrl_status; /* Control/Status. */ +@@ -1203,6 +1208,62 @@ struct qla_fdt_layout { + uint8_t unused2[65]; + }; + ++/* Flash Layout Table ********************************************************/ ++ ++struct qla_flt_location { ++ uint8_t sig[4]; ++ uint32_t start_lo; ++ uint32_t start_hi; ++ uint16_t unused; ++ uint16_t checksum; ++}; ++ ++struct qla_flt_header { ++ uint16_t version; ++ uint16_t length; ++ uint16_t checksum; ++ uint16_t unused; ++}; ++ ++#define FLT_REG_FW 0x01 ++#define FLT_REG_BOOT_CODE 0x07 ++#define FLT_REG_VPD_0 0x14 ++#define FLT_REG_NVRAM_0 0x15 ++#define FLT_REG_VPD_1 0x16 ++#define FLT_REG_NVRAM_1 0x17 ++#define FLT_REG_FDT 0x1a ++#define FLT_REG_FLT 0x1c ++#define FLT_REG_HW_EVENT_0 0x1d ++#define FLT_REG_HW_EVENT_1 0x1f ++#define FLT_REG_NPIV_CONF_0 0x29 ++#define FLT_REG_NPIV_CONF_1 0x2a ++ ++struct qla_flt_region { ++ uint32_t code; ++ uint32_t size; ++ uint32_t start; ++ uint32_t end; ++}; ++ ++/* Flash NPIV Configuration Table ********************************************/ ++ ++struct qla_npiv_header { ++ uint8_t sig[2]; ++ uint16_t version; ++ uint16_t entries; ++ uint16_t unused[4]; ++ uint16_t checksum; ++}; ++ ++struct qla_npiv_entry { ++ uint16_t flags; ++ uint16_t vf_id; ++ uint16_t qos; ++ uint16_t unused1; ++ uint8_t port_name[WWN_SIZE]; ++ uint8_t node_name[WWN_SIZE]; ++}; ++ + /* 84XX Support **************************************************************/ + + #define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */ +--- a/drivers/scsi/qla2xxx/qla_gbl.h ++++ b/drivers/scsi/qla2xxx/qla_gbl.h +@@ -313,9 +313,11 @@ extern int qla24xx_get_flash_version(scs + extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, + uint16_t, uint16_t); + +-extern void qla2xxx_get_flash_info(scsi_qla_host_t *); ++extern int qla2xxx_get_flash_info(scsi_qla_host_t *); + extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t); + ++extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *); ++ + /* + * Global Function Prototypes in qla_dbg.c source file. + */ +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -83,6 +83,13 @@ qla2x00_initialize_adapter(scsi_qla_host + + ha->isp_ops->reset_chip(ha); + ++ rval = qla2xxx_get_flash_info(ha); ++ if (rval) { ++ DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n", ++ ha->host_no)); ++ return (rval); ++ } ++ + ha->isp_ops->get_flash_version(ha, ha->request_ring); + + qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n"); +@@ -109,7 +116,6 @@ qla2x00_initialize_adapter(scsi_qla_host + rval = qla2x00_setup_chip(ha); + if (rval) + return (rval); +- qla2xxx_get_flash_info(ha); + } + if (IS_QLA84XX(ha)) { + ha->cs84xx = qla84xx_get_chip(ha); +@@ -2016,7 +2022,7 @@ qla2x00_configure_loop(scsi_qla_host_t * + DEBUG3(printk("%s: exiting normally\n", __func__)); + } + +- /* Restore state if a resync event occured during processing */ ++ /* Restore state if a resync event occurred during processing */ + if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { + if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); +@@ -2561,7 +2567,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_ho + rval = QLA_SUCCESS; + + /* Try GID_PT to get device list, else GAN. */ +- swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC); ++ swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL); + if (!swl) { + /*EMPTY*/ + DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback " +@@ -3751,7 +3757,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t + rval = QLA_SUCCESS; + + segments = FA_RISC_CODE_SEGMENTS; +- faddr = FA_RISC_CODE_ADDR; ++ faddr = ha->flt_region_fw; + dcode = (uint32_t *)ha->request_ring; + *srisc_addr = 0; + +--- a/drivers/scsi/qla2xxx/qla_inline.h ++++ b/drivers/scsi/qla2xxx/qla_inline.h +@@ -52,7 +52,7 @@ to_qla_parent(scsi_qla_host_t *ha) + * @ha: HA context + * @ha_locked: is function called with the hardware lock + * +- * Returns non-zero if a failure occured, else zero. ++ * Returns non-zero if a failure occurred, else zero. + */ + static inline int + qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked) +--- a/drivers/scsi/qla2xxx/qla_iocb.c ++++ b/drivers/scsi/qla2xxx/qla_iocb.c +@@ -21,17 +21,22 @@ static void qla2x00_isp_cmd(scsi_qla_hos + * Returns the proper CF_* direction based on CDB. + */ + static inline uint16_t +-qla2x00_get_cmd_direction(struct scsi_cmnd *cmd) ++qla2x00_get_cmd_direction(srb_t *sp) + { + uint16_t cflags; + + cflags = 0; + + /* Set transfer direction */ +- if (cmd->sc_data_direction == DMA_TO_DEVICE) ++ if (sp->cmd->sc_data_direction == DMA_TO_DEVICE) { + cflags = CF_WRITE; +- else if (cmd->sc_data_direction == DMA_FROM_DEVICE) ++ sp->fcport->ha->qla_stats.output_bytes += ++ scsi_bufflen(sp->cmd); ++ } else if (sp->cmd->sc_data_direction == DMA_FROM_DEVICE) { + cflags = CF_READ; ++ sp->fcport->ha->qla_stats.input_bytes += ++ scsi_bufflen(sp->cmd); ++ } + return (cflags); + } + +@@ -169,7 +174,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t * + + ha = sp->ha; + +- cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd)); ++ cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); + + /* Three DSDs are available in the Command Type 2 IOCB */ + avail_dsds = 3; +@@ -228,7 +233,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t * + + ha = sp->ha; + +- cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd)); ++ cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); + + /* Two DSDs are available in the Command Type 3 IOCB */ + avail_dsds = 2; +@@ -262,7 +267,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t * + * qla2x00_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * +- * Returns non-zero if a failure occured, else zero. ++ * Returns non-zero if a failure occurred, else zero. + */ + int + qla2x00_start_scsi(srb_t *sp) +@@ -407,7 +412,7 @@ queuing_error: + * + * Can be called from both normal and interrupt context. + * +- * Returns non-zero if a failure occured, else zero. ++ * Returns non-zero if a failure occurred, else zero. + */ + int + __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, +@@ -625,12 +630,17 @@ qla24xx_build_scsi_iocbs(srb_t *sp, stru + ha = sp->ha; + + /* Set transfer direction */ +- if (cmd->sc_data_direction == DMA_TO_DEVICE) ++ if (cmd->sc_data_direction == DMA_TO_DEVICE) { + cmd_pkt->task_mgmt_flags = + __constant_cpu_to_le16(TMF_WRITE_DATA); +- else if (cmd->sc_data_direction == DMA_FROM_DEVICE) ++ sp->fcport->ha->qla_stats.output_bytes += ++ scsi_bufflen(sp->cmd); ++ } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { + cmd_pkt->task_mgmt_flags = + __constant_cpu_to_le16(TMF_READ_DATA); ++ sp->fcport->ha->qla_stats.input_bytes += ++ scsi_bufflen(sp->cmd); ++ } + + /* One DSD is available in the Command Type 3 IOCB */ + avail_dsds = 1; +@@ -666,7 +676,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, stru + * qla24xx_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * +- * Returns non-zero if a failure occured, else zero. ++ * Returns non-zero if a failure occurred, else zero. + */ + int + qla24xx_start_scsi(srb_t *sp) +--- a/drivers/scsi/qla2xxx/qla_isr.c ++++ b/drivers/scsi/qla2xxx/qla_isr.c +@@ -391,9 +391,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, + break; + + case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ +- DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no, ++ DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", ha->host_no, + mb[1])); +- qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]); ++ qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); +@@ -460,7 +460,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, + DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n", + ha->host_no, mb[1])); + qla_printk(KERN_INFO, ha, +- "LIP reset occured (%x).\n", mb[1]); ++ "LIP reset occurred (%x).\n", mb[1]); + + if (atomic_read(&ha->loop_state) != LOOP_DOWN) { + atomic_set(&ha->loop_state, LOOP_DOWN); +@@ -543,7 +543,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, + + case MBA_PORT_UPDATE: /* Port database update */ + /* +- * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET ++ * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET + * event etc. earlier indicating loop is down) then process + * it. Otherwise ignore it and Wait for RSCN to come in. + */ +@@ -589,7 +589,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, + "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n", + ha->host_no, mb[1], mb[2], mb[3])); + +- rscn_entry = (mb[1] << 16) | mb[2]; ++ rscn_entry = ((mb[1] & 0xff) << 16) | mb[2]; + host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) | + ha->d_id.b.al_pa; + if (rscn_entry == host_pid) { +@@ -600,6 +600,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, + break; + } + ++ /* Ignore reserved bits from RSCN-payload. */ ++ rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2]; + rscn_queue_index = ha->rscn_in_ptr + 1; + if (rscn_queue_index == MAX_RSCN_COUNT) + rscn_queue_index = 0; +@@ -1060,8 +1062,9 @@ qla2x00_status_entry(scsi_qla_host_t *ha + resid = resid_len; + /* Use F/W calculated residual length. */ + if (IS_FWI2_CAPABLE(ha)) { +- if (scsi_status & SS_RESIDUAL_UNDER && +- resid != fw_resid_len) { ++ if (!(scsi_status & SS_RESIDUAL_UNDER)) { ++ lscsi_status = 0; ++ } else if (resid != fw_resid_len) { + scsi_status &= ~SS_RESIDUAL_UNDER; + lscsi_status = 0; + } +--- a/drivers/scsi/qla2xxx/qla_mbx.c ++++ b/drivers/scsi/qla2xxx/qla_mbx.c +@@ -233,7 +233,7 @@ qla2x00_mailbox_command(scsi_qla_host_t + DEBUG2_3_11(printk("%s(%ld): timeout schedule " + "isp_abort_needed.\n", __func__, ha->host_no)); + qla_printk(KERN_WARNING, ha, +- "Mailbox command timeout occured. Scheduling ISP " ++ "Mailbox command timeout occurred. Scheduling ISP " + "abort.\n"); + set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + qla2xxx_wake_dpc(ha); +@@ -244,7 +244,7 @@ qla2x00_mailbox_command(scsi_qla_host_t + DEBUG2_3_11(printk("%s(%ld): timeout calling " + "abort_isp\n", __func__, ha->host_no)); + qla_printk(KERN_WARNING, ha, +- "Mailbox command timeout occured. Issuing ISP " ++ "Mailbox command timeout occurred. Issuing ISP " + "abort.\n"); + + set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); +@@ -1995,7 +1995,7 @@ qla2x00_get_fcal_position_map(scsi_qla_h + char *pmap; + dma_addr_t pmap_dma; + +- pmap = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &pmap_dma); ++ pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma); + if (pmap == NULL) { + DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****", + __func__, ha->host_no)); +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -1515,6 +1515,7 @@ qla2xxx_scan_start(struct Scsi_Host *sho + set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); + set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); + set_bit(RSCN_UPDATE, &ha->dpc_flags); ++ set_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags); + } + + static int +@@ -1661,8 +1662,6 @@ qla2x00_probe_one(struct pci_dev *pdev, + ha->gid_list_info_size = 8; + ha->optrom_size = OPTROM_SIZE_25XX; + ha->isp_ops = &qla25xx_isp_ops; +- ha->hw_event_start = PCI_FUNC(pdev->devfn) ? +- FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR; + } + host->can_queue = ha->request_q_length + 128; + +@@ -2431,6 +2430,12 @@ qla2x00_do_dpc(void *data) + ha->host_no)); + } + ++ if (test_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags) && ++ atomic_read(&ha->loop_state) == LOOP_READY) { ++ clear_bit(NPIV_CONFIG_NEEDED, &ha->dpc_flags); ++ qla2xxx_flash_npiv_conf(ha); ++ } ++ + if (!ha->interrupts_on) + ha->isp_ops->enable_intrs(ha); + +--- a/drivers/scsi/qla2xxx/qla_sup.c ++++ b/drivers/scsi/qla2xxx/qla_sup.c +@@ -543,23 +543,198 @@ qla24xx_get_flash_manufacturer(scsi_qla_ + } + } + +-void +-qla2xxx_get_flash_info(scsi_qla_host_t *ha) ++static int ++qla2xxx_find_flt_start(scsi_qla_host_t *ha, uint32_t *start) ++{ ++ const char *loc, *locations[] = { "DEF", "PCI" }; ++ uint32_t pcihdr, pcids; ++ uint32_t *dcode; ++ uint8_t *buf, *bcode, last_image; ++ uint16_t cnt, chksum, *wptr; ++ struct qla_flt_location *fltl; ++ ++ /* ++ * FLT-location structure resides after the last PCI region. ++ */ ++ ++ /* Begin with sane defaults. */ ++ loc = locations[0]; ++ *start = IS_QLA24XX_TYPE(ha) ? FA_FLASH_LAYOUT_ADDR_24: ++ FA_FLASH_LAYOUT_ADDR; ++ ++ /* Begin with first PCI expansion ROM header. */ ++ buf = (uint8_t *)ha->request_ring; ++ dcode = (uint32_t *)ha->request_ring; ++ pcihdr = 0; ++ last_image = 1; ++ do { ++ /* Verify PCI expansion ROM header. */ ++ qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20); ++ bcode = buf + (pcihdr % 4); ++ if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) ++ goto end; ++ ++ /* Locate PCI data structure. */ ++ pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); ++ qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20); ++ bcode = buf + (pcihdr % 4); ++ ++ /* Validate signature of PCI data structure. */ ++ if (bcode[0x0] != 'P' || bcode[0x1] != 'C' || ++ bcode[0x2] != 'I' || bcode[0x3] != 'R') ++ goto end; ++ ++ last_image = bcode[0x15] & BIT_7; ++ ++ /* Locate next PCI expansion ROM. */ ++ pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512; ++ } while (!last_image); ++ ++ /* Now verify FLT-location structure. */ ++ fltl = (struct qla_flt_location *)ha->request_ring; ++ qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, ++ sizeof(struct qla_flt_location) >> 2); ++ if (fltl->sig[0] != 'Q' || fltl->sig[1] != 'F' || ++ fltl->sig[2] != 'L' || fltl->sig[3] != 'T') ++ goto end; ++ ++ wptr = (uint16_t *)ha->request_ring; ++ cnt = sizeof(struct qla_flt_location) >> 1; ++ for (chksum = 0; cnt; cnt--) ++ chksum += le16_to_cpu(*wptr++); ++ if (chksum) { ++ qla_printk(KERN_ERR, ha, ++ "Inconsistent FLTL detected: checksum=0x%x.\n", chksum); ++ qla2x00_dump_buffer(buf, sizeof(struct qla_flt_location)); ++ return QLA_FUNCTION_FAILED; ++ } ++ ++ /* Good data. Use specified location. */ ++ loc = locations[1]; ++ *start = le16_to_cpu(fltl->start_hi) << 16 | ++ le16_to_cpu(fltl->start_lo); ++end: ++ DEBUG2(qla_printk(KERN_DEBUG, ha, "FLTL[%s] = 0x%x.\n", loc, *start)); ++ return QLA_SUCCESS; ++} ++ ++static void ++qla2xxx_get_flt_info(scsi_qla_host_t *ha, uint32_t flt_addr) ++{ ++ const char *loc, *locations[] = { "DEF", "FLT" }; ++ uint16_t *wptr; ++ uint16_t cnt, chksum; ++ uint32_t start; ++ struct qla_flt_header *flt; ++ struct qla_flt_region *region; ++ ++ ha->flt_region_flt = flt_addr; ++ wptr = (uint16_t *)ha->request_ring; ++ flt = (struct qla_flt_header *)ha->request_ring; ++ region = (struct qla_flt_region *)&flt[1]; ++ ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring, ++ flt_addr << 2, OPTROM_BURST_SIZE); ++ if (*wptr == __constant_cpu_to_le16(0xffff)) ++ goto no_flash_data; ++ if (flt->version != __constant_cpu_to_le16(1)) { ++ DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported FLT detected: " ++ "version=0x%x length=0x%x checksum=0x%x.\n", ++ le16_to_cpu(flt->version), le16_to_cpu(flt->length), ++ le16_to_cpu(flt->checksum))); ++ goto no_flash_data; ++ } ++ ++ cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1; ++ for (chksum = 0; cnt; cnt--) ++ chksum += le16_to_cpu(*wptr++); ++ if (chksum) { ++ DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FLT detected: " ++ "version=0x%x length=0x%x checksum=0x%x.\n", ++ le16_to_cpu(flt->version), le16_to_cpu(flt->length), ++ chksum)); ++ goto no_flash_data; ++ } ++ ++ loc = locations[1]; ++ cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); ++ for ( ; cnt; cnt--, region++) { ++ /* Store addresses as DWORD offsets. */ ++ start = le32_to_cpu(region->start) >> 2; ++ ++ DEBUG3(qla_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x " ++ "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start, ++ le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size))); ++ ++ switch (le32_to_cpu(region->code)) { ++ case FLT_REG_FW: ++ ha->flt_region_fw = start; ++ break; ++ case FLT_REG_BOOT_CODE: ++ ha->flt_region_boot = start; ++ break; ++ case FLT_REG_VPD_0: ++ ha->flt_region_vpd_nvram = start; ++ break; ++ case FLT_REG_FDT: ++ ha->flt_region_fdt = start; ++ break; ++ case FLT_REG_HW_EVENT_0: ++ if (!PCI_FUNC(ha->pdev->devfn)) ++ ha->flt_region_hw_event = start; ++ break; ++ case FLT_REG_HW_EVENT_1: ++ if (PCI_FUNC(ha->pdev->devfn)) ++ ha->flt_region_hw_event = start; ++ break; ++ case FLT_REG_NPIV_CONF_0: ++ if (!PCI_FUNC(ha->pdev->devfn)) ++ ha->flt_region_npiv_conf = start; ++ break; ++ case FLT_REG_NPIV_CONF_1: ++ if (PCI_FUNC(ha->pdev->devfn)) ++ ha->flt_region_npiv_conf = start; ++ break; ++ } ++ } ++ goto done; ++ ++no_flash_data: ++ /* Use hardcoded defaults. */ ++ loc = locations[0]; ++ ha->flt_region_fw = FA_RISC_CODE_ADDR; ++ ha->flt_region_boot = FA_BOOT_CODE_ADDR; ++ ha->flt_region_vpd_nvram = FA_VPD_NVRAM_ADDR; ++ ha->flt_region_fdt = IS_QLA24XX_TYPE(ha) ? FA_FLASH_DESCR_ADDR_24: ++ FA_FLASH_DESCR_ADDR; ++ ha->flt_region_hw_event = !PCI_FUNC(ha->pdev->devfn) ? ++ FA_HW_EVENT0_ADDR: FA_HW_EVENT1_ADDR; ++ ha->flt_region_npiv_conf = !PCI_FUNC(ha->pdev->devfn) ? ++ (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF0_ADDR_24: FA_NPIV_CONF0_ADDR): ++ (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF1_ADDR_24: FA_NPIV_CONF1_ADDR); ++done: ++ DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x " ++ "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x npiv=0x%x.\n", loc, ++ ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram, ++ ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event, ++ ha->flt_region_npiv_conf)); ++} ++ ++static void ++qla2xxx_get_fdt_info(scsi_qla_host_t *ha) + { + #define FLASH_BLK_SIZE_32K 0x8000 + #define FLASH_BLK_SIZE_64K 0x10000 ++ const char *loc, *locations[] = { "MID", "FDT" }; + uint16_t cnt, chksum; + uint16_t *wptr; + struct qla_fdt_layout *fdt; + uint8_t man_id, flash_id; +- +- if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) +- return; ++ uint16_t mid, fid; + + wptr = (uint16_t *)ha->request_ring; + fdt = (struct qla_fdt_layout *)ha->request_ring; + ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring, +- FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE); ++ ha->flt_region_fdt << 2, OPTROM_BURST_SIZE); + if (*wptr == __constant_cpu_to_le16(0xffff)) + goto no_flash_data; + if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || +@@ -577,7 +752,10 @@ qla2xxx_get_flash_info(scsi_qla_host_t * + goto no_flash_data; + } + +- ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; ++ loc = locations[1]; ++ mid = le16_to_cpu(fdt->man_id); ++ fid = le16_to_cpu(fdt->id); ++ ha->fdt_odd_index = mid == 0x1f; + ha->fdt_wrt_disable = fdt->wrt_disable_bits; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_block_size = le32_to_cpu(fdt->block_size); +@@ -588,16 +766,12 @@ qla2xxx_get_flash_info(scsi_qla_host_t * + flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd): + flash_conf_to_access_addr(0x0336); + } +- +- DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " +- "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", +- le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, +- ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, +- ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); +- return; +- ++ goto done; + no_flash_data: ++ loc = locations[0]; + qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); ++ mid = man_id; ++ fid = flash_id; + ha->fdt_wrt_disable = 0x9c; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8); + switch (man_id) { +@@ -625,14 +799,115 @@ no_flash_data: + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + break; + } +- +- DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " +- "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, ++done: ++ DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x " ++ "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", loc, mid, fid, + ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, + ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, + ha->fdt_block_size)); + } + ++int ++qla2xxx_get_flash_info(scsi_qla_host_t *ha) ++{ ++ int ret; ++ uint32_t flt_addr; ++ ++ if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) ++ return QLA_SUCCESS; ++ ++ ret = qla2xxx_find_flt_start(ha, &flt_addr); ++ if (ret != QLA_SUCCESS) ++ return ret; ++ ++ qla2xxx_get_flt_info(ha, flt_addr); ++ qla2xxx_get_fdt_info(ha); ++ ++ return QLA_SUCCESS; ++} ++ ++void ++qla2xxx_flash_npiv_conf(scsi_qla_host_t *ha) ++{ ++#define NPIV_CONFIG_SIZE (16*1024) ++ void *data; ++ uint16_t *wptr; ++ uint16_t cnt, chksum; ++ struct qla_npiv_header hdr; ++ struct qla_npiv_entry *entry; ++ ++ if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) ++ return; ++ ++ ha->isp_ops->read_optrom(ha, (uint8_t *)&hdr, ++ ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header)); ++ if (hdr.version == __constant_cpu_to_le16(0xffff)) ++ return; ++ if (hdr.version != __constant_cpu_to_le16(1)) { ++ DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported NPIV-Config " ++ "detected: version=0x%x entries=0x%x checksum=0x%x.\n", ++ le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries), ++ le16_to_cpu(hdr.checksum))); ++ return; ++ } ++ ++ data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL); ++ if (!data) { ++ DEBUG2(qla_printk(KERN_INFO, ha, "NPIV-Config: Unable to " ++ "allocate memory.\n")); ++ return; ++ } ++ ++ ha->isp_ops->read_optrom(ha, (uint8_t *)data, ++ ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE); ++ ++ cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) * ++ sizeof(struct qla_npiv_entry)) >> 1; ++ for (wptr = data, chksum = 0; cnt; cnt--) ++ chksum += le16_to_cpu(*wptr++); ++ if (chksum) { ++ DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent NPIV-Config " ++ "detected: version=0x%x entries=0x%x checksum=0x%x.\n", ++ le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries), ++ chksum)); ++ goto done; ++ } ++ ++ entry = data + sizeof(struct qla_npiv_header); ++ cnt = le16_to_cpu(hdr.entries); ++ for ( ; cnt; cnt--, entry++) { ++ uint16_t flags; ++ struct fc_vport_identifiers vid; ++ struct fc_vport *vport; ++ ++ flags = le16_to_cpu(entry->flags); ++ if (flags == 0xffff) ++ continue; ++ if ((flags & BIT_0) == 0) ++ continue; ++ ++ memset(&vid, 0, sizeof(vid)); ++ vid.roles = FC_PORT_ROLE_FCP_INITIATOR; ++ vid.vport_type = FC_PORTTYPE_NPIV; ++ vid.disable = false; ++ vid.port_name = wwn_to_u64(entry->port_name); ++ vid.node_name = wwn_to_u64(entry->node_name); ++ ++ DEBUG2(qla_printk(KERN_DEBUG, ha, "NPIV[%02x]: wwpn=%llx " ++ "wwnn=%llx vf_id=0x%x qos=0x%x.\n", cnt, vid.port_name, ++ vid.node_name, le16_to_cpu(entry->vf_id), ++ le16_to_cpu(entry->qos))); ++ ++ vport = fc_vport_create(ha->host, 0, &vid); ++ if (!vport) ++ qla_printk(KERN_INFO, ha, "NPIV-Config: Failed to " ++ "create vport [%02x]: wwpn=%llx wwnn=%llx.\n", cnt, ++ vid.port_name, vid.node_name); ++ } ++done: ++ kfree(data); ++} ++ + static void + qla24xx_unprotect_flash(scsi_qla_host_t *ha) + { +@@ -920,7 +1195,8 @@ qla25xx_read_nvram_data(scsi_qla_host_t + dwptr = (uint32_t *)buf; + for (i = 0; i < bytes >> 2; i++, naddr++) + dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, +- flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr))); ++ flash_data_to_access_addr(ha->flt_region_vpd_nvram | ++ naddr))); + + return buf; + } +@@ -935,10 +1211,10 @@ qla25xx_write_nvram_data(scsi_qla_host_t + dbuf = vmalloc(RMW_BUFFER_SIZE); + if (!dbuf) + return QLA_MEMORY_ALLOC_FAILED; +- ha->isp_ops->read_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2, ++ ha->isp_ops->read_optrom(ha, dbuf, ha->flt_region_vpd_nvram << 2, + RMW_BUFFER_SIZE); + memcpy(dbuf + (naddr << 2), buf, bytes); +- ha->isp_ops->write_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2, ++ ha->isp_ops->write_optrom(ha, dbuf, ha->flt_region_vpd_nvram << 2, + RMW_BUFFER_SIZE); + vfree(dbuf); + +@@ -2166,7 +2442,7 @@ qla2x00_get_flash_version(scsi_qla_host_ + memset(dbyte, 0, 8); + dcode = (uint16_t *)dbyte; + +- qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10, ++ qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10, + 8); + DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n", + __func__, ha->host_no)); +@@ -2177,7 +2453,7 @@ qla2x00_get_flash_version(scsi_qla_host_ + (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && + dcode[3] == 0)) { + DEBUG2(printk("%s(): Unrecognized fw revision at " +- "%x.\n", __func__, FA_RISC_CODE_ADDR * 4)); ++ "%x.\n", __func__, ha->flt_region_fw * 4)); + } else { + /* values are in big endian */ + ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1]; +@@ -2212,7 +2488,7 @@ qla24xx_get_flash_version(scsi_qla_host_ + dcode = mbuf; + + /* Begin with first PCI expansion ROM header. */ +- pcihdr = 0; ++ pcihdr = ha->flt_region_boot; + last_image = 1; + do { + /* Verify PCI expansion ROM header. */ +@@ -2282,7 +2558,7 @@ qla24xx_get_flash_version(scsi_qla_host_ + memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); + dcode = mbuf; + +- qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4); ++ qla24xx_read_flash_data(ha, dcode, ha->flt_region_fw + 4, 4); + for (i = 0; i < 4; i++) + dcode[i] = be32_to_cpu(dcode[i]); + +@@ -2291,7 +2567,7 @@ qla24xx_get_flash_version(scsi_qla_host_ + (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && + dcode[3] == 0)) { + DEBUG2(printk("%s(): Unrecognized fw version at %x.\n", +- __func__, FA_RISC_CODE_ADDR)); ++ __func__, ha->flt_region_fw)); + } else { + ha->fw_revision[0] = dcode[0]; + ha->fw_revision[1] = dcode[1]; +@@ -2355,7 +2631,7 @@ qla2xxx_hw_event_store(scsi_qla_host_t * + /* Locate first empty entry. */ + for (;;) { + if (ha->hw_event_ptr >= +- ha->hw_event_start + FA_HW_EVENT_SIZE) { ++ ha->flt_region_hw_event + FA_HW_EVENT_SIZE) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Log Full!\n")); + return QLA_MEMORY_ALLOC_FAILED; +@@ -2391,7 +2667,7 @@ qla2xxx_hw_event_log(scsi_qla_host_t *ha + int rval; + uint32_t marker[2], fdata[4]; + +- if (ha->hw_event_start == 0) ++ if (ha->flt_region_hw_event == 0) + return QLA_FUNCTION_FAILED; + + DEBUG2(qla_printk(KERN_WARNING, ha, +@@ -2406,7 +2682,7 @@ qla2xxx_hw_event_log(scsi_qla_host_t *ha + QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER); + + /* Locate marker. */ +- ha->hw_event_ptr = ha->hw_event_start; ++ ha->hw_event_ptr = ha->flt_region_hw_event; + for (;;) { + qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr, + 4); +@@ -2415,7 +2691,7 @@ qla2xxx_hw_event_log(scsi_qla_host_t *ha + break; + ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; + if (ha->hw_event_ptr >= +- ha->hw_event_start + FA_HW_EVENT_SIZE) { ++ ha->flt_region_hw_event + FA_HW_EVENT_SIZE) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Log Full!\n")); + return QLA_MEMORY_ALLOC_FAILED; +--- a/drivers/scsi/qla2xxx/qla_version.h ++++ b/drivers/scsi/qla2xxx/qla_version.h +@@ -7,7 +7,7 @@ + /* + * Driver version + */ +-#define QLA2XXX_VERSION "8.02.01-k7" ++#define QLA2XXX_VERSION "8.02.01-k8" + + #define QLA_DRIVER_MAJOR_VER 8 + #define QLA_DRIVER_MINOR_VER 2 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01-k9-update b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01-k9-update new file mode 100644 index 000000000..b9f1ac0f1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01-k9-update @@ -0,0 +1,167 @@ +From: Andrew Vasquez +Subject: Update qla2xxx to 8.02.01-k9 +References: bnc#439208 +Patch-Mainline: 2.6.28 + +Since our last resync of SLES11 patches, We've since pushed upstream +another round of updates which we'd like pulled into the SLES11 tree. + +Here's the upstream pull request: + + [PATCH 0/5] qla2xxx: fixes for 2.6.28 [8.02.01-k9]. + http://article.gmane.org/gmane.linux.scsi/45496 + +through the following commits: + + qla2xxx: Correct Atmel flash-part handling. + qla2xxx: Use pci_disable_rom() to manipulate PCI config space. + qla2xxx: Do not honour max_vports from firmware for 2G ISPs and below. + qla2xxx: Return a FAILED status when abort mailbox-command fails. + qla2xxx: Update version number to 8.02.01-k9. + +there's actually only 4 of the 5 which are applicable or SLES11: + + qla2xxx: Correct Atmel flash-part handling. + http://article.gmane.org/gmane.linux.scsi/45495 + + qla2xxx: Do not honour max_vports from firmware for 2G ISPs and below. + http://article.gmane.org/gmane.linux.scsi/45498 + + qla2xxx: Return a FAILED status when abort mailbox-command fails. + http://article.gmane.org/gmane.linux.scsi/45494 + + qla2xxx: Update version number to 8.02.01-k9. + http://article.gmane.org/gmane.linux.scsi/45499 + +Signed-off-by: Andrew Vasquez +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h +index ab802e9..a45e333 100644 +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -2548,7 +2548,6 @@ typedef struct scsi_qla_host { + uint8_t fcode_revision[16]; + uint32_t fw_revision[4]; + +- uint16_t fdt_odd_index; + uint32_t fdt_wrt_disable; + uint32_t fdt_erase_cmd; + uint32_t fdt_block_size; +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index a470f2d..ad2dd8c 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -980,7 +980,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) + &ha->fw_minor_version, + &ha->fw_subminor_version, + &ha->fw_attributes, &ha->fw_memory_size); +- qla2x00_resize_request_q(ha); + ha->flags.npiv_supported = 0; + if ((IS_QLA24XX(ha) || IS_QLA25XX(ha) || + IS_QLA84XX(ha)) && +@@ -992,6 +991,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) + ha->max_npiv_vports = + MIN_MULTI_ID_FABRIC - 1; + } ++ qla2x00_resize_request_q(ha); + + if (ql2xallocfwdump) + qla2x00_alloc_fw_dump(ha); +diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c +index 36bc685..3402746 100644 +--- a/drivers/scsi/qla2xxx/qla_mbx.c ++++ b/drivers/scsi/qla2xxx/qla_mbx.c +@@ -1964,7 +1964,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, + *cur_iocb_cnt = mcp->mb[7]; + if (orig_iocb_cnt) + *orig_iocb_cnt = mcp->mb[10]; +- if (max_npiv_vports) ++ if (ha->flags.npiv_supported && max_npiv_vports) + *max_npiv_vports = mcp->mb[11]; + } + +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 2aed472..4774acb 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -728,6 +728,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) + if (ha->isp_ops->abort_command(ha, sp)) { + DEBUG2(printk("%s(%ld): abort_command " + "mbx failed.\n", __func__, ha->host_no)); ++ ret = FAILED; + } else { + DEBUG3(printk("%s(%ld): abort_command " + "mbx success.\n", __func__, ha->host_no)); +diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c +index e2432ef..6729a39 100644 +--- a/drivers/scsi/qla2xxx/qla_sup.c ++++ b/drivers/scsi/qla2xxx/qla_sup.c +@@ -722,6 +722,7 @@ done: + static void + qla2xxx_get_fdt_info(scsi_qla_host_t *ha) + { ++#define FLASH_BLK_SIZE_4K 0x1000 + #define FLASH_BLK_SIZE_32K 0x8000 + #define FLASH_BLK_SIZE_64K 0x10000 + const char *loc, *locations[] = { "MID", "FDT" }; +@@ -755,7 +756,6 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *ha) + loc = locations[1]; + mid = le16_to_cpu(fdt->man_id); + fid = le16_to_cpu(fdt->id); +- ha->fdt_odd_index = mid == 0x1f; + ha->fdt_wrt_disable = fdt->wrt_disable_bits; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_block_size = le32_to_cpu(fdt->block_size); +@@ -788,8 +788,7 @@ no_flash_data: + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + break; + case 0x1f: /* Atmel 26DF081A. */ +- ha->fdt_odd_index = 1; +- ha->fdt_block_size = FLASH_BLK_SIZE_64K; ++ ha->fdt_block_size = FLASH_BLK_SIZE_4K; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); + ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); +@@ -801,9 +800,9 @@ no_flash_data: + } + done: + DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x " +- "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", loc, mid, fid, ++ "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid, + ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, +- ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, ++ ha->fdt_unprotect_sec_cmd, ha->fdt_wrt_disable, + ha->fdt_block_size)); + } + +@@ -985,13 +984,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, + qla24xx_unprotect_flash(ha); + + for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { +- if (ha->fdt_odd_index) { +- findex = faddr << 2; +- fdata = findex & sec_mask; +- } else { +- findex = faddr; +- fdata = (findex & sec_mask) << 2; +- } ++ ++ findex = faddr; ++ fdata = (findex & sec_mask) << 2; + + /* Are we at the beginning of a sector? */ + if ((findex & rest_addr) == 0) { +diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h +index be5e299..eea6720 100644 +--- a/drivers/scsi/qla2xxx/qla_version.h ++++ b/drivers/scsi/qla2xxx/qla_version.h +@@ -7,7 +7,7 @@ + /* + * Driver version + */ +-#define QLA2XXX_VERSION "8.02.01-k8" ++#define QLA2XXX_VERSION "8.02.01-k9" + + #define QLA_DRIVER_MAJOR_VER 8 + #define QLA_DRIVER_MINOR_VER 2 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01.02.11.0-k9-update b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01.02.11.0-k9-update new file mode 100644 index 000000000..914a7a1df --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01.02.11.0-k9-update @@ -0,0 +1,1453 @@ +From: David Wagner +Subject: qla2xxx: additional fixes/updates for SLES11 +References: bnc#450197 + +Here's some additional updates/corrections to qla2xxx for SLES11. +Should apply cleanly to the beta6 driver sources. + + [PATCH 1/5] qla2xxx: Add ISP84xx firmware-update support. + [PATCH 2/5] qla2xxx: Add CT/ELS passthru support. + [PATCH 3/5] qla2xxx: Use correct value for max vport in LOOP topology. + [PATCH 4/5] qla2xxx: Correction of struct qla_flt_location. + [PATCH 5/5] qla2xxx: Update version number to 8.02.01.02.11.0-k9. + +Corresponding upstream patches are queued in our local tree for +for the next merge window (post 2.6.28). + +Signed-off-by: David Vasquez +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile +index c51fd1f..01ed81c 100644 +--- a/drivers/scsi/qla2xxx/Makefile ++++ b/drivers/scsi/qla2xxx/Makefile +@@ -1,4 +1,5 @@ + qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ +- qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o ++ qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o \ ++ qla_nlnk.o + + obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o +diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c +index ed73196..6d5210e 100644 +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -454,6 +454,287 @@ static struct bin_attribute sysfs_sfp_attr = { + .read = qla2x00_sysfs_read_sfp, + }; + ++static fc_port_t * ++qla2x00_find_port(struct scsi_qla_host *ha, uint8_t *pn) ++{ ++ fc_port_t *fcport; ++ ++ list_for_each_entry(fcport, &ha->fcports, list) ++ if (!memcmp(pn, fcport->port_name, sizeof(fcport->port_name))) ++ return fcport; ++ ++ return NULL; ++} ++ ++static void ++qla2x00_wait_for_passthru_completion(struct scsi_qla_host *ha) ++{ ++ if (!wait_for_completion_timeout(&ha->pass_thru_intr_comp, 10 * HZ)) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru request timed out.\n")); ++ ha->isp_ops->fw_dump(ha, 0); ++ } ++} ++ ++static ssize_t ++qla2x00_sysfs_read_els(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, ++ struct device, kobj))); ++ ++ if (!IS_FWI2_CAPABLE(ha)) ++ return 0; ++ ++ if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS response is not available.\n")); ++ return 0; ++ } ++ ++ memcpy(buf, ha->pass_thru, count); ++ ++ ha->pass_thru_cmd_result = 0; ++ ha->pass_thru_cmd_in_process = 0; ++ ++ return count; ++} ++ ++static ssize_t ++qla2x00_sysfs_write_els(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, ++ struct device, kobj))); ++ struct els_request *request = (struct els_request *) buf; ++ struct els_entry_24xx *els_iocb; ++ unsigned long flags; ++ uint16_t nextlid = 0; ++ fc_port_t *fcport; ++ ++ count -= sizeof(request->header); ++ ++ if (!IS_FWI2_CAPABLE(ha) || ++ atomic_read(&ha->loop_state) != LOOP_READY) ++ goto els_error0; ++ ++ if (count < sizeof(request->ct_iu)) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS buffer insufficient size %ld...\n", count)); ++ goto els_error0; ++ } ++ ++ if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS request is already progress\n")); ++ goto els_error0; ++ } ++ ++ fcport = qla2x00_find_port(ha, request->header.WWPN); ++ if (!fcport) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS request failed find port\n")); ++ goto els_error0; ++ } ++ ++ if (qla2x00_fabric_login(ha, fcport, &nextlid)) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS request failed to login port %06X\n", ++ fcport->d_id.b24)); ++ goto els_error0; ++ } ++ ++ ha->pass_thru_cmd_in_process = 1; ++ spin_lock_irqsave(&ha->hardware_lock, flags); ++ ++ els_iocb = (void *)qla2x00_req_pkt(ha); ++ if (els_iocb == NULL) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS request failed to get request packet\n")); ++ goto els_error1; ++ } ++ ++ if (count > PAGE_SIZE) { ++ DEBUG2(qla_printk(KERN_INFO, ha, ++ "Passthru ELS request excessive size %ld...\n", count)); ++ count = PAGE_SIZE; ++ } ++ ++ memset(ha->pass_thru, 0, PAGE_SIZE); ++ memcpy(ha->pass_thru, &request->ct_iu, count); ++ ++ els_iocb->entry_type = ELS_IOCB_TYPE; ++ els_iocb->entry_count = 1; ++ els_iocb->sys_define = 0; ++ els_iocb->entry_status = 0; ++ els_iocb->nport_handle = cpu_to_le16(fcport->loop_id); ++ els_iocb->tx_dsd_count = __constant_cpu_to_le16(1); ++ els_iocb->vp_index = ha->vp_idx; ++ els_iocb->sof_type = EST_SOFI3; ++ els_iocb->rx_dsd_count = __constant_cpu_to_le16(1); ++ els_iocb->opcode = 0; ++ els_iocb->port_id[0] = fcport->d_id.b.al_pa; ++ els_iocb->port_id[1] = fcport->d_id.b.area; ++ els_iocb->port_id[2] = fcport->d_id.b.domain; ++ els_iocb->control_flags = __constant_cpu_to_le16(0); ++ els_iocb->rx_byte_count = cpu_to_le32(PAGE_SIZE); ++ els_iocb->tx_byte_count = cpu_to_le32(count); ++ els_iocb->tx_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); ++ els_iocb->tx_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); ++ els_iocb->tx_len = els_iocb->tx_byte_count; ++ els_iocb->rx_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); ++ els_iocb->rx_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); ++ els_iocb->rx_len = els_iocb->rx_byte_count; ++ ++ wmb(); ++ qla2x00_isp_cmd(ha); ++ ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ qla2x00_wait_for_passthru_completion(ha); ++ ++ return count; ++ ++els_error1: ++ ha->pass_thru_cmd_in_process = 0; ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++els_error0: ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru ELS failed on scsi(%ld)\n", ha->host_no)); ++ return 0; ++} ++ ++static struct bin_attribute sysfs_els_attr = { ++ .attr = { ++ .name = "els", ++ .mode = S_IRUSR | S_IWUSR, ++ .owner = THIS_MODULE, ++ }, ++ .size = 0, ++ .read = qla2x00_sysfs_read_els, ++ .write = qla2x00_sysfs_write_els, ++}; ++ ++static ssize_t ++qla2x00_sysfs_read_ct(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, ++ struct device, kobj))); ++ ++ if (!IS_FWI2_CAPABLE(ha)) ++ return 0; ++ ++ if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru CT response is not available.\n")); ++ return 0; ++ } ++ ++ memcpy(buf, ha->pass_thru, count); ++ ++ ha->pass_thru_cmd_result = 0; ++ ha->pass_thru_cmd_in_process = 0; ++ ++ return count; ++} ++ ++static ssize_t ++qla2x00_sysfs_write_ct(struct kobject *kobj, struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, ++ struct device, kobj))); ++ struct fc_ct_request *request = (struct fc_ct_request *) buf; ++ struct ct_entry_24xx *ct_iocb; ++ unsigned long flags; ++ ++ if (!IS_FWI2_CAPABLE(ha) || ++ atomic_read(&ha->loop_state) != LOOP_READY) ++ goto ct_error0; ++ ++ if (count < sizeof(request->ct_iu)) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru CT buffer insufficient size %ld...\n", count)); ++ goto ct_error0; ++ } ++ ++ if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru CT request is already progress\n")); ++ goto ct_error0; ++ } ++ ++ if (qla2x00_mgmt_svr_login(ha)) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru CT request failed to login management server\n")); ++ goto ct_error0; ++ } ++ ++ ha->pass_thru_cmd_in_process = 1; ++ spin_lock_irqsave(&ha->hardware_lock, flags); ++ ++ ct_iocb = (void *)qla2x00_req_pkt(ha); ++ if (ct_iocb == NULL) { ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru CT request failed to get request packet\n")); ++ goto ct_error1; ++ } ++ ++ if (count > PAGE_SIZE) { ++ DEBUG2(qla_printk(KERN_INFO, ha, ++ "Passthru CT request excessive size %ld...\n", count)); ++ count = PAGE_SIZE; ++ } ++ ++ memset(ha->pass_thru, 0, PAGE_SIZE); ++ memcpy(ha->pass_thru, &request->ct_iu, count); ++ ++ ct_iocb->entry_type = CT_IOCB_TYPE; ++ ct_iocb->entry_count = 1; ++ ct_iocb->entry_status = 0; ++ ct_iocb->comp_status = __constant_cpu_to_le16(0); ++ ct_iocb->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); ++ ct_iocb->cmd_dsd_count = __constant_cpu_to_le16(1); ++ ct_iocb->vp_index = ha->vp_idx; ++ ct_iocb->timeout = __constant_cpu_to_le16(25); ++ ct_iocb->rsp_dsd_count = __constant_cpu_to_le16(1); ++ ct_iocb->rsp_byte_count = cpu_to_le32(PAGE_SIZE); ++ ct_iocb->cmd_byte_count = cpu_to_le32(count); ++ ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); ++ ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); ++ ct_iocb->dseg_0_len = ct_iocb->cmd_byte_count; ++ ct_iocb->dseg_1_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); ++ ct_iocb->dseg_1_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); ++ ct_iocb->dseg_1_len = ct_iocb->rsp_byte_count; ++ ++ wmb(); ++ qla2x00_isp_cmd(ha); ++ ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ qla2x00_wait_for_passthru_completion(ha); ++ ++ return count; ++ ++ct_error1: ++ ha->pass_thru_cmd_in_process = 0; ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ct_error0: ++ DEBUG2(qla_printk(KERN_WARNING, ha, ++ "Passthru CT failed on scsi(%ld)\n", ha->host_no)); ++ return 0; ++} ++ ++static struct bin_attribute sysfs_ct_attr = { ++ .attr = { ++ .name = "ct", ++ .mode = S_IRUSR | S_IWUSR, ++ .owner = THIS_MODULE, ++ }, ++ .size = 0, ++ .read = qla2x00_sysfs_read_ct, ++ .write = qla2x00_sysfs_write_ct, ++}; ++ + static struct sysfs_entry { + char *name; + struct bin_attribute *attr; +@@ -465,6 +746,8 @@ static struct sysfs_entry { + { "optrom_ctl", &sysfs_optrom_ctl_attr, }, + { "vpd", &sysfs_vpd_attr, 1 }, + { "sfp", &sysfs_sfp_attr, 1 }, ++ { "els", &sysfs_els_attr, 1 }, ++ { "ct", &sysfs_ct_attr, 1 }, + { NULL }, + }; + +@@ -797,6 +1080,27 @@ qla2x00_total_isp_aborts_show(struct device *dev, + ha->qla_stats.total_isp_aborts); + } + ++static ssize_t ++qla24xx_84xx_fw_version_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int rval = QLA_SUCCESS; ++ uint16_t status[2] = {0, 0}; ++ scsi_qla_host_t *ha = shost_priv(class_to_shost(dev)); ++ ++ if (IS_QLA84XX(ha) && ha->cs84xx) { ++ if (ha->cs84xx->op_fw_version == 0) { ++ rval = qla84xx_verify_chip(ha, status); ++ } ++ ++ if ((rval == QLA_SUCCESS) && (status[0] == 0)) ++ return snprintf(buf, PAGE_SIZE, "%u\n", ++ (uint32_t)ha->cs84xx->op_fw_version); ++ } ++ ++ return snprintf(buf, PAGE_SIZE, "\n"); ++} ++ + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); + static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); + static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); +@@ -821,6 +1125,8 @@ static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, + NULL); + static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, + NULL); ++static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, ++ NULL); + + struct device_attribute *qla2x00_host_attrs[] = { + &dev_attr_driver_version, +@@ -840,6 +1146,7 @@ struct device_attribute *qla2x00_host_attrs[] = { + &dev_attr_optrom_fcode_version, + &dev_attr_optrom_fw_version, + &dev_attr_total_isp_aborts, ++ &dev_attr_84xx_fw_version, + NULL, + }; + +diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h +index a45e333..851dc96 100644 +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -94,6 +94,89 @@ + #define LSD(x) ((uint32_t)((uint64_t)(x))) + #define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) + ++/* ELS PT request buffer = 32 bytes */ ++#define EXT_ELS_PT_REQ_WWPN_VALID 0x1 ++#define EXT_ELS_PT_REQ_WWNN_VALID 0x2 ++#define EXT_ELS_PT_REQ_PID_VALID 0x4 ++ ++struct ext_els_pt_req { ++ uint8_t WWNN[8]; ++ uint8_t WWPN[8]; ++ uint8_t Id[4]; ++ uint16_t ValidMask; ++ uint16_t Lid; ++ uint16_t Rxid; ++ uint16_t AccRjt; ++ uint32_t Reserved; ++}; ++ ++/* CT IU */ ++struct ct_iu { ++ uint8_t revision; ++ uint8_t in_id[3]; ++ uint8_t gs_type; ++ uint8_t gs_subtype; ++ uint8_t options; ++ uint8_t reserved0; ++ uint16_t command; ++ uint16_t max_rsp_size; ++ uint8_t fragment_id; ++ uint8_t reserved1[3]; ++}; ++ ++/* CT request format */ ++struct fc_ct_request { ++ struct ct_iu ct_iu; ++ union { ++ struct { ++ uint8_t reserved; ++ uint8_t port_id[3]; ++ } port_id; ++ ++ struct { ++ uint8_t port_type; ++ uint8_t domain; ++ uint8_t area; ++ uint8_t reserved; ++ } gid_pt; ++ ++ struct { ++ uint8_t reserved; ++ uint8_t port_id[3]; ++ uint8_t fc4_types[32]; ++ } rft_id; ++ ++ struct { ++ uint8_t reserved; ++ uint8_t port_id[3]; ++ uint16_t reserved2; ++ uint8_t fc4_feature; ++ uint8_t fc4_type; ++ } rff_id; ++ ++ struct { ++ uint8_t reserved; ++ uint8_t port_id[3]; ++ uint8_t node_name[8]; ++ } rnn_id; ++ ++ struct { ++ uint8_t node_name[8]; ++ uint8_t name_len; ++ uint8_t sym_node_name[255]; ++ } rsnn_nn; ++ ++ struct { ++ uint8_t hba_indentifier[8]; ++ } ghat; ++ } extended; ++}; ++ ++/* ELS request format */ ++struct els_request { ++ struct ext_els_pt_req header; ++ struct ct_iu ct_iu; ++}; + + /* + * I/O register +@@ -2161,6 +2244,14 @@ struct qla_statistics { + uint64_t output_bytes; + }; + ++#include "qla_nlnk.h" ++/* place holder for fw buffer parameters for netlink */ ++struct qlfc_fw { ++ void *fw_buf; ++ dma_addr_t fw_dma; ++ uint32_t len; ++}; ++ + /* + * Linux Host Adapter structure + */ +@@ -2426,6 +2517,8 @@ typedef struct scsi_qla_host { + /* SNS command interfaces for 2200. */ + struct sns_cmd_pkt *sns_cmd; + dma_addr_t sns_cmd_dma; ++ char *pass_thru; ++ dma_addr_t pass_thru_dma; + + #define SFP_DEV_SIZE 256 + #define SFP_BLOCK_SIZE 64 +@@ -2467,6 +2560,7 @@ typedef struct scsi_qla_host { + struct mutex vport_lock; /* Virtual port synchronization */ + struct completion mbx_cmd_comp; /* Serialize mbx access */ + struct completion mbx_intr_comp; /* Used for completion notification */ ++ struct completion pass_thru_intr_comp; /* For pass thru notification */ + + uint32_t mbx_flags; + #define MBX_IN_PROGRESS BIT_0 +@@ -2608,8 +2702,13 @@ typedef struct scsi_qla_host { + uint16_t max_npiv_vports; /* 63 or 125 per topoloty */ + int cur_vport_count; + ++ /* pass throuth support */ ++ int pass_thru_cmd_result; ++ int pass_thru_cmd_in_process; ++ + struct qla_chip_state_84xx *cs84xx; + struct qla_statistics qla_stats; ++ struct qlfc_fw fw_buf; + } scsi_qla_host_t; + + +diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h +index d1d1420..0ccf534 100644 +--- a/drivers/scsi/qla2xxx/qla_fw.h ++++ b/drivers/scsi/qla2xxx/qla_fw.h +@@ -1212,9 +1212,10 @@ struct qla_fdt_layout { + + struct qla_flt_location { + uint8_t sig[4]; +- uint32_t start_lo; +- uint32_t start_hi; +- uint16_t unused; ++ uint16_t start_lo; ++ uint16_t start_hi; ++ uint8_t version; ++ uint8_t unused[5]; + uint16_t checksum; + }; + +diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h +index 753dbe6..de1efc6 100644 +--- a/drivers/scsi/qla2xxx/qla_gbl.h ++++ b/drivers/scsi/qla2xxx/qla_gbl.h +@@ -121,6 +121,8 @@ extern int qla2x00_start_scsi(srb_t *sp); + extern int qla24xx_start_scsi(srb_t *sp); + int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); + int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); ++extern request_t *qla2x00_req_pkt(scsi_qla_host_t *); ++extern void qla2x00_isp_cmd(scsi_qla_host_t *ha); + + /* + * Global Function Prototypes in qla_mbx.c source file. +@@ -154,6 +156,10 @@ extern int + qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); + + extern int ++qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t, ++ uint32_t); ++ ++extern int + qla2x00_abort_command(scsi_qla_host_t *, srb_t *); + + extern int +@@ -258,6 +264,8 @@ qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); + + extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); + ++extern int qla84xx_reset(struct scsi_qla_host *, uint32_t); ++ + /* + * Global Function Prototypes in qla_isr.c source file. + */ +@@ -327,6 +335,8 @@ extern void qla24xx_fw_dump(scsi_qla_host_t *, int); + extern void qla25xx_fw_dump(scsi_qla_host_t *, int); + extern void qla2x00_dump_regs(scsi_qla_host_t *); + extern void qla2x00_dump_buffer(uint8_t *, uint32_t); ++extern void qla2x00_print_byte_buf(void *, size_t, size_t); ++extern void qla2x00_print_word_buf(void *, size_t, size_t); + + /* + * Global Function Prototypes in qla_gs.c source file. +@@ -347,6 +357,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *); + extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); + extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); + extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *); ++extern int qla2x00_mgmt_svr_login(scsi_qla_host_t *); + + /* + * Global Function Prototypes in qla_attr.c source file. +@@ -363,6 +374,13 @@ extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); + extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); + + /* ++ * Global functions in qla_nlk.c ++ */ ++extern int ql_nl_register(void); ++extern void ql_nl_unregister(void); ++extern void qla_free_nlnk_dmabuf(scsi_qla_host_t *); ++ ++/* + * Global Function Prototypes in qla_dfs.c source file. + */ + extern int qla2x00_dfs_setup(scsi_qla_host_t *); +diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c +index c2a4bfb..ceef231 100644 +--- a/drivers/scsi/qla2xxx/qla_gs.c ++++ b/drivers/scsi/qla2xxx/qla_gs.c +@@ -1093,7 +1093,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha) + * + * Returns 0 on success. + */ +-static int ++int + qla2x00_mgmt_svr_login(scsi_qla_host_t *ha) + { + int ret; +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index ad2dd8c..407e87a 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -1241,8 +1241,11 @@ qla2x00_init_rings(scsi_qla_host_t *ha) + + DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); + +- if (ha->flags.npiv_supported) ++ if (ha->flags.npiv_supported) { ++ if (ha->operating_mode == LOOP) ++ ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; + mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); ++ } + + mid_init_cb->options = __constant_cpu_to_le16(BIT_1); + +diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c +index 85bc0a4..352517d 100644 +--- a/drivers/scsi/qla2xxx/qla_iocb.c ++++ b/drivers/scsi/qla2xxx/qla_iocb.c +@@ -11,8 +11,6 @@ + + #include + +-static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); +-static void qla2x00_isp_cmd(scsi_qla_host_t *ha); + + /** + * qla2x00_get_cmd_direction() - Determine control_flag data direction. +@@ -476,7 +474,7 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, + * + * Returns NULL if function failed, else, a pointer to the request packet. + */ +-static request_t * ++request_t * + qla2x00_req_pkt(scsi_qla_host_t *ha) + { + device_reg_t __iomem *reg = ha->iobase; +@@ -546,7 +544,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) + * + * Note: The caller must hold the hardware lock before calling this routine. + */ +-static void ++void + qla2x00_isp_cmd(scsi_qla_host_t *ha) + { + device_reg_t __iomem *reg = ha->iobase; +diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c +index a76efd9..758d0ee 100644 +--- a/drivers/scsi/qla2xxx/qla_isr.c ++++ b/drivers/scsi/qla2xxx/qla_isr.c +@@ -1443,6 +1443,27 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha) + case STATUS_CONT_TYPE: + qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); + break; ++ case MS_IOCB_TYPE: ++ if (ha->pass_thru_cmd_result) ++ DEBUG2(qla_printk(KERN_INFO, ha, ++ "Passthru cmd result on.\n")); ++ if (!ha->pass_thru_cmd_in_process) ++ DEBUG2(qla_printk(KERN_INFO, ha, ++ "Passthru in process off.\n")); ++ ++ ha->pass_thru_cmd_result = 1; ++ complete(&ha->pass_thru_intr_comp); ++ break; ++ case ELS_IOCB_TYPE: ++ if (ha->pass_thru_cmd_result) ++ DEBUG2(qla_printk(KERN_INFO, ha, ++ "Passthru cmd result on.\n")); ++ if (!ha->pass_thru_cmd_in_process) ++ DEBUG2(qla_printk(KERN_INFO, ha, ++ "Passthru in process off.\n")); ++ ++ ha->pass_thru_cmd_result = 1; ++ complete(&ha->pass_thru_intr_comp); + case VP_RPT_ID_IOCB_TYPE: + qla24xx_report_id_acquisition(ha, + (struct vp_rpt_id_entry_24xx *)pkt); +diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c +index 3402746..9d78629 100644 +--- a/drivers/scsi/qla2xxx/qla_mbx.c ++++ b/drivers/scsi/qla2xxx/qla_mbx.c +@@ -681,7 +681,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) + * Context: + * Kernel context. + */ +-static int ++int + qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer, + dma_addr_t phys_addr, size_t size, uint32_t tov) + { +@@ -2946,6 +2946,33 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, + + /* 84XX Support **************************************************************/ + ++/* ++ * qla84xx_reset ++ * Resets the QLA8432 ++ */ ++int ++qla84xx_reset(struct scsi_qla_host *ha, uint32_t diag_fw) ++{ ++ int rval; ++ mbx_cmd_t mc; ++ mbx_cmd_t *mcp = &mc; ++ ++ mcp->mb[0] = MBC_ISP84XX_RESET; ++ mcp->mb[1] = diag_fw; ++ mcp->out_mb = MBX_1 | MBX_0; ++ mcp->in_mb = MBX_1 | MBX_0; ++ mcp->tov = MBX_TOV_SECONDS; ++ mcp->flags = 0; ++ ++ rval = qla2x00_mailbox_command(ha, mcp); ++ ++ if (rval != QLA_SUCCESS) ++ DEBUG2_16(printk("%s(%ld): failed mb[0]=0x%x mb[1]=0x%x\n", ++ __func__, ha->host_no, mcp->mb[0], mcp->mb[1])); ++ ++ return (rval); ++} ++ + struct cs84xx_mgmt_cmd { + union { + struct verify_chip_entry_84xx req; +diff --git a/drivers/scsi/qla2xxx/qla_nlnk.c b/drivers/scsi/qla2xxx/qla_nlnk.c +new file mode 100644 +index 0000000..2ab339d +--- /dev/null ++++ b/drivers/scsi/qla2xxx/qla_nlnk.c +@@ -0,0 +1,434 @@ ++/* ++ * QLogic Fibre Channel HBA Driver ++ * Copyright (c) 2003-2005 QLogic Corporation ++ * ++ * See LICENSE.qla2xxx for copyright and licensing details. ++ */ ++ ++#include "qla_def.h" ++#include ++#include ++#include "qla_nlnk.h" ++ ++static struct sock *ql_fc_nl_sock = NULL; ++static int ql_fc_nl_event(struct notifier_block *this, ++ unsigned long event, void *ptr); ++ ++static struct notifier_block ql_fc_nl_notifier = { ++ .notifier_call = ql_fc_nl_event, ++}; ++ ++/* ++ * local functions ++ */ ++static int ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, ++ struct nlmsghdr *nlh, int rcvlen); ++static int ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, ++ void *hdr, int hdr_len, void *payload, int size); ++ ++static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen, ++ struct msg_update_fw *upd_fw) ++{ ++ struct qlfc_fw *qlfw; ++ struct verify_chip_entry_84xx *mn; ++ dma_addr_t mn_dma; ++ int ret = 0; ++ uint32_t fw_ver; ++ uint16_t options; ++ ++ if (rlen < (sizeof(struct msg_update_fw) + upd_fw->len + ++ offsetof(struct qla_fc_msg, u))){ ++ DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid len\n", ++ __func__, ha->host_no)); ++ return -EINVAL; ++ } ++ ++ qlfw = &ha->fw_buf; ++ if (!upd_fw->offset) { ++ if (qlfw->fw_buf || !upd_fw->fw_len || ++ upd_fw->len > upd_fw->fw_len) { ++ DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid offset or " ++ "fw_len\n", __func__, ha->host_no)); ++ return -EINVAL; ++ } else { ++ qlfw->fw_buf = dma_alloc_coherent(&ha->pdev->dev, ++ upd_fw->fw_len, &qlfw->fw_dma, ++ GFP_KERNEL); ++ if (qlfw->fw_buf == NULL) { ++ DEBUG2_16(printk(KERN_ERR "%s: dma alloc " ++ "failed%lu\n", __func__, ha->host_no)); ++ return (-ENOMEM); ++ } ++ qlfw->len = upd_fw->fw_len; ++ } ++ fw_ver = le32_to_cpu(*((uint32_t *) ++ ((uint32_t *)upd_fw->fw_bytes + 2))); ++ if (!fw_ver) { ++ DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid fw " ++ "revision 0x%x\n", __func__, ha->host_no, fw_ver)); ++ return -EINVAL; ++ } ++ } else { ++ /* make sure we have a buffer allocated */ ++ if (!qlfw->fw_buf || upd_fw->fw_len != qlfw->len || ++ ((upd_fw->offset + upd_fw->len) > upd_fw->fw_len)){ ++ DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid size of " ++ "offset=0 expected\n", __func__, ha->host_no)); ++ return -EINVAL; ++ } ++ } ++ /* Copy the firmware into DMA Buffer */ ++ memcpy(((uint8_t *)qlfw->fw_buf + upd_fw->offset), ++ upd_fw->fw_bytes, upd_fw->len); ++ ++ if ((upd_fw->offset+upd_fw->len) != qlfw->len) ++ return 0; ++ ++ mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); ++ if (mn == NULL) { ++ DEBUG2_16(printk(KERN_ERR "%s: dma alloc for fw buffer " ++ "failed%lu\n", __func__, ha->host_no)); ++ return -ENOMEM; ++ } ++ ++ fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)qlfw->fw_buf + 2))); ++ ++ /* Create iocb and issue it */ ++ memset(mn, 0, sizeof(*mn)); ++ ++ mn->entry_type = VERIFY_CHIP_IOCB_TYPE; ++ mn->entry_count = 1; ++ ++ options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; ++ if (upd_fw->diag_fw) ++ options |= VCO_DIAG_FW; ++ mn->options = cpu_to_le16(options); ++ ++ mn->fw_ver = cpu_to_le32(fw_ver); ++ mn->fw_size = cpu_to_le32(qlfw->len); ++ mn->fw_seq_size = cpu_to_le32(qlfw->len); ++ ++ mn->dseg_address[0] = cpu_to_le32(LSD(qlfw->fw_dma)); ++ mn->dseg_address[1] = cpu_to_le32(MSD(qlfw->fw_dma)); ++ mn->dseg_length = cpu_to_le32(qlfw->len); ++ mn->data_seg_cnt = cpu_to_le16(1); ++ ++ ret = qla2x00_issue_iocb_timeout(ha, mn, mn_dma, 0, 120); ++ ++ if (ret != QLA_SUCCESS) { ++ DEBUG2_16(printk(KERN_ERR "%s(%lu): failed\n", __func__, ++ ha->host_no)); ++ } ++ ++ qla_free_nlnk_dmabuf(ha); ++ return ret; ++} ++ ++static int ++qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen, ++ uint32_t pid, uint32_t seq, uint32_t type) ++{ ++ struct access_chip_84xx *mn; ++ dma_addr_t mn_dma, mgmt_dma; ++ void *mgmt_b = NULL; ++ int ret = 0; ++ int rsp_hdr_len, len = 0; ++ struct qla84_msg_mgmt *ql84_mgmt; ++ ++ ql84_mgmt = &cmd->u.utok.mgmt; ++ rsp_hdr_len = offsetof(struct qla_fc_msg, u) + ++ offsetof(struct qla84_msg_mgmt, payload); ++ ++ mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); ++ if (mn == NULL) { ++ DEBUG2_16(printk(KERN_ERR "%s: dma alloc for fw buffer " ++ "failed%lu\n", __FUNCTION__, ha->host_no)); ++ return (-ENOMEM); ++ } ++ ++ memset(mn, 0, sizeof (struct access_chip_84xx)); ++ ++ mn->entry_type = ACCESS_CHIP_IOCB_TYPE; ++ mn->entry_count = 1; ++ ++ switch (ql84_mgmt->cmd) { ++ case QLA84_MGMT_READ_MEM: ++ mn->options = cpu_to_le16(ACO_DUMP_MEMORY); ++ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); ++ break; ++ case QLA84_MGMT_WRITE_MEM: ++ if (rlen < (sizeof(struct qla84_msg_mgmt) + ql84_mgmt->len + ++ offsetof(struct qla_fc_msg, u))){ ++ ret = -EINVAL; ++ goto exit_mgmt0; ++ } ++ mn->options = cpu_to_le16(ACO_LOAD_MEMORY); ++ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); ++ break; ++ case QLA84_MGMT_CHNG_CONFIG: ++ mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); ++ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); ++ mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); ++ mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); ++ break; ++ case QLA84_MGMT_GET_INFO: ++ mn->options = cpu_to_le16(ACO_REQUEST_INFO); ++ mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); ++ mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); ++ break; ++ default: ++ ret = -EIO; ++ goto exit_mgmt0; ++ } ++ ++ if ((len = ql84_mgmt->len) && ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { ++ mgmt_b = dma_alloc_coherent(&ha->pdev->dev, len, ++ &mgmt_dma, GFP_KERNEL); ++ if (mgmt_b == NULL) { ++ DEBUG2_16(printk(KERN_ERR "%s: dma alloc mgmt_b " ++ "failed%lu\n", __func__, ha->host_no)); ++ ret = -ENOMEM; ++ goto exit_mgmt0; ++ } ++ mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); ++ mn->dseg_count = cpu_to_le16(1); ++ mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); ++ mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); ++ mn->dseg_length = cpu_to_le32(len); ++ ++ if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { ++ memcpy(mgmt_b, ql84_mgmt->payload, len); ++ } ++ } ++ ++ ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); ++ cmd->error = ret; ++ ++ if ((ret != QLA_SUCCESS) || ++ (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) || ++ (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { ++ if (ret != QLA_SUCCESS) ++ DEBUG2_16(printk(KERN_ERR "%s(%lu): failed\n", ++ __func__, ha->host_no)); ++ ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, NULL, 0); ++ } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM)|| ++ (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { ++ ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, mgmt_b, len); ++ } ++ ++ if (mgmt_b) ++ dma_free_coherent(&ha->pdev->dev, len, mgmt_b, mgmt_dma); ++ ++exit_mgmt0: ++ dma_pool_free(ha->s_dma_pool, mn, mn_dma); ++ return ret; ++} ++ ++/* ++ * Netlink Interface Related Functions ++ */ ++ ++static void ++ql_fc_nl_rcv_msg(struct sk_buff *skb) ++{ ++ struct nlmsghdr *nlh; ++ struct scsi_nl_hdr *snlh; ++ uint32_t rlen; ++ int err; ++ ++ while (skb->len >= NLMSG_SPACE(0)) { ++ err = 0; ++ ++ nlh = (struct nlmsghdr *) skb->data; ++ ++ if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*snlh))) || ++ (skb->len < nlh->nlmsg_len)) { ++ DEBUG2_16(printk(KERN_WARNING "%s: discarding partial " ++ "skb\n", __FUNCTION__)); ++ break; ++ } ++ ++ rlen = NLMSG_ALIGN(nlh->nlmsg_len); ++ if (rlen > skb->len) { ++ DEBUG2_16(printk(KERN_WARNING "%s: rlen > skb->len\n", ++ __FUNCTION__)); ++ rlen = skb->len; ++ } ++ ++ if (nlh->nlmsg_type != FC_TRANSPORT_MSG) { ++ DEBUG2_16(printk(KERN_WARNING "%s: Not " ++ "FC_TRANSPORT_MSG\n", __FUNCTION__)); ++ err = -EBADMSG; ++ goto next_msg; ++ } ++ ++ snlh = NLMSG_DATA(nlh); ++ if ((snlh->version != SCSI_NL_VERSION) || ++ (snlh->magic != SCSI_NL_MAGIC)) { ++ DEBUG2_16(printk(KERN_WARNING "%s: Bad Version or " ++ "Magic number\n", __FUNCTION__)); ++ err = -EPROTOTYPE; ++ goto next_msg; ++ } ++ err = ql_fc_proc_nl_rcv_msg(skb, nlh, rlen); ++next_msg: ++ if (err) ++ netlink_ack(skb, nlh, err); ++ skb_pull(skb, rlen); ++ } ++} ++ ++static int ++ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int rcvlen) ++{ ++ struct scsi_nl_hdr *snlh; ++ struct qla_fc_msg *ql_cmd; ++ struct Scsi_Host *shost; ++ struct scsi_qla_host *ha; ++ int err = 0; ++ int rsp_hdr_len; ++ ++ snlh = NLMSG_DATA(nlh); ++ ++ /* Only vendor specific commands are supported */ ++ if (!(snlh->msgtype & FC_NL_VNDR_SPECIFIC)) ++ return -EBADMSG; ++ ++ ql_cmd = (struct qla_fc_msg *)((char *)snlh + sizeof (struct scsi_nl_hdr)); ++ ++ if (ql_cmd->magic != QL_FC_NL_MAGIC) ++ return -EBADMSG; ++ ++ shost = scsi_host_lookup(ql_cmd->host_no); ++ if (IS_ERR(shost)) { ++ DEBUG2_16(printk(KERN_ERR "%s: could not find host no %u\n", ++ __FUNCTION__, ql_cmd->host_no)); ++ err = -ENODEV; ++ goto exit_proc_nl_rcv_msg; ++ } ++ ++ ha = (struct scsi_qla_host *)shost->hostdata; ++ ++ if (!ha || (!IS_QLA84XX(ha) && (ql_cmd->cmd != QLFC_GET_AEN))) { ++ DEBUG2_16(printk(KERN_ERR "%s: invalid host ha = %p dtype = " ++ "0x%x\n", __FUNCTION__, ha, (ha ? DT_MASK(ha): ~0))); ++ err = -ENODEV; ++ goto exit_proc_nl_rcv_msg; ++ } ++ ++ switch (ql_cmd->cmd) { ++ ++ case QLA84_RESET: ++ ++ rsp_hdr_len = offsetof(struct qla_fc_msg, u); ++ err = qla84xx_reset(ha, ql_cmd->u.utok.qla84_reset.diag_fw); ++ ql_cmd->error = err; ++ ++ err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, ++ (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0); ++ break; ++ ++ case QLA84_UPDATE_FW: ++ rsp_hdr_len = offsetof(struct qla_fc_msg, u); ++ err = qla84xx_update_fw(ha, (rcvlen - sizeof(struct scsi_nl_hdr)), ++ &ql_cmd->u.utok.qla84_update_fw); ++ ql_cmd->error = err; ++ ++ err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, ++ (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0); ++ break; ++ ++ case QLA84_MGMT_CMD: ++ err = qla84xx_mgmt_cmd(ha, ql_cmd, ++ (rcvlen - sizeof(struct scsi_nl_hdr)), ++ NETLINK_CREDS(skb)->pid, ++ nlh->nlmsg_seq, (uint32_t)nlh->nlmsg_type); ++ break; ++ default: ++ err = -EBADMSG; ++ } ++ ++exit_proc_nl_rcv_msg: ++ return err; ++} ++ ++static int ++ql_fc_nl_event(struct notifier_block *this, unsigned long event, void *ptr) ++{ ++ DEBUG16(printk(KERN_WARNING "%s: event 0x%lx ptr = %p\n", __func__, ++ event, ptr)); ++ return NOTIFY_DONE; ++} ++ ++static int ++ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, void *hdr, int hdr_len, ++ void *payload, int size) ++{ ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ int rc; ++ int len = NLMSG_SPACE(size + hdr_len); ++ ++ skb = alloc_skb(len, GFP_ATOMIC); ++ if (!skb) { ++ DEBUG2_16(printk(KERN_ERR "%s: Could not alloc skb\n", ++ __func__)); ++ return -ENOMEM; ++ } ++ nlh = __nlmsg_put(skb, pid, seq, type, (len - sizeof(*nlh)), 0); ++ nlh->nlmsg_flags = 0; ++ memcpy(NLMSG_DATA(nlh), hdr, hdr_len); ++ ++ if (payload) ++ memcpy((void *)((char *)(NLMSG_DATA(nlh)) + hdr_len), payload, size); ++ ++ rc = netlink_unicast(ql_fc_nl_sock, skb, pid, MSG_DONTWAIT); ++ if (rc < 0) { ++ DEBUG2_16(printk(KERN_ERR "%s: netlink_unicast failed\n", ++ __func__)); ++ return rc; ++ } ++ return 0; ++} ++ ++void qla_free_nlnk_dmabuf(scsi_qla_host_t *ha) ++{ ++ struct qlfc_fw *qlfw; ++ ++ qlfw = &ha->fw_buf; ++ ++ if (qlfw->fw_buf) { ++ dma_free_coherent(&ha->pdev->dev, qlfw->len, qlfw->fw_buf, ++ qlfw->fw_dma); ++ memset(qlfw, 0, sizeof(struct qlfc_fw)); ++ } ++} ++ ++int ++ql_nl_register(void) ++{ ++ int error = 0; ++ ++ error = netlink_register_notifier(&ql_fc_nl_notifier); ++ if (!error) { ++ ++ ql_fc_nl_sock = netlink_kernel_create(&init_net, ++ NETLINK_FCTRANSPORT, QL_FC_NL_GROUP_CNT, ql_fc_nl_rcv_msg, ++ NULL, THIS_MODULE); ++ ++ if (!ql_fc_nl_sock) { ++ netlink_unregister_notifier(&ql_fc_nl_notifier); ++ error = -ENODEV; ++ } ++ } ++ return (error); ++} ++ ++void ++ql_nl_unregister() ++{ ++ if (ql_fc_nl_sock) { ++ sock_release(ql_fc_nl_sock->sk_socket); ++ netlink_unregister_notifier(&ql_fc_nl_notifier); ++ } ++} +diff --git a/drivers/scsi/qla2xxx/qla_nlnk.h b/drivers/scsi/qla2xxx/qla_nlnk.h +new file mode 100644 +index 0000000..d1488a6 +--- /dev/null ++++ b/drivers/scsi/qla2xxx/qla_nlnk.h +@@ -0,0 +1,168 @@ ++/* ++ * QLogic Fibre Channel HBA Driver ++ * Copyright (c) 2003-2005 QLogic Corporation ++ * ++ * See LICENSE.qla2xxx for copyright and licensing details. ++ */ ++#ifndef _QLA_NLNK_H_ ++#define _QLA_NLNK_H_ ++ ++#ifndef NETLINK_FCTRANSPORT ++#define NETLINK_FCTRANSPORT 20 ++#endif ++#define QL_FC_NL_GROUP_CNT 0 ++ ++#define FC_TRANSPORT_MSG NLMSG_MIN_TYPE + 1 ++ ++/* ++ * Transport Message Types ++ */ ++#define FC_NL_VNDR_SPECIFIC 0x8000 ++ ++/* ++ * Structures ++ */ ++ ++struct qla84_mgmt_param { ++ union { ++ struct { ++ uint32_t start_addr; ++ } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ ++ struct { ++ uint32_t id; ++#define QLA84_MGMT_CONFIG_ID_UIF 1 ++#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 ++#define QLA84_MGMT_CONFIG_ID_PAUSE 3 ++#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 ++ ++ uint32_t param0; ++ uint32_t param1; ++ } config; /* for QLA84_MGMT_CHNG_CONFIG */ ++ ++ struct { ++ uint32_t type; ++#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ ++#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ ++#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ ++#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ ++#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ ++#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ ++#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ ++ ++ uint32_t context; ++/* ++ * context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA ++ */ ++#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 ++#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 ++#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 ++#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 ++#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 ++#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 ++#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 ++#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 ++#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 ++#define IC_LOG_DATA_LOG_ID_DCX_LOG 9 ++ ++/* ++ * context definitions for QLA84_MGMT_INFO_PORT_STAT ++ */ ++#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 ++#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 ++#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 ++#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 ++#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 ++#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 ++ ++ ++/* ++ * context definitions for QLA84_MGMT_INFO_LIF_STAT ++ */ ++#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 ++#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 ++#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 ++#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 ++#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 ++ ++ } info; /* for QLA84_MGMT_GET_INFO */ ++ } u; ++}; ++ ++#define QLFC_MAX_AEN 256 ++struct qlfc_aen_entry { ++ uint16_t event_code; ++ uint16_t payload[3]; ++}; ++ ++struct qlfc_aen_log { ++ uint32_t num_events; ++ struct qlfc_aen_entry aen[QLFC_MAX_AEN]; ++}; ++ ++struct qla84_msg_mgmt { ++ uint16_t cmd; ++#define QLA84_MGMT_READ_MEM 0x00 ++#define QLA84_MGMT_WRITE_MEM 0x01 ++#define QLA84_MGMT_CHNG_CONFIG 0x02 ++#define QLA84_MGMT_GET_INFO 0x03 ++ uint16_t rsrvd; ++ struct qla84_mgmt_param mgmtp;/* parameters for cmd */ ++ uint32_t len; /* bytes in payload following this struct */ ++ uint8_t payload[0]; /* payload for cmd */ ++}; ++ ++struct msg_update_fw { ++ /* ++ * diag_fw = 0 operational fw ++ * otherwise diagnostic fw ++ * offset, len, fw_len are present to overcome the current limitation ++ * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk ++ * specifies the byte "offset" where it fits in the fw buffer. The ++ * number of bytes in each chunk is specified in "len". "fw_len" ++ * is the total size of fw. The first chunk should start at offset = 0. ++ * When offset+len == fw_len, the fw is written to the HBA. ++ */ ++ uint32_t diag_fw; ++ uint32_t offset;/* start offset */ ++ uint32_t len; /* num bytes in cur xfer */ ++ uint32_t fw_len; /* size of fw in bytes */ ++ uint8_t fw_bytes[0]; ++}; ++ ++struct qla_fc_msg { ++ ++ uint64_t magic; ++#define QL_FC_NL_MAGIC 0x107784DDFCAB1FC1 ++ uint16_t host_no; ++ uint16_t vmsg_datalen; ++ ++ uint32_t cmd; ++#define QLA84_RESET 0x01 ++#define QLA84_UPDATE_FW 0x02 ++#define QLA84_MGMT_CMD 0x03 ++#define QLFC_GET_AEN 0x04 ++ ++ uint32_t error; /* interface or resource error holder*/ ++ ++ union { ++ union { ++ struct msg_reset { ++ /* ++ * diag_fw = 0 for operational fw ++ * otherwise diagnostic fw ++ */ ++ uint32_t diag_fw; ++ } qla84_reset; ++ ++ struct msg_update_fw qla84_update_fw; ++ struct qla84_msg_mgmt mgmt; ++ } utok; ++ ++ union { ++ struct qla84_msg_mgmt mgmt; ++ struct qlfc_aen_log aen_log; ++ } ktou; ++ } u; ++} __attribute__ ((aligned (sizeof(uint64_t)))); ++ ++#endif /* _QLA_NLNK_H_ */ +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 4774acb..70d03a8 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -1670,6 +1670,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + init_completion(&ha->mbx_cmd_comp); + complete(&ha->mbx_cmd_comp); + init_completion(&ha->mbx_intr_comp); ++ init_completion(&ha->pass_thru_intr_comp); + + INIT_LIST_HEAD(&ha->list); + INIT_LIST_HEAD(&ha->fcports); +@@ -1790,6 +1791,8 @@ qla2x00_remove_one(struct pci_dev *pdev) + + qla2x00_free_sysfs_attr(ha); + ++ qla_free_nlnk_dmabuf(ha); ++ + fc_remove_host(ha->host); + + scsi_remove_host(ha->host); +@@ -2020,10 +2023,19 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) + sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); + if (!ha->ct_sns) + goto fail_free_ms_iocb; ++ /*Get consistent memory allocated for pass-thru commands */ ++ ha->pass_thru = dma_alloc_coherent(&ha->pdev->dev, ++ PAGE_SIZE, &ha->pass_thru_dma, GFP_KERNEL); ++ if (!ha->pass_thru) ++ goto fail_free_ct_sns; + } + + return 0; + ++fail_free_ct_sns: ++ dma_pool_free(ha->s_dma_pool, ha->ct_sns, ha->ct_sns_dma); ++ ha->ct_sns = NULL; ++ ha->ct_sns_dma = 0; + fail_free_ms_iocb: + dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); + ha->ms_iocb = NULL; +@@ -2092,6 +2104,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha) + dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), + ha->sns_cmd, ha->sns_cmd_dma); + ++ if (ha->pass_thru) ++ dma_free_coherent(&ha->pdev->dev, PAGE_SIZE, ++ ha->pass_thru, ha->pass_thru_dma); ++ + if (ha->ct_sns) + dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), + ha->ct_sns, ha->ct_sns_dma); +@@ -2130,6 +2146,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) + ha->sns_cmd_dma = 0; + ha->ct_sns = NULL; + ha->ct_sns_dma = 0; ++ ha->pass_thru = NULL; ++ ha->pass_thru_dma = 0; + ha->ms_iocb = NULL; + ha->ms_iocb_dma = 0; + ha->init_cb = NULL; +@@ -2903,10 +2921,18 @@ qla2x00_module_init(void) + return -ENODEV; + } + ++ if (ql_nl_register()) { ++ kmem_cache_destroy(srb_cachep); ++ fc_release_transport(qla2xxx_transport_template); ++ fc_release_transport(qla2xxx_transport_vport_template); ++ return -ENODEV; ++ } ++ + printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n", + qla2x00_version_str); + ret = pci_register_driver(&qla2xxx_pci_driver); + if (ret) { ++ ql_nl_unregister(); + kmem_cache_destroy(srb_cachep); + fc_release_transport(qla2xxx_transport_template); + fc_release_transport(qla2xxx_transport_vport_template); +@@ -2922,6 +2948,7 @@ qla2x00_module_exit(void) + { + pci_unregister_driver(&qla2xxx_pci_driver); + qla2x00_release_firmware(); ++ ql_nl_unregister(); + kmem_cache_destroy(srb_cachep); + fc_release_transport(qla2xxx_transport_template); + fc_release_transport(qla2xxx_transport_vport_template); +diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h +index eea6720..d88bb2c 100644 +--- a/drivers/scsi/qla2xxx/qla_version.h ++++ b/drivers/scsi/qla2xxx/qla_version.h +@@ -7,7 +7,7 @@ + /* + * Driver version + */ +-#define QLA2XXX_VERSION "8.02.01-k9" ++#define QLA2XXX_VERSION "8.02.01.02.11.0-k9" + + #define QLA_DRIVER_MAJOR_VER 8 + #define QLA_DRIVER_MINOR_VER 2 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-correct-endianness-issue-during-flash b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-correct-endianness-issue-during-flash new file mode 100644 index 000000000..7ce80caa1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-correct-endianness-issue-during-flash @@ -0,0 +1,48 @@ +From ccac18563cb9ba20a4afc722878804bcf2936170 Mon Sep 17 00:00:00 2001 +From: Andrew Vasquez +Date: Mon, 16 Feb 2009 08:19:31 -0800 +Subject: qla2xxx: Correct endianness issue during flash manipulation. +References: bnc#476206 + +The flash data was incorrectly being converted (cpu_to_le32()) +when using the bulk-flash-write mailbox command (ISP25xx and +above). + +Signed-off-by: Andrew Vasquez +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/qla2xxx/qla_sup.c | 7 ++----- + 1 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c +index 6729a39..a0b5ece 100644 +--- a/drivers/scsi/qla2xxx/qla_sup.c ++++ b/drivers/scsi/qla2xxx/qla_sup.c +@@ -957,12 +957,11 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, + uint32_t dwords) + { + int ret; +- uint32_t liter, miter; ++ uint32_t liter; + uint32_t sec_mask, rest_addr; + uint32_t fdata, findex; + dma_addr_t optrom_dma; + void *optrom = NULL; +- uint32_t *s, *d; + + ret = QLA_SUCCESS; + +@@ -1010,9 +1009,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, + /* Go with burst-write. */ + if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) { + /* Copy data to DMA'ble buffer. */ +- for (miter = 0, s = optrom, d = dwptr; +- miter < OPTROM_BURST_DWORDS; miter++, s++, d++) +- *s = cpu_to_le32(*d); ++ memcpy(optrom, dwptr, OPTROM_BURST_SIZE); + + ret = qla2x00_load_ram(ha, optrom_dma, + flash_data_to_access_addr(faddr), +-- +1.6.0.4.781.gf2070 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-eeh-recovery b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-eeh-recovery new file mode 100644 index 000000000..154961928 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-eeh-recovery @@ -0,0 +1,110 @@ +From: David Wagner +Subject: qla2xxx driver EEH unable to recover from injected PCI error +References: bnc#442923 + +qla2xxx driver EEH unable to recover from injected PCI errror. +Driver enters infinite EEH loop. +With this patch the qla2xxx driver survives andy PCI error injection +and properly terminates all commands. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/qla2xxx/qla_attr.c | 9 ++++++++- + drivers/scsi/qla2xxx/qla_mbx.c | 3 +++ + drivers/scsi/qla2xxx/qla_os.c | 14 +++++++++++--- + drivers/scsi/qla2xxx/qla_version.h | 2 +- + 4 files changed, 23 insertions(+), 5 deletions(-) + +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -1286,7 +1286,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rp + if (!fcport) + return; + +- qla2x00_abort_fcport_cmds(fcport); ++ if (unlikely(pci_channel_offline(fcport->ha->pdev))) ++ qla2x00_abort_all_cmds(fcport->ha, DID_NO_CONNECT << 16); ++ else ++ qla2x00_abort_fcport_cmds(fcport); + + /* + * Transport has effectively 'deleted' the rport, clear +@@ -1306,6 +1309,10 @@ qla2x00_terminate_rport_io(struct fc_rpo + if (!fcport) + return; + ++ if (unlikely(pci_channel_offline(fcport->ha->pdev))) { ++ qla2x00_abort_all_cmds(fcport->ha, DID_NO_CONNECT << 16); ++ return; ++ } + /* + * At this point all fcport's software-states are cleared. Perform any + * final cleanup of firmware resources (PCBs and XCBs). +--- a/drivers/scsi/qla2xxx/qla_mbx.c ++++ b/drivers/scsi/qla2xxx/qla_mbx.c +@@ -44,6 +44,9 @@ qla2x00_mailbox_command(scsi_qla_host_t + unsigned long wait_time; + scsi_qla_host_t *ha = to_qla_parent(pvha); + ++ if (ha->pdev->error_state == pci_channel_io_perm_failure) ++ return QLA_FUNCTION_TIMEOUT; ++ + reg = ha->iobase; + io_lock_on = ha->flags.init_done; + +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -391,7 +391,10 @@ qla2x00_queuecommand(struct scsi_cmnd *c + int rval; + + if (unlikely(pci_channel_offline(ha->pdev))) { +- cmd->result = DID_REQUEUE << 16; ++ if (ha->pdev->error_state == pci_channel_io_frozen) ++ cmd->result = DID_REQUEUE << 16; ++ else ++ cmd->result = DID_NO_CONNECT << 16; + goto qc_fail_command; + } + +@@ -457,7 +460,10 @@ qla24xx_queuecommand(struct scsi_cmnd *c + scsi_qla_host_t *pha = to_qla_parent(ha); + + if (unlikely(pci_channel_offline(pha->pdev))) { +- cmd->result = DID_REQUEUE << 16; ++ if (ha->pdev->error_state == pci_channel_io_frozen) ++ cmd->result = DID_REQUEUE << 16; ++ else ++ cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } + +@@ -2762,6 +2768,8 @@ qla2x00_release_firmware(void) + static pci_ers_result_t + qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) + { ++ scsi_qla_host_t *ha = pci_get_drvdata(pdev); ++ + switch (state) { + case pci_channel_io_normal: + return PCI_ERS_RESULT_CAN_RECOVER; +@@ -2769,7 +2777,7 @@ qla2xxx_pci_error_detected(struct pci_de + pci_disable_device(pdev); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: +- qla2x00_remove_one(pdev); ++ qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_NEED_RESET; +--- a/drivers/scsi/qla2xxx/qla_version.h ++++ b/drivers/scsi/qla2xxx/qla_version.h +@@ -7,7 +7,7 @@ + /* + * Driver version + */ +-#define QLA2XXX_VERSION "8.02.01.02.11.0-k9" ++#define QLA2XXX_VERSION "8.02.01.03.11.0-k9" + + #define QLA_DRIVER_MAJOR_VER 8 + #define QLA_DRIVER_MINOR_VER 2 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-extend-address-range-of-option-rom-update b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-extend-address-range-of-option-rom-update new file mode 100644 index 000000000..bf29f88fd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-extend-address-range-of-option-rom-update @@ -0,0 +1,39 @@ +From 7bb61cdff8715631deda859443d3a6650a1bbb28 Mon Sep 17 00:00:00 2001 +From: Andrew Vasquez +Date: Mon, 16 Feb 2009 07:27:09 -0800 +Subject: qla2xxx: Extend address range of option-rom update for recent ISPs +References: bnc#476206 + +Please consider this correction to option-rom +update handling. The issue is that applications will need +to update a larger address-range of the flash than was previously +allowed with earlier ISP parts. + +This will be important for customers such as IBM and HPQ to +allow their end-users to enable multi-queue facilities within +the field with inbox SLES11 drivers. + +Signed-off-by: Andrew Vasquez +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/qla2xxx/qla_attr.c | 3 +-- + 1 files changed, 1 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c +index 34c4016..ef9146f 100644 +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -295,8 +295,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, + else if (start == (ha->flt_region_boot * 4) || + start == (ha->flt_region_fw * 4)) + valid = 1; +- else if (IS_QLA25XX(ha) && +- start == (ha->flt_region_vpd_nvram * 4)) ++ else if (IS_QLA25XX(ha)) + valid = 1; + if (!valid) { + qla_printk(KERN_WARNING, ha, +-- +1.6.0.4.781.gf2070 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-5.01.00-k8_sles11-03-update b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-5.01.00-k8_sles11-03-update new file mode 100644 index 000000000..847c377e5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-5.01.00-k8_sles11-03-update @@ -0,0 +1,2360 @@ +From: David Somayajulu +Subject: Update qla4xxx to 5.01.00-k8_sles11-03 +References: bnc#444884 + +This patch updates the qla4xxx driver to 5.01.00-k8_sles11-03. + + +Signed-off-by: David Somayajulu +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/qla4xxx/ql4_dbg.c | 36 -- + drivers/scsi/qla4xxx/ql4_dbg.h | 59 ++-- + drivers/scsi/qla4xxx/ql4_def.h | 11 + drivers/scsi/qla4xxx/ql4_glbl.h | 10 + drivers/scsi/qla4xxx/ql4_init.c | 172 +++++++----- + drivers/scsi/qla4xxx/ql4_inline.h | 143 ++++++++++ + drivers/scsi/qla4xxx/ql4_iocb.c | 161 +---------- + drivers/scsi/qla4xxx/ql4_isr.c | 36 +- + drivers/scsi/qla4xxx/ql4_mbx.c | 11 + drivers/scsi/qla4xxx/ql4_os.c | 499 ++++++++++++++++++++----------------- + drivers/scsi/qla4xxx/ql4_os.h | 125 +++++++++ + drivers/scsi/qla4xxx/ql4_version.h | 3 + 12 files changed, 736 insertions(+), 530 deletions(-) + +--- a/drivers/scsi/qla4xxx/ql4_dbg.c ++++ b/drivers/scsi/qla4xxx/ql4_dbg.c +@@ -13,28 +13,6 @@ + + #include + +-static void qla4xxx_print_srb_info(struct srb * srb) +-{ +- printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags); +- printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n", +- __func__, srb->cmd, (unsigned long) srb->dma_handle); +- printk("%s: fw_ddb_index = %d, lun = %d\n", +- __func__, srb->fw_ddb_index, srb->cmd->device->lun); +- printk("%s: iocb_tov = %d\n", +- __func__, srb->iocb_tov); +- printk("%s: cc_stat = 0x%x\n", __func__, srb->cc_stat); +-} +- +-void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd) +-{ +- printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); +- printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n", +- cmd->device->channel, cmd->device->id, cmd->device->lun, +- cmd->cmd_len); +- scsi_print_command(cmd); +- qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr); +-} +- + void __dump_registers(struct scsi_qla_host *ha) + { + uint8_t i; +@@ -143,17 +121,6 @@ void __dump_registers(struct scsi_qla_ho + } + } + +-void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha) +-{ +- unsigned long flags = 0; +- int i = 0; +- spin_lock_irqsave(&ha->hardware_lock, flags); +- for (i = 1; i < MBOX_REG_COUNT; i++) +- printk(KERN_INFO " Mailbox[%d] = %08x\n", i, +- readw(&ha->reg->mailbox[i])); +- spin_unlock_irqrestore(&ha->hardware_lock, flags); +-} +- + void qla4xxx_dump_registers(struct scsi_qla_host *ha) + { + unsigned long flags = 0; +@@ -179,6 +146,5 @@ void qla4xxx_dump_buffer(void *b, uint32 + else + printk(KERN_DEBUG " "); + } +- if (cnt % 16) +- printk(KERN_DEBUG "\n"); ++ printk(KERN_DEBUG "\n"); + } +--- a/drivers/scsi/qla4xxx/ql4_dbg.h ++++ b/drivers/scsi/qla4xxx/ql4_dbg.h +@@ -14,49 +14,44 @@ + /* #define QL_DEBUG_LEVEL_5 */ + /* #define QL_DEBUG_LEVEL_6 */ + /* #define QL_DEBUG_LEVEL_9 */ ++#ifndef _QL4_DBG_ ++#define _QL4_DBG_ + + #define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */ + #if defined(QL_DEBUG) +-#define DEBUG(x) do {x;} while (0); ++#define DEBUG(x) do {if(extended_error_logging & 0x01) x;} while (0); + #else +-#define DEBUG(x) do {} while (0); ++#define DEBUG(x) + #endif + + #if defined(QL_DEBUG_LEVEL_2) +-#define DEBUG2(x) do {if(extended_error_logging == 2) x;} while (0); +-#define DEBUG2_3(x) do {x;} while (0); +-#else /* */ +-#define DEBUG2(x) do {} while (0); +-#endif /* */ ++#define DEBUG2(x) do {if(extended_error_logging & 0x02) x;} while (0); ++#else ++#define DEBUG2(x) ++#endif + + #if defined(QL_DEBUG_LEVEL_3) +-#define DEBUG3(x) do {if(extended_error_logging == 3) x;} while (0); +-#else /* */ +-#define DEBUG3(x) do {} while (0); +-#if !defined(QL_DEBUG_LEVEL_2) +-#define DEBUG2_3(x) do {} while (0); +-#endif /* */ +-#endif /* */ ++#define DEBUG3(x) do {if(extended_error_logging & 0x04) x;} while (0); ++#else ++#define DEBUG3(x) ++#endif ++ + #if defined(QL_DEBUG_LEVEL_4) +-#define DEBUG4(x) do {x;} while (0); +-#else /* */ +-#define DEBUG4(x) do {} while (0); +-#endif /* */ ++#define DEBUG4(x) do {if(extended_error_logging & 0x08) x;} while (0); ++#else ++#define DEBUG4(x) ++#endif + + #if defined(QL_DEBUG_LEVEL_5) +-#define DEBUG5(x) do {x;} while (0); +-#else /* */ +-#define DEBUG5(x) do {} while (0); +-#endif /* */ ++#define DEBUG5(x) do {if(extended_error_logging & 0x10) x;} while (0); ++#else ++#define DEBUG5(x) ++#endif + + #if defined(QL_DEBUG_LEVEL_6) +-#define DEBUG6(x) do {x;} while (0); +-#else /* */ +-#define DEBUG6(x) do {} while (0); +-#endif /* */ +- +-#if defined(QL_DEBUG_LEVEL_9) +-#define DEBUG9(x) do {x;} while (0); +-#else /* */ +-#define DEBUG9(x) do {} while (0); +-#endif /* */ ++#define DEBUG6(x) do {if(extended_error_logging & 0x20) x;} while (0); ++#else ++#define DEBUG6(x) ++#endif ++ ++#endif /*_QL4_DBG_*/ +--- a/drivers/scsi/qla4xxx/ql4_def.h ++++ b/drivers/scsi/qla4xxx/ql4_def.h +@@ -144,7 +144,6 @@ + #define RESET_FIRMWARE_TOV 30 + #define LOGOUT_TOV 10 + #define IOCB_TOV_MARGIN 10 +-#define RELOGIN_TOV 18 + #define ISNS_DEREG_TOV 5 + + #define MAX_RESET_HA_RETRIES 2 +@@ -252,6 +251,8 @@ struct ddb_entry { + #define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL + * logged it out */ + #define DF_SCAN_ISSUED 2 ++#define DF_OFFLINE 3 /* Offline Device */ ++#define DF_DELETED 4 /* Device has been removed */ + + /* + * Asynchronous Event Queue structure +@@ -286,7 +287,6 @@ struct scsi_qla_host { + uint32_t tot_ddbs; + unsigned long flags; + +-#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */ + #define AF_ONLINE 0 /* 0x00000001 */ + #define AF_INIT_DONE 1 /* 0x00000002 */ + #define AF_MBOX_COMMAND 2 /* 0x00000004 */ +@@ -294,9 +294,9 @@ struct scsi_qla_host { + #define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */ + #define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ + #define AF_LINK_UP 8 /* 0x00000100 */ +-#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */ + #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ + #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ ++#define AF_OS_INDEX_VALID 12 /* 0x00001000 */ + + unsigned long dpc_flags; + +@@ -308,6 +308,8 @@ struct scsi_qla_host { + #define DPC_ISNS_RESTART 7 /* 0x00000080 */ + #define DPC_AEN 9 /* 0x00000200 */ + #define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ ++#define DPC_OFFLINE_DEVICE 16 /* 0x00010000 */ ++#define DPC_DELETE_DEVICE 17 /* 0x00020000 */ + + uint16_t iocb_cnt; + uint16_t iocb_hiwat; +@@ -460,7 +462,7 @@ struct scsi_qla_host { + void (*ql4getaenlog)(struct scsi_qla_host *ha, struct ql4_aen_log *aenl); + #define QL_INDICES_PER_ENTRY 32 + #define QL_OSINDEX_ENTRIES (MAX_DDB_ENTRIES/QL_INDICES_PER_ENTRY) +- volatile uint32_t os_map[QL_OSINDEX_ENTRIES]; ++ volatile unsigned long os_map[QL_OSINDEX_ENTRIES]; + }; + + static inline int is_qla4010(struct scsi_qla_host *ha) +@@ -468,6 +470,7 @@ static inline int is_qla4010(struct scsi + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010; + } + ++ + static inline int is_qla4022(struct scsi_qla_host *ha) + { + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022; +--- a/drivers/scsi/qla4xxx/ql4_glbl.h ++++ b/drivers/scsi/qla4xxx/ql4_glbl.h +@@ -10,7 +10,7 @@ + + struct iscsi_cls_conn; + +-void qla4xxx_hw_reset(struct scsi_qla_host *ha); ++void qla4xxx_hw_reset(struct scsi_qla_host *ha, int hw_lock); + int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); + int qla4xxx_conn_start(struct iscsi_cls_conn *conn); + int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); +@@ -18,9 +18,9 @@ int qla4xxx_send_command_to_isp(struct s + int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, + uint8_t renew_ddb_list); + int qla4xxx_soft_reset(struct scsi_qla_host *ha); +-irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); + + void qla4xxx_free_ddb_list(struct scsi_qla_host * ha); ++void qla4xxx_free_ddb(struct scsi_qla_host *, struct ddb_entry *); + void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen); + + int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha); +@@ -47,6 +47,8 @@ int qla4xxx_get_fwddb_entry(struct scsi_ + uint16_t *tcp_source_port_num, + uint16_t *connection_id); + ++struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha, ++ uint32_t fw_ddb_index); + int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, + dma_addr_t fw_ddb_entry_dma); + +@@ -77,10 +79,6 @@ int qla4xxx_process_ddb_changed(struct s + + int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); +-int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry, int lun); +- +- + + extern int extended_error_logging; + extern int ql4xdiscoverywait; +--- a/drivers/scsi/qla4xxx/ql4_init.c ++++ b/drivers/scsi/qla4xxx/ql4_init.c +@@ -10,6 +10,7 @@ + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" ++#include "ql4_os.h" + + /* link auto negotiation normally takes roughly 2s. */ + /* If we don't have link in 3 times that period quit. */ +@@ -19,9 +20,6 @@ + * QLogic ISP4xxx Hardware Support Function Prototypes. + */ + +-static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, +- uint32_t fw_ddb_index); +- + static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) + { + uint32_t value; +@@ -52,15 +50,14 @@ static void ql4xxx_set_mac_number(struct + } + + /** +- * qla4xxx_free_ddb - deallocate ddb ++ * qla4xxx_free_ddb - deallocate ddb + * @ha: pointer to host adapter structure. + * @ddb_entry: pointer to device database entry + * + * This routine deallocates and unlinks the specified ddb_entry from the + * adapter's + **/ +-static void qla4xxx_free_ddb(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry) ++void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) + { + /* Remove device entry from list */ + list_del_init(&ddb_entry->list); +@@ -359,8 +356,8 @@ static void qla4xxx_fill_ddb(struct ddb_ + * This routine allocates a ddb_entry, ititializes some values, and + * inserts it into the ddb list. + **/ +-static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, +- uint32_t fw_ddb_index) ++struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, ++ uint32_t fw_ddb_index) + { + struct ddb_entry *ddb_entry; + +@@ -478,7 +475,7 @@ static int qla4xxx_build_ddb_list(struct + (strlen(fw_ddb_entry->iscsi_name) != 0)){ + ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); + if (ddb_entry == NULL) { +- DEBUG2(dev_info(&ha->pdev->dev,"%s alloc_ddb %d " ++ DEBUG2(dev_info(&ha->pdev->dev,"%s alloc_ddb %d" + "failed\n", __func__, fw_ddb_index)); + goto exit_ddb_list; + } +@@ -488,7 +485,7 @@ static int qla4xxx_build_ddb_list(struct + ddb_entry->connection_id = conn_id; + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + ddb_entry->fw_ddb_device_state = ddb_state; +- ++ + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + dev_info(&ha->pdev->dev, +@@ -695,6 +692,8 @@ static int qla4xxx_initialize_ddb_list(s + + qla4xxx_flush_AENS(ha); + ++ /* Wait for an AEN */ ++ qla4xxx_devices_ready(ha); + + /* + * First perform device discovery for active +@@ -704,9 +703,6 @@ static int qla4xxx_initialize_ddb_list(s + if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) + return status; + +- /* Wait for an AEN */ +- qla4xxx_devices_ready(ha); +- + /* + * Targets can come online after the inital discovery, so processing + * the aens here will catch them. +@@ -747,13 +743,15 @@ int qla4xxx_reinitialize_ddb_list(struct + + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + +- if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { ++ if (ddb_entry->fw_ddb_device_state == ++ DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + dev_info(&ha->pdev->dev, +- "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", +- ha->host_no, __func__, ddb_entry->fw_ddb_index, ++ "%s: ddb[%d] os[%d] marked ONLINE\n", ++ __func__, ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); +- } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) ++ } else if (atomic_read(&ddb_entry->state) == ++ DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + } + } +@@ -884,8 +882,8 @@ static int qla4xxx_start_firmware_from_f + writel(set_rmask(NVR_WRITE_ENABLE), + &ha->reg->u1.isp4022.nvram); + +- writel(2, &ha->reg->mailbox[6]); +- readl(&ha->reg->mailbox[6]); ++ writel(2, &ha->reg->mailbox[6]); ++ readl(&ha->reg->mailbox[6]); + + writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); +@@ -1054,7 +1052,7 @@ static int qla4xxx_start_firmware(struct + } + config_chip = 1; + +- /* Reset clears the semaphore, so acquire again */ ++ /* Reset clears the semaphore, so aquire again */ + if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) + return QLA_ERROR; + } +@@ -1083,7 +1081,7 @@ static int qla4xxx_start_firmware(struct + * @renew_ddb_list: Indicates what to do with the adapter's ddb list + * after adapter recovery has completed. + * 0=preserve ddb list, 1=destroy and rebuild ddb list +- * ++ * + * This routine parforms all of the steps necessary to initialize the adapter. + * + **/ +@@ -1119,12 +1117,12 @@ int qla4xxx_initialize_adapter(struct sc + * followed by 0x8014 aen" to trigger the tgt discovery process. + */ + if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) +- goto exit_init_online; ++ goto exit_init_hba0; + + /* Skip device discovery if ip and subnet is zero */ + if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 || + memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0) +- goto exit_init_online; ++ goto exit_init_hba0; + + if (renew_ddb_list == PRESERVE_DDB_LIST) { + /* +@@ -1153,8 +1151,10 @@ int qla4xxx_initialize_adapter(struct sc + ha->host_no)); + } + +-exit_init_online: ++exit_init_hba0: + set_bit(AF_ONLINE, &ha->flags); ++ dev_info(&ha->pdev->dev, "%s: adapter ONLINE\n", __func__); ++ + exit_init_hba: + return status; + } +@@ -1204,40 +1204,63 @@ static void qla4xxx_add_device_dynamical + } + } + +- if (!found) +- ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); +- else if (ddb_entry->fw_ddb_index != fw_ddb_index) { +- /* Target has been bound to a new fw_ddb_index */ +- qla4xxx_free_ddb(ha, ddb_entry); ++ if (!found) { + ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); +- } + +- if (ddb_entry == NULL) { +- DEBUG2(dev_info(&ha->pdev->dev, "%s NULL DDB %d\n", +- __func__, fw_ddb_index)); +- goto exit_dyn_add; +- } ++ if (ddb_entry == NULL) { ++ DEBUG2(dev_info(&ha->pdev->dev, "%s NULL DDB %d\n", ++ __func__, fw_ddb_index)); ++ goto exit_dyn_add; ++ } + +- ddb_entry->fw_ddb_index = fw_ddb_index; +- ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; +- ddb_entry->tcp_source_port_num = src_port; +- ddb_entry->connection_id = conn_id; +- qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); +- ddb_entry->fw_ddb_device_state = ddb_state; ++ ddb_entry->fw_ddb_index = fw_ddb_index; ++ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ++ ddb_entry->tcp_source_port_num = src_port; ++ ddb_entry->connection_id = conn_id; ++ qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); ++ ddb_entry->fw_ddb_device_state = ddb_state; ++ ++ if (probe) ++ goto exit_dyn_add; + +- if (!probe) { + if (qla4xxx_add_sess(ddb_entry, 1)) { +- DEBUG2(printk(KERN_WARNING +- "scsi%ld: failed to add new device at index " +- "[%d]\n Unable to add connection and session\n", +- ha->host_no, fw_ddb_index)); ++ DEBUG2(dev_info(&ha->pdev->dev, ++ "%s: failed to add new ddb %d\n", ++ __func__, fw_ddb_index)); + qla4xxx_free_ddb(ha, ddb_entry); ++ } else { ++ DEBUG6(dev_info(&ha->pdev->dev, ++ "%s added ddb 0x%p sess 0x%p" ++ " conn 0x%p state 0x%x\n", ++ __func__, ddb_entry, ++ ddb_entry->sess, ddb_entry->conn, ++ ddb_entry->state)); + } +- } ++ } else if (ddb_entry->fw_ddb_index != fw_ddb_index) { ++ /* Target has been bound to a new fw_ddb_index */ ++ ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = NULL; ++ ddb_entry->fw_ddb_index = fw_ddb_index; ++ ddb_entry->fw_ddb_device_state = ddb_state; ++ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ++ atomic_set(&ddb_entry->port_down_timer, ++ ha->port_down_retry_count); ++ atomic_set(&ddb_entry->relogin_retry_count, 0); ++ atomic_set(&ddb_entry->relogin_timer, 0); ++ clear_bit(DF_RELOGIN, &ddb_entry->flags); ++ clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); ++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + +- DEBUG6(dev_info(&ha->pdev->dev, "%s added ddb 0x%p sess 0x%p conn 0x%p" +- " state 0x%x\n", __func__, ddb_entry, ddb_entry->sess, +- ddb_entry->conn, ddb_entry->state)); ++ dev_info(&ha->pdev->dev, ++ "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE sess:%p conn:%p\n", ++ ha->host_no, __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id, ddb_entry->sess, ddb_entry->conn); ++ ++ if (!probe) ++ qla4xxx_conn_start(ddb_entry->conn); ++ DEBUG6(dev_info(&ha->pdev->dev, "%s calling conn_start ddb 0x%p sess 0x%p" ++ " conn 0x%p state 0x%x\n", __func__, ddb_entry, ddb_entry->sess, ++ ddb_entry->conn, ddb_entry->state)); ++ } + exit_dyn_add: + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); +@@ -1272,15 +1295,15 @@ int qla4xxx_process_ddb_changed(struct s + qla4xxx_add_device_dynamically(ha, fw_ddb_index, probe); + return QLA_SUCCESS; + } +- DEBUG6(dev_info(&ha->pdev->dev, "%s ddb_entry 0x%p ostate 0x%x" +- " sess 0x%p conn 0x%p\n", __func__, ddb_entry, +- ddb_entry->state, ddb_entry->sess, ddb_entry->conn)); ++ DEBUG6(dev_info(&ha->pdev->dev, "%s ddb[%d] os[%d] ostate 0x%x" ++ " sess 0x%p conn 0x%p o_fwstate 0x%x n_fwstate ox%x \n", ++ __func__, ddb_entry->fw_ddb_index, ddb_entry->os_target_id, ++ ddb_entry->state, ddb_entry->sess, ddb_entry->conn, ++ ddb_entry->fw_ddb_device_state, state)); + + /* Device already exists in our database. */ + old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; +- DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for " +- "index [%d]\n", ha->host_no, __func__, +- ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); ++ + if (old_fw_ddb_device_state == state && + state == DDB_DS_SESSION_ACTIVE) { + /* Do nothing, state not changed. */ +@@ -1297,26 +1320,33 @@ int qla4xxx_process_ddb_changed(struct s + atomic_set(&ddb_entry->port_down_timer, + ha->port_down_retry_count); + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); ++ dev_info(&ha->pdev->dev, ++ "%s: ddb[%d] os[%d] marked ONLINE\n", ++ __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ + atomic_set(&ddb_entry->relogin_retry_count, 0); + atomic_set(&ddb_entry->relogin_timer, 0); + clear_bit(DF_RELOGIN, &ddb_entry->flags); + clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); + +- DEBUG6(dev_info(&ha->pdev->dev, "%s conn startddb_entry 0x%p" +- " sess 0x%p conn 0x%p\n", +- __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); +- +- qla4xxx_conn_start(ddb_entry->conn); +- +- DEBUG6(dev_info(&ha->pdev->dev, "%s conn start done " +- "ddb_entry 0x%p sess 0x%p conn 0x%p\n", +- __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); +- +- if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) { +- scsi_scan_target(&ddb_entry->sess->dev, 0, +- ddb_entry->sess->target_id, +- SCAN_WILD_CARD, 0); +- set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); ++ if (ddb_entry->conn) { ++ DEBUG6(dev_info(&ha->pdev->dev, ++ "%s conn startddb_entry 0x%p" ++ " sess 0x%p conn 0x%p\n", ++ __func__, ++ ddb_entry, ddb_entry->sess, ddb_entry->conn)); ++ ++ qla4xxx_conn_start(ddb_entry->conn); ++ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s conn start done " ++ "ddb_entry 0x%p sess 0x%p conn 0x%p\n", ++ __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); ++ ++ if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) { ++ qla4xxx_scan_target(ddb_entry); ++ set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); ++ } + } + } else { + /* Device went away, try to relogin. */ +--- a/drivers/scsi/qla4xxx/ql4_inline.h ++++ b/drivers/scsi/qla4xxx/ql4_inline.h +@@ -34,6 +34,34 @@ qla4xxx_lookup_ddb_by_fw_index(struct sc + return ddb_entry; + } + ++/* ++ * The MBOX_CMD_CLEAR_DATABASE_ENTRY (0x31) mailbox command does not ++ * result in an AEN, so we need to process it seperately. ++ */ ++static inline void qla4xxx_check_for_clear_ddb(struct scsi_qla_host *ha, ++ uint32_t *mbox_cmd) ++{ ++ uint32_t fw_ddb_index; ++ struct ddb_entry *ddb_entry = NULL; ++ ++ if (mbox_cmd[0] == MBOX_CMD_CLEAR_DATABASE_ENTRY) { ++ ++ fw_ddb_index = mbox_cmd[1]; ++ ++ if (fw_ddb_index < MAX_DDB_ENTRIES) ++ ddb_entry = ha->fw_ddb_index_map[fw_ddb_index]; ++ ++ if (ddb_entry) { ++ dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] freed\n", ++ __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ set_bit(DF_DELETED, &ddb_entry->flags); ++ set_bit(DPC_DELETE_DEVICE, &ha->dpc_flags); ++ queue_work(ha->dpc_thread, &ha->dpc_work); ++ } ++ } ++} ++ + static inline void + __qla4xxx_enable_intrs(struct scsi_qla_host *ha) + { +@@ -81,3 +109,118 @@ qla4xxx_disable_intrs(struct scsi_qla_ho + __qla4xxx_disable_intrs(ha); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } ++ ++static inline int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, ++ struct queue_entry **queue_entry) ++{ ++ uint16_t request_in; ++ uint8_t status = QLA_SUCCESS; ++ ++ *queue_entry = ha->request_ptr; ++ ++ /* get the latest request_in and request_out index */ ++ request_in = ha->request_in; ++ ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); ++ ++ /* Advance request queue pointer and check for queue full */ ++ if (request_in == (REQUEST_QUEUE_DEPTH - 1)) { ++ request_in = 0; ++ ha->request_ptr = ha->request_ring; ++ } else { ++ request_in++; ++ ha->request_ptr++; ++ } ++ ++ /* request queue is full, try again later */ ++ if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) { ++ /* restore request pointer */ ++ ha->request_ptr = *queue_entry; ++ status = QLA_ERROR; ++ } else { ++ ha->request_in = request_in; ++ memset(*queue_entry, 0, sizeof(**queue_entry)); ++ } ++ ++ return status; ++} ++ ++/** ++ * qla4xxx_send_marker_iocb - issues marker iocb to HBA ++ * @ha: Pointer to host adapter structure. ++ * @ddb_entry: Pointer to device database entry ++ * @lun: SCSI LUN ++ * @marker_type: marker identifier ++ * ++ * This routine issues a marker IOCB. ++ **/ ++static inline int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, ++ struct ddb_entry *ddb_entry, int lun) ++{ ++ struct marker_entry *marker_entry; ++ unsigned long flags = 0; ++ uint8_t status = QLA_SUCCESS; ++ ++ /* Acquire hardware specific lock */ ++ spin_lock_irqsave(&ha->hardware_lock, flags); ++ ++ /* Get pointer to the queue entry for the marker */ ++ if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) != ++ QLA_SUCCESS) { ++ status = QLA_ERROR; ++ goto exit_send_marker; ++ } ++ ++ /* Put the marker in the request queue */ ++ marker_entry->hdr.entryType = ET_MARKER; ++ marker_entry->hdr.entryCount = 1; ++ marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); ++ marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); ++ int_to_scsilun(lun, &marker_entry->lun); ++ wmb(); ++ ++ /* Tell ISP it's got a new I/O request */ ++ writel(ha->request_in, &ha->reg->req_q_in); ++ readl(&ha->reg->req_q_in); ++ ++exit_send_marker: ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ return status; ++} ++ ++static inline struct continuation_t1_entry* qla4xxx_alloc_cont_entry( ++ struct scsi_qla_host *ha) ++{ ++ struct continuation_t1_entry *cont_entry; ++ ++ cont_entry = (struct continuation_t1_entry *)ha->request_ptr; ++ ++ /* Advance request queue pointer */ ++ if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) { ++ ha->request_in = 0; ++ ha->request_ptr = ha->request_ring; ++ } else { ++ ha->request_in++; ++ ha->request_ptr++; ++ } ++ ++ /* Load packet defaults */ ++ cont_entry->hdr.entryType = ET_CONTINUE; ++ cont_entry->hdr.entryCount = 1; ++ cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in); ++ ++ return cont_entry; ++} ++ ++static inline uint16_t qla4xxx_calc_request_entries(uint16_t dsds) ++{ ++ uint16_t iocbs; ++ ++ iocbs = 1; ++ if (dsds > COMMAND_SEG) { ++ iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG; ++ if ((dsds - COMMAND_SEG) % CONTINUE_SEG) ++ iocbs++; ++ } ++ return iocbs; ++} ++ +--- a/drivers/scsi/qla4xxx/ql4_iocb.c ++++ b/drivers/scsi/qla4xxx/ql4_iocb.c +@@ -11,133 +11,8 @@ + #include "ql4_dbg.h" + #include "ql4_inline.h" + +-#define VMWARE_CMD_TIMEOUT 30 + #include + +-/** +- * qla4xxx_get_req_pkt - returns a valid entry in request queue. +- * @ha: Pointer to host adapter structure. +- * @queue_entry: Pointer to pointer to queue entry structure +- * +- * This routine performs the following tasks: +- * - returns the current request_in pointer (if queue not full) +- * - advances the request_in pointer +- * - checks for queue full +- **/ +-static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, +- struct queue_entry **queue_entry) +-{ +- uint16_t request_in; +- uint8_t status = QLA_SUCCESS; +- +- *queue_entry = ha->request_ptr; +- +- /* get the latest request_in and request_out index */ +- request_in = ha->request_in; +- ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); +- +- /* Advance request queue pointer and check for queue full */ +- if (request_in == (REQUEST_QUEUE_DEPTH - 1)) { +- request_in = 0; +- ha->request_ptr = ha->request_ring; +- } else { +- request_in++; +- ha->request_ptr++; +- } +- +- /* request queue is full, try again later */ +- if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) { +- /* restore request pointer */ +- ha->request_ptr = *queue_entry; +- status = QLA_ERROR; +- } else { +- ha->request_in = request_in; +- memset(*queue_entry, 0, sizeof(**queue_entry)); +- } +- +- return status; +-} +- +-/** +- * qla4xxx_send_marker_iocb - issues marker iocb to HBA +- * @ha: Pointer to host adapter structure. +- * @ddb_entry: Pointer to device database entry +- * @lun: SCSI LUN +- * @marker_type: marker identifier +- * +- * This routine issues a marker IOCB. +- **/ +-int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry, int lun) +-{ +- struct marker_entry *marker_entry; +- unsigned long flags = 0; +- uint8_t status = QLA_SUCCESS; +- +- /* Acquire hardware specific lock */ +- spin_lock_irqsave(&ha->hardware_lock, flags); +- +- /* Get pointer to the queue entry for the marker */ +- if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) != +- QLA_SUCCESS) { +- status = QLA_ERROR; +- goto exit_send_marker; +- } +- +- /* Put the marker in the request queue */ +- marker_entry->hdr.entryType = ET_MARKER; +- marker_entry->hdr.entryCount = 1; +- marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); +- marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); +- int_to_scsilun(lun, &marker_entry->lun); +- wmb(); +- +- /* Tell ISP it's got a new I/O request */ +- writel(ha->request_in, &ha->reg->req_q_in); +- readl(&ha->reg->req_q_in); +- +-exit_send_marker: +- spin_unlock_irqrestore(&ha->hardware_lock, flags); +- return status; +-} +- +-static struct continuation_t1_entry* qla4xxx_alloc_cont_entry( +- struct scsi_qla_host *ha) +-{ +- struct continuation_t1_entry *cont_entry; +- +- cont_entry = (struct continuation_t1_entry *)ha->request_ptr; +- +- /* Advance request queue pointer */ +- if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) { +- ha->request_in = 0; +- ha->request_ptr = ha->request_ring; +- } else { +- ha->request_in++; +- ha->request_ptr++; +- } +- +- /* Load packet defaults */ +- cont_entry->hdr.entryType = ET_CONTINUE; +- cont_entry->hdr.entryCount = 1; +- cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in); +- +- return cont_entry; +-} +- +-static uint16_t qla4xxx_calc_request_entries(uint16_t dsds) +-{ +- uint16_t iocbs; +- +- iocbs = 1; +- if (dsds > COMMAND_SEG) { +- iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG; +- if ((dsds - COMMAND_SEG) % CONTINUE_SEG) +- iocbs++; +- } +- return iocbs; +-} +- + static void qla4xxx_build_scsi_iocbs(struct srb *srb, + struct command_t3_entry *cmd_entry, + uint16_t tot_dsds) +@@ -224,6 +99,7 @@ int qla4xxx_send_command_to_isp(struct s + /* Acquire hardware specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + ++ //index = (uint32_t)cmd->request->tag; + index = ha->current_active_index; + for (i = 0; i < MAX_SRBS; i++) { + index++; +@@ -242,10 +118,14 @@ int qla4xxx_send_command_to_isp(struct s + } + + /* Calculate the number of request entries needed. */ +- nseg = scsi_dma_map(cmd); +- if (nseg < 0) +- goto queuing_error; +- tot_dsds = nseg; ++ if (srb->flags & SRB_SCSI_PASSTHRU) ++ tot_dsds = 1; ++ else { ++ nseg = scsi_dma_map(cmd); ++ if (nseg < 0) ++ goto queuing_error; ++ tot_dsds = nseg; ++ } + + req_cnt = qla4xxx_calc_request_entries(tot_dsds); + +@@ -281,9 +161,9 @@ int qla4xxx_send_command_to_isp(struct s + cmd_entry->hdr.entryCount = req_cnt; + + /* Set data transfer direction control flags +- * NOTE: Look at data_direction bits iff there is data to be +- * transferred, as the data direction bit is sometimed filled +- * in when there is no data to be transferred */ ++ * NOTE: Look at data_direction bits iff there is data to be ++ * transferred, as the data direction bit is sometimed filled ++ * in when there is no data to be transferred */ + cmd_entry->control_flags = CF_NO_DATA; + if (scsi_bufflen(cmd)) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) +@@ -324,10 +204,10 @@ int qla4xxx_send_command_to_isp(struct s + + /* + * Check to see if adapter is online before placing request on +- * request queue. If a reset occurs and a request is in the queue, +- * the firmware will still attempt to process the request, retrieving +- * garbage for pointers. +- */ ++ * request queue. If a reset occurs and a request is in the queue, ++ * the firmware will still attempt to process the request, retrieving ++ * garbage for pointers. ++ */ + if (!test_bit(AF_ONLINE, &ha->flags)) { + DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! " + "Do not issue command.\n", +@@ -355,13 +235,12 @@ int qla4xxx_send_command_to_isp(struct s + return QLA_SUCCESS; + + queuing_error: +- if (srb->flags & SRB_SCSI_PASSTHRU) +- return QLA_ERROR; +- +- if (tot_dsds) +- scsi_dma_unmap(cmd); ++ if (!(srb->flags & SRB_SCSI_PASSTHRU)) ++ if (tot_dsds) ++ scsi_dma_unmap(cmd); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_ERROR; + } ++ +--- a/drivers/scsi/qla4xxx/ql4_isr.c ++++ b/drivers/scsi/qla4xxx/ql4_isr.c +@@ -10,6 +10,7 @@ + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" ++#include "ql4_os.h" + + /** + * qla4xxx_status_entry - processes status IOCBs +@@ -59,8 +60,8 @@ static void qla4xxx_status_entry(struct + break; + } + if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) { +- scsi_set_resid(cmd, residual); +- if (!scsi_status && ((scsi_bufflen(cmd) - residual) < ++ QL_SET_SCSI_RESID(cmd, residual); ++ if (!scsi_status && ((QL_SCSI_BUFFLEN(cmd) - residual) < + cmd->underflow)) { + cmd->result = DID_ERROR << 16; + break; +@@ -144,7 +145,7 @@ static void qla4xxx_status_entry(struct + break; + } + +- scsi_set_resid(cmd, residual); ++ QL_SET_SCSI_RESID(cmd, residual); + + /* + * If there is scsi_status, it takes precedense over +@@ -184,7 +185,7 @@ static void qla4xxx_status_entry(struct + if ((sts_entry->iscsiFlags & + ISCSI_FLAG_RESIDUAL_UNDER) == 0) { + cmd->result = DID_BUS_BUSY << 16; +- } else if ((scsi_bufflen(cmd) - residual) < ++ } else if ((QL_SCSI_BUFFLEN(cmd) - residual) < + cmd->underflow) { + /* + * Handle mid-layer underflow??? +@@ -203,7 +204,7 @@ static void qla4xxx_status_entry(struct + "resid = 0x%x, compstat = 0x%x\n", + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun, +- __func__, scsi_bufflen(cmd), ++ __func__, QL_SCSI_BUFFLEN(cmd), + residual, + sts_entry->completionStatus)); + +@@ -396,13 +397,13 @@ static void qla4xxx_isr_decode_mailbox(s + /* Immediately process the AENs that don't require much work. + * Only queue the database_changed AENs */ + +- dev_info(&ha->pdev->dev, "%s mbx0 0x%08x mbx1 0x%08x" ++ DEBUG6(dev_info(&ha->pdev->dev, "%s mbx0 0x%08x mbx1 0x%08x" + " mbx2 0x%08x mbx3 0x%08x mbx4 0x%08x mbx5 0x%08x " + "mbx6 0x%08x mbx7 0x%08x\n", __func__, + readl(&ha->reg->mailbox[0]), readl(&ha->reg->mailbox[1]), + readl(&ha->reg->mailbox[2]), readl(&ha->reg->mailbox[3]), + readl(&ha->reg->mailbox[4]), readl(&ha->reg->mailbox[5]), +- readl(&ha->reg->mailbox[6]), readl(&ha->reg->mailbox[7])); ++ readl(&ha->reg->mailbox[6]), readl(&ha->reg->mailbox[7]))); + + if (ha->aen_log.count < MAX_AEN_ENTRIES) { + for (i = 0; i < MBOX_AEN_REG_COUNT; i++) +@@ -412,11 +413,13 @@ static void qla4xxx_isr_decode_mailbox(s + } + switch (mbox_status) { + case MBOX_ASTS_SYSTEM_ERROR: ++ dev_info(&ha->pdev->dev, "%s: System Err\n", __func__); + /* Log Mailbox registers */ + if (ql4xdontresethba) { + DEBUG2(printk("%s:Dont Reset HBA\n", + __func__)); + } else { ++ qla4xxx_hw_reset(ha, 0); + set_bit(AF_GET_CRASH_RECORD, &ha->flags); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } +@@ -433,15 +436,13 @@ static void qla4xxx_isr_decode_mailbox(s + break; + + case MBOX_ASTS_LINK_UP: +- DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n", +- ha->host_no, mbox_status)); + set_bit(AF_LINK_UP, &ha->flags); ++ dev_info(&ha->pdev->dev, "%s: LINK UP\n", __func__); + break; + + case MBOX_ASTS_LINK_DOWN: +- DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n", +- ha->host_no, mbox_status)); + clear_bit(AF_LINK_UP, &ha->flags); ++ dev_info(&ha->pdev->dev, "%s: LINK DOWN\n", __func__); + break; + + case MBOX_ASTS_HEARTBEAT: +@@ -470,9 +471,9 @@ static void qla4xxx_isr_decode_mailbox(s + mbox_stat2 = readl(&ha->reg->mailbox[2]); + mbox_stat3 = readl(&ha->reg->mailbox[3]); + +- if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) ++ if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) + set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); +- else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) ++ else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) + set_bit(DPC_RESET_HA, &ha->dpc_flags); + break; + +@@ -591,10 +592,10 @@ void qla4xxx_interrupt_service_routine(s + * qla4xxx_intr_handler - hardware interrupt handler. + * @irq: Unused + * @dev_id: Pointer to host adapter structure ++ * @regs: Unused + **/ +-irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) ++QL_DECLARE_INTR_HANDLER(qla4xxx_intr_handler, irq, dev_id, regs) + { +- + struct scsi_qla_host *ha; + uint32_t intr_status; + unsigned long flags = 0; +@@ -625,8 +626,7 @@ irqreturn_t qla4xxx_intr_handler(int irq + intr_status = readl(&ha->reg->ctrl_status); + + if ((intr_status & +- (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == +- 0) { ++ (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) { + if (reqs_count == 0) + ha->spurious_int_count++; + break; +@@ -662,6 +662,8 @@ irqreturn_t qla4xxx_intr_handler(int irq + break; + } else if (intr_status & CSR_SCSI_RESET_INTR) { + clear_bit(AF_ONLINE, &ha->flags); ++ dev_info(&ha->pdev->dev,"%s: adapter OFFLINE\n", ++ __func__); + __qla4xxx_disable_intrs(ha); + + writel(set_rmask(CSR_SCSI_RESET_INTR), +--- a/drivers/scsi/qla4xxx/ql4_mbx.c ++++ b/drivers/scsi/qla4xxx/ql4_mbx.c +@@ -10,6 +10,7 @@ + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" ++#include "ql4_os.h" + + + /** +@@ -43,6 +44,7 @@ int qla4xxx_mailbox_command(struct scsi_ + + /* Mailbox code active */ + wait_count = MBOX_TOV * 100; ++ + while (wait_count--) { + mutex_lock(&ha->mbox_sem); + if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { +@@ -166,6 +168,8 @@ int qla4xxx_mailbox_command(struct scsi_ + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + mbox_exit: ++ if (status == QLA_SUCCESS) ++ qla4xxx_check_for_clear_ddb(ha, mbx_cmd); + mutex_lock(&ha->mbox_sem); + clear_bit(AF_MBOX_COMMAND, &ha->flags); + mutex_unlock(&ha->mbox_sem); +@@ -851,8 +855,8 @@ int qla4xxx_get_flash(struct scsi_qla_ho + * qla4xxx_get_fw_version - gets firmware version + * @ha: Pointer to host adapter structure. + * +- * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may +- * hold an address for data. Make sure that we write 0 to those mailboxes, ++ * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may ++ * hold an address for data. Make sure that we write 0 to those mailboxes, + * if unused. + **/ + int qla4xxx_get_fw_version(struct scsi_qla_host * ha) +@@ -882,8 +886,7 @@ int qla4xxx_get_fw_version(struct scsi_q + return QLA_SUCCESS; + } + +-static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, +- dma_addr_t dma_addr) ++int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr) + { + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -15,6 +15,8 @@ + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" ++#include "ql4_os.h" ++ + + /* + * Driver version +@@ -56,24 +58,32 @@ MODULE_PARM_DESC(extended_error_logging, + "Option to enable extended error logging, " + "Default is 0 - no logging, 1 - debug logging"); + ++/* Command Timeout before ddb state goes to MISSING */ ++int cmd_timeout = IOCB_CMD_TIMEOUT; ++module_param(cmd_timeout, int, S_IRUGO | S_IRUSR); ++MODULE_PARM_DESC(cmd_timeout, "Command Timeout"); ++ ++/* Timeout before ddb state MISSING goes DEAD */ ++int recovery_tmo = RECOVERY_TIMEOUT; ++module_param(recovery_tmo, int, S_IRUGO | S_IRUSR); ++MODULE_PARM_DESC(recovery_tmo, "Recovery Timeout"); ++ + int ql4_mod_unload = 0; + /* + * SCSI host template entry points + */ +-static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); ++ ++void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); + + /* + * iSCSI template entry points + */ +-static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost, +- enum iscsi_tgt_dscvr type, uint32_t enable, +- struct sockaddr *dst_addr); ++static int qla4xxx_host_get_param(struct Scsi_Host *, ++ enum iscsi_host_param, char *); + static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, + enum iscsi_param param, char *buf); + static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, + enum iscsi_param param, char *buf); +-static int qla4xxx_host_get_param(struct Scsi_Host *shost, +- enum iscsi_host_param param, char *buf); + static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); + + /* +@@ -85,11 +95,13 @@ static int qla4xxx_eh_device_reset(struc + static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); + static int qla4xxx_slave_alloc(struct scsi_device *device); + static int qla4xxx_slave_configure(struct scsi_device *device); ++static void qla4xxx_slave_destroy(struct scsi_device *device); + + static struct scsi_host_template qla4xxx_driver_template = { + .module = THIS_MODULE, + .name = DRIVER_NAME, + .proc_name = DRIVER_NAME, ++ .proc_info = qla4xxx_proc_info, + .queuecommand = qla4xxx_queuecommand, + + .eh_device_reset_handler = qla4xxx_eh_device_reset, +@@ -97,6 +109,7 @@ static struct scsi_host_template qla4xxx + + .slave_configure = qla4xxx_slave_configure, + .slave_alloc = qla4xxx_slave_alloc, ++ .slave_destroy = qla4xxx_slave_destroy, + + .this_id = -1, + .cmd_per_lun = 3, +@@ -113,10 +126,13 @@ static struct iscsi_transport qla4xxx_is + ISCSI_CONN_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, +- .tgt_dscvr = qla4xxx_tgt_dscvr, ++ ++ QL_INIT_SESSION_DATASIZE(sessiondata_size) ++ QL_INIT_HOST_TEMPLATE(host_template) ++ ++ .get_host_param = qla4xxx_host_get_param, + .get_conn_param = qla4xxx_conn_get_param, + .get_session_param = qla4xxx_sess_get_param, +- .get_host_param = qla4xxx_host_get_param, + .session_recovery_timedout = qla4xxx_recovery_timedout, + }; + +@@ -134,31 +150,9 @@ static void qla4xxx_recovery_timedout(st + ddb_entry->fw_ddb_index, ddb_entry->os_target_id, + ha->port_down_retry_count); + +- DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " +- "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); +- queue_work(ha->dpc_thread, &ha->dpc_work); +-} +- +-static int qla4xxx_host_get_param(struct Scsi_Host *shost, +- enum iscsi_host_param param, char *buf) +-{ +- struct scsi_qla_host *ha = to_qla_host(shost); +- int len; +- +- switch (param) { +- case ISCSI_HOST_PARAM_IPADDRESS: +- len = sprintf(buf, "%d.%d.%d.%d", ha->ip_address[0], +- ha->ip_address[1], ha->ip_address[2], +- ha->ip_address[3]); +- break; +- case ISCSI_HOST_PARAM_INITIATOR_NAME: +- len = sprintf(buf, "%s", ha->name_string); +- break; +- default: +- return -ENOSYS; +- } ++ QL_SET_DDB_OFFLINE(ha, ddb_entry); + +- return len; ++ queue_work(ha->dpc_thread, &ha->dpc_work); + } + + int qla4xxx_conn_start(struct iscsi_cls_conn *conn) +@@ -166,7 +160,8 @@ int qla4xxx_conn_start(struct iscsi_cls_ + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + +- session = iscsi_dev_to_session(conn->dev.parent); ++ session = QL_ISCSI_CONN_TO_SESS(conn); ++ + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", +@@ -181,7 +176,8 @@ static void qla4xxx_conn_stop(struct isc + struct iscsi_cls_session *session; + struct ddb_entry *ddb_entry; + +- session = iscsi_dev_to_session(conn->dev.parent); ++ session = QL_ISCSI_CONN_TO_SESS(conn); ++ + ddb_entry = session->dd_data; + + DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", +@@ -207,6 +203,12 @@ static int qla4xxx_sess_get_param(struct + case ISCSI_PARAM_TPGT: + len = sprintf(buf, "%u", ddb_entry->tpgt); + break; ++ ++#ifdef ISCSI_ISID ++ case ISCSI_PARAM_ISID: ++ len = sprintf(buf, "%u", QL_ISCSI_SESSION_ID(ddb_entry)); ++ break; ++#endif + default: + return -ENOSYS; + } +@@ -221,7 +223,8 @@ static int qla4xxx_conn_get_param(struct + struct ddb_entry *ddb_entry; + int len; + +- session = iscsi_dev_to_session(conn->dev.parent); ++ session = QL_ISCSI_CONN_TO_SESS(conn); ++ + ddb_entry = session->dd_data; + + switch (param) { +@@ -240,47 +243,53 @@ static int qla4xxx_conn_get_param(struct + return len; + } + +-static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost, +- enum iscsi_tgt_dscvr type, uint32_t enable, +- struct sockaddr *dst_addr) ++static int qla4xxx_host_get_param(struct Scsi_Host *shost, ++ enum iscsi_host_param param, char *buf) + { +- struct scsi_qla_host *ha; +- struct sockaddr_in *addr; +- struct sockaddr_in6 *addr6; +- int ret = 0; +- +- ha = (struct scsi_qla_host *) shost->hostdata; +- +- switch (type) { +- case ISCSI_TGT_DSCVR_SEND_TARGETS: +- if (dst_addr->sa_family == AF_INET) { +- addr = (struct sockaddr_in *)dst_addr; +- if (qla4xxx_send_tgts(ha, (char *)&addr->sin_addr, +- addr->sin_port) != QLA_SUCCESS) +- ret = -EIO; +- } else if (dst_addr->sa_family == AF_INET6) { +- /* +- * TODO: fix qla4xxx_send_tgts +- */ +- addr6 = (struct sockaddr_in6 *)dst_addr; +- if (qla4xxx_send_tgts(ha, (char *)&addr6->sin6_addr, +- addr6->sin6_port) != QLA_SUCCESS) +- ret = -EIO; +- } else +- ret = -ENOSYS; ++ struct scsi_qla_host *ha = to_qla_host(shost); ++ int len; ++ ++ switch (param) { ++ case ISCSI_HOST_PARAM_IPADDRESS: ++ len = sprintf(buf, "%d.%d.%d.%d", ha->ip_address[0], ++ ha->ip_address[1], ha->ip_address[2], ++ ha->ip_address[3]); ++ break; ++ case ISCSI_HOST_PARAM_INITIATOR_NAME: ++ len = sprintf(buf, "%s", ha->name_string); + break; + default: +- ret = -ENOSYS; ++ return -ENOSYS; + } +- return ret; ++ ++ return len; ++} ++ ++static int ql_alloc_osindex(struct scsi_qla_host *ha) ++{ ++ unsigned int idx; ++ ++ for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) ++ if (test_and_set_bit((idx & 0x1F), &ha->os_map[(idx >> 5)]) == 0) ++ return idx; ++ return -1; ++} ++ ++static void free_osindex(struct scsi_qla_host *ha, uint32_t idx) ++{ ++ clear_bit((idx & 0x1F), &ha->os_map[idx >> 5]); + } + ++ + void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) + { + if (!ddb_entry->sess) + return; ++ free_osindex(ddb_entry->ha, ddb_entry->os_target_id); + + if (ddb_entry->conn) { ++ QL_ISCSI_IF_DESTROY_SESSION_DONE(ddb_entry); ++ QL_ISCSI_DESTROY_CONN(ddb_entry); + iscsi_remove_session(ddb_entry->sess); + } + iscsi_free_session(ddb_entry->sess); +@@ -290,25 +299,27 @@ int qla4xxx_add_sess(struct ddb_entry *d + { + int err; + +- err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); ++ err = QL_ISCSI_ADD_SESS(ddb_entry); ++ + if (err) { + DEBUG2(printk(KERN_ERR "Could not add session.\n")); + return err; + } + +- ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0, 0); ++ ddb_entry->conn = QL_ISCSI_CREATE_CONN(ddb_entry); ++ + if (!ddb_entry->conn) { + iscsi_remove_session(ddb_entry->sess); + DEBUG2(printk(KERN_ERR "Could not add connection.\n")); + return -ENOMEM; + } + +- ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; +- if (scan) +- scsi_scan_target(&ddb_entry->sess->dev, 0, +- ddb_entry->sess->target_id, +- SCAN_WILD_CARD, 0); +- iscsi_unblock_session(ddb_entry->sess); ++ ddb_entry->sess->recovery_tmo = QL_SESS_RECOVERY_TO(ddb_entry); ++ ++ qla4xxx_scan_target(ddb_entry); ++ ++ QL_ISCSI_CREATE_SESS_DONE(ddb_entry); ++ + return 0; + } + +@@ -317,13 +328,20 @@ struct ddb_entry *qla4xxx_alloc_sess(str + struct ddb_entry *ddb_entry; + struct iscsi_cls_session *sess; + +- sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport, +- sizeof(struct ddb_entry)); +- if (!sess) ++ int os_idx; ++ ++ if ((os_idx = ql_alloc_osindex(ha)) >= MAX_DDB_ENTRIES) ++ return NULL; ++ ++ sess = QL_ISCSI_ALLOC_SESSION(ha, &qla4xxx_iscsi_transport); ++ if (!sess) { ++ free_osindex(ha, os_idx); + return NULL; ++ } + + ddb_entry = sess->dd_data; + memset(ddb_entry, 0, sizeof(*ddb_entry)); ++ ddb_entry->os_target_id = os_idx; + ddb_entry->ha = ha; + ddb_entry->sess = sess; + return ddb_entry; +@@ -371,9 +389,9 @@ void qla4xxx_mark_device_missing(struct + } + + static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry, +- struct scsi_cmnd *cmd, +- void (*done)(struct scsi_cmnd *)) ++ struct ddb_entry *ddb_entry, ++ struct scsi_cmnd *cmd, ++ void (*done)(struct scsi_cmnd *)) + { + struct srb *srb; + +@@ -392,17 +410,6 @@ static struct srb* qla4xxx_get_new_srb(s + return srb; + } + +-static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) +-{ +- struct scsi_cmnd *cmd = srb->cmd; +- +- if (srb->flags & SRB_DMA_VALID) { +- scsi_dma_unmap(cmd); +- srb->flags &= ~SRB_DMA_VALID; +- } +- cmd->SCp.ptr = NULL; +-} +- + void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) + { + struct scsi_cmnd *cmd = srb->cmd; +@@ -418,14 +425,14 @@ void qla4xxx_srb_compl(struct scsi_qla_h + * qla4xxx_queuecommand - scsi layer issues scsi command to driver. + * @cmd: Pointer to Linux's SCSI command structure + * @done_fn: Function that the driver calls to notify the SCSI mid-layer +- * that the command has been processed. ++ * that the command has been processed. + * + * Remarks: + * This routine is invoked by Linux to send a SCSI command to the driver. + * The mid-level driver tries to ensure that queuecommand never gets + * invoked concurrently with itself or the interrupt handler (although + * the interrupt handler may call this routine as part of request- +- * completion handling). Unfortunely, it sometimes calls the scheduler ++ * completion handling). Unfortunely, it sometimes calls the scheduler + * in interrupt context which is a big NO! NO!. + **/ + static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, +@@ -546,7 +553,7 @@ static int qla4xxx_mem_alloc(struct scsi + align = 0; + if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) + align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & +- (MEM_ALIGN_VALUE - 1)); ++ (MEM_ALIGN_VALUE - 1)); + + /* Update request and response queue pointers. */ + ha->request_dma = ha->queues_dma + align; +@@ -554,16 +561,16 @@ static int qla4xxx_mem_alloc(struct scsi + ha->response_dma = ha->queues_dma + align + + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); + ha->response_ring = (struct queue_entry *) (ha->queues + align + +- (REQUEST_QUEUE_DEPTH * +- QUEUE_SIZE)); ++ (REQUEST_QUEUE_DEPTH * ++ QUEUE_SIZE)); + ha->shadow_regs_dma = ha->queues_dma + align + + (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + + (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); + ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + + (REQUEST_QUEUE_DEPTH * +- QUEUE_SIZE) + ++ QUEUE_SIZE) + + (RESPONSE_QUEUE_DEPTH * +- QUEUE_SIZE)); ++ QUEUE_SIZE)); + + /* Allocate memory for srb pool. */ + ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, +@@ -595,12 +602,12 @@ static void qla4xxx_timer(struct scsi_ql + list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { + /* Count down time between sending relogins */ + if (adapter_up(ha) && +- !test_bit(DF_RELOGIN, &ddb_entry->flags) && +- atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { ++ !test_bit(DF_RELOGIN, &ddb_entry->flags) && ++ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + if (atomic_read(&ddb_entry->retry_relogin_timer) != +- INVALID_ENTRY) { ++ INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) +- == 0) { ++ == 0) { + atomic_set(&ddb_entry-> + retry_relogin_timer, + INVALID_ENTRY); +@@ -608,9 +615,9 @@ static void qla4xxx_timer(struct scsi_ql + &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + DEBUG2(printk("scsi%ld: %s: index [%d]" +- " login device\n", +- ha->host_no, __func__, +- ddb_entry->fw_ddb_index)); ++ " login device\n", ++ ha->host_no, __func__, ++ ddb_entry->fw_ddb_index)); + } else + atomic_dec(&ddb_entry-> + retry_relogin_timer); +@@ -619,64 +626,64 @@ static void qla4xxx_timer(struct scsi_ql + + /* Wait for relogin to timeout */ + if (atomic_read(&ddb_entry->relogin_timer) && +- (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { ++ (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { + /* + * If the relogin times out and the device is + * still NOT ONLINE then try and relogin again. + */ + if (atomic_read(&ddb_entry->state) != +- DDB_STATE_ONLINE && +- ddb_entry->fw_ddb_device_state == +- DDB_DS_SESSION_FAILED) { ++ DDB_STATE_ONLINE && ++ ddb_entry->fw_ddb_device_state == ++ DDB_DS_SESSION_FAILED) { + /* Reset retry relogin timer */ + atomic_inc(&ddb_entry->relogin_retry_count); + DEBUG2(printk("scsi%ld: index[%d] relogin" +- " timed out-retrying" +- " relogin (%d)\n", +- ha->host_no, +- ddb_entry->fw_ddb_index, +- atomic_read(&ddb_entry-> ++ " timed out-retrying" ++ " relogin (%d)\n", ++ ha->host_no, ++ ddb_entry->fw_ddb_index, ++ atomic_read(&ddb_entry-> + relogin_retry_count)) + ); + start_dpc++; + DEBUG(printk("scsi%ld:%d:%d: index [%d] " +- "initate relogin after" +- " %d seconds\n", +- ha->host_no, ddb_entry->bus, +- ddb_entry->target, +- ddb_entry->fw_ddb_index, +- ddb_entry->default_time2wait + 4) +- ); ++ "initate relogin after" ++ " %d seconds\n", ++ ha->host_no, ddb_entry->bus, ++ ddb_entry->target, ++ ddb_entry->fw_ddb_index, ++ ddb_entry->default_time2wait + 4)); + + atomic_set(&ddb_entry->retry_relogin_timer, +- ddb_entry->default_time2wait + 4); ++ ddb_entry->default_time2wait + 4); + } + } + } + + /* Check for heartbeat interval. */ + if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && +- ha->heartbeat_interval != 0) { ++ ha->heartbeat_interval != 0) { + ha->seconds_since_last_heartbeat++; + if (ha->seconds_since_last_heartbeat > +- ha->heartbeat_interval + 2) ++ ha->heartbeat_interval + 2) + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + + + /* Wakeup the dpc routine for this adapter, if needed. */ + if ((start_dpc || +- test_bit(DPC_RESET_HA, &ha->dpc_flags) || +- test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || +- test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || +- test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || +- test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || +- test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || +- test_bit(DPC_AEN, &ha->dpc_flags)) && +- ha->dpc_thread) { ++ test_bit(DPC_RESET_HA, &ha->dpc_flags) || ++ test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || ++ test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || ++ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || ++ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || ++ test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || ++ QL_DPC_OFFLINE_SET(ha) || ++ test_bit(DPC_AEN, &ha->dpc_flags)) && ++ ha->dpc_thread) { + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" +- " - dpc flags = 0x%lx\n", +- ha->host_no, __func__, ha->dpc_flags)); ++ " - dpc flags = 0x%lx\n", ++ ha->host_no, __func__, ha->dpc_flags)); + queue_work(ha->dpc_thread, &ha->dpc_work); + } + +@@ -732,14 +739,15 @@ static int qla4xxx_cmd_wait(struct scsi_ + return stat; + } + +-void qla4xxx_hw_reset(struct scsi_qla_host *ha) ++void qla4xxx_hw_reset(struct scsi_qla_host *ha, int hw_lock) + { + uint32_t ctrl_status; + unsigned long flags = 0; + + DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); + +- spin_lock_irqsave(&ha->hardware_lock, flags); ++ if (hw_lock) ++ spin_lock_irqsave(&ha->hardware_lock, flags); + /* + * If the SCSI Reset Interrupt bit is set, clear it. + * Otherwise, the Soft Reset won't work. +@@ -752,7 +760,8 @@ void qla4xxx_hw_reset(struct scsi_qla_ho + writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + +- spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ if (hw_lock) ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + + /** +@@ -766,7 +775,7 @@ int qla4xxx_soft_reset(struct scsi_qla_h + int status = QLA_ERROR; + uint32_t ctrl_status; + +- qla4xxx_hw_reset(ha); ++ qla4xxx_hw_reset(ha, 1); + + /* Wait until the Network Reset Intr bit is cleared */ + max_wait_time = RESET_INTR_TOV; +@@ -783,9 +792,9 @@ int qla4xxx_soft_reset(struct scsi_qla_h + + if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { + DEBUG2(printk(KERN_WARNING +- "scsi%ld: Network Reset Intr not cleared by " +- "Network function, clearing it now!\n", +- ha->host_no)); ++ "scsi%ld: Network Reset Intr not cleared by " ++ "Network function, clearing it now!\n", ++ ha->host_no)); + spin_lock_irqsave(&ha->hardware_lock, flags); + writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); +@@ -881,14 +890,13 @@ static void qla4xxx_flush_active_srbs(st + * qla4xxx_recover_adapter - recovers adapter after a fatal error + * @ha: Pointer to host adapter structure. + **/ +-static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) ++static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) + { + int status; + + /* Stall incoming I/O until we are done */ + clear_bit(AF_ONLINE, &ha->flags); +- DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, +- __func__)); ++ dev_info(&ha->pdev->dev, "%s: adapter OFFLINE\n", __func__); + + /* Wait for outstanding commands to complete. + * Stalls the driver for max 30 secs +@@ -905,7 +913,7 @@ static int qla4xxx_recover_adapter(struc + */ + if (status == QLA_SUCCESS) { + DEBUG2(printk(KERN_ERR "scsi%ld: %s - Performing soft reset..\n", +- ha->host_no, __func__)); ++ ha->host_no, __func__)); + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) + status = qla4xxx_soft_reset(ha); +@@ -920,24 +928,26 @@ static int qla4xxx_recover_adapter(struc + * with ISP interrupts enabled */ + if (status == QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n", +- ha->host_no, __func__)); ++ ha->host_no, __func__)); + + /* If successful, AF_ONLINE flag set in + * qla4xxx_initialize_adapter */ ++ if (ha->mac_index == 3) ++ ssleep(6); + status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST); + } + + /* Failed adapter initialization? + * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */ + if ((test_bit(AF_ONLINE, &ha->flags) == 0) && +- (test_bit(DPC_RESET_HA, &ha->dpc_flags))) { ++ (test_bit(DPC_RESET_HA, &ha->dpc_flags))) { + /* Adapter initialization failed, see if we can retry + * resetting the ha */ + if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { + ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; + DEBUG2(printk("scsi%ld: recover adapter - retrying " +- "(%d) more times\n", ha->host_no, +- ha->retry_reset_ha_cnt)); ++ "(%d) more times\n", ha->host_no, ++ ha->retry_reset_ha_cnt)); + set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); + status = QLA_ERROR; + } else { +@@ -945,9 +955,9 @@ static int qla4xxx_recover_adapter(struc + /* Schedule another Reset HA--DPC will retry */ + ha->retry_reset_ha_cnt--; + DEBUG2(printk("scsi%ld: recover adapter - " +- "retry remaining %d\n", +- ha->host_no, +- ha->retry_reset_ha_cnt)); ++ "retry remaining %d\n", ++ ha->host_no, ++ ha->retry_reset_ha_cnt)); + status = QLA_ERROR; + } + +@@ -955,8 +965,8 @@ static int qla4xxx_recover_adapter(struc + /* Recover adapter retries have been exhausted. + * Adapter DEAD */ + DEBUG2(printk("scsi%ld: recover adapter " +- "failed - board disabled\n", +- ha->host_no)); ++ "failed - board disabled\n", ++ ha->host_no)); + qla4xxx_flush_active_srbs(ha); + clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA, &ha->dpc_flags); +@@ -991,10 +1001,9 @@ static int qla4xxx_recover_adapter(struc + * the mid-level tries to sleep when it reaches the driver threshold + * "host->can_queue". This can cause a panic if we were in our interrupt code. + **/ +-static void qla4xxx_do_dpc(struct work_struct *work) ++static QL_DECLARE_DPC(qla4xxx_do_dpc, data) + { +- struct scsi_qla_host *ha = +- container_of(work, struct scsi_qla_host, dpc_work); ++ struct scsi_qla_host *ha = QL_DPC_DATA_TO_HA(data); + struct ddb_entry *ddb_entry, *dtemp; + int status = QLA_ERROR; + +@@ -1009,11 +1018,11 @@ static void qla4xxx_do_dpc(struct work_s + return; + + if (adapter_up(ha) || +- test_bit(DPC_RESET_HA, &ha->dpc_flags) || +- test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || +- test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { ++ test_bit(DPC_RESET_HA, &ha->dpc_flags) || ++ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || ++ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { + if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || +- test_bit(DPC_RESET_HA, &ha->dpc_flags)) ++ test_bit(DPC_RESET_HA, &ha->dpc_flags)) + qla4xxx_recover_adapter(ha); + + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { +@@ -1025,14 +1034,15 @@ static void qla4xxx_do_dpc(struct work_s + break; + msleep(1000); + } ++ + if (wait_time == 0) + DEBUG2(printk("scsi%ld: %s: SR|FSR " +- "bit not cleared-- resetting\n", +- ha->host_no, __func__)); ++ "bit not cleared-- resetting\n", ++ ha->host_no, __func__)); + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); +- status = qla4xxx_initialize_adapter(ha, ++ status = qla4xxx_initialize_adapter(ha, + PRESERVE_DDB_LIST); + } + clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); +@@ -1049,13 +1059,42 @@ static void qla4xxx_do_dpc(struct work_s + if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) + qla4xxx_get_dhcp_ip_address(ha); + ++ qla4xxx_check_dev_offline(ha); ++ ++ if (test_and_clear_bit(DPC_DELETE_DEVICE, &ha->dpc_flags)) { ++ list_for_each_entry_safe(ddb_entry, dtemp, ++ &ha->ddb_list, list) { ++ if (test_and_clear_bit(DF_DELETED, ++ &ddb_entry->flags)) { ++ if (atomic_read(&ddb_entry->state) == ++ DDB_STATE_DEAD) { ++ dev_info(&ha->pdev->dev, ++ "%s: ddb[%d] os[%d] - " ++ "delete\n", ++ __func__, ++ ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ } else { ++ dev_info(&ha->pdev->dev, ++ "%s: ddb[%d] os[%d] - " ++ "ddb state not dead but" ++ " marked for delete\n", ++ __func__, ++ ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ } ++ } ++ } ++ } ++ + /* ---- relogin device? --- */ + if (adapter_up(ha) && +- test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { ++ test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { + list_for_each_entry_safe(ddb_entry, dtemp, + &ha->ddb_list, list) { + if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && +- atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) ++ (atomic_read(&ddb_entry->state) != ++ DDB_STATE_ONLINE)) + qla4xxx_relogin_device(ha, ddb_entry); + + /* +@@ -1092,7 +1131,7 @@ static void qla4xxx_free_adapter(struct + + /* Issue Soft Reset to put firmware in unknown state */ + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) +- qla4xxx_hw_reset(ha); ++ qla4xxx_hw_reset(ha, 1); + + /* Remove timer thread, if present */ + if (ha->timer_active) +@@ -1142,6 +1181,7 @@ static int qla4xxx_iospace_config(struct + if (!(mmio_flags & IORESOURCE_MEM)) { + dev_err(&ha->pdev->dev, + "region #0 not an MMIO resource, aborting\n"); ++ + goto iospace_error_exit; + } + if (mmio_len < MIN_IOBASE_LEN) { +@@ -1173,14 +1213,6 @@ iospace_error_exit: + return -ENOMEM; + } + +-static void ql4_get_aen_log(struct scsi_qla_host *ha, struct ql4_aen_log *aenl) +-{ +- if (aenl) { +- memcpy(aenl, &ha->aen_log, sizeof (ha->aen_log)); +- ha->aen_log.count = 0; +- } +-} +- + /** + * qla4xxx_probe_adapter - callback function to probe HBA + * @pdev: pointer to pci_dev structure +@@ -1191,7 +1223,7 @@ static void ql4_get_aen_log(struct scsi_ + * the driver. + **/ + static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, +- const struct pci_device_id *ent) ++ const struct pci_device_id *ent) + { + int ret = -ENODEV, status; + struct Scsi_Host *host; +@@ -1206,7 +1238,7 @@ static int __devinit qla4xxx_probe_adapt + host = scsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha)); + if (host == NULL) { + printk(KERN_WARNING +- "qla4xxx: Couldn't allocate host from scsi layer!\n"); ++ "qla4xxx: Couldn't allocate host from scsi layer!\n"); + goto probe_disable_device; + } + +@@ -1218,10 +1250,7 @@ static int __devinit qla4xxx_probe_adapt + ha->pdev = pdev; + ha->host = host; + ha->host_no = host->host_no; +- +- ha->ql4mbx = qla4xxx_mailbox_command; +- ha->ql4cmd = qla4xxx_send_command_to_isp; +- ha->ql4getaenlog = ql4_get_aen_log; ++ set_bit(AF_OS_INDEX_VALID, &ha->flags); + + /* Configure PCI I/O space. */ + ret = qla4xxx_iospace_config(ha); +@@ -1229,7 +1258,7 @@ static int __devinit qla4xxx_probe_adapt + goto probe_failed; + + dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n", +- pdev->device, pdev->irq, ha->reg); ++ pdev->device, pdev->irq, ha->reg); + + qla4xxx_config_dma_addressing(ha); + +@@ -1245,7 +1274,7 @@ static int __devinit qla4xxx_probe_adapt + /* Allocate dma buffers */ + if (qla4xxx_mem_alloc(ha)) { + dev_warn(&ha->pdev->dev, +- "[ERROR] Failed to allocate memory for adapter\n"); ++ "[ERROR] Failed to allocate memory for adapter\n"); + + ret = -ENOMEM; + goto probe_failed; +@@ -1258,8 +1287,8 @@ static int __devinit qla4xxx_probe_adapt + */ + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); + while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) { +- DEBUG2(printk(KERN_ERR "scsi%ld: %s: retrying adapter initialization " +- "(%d)\n", ha->host_no, __func__, init_retry_count)); ++ DEBUG2(dev_info(&ha->pdev->dev, "%s: retry adapter init %d\n", ++ __func__, init_retry_count)); + qla4xxx_soft_reset(ha); + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); + } +@@ -1280,7 +1309,7 @@ static int __devinit qla4xxx_probe_adapt + + /* Startup the kernel thread for this host adapter. */ + DEBUG2(printk("scsi: %s: Starting kernel thread for " +- "qla4xxx_dpc\n", __func__)); ++ "qla4xxx_dpc\n", __func__)); + sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); + ha->dpc_thread = create_singlethread_workqueue(buf); + if (!ha->dpc_thread) { +@@ -1288,9 +1317,11 @@ static int __devinit qla4xxx_probe_adapt + ret = -ENODEV; + goto probe_failed; + } +- INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); ++ QL_INIT_WORK(ha, qla4xxx_do_dpc); ++ + ret = request_irq(pdev->irq, qla4xxx_intr_handler, +- IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); ++ QL_REQ_IRQ_FLAGS, "qla4xxx", ha); ++ + if (ret) { + dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" + " already in use.\n", pdev->irq); +@@ -1298,7 +1329,7 @@ static int __devinit qla4xxx_probe_adapt + } + set_bit(AF_IRQ_ATTACHED, &ha->flags); + host->irq = pdev->irq; +- DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq)); ++ dev_info(&ha->pdev->dev, "irq %d attached\n", ha->pdev->irq); + + qla4xxx_enable_intrs(ha); + +@@ -1313,6 +1344,9 @@ static int __devinit qla4xxx_probe_adapt + if (ret) + goto probe_failed; + ++ if ((ret = QL_ISCSI_REGISTER_HOST(host, qla4xxx_scsi_transport))) ++ goto remove_host; ++ + /* Update transport device information for all devices. */ + list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { + +@@ -1320,25 +1354,36 @@ static int __devinit qla4xxx_probe_adapt + set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); + + if (qla4xxx_add_sess(ddb_entry, +- test_bit(DF_SCAN_ISSUED, &ddb_entry->flags))) ++ test_bit(DF_SCAN_ISSUED, &ddb_entry->flags))) { ++ QL_ISCSI_UNREGISTER_HOST(host, qla4xxx_scsi_transport); + goto remove_host; ++ } + if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) + qla4xxx_mark_device_missing(ha, ddb_entry); + } + +- printk(KERN_INFO +- " QLogic iSCSI HBA Driver version: %s\n" +- " QLogic ISP%04x @ %s, pdev = %p host#=%ld, fw=%02d.%02d.%02d.%02d\n", +- qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), pdev, +- ha->host_no, ha->firmware_version[0], ha->firmware_version[1], +- ha->patch_number, ha->build_number); ++ dev_info(&ha->pdev->dev, " QLogic iSCSI HBA Driver version: %s\n" ++ " QLogic ISP%04x @ %s, pdev = %p host#=%ld," ++ " fw=%02d.%02d.%02d.%02d\n", qla4xxx_version_str, ++ ha->pdev->device, pci_name(ha->pdev), pdev, ++ ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ++ ha->patch_number, ha->build_number); + + /* Insert new entry into the list of adapters. */ + klist_add_tail(&ha->node, &qla4xxx_hostlist); + ha->instance = atomic_inc_return(&qla4xxx_hba_count) - 1; + +- DEBUG2(printk("qla4xxx: listhead=%p, done adding ha=%p i=%d\n", +- &qla4xxx_hostlist, &ha->node, ha->instance)); ++ if (qla4xxx_ioctl_init(ha)) { ++ dev_info(&ha->pdev->dev, "ioctl init failed\n"); ++ QL_ISCSI_UNREGISTER_HOST(host, qla4xxx_scsi_transport); ++ goto remove_host; ++ } ++ ++ DEBUG2(dev_info(&ha->pdev->dev, "listhead=%p, done adding ha=%p i=%d\n", ++ &qla4xxx_hostlist, &ha->node, ha->instance)); ++ ++// set_bit(AF_INIT_DONE, &ha->flags); ++ dev_info(&ha->pdev->dev, "%s: AF_INIT_DONE\n", __func__); + + return 0; + +@@ -1377,8 +1422,12 @@ static void __devexit qla4xxx_remove_ada + /* remove devs from iscsi_sessions to scsi_devices */ + qla4xxx_free_ddb_list(ha); + ++ QL_ISCSI_UNREGISTER_HOST(ha->host, qla4xxx_scsi_transport); ++ + scsi_remove_host(ha->host); + ++ qla4xxx_ioctl_exit(ha); ++ + qla4xxx_free_adapter(ha); + + scsi_host_put(ha->host); +@@ -1393,7 +1442,7 @@ static void __devexit qla4xxx_remove_ada + * At exit, the @ha's flags.enable_64bit_addressing set to indicated + * supported addressing method. + */ +-static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) ++void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) + { + int retval; + +@@ -1402,9 +1451,9 @@ static void qla4xxx_config_dma_addressin + if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { + dev_dbg(&ha->pdev->dev, + "Failed to set 64 bit PCI consistent mask; " +- "using 32 bit.\n"); ++ "using 32 bit.\n"); + retval = pci_set_consistent_dma_mask(ha->pdev, +- DMA_32BIT_MASK); ++ DMA_32BIT_MASK); + } + } else + retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); +@@ -1412,7 +1461,7 @@ static void qla4xxx_config_dma_addressin + + static int qla4xxx_slave_alloc(struct scsi_device *sdev) + { +- struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); ++ struct iscsi_cls_session *sess = QL_ISCSI_SDEV_TO_SESS(sdev); + + if (sess) { + sdev->hostdata = sess->dd_data; +@@ -1431,6 +1480,11 @@ static int qla4xxx_slave_configure(struc + return 0; + } + ++static void qla4xxx_slave_destroy(struct scsi_device *sdev) ++{ ++ sdev->hostdata = NULL; ++} ++ + /** + * qla4xxx_del_from_active_array - returns an active srb + * @ha: Pointer to host adapter structure. +@@ -1470,7 +1524,7 @@ struct srb * qla4xxx_del_from_active_arr + * for some max time. + **/ + static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, +- struct scsi_cmnd *cmd) ++ struct scsi_cmnd *cmd) + { + int done = 0; + struct srb *rp; +@@ -1564,8 +1618,8 @@ static int qla4xxx_eh_device_reset(struc + return ret; + + dev_info(&ha->pdev->dev, +- "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, +- cmd->device->channel, cmd->device->id, cmd->device->lun); ++ "%s: %d:%d:%d: DEVICE RESET ISSUED.\n", __func__, ++ cmd->device->channel, cmd->device->id, cmd->device->lun); + + if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { + dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__); +@@ -1584,12 +1638,12 @@ static int qla4xxx_eh_device_reset(struc + */ + if (cmd->device->host->shost_state == SHOST_RECOVERY) { + if (qla4xxx_eh_wait_for_active_target_commands(ha, +- cmd->device->id, +- cmd->device-> +- lun)) { ++ cmd->device->id, ++ cmd->device-> ++ lun)) { + dev_info(&ha->pdev->dev, +- "DEVICE RESET FAILED - waiting for " +- "commands.\n"); ++ "DEVICE RESET FAILED - waiting for " ++ "commands.\n"); + goto eh_dev_reset_done; + } + } +@@ -1598,9 +1652,9 @@ static int qla4xxx_eh_device_reset(struc + goto eh_dev_reset_done; + + dev_info(&ha->pdev->dev, +- "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", +- ha->host_no, cmd->device->channel, cmd->device->id, +- cmd->device->lun); ++ "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", ++ ha->host_no, cmd->device->channel, cmd->device->id, ++ cmd->device->lun); + + ret = SUCCESS; + +@@ -1635,7 +1689,7 @@ static int qla4xxx_eh_host_reset(struct + } + + dev_info(&ha->pdev->dev, "HOST RESET %s.\n", +- return_status == FAILED ? "FAILED" : "SUCCEDED"); ++ return_status == FAILED ? "FAILED" : "SUCCEDED"); + + return return_status; + } +@@ -1664,7 +1718,7 @@ static struct pci_device_id qla4xxx_pci_ + }; + MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); + +-static struct pci_driver qla4xxx_pci_driver = { ++struct pci_driver qla4xxx_pci_driver = { + .name = DRIVER_NAME, + .id_table = qla4xxx_pci_tbl, + .probe = qla4xxx_probe_adapter, +@@ -1678,12 +1732,11 @@ static int __init qla4xxx_module_init(vo + atomic_set(&qla4xxx_hba_count, 0); + klist_init(&qla4xxx_hostlist, NULL, NULL); + /* Allocate cache for SRBs. */ +- srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, +- SLAB_HWCACHE_ALIGN, NULL); ++ srb_cachep = ql_kmem_cache_create(); ++ + if (srb_cachep == NULL) { +- printk(KERN_ERR +- "%s: Unable to allocate SRB cache..." +- "Failing load!\n", DRIVER_NAME); ++ printk(KERN_ERR "%s: Unable to allocate SRB cache..." ++ "Failing load!\n", DRIVER_NAME); + ret = -ENOMEM; + goto no_srp_cache; + } +@@ -1700,7 +1753,14 @@ static int __init qla4xxx_module_init(vo + goto release_srb_cache; + } + ++ ret = QL_MISC_INIT; ++ if (ret) { ++ printk(KERN_INFO "QLogic iSCSI HBA Driver ioctl init failed\n"); ++ goto unregister_transport; ++ } ++ + printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); ++ + ret = pci_register_driver(&qla4xxx_pci_driver); + if (ret) + goto unregister_transport; +@@ -1718,6 +1778,9 @@ no_srp_cache: + static void __exit qla4xxx_module_exit(void) + { + ql4_mod_unload = 1; ++ ++ QL_MISC_EXIT; ++ + pci_unregister_driver(&qla4xxx_pci_driver); + iscsi_unregister_transport(&qla4xxx_iscsi_transport); + kmem_cache_destroy(srb_cachep); +--- /dev/null ++++ b/drivers/scsi/qla4xxx/ql4_os.h +@@ -0,0 +1,125 @@ ++/* ++ * QLogic iSCSI HBA Driver ++ * Copyright (c) 2003-2006 QLogic Corporation ++ * ++ * See LICENSE.qla4xxx for copyright and licensing details. ++ */ ++ ++/* ++ * This file encapsulates RHEL5 Specific Code ++ */ ++ ++#ifndef __QLA4x_OS_H ++#define __QLA4x_OS_H ++ ++/* Common across all O.S platforms */ ++#define IOCB_CMD_TIMEOUT 30 ++#define RELOGIN_TOV 18 ++#define RECOVERY_TIMEOUT 20 /* ddb state MISSING -> DEAD */ ++ ++#define QL_IOCB_CMD_TIMEOUT(cmd) ++ ++#define QL_SET_DDB_OFFLINE(ha, ddb_entry) ++ ++#define QL_SESS_RECOVERY_TO(ddb_entry) ddb_entry->ha->port_down_retry_count ++ ++#define QL_DPC_OFFLINE_SET(ha) 0 ++ ++#define QL_ISCSI_CONN_TO_SESS(conn) iscsi_dev_to_session(conn->dev.parent) ++ ++#define QL_ISCSI_SDEV_TO_SESS(sdev) starget_to_session(sdev->sdev_target) ++ ++#define QL_ISCSI_ADD_SESS(ddb_entry) \ ++ iscsi_add_session(ddb_entry->sess, ddb_entry->os_target_id) ++ ++#define QL_ISCSI_REGISTER_HOST(host, trans) 0 ++#define QL_ISCSI_UNREGISTER_HOST(host, trans) ++ ++#define QL_ISCSI_SESSION_ID(ddb_entry) ddb_entry->sess->sid ++#define QL_ISCSI_IF_DESTROY_SESSION_DONE(ddb_entry) ++#define QL_ISCSI_DESTROY_CONN(ddb_entry) ++#define QL_ISCSI_CREATE_CONN(ddb_entry) \ ++ iscsi_create_conn(ddb_entry->sess, 0, 0) ++#define QL_ISCSI_CREATE_SESS_DONE(ddb_entry) \ ++ iscsi_unblock_session(ddb_entry->sess) ++#define QL_ISCSI_ALLOC_SESSION(ha, trans) \ ++ iscsi_alloc_session(ha->host, trans, sizeof(struct ddb_entry)) ++ ++ ++#define QL_MISC_INIT 0 ++#define QL_MISC_EXIT ++ ++#define qla4xxx_check_dev_offline(ha) ++#define qla4xxx_proc_info NULL ++ ++#define QL_SET_SCSI_RESID(cmd, residual) scsi_set_resid(cmd, residual) ++#define QL_SCSI_BUFFLEN(cmd) scsi_bufflen(cmd) ++ ++#define QL_DPC_DATA_TO_HA(work) \ ++ container_of((struct work_struct *)work, struct scsi_qla_host, dpc_work) ++ ++#define QL_INIT_WORK(ha, dpc_func) INIT_WORK(&ha->dpc_work, dpc_func) ++ ++#define QL_REQ_IRQ_FLAGS (IRQF_DISABLED | IRQF_SHARED) ++ ++#define QL_DECLARE_INTR_HANDLER(intr_func, irq, dev_id, regs) \ ++ irqreturn_t intr_func(int irq, void *dev_id) ++ ++#define QL_DECLARE_DPC(dpc_func, data) \ ++ void dpc_func(struct work_struct *data) ++ ++#define QL_INIT_SESSION_DATASIZE(sessiondata_size) ++// .sessiondata_size = sizeof(struct ddb_entry), ++ ++#define QL_INIT_HOST_TEMPLATE(host_template) ++// .host_template = &qla4xxx_driver_template, ++ ++QL_DECLARE_INTR_HANDLER(qla4xxx_intr_handler, irq, dev_id, regs); ++ ++static inline struct kmem_cache *ql_kmem_cache_create(void) ++{ ++ return (kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, ++ SLAB_HWCACHE_ALIGN, NULL)); ++} ++ ++static inline void qla4xxx_scan_target(struct ddb_entry * ddb_entry) ++{ ++ scsi_scan_target(&ddb_entry->sess->dev, 0, ++ ddb_entry->sess->target_id, SCAN_WILD_CARD, 0); ++} ++ ++static void ql4_get_aen_log(struct scsi_qla_host *ha, struct ql4_aen_log *aenl) ++{ ++ if (aenl) { ++ memcpy(aenl, &ha->aen_log, sizeof (ha->aen_log)); ++ ha->aen_log.count = 0; ++ } ++} ++ ++static inline int qla4xxx_ioctl_init(struct scsi_qla_host *ha) ++{ ++ ha->ql4mbx = qla4xxx_mailbox_command; ++ ha->ql4cmd = qla4xxx_send_command_to_isp; ++ ha->ql4getaenlog = ql4_get_aen_log; ++ return 0; ++} ++ ++static inline void qla4xxx_ioctl_exit(struct scsi_qla_host *ha) ++{ ++ return; ++} ++ ++static inline void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, ++ struct srb *srb) ++{ ++ struct scsi_cmnd *cmd = srb->cmd; ++ ++ if (srb->flags & SRB_DMA_VALID) { ++ scsi_dma_unmap(cmd); ++ srb->flags &= ~SRB_DMA_VALID; ++ } ++ ++ cmd->SCp.ptr = NULL; ++} ++ ++#endif /* _QLA4x_OS_H */ +--- a/drivers/scsi/qla4xxx/ql4_version.h ++++ b/drivers/scsi/qla4xxx/ql4_version.h +@@ -5,6 +5,5 @@ + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-01" +- ++#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-03" + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-5.01.00-k8_sles11-04-update b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-5.01.00-k8_sles11-04-update new file mode 100644 index 000000000..473e3db30 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-5.01.00-k8_sles11-04-update @@ -0,0 +1,491 @@ +From: David Somayajulu +Subject: qla4xxx driver SLES 11 Beta6 update +References: bnc#458186 + +This updates the qla4xxx driver with the following bug fixes: +1. Fix the handling of qla4xxx firmware Device DataBase Entry removal. +2. Fix the pass thru scsi_cmnd handling. This prevented our + configuration tool SanSurfer from operating properly. +3. updates version to 5.01.00-k8_sles11-04 + +and quite some whitespace fixes. + +Signed-off-by: David Somayajulu +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h +index 5764a25..2b5af89 100644 +--- a/drivers/scsi/qla4xxx/ql4_def.h ++++ b/drivers/scsi/qla4xxx/ql4_def.h +@@ -144,7 +144,6 @@ + #define RESET_FIRMWARE_TOV 30 + #define LOGOUT_TOV 10 + #define IOCB_TOV_MARGIN 10 +-#define ISNS_DEREG_TOV 5 + + #define MAX_RESET_HA_RETRIES 2 + +@@ -232,6 +231,8 @@ struct ddb_entry { + uint8_t ip_addr[ISCSI_IPADDR_SIZE]; + uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */ + uint8_t iscsi_alias[0x20]; ++ uint8_t isid[6]; ++ uint8_t rsrvd[2]; + }; + + /* +@@ -243,6 +244,8 @@ struct ddb_entry { + * commands */ + #define DDB_STATE_MISSING 2 /* Device logged off, trying + * to re-login */ ++#define DDB_STATE_REMOVED 3 /* The fw ddb_entry is freed ++ * the session can be destroyed */ + + /* + * DDB flags. +@@ -252,7 +255,7 @@ struct ddb_entry { + * logged it out */ + #define DF_SCAN_ISSUED 2 + #define DF_OFFLINE 3 /* Offline Device */ +-#define DF_DELETED 4 /* Device has been removed */ ++#define DF_REMOVE 4 /* FW DDB is destroyed */ + + /* + * Asynchronous Event Queue structure +@@ -305,11 +308,10 @@ struct scsi_qla_host { + #define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */ + #define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */ + #define DPC_RESET_HA_INTR 5 /* 0x00000020 */ +-#define DPC_ISNS_RESTART 7 /* 0x00000080 */ + #define DPC_AEN 9 /* 0x00000200 */ + #define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ + #define DPC_OFFLINE_DEVICE 16 /* 0x00010000 */ +-#define DPC_DELETE_DEVICE 17 /* 0x00020000 */ ++#define DPC_REMOVE_DEVICE 17 /* 0x00020000 */ + + uint16_t iocb_cnt; + uint16_t iocb_hiwat; +diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c +index 3b38d79..cc17469 100644 +--- a/drivers/scsi/qla4xxx/ql4_init.c ++++ b/drivers/scsi/qla4xxx/ql4_init.c +@@ -14,7 +14,7 @@ + + /* link auto negotiation normally takes roughly 2s. */ + /* If we don't have link in 3 times that period quit. */ +-#define QLA4XXX_LINK_UP_DELAY 6 ++#define QLA4XXX_LINK_UP_DELAY 6 + + /* + * QLogic ISP4xxx Hardware Support Function Prototypes. +@@ -63,8 +63,10 @@ void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) + list_del_init(&ddb_entry->list); + + /* Remove device pointer from index mapping arrays */ +- ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = NULL; +- ha->tot_ddbs--; ++ if (!QL_DDB_STATE_REMOVED(ddb_entry)) { ++ ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = NULL; ++ ha->tot_ddbs--; ++ } + + /* Free memory and scsi-ml struct for device entry */ + qla4xxx_destroy_sess(ddb_entry); +@@ -267,14 +269,6 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) + (ha->addl_fw_state & + FW_ADDSTATE_LINK_UP) != 0 ? + "UP" : "DOWN")); +- DEBUG2(dev_info(&ha->pdev->dev, +- "scsi%ld: %s: iSNS Service " +- "Started %s\n", +- ha->host_no, __func__, +- (ha->addl_fw_state & +- FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? +- "YES" : "NO")); +- + ready = 1; + break; + } +@@ -341,6 +335,7 @@ static void qla4xxx_fill_ddb(struct ddb_entry *ddb_entry, + + ddb_entry->port = le16_to_cpu(fw_ddb_entry->port); + ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); ++ memcpy(ddb_entry->isid, fw_ddb_entry->isid, sizeof(ddb_entry->isid)); + memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], + min(sizeof(ddb_entry->iscsi_name), + sizeof(fw_ddb_entry->iscsi_name))); +@@ -396,7 +391,7 @@ struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + * @ha: Pointer to host adapter structure. + * + * This routine searches for all valid firmware ddb entries and builds +- * an internal ddb list. Ddbs that are considered valid are those with ++ * an internal ddb list. Ddbs that are considered valid are those with + * a device state of SESSION_ACTIVE. + **/ + static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) +@@ -486,19 +481,6 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + ddb_entry->fw_ddb_device_state = ddb_state; + +- if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { +- atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); +- dev_info(&ha->pdev->dev, +- "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", +- ha->host_no, __func__, ddb_entry->fw_ddb_index, +- ddb_entry->os_target_id); +- } else { +- atomic_set(&ddb_entry->state, DDB_STATE_MISSING); +- dev_info(&ha->pdev->dev, +- "scsi%ld: %s: ddb[%d] os[%d] marked MISSING\n", +- ha->host_no, __func__, ddb_entry->fw_ddb_index, +- ddb_entry->os_target_id); +- } + DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d State %04x" + " ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__, + fw_ddb_index, ddb_entry->os_target_id, ddb_state, conn_err, +@@ -714,7 +696,7 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) + } + + /** +- * qla4xxx_update_ddb_list - update the driver ddb list ++ * qla4xxx_reinitialize_ddb_list - update the driver ddb list + * @ha: pointer to host adapter structure. + * + * This routine obtains device information from the F/W database after +@@ -735,11 +717,12 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha) + + /* Update the device information for all devices. */ + list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) { +- if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, +- fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL, +- &ddb_entry->fw_ddb_device_state, NULL, +- &ddb_entry->tcp_source_port_num, +- &ddb_entry->connection_id) == QLA_SUCCESS) { ++ if (!QL_DDB_STATE_REMOVED(ddb_entry) && ++ (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, ++ fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL, ++ &ddb_entry->fw_ddb_device_state, NULL, ++ &ddb_entry->tcp_source_port_num, ++ &ddb_entry->connection_id) == QLA_SUCCESS)) { + + qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); + +@@ -1192,8 +1175,13 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, + } + + list_for_each_entry(ddb_entry, &ha->ddb_list, list) { +- if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name, +- ISCSI_NAME_SIZE) == 0) { ++ if ((memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name, ++ ISCSI_NAME_SIZE) == 0) && ++ (ddb_entry->tpgt == ++ le32_to_cpu(fw_ddb_entry->tgt_portal_grp)) && ++ (memcmp(ddb_entry->isid, fw_ddb_entry->isid, ++ sizeof(ddb_entry->isid)) == 0) && ++ !QL_DDB_STATE_REMOVED(ddb_entry)) { + found = 1; + + DEBUG6(dev_info(&ha->pdev->dev, "%s found target ddb = 0x%p" +diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h +index bdf2475..a93b817 100644 +--- a/drivers/scsi/qla4xxx/ql4_inline.h ++++ b/drivers/scsi/qla4xxx/ql4_inline.h +@@ -55,8 +55,8 @@ static inline void qla4xxx_check_for_clear_ddb(struct scsi_qla_host *ha, + dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] freed\n", + __func__, ddb_entry->fw_ddb_index, + ddb_entry->os_target_id); +- set_bit(DF_DELETED, &ddb_entry->flags); +- set_bit(DPC_DELETE_DEVICE, &ha->dpc_flags); ++ set_bit(DF_REMOVE, &ddb_entry->flags); ++ set_bit(DPC_REMOVE_DEVICE, &ha->dpc_flags); + queue_work(ha->dpc_thread, &ha->dpc_work); + } + } +diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c +index bfe4d1e..67071d6 100644 +--- a/drivers/scsi/qla4xxx/ql4_iocb.c ++++ b/drivers/scsi/qla4xxx/ql4_iocb.c +@@ -27,12 +27,6 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb, + cmd = srb->cmd; + ha = srb->ha; + +- if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { +- /* No data being transferred */ +- cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0); +- return; +- } +- + avail_dsds = COMMAND_SEG; + cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); + +@@ -43,6 +37,12 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb, + return; + } + ++ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { ++ /* No data being transferred */ ++ cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0); ++ return; ++ } ++ + scsi_for_each_sg(cmd, sg, tot_dsds, i) { + dma_addr_t sle_dma; + +@@ -155,7 +155,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + + int_to_scsilun(cmd->device->lun, &cmd_entry->lun); + cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn); +- cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd)); ++ + memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len); + cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds); + cmd_entry->hdr.entryCount = req_cnt; +@@ -165,6 +165,9 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + * transferred, as the data direction bit is sometimed filled + * in when there is no data to be transferred */ + cmd_entry->control_flags = CF_NO_DATA; ++ ++ cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd)); ++ + if (scsi_bufflen(cmd)) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) + cmd_entry->control_flags = CF_WRITE; +@@ -203,7 +206,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + wmb(); + + /* +- * Check to see if adapter is online before placing request on ++ * Check to see if adapter is online before placing request on + * request queue. If a reset occurs and a request is in the queue, + * the firmware will still attempt to process the request, retrieving + * garbage for pointers. +@@ -243,4 +246,3 @@ queuing_error: + + return QLA_ERROR; + } +- +diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c +index 2efcc20..a5cd40d 100644 +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -111,6 +111,8 @@ static struct scsi_host_template qla4xxx_driver_template = { + .slave_alloc = qla4xxx_slave_alloc, + .slave_destroy = qla4xxx_slave_destroy, + ++ .target_destroy = qla4xxx_target_destroy, ++ + .this_id = -1, + .cmd_per_lun = 3, + .use_clustering = ENABLE_CLUSTERING, +@@ -290,7 +292,8 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) + if (ddb_entry->conn) { + QL_ISCSI_IF_DESTROY_SESSION_DONE(ddb_entry); + QL_ISCSI_DESTROY_CONN(ddb_entry); +- iscsi_remove_session(ddb_entry->sess); ++ if (!QL_DDB_STATE_REMOVED(ddb_entry)) ++ iscsi_remove_session(ddb_entry->sess); + } + iscsi_free_session(ddb_entry->sess); + } +@@ -385,7 +388,8 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, + dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked MISSING\n", + __func__, ddb_entry->fw_ddb_index, ddb_entry->os_target_id); + +- qla4xxx_conn_stop(ddb_entry->conn, STOP_CONN_RECOVER); ++ if (ddb_entry->conn) ++ qla4xxx_conn_stop(ddb_entry->conn, STOP_CONN_RECOVER); + } + + static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, +@@ -444,7 +448,8 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, + int rval; + + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { +- if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { ++ if ((atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) || ++ QL_DDB_STATE_REMOVED(ddb_entry)) { + cmd->result = DID_NO_CONNECT << 16; + goto qc_fail_command; + } +@@ -602,8 +607,9 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) + list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { + /* Count down time between sending relogins */ + if (adapter_up(ha) && +- !test_bit(DF_RELOGIN, &ddb_entry->flags) && +- atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { ++ !test_bit(DF_RELOGIN, &ddb_entry->flags) && ++ !QL_DDB_STATE_REMOVED(ddb_entry) && ++ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + if (atomic_read(&ddb_entry->retry_relogin_timer) != + INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) +@@ -626,15 +632,16 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) + + /* Wait for relogin to timeout */ + if (atomic_read(&ddb_entry->relogin_timer) && +- (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { ++ (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { + /* + * If the relogin times out and the device is + * still NOT ONLINE then try and relogin again. + */ + if (atomic_read(&ddb_entry->state) != +- DDB_STATE_ONLINE && +- ddb_entry->fw_ddb_device_state == +- DDB_DS_SESSION_FAILED) { ++ DDB_STATE_ONLINE && ++ !QL_DDB_STATE_REMOVED(ddb_entry) && ++ ddb_entry->fw_ddb_device_state == ++ DDB_DS_SESSION_FAILED) { + /* Reset retry relogin timer */ + atomic_inc(&ddb_entry->relogin_retry_count); + DEBUG2(printk("scsi%ld: index[%d] relogin" +@@ -678,6 +685,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) + test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || ++ test_bit(DPC_REMOVE_DEVICE, &ha->dpc_flags) || + QL_DPC_OFFLINE_SET(ha) || + test_bit(DPC_AEN, &ha->dpc_flags)) && + ha->dpc_thread) { +@@ -1061,31 +1069,7 @@ static QL_DECLARE_DPC(qla4xxx_do_dpc, data) + + qla4xxx_check_dev_offline(ha); + +- if (test_and_clear_bit(DPC_DELETE_DEVICE, &ha->dpc_flags)) { +- list_for_each_entry_safe(ddb_entry, dtemp, +- &ha->ddb_list, list) { +- if (test_and_clear_bit(DF_DELETED, +- &ddb_entry->flags)) { +- if (atomic_read(&ddb_entry->state) == +- DDB_STATE_DEAD) { +- dev_info(&ha->pdev->dev, +- "%s: ddb[%d] os[%d] - " +- "delete\n", +- __func__, +- ddb_entry->fw_ddb_index, +- ddb_entry->os_target_id); +- } else { +- dev_info(&ha->pdev->dev, +- "%s: ddb[%d] os[%d] - " +- "ddb state not dead but" +- " marked for delete\n", +- __func__, +- ddb_entry->fw_ddb_index, +- ddb_entry->os_target_id); +- } +- } +- } +- } ++ qla4xxx_remove_device(ha); + + /* ---- relogin device? --- */ + if (adapter_up(ha) && +@@ -1093,6 +1077,7 @@ static QL_DECLARE_DPC(qla4xxx_do_dpc, data) + list_for_each_entry_safe(ddb_entry, dtemp, + &ha->ddb_list, list) { + if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && ++ !QL_DDB_STATE_REMOVED(ddb_entry) && + (atomic_read(&ddb_entry->state) != + DDB_STATE_ONLINE)) + qla4xxx_relogin_device(ha, ddb_entry); +@@ -1181,7 +1166,6 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha) + if (!(mmio_flags & IORESOURCE_MEM)) { + dev_err(&ha->pdev->dev, + "region #0 not an MMIO resource, aborting\n"); +- + goto iospace_error_exit; + } + if (mmio_len < MIN_IOBASE_LEN) { +@@ -1336,7 +1320,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + /* Start timer thread. */ + qla4xxx_start_timer(ha, qla4xxx_timer, 1); + +- set_bit(AF_INIT_DONE, &ha->flags); ++// set_bit(AF_INIT_DONE, &ha->flags); + + pci_set_drvdata(pdev, ha); + +@@ -1382,7 +1366,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + DEBUG2(dev_info(&ha->pdev->dev, "listhead=%p, done adding ha=%p i=%d\n", + &qla4xxx_hostlist, &ha->node, ha->instance)); + +-// set_bit(AF_INIT_DONE, &ha->flags); ++ set_bit(AF_INIT_DONE, &ha->flags); + dev_info(&ha->pdev->dev, "%s: AF_INIT_DONE\n", __func__); + + return 0; +@@ -1465,6 +1449,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) + + if (sess) { + sdev->hostdata = sess->dd_data; ++ QL_SET_SDEV_HOSTDATA(sdev, sess); + return 0; + } + return FAILED; +diff --git a/drivers/scsi/qla4xxx/ql4_os.h b/drivers/scsi/qla4xxx/ql4_os.h +index 71c3da0..c96ab8f 100644 +--- a/drivers/scsi/qla4xxx/ql4_os.h ++++ b/drivers/scsi/qla4xxx/ql4_os.h +@@ -44,13 +44,16 @@ + iscsi_unblock_session(ddb_entry->sess) + #define QL_ISCSI_ALLOC_SESSION(ha, trans) \ + iscsi_alloc_session(ha->host, trans, sizeof(struct ddb_entry)) ++#define QL_SET_SDEV_HOSTDATA(sdev, sess) + ++#define QL_DDB_STATE_REMOVED(ddb_entry) 0 + + #define QL_MISC_INIT 0 + #define QL_MISC_EXIT + + #define qla4xxx_check_dev_offline(ha) + #define qla4xxx_proc_info NULL ++#define qla4xxx_target_destroy NULL + + #define QL_SET_SCSI_RESID(cmd, residual) scsi_set_resid(cmd, residual) + #define QL_SCSI_BUFFLEN(cmd) scsi_bufflen(cmd) +@@ -69,10 +72,8 @@ + void dpc_func(struct work_struct *data) + + #define QL_INIT_SESSION_DATASIZE(sessiondata_size) +-// .sessiondata_size = sizeof(struct ddb_entry), + + #define QL_INIT_HOST_TEMPLATE(host_template) +-// .host_template = &qla4xxx_driver_template, + + QL_DECLARE_INTR_HANDLER(qla4xxx_intr_handler, irq, dev_id, regs); + +@@ -122,4 +123,22 @@ static inline void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, + cmd->SCp.ptr = NULL; + } + ++static inline void qla4xxx_remove_device(struct scsi_qla_host *ha) ++{ ++ struct ddb_entry *ddb_entry, *dtemp; ++ ++ if (test_and_clear_bit(DPC_REMOVE_DEVICE, &ha->dpc_flags)) { ++ list_for_each_entry_safe(ddb_entry, dtemp, ++ &ha->ddb_list, list) { ++ if (test_and_clear_bit(DF_REMOVE, &ddb_entry->flags)) { ++ dev_info(&ha->pdev->dev, ++ "%s: ddb[%d] os[%d] - removed\n", ++ __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ qla4xxx_free_ddb(ha, ddb_entry); ++ } ++ } ++ } ++} ++ + #endif /* _QLA4x_OS_H */ +diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h +index d6ff1b7..073e401 100644 +--- a/drivers/scsi/qla4xxx/ql4_version.h ++++ b/drivers/scsi/qla4xxx/ql4_version.h +@@ -5,5 +5,5 @@ + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-03" ++#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-04" + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-correct-extended-sense-data-errors b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-correct-extended-sense-data-errors new file mode 100644 index 000000000..bcd44004e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-correct-extended-sense-data-errors @@ -0,0 +1,304 @@ +From 517614ffd4e2408c731ad62bcbe169b0d0c49a0d Mon Sep 17 00:00:00 2001 +From: Karen Higgins +Date: Thu, 23 Apr 2009 21:48:36 -0700 +Subject: Correct Extended Sense Data Errors +References: bnc#483706 + +Fixed sense data errors occurring above the first 32 bytes, +as required by some third party applications. Sense data +in the first 32 bytes has always been correct. + +Also, corrected debug print alignment bug in dump_buffer routine. +Removed KERN_DEBUG from printk statements in this routine, +as loglevel #defines only get interpreted if the previous +print statement ends with a newline character. This prevents +<7> from being diplayed throughout the buffer. + +Changed version number to 5.01.00-k9 + +Signed-off-by: Karen Higgins +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/qla4xxx/ql4_dbg.c | 15 ++-- + drivers/scsi/qla4xxx/ql4_def.h | 2 + + drivers/scsi/qla4xxx/ql4_fw.h | 7 ++ + drivers/scsi/qla4xxx/ql4_isr.c | 147 +++++++++++++++++++++++++----------- + drivers/scsi/qla4xxx/ql4_version.h | 2 +- + 5 files changed, 119 insertions(+), 54 deletions(-) + +diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c +index 7ea69a6..0f6b6b0 100644 +--- a/drivers/scsi/qla4xxx/ql4_dbg.c ++++ b/drivers/scsi/qla4xxx/ql4_dbg.c +@@ -138,13 +138,13 @@ void qla4xxx_dump_buffer(void *b, uint32_t size) + "Fh\n"); + printk("------------------------------------------------------------" + "--\n"); +- for (cnt = 0; cnt < size; cnt++, c++) { +- printk(KERN_DEBUG "%02x", *c); +- if (!(cnt % 16)) +- printk(KERN_DEBUG "\n"); ++ for (cnt = 0; cnt < size; c++) { ++ printk("%02x", *c); ++ if (!(++cnt % 16)) ++ printk("\n"); + + else +- printk(KERN_DEBUG " "); ++ printk(" "); + } +- printk(KERN_DEBUG "\n"); ++ printk("\n"); + } +diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h +index 2b5af89..f8ea527 100644 +--- a/drivers/scsi/qla4xxx/ql4_def.h ++++ b/drivers/scsi/qla4xxx/ql4_def.h +@@ -465,6 +465,9 @@ struct scsi_qla_host { + #define QL_INDICES_PER_ENTRY 32 + #define QL_OSINDEX_ENTRIES (MAX_DDB_ENTRIES/QL_INDICES_PER_ENTRY) + volatile unsigned long os_map[QL_OSINDEX_ENTRIES]; ++ ++ /* Saved srb for status continuation entry processing */ ++ struct srb *status_srb; + }; + + static inline int is_qla4010(struct scsi_qla_host *ha) +diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h +index 3fb3658..083089e 100644 +--- a/drivers/scsi/qla4xxx/ql4_fw.h ++++ b/drivers/scsi/qla4xxx/ql4_fw.h +@@ -581,6 +581,7 @@ struct conn_event_log_entry { + *************************************************************************/ + #define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */ + #define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */ ++#define IOCB_MAX_EXT_SENSEDATA_LEN 60 /* Bytes of extended sense data */ + + /* IOCB header structure */ + struct qla4_header { +@@ -750,6 +751,12 @@ struct pdu_entry { + dma_addr_t DmaBuff; + }; + ++/* Status Continuation entry */ ++struct status_cont_entry { ++ struct qla4_header hdr; /* 00-03 */ ++ uint8_t extSenseData[IOCB_MAX_EXT_SENSEDATA_LEN]; /* 04-63 */ ++}; ++ + struct passthru0 { + struct qla4_header hdr; /* 00-03 */ + uint32_t handle; /* 04-07 */ +diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c +index 5c36ce6..c3354b8 100644 +--- a/drivers/scsi/qla4xxx/ql4_isr.c ++++ b/drivers/scsi/qla4xxx/ql4_isr.c +@@ -13,6 +13,100 @@ + #include "ql4_os.h" + + /** ++ * qla4xxx_copy_sense - copy sense data into cmd sense buffer ++ * @ha: Pointer to host adapter structure. ++ * @sts_entry: Pointer to status entry structure. ++ * @srb: Pointer to srb structure. ++ **/ ++static void qla4xxx_copy_sense(struct scsi_qla_host *ha, ++ struct status_entry *sts_entry, ++ struct srb *srb) ++{ ++ struct scsi_cmnd *cmd = srb->cmd; ++ uint16_t sense_len; ++ ++ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); ++ sense_len = le16_to_cpu(sts_entry->senseDataByteCnt); ++ if (sense_len == 0) ++ return; ++ ++ /* Save total available sense length, ++ * not to exceed cmd's sense buffer size */ ++ sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE); ++ cmd->SCp.ptr = cmd->sense_buffer; ++ cmd->SCp.this_residual = sense_len; ++ ++ /* Copy sense from sts_entry pkt */ ++ sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN); ++ memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len); ++ ++ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " ++ "Addl.SenseLen - %02x, " ++ "ASC/ASCQ = %02x/%02x\n", ha->host_no, ++ cmd->device->channel, cmd->device->id, ++ cmd->device->lun, __func__, ++ sts_entry->senseData[2] & 0x0f, ++ sts_entry->senseData[7], ++ sts_entry->senseData[12], ++ sts_entry->senseData[13])); ++ ++ DEBUG5(qla4xxx_dump_buffer(cmd->SCp.ptr, sense_len)); ++ srb->flags |= SRB_GOT_SENSE; ++ ++ /* Update srb, in case a sts_cont pkt follows */ ++ cmd->SCp.ptr += sense_len; ++ cmd->SCp.this_residual -= sense_len; ++ if (cmd->SCp.this_residual != 0) ++ ha->status_srb = srb; ++ else ++ ha->status_srb = NULL; ++} ++ ++/** ++ * qla4xxx_status_cont_entry() - Process a Status Continuations entry. ++ * @ha: SCSI driver HA context ++ * @sts_cont: Entry pointer ++ * ++ * Extended sense data. ++ */ ++static void ++qla4xxx_status_cont_entry(struct scsi_qla_host *ha, ++ struct status_cont_entry *sts_cont) ++{ ++ struct srb *srb = ha->status_srb; ++ struct scsi_cmnd *cmd; ++ uint8_t sense_len; ++ ++ if (srb == NULL) { ++ DEBUG2(printk("scsi%ld: %s: Throw away extra STATUS CONTINUATION\n", ++ ha->host_no, __func__)); ++ return; ++ } ++ ++ cmd = srb->cmd; ++ if (cmd == NULL) { ++ DEBUG2(printk("scsi%ld: %s: Cmd already returned back to OS " ++ "srb=%p srb->state:%d\n", ha->host_no, __func__, srb, srb->state)); ++ ha->status_srb = NULL; ++ return; ++ } ++ ++ /* Copy sense data. */ ++ sense_len = min(cmd->SCp.this_residual, IOCB_MAX_EXT_SENSEDATA_LEN); ++ memcpy(cmd->SCp.ptr, sts_cont->extSenseData, sense_len); ++ DEBUG5(qla4xxx_dump_buffer(cmd->SCp.ptr, sense_len)); ++ ++ cmd->SCp.ptr += sense_len; ++ cmd->SCp.this_residual -= sense_len; ++ ++ /* Place command on done queue. */ ++ if (cmd->SCp.this_residual == 0) { ++ qla4xxx_srb_compl(ha, srb); ++ ha->status_srb = NULL; ++ } ++} ++ ++/** + * qla4xxx_status_entry - processes status IOCBs + * @ha: Pointer to host adapter structure. + * @sts_entry: Pointer to status entry structure. +@@ -25,7 +119,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + struct srb *srb; + struct ddb_entry *ddb_entry; + uint32_t residual; +- uint16_t sensebytecnt; + + srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); + if (!srb) { +@@ -74,24 +167,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + break; + + /* Copy Sense Data into sense buffer. */ +- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); +- +- sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt); +- if (sensebytecnt == 0) +- break; +- +- memcpy(cmd->sense_buffer, sts_entry->senseData, +- min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE)); +- +- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " +- "ASC/ASCQ = %02x/%02x\n", ha->host_no, +- cmd->device->channel, cmd->device->id, +- cmd->device->lun, __func__, +- sts_entry->senseData[2] & 0x0f, +- sts_entry->senseData[12], +- sts_entry->senseData[13])); +- +- srb->flags |= SRB_GOT_SENSE; ++ qla4xxx_copy_sense(ha, sts_entry, srb); + break; + + case SCS_INCOMPLETE: +@@ -158,23 +234,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + break; + + /* Copy Sense Data into sense buffer. */ +- memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); +- +- sensebytecnt = +- le16_to_cpu(sts_entry->senseDataByteCnt); +- if (sensebytecnt == 0) +- break; +- +- memcpy(cmd->sense_buffer, sts_entry->senseData, +- min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE)); +- +- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " +- "ASC/ASCQ = %02x/%02x\n", ha->host_no, +- cmd->device->channel, cmd->device->id, +- cmd->device->lun, __func__, +- sts_entry->senseData[2] & 0x0f, +- sts_entry->senseData[12], +- sts_entry->senseData[13])); ++ qla4xxx_copy_sense(ha, sts_entry, srb); + } else { + /* + * If RISC reports underrun and target does not +@@ -250,9 +310,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + + status_entry_exit: + +- /* complete the request */ ++ /* complete the request, if not waiting for status_continuation pkt */ + srb->cc_stat = sts_entry->completionStatus; +- qla4xxx_srb_compl(ha, srb); ++ if (ha->status_srb == NULL) ++ qla4xxx_srb_compl(ha, srb); + } + + /** +@@ -287,10 +348,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha) + /* process entry */ + switch (sts_entry->hdr.entryType) { + case ET_STATUS: +- /* +- * Common status - Single completion posted in single +- * IOSB. +- */ ++ /* Common status */ + qla4xxx_status_entry(ha, sts_entry); + break; + +@@ -298,9 +356,8 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha) + break; + + case ET_STATUS_CONTINUATION: +- /* Just throw away the status continuation entries */ +- DEBUG2(printk("scsi%ld: %s: Status Continuation entry " +- "- ignoring\n", ha->host_no, __func__)); ++ qla4xxx_status_cont_entry(ha, ++ (struct status_cont_entry *) sts_entry); + break; + + case ET_COMMAND: +diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h +index 073e401..5de8e5f 100644 +--- a/drivers/scsi/qla4xxx/ql4_version.h ++++ b/drivers/scsi/qla4xxx/ql4_version.h +@@ -5,5 +5,5 @@ + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-04" ++#define QLA4XXX_DRIVER_VERSION "5.01.00-k9_sles11-04" + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-sles11-update b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-sles11-update new file mode 100644 index 000000000..060ad6412 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/qla4xxx-sles11-update @@ -0,0 +1,3160 @@ +From: Hannes Reinecke +Subject: qla4xxx driver fixes for SLES11 +Date: Tue Oct 7 12:59:55 2008 +0200: +References: bnc#432976 + +The upstream qla4xxx driver requires some fixes for SLES11. + +Signed-off-by: David Wagner +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig +index 69cbff3..4eda26a 100644 +--- a/drivers/scsi/qla4xxx/Kconfig ++++ b/drivers/scsi/qla4xxx/Kconfig +@@ -1,7 +1,7 @@ + config SCSI_QLA_ISCSI + tristate "QLogic ISP4XXX host adapter family support" +- depends on PCI && SCSI && NET ++ depends on PCI && SCSI + select SCSI_ISCSI_ATTRS + ---help--- +- This driver supports the QLogic 40xx (ISP4XXX) iSCSI host ++ This driver supports the QLogic 40xx (ISP4XXX) iSCSI host + adapter family. +diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c +index fcc184c..171a342 100644 +--- a/drivers/scsi/qla4xxx/ql4_dbg.c ++++ b/drivers/scsi/qla4xxx/ql4_dbg.c +@@ -6,10 +6,162 @@ + */ + + #include "ql4_def.h" ++#include "ql4_version.h" + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" + ++#include ++ ++static void qla4xxx_print_srb_info(struct srb * srb) ++{ ++ printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags); ++ printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n", ++ __func__, srb->cmd, (unsigned long) srb->dma_handle); ++ printk("%s: fw_ddb_index = %d, lun = %d\n", ++ __func__, srb->fw_ddb_index, srb->cmd->device->lun); ++ printk("%s: iocb_tov = %d\n", ++ __func__, srb->iocb_tov); ++ printk("%s: cc_stat = 0x%x\n", __func__, srb->cc_stat); ++} ++ ++void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd) ++{ ++ printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); ++ printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n", ++ cmd->device->channel, cmd->device->id, cmd->device->lun, ++ cmd->cmd_len); ++ scsi_print_command(cmd); ++ qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr); ++} ++ ++void __dump_registers(struct scsi_qla_host *ha) ++{ ++ uint8_t i; ++ for (i = 0; i < MBOX_REG_COUNT; i++) { ++ printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, mailbox[i]), i, ++ readw(&ha->reg->mailbox[i])); ++ } ++ printk(KERN_INFO "0x%02X flash_address = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, flash_address), ++ readw(&ha->reg->flash_address)); ++ printk(KERN_INFO "0x%02X flash_data = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, flash_data), ++ readw(&ha->reg->flash_data)); ++ printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ctrl_status), ++ readw(&ha->reg->ctrl_status)); ++ if (is_qla4010(ha)) { ++ printk(KERN_INFO "0x%02X nvram = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram), ++ readw(&ha->reg->u1.isp4010.nvram)); ++ } ++ ++ else if (is_qla4022(ha) | is_qla4032(ha)) { ++ printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u1.isp4022.intr_mask), ++ readw(&ha->reg->u1.isp4022.intr_mask)); ++ printk(KERN_INFO "0x%02X nvram = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram), ++ readw(&ha->reg->u1.isp4022.nvram)); ++ printk(KERN_INFO "0x%02X semaphore = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u1.isp4022.semaphore), ++ readw(&ha->reg->u1.isp4022.semaphore)); ++ } ++ printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, req_q_in), ++ readw(&ha->reg->req_q_in)); ++ printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, rsp_q_out), ++ readw(&ha->reg->rsp_q_out)); ++ if (is_qla4010(ha)) { ++ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4010.ext_hw_conf), ++ readw(&ha->reg->u2.isp4010.ext_hw_conf)); ++ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4010.port_ctrl), ++ readw(&ha->reg->u2.isp4010.port_ctrl)); ++ printk(KERN_INFO "0x%02X port_status = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4010.port_status), ++ readw(&ha->reg->u2.isp4010.port_status)); ++ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4010.req_q_out), ++ readw(&ha->reg->u2.isp4010.req_q_out)); ++ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out), ++ readw(&ha->reg->u2.isp4010.gp_out)); ++ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in), ++ readw(&ha->reg->u2.isp4010.gp_in)); ++ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4010.port_err_status), ++ readw(&ha->reg->u2.isp4010.port_err_status)); ++ } ++ ++ else if (is_qla4022(ha) | is_qla4032(ha)) { ++ printk(KERN_INFO "Page 0 Registers:\n"); ++ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4022.p0.ext_hw_conf), ++ readw(&ha->reg->u2.isp4022.p0.ext_hw_conf)); ++ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4022.p0.port_ctrl), ++ readw(&ha->reg->u2.isp4022.p0.port_ctrl)); ++ printk(KERN_INFO "0x%02X port_status = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4022.p0.port_status), ++ readw(&ha->reg->u2.isp4022.p0.port_status)); ++ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4022.p0.gp_out), ++ readw(&ha->reg->u2.isp4022.p0.gp_out)); ++ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in), ++ readw(&ha->reg->u2.isp4022.p0.gp_in)); ++ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4022.p0.port_err_status), ++ readw(&ha->reg->u2.isp4022.p0.port_err_status)); ++ printk(KERN_INFO "Page 1 Registers:\n"); ++ writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), ++ &ha->reg->ctrl_status); ++ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", ++ (uint8_t) offsetof(struct isp_reg, ++ u2.isp4022.p1.req_q_out), ++ readw(&ha->reg->u2.isp4022.p1.req_q_out)); ++ writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), ++ &ha->reg->ctrl_status); ++ } ++} ++ ++void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha) ++{ ++ unsigned long flags = 0; ++ int i = 0; ++ spin_lock_irqsave(&ha->hardware_lock, flags); ++ for (i = 1; i < MBOX_REG_COUNT; i++) ++ printk(KERN_INFO " Mailbox[%d] = %08x\n", i, ++ readw(&ha->reg->mailbox[i])); ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++} ++ ++void qla4xxx_dump_registers(struct scsi_qla_host *ha) ++{ ++ unsigned long flags = 0; ++ spin_lock_irqsave(&ha->hardware_lock, flags); ++ __dump_registers(ha); ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++} ++ + void qla4xxx_dump_buffer(void *b, uint32_t size) + { + uint32_t cnt; +@@ -30,4 +182,3 @@ void qla4xxx_dump_buffer(void *b, uint32_t size) + if (cnt % 16) + printk(KERN_DEBUG "\n"); + } +- +diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h +index d861c3b..20dfe4a 100644 +--- a/drivers/scsi/qla4xxx/ql4_dbg.h ++++ b/drivers/scsi/qla4xxx/ql4_dbg.h +@@ -12,6 +12,7 @@ + /* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */ + /* #define QL_DEBUG_LEVEL_4 */ + /* #define QL_DEBUG_LEVEL_5 */ ++/* #define QL_DEBUG_LEVEL_6 */ + /* #define QL_DEBUG_LEVEL_9 */ + + #define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */ +@@ -22,14 +23,14 @@ + #endif + + #if defined(QL_DEBUG_LEVEL_2) +-#define DEBUG2(x) do {if(ql4xextended_error_logging == 2) x;} while (0); ++#define DEBUG2(x) do {if(extended_error_logging == 2) x;} while (0); + #define DEBUG2_3(x) do {x;} while (0); + #else /* */ + #define DEBUG2(x) do {} while (0); + #endif /* */ + + #if defined(QL_DEBUG_LEVEL_3) +-#define DEBUG3(x) do {if(ql4xextended_error_logging == 3) x;} while (0); ++#define DEBUG3(x) do {if(extended_error_logging == 3) x;} while (0); + #else /* */ + #define DEBUG3(x) do {} while (0); + #if !defined(QL_DEBUG_LEVEL_2) +@@ -48,6 +49,12 @@ + #define DEBUG5(x) do {} while (0); + #endif /* */ + ++#if defined(QL_DEBUG_LEVEL_6) ++#define DEBUG6(x) do {x;} while (0); ++#else /* */ ++#define DEBUG6(x) do {} while (0); ++#endif /* */ ++ + #if defined(QL_DEBUG_LEVEL_9) + #define DEBUG9(x) do {x;} while (0); + #else /* */ +diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h +index d6be076..52d36b2 100644 +--- a/drivers/scsi/qla4xxx/ql4_def.h ++++ b/drivers/scsi/qla4xxx/ql4_def.h +@@ -90,10 +90,10 @@ + ***********************************/ + #define MAX_HBAS 16 + #define MAX_BUSES 1 +-#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) ++#define MAX_TARGETS MAX_DEV_DB_ENTRIES + #define MAX_LUNS 0xffff + #define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */ +-#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) ++#define MAX_DDB_ENTRIES MAX_DEV_DB_ENTRIES + #define MAX_PDU_ENTRIES 32 + #define INVALID_ENTRY 0xFFFF + #define MAX_CMDS_TO_RISC 1024 +@@ -121,8 +121,9 @@ + #define MAX_REQS_SERVICED_PER_INTR 16 + + #define ISCSI_IPADDR_SIZE 4 /* IP address size */ +-#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ +-#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ ++#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */ ++#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size - ++ * usually a string */ + + #define LSDW(x) ((u32)((u64)(x))) + #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) +@@ -158,6 +159,7 @@ struct srb { + struct ddb_entry *ddb; + uint16_t flags; /* (1) Status flags. */ + ++#define SRB_SCSI_PASSTHRU BIT_2 /* for scsi passthru cmds */ + #define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */ + #define SRB_GOT_SENSE BIT_4 /* sense data recieved. */ + uint8_t state; /* (1) Status flags. */ +@@ -182,25 +184,12 @@ struct srb { + uint16_t iocb_tov; + uint16_t iocb_cnt; /* Number of used iocbs */ + uint16_t cc_stat; +- u_long r_start; /* Time we recieve a cmd from OS */ +- u_long u_start; /* Time when we handed the cmd to F/W */ ++ uint32_t dma_len; + }; + +-/* +- * Asynchronous Event Queue structure +- */ +-struct aen { +- uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; +-}; +- +-struct ql4_aen_log { +- int count; +- struct aen entry[MAX_AEN_ENTRIES]; +-}; +- +-/* +- * Device Database (DDB) structure +- */ ++ /* ++ * Device Database (DDB) structure ++ */ + struct ddb_entry { + struct list_head list; /* ddb list */ + struct scsi_qla_host *ha; +@@ -262,9 +251,19 @@ struct ddb_entry { + #define DF_RELOGIN 0 /* Relogin to device */ + #define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL + * logged it out */ +-#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ +-#define DF_FO_MASKED 3 ++#define DF_SCAN_ISSUED 2 ++ ++/* ++ * Asynchronous Event Queue structure ++ */ ++struct aen { ++ uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; ++}; + ++struct ql4_aen_log { ++ int count; ++ struct aen entry[MAX_AEN_ENTRIES]; ++}; + + #include "ql4_fw.h" + #include "ql4_nvram.h" +@@ -273,16 +272,29 @@ struct ddb_entry { + * Linux Host Adapter structure + */ + struct scsi_qla_host { ++ struct klist_node node; ++ uint16_t instance; ++ uint16_t rsvd0; ++ ++ /* exported functions */ ++ int (*ql4cmd)(struct scsi_qla_host *ha, struct srb * srb); ++ int (*ql4mbx)(struct scsi_qla_host *ha, uint8_t inCount, ++ uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); ++ + /* Linux adapter configuration data */ ++ struct Scsi_Host *host; /* pointer to host data */ ++ uint32_t tot_ddbs; + unsigned long flags; + ++#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */ + #define AF_ONLINE 0 /* 0x00000001 */ + #define AF_INIT_DONE 1 /* 0x00000002 */ + #define AF_MBOX_COMMAND 2 /* 0x00000004 */ + #define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */ +-#define AF_INTERRUPTS_ON 6 /* 0x00000040 */ ++#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */ + #define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ + #define AF_LINK_UP 8 /* 0x00000100 */ ++#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */ + #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ + #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ + +@@ -297,9 +309,6 @@ struct scsi_qla_host { + #define DPC_AEN 9 /* 0x00000200 */ + #define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ + +- struct Scsi_Host *host; /* pointer to host data */ +- uint32_t tot_ddbs; +- + uint16_t iocb_cnt; + uint16_t iocb_hiwat; + +@@ -324,6 +333,7 @@ struct scsi_qla_host { + /* NVRAM registers */ + struct eeprom_data *nvram; + spinlock_t hardware_lock ____cacheline_aligned; ++ spinlock_t list_lock; + uint32_t eeprom_cmd_data; + + /* Counters for general statistics */ +@@ -348,7 +358,6 @@ struct scsi_qla_host { + uint32_t firmware_version[2]; + uint32_t patch_number; + uint32_t build_number; +- uint32_t board_id; + + /* --- From Init_FW --- */ + /* init_cb_t *init_cb; */ +@@ -368,6 +377,7 @@ struct scsi_qla_host { + + /* --- From GetFwState --- */ + uint32_t firmware_state; ++ uint32_t board_id; + uint32_t addl_fw_state; + + /* Linux kernel thread */ +@@ -390,6 +400,10 @@ struct scsi_qla_host { + uint16_t free_srb_q_count; + uint16_t num_srbs_allocated; + ++ /* Active array */ ++ struct srb *active_srb_array[MAX_SRBS]; ++ uint16_t current_active_index; ++ + /* DMA Memory Block */ + void *queues; + dma_addr_t queues_dma; +@@ -418,12 +432,20 @@ struct scsi_qla_host { + uint16_t aen_out; + struct aen aen_q[MAX_AEN_ENTRIES]; + +- struct ql4_aen_log aen_log;/* tracks all aens */ ++ /* pdu variables */ ++ uint16_t pdu_count; /* Number of available aen_q entries */ ++ uint16_t pdu_in; /* Current indexes */ ++ uint16_t pdu_out; ++ uint16_t pdu_active; ++ struct pdu_entry *free_pdu_top; ++ struct pdu_entry *free_pdu_bottom; ++ struct pdu_entry pdu_queue[MAX_PDU_ENTRIES]; + + /* This mutex protects several threads to do mailbox commands + * concurrently. + */ + struct mutex mbox_sem; ++ wait_queue_head_t mailbox_wait_queue; + + /* temporary mailbox status registers */ + volatile uint8_t mbox_status_count; +@@ -434,7 +456,11 @@ struct scsi_qla_host { + + /* Map ddb_list entry by FW ddb index */ + struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES]; +- ++ struct ql4_aen_log aen_log; ++ void (*ql4getaenlog)(struct scsi_qla_host *ha, struct ql4_aen_log *aenl); ++#define QL_INDICES_PER_ENTRY 32 ++#define QL_OSINDEX_ENTRIES (MAX_DDB_ENTRIES/QL_INDICES_PER_ENTRY) ++ volatile uint32_t os_map[QL_OSINDEX_ENTRIES]; + }; + + static inline int is_qla4010(struct scsi_qla_host *ha) +@@ -512,6 +538,20 @@ static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha) + &ha->reg->u2.isp4022.p0.gp_out); + } + ++static inline void __iomem * isp_probe_mux_addr(struct scsi_qla_host *ha) ++{ ++ return (is_qla4010(ha) ? ++ &ha->reg->u2.isp4010.probe_mux_addr : ++ &ha->reg->u2.isp4022.p0.probe_mux_addr); ++} ++ ++static inline void __iomem * isp_probe_mux_data(struct scsi_qla_host *ha) ++{ ++ return (is_qla4010(ha) ? ++ &ha->reg->u2.isp4010.probe_mux_data : ++ &ha->reg->u2.isp4022.p0.probe_mux_data); ++} ++ + static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha) + { + return (is_qla4010(ha) ? +@@ -590,5 +630,6 @@ static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) + #define PROCESS_ALL_AENS 0 + #define FLUSH_DDB_CHANGED_AENS 1 + #define RELOGIN_DDB_CHANGED_AENS 2 ++#define PROCESS_FOR_PROBE 3 + + #endif /*_QLA4XXX_H */ +diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h +index 1b667a7..3fb3658 100644 +--- a/drivers/scsi/qla4xxx/ql4_fw.h ++++ b/drivers/scsi/qla4xxx/ql4_fw.h +@@ -27,7 +27,11 @@ struct port_ctrl_stat_regs { + __le32 rsrvd1[32]; /* 0x60-0xdf */ + __le32 gp_out; /* 0xe0 */ + __le32 gp_in; /* 0xe4 */ +- __le32 rsrvd2[5]; /* 0xe8-0xfb */ ++ __le32 probe_mux_addr; /* 0xe8 */ ++ __le32 probe_mux_data; /* 0xec */ ++ __le32 stats_index; /* 0xf0 */ ++ __le32 stats_read_data_inc; /* 0xf4 */ ++ __le32 stats_read_data_noinc; /* 0xf8 */ + __le32 port_err_status; /* 0xfc */ + }; + +@@ -61,7 +65,9 @@ struct isp_reg { + __le32 req_q_in; /* SCSI Request Queue Producer Index */ + __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */ + +- __le32 reserved2[4]; /* 0x40 */ ++ __le32 reserved2[2]; /* 0x40 */ ++ __le32 arc_madi_cmd; ++ __le32 arc_madi_data; + + union { + struct { +@@ -79,7 +85,10 @@ struct isp_reg { + __le32 gp_out; /* 0xe0 */ + __le32 gp_in; + +- __le32 reserved5[5]; ++ __le32 probe_mux_addr; ++ __le32 probe_mux_data; ++ ++ __le32 reserved5[3]; + + __le32 port_err_status; /* 0xfc */ + } __attribute__ ((packed)) isp4010; +@@ -216,7 +225,6 @@ union external_hw_config_reg { + #define MBOX_CMD_ABOUT_FW 0x0009 + #define MBOX_CMD_PING 0x000B + #define MBOX_CMD_LUN_RESET 0x0016 +-#define MBOX_CMD_TARGET_WARM_RESET 0x0017 + #define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E + #define MBOX_CMD_GET_FW_STATUS 0x001F + #define MBOX_CMD_SET_ISNS_SERVICE 0x0021 +@@ -431,8 +439,9 @@ struct init_fw_ctrl_blk { + + struct dev_db_entry { + uint16_t options; /* 00-01 */ +-#define DDB_OPT_DISC_SESSION 0x10 +-#define DDB_OPT_TARGET 0x02 /* device is a target */ ++#define DDB_OPT_DISC_SESSION 0x10 ++#define DDB_OPT_TARGET 0x02 /* device is a target */ ++#define DDB_OPT_IPV6_DEVICE 0x100 + + uint16_t exec_throttle; /* 02-03 */ + uint16_t exec_count; /* 04-05 */ +@@ -672,14 +681,13 @@ struct continuation_t1_entry { + #define ET_CONTINUE ET_CONT_T1 + + /* Marker entry structure*/ +-struct qla4_marker_entry { ++struct marker_entry { + struct qla4_header hdr; /* 00-03 */ + + uint32_t system_defined; /* 04-07 */ + uint16_t target; /* 08-09 */ + uint16_t modifier; /* 0A-0B */ +-#define MM_LUN_RESET 0 +-#define MM_TGT_WARM_RESET 1 ++#define MM_LUN_RESET 0 + + uint16_t flags; /* 0C-0D */ + uint16_t reserved1; /* 0E-0F */ +@@ -733,6 +741,15 @@ struct status_entry { + + }; + ++struct pdu_entry { ++ uint8_t *Buff; ++ uint32_t BuffLen; ++ uint32_t SendBuffLen; ++ uint32_t RecvBuffLen; ++ struct pdu_entry *Next; ++ dma_addr_t DmaBuff; ++}; ++ + struct passthru0 { + struct qla4_header hdr; /* 00-03 */ + uint32_t handle; /* 04-07 */ +diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h +index 96ebfb0..f948b9a 100644 +--- a/drivers/scsi/qla4xxx/ql4_glbl.h ++++ b/drivers/scsi/qla4xxx/ql4_glbl.h +@@ -12,6 +12,7 @@ struct iscsi_cls_conn; + + void qla4xxx_hw_reset(struct scsi_qla_host *ha); + int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); ++int qla4xxx_conn_start(struct iscsi_cls_conn *conn); + int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); + int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb); + int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, +@@ -27,8 +28,6 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha, + struct ddb_entry * ddb_entry); + int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, + int lun); +-int qla4xxx_reset_target(struct scsi_qla_host * ha, +- struct ddb_entry * ddb_entry); + int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, + uint32_t offset, uint32_t len); + int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); +@@ -56,25 +55,35 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, + u16 rd_nvram_word(struct scsi_qla_host * ha, int offset); + void qla4xxx_get_crash_record(struct scsi_qla_host * ha); + struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha); +-int qla4xxx_add_sess(struct ddb_entry *); ++int qla4xxx_add_sess(struct ddb_entry *, int); + void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry); ++int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, ++ uint16_t fw_ddb_index, ++ uint16_t connection_id, ++ uint16_t option); ++int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, ++ uint16_t fw_ddb_index); + int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha); + int qla4xxx_get_fw_version(struct scsi_qla_host * ha); + void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, + uint32_t intr_status); + int qla4xxx_init_rings(struct scsi_qla_host * ha); +-struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, +- uint32_t index); ++void qla4xxx_dump_buffer(void *b, uint32_t size); ++struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index); + void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); + int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); + int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, +- uint32_t fw_ddb_index, uint32_t state); +-void qla4xxx_dump_buffer(void *b, uint32_t size); ++ uint32_t fw_ddb_index, uint32_t state, uint32_t probe); ++ ++int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, ++ uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); + int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); ++ struct ddb_entry *ddb_entry, int lun); ++ ++ + +-extern int ql4xextended_error_logging; ++extern int extended_error_logging; + extern int ql4xdiscoverywait; + extern int ql4xdontresethba; + extern int ql4_mod_unload; +-#endif /* _QLA4x_GBL_H */ ++#endif /* _QLA4x_GBL_H */ +diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c +index 109c5f5..6e83198 100644 +--- a/drivers/scsi/qla4xxx/ql4_init.c ++++ b/drivers/scsi/qla4xxx/ql4_init.c +@@ -5,12 +5,20 @@ + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +-#include + #include "ql4_def.h" ++#include "ql4_version.h" + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" + ++/* link auto negotiation normally takes roughly 2s. */ ++/* If we don't have link in 3 times that period quit. */ ++#define QLA4XXX_LINK_UP_DELAY 6 ++ ++/* ++ * QLogic ISP4xxx Hardware Support Function Prototypes. ++ */ ++ + static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + uint32_t fw_ddb_index); + +@@ -44,7 +52,7 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) + } + + /** +- * qla4xxx_free_ddb - deallocate ddb ++ * qla4xxx_free_ddb - deallocate ddb + * @ha: pointer to host adapter structure. + * @ddb_entry: pointer to device database entry + * +@@ -58,8 +66,7 @@ static void qla4xxx_free_ddb(struct scsi_qla_host *ha, + list_del_init(&ddb_entry->list); + + /* Remove device pointer from index mapping arrays */ +- ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = +- (struct ddb_entry *) INVALID_ENTRY; ++ ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = NULL; + ha->tot_ddbs--; + + /* Free memory and scsi-ml struct for device entry */ +@@ -95,6 +102,7 @@ void qla4xxx_free_ddb_list(struct scsi_qla_host *ha) + **/ + int qla4xxx_init_rings(struct scsi_qla_host *ha) + { ++ uint16_t i; + unsigned long flags = 0; + + /* Initialize request queue. */ +@@ -123,6 +131,10 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) + writel(0, &ha->reg->rsp_q_out); + readl(&ha->reg->rsp_q_out); + ++ /* Initialize active array */ ++ for (i = 0; i < MAX_SRBS; i++) ++ ha->active_srb_array[i] = NULL; ++ + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_SUCCESS; +@@ -183,6 +195,16 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) + **/ + static int qla4xxx_init_local_data(struct scsi_qla_host *ha) + { ++ int i; ++ ++ /* Initialize passthru PDU list */ ++ for (i = 0; i < (MAX_PDU_ENTRIES - 1); i++) ++ ha->pdu_queue[i].Next = &ha->pdu_queue[i + 1]; ++ ha->free_pdu_top = &ha->pdu_queue[0]; ++ ha->free_pdu_bottom = &ha->pdu_queue[MAX_PDU_ENTRIES - 1]; ++ ha->free_pdu_bottom->Next = NULL; ++ ha->pdu_active = 0; ++ + /* Initilize aen queue */ + ha->aen_q_count = MAX_AEN_ENTRIES; + +@@ -263,12 +285,10 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) + "seconds expired= %d\n", ha->host_no, __func__, + ha->firmware_state, ha->addl_fw_state, + timeout_count)); +- if (is_qla4032(ha) && +- !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && ++ if (!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && + (timeout_count < ADAPTER_INIT_TOV - 5)) { + break; + } +- + msleep(1000); + } /* end of for */ + +@@ -276,7 +296,8 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) + DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", + ha->host_no, __func__)); + +- if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) { ++ if ((ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)|| ++ !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP)) { + DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to" + " grab an IP address from DHCP server\n", + ha->host_no, __func__)); +@@ -307,145 +328,27 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) + return qla4xxx_get_firmware_status(ha); + } + +-static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, +- uint32_t fw_ddb_index, +- uint32_t *new_tgt) ++static void qla4xxx_fill_ddb(struct ddb_entry *ddb_entry, ++ struct dev_db_entry *fw_ddb_entry) + { +- struct dev_db_entry *fw_ddb_entry = NULL; +- dma_addr_t fw_ddb_entry_dma; +- struct ddb_entry *ddb_entry = NULL; +- int found = 0; +- uint32_t device_state; +- +- *new_tgt = 0; +- /* Make sure the dma buffer is valid */ +- fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, +- sizeof(*fw_ddb_entry), +- &fw_ddb_entry_dma, GFP_KERNEL); +- if (fw_ddb_entry == NULL) { +- DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", +- ha->host_no, __func__)); +- return NULL; +- } +- +- if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, +- fw_ddb_entry_dma, NULL, NULL, +- &device_state, NULL, NULL, NULL) == +- QLA_ERROR) { +- DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " +- "fw_ddb_index %d\n", ha->host_no, __func__, +- fw_ddb_index)); +- return NULL; +- } +- +- /* Allocate DDB if not already allocated. */ +- DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no, +- __func__, fw_ddb_index)); +- list_for_each_entry(ddb_entry, &ha->ddb_list, list) { +- if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name, +- ISCSI_NAME_SIZE) == 0) { +- found++; +- break; +- } +- } +- +- if (!found) { +- DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating " +- "new ddb\n", ha->host_no, __func__, +- fw_ddb_index)); +- *new_tgt = 1; +- ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); +- } +- +- /* if not found allocate new ddb */ +- dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, +- fw_ddb_entry_dma); +- +- return ddb_entry; +-} +- +-/** +- * qla4xxx_update_ddb_entry - update driver's internal ddb +- * @ha: pointer to host adapter structure. +- * @ddb_entry: pointer to device database structure to be filled +- * @fw_ddb_index: index of the ddb entry in fw ddb table +- * +- * This routine updates the driver's internal device database entry +- * with information retrieved from the firmware's device database +- * entry for the specified device. The ddb_entry->fw_ddb_index field +- * must be initialized prior to calling this routine +- * +- **/ +-static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry, +- uint32_t fw_ddb_index) +-{ +- struct dev_db_entry *fw_ddb_entry = NULL; +- dma_addr_t fw_ddb_entry_dma; +- int status = QLA_ERROR; +- +- if (ddb_entry == NULL) { +- DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no, +- __func__)); +- goto exit_update_ddb; +- } +- +- /* Make sure the dma buffer is valid */ +- fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, +- sizeof(*fw_ddb_entry), +- &fw_ddb_entry_dma, GFP_KERNEL); +- if (fw_ddb_entry == NULL) { +- DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", +- ha->host_no, __func__)); +- +- goto exit_update_ddb; +- } +- +- if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, +- fw_ddb_entry_dma, NULL, NULL, +- &ddb_entry->fw_ddb_device_state, NULL, +- &ddb_entry->tcp_source_port_num, +- &ddb_entry->connection_id) == +- QLA_ERROR) { +- DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " +- "fw_ddb_index %d\n", ha->host_no, __func__, +- fw_ddb_index)); +- +- goto exit_update_ddb; +- } +- +- status = QLA_SUCCESS; + ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid); + ddb_entry->task_mgmt_timeout = + le16_to_cpu(fw_ddb_entry->def_timeout); + ddb_entry->CmdSn = 0; + ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle); ++ + ddb_entry->default_relogin_timeout = + le16_to_cpu(fw_ddb_entry->def_timeout); +- ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); +- +- /* Update index in case it changed */ +- ddb_entry->fw_ddb_index = fw_ddb_index; +- ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ++ ddb_entry->default_time2wait = ++ le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + + ddb_entry->port = le16_to_cpu(fw_ddb_entry->port); + ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], +- min(sizeof(ddb_entry->iscsi_name), +- sizeof(fw_ddb_entry->iscsi_name))); ++ min(sizeof(ddb_entry->iscsi_name), ++ sizeof(fw_ddb_entry->iscsi_name))); + memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0], +- min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); +- +- DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", +- ha->host_no, __func__, fw_ddb_index, +- ddb_entry->fw_ddb_device_state, status)); +- +- exit_update_ddb: +- if (fw_ddb_entry) +- dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), +- fw_ddb_entry, fw_ddb_entry_dma); +- +- return status; ++ min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); + } + + /** +@@ -478,6 +381,12 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->relogin_retry_count, 0); + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); ++ ++ dev_info(&ha->pdev->dev, ++ "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", ++ ha->host_no, __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ + list_add_tail(&ddb_entry->list, &ha->ddb_list); + ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; + ha->tot_ddbs++; +@@ -490,7 +399,7 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + * @ha: Pointer to host adapter structure. + * + * This routine searches for all valid firmware ddb entries and builds +- * an internal ddb list. Ddbs that are considered valid are those with ++ * an internal ddb list. Ddbs that are considered valid are those with + * a device state of SESSION_ACTIVE. + **/ + static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) +@@ -501,90 +410,116 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) + uint32_t ddb_state; + uint32_t conn_err, err_code; + struct ddb_entry *ddb_entry; +- uint32_t new_tgt; ++ struct dev_db_entry *fw_ddb_entry = NULL; ++ dma_addr_t fw_ddb_entry_dma; ++ uint16_t src_port, conn_id; ++ uint32_t ipv6_device; + + dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); ++ ++ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), ++ &fw_ddb_entry_dma, GFP_KERNEL); ++ ++ if (fw_ddb_entry == NULL) { ++ DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n", ++ __func__)); ++ return QLA_ERROR; ++ } ++ + for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; + fw_ddb_index = next_fw_ddb_index) { + /* First, let's see if a device exists here */ +- if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL, +- &next_fw_ddb_index, &ddb_state, +- &conn_err, NULL, NULL) == +- QLA_ERROR) { +- DEBUG2(printk("scsi%ld: %s: get_ddb_entry, " +- "fw_ddb_index %d failed", ha->host_no, +- __func__, fw_ddb_index)); +- return QLA_ERROR; ++ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, ++ fw_ddb_entry_dma, NULL, &next_fw_ddb_index, ++ &ddb_state, &conn_err, &src_port, ++ &conn_id) == QLA_ERROR) { ++ DEBUG2(dev_info(&ha->pdev->dev, "%s: get_ddb_entry," ++ " fw_ddb_index %d failed", __func__, ++ fw_ddb_index)); ++ goto exit_ddb_list; + } + +- DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, " +- "next_fw_ddb_index=%d.\n", ha->host_no, __func__, ++ DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] ddbstate=0x%x, " ++ "next_fw_ddb_index=%d.\n", __func__, + fw_ddb_index, ddb_state, next_fw_ddb_index)); + + /* Issue relogin, if necessary. */ + if (ddb_state == DDB_DS_SESSION_FAILED || + ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) { ++ ipv6_device = le16_to_cpu(fw_ddb_entry->options) & ++ DDB_OPT_IPV6_DEVICE; + /* Try and login to device */ +- DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n", +- ha->host_no, __func__, fw_ddb_index)); ++ DEBUG2(dev_info(&ha->pdev->dev, "%s: Login DDB[%d]\n", ++ __func__, fw_ddb_index)); + err_code = ((conn_err & 0x00ff0000) >> 16); + if (err_code == 0x1c || err_code == 0x06) { +- DEBUG2(printk("scsi%ld: %s send target " +- "completed " +- "or access denied failure\n", +- ha->host_no, __func__)); +- } else { ++ DEBUG2(dev_info(&ha->pdev->dev, ++ ": %s send target completed or access" ++ " denied failure\n", __func__)); ++ } else if ((!ipv6_device && ++ *((uint32_t *)fw_ddb_entry->ip_addr)) || ++ ipv6_device) { + qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0); + if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, +- NULL, 0, NULL, &next_fw_ddb_index, +- &ddb_state, &conn_err, NULL, NULL) +- == QLA_ERROR) { +- DEBUG2(printk("scsi%ld: %s:" +- "get_ddb_entry %d failed\n", +- ha->host_no, ++ fw_ddb_entry, fw_ddb_entry_dma, NULL, ++ &next_fw_ddb_index, &ddb_state, ++ &conn_err, &src_port, ++ &conn_id) == QLA_ERROR) { ++ DEBUG2(dev_info(&ha->pdev->dev, ++ "%s: get_fwddb %d failed\n", + __func__, fw_ddb_index)); +- return QLA_ERROR; ++ goto exit_ddb_list; + } + } + } + +- if (ddb_state != DDB_DS_SESSION_ACTIVE) +- goto next_one; +- /* +- * if fw_ddb with session active state found, +- * add to ddb_list +- */ +- DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n", +- ha->host_no, __func__, fw_ddb_index)); +- +- /* Add DDB to internal our ddb list. */ +- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt); +- if (ddb_entry == NULL) { +- DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " +- "for device at fw_ddb_index %d\n", +- ha->host_no, __func__, fw_ddb_index)); +- return QLA_ERROR; +- } +- /* Fill in the device structure */ +- if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == +- QLA_ERROR) { +- ha->fw_ddb_index_map[fw_ddb_index] = +- (struct ddb_entry *)INVALID_ENTRY; +- +- +- DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed " +- "for fw_ddb_index %d.\n", +- ha->host_no, __func__, fw_ddb_index)); +- return QLA_ERROR; ++ if (!(le16_to_cpu(fw_ddb_entry->options) & DDB_OPT_DISC_SESSION) && ++ (ddb_state != DDB_DS_UNASSIGNED) && ++ (strlen(fw_ddb_entry->iscsi_name) != 0)){ ++ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); ++ if (ddb_entry == NULL) { ++ DEBUG2(dev_info(&ha->pdev->dev,"%s alloc_ddb %d " ++ "failed\n", __func__, fw_ddb_index)); ++ goto exit_ddb_list; ++ } ++ ddb_entry->fw_ddb_index = fw_ddb_index; ++ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ++ ddb_entry->tcp_source_port_num = src_port; ++ ddb_entry->connection_id = conn_id; ++ qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); ++ ddb_entry->fw_ddb_device_state = ddb_state; ++ ++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { ++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); ++ dev_info(&ha->pdev->dev, ++ "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", ++ ha->host_no, __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ } else { ++ atomic_set(&ddb_entry->state, DDB_STATE_MISSING); ++ dev_info(&ha->pdev->dev, ++ "scsi%ld: %s: ddb[%d] os[%d] marked MISSING\n", ++ ha->host_no, __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ } ++ DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d State %04x" ++ " ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__, ++ fw_ddb_index, ddb_entry->os_target_id, ddb_state, conn_err, ++ fw_ddb_entry->ip_addr[0], fw_ddb_entry->ip_addr[1], ++ fw_ddb_entry->ip_addr[2], fw_ddb_entry->ip_addr[3], ++ le16_to_cpu(fw_ddb_entry->port), ++ fw_ddb_entry->iscsi_name)); + } + +-next_one: + /* We know we've reached the last device when + * next_fw_ddb_index is 0 */ + if (next_fw_ddb_index == 0) + break; + } + ++exit_ddb_list: ++ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, ++ fw_ddb_entry_dma); + dev_info(&ha->pdev->dev, "DDB list done..\n"); + + return status; +@@ -682,15 +617,18 @@ static int qla4_scan_for_relogin(struct scsi_qla_host *ha, + static int qla4xxx_devices_ready(struct scsi_qla_host *ha) + { + int error; +- unsigned long discovery_wtime; ++ unsigned long discovery_wtime = 0; + struct qla4_relog_scan rs; + +- discovery_wtime = jiffies + (ql4xdiscoverywait * HZ); +- + DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait)); + do { + /* poll for AEN. */ + qla4xxx_get_firmware_state(ha); ++ ++ if(!(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && ++ (discovery_wtime > QLA4XXX_LINK_UP_DELAY)) ++ break; ++ + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) { + /* Set time-between-relogin timer */ + qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS); +@@ -708,7 +646,8 @@ static int qla4xxx_devices_ready(struct scsi_qla_host *ha) + } + + msleep(2000); +- } while (!time_after_eq(jiffies, discovery_wtime)); ++ discovery_wtime += 2; ++ } while (discovery_wtime < ql4xdiscoverywait); + + DEBUG3(qla4xxx_get_conn_event_log(ha)); + +@@ -750,13 +689,13 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) + qla4xxx_free_ddb_list(ha); + + for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) +- ha->fw_ddb_index_map[fw_ddb_index] = +- (struct ddb_entry *)INVALID_ENTRY; ++ ha->fw_ddb_index_map[fw_ddb_index] = NULL; + + ha->tot_ddbs = 0; + + qla4xxx_flush_AENS(ha); + ++ + /* + * First perform device discovery for active + * fw ddb indexes and build +@@ -773,7 +712,7 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) + * the aens here will catch them. + */ + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) +- qla4xxx_process_aen(ha, PROCESS_ALL_AENS); ++ qla4xxx_process_aen(ha, PROCESS_FOR_PROBE); + + return status; + } +@@ -789,19 +728,37 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha) + { + int status = QLA_SUCCESS; + struct ddb_entry *ddb_entry, *detemp; ++ struct dev_db_entry *fw_ddb_entry = NULL; ++ dma_addr_t fw_ddb_entry_dma; ++ ++ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, ++ sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, ++ GFP_KERNEL); ++ if (fw_ddb_entry == NULL) ++ return QLA_ERROR; + + /* Update the device information for all devices. */ + list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) { +- qla4xxx_update_ddb_entry(ha, ddb_entry, +- ddb_entry->fw_ddb_index); +- if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { +- atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); +- DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked " +- "ONLINE\n", ha->host_no, __func__, +- ddb_entry->fw_ddb_index)); +- } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) +- qla4xxx_mark_device_missing(ha, ddb_entry); ++ if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, ++ fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL, ++ &ddb_entry->fw_ddb_device_state, NULL, ++ &ddb_entry->tcp_source_port_num, ++ &ddb_entry->connection_id) == QLA_SUCCESS) { ++ ++ qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); ++ ++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { ++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); ++ dev_info(&ha->pdev->dev, ++ "scsi%ld: %s: ddb[%d] os[%d] marked ONLINE\n", ++ ha->host_no, __func__, ddb_entry->fw_ddb_index, ++ ddb_entry->os_target_id); ++ } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) ++ qla4xxx_mark_device_missing(ha, ddb_entry); ++ } + } ++ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), ++ fw_ddb_entry, fw_ddb_entry_dma); + return status; + } + +@@ -884,12 +841,11 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha) + static void qla4x00_pci_config(struct scsi_qla_host *ha) + { + uint16_t w; +- int status; + + dev_info(&ha->pdev->dev, "Configuring PCI space...\n"); + + pci_set_master(ha->pdev); +- status = pci_set_mwi(ha->pdev); ++ pci_set_mwi(ha->pdev); + /* + * We want to respect framework's setting of PCI configuration space + * command register and also want to make sure that all bits of +@@ -1007,7 +963,7 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) + * qla4xxx_start_firmware - starts qla4xxx firmware + * @ha: Pointer to host adapter structure. + * +- * This routine performs the necessary steps to start the firmware for ++ * This routine performs the neccessary steps to start the firmware for + * the QLA4010 adapter. + **/ + static int qla4xxx_start_firmware(struct scsi_qla_host *ha) +@@ -1127,7 +1083,7 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha) + * @renew_ddb_list: Indicates what to do with the adapter's ddb list + * after adapter recovery has completed. + * 0=preserve ddb list, 1=destroy and rebuild ddb list +- * ++ * + * This routine parforms all of the steps necessary to initialize the adapter. + * + **/ +@@ -1211,51 +1167,81 @@ exit_init_hba: + * This routine processes adds a device as a result of an 8014h AEN. + **/ + static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, +- uint32_t fw_ddb_index) ++ uint32_t fw_ddb_index, uint32_t probe) + { +- struct ddb_entry * ddb_entry; +- uint32_t new_tgt; ++ struct dev_db_entry *fw_ddb_entry = NULL; ++ dma_addr_t fw_ddb_entry_dma; ++ uint16_t src_port, conn_id; ++ struct ddb_entry *ddb_entry = NULL; ++ uint32_t ddb_state, found = 0; + +- /* First allocate a device structure */ +- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt); +- if (ddb_entry == NULL) { +- DEBUG2(printk(KERN_WARNING +- "scsi%ld: Unable to allocate memory to add " +- "fw_ddb_index %d\n", ha->host_no, fw_ddb_index)); ++ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), ++ &fw_ddb_entry_dma, GFP_KERNEL); ++ ++ if (fw_ddb_entry == NULL) { ++ DEBUG2(dev_info(&ha->pdev->dev, "%s dmaalloc failed\n", __func__)); + return; + } + +- if (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) { ++ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, ++ fw_ddb_entry_dma, NULL, NULL, &ddb_state, NULL, &src_port, ++ &conn_id) == QLA_ERROR) { ++ DEBUG2(dev_info(&ha->pdev->dev, "%s getddb %d failed\n", ++ __func__, fw_ddb_index)); ++ return; ++ } ++ ++ list_for_each_entry(ddb_entry, &ha->ddb_list, list) { ++ if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name, ++ ISCSI_NAME_SIZE) == 0) { ++ found = 1; ++ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s found target ddb = 0x%p" ++ " sess 0x%p conn 0x%p state 0x%x nidx 0x%x oidx 0x%x\n", ++ __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn, ++ ddb_entry->state, fw_ddb_index, ddb_entry->fw_ddb_index)); ++ break; ++ } ++ } ++ ++ if (!found) ++ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); ++ else if (ddb_entry->fw_ddb_index != fw_ddb_index) { + /* Target has been bound to a new fw_ddb_index */ + qla4xxx_free_ddb(ha, ddb_entry); + ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); +- if (ddb_entry == NULL) { +- DEBUG2(printk(KERN_WARNING +- "scsi%ld: Unable to allocate memory" +- " to add fw_ddb_index %d\n", +- ha->host_no, fw_ddb_index)); +- return; +- } + } +- if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == +- QLA_ERROR) { +- ha->fw_ddb_index_map[fw_ddb_index] = +- (struct ddb_entry *)INVALID_ENTRY; +- DEBUG2(printk(KERN_WARNING +- "scsi%ld: failed to add new device at index " +- "[%d]\n Unable to retrieve fw ddb entry\n", +- ha->host_no, fw_ddb_index)); +- qla4xxx_free_ddb(ha, ddb_entry); +- return; ++ ++ if (ddb_entry == NULL) { ++ DEBUG2(dev_info(&ha->pdev->dev, "%s NULL DDB %d\n", ++ __func__, fw_ddb_index)); ++ goto exit_dyn_add; + } + +- if (qla4xxx_add_sess(ddb_entry)) { +- DEBUG2(printk(KERN_WARNING ++ ddb_entry->fw_ddb_index = fw_ddb_index; ++ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry; ++ ddb_entry->tcp_source_port_num = src_port; ++ ddb_entry->connection_id = conn_id; ++ qla4xxx_fill_ddb(ddb_entry, fw_ddb_entry); ++ ddb_entry->fw_ddb_device_state = ddb_state; ++ ++ if (!probe) { ++ if (qla4xxx_add_sess(ddb_entry, 1)) { ++ DEBUG2(printk(KERN_WARNING + "scsi%ld: failed to add new device at index " + "[%d]\n Unable to add connection and session\n", + ha->host_no, fw_ddb_index)); +- qla4xxx_free_ddb(ha, ddb_entry); ++ qla4xxx_free_ddb(ha, ddb_entry); ++ } + } ++ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s added ddb 0x%p sess 0x%p conn 0x%p" ++ " state 0x%x\n", __func__, ddb_entry, ddb_entry->sess, ++ ddb_entry->conn, ddb_entry->state)); ++exit_dyn_add: ++ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, ++ fw_ddb_entry_dma); ++ return; + } + + /** +@@ -1267,11 +1253,13 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha, + * This routine processes a Decive Database Changed AEN Event. + **/ + int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, +- uint32_t fw_ddb_index, uint32_t state) ++ uint32_t fw_ddb_index, uint32_t state, uint32_t probe) + { + struct ddb_entry * ddb_entry; + uint32_t old_fw_ddb_device_state; + ++ DEBUG6(dev_info(&ha->pdev->dev, "%s idx %d nstate 0x%x\n", ++ __func__, fw_ddb_index, state)); + /* check for out of range index */ + if (fw_ddb_index >= MAX_DDB_ENTRIES) + return QLA_ERROR; +@@ -1281,9 +1269,12 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + /* Device does not currently exist in our database. */ + if (ddb_entry == NULL) { + if (state == DDB_DS_SESSION_ACTIVE) +- qla4xxx_add_device_dynamically(ha, fw_ddb_index); ++ qla4xxx_add_device_dynamically(ha, fw_ddb_index, probe); + return QLA_SUCCESS; + } ++ DEBUG6(dev_info(&ha->pdev->dev, "%s ddb_entry 0x%p ostate 0x%x" ++ " sess 0x%p conn 0x%p\n", __func__, ddb_entry, ++ ddb_entry->state, ddb_entry->sess, ddb_entry->conn)); + + /* Device already exists in our database. */ + old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; +@@ -1297,25 +1288,43 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + } + + ddb_entry->fw_ddb_device_state = state; ++ ++ if (probe) ++ return QLA_SUCCESS; ++ + /* Device is back online. */ + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { +- atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + atomic_set(&ddb_entry->port_down_timer, + ha->port_down_retry_count); ++ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + atomic_set(&ddb_entry->relogin_retry_count, 0); + atomic_set(&ddb_entry->relogin_timer, 0); + clear_bit(DF_RELOGIN, &ddb_entry->flags); + clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); +- iscsi_unblock_session(ddb_entry->sess); +- iscsi_session_event(ddb_entry->sess, +- ISCSI_KEVENT_CREATE_SESSION); +- /* +- * Change the lun state to READY in case the lun TIMEOUT before +- * the device came back. +- */ ++ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s conn startddb_entry 0x%p" ++ " sess 0x%p conn 0x%p\n", ++ __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); ++ ++ qla4xxx_conn_start(ddb_entry->conn); ++ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s conn start done " ++ "ddb_entry 0x%p sess 0x%p conn 0x%p\n", ++ __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); ++ ++ if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) { ++ scsi_scan_target(&ddb_entry->sess->dev, 0, ++ ddb_entry->sess->target_id, ++ SCAN_WILD_CARD, 0); ++ set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); ++ } + } else { + /* Device went away, try to relogin. */ + /* Mark device missing */ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s mark missing ddb_entry 0x%p" ++ " sess 0x%p conn 0x%p\n", __func__, ddb_entry, ++ ddb_entry->sess, ddb_entry->conn)); ++ + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + /* +@@ -1325,8 +1334,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + */ + if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && + !test_bit(DF_RELOGIN, &ddb_entry->flags) && +- !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && +- !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) { ++ !test_bit(DF_NO_RELOGIN, &ddb_entry->flags)) { + /* + * This triggers a relogin. After the relogin_timer + * expires, the relogin gets scheduled. We must wait a +diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h +index 6375eb0..3cf28aa 100644 +--- a/drivers/scsi/qla4xxx/ql4_inline.h ++++ b/drivers/scsi/qla4xxx/ql4_inline.h +@@ -24,8 +24,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index) + struct ddb_entry *ddb_entry = NULL; + + if ((fw_ddb_index < MAX_DDB_ENTRIES) && +- (ha->fw_ddb_index_map[fw_ddb_index] != +- (struct ddb_entry *) INVALID_ENTRY)) { ++ (ha->fw_ddb_index_map[fw_ddb_index] != NULL)) { + ddb_entry = ha->fw_ddb_index_map[fw_ddb_index]; + } + +diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c +index 912a674..d387386 100644 +--- a/drivers/scsi/qla4xxx/ql4_iocb.c ++++ b/drivers/scsi/qla4xxx/ql4_iocb.c +@@ -6,11 +6,12 @@ + */ + + #include "ql4_def.h" ++#include "ql4_version.h" + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" + +- ++#define VMWARE_CMD_TIMEOUT 30 + #include + + /** +@@ -67,9 +68,9 @@ static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, + * This routine issues a marker IOCB. + **/ + int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod) ++ struct ddb_entry *ddb_entry, int lun) + { +- struct qla4_marker_entry *marker_entry; ++ struct marker_entry *marker_entry; + unsigned long flags = 0; + uint8_t status = QLA_SUCCESS; + +@@ -87,7 +88,7 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, + marker_entry->hdr.entryType = ET_MARKER; + marker_entry->hdr.entryCount = 1; + marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); +- marker_entry->modifier = cpu_to_le16(mrkr_mod); ++ marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); + int_to_scsilun(lun, &marker_entry->lun); + wmb(); + +@@ -160,6 +161,13 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb, + avail_dsds = COMMAND_SEG; + cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); + ++ if (srb->flags & SRB_SCSI_PASSTHRU) { ++ cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle)); ++ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle)); ++ cur_dsd->count = cpu_to_le32(srb->dma_len); ++ return; ++ } ++ + scsi_for_each_sg(cmd, sg, tot_dsds, i) { + dma_addr_t sle_dma; + +@@ -204,6 +212,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + + unsigned long flags; + uint16_t cnt; ++ uint16_t i; + uint32_t index; + char tag[2]; + +@@ -215,7 +224,22 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + /* Acquire hardware specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + +- index = (uint32_t)cmd->request->tag; ++ index = ha->current_active_index; ++ for (i = 0; i < MAX_SRBS; i++) { ++ index++; ++ if (index == MAX_SRBS) ++ index = 1; ++ if (ha->active_srb_array[index] == 0) { ++ ha->current_active_index = index; ++ break; ++ } ++ } ++ if (i >= MAX_SRBS) { ++ printk(KERN_INFO "scsi%ld: %s: NO more SRB entries used " ++ "iocbs=%d, \n reqs remaining=%d\n", ha->host_no, ++ __func__, ha->iocb_cnt, ha->req_q_count); ++ goto queuing_error; ++ } + + /* Calculate the number of request entries needed. */ + nseg = scsi_dma_map(cmd); +@@ -258,8 +282,8 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + + /* Set data transfer direction control flags + * NOTE: Look at data_direction bits iff there is data to be +- * transferred, as the data direction bit is sometimed filled +- * in when there is no data to be transferred */ ++ * transferred, as the data direction bit is sometimed filled ++ * in when there is no data to be transferred */ + cmd_entry->control_flags = CF_NO_DATA; + if (scsi_bufflen(cmd)) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) +@@ -286,7 +310,6 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + break; + } + +- + /* Advance request queue pointer */ + ha->request_in++; + if (ha->request_in == REQUEST_QUEUE_DEPTH) { +@@ -313,6 +336,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + } + + srb->cmd->host_scribble = (unsigned char *)srb; ++ ha->active_srb_array[index] = srb; + + /* update counters */ + srb->state = SRB_ACTIVE_STATE; +@@ -331,6 +355,9 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) + return QLA_SUCCESS; + + queuing_error: ++ if (srb->flags & SRB_SCSI_PASSTHRU) ++ return QLA_ERROR; ++ + if (tot_dsds) + scsi_dma_unmap(cmd); + +@@ -338,4 +365,3 @@ queuing_error: + + return QLA_ERROR; + } +- +diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c +index 799120f..dfe985b 100644 +--- a/drivers/scsi/qla4xxx/ql4_isr.c ++++ b/drivers/scsi/qla4xxx/ql4_isr.c +@@ -6,6 +6,7 @@ + */ + + #include "ql4_def.h" ++#include "ql4_version.h" + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" +@@ -27,11 +28,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + + srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); + if (!srb) { +- /* FIXMEdg: Don't we need to reset ISP in this case??? */ +- DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid " +- "handle 0x%x, sp=%p. This cmd may have already " +- "been completed.\n", ha->host_no, __func__, +- le32_to_cpu(sts_entry->handle), srb)); + dev_warn(&ha->pdev->dev, "%s invalid status entry:" + " handle=0x%0x\n", __func__, sts_entry->handle); + set_bit(DPC_RESET_HA, &ha->dpc_flags); +@@ -40,12 +36,9 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + + cmd = srb->cmd; + if (cmd == NULL) { +- DEBUG2(printk("scsi%ld: %s: Command already returned back to " +- "OS pkt->handle=%d srb=%p srb->state:%d\n", +- ha->host_no, __func__, sts_entry->handle, +- srb, srb->state)); +- dev_warn(&ha->pdev->dev, "Command is NULL:" +- " already returned to OS (srb=%p)\n", srb); ++ dev_warn(&ha->pdev->dev, "%s Command is NULL: srb=%p" ++ " sts_handle=0x%0x srb_state=0x%0x\n", __func__, ++ srb, sts_entry->handle, srb->state); + return; + } + +@@ -61,27 +54,15 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + scsi_status = sts_entry->scsiStatus; + switch (sts_entry->completionStatus) { + case SCS_COMPLETE: +- + if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) { + cmd->result = DID_ERROR << 16; + break; + } +- +- if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) { ++ if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) { + scsi_set_resid(cmd, residual); + if (!scsi_status && ((scsi_bufflen(cmd) - residual) < +- cmd->underflow)) { +- ++ cmd->underflow)) { + cmd->result = DID_ERROR << 16; +- +- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " +- "Mid-layer Data underrun0, " +- "xferlen = 0x%x, " +- "residual = 0x%x\n", ha->host_no, +- cmd->device->channel, +- cmd->device->id, +- cmd->device->lun, __func__, +- scsi_bufflen(cmd), residual)); + break; + } + } +@@ -218,13 +202,13 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, + * will return DID_ERROR. + */ + DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " +- "Mid-layer Data underrun1, " +- "xferlen = 0x%x, " +- "residual = 0x%x\n", ha->host_no, +- cmd->device->channel, +- cmd->device->id, +- cmd->device->lun, __func__, +- scsi_bufflen(cmd), residual)); ++ "Mid-layer Data underrun len = 0x%x, " ++ "resid = 0x%x, compstat = 0x%x\n", ++ ha->host_no, cmd->device->channel, ++ cmd->device->id, cmd->device->lun, ++ __func__, scsi_bufflen(cmd), ++ residual, ++ sts_entry->completionStatus)); + + cmd->result = DID_ERROR << 16; + } else { +@@ -414,6 +398,15 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, + } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { + /* Immediately process the AENs that don't require much work. + * Only queue the database_changed AENs */ ++ ++ dev_info(&ha->pdev->dev, "%s mbx0 0x%08x mbx1 0x%08x" ++ " mbx2 0x%08x mbx3 0x%08x mbx4 0x%08x mbx5 0x%08x " ++ "mbx6 0x%08x mbx7 0x%08x\n", __func__, ++ readl(&ha->reg->mailbox[0]), readl(&ha->reg->mailbox[1]), ++ readl(&ha->reg->mailbox[2]), readl(&ha->reg->mailbox[3]), ++ readl(&ha->reg->mailbox[4]), readl(&ha->reg->mailbox[5]), ++ readl(&ha->reg->mailbox[6]), readl(&ha->reg->mailbox[7])); ++ + if (ha->aen_log.count < MAX_AEN_ENTRIES) { + for (i = 0; i < MBOX_AEN_REG_COUNT; i++) + ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] = +@@ -480,9 +473,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, + mbox_stat2 = readl(&ha->reg->mailbox[2]); + mbox_stat3 = readl(&ha->reg->mailbox[3]); + +- if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) ++ if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) + set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); +- else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) ++ else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) + set_bit(DPC_RESET_HA, &ha->dpc_flags); + break; + +@@ -604,6 +597,7 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, + **/ + irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) + { ++ + struct scsi_qla_host *ha; + uint32_t intr_status; + unsigned long flags = 0; +@@ -714,7 +708,17 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) + int i; + unsigned long flags; + ++ DEBUG6(dev_info(&ha->pdev->dev, "%s proc_aen 0x%x\n", ++ __func__, process_aen)); ++ + spin_lock_irqsave(&ha->hardware_lock, flags); ++ if (process_aen == FLUSH_DDB_CHANGED_AENS) { ++ ha->aen_q_count = MAX_AEN_ENTRIES; ++ ha->aen_out = ha->aen_in = 0; ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ return; ++ } ++ + while (ha->aen_out != ha->aen_in) { + aen = &ha->aen_q[ha->aen_out]; + /* copy aen information to local structure */ +@@ -727,60 +731,46 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) + if (ha->aen_out == MAX_AEN_ENTRIES) + ha->aen_out = 0; + +- spin_unlock_irqrestore(&ha->hardware_lock, flags); ++ DEBUG6(dev_info(&ha->pdev->dev, "%s mbx0 0x%x mbx1 0x%x mbx2 " ++ "0x%x mbx3 0x%x ddb 0x%p\n", __func__, mbox_sts[0], ++ mbox_sts[1], mbox_sts[2], mbox_sts[3], ++ qla4xxx_lookup_ddb_by_fw_index(ha, mbox_sts[2]))); + +- DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x" +- " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no, +- (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)), +- mbox_sts[0], mbox_sts[1], mbox_sts[2], +- mbox_sts[3], mbox_sts[4])); ++ if (process_aen == RELOGIN_DDB_CHANGED_AENS) { ++ /* for use during init time, we only want to ++ * relogin non-active ddbs */ ++ struct ddb_entry *ddb_entry; + +- switch (mbox_sts[0]) { +- case MBOX_ASTS_DATABASE_CHANGED: +- if (process_aen == FLUSH_DDB_CHANGED_AENS) { +- DEBUG2(printk("scsi%ld: AEN[%d] %04x, index " +- "[%d] state=%04x FLUSHED!\n", +- ha->host_no, ha->aen_out, +- mbox_sts[0], mbox_sts[2], +- mbox_sts[3])); +- break; +- } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) { +- /* for use during init time, we only want to +- * relogin non-active ddbs */ +- struct ddb_entry *ddb_entry; +- +- ddb_entry = +- /* FIXME: name length? */ +- qla4xxx_lookup_ddb_by_fw_index(ha, +- mbox_sts[2]); +- if (!ddb_entry) +- break; +- +- ddb_entry->dev_scan_wait_to_complete_relogin = +- 0; ++ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, mbox_sts[2]); ++ ++ if (ddb_entry) { ++ ++ DEBUG6(dev_info(&ha->pdev->dev, "%s ddb 0x%p " ++ "sess 0x%p conn 0x%p state 0x%x\n", ++ __func__, ddb_entry, ddb_entry->sess, ++ ddb_entry->conn, ddb_entry->state)); ++ ++ ddb_entry->dev_scan_wait_to_complete_relogin = 0; + ddb_entry->dev_scan_wait_to_start_relogin = + jiffies + +- ((ddb_entry->default_time2wait + +- 4) * HZ); ++ ((ddb_entry->default_time2wait + 4) * HZ); + + DEBUG2(printk("scsi%ld: ddb index [%d] initate" +- " RELOGIN after %d seconds\n", +- ha->host_no, +- ddb_entry->fw_ddb_index, +- ddb_entry->default_time2wait + +- 4)); +- break; ++ " RELOGIN after %d seconds\n", ha->host_no, ++ ddb_entry->fw_ddb_index, ++ ddb_entry->default_time2wait + 4)); + } +- ++ } else if (mbox_sts[0] == MBOX_ASTS_DATABASE_CHANGED) { ++ spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (mbox_sts[1] == 0) { /* Global DB change. */ + qla4xxx_reinitialize_ddb_list(ha); + } else if (mbox_sts[1] == 1) { /* Specific device. */ + qla4xxx_process_ddb_changed(ha, mbox_sts[2], +- mbox_sts[3]); ++ mbox_sts[3], ++ ((process_aen == PROCESS_FOR_PROBE) ? 1 : 0 )); + } +- break; ++ spin_lock_irqsave(&ha->hardware_lock, flags); + } +- spin_lock_irqsave(&ha->hardware_lock, flags); + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } +diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c +index c577d79..dbd7218 100644 +--- a/drivers/scsi/qla4xxx/ql4_mbx.c ++++ b/drivers/scsi/qla4xxx/ql4_mbx.c +@@ -6,6 +6,7 @@ + */ + + #include "ql4_def.h" ++#include "ql4_version.h" + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" +@@ -23,9 +24,9 @@ + * If outCount is 0, this routine completes successfully WITHOUT waiting + * for the mailbox command to complete. + **/ +-static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, +- uint8_t outCount, uint32_t *mbx_cmd, +- uint32_t *mbx_sts) ++int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, ++ uint8_t outCount, uint32_t *mbx_cmd, ++ uint32_t *mbx_sts) + { + int status = QLA_ERROR; + uint8_t i; +@@ -39,9 +40,9 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + "pointer\n", ha->host_no, __func__)); + return status; + } ++ + /* Mailbox code active */ + wait_count = MBOX_TOV * 100; +- + while (wait_count--) { + mutex_lock(&ha->mbox_sem); + if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { +@@ -87,8 +88,6 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + readl(&ha->reg->ctrl_status); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + +- /* Wait for completion */ +- + /* + * If we don't want status, don't wait for the mailbox command to + * complete. For example, MBOX_CMD_RESET_FW doesn't return status, +@@ -98,6 +97,8 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + status = QLA_SUCCESS; + goto mbox_exit; + } ++ /* Wait for completion */ ++ set_current_state(TASK_UNINTERRUPTIBLE); + /* Wait for command to complete */ + wait_count = jiffies + MBOX_TOV * HZ; + while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { +@@ -119,6 +120,7 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + spin_unlock_irqrestore(&ha->hardware_lock, flags); + msleep(10); + } ++ set_current_state(TASK_RUNNING); + + /* Check for mailbox timeout. */ + if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { +@@ -172,6 +174,86 @@ mbox_exit: + return status; + } + ++ ++/** ++ * qla4xxx_issue_iocb - issue mailbox iocb command ++ * @ha: adapter state pointer. ++ * @buffer: buffer pointer. ++ * @phys_addr: physical address of buffer. ++ * @size: size of buffer. ++ * ++ * Issues iocbs via mailbox commands. ++ * TARGET_QUEUE_LOCK must be released. ++ * ADAPTER_STATE_LOCK must be released. ++ **/ ++int ++qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer, ++ dma_addr_t phys_addr, size_t size) ++{ ++ uint32_t mbox_cmd[MBOX_REG_COUNT]; ++ uint32_t mbox_sts[MBOX_REG_COUNT]; ++ int status; ++ ++ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); ++ memset(&mbox_sts, 0, sizeof(mbox_sts)); ++ ++ mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64; ++ mbox_cmd[1] = 0; ++ mbox_cmd[2] = LSDW(phys_addr); ++ mbox_cmd[3] = MSDW(phys_addr); ++ ++ status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); ++ return status; ++} ++ ++int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, ++ uint16_t fw_ddb_index, ++ uint16_t connection_id, ++ uint16_t option) ++{ ++ uint32_t mbox_cmd[MBOX_REG_COUNT]; ++ uint32_t mbox_sts[MBOX_REG_COUNT]; ++ ++ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); ++ memset(&mbox_sts, 0, sizeof(mbox_sts)); ++ ++ mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; ++ mbox_cmd[1] = fw_ddb_index; ++ mbox_cmd[2] = connection_id; ++ mbox_cmd[3] = LOGOUT_OPTION_RELOGIN; ++ ++ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) != ++ QLA_SUCCESS) { ++ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " ++ "option %04x failed sts %04X %04X", ++ ha->host_no, __func__, ++ option, mbox_sts[0], mbox_sts[1])); ++ if (mbox_sts[0] == 0x4005) ++ DEBUG2(printk("%s reason %04X\n", __func__, ++ mbox_sts[1])); ++ } ++ return QLA_SUCCESS; ++} ++ ++int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, ++ uint16_t fw_ddb_index) ++{ ++ uint32_t mbox_cmd[MBOX_REG_COUNT]; ++ uint32_t mbox_sts[MBOX_REG_COUNT]; ++ ++ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); ++ memset(&mbox_sts, 0, sizeof(mbox_sts)); ++ ++ mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY; ++ mbox_cmd[1] = fw_ddb_index; ++ ++ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != ++ QLA_SUCCESS) ++ return QLA_ERROR; ++ ++ return QLA_SUCCESS; ++} ++ + /** + * qla4xxx_initialize_fw_cb - initializes firmware control block. + * @ha: Pointer to host adapter structure. +@@ -450,15 +532,16 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, + mbox_sts[1])); + goto exit_get_fwddb; + } ++ + if (fw_ddb_entry) { +- dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " +- "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", ++ DEBUG6(dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d Next %d " ++ "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", __func__, + fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], + mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0], + fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2], + fw_ddb_entry->ip_addr[3], + le16_to_cpu(fw_ddb_entry->port), +- fw_ddb_entry->iscsi_name); ++ fw_ddb_entry->iscsi_name)); + } + if (num_valid_ddb_entries) + *num_valid_ddb_entries = mbox_sts[2]; +@@ -518,6 +601,31 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, + return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); + } + ++int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha, ++ uint16_t fw_ddb_index) ++{ ++ int status = QLA_ERROR; ++ uint32_t mbox_cmd[MBOX_REG_COUNT]; ++ uint32_t mbox_sts[MBOX_REG_COUNT]; ++ ++ /* Do not wait for completion. The firmware will send us an ++ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. ++ */ ++ memset(&mbox_cmd, 0, sizeof(mbox_cmd)); ++ memset(&mbox_sts, 0, sizeof(mbox_sts)); ++ ++ mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN; ++ mbox_cmd[1] = (uint32_t) fw_ddb_index; ++ mbox_cmd[6] = 1; ++ ++ status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 0, &mbox_cmd[0], &mbox_sts[0]); ++ DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n", ++ __func__, fw_ddb_index, status, mbox_sts[0], ++ mbox_sts[1]);) ++ ++ return status; ++} ++ + /** + * qla4xxx_get_crash_record - retrieves crash record. + * @ha: Pointer to host adapter structure. +@@ -642,7 +750,7 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) + DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", + ha->host_no, num_valid_entries)); + +- if (ql4xextended_error_logging == 3) { ++ if (extended_error_logging == 3) { + if (oldest_entry == 0) { + /* Circular Buffer has not wrapped around */ + for (i=0; i < num_valid_entries; i++) { +@@ -713,45 +821,6 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, + return status; + } + +-/** +- * qla4xxx_reset_target - issues target Reset +- * @ha: Pointer to host adapter structure. +- * @db_entry: Pointer to device database entry +- * @un_entry: Pointer to lun entry structure +- * +- * This routine performs a TARGET RESET on the specified target. +- * The caller must ensure that the ddb_entry pointers +- * are valid before calling this routine. +- **/ +-int qla4xxx_reset_target(struct scsi_qla_host *ha, +- struct ddb_entry *ddb_entry) +-{ +- uint32_t mbox_cmd[MBOX_REG_COUNT]; +- uint32_t mbox_sts[MBOX_REG_COUNT]; +- int status = QLA_SUCCESS; +- +- DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, +- ddb_entry->os_target_id)); +- +- /* +- * Send target reset command to ISP, so that the ISP will return all +- * outstanding requests with RESET status +- */ +- memset(&mbox_cmd, 0, sizeof(mbox_cmd)); +- memset(&mbox_sts, 0, sizeof(mbox_sts)); +- +- mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; +- mbox_cmd[1] = ddb_entry->fw_ddb_index; +- mbox_cmd[5] = 0x01; /* Immediate Command Enable */ +- +- qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], +- &mbox_sts[0]); +- if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && +- mbox_sts[0] != MBOX_STS_COMMAND_ERROR) +- status = QLA_ERROR; +- +- return status; +-} + + int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, + uint32_t offset, uint32_t len) +@@ -782,8 +851,8 @@ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, + * qla4xxx_get_fw_version - gets firmware version + * @ha: Pointer to host adapter structure. + * +- * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may +- * hold an address for data. Make sure that we write 0 to those mailboxes, ++ * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may ++ * hold an address for data. Make sure that we write 0 to those mailboxes, + * if unused. + **/ + int qla4xxx_get_fw_version(struct scsi_qla_host * ha) +@@ -835,7 +904,7 @@ static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, + return QLA_SUCCESS; + } + +-static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) ++int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) + { + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; +@@ -889,14 +958,14 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) + if (ret_val != QLA_SUCCESS) + goto qla4xxx_send_tgts_exit; + +- memset(fw_ddb_entry->iscsi_alias, 0, ++ memset((void *)fw_ddb_entry->iscsi_alias, 0, + sizeof(fw_ddb_entry->iscsi_alias)); + +- memset(fw_ddb_entry->iscsi_name, 0, ++ memset((void *)fw_ddb_entry->iscsi_name, 0, + sizeof(fw_ddb_entry->iscsi_name)); + +- memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); +- memset(fw_ddb_entry->tgt_addr, 0, ++ memset((void *)fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); ++ memset((void *)fw_ddb_entry->tgt_addr, 0, + sizeof(fw_ddb_entry->tgt_addr)); + + fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET); +diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c +index 7fe0482..67cfd0a 100644 +--- a/drivers/scsi/qla4xxx/ql4_nvram.c ++++ b/drivers/scsi/qla4xxx/ql4_nvram.c +@@ -6,6 +6,7 @@ + */ + + #include "ql4_def.h" ++#include "ql4_version.h" + #include "ql4_glbl.h" + #include "ql4_dbg.h" + #include "ql4_inline.h" +diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h +index b47b4fc..08e2aed 100644 +--- a/drivers/scsi/qla4xxx/ql4_nvram.h ++++ b/drivers/scsi/qla4xxx/ql4_nvram.h +@@ -134,7 +134,9 @@ struct eeprom_data { + u16 phyConfig; /* x36 */ + #define PHY_CONFIG_PHY_ADDR_MASK 0x1f + #define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20 +- u16 reserved_56; /* x38 */ ++ u16 topcat; /* x38 */ ++#define TOPCAT_PRESENT 0x0100 ++#define TOPCAT_MASK 0xFF00 + + #define EEPROM_UNUSED_1_SIZE 2 + u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */ +diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c +index 4255b36..a62188b 100644 +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -1,6 +1,6 @@ + /* + * QLogic iSCSI HBA Driver +- * Copyright (c) 2003-2006 QLogic Corporation ++ * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ +@@ -9,6 +9,7 @@ + #include + #include + ++#include + #include "ql4_def.h" + #include "ql4_version.h" + #include "ql4_glbl.h" +@@ -18,7 +19,18 @@ + /* + * Driver version + */ +-static char qla4xxx_version_str[40]; ++char qla4xxx_version_str[40]; ++EXPORT_SYMBOL_GPL(qla4xxx_version_str); ++ ++/* ++ * List of host adapters ++ */ ++struct klist qla4xxx_hostlist; ++ ++struct klist *qla4xxx_hostlist_ptr = &qla4xxx_hostlist; ++EXPORT_SYMBOL_GPL(qla4xxx_hostlist_ptr); ++ ++static atomic_t qla4xxx_hba_count; + + /* + * SRB allocation cache +@@ -38,16 +50,13 @@ MODULE_PARM_DESC(ql4xdontresethba, + " default it will reset hba :0" + " set to 1 to avoid resetting HBA"); + +-int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ +-module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR); +-MODULE_PARM_DESC(ql4xextended_error_logging, ++int extended_error_logging = 0; /* 0 = off, 1 = log errors */ ++module_param(extended_error_logging, int, S_IRUGO | S_IRUSR); ++MODULE_PARM_DESC(extended_error_logging, + "Option to enable extended error logging, " + "Default is 0 - no logging, 1 - debug logging"); + + int ql4_mod_unload = 0; +- +-#define QL4_DEF_QDEPTH 32 +- + /* + * SCSI host template entry points + */ +@@ -73,12 +82,9 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); + static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)); + static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); +-static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); + static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); + static int qla4xxx_slave_alloc(struct scsi_device *device); + static int qla4xxx_slave_configure(struct scsi_device *device); +-static void qla4xxx_slave_destroy(struct scsi_device *sdev); +-static void qla4xxx_scan_start(struct Scsi_Host *shost); + + static struct scsi_host_template qla4xxx_driver_template = { + .module = THIS_MODULE, +@@ -87,15 +93,10 @@ static struct scsi_host_template qla4xxx_driver_template = { + .queuecommand = qla4xxx_queuecommand, + + .eh_device_reset_handler = qla4xxx_eh_device_reset, +- .eh_target_reset_handler = qla4xxx_eh_target_reset, + .eh_host_reset_handler = qla4xxx_eh_host_reset, + + .slave_configure = qla4xxx_slave_configure, + .slave_alloc = qla4xxx_slave_alloc, +- .slave_destroy = qla4xxx_slave_destroy, +- +- .scan_finished = iscsi_scan_finished, +- .scan_start = qla4xxx_scan_start, + + .this_id = -1, + .cmd_per_lun = 3, +@@ -108,13 +109,10 @@ static struct scsi_host_template qla4xxx_driver_template = { + static struct iscsi_transport qla4xxx_iscsi_transport = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, +- .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD | +- CAP_DATA_PATH_OFFLOAD, +- .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | +- ISCSI_TARGET_NAME | ISCSI_TPGT, +- .host_param_mask = ISCSI_HOST_HWADDRESS | +- ISCSI_HOST_IPADDRESS | +- ISCSI_HOST_INITIATOR_NAME, ++ .param_mask = ISCSI_CONN_PORT | ++ ISCSI_CONN_ADDRESS | ++ ISCSI_TARGET_NAME | ++ ISCSI_TPGT, + .tgt_dscvr = qla4xxx_tgt_dscvr, + .get_conn_param = qla4xxx_conn_get_param, + .get_session_param = qla4xxx_sess_get_param, +@@ -129,19 +127,16 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) + struct ddb_entry *ddb_entry = session->dd_data; + struct scsi_qla_host *ha = ddb_entry->ha; + +- if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { +- atomic_set(&ddb_entry->state, DDB_STATE_DEAD); ++ atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + +- DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " +- "of (%d) secs exhausted, marking device DEAD.\n", +- ha->host_no, __func__, ddb_entry->fw_ddb_index, +- ha->port_down_retry_count)); ++ dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked DEAD" ++ " - retry count of (%d)\n", __func__, ++ ddb_entry->fw_ddb_index, ddb_entry->os_target_id, ++ ha->port_down_retry_count); + +- DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " +- "flags = 0x%lx\n", +- ha->host_no, __func__, ha->dpc_flags)); +- queue_work(ha->dpc_thread, &ha->dpc_work); +- } ++ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " ++ "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); ++ queue_work(ha->dpc_thread, &ha->dpc_work); + } + + static int qla4xxx_host_get_param(struct Scsi_Host *shost, +@@ -151,16 +146,13 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, + int len; + + switch (param) { +- case ISCSI_HOST_PARAM_HWADDRESS: +- len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); +- break; + case ISCSI_HOST_PARAM_IPADDRESS: +- len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0], +- ha->ip_address[1], ha->ip_address[2], +- ha->ip_address[3]); ++ len = sprintf(buf, "%d.%d.%d.%d", ha->ip_address[0], ++ ha->ip_address[1], ha->ip_address[2], ++ ha->ip_address[3]); + break; + case ISCSI_HOST_PARAM_INITIATOR_NAME: +- len = sprintf(buf, "%s\n", ha->name_string); ++ len = sprintf(buf, "%s", ha->name_string); + break; + default: + return -ENOSYS; +@@ -169,6 +161,38 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, + return len; + } + ++int qla4xxx_conn_start(struct iscsi_cls_conn *conn) ++{ ++ struct iscsi_cls_session *session; ++ struct ddb_entry *ddb_entry; ++ ++ session = iscsi_dev_to_session(conn->dev.parent); ++ ddb_entry = session->dd_data; ++ ++ DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", ++ ddb_entry->ha->host_no, __func__, ++ ddb_entry->fw_ddb_index)); ++ iscsi_unblock_session(session); ++ return 0; ++} ++ ++static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) ++{ ++ struct iscsi_cls_session *session; ++ struct ddb_entry *ddb_entry; ++ ++ session = iscsi_dev_to_session(conn->dev.parent); ++ ddb_entry = session->dd_data; ++ ++ DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", ++ ddb_entry->ha->host_no, __func__, ++ ddb_entry->fw_ddb_index)); ++ if (flag == STOP_CONN_RECOVER) ++ iscsi_block_session(session); ++ else ++ printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); ++} ++ + static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, + enum iscsi_param param, char *buf) + { +@@ -177,11 +201,11 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, + + switch (param) { + case ISCSI_PARAM_TARGET_NAME: +- len = snprintf(buf, PAGE_SIZE - 1, "%s\n", +- ddb_entry->iscsi_name); ++ len = snprintf(buf, PAGE_SIZE - 1, "%s", ++ ddb_entry->iscsi_name); + break; + case ISCSI_PARAM_TPGT: +- len = sprintf(buf, "%u\n", ddb_entry->tpgt); ++ len = sprintf(buf, "%u", ddb_entry->tpgt); + break; + default: + return -ENOSYS; +@@ -202,12 +226,12 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, + + switch (param) { + case ISCSI_PARAM_CONN_PORT: +- len = sprintf(buf, "%hu\n", ddb_entry->port); ++ len = sprintf(buf, "%u", (uint32_t)ddb_entry->port); + break; + case ISCSI_PARAM_CONN_ADDRESS: + /* TODO: what are the ipv6 bits */ +- len = sprintf(buf, "%u.%u.%u.%u\n", +- NIPQUAD(ddb_entry->ip_addr)); ++ len = sprintf(buf, "%u.%u.%u.%u", ++ NIPQUAD(ddb_entry->ip_addr)); + break; + default: + return -ENOSYS; +@@ -257,17 +281,15 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) + return; + + if (ddb_entry->conn) { +- atomic_set(&ddb_entry->state, DDB_STATE_DEAD); + iscsi_remove_session(ddb_entry->sess); + } + iscsi_free_session(ddb_entry->sess); + } + +-int qla4xxx_add_sess(struct ddb_entry *ddb_entry) ++int qla4xxx_add_sess(struct ddb_entry *ddb_entry, int scan) + { + int err; + +- ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; + err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); + if (err) { + DEBUG2(printk(KERN_ERR "Could not add session.\n")); +@@ -281,7 +303,11 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) + return -ENOMEM; + } + +- /* finally ready to go */ ++ ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; ++ if (scan) ++ scsi_scan_target(&ddb_entry->sess->dev, 0, ++ ddb_entry->sess->target_id, ++ SCAN_WILD_CARD, 0); + iscsi_unblock_session(ddb_entry->sess); + return 0; + } +@@ -292,7 +318,7 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) + struct iscsi_cls_session *sess; + + sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport, +- sizeof(struct ddb_entry)); ++ sizeof(struct ddb_entry)); + if (!sess) + return NULL; + +@@ -303,18 +329,6 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) + return ddb_entry; + } + +-static void qla4xxx_scan_start(struct Scsi_Host *shost) +-{ +- struct scsi_qla_host *ha = shost_priv(shost); +- struct ddb_entry *ddb_entry, *ddbtemp; +- +- /* finish setup of sessions that were already setup in firmware */ +- list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { +- if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) +- qla4xxx_add_sess(ddb_entry); +- } +-} +- + /* + * Timer routines + */ +@@ -323,7 +337,7 @@ static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, + unsigned long interval) + { + DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", +- __func__, ha->host->host_no)); ++ __func__, ha->host->host_no)); + init_timer(&ha->timer); + ha->timer.expires = jiffies + interval * HZ; + ha->timer.data = (unsigned long)ha; +@@ -349,11 +363,11 @@ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) + { + atomic_set(&ddb_entry->state, DDB_STATE_MISSING); +- DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", +- ha->host_no, ddb_entry->bus, ddb_entry->target, +- ddb_entry->fw_ddb_index)); +- iscsi_block_session(ddb_entry->sess); +- iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); ++ ++ dev_info(&ha->pdev->dev, "%s: ddb[%d] os[%d] marked MISSING\n", ++ __func__, ddb_entry->fw_ddb_index, ddb_entry->os_target_id); ++ ++ qla4xxx_conn_stop(ddb_entry->conn, STOP_CONN_RECOVER); + } + + static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, +@@ -393,10 +407,10 @@ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) + { + struct scsi_cmnd *cmd = srb->cmd; + +- qla4xxx_srb_free_dma(ha, srb); +- +- mempool_free(srb, ha->srb_mempool); +- ++ if (!(srb->flags & SRB_SCSI_PASSTHRU)) { ++ qla4xxx_srb_free_dma(ha, srb); ++ mempool_free(srb, ha->srb_mempool); ++ } + cmd->scsi_done(cmd); + } + +@@ -404,7 +418,7 @@ void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) + * qla4xxx_queuecommand - scsi layer issues scsi command to driver. + * @cmd: Pointer to Linux's SCSI command structure + * @done_fn: Function that the driver calls to notify the SCSI mid-layer +- * that the command has been processed. ++ * that the command has been processed. + * + * Remarks: + * This routine is invoked by Linux to send a SCSI command to the driver. +@@ -419,30 +433,20 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, + { + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; +- struct iscsi_cls_session *sess = ddb_entry->sess; + struct srb *srb; + int rval; + +- if (!sess) { +- cmd->result = DID_IMM_RETRY << 16; +- goto qc_fail_command; +- } +- +- rval = iscsi_session_chkready(sess); +- if (rval) { +- cmd->result = rval; +- goto qc_fail_command; +- } +- + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) { + cmd->result = DID_NO_CONNECT << 16; + goto qc_fail_command; + } +- return SCSI_MLQUEUE_TARGET_BUSY; ++ goto qc_host_busy; + } + +- if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) ++ if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || ++ test_bit(DPC_RESET_HA, &ha->dpc_flags) || ++ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) + goto qc_host_busy; + + spin_unlock_irq(ha->host->host_lock); +@@ -596,7 +600,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) + if (atomic_read(&ddb_entry->retry_relogin_timer) != + INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) +- == 0) { ++ == 0) { + atomic_set(&ddb_entry-> + retry_relogin_timer, + INVALID_ENTRY); +@@ -669,7 +673,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) + test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || + test_bit(DPC_AEN, &ha->dpc_flags)) && +- ha->dpc_thread) { ++ ha->dpc_thread) { + DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" + " - dpc flags = 0x%lx\n", + ha->host_no, __func__, ha->dpc_flags)); +@@ -694,7 +698,6 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) + uint32_t index = 0; + int stat = QLA_SUCCESS; + unsigned long flags; +- struct scsi_cmnd *cmd; + int wait_cnt = WAIT_CMD_TOV; /* + * Initialized for 30 seconds as we + * expect all commands to retuned +@@ -704,15 +707,14 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) + while (wait_cnt) { + spin_lock_irqsave(&ha->hardware_lock, flags); + /* Find a command that hasn't completed. */ +- for (index = 0; index < ha->host->can_queue; index++) { +- cmd = scsi_host_find_tag(ha->host, index); +- if (cmd != NULL) ++ for (index = 1; index < MAX_SRBS; index++) { ++ if (ha->active_srb_array[index] != NULL) + break; + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + /* If No Commands are pending, wait is complete */ +- if (index == ha->host->can_queue) { ++ if (index == MAX_SRBS) { + break; + } + +@@ -738,7 +740,6 @@ void qla4xxx_hw_reset(struct scsi_qla_host *ha) + DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); + + spin_lock_irqsave(&ha->hardware_lock, flags); +- + /* + * If the SCSI Reset Interrupt bit is set, clear it. + * Otherwise, the Soft Reset won't work. +@@ -865,9 +866,9 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); +- for (i = 0; i < ha->host->can_queue; i++) { +- srb = qla4xxx_del_from_active_array(ha, i); +- if (srb != NULL) { ++ for (i = 1; i < MAX_SRBS; i++) { ++ if ((srb = ha->active_srb_array[i]) != NULL) { ++ qla4xxx_del_from_active_array(ha, i); + srb->cmd->result = DID_RESET << 16; + qla4xxx_srb_compl(ha, srb); + } +@@ -879,19 +880,13 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) + /** + * qla4xxx_recover_adapter - recovers adapter after a fatal error + * @ha: Pointer to host adapter structure. +- * @renew_ddb_list: Indicates what to do with the adapter's ddb list +- * +- * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild +- * ddb list. + **/ +-static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, +- uint8_t renew_ddb_list) ++static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) + { + int status; + + /* Stall incoming I/O until we are done */ + clear_bit(AF_ONLINE, &ha->flags); +- + DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, + __func__)); + +@@ -909,7 +904,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, + * returns with ISP interrupts enabled. + */ + if (status == QLA_SUCCESS) { +- DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n", ++ DEBUG2(printk(KERN_ERR "scsi%ld: %s - Performing soft reset..\n", + ha->host_no, __func__)); + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) +@@ -929,7 +924,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, + + /* If successful, AF_ONLINE flag set in + * qla4xxx_initialize_adapter */ +- status = qla4xxx_initialize_adapter(ha, renew_ddb_list); ++ status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST); + } + + /* Failed adapter initialization? +@@ -990,7 +985,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, + * @data: in our case pointer to adapter structure + * + * This routine is a task that is schedule by the interrupt handler +- * to perform the background processing for interrupts. We put it ++ * to perform the background processing for interrupts. We put it + * on a task queue that is consumed whenever the scheduler runs; that's + * so you can do anything (i.e. put the process to sleep etc). In fact, + * the mid-level tries to sleep when it reaches the driver threshold +@@ -1004,7 +999,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) + int status = QLA_ERROR; + + DEBUG2(printk("scsi%ld: %s: DPC handler waking up." +- "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n", ++ "ha->flags=0x%08lx ha->dpc_flags=0x%08lx" ++ " ctrl_status=0x%08x\n", + ha->host_no, __func__, ha->flags, ha->dpc_flags, + readw(&ha->reg->ctrl_status))); + +@@ -1017,8 +1013,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) + test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { + if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || +- test_bit(DPC_RESET_HA, &ha->dpc_flags)) +- qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); ++ test_bit(DPC_RESET_HA, &ha->dpc_flags)) ++ qla4xxx_recover_adapter(ha); + + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { + uint8_t wait_time = RESET_INTR_TOV; +@@ -1036,7 +1032,7 @@ static void qla4xxx_do_dpc(struct work_struct *work) + qla4xxx_flush_active_srbs(ha); + if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); +- status = qla4xxx_initialize_adapter(ha, ++ status = qla4xxx_initialize_adapter(ha, + PRESERVE_DDB_LIST); + } + clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); +@@ -1070,8 +1066,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) + */ + if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + printk(KERN_WARNING "scsi%ld: %s: " +- "need to reset hba\n", +- ha->host_no, __func__); ++ "need to reset hba\n", ++ ha->host_no, __func__); + break; + } + } +@@ -1110,7 +1106,6 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) + qla4xxx_mem_free(ha); + + pci_disable_device(ha->pdev); +- + } + + /*** +@@ -1147,7 +1142,6 @@ static int qla4xxx_iospace_config(struct scsi_qla_host *ha) + if (!(mmio_flags & IORESOURCE_MEM)) { + dev_err(&ha->pdev->dev, + "region #0 not an MMIO resource, aborting\n"); +- + goto iospace_error_exit; + } + if (mmio_len < MIN_IOBASE_LEN) { +@@ -1179,6 +1173,14 @@ iospace_error_exit: + return -ENOMEM; + } + ++static void ql4_get_aen_log(struct scsi_qla_host *ha, struct ql4_aen_log *aenl) ++{ ++ if (aenl) { ++ memcpy(aenl, &ha->aen_log, sizeof (ha->aen_log)); ++ ha->aen_log.count = 0; ++ } ++} ++ + /** + * qla4xxx_probe_adapter - callback function to probe HBA + * @pdev: pointer to pci_dev structure +@@ -1194,6 +1196,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + int ret = -ENODEV, status; + struct Scsi_Host *host; + struct scsi_qla_host *ha; ++ struct ddb_entry *ddb_entry, *ddbtemp; + uint8_t init_retry_count = 0; + char buf[34]; + +@@ -1211,18 +1214,22 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + ha = (struct scsi_qla_host *) host->hostdata; + memset(ha, 0, sizeof(*ha)); + +- /* Save the information from PCI BIOS. */ ++ /* Save the information from PCI BIOS. */ + ha->pdev = pdev; + ha->host = host; + ha->host_no = host->host_no; + ++ ha->ql4mbx = qla4xxx_mailbox_command; ++ ha->ql4cmd = qla4xxx_send_command_to_isp; ++ ha->ql4getaenlog = ql4_get_aen_log; ++ + /* Configure PCI I/O space. */ + ret = qla4xxx_iospace_config(ha); + if (ret) + goto probe_failed; + + dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n", +- pdev->device, pdev->irq, ha->reg); ++ pdev->device, pdev->irq, ha->reg); + + qla4xxx_config_dma_addressing(ha); + +@@ -1233,11 +1240,12 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + mutex_init(&ha->mbox_sem); + + spin_lock_init(&ha->hardware_lock); ++ spin_lock_init(&ha->list_lock); + + /* Allocate dma buffers */ + if (qla4xxx_mem_alloc(ha)) { + dev_warn(&ha->pdev->dev, +- "[ERROR] Failed to allocate memory for adapter\n"); ++ "[ERROR] Failed to allocate memory for adapter\n"); + + ret = -ENOMEM; + goto probe_failed; +@@ -1250,8 +1258,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + */ + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); + while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) { +- DEBUG2(printk("scsi: %s: retrying adapter initialization " +- "(%d)\n", __func__, init_retry_count)); ++ DEBUG2(printk(KERN_ERR "scsi%ld: %s: retrying adapter initialization " ++ "(%d)\n", ha->host_no, __func__, init_retry_count)); + qla4xxx_soft_reset(ha); + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); + } +@@ -1267,15 +1275,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + host->max_lun = MAX_LUNS - 1; + host->max_id = MAX_TARGETS; + host->max_cmd_len = IOCB_MAX_CDB_LEN; +- host->can_queue = MAX_SRBS ; ++ host->can_queue = REQUEST_QUEUE_DEPTH + 128; + host->transportt = qla4xxx_scsi_transport; + +- ret = scsi_init_shared_tag_map(host, MAX_SRBS); +- if (ret) { +- dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n"); +- goto probe_failed; +- } +- + /* Startup the kernel thread for this host adapter. */ + DEBUG2(printk("scsi: %s: Starting kernel thread for " + "qla4xxx_dpc\n", __func__)); +@@ -1287,9 +1289,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + goto probe_failed; + } + INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); +- + ret = request_irq(pdev->irq, qla4xxx_intr_handler, +- IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); ++ IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); + if (ret) { + dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" + " already in use.\n", pdev->irq); +@@ -1312,15 +1313,39 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, + if (ret) + goto probe_failed; + ++ /* Update transport device information for all devices. */ ++ list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { ++ ++ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) ++ set_bit(DF_SCAN_ISSUED, &ddb_entry->flags); ++ ++ if (qla4xxx_add_sess(ddb_entry, ++ test_bit(DF_SCAN_ISSUED, &ddb_entry->flags))) ++ goto remove_host; ++ if (!test_bit(DF_SCAN_ISSUED, &ddb_entry->flags)) ++ qla4xxx_mark_device_missing(ha, ddb_entry); ++ } ++ + printk(KERN_INFO + " QLogic iSCSI HBA Driver version: %s\n" +- " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", +- qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), ++ " QLogic ISP%04x @ %s, pdev = %p host#=%ld, fw=%02d.%02d.%02d.%02d\n", ++ qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), pdev, + ha->host_no, ha->firmware_version[0], ha->firmware_version[1], + ha->patch_number, ha->build_number); +- scsi_scan_host(host); ++ ++ /* Insert new entry into the list of adapters. */ ++ klist_add_tail(&ha->node, &qla4xxx_hostlist); ++ ha->instance = atomic_inc_return(&qla4xxx_hba_count) - 1; ++ ++ DEBUG2(printk("qla4xxx: listhead=%p, done adding ha=%p i=%d\n", ++ &qla4xxx_hostlist, &ha->node, ha->instance)); ++ + return 0; + ++remove_host: ++ qla4xxx_free_ddb_list(ha); ++ scsi_remove_host(host); ++ + probe_failed: + qla4xxx_free_adapter(ha); + scsi_host_put(ha->host); +@@ -1346,6 +1371,9 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) + while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) + ssleep(1); + ++ klist_remove(&ha->node); ++ atomic_dec(&qla4xxx_hba_count); ++ + /* remove devs from iscsi_sessions to scsi_devices */ + qla4xxx_free_ddb_list(ha); + +@@ -1374,7 +1402,7 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) + if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { + dev_dbg(&ha->pdev->dev, + "Failed to set 64 bit PCI consistent mask; " +- "using 32 bit.\n"); ++ "using 32 bit.\n"); + retval = pci_set_consistent_dma_mask(ha->pdev, + DMA_32BIT_MASK); + } +@@ -1385,23 +1413,22 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) + static int qla4xxx_slave_alloc(struct scsi_device *sdev) + { + struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); +- struct ddb_entry *ddb = sess->dd_data; + +- sdev->hostdata = ddb; +- sdev->tagged_supported = 1; +- scsi_activate_tcq(sdev, QL4_DEF_QDEPTH); +- return 0; ++ if (sess) { ++ sdev->hostdata = sess->dd_data; ++ return 0; ++ } ++ return FAILED; + } + + static int qla4xxx_slave_configure(struct scsi_device *sdev) + { +- sdev->tagged_supported = 1; +- return 0; +-} ++ if (sdev->tagged_supported) ++ scsi_activate_tcq(sdev, 32); ++ else ++ scsi_deactivate_tcq(sdev, 32); + +-static void qla4xxx_slave_destroy(struct scsi_device *sdev) +-{ +- scsi_deactivate_tcq(sdev, 1); ++ return 0; + } + + /** +@@ -1414,12 +1441,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) + struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) + { + struct srb *srb = NULL; +- struct scsi_cmnd *cmd; + +- if (!(cmd = scsi_host_find_tag(ha->host, index))) ++ /* validate handle and remove from active array */ ++ if (index >= MAX_SRBS) + return srb; + +- if (!(srb = (struct srb *)cmd->host_scribble)) ++ srb = ha->active_srb_array[index]; ++ ha->active_srb_array[index] = NULL; ++ if (!srb) + return srb; + + /* update counters */ +@@ -1467,24 +1496,18 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, + **/ + static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) + { +- unsigned long wait_online; +- +- wait_online = jiffies + (30 * HZ); +- while (time_before(jiffies, wait_online)) { ++ unsigned long wait_online = 60; + ++ while (wait_online--) { + if (adapter_up(ha)) + return QLA_SUCCESS; +- else if (ha->retry_reset_ha_cnt == 0) +- return QLA_ERROR; +- +- msleep(2000); ++ ssleep(2); + } +- + return QLA_ERROR; + } + + /** +- * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. ++ * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. + * @ha: pointer to to HBA + * @t: target id + * @l: lun id +@@ -1492,26 +1515,33 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) + * This function waits for all outstanding commands to a lun to complete. It + * returns 0 if all pending commands are returned and 1 otherwise. + **/ +-static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, +- struct scsi_target *stgt, +- struct scsi_device *sdev) ++static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, ++ int t, int l) + { + int cnt; +- int status = 0; ++ int status; ++ struct srb *sp; + struct scsi_cmnd *cmd; + + /* +- * Waiting for all commands for the designated target or dev +- * in the active array ++ * Waiting for all commands for the designated target in the active ++ * array + */ +- for (cnt = 0; cnt < ha->host->can_queue; cnt++) { +- cmd = scsi_host_find_tag(ha->host, cnt); +- if (cmd && stgt == scsi_target(cmd->device) && +- (!sdev || sdev == cmd->device)) { +- if (!qla4xxx_eh_wait_on_command(ha, cmd)) { +- status++; +- break; ++ status = 0; ++ for (cnt = 1; cnt < MAX_SRBS; cnt++) { ++ spin_lock(&ha->hardware_lock); ++ sp = ha->active_srb_array[cnt]; ++ if (sp) { ++ cmd = sp->cmd; ++ spin_unlock(&ha->hardware_lock); ++ if (cmd->device->id == t && cmd->device->lun == l) { ++ if (!qla4xxx_eh_wait_on_command(ha, cmd)) { ++ status++; ++ break; ++ } + } ++ } else { ++ spin_unlock(&ha->hardware_lock); + } + } + return status; +@@ -1528,47 +1558,49 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) + { + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; +- struct srb *sp; + int ret = FAILED, stat; + +- sp = (struct srb *) cmd->SCp.ptr; +- if (!sp || !ddb_entry) ++ if (!ddb_entry) + return ret; + + dev_info(&ha->pdev->dev, +- "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, +- cmd->device->channel, cmd->device->id, cmd->device->lun); ++ "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, ++ cmd->device->channel, cmd->device->id, cmd->device->lun); + +- DEBUG2(printk(KERN_INFO +- "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," +- "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, +- cmd, jiffies, cmd->request->timeout / HZ, +- ha->dpc_flags, cmd->result, cmd->allowed)); ++ if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { ++ dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__); ++ return FAILED; ++ } + +- /* FIXME: wait for hba to go online */ + stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); + if (stat != QLA_SUCCESS) { + dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat); + goto eh_dev_reset_done; + } + +- if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), +- cmd->device)) { +- dev_info(&ha->pdev->dev, +- "DEVICE RESET FAILED - waiting for " +- "commands.\n"); +- goto eh_dev_reset_done; ++ /* ++ * If we are coming down the EH path, wait for all commands to complete ++ * for the device. ++ */ ++ if (cmd->device->host->shost_state == SHOST_RECOVERY) { ++ if (qla4xxx_eh_wait_for_active_target_commands(ha, ++ cmd->device->id, ++ cmd->device-> ++ lun)) { ++ dev_info(&ha->pdev->dev, ++ "DEVICE RESET FAILED - waiting for " ++ "commands.\n"); ++ goto eh_dev_reset_done; ++ } + } +- +- /* Send marker. */ +- if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, +- MM_LUN_RESET) != QLA_SUCCESS) ++ if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun) ++ != QLA_SUCCESS) + goto eh_dev_reset_done; + + dev_info(&ha->pdev->dev, +- "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", +- ha->host_no, cmd->device->channel, cmd->device->id, +- cmd->device->lun); ++ "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", ++ ha->host_no, cmd->device->channel, cmd->device->id, ++ cmd->device->lun); + + ret = SUCCESS; + +@@ -1578,59 +1610,6 @@ eh_dev_reset_done: + } + + /** +- * qla4xxx_eh_target_reset - callback for target reset. +- * @cmd: Pointer to Linux's SCSI command structure +- * +- * This routine is called by the Linux OS to reset the target. +- **/ +-static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) +-{ +- struct scsi_qla_host *ha = to_qla_host(cmd->device->host); +- struct ddb_entry *ddb_entry = cmd->device->hostdata; +- int stat; +- +- if (!ddb_entry) +- return FAILED; +- +- starget_printk(KERN_INFO, scsi_target(cmd->device), +- "WARM TARGET RESET ISSUED.\n"); +- +- DEBUG2(printk(KERN_INFO +- "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " +- "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", +- ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, +- ha->dpc_flags, cmd->result, cmd->allowed)); +- +- stat = qla4xxx_reset_target(ha, ddb_entry); +- if (stat != QLA_SUCCESS) { +- starget_printk(KERN_INFO, scsi_target(cmd->device), +- "WARM TARGET RESET FAILED.\n"); +- return FAILED; +- } +- +- if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), +- NULL)) { +- starget_printk(KERN_INFO, scsi_target(cmd->device), +- "WARM TARGET DEVICE RESET FAILED - " +- "waiting for commands.\n"); +- return FAILED; +- } +- +- /* Send marker. */ +- if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, +- MM_TGT_WARM_RESET) != QLA_SUCCESS) { +- starget_printk(KERN_INFO, scsi_target(cmd->device), +- "WARM TARGET DEVICE RESET FAILED - " +- "marker iocb failed.\n"); +- return FAILED; +- } +- +- starget_printk(KERN_INFO, scsi_target(cmd->device), +- "WARM TARGET RESET SUCCEEDED.\n"); +- return SUCCESS; +-} +- +-/** + * qla4xxx_eh_host_reset - kernel callback + * @cmd: Pointer to Linux's SCSI command structure + * +@@ -1644,27 +1623,19 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) + + ha = (struct scsi_qla_host *) cmd->device->host->hostdata; + +- dev_info(&ha->pdev->dev, +- "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, +- cmd->device->channel, cmd->device->id, cmd->device->lun); ++ dev_info(&ha->pdev->dev, "%s: ADAPTER RESET ISSUED.\n", __func__); + + if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { +- DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " +- "DEAD.\n", ha->host_no, cmd->device->channel, +- __func__)); +- ++ dev_info(&ha->pdev->dev, "%s: HBA OFFLINE: FAILED\n", __func__); + return FAILED; + } + +- /* make sure the dpc thread is stopped while we reset the hba */ +- clear_bit(AF_ONLINE, &ha->flags); +- flush_workqueue(ha->dpc_thread); +- +- if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) ++ if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) { + return_status = SUCCESS; ++ } + + dev_info(&ha->pdev->dev, "HOST RESET %s.\n", +- return_status == FAILED ? "FAILED" : "SUCCEDED"); ++ return_status == FAILED ? "FAILED" : "SUCCEDED"); + + return return_status; + } +@@ -1704,9 +1675,11 @@ static int __init qla4xxx_module_init(void) + { + int ret; + ++ atomic_set(&qla4xxx_hba_count, 0); ++ klist_init(&qla4xxx_hostlist, NULL, NULL); + /* Allocate cache for SRBs. */ + srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, +- SLAB_HWCACHE_ALIGN, NULL); ++ SLAB_HWCACHE_ALIGN, NULL); + if (srb_cachep == NULL) { + printk(KERN_ERR + "%s: Unable to allocate SRB cache..." +@@ -1717,7 +1690,7 @@ static int __init qla4xxx_module_init(void) + + /* Derive version string. */ + strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); +- if (ql4xextended_error_logging) ++ if (extended_error_logging) + strcat(qla4xxx_version_str, "-debug"); + + qla4xxx_scsi_transport = +@@ -1727,13 +1700,13 @@ static int __init qla4xxx_module_init(void) + goto release_srb_cache; + } + ++ printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); + ret = pci_register_driver(&qla4xxx_pci_driver); + if (ret) + goto unregister_transport; + + printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); + return 0; +- + unregister_transport: + iscsi_unregister_transport(&qla4xxx_iscsi_transport); + release_srb_cache: +diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h +index ab984cb..1cbfcbb 100644 +--- a/drivers/scsi/qla4xxx/ql4_version.h ++++ b/drivers/scsi/qla4xxx/ql4_version.h +@@ -5,5 +5,6 @@ + * See LICENSE.qla4xxx for copyright and licensing details. + */ + +-#define QLA4XXX_DRIVER_VERSION "5.01.00-k8" ++#define QLA4XXX_DRIVER_VERSION "5.01.00-k8_sles11-01" ++ + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/quickcam_messenger.c-add-support-for-all-quickcam.patch b/src/patches/suse-2.6.27.31/patches.drivers/quickcam_messenger.c-add-support-for-all-quickcam.patch new file mode 100644 index 000000000..320264e8a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/quickcam_messenger.c-add-support-for-all-quickcam.patch @@ -0,0 +1,69 @@ +From: Brandon Philips +Subject: [PATCH] quickcam_messenger.c: add support for all quickcam + Messengers of the same family +References: bnc#441650 +Patch-Mainline: never, gspca_stv06xx.ko should be used for 2.6.30+ + +Add three devices that are supported by out of tree drivers to the +quickcam_messenger driver. Also, remove the sensor_id check since it seems to +just check the PID. + +The quickcam messenger plus (0x08F6) is supported by Christian's out of tree +driver[1] but two users have confirmed that the in tree quickcam_messenger +driver works for their devices if the IDs are added: + + https://bugzilla.novell.com/show_bug.cgi?id=441650#c3 + https://bugs.launchpad.net/ubuntu/+source/linux-source-2.6.15/+bug/22070/comments/33 + https://bugs.launchpad.net/ubuntu/+source/linux-source-2.6.15/+bug/22070/comments/34 + +[1] http://home.mag.cx/messenger/source/ + +Information on removal of the driver: + http://article.gmane.org/gmane.linux.drivers.video-input-infrastructure/8982/ + +Signed-off-by: Brandon Philips +Acked-by: Jaya Kumar + +--- + drivers/media/video/usbvideo/quickcam_messenger.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +Index: linux-2.6/drivers/media/video/usbvideo/quickcam_messenger.c +=================================================================== +--- linux-2.6.orig/drivers/media/video/usbvideo/quickcam_messenger.c ++++ linux-2.6/drivers/media/video/usbvideo/quickcam_messenger.c +@@ -56,9 +56,6 @@ static const int debug; + #define DRIVER_VERSION "v0.01" + #define DRIVER_DESC "Logitech Quickcam Messenger USB" + +-#define USB_LOGITECH_VENDOR_ID 0x046D +-#define USB_QCM_PRODUCT_ID 0x08F0 +- + #define MAX_CAMERAS 1 + + #define MAX_COLOUR 32768 +@@ -77,7 +74,10 @@ static int whiteness = MAX_WHITENESS; + static struct usbvideo *cams; + + static struct usb_device_id qcm_table [] = { +- { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) }, ++ { USB_DEVICE(0x046D, 0x08F0) }, /* QuickCam Messenger */ ++ { USB_DEVICE(0x046D, 0x08F5) }, /* QuickCam Communicate */ ++ { USB_DEVICE(0x046D, 0x08F6) }, /* QuickCam Messenger (new) */ ++ { USB_DEVICE(0x046D, 0x08DA) }, /* QuickCam Messenger (new) */ + { } + }; + MODULE_DEVICE_TABLE(usb, qcm_table); +@@ -998,11 +998,6 @@ good_videoep: + err("Couldn't read sensor values. Err %d\n",err); + return err; + } +- if (sensor_id != cpu_to_le16(0x08F0)) { +- err("Sensor ID %x != %x. Unsupported. Sorry\n", +- le16_to_cpu(sensor_id), (0x08F0)); +- return -ENODEV; +- } + + uvd = usbvideo_AllocateDevice(cams); + if (!uvd) + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/r8169-Tx-performance-tweak-helper b/src/patches/suse-2.6.27.31/patches.drivers/r8169-Tx-performance-tweak-helper new file mode 100644 index 000000000..e95150368 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/r8169-Tx-performance-tweak-helper @@ -0,0 +1,50 @@ +Commit-Id: 458a9f617adfb2fc5f38e7673339115c4ba3290f +From: Francois Romieu +Date: Sat, 2 Aug 2008 15:50:02 +0200 +Acked-by: Karsten Keil +Reference: bnc#448168 +Subject: [PATCH] r8169: Tx performance tweak helper + +Signed-off-by: Francois Romieu +Cc: Edward Hsu + +--- + drivers/net/r8169.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +--- a/drivers/net/r8169.c ++++ b/drivers/net/r8169.c +@@ -2078,12 +2078,20 @@ static void rtl_hw_start_8169(struct net + RTL_W16(IntrMask, tp->intr_event); + } + ++static void rtl_tx_performance_tweak(struct pci_dev *pdev, u8 force) ++{ ++ u8 ctl; ++ ++ pci_read_config_byte(pdev, 0x69, &ctl); ++ ctl = (ctl & ~0x70) | force; ++ pci_write_config_byte(pdev, 0x69, ctl); ++} ++ + static void rtl_hw_start_8168(struct net_device *dev) + { + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct pci_dev *pdev = tp->pci_dev; +- u8 ctl; + + RTL_W8(Cfg9346, Cfg9346_Unlock); + +@@ -2097,10 +2105,7 @@ static void rtl_hw_start_8168(struct net + + RTL_W16(CPlusCmd, tp->cp_cmd); + +- /* Tx performance tweak. */ +- pci_read_config_byte(pdev, 0x69, &ctl); +- ctl = (ctl & ~0x70) | 0x50; +- pci_write_config_byte(pdev, 0x69, ctl); ++ rtl_tx_performance_tweak(pdev, 0x50); + + RTL_W16(IntrMitigate, 0x5151); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/r8169-add-8168-8101-registers-description b/src/patches/suse-2.6.27.31/patches.drivers/r8169-add-8168-8101-registers-description new file mode 100644 index 000000000..7e5075545 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/r8169-add-8168-8101-registers-description @@ -0,0 +1,99 @@ +Commit-Id: f162a5d1b326d54b0be7e3100f69763d8a707721 +From: Francois Romieu +Date: Sun, 1 Jun 2008 22:37:49 +0200 +Acked-by: Karsten Keil +Reference: bnc#448168 +Subject: [PATCH] r8169: add 8168/8101 registers description + +Signed-off-by: Francois Romieu +Cc: Edward Hsu + +--- + drivers/net/r8169.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 43 insertions(+), 4 deletions(-) + +--- a/drivers/net/r8169.c ++++ b/drivers/net/r8169.c +@@ -196,9 +196,6 @@ enum rtl_registers { + Config5 = 0x56, + MultiIntr = 0x5c, + PHYAR = 0x60, +- TBICSR = 0x64, +- TBI_ANAR = 0x68, +- TBI_LPAR = 0x6a, + PHYstatus = 0x6c, + RxMaxSize = 0xda, + CPlusCmd = 0xe0, +@@ -212,6 +209,32 @@ enum rtl_registers { + FuncForceEvent = 0xfc, + }; + ++enum rtl8110_registers { ++ TBICSR = 0x64, ++ TBI_ANAR = 0x68, ++ TBI_LPAR = 0x6a, ++}; ++ ++enum rtl8168_8101_registers { ++ CSIDR = 0x64, ++ CSIAR = 0x68, ++#define CSIAR_FLAG 0x80000000 ++#define CSIAR_WRITE_CMD 0x80000000 ++#define CSIAR_BYTE_ENABLE 0x0f ++#define CSIAR_BYTE_ENABLE_SHIFT 12 ++#define CSIAR_ADDR_MASK 0x0fff ++ ++ EPHYAR = 0x80, ++#define EPHYAR_FLAG 0x80000000 ++#define EPHYAR_WRITE_CMD 0x80000000 ++#define EPHYAR_REG_MASK 0x1f ++#define EPHYAR_REG_SHIFT 16 ++#define EPHYAR_DATA_MASK 0xffff ++ DBG_REG = 0xd1, ++#define FIX_NAK_1 (1 << 4) ++#define FIX_NAK_2 (1 << 3) ++}; ++ + enum rtl_register_content { + /* InterruptStatusBits */ + SYSErr = 0x8000, +@@ -265,7 +288,13 @@ enum rtl_register_content { + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + + /* Config1 register p.24 */ ++ LEDS1 = (1 << 7), ++ LEDS0 = (1 << 6), + MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ ++ Speed_down = (1 << 4), ++ MEMMAP = (1 << 3), ++ IOMAP = (1 << 2), ++ VPD = (1 << 1), + PMEnable = (1 << 0), /* Power Management Enable */ + + /* Config2 register p. 25 */ +@@ -275,6 +304,7 @@ enum rtl_register_content { + /* Config3 register p.25 */ + MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ + LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ ++ Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ + + /* Config5 register p.27 */ + BWF = (1 << 6), /* Accept Broadcast wakeup frame */ +@@ -292,7 +322,16 @@ enum rtl_register_content { + TBINwComplete = 0x01000000, + + /* CPlusCmd p.31 */ +- PktCntrDisable = (1 << 7), // 8168 ++ EnableBist = (1 << 15), // 8168 8101 ++ Mac_dbgo_oe = (1 << 14), // 8168 8101 ++ Normal_mode = (1 << 13), // unused ++ Force_half_dup = (1 << 12), // 8168 8101 ++ Force_rxflow_en = (1 << 11), // 8168 8101 ++ Force_txflow_en = (1 << 10), // 8168 8101 ++ Cxpl_dbg_sel = (1 << 9), // 8168 8101 ++ ASF = (1 << 8), // 8168 8101 ++ PktCntrDisable = (1 << 7), // 8168 8101 ++ Mac_dbgo_sel = 0x001c, // 8168 + RxVlan = (1 << 6), + RxChkSum = (1 << 5), + PCIDAC = (1 << 4), diff --git a/src/patches/suse-2.6.27.31/patches.drivers/r8169-add-hw-start-helpers-for-the-8168-and-the-8101 b/src/patches/suse-2.6.27.31/patches.drivers/r8169-add-hw-start-helpers-for-the-8168-and-the-8101 new file mode 100644 index 000000000..3b8dfab7e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/r8169-add-hw-start-helpers-for-the-8168-and-the-8101 @@ -0,0 +1,137 @@ +Commit-Id: dacf815434a4d5f5b45687873df46927c64cfb19 +From: Francois Romieu +Date: Sat, 2 Aug 2008 20:44:13 +0200 +Acked-by: Karsten Keil +Reference: bnc#448168 +Subject: [PATCH] r8169: add hw start helpers for the 8168 and the 8101 + +This commit triggers three 'defined but not used' warnings but +I prefer avoiding to tie these helpers to a specific change in +the hw start sequences of the 8168 or of the 8101. + +Signed-off-by: Francois Romieu +Cc: Edward Hsu + +--- + drivers/net/r8169.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +--- a/drivers/net/r8169.c ++++ b/drivers/net/r8169.c +@@ -542,6 +542,11 @@ static int mdio_read(void __iomem *ioadd + return value; + } + ++static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value) ++{ ++ mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value); ++} ++ + static void rtl_mdio_write(struct net_device *dev, int phy_id, int location, + int val) + { +@@ -559,6 +564,72 @@ static int rtl_mdio_read(struct net_devi + return mdio_read(ioaddr, location); + } + ++static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value) ++{ ++ unsigned int i; ++ ++ RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | ++ (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); ++ ++ for (i = 0; i < 100; i++) { ++ if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG)) ++ break; ++ udelay(10); ++ } ++} ++ ++static u16 rtl_ephy_read(void __iomem *ioaddr, int reg_addr) ++{ ++ u16 value = 0xffff; ++ unsigned int i; ++ ++ RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); ++ ++ for (i = 0; i < 100; i++) { ++ if (RTL_R32(EPHYAR) & EPHYAR_FLAG) { ++ value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK; ++ break; ++ } ++ udelay(10); ++ } ++ ++ return value; ++} ++ ++static void rtl_csi_write(void __iomem *ioaddr, int addr, int value) ++{ ++ unsigned int i; ++ ++ RTL_W32(CSIDR, value); ++ RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | ++ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); ++ ++ for (i = 0; i < 100; i++) { ++ if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) ++ break; ++ udelay(10); ++ } ++} ++ ++static u32 rtl_csi_read(void __iomem *ioaddr, int addr) ++{ ++ u32 value = ~0x00; ++ unsigned int i; ++ ++ RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | ++ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); ++ ++ for (i = 0; i < 100; i++) { ++ if (RTL_R32(CSIAR) & CSIAR_FLAG) { ++ value = RTL_R32(CSIDR); ++ break; ++ } ++ udelay(10); ++ } ++ ++ return value; ++} ++ + static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) + { + RTL_W16(IntrMask, 0x0000); +@@ -2138,6 +2209,31 @@ static void rtl_tx_performance_tweak(str + } + } + ++static void rtl_csi_access_enable(void __iomem *ioaddr) ++{ ++ u32 csi; ++ ++ csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; ++ rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000); ++} ++ ++struct ephy_info { ++ unsigned int offset; ++ u16 mask; ++ u16 bits; ++}; ++ ++static void rtl_ephy_init(void __iomem *ioaddr, struct ephy_info *e, int len) ++{ ++ u16 w; ++ ++ while (len-- > 0) { ++ w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits; ++ rtl_ephy_write(ioaddr, e->offset, w); ++ e++; ++ } ++} ++ + static void rtl_hw_start_8168(struct net_device *dev) + { + struct rtl8169_private *tp = netdev_priv(dev); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/r8169-additional-8101-and-8102-support b/src/patches/suse-2.6.27.31/patches.drivers/r8169-additional-8101-and-8102-support new file mode 100644 index 000000000..89d6e45f9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/r8169-additional-8101-and-8102-support @@ -0,0 +1,199 @@ +Commit-Id: 2857ffb7b8913ef713533ac5783abd70a20529e4 +From: Francois Romieu +Date: Sat, 2 Aug 2008 21:08:49 +0200 +Acked-by: Karsten Keil +Reference: bnc#448168 +Subject: [PATCH] r8169: additional 8101 and 8102 support + +Signed-off-by: Ivan Vecera +Signed-off-by: Francois Romieu +Cc: Edward Hsu + +--- + drivers/net/r8169.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 122 insertions(+), 2 deletions(-) + +--- a/drivers/net/r8169.c ++++ b/drivers/net/r8169.c +@@ -95,6 +95,10 @@ enum mac_version { + RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB + RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd + RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe ++ RTL_GIGA_MAC_VER_07 = 0x07, // 8102e ++ RTL_GIGA_MAC_VER_08 = 0x08, // 8102e ++ RTL_GIGA_MAC_VER_09 = 0x09, // 8102e ++ RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e + RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb + RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be + RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb +@@ -121,6 +125,10 @@ static const struct { + _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd + _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe ++ _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E ++ _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E ++ _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E ++ _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E + _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E + _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 +@@ -853,8 +861,12 @@ static int rtl8169_set_speed_xmii(struct + } + } + +- /* The 8100e/8101e do Fast Ethernet only. */ +- if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || ++ /* The 8100e/8101e/8102e do Fast Ethernet only. */ ++ if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || ++ (tp->mac_version == RTL_GIGA_MAC_VER_08) || ++ (tp->mac_version == RTL_GIGA_MAC_VER_09) || ++ (tp->mac_version == RTL_GIGA_MAC_VER_10) || ++ (tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_14) || + (tp->mac_version == RTL_GIGA_MAC_VER_15) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { +@@ -1235,8 +1247,17 @@ static void rtl8169_get_mac_version(stru + { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, + + /* 8101 family. */ ++ { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 }, ++ { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 }, ++ { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 }, ++ { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 }, ++ { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 }, ++ { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 }, + { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, ++ { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 }, + { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, ++ { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 }, ++ { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 }, + { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, + /* FIXME: where did these entries come from ? -- FR */ + { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, +@@ -1398,6 +1419,22 @@ static void rtl8168cx_hw_phy_config(void + rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); + } + ++static void rtl8102e_hw_phy_config(void __iomem *ioaddr) ++{ ++ struct phy_reg phy_reg_init[] = { ++ { 0x1f, 0x0003 }, ++ { 0x08, 0x441d }, ++ { 0x01, 0x9100 }, ++ { 0x1f, 0x0000 } ++ }; ++ ++ mdio_write(ioaddr, 0x1f, 0x0000); ++ mdio_patch(ioaddr, 0x11, 1 << 12); ++ mdio_patch(ioaddr, 0x19, 1 << 13); ++ ++ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); ++} ++ + static void rtl_hw_phy_config(struct net_device *dev) + { + struct rtl8169_private *tp = netdev_priv(dev); +@@ -1415,6 +1452,11 @@ static void rtl_hw_phy_config(struct net + case RTL_GIGA_MAC_VER_04: + rtl8169sb_hw_phy_config(ioaddr); + break; ++ case RTL_GIGA_MAC_VER_07: ++ case RTL_GIGA_MAC_VER_08: ++ case RTL_GIGA_MAC_VER_09: ++ rtl8102e_hw_phy_config(ioaddr); ++ break; + case RTL_GIGA_MAC_VER_18: + rtl8168cp_hw_phy_config(ioaddr); + break; +@@ -2277,6 +2319,70 @@ static void rtl_hw_start_8168(struct net + RTL_W16(IntrMask, tp->intr_event); + } + ++#define R810X_CPCMD_QUIRK_MASK (\ ++ EnableBist | \ ++ Mac_dbgo_oe | \ ++ Force_half_dup | \ ++ Force_half_dup | \ ++ Force_txflow_en | \ ++ Cxpl_dbg_sel | \ ++ ASF | \ ++ PktCntrDisable | \ ++ PCIDAC | \ ++ PCIMulRW) ++ ++static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) ++{ ++ static struct ephy_info e_info_8102e_1[] = { ++ { 0x01, 0, 0x6e65 }, ++ { 0x02, 0, 0x091f }, ++ { 0x03, 0, 0xc2f9 }, ++ { 0x06, 0, 0xafb5 }, ++ { 0x07, 0, 0x0e00 }, ++ { 0x19, 0, 0xec80 }, ++ { 0x01, 0, 0x2e65 }, ++ { 0x01, 0, 0x6e65 } ++ }; ++ u8 cfg1; ++ ++ rtl_csi_access_enable(ioaddr); ++ ++ RTL_W8(DBG_REG, FIX_NAK_1); ++ ++ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); ++ ++ RTL_W8(Config1, ++ LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); ++ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); ++ ++ cfg1 = RTL_R8(Config1); ++ if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) ++ RTL_W8(Config1, cfg1 & ~LEDS0); ++ ++ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); ++ ++ rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); ++} ++ ++static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev) ++{ ++ rtl_csi_access_enable(ioaddr); ++ ++ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); ++ ++ RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable); ++ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); ++ ++ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); ++} ++ ++static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev) ++{ ++ rtl_hw_start_8102e_2(ioaddr, pdev); ++ ++ rtl_ephy_write(ioaddr, 0x03, 0xc2f9); ++} ++ + static void rtl_hw_start_8101(struct net_device *dev) + { + struct rtl8169_private *tp = netdev_priv(dev); +@@ -2293,6 +2399,20 @@ static void rtl_hw_start_8101(struct net + } + } + ++ switch (tp->mac_version) { ++ case RTL_GIGA_MAC_VER_07: ++ rtl_hw_start_8102e_1(ioaddr, pdev); ++ break; ++ ++ case RTL_GIGA_MAC_VER_08: ++ rtl_hw_start_8102e_3(ioaddr, pdev); ++ break; ++ ++ case RTL_GIGA_MAC_VER_09: ++ rtl_hw_start_8102e_2(ioaddr, pdev); ++ break; ++ } ++ + RTL_W8(Cfg9346, Cfg9346_Unlock); + + RTL_W8(EarlyTxThres, EarlyTxThld); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/r8169-allow-true-forced-mode-setting.patch b/src/patches/suse-2.6.27.31/patches.drivers/r8169-allow-true-forced-mode-setting.patch new file mode 100644 index 000000000..aad073648 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/r8169-allow-true-forced-mode-setting.patch @@ -0,0 +1,165 @@ +Date: Tue, 19 May 2009 22:46:48 +0200 +From: Francois Romieu +Subject: r8169: allow true forced mode setting +References: bnc#467518 + +Due to mostly historic reasons, including a lack of reliability +of the link handling (especially with the older 8169), the +current r8169 driver emulates forced mode setting by limiting +the advertised modes. + +With this change the driver allows real 10/100 forced mode +settings on the 8169 and 8101/8102. + +Original idea by Vincent Steenhoute. The RTL_GIGA_MAC_VER_03 +tweak was extracted from Realtek's r8169 v6.010.00 driver. + +Signed-off-by: Francois Romieu +Tested-by: Jean Delvare +Cc: Edward Hsu + +Tested-by: Vincent Steenhoute +Acked-by: Jean Delvare +--- + drivers/net/r8169.c | 115 +++++++++++++++++++++++++++------------------------- + 1 file changed, 61 insertions(+), 54 deletions(-) +--- a/drivers/net/r8169.c ++++ b/drivers/net/r8169.c +@@ -827,76 +827,83 @@ static int rtl8169_set_speed_xmii(struct + { + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; +- int auto_nego, giga_ctrl; +- +- auto_nego = mdio_read(ioaddr, MII_ADVERTISE); +- auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | +- ADVERTISE_100HALF | ADVERTISE_100FULL); +- giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); +- giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); ++ int giga_ctrl, bmcr; + + if (autoneg == AUTONEG_ENABLE) { ++ int auto_nego; ++ ++ auto_nego = mdio_read(ioaddr, MII_ADVERTISE); + auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_100FULL); +- giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; +- } else { +- if (speed == SPEED_10) +- auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; +- else if (speed == SPEED_100) +- auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; +- else if (speed == SPEED_1000) +- giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; ++ auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + +- if (duplex == DUPLEX_HALF) +- auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); +- +- if (duplex == DUPLEX_FULL) +- auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); +- +- /* This tweak comes straight from Realtek's driver. */ +- if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && +- ((tp->mac_version == RTL_GIGA_MAC_VER_13) || +- (tp->mac_version == RTL_GIGA_MAC_VER_16))) { +- auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; +- } +- } ++ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); ++ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + +- /* The 8100e/8101e/8102e do Fast Ethernet only. */ +- if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || +- (tp->mac_version == RTL_GIGA_MAC_VER_08) || +- (tp->mac_version == RTL_GIGA_MAC_VER_09) || +- (tp->mac_version == RTL_GIGA_MAC_VER_10) || +- (tp->mac_version == RTL_GIGA_MAC_VER_13) || +- (tp->mac_version == RTL_GIGA_MAC_VER_14) || +- (tp->mac_version == RTL_GIGA_MAC_VER_15) || +- (tp->mac_version == RTL_GIGA_MAC_VER_16)) { +- if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) && +- netif_msg_link(tp)) { ++ /* The 8100e/8101e/8102e do Fast Ethernet only. */ ++ if ((tp->mac_version != RTL_GIGA_MAC_VER_07) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_08) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_09) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_10) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_13) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_14) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_15) && ++ (tp->mac_version != RTL_GIGA_MAC_VER_16)) { ++ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; ++ } else if (netif_msg_link(tp)) { + printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n", + dev->name); + } +- giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); +- } + +- auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; ++ bmcr = BMCR_ANENABLE | BMCR_ANRESTART; ++ ++ if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || ++ (tp->mac_version == RTL_GIGA_MAC_VER_12) || ++ (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { ++ /* ++ * Wake up the PHY. ++ * Vendor specific (0x1f) and reserved (0x0e) MII ++ * registers. ++ */ ++ mdio_write(ioaddr, 0x1f, 0x0000); ++ mdio_write(ioaddr, 0x0e, 0x0000); ++ } ++ ++ tp->phy_auto_nego_reg = auto_nego; ++ ++ mdio_write(ioaddr, MII_ADVERTISE, auto_nego); ++ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); ++ } else { ++ giga_ctrl = 0; ++ ++ if (speed == SPEED_10) ++ bmcr = 0; ++ else if (speed == SPEED_100) ++ bmcr = BMCR_SPEED100; ++ else ++ return -EINVAL; ++ ++ if (duplex == DUPLEX_FULL) ++ bmcr |= BMCR_FULLDPLX; + +- if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || +- (tp->mac_version == RTL_GIGA_MAC_VER_12) || +- (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { +- /* +- * Wake up the PHY. +- * Vendor specific (0x1f) and reserved (0x0e) MII registers. +- */ + mdio_write(ioaddr, 0x1f, 0x0000); +- mdio_write(ioaddr, 0x0e, 0x0000); + } + +- tp->phy_auto_nego_reg = auto_nego; + tp->phy_1000_ctrl_reg = giga_ctrl; + +- mdio_write(ioaddr, MII_ADVERTISE, auto_nego); +- mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); +- mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); ++ mdio_write(ioaddr, MII_BMCR, bmcr); ++ ++ if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || ++ (tp->mac_version == RTL_GIGA_MAC_VER_03)) { ++ if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) { ++ mdio_write(ioaddr, 0x17, 0x2138); ++ mdio_write(ioaddr, 0x0e, 0x0260); ++ } else { ++ mdio_write(ioaddr, 0x17, 0x2108); ++ mdio_write(ioaddr, 0x0e, 0x0000); ++ } ++ } ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/r8169-use-pci_find_capability-for-the-PCI-E-features b/src/patches/suse-2.6.27.31/patches.drivers/r8169-use-pci_find_capability-for-the-PCI-E-features new file mode 100644 index 000000000..5236600fd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/r8169-use-pci_find_capability-for-the-PCI-E-features @@ -0,0 +1,92 @@ +Commit-Id: 9c14ceafa5ca7f57225a43fb0785c56ddc7f1823 +From: Francois Romieu +Date: Sat, 5 Jul 2008 00:21:15 +0200 +Acked-by: Karsten Keil +Reference: bnc#448168 +Subject: [PATCH] r8169: use pci_find_capability for the PCI-E features + +Signed-off-by: Francois Romieu +Cc: Edward Hsu + +--- + drivers/net/r8169.c | 32 ++++++++++++++++++++++++-------- + 1 file changed, 24 insertions(+), 8 deletions(-) + +--- a/drivers/net/r8169.c ++++ b/drivers/net/r8169.c +@@ -61,6 +61,7 @@ static const int multicast_filter_limit + /* MAC address length */ + #define MAC_ADDR_LEN 6 + ++#define MAX_READ_REQUEST_SHIFT 12 + #define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ + #define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ + #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +@@ -427,6 +428,7 @@ struct rtl8169_private { + void (*hw_start)(struct net_device *); + unsigned int (*phy_reset_pending)(void __iomem *); + unsigned int (*link_ok)(void __iomem *); ++ int pcie_cap; + struct delayed_work task; + unsigned features; + +@@ -1686,6 +1688,10 @@ rtl8169_init_one(struct pci_dev *pdev, c + goto err_out_free_res_4; + } + ++ tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); ++ if (!tp->pcie_cap && netif_msg_probe(tp)) ++ dev_info(&pdev->dev, "no PCI Express capability\n"); ++ + RTL_W16(IntrMask, 0x0000); + + /* Soft reset the chip. */ +@@ -2078,13 +2084,19 @@ static void rtl_hw_start_8169(struct net + RTL_W16(IntrMask, tp->intr_event); + } + +-static void rtl_tx_performance_tweak(struct pci_dev *pdev, u8 force) ++static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force) + { +- u8 ctl; ++ struct net_device *dev = pci_get_drvdata(pdev); ++ struct rtl8169_private *tp = netdev_priv(dev); ++ int cap = tp->pcie_cap; ++ ++ if (cap) { ++ u16 ctl; + +- pci_read_config_byte(pdev, 0x69, &ctl); +- ctl = (ctl & ~0x70) | force; +- pci_write_config_byte(pdev, 0x69, ctl); ++ pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); ++ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force; ++ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); ++ } + } + + static void rtl_hw_start_8168(struct net_device *dev) +@@ -2105,7 +2117,7 @@ static void rtl_hw_start_8168(struct net + + RTL_W16(CPlusCmd, tp->cp_cmd); + +- rtl_tx_performance_tweak(pdev, 0x50); ++ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); + + RTL_W16(IntrMitigate, 0x5151); + +@@ -2138,8 +2150,12 @@ static void rtl_hw_start_8101(struct net + + if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || + (tp->mac_version == RTL_GIGA_MAC_VER_16)) { +- pci_write_config_word(pdev, 0x68, 0x00); +- pci_write_config_word(pdev, 0x69, 0x08); ++ int cap = tp->pcie_cap; ++ ++ if (cap) { ++ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ++ PCI_EXP_DEVCTL_NOSNOOP_EN); ++ } + } + + RTL_W8(Cfg9346, Cfg9346_Unlock); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/sgi-ioc4-request-submodules b/src/patches/suse-2.6.27.31/patches.drivers/sgi-ioc4-request-submodules new file mode 100644 index 000000000..89b11211b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/sgi-ioc4-request-submodules @@ -0,0 +1,59 @@ +From: Michael Reed +Subject: ioc4 request module +Patch-mainline: ? +References: bnc#429215 + +It modifies ioc4.c to call request_module() for each of the two modules +which support the hardware. + +The patch uses a workqueue to prevent a deadlock. It seems to do the right +thing on my system, but I don't have a way to install test it. If this works +and you find it acceptable, I'll try to get it pushed upstream next week. + +Mike + +Acked-by: Raymund Will + +--- linux-2.6.27-rc6-7.2/drivers/misc/ioc4.c 2008-07-13 16:51:29.000000000 -0500 ++++ b/drivers/misc/ioc4.c 2008-10-03 15:58:40.225723102 -0500 +@@ -269,6 +269,17 @@ ioc4_variant(struct ioc4_driver_data *id + return IOC4_VARIANT_PCI_RT; + } + ++static void ++ioc4_load_modules(struct work_struct *work) ++{ ++ /* arg just has to be freed */ ++ ++ request_module("sgiioc4"); ++ request_module("ioc4_serial"); ++ ++ kfree(work); ++} ++ + /* Adds a new instance of an IOC4 card */ + static int + ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +@@ -378,6 +389,22 @@ ioc4_probe(struct pci_dev *pdev, const s + } + mutex_unlock(&ioc4_mutex); + ++ if (idd->idd_variant != IOC4_VARIANT_PCI_RT) { ++ struct work_struct *work; ++ work = kzalloc(sizeof(struct work_struct), GFP_KERNEL); ++ if (!work) { ++ printk(KERN_WARNING ++ "%s: IOC4 unable to allocate memory for " ++ "load of sub-modules.\n", ++ __FUNCTION__); ++ } ++ else { ++ printk(KERN_INFO "IOC4 loading ioc4 submodule\n"); ++ INIT_WORK(work, ioc4_load_modules); ++ schedule_work(work); ++ } ++ } ++ + return 0; + + out_misc_region: diff --git a/src/patches/suse-2.6.27.31/patches.drivers/sgi-xp-no-uv b/src/patches/suse-2.6.27.31/patches.drivers/sgi-xp-no-uv new file mode 100644 index 000000000..512fd24eb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/sgi-xp-no-uv @@ -0,0 +1,78 @@ +From: Dean Nelson +Subject: SGI SN: Eliminate dependency of the XP/XPC drivers on GRU. +Patch-mainline: no +References: bnc#442442 + +For the time being build for ia64-sn2 alone when CONFIG_IA64_GENERIC is +specified. + +Signed-off-by: Dean Nelson +Acked-by: Raymund Will + +--- + + drivers/misc/sgi-xp/Makefile | 4 ++-- + drivers/misc/sgi-xp/xp.h | 4 ++++ + drivers/misc/sgi-xp/xpc_main.c | 4 ++-- + 3 files changed, 8 insertions(+), 4 deletions(-) + +Index: linux/drivers/misc/sgi-xp/Makefile +=================================================================== +--- linux.orig/drivers/misc/sgi-xp/Makefile 2008-10-23 10:59:42.000000000 -0500 ++++ linux/drivers/misc/sgi-xp/Makefile 2008-10-23 10:59:44.000000000 -0500 +@@ -5,14 +5,14 @@ + obj-$(CONFIG_SGI_XP) += xp.o + xp-y := xp_main.o + xp-$(CONFIG_IA64_SGI_SN2) += xp_sn2.o xp_nofault.o +-xp-$(CONFIG_IA64_GENERIC) += xp_sn2.o xp_nofault.o xp_uv.o ++xp-$(CONFIG_IA64_GENERIC) += xp_sn2.o xp_nofault.o + xp-$(CONFIG_IA64_SGI_UV) += xp_uv.o + xp-$(CONFIG_X86_64) += xp_uv.o + + obj-$(CONFIG_SGI_XP) += xpc.o + xpc-y := xpc_main.o xpc_channel.o xpc_partition.o + xpc-$(CONFIG_IA64_SGI_SN2) += xpc_sn2.o +-xpc-$(CONFIG_IA64_GENERIC) += xpc_sn2.o xpc_uv.o ++xpc-$(CONFIG_IA64_GENERIC) += xpc_sn2.o + xpc-$(CONFIG_IA64_SGI_UV) += xpc_uv.o + xpc-$(CONFIG_X86_64) += xpc_uv.o + +Index: linux/drivers/misc/sgi-xp/xp.h +=================================================================== +--- linux.orig/drivers/misc/sgi-xp/xp.h 2008-10-23 10:59:42.000000000 -0500 ++++ linux/drivers/misc/sgi-xp/xp.h 2008-10-23 10:59:44.000000000 -0500 +@@ -19,7 +19,11 @@ + #include + #include /* defines is_shub1() and is_shub2() */ + #define is_shub() ia64_platform_is("sn2") ++#ifdef CONFIG_IA64_SGI_UV + #define is_uv() ia64_platform_is("uv") ++#else ++#define is_uv() 0 ++#endif + #endif + #ifdef CONFIG_X86_64 + #include +Index: linux/drivers/misc/sgi-xp/xpc_main.c +=================================================================== +--- linux.orig/drivers/misc/sgi-xp/xpc_main.c 2008-10-23 10:59:42.000000000 -0500 ++++ linux/drivers/misc/sgi-xp/xpc_main.c 2008-10-23 10:59:44.000000000 -0500 +@@ -1104,7 +1104,7 @@ xpc_do_exit(enum xp_retval reason) + + if (is_shub()) + xpc_exit_sn2(); +- else ++ else if (is_uv()) + xpc_exit_uv(); + } + +@@ -1363,7 +1363,7 @@ out_2: + out_1: + if (is_shub()) + xpc_exit_sn2(); +- else ++ else if (is_uv()) + xpc_exit_uv(); + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-agnx-wireless-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-agnx-wireless-driver.patch new file mode 100644 index 000000000..f49924dcb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-agnx-wireless-driver.patch @@ -0,0 +1,5316 @@ +From e983cf526bfd8ea56b72490f7449c65ee4dd0a16 Mon Sep 17 00:00:00 2001 +From: Li YanBo +Date: Mon, 27 Oct 2008 20:32:57 -0700 +Subject: Staging: add agnx wireless driver +Patch-mainline: 2.6.28 + +From: Li YanBo + +This driver is for the Airgo AGNX00 wireless chip. + +From: Li YanBo +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/agnx/Kconfig | 5 + drivers/staging/agnx/Makefile | 8 + drivers/staging/agnx/TODO | 22 + drivers/staging/agnx/agnx.h | 156 ++++++ + drivers/staging/agnx/debug.h | 418 ++++++++++++++++++ + drivers/staging/agnx/pci.c | 650 ++++++++++++++++++++++++++++ + drivers/staging/agnx/phy.c | 958 ++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/agnx/phy.h | 409 +++++++++++++++++ + drivers/staging/agnx/rf.c | 894 +++++++++++++++++++++++++++++++++++++++ + drivers/staging/agnx/sta.c | 219 +++++++++ + drivers/staging/agnx/sta.h | 222 +++++++++ + drivers/staging/agnx/table.c | 168 +++++++ + drivers/staging/agnx/table.h | 10 + drivers/staging/agnx/xmit.c | 819 +++++++++++++++++++++++++++++++++++ + drivers/staging/agnx/xmit.h | 250 ++++++++++ + 17 files changed, 5211 insertions(+) + create mode 100644 drivers/staging/agnx/Kconfig + create mode 100644 drivers/staging/agnx/Makefile + create mode 100644 drivers/staging/agnx/TODO + create mode 100644 drivers/staging/agnx/agnx.h + create mode 100644 drivers/staging/agnx/debug.h + create mode 100644 drivers/staging/agnx/pci.c + create mode 100644 drivers/staging/agnx/phy.c + create mode 100644 drivers/staging/agnx/phy.h + create mode 100644 drivers/staging/agnx/rf.c + create mode 100644 drivers/staging/agnx/sta.c + create mode 100644 drivers/staging/agnx/sta.h + create mode 100644 drivers/staging/agnx/table.c + create mode 100644 drivers/staging/agnx/table.h + create mode 100644 drivers/staging/agnx/xmit.c + create mode 100644 drivers/staging/agnx/xmit.h + +--- /dev/null ++++ b/drivers/staging/agnx/agnx.h +@@ -0,0 +1,156 @@ ++#ifndef AGNX_H_ ++#define AGNX_H_ ++ ++#include "xmit.h" ++ ++#define PFX KBUILD_MODNAME ": " ++ ++static inline u32 agnx_read32(void __iomem *mem_region, u32 offset) ++{ ++ return ioread32(mem_region + offset); ++} ++ ++static inline void agnx_write32(void __iomem *mem_region, u32 offset, u32 val) ++{ ++ iowrite32(val, mem_region + offset); ++} ++ ++/* static const struct ieee80211_rate agnx_rates_80211b[] = { */ ++/* { .rate = 10, */ ++/* .val = 0xa, */ ++/* .flags = IEEE80211_RATE_CCK }, */ ++/* { .rate = 20, */ ++/* .val = 0x14, */ ++/* .hw_value = -0x14, */ ++/* .flags = IEEE80211_RATE_CCK_2 }, */ ++/* { .rate = 55, */ ++/* .val = 0x37, */ ++/* .val2 = -0x37, */ ++/* .flags = IEEE80211_RATE_CCK_2 }, */ ++/* { .rate = 110, */ ++/* .val = 0x6e, */ ++/* .val2 = -0x6e, */ ++/* .flags = IEEE80211_RATE_CCK_2 } */ ++/* }; */ ++ ++ ++static const struct ieee80211_rate agnx_rates_80211g[] = { ++/* { .bitrate = 10, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */ ++/* { .bitrate = 20, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */ ++/* { .bitrate = 55, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */ ++/* { .bitrate = 110, .hw_value = 4, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */ ++ { .bitrate = 10, .hw_value = 1, }, ++ { .bitrate = 20, .hw_value = 2, }, ++ { .bitrate = 55, .hw_value = 3, }, ++ { .bitrate = 110, .hw_value = 4,}, ++ ++ { .bitrate = 60, .hw_value = 0xB, }, ++ { .bitrate = 90, .hw_value = 0xF, }, ++ { .bitrate = 120, .hw_value = 0xA }, ++ { .bitrate = 180, .hw_value = 0xE, }, ++// { .bitrate = 240, .hw_value = 0xd, }, ++ { .bitrate = 360, .hw_value = 0xD, }, ++ { .bitrate = 480, .hw_value = 0x8, }, ++ { .bitrate = 540, .hw_value = 0xC, }, ++}; ++ ++static const struct ieee80211_channel agnx_channels[] = { ++ { .center_freq = 2412, .hw_value = 1, }, ++ { .center_freq = 2417, .hw_value = 2, }, ++ { .center_freq = 2422, .hw_value = 3, }, ++ { .center_freq = 2427, .hw_value = 4, }, ++ { .center_freq = 2432, .hw_value = 5, }, ++ { .center_freq = 2437, .hw_value = 6, }, ++ { .center_freq = 2442, .hw_value = 7, }, ++ { .center_freq = 2447, .hw_value = 8, }, ++ { .center_freq = 2452, .hw_value = 9, }, ++ { .center_freq = 2457, .hw_value = 10, }, ++ { .center_freq = 2462, .hw_value = 11, }, ++ { .center_freq = 2467, .hw_value = 12, }, ++ { .center_freq = 2472, .hw_value = 13, }, ++ { .center_freq = 2484, .hw_value = 14, }, ++}; ++ ++#define NUM_DRIVE_MODES 2 ++/* Agnx operate mode */ ++enum { ++ AGNX_MODE_80211A, ++ AGNX_MODE_80211A_OOB, ++ AGNX_MODE_80211A_MIMO, ++ AGNX_MODE_80211B_SHORT, ++ AGNX_MODE_80211B_LONG, ++ AGNX_MODE_80211G, ++ AGNX_MODE_80211G_OOB, ++ AGNX_MODE_80211G_MIMO, ++}; ++ ++enum { ++ AGNX_UNINIT, ++ AGNX_START, ++ AGNX_STOP, ++}; ++ ++struct agnx_priv { ++ struct pci_dev *pdev; ++ struct ieee80211_hw *hw; ++ ++ spinlock_t lock; ++ struct mutex mutex; ++ unsigned int init_status; ++ ++ void __iomem *ctl; /* pointer to base ram address */ ++ void __iomem *data; /* pointer to mem region #2 */ ++ ++ struct agnx_ring rx; ++ struct agnx_ring txm; ++ struct agnx_ring txd; ++ ++ /* Need volatile? */ ++ u32 irq_status; ++ ++ struct delayed_work periodic_work; /* Periodic tasks like recalibrate*/ ++ struct ieee80211_low_level_stats stats; ++ ++// unsigned int phymode; ++ int mode; ++ int channel; ++ u8 bssid[ETH_ALEN]; ++ u8 ssid[32]; ++ size_t ssid_len; ++ ++ u8 mac_addr[ETH_ALEN]; ++ u8 revid; ++ ++ struct ieee80211_supported_band band; ++}; ++ ++ ++#define AGNX_CHAINS_MAX 6 ++#define AGNX_PERIODIC_DELAY 60000 /* unit: ms */ ++#define LOCAL_STAID 0 /* the station entry for the card itself */ ++#define BSSID_STAID 1 /* the station entry for the bsssid AP */ ++#define spi_delay() udelay(40) ++#define eeprom_delay() udelay(40) ++#define routing_table_delay() udelay(50) ++ ++/* PDU pool MEM region #2 */ ++#define AGNX_PDUPOOL 0x40000 /* PDU pool */ ++#define AGNX_PDUPOOL_SIZE 0x8000 /* PDU pool size*/ ++#define AGNX_PDU_TX_WQ 0x41000 /* PDU list TX workqueue */ ++#define AGNX_PDU_FREE 0x41800 /* Free Pool */ ++#define PDU_SIZE 0x80 /* Free Pool node size */ ++#define PDU_FREE_CNT 0xd0 /* Free pool node count */ ++ ++ ++/* RF stuffs */ ++extern void rf_chips_init(struct agnx_priv *priv); ++extern void spi_rc_write(void __iomem *mem_region, u32 chip_ids, u32 sw); ++extern void calibrate_oscillator(struct agnx_priv *priv); ++extern void do_calibration(struct agnx_priv *priv); ++extern void antenna_calibrate(struct agnx_priv *priv); ++extern void __antenna_calibrate(struct agnx_priv *priv); ++extern void print_offsets(struct agnx_priv *priv); ++extern int agnx_set_channel(struct agnx_priv *priv, unsigned int channel); ++ ++ ++#endif /* AGNX_H_ */ +--- /dev/null ++++ b/drivers/staging/agnx/debug.h +@@ -0,0 +1,418 @@ ++#ifndef AGNX_DEBUG_H_ ++#define AGNX_DEBUG_H_ ++ ++#include "agnx.h" ++#include "phy.h" ++#include "sta.h" ++#include "xmit.h" ++ ++#define AGNX_TRACE printk(KERN_ERR PFX "function:%s line:%d\n", __func__, __LINE__) ++ ++#define PRINTK_LE16(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.4x\n", le16_to_cpu(var)) ++#define PRINTK_LE32(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.8x\n", le32_to_cpu(var)) ++#define PRINTK_U8(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.2x\n", var) ++#define PRINTK_BE16(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.4x\n", be16_to_cpu(var)) ++#define PRINTK_BE32(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.8x\n", be32_to_cpu(var)) ++#define PRINTK_BITS(prefix, field) printk(KERN_DEBUG PFX #prefix ": " #field ": 0x%x\n", (reg & field) >> field##_SHIFT) ++ ++static inline void agnx_bug(char *reason) ++{ ++ printk(KERN_ERR PFX "%s\n", reason); ++ BUG(); ++} ++ ++static inline void agnx_print_desc(struct agnx_desc *desc) ++{ ++ u32 reg = be32_to_cpu(desc->frag); ++ ++ PRINTK_BITS(DESC, PACKET_LEN); ++ ++ if (reg & FIRST_FRAG) { ++ PRINTK_BITS(DESC, FIRST_PACKET_MASK); ++ PRINTK_BITS(DESC, FIRST_RESERV2); ++ PRINTK_BITS(DESC, FIRST_TKIP_ERROR); ++ PRINTK_BITS(DESC, FIRST_TKIP_PACKET); ++ PRINTK_BITS(DESC, FIRST_RESERV1); ++ PRINTK_BITS(DESC, FIRST_FRAG_LEN); ++ } else { ++ PRINTK_BITS(DESC, SUB_RESERV2); ++ PRINTK_BITS(DESC, SUB_TKIP_ERROR); ++ PRINTK_BITS(DESC, SUB_TKIP_PACKET); ++ PRINTK_BITS(DESC, SUB_RESERV1); ++ PRINTK_BITS(DESC, SUB_FRAG_LEN); ++ } ++ ++ PRINTK_BITS(DESC, FIRST_FRAG); ++ PRINTK_BITS(DESC, LAST_FRAG); ++ PRINTK_BITS(DESC, OWNER); ++} ++ ++ ++static inline void dump_ieee80211b_phy_hdr(__be32 _11b0, __be32 _11b1) ++{ ++ ++} ++ ++static inline void agnx_print_hdr(struct agnx_hdr *hdr) ++{ ++ u32 reg; ++ int i; ++ ++ reg = be32_to_cpu(hdr->reg0); ++ PRINTK_BITS(HDR, RTS); ++ PRINTK_BITS(HDR, MULTICAST); ++ PRINTK_BITS(HDR, ACK); ++ PRINTK_BITS(HDR, TM); ++ PRINTK_BITS(HDR, RELAY); ++ PRINTK_BITS(HDR, REVISED_FCS); ++ PRINTK_BITS(HDR, NEXT_BUFFER_ADDR); ++ ++ reg = be32_to_cpu(hdr->reg1); ++ PRINTK_BITS(HDR, MAC_HDR_LEN); ++ PRINTK_BITS(HDR, DURATION_OVERIDE); ++ PRINTK_BITS(HDR, PHY_HDR_OVERIDE); ++ PRINTK_BITS(HDR, CRC_FAIL); ++ PRINTK_BITS(HDR, SEQUENCE_NUMBER); ++ PRINTK_BITS(HDR, BUFF_HEAD_ADDR); ++ ++ reg = be32_to_cpu(hdr->reg2); ++ PRINTK_BITS(HDR, PDU_COUNT); ++ PRINTK_BITS(HDR, WEP_KEY); ++ PRINTK_BITS(HDR, USES_WEP_KEY); ++ PRINTK_BITS(HDR, KEEP_ALIVE); ++ PRINTK_BITS(HDR, BUFF_TAIL_ADDR); ++ ++ reg = be32_to_cpu(hdr->reg3); ++ PRINTK_BITS(HDR, CTS_11G); ++ PRINTK_BITS(HDR, RTS_11G); ++ PRINTK_BITS(HDR, FRAG_SIZE); ++ PRINTK_BITS(HDR, PAYLOAD_LEN); ++ PRINTK_BITS(HDR, FRAG_NUM); ++ ++ reg = be32_to_cpu(hdr->reg4); ++ PRINTK_BITS(HDR, RELAY_STAID); ++ PRINTK_BITS(HDR, STATION_ID); ++ PRINTK_BITS(HDR, WORKQUEUE_ID); ++ ++ reg = be32_to_cpu(hdr->reg5); ++ /* printf the route flag */ ++ PRINTK_BITS(HDR, ROUTE_HOST); ++ PRINTK_BITS(HDR, ROUTE_CARD_CPU); ++ PRINTK_BITS(HDR, ROUTE_ENCRYPTION); ++ PRINTK_BITS(HDR, ROUTE_TX); ++ PRINTK_BITS(HDR, ROUTE_RX1); ++ PRINTK_BITS(HDR, ROUTE_RX2); ++ PRINTK_BITS(HDR, ROUTE_COMPRESSION); ++ ++ PRINTK_BE32(HDR, hdr->_11g0); ++ PRINTK_BE32(HDR, hdr->_11g1); ++ PRINTK_BE32(HDR, hdr->_11b0); ++ PRINTK_BE32(HDR, hdr->_11b1); ++ ++ dump_ieee80211b_phy_hdr(hdr->_11b0, hdr->_11b1); ++ ++ /* Fixme */ ++ for (i = 0; i < ARRAY_SIZE(hdr->mac_hdr); i++) { ++ if (i == 0) ++ printk(KERN_DEBUG PFX "IEEE80211 HDR: "); ++ printk("%.2x ", hdr->mac_hdr[i]); ++ if (i + 1 == ARRAY_SIZE(hdr->mac_hdr)) ++ printk("\n"); ++ } ++ ++ PRINTK_BE16(HDR, hdr->rts_duration); ++ PRINTK_BE16(HDR, hdr->last_duration); ++ PRINTK_BE16(HDR, hdr->sec_last_duration); ++ PRINTK_BE16(HDR, hdr->other_duration); ++ PRINTK_BE16(HDR, hdr->tx_other_duration); ++ PRINTK_BE16(HDR, hdr->last_11g_len); ++ PRINTK_BE16(HDR, hdr->other_11g_len); ++ PRINTK_BE16(HDR, hdr->last_11b_len); ++ PRINTK_BE16(HDR, hdr->other_11b_len); ++ ++ /* FIXME */ ++ reg = be16_to_cpu(hdr->reg6); ++ PRINTK_BITS(HDR, MBF); ++ PRINTK_BITS(HDR, RSVD4); ++ ++ PRINTK_BE16(HDR, hdr->rx_frag_stat); ++ ++ PRINTK_BE32(HDR, hdr->time_stamp); ++ PRINTK_BE32(HDR, hdr->phy_stats_hi); ++ PRINTK_BE32(HDR, hdr->phy_stats_lo); ++ PRINTK_BE32(HDR, hdr->mic_key0); ++ PRINTK_BE32(HDR, hdr->mic_key1); ++} /* agnx_print_hdr */ ++ ++ ++static inline void agnx_print_rx_hdr(struct agnx_hdr *hdr) ++{ ++ agnx_print_hdr(hdr); ++ ++ PRINTK_BE16(HDR, hdr->rx.rx_packet_duration); ++ PRINTK_BE16(HDR, hdr->rx.replay_cnt); ++ ++ PRINTK_U8(HDR, hdr->rx_channel); ++} ++ ++static inline void agnx_print_tx_hdr(struct agnx_hdr *hdr) ++{ ++ agnx_print_hdr(hdr); ++ ++ PRINTK_U8(HDR, hdr->tx.long_retry_limit); ++ PRINTK_U8(HDR, hdr->tx.short_retry_limit); ++ PRINTK_U8(HDR, hdr->tx.long_retry_cnt); ++ PRINTK_U8(HDR, hdr->tx.short_retry_cnt); ++ ++ PRINTK_U8(HDR, hdr->rx_channel); ++} ++ ++static inline void ++agnx_print_sta_power(struct agnx_priv *priv, unsigned int sta_idx) ++{ ++ struct agnx_sta_power power; ++ u32 reg; ++ ++ get_sta_power(priv, &power, sta_idx); ++ ++ reg = le32_to_cpu(power.reg); ++ PRINTK_BITS(STA_POWER, SIGNAL); ++ PRINTK_BITS(STA_POWER, RATE); ++ PRINTK_BITS(STA_POWER, TIFS); ++ PRINTK_BITS(STA_POWER, EDCF); ++ PRINTK_BITS(STA_POWER, CHANNEL_BOND); ++ PRINTK_BITS(STA_POWER, PHY_MODE); ++ PRINTK_BITS(STA_POWER, POWER_LEVEL); ++ PRINTK_BITS(STA_POWER, NUM_TRANSMITTERS); ++} ++ ++static inline void ++agnx_print_sta_tx_wq(struct agnx_priv *priv, unsigned int sta_idx, unsigned int wq_idx) ++{ ++ struct agnx_sta_tx_wq tx_wq; ++ u32 reg; ++ ++ get_sta_tx_wq(priv, &tx_wq, sta_idx, wq_idx); ++ ++ reg = le32_to_cpu(tx_wq.reg0); ++ PRINTK_BITS(STA_TX_WQ, TAIL_POINTER); ++ PRINTK_BITS(STA_TX_WQ, HEAD_POINTER_LOW); ++ ++ reg = le32_to_cpu(tx_wq.reg3); ++ PRINTK_BITS(STA_TX_WQ, HEAD_POINTER_HIGH); ++ PRINTK_BITS(STA_TX_WQ, ACK_POINTER_LOW); ++ ++ reg = le32_to_cpu(tx_wq.reg1); ++ PRINTK_BITS(STA_TX_WQ, ACK_POINTER_HIGH); ++ PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_TAIL_PACK_CNT); ++ PRINTK_BITS(STA_TX_WQ, ACK_TIMOUT_TAIL_PACK_CNT); ++ ++ reg = le32_to_cpu(tx_wq.reg2); ++ PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_WIN_LIM_BYTE_CNT); ++ PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_WIN_LIM_FRAG_CNT); ++ PRINTK_BITS(STA_TX_WQ, WORK_QUEUE_ACK_TYPE); ++ PRINTK_BITS(STA_TX_WQ, WORK_QUEUE_VALID); ++} ++ ++static inline void agnx_print_sta_traffic(struct agnx_sta_traffic *traffic) ++{ ++ u32 reg; ++ ++ reg = le32_to_cpu(traffic->reg0); ++ PRINTK_BITS(STA_TRAFFIC, ACK_TIMOUT_CNT); ++ PRINTK_BITS(STA_TRAFFIC, TRAFFIC_ACK_TYPE); ++ PRINTK_BITS(STA_TRAFFIC, NEW_PACKET); ++ PRINTK_BITS(STA_TRAFFIC, TRAFFIC_VALID); ++ PRINTK_BITS(STA_TRAFFIC, RX_HDR_DESC_POINTER); ++ ++ reg = le32_to_cpu(traffic->reg1); ++ PRINTK_BITS(STA_TRAFFIC, RX_PACKET_TIMESTAMP); ++ PRINTK_BITS(STA_TRAFFIC, TRAFFIC_RESERVED); ++ PRINTK_BITS(STA_TRAFFIC, SV); ++ PRINTK_BITS(STA_TRAFFIC, RX_SEQUENCE_NUM); ++ ++ PRINTK_LE32(STA_TRAFFIC, traffic->tx_replay_cnt_low); ++ ++ PRINTK_LE16(STA_TRAFFIC, traffic->tx_replay_cnt_high); ++ PRINTK_LE16(STA_TRAFFIC, traffic->rx_replay_cnt_high); ++ ++ PRINTK_LE32(STA_TRAFFIC, traffic->rx_replay_cnt_low); ++} ++ ++static inline void agnx_print_sta(struct agnx_priv *priv, unsigned int sta_idx) ++{ ++ struct agnx_sta station; ++ struct agnx_sta *sta = &station; ++ u32 reg; ++ unsigned int i; ++ ++ get_sta(priv, sta, sta_idx); ++ ++ for (i = 0; i < 4; i++) ++ PRINTK_LE32(STA, sta->tx_session_keys[i]); ++ for (i = 0; i < 4; i++) ++ PRINTK_LE32(STA, sta->rx_session_keys[i]); ++ ++ reg = le32_to_cpu(sta->reg); ++ PRINTK_BITS(STA, ID_1); ++ PRINTK_BITS(STA, ID_0); ++ PRINTK_BITS(STA, ENABLE_CONCATENATION); ++ PRINTK_BITS(STA, ENABLE_DECOMPRESSION); ++ PRINTK_BITS(STA, STA_RESERVED); ++ PRINTK_BITS(STA, EAP); ++ PRINTK_BITS(STA, ED_NULL); ++ PRINTK_BITS(STA, ENCRYPTION_POLICY); ++ PRINTK_BITS(STA, DEFINED_KEY_ID); ++ PRINTK_BITS(STA, FIXED_KEY); ++ PRINTK_BITS(STA, KEY_VALID); ++ PRINTK_BITS(STA, STATION_VALID); ++ ++ PRINTK_LE32(STA, sta->tx_aes_blks_unicast); ++ PRINTK_LE32(STA, sta->rx_aes_blks_unicast); ++ ++ PRINTK_LE16(STA, sta->aes_format_err_unicast_cnt); ++ PRINTK_LE16(STA, sta->aes_replay_unicast); ++ ++ PRINTK_LE16(STA, sta->aes_decrypt_err_unicast); ++ PRINTK_LE16(STA, sta->aes_decrypt_err_default); ++ ++ PRINTK_LE16(STA, sta->single_retry_packets); ++ PRINTK_LE16(STA, sta->failed_tx_packets); ++ ++ PRINTK_LE16(STA, sta->muti_retry_packets); ++ PRINTK_LE16(STA, sta->ack_timeouts); ++ ++ PRINTK_LE16(STA, sta->frag_tx_cnt); ++ PRINTK_LE16(STA, sta->rts_brq_sent); ++ ++ PRINTK_LE16(STA, sta->tx_packets); ++ PRINTK_LE16(STA, sta->cts_back_timeout); ++ ++ PRINTK_LE32(STA, sta->phy_stats_high); ++ PRINTK_LE32(STA, sta->phy_stats_low); ++ ++// for (i = 0; i < 8; i++) ++ agnx_print_sta_traffic(sta->traffic + 0); ++ ++ PRINTK_LE16(STA, sta->traffic_class0_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class1_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class2_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class3_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class4_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class5_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class6_frag_success); ++ PRINTK_LE16(STA, sta->traffic_class7_frag_success); ++ ++ PRINTK_LE16(STA, sta->num_frag_non_prime_rates); ++ PRINTK_LE16(STA, sta->ack_timeout_non_prime_rates); ++} ++ ++ ++static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag) ++{ ++ u16 fctl; ++ int hdrlen; ++ DECLARE_MAC_BUF(mac); ++ ++ fctl = le16_to_cpu(hdr->frame_control); ++ switch (fctl & IEEE80211_FCTL_FTYPE) { ++ case IEEE80211_FTYPE_DATA: ++ printk(PFX "%s DATA ", tag); ++ break; ++ case IEEE80211_FTYPE_CTL: ++ printk(PFX "%s CTL ", tag); ++ break; ++ case IEEE80211_FTYPE_MGMT: ++ printk(PFX "%s MGMT ", tag); ++ switch(fctl & IEEE80211_FCTL_STYPE) { ++ case IEEE80211_STYPE_ASSOC_REQ: ++ printk("SubType: ASSOC_REQ "); ++ break; ++ case IEEE80211_STYPE_ASSOC_RESP: ++ printk("SubType: ASSOC_RESP "); ++ break; ++ case IEEE80211_STYPE_REASSOC_REQ: ++ printk("SubType: REASSOC_REQ "); ++ break; ++ case IEEE80211_STYPE_REASSOC_RESP: ++ printk("SubType: REASSOC_RESP "); ++ break; ++ case IEEE80211_STYPE_PROBE_REQ: ++ printk("SubType: PROBE_REQ "); ++ break; ++ case IEEE80211_STYPE_PROBE_RESP: ++ printk("SubType: PROBE_RESP "); ++ break; ++ case IEEE80211_STYPE_BEACON: ++ printk("SubType: BEACON "); ++ break; ++ case IEEE80211_STYPE_ATIM: ++ printk("SubType: ATIM "); ++ break; ++ case IEEE80211_STYPE_DISASSOC: ++ printk("SubType: DISASSOC "); ++ break; ++ case IEEE80211_STYPE_AUTH: ++ printk("SubType: AUTH "); ++ break; ++ case IEEE80211_STYPE_DEAUTH: ++ printk("SubType: DEAUTH "); ++ break; ++ case IEEE80211_STYPE_ACTION: ++ printk("SubType: ACTION "); ++ break; ++ default: ++ printk("SubType: Unknow\n"); ++ } ++ break; ++ default: ++ printk(PFX "%s Packet type: Unknow\n", tag); ++ } ++ ++ hdrlen = ieee80211_hdrlen(fctl); ++ ++ if (hdrlen >= 4) ++ printk("FC=0x%04x DUR=0x%04x", ++ fctl, le16_to_cpu(hdr->duration_id)); ++ if (hdrlen >= 10) ++ printk(" A1=%s", print_mac(mac, hdr->addr1)); ++ if (hdrlen >= 16) ++ printk(" A2=%s", print_mac(mac, hdr->addr2)); ++ if (hdrlen >= 24) ++ printk(" A3=%s", print_mac(mac, hdr->addr3)); ++ if (hdrlen >= 30) ++ printk(" A4=%s", print_mac(mac, hdr->addr4)); ++ printk("\n"); ++} ++ ++static inline void dump_txm_registers(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int i; ++ for (i = 0; i <=0x1e8; i += 4) { ++ printk(KERN_DEBUG PFX "TXM: %x---> 0x%.8x\n", i, ioread32(ctl + i)); ++ } ++} ++static inline void dump_rxm_registers(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int i; ++ for (i = 0; i <=0x108; i += 4) ++ printk(KERN_DEBUG PFX "RXM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2000 + i)); ++} ++static inline void dump_bm_registers(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int i; ++ for (i = 0; i <=0x90; i += 4) ++ printk(KERN_DEBUG PFX "BM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2c00 + i)); ++} ++static inline void dump_cir_registers(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int i; ++ for (i = 0; i <=0xb8; i += 4) ++ printk(KERN_DEBUG PFX "CIR: %x---> 0x%.8x\n", i, ioread32(ctl + 0x3000 + i)); ++} ++ ++#endif /* AGNX_DEBUG_H_ */ +--- /dev/null ++++ b/drivers/staging/agnx/Kconfig +@@ -0,0 +1,5 @@ ++config AGNX ++ tristate "Wireless Airgo AGNX support" ++ depends on WLAN_80211 && MAC80211 ++ ---help--- ++ This is an experimental driver for Airgo AGNX00 wireless chip. +--- /dev/null ++++ b/drivers/staging/agnx/Makefile +@@ -0,0 +1,8 @@ ++obj-$(CONFIG_AGNX) += agnx.o ++ ++agnx-objs := rf.o \ ++ pci.o \ ++ xmit.o \ ++ table.o \ ++ sta.o \ ++ phy.o +--- /dev/null ++++ b/drivers/staging/agnx/pci.c +@@ -0,0 +1,650 @@ ++/** ++ * Airgo MIMO wireless driver ++ * ++ * Copyright (c) 2007 Li YanBo ++ ++ * Thanks for Jeff Williams do reverse engineer ++ * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin ++ ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "agnx.h" ++#include "debug.h" ++#include "xmit.h" ++#include "phy.h" ++ ++MODULE_AUTHOR("Li YanBo "); ++MODULE_DESCRIPTION("Airgo MIMO PCI wireless driver"); ++MODULE_LICENSE("GPL"); ++ ++static struct pci_device_id agnx_pci_id_tbl[] __devinitdata = { ++ { PCI_DEVICE(0x17cb, 0x0001) }, /* Beklin F5d8010, Netgear WGM511 etc */ ++ { PCI_DEVICE(0x17cb, 0x0002) }, /* Netgear Wpnt511 */ ++ { 0 } ++}; ++ ++MODULE_DEVICE_TABLE(pci, agnx_pci_id_tbl); ++ ++ ++static inline void agnx_interrupt_ack(struct agnx_priv *priv, u32 *reason) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ if ( *reason & AGNX_STAT_RX ) { ++ /* Mark complete RX */ ++ reg = ioread32(ctl + AGNX_CIR_RXCTL); ++ reg |= 0x4; ++ iowrite32(reg, ctl + AGNX_CIR_RXCTL); ++ /* disable Rx interrupt */ ++ } ++ if ( *reason & AGNX_STAT_TX ) { ++ reg = ioread32(ctl + AGNX_CIR_TXDCTL); ++ if (reg & 0x4) { ++ iowrite32(reg, ctl + AGNX_CIR_TXDCTL); ++ *reason |= AGNX_STAT_TXD; ++ } ++ reg = ioread32(ctl + AGNX_CIR_TXMCTL); ++ if (reg & 0x4) { ++ iowrite32(reg, ctl + AGNX_CIR_TXMCTL); ++ *reason |= AGNX_STAT_TXM; ++ } ++ } ++ if ( *reason & AGNX_STAT_X ) { ++/* reg = ioread32(ctl + AGNX_INT_STAT); */ ++/* iowrite32(reg, ctl + AGNX_INT_STAT); */ ++/* /\* FIXME reinit interrupt mask *\/ */ ++/* reg = 0xc390bf9 & ~IRQ_TX_BEACON; */ ++/* reg &= ~IRQ_TX_DISABLE; */ ++/* iowrite32(reg, ctl + AGNX_INT_MASK); */ ++/* iowrite32(0x800, ctl + AGNX_CIR_BLKCTL); */ ++ } ++} /* agnx_interrupt_ack */ ++ ++static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id) ++{ ++ struct ieee80211_hw *dev = dev_id; ++ struct agnx_priv *priv = dev->priv; ++ void __iomem *ctl = priv->ctl; ++ irqreturn_t ret = IRQ_NONE; ++ u32 irq_reason; ++ ++ spin_lock(&priv->lock); ++ ++// printk(KERN_ERR PFX "Get a interrupt %s\n", __func__); ++ ++ if (priv->init_status != AGNX_START) ++ goto out; ++ ++ /* FiXME Here has no lock, Is this will lead to race? */ ++ irq_reason = ioread32(ctl + AGNX_CIR_BLKCTL); ++ if (!(irq_reason & 0x7)) ++ goto out; ++ ++ ret = IRQ_HANDLED; ++ priv->irq_status = ioread32(ctl + AGNX_INT_STAT); ++ ++// printk(PFX "Interrupt reason is 0x%x\n", irq_reason); ++ /* Make sure the txm and txd flags don't conflict with other unknown ++ interrupt flag, maybe is not necessary */ ++ irq_reason &= 0xF; ++ ++ disable_rx_interrupt(priv); ++ /* TODO Make sure the card finished initialized */ ++ agnx_interrupt_ack(priv, &irq_reason); ++ ++ if ( irq_reason & AGNX_STAT_RX ) ++ handle_rx_irq(priv); ++ if ( irq_reason & AGNX_STAT_TXD ) ++ handle_txd_irq(priv); ++ if ( irq_reason & AGNX_STAT_TXM ) ++ handle_txm_irq(priv); ++ if ( irq_reason & AGNX_STAT_X ) ++ handle_other_irq(priv); ++ ++ enable_rx_interrupt(priv); ++out: ++ spin_unlock(&priv->lock); ++ return ret; ++} /* agnx_interrupt_handler */ ++ ++ ++/* FIXME */ ++static int agnx_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ++{ ++ AGNX_TRACE; ++ return _agnx_tx(dev->priv, skb); ++} /* agnx_tx */ ++ ++ ++static int agnx_get_mac_address(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ /* Attention! directly read the MAC or other date from EEPROM will ++ lead to cardbus(WGM511) lock up when write to PM PLL register */ ++ reg = agnx_read32(ctl, 0x3544); ++ udelay(40); ++ reg = agnx_read32(ctl, 0x354c); ++ udelay(50); ++ /* Get the mac address */ ++ reg = agnx_read32(ctl, 0x3544); ++ udelay(40); ++ ++ /* HACK */ ++ reg = cpu_to_le32(reg); ++ priv->mac_addr[0] = ((u8 *)®)[2]; ++ priv->mac_addr[1] = ((u8 *)®)[3]; ++ reg = agnx_read32(ctl, 0x3548); ++ udelay(50); ++ *((u32 *)(priv->mac_addr + 2)) = cpu_to_le32(reg); ++ ++ if (!is_valid_ether_addr(priv->mac_addr)) { ++ DECLARE_MAC_BUF(mbuf); ++ printk(KERN_WARNING PFX "read mac %s\n", print_mac(mbuf, priv->mac_addr)); ++ printk(KERN_WARNING PFX "Invalid hwaddr! Using random hwaddr\n"); ++ random_ether_addr(priv->mac_addr); ++ } ++ ++ return 0; ++} /* agnx_get_mac_address */ ++ ++static int agnx_alloc_rings(struct agnx_priv *priv) ++{ ++ unsigned int len; ++ AGNX_TRACE; ++ ++ /* Allocate RX/TXM/TXD rings info */ ++ priv->rx.size = AGNX_RX_RING_SIZE; ++ priv->txm.size = AGNX_TXM_RING_SIZE; ++ priv->txd.size = AGNX_TXD_RING_SIZE; ++ ++ len = priv->rx.size + priv->txm.size + priv->txd.size; ++ ++// priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL); ++ priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_ATOMIC); ++ if (!priv->rx.info) ++ return -ENOMEM; ++ priv->txm.info = priv->rx.info + priv->rx.size; ++ priv->txd.info = priv->txm.info + priv->txm.size; ++ ++ /* Allocate RX/TXM/TXD descriptors */ ++ priv->rx.desc = pci_alloc_consistent(priv->pdev, sizeof(struct agnx_desc) * len, ++ &priv->rx.dma); ++ if (!priv->rx.desc) { ++ kfree(priv->rx.info); ++ return -ENOMEM; ++ } ++ ++ priv->txm.desc = priv->rx.desc + priv->rx.size; ++ priv->txm.dma = priv->rx.dma + sizeof(struct agnx_desc) * priv->rx.size; ++ priv->txd.desc = priv->txm.desc + priv->txm.size; ++ priv->txd.dma = priv->txm.dma + sizeof(struct agnx_desc) * priv->txm.size; ++ ++ return 0; ++} /* agnx_alloc_rings */ ++ ++static void rings_free(struct agnx_priv *priv) ++{ ++ unsigned int len = priv->rx.size + priv->txm.size + priv->txd.size; ++ unsigned long flags; ++ AGNX_TRACE; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ kfree(priv->rx.info); ++ pci_free_consistent(priv->pdev, sizeof(struct agnx_desc) * len, ++ priv->rx.desc, priv->rx.dma); ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++ ++static void agnx_periodic_work_handler(struct work_struct *work) ++{ ++ struct agnx_priv *priv = container_of(work, struct agnx_priv, ++ periodic_work.work); ++// unsigned long flags; ++ unsigned long delay; ++ ++ /* fixme: using mutex?? */ ++// spin_lock_irqsave(&priv->lock, flags); ++ ++ /* TODO Recalibrate*/ ++// calibrate_oscillator(priv); ++// antenna_calibrate(priv); ++// agnx_send_packet(priv, 997); ++ /* FIXME */ ++/* if (debug == 3) */ ++/* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */ ++/* else */ ++ delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); ++// delay = round_jiffies(HZ * 15); ++ ++ queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); ++ ++// spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++ ++static int agnx_start(struct ieee80211_hw *dev) ++{ ++ struct agnx_priv *priv = dev->priv; ++ unsigned long delay; ++ int err = 0; ++ AGNX_TRACE; ++ ++ err = agnx_alloc_rings(priv); ++ if (err) { ++ printk(KERN_ERR PFX "Can't alloc RX/TXM/TXD rings\n"); ++ goto out; ++ } ++ err = request_irq(priv->pdev->irq, &agnx_interrupt_handler, ++ IRQF_SHARED, "agnx_pci", dev); ++ if (err) { ++ printk(KERN_ERR PFX "Failed to register IRQ handler\n"); ++ rings_free(priv); ++ goto out; ++ } ++ ++// mdelay(500); ++ ++ might_sleep(); ++ agnx_hw_init(priv); ++ ++// mdelay(500); ++ might_sleep(); ++ ++ priv->init_status = AGNX_START; ++/* INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); */ ++/* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */ ++/* queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */ ++out: ++ return err; ++} /* agnx_start */ ++ ++static void agnx_stop(struct ieee80211_hw *dev) ++{ ++ struct agnx_priv *priv = dev->priv; ++ AGNX_TRACE; ++ ++ priv->init_status = AGNX_STOP; ++ /* make sure hardware will not generate irq */ ++ agnx_hw_reset(priv); ++ free_irq(priv->pdev->irq, dev); ++ flush_workqueue(priv->hw->workqueue); ++// cancel_delayed_work_sync(&priv->periodic_work); ++ unfill_rings(priv); ++ rings_free(priv); ++} ++ ++static int agnx_config(struct ieee80211_hw *dev, ++ struct ieee80211_conf *conf) ++{ ++ struct agnx_priv *priv = dev->priv; ++ int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); ++ AGNX_TRACE; ++ ++ spin_lock(&priv->lock); ++ /* FIXME need priv lock? */ ++ if (channel != priv->channel) { ++ priv->channel = channel; ++ agnx_set_channel(priv, priv->channel); ++ } ++ ++ spin_unlock(&priv->lock); ++ return 0; ++} ++ ++static int agnx_config_interface(struct ieee80211_hw *dev, ++ struct ieee80211_vif *vif, ++ struct ieee80211_if_conf *conf) ++{ ++ struct agnx_priv *priv = dev->priv; ++ void __iomem *ctl = priv->ctl; ++ AGNX_TRACE; ++ ++ spin_lock(&priv->lock); ++ ++ if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { ++// u32 reghi, reglo; ++ agnx_set_bssid(priv, conf->bssid); ++ memcpy(priv->bssid, conf->bssid, ETH_ALEN); ++ hash_write(priv, conf->bssid, BSSID_STAID); ++ sta_init(priv, BSSID_STAID); ++ /* FIXME needed? */ ++ sta_power_init(priv, BSSID_STAID); ++ agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1); ++ } ++ if (conf->ssid_len != priv->ssid_len || ++ memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { ++ agnx_set_ssid(priv, conf->ssid, conf->ssid_len); ++ priv->ssid_len = conf->ssid_len; ++ memcpy(priv->ssid, conf->ssid, conf->ssid_len); ++ } ++ spin_unlock(&priv->lock); ++ return 0; ++} /* agnx_config_interface */ ++ ++ ++static void agnx_configure_filter(struct ieee80211_hw *dev, ++ unsigned int changed_flags, ++ unsigned int *total_flags, ++ int mc_count, struct dev_mc_list *mclist) ++{ ++ unsigned int new_flags = 0; ++ ++ *total_flags = new_flags; ++ /* TODO */ ++} ++ ++static int agnx_add_interface(struct ieee80211_hw *dev, ++ struct ieee80211_if_init_conf *conf) ++{ ++ struct agnx_priv *priv = dev->priv; ++ AGNX_TRACE; ++ ++ spin_lock(&priv->lock); ++ /* FIXME */ ++ if (priv->mode != NL80211_IFTYPE_MONITOR) ++ return -EOPNOTSUPP; ++ ++ switch (conf->type) { ++ case NL80211_IFTYPE_STATION: ++ priv->mode = conf->type; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ spin_unlock(&priv->lock); ++ ++ return 0; ++} ++ ++static void agnx_remove_interface(struct ieee80211_hw *dev, ++ struct ieee80211_if_init_conf *conf) ++{ ++ struct agnx_priv *priv = dev->priv; ++ AGNX_TRACE; ++ ++ /* TODO */ ++ priv->mode = NL80211_IFTYPE_MONITOR; ++} ++ ++static int agnx_get_stats(struct ieee80211_hw *dev, ++ struct ieee80211_low_level_stats *stats) ++{ ++ struct agnx_priv *priv = dev->priv; ++ AGNX_TRACE; ++ spin_lock(&priv->lock); ++ /* TODO !! */ ++ memcpy(stats, &priv->stats, sizeof(*stats)); ++ spin_unlock(&priv->lock); ++ ++ return 0; ++} ++ ++static u64 agnx_get_tsft(struct ieee80211_hw *dev) ++{ ++ void __iomem *ctl = ((struct agnx_priv *)dev->priv)->ctl; ++ u32 tsftl; ++ u64 tsft; ++ AGNX_TRACE; ++ ++ /* FIXME */ ++ tsftl = ioread32(ctl + AGNX_TXM_TIMESTAMPLO); ++ tsft = ioread32(ctl + AGNX_TXM_TIMESTAMPHI); ++ tsft <<= 32; ++ tsft |= tsftl; ++ ++ return tsft; ++} ++ ++static int agnx_get_tx_stats(struct ieee80211_hw *dev, ++ struct ieee80211_tx_queue_stats *stats) ++{ ++ struct agnx_priv *priv = dev->priv; ++ AGNX_TRACE; ++ ++ /* FIXME now we just using txd queue, but should using txm queue too */ ++ stats[0].len = (priv->txd.idx - priv->txd.idx_sent) / 2; ++ stats[0].limit = priv->txd.size - 2; ++ stats[0].count = priv->txd.idx / 2; ++ ++ return 0; ++} ++ ++static struct ieee80211_ops agnx_ops = { ++ .tx = agnx_tx, ++ .start = agnx_start, ++ .stop = agnx_stop, ++ .add_interface = agnx_add_interface, ++ .remove_interface = agnx_remove_interface, ++ .config = agnx_config, ++ .config_interface = agnx_config_interface, ++ .configure_filter = agnx_configure_filter, ++ .get_stats = agnx_get_stats, ++ .get_tx_stats = agnx_get_tx_stats, ++ .get_tsf = agnx_get_tsft ++}; ++ ++static void __devexit agnx_pci_remove(struct pci_dev *pdev) ++{ ++ struct ieee80211_hw *dev = pci_get_drvdata(pdev); ++ struct agnx_priv *priv = dev->priv; ++ AGNX_TRACE; ++ ++ if (!dev) ++ return; ++ ieee80211_unregister_hw(dev); ++ pci_iounmap(pdev, priv->ctl); ++ pci_iounmap(pdev, priv->data); ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++ ++ ieee80211_free_hw(dev); ++} ++ ++static int __devinit agnx_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ struct ieee80211_hw *dev; ++ struct agnx_priv *priv; ++ u32 mem_addr0, mem_len0; ++ u32 mem_addr1, mem_len1; ++ int err; ++ DECLARE_MAC_BUF(mac); ++ ++ err = pci_enable_device(pdev); ++ if (err) { ++ printk(KERN_ERR PFX "Can't enable new PCI device\n"); ++ return err; ++ } ++ ++ /* get pci resource */ ++ mem_addr0 = pci_resource_start(pdev, 0); ++ mem_len0 = pci_resource_len(pdev, 0); ++ mem_addr1 = pci_resource_start(pdev, 1); ++ mem_len1 = pci_resource_len(pdev, 1); ++ printk(KERN_DEBUG PFX "Memaddr0 is %x, length is %x\n", mem_addr0, mem_len0); ++ printk(KERN_DEBUG PFX "Memaddr1 is %x, length is %x\n", mem_addr1, mem_len1); ++ ++ err = pci_request_regions(pdev, "agnx-pci"); ++ if (err) { ++ printk(KERN_ERR PFX "Can't obtain PCI resource\n"); ++ return err; ++ } ++ ++ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || ++ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { ++ printk(KERN_ERR PFX "No suitable DMA available\n"); ++ goto err_free_reg; ++ } ++ ++ pci_set_master(pdev); ++ printk(KERN_DEBUG PFX "pdev->irq is %d\n", pdev->irq); ++ ++ dev = ieee80211_alloc_hw(sizeof(*priv), &agnx_ops); ++ if (!dev) { ++ printk(KERN_ERR PFX "ieee80211 alloc failed\n"); ++ err = -ENOMEM; ++ goto err_free_reg; ++ } ++ /* init priv */ ++ priv = dev->priv; ++ memset(priv, 0, sizeof(*priv)); ++ priv->mode = NL80211_IFTYPE_MONITOR; ++ priv->pdev = pdev; ++ priv->hw = dev; ++ spin_lock_init(&priv->lock); ++ priv->init_status = AGNX_UNINIT; ++ ++ /* Map mem #1 and #2 */ ++ priv->ctl = pci_iomap(pdev, 0, mem_len0); ++// printk(KERN_DEBUG PFX"MEM1 mapped address is 0x%p\n", priv->ctl); ++ if (!priv->ctl) { ++ printk(KERN_ERR PFX "Can't map device memory\n"); ++ goto err_free_dev; ++ } ++ priv->data = pci_iomap(pdev, 1, mem_len1); ++ printk(KERN_DEBUG PFX "MEM2 mapped address is 0x%p\n", priv->data); ++ if (!priv->data) { ++ printk(KERN_ERR PFX "Can't map device memory\n"); ++ goto err_iounmap2; ++ } ++ ++ pci_read_config_byte(pdev, PCI_REVISION_ID, &priv->revid); ++ ++ priv->band.channels = (struct ieee80211_channel *)agnx_channels; ++ priv->band.n_channels = ARRAY_SIZE(agnx_channels); ++ priv->band.bitrates = (struct ieee80211_rate *)agnx_rates_80211g; ++ priv->band.n_bitrates = ARRAY_SIZE(agnx_rates_80211g); ++ ++ /* Init ieee802.11 dev */ ++ SET_IEEE80211_DEV(dev, &pdev->dev); ++ pci_set_drvdata(pdev, dev); ++ dev->extra_tx_headroom = sizeof(struct agnx_hdr); ++ ++ /* FIXME It only include FCS in promious mode but not manage mode */ ++/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS; */ ++ dev->channel_change_time = 5000; ++ dev->max_signal = 100; ++ /* FIXME */ ++ dev->queues = 1; ++ ++ agnx_get_mac_address(priv); ++ ++ SET_IEEE80211_PERM_ADDR(dev, priv->mac_addr); ++ ++/* /\* FIXME *\/ */ ++/* for (i = 1; i < NUM_DRIVE_MODES; i++) { */ ++/* err = ieee80211_register_hwmode(dev, &priv->modes[i]); */ ++/* if (err) { */ ++/* printk(KERN_ERR PFX "Can't register hwmode\n"); */ ++/* goto err_iounmap; */ ++/* } */ ++/* } */ ++ ++ priv->channel = 1; ++ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; ++ ++ err = ieee80211_register_hw(dev); ++ if (err) { ++ printk(KERN_ERR PFX "Can't register hardware\n"); ++ goto err_iounmap; ++ } ++ ++ agnx_hw_reset(priv); ++ ++ ++ printk(PFX "%s: hwaddr %s, Rev 0x%02x\n", wiphy_name(dev->wiphy), ++ print_mac(mac, dev->wiphy->perm_addr), priv->revid); ++ return 0; ++ ++ err_iounmap: ++ pci_iounmap(pdev, priv->data); ++ ++ err_iounmap2: ++ pci_iounmap(pdev, priv->ctl); ++ ++ err_free_dev: ++ pci_set_drvdata(pdev, NULL); ++ ieee80211_free_hw(dev); ++ ++ err_free_reg: ++ pci_release_regions(pdev); ++ ++ pci_disable_device(pdev); ++ return err; ++} /* agnx_pci_probe*/ ++ ++#ifdef CONFIG_PM ++ ++static int agnx_pci_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct ieee80211_hw *dev = pci_get_drvdata(pdev); ++ AGNX_TRACE; ++ ++ ieee80211_stop_queues(dev); ++ agnx_stop(dev); ++ ++ pci_save_state(pdev); ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ return 0; ++} ++ ++static int agnx_pci_resume(struct pci_dev *pdev) ++{ ++ struct ieee80211_hw *dev = pci_get_drvdata(pdev); ++ AGNX_TRACE; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ ++ agnx_start(dev); ++ ieee80211_wake_queues(dev); ++ ++ return 0; ++} ++ ++#else ++ ++#define agnx_pci_suspend NULL ++#define agnx_pci_resume NULL ++ ++#endif /* CONFIG_PM */ ++ ++ ++static struct pci_driver agnx_pci_driver = { ++ .name = "agnx-pci", ++ .id_table = agnx_pci_id_tbl, ++ .probe = agnx_pci_probe, ++ .remove = __devexit_p(agnx_pci_remove), ++ .suspend = agnx_pci_suspend, ++ .resume = agnx_pci_resume, ++}; ++ ++static int __init agnx_pci_init(void) ++{ ++ AGNX_TRACE; ++ return pci_register_driver(&agnx_pci_driver); ++} ++ ++static void __exit agnx_pci_exit(void) ++{ ++ AGNX_TRACE; ++ pci_unregister_driver(&agnx_pci_driver); ++} ++ ++ ++module_init(agnx_pci_init); ++module_exit(agnx_pci_exit); +--- /dev/null ++++ b/drivers/staging/agnx/phy.c +@@ -0,0 +1,958 @@ ++/** ++ * Airgo MIMO wireless driver ++ * ++ * Copyright (c) 2007 Li YanBo ++ ++ * Thanks for Jeff Williams do reverse engineer ++ * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin ++ ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "agnx.h" ++#include "debug.h" ++#include "phy.h" ++#include "table.h" ++#include "sta.h" ++#include "xmit.h" ++ ++u8 read_from_eeprom(struct agnx_priv *priv, u16 address) ++{ ++ void __iomem *ctl = priv->ctl; ++ struct agnx_eeprom cmd; ++ u32 reg; ++ ++ memset(&cmd, 0, sizeof(cmd)); ++ cmd.cmd = EEPROM_CMD_READ << AGNX_EEPROM_COMMAND_SHIFT; ++ cmd.address = address; ++ /* Verify that the Status bit is clear */ ++ /* Read Command and Address are written to the Serial Interface */ ++ iowrite32(*(__le32 *)&cmd, ctl + AGNX_CIR_SERIALITF); ++ /* Wait for the Status bit to clear again */ ++ eeprom_delay(); ++ /* Read from Data */ ++ reg = ioread32(ctl + AGNX_CIR_SERIALITF); ++ ++ cmd = *(struct agnx_eeprom *)® ++ ++ return cmd.data; ++} ++ ++static int card_full_reset(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ reg = agnx_read32(ctl, AGNX_CIR_BLKCTL); ++ agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x80); ++ reg = agnx_read32(ctl, AGNX_CIR_BLKCTL); ++ return 0; ++} ++ ++inline void enable_power_saving(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg &= ~0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++} ++ ++inline void disable_power_saving(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++} ++ ++ ++void disable_receiver(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ AGNX_TRACE; ++ ++ /* FIXME Disable the receiver */ ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0); ++ /* Set gain control reset */ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); ++ /* Reset gain control reset */ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0); ++} ++ ++ ++/* Fixme this shoule be disable RX, above is enable RX */ ++void enable_receiver(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ AGNX_TRACE; ++ ++ /* Set adaptive gain control discovery mode */ ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); ++ /* Set gain control reset */ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); ++ /* Clear gain control reset */ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0); ++} ++ ++static void mac_address_set(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u8 *mac_addr = priv->mac_addr; ++ u32 reg; ++ ++ /* FIXME */ ++ reg = (mac_addr[0] << 24) | (mac_addr[1] << 16) | mac_addr[2] << 8 | mac_addr[3]; ++ iowrite32(reg, ctl + AGNX_RXM_MACHI); ++ reg = (mac_addr[4] << 8) | mac_addr[5]; ++ iowrite32(reg, ctl + AGNX_RXM_MACLO); ++} ++ ++static void receiver_bssid_set(struct agnx_priv *priv, u8 *bssid) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ disable_receiver(priv); ++ /* FIXME */ ++ reg = bssid[0] << 24 | (bssid[1] << 16) | (bssid[2] << 8) | bssid[3]; ++ iowrite32(reg, ctl + AGNX_RXM_BSSIDHI); ++ reg = (bssid[4] << 8) | bssid[5]; ++ iowrite32(reg, ctl + AGNX_RXM_BSSIDLO); ++ ++ /* Enable the receiver */ ++ enable_receiver(priv); ++ ++ /* Clear the TSF */ ++/* agnx_write32(ctl, AGNX_TXM_TSFLO, 0x0); */ ++/* agnx_write32(ctl, AGNX_TXM_TSFHI, 0x0); */ ++ /* Clear the TBTT */ ++ agnx_write32(ctl, AGNX_TXM_TBTTLO, 0x0); ++ agnx_write32(ctl, AGNX_TXM_TBTTHI, 0x0); ++ disable_receiver(priv); ++} /* receiver_bssid_set */ ++ ++static void band_management_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ void __iomem *data = priv->data; ++ u32 reg; ++ int i; ++ AGNX_TRACE; ++ ++ agnx_write32(ctl, AGNX_BM_TXWADDR, AGNX_PDU_TX_WQ); ++ agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0); ++ memset_io(data + AGNX_PDUPOOL, 0x0, AGNX_PDUPOOL_SIZE); ++ agnx_write32(ctl, AGNX_BM_BMCTL, 0x200); ++ ++ agnx_write32(ctl, AGNX_BM_CIPDUWCNT, 0x40); ++ agnx_write32(ctl, AGNX_BM_SPPDUWCNT, 0x2); ++ agnx_write32(ctl, AGNX_BM_RFPPDUWCNT, 0x0); ++ agnx_write32(ctl, AGNX_BM_RHPPDUWCNT, 0x22); ++ ++ /* FIXME Initialize the Free Pool Linked List */ ++ /* 1. Write the Address of the Next Node ((0x41800 + node*size)/size) ++ to the first word of each node. */ ++ for (i = 0; i < PDU_FREE_CNT; i++) { ++ iowrite32((AGNX_PDU_FREE + (i+1)*PDU_SIZE)/PDU_SIZE, ++ data + AGNX_PDU_FREE + (PDU_SIZE * i)); ++ /* The last node should be set to 0x0 */ ++ if ((i + 1) == PDU_FREE_CNT) ++ memset_io(data + AGNX_PDU_FREE + (PDU_SIZE * i), ++ 0x0, PDU_SIZE); ++ } ++ ++ /* Head is First Pool address (0x41800) / size (0x80) */ ++ agnx_write32(ctl, AGNX_BM_FPLHP, AGNX_PDU_FREE/PDU_SIZE); ++ /* Tail is Last Pool Address (0x47f80) / size (0x80) */ ++ agnx_write32(ctl, AGNX_BM_FPLTP, 0x47f80/PDU_SIZE); ++ /* Count is Number of Nodes in the Pool (0xd0) */ ++ agnx_write32(ctl, AGNX_BM_FPCNT, PDU_FREE_CNT); ++ ++ /* Start all workqueue */ ++ agnx_write32(ctl, AGNX_BM_CIWQCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_CPULWCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_CPUHWCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_CPUTXWCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_CPURXWCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_SPRXWCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_SPTXWCTL, 0x80000); ++ agnx_write32(ctl, AGNX_BM_RFPWCTL, 0x80000); ++ ++ /* Enable the Band Management */ ++ reg = agnx_read32(ctl, AGNX_BM_BMCTL); ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_BM_BMCTL, reg); ++} /* band_managment_init */ ++ ++ ++static void system_itf_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x0); ++ agnx_write32(ctl, AGNX_PM_TESTPHY, 0x11e143a); ++ ++ if (priv->revid == 0) { ++ reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE); ++ reg |= 0x11; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg); ++ } ++ /* ??? What is that means? it should difference for differice type ++ of cards */ ++ agnx_write32(ctl, AGNX_CIR_SERIALITF, 0xfff81006); ++ ++ agnx_write32(ctl, AGNX_SYSITF_GPIOIN, 0x1f0000); ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5); ++ reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN); ++} ++ ++static void encryption_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ AGNX_TRACE; ++ ++ agnx_write32(ctl, AGNX_ENCRY_WEPKEY0, 0x0); ++ agnx_write32(ctl, AGNX_ENCRY_WEPKEY1, 0x0); ++ agnx_write32(ctl, AGNX_ENCRY_WEPKEY2, 0x0); ++ agnx_write32(ctl, AGNX_ENCRY_WEPKEY3, 0x0); ++ agnx_write32(ctl, AGNX_ENCRY_CCMRECTL, 0x8); ++} ++ ++static void tx_management_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ void __iomem *data = priv->data; ++ u32 reg; ++ AGNX_TRACE; ++ ++ /* Fill out the ComputationalEngineLookupTable ++ * starting at memory #2 offset 0x800 ++ */ ++ tx_engine_lookup_tbl_init(priv); ++ memset_io(data + 0x1000, 0, 0xfe0); ++ /* Enable Transmission Management Functions */ ++ agnx_write32(ctl, AGNX_TXM_ETMF, 0x3ff); ++ /* Write 0x3f to Transmission Template */ ++ agnx_write32(ctl, AGNX_TXM_TXTEMP, 0x3f); ++ ++ if (priv->revid >= 2) ++ agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e140a0b); ++ else ++ agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e190a0b); ++ ++ reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); ++ reg &= 0xff00; ++ reg |= 0xb; ++ agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); ++ reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); ++ reg &= 0xffff00ff; ++ reg |= 0xa00; ++ agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); ++ /* Enable TIFS */ ++ agnx_write32(ctl, AGNX_TXM_CTL, 0x40000); ++ ++ reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); ++ reg &= 0xff00ffff; ++ reg |= 0x510000; ++ agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); ++ reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY); ++ reg &= 0xff00ffff; ++ agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg); ++ reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS); ++ reg &= 0x00ffffff; ++ reg |= 0x1c000000; ++ agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg); ++ reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY); ++ reg &= 0x00ffffff; ++ reg |= 0x01000000; ++ agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg); ++ ++ /* # Set DIF 0-1,2-3,4-5,6-7 to defaults */ ++ agnx_write32(ctl, AGNX_TXM_DIF01, 0x321d321d); ++ agnx_write32(ctl, AGNX_TXM_DIF23, 0x321d321d); ++ agnx_write32(ctl, AGNX_TXM_DIF45, 0x321d321d); ++ agnx_write32(ctl, AGNX_TXM_DIF67, 0x321d321d); ++ ++ /* Max Ack timeout limit */ ++ agnx_write32(ctl, AGNX_TXM_MAXACKTIM, 0x1e19); ++ /* Max RX Data Timeout count, */ ++ reg = agnx_read32(ctl, AGNX_TXM_MAXRXTIME); ++ reg &= 0xffff0000; ++ reg |= 0xff; ++ agnx_write32(ctl, AGNX_TXM_MAXRXTIME, reg); ++ ++ /* CF poll RX Timeout count */ ++ reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM); ++ reg &= 0xffff; ++ reg |= 0xff0000; ++ agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg); ++ ++ /* Max Timeout Exceeded count, */ ++ reg = agnx_read32(ctl, AGNX_TXM_MAXTIMOUT); ++ reg &= 0xff00ffff; ++ reg |= 0x190000; ++ agnx_write32(ctl, AGNX_TXM_MAXTIMOUT, reg); ++ ++ /* CF ack timeout limit for 11b */ ++ reg = agnx_read32(ctl, AGNX_TXM_CFACKT11B); ++ reg &= 0xff00; ++ reg |= 0x1e; ++ agnx_write32(ctl, AGNX_TXM_CFACKT11B, reg); ++ ++ /* Max CF Poll Timeout Count */ ++ reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM); ++ reg &= 0xffff0000; ++ reg |= 0x19; ++ agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg); ++ /* CF Poll RX Timeout Count */ ++ reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM); ++ reg &= 0xffff0000; ++ reg |= 0x1e; ++ agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg); ++ ++ /* # write default to */ ++ /* 1. Schedule Empty Count */ ++ agnx_write32(ctl, AGNX_TXM_SCHEMPCNT, 0x5); ++ /* 2. CFP Period Count */ ++ agnx_write32(ctl, AGNX_TXM_CFPERCNT, 0x1); ++ /* 3. CFP MDV */ ++ agnx_write32(ctl, AGNX_TXM_CFPMDV, 0x10000); ++ ++ /* Probe Delay */ ++ reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY); ++ reg &= 0xffff0000; ++ reg |= 0x400; ++ agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg); ++ ++ /* Max CCA count Slot */ ++ reg = agnx_read32(ctl, AGNX_TXM_MAXCCACNTSLOT); ++ reg &= 0xffff00ff; ++ reg |= 0x900; ++ agnx_write32(ctl, AGNX_TXM_MAXCCACNTSLOT, reg); ++ ++ /* Slot limit/1 msec Limit */ ++ reg = agnx_read32(ctl, AGNX_TXM_SLOTLIMIT); ++ reg &= 0xff00ffff; ++ reg |= 0x140077; ++ agnx_write32(ctl, AGNX_TXM_SLOTLIMIT, reg); ++ ++ /* # Set CW #(0-7) to default */ ++ agnx_write32(ctl, AGNX_TXM_CW0, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW1, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW2, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW3, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW4, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW5, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW6, 0xff0007); ++ agnx_write32(ctl, AGNX_TXM_CW7, 0xff0007); ++ ++ /* # Set Short/Long limit #(0-7) to default */ ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM0, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM1, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM2, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM3, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM4, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM5, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM6, 0xa000a); ++ agnx_write32(ctl, AGNX_TXM_SLBEALIM7, 0xa000a); ++ ++ reg = agnx_read32(ctl, AGNX_TXM_CTL); ++ reg |= 0x1400; ++ agnx_write32(ctl, AGNX_TXM_CTL, reg); ++ /* Wait for bit 0 in Control Reg to clear */ ++ udelay(80); ++ reg = agnx_read32(ctl, AGNX_TXM_CTL); ++ /* Or 0x18000 to Control reg */ ++ reg = agnx_read32(ctl, AGNX_TXM_CTL); ++ reg |= 0x18000; ++ agnx_write32(ctl, AGNX_TXM_CTL, reg); ++ /* Wait for bit 0 in Control Reg to clear */ ++ udelay(80); ++ reg = agnx_read32(ctl, AGNX_TXM_CTL); ++ ++ /* Set Listen Interval Count to default */ ++ agnx_write32(ctl, AGNX_TXM_LISINTERCNT, 0x1); ++ /* Set DTIM period count to default */ ++ agnx_write32(ctl, AGNX_TXM_DTIMPERICNT, 0x2000); ++} /* tx_management_init */ ++ ++static void rx_management_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ AGNX_TRACE; ++ ++ /* Initialize the Routing Table */ ++ routing_table_init(priv); ++ ++ if (priv->revid >= 3) { ++ agnx_write32(ctl, 0x2074, 0x1f171710); ++ agnx_write32(ctl, 0x2078, 0x10100d0d); ++ agnx_write32(ctl, 0x207c, 0x11111010); ++ } ++ else ++ agnx_write32(ctl, AGNX_RXM_DELAY11, 0x0); ++ agnx_write32(ctl, AGNX_RXM_REQRATE, 0x8195e00); ++} ++ ++ ++static void agnx_timer_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ AGNX_TRACE; ++ ++/* /\* Write 0x249f00 (tick duration?) to Timer 1 *\/ */ ++/* agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x249f00); */ ++/* /\* Write 0xe2 to Timer 1 Control *\/ */ ++/* agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0xe2); */ ++ ++ /* Write 0x249f00 (tick duration?) to Timer 1 */ ++ agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x0); ++ /* Write 0xe2 to Timer 1 Control */ ++ agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0x0); ++ ++ iowrite32(0xFFFFFFFF, priv->ctl + AGNX_TXM_BEACON_CTL); ++} ++ ++static void power_manage_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ agnx_write32(ctl, AGNX_PM_MACMSW, 0x1f); ++ agnx_write32(ctl, AGNX_PM_RFCTL, 0x1f); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg &= 0xf00f; ++ reg |= 0xa0; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ ++ if (priv->revid >= 3) { ++ reg = agnx_read32(ctl, AGNX_PM_SOFTRST); ++ reg |= 0x18; ++ agnx_write32(ctl, AGNX_PM_SOFTRST, reg); ++ } ++} /* power_manage_init */ ++ ++ ++static void gain_ctlcnt_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ agnx_write32(ctl, AGNX_GCR_TRACNT5, 0x119); ++ agnx_write32(ctl, AGNX_GCR_TRACNT6, 0x118); ++ agnx_write32(ctl, AGNX_GCR_TRACNT7, 0x117); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg &= ~0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ ++ agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0); ++ ++ /* FIXME Write the initial Station Descriptor for the card */ ++ sta_init(priv, LOCAL_STAID); ++ sta_init(priv, BSSID_STAID); ++ ++ /* Enable staion 0 and 1 can do TX */ ++ /* It seemed if we set other bit to 1 the bit 0 will ++ be auto change to 0 */ ++ agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x2 | 0x1); ++// agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x1); ++} /* gain_ctlcnt_init */ ++ ++ ++static void phy_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ void __iomem *data = priv->data; ++ u32 reg; ++ AGNX_TRACE; ++ ++ /* Load InitialGainTable */ ++ gain_table_init(priv); ++ ++ agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x2000000); ++ ++ /* Clear the following offsets in Memory Range #2: */ ++ memset_io(data + 0x5040, 0, 0xa * 4); ++ memset_io(data + 0x5080, 0, 0xa * 4); ++ memset_io(data + 0x50c0, 0, 0xa * 4); ++ memset_io(data + 0x5400, 0, 0x80 * 4); ++ memset_io(data + 0x6000, 0, 0x280 * 4); ++ memset_io(data + 0x7000, 0, 0x280 * 4); ++ memset_io(data + 0x8000, 0, 0x280 * 4); ++ ++ /* Initialize the Following Registers According to PCI Revision ID */ ++ if (priv->revid == 0) { ++ /* fixme the part hasn't been update but below has been update ++ based on WGM511 */ ++ agnx_write32(ctl, AGNX_ACI_LEN, 0xf); ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x1d); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x3); ++ agnx_write32(ctl, AGNX_ACI_AICCHA0OVE, 0x11); ++ agnx_write32(ctl, AGNX_ACI_AICCHA1OVE, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THD0A, 0x64); ++ agnx_write32(ctl, AGNX_GCR_THD0AL, 0x4b); ++ agnx_write32(ctl, AGNX_GCR_THD0B, 0x4b); ++ agnx_write32(ctl, AGNX_GCR_DUNSAT, 0x14); ++ agnx_write32(ctl, AGNX_GCR_DSAT, 0x24); ++ agnx_write32(ctl, AGNX_GCR_DFIRCAL, 0x8); ++ agnx_write32(ctl, AGNX_GCR_DGCTL11A, 0x1a); ++ agnx_write32(ctl, AGNX_GCR_DGCTL11B, 0x3); ++ agnx_write32(ctl, AGNX_GCR_GAININIT, 0xd); ++ agnx_write32(ctl, AGNX_GCR_THNOSIG, 0x1); ++ agnx_write32(ctl, AGNX_GCR_COARSTEP, 0x7); ++ agnx_write32(ctl, AGNX_GCR_SIFST11A, 0x28); ++ agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28); ++ reg = agnx_read32(ctl, AGNX_GCR_CWDETEC); ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_GCR_CWDETEC, reg); ++ agnx_write32(ctl, AGNX_GCR_0X38, 0x1e); ++ agnx_write32(ctl, AGNX_GCR_BOACT, 0x26); ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THCAP11B, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THCAPRX11A, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THCAPRX11B, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THLEVDRO, 0x10); ++ agnx_write32(ctl, AGNX_GCR_MAXRXTIME11A, 0x1); ++ agnx_write32(ctl, AGNX_GCR_MAXRXTIME11B, 0x1); ++ agnx_write32(ctl, AGNX_GCR_CORRTIME, 0x190); ++ agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x78); ++ agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x1c); ++ agnx_write32(ctl, AGNX_GCR_CORRDROP, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THCD, 0x0); ++ agnx_write32(ctl, AGNX_GCR_MAXPOWDIFF, 0x1); ++ agnx_write32(ctl, AGNX_GCR_TESTBUS, 0x0); ++ agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f); ++ agnx_write32(ctl, AGNX_GCR_THJUMP, 0x14); ++ agnx_write32(ctl, AGNX_GCR_THPOWER, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THPOWCLIP, 0x30); ++ agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x32); ++ agnx_write32(ctl, AGNX_GCR_THRX11BPOWMIN, 0x19); ++ agnx_write32(ctl, AGNX_GCR_0X14c, 0x0); ++ agnx_write32(ctl, AGNX_GCR_0X150, 0x0); ++ agnx_write32(ctl, 0x9400, 0x0); ++ agnx_write32(ctl, 0x940c, 0x6ff); ++ agnx_write32(ctl, 0x9428, 0xa0); ++ agnx_write32(ctl, 0x9434, 0x0); ++ agnx_write32(ctl, 0x9c04, 0x15); ++ agnx_write32(ctl, 0x9c0c, 0x7f); ++ agnx_write32(ctl, 0x9c34, 0x0); ++ agnx_write32(ctl, 0xc000, 0x38d); ++ agnx_write32(ctl, 0x14018, 0x0); ++ agnx_write32(ctl, 0x16000, 0x1); ++ agnx_write32(ctl, 0x11004, 0x0); ++ agnx_write32(ctl, 0xec54, 0xa); ++ agnx_write32(ctl, 0xec1c, 0x5); ++ } else if (priv->revid > 0) { ++ agnx_write32(ctl, AGNX_ACI_LEN, 0xf); ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27); ++ agnx_write32(ctl, AGNX_ACI_AICCHA0OVE, 0x11); ++ agnx_write32(ctl, AGNX_ACI_AICCHA1OVE, 0x0); ++ agnx_write32(ctl, AGNX_GCR_DUNSAT, 0x14); ++ agnx_write32(ctl, AGNX_GCR_DSAT, 0x24); ++ agnx_write32(ctl, AGNX_GCR_DFIRCAL, 0x8); ++ agnx_write32(ctl, AGNX_GCR_DGCTL11A, 0x1a); ++ agnx_write32(ctl, AGNX_GCR_DGCTL11B, 0x3); ++ agnx_write32(ctl, AGNX_GCR_GAININIT, 0xd); ++ agnx_write32(ctl, AGNX_GCR_THNOSIG, 0x1); ++ agnx_write32(ctl, AGNX_GCR_COARSTEP, 0x7); ++ agnx_write32(ctl, AGNX_GCR_SIFST11A, 0x28); ++ agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28); ++ agnx_write32(ctl, AGNX_GCR_CWDETEC, 0x0); ++ agnx_write32(ctl, AGNX_GCR_0X38, 0x1e); ++// agnx_write32(ctl, AGNX_GCR_BOACT, 0x26); ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); ++ ++ agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x32); ++ agnx_write32(ctl, AGNX_GCR_THCAP11B, 0x32); ++ agnx_write32(ctl, AGNX_GCR_THCAPRX11A, 0x32); ++ agnx_write32(ctl, AGNX_GCR_THCAPRX11B, 0x32); ++ agnx_write32(ctl, AGNX_GCR_THLEVDRO, 0x10); ++ agnx_write32(ctl, AGNX_GCR_MAXRXTIME11A, 0x1ad); ++ agnx_write32(ctl, AGNX_GCR_MAXRXTIME11B, 0xa10); ++ agnx_write32(ctl, AGNX_GCR_CORRTIME, 0x190); ++ agnx_write32(ctl, AGNX_GCR_CORRDROP, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THCD, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THCS, 0x0); ++ agnx_write32(ctl, AGNX_GCR_MAXPOWDIFF, 0x4); ++ agnx_write32(ctl, AGNX_GCR_TESTBUS, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THJUMP, 0x1e); ++ agnx_write32(ctl, AGNX_GCR_THPOWER, 0x0); ++ agnx_write32(ctl, AGNX_GCR_THPOWCLIP, 0x2a); ++ agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c); ++ agnx_write32(ctl, AGNX_GCR_THRX11BPOWMIN, 0x19); ++ agnx_write32(ctl, AGNX_GCR_0X14c, 0x0); ++ agnx_write32(ctl, AGNX_GCR_0X150, 0x0); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ agnx_write32(ctl, AGNX_GCR_WATCHDOG, 0x37); ++ agnx_write32(ctl, 0x9400, 0x0); ++ agnx_write32(ctl, 0x940c, 0x6ff); ++ agnx_write32(ctl, 0x9428, 0xa0); ++ agnx_write32(ctl, 0x9434, 0x0); ++ agnx_write32(ctl, 0x9c04, 0x15); ++ agnx_write32(ctl, 0x9c0c, 0x7f); ++ agnx_write32(ctl, 0x9c34, 0x0); ++ agnx_write32(ctl, 0xc000, 0x38d); ++ agnx_write32(ctl, 0x14014, 0x1000); ++ agnx_write32(ctl, 0x14018, 0x0); ++ agnx_write32(ctl, 0x16000, 0x1); ++ agnx_write32(ctl, 0x11004, 0x0); ++ agnx_write32(ctl, 0xec54, 0xa); ++ agnx_write32(ctl, 0xec1c, 0x50); ++ } else if (priv->revid > 1) { ++ reg = agnx_read32(ctl, 0xec18); ++ reg |= 0x8; ++ agnx_write32(ctl, 0xec18, reg); ++ } ++ ++ /* Write the TX Fir Coefficient Table */ ++ tx_fir_table_init(priv); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg &= ~0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ reg = agnx_read32(ctl, AGNX_PM_PLLCTL); ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_PM_PLLCTL, reg); ++ ++/* reg = agnx_read32(ctl, 0x1a030); */ ++/* reg &= ~0x4; */ ++/* agnx_write32(ctl, 0x1a030, reg); */ ++ ++ agnx_write32(ctl, AGNX_GCR_TRACNT4, 0x113); ++} /* phy_init */ ++ ++static void chip_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ band_management_init(priv); ++ ++ rf_chips_init(priv); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ ++ /* Initialize the PHY */ ++ phy_init(priv); ++ ++ encryption_init(priv); ++ ++ tx_management_init(priv); ++ ++ rx_management_init(priv); ++ ++ power_manage_init(priv); ++ ++ /* Initialize the Timers */ ++ agnx_timer_init(priv); ++ ++ /* Write 0xc390bf9 to Interrupt Mask (Disable TX) */ ++ reg = 0xc390bf9 & ~IRQ_TX_BEACON; ++ reg &= ~IRQ_TX_DISABLE; ++ agnx_write32(ctl, AGNX_INT_MASK, reg); ++ ++ reg = agnx_read32(ctl, AGNX_CIR_BLKCTL); ++ reg |= 0x800; ++ agnx_write32(ctl, AGNX_CIR_BLKCTL, reg); ++ ++ /* set it when need get multicast enable? */ ++ agnx_write32(ctl, AGNX_BM_MTSM, 0xff); ++} /* chip_init */ ++ ++ ++static inline void set_promis_and_managed(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10 | 0x2); ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10 | 0x2); ++} ++static inline void set_learn_mode(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x8); ++} ++static inline void set_scan_mode(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x20); ++} ++static inline void set_promiscuous_mode(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ /* agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x210);*/ ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10); ++} ++static inline void set_managed_mode(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x2); ++} ++static inline void set_adhoc_mode(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x0); ++} ++ ++static void unknow_register_write(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x0, 0x3e); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x4, 0xb2); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x8, 0x140); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0xc, 0x1C0); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x10, 0x1FF); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x14, 0x1DD); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x18, 0x15F); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x1c, 0xA1); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x20, 0x3E7); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x24, 0x36B); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x28, 0x348); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x2c, 0x37D); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x30, 0x3DE); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x34, 0x36); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x38, 0x64); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x3c, 0x57); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x40, 0x23); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x44, 0x3ED); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x48, 0x3C9); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x4c, 0x3CA); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x50, 0x3E7); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x54, 0x8); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x58, 0x1F); ++ agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x5c, 0x1a); ++} ++ ++static void card_interface_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u8 bssid[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u32 reg; ++ unsigned int i; ++ AGNX_TRACE; ++ ++ might_sleep(); ++ /* Clear RX Control and Enable RX queues */ ++ agnx_write32(ctl, AGNX_CIR_RXCTL, 0x8); ++ ++ might_sleep(); ++ /* Do a full reset of the card */ ++ card_full_reset(priv); ++ might_sleep(); ++ ++ /* Check and set Card Endianness */ ++ reg = ioread32(priv->ctl + AGNX_CIR_ENDIAN); ++ /* TODO If not 0xB3B2B1B0 set to 0xB3B2B1B0 */ ++ printk(KERN_INFO PFX "CIR_ENDIAN is %x\n", reg); ++ ++ ++ /* Config the eeprom */ ++ agnx_write32(ctl, AGNX_CIR_SERIALITF, 0x7000086); ++ udelay(10); ++ reg = agnx_read32(ctl, AGNX_CIR_SERIALITF); ++ ++ ++ agnx_write32(ctl, AGNX_PM_SOFTRST, 0x80000033); ++ reg = agnx_read32(ctl, 0xec50); ++ reg |= 0xf; ++ agnx_write32(ctl, 0xec50, reg); ++ agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0); ++ ++ ++ reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN); ++ udelay(10); ++ reg = agnx_read32(ctl, AGNX_CIR_SERIALITF); ++ ++ /* Dump the eeprom */ ++ do { ++ char eeprom[0x100000/0x100]; ++ ++ for (i = 0; i < 0x100000; i += 0x100) { ++ agnx_write32(ctl, AGNX_CIR_SERIALITF, 0x3000000 + i); ++ udelay(13); ++ reg = agnx_read32(ctl, AGNX_CIR_SERIALITF); ++ udelay(70); ++ reg = agnx_read32(ctl, AGNX_CIR_SERIALITF); ++ eeprom[i/0x100] = reg & 0xFF; ++ udelay(10); ++ } ++ print_hex_dump_bytes(PFX "EEPROM: ", DUMP_PREFIX_NONE, eeprom, ++ ARRAY_SIZE(eeprom)); ++ } while(0); ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x26); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ ++ /* Initialize the system interface */ ++ system_itf_init(priv); ++ ++ might_sleep(); ++ /* Chip Initialization (Polaris) */ ++ chip_init(priv); ++ might_sleep(); ++ ++ /* Calibrate the antennae */ ++ antenna_calibrate(priv); ++ ++ reg = agnx_read32(ctl, 0xec50); ++ reg &= ~0x40; ++ agnx_write32(ctl, 0xec50, reg); ++ agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0); ++ agnx_write32(ctl, AGNX_PM_PLLCTL, 0x1); ++ ++ reg = agnx_read32(ctl, AGNX_BM_BMCTL); ++ reg |= 0x8000; ++ agnx_write32(ctl, AGNX_BM_BMCTL, reg); ++ enable_receiver(priv); ++ reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE); ++ reg |= 0x200; ++ agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg); ++ enable_receiver(priv); ++ ++ might_sleep(); ++ /* Initialize Gain Control Counts */ ++ gain_ctlcnt_init(priv); ++ ++ /* Write Initial Station Power Template for this station(#0) */ ++ sta_power_init(priv, LOCAL_STAID); ++ ++ might_sleep(); ++ /* Initialize the rx,td,tm rings, for each node in the ring */ ++ fill_rings(priv); ++ ++ might_sleep(); ++ ++ ++ agnx_write32(ctl, AGNX_PM_SOFTRST, 0x80000033); ++ agnx_write32(ctl, 0xec50, 0xc); ++ agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0); ++ ++ /* FIXME Initialize the transmit control register */ ++ agnx_write32(ctl, AGNX_TXM_CTL, 0x194c1); ++ ++ enable_receiver(priv); ++ ++ might_sleep(); ++ /* FIXME Set the Receive Control Mac Address to card address */ ++ mac_address_set(priv); ++ enable_receiver(priv); ++ might_sleep(); ++ ++ /* Set the recieve request rate */ ++ /* FIXME Enable the request */ ++ /* Check packet length */ ++ /* Set maximum packet length */ ++/* agnx_write32(ctl, AGNX_RXM_REQRATE, 0x88195e00); */ ++/* enable_receiver(priv); */ ++ ++ /* Set the Receiver BSSID */ ++ receiver_bssid_set(priv, bssid); ++ ++ /* FIXME Set to managed mode */ ++ set_managed_mode(priv); ++// set_promiscuous_mode(priv); ++/* set_scan_mode(priv); */ ++/* set_learn_mode(priv); */ ++// set_promis_and_managed(priv); ++// set_adhoc_mode(priv); ++ ++ /* Set the recieve request rate */ ++ /* Check packet length */ ++ agnx_write32(ctl, AGNX_RXM_REQRATE, 0x08000000); ++ reg = agnx_read32(ctl, AGNX_RXM_REQRATE); ++ /* Set maximum packet length */ ++ reg |= 0x00195e00; ++ agnx_write32(ctl, AGNX_RXM_REQRATE, reg); ++ ++ /* Configure the RX and TX interrupt */ ++ reg = ENABLE_RX_INTERRUPT | RX_CACHE_LINE | FRAG_LEN_2048 | FRAG_BE; ++ agnx_write32(ctl, AGNX_CIR_RXCFG, reg); ++ /* FIXME */ ++ reg = ENABLE_TX_INTERRUPT | TX_CACHE_LINE | FRAG_LEN_2048 | FRAG_BE; ++ agnx_write32(ctl, AGNX_CIR_TXCFG, reg); ++ ++ /* Enable RX TX Interrupts */ ++ agnx_write32(ctl, AGNX_CIR_RXCTL, 0x80); ++ agnx_write32(ctl, AGNX_CIR_TXMCTL, 0x80); ++ agnx_write32(ctl, AGNX_CIR_TXDCTL, 0x80); ++ ++ /* FIXME Set the master control interrupt in block control */ ++ agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x800); ++ ++ /* Enable RX and TX queues */ ++ reg = agnx_read32(ctl, AGNX_CIR_RXCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_CIR_RXCTL, reg); ++ reg = agnx_read32(ctl, AGNX_CIR_TXMCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_CIR_TXMCTL, reg); ++ reg = agnx_read32(ctl, AGNX_CIR_TXDCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_CIR_TXDCTL, reg); ++ ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5); ++ /* FIXME */ ++ /* unknow_register_write(priv); */ ++ /* Update local card hash entry */ ++ hash_write(priv, priv->mac_addr, LOCAL_STAID); ++ ++ might_sleep(); ++ ++ /* FIXME */ ++ agnx_set_channel(priv, 1); ++ might_sleep(); ++} /* agnx_card_interface_init */ ++ ++ ++void agnx_hw_init(struct agnx_priv *priv) ++{ ++ AGNX_TRACE; ++ might_sleep(); ++ card_interface_init(priv); ++} ++ ++int agnx_hw_reset(struct agnx_priv *priv) ++{ ++ return card_full_reset(priv); ++} ++ ++int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len) ++{ ++ AGNX_TRACE; ++ return 0; ++} ++ ++void agnx_set_bssid(struct agnx_priv *priv, u8 *bssid) ++{ ++ receiver_bssid_set(priv, bssid); ++} +--- /dev/null ++++ b/drivers/staging/agnx/phy.h +@@ -0,0 +1,409 @@ ++#ifndef AGNX_PHY_H_ ++#define AGNX_PHY_H_ ++ ++#include "agnx.h" ++ ++/* Transmission Managment Registers */ ++#define AGNX_TXM_BASE 0x0000 ++#define AGNX_TXM_CTL 0x0000 /* control register */ ++#define AGNX_TXM_ETMF 0x0004 /* enable transmission management functions */ ++#define AGNX_TXM_TXTEMP 0x0008 /* transmission template */ ++#define AGNX_TXM_RETRYSTAID 0x000c /* Retry Station ID */ ++#define AGNX_TXM_TIMESTAMPLO 0x0010 /* Timestamp Lo */ ++#define AGNX_TXM_TIMESTAMPHI 0x0014 /* Timestamp Hi */ ++#define AGNX_TXM_TXDELAY 0x0018 /* tx delay */ ++#define AGNX_TXM_TBTTLO 0x0020 /* tbtt Lo */ ++#define AGNX_TXM_TBTTHI 0x0024 /* tbtt Hi */ ++#define AGNX_TXM_BEAINTER 0x0028 /* Beacon Interval */ ++#define AGNX_TXM_NAV 0x0030 /* NAV */ ++#define AGNX_TXM_CFPMDV 0x0034 /* CFP MDV */ ++#define AGNX_TXM_CFPERCNT 0x0038 /* CFP period count */ ++#define AGNX_TXM_PROBDELAY 0x003c /* probe delay */ ++#define AGNX_TXM_LISINTERCNT 0x0040 /* listen interval count */ ++#define AGNX_TXM_DTIMPERICNT 0x004c /* DTIM period count */ ++ ++#define AGNX_TXM_BEACON_CTL 0x005c /* beacon control */ ++ ++#define AGNX_TXM_SCHEMPCNT 0x007c /* schedule empty count */ ++#define AGNX_TXM_MAXTIMOUT 0x0084 /* max timeout exceed count */ ++#define AGNX_TXM_MAXCFPTIM 0x0088 /* max CF poll timeout count */ ++#define AGNX_TXM_MAXRXTIME 0x008c /* max RX timeout count */ ++#define AGNX_TXM_MAXACKTIM 0x0090 /* max ACK timeout count */ ++#define AGNX_TXM_DIF01 0x00a0 /* DIF 0-1 */ ++#define AGNX_TXM_DIF23 0x00a4 /* DIF 2-3 */ ++#define AGNX_TXM_DIF45 0x00a8 /* DIF 4-5 */ ++#define AGNX_TXM_DIF67 0x00ac /* DIF 6-7 */ ++#define AGNX_TXM_SIFSPIFS 0x00b0 /* SIFS/PIFS */ ++#define AGNX_TXM_TIFSEIFS 0x00b4 /* TIFS/EIFS */ ++#define AGNX_TXM_MAXCCACNTSLOT 0x00b8 /* max CCA count slot */ ++#define AGNX_TXM_SLOTLIMIT 0x00bc /* slot limit/1 msec limit */ ++#define AGNX_TXM_CFPOLLRXTIM 0x00f0 /* CF poll RX timeout count */ ++#define AGNX_TXM_CFACKT11B 0x00f4 /* CF ack timeout limit for 11b */ ++#define AGNX_TXM_CW0 0x0100 /* CW 0 */ ++#define AGNX_TXM_SLBEALIM0 0x0108 /* short/long beacon limit 0 */ ++#define AGNX_TXM_CW1 0x0120 /* CW 1 */ ++#define AGNX_TXM_SLBEALIM1 0x0128 /* short/long beacon limit 1 */ ++#define AGNX_TXM_CW2 0x0140 /* CW 2 */ ++#define AGNX_TXM_SLBEALIM2 0x0148 /* short/long beacon limit 2 */ ++#define AGNX_TXM_CW3 0x0160 /* CW 3 */ ++#define AGNX_TXM_SLBEALIM3 0x0168 /* short/long beacon limit 3 */ ++#define AGNX_TXM_CW4 0x0180 /* CW 4 */ ++#define AGNX_TXM_SLBEALIM4 0x0188 /* short/long beacon limit 4 */ ++#define AGNX_TXM_CW5 0x01a0 /* CW 5 */ ++#define AGNX_TXM_SLBEALIM5 0x01a8 /* short/long beacon limit 5 */ ++#define AGNX_TXM_CW6 0x01c0 /* CW 6 */ ++#define AGNX_TXM_SLBEALIM6 0x01c8 /* short/long beacon limit 6 */ ++#define AGNX_TXM_CW7 0x01e0 /* CW 7 */ ++#define AGNX_TXM_SLBEALIM7 0x01e8 /* short/long beacon limit 7 */ ++#define AGNX_TXM_BEACONTEMP 0x1000 /* beacon template */ ++#define AGNX_TXM_STAPOWTEMP 0x1a00 /* Station Power Template */ ++ ++/* Receive Management Control Registers */ ++#define AGNX_RXM_BASE 0x2000 ++#define AGNX_RXM_REQRATE 0x2000 /* requested rate */ ++#define AGNX_RXM_MACHI 0x2004 /* first 4 bytes of mac address */ ++#define AGNX_RXM_MACLO 0x2008 /* last 2 bytes of mac address */ ++#define AGNX_RXM_BSSIDHI 0x200c /* bssid hi */ ++#define AGNX_RXM_BSSIDLO 0x2010 /* bssid lo */ ++#define AGNX_RXM_HASH_CMD_FLAG 0x2014 /* Flags for the RX Hash Command Default:0 */ ++#define AGNX_RXM_HASH_CMD_HIGH 0x2018 /* The High half of the Hash Command */ ++#define AGNX_RXM_HASH_CMD_LOW 0x201c /* The Low half of the Hash Command */ ++#define AGNX_RXM_ROUTAB 0x2020 /* routing table */ ++#define ROUTAB_SUBTYPE_SHIFT 24 ++#define ROUTAB_TYPE_SHIFT 28 ++#define ROUTAB_STATUS_SHIFT 30 ++#define ROUTAB_RW_SHIFT 31 ++#define ROUTAB_ROUTE_DROP 0xf00000 /* Drop */ ++#define ROUTAB_ROUTE_CPU 0x400000 /* CPU */ ++#define ROUTAB_ROUTE_ENCRY 0x500800 /* Encryption */ ++#define ROUTAB_ROUTE_RFP 0x800000 /* RFP */ ++ ++#define ROUTAB_TYPE_MANAG 0x0 /* Management */ ++#define ROUTAB_TYPE_CTL 0x1 /* Control */ ++#define ROUTAB_TYPE_DATA 0x2 /* Data */ ++ ++#define ROUTAB_SUBTYPE_DATA 0x0 ++#define ROUTAB_SUBTYPE_DATAACK 0x1 ++#define ROUTAB_SUBTYPE_DATAPOLL 0x2 ++#define ROUTAB_SUBTYPE_DATAPOLLACK 0x3 ++#define ROUTAB_SUBTYPE_NULL 0x4 /* NULL */ ++#define ROUTAB_SUBTYPE_NULLACK 0x5 ++#define ROUTAB_SUBTYPE_NULLPOLL 0x6 ++#define ROUTAB_SUBTYPE_NULLPOLLACK 0x7 ++#define ROUTAB_SUBTYPE_QOSDATA 0x8 /* QOS DATA */ ++#define ROUTAB_SUBTYPE_QOSDATAACK 0x9 ++#define ROUTAB_SUBTYPE_QOSDATAPOLL 0xa ++#define ROUTAB_SUBTYPE_QOSDATAACKPOLL 0xb ++#define ROUTAB_SUBTYPE_QOSNULL 0xc ++#define ROUTAB_SUBTYPE_QOSNULLACK 0xd ++#define ROUTAB_SUBTYPE_QOSNULLPOLL 0xe ++#define ROUTAB_SUBTYPE_QOSNULLPOLLACK 0xf ++#define AGNX_RXM_DELAY11 0x2024 /* delay 11(AB) */ ++#define AGNX_RXM_SOF_CNT 0x2028 /* SOF Count */ ++#define AGNX_RXM_FRAG_CNT 0x202c /* Fragment Count*/ ++#define AGNX_RXM_FCS_CNT 0x2030 /* FCS Count */ ++#define AGNX_RXM_BSSID_MISS_CNT 0x2034 /* BSSID Miss Count */ ++#define AGNX_RXM_PDU_ERR_CNT 0x2038 /* PDU Error Count */ ++#define AGNX_RXM_DEST_MISS_CNT 0x203C /* Destination Miss Count */ ++#define AGNX_RXM_DROP_CNT 0x2040 /* Drop Count */ ++#define AGNX_RXM_ABORT_CNT 0x2044 /* Abort Count */ ++#define AGNX_RXM_RELAY_CNT 0x2048 /* Relay Count */ ++#define AGNX_RXM_HASH_MISS_CNT 0x204c /* Hash Miss Count */ ++#define AGNX_RXM_SA_HI 0x2050 /* Address of received packet Hi */ ++#define AGNX_RXM_SA_LO 0x2054 /* Address of received packet Lo */ ++#define AGNX_RXM_HASH_DUMP_LST 0x2100 /* Contains Hash Data */ ++#define AGNX_RXM_HASH_DUMP_MST 0x2104 /* Contains Hash Data */ ++#define AGNX_RXM_HASH_DUMP_DATA 0x2108 /* The Station ID to dump */ ++ ++ ++/* Encryption Managment */ ++#define AGNX_ENCRY_BASE 0x2400 ++#define AGNX_ENCRY_WEPKEY0 0x2440 /* wep key #0 */ ++#define AGNX_ENCRY_WEPKEY1 0x2444 /* wep key #1 */ ++#define AGNX_ENCRY_WEPKEY2 0x2448 /* wep key #2 */ ++#define AGNX_ENCRY_WEPKEY3 0x244c /* wep key #3 */ ++#define AGNX_ENCRY_CCMRECTL 0x2460 /* ccm replay control */ ++ ++ ++/* Band Management Registers */ ++#define AGNX_BM_BASE 0x2c00 ++#define AGNX_BM_BMCTL 0x2c00 /* band management control */ ++#define AGNX_BM_TXWADDR 0x2c18 /* tx workqueue address start */ ++#define AGNX_BM_TXTOPEER 0x2c24 /* transmit to peers */ ++#define AGNX_BM_FPLHP 0x2c2c /* free pool list head pointer */ ++#define AGNX_BM_FPLTP 0x2c30 /* free pool list tail pointer */ ++#define AGNX_BM_FPCNT 0x2c34 /* free pool count */ ++#define AGNX_BM_CIPDUWCNT 0x2c38 /* card interface pdu workqueue count */ ++#define AGNX_BM_SPPDUWCNT 0x2c3c /* sp pdu workqueue count */ ++#define AGNX_BM_RFPPDUWCNT 0x2c40 /* rfp pdu workqueue count */ ++#define AGNX_BM_RHPPDUWCNT 0x2c44 /* rhp pdu workqueue count */ ++#define AGNX_BM_CIWQCTL 0x2c48 /* Card Interface WorkQueue Control */ ++#define AGNX_BM_CPUTXWCTL 0x2c50 /* cpu tx workqueue control */ ++#define AGNX_BM_CPURXWCTL 0x2c58 /* cpu rx workqueue control */ ++#define AGNX_BM_CPULWCTL 0x2c60 /* cpu low workqueue control */ ++#define AGNX_BM_CPUHWCTL 0x2c68 /* cpu high workqueue control */ ++#define AGNX_BM_SPTXWCTL 0x2c70 /* sp tx workqueue control */ ++#define AGNX_BM_SPRXWCTL 0x2c78 /* sp rx workqueue control */ ++#define AGNX_BM_RFPWCTL 0x2c80 /* RFP workqueue control */ ++#define AGNX_BM_MTSM 0x2c90 /* Multicast Transmit Station Mask */ ++ ++/* Card Interface Registers (32bits) */ ++#define AGNX_CIR_BASE 0x3000 ++#define AGNX_CIR_BLKCTL 0x3000 /* block control*/ ++#define AGNX_STAT_TX 0x1 ++#define AGNX_STAT_RX 0x2 ++#define AGNX_STAT_X 0x4 ++/* Below two interrupt flags will be set by our but not CPU or the card */ ++#define AGNX_STAT_TXD 0x10 ++#define AGNX_STAT_TXM 0x20 ++ ++#define AGNX_CIR_ADDRWIN 0x3004 /* Addressable Windows*/ ++#define AGNX_CIR_ENDIAN 0x3008 /* card endianness */ ++#define AGNX_CIR_SERIALITF 0x3020 /* serial interface */ ++#define AGNX_CIR_RXCFG 0x3040 /* receive config */ ++#define ENABLE_RX_INTERRUPT 0x20 ++#define RX_CACHE_LINE 0x8 ++/* the RX fragment length */ ++#define FRAG_LEN_256 0x0 /* 256B */ ++#define FRAG_LEN_512 0x1 ++#define FRAG_LEN_1024 0x2 ++#define FRAG_LEN_2048 0x3 ++#define FRAG_BE 0x10 ++#define AGNX_CIR_RXCTL 0x3050 /* receive control */ ++/* memory address, chipside */ ++#define AGNX_CIR_RXCMSTART 0x3054 /* receive client memory start */ ++#define AGNX_CIR_RXCMEND 0x3058 /* receive client memory end */ ++/* memory address, pci */ ++#define AGNX_CIR_RXHOSTADDR 0x3060 /* receive hostside address */ ++/* memory address, chipside */ ++#define AGNX_CIR_RXCLIADDR 0x3064 /* receive clientside address */ ++#define AGNX_CIR_RXDMACTL 0x3068 /* receive dma control */ ++#define AGNX_CIR_TXCFG 0x3080 /* transmit config */ ++#define AGNX_CIR_TXMCTL 0x3090 /* Transmit Management Control */ ++#define ENABLE_TX_INTERRUPT 0x20 ++#define TX_CACHE_LINE 0x8 ++#define AGNX_CIR_TXMSTART 0x3094 /* Transmit Management Start */ ++#define AGNX_CIR_TXMEND 0x3098 /* Transmit Management End */ ++#define AGNX_CIR_TXDCTL 0x30a0 /* transmit data control */ ++/* memeory address, chipset */ ++#define AGNX_CIR_TXDSTART 0x30a4 /* transmit data start */ ++#define AGNX_CIR_TXDEND 0x30a8 /* transmit data end */ ++#define AGNX_CIR_TXMHADDR 0x30b0 /* Transmit Management Hostside Address */ ++#define AGNX_CIR_TXMCADDR 0x30b4 /* Transmit Management Clientside Address */ ++#define AGNX_CIR_TXDMACTL 0x30b8 /* transmit dma control */ ++ ++ ++/* Power Managment Unit */ ++#define AGNX_PM_BASE 0x3c00 ++#define AGNX_PM_PMCTL 0x3c00 /* PM Control*/ ++#define AGNX_PM_MACMSW 0x3c08 /* MAC Manual Slow Work Enable */ ++#define AGNX_PM_RFCTL 0x3c0c /* RF Control */ ++#define AGNX_PM_PHYMW 0x3c14 /* Phy Mannal Work */ ++#define AGNX_PM_SOFTRST 0x3c18 /* PMU Soft Reset */ ++#define AGNX_PM_PLLCTL 0x3c1c /* PMU PLL control*/ ++#define AGNX_PM_TESTPHY 0x3c24 /* PMU Test Phy */ ++ ++ ++/* Interrupt Control interface */ ++#define AGNX_INT_BASE 0x4000 ++#define AGNX_INT_STAT 0x4000 /* interrupt status */ ++#define AGNX_INT_MASK 0x400c /* interrupt mask */ ++/* FIXME */ ++#define IRQ_TX_BEACON 0x1 /* TX Beacon */ ++#define IRQ_TX_RETRY 0x8 /* TX Retry Interrupt */ ++#define IRQ_TX_ACTIVITY 0x10 /* TX Activity */ ++#define IRQ_RX_ACTIVITY 0x20 /* RX Activity */ ++/* FIXME I guess that instead RX a none exist staion's packet or ++ the station hasn't been init */ ++#define IRQ_RX_X 0x40 ++#define IRQ_RX_Y 0x80 /* RX ? */ ++#define IRQ_RX_HASHHIT 0x100 /* RX Hash Hit */ ++#define IRQ_RX_FRAME 0x200 /* RX Frame */ ++#define IRQ_ERR_INT 0x400 /* Error Interrupt */ ++#define IRQ_TX_QUE_FULL 0x800 /* TX Workqueue Full */ ++#define IRQ_BANDMAN_ERR 0x10000 /* Bandwidth Management Error */ ++#define IRQ_TX_DISABLE 0x20000 /* TX Disable */ ++#define IRQ_RX_IVASESKEY 0x80000 /* RX Invalid Session Key */ ++#define IRQ_RX_KEYIDMIS 0x100000 /* RX key ID Mismatch */ ++#define IRQ_REP_THHIT 0x200000 /* Replay Threshold Hit */ ++#define IRQ_TIMER1 0x4000000 /* Timer1 */ ++#define IRQ_TIMER_CNT 0x10000000 /* Timer Count */ ++#define IRQ_PHY_FASTINT 0x20000000 /* Phy Fast Interrupt */ ++#define IRQ_PHY_SLOWINT 0x40000000 /* Phy Slow Interrupt */ ++#define IRQ_OTHER 0x80000000 /* Unknow interrupt */ ++#define AGNX_IRQ_ALL 0xffffffff ++ ++/* System Interface */ ++#define AGNX_SYSITF_BASE 0x4400 ++#define AGNX_SYSITF_SYSMODE 0x4400 /* system mode */ ++#define AGNX_SYSITF_GPIOIN 0x4410 /* GPIO In */ ++/* PIN lines for leds? */ ++#define AGNX_SYSITF_GPIOUT 0x4414 /* GPIO Out */ ++ ++/* Timer Control */ ++#define AGNX_TIMCTL_TIMER1 0x4800 /* Timer 1 */ ++#define AGNX_TIMCTL_TIM1CTL 0x4808 /* Timer 1 Control */ ++ ++ ++/* Antenna Calibration Interface */ ++#define AGNX_ACI_BASE 0x5000 ++#define AGNX_ACI_MODE 0x5000 /* Mode */ ++#define AGNX_ACI_MEASURE 0x5004 /* Measure */ ++#define AGNX_ACI_SELCHAIN 0x5008 /* Select Chain */ ++#define AGNX_ACI_LEN 0x500c /* Length */ ++#define AGNX_ACI_TIMER1 0x5018 /* Timer 1 */ ++#define AGNX_ACI_TIMER2 0x501c /* Timer 2 */ ++#define AGNX_ACI_OFFSET 0x5020 /* Offset */ ++#define AGNX_ACI_STATUS 0x5030 /* Status */ ++#define CALI_IDLE 0x0 ++#define CALI_DONE 0x1 ++#define CALI_BUSY 0x2 ++#define CALI_ERR 0x3 ++#define AGNX_ACI_AICCHA0OVE 0x5034 /* AIC Channel 0 Override */ ++#define AGNX_ACI_AICCHA1OVE 0x5038 /* AIC Channel 1 Override */ ++ ++/* Gain Control Registers */ ++#define AGNX_GCR_BASE 0x9000 ++/* threshold of primary antenna */ ++#define AGNX_GCR_THD0A 0x9000 /* threshold? D0 A */ ++/* low threshold of primary antenna */ ++#define AGNX_GCR_THD0AL 0x9004 /* threshold? D0 A low */ ++/* threshold of secondary antenna */ ++#define AGNX_GCR_THD0B 0x9008 /* threshold? D0_B */ ++#define AGNX_GCR_DUNSAT 0x900c /* d unsaturated */ ++#define AGNX_GCR_DSAT 0x9010 /* d saturated */ ++#define AGNX_GCR_DFIRCAL 0x9014 /* D Fir/Cal */ ++#define AGNX_GCR_DGCTL11A 0x9018 /* d gain control 11a */ ++#define AGNX_GCR_DGCTL11B 0x901c /* d gain control 11b */ ++/* strength of gain */ ++#define AGNX_GCR_GAININIT 0x9020 /* gain initialization */ ++#define AGNX_GCR_THNOSIG 0x9024 /* threhold no signal */ ++#define AGNX_GCR_COARSTEP 0x9028 /* coarse stepping */ ++#define AGNX_GCR_SIFST11A 0x902c /* sifx time 11a */ ++#define AGNX_GCR_SIFST11B 0x9030 /* sifx time 11b */ ++#define AGNX_GCR_CWDETEC 0x9034 /* cw detection */ ++#define AGNX_GCR_0X38 0x9038 /* ???? */ ++#define AGNX_GCR_BOACT 0x903c /* BO Active */ ++#define AGNX_GCR_BOINACT 0x9040 /* BO Inactive */ ++#define AGNX_GCR_BODYNA 0x9044 /* BO dynamic */ ++/* 802.11 mode(a,b,g) */ ++#define AGNX_GCR_DISCOVMOD 0x9048 /* discovery mode */ ++#define AGNX_GCR_NLISTANT 0x904c /* number of listening antenna */ ++#define AGNX_GCR_NACTIANT 0x9050 /* number of active antenna */ ++#define AGNX_GCR_NMEASANT 0x9054 /* number of measuring antenna */ ++#define AGNX_GCR_NCAPTANT 0x9058 /* number of capture antenna */ ++#define AGNX_GCR_THCAP11A 0x905c /* threshold capture 11a */ ++#define AGNX_GCR_THCAP11B 0x9060 /* threshold capture 11b */ ++#define AGNX_GCR_THCAPRX11A 0x9064 /* threshold capture rx 11a */ ++#define AGNX_GCR_THCAPRX11B 0x9068 /* threshold capture rx 11b */ ++#define AGNX_GCR_THLEVDRO 0x906c /* threshold level drop */ ++#define AGNX_GCR_GAINSET0 0x9070 /* Gainset 0 */ ++#define AGNX_GCR_GAINSET1 0x9074 /* Gainset 1 */ ++#define AGNX_GCR_GAINSET2 0x9078 /* Gainset 2 */ ++#define AGNX_GCR_MAXRXTIME11A 0x907c /* maximum rx time 11a */ ++#define AGNX_GCR_MAXRXTIME11B 0x9080 /* maximum rx time 11b */ ++#define AGNX_GCR_CORRTIME 0x9084 /* correction time */ ++/* reset the subsystem, 0 = disable, 1 = enable */ ++#define AGNX_GCR_RSTGCTL 0x9088 /* reset gain control */ ++/* channel receiving */ ++#define AGNX_GCR_RXCHANEL 0x908c /* receive channel */ ++#define AGNX_GCR_NOISE0 0x9090 /* Noise 0 */ ++#define AGNX_GCR_NOISE1 0x9094 /* Noise 1 */ ++#define AGNX_GCR_NOISE2 0x9098 /* Noise 2 */ ++#define AGNX_GCR_SIGHTH 0x909c /* Signal High Threshold */ ++#define AGNX_GCR_SIGLTH 0x90a0 /* Signal Low Threshold */ ++#define AGNX_GCR_CORRDROP 0x90a4 /* correction drop */ ++/* threshold of tertiay antenna */ ++#define AGNX_GCR_THCD 0x90a8 /* threshold? CD */ ++#define AGNX_GCR_THCS 0x90ac /* threshold? CS */ ++#define AGNX_GCR_MAXPOWDIFF 0x90b8 /* maximum power difference */ ++#define AGNX_GCR_TRACNT4 0x90ec /* Transition Count 4 */ ++#define AGNX_GCR_TRACNT5 0x90f0 /* transition count 5 */ ++#define AGNX_GCR_TRACNT6 0x90f4 /* transition count 6 */ ++#define AGNX_GCR_TRACNT7 0x90f8 /* transition coutn 7 */ ++#define AGNX_GCR_TESTBUS 0x911c /* test bus */ ++#define AGNX_GCR_CHAINNUM 0x9120 /* Number of Chains */ ++#define AGNX_GCR_ANTCFG 0x9124 /* Antenna Config */ ++#define AGNX_GCR_THJUMP 0x912c /* threhold jump */ ++#define AGNX_GCR_THPOWER 0x9130 /* threshold power */ ++#define AGNX_GCR_THPOWCLIP 0x9134 /* threshold power clip*/ ++#define AGNX_GCR_FORCECTLCLK 0x9138 /* Force Gain Control Clock */ ++#define AGNX_GCR_GAINSETWRITE 0x913c /* Gainset Write */ ++#define AGNX_GCR_THD0BTFEST 0x9140 /* threshold d0 b tf estimate */ ++#define AGNX_GCR_THRX11BPOWMIN 0x9144 /* threshold rx 11b power minimum */ ++#define AGNX_GCR_0X14c 0x914c /* ?? */ ++#define AGNX_GCR_0X150 0x9150 /* ?? */ ++#define AGNX_GCR_RXOVERIDE 0x9194 /* recieve override */ ++#define AGNX_GCR_WATCHDOG 0x91b0 /* watchdog timeout */ ++ ++ ++/* Spi Interface */ ++#define AGNX_SPI_BASE 0xdc00 ++#define AGNX_SPI_CFG 0xdc00 /* spi configuration */ ++/* Only accept 16 bits */ ++#define AGNX_SPI_WMSW 0xdc04 /* write most significant word */ ++/* Only accept 16 bits */ ++#define AGNX_SPI_WLSW 0xdc08 /* write least significant word */ ++#define AGNX_SPI_CTL 0xdc0c /* spi control */ ++#define AGNX_SPI_RMSW 0xdc10 /* read most significant word */ ++#define AGNX_SPI_RLSW 0xdc14 /* read least significant word */ ++/* SPI Control Mask */ ++#define SPI_READ_CTL 0x4000 /* read control */ ++#define SPI_BUSY_CTL 0x8000 /* busy control */ ++/* RF and synth chips in spi */ ++#define RF_CHIP0 0x400 ++#define RF_CHIP1 0x800 ++#define RF_CHIP2 0x1000 ++#define SYNTH_CHIP 0x2000 ++ ++/* Unknown register */ ++#define AGNX_UNKNOWN_BASE 0x7800 ++ ++/* FIXME MonitorGain */ ++#define AGNX_MONGCR_BASE 0x12000 ++ ++/* Gain Table */ ++#define AGNX_GAIN_TABLE 0x12400 ++ ++/* The initial FIR coefficient table */ ++#define AGNX_FIR_BASE 0x19804 ++ ++#define AGNX_ENGINE_LOOKUP_TBL 0x800 ++ ++/* eeprom commands */ ++#define EEPROM_CMD_NULL 0x0 /* NULL */ ++#define EEPROM_CMD_WRITE 0x2 /* write */ ++#define EEPROM_CMD_READ 0x3 /* read */ ++#define EEPROM_CMD_STATUSREAD 0x5 /* status register read */ ++#define EEPROM_CMD_WRITEENABLE 0x6 /* write enable */ ++#define EEPROM_CMD_CONFIGURE 0x7 /* configure */ ++ ++#define EEPROM_DATAFORCOFIGURE 0x6 /* ??? */ ++ ++/* eeprom address */ ++#define EEPROM_ADDR_SUBVID 0x0 /* Sub Vendor ID */ ++#define EEPROM_ADDR_SUBSID 0x2 /* Sub System ID */ ++#define EEPROM_ADDR_MACADDR 0x146 /* MAC Address */ ++#define EEPROM_ADDR_LOTYPE 0x14f /* LO type */ ++ ++struct agnx_eeprom { ++ u8 data; /* date */ ++ u16 address; /* address in EEPROM */ ++ u8 cmd; /* command, unknown, status */ ++} __attribute__((__packed__)); ++ ++#define AGNX_EEPROM_COMMAND_SHIFT 5 ++#define AGNX_EEPROM_COMMAND_STAT 0x01 ++ ++void disable_receiver(struct agnx_priv *priv); ++void enable_receiver(struct agnx_priv *priv); ++u8 read_from_eeprom(struct agnx_priv *priv, u16 address); ++void agnx_hw_init(struct agnx_priv *priv); ++int agnx_hw_reset(struct agnx_priv *priv); ++int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len); ++void agnx_set_bssid(struct agnx_priv *priv, u8 *bssid); ++void enable_power_saving(struct agnx_priv *priv); ++void disable_power_saving(struct agnx_priv *priv); ++void calibrate_antenna_period(unsigned long data); ++ ++#endif /* AGNX_PHY_H_ */ +--- /dev/null ++++ b/drivers/staging/agnx/rf.c +@@ -0,0 +1,894 @@ ++/** ++ * Airgo MIMO wireless driver ++ * ++ * Copyright (c) 2007 Li YanBo ++ ++ * Thanks for Jeff Williams do reverse engineer ++ * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin ++ ++ * 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; ++ */ ++ ++#include ++#include ++#include "agnx.h" ++#include "debug.h" ++#include "phy.h" ++#include "table.h" ++ ++/* FIXME! */ ++static inline void spi_write(void __iomem *region, u32 chip_ids, u32 sw, ++ u16 size, u32 control) ++{ ++ u32 reg; ++ u32 lsw = sw & 0xffff; /* lower 16 bits of sw*/ ++ u32 msw = sw >> 16; /* high 16 bits of sw */ ++ ++ /* FIXME Write Most Significant Word of the 32bit data to MSW */ ++ /* FIXME And Least Significant Word to LSW */ ++ iowrite32((lsw), region + AGNX_SPI_WLSW); ++ iowrite32((msw), region + AGNX_SPI_WMSW); ++ reg = chip_ids | size | control; ++ /* Write chip id(s), write size and busy control to Control Register */ ++ iowrite32((reg), region + AGNX_SPI_CTL); ++ /* Wait for Busy control to clear */ ++ spi_delay(); ++} ++ ++/* ++ * Write to SPI Synth register ++ */ ++static inline void spi_sy_write(void __iomem *region, u32 chip_ids, u32 sw) ++{ ++ /* FIXME the size 0x15 is a magic value*/ ++ spi_write(region, chip_ids, sw, 0x15, SPI_BUSY_CTL); ++} ++ ++/* ++ * Write to SPI RF register ++ */ ++static inline void spi_rf_write(void __iomem *region, u32 chip_ids, u32 sw) ++{ ++ /* FIXME the size 0xd is a magic value*/ ++ spi_write(region, chip_ids, sw, 0xd, SPI_BUSY_CTL); ++} /* spi_rf_write */ ++ ++/* ++ * Write to SPI with Read Control bit set ++ */ ++inline void spi_rc_write(void __iomem *region, u32 chip_ids, u32 sw) ++{ ++ /* FIXME the size 0xe5 is a magic value */ ++ spi_write(region, chip_ids, sw, 0xe5, SPI_BUSY_CTL|SPI_READ_CTL); ++} ++ ++/* Get the active chains's count */ ++static int get_active_chains(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int num = 0; ++ u32 reg; ++ AGNX_TRACE; ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x21); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ if (reg == 1) ++ num++; ++ ++ spi_rc_write(ctl, RF_CHIP1, 0x21); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ if (reg == 1) ++ num++; ++ ++ spi_rc_write(ctl, RF_CHIP2, 0x21); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ if (reg == 1) ++ num++; ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x26); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ if (0x33 != reg) ++ printk(KERN_WARNING PFX "Unmatched rf chips result\n"); ++ ++ return num; ++} /* get_active_chains */ ++ ++void rf_chips_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ int num; ++ AGNX_TRACE; ++ ++ if (priv->revid == 1) { ++ reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg); ++ } ++ ++ /* Set SPI clock speed to 200NS */ ++ reg = agnx_read32(ctl, AGNX_SPI_CFG); ++ reg &= ~0xF; ++ reg |= 0x3; ++ agnx_write32(ctl, AGNX_SPI_CFG, reg); ++ ++ /* Set SPI clock speed to 50NS */ ++ reg = agnx_read32(ctl, AGNX_SPI_CFG); ++ reg &= ~0xF; ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_SPI_CFG, reg); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1101); ++ ++ num = get_active_chains(priv); ++ printk(KERN_INFO PFX "Active chains are %d\n", num); ++ ++ reg = agnx_read32(ctl, AGNX_SPI_CFG); ++ reg &= ~0xF; ++ agnx_write32(ctl, AGNX_SPI_CFG, reg); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1908); ++} /* rf_chips_init */ ++ ++ ++static u32 channel_tbl[15][9] = { ++ {0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ++ {1, 0x00, 0x00, 0x624, 0x00, 0x1a4, 0x28, 0x00, 0x1e}, ++ {2, 0x00, 0x00, 0x615, 0x00, 0x1ae, 0x28, 0x00, 0x1e}, ++ {3, 0x00, 0x00, 0x61a, 0x00, 0x1ae, 0x28, 0x00, 0x1e}, ++ {4, 0x00, 0x00, 0x61f, 0x00, 0x1ae, 0x28, 0x00, 0x1e}, ++ {5, 0x00, 0x00, 0x624, 0x00, 0x1ae, 0x28, 0x00, 0x1e}, ++ {6, 0x00, 0x00, 0x61f, 0x00, 0x1b3, 0x28, 0x00, 0x1e}, ++ {7, 0x00, 0x00, 0x624, 0x00, 0x1b3, 0x28, 0x00, 0x1e}, ++ {8, 0x00, 0x00, 0x629, 0x00, 0x1b3, 0x28, 0x00, 0x1e}, ++ {9, 0x00, 0x00, 0x624, 0x00, 0x1b8, 0x28, 0x00, 0x1e}, ++ {10, 0x00, 0x00, 0x629, 0x00, 0x1b8, 0x28, 0x00, 0x1e}, ++ {11, 0x00, 0x00, 0x62e, 0x00, 0x1b8, 0x28, 0x00, 0x1e}, ++ {12, 0x00, 0x00, 0x633, 0x00, 0x1b8, 0x28, 0x00, 0x1e}, ++ {13, 0x00, 0x00, 0x628, 0x00, 0x1b8, 0x28, 0x00, 0x1e}, ++ {14, 0x00, 0x00, 0x644, 0x00, 0x1b8, 0x28, 0x00, 0x1e}, ++}; ++ ++ ++static inline void ++channel_tbl_write(struct agnx_priv *priv, unsigned int channel, unsigned int reg_num) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ reg = channel_tbl[channel][reg_num]; ++ reg <<= 4; ++ reg |= reg_num; ++ spi_sy_write(ctl, SYNTH_CHIP, reg); ++} ++ ++static void synth_freq_set(struct agnx_priv *priv, unsigned int channel) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201); ++ ++ /* Set the Clock bits to 50NS */ ++ reg = agnx_read32(ctl, AGNX_SPI_CFG); ++ reg &= ~0xF; ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_SPI_CFG, reg); ++ ++ /* Write 0x00c0 to LSW and 0x3 to MSW of Synth Chip */ ++ spi_sy_write(ctl, SYNTH_CHIP, 0x300c0); ++ ++ spi_sy_write(ctl, SYNTH_CHIP, 0x32); ++ ++ /* # Write to Register 1 on the Synth Chip */ ++ channel_tbl_write(priv, channel, 1); ++ /* # Write to Register 3 on the Synth Chip */ ++ channel_tbl_write(priv, channel, 3); ++ /* # Write to Register 6 on the Synth Chip */ ++ channel_tbl_write(priv, channel, 6); ++ /* # Write to Register 5 on the Synth Chip */ ++ channel_tbl_write(priv, channel, 5); ++ /* # Write to register 8 on the Synth Chip */ ++ channel_tbl_write(priv, channel, 8); ++ ++ /* FIXME Clear the clock bits */ ++ reg = agnx_read32(ctl, AGNX_SPI_CFG); ++ reg &= ~0xf; ++ agnx_write32(ctl, AGNX_SPI_CFG, reg); ++} /* synth_chip_init */ ++ ++ ++static void antenna_init(struct agnx_priv *priv, int num_antenna) ++{ ++ void __iomem *ctl = priv->ctl; ++ ++ switch (num_antenna) { ++ case 1: ++ agnx_write32(ctl, AGNX_GCR_NLISTANT, 1); ++ agnx_write32(ctl, AGNX_GCR_NMEASANT, 1); ++ agnx_write32(ctl, AGNX_GCR_NACTIANT, 1); ++ agnx_write32(ctl, AGNX_GCR_NCAPTANT, 1); ++ ++ agnx_write32(ctl, AGNX_GCR_ANTCFG, 7); ++ agnx_write32(ctl, AGNX_GCR_BOACT, 34); ++ agnx_write32(ctl, AGNX_GCR_BOINACT, 34); ++ agnx_write32(ctl, AGNX_GCR_BODYNA, 30); ++ ++ agnx_write32(ctl, AGNX_GCR_THD0A, 125); ++ agnx_write32(ctl, AGNX_GCR_THD0AL, 100); ++ agnx_write32(ctl, AGNX_GCR_THD0B, 90); ++ ++ agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 80); ++ agnx_write32(ctl, AGNX_GCR_SIGHTH, 100); ++ agnx_write32(ctl, AGNX_GCR_SIGLTH, 16); ++ break; ++ case 2: ++ agnx_write32(ctl, AGNX_GCR_NLISTANT, 2); ++ agnx_write32(ctl, AGNX_GCR_NMEASANT, 2); ++ agnx_write32(ctl, AGNX_GCR_NACTIANT, 2); ++ agnx_write32(ctl, AGNX_GCR_NCAPTANT, 2); ++ agnx_write32(ctl, AGNX_GCR_ANTCFG, 15); ++ agnx_write32(ctl, AGNX_GCR_BOACT, 36); ++ agnx_write32(ctl, AGNX_GCR_BOINACT, 36); ++ agnx_write32(ctl, AGNX_GCR_BODYNA, 32); ++ agnx_write32(ctl, AGNX_GCR_THD0A, 120); ++ agnx_write32(ctl, AGNX_GCR_THD0AL, 100); ++ agnx_write32(ctl, AGNX_GCR_THD0B, 80); ++ agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70); ++ agnx_write32(ctl, AGNX_GCR_SIGHTH, 100); ++ agnx_write32(ctl, AGNX_GCR_SIGLTH, 32); ++ break; ++ case 3: ++ agnx_write32(ctl, AGNX_GCR_NLISTANT, 3); ++ agnx_write32(ctl, AGNX_GCR_NMEASANT, 3); ++ agnx_write32(ctl, AGNX_GCR_NACTIANT, 3); ++ agnx_write32(ctl, AGNX_GCR_NCAPTANT, 3); ++ agnx_write32(ctl, AGNX_GCR_ANTCFG, 31); ++ agnx_write32(ctl, AGNX_GCR_BOACT, 36); ++ agnx_write32(ctl, AGNX_GCR_BOINACT, 36); ++ agnx_write32(ctl, AGNX_GCR_BODYNA, 32); ++ agnx_write32(ctl, AGNX_GCR_THD0A, 100); ++ agnx_write32(ctl, AGNX_GCR_THD0AL, 100); ++ agnx_write32(ctl, AGNX_GCR_THD0B, 70); ++ agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70); ++ agnx_write32(ctl, AGNX_GCR_SIGHTH, 100); ++ agnx_write32(ctl, AGNX_GCR_SIGLTH, 48); ++// agnx_write32(ctl, AGNX_GCR_SIGLTH, 16); ++ break; ++ default: ++ printk(KERN_WARNING PFX "Unknow antenna number\n"); ++ } ++} /* antenna_init */ ++ ++static void chain_update(struct agnx_priv *priv, u32 chain) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x20); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ ++ if (reg == 0x4) ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000); ++ else if (reg != 0x0) ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000); ++ else { ++ if (chain == 3 || chain == 6) { ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ } else if (chain == 2 || chain == 4) { ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000); ++ spi_rf_write(ctl, RF_CHIP2, 0x1005); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x824); ++ } else if (chain == 1) { ++ spi_rf_write(ctl, RF_CHIP0, reg|0x1000); ++ spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1004); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xc36); ++ } ++ } ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x22); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ ++ switch (reg) { ++ case 0: ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005); ++ break; ++ case 1: ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201); ++ break; ++ case 2: ++ if (chain == 6 || chain == 4) { ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1202); ++ spi_rf_write(ctl, RF_CHIP2, 0x1005); ++ } else if (chain < 3) { ++ spi_rf_write(ctl, RF_CHIP0, 0x1202); ++ spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1005); ++ } ++ break; ++ default: ++ if (chain == 3) { ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203); ++ spi_rf_write(ctl, RF_CHIP2, 0x1201); ++ } else if (chain == 2) { ++ spi_rf_write(ctl, RF_CHIP0, 0x1203); ++ spi_rf_write(ctl, RF_CHIP2, 0x1200); ++ spi_rf_write(ctl, RF_CHIP1, 0x1201); ++ } else if (chain == 1) { ++ spi_rf_write(ctl, RF_CHIP0, 0x1203); ++ spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1200); ++ } else if (chain == 4) { ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203); ++ spi_rf_write(ctl, RF_CHIP2, 0x1201); ++ } else { ++ spi_rf_write(ctl, RF_CHIP0, 0x1203); ++ spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1201); ++ } ++ } ++} /* chain_update */ ++ ++static void antenna_config(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ /* Write 0x0 to the TX Management Control Register Enable bit */ ++ reg = agnx_read32(ctl, AGNX_TXM_CTL); ++ reg &= ~0x1; ++ agnx_write32(ctl, AGNX_TXM_CTL, reg); ++ ++ /* FIXME */ ++ /* Set initial value based on number of Antennae */ ++ antenna_init(priv, 3); ++ ++ /* FIXME Update Power Templates for current valid Stations */ ++ /* sta_power_init(priv, 0);*/ ++ ++ /* FIXME the number of chains should get from eeprom*/ ++ chain_update(priv, AGNX_CHAINS_MAX); ++} /* antenna_config */ ++ ++void calibrate_oscillator(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201); ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET1); ++ reg |= 0x10; ++ agnx_write32(ctl, AGNX_GCR_GAINSET1, reg); ++ ++ agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 1); ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 1); ++ ++ agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff); ++ ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27); ++ /* (Residual DC Calibration) to Calibration Mode */ ++ agnx_write32(ctl, AGNX_ACI_MODE, 0x2); ++ ++ spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1004); ++ agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff); ++ /* (TX LO Calibration) to Calibration Mode */ ++ agnx_write32(ctl, AGNX_ACI_MODE, 0x4); ++ ++ do { ++ u32 reg1, reg2, reg3; ++ /* Enable Power Saving Control */ ++ enable_power_saving(priv); ++ /* Save the following registers to restore */ ++ reg1 = ioread32(ctl + 0x11000); ++ reg2 = ioread32(ctl + 0xec50); ++ reg3 = ioread32(ctl + 0xec54); ++ wmb(); ++ ++ agnx_write32(ctl, 0x11000, 0xcfdf); ++ agnx_write32(ctl, 0xec50, 0x70); ++ /* Restore the registers */ ++ agnx_write32(ctl, 0x11000, reg1); ++ agnx_write32(ctl, 0xec50, reg2); ++ agnx_write32(ctl, 0xec54, reg3); ++ /* Disable Power Saving Control */ ++ disable_power_saving(priv); ++ } while (0); ++ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0); ++} /* calibrate_oscillator */ ++ ++ ++static void radio_channel_set(struct agnx_priv *priv, unsigned int channel) ++{ ++ void __iomem *ctl = priv->ctl; ++ unsigned int freq = priv->band.channels[channel - 1].center_freq; ++ u32 reg; ++ AGNX_TRACE; ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201); ++ /* Set SPI Clock to 50 Ns */ ++ reg = agnx_read32(ctl, AGNX_SPI_CFG); ++ reg &= ~0xF; ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_SPI_CFG, reg); ++ ++ /* Clear the Disable Tx interrupt bit in Interrupt Mask */ ++/* reg = agnx_read32(ctl, AGNX_INT_MASK); */ ++/* reg &= ~IRQ_TX_DISABLE; */ ++/* agnx_write32(ctl, AGNX_INT_MASK, reg); */ ++ ++ /* Band Selection */ ++ reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg); ++ ++ /* FIXME Set the SiLabs Chip Frequency */ ++ synth_freq_set(priv, channel); ++ ++ reg = agnx_read32(ctl, AGNX_PM_SOFTRST); ++ reg |= 0x80100030; ++ agnx_write32(ctl, AGNX_PM_SOFTRST, reg); ++ reg = agnx_read32(ctl, AGNX_PM_PLLCTL); ++ reg |= 0x20009; ++ agnx_write32(ctl, AGNX_PM_PLLCTL, reg); ++ ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1100); ++ ++ /* Load the MonitorGain Table */ ++ monitor_gain_table_init(priv); ++ ++ /* Load the TX Fir table */ ++ tx_fir_table_init(priv); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg |= 0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ ++ spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x22); ++ udelay(80); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ ++ ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff); ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); ++ ++ reg = agnx_read32(ctl, 0xec50); ++ reg |= 0x4f; ++ agnx_write32(ctl, 0xec50, reg); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201); ++ agnx_write32(ctl, 0x11008, 0x1); ++ agnx_write32(ctl, 0x1100c, 0x0); ++ agnx_write32(ctl, 0x11008, 0x0); ++ agnx_write32(ctl, 0xec50, 0xc); ++ ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ agnx_write32(ctl, 0x11010, 0x6e); ++ agnx_write32(ctl, 0x11014, 0x6c); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201); ++ ++ /* Calibrate the Antenna */ ++ /* antenna_calibrate(priv); */ ++ /* Calibrate the TxLocalOscillator */ ++ calibrate_oscillator(priv); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PMCTL); ++ reg &= ~0x8; ++ agnx_write32(ctl, AGNX_PM_PMCTL, reg); ++ agnx_write32(ctl, AGNX_GCR_GAININIT, 0xa); ++ agnx_write32(ctl, AGNX_GCR_THCD, 0x0); ++ ++ agnx_write32(ctl, 0x11018, 0xb); ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0); ++ ++ /* Write Frequency to Gain Control Channel */ ++ agnx_write32(ctl, AGNX_GCR_RXCHANEL, freq); ++ /* Write 0x140000/Freq to 0x9c08 */ ++ reg = 0x140000/freq; ++ agnx_write32(ctl, 0x9c08, reg); ++ ++ reg = agnx_read32(ctl, AGNX_PM_SOFTRST); ++ reg &= ~0x80100030; ++ agnx_write32(ctl, AGNX_PM_SOFTRST, reg); ++ ++ reg = agnx_read32(ctl, AGNX_PM_PLLCTL); ++ reg &= ~0x20009; ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_PM_PLLCTL, reg); ++ ++ agnx_write32(ctl, AGNX_ACI_MODE, 0x0); ++ ++/* FIXME According to Number of Chains: */ ++ ++/* 1. 1: */ ++/* 1. Write 0x1203 to RF Chip 0 */ ++/* 2. Write 0x1200 to RF Chips 1 +2 */ ++/* 2. 2: */ ++/* 1. Write 0x1203 to RF Chip 0 */ ++/* 2. Write 0x1200 to RF Chip 2 */ ++/* 3. Write 0x1201 to RF Chip 1 */ ++/* 3. 3: */ ++/* 1. Write 0x1203 to RF Chip 0 */ ++/* 2. Write 0x1201 to RF Chip 1 + 2 */ ++/* 4. 4: */ ++/* 1. Write 0x1203 to RF Chip 0 + 1 */ ++/* 2. Write 0x1200 to RF Chip 2 */ ++ ++/* 5. 6: */ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203); ++ spi_rf_write(ctl, RF_CHIP2, 0x1201); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ ++ /* FIXME Set the Disable Tx interrupt bit in Interrupt Mask ++ (Or 0x20000 to Interrupt Mask) */ ++/* reg = agnx_read32(ctl, AGNX_INT_MASK); */ ++/* reg |= IRQ_TX_DISABLE; */ ++/* agnx_write32(ctl, AGNX_INT_MASK, reg); */ ++ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0); ++ ++ /* Configure the Antenna */ ++ antenna_config(priv); ++ ++ /* Write 0x0 to Discovery Mode Enable detect G, B, A packet? */ ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0); ++ ++ reg = agnx_read32(ctl, AGNX_RXM_REQRATE); ++ reg |= 0x80000000; ++ agnx_write32(ctl, AGNX_RXM_REQRATE, reg); ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0); ++ ++ /* enable radio on and the power LED */ ++ reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT); ++ reg &= ~0x1; ++ reg |= 0x2; ++ agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg); ++ ++ reg = agnx_read32(ctl, AGNX_TXM_CTL); ++ reg |= 0x1; ++ agnx_write32(ctl, AGNX_TXM_CTL, reg); ++} /* radio_channel_set */ ++ ++static void base_band_filter_calibrate(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1001); ++ agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x0); ++ spi_rc_write(ctl, RF_CHIP0, 0x27); ++ spi_rc_write(ctl, RF_CHIP1, 0x27); ++ spi_rc_write(ctl, RF_CHIP2, 0x27); ++ agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x1); ++} ++ ++static void print_offset(struct agnx_priv *priv, u32 chain) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 offset; ++ ++ iowrite32((chain), ctl + AGNX_ACI_SELCHAIN); ++ udelay(10); ++ offset = (ioread32(ctl + AGNX_ACI_OFFSET)); ++ printk(PFX "Chain is 0x%x, Offset is 0x%x\n", chain, offset); ++} ++ ++void print_offsets(struct agnx_priv *priv) ++{ ++ print_offset(priv, 0); ++ print_offset(priv, 4); ++ print_offset(priv, 1); ++ print_offset(priv, 5); ++ print_offset(priv, 2); ++ print_offset(priv, 6); ++} ++ ++ ++struct chains { ++ u32 cali; /* calibrate value*/ ++ ++#define NEED_CALIBRATE 0 ++#define SUCCESS_CALIBRATE 1 ++ int status; ++}; ++ ++static void chain_calibrate(struct agnx_priv *priv, struct chains *chains, ++ unsigned int num) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 calibra = chains[num].cali; ++ ++ if (num < 3) ++ calibra |= 0x1400; ++ else ++ calibra |= 0x1500; ++ ++ switch (num) { ++ case 0: ++ case 4: ++ spi_rf_write(ctl, RF_CHIP0, calibra); ++ break; ++ case 1: ++ case 5: ++ spi_rf_write(ctl, RF_CHIP1, calibra); ++ break; ++ case 2: ++ case 6: ++ spi_rf_write(ctl, RF_CHIP2, calibra); ++ break; ++ default: ++ BUG(); ++ } ++} /* chain_calibrate */ ++ ++ ++static void inline get_calibrete_value(struct agnx_priv *priv, struct chains *chains, ++ unsigned int num) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 offset; ++ ++ iowrite32((num), ctl + AGNX_ACI_SELCHAIN); ++ /* FIXME */ ++ udelay(10); ++ offset = (ioread32(ctl + AGNX_ACI_OFFSET)); ++ ++ if (offset < 0xf) { ++ chains[num].status = SUCCESS_CALIBRATE; ++ return; ++ } ++ ++ if (num == 0 || num == 1 || num == 2) { ++ if ( 0 == chains[num].cali) ++ chains[num].cali = 0xff; ++ else ++ chains[num].cali--; ++ } else ++ chains[num].cali++; ++ ++ chains[num].status = NEED_CALIBRATE; ++} ++ ++static inline void calibra_delay(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ unsigned int i = 100; ++ ++ wmb(); ++ while (i--) { ++ reg = (ioread32(ctl + AGNX_ACI_STATUS)); ++ if (reg == 0x4000) ++ break; ++ udelay(10); ++ } ++ if (!i) ++ printk(PFX "calibration failed\n"); ++} ++ ++void do_calibration(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ struct chains chains[7]; ++ unsigned int i, j; ++ AGNX_TRACE; ++ ++ for (i = 0; i < 7; i++) { ++ if (i == 3) ++ continue; ++ ++ chains[i].cali = 0x7f; ++ chains[i].status = NEED_CALIBRATE; ++ } ++ ++ /* FIXME 0x300 is a magic number */ ++ for (j = 0; j < 0x300; j++) { ++ if (chains[0].status == SUCCESS_CALIBRATE && ++ chains[1].status == SUCCESS_CALIBRATE && ++ chains[2].status == SUCCESS_CALIBRATE && ++ chains[4].status == SUCCESS_CALIBRATE && ++ chains[5].status == SUCCESS_CALIBRATE && ++ chains[6].status == SUCCESS_CALIBRATE) ++ break; ++ ++ /* Attention, there is no chain 3 */ ++ for (i = 0; i < 7; i++) { ++ if (i == 3) ++ continue; ++ if (chains[i].status == NEED_CALIBRATE) ++ chain_calibrate(priv, chains, i); ++ } ++ /* Write 0x1 to Calibration Measure */ ++ iowrite32((0x1), ctl + AGNX_ACI_MEASURE); ++ calibra_delay(priv); ++ ++ for (i = 0; i < 7; i++) { ++ if (i == 3) ++ continue; ++ ++ get_calibrete_value(priv, chains, i); ++ } ++ } ++ printk(PFX "Clibrate times is %d\n", j); ++ print_offsets(priv); ++} /* do_calibration */ ++ ++void antenna_calibrate(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ AGNX_TRACE; ++ ++ agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3); ++ agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3); ++ ++ agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f); ++ agnx_write32(ctl, AGNX_GCR_BOACT, 0x24); ++ agnx_write32(ctl, AGNX_GCR_BOINACT, 0x24); ++ agnx_write32(ctl, AGNX_GCR_BODYNA, 0x20); ++ agnx_write32(ctl, AGNX_GCR_THD0A, 0x64); ++ agnx_write32(ctl, AGNX_GCR_THD0AL, 0x64); ++ agnx_write32(ctl, AGNX_GCR_THD0B, 0x46); ++ agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c); ++ agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x64); ++ agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x30); ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x20); ++ /* Fixme */ ++ udelay(80); ++ /* 1. Should read 0x0 */ ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ if (0x0 != reg) ++ printk(KERN_WARNING PFX "Unmatched rf chips result\n"); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000); ++ ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ ++ spi_rc_write(ctl, RF_CHIP0, 0x22); ++ udelay(80); ++ reg = agnx_read32(ctl, AGNX_SPI_RLSW); ++ if (0x0 != reg) ++ printk(KERN_WARNING PFX "Unmatched rf chips result\n"); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005); ++ ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1); ++ agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0); ++ ++ reg = agnx_read32(ctl, AGNX_PM_SOFTRST); ++ reg |= 0x1c000032; ++ agnx_write32(ctl, AGNX_PM_SOFTRST, reg); ++ reg = agnx_read32(ctl, AGNX_PM_PLLCTL); ++ reg |= 0x0003f07; ++ agnx_write32(ctl, AGNX_PM_PLLCTL, reg); ++ ++ reg = agnx_read32(ctl, 0xec50); ++ reg |= 0x40; ++ agnx_write32(ctl, 0xec50, reg); ++ ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff8); ++ agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3); ++ ++ agnx_write32(ctl, AGNX_GCR_CHAINNUM, 0x6); ++ agnx_write32(ctl, 0x19874, 0x0); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700); ++ ++ /* Calibrate the BaseBandFilter */ ++ base_band_filter_calibrate(priv); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002); ++ ++ agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d); ++ agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d); ++ agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d); ++ agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1); ++ ++ agnx_write32(ctl, AGNX_ACI_MODE, 0x1); ++ agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff); ++ ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27); ++ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500); ++ ++ /* Measure Calibration */ ++ agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1); ++ calibra_delay(priv); ++ ++ /* do calibration */ ++ do_calibration(priv); ++ ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27); ++ agnx_write32(ctl, AGNX_ACI_LEN, 0xf); ++ ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET0); ++ reg &= 0xf; ++ agnx_write32(ctl, AGNX_GCR_GAINSET0, reg); ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET1); ++ reg &= 0xf; ++ agnx_write32(ctl, AGNX_GCR_GAINSET1, reg); ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET2); ++ reg &= 0xf; ++ agnx_write32(ctl, AGNX_GCR_GAINSET2, reg); ++ ++ agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0); ++ disable_receiver(priv); ++} /* antenna_calibrate */ ++ ++void __antenna_calibrate(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ /* Calibrate the BaseBandFilter */ ++ /* base_band_filter_calibrate(priv); */ ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002); ++ ++ ++ agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d); ++ agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d); ++ agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d); ++ ++ agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1); ++ ++ agnx_write32(ctl, AGNX_ACI_MODE, 0x1); ++ agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff); ++ ++ ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400); ++ spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500); ++ /* Measure Calibration */ ++ agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1); ++ calibra_delay(priv); ++ do_calibration(priv); ++ agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0); ++ ++ agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21); ++ agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27); ++ ++ agnx_write32(ctl, AGNX_ACI_LEN, 0xf); ++ ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET0); ++ reg &= 0xf; ++ agnx_write32(ctl, AGNX_GCR_GAINSET0, reg); ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET1); ++ reg &= 0xf; ++ agnx_write32(ctl, AGNX_GCR_GAINSET1, reg); ++ reg = agnx_read32(ctl, AGNX_GCR_GAINSET2); ++ reg &= 0xf; ++ agnx_write32(ctl, AGNX_GCR_GAINSET2, reg); ++ ++ ++ agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0); ++ ++ /* Write 0x3 Gain Control Discovery Mode */ ++ enable_receiver(priv); ++} ++ ++int agnx_set_channel(struct agnx_priv *priv, unsigned int channel) ++{ ++ AGNX_TRACE; ++ ++ printk(KERN_ERR PFX "Channel is %d %s\n", channel, __func__); ++ radio_channel_set(priv, channel); ++ return 0; ++} +--- /dev/null ++++ b/drivers/staging/agnx/sta.c +@@ -0,0 +1,219 @@ ++#include ++#include ++#include "phy.h" ++#include "sta.h" ++#include "debug.h" ++ ++void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id) ++{ ++ void __iomem *ctl = priv->ctl; ++ ++ reglo &= 0xFFFF; ++ reglo |= 0x30000000; ++ reglo |= 0x40000000; /* Set status busy */ ++ reglo |= sta_id << 16; ++ ++ iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG); ++ iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH); ++ iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW); ++ ++ reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH); ++ reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW); ++ printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo); ++} ++ ++void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reghi, reglo; ++ ++ if (!is_valid_ether_addr(mac_addr)) ++ printk(KERN_WARNING PFX "Update hash table: Invalid hwaddr!\n"); ++ ++ reghi = mac_addr[0] << 24 | mac_addr[1] << 16 | mac_addr[2] << 8 | mac_addr[3]; ++ reglo = mac_addr[4] << 8 | mac_addr[5]; ++ reglo |= 0x10000000; /* Set hash commmand */ ++ reglo |= 0x40000000; /* Set status busy */ ++ reglo |= sta_id << 16; ++ ++ iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG); ++ iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH); ++ iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW); ++ ++ reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW); ++ if (!(reglo & 0x80000000)) ++ printk(KERN_WARNING PFX "Update hash table failed\n"); ++} ++ ++void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id) ++{ ++ void __iomem *ctl = priv->ctl; ++ ++ reglo &= 0xFFFF; ++ reglo |= 0x20000000; ++ reglo |= 0x40000000; /* Set status busy */ ++ reglo |= sta_id << 16; ++ ++ iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG); ++ iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH); ++ iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW); ++ reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH); ++ ++ reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW); ++ printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo); ++ ++} ++ ++void hash_dump(struct agnx_priv *priv, u8 sta_id) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reghi, reglo; ++ ++ reglo = 0x0; /* dump command */ ++ reglo|= 0x40000000; /* status bit */ ++ iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW); ++ iowrite32(sta_id << 16, ctl + AGNX_RXM_HASH_DUMP_DATA); ++ ++ udelay(80); ++ ++ reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH); ++ reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW); ++ printk(PFX "hash cmd are : %.8x%.8x\n", reghi, reglo); ++ reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_FLAG); ++ printk(PFX "hash flag is : %.8x\n", reghi); ++ reghi = ioread32(ctl + AGNX_RXM_HASH_DUMP_MST); ++ reglo = ioread32(ctl + AGNX_RXM_HASH_DUMP_LST); ++ printk(PFX "hash dump mst lst: %.8x%.8x\n", reghi, reglo); ++ reghi = ioread32(ctl + AGNX_RXM_HASH_DUMP_DATA); ++ printk(PFX "hash dump data: %.8x\n", reghi); ++} ++ ++void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx) ++{ ++ void __iomem *ctl = priv->ctl; ++ memcpy_fromio(power, ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx, ++ sizeof(*power)); ++} ++ ++inline void ++set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx) ++{ ++ void __iomem *ctl = priv->ctl; ++ /* FIXME 2. Write Template to offset + station number */ ++ memcpy_toio(ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx, ++ power, sizeof(*power)); ++} ++ ++ ++void get_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq, ++ unsigned int sta_idx, unsigned int wq_idx) ++{ ++ void __iomem *data = priv->data; ++ memcpy_fromio(tx_wq, data + AGNX_PDU_TX_WQ + sizeof(*tx_wq) * STA_TX_WQ_NUM * sta_idx + ++ sizeof(*tx_wq) * wq_idx, sizeof(*tx_wq)); ++ ++} ++ ++inline void set_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq, ++ unsigned int sta_idx, unsigned int wq_idx) ++{ ++ void __iomem *data = priv->data; ++ memcpy_toio(data + AGNX_PDU_TX_WQ + sizeof(*tx_wq) * STA_TX_WQ_NUM * sta_idx + ++ sizeof(*tx_wq) * wq_idx, tx_wq, sizeof(*tx_wq)); ++} ++ ++ ++void get_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx) ++{ ++ void __iomem *data = priv->data; ++ ++ memcpy_fromio(sta, data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx, ++ sizeof(*sta)); ++} ++ ++inline void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx) ++{ ++ void __iomem *data = priv->data; ++ ++ memcpy_toio(data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx, ++ sta, sizeof(*sta)); ++} ++ ++/* FIXME */ ++void sta_power_init(struct agnx_priv *priv, unsigned int sta_idx) ++{ ++ struct agnx_sta_power power; ++ u32 reg; ++ AGNX_TRACE; ++ ++ memset(&power, 0, sizeof(power)); ++ reg = agnx_set_bits(EDCF, EDCF_SHIFT, 0x1); ++ power.reg = cpu_to_le32(reg); ++ set_sta_power(priv, &power, sta_idx); ++ udelay(40); ++} /* add_power_template */ ++ ++ ++/* @num: The #number of station that is visible to the card */ ++static void sta_tx_workqueue_init(struct agnx_priv *priv, unsigned int sta_idx) ++{ ++ struct agnx_sta_tx_wq tx_wq; ++ u32 reg; ++ unsigned int i; ++ ++ memset(&tx_wq, 0, sizeof(tx_wq)); ++ ++ reg = agnx_set_bits(WORK_QUEUE_VALID, WORK_QUEUE_VALID_SHIFT, 1); ++ reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 1); ++// reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 0); ++ tx_wq.reg2 |= cpu_to_le32(reg); ++ ++ /* Suppose all 8 traffic class are used */ ++ for (i = 0; i < STA_TX_WQ_NUM; i++) ++ set_sta_tx_wq(priv, &tx_wq, sta_idx, i); ++} /* sta_tx_workqueue_init */ ++ ++ ++static void sta_traffic_init(struct agnx_sta_traffic *traffic) ++{ ++ u32 reg; ++ memset(traffic, 0, sizeof(*traffic)); ++ ++ reg = agnx_set_bits(NEW_PACKET, NEW_PACKET_SHIFT, 1); ++ reg |= agnx_set_bits(TRAFFIC_VALID, TRAFFIC_VALID_SHIFT, 1); ++// reg |= agnx_set_bits(TRAFFIC_ACK_TYPE, TRAFFIC_ACK_TYPE_SHIFT, 1); ++ traffic->reg0 = cpu_to_le32(reg); ++ ++ /* 3. setting RX Sequence Number to 4095 */ ++ reg = agnx_set_bits(RX_SEQUENCE_NUM, RX_SEQUENCE_NUM_SHIFT, 4095); ++ traffic->reg1 = cpu_to_le32(reg); ++} ++ ++ ++/* @num: The #number of station that is visible to the card */ ++void sta_init(struct agnx_priv *priv, unsigned int sta_idx) ++{ ++ /* FIXME the length of sta is 256 bytes Is that ++ * dangerous to stack overflow? */ ++ struct agnx_sta sta; ++ u32 reg; ++ int i; ++ ++ memset(&sta, 0, sizeof(sta)); ++ /* Set valid to 1 */ ++ reg = agnx_set_bits(STATION_VALID, STATION_VALID_SHIFT, 1); ++ /* Set Enable Concatenation to 0 (?) */ ++ reg |= agnx_set_bits(ENABLE_CONCATENATION, ENABLE_CONCATENATION_SHIFT, 0); ++ /* Set Enable Decompression to 0 (?) */ ++ reg |= agnx_set_bits(ENABLE_DECOMPRESSION, ENABLE_DECOMPRESSION_SHIFT, 0); ++ sta.reg = cpu_to_le32(reg); ++ ++ /* Initialize each of the Traffic Class Structures by: */ ++ for (i = 0; i < 8; i++) ++ sta_traffic_init(sta.traffic + i); ++ ++ set_sta(priv, &sta, sta_idx); ++ sta_tx_workqueue_init(priv, sta_idx); ++} /* sta_descriptor_init */ ++ ++ +--- /dev/null ++++ b/drivers/staging/agnx/sta.h +@@ -0,0 +1,222 @@ ++#ifndef AGNX_STA_H_ ++#define AGNX_STA_H_ ++ ++#define STA_TX_WQ_NUM 8 /* The number of TX workqueue one STA has */ ++ ++struct agnx_hash_cmd { ++ __be32 cmdhi; ++#define MACLO 0xFFFF0000 ++#define MACLO_SHIFT 16 ++#define STA_ID 0x0000FFF0 ++#define STA_ID_SHIFT 4 ++#define CMD 0x0000000C ++#define CMD_SHIFT 2 ++#define STATUS 0x00000002 ++#define STATUS_SHIFT 1 ++#define PASS 0x00000001 ++#define PASS_SHIFT 1 ++ __be32 cmdlo; ++}__attribute__((__packed__)); ++ ++ ++/* ++ * Station Power Template ++ * FIXME Just for agn100 yet ++ */ ++struct agnx_sta_power { ++ __le32 reg; ++#define SIGNAL 0x000000FF /* signal */ ++#define SIGNAL_SHIFT 0 ++#define RATE 0x00000F00 ++#define RATE_SHIFT 8 ++#define TIFS 0x00001000 ++#define TIFS_SHIFT 12 ++#define EDCF 0x00002000 ++#define EDCF_SHIFT 13 ++#define CHANNEL_BOND 0x00004000 ++#define CHANNEL_BOND_SHIFT 14 ++#define PHY_MODE 0x00038000 ++#define PHY_MODE_SHIFT 15 ++#define POWER_LEVEL 0x007C0000 ++#define POWER_LEVEL_SHIFT 18 ++#define NUM_TRANSMITTERS 0x00800000 ++#define NUM_TRANSMITTERS_SHIFT 23 ++} __attribute__((__packed__)); ++ ++/* ++ * TX Workqueue Descriptor ++ */ ++struct agnx_sta_tx_wq { ++ __le32 reg0; ++#define HEAD_POINTER_LOW 0xFF000000 /* Head pointer low */ ++#define HEAD_POINTER_LOW_SHIFT 24 ++#define TAIL_POINTER 0x00FFFFFF /* Tail pointer */ ++#define TAIL_POINTER_SHIFT 0 ++ ++ __le32 reg3; ++#define ACK_POINTER_LOW 0xFFFF0000 /* ACK pointer low */ ++#define ACK_POINTER_LOW_SHIFT 16 ++#define HEAD_POINTER_HIGH 0x0000FFFF /* Head pointer high */ ++#define HEAD_POINTER_HIGH_SHIFT 0 ++ ++ __le32 reg1; ++/* ACK timeout tail packet count */ ++#define ACK_TIMOUT_TAIL_PACK_CNT 0xFFF00000 ++#define ACK_TIMOUT_TAIL_PACK_CNT_SHIFT 20 ++/* Head timeout tail packet count */ ++#define HEAD_TIMOUT_TAIL_PACK_CNT 0x000FFF00 ++#define HEAD_TIMOUT_TAIL_PACK_CNT_SHIFT 8 ++#define ACK_POINTER_HIGH 0x000000FF /* ACK pointer high */ ++#define ACK_POINTER_HIGH_SHIFT 0 ++ ++ __le32 reg2; ++#define WORK_QUEUE_VALID 0x80000000 /* valid */ ++#define WORK_QUEUE_VALID_SHIFT 31 ++#define WORK_QUEUE_ACK_TYPE 0x40000000 /* ACK type */ ++#define WORK_QUEUE_ACK_TYPE_SHIFT 30 ++/* Head timeout window limit fragmentation count */ ++#define HEAD_TIMOUT_WIN_LIM_FRAG_CNT 0x3FFF0000 ++#define HEAD_TIMOUT_WIN_LIM_FRAG_CNT_SHIFT 16 ++/* Head timeout window limit byte count */ ++#define HEAD_TIMOUT_WIN_LIM_BYTE_CNT 0x0000FFFF ++#define HEAD_TIMOUT_WIN_LIM_BYTE_CNT_SHIFT 0 ++} __attribute__((__packed__)); ++ ++ ++/* ++ * Traffic Class Structure ++ */ ++struct agnx_sta_traffic { ++ __le32 reg0; ++#define ACK_TIMOUT_CNT 0xFF800000 /* ACK Timeout Counts */ ++#define ACK_TIMOUT_CNT_SHIFT 23 ++#define TRAFFIC_ACK_TYPE 0x00600000 /* ACK Type */ ++#define TRAFFIC_ACK_TYPE_SHIFT 21 ++#define NEW_PACKET 0x00100000 /* New Packet */ ++#define NEW_PACKET_SHIFT 20 ++#define TRAFFIC_VALID 0x00080000 /* Valid */ ++#define TRAFFIC_VALID_SHIFT 19 ++#define RX_HDR_DESC_POINTER 0x0007FFFF /* RX Header Descripter pointer */ ++#define RX_HDR_DESC_POINTER_SHIFT 0 ++ ++ __le32 reg1; ++#define RX_PACKET_TIMESTAMP 0xFFFF0000 /* RX Packet Timestamp */ ++#define RX_PACKET_TIMESTAMP_SHIFT 16 ++#define TRAFFIC_RESERVED 0x0000E000 /* Reserved */ ++#define TRAFFIC_RESERVED_SHIFT 13 ++#define SV 0x00001000 /* sv */ ++#define SV_SHIFT 12 ++#define RX_SEQUENCE_NUM 0x00000FFF /* RX Sequence Number */ ++#define RX_SEQUENCE_NUM_SHIFT 0 ++ ++ __le32 tx_replay_cnt_low; /* TX Replay Counter Low */ ++ ++ __le16 tx_replay_cnt_high; /* TX Replay Counter High */ ++ __le16 rx_replay_cnt_high; /* RX Replay Counter High */ ++ ++ __be32 rx_replay_cnt_low; /* RX Replay Counter Low */ ++} __attribute__((__packed__)); ++ ++/* ++ * Station Descriptors ++ */ ++struct agnx_sta { ++ __le32 tx_session_keys[4]; /* Transmit Session Key (0-3) */ ++ __le32 rx_session_keys[4]; /* Receive Session Key (0-3) */ ++ ++ __le32 reg; ++#define ID_1 0xC0000000 /* id 1 */ ++#define ID_1_SHIFT 30 ++#define ID_0 0x30000000 /* id 0 */ ++#define ID_0_SHIFT 28 ++#define ENABLE_CONCATENATION 0x0FF00000 /* Enable concatenation */ ++#define ENABLE_CONCATENATION_SHIFT 20 ++#define ENABLE_DECOMPRESSION 0x000FF000 /* Enable decompression */ ++#define ENABLE_DECOMPRESSION_SHIFT 12 ++#define STA_RESERVED 0x00000C00 /* Reserved */ ++#define STA_RESERVED_SHIFT 10 ++#define EAP 0x00000200 /* EAP */ ++#define EAP_SHIFT 9 ++#define ED_NULL 0x00000100 /* ED NULL */ ++#define ED_NULL_SHIFT 8 ++#define ENCRYPTION_POLICY 0x000000E0 /* Encryption Policy */ ++#define ENCRYPTION_POLICY_SHIFT 5 ++#define DEFINED_KEY_ID 0x00000018 /* Defined Key ID */ ++#define DEFINED_KEY_ID_SHIFT 3 ++#define FIXED_KEY 0x00000004 /* Fixed Key */ ++#define FIXED_KEY_SHIFT 2 ++#define KEY_VALID 0x00000002 /* Key Valid */ ++#define KEY_VALID_SHIFT 1 ++#define STATION_VALID 0x00000001 /* Station Valid */ ++#define STATION_VALID_SHIFT 0 ++ ++ __le32 tx_aes_blks_unicast; /* TX AES Blks Unicast */ ++ __le32 rx_aes_blks_unicast; /* RX AES Blks Unicast */ ++ ++ __le16 aes_format_err_unicast_cnt; /* AES Format Error Unicast Counts */ ++ __le16 aes_replay_unicast; /* AES Replay Unicast */ ++ ++ __le16 aes_decrypt_err_unicast; /* AES Decrypt Error Unicast */ ++ __le16 aes_decrypt_err_default; /* AES Decrypt Error default */ ++ ++ __le16 single_retry_packets; /* Single Retry Packets */ ++ __le16 failed_tx_packets; /* Failed Tx Packets */ ++ ++ __le16 muti_retry_packets; /* Multiple Retry Packets */ ++ __le16 ack_timeouts; /* ACK Timeouts */ ++ ++ __le16 frag_tx_cnt; /* Fragment TX Counts */ ++ __le16 rts_brq_sent; /* RTS Brq Sent */ ++ ++ __le16 tx_packets; /* TX Packets */ ++ __le16 cts_back_timeout; /* CTS Back Timeout */ ++ ++ __le32 phy_stats_high; /* PHY Stats High */ ++ __le32 phy_stats_low; /* PHY Stats Low */ ++ ++ struct agnx_sta_traffic traffic[8]; /* Traffic Class Structure (8) */ ++ ++ __le16 traffic_class0_frag_success; /* Traffic Class 0 Fragment Success */ ++ __le16 traffic_class1_frag_success; /* Traffic Class 1 Fragment Success */ ++ __le16 traffic_class2_frag_success; /* Traffic Class 2 Fragment Success */ ++ __le16 traffic_class3_frag_success; /* Traffic Class 3 Fragment Success */ ++ __le16 traffic_class4_frag_success; /* Traffic Class 4 Fragment Success */ ++ __le16 traffic_class5_frag_success; /* Traffic Class 5 Fragment Success */ ++ __le16 traffic_class6_frag_success; /* Traffic Class 6 Fragment Success */ ++ __le16 traffic_class7_frag_success; /* Traffic Class 7 Fragment Success */ ++ ++ __le16 num_frag_non_prime_rates; /* number of Fragments for non-prime rates */ ++ __le16 ack_timeout_non_prime_rates; /* ACK Timeout for non-prime rates */ ++ ++} __attribute__((__packed__)); ++ ++ ++struct agnx_beacon_hdr { ++ struct agnx_sta_power power; /* Tx Station Power Template */ ++ u8 phy_hdr[6]; /* PHY Hdr */ ++ u8 frame_len_lo; /* Frame Length Lo */ ++ u8 frame_len_hi; /* Frame Length Hi */ ++ u8 mac_hdr[24]; /* MAC Header */ ++ /* FIXME */ ++ /* 802.11(abg) beacon */ ++} __attribute__((__packed__)); ++ ++void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id); ++void hash_dump(struct agnx_priv *priv, u8 sta_id); ++void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id); ++void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id); ++ ++void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx); ++void set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, ++ unsigned int sta_idx); ++void get_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq, ++ unsigned int sta_idx, unsigned int wq_idx); ++void set_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq, ++ unsigned int sta_idx, unsigned int wq_idx); ++void get_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx); ++void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx); ++ ++void sta_power_init(struct agnx_priv *priv, unsigned int num); ++void sta_init(struct agnx_priv *priv, unsigned int num); ++ ++#endif /* AGNX_STA_H_ */ +--- /dev/null ++++ b/drivers/staging/agnx/table.c +@@ -0,0 +1,168 @@ ++#include ++#include ++#include "agnx.h" ++#include "debug.h" ++#include "phy.h" ++ ++static const u32 ++tx_fir_table[] = { 0x19, 0x5d, 0xce, 0x151, 0x1c3, 0x1ff, 0x1ea, 0x17c, 0xcf, ++ 0x19, 0x38e, 0x350, 0x362, 0x3ad, 0x5, 0x44, 0x59, 0x49, ++ 0x21, 0x3f7, 0x3e0, 0x3e3, 0x3f3, 0x0 }; ++ ++void tx_fir_table_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(tx_fir_table); i++) ++ iowrite32(tx_fir_table[i], ctl + AGNX_FIR_BASE + i*4); ++} /* fir_table_setup */ ++ ++ ++static const u32 ++gain_table[] = { 0x8, 0x8, 0xf, 0x13, 0x17, 0x1b, 0x1f, 0x23, 0x27, 0x2b, ++ 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, 0x47, 0x4b, 0x4f, ++ 0x53, 0x57, 0x5b, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, ++ 0x5f, 0x5f, 0x5f, 0x5f }; ++ ++void gain_table_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(gain_table); i++) { ++ iowrite32(gain_table[i], ctl + AGNX_GAIN_TABLE + i*4); ++ iowrite32(gain_table[i], ctl + AGNX_GAIN_TABLE + i*4 + 0x80); ++ } ++} /* gain_table_init */ ++ ++void monitor_gain_table_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ unsigned int i; ++ ++ for (i = 0; i < 0x44; i += 4) { ++ iowrite32(0x61, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0x61, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++ for (i = 0x44; i < 0x64; i += 4) { ++ iowrite32(0x6e, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0x6e, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++ for (i = 0x64; i < 0x94; i += 4) { ++ iowrite32(0x7a, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0x7a, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++ for (i = 0x94; i < 0xdc; i += 4) { ++ iowrite32(0x87, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0x87, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++ for (i = 0xdc; i < 0x148; i += 4) { ++ iowrite32(0x95, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0x95, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++ for (i = 0x148; i < 0x1e8; i += 4) { ++ iowrite32(0xa2, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0xa2, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++ for (i = 0x1e8; i <= 0x1fc; i += 4) { ++ iowrite32(0xb0, ctl + AGNX_MONGCR_BASE + i); ++ iowrite32(0xb0, ctl + AGNX_MONGCR_BASE + 0x200 + i); ++ } ++} /* monitor_gain_table_init */ ++ ++ ++void routing_table_init(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ unsigned int type, subtype; ++ u32 reg; ++ ++ disable_receiver(priv); ++ ++ for ( type = 0; type < 0x3; type++ ) { ++ for (subtype = 0; subtype < 0x10; subtype++) { ++ /* 1. Set Routing table to R/W and to Return status on Read */ ++ reg = (type << ROUTAB_TYPE_SHIFT) | ++ (subtype << ROUTAB_SUBTYPE_SHIFT); ++ reg |= (1 << ROUTAB_RW_SHIFT) | (1 << ROUTAB_STATUS_SHIFT); ++ if (type == ROUTAB_TYPE_DATA) { ++ /* NULL goes to RFP */ ++ if (subtype == ROUTAB_SUBTYPE_NULL) ++// reg |= ROUTAB_ROUTE_RFP; ++ reg |= ROUTAB_ROUTE_CPU; ++ /* QOS NULL goes to CPU */ ++ else if (subtype == ROUTAB_SUBTYPE_QOSNULL) ++ reg |= ROUTAB_ROUTE_CPU; ++ /* All Data and QOS data subtypes go to Encryption */ ++ else if ((subtype == ROUTAB_SUBTYPE_DATA) || ++ (subtype == ROUTAB_SUBTYPE_DATAACK) || ++ (subtype == ROUTAB_SUBTYPE_DATAPOLL) || ++ (subtype == ROUTAB_SUBTYPE_DATAPOLLACK) || ++ (subtype == ROUTAB_SUBTYPE_QOSDATA) || ++ (subtype == ROUTAB_SUBTYPE_QOSDATAACK) || ++ (subtype == ROUTAB_SUBTYPE_QOSDATAPOLL) || ++ (subtype == ROUTAB_SUBTYPE_QOSDATAACKPOLL)) ++ reg |= ROUTAB_ROUTE_ENCRY; ++// reg |= ROUTAB_ROUTE_CPU; ++ /*Drop NULL and QOS NULL ack, poll and poll ack*/ ++ else if ((subtype == ROUTAB_SUBTYPE_NULLACK) || ++ (subtype == ROUTAB_SUBTYPE_QOSNULLACK) || ++ (subtype == ROUTAB_SUBTYPE_NULLPOLL) || ++ (subtype == ROUTAB_SUBTYPE_QOSNULLPOLL) || ++ (subtype == ROUTAB_SUBTYPE_NULLPOLLACK) || ++ (subtype == ROUTAB_SUBTYPE_QOSNULLPOLLACK)) ++// reg |= ROUTAB_ROUTE_DROP; ++ reg |= ROUTAB_ROUTE_CPU; ++ } ++ else ++ reg |= (ROUTAB_ROUTE_CPU); ++ iowrite32(reg, ctl + AGNX_RXM_ROUTAB); ++ /* Check to verify that the status bit cleared */ ++ routing_table_delay(); ++ } ++ } ++ enable_receiver(priv); ++} /* routing_table_init */ ++ ++void tx_engine_lookup_tbl_init(struct agnx_priv *priv) ++{ ++ void __iomem *data = priv->data; ++ unsigned int i; ++ ++ for (i = 0; i <= 28; i += 4) ++ iowrite32(0xb00c, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ for (i = 32; i <= 120; i += 8) { ++ iowrite32(0x1e58, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ iowrite32(0xb00c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4); ++ } ++ ++ for (i = 128; i <= 156; i += 4) ++ iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ for (i = 160; i <= 248; i += 8) { ++ iowrite32(0x1858, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4); ++ } ++ ++ for (i = 256; i <= 284; i += 4) ++ iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ for (i = 288; i <= 376; i += 8) { ++ iowrite32(0x1a58, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ iowrite32(0x1858, data + AGNX_ENGINE_LOOKUP_TBL + i + 4); ++ } ++ ++ for (i = 512; i <= 540; i += 4) ++ iowrite32(0xc00c, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ for (i = 544; i <= 632; i += 8) { ++ iowrite32(0x2058, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ iowrite32(0xc00c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4); ++ } ++ ++ for (i = 640; i <= 668; i += 4) ++ iowrite32(0xc80c, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ for (i = 672; i <= 764; i += 8) { ++ iowrite32(0x2258, data + AGNX_ENGINE_LOOKUP_TBL + i); ++ iowrite32(0xc80c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/agnx/table.h +@@ -0,0 +1,10 @@ ++#ifndef AGNX_TABLE_H_ ++#define AGNX_TABLE_H_ ++ ++void tx_fir_table_init(struct agnx_priv *priv); ++void gain_table_init(struct agnx_priv *priv); ++void monitor_gain_table_init(struct agnx_priv *priv); ++void routing_table_init(struct agnx_priv *priv); ++void tx_engine_lookup_tbl_init(struct agnx_priv *priv); ++ ++#endif /* AGNX_TABLE_H_ */ +--- /dev/null ++++ b/drivers/staging/agnx/TODO +@@ -0,0 +1,22 @@ ++2008 7/18 ++ ++The RX has can't receive OFDM packet correctly, ++Guess it need be do RX calibrate. ++ ++ ++before 2008 3/1 ++ ++1: The RX get too much "CRC failed" pakets, it make the card work very unstable, ++2: After running a while, the card will get infinity "RX Frame" and "Error" ++interrupt, not know the root reason so far, try to fix it ++3: Using two tx queue txd and txm but not only txm. ++4: Set the hdr correctly. ++5: Try to do recalibrate correvtly ++6: To support G mode in future ++7: Fix the mac address can't be readed and set correctly in BE machine. ++8: Fix include and exclude FCS in promisous mode and manage mode ++9: Using sta_notify to notice sta change ++10: Turn on frame reception at the end of start ++11: Guess the card support HW_MULTICAST_FILTER ++12: The tx process should be implment atomic? ++13: Using mac80211 function to control the TX&RX LED. +--- /dev/null ++++ b/drivers/staging/agnx/xmit.c +@@ -0,0 +1,819 @@ ++/** ++ * Airgo MIMO wireless driver ++ * ++ * Copyright (c) 2007 Li YanBo ++ ++ * Thanks for Jeff Williams do reverse engineer ++ * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin ++ ++ * 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. ++ */ ++ ++#include ++#include ++#include "agnx.h" ++#include "debug.h" ++#include "phy.h" ++ ++unsigned int rx_frame_cnt = 0; ++//unsigned int local_tx_sent_cnt = 0; ++ ++static inline void disable_rx_engine(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ iowrite32(0x100, ctl + AGNX_CIR_RXCTL); ++ /* Wait for RX Control to have the Disable Rx Interrupt (0x100) set */ ++ ioread32(ctl + AGNX_CIR_RXCTL); ++} ++ ++static inline void enable_rx_engine(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ iowrite32(0x80, ctl + AGNX_CIR_RXCTL); ++ ioread32(ctl + AGNX_CIR_RXCTL); ++} ++ ++inline void disable_rx_interrupt(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ disable_rx_engine(priv); ++ reg = ioread32(ctl + AGNX_CIR_RXCFG); ++ reg &= ~0x20; ++ iowrite32(reg, ctl + AGNX_CIR_RXCFG); ++ ioread32(ctl + AGNX_CIR_RXCFG); ++} ++ ++inline void enable_rx_interrupt(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ reg = ioread32(ctl + AGNX_CIR_RXCFG); ++ reg |= 0x20; ++ iowrite32(reg, ctl + AGNX_CIR_RXCFG); ++ ioread32(ctl + AGNX_CIR_RXCFG); ++ enable_rx_engine(priv); ++} ++ ++static inline void rx_desc_init(struct agnx_priv *priv, unsigned int idx) ++{ ++ struct agnx_desc *desc = priv->rx.desc + idx; ++ struct agnx_info *info = priv->rx.info + idx; ++ ++ memset(info, 0, sizeof(*info)); ++ ++ info->dma_len = IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct agnx_hdr); ++ info->skb = dev_alloc_skb(info->dma_len); ++ if (info->skb == NULL) ++ agnx_bug("refill err"); ++ ++ info->mapping = pci_map_single(priv->pdev, skb_tail_pointer(info->skb), ++ info->dma_len, PCI_DMA_FROMDEVICE); ++ memset(desc, 0, sizeof(*desc)); ++ desc->dma_addr = cpu_to_be32(info->mapping); ++ /* Set the owner to the card */ ++ desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER); ++} ++ ++static inline void rx_desc_reinit(struct agnx_priv *priv, unsigned int idx) ++{ ++ struct agnx_info *info = priv->rx.info + idx; ++ ++ /* Cause ieee80211 will free the skb buffer, so we needn't to free it again?! */ ++ pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE); ++ rx_desc_init(priv, idx); ++} ++ ++static inline void rx_desc_reusing(struct agnx_priv *priv, unsigned int idx) ++{ ++ struct agnx_desc *desc = priv->rx.desc + idx; ++ struct agnx_info *info = priv->rx.info + idx; ++ ++ memset(desc, 0, sizeof(*desc)); ++ desc->dma_addr = cpu_to_be32(info->mapping); ++ /* Set the owner to the card */ ++ desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER); ++} ++ ++static void rx_desc_free(struct agnx_priv *priv, unsigned int idx) ++{ ++ struct agnx_desc *desc = priv->rx.desc + idx; ++ struct agnx_info *info = priv->rx.info + idx; ++ ++ BUG_ON(!desc || !info); ++ if (info->mapping) ++ pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE); ++ if (info->skb) ++ dev_kfree_skb(info->skb); ++ memset(info, 0, sizeof(*info)); ++ memset(desc, 0, sizeof(*desc)); ++} ++ ++static inline void __tx_desc_free(struct agnx_priv *priv, ++ struct agnx_desc *desc, struct agnx_info *info) ++{ ++ BUG_ON(!desc || !info); ++ /* TODO make sure mapping, skb and len are consistency */ ++ if (info->mapping) ++ pci_unmap_single(priv->pdev, info->mapping, ++ info->dma_len, PCI_DMA_TODEVICE); ++ if (info->type == PACKET) ++ dev_kfree_skb(info->skb); ++ ++ memset(info, 0, sizeof(*info)); ++ memset(desc, 0, sizeof(*desc)); ++} ++ ++static void txm_desc_free(struct agnx_priv *priv, unsigned int idx) ++{ ++ struct agnx_desc *desc = priv->txm.desc + idx; ++ struct agnx_info *info = priv->txm.info + idx; ++ ++ __tx_desc_free(priv, desc, info); ++} ++ ++static void txd_desc_free(struct agnx_priv *priv, unsigned int idx) ++{ ++ struct agnx_desc *desc = priv->txd.desc + idx; ++ struct agnx_info *info = priv->txd.info + idx; ++ ++ __tx_desc_free(priv, desc, info); ++} ++ ++int fill_rings(struct agnx_priv *priv) ++{ ++ void __iomem *ctl = priv->ctl; ++ unsigned int i; ++ u32 reg; ++ AGNX_TRACE; ++ ++ priv->txd.idx_sent = priv->txm.idx_sent = 0; ++ priv->rx.idx = priv->txm.idx = priv->txd.idx = 0; ++ ++ for (i = 0; i < priv->rx.size; i++) ++ rx_desc_init(priv, i); ++ for (i = 0; i < priv->txm.size; i++) { ++ memset(priv->txm.desc + i, 0, sizeof(struct agnx_desc)); ++ memset(priv->txm.info + i, 0, sizeof(struct agnx_info)); ++ } ++ for (i = 0; i < priv->txd.size; i++) { ++ memset(priv->txd.desc + i, 0, sizeof(struct agnx_desc)); ++ memset(priv->txd.info + i, 0, sizeof(struct agnx_info)); ++ } ++ ++ /* FIXME Set the card RX TXM and TXD address */ ++ agnx_write32(ctl, AGNX_CIR_RXCMSTART, priv->rx.dma); ++ agnx_write32(ctl, AGNX_CIR_RXCMEND, priv->txm.dma); ++ ++ agnx_write32(ctl, AGNX_CIR_TXMSTART, priv->txm.dma); ++ agnx_write32(ctl, AGNX_CIR_TXMEND, priv->txd.dma); ++ ++ agnx_write32(ctl, AGNX_CIR_TXDSTART, priv->txd.dma); ++ agnx_write32(ctl, AGNX_CIR_TXDEND, priv->txd.dma + ++ sizeof(struct agnx_desc) * priv->txd.size); ++ ++ /* FIXME Relinquish control of rings to card */ ++ reg = agnx_read32(ctl, AGNX_CIR_BLKCTL); ++ reg &= ~0x800; ++ agnx_write32(ctl, AGNX_CIR_BLKCTL, reg); ++ return 0; ++} /* fill_rings */ ++ ++void unfill_rings(struct agnx_priv *priv) ++{ ++ unsigned long flags; ++ unsigned int i; ++ AGNX_TRACE; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ for (i = 0; i < priv->rx.size; i++) ++ rx_desc_free(priv, i); ++ for (i = 0; i < priv->txm.size; i++) ++ txm_desc_free(priv, i); ++ for (i = 0; i < priv->txd.size; i++) ++ txd_desc_free(priv, i); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++/* Extract the bitrate out of a CCK PLCP header. ++ copy from bcm43xx driver */ ++static inline u8 agnx_plcp_get_bitrate_cck(__be32 *phyhdr_11b) ++{ ++ /* FIXME */ ++ switch (*(u8 *)phyhdr_11b) { ++ case 0x0A: ++ return 0; ++ case 0x14: ++ return 1; ++ case 0x37: ++ return 2; ++ case 0x6E: ++ return 3; ++ } ++ agnx_bug("Wrong plcp rate"); ++ return 0; ++} ++ ++/* FIXME */ ++static inline u8 agnx_plcp_get_bitrate_ofdm(__be32 *phyhdr_11g) ++{ ++ u8 rate = *(u8 *)phyhdr_11g & 0xF; ++ ++ printk(PFX "G mode rate is 0x%x\n", rate); ++ return rate; ++} ++ ++/* FIXME */ ++static void get_rx_stats(struct agnx_priv *priv, struct agnx_hdr *hdr, ++ struct ieee80211_rx_status *stat) ++{ ++ void __iomem *ctl = priv->ctl; ++ u8 *rssi; ++ u32 noise; ++ /* FIXME just for test */ ++ int snr = 40; /* signal-to-noise ratio */ ++ ++ memset(stat, 0, sizeof(*stat)); ++ /* RSSI */ ++ rssi = (u8 *)&hdr->phy_stats_lo; ++// stat->ssi = (rssi[0] + rssi[1] + rssi[2]) / 3; ++ /* Noise */ ++ noise = ioread32(ctl + AGNX_GCR_NOISE0); ++ noise += ioread32(ctl + AGNX_GCR_NOISE1); ++ noise += ioread32(ctl + AGNX_GCR_NOISE2); ++ stat->noise = noise / 3; ++ /* Signal quality */ ++ //snr = stat->ssi - stat->noise; ++ if (snr >=0 && snr < 40) ++ stat->signal = 5 * snr / 2; ++ else if (snr >= 40) ++ stat->signal = 100; ++ else ++ stat->signal = 0; ++ ++ ++ if (hdr->_11b0 && !hdr->_11g0) { ++ stat->rate_idx = agnx_plcp_get_bitrate_cck(&hdr->_11b0); ++ } else if (!hdr->_11b0 && hdr->_11g0) { ++ printk(PFX "RX: Found G mode packet\n"); ++ stat->rate_idx = agnx_plcp_get_bitrate_ofdm(&hdr->_11g0); ++ } else ++ agnx_bug("Unknown packets type"); ++ ++ ++ stat->band = IEEE80211_BAND_2GHZ; ++ stat->freq = agnx_channels[priv->channel - 1].center_freq; ++// stat->antenna = 3; ++// stat->mactime = be32_to_cpu(hdr->time_stamp); ++// stat->channel = priv->channel; ++ ++} ++ ++static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr, ++ struct sk_buff *skb) ++{ ++ u16 fctl; ++ unsigned int hdrlen; ++ ++ fctl = le16_to_cpu(ieeehdr->frame_control); ++ hdrlen = ieee80211_hdrlen(fctl); ++ /* FIXME */ ++ if (hdrlen < (2+2+6)/*minimum hdr*/ || ++ hdrlen > sizeof(struct ieee80211_mgmt)) { ++ printk(KERN_ERR PFX "hdr len is %d\n", hdrlen); ++ agnx_bug("Wrong ieee80211 hdr detected"); ++ } ++ skb_push(skb, hdrlen); ++ memcpy(skb->data, ieeehdr, hdrlen); ++} /* combine_hdr_frag */ ++ ++static inline int agnx_packet_check(struct agnx_priv *priv, struct agnx_hdr *agnxhdr, ++ unsigned packet_len) ++{ ++ if (agnx_get_bits(CRC_FAIL, CRC_FAIL_SHIFT, be32_to_cpu(agnxhdr->reg1)) == 1){ ++ printk(PFX "RX: CRC check fail\n"); ++ goto drop; ++ } ++ if (packet_len > 2048) { ++ printk(PFX "RX: Too long packet detected\n"); ++ goto drop; ++ } ++ ++ /* FIXME Just usable for Promious Mode, for Manage mode exclude FCS */ ++/* if (packet_len - sizeof(*agnxhdr) < FCS_LEN) { */ ++/* printk(PFX "RX: Too short packet detected\n"); */ ++/* goto drop; */ ++/* } */ ++ return 0; ++drop: ++ priv->stats.dot11FCSErrorCount++; ++ return -1; ++} ++ ++void handle_rx_irq(struct agnx_priv *priv) ++{ ++ struct ieee80211_rx_status status; ++ unsigned int len; ++// AGNX_TRACE; ++ ++ do { ++ struct agnx_desc *desc; ++ u32 frag; ++ struct agnx_info *info; ++ struct agnx_hdr *hdr; ++ struct sk_buff *skb; ++ unsigned int i = priv->rx.idx % priv->rx.size; ++ ++ desc = priv->rx.desc + i; ++ frag = be32_to_cpu(desc->frag); ++ if (frag & OWNER) ++ break; ++ ++ info = priv->rx.info + i; ++ skb = info->skb; ++ hdr = (struct agnx_hdr *)(skb->data); ++ ++ len = (frag & PACKET_LEN) >> PACKET_LEN_SHIFT; ++ if (agnx_packet_check(priv, hdr, len) == -1) { ++ rx_desc_reusing(priv, i); ++ continue; ++ } ++ skb_put(skb, len); ++ ++ do { ++ u16 fctl; ++ fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)->frame_control); ++ if ((fctl & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_BEACON)// && !(fctl & IEEE80211_STYPE_BEACON)) ++ dump_ieee80211_hdr((struct ieee80211_hdr *)hdr->mac_hdr, "RX"); ++ } while (0); ++ ++ if (hdr->_11b0 && !hdr->_11g0) { ++/* int j; */ ++/* u16 fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr) */ ++/* ->frame_control); */ ++/* if ( (fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { */ ++/* agnx_print_rx_hdr(hdr); */ ++// agnx_print_sta(priv, BSSID_STAID); ++/* for (j = 0; j < 8; j++) */ ++/* agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */ ++/* } */ ++ ++ get_rx_stats(priv, hdr, &status); ++ skb_pull(skb, sizeof(*hdr)); ++ combine_hdr_frag((struct ieee80211_hdr *)hdr->mac_hdr, skb); ++ } else if (!hdr->_11b0 && hdr->_11g0) { ++// int j; ++ agnx_print_rx_hdr(hdr); ++ agnx_print_sta(priv, BSSID_STAID); ++// for (j = 0; j < 8; j++) ++ agnx_print_sta_tx_wq(priv, BSSID_STAID, 0); ++ ++ print_hex_dump_bytes("agnx: RX_PACKET: ", DUMP_PREFIX_NONE, ++ skb->data, skb->len + 8); ++ ++// if (agnx_plcp_get_bitrate_ofdm(&hdr->_11g0) == 0) ++ get_rx_stats(priv, hdr, &status); ++ skb_pull(skb, sizeof(*hdr)); ++ combine_hdr_frag((struct ieee80211_hdr *) ++ ((void *)&hdr->mac_hdr), skb); ++// dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); ++ } else ++ agnx_bug("Unknown packets type"); ++ ieee80211_rx_irqsafe(priv->hw, skb, &status); ++ rx_desc_reinit(priv, i); ++ ++ } while ( priv->rx.idx++ ); ++} /* handle_rx_irq */ ++ ++static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring) ++{ ++ struct agnx_desc *desc; ++ struct agnx_info *info; ++ unsigned int idx; ++ ++ for (idx = ring->idx_sent; idx < ring->idx; idx++) { ++ unsigned int i = idx % ring->size; ++ u32 frag; ++ ++ desc = ring->desc + i; ++ info = ring->info + i; ++ ++ frag = be32_to_cpu(desc->frag); ++ if (frag & OWNER) { ++ if (info->type == HEADER) ++ break; ++ else ++ agnx_bug("TX error"); ++ } ++ ++ pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_TODEVICE); ++ ++ do { ++// int j; ++ size_t len; ++ len = info->skb->len - sizeof(struct agnx_hdr) + info->hdr_len; ++ // if (len == 614) { ++// agnx_print_desc(desc); ++ if (info->type == PACKET) { ++// agnx_print_tx_hdr((struct agnx_hdr *)info->skb->data); ++/* agnx_print_sta_power(priv, LOCAL_STAID); */ ++/* agnx_print_sta(priv, LOCAL_STAID); */ ++/* // for (j = 0; j < 8; j++) */ ++/* agnx_print_sta_tx_wq(priv, LOCAL_STAID, 0); */ ++// agnx_print_sta_power(priv, BSSID_STAID); ++// agnx_print_sta(priv, BSSID_STAID); ++// for (j = 0; j < 8; j++) ++// agnx_print_sta_tx_wq(priv, BSSID_STAID, 0); ++ } ++// } ++ } while (0); ++ ++ if (info->type == PACKET) { ++// dump_txm_registers(priv); ++// dump_rxm_registers(priv); ++// dump_bm_registers(priv); ++// dump_cir_registers(priv); ++ } ++ ++ if (info->type == PACKET) { ++// struct ieee80211_hdr *hdr; ++ struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(info->skb); ++ ++ skb_pull(info->skb, sizeof(struct agnx_hdr)); ++ memcpy(skb_push(info->skb, info->hdr_len), &info->hdr, info->hdr_len); ++ ++// dump_ieee80211_hdr((struct ieee80211_hdr *)info->skb->data, "TX_HANDLE"); ++/* print_hex_dump_bytes("agnx: TX_HANDLE: ", DUMP_PREFIX_NONE, */ ++/* info->skb->data, info->skb->len); */ ++ ++ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) ++ txi->flags |= IEEE80211_TX_STAT_ACK; ++ ++ ieee80211_tx_status_irqsafe(priv->hw, info->skb); ++ ++ ++/* info->tx_status.queue_number = (ring->size - i) / 2; */ ++/* ieee80211_tx_status_irqsafe(priv->hw, info->skb, &(info->tx_status)); */ ++/* } else */ ++/* dev_kfree_skb_irq(info->skb); */ ++ } ++ memset(desc, 0, sizeof(*desc)); ++ memset(info, 0, sizeof(*info)); ++ } ++ ++ ring->idx_sent = idx; ++ /* TODO fill the priv->low_level_stats */ ++ ++ /* ieee80211_wake_queue(priv->hw, 0); */ ++} ++ ++void handle_txm_irq(struct agnx_priv *priv) ++{ ++ handle_tx_irq(priv, &priv->txm); ++} ++ ++void handle_txd_irq(struct agnx_priv *priv) ++{ ++ handle_tx_irq(priv, &priv->txd); ++} ++ ++void handle_other_irq(struct agnx_priv *priv) ++{ ++// void __iomem *ctl = priv->ctl; ++ u32 status = priv->irq_status; ++ void __iomem *ctl = priv->ctl; ++ u32 reg; ++ ++ if (status & IRQ_TX_BEACON) { ++ iowrite32(IRQ_TX_BEACON, ctl + AGNX_INT_STAT); ++ printk(PFX "IRQ: TX Beacon control is 0X%.8X\n", ioread32(ctl + AGNX_TXM_BEACON_CTL)); ++ printk(PFX "IRQ: TX Beacon rx frame num: %d\n", rx_frame_cnt); ++ } ++ if (status & IRQ_TX_RETRY) { ++ reg = ioread32(ctl + AGNX_TXM_RETRYSTAID); ++ printk(PFX "IRQ: TX Retry, RETRY STA ID is %x\n", reg); ++ } ++ if (status & IRQ_TX_ACTIVITY) ++ printk(PFX "IRQ: TX Activity\n"); ++ if (status & IRQ_RX_ACTIVITY) ++ printk(PFX "IRQ: RX Activity\n"); ++ if (status & IRQ_RX_X) ++ printk(PFX "IRQ: RX X\n"); ++ if (status & IRQ_RX_Y) { ++ reg = ioread32(ctl + AGNX_INT_MASK); ++ reg &= ~IRQ_RX_Y; ++ iowrite32(reg, ctl + AGNX_INT_MASK); ++ iowrite32(IRQ_RX_Y, ctl + AGNX_INT_STAT); ++ printk(PFX "IRQ: RX Y\n"); ++ } ++ if (status & IRQ_RX_HASHHIT) { ++ reg = ioread32(ctl + AGNX_INT_MASK); ++ reg &= ~IRQ_RX_HASHHIT; ++ iowrite32(reg, ctl + AGNX_INT_MASK); ++ iowrite32(IRQ_RX_HASHHIT, ctl + AGNX_INT_STAT); ++ printk(PFX "IRQ: RX Hash Hit\n"); ++ ++ } ++ if (status & IRQ_RX_FRAME) { ++ reg = ioread32(ctl + AGNX_INT_MASK); ++ reg &= ~IRQ_RX_FRAME; ++ iowrite32(reg, ctl + AGNX_INT_MASK); ++ iowrite32(IRQ_RX_FRAME, ctl + AGNX_INT_STAT); ++ printk(PFX "IRQ: RX Frame\n"); ++ rx_frame_cnt++; ++ } ++ if (status & IRQ_ERR_INT) { ++ iowrite32(IRQ_ERR_INT, ctl + AGNX_INT_STAT); ++// agnx_hw_reset(priv); ++ printk(PFX "IRQ: Error Interrupt\n"); ++ } ++ if (status & IRQ_TX_QUE_FULL) ++ printk(PFX "IRQ: TX Workqueue Full\n"); ++ if (status & IRQ_BANDMAN_ERR) ++ printk(PFX "IRQ: Bandwidth Management Error\n"); ++ if (status & IRQ_TX_DISABLE) ++ printk(PFX "IRQ: TX Disable\n"); ++ if (status & IRQ_RX_IVASESKEY) ++ printk(PFX "IRQ: RX Invalid Session Key\n"); ++ if (status & IRQ_REP_THHIT) ++ printk(PFX "IRQ: Replay Threshold Hit\n"); ++ if (status & IRQ_TIMER1) ++ printk(PFX "IRQ: Timer1\n"); ++ if (status & IRQ_TIMER_CNT) ++ printk(PFX "IRQ: Timer Count\n"); ++ if (status & IRQ_PHY_FASTINT) ++ printk(PFX "IRQ: Phy Fast Interrupt\n"); ++ if (status & IRQ_PHY_SLOWINT) ++ printk(PFX "IRQ: Phy Slow Interrupt\n"); ++ if (status & IRQ_OTHER) ++ printk(PFX "IRQ: 0x80000000\n"); ++} /* handle_other_irq */ ++ ++ ++static inline void route_flag_set(struct agnx_hdr *txhdr) ++{ ++// u32 reg = 0; ++ ++ /* FIXME */ ++/* reg = (0x7 << ROUTE_COMPRESSION_SHIFT) & ROUTE_COMPRESSION; */ ++/* txhdr->reg5 = cpu_to_be32(reg); */ ++ txhdr->reg5 = (0xa << 0x0) | (0x7 << 0x18); ++// txhdr->reg5 = cpu_to_be32((0xa << 0x0) | (0x7 << 0x18)); ++// txhdr->reg5 = cpu_to_be32(0x7 << 0x0); ++} ++ ++/* Return 0 if no match */ ++static inline unsigned int get_power_level(unsigned int rate, unsigned int antennas_num) ++{ ++ unsigned int power_level; ++ ++ switch (rate) { ++ case 10: ++ case 20: ++ case 55: ++ case 60: ++ case 90: ++ case 120: power_level = 22; break; ++ case 180: power_level = 19; break; ++ case 240: power_level = 18; break; ++ case 360: power_level = 16; break; ++ case 480: power_level = 15; break; ++ case 540: power_level = 14; break; ++ default: ++ agnx_bug("Error rate setting\n"); ++ } ++ ++ if (power_level && (antennas_num == 2)) ++ power_level -= 3; ++ ++ return power_level; ++} ++ ++static inline void fill_agnx_hdr(struct agnx_priv *priv, struct agnx_info *tx_info) ++{ ++ struct agnx_hdr *txhdr = (struct agnx_hdr *)tx_info->skb->data; ++ size_t len; ++ u16 fc = le16_to_cpu(*(__le16 *)&tx_info->hdr); ++ u32 reg; ++ ++ memset(txhdr, 0, sizeof(*txhdr)); ++ ++// reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, LOCAL_STAID); ++ reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, BSSID_STAID); ++ reg |= agnx_set_bits(WORKQUEUE_ID, WORKQUEUE_ID_SHIFT, 0); ++ txhdr->reg4 = cpu_to_be32(reg); ++ ++ /* Set the Hardware Sequence Number to 1? */ ++ reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 0); ++// reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 1); ++ reg |= agnx_set_bits(MAC_HDR_LEN, MAC_HDR_LEN_SHIFT, tx_info->hdr_len); ++ txhdr->reg1 = cpu_to_be32(reg); ++ /* Set the agnx_hdr's MAC header */ ++ memcpy(txhdr->mac_hdr, &tx_info->hdr, tx_info->hdr_len); ++ ++ reg = agnx_set_bits(ACK, ACK_SHIFT, 1); ++// reg = agnx_set_bits(ACK, ACK_SHIFT, 0); ++ reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 0); ++// reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 1); ++ reg |= agnx_set_bits(RELAY, RELAY_SHIFT, 0); ++ reg |= agnx_set_bits(TM, TM_SHIFT, 0); ++ txhdr->reg0 = cpu_to_be32(reg); ++ ++ /* Set the long and short retry limits */ ++ txhdr->tx.short_retry_limit = tx_info->txi->control.retry_limit; ++ txhdr->tx.long_retry_limit = tx_info->txi->control.retry_limit; ++ ++ /* FIXME */ ++ len = tx_info->skb->len - sizeof(*txhdr) + tx_info->hdr_len + FCS_LEN; ++ if (fc & IEEE80211_FCTL_PROTECTED) ++ len += 8; ++ len = 2398; ++ reg = agnx_set_bits(FRAG_SIZE, FRAG_SIZE_SHIFT, len); ++ len = tx_info->skb->len - sizeof(*txhdr); ++ reg |= agnx_set_bits(PAYLOAD_LEN, PAYLOAD_LEN_SHIFT, len); ++ txhdr->reg3 = cpu_to_be32(reg); ++ ++ route_flag_set(txhdr); ++} /* fill_hdr */ ++ ++static void txm_power_set(struct agnx_priv *priv, ++ struct ieee80211_tx_info *txi) ++{ ++ struct agnx_sta_power power; ++ u32 reg; ++ ++ /* FIXME */ ++ if (txi->tx_rate_idx < 0) { ++ /* For B mode Short Preamble */ ++ reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_SHORT); ++// control->tx_rate = -control->tx_rate; ++ } else ++ reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211G); ++// reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_LONG); ++ reg |= agnx_set_bits(SIGNAL, SIGNAL_SHIFT, 0xB); ++ reg |= agnx_set_bits(RATE, RATE_SHIFT, 0xB); ++// reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 15); ++ reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 20); ++ /* if rate < 11M set it to 0 */ ++ reg |= agnx_set_bits(NUM_TRANSMITTERS, NUM_TRANSMITTERS_SHIFT, 1); ++// reg |= agnx_set_bits(EDCF, EDCF_SHIFT, 1); ++// reg |= agnx_set_bits(TIFS, TIFS_SHIFT, 1); ++ ++ power.reg = reg; ++// power.reg = cpu_to_le32(reg); ++ ++// set_sta_power(priv, &power, LOCAL_STAID); ++ set_sta_power(priv, &power, BSSID_STAID); ++} ++ ++static inline int tx_packet_check(struct sk_buff *skb) ++{ ++ unsigned int ieee_len = ieee80211_get_hdrlen_from_skb(skb); ++ if (skb->len > 2048) { ++ printk(KERN_ERR PFX "length is %d\n", skb->len); ++ agnx_bug("Too long TX skb"); ++ return -1; ++ } ++ /* FIXME */ ++ if (skb->len == ieee_len) { ++ printk(PFX "A strange TX packet\n"); ++ return -1; ++ /* tx_faile_irqsafe(); */ ++ } ++ return 0; ++} ++ ++static int __agnx_tx(struct agnx_priv *priv, struct sk_buff *skb, ++ struct agnx_ring *ring) ++{ ++ struct agnx_desc *hdr_desc, *frag_desc; ++ struct agnx_info *hdr_info, *frag_info; ++ struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); ++ unsigned long flags; ++ unsigned int i; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ /* The RX interrupt need be Disable until this TX packet ++ is handled in the next tx interrupt */ ++ disable_rx_interrupt(priv); ++ ++ i = ring->idx; ++ ring->idx += 2; ++/* if (priv->txm_idx - priv->txm_idx_sent == AGNX_TXM_RING_SIZE - 2) */ ++/* ieee80211_stop_queue(priv->hw, 0); */ ++ ++ /* Set agnx header's info and desc */ ++ i %= ring->size; ++ hdr_desc = ring->desc + i; ++ hdr_info = ring->info + i; ++ hdr_info->hdr_len = ieee80211_get_hdrlen_from_skb(skb); ++ memcpy(&hdr_info->hdr, skb->data, hdr_info->hdr_len); ++ ++ /* Add the agnx header to the front of the SKB */ ++ skb_push(skb, sizeof(struct agnx_hdr) - hdr_info->hdr_len); ++ ++ hdr_info->txi = txi; ++ hdr_info->dma_len = sizeof(struct agnx_hdr); ++ hdr_info->skb = skb; ++ hdr_info->type = HEADER; ++ fill_agnx_hdr(priv, hdr_info); ++ hdr_info->mapping = pci_map_single(priv->pdev, skb->data, ++ hdr_info->dma_len, PCI_DMA_TODEVICE); ++ do { ++ u32 frag = 0; ++ frag |= agnx_set_bits(FIRST_FRAG, FIRST_FRAG_SHIFT, 1); ++ frag |= agnx_set_bits(LAST_FRAG, LAST_FRAG_SHIFT, 0); ++ frag |= agnx_set_bits(PACKET_LEN, PACKET_LEN_SHIFT, skb->len); ++ frag |= agnx_set_bits(FIRST_FRAG_LEN, FIRST_FRAG_LEN_SHIFT, 1); ++ frag |= agnx_set_bits(OWNER, OWNER_SHIFT, 1); ++ hdr_desc->frag = cpu_to_be32(frag); ++ } while (0); ++ hdr_desc->dma_addr = cpu_to_be32(hdr_info->mapping); ++ ++ ++ /* Set Frag's info and desc */ ++ i = (i + 1) % ring->size; ++ frag_desc = ring->desc + i; ++ frag_info = ring->info + i; ++ memcpy(frag_info, hdr_info, sizeof(struct agnx_info)); ++ frag_info->type = PACKET; ++ frag_info->dma_len = skb->len - hdr_info->dma_len; ++ frag_info->mapping = pci_map_single(priv->pdev, skb->data + hdr_info->dma_len, ++ frag_info->dma_len, PCI_DMA_TODEVICE); ++ do { ++ u32 frag = 0; ++ frag |= agnx_set_bits(FIRST_FRAG, FIRST_FRAG_SHIFT, 0); ++ frag |= agnx_set_bits(LAST_FRAG, LAST_FRAG_SHIFT, 1); ++ frag |= agnx_set_bits(PACKET_LEN, PACKET_LEN_SHIFT, skb->len); ++ frag |= agnx_set_bits(SUB_FRAG_LEN, SUB_FRAG_LEN_SHIFT, frag_info->dma_len); ++ frag_desc->frag = cpu_to_be32(frag); ++ } while (0); ++ frag_desc->dma_addr = cpu_to_be32(frag_info->mapping); ++ ++ txm_power_set(priv, txi); ++ ++/* do { */ ++/* int j; */ ++/* size_t len; */ ++/* len = skb->len - hdr_info->dma_len + hdr_info->hdr_len; */ ++/* // if (len == 614) { */ ++/* agnx_print_desc(hdr_desc); */ ++/* agnx_print_desc(frag_desc); */ ++/* agnx_print_tx_hdr((struct agnx_hdr *)skb->data); */ ++/* agnx_print_sta_power(priv, LOCAL_STAID); */ ++/* agnx_print_sta(priv, LOCAL_STAID); */ ++/* for (j = 0; j < 8; j++) */ ++/* agnx_print_sta_tx_wq(priv, LOCAL_STAID, j); */ ++/* agnx_print_sta_power(priv, BSSID_STAID); */ ++/* agnx_print_sta(priv, BSSID_STAID); */ ++/* for (j = 0; j < 8; j++) */ ++/* agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */ ++/* // } */ ++/* } while (0); */ ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* FIXME ugly code */ ++ /* Trigger TXM */ ++ do { ++ u32 reg; ++ reg = (ioread32(priv->ctl + AGNX_CIR_TXMCTL)); ++ reg |= 0x8; ++ iowrite32((reg), priv->ctl + AGNX_CIR_TXMCTL); ++ }while (0); ++ ++ /* Trigger TXD */ ++ do { ++ u32 reg; ++ reg = (ioread32(priv->ctl + AGNX_CIR_TXDCTL)); ++ reg |= 0x8; ++ iowrite32((reg), priv->ctl + AGNX_CIR_TXDCTL); ++ }while (0); ++ ++ return 0; ++} ++ ++int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb) ++{ ++ u16 fctl; ++ ++ if (tx_packet_check(skb)) ++ return 0; ++ ++/* print_hex_dump_bytes("agnx: TX_PACKET: ", DUMP_PREFIX_NONE, */ ++/* skb->data, skb->len); */ ++ ++ fctl = le16_to_cpu(*((__le16 *)skb->data)); ++ ++ if ( (fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ) ++ return __agnx_tx(priv, skb, &priv->txd); ++ else ++ return __agnx_tx(priv, skb, &priv->txm); ++} +--- /dev/null ++++ b/drivers/staging/agnx/xmit.h +@@ -0,0 +1,250 @@ ++#ifndef AGNX_XMIT_H_ ++#define AGNX_XMIT_H_ ++ ++#include ++ ++struct agnx_priv; ++ ++static inline u32 agnx_set_bits(u32 mask, u8 shift, u32 value) ++{ ++ return (value << shift) & mask; ++} ++ ++static inline u32 agnx_get_bits(u32 mask, u8 shift, u32 value) ++{ ++ return (value & mask) >> shift; ++} ++ ++ ++struct agnx_rx { ++ __be16 rx_packet_duration; /* RX Packet Duration */ ++ __be16 replay_cnt; /* Replay Count */ ++} __attribute__((__packed__)); ++ ++ ++struct agnx_tx { ++ u8 long_retry_limit; /* Long Retry Limit */ ++ u8 short_retry_limit; /* Short Retry Limit */ ++ u8 long_retry_cnt; /* Long Retry Count */ ++ u8 short_retry_cnt; /* Short Retry Count */ ++} __attribute__((__packed__)); ++ ++ ++/* Copy from bcm43xx */ ++#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] ++#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) ++#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__, nr_bytes) ++ ++#define P4D_BIT3S(magic, nr_bits) __be32 __padding##magic:nr_bits ++#define P4D_BITS(line, nr_bits) P4D_BIT3S(line, nr_bits) ++#define PAD_BITS(nr_bits) P4D_BITS(__LINE__, nr_bits) ++ ++ ++struct agnx_hdr { ++ __be32 reg0; ++#define RTS 0x80000000 /* RTS */ ++#define RTS_SHIFT 31 ++#define MULTICAST 0x40000000 /* multicast */ ++#define MULTICAST_SHIFT 30 ++#define ACK 0x30000000 /* ACK */ ++#define ACK_SHIFT 28 ++#define TM 0x08000000 /* TM */ ++#define TM_SHIFT 27 ++#define RELAY 0x04000000 /* Relay */ ++#define RELAY_SHIFT 26 ++/* PAD_BITS(4); */ ++#define REVISED_FCS 0x00380000 /* revised FCS */ ++#define REVISED_FCS_SHIFT 19 ++#define NEXT_BUFFER_ADDR 0x0007FFFF /* Next Buffer Address */ ++#define NEXT_BUFFER_ADDR_SHIFT 0 ++ ++ __be32 reg1; ++#define MAC_HDR_LEN 0xFC000000 /* MAC Header Length */ ++#define MAC_HDR_LEN_SHIFT 26 ++#define DURATION_OVERIDE 0x02000000 /* Duration Override */ ++#define DURATION_OVERIDE_SHIFT 25 ++#define PHY_HDR_OVERIDE 0x01000000 /* PHY Header Override */ ++#define PHY_HDR_OVERIDE_SHIFT 24 ++#define CRC_FAIL 0x00800000 /* CRC fail */ ++#define CRC_FAIL_SHIFT 23 ++/* PAD_BITS(1); */ ++#define SEQUENCE_NUMBER 0x00200000 /* Sequence Number */ ++#define SEQUENCE_NUMBER_SHIFT 21 ++/* PAD_BITS(2); */ ++#define BUFF_HEAD_ADDR 0x0007FFFF /* Buffer Head Address */ ++#define BUFF_HEAD_ADDR_SHIFT 0 ++ ++ __be32 reg2; ++#define PDU_COUNT 0xFC000000 /* PDU Count */ ++#define PDU_COUNT_SHIFT 26 ++/* PAD_BITS(3); */ ++#define WEP_KEY 0x00600000 /* WEP Key # */ ++#define WEP_KEY_SHIFT 21 ++#define USES_WEP_KEY 0x00100000 /* Uses WEP Key */ ++#define USES_WEP_KEY_SHIFT 20 ++#define KEEP_ALIVE 0x00080000 /* Keep alive */ ++#define KEEP_ALIVE_SHIFT 19 ++#define BUFF_TAIL_ADDR 0x0007FFFF /* Buffer Tail Address */ ++#define BUFF_TAIL_ADDR_SHIFT 0 ++ ++ __be32 reg3; ++#define CTS_11G 0x80000000 /* CTS in 11g */ ++#define CTS_11G_SHIFT 31 ++#define RTS_11G 0x40000000 /* RTS in 11g */ ++#define RTS_11G_SHIFT 30 ++/* PAD_BITS(2); */ ++#define FRAG_SIZE 0x0FFF0000 /* fragment size */ ++#define FRAG_SIZE_SHIFT 16 ++#define PAYLOAD_LEN 0x0000FFF0 /* payload length */ ++#define PAYLOAD_LEN_SHIFT 4 ++#define FRAG_NUM 0x0000000F /* number of frags */ ++#define FRAG_NUM_SHIFT 0 ++ ++ __be32 reg4; ++/* PAD_BITS(4); */ ++#define RELAY_STAID 0x0FFF0000 /* relayStald */ ++#define RELAY_STAID_SHIFT 16 ++#define STATION_ID 0x0000FFF0 /* Station ID */ ++#define STATION_ID_SHIFT 4 ++#define WORKQUEUE_ID 0x0000000F /* Workqueue ID */ ++#define WORKQUEUE_ID_SHIFT 0 ++ ++ /* FIXME this register maybe is LE? */ ++ __be32 reg5; ++/* PAD_BITS(4); */ ++#define ROUTE_HOST 0x0F000000 ++#define ROUTE_HOST_SHIFT 24 ++#define ROUTE_CARD_CPU 0x00F00000 ++#define ROUTE_CARD_CPU_SHIFT 20 ++#define ROUTE_ENCRYPTION 0x000F0000 ++#define ROUTE_ENCRYPTION_SHIFT 16 ++#define ROUTE_TX 0x0000F000 ++#define ROUTE_TX_SHIFT 12 ++#define ROUTE_RX1 0x00000F00 ++#define ROUTE_RX1_SHIFT 8 ++#define ROUTE_RX2 0x000000F0 ++#define ROUTE_RX2_SHIFT 4 ++#define ROUTE_COMPRESSION 0x0000000F ++#define ROUTE_COMPRESSION_SHIFT 0 ++ ++ __be32 _11g0; /* 11g */ ++ __be32 _11g1; /* 11g */ ++ __be32 _11b0; /* 11b */ ++ __be32 _11b1; /* 11b */ ++ u8 mac_hdr[32]; /* MAC header */ ++ ++ __be16 rts_duration; /* RTS duration */ ++ __be16 last_duration; /* Last duration */ ++ __be16 sec_last_duration; /* Second to Last duration */ ++ __be16 other_duration; /* Other duration */ ++ __be16 tx_last_duration; /* TX Last duration */ ++ __be16 tx_other_duration; /* TX Other Duration */ ++ __be16 last_11g_len; /* Length of last 11g */ ++ __be16 other_11g_len; /* Lenght of other 11g */ ++ ++ __be16 last_11b_len; /* Length of last 11b */ ++ __be16 other_11b_len; /* Lenght of other 11b */ ++ ++ ++ __be16 reg6; ++#define MBF 0xF000 /* mbf */ ++#define MBF_SHIFT 12 ++#define RSVD4 0x0FFF /* rsvd4 */ ++#define RSVD4_SHIFT 0 ++ ++ __be16 rx_frag_stat; /* RX fragmentation status */ ++ ++ __be32 time_stamp; /* TimeStamp */ ++ __be32 phy_stats_hi; /* PHY stats hi */ ++ __be32 phy_stats_lo; /* PHY stats lo */ ++ __be32 mic_key0; /* MIC key 0 */ ++ __be32 mic_key1; /* MIC key 1 */ ++ ++ union { /* RX/TX Union */ ++ struct agnx_rx rx; ++ struct agnx_tx tx; ++ }; ++ ++ u8 rx_channel; /* Recieve Channel */ ++ PAD_BYTES(3); ++ ++ u8 reserved[4]; ++} __attribute__((__packed__)); ++ ++ ++struct agnx_desc { ++#define PACKET_LEN 0xFFF00000 ++#define PACKET_LEN_SHIFT 20 ++/* ------------------------------------------------ */ ++#define FIRST_PACKET_MASK 0x00080000 ++#define FIRST_PACKET_MASK_SHIFT 19 ++#define FIRST_RESERV2 0x00040000 ++#define FIRST_RESERV2_SHIFT 18 ++#define FIRST_TKIP_ERROR 0x00020000 ++#define FIRST_TKIP_ERROR_SHIFT 17 ++#define FIRST_TKIP_PACKET 0x00010000 ++#define FIRST_TKIP_PACKET_SHIFT 16 ++#define FIRST_RESERV1 0x0000F000 ++#define FIRST_RESERV1_SHIFT 12 ++#define FIRST_FRAG_LEN 0x00000FF8 ++#define FIRST_FRAG_LEN_SHIFT 3 ++/* ------------------------------------------------ */ ++#define SUB_RESERV2 0x000c0000 ++#define SUB_RESERV2_SHIFT 18 ++#define SUB_TKIP_ERROR 0x00020000 ++#define SUB_TKIP_ERROR_SHIFT 17 ++#define SUB_TKIP_PACKET 0x00010000 ++#define SUB_TKIP_PACKET_SHIFT 16 ++#define SUB_RESERV1 0x00008000 ++#define SUB_RESERV1_SHIFT 15 ++#define SUB_FRAG_LEN 0x00007FF8 ++#define SUB_FRAG_LEN_SHIFT 3 ++/* ------------------------------------------------ */ ++#define FIRST_FRAG 0x00000004 ++#define FIRST_FRAG_SHIFT 2 ++#define LAST_FRAG 0x00000002 ++#define LAST_FRAG_SHIFT 1 ++#define OWNER 0x00000001 ++#define OWNER_SHIFT 0 ++ __be32 frag; ++ __be32 dma_addr; ++} __attribute__((__packed__)); ++ ++enum {HEADER, PACKET}; ++ ++struct agnx_info { ++ struct sk_buff *skb; ++ dma_addr_t mapping; ++ u32 dma_len; /* dma buffer len */ ++ /* Below fields only usful for tx */ ++ u32 hdr_len; /* ieee80211 header length */ ++ unsigned int type; ++ struct ieee80211_tx_info *txi; ++ struct ieee80211_hdr hdr; ++}; ++ ++ ++struct agnx_ring { ++ struct agnx_desc *desc; ++ dma_addr_t dma; ++ struct agnx_info *info; ++ /* Will lead to overflow when sent packet number enough? */ ++ unsigned int idx; ++ unsigned int idx_sent; /* only usful for txd and txm */ ++ unsigned int size; ++}; ++ ++#define AGNX_RX_RING_SIZE 128 ++#define AGNX_TXD_RING_SIZE 256 ++#define AGNX_TXM_RING_SIZE 128 ++ ++void disable_rx_interrupt(struct agnx_priv *priv); ++void enable_rx_interrupt(struct agnx_priv *priv); ++int fill_rings(struct agnx_priv *priv); ++void unfill_rings(struct agnx_priv *priv); ++void handle_rx_irq(struct agnx_priv *priv); ++void handle_txd_irq(struct agnx_priv *priv); ++void handle_txm_irq(struct agnx_priv *priv); ++void handle_other_irq(struct agnx_priv *priv); ++int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb); ++#endif /* AGNX_XMIT_H_ */ +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -43,4 +43,6 @@ source "drivers/staging/echo/Kconfig" + + source "drivers/staging/at76_usb/Kconfig" + ++source "drivers/staging/agnx/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_W35UND) += winbond/ + obj-$(CONFIG_PRISM2_USB) += wlan-ng/ + obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_USB_ATMEL) += at76_usb/ ++obj-$(CONFIG_AGNX) += agnx/ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-otus-atheros-wireless-network-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-otus-atheros-wireless-network-driver.patch new file mode 100644 index 000000000..28de5fec4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-otus-atheros-wireless-network-driver.patch @@ -0,0 +1,70755 @@ +From 6dbf61162153a00ad21537c4153009d8a26df723 Mon Sep 17 00:00:00 2001 +From: Luis R. Rodriguez +Date: Mon, 27 Oct 2008 22:44:22 -0700 +Subject: Staging: add otus Atheros wireless network driver +Patch-mainline: 2.6.28 + +From: Luis R. Rodriguez + +Initial dump of the otus USB wireless network driver. +It builds properly, but a lot of work needs to be done cleaning +it up before it can be merged into the wireless driver tree. + +Signed-off-by: Luis R. Rodriguez +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/otus/80211core/amsdu.c | 134 + drivers/staging/otus/80211core/cagg.c | 3611 +++++++++++++++ + drivers/staging/otus/80211core/cagg.h | 435 + + drivers/staging/otus/80211core/ccmd.c | 1861 ++++++++ + drivers/staging/otus/80211core/cfunc.c | 1227 +++++ + drivers/staging/otus/80211core/cfunc.h | 449 + + drivers/staging/otus/80211core/chb.c | 200 + drivers/staging/otus/80211core/cic.c | 496 ++ + drivers/staging/otus/80211core/cinit.c | 1911 ++++++++ + drivers/staging/otus/80211core/cmm.c | 2141 +++++++++ + drivers/staging/otus/80211core/cmmap.c | 2402 ++++++++++ + drivers/staging/otus/80211core/cmmsta.c | 5782 +++++++++++++++++++++++++ + drivers/staging/otus/80211core/coid.c | 2695 +++++++++++ + drivers/staging/otus/80211core/cprecomp.h | 32 + drivers/staging/otus/80211core/cpsmgr.c | 731 +++ + drivers/staging/otus/80211core/cscanmgr.c | 535 ++ + drivers/staging/otus/80211core/ctkip.c | 598 ++ + drivers/staging/otus/80211core/ctxrx.c | 4096 +++++++++++++++++ + drivers/staging/otus/80211core/cwep.c | 299 + + drivers/staging/otus/80211core/cwm.c | 131 + drivers/staging/otus/80211core/cwm.h | 45 + drivers/staging/otus/80211core/freqctrl.c | 259 + + drivers/staging/otus/80211core/ledmgr.c | 557 ++ + drivers/staging/otus/80211core/performance.c | 431 + + drivers/staging/otus/80211core/performance.h | 97 + drivers/staging/otus/80211core/pub_usb.h | 102 + drivers/staging/otus/80211core/pub_zfi.h | 821 +++ + drivers/staging/otus/80211core/pub_zfw.h | 93 + drivers/staging/otus/80211core/queue.c | 303 + + drivers/staging/otus/80211core/queue.h | 37 + drivers/staging/otus/80211core/ratectrl.c | 874 +++ + drivers/staging/otus/80211core/ratectrl.h | 37 + drivers/staging/otus/80211core/struct.h | 1315 +++++ + drivers/staging/otus/80211core/wlan.h | 595 ++ + drivers/staging/otus/Kconfig | 32 + drivers/staging/otus/Makefile | 67 + drivers/staging/otus/TODO | 9 + drivers/staging/otus/apdbg.c | 457 + + drivers/staging/otus/athr_common.h | 141 + drivers/staging/otus/hal/hpDKfwu.c | 832 +++ + drivers/staging/otus/hal/hpani.c | 732 +++ + drivers/staging/otus/hal/hpani.h | 420 + + drivers/staging/otus/hal/hpfw2.c | 1018 ++++ + drivers/staging/otus/hal/hpfwbu.c | 5269 ++++++++++++++++++++++ + drivers/staging/otus/hal/hpfwspiu.c | 655 ++ + drivers/staging/otus/hal/hpfwu.c | 1017 ++++ + drivers/staging/otus/hal/hpfwu.c.drv_ba_resend | 742 +++ + drivers/staging/otus/hal/hpfwu_2k.c | 1016 ++++ + drivers/staging/otus/hal/hpfwu_BA.c | 874 +++ + drivers/staging/otus/hal/hpfwu_FB50_mdk.c | 721 +++ + drivers/staging/otus/hal/hpfwu_OTUS_RC.c | 715 +++ + drivers/staging/otus/hal/hpfwu_txstream.c | 1017 ++++ + drivers/staging/otus/hal/hpfwuinit.c | 240 + + drivers/staging/otus/hal/hpmain.c | 4643 ++++++++++++++++++++ + drivers/staging/otus/hal/hpreg.c | 2481 ++++++++++ + drivers/staging/otus/hal/hpreg.h | 524 ++ + drivers/staging/otus/hal/hprw.c | 1557 ++++++ + drivers/staging/otus/hal/hpusb.c | 1584 ++++++ + drivers/staging/otus/hal/hpusb.h | 437 + + drivers/staging/otus/hal/otus.ini | 414 + + drivers/staging/otus/ioctl.c | 2936 ++++++++++++ + drivers/staging/otus/oal_dt.h | 60 + drivers/staging/otus/oal_marc.h | 135 + drivers/staging/otus/usbdrv.c | 1210 +++++ + drivers/staging/otus/usbdrv.h | 257 + + drivers/staging/otus/wrap_buf.c | 114 + drivers/staging/otus/wrap_dbg.c | 101 + drivers/staging/otus/wrap_ev.c | 283 + + drivers/staging/otus/wrap_mem.c | 101 + drivers/staging/otus/wrap_mis.c | 108 + drivers/staging/otus/wrap_pkt.c | 178 + drivers/staging/otus/wrap_sec.c | 127 + drivers/staging/otus/wrap_usb.c | 195 + drivers/staging/otus/wwrap.c | 1207 +++++ + drivers/staging/otus/zdcompat.h | 116 + drivers/staging/otus/zdusb.c | 295 + + drivers/staging/otus/zdusb.h | 43 + 79 files changed, 70415 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -45,4 +45,6 @@ source "drivers/staging/at76_usb/Kconfig + + source "drivers/staging/agnx/Kconfig" + ++source "drivers/staging/otus/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -14,3 +14,4 @@ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ + obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_USB_ATMEL) += at76_usb/ + obj-$(CONFIG_AGNX) += agnx/ ++obj-$(CONFIG_OTUS) += otus/ +--- /dev/null ++++ b/drivers/staging/otus/80211core/amsdu.c +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfGetAmsduSubFrame */ ++/* Get a subframe from a-MSDU. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : A-MSDU frame buffer */ ++/* offset : offset of subframe in the A-MSDU */ ++/* */ ++/* OUTPUTS */ ++/* NULL or subframe */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++zbuf_t* zfGetAmsduSubFrame(zdev_t* dev, zbuf_t* buf, u16_t* offset) ++{ ++ u16_t subframeLen; ++ u16_t amsduLen = zfwBufGetSize(dev, buf); ++ zbuf_t* newBuf; ++ ++ ZM_PERFORMANCE_RX_AMSDU(dev, buf, amsduLen); ++ ++ /* Verify A-MSDU length */ ++ if (amsduLen < (*offset + 14)) ++ { ++ return NULL; ++ } ++ ++ /* Locate A-MSDU subframe by offset and verify subframe length */ ++ subframeLen = (zmw_buf_readb(dev, buf, *offset + 12) << 8) + ++ zmw_buf_readb(dev, buf, *offset + 13); ++ if (subframeLen == 0) ++ { ++ return NULL; ++ } ++ ++ /* Verify A-MSDU subframe length */ ++ if ((*offset+14+subframeLen) <= amsduLen) ++ { ++ /* Allocate a new buffer */ ++ if ((newBuf = zfwBufAllocate(dev, 24+2+subframeLen)) != NULL) ++ { ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ /* Copy and convert subframe to wlan frame format */ ++ /* SHALL NOT INCLUDE QOS and AMSDU header. Ray 20070807 For Vista */ ++ zfRxBufferCopy(dev, newBuf, buf, 0, 0, 24); ++ zfRxBufferCopy(dev, newBuf, buf, 24, *offset+14, subframeLen); ++ zfwBufSetSize(dev, newBuf, 24+subframeLen); ++#else ++ /* Copy subframe to new buffer */ ++ zfRxBufferCopy(dev, newBuf, buf, 0, *offset, 14+subframeLen); ++ zfwBufSetSize(dev, newBuf, 14+subframeLen); ++#endif ++ /* Update offset */ ++ *offset += (((14+subframeLen)+3) & 0xfffc); ++ ++ /* Return buffer pointer */ ++ return newBuf; ++ } ++ } ++ return NULL; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfDeAmsdu */ ++/* De-AMSDU. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : A-MSDU frame buffer */ ++/* vap : VAP port */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++void zfDeAmsdu(zdev_t* dev, zbuf_t* buf, u16_t vap, u8_t encryMode) ++{ ++ u16_t offset = ZM_SIZE_OF_WLAN_DATA_HEADER+ZM_SIZE_OF_QOS_CTRL; ++ zbuf_t* subframeBuf; ++ zmw_get_wlan_dev(dev); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ if (encryMode == ZM_AES || encryMode == ZM_TKIP) ++ { ++ offset += (ZM_SIZE_OF_IV + ZM_SIZE_OF_EXT_IV); ++ } ++ else if (encryMode == ZM_WEP64 || encryMode == ZM_WEP128) ++ { ++ offset += ZM_SIZE_OF_IV; ++ } ++ ++ /* Repeatly calling zfGetAmsduSubFrame() until NULL returned */ ++ while ((subframeBuf = zfGetAmsduSubFrame(dev, buf, &offset)) != NULL) ++ { ++ wd->commTally.NotifyNDISRxFrmCnt++; ++ if (wd->zfcbRecvEth != NULL) ++ { ++ wd->zfcbRecvEth(dev, subframeBuf, (u8_t)vap); ++ ZM_PERFORMANCE_RX_MSDU(dev, wd->tick); ++ } ++ } ++ zfwBufFree(dev, buf, 0); ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cagg.c +@@ -0,0 +1,3611 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : cagg.c */ ++/* */ ++/* Abstract */ ++/* This module contains A-MPDU aggregation related functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#include "cprecomp.h" ++ ++extern u8_t zcUpToAc[8]; ++const u8_t pri[] = {3,3,2,3,2,1,3,2,1,0}; ++ ++ ++u16_t aggr_count; ++u32_t success_mpdu; ++u32_t total_mpdu; ++ ++void zfAggInit(zdev_t* dev) ++{ ++ u16_t i,j; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ /* ++ * reset sta information ++ */ ++ ++ zmw_enter_critical_section(dev); ++ wd->aggInitiated = 0; ++ wd->addbaComplete = 0; ++ wd->addbaCount = 0; ++ wd->reorder = 1; ++ for (i=0; iaggSta[i].aggQNumber[j] = ZM_AGG_POOL_SIZE; ++ wd->aggSta[i].aggFlag[j] = wd->aggSta[i].count[j] = 0; ++ wd->aggSta[i].tid_tx[j] = NULL; ++ wd->aggSta[i].tid_tx[j+1] = NULL; ++ ++ } ++ } ++ ++ /* ++ * reset Tx/Rx aggregation queue information ++ */ ++ wd->aggState = 0; ++ for (i=0; iaggQPool[i] = zfwMemAllocate(dev, sizeof(struct aggQueue)); ++ if(!wd->aggQPool[i]) ++ { ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ wd->aggQPool[i]->aggHead = wd->aggQPool[i]->aggTail = ++ wd->aggQPool[i]->aggQEnabled = wd->aggQPool[i]->aggReady = ++ wd->aggQPool[i]->clearFlag = wd->aggQPool[i]->deleteFlag = 0; ++ //wd->aggQPool[i]->aggSize = 16; ++ ++ /* ++ * reset rx aggregation queue ++ */ ++ wd->tid_rx[i] = zfwMemAllocate(dev, sizeof(struct agg_tid_rx)); ++ if (!wd->tid_rx[i]) ++ { ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ wd->tid_rx[i]->aid = ZM_MAX_STA_SUPPORT; ++ wd->tid_rx[i]->seq_start = wd->tid_rx[i]->baw_head = \ ++ wd->tid_rx[i]->baw_tail = 0; ++ wd->tid_rx[i]->sq_exceed_count = wd->tid_rx[i]->sq_behind_count = 0; ++ for (j=0; j<=ZM_AGG_BAW_SIZE; j++) ++ wd->tid_rx[i]->frame[j].buf = 0; ++ /* ++ * reset ADDBA exchange status code ++ * 0: NULL ++ * 1: ADDBA Request sent/received ++ * 2: ACK for ADDBA Request sent/received ++ * 3: ADDBA Response sent/received ++ * 4: ACK for ADDBA Response sent/received ++ */ ++ wd->tid_rx[i]->addBaExchangeStatusCode = 0; ++ ++ } ++ zmw_leave_critical_section(dev); ++ zfAggTallyReset(dev); ++ DESTQ.init = zfAggDestInit; ++ DESTQ.init(dev); ++ wd->aggInitiated = 1; ++ aggr_count = 0; ++ success_mpdu = 0; ++ total_mpdu = 0; ++#ifdef ZM_ENABLE_AGGREGATION ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++ BAW = zfwMemAllocate(dev, sizeof(struct baw_enabler)); ++ if(!BAW) ++ { ++ return; ++ } ++ BAW->init = zfBawInit; ++ BAW->init(dev); ++#endif //disable BAW ++#endif ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggGetSta */ ++/* return STA AID. */ ++/* take buf as input, use the dest address of buf as index to */ ++/* search STA AID. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer for one particular packet */ ++/* */ ++/* OUTPUTS */ ++/* AID */ ++/* */ ++/* AUTHOR */ ++/* Honda ZyDAS Technology Corporation 2006.11 */ ++/* */ ++/************************************************************************/ ++ ++ ++ ++u16_t zfAggGetSta(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t id; ++ u16_t dst[3]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ dst[0] = zmw_rx_buf_readh(dev, buf, 0); ++ dst[1] = zmw_rx_buf_readh(dev, buf, 2); ++ dst[2] = zmw_rx_buf_readh(dev, buf, 4); ++ ++ zmw_enter_critical_section(dev); ++ ++ if(wd->wlanMode == ZM_MODE_AP) { ++ id = zfApFindSta(dev, dst); ++ } ++ else { ++ id = 0; ++ } ++ zmw_leave_critical_section(dev); ++ ++#if ZM_AGG_FPGA_DEBUG ++ id = 0; ++#endif ++ ++ return id; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxGetQueue */ ++/* return Queue Pool index. */ ++/* take aid as input, look for the queue index associated */ ++/* with this aid. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* aid : associated id */ ++/* */ ++/* OUTPUTS */ ++/* Queue number */ ++/* */ ++/* AUTHOR */ ++/* Honda ZyDAS Technology Corporation 2006.11 */ ++/* */ ++/************************************************************************/ ++TID_TX zfAggTxGetQueue(zdev_t* dev, u16_t aid, u16_t tid) ++{ ++ //u16_t i; ++ TID_TX tid_tx; ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ /* ++ * not a STA aid ++ */ ++ if (0xffff == aid) ++ return NULL; ++ ++ //zmw_enter_critical_section(dev); ++ ++ tid_tx = wd->aggSta[aid].tid_tx[tid]; ++ if (!tid_tx) return NULL; ++ if (0 == tid_tx->aggQEnabled) ++ return NULL; ++ ++ //zmw_leave_critical_section(dev); ++ ++ return tid_tx; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxNewQueue */ ++/* return Queue Pool index. */ ++/* take aid as input, find a new queue for this aid. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* aid : associated id */ ++/* */ ++/* OUTPUTS */ ++/* Queue number */ ++/* */ ++/* AUTHOR */ ++/* Honda ZyDAS Technology Corporation 2006.12 */ ++/* */ ++/************************************************************************/ ++TID_TX zfAggTxNewQueue(zdev_t* dev, u16_t aid, u16_t tid, zbuf_t* buf) ++{ ++ u16_t i; ++ TID_TX tid_tx=NULL; ++ u16_t ac = zcUpToAc[tid&0x7] & 0x3; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* ++ * not a STA aid ++ */ ++ if (0xffff == aid) ++ return NULL; ++ ++ zmw_enter_critical_section(dev); ++ ++ /* ++ * find one new queue for sta ++ */ ++ for (i=0; iaggQPool[i]->aggQEnabled) ++ { ++ /* ++ * this q is enabled ++ */ ++ } ++ else ++ { ++ tid_tx = wd->aggQPool[i]; ++ tid_tx->aggQEnabled = 1; ++ tid_tx->aggQSTA = aid; ++ tid_tx->ac = ac; ++ tid_tx->tid = tid; ++ tid_tx->aggHead = tid_tx->aggTail = tid_tx->size = 0; ++ tid_tx->aggReady = 0; ++ wd->aggSta[aid].tid_tx[tid] = tid_tx; ++ tid_tx->dst[0] = zmw_rx_buf_readh(dev, buf, 0); ++ tid_tx->dst[1] = zmw_rx_buf_readh(dev, buf, 2); ++ tid_tx->dst[2] = zmw_rx_buf_readh(dev, buf, 4); ++ break; ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return tid_tx; ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxEnqueue */ ++/* return Status code ZM_SUCCESS or error code */ ++/* take (aid,ac,qnum,buf) as input */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* aid : associated id */ ++/* ac : access category */ ++/* qnum: the queue number to which will be enqueued */ ++/* buf : the packet to be queued */ ++/* */ ++/* OUTPUTS */ ++/* status code */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTxEnqueue(zdev_t* dev, zbuf_t* buf, u16_t aid, TID_TX tid_tx) ++{ ++ //u16_t qlen, frameLen; ++ u32_t time; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ ++ if (tid_tx->size < (ZM_AGGQ_SIZE - 2)) ++ { ++ /* Queue not full */ ++ ++ ++ /* ++ * buffer copy ++ * in zfwBufFree will return a ndismsendcomplete ++ * to resolve the synchronize problem in aggregate ++ */ ++ ++ u8_t sendComplete = 0; ++ ++ tid_tx->aggvtxq[tid_tx->aggHead].buf = buf; ++ time = zm_agg_GetTime(); ++ tid_tx->aggvtxq[tid_tx->aggHead].arrivalTime = time; ++ tid_tx->aggvtxq[tid_tx->aggHead].baw_retransmit = 0; ++ ++ tid_tx->aggHead = ((tid_tx->aggHead + 1) & ZM_AGGQ_SIZE_MASK); ++ tid_tx->lastArrival = time; ++ tid_tx->size++; ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ if (buf && (tid_tx->size < (ZM_AGGQ_SIZE - 10))) { ++ tid_tx->complete = tid_tx->aggHead; ++ sendComplete = 1; ++ } ++ zmw_leave_critical_section(dev); ++ ++ if (!DESTQ.exist(dev, 0, tid_tx->ac, tid_tx, NULL)) { ++ DESTQ.insert(dev, 0, tid_tx->ac, tid_tx, NULL); ++ } ++ ++ zm_msg1_agg(ZM_LV_0, "tid_tx->size=", tid_tx->size); ++ //zm_debug_msg1("tid_tx->size=", tid_tx->size); ++ ++ if (buf && sendComplete && wd->zfcbSendCompleteIndication) { ++ //zmw_leave_critical_section(dev); ++ wd->zfcbSendCompleteIndication(dev, buf); ++ } ++ ++ /*if (tid_tx->size >= 16 && zfHpGetFreeTxdCount(dev) > 20) ++ zfAggTxSend(dev, zfHpGetFreeTxdCount(dev), tid_tx); ++ */ ++ return ZM_SUCCESS; ++ } ++ else ++ { ++ zm_msg1_agg(ZM_LV_0, "can't enqueue, tid_tx->size=", tid_tx->size); ++ /* ++ * Queue Full ++ */ ++ ++ /* ++ * zm_msg1_agg(ZM_LV_0, "Queue full, qnum = ", qnum); ++ * wd->commTally.txQosDropCount[ac]++; ++ * zfwBufFree(dev, buf, ZM_SUCCESS); ++ * zm_msg1_agg(ZM_LV_1, "Packet discarded, VTXQ full, ac=", ac); ++ * ++ * return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; ++ */ ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (!DESTQ.exist(dev, 0, tid_tx->ac, tid_tx, NULL)) { ++ DESTQ.insert(dev, 0, tid_tx->ac, tid_tx, NULL); ++ } ++ ++ return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; ++} ++ ++u16_t zfAggDestExist(zdev_t* dev, u16_t Qtype, u16_t ac, TID_TX tid_tx, void* vtxq) { ++ struct dest* dest; ++ u16_t exist = 0; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (!DESTQ.Head[ac]) { ++ exist = 0; ++ } ++ else { ++ dest = DESTQ.Head[ac]; ++ if (dest->tid_tx == tid_tx) { ++ exist = 1; ++ } ++ else { ++ while (dest->next != DESTQ.Head[ac]) { ++ dest = dest->next; ++ if (dest->tid_tx == tid_tx){ ++ exist = 1; ++ break; ++ } ++ } ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return exist; ++} ++ ++void zfAggDestInsert(zdev_t* dev, u16_t Qtype, u16_t ac, TID_TX tid_tx, void* vtxq) ++{ ++ struct dest* new_dest; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ new_dest = zfwMemAllocate(dev, sizeof(struct dest)); ++ if(!new_dest) ++ { ++ return; ++ } ++ new_dest->Qtype = Qtype; ++ new_dest->tid_tx = tid_tx; ++ if (0 == Qtype) ++ new_dest->tid_tx = tid_tx; ++ else ++ new_dest->vtxq = vtxq; ++ if (!DESTQ.Head[ac]) { ++ ++ zmw_enter_critical_section(dev); ++ new_dest->next = new_dest; ++ DESTQ.Head[ac] = DESTQ.dest[ac] = new_dest; ++ zmw_leave_critical_section(dev); ++ } ++ else { ++ ++ zmw_enter_critical_section(dev); ++ new_dest->next = DESTQ.dest[ac]->next; ++ DESTQ.dest[ac]->next = new_dest; ++ zmw_leave_critical_section(dev); ++ } ++ ++ ++ //DESTQ.size[ac]++; ++ return; ++} ++ ++void zfAggDestDelete(zdev_t* dev, u16_t Qtype, TID_TX tid_tx, void* vtxq) ++{ ++ struct dest* dest, *temp; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (wd->destLock) { ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ ++ ++ //zmw_declare_for_critical_section(); ++ for (i=0; i<4; i++) { ++ if (!DESTQ.Head[i]) continue; ++ dest = DESTQ.Head[i]; ++ if (!dest) continue; ++ ++ ++ while (dest && (dest->next != DESTQ.Head[i])) { ++ if (Qtype == 0 && dest->next->tid_tx == tid_tx){ ++ break; ++ } ++ if (Qtype == 1 && dest->next->vtxq == vtxq) { ++ break; ++ } ++ dest = dest->next; ++ } ++ ++ if ((Qtype == 0 && dest->next->tid_tx == tid_tx) || (Qtype == 1 && dest->next->vtxq == vtxq)) { ++ ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ if (tid_tx->size) { ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ if (!DESTQ.Head[i]) { ++ temp = NULL; ++ } ++ else { ++ temp = dest->next; ++ if (temp == dest) { ++ DESTQ.Head[i] = DESTQ.dest[i] = NULL; ++ //DESTQ.size[i] = 0; ++ } ++ else { ++ dest->next = dest->next->next; ++ } ++ } ++ ++ if (temp == NULL) ++ {/* do nothing */} //zfwMemFree(dev, temp, sizeof(struct dest)); ++ else ++ zfwMemFree(dev, temp, sizeof(struct dest)); ++ ++ /*zmw_enter_critical_section(dev); ++ if (DESTQ.size[i] > 0) ++ DESTQ.size[i]--; ++ zmw_leave_critical_section(dev); ++ */ ++ } ++ ++ } ++ zmw_leave_critical_section(dev); ++ return; ++} ++ ++void zfAggDestInit(zdev_t* dev) ++{ ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ for (i=0; i<4; i++) { ++ //wd->destQ.Head[i].next = wd->destQ.Head[i]; ++ //wd->destQ.dest[i] = wd->destQ.Head[i]; ++ //DESTQ.size[i] = 0; ++ DESTQ.Head[i] = NULL; ++ } ++ DESTQ.insert = zfAggDestInsert; ++ DESTQ.delete = zfAggDestDelete; ++ DESTQ.init = zfAggDestInit; ++ DESTQ.getNext = zfAggDestGetNext; ++ DESTQ.exist = zfAggDestExist; ++ DESTQ.ppri = 0; ++ return; ++} ++ ++struct dest* zfAggDestGetNext(zdev_t* dev, u16_t ac) ++{ ++ struct dest *dest = NULL; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (DESTQ.dest[ac]) { ++ dest = DESTQ.dest[ac]; ++ DESTQ.dest[ac] = DESTQ.dest[ac]->next; ++ } ++ else { ++ dest = NULL; ++ } ++ zmw_leave_critical_section(dev); ++ ++ return dest; ++} ++ ++#ifdef ZM_ENABLE_AGGREGATION ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++u16_t zfAggTidTxInsertHead(zdev_t* dev, struct bufInfo *buf_info,TID_TX tid_tx) ++{ ++ zbuf_t* buf; ++ u32_t time; ++ struct baw_header *baw_header; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ ++ buf = buf_info->buf; ++ ++ zmw_enter_critical_section(dev); ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ zmw_leave_critical_section(dev); ++ ++ if (tid_tx->size >= (ZM_AGGQ_SIZE - 2)) { ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ return 0; ++ } ++ ++ zmw_enter_critical_section(dev); ++ tid_tx->aggTail = (tid_tx->aggTail == 0)? ZM_AGGQ_SIZE_MASK: tid_tx->aggTail - 1; ++ tid_tx->aggvtxq[tid_tx->aggTail].buf = buf; ++ //time = zm_agg_GetTime(); ++ tid_tx->aggvtxq[tid_tx->aggTail].arrivalTime = buf_info->timestamp; ++ tid_tx->aggvtxq[tid_tx->aggTail].baw_retransmit = buf_info->baw_retransmit; ++ ++ baw_header = &tid_tx->aggvtxq[tid_tx->aggTail].baw_header; ++ baw_header->headerLen = buf_info->baw_header->headerLen; ++ baw_header->micLen = buf_info->baw_header->micLen; ++ baw_header->snapLen = buf_info->baw_header->snapLen; ++ baw_header->removeLen = buf_info->baw_header->removeLen; ++ baw_header->keyIdx = buf_info->baw_header->keyIdx; ++ zfwMemoryCopy((u8_t *)baw_header->header, (u8_t *)buf_info->baw_header->header, 58); ++ zfwMemoryCopy((u8_t *)baw_header->mic , (u8_t *)buf_info->baw_header->mic , 8); ++ zfwMemoryCopy((u8_t *)baw_header->snap , (u8_t *)buf_info->baw_header->snap , 8); ++ ++ tid_tx->size++; ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ zmw_leave_critical_section(dev); ++ ++ //tid_tx->lastArrival = time; ++ if (1 == tid_tx->size) { ++ DESTQ.insert(dev, 0, tid_tx->ac, tid_tx, NULL); ++ } ++ ++ ++ zm_msg1_agg(ZM_LV_0, "0xC2:insertHead, tid_tx->size=", tid_tx->size); ++ ++ return TRUE; ++} ++#endif //disable BAW ++#endif ++ ++void zfiTxComplete(zdev_t* dev) ++{ ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ if( (wd->wlanMode == ZM_MODE_AP) || ++ (wd->wlanMode == ZM_MODE_INFRASTRUCTURE && wd->sta.EnableHT) || ++ (wd->wlanMode == ZM_MODE_PSEUDO) ) { ++ zfAggTxScheduler(dev, 0); ++ } ++ ++ return; ++} ++ ++TID_TX zfAggTxReady(zdev_t* dev) { ++ //struct dest* dest; ++ u16_t i; ++ TID_TX tid_tx = NULL; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ for (i=0; iaggQPool[i]->aggQEnabled) ++ { ++ if (wd->aggQPool[i]->size >= 16) { ++ tid_tx = wd->aggQPool[i]; ++ break; ++ } ++ } ++ else { ++ } ++ } ++ zmw_leave_critical_section(dev); ++ return tid_tx; ++} ++ ++u16_t zfAggValidTidTx(zdev_t* dev, TID_TX tid_tx) { ++ u16_t i, valid = 0; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ for (i=0; iaggQPool[i] == tid_tx) ++ { ++ valid = 1; ++ break; ++ } ++ else { ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++ return valid; ++} ++ ++void zfAggTxScheduler(zdev_t* dev, u8_t ScanAndClear) ++{ ++ TID_TX tid_tx = NULL; ++ void* vtxq; ++ struct dest* dest; ++ zbuf_t* buf; ++ u32_t txql, min_txql; ++ //u16_t aggr_size = 1; ++ u16_t txq_threshold; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if (!wd->aggInitiated) ++ { ++ return; ++ } ++ ++ /* debug */ ++ txql = TXQL; ++ min_txql = AGG_MIN_TXQL; ++ ++ if(wd->txq_threshold) ++ txq_threshold = wd->txq_threshold; ++ else ++ txq_threshold = AGG_MIN_TXQL; ++ ++ tid_tx = zfAggTxReady(dev); ++ if (tid_tx) ScanAndClear = 0; ++ while (zfHpGetFreeTxdCount(dev) > 20 && (TXQL < txq_threshold || tid_tx)) { ++ //while (zfHpGetFreeTxdCount(dev) > 20 && (ScanAndClear || tid_tx)) { ++ //while (TXQL < txq_threshold) { ++ u16_t i; ++ u8_t ac; ++ s8_t destQ_count = 0; ++ //while ((zfHpGetFreeTxdCount(dev)) > 32) { ++ ++ //DbgPrint("zfAggTxScheduler: in while loop"); ++ for (i=0; i<4; i++) { ++ if (DESTQ.Head[i]) destQ_count++; ++ } ++ if (0 >= destQ_count) break; ++ ++ zmw_enter_critical_section(dev); ++ ac = pri[DESTQ.ppri]; DESTQ.ppri = (DESTQ.ppri + 1) % 10; ++ zmw_leave_critical_section(dev); ++ ++ for (i=0; i<10; i++){ ++ if(DESTQ.Head[ac]) break; ++ ++ zmw_enter_critical_section(dev); ++ ac = pri[DESTQ.ppri]; DESTQ.ppri = (DESTQ.ppri + 1) % 10; ++ zmw_leave_critical_section(dev); ++ } ++ if (i == 10) break; ++ //DbgPrint("zfAggTxScheduler: have dest Q"); ++ zmw_enter_critical_section(dev); ++ wd->destLock = 1; ++ zmw_leave_critical_section(dev); ++ ++ dest = DESTQ.getNext(dev, ac); ++ if (!dest) { ++ zmw_enter_critical_section(dev); ++ wd->destLock = 0; ++ zmw_leave_critical_section(dev); ++ ++ DbgPrint("bug report! DESTQ.getNext got nothing!"); ++ break; ++ } ++ if (dest->Qtype == 0) { ++ tid_tx = dest->tid_tx; ++ ++ //DbgPrint("zfAggTxScheduler: have tid_tx Q"); ++ ++ if(tid_tx && zfAggValidTidTx(dev, tid_tx)) ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ else { ++ zmw_enter_critical_section(dev); ++ wd->destLock = 0; ++ zmw_leave_critical_section(dev); ++ ++ tid_tx = zfAggTxReady(dev); ++ continue; ++ } ++ ++ zmw_enter_critical_section(dev); ++ wd->destLock = 0; ++ zmw_leave_critical_section(dev); ++ //zmw_enter_critical_section(dev); ++ if (tid_tx && !tid_tx->size) { ++ ++ //zmw_leave_critical_section(dev); ++ //DESTQ.delete(dev, 0, tid_tx, NULL); ++ } ++ else if(wd->aggState == 0){ ++ //wd->aggState = 1; ++ //zmw_leave_critical_section(dev); ++ zfAggTxSend(dev, zfHpGetFreeTxdCount(dev), tid_tx); ++ //wd->aggState = 0; ++ } ++ else { ++ //zmw_leave_critical_section(dev); ++ break; ++ } ++ } ++ else { ++ vtxq = dest->vtxq; ++ buf = zfGetVtxq(dev, ac); ++ zm_assert( buf != 0 ); ++ ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ ++ } ++ /*flush all but < 16 frames in tid_tx to TXQ*/ ++ tid_tx = zfAggTxReady(dev); ++ } ++ ++ /*while ((zfHpGetFreeTxdCount(dev)) > 32) { ++ //while ((zfHpGetFreeTxdCount(dev)) > 32) { ++ ++ destQ_count = 0; ++ for (i=0; i<4; i++) destQ_count += wd->destQ.size[i]; ++ if (0 >= destQ_count) break; ++ ++ ac = pri[wd->destQ.ppri]; wd->destQ.ppri = (wd->destQ.ppri + 1) % 10; ++ for (i=0; i<10; i++){ ++ if(wd->destQ.size[ac]!=0) break; ++ ac = pri[wd->destQ.ppri]; wd->destQ.ppri = (wd->destQ.ppri + 1) % 10; ++ } ++ if (i == 10) break; ++ dest = wd->destQ.getNext(dev, ac); ++ if (dest->Qtype == 0) { ++ tid_tx = dest->tid_tx; ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ if (!tid_tx->size) { ++ wd->destQ.delete(dev, 0, tid_tx, NULL); ++ break; ++ } ++ else if((wd->aggState == 0) && (tid_tx->size >= 16)){ ++ zfAggTxSend(dev, zfHpGetFreeTxdCount(dev), tid_tx); ++ } ++ else { ++ break; ++ } ++ } ++ ++ } ++ */ ++ return; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTx */ ++/* return Status code ZM_SUCCESS or error code */ ++/* management A-MPDU aggregation function, */ ++/* management aggregation queue, calculate arrivalrate, */ ++/* add/delete an aggregation queue of a stream, */ ++/* enqueue packets into responsible aggregate queue. */ ++/* take (dev, buf, ac) as input */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : packet buff */ ++/* ac : access category */ ++/* */ ++/* OUTPUTS */ ++/* status code */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTx(zdev_t* dev, zbuf_t* buf, u16_t tid) ++{ ++ u16_t aid; ++ //u16_t qnum; ++ //u16_t aggflag = 0; ++ //u16_t arrivalrate = 0; ++ TID_TX tid_tx; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if(!wd->aggInitiated) ++ { ++ return ZM_ERR_TX_BUFFER_UNAVAILABLE; ++ } ++ ++ aid = zfAggGetSta(dev, buf); ++ ++ //arrivalrate = zfAggTxArrivalRate(dev, aid, tid); ++ ++ if (0xffff == aid) ++ { ++ /* ++ * STA not associated, this is a BC/MC or STA->AP packet ++ */ ++ ++ return ZM_ERR_TX_BUFFER_UNAVAILABLE; ++ } ++ ++ /* ++ * STA associated, a unicast packet ++ */ ++ ++ tid_tx = zfAggTxGetQueue(dev, aid, tid); ++ ++ /*tid_q.tid_tx = tid_tx; ++ wd->destQ.insert = zfAggDestInsert; ++ wd->destQ.insert(dev, 0, tid_q); ++ */ ++ if (tid_tx != NULL) ++ { ++ /* ++ * this (aid, ac) is aggregated ++ */ ++ ++ //if (arrivalrate < ZM_AGG_LOW_THRESHOLD) ++ if (0) ++ { ++ /* ++ * arrival rate too low ++ * delete this aggregate queue ++ */ ++ ++ zmw_enter_critical_section(dev); ++ ++ //wd->aggQPool[qnum]->clearFlag = wd->aggQPool[qnum]->deleteFlag =1; ++ ++ zmw_leave_critical_section(dev); ++ ++ } ++ ++ return zfAggTxEnqueue(dev, buf, aid, tid_tx); ++ ++ } ++ else ++ { ++ /* ++ * this (aid, ac) not yet aggregated ++ * queue not found ++ */ ++ ++ //if (arrivalrate > ZM_AGG_HIGH_THRESHOLD) ++ if (1) ++ { ++ /* ++ * arrivalrate high enough to get a new agg queue ++ */ ++ ++ tid_tx = zfAggTxNewQueue(dev, aid, tid, buf); ++ ++ //zm_msg1_agg(ZM_LV_0, "get new AggQueue qnum = ", tid_tx->); ++ ++ if (tid_tx) ++ { ++ /* ++ * got a new aggregate queue ++ */ ++ ++ //zmw_enter_critical_section(dev); ++ ++ //wd->aggSta[aid].aggFlag[ac] = 1; ++ ++ //zmw_leave_critical_section(dev); ++ ++ /* ++ * add ADDBA functions here ++ * return ZM_ERR_TX_BUFFER_UNAVAILABLE; ++ */ ++ ++ ++ //zfAggSendAddbaRequest(dev, tid_tx->dst, tid_tx->ac, tid_tx->tid); ++ //zmw_enter_critical_section(dev); ++ ++ //wd->aggSta[aid].aggFlag[ac] = 0; ++ ++ //zmw_leave_critical_section(dev); ++ ++ return zfAggTxEnqueue(dev, buf, aid, tid_tx); ++ ++ } ++ else ++ { ++ /* ++ * just can't get a new aggregate queue ++ */ ++ ++ return ZM_ERR_TX_BUFFER_UNAVAILABLE; ++ } ++ } ++ else ++ { ++ /* ++ * arrival rate is not high enough to get a new agg queue ++ */ ++ ++ return ZM_ERR_TX_BUFFER_UNAVAILABLE; ++ } ++ } ++ ++ ++ ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxReadyCount */ ++/* return counter of ready to aggregate queues. */ ++/* take (dev, ac) as input, only calculate the ready to aggregate */ ++/* queues of one particular ac. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* ac : access category */ ++/* */ ++/* OUTPUTS */ ++/* counter of ready to aggregate queues */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTxReadyCount(zdev_t* dev, u16_t ac) ++{ ++ u16_t i; ++ u16_t readycount = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ for (i=0 ; iaggQPool[i]->aggQEnabled && (wd->aggQPool[i]->aggReady || \ ++ wd->aggQPool[i]->clearFlag) && ac == wd->aggQPool[i]->ac) ++ readycount++; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return readycount; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxPartial */ ++/* return the number that Vtxq has to send. */ ++/* take (dev, ac, readycount) as input, calculate the ratio of */ ++/* Vtxq length to (Vtxq length + readycount) of a particular ac, */ ++/* and returns the Vtxq length * the ratio */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* ac : access category */ ++/* readycount: the number of ready to aggregate queues of this ac */ ++/* */ ++/* OUTPUTS */ ++/* Vtxq length * ratio */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTxPartial(zdev_t* dev, u16_t ac, u16_t readycount) ++{ ++ u16_t qlen; ++ u16_t partial; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ qlen = zm_agg_qlen(dev, wd->vtxqHead[ac], wd->vtxqTail[ac]); ++ ++ if ((qlen + readycount) > 0) ++ { ++ partial = (u16_t)( zm_agg_weight(ac) * ((u16_t)qlen/(qlen + \ ++ readycount)) ); ++ } ++ else ++ { ++ partial = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (partial > qlen) ++ partial = qlen; ++ ++ return partial; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxSend */ ++/* return sentcount */ ++/* take (dev, ac, n) as input, n is the number of scheduled agg */ ++/* queues to be sent of the particular ac. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* ac : access category */ ++/* n : the number of scheduled aggregation queues to be sent */ ++/* */ ++/* OUTPUTS */ ++/* sentcount */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTxSend(zdev_t* dev, u32_t freeTxd, TID_TX tid_tx) ++{ ++ //u16_t qnum; ++ //u16_t qlen; ++ u16_t j; ++ //u16_t sentcount = 0; ++ zbuf_t* buf; ++ struct aggControl aggControl; ++ u16_t aggLen; ++ //zbuf_t* newBuf; ++ //u16_t bufLen; ++ //TID_BAW tid_baw = NULL; ++ //struct bufInfo *buf_info; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ //while (tid_tx->size > 0) ++ ++ zmw_enter_critical_section(dev); ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ aggLen = zm_agg_min(16, zm_agg_min(tid_tx->size, (u16_t)(freeTxd - 2))); ++ zmw_leave_critical_section(dev); ++ ++ /* ++ * why there have to be 2 free Txd? ++ */ ++ if (aggLen <=0 ) ++ return 0; ++ ++ ++ if (aggLen == 1) { ++ buf = zfAggTxGetVtxq(dev, tid_tx); ++ if (buf) ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ if (tid_tx->size == 0) { ++ //DESTQ.delete(dev, 0, tid_tx, NULL); ++ } ++ ++ return 1; ++ } ++ /* ++ * Free Txd queue is big enough to put aggregation ++ */ ++ zmw_enter_critical_section(dev); ++ if (wd->aggState == 1) { ++ zmw_leave_critical_section(dev); ++ return 0; ++ } ++ wd->aggState = 1; ++ zmw_leave_critical_section(dev); ++ ++ ++ zm_msg1_agg(ZM_LV_0, "aggLen=", aggLen); ++ tid_tx->aggFrameSize = 0; ++ for (j=0; j < aggLen; j++) { ++ buf = zfAggTxGetVtxq(dev, tid_tx); ++ ++ zmw_enter_critical_section(dev); ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ zmw_leave_critical_section(dev); ++ ++ if ( buf ) { ++ //struct aggTally *agg_tal; ++ u16_t completeIndex; ++ ++ if (0 == j) { ++ aggControl.ampduIndication = ZM_AGG_FIRST_MPDU; ++ ++ } ++ else if ((j == (aggLen - 1)) || tid_tx->size == 0) ++ { ++ aggControl.ampduIndication = ZM_AGG_LAST_MPDU; ++ //wd->aggState = 0; ++ ++ } ++ else ++ { ++ aggControl.ampduIndication = ZM_AGG_MIDDLE_MPDU; ++ /* the packet is delayed more than 500 ms, drop it */ ++ ++ } ++ tid_tx->aggFrameSize += zfwBufGetSize(dev, buf); ++ aggControl.addbaIndication = 0; ++ aggControl.aggEnabled = 1; ++ ++#ifdef ZM_AGG_TALLY ++ agg_tal = &wd->agg_tal; ++ agg_tal->sent_packets_sum++; ++ ++#endif ++ ++ zfAggTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0, &aggControl, tid_tx); ++ ++ zmw_enter_critical_section(dev); ++ completeIndex = tid_tx->complete; ++ if(zm_agg_inQ(tid_tx, tid_tx->complete)) ++ zm_agg_plus(tid_tx->complete); ++ zmw_leave_critical_section(dev); ++ ++ if(zm_agg_inQ(tid_tx, completeIndex) && wd->zfcbSendCompleteIndication ++ && tid_tx->aggvtxq[completeIndex].buf) { ++ wd->zfcbSendCompleteIndication(dev, tid_tx->aggvtxq[completeIndex].buf); ++ zm_debug_msg0("in queue complete worked!"); ++ } ++ ++ } ++ else { ++ /* ++ * this aggregation queue is empty ++ */ ++ zm_msg1_agg(ZM_LV_0, "aggLen not reached, but no more frame, j=", j); ++ ++ break; ++ } ++ } ++ zmw_enter_critical_section(dev); ++ wd->aggState = 0; ++ zmw_leave_critical_section(dev); ++ ++ //zm_acquire_agg_spin_lock(Adapter); ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ //zm_release_agg_spin_lock(Adapter); ++ ++ if (tid_tx->size == 0) { ++ //DESTQ.delete(dev, 0, tid_tx, NULL); ++ } ++ ++ ++ ++ //zfAggInvokeBar(dev, tid_tx); ++ if(j>0) { ++ aggr_count++; ++ zm_msg1_agg(ZM_LV_0, "0xC2:sent 1 aggr, aggr_count=", aggr_count); ++ zm_msg1_agg(ZM_LV_0, "0xC2:sent 1 aggr, aggr_size=", j); ++ } ++ return j; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxGetReadyQueue */ ++/* return the number of the aggregation queue */ ++/* take (dev, ac) as input, find the agg queue with smallest */ ++/* arrival time (waited longest) among those ready or clearFlag */ ++/* set queues. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* ac : access category */ ++/* */ ++/* OUTPUTS */ ++/* aggregation queue number */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++TID_TX zfAggTxGetReadyQueue(zdev_t* dev, u16_t ac) ++{ ++ //u16_t qnum = ZM_AGG_POOL_SIZE; ++ u16_t i; ++ u32_t time = 0; ++ TID_TX tid_tx = NULL; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ for (i=0 ;iaggQPool[i]->aggQEnabled && ac == wd->aggQPool[i]->ac && ++ (wd->aggQPool[i]->size > 0)) ++ { ++ if (0 == time || time > wd->aggQPool[i]->aggvtxq[ \ ++ wd->aggQPool[i]->aggHead ].arrivalTime) ++ { ++ tid_tx = wd->aggQPool[i]; ++ time = tid_tx->aggvtxq[ tid_tx->aggHead ].arrivalTime; ++ } ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return tid_tx; ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxGetVtxq */ ++/* return an MSDU */ ++/* take (dev, qnum) as input, return an MSDU out of the agg queue. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* qnum: queue number */ ++/* */ ++/* OUTPUTS */ ++/* a MSDU */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++zbuf_t* zfAggTxGetVtxq(zdev_t* dev, TID_TX tid_tx) ++{ ++ zbuf_t* buf = NULL; ++ ++ zmw_declare_for_critical_section(); ++ ++ if (tid_tx->aggHead != tid_tx->aggTail) ++ { ++ buf = tid_tx->aggvtxq[ tid_tx->aggTail ].buf; ++ ++ tid_tx->aggvtxq[tid_tx->aggTail].buf = NULL; ++ ++ zmw_enter_critical_section(dev); ++ tid_tx->aggTail = ((tid_tx->aggTail + 1) & ZM_AGGQ_SIZE_MASK); ++ if(tid_tx->size > 0) tid_tx->size--; ++ tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail); ++ if (NULL == buf) { ++ //tid_tx->aggTail = tid_tx->aggHead = tid_tx->size = 0; ++ //zm_msg1_agg(ZM_LV_0, "GetVtxq buf == NULL, tid_tx->size=", tid_tx->size); ++ } ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ /* ++ * queue is empty ++ */ ++ zm_msg1_agg(ZM_LV_0, "tid_tx->aggHead == tid_tx->aggTail, tid_tx->size=", tid_tx->size); ++ ++ } ++ ++ if (zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail) != tid_tx->size) ++ zm_msg1_agg(ZM_LV_0, "qlen!=tid_tx->size! tid_tx->size=", tid_tx->size); ++ return buf; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxDeleteQueue */ ++/* return ZM_SUCCESS (can't fail) */ ++/* take (dev, qnum) as input, reset (delete) this aggregate queue, */ ++/* this queue is virtually returned to the aggregate queue pool. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* qnum: queue number */ ++/* */ ++/* OUTPUTS */ ++/* ZM_SUCCESS */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTxDeleteQueue(zdev_t* dev, u16_t qnum) ++{ ++ u16_t ac, tid; ++ struct aggQueue *tx_tid; ++ struct aggSta *agg_sta; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ tx_tid = wd->aggQPool[qnum]; ++ agg_sta = &wd->aggSta[tx_tid->aggQSTA]; ++ ac = tx_tid->ac; ++ tid = tx_tid->tid; ++ ++ zmw_enter_critical_section(dev); ++ ++ tx_tid->aggQEnabled = 0; ++ tx_tid->aggHead = tx_tid->aggTail = 0; ++ tx_tid->aggReady = 0; ++ tx_tid->clearFlag = tx_tid->deleteFlag = 0; ++ tx_tid->size = 0; ++ agg_sta->count[ac] = 0; ++ ++ agg_sta->tid_tx[tid] = NULL; ++ agg_sta->aggFlag[ac] = 0; ++ ++ zmw_leave_critical_section(dev); ++ ++ zm_msg1_agg(ZM_LV_0, "queue deleted! qnum=", qnum); ++ ++ return ZM_SUCCESS; ++} ++ ++#ifdef ZM_ENABLE_AGGREGATION ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++void zfBawCore(zdev_t* dev, u16_t baw_seq, u32_t bitmap, u16_t aggLen) { ++ TID_BAW tid_baw; ++ s16_t i; ++ zbuf_t* buf; ++ struct bufInfo *buf_info; ++ ++ zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ tid_baw = BAW->getQ(dev, baw_seq); ++ //tid_baw = NULL; ++ if (NULL == tid_baw) ++ return; ++ ++ total_mpdu += aggLen; ++ for (i = aggLen - 1; i>=0; i--) { ++ if (((bitmap >> i) & 0x1) == 0) { ++ buf_info = BAW->pop(dev, i, tid_baw); ++ buf = buf_info->buf; ++ if (buf) { ++ //wd->zfcbSetBawQ(dev, buf, 0); ++ zfAggTidTxInsertHead(dev, buf_info, tid_baw->tid_tx); ++ } ++ } ++ else { ++ success_mpdu++; ++ } ++ } ++ BAW->disable(dev, tid_baw); ++ zfAggTxScheduler(dev); ++ zm_debug_msg1("success_mpdu = ", success_mpdu); ++ zm_debug_msg1(" total_mpdu = ", total_mpdu); ++} ++ ++void zfBawInit(zdev_t* dev) { ++ TID_BAW tid_baw; ++ u16_t i,j; ++ zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ ++ for (i=0; itid_baw[i]; ++ for (j=0; jframe[j].buf = NULL; ++ } ++ tid_baw->enabled = tid_baw->head = tid_baw->tail = tid_baw->size = 0; ++ tid_baw->start_seq = 0; ++ } ++ BAW->delPoint = 0; ++ BAW->core = zfBawCore; ++ BAW->getNewQ = zfBawGetNewQ; ++ BAW->insert = zfBawInsert; ++ BAW->pop = zfBawPop; ++ BAW->enable = zfBawEnable; ++ BAW->disable = zfBawDisable; ++ BAW->getQ = zfBawGetQ; ++} ++ ++ ++ ++TID_BAW zfBawGetNewQ(zdev_t* dev, u16_t start_seq, TID_TX tid_tx) { ++ TID_BAW tid_baw=NULL; ++ TID_BAW next_baw=NULL; ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ ++ /* ++ for (i=0; itid_baw[i]; ++ if (FALSE == tid_baw->enabled) ++ break; ++ } ++ */ ++ ++ tid_baw = &BAW->tid_baw[BAW->delPoint]; ++ i = BAW->delPoint; ++ //if (ZM_BAW_POOL_SIZE == i) { ++ //return NULL; ++ // u8_t temp = BAW->delPoint; ++ // tid_baw = &BAW->tid_baw[BAW->delPoint]; ++ // BAW->disable(dev, tid_baw); ++ // BAW->delPoint = (BAW->delPoint < (ZM_BAW_POOL_SIZE - 1))? (BAW->delPoint + 1): 0; ++ // temp = BAW->delPoint; ++ //} ++ ++ zm_msg1_agg(ZM_LV_0, "get new tid_baw, index=", i); ++ BAW->delPoint = (i < (ZM_BAW_POOL_SIZE -1))? (i + 1): 0; ++ next_baw = &BAW->tid_baw[BAW->delPoint]; ++ if (1 == next_baw->enabled) BAW->disable(dev, next_baw); ++ ++ BAW->enable(dev, tid_baw, start_seq); ++ tid_baw->tid_tx = tid_tx; ++ ++ return tid_baw; ++} ++ ++u16_t zfBawInsert(zdev_t* dev, zbuf_t* buf, u16_t baw_seq, TID_BAW tid_baw, u8_t baw_retransmit, struct baw_header_r *header_r) { ++ //TID_BAW tid_baw; ++ //u16_t bufLen; ++ ++ //zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ ++ if(tid_baw->size < (ZM_VTXQ_SIZE - 1)) { ++ struct baw_header *baw_header = &tid_baw->frame[tid_baw->head].baw_header; ++ ++ baw_header->headerLen = header_r->headerLen; ++ baw_header->micLen = header_r->micLen; ++ baw_header->snapLen = header_r->snapLen; ++ baw_header->removeLen = header_r->removeLen; ++ baw_header->keyIdx = header_r->keyIdx; ++ zfwMemoryCopy((u8_t *)baw_header->header, (u8_t *)header_r->header, 58); ++ zfwMemoryCopy((u8_t *)baw_header->mic , (u8_t *)header_r->mic , 8); ++ zfwMemoryCopy((u8_t *)baw_header->snap , (u8_t *)header_r->snap , 8); ++ //wd->zfcbSetBawQ(dev, buf, 1); ++ tid_baw->frame[tid_baw->head].buf = buf; ++ tid_baw->frame[tid_baw->head].baw_seq = baw_seq; ++ tid_baw->frame[tid_baw->head].baw_retransmit = baw_retransmit + 1; ++ ++ //tid_baw->frame[tid_baw->head].data = pBuf->data; ++ tid_baw->head++; ++ tid_baw->size++; ++ } ++ else { ++ //wd->zfcbSetBawQ(dev, buf, 0); ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++struct bufInfo* zfBawPop(zdev_t* dev, u16_t index, TID_BAW tid_baw) { ++ //TID_BAW tid_baw; ++ //zbuf_t* buf; ++ struct bufInfo *buf_info; ++ zmw_get_wlan_dev(dev); ++ ++ buf_info = &wd->buf_info; ++ buf_info->baw_header = NULL; ++ ++ if (NULL == (buf_info->buf = tid_baw->frame[index].buf)) ++ return buf_info; ++ ++ buf_info->baw_retransmit = tid_baw->frame[index].baw_retransmit; ++ buf_info->baw_header = &tid_baw->frame[index].baw_header; ++ buf_info->timestamp = tid_baw->frame[index].timestamp; ++ //pBuf->data = pBuf->buffer; ++ //wd->zfcbRestoreBufData(dev, buf); ++ tid_baw->frame[index].buf = NULL; ++ ++ return buf_info; ++} ++ ++void zfBawEnable(zdev_t* dev, TID_BAW tid_baw, u16_t start_seq) { ++ //TID_BAW tid_baw; ++ ++ //zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ ++ tid_baw->enabled = TRUE; ++ tid_baw->head = tid_baw->tail = tid_baw->size = 0; ++ tid_baw->start_seq = start_seq; ++} ++ ++void zfBawDisable(zdev_t* dev, TID_BAW tid_baw) { ++ //TID_BAW tid_baw; ++ u16_t i; ++ ++ //zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ for (i=0; iframe[i].buf) { ++ ++ //wd->zfcbSetBawQ(dev, tid_baw->frame[i].buf, 0); ++ zfwBufFree(dev, tid_baw->frame[i].buf, ZM_SUCCESS); ++ tid_baw->frame[i].buf = NULL; ++ } ++ } ++ ++ tid_baw->enabled = FALSE; ++} ++ ++TID_BAW zfBawGetQ(zdev_t* dev, u16_t baw_seq) { ++ TID_BAW tid_baw=NULL; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ for (i=0; itid_baw[i]; ++ if (TRUE == tid_baw->enabled) ++ { ++ zm_msg1_agg(ZM_LV_0, "get an old tid_baw, baw_seq=", baw_seq); ++ zm_msg1_agg(ZM_LV_0, "check a tid_baw->start_seq=", tid_baw->start_seq); ++ if(baw_seq == tid_baw->start_seq) ++ break; ++ } ++ ++ } ++ if (ZM_BAW_POOL_SIZE == i) ++ return NULL; ++ return tid_baw; ++} ++#endif //disable BAW ++#endif ++ ++u16_t zfAggTallyReset(zdev_t* dev) ++{ ++ struct aggTally* agg_tal; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ agg_tal = &wd->agg_tal; ++ agg_tal->got_packets_sum = 0; ++ agg_tal->got_bytes_sum = 0; ++ agg_tal->sent_bytes_sum = 0; ++ agg_tal->sent_packets_sum = 0; ++ agg_tal->avg_got_packets = 0; ++ agg_tal->avg_got_bytes = 0; ++ agg_tal->avg_sent_packets = 0; ++ agg_tal->avg_sent_bytes = 0; ++ agg_tal->time = 0; ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggScanAndClear */ ++/* If the packets in a queue have waited for too long, clear and */ ++/* delete this aggregation queue. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* time : current time */ ++/* */ ++/* OUTPUTS */ ++/* ZM_SUCCESS */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggScanAndClear(zdev_t* dev, u32_t time) ++{ ++ u16_t i; ++ u16_t head; ++ u16_t tail; ++ u32_t tick; ++ u32_t arrivalTime; ++ //u16_t aid, ac; ++ TID_TX tid_tx; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if(!(wd->state == ZM_WLAN_STATE_ENABLED)) return 0; ++ zfAggTxScheduler(dev, 1); ++ tick = zm_agg_GetTime(); ++ for (i=0; iaggQPool[i]) return 0; ++ if (1 == wd->aggQPool[i]->aggQEnabled) ++ { ++ tid_tx = wd->aggQPool[i]; ++ zmw_enter_critical_section(dev); ++ ++ head = tid_tx->aggHead; ++ tail = tid_tx->aggTail; ++ ++ arrivalTime = (u32_t)tid_tx->aggvtxq[tid_tx->aggTail].arrivalTime; ++ ++ ++ if((tick - arrivalTime) <= ZM_AGG_CLEAR_TIME) ++ { ++ ++ } ++ else if((tid_tx->size = zm_agg_qlen(dev, tid_tx->aggHead, tid_tx->aggTail)) > 0) ++ { ++ ++ tid_tx->clearFlag = 1; ++ ++ //zm_msg1_agg(ZM_LV_0, "clear queue tick =", tick); ++ //zm_msg1_agg(ZM_LV_0, "clear queue arrival =", arrivalTime); ++ ++ ++ //zmw_leave_critical_section(dev); ++ //zfAggTxScheduler(dev); ++ //zmw_enter_critical_section(dev); ++ ++ } ++ ++ if (tid_tx->size == 0) ++ { ++ /* ++ * queue empty ++ */ ++ if (tick - tid_tx->lastArrival > ZM_AGG_DELETE_TIME) ++ { ++ zm_msg1_agg(ZM_LV_0, "delete queue, idle for n sec. n = ", \ ++ ZM_AGG_DELETE_TIME/10); ++ ++ zmw_leave_critical_section(dev); ++ zfAggTxDeleteQueue(dev, i); ++ zmw_enter_critical_section(dev); ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ } ++ } ++ ++ zfAggRxClear(dev, time); ++ ++#ifdef ZM_AGG_TALLY ++ if((wd->tick % 100) == 0) { ++ zfAggPrintTally(dev); ++ } ++#endif ++ ++ return ZM_SUCCESS; ++} ++ ++u16_t zfAggPrintTally(zdev_t* dev) ++{ ++ struct aggTally* agg_tal; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ agg_tal = &wd->agg_tal; ++ ++ if(agg_tal->got_packets_sum < 10) ++ { ++ zfAggTallyReset(dev); ++ return 0; ++ } ++ ++ agg_tal->time++; ++ agg_tal->avg_got_packets = (agg_tal->avg_got_packets * (agg_tal->time - 1) + ++ agg_tal->got_packets_sum) / agg_tal->time; ++ agg_tal->avg_got_bytes = (agg_tal->avg_got_bytes * (agg_tal->time - 1) + ++ agg_tal->got_bytes_sum) / agg_tal->time; ++ agg_tal->avg_sent_packets = (agg_tal->avg_sent_packets * (agg_tal->time - 1) ++ + agg_tal->sent_packets_sum) / agg_tal->time; ++ agg_tal->avg_sent_bytes = (agg_tal->avg_sent_bytes * (agg_tal->time - 1) + ++ agg_tal->sent_bytes_sum) / agg_tal->time; ++ zm_msg1_agg(ZM_LV_0, "got_packets_sum =", agg_tal->got_packets_sum); ++ zm_msg1_agg(ZM_LV_0, " got_bytes_sum =", agg_tal->got_bytes_sum); ++ zm_msg1_agg(ZM_LV_0, "sent_packets_sum=", agg_tal->sent_packets_sum); ++ zm_msg1_agg(ZM_LV_0, " sent_bytes_sum =", agg_tal->sent_bytes_sum); ++ agg_tal->got_packets_sum = agg_tal->got_bytes_sum =agg_tal->sent_packets_sum ++ = agg_tal->sent_bytes_sum = 0; ++ zm_msg1_agg(ZM_LV_0, "avg_got_packets =", agg_tal->avg_got_packets); ++ zm_msg1_agg(ZM_LV_0, " avg_got_bytes =", agg_tal->avg_got_bytes); ++ zm_msg1_agg(ZM_LV_0, "avg_sent_packets=", agg_tal->avg_sent_packets); ++ zm_msg1_agg(ZM_LV_0, " avg_sent_bytes =", agg_tal->avg_sent_bytes); ++ if ((wd->commTally.BA_Fail == 0) || (wd->commTally.Hw_Tx_MPDU == 0)) ++ { ++ zm_msg1_agg(ZM_LV_0, "Hardware Tx MPDU=", wd->commTally.Hw_Tx_MPDU); ++ zm_msg1_agg(ZM_LV_0, " BA Fail number=", wd->commTally.BA_Fail); ++ } ++ else ++ zm_msg1_agg(ZM_LV_0, "1/(BA fail rate)=", wd->commTally.Hw_Tx_MPDU/wd->commTally.BA_Fail); ++ ++ return 0; ++} ++ ++u16_t zfAggRxClear(zdev_t* dev, u32_t time) ++{ ++ u16_t i; ++ struct agg_tid_rx *tid_rx; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ for (i=0; itid_rx[i]; ++ if (tid_rx->baw_head != tid_rx->baw_tail) ++ { ++ u16_t j = tid_rx->baw_tail; ++ while ((j != tid_rx->baw_head) && !tid_rx->frame[j].buf) { ++ j = (j + 1) & ZM_AGG_BAW_MASK; ++ } ++ if ((j != tid_rx->baw_head) && (time - tid_rx->frame[j].arrivalTime) > ++ (ZM_AGG_CLEAR_TIME - 5)) ++ { ++ zmw_leave_critical_section(dev); ++ zm_msg0_agg(ZM_LV_1, "queue RxFlush by RxClear"); ++ zfAggRxFlush(dev, 0, tid_rx); ++ zmw_enter_critical_section(dev); ++ } ++ } ++ zmw_leave_critical_section(dev); ++ } ++ ++ return ZM_SUCCESS; ++} ++ ++struct agg_tid_rx* zfAggRxEnabled(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t dst0, src[3], ac, aid, fragOff; ++ u8_t up; ++ u16_t offset = 0; ++ u16_t seq_no; ++ u16_t frameType; ++ u16_t frameCtrl; ++ u16_t frameSubtype; ++ u32_t tcp_seq; ++ //struct aggSta *agg_sta; ++#if ZM_AGG_FPGA_REORDERING ++ struct agg_tid_rx *tid_rx; ++#endif ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ seq_no = zmw_rx_buf_readh(dev, buf, 22) >> 4; ++ //DbgPrint("Rx seq=%d\n", seq_no); ++ if (wd->sta.EnableHT == 0) ++ { ++ return NULL; ++ } ++ ++ frameCtrl = zmw_rx_buf_readb(dev, buf, 0); ++ frameType = frameCtrl & 0xf; ++ frameSubtype = frameCtrl & 0xf0; ++ ++ ++ if (frameType != ZM_WLAN_DATA_FRAME) //non-Qos Data? (frameSubtype&0x80) ++ { ++ return NULL; ++ } ++#ifdef ZM_ENABLE_PERFORMANCE_EVALUATION ++ tcp_seq = zmw_rx_buf_readb(dev, buf, 22+36) << 24; ++ tcp_seq += zmw_rx_buf_readb(dev, buf, 22+37) << 16; ++ tcp_seq += zmw_rx_buf_readb(dev, buf, 22+38) << 8; ++ tcp_seq += zmw_rx_buf_readb(dev, buf, 22+39); ++#endif ++ ++ ZM_SEQ_DEBUG("In %5d, %12u\n", seq_no, tcp_seq); ++ dst0 = zmw_rx_buf_readh(dev, buf, offset+4); ++ ++ src[0] = zmw_rx_buf_readh(dev, buf, offset+10); ++ src[1] = zmw_rx_buf_readh(dev, buf, offset+12); ++ src[2] = zmw_rx_buf_readh(dev, buf, offset+14); ++ ++#if ZM_AGG_FPGA_DEBUG ++ aid = 0; ++#else ++ aid = zfApFindSta(dev, src); ++#endif ++ ++ //agg_sta = &wd->aggSta[aid]; ++ //zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); ++ //ac = zcUpToAc[up&0x7] & 0x3; ++ ++ /* ++ * Filter unicast frame only, aid == 0 is for debug only ++ */ ++ if ((dst0 & 0x1) == 0 && aid == 0) ++ { ++#if ZM_AGG_FPGA_REORDERING ++ tid_rx = zfAggRxGetQueue(dev, buf) ; ++ if(!tid_rx) ++ return NULL; ++ else ++ { ++ //if (tid_rx->addBaExchangeStatusCode == ZM_AGG_ADDBA_RESPONSE) ++ return tid_rx; ++ } ++#else ++ return NULL; ++#endif ++ } ++ ++ return NULL; ++} ++ ++u16_t zfAggRx(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo *addInfo, struct agg_tid_rx *tid_rx) ++{ ++ u16_t seq_no; ++ s16_t index; ++ u16_t offset = 0; ++ zbuf_t* pbuf; ++ u8_t frameSubType; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ ZM_PERFORMANCE_RX_REORDER(dev); ++ ++ seq_no = zmw_rx_buf_readh(dev, buf, offset+22) >> 4; ++ ++ index = seq_no - tid_rx->seq_start; ++ /* ++ * for debug ++ */ ++ ++ /* zm_msg2_agg(ZM_LV_0, "queue seq = ", seq_no); ++ * DbgPrint("%s:%s%lxh %s%lxh\n", __FUNCTION__, "queue seq=", seq_no, ++ * "; seq_start=", tid_rx->seq_start); ++ */ ++ ++ //DbgPrint("seq_no=%d, seq_start=%d\n", seq_no, tid_rx->seq_start); ++ ++ /* In some APs, we found that it might transmit NULL data whose sequence number ++ is out or order. In order to avoid this problem, we ignore these NULL data. ++ */ ++ ++ frameSubType = (zmw_rx_buf_readh(dev, buf, 0) & 0xF0) >> 4; ++ ++ /* If this is a NULL data instead of Qos NULL data */ ++ if ((frameSubType & 0x0C) == 0x04) ++ { ++ s16_t seq_diff; ++ ++ seq_diff = (seq_no > tid_rx->seq_start) ? ++ seq_no - tid_rx->seq_start : tid_rx->seq_start - seq_no; ++ ++ if (seq_diff > ZM_AGG_BAW_SIZE) ++ { ++ zm_debug_msg0("Free Rx NULL data in zfAggRx"); ++ ++ /* Free Rx buffer */ ++ zfwBufFree(dev, buf, 0); ++ return ZM_ERR_OUT_OF_ORDER_NULL_DATA; ++ } ++ } ++ ++ /* ++ * sequence number wrap at 4k ++ */ ++ if (tid_rx->seq_start > seq_no) ++ { ++ //index += 4096; ++ ++ zmw_enter_critical_section(dev); ++ if (tid_rx->seq_start >= 4096) { ++ tid_rx->seq_start = 0; ++ } ++ zmw_leave_critical_section(dev); ++ ++ } ++ ++ if (tid_rx->seq_start == seq_no) { ++ zmw_enter_critical_section(dev); ++ if (((tid_rx->baw_head - tid_rx->baw_tail) & ZM_AGG_BAW_MASK) > 0) { ++ //DbgPrint("head=%d, tail=%d", tid_rx->baw_head, tid_rx->baw_tail); ++ tid_rx->baw_tail = (tid_rx->baw_tail + 1) & ZM_AGG_BAW_MASK; ++ } ++ tid_rx->seq_start = (tid_rx->seq_start + 1) & (4096 - 1); ++ zmw_leave_critical_section(dev); ++ ++ ZM_PERFORMANCE_RX_SEQ(dev, buf); ++ ++ if (wd->zfcbRecv80211 != NULL) { ++ //seq_no = zmw_rx_buf_readh(dev, buf, offset+22) >> 4; ++ //DbgPrint("Recv indicate seq=%d\n", seq_no); ++ //DbgPrint("1. seq=%d\n", seq_no); ++ ++ wd->zfcbRecv80211(dev, buf, addInfo); ++ } ++ else { ++ zfiRecv80211(dev, buf, addInfo); ++ } ++ } ++ else if (!zfAggRxEnqueue(dev, buf, tid_rx, addInfo)) ++ { ++ /* ++ * duplicated packet ++ */ ++ return 1; ++ } ++ ++ while (tid_rx->baw_head != tid_rx->baw_tail) {// && tid_rx->frame[tid_rx->baw_tail].buf) ++ u16_t tailIndex; ++ ++ zmw_enter_critical_section(dev); ++ ++ tailIndex = tid_rx->baw_tail; ++ pbuf = tid_rx->frame[tailIndex].buf; ++ tid_rx->frame[tailIndex].buf = 0; ++ if (!pbuf) ++ { ++ zmw_leave_critical_section(dev); ++ break; ++ } ++ ++ tid_rx->baw_tail = (tid_rx->baw_tail + 1) & ZM_AGG_BAW_MASK; ++ tid_rx->seq_start = (tid_rx->seq_start + 1) & (4096 - 1); ++ ++ ++ //if(pbuf && tid_rx->baw_size > 0) ++ // tid_rx->baw_size--; ++ ++ zmw_leave_critical_section(dev); ++ ++ ZM_PERFORMANCE_RX_SEQ(dev, pbuf); ++ ++ if (wd->zfcbRecv80211 != NULL) ++ { ++ //seq_no = zmw_rx_buf_readh(dev, pbuf, offset+22) >> 4; ++ //DbgPrint("Recv indicate seq=%d\n", seq_no); ++ //DbgPrint("1. seq=%d\n", seq_no); ++ wd->zfcbRecv80211(dev, pbuf, addInfo); ++ } ++ else ++ { ++ //seq_no = zmw_rx_buf_readh(dev, pbuf, offset+22) >> 4; ++ //DbgPrint("Recv indicate seq=%d\n", seq_no); ++ zfiRecv80211(dev, pbuf, addInfo); ++ } ++ } ++ ++ return 1; ++} ++ ++struct agg_tid_rx *zfAggRxGetQueue(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t src[3]; ++ u16_t aid, ac, i; ++ u16_t offset = 0; ++ struct agg_tid_rx *tid_rx = NULL; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ src[0] = zmw_rx_buf_readh(dev, buf, offset+10); ++ src[1] = zmw_rx_buf_readh(dev, buf, offset+12); ++ src[2] = zmw_rx_buf_readh(dev, buf, offset+14); ++ aid = zfApFindSta(dev, src); ++ ++ ac = (zmw_rx_buf_readh(dev, buf, 24) & 0xF); ++ ++ // mark by spin lock debug ++ //zmw_enter_critical_section(dev); ++ ++ for (i=0; itid_rx[i]->aid == aid) && (wd->tid_rx[i]->ac == ac)) ++ { ++ tid_rx = wd->tid_rx[i]; ++ break; ++ } ++ } ++ ++ // mark by spin lock debug ++ //zmw_leave_critical_section(dev); ++ return tid_rx; ++} ++ ++ ++u16_t zfAggRxEnqueue(zdev_t* dev, zbuf_t* buf, struct agg_tid_rx *tid_rx, struct zsAdditionInfo *addInfo) ++{ ++ u16_t seq_no, offset = 0; ++ u16_t q_index; ++ s16_t index; ++ u8_t bdropframe = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ seq_no = zmw_rx_buf_readh(dev, buf, offset+22) >> 4; ++ index = seq_no - tid_rx->seq_start; ++ ++ /* ++ * sequence number wrap at 4k ++ * -1000: check for duplicate past packet ++ */ ++ bdropframe = 0; ++ if (tid_rx->seq_start > seq_no) { ++ if ((tid_rx->seq_start > 3967) && (seq_no < 128)) { ++ index += 4096; ++ } else if (tid_rx->seq_start - seq_no > 70) { ++ zmw_enter_critical_section(dev); ++ tid_rx->sq_behind_count++; ++ if (tid_rx->sq_behind_count > 3) { ++ tid_rx->sq_behind_count = 0; ++ } else { ++ bdropframe = 1; ++ } ++ zmw_leave_critical_section(dev); ++ } else { ++ bdropframe = 1; ++ } ++ } else { ++ if (seq_no - tid_rx->seq_start > 70) { ++ zmw_enter_critical_section(dev); ++ tid_rx->sq_exceed_count++; ++ if (tid_rx->sq_exceed_count > 3) { ++ tid_rx->sq_exceed_count = 0; ++ } else { ++ bdropframe = 1; ++ } ++ zmw_leave_critical_section(dev); ++ } ++ } ++ ++ if (bdropframe == 1) { ++ /*if (wd->zfcbRecv80211 != NULL) { ++ wd->zfcbRecv80211(dev, buf, addInfo); ++ } ++ else { ++ zfiRecv80211(dev, buf, addInfo); ++ }*/ ++ ++ ZM_PERFORMANCE_FREE(dev, buf); ++ ++ zfwBufFree(dev, buf, 0); ++ /*zfAggRxFlush(dev, seq_no, tid_rx); ++ tid_rx->seq_start = seq_no; ++ index = seq_no - tid_rx->seq_start; ++ */ ++ ++ //DbgPrint("Free an old packet, seq_start=%d, seq_no=%d\n", tid_rx->seq_start, seq_no); ++ ++ /* ++ * duplicate past packet ++ * happens only in simulated aggregation environment ++ */ ++ return 0; ++ } else { ++ zmw_enter_critical_section(dev); ++ if (tid_rx->sq_exceed_count > 0){ ++ tid_rx->sq_exceed_count--; ++ } ++ ++ if (tid_rx->sq_behind_count > 0) { ++ tid_rx->sq_behind_count--; ++ } ++ zmw_leave_critical_section(dev); ++ } ++ ++ if (index < 0) { ++ zfAggRxFlush(dev, seq_no, tid_rx); ++ tid_rx->seq_start = seq_no; ++ index = 0; ++ } ++ ++ //if (index >= (ZM_AGG_BAW_SIZE - 1)) ++ if (index >= (ZM_AGG_BAW_MASK)) ++ { ++ /* ++ * queue full ++ */ ++ //DbgPrint("index >= 64, seq_start=%d, seq_no=%d\n", tid_rx->seq_start, seq_no); ++ zfAggRxFlush(dev, seq_no, tid_rx); ++ //tid_rx->seq_start = seq_no; ++ index = seq_no - tid_rx->seq_start; ++ if ((tid_rx->seq_start > seq_no) && (tid_rx->seq_start > 1000) && (tid_rx->seq_start - 1000) > seq_no) ++ { ++ //index = seq_no - tid_rx->seq_start; ++ index += 4096; ++ } ++ //index = seq_no - tid_rx->seq_start; ++ while (index >= (ZM_AGG_BAW_MASK)) { ++ //DbgPrint("index >= 64, seq_start=%d, seq_no=%d\n", tid_rx->seq_start, seq_no); ++ tid_rx->seq_start = (tid_rx->seq_start + ZM_AGG_BAW_MASK) & (4096 - 1); ++ index = seq_no - tid_rx->seq_start; ++ if ((tid_rx->seq_start > seq_no) && (tid_rx->seq_start > 1000) && (tid_rx->seq_start - 1000) > seq_no) ++ { ++ index += 4096; ++ } ++ } ++ } ++ ++ ++ q_index = (tid_rx->baw_tail + index) & ZM_AGG_BAW_MASK; ++ if (tid_rx->frame[q_index].buf && (((tid_rx->baw_head - tid_rx->baw_tail) & ZM_AGG_BAW_MASK) > ++ (((q_index) - tid_rx->baw_tail) & ZM_AGG_BAW_MASK))) ++ { ++ ++ ZM_PERFORMANCE_DUP(dev, tid_rx->frame[q_index].buf, buf); ++ zfwBufFree(dev, buf, 0); ++ //DbgPrint("Free a duplicate packet, seq_start=%d, seq_no=%d\n", tid_rx->seq_start, seq_no); ++ //DbgPrint("head=%d, tail=%d", tid_rx->baw_head, tid_rx->baw_tail); ++ /* ++ * duplicate packet ++ */ ++ return 0; ++ } ++ ++ zmw_enter_critical_section(dev); ++ if(tid_rx->frame[q_index].buf) { ++ zfwBufFree(dev, tid_rx->frame[q_index].buf, 0); ++ tid_rx->frame[q_index].buf = 0; ++ } ++ ++ tid_rx->frame[q_index].buf = buf; ++ tid_rx->frame[q_index].arrivalTime = zm_agg_GetTime(); ++ zfwMemoryCopy((void*)&tid_rx->frame[q_index].addInfo, (void*)addInfo, sizeof(struct zsAdditionInfo)); ++ ++ /* ++ * for debug simulated aggregation only, ++ * should be done in rx of ADDBA Request ++ */ ++ //tid_rx->addInfo = addInfo; ++ ++ ++ if (((tid_rx->baw_head - tid_rx->baw_tail) & ZM_AGG_BAW_MASK) <= index) ++ { ++ //tid_rx->baw_size = index + 1; ++ if (((tid_rx->baw_head - tid_rx->baw_tail) & ZM_AGG_BAW_MASK) <= ++ //((q_index + 1) & ZM_AGG_BAW_MASK)) ++ (((q_index) - tid_rx->baw_tail) & ZM_AGG_BAW_MASK))//tid_rx->baw_size ) ++ tid_rx->baw_head = (q_index + 1) & ZM_AGG_BAW_MASK; ++ } ++ zmw_leave_critical_section(dev); ++ ++ /* ++ * success ++ */ ++ //DbgPrint("head=%d, tail=%d, start=%d", tid_rx->baw_head, tid_rx->baw_tail, tid_rx->seq_start); ++ return 1; ++} ++ ++u16_t zfAggRxFlush(zdev_t* dev, u16_t seq_no, struct agg_tid_rx *tid_rx) ++{ ++ zbuf_t* pbuf; ++ u16_t seq; ++ struct zsAdditionInfo addInfo; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ZM_PERFORMANCE_RX_FLUSH(dev); ++ ++ while (1) ++ { ++ zmw_enter_critical_section(dev); ++ if (tid_rx->baw_tail == tid_rx->baw_head) { ++ zmw_leave_critical_section(dev); ++ break; ++ } ++ ++ pbuf = tid_rx->frame[tid_rx->baw_tail].buf; ++ zfwMemoryCopy((void*)&addInfo, (void*)&tid_rx->frame[tid_rx->baw_tail].addInfo, sizeof(struct zsAdditionInfo)); ++ tid_rx->frame[tid_rx->baw_tail].buf = 0; ++ //if(pbuf && tid_rx->baw_size > 0) tid_rx->baw_size--; ++ tid_rx->baw_tail = (tid_rx->baw_tail + 1) & ZM_AGG_BAW_MASK; ++ tid_rx->seq_start = (tid_rx->seq_start + 1) & (4096 - 1); ++ zmw_leave_critical_section(dev); ++ ++ if (pbuf) ++ { ++ ++ ZM_PERFORMANCE_RX_SEQ(dev, pbuf); ++ ++ if (wd->zfcbRecv80211 != NULL) ++ { ++ seq = zmw_rx_buf_readh(dev, pbuf, 22) >> 4; ++ //DbgPrint("Recv indicate seq=%d\n", seq); ++ //DbgPrint("2. seq=%d\n", seq); ++ wd->zfcbRecv80211(dev, pbuf, &addInfo); ++ } ++ else ++ { ++ seq = zmw_rx_buf_readh(dev, pbuf, 22) >> 4; ++ //DbgPrint("Recv indicate seq=%d\n", seq); ++ zfiRecv80211(dev, pbuf, &addInfo); ++ } ++ } ++ } ++ ++ zmw_enter_critical_section(dev); ++ tid_rx->baw_head = tid_rx->baw_tail = 0; ++ zmw_leave_critical_section(dev); ++ return 1; ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggRxFreeBuf */ ++/* Frees all queued packets in buffer when the driver is down. */ ++/* The zfFreeResource() will check if the buffer is all freed. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* ZM_SUCCESS */ ++/* */ ++/* AUTHOR */ ++/* Honda Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggRxFreeBuf(zdev_t* dev, u16_t destroy) ++{ ++ u16_t i; ++ zbuf_t* buf; ++ struct agg_tid_rx *tid_rx; ++ ++ TID_TX tid_tx; ++ //struct bufInfo *buf_info; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ for (i=0; itid_rx[i]; ++ ++ for(j=0; j <= ZM_AGG_BAW_SIZE; j++) ++ { ++ zmw_enter_critical_section(dev); ++ buf = tid_rx->frame[j].buf; ++ tid_rx->frame[j].buf = 0; ++ zmw_leave_critical_section(dev); ++ ++ if (buf) ++ { ++ zfwBufFree(dev, buf, 0); ++ } ++ } ++ ++ #if 0 ++ if ( tid_rx->baw_head != tid_rx->baw_tail ) ++ { ++ while (tid_rx->baw_head != tid_rx->baw_tail) ++ { ++ buf = tid_rx->frame[tid_rx->baw_tail].buf; ++ tid_rx->frame[tid_rx->baw_tail].buf = 0; ++ if (buf) ++ { ++ zfwBufFree(dev, buf, 0); ++ ++ zmw_enter_critical_section(dev); ++ tid_rx->frame[tid_rx->baw_tail].buf = 0; ++ zmw_leave_critical_section(dev); ++ } ++ zmw_enter_critical_section(dev); ++ //if (tid_rx->baw_size > 0)tid_rx->baw_size--; ++ tid_rx->baw_tail = (tid_rx->baw_tail + 1) & ZM_AGG_BAW_MASK; ++ tid_rx->seq_start++; ++ zmw_leave_critical_section(dev); ++ } ++ } ++ #endif ++ ++ zmw_enter_critical_section(dev); ++ tid_rx->seq_start = 0; ++ tid_rx->baw_head = tid_rx->baw_tail = 0; ++ tid_rx->aid = ZM_MAX_STA_SUPPORT; ++ zmw_leave_critical_section(dev); ++ ++ #ifdef ZM_ENABLE_AGGREGATION ++ #ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++ if (tid_baw->enabled) { ++ zm_msg1_agg(ZM_LV_0, "Device down, clear BAW queue:", i); ++ BAW->disable(dev, tid_baw); ++ } ++ #endif ++ #endif ++ if (1 == wd->aggQPool[i]->aggQEnabled) { ++ tid_tx = wd->aggQPool[i]; ++ buf = zfAggTxGetVtxq(dev, tid_tx); ++ while (buf) { ++ zfwBufFree(dev, buf, 0); ++ buf = zfAggTxGetVtxq(dev, tid_tx); ++ } ++ } ++ ++ if(destroy) { ++ zfwMemFree(dev, wd->aggQPool[i], sizeof(struct aggQueue)); ++ zfwMemFree(dev, wd->tid_rx[i], sizeof(struct agg_tid_rx)); ++ } ++ } ++ #ifdef ZM_ENABLE_AGGREGATION ++ #ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++ if(destroy) zfwMemFree(dev, BAW, sizeof(struct baw_enabler)); ++ #endif ++ #endif ++ return ZM_SUCCESS; ++} ++ ++ ++void zfAggRecvBAR(zdev_t* dev, zbuf_t *buf) { ++ u16_t start_seq, len; ++ u8_t i, bitmap[8]; ++ len = zfwBufGetSize(dev, buf); ++ start_seq = zmw_rx_buf_readh(dev, buf, len-2); ++ DbgPrint("Received a BAR Control frame, start_seq=%d", start_seq>>4); ++ /* todo: set the bitmap by reordering buffer! */ ++ for (i=0; i<8; i++) bitmap[i]=0; ++ zfSendBA(dev, start_seq, bitmap); ++} ++ ++#ifdef ZM_ENABLE_AGGREGATION ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++void zfAggTxRetransmit(zdev_t* dev, struct bufInfo *buf_info, struct aggControl *aggControl, TID_TX tid_tx) { ++ u16_t removeLen; ++ u16_t err; ++ ++ zmw_get_wlan_dev(dev); ++ if (aggControl && (ZM_AGG_FIRST_MPDU == aggControl->ampduIndication) ) { ++ tid_tx->bar_ssn = buf_info->baw_header->header[15]; ++ aggControl->tid_baw->start_seq = tid_tx->bar_ssn >> 4; ++ zm_msg1_agg(ZM_LV_0, "start seq=", tid_tx->bar_ssn >> 4); ++ } ++ buf_info->baw_header->header[4] |= (1 << 11); ++ if (aggControl && aggControl->aggEnabled) { ++ //if (wd->enableAggregation==0 && !(buf_info->baw_header->header[6]&0x1)) ++ //{ ++ //if (((buf_info->baw_header->header[2] & 0x3) == 2)) ++ //{ ++ /* Enable aggregation */ ++ buf_info->baw_header->header[1] |= 0x20; ++ if (ZM_AGG_LAST_MPDU == aggControl->ampduIndication) { ++ buf_info->baw_header->header[1] |= 0x4000; ++ } ++ else { ++ buf_info->baw_header->header[1] &= ~0x4000; ++ //zm_debug_msg0("ZM_AGG_LAST_MPDU"); ++ } ++ //} ++ //else { ++ // zm_debug_msg1("no aggr, header[2]&0x3 = ",buf_info->baw_header->header[2] & 0x3) ++ // aggControl->aggEnabled = 0; ++ //} ++ //} ++ //else { ++ // zm_debug_msg1("no aggr, wd->enableAggregation = ", wd->enableAggregation); ++ // zm_debug_msg1("no aggr, !header[6]&0x1 = ",!(buf_info->baw_header->header[6]&0x1)); ++ // aggControl->aggEnabled = 0; ++ //} ++ } ++ ++ /*if (aggControl->tid_baw) { ++ struct baw_header_r header_r; ++ ++ header_r.header = buf_info->baw_header->header; ++ header_r.mic = buf_info->baw_header->mic; ++ header_r.snap = buf_info->baw_header->snap; ++ header_r.headerLen = buf_info->baw_header->headerLen; ++ header_r.micLen = buf_info->baw_header->micLen; ++ header_r.snapLen = buf_info->baw_header->snapLen; ++ header_r.removeLen = buf_info->baw_header->removeLen; ++ header_r.keyIdx = buf_info->baw_header->keyIdx; ++ ++ BAW->insert(dev, buf_info->buf, tid_tx->bar_ssn >> 4, aggControl->tid_baw, buf_info->baw_retransmit, &header_r); ++ }*/ ++ ++ if ((err = zfHpSend(dev, ++ buf_info->baw_header->header, ++ buf_info->baw_header->headerLen, ++ buf_info->baw_header->snap, ++ buf_info->baw_header->snapLen, ++ buf_info->baw_header->mic, ++ buf_info->baw_header->micLen, ++ buf_info->buf, ++ buf_info->baw_header->removeLen, ++ ZM_EXTERNAL_ALLOC_BUF, ++ (u8_t)tid_tx->ac, ++ buf_info->baw_header->keyIdx)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ ++ return; ++ ++zlError: ++ zfwBufFree(dev, buf_info->buf, 0); ++ return; ++ ++} ++#endif //disable BAW ++#endif ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAggTxSendEth */ ++/* Called to transmit Ethernet frame from upper elayer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer pointer */ ++/* port : WLAN port, 0=>standard, 0x10-0x17=>VAP, 0x20-0x25=>WDS */ ++/* */ ++/* OUTPUTS */ ++/* error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen, Honda Atheros Communications, Inc. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfAggTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, u16_t bufType, u8_t flag, struct aggControl *aggControl, TID_TX tid_tx) ++{ ++ u16_t err; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ u16_t removeLen; ++ u16_t header[(8+30+2+18)/2]; /* ctr+(4+a1+a2+a3+2+a4)+qos+iv */ ++ u16_t headerLen; ++ u16_t mic[8/2]; ++ u16_t micLen; ++ u16_t snap[8/2]; ++ u16_t snapLen; ++ u16_t fragLen; ++ u16_t frameLen; ++ u16_t fragNum; ++ struct zsFrag frag; ++ u16_t i, id; ++ u16_t da[3]; ++ u16_t sa[3]; ++ u8_t up; ++ u8_t qosType, keyIdx = 0; ++ u16_t fragOff; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zm_msg1_tx(ZM_LV_2, "zfTxSendEth(), port=", port); ++ ++ /* Get IP TOS for QoS AC and IP frag offset */ ++ zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); ++ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 16); ++ da[1] = zmw_tx_buf_readh(dev, buf, 18); ++ da[2] = zmw_tx_buf_readh(dev, buf, 20); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 10); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 12); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 14); ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 4); ++ da[1] = zmw_tx_buf_readh(dev, buf, 6); ++ da[2] = zmw_tx_buf_readh(dev, buf, 8); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 10); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 12); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 14); ++ } ++ else if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 4); ++ da[1] = zmw_tx_buf_readh(dev, buf, 6); ++ da[2] = zmw_tx_buf_readh(dev, buf, 8); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 16); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 18); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 20); ++ } ++ else ++ { ++ // ++ } ++#else ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 0); ++ da[1] = zmw_tx_buf_readh(dev, buf, 2); ++ da[2] = zmw_tx_buf_readh(dev, buf, 4); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 6); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 8); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 10); ++#endif ++ //Decide Key Index in ATOM, No meaning in OTUS--CWYang(m) ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ keyIdx = wd->ap.bcHalKeyIdx[port]; ++ id = zfApFindSta(dev, da); ++ if (id != 0xffff) ++ { ++ switch (wd->ap.staTable[id].encryMode) ++ { ++ case ZM_AES: ++ case ZM_TKIP: ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++#endif //ZM_ENABLE_CENC ++ keyIdx = wd->ap.staTable[id].keyIdx; ++ break; ++ } ++ } ++ } ++ else ++ { ++ switch (wd->sta.encryMode) ++ { ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++ keyIdx = wd->sta.keyId; ++ break; ++ case ZM_AES: ++ case ZM_TKIP: ++ if ((da[0]& 0x1)) ++ keyIdx = 5; ++ else ++ keyIdx = 4; ++ break; ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++ keyIdx = wd->sta.cencKeyId; ++ break; ++#endif //ZM_ENABLE_CENC ++ } ++ } ++ ++ /* Create SNAP */ ++ removeLen = zfTxGenWlanSnap(dev, buf, snap, &snapLen); ++ //zm_msg1_tx(ZM_LV_0, "fragOff=", fragOff); ++ ++ fragLen = wd->fragThreshold; ++ frameLen = zfwBufGetSize(dev, buf); ++ frameLen -= removeLen; ++ ++#if 0 ++ /* Create MIC */ ++ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&& ++ (wd->sta.encryMode == ZM_TKIP) ) ++ { ++ if ( frameLen > fragLen ) ++ { ++ micLen = zfTxGenWlanTail(dev, buf, snap, snapLen, mic); ++ } ++ else ++ { ++ /* append MIC by HMAC */ ++ micLen = 8; ++ } ++ } ++ else ++ { ++ micLen = 0; ++ } ++#else ++ if ( frameLen > fragLen ) ++ { ++ micLen = zfTxGenWlanTail(dev, buf, snap, snapLen, mic); ++ } ++ else ++ { ++ /* append MIC by HMAC */ ++ micLen = 0; ++ } ++#endif ++ ++ /* Access Category */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ zfApGetStaQosType(dev, da, &qosType); ++ if (qosType == 0) ++ { ++ up = 0; ++ } ++ } ++ else if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ if (wd->sta.wmeConnected == 0) ++ { ++ up = 0; ++ } ++ } ++ else ++ { ++ /* TODO : STA QoS control field */ ++ up = 0; ++ } ++ ++ /* Assign sequence number */ ++ zmw_enter_critical_section(dev); ++ frag.seq[0] = ((wd->seq[zcUpToAc[up&0x7]]++) << 4); ++ if (aggControl && (ZM_AGG_FIRST_MPDU == aggControl->ampduIndication) ) { ++ tid_tx->bar_ssn = frag.seq[0]; ++ ++ zm_msg1_agg(ZM_LV_0, "start seq=", tid_tx->bar_ssn >> 4); ++ } ++ //tid_tx->baw_buf[tid_tx->baw_head-1].baw_seq=frag.seq[0]; ++ zmw_leave_critical_section(dev); ++ ++ ++ frag.buf[0] = buf; ++ frag.bufType[0] = bufType; ++ frag.flag[0] = flag; ++ fragNum = 1; ++ ++ for (i=0; i>1); i++) ++ { ++ zmw_tx_buf_writeh(dev, buf, i*2, header[i]); ++ } ++ ++ /* Get buffer DMA address */ ++ //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) ++ //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) ++ //{ ++ // goto zlError; ++ //} ++ ++ //zm_msg2_mm(ZM_LV_2, "offset=", offset); ++ //zm_msg2_mm(ZM_LV_2, "hlen=", hlen); ++ //zm_msg2_mm(ZM_LV_2, "addrTblSize=", addrTblSize); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.len[0]=", addrTbl.len[0]); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.physAddrl[0]=", addrTbl.physAddrl[0]); ++ //zm_msg2_mm(ZM_LV_2, "buf->data=", buf->data); ++ ++ #if 0 ++ if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ #else ++ zfPutVmmq(dev, buf); ++ zfPushVtxq(dev); ++ #endif ++ ++ return ZM_SUCCESS; ++ ++} ++ ++u16_t zfAggSetAddbaFrameBody(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t ac, u16_t up) ++{ ++ u16_t ba_parameter, start_seq; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ /* ++ * ADDBA Request frame body ++ */ ++ ++ /* ++ * Category ++ */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 3); ++ /* ++ * Action details = 0 ++ */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_ADDBA_REQUEST_FRAME); ++ /* ++ * Dialog Token = nonzero ++ * TBD: define how to get dialog token? ++ */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 2); ++ /* ++ * Block Ack parameter set ++ * BA policy = 1 for immediate BA, 0 for delayed BA ++ * TID(4bits) & buffer size(4bits) (TID=up & buffer size=0x80) ++ * TBD: how to get buffer size? ++ * ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++ * ¢x B0 ¢x B1 ¢x B2 B5 ¢x B6 B15 ¢x ++ * ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++ * ¢x Reserved ¢x BA policy ¢x TID ¢x Buffer size ¢x ++ * ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++ */ ++ ba_parameter = 1 << 12; // buffer size = 0x40(64) ++ ba_parameter |= up << 2; // tid = up ++ ba_parameter |= 2; // ba policy = 1 ++ zmw_tx_buf_writeh(dev, buf, offset, ba_parameter); ++ offset+=2; ++ /* ++ * BA timeout value ++ */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0); ++ offset+=2; ++ /* ++ * BA starting sequence number ++ * ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++ * ¢x B0 B3 ¢x B4 B15 ¢x ++ * ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++ * ¢x Frag num(0) ¢x BA starting seq num ¢x ++ * ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++ */ ++ start_seq = ((wd->seq[ac]) << 4) & 0xFFF0; ++ zmw_tx_buf_writeh(dev, buf, offset, start_seq); ++ offset+=2; ++ ++ return offset; ++} ++ ++u16_t zfAggGenAddbaHeader(zdev_t* dev, u16_t* dst, ++ u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt) ++{ ++ u8_t hlen = 32; // MAC ctrl + PHY ctrl + 802.11 MM header ++ //u8_t frameType = ZM_WLAN_FRAME_TYPE_ACTION; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* ++ * Generate control setting ++ */ ++ //bodyLen = zfwBufGetSize(dev, buf); ++ header[0] = 24+len+4; //Length ++ header[1] = 0x8; //MAC control, backoff + (ack) ++ ++#if 0 ++ /* CCK 1M */ ++ header[2] = 0x0f00; //PHY control L ++ header[3] = 0x0000; //PHY control H ++#else ++ /* OFDM 6M */ ++ header[2] = 0x0f01; //PHY control L ++ header[3] = 0x000B; //PHY control H ++#endif ++ ++ /* ++ * Generate WLAN header ++ * Frame control frame type and subtype ++ */ ++ header[4+0] = ZM_WLAN_FRAME_TYPE_ACTION; ++ /* ++ * Duration ++ */ ++ header[4+1] = 0; ++ ++ if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ header[4+8] = wd->sta.bssid[0]; ++ header[4+9] = wd->sta.bssid[1]; ++ header[4+10] = wd->sta.bssid[2]; ++ } ++ else if (wd->wlanMode == ZM_MODE_PSEUDO) ++ { ++ /* Address 3 = 00:00:00:00:00:00 */ ++ header[4+8] = 0; ++ header[4+9] = 0; ++ header[4+10] = 0; ++ } ++ else if (wd->wlanMode == ZM_MODE_IBSS) ++ { ++ header[4+8] = wd->sta.bssid[0]; ++ header[4+9] = wd->sta.bssid[1]; ++ header[4+10] = wd->sta.bssid[2]; ++ } ++ else if (wd->wlanMode == ZM_MODE_AP) ++ { ++ /* Address 3 = BSSID */ ++ header[4+8] = wd->macAddr[0]; ++ header[4+9] = wd->macAddr[1]; ++ header[4+10] = wd->macAddr[2] + (vap<<8); ++ } ++ ++ /* Address 1 = DA */ ++ header[4+2] = dst[0]; ++ header[4+3] = dst[1]; ++ header[4+4] = dst[2]; ++ ++ /* Address 2 = SA */ ++ header[4+5] = wd->macAddr[0]; ++ header[4+6] = wd->macAddr[1]; ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ header[4+7] = wd->macAddr[2] + (vap<<8); ++ } ++ else ++ { ++ header[4+7] = wd->macAddr[2]; ++ } ++ ++ /* Sequence Control */ ++ zmw_enter_critical_section(dev); ++ header[4+11] = ((wd->mmseq++)<<4); ++ zmw_leave_critical_section(dev); ++ ++ ++ return hlen; ++} ++ ++ ++u16_t zfAggProcessAction(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t category; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ category = zmw_rx_buf_readb(dev, buf, 24); ++ ++ switch (category) ++ { ++ case ZM_WLAN_BLOCK_ACK_ACTION_FRAME: ++ zfAggBlockAckActionFrame(dev, buf); ++ break; ++ ++ } ++ ++ return ZM_SUCCESS; ++} ++ ++ ++u16_t zfAggBlockAckActionFrame(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t action; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ action = zmw_rx_buf_readb(dev, buf, 25); ++#ifdef ZM_ENABLE_AGGREGATION ++ switch (action) ++ { ++ case ZM_WLAN_ADDBA_REQUEST_FRAME: ++ zm_msg0_agg(ZM_LV_0, "Received BA Action frame is ADDBA request"); ++ zfAggRecvAddbaRequest(dev, buf); ++ break; ++ case ZM_WLAN_ADDBA_RESPONSE_FRAME: ++ zm_msg0_agg(ZM_LV_0, "Received BA Action frame is ADDBA response"); ++ zfAggRecvAddbaResponse(dev, buf); ++ break; ++ case ZM_WLAN_DELBA_FRAME: ++ zfAggRecvDelba(dev, buf); ++ break; ++ } ++#endif ++ return ZM_SUCCESS; ++} ++ ++u16_t zfAggRecvAddbaRequest(zdev_t* dev, zbuf_t* buf) ++{ ++ //u16_t dialog; ++ struct aggBaFrameParameter bf; ++ u16_t i; ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ bf.buf = buf; ++ bf.dialog = zmw_rx_buf_readb(dev, buf, 26); ++ /* ++ * ba parameter set ++ */ ++ bf.ba_parameter = zmw_rx_buf_readh(dev, buf, 27); ++ bf.ba_policy = (bf.ba_parameter >> 1) & 1; ++ bf.tid = (bf.ba_parameter >> 2) & 0xF; ++ bf.buffer_size = (bf.ba_parameter >> 6); ++ /* ++ * BA timeout value ++ */ ++ bf.ba_timeout = zmw_rx_buf_readh(dev, buf, 29); ++ /* ++ * BA starting sequence number ++ */ ++ bf.ba_start_seq = zmw_rx_buf_readh(dev, buf, 31) >> 4; ++ ++ i=26; ++ while(i < 32) { ++ zm_debug_msg2("Recv ADDBA Req:", zmw_rx_buf_readb(dev,buf,i)); ++ i++; ++ } ++ ++ zfAggSendAddbaResponse(dev, &bf); ++ ++ zfAggAddbaSetTidRx(dev, buf, &bf); ++ ++ return ZM_SUCCESS; ++} ++ ++u16_t zfAggAddbaSetTidRx(zdev_t* dev, zbuf_t* buf, struct aggBaFrameParameter *bf) ++{ ++ u16_t i, ac, aid, fragOff; ++ u16_t src[3]; ++ u16_t offset = 0; ++ u8_t up; ++ struct agg_tid_rx *tid_rx = NULL; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ src[0] = zmw_rx_buf_readh(dev, buf, offset+10); ++ src[1] = zmw_rx_buf_readh(dev, buf, offset+12); ++ src[2] = zmw_rx_buf_readh(dev, buf, offset+14); ++ aid = zfApFindSta(dev, src); ++ ++ zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); ++ ac = zcUpToAc[up&0x7] & 0x3; ++ ++ ac = bf->tid; ++ ++ for (i=0; itid_rx[i]->aid == aid) && (wd->tid_rx[i]->ac == ac)) ++ { ++ tid_rx = wd->tid_rx[i]; ++ break; ++ } ++ } ++ ++ if (!tid_rx) ++ { ++ for (i=0; itid_rx[i]->aid == ZM_MAX_STA_SUPPORT) ++ { ++ tid_rx = wd->tid_rx[i]; ++ break; ++ } ++ } ++ if (!tid_rx) ++ return 0; ++ } ++ ++ zmw_enter_critical_section(dev); ++ ++ tid_rx->aid = aid; ++ tid_rx->ac = ac; ++ tid_rx->addBaExchangeStatusCode = ZM_AGG_ADDBA_RESPONSE; ++ tid_rx->seq_start = bf->ba_start_seq; ++ tid_rx->baw_head = tid_rx->baw_tail = 0; ++ tid_rx->sq_exceed_count = tid_rx->sq_behind_count = 0; ++ zmw_leave_critical_section(dev); ++ ++ return 0; ++} ++ ++u16_t zfAggRecvAddbaResponse(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t i,ac, aid=0; ++ u16_t src[3]; ++ struct aggBaFrameParameter bf; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ src[0] = zmw_rx_buf_readh(dev, buf, 10); ++ src[1] = zmw_rx_buf_readh(dev, buf, 12); ++ src[2] = zmw_rx_buf_readh(dev, buf, 14); ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ aid = zfApFindSta(dev, src); ++ ++ ++ bf.buf = buf; ++ bf.dialog = zmw_rx_buf_readb(dev, buf, 26); ++ bf.status_code = zmw_rx_buf_readh(dev, buf, 27); ++ if (!bf.status_code) ++ { ++ wd->addbaComplete=1; ++ } ++ ++ /* ++ * ba parameter set ++ */ ++ bf.ba_parameter = zmw_rx_buf_readh(dev, buf, 29); ++ bf.ba_policy = (bf.ba_parameter >> 1) & 1; ++ bf.tid = (bf.ba_parameter >> 2) & 0xF; ++ bf.buffer_size = (bf.ba_parameter >> 6); ++ /* ++ * BA timeout value ++ */ ++ bf.ba_timeout = zmw_rx_buf_readh(dev, buf, 31); ++ ++ i=26; ++ while(i < 32) { ++ zm_debug_msg2("Recv ADDBA Rsp:", zmw_rx_buf_readb(dev,buf,i)); ++ i++; ++ } ++ ++ ac = zcUpToAc[bf.tid&0x7] & 0x3; ++ ++ //zmw_enter_critical_section(dev); ++ ++ //wd->aggSta[aid].aggFlag[ac] = 0; ++ ++ //zmw_leave_critical_section(dev); ++ ++ return ZM_SUCCESS; ++} ++ ++u16_t zfAggRecvDelba(zdev_t* dev, zbuf_t* buf) ++{ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ return ZM_SUCCESS; ++} ++ ++u16_t zfAggSendAddbaResponse(zdev_t* dev, struct aggBaFrameParameter *bf) ++{ ++ zbuf_t* buf; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ //u16_t err; ++ u16_t offset = 0; ++ u16_t hlen = 32; ++ u16_t header[(24+25+1)/2]; ++ u16_t vap = 0; ++ u16_t i; ++ u8_t encrypt = 0; ++ u16_t dst[3]; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ ++ /* ++ * TBD : Maximum size of managment frame ++ */ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); ++ return ZM_SUCCESS; ++ } ++ ++ /* ++ * Reserve room for wlan header ++ */ ++ offset = hlen; ++ ++ /* ++ * add addba frame body ++ */ ++ offset = zfAggSetAddbaResponseFrameBody(dev, buf, bf, offset); ++ ++ ++ zfwBufSetSize(dev, buf, offset); ++ ++ /* ++ * Copy wlan header ++ */ ++ ++ dst[0] = zmw_rx_buf_readh(dev, bf->buf, 10); ++ dst[1] = zmw_rx_buf_readh(dev, bf->buf, 12); ++ dst[2] = zmw_rx_buf_readh(dev, bf->buf, 14); ++ zfAggGenAddbaHeader(dev, dst, header, offset-hlen, buf, vap, encrypt); ++ for (i=0; i<(hlen>>1); i++) ++ { ++ zmw_tx_buf_writeh(dev, buf, i*2, header[i]); ++ } ++ ++ /* Get buffer DMA address */ ++ //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) ++ //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) ++ //{ ++ // goto zlError; ++ //} ++ ++ //zm_msg2_mm(ZM_LV_2, "offset=", offset); ++ //zm_msg2_mm(ZM_LV_2, "hlen=", hlen); ++ //zm_msg2_mm(ZM_LV_2, "addrTblSize=", addrTblSize); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.len[0]=", addrTbl.len[0]); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.physAddrl[0]=", addrTbl.physAddrl[0]); ++ //zm_msg2_mm(ZM_LV_2, "buf->data=", buf->data); ++ ++ #if 0 ++ if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ #else ++ zfPutVmmq(dev, buf); ++ zfPushVtxq(dev); ++ #endif ++ ++ //zfAggSendAddbaRequest(dev, dst, zcUpToAc[bf->tid&0x7] & 0x3, bf->tid); ++ return ZM_SUCCESS; ++ ++} ++ ++u16_t zfAggSetAddbaResponseFrameBody(zdev_t* dev, zbuf_t* buf, ++ struct aggBaFrameParameter *bf, u16_t offset) ++{ ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ /* ++ * ADDBA Request frame body ++ */ ++ ++ /* ++ * Category ++ */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 3); ++ /* ++ * Action details = 0 ++ */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_ADDBA_RESPONSE_FRAME); ++ /* ++ * Dialog Token = nonzero ++ */ ++ zmw_tx_buf_writeb(dev, buf, offset++, bf->dialog); ++ /* ++ * Status code ++ */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0); ++ offset+=2; ++ /* ++ * Block Ack parameter set ++ * BA policy = 1 for immediate BA, 0 for delayed BA ++ * TID(4bits) & buffer size(4bits) (TID=0x1 & buffer size=0x80) ++ * TBD: how to get TID number and buffer size? ++ * ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++ * ¢x B0 ¢x B1 ¢x B2 B5 ¢x B6 B15 ¢x ++ * ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++ * ¢x Reserved ¢x BA policy ¢x TID ¢x Buffer size ¢x ++ * ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++ */ ++ zmw_tx_buf_writeh(dev, buf, offset, bf->ba_parameter); ++ offset+=2; ++ /* ++ * BA timeout value ++ */ ++ zmw_tx_buf_writeh(dev, buf, offset, bf->ba_timeout); ++ offset+=2; ++ ++ return offset; ++} ++ ++void zfAggInvokeBar(zdev_t* dev, TID_TX tid_tx) ++{ ++ struct aggBarControl aggBarControl; ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ //bar_control = aggBarControl->tid_info << 12 | aggBarControl->compressed_bitmap << 2 ++ // | aggBarControl->multi_tid << 1 | aggBarControl->bar_ack_policy; ++ aggBarControl.bar_ack_policy = 0; ++ aggBarControl.multi_tid = 0; ++ aggBarControl.compressed_bitmap = 0; ++ aggBarControl.tid_info = tid_tx->tid; ++ zfAggSendBar(dev, tid_tx, &aggBarControl); ++ ++ return; ++ ++} ++/* ++ * zfAggSendBar() refers zfAggSendAddbaRequest() ++ */ ++u16_t zfAggSendBar(zdev_t* dev, TID_TX tid_tx, struct aggBarControl *aggBarControl) ++{ ++ zbuf_t* buf; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ //u16_t err; ++ u16_t offset = 0; ++ u16_t hlen = 16+8; /* mac header + control headers*/ ++ u16_t header[(8+24+1)/2]; ++ u16_t vap = 0; ++ u16_t i; ++ u8_t encrypt = 0; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ ++ /* ++ * TBD : Maximum size of managment frame ++ */ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); ++ return ZM_SUCCESS; ++ } ++ ++ /* ++ * Reserve room for wlan header ++ */ ++ offset = hlen; ++ ++ /* ++ * add addba frame body ++ */ ++ offset = zfAggSetBarBody(dev, buf, offset, tid_tx, aggBarControl); ++ ++ ++ zfwBufSetSize(dev, buf, offset); ++ ++ /* ++ * Copy wlan header ++ */ ++ zfAggGenBarHeader(dev, tid_tx->dst, header, offset-hlen, buf, vap, encrypt); ++ for (i=0; i<(hlen>>1); i++) ++ { ++ zmw_tx_buf_writeh(dev, buf, i*2, header[i]); ++ } ++ ++ /* Get buffer DMA address */ ++ //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) ++ //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) ++ //{ ++ // goto zlError; ++ //} ++ ++ //zm_msg2_mm(ZM_LV_2, "offset=", offset); ++ //zm_msg2_mm(ZM_LV_2, "hlen=", hlen); ++ //zm_msg2_mm(ZM_LV_2, "addrTblSize=", addrTblSize); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.len[0]=", addrTbl.len[0]); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.physAddrl[0]=", addrTbl.physAddrl[0]); ++ //zm_msg2_mm(ZM_LV_2, "buf->data=", buf->data); ++ ++ #if 0 ++ if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ #else ++ zfPutVmmq(dev, buf); ++ zfPushVtxq(dev); ++ #endif ++ ++ return ZM_SUCCESS; ++ ++} ++ ++u16_t zfAggSetBarBody(zdev_t* dev, zbuf_t* buf, u16_t offset, TID_TX tid_tx, struct aggBarControl *aggBarControl) ++{ ++ u16_t bar_control, start_seq; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ /* ++ * BAR Control frame body ++ */ ++ ++ /* ++ * BAR Control Field ++ * ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++ * ¢x B0 ¢x B1 ¢x B2 ¢x B3 B11 ¢x B12 B15 ¢x ++ * ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++ * ¢x BAR Ack ¢x Multi-TID ¢x Compressed ¢x Reserved ¢x TID_INFO ¢x ++ * ¢x Policy ¢x ¢x Bitmap ¢x ¢x ¢x ++ * ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++ */ ++ bar_control = aggBarControl->tid_info << 12 | aggBarControl->compressed_bitmap << 2 ++ | aggBarControl->multi_tid << 1 | aggBarControl->bar_ack_policy; ++ ++ zmw_tx_buf_writeh(dev, buf, offset, bar_control); ++ offset+=2; ++ if (0 == aggBarControl->multi_tid) { ++ /* ++ * BA starting sequence number ++ * ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++ * ¢x B0 B3 ¢x B4 B15 ¢x ++ * ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++ * ¢x Frag num(0) ¢x BA starting seq num ¢x ++ * ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++ */ ++ start_seq = (tid_tx->bar_ssn << 4) & 0xFFF0; ++ zmw_tx_buf_writeh(dev, buf, offset, start_seq); ++ offset+=2; ++ } ++ if (1 == aggBarControl->multi_tid && 1 == aggBarControl->compressed_bitmap) { ++ /* multi-tid BlockAckReq variant, not implemented*/ ++ } ++ ++ return offset; ++} ++ ++u16_t zfAggGenBarHeader(zdev_t* dev, u16_t* dst, ++ u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt) ++{ ++ u8_t hlen = 16+8; // MAC ctrl + PHY ctrl + 802.11 MM header ++ //u8_t frameType = ZM_WLAN_FRAME_TYPE_ACTION; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* ++ * Generate control setting ++ */ ++ //bodyLen = zfwBufGetSize(dev, buf); ++ header[0] = 16+len+4; //Length ++ header[1] = 0x8; //MAC control, backoff + (ack) ++ ++#if 1 ++ /* CCK 1M */ ++ header[2] = 0x0f00; //PHY control L ++ header[3] = 0x0000; //PHY control H ++#else ++ /* CCK 6M */ ++ header[2] = 0x0f01; //PHY control L ++ header[3] = 0x000B; //PHY control H ++ ++#endif ++ /* ++ * Generate WLAN header ++ * Frame control frame type and subtype ++ */ ++ header[4+0] = ZM_WLAN_FRAME_TYPE_BAR; ++ /* ++ * Duration ++ */ ++ header[4+1] = 0; ++ ++ /* Address 1 = DA */ ++ header[4+2] = dst[0]; ++ header[4+3] = dst[1]; ++ header[4+4] = dst[2]; ++ ++ /* Address 2 = SA */ ++ header[4+5] = wd->macAddr[0]; ++ header[4+6] = wd->macAddr[1]; ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ header[4+7] = wd->macAddr[2]; //Multiple SSID ++#else ++ header[4+7] = wd->macAddr[2] + (vap<<8); //VAP ++#endif ++ } ++ else ++ { ++ header[4+7] = wd->macAddr[2]; ++ } ++ ++ /* Sequence Control */ ++ zmw_enter_critical_section(dev); ++ header[4+11] = ((wd->mmseq++)<<4); ++ zmw_leave_critical_section(dev); ++ ++ ++ return hlen; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cagg.h +@@ -0,0 +1,435 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : cagg.h */ ++/* */ ++/* Abstract */ ++/* This module contains A-MPDU aggregation relatived functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/****************************************************************************/ ++/*Revision History: */ ++/* Who When What */ ++/* -------- -------- ----------------------------------------------*/ ++/* */ ++/* Honda 12-4-06 created */ ++/* */ ++/****************************************************************************/ ++ ++#ifndef _CAGG_H ++#define _CAGG_H ++ ++ ++/* ++ * the aggregation functions flag, 0 if don't do aggregate ++ */ ++ ++#define ZM_AGG_FPGA_DEBUG 1 ++#define ZM_AGG_FPGA_REORDERING 1 ++ ++#ifndef ZM_AGG_TALLY ++//#define ZM_AGG_TALLY ++#endif ++/* ++ * Aggregate control ++ */ ++ ++ ++#define ZM_AGG_POOL_SIZE 20 ++#define ZM_BAW_POOL_SIZE 32 ++#define ZM_AGGQ_SIZE 64 ++#define ZM_AGGQ_SIZE_MASK (ZM_AGGQ_SIZE-1) ++#define ZM_AGG_LOW_THRESHOLD 1 ++#define ZM_AGG_HIGH_THRESHOLD 5 ++ ++/* ++ * number of access categories (ac) ++ */ ++#define ZM_AC 4 ++/* ++ * the timer to clear aggregation queue, unit: 1 tick ++ * if the packet is too old (current time - arrival time) ++ * the packet and the aggregate queue will be cleared ++ */ ++#define ZM_AGG_CLEAR_TIME 10 ++/* ++ * delete the queue if idle for ZM_DELETE_TIME ++ * unit: 10ms ++ */ ++#define ZM_AGG_DELETE_TIME 10000 ++ ++/* ++ * block ack window size ++ */ ++#define ZM_AGG_BAW_SIZE 64 ++#define ZM_AGG_BAW_MASK (ZM_AGG_BAW_SIZE-1) ++/* ++ * originator ADDBA Resquest receiver ++ * |----------------------------->| ++ * 1| ACK |1 ++ * |<-----------------------------| ++ * 2| ADDBA Response |2 ++ * |<-----------------------------| ++ * 3| ACK |3 ++ * |----------------------------->| ++ * 4 4 ++ */ ++#define ZM_AGG_ADDBA_REQUEST 1 ++#define ZM_AGG_ADDBA_REQUEST_ACK 2 ++#define ZM_AGG_ADDBA_RESPONSE 3 ++#define ZM_AGG_ADDBA_RESPONSE_ACK 4 ++ ++#define ZM_AGG_SINGLE_MPDU 00 ++#define ZM_AGG_FIRST_MPDU 01 ++#define ZM_AGG_MIDDLE_MPDU 11 ++#define ZM_AGG_LAST_MPDU 10 ++/* ++ * end of Aggregate control ++ */ ++ ++#define TID_TX struct aggQueue* ++#define TID_BAW struct baw_q* ++#define BAW wd->baw_enabler ++#define DESTQ wd->destQ ++ ++/* ++ * Queue access ++ */ ++#define zm_agg_qlen(dev, head, tail) ((head - tail) & ZM_AGGQ_SIZE_MASK) ++#define zm_agg_inQ(tid_tx, pt) ((((pt - tid_tx->aggTail) & ZM_AGGQ_SIZE_MASK) < \ ++ ((tid_tx->aggHead - tid_tx->aggTail) & ZM_AGGQ_SIZE_MASK))? TRUE:FALSE) ++#define zm_agg_plus(pt) pt = (pt + 1) & ZM_AGGQ_SIZE_MASK ++#define zm_agg_min(A, B) ((A>B)? B:A) ++#define zm_agg_GetTime() wd->tick ++#define TXQL (zfHpGetMaxTxdCount(dev) - zfHpGetFreeTxdCount(dev)) ++ ++/* don't change AGG_MIN_TXQL easily, this might cause BAW BSOD */ ++#define AGG_MIN_TXQL 2 ++/* ++ * consider tcp,udp,ac(1234) ++ */ ++#define zm_agg_dynamic_threshold(dev, ar) ((ar > 16)? 11: \ ++ (ar > 12)? 8: \ ++ (ar > 8)? 5: \ ++ (ar > 4)? 2:1) ++#define zm_agg_weight(ac) ((3 == ac)? 4: \ ++ (2 == ac)? 3: \ ++ (0 == ac)? 2:1) ++/* ++ * the required free queue ratio per ac ++ */ ++ ++#define zm_agg_ratio(ac) ((3 == ac)? 3: \ ++ (2 == ac)? (zfHpGetMaxTxdCount(dev)*1/4): \ ++ (0 == ac)? (zfHpGetMaxTxdCount(dev)*2/4): \ ++ (zfHpGetMaxTxdCount(dev)*3/4)) ++ ++//#define zm_agg_ratio(ac) 3 ++/* ++ * end of Queue access ++ */ ++ ++#define ZM_AGGMSG_LEV ZM_LV_3 ++#define zm_msg0_agg(lv, msg) if (ZM_AGGMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_agg(lv, msg, val) if (ZM_AGGMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_agg(lv, msg, val) if (ZM_AGGMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++struct baw_header_r { ++ u16_t *header; ++ u16_t *mic; ++ u16_t *snap; ++ u16_t headerLen; ++ u16_t micLen; ++ u16_t snapLen; ++ u16_t removeLen; ++ u8_t keyIdx; ++}; ++ ++struct baw_header { ++ u16_t header[29];//[(8+30+2+18)/2]; 58 bytes /* ctr+(4+a1+a2+a3+2+a4)+qos+iv */ ++ u16_t headerLen; ++ u16_t mic[4]; //[8/2]; 8 bytes ++ u16_t micLen; ++ u16_t snap[4]; //[8/2]; 8 bytes ++ u16_t snapLen; ++ u16_t removeLen; ++ u8_t keyIdx; ++}; ++ ++struct bufInfo { ++ zbuf_t* buf; ++ u8_t baw_retransmit; ++ u32_t timestamp; ++ struct baw_header *baw_header; ++}; ++#endif ++struct aggElement ++{ ++ zbuf_t* buf; ++ u32_t arrivalTime; ++ u8_t baw_retransmit; ++ struct zsAdditionInfo addInfo; ++ //struct baw_header baw_header; ++}; ++ ++ ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++struct baw_buf ++{ ++ zbuf_t* buf; ++ u16_t baw_seq; ++ u32_t timestamp; ++ u8_t baw_retransmit; ++ struct baw_header baw_header; ++}; ++ ++struct baw_q { ++ struct baw_buf frame[ZM_VTXQ_SIZE]; ++ u16_t enabled; ++ u16_t start_seq; ++ u16_t head; ++ u16_t tail; ++ u16_t size; ++ TID_TX tid_tx; ++ ++ //struct baw_header *baw_header; ++}; ++ ++struct baw_enabler ++{ ++ struct baw_q tid_baw[ZM_BAW_POOL_SIZE]; ++ u8_t delPoint; ++ void (*core)(zdev_t* dev, u16_t baw_seq, u32_t bitmap, u16_t aggLen); ++ //void (*core); ++ void (*init)(zdev_t* dev); ++ TID_BAW (*getNewQ)(zdev_t* dev, u16_t start_seq, TID_TX tid_tx); ++ TID_BAW (*getQ)(zdev_t* dev, u16_t baw_seq); ++ u16_t (*insert)(zdev_t* dev, zbuf_t* buf, u16_t baw_seq, TID_BAW tid_baw, u8_t baw_retransmit, struct baw_header_r *header_r); ++ struct bufInfo* (*pop)(zdev_t* dev, u16_t index, TID_BAW tid_baw); ++ void (*enable)(zdev_t* dev, TID_BAW tid_baw, u16_t start_seq); ++ void (*disable)(zdev_t* dev, TID_BAW tid_baw); ++ ++}; ++#endif ++struct aggQueue ++{ ++ struct aggElement aggvtxq[ZM_AGGQ_SIZE]; ++ u16_t aggHead; ++ u16_t aggTail; ++ s16_t size; ++ u16_t aggQSTA; ++ u16_t aggQEnabled; ++ u16_t ac; ++ u16_t tid; ++ u16_t aggReady; ++ u16_t clearFlag; ++ u16_t deleteFlag; ++ u32_t lastArrival; ++ u16_t aggFrameSize; ++ u16_t bar_ssn; /* starting sequence number in BAR */ ++ u16_t dst[3]; ++ u16_t complete; /* complete indication pointer */ ++}; ++ ++struct aggSta ++{ ++ u16_t count[ZM_AC]; ++ TID_TX tid_tx[8]; ++ u16_t aggFlag[ZM_AC]; ++}; ++ ++struct agg_tid_rx ++{ ++ u16_t aid; ++ u16_t ac; ++ u16_t addBaExchangeStatusCode; ++ //struct zsAdditionInfo *addInfo; ++ u16_t seq_start; /* first seq expected next */ ++ u16_t baw_head; /* head of valid block ack window */ ++ u16_t baw_tail; /* tail of valid block ack window */ ++ //u16_t free_count; /* block ack window size */ ++ u8_t sq_exceed_count; ++ u8_t sq_behind_count; ++ struct aggElement frame[ZM_AGG_BAW_SIZE + 1]; /* out-of-order rx frames */ ++}; ++ ++struct aggControl ++{ ++ u16_t aggEnabled; ++ u16_t ampduIndication; ++ u16_t addbaIndication; ++ //TID_BAW tid_baw; ++ u32_t timestamp; ++}; ++ ++struct aggBaFrameParameter ++{ ++ zbuf_t* buf; ++ u16_t ba_parameter; ++ u8_t dialog; ++ u16_t ba_policy; ++ u16_t tid; ++ u16_t buffer_size; ++ u16_t ba_timeout; ++ u16_t ba_start_seq; ++ u16_t status_code; ++}; ++ ++struct aggBarControl ++{ ++ u16_t bar_ack_policy ; ++ u16_t multi_tid ; ++ u16_t compressed_bitmap ; ++ u16_t tid_info ; ++}; ++ ++struct aggTally ++{ ++ u32_t got_packets_sum; ++ u32_t got_bytes_sum; ++ u32_t sent_packets_sum; ++ u32_t sent_bytes_sum; ++ u32_t avg_got_packets; ++ u32_t avg_got_bytes; ++ u32_t avg_sent_packets; ++ u32_t avg_sent_bytes; ++ u16_t time; ++}; ++ ++ ++struct destQ { ++ struct dest{ ++ u16_t Qtype : 1; /* 0 aggr, 1 vtxq */ ++ TID_TX tid_tx; ++ void* vtxq; ++ ++ struct dest* next; ++ } *dest[4]; ++ struct dest* Head[4]; ++ //s16_t size[4]; ++ u16_t ppri; ++ void (*insert)(zdev_t* dev, u16_t Qtype, u16_t ac, TID_TX tid_tx, void* vtxq); ++ void (*delete)(zdev_t* dev, u16_t Qtype, TID_TX tid_tx, void* vtxq); ++ void (*init)(zdev_t* dev); ++ struct dest* (*getNext)(zdev_t* dev, u16_t ac); ++ u16_t (*exist)(zdev_t* dev, u16_t Qtype, u16_t ac, TID_TX tid_tx, void* vtxq); ++ //void (*scan)(zdev_t* dev); ++}; ++/* ++ * aggregation tx ++ */ ++void zfAggInit(zdev_t* dev); ++u16_t zfApFindSta(zdev_t* dev, u16_t* addr); ++u16_t zfAggGetSta(zdev_t* dev, zbuf_t* buf); ++TID_TX zfAggTxGetQueue(zdev_t* dev, u16_t aid, u16_t tid); ++TID_TX zfAggTxNewQueue(zdev_t* dev, u16_t aid, u16_t tid, zbuf_t* buf); ++u16_t zfAggTxEnqueue(zdev_t* dev, zbuf_t* buf, u16_t aid, TID_TX tid_tx); ++u16_t zfAggTx(zdev_t* dev, zbuf_t* buf, u16_t tid); ++u16_t zfAggTxReadyCount(zdev_t* dev, u16_t ac); ++u16_t zfAggTxPartial(zdev_t* dev, u16_t ac, u16_t readycount); ++u16_t zfAggTxSend(zdev_t* dev, u32_t freeTxd, TID_TX tid_tx); ++TID_TX zfAggTxGetReadyQueue(zdev_t* dev, u16_t ac); ++zbuf_t* zfAggTxGetVtxq(zdev_t* dev, TID_TX tid_tx); ++u16_t zfAggTxDeleteQueue(zdev_t* dev, u16_t qnum); ++u16_t zfAggScanAndClear(zdev_t* dev, u32_t time); ++u16_t zfAggClearQueue(zdev_t* dev); ++void zfAggTxScheduler(zdev_t* dev, u8_t ScanAndClear); ++ ++/* tid_tx manipulation */ ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++u16_t zfAggTidTxInsertHead(zdev_t* dev, struct bufInfo* buf_info, TID_TX tid_tx); ++#endif ++void zfAggDestInsert(zdev_t* dev, u16_t Qtype, u16_t ac, TID_TX tid_tx, void* vtxq); ++void zfAggDestDelete(zdev_t* dev, u16_t Qtype, TID_TX tid_tx, void* vtxq); ++void zfAggDestInit(zdev_t* dev); ++struct dest* zfAggDestGetNext(zdev_t* dev, u16_t ac); ++u16_t zfAggDestExist(zdev_t* dev, u16_t Qtype, u16_t ac, TID_TX tid_tx, void* vtxq); ++/* ++ * aggregation rx ++ */ ++struct agg_tid_rx *zfAggRxEnabled(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggRx(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo *addInfo, struct agg_tid_rx *tid_rx); ++struct agg_tid_rx *zfAggRxGetQueue(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggRxEnqueue(zdev_t* dev, zbuf_t* buf, struct agg_tid_rx *tid_rx, struct zsAdditionInfo *addInfo); ++u16_t zfAggRxFlush(zdev_t* dev, u16_t seq_no, struct agg_tid_rx *tid_rx); ++u16_t zfAggRxFreeBuf(zdev_t* dev, u16_t destroy); ++u16_t zfAggRxClear(zdev_t* dev, u32_t time); ++void zfAggRecvBAR(zdev_t* dev, zbuf_t* buf); ++/* ++ * end of aggregation rx ++ */ ++ ++/* ++ * ADDBA ++ */ ++u16_t zfAggSendAddbaRequest(zdev_t* dev, u16_t *dst, u16_t ac, u16_t up); ++u16_t zfAggSetAddbaFrameBody(zdev_t* dev,zbuf_t* buf, u16_t offset, u16_t ac, u16_t up); ++u16_t zfAggGenAddbaHeader(zdev_t* dev, u16_t* dst, ++ u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt); ++u16_t zfAggProcessAction(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggBlockAckActionFrame(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggRecvAddbaRequest(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggRecvAddbaResponse(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggRecvDelba(zdev_t* dev, zbuf_t* buf); ++u16_t zfAggSendAddbaResponse(zdev_t* dev, struct aggBaFrameParameter *bf); ++u16_t zfAggSetAddbaResponseFrameBody(zdev_t* dev, zbuf_t* buf, ++ struct aggBaFrameParameter *bf, u16_t offset); ++u16_t zfAggAddbaSetTidRx(zdev_t* dev, zbuf_t* buf, ++ struct aggBaFrameParameter *bf); ++/* ++ * zfAggTxSendEth ++ */ ++u16_t zfAggTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, u16_t bufType, u8_t flag, struct aggControl *aggControl, TID_TX tid_tx); ++ ++/* ++ * statistics functions ++ */ ++u16_t zfAggTallyReset(zdev_t* dev); ++ ++u16_t zfAggPrintTally(zdev_t* dev); ++ ++/* ++ * BAR ++ */ ++void zfAggInvokeBar(zdev_t* dev, TID_TX tid_tx); ++u16_t zfAggSendBar(zdev_t* dev, TID_TX tid_tx, struct aggBarControl *aggBarControl); ++u16_t zfAggSetBarBody(zdev_t* dev, zbuf_t* buf, u16_t offset, TID_TX tid_tx, struct aggBarControl *aggBarControl); ++u16_t zfAggGenBarHeader(zdev_t* dev, u16_t* dst, ++ u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt); ++ ++#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION //disable BAW ++/* BAW BA retransmission */ ++void zfBawCore(zdev_t* dev, u16_t baw_seq, u32_t bitmap, u16_t aggLen); ++void zfBawInit(zdev_t* dev); ++TID_BAW zfBawGetNewQ(zdev_t* dev, u16_t start_seq, TID_TX tid_tx); ++u16_t zfBawInsert(zdev_t* dev, zbuf_t* buf, u16_t baw_seq, TID_BAW tid_baw, u8_t baw_retransmit, struct baw_header_r *header_r); ++struct bufInfo* zfBawPop(zdev_t* dev, u16_t index, TID_BAW tid_baw); ++void zfBawEnable(zdev_t* dev, TID_BAW tid_baw, u16_t start_seq); ++void zfBawDisable(zdev_t* dev, TID_BAW tid_baw); ++TID_BAW zfBawGetQ(zdev_t* dev, u16_t baw_seq); ++void zfAggTxRetransmit(zdev_t* dev, struct bufInfo *buf_info, struct aggControl *aggControl, TID_TX tid_tx); ++#endif ++/* extern functions */ ++extern zbuf_t* zfGetVtxq(zdev_t* dev, u8_t ac); ++ ++#endif /* #ifndef _CAGG_H */ ++ +--- /dev/null ++++ b/drivers/staging/otus/80211core/ccmd.c +@@ -0,0 +1,1861 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : cmd.c */ ++/* */ ++/* Abstract */ ++/* This module contains command interface functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#include "../hal/hpreg.h" ++ ++ ++u16_t zfWlanReset(zdev_t* dev); ++u32_t zfUpdateRxRate(zdev_t* dev); ++ ++ ++extern void zfiUsbRecv(zdev_t *dev, zbuf_t *buf); ++extern void zfiUsbRegIn(zdev_t* dev, u32_t* rsp, u16_t rspLen); ++extern void zfiUsbOutComplete(zdev_t* dev, zbuf_t *buf, u8_t status, u8_t *hdr); ++extern void zfiUsbRegOutComplete(zdev_t* dev); ++extern u16_t zfHpReinit(zdev_t* dev, u32_t frequency); ++ ++/* Get size (byte) of driver core global data structure. */ ++/* This size will be used by driver wrapper to allocate */ ++/* a memory space for driver core to store global variables */ ++u16_t zfiGlobalDataSize(zdev_t* dev) ++{ ++ u32_t ret; ++ ret = (sizeof(struct zsWlanDev)); ++ zm_assert((ret>>16) == 0); ++ return (u16_t)ret; ++} ++ ++ ++/* Initialize WLAN hardware and software, resource will be allocated */ ++/* for WLAN operation, must be called first before other function. */ ++extern u16_t zfiWlanOpen(zdev_t* dev, struct zsCbFuncTbl* cbFuncTbl) ++{ ++ //u16_t ret; ++ //u32_t i; ++ //u8_t* ch; ++ //u8_t bPassive; ++ u32_t devSize; ++ struct zfCbUsbFuncTbl cbUsbFuncTbl; ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg0("start"); ++ ++ devSize = sizeof(struct zsWlanDev); ++ /* Zeroize zsWlanDev struct */ ++ zfZeroMemory((u8_t*)wd, (u16_t)devSize); ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ zfAggInit(dev); ++#endif ++ ++ zfCwmInit(dev); ++ ++ wd->commTally.RateCtrlTxMPDU = 0; ++ wd->commTally.RateCtrlBAFail = 0; ++ wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; ++ ++ if (cbFuncTbl == NULL) ++ { ++ /* zfcbRecvEth() is mandatory */ ++ zm_assert(0); ++ } ++ else ++ { ++ if (cbFuncTbl->zfcbRecvEth == NULL) ++ { ++ /* zfcbRecvEth() is mandatory */ ++ zm_assert(0); ++ } ++ wd->zfcbAuthNotify = cbFuncTbl->zfcbAuthNotify; ++ wd->zfcbAuthNotify = cbFuncTbl->zfcbAuthNotify; ++ wd->zfcbAsocNotify = cbFuncTbl->zfcbAsocNotify; ++ wd->zfcbDisAsocNotify = cbFuncTbl->zfcbDisAsocNotify; ++ wd->zfcbApConnectNotify = cbFuncTbl->zfcbApConnectNotify; ++ wd->zfcbConnectNotify = cbFuncTbl->zfcbConnectNotify; ++ wd->zfcbScanNotify = cbFuncTbl->zfcbScanNotify; ++ wd->zfcbMicFailureNotify = cbFuncTbl->zfcbMicFailureNotify; ++ wd->zfcbApMicFailureNotify = cbFuncTbl->zfcbApMicFailureNotify; ++ wd->zfcbIbssPartnerNotify = cbFuncTbl->zfcbIbssPartnerNotify; ++ wd->zfcbMacAddressNotify = cbFuncTbl->zfcbMacAddressNotify; ++ wd->zfcbSendCompleteIndication = cbFuncTbl->zfcbSendCompleteIndication; ++ wd->zfcbRecvEth = cbFuncTbl->zfcbRecvEth; ++ wd->zfcbRestoreBufData = cbFuncTbl->zfcbRestoreBufData; ++ wd->zfcbRecv80211 = cbFuncTbl->zfcbRecv80211; ++#ifdef ZM_ENABLE_CENC ++ wd->zfcbCencAsocNotify = cbFuncTbl->zfcbCencAsocNotify; ++#endif //ZM_ENABLE_CENC ++ wd->zfcbClassifyTxPacket = cbFuncTbl->zfcbClassifyTxPacket; ++ wd->zfcbHwWatchDogNotify = cbFuncTbl->zfcbHwWatchDogNotify; ++ } ++ ++ //add by honda 0330 ++ cbUsbFuncTbl.zfcbUsbRecv = zfiUsbRecv; ++ cbUsbFuncTbl.zfcbUsbRegIn = zfiUsbRegIn; ++ cbUsbFuncTbl.zfcbUsbOutComplete = zfiUsbOutComplete; ++ cbUsbFuncTbl.zfcbUsbRegOutComplete = zfiUsbRegOutComplete; ++ zfwUsbRegisterCallBack(dev, &cbUsbFuncTbl); ++ /* Init OWN MAC address */ ++ wd->macAddr[0] = 0x8000; ++ wd->macAddr[1] = 0x0000; ++ wd->macAddr[2] = 0x0000; ++ ++ wd->regulationTable.regionCode = 0xffff; ++ ++ zfHpInit(dev, wd->frequency); ++ ++ /* init region code */ ++ //wd->regulationTable.regionCode = NULL1_WORLD; //Only 2.4g RegCode ++ //zfHpGetRegulationTablefromRegionCode(dev, NULL1_WORLD); ++ //zfiWlanSetDot11DMode(dev , 1); // Enable 802.11d ++ /* Get the first channel */ ++ //wd->frequency = zfChGetFirstChannel(dev, &bPassive); ++#ifdef ZM_AP_DEBUG ++ //wd->frequency = 2437; ++#endif ++ ++ //STA mode ++ wd->sta.mTxRate = 0x0; ++ wd->sta.uTxRate = 0x3; ++ wd->sta.mmTxRate = 0x0; ++ wd->sta.adapterState = ZM_STA_STATE_DISCONNECT; ++ wd->sta.capability[0] = 0x01; ++ wd->sta.capability[1] = 0x00; ++ ++ wd->sta.preambleTypeHT = 0; ++ wd->sta.htCtrlBandwidth = 0; ++ wd->sta.htCtrlSTBC = 0; ++ wd->sta.htCtrlSG = 0; ++ wd->sta.defaultTA = 0; ++ //wd->sta.activescanTickPerChannel = ZM_TIME_ACTIVE_SCAN/ZM_MS_PER_TICK; ++ { ++ u8_t Dur = ZM_TIME_ACTIVE_SCAN; ++ zfwGetActiveScanDur(dev, &Dur); ++ wd->sta.activescanTickPerChannel = Dur/ZM_MS_PER_TICK; ++ ++ } ++ wd->sta.passiveScanTickPerChannel = ZM_TIME_PASSIVE_SCAN/ZM_MS_PER_TICK; ++ wd->sta.bAutoReconnect = TRUE; ++ wd->sta.dropUnencryptedPkts = FALSE; ++ ++ /* set default to bypass all multicast packet for linux, window XP would set 0 by wrapper initialization */ ++ wd->sta.bAllMulticast = 1; ++ ++ /* Initial the RIFS Status / RIFS-like frame count / RIFS count */ ++ wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; ++ wd->sta.rifsLikeFrameCnt = 0; ++ wd->sta.rifsCount = 0; ++ ++ wd->sta.osRxFilter = 0; ++ wd->sta.bSafeMode = 0; ++ ++ //Common ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_DISCONNECT); ++ wd->beaconInterval = 100; ++ wd->rtsThreshold = 2346; ++ wd->fragThreshold = 32767; ++ wd->wlanMode = ZM_MODE_INFRASTRUCTURE; ++ wd->txMCS = 0xff; //AUTO ++ wd->dtim = 1; ++ //wd->txMT = 1; //OFDM ++ wd->tick = 1; ++ wd->maxTxPower2 = 0xff; ++ wd->maxTxPower5 = 0xff; ++ wd->supportMode = 0xffffffff; ++ wd->ws.adhocMode = ZM_ADHOCBAND_G; ++ wd->ws.autoSetFrequency = 0xff; ++ ++ //AP mode ++ //wd->bgMode = wd->ws.bgMode; ++ wd->ap.ssidLen[0] = 6; ++ wd->ap.ssid[0][0] = 'Z'; ++ wd->ap.ssid[0][1] = 'D'; ++ wd->ap.ssid[0][2] = '1'; ++ wd->ap.ssid[0][3] = '2'; ++ wd->ap.ssid[0][4] = '2'; ++ wd->ap.ssid[0][5] = '1'; ++ ++ // Init the country iso name as NA ++ wd->ws.countryIsoName[0] = 0; ++ wd->ws.countryIsoName[1] = 0; ++ wd->ws.countryIsoName[2] = '\0'; ++ ++ /* init fragmentation is disabled */ ++ //zfiWlanSetFragThreshold(dev, 0); ++ ++ /* airopeek : swSniffer 1=>on 0=>off */ ++ wd->swSniffer = 0; ++ wd->XLinkMode = 0; ++ ++// jhlee HT 0 ++#if 1 ++ /* AP Mode*/ ++ /* Init HT Capability Info */ ++ wd->ap.HTCap.Data.ElementID = ZM_WLAN_EID_HT_CAPABILITY; ++ wd->ap.HTCap.Data.Length = 26; ++ //wd->ap.HTCap.Data.SupChannelWidthSet = 0; ++ //wd->ap.HTCap.Data.MIMOPowerSave = 3; ++ //wd->ap.HTCap.Data.ShortGIfor40MHz = 0; ++ //wd->ap.HTCap.Data.ShortGIfor20MHz = 0; ++ //wd->ap.HTCap.Data.DSSSandCCKin40MHz = 0; ++ wd->ap.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; ++ wd->ap.HTCap.Data.MCSSet[0] = 0xFF; // MCS 0 ~ 7 ++ wd->ap.HTCap.Data.MCSSet[1] = 0xFF; // MCS 8 ~ 15 ++ ++ /* Init Extended HT Capability Info */ ++ wd->ap.ExtHTCap.Data.ElementID = ZM_WLAN_EID_EXTENDED_HT_CAPABILITY; ++ wd->ap.ExtHTCap.Data.Length = 22; ++ wd->ap.ExtHTCap.Data.ControlChannel = 6; ++ //wd->ap.ExtHTCap.Data.ExtChannelOffset = 3; ++ wd->ap.ExtHTCap.Data.ChannelInfo |= ExtHtCap_RecomTxWidthSet; ++ //wd->ap.ExtHTCap.Data.RIFSMode = 1; ++ wd->ap.ExtHTCap.Data.OperatingInfo |= 1; ++ ++ /* STA Mode*/ ++ /* Init HT Capability Info */ ++ wd->sta.HTCap.Data.ElementID = ZM_WLAN_EID_HT_CAPABILITY; ++ wd->sta.HTCap.Data.Length = 26; ++ ++ /* Test with 5G-AP : 7603 */ ++ //wd->sta.HTCap.Data.SupChannelWidthSet = 1; ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SMEnabled; ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_ShortGIfor40MHz; ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_DSSSandCCKin40MHz; ++#ifndef ZM_DISABLE_AMSDU8K_SUPPORT ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_MaxAMSDULength; ++#endif ++ //wd->sta.HTCap.Data.MIMOPowerSave = 0; ++ //wd->sta.HTCap.Data.ShortGIfor40MHz = 0; ++ //wd->sta.HTCap.Data.ShortGIfor20MHz = 0; ++ //wd->sta.HTCap.Data.DSSSandCCKin40MHz = 0; ++ wd->sta.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; ++ wd->sta.HTCap.Data.MCSSet[0] = 0xFF; // MCS 0 ~ 7 ++ wd->sta.HTCap.Data.MCSSet[1] = 0xFF; // MCS 8 ~ 15 ++ wd->sta.HTCap.Data.PCO |= HTCAP_TransmissionTime3; ++ //wd->sta.HTCap.Data.TransmissionTime = 0; ++ /* Init Extended HT Capability Info */ ++ wd->sta.ExtHTCap.Data.ElementID = ZM_WLAN_EID_EXTENDED_HT_CAPABILITY; ++ wd->sta.ExtHTCap.Data.Length = 22; ++ wd->sta.ExtHTCap.Data.ControlChannel = 6; ++ ++ //wd->sta.ExtHTCap.Data.ExtChannelOffset |= 3; ++ wd->sta.ExtHTCap.Data.ChannelInfo |= ExtHtCap_ExtChannelOffsetBelow; ++ ++ //wd->sta.ExtHTCap.Data.RecomTxWidthSet = 1; ++ //wd->sta.ExtHTCap.Data.RIFSMode = 1; ++ wd->sta.ExtHTCap.Data.OperatingInfo |= 1; ++#endif ++ ++#if 0 ++ /* WME test code */ ++ wd->ap.qosMode[0] = 1; ++#endif ++ ++ wd->ledStruct.ledMode[0] = 0x2221; ++ wd->ledStruct.ledMode[1] = 0x2221; ++ ++ zfTimerInit(dev); ++ ++ ZM_PERFORMANCE_INIT(dev); ++ ++ zfBssInfoCreate(dev); ++ zfScanMgrInit(dev); ++ zfPowerSavingMgrInit(dev); ++ ++#if 0 ++ /* Test code */ ++ { ++ u32_t key[4] = {0xffffffff, 0xff, 0, 0}; ++ u16_t addr[3] = {0x8000, 0x01ab, 0x0000}; ++ //zfSetKey(dev, 0, 0, ZM_WEP64, addr, key); ++ //zfSetKey(dev, 0, 0, ZM_AES, addr, key); ++ //zfSetKey(dev, 64, 0, 1, wd->macAddr, key); ++ } ++#endif ++ ++ // WME settings ++ wd->ws.staWmeEnabled = 1; // Enable WME by default ++ #define ZM_UAPSD_Q_SIZE 32 //2^N ++ wd->ap.uapsdQ = zfQueueCreate(dev, ZM_UAPSD_Q_SIZE); ++ zm_assert(wd->ap.uapsdQ != NULL); ++ wd->sta.uapsdQ = zfQueueCreate(dev, ZM_UAPSD_Q_SIZE); ++ zm_assert(wd->sta.uapsdQ != NULL); ++ ++ //zfHpInit(dev, wd->frequency); ++ ++ /* MAC address */ ++ //zfHpSetMacAddress(dev, wd->macAddr, 0); ++ zfHpGetMacAddress(dev); ++ ++ zfCoreSetFrequency(dev, wd->frequency); ++ ++#if ZM_PCI_LOOP_BACK == 1 ++ zfwWriteReg(dev, ZM_REG_PCI_CONTROL, 6); ++#endif /* #if ZM_PCI_LOOP_BACK == 1 */ ++ ++ //zfiWlanSetDot11DMode(dev , 1); // Enable 802.11d ++ //zfiWlanSetDot11HDFSMode(dev , 1); // Enable 802.11h DFS ++ wd->sta.DFSEnable = 1; ++ wd->sta.capability[1] |= ZM_BIT_0; ++ ++ //zfiWlanSetFrequency(dev, 5260000, TRUE); ++ //zfiWlanSetAniMode(dev , 1); // Enable ANI ++ ++ /* Trgger Rx DMA */ ++ zfHpStartRecv(dev); ++ ++ zm_debug_msg0("end"); ++ ++ return 0; ++} ++ ++/* WLAN hardware will be shutdown and all resource will be release */ ++u16_t zfiWlanClose(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg0_init(ZM_LV_0, "enter"); ++ ++ wd->state = ZM_WLAN_STATE_CLOSEDED; ++ ++ //zfiWlanDisable(dev, 1); ++ zfWlanReset(dev); ++ ++ zfHpStopRecv(dev); ++ ++ /* Disable MAC */ ++ /* Disable PHY */ ++ /* Disable RF */ ++ ++ zfHpRelease(dev); ++ ++ zfQueueDestroy(dev, wd->ap.uapsdQ); ++ zfQueueDestroy(dev, wd->sta.uapsdQ); ++ ++ zfBssInfoDestroy(dev); ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ /* add by honda */ ++ zfAggRxFreeBuf(dev, 1); //1 for release structure memory ++ /* end of add by honda */ ++#endif ++ ++ zm_msg0_init(ZM_LV_0, "exit"); ++ ++ return 0; ++} ++ ++void zfGetWrapperSetting(zdev_t* dev) ++{ ++ u8_t bPassive; ++ u16_t vapId = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++#if 0 ++ if ( (wd->ws.countryIsoName[0] != 0) ++ || (wd->ws.countryIsoName[1] != 0) ++ || (wd->ws.countryIsoName[2] != '\0') ) ++ { ++ zfHpGetRegulationTablefromRegionCode( ++ dev, ++ zfHpGetRegionCodeFromIsoName(dev, wd->ws.countryIsoName) ); ++ } ++#endif ++ zmw_enter_critical_section(dev); ++ ++ wd->wlanMode = wd->ws.wlanMode; ++ ++ /* set channel */ ++ if ( wd->ws.frequency ) ++ { ++ wd->frequency = wd->ws.frequency; ++ wd->ws.frequency = 0; ++ } ++ else ++ { ++ wd->frequency = zfChGetFirstChannel(dev, &bPassive); ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ if (wd->ws.adhocMode == ZM_ADHOCBAND_A) ++ { ++ wd->frequency = ZM_CH_A_36; ++ } ++ else ++ { ++ wd->frequency = ZM_CH_G_6; ++ } ++ } ++ } ++#ifdef ZM_AP_DEBUG ++ /* honda add for debug, 2437 channel 6, 2452 channel 9 */ ++ wd->frequency = 2437; ++ /* end of add by honda */ ++#endif ++ ++ /* set preamble type */ ++ switch (wd->ws.preambleType) ++ { ++ case ZM_PREAMBLE_TYPE_AUTO: ++ case ZM_PREAMBLE_TYPE_SHORT: ++ case ZM_PREAMBLE_TYPE_LONG: ++ wd->preambleType = wd->ws.preambleType; ++ break; ++ default: ++ wd->preambleType = ZM_PREAMBLE_TYPE_SHORT; ++ break; ++ } ++ wd->ws.preambleType = 0; ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ vapId = zfwGetVapId(dev); ++ ++ if (vapId == 0xffff) ++ { ++ wd->ap.authAlgo[0] = wd->ws.authMode; ++ wd->ap.encryMode[0] = wd->ws.encryMode; ++ } ++ else ++ { ++ wd->ap.authAlgo[vapId + 1] = wd->ws.authMode; ++ wd->ap.encryMode[vapId + 1] = wd->ws.encryMode; ++ } ++ wd->ws.authMode = 0; ++ wd->ws.encryMode = ZM_NO_WEP; ++ ++ /* Get beaconInterval from WrapperSetting */ ++ if ((wd->ws.beaconInterval >= 20) && (wd->ws.beaconInterval <= 1000)) ++ { ++ wd->beaconInterval = wd->ws.beaconInterval; ++ } ++ else ++ { ++ wd->beaconInterval = 100; //100ms ++ } ++ ++ if (wd->ws.dtim > 0) ++ { ++ wd->dtim = wd->ws.dtim; ++ } ++ else ++ { ++ wd->dtim = 1; ++ } ++ ++ wd->ap.qosMode = wd->ws.apWmeEnabled & 0x1; ++ wd->ap.uapsdEnabled = (wd->ws.apWmeEnabled & 0x2) >> 1; ++ } ++ else ++ { ++ wd->sta.authMode = wd->ws.authMode; ++ wd->sta.currentAuthMode = wd->ws.authMode; ++ wd->sta.wepStatus = wd->ws.wepStatus; ++ ++ if ( wd->ws.beaconInterval ) ++ { ++ wd->beaconInterval = wd->ws.beaconInterval; ++ } ++ else ++ { ++ wd->beaconInterval = 0x64; ++ } ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ /* 1. Set default channel 6 (2437MHz) */ ++// wd->frequency = 2437; ++ ++ /* 2. Otus support 802.11g Mode */ ++ if ((wd->ws.adhocMode == ZM_ADHOCBAND_G) || ++ (wd->ws.adhocMode == ZM_ADHOCBAND_BG) || ++ (wd->ws.adhocMode == ZM_ADHOCBAND_ABG) ) { ++ wd->wfc.bIbssGMode = 1; ++ } else { ++ wd->wfc.bIbssGMode = 0; ++ } ++ ++ /* 3. set short preamble */ ++ //wd->sta.preambleType = ZM_PREAMBLE_TYPE_SHORT ; ++ } ++ ++ /* set ATIM window */ ++ if ( wd->ws.atimWindow ) ++ { ++ wd->sta.atimWindow = wd->ws.atimWindow; ++ } ++ else ++ { ++ //wd->sta.atimWindow = 0x0a; ++ wd->sta.atimWindow = 0; ++ } ++ ++ //wd->sta.connectingHiddenAP = 1;//wd->ws.connectingHiddenAP; ++ wd->sta.dropUnencryptedPkts = wd->ws.dropUnencryptedPkts; ++ wd->sta.ibssJoinOnly = wd->ws.ibssJoinOnly; ++ ++ if ( wd->ws.bDesiredBssid ) ++ { ++ zfMemoryCopy(wd->sta.desiredBssid, wd->ws.desiredBssid, 6); ++ wd->sta.bDesiredBssid = TRUE; ++ wd->ws.bDesiredBssid = FALSE; ++ } ++ else ++ { ++ wd->sta.bDesiredBssid = FALSE; ++ } ++ ++ /* check ssid */ ++ if ( wd->ws.ssidLen != 0 ) ++ { ++ if ( (!zfMemoryIsEqual(wd->ws.ssid, wd->sta.ssid, ++ wd->sta.ssidLen))|| ++ (wd->ws.ssidLen != wd->sta.ssidLen)|| ++ (wd->sta.authMode == ZM_AUTH_MODE_WPA)|| ++ (wd->sta.authMode == ZM_AUTH_MODE_WPAPSK) || ++ (wd->ws.staWmeQosInfo!= 0) ) ++ { ++ /*if u-APSD test(set QosInfo), clear connectByReasso to do association (not reassociation)*/ ++ wd->sta.connectByReasso = FALSE; ++ wd->sta.failCntOfReasso = 0; ++ wd->sta.pmkidInfo.bssidCount = 0; ++ ++ wd->sta.ssidLen = wd->ws.ssidLen; ++ zfMemoryCopy(wd->sta.ssid, wd->ws.ssid, wd->sta.ssidLen); ++ ++ if ( wd->sta.ssidLen < 32 ) ++ { ++ wd->sta.ssid[wd->sta.ssidLen] = 0; ++ } ++ } ++ } ++ else ++ { /* ANY BSS */ ++ wd->sta.ssid[0] = 0; ++ wd->sta.ssidLen = 0; ++ } ++ ++ wd->sta.wmeEnabled = wd->ws.staWmeEnabled; ++ wd->sta.wmeQosInfo = wd->ws.staWmeQosInfo; ++ ++ } ++ ++ zmw_leave_critical_section(dev); ++} ++ ++u16_t zfWlanEnable(zdev_t* dev) ++{ ++ u8_t bssid[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->wlanMode == ZM_MODE_UNKNOWN ) ++ { ++ zm_debug_msg0("Unknown Mode...Skip..."); ++ return 0; ++ } ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ u16_t vapId; ++ ++ vapId = zfwGetVapId(dev); ++ ++ if (vapId == 0xffff) ++ { ++ /* AP mode */ ++ zfApInitStaTbl(dev); ++ ++ /* AP default parameters */ ++ wd->bRate = 0xf; ++ wd->gRate = 0xff; ++ wd->bRateBasic = 0xf; ++ wd->gRateBasic = 0x0; ++ //wd->beaconInterval = 100; ++ wd->ap.apBitmap = 1; ++ wd->ap.beaconCounter = 0; ++ //wd->ap.vapNumber = 1; //mark by ygwei for Vap ++ ++ wd->ap.hideSsid[0] = 0; ++ wd->ap.staAgingTimeSec = 10*60; ++ wd->ap.staProbingTimeSec = 60; ++ ++ for (i=0; iap.bcmcHead[i] = wd->ap.bcmcTail[i] = 0; ++ } ++ ++ //wd->ap.uniHead = wd->ap.uniTail = 0; ++ ++ /* load AP parameters */ ++ wd->bRateBasic = wd->ws.bRateBasic; ++ wd->gRateBasic = wd->ws.gRateBasic; ++ wd->bgMode = wd->ws.bgMode; ++ if ((wd->ws.ssidLen <= 32) && (wd->ws.ssidLen != 0)) ++ { ++ wd->ap.ssidLen[0] = wd->ws.ssidLen; ++ for(i=0; iws.ssidLen; i++) ++ { ++ wd->ap.ssid[0][i] = wd->ws.ssid[i]; ++ } ++ wd->ws.ssidLen = 0; // Reset Wrapper Variable ++ } ++ ++ if (wd->ap.encryMode[0] == 0) ++ { ++ wd->ap.capab[0] = 0x001; ++ } ++ else ++ { ++ wd->ap.capab[0] = 0x011; ++ } ++ /* set Short Slot Time bit if not 11b */ ++ if (wd->ap.wlanType[0] != ZM_WLAN_TYPE_PURE_B) ++ { ++ wd->ap.capab[0] |= 0x400; ++ } ++ ++ // wd->ap.vapNumber = 1; // mark by ygwei for Vap Test ++ } ++ else ++ { ++#if 0 ++ /* VAP Test Code */ ++ wd->ap.apBitmap = 0x3; ++ wd->ap.capab[1] = 0x401; ++ wd->ap.ssidLen[1] = 4; ++ wd->ap.ssid[1][0] = 'v'; ++ wd->ap.ssid[1][1] = 'a'; ++ wd->ap.ssid[1][2] = 'p'; ++ wd->ap.ssid[1][3] = '1'; ++ wd->ap.authAlgo[1] = wd->ws.authMode; ++ wd->ap.encryMode[1] = wd->ws.encryMode; ++ wd->ap.vapNumber = 2; ++#else ++ /* VAP Test Code */ ++ wd->ap.apBitmap = 0x1 | (0x01 << (vapId+1)); ++ ++ if ((wd->ws.ssidLen <= 32) && (wd->ws.ssidLen != 0)) ++ { ++ wd->ap.ssidLen[vapId+1] = wd->ws.ssidLen; ++ for(i=0; iws.ssidLen; i++) ++ { ++ wd->ap.ssid[vapId+1][i] = wd->ws.ssid[i]; ++ } ++ wd->ws.ssidLen = 0; // Reset Wrapper Variable ++ } ++ ++ if (wd->ap.encryMode[vapId+1] == 0) ++ { ++ wd->ap.capab[vapId+1] = 0x401; ++ } ++ else ++ { ++ wd->ap.capab[vapId+1] = 0x411; ++ } ++ ++ wd->ap.authAlgo[vapId+1] = wd->ws.authMode; ++ wd->ap.encryMode[vapId+1] = wd->ws.encryMode; ++ ++ /* Need to be modified when VAP is used */ ++ //wd->ap.vapNumber = 2; ++#endif ++ } ++ ++ wd->ap.vapNumber++; ++ ++ zfCoreSetFrequency(dev, wd->frequency); ++ ++ zfInitMacApMode(dev); ++ ++ /* Disable protection mode */ ++ zfApSetProtectionMode(dev, 0); ++ ++ zfApSendBeacon(dev); ++ } /*if (wd->wlanMode == ZM_MODE_AP) */ ++ else ++ { ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.oppositeCount = 0; /* reset opposite count */ ++ //wd->sta.bAutoReconnect = wd->sta.bAutoReconnectEnabled; ++ //wd->sta.scanWithSSID = 0; ++ zfStaInitOppositeInfo(dev); ++ zmw_leave_critical_section(dev); ++ ++ zfStaResetStatus(dev, 0); ++ ++ if ( (wd->sta.cmDisallowSsidLength != 0)&& ++ (wd->sta.ssidLen == wd->sta.cmDisallowSsidLength)&& ++ (zfMemoryIsEqual(wd->sta.ssid, wd->sta.cmDisallowSsid, ++ wd->sta.ssidLen)) && ++ (wd->sta.wepStatus == ZM_ENCRYPTION_TKIP)) ++ { /* countermeasures */ ++ zm_debug_msg0("countermeasures disallow association"); ++ ++ } ++ else ++ { ++ switch( wd->wlanMode ) ++ { ++ case ZM_MODE_IBSS: ++ /* some registers may be set here */ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) ++ { ++ zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_IBSS_WPA2PSK); ++ } ++ else ++ { ++ zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_IBSS_GENERAL); ++ } ++ ++ zm_msg0_mm(ZM_LV_0, "ZM_MODE_IBSS"); ++ zfIbssConnectNetwork(dev); ++ break; ++ ++ case ZM_MODE_INFRASTRUCTURE: ++ /* some registers may be set here */ ++ zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_STA); ++ ++ zfInfraConnectNetwork(dev); ++ break; ++ ++ case ZM_MODE_PSEUDO: ++ /* some registers may be set here */ ++ zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_STA); ++ ++ zfUpdateBssid(dev, bssid); ++ zfCoreSetFrequency(dev, wd->frequency); ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ } ++ ++ ++ //if ( (wd->wlanMode != ZM_MODE_INFRASTRUCTURE)&& ++ // (wd->wlanMode != ZM_MODE_AP) ) ++ if ( wd->wlanMode == ZM_MODE_PSEUDO ) ++ { ++ /* Reset Wlan status */ ++ zfWlanReset(dev); ++ ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); ++ } ++ zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); ++ } ++ ++ ++ if(wd->wlanMode == ZM_MODE_AP) ++ { ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); ++ } ++ //zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); ++ } ++ ++ // Assign default Tx Rate ++ if ( wd->sta.EnableHT ) ++ { ++ u32_t oneTxStreamCap; ++ oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM); ++ if(oneTxStreamCap) ++ wd->CurrentTxRateKbps = 135000; ++ else ++ wd->CurrentTxRateKbps = 270000; ++ wd->CurrentRxRateKbps = 270000; ++ } ++ else ++ { ++ wd->CurrentTxRateKbps = 54000; ++ wd->CurrentRxRateKbps = 54000; ++ } ++ ++ wd->state = ZM_WLAN_STATE_ENABLED; ++ ++ return 0; ++} ++ ++/* Enable/disable Wlan operation */ ++u16_t zfiWlanEnable(zdev_t* dev) ++{ ++ u16_t ret; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg0_mm(ZM_LV_1, "Enable Wlan"); ++ ++ zfGetWrapperSetting(dev); ++ ++ zfZeroMemory((u8_t*) &wd->trafTally, sizeof(struct zsTrafTally)); ++ ++ // Reset cmMicFailureCount to 0 for new association request ++ if ( wd->sta.cmMicFailureCount == 1 ) ++ { ++ zfTimerCancel(dev, ZM_EVENT_CM_TIMER); ++ wd->sta.cmMicFailureCount = 0; ++ } ++ ++ zfFlushVtxq(dev); ++ if ((wd->queueFlushed & 0x10) != 0) ++ { ++ zfHpUsbReset(dev); ++ } ++ ret = zfWlanEnable(dev); ++ ++ return ret; ++} ++/* Add a flag named ResetKeyCache to show if KeyCache should be cleared. ++ for hostapd in AP mode, if driver receives iwconfig ioctl ++ after setting group key, it shouldn't clear KeyCache. */ ++u16_t zfiWlanDisable(zdev_t* dev, u8_t ResetKeyCache) ++{ ++ u16_t i; ++ u8_t isConnected; ++ ++ zmw_get_wlan_dev(dev); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ zmw_declare_for_critical_section(); ++#endif ++ wd->state = ZM_WLAN_STATE_DISABLED; ++ ++ zm_msg0_mm(ZM_LV_1, "Disable Wlan"); ++ ++ if ( wd->wlanMode != ZM_MODE_AP ) ++ { ++ isConnected = zfStaIsConnected(dev); ++ ++ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&& ++ (wd->sta.currentAuthMode != ZM_AUTH_MODE_WPA2) ) ++ { ++ /* send deauthentication frame */ ++ if (isConnected) ++ { ++ //zfiWlanDeauth(dev, NULL, 0); ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); ++ //zmw_debug_msg0("send a Deauth frame!"); ++ } ++ } ++ ++ // Remove all the connected peer stations ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ wd->sta.ibssBssIsCreator = 0; ++ zfTimerCancel(dev, ZM_EVENT_IBSS_MONITOR); ++ zfStaIbssMonitoring(dev, 1); ++ } ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssWpa2Psk = 0; ++ zmw_leave_critical_section(dev); ++#endif ++ ++ wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; ++ ++ /* reset connect timeout counter */ ++ wd->sta.connectTimeoutCount = 0; ++ ++ /* reset connectState to None */ ++ wd->sta.connectState = ZM_STA_CONN_STATE_NONE; ++ ++ /* reset leap enable variable */ ++ wd->sta.leapEnabled = 0; ++ ++ /* Disable the RIFS Status / RIFS-like frame count / RIFS count */ ++ if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) ++ zfHpDisableRifs(dev); ++ wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; ++ wd->sta.rifsLikeFrameCnt = 0; ++ wd->sta.rifsCount = 0; ++ ++ wd->sta.osRxFilter = 0; ++ wd->sta.bSafeMode = 0; ++ ++ zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); ++ if (ResetKeyCache) ++ zfHpResetKeyCache(dev); ++ ++ if (isConnected) ++ { ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECTION_DISABLED, wd->sta.bssid); ++ } ++ } ++ else ++ { ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_DISABLED, wd->sta.bssid); ++ } ++ } ++ } ++ else //if (wd->wlanMode == ZM_MODE_AP) ++ { ++ for (i=0; iap.staTable[i].valid == 1) ++ { ++ /* Reason : Sending station is leaving */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, ++ wd->ap.staTable[i].addr, 3, 0, 0); ++ } ++ } ++ ++ if (ResetKeyCache) ++ zfHpResetKeyCache(dev); ++ ++ wd->ap.vapNumber--; ++ } ++ ++ /* stop beacon */ ++ zfHpDisableBeacon(dev); ++ ++ /* Flush VTxQ and MmQ */ ++ zfFlushVtxq(dev); ++ /* Flush AP PS queues */ ++ zfApFlushBufferedPsFrame(dev); ++ /* Free buffer in defragment list*/ ++ zfAgingDefragList(dev, 1); ++ ++ #ifdef ZM_ENABLE_AGGREGATION ++ /* add by honda */ ++ zfAggRxFreeBuf(dev, 0); //1 for release structure memory ++ /* end of add by honda */ ++ #endif ++ ++ // Clear the information for the peer stations of IBSS or AP of Station mode ++ zfZeroMemory((u8_t*)wd->sta.oppositeInfo, sizeof(struct zsOppositeInfo) * ZM_MAX_OPPOSITE_COUNT); ++ ++ /* Turn off Software WEP/TKIP */ ++ if (wd->sta.SWEncryptEnable != 0) ++ { ++ zm_debug_msg0("Disable software encryption"); ++ zfStaDisableSWEncryption(dev); ++ } ++ ++ /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ ++ //zfHpSetTTSIFSTime(dev, 0x8); ++ ++ return 0; ++} ++ ++u16_t zfiWlanSuspend(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ // Change the HAL state to init so that any packet can't be transmitted between ++ // resume & HAL reinit. This would cause the chip hang issue in OTUS. ++ zmw_enter_critical_section(dev); ++ wd->halState = ZM_HAL_STATE_INIT; ++ zmw_leave_critical_section(dev); ++ ++ return 0; ++} ++ ++u16_t zfiWlanResume(zdev_t* dev, u8_t doReconn) ++{ ++ u16_t ret; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ /* Redownload firmware, Reinit MAC,PHY,RF */ ++ zfHpReinit(dev, wd->frequency); ++ ++ //Set channel according to AP's configuration ++ zfCoreSetFrequencyExV2(dev, wd->frequency, wd->BandWidth40, ++ wd->ExtOffset, NULL, 1); ++ ++ zfHpSetMacAddress(dev, wd->macAddr, 0); ++ ++ /* Start Rx */ ++ zfHpStartRecv(dev); ++ ++ zfFlushVtxq(dev); ++ ++ if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE && ++ wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ return 1; ++ } ++ ++ zm_msg0_mm(ZM_LV_1, "Resume Wlan"); ++ if ( (zfStaIsConnected(dev)) || (zfStaIsConnecting(dev)) ) ++ { ++ if (doReconn == 1) ++ { ++ zm_msg0_mm(ZM_LV_1, "Re-connect..."); ++ zmw_enter_critical_section(dev); ++ wd->sta.connectByReasso = FALSE; ++ zmw_leave_critical_section(dev); ++ ++ zfWlanEnable(dev); ++ } ++ else if (doReconn == 0) ++ { ++ zfHpSetRollCallTable(dev); ++ } ++ } ++ ++ ret = 0; ++ ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiWlanFlushAllQueuedBuffers */ ++/* Flush Virtual TxQ, MmQ, PS frames and defragment list */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++void zfiWlanFlushAllQueuedBuffers(zdev_t* dev) ++{ ++ /* Flush VTxQ and MmQ */ ++ zfFlushVtxq(dev); ++ /* Flush AP PS queues */ ++ zfApFlushBufferedPsFrame(dev); ++ /* Free buffer in defragment list*/ ++ zfAgingDefragList(dev, 1); ++} ++ ++/* Do WLAN site survey */ ++u16_t zfiWlanScan(zdev_t* dev) ++{ ++ u16_t ret = 1; ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg0(""); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ wd->heartBeatNotification |= ZM_BSSID_LIST_SCAN; ++ wd->sta.scanFrequency = 0; ++ //wd->sta.pUpdateBssList->bssCount = 0; ++ ret = 0; ++ } ++ else ++ { ++ #if 0 ++ if ( !zfStaBlockWlanScan(dev) ) ++ { ++ zm_debug_msg0("scan request"); ++ //zfTimerSchedule(dev, ZM_EVENT_SCAN, ZM_TICK_ZERO); ++ ret = 0; ++ goto start_scan; ++ } ++ #else ++ goto start_scan; ++ #endif ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return ret; ++ ++start_scan: ++ zmw_leave_critical_section(dev); ++ ++ if(wd->ledStruct.LEDCtrlFlagFromReg & ZM_LED_CTRL_FLAG_ALPHA) // flag for Alpha ++ wd->ledStruct.LEDCtrlFlag |= ZM_LED_CTRL_FLAG_ALPHA; ++ ++ ret = zfScanMgrScanStart(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); ++ ++ zm_debug_msg1("ret = ", ret); ++ ++ return ret; ++} ++ ++ ++/* rate */ ++/* 0 : AUTO */ ++/* 1 : CCK 1M */ ++/* 2 : CCK 2M */ ++/* 3 : CCK 5.5M */ ++/* 4 : CCK 11M */ ++/* 5 : OFDM 6M */ ++/* 6 : OFDM 9M */ ++/* 7 : OFDM 12M */ ++/* 8 : OFDM 18M */ ++/* 9 : OFDM 24M */ ++/* 10 : OFDM 36M */ ++/* 11 : OFDM 48M */ ++/* 12 : OFDM 54M */ ++/* 13 : MCS 0 */ ++/* 28 : MCS 15 */ ++u16_t zcRateToMCS[] = ++ {0xff, 0, 1, 2, 3, 0xb, 0xf, 0xa, 0xe, 0x9, 0xd, 0x8, 0xc}; ++u16_t zcRateToMT[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}; ++ ++u16_t zfiWlanSetTxRate(zdev_t* dev, u16_t rate) ++{ // jhlee HT 0 ++ zmw_get_wlan_dev(dev); ++ ++ if (rate <=12) ++ { ++ wd->txMCS = zcRateToMCS[rate]; ++ wd->txMT = zcRateToMT[rate]; ++ return ZM_SUCCESS; ++ } ++ else if ((rate<=28)||(rate==13+32)) ++ { ++ wd->txMCS = rate - 12 - 1; ++ wd->txMT = 2; ++ return ZM_SUCCESS; ++ } ++ ++ return ZM_ERR_INVALID_TX_RATE; ++} ++ ++const u32_t zcRateIdToKbps40M[] = ++ { ++ 1000, 2000, 5500, 11000, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ ++ 6000, 9000, 12000, 18000, /* 6M 9M 12M 18M , 4 5 6 7*/ ++ 24000, 36000, 48000, 54000, /* 24M 36M 48M 54M , 8 9 10 11*/ ++ 13500, 27000, 40500, 54000, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ ++ 81000, 108000, 121500, 135000, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ ++ 27000, 54000, 81000, 108000, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ ++ 162000, 216000, 243000, 270000, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ ++ 270000, 300000, 150000 /* MCS14SG, MCS15SG, MCS7SG , 28 29 30*/ ++ }; ++ ++const u32_t zcRateIdToKbps20M[] = ++ { ++ 1000, 2000, 5500, 11000, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ ++ 6000, 9000, 12000, 18000, /* 6M 9M 12M 18M , 4 5 6 7*/ ++ 24000, 36000, 48000, 54000, /* 24M 36M 48M 54M , 8 9 10 11*/ ++ 6500, 13000, 19500, 26000, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ ++ 39000, 52000, 58500, 65000, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ ++ 13000, 26000, 39000, 52000, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ ++ 78000, 104000, 117000, 130000, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ ++ 130000, 144400, 72200 /* MCS14SG, MCS15SG, MSG7SG , 28 29 30*/ ++ }; ++ ++u32_t zfiWlanQueryTxRate(zdev_t* dev) ++{ ++ u8_t rateId = 0xff; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ /* If Tx rate had not been trained, return maximum Tx rate instead */ ++ if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && (zfStaIsConnected(dev))) ++ { ++ zmw_enter_critical_section(dev); ++ //Not in fixed rate mode ++ if (wd->txMCS == 0xff) ++ { ++ if ((wd->sta.oppositeInfo[0].rcCell.flag & ZM_RC_TRAINED_BIT) == 0) ++ { ++ rateId = wd->sta.oppositeInfo[0].rcCell.operationRateSet[wd->sta.oppositeInfo[0].rcCell.operationRateCount-1]; ++ } ++ else ++ { ++ rateId = wd->sta.oppositeInfo[0].rcCell.operationRateSet[wd->sta.oppositeInfo[0].rcCell.currentRateIndex]; ++ } ++ } ++ zmw_leave_critical_section(dev); ++ } ++ if (rateId != 0xff) ++ { ++ if (wd->sta.htCtrlBandwidth) ++ { ++ return zcRateIdToKbps40M[rateId]; ++ } ++ else ++ { ++ return zcRateIdToKbps20M[rateId]; ++ } ++ } ++ else ++ { ++ return wd->CurrentTxRateKbps; ++ } ++} ++ ++void zfWlanUpdateRxRate(zdev_t* dev, struct zsAdditionInfo* addInfo) ++{ ++ u32_t rxRateKbps; ++ zmw_get_wlan_dev(dev); ++ //zm_msg1_mm(ZM_LV_0, "addInfo->Tail.Data.RxMacStatus =", addInfo->Tail.Data.RxMacStatus & 0x03); ++ ++ /* b5~b4: MPDU indication. */ ++ /* 00: Single MPDU. */ ++ /* 10: First MPDU of A-MPDU. */ ++ /* 11: Middle MPDU of A-MPDU. */ ++ /* 01: Last MPDU of A-MPDU. */ ++ /* Only First MPDU and Single MPDU have PLCP header */ ++ /* First MPDU : (mpduInd & 0x30) == 0x00 */ ++ /* Single MPDU : (mpduInd & 0x30) == 0x20 */ ++ if ((addInfo->Tail.Data.RxMacStatus & 0x10) == 0) ++ { ++ /* Modulation type */ ++ wd->modulationType = addInfo->Tail.Data.RxMacStatus & 0x03; ++ switch(wd->modulationType) ++ { ++ case 0x0: wd->rateField = addInfo->PlcpHeader[0] & 0xff; //CCK mode ++ wd->rxInfo = 0; ++ break; ++ case 0x1: wd->rateField = addInfo->PlcpHeader[0] & 0x0f; //Legacy-OFDM mode ++ wd->rxInfo = 0; ++ break; ++ case 0x2: wd->rateField = addInfo->PlcpHeader[3]; //HT-OFDM mode ++ wd->rxInfo = addInfo->PlcpHeader[6]; ++ break; ++ default: break; ++ } ++ ++ rxRateKbps = zfUpdateRxRate(dev); ++ if (wd->CurrentRxRateUpdated == 1) ++ { ++ if (rxRateKbps > wd->CurrentRxRateKbps) ++ { ++ wd->CurrentRxRateKbps = rxRateKbps; ++ } ++ } ++ else ++ { ++ wd->CurrentRxRateKbps = rxRateKbps; ++ wd->CurrentRxRateUpdated = 1; ++ } ++ } ++} ++#if 0 ++u16_t zcIndextoRateBG[16] = {1000, 2000, 5500, 11000, 0, 0, 0, 0, 48000, ++ 24000, 12000, 6000, 54000, 36000, 18000, 9000}; ++u32_t zcIndextoRateN20L[16] = {6500, 13000, 19500, 26000, 39000, 52000, 58500, ++ 65000, 13000, 26000, 39000, 52000, 78000, 104000, ++ 117000, 130000}; ++u32_t zcIndextoRateN20S[16] = {7200, 14400, 21700, 28900, 43300, 57800, 65000, ++ 72200, 14400, 28900, 43300, 57800, 86700, 115600, ++ 130000, 144400}; ++u32_t zcIndextoRateN40L[16] = {13500, 27000, 40500, 54000, 81000, 108000, 121500, ++ 135000, 27000, 54000, 81000, 108000, 162000, 216000, ++ 243000, 270000}; ++u32_t zcIndextoRateN40S[16] = {15000, 30000, 45000, 60000, 90000, 120000, 135000, ++ 150000, 30000, 60000, 90000, 120000, 180000, 240000, ++ 270000, 300000}; ++#endif ++ ++extern u16_t zcIndextoRateBG[16]; ++extern u32_t zcIndextoRateN20L[16]; ++extern u32_t zcIndextoRateN20S[16]; ++extern u32_t zcIndextoRateN40L[16]; ++extern u32_t zcIndextoRateN40S[16]; ++ ++u32_t zfiWlanQueryRxRate(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->CurrentRxRateUpdated = 0; ++ return wd->CurrentRxRateKbps; ++} ++ ++u32_t zfUpdateRxRate(zdev_t* dev) ++{ ++ u8_t mcs, bandwidth; ++ u32_t rxRateKbps = 130000; ++ zmw_get_wlan_dev(dev); ++ ++ switch (wd->modulationType) ++ { ++ case 0x0: //CCK mode ++ switch (wd->rateField) ++ { ++ case 0x0a: rxRateKbps = 1000; ++ break; ++ case 0x14: rxRateKbps = 2000; ++ ++ case 0x37: rxRateKbps = 5500; ++ break; ++ case 0x6e: rxRateKbps = 11000; ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x1: //Legacy-OFDM mode ++ if (wd->rateField <= 15) ++ { ++ rxRateKbps = zcIndextoRateBG[wd->rateField]; ++ } ++ break; ++ case 0x2: //HT-OFDM mode ++ mcs = wd->rateField & 0x7F; ++ bandwidth = wd->rateField & 0x80; ++ if (mcs <= 15) ++ { ++ if (bandwidth != 0) ++ { ++ if((wd->rxInfo & 0x80) != 0) ++ { ++ /* Short GI 40 MHz MIMO Rate */ ++ rxRateKbps = zcIndextoRateN40S[mcs]; ++ } ++ else ++ { ++ /* Long GI 40 MHz MIMO Rate */ ++ rxRateKbps = zcIndextoRateN40L[mcs]; ++ } ++ } ++ else ++ { ++ if((wd->rxInfo & 0x80) != 0) ++ { ++ /* Short GI 20 MHz MIMO Rate */ ++ rxRateKbps = zcIndextoRateN20S[mcs]; ++ } ++ else ++ { ++ /* Long GI 20 MHz MIMO Rate */ ++ rxRateKbps = zcIndextoRateN20L[mcs]; ++ } ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ //zm_msg1_mm(ZM_LV_0, "wd->CurrentRxRateKbps=", wd->CurrentRxRateKbps); ++ ++ // ToDo: use bandwith field to define 40MB ++ return rxRateKbps; ++} ++ ++/* Get WLAN stastics */ ++u16_t zfiWlanGetStatistics(zdev_t* dev) ++{ ++ /* Return link statistics */ ++ return 0; ++} ++ ++u16_t zfiWlanReset(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->state = ZM_WLAN_STATE_DISABLED; ++ ++ return zfWlanReset(dev); ++} ++ ++/* Reset WLAN */ ++u16_t zfWlanReset(zdev_t* dev) ++{ ++ u8_t isConnected; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zm_debug_msg0("zfWlanReset"); ++ ++ isConnected = zfStaIsConnected(dev); ++ ++ //if ( wd->wlanMode != ZM_MODE_AP ) ++ { ++ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&& ++ (wd->sta.currentAuthMode != ZM_AUTH_MODE_WPA2) ) ++ { ++ /* send deauthentication frame */ ++ if (isConnected) ++ { ++ //zfiWlanDeauth(dev, NULL, 0); ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); ++ //zmw_debug_msg0("send a Deauth frame!"); ++ } ++ } ++ } ++ ++ zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); ++ zfHpResetKeyCache(dev); ++ ++ if (isConnected) ++ { ++ //zfiWlanDisable(dev); ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECTION_RESET, wd->sta.bssid); ++ } ++ } ++ else ++ { ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_RESET, wd->sta.bssid); ++ } ++ } ++ ++ /* stop beacon */ ++ zfHpDisableBeacon(dev); ++ ++ /* Free buffer in defragment list*/ ++ zfAgingDefragList(dev, 1); ++ ++ /* Flush VTxQ and MmQ */ ++ zfFlushVtxq(dev); ++ ++ #ifdef ZM_ENABLE_AGGREGATION ++ /* add by honda */ ++ zfAggRxFreeBuf(dev, 0); //1 for release structure memory ++ /* end of add by honda */ ++ #endif ++ ++ zfStaRefreshBlockList(dev, 1); ++ ++ zmw_enter_critical_section(dev); ++ ++ zfTimerCancel(dev, ZM_EVENT_IBSS_MONITOR); ++ zfTimerCancel(dev, ZM_EVENT_CM_BLOCK_TIMER); ++ zfTimerCancel(dev, ZM_EVENT_CM_DISCONNECT); ++ ++ wd->sta.connectState = ZM_STA_CONN_STATE_NONE; ++ wd->sta.connectByReasso = FALSE; ++ wd->sta.cmDisallowSsidLength = 0; ++ wd->sta.bAutoReconnect = 0; ++ wd->sta.InternalScanReq = 0; ++ wd->sta.encryMode = ZM_NO_WEP; ++ wd->sta.wepStatus = ZM_ENCRYPTION_WEP_DISABLED; ++ wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; ++ wd->sta.cmMicFailureCount = 0; ++ wd->sta.ibssBssIsCreator = 0; ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ wd->sta.ibssWpa2Psk = 0; ++#endif ++ /* reset connect timeout counter */ ++ wd->sta.connectTimeoutCount = 0; ++ ++ /* reset leap enable variable */ ++ wd->sta.leapEnabled = 0; ++ ++ /* Reset the RIFS Status / RIFS-like frame count / RIFS count */ ++ if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) ++ zfHpDisableRifs(dev); ++ wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; ++ wd->sta.rifsLikeFrameCnt = 0; ++ wd->sta.rifsCount = 0; ++ ++ wd->sta.osRxFilter = 0; ++ wd->sta.bSafeMode = 0; ++ ++ // Clear the information for the peer stations of IBSS or AP of Station mode ++ zfZeroMemory((u8_t*)wd->sta.oppositeInfo, sizeof(struct zsOppositeInfo) * ZM_MAX_OPPOSITE_COUNT); ++ ++ zmw_leave_critical_section(dev); ++ ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_EXTERNAL); ++ ++ /* Turn off Software WEP/TKIP */ ++ if (wd->sta.SWEncryptEnable != 0) ++ { ++ zm_debug_msg0("Disable software encryption"); ++ zfStaDisableSWEncryption(dev); ++ } ++ ++ /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ ++ //zfHpSetTTSIFSTime(dev, 0x8); ++ ++ /* Keep Pseudo mode */ ++ if ( wd->wlanMode != ZM_MODE_PSEUDO ) ++ { ++ wd->wlanMode = ZM_MODE_INFRASTRUCTURE; ++ } ++ return 0; ++} ++ ++/* Deauthenticate a STA */ ++u16_t zfiWlanDeauth(zdev_t* dev, u16_t* macAddr, u16_t reason) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ //u16_t id; ++ ++ /* ++ * we will reset all key in zfHpResetKeyCache() when call ++ * zfiWlanDisable(), if we want to reset PairwiseKey for each sta, ++ * need to use a nullAddr to let keyindex not match. ++ * otherwise hardware will still find PairwiseKey when AP change ++ * encryption mode from WPA to WEP ++ */ ++ ++ /* ++ if ((id = zfApFindSta(dev, macAddr)) != 0xffff) ++ { ++ u32_t key[8]; ++ u16_t nullAddr[3] = { 0x0, 0x0, 0x0 }; ++ ++ if (wd->ap.staTable[i].encryMode != ZM_NO_WEP) ++ { ++ zfHpSetApPairwiseKey(dev, nullAddr, ++ ZM_NO_WEP, &key[0], &key[4], i+1); ++ } ++ //zfHpSetApPairwiseKey(dev, (u16_t *)macAddr, ++ // ZM_NO_WEP, &key[0], &key[4], id+1); ++ wd->ap.staTable[id].encryMode = ZM_NO_WEP; ++ wd->ap.staTable[id].keyIdx = 0xff; ++ } ++ */ ++ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, macAddr, reason, 0, 0); ++ } ++ else ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); ++ } ++ ++ /* Issue DEAUTH command to FW */ ++ return 0; ++} ++ ++ ++/* XP packet filter feature : */ ++/* 1=>enable: All multicast address packets, not just the ones enumerated in the multicast address list. */ ++/* 0=>disable */ ++void zfiWlanSetAllMulticast(zdev_t* dev, u32_t setting) ++{ ++ zmw_get_wlan_dev(dev); ++ zm_msg1_mm(ZM_LV_0, "sta.bAllMulticast = ", setting); ++ wd->sta.bAllMulticast = (u8_t)setting; ++} ++ ++ ++/* HT configure API */ ++void zfiWlanSetHTCtrl(zdev_t* dev, u32_t *setting, u32_t forceTxTPC) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->preambleType = (u8_t)setting[0]; ++ wd->sta.preambleTypeHT = (u8_t)setting[1]; ++ wd->sta.htCtrlBandwidth = (u8_t)setting[2]; ++ wd->sta.htCtrlSTBC = (u8_t)setting[3]; ++ wd->sta.htCtrlSG = (u8_t)setting[4]; ++ wd->sta.defaultTA = (u8_t)setting[5]; ++ wd->enableAggregation = (u8_t)setting[6]; ++ wd->enableWDS = (u8_t)setting[7]; ++ ++ wd->forceTxTPC = forceTxTPC; ++} ++ ++/* FB50 in OS XP, RD private test code */ ++void zfiWlanQueryHTCtrl(zdev_t* dev, u32_t *setting, u32_t *forceTxTPC) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ setting[0] = wd->preambleType; ++ setting[1] = wd->sta.preambleTypeHT; ++ setting[2] = wd->sta.htCtrlBandwidth; ++ setting[3] = wd->sta.htCtrlSTBC; ++ setting[4] = wd->sta.htCtrlSG; ++ setting[5] = wd->sta.defaultTA; ++ setting[6] = wd->enableAggregation; ++ setting[7] = wd->enableWDS; ++ ++ *forceTxTPC = wd->forceTxTPC; ++} ++ ++void zfiWlanDbg(zdev_t* dev, u8_t setting) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->enableHALDbgInfo = setting; ++} ++ ++/* FB50 in OS XP, RD private test code */ ++void zfiWlanSetRxPacketDump(zdev_t* dev, u32_t setting) ++{ ++ zmw_get_wlan_dev(dev); ++ if (setting) ++ { ++ wd->rxPacketDump = 1; /* enable */ ++ } ++ else ++ { ++ wd->rxPacketDump = 0; /* disable */ ++ } ++} ++ ++ ++/* FB50 in OS XP, RD private test code */ ++/* Tally */ ++void zfiWlanResetTally(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ wd->commTally.txUnicastFrm = 0; //txUnicastFrames ++ wd->commTally.txMulticastFrm = 0; //txMulticastFrames ++ wd->commTally.txUnicastOctets = 0; //txUniOctets byte size ++ wd->commTally.txMulticastOctets = 0; //txMultiOctets byte size ++ wd->commTally.txFrmUpperNDIS = 0; ++ wd->commTally.txFrmDrvMgt = 0; ++ wd->commTally.RetryFailCnt = 0; ++ wd->commTally.Hw_TotalTxFrm = 0; //Hardware total Tx Frame ++ wd->commTally.Hw_RetryCnt = 0; //txMultipleRetriesFrames ++ wd->commTally.Hw_UnderrunCnt = 0;// ++ wd->commTally.DriverRxFrmCnt = 0;// ++ wd->commTally.rxUnicastFrm = 0; //rxUnicastFrames ++ wd->commTally.rxMulticastFrm = 0; //rxMulticastFrames ++ wd->commTally.NotifyNDISRxFrmCnt = 0;// ++ wd->commTally.rxUnicastOctets = 0; //rxUniOctets byte size ++ wd->commTally.rxMulticastOctets = 0; //rxMultiOctets byte size ++ wd->commTally.DriverDiscardedFrm = 0;// Discard by ValidateFrame ++ wd->commTally.LessThanDataMinLen = 0;// ++ wd->commTally.GreaterThanMaxLen = 0;// ++ wd->commTally.DriverDiscardedFrmCauseByMulticastList = 0; ++ wd->commTally.DriverDiscardedFrmCauseByFrmCtrl = 0; ++ wd->commTally.rxNeedFrgFrm = 0; // need more frg frm ++ wd->commTally.DriverRxMgtFrmCnt = 0; ++ wd->commTally.rxBroadcastFrm = 0; //Receive broadcast frame count ++ wd->commTally.rxBroadcastOctets = 0; //Receive broadcast frame byte size ++ wd->commTally.Hw_TotalRxFrm = 0;// ++ wd->commTally.Hw_CRC16Cnt = 0; //rxPLCPCRCErrCnt ++ wd->commTally.Hw_CRC32Cnt = 0; //rxCRC32ErrCnt ++ wd->commTally.Hw_DecrypErr_UNI = 0;// ++ wd->commTally.Hw_DecrypErr_Mul = 0;// ++ wd->commTally.Hw_RxFIFOOverrun = 0;// ++ wd->commTally.Hw_RxTimeOut = 0; ++ wd->commTally.LossAP = 0;// ++ ++ wd->commTally.Tx_MPDU = 0; ++ wd->commTally.BA_Fail = 0; ++ wd->commTally.Hw_Tx_AMPDU = 0; ++ wd->commTally.Hw_Tx_MPDU = 0; ++ ++ wd->commTally.txQosDropCount[0] = 0; ++ wd->commTally.txQosDropCount[1] = 0; ++ wd->commTally.txQosDropCount[2] = 0; ++ wd->commTally.txQosDropCount[3] = 0; ++ wd->commTally.txQosDropCount[4] = 0; ++ ++ wd->commTally.Hw_RxMPDU = 0; ++ wd->commTally.Hw_RxDropMPDU = 0; ++ wd->commTally.Hw_RxDelMPDU = 0; ++ ++ wd->commTally.Hw_RxPhyMiscError = 0; ++ wd->commTally.Hw_RxPhyXRError = 0; ++ wd->commTally.Hw_RxPhyOFDMError = 0; ++ wd->commTally.Hw_RxPhyCCKError = 0; ++ wd->commTally.Hw_RxPhyHTError = 0; ++ wd->commTally.Hw_RxPhyTotalCount = 0; ++ ++#if (defined(GCCK) && defined(OFDM)) ++ wd->commTally.rx11bDataFrame = 0; ++ wd->commTally.rxOFDMDataFrame = 0; ++#endif ++ ++ zmw_leave_critical_section(dev); ++} ++ ++/* FB50 in OS XP, RD private test code */ ++void zfiWlanQueryTally(zdev_t* dev, struct zsCommTally *tally) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ zfMemoryCopy((u8_t*)tally, (u8_t*)&wd->commTally, sizeof(struct zsCommTally)); ++ zmw_leave_critical_section(dev); ++} ++void zfiWlanQueryTrafTally(zdev_t* dev, struct zsTrafTally *tally) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ zfMemoryCopy((u8_t*)tally, (u8_t*)&wd->trafTally, sizeof(struct zsTrafTally)); ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanQueryMonHalRxInfo(zdev_t* dev, struct zsMonHalRxInfo *monHalRxInfo) ++{ ++ zfHpQueryMonHalRxInfo(dev, (u8_t *)monHalRxInfo); ++} ++ ++/* parse the modeMDKEnable to DrvCore */ ++void zfiDKEnable(zdev_t* dev, u32_t enable) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->modeMDKEnable = enable; ++ zm_debug_msg1("modeMDKEnable = ", wd->modeMDKEnable); ++} ++ ++/* airoPeek */ ++u32_t zfiWlanQueryPacketTypePromiscuous(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->swSniffer; ++} ++ ++/* airoPeek */ ++void zfiWlanSetPacketTypePromiscuous(zdev_t* dev, u32_t setValue) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->swSniffer = setValue; ++ zm_msg1_mm(ZM_LV_0, "wd->swSniffer ", wd->swSniffer); ++ if (setValue) ++ { ++ /* write register for sniffer mode */ ++ zfHpSetSnifferMode(dev, 1); ++ zm_msg0_mm(ZM_LV_1, "enalbe sniffer mode"); ++ } ++ else ++ { ++ zfHpSetSnifferMode(dev, 0); ++ zm_msg0_mm(ZM_LV_0, "disalbe sniffer mode"); ++ } ++} ++ ++void zfiWlanSetXLinkMode(zdev_t* dev, u32_t setValue) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->XLinkMode = setValue; ++ if (setValue) ++ { ++ /* write register for sniffer mode */ ++ zfHpSetSnifferMode(dev, 1); ++ } ++ else ++ { ++ zfHpSetSnifferMode(dev, 0); ++ } ++} ++ ++extern void zfStaChannelManagement(zdev_t* dev, u8_t scan); ++void zfiSetChannelManagement(zdev_t* dev, u32_t setting) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch (setting) ++ { ++ case 1: ++ wd->sta.EnableHT = 1; ++ wd->BandWidth40 = 1; ++ wd->ExtOffset = 1; ++ break; ++ case 3: ++ wd->sta.EnableHT = 1; ++ wd->BandWidth40 = 1; ++ wd->ExtOffset = 3; ++ break; ++ case 0: ++ wd->sta.EnableHT = 1; ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ break; ++ default: ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ break; ++ ++ } ++ zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, ++ wd->ExtOffset, NULL); ++} ++ ++void zfiSetRifs(zdev_t* dev, u16_t setting) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.ie.HtInfo.ChannelInfo |= ExtHtCap_RIFSMode; ++ wd->sta.EnableHT = 1; ++ switch (setting) ++ { ++ case 0: ++ wd->sta.HT2040 = 0; ++// zfHpSetRifs(dev, 1, 0, (wd->sta.currentFrequency < 3000)? 1:0); ++ break; ++ case 1: ++ wd->sta.HT2040 = 1; ++// zfHpSetRifs(dev, 1, 1, (wd->sta.currentFrequency < 3000)? 1:0); ++ break; ++ default: ++ wd->sta.HT2040 = 0; ++// zfHpSetRifs(dev, 1, 0, (wd->sta.currentFrequency < 3000)? 1:0); ++ break; ++ } ++} ++ ++void zfiCheckRifs(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if(wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_RIFSMode) ++ { ++// zfHpSetRifs(dev, wd->sta.EnableHT, wd->sta.HT2040, (wd->sta.currentFrequency < 3000)? 1:0); ++ } ++} ++ ++void zfiSetReorder(zdev_t* dev, u16_t value) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->reorder = value; ++} ++ ++void zfiSetSeqDebug(zdev_t* dev, u16_t value) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->seq_debug = value; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cfunc.c +@@ -0,0 +1,1227 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++ ++u8_t zfQueryOppositeRate(zdev_t* dev, u8_t dst_mac[6], u8_t frameType) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* For AP's rate adaption */ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ return 0; ++ } ++ ++ /* For STA's rate adaption */ ++ if ( (frameType & 0x0c) == ZM_WLAN_DATA_FRAME ) ++ { ++ if ( ZM_IS_MULTICAST(dst_mac) ) ++ { ++ return wd->sta.mTxRate; ++ } ++ else ++ { ++ return wd->sta.uTxRate; ++ } ++ } ++ ++ return wd->sta.mmTxRate; ++} ++ ++void zfCopyToIntTxBuffer(zdev_t* dev, zbuf_t* buf, u8_t* src, ++ u16_t offset, u16_t length) ++{ ++ u16_t i; ++ ++ for(i=0; icommTally.Hw_UnderrunCnt += (0xFFFF & rsp[1]); ++ wd->commTally.Hw_TotalRxFrm += rsp[2]; ++ wd->commTally.Hw_CRC32Cnt += rsp[3]; ++ wd->commTally.Hw_CRC16Cnt += rsp[4]; ++ #ifdef ZM_ENABLE_NATIVE_WIFI ++ /* These code are here to satisfy Vista DTM */ ++ wd->commTally.Hw_DecrypErr_UNI += ((rsp[5]>50) && (rsp[5]<60))?50:rsp[5]; ++ #else ++ wd->commTally.Hw_DecrypErr_UNI += rsp[5]; ++ #endif ++ wd->commTally.Hw_RxFIFOOverrun += rsp[6]; ++ wd->commTally.Hw_DecrypErr_Mul += rsp[7]; ++ wd->commTally.Hw_RetryCnt += rsp[8]; ++ wd->commTally.Hw_TotalTxFrm += rsp[9]; ++ wd->commTally.Hw_RxTimeOut +=rsp[10]; ++ ++ wd->commTally.Tx_MPDU += rsp[11]; ++ wd->commTally.BA_Fail += rsp[12]; ++ wd->commTally.Hw_Tx_AMPDU += rsp[13]; ++ wd->commTally.Hw_Tx_MPDU += rsp[14]; ++ wd->commTally.RateCtrlTxMPDU += rsp[11]; ++ wd->commTally.RateCtrlBAFail += rsp[12]; ++ } ++ else ++ { ++ wd->commTally.Hw_RxMPDU += rsp[1]; ++ wd->commTally.Hw_RxDropMPDU += rsp[2]; ++ wd->commTally.Hw_RxDelMPDU += rsp[3]; ++ ++ wd->commTally.Hw_RxPhyMiscError += rsp[4]; ++ wd->commTally.Hw_RxPhyXRError += rsp[5]; ++ wd->commTally.Hw_RxPhyOFDMError += rsp[6]; ++ wd->commTally.Hw_RxPhyCCKError += rsp[7]; ++ wd->commTally.Hw_RxPhyHTError += rsp[8]; ++ wd->commTally.Hw_RxPhyTotalCount += rsp[9]; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (id == 0) ++ { ++ zm_msg1_mm(ZM_LV_1, "rsplen =", rsp[0]); ++ zm_msg1_mm(ZM_LV_1, "Hw_UnderrunCnt = ", (0xFFFF & rsp[1])); ++ zm_msg1_mm(ZM_LV_1, "Hw_TotalRxFrm = ", rsp[2]); ++ zm_msg1_mm(ZM_LV_1, "Hw_CRC32Cnt = ", rsp[3]); ++ zm_msg1_mm(ZM_LV_1, "Hw_CRC16Cnt = ", rsp[4]); ++ zm_msg1_mm(ZM_LV_1, "Hw_DecrypErr_UNI = ", rsp[5]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxFIFOOverrun = ", rsp[6]); ++ zm_msg1_mm(ZM_LV_1, "Hw_DecrypErr_Mul = ", rsp[7]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RetryCnt = ", rsp[8]); ++ zm_msg1_mm(ZM_LV_1, "Hw_TotalTxFrm = ", rsp[9]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxTimeOut = ", rsp[10]); ++ zm_msg1_mm(ZM_LV_1, "Tx_MPDU = ", rsp[11]); ++ zm_msg1_mm(ZM_LV_1, "BA_Fail = ", rsp[12]); ++ zm_msg1_mm(ZM_LV_1, "Hw_Tx_AMPDU = ", rsp[13]); ++ zm_msg1_mm(ZM_LV_1, "Hw_Tx_MPDU = ", rsp[14]); ++ } ++ else ++ { ++ zm_msg1_mm(ZM_LV_1, "rsplen = ", rsp[0]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxMPDU = ", (0xFFFF & rsp[1])); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxDropMPDU = ", rsp[2]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxDelMPDU = ", rsp[3]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyMiscError = ", rsp[4]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyXRError = ", rsp[5]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyOFDMError = ", rsp[6]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyCCKError = ", rsp[7]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyHTError = ", rsp[8]); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyTotalCount = ", rsp[9]); ++ } ++ ++} ++ ++/* Timer related functions */ ++void zfTimerInit(zdev_t* dev) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg0(""); ++ ++ wd->timerList.freeCount = ZM_MAX_TIMER_COUNT; ++ wd->timerList.head = &(wd->timerList.list[0]); ++ wd->timerList.tail = &(wd->timerList.list[ZM_MAX_TIMER_COUNT-1]); ++ wd->timerList.head->pre = NULL; ++ wd->timerList.head->next = &(wd->timerList.list[1]); ++ wd->timerList.tail->pre = &(wd->timerList.list[ZM_MAX_TIMER_COUNT-2]); ++ wd->timerList.tail->next = NULL; ++ ++ for( i=1; i<(ZM_MAX_TIMER_COUNT-1); i++ ) ++ { ++ wd->timerList.list[i].pre = &(wd->timerList.list[i-1]); ++ wd->timerList.list[i].next = &(wd->timerList.list[i+1]); ++ } ++ ++ wd->bTimerReady = TRUE; ++} ++ ++ ++u16_t zfTimerSchedule(zdev_t* dev, u16_t event, u32_t tick) ++{ ++ struct zsTimerEntry *pFreeEntry; ++ struct zsTimerEntry *pEntry; ++ u8_t i, count; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->timerList.freeCount == 0 ) ++ { ++ zm_debug_msg0("no more timer"); ++ return 1; ++ } ++ ++ //zm_debug_msg2("event = ", event); ++ //zm_debug_msg1("target tick = ", wd->tick + tick); ++ ++ count = ZM_MAX_TIMER_COUNT - wd->timerList.freeCount; ++ ++ if ( count == 0 ) ++ { ++ wd->timerList.freeCount--; ++ wd->timerList.head->event = event; ++ wd->timerList.head->timer = wd->tick + tick; ++ //zm_debug_msg1("free timer count = ", wd->timerList.freeCount); ++ ++ return 0; ++ } ++ ++ pFreeEntry = wd->timerList.tail; ++ pFreeEntry->timer = wd->tick + tick; ++ pFreeEntry->event = event; ++ wd->timerList.tail = pFreeEntry->pre; ++ pEntry = wd->timerList.head; ++ ++ for( i=0; itimer > pFreeEntry->timer )&& ++ ((pEntry->timer - pFreeEntry->timer) < 1000000000) ) ++ { ++ if ( i != 0 ) ++ { ++ pFreeEntry->pre = pEntry->pre; ++ pFreeEntry->pre->next = pFreeEntry; ++ } ++ else ++ { ++ pFreeEntry->pre = NULL; ++ } ++ ++ pEntry->pre = pFreeEntry; ++ pFreeEntry->next = pEntry; ++ break; ++ } ++ ++ pEntry = pEntry->next; ++ } ++ ++ if ( i == 0 ) ++ { ++ wd->timerList.head = pFreeEntry; ++ } ++ ++ if ( i == count ) ++ { ++ pFreeEntry->pre = pEntry->pre; ++ pFreeEntry->pre->next = pFreeEntry; ++ pEntry->pre = pFreeEntry; ++ pFreeEntry->next = pEntry; ++ } ++ ++ wd->timerList.freeCount--; ++ //zm_debug_msg1("free timer count = ", wd->timerList.freeCount); ++ ++ return 0; ++} ++ ++u16_t zfTimerCancel(zdev_t* dev, u16_t event) ++{ ++ struct zsTimerEntry *pEntry; ++ u8_t i, count; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zm_debug_msg2("event = ", event); ++ //zm_debug_msg1("free timer count(b) = ", wd->timerList.freeCount); ++ ++ pEntry = wd->timerList.head; ++ count = ZM_MAX_TIMER_COUNT - wd->timerList.freeCount; ++ ++ for( i=0; ievent == event ) ++ { ++ if ( pEntry == wd->timerList.head ) ++ { /* remove head entry */ ++ wd->timerList.head = pEntry->next; ++ wd->timerList.tail->next = pEntry; ++ pEntry->pre = wd->timerList.tail; ++ wd->timerList.tail = pEntry; ++ pEntry = wd->timerList.head; ++ } ++ else ++ { /* remove non-head entry */ ++ pEntry->pre->next = pEntry->next; ++ pEntry->next->pre = pEntry->pre; ++ wd->timerList.tail->next = pEntry; ++ pEntry->pre = wd->timerList.tail; ++ wd->timerList.tail = pEntry; ++ pEntry = pEntry->next; ++ } ++ ++ wd->timerList.freeCount++; ++ } ++ else ++ { ++ pEntry = pEntry->next; ++ } ++ } ++ ++ //zm_debug_msg1("free timer count(a) = ", wd->timerList.freeCount); ++ ++ return 0; ++} ++ ++void zfTimerClear(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->timerList.freeCount = ZM_MAX_TIMER_COUNT; ++} ++ ++u16_t zfTimerCheckAndHandle(zdev_t* dev) ++{ ++ struct zsTimerEntry *pEntry; ++ struct zsTimerEntry *pTheLastEntry = NULL; ++ u16_t event[ZM_MAX_TIMER_COUNT]; ++ u8_t i, j=0, count; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( !wd->bTimerReady ) ++ { ++ return 0; ++ } ++ ++ zmw_enter_critical_section(dev); ++ ++ pEntry = wd->timerList.head; ++ count = ZM_MAX_TIMER_COUNT - wd->timerList.freeCount; ++ ++ for( i=0; itimer > wd->tick )&& ++ ((pEntry->timer - wd->tick) < 1000000000) ) ++ { ++ break; ++ } ++ ++ event[j++] = pEntry->event; ++ pTheLastEntry = pEntry; ++ pEntry = pEntry->next; ++ } ++ ++ if ( j > 0 ) ++ { ++ wd->timerList.tail->next = wd->timerList.head; ++ wd->timerList.head->pre = wd->timerList.tail; ++ wd->timerList.head = pEntry; ++ wd->timerList.tail = pTheLastEntry; ++ wd->timerList.freeCount += j; ++ //zm_debug_msg1("free timer count = ", wd->timerList.freeCount); ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zfProcessEvent(dev, event, j); ++ ++ return 0; ++} ++ ++u32_t zfCoreSetKey(zdev_t* dev, u8_t user, u8_t keyId, u8_t type, ++ u16_t* mac, u32_t* key) ++{ ++ u32_t ret; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.flagKeyChanging++; ++ zm_debug_msg1(" zfCoreSetKey++++ ", wd->sta.flagKeyChanging); ++ zmw_leave_critical_section(dev); ++ ++ ret = zfHpSetKey(dev, user, keyId, type, mac, key); ++ return ret; ++} ++ ++void zfCoreSetKeyComplete(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++#if 0 ++ wd->sta.flagKeyChanging = 0; ++#else ++ if(wd->sta.flagKeyChanging) ++ { ++ zmw_enter_critical_section(dev); ++ wd->sta.flagKeyChanging--; ++ zmw_leave_critical_section(dev); ++ } ++#endif ++ zm_debug_msg1(" zfCoreSetKeyComplete--- ", wd->sta.flagKeyChanging); ++ ++ zfPushVtxq(dev); ++} ++ ++void zfCoreHalInitComplete(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->halState = ZM_HAL_STATE_RUNNING; ++ zmw_leave_critical_section(dev); ++ ++ zfPushVtxq(dev); ++} ++ ++void zfCoreMacAddressNotify(zdev_t* dev, u8_t* addr) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->macAddr[0] = addr[0] | ((u16_t)addr[1]<<8); ++ wd->macAddr[1] = addr[2] | ((u16_t)addr[3]<<8); ++ wd->macAddr[2] = addr[4] | ((u16_t)addr[5]<<8); ++ ++ ++ //zfHpSetMacAddress(dev, wd->macAddr, 0); ++ if (wd->zfcbMacAddressNotify != NULL) ++ { ++ wd->zfcbMacAddressNotify(dev, addr); ++ } ++} ++ ++void zfCoreSetIsoName(zdev_t* dev, u8_t* isoName) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.countryIsoName[0] = isoName[0]; ++ wd->ws.countryIsoName[1] = isoName[1]; ++ wd->ws.countryIsoName[2] = '\0'; ++ } ++ ++ ++extern void zfScanMgrScanEventStart(zdev_t* dev); ++extern u8_t zfScanMgrScanEventTimeout(zdev_t* dev); ++extern void zfScanMgrScanEventRetry(zdev_t* dev); ++ ++void zfProcessEvent(zdev_t* dev, u16_t* eventArray, u8_t eventCount) ++{ ++ u8_t i, j, bypass = FALSE; ++ u16_t eventBypass[32]; ++ u8_t eventBypassCount = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zfZeroMemory((u8_t*) eventBypass, 64); ++ ++ for( i=0; ista.cmMicFailureCount = 0; ++ } ++ break; ++ ++ case ZM_EVENT_CM_DISCONNECT: ++ { ++ zm_msg0_mm(ZM_LV_0, "ZM_EVENT_CM_DISCONNECT"); ++ ++ zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); ++ ++ zmw_enter_critical_section(dev); ++ //zfTimerSchedule(dev, ZM_EVENT_CM_BLOCK_TIMER, ++ // ZM_TICK_CM_BLOCK_TIMEOUT); ++ ++ /* Timer Resolution on WinXP is 15/16 ms */ ++ /* Decrease Time offset for Counter Measure */ ++ zfTimerSchedule(dev, ZM_EVENT_CM_BLOCK_TIMER, ++ ZM_TICK_CM_BLOCK_TIMEOUT - ZM_TICK_CM_BLOCK_TIMEOUT_OFFSET); ++ ++ zmw_leave_critical_section(dev); ++ wd->sta.cmMicFailureCount = 0; ++ //zfiWlanDisable(dev); ++ zfHpResetKeyCache(dev); ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_DISCONNECT_MIC_FAIL, ++ wd->sta.bssid); ++ } ++ } ++ break; ++ ++ case ZM_EVENT_CM_BLOCK_TIMER: ++ { ++ zm_msg0_mm(ZM_LV_0, "ZM_EVENT_CM_BLOCK_TIMER"); ++ ++ //zmw_enter_critical_section(dev); ++ wd->sta.cmDisallowSsidLength = 0; ++ if ( wd->sta.bAutoReconnect ) ++ { ++ zm_msg0_mm(ZM_LV_0, "ZM_EVENT_CM_BLOCK_TIMER:bAutoReconnect!=0"); ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ zfScanMgrScanStart(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ } ++ //zmw_leave_critical_section(dev); ++ } ++ break; ++ ++ case ZM_EVENT_TIMEOUT_ADDBA: ++ { ++ if (!wd->addbaComplete && (wd->addbaCount < 5)) ++ { ++ zfAggSendAddbaRequest(dev, wd->sta.bssid, 0, 0); ++ wd->addbaCount++; ++ zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_ADDBA, 100); ++ } ++ else ++ { ++ zfTimerCancel(dev, ZM_EVENT_TIMEOUT_ADDBA); ++ } ++ } ++ break; ++ ++ #ifdef ZM_ENABLE_PERFORMANCE_EVALUATION ++ case ZM_EVENT_TIMEOUT_PERFORMANCE: ++ { ++ zfiPerformanceRefresh(dev); ++ } ++ break; ++ #endif ++ case ZM_EVENT_SKIP_COUNTERMEASURE: ++ //enable the Countermeasure ++ { ++ zm_debug_msg0("Countermeasure : Enable MIC Check "); ++ wd->TKIP_Group_KeyChanging = 0x0; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++} ++ ++void zfBssInfoCreate(zdev_t* dev) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ wd->sta.bssList.bssCount = 0; ++ wd->sta.bssList.head = NULL; ++ wd->sta.bssList.tail = NULL; ++ wd->sta.bssInfoArrayHead = 0; ++ wd->sta.bssInfoArrayTail = 0; ++ wd->sta.bssInfoFreeCount = ZM_MAX_BSS; ++ ++ for( i=0; i< ZM_MAX_BSS; i++ ) ++ { ++ //wd->sta.bssInfoArray[i] = &(wd->sta.bssInfoPool[i]); ++ wd->sta.bssInfoArray[i] = zfwMemAllocate(dev, sizeof(struct zsBssInfo)); ++ ++ } ++ ++ zmw_leave_critical_section(dev); ++} ++ ++void zfBssInfoDestroy(zdev_t* dev) ++{ ++ u8_t i; ++ zmw_get_wlan_dev(dev); ++ ++ zfBssInfoRefresh(dev, 1); ++ ++ for( i=0; i< ZM_MAX_BSS; i++ ) ++ { ++ if (wd->sta.bssInfoArray[i] != NULL) ++ { ++ zfwMemFree(dev, wd->sta.bssInfoArray[i], sizeof(struct zsBssInfo)); ++ } ++ else ++ { ++ zm_assert(0); ++ } ++ } ++ return; ++} ++ ++struct zsBssInfo* zfBssInfoAllocate(zdev_t* dev) ++{ ++ struct zsBssInfo* pBssInfo; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->sta.bssInfoFreeCount == 0) ++ return NULL; ++ ++ pBssInfo = wd->sta.bssInfoArray[wd->sta.bssInfoArrayHead]; ++ wd->sta.bssInfoArray[wd->sta.bssInfoArrayHead] = NULL; ++ wd->sta.bssInfoArrayHead = (wd->sta.bssInfoArrayHead + 1) & (ZM_MAX_BSS - 1); ++ wd->sta.bssInfoFreeCount--; ++ ++ zfZeroMemory((u8_t*)pBssInfo, sizeof(struct zsBssInfo)); ++ ++ return pBssInfo; ++} ++ ++void zfBssInfoFree(zdev_t* dev, struct zsBssInfo* pBssInfo) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_assert(wd->sta.bssInfoArray[wd->sta.bssInfoArrayTail] == NULL); ++ ++ pBssInfo->signalStrength = pBssInfo->signalQuality = 0; ++ pBssInfo->sortValue = 0; ++ ++ wd->sta.bssInfoArray[wd->sta.bssInfoArrayTail] = pBssInfo; ++ wd->sta.bssInfoArrayTail = (wd->sta.bssInfoArrayTail + 1) & (ZM_MAX_BSS - 1); ++ wd->sta.bssInfoFreeCount++; ++} ++ ++void zfBssInfoReorderList(zdev_t* dev) ++{ ++ struct zsBssInfo* pBssInfo = NULL; ++ struct zsBssInfo* pInsBssInfo = NULL; ++ struct zsBssInfo* pNextBssInfo = NULL; ++ struct zsBssInfo* pPreBssInfo = NULL; ++ u8_t i = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (wd->sta.bssList.bssCount > 1) ++ { ++ pInsBssInfo = wd->sta.bssList.head; ++ wd->sta.bssList.tail = pInsBssInfo; ++ pBssInfo = pInsBssInfo->next; ++ pInsBssInfo->next = NULL; ++ while (pBssInfo != NULL) ++ { ++ i = 0; ++ while (1) ++ { ++// if (pBssInfo->signalStrength >= pInsBssInfo->signalStrength) ++ if( pBssInfo->sortValue >= pInsBssInfo->sortValue) ++ { ++ if (i==0) ++ { ++ //Insert BssInfo to head ++ wd->sta.bssList.head = pBssInfo; ++ pNextBssInfo = pBssInfo->next; ++ pBssInfo->next = pInsBssInfo; ++ break; ++ } ++ else ++ { ++ //Insert BssInfo to neither head nor tail ++ pPreBssInfo->next = pBssInfo; ++ pNextBssInfo = pBssInfo->next; ++ pBssInfo->next = pInsBssInfo; ++ break; ++ } ++ } ++ else ++ { ++ if (pInsBssInfo->next != NULL) ++ { ++ //Signal strength smaller than current BssInfo, check next ++ pPreBssInfo = pInsBssInfo; ++ pInsBssInfo = pInsBssInfo->next; ++ } ++ else ++ { ++ //Insert BssInfo to tail ++ pInsBssInfo->next = pBssInfo; ++ pNextBssInfo = pBssInfo->next; ++ wd->sta.bssList.tail = pBssInfo; ++ pBssInfo->next = NULL; ++ break; ++ } ++ } ++ i++; ++ } ++ pBssInfo = pNextBssInfo; ++ pInsBssInfo = wd->sta.bssList.head; ++ } ++ } //if (wd->sta.bssList.bssCount > 1) ++ ++ zmw_leave_critical_section(dev); ++} ++ ++void zfBssInfoInsertToList(zdev_t* dev, struct zsBssInfo* pBssInfo) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_assert(pBssInfo); ++ ++ //zm_debug_msg2("pBssInfo = ", pBssInfo); ++ ++ if ( wd->sta.bssList.bssCount == 0 ) ++ { ++ wd->sta.bssList.head = pBssInfo; ++ wd->sta.bssList.tail = pBssInfo; ++ } ++ else ++ { ++ wd->sta.bssList.tail->next = pBssInfo; ++ wd->sta.bssList.tail = pBssInfo; ++ } ++ ++ pBssInfo->next = NULL; ++ wd->sta.bssList.bssCount++; ++ ++ //zm_debug_msg2("bss count = ", wd->sta.bssList.bssCount); ++} ++ ++void zfBssInfoRemoveFromList(zdev_t* dev, struct zsBssInfo* pBssInfo) ++{ ++ struct zsBssInfo* pNowBssInfo; ++ struct zsBssInfo* pPreBssInfo = NULL; ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_assert(pBssInfo); ++ zm_assert(wd->sta.bssList.bssCount); ++ ++ //zm_debug_msg2("pBssInfo = ", pBssInfo); ++ ++ pNowBssInfo = wd->sta.bssList.head; ++ ++ for( i=0; ista.bssList.bssCount; i++ ) ++ { ++ if ( pNowBssInfo == pBssInfo ) ++ { ++ if ( i == 0 ) ++ { /* remove head */ ++ wd->sta.bssList.head = pBssInfo->next; ++ } ++ else ++ { ++ pPreBssInfo->next = pBssInfo->next; ++ } ++ ++ if ( i == (wd->sta.bssList.bssCount - 1) ) ++ { /* remove tail */ ++ wd->sta.bssList.tail = pPreBssInfo; ++ } ++ ++ break; ++ } ++ ++ pPreBssInfo = pNowBssInfo; ++ pNowBssInfo = pNowBssInfo->next; ++ } ++ ++ zm_assert(i != wd->sta.bssList.bssCount); ++ wd->sta.bssList.bssCount--; ++ ++ //zm_debug_msg2("bss count = ", wd->sta.bssList.bssCount); ++} ++ ++void zfBssInfoRefresh(zdev_t* dev, u16_t mode) ++{ ++ struct zsBssInfo* pBssInfo; ++ struct zsBssInfo* pNextBssInfo; ++ u8_t i, bssCount; ++ ++ zmw_get_wlan_dev(dev); ++ ++ pBssInfo = wd->sta.bssList.head; ++ bssCount = wd->sta.bssList.bssCount; ++ ++ for( i=0; inext; ++ zfBssInfoRemoveFromList(dev, pBssInfo); ++ zfBssInfoFree(dev, pBssInfo); ++ pBssInfo = pNextBssInfo; ++ } ++ else ++ { ++ if ( pBssInfo->flag & ZM_BSS_INFO_VALID_BIT ) ++ { /* this one must be kept */ ++ pBssInfo->flag &= ~ZM_BSS_INFO_VALID_BIT; ++ pBssInfo = pBssInfo->next; ++ } ++ else ++ { ++ #define ZM_BSS_CACHE_TIME_IN_MS 20000 ++ if ((wd->tick - pBssInfo->tick) > (ZM_BSS_CACHE_TIME_IN_MS/ZM_MS_PER_TICK)) ++ { ++ pNextBssInfo = pBssInfo->next; ++ zfBssInfoRemoveFromList(dev, pBssInfo); ++ zfBssInfoFree(dev, pBssInfo); ++ pBssInfo = pNextBssInfo; ++ } ++ else ++ { ++ pBssInfo = pBssInfo->next; ++ } ++ } ++ } ++ } //for( i=0; i 49 ) ++ { ++ tmpLength = 49; ++ } ++ ++ zfMemoryCopy(buf, value, tmpLength); ++ buf[tmpLength] = '\0'; ++ //printk("SSID: %s\n", buf); ++ //zm_debug_msg_s("ssid = ", value); ++} ++ ++void zfCoreReinit(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.flagKeyChanging = 0; ++ wd->sta.flagFreqChanging = 0; ++} ++ ++void zfGenerateRandomBSSID(zdev_t* dev, u8_t *MACAddr, u8_t *BSSID) ++{ ++ //ULONGLONG time; ++ u32_t time; ++ ++ zmw_get_wlan_dev(dev); ++ ++ time = wd->tick; ++ ++ // ++ // Initialize the random BSSID to be the same as MAC address. ++ // ++ ++ // RtlCopyMemory(BSSID, MACAddr, sizeof(DOT11_MAC_ADDRESS)); ++ zfMemoryCopy(BSSID, MACAddr, 6); ++ ++ // ++ // Get the system time in 10 millisecond. ++ // ++ ++ // NdisGetCurrentSystemTime((PLARGE_INTEGER)&time); ++ // time /= 100000; ++ ++ // ++ // Randomize the first 4 bytes of BSSID. ++ // ++ ++ BSSID[0] ^= (u8_t)(time & 0xff); ++ BSSID[0] &= ~0x01; // Turn off multicast bit ++ BSSID[0] |= 0x02; // Turn on local bit ++ ++ time >>= 8; ++ BSSID[1] ^= (u8_t)(time & 0xff); ++ ++ time >>= 8; ++ BSSID[2] ^= (u8_t)(time & 0xff); ++ ++ time >>= 8; ++ BSSID[3] ^= (u8_t)(time & 0xff); ++} ++ ++u8_t zfiWlanGetDestAddrFromBuf(zdev_t *dev, zbuf_t *buf, u16_t *macAddr) ++{ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ /* DA */ ++ macAddr[0] = zmw_tx_buf_readh(dev, buf, 16); ++ macAddr[1] = zmw_tx_buf_readh(dev, buf, 18); ++ macAddr[2] = zmw_tx_buf_readh(dev, buf, 20); ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ /* DA */ ++ macAddr[0] = zmw_tx_buf_readh(dev, buf, 4); ++ macAddr[1] = zmw_tx_buf_readh(dev, buf, 6); ++ macAddr[2] = zmw_tx_buf_readh(dev, buf, 8); ++ } ++ else if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ /* DA */ ++ macAddr[0] = zmw_tx_buf_readh(dev, buf, 4); ++ macAddr[1] = zmw_tx_buf_readh(dev, buf, 6); ++ macAddr[2] = zmw_tx_buf_readh(dev, buf, 8); ++ } ++ else ++ { ++ return 1; ++ } ++#else ++ /* DA */ ++ macAddr[0] = zmw_tx_buf_readh(dev, buf, 0); ++ macAddr[1] = zmw_tx_buf_readh(dev, buf, 2); ++ macAddr[2] = zmw_tx_buf_readh(dev, buf, 4); ++#endif ++ ++ return 0; ++} ++ ++/* Leave an empty line below to remove warning message on some compiler */ ++ ++u16_t zfFindCleanFrequency(zdev_t* dev, u32_t adhocMode) ++{ ++ u8_t i, j; ++ u16_t returnChannel; ++ u16_t count_24G = 0, min24GIndex = 0; ++ u16_t count_5G = 0, min5GIndex = 0; ++ u16_t CombinationBssNumberIn24G[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; ++ u16_t BssNumberIn24G[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; ++ u16_t Array_24G[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; ++ u16_t BssNumberIn5G[31] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; ++ u16_t Array_5G[31] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; ++ struct zsBssInfo* pBssInfo; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ((pBssInfo = wd->sta.bssList.head) == NULL) ++ { ++ if( adhocMode == ZM_ADHOCBAND_B || adhocMode == ZM_ADHOCBAND_G || ++ adhocMode == ZM_ADHOCBAND_BG || adhocMode == ZM_ADHOCBAND_ABG ) ++ { ++ returnChannel = zfChGetFirst2GhzChannel(dev); ++ } ++ else ++ { ++ returnChannel = zfChGetFirst5GhzChannel(dev); ++ } ++ ++ return returnChannel; ++ } ++ ++ /* #1 Get Allowed Channel following Country Code ! */ ++ zmw_declare_for_critical_section(); ++ zmw_enter_critical_section(dev); ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel < 3000) ++ { // 2.4GHz ++ Array_24G[count_24G] = wd->regulationTable.allowChannel[i].channel; ++ count_24G++; ++ } ++ else ++ { // 5GHz ++ count_5G++; ++ Array_5G[i] = wd->regulationTable.allowChannel[i].channel; ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++ while( pBssInfo != NULL ) ++ { ++ /* #2_1 Count BSS number in some specificed frequency in 2.4GHz band ! */ ++ if( adhocMode == ZM_ADHOCBAND_B || adhocMode == ZM_ADHOCBAND_G || ++ adhocMode == ZM_ADHOCBAND_BG || adhocMode == ZM_ADHOCBAND_ABG ) ++ { ++ for( i=0; i<=(count_24G+3); i++ ) ++ { ++ if( pBssInfo->frequency == Array_24G[i] ) ++ { // Array_24G[0] correspond to BssNumberIn24G[2] ++ BssNumberIn24G[pBssInfo->channel+1]++; ++ } ++ } ++ } ++ ++ /* #2_2 Count BSS number in some specificed frequency in 5GHz band ! */ ++ if( adhocMode == ZM_ADHOCBAND_A || adhocMode == ZM_ADHOCBAND_ABG ) ++ { ++ for( i=0; ifrequency == Array_5G[i] ) ++ { // Array_5G[0] correspond to BssNumberIn5G[0] ++ BssNumberIn5G[i]++; ++ } ++ } ++ } ++ ++ pBssInfo = pBssInfo->next; ++ } ++ ++#if 0 ++ for(i=0; i<=(count_24G+3); i++) ++ { ++ printk("2.4GHz Before combin, %d BSS network : %d", i, BssNumberIn24G[i]); ++ } ++ ++ for(i=0; ista.bssid, 6) ) ++ { ++ return 1; ++ } ++ else ++ { ++ return 0; ++ } ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cfunc.h +@@ -0,0 +1,449 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : func_extr.c */ ++/* */ ++/* Abstract */ ++/* This module contains function prototype. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _CFUNC_H ++#define _CFUNC_H ++ ++#include "queue.h" ++ ++/* amsdu.c */ ++void zfDeAmsdu(zdev_t* dev, zbuf_t* buf, u16_t vap, u8_t encryMode); ++ ++/* cscanmgr.c */ ++void zfScanMgrInit(zdev_t* dev); ++u8_t zfScanMgrScanStart(zdev_t* dev, u8_t scanType); ++void zfScanMgrScanStop(zdev_t* dev, u8_t scanType); ++void zfScanMgrScanAck(zdev_t* dev); ++ ++/* cpsmgr.c */ ++void zfPowerSavingMgrInit(zdev_t* dev); ++void zfPowerSavingMgrSetMode(zdev_t* dev, u8_t mode); ++void zfPowerSavingMgrMain(zdev_t* dev); ++void zfPowerSavingMgrWakeup(zdev_t* dev); ++u8_t zfPowerSavingMgrIsSleeping(zdev_t *dev); ++void zfPowerSavingMgrProcessBeacon(zdev_t* dev, zbuf_t* buf); ++void zfPowerSavingMgrAtimWinExpired(zdev_t* dev); ++void zfPowerSavingMgrConnectNotify(zdev_t *dev); ++void zfPowerSavingMgrPreTBTTInterrupt(zdev_t *dev); ++ ++/* ccmd.c */ ++u16_t zfWlanEnable(zdev_t* dev); ++ ++/* cfunc.c */ ++u8_t zfQueryOppositeRate(zdev_t* dev, u8_t dst_mac[6], u8_t frameType); ++void zfCopyToIntTxBuffer(zdev_t* dev, zbuf_t* buf, u8_t* src, ++ u16_t offset, u16_t length); ++void zfCopyToRxBuffer(zdev_t* dev, zbuf_t* buf, u8_t* src, ++ u16_t offset, u16_t length); ++void zfCopyFromIntTxBuffer(zdev_t* dev, zbuf_t* buf, u8_t* dst, ++ u16_t offset, u16_t length); ++void zfCopyFromRxBuffer(zdev_t* dev, zbuf_t* buf, u8_t* dst, ++ u16_t offset, u16_t length); ++void zfMemoryCopy(u8_t* dst, u8_t* src, u16_t length); ++void zfMemoryMove(u8_t* dst, u8_t* src, u16_t length); ++void zfZeroMemory(u8_t* va, u16_t length); ++u8_t zfMemoryIsEqual(u8_t* m1, u8_t* m2, u16_t length); ++u8_t zfRxBufferEqualToStr(zdev_t* dev, zbuf_t* buf, const u8_t* str, ++ u16_t offset, u16_t length); ++void zfTxBufferCopy(zdev_t*dev, zbuf_t* dst, zbuf_t* src, ++ u16_t dstOffset, u16_t srcOffset, u16_t length); ++void zfRxBufferCopy(zdev_t*dev, zbuf_t* dst, zbuf_t* src, ++ u16_t dstOffset, u16_t srcOffset, u16_t length); ++ ++void zfCollectHWTally(zdev_t*dev, u32_t* rsp, u8_t id); ++void zfTimerInit(zdev_t* dev); ++u16_t zfTimerSchedule(zdev_t* dev, u16_t event, u32_t tick); ++u16_t zfTimerCancel(zdev_t* dev, u16_t event); ++void zfTimerClear(zdev_t* dev); ++u16_t zfTimerCheckAndHandle(zdev_t* dev); ++void zfProcessEvent(zdev_t* dev, u16_t* eventArray, u8_t eventCount); ++ ++void zfBssInfoCreate(zdev_t* dev); ++void zfBssInfoDestroy(zdev_t* dev); ++ ++struct zsBssInfo* zfBssInfoAllocate(zdev_t* dev); ++void zfBssInfoFree(zdev_t* dev, struct zsBssInfo* pBssInfo); ++void zfBssInfoReorderList(zdev_t* dev); ++void zfBssInfoInsertToList(zdev_t* dev, struct zsBssInfo* pBssInfo); ++void zfBssInfoRemoveFromList(zdev_t* dev, struct zsBssInfo* pBssInfo); ++void zfBssInfoRefresh(zdev_t* dev, u16_t mode); ++void zfCoreSetFrequencyComplete(zdev_t* dev); ++void zfCoreSetFrequency(zdev_t* dev, u16_t frequency); ++void zfCoreSetFrequencyV2(zdev_t* dev, u16_t frequency, ++ zfpFreqChangeCompleteCb cb); ++void zfCoreSetFrequencyEx(zdev_t* dev, u16_t frequency, u8_t bw40, ++ u8_t extOffset, zfpFreqChangeCompleteCb cb); ++void zfCoreSetFrequencyExV2(zdev_t* dev, u16_t frequency, u8_t bw40, ++ u8_t extOffset, zfpFreqChangeCompleteCb cb, u8_t forceSetFreq); ++void zfReSetCurrentFrequency(zdev_t* dev); ++u32_t zfCoreSetKey(zdev_t* dev, u8_t user, u8_t keyId, u8_t type, ++ u16_t* mac, u32_t* key); ++void zfCoreSetKeyComplete(zdev_t* dev); ++void zfCoreReinit(zdev_t* dev); ++void zfCoreMacAddressNotify(zdev_t* dev, u8_t *addr); ++void zfCoreSetIsoName(zdev_t* dev, u8_t* isoName); ++void zfGenerateRandomBSSID(zdev_t* dev, u8_t *MACAddr, u8_t *BSSID); ++void zfCoreHalInitComplete(zdev_t* dev); ++ ++u16_t zfFindCleanFrequency(zdev_t* dev, u32_t adhocMode); ++u16_t zfFindMinimumUtilizationChannelIndex(zdev_t* dev, u16_t* array, u16_t count); ++u8_t zfCompareWithBssid(zdev_t* dev, u16_t* bssid); ++ ++/* chb.c */ ++void zfDumpBssList(zdev_t* dev); ++ ++ ++u16_t zfIssueCmd(zdev_t* dev, u32_t* cmd, u16_t cmdLen, u16_t src, u8_t* buf); ++ ++ ++/* cic.c */ ++void zfUpdateBssid(zdev_t* dev, u8_t* bssid); ++void zfResetSupportRate(zdev_t* dev, u8_t type); ++void zfUpdateSupportRate(zdev_t* dev, u8_t* rateArray); ++u8_t zfIsGOnlyMode(zdev_t* dev, u16_t frequency, u8_t* rateArray); ++void zfGatherBMode(zdev_t* dev, u8_t* rateArray, u8_t* extrateArray); ++u8_t zfPSDeviceSleep(zdev_t* dev); ++u16_t zfGetRandomNumber(zdev_t* dev, u16_t initValue); ++void zfCoreEvent(zdev_t* dev, u16_t event, u8_t* rsp); ++void zfBeaconCfgInterrupt(zdev_t* dev, u8_t* rsp); ++void zfEndOfAtimWindowInterrupt(zdev_t* dev); ++ ++/* cinit.c */ ++u16_t zfTxGenWlanHeader(zdev_t* dev, zbuf_t* buf, u16_t* header, u16_t seq, ++ u8_t flag, u16_t plusLen, u16_t minusLen, u16_t port, ++ u16_t* da, u16_t* sa, u8_t up, u16_t *micLen, ++ u16_t* snap, u16_t snapLen, struct aggControl *aggControl); ++u16_t zfTxGenMmHeader(zdev_t* dev, u8_t frameType, u16_t* dst, ++ u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt); ++void zfInitMacApMode(zdev_t* dev); ++u16_t zfChGetNextChannel(zdev_t* dev, u16_t frequency, u8_t* pbPassive); ++u16_t zfChGetFirstChannel(zdev_t* dev, u8_t* pbPassive); ++u16_t zfChGetFirst2GhzChannel(zdev_t* dev); ++u16_t zfChGetFirst5GhzChannel(zdev_t* dev); ++u16_t zfChGetLastChannel(zdev_t* dev, u8_t* pbPassive); ++u16_t zfChGetLast5GhzChannel(zdev_t* dev); ++u16_t zfChNumToFreq(zdev_t* dev, u8_t ch, u8_t freqBand); ++u8_t zfChFreqToNum(u16_t freq, u8_t* bIs5GBand); ++ ++/* cmm.c */ ++void zfProcessManagement(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo); //CWYang(m) ++void zfSendMmFrame(zdev_t* dev, u8_t frameType, u16_t* dst, ++ u32_t p1, u32_t p2, u32_t p3); ++u16_t zfFindElement(zdev_t* dev, zbuf_t* buf, u8_t eid); ++u16_t zfFindWifiElement(zdev_t* dev, zbuf_t* buf, u8_t type, u8_t subtype); ++u16_t zfFindSuperGElement(zdev_t* dev, zbuf_t* buf, u8_t type); ++u16_t zfFindXRElement(zdev_t* dev, zbuf_t* buf, u8_t type); ++u16_t zfRemoveElement(zdev_t* dev, u8_t* buf, u16_t size, u8_t eid); ++u16_t zfUpdateElement(zdev_t* dev, u8_t* buf, u16_t size, u8_t* updateeid); ++void zfProcessProbeReq(zdev_t* dev, zbuf_t* buf, u16_t* src); ++void zfProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo); ++u16_t zfSendProbeReq(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t bWithSSID); ++u16_t zfMmAddIeSupportRate(zdev_t* dev, zbuf_t* buf, ++ u16_t offset, u8_t eid, u8_t rateSet); ++u16_t zfMmAddIeDs(zdev_t* dev, zbuf_t* buf, u16_t offset); ++u16_t zfMmAddIeErp(zdev_t* dev, zbuf_t* buf, u16_t offset); ++void zfUpdateDefaultQosParameter(zdev_t* dev, u8_t mode); ++u16_t zfMmAddIeWpa(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t apId); ++u16_t zfMmAddHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset); //CWYang(+) ++u16_t zfMmAddPreNHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset); ++u16_t zfMmAddExtendedHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset); //CWYang(+) ++u16_t zfFindATHExtCap(zdev_t* dev, zbuf_t* buf, u8_t type, u8_t subtype); ++u16_t zfFindBrdcmMrvlRlnkExtCap(zdev_t* dev, zbuf_t* buf); ++u16_t zfFindMarvelExtCap(zdev_t* dev, zbuf_t* buf); ++u16_t zfFindBroadcomExtCap(zdev_t* dev, zbuf_t* buf); ++u16_t zfFindRlnkExtCap(zdev_t* dev, zbuf_t* buf); ++ ++/* cmmap.c */ ++void zfMmApTimeTick(zdev_t* dev); ++void zfApAgingSta(zdev_t* dev); ++u16_t zfApAddSta(zdev_t* dev, u16_t* addr, u16_t state, u16_t apId, u8_t type, ++ u8_t qosType, u8_t qosInfo); ++void zfApProtctionMonitor(zdev_t* dev); ++void zfApProcessBeacon(zdev_t* dev, zbuf_t* buf); ++void zfApProcessAuth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId); ++void zfApProcessAsocReq(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId); ++void zfApProcessAsocRsp(zdev_t* dev, zbuf_t* buf); ++void zfApProcessDeauth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId); ++void zfApProcessDisasoc(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId); ++void zfApProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo); ++void zfApStoreAsocReqIe(zdev_t* dev, zbuf_t* buf, u16_t aid); ++u16_t zfApAddIeSsid(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap); ++void zfApSendBeacon(zdev_t* dev); ++u16_t zfApGetSTAInfo(zdev_t* dev, u16_t* addr, u16_t* state, u8_t* vap); ++u16_t zfIntrabssForward(zdev_t* dev, zbuf_t* buf, u8_t srcVap); ++u16_t zfApBufferPsFrame(zdev_t* dev, zbuf_t* buf, u16_t port); ++void zfApInitStaTbl(zdev_t* dev); ++void zfApGetStaTxRateAndQosType(zdev_t* dev, u16_t* addr, u32_t* phyCtrl, ++ u8_t* qosType, u16_t* rcProbingFlag); ++void zfApGetStaQosType(zdev_t* dev, u16_t* addr, u8_t* qosType); ++void zfApSetStaTxRate(zdev_t* dev, u16_t* addr, u32_t phyCtrl); ++struct zsMicVar* zfApGetRxMicKey(zdev_t* dev, zbuf_t* buf); ++struct zsMicVar* zfApGetTxMicKey(zdev_t* dev, zbuf_t* buf, u8_t* qosType); ++u16_t zfApAddIeWmePara(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap); ++u16_t zfApUpdatePsBit(zdev_t* dev, zbuf_t* buf, u8_t* vap, u8_t* uapsdTrig); ++void zfApProcessPsPoll(zdev_t* dev, zbuf_t* buf); ++u16_t zfApFindSta(zdev_t* dev, u16_t* addr); ++void zfApGetStaEncryType(zdev_t* dev, u16_t* addr, u8_t* encryType); ++void zfApGetStaWpaIv(zdev_t* dev, u16_t* addr, u16_t* iv16, u32_t* iv32); ++void zfApSetStaWpaIv(zdev_t* dev, u16_t* addr, u16_t iv16, u32_t iv32); ++void zfApClearStaKey(zdev_t* dev, u16_t* addr); ++#ifdef ZM_ENABLE_CENC ++void zfApGetStaCencIvAndKeyIdx(zdev_t* dev, u16_t* addr, u32_t *iv, ++ u8_t *keyIdx); ++void zfApSetStaCencIv(zdev_t* dev, u16_t* addr, u32_t *iv); ++#endif //ZM_ENABLE_CENC ++void zfApSetProtectionMode(zdev_t* dev, u16_t mode); ++void zfApFlushBufferedPsFrame(zdev_t* dev); ++void zfApSendFailure(zdev_t* dev, u8_t* addr); ++u8_t zfApRemoveFromPsQueue(zdev_t* dev, u16_t id, u16_t* src); ++void zfApProcessAction(zdev_t* dev, zbuf_t* buf); ++/* cmmsta.c */ ++void zfMmStaTimeTick(zdev_t* dev); ++void zfReWriteBeaconStartAddress(zdev_t* dev); // Mxzeng ++void zfStaProcessBeacon(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo); //CWYang(m) ++void zfStaProcessAuth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId); ++void zfStaProcessAsocReq(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId); ++void zfStaProcessAsocRsp(zdev_t* dev, zbuf_t* buf); ++void zfStaProcessDeauth(zdev_t* dev, zbuf_t* buf); ++void zfStaProcessDisasoc(zdev_t* dev, zbuf_t* buf); ++void zfStaProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo); ++void zfStaProcessAtim(zdev_t* dev, zbuf_t* buf); ++void zfStaStoreAsocRspIe(zdev_t* dev, zbuf_t* buf); ++void zfStaChannelManagement(zdev_t* dev, u8_t scan); ++void zfIbssConnectNetwork(zdev_t* dev); ++void zfInfraConnectNetwork(zdev_t* dev); ++u8_t zfCheckAuthentication(zdev_t* dev, struct zsBssInfo* pBssInfo); ++u8_t zfChangeAdapterState(zdev_t* dev, u8_t newState); ++u16_t zfStaAddIeSsid(zdev_t* dev, zbuf_t* buf, u16_t offset); ++u16_t zfStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType); ++u16_t zfStaAddIeIbss(zdev_t* dev, zbuf_t* buf, u16_t offset); ++void zfStaStartConnect(zdev_t* dev, u8_t bIsSharedKey); ++u8_t zfStaIsConnected(zdev_t* dev); ++u8_t zfStaIsConnecting(zdev_t* dev); ++u8_t zfStaIsDisconnect(zdev_t* dev); ++void zfStaSendBeacon(zdev_t* dev); ++void zfSendNullData(zdev_t* dev, u8_t type); ++void zfSendPSPoll(zdev_t* dev); ++void zfSendBA(zdev_t* dev, u16_t start_seq, u8_t *bitmap); ++void zdRateInfoCountTx(zdev_t* dev, u16_t* macAddr); ++struct zsMicVar* zfStaGetRxMicKey(zdev_t* dev, zbuf_t* buf); ++struct zsMicVar* zfStaGetTxMicKey(zdev_t* dev, zbuf_t* buf); ++u16_t zfStaRxValidateFrame(zdev_t* dev, zbuf_t* buf); ++void zfStaMicFailureHandling(zdev_t* dev, zbuf_t* buf); ++u8_t zfStaBlockWlanScan(zdev_t* dev); ++void zfStaIbssPSCheckState(zdev_t* dev, zbuf_t* buf); ++u8_t zfStaIbssPSQueueData(zdev_t* dev, zbuf_t* buf); ++void zfStaIbssPSSend(zdev_t* dev); ++void zfStaResetStatus(zdev_t* dev, u8_t bInit); ++u16_t zfStaAddIeWmeInfo(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t qosInfo); ++void zfInitPartnerNotifyEvent(zdev_t* dev, zbuf_t* buf, struct zsPartnerNotifyEvent *event); ++void zfStaInitOppositeInfo(zdev_t* dev); ++void zfStaIbssMonitoring(zdev_t* dev, u8_t reset); ++struct zsBssInfo* zfStaFindBssInfo(zdev_t* dev, zbuf_t* buf, struct zsWlanProbeRspFrameHeader *pProbeRspHeader); ++u8_t zfStaInitBssInfo(zdev_t* dev, zbuf_t* buf, ++ struct zsWlanProbeRspFrameHeader *pProbeRspHeader, ++ struct zsBssInfo* pBssInfo, struct zsAdditionInfo* AddInfo, u8_t type); ++s8_t zfStaFindFreeOpposite(zdev_t* dev, u16_t *sa, int *pFoundIdx); ++s8_t zfStaFindOppositeByMACAddr(zdev_t* dev, u16_t *sa, u8_t *pFoundIdx); ++void zfStaRefreshBlockList(zdev_t* dev, u16_t flushFlag); ++void zfStaConnectFail(zdev_t* dev, u16_t reason, u16_t* bssid, u8_t weight); ++void zfStaGetTxRate(zdev_t* dev, u16_t* macAddr, u32_t* phyCtrl, ++ u16_t* rcProbingFlag); ++u16_t zfStaProcessAction(zdev_t* dev, zbuf_t* buf); ++struct zsTkipSeed* zfStaGetRxSeed(zdev_t* dev, zbuf_t* buf); ++#ifdef ZM_ENABLE_CENC ++/* CENC */ ++u16_t zfStaAddIeCenc(zdev_t* dev, zbuf_t* buf, u16_t offset); ++#endif //ZM_ENABLE_CENC ++void zfStaEnableSWEncryption(zdev_t *dev, u8_t value); ++void zfStaDisableSWEncryption(zdev_t *dev); ++u16_t zfComputeBssInfoWeightValue(zdev_t *dev, u8_t isBMode, u8_t isHT, u8_t isHT40, u8_t signalStrength); ++u16_t zfStaAddIbssAdditionalIE(zdev_t* dev, zbuf_t* buf, u16_t offset); ++ ++/* ctkip.c */ ++void zfTkipInit(u8_t* key, u8_t* ta, struct zsTkipSeed* pSeed, u8_t* initIv); ++void zfMicSetKey(u8_t* key, struct zsMicVar* pMic); ++void zfMicAppendByte(u8_t b, struct zsMicVar* pMic); ++void zfMicClear(struct zsMicVar* pMic); ++void zfMicAppendTxBuf(zdev_t* dev, zbuf_t* buf, u8_t* da, u8_t* sa, ++ u16_t removeLen, u8_t* mic); ++u8_t zfMicRxVerify(zdev_t* dev, zbuf_t* buf); ++void zfMicGetMic(u8_t* dst, struct zsMicVar* pMic); ++void zfCalTxMic(zdev_t *dev, zbuf_t *buf, u8_t *snap, u16_t snapLen, u16_t offset, u16_t *da, u16_t *sa, u8_t up, u8_t *mic); ++void zfTKIPEncrypt(zdev_t *dev, zbuf_t *buf, u8_t *snap, u16_t snapLen, u16_t offset, u8_t keyLen, u8_t* key, u32_t* icv); ++u16_t zfTKIPDecrypt(zdev_t *dev, zbuf_t *buf, u16_t offset, u8_t keyLen, u8_t* key); ++void zfTkipGetseeds(u16_t iv16, u8_t *RC4Key, struct zsTkipSeed *Seed); ++u8_t zfTkipPhase1KeyMix(u32_t iv32, struct zsTkipSeed* pSeed); ++u8_t zfTkipPhase2KeyMix(u16_t iv16, struct zsTkipSeed* pSeed); ++void zfWEPEncrypt(zdev_t *dev, zbuf_t *buf, u8_t *snap, u16_t snapLen, u16_t offset, u8_t keyLen, u8_t* WepKey, u8_t *iv); ++u16_t zfWEPDecrypt(zdev_t *dev, zbuf_t *buf, u16_t offset, u8_t keyLen, u8_t* WepKey, u8_t *iv); ++ ++/* ctxrx.c */ ++u16_t zfSend80211Frame(zdev_t* dev, zbuf_t* buf); ++void zfIsrPciTxComp(zdev_t* dev); ++void zfTxPciDmaStart(zdev_t* dev); ++u16_t zfTxPortControl(zdev_t* dev, zbuf_t* buf, u16_t port); ++u16_t zfTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, ++ u16_t bufType, u16_t flag); ++u16_t zfTxGenWlanTail(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t snaplen, ++ u16_t* mic); ++u16_t zfTxGenWlanSnap(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t* snaplen); ++void zfTxGetIpTosAndFrag(zdev_t* dev, zbuf_t* buf, u8_t* up, u16_t* fragOff); ++u16_t zfPutVtxq(zdev_t* dev, zbuf_t* buf); ++void zfPushVtxq(zdev_t* dev); ++u8_t zfIsVtxqEmpty(zdev_t* dev); ++u16_t zfGetSeqCtrl(zdev_t* dev, zbuf_t* buf, u16_t offset); ++u8_t zfGetFragNo(zdev_t* dev, zbuf_t* buf); ++void zfShowRxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset); ++void zfShowTxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset); ++void zfCoreRecv(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++u16_t zfPutVmmq(zdev_t* dev, zbuf_t* buf); ++void zfFlushVtxq(zdev_t* dev); ++void zfAgingDefragList(zdev_t* dev, u16_t flushFlag); ++ ++void zfLed100msCtrl(zdev_t* dev); ++void zf80211FrameSend(zdev_t* dev, zbuf_t* buf, u16_t* header, u16_t snapLen, ++ u16_t* da, u16_t* sa, u8_t up, u16_t headerLen, u16_t* snap, ++ u16_t* tail, u16_t tailLen, u16_t offset, u16_t bufType, ++ u8_t ac, u8_t keyIdx); ++void zfCheckIsRIFSFrame(zdev_t* dev, zbuf_t* buf, u16_t frameSubType); ++ ++/* queue.c */ ++struct zsQueue* zfQueueCreate(zdev_t* dev, u16_t size); ++void zfQueueDestroy(zdev_t* dev, struct zsQueue* q); ++u16_t zfQueuePutNcs(zdev_t* dev, struct zsQueue* q, zbuf_t* buf, u32_t tick); ++u16_t zfQueuePut(zdev_t* dev, struct zsQueue* q, zbuf_t* buf, u32_t tick); ++zbuf_t* zfQueueGet(zdev_t* dev, struct zsQueue* q); ++zbuf_t* zfQueueGetWithMac(zdev_t* dev, struct zsQueue* q, u8_t* addr, u8_t* mb); ++void zfQueueFlush(zdev_t* dev, struct zsQueue* q); ++void zfQueueAge(zdev_t* dev, struct zsQueue* q, u32_t tick, u32_t msAge); ++void zfQueueGenerateUapsdTim(zdev_t* dev, struct zsQueue* q, ++ u8_t* uniBitMap, u16_t* highestByte); ++ ++/* hpmain.c */ ++u16_t zfHpInit(zdev_t* dev, u32_t frequency); ++u16_t zfHpRelease(zdev_t* dev); ++void zfHpSetFrequencyEx(zdev_t* dev, u32_t frequency, u8_t bw40, ++ u8_t extOffset, u8_t initRF); ++u16_t zfHpStartRecv(zdev_t* dev); ++u16_t zfHpStopRecv(zdev_t* dev); ++u16_t zfHpResetKeyCache(zdev_t* dev); ++u16_t zfHpSetApStaMode(zdev_t* dev, u8_t mode); ++u16_t zfHpSetBssid(zdev_t* dev, u8_t* bssid); ++u16_t zfHpSetSnifferMode(zdev_t* dev, u16_t on); ++u8_t zfHpUpdateQosParameter(zdev_t* dev, u16_t* cwminTbl, u16_t* cwmaxTbl, ++ u16_t* aifsTbl, u16_t* txopTbl); ++void zfHpSetAtimWindow(zdev_t* dev, u16_t atimWin); ++void zfHpEnableBeacon(zdev_t* dev, u16_t mode, u16_t bcnInterval, u16_t dtim, u8_t enableAtim); ++void zfHpDisableBeacon(zdev_t* dev); ++void zfHpSetBasicRateSet(zdev_t* dev, u16_t bRateBasic, u16_t gRateBasic); ++void zfHpSetRTSCTSRate(zdev_t* dev, u32_t rate); ++void zfHpSetMacAddress(zdev_t* dev, u16_t* macAddr, u16_t macAddrId); ++u32_t zfHpGetMacAddress(zdev_t* dev); ++u32_t zfHpGetTransmitPower(zdev_t* dev); ++void zfHpSetMulticastList(zdev_t* dev, u8_t size, u8_t* pList, u8_t bAllMulticast); ++ ++u16_t zfHpRemoveKey(zdev_t* dev, u16_t user); ++u32_t zfHpSetKey(zdev_t* dev, u8_t user, u8_t keyId, u8_t type, ++ u16_t* mac, u32_t* key); ++//u32_t zfHpSetStaPairwiseKey(zdev_t* dev, u16_t* apMacAddr, u8_t type, ++// u32_t* key, u32_t* micKey); ++//u32_t zfHpSetStaGroupKey(zdev_t* dev, u16_t* apMacAddr, u8_t type, ++// u32_t* key, u32_t* micKey); ++u32_t zfHpSetApPairwiseKey(zdev_t* dev, u16_t* staMacAddr, u8_t type, ++ u32_t* key, u32_t* micKey, u16_t staAid); ++u32_t zfHpSetApGroupKey(zdev_t* dev, u16_t* apMacAddr, u8_t type, ++ u32_t* key, u32_t* micKey, u16_t vapId); ++u32_t zfHpSetDefaultKey(zdev_t* dev, u8_t keyId, u8_t type, u32_t* key, u32_t* micKey); ++u32_t zfHpSetPerUserKey(zdev_t* dev, u8_t user, u8_t keyId, u8_t* mac, u8_t type, u32_t* key, u32_t* micKey); ++ ++void zfHpSendBeacon(zdev_t* dev, zbuf_t* buf, u16_t len); ++u16_t zfHpGetPayloadLen(zdev_t* dev, ++ zbuf_t* buf, ++ u16_t len, ++ u16_t plcpHdrLen, ++ u32_t *rxMT, ++ u32_t *rxMCS, ++ u32_t *rxBW, ++ u32_t *rxSG ++ ); ++u32_t zfHpGetFreeTxdCount(zdev_t* dev); ++u32_t zfHpGetMaxTxdCount(zdev_t* dev); ++u16_t zfHpSend(zdev_t* dev, u16_t* header, u16_t headerLen, ++ u16_t* snap, u16_t snapLen, u16_t* tail, u16_t tailLen, zbuf_t* buf, ++ u16_t offset, u16_t bufType, u8_t ac, u8_t keyIdx); ++void zfHpGetRegulationTablefromRegionCode(zdev_t* dev, u16_t regionCode); ++void zfHpGetRegulationTablefromCountry(zdev_t* dev, u16_t CountryCode); ++u8_t zfHpGetRegulationTablefromISO(zdev_t* dev, u8_t *countryInfo, u8_t length); ++const char* zfHpGetisoNamefromregionCode(zdev_t* dev, u16_t regionCode); ++u16_t zfHpGetRegionCodeFromIsoName(zdev_t* dev, u8_t *countryIsoName); ++u8_t zfHpGetRegulatoryDomain(zdev_t* dev); ++void zfHpLedCtrl(zdev_t* dev, u16_t ledId, u8_t mode); ++u16_t zfHpResetTxRx(zdev_t* dev); ++u16_t zfHpDeleteAllowChannel(zdev_t* dev, u16_t freq); ++u16_t zfHpAddAllowChannel(zdev_t* dev, u16_t freq); ++u32_t zfHpCwmUpdate(zdev_t* dev); ++u32_t zfHpAniUpdate(zdev_t* dev); ++u32_t zfHpAniUpdateRssi(zdev_t* dev, u8_t rssi); ++void zfHpAniAttach(zdev_t* dev); ++void zfHpAniArPoll(zdev_t* dev, u32_t listenTime, u32_t phyCnt1, u32_t phyCnt2); ++void zfHpHeartBeat(zdev_t* dev); ++void zfHpPowerSaveSetState(zdev_t* dev, u8_t psState); ++void zfHpPowerSaveSetMode(zdev_t* dev, u8_t staMode, u8_t psMode, u16_t bcnInterval); ++u16_t zfHpIsDfsChannel(zdev_t* dev, u16_t freq); ++u16_t zfHpIsDfsChannelNCS(zdev_t* dev, u16_t freq); ++u16_t zfHpFindFirstNonDfsChannel(zdev_t* dev, u16_t aBand); ++u16_t zfHpIsAllowedChannel(zdev_t* dev, u16_t freq); ++void zfHpDisableDfsChannel(zdev_t* dev, u8_t disableFlag); ++void zfHpSetTTSIFSTime(zdev_t* dev, u8_t sifs_time); ++ ++void zfHpQueryMonHalRxInfo(zdev_t* dev, u8_t *monHalRxInfo); ++ ++void zfDumpSSID(u8_t length, u8_t *value); ++void zfHpSetAggPktNum(zdev_t* dev, u32_t num); ++void zfHpSetMPDUDensity(zdev_t* dev, u8_t density); ++void zfHpSetSlotTime(zdev_t* dev, u8_t type); ++void zfHpSetSlotTimeRegister(zdev_t* dev, u8_t type); ++void zfHpSetRifs(zdev_t* dev, u8_t ht_enable, u8_t ht2040, u8_t g_mode); ++void zfHpBeginSiteSurvey(zdev_t* dev, u8_t status); ++void zfHpFinishSiteSurvey(zdev_t* dev, u8_t status); ++u16_t zfHpEnableHwRetry(zdev_t* dev); ++u16_t zfHpDisableHwRetry(zdev_t* dev); ++void zfHpSWDecrypt(zdev_t* dev, u8_t enable); ++void zfHpSWEncrypt(zdev_t* dev, u8_t enable); ++u32_t zfHpCapability(zdev_t* dev); ++void zfHpSetRollCallTable(zdev_t* dev); ++u8_t zfHpregulatoryDomain(zdev_t* dev); ++u16_t zfStaAddIePowerCap(zdev_t* dev, zbuf_t* buf, u16_t offset); ++u8_t zfHpGetMaxTxPower(zdev_t* dev); ++u8_t zfHpGetMinTxPower(zdev_t* dev); ++u16_t zfStaAddIeSupportCh(zdev_t* dev, zbuf_t* buf, u16_t offset); ++void zfHpEnableRifs(zdev_t* dev, u8_t mode24g, u8_t modeHt, u8_t modeHt2040); ++void zfHpDisableRifs(zdev_t* dev); ++u16_t zfHpUsbReset(zdev_t* dev); ++ ++ ++#endif /* #ifndef _CFUNC_H */ +--- /dev/null ++++ b/drivers/staging/otus/80211core/chb.c +@@ -0,0 +1,200 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : hb.c */ ++/* */ ++/* Abstract */ ++/* This module contains house keeping and timer functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++ ++/* Called by wrapper every 10 msec */ ++void zfiHeartBeat(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->tick++; ++ ++#if 0 ++ /* => every 1.28 seconds */ ++ if (wd->cwm.cw_enable && ((wd->tick & 0x7f) == 0x3f)) ++ { ++ zfHpCwmUpdate(dev); ++ } ++#endif ++ /* => every 2.56 seconds */ ++ if ((wd->tick & 0xff) == 0) ++ { ++ zfAgingDefragList(dev, 1); ++ } ++ ++ /* Watch Dog */ ++ //zfWatchDog(); ++ ++ /* LED Control (per 100ms) */ ++ if ((wd->tick % 10) == 9) ++ { ++ zfLed100msCtrl(dev); ++#ifdef ZM_ENABLE_BA_RATECTRL ++ if (!wd->modeMDKEnable) ++ { ++ zfiDbgReadTally(dev); ++ } ++#endif ++ } ++ ++#ifdef ZM_ENABLE_REWRITE_BEACON_START_ADDRESS ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ if ( zfStaIsConnected(dev) ) ++ { ++ zfReWriteBeaconStartAddress(dev); ++ } ++ } ++#endif ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ if ( zfStaIsConnected(dev) ) ++ { ++ wd->tickIbssReceiveBeacon++; // add 10ms ++ ++ if ( (wd->sta.ibssSiteSurveyStatus == 2) && ++ (wd->tickIbssReceiveBeacon == 300) && ++ (wd->sta.ibssReceiveBeaconCount < 3) ) ++ { ++ zm_debug_msg0("It is happen!!! No error message"); ++ zfReSetCurrentFrequency(dev); ++ } ++ } ++ } ++ ++ if(wd->sta.ReceivedPacketRateCounter <= 0) ++ { ++ wd->sta.ReceivedPktRatePerSecond = wd->sta.TotalNumberOfReceivePackets; ++ //zm_debug_msg1("Receive Packet Per Second = ", wd->sta.ReceivedPktRatePerSecond); ++ if (wd->sta.TotalNumberOfReceivePackets != 0) ++ { ++ wd->sta.avgSizeOfReceivePackets = wd->sta.TotalNumberOfReceiveBytes/wd->sta.TotalNumberOfReceivePackets; ++ } ++ else ++ { ++ wd->sta.avgSizeOfReceivePackets = 640; ++ } ++ wd->sta.TotalNumberOfReceivePackets = 0; ++ wd->sta.TotalNumberOfReceiveBytes = 0; ++ wd->sta.ReceivedPacketRateCounter = 100; /*for another 1s*/ ++ } ++ else ++ { ++ wd->sta.ReceivedPacketRateCounter--; ++ } ++ ++ /* => every 1.28 seconds */ ++ if((wd->tick & 0x7f) == 0x3f) ++ { ++ if( wd->sta.NonNAPcount > 0) ++ { ++ wd->sta.RTSInAGGMode = TRUE; ++ wd->sta.NonNAPcount = 0; ++ } ++ else ++ { ++ wd->sta.RTSInAGGMode = FALSE; ++ } ++ } ++ ++ ++ ++ /* Maintain management time tick */ ++ zfMmApTimeTick(dev); ++ zfMmStaTimeTick(dev); ++ ++ //zfPhyCrTuning(dev); ++ ++ //zfTxPowerControl(dev); ++ zfHpHeartBeat(dev); ++ ++} ++ ++ ++void zfDumpBssList(zdev_t* dev) ++{ ++ struct zsBssInfo* pBssInfo; ++ u8_t str[33]; ++ u8_t i, j; ++ u32_t addr1, addr2; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zm_debug_msg0("***** Bss scan result *****"); ++ zmw_enter_critical_section(dev); ++ ++ pBssInfo = wd->sta.bssList.head; ++ ++ for( i=0; ista.bssList.bssCount; i++ ) ++ { ++ if ( i ) ++ { ++ zm_debug_msg0("---------------------------"); ++ } ++ ++ zm_debug_msg1("BSS #", i); ++ for(j=0; jssid[1]; j++) ++ { ++ str[j] = pBssInfo->ssid[2+j]; ++ } ++ str[pBssInfo->ssid[1]] = 0; ++ zm_debug_msg0("SSID = "); ++ zm_debug_msg0(str); ++ ++ addr1 = (pBssInfo->bssid[0] << 16) + (pBssInfo->bssid[1] << 8 ) ++ + pBssInfo->bssid[2]; ++ addr2 = (pBssInfo->bssid[3] << 16) + (pBssInfo->bssid[4] << 8 ) ++ + pBssInfo->bssid[5]; ++ zm_debug_msg2("Bssid = ", addr1); ++ zm_debug_msg2(" ", addr2); ++ zm_debug_msg1("frequency = ", pBssInfo->frequency); ++ zm_debug_msg1("security type = ", pBssInfo->securityType); ++ zm_debug_msg1("WME = ", pBssInfo->wmeSupport); ++ zm_debug_msg1("beacon interval = ", pBssInfo->beaconInterval[0] ++ + (pBssInfo->beaconInterval[1] << 8)); ++ zm_debug_msg1("capability = ", pBssInfo->capability[0] ++ + (pBssInfo->capability[1] << 8)); ++ if ( pBssInfo->supportedRates[1] > 0 ) ++ { ++ for( j=0; jsupportedRates[1]; j++ ) ++ { ++ zm_debug_msg2("supported rates = ", pBssInfo->supportedRates[2+j]); ++ } ++ } ++ ++ for( j=0; jextSupportedRates[1]; j++ ) ++ { ++ zm_debug_msg2("ext supported rates = ", pBssInfo->extSupportedRates[2+j]); ++ } ++ ++ pBssInfo = pBssInfo->next; ++ } ++ zmw_leave_critical_section(dev); ++ ++ zm_debug_msg0("***************************"); ++} ++ +--- /dev/null ++++ b/drivers/staging/otus/80211core/cic.c +@@ -0,0 +1,496 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++#include "ratectrl.h" ++ ++ ++void zfUpdateBssid(zdev_t* dev, u8_t* bssid) ++{ ++ ++ zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ //zmw_enter_critical_section(dev); ++ wd->sta.bssid[0] = bssid[0] + (((u16_t) bssid[1]) << 8); ++ wd->sta.bssid[1] = bssid[2] + (((u16_t) bssid[3]) << 8); ++ wd->sta.bssid[2] = bssid[4] + (((u16_t) bssid[5]) << 8); ++ //zmw_leave_critical_section(dev); ++ ++ zfHpSetBssid(dev, bssid); ++ ++} ++ ++/************************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfResetSupportRate */ ++/* Reset support rate to default value. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* type: ZM_DEFAULT_SUPPORT_RATE_ZERO => reset to zero */ ++/* ZM_DEFAULT_SUPPORT_RATE_DISCONNECT => reset to disconnect status */ ++/* ZM_DEFAULT_SUPPORT_RATE_IBSS_B => reset to IBSS creator(b mode) */ ++/* ZM_DEFAULT_SUPPORT_RATE_IBSS_AG => reset to IBSS creator(a/g mode) */ ++/* */ ++/************************************************************************************/ ++void zfResetSupportRate(zdev_t* dev, u8_t type) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch(type) ++ { ++ case ZM_DEFAULT_SUPPORT_RATE_ZERO: ++ wd->bRate = 0; ++ wd->bRateBasic = 0; ++ wd->gRate = 0; ++ wd->gRateBasic = 0; ++ break; ++ case ZM_DEFAULT_SUPPORT_RATE_DISCONNECT: ++ wd->bRate = 0xf; ++ wd->bRateBasic = 0xf; ++ wd->gRate = 0xff; ++ wd->gRateBasic = 0x15; ++ break; ++ case ZM_DEFAULT_SUPPORT_RATE_IBSS_B: ++ wd->bRate = 0xf; ++ wd->bRateBasic = 0xf; ++ wd->gRate = 0; ++ wd->gRateBasic = 0; ++ break; ++ case ZM_DEFAULT_SUPPORT_RATE_IBSS_AG: ++ wd->bRate = 0xf; ++ wd->bRateBasic = 0xf; ++ wd->gRate = 0xff; ++ wd->gRateBasic = 0; ++ break; ++ } ++} ++ ++void zfUpdateSupportRate(zdev_t* dev, u8_t* rateArray) ++{ ++ u8_t bRate=0, bRateBasic=0, gRate=0, gRateBasic=0; ++ u8_t length = rateArray[1]; ++ u8_t i, j; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for(i=2; ibRate |= bRate; ++ wd->bRateBasic |= bRateBasic; ++ wd->gRate |= gRate; ++ wd->gRateBasic |= gRateBasic; ++} ++ ++u8_t zfIsGOnlyMode(zdev_t* dev, u16_t frequency, u8_t* rateArray) ++{ ++ u8_t length = rateArray[1]; ++ u8_t i, j; ++ ++ if (frequency < 3000) { ++ for (i = 2; i < length+2; i++) { ++ for (j = 0; j < 8; j++) { ++ if ( ((rateArray[i] & 0x7f) == zg11gRateTbl[j]) ++ && (rateArray[i] & 0x80) ) { ++ return 1; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++void zfGatherBMode(zdev_t* dev, u8_t* rateArray, u8_t* extrateArray) ++{ ++ u8_t gatherBMode[ZM_MAX_SUPP_RATES_IE_SIZE + 2]; ++ u8_t i, j, k = 0; ++ u8_t length; ++ ++ gatherBMode[0] = ZM_WLAN_EID_SUPPORT_RATE; ++ gatherBMode[1] = 0; ++ ++ length = rateArray[1]; ++ for (i = 2; i < length+2; i++) { ++ for (j = 0; j < 4; j++) { ++ if ( (rateArray[i] & 0x7f) == zg11bRateTbl[j] ) { ++ gatherBMode[2+k] = rateArray[i]; ++ ++ gatherBMode[1]++; ++ k++; ++ } ++ } ++ } ++ ++ length = extrateArray[1]; ++ for (i = 2; i < length+2; i++) { ++ for (j = 0; j < 4; j++) { ++ if ( (extrateArray[i] & 0x7f) == zg11bRateTbl[j] ) { ++ gatherBMode[2+k] = extrateArray[i]; ++ ++ gatherBMode[1]++; ++ k++; ++ } ++ } ++ } ++ ++ extrateArray[0] = extrateArray[1] = 0; ++ zfMemoryCopy(rateArray, gatherBMode, gatherBMode[1]+2); ++} ++ ++u16_t zfGetRandomNumber(zdev_t* dev, u16_t initValue) ++{ ++#if 0 ++ /* Compiler/Linker error on Linux */ ++ if ( initValue ) ++ { ++ srand(initValue); ++ } ++ ++ return ((u16_t)rand()); ++#endif ++ return 0; ++} ++ ++u8_t zfPSDeviceSleep(zdev_t* dev) ++{ ++ //zmw_get_wlan_dev(dev); ++ ++ /* enter PS mode */ ++ ++ return 0; ++} ++ ++u8_t zcOfdmPhyCrtlToRate[] = ++{ ++ /* 0x8=48M, 0x9=24M, 0xa=12M, 0xb=6M, 0xc=54M, 0xd=36M, 0xe=18M, 0xf=9M */ ++ 10, 8, 6, 4, 11, 9, 7, 5 ++}; ++ ++u8_t zfPhyCtrlToRate(u32_t phyCtrl) ++{ ++ u32_t mt, mcs, sg; ++ u8_t rate = 0; ++ ++ mt = phyCtrl & 0x3; ++ mcs = (phyCtrl>>18) & 0x3f; ++ sg = (phyCtrl>>31) & 0x1; ++ ++ if ((mt == 0) && (mcs <=3)) ++ { ++ rate = (u8_t)mcs; ++ } ++ else if ((mt == 1) && (mcs >= 0x8) && (mcs <= 0xf)) ++ { ++ rate = zcOfdmPhyCrtlToRate[mcs-8]; ++ } ++ else if ((mt == 2) && (mcs <= 15)) ++ { ++ rate = (u8_t)mcs + 12; ++ if(sg) { ++ if (mcs != 7) ++ { ++ rate = (u8_t)mcs + 12 + 2; ++ } ++ else //MCS7-SG ++ { ++ rate = (u8_t)30; ++ } ++ } ++ } ++ ++ return rate; ++} ++ ++ ++void zfCoreEvent(zdev_t* dev, u16_t event, u8_t* rsp) ++{ ++ u16_t i; ++ zbuf_t* psBuf; ++ u8_t moreData; ++ u8_t vap = 0; ++ u8_t peerIdx; ++ s8_t res; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ++ if (event == 0) //Beacon Event ++ { ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ zfApSendBeacon(dev); ++ ++ if (wd->CurrentDtimCount == 0) ++ { ++ /* TODO : Send queued broadcast frames at BC/MC event */ ++ do ++ { ++ psBuf = NULL; ++ moreData = 0; ++ zmw_enter_critical_section(dev); ++ if (wd->ap.bcmcTail[vap] != wd->ap.bcmcHead[vap]) ++ { ++ //zm_msg0_mm(ZM_LV_0, "Send BCMC frames"); ++ psBuf = wd->ap.bcmcArray[vap][wd->ap.bcmcHead[vap]]; ++ wd->ap.bcmcHead[vap] = (wd->ap.bcmcHead[vap] + 1) ++ & (ZM_BCMC_ARRAY_SIZE - 1); ++ if (wd->ap.bcmcTail[vap] != wd->ap.bcmcHead[vap]) ++ { ++ moreData = 0x20; ++ } ++ } ++ zmw_leave_critical_section(dev); ++ if (psBuf != NULL) ++ { ++ /* TODO : config moreData bit */ ++ zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, ++ moreData); ++ } ++ } while(psBuf != NULL); ++ ++ } ++ } ++ else ++ { ++ /* STA mode */ ++ if ( wd->sta.powerSaveMode > ZM_STA_PS_NONE ) ++ { ++ /* send queued packets */ ++ for(i=0; ista.staPSDataCount; i++) ++ { ++ zfTxSendEth(dev, wd->sta.staPSDataQueue[i], 0, ++ ZM_EXTERNAL_ALLOC_BUF, 0); ++ } ++ ++ wd->sta.staPSDataCount = 0; ++ } ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ zfStaSendBeacon(dev); ++ wd->sta.ibssAtimTimer = ZM_BIT_15 | wd->sta.atimWindow; ++ } ++ ++ zfPowerSavingMgrPreTBTTInterrupt(dev); ++ } ++ } //if (event == 0) //Beacon Event ++ else if (event == 1) //Retry completed event ++ { ++ u32_t retryRate; ++ ++ retryRate = (u32_t)(rsp[6]) + (((u32_t)(rsp[7]))<<8) ++ + (((u32_t)(rsp[8]))<<16) + (((u32_t)(rsp[9]))<<24); ++ /* Degrade Tx Rate */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ zmw_enter_critical_section(dev); ++ if ((i=zfApFindSta(dev, (u16_t*)rsp)) != 0xffff) ++ { ++ zfRateCtrlTxFailEvent(dev, &wd->ap.staTable[i].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate)); ++ } ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, (u16_t*)rsp, &peerIdx); ++ if ( res == 0 ) ++ { ++ zfRateCtrlTxFailEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate)); ++ } ++ zmw_leave_critical_section(dev); ++ } ++ } //else if (event == 1) //Retry completed event ++ else if (event == 2) //Tx Fail event ++ { ++ u32_t retryRate; ++ ++ retryRate = (u32_t)(rsp[6]) + (((u32_t)(rsp[7]))<<8) ++ + (((u32_t)(rsp[8]))<<16) + (((u32_t)(rsp[9]))<<24); ++ ++ /* Degrade Tx Rate */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ zmw_enter_critical_section(dev); ++ if ((i=zfApFindSta(dev, (u16_t*)rsp)) != 0xffff) ++ { ++ zfRateCtrlTxFailEvent(dev, &wd->ap.staTable[i].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate)); ++ } ++ zmw_leave_critical_section(dev); ++ ++ zfApSendFailure(dev, rsp); ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, (u16_t*)rsp, &peerIdx); ++ if ( res == 0 ) ++ { ++ zfRateCtrlTxFailEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, 0,(u32_t)zfPhyCtrlToRate(retryRate)); ++ } ++ zmw_leave_critical_section(dev); ++ } ++ } //else if (event == 2) //Tx Fail event ++ else if (event == 3) //Tx Comp event ++ { ++ u32_t retryRate; ++ ++ retryRate = (u32_t)(rsp[6]) + (((u32_t)(rsp[7]))<<8) ++ + (((u32_t)(rsp[8]))<<16) + (((u32_t)(rsp[9]))<<24); ++ ++ /* TODO : Tx completed, used for rate control probing */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ zmw_enter_critical_section(dev); ++ if ((i=zfApFindSta(dev, (u16_t*)rsp)) != 0xffff) ++ { ++ zfRateCtrlTxSuccessEvent(dev, &wd->ap.staTable[i].rcCell, zfPhyCtrlToRate(retryRate)); ++ } ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, (u16_t*)rsp, &peerIdx); ++ if ( res == 0 ) ++ { ++ zfRateCtrlTxSuccessEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, zfPhyCtrlToRate(retryRate)); ++ } ++ zmw_leave_critical_section(dev); ++ } ++ } //else if (event == 3) //Tx Comp event ++ else if (event == 4) //BA failed count ++ { ++ u32_t fail; ++ u32_t rate; ++ peerIdx = 0; ++ ++ fail=((u32_t*)rsp)[0] & 0xFFFF; ++ rate=((u32_t*)rsp)[0] >> 16; ++ ++ if (rate > 15) { ++ rate = (rate & 0xF) + 12 + 2; ++ } ++ else { ++ rate = rate + 12; ++ } ++ ++ zmw_enter_critical_section(dev); ++ zfRateCtrlTxFailEvent(dev, &wd->sta.oppositeInfo[peerIdx].rcCell, (u8_t)rate, fail); ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++void zfBeaconCfgInterrupt(zdev_t* dev, u8_t* rsp) ++{ ++ u32_t txBeaconCounter; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ txBeaconCounter = *((u32_t *)rsp); ++ if ( wd->sta.beaconTxCnt != txBeaconCounter ) ++ { ++ wd->sta.txBeaconInd = 1; ++ ++ zmw_enter_critical_section(dev); ++ wd->tickIbssSendBeacon = 0; ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ wd->sta.txBeaconInd = 0; ++ } ++ ++#ifdef ZM_ENABLE_IBSS_DELAYED_JOIN_INDICATION ++ if ( wd->sta.txBeaconInd && wd->sta.ibssDelayedInd ) ++ { ++ if (wd->zfcbIbssPartnerNotify != NULL) ++ { ++ wd->zfcbIbssPartnerNotify(dev, 1, &wd->sta.ibssDelayedIndEvent); ++ } ++ ++ wd->sta.ibssDelayedInd = 0; ++ } ++#endif ++ ++ wd->sta.beaconTxCnt = txBeaconCounter; ++ ++ // Need to check if the time is expired after ATIM window?? ++ ++ // Check if we have buffered any data for those stations that are sleeping ++ // If it's true, then transmitting ATIM pkt to notify them ++ ++#ifdef ZM_ENABLE_IBSS_PS ++ // TODO: Need to check if the station receive our ATIM pkt??? ++ zfStaIbssPSSend(dev); ++ ++ if ( wd->sta.atimWindow == 0 ) ++ { ++ // We won't receive the end of ATIM isr so we fake it ++ zfPowerSavingMgrAtimWinExpired(dev); ++ } ++#endif ++ } ++} ++ ++void zfEndOfAtimWindowInterrupt(zdev_t* dev) ++{ ++#ifdef ZM_ENABLE_IBSS_PS ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ // Transmit any queued pkt for the stations!! ++ zfPowerSavingMgrAtimWinExpired(dev); ++ } ++#endif ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cinit.c +@@ -0,0 +1,1911 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : init.c */ ++/* */ ++/* Abstract */ ++/* This module contains init functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#include "../hal/hpreg.h" ++ ++extern const u8_t zcUpToAc[8]; ++ ++u16_t zcIndextoRateBG[16] = {1000, 2000, 5500, 11000, 0, 0, 0, 0, 48000, ++ 24000, 12000, 6000, 54000, 36000, 18000, 9000}; ++u32_t zcIndextoRateN20L[16] = {6500, 13000, 19500, 26000, 39000, 52000, 58500, ++ 65000, 13000, 26000, 39000, 52000, 78000, 104000, ++ 117000, 130000}; ++u32_t zcIndextoRateN20S[16] = {7200, 14400, 21700, 28900, 43300, 57800, 65000, ++ 72200, 14400, 28900, 43300, 57800, 86700, 115600, ++ 130000, 144400}; ++u32_t zcIndextoRateN40L[16] = {13500, 27000, 40500, 54000, 81000, 108000, 121500, ++ 135000, 27000, 54000, 81000, 108000, 162000, 216000, ++ 243000, 270000}; ++u32_t zcIndextoRateN40S[16] = {15000, 30000, 45000, 60000, 90000, 120000, 135000, ++ 150000, 30000, 60000, 90000, 120000, 180000, 240000, ++ 270000, 300000}; ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfTxGenWlanHeader */ ++/* Generate WLAN MAC header and LLC header. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer pointer */ ++/* id : Index of TxD */ ++/* port : WLAN port */ ++/* */ ++/* OUTPUTS */ ++/* length of removed Ethernet header */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.5 */ ++/* */ ++/************************************************************************/ ++u16_t zfTxGenWlanHeader(zdev_t* dev, zbuf_t* buf, u16_t* header, u16_t seq, ++ u8_t flag, u16_t plusLen, u16_t minusLen, u16_t port, ++ u16_t* da, u16_t* sa, u8_t up, u16_t *micLen, ++ u16_t* snap, u16_t snapLen, struct aggControl *aggControl) ++{ ++ ++ u16_t len; ++ u16_t macCtrl; ++ u32_t phyCtrl; ++ u16_t hlen = 16; ++ u16_t icvLen = 0; ++ u16_t wdsPortId; ++ u16_t vap = 0; ++ u16_t mcs = 0; ++ u16_t mt = 0; ++ u8_t qosType; ++ u8_t b1, b2; ++ u16_t wdsPort; ++ u8_t encExemptionActionType; ++ u16_t rateProbingFlag = 0; ++ u8_t tkipFrameOffset = 0; ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ u8_t res, peerIdx; ++ u8_t userIdx=0; ++ u16_t *iv16; ++ u32_t *iv32; ++#endif ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Generate WLAN header */ ++ /* Frame control */ ++ header[4] = 0x0008 | (flag<<8); ++ /* Duration */ ++ header[5] = 0x0000; ++ ++ if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ /* ToDS bit */ ++ header[4] |= 0x0100; ++ ++ /*Sometimes we wake up to tx/rx but AP still think we are sleeping, so still need to set this bit*/ ++ if ( zfPowerSavingMgrIsSleeping(dev) || wd->sta.psMgr.tempWakeUp == 1 ) ++ { ++ header[4] |= 0x1000; ++ } ++ ++ /* Address 1 = BSSID */ ++ header[6] = wd->sta.bssid[0]; ++ header[7] = wd->sta.bssid[1]; ++ header[8] = wd->sta.bssid[2]; ++ /* Address 3 = DA */ ++ header[12] = da[0]; ++ header[13] = da[1]; ++ header[14] = da[2]; ++ } ++ else if (wd->wlanMode == ZM_MODE_PSEUDO) ++ { ++ /* Address 1 = DA */ ++ header[6] = da[0]; ++ header[7] = da[1]; ++ header[8] = da[2]; ++ /* Address 3 = 00:00:00:00:00:00 */ ++ header[12] = 0; ++ header[13] = 0; ++ header[14] = 0; ++ ++ /* PSEUDO test : WDS */ ++ if (wd->enableWDS) ++ { ++ /* ToDS and FromDS bit */ ++ header[4] |= 0x0300; ++ ++ /* Address 4 = SA */ ++ header[16] = 0; ++ header[17] = 0; ++ header[18] = 0; ++ ++ hlen = 19; ++ } ++ } ++ else if (wd->wlanMode == ZM_MODE_IBSS) ++ { ++ /* Address 1 = DA */ ++ header[6] = da[0]; ++ header[7] = da[1]; ++ header[8] = da[2]; ++ /* Address 3 = BSSID */ ++ header[12] = wd->sta.bssid[0]; ++ header[13] = wd->sta.bssid[1]; ++ header[14] = wd->sta.bssid[2]; ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, da, &peerIdx); ++ if(res == 0) // Find opposite in our OppositeInfo Structure ! ++ { ++ userIdx = peerIdx; ++ } ++ zmw_leave_critical_section(dev); ++#endif ++ } ++ else if (wd->wlanMode == ZM_MODE_AP) ++ { ++ if (port < 0x20) ++ /* AP mode */ ++ { ++ /* FromDS bit */ ++ header[4] |= 0x0200; ++ ++ /* Address 1 = DA */ ++ header[6] = da[0]; ++ header[7] = da[1]; ++ header[8] = da[2]; ++ /* Address 3 = SA */ ++ header[12] = sa[0]; ++ header[13] = sa[1]; ++ header[14] = sa[2]; ++ ++ if (port < ZM_MAX_AP_SUPPORT) ++ { ++ vap = port; ++ header[14] += (vap<<8); ++ } ++ } ++ else ++ /* WDS port */ ++ { ++ /* ToDS and FromDS bit */ ++ header[4] |= 0x0300; ++ ++ wdsPortId = port - 0x20; ++ ++ /* Address 1 = RA */ ++ header[6] = wd->ap.wds.macAddr[wdsPortId][0]; ++ header[7] = wd->ap.wds.macAddr[wdsPortId][1]; ++ header[8] = wd->ap.wds.macAddr[wdsPortId][2]; ++ /* Address 3 = DA */ ++ header[12] = da[0]; ++ header[13] = da[1]; ++ header[14] = da[2]; ++ /* Address 4 = SA */ ++ header[16] = sa[0]; ++ header[17] = sa[1]; ++ header[18] = sa[2]; ++ ++ hlen = 19; ++ } ++ } /* else if (wd->wlanMode == ZM_MODE_AP) */ ++ ++ /* Address 2 = TA */ ++ header[9] = wd->macAddr[0]; ++ header[10] = wd->macAddr[1]; ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ header[11] = wd->macAddr[2]; //Multiple SSID ++#else ++ header[11] = wd->macAddr[2] + (vap<<8); //VAP ++#endif ++ ++ if ( (wd->wlanMode == ZM_MODE_IBSS) && (wd->XLinkMode) ) ++ { ++ header[9] = sa[0]; ++ header[10] = sa[1]; ++ header[11] = sa[2]; ++ } ++ ++ /* Sequence Control */ ++ header[15] = seq; ++ ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ zfApGetStaTxRateAndQosType(dev, da, &phyCtrl, &qosType, &rateProbingFlag); ++ mt = (u16_t)(phyCtrl & 0x3); ++ mcs = (u16_t)((phyCtrl >> 16) & 0x3f); ++#if 1 ++ //zfApGetStaQosType(dev, da, &qosType); ++ ++ /* if DA == WME STA */ ++ if (qosType == 1) ++ { ++ /* QoS data */ ++ header[4] |= 0x0080; ++ ++ /* QoS Control */ ++ header[hlen] = up; ++ hlen += 1; ++ } ++#endif ++ } ++ ++#if 0 ++ //AGG Test Code ++ if (header[6] == 0x8000) ++ { ++ /* QoS data */ ++ header[4] |= 0x0080; ++ ++ /* QoS Control */ ++ header[hlen] = 0; ++ hlen += 1; ++ } ++#endif ++ ++ if (wd->wlanMode == ZM_MODE_AP) { ++ /* Todo: rate control here for qos field */ ++ } ++ else { ++ /* Rate control */ ++ zfStaGetTxRate(dev, da, &phyCtrl, &rateProbingFlag); ++ mt = (u16_t)(phyCtrl & 0x3); ++ mcs = (u16_t)((phyCtrl >> 16) & 0x3f); ++ } ++ ++ if (wd->txMCS != 0xff) ++ { ++ /* fixed rate */ ++ phyCtrl = ((u32_t)wd->txMCS<<16) + wd->txMT; ++ mcs = wd->txMCS; ++ mt = wd->txMT; ++ } ++ ++ if (wd->enableAggregation) ++ { ++ /* force enable aggregation */ ++ if (wd->enableAggregation==2 && !(header[6]&0x1)) ++ { ++ /* QoS data */ ++ header[4] |= 0x0080; ++ ++ /* QoS Control */ ++ header[hlen] = 0; ++ hlen += 1; ++ } ++ /* if wd->enableAggregation=1 => force disable */ ++ /* if wd->enableAggregation=0 => auto */ ++ } ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ /* ++ * aggregation control ++ */ ++ ++ /* ++ * QoS data ++ */ ++ if (wd->wlanMode == ZM_MODE_AP) { ++ if (aggControl && mt == 2) { ++ if (wd->enableAggregation==0 && !(header[6]&0x1)) ++ { ++ header[4] |= 0x0080; ++ ++ /* ++ * QoS Control ++ */ ++ header[hlen] = 0; ++ hlen += 1; ++ } ++ } ++ } ++#endif ++ ++ // MSDU Length ++ len = zfwBufGetSize(dev, buf); ++ ++ /* Generate control setting */ ++ /* Backoff, Non-Burst and hardware duration */ ++ macCtrl = 0x208; ++ ++ /* ACK */ ++ if ((header[6] & 0x1) == 0x1) ++ { ++ /* multicast frame : Set NO-ACK bit */ ++ macCtrl |= 0x4; ++ } ++ else ++ { ++ /* unicast frame */ ++ #if 0 ++ // Enable RTS according to MPDU Lengths ( not MSDU Lengths ) ++ if (len >= wd->rtsThreshold) ++ { ++ /* Enable RTS */ ++ macCtrl |= 1; ++ } ++ #endif ++ } ++ /* VAP test code */ ++ //macCtrl |= 0x4; ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ u8_t encryType; ++ u16_t iv16; ++ u32_t iv32; ++ ++ /* Check whether this is a multicast frame */ ++ if ((header[6] & 0x1) == 0x1) ++ { ++ /* multicast frame */ ++ if (wd->ap.encryMode[vap] == ZM_TKIP) ++ { ++ wd->ap.iv16[vap]++; ++ ++ if(wd->ap.iv16[vap] == 0) ++ { ++ wd->ap.iv32[vap]++; ++ } ++ ++ b1 = (u8_t) (wd->ap.iv16[vap] >> 8); ++ b2 = (b1 | 0x20) & 0x7f; ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ b1 = (u8_t) wd->ap.iv16[vap]; ++ b2 = 0x20 | (wd->ap.bcKeyIndex[vap] << 6); ++ header[hlen+1] = ((u16_t)b2 << 8) + b1; ++ header[hlen+2] = (u16_t) wd->ap.iv32[vap]; ++ header[hlen+3] = (u16_t) (wd->ap.iv32[vap] >> 16); ++ ++ //macCtrl |= 0x80; ++ macCtrl |= 0x40; ++ icvLen = 4; ++ ++ /* set hardware MIC */ ++ if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) ++ { ++ macCtrl |= 0x100; ++ plusLen += 8; ++ *micLen = 8; ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ } ++ else if (wd->ap.encryMode[vap] == ZM_AES) ++ { ++ wd->ap.iv16[vap]++; ++ ++ if(wd->ap.iv16[vap] == 0) ++ { ++ wd->ap.iv32[vap]++; ++ } ++ ++ b1 = (u8_t) wd->ap.iv16[vap]; ++ b2 = (u8_t) (wd->ap.iv16[vap] >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ header[hlen+1] = 0x2000 | (wd->ap.bcKeyIndex[vap] << 14); ++ header[hlen+2] = (u16_t) (wd->ap.iv32[vap]); ++ header[hlen+3] = (u16_t) (wd->ap.iv32[vap] >> 16); ++ ++ macCtrl |= 0xc0; ++ icvLen = 8; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ } ++ #ifdef ZM_ENABLE_CENC ++ else if (wd->ap.encryMode[vap] == ZM_CENC) ++ { ++ //u32_t txiv[4]; ++ ++ wd->ap.txiv[vap][0]++; ++ ++ if (wd->ap.txiv[vap][0] == 0) ++ { ++ wd->ap.txiv[vap][1]++; ++ } ++ ++ if (wd->ap.txiv[vap][1] == 0) ++ { ++ wd->ap.txiv[vap][2]++; ++ } ++ ++ if (wd->ap.txiv[vap][2] == 0) ++ { ++ wd->ap.txiv[vap][3]++; ++ } ++ ++ if (wd->ap.txiv[vap][3] == 0) ++ { ++ wd->ap.txiv[vap][0] = 0; ++ wd->ap.txiv[vap][1] = 0; ++ wd->ap.txiv[vap][2] = 0; ++ } ++ ++ header[hlen] = (wd->ap.bcKeyIndex[vap] & 0x0001); /* For Key Id and reserved field */ ++ header[hlen+1] = (u16_t)wd->ap.txiv[vap][0]; ++ header[hlen+2] = (u16_t)(wd->ap.txiv[vap][0] >> 16); ++ header[hlen+3] = (u16_t)wd->ap.txiv[vap][1]; ++ header[hlen+4] = (u16_t)(wd->ap.txiv[vap][1] >> 16); ++ header[hlen+5] = (u16_t)wd->ap.txiv[vap][2]; ++ header[hlen+6] = (u16_t)(wd->ap.txiv[vap][2] >> 16); ++ header[hlen+7] = (u16_t)wd->ap.txiv[vap][3]; ++ header[hlen+8] = (u16_t)(wd->ap.txiv[vap][3] >> 16); ++ ++ macCtrl |= 0x80; ++ icvLen = 16; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 9; ++ } ++ #endif //ZM_ENABLE_CENC ++ } ++ else ++ { ++ /* Get STA's encryption type */ ++ zfApGetStaEncryType(dev, da, &encryType); ++ ++ if (encryType == ZM_TKIP) ++ { ++ /* Get iv16 and iv32 */ ++ zfApGetStaWpaIv(dev, da, &iv16, &iv32); ++ ++ iv16++; ++ if (iv16 == 0) ++ { ++ iv32++; ++ } ++ ++ b1 = (u8_t) (iv16 >> 8); ++ b2 = (b1 | 0x20) & 0x7f; ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ b1 = (u8_t) iv16; ++ b2 = 0x20; ++ header[hlen+1] = ((u16_t)b2 << 8) + b1; ++ header[hlen+2] = (u16_t) iv32; ++ header[hlen+3] = (u16_t) (iv32 >> 16); ++ ++ //macCtrl |= 0x80; ++ macCtrl |= 0x40; ++ icvLen = 4; ++ ++ /* set hardware MIC */ ++ if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) ++ { ++ macCtrl |= 0x100; ++ plusLen += 8; ++ *micLen = 8; ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ ++ /* Set iv16 and iv32 */ ++ zfApSetStaWpaIv(dev, da, iv16, iv32); ++ } ++ else if (encryType == ZM_AES) ++ { ++ /* Get iv16 and iv32 */ ++ zfApGetStaWpaIv(dev, da, &iv16, &iv32); ++ ++ iv16++; ++ if (iv16 == 0) ++ { ++ iv32++; ++ } ++ ++ b1 = (u8_t) iv16; ++ b2 = (u8_t) (iv16 >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ header[hlen+1] = 0x2000; ++ header[hlen+2] = (u16_t) (iv32); ++ header[hlen+3] = (u16_t) (iv32 >> 16); ++ ++ macCtrl |= 0xc0; ++ icvLen = 8; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ ++ /* Set iv16 and iv32 */ ++ zfApSetStaWpaIv(dev, da, iv16, iv32); ++ } ++ #ifdef ZM_ENABLE_CENC ++ else if (encryType == ZM_CENC) ++ { ++ u32_t txiv[4]; ++ u8_t keyIdx; ++ ++ /* Get CENC TxIV */ ++ zfApGetStaCencIvAndKeyIdx(dev, da, txiv, &keyIdx); ++ ++ txiv[0] += 2; ++ ++ if (txiv[0] == 0 || txiv[0] == 1) ++ { ++ txiv[1]++; ++ } ++ ++ if (txiv[1] == 0) ++ { ++ txiv[2]++; ++ } ++ ++ if (txiv[2] == 0) ++ { ++ txiv[3]++; ++ } ++ ++ if (txiv[3] == 0) ++ { ++ txiv[0] = 0; ++ txiv[1] = 0; ++ txiv[2] = 0; ++ } ++ ++ header[hlen] = (keyIdx & 0x0001); /* For Key Id and reserved field */ ++ header[hlen+1] = (u16_t)txiv[0]; ++ header[hlen+2] = (u16_t)(txiv[0] >> 16); ++ header[hlen+3] = (u16_t)txiv[1]; ++ header[hlen+4] = (u16_t)(txiv[1] >> 16); ++ header[hlen+5] = (u16_t)txiv[2]; ++ header[hlen+6] = (u16_t)(txiv[2] >> 16); ++ header[hlen+7] = (u16_t)txiv[3]; ++ header[hlen+8] = (u16_t)(txiv[3] >> 16); ++ ++ macCtrl |= 0x80; ++ icvLen = 16; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 9; ++ ++ /* Set CENC IV */ ++ zfApSetStaCencIv(dev, da, txiv); ++ } ++ #endif //ZM_ENABLE_CENC ++ } ++ ++ /* protection mode */ ++ if (wd->ap.protectionMode == 1) ++ { ++ /* Enable Self-CTS */ ++ macCtrl &= 0xFFFC; ++ macCtrl |= 2; ++ } ++ ++ /* Rate Control */ ++ if (port < 0x20) ++ { ++ /* AP */ ++ /* IV */ ++ if ((wd->ap.encryMode[vap] == ZM_WEP64) || ++ (wd->ap.encryMode[vap] == ZM_WEP128) || ++ (wd->ap.encryMode[vap] == ZM_WEP256)) ++ { ++ header[4] |= 0x4000; ++ header[hlen] = 0x0; //IV ++ header[hlen+1] = wd->ap.bcKeyIndex[vap] << 14; //IV with Keyid--CWYang(m) ++ hlen += 2; ++ icvLen = 4; ++ macCtrl |= 0x40; ++ } ++ } ++ else ++ { ++ /* WDS */ ++ ++ /* TODO : Fixed rate to 54M */ ++ phyCtrl = 0xc0001; //PHY control L ++ ++ /* WDS port checking */ ++ if ((wdsPort = (port - 0x20)) >= ZM_MAX_WDS_SUPPORT) ++ { ++ wdsPort = 0; ++ } ++ ++ #if 1 ++ /* IV */ ++ switch (wd->ap.wds.encryMode[wdsPort]) ++ { ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++ header[4] |= 0x4000; ++ header[hlen] = 0x0; //IV ++ header[hlen+1] = wd->ap.bcKeyIndex[vap] << 14; //IV with Keyid ++ hlen += 2; ++ icvLen = 4; ++ macCtrl |= 0x40; ++ break; ++ ++ case ZM_TKIP: ++ wd->sta.iv16++; ++ ++ if ( wd->sta.iv16 == 0 ) ++ { ++ wd->sta.iv32++; ++ } ++ ++ b1 = (u8_t) (wd->sta.iv16 >> 8); ++ b2 = (b1 | 0x20) & 0x7f; ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = 0x20; ++ header[hlen+1] = ((u16_t)b2 << 8) + b1; ++ header[hlen+2] = (u16_t) wd->sta.iv32; ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ ++ //macCtrl |= 0x80; ++ macCtrl |= 0x40; ++ icvLen = 4; ++ ++ /* set hardware MIC */ ++ if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) ++ { ++ macCtrl |= 0x100; ++ plusLen += 8; ++ *micLen = 8; ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ break; ++ ++ case ZM_AES: ++ wd->sta.iv16++; ++ if ( wd->sta.iv16 == 0 ) ++ { ++ wd->sta.iv32++; ++ } ++ ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = (u8_t) (wd->sta.iv16 >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ header[hlen+1] = 0x2000; ++ header[hlen+2] = (u16_t) (wd->sta.iv32); ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ ++ macCtrl |= 0xc0; /* Set to AES in control setting */ ++ icvLen = 8; /* MIC */ ++ ++ header[4] |= 0x4000; /* Set WEP bit in wlan header */ ++ hlen += 4; /* plus IV length */ ++ break; ++ }/* end of switch */ ++ #endif ++ } ++ } ++ else /* wd->wlanMode != ZM_MODE_AP */ ++ { ++ encExemptionActionType = zfwGetPktEncExemptionActionType(dev, buf); ++ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ #if 1 ++ /* if WME AP */ ++ if (wd->sta.wmeConnected != 0) ++ { ++ /* QoS data */ ++ header[4] |= 0x0080; ++ ++ /* QoS Control */ ++ header[hlen] = up; ++ hlen += 1; ++ } ++ #endif ++ ++ if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) ++ { ++ if ( wd->sta.authMode < ZM_AUTH_MODE_WPA ) ++ { /* non-WPA */ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED ) ++ { ++ if ( (wd->sta.encryMode == ZM_WEP64)|| ++ (wd->sta.encryMode == ZM_WEP128)|| ++ (wd->sta.encryMode == ZM_WEP256) ) ++ { ++ header[4] |= 0x4000; ++ header[hlen] = 0x0; //IV ++ header[hlen+1] = 0x0; //IV ++ header[hlen+1] |= (((u16_t) wd->sta.keyId) << 14); ++ hlen += 2; ++ icvLen = 4; ++ ++ /* For Software WEP */ ++ if ((wd->sta.SWEncryptEnable & ZM_SW_WEP_ENCRY_EN) != 0) ++ { ++ u8_t keyLen = 5; ++ u8_t iv[3]; ++ ++ iv[0] = 0x0; ++ iv[1] = 0x0; ++ iv[2] = 0x0; ++ ++ if (wd->sta.SWEncryMode[wd->sta.keyId] == ZM_WEP64) ++ { ++ keyLen = 5; ++ } ++ else if (wd->sta.SWEncryMode[wd->sta.keyId] == ZM_WEP128) ++ { ++ keyLen = 13; ++ } ++ else if (wd->sta.SWEncryMode[wd->sta.keyId] == ZM_WEP256) ++ { ++ keyLen = 29; ++ } ++ ++ zfWEPEncrypt(dev, buf, (u8_t*) snap, snapLen, minusLen, keyLen, ++ wd->sta.wepKey[wd->sta.keyId], iv); ++ } ++ else ++ { ++ macCtrl |= 0x40; ++ } ++ } ++ } ++ } ++ else ++ { /* WPA */ ++ if ( wd->sta.wpaState >= ZM_STA_WPA_STATE_PK_OK ) ++ { ++ wd->sta.iv16++; ++ if ( wd->sta.iv16 == 0 ) ++ { ++ wd->sta.iv32++; ++ } ++ ++ /* set encryption mode */ ++ if ( wd->sta.encryMode == ZM_TKIP ) ++ { ++ b1 = (u8_t) (wd->sta.iv16 >> 8); ++ b2 = (b1 | 0x20) & 0x7f; ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = 0x20; ++ ++ // header[hlen+1] = (((u16_t) wd->sta.keyId) << 14) | (((u16_t)b2 << 8) + b1); ++ // STA in infrastructure mode should use keyId = 0 to transmit unicast ! ++ header[hlen+1] = (((u16_t)b2 << 8) + b1); ++ header[hlen+2] = (u16_t) wd->sta.iv32; ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ ++ /* If software encryption enable */ ++ if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_ENCRY_EN) == 0) ++ { ++ //macCtrl |= 0x80; ++ /* TKIP same to WEP */ ++ macCtrl |= 0x40; ++ icvLen = 4; ++ ++ /* set hardware MIC */ ++ if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) ++ { ++ macCtrl |= 0x100; ++ plusLen += 8; ++ *micLen = 8; ++ } ++ } ++ else ++ { ++ u8_t mic[8]; ++ u16_t offset; ++ u32_t icv; ++ u8_t RC4Key[16]; ++ ++ /* TODO: Remove the criticial section here. */ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ /* Calculate MIC */ ++ zfCalTxMic(dev, buf, (u8_t *)snap, snapLen, minusLen, da, sa, up, mic); ++ ++ offset = zfwBufGetSize(dev, buf); ++ ++ /* Append MIC to the buffer */ ++ zfCopyToIntTxBuffer(dev, buf, mic, offset, 8); ++ zfwBufSetSize(dev, buf, offset+8); ++ zmw_leave_critical_section(dev); ++ ++ /* TKIP Key Mixing */ ++ zfTkipPhase1KeyMix(wd->sta.iv32, &wd->sta.txSeed); ++ zfTkipPhase2KeyMix(wd->sta.iv16, &wd->sta.txSeed); ++ zfTkipGetseeds(wd->sta.iv16, RC4Key, &wd->sta.txSeed); ++ ++ /* Encrypt Data */ ++ zfTKIPEncrypt(dev, buf, (u8_t *)snap, snapLen, minusLen, 16, RC4Key, &icv); ++ ++ icvLen = 4; ++ len += 8; ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ } ++ else if ( wd->sta.encryMode == ZM_AES ) ++ { ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = (u8_t) (wd->sta.iv16 >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ // header[hlen+1] = (((u16_t) wd->sta.keyId) << 14) | (0x2000); ++ // STA in infrastructure mode should use keyId = 0 to transmit unicast ! ++ header[hlen+1] = 0x2000; ++ header[hlen+2] = (u16_t) (wd->sta.iv32); ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ ++ macCtrl |= 0xc0; ++ icvLen = 8; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ } ++ #ifdef ZM_ENABLE_CENC ++ else if ( wd->sta.encryMode == ZM_CENC ) ++ { ++ /* Accumlate the PN sequence */ ++ wd->sta.txiv[0] += 2; ++ ++ if (wd->sta.txiv[0] == 0 || wd->sta.txiv[0] == 1) ++ { ++ wd->sta.txiv[1]++; ++ } ++ ++ if (wd->sta.txiv[1] == 0) ++ { ++ wd->sta.txiv[2]++; ++ } ++ ++ if (wd->sta.txiv[2] == 0) ++ { ++ wd->sta.txiv[3]++; ++ } ++ ++ if (wd->sta.txiv[3] == 0) ++ { ++ wd->sta.txiv[0] = 0; ++ wd->sta.txiv[1] = 0; ++ wd->sta.txiv[2] = 0; ++ } ++ ++ header[hlen] = (wd->sta.cencKeyId & 0x0001); /* For Key Id and reserved field */ ++ header[hlen+1] = (u16_t) wd->sta.txiv[0]; ++ header[hlen+2] = (u16_t) (wd->sta.txiv[0] >> 16); ++ header[hlen+3] = (u16_t) wd->sta.txiv[1]; ++ header[hlen+4] = (u16_t) (wd->sta.txiv[1] >> 16); ++ header[hlen+5] = (u16_t) wd->sta.txiv[2]; ++ header[hlen+6] = (u16_t) (wd->sta.txiv[2] >> 16); ++ header[hlen+7] = (u16_t) wd->sta.txiv[3]; ++ header[hlen+8] = (u16_t) (wd->sta.txiv[3] >> 16); ++ ++ macCtrl |= 0x80; ++ icvLen = 16; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 9; ++ } ++ #endif //ZM_ENABLE_CENC ++ } ++ } ++ } // if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) ++ } /* if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE ) */ ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) ++ { ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if( wd->sta.oppositeInfo[userIdx].wpaState >= ZM_STA_WPA_STATE_PK_OK || wd->sta.wpaState >= ZM_STA_WPA_STATE_PK_OK) ++ { ++ int isUnicast = 1 ; ++ ++ if((da[0]& 0x1)) ++ { ++ isUnicast = 0 ; // Not unicast , is broadcast ++ } ++ ++ if( wd->sta.ibssWpa2Psk == 1 ) ++ { /* The IV order is not the same between unicast and broadcast ! */ ++ if ( isUnicast ) ++ { ++ iv16 = &wd->sta.oppositeInfo[userIdx].iv16; ++ iv32 = &wd->sta.oppositeInfo[userIdx].iv32; ++ } ++ else ++ { ++ iv16 = &wd->sta.iv16; ++ iv32 = &wd->sta.iv32; ++ } ++ } ++ else ++ { ++ iv16 = &wd->sta.iv16; ++ iv32 = &wd->sta.iv32; ++ } ++ ++ (*iv16)++; ++ if ( *iv16 == 0 ) ++ { ++ *iv32++; ++ } ++ ++ if ( wd->sta.oppositeInfo[userIdx].encryMode == ZM_AES || wd->sta.encryMode == ZM_AES) ++ { ++ //printk("Station encryption mode is AES-CCMP\n") ; ++ b1 = (u8_t) (*iv16); ++ b2 = (u8_t) ((*iv16) >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ ++ if ( isUnicast ) ++ { ++ header[hlen+1] = 0x2000; ++ } ++ else ++ { ++ header[hlen+1] = 0x2000 | (((u16_t) wd->sta.keyId) << 14); ++ } ++ ++ header[hlen+2] = (u16_t) (*iv32); ++ header[hlen+3] = (u16_t) ((*iv32) >> 16); ++ macCtrl |= 0xc0; ++ icvLen = 8; /* MIC */ ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ } ++ else if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED) ++ { ++ if ( (wd->sta.encryMode == ZM_WEP64)|| ++ (wd->sta.encryMode == ZM_WEP128)|| ++ (wd->sta.encryMode == ZM_WEP256) ) ++ { ++ header[4] |= 0x4000; ++ header[hlen] = 0x0; //IV ++ header[hlen+1] = 0x0; //IV ++ header[hlen+1] |= (((u16_t) wd->sta.keyId) << 14); ++ hlen += 2; ++ icvLen = 4; ++ macCtrl |= 0x40; ++ } ++ } ++#else ++ /* ----- 20070405 add by Mxzeng ----- */ ++ if( wd->sta.wpaState >= ZM_STA_WPA_STATE_PK_OK ) ++ { ++ int isUnicast = 1 ; ++ ++ if((da[0]& 0x1)) ++ { ++ isUnicast = 0 ; // Not unicast , is broadcast ++ } ++ ++ wd->sta.iv16++; ++ if ( wd->sta.iv16 == 0 ) ++ { ++ wd->sta.iv32++; ++ } ++ ++ if ( wd->sta.encryMode == ZM_AES ) ++ { ++ //printk("Station encryption mode is AES-CCMP\n") ; ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = (u8_t) (wd->sta.iv16 >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ ++ if ( isUnicast ) ++ { ++ header[hlen+1] = 0x2000; ++ } ++ else ++ { ++ header[hlen+1] = 0x2000 | (((u16_t) wd->sta.keyId) << 14); ++ } ++ ++ header[hlen+2] = (u16_t) (wd->sta.iv32); ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ macCtrl |= 0xc0; ++ icvLen = 8; /* MIC */ ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ } ++ else if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED) ++ { ++ if ( (wd->sta.encryMode == ZM_WEP64)|| ++ (wd->sta.encryMode == ZM_WEP128)|| ++ (wd->sta.encryMode == ZM_WEP256) ) ++ { ++ header[4] |= 0x4000; ++ header[hlen] = 0x0; //IV ++ header[hlen+1] = 0x0; //IV ++ header[hlen+1] |= (((u16_t) wd->sta.keyId) << 14); ++ hlen += 2; ++ icvLen = 4; ++ macCtrl |= 0x40; ++ } ++ } ++#endif ++ } // End if ( encExemptionActionType == ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION ) ++ } // End if ( wd->wlanMode == ZM_MODE_IBSS ) ++ else if ( wd->wlanMode == ZM_MODE_PSEUDO ) ++ { ++ switch (wd->sta.encryMode) ++ { ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++ header[4] |= 0x4000; ++ header[hlen] = 0x0; //IV ++ header[hlen+1] = 0x0; //IV ++ hlen += 2; ++ icvLen = 4; ++ macCtrl |= 0x40; ++ break; ++ ++ case ZM_TKIP: ++ { ++ wd->sta.iv16++; ++ if ( wd->sta.iv16 == 0 ) ++ { ++ wd->sta.iv32++; ++ } ++ ++ b1 = (u8_t) (wd->sta.iv16 >> 8); ++ b2 = (b1 | 0x20) & 0x7f; ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = 0x20; ++ header[hlen+1] = ((u16_t)b2 << 8) + b1; ++ header[hlen+2] = (u16_t) wd->sta.iv32; ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ ++ //macCtrl |= 0x80; ++ macCtrl |= 0x40; ++ icvLen = 4; ++ ++ /* set hardware MIC */ ++ if ( (!(seq & 0xf))&&(!(flag & 0x4)) ) ++ { ++ macCtrl |= 0x100; ++ plusLen += 8; ++ *micLen = 8; ++ } ++ ++ header[4] |= 0x4000; ++ hlen += 4; ++ }/* end of PSEUDO TKIP */ ++ break; ++ ++ case ZM_AES: ++ { ++ wd->sta.iv16++; ++ if ( wd->sta.iv16 == 0 ) ++ { ++ wd->sta.iv32++; ++ } ++ ++ b1 = (u8_t) wd->sta.iv16; ++ b2 = (u8_t) (wd->sta.iv16 >> 8); ++ header[hlen] = ((u16_t)b2 << 8) + b1; ++ header[hlen+1] = 0x2000; ++ header[hlen+2] = (u16_t) (wd->sta.iv32); ++ header[hlen+3] = (u16_t) (wd->sta.iv32 >> 16); ++ macCtrl |= 0xc0; ++ icvLen = 8; /* MIC */ ++ header[4] |= 0x4000; ++ hlen += 4; ++ }/* end of PSEUDO AES */ ++ break; ++ ++ #ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++ /* Accumlate the PN sequence */ ++ wd->sta.txiv[0] += 2; ++ ++ if (wd->sta.txiv[0] == 0 || wd->sta.txiv[0] == 1) ++ { ++ wd->sta.txiv[1]++; ++ } ++ ++ if (wd->sta.txiv[1] == 0) ++ { ++ wd->sta.txiv[2]++; ++ } ++ ++ if (wd->sta.txiv[2] == 0) ++ { ++ wd->sta.txiv[3]++; ++ } ++ ++ if (wd->sta.txiv[3] == 0) ++ { ++ wd->sta.txiv[0] = 0; ++ wd->sta.txiv[1] = 0; ++ wd->sta.txiv[2] = 0; ++ } ++ ++ header[hlen] = 0; ++ header[hlen+1] = (u16_t) wd->sta.txiv[0]; ++ header[hlen+2] = (u16_t) (wd->sta.txiv[0] >> 16); ++ header[hlen+3] = (u16_t) wd->sta.txiv[1]; ++ header[hlen+4] = (u16_t) (wd->sta.txiv[1] >> 16); ++ header[hlen+5] = (u16_t) wd->sta.txiv[2]; ++ header[hlen+6] = (u16_t) (wd->sta.txiv[2] >> 16); ++ header[hlen+7] = (u16_t) wd->sta.txiv[3]; ++ header[hlen+8] = (u16_t) (wd->sta.txiv[3] >> 16); ++ ++ macCtrl |= 0x80; ++ icvLen = 16; /* MIC */ ++ ++ header[4] |= 0x4000; ++ hlen += 9; ++ break; ++ #endif //ZM_ENABLE_CENC ++ }/* end of switch */ ++ } ++ ++ /* Generate control setting */ ++ ++ /* protection mode */ ++ if (wd->enableProtectionMode) ++ { ++ if (wd->enableProtectionMode==2) ++ { ++ /* Force enable protection: self cts */ ++ macCtrl &= 0xFFFC; ++ macCtrl |= 2; ++ } ++ /* if wd->enableProtectionMode=1 => force disable */ ++ /* if wd->enableProtectionMode=0 => auto */ ++ } ++ else ++ { ++ ++ /* protection mode */ ++ if (wd->sta.bProtectionMode == TRUE) ++ { ++ /* Enable Self-CTS */ ++ macCtrl &= 0xFFFC; ++ macCtrl |= 2; ++ } ++ } ++ ++ } ++ ++ if (wd->txMCS != 0xff) ++ { ++ /* fixed rate */ ++ phyCtrl = ((u32_t)wd->txMCS<<16) + wd->txMT; ++ mcs = wd->txMCS; ++ mt = wd->txMT; ++ } ++ ++ if (mt == 2) ++ { ++#if 0 ++ /* HT PT: 0 Mixed mode 1 Green field */ ++ if (wd->sta.preambleTypeHT == ZM_PREAMBLE_TYPE_GREEN_FIELD) ++ { ++ phyCtrl |= 0x4; /* Bit 2 */ ++ } ++#endif ++ /* Bandwidth */ ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) ++ { ++ phyCtrl |= (0x80<<16); /* BIT 23 */ ++ } ++#if 0 ++ /* STBC */ ++ if (wd->sta.htCtrlSTBC<=0x3) ++ { ++ phyCtrl |= (wd->sta.htCtrlSTBC<<28); /* BIT 23 */ ++ } ++#endif ++ /* Short GI */ ++ if(wd->sta.htCtrlSG) ++ { ++ phyCtrl |= (0x8000<<16); /* BIT 31 */ ++ } ++ ++ /* TA */ ++ if ( ((mcs >=0x8) && (mcs<=0xf)) || (wd->sta.htCtrlSTBC) ) ++ { ++ phyCtrl |= 0x1800; /* BIT 11 12 */ ++ } ++ } ++ else if(mt == 1) ++ { ++ #if 0 ++ //bug that cause OFDM rate become duplicate legacy rate ++ /* Bandwidth */ ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) ++ { ++ phyCtrl |= (0x80<<16); /* BIT 23 */ ++ mt = 3; /* duplicate legacy */ ++ phyCtrl |= mt; ++ } ++ #endif ++ } ++ else if(mt == 0) ++ { ++ /* CCK PT: Legcy Preamble: 1 long preamble 2 short preamble */ ++ if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_SHORT) ++ { ++ //phyCtrl |= 0x4; /* BIT 2 */ ++ } ++ } ++ ++ /* TA */ ++ if (wd->sta.defaultTA) ++ { ++ phyCtrl |= 0x1000; ++ } ++ else ++ { ++ phyCtrl |= 0x0800; ++ } ++ ++ //Get CurrentTxRate -- CWYang(+) ++ if ((mt == 0) || (mt == 1)) //B,G Rate ++ { ++ if (mcs < 16) ++ { ++ wd->CurrentTxRateKbps = zcIndextoRateBG[mcs]; ++ } ++ } ++ else if (mt == 2) ++ { ++ if (mcs < 16) ++ { ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) ++ { ++ if((phyCtrl & 0x80000000) != 0) ++ { ++ /* Short GI 40 MHz MIMO Rate */ ++ wd->CurrentTxRateKbps = zcIndextoRateN40S[mcs]; ++ } ++ else ++ { ++ /* Long GI 40 MHz MIMO Rate */ ++ wd->CurrentTxRateKbps = zcIndextoRateN40L[mcs]; ++ } ++ } ++ else ++ { ++ if((phyCtrl & 0x80000000) != 0) ++ { ++ /* Short GI 20 MHz MIMO Rate */ ++ wd->CurrentTxRateKbps = zcIndextoRateN20S[mcs]; ++ } ++ else ++ { ++ /* Long GI 20 MHz MIMO Rate */ ++ wd->CurrentTxRateKbps = zcIndextoRateN20L[mcs]; ++ } ++ } ++ } ++ } ++ ++ //802.11 header(include IV) = (hlen<<1)-8 ++ //ethernet frame = len ++ //snap + mic = plusLen ++ //ethernet header = minusLen ++ //icv = icvLen ++ //crc32 = 4 ++ //length=802.11 header+snap+(ethernet frame-ethernet header)+mic+icv+crc32 ++ header[0] = ((hlen<<1)-8)+plusLen+(len-minusLen)+icvLen+4; //Length ++ ++ // header[0] : MPDU Lengths ++ if ((header[6] & 0x1) != 0x1) // Unicast Frame ++ { ++ if (header[0] >= wd->rtsThreshold) ++ { ++ /* Enable RTS */ ++ macCtrl |= 1; ++ } ++ } ++ ++ if ( wd->sta.encryMode == ZM_TKIP ) ++ tkipFrameOffset = 8; ++ ++ if( wd->sta.EnableHT != 1 ) ++ { // Aggregation should not be fragmented ! ++ if ( header[0] > ( wd->fragThreshold + tkipFrameOffset ) ) ++ { ++ return 0; // Need to be fragmented ! ! ++ } ++ } ++ ++ //if ( wd->sta.encryMode == ZM_TKIP ) ++ //{ ++ // zm_debug_msg1("ctrl length = ", header[0]); ++ //} ++ ++ //MAC control ++ if (rateProbingFlag != 0) ++ { ++ macCtrl |= 0x8000; ++ } ++ header[1] = macCtrl; ++ //PHY control L ++ header[2] = (u16_t) ((phyCtrl&0xffff) | 0x700 | (zcUpToAc[up&0x7]<<13)); ++ //PHY control H ++ header[3] = (u16_t) ((phyCtrl>>16) | 0x700); ++ ++ if (wd->enableAggregation) ++ { ++ /* force enable aggregation */ ++ if (wd->enableAggregation==2 && !(header[6]&0x1)) ++ { ++ if (((header[2] & 0x3) == 2)) ++ { ++ /* Enable aggregation */ ++ header[1] |= 0x20; ++ } ++ } ++ /* if wd->enableAggregation=1 => force disable */ ++ /* if wd->enableAggregation=0 => auto */ ++ } ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ if (wd->addbaComplete) { ++ #ifdef ZM_BYPASS_AGGR_SCHEDULING ++ if (!(header[6]&0x1) && !rateProbingFlag && (wd->enableAggregation != 1)) ++ { ++ if (((header[2] & 0x3) == 2)) ++ { ++ /* Unicast frame with HT rate => Enable aggregation */ ++ /* We only support software encryption in single packet mode */ ++ if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_ENCRY_EN) == 0 && ++ (wd->sta.SWEncryptEnable & ZM_SW_WEP_ENCRY_EN) == 0) ++ { ++ /* Set aggregation group bits per AC */ ++ header[1] |= (0x20 | (zcUpToAc[up&0x7]<<10)); ++ ++ //if (wd->sta.currentFrequency < 3000) ++ { ++ /* issue: -PB42 Enable RTS/CTS to prevent OWL Tx hang up */ ++ /* If this is Owl Ap, enable RTS/CTS protect */ ++ if ( (wd->sta.athOwlAp == 1) || (wd->sta.RTSInAGGMode == TRUE) ) ++ { ++ header[1] &= 0xfffc; ++ header[1] |= 0x1; ++ } ++ ++ /* Enable RIFS : workaround 854T RTS/CTS */ ++ /* Bit13 : TI enable RIFS */ ++ //header[1] |= 0x2000; ++ } ++ } ++ } ++ } ++ #else ++ /* ++ * aggregation ampduIndication control ++ */ ++ if (aggControl && aggControl->aggEnabled) { ++ if (wd->enableAggregation==0 && !(header[6]&0x1)) ++ { ++ if (((header[2] & 0x3) == 2)) ++ { ++ /* Enable aggregation */ ++ header[1] |= 0x20; ++ if (ZM_AGG_LAST_MPDU == aggControl->ampduIndication) ++ header[1] |= 0x4000; ++ } ++ else { ++ zm_debug_msg1("no aggr, header[2]&0x3 = ",header[2] & 0x3) ++ aggControl->aggEnabled = 0; ++ } ++ } ++ else { ++ zm_debug_msg1("no aggr, wd->enableAggregation = ", wd->enableAggregation); ++ zm_debug_msg1("no aggr, !header[6]&0x1 = ",!(header[6]&0x1)); ++ aggControl->aggEnabled = 0; ++ } ++ } ++ #endif ++ ++ #ifdef ZM_AGGR_BIT_ON ++ if (!(header[6]&0x1) && !rateProbingFlag) ++ { ++ if (((header[2] & 0x3) == 2)) ++ { ++ /* Unicast frame with HT rate => Enable aggregation */ ++ /* Set aggregation group bits per AC */ ++ header[1] |= (0x20 | (zcUpToAc[up&0x7]<<10)); ++ ++ //if (wd->sta.currentFrequency < 3000) ++ { ++ /* Enable RTS/CTS to prevent OWL Tx hang up */ ++ header[1] &= 0xfffc; ++ header[1] |= 0x1; ++ } ++ } ++ } ++ #endif ++ } ++#endif ++ ++ return (hlen<<1); ++} ++ ++ ++u16_t zfTxGenMmHeader(zdev_t* dev, u8_t frameType, u16_t* dst, ++ u16_t* header, u16_t len, zbuf_t* buf, u16_t vap, u8_t encrypt) ++{ ++ //u16_t bodyLen; ++ u8_t hlen = 32; // MAC ctrl + PHY ctrl + 802.11 MM header ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* Generate control setting */ ++ //bodyLen = zfwBufGetSize(dev, buf); ++ header[0] = 24+len+4; //Length ++ if ((dst[0] & 0x1) != 0) //Broadcast, multicast frames ++ { ++ header[1] = 0xc; //MAC control, backoff + noack ++ } ++ else ++ { ++ header[1] = 0x8; //MAC control, backoff + (ack) ++ } ++ /* Dualband Management frame tx Rate */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ if (wd->frequency < 3000) ++ { ++ /* CCK 1M */ ++ header[2] = 0x0f00; //PHY control L ++ header[3] = 0x0000; //PHY control H ++ } ++ else ++ { ++ /* CCK 6M */ ++ header[2] = 0x0f01; //PHY control L ++ header[3] = 0x000B; //PHY control H ++ } ++ } ++ else ++ { ++ if (wd->sta.currentFrequency < 3000) ++ { ++ /* CCK 2M */ ++ header[2] = 0x0f00; //PHY control L ++ header[3] = 0x0001; //PHY control H ++ } ++ else ++ { ++ /* CCK 6M */ ++ header[2] = 0x0f01; //PHY control L ++ header[3] = 0x000B; //PHY control H ++ } ++ } ++ /* Generate WLAN header */ ++ /* Frame control */ ++ header[4+0] = frameType; ++ /* Duration */ ++ header[4+1] = 0; ++ ++ if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ if ( frameType == ZM_WLAN_FRAME_TYPE_PROBEREQ ) ++ { ++ header[4+8] = 0xFFFF; ++ header[4+9] = 0xFFFF; ++ header[4+10] = 0xFFFF; ++ } ++ else if ( frameType == ZM_WLAN_FRAME_TYPE_BA ) { ++ /* do nothing */ ++ } ++ else ++ { ++ header[4+8] = wd->sta.bssid[0]; ++ header[4+9] = wd->sta.bssid[1]; ++ header[4+10] = wd->sta.bssid[2]; ++ } ++ } ++ else if (wd->wlanMode == ZM_MODE_PSEUDO) ++ { ++ /* Address 3 = 00:00:00:00:00:00 */ ++ header[4+8] = 0; ++ header[4+9] = 0; ++ header[4+10] = 0; ++ } ++ else if (wd->wlanMode == ZM_MODE_IBSS) ++ { ++ header[4+8] = wd->sta.bssid[0]; ++ header[4+9] = wd->sta.bssid[1]; ++ header[4+10] = wd->sta.bssid[2]; ++ ++ if ( frameType == ZM_WLAN_FRAME_TYPE_ATIM ) ++ { ++ /* put ATIM to queue 5th */ ++ //header[2] |= (ZM_BIT_13|ZM_BIT_14); ++ header[2] |= ZM_BIT_15; ++ } ++ } ++ else if (wd->wlanMode == ZM_MODE_AP) ++ { ++ /* Address 3 = BSSID */ ++ header[4+8] = wd->macAddr[0]; ++ header[4+9] = wd->macAddr[1]; ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ header[4+10] = wd->macAddr[2]; //Multiple SSID ++#else ++ header[4+10] = wd->macAddr[2] + (vap<<8); //VAP ++#endif ++ //if in scan, must set address 3 to broadcast because of some ap would care this ++ //if ((wd->heartBeatNotification & ZM_BSSID_LIST_SCAN) ++ // == ZM_BSSID_LIST_SCAN) ++ //if FrameType is Probe Request, Address3 should be boradcast ++ if (frameType == ZM_WLAN_FRAME_TYPE_PROBEREQ) ++ { ++ header[4+8] = 0xFFFF; ++ header[4+9] = 0xFFFF; ++ header[4+10] = 0xFFFF; ++ } ++ } ++ ++ /* Address 1 = DA */ ++ header[4+2] = dst[0]; ++ header[4+3] = dst[1]; ++ header[4+4] = dst[2]; ++ ++ /* Address 2 = SA */ ++ header[4+5] = wd->macAddr[0]; ++ header[4+6] = wd->macAddr[1]; ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ header[4+7] = wd->macAddr[2]; //Multiple SSID ++#else ++ header[4+7] = wd->macAddr[2] + (vap<<8); //VAP ++#endif ++ } ++ else ++ { ++ header[4+7] = wd->macAddr[2]; ++ } ++ ++ /* Sequence Control */ ++ zmw_enter_critical_section(dev); ++ header[4+11] = ((wd->mmseq++)<<4); ++ zmw_leave_critical_section(dev); ++ ++ if( frameType == ZM_WLAN_FRAME_TYPE_QOS_NULL ) ++ { ++ /*Qos Control*/ ++ header[4+12] = 0x0; ++ hlen+=2; ++ header[0]+=2; ++ } ++ ++ if ( encrypt ) ++ { ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED ) ++ { ++ if ( (wd->sta.encryMode == ZM_WEP64)|| ++ (wd->sta.encryMode == ZM_WEP128)|| ++ (wd->sta.encryMode == ZM_WEP256) ) ++ { ++ header[4] |= 0x4000; ++ header[16] = 0x0; //IV ++ header[17] = 0x0; //IV ++ header[17] |= (((u16_t) wd->sta.keyId) << 14); ++ hlen += 4; ++ ++ header[0] += 8; // icvLen = 4; ++ header[1] |= 0x40; // enable encryption on macCtrl ++ } ++ } ++ } ++ ++ // Enable HW duration ++ if ( frameType != ZM_WLAN_FRAME_TYPE_PSPOLL ) ++ { ++ header[1] |= 0x200; ++ } ++ ++ return hlen; ++} ++ ++void zfInitMacApMode(zdev_t* dev) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zfHpEnableBeacon(dev, ZM_MODE_AP, (wd->beaconInterval/wd->ap.vapNumber), 1, 0); ++ ++ /* AP mode */ ++ zfHpSetApStaMode(dev, ZM_HAL_80211_MODE_AP); ++ ++ /* VAP test code */ ++ /* AP + VAP mode */ ++ if (wd->ap.vapNumber >= 2) ++ { ++ for (i=1; iap.apBitmap >> i) & 0x1) != 0) ++ { ++ u16_t mac[3]; ++ mac[0] = wd->macAddr[0]; ++ mac[1] = wd->macAddr[1]; ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ mac[2] = wd->macAddr[2]; //Multiple SSID ++#else ++ mac[2] = wd->macAddr[2] + (i<<8); //VAP ++#endif ++ zfHpSetMacAddress(dev, mac, i); ++ ++ } ++ } ++ } ++ ++ /* basic rate setting */ ++ zfHpSetBasicRateSet(dev, wd->bRateBasic, wd->gRateBasic); ++ ++ /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME AP default. */ ++ zfUpdateDefaultQosParameter(dev, 1); ++ ++ return; ++} ++ ++u16_t zfChGetNextChannel(zdev_t* dev, u16_t frequency, u8_t* pbPassive) ++{ ++ u8_t i; ++ u8_t bPassive; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Avoid NULL value */ ++ if ( pbPassive == NULL ) ++ { ++ pbPassive = &bPassive; ++ } ++ ++ for( i=0; iregulationTable.allowChannelCnt; i++ ) ++ { ++ if ( wd->regulationTable.allowChannel[i].channel == frequency ) ++ { ++ if ( i == (wd->regulationTable.allowChannelCnt-1) ) ++ { ++ i = 0; ++ } ++ else ++ { ++ i++; ++ } ++ ++ if ( wd->regulationTable.allowChannel[i].channelFlags ++ & ZM_REG_FLAG_CHANNEL_PASSIVE ) ++ { ++ *pbPassive = TRUE; ++ } ++ else ++ { ++ *pbPassive = FALSE; ++ } ++ ++ return wd->regulationTable.allowChannel[i].channel; ++ } ++ } ++ ++ return 0xffff; ++} ++ ++u16_t zfChGetFirstChannel(zdev_t* dev, u8_t* pbPassive) ++{ ++ u8_t bPassive; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Avoid NULL value */ ++ if ( pbPassive == NULL ) ++ { ++ pbPassive = &bPassive; ++ } ++ ++ if ( wd->regulationTable.allowChannel[0].channelFlags & ZM_REG_FLAG_CHANNEL_PASSIVE ) ++ { ++ *pbPassive = TRUE; ++ } ++ else ++ { ++ *pbPassive = FALSE; ++ } ++ ++ return wd->regulationTable.allowChannel[0].channel; ++} ++ ++u16_t zfChGetFirst2GhzChannel(zdev_t* dev) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for( i=0; iregulationTable.allowChannelCnt; i++ ) ++ { ++ if ( wd->regulationTable.allowChannel[i].channel < 3000 ) ++ { ++ /* find the first 2Ghz channel */ ++ return wd->regulationTable.allowChannel[i].channel; ++ } ++ } ++ ++ /* Can not find any 2Ghz channel */ ++ return 0; ++} ++ ++u16_t zfChGetFirst5GhzChannel(zdev_t* dev) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for( i=0; iregulationTable.allowChannelCnt; i++ ) ++ { ++ if ( wd->regulationTable.allowChannel[i].channel > 3000 ) ++ { ++ /* find the first 5Ghz channel */ ++ return wd->regulationTable.allowChannel[i].channel; ++ } ++ } ++ ++ /* Can not find any 5Ghz channel */ ++ return 0; ++} ++ ++u16_t zfChGetLastChannel(zdev_t* dev, u8_t* pbPassive) ++{ ++ u8_t bPassive; ++ u8_t ChannelIndex; ++ ++ zmw_get_wlan_dev(dev); ++ ++ ChannelIndex = wd->regulationTable.allowChannelCnt-1; ++ ++ /* Avoid NULL value */ ++ if ( pbPassive == NULL ) ++ { ++ pbPassive = &bPassive; ++ } ++ ++ if ( wd->regulationTable.allowChannel[ChannelIndex].channelFlags ++ & ZM_REG_FLAG_CHANNEL_PASSIVE ) ++ { ++ *pbPassive = TRUE; ++ } ++ else ++ { ++ *pbPassive = FALSE; ++ } ++ ++ return wd->regulationTable.allowChannel[ChannelIndex].channel; ++} ++ ++u16_t zfChGetLast5GhzChannel(zdev_t* dev) ++{ ++ u8_t i; ++ u16_t last5Ghzfrequency; ++ ++ zmw_get_wlan_dev(dev); ++ ++ last5Ghzfrequency = 0; ++ for( i=0; iregulationTable.allowChannelCnt; i++ ) ++ { ++ if ( wd->regulationTable.allowChannel[i].channel > 3000 ) ++ { ++ last5Ghzfrequency = wd->regulationTable.allowChannel[i].channel; ++ } ++ } ++ ++ return last5Ghzfrequency; ++} ++ ++/* freqBand = 0 => auto check */ ++/* = 1 => 2.4 GHz band */ ++/* = 2 => 5 GHz band */ ++u16_t zfChNumToFreq(zdev_t* dev, u8_t ch, u8_t freqBand) ++{ ++ u16_t freq = 0xffff; ++ ++ if ( freqBand == 0 ) ++ { ++ if (ch > 14) ++ { /* adapter is at 5 GHz band */ ++ freqBand = 2; ++ } ++ else ++ { ++ freqBand = 1; ++ } ++ } ++ ++ if ( freqBand == 2 ) ++ { /* the channel belongs to 5 GHz band */ ++ if ( (ch >= 184)&&(ch <= 196) ) ++ { ++ freq = 4000 + ch*5; ++ } ++ else ++ { ++ freq = 5000 + ch*5; ++ } ++ } ++ else ++ { /* the channel belongs to 2.4 GHz band */ ++ if ( ch == 14 ) ++ { ++ freq = ZM_CH_G_14; ++ } ++ else ++ { ++ freq = ZM_CH_G_1 + (ch-1)*5; ++ } ++ } ++ ++ return freq; ++} ++ ++u8_t zfChFreqToNum(u16_t freq, u8_t* pbIs5GBand) ++{ ++ u8_t ch; ++ u8_t Is5GBand; ++ ++ /* to avoid NULL value */ ++ if ( pbIs5GBand == NULL ) ++ { ++ pbIs5GBand = &Is5GBand; ++ } ++ ++ *pbIs5GBand = FALSE; ++ ++ if ( freq == ZM_CH_G_14 ) ++ { ++ ch = 14; ++ } ++ else if ( freq < 4000 ) ++ { ++ ch = (freq - ZM_CH_G_1) / 5 + 1; ++ } ++ else if ( freq < 5000 ) ++ { ++ ch = (freq - 4000) / 5; ++ *pbIs5GBand = TRUE; ++ } ++ else ++ { ++ ch = (freq - 5000) / 5; ++ *pbIs5GBand = TRUE; ++ } ++ ++ return ch; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cmmap.c +@@ -0,0 +1,2402 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : mm.c */ ++/* */ ++/* Abstract */ ++/* This module contains common functions for handle AP */ ++/* management frame. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#include "ratectrl.h" ++ ++extern const u8_t zcUpToAc[]; ++ ++void zfMmApTimeTick(zdev_t* dev) ++{ ++ u32_t now; ++ zmw_get_wlan_dev(dev); ++ ++ //zm_debug_msg1("wd->wlanMode : ", wd->wlanMode); ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ /* => every 1.28 seconds */ ++ /* AP : aging STA that does not active for wd->ap.staAgingTime */ ++ now = wd->tick & 0x7f; ++ if (now == 0x0) ++ { ++ zfApAgingSta(dev); ++ } ++ else if (now == 0x1f) ++ { ++ zfQueueAge(dev, wd->ap.uapsdQ, wd->tick, 10000); ++ } ++ /* AP : check (wd->ap.protectedObss) and (wd->ap.bStaAssociated) */ ++ /* to enable NonErp and Protection mode */ ++ else if (now == 0x3f) ++ { ++ //zfApProtctionMonitor(dev); ++ } ++ } ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApInitStaTbl */ ++/* Init AP's station table. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfApInitStaTbl(zdev_t* dev) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; iap.staTable[i].valid = 0; ++ wd->ap.staTable[i].state = 0; ++ wd->ap.staTable[i].addr[0] = 0; ++ wd->ap.staTable[i].addr[1] = 0; ++ wd->ap.staTable[i].addr[2] = 0; ++ wd->ap.staTable[i].time = 0; ++ wd->ap.staTable[i].vap = 0; ++ wd->ap.staTable[i].encryMode = ZM_NO_WEP; ++ } ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApFindSta */ ++/* Find a STA in station table. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : Target STA address */ ++/* */ ++/* OUTPUTS */ ++/* 0xffff : fail */ ++/* other : STA table index */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfApFindSta(zdev_t* dev, u16_t* addr) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; iap.staTable[i].valid == 1) ++ { ++ if ((wd->ap.staTable[i].addr[0] == addr[0]) ++ && (wd->ap.staTable[i].addr[1] == addr[1]) ++ && (wd->ap.staTable[i].addr[2] == addr[2])) ++ { ++ return i; ++ } ++ } ++ } ++ return 0xffff; ++} ++ ++u16_t zfApGetSTAInfo(zdev_t* dev, u16_t* addr, u16_t* state, u8_t* vap) ++{ ++ u16_t id; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ *vap = wd->ap.staTable[id].vap; ++ *state = wd->ap.staTable[id++].state; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return id; ++} ++ ++ ++void zfApGetStaQosType(zdev_t* dev, u16_t* addr, u8_t* qosType) ++{ ++ u16_t id; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ *qosType = wd->ap.staTable[id].qosType; ++ } ++ else ++ { ++ *qosType = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return; ++} ++ ++void zfApGetStaTxRateAndQosType(zdev_t* dev, u16_t* addr, u32_t* phyCtrl, ++ u8_t* qosType, u16_t* rcProbingFlag) ++{ ++ u16_t id; ++ u8_t rate; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->ap.staTable[id].rcCell, rcProbingFlag); ++#ifdef ZM_AP_DEBUG ++ //rate = 15; ++#endif ++ *phyCtrl = zcRateToPhyCtrl[rate]; ++ *qosType = wd->ap.staTable[id].qosType; ++ } ++ else ++ { ++ if (wd->frequency < 3000) ++ { ++ /* CCK 1M */ ++ //header[2] = 0x0f00; //PHY control L ++ //header[3] = 0x0000; //PHY control H ++ *phyCtrl = 0x00000F00; ++ } ++ else ++ { ++ /* CCK 6M */ ++ //header[2] = 0x0f01; //PHY control L ++ //header[3] = 0x000B; //PHY control H ++ *phyCtrl = 0x000B0F01; ++ } ++ *qosType = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zm_msg2_mm(ZM_LV_3, "PhyCtrl=", *phyCtrl); ++ return; ++} ++ ++void zfApGetStaEncryType(zdev_t* dev, u16_t* addr, u8_t* encryType) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u16_t id; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ *encryType = wd->ap.staTable[id].encryMode; ++ } ++ else ++ { ++ *encryType = ZM_NO_WEP; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zm_msg2_mm(ZM_LV_3, "encyrType=", *encryType); ++ return; ++} ++ ++void zfApGetStaWpaIv(zdev_t* dev, u16_t* addr, u16_t* iv16, u32_t* iv32) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u16_t id; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ *iv16 = wd->ap.staTable[id].iv16; ++ *iv32 = wd->ap.staTable[id].iv32; ++ } ++ else ++ { ++ *iv16 = 0; ++ *iv32 = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zm_msg2_mm(ZM_LV_3, "iv16=", *iv16); ++ zm_msg2_mm(ZM_LV_3, "iv32=", *iv32); ++ return; ++} ++ ++void zfApSetStaWpaIv(zdev_t* dev, u16_t* addr, u16_t iv16, u32_t iv32) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u16_t id; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ wd->ap.staTable[id].iv16 = iv16; ++ wd->ap.staTable[id].iv32 = iv32; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zm_msg2_mm(ZM_LV_3, "iv16=", iv16); ++ zm_msg2_mm(ZM_LV_3, "iv32=", iv32); ++ return; ++} ++ ++void zfApClearStaKey(zdev_t* dev, u16_t* addr) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u16_t bcAddr[3] = { 0xffff, 0xffff, 0xffff }; ++ u16_t id; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if (zfMemoryIsEqual((u8_t*)bcAddr, (u8_t*)addr, sizeof(bcAddr)) == TRUE) ++ { ++ /* Turn off group key information */ ++ // zfClearKey(dev, 0); ++ } ++ else ++ { ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ /* Turn off STA's key information */ ++ zfHpRemoveKey(dev, id+1); ++ ++ /* Update STA's Encryption Type */ ++ wd->ap.staTable[id].encryMode = ZM_NO_WEP; ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_3, "Can't find STA address\n"); ++ } ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++#ifdef ZM_ENABLE_CENC ++void zfApGetStaCencIvAndKeyIdx(zdev_t* dev, u16_t* addr, u32_t *iv, u8_t *keyIdx) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u16_t id; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ *iv++ = wd->ap.staTable[id].txiv[0]; ++ *iv++ = wd->ap.staTable[id].txiv[1]; ++ *iv++ = wd->ap.staTable[id].txiv[2]; ++ *iv = wd->ap.staTable[id].txiv[3]; ++ *keyIdx = wd->ap.staTable[id].cencKeyIdx; ++ } ++ else ++ { ++ *iv++ = 0x5c365c37; ++ *iv++ = 0x5c365c36; ++ *iv++ = 0x5c365c36; ++ *iv = 0x5c365c36; ++ *keyIdx = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ return; ++} ++ ++void zfApSetStaCencIv(zdev_t* dev, u16_t* addr, u32_t *iv) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u16_t id; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ wd->ap.staTable[id].txiv[0] = *iv++; ++ wd->ap.staTable[id].txiv[1] = *iv++; ++ wd->ap.staTable[id].txiv[2] = *iv++; ++ wd->ap.staTable[id].txiv[3] = *iv; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return; ++} ++#endif //ZM_ENABLE_CENC ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApFlushBufferedPsFrame */ ++/* Free buffered PS frames. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++void zfApFlushBufferedPsFrame(zdev_t* dev) ++{ ++ u16_t emptyFlag; ++ u16_t freeCount; ++ u16_t vap; ++ zbuf_t* psBuf = NULL; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ freeCount = 0; ++ emptyFlag = 0; ++ while (1) ++ { ++ psBuf = NULL; ++ zmw_enter_critical_section(dev); ++ if (wd->ap.uniHead != wd->ap.uniTail) ++ { ++ psBuf = wd->ap.uniArray[wd->ap.uniHead]; ++ wd->ap.uniHead = (wd->ap.uniHead + 1) & (ZM_UNI_ARRAY_SIZE - 1); ++ } ++ else ++ { ++ emptyFlag = 1; ++ } ++ zmw_leave_critical_section(dev); ++ ++ if (psBuf != NULL) ++ { ++ zfwBufFree(dev, psBuf, ZM_ERR_FLUSH_PS_QUEUE); ++ } ++ zm_assert(freeCount++ < (ZM_UNI_ARRAY_SIZE*2)); ++ ++ if (emptyFlag != 0) ++ { ++ break; ++ } ++ } ++ ++ for (vap=0; vapap.bcmcHead[vap] != wd->ap.bcmcTail[vap]) ++ { ++ psBuf = wd->ap.bcmcArray[vap][wd->ap.bcmcHead[vap]]; ++ wd->ap.bcmcHead[vap] = (wd->ap.bcmcHead[vap] + 1) ++ & (ZM_BCMC_ARRAY_SIZE - 1); ++ } ++ else ++ { ++ emptyFlag = 1; ++ } ++ zmw_leave_critical_section(dev); ++ ++ if (psBuf != NULL) ++ { ++ zfwBufFree(dev, psBuf, ZM_ERR_FLUSH_PS_QUEUE); ++ } ++ zm_assert(freeCount++ < (ZM_BCMC_ARRAY_SIZE*2)); ++ ++ if (emptyFlag != 0) ++ { ++ break; ++ } ++ } ++ } ++ return; ++} ++ ++ ++u16_t zfApBufferPsFrame(zdev_t* dev, zbuf_t* buf, u16_t port) ++{ ++ u16_t id; ++ u16_t addr[3]; ++ u16_t vap = 0; ++ u8_t up; ++ u16_t fragOff; ++ u8_t ac; ++ u16_t ret; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if (port < ZM_MAX_AP_SUPPORT) ++ { ++ vap = port; ++ } ++ ++ addr[0] = zmw_rx_buf_readh(dev, buf, 0); ++ addr[1] = zmw_rx_buf_readh(dev, buf, 2); ++ addr[2] = zmw_rx_buf_readh(dev, buf, 4); ++ ++ if ((addr[0] & 0x1) == 0x1) ++ { ++ if (wd->ap.staPowerSaving > 0) ++ { ++ zmw_enter_critical_section(dev); ++ ++ /* Buffer this BC or MC frame */ ++ if (((wd->ap.bcmcTail[vap]+1)&(ZM_BCMC_ARRAY_SIZE-1)) ++ != wd->ap.bcmcHead[vap]) ++ { ++ wd->ap.bcmcArray[vap][wd->ap.bcmcTail[vap]++] = buf; ++ wd->ap.bcmcTail[vap] &= (ZM_BCMC_ARRAY_SIZE-1); ++ zmw_leave_critical_section(dev); ++ ++ zm_msg0_tx(ZM_LV_0, "Buffer BCMC"); ++ } ++ else ++ { ++ /* bcmcArray full */ ++ zmw_leave_critical_section(dev); ++ ++ zm_msg0_tx(ZM_LV_0, "BCMC buffer full"); ++ ++ /* free buffer according to buffer type */ ++ zfwBufFree(dev, buf, ZM_ERR_BCMC_PS_BUFFER_UNAVAILABLE); ++ } ++ return 1; ++ } ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ if (wd->ap.staTable[id].psMode == 1) ++ { ++ ++ zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); ++ ac = zcUpToAc[up&0x7] & 0x3; ++ ++ if ((wd->ap.staTable[id].qosType == 1) && ++ ((wd->ap.staTable[id].qosInfo & (0x8>>ac)) != 0)) ++ { ++ ret = zfQueuePutNcs(dev, wd->ap.uapsdQ, buf, wd->tick); ++ zmw_leave_critical_section(dev); ++ if (ret != ZM_SUCCESS) ++ { ++ zfwBufFree(dev, buf, ZM_ERR_AP_UAPSD_QUEUE_FULL); ++ } ++ } ++ else ++ { ++ /* Buffer this unicast frame */ ++ if (((wd->ap.uniTail+1)&(ZM_UNI_ARRAY_SIZE-1)) ++ != wd->ap.uniHead) ++ { ++ wd->ap.uniArray[wd->ap.uniTail++] = buf; ++ wd->ap.uniTail &= (ZM_UNI_ARRAY_SIZE-1); ++ zmw_leave_critical_section(dev); ++ zm_msg0_tx(ZM_LV_0, "Buffer UNI"); ++ ++ } ++ else ++ { ++ /* uniArray full */ ++ zmw_leave_critical_section(dev); ++ zm_msg0_tx(ZM_LV_0, "UNI buffer full"); ++ /* free buffer according to buffer type */ ++ zfwBufFree(dev, buf, ZM_ERR_UNI_PS_BUFFER_UNAVAILABLE); ++ } ++ } ++ return 1; ++ } /* if (wd->ap.staTable[id++].psMode == 1) */ ++ } /* if ((id = zfApFindSta(dev, addr)) != 0xffff) */ ++ zmw_leave_critical_section(dev); ++ } ++ ++ return 0; ++} ++ ++u16_t zfApGetSTAInfoAndUpdatePs(zdev_t* dev, u16_t* addr, u16_t* state, ++ u8_t* vap, u16_t psMode, u8_t* uapsdTrig) ++{ ++ u16_t id; ++ u8_t uapsdStaAwake = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++#ifdef ZM_AP_DEBUG ++ //psMode=0; ++#endif ++ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ if (psMode != 0) ++ { ++ zm_msg0_mm(ZM_LV_0, "psMode = 1"); ++ if (wd->ap.staTable[id].psMode == 0) ++ { ++ wd->ap.staPowerSaving++; ++ } ++ else ++ { ++ if (wd->ap.staTable[id].qosType == 1) ++ { ++ zm_msg0_mm(ZM_LV_0, "UAPSD trigger"); ++ *uapsdTrig = wd->ap.staTable[id].qosInfo; ++ } ++ } ++ } ++ else ++ { ++ if (wd->ap.staTable[id].psMode != 0) ++ { ++ wd->ap.staPowerSaving--; ++ if ((wd->ap.staTable[id].qosType == 1) && ((wd->ap.staTable[id].qosInfo&0xf)!=0)) ++ { ++ uapsdStaAwake = 1; ++ } ++ } ++ } ++ ++ wd->ap.staTable[id].psMode = (u8_t) psMode; ++ wd->ap.staTable[id].time = wd->tick; ++ *vap = wd->ap.staTable[id].vap; ++ *state = wd->ap.staTable[id++].state; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (uapsdStaAwake == 1) ++ { ++ zbuf_t* psBuf; ++ u8_t mb; ++ ++ while (1) ++ { ++ if ((psBuf = zfQueueGetWithMac(dev, wd->ap.uapsdQ, (u8_t*)addr, &mb)) != NULL) ++ { ++ zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ } ++ else ++ { ++ break; ++ } ++ } ++ } ++ ++ return id; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApGetNewSta */ ++/* Get a new STA from station table. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0xffff : fail */ ++/* other : STA table index */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfApGetNewSta(zdev_t* dev) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; iap.staTable[i].valid == 0) ++ { ++ zm_msg2_mm(ZM_LV_0, "zfApGetNewSta=", i); ++ return i; ++ } ++ } ++ return 0xffff; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApAddSta */ ++/* Add a STA to station table. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : STA MAC address */ ++/* state : STA state */ ++/* apId : Virtual AP ID */ ++/* type : 0=>11b, 1=>11g */ ++/* */ ++/* OUTPUTS */ ++/* 0xffff : fail */ ++/* Other : index */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfApAddSta(zdev_t* dev, u16_t* addr, u16_t state, u16_t apId, u8_t type, ++ u8_t qosType, u8_t qosInfo) ++{ ++ u16_t index; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zm_msg1_mm(ZM_LV_0, "STA type=", type); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ((index = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ zm_msg0_mm(ZM_LV_2, "found"); ++ /* Update STA state */ ++ if ((state == ZM_STATE_AUTH) || (state == ZM_STATE_PREAUTH)) ++ { ++ wd->ap.staTable[index].state = state; ++ wd->ap.staTable[index].time = wd->tick; ++ wd->ap.staTable[index].vap = (u8_t)apId; ++ } ++ else if (state == ZM_STATE_ASOC) ++ { ++ if ((wd->ap.staTable[index].state == ZM_STATE_AUTH)) ++ //&& (wd->ap.staTable[index].vap == apId)) ++ { ++ wd->ap.staTable[index].state = state; ++ wd->ap.staTable[index].time = wd->tick; ++ wd->ap.staTable[index].qosType = qosType; ++ wd->ap.staTable[index].vap = (u8_t)apId; ++ wd->ap.staTable[index].staType = type; ++ wd->ap.staTable[index].qosInfo = qosInfo; ++ ++ if (wd->frequency < 3000) ++ { ++ /* Init 11b/g */ ++ zfRateCtrlInitCell(dev, &wd->ap.staTable[index].rcCell, type, 1, 1); ++ } ++ else ++ { ++ /* Init 11a */ ++ zfRateCtrlInitCell(dev, &wd->ap.staTable[index].rcCell, type, 0, 1); ++ } ++ ++ if (wd->zfcbApConnectNotify != NULL) ++ { ++ wd->zfcbApConnectNotify(dev, (u8_t*)addr, apId); ++ } ++ } ++ else ++ { ++ index = 0xffff; ++ } ++ } ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_2, "Not found"); ++ if ((state == ZM_STATE_AUTH) || (state == ZM_STATE_PREAUTH)) ++ { ++ /* Get a new STA and update state */ ++ index = zfApGetNewSta(dev); ++ zm_msg2_mm(ZM_LV_1, "new STA index=", index); ++ ++ if (index != 0xffff) ++ { ++ for (i=0; i<3; i++) ++ { ++ wd->ap.staTable[index].addr[i] = addr[i]; ++ } ++ wd->ap.staTable[index].state = state; ++ wd->ap.staTable[index].valid = 1; ++ wd->ap.staTable[index].time = wd->tick; ++ wd->ap.staTable[index].vap = (u8_t)apId; ++ wd->ap.staTable[index].encryMode = ZM_NO_WEP; ++ } ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return index; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApAgingSta */ ++/* Aging STA in station table. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* number of 11b STA in STA table */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfApAgingSta(zdev_t* dev) ++{ ++ u16_t i; ++ u32_t deltaMs; ++ u16_t addr[3]; ++ u16_t txFlag; ++ u16_t psStaCount = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ wd->ap.gStaAssociated = wd->ap.bStaAssociated = 0; ++ ++ for (i=0; iap.staTable[i].valid == 1) ++ { ++ addr[0] = wd->ap.staTable[i].addr[0]; ++ addr[1] = wd->ap.staTable[i].addr[1]; ++ addr[2] = wd->ap.staTable[i].addr[2]; ++ /* millisecond */ ++ deltaMs = (u32_t)((u32_t)wd->tick-(u32_t)wd->ap.staTable[i].time) ++ * ZM_MS_PER_TICK; ++ ++ /* preauth */ ++ if ((wd->ap.staTable[i].state == ZM_STATE_PREAUTH) ++ && (deltaMs > ZM_PREAUTH_TIMEOUT_MS)) ++ { ++ /* Aging STA */ ++ wd->ap.staTable[i].valid = 0; ++ wd->ap.authSharing = 0; ++ txFlag = 1; ++ } ++ ++ /* auth */ ++ if ((wd->ap.staTable[i].state == ZM_STATE_AUTH) ++ && (deltaMs > ZM_AUTH_TIMEOUT_MS)) ++ { ++ /* Aging STA */ ++ wd->ap.staTable[i].valid = 0; ++ txFlag = 1; ++ } ++ ++ /* asoc */ ++ if (wd->ap.staTable[i].state == ZM_STATE_ASOC) ++ { ++ if (wd->ap.staTable[i].psMode != 0) ++ { ++ psStaCount++; ++ } ++ ++ if (deltaMs > ((u32_t)wd->ap.staAgingTimeSec<<10)) ++ { ++ /* Aging STA */ ++ zm_msg1_mm(ZM_LV_0, "Age STA index=", i); ++ wd->ap.staTable[i].valid = 0; ++ txFlag = 1; ++ } ++ else if (deltaMs > ((u32_t)wd->ap.staProbingTimeSec<<10)) ++ { ++ if (wd->ap.staTable[i].psMode == 0) ++ { ++ /* Probing non-PS STA */ ++ zm_msg1_mm(ZM_LV_0, "Probing STA index=", i); ++ wd->ap.staTable[i].time += ++ (wd->ap.staProbingTimeSec * ZM_TICK_PER_SECOND); ++ txFlag = 2; ++ } ++ } ++ } ++ ++ ++ } ++ zmw_leave_critical_section(dev); ++ ++ if (txFlag == 1) ++ { ++ /* Send deauthentication management frame */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, addr, 4, 0, 0); ++ } ++ else if (txFlag == 2) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_DATA_FRAME, addr, 0, 0, 0); ++ } ++ ++ } ++ ++ wd->ap.staPowerSaving = psStaCount; ++ ++ return; ++} ++ ++void zfApProtctionMonitor(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* 11b STA associated => nonErp, Protect */ ++ if (wd->ap.bStaAssociated > 0) ++ { ++ /* Enable NonErp bit in information element */ ++ wd->erpElement = ZM_WLAN_NON_ERP_PRESENT_BIT ++ | ZM_WLAN_USE_PROTECTION_BIT; ++ ++ /* Enable protection mode */ ++ zfApSetProtectionMode(dev, 1); ++ ++ } ++ /* 11b STA not associated, protection OBSS present => Protect */ ++ else if (wd->ap.protectedObss > 2) //Threshold ++ { ++ if (wd->disableSelfCts == 0) ++ { ++ /* Disable NonErp bit in information element */ ++ wd->erpElement = ZM_WLAN_USE_PROTECTION_BIT; ++ ++ /* Enable protection mode */ ++ zfApSetProtectionMode(dev, 1); ++ } ++ } ++ else ++ { ++ /* Disable NonErp bit in information element */ ++ wd->erpElement = 0; ++ ++ /* Disable protection mode */ ++ zfApSetProtectionMode(dev, 0); ++ } ++ wd->ap.protectedObss = 0; ++} ++ ++ ++void zfApProcessBeacon(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t offset; ++ u8_t ch; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg0_mm(ZM_LV_3, "Rx beacon"); ++ ++ /* update Non-ERP flag(wd->ap.nonErpObss) */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) == 0xffff) ++ { ++ /* 11b OBSS */ ++ wd->ap.protectedObss++; ++ return; ++ } ++ ++ ch = zmw_rx_buf_readb(dev, buf, offset+2); ++ if ((ch & ZM_WLAN_USE_PROTECTION_BIT) == ZM_WLAN_USE_PROTECTION_BIT) ++ { ++ /* Protected OBSS */ ++ wd->ap.protectedObss = 1; ++ } ++ ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfProcessAuth */ ++/* Process authenticate management frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : auth frame buffer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++/* Note : AP allows one authenticating STA at a time, does not */ ++/* support multiple authentication process. Make sure */ ++/* authentication state machine will not be blocked due */ ++/* to incompleted authentication handshake. */ ++void zfApProcessAuth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId) ++{ ++ u16_t algo, seq, status; ++ u8_t authSharing; ++ u16_t ret; ++ u16_t i; ++ u8_t challengePassed = 0; ++ u8_t frameCtrl; ++ u32_t retAlgoSeq; ++ u32_t retStatus; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ++ frameCtrl = zmw_rx_buf_readb(dev, buf, 1); ++ /* AP : Auth share 3 */ ++ /* shift for WEP IV */ ++ if ((frameCtrl & 0x40) != 0) ++ { ++ algo = zmw_rx_buf_readh(dev, buf, 28); ++ seq = zmw_rx_buf_readh(dev, buf, 30); ++ status = zmw_rx_buf_readh(dev, buf, 32); ++ } ++ else ++ { ++ algo = zmw_rx_buf_readh(dev, buf, 24); ++ seq = zmw_rx_buf_readh(dev, buf, 26); ++ status = zmw_rx_buf_readh(dev, buf, 28); ++ } ++ ++ zm_msg2_mm(ZM_LV_0, "Rx Auth, seq=", seq); ++ ++ /* Set default to authentication algorithm not support */ ++ retAlgoSeq = 0x20000 | algo; ++ retStatus = 13; /* authentication algorithm not support */ ++ ++ /* AP : Auth open 1 */ ++ if (algo == 0) ++ { ++ if (wd->ap.authAlgo[apId] == 0) ++ { ++ retAlgoSeq = 0x20000; ++ if (seq == 1) ++ { ++ /* AP : update STA to auth */ ++ if ((ret = zfApAddSta(dev, src, ZM_STATE_AUTH, apId, 0, 0, 0)) != 0xffff) ++ { ++ /* AP : call zfwAuthNotify() for host to judge */ ++ //zfwAuthNotify(dev, src); ++ ++ /* AP : response Auth seq=2, success */ ++ retStatus = 0; ++ ++ } ++ else ++ { ++ /* AP : response Auth seq=2, unspecific error */ ++ retStatus = 1; ++ } ++ } ++ else ++ { ++ /* AP : response Auth seq=2, sequence number out of expected */ ++ retStatus = 14; ++ } ++ } ++ } ++ /* AP : Auth share 1 */ ++ else if (algo == 1) ++ { ++ if (wd->ap.authAlgo[apId] == 1) ++ { ++ if (seq == 1) ++ { ++ retAlgoSeq = 0x20001; ++ ++ /* critical section */ ++ zmw_enter_critical_section(dev); ++ if (wd->ap.authSharing == 1) ++ { ++ authSharing = 1; ++ } ++ else ++ { ++ authSharing = 0; ++ wd->ap.authSharing = 1; ++ } ++ /* end of critical section */ ++ zmw_leave_critical_section(dev); ++ ++ if (authSharing == 1) ++ { ++ /* AP : response Auth seq=2, status = fail */ ++ retStatus = 1; ++ } ++ else ++ { ++ /* AP : update STA to preauth */ ++ zfApAddSta(dev, src, ZM_STATE_PREAUTH, apId, 0, 0, 0); ++ ++ /* AP : call zfwAuthNotify() for host to judge */ ++ //zfwAuthNotify(dev, src); ++ ++ /* AP : response Auth seq=2 */ ++ retStatus = 0; ++ } ++ } ++ else if (seq == 3) ++ { ++ retAlgoSeq = 0x40001; ++ ++ if (wd->ap.authSharing == 1) ++ { ++ /* check challenge text */ ++ if (zmw_buf_readh(dev, buf, 30+4) == 0x8010) ++ { ++ for (i=0; i<128; i++) ++ { ++ if (wd->ap.challengeText[i] ++ != zmw_buf_readb(dev, buf, 32+i+4)) ++ { ++ break; ++ } ++ } ++ if (i == 128) ++ { ++ challengePassed = 1; ++ } ++ } ++ ++ if (challengePassed == 1) ++ { ++ /* AP : update STA to auth */ ++ zfApAddSta(dev, src, ZM_STATE_AUTH, apId, 0, 0, 0); ++ ++ /* AP : response Auth seq=2 */ ++ retStatus = 0; ++ } ++ else ++ { ++ /* AP : response Auth seq=2, challenge failure */ ++ retStatus = 15; ++ ++ /* TODO : delete STA */ ++ } ++ ++ wd->ap.authSharing = 0; ++ } ++ } ++ else ++ { ++ retAlgoSeq = 0x40001; ++ retStatus = 14; ++ } ++ } ++ } ++ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_AUTH, src, retAlgoSeq, ++ retStatus, apId); ++ return; ++} ++ ++void zfApProcessAsocReq(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId) ++{ ++ u16_t aid = 0xffff; ++ u8_t frameType; ++ u16_t offset; ++ u8_t staType = 0; ++ u8_t qosType = 0; ++ u8_t qosInfo = 0; ++ u8_t tmp; ++ u16_t i, j, k; ++ u16_t encMode = 0; ++ ++ zmw_get_wlan_dev(dev); ++ /* AP : check SSID */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) != 0xffff) ++ { ++ k = 0; ++ for (j = 0; j < wd->ap.vapNumber; j++) ++ { ++ if ((tmp = zmw_buf_readb(dev, buf, offset+1)) ++ != wd->ap.ssidLen[j]) ++ { ++ k++; ++ } ++ } ++ if (k == wd->ap.vapNumber) ++ { ++ goto zlDeauth; ++ } ++ ++ k = 0; ++ for (j = 0; j < wd->ap.vapNumber; j++) ++ { ++ for (i=0; iap.ssidLen[j]; i++) ++ { ++ if ((tmp = zmw_buf_readb(dev, buf, offset+2+i)) ++ != wd->ap.ssid[j][i]) ++ { ++ break; ++ } ++ } ++ if (i == wd->ap.ssidLen[j]) ++ { ++ apId = j; ++ } ++ else ++ { ++ k++; ++ } ++ } ++ if (k == wd->ap.vapNumber) ++ { ++ goto zlDeauth; ++ } ++ } ++ ++ /* TODO : check capability */ ++ ++ /* AP : check support rate */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) != 0xffff) ++ { ++ /* 11g STA */ ++ staType = 1; ++ } ++ //CWYang(+) ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff) ++ { ++ /* 11n STA */ ++ staType = 2; ++ } ++ ++ /* TODO : do not allow 11b STA to associated in Pure G mode */ ++ if (wd->ap.wlanType[apId] == ZM_WLAN_TYPE_PURE_G && staType == 0) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 3, 0, 0); ++ return; ++ } ++ ++ /* In pure B mode, we set G STA into B mode */ ++ if (wd->ap.wlanType[apId] == ZM_WLAN_TYPE_PURE_B && staType == 1) ++ { ++ staType = 0; ++ } ++ ++ /* AP : check 11i and WPA */ ++ /* AP : check 11h */ ++ ++ /* AP : check WME */ ++ if ((offset = zfFindWifiElement(dev, buf, 2, 0)) != 0xffff) ++ { ++ /* WME STA */ ++ qosType = 1; ++ zm_msg0_mm(ZM_LV_0, "WME STA"); ++ ++ if (wd->ap.uapsdEnabled != 0) ++ { ++ qosInfo = zmw_rx_buf_readb(dev, buf, offset+8); ++ } ++ } ++ ++ if (wd->ap.wpaSupport[apId] == 1) ++ { ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_WPA_IE)) != 0xffff ) ++ { ++ /* get WPA IE */ ++ u8_t length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length+2 < ZM_MAX_WPAIE_SIZE) ++ { ++ zfCopyFromRxBuffer(dev, buf, wd->ap.stawpaIe[apId], offset, length+2); ++ wd->ap.stawpaLen[apId] = length+2; ++ encMode = 1; ++ ++ ++ zm_msg1_mm(ZM_LV_0, "WPA Mode zfwAsocNotify, apId=", apId); ++ ++ /* AP : Call zfwAsocNotify() */ ++ if (wd->zfcbAsocNotify != NULL) ++ { ++ wd->zfcbAsocNotify(dev, src, wd->ap.stawpaIe[apId], wd->ap.stawpaLen[apId], apId); ++ } ++ } ++ else ++ { ++ goto zlDeauth; ++ } ++ } ++ else if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_RSN_IE)) != 0xffff ) ++ { ++ /* get RSN IE */ ++ u8_t length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length+2 < ZM_MAX_WPAIE_SIZE) ++ { ++ zfCopyFromRxBuffer(dev, buf, wd->ap.stawpaIe[apId], offset, length+2); ++ wd->ap.stawpaLen[apId] = length+2; ++ encMode = 1; ++ ++ zm_msg1_mm(ZM_LV_0, "RSN Mode zfwAsocNotify, apId=", apId); ++ ++ /* AP : Call zfwAsocNotify() */ ++ if (wd->zfcbAsocNotify != NULL) ++ { ++ wd->zfcbAsocNotify(dev, src, wd->ap.stawpaIe[apId], wd->ap.stawpaLen[apId], apId); ++ } ++ } ++ else ++ { ++ goto zlDeauth; ++ } ++ } ++#ifdef ZM_ENABLE_CENC ++ else if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_CENC_IE)) != 0xffff ) ++ { ++ /* get CENC IE */ ++ u8_t length = zmw_rx_buf_readb(dev, buf, offset+1); ++ ++ if (length+2 < ZM_MAX_WPAIE_SIZE) ++ { ++ zfCopyFromRxBuffer(dev, buf, wd->ap.stawpaIe[apId], offset, length+2); ++ wd->ap.stawpaLen[apId] = length+2; ++ encMode = 1; ++ ++ zm_msg1_mm(ZM_LV_0, "CENC Mode zfwAsocNotify, apId=", apId); ++ ++ /* AP : Call zfwAsocNotify() */ ++ if (wd->zfcbCencAsocNotify != NULL) ++ { ++ wd->zfcbCencAsocNotify(dev, src, wd->ap.stawpaIe[apId], ++ wd->ap.stawpaLen[apId], apId); ++ } ++ } ++ else ++ { ++ goto zlDeauth; ++ } ++ } ++#endif //ZM_ENABLE_CENC ++ else ++ { /* ap is encryption but sta has no wpa/rsn ie */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 6, 0, 0); ++ return; ++ } ++ } ++ /* sta has wpa/rsn ie but ap is no encryption */ ++ if ((wd->ap.wpaSupport[apId] == 0) && (encMode == 1)) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 6, 0, 0); ++ return; ++ } ++ ++ /* AP : update STA to asoc */ ++ aid = zfApAddSta(dev, src, ZM_STATE_ASOC, apId, staType, qosType, qosInfo); ++ ++ zfApStoreAsocReqIe(dev, buf, aid); ++ ++zlDeauth: ++ /* AP : send asoc rsp2 */ ++ if (aid != 0xffff) ++ { ++ frameType = zmw_rx_buf_readb(dev, buf, 0); ++ ++ if (frameType == ZM_WLAN_FRAME_TYPE_ASOCREQ) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ASOCRSP, src, 0, aid+1, apId); ++ } ++ else ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_REASOCRSP, src, 0, aid+1, apId); ++ } ++ } ++ else ++ { ++ /* TODO : send deauthentication */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 6, 0, 0); ++ } ++ ++ return; ++} ++ ++void zfApStoreAsocReqIe(zdev_t* dev, zbuf_t* buf, u16_t aid) ++{ ++ //struct zsWlanAssoFrameHeader* pAssoFrame; ++ //u8_t pBuf[sizeof(struct zsWlanAssoFrameHeader)]; ++ u16_t offset; ++ u32_t i; ++ u16_t length; ++ u8_t *htcap; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; ista.asocRspFrameBodySize; i++) ++ { ++ wd->sta.asocRspFrameBody[i] = zmw_rx_buf_readb(dev, buf, i+24); ++ } ++ /* capability: 2 octets */ ++ offset = 24; ++ ++ /* Listen interval: 2 octets */ ++ offset = 26; ++ ++ /* SSID */ ++ offset = 28; ++ ++ /* supported rates */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SUPPORT_RATE)) == 0xffff) ++ return; ++ length = zmw_rx_buf_readb(dev, buf, offset + 1); ++ ++ /* extended supported rates */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) == 0xffff) ++ return; ++ length = zmw_rx_buf_readb(dev, buf, offset + 1); ++ ++ /* power capability:4 octets */ ++ offset = offset + 2 + length; ++ ++ /* supported channels: 4 octets */ ++ offset = offset + 2 + 4; ++ ++ /* RSN */ ++ ++ /* QoS */ ++ ++ /* HT capabilities: 28 octets */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff) { ++ /* atheros pre n */ ++ htcap = (u8_t *)&wd->ap.ie[aid].HtCap; ++ htcap[0] = zmw_rx_buf_readb(dev, buf, offset); ++ htcap[1] = 26; ++ for (i=1; i<=26; i++) ++ { ++ htcap[i+1] = zmw_rx_buf_readb(dev, buf, offset + i); ++ zm_debug_msg2("ASOC: HT Capabilities, htcap=", htcap[i+1]); ++ } ++ return; ++ } ++ else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff) { ++ /* pre n 2.0 standard */ ++ htcap = (u8_t *)&wd->ap.ie[aid].HtCap; ++ for (i=0; i<28; i++) ++ { ++ htcap[i] = zmw_rx_buf_readb(dev, buf, offset + i); ++ zm_debug_msg2("ASOC: HT Capabilities, htcap=", htcap[i]); ++ } ++ } ++ else { ++ /* not 11n AP */ ++ return; ++ } ++ ++ ++ /* supported regulatory classes */ ++ offset = offset + length; ++ //length = zmw_rx_buf_readb(dev, buf, offset + 1); ++ { ++ u8_t *htcap; ++ htcap = (u8_t *)&wd->sta.ie.HtInfo; ++ //zm_debug_msg2("ASOC: HT Capabilities info=", ((u16_t *)htcap)[1]); ++ //zm_debug_msg2("ASOC: A-MPDU parameters=", htcap[4]); ++ //zm_debug_msg2("ASOC: Supported MCS set=", ((u32_t *)htcap)[1]>>8); ++ } ++ ++} ++ ++void zfApProcessAsocRsp(zdev_t* dev, zbuf_t* buf) ++{ ++ ++} ++ ++void zfApProcessDeauth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId) ++{ ++ u16_t aid; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ /* AP : if SA=associated STA then deauthenticate STA */ ++ if ((aid = zfApFindSta(dev, src)) != 0xffff) ++ { ++ /* Clear STA table */ ++ wd->ap.staTable[aid].valid = 0; ++ if (wd->zfcbDisAsocNotify != NULL) ++ { ++ wd->zfcbDisAsocNotify(dev, (u8_t*)src, apId); ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++} ++ ++void zfApProcessDisasoc(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId) ++{ ++ u16_t aid; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ /* AP : if SA=associated STA then deauthenticate STA */ ++ if ((aid = zfApFindSta(dev, src)) != 0xffff) ++ { ++ /* Clear STA table */ ++ wd->ap.staTable[aid].valid = 0; ++ zmw_leave_critical_section(dev); ++ if (wd->zfcbDisAsocNotify != NULL) ++ { ++ wd->zfcbDisAsocNotify(dev, (u8_t*)src, apId); ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++} ++ ++ ++void zfApProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) ++{ ++#if 0 ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg0_mm(ZM_LV_0, "Rx probersp"); ++ ++ /* Gather scan result */ ++ ++ //zm_debug_msg1("bssList Count = ", wd->sta.bssList.bssCount); ++ /* return if not in scanning */ ++ if ((wd->heartBeatNotification & ZM_BSSID_LIST_SCAN) ++ != ZM_BSSID_LIST_SCAN) ++ { ++ return; ++ } ++ ++ //if ( wd->sta.pUpdateBssList->bssCount == ZM_MAX_BSS ) ++ if ( wd->sta.bssList.bssCount == ZM_MAX_BSS ) ++ { ++ return; ++ } ++ ++ zfProcessProbeRsp(dev, buf, AddInfo); ++ ++#endif ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApAddIeSsid */ ++/* Add AP information element SSID to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* vap : virtual AP ID */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u16_t zfApAddIeSsid(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->ap.ssidLen[vap]); ++ ++ /* Information : SSID */ ++ for (i=0; iap.ssidLen[vap]; i++) ++ { ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->ap.ssid[vap][i]); ++ } ++ ++ return offset; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApAddIeTim */ ++/* Add AP information element TIM to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* vap : virtual AP ID */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u16_t zfApAddIeTim(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap) ++{ ++ u8_t uniBitMap[9]; ++ u16_t highestByte; ++ u16_t i; ++ u16_t lenOffset; ++ u16_t id; ++ u16_t dst[3]; ++ u16_t aid; ++ u16_t bitPosition; ++ u16_t bytePosition; ++ zbuf_t* psBuf; ++ zbuf_t* tmpBufArray[ZM_UNI_ARRAY_SIZE]; ++ u16_t tmpBufArraySize = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_TIM); ++ ++ /* offset of Element Length */ ++ lenOffset = offset++; ++ ++ /* Information : TIM */ ++ /* DTIM count */ ++ /* TODO : Doesn't work for Virtual AP's case */ ++ wd->CurrentDtimCount++; ++ if (wd->CurrentDtimCount >= wd->dtim) ++ { ++ wd->CurrentDtimCount = 0; ++ } ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->CurrentDtimCount); ++ /* DTIM period */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->dtim); ++ /* bitmap offset */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0); ++ ++ /* Update BCMC bit */ ++ if (wd->CurrentDtimCount == 0) ++ { ++ zmw_enter_critical_section(dev); ++ wd->ap.timBcmcBit[vap] = (wd->ap.bcmcTail[vap]!=wd->ap.bcmcHead[vap])?1:0; ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ wd->ap.timBcmcBit[vap] = 0; ++ } ++ ++ /* Update Unicast bitmap */ ++ /* reset bit map */ ++ for (i=0; i<9; i++) ++ { ++ uniBitMap[i] = 0; ++ } ++ highestByte = 0; ++#if 1 ++ ++ zmw_enter_critical_section(dev); ++ ++ id = wd->ap.uniHead; ++ while (id != wd->ap.uniTail) ++ { ++ psBuf = wd->ap.uniArray[id]; ++ ++ /* TODO : Aging PS frame after queuing for more than 10 seconds */ ++ ++ /* get destination STA's aid */ ++ dst[0] = zmw_tx_buf_readh(dev, psBuf, 0); ++ dst[1] = zmw_tx_buf_readh(dev, psBuf, 2); ++ dst[2] = zmw_tx_buf_readh(dev, psBuf, 4); ++ if ((aid = zfApFindSta(dev, dst)) != 0xffff) ++ { ++ if (wd->ap.staTable[aid].psMode != 0) ++ { ++ zm_msg1_mm(ZM_LV_0, "aid=",aid); ++ aid++; ++ zm_assert(aid<=64); ++ bitPosition = (1 << (aid & 0x7)); ++ bytePosition = (aid >> 3); ++ uniBitMap[bytePosition] |= bitPosition; ++ ++ if (bytePosition>highestByte) ++ { ++ highestByte = bytePosition; ++ } ++ id = (id+1) & (ZM_UNI_ARRAY_SIZE-1); ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_0, "Send PS frame which STA no longer in PS mode"); ++ /* Send PS frame which STA no longer in PS mode */ ++ zfApRemoveFromPsQueue(dev, id, dst); ++ tmpBufArray[tmpBufArraySize++] = psBuf; ++ } ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_0, "Free garbage PS frame"); ++ /* Free garbage PS frame */ ++ zfApRemoveFromPsQueue(dev, id, dst); ++ zfwBufFree(dev, psBuf, 0); ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++#endif ++ ++ zfQueueGenerateUapsdTim(dev, wd->ap.uapsdQ, uniBitMap, &highestByte); ++ ++ zm_msg1_mm(ZM_LV_3, "bm=",uniBitMap[0]); ++ zm_msg1_mm(ZM_LV_3, "highestByte=",highestByte); ++ zm_msg1_mm(ZM_LV_3, "timBcmcBit[]=",wd->ap.timBcmcBit[vap]); ++ ++ /* bitmap */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ++ uniBitMap[0] | wd->ap.timBcmcBit[vap]); ++ for (i=0; iap.uniTail = (wd->ap.uniTail-1) & (ZM_UNI_ARRAY_SIZE-1); ++ while (id != wd->ap.uniTail) ++ { ++ nid = (id + 1) & (ZM_UNI_ARRAY_SIZE - 1); ++ wd->ap.uniArray[id] = wd->ap.uniArray[nid]; ++ ++ /* Search until tail to config more data bit */ ++ dst[0] = zmw_buf_readh(dev, wd->ap.uniArray[id], 0); ++ dst[1] = zmw_buf_readh(dev, wd->ap.uniArray[id], 2); ++ dst[2] = zmw_buf_readh(dev, wd->ap.uniArray[id], 4); ++ if ((addr[0] == dst[0]) && (addr[1] == dst[1]) ++ && (addr[2] == dst[2])) ++ { ++ moreData = 0x20; ++ } ++ ++ id = nid; ++ } ++ return moreData; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApAddIeWmePara */ ++/* Add WME Parameter Element to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* vap : virtual AP ID */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.1 */ ++/* */ ++/************************************************************************/ ++u16_t zfApAddIeWmePara(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t vap) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WIFI_IE); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 24); ++ ++ /* OUI */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x50); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0xF2); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x02); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x01); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x01); ++ ++ /* QoS Info */ ++ if (wd->ap.uapsdEnabled) ++ { ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x81); ++ } ++ else ++ { ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x01); ++ } ++ ++ /* Reserved */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ ++ /* Best Effort AC parameters */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x03); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0xA4); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ /* Backfround AC parameters */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x27); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0xA4); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ /* Video AC parameters */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x42); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x43); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x5E); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ /* Voice AC parameters */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x62); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x32); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x2F); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ ++ return offset; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApSendBeacon */ ++/* Sned AP mode beacon. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++void zfApSendBeacon(zdev_t* dev) ++{ ++ zbuf_t* buf; ++ u16_t offset; ++ u16_t vap; ++ u16_t seq; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ wd->ap.beaconCounter++; ++ if (wd->ap.beaconCounter >= wd->ap.vapNumber) ++ { ++ wd->ap.beaconCounter = 0; ++ } ++ vap = wd->ap.beaconCounter; ++ ++ ++ zm_msg1_mm(ZM_LV_2, "Send beacon, vap=", vap); ++ ++ /* TBD : Maximum size of beacon */ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc beacon buf Fail!"); ++ return; ++ } ++ ++ offset = 0; ++ ++ /* wlan header */ ++ /* Frame control */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0x0080); ++ offset+=2; ++ /* Duration */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0x0000); ++ offset+=2; ++ /* Address 1 */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0xffff); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, 0xffff); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, 0xffff); ++ offset+=2; ++ /* Address 2 */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[0]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[1]); ++ offset+=2; ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[2]); //Multiple SSID ++#else ++ zmw_tx_buf_writeh(dev, buf, offset, (wd->macAddr[2]+(vap<<8))); //VAP ++#endif ++ offset+=2; ++ /* Address 3 */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[0]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[1]); ++ offset+=2; ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[2]); //Multiple SSID ++#else ++ zmw_tx_buf_writeh(dev, buf, offset, (wd->macAddr[2]+(vap<<8))); //VAP ++#endif ++ offset+=2; ++ ++ /* Sequence number */ ++ zmw_enter_critical_section(dev); ++ seq = ((wd->mmseq++)<<4); ++ zmw_leave_critical_section(dev); ++ zmw_tx_buf_writeh(dev, buf, offset, seq); ++ offset+=2; ++ ++ /* 24-31 Time Stamp : hardware will fill this field */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0); ++ zmw_tx_buf_writeh(dev, buf, offset+2, 0); ++ zmw_tx_buf_writeh(dev, buf, offset+4, 0); ++ zmw_tx_buf_writeh(dev, buf, offset+6, 0); ++ offset+=8; ++ ++ /* Beacon Interval */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->beaconInterval); ++ offset+=2; ++ ++ /* Capability */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]); ++ offset+=2; ++ ++ /* SSID */ ++ if (wd->ap.hideSsid[vap] == 0) ++ { ++ offset = zfApAddIeSsid(dev, buf, offset, vap); ++ } ++ else ++ { ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0); ++ ++ } ++ ++ /* Support Rate */ ++ if ( wd->frequency < 3000 ) ++ { ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); ++ } ++ else ++ { ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); ++ } ++ ++ /* DS parameter set */ ++ offset = zfMmAddIeDs(dev, buf, offset); ++ ++ /* TIM */ ++ offset = zfApAddIeTim(dev, buf, offset, vap); ++ ++ /* If WLAN Type is not PURE B */ ++ if (wd->ap.wlanType[vap] != ZM_WLAN_TYPE_PURE_B) ++ { ++ if ( wd->frequency < 3000 ) ++ { ++ /* ERP Information */ ++ offset = zfMmAddIeErp(dev, buf, offset); ++ ++ /* Extended Supported Rates */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ } ++ } ++ ++ /* TODO : country information */ ++ /* TODO : RSN */ ++ if (wd->ap.wpaSupport[vap] == 1) ++ { ++ offset = zfMmAddIeWpa(dev, buf, offset, vap); ++ } ++ ++ /* WME Parameters */ ++ if (wd->ap.qosMode == 1) ++ { ++ offset = zfApAddIeWmePara(dev, buf, offset, vap); ++ } ++ ++ /* HT Capabilities Info */ ++ offset = zfMmAddHTCapability(dev, buf, offset); ++ ++ /* Extended HT Capabilities Info */ ++ offset = zfMmAddExtendedHTCapability(dev, buf, offset); ++ ++ /* 1212 : write to beacon fifo */ ++ /* 1221 : write to share memory */ ++ zfHpSendBeacon(dev, buf, offset); ++ ++ /* Free beacon buffer */ ++ /* TODO: In order to fit the madwifi beacon architecture, we need to ++ free beacon buffer in the HAL layer. ++ */ ++ ++ //zfwBufFree(dev, buf, 0); ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfIntrabssForward */ ++/* Called to transmit intra-BSS frame from upper layer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer pointer */ ++/* vap : virtual AP */ ++/* */ ++/* OUTPUTS */ ++/* 1 : unicast intras-BSS frame */ ++/* 0 : other frames */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u16_t zfIntrabssForward(zdev_t* dev, zbuf_t* buf, u8_t srcVap) ++{ ++ u16_t err; ++ u16_t asocFlag = 0; ++ u16_t dst[3]; ++ u16_t aid; ++ u16_t staState; ++ zbuf_t* txBuf; ++ u16_t len; ++ u16_t i; ++ u16_t temp; ++ u16_t ret; ++ u8_t vap = 0; ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ dst[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET); ++ dst[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2); ++ dst[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4); ++#else ++ dst[0] = zmw_rx_buf_readh(dev, buf, 0); ++ dst[1] = zmw_rx_buf_readh(dev, buf, 2); ++ dst[2] = zmw_rx_buf_readh(dev, buf, 4); ++#endif // ZM_ENABLE_NATIVE_WIFI ++ ++ /* Do Intra-BSS forward(data copy) if necessary*/ ++ if ((dst[0]&0x1) != 0x1) ++ { ++ aid = zfApGetSTAInfo(dev, dst, &staState, &vap); ++ if ((aid != 0xffff) && (staState == ZM_STATE_ASOC) && (srcVap == vap)) ++ { ++ asocFlag = 1; ++ zm_msg0_rx(ZM_LV_2, "Intra-BSS forward : asoc STA"); ++ } ++ ++ } ++ else ++ { ++ vap = srcVap; ++ zm_msg0_rx(ZM_LV_2, "Intra-BSS forward : BCorMC"); ++ } ++ ++ /* destination address = associated STA or BC/MC */ ++ if ((asocFlag == 1) || ((dst[0]&0x1) == 0x1)) ++ { ++ /* Allocate frame */ ++ if ((txBuf = zfwBufAllocate(dev, ZM_RX_FRAME_SIZE)) ++ == NULL) ++ { ++ zm_msg0_rx(ZM_LV_1, "Alloc intra-bss buf Fail!"); ++ goto zlAllocError; ++ } ++ ++ /* Copy frame */ ++ len = zfwBufGetSize(dev, buf); ++ for (i=0; iap.staTable[id].rxMicKey); ++ ++ return NULL; ++} ++ ++struct zsMicVar* zfApGetTxMicKey(zdev_t* dev, zbuf_t* buf, u8_t* qosType) ++{ ++ u8_t da[6]; ++ u16_t id = 0, macAddr[3]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zfCopyFromIntTxBuffer(dev, buf, da, 0, 6); ++ ++ macAddr[0] = da[0] + (da[1] << 8); ++ macAddr[1] = da[2] + (da[3] << 8); ++ macAddr[2] = da[4] + (da[5] << 8); ++ ++ if ((macAddr[0] & 0x1)) ++ { ++ return (&wd->ap.bcMicKey[0]); ++ } ++ else if ((id = zfApFindSta(dev, macAddr)) != 0xffff) ++ { ++ *qosType = wd->ap.staTable[id].qosType; ++ return (&wd->ap.staTable[id].txMicKey); ++ } ++ ++ return NULL; ++} ++ ++u16_t zfApUpdatePsBit(zdev_t* dev, zbuf_t* buf, u8_t* vap, u8_t* uapsdTrig) ++{ ++ u16_t staState; ++ u16_t aid; ++ u16_t psBit; ++ u16_t src[3]; ++ u16_t dst[1]; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ src[0] = zmw_rx_buf_readh(dev, buf, 10); ++ src[1] = zmw_rx_buf_readh(dev, buf, 12); ++ src[2] = zmw_rx_buf_readh(dev, buf, 14); ++ ++ if ((zmw_rx_buf_readb(dev, buf, 1) & 0x3) != 3) ++ { ++ /* AP */ ++ dst[0] = zmw_rx_buf_readh(dev, buf, 4); ++ ++ psBit = (zmw_rx_buf_readb(dev, buf, 1) & 0x10) >> 4; ++ /* Get AID and update STA PS mode */ ++ aid = zfApGetSTAInfoAndUpdatePs(dev, src, &staState, vap, psBit, uapsdTrig); ++ ++ /* if STA not associated, send deauth */ ++ if ((aid == 0xffff) || (staState != ZM_STATE_ASOC)) ++ { ++ if ((dst[0]&0x1)==0) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, src, 0x7, ++ 0, 0); ++ } ++ ++ return ZM_ERR_STA_NOT_ASSOCIATED; ++ } ++ } /* if ((zmw_rx_buf_readb(dev, buf, 1) & 0x3) != 3) */ ++ else ++ { ++ /* WDS */ ++ for (i=0; iap.wds.wdsBitmap & (1<ap.wds.macAddr[i][0]) ++ && (src[1] == wd->ap.wds.macAddr[i][1]) ++ && (src[2] == wd->ap.wds.macAddr[i][2])) ++ { ++ *vap = 0x20 + i; ++ break; ++ } ++ } ++ } ++ } ++ return ZM_SUCCESS; ++} ++ ++void zfApProcessPsPoll(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t src[3]; ++ u16_t dst[3]; ++ zbuf_t* psBuf = NULL; ++ u16_t id; ++ u8_t moreData = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ src[0] = zmw_tx_buf_readh(dev, buf, 10); ++ src[1] = zmw_tx_buf_readh(dev, buf, 12); ++ src[2] = zmw_tx_buf_readh(dev, buf, 14); ++ ++ /* Find ps buffer for PsPoll */ ++ zmw_enter_critical_section(dev); ++ id = wd->ap.uniHead; ++ while (id != wd->ap.uniTail) ++ { ++ psBuf = wd->ap.uniArray[id]; ++ ++ dst[0] = zmw_tx_buf_readh(dev, psBuf, 0); ++ dst[1] = zmw_tx_buf_readh(dev, psBuf, 2); ++ dst[2] = zmw_tx_buf_readh(dev, psBuf, 4); ++ ++ if ((src[0] == dst[0]) && (src[1] == dst[1]) && (src[2] == dst[2])) ++ { ++ moreData = zfApRemoveFromPsQueue(dev, id, src); ++ break; ++ } ++ else ++ { ++ psBuf = NULL; ++ } ++ id = (id + 1) & (ZM_UNI_ARRAY_SIZE - 1); ++ } ++ zmw_leave_critical_section(dev); ++ ++ /* Send ps buffer */ ++ if (psBuf != NULL) ++ { ++ /* Send with more data bit */ ++ zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, moreData); ++ } ++ ++ return; ++} ++ ++void zfApSetProtectionMode(zdev_t* dev, u16_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if (mode == 0) ++ { ++ if (wd->ap.protectionMode != mode) ++ { ++ /* Write MAC&PHY registers to disable protection */ ++ ++ wd->ap.protectionMode = mode; ++ } ++ ++ } ++ else ++ { ++ if (wd->ap.protectionMode != mode) ++ { ++ /* Write MAC&PHY registers to enable protection */ ++ ++ wd->ap.protectionMode = mode; ++ } ++ } ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfApSendFailure */ ++/* Send failure. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : receiver address */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++void zfApSendFailure(zdev_t* dev, u8_t* addr) ++{ ++ u16_t id; ++ u16_t staAddr[3]; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ staAddr[0] = addr[0] + (((u16_t)addr[1])<<8); ++ staAddr[1] = addr[2] + (((u16_t)addr[3])<<8); ++ staAddr[2] = addr[4] + (((u16_t)addr[5])<<8); ++ zmw_enter_critical_section(dev); ++ if ((id = zfApFindSta(dev, staAddr)) != 0xffff) ++ { ++ /* Send failture : Add 3 minutes to inactive time that will */ ++ /* will make STA been kicked out soon */ ++ wd->ap.staTable[id].time -= (3*ZM_TICK_PER_MINUTE); ++ } ++ zmw_leave_critical_section(dev); ++} ++ ++ ++void zfApProcessAction(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t category; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ //zmw_declare_for_critical_section(); ++ ++ category = zmw_rx_buf_readb(dev, buf, 24); ++ ++ switch (category) ++ { ++ case ZM_WLAN_BLOCK_ACK_ACTION_FRAME: ++ zfAggBlockAckActionFrame(dev, buf); ++ break; ++ default: ++ break; ++ } ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cmm.c +@@ -0,0 +1,2141 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : mm.c */ ++/* */ ++/* Abstract */ ++/* This module contains common functions for handle management */ ++/* frame. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#include "../hal/hpreg.h" ++ ++/* TODO : put all constant tables to a file */ ++const u8_t zg11bRateTbl[4] = {2, 4, 11, 22}; ++const u8_t zg11gRateTbl[8] = {12, 18, 24, 36, 48, 72, 96, 108}; ++ ++/* 0xff => element does not exist */ ++const u8_t zgElementOffsetTable[] = ++{ ++ 4, /* 0 : asoc req */ ++ 6, /* 1 : asoc rsp */ ++ 10, /* 2 : reasoc req*/ ++ 6, /* 3 : reasoc rsp */ ++ 0, /* 4 : probe req */ ++ 12, /* 5 : probe rsp */ ++ 0xff, /* 6 : reserved */ ++ 0xff, /* 7 : reserved */ ++ 12, /* 8 : beacon */ ++ 4, /* 9 : ATIM */ ++ 0xff, /* 10 : disasoc */ ++ 6, /* 11 : auth */ ++ 0xff, /* 12 : deauth */ ++ 4, /* 13 : action */ ++ 0xff, /* 14 : reserved */ ++ 0xff, /* 15 : reserved */ ++}; ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfFindElement */ ++/* Find a specific element in management frame */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : management frame buffer */ ++/* eid : target element id */ ++/* */ ++/* OUTPUTS */ ++/* byte offset of target element */ ++/* or 0xffff if not found */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfFindElement(zdev_t* dev, zbuf_t* buf, u8_t eid) ++{ ++ u8_t subType; ++ u16_t offset; ++ u16_t bufLen; ++ u16_t elen; ++ u8_t id, HTEid=0; ++ u8_t oui[4] = {0x00, 0x50, 0xf2, 0x01}; ++ u8_t oui11n[3] = {0x00,0x90,0x4C}; ++ u8_t HTType = 0; ++ ++ /* Get offset of first element */ ++ subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); ++ if ((offset = zgElementOffsetTable[subType]) == 0xff) ++ { ++ zm_assert(0); ++ } ++ ++ /* Plus wlan header */ ++ offset += 24; ++ ++ // jhlee HT 0 ++ ++ if ((eid == ZM_WLAN_EID_HT_CAPABILITY) || ++ (eid == ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) ++ { ++ HTEid = eid; ++ eid = ZM_WLAN_EID_WPA_IE; ++ HTType = 1; ++ } ++ ++ ++ bufLen = zfwBufGetSize(dev, buf); ++ /* Search loop */ ++ while ((offset+2)(bufLen - offset)) ++ { ++ /* Element length error */ ++ return 0xffff; ++ } ++ ++ if ( elen == 0 && eid != ZM_WLAN_EID_SSID) ++ { ++ /* Element length error */ ++ return 0xffff; ++ } ++ ++ if ( eid == ZM_WLAN_EID_WPA_IE ) ++ { ++ /* avoid sta to be thought use 11n when find a WPA_IE */ ++ if ( (HTType == 0) && zfRxBufferEqualToStr(dev, buf, oui, offset+2, 4) ) ++ { ++ return offset; ++ } ++ ++ // jhlee HT 0 ++ // CWYang(+) ++ ++ if ((HTType == 1) && ( zfRxBufferEqualToStr(dev, buf, oui11n, offset+2, 3) )) ++ { ++ if ( zmw_rx_buf_readb(dev, buf, offset+5) == HTEid ) ++ { ++ return offset + 5; ++ } ++ } ++ ++ } ++ else ++ { ++ return offset; ++ } ++ } ++ /* Advance to next element */ ++ #if 1 ++ elen = zmw_rx_buf_readb(dev, buf, offset+1); ++ #else ++ if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) ++ { ++ return 0xffff; ++ } ++ #endif ++ ++ offset += (elen+2); ++ } ++ return 0xffff; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfFindWifiElement */ ++/* Find a specific Wifi element in management frame */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : management frame buffer */ ++/* type : OUI type */ ++/* subType : OUI subtype */ ++/* */ ++/* OUTPUTS */ ++/* byte offset of target element */ ++/* or 0xffff if not found */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.1 */ ++/* */ ++/************************************************************************/ ++u16_t zfFindWifiElement(zdev_t* dev, zbuf_t* buf, u8_t type, u8_t subtype) ++{ ++ u8_t subType; ++ u16_t offset; ++ u16_t bufLen; ++ u16_t elen; ++ u8_t id; ++ u8_t tmp; ++ ++ /* Get offset of first element */ ++ subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); ++ ++ if ((offset = zgElementOffsetTable[subType]) == 0xff) ++ { ++ zm_assert(0); ++ } ++ ++ /* Plus wlan header */ ++ offset += 24; ++ ++ bufLen = zfwBufGetSize(dev, buf); ++ /* Search loop */ ++ while ((offset+2)(bufLen - offset)) ++ { ++ /* Element length error */ ++ return 0xffff; ++ } ++ ++ if ( elen == 0 ) ++ { ++ return 0xffff; ++ } ++ ++ if (((tmp = zmw_rx_buf_readb(dev, buf, offset+2)) == 0x00) ++ && ((tmp = zmw_rx_buf_readb(dev, buf, offset+3)) == 0x50) ++ && ((tmp = zmw_rx_buf_readb(dev, buf, offset+4)) == 0xF2) ++ && ((tmp = zmw_rx_buf_readb(dev, buf, offset+5)) == type)) ++ ++ { ++ if ( subtype != 0xff ) ++ { ++ if ( (tmp = zmw_rx_buf_readb(dev, buf, offset+6)) == subtype ) ++ { ++ return offset; ++ } ++ } ++ else ++ { ++ return offset; ++ } ++ } ++ } ++ /* Advance to next element */ ++ if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) ++ { ++ return 0xffff; ++ } ++ offset += (elen+2); ++ } ++ return 0xffff; ++} ++ ++u16_t zfRemoveElement(zdev_t* dev, u8_t* buf, u16_t size, u8_t eid) ++{ ++ u16_t offset = 0; ++ u16_t elen; ++ u8_t HTEid = 0; ++ u8_t oui[4] = {0x00, 0x50, 0xf2, 0x01}; ++ u8_t oui11n[3] = {0x00,0x90,0x4C}; ++ u8_t HTType = 0; ++ ++ if ((eid == ZM_WLAN_EID_HT_CAPABILITY) || ++ (eid == ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) ++ { ++ HTEid = eid; ++ eid = ZM_WLAN_EID_WPA_IE; ++ HTType = 1; ++ } ++ ++ while (offset < size) ++ { ++ elen = *(buf+offset+1); ++ ++ if (*(buf+offset) == eid) ++ { ++ if ( eid == ZM_WLAN_EID_WPA_IE ) ++ { ++ if ( (HTType == 0) ++ && (*(buf+offset+2) == oui[0]) ++ && (*(buf+offset+3) == oui[1]) ++ && (*(buf+offset+4) == oui[2]) ++ && (*(buf+offset+5) == oui[3]) ) ++ { ++ zfMemoryMove(buf+offset, buf+offset+elen+2, size-offset-elen-2); ++ return (size-elen-2); ++ } ++ ++ if ( (HTType == 1) ++ && (*(buf+offset+2) == oui11n[0]) ++ && (*(buf+offset+3) == oui11n[1]) ++ && (*(buf+offset+4) == oui11n[2]) ++ && (*(buf+offset+5) == HTEid) ) ++ { ++ zfMemoryMove(buf+offset, buf+offset+elen+2, size-offset-elen-2); ++ return (size-elen-2); ++ } ++ } ++ else ++ { ++ zfMemoryMove(buf+offset, buf+offset+elen+2, size-offset-elen-2); ++ return (size-elen-2); ++ } ++ } ++ ++ offset += (elen+2); ++ } ++ ++ return size; ++} ++ ++u16_t zfUpdateElement(zdev_t* dev, u8_t* buf, u16_t size, u8_t* updateeid) ++{ ++ u16_t offset = 0; ++ u16_t elen; ++ ++ while (offset < size) { ++ elen = *(buf+offset+1); ++ ++ if (*(buf+offset) == updateeid[0]) { ++ if (updateeid[1] <= elen) { ++ zfMemoryMove(buf+offset, updateeid, updateeid[1]+2); ++ zfMemoryMove(buf+offset+updateeid[1]+2, buf+offset+elen+2, size-offset-elen-2); ++ ++ return size-(elen-updateeid[1]); ++ } else { ++ zfMemoryMove(buf+offset+updateeid[1]+2, buf+offset+elen+2, size-offset-elen-2); ++ zfMemoryMove(buf+offset, updateeid, updateeid[1]+2); ++ ++ return size+(updateeid[1]-elen); ++ } ++ } ++ ++ offset += (elen+2); ++ } ++ ++ return size; ++} ++ ++u16_t zfFindSuperGElement(zdev_t* dev, zbuf_t* buf, u8_t type) ++{ ++ u8_t subType; ++ u16_t offset; ++ u16_t bufLen; ++ u16_t elen; ++ u8_t id; ++ u8_t super_feature; ++ u8_t ouiSuperG[6] = {0x00,0x03,0x7f,0x01, 0x01, 0x00}; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Get offset of first element */ ++ subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); ++ if ((offset = zgElementOffsetTable[subType]) == 0xff) ++ { ++ zm_assert(0); ++ } ++ ++ /* Plus wlan header */ ++ offset += 24; ++ ++ bufLen = zfwBufGetSize(dev, buf); ++ /* Search loop */ ++ while ((offset+2)(bufLen - offset)) ++ { ++ /* Element length error */ ++ return 0xffff; ++ } ++ ++ if ( elen == 0 ) ++ { ++ return 0xffff; ++ } ++ ++ if (zfRxBufferEqualToStr(dev, buf, ouiSuperG, offset+2, 6) && ( zmw_rx_buf_readb(dev, buf, offset+1) >= 6)) ++ { ++ /* super_feature 0:useFastFrame, 1:useCompression, 2:useTurboPrime */ ++ super_feature= zmw_rx_buf_readb(dev, buf, offset+8); ++ if ((super_feature & 0x01) || (super_feature & 0x02) || (super_feature & 0x04)) ++ { ++ return offset; ++ } ++ } ++ } ++ /* Advance to next element */ ++ #if 1 ++ elen = zmw_rx_buf_readb(dev, buf, offset+1); ++ #else ++ if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) ++ { ++ return 0xffff; ++ } ++ #endif ++ ++ offset += (elen+2); ++ } ++ return 0xffff; ++} ++ ++u16_t zfFindXRElement(zdev_t* dev, zbuf_t* buf, u8_t type) ++{ ++ u8_t subType; ++ u16_t offset; ++ u16_t bufLen; ++ u16_t elen; ++ u8_t id; ++ u8_t ouixr[6] = {0x00,0x03,0x7f,0x03, 0x01, 0x00}; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Get offset of first element */ ++ subType = (zmw_rx_buf_readb(dev, buf, 0) >> 4); ++ if ((offset = zgElementOffsetTable[subType]) == 0xff) ++ { ++ zm_assert(0); ++ } ++ ++ /* Plus wlan header */ ++ offset += 24; ++ ++ bufLen = zfwBufGetSize(dev, buf); ++ /* Search loop */ ++ while ((offset+2)(bufLen - offset)) ++ { ++ /* Element length error */ ++ return 0xffff; ++ } ++ ++ if ( elen == 0 ) ++ { ++ return 0xffff; ++ } ++ ++ if (zfRxBufferEqualToStr(dev, buf, ouixr, offset+2, 6) && ( zmw_rx_buf_readb(dev, buf, offset+1) >= 6)) ++ { ++ return offset; ++ } ++ } ++ /* Advance to next element */ ++ #if 1 ++ elen = zmw_rx_buf_readb(dev, buf, offset+1); ++ #else ++ if ((elen = zmw_rx_buf_readb(dev, buf, offset+1)) == 0) ++ { ++ return 0xffff; ++ } ++ #endif ++ ++ offset += (elen+2); ++ } ++ return 0xffff; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfMmAddIeSupportRate */ ++/* Add information element Support Rate to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* eid : element ID */ ++/* rateSet : CCK or OFDM */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfMmAddIeSupportRate(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t eid, u8_t rateSet) ++{ ++ u8_t len = 0; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ //if ( (rateSet == ZM_RATE_SET_OFDM)&&((wd->gRate & 0xff) == 0) ) ++ //{ ++ // return offset; ++ //} ++ ++ /* Information : Support Rate */ ++ if ( rateSet == ZM_RATE_SET_CCK ) ++ { ++ for (i=0; i<4; i++) ++ { ++ if ((wd->bRate & (0x1<bRateBasic & (0x1<gRate & (0x1<gRateBasic & (0x1< 0) ++ { ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset, eid); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset+1, len); ++ ++ /* Return value */ ++ offset += (2+len); ++ } ++ ++ return offset; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfMmAddIeDs */ ++/* Add information element DS to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfMmAddIeDs(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_DS); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 1); ++ ++ /* Information : DS */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ++ zfChFreqToNum(wd->frequency, NULL)); ++ ++ return offset; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfMmAddIeErp */ ++/* Add information element ERP to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfMmAddIeErp(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_ERP); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 1); ++ ++ /* Information : ERP */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->erpElement); ++ ++ return offset; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfMmAddIeWpa */ ++/* Add information element WPA to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Yuan-Gu Wei ZyDAS Technology Corporation 2006.2 */ ++/* */ ++/************************************************************************/ ++u16_t zfMmAddIeWpa(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t apId) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ int i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ //zmw_inttx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WPA_IE); ++ ++ /* Element Length */ ++ //zmw_inttx_buf_writeb(dev, buf, offset++, wd->ap.wpaLen); ++ for(i = 0; i < wd->ap.wpaLen[apId]; i++) ++ { ++ /* Information : WPA */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->ap.wpaIe[apId][i]); ++ } ++ ++ return offset; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfMmAddHTCapability */ ++/* Add HT Capability Infomation to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Chao-Wen Yang ZyDAS Technology Corporation 2006.06 */ ++/* */ ++/************************************************************************/ ++u16_t zfMmAddHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u8_t OUI[3] = {0x0,0x90,0x4C}; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Prob ID */ ++ zmw_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WPA_IE); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ /* Element Length */ ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Data.Length + 4); ++ ++ /* OUI Data */ ++ for (i = 0; i < 3; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, OUI[i]); ++ } ++ ++ /* Element Type ID */ ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Data.ElementID); ++ ++ /* HT Capability Data */ ++ for (i = 0; i < 26; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Byte[i+2]); ++ } ++ } ++ else ++ { ++ /* Element Length */ ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Data.Length + 4); ++ ++ /* OUI Data */ ++ for (i = 0; i < 3; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, OUI[i]); ++ } ++ ++ /* Element Type ID */ ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Data.ElementID); ++ ++ /* HT Capability Data */ ++ for (i = 0; i < 26; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Byte[i+2]); ++ } ++ } ++ ++ return offset; ++} ++ ++ ++u16_t zfMmAddPreNHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ //u8_t OUI[3] = {0x0,0x90,0x4C}; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Prob ID */ ++ zmw_buf_writeb(dev, buf, offset++, ZM_WLAN_PREN2_EID_HTCAPABILITY); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ /* Element Length */ ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Data.Length); ++ ++ /* HT Capability Data */ ++ for (i = 0; i < 26; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.HTCap.Byte[i+2]); ++ } ++ } ++ else ++ { ++ /* Element Length */ ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Data.Length); ++ ++ /* HT Capability Data */ ++ for (i = 0; i < 26; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.HTCap.Byte[i+2]); ++ } ++ } ++ ++ return offset; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfMmAddExtendedHTCapability */ ++/* Add Extended HT Capability Infomation to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Chao-Wen Yang ZyDAS Technology Corporation 2006.06 */ ++/* */ ++/************************************************************************/ ++u16_t zfMmAddExtendedHTCapability(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u8_t OUI[3] = {0x0,0x90,0x4C}; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Prob ID */ ++ zmw_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WPA_IE); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ /* Element Length */ ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.ExtHTCap.Data.Length + 4); ++ ++ /* OUI Data */ ++ for (i = 0; i < 3; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, OUI[i]); ++ } ++ ++ /* Element Type ID */ ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.ExtHTCap.Data.ElementID); ++ ++ /* HT Capability Data */ ++ for (i = 0; i < 22; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, wd->ap.ExtHTCap.Byte[i+2]); ++ } ++ } ++ else ++ { ++ /* Element Length */ ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.ExtHTCap.Data.Length + 4); ++ ++ /* OUI Data */ ++ for (i = 0; i < 3; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, OUI[i]); ++ } ++ ++ /* Element Type ID */ ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.ExtHTCap.Data.ElementID); ++ ++ /* HT Capability Data */ ++ for (i = 0; i < 22; i++) ++ { ++ zmw_buf_writeb(dev, buf, offset++, wd->sta.ExtHTCap.Byte[i+2]); ++ } ++ } ++ ++ return offset; ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfSendMmFrame */ ++/* Send management frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* frameType : management frame type */ ++/* dst : destination MAC address */ ++/* p1 : parameter 1 */ ++/* p2 : parameter 2 */ ++/* p3 : parameter 3 */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++/* probe req : p1=> bWithSSID, p2=>R, p3=>R */ ++/* probe rsp : p1=>R, p2=>R, p3=>VAP ID(AP) */ ++/* deauth : p1=>Reason Code, p2=>R, p3=>VAP ID(AP) */ ++/* Disasoc : p1=>Reason Code, p2=>R, p3=>VAP ID(AP) */ ++/* ATIM : p1=>R, p2=>R, p3=>R */ ++/* (re)asoc rsp : p1=>Status Code, p2=>AID, p3=>VAP ID(AP) */ ++/* asoc req : p1=>R, p2=>R, p3=>R */ ++/* reasoc req : p1=>AP MAC[0], p2=>AP MAC[1], p3=>AP MAC[2] */ ++/* auth : p1=>low=Algorithm, high=Transaction, p2=>Status, p3=>VAP ID */ ++void zfSendMmFrame(zdev_t* dev, u8_t frameType, u16_t* dst, ++ u32_t p1, u32_t p2, u32_t p3) ++{ ++ zbuf_t* buf; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ u16_t offset = 0; ++ u16_t hlen = 32; ++ u16_t header[(24+25+1)/2]; ++ u16_t vap = 0; ++ u16_t i; ++ u8_t encrypt = 0; ++ u16_t aid; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zm_msg2_mm(ZM_LV_2, "Send mm frame, type=", frameType); ++ /* TBD : Maximum size of managment frame */ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); ++ return; ++ } ++ ++ //Reserve room for wlan header ++ offset = hlen; ++ ++ switch (frameType) ++ { ++ case ZM_WLAN_FRAME_TYPE_PROBEREQ : ++ offset = zfSendProbeReq(dev, buf, offset, (u8_t) p1); ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_PROBERSP : ++ zm_msg0_mm(ZM_LV_3, "probe rsp"); ++ /* 24-31 Time Stamp : hardware WON'T fill this field */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0); ++ zmw_tx_buf_writeh(dev, buf, offset+2, 0); ++ zmw_tx_buf_writeh(dev, buf, offset+4, 0); ++ zmw_tx_buf_writeh(dev, buf, offset+6, 0); ++ offset+=8; ++ ++ /* Beacon Interval */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->beaconInterval); ++ offset+=2; ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ vap = (u16_t) p3; ++ /* Capability */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]); ++ offset+=2; ++ /* SSID */ ++ offset = zfApAddIeSsid(dev, buf, offset, vap); ++ } ++ else ++ { ++ /* Capability */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]); ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]); ++ /* SSID */ ++ offset = zfStaAddIeSsid(dev, buf, offset); ++ } ++ ++ /* Support Rate */ ++ if ( wd->frequency < 3000 ) ++ { ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); ++ } ++ else ++ { ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); ++ } ++ ++ /* DS parameter set */ ++ offset = zfMmAddIeDs(dev, buf, offset); ++ ++ /* TODO ¡G IBSS */ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ offset = zfStaAddIeIbss(dev, buf, offset); ++ ++ if (wd->frequency < 3000) ++ { ++ if( wd->wfc.bIbssGMode ++ && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) // Only accompany with enabling a mode . ++ { ++ /* ERP Information */ ++ wd->erpElement = 0; ++ offset = zfMmAddIeErp(dev, buf, offset); ++ ++ /* Enable G Mode */ ++ /* Extended Supported Rates */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ } ++ } ++ } ++ ++ ++ if ((wd->wlanMode == ZM_MODE_AP) ++ && (wd->ap.wlanType[vap] != ZM_WLAN_TYPE_PURE_B)) ++ { ++ /* ERP Information */ ++ offset = zfMmAddIeErp(dev, buf, offset); ++ ++ /* Extended Supported Rates */ ++ if ( wd->frequency < 3000 ) ++ { ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ } ++ } ++ ++ /* ERP Information */ ++ //offset = zfMmAddIeErp(dev, buf, offset); ++ ++ /* Extended Supported Rates */ ++ //offset = zfMmAddIeSupportRate(dev, buf, offset, ++ // ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ ++ /* TODO : RSN */ ++ if (wd->wlanMode == ZM_MODE_AP && wd->ap.wpaSupport[vap] == 1) ++ { ++ offset = zfMmAddIeWpa(dev, buf, offset, vap); ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS && wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK) ++ { ++ offset = zfwStaAddIeWpaRsn(dev, buf, offset, ZM_WLAN_FRAME_TYPE_AUTH); ++ } ++ ++ /* WME Parameters */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ if (wd->ap.qosMode == 1) ++ { ++ offset = zfApAddIeWmePara(dev, buf, offset, vap); ++ } ++ } ++ ++ if ( wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ // jhlee HT 0 ++ //CWYang(+) ++ /* TODO : Need to check if it is ok */ ++ /* HT Capabilities Info */ ++ offset = zfMmAddHTCapability(dev, buf, offset); ++ //CWYang(+) ++ /* Extended HT Capabilities Info */ ++ offset = zfMmAddExtendedHTCapability(dev, buf, offset); ++ } ++ ++ if ( wd->sta.ibssAdditionalIESize ) ++ offset = zfStaAddIbssAdditionalIE(dev, buf, offset); ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_AUTH : ++ if (p1 == 0x30001) ++ { ++ hlen += 4; ++ offset += 4; // for reserving wep header ++ encrypt = 1; ++ } ++ ++ /* Algotrithm Number */ ++ zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p1&0xffff)); ++ offset+=2; ++ ++ /* Transaction Number */ ++ zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p1>>16)); ++ offset+=2; ++ ++ /* Status Code */ ++ zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p2); ++ offset+=2; ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ vap = (u16_t) p3; ++ } ++ ++ /* Challenge Text => share-2 or share-3 */ ++ if (p1 == 0x20001) ++ { ++ if (p2 == 0) //Status == success ++ { ++ zmw_buf_writeh(dev, buf, offset, 0x8010); ++ offset+=2; ++ /* share-2 : AP generate challenge text */ ++ for (i=0; i<128; i++) ++ { ++ wd->ap.challengeText[i] = (u8_t)zfGetRandomNumber(dev, 0); ++ } ++ zfCopyToIntTxBuffer(dev, buf, wd->ap.challengeText, offset, 128); ++ offset += 128; ++ } ++ } ++ else if (p1 == 0x30001) ++ { ++ /* share-3 : STA return challenge Text */ ++ zfCopyToIntTxBuffer(dev, buf, wd->sta.challengeText, offset, wd->sta.challengeText[1]+2); ++ offset += (wd->sta.challengeText[1]+2); ++ } ++ ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_ASOCREQ : ++ case ZM_WLAN_FRAME_TYPE_REASOCREQ : ++ /* Capability */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]); ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]); ++ ++ /* Listen Interval */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0x0005); ++ offset+=2; ++ ++ /* Reassocaited Request : Current AP address */ ++ if (frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ) ++ { ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[0]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[1]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[2]); ++ offset+=2; ++ } ++ ++ /* SSID */ ++ offset = zfStaAddIeSsid(dev, buf, offset); ++ ++ ++ if ( wd->sta.currentFrequency < 3000 ) ++ { ++ /* Support Rate */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); ++ } ++ else ++ { ++ /* Support Rate */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); ++ } ++ ++ if ((wd->sta.capability[1] & ZM_BIT_0) == 1) ++ { //spectrum managment flag enable ++ offset = zfStaAddIePowerCap(dev, buf, offset); ++ offset = zfStaAddIeSupportCh(dev, buf, offset); ++ } ++ ++ if (wd->sta.currentFrequency < 3000) ++ { ++ /* Extended Supported Rates */ ++ if (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ++ { ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ } ++ } ++ ++ ++ //offset = zfStaAddIeWpaRsn(dev, buf, offset, frameType); ++ //Move to wrapper function, for OS difference--CWYang(m) ++ //for windows wrapper, zfwStaAddIeWpaRsn() should be below: ++ //u16_t zfwStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType) ++ //{ ++ // return zfStaAddIeWpaRsn(dev, buf, offset, frameType); ++ //} ++ offset = zfwStaAddIeWpaRsn(dev, buf, offset, frameType); ++ ++#ifdef ZM_ENABLE_CENC ++ /* CENC */ ++ //if (wd->sta.encryMode == ZM_CENC) ++ offset = zfStaAddIeCenc(dev, buf, offset); ++#endif //ZM_ENABLE_CENC ++ if (((wd->sta.wmeEnabled & ZM_STA_WME_ENABLE_BIT) != 0) //WME enabled ++ && ((wd->sta.apWmeCapability & 0x1) != 0)) //WME AP ++ { ++ if (((wd->sta.apWmeCapability & 0x80) != 0) //UAPSD AP ++ && ((wd->sta.wmeEnabled & ZM_STA_UAPSD_ENABLE_BIT) != 0)) //UAPSD enabled ++ { ++ offset = zfStaAddIeWmeInfo(dev, buf, offset, wd->sta.wmeQosInfo); ++ } ++ else ++ { ++ offset = zfStaAddIeWmeInfo(dev, buf, offset, 0); ++ } ++ } ++ // jhlee HT 0 ++ //CWYang(+) ++ if (wd->sta.EnableHT != 0) ++ { ++ #ifndef ZM_DISABLE_AMSDU8K_SUPPORT ++ //Support 8K A-MSDU ++ if (wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED) ++ { ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_MaxAMSDULength; ++ } ++ else ++ { ++ wd->sta.HTCap.Data.HtCapInfo &= (~HTCAP_MaxAMSDULength); ++ } ++ #else ++ //Support 4K A-MSDU ++ wd->sta.HTCap.Data.HtCapInfo &= (~HTCAP_MaxAMSDULength); ++ #endif ++ ++ /* HT Capabilities Info */ ++ if (wd->BandWidth40 == 1) { ++ wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; ++ } ++ else { ++ wd->sta.HTCap.Data.HtCapInfo &= ~HTCAP_SupChannelWidthSet; ++ //wd->sta.HTCap.Data.HtCapInfo |= HTCAP_SupChannelWidthSet; ++ } ++ ++ wd->sta.HTCap.Data.AMPDUParam &= ~HTCAP_MaxRxAMPDU3; ++ wd->sta.HTCap.Data.AMPDUParam |= HTCAP_MaxRxAMPDU3; ++ wd->sta.HTCap.Data.MCSSet[1] = 0xFF; // MCS 8 ~ 15 ++ offset = zfMmAddHTCapability(dev, buf, offset); ++ offset = zfMmAddPreNHTCapability(dev, buf, offset); ++ //CWYang(+) ++ /* Extended HT Capabilities Info */ ++ //offset = zfMmAddExtendedHTCapability(dev, buf, offset); ++ } ++ ++ ++ //Store asoc request frame body, for VISTA only ++ wd->sta.asocReqFrameBodySize = ((offset - hlen) > ++ ZM_CACHED_FRAMEBODY_SIZE)? ++ ZM_CACHED_FRAMEBODY_SIZE:(offset - hlen); ++ for (i=0; ista.asocReqFrameBodySize; i++) ++ { ++ wd->sta.asocReqFrameBody[i] = zmw_tx_buf_readb(dev, buf, i + hlen); ++ } ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_ASOCRSP : ++ case ZM_WLAN_FRAME_TYPE_REASOCRSP : ++ vap = (u16_t) p3; ++ ++ /* Capability */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->ap.capab[vap]); ++ offset+=2; ++ ++ /* Status Code */ ++ zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p1); ++ offset+=2; ++ ++ /* AID */ ++ zmw_tx_buf_writeh(dev, buf, offset, (u16_t)(p2|0xc000)); ++ offset+=2; ++ ++ ++ if ( wd->frequency < 3000 ) ++ { ++ /* Support Rate */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); ++ ++ /* Extended Supported Rates */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ } ++ else ++ { ++ /* Support Rate */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); ++ } ++ ++ ++ ++ /* WME Parameters */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ /* TODO : if WME STA then send WME parameter element */ ++ if (wd->ap.qosMode == 1) ++ { ++ offset = zfApAddIeWmePara(dev, buf, offset, vap); ++ } ++ } ++ // jhlee HT 0 ++ //CWYang(+) ++ /* HT Capabilities Info */ ++ offset = zfMmAddHTCapability(dev, buf, offset); ++ //CWYang(+) ++ /* Extended HT Capabilities Info */ ++ offset = zfMmAddExtendedHTCapability(dev, buf, offset); ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_ATIM : ++ /* NULL frame */ ++ /* TODO : add two dumb bytes temporarily */ ++ offset += 2; ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_QOS_NULL : ++ zmw_buf_writeh(dev, buf, offset, 0x0010); ++ offset += 2; ++ break; ++ ++ case ZM_WLAN_DATA_FRAME : ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_DISASOC : ++ case ZM_WLAN_FRAME_TYPE_DEAUTH : ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ vap = (u16_t) p3; ++ ++ if ((aid = zfApFindSta(dev, dst)) != 0xffff) ++ { ++ zmw_enter_critical_section(dev); ++ /* Clear STA table */ ++ wd->ap.staTable[aid].valid = 0; ++ ++ zmw_leave_critical_section(dev); ++ ++ if (wd->zfcbDisAsocNotify != NULL) ++ { ++ wd->zfcbDisAsocNotify(dev, (u8_t*)dst, vap); ++ } ++ } ++ } ++ /* Reason Code */ ++ zmw_tx_buf_writeh(dev, buf, offset, (u16_t)p1); ++ offset+=2; ++ break; ++ } ++ ++ zfwBufSetSize(dev, buf, offset); ++ ++ zm_msg2_mm(ZM_LV_2, "management frame body size=", offset-hlen); ++ ++ //Copy wlan header ++ zfTxGenMmHeader(dev, frameType, dst, header, offset-hlen, buf, vap, encrypt); ++ for (i=0; i<(hlen>>1); i++) ++ { ++ zmw_tx_buf_writeh(dev, buf, i*2, header[i]); ++ } ++ ++ /* Get buffer DMA address */ ++ //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) ++ //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) ++ //{ ++ // goto zlError; ++ //} ++ ++ zm_msg2_mm(ZM_LV_2, "offset=", offset); ++ zm_msg2_mm(ZM_LV_2, "hlen=", hlen); ++ //zm_msg2_mm(ZM_LV_2, "addrTblSize=", addrTblSize); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.len[0]=", addrTbl.len[0]); ++ //zm_msg2_mm(ZM_LV_2, "addrTbl.physAddrl[0]=", addrTbl.physAddrl[0]); ++ //zm_msg2_mm(ZM_LV_2, "buf->data=", buf->data); ++ ++ #if 0 ++ if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ #else ++ zfPutVmmq(dev, buf); ++ zfPushVtxq(dev); ++ #endif ++ ++ return; ++#if 0 ++zlError: ++ ++ zfwBufFree(dev, buf, 0); ++ return; ++#endif ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfProcessManagement */ ++/* Process received management frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : received management frame buffer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfProcessManagement(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) //CWYang(m) ++{ ++ u8_t frameType; ++ u16_t ta[3]; ++ u16_t ra[3]; ++ u16_t vap = 0, index = 0; ++ //u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ ra[0] = zmw_rx_buf_readh(dev, buf, 4); ++ ra[1] = zmw_rx_buf_readh(dev, buf, 6); ++ ra[2] = zmw_rx_buf_readh(dev, buf, 8); ++ ++ ta[0] = zmw_rx_buf_readh(dev, buf, 10); ++ ta[1] = zmw_rx_buf_readh(dev, buf, 12); ++ ta[2] = zmw_rx_buf_readh(dev, buf, 14); ++ ++ frameType = zmw_rx_buf_readb(dev, buf, 0); ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++#if 1 ++ vap = 0; ++ if ((ra[0] & 0x1) != 1) ++ { ++ /* AP : Find virtual AP */ ++ if ((index = zfApFindSta(dev, ta)) != 0xffff) ++ { ++ vap = wd->ap.staTable[index].vap; ++ } ++ } ++ zm_msg2_mm(ZM_LV_2, "vap=", vap); ++#endif ++ ++ /* Dispatch by frame type */ ++ switch (frameType) ++ { ++ /* Beacon */ ++ case ZM_WLAN_FRAME_TYPE_BEACON : ++ zfApProcessBeacon(dev, buf); ++ break; ++ /* Authentication */ ++ case ZM_WLAN_FRAME_TYPE_AUTH : ++ zfApProcessAuth(dev, buf, ta, vap); ++ break; ++ /* Association request */ ++ case ZM_WLAN_FRAME_TYPE_ASOCREQ : ++ /* Reassociation request */ ++ case ZM_WLAN_FRAME_TYPE_REASOCREQ : ++ zfApProcessAsocReq(dev, buf, ta, vap); ++ break; ++ /* Association response */ ++ case ZM_WLAN_FRAME_TYPE_ASOCRSP : ++ //zfApProcessAsocRsp(dev, buf); ++ break; ++ /* Deauthentication */ ++ case ZM_WLAN_FRAME_TYPE_DEAUTH : ++ zfApProcessDeauth(dev, buf, ta, vap); ++ break; ++ /* Disassociation */ ++ case ZM_WLAN_FRAME_TYPE_DISASOC : ++ zfApProcessDisasoc(dev, buf, ta, vap); ++ break; ++ /* Probe request */ ++ case ZM_WLAN_FRAME_TYPE_PROBEREQ : ++ zfProcessProbeReq(dev, buf, ta); ++ break; ++ /* Probe response */ ++ case ZM_WLAN_FRAME_TYPE_PROBERSP : ++ zfApProcessProbeRsp(dev, buf, AddInfo); ++ break; ++ /* Action */ ++ case ZM_WLAN_FRAME_TYPE_ACTION : ++ zfApProcessAction(dev, buf); ++ break; ++ } ++ } ++ else //if ((wd->wlanMode == ZM_MODE_INFRASTRUCTURE) || (wd->wlanMode == ZM_MODE_IBSS)) ++ { ++ /* Dispatch by frame type */ ++ switch (frameType) ++ { ++ /* Beacon */ ++ case ZM_WLAN_FRAME_TYPE_BEACON : ++ /* if enable 802.11h and current chanel is silent but receive beacon from other AP */ ++ if (((wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags ++ & ZM_REG_FLAG_CHANNEL_CSA) != 0) && wd->sta.DFSEnable) ++ { ++ wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags ++ &= ~(ZM_REG_FLAG_CHANNEL_CSA & ZM_REG_FLAG_CHANNEL_PASSIVE); ++ } ++ zfStaProcessBeacon(dev, buf, AddInfo); //CWYang(m) ++ break; ++ /* Authentication */ ++ case ZM_WLAN_FRAME_TYPE_AUTH : ++ /* TODO : vap parameter is useless in STA mode, get rid of it */ ++ zfStaProcessAuth(dev, buf, ta, 0); ++ break; ++ /* Association request */ ++ case ZM_WLAN_FRAME_TYPE_ASOCREQ : ++ /* TODO : vap parameter is useless in STA mode, get rid of it */ ++ zfStaProcessAsocReq(dev, buf, ta, 0); ++ break; ++ /* Association response */ ++ case ZM_WLAN_FRAME_TYPE_ASOCRSP : ++ /* Reassociation request */ ++ case ZM_WLAN_FRAME_TYPE_REASOCRSP : ++ zfStaProcessAsocRsp(dev, buf); ++ break; ++ /* Deauthentication */ ++ case ZM_WLAN_FRAME_TYPE_DEAUTH : ++ zm_debug_msg0("Deauthentication received"); ++ zfStaProcessDeauth(dev, buf); ++ break; ++ /* Disassociation */ ++ case ZM_WLAN_FRAME_TYPE_DISASOC : ++ zm_debug_msg0("Disassociation received"); ++ zfStaProcessDisasoc(dev, buf); ++ break; ++ /* Probe request */ ++ case ZM_WLAN_FRAME_TYPE_PROBEREQ : ++ zfProcessProbeReq(dev, buf, ta); ++ break; ++ /* Probe response */ ++ case ZM_WLAN_FRAME_TYPE_PROBERSP : ++ /* if enable 802.11h and current chanel is silent but receive probe response from other AP */ ++ if (((wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags ++ & ZM_REG_FLAG_CHANNEL_CSA) != 0) && wd->sta.DFSEnable) ++ { ++ wd->regulationTable.allowChannel[wd->regulationTable.CurChIndex].channelFlags ++ &= ~(ZM_REG_FLAG_CHANNEL_CSA & ZM_REG_FLAG_CHANNEL_PASSIVE); ++ } ++ zfStaProcessProbeRsp(dev, buf, AddInfo); ++ break; ++ ++ case ZM_WLAN_FRAME_TYPE_ATIM: ++ zfStaProcessAtim(dev, buf); ++ break; ++ /* Action */ ++ case ZM_WLAN_FRAME_TYPE_ACTION : ++ zm_msg0_mm(ZM_LV_2, "ProcessActionMgtFrame"); ++ zfStaProcessAction(dev, buf); ++ break; ++ } ++ } ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfProcessProbeReq */ ++/* Process probe request management frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : auth frame buffer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfProcessProbeReq(zdev_t* dev, zbuf_t* buf, u16_t* src) ++{ ++ u16_t offset; ++ u8_t len; ++ u16_t i, j; ++ u8_t ch; ++ u16_t sendFlag; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* check mode : AP/IBSS */ ++ if ((wd->wlanMode != ZM_MODE_AP) && (wd->wlanMode != ZM_MODE_IBSS)) ++ { ++ zm_msg0_mm(ZM_LV_3, "Ignore probe req"); ++ return; ++ } ++ ++ if ((wd->wlanMode != ZM_MODE_AP) && (wd->sta.adapterState == ZM_STA_STATE_DISCONNECT)) ++ { ++ zm_msg0_mm(ZM_LV_3, "Packets dropped due to disconnect state"); ++ return; ++ } ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBERSP, src, 0, 0, 0); ++ ++ return; ++ } ++ ++ /* check SSID */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) == 0xffff) ++ { ++ zm_msg0_mm(ZM_LV_3, "probe req SSID not found"); ++ return; ++ } ++ ++ len = zmw_rx_buf_readb(dev, buf, offset+1); ++ ++ for (i=0; iap.apBitmap & (1< 0) ++ { ++ zmw_enter_critical_section(dev); ++ /*Find same bssid entry first*/ ++ for (i=0; ista.blockingApList[i].addr[j]!= bssid[j]) ++ { ++ break; ++ } ++ } ++ ++ if(j==6) ++ { ++ break; ++ } ++ } ++ /*This bssid doesn't have old record.Find an empty entry*/ ++ if (i == ZM_MAX_BLOCKING_AP_LIST_SIZE) ++ { ++ for (i=0; ista.blockingApList[i].weight == 0) ++ { ++ break; ++ } ++ } ++ } ++ ++ /* If the list is full, pick one entry for replacement */ ++ if (i == ZM_MAX_BLOCKING_AP_LIST_SIZE) ++ { ++ i = bssid[5] & (ZM_MAX_BLOCKING_AP_LIST_SIZE-1); ++ } ++ ++ /* Update AP address and weight */ ++ for (j=0; j<6; j++) ++ { ++ wd->sta.blockingApList[i].addr[j] = bssid[j]; ++ } ++ ++ wd->sta.blockingApList[i].weight = weight; ++ zmw_leave_critical_section(dev); ++ } ++ ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaIsApInBlockingList */ ++/* Is AP in blocking list. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* bssid : AP's BSSID */ ++/* */ ++/* OUTPUTS */ ++/* TRUE : AP in blocking list */ ++/* FALSE : AP not in blocking list */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaIsApInBlockingList(zdev_t* dev, u8_t* bssid) ++{ ++ u16_t i, j; ++ zmw_get_wlan_dev(dev); ++ //zmw_declare_for_critical_section(); ++ ++ //zmw_enter_critical_section(dev); ++ for (i=0; ista.blockingApList[i].weight != 0) ++ { ++ for (j=0; j<6; j++) ++ { ++ if (wd->sta.blockingApList[i].addr[j] != bssid[j]) ++ { ++ break; ++ } ++ } ++ if (j == 6) ++ { ++ //zmw_leave_critical_section(dev); ++ return TRUE; ++ } ++ } ++ } ++ //zmw_leave_critical_section(dev); ++ return FALSE; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaRefreshBlockList */ ++/* Is AP in blocking list. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* flushFlag : flush whole blocking list */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++void zfStaRefreshBlockList(zdev_t* dev, u16_t flushFlag) ++{ ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ for (i=0; ista.blockingApList[i].weight != 0) ++ { ++ if (flushFlag != 0) ++ { ++ wd->sta.blockingApList[i].weight = 0; ++ } ++ else ++ { ++ wd->sta.blockingApList[i].weight--; ++ } ++ } ++ } ++ zmw_leave_critical_section(dev); ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaConnectFail */ ++/* Handle Connect failure. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* bssid : BSSID */ ++/* reason : reason of failure */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++void zfStaConnectFail(zdev_t* dev, u16_t reason, u16_t* bssid, u8_t weight) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Change internal state */ ++ zfChangeAdapterState(dev, ZM_STA_STATE_DISCONNECT); ++ ++ /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ ++ //zfHpSetTTSIFSTime(dev, 0x8); ++ ++ /* Notify wrapper of connection status changes */ ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, reason, bssid); ++ } ++ ++ /* Put AP into internal blocking list */ ++ zfStaPutApIntoBlockingList(dev, (u8_t *)bssid, weight); ++ ++ /* Issue another SCAN */ ++ if ( wd->sta.bAutoReconnect ) ++ { ++ zm_debug_msg0("Start internal scan..."); ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ zfScanMgrScanStart(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ } ++} ++ ++u8_t zfiWlanIBSSGetPeerStationsCount(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->sta.oppositeCount; ++} ++ ++u8_t zfiWlanIBSSIteratePeerStations(zdev_t* dev, u8_t numToIterate, zfpIBSSIteratePeerStationCb callback, void *ctx) ++{ ++ u8_t oppositeCount; ++ u8_t i; ++ u8_t index = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ oppositeCount = wd->sta.oppositeCount; ++ if ( oppositeCount > numToIterate ) ++ { ++ oppositeCount = numToIterate; ++ } ++ ++ for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++) ++ { ++ if ( oppositeCount == 0 ) ++ { ++ break; ++ } ++ ++ if ( wd->sta.oppositeInfo[i].valid == 0 ) ++ { ++ continue; ++ } ++ ++ callback(dev, &wd->sta.oppositeInfo[i], ctx, index++); ++ oppositeCount--; ++ ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return index; ++} ++ ++ ++s8_t zfStaFindFreeOpposite(zdev_t* dev, u16_t *sa, int *pFoundIdx) ++{ ++ int oppositeCount; ++ int i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ oppositeCount = wd->sta.oppositeCount; ++ ++ for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++) ++ { ++ if ( oppositeCount == 0 ) ++ { ++ break; ++ } ++ ++ if ( wd->sta.oppositeInfo[i].valid == 0 ) ++ { ++ continue; ++ } ++ ++ oppositeCount--; ++ if ( zfMemoryIsEqual((u8_t*) sa, wd->sta.oppositeInfo[i].macAddr, 6) ) ++ { ++ //wd->sta.oppositeInfo[i].aliveCounter++; ++ wd->sta.oppositeInfo[i].aliveCounter = ZM_IBSS_PEER_ALIVE_COUNTER; ++ ++ /* it is already stored */ ++ return 1; ++ } ++ } ++ ++ // Check if there's still space for new comer ++ if ( wd->sta.oppositeCount == ZM_MAX_OPPOSITE_COUNT ) ++ { ++ return -1; ++ } ++ ++ // Find an unused slot for new peer station ++ for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++) ++ { ++ if ( wd->sta.oppositeInfo[i].valid == 0 ) ++ { ++ break; ++ } ++ } ++ ++ *pFoundIdx = i; ++ return 0; ++} ++ ++s8_t zfStaFindOppositeByMACAddr(zdev_t* dev, u16_t *sa, u8_t *pFoundIdx) ++{ ++ u32_t oppositeCount; ++ u32_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ oppositeCount = wd->sta.oppositeCount; ++ ++ for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++) ++ { ++ if ( oppositeCount == 0 ) ++ { ++ break; ++ } ++ ++ if ( wd->sta.oppositeInfo[i].valid == 0 ) ++ { ++ continue; ++ } ++ ++ oppositeCount--; ++ if ( zfMemoryIsEqual((u8_t*) sa, wd->sta.oppositeInfo[i].macAddr, 6) ) ++ { ++ *pFoundIdx = (u8_t)i; ++ ++ return 0; ++ } ++ } ++ ++ *pFoundIdx = 0; ++ return 1; ++} ++ ++static void zfStaInitCommonOppositeInfo(zdev_t* dev, int i) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* set the default rate to the highest rate */ ++ wd->sta.oppositeInfo[i].valid = 1; ++ wd->sta.oppositeInfo[i].aliveCounter = ZM_IBSS_PEER_ALIVE_COUNTER; ++ wd->sta.oppositeCount++; ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ /* Set parameters for new opposite peer station !!! */ ++ wd->sta.oppositeInfo[i].camIdx = 0xff; // Not set key in this location ++ wd->sta.oppositeInfo[i].pkInstalled = 0; ++ wd->sta.oppositeInfo[i].wpaState = ZM_STA_WPA_STATE_INIT ; // No encryption ++#endif ++} ++ ++int zfStaSetOppositeInfoFromBSSInfo(zdev_t* dev, struct zsBssInfo* pBssInfo) ++{ ++ int i; ++ u8_t* dst; ++ u16_t sa[3]; ++ int res; ++ u32_t oneTxStreamCap; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zfMemoryCopy((u8_t*) sa, pBssInfo->macaddr, 6); ++ ++ res = zfStaFindFreeOpposite(dev, sa, &i); ++ if ( res != 0 ) ++ { ++ goto zlReturn; ++ } ++ ++ dst = wd->sta.oppositeInfo[i].macAddr; ++ zfMemoryCopy(dst, (u8_t *)sa, 6); ++ ++ oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM); ++ ++ if (pBssInfo->extSupportedRates[1] != 0) ++ { ++ /* TODO : Handle 11n */ ++ if (pBssInfo->frequency < 3000) ++ { ++ /* 2.4GHz */ ++ if (pBssInfo->EnableHT == 1) ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, pBssInfo->SG40); ++ else ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 1, pBssInfo->SG40); ++ } ++ else ++ { ++ /* 5GHz */ ++ if (pBssInfo->EnableHT == 1) ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, pBssInfo->SG40); ++ else ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, pBssInfo->SG40); ++ } ++ } ++ else ++ { ++ /* TODO : Handle 11n */ ++ if (pBssInfo->frequency < 3000) ++ { ++ /* 2.4GHz */ ++ if (pBssInfo->EnableHT == 1) ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, pBssInfo->SG40); ++ else ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 0, 1, pBssInfo->SG40); ++ } ++ else ++ { ++ /* 5GHz */ ++ if (pBssInfo->EnableHT == 1) ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, pBssInfo->SG40); ++ else ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, pBssInfo->SG40); ++ } ++ } ++ ++ ++ zfStaInitCommonOppositeInfo(dev, i); ++zlReturn: ++ return 0; ++} ++ ++int zfStaSetOppositeInfoFromRxBuf(zdev_t* dev, zbuf_t* buf) ++{ ++ int i; ++ u8_t* dst; ++ u16_t sa[3]; ++ int res = 0; ++ u16_t offset; ++ u8_t bSupportExtRate; ++ u32_t rtsctsRate = 0xffffffff; /* CTS:OFDM 6M, RTS:OFDM 6M */ ++ u32_t oneTxStreamCap; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ sa[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); ++ sa[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2); ++ sa[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4); ++ ++ zmw_enter_critical_section(dev); ++ ++ res = zfStaFindFreeOpposite(dev, sa, &i); ++ if ( res != 0 ) ++ { ++ goto zlReturn; ++ } ++ ++ dst = wd->sta.oppositeInfo[i].macAddr; ++ zfCopyFromRxBuffer(dev, buf, dst, ZM_WLAN_HEADER_A2_OFFSET, 6); ++ ++ if ( (wd->sta.currentFrequency < 3000) && !(wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) ++ { ++ bSupportExtRate = 0; ++ } else { ++ bSupportExtRate = 1; ++ } ++ ++ if ( (bSupportExtRate == 1) ++ && (wd->sta.currentFrequency < 3000) ++ && (wd->wlanMode == ZM_MODE_IBSS) ++ && (wd->wfc.bIbssGMode == 0) ) ++ { ++ bSupportExtRate = 0; ++ } ++ ++ wd->sta.connection_11b = 0; ++ oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM); ++ ++ if ( ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) != 0xffff) ++ && (bSupportExtRate == 1) ) ++ { ++ /* TODO : Handle 11n */ ++ if (wd->sta.currentFrequency < 3000) ++ { ++ /* 2.4GHz */ ++ if (wd->sta.EnableHT == 1) ++ { ++ //11ng ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, wd->sta.SG40); ++ } ++ else ++ { ++ //11g ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 1, wd->sta.SG40); ++ } ++ rtsctsRate = 0x00001bb; /* CTS:CCK 1M, RTS:OFDM 6M */ ++ } ++ else ++ { ++ /* 5GHz */ ++ if (wd->sta.EnableHT == 1) ++ { ++ //11na ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, wd->sta.SG40); ++ } ++ else ++ { ++ //11a ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, wd->sta.SG40); ++ } ++ rtsctsRate = 0x10b01bb; /* CTS:OFDM 6M, RTS:OFDM 6M */ ++ } ++ } ++ else ++ { ++ /* TODO : Handle 11n */ ++ if (wd->sta.currentFrequency < 3000) ++ { ++ /* 2.4GHz */ ++ if (wd->sta.EnableHT == 1) ++ { ++ //11ng ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 1, wd->sta.SG40); ++ rtsctsRate = 0x00001bb; /* CTS:CCK 1M, RTS:OFDM 6M */ ++ } ++ else ++ { ++ //11b ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 0, 1, wd->sta.SG40); ++ rtsctsRate = 0x0; /* CTS:CCK 1M, RTS:CCK 1M */ ++ wd->sta.connection_11b = 1; ++ } ++ } ++ else ++ { ++ /* 5GHz */ ++ if (wd->sta.EnableHT == 1) ++ { ++ //11na ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, (oneTxStreamCap!=0)?3:2, 0, wd->sta.SG40); ++ } ++ else ++ { ++ //11a ++ zfRateCtrlInitCell(dev, &wd->sta.oppositeInfo[i].rcCell, 1, 0, wd->sta.SG40); ++ } ++ rtsctsRate = 0x10b01bb; /* CTS:OFDM 6M, RTS:OFDM 6M */ ++ } ++ } ++ ++ zfStaInitCommonOppositeInfo(dev, i); ++ ++zlReturn: ++ zmw_leave_critical_section(dev); ++ ++ if (rtsctsRate != 0xffffffff) ++ { ++ zfHpSetRTSCTSRate(dev, rtsctsRate); ++ } ++ return res; ++} ++ ++void zfStaProtErpMonitor(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t offset; ++ u8_t erp; ++ u8_t bssid[6]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)&&(zfStaIsConnected(dev)) ) ++ { ++ ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid); ++ ++ if (zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A2_OFFSET, 6)) ++ { ++ if ( (offset=zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) != 0xffff ) ++ { ++ erp = zmw_rx_buf_readb(dev, buf, offset+2); ++ ++ if ( erp & ZM_BIT_1 ) ++ { ++ //zm_debug_msg0("protection mode on"); ++ if (wd->sta.bProtectionMode == FALSE) ++ { ++ wd->sta.bProtectionMode = TRUE; ++ zfHpSetSlotTime(dev, 0); ++ } ++ } ++ else ++ { ++ //zm_debug_msg0("protection mode off"); ++ if (wd->sta.bProtectionMode == TRUE) ++ { ++ wd->sta.bProtectionMode = FALSE; ++ zfHpSetSlotTime(dev, 1); ++ } ++ } ++ } ++ } ++ //Check the existence of Non-N AP ++ //Follow the check the "pBssInfo->EnableHT" ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff) ++ {} ++ else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff) ++ {} ++ else ++ {wd->sta.NonNAPcount++;} ++ } ++} ++ ++void zfStaUpdateWmeParameter(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t tmp; ++ u16_t aifs[5]; ++ u16_t cwmin[5]; ++ u16_t cwmax[5]; ++ u16_t txop[5]; ++ u8_t acm; ++ u8_t ac; ++ u16_t len; ++ u16_t i; ++ u16_t offset; ++ u8_t rxWmeParameterSetCount; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Update if WME parameter set count is changed */ ++ /* If connect to WME AP */ ++ if (wd->sta.wmeConnected != 0) ++ { ++ /* Find WME parameter element */ ++ if ((offset = zfFindWifiElement(dev, buf, 2, 1)) != 0xffff) ++ { ++ if ((len = zmw_rx_buf_readb(dev, buf, offset+1)) >= 7) ++ { ++ rxWmeParameterSetCount=zmw_rx_buf_readb(dev, buf, offset+8); ++ if (rxWmeParameterSetCount != wd->sta.wmeParameterSetCount) ++ { ++ zm_msg0_mm(ZM_LV_0, "wmeParameterSetCount changed!"); ++ wd->sta.wmeParameterSetCount = rxWmeParameterSetCount; ++ /* retrieve WME parameter and update TxQ parameters */ ++ acm = 0xf; ++ for (i=0; i<4; i++) ++ { ++ if (len >= (8+(i*4)+4)) ++ { ++ tmp=zmw_rx_buf_readb(dev, buf, offset+10+i*4); ++ ac = (tmp >> 5) & 0x3; ++ if ((tmp & 0x10) == 0) ++ { ++ acm &= (~(1<> 4)]; ++ txop[ac]=zmw_rx_buf_readh(dev, buf, ++ offset+12+i*4); ++ } ++ } ++ ++ if ((acm & 0x4) != 0) ++ { ++ cwmin[2] = cwmin[0]; ++ cwmax[2] = cwmax[0]; ++ aifs[2] = aifs[0]; ++ txop[2] = txop[0]; ++ } ++ if ((acm & 0x8) != 0) ++ { ++ cwmin[3] = cwmin[2]; ++ cwmax[3] = cwmax[2]; ++ aifs[3] = aifs[2]; ++ txop[3] = txop[2]; ++ } ++ cwmin[4] = 3; ++ cwmax[4] = 7; ++ aifs[4] = 28; ++ ++ if ((cwmin[2]+aifs[2]) > ((cwmin[0]+aifs[0])+1)) ++ { ++ wd->sta.ac0PriorityHigherThanAc2 = 1; ++ } ++ else ++ { ++ wd->sta.ac0PriorityHigherThanAc2 = 0; ++ } ++ zfHpUpdateQosParameter(dev, cwmin, cwmax, aifs, txop); ++ } ++ } ++ } ++ } //if (wd->sta.wmeConnected != 0) ++} ++/* process 802.11h Dynamic Frequency Selection */ ++void zfStaUpdateDot11HDFS(zdev_t* dev, zbuf_t* buf) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* ++ Channel Switch Announcement Element Format ++ +------+----------+------+-------------------+------------------+--------------------+ ++ |Format|Element ID|Length|Channel Switch Mode|New Channel Number|Channel Switch Count| ++ +------+----------+------+-------------------+------------------+--------------------+ ++ |Bytes | 1 | 1 | 1 | 1 | 1 | ++ +------+----------+------+-------------------+------------------+--------------------+ ++ |Value | 37 | 3 | 0 or 1 |unsigned integer |unsigned integer | ++ +------+----------+------+-------------------+------------------+--------------------+ ++ */ ++ //u8_t length, channel, is5G; ++ u16_t offset; ++ ++ /* get EID(Channel Switch Announcement) */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_CHANNEL_SWITCH_ANNOUNCE)) == 0xffff ) ++ { ++ //zm_debug_msg0("EID(Channel Switch Announcement) not found"); ++ return; ++ } ++ else if ( zmw_rx_buf_readb(dev, buf, offset+1) == 0x3 ) ++ { ++ zm_debug_msg0("EID(Channel Switch Announcement) found"); ++ ++ //length = zmw_rx_buf_readb(dev, buf, offset+1); ++ //zfCopyFromRxBuffer(dev, buf, pBssInfo->supportedRates, offset, length+2); ++ ++ //Chanell Switch Mode set to 1, driver should disable transmit immediate ++ //we do this by poll CCA high ++ if (zmw_rx_buf_readb(dev, buf, offset+2) == 0x1 ) ++ { ++ //use ZM_OID_INTERNAL_WRITE,ZM_CMD_RESET to notice firmware flush quene and stop dma, ++ //then restart rx dma but not tx dma ++ if (wd->sta.DFSDisableTx != TRUE) ++ { ++ /* TODO : zfHpResetTxRx would cause Rx hang */ ++ //zfHpResetTxRx(dev); ++ wd->sta.DFSDisableTx = TRUE; ++ /* Trgger Rx DMA */ ++ zfHpStartRecv(dev); ++ } ++ //Adapter->ZD80211HSetting.DisableTxBy80211H=TRUE; ++ //AcquireCtrOfPhyReg(Adapter); ++ //ZD1205_WRITE_REGISTER(Adapter,CR24, 0x0); ++ //ReleaseDoNotSleep(Adapter); ++ } ++ ++ if (zmw_rx_buf_readb(dev, buf, offset+4) <= 0x2 ) ++ { ++ //Channel Switch ++ //if Channel Switch Count = 0 , STA should change channel immediately. ++ //if Channel Switch Count > 0 , STA should change channel after TBTT*count ++ //But it won't be accurate to let driver calculate TBTT*count, and the value of ++ //Channel Switch Count will decrease by one each when continue receving beacon ++ //So we change channel here when we receive count <=2. ++ ++ zfHpDeleteAllowChannel(dev, wd->sta.currentFrequency); ++ wd->frequency = zfChNumToFreq(dev, zmw_rx_buf_readb(dev, buf, offset+3), 0); ++ //zfHpAddAllowChannel(dev, wd->frequency); ++ zm_debug_msg1("CWY - jump to frequency = ", wd->frequency); ++ zfCoreSetFrequency(dev, wd->frequency); ++ wd->sta.DFSDisableTx = FALSE; ++ /* Increase rxBeaconCount to prevent beacon lost */ ++ if (zfStaIsConnected(dev)) ++ { ++ wd->sta.rxBeaconCount = 1 << 6; // 2 times of check would pass ++ } ++ //start tx dma to transmit packet ++ ++ //if (zmw_rx_buf_readb(dev, buf, offset+3) != wd->frequency) ++ //{ ++ // //ZDDbgPrint(("Radar Detect by AP\n")); ++ // zfCoreSetFrequency(); ++ // ProcessRadarDetectEvent(Adapter); ++ // Set_RF_Channel(Adapter, SwRfd->Rfd->RxBuffer[index+3], (UCHAR)Adapter->RF_Mode, 1); ++ // Adapter->CardSetting.Channel = SwRfd->Rfd->RxBuffer[index+3]; ++ // Adapter->SaveChannel = Adapter->CardSetting.Channel; ++ // Adapter->UtilityChannel = Adapter->CardSetting.Channel; ++ //} ++ } ++ } ++ ++} ++/* TODO : process 802.11h Transmission Power Control */ ++void zfStaUpdateDot11HTPC(zdev_t* dev, zbuf_t* buf) ++{ ++} ++ ++/* IBSS power-saving mode */ ++void zfStaIbssPSCheckState(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t i, frameCtrl; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( !zfStaIsConnected(dev) ) ++ { ++ return; ++ } ++ ++ if ( wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ return ; ++ } ++ ++ /* check BSSID */ ++ if ( !zfRxBufferEqualToStr(dev, buf, (u8_t*) wd->sta.bssid, ++ ZM_WLAN_HEADER_A3_OFFSET, 6) ) ++ { ++ return; ++ } ++ ++ frameCtrl = zmw_rx_buf_readb(dev, buf, 1); ++ ++ /* check power management bit */ ++ if ( frameCtrl & ZM_BIT_4 ) ++ { ++ for(i=1; ista.staPSList.entity[i].bUsed ) ++ { ++ continue; ++ } ++ ++ /* check source address */ ++ if ( zfRxBufferEqualToStr(dev, buf, ++ wd->sta.staPSList.entity[i].macAddr, ++ ZM_WLAN_HEADER_A2_OFFSET, 6) ) ++ { ++ return; ++ } ++ } ++ ++ for(i=1; ista.staPSList.entity[i].bUsed ) ++ { ++ wd->sta.staPSList.entity[i].bUsed = TRUE; ++ wd->sta.staPSList.entity[i].bDataQueued = FALSE; ++ break; ++ } ++ } ++ ++ if ( i == ZM_MAX_PS_STA ) ++ { ++ /* STA list is full */ ++ return; ++ } ++ ++ zfCopyFromRxBuffer(dev, buf, wd->sta.staPSList.entity[i].macAddr, ++ ZM_WLAN_HEADER_A2_OFFSET, 6); ++ ++ if ( wd->sta.staPSList.count == 0 ) ++ { ++ // enable ATIM window ++ //zfEnableAtimWindow(dev); ++ } ++ ++ wd->sta.staPSList.count++; ++ } ++ else if ( wd->sta.staPSList.count ) ++ { ++ for(i=1; ista.staPSList.entity[i].bUsed ) ++ { ++ if ( zfRxBufferEqualToStr(dev, buf, ++ wd->sta.staPSList.entity[i].macAddr, ++ ZM_WLAN_HEADER_A2_OFFSET, 6) ) ++ { ++ wd->sta.staPSList.entity[i].bUsed = FALSE; ++ wd->sta.staPSList.count--; ++ ++ if ( wd->sta.staPSList.entity[i].bDataQueued ) ++ { ++ /* send queued data */ ++ } ++ } ++ } ++ } ++ ++ if ( wd->sta.staPSList.count == 0 ) ++ { ++ /* disable ATIM window */ ++ //zfDisableAtimWindow(dev); ++ } ++ ++ } ++} ++ ++/* IBSS power-saving mode */ ++u8_t zfStaIbssPSQueueData(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t i; ++ u16_t da[3]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( !zfStaIsConnected(dev) ) ++ { ++ return 0; ++ } ++ ++ if ( wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ return 0; ++ } ++ ++ if ( wd->sta.staPSList.count == 0 && wd->sta.powerSaveMode <= ZM_STA_PS_NONE ) ++ { ++ return 0; ++ } ++ ++ /* DA */ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ da[0] = zmw_tx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ da[1] = zmw_tx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET + 2); ++ da[2] = zmw_tx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET + 4); ++#else ++ da[0] = zmw_tx_buf_readh(dev, buf, 0); ++ da[1] = zmw_tx_buf_readh(dev, buf, 2); ++ da[2] = zmw_tx_buf_readh(dev, buf, 4); ++#endif ++ ++ if ( ZM_IS_MULTICAST_OR_BROADCAST(da) ) ++ { ++ wd->sta.staPSList.entity[0].bDataQueued = TRUE; ++ wd->sta.ibssPSDataQueue[wd->sta.ibssPSDataCount++] = buf; ++ return 1; ++ } ++ ++ // Unicast packet... ++ ++ for(i=1; ista.staPSList.entity[i].macAddr, ++ (u8_t*) da, 6) ) ++ { ++ wd->sta.staPSList.entity[i].bDataQueued = TRUE; ++ wd->sta.ibssPSDataQueue[wd->sta.ibssPSDataCount++] = buf; ++ ++ return 1; ++ } ++ } ++ ++#if 0 ++ if ( wd->sta.powerSaveMode > ZM_STA_PS_NONE ) ++ { ++ wd->sta.staPSDataQueue[wd->sta.staPSDataCount++] = buf; ++ ++ return 1; ++ } ++#endif ++ ++ return 0; ++} ++ ++/* IBSS power-saving mode */ ++void zfStaIbssPSSend(zdev_t* dev) ++{ ++ u8_t i; ++ u16_t bcastAddr[3] = {0xffff, 0xffff, 0xffff}; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( !zfStaIsConnected(dev) ) ++ { ++ return ; ++ } ++ ++ if ( wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ return ; ++ } ++ ++ for(i=0; ista.staPSList.entity[i].bDataQueued ) ++ { ++ if ( i == 0 ) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ATIM, ++ bcastAddr, ++ 0, 0, 0); ++ } ++ else if ( wd->sta.staPSList.entity[i].bUsed ) ++ { ++ // Send ATIM to prevent the peer to go to sleep ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ATIM, ++ (u16_t*) wd->sta.staPSList.entity[i].macAddr, ++ 0, 0, 0); ++ } ++ ++ wd->sta.staPSList.entity[i].bDataQueued = FALSE; ++ } ++ } ++ ++ for(i=0; ista.ibssPSDataCount; i++) ++ { ++ zfTxSendEth(dev, wd->sta.ibssPSDataQueue[i], 0, ++ ZM_EXTERNAL_ALLOC_BUF, 0); ++ } ++ ++ wd->sta.ibssPrevPSDataCount = wd->sta.ibssPSDataCount; ++ wd->sta.ibssPSDataCount = 0; ++} ++ ++ ++void zfStaReconnect(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE && ++ wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ return; ++ } ++ ++ if ( (zfStaIsConnected(dev))||(zfStaIsConnecting(dev)) ) ++ { ++ return; ++ } ++ ++ if ( wd->sta.bChannelScan ) ++ { ++ return; ++ } ++ ++ /* Recover zero SSID length */ ++ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) && (wd->ws.ssidLen == 0)) ++ { ++ zm_debug_msg0("zfStaReconnect: NOT Support!! Set SSID to any BSS"); ++ /* ANY BSS */ ++ zmw_enter_critical_section(dev); ++ wd->sta.ssid[0] = 0; ++ wd->sta.ssidLen = 0; ++ zmw_leave_critical_section(dev); ++ } ++ ++ // RAY: To ensure no TX pending before re-connecting ++ zfFlushVtxq(dev); ++ zfWlanEnable(dev); ++ zfScanMgrScanAck(dev); ++} ++ ++void zfStaTimer100ms(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( (wd->tick % 10) == 0 ) ++ { ++ zfPushVtxq(dev); ++// zfPowerSavingMgrMain(dev); ++ } ++} ++ ++ ++void zfStaCheckRxBeacon(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) && (zfStaIsConnected(dev))) ++ { ++ if (wd->beaconInterval == 0) ++ { ++ wd->beaconInterval = 100; ++ } ++ if ( (wd->tick % ((wd->beaconInterval * 10) / ZM_MS_PER_TICK)) == 0 ) ++ { ++ /* Check rxBeaconCount */ ++ if (wd->sta.rxBeaconCount == 0) ++ { ++ if (wd->sta.beaconMissState == 1) ++ { ++ /*notify AP that we left*/ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, wd->sta.bssid, 3, 0, 0); ++ /* Beacon Lost */ ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_BEACON_MISS, ++ wd->sta.bssid, 0); ++ } ++ else ++ { ++ wd->sta.beaconMissState = 1; ++ /* Reset channel */ ++ zfCoreSetFrequencyExV2(dev, wd->frequency, wd->BandWidth40, ++ wd->ExtOffset, NULL, 1); ++ } ++ } ++ else ++ { ++ wd->sta.beaconMissState = 0; ++ } ++ wd->sta.rxBeaconCount = 0; ++ } ++ } ++} ++ ++ ++ ++void zfStaCheckConnectTimeout(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE ) ++ { ++ return; ++ } ++ ++ if ( !zfStaIsConnecting(dev) ) ++ { ++ return; ++ } ++ ++ zmw_enter_critical_section(dev); ++ if ( (wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_OPEN)|| ++ (wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_1)|| ++ (wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_2)|| ++ (wd->sta.connectState == ZM_STA_CONN_STATE_ASSOCIATE) ) ++ { ++ if ( (wd->tick - wd->sta.connectTimer) > ZM_INTERVAL_CONNECT_TIMEOUT ) ++ { ++ if ( wd->sta.connectByReasso ) ++ { ++ wd->sta.failCntOfReasso++; ++ if ( wd->sta.failCntOfReasso > 2 ) ++ { ++ wd->sta.connectByReasso = FALSE; ++ } ++ } ++ ++ wd->sta.connectState = ZM_STA_CONN_STATE_NONE; ++ zm_debug_msg1("connect timeout, state = ", wd->sta.connectState); ++ //zfiWlanDisable(dev); ++ goto failed; ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ return; ++ ++failed: ++ zmw_leave_critical_section(dev); ++ if(wd->sta.authMode == ZM_AUTH_MODE_AUTO) ++ { // Fix some AP not send authentication failed message to sta and lead to connect timeout ! ++ wd->sta.connectTimeoutCount++; ++ } ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_TIMEOUT, wd->sta.bssid, 2); ++ return; ++} ++ ++void zfMmStaTimeTick(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* airopeek */ ++ if (wd->wlanMode != ZM_MODE_AP && !wd->swSniffer) ++ { ++ if ( wd->tick & 1 ) ++ { ++ zfTimerCheckAndHandle(dev); ++ } ++ ++ zfStaCheckRxBeacon(dev); ++ zfStaTimer100ms(dev); ++ zfStaCheckConnectTimeout(dev); ++ zfPowerSavingMgrMain(dev); ++ } ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ /* ++ * add by honda ++ */ ++ zfAggScanAndClear(dev, wd->tick); ++#endif ++} ++ ++void zfStaSendBeacon(zdev_t* dev) ++{ ++ zbuf_t* buf; ++ u16_t offset, seq; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ //zm_debug_msg0("\n"); ++ ++ /* TBD : Maximum size of beacon */ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_debug_msg0("Allocate beacon buffer failed"); ++ return; ++ } ++ ++ offset = 0; ++ /* wlan header */ ++ /* Frame control */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0x0080); ++ offset+=2; ++ /* Duration */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0x0000); ++ offset+=2; ++ /* Address 1 */ ++ zmw_tx_buf_writeh(dev, buf, offset, 0xffff); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, 0xffff); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, 0xffff); ++ offset+=2; ++ /* Address 2 */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[0]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[1]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->macAddr[2]); ++ offset+=2; ++ /* Address 3 */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[0]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[1]); ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.bssid[2]); ++ offset+=2; ++ ++ /* Sequence number */ ++ zmw_enter_critical_section(dev); ++ seq = ((wd->mmseq++)<<4); ++ zmw_leave_critical_section(dev); ++ zmw_tx_buf_writeh(dev, buf, offset, seq); ++ offset+=2; ++ ++ /* 24-31 Time Stamp : hardware will fill this field */ ++ offset+=8; ++ ++ /* Beacon Interval */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->beaconInterval); ++ offset+=2; ++ ++ /* Capability */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[0]); ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.capability[1]); ++ ++ /* SSID */ ++ offset = zfStaAddIeSsid(dev, buf, offset); ++ ++ if(wd->frequency <= ZM_CH_G_14) // 2.4 GHz b+g ++ { ++ ++ /* Support Rate */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_CCK); ++ ++ /* DS parameter set */ ++ offset = zfMmAddIeDs(dev, buf, offset); ++ ++ offset = zfStaAddIeIbss(dev, buf, offset); ++ ++ if( wd->wfc.bIbssGMode ++ && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) // Only accompany with enabling a mode . ++ { ++ /* ERP Information */ ++ wd->erpElement = 0; ++ offset = zfMmAddIeErp(dev, buf, offset); ++ } ++ ++ /* TODO : country information */ ++ /* RSN */ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) ++ { ++ offset = zfwStaAddIeWpaRsn(dev, buf, offset, ZM_WLAN_FRAME_TYPE_AUTH); ++ } ++ ++ if( wd->wfc.bIbssGMode ++ && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) // Only accompany with enabling a mode . ++ { ++ /* Enable G Mode */ ++ /* Extended Supported Rates */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_EXTENDED_RATE, ZM_RATE_SET_OFDM); ++ } ++ } ++ else // 5GHz a ++ { ++ /* Support Rate a Mode */ ++ offset = zfMmAddIeSupportRate(dev, buf, offset, ++ ZM_WLAN_EID_SUPPORT_RATE, ZM_RATE_SET_OFDM); ++ ++ /* DS parameter set */ ++ offset = zfMmAddIeDs(dev, buf, offset); ++ ++ offset = zfStaAddIeIbss(dev, buf, offset); ++ ++ /* TODO : country information */ ++ /* RSN */ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) ++ { ++ offset = zfwStaAddIeWpaRsn(dev, buf, offset, ZM_WLAN_FRAME_TYPE_AUTH); ++ } ++ } ++ ++ if ( wd->wlanMode != ZM_MODE_IBSS ) ++ { ++ /* TODO : Need to check if it is ok */ ++ /* HT Capabilities Info */ ++ offset = zfMmAddHTCapability(dev, buf, offset); ++ ++ /* Extended HT Capabilities Info */ ++ offset = zfMmAddExtendedHTCapability(dev, buf, offset); ++ } ++ ++ if ( wd->sta.ibssAdditionalIESize ) ++ offset = zfStaAddIbssAdditionalIE(dev, buf, offset); ++ ++ /* 1212 : write to beacon fifo */ ++ /* 1221 : write to share memory */ ++ zfHpSendBeacon(dev, buf, offset); ++ ++ /* Free beacon buffer */ ++ //zfwBufFree(dev, buf, 0); ++} ++ ++void zfStaSignalStatistic(zdev_t* dev, u8_t SignalStrength, u8_t SignalQuality) //CWYang(+) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Add Your Code to Do Works Like Moving Average Here */ ++ wd->SignalStrength = (wd->SignalStrength * 7 + SignalStrength * 3)/10; ++ wd->SignalQuality = (wd->SignalQuality * 7 + SignalQuality * 3)/10; ++ ++} ++ ++struct zsBssInfo* zfStaFindBssInfo(zdev_t* dev, zbuf_t* buf, struct zsWlanProbeRspFrameHeader *pProbeRspHeader) ++{ ++ u8_t i; ++ u8_t j; ++ u8_t k; ++ u8_t isMatched, length, channel; ++ u16_t offset, frequency; ++ struct zsBssInfo* pBssInfo; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ((pBssInfo = wd->sta.bssList.head) == NULL) ++ { ++ return NULL; ++ } ++ ++ for( i=0; ista.bssList.bssCount; i++ ) ++ { ++ //zm_debug_msg2("check pBssInfo = ", pBssInfo); ++ ++ /* Check BSSID */ ++ for( j=0; j<6; j++ ) ++ { ++ if ( pBssInfo->bssid[j] != pProbeRspHeader->bssid[j] ) ++ { ++ break; ++ } ++ } ++ ++ /* Check SSID */ ++ if (j == 6) ++ { ++ if (pProbeRspHeader->ssid[1] <= 32) ++ { ++ /* compare length and ssid */ ++ isMatched = 1; ++ if((pProbeRspHeader->ssid[1] != 0) && (pBssInfo->ssid[1] != 0)) ++ { ++ for( k=1; kssid[1] + 1; k++ ) ++ { ++ if ( pBssInfo->ssid[k] != pProbeRspHeader->ssid[k] ) ++ { ++ isMatched = 0; ++ break; ++ } ++ } ++ } ++ } ++ else ++ { ++ isMatched = 0; ++ } ++ } ++ else ++ { ++ isMatched = 0; ++ } ++ ++ /* Check channel */ ++ /* Add check channel to solve the bug #31222 */ ++ if (isMatched) { ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_DS)) != 0xffff) { ++ if ((length = zmw_rx_buf_readb(dev, buf, offset+1)) == 1) { ++ channel = zmw_rx_buf_readb(dev, buf, offset+2); ++ if (zfHpIsAllowedChannel(dev, zfChNumToFreq(dev, channel, 0)) == 0) { ++ frequency = 0; ++ } else { ++ frequency = zfChNumToFreq(dev, channel, 0);; ++ } ++ } else { ++ frequency = 0; ++ } ++ } else { ++ frequency = wd->sta.currentFrequency; ++ } ++ ++ if (frequency != 0) { ++ if ( ((frequency > 3000) && (pBssInfo->frequency > 3000)) ++ || ((frequency < 3000) && (pBssInfo->frequency < 3000)) ) { ++ /* redundant */ ++ break; ++ } ++ } ++ } ++ ++ pBssInfo = pBssInfo->next; ++ } ++ ++ if ( i == wd->sta.bssList.bssCount ) ++ { ++ pBssInfo = NULL; ++ } ++ ++ return pBssInfo; ++} ++ ++u8_t zfStaInitBssInfo(zdev_t* dev, zbuf_t* buf, ++ struct zsWlanProbeRspFrameHeader *pProbeRspHeader, ++ struct zsBssInfo* pBssInfo, struct zsAdditionInfo* AddInfo, u8_t type) ++{ ++ u8_t length, channel, is5G; ++ u16_t i, offset; ++ u8_t apQosInfo; ++ u16_t eachIElength = 0; ++ u16_t accumulateLen = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ((type == 1) && ((pBssInfo->flag & ZM_BSS_INFO_VALID_BIT) != 0)) ++ { ++ goto zlUpdateRssi; ++ } ++ ++ /* get SSID */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) == 0xffff ) ++ { ++ zm_debug_msg0("EID(SSID) not found"); ++ goto zlError; ++ } ++ ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ ++ { ++ u8_t Show_Flag = 0; ++ zfwGetShowZeroLengthSSID(dev, &Show_Flag); ++ ++ if(Show_Flag) ++ { ++ if (length > ZM_MAX_SSID_LENGTH ) ++ { ++ zm_debug_msg0("EID(SSID) is invalid"); ++ goto zlError; ++ } ++ } ++ else ++ { ++ if ( length == 0 || length > ZM_MAX_SSID_LENGTH ) ++ { ++ zm_debug_msg0("EID(SSID) is invalid"); ++ goto zlError; ++ } ++ ++ } ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->ssid, offset, length+2); ++ ++ /* get DS parameter */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_DS)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if ( length != 1 ) ++ { ++ zm_msg0_mm(ZM_LV_0, "Abnormal DS Param Set IE"); ++ goto zlError; ++ } ++ channel = zmw_rx_buf_readb(dev, buf, offset+2); ++ ++ if (zfHpIsAllowedChannel(dev, zfChNumToFreq(dev, channel, 0)) == 0) ++ { ++ goto zlError2; ++ } ++ ++ pBssInfo->frequency = zfChNumToFreq(dev, channel, 0); // auto check ++ pBssInfo->channel = channel; ++ ++ ++ } ++ else ++ { ++ /* DS parameter not found */ ++ pBssInfo->frequency = wd->sta.currentFrequency; ++ pBssInfo->channel = zfChFreqToNum(wd->sta.currentFrequency, &is5G); ++ } ++ ++ /* initialize security type */ ++ pBssInfo->securityType = ZM_SECURITY_TYPE_NONE; ++ ++ /* get macaddr */ ++ for( i=0; i<6; i++ ) ++ { ++ pBssInfo->macaddr[i] = pProbeRspHeader->sa[i]; ++ } ++ ++ /* get bssid */ ++ for( i=0; i<6; i++ ) ++ { ++ pBssInfo->bssid[i] = pProbeRspHeader->bssid[i]; ++ } ++ ++ /* get timestamp */ ++ for( i=0; i<8; i++ ) ++ { ++ pBssInfo->timeStamp[i] = pProbeRspHeader->timeStamp[i]; ++ } ++ ++ /* get beacon interval */ ++ pBssInfo->beaconInterval[0] = pProbeRspHeader->beaconInterval[0]; ++ pBssInfo->beaconInterval[1] = pProbeRspHeader->beaconInterval[1]; ++ ++ /* get capability */ ++ pBssInfo->capability[0] = pProbeRspHeader->capability[0]; ++ pBssInfo->capability[1] = pProbeRspHeader->capability[1]; ++ ++ /* Copy frame body */ ++ offset = 36; // Copy from the start of variable IE ++ pBssInfo->frameBodysize = zfwBufGetSize(dev, buf)-offset; ++ if (pBssInfo->frameBodysize > (ZM_MAX_PROBE_FRAME_BODY_SIZE-1)) ++ { ++ pBssInfo->frameBodysize = ZM_MAX_PROBE_FRAME_BODY_SIZE-1; ++ } ++ accumulateLen = 0; ++ do ++ { ++ eachIElength = zmw_rx_buf_readb(dev, buf, offset + accumulateLen+1) + 2; //Len+(EID+Data) ++ ++ if ( (eachIElength >= 2) ++ && ((accumulateLen + eachIElength) <= pBssInfo->frameBodysize) ) ++ { ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->frameBody+accumulateLen, offset+accumulateLen, eachIElength); ++ accumulateLen+=(u16_t)eachIElength; ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_1, "probersp frameBodysize abnormal"); ++ break; ++ } ++ } ++ while(accumulateLen < pBssInfo->frameBodysize); ++ pBssInfo->frameBodysize = accumulateLen; ++ ++ /* get supported rates */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_SUPPORT_RATE)) == 0xffff ) ++ { ++ zm_debug_msg0("EID(supported rates) not found"); ++ goto zlError; ++ } ++ ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if ( length == 0 || length > ZM_MAX_SUPP_RATES_IE_SIZE) ++ { ++ zm_msg0_mm(ZM_LV_0, "Supported rates IE length abnormal"); ++ goto zlError; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->supportedRates, offset, length+2); ++ ++ ++ ++ /* get Country information */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_COUNTRY)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length > ZM_MAX_COUNTRY_INFO_SIZE) ++ { ++ length = ZM_MAX_COUNTRY_INFO_SIZE; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->countryInfo, offset, length+2); ++ /* check 802.11d support data */ ++ if (wd->sta.b802_11D) ++ { ++ zfHpGetRegulationTablefromISO(dev, (u8_t *)&pBssInfo->countryInfo, 3); ++ /* only set regulatory one time */ ++ wd->sta.b802_11D = 0; ++ } ++ } ++ ++ /* get ERP information */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) != 0xffff ) ++ { ++ pBssInfo->erp = zmw_rx_buf_readb(dev, buf, offset+2); ++ } ++ ++ /* get extended supported rates */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_RATE)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length > ZM_MAX_SUPP_RATES_IE_SIZE) ++ { ++ zm_msg0_mm(ZM_LV_0, "Extended rates IE length abnormal"); ++ goto zlError; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->extSupportedRates, offset, length+2); ++ } ++ else ++ { ++ pBssInfo->extSupportedRates[0] = 0; ++ pBssInfo->extSupportedRates[1] = 0; ++ } ++ ++ /* get WPA IE */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_WPA_IE)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length > ZM_MAX_IE_SIZE) ++ { ++ length = ZM_MAX_IE_SIZE; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->wpaIe, offset, length+2); ++ pBssInfo->securityType = ZM_SECURITY_TYPE_WPA; ++ } ++ else ++ { ++ pBssInfo->wpaIe[1] = 0; ++ } ++ ++ /* get WPS IE */ ++ if ((offset = zfFindWifiElement(dev, buf, 4, 0xff)) != 0xffff) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length > ZM_MAX_WPS_IE_SIZE ) ++ { ++ length = ZM_MAX_WPS_IE_SIZE; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->wscIe, offset, length+2); ++ } ++ else ++ { ++ pBssInfo->wscIe[1] = 0; ++ } ++ ++ /* get SuperG IE */ ++ if ((offset = zfFindSuperGElement(dev, buf, ZM_WLAN_EID_VENDOR_PRIVATE)) != 0xffff) ++ { ++ pBssInfo->apCap |= ZM_SuperG_AP; ++ } ++ ++ /* get XR IE */ ++ if ((offset = zfFindXRElement(dev, buf, ZM_WLAN_EID_VENDOR_PRIVATE)) != 0xffff) ++ { ++ pBssInfo->apCap |= ZM_XR_AP; ++ } ++ ++ /* get RSN IE */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_RSN_IE)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length > ZM_MAX_IE_SIZE) ++ { ++ length = ZM_MAX_IE_SIZE; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->rsnIe, offset, length+2); ++ pBssInfo->securityType = ZM_SECURITY_TYPE_WPA; ++ } ++ else ++ { ++ pBssInfo->rsnIe[1] = 0; ++ } ++#ifdef ZM_ENABLE_CENC ++ /* get CENC IE */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_CENC_IE)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ if (length > ZM_MAX_IE_SIZE ) ++ { ++ length = ZM_MAX_IE_SIZE; ++ } ++ zfCopyFromRxBuffer(dev, buf, pBssInfo->cencIe, offset, length+2); ++ pBssInfo->securityType = ZM_SECURITY_TYPE_CENC; ++ pBssInfo->capability[0] &= 0xffef; ++ } ++ else ++ { ++ pBssInfo->cencIe[1] = 0; ++ } ++#endif //ZM_ENABLE_CENC ++ /* get WME Parameter IE, probe rsp may contain WME parameter element */ ++ //if ( wd->bQoSEnable ) ++ { ++ if ((offset = zfFindWifiElement(dev, buf, 2, 1)) != 0xffff) ++ { ++ apQosInfo = zmw_rx_buf_readb(dev, buf, offset+8) & 0x80; ++ pBssInfo->wmeSupport = 1 | apQosInfo; ++ } ++ else if ((offset = zfFindWifiElement(dev, buf, 2, 0)) != 0xffff) ++ { ++ apQosInfo = zmw_rx_buf_readb(dev, buf, offset+8) & 0x80; ++ pBssInfo->wmeSupport = 1 | apQosInfo; ++ } ++ else ++ { ++ pBssInfo->wmeSupport = 0; ++ } ++ } ++ //CWYang(+) ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff) ++ { ++ /* 11n AP */ ++ pBssInfo->EnableHT = 1; ++ if (zmw_rx_buf_readb(dev, buf, offset+1) & 0x02) ++ { ++ pBssInfo->enableHT40 = 1; ++ } ++ else ++ { ++ pBssInfo->enableHT40 = 0; ++ } ++ ++ if (zmw_rx_buf_readb(dev, buf, offset+1) & 0x40) ++ { ++ pBssInfo->SG40 = 1; ++ } ++ else ++ { ++ pBssInfo->SG40 = 0; ++ } ++ } ++ else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff) ++ { ++ /* 11n AP */ ++ pBssInfo->EnableHT = 1; ++ pBssInfo->apCap |= ZM_All11N_AP; ++ if (zmw_rx_buf_readb(dev, buf, offset+2) & 0x02) ++ { ++ pBssInfo->enableHT40 = 1; ++ } ++ else ++ { ++ pBssInfo->enableHT40 = 0; ++ } ++ ++ if (zmw_rx_buf_readb(dev, buf, offset+2) & 0x40) ++ { ++ pBssInfo->SG40 = 1; ++ } ++ else ++ { ++ pBssInfo->SG40 = 0; ++ } ++ } ++ else ++ { ++ pBssInfo->EnableHT = 0; ++ } ++ /* HT information */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff) ++ { ++ /* atheros pre n */ ++ pBssInfo->extChOffset = zmw_rx_buf_readb(dev, buf, offset+2) & 0x03; ++ } ++ else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTINFORMATION)) != 0xffff) ++ { ++ /* pre n 2.0 standard */ ++ pBssInfo->extChOffset = zmw_rx_buf_readb(dev, buf, offset+3) & 0x03; ++ } ++ else ++ { ++ pBssInfo->extChOffset = 0; ++ } ++ ++ if ( (pBssInfo->enableHT40 == 1) ++ && ((pBssInfo->extChOffset != 1) && (pBssInfo->extChOffset != 3)) ) ++ { ++ pBssInfo->enableHT40 = 0; ++ } ++ ++ if (pBssInfo->enableHT40 == 1) ++ { ++ if (zfHpIsAllowedChannel(dev, pBssInfo->frequency+((pBssInfo->extChOffset==1)?20:-20)) == 0) ++ { ++ /* if extension channel is not an allowed channel, treat AP as non-HT mode */ ++ pBssInfo->EnableHT = 0; ++ pBssInfo->enableHT40 = 0; ++ pBssInfo->extChOffset = 0; ++ } ++ } ++ ++ /* get ATH Extended Capability */ ++ if ( ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff)&& ++ ((offset = zfFindBrdcmMrvlRlnkExtCap(dev, buf)) == 0xffff)) ++ ++ { ++ pBssInfo->athOwlAp = 1; ++ } ++ else ++ { ++ pBssInfo->athOwlAp = 0; ++ } ++ ++ /* get Broadcom Extended Capability */ ++ if ( (pBssInfo->EnableHT == 1) //((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff) ++ && ((offset = zfFindBroadcomExtCap(dev, buf)) != 0xffff) ) ++ { ++ pBssInfo->broadcomHTAp = 1; ++ } ++ else ++ { ++ pBssInfo->broadcomHTAp = 0; ++ } ++ ++ /* get Marvel Extended Capability */ ++ if ((offset = zfFindMarvelExtCap(dev, buf)) != 0xffff) ++ { ++ pBssInfo->marvelAp = 1; ++ } ++ else ++ { ++ pBssInfo->marvelAp = 0; ++ } ++ ++ /* get ATIM window */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_IBSS)) != 0xffff ) ++ { ++ pBssInfo->atimWindow = zmw_rx_buf_readh(dev, buf,offset+2); ++ } ++ ++ /* Fit for support mode */ ++ if (pBssInfo->frequency > 3000) { ++ if (wd->supportMode & ZM_WIRELESS_MODE_5_N) { ++#if 0 ++ if (wd->supportMode & ZM_WIRELESS_MODE_5_54) { ++ /* support mode: a, n */ ++ /* do nothing */ ++ } else { ++ /* support mode: n */ ++ /* reject non-n bss info */ ++ if (!pBssInfo->EnableHT) { ++ goto zlError2; ++ } ++ } ++#endif ++ } else { ++ if (wd->supportMode & ZM_WIRELESS_MODE_5_54) { ++ /* support mode: a */ ++ /* delete n mode information */ ++ pBssInfo->EnableHT = 0; ++ pBssInfo->enableHT40 = 0; ++ pBssInfo->apCap &= (~ZM_All11N_AP); ++ pBssInfo->extChOffset = 0; ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_EID_HT_CAPABILITY); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTCAPABILITY); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTINFORMATION); ++ } else { ++ /* support mode: none */ ++ goto zlError2; ++ } ++ } ++ } else { ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_N) { ++#if 0 ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_54) { ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_11) { ++ /* support mode: b, g, n */ ++ /* do nothing */ ++ } else { ++ /* support mode: g, n */ ++ /* reject b-only bss info */ ++ if ( (!pBssInfo->EnableHT) ++ && (pBssInfo->extSupportedRates[1] == 0) ) { ++ goto zlError2; ++ } ++ } ++ } else { ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_11) { ++ /* support mode: b, n */ ++ /* 1. reject g-only bss info ++ * 2. if non g-only, delete g mode information ++ */ ++ if ( !pBssInfo->EnableHT ) { ++ if ( zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->supportedRates) ++ || zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->extSupportedRates) ) { ++ goto zlError2; ++ } else { ++ zfGatherBMode(dev, pBssInfo->supportedRates, ++ pBssInfo->extSupportedRates); ++ pBssInfo->erp = 0; ++ ++ pBssInfo->frameBodysize = zfRemoveElement(dev, ++ pBssInfo->frameBody, pBssInfo->frameBodysize, ++ ZM_WLAN_EID_ERP); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, ++ pBssInfo->frameBody, pBssInfo->frameBodysize, ++ ZM_WLAN_EID_EXTENDED_RATE); ++ ++ pBssInfo->frameBodysize = zfUpdateElement(dev, ++ pBssInfo->frameBody, pBssInfo->frameBodysize, ++ pBssInfo->supportedRates); ++ } ++ } ++ } else { ++ /* support mode: n */ ++ /* reject non-n bss info */ ++ if (!pBssInfo->EnableHT) { ++ goto zlError2; ++ } ++ } ++ } ++#endif ++ } else { ++ /* delete n mode information */ ++ pBssInfo->EnableHT = 0; ++ pBssInfo->enableHT40 = 0; ++ pBssInfo->apCap &= (~ZM_All11N_AP); ++ pBssInfo->extChOffset = 0; ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_EID_HT_CAPABILITY); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTCAPABILITY); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, pBssInfo->frameBody, ++ pBssInfo->frameBodysize, ZM_WLAN_PREN2_EID_HTINFORMATION); ++ ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_54) { ++#if 0 ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_11) { ++ /* support mode: b, g */ ++ /* delete n mode information */ ++ } else { ++ /* support mode: g */ ++ /* delete n mode information */ ++ /* reject b-only bss info */ ++ if (pBssInfo->extSupportedRates[1] == 0) { ++ goto zlError2; ++ } ++ } ++#endif ++ } else { ++ if (wd->supportMode & ZM_WIRELESS_MODE_24_11) { ++ /* support mode: b */ ++ /* delete n mode information */ ++ if ( zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->supportedRates) ++ || zfIsGOnlyMode(dev, pBssInfo->frequency, pBssInfo->extSupportedRates) ) { ++ goto zlError2; ++ } else { ++ zfGatherBMode(dev, pBssInfo->supportedRates, ++ pBssInfo->extSupportedRates); ++ pBssInfo->erp = 0; ++ ++ pBssInfo->frameBodysize = zfRemoveElement(dev, ++ pBssInfo->frameBody, pBssInfo->frameBodysize, ++ ZM_WLAN_EID_ERP); ++ pBssInfo->frameBodysize = zfRemoveElement(dev, ++ pBssInfo->frameBody, pBssInfo->frameBodysize, ++ ZM_WLAN_EID_EXTENDED_RATE); ++ ++ pBssInfo->frameBodysize = zfUpdateElement(dev, ++ pBssInfo->frameBody, pBssInfo->frameBodysize, ++ pBssInfo->supportedRates); ++ } ++ } else { ++ /* support mode: none */ ++ goto zlError2; ++ } ++ } ++ } ++ } ++ ++ pBssInfo->flag |= ZM_BSS_INFO_VALID_BIT; ++ ++zlUpdateRssi: ++ /* Update Timer information */ ++ pBssInfo->tick = wd->tick; ++ ++ /* Update ERP information */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_ERP)) != 0xffff ) ++ { ++ pBssInfo->erp = zmw_rx_buf_readb(dev, buf, offset+2); ++ } ++ ++ if( (s8_t)pBssInfo->signalStrength < (s8_t)AddInfo->Tail.Data.SignalStrength1 ) ++ { ++ /* Update signal strength */ ++ pBssInfo->signalStrength = (u8_t)AddInfo->Tail.Data.SignalStrength1; ++ /* Update signal quality */ ++ pBssInfo->signalQuality = (u8_t)(AddInfo->Tail.Data.SignalStrength1 * 2); ++ ++ /* Update the sorting value */ ++ pBssInfo->sortValue = zfComputeBssInfoWeightValue(dev, ++ (pBssInfo->supportedRates[6] + pBssInfo->extSupportedRates[0]), ++ pBssInfo->EnableHT, ++ pBssInfo->enableHT40, ++ pBssInfo->signalStrength); ++ } ++ ++ return 0; ++ ++zlError: ++ ++ return 1; ++ ++zlError2: ++ ++ return 2; ++} ++ ++void zfStaProcessBeacon(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) //CWYang(m) ++{ ++ /* Parse TIM and send PS-POLL in power saving mode */ ++ struct zsWlanBeaconFrameHeader* pBeaconHeader; ++ struct zsBssInfo* pBssInfo; ++ u8_t pBuf[sizeof(struct zsWlanBeaconFrameHeader)]; ++ u8_t bssid[6]; ++ int res; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* sta routine jobs */ ++ zfStaProtErpMonitor(dev, buf); /* check protection mode */ ++ ++ if (zfStaIsConnected(dev)) ++ { ++ ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid); ++ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ if ( zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A2_OFFSET, 6) ) ++ { ++ zfPowerSavingMgrProcessBeacon(dev, buf); ++ zfStaUpdateWmeParameter(dev, buf); ++ if (wd->sta.DFSEnable) ++ zfStaUpdateDot11HDFS(dev, buf); ++ if (wd->sta.TPCEnable) ++ zfStaUpdateDot11HTPC(dev, buf); ++ /* update signal strength and signal quality */ ++ zfStaSignalStatistic(dev, AddInfo->Tail.Data.SignalStrength1, ++ AddInfo->Tail.Data.SignalQuality); //CWYang(+) ++ wd->sta.rxBeaconCount++; ++ } ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ if ( zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A3_OFFSET, 6) ) ++ { ++ int res; ++ struct zsPartnerNotifyEvent event; ++ ++ zm_debug_msg0("20070916 Receive opposite Beacon!"); ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssReceiveBeaconCount++; ++ zmw_leave_critical_section(dev); ++ ++ res = zfStaSetOppositeInfoFromRxBuf(dev, buf); ++ if ( res == 0 ) ++ { ++ // New peer station found. Notify the wrapper now ++ zfInitPartnerNotifyEvent(dev, buf, &event); ++ if (wd->zfcbIbssPartnerNotify != NULL) ++ { ++ wd->zfcbIbssPartnerNotify(dev, 1, &event); ++ } ++ } ++ /* update signal strength and signal quality */ ++ zfStaSignalStatistic(dev, AddInfo->Tail.Data.SignalStrength1, ++ AddInfo->Tail.Data.SignalQuality); //CWYang(+) ++ } ++ //else if ( wd->sta.ibssPartnerStatus == ZM_IBSS_PARTNER_LOST ) ++ // Why does this happen in IBSS?? The impact of Vista since ++ // we need to tell it the BSSID ++#if 0 ++ else if ( wd->sta.oppositeCount == 0 ) ++ { /* IBSS merge if SSID matched */ ++ if ( (offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) != 0xffff ) ++ { ++ if ( (wd->sta.ssidLen == zmw_buf_readb(dev, buf, offset+1))&& ++ (zfRxBufferEqualToStr(dev, buf, wd->sta.ssid, ++ offset+2, wd->sta.ssidLen)) ) ++ { ++ capabilityInfo = zmw_buf_readh(dev, buf, 34); ++ ++ if ( capabilityInfo & ZM_BIT_1 ) ++ { ++ if ( (wd->sta.capability[0] & ZM_BIT_4) == ++ (capabilityInfo & ZM_BIT_4) ) ++ { ++ zm_debug_msg0("IBSS merge"); ++ zfCopyFromRxBuffer(dev, buf, bssid, ++ ZM_WLAN_HEADER_A3_OFFSET, 6); ++ zfUpdateBssid(dev, bssid); ++ } ++ } ++ } ++ } ++ } ++#endif ++ } ++ } ++ ++ /* return if not channel scan */ ++ if ( !wd->sta.bChannelScan ) ++ { ++ goto zlReturn; ++ } ++ ++ zfCopyFromRxBuffer(dev, buf, pBuf, 0, sizeof(struct zsWlanBeaconFrameHeader)); ++ pBeaconHeader = (struct zsWlanBeaconFrameHeader*) pBuf; ++ ++ zmw_enter_critical_section(dev); ++ ++ //zm_debug_msg1("bss count = ", wd->sta.bssList.bssCount); ++ ++ pBssInfo = zfStaFindBssInfo(dev, buf, pBeaconHeader); ++ ++ if ( pBssInfo == NULL ) ++ { ++ /* Allocate a new entry if BSS not in the scan list */ ++ pBssInfo = zfBssInfoAllocate(dev); ++ if (pBssInfo != NULL) ++ { ++ res = zfStaInitBssInfo(dev, buf, pBeaconHeader, pBssInfo, AddInfo, 0); ++ //zfDumpSSID(pBssInfo->ssid[1], &(pBssInfo->ssid[2])); ++ if ( res != 0 ) ++ { ++ zfBssInfoFree(dev, pBssInfo); ++ } ++ else ++ { ++ zfBssInfoInsertToList(dev, pBssInfo); ++ } ++ } ++ } ++ else ++ { ++ res = zfStaInitBssInfo(dev, buf, pBeaconHeader, pBssInfo, AddInfo, 1); ++ if (res == 2) ++ { ++ zfBssInfoRemoveFromList(dev, pBssInfo); ++ zfBssInfoFree(dev, pBssInfo); ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ int idx; ++ ++ // It would reset the alive counter if the peer station is found! ++ zfStaFindFreeOpposite(dev, (u16_t *)pBssInfo->macaddr, &idx); ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++zlReturn: ++ ++ return; ++} ++ ++ ++void zfAuthFreqCompleteCb(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_COMPLETED) ++ { ++ zm_debug_msg0("ZM_STA_CONN_STATE_ASSOCIATE"); ++ wd->sta.connectTimer = wd->tick; ++ wd->sta.connectState = ZM_STA_CONN_STATE_ASSOCIATE; ++ } ++ ++ zmw_leave_critical_section(dev); ++ return; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfProcessAuth */ ++/* Process authenticate management frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : auth frame buffer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++/* Note : AP allows one authenticating STA at a time, does not */ ++/* support multiple authentication process. Make sure */ ++/* authentication state machine will not be blocked due */ ++/* to incompleted authentication handshake. */ ++void zfStaProcessAuth(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId) ++{ ++ struct zsWlanAuthFrameHeader* pAuthFrame; ++ u8_t pBuf[sizeof(struct zsWlanAuthFrameHeader)]; ++ u32_t p1, p2; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ if ( !zfStaIsConnecting(dev) ) ++ { ++ return; ++ } ++ ++ pAuthFrame = (struct zsWlanAuthFrameHeader*) pBuf; ++ zfCopyFromRxBuffer(dev, buf, pBuf, 0, sizeof(struct zsWlanAuthFrameHeader)); ++ ++ if ( wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_OPEN ) ++ { ++ if ( (zmw_le16_to_cpu(pAuthFrame->seq) == 2)&& ++ (zmw_le16_to_cpu(pAuthFrame->algo) == 0)&& ++ (zmw_le16_to_cpu(pAuthFrame->status) == 0) ) ++ { ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.connectTimer = wd->tick; ++ zm_debug_msg0("ZM_STA_CONN_STATE_AUTH_COMPLETED"); ++ wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_COMPLETED; ++ zmw_leave_critical_section(dev); ++ ++ //Set channel according to AP's configuration ++ //Move to here because of Cisco 11n AP feature ++ zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, ++ wd->ExtOffset, zfAuthFreqCompleteCb); ++ ++ /* send association frame */ ++ if ( wd->sta.connectByReasso ) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_REASOCREQ, ++ wd->sta.bssid, 0, 0, 0); ++ } ++ else ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ASOCREQ, ++ wd->sta.bssid, 0, 0, 0); ++ } ++ ++ ++ } ++ else ++ { ++ zm_debug_msg1("authentication failed, status = ", ++ pAuthFrame->status); ++ ++ if (wd->sta.authMode == ZM_AUTH_MODE_AUTO) ++ { ++ wd->sta.bIsSharedKey = 1; ++ zfStaStartConnect(dev, wd->sta.bIsSharedKey); ++ } ++ else ++ { ++ zm_debug_msg0("ZM_STA_STATE_DISCONNECT"); ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3); ++ } ++ } ++ } ++ else if ( wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_1 ) ++ { ++ if ( (zmw_le16_to_cpu(pAuthFrame->algo) == 1) && ++ (zmw_le16_to_cpu(pAuthFrame->seq) == 2) && ++ (zmw_le16_to_cpu(pAuthFrame->status) == 0)) ++ //&& (pAuthFrame->challengeText[1] <= 255) ) ++ { ++ zfMemoryCopy(wd->sta.challengeText, pAuthFrame->challengeText, ++ pAuthFrame->challengeText[1]+2); ++ ++ /* send the 3rd authentication frame */ ++ p1 = 0x30001; ++ p2 = 0; ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_AUTH, ++ wd->sta.bssid, p1, p2, 0); ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.connectTimer = wd->tick; ++ ++ zm_debug_msg0("ZM_STA_SUB_STATE_AUTH_SHARE_2"); ++ wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_SHARE_2; ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ zm_debug_msg1("authentication failed, status = ", ++ pAuthFrame->status); ++ ++ zm_debug_msg0("ZM_STA_STATE_DISCONNECT"); ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3); ++ } ++ } ++ else if ( wd->sta.connectState == ZM_STA_CONN_STATE_AUTH_SHARE_2 ) ++ { ++ if ( (zmw_le16_to_cpu(pAuthFrame->algo) == 1)&& ++ (zmw_le16_to_cpu(pAuthFrame->seq) == 4)&& ++ (zmw_le16_to_cpu(pAuthFrame->status) == 0) ) ++ { ++ //Set channel according to AP's configuration ++ //Move to here because of Cisco 11n AP feature ++ zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, ++ wd->ExtOffset, NULL); ++ ++ /* send association frame */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_ASOCREQ, ++ wd->sta.bssid, 0, 0, 0); ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.connectTimer = wd->tick; ++ ++ zm_debug_msg0("ZM_STA_SUB_STATE_ASSOCIATE"); ++ wd->sta.connectState = ZM_STA_CONN_STATE_ASSOCIATE; ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ zm_debug_msg1("authentication failed, status = ", ++ pAuthFrame->status); ++ ++ zm_debug_msg0("ZM_STA_STATE_DISCONNECT"); ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3); ++ } ++ } ++ else ++ { ++ zm_debug_msg0("unknown case"); ++ } ++} ++ ++void zfStaProcessAsocReq(zdev_t* dev, zbuf_t* buf, u16_t* src, u16_t apId) ++{ ++ ++ return; ++} ++ ++void zfStaProcessAsocRsp(zdev_t* dev, zbuf_t* buf) ++{ ++ struct zsWlanAssoFrameHeader* pAssoFrame; ++ u8_t pBuf[sizeof(struct zsWlanAssoFrameHeader)]; ++ u16_t offset; ++ u32_t i; ++ u32_t oneTxStreamCap; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( !zfStaIsConnecting(dev) ) ++ { ++ return; ++ } ++ ++ pAssoFrame = (struct zsWlanAssoFrameHeader*) pBuf; ++ zfCopyFromRxBuffer(dev, buf, pBuf, 0, sizeof(struct zsWlanAssoFrameHeader)); ++ ++ if ( wd->sta.connectState == ZM_STA_CONN_STATE_ASSOCIATE ) ++ { ++ if ( pAssoFrame->status == 0 ) ++ { ++ zm_debug_msg0("ZM_STA_STATE_CONNECTED"); ++ ++ if (wd->sta.EnableHT == 1) ++ { ++ wd->sta.wmeConnected = 1; ++ } ++ if ((wd->sta.wmeEnabled & ZM_STA_WME_ENABLE_BIT) != 0) //WME enabled ++ { ++ /* Asoc rsp may contain WME parameter element */ ++ if ((offset = zfFindWifiElement(dev, buf, 2, 1)) != 0xffff) ++ { ++ zm_debug_msg0("WME enable"); ++ wd->sta.wmeConnected = 1; ++ if ((wd->sta.wmeEnabled & ZM_STA_UAPSD_ENABLE_BIT) != 0) ++ { ++ if ((zmw_rx_buf_readb(dev, buf, offset+8) & 0x80) != 0) ++ { ++ zm_debug_msg0("UAPSD enable"); ++ wd->sta.qosInfo = wd->sta.wmeQosInfo; ++ } ++ } ++ ++ zfStaUpdateWmeParameter(dev, buf); ++ } ++ } ++ ++ ++ //Store asoc response frame body, for VISTA only ++ wd->sta.asocRspFrameBodySize = zfwBufGetSize(dev, buf)-24; ++ if (wd->sta.asocRspFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) ++ { ++ wd->sta.asocRspFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; ++ } ++ for (i=0; ista.asocRspFrameBodySize; i++) ++ { ++ wd->sta.asocRspFrameBody[i] = zmw_rx_buf_readb(dev, buf, i+24); ++ } ++ ++ zfStaStoreAsocRspIe(dev, buf); ++ if (wd->sta.EnableHT && ++ ((wd->sta.ie.HtCap.HtCapInfo & HTCAP_SupChannelWidthSet) != 0) && ++ (wd->ExtOffset != 0)) ++ { ++ wd->sta.htCtrlBandwidth = 1; ++ } ++ else ++ { ++ wd->sta.htCtrlBandwidth = 0; ++ } ++ ++ //Set channel according to AP's configuration ++ //zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, ++ // wd->ExtOffset, NULL); ++ ++ if (wd->sta.EnableHT == 1) ++ { ++ wd->addbaComplete = 0; ++ ++ if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_ENCRY_EN) == 0 && ++ (wd->sta.SWEncryptEnable & ZM_SW_WEP_ENCRY_EN) == 0) ++ { ++ wd->addbaCount = 1; ++ zfAggSendAddbaRequest(dev, wd->sta.bssid, 0, 0); ++ zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_ADDBA, 100); ++ } ++ } ++ ++ /* set RIFS support */ ++ if(wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_RIFSMode) ++ { ++ wd->sta.HT2040 = 1; ++// zfHpSetRifs(dev, wd->sta.EnableHT, 1, (wd->sta.currentFrequency < 3000)? 1:0); ++ } ++ ++ wd->sta.aid = pAssoFrame->aid & 0x3fff; ++ wd->sta.oppositeCount = 0; /* reset opposite count */ ++ zfStaSetOppositeInfoFromRxBuf(dev, buf); ++ ++ wd->sta.rxBeaconCount = 16; ++ ++ zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); ++ wd->sta.connPowerInHalfDbm = zfHpGetTransmitPower(dev); ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ if (wd->sta.EnableHT != 0) /* 11n */ ++ { ++ oneTxStreamCap = (zfHpCapability(dev) & ZM_HP_CAP_11N_ONE_TX_STREAM); ++ if (wd->sta.htCtrlBandwidth == 1) /* HT40*/ ++ { ++ if(oneTxStreamCap) /* one Tx stream */ ++ { ++ if (wd->sta.SG40) ++ { ++ wd->CurrentTxRateKbps = 150000; ++ wd->CurrentRxRateKbps = 300000; ++ } ++ else ++ { ++ wd->CurrentTxRateKbps = 135000; ++ wd->CurrentRxRateKbps = 270000; ++ } ++ } ++ else /* Two Tx streams */ ++ { ++ if (wd->sta.SG40) ++ { ++ wd->CurrentTxRateKbps = 300000; ++ wd->CurrentRxRateKbps = 300000; ++ } ++ else ++ { ++ wd->CurrentTxRateKbps = 270000; ++ wd->CurrentRxRateKbps = 270000; ++ } ++ } ++ } ++ else /* HT20 */ ++ { ++ if(oneTxStreamCap) /* one Tx stream */ ++ { ++ wd->CurrentTxRateKbps = 650000; ++ wd->CurrentRxRateKbps = 130000; ++ } ++ else /* Two Tx streams */ ++ { ++ wd->CurrentTxRateKbps = 130000; ++ wd->CurrentRxRateKbps = 130000; ++ } ++ } ++ } ++ else /* 11abg */ ++ { ++ if (wd->sta.connection_11b != 0) ++ { ++ wd->CurrentTxRateKbps = 11000; ++ wd->CurrentRxRateKbps = 11000; ++ } ++ else ++ { ++ wd->CurrentTxRateKbps = 54000; ++ wd->CurrentRxRateKbps = 54000; ++ } ++ } ++ ++ ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); ++ } ++ wd->sta.connectByReasso = TRUE; ++ wd->sta.failCntOfReasso = 0; ++ ++ zfPowerSavingMgrConnectNotify(dev); ++ ++ /* Disable here because fixed rate is only for test, TBD. */ ++ //if (wd->sta.EnableHT) ++ //{ ++ // wd->txMCS = 7; //Rate = 65Mbps ++ // wd->txMT = 2; // Ht rate ++ // wd->enableAggregation = 2; // Enable Aggregation ++ //} ++ } ++ else ++ { ++ zm_debug_msg1("association failed, status = ", ++ pAssoFrame->status); ++ ++ zm_debug_msg0("ZM_STA_STATE_DISCONNECT"); ++ wd->sta.connectByReasso = FALSE; ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_ASOC_FAILED, wd->sta.bssid, 3); ++ } ++ } ++ ++} ++ ++void zfStaStoreAsocRspIe(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t offset; ++ u32_t i; ++ u16_t length; ++ u8_t *htcap; ++ u8_t asocBw40 = 0; ++ u8_t asocExtOffset = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; ista.asocRspFrameBodySize; i++) ++ { ++ wd->sta.asocRspFrameBody[i] = zmw_rx_buf_readb(dev, buf, i+24); ++ } ++ ++ /* HT capabilities: 28 octets */ ++ if ( ((wd->sta.currentFrequency > 3000) && !(wd->supportMode & ZM_WIRELESS_MODE_5_N)) ++ || ((wd->sta.currentFrequency < 3000) && !(wd->supportMode & ZM_WIRELESS_MODE_24_N)) ) ++ { ++ /* not 11n AP */ ++ htcap = (u8_t *)&wd->sta.ie.HtCap; ++ for (i=0; i<28; i++) ++ { ++ htcap[i] = 0; ++ } ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ return; ++ } ++ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_HT_CAPABILITY)) != 0xffff) ++ { ++ /* atheros pre n */ ++ zm_debug_msg0("atheros pre n"); ++ htcap = (u8_t *)&wd->sta.ie.HtCap; ++ htcap[0] = zmw_rx_buf_readb(dev, buf, offset); ++ htcap[1] = 26; ++ for (i=1; i<=26; i++) ++ { ++ htcap[i+1] = zmw_rx_buf_readb(dev, buf, offset + i); ++ zm_msg2_mm(ZM_LV_1, "ASOC: HT Capabilities, htcap=", htcap[i+1]); ++ } ++ } ++ else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTCAPABILITY)) != 0xffff) ++ { ++ /* pre n 2.0 standard */ ++ zm_debug_msg0("pre n 2.0 standard"); ++ htcap = (u8_t *)&wd->sta.ie.HtCap; ++ for (i=0; i<28; i++) ++ { ++ htcap[i] = zmw_rx_buf_readb(dev, buf, offset + i); ++ zm_msg2_mm(ZM_LV_1, "ASOC: HT Capabilities, htcap=", htcap[i]); ++ } ++ } ++ else ++ { ++ /* not 11n AP */ ++ htcap = (u8_t *)&wd->sta.ie.HtCap; ++ for (i=0; i<28; i++) ++ { ++ htcap[i] = 0; ++ } ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ return; ++ } ++ ++ asocBw40 = (u8_t)((wd->sta.ie.HtCap.HtCapInfo & HTCAP_SupChannelWidthSet) >> 1); ++ ++ /* HT information */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_EXTENDED_HT_CAPABILITY)) != 0xffff) ++ { ++ /* atheros pre n */ ++ zm_debug_msg0("atheros pre n HTINFO"); ++ length = 22; ++ htcap = (u8_t *)&wd->sta.ie.HtInfo; ++ htcap[0] = zmw_rx_buf_readb(dev, buf, offset); ++ htcap[1] = 22; ++ for (i=1; i<=22; i++) ++ { ++ htcap[i+1] = zmw_rx_buf_readb(dev, buf, offset + i); ++ zm_msg2_mm(ZM_LV_1, "ASOC: HT Info, htinfo=", htcap[i+1]); ++ } ++ } ++ else if ((offset = zfFindElement(dev, buf, ZM_WLAN_PREN2_EID_HTINFORMATION)) != 0xffff) ++ { ++ /* pre n 2.0 standard */ ++ zm_debug_msg0("pre n 2.0 standard HTINFO"); ++ length = zmw_rx_buf_readb(dev, buf, offset + 1); ++ htcap = (u8_t *)&wd->sta.ie.HtInfo; ++ for (i=0; i<24; i++) ++ { ++ htcap[i] = zmw_rx_buf_readb(dev, buf, offset + i); ++ zm_msg2_mm(ZM_LV_1, "ASOC: HT Info, htinfo=", htcap[i]); ++ } ++ } ++ else ++ { ++ zm_debug_msg0("no HTINFO"); ++ htcap = (u8_t *)&wd->sta.ie.HtInfo; ++ for (i=0; i<24; i++) ++ { ++ htcap[i] = 0; ++ } ++ } ++ asocExtOffset = wd->sta.ie.HtInfo.ChannelInfo & ExtHtCap_ExtChannelOffsetBelow; ++ ++ if ((wd->sta.EnableHT == 1) && (asocBw40 == 1) && ((asocExtOffset == 1) || (asocExtOffset == 3))) ++ { ++ wd->BandWidth40 = asocBw40; ++ wd->ExtOffset = asocExtOffset; ++ } ++ else ++ { ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ } ++ ++ return; ++} ++ ++void zfStaProcessDeauth(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t apMacAddr[3]; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ /* STA : if SA=connected AP then disconnect with AP */ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ apMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET); ++ apMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2); ++ apMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4); ++ if ((apMacAddr[0] == wd->sta.bssid[0]) && (apMacAddr[1] == wd->sta.bssid[1]) && (apMacAddr[2] == wd->sta.bssid[2])) ++ { ++ if (zfwBufGetSize(dev, buf) >= 24+2) //not a malformed frame ++ { ++ if ( zfStaIsConnected(dev) ) ++ { ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_DEAUTH, wd->sta.bssid, 2); ++ } ++ else if (zfStaIsConnecting(dev)) ++ { ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED, wd->sta.bssid, 3); ++ } ++ else ++ { ++ } ++ } ++ } ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ u16_t peerMacAddr[3]; ++ u8_t peerIdx; ++ s8_t res; ++ ++ if ( zfStaIsConnected(dev) ) ++ { ++ peerMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); ++ peerMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2); ++ peerMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4); ++ ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, peerMacAddr, &peerIdx); ++ if ( res == 0 ) ++ { ++ wd->sta.oppositeInfo[peerIdx].aliveCounter = 0; ++ } ++ zmw_leave_critical_section(dev); ++ } ++ } ++} ++ ++void zfStaProcessDisasoc(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t apMacAddr[3]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* STA : if SA=connected AP then disconnect with AP */ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ apMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET); ++ apMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2); ++ apMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4); ++ ++ if ((apMacAddr[0] == wd->sta.bssid[0]) && (apMacAddr[1] == wd->sta.bssid[1]) && (apMacAddr[2] == wd->sta.bssid[2])) ++ { ++ if (zfwBufGetSize(dev, buf) >= 24+2) //not a malformed frame ++ { ++ if ( zfStaIsConnected(dev) ) ++ { ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_DISASOC, wd->sta.bssid, 2); ++ } ++ else ++ { ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_ASOC_FAILED, wd->sta.bssid, 3); ++ } ++ } ++ } ++ } ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfProcessProbeReq */ ++/* Process probe request management frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : auth frame buffer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfStaProcessProbeReq(zdev_t* dev, zbuf_t* buf, u16_t* src) ++{ ++ u16_t offset; ++ u8_t len; ++ u16_t i, j; ++ u16_t sendFlag; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* check mode : AP/IBSS */ ++ if ((wd->wlanMode != ZM_MODE_AP) || (wd->wlanMode != ZM_MODE_IBSS)) ++ { ++ zm_msg0_mm(ZM_LV_3, "Ignore probe req"); ++ return; ++ } ++ ++ /* check SSID */ ++ if ((offset = zfFindElement(dev, buf, ZM_WLAN_EID_SSID)) == 0xffff) ++ { ++ zm_msg0_mm(ZM_LV_3, "probe req SSID not found"); ++ return; ++ } ++ ++ len = zmw_rx_buf_readb(dev, buf, offset+1); ++ ++ for (i=0; iap.apBitmap & (i<ap.hideSsid[i] == 0)) ++ { ++ sendFlag = 1; ++ } ++ /* Not broadcast SSID */ ++ else if (wd->ap.ssidLen[i] == len) ++ { ++ for (j=0; jap.ssid[i][j]) ++ { ++ break; ++ } ++ } ++ if (j == len) ++ { ++ sendFlag = 1; ++ } ++ } ++ if (sendFlag == 1) ++ { ++ /* Send probe response */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBERSP, src, i, 0, 0); ++ } ++ } ++ } ++} ++ ++void zfStaProcessProbeRsp(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* AddInfo) ++{ ++ /* return if not channel scan */ ++ // Probe response is sent with unicast. Is this required? ++ // IBSS would send probe request and the code below would prevent ++ // the probe response from handling. ++ #if 0 ++ zmw_get_wlan_dev(dev); ++ ++ if ( !wd->sta.bChannelScan ) ++ { ++ return; ++ } ++ #endif ++ ++ zfProcessProbeRsp(dev, buf, AddInfo); ++} ++ ++void zfIBSSSetupBssDesc(zdev_t *dev) ++{ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ u8_t i; ++#endif ++ struct zsBssInfo *pBssInfo; ++ u16_t offset = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ pBssInfo = &wd->sta.ibssBssDesc; ++ zfZeroMemory((u8_t *)pBssInfo, sizeof(struct zsBssInfo)); ++ ++ pBssInfo->signalStrength = 100; ++ ++ zfMemoryCopy((u8_t *)pBssInfo->macaddr, (u8_t *)wd->macAddr,6); ++ zfMemoryCopy((u8_t *)pBssInfo->bssid, (u8_t *)wd->sta.bssid, 6); ++ ++ pBssInfo->beaconInterval[0] = (u8_t)(wd->beaconInterval) ; ++ pBssInfo->beaconInterval[1] = (u8_t)((wd->beaconInterval) >> 8) ; ++ ++ pBssInfo->capability[0] = wd->sta.capability[0]; ++ pBssInfo->capability[1] = wd->sta.capability[1]; ++ ++ pBssInfo->ssid[0] = ZM_WLAN_EID_SSID; ++ pBssInfo->ssid[1] = wd->sta.ssidLen; ++ zfMemoryCopy((u8_t *)&pBssInfo->ssid[2], (u8_t *)wd->sta.ssid, wd->sta.ssidLen); ++ zfMemoryCopy((u8_t *)&pBssInfo->frameBody[offset], (u8_t *)pBssInfo->ssid, ++ wd->sta.ssidLen + 2); ++ offset += wd->sta.ssidLen + 2; ++ ++ /* support rate */ ++ ++ /* DS parameter set */ ++ pBssInfo->channel = zfChFreqToNum(wd->frequency, NULL); ++ pBssInfo->frequency = wd->frequency; ++ pBssInfo->atimWindow = wd->sta.atimWindow; ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) ++ { ++ u8_t rsn[64]= ++ { ++ /* Element ID */ ++ 0x30, ++ /* Length */ ++ 0x14, ++ /* Version */ ++ 0x01, 0x00, ++ /* Group Cipher Suite, default=TKIP */ ++ 0x00, 0x0f, 0xac, 0x04, ++ /* Pairwise Cipher Suite Count */ ++ 0x01, 0x00, ++ /* Pairwise Cipher Suite, default=TKIP */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* Authentication and Key Management Suite Count */ ++ 0x01, 0x00, ++ /* Authentication type, default=PSK */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* RSN capability */ ++ 0x00, 0x00 ++ }; ++ ++ /* Overwrite Group Cipher Suite by AP's setting */ ++ zfMemoryCopy(rsn+4, zgWpa2AesOui, 4); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ /* Overwrite Pairwise Cipher Suite by AES */ ++ zfMemoryCopy(rsn+10, zgWpa2AesOui, 4); ++ } ++ ++ // RSN element id ++ pBssInfo->frameBody[offset++] = ZM_WLAN_EID_RSN_IE ; ++ ++ // RSN length ++ pBssInfo->frameBody[offset++] = rsn[1] ; ++ ++ // RSN information ++ for(i=0; iframeBody[offset++] = rsn[i+2] ; ++ } ++ ++ zfMemoryCopy(pBssInfo->rsnIe, rsn, rsn[1]+2); ++ } ++#endif ++} ++ ++void zfIbssConnectNetwork(zdev_t* dev) ++{ ++ struct zsBssInfo* pBssInfo; ++ struct zsBssInfo tmpBssInfo; ++ u8_t macAddr[6], bssid[6], bssNotFound = TRUE; ++ u16_t i, j=100; ++ u16_t k; ++ struct zsPartnerNotifyEvent event; ++ u32_t channelFlags; ++ u16_t oppositeWepStatus; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ /* change state to CONNECTING and stop the channel scanning */ ++ zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTING); ++ zfPowerSavingMgrWakeup(dev); ++ ++ /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME STA default. */ ++ zfUpdateDefaultQosParameter(dev, 0); ++ ++ wd->sta.bProtectionMode = FALSE; ++ zfHpSetSlotTime(dev, 1); ++ ++ /* ESS bit off */ ++ wd->sta.capability[0] &= ~ZM_BIT_0; ++ /* IBSS bit on */ ++ wd->sta.capability[0] |= ZM_BIT_1; ++ /* not not use short slot time */ ++ wd->sta.capability[1] &= ~ZM_BIT_2; ++ ++ wd->sta.wmeConnected = 0; ++ wd->sta.psMgr.tempWakeUp = 0; ++ wd->sta.qosInfo = 0; ++ wd->sta.EnableHT = 0; ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ ++ if ( wd->sta.bssList.bssCount ) ++ { ++ //Reorder BssList by RSSI--CWYang(+) ++ zfBssInfoReorderList(dev); ++ ++ zmw_enter_critical_section(dev); ++ ++ pBssInfo = wd->sta.bssList.head; ++ ++ for(i=0; ista.bssList.bssCount; i++) ++ { ++ // 20070806 #1 Privacy bit ++ if ( pBssInfo->capability[0] & ZM_BIT_4 ) ++ { // Privacy Ibss network ++// zm_debug_msg0("Privacy bit on"); ++ oppositeWepStatus = ZM_ENCRYPTION_WEP_ENABLED; ++ ++ if ( pBssInfo->rsnIe[1] != 0 ) ++ { ++ if ( (pBssInfo->rsnIe[7] == 0x01) || (pBssInfo->rsnIe[7] == 0x05) ) ++ { // WEP-40 & WEP-104 ++// zm_debug_msg0("WEP40 or WEP104"); ++ oppositeWepStatus = ZM_ENCRYPTION_WEP_ENABLED; ++ } ++ else if ( pBssInfo->rsnIe[7] == 0x02 ) ++ { // TKIP ++// zm_debug_msg0("TKIP"); ++ oppositeWepStatus = ZM_ENCRYPTION_TKIP; ++ } ++ else if ( pBssInfo->rsnIe[7] == 0x04 ) ++ { // AES ++// zm_debug_msg0("CCMP-AES"); ++ oppositeWepStatus = ZM_ENCRYPTION_AES; ++ } ++ } ++ } ++ else ++ { ++// zm_debug_msg0("Privacy bit off"); ++ oppositeWepStatus = ZM_ENCRYPTION_WEP_DISABLED; ++ } ++ ++ if ( (zfMemoryIsEqual(&(pBssInfo->ssid[2]), wd->sta.ssid, ++ wd->sta.ssidLen))&& ++ (wd->sta.ssidLen == pBssInfo->ssid[1])&& ++ (oppositeWepStatus == wd->sta.wepStatus) ) ++ { ++ /* Check support mode */ ++ if (pBssInfo->frequency > 3000) { ++ if ( (pBssInfo->EnableHT == 1) ++ || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP ++ { ++ channelFlags = CHANNEL_A_HT; ++ if (pBssInfo->enableHT40 == 1) { ++ channelFlags |= CHANNEL_HT40; ++ } ++ } else { ++ channelFlags = CHANNEL_A; ++ } ++ } else { ++ if ( (pBssInfo->EnableHT == 1) ++ || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP ++ { ++ channelFlags = CHANNEL_G_HT; ++ if(pBssInfo->enableHT40 == 1) { ++ channelFlags |= CHANNEL_HT40; ++ } ++ } else { ++ if (pBssInfo->extSupportedRates[1] == 0) { ++ channelFlags = CHANNEL_B; ++ } else { ++ channelFlags = CHANNEL_G; ++ } ++ } ++ } ++ ++ if ( ((channelFlags == CHANNEL_B) && (wd->connectMode & ZM_BIT_0)) ++ || ((channelFlags == CHANNEL_G) && (wd->connectMode & ZM_BIT_1)) ++ || ((channelFlags == CHANNEL_A) && (wd->connectMode & ZM_BIT_2)) ++ || ((channelFlags & CHANNEL_HT20) && (wd->connectMode & ZM_BIT_3)) ) ++ { ++ pBssInfo = pBssInfo->next; ++ continue; ++ } ++ ++ /* Bypass DFS channel */ ++ if (zfHpIsDfsChannelNCS(dev, pBssInfo->frequency)) ++ { ++ zm_debug_msg0("Bypass DFS channel"); ++ continue; ++ } ++ ++ /* check IBSS bit */ ++ if ( pBssInfo->capability[0] & ZM_BIT_1 ) ++ { ++ /* may check timestamp here */ ++ j = i; ++ break; ++ } ++ } ++ ++ pBssInfo = pBssInfo->next; ++ } ++ ++ if ((j < wd->sta.bssList.bssCount) && (pBssInfo != NULL)) ++ { ++ zfwMemoryCopy((u8_t*)&tmpBssInfo, (u8_t*)(pBssInfo), sizeof(struct zsBssInfo)); ++ pBssInfo = &tmpBssInfo; ++ } ++ else ++ { ++ pBssInfo = NULL; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ //if ( j < wd->sta.bssList.bssCount ) ++ if (pBssInfo != NULL) ++ { ++ int res; ++ ++ zm_debug_msg0("IBSS found"); ++ ++ /* Found IBSS, reset bssNotFoundCount */ ++ zmw_enter_critical_section(dev); ++ wd->sta.bssNotFoundCount = 0; ++ zmw_leave_critical_section(dev); ++ ++ bssNotFound = FALSE; ++ wd->sta.atimWindow = pBssInfo->atimWindow; ++ wd->frequency = pBssInfo->frequency; ++ //wd->sta.flagFreqChanging = 1; ++ zfCoreSetFrequency(dev, wd->frequency); ++ zfUpdateBssid(dev, pBssInfo->bssid); ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_ZERO); ++ zfUpdateSupportRate(dev, pBssInfo->supportedRates); ++ zfUpdateSupportRate(dev, pBssInfo->extSupportedRates); ++ wd->beaconInterval = pBssInfo->beaconInterval[0] + ++ (((u16_t) pBssInfo->beaconInterval[1]) << 8); ++ ++ if (wd->beaconInterval == 0) ++ { ++ wd->beaconInterval = 100; ++ } ++ ++ /* rsn information element */ ++ if ( pBssInfo->rsnIe[1] != 0 ) ++ { ++ zfMemoryCopy(wd->sta.rsnIe, pBssInfo->rsnIe, ++ pBssInfo->rsnIe[1]+2); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ /* If not use RSNA , run traditional */ ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssWpa2Psk = 1; ++ zmw_leave_critical_section(dev); ++#endif ++ } ++ else ++ { ++ wd->sta.rsnIe[1] = 0; ++ } ++ ++ /* privacy bit */ ++ if ( pBssInfo->capability[0] & ZM_BIT_4 ) ++ { ++ wd->sta.capability[0] |= ZM_BIT_4; ++ } ++ else ++ { ++ wd->sta.capability[0] &= ~ZM_BIT_4; ++ } ++ ++ /* preamble type */ ++ wd->preambleTypeInUsed = wd->preambleType; ++ if ( wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_AUTO ) ++ { ++ if (pBssInfo->capability[0] & ZM_BIT_5) ++ { ++ wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; ++ } ++ else ++ { ++ wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_LONG; ++ } ++ } ++ ++ if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_LONG) ++ { ++ wd->sta.capability[0] &= ~ZM_BIT_5; ++ } ++ else ++ { ++ wd->sta.capability[0] |= ZM_BIT_5; ++ } ++ ++ wd->sta.beaconFrameBodySize = pBssInfo->frameBodysize + 12; ++ ++ if (wd->sta.beaconFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) ++ { ++ wd->sta.beaconFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; ++ } ++ ++ for (k=0; k<8; k++) ++ { ++ wd->sta.beaconFrameBody[k] = pBssInfo->timeStamp[k]; ++ } ++ wd->sta.beaconFrameBody[8] = pBssInfo->beaconInterval[0]; ++ wd->sta.beaconFrameBody[9] = pBssInfo->beaconInterval[1]; ++ wd->sta.beaconFrameBody[10] = pBssInfo->capability[0]; ++ wd->sta.beaconFrameBody[11] = pBssInfo->capability[1]; ++ //for (k=12; ksta.beaconFrameBodySize; k++) ++ for (k=0; kframeBodysize; k++) ++ { ++ wd->sta.beaconFrameBody[k+12] = pBssInfo->frameBody[k]; ++ } ++ ++ zmw_enter_critical_section(dev); ++ res = zfStaSetOppositeInfoFromBSSInfo(dev, pBssInfo); ++ if ( res == 0 ) ++ { ++ zfMemoryCopy(event.bssid, (u8_t *)(pBssInfo->bssid), 6); ++ zfMemoryCopy(event.peerMacAddr, (u8_t *)(pBssInfo->macaddr), 6); ++ } ++ zmw_leave_critical_section(dev); ++ ++ //zfwIbssPartnerNotify(dev, 1, &event); ++ goto connect_done; ++ } ++ } ++ ++ /* IBSS not found */ ++ if ( bssNotFound ) ++ { ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ u16_t offset ; ++#endif ++ if ( wd->sta.ibssJoinOnly ) ++ { ++ zm_debug_msg0("IBSS join only...retry..."); ++ goto retry_ibss; ++ } ++ ++ if(wd->sta.bssNotFoundCount<2) ++ { ++ zmw_enter_critical_section(dev); ++ zm_debug_msg1("IBSS not found, do sitesurvey!! bssNotFoundCount=", wd->sta.bssNotFoundCount); ++ wd->sta.bssNotFoundCount++; ++ zmw_leave_critical_section(dev); ++ goto retry_ibss; ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ /* Fail IBSS found, TODO create IBSS */ ++ wd->sta.bssNotFoundCount = 0; ++ zmw_leave_critical_section(dev); ++ } ++ ++ ++ if (zfHpIsDfsChannel(dev, wd->frequency)) ++ { ++ wd->frequency = zfHpFindFirstNonDfsChannel(dev, wd->frequency > 3000); ++ } ++ ++ if( wd->ws.autoSetFrequency == 0 ) ++ { /* Auto set frequency */ ++ zm_debug_msg1("Create Ad Hoc Network Band ", wd->ws.adhocMode); ++ wd->frequency = zfFindCleanFrequency(dev, wd->ws.adhocMode); ++ wd->ws.autoSetFrequency = 0xff; ++ } ++ zm_debug_msg1("IBSS not found, created one in channel ", wd->frequency); ++ ++ wd->sta.ibssBssIsCreator = 1; ++ ++ //wd->sta.flagFreqChanging = 1; ++ zfCoreSetFrequency(dev, wd->frequency); ++ if (wd->sta.bDesiredBssid == TRUE) ++ { ++ for (k=0; k<6; k++) ++ { ++ bssid[k] = wd->sta.desiredBssid[k]; ++ } ++ } ++ else ++ { ++ #if 1 ++ macAddr[0] = (wd->macAddr[0] & 0xff); ++ macAddr[1] = (wd->macAddr[0] >> 8); ++ macAddr[2] = (wd->macAddr[1] & 0xff); ++ macAddr[3] = (wd->macAddr[1] >> 8); ++ macAddr[4] = (wd->macAddr[2] & 0xff); ++ macAddr[5] = (wd->macAddr[2] >> 8); ++ zfGenerateRandomBSSID(dev, (u8_t *)wd->macAddr, (u8_t *)bssid); ++ #else ++ for (k=0; k<6; k++) ++ { ++ bssid[k] = (u8_t) zfGetRandomNumber(dev, 0); ++ } ++ bssid[0] &= ~ZM_BIT_0; ++ bssid[0] |= ZM_BIT_1; ++ #endif ++ } ++ ++ zfUpdateBssid(dev, bssid); ++ //wd->sta.atimWindow = 0x0a; ++ ++ /* rate information */ ++ if(wd->frequency <= ZM_CH_G_14) // 2.4 GHz b+g ++ { ++ if ( wd->wfc.bIbssGMode ++ && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) ++ { ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_IBSS_AG); ++ } ++ else ++ { ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_IBSS_B); ++ } ++ } else { ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_IBSS_AG); ++ } ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED ) ++ { ++ wd->sta.capability[0] &= ~ZM_BIT_4; ++ } ++ else ++ { ++ wd->sta.capability[0] |= ZM_BIT_4; ++ } ++ ++ wd->preambleTypeInUsed = wd->preambleType; ++ if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_LONG) ++ { ++ wd->sta.capability[0] &= ~ZM_BIT_5; ++ } ++ else ++ { ++ wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; ++ wd->sta.capability[0] |= ZM_BIT_5; ++ } ++ ++ zfIBSSSetupBssDesc(dev); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ ++ // 20070411 Add WPA2PSK information to its IBSS network !!! ++ offset = 0 ; ++ ++ /* timestamp */ ++ offset += 8 ; ++ ++ /* beacon interval */ ++ wd->sta.beaconFrameBody[offset++] = (u8_t)(wd->beaconInterval) ; ++ wd->sta.beaconFrameBody[offset++] = (u8_t)((wd->beaconInterval) >> 8) ; ++ ++ /* capability information */ ++ wd->sta.beaconFrameBody[offset++] = wd->sta.capability[0] ; ++ wd->sta.beaconFrameBody[offset++] = wd->sta.capability[1] ; ++ #if 0 ++ /* ssid */ ++ // ssid element id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_SSID ; ++ // ssid length ++ wd->sta.beaconFrameBody[offset++] = wd->sta.ssidLen ; ++ // ssid information ++ for(i=0; ista.ssidLen; i++) ++ { ++ wd->sta.beaconFrameBody[offset++] = wd->sta.ssid[i] ; ++ } ++ ++ /* support rate */ ++ rateSet = ZM_RATE_SET_CCK ; ++ if ( (rateSet == ZM_RATE_SET_OFDM)&&((wd->gRate & 0xff) == 0) ) ++ { ++ offset += 0 ; ++ } ++ else ++ { ++ // support rate element id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_SUPPORT_RATE ; ++ ++ // support rate length ++ lenOffset = offset++; ++ ++ // support rate information ++ for (i=0; i<4; i++) ++ { ++ if ((wd->bRate & (0x1<sta.beaconFrameBody[offset++] = ++ zg11bRateTbl[i]+((wd->bRateBasic & (0x1<sta.beaconFrameBody[lenOffset] = len ; ++ } ++ ++ /* DS parameter set */ ++ // DS parameter set elemet id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_DS ; ++ ++ // DS parameter set length ++ wd->sta.beaconFrameBody[offset++] = 1 ; ++ ++ // DS parameter set information ++ wd->sta.beaconFrameBody[offset++] = ++ zfChFreqToNum(wd->frequency, NULL) ; ++ ++ /* IBSS parameter set */ ++ // IBSS parameter set element id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_IBSS ; ++ ++ // IBSS parameter set length ++ wd->sta.beaconFrameBody[offset++] = 2 ; ++ ++ // IBSS parameter set information ++ wd->sta.beaconFrameBody[offset] = wd->sta.atimWindow ; ++ offset += 2 ; ++ ++ /* ERP Information and Extended Supported Rates */ ++ if ( wd->wfc.bIbssGMode ++ && (wd->supportMode & (ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N)) ) ++ { ++ /* ERP Information */ ++ wd->erpElement = 0; ++ // ERP element id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_ERP ; ++ ++ // ERP length ++ wd->sta.beaconFrameBody[offset++] = 1 ; ++ ++ // ERP information ++ wd->sta.beaconFrameBody[offset++] = wd->erpElement ; ++ ++ /* Extended Supported Rates */ ++ if ( (rateSet == ZM_RATE_SET_OFDM)&&((wd->gRate & 0xff) == 0) ) ++ { ++ offset += 0 ; ++ } ++ else ++ { ++ len = 0 ; ++ ++ // Extended Supported Rates element id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_EXTENDED_RATE ; ++ ++ // Extended Supported Rates length ++ lenOffset = offset++ ; ++ ++ // Extended Supported Rates information ++ for (i=0; i<8; i++) ++ { ++ if ((wd->gRate & (0x1<sta.beaconFrameBody[offset++] = ++ zg11gRateTbl[i]+((wd->gRateBasic & (0x1<sta.beaconFrameBody[lenOffset] = len ; ++ } ++ } ++ #endif ++ ++ /* RSN : important information influence the result of creating an IBSS network */ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA2PSK ) ++ { ++ u8_t frameType = ZM_WLAN_FRAME_TYPE_AUTH ; ++ u8_t rsn[64]= ++ { ++ /* Element ID */ ++ 0x30, ++ /* Length */ ++ 0x14, ++ /* Version */ ++ 0x01, 0x00, ++ /* Group Cipher Suite, default=TKIP */ ++ 0x00, 0x0f, 0xac, 0x04, ++ /* Pairwise Cipher Suite Count */ ++ 0x01, 0x00, ++ /* Pairwise Cipher Suite, default=TKIP */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* Authentication and Key Management Suite Count */ ++ 0x01, 0x00, ++ /* Authentication type, default=PSK */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* RSN capability */ ++ 0x00, 0x00 ++ }; ++ ++ /* Overwrite Group Cipher Suite by AP's setting */ ++ zfMemoryCopy(rsn+4, zgWpa2AesOui, 4); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ /* Overwrite Pairwise Cipher Suite by AES */ ++ zfMemoryCopy(rsn+10, zgWpa2AesOui, 4); ++ } ++ ++ // RSN element id ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_RSN_IE ; ++ ++ // RSN length ++ wd->sta.beaconFrameBody[offset++] = rsn[1] ; ++ ++ // RSN information ++ for(i=0; ista.beaconFrameBody[offset++] = rsn[i+2] ; ++ ++ zfMemoryCopy(wd->sta.rsnIe, rsn, rsn[1]+2); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ /* If not use RSNA , run traditional */ ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssWpa2Psk = 1; ++ zmw_leave_critical_section(dev); ++#endif ++ } ++ ++ #if 0 ++ /* HT Capabilities Info */ ++ { ++ u8_t OUI[3] = { 0x0 , 0x90 , 0x4C } ; ++ ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_WPA_IE ; ++ ++ wd->sta.beaconFrameBody[offset++] = wd->sta.HTCap.Data.Length + 4 ; ++ ++ for (i = 0; i < 3; i++) ++ { ++ wd->sta.beaconFrameBody[offset++] = OUI[i] ; ++ } ++ ++ wd->sta.beaconFrameBody[offset++] = wd->sta.HTCap.Data.ElementID ; ++ ++ for (i = 0; i < 26; i++) ++ { ++ wd->sta.beaconFrameBody[offset++] = wd->sta.HTCap.Byte[i+2] ; ++ } ++ } ++ ++ /* Extended HT Capabilities Info */ ++ { ++ u8_t OUI[3] = { 0x0 , 0x90 , 0x4C } ; ++ ++ wd->sta.beaconFrameBody[offset++] = ZM_WLAN_EID_WPA_IE ; ++ ++ wd->sta.beaconFrameBody[offset++] = wd->sta.ExtHTCap.Data.Length + 4 ; ++ ++ for (i = 0; i < 3; i++) ++ { ++ wd->sta.beaconFrameBody[offset++] = OUI[i] ; ++ } ++ ++ wd->sta.beaconFrameBody[offset++] = wd->sta.ExtHTCap.Data.ElementID ; ++ ++ for (i = 0; i < 22; i++) ++ { ++ wd->sta.beaconFrameBody[offset++] = wd->sta.ExtHTCap.Byte[i+2] ; ++ } ++ } ++ #endif ++ ++ wd->sta.beaconFrameBodySize = offset ; ++ ++ if (wd->sta.beaconFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) ++ { ++ wd->sta.beaconFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; ++ } ++ ++ // 20070416 Let Create IBSS network could enter the zfwIbssPartnerNotify function ++ // bssNotFound = FALSE ; ++ ++ printk("The capability info 1 = %02x\n", wd->sta.capability[0]) ; ++ printk("The capability info 2 = %02x\n", wd->sta.capability[1]) ; ++ for(k=0; ksta.beaconFrameBodySize; k++) ++ { ++ printk("%02x ", wd->sta.beaconFrameBody[k]) ; ++ } ++ #if 0 ++ zmw_enter_critical_section(dev); ++ zfMemoryCopy(event.bssid, (u8_t *)bssid, 6); ++ zfMemoryCopy(event.peerMacAddr, (u8_t *)wd->macAddr, 6); ++ zmw_leave_critical_section(dev); ++ #endif ++#endif ++ ++ //zmw_enter_critical_section(dev); ++ //wd->sta.ibssPartnerStatus = ZM_IBSS_PARTNER_LOST; ++ //zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ wd->sta.ibssBssIsCreator = 0; ++ } ++ ++connect_done: ++ zfHpEnableBeacon(dev, ZM_MODE_IBSS, wd->beaconInterval, wd->dtim, (u8_t)wd->sta.atimWindow); ++ zfStaSendBeacon(dev); // Refresh Beacon content for ZD1211B HalPlus ++ zfHpSetAtimWindow(dev, wd->sta.atimWindow); ++ ++ // Start the IBSS timer to monitor for new stations ++ zmw_enter_critical_section(dev); ++ zfTimerSchedule(dev, ZM_EVENT_IBSS_MONITOR, ZM_TICK_IBSS_MONITOR); ++ zmw_leave_critical_section(dev); ++ ++ ++ if (wd->zfcbConnectNotify != NULL) ++ { ++ wd->zfcbConnectNotify(dev, ZM_STATUS_MEDIA_CONNECT, wd->sta.bssid); ++ } ++ zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTED); ++ wd->sta.connPowerInHalfDbm = zfHpGetTransmitPower(dev); ++ ++#ifdef ZM_ENABLE_IBSS_DELAYED_JOIN_INDICATION ++ if ( !bssNotFound ) ++ { ++ wd->sta.ibssDelayedInd = 1; ++ zfMemoryCopy((u8_t *)&wd->sta.ibssDelayedIndEvent, (u8_t *)&event, sizeof(struct zsPartnerNotifyEvent)); ++ } ++#else ++ if ( !bssNotFound ) ++ { ++ if (wd->zfcbIbssPartnerNotify != NULL) ++ { ++ wd->zfcbIbssPartnerNotify(dev, 1, &event); ++ } ++ } ++#endif ++ ++ return; ++ ++retry_ibss: ++ zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTING); ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_NOT_FOUND, wd->sta.bssid, 0); ++ return; ++} ++ ++void zfStaProcessAtim(zdev_t* dev, zbuf_t* buf) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg0("Receiving Atim window notification"); ++ ++ wd->sta.recvAtim = 1; ++} ++ ++static struct zsBssInfo* zfInfraFindAPToConnect(zdev_t* dev, ++ struct zsBssInfo* candidateBss) ++{ ++ struct zsBssInfo* pBssInfo; ++ struct zsBssInfo* pNowBssInfo=NULL; ++ u16_t i; ++ u16_t ret, apWepStatus; ++ u32_t k; ++ u32_t channelFlags; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ pBssInfo = wd->sta.bssList.head; ++ ++ for(i=0; ista.bssList.bssCount; i++) ++ { ++ if ( pBssInfo->capability[0] & ZM_BIT_4 ) ++ { ++ apWepStatus = ZM_ENCRYPTION_WEP_ENABLED; ++ } ++ else ++ { ++ apWepStatus = ZM_ENCRYPTION_WEP_DISABLED; ++ } ++ ++ if ( ((zfMemoryIsEqual(&(pBssInfo->ssid[2]), wd->sta.ssid, ++ wd->sta.ssidLen))&& ++ (wd->sta.ssidLen == pBssInfo->ssid[1]))|| ++ ((wd->sta.ssidLen == 0)&& ++ /* connect to any BSS: AP's ans STA's WEP status must match */ ++ (wd->sta.wepStatus == apWepStatus )&& ++ (pBssInfo->securityType != ZM_SECURITY_TYPE_WPA) )) ++ { ++ if ( wd->sta.ssidLen == 0 ) ++ { ++ zm_debug_msg0("ANY BSS found"); ++ } ++ ++ if ( ((wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED && apWepStatus == ZM_ENCRYPTION_WEP_ENABLED) || ++ (wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED && ++ (apWepStatus == ZM_ENCRYPTION_WEP_DISABLED && wd->sta.dropUnencryptedPkts == 1))) && ++ (wd->sta.authMode >= ZM_AUTH_MODE_OPEN && wd->sta.authMode <= ZM_AUTH_MODE_AUTO) ) ++ { ++ zm_debug_msg0("Privacy policy is inconsistent"); ++ pBssInfo = pBssInfo->next; ++ continue; ++ } ++ ++ /* for WPA negative test */ ++ if ( !zfCheckAuthentication(dev, pBssInfo) ) ++ { ++ pBssInfo = pBssInfo->next; ++ continue; ++ } ++ ++ /* Check bssid */ ++ if (wd->sta.bDesiredBssid == TRUE) ++ { ++ for (k=0; k<6; k++) ++ { ++ if (wd->sta.desiredBssid[k] != pBssInfo->bssid[k]) ++ { ++ zm_msg0_mm(ZM_LV_1, "desired bssid not matched 1"); ++ break; ++ } ++ } ++ ++ if (k != 6) ++ { ++ zm_msg0_mm(ZM_LV_1, "desired bssid not matched 2"); ++ pBssInfo = pBssInfo->next; ++ continue; ++ } ++ } ++ ++ /* Check support mode */ ++ if (pBssInfo->frequency > 3000) { ++ if ( (pBssInfo->EnableHT == 1) ++ || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP ++ { ++ channelFlags = CHANNEL_A_HT; ++ if (pBssInfo->enableHT40 == 1) { ++ channelFlags |= CHANNEL_HT40; ++ } ++ } else { ++ channelFlags = CHANNEL_A; ++ } ++ } else { ++ if ( (pBssInfo->EnableHT == 1) ++ || (pBssInfo->apCap & ZM_All11N_AP) ) //11n AP ++ { ++ channelFlags = CHANNEL_G_HT; ++ if(pBssInfo->enableHT40 == 1) { ++ channelFlags |= CHANNEL_HT40; ++ } ++ } else { ++ if (pBssInfo->extSupportedRates[1] == 0) { ++ channelFlags = CHANNEL_B; ++ } else { ++ channelFlags = CHANNEL_G; ++ } ++ } ++ } ++ ++ if ( ((channelFlags == CHANNEL_B) && (wd->connectMode & ZM_BIT_0)) ++ || ((channelFlags == CHANNEL_G) && (wd->connectMode & ZM_BIT_1)) ++ || ((channelFlags == CHANNEL_A) && (wd->connectMode & ZM_BIT_2)) ++ || ((channelFlags & CHANNEL_HT20) && (wd->connectMode & ZM_BIT_3)) ) ++ { ++ pBssInfo = pBssInfo->next; ++ continue; ++ } ++ ++ /* Skip if AP in blocking list */ ++ if ((ret = zfStaIsApInBlockingList(dev, pBssInfo->bssid)) == TRUE) ++ { ++ zm_msg0_mm(ZM_LV_0, "Candidate AP in blocking List, skip if there's stilla choice!"); ++ pNowBssInfo = pBssInfo; ++ pBssInfo = pBssInfo->next; ++ continue; ++ } ++ ++ if ( pBssInfo->capability[0] & ZM_BIT_0 ) // check if infra-BSS ++ { ++ pNowBssInfo = pBssInfo; ++ wd->sta.apWmeCapability = pBssInfo->wmeSupport; ++ ++ ++ goto done; ++ } ++ } ++ ++ pBssInfo = pBssInfo->next; ++ } ++ ++done: ++ if (pNowBssInfo != NULL) ++ { ++ zfwMemoryCopy((void*)candidateBss, (void*)pNowBssInfo, sizeof(struct zsBssInfo)); ++ pNowBssInfo = candidateBss; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return pNowBssInfo; ++} ++ ++ ++void zfInfraConnectNetwork(zdev_t* dev) ++{ ++ struct zsBssInfo* pBssInfo; ++ struct zsBssInfo* pNowBssInfo=NULL; ++ struct zsBssInfo candidateBss; ++ //u16_t i, j=100, quality=10000; ++ //u8_t ret=FALSE, apWepStatus; ++ u8_t ret=FALSE; ++ u16_t k; ++ u8_t density = ZM_MPDU_DENSITY_NONE; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ /* Reset bssNotFoundCount for Ad-Hoc:IBSS */ ++ /* Need review : IbssConn -> InfraConn -> IbssConn etc, flag/counter reset? */ ++ zmw_enter_critical_section(dev); ++ wd->sta.bssNotFoundCount = 0; ++ zmw_leave_critical_section(dev); ++ ++ /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME STA default. */ ++ zfUpdateDefaultQosParameter(dev, 0); ++ ++ zfStaRefreshBlockList(dev, 0); ++ ++ /* change state to CONNECTING and stop the channel scanning */ ++ zfChangeAdapterState(dev, ZM_STA_STATE_CONNECTING); ++ zfPowerSavingMgrWakeup(dev); ++ ++ wd->sta.wmeConnected = 0; ++ wd->sta.psMgr.tempWakeUp = 0; ++ wd->sta.qosInfo = 0; ++ zfQueueFlush(dev, wd->sta.uapsdQ); ++ ++ wd->sta.connectState = ZM_STA_CONN_STATE_NONE; ++ ++ //Reorder BssList by RSSI--CWYang(+) ++ zfBssInfoReorderList(dev); ++ ++ pNowBssInfo = zfInfraFindAPToConnect(dev, &candidateBss); ++ ++ if (wd->sta.SWEncryptEnable != 0) ++ { ++ if (wd->sta.bSafeMode == 0) ++ { ++ zfStaDisableSWEncryption(dev);//Quickly reboot ++ } ++ } ++ if ( pNowBssInfo != NULL ) ++ { ++ //zm_assert(pNowBssInfo != NULL); ++ ++ pBssInfo = pNowBssInfo; ++ wd->sta.ssidLen = pBssInfo->ssid[1]; ++ zfMemoryCopy(wd->sta.ssid, &(pBssInfo->ssid[2]), pBssInfo->ssid[1]); ++ wd->frequency = pBssInfo->frequency; ++ //wd->sta.flagFreqChanging = 1; ++ ++ //zfCoreSetFrequency(dev, wd->frequency); ++ zfUpdateBssid(dev, pBssInfo->bssid); ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_ZERO); ++ zfUpdateSupportRate(dev, pBssInfo->supportedRates); ++ zfUpdateSupportRate(dev, pBssInfo->extSupportedRates); ++ ++ wd->beaconInterval = pBssInfo->beaconInterval[0] + ++ (((u16_t) pBssInfo->beaconInterval[1]) << 8); ++ if (wd->beaconInterval == 0) ++ { ++ wd->beaconInterval = 100; ++ } ++ ++ /* ESS bit on */ ++ wd->sta.capability[0] |= ZM_BIT_0; ++ /* IBSS bit off */ ++ wd->sta.capability[0] &= ~ZM_BIT_1; ++ ++ /* 11n AP flag */ ++ wd->sta.EnableHT = pBssInfo->EnableHT; ++ wd->sta.SG40 = pBssInfo->SG40; ++#ifdef ZM_ENABLE_CENC ++ if ( pBssInfo->securityType == ZM_SECURITY_TYPE_CENC ) ++ { ++ wd->sta.wmeEnabled = 0; //Disable WMM in CENC ++ cencInit(dev); ++ cencSetCENCMode(dev, NdisCENC_PSK); ++ wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; ++ /* CENC */ ++ if ( pBssInfo->cencIe[1] != 0 ) ++ { ++ //wd->sta.wepStatus = ZM_ENCRYPTION_CENC; ++ //wd->sta.encryMode = ZM_CENC; ++ zfwCencHandleBeaconProbrespon(dev, (u8_t *)&pBssInfo->cencIe, ++ (u8_t *)&pBssInfo->ssid, (u8_t *)&pBssInfo->macaddr); ++ zfMemoryCopy(wd->sta.cencIe, pBssInfo->cencIe, ++ pBssInfo->cencIe[1]+2); ++ } ++ else ++ { ++ wd->sta.cencIe[1] = 0; ++ } ++ } ++#endif //ZM_ENABLE_CENC ++ if ( pBssInfo->securityType == ZM_SECURITY_TYPE_WPA ) ++ { ++ wd->sta.wpaState = ZM_STA_WPA_STATE_INIT; ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_TKIP ) ++ { ++ wd->sta.encryMode = ZM_TKIP; ++ ++ /* Turn on software encryption/decryption for TKIP */ ++ if (wd->sta.EnableHT == 1) ++ { ++ zfStaEnableSWEncryption(dev, (ZM_SW_TKIP_ENCRY_EN|ZM_SW_TKIP_DECRY_EN)); ++ } ++ ++ /* Do not support TKIP in 11n mode */ ++ //wd->sta.EnableHT = 0; ++ //pBssInfo->enableHT40 = 0; ++ } ++ else if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ wd->sta.encryMode = ZM_AES; ++ ++ /* If AP supports HT mode */ ++ if (wd->sta.EnableHT) ++ { ++ /* Set MPDU density to 8 us*/ ++ density = ZM_MPDU_DENSITY_8US; ++ } ++ } ++ ++ if ( pBssInfo->wpaIe[1] != 0 ) ++ { ++ zfMemoryCopy(wd->sta.wpaIe, pBssInfo->wpaIe, ++ pBssInfo->wpaIe[1]+2); ++ } ++ else ++ { ++ wd->sta.wpaIe[1] = 0; ++ } ++ ++ if ( pBssInfo->rsnIe[1] != 0 ) ++ { ++ zfMemoryCopy(wd->sta.rsnIe, pBssInfo->rsnIe, ++ pBssInfo->rsnIe[1]+2); ++ } ++ else ++ { ++ wd->sta.rsnIe[1] = 0; ++ } ++ } ++ ++ ++ ++ /* check preamble bit */ ++ wd->preambleTypeInUsed = wd->preambleType; ++ if ( wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_AUTO ) ++ { ++ if (pBssInfo->capability[0] & ZM_BIT_5) ++ { ++ wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_SHORT; ++ } ++ else ++ { ++ wd->preambleTypeInUsed = ZM_PREAMBLE_TYPE_LONG; ++ } ++ } ++ ++ if (wd->preambleTypeInUsed == ZM_PREAMBLE_TYPE_LONG) ++ { ++ wd->sta.capability[0] &= ~ZM_BIT_5; ++ } ++ else ++ { ++ wd->sta.capability[0] |= ZM_BIT_5; ++ } ++ ++ /* check 802.11n 40MHz Setting */ ++ if ((pBssInfo->enableHT40 == 1) && ++ ((pBssInfo->extChOffset == 1) || (pBssInfo->extChOffset == 3))) ++ { ++ wd->BandWidth40 = pBssInfo->enableHT40; ++ wd->ExtOffset = pBssInfo->extChOffset; ++ } ++ else ++ { ++ wd->BandWidth40 = 0; ++ wd->ExtOffset = 0; ++ } ++ ++ /* check 802.11H support bit */ ++ ++ /* check Owl Ap */ ++ if ( pBssInfo->athOwlAp & ZM_BIT_0 ) ++ { ++ /* In this function, FW retry will be enable, ZM_MAC_REG_RETRY_MAX ++ will be set to 0. ++ */ ++ zfHpDisableHwRetry(dev); ++ wd->sta.athOwlAp = 1; ++ /* Set MPDU density to 8 us*/ ++ density = ZM_MPDU_DENSITY_8US; ++ } ++ else ++ { ++ /* In this function, FW retry will be disable, ZM_MAC_REG_RETRY_MAX ++ will be set to 3. ++ */ ++ zfHpEnableHwRetry(dev); ++ wd->sta.athOwlAp = 0; ++ } ++ wd->reorder = 1; ++ ++ /* Set MPDU density */ ++ zfHpSetMPDUDensity(dev, density); ++ ++ /* check short slot time bit */ ++ if ( pBssInfo->capability[1] & ZM_BIT_2 ) ++ { ++ wd->sta.capability[1] |= ZM_BIT_2; ++ } ++ ++ if ( pBssInfo->erp & ZM_BIT_1 ) ++ { ++ //zm_debug_msg0("protection mode on"); ++ wd->sta.bProtectionMode = TRUE; ++ zfHpSetSlotTime(dev, 0); ++ } ++ else ++ { ++ //zm_debug_msg0("protection mode off"); ++ wd->sta.bProtectionMode = FALSE; ++ zfHpSetSlotTime(dev, 1); ++ } ++ ++ if (pBssInfo->marvelAp == 1) ++ { ++ wd->sta.enableDrvBA = 0; ++ /* ++ * 8701 : NetGear 3500 (MARVELL) ++ * Downlink issue : set slottime to 20. ++ */ ++ zfHpSetSlotTimeRegister(dev, 0); ++ } ++ else ++ { ++ wd->sta.enableDrvBA = 1; ++ ++ /* ++ * This is not good for here do reset slot time. ++ * I think it should reset when leave MARVELL ap ++ * or enter disconnect state etc. ++ */ ++ zfHpSetSlotTimeRegister(dev, 1); ++ } ++ ++ //Store probe response frame body, for VISTA only ++ wd->sta.beaconFrameBodySize = pBssInfo->frameBodysize + 12; ++ if (wd->sta.beaconFrameBodySize > ZM_CACHED_FRAMEBODY_SIZE) ++ { ++ wd->sta.beaconFrameBodySize = ZM_CACHED_FRAMEBODY_SIZE; ++ } ++ for (k=0; k<8; k++) ++ { ++ wd->sta.beaconFrameBody[k] = pBssInfo->timeStamp[k]; ++ } ++ wd->sta.beaconFrameBody[8] = pBssInfo->beaconInterval[0]; ++ wd->sta.beaconFrameBody[9] = pBssInfo->beaconInterval[1]; ++ wd->sta.beaconFrameBody[10] = pBssInfo->capability[0]; ++ wd->sta.beaconFrameBody[11] = pBssInfo->capability[1]; ++ for (k=0; k<(wd->sta.beaconFrameBodySize - 12); k++) ++ { ++ wd->sta.beaconFrameBody[k+12] = pBssInfo->frameBody[k]; ++ } ++ ++ if ( ( pBssInfo->capability[0] & ZM_BIT_4 )&& ++ (( wd->sta.authMode == ZM_AUTH_MODE_OPEN )|| ++ ( wd->sta.authMode == ZM_AUTH_MODE_SHARED_KEY)|| ++ (wd->sta.authMode == ZM_AUTH_MODE_AUTO)) ) ++ { /* privacy enabled */ ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_DISABLED ) ++ { ++ zm_debug_msg0("Adapter is no WEP, try to connect to WEP AP"); ++ ret = FALSE; ++ } ++ ++ /* Do not support WEP in 11n mode */ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_WEP_ENABLED ) ++ { ++ /* Turn on software encryption/decryption for WEP */ ++ if (wd->sta.EnableHT == 1) ++ { ++ zfStaEnableSWEncryption(dev, (ZM_SW_WEP_ENCRY_EN|ZM_SW_WEP_DECRY_EN)); ++ } ++ ++ //wd->sta.EnableHT = 0; ++ //wd->BandWidth40 = 0; ++ //wd->ExtOffset = 0; ++ } ++ ++ wd->sta.capability[0] |= ZM_BIT_4; ++ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_AUTO ) ++ { /* Try to use open and shared-key authehtication alternatively */ ++ if ( (wd->sta.connectTimeoutCount % 2) == 0 ) ++ wd->sta.bIsSharedKey = 0; ++ else ++ wd->sta.bIsSharedKey = 1; ++ } ++ else if ( wd->sta.authMode != ZM_AUTH_MODE_SHARED_KEY ) ++ { /* open or auto */ ++ //zfStaStartConnect(dev, 0); ++ wd->sta.bIsSharedKey = 0; ++ } ++ else if ( wd->sta.authMode != ZM_AUTH_MODE_OPEN ) ++ { /* shared key */ ++ //zfStaStartConnect(dev, 1) ; ++ wd->sta.bIsSharedKey = 1; ++ } ++ } ++ else ++ { ++ if ( (pBssInfo->securityType == ZM_SECURITY_TYPE_WPA)|| ++ (pBssInfo->capability[0] & ZM_BIT_4) ) ++ { ++ wd->sta.capability[0] |= ZM_BIT_4; ++ /* initialize WPA related parameters */ ++ } ++ else ++ { ++ wd->sta.capability[0] &= (~ZM_BIT_4); ++ } ++ ++ /* authentication with open system */ ++ //zfStaStartConnect(dev, 0); ++ wd->sta.bIsSharedKey = 0; ++ } ++ ++ /* Improve WEP/TKIP performace with HT AP, detail information please look bug#32495 */ ++ /* ++ if ( (pBssInfo->broadcomHTAp == 1) ++ && (wd->sta.SWEncryptEnable != 0) ) ++ { ++ zfHpSetTTSIFSTime(dev, 0xa); ++ } ++ else ++ { ++ zfHpSetTTSIFSTime(dev, 0x8); ++ } ++ */ ++ } ++ else ++ { ++ zm_debug_msg0("Desired SSID not found"); ++ goto zlConnectFailed; ++ } ++ ++ ++ zfCoreSetFrequencyV2(dev, wd->frequency, zfStaStartConnectCb); ++ return; ++ ++zlConnectFailed: ++ zfStaConnectFail(dev, ZM_STATUS_MEDIA_DISCONNECT_NOT_FOUND, wd->sta.bssid, 0); ++ return; ++} ++ ++u8_t zfCheckWPAAuth(zdev_t* dev, struct zsBssInfo* pBssInfo) ++{ ++ u8_t ret=TRUE; ++ u8_t pmkCount; ++ u8_t i; ++ u16_t encAlgoType = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_TKIP ) ++ { ++ encAlgoType = ZM_TKIP; ++ } ++ else if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ encAlgoType = ZM_AES; ++ } ++ ++ switch(wd->sta.authMode) ++ { ++ case ZM_AUTH_MODE_WPA: ++ case ZM_AUTH_MODE_WPAPSK: ++ if ( pBssInfo->wpaIe[1] == 0 ) ++ { ++ ret = FALSE; ++ break; ++ } ++ ++ pmkCount = pBssInfo->wpaIe[12]; ++ for(i=0; i < pmkCount; i++) ++ { ++ if ( pBssInfo->wpaIe[17 + 4*i] == encAlgoType ) ++ { ++ ret = TRUE; ++ goto done; ++ } ++ } ++ ++ ret = FALSE; ++ break; ++ ++ case ZM_AUTH_MODE_WPA2: ++ case ZM_AUTH_MODE_WPA2PSK: ++ if ( pBssInfo->rsnIe[1] == 0 ) ++ { ++ ret = FALSE; ++ break; ++ } ++ ++ pmkCount = pBssInfo->rsnIe[8]; ++ for(i=0; i < pmkCount; i++) ++ { ++ if ( pBssInfo->rsnIe[13 + 4*i] == encAlgoType ) ++ { ++ ret = TRUE; ++ goto done; ++ } ++ } ++ ++ ret = FALSE; ++ break; ++ } ++ ++done: ++ return ret; ++} ++ ++u8_t zfCheckAuthentication(zdev_t* dev, struct zsBssInfo* pBssInfo) ++{ ++ u8_t ret=TRUE; ++ u16_t encAlgoType; ++ u16_t UnicastCipherNum; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Connecting to ANY has been checked */ ++ if ( wd->sta.ssidLen == 0 ) ++ { ++ return ret; ++ } ++ ++ ++ switch(wd->sta.authMode) ++ //switch(wd->ws.authMode)//Quickly reboot ++ { ++ case ZM_AUTH_MODE_WPA_AUTO: ++ case ZM_AUTH_MODE_WPAPSK_AUTO: ++ encAlgoType = 0; ++ if(pBssInfo->rsnIe[1] != 0) ++ { ++ UnicastCipherNum = (pBssInfo->rsnIe[8]) + ++ (pBssInfo->rsnIe[9] << 8); ++ ++ /* If there is only one unicast cipher */ ++ if (UnicastCipherNum == 1) ++ { ++ encAlgoType = pBssInfo->rsnIe[13]; ++ //encAlgoType = pBssInfo->rsnIe[7]; ++ } ++ else ++ { ++ u16_t ii; ++ u16_t desiredCipher = 0; ++ u16_t IEOffSet = 13; ++ ++ /* Enumerate all the supported unicast cipher */ ++ for (ii = 0; ii < UnicastCipherNum; ii++) ++ { ++ if (pBssInfo->rsnIe[IEOffSet+ii*4] > desiredCipher) ++ { ++ desiredCipher = pBssInfo->rsnIe[IEOffSet+ii*4]; ++ } ++ } ++ ++ encAlgoType = desiredCipher; ++ } ++ ++ if ( encAlgoType == 0x02 ) ++ { ++ wd->sta.wepStatus = ZM_ENCRYPTION_TKIP; ++ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2; ++ } ++ else //ZM_AUTH_MODE_WPAPSK_AUTO ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2PSK; ++ } ++ } ++ else if ( encAlgoType == 0x04 ) ++ { ++ wd->sta.wepStatus = ZM_ENCRYPTION_AES; ++ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2; ++ } ++ else //ZM_AUTH_MODE_WPAPSK_AUTO ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA2PSK; ++ } ++ } ++ else ++ { ++ ret = FALSE; ++ } ++ } ++ else if(pBssInfo->wpaIe[1] != 0) ++ { ++ UnicastCipherNum = (pBssInfo->wpaIe[12]) + ++ (pBssInfo->wpaIe[13] << 8); ++ ++ /* If there is only one unicast cipher */ ++ if (UnicastCipherNum == 1) ++ { ++ encAlgoType = pBssInfo->wpaIe[17]; ++ //encAlgoType = pBssInfo->wpaIe[11]; ++ } ++ else ++ { ++ u16_t ii; ++ u16_t desiredCipher = 0; ++ u16_t IEOffSet = 17; ++ ++ /* Enumerate all the supported unicast cipher */ ++ for (ii = 0; ii < UnicastCipherNum; ii++) ++ { ++ if (pBssInfo->wpaIe[IEOffSet+ii*4] > desiredCipher) ++ { ++ desiredCipher = pBssInfo->wpaIe[IEOffSet+ii*4]; ++ } ++ } ++ ++ encAlgoType = desiredCipher; ++ } ++ ++ if ( encAlgoType == 0x02 ) ++ { ++ wd->sta.wepStatus = ZM_ENCRYPTION_TKIP; ++ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA; ++ } ++ else //ZM_AUTH_MODE_WPAPSK_AUTO ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPAPSK; ++ } ++ } ++ else if ( encAlgoType == 0x04 ) ++ { ++ wd->sta.wepStatus = ZM_ENCRYPTION_AES; ++ ++ if ( wd->sta.authMode == ZM_AUTH_MODE_WPA_AUTO ) ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPA; ++ } ++ else //ZM_AUTH_MODE_WPAPSK_AUTO ++ { ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_WPAPSK; ++ } ++ } ++ else ++ { ++ ret = FALSE; ++ } ++ ++ ++ } ++ else ++ { ++ ret = FALSE; ++ } ++ ++ break; ++ ++ case ZM_AUTH_MODE_WPA: ++ case ZM_AUTH_MODE_WPAPSK: ++ case ZM_AUTH_MODE_WPA_NONE: ++ case ZM_AUTH_MODE_WPA2: ++ case ZM_AUTH_MODE_WPA2PSK: ++ { ++ if ( pBssInfo->securityType != ZM_SECURITY_TYPE_WPA ) ++ { ++ ret = FALSE; ++ } ++ ++ ret = zfCheckWPAAuth(dev, pBssInfo); ++ } ++ break; ++ ++ case ZM_AUTH_MODE_OPEN: ++ case ZM_AUTH_MODE_SHARED_KEY: ++ case ZM_AUTH_MODE_AUTO: ++ { ++ if ( pBssInfo->wscIe[1] ) ++ { ++ // If the AP is a Jumpstart AP, it's ok!! Ray ++ break; ++ } ++ else if ( pBssInfo->securityType == ZM_SECURITY_TYPE_WPA ) ++ { ++ ret = FALSE; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++u8_t zfStaIsConnected(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.adapterState == ZM_STA_STATE_CONNECTED ) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++u8_t zfStaIsConnecting(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.adapterState == ZM_STA_STATE_CONNECTING ) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++u8_t zfStaIsDisconnect(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.adapterState == ZM_STA_STATE_DISCONNECT ) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++u8_t zfChangeAdapterState(zdev_t* dev, u8_t newState) ++{ ++ u8_t ret = TRUE; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ //if ( newState == wd->sta.adapterState ) ++ //{ ++ // return FALSE; ++ //} ++ ++ switch(newState) ++ { ++ case ZM_STA_STATE_DISCONNECT: ++ zfResetSupportRate(dev, ZM_DEFAULT_SUPPORT_RATE_DISCONNECT); ++ ++ #if 1 ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ #else ++ if ( wd->sta.bChannelScan ) ++ { ++ /* stop the action of channel scanning */ ++ wd->sta.bChannelScan = FALSE; ++ ret = TRUE; ++ break; ++ } ++ #endif ++ ++ break; ++ case ZM_STA_STATE_CONNECTING: ++ #if 1 ++ zfScanMgrScanStop(dev, ZM_SCAN_MGR_SCAN_INTERNAL); ++ #else ++ if ( wd->sta.bChannelScan ) ++ { ++ /* stop the action of channel scanning */ ++ wd->sta.bChannelScan = FALSE; ++ ret = TRUE; ++ break; ++ } ++ #endif ++ ++ break; ++ case ZM_STA_STATE_CONNECTED: ++ break; ++ default: ++ break; ++ } ++ ++ //if ( ret ) ++ //{ ++ zmw_enter_critical_section(dev); ++ wd->sta.adapterState = newState; ++ zmw_leave_critical_section(dev); ++ ++ zm_debug_msg1("change adapter state = ", newState); ++ //} ++ ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaMmAddIeSsid */ ++/* Add information element SSID to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Ji-Huang Lee ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaAddIeSsid(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SSID); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.ssidLen); ++ ++ /* Information : SSID */ ++ for (i=0; ista.ssidLen; i++) ++ { ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.ssid[i]); ++ } ++ ++ return offset; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaMmAddIeWpa */ ++/* Add information element SSID to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Ji-Huang Lee ZyDAS Technology Corporation 2006.01 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType) ++{ ++ u32_t i; ++ u8_t ssn[64]={ ++ /* Element ID */ ++ 0xdd, ++ /* Length */ ++ 0x18, ++ /* OUI type */ ++ 0x00, 0x50, 0xf2, 0x01, ++ /* Version */ ++ 0x01, 0x00, ++ /* Group Cipher Suite, default=TKIP */ ++ 0x00, 0x50, 0xf2, 0x02, ++ /* Pairwise Cipher Suite Count */ ++ 0x01, 0x00, ++ /* Pairwise Cipher Suite, default=TKIP */ ++ 0x00, 0x50, 0xf2, 0x02, ++ /* Authentication and Key Management Suite Count */ ++ 0x01, 0x00, ++ /* Authentication type, default=PSK */ ++ 0x00, 0x50, 0xf2, 0x02, ++ /* WPA capability */ ++ 0x00, 0x00 ++ }; ++ ++ u8_t rsn[64]={ ++ /* Element ID */ ++ 0x30, ++ /* Length */ ++ 0x14, ++ /* Version */ ++ 0x01, 0x00, ++ /* Group Cipher Suite, default=TKIP */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* Pairwise Cipher Suite Count */ ++ 0x01, 0x00, ++ /* Pairwise Cipher Suite, default=TKIP */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* Authentication and Key Management Suite Count */ ++ 0x01, 0x00, ++ /* Authentication type, default=PSK */ ++ 0x00, 0x0f, 0xac, 0x02, ++ /* RSN capability */ ++ 0x00, 0x00 ++ }; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPAPSK ) ++ { ++ /* Overwrite Group Cipher Suite by AP's setting */ ++ zfMemoryCopy(ssn+8, wd->sta.wpaIe+8, 4); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ /* Overwrite Pairwise Cipher Suite by AES */ ++ zfMemoryCopy(ssn+14, zgWpaAesOui, 4); ++ } ++ ++ zfCopyToIntTxBuffer(dev, buf, ssn, offset, ssn[1]+2); ++ zfMemoryCopy(wd->sta.wpaIe, ssn, ssn[1]+2); ++ offset += (ssn[1]+2); ++ } ++ else if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPA ) ++ { ++ /* Overwrite Group Cipher Suite by AP's setting */ ++ zfMemoryCopy(ssn+8, wd->sta.wpaIe+8, 4); ++ /* Overwrite Key Management Suite by WPA-Radius */ ++ zfMemoryCopy(ssn+20, zgWpaRadiusOui, 4); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ /* Overwrite Pairwise Cipher Suite by AES */ ++ zfMemoryCopy(ssn+14, zgWpaAesOui, 4); ++ } ++ ++ zfCopyToIntTxBuffer(dev, buf, ssn, offset, ssn[1]+2); ++ zfMemoryCopy(wd->sta.wpaIe, ssn, ssn[1]+2); ++ offset += (ssn[1]+2); ++ } ++ else if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPA2PSK ) ++ { ++ /* Overwrite Group Cipher Suite by AP's setting */ ++ zfMemoryCopy(rsn+4, wd->sta.rsnIe+4, 4); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ /* Overwrite Pairwise Cipher Suite by AES */ ++ zfMemoryCopy(rsn+10, zgWpa2AesOui, 4); ++ } ++ ++ if ( frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ ) ++ { ++ for(i=0; ista.pmkidInfo.bssidCount; i++) ++ { ++ if ( zfMemoryIsEqual((u8_t*) wd->sta.pmkidInfo.bssidInfo[i].bssid, ++ (u8_t*) wd->sta.bssid, 6) ) ++ { ++ /* matched */ ++ break; ++ } ++ ++ if ( i < wd->sta.pmkidInfo.bssidCount ) ++ { ++ // Fill PMKID Count in RSN information element ++ rsn[22] = 0x01; ++ rsn[23] = 0x00; ++ ++ // Fill PMKID in RSN information element ++ zfMemoryCopy(rsn+24, ++ wd->sta.pmkidInfo.bssidInfo[i].pmkid, 16); ++ rsn[1] += 18; ++ } ++ } ++ } ++ ++ zfCopyToIntTxBuffer(dev, buf, rsn, offset, rsn[1]+2); ++ zfMemoryCopy(wd->sta.rsnIe, rsn, rsn[1]+2); ++ offset += (rsn[1]+2); ++ } ++ else if ( wd->sta.currentAuthMode == ZM_AUTH_MODE_WPA2 ) ++ { ++ /* Overwrite Group Cipher Suite by AP's setting */ ++ zfMemoryCopy(rsn+4, wd->sta.rsnIe+4, 4); ++ /* Overwrite Key Management Suite by WPA2-Radius */ ++ zfMemoryCopy(rsn+16, zgWpa2RadiusOui, 4); ++ ++ if ( wd->sta.wepStatus == ZM_ENCRYPTION_AES ) ++ { ++ /* Overwrite Pairwise Cipher Suite by AES */ ++ zfMemoryCopy(rsn+10, zgWpa2AesOui, 4); ++ } ++ ++ if (( frameType == ZM_WLAN_FRAME_TYPE_REASOCREQ || ( frameType == ZM_WLAN_FRAME_TYPE_ASOCREQ ))) ++ { ++ ++ if (wd->sta.pmkidInfo.bssidCount != 0) { ++ // Fill PMKID Count in RSN information element ++ rsn[22] = 1; ++ rsn[23] = 0; ++ /* ++ * The caller is respnsible to give us the relevant PMKID. ++ * We'll only accept 1 PMKID for now. ++ */ ++ for(i=0; ista.pmkidInfo.bssidCount; i++) ++ { ++ if ( zfMemoryIsEqual((u8_t*) wd->sta.pmkidInfo.bssidInfo[i].bssid, (u8_t*) wd->sta.bssid, 6) ) ++ { ++ zfMemoryCopy(rsn+24, wd->sta.pmkidInfo.bssidInfo[i].pmkid, 16); ++ break; ++ } ++ } ++ rsn[1] += 18; ++ } ++ ++ } ++ ++ zfCopyToIntTxBuffer(dev, buf, rsn, offset, rsn[1]+2); ++ zfMemoryCopy(wd->sta.rsnIe, rsn, rsn[1]+2); ++ offset += (rsn[1]+2); ++ } ++ ++ return offset; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaAddIeIbss */ ++/* Add information element IBSS parameter to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Ji-Huang Lee ZyDAS Technology Corporation 2005.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaAddIeIbss(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_IBSS); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 2); ++ ++ /* ATIM window */ ++ zmw_tx_buf_writeh(dev, buf, offset, wd->sta.atimWindow); ++ offset += 2; ++ ++ return offset; ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaAddIeWmeInfo */ ++/* Add WME Information Element to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaAddIeWmeInfo(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t qosInfo) ++{ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_WIFI_IE); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 7); ++ ++ /* OUI */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x50); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0xF2); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x02); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x00); ++ zmw_tx_buf_writeb(dev, buf, offset++, 0x01); ++ ++ /* QoS Info */ ++ zmw_tx_buf_writeb(dev, buf, offset++, qosInfo); ++ ++ return offset; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaAddIePowerCap */ ++/* Add information element Power capability to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Sharon 2007.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaAddIePowerCap(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u8_t MaxTxPower; ++ u8_t MinTxPower; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_POWER_CAPABILITY); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, 2); ++ ++ MinTxPower = (u8_t)(zfHpGetMinTxPower(dev)/2); ++ MaxTxPower = (u8_t)(zfHpGetMaxTxPower(dev)/2); ++ ++ /* Min Transmit Power Cap */ ++ zmw_tx_buf_writeh(dev, buf, offset++, MinTxPower); ++ ++ /* Max Transmit Power Cap */ ++ zmw_tx_buf_writeh(dev, buf, offset++, MaxTxPower); ++ ++ return offset; ++} ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfStaAddIeSupportCh */ ++/* Add information element supported channels to buffer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer to add information element */ ++/* offset : add information element from this offset */ ++/* */ ++/* OUTPUTS */ ++/* buffer offset after adding information element */ ++/* */ ++/* AUTHOR */ ++/* Sharon 2007.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfStaAddIeSupportCh(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ ++ u8_t i; ++ u16_t count_24G = 0; ++ u16_t count_5G = 0; ++ u16_t channelNum; ++ u8_t length; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ zmw_enter_critical_section(dev); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel < 3000) ++ { // 2.4Hz ++ count_24G++; ++ } ++ else ++ { // 5GHz ++ count_5G++; ++ } ++ } ++ ++ length = (u8_t)(count_5G * 2 + 2); //5G fill by pair, 2,4G (continuous channels) fill 2 bytes ++ ++ /* Element ID */ ++ zmw_tx_buf_writeb(dev, buf, offset++, ZM_WLAN_EID_SUPPORTED_CHANNELS ); ++ ++ /* Element Length */ ++ zmw_tx_buf_writeb(dev, buf, offset++, length); ++ ++ // 2.4GHz (continuous channels) ++ /* First channel number */ ++ zmw_tx_buf_writeh(dev, buf, offset++, 1); //Start from channle 1 ++ /* Number of channels */ ++ zmw_tx_buf_writeh(dev, buf, offset++, count_24G); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt ; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel > 4000 && wd->regulationTable.allowChannel[i].channel < 5000) ++ { // 5GHz 4000 -5000Mhz ++ channelNum = (wd->regulationTable.allowChannel[i].channel-4000)/5; ++ /* First channel number */ ++ zmw_tx_buf_writeh(dev, buf, offset++, channelNum); ++ /* Number of channels */ ++ zmw_tx_buf_writeh(dev, buf, offset++, 1); ++ } ++ else if (wd->regulationTable.allowChannel[i].channel >= 5000) ++ { // 5GHz >5000Mhz ++ channelNum = (wd->regulationTable.allowChannel[i].channel-5000)/5; ++ /* First channel number */ ++ zmw_tx_buf_writeh(dev, buf, offset++, channelNum); ++ /* Number of channels */ ++ zmw_tx_buf_writeh(dev, buf, offset++, 1); ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++ return offset; ++} ++ ++void zfStaStartConnectCb(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zfStaStartConnect(dev, wd->sta.bIsSharedKey); ++} ++ ++void zfStaStartConnect(zdev_t* dev, u8_t bIsSharedKey) ++{ ++ u32_t p1, p2; ++ u8_t newConnState; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ /* p1_low = algorithm number, p1_high = transaction sequence number */ ++ if ( bIsSharedKey ) ++ { ++ //wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_SHARE_1; ++ newConnState = ZM_STA_CONN_STATE_AUTH_SHARE_1; ++ zm_debug_msg0("ZM_STA_CONN_STATE_AUTH_SHARE_1"); ++ p1 = ZM_AUTH_ALGO_SHARED_KEY; ++ } ++ else ++ { ++ //wd->sta.connectState = ZM_STA_CONN_STATE_AUTH_OPEN; ++ newConnState = ZM_STA_CONN_STATE_AUTH_OPEN; ++ zm_debug_msg0("ZM_STA_CONN_STATE_AUTH_OPEN"); ++ if( wd->sta.leapEnabled ) ++ p1 = ZM_AUTH_ALGO_LEAP; ++ else ++ p1 = ZM_AUTH_ALGO_OPEN_SYSTEM; ++ } ++ ++ /* status code */ ++ p2 = 0x0; ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.connectTimer = wd->tick; ++ wd->sta.connectState = newConnState; ++ zmw_leave_critical_section(dev); ++ ++ /* send the 1st authentication frame */ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_AUTH, wd->sta.bssid, p1, p2, 0); ++ ++ return; ++} ++ ++void zfSendNullData(zdev_t* dev, u8_t type) ++{ ++ zbuf_t* buf; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ u16_t err; ++ u16_t hlen; ++ u16_t header[(34+8+1)/2]; ++ u16_t bcastAddr[3] = {0xffff,0xffff,0xffff}; ++ u16_t *dstAddr; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); ++ return; ++ } ++ ++ zfwBufSetSize(dev, buf, 0); ++ ++ //zm_msg2_mm(ZM_LV_2, "buf->len=", buf->len); ++ ++ if ( wd->wlanMode == ZM_MODE_IBSS) ++ { ++ dstAddr = bcastAddr; ++ } ++ else ++ { ++ dstAddr = wd->sta.bssid; ++ } ++ ++ if (wd->sta.wmeConnected != 0) ++ { ++ /* If connect to a WMM AP, Send QoS Null data */ ++ hlen = zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_QOS_NULL, dstAddr, header, 0, buf, 0, 0); ++ } ++ else ++ { ++ hlen = zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_NULL, dstAddr, header, 0, buf, 0, 0); ++ } ++ ++ if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ header[4] |= 0x0100; //TODS bit ++ } ++ ++ if ( type == 1 ) ++ { ++ header[4] |= 0x1000; ++ } ++ ++ /* Get buffer DMA address */ ++ //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) ++ //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) ++ //{ ++ // goto zlError; ++ //} ++ ++ /*increase unicast frame counter*/ ++ wd->commTally.txUnicastFrm++; ++ ++ if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ ++ ++ return; ++ ++zlError: ++ ++ zfwBufFree(dev, buf, 0); ++ return; ++ ++} ++ ++void zfSendPSPoll(zdev_t* dev) ++{ ++ zbuf_t* buf; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ u16_t err; ++ u16_t hlen; ++ u16_t header[(8+24+1)/2]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); ++ return; ++ } ++ ++ zfwBufSetSize(dev, buf, 0); ++ ++ //zm_msg2_mm(ZM_LV_2, "buf->len=", buf->len); ++ ++ zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_PSPOLL, wd->sta.bssid, header, 0, buf, 0, 0); ++ ++ header[0] = 20; ++ header[4] |= 0x1000; ++ header[5] = wd->sta.aid | 0xc000; //Both bit-14 and bit-15 are 1 ++ hlen = 16 + 8; ++ ++ /* Get buffer DMA address */ ++ //if ((addrTblSize = zfwBufMapDma(dev, buf, &addrTbl)) == 0) ++ //if ((addrTblSize = zfwMapTxDma(dev, buf, &addrTbl)) == 0) ++ //{ ++ // goto zlError; ++ //} ++ ++ if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ ++ return; ++ ++zlError: ++ ++ zfwBufFree(dev, buf, 0); ++ return; ++ ++} ++ ++void zfSendBA(zdev_t* dev, u16_t start_seq, u8_t *bitmap) ++{ ++ zbuf_t* buf; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ u16_t err; ++ u16_t hlen; ++ u16_t header[(8+24+1)/2]; ++ u16_t i, offset = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ((buf = zfwBufAllocate(dev, 1024)) == NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Alloc mm buf Fail!"); ++ return; ++ } ++ ++ zfwBufSetSize(dev, buf, 12); // 28 = FC 2 + DU 2 + RA 6 + TA 6 + BAC 2 + SEQ 2 + BitMap 8 ++ // 12 = BAC 2 + SEQ 2 + BitMap 8 ++ ++ //zm_msg2_mm(ZM_LV_2, "buf->len=", buf->len); ++ ++ zfTxGenMmHeader(dev, ZM_WLAN_FRAME_TYPE_BA, wd->sta.bssid, header, 0, buf, 0, 0); ++ ++ header[0] = 32; /* MAC header 16 + BA control 2 + BA info 10 + FCS 4*/ ++ header[1] = 0x4; /* No ACK */ ++ ++ /* send by OFDM 6M */ ++ header[2] = (u16_t)(zcRateToPhyCtrl[4] & 0xffff); ++ header[3] = (u16_t)(zcRateToPhyCtrl[4]>>16) & 0xffff; ++ ++ hlen = 16 + 8; /* MAC header 16 + control 8*/ ++ offset = 0; ++ zmw_tx_buf_writeh(dev, buf, offset, 0x05); /*compressed bitmap on*/ ++ offset+=2; ++ zmw_tx_buf_writeh(dev, buf, offset, start_seq); ++ offset+=2; ++ ++ for (i=0; i<8; i++) { ++ zmw_tx_buf_writeb(dev, buf, offset, bitmap[i]); ++ offset++; ++ } ++ ++ if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ ++ return; ++ ++zlError: ++ ++ zfwBufFree(dev, buf, 0); ++ return; ++ ++} ++ ++void zfStaGetTxRate(zdev_t* dev, u16_t* macAddr, u32_t* phyCtrl, ++ u16_t* rcProbingFlag) ++{ ++ u8_t addr[6], i; ++ u8_t rate; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ZM_MAC_WORD_TO_BYTE(macAddr, addr); ++ *phyCtrl = 0; ++ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ zmw_enter_critical_section(dev); ++ rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->sta.oppositeInfo[0].rcCell, rcProbingFlag); ++//#ifdef ZM_FB50 ++ //rate = 27; ++//#endif ++ *phyCtrl = zcRateToPhyCtrl[rate]; ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ for(i=0; ista.oppositeCount; i++) ++ { ++ if ( addr[0] && 0x01 == 1 ) // The default beacon transmitted rate is CCK and 1 Mbps , but the a mode should use ++ // OFDM modulation and 6Mbps to transmit beacon. ++ { ++ //rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->sta.oppositeInfo[i].rcCell, rcProbingFlag); ++ rate = wd->sta.oppositeInfo[i].rcCell.operationRateSet[0]; ++ *phyCtrl = zcRateToPhyCtrl[rate]; ++ break; ++ } ++ else if ( zfMemoryIsEqual(addr, wd->sta.oppositeInfo[i].macAddr, 6) ) ++ { ++ rate = (u8_t)zfRateCtrlGetTxRate(dev, &wd->sta.oppositeInfo[i].rcCell, rcProbingFlag); ++ *phyCtrl = zcRateToPhyCtrl[rate]; ++ break; ++ } ++ } ++ zmw_leave_critical_section(dev); ++ } ++ ++ return; ++} ++ ++struct zsMicVar* zfStaGetRxMicKey(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t keyIndex; ++ u8_t da0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* if need not check MIC, return NULL */ ++ if ( ((wd->sta.encryMode != ZM_TKIP)&&(wd->sta.encryMode != ZM_AES))|| ++ (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) ++ { ++ return NULL; ++ } ++ ++ da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ ++ if ((zmw_rx_buf_readb(dev, buf, 0) & 0x80) == 0x80) ++ keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+5); /* Qos Packet*/ ++ else ++ keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+3); /* normal Packet*/ ++ keyIndex = (keyIndex & 0xc0) >> 6; ++ ++ return (&wd->sta.rxMicKey[keyIndex]); ++} ++ ++struct zsMicVar* zfStaGetTxMicKey(zdev_t* dev, zbuf_t* buf) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* if need not check MIC, return NULL */ ++ //if ( ((wd->sta.encryMode != ZM_TKIP)&&(wd->sta.encryMode != ZM_AES))|| ++ // (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) ++ if ( (wd->sta.encryMode != ZM_TKIP) || (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) ++ { ++ return NULL; ++ } ++ ++ return (&wd->sta.txMicKey); ++} ++ ++u16_t zfStaRxValidateFrame(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t frameType, frameCtrl; ++ u8_t da0; ++ //u16_t sa[3]; ++ u16_t ret; ++ u16_t i; ++ //u8_t sa0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ frameType = zmw_rx_buf_readb(dev, buf, 0); ++ da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ //sa0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); ++ ++ if ( (!zfStaIsConnected(dev))&&((frameType & 0xf) == ZM_WLAN_DATA_FRAME) ) ++ { ++ return ZM_ERR_DATA_BEFORE_CONNECTED; ++ } ++ ++ ++ if ( (zfStaIsConnected(dev))&&((frameType & 0xf) == ZM_WLAN_DATA_FRAME) ) ++ { ++ /* check BSSID */ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ /* Big Endian and Little Endian Compatibility */ ++ u16_t mac[3]; ++ mac[0] = zmw_cpu_to_le16(wd->sta.bssid[0]); ++ mac[1] = zmw_cpu_to_le16(wd->sta.bssid[1]); ++ mac[2] = zmw_cpu_to_le16(wd->sta.bssid[2]); ++ if ( !zfRxBufferEqualToStr(dev, buf, (u8_t *)mac, ++ ZM_WLAN_HEADER_A2_OFFSET, 6) ) ++ { ++/*We will get lots of garbage data, especially in AES mode.*/ ++/*To avoid sending too many deauthentication frames in STA mode, mark it.*/ ++#if 0 ++ /* If unicast frame, send deauth to the transmitter */ ++ if (( da0 & 0x01 ) == 0) ++ { ++ for (i=0; i<3; i++) ++ { ++ sa[i] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+(i*2)); ++ } ++ /* If mutilcast address, don't send deauthentication*/ ++ if (( sa0 & 0x01 ) == 0) ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_DEAUTH, sa, 7, 0, 0); ++ } ++#endif ++ return ZM_ERR_DATA_BSSID_NOT_MATCHED; ++ } ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ /* Big Endian and Little Endian Compatibility */ ++ u16_t mac[3]; ++ mac[0] = zmw_cpu_to_le16(wd->sta.bssid[0]); ++ mac[1] = zmw_cpu_to_le16(wd->sta.bssid[1]); ++ mac[2] = zmw_cpu_to_le16(wd->sta.bssid[2]); ++ if ( !zfRxBufferEqualToStr(dev, buf, (u8_t *)mac, ++ ZM_WLAN_HEADER_A3_OFFSET, 6) ) ++ { ++ return ZM_ERR_DATA_BSSID_NOT_MATCHED; ++ } ++ } ++ ++ frameCtrl = zmw_rx_buf_readb(dev, buf, 1); ++ ++ /* check security bit */ ++ if ( wd->sta.dropUnencryptedPkts && ++ (wd->sta.wepStatus != ZM_ENCRYPTION_WEP_DISABLED )&& ++ ( !(frameCtrl & ZM_BIT_6) ) ) ++ { /* security on, but got data without encryption */ ++ ++ #if 1 ++ ret = ZM_ERR_DATA_NOT_ENCRYPTED; ++ if ( wd->sta.pStaRxSecurityCheckCb != NULL ) ++ { ++ ret = wd->sta.pStaRxSecurityCheckCb(dev, buf); ++ } ++ else ++ { ++ ret = ZM_ERR_DATA_NOT_ENCRYPTED; ++ } ++ if (ret == ZM_ERR_DATA_NOT_ENCRYPTED) ++ { ++ wd->commTally.swRxDropUnencryptedCount++; ++ } ++ return ret; ++ #else ++ if ( (wd->sta.wepStatus != ZM_ENCRYPTION_TKIP)&& ++ (wd->sta.wepStatus != ZM_ENCRYPTION_AES) ) ++ { ++ return ZM_ERR_DATA_NOT_ENCRYPTED; ++ } ++ #endif ++ } ++ } ++ ++ return ZM_SUCCESS; ++} ++ ++void zfStaMicFailureHandling(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t da0; ++ u8_t micNotify = 1; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK ) ++ { ++ return; ++ } ++ ++ zmw_enter_critical_section(dev); ++ ++ wd->sta.cmMicFailureCount++; ++ ++ if ( wd->sta.cmMicFailureCount == 1 ) ++ { ++ zm_debug_msg0("get the first MIC failure"); ++ //zfTimerSchedule(dev, ZM_EVENT_CM_TIMER, ZM_TICK_CM_TIMEOUT); ++ ++ /* Timer Resolution on WinXP is 15/16 ms */ ++ /* Decrease Time offset for Counter Measure */ ++ zfTimerSchedule(dev, ZM_EVENT_CM_TIMER, ZM_TICK_CM_TIMEOUT - ZM_TICK_CM_TIMEOUT_OFFSET); ++ } ++ else if ( wd->sta.cmMicFailureCount == 2 ) ++ { ++ zm_debug_msg0("get the second MIC failure"); ++ /* reserve 2 second for OS to send MIC failure report to AP */ ++ wd->sta.cmDisallowSsidLength = wd->sta.ssidLen; ++ zfMemoryCopy(wd->sta.cmDisallowSsid, wd->sta.ssid, wd->sta.ssidLen); ++ //wd->sta.cmMicFailureCount = 0; ++ zfTimerCancel(dev, ZM_EVENT_CM_TIMER); ++ //zfTimerSchedule(dev, ZM_EVENT_CM_DISCONNECT, ZM_TICK_CM_DISCONNECT); ++ ++ /* Timer Resolution on WinXP is 15/16 ms */ ++ /* Decrease Time offset for Counter Measure */ ++ zfTimerSchedule(dev, ZM_EVENT_CM_DISCONNECT, ZM_TICK_CM_DISCONNECT - ZM_TICK_CM_DISCONNECT_OFFSET); ++ } ++ else ++ { ++ micNotify = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (micNotify == 1) ++ { ++ da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ if ( da0 & 0x01 ) ++ { ++ if (wd->zfcbMicFailureNotify != NULL) ++ { ++ wd->zfcbMicFailureNotify(dev, wd->sta.bssid, ZM_MIC_GROUP_ERROR); ++ } ++ } ++ else ++ { ++ if (wd->zfcbMicFailureNotify != NULL) ++ { ++ wd->zfcbMicFailureNotify(dev, wd->sta.bssid, ZM_MIC_PAIRWISE_ERROR); ++ } ++ } ++ } ++} ++ ++ ++u8_t zfStaBlockWlanScan(zdev_t* dev) ++{ ++ u8_t ret=FALSE; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.bChannelScan ) ++ { ++ return TRUE; ++ } ++ ++ return ret; ++} ++ ++void zfStaResetStatus(zdev_t* dev, u8_t bInit) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zfHpDisableBeacon(dev); ++ ++ wd->dtim = 1; ++ wd->sta.capability[0] = 0x01; ++ wd->sta.capability[1] = 0x00; ++ /* 802.11h */ ++ if (wd->sta.DFSEnable || wd->sta.TPCEnable) ++ wd->sta.capability[1] |= ZM_BIT_0; ++ ++ /* release queued packets */ ++ for(i=0; ista.ibssPSDataCount; i++) ++ { ++ zfwBufFree(dev, wd->sta.ibssPSDataQueue[i], 0); ++ } ++ ++ for(i=0; ista.staPSDataCount; i++) ++ { ++ zfwBufFree(dev, wd->sta.staPSDataQueue[i], 0); ++ } ++ ++ wd->sta.ibssPSDataCount = 0; ++ wd->sta.staPSDataCount = 0; ++ zfZeroMemory((u8_t*) &wd->sta.staPSList, sizeof(struct zsStaPSList)); ++ ++ wd->sta.wmeConnected = 0; ++ wd->sta.psMgr.tempWakeUp = 0; ++ wd->sta.qosInfo = 0; ++ zfQueueFlush(dev, wd->sta.uapsdQ); ++ ++ return; ++ ++} ++ ++void zfStaIbssMonitoring(zdev_t* dev, u8_t reset) ++{ ++ u16_t i; ++ u16_t oppositeCount; ++ struct zsPartnerNotifyEvent event; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ //zm_debug_msg1("zfStaIbssMonitoring %d", wd->sta.oppositeCount); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ( wd->sta.oppositeCount == 0 ) ++ { ++ goto done; ++ } ++ ++ if ( wd->sta.bChannelScan ) ++ { ++ goto done; ++ } ++ ++ oppositeCount = wd->sta.oppositeCount; ++ ++ for(i=0; i < ZM_MAX_OPPOSITE_COUNT; i++) ++ { ++ if ( oppositeCount == 0 ) ++ { ++ break; ++ } ++ ++ if ( reset ) ++ { ++ wd->sta.oppositeInfo[i].valid = 0; ++ } ++ ++ if ( wd->sta.oppositeInfo[i].valid == 0 ) ++ { ++ continue; ++ } ++ ++ oppositeCount--; ++ ++ if ( wd->sta.oppositeInfo[i].aliveCounter ) ++ { ++ zm_debug_msg1("Setting alive to ", wd->sta.oppositeInfo[i].aliveCounter); ++ ++ zmw_leave_critical_section(dev); ++ ++ if ( wd->sta.oppositeInfo[i].aliveCounter != ZM_IBSS_PEER_ALIVE_COUNTER ) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBEREQ, ++ (u16_t*)wd->sta.oppositeInfo[i].macAddr, 1, 0, 0); ++ } ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.oppositeInfo[i].aliveCounter--; ++ } ++ else ++ { ++ zm_debug_msg0("zfStaIbssMonitoring remove the peer station"); ++ zfMemoryCopy(event.bssid, (u8_t *)(wd->sta.bssid), 6); ++ zfMemoryCopy(event.peerMacAddr, wd->sta.oppositeInfo[i].macAddr, 6); ++ ++ wd->sta.oppositeInfo[i].valid = 0; ++ wd->sta.oppositeCount--; ++ if (wd->zfcbIbssPartnerNotify != NULL) ++ { ++ zmw_leave_critical_section(dev); ++ wd->zfcbIbssPartnerNotify(dev, 0, &event); ++ zmw_enter_critical_section(dev); ++ } ++ } ++ } ++ ++done: ++ if ( reset == 0 ) ++ { ++ zfTimerSchedule(dev, ZM_EVENT_IBSS_MONITOR, ZM_TICK_IBSS_MONITOR); ++ } ++ ++ zmw_leave_critical_section(dev); ++} ++ ++void zfInitPartnerNotifyEvent(zdev_t* dev, zbuf_t* buf, struct zsPartnerNotifyEvent *event) ++{ ++ u16_t *peerMacAddr; ++ ++ zmw_get_wlan_dev(dev); ++ ++ peerMacAddr = (u16_t *)event->peerMacAddr; ++ ++ zfMemoryCopy(event->bssid, (u8_t *)(wd->sta.bssid), 6); ++ peerMacAddr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); ++ peerMacAddr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET + 2); ++ peerMacAddr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET + 4); ++} ++ ++void zfStaInitOppositeInfo(zdev_t* dev) ++{ ++ int i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for(i=0; ista.oppositeInfo[i].valid = 0; ++ wd->sta.oppositeInfo[i].aliveCounter = ZM_IBSS_PEER_ALIVE_COUNTER; ++ } ++} ++#ifdef ZM_ENABLE_CENC ++u16_t zfStaAddIeCenc(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->sta.cencIe[1] != 0) ++ { ++ zfCopyToIntTxBuffer(dev, buf, wd->sta.cencIe, offset, wd->sta.cencIe[1]+2); ++ offset += (wd->sta.cencIe[1]+2); ++ } ++ return offset; ++} ++#endif //ZM_ENABLE_CENC ++u16_t zfStaProcessAction(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t category, actionDetails; ++ zmw_get_wlan_dev(dev); ++ ++ category = zmw_rx_buf_readb(dev, buf, 24); ++ actionDetails = zmw_rx_buf_readb(dev, buf, 25); ++ switch (category) ++ { ++ case 0: //Spectrum Management ++ switch(actionDetails) ++ { ++ case 0: //Measurement Request ++ break; ++ case 1: //Measurement Report ++ //ProcessActionSpectrumFrame_MeasurementReport(Adapter,pActionBody+3); ++ break; ++ case 2: //TPC request ++ //if (wd->sta.TPCEnable) ++ // zfStaUpdateDot11HTPC(dev, buf); ++ break; ++ case 3: //TPC report ++ //if (wd->sta.TPCEnable) ++ // zfStaUpdateDot11HTPC(dev, buf); ++ break; ++ case 4: //Channel Switch Announcement ++ if (wd->sta.DFSEnable) ++ zfStaUpdateDot11HDFS(dev, buf); ++ break; ++ default: ++ zm_debug_msg1("Action Frame contain not support action field ", actionDetails); ++ break; ++ } ++ break; ++ case ZM_WLAN_BLOCK_ACK_ACTION_FRAME: ++ zfAggBlockAckActionFrame(dev, buf); ++ break; ++ case 17: //Qos Management ++ break; ++ } ++ ++ return 0; ++} ++ ++/* Determine the time not send beacon , if more than some value , ++ re-write the beacon start address */ ++void zfReWriteBeaconStartAddress(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->tickIbssSendBeacon++; // Increase 1 per 10ms . ++ zmw_leave_critical_section(dev); ++ ++ if ( wd->tickIbssSendBeacon == 40 ) ++ { ++// DbgPrint("20070727"); ++ zfHpEnableBeacon(dev, ZM_MODE_IBSS, wd->beaconInterval, wd->dtim, (u8_t)wd->sta.atimWindow); ++ zmw_enter_critical_section(dev); ++ wd->tickIbssSendBeacon = 0; ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++struct zsTkipSeed* zfStaGetRxSeed(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t keyIndex; ++ u8_t da0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* if need not check MIC, return NULL */ ++ if ( ((wd->sta.encryMode != ZM_TKIP)&&(wd->sta.encryMode != ZM_AES))|| ++ (wd->sta.wpaState < ZM_STA_WPA_STATE_PK_OK) ) ++ { ++ return NULL; ++ } ++ ++ da0 = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ ++ if ((zmw_rx_buf_readb(dev, buf, 0) & 0x80) == 0x80) ++ keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+5); /* Qos Packet*/ ++ else ++ keyIndex = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_IV_OFFSET+3); /* normal Packet*/ ++ keyIndex = (keyIndex & 0xc0) >> 6; ++ ++ return (&wd->sta.rxSeed[keyIndex]); ++} ++ ++void zfStaEnableSWEncryption(zdev_t *dev, u8_t value) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.SWEncryptEnable = value; ++ zfHpSWDecrypt(dev, 1); ++ zfHpSWEncrypt(dev, 1); ++} ++ ++void zfStaDisableSWEncryption(zdev_t *dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.SWEncryptEnable = 0; ++ zfHpSWDecrypt(dev, 0); ++ zfHpSWEncrypt(dev, 0); ++} ++ ++u16_t zfComputeBssInfoWeightValue(zdev_t *dev, u8_t isBMode, u8_t isHT, u8_t isHT40, u8_t signalStrength) ++{ ++ u8_t weightOfB = 0; ++ u8_t weightOfAGBelowThr = 0; ++ u8_t weightOfAGUpThr = 15; ++ u8_t weightOfN20BelowThr = 15; ++ u8_t weightOfN20UpThr = 30; ++ u8_t weightOfN40BelowThr = 16; ++ u8_t weightOfN40UpThr = 32; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if( isBMode == 0 ) ++ return (signalStrength + weightOfB); // pure b mode , do not add the weight value for this AP ! ++ else ++ { ++ if( isHT == 0 && isHT40 == 0 ) ++ { // a , g , b/g mode ! add the weight value 15 for this AP if it's signal strength is more than some value ! ++ if( signalStrength < 18 ) // -77 dBm ++ return signalStrength + weightOfAGBelowThr; ++ else ++ return (signalStrength + weightOfAGUpThr); ++ } ++ else if( isHT == 1 && isHT40 == 0 ) ++ { // 80211n mode use 20MHz ++ if( signalStrength < 23 ) // -72 dBm ++ return (signalStrength + weightOfN20BelowThr); ++ else ++ return (signalStrength + weightOfN20UpThr); ++ } ++ else // isHT == 1 && isHT40 == 1 ++ { // 80211n mode use 40MHz ++ if( signalStrength < 16 ) // -79 dBm ++ return (signalStrength + weightOfN40BelowThr); ++ else ++ return (signalStrength + weightOfN40UpThr); ++ } ++ } ++} ++ ++u16_t zfStaAddIbssAdditionalIE(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; ista.ibssAdditionalIESize; i++) ++ { ++ zmw_tx_buf_writeb(dev, buf, offset++, wd->sta.ibssAdditionalIE[i]); ++ } ++ ++ return offset; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/coid.c +@@ -0,0 +1,2695 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : iod.c */ ++/* */ ++/* Abstract */ ++/* This module contains OID functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#include "../hal/hpreg.h" ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiWlanQueryMacAddress */ ++/* Query OWN MAC address. */ ++/* */ ++/* INPUTS */ ++/* addr : for return MAC address */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfiWlanQueryMacAddress(zdev_t* dev, u8_t* addr) ++{ ++ u16_t vapId = 0; ++ zmw_get_wlan_dev(dev); ++ ++ vapId = zfwGetVapId(dev); ++ ++ addr[0] = (u8_t)(wd->macAddr[0] & 0xff); ++ addr[1] = (u8_t)(wd->macAddr[0] >> 8); ++ addr[2] = (u8_t)(wd->macAddr[1] & 0xff); ++ addr[3] = (u8_t)(wd->macAddr[1] >> 8); ++ addr[4] = (u8_t)(wd->macAddr[2] & 0xff); ++ if (vapId == 0xffff) ++ addr[5] = (u8_t)(wd->macAddr[2] >> 8); ++ else ++ { ++#ifdef ZM_VAPMODE_MULTILE_SSID ++ addr[5] = (u8_t)(wd->macAddr[2] >> 8); // Multiple SSID ++#else ++ addr[5] = vapId + 1 + (u8_t)(wd->macAddr[2] >> 8); //VAP ++#endif ++ } ++ ++ return; ++} ++ ++void zfiWlanQueryBssList(zdev_t* dev, struct zsBssList* pBssList) ++{ ++ struct zsBssInfo* pBssInfo; ++ struct zsBssInfo* pDstBssInfo; ++ u8_t i; ++ u8_t* pMemList; ++ u8_t* pMemInfo; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ pMemList = (u8_t*) pBssList; ++ pMemInfo = pMemList + sizeof(struct zsBssList); ++ pBssList->head = (struct zsBssInfo*) pMemInfo; ++ ++ zmw_enter_critical_section(dev); ++ ++ pBssInfo = wd->sta.bssList.head; ++ pDstBssInfo = (struct zsBssInfo*) pMemInfo; ++ pBssList->bssCount = wd->sta.bssList.bssCount; ++ ++ for( i=0; ista.bssList.bssCount; i++ ) ++ { ++ zfMemoryCopy((u8_t*)pDstBssInfo, (u8_t*)pBssInfo, ++ sizeof(struct zsBssInfo)); ++ ++ if ( pBssInfo->next != NULL ) ++ { ++ pBssInfo = pBssInfo->next; ++ pDstBssInfo->next = pDstBssInfo + 1; ++ pDstBssInfo++; ++ } ++ else ++ { ++ zm_assert(i==(wd->sta.bssList.bssCount-1)); ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zfScanMgrScanAck(dev); ++} ++ ++void zfiWlanQueryBssListV1(zdev_t* dev, struct zsBssListV1* bssListV1) ++{ ++ struct zsBssInfo* pBssInfo; ++ //struct zsBssInfo* pDstBssInfo; ++ u8_t i, j, bdrop = 0, k = 0, Same_Count = 0; ++ u8_t bssid[6]; ++ //u8_t* pMemList; ++ //u8_t* pMemInfo; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ bssListV1->bssCount = wd->sta.bssList.bssCount; ++ ++ pBssInfo = wd->sta.bssList.head; ++ ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid); ++ ++ for( i=0; ista.bssList.bssCount; i++ ) ++ { ++ bdrop = 0; ++ if ( zfStaIsConnected(dev) ++ && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ) ++ { ++ for (j = 0; j < 6; j++) ++ { ++ if ( pBssInfo->bssid[j] != bssid[j] ) ++ { ++ break; ++ } ++ } ++ ++ if ( (j == 6) ++ &&((pBssInfo->ssid[1] == wd->sta.ssidLen) || (pBssInfo->ssid[1] == 0) )&& (pBssInfo->frequency == wd->frequency) ) ++ { ++ if(pBssInfo->ssid[1] == 0) ++ pBssInfo->ssid[1] = wd->sta.ssidLen; ++ ++ if(Same_Count == 0) ++ {//First meet ++ Same_Count++; ++ } ++ else ++ {//same one ++ bdrop = 1; ++ bssListV1->bssCount--; ++ } ++ ++ } ++ } ++ ++ if (bdrop == 0) ++ { ++ zfMemoryCopy((u8_t*)(&bssListV1->bssInfo[k]), (u8_t*)pBssInfo, ++ sizeof(struct zsBssInfo)); ++ ++ if(Same_Count == 1) ++ { ++ zfMemoryCopy(&(bssListV1->bssInfo[k].ssid[2]), wd->sta.ssid, wd->sta.ssidLen); ++ Same_Count++; ++ } ++ ++ k++; ++ } ++ ++ if ( pBssInfo->next != NULL ) ++ { ++ pBssInfo = pBssInfo->next; ++ } ++ else ++ { ++ zm_assert(i==(wd->sta.bssList.bssCount-1)); ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zfScanMgrScanAck(dev); ++} ++ ++void zfiWlanQueryAdHocCreatedBssDesc(zdev_t* dev, struct zsBssInfo *pBssInfo) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zfMemoryCopy((u8_t *)pBssInfo, (u8_t *)&wd->sta.ibssBssDesc, sizeof(struct zsBssInfo)); ++} ++ ++u8_t zfiWlanQueryAdHocIsCreator(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->sta.ibssBssIsCreator; ++} ++ ++u32_t zfiWlanQuerySupportMode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->supportMode; ++} ++ ++u32_t zfiWlanQueryTransmitPower(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ u32_t ret = 0; ++ ++ if (zfStaIsConnected(dev)) { ++ ret = wd->sta.connPowerInHalfDbm; ++ } else { ++ ret = zfHpGetTransmitPower(dev); ++ } ++ ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiWlanFlushBssList */ ++/* Flush BSSID List. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2006.12 */ ++/* */ ++/************************************************************************/ ++void zfiWlanFlushBssList(zdev_t* dev) ++{ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ /* Call zfBssInfoRefresh() twice to remove all entry */ ++ zfBssInfoRefresh(dev, 1); ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetWlanMode(zdev_t* dev, u8_t wlanMode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->ws.wlanMode = wlanMode; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetAuthenticationMode(zdev_t* dev, u8_t authMode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->ws.authMode = authMode; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetWepStatus(zdev_t* dev, u8_t wepStatus) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->ws.wepStatus = wepStatus; ++ zmw_leave_critical_section(dev); ++ ++} ++ ++void zfiWlanSetSSID(zdev_t* dev, u8_t* ssid, u8_t ssidLength) ++{ ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( ssidLength <= 32 ) ++ { ++ zmw_enter_critical_section(dev); ++ ++ wd->ws.ssidLen = ssidLength; ++ zfMemoryCopy(wd->ws.ssid, ssid, ssidLength); ++ ++ if ( ssidLength < 32 ) ++ { ++ wd->ws.ssid[ssidLength] = 0; ++ } ++ ++ wd->ws.probingSsidList[0].ssidLen = ssidLength; ++ zfMemoryCopy(wd->ws.probingSsidList[0].ssid, ssid, ssidLength); ++ for (i=1; iws.probingSsidList[i].ssidLen = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++void zfiWlanSetFragThreshold(zdev_t* dev, u16_t fragThreshold) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (fragThreshold == 0) ++ { /* fragmentation is disabled */ ++ wd->fragThreshold = 32767; ++ } ++ else if (fragThreshold < 256) ++ { ++ /* Minimum fragment threshold */ ++ wd->fragThreshold = 256; ++ } ++ else if (fragThreshold > 2346) ++ { ++ wd->fragThreshold = 2346; ++ } ++ else ++ { ++ wd->fragThreshold = fragThreshold & 0xfffe; ++ } ++ ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetRtsThreshold(zdev_t* dev, u16_t rtsThreshold) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->rtsThreshold = rtsThreshold; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetFrequency(zdev_t* dev, u32_t frequency, u8_t bImmediate) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( bImmediate ) ++ { ++ zmw_enter_critical_section(dev); ++ wd->frequency = (u16_t) (frequency/1000); ++ zmw_leave_critical_section(dev); ++ zfCoreSetFrequency(dev, wd->frequency); ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ if( frequency == 0 ) ++ { // Auto select clean channel depend on wireless environment ! ++ wd->ws.autoSetFrequency = 0; ++ } ++ wd->ws.frequency = (u16_t) (frequency/1000); ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++void zfiWlanSetBssid(zdev_t* dev, u8_t* bssid) ++{ ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ for (i=0; i<6; i++) ++ { ++ wd->ws.desiredBssid[i] = bssid[i]; ++ } ++ wd->ws.bDesiredBssid = TRUE; ++ zmw_leave_critical_section(dev); ++ ++} ++ ++void zfiWlanSetBeaconInterval(zdev_t* dev, ++ u16_t beaconInterval, ++ u8_t bImmediate) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( bImmediate ) ++ { ++ zmw_enter_critical_section(dev); ++ wd->beaconInterval = beaconInterval; ++ zmw_leave_critical_section(dev); ++ ++ /* update beacon interval here */ ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ wd->ws.beaconInterval = beaconInterval; ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++ ++void zfiWlanSetDtimCount(zdev_t* dev, u8_t dtim) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (dtim > 0) ++ { ++ wd->ws.dtim = dtim; ++ } ++ zmw_leave_critical_section(dev); ++} ++ ++ ++void zfiWlanSetAtimWindow(zdev_t* dev, u16_t atimWindow, u8_t bImmediate) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( bImmediate ) ++ { ++ zmw_enter_critical_section(dev); ++ wd->sta.atimWindow = atimWindow; ++ zmw_leave_critical_section(dev); ++ ++ /* atim window here */ ++ } ++ else ++ { ++ zmw_enter_critical_section(dev); ++ wd->ws.atimWindow = atimWindow; ++ zmw_leave_critical_section(dev); ++ } ++} ++ ++ ++void zfiWlanSetEncryMode(zdev_t* dev, u8_t encryMode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ /* Hostapd Issue */ ++ if ((wd->ws.encryMode != ZM_AES) && (wd->ws.encryMode != ZM_TKIP)) ++ wd->ws.encryMode = encryMode; ++ } ++ else ++ wd->ws.encryMode = encryMode; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetDefaultKeyId(zdev_t* dev, u8_t keyId) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.keyId = keyId; ++} ++ ++u8_t zfiWlanQueryIsPKInstalled(zdev_t *dev, u8_t *staMacAddr) ++{ ++ u8_t isInstalled = 0; ++ ++#if 1 ++//#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ u8_t res, peerIdx; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, (u16_t *)staMacAddr, &peerIdx); ++ if( res == 0 ) ++ { ++ isInstalled = wd->sta.oppositeInfo[peerIdx].pkInstalled; ++ } ++ zmw_leave_critical_section(dev); ++//#endif ++#endif ++ ++ return isInstalled; ++} ++ ++u8_t zfiWlanSetKey(zdev_t* dev, struct zsKeyInfo keyInfo) ++{ ++ u16_t broadcast[3] = {0xffff, 0xffff, 0xffff}; ++ u32_t* key; ++ u8_t encryMode = ZM_NO_WEP; ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ u8_t encryType = ZM_NO_WEP; ++#endif ++ u8_t micKey[16]; ++ u16_t id = 0; ++ u8_t vapId, i, addr[6]; ++ u8_t userIdx=0; ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ /* Determine opposite exist or not */ ++ u8_t res, peerIdx; ++// u8_t userIdx=0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->sta.ibssWpa2Psk == 1 ) ++ { ++ zmw_enter_critical_section(dev); ++ res = zfStaFindOppositeByMACAddr(dev, (u16_t*)keyInfo.macAddr, &peerIdx); ++ if( res == 0 ) ++ { ++ userIdx = peerIdx; ++ if ( wd->sta.oppositeInfo[userIdx].camIdx == 0xff ) ++ wd->sta.oppositeInfo[userIdx].camIdx = userIdx; ++ } ++ zmw_leave_critical_section(dev); ++ } ++#else ++ zmw_get_wlan_dev(dev); ++#endif ++ ++ if ( keyInfo.flag & ZM_KEY_FLAG_AUTHENTICATOR ) ++ { /* set key by authenticator */ ++ /* set pairwise key */ ++ if (keyInfo.flag & ZM_KEY_FLAG_PK) ++ { ++ /* Find STA's information */ ++ if ((id = zfApFindSta(dev, keyInfo.macAddr)) == 0xffff) ++ { ++ /* Can't STA in the staTable */ ++ return ZM_STATUS_FAILURE; ++ } ++ ++ wd->ap.staTable[id].iv16 = 0; ++ wd->ap.staTable[id].iv32 = 0; ++ ++ if (keyInfo.keyLength == 32) ++ { /* TKIP */ ++ //u8_t KeyRsc[6] = {0, 0, 0, 0, 0, 0}; ++ ++ /* In the current AP mode, we set KeyRsc to zero */ ++ //zfTkipInit(keyInfo.key, (u8_t*) wd->macAddr, ++ // &(wd->ap.staTable[id].txSeed), KeyRsc); ++ //zfTkipInit(keyInfo.key, (u8_t*) keyInfo.macAddr, ++ // &(wd->ap.staTable[id].rxSeed), KeyRsc); ++#ifdef ZM_ENABLE_CENC ++ if (keyInfo.flag & ZM_KEY_FLAG_CENC) ++ { ++ zm_debug_msg0("Set CENC pairwise Key"); ++ ++ wd->ap.staTable[id].encryMode = ZM_CENC; ++ ++ /* Reset txiv and rxiv */ ++ wd->ap.staTable[id].txiv[0] = 0x5c365c37; ++ wd->ap.staTable[id].txiv[1] = 0x5c365c36; ++ wd->ap.staTable[id].txiv[2] = 0x5c365c36; ++ wd->ap.staTable[id].txiv[3] = 0x5c365c36; ++ ++ wd->ap.staTable[id].rxiv[0] = 0x5c365c36; ++ wd->ap.staTable[id].rxiv[1] = 0x5c365c36; ++ wd->ap.staTable[id].rxiv[2] = 0x5c365c36; ++ wd->ap.staTable[id].rxiv[3] = 0x5c365c36; ++ ++ /* Set Key Index */ ++ wd->ap.staTable[id].cencKeyIdx = keyInfo.keyIndex; ++ ++ //zfCoreSetKey(dev, id+1, 1, ZM_CENC, (u16_t *)keyInfo.macAddr, ++ // (u32_t*) &keyInfo.key[16]); ++ } ++ else ++#endif //ZM_ENABLE_CENC ++ { ++ wd->ap.staTable[id].encryMode = ZM_TKIP; ++ ++ zfMemoryCopy(micKey, &keyInfo.key[16], 8); ++ zfMemoryCopy(&micKey[8], &keyInfo.key[24], 8); ++ ++ //zfCoreSetKey(dev, id+1, 1, ZM_TKIP, (u16_t *)keyInfo.macAddr, ++ // (u32_t*) micKey); ++ ++ /* For fragmentation, we use software MIC */ ++ zfMemoryCopy((u8_t *)&(wd->ap.staTable[id].txMicKey), &(keyInfo.key[16]), 8); ++ zfMemoryCopy((u8_t *)&(wd->ap.staTable[id].rxMicKey), &(keyInfo.key[24]), 8); ++ ++ } ++ } ++ else if (keyInfo.keyLength == 16) ++ { /* AES */ ++ wd->ap.staTable[id].encryMode = ZM_AES; ++ } ++ else if (keyInfo.keyLength == 0) ++ { ++ /* Clear Key Info */ ++ zfApClearStaKey(dev, (u16_t *)keyInfo.macAddr); ++ ++ return ZM_STATUS_SUCCESS; ++ } ++ else ++ { ++ return ZM_STATUS_FAILURE; ++ } ++ ++ //zfCoreSetKey(dev, id+1, 0, wd->ap.staTable[id].encryMode, ++ // (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ zfHpSetApPairwiseKey(dev, (u16_t *)keyInfo.macAddr, ++ wd->ap.staTable[id].encryMode, (u32_t*) keyInfo.key, ++ (u32_t*) &keyInfo.key[16], id+1); ++ wd->ap.staTable[id].keyIdx = id + 1 + 4; ++ } ++ else if (keyInfo.flag & ZM_KEY_FLAG_GK) ++ { ++ vapId = keyInfo.vapId; ++ ++ wd->ap.iv16[vapId] = 0; ++ wd->ap.iv32[vapId] = 0; ++ ++ if (keyInfo.keyLength == 32) ++ { /* TKIP */ ++ //u8_t KeyRsc[6] = {0, 0, 0, 0, 0, 0}; ++ ++ //zfTkipInit(keyInfo.key, (u8_t*) wd->macAddr, ++ // &(wd->ap.bcSeed), KeyRsc); ++#ifdef ZM_ENABLE_CENC ++ if (keyInfo.flag & ZM_KEY_FLAG_CENC) ++ { ++ encryMode = ZM_CENC; ++ zm_debug_msg0("Set CENC group Key"); ++ ++ /* Reset txiv and rxiv */ ++ wd->ap.txiv[vapId][0] = 0x5c365c36; ++ wd->ap.txiv[vapId][1] = 0x5c365c36; ++ wd->ap.txiv[vapId][2] = 0x5c365c36; ++ wd->ap.txiv[vapId][3] = 0x5c365c36; ++ ++ //zfCoreSetKey(dev, 0, 1, ZM_CENC, keyInfo.vapAddr, ++ // (u32_t*) &keyInfo.key[16]); ++ key = (u32_t*) keyInfo.key; ++ } ++ else ++#endif //ZM_ENABLE_CENC ++ { ++ encryMode = ZM_TKIP; ++ key = (u32_t *)keyInfo.key; ++ ++ /* set MIC key to HMAC */ ++ //zfCoreSetKey(dev, 0, 1, ZM_TKIP, broadcast, ++ // (u32_t*) (&keyInfo.key[16])); ++ //zfCoreSetKey(dev, 0, 1, ZM_TKIP, keyInfo.vapAddr, ++ // (u32_t*) (&keyInfo.key[16])); ++ ++ zfMicSetKey(&(keyInfo.key[16]), &(wd->ap.bcMicKey[0])); ++ key = (u32_t*) keyInfo.key; ++ } ++ } ++ else if (keyInfo.keyLength == 16) ++ { /* AES */ ++ encryMode = ZM_AES; ++ key = (u32_t *)keyInfo.key; ++ zm_debug_msg0("CWY - Set AES Group Key"); ++ } ++ else if (keyInfo.keyLength == 0) ++ { ++ /* Clear Key Info */ ++ zfApClearStaKey(dev, broadcast); ++ ++ /* Turn off WEP bit in the capability field */ ++ wd->ap.capab[vapId] &= 0xffef; ++ ++ return ZM_STATUS_SUCCESS; ++ } ++ else ++ { /* WEP */ ++ if (keyInfo.keyLength == 5) ++ { ++ encryMode = ZM_WEP64; ++ } ++ else if (keyInfo.keyLength == 13) ++ { ++ encryMode = ZM_WEP128; ++ } ++ else if (keyInfo.keyLength == 29) ++ { ++ encryMode = ZM_WEP256; ++ } ++ ++ key = (u32_t*) keyInfo.key; ++ } ++ ++ // Modification for CAM not support VAP search ++ //zfCoreSetKey(dev, 0, 0, encryMode, broadcast, key); ++ //zfCoreSetKey(dev, 0, 0, encryMode, wd->macAddr, key); ++ //zfCoreSetKey(dev, 0, 0, encryMode, keyInfo.vapAddr, key); ++ zfHpSetApGroupKey(dev, wd->macAddr, encryMode, ++ key, (u32_t*) &keyInfo.key[16], vapId); ++ ++ //zfiWlanSetEncryMode(dev, encryMode); ++ wd->ws.encryMode = encryMode; ++ ++ /* set the multicast address encryption type */ ++ wd->ap.encryMode[vapId] = encryMode; ++ ++ /* set the multicast key index */ ++ wd->ap.bcKeyIndex[vapId] = keyInfo.keyIndex; ++ wd->ap.bcHalKeyIdx[vapId] = vapId + 60; ++ ++ /* Turn on WEP bit in the capability field */ ++ wd->ap.capab[vapId] |= 0x10; ++ } ++ } ++ else ++ { /* set by supplicant */ ++ ++ if ( keyInfo.flag & ZM_KEY_FLAG_PK ) ++ { /* set pairwise key */ ++ ++ //zfTkipInit(keyInfo.key, (u8_t*) wd->macAddr, ++ // &wd->sta.txSeed, keyInfo.initIv); ++ //zfTkipInit(keyInfo.key, (u8_t*) wd->sta.bssid, ++ // &wd->sta.rxSeed[keyInfo.keyIndex], keyInfo.initIv); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if ( wd->sta.ibssWpa2Psk == 1 ) ++ { ++ /* unicast -- > pairwise key */ ++ wd->sta.oppositeInfo[userIdx].iv16 = 0; ++ wd->sta.oppositeInfo[userIdx].iv32 = 0; ++ } ++ else ++ { ++ wd->sta.iv16 = 0; ++ wd->sta.iv32 = 0; ++ } ++ ++ wd->sta.oppositeInfo[userIdx].pkInstalled = 1; ++#else ++ wd->sta.iv16 = 0; ++ wd->sta.iv32 = 0; ++ ++ wd->sta.oppositeInfo[userIdx].pkInstalled = 1; ++#endif ++ ++ if ( keyInfo.keyLength == 32 ) ++ { /* TKIP */ ++ zfTkipInit(keyInfo.key, (u8_t*) wd->macAddr, ++ &wd->sta.txSeed, keyInfo.initIv); ++ zfTkipInit(keyInfo.key, (u8_t*) wd->sta.bssid, ++ &wd->sta.rxSeed[keyInfo.keyIndex], keyInfo.initIv); ++ ++#ifdef ZM_ENABLE_CENC ++ if (keyInfo.flag & ZM_KEY_FLAG_CENC) ++ { ++ zm_debug_msg0("Set CENC pairwise Key"); ++ ++ wd->sta.encryMode = ZM_CENC; ++ ++ /* Reset txiv and rxiv */ ++ wd->sta.txiv[0] = 0x5c365c36; ++ wd->sta.txiv[1] = 0x5c365c36; ++ wd->sta.txiv[2] = 0x5c365c36; ++ wd->sta.txiv[3] = 0x5c365c36; ++ ++ wd->sta.rxiv[0] = 0x5c365c37; ++ wd->sta.rxiv[1] = 0x5c365c36; ++ wd->sta.rxiv[2] = 0x5c365c36; ++ wd->sta.rxiv[3] = 0x5c365c36; ++ ++ /* Set Key Index */ ++ wd->sta.cencKeyId = keyInfo.keyIndex; ++ ++ //zfCoreSetKey(dev, id+1, 1, ZM_CENC, (u16_t *)keyInfo.macAddr, ++ // (u32_t*) &keyInfo.key[16]); ++ } ++ else ++#endif //ZM_ENABLE_CENC ++ { ++ wd->sta.encryMode = ZM_TKIP; ++ ++ //zfCoreSetKey(dev, 0, 1, ZM_TKIP, wd->sta.bssid, ++ // (u32_t*) &keyInfo.key[16]); ++ ++ zfMicSetKey(&keyInfo.key[16], &wd->sta.txMicKey); ++ zfMicSetKey(&keyInfo.key[24], ++ &wd->sta.rxMicKey[keyInfo.keyIndex]); ++ } ++ } ++ else if ( keyInfo.keyLength == 16 ) ++ { /* AES */ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if ( wd->sta.ibssWpa2Psk == 1 ) ++ { ++ wd->sta.oppositeInfo[userIdx].encryMode = ZM_AES; ++ encryType = wd->sta.oppositeInfo[userIdx].encryMode; ++ } ++ else ++ { ++ wd->sta.encryMode = ZM_AES; ++ encryType = wd->sta.encryMode; ++ } ++#else ++ wd->sta.encryMode = ZM_AES; ++#endif ++ } ++ else ++ { ++ return ZM_STATUS_FAILURE; ++ } ++ ++ /* user 0 */ ++ //zfCoreSetKey(dev, 0, 0, wd->sta.encryMode, ++ // wd->sta.bssid, (u32_t*) keyInfo.key); ++ //zfHpSetStaPairwiseKey(dev, wd->sta.bssid, wd->sta.encryMode, ++ // (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if ( (keyInfo.keyLength==16) && (wd->sta.ibssWpa2Psk==1) ) ++ { /* If not AES-CCMP and ibss network , use traditional */ ++ zfHpSetPerUserKey(dev, ++ userIdx, ++ keyInfo.keyIndex, // key id == 0 ( Pairwise key = 0 ) ++ (u8_t*)keyInfo.macAddr, // RX need Source Address ( Address 2 ) ++ encryType, ++// wd->sta.encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++ wd->sta.oppositeInfo[userIdx].wpaState = ZM_STA_WPA_STATE_PK_OK ; ++ } ++ else ++ {/* Big Endian and Little Endian Compatibility */ ++ for (i = 0; i < 3; i++) ++ { ++ addr[2 * i] = wd->sta.bssid[i] & 0xff; ++ addr[2 * i + 1] = wd->sta.bssid[i] >> 8; ++ } ++ zfHpSetPerUserKey(dev, ++ ZM_USER_KEY_PK, // user id ++ 0, // key id ++ addr,//(u8_t *)wd->sta.bssid, ++ wd->sta.encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++ wd->sta.keyId = 4; ++ } ++#else ++ /* Big Endian and Little Endian Compatibility */ ++ for (i = 0; i < 3; i++) ++ { ++ addr[2 * i] = wd->sta.bssid[i] & 0xff; ++ addr[2 * i + 1] = wd->sta.bssid[i] >> 8; ++ } ++ zfHpSetPerUserKey(dev, ++ ZM_USER_KEY_PK, // user id ++ 0, // key id ++ addr,//(u8_t *)wd->sta.bssid, ++ wd->sta.encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++ wd->sta.keyId = 4; ++#endif ++ ++ wd->sta.wpaState = ZM_STA_WPA_STATE_PK_OK; ++ } ++ else if ( keyInfo.flag & ZM_KEY_FLAG_GK ) ++ { /* set group key */ ++ ++ zfTkipInit(keyInfo.key, (u8_t*) wd->sta.bssid, ++ &wd->sta.rxSeed[keyInfo.keyIndex], keyInfo.initIv); ++ ++ if ( keyInfo.keyLength == 32 ) ++ { /* TKIP */ ++#ifdef ZM_ENABLE_CENC ++ if (keyInfo.flag & ZM_KEY_FLAG_CENC) ++ { ++ encryMode = ZM_CENC; ++ zm_debug_msg0("Set CENC group Key"); ++ ++ /* Reset txiv and rxiv */ ++ wd->sta.rxivGK[0] = 0x5c365c36; ++ wd->sta.rxivGK[1] = 0x5c365c36; ++ wd->sta.rxivGK[2] = 0x5c365c36; ++ wd->sta.rxivGK[3] = 0x5c365c36; ++ ++ //zfCoreSetKey(dev, 0, 1, ZM_CENC, keyInfo.vapAddr, ++ // (u32_t*) &keyInfo.key[16]); ++ key = (u32_t*) keyInfo.key; ++ } ++ else ++#endif //ZM_ENABLE_CENC ++ { ++ encryMode = ZM_TKIP; ++ key = (u32_t*) wd->sta.rxSeed[keyInfo.keyIndex].tk; ++ ++ if ( !(keyInfo.flag & ZM_KEY_FLAG_INIT_IV) ) ++ { ++ wd->sta.rxSeed[keyInfo.keyIndex].iv16 = 0; ++ wd->sta.rxSeed[keyInfo.keyIndex].iv32 = 0; ++ } ++ ++ /* set MIC key to HMAC */ ++ //zfCoreSetKey(dev, 8, 1, ZM_TKIP, broadcast, ++ // (u32_t*) (&keyInfo.key[16])); ++ ++ zfMicSetKey(&keyInfo.key[24], ++ &wd->sta.rxMicKey[keyInfo.keyIndex]); ++ } ++ } ++ else if ( keyInfo.keyLength == 16 ) ++ { /* AES */ ++ encryMode = ZM_AES; ++ //key = (u32_t*) wd->sta.rxSeed[keyInfo.keyIndex].tk; ++ } ++ else ++ { /* WEP */ ++ if ( keyInfo.keyLength == 5 ) ++ { ++ encryMode = ZM_WEP64; ++ } ++ else if ( keyInfo.keyLength == 13 ) ++ { ++ encryMode = ZM_WEP128; ++ } ++ else if ( keyInfo.keyLength == 29 ) ++ { ++ encryMode = ZM_WEP256; ++ } ++ ++ key = (u32_t*) keyInfo.key; ++ } ++ ++ /* user 8 */ ++ //zfCoreSetKey(dev, 8, 0, encryMode, broadcast, key); ++ //zfHpSetStaGroupKey(dev, broadcast, encryMode, ++ // (u32_t*) keyInfo.key, (u32_t*) (&keyInfo.key[16])); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if ( (keyInfo.keyLength==16) && (wd->sta.ibssWpa2Psk==1) ) ++ {/* If not AES-CCMP and ibss network , use traditional */ ++ zfHpSetPerUserKey(dev, ++ userIdx, ++ keyInfo.keyIndex, // key id ++ // (u8_t *)broadcast, // for only 2 stations IBSS netwrl ( A2 ) ++ (u8_t*)keyInfo.macAddr, // for multiple ( > 2 ) stations IBSS network ( A2 ) ++ encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ } ++ else ++ { ++ zfHpSetPerUserKey(dev, ++ ZM_USER_KEY_GK, // user id ++ 0, // key id ++ (u8_t *)broadcast, ++ encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++ wd->sta.wpaState = ZM_STA_WPA_STATE_GK_OK; ++ } ++#else ++ zfHpSetPerUserKey(dev, ++ ZM_USER_KEY_GK, // user id ++ 0, // key id ++ (u8_t *)broadcast, ++ encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++ wd->sta.wpaState = ZM_STA_WPA_STATE_GK_OK; ++#endif ++ } ++ else ++ { /* legacy WEP */ ++ zm_debug_msg0("legacy WEP"); ++ ++ if ( keyInfo.keyIndex >= 4 ) ++ { ++ return ZM_STATUS_FAILURE; ++ } ++ ++ if ( keyInfo.keyLength == 5 ) ++ { ++ zm_debug_msg0("WEP 64"); ++ ++ encryMode = ZM_WEP64; ++ } ++ else if ( keyInfo.keyLength == 13 ) ++ { ++ zm_debug_msg0("WEP 128"); ++ ++ encryMode = ZM_WEP128; ++ } ++ else if ( keyInfo.keyLength == 32 ) ++ { ++ /* TKIP */ ++ #if 0 ++ // Don't reset the IV since some AP would fail in IV check and drop our connection ++ if ( wd->sta.wpaState != ZM_STA_WPA_STATE_PK_OK ) ++ { ++ wd->sta.iv16 = 0; ++ wd->sta.iv32 = 0; ++ } ++ #endif ++ ++ encryMode = ZM_TKIP; ++ ++ zfTkipInit(keyInfo.key, (u8_t*) wd->sta.bssid, ++ &wd->sta.rxSeed[keyInfo.keyIndex], keyInfo.initIv); ++ zfMicSetKey(&keyInfo.key[24], ++ &wd->sta.rxMicKey[keyInfo.keyIndex]); ++ } ++ else if ( keyInfo.keyLength == 16 ) ++ { ++ /* AES */ ++ #if 0 ++ // Don't reset the IV since some AP would fail in IV check and drop our connection ++ if ( wd->sta.wpaState != ZM_STA_WPA_STATE_PK_OK ) ++ { ++ /* broadcast -- > group key */ ++ /* Only initialize when set our default key ! */ ++ wd->sta.iv16 = 0; ++ wd->sta.iv32 = 0; ++ } ++ #endif ++ ++ encryMode = ZM_AES; ++ } ++ else if ( keyInfo.keyLength == 29 ) ++ { ++ zm_debug_msg0("WEP 256"); ++ ++ encryMode = ZM_WEP256; ++ //zfCoreSetKey(dev, 64, 1, wd->sta.encryMode, ++ // wd->sta.bssid, (u32_t*) (&keyInfo.key[16])); ++ } ++ else ++ { ++ return ZM_STATUS_FAILURE; ++ } ++ ++ { ++ u8_t i; ++ ++ zm_debug_msg0("key = "); ++ for(i = 0; i < keyInfo.keyLength; i++) ++ { ++ zm_debug_msg2("", keyInfo.key[i]); ++ } ++ } ++ ++ if ( keyInfo.flag & ZM_KEY_FLAG_DEFAULT_KEY ) ++ { ++ //for WEP default key 1~3 and ATOM platform--CWYang(+) ++ vapId = 0; ++ wd->ap.bcHalKeyIdx[vapId] = keyInfo.keyIndex; ++ wd->ap.bcKeyIndex[vapId] = keyInfo.keyIndex; ++ wd->sta.keyId = keyInfo.keyIndex; ++ } ++ ++ if(encryMode == ZM_TKIP) ++ { ++ if(wd->TKIP_Group_KeyChanging == 0x1) ++ { ++ zm_debug_msg0("Countermeasure : Cancel Old Timer "); ++ zfTimerCancel(dev, ZM_EVENT_SKIP_COUNTERMEASURE); ++ } ++ else ++ { ++ zm_debug_msg0("Countermeasure : Create New Timer "); ++ } ++ ++ wd->TKIP_Group_KeyChanging = 0x1; ++ zfTimerSchedule(dev, ZM_EVENT_SKIP_COUNTERMEASURE, 150); ++ } ++ ++ ++ ++ //------------------------------------------------------------------------ ++ ++ /* use default key */ ++ //zfCoreSetKey(dev, ZM_USER_KEY_DEFAULT+keyInfo.keyIndex, 0, ++ // wd->sta.encryMode, wd->sta.bssid, (u32_t*) keyInfo.key); ++ ++ if ( encryMode == ZM_TKIP || ++ encryMode == ZM_AES ) ++ { ++ zfHpSetDefaultKey(dev, keyInfo.keyIndex, encryMode, ++ (u32_t*) keyInfo.key, (u32_t*) &keyInfo.key[16]); ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ if ( (keyInfo.keyLength==16) && (wd->sta.ibssWpa2Psk==1) ) ++ {/* If not AES-CCMP and ibss network , use traditional */ ++ wd->sta.wpaState = ZM_STA_WPA_STATE_PK_OK; ++ } ++ else ++ { ++ if (wd->sta.wpaState == ZM_STA_WPA_STATE_PK_OK) ++ wd->sta.wpaState = ZM_STA_WPA_STATE_GK_OK; ++ else ++ { ++ wd->sta.wpaState = ZM_STA_WPA_STATE_PK_OK; ++ wd->sta.encryMode = encryMode; ++ wd->ws.encryMode = encryMode; ++ } ++ } ++#else ++ if (wd->sta.wpaState == ZM_STA_WPA_STATE_PK_OK) ++ wd->sta.wpaState = ZM_STA_WPA_STATE_GK_OK; ++ else if ( wd->sta.wpaState == ZM_STA_WPA_STATE_INIT ) ++ { ++ wd->sta.wpaState = ZM_STA_WPA_STATE_PK_OK; ++ wd->sta.encryMode = encryMode; ++ wd->ws.encryMode = encryMode; ++ } ++#endif ++ } ++ else ++ { ++ zfHpSetDefaultKey(dev, keyInfo.keyIndex, encryMode, ++ (u32_t*) keyInfo.key, NULL); ++ ++ /* Save key for software WEP */ ++ zfMemoryCopy(wd->sta.wepKey[keyInfo.keyIndex], keyInfo.key, ++ keyInfo.keyLength); ++ ++ /* TODO: Check whether we need to save the SWEncryMode */ ++ wd->sta.SWEncryMode[keyInfo.keyIndex] = encryMode; ++ ++ wd->sta.encryMode = encryMode; ++ wd->ws.encryMode = encryMode; ++ } ++ } ++ } ++ ++// wd->sta.flagKeyChanging = 1; ++ return ZM_STATUS_SUCCESS; ++} ++ ++/* PSEUDO test */ ++u8_t zfiWlanPSEUDOSetKey(zdev_t* dev, struct zsKeyInfo keyInfo) ++{ ++ //u16_t broadcast[3] = {0xffff, 0xffff, 0xffff}; ++ //u32_t* key; ++ u8_t micKey[16]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ switch (keyInfo.keyLength) ++ { ++ case 5: ++ wd->sta.encryMode = ZM_WEP64; ++ /* use default key */ ++ zfCoreSetKey(dev, 64, 0, ZM_WEP64, (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ break; ++ ++ case 13: ++ wd->sta.encryMode = ZM_WEP128; ++ /* use default key */ ++ zfCoreSetKey(dev, 64, 0, ZM_WEP128, (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ break; ++ ++ case 29: ++ wd->sta.encryMode = ZM_WEP256; ++ /* use default key */ ++ zfCoreSetKey(dev, 64, 1, ZM_WEP256, (u16_t *)keyInfo.macAddr, (u32_t*) (&keyInfo.key[16])); ++ zfCoreSetKey(dev, 64, 0, ZM_WEP256, (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ break; ++ ++ case 16: ++ wd->sta.encryMode = ZM_AES; ++ //zfCoreSetKey(dev, 0, 0, ZM_AES, (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ zfCoreSetKey(dev, 64, 0, ZM_AES, (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ break; ++ ++ case 32: ++#ifdef ZM_ENABLE_CENC ++ if (keyInfo.flag & ZM_KEY_FLAG_CENC) ++ { ++ u16_t boardcastAddr[3] = {0xffff, 0xffff, 0xffff}; ++ u16_t Addr_a[] = { 0x0000, 0x0080, 0x0901}; ++ u16_t Addr_b[] = { 0x0000, 0x0080, 0x0902}; ++ /* CENC test: user0,1 and user2 for boardcast */ ++ wd->sta.encryMode = ZM_CENC; ++ zfCoreSetKey(dev, 0, 1, ZM_CENC, (u16_t *)Addr_a, (u32_t*) (&keyInfo.key[16])); ++ zfCoreSetKey(dev, 0, 0, ZM_CENC, (u16_t *)Addr_a, (u32_t*) keyInfo.key); ++ ++ zfCoreSetKey(dev, 1, 1, ZM_CENC, (u16_t *)Addr_b, (u32_t*) (&keyInfo.key[16])); ++ zfCoreSetKey(dev, 1, 0, ZM_CENC, (u16_t *)Addr_b, (u32_t*) keyInfo.key); ++ ++ zfCoreSetKey(dev, 2, 1, ZM_CENC, (u16_t *)boardcastAddr, (u32_t*) (&keyInfo.key[16])); ++ zfCoreSetKey(dev, 2, 0, ZM_CENC, (u16_t *)boardcastAddr, (u32_t*) keyInfo.key); ++ ++ /* Initialize PN sequence */ ++ wd->sta.txiv[0] = 0x5c365c36; ++ wd->sta.txiv[1] = 0x5c365c36; ++ wd->sta.txiv[2] = 0x5c365c36; ++ wd->sta.txiv[3] = 0x5c365c36; ++ } ++ else ++#endif //ZM_ENABLE_CENC ++ { ++ wd->sta.encryMode = ZM_TKIP; ++ zfCoreSetKey(dev, 64, 1, ZM_TKIP, (u16_t *)keyInfo.macAddr, (u32_t*) micKey); ++ zfCoreSetKey(dev, 64, 0, ZM_TKIP, (u16_t *)keyInfo.macAddr, (u32_t*) keyInfo.key); ++ } ++ break; ++ default: ++ wd->sta.encryMode = ZM_NO_WEP; ++ } ++ ++ return ZM_STATUS_SUCCESS; ++} ++ ++void zfiWlanSetPowerSaveMode(zdev_t* dev, u8_t mode) ++{ ++#if 0 ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.powerSaveMode = mode; ++ ++ /* send null data with PwrBit to inform AP */ ++ if ( mode > ZM_STA_PS_NONE ) ++ { ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ zfSendNullData(dev, 1); ++ } ++ ++ /* device into PS mode */ ++ zfPSDeviceSleep(dev); ++ } ++#endif ++ ++ zfPowerSavingMgrSetMode(dev, mode); ++} ++ ++void zfiWlanSetMacAddress(zdev_t* dev, u16_t* mac) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->macAddr[0] = mac[0]; ++ wd->macAddr[1] = mac[1]; ++ wd->macAddr[2] = mac[2]; ++ ++ zfHpSetMacAddress(dev, mac, 0); ++} ++ ++u8_t zfiWlanQueryWlanMode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->wlanMode; ++} ++ ++u8_t zfiWlanQueryAdapterState(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->state; ++} ++ ++u8_t zfiWlanQueryAuthenticationMode(zdev_t* dev, u8_t bWrapper) ++{ ++ u8_t authMode; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( bWrapper ) ++ { ++ authMode = wd->ws.authMode; ++ } ++ else ++ { ++ //authMode = wd->sta.authMode; ++ authMode = wd->sta.currentAuthMode; ++ } ++ ++ return authMode; ++} ++ ++u8_t zfiWlanQueryWepStatus(zdev_t* dev, u8_t bWrapper) ++{ ++ u8_t wepStatus; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( bWrapper ) ++ { ++ wepStatus = wd->ws.wepStatus; ++ } ++ else ++ { ++ wepStatus = wd->sta.wepStatus; ++ } ++ ++ return wepStatus; ++} ++ ++void zfiWlanQuerySSID(zdev_t* dev, u8_t* ssid, u8_t* pSsidLength) ++{ ++ u16_t vapId = 0; ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ vapId = zfwGetVapId(dev); ++ ++ if (vapId == 0xffff) ++ { ++ *pSsidLength = wd->ap.ssidLen[0]; ++ zfMemoryCopy(ssid, wd->ap.ssid[0], wd->ap.ssidLen[0]); ++ } ++ else ++ { ++ *pSsidLength = wd->ap.ssidLen[vapId + 1]; ++ zfMemoryCopy(ssid, wd->ap.ssid[vapId + 1], wd->ap.ssidLen[vapId + 1]); ++ } ++ } ++ else ++ { ++ *pSsidLength = wd->sta.ssidLen; ++ zfMemoryCopy(ssid, wd->sta.ssid, wd->sta.ssidLen); ++ } ++} ++ ++u16_t zfiWlanQueryFragThreshold(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->fragThreshold; ++} ++ ++u16_t zfiWlanQueryRtsThreshold(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->rtsThreshold; ++} ++ ++u32_t zfiWlanQueryFrequency(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return (wd->frequency*1000); ++} ++ ++/*********************************************************** ++ * Function: zfiWlanQueryCurrentFrequency ++ * Return value: ++ * - 0 : no validate current frequency ++ * - (>0): current frequency depend on "qmode" ++ * Input: ++ * - qmode: ++ * 0: return value depend on the support mode, this ++ qmode is use to solve the bug #31223 ++ * 1: return the actually current frequency ++ ***********************************************************/ ++u32_t zfiWlanQueryCurrentFrequency(zdev_t* dev, u8_t qmode) ++{ ++ u32_t frequency; ++ ++ zmw_get_wlan_dev(dev); ++ ++ switch (qmode) ++ { ++ case 0: ++ if (wd->sta.currentFrequency > 3000) ++ { ++ if (wd->supportMode & ZM_WIRELESS_MODE_5) ++ { ++ frequency = wd->sta.currentFrequency; ++ } ++ else if (wd->supportMode & ZM_WIRELESS_MODE_24) ++ { ++ frequency = zfChGetFirst2GhzChannel(dev); ++ } ++ else ++ { ++ frequency = 0; ++ } ++ } ++ else ++ { ++ if (wd->supportMode & ZM_WIRELESS_MODE_24) ++ { ++ frequency = wd->sta.currentFrequency; ++ } ++ else if (wd->supportMode & ZM_WIRELESS_MODE_5) ++ { ++ frequency = zfChGetLast5GhzChannel(dev); ++ } ++ else ++ { ++ frequency = 0; ++ } ++ } ++ break; ++ ++ case 1: ++ frequency = wd->sta.currentFrequency; ++ break; ++ ++ default: ++ frequency = 0; ++ } ++ ++ return (frequency*1000); ++} ++ ++u32_t zfiWlanQueryFrequencyAttribute(zdev_t* dev, u32_t freq) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ u8_t i; ++ u16_t frequency = (u16_t) (freq/1000); ++ u32_t ret = 0; ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if ( wd->regulationTable.allowChannel[i].channel == frequency ) ++ { ++ ret = wd->regulationTable.allowChannel[i].channelFlags; ++ } ++ } ++ ++ return ret; ++} ++ ++/* BandWidth 0=>20 1=>40 */ ++/* ExtOffset 0=>20 1=>high control 40 3=>low control 40 */ ++void zfiWlanQueryFrequencyHT(zdev_t* dev, u32_t *bandWidth, u32_t *extOffset) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ *bandWidth = wd->BandWidth40; ++ *extOffset = wd->ExtOffset; ++} ++ ++u8_t zfiWlanQueryCWMode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->cwm.cw_mode; ++} ++ ++u32_t zfiWlanQueryCWEnable(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->cwm.cw_enable; ++} ++ ++void zfiWlanQueryBssid(zdev_t* dev, u8_t* bssid) ++{ ++ u8_t addr[6]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, addr); ++ zfMemoryCopy(bssid, addr, 6); ++} ++ ++u16_t zfiWlanQueryBeaconInterval(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->beaconInterval; ++} ++ ++u32_t zfiWlanQueryRxBeaconTotal(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ wd->sta.rxBeaconTotal += wd->sta.rxBeaconCount; ++ ++ return wd->sta.rxBeaconTotal; ++} ++ ++u16_t zfiWlanQueryAtimWindow(zdev_t* dev) ++{ ++ u16_t atimWindow; ++ ++ zmw_get_wlan_dev(dev); ++ ++ atimWindow = wd->sta.atimWindow; ++ ++ return atimWindow; ++} ++ ++u8_t zfiWlanQueryEncryMode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->wlanMode == ZM_MODE_AP) ++ return wd->ap.encryMode[0]; ++ else ++ return wd->sta.encryMode; ++} ++ ++u16_t zfiWlanQueryCapability(zdev_t* dev) ++{ ++ u16_t capability; ++ ++ zmw_get_wlan_dev(dev); ++ ++ capability = wd->sta.capability[0] + ++ (((u16_t) wd->sta.capability[1]) << 8); ++ ++ return capability; ++ ++} ++ ++u16_t zfiWlanQueryAid(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->sta.aid; ++} ++ ++void zfiWlanQuerySupportRate(zdev_t* dev, u8_t* rateArray, u8_t* pLength) ++{ ++ u8_t i, j=0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for( i=0; i<4; i++ ) ++ { ++ if ( wd->bRate & (0x1 << i) ) ++ { ++ rateArray[j] = zg11bRateTbl[i] + ++ ((wd->bRateBasic & (0x1<gRate & (0x1 << i) ) ++ { ++ rateArray[j] = zg11gRateTbl[i] + ++ ((wd->gRateBasic & (0x1<sta.rsnIe[1] + 2; ++ zfMemoryCopy(ie, wd->sta.rsnIe, len); ++ *pLength = len; ++} ++ ++void zfiWlanQueryWpaIe(zdev_t* dev, u8_t* ie, u8_t* pLength) ++{ ++ u8_t len; ++ ++ zmw_get_wlan_dev(dev); ++ ++ len = wd->sta.wpaIe[1] + 2; ++ zfMemoryCopy(ie, wd->sta.wpaIe, len); ++ *pLength = len; ++ ++} ++ ++u8_t zfiWlanQueryMulticastCipherAlgo(zdev_t *dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch( wd->sta.currentAuthMode ) ++ { ++ case ZM_AUTH_MODE_WPA2PSK: ++ case ZM_AUTH_MODE_WPA2: ++ if ( wd->sta.rsnIe[7] == 2 ) ++ { ++ return ZM_TKIP; ++ } ++ else ++ { ++ return ZM_AES; ++ } ++ break; ++ ++ case ZM_AUTH_MODE_WPAPSK: ++ case ZM_AUTH_MODE_WPA: ++ if ( wd->sta.rsnIe[11] == 2 ) ++ { ++ return ZM_TKIP; ++ } ++ else ++ { ++ return ZM_AES; ++ } ++ break; ++ ++ default: ++ return wd->sta.encryMode; ++ } ++} ++ ++u8_t zfiWlanQueryHTMode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ // 0:Legancy, 1:N ++ return wd->sta.EnableHT; ++} ++ ++u8_t zfiWlanQueryBandWidth40(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ // 0:20M, 1:40M ++ return wd->BandWidth40; ++} ++ ++u16_t zfiWlanQueryRegionCode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->regulationTable.regionCode; ++} ++void zfiWlanSetWpaIe(zdev_t* dev, u8_t* ie, u8_t Length) ++{ ++ u16_t vapId = 0; ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->wlanMode == ZM_MODE_AP) // AP Mode ++ { ++ vapId = zfwGetVapId(dev); ++ ++ if (vapId == 0xffff) ++ vapId = 0; ++ else ++ vapId++; ++ ++ zm_assert(Length < ZM_MAX_WPAIE_SIZE); ++ if (Length < ZM_MAX_WPAIE_SIZE) ++ { ++ wd->ap.wpaLen[vapId] = Length; ++ zfMemoryCopy(wd->ap.wpaIe[vapId], ie, wd->ap.wpaLen[vapId]); ++ } ++ ++ } ++ else ++ { ++ wd->sta.wpaLen = Length; ++ zfMemoryCopy(wd->sta.wpaIe, ie, wd->sta.wpaLen); ++ } ++ //zfiWlanSetWpaSupport(dev, 1); ++ if (wd->wlanMode == ZM_MODE_AP) // AP Mode ++ { ++ wd->ap.wpaSupport[vapId] = 1; ++ } ++ else ++ { ++ wd->sta.wpaSupport = 1; ++ } ++ ++} ++ ++void zfiWlanSetWpaSupport(zdev_t* dev, u8_t WpaSupport) ++{ ++ u16_t vapId = 0; ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->wlanMode == ZM_MODE_AP) // AP Mode ++ { ++ vapId = zfwGetVapId(dev); ++ ++ if (vapId == 0xffff) ++ vapId = 0; ++ else ++ vapId++; ++ ++ wd->ap.wpaSupport[vapId] = WpaSupport; ++ } ++ else ++ { ++ wd->sta.wpaSupport = WpaSupport; ++ } ++ ++} ++ ++void zfiWlanSetProtectionMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.bProtectionMode = mode; ++ if (wd->sta.bProtectionMode == TRUE) ++ { ++ zfHpSetSlotTime(dev, 0); ++ } ++ else ++ { ++ zfHpSetSlotTime(dev, 1); ++ } ++ ++ zm_msg1_mm(ZM_LV_1, "wd->protectionMode=", wd->sta.bProtectionMode); ++} ++ ++void zfiWlanSetBasicRate(zdev_t* dev, u8_t bRateSet, u8_t gRateSet, ++ u32_t nRateSet) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.bRateBasic = bRateSet; ++ wd->ws.gRateBasic = gRateSet; ++ wd->ws.nRateBasic = nRateSet; ++} ++ ++void zfiWlanSetBGMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.bgMode = mode; ++} ++ ++void zfiWlanSetpreambleType(zdev_t* dev, u8_t type) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.preambleType = type; ++} ++ ++u8_t zfiWlanQuerypreambleType(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->ws.preambleType; ++} ++ ++u8_t zfiWlanQueryPowerSaveMode(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->sta.powerSaveMode; ++} ++ ++u8_t zfiWlanSetPmkidInfo(zdev_t* dev, u16_t* bssid, u8_t* pmkid) ++{ ++ u32_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for(i=0; ista.pmkidInfo.bssidCount; i++) ++ { ++ if ( zfMemoryIsEqual((u8_t*) wd->sta.pmkidInfo.bssidInfo[i].bssid, ++ (u8_t*) bssid, 6) ) ++ { ++ /* matched */ ++ break; ++ } ++ } ++ ++ if ( i < wd->sta.pmkidInfo.bssidCount ) ++ { ++ /* overwrite the original one */ ++ zfMemoryCopy(wd->sta.pmkidInfo.bssidInfo[i].pmkid, pmkid, 16); ++ } ++ else ++ { ++ if ( i < ZM_PMKID_MAX_BSS_CNT ) ++ { ++ wd->sta.pmkidInfo.bssidInfo[i].bssid[0] = bssid[0]; ++ wd->sta.pmkidInfo.bssidInfo[i].bssid[1] = bssid[1]; ++ wd->sta.pmkidInfo.bssidInfo[i].bssid[2] = bssid[2]; ++ ++ zfMemoryCopy(wd->sta.pmkidInfo.bssidInfo[i].pmkid, pmkid, 16); ++ wd->sta.pmkidInfo.bssidCount++; ++ } ++ } ++ ++ return 0; ++} ++ ++u32_t zfiWlanQueryPmkidInfo(zdev_t* dev, u8_t* buf, u32_t len) ++{ ++ //struct zsPmkidInfo* pPmkidInfo = ( struct zsPmkidInfo* ) buf; ++ u32_t size; ++ ++ zmw_get_wlan_dev(dev); ++ ++ size = sizeof(u32_t) + ++ wd->sta.pmkidInfo.bssidCount * sizeof(struct zsPmkidBssidInfo); ++ ++ if ( len < size ) ++ { ++ return wd->sta.pmkidInfo.bssidCount; ++ } ++ ++ zfMemoryCopy(buf, (u8_t*) &wd->sta.pmkidInfo, (u16_t) size); ++ ++ return 0; ++} ++ ++void zfiWlanSetMulticastList(zdev_t* dev, u8_t size, u8_t* pList) ++{ ++ struct zsMulticastAddr* pMacList = (struct zsMulticastAddr*) pList; ++ u8_t i; ++ u8_t bAllMulticast = 0; ++ //u32_t value; ++ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.multicastList.size = size; ++ for(i=0; ista.multicastList.macAddr[i].addr, ++ pMacList[i].addr, 6); ++ } ++ ++ if ( wd->sta.osRxFilter & ZM_PACKET_TYPE_ALL_MULTICAST ) ++ bAllMulticast = 1; ++ zfHpSetMulticastList(dev, size, pList, bAllMulticast); ++ ++} ++ ++void zfiWlanRemoveKey(zdev_t* dev, u8_t keyType, u8_t keyId) ++{ ++ u16_t fakeMacAddr[3] = {0, 0, 0}; ++ u32_t fakeKey[4] = {0, 0, 0, 0}; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( keyType == 0 ) ++ { ++ /* remove WEP key */ ++ zm_debug_msg0("remove WEP key"); ++ zfCoreSetKey(dev, ZM_USER_KEY_DEFAULT+keyId, 0, ++ ZM_NO_WEP, fakeMacAddr, fakeKey); ++ wd->sta.encryMode = ZM_NO_WEP; ++ } ++ else if ( keyType == 1 ) ++ { ++ /* remove pairwise key */ ++ zm_debug_msg0("remove pairwise key"); ++ zfHpRemoveKey(dev, ZM_USER_KEY_PK); ++ wd->sta.encryMode = ZM_NO_WEP; ++ } ++ else ++ { ++ /* remove group key */ ++ zm_debug_msg0("remove group key"); ++ zfHpRemoveKey(dev, ZM_USER_KEY_GK); ++ } ++} ++ ++ ++void zfiWlanQueryRegulationTable(zdev_t* dev, struct zsRegulationTable* pEntry) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zfMemoryCopy((u8_t*) pEntry, (u8_t*) &wd->regulationTable, ++ sizeof(struct zsRegulationTable)); ++} ++ ++/* parameter "time" is specified in ms */ ++void zfiWlanSetScanTimerPerChannel(zdev_t* dev, u16_t time) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg1("scan time (ms) = ", time); ++ ++ wd->sta.activescanTickPerChannel = time / ZM_MS_PER_TICK; ++} ++ ++void zfiWlanSetAutoReconnect(zdev_t* dev, u8_t enable) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.bAutoReconnect = enable; ++ //wd->sta.bAutoReconnectEnabled = enable; ++} ++ ++void zfiWlanSetStaWme(zdev_t* dev, u8_t enable, u8_t uapsdInfo) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.staWmeEnabled = enable & 0x3; ++ if ((enable & 0x2) != 0) ++ { ++ wd->ws.staWmeQosInfo = uapsdInfo & 0x6f; ++ } ++ else ++ { ++ wd->ws.staWmeQosInfo = 0; ++ } ++} ++ ++void zfiWlanSetApWme(zdev_t* dev, u8_t enable) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.apWmeEnabled = enable; ++} ++ ++u8_t zfiWlanQuerywmeEnable(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->ws.staWmeEnabled; ++} ++ ++void zfiWlanSetProbingHiddenSsid(zdev_t* dev, u8_t* ssid, u8_t ssidLen, ++ u16_t entry) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ++ if ((ssidLen <= 32) && (entry < ZM_MAX_PROBE_HIDDEN_SSID_SIZE)) ++ { ++ zmw_enter_critical_section(dev); ++ wd->ws.probingSsidList[entry].ssidLen = ssidLen; ++ zfMemoryCopy(wd->ws.probingSsidList[entry].ssid, ssid, ssidLen); ++ zmw_leave_critical_section(dev); ++ } ++ ++ return; ++} ++ ++void zfiWlanSetDisableProbingWithSsid(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.disableProbingWithSsid = mode; ++ ++ return; ++} ++ ++void zfiWlanSetDropUnencryptedPackets(zdev_t* dev, u8_t enable) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.dropUnencryptedPkts = enable; ++} ++ ++void zfiWlanSetStaRxSecurityCheckCb(zdev_t* dev, zfpStaRxSecurityCheckCb pStaRxSecurityCheckCb) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.pStaRxSecurityCheckCb = pStaRxSecurityCheckCb; ++} ++ ++void zfiWlanSetIBSSJoinOnly(zdev_t* dev, u8_t joinOnly) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.ibssJoinOnly = joinOnly; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiConfigWdsPort */ ++/* Configure WDS port. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* wdsPortId : WDS port ID, start from 0 */ ++/* flag : 0=>disable WDS port, 1=>enable WDS port */ ++/* wdsAddr : WDS neighbor MAC address */ ++/* encType : encryption type for WDS port */ ++/* wdsKey : encryption key for WDS port */ ++/* */ ++/* OUTPUTS */ ++/* Error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++u16_t zfiConfigWdsPort(zdev_t* dev, u8_t wdsPortId, u16_t flag, u16_t* wdsAddr, ++ u16_t encType, u32_t* wdsKey) ++{ ++ u16_t addr[3]; ++ u32_t key[4]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if (wdsPortId > ZM_MAX_WDS_SUPPORT) ++ { ++ return ZM_ERR_WDS_PORT_ID; ++ } ++ ++ if (flag == 1) ++ { ++ /* Enable WDS port */ ++ wd->ap.wds.macAddr[wdsPortId][0] = wdsAddr[0]; ++ wd->ap.wds.macAddr[wdsPortId][1] = wdsAddr[1]; ++ wd->ap.wds.macAddr[wdsPortId][2] = wdsAddr[2]; ++ ++ wd->ap.wds.wdsBitmap |= (1 << wdsPortId); ++ wd->ap.wds.encryMode[wdsPortId] = (u8_t) encType; ++ ++ zfCoreSetKey(dev, 10+ZM_MAX_WDS_SUPPORT, 0, (u8_t) encType, wdsAddr, wdsKey); ++ } ++ else ++ { ++ /* Disable WDS port */ ++ addr[0] = addr[1] = addr[2] = 0; ++ key[0] = key[1] = key[2] = key[3] = 0; ++ wd->ap.wds.wdsBitmap &= (~(1 << wdsPortId)); ++ zfCoreSetKey(dev, 10+ZM_MAX_WDS_SUPPORT, 0, ZM_NO_WEP, addr, key); ++ } ++ ++ return ZM_SUCCESS; ++} ++#ifdef ZM_ENABLE_CENC ++/* CENC */ ++void zfiWlanQueryGSN(zdev_t* dev, u8_t *gsn, u16_t vapId) ++{ ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ u32_t txiv[4]; ++ zmw_get_wlan_dev(dev); ++ ++ /* convert little endian to big endian for 32 bits */ ++ txiv[3] = wd->ap.txiv[vapId][0]; ++ txiv[2] = wd->ap.txiv[vapId][1]; ++ txiv[1] = wd->ap.txiv[vapId][2]; ++ txiv[0] = wd->ap.txiv[vapId][3]; ++ ++ zfMemoryCopy(gsn, (u8_t*)txiv, 16); ++} ++#endif //ZM_ENABLE_CENC ++//CWYang(+) ++void zfiWlanQuerySignalInfo(zdev_t* dev, u8_t *buffer) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /*Change Signal Strength/Quality Value to Human Sense Here*/ ++ ++ buffer[0] = wd->SignalStrength; ++ buffer[1] = wd->SignalQuality; ++} ++ ++/* OS-XP */ ++u16_t zfiStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType) ++{ ++ return zfStaAddIeWpaRsn(dev, buf, offset, frameType); ++} ++ ++/* zfiDebugCmd */ ++/* cmd value-description */ ++/* 0 schedule timer */ ++/* 1 cancel timer */ ++/* 2 clear timer */ ++/* 3 test timer */ ++/* 4 */ ++/* 5 */ ++/* 6 checksum test 0/1 */ ++/* 7 enableProtectionMode */ ++/* 8 rx packet content dump 0/1 */ ++ ++u32_t zfiDebugCmd(zdev_t* dev, u32_t cmd, u32_t value) ++{ ++ u16_t event; ++ u32_t tick; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ ++ zmw_enter_critical_section(dev); ++ ++ if ( cmd == 0 ) ++ { /* schedule timer */ ++ event = (u16_t) ((value >> 16) & 0xffff); ++ tick = value & 0xffff; ++ zfTimerSchedule(dev, event, tick); ++ } ++ else if ( cmd == 1 ) ++ { /* cancel timer */ ++ event = (u16_t) (value & 0xffff); ++ zfTimerCancel(dev, event); ++ } ++ else if ( cmd == 2 ) ++ { /* clear timer */ ++ zfTimerClear(dev); ++ } ++ else if ( cmd == 3 ) ++ { /* test timer */ ++ zfTimerSchedule(dev, 1, 500); ++ zfTimerSchedule(dev, 2, 1000); ++ zfTimerSchedule(dev, 3, 1000); ++ zfTimerSchedule(dev, 4, 1000); ++ zfTimerSchedule(dev, 5, 1500); ++ zfTimerSchedule(dev, 6, 2000); ++ zfTimerSchedule(dev, 7, 2200); ++ zfTimerSchedule(dev, 6, 2500); ++ zfTimerSchedule(dev, 8, 2800); ++ } ++ else if ( cmd == 4) ++ { ++ zfTimerSchedule(dev, 1, 500); ++ zfTimerSchedule(dev, 2, 1000); ++ zfTimerSchedule(dev, 3, 1000); ++ zfTimerSchedule(dev, 4, 1000); ++ zfTimerSchedule(dev, 5, 1500); ++ zfTimerSchedule(dev, 6, 2000); ++ zfTimerSchedule(dev, 7, 2200); ++ zfTimerSchedule(dev, 6, 2500); ++ zfTimerSchedule(dev, 8, 2800); ++ zfTimerCancel(dev, 1); ++ zfTimerCancel(dev, 3); ++ zfTimerCancel(dev, 6); ++ } ++ else if ( cmd == 5 ) ++ { ++ wd->sta.keyId = (u8_t) value; ++ } ++ else if ( cmd == 6 ) ++ { ++ /* 0: normal 1: always set TCP/UDP checksum zero */ ++ wd->checksumTest = value; ++ } ++ else if ( cmd == 7 ) ++ { ++ wd->enableProtectionMode = value; ++ zm_msg1_mm(ZM_LV_1, "wd->enableProtectionMode=", wd->enableProtectionMode); ++ } ++ else if ( cmd == 8 ) ++ { ++ /* rx packet content dump */ ++ if (value) ++ { ++ wd->rxPacketDump = 1; ++ } ++ else ++ { ++ wd->rxPacketDump = 0; ++ } ++ } ++ ++ ++ zmw_leave_critical_section(dev); ++ ++ return 0; ++} ++ ++#ifdef ZM_ENABLE_CENC ++u8_t zfiWlanSetCencPairwiseKey(zdev_t* dev, u8_t keyid, u32_t *txiv, u32_t *rxiv, ++ u8_t *key, u8_t *mic) ++{ ++ struct zsKeyInfo keyInfo; ++ u8_t cencKey[32]; ++ u8_t i; ++ u16_t macAddr[3]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i = 0; i < 16; i++) ++ cencKey[i] = key[i]; ++ for (i = 0; i < 16; i++) ++ cencKey[i + 16] = mic[i]; ++ keyInfo.key = cencKey; ++ keyInfo.keyLength = 32; ++ keyInfo.keyIndex = keyid; ++ keyInfo.flag = ZM_KEY_FLAG_CENC | ZM_KEY_FLAG_PK; ++ for (i = 0; i < 3; i++) ++ macAddr[i] = wd->sta.bssid[i]; ++ keyInfo.macAddr = macAddr; ++ ++ zfiWlanSetKey(dev, keyInfo); ++ ++ /* Reset txiv and rxiv */ ++ //wd->sta.txiv[0] = txiv[0]; ++ //wd->sta.txiv[1] = txiv[1]; ++ //wd->sta.txiv[2] = txiv[2]; ++ //wd->sta.txiv[3] = txiv[3]; ++ // ++ //wd->sta.rxiv[0] = rxiv[0]; ++ //wd->sta.rxiv[1] = rxiv[1]; ++ //wd->sta.rxiv[2] = rxiv[2]; ++ //wd->sta.rxiv[3] = rxiv[3]; ++ ++ return 0; ++} ++ ++u8_t zfiWlanSetCencGroupKey(zdev_t* dev, u8_t keyid, u32_t *rxiv, ++ u8_t *key, u8_t *mic) ++{ ++ struct zsKeyInfo keyInfo; ++ u8_t cencKey[32]; ++ u8_t i; ++ u16_t macAddr[6] = {0xffff, 0xffff, 0xffff}; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i = 0; i < 16; i++) ++ cencKey[i] = key[i]; ++ for (i = 0; i < 16; i++) ++ cencKey[i + 16] = mic[i]; ++ keyInfo.key = cencKey; ++ keyInfo.keyLength = 32; ++ keyInfo.keyIndex = keyid; ++ keyInfo.flag = ZM_KEY_FLAG_CENC | ZM_KEY_FLAG_GK; ++ keyInfo.vapId = 0; ++ for (i = 0; i < 3; i++) ++ keyInfo.vapAddr[i] = wd->macAddr[i]; ++ keyInfo.macAddr = macAddr; ++ ++ zfiWlanSetKey(dev, keyInfo); ++ ++ /* Reset txiv and rxiv */ ++ wd->sta.rxivGK[0] = ((rxiv[3] >> 24) & 0xFF) ++ + (((rxiv[3] >> 16) & 0xFF) << 8) ++ + (((rxiv[3] >> 8) & 0xFF) << 16) ++ + ((rxiv[3] & 0xFF) << 24); ++ wd->sta.rxivGK[1] = ((rxiv[2] >> 24) & 0xFF) ++ + (((rxiv[2] >> 16) & 0xFF) << 8) ++ + (((rxiv[2] >> 8) & 0xFF) << 16) ++ + ((rxiv[2] & 0xFF) << 24); ++ wd->sta.rxivGK[2] = ((rxiv[1] >> 24) & 0xFF) ++ + (((rxiv[1] >> 16) & 0xFF) << 8) ++ + (((rxiv[1] >> 8) & 0xFF) << 16) ++ + ((rxiv[1] & 0xFF) << 24); ++ wd->sta.rxivGK[3] = ((rxiv[0] >> 24) & 0xFF) ++ + (((rxiv[0] >> 16) & 0xFF) << 8) ++ + (((rxiv[0] >> 8) & 0xFF) << 16) ++ + ((rxiv[0] & 0xFF) << 24); ++ ++ wd->sta.authMode = ZM_AUTH_MODE_CENC; ++ wd->sta.currentAuthMode = ZM_AUTH_MODE_CENC; ++ ++ return 0; ++} ++#endif //ZM_ENABLE_CENC ++ ++u8_t zfiWlanSetDot11DMode(zdev_t* dev, u8_t mode) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.b802_11D = mode; ++ if (mode) //Enable 802.11d ++ { ++ wd->regulationTable.regionCode = NO_ENUMRD; ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ wd->regulationTable.allowChannel[i].channelFlags |= ZM_REG_FLAG_CHANNEL_PASSIVE; ++ } ++ else //Disable ++ { ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ wd->regulationTable.allowChannel[i].channelFlags &= ~ZM_REG_FLAG_CHANNEL_PASSIVE; ++ } ++ ++ return 0; ++} ++ ++u8_t zfiWlanSetDot11HDFSMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ //zm_debug_msg0("CWY - Enable 802.11h DFS"); ++ ++ // TODO : DFS Enable in 5250 to 5350 MHz and 5470 to 5725 MHz . ++ //if ( Adapter->ZD80211HSupport && ++ // Adapter->CardSetting.NetworkTypeInUse == Ndis802_11OFDM5 && ++ // ((ChannelNo >=52 && ChannelNo <= 64) || //5250~5350 MHZ ++ // (ChannelNo >=100 && ChannelNo <= 140))) //5470~5725 MHZ ++ //{ ++ // Adapter->ZD80211HSetting.DFSEnable=TRUE; ++ //} ++ //else ++ //{ ++ // Adapter->ZD80211HSetting.DFSEnable=FALSE; ++ //} ++ ++ wd->sta.DFSEnable = mode; ++ if (mode) ++ wd->sta.capability[1] |= ZM_BIT_0; ++ else ++ wd->sta.capability[1] &= (~ZM_BIT_0); ++ ++ return 0; ++} ++ ++u8_t zfiWlanSetDot11HTPCMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ // TODO : TPC Enable in 5150~5350 MHz and 5470~5725MHz. ++ //if ( Adapter->ZD80211HSupport && ++ // Adapter->CardSetting.NetworkTypeInUse == Ndis802_11OFDM5 && ++ // ((ChannelNo == 36 || ChannelNo == 40 || ChannelNo == 44 || ChannelNo == 48) || //5150~5250 MHZ , Not Japan ++ // (ChannelNo >=52 && ChannelNo <= 64) || //5250~5350 MHZ ++ // (ChannelNo >=100 && ChannelNo <= 140))) //5470~5725 MHZ ++ //{ ++ // Adapter->ZD80211HSetting.TPCEnable=TRUE; ++ //} ++ //else ++ //{ ++ // Adapter->ZD80211HSetting.TPCEnable=FALSE; ++ //} ++ ++ wd->sta.TPCEnable = mode; ++ if (mode) ++ wd->sta.capability[1] |= ZM_BIT_0; ++ else ++ wd->sta.capability[1] &= (~ZM_BIT_0); ++ ++ return 0; ++} ++ ++u8_t zfiWlanSetAniMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->aniEnable = mode; ++ if (mode) ++ zfHpAniAttach(dev); ++ ++ return 0; ++} ++ ++#ifdef ZM_OS_LINUX_FUNC ++void zfiWlanShowTally(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg1_mm(ZM_LV_0, "Hw_UnderrunCnt = ", wd->commTally.Hw_UnderrunCnt); ++ zm_msg1_mm(ZM_LV_0, "Hw_TotalRxFrm = ", wd->commTally.Hw_TotalRxFrm); ++ zm_msg1_mm(ZM_LV_0, "Hw_CRC32Cnt = ", wd->commTally.Hw_CRC32Cnt); ++ zm_msg1_mm(ZM_LV_0, "Hw_CRC16Cnt = ", wd->commTally.Hw_CRC16Cnt); ++ zm_msg1_mm(ZM_LV_1, "Hw_DecrypErr_UNI = ", wd->commTally.Hw_DecrypErr_UNI); ++ zm_msg1_mm(ZM_LV_0, "Hw_RxFIFOOverrun = ", wd->commTally.Hw_RxFIFOOverrun); ++ zm_msg1_mm(ZM_LV_1, "Hw_DecrypErr_Mul = ", wd->commTally.Hw_DecrypErr_Mul); ++ zm_msg1_mm(ZM_LV_1, "Hw_RetryCnt = ", wd->commTally.Hw_RetryCnt); ++ zm_msg1_mm(ZM_LV_0, "Hw_TotalTxFrm = ", wd->commTally.Hw_TotalTxFrm); ++ zm_msg1_mm(ZM_LV_0, "Hw_RxTimeOut = ", wd->commTally.Hw_RxTimeOut); ++ zm_msg1_mm(ZM_LV_0, "Tx_MPDU = ", wd->commTally.Tx_MPDU); ++ zm_msg1_mm(ZM_LV_0, "BA_Fail = ", wd->commTally.BA_Fail); ++ zm_msg1_mm(ZM_LV_0, "Hw_Tx_AMPDU = ", wd->commTally.Hw_Tx_AMPDU); ++ zm_msg1_mm(ZM_LV_0, "Hw_Tx_MPDU = ", wd->commTally.Hw_Tx_MPDU); ++ ++ zm_msg1_mm(ZM_LV_1, "Hw_RxMPDU = ", wd->commTally.Hw_RxMPDU); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxDropMPDU = ", wd->commTally.Hw_RxDropMPDU); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxDelMPDU = ", wd->commTally.Hw_RxDelMPDU); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyMiscError = ", wd->commTally.Hw_RxPhyMiscError); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyXRError = ", wd->commTally.Hw_RxPhyXRError); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyOFDMError = ", wd->commTally.Hw_RxPhyOFDMError); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyCCKError = ", wd->commTally.Hw_RxPhyCCKError); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyHTError = ", wd->commTally.Hw_RxPhyHTError); ++ zm_msg1_mm(ZM_LV_1, "Hw_RxPhyTotalCount = ", wd->commTally.Hw_RxPhyTotalCount); ++ ++ if (!((wd->commTally.Tx_MPDU == 0) && (wd->commTally.BA_Fail == 0))) ++ { ++ zm_debug_msg_p("BA Fail Ratio(%) = ", wd->commTally.BA_Fail * 100, ++ (wd->commTally.BA_Fail + wd->commTally.Tx_MPDU)); ++ } ++ ++ if (!((wd->commTally.Hw_Tx_MPDU == 0) && (wd->commTally.Hw_Tx_AMPDU == 0))) ++ { ++ zm_debug_msg_p("Avg Agg Number = ", ++ wd->commTally.Hw_Tx_MPDU, wd->commTally.Hw_Tx_AMPDU); ++ } ++} ++#endif ++ ++void zfiWlanSetMaxTxPower(zdev_t* dev, u8_t power2, u8_t power5) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->maxTxPower2 = power2; ++ wd->maxTxPower5 = power5; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanQueryMaxTxPower(zdev_t* dev, u8_t *power2, u8_t *power5) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ *power2 = wd->maxTxPower2; ++ *power5 = wd->maxTxPower5; ++} ++ ++void zfiWlanSetConnectMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->connectMode = mode; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetSupportMode(zdev_t* dev, u32_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->supportMode = mode; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanSetAdhocMode(zdev_t* dev, u32_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ws.adhocMode = mode; ++} ++ ++u32_t zfiWlanQueryAdhocMode(zdev_t* dev, u8_t bWrapper) ++{ ++ u32_t adhocMode; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( bWrapper ) ++ { ++ adhocMode = wd->ws.adhocMode; ++ } ++ else ++ { ++ adhocMode = wd->wfc.bIbssGMode; ++ } ++ ++ return adhocMode; ++} ++ ++ ++u8_t zfiWlanSetCountryIsoName(zdev_t* dev, u8_t *countryIsoName, u8_t length) ++{ ++ u8_t buf[5]; ++ zmw_get_wlan_dev(dev); ++ ++ if (length == 4) ++ { ++ buf[2] = wd->ws.countryIsoName[0] = countryIsoName[2]; ++ buf[3] = wd->ws.countryIsoName[1] = countryIsoName[1]; ++ buf[4] = wd->ws.countryIsoName[2] = countryIsoName[0]; ++ } ++ else if (length == 3) ++ { ++ buf[2] = wd->ws.countryIsoName[0] = countryIsoName[1]; ++ buf[3] = wd->ws.countryIsoName[1] = countryIsoName[0]; ++ buf[4] = wd->ws.countryIsoName[2] = '\0'; ++ } ++ else ++ { ++ return 1; ++ } ++ ++ return zfHpGetRegulationTablefromISO(dev, buf, length); ++} ++ ++ ++const char* zfiWlanQueryCountryIsoName(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->ws.countryIsoName; ++} ++ ++ ++ ++void zfiWlanSetRegulatory(zdev_t* dev, u8_t CCS, u16_t Code, u8_t bfirstChannel) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if (CCS) ++ { ++ /* Reset Regulation Table by Country Code */ ++ zfHpGetRegulationTablefromCountry(dev, Code); ++ } ++ else ++ { ++ /* Reset Regulation Table by Region Code */ ++ zfHpGetRegulationTablefromRegionCode(dev, Code); ++ } ++ ++ if (bfirstChannel) { ++ zmw_enter_critical_section(dev); ++ wd->frequency = zfChGetFirstChannel(dev, NULL); ++ zmw_leave_critical_section(dev); ++ zfCoreSetFrequency(dev, wd->frequency); ++ } ++} ++ ++ ++const char* zfiHpGetisoNamefromregionCode(zdev_t* dev, u16_t regionCode) ++{ ++ return zfHpGetisoNamefromregionCode(dev, regionCode); ++} ++ ++u16_t zfiWlanChannelToFrequency(zdev_t* dev, u8_t channel) ++{ ++ return zfChNumToFreq(dev, channel, 0); ++} ++ ++u8_t zfiWlanFrequencyToChannel(zdev_t* dev, u16_t freq) ++{ ++ u8_t is5GBand = 0; ++ ++ return zfChFreqToNum(freq, &is5GBand); ++} ++ ++void zfiWlanDisableDfsChannel(zdev_t* dev, u8_t disableFlag) ++{ ++ zfHpDisableDfsChannel(dev, disableFlag); ++ return; ++} ++ ++void zfiWlanSetLEDCtrlParam(zdev_t* dev, u8_t type, u8_t flag) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->ledStruct.LEDCtrlType = type; ++ wd->ledStruct.LEDCtrlFlagFromReg = flag; ++ zmw_leave_critical_section(dev); ++} ++ ++void zfiWlanEnableLeapConfig(zdev_t* dev, u8_t leapEnabled) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.leapEnabled = leapEnabled; ++} ++ ++u32_t zfiWlanQueryHwCapability(zdev_t* dev) ++{ ++ return zfHpCapability(dev); ++} ++ ++u32_t zfiWlanQueryReceivedPacket(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->sta.ReceivedPktRatePerSecond; ++} ++ ++void zfiWlanCheckSWEncryption(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if (wd->sta.SWEncryptEnable != 0) ++ { ++ zfHpSWDecrypt(dev, 1); ++ } ++} ++ ++u16_t zfiWlanQueryAllowChannels(zdev_t* dev, u16_t *channels) ++{ ++ u16_t ii; ++ zmw_get_wlan_dev(dev); ++ ++ for (ii = 0; ii < wd->regulationTable.allowChannelCnt; ii++) ++ { ++ channels[ii] = wd->regulationTable.allowChannel[ii].channel; ++ } ++ ++ return wd->regulationTable.allowChannelCnt; ++} ++ ++void zfiWlanSetDynamicSIFSParam(zdev_t* dev, u8_t val) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->dynamicSIFSEnable = val; ++ ++ zm_debug_msg1("wd->dynamicSIFSEnable = ", wd->dynamicSIFSEnable) ++} ++ ++u16_t zfiWlanGetMulticastAddressCount(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ return wd->sta.multicastList.size; ++} ++ ++void zfiWlanGetMulticastList(zdev_t* dev, u8_t* pMCList) ++{ ++ struct zsMulticastAddr* pMacList = (struct zsMulticastAddr*) pMCList; ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for ( i=0; ista.multicastList.size; i++ ) ++ { ++ zfMemoryCopy(pMacList[i].addr, wd->sta.multicastList.macAddr[i].addr, 6); ++ } ++} ++ ++void zfiWlanSetPacketFilter(zdev_t* dev, u32_t PacketFilter) ++{ ++ u8_t bAllMulticast = 0; ++ u32_t oldFilter; ++ ++ zmw_get_wlan_dev(dev); ++ ++ oldFilter = wd->sta.osRxFilter; ++ ++ wd->sta.osRxFilter = PacketFilter; ++ ++ if ((oldFilter & ZM_PACKET_TYPE_ALL_MULTICAST) != ++ (wd->sta.osRxFilter & ZM_PACKET_TYPE_ALL_MULTICAST)) ++ { ++ if ( wd->sta.osRxFilter & ZM_PACKET_TYPE_ALL_MULTICAST ) ++ bAllMulticast = 1; ++ zfHpSetMulticastList(dev, wd->sta.multicastList.size, ++ (u8_t*)wd->sta.multicastList.macAddr, bAllMulticast); ++ } ++} ++ ++u8_t zfiCompareWithMulticastListAddress(zdev_t* dev, u16_t* dstMacAddr) ++{ ++ u8_t i; ++ u8_t bIsInMCListAddr = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for ( i=0; ista.multicastList.size; i++ ) ++ { ++ if ( zfwMemoryIsEqual((u8_t*)dstMacAddr, (u8_t*)wd->sta.multicastList.macAddr[i].addr, 6) ) ++ { ++ bIsInMCListAddr = 1; ++ break; ++ } ++ } ++ ++ return bIsInMCListAddr; ++} ++ ++void zfiWlanSetSafeModeEnabled(zdev_t* dev, u8_t safeMode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.bSafeMode = safeMode; ++ ++ if ( safeMode ) ++ zfStaEnableSWEncryption(dev, 1); ++ else ++ zfStaDisableSWEncryption(dev); ++} ++ ++void zfiWlanSetIBSSAdditionalIELength(zdev_t* dev, u32_t ibssAdditionalIESize, u8_t* ibssAdditionalIE) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( ibssAdditionalIESize ) ++ { ++ wd->sta.ibssAdditionalIESize = ibssAdditionalIESize; ++ zfMemoryCopy(wd->sta.ibssAdditionalIE, ibssAdditionalIE, (u16_t)ibssAdditionalIESize); ++ } ++ else ++ wd->sta.ibssAdditionalIESize = 0; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cprecomp.h +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _CPRECOMP_H ++#define _CPRECOMP_H ++ ++#include "../oal_dt.h" ++#include "../oal_marc.h" ++#include "pub_zfi.h" ++#include "pub_zfw.h" ++#include "pub_usb.h" ++#include "wlan.h" ++#include "struct.h" ++#include "cfunc.h" ++#include "cagg.h" ++#include "cwm.h" ++#include "performance.h" ++#endif ++ +--- /dev/null ++++ b/drivers/staging/otus/80211core/cpsmgr.c +@@ -0,0 +1,731 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/** ++ * The power saving manager is to save the power as much as possible. ++ * Generally speaking, it controls: ++ * ++ * - when to sleep ++ * - ++ * ++ */ ++#include "cprecomp.h" ++ ++void zfPowerSavingMgrInit(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.powerSaveMode = ZM_STA_PS_NONE; ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_ACTIVE; ++ wd->sta.psMgr.isSleepAllowed = 0; ++ wd->sta.psMgr.maxSleepPeriods = 1; ++ wd->sta.psMgr.ticks = 0; ++ wd->sta.psMgr.sleepAllowedtick = 0; ++} ++ ++static u16_t zfPowerSavingMgrHandlePsNone(zdev_t* dev, u8_t *isWakeUpRequired) ++{ ++ u16_t ret = 0; ++ zmw_get_wlan_dev(dev); ++ ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ *isWakeUpRequired = 0; ++ break; ++ ++ case ZM_PS_MSG_STATE_T1: ++ case ZM_PS_MSG_STATE_T2: ++ case ZM_PS_MSG_STATE_SLEEP: ++ default: ++ *isWakeUpRequired = 1; ++zm_debug_msg0("zfPowerSavingMgrHandlePsNone: Wake up now\n"); ++ if ( zfStaIsConnected(dev) ) ++ { ++ zm_debug_msg0("zfPowerSavingMgrOnHandleT1 send Null data\n"); ++ //zfSendNullData(dev, 0); ++ ret = 1; ++ } ++ ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_ACTIVE; ++ break; ++ } ++ return ret; ++} ++ ++static void zfPowerSavingMgrHandlePs(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ //zm_debug_msg0("zfPowerSavingMgrHandlePs: Prepare to sleep...\n"); ++ //wd->sta.psMgr.state = ZM_PS_MSG_STATE_T1; ++ break; ++ ++ case ZM_PS_MSG_STATE_T1: ++ case ZM_PS_MSG_STATE_T2: ++ case ZM_PS_MSG_STATE_SLEEP: ++ default: ++ break; ++ } ++} ++ ++void zfPowerSavingMgrSetMode(zdev_t* dev, u8_t mode) ++{ ++ u16_t sendNull = 0; ++ u8_t isWakeUpRequired = 0; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zm_debug_msg1("mode = ", mode); ++ ++ if (mode > ZM_STA_PS_LIGHT) ++ { ++ zm_debug_msg0("return - wrong power save mode"); ++ return; ++ } ++ ++ zmw_enter_critical_section(dev); ++ ++ #if 1 ++ switch(mode) ++ { ++ case ZM_STA_PS_NONE: ++ sendNull = zfPowerSavingMgrHandlePsNone(dev, &isWakeUpRequired); ++ break; ++ ++ case ZM_STA_PS_FAST: ++ case ZM_STA_PS_LIGHT: ++ wd->sta.psMgr.maxSleepPeriods = 1; ++ zfPowerSavingMgrHandlePs(dev); ++ break; ++ ++ case ZM_STA_PS_MAX: ++ wd->sta.psMgr.maxSleepPeriods = ZM_PS_MAX_SLEEP_PERIODS; ++ zfPowerSavingMgrHandlePs(dev); ++ break; ++ } ++ #else ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ if ( mode != ZM_STA_PS_NONE ) ++ { ++zm_debug_msg0("zfPowerSavingMgrSetMode: switch from ZM_PS_MSG_STATE_ACTIVE to ZM_PS_MSG_STATE_T1\n"); ++ // Stall the TX & start to wait the pending TX to be completed ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_T1; ++ } ++ break; ++ ++ case ZM_PS_MSG_STATE_SLEEP: ++ break; ++ } ++ #endif ++ ++ wd->sta.powerSaveMode = mode; ++ zmw_leave_critical_section(dev); ++ ++ if ( isWakeUpRequired ) ++ { ++ zfHpPowerSaveSetState(dev, 0); ++ wd->sta.psMgr.tempWakeUp = 0; ++ } ++ ++ if ( zfStaIsConnected(dev) ++ && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ) ++ { ++ switch(mode) ++ { ++ case ZM_STA_PS_NONE: ++ zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); ++ break; ++ ++ case ZM_STA_PS_FAST: ++ case ZM_STA_PS_MAX: ++ case ZM_STA_PS_LIGHT: ++ zfHpPowerSaveSetMode(dev, 0, 1, wd->beaconInterval); ++ break; ++ ++ default: ++ zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); ++ break; ++ } ++ } ++ ++ if (sendNull == 1) ++ { ++ zfSendNullData(dev, 0); ++ } ++ ++ return; ++} ++ ++static void zfPowerSavingMgrNotifyPSToAP(zdev_t *dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ if ( (wd->sta.psMgr.tempWakeUp != 1)&& ++ (wd->sta.psMgr.lastTxUnicastFrm != wd->commTally.txUnicastFrm || ++ wd->sta.psMgr.lastTxBroadcastFrm != wd->commTally.txBroadcastFrm || ++ wd->sta.psMgr.lastTxMulticastFrm != wd->commTally.txMulticastFrm) ) ++ { ++ zmw_enter_critical_section(dev); ++ wd->sta.psMgr.lastTxUnicastFrm = wd->commTally.txUnicastFrm; ++ wd->sta.psMgr.lastTxBroadcastFrm = wd->commTally.txBroadcastFrm; ++ wd->sta.psMgr.lastTxMulticastFrm = wd->commTally.txMulticastFrm; ++ zmw_leave_critical_section(dev); ++ ++ zfSendNullData(dev, 1); ++ } ++} ++ ++static void zfPowerSavingMgrOnHandleT1(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ // If the tx Q is not empty...return ++ if ( zfIsVtxqEmpty(dev) == FALSE ) ++ { ++ return; ++ } ++ ++zm_debug_msg0("VtxQ is empty now...Check if HAL TXQ is empty\n"); ++ ++ // The the HAL TX Q is not empty...return ++ if ( zfHpGetFreeTxdCount(dev) != zfHpGetMaxTxdCount(dev) ) ++ { ++ return; ++ } ++ ++zm_debug_msg0("HAL TXQ is empty now...Could go to sleep...\n"); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (wd->sta.powerSaveMode == ZM_STA_PS_LIGHT) ++ { ++ if (wd->sta.ReceivedPktRatePerSecond > 200) ++ { ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ ++ if ( zfStaIsConnected(dev) ++ && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ) ++ { ++ if (wd->sta.psMgr.sleepAllowedtick) { ++ wd->sta.psMgr.sleepAllowedtick--; ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ } ++ } ++ ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_T2; ++ ++ zmw_leave_critical_section(dev); ++ ++ // Send the Null pkt to AP to notify that I'm going to sleep ++ if ( zfStaIsConnected(dev) ) ++ { ++zm_debug_msg0("zfPowerSavingMgrOnHandleT1 send Null data\n"); ++ zfPowerSavingMgrNotifyPSToAP(dev); ++ } ++ ++ // Stall the TX now ++ // zfTxEngineStop(dev); ++} ++ ++static void zfPowerSavingMgrOnHandleT2(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ // Wait until the Null pkt is transmitted ++ if ( zfHpGetFreeTxdCount(dev) != zfHpGetMaxTxdCount(dev) ) ++ { ++ return; ++ } ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_SLEEP; ++ wd->sta.psMgr.lastTxUnicastFrm = wd->commTally.txUnicastFrm; ++ wd->sta.psMgr.lastTxBroadcastFrm = wd->commTally.txBroadcastFrm; ++ wd->sta.psMgr.lastTxMulticastFrm = wd->commTally.txMulticastFrm; ++ zmw_leave_critical_section(dev); ++ ++ // Let CHIP sleep now ++zm_debug_msg0("zfPowerSavingMgrOnHandleT2 zzzz....\n"); ++ zfHpPowerSaveSetState(dev, 1); ++ wd->sta.psMgr.tempWakeUp = 0; ++} ++ ++u8_t zfPowerSavingMgrIsSleeping(zdev_t *dev) ++{ ++ u8_t isSleeping = FALSE; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if ( wd->sta.psMgr.state == ZM_PS_MSG_STATE_SLEEP || ++ wd->sta.psMgr.state == ZM_PS_MSG_STATE_T2) ++ { ++ isSleeping = TRUE; ++ } ++ zmw_leave_critical_section(dev); ++ return isSleeping; ++} ++ ++static u8_t zfPowerSavingMgrIsIdle(zdev_t *dev) ++{ ++ u8_t isIdle = 0; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ( zfStaIsConnected(dev) && wd->sta.psMgr.isSleepAllowed == 0 ) ++ { ++ goto done; ++ } ++ ++ if ( wd->sta.bChannelScan ) ++ { ++ goto done; ++ } ++ ++ if ( zfStaIsConnecting(dev) ) ++ { ++ goto done; ++ } ++ ++ if (wd->sta.powerSaveMode == ZM_STA_PS_LIGHT) ++ { ++ if (wd->sta.ReceivedPktRatePerSecond > 200) ++ { ++ goto done; ++ } ++ ++ if ( zfStaIsConnected(dev) ++ && (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ) ++ { ++ if (wd->sta.psMgr.sleepAllowedtick) { ++ wd->sta.psMgr.sleepAllowedtick--; ++ goto done; ++ } ++ } ++ } ++ ++ isIdle = 1; ++ ++done: ++ zmw_leave_critical_section(dev); ++ ++ if ( zfIsVtxqEmpty(dev) == FALSE ) ++ { ++ isIdle = 0; ++ } ++ ++ return isIdle; ++} ++ ++static void zfPowerSavingMgrSleepIfIdle(zdev_t *dev) ++{ ++ u8_t isIdle; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ isIdle = zfPowerSavingMgrIsIdle(dev); ++ ++ if ( isIdle == 0 ) ++ { ++ return; ++ } ++ ++ zmw_enter_critical_section(dev); ++ ++ switch(wd->sta.powerSaveMode) ++ { ++ case ZM_STA_PS_NONE: ++ break; ++ ++ case ZM_STA_PS_MAX: ++ case ZM_STA_PS_FAST: ++ case ZM_STA_PS_LIGHT: ++ zm_debug_msg0("zfPowerSavingMgrSleepIfIdle: IDLE so slep now...\n"); ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_T1; ++ break; ++ } ++ ++ zmw_leave_critical_section(dev); ++} ++ ++static void zfPowerSavingMgrDisconnectMain(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++#ifdef ZM_ENABLE_DISCONNECT_PS ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ zfPowerSavingMgrSleepIfIdle(dev); ++ break; ++ ++ case ZM_PS_MSG_STATE_SLEEP: ++ break; ++ ++ case ZM_PS_MSG_STATE_T1: ++ zfPowerSavingMgrOnHandleT1(dev); ++ break; ++ ++ case ZM_PS_MSG_STATE_T2: ++ zfPowerSavingMgrOnHandleT2(dev); ++ break; ++ } ++#else ++ zfPowerSavingMgrWakeup(dev); ++#endif ++} ++ ++static void zfPowerSavingMgrInfraMain(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ zfPowerSavingMgrSleepIfIdle(dev); ++ break; ++ ++ case ZM_PS_MSG_STATE_SLEEP: ++ break; ++ ++ case ZM_PS_MSG_STATE_T1: ++ zfPowerSavingMgrOnHandleT1(dev); ++ break; ++ ++ case ZM_PS_MSG_STATE_T2: ++ zfPowerSavingMgrOnHandleT2(dev); ++ break; ++ } ++} ++ ++void zfPowerSavingMgrAtimWinExpired(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++//printk("zfPowerSavingMgrAtimWinExpired #1\n"); ++ if ( wd->sta.powerSaveMode == ZM_STA_PS_NONE ) ++ { ++ return; ++ } ++ ++//printk("zfPowerSavingMgrAtimWinExpired #2\n"); ++ // if we received any ATIM window from the others to indicate we have buffered data ++ // at the other station, we can't go to sleep ++ if ( wd->sta.recvAtim ) ++ { ++ wd->sta.recvAtim = 0; ++ zm_debug_msg0("Can't sleep due to receving ATIM window!"); ++ return; ++ } ++ ++ // if we are the one to tx beacon during last beacon interval. we can't go to sleep ++ // since we need to be alive to respond the probe request! ++ if ( wd->sta.txBeaconInd ) ++ { ++ zm_debug_msg0("Can't sleep due to just transmit a beacon!"); ++ return; ++ } ++ ++ // If we buffer any data for the other stations. we could not go to sleep ++ if ( wd->sta.ibssPrevPSDataCount != 0 ) ++ { ++ zm_debug_msg0("Can't sleep due to buffering data for the others!"); ++ return; ++ } ++ ++ // before sleeping, we still need to notify the others by transmitting null ++ // pkt with power mgmt bit turned on. ++ zfPowerSavingMgrOnHandleT1(dev); ++} ++ ++static void zfPowerSavingMgrIBSSMain(zdev_t* dev) ++{ ++ // wait for the end of ++ // if need to wait to know if we are the one to transmit the beacon ++ // during the beacon interval. If it's me, we can't go to sleep. ++ ++ zmw_get_wlan_dev(dev); ++ ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ case ZM_PS_MSG_STATE_SLEEP: ++ case ZM_PS_MSG_STATE_T1: ++ break; ++ ++ case ZM_PS_MSG_STATE_T2: ++ zfPowerSavingMgrOnHandleT2(dev); ++ break; ++ } ++ ++ return; ++} ++ ++#if 1 ++void zfPowerSavingMgrMain(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch (wd->sta.adapterState) ++ { ++ case ZM_STA_STATE_DISCONNECT: ++ zfPowerSavingMgrDisconnectMain(dev); ++ break; ++ case ZM_STA_STATE_CONNECTED: ++ { ++ if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) { ++ zfPowerSavingMgrInfraMain(dev); ++ } else if (wd->wlanMode == ZM_MODE_IBSS) { ++ zfPowerSavingMgrIBSSMain(dev); ++ } ++ } ++ break; ++ case ZM_STA_STATE_CONNECTING: ++ default: ++ break; ++ } ++} ++#else ++void zfPowerSavingMgrMain(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode != ZM_MODE_INFRASTRUCTURE ) ++ { ++ return; ++ } ++ ++ switch(wd->sta.psMgr.state) ++ { ++ case ZM_PS_MSG_STATE_ACTIVE: ++ goto check_sleep; ++ break; ++ ++ case ZM_PS_MSG_STATE_SLEEP: ++ goto sleeping; ++ break; ++ ++ case ZM_PS_MSG_STATE_T1: ++ zfPowerSavingMgrOnHandleT1(dev); ++ break; ++ ++ case ZM_PS_MSG_STATE_T2: ++ zfPowerSavingMgrOnHandleT2(dev); ++ break; ++ } ++ ++ return; ++ ++sleeping: ++ return; ++ ++check_sleep: ++ zfPowerSavingMgrSleepIfIdle(dev); ++ return; ++} ++#endif ++ ++#ifdef ZM_ENABLE_POWER_SAVE ++void zfPowerSavingMgrWakeup(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++//zm_debug_msg0("zfPowerSavingMgrWakeup"); ++ ++ //if ( wd->sta.psMgr.state != ZM_PS_MSG_STATE_ACTIVE && ( zfPowerSavingMgrIsIdle(dev) == 0 )) ++ if ( wd->sta.psMgr.state != ZM_PS_MSG_STATE_ACTIVE ) ++ { ++ zmw_enter_critical_section(dev); ++ ++ wd->sta.psMgr.isSleepAllowed = 0; ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_ACTIVE; ++ ++ if ( wd->sta.powerSaveMode > ZM_STA_PS_NONE ) ++ wd->sta.psMgr.tempWakeUp = 1; ++ ++ zmw_leave_critical_section(dev); ++ ++ // Wake up the CHIP now!! ++ zfHpPowerSaveSetState(dev, 0); ++ } ++} ++#else ++void zfPowerSavingMgrWakeup(zdev_t* dev) ++{ ++} ++#endif ++ ++void zfPowerSavingMgrProcessBeacon(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t length, bitmap; ++ u16_t offset, n1, n2, q, r; ++ zbuf_t* psBuf; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->sta.powerSaveMode == ZM_STA_PS_NONE ) ++ //if ( wd->sta.psMgr.state != ZM_PS_MSG_STATE_SLEEP ) ++ { ++ return; ++ } ++ ++ wd->sta.psMgr.isSleepAllowed = 1; ++ ++ if ( (offset=zfFindElement(dev, buf, ZM_WLAN_EID_TIM)) != 0xffff ) ++ { ++ length = zmw_rx_buf_readb(dev, buf, offset+1); ++ ++ if ( length > 3 ) ++ { ++ n1 = zmw_rx_buf_readb(dev, buf, offset+4) & (~ZM_BIT_0); ++ n2 = length + n1 - 4; ++ q = wd->sta.aid >> 3; ++ r = wd->sta.aid & 7; ++ ++ if ((q >= n1) && (q <= n2)) ++ { ++ bitmap = zmw_rx_buf_readb(dev, buf, offset+5+q-n1); ++ ++ if ( (bitmap >> r) & ZM_BIT_0 ) ++ { ++ //if ( wd->sta.powerSaveMode == ZM_STA_PS_FAST ) ++ if ( 0 ) ++ { ++ wd->sta.psMgr.state = ZM_PS_MSG_STATE_S1; ++ //zfSendPSPoll(dev); ++ zfSendNullData(dev, 0); ++ } ++ else ++ { ++ if ((wd->sta.qosInfo&0xf) != 0xf) ++ { ++ /* send ps-poll */ ++ //printk("zfSendPSPoll #1\n"); ++ ++ wd->sta.psMgr.isSleepAllowed = 0; ++ ++ switch (wd->sta.powerSaveMode) ++ { ++ case ZM_STA_PS_MAX: ++ case ZM_STA_PS_FAST: ++ //zm_debug_msg0("wake up and send PS-Poll\n"); ++ zfSendPSPoll(dev); ++ break; ++ case ZM_STA_PS_LIGHT: ++ zm_debug_msg0("wake up and send null data\n"); ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.psMgr.sleepAllowedtick = 400; ++ zmw_leave_critical_section(dev); ++ ++ zfSendNullData(dev, 0); ++ break; ++ } ++ ++ wd->sta.psMgr.tempWakeUp = 0; ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ while ((psBuf = zfQueueGet(dev, wd->sta.uapsdQ)) != NULL) ++ { ++ zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ } ++ ++ //printk("zfPowerSavingMgrProcessBeacon #1\n"); ++ zfPowerSavingMgrMain(dev); ++} ++ ++void zfPowerSavingMgrConnectNotify(zdev_t *dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ switch(wd->sta.powerSaveMode) ++ { ++ case ZM_STA_PS_NONE: ++ zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); ++ break; ++ ++ case ZM_STA_PS_FAST: ++ case ZM_STA_PS_MAX: ++ case ZM_STA_PS_LIGHT: ++ zfHpPowerSaveSetMode(dev, 0, 1, wd->beaconInterval); ++ break; ++ ++ default: ++ zfHpPowerSaveSetMode(dev, 0, 0, wd->beaconInterval); ++ break; ++ } ++ } ++} ++ ++void zfPowerSavingMgrPreTBTTInterrupt(zdev_t *dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ /* disable TBTT interrupt when change from connection to disconnect */ ++ if (zfStaIsDisconnect(dev)) { ++ zfHpPowerSaveSetMode(dev, 0, 0, 0); ++ zfPowerSavingMgrWakeup(dev); ++ return; ++ } ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.psMgr.ticks++; ++ ++ if ( wd->sta.psMgr.ticks < wd->sta.psMgr.maxSleepPeriods ) ++ { ++ zmw_leave_critical_section(dev); ++ return; ++ } ++ else ++ { ++ wd->sta.psMgr.ticks = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zfPowerSavingMgrWakeup(dev); ++} ++ ++/* Leave an empty line below to remove warning message on some compiler */ ++ +--- /dev/null ++++ b/drivers/staging/otus/80211core/cscanmgr.c +@@ -0,0 +1,535 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++ ++void zfScanMgrInit(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->sta.scanMgr.scanReqs[0] = 0; ++ wd->sta.scanMgr.scanReqs[1] = 0; ++ ++ wd->sta.scanMgr.currScanType = ZM_SCAN_MGR_SCAN_NONE; ++ wd->sta.scanMgr.scanStartDelay = 3; ++ //wd->sta.scanMgr.scanStartDelay = 0; ++} ++ ++u8_t zfScanMgrScanStart(zdev_t* dev, u8_t scanType) ++{ ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg1("scanType = ", scanType); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( scanType != ZM_SCAN_MGR_SCAN_INTERNAL && ++ scanType != ZM_SCAN_MGR_SCAN_EXTERNAL ) ++ { ++ zm_debug_msg0("unknown scanType"); ++ return 1; ++ } ++ else if (zfStaIsConnecting(dev)) ++ { ++ zm_debug_msg0("reject scan request due to connecting"); ++ return 1; ++ } ++ ++ i = scanType - 1; ++ ++ zmw_enter_critical_section(dev); ++ ++ if ( wd->sta.scanMgr.scanReqs[i] == 1 ) ++ { ++ zm_debug_msg1("scan rescheduled", scanType); ++ goto scan_done; ++ } ++ ++ wd->sta.scanMgr.scanReqs[i] = 1; ++ zm_debug_msg1("scan scheduled: ", scanType); ++ ++ // If there's no scan pending, we do the scan right away. ++ // If there's an internal scan and the new scan request is external one, ++ // we will restart the scan. ++ if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_NONE ) ++ { ++ goto schedule_scan; ++ } ++ else if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_INTERNAL && ++ scanType == ZM_SCAN_MGR_SCAN_EXTERNAL ) ++ { ++ // Stop the internal scan & schedule external scan first ++ zfTimerCancel(dev, ZM_EVENT_SCAN); ++ ++ /* Fix for WHQL sendrecv => we do not apply delay time in which the device ++ stop transmitting packet when we already connect to some AP */ ++ wd->sta.bScheduleScan = FALSE; ++ ++ zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); ++ zfTimerCancel(dev, ZM_EVENT_IN_SCAN); ++ ++ wd->sta.bChannelScan = FALSE; ++ goto schedule_scan; ++ } ++ else ++ { ++ zm_debug_msg0("Scan is busy...waiting later to start\n"); ++ } ++ ++ zmw_leave_critical_section(dev); ++ return 0; ++ ++scan_done: ++ zmw_leave_critical_section(dev); ++ return 1; ++ ++schedule_scan: ++ ++ wd->sta.bScheduleScan = TRUE; ++ ++ zfTimerSchedule(dev, ZM_EVENT_SCAN, wd->sta.scanMgr.scanStartDelay); ++ wd->sta.scanMgr.scanStartDelay = 3; ++ //wd->sta.scanMgr.scanStartDelay = 0; ++ wd->sta.scanMgr.currScanType = scanType; ++ zmw_leave_critical_section(dev); ++ ++ if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) ++ { ++ zfSendNullData(dev, 1); ++ } ++ return 0; ++} ++ ++void zfScanMgrScanStop(zdev_t* dev, u8_t scanType) ++{ ++ u8_t scanNotifyRequired = 0; ++ u8_t theOtherScan = ZM_SCAN_MGR_SCAN_NONE; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_NONE ) ++ { ++ zm_assert(wd->sta.scanMgr.scanReqs[0] == 0); ++ zm_assert(wd->sta.scanMgr.scanReqs[1] == 0); ++ goto done; ++ } ++ ++ switch(scanType) ++ { ++ case ZM_SCAN_MGR_SCAN_EXTERNAL: ++ scanNotifyRequired = 1; ++ theOtherScan = ZM_SCAN_MGR_SCAN_INTERNAL; ++ break; ++ ++ case ZM_SCAN_MGR_SCAN_INTERNAL: ++ theOtherScan = ZM_SCAN_MGR_SCAN_EXTERNAL; ++ break; ++ ++ default: ++ goto done; ++ } ++ ++ if ( wd->sta.scanMgr.currScanType != scanType ) ++ { ++ goto stop_done; ++ } ++ ++ zfTimerCancel(dev, ZM_EVENT_SCAN); ++ ++ /* Fix for WHQL sendrecv => we do not apply delay time in which the device ++ stop transmitting packet when we already connect to some AP */ ++ wd->sta.bScheduleScan = FALSE; ++ ++ zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); ++ zfTimerCancel(dev, ZM_EVENT_IN_SCAN); ++ ++ wd->sta.bChannelScan = FALSE; ++ wd->sta.scanFrequency = 0; ++ ++ if ( wd->sta.scanMgr.scanReqs[theOtherScan - 1] ) ++ { ++ wd->sta.scanMgr.currScanType = theOtherScan; ++ ++ // Schedule the other scan after 1 second later ++ zfTimerSchedule(dev, ZM_EVENT_SCAN, 100); ++ } ++ else ++ { ++ wd->sta.scanMgr.currScanType = ZM_SCAN_MGR_SCAN_NONE; ++ } ++ ++stop_done: ++ wd->sta.scanMgr.scanReqs[scanType - 1] = 0; ++ ++ zmw_leave_critical_section(dev); ++ ++ /* avoid lose receive packet when site survey */ ++ if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) ++ { ++ zfSendNullData(dev, 0); ++ } ++ ++ if ( scanNotifyRequired ) ++ { ++ zm_debug_msg0("Scan notify after reset"); ++ if (wd->zfcbScanNotify != NULL) ++ { ++ wd->zfcbScanNotify(dev, NULL); ++ } ++ } ++ ++ return; ++ ++done: ++ zmw_leave_critical_section(dev); ++ return; ++} ++ ++void zfScanMgrScanAck(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ wd->sta.scanMgr.scanStartDelay = 3; ++ //wd->sta.scanMgr.scanStartDelay = 0; ++ ++ zmw_leave_critical_section(dev); ++ return; ++} ++ ++extern void zfStaReconnect(zdev_t* dev); ++ ++static void zfScanSendProbeRequest(zdev_t* dev) ++{ ++ u8_t k; ++ u16_t dst[3] = { 0xffff, 0xffff, 0xffff }; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Increase rxBeaconCount to prevent beacon lost */ ++ if (zfStaIsConnected(dev)) ++ { ++ wd->sta.rxBeaconCount++; ++ } ++ ++ if ( wd->sta.bPassiveScan ) ++ { ++ return; ++ } ++ /* enable 802.l11h and in DFS Band , disable sending probe request */ ++ if (wd->sta.DFSEnable) ++ { ++ if (zfHpIsDfsChannel(dev, wd->sta.scanFrequency)) ++ { ++ return; ++ } ++ } ++ ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBEREQ, dst, 0, 0, 0); ++ ++ if ( wd->sta.disableProbingWithSsid ) ++ { ++ return; ++ } ++ ++ for (k=1; k<=ZM_MAX_PROBE_HIDDEN_SSID_SIZE; k++) ++ { ++ if ( wd->ws.probingSsidList[k-1].ssidLen != 0 ) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_PROBEREQ, dst, k, 0, 0); ++ } ++ } ++} ++ ++static void zfScanMgrEventSetFreqCompleteCb(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++//printk("zfScanMgrEventSetFreqCompleteCb #1\n"); ++ ++ zmw_enter_critical_section(dev); ++ zfTimerSchedule(dev, ZM_EVENT_IN_SCAN, ZM_TICK_IN_SCAN); ++ if (wd->sta.bPassiveScan) ++ { ++ zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_SCAN, wd->sta.passiveScanTickPerChannel); ++ } ++ else ++ { ++ zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_SCAN, wd->sta.activescanTickPerChannel); ++ } ++ zmw_leave_critical_section(dev); ++ ++ zfScanSendProbeRequest(dev); ++} ++ ++ ++static void zfScanMgrEventScanCompleteCb(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) ++ { ++ zfSendNullData(dev, 0); ++ } ++ return; ++} ++ ++ ++void zfScanMgrScanEventRetry(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( !wd->sta.bChannelScan ) ++ { ++ return; ++ } ++ ++ if ( !wd->sta.bPassiveScan ) ++ { ++ zfScanSendProbeRequest(dev); ++ #if 0 ++ zmw_enter_critical_section(dev); ++ zfTimerSchedule(dev, ZM_EVENT_IN_SCAN, ZM_TICK_IN_SCAN); ++ zmw_leave_critical_section(dev); ++ #endif ++ } ++} ++ ++u8_t zfScanMgrScanEventTimeout(zdev_t* dev) ++{ ++ u16_t nextScanFrequency = 0; ++ u8_t temp; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if ( wd->sta.scanFrequency == 0 ) ++ { ++ zmw_leave_critical_section(dev); ++ return -1; ++ } ++ ++ nextScanFrequency = zfChGetNextChannel(dev, wd->sta.scanFrequency, ++ &wd->sta.bPassiveScan); ++ ++ if ( (nextScanFrequency == 0xffff) ++ || (wd->sta.scanFrequency == zfChGetLastChannel(dev, &temp)) ) ++ { ++ u8_t currScanType; ++ u8_t isExternalScan = 0; ++ u8_t isInternalScan = 0; ++ ++ //zm_debug_msg1("end scan = ", KeQueryInterruptTime()); ++ wd->sta.scanFrequency = 0; ++ ++ zm_debug_msg1("scan 1 type: ", wd->sta.scanMgr.currScanType); ++ zm_debug_msg1("scan channel count = ", wd->regulationTable.allowChannelCnt); ++ ++ //zfBssInfoRefresh(dev); ++ zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); ++ ++ if ( wd->sta.bChannelScan == FALSE ) ++ { ++ zm_debug_msg0("WOW!! scan is cancelled\n"); ++ zmw_leave_critical_section(dev); ++ goto report_scan_result; ++ } ++ ++ ++ currScanType = wd->sta.scanMgr.currScanType; ++ switch(currScanType) ++ { ++ case ZM_SCAN_MGR_SCAN_EXTERNAL: ++ isExternalScan = 1; ++ ++ if ( wd->sta.scanMgr.scanReqs[ZM_SCAN_MGR_SCAN_INTERNAL - 1] ) ++ { ++ wd->sta.scanMgr.scanReqs[ZM_SCAN_MGR_SCAN_INTERNAL - 1] = 0; ++ isInternalScan = 1; ++ } ++ ++ break; ++ ++ case ZM_SCAN_MGR_SCAN_INTERNAL: ++ isInternalScan = 1; ++ ++ if ( wd->sta.scanMgr.scanReqs[ZM_SCAN_MGR_SCAN_EXTERNAL - 1] ) ++ { ++ // Because the external scan should pre-empts internal scan. ++ // So this shall not be happened!! ++ zm_assert(0); ++ } ++ ++ break; ++ ++ default: ++ zm_assert(0); ++ break; ++ } ++ ++ wd->sta.scanMgr.scanReqs[currScanType - 1] = 0; ++ wd->sta.scanMgr.scanStartDelay = 100; ++ wd->sta.scanMgr.currScanType = ZM_SCAN_MGR_SCAN_NONE; ++ zmw_leave_critical_section(dev); ++ ++ //Set channel according to AP's configuration ++ zfCoreSetFrequencyEx(dev, wd->frequency, wd->BandWidth40, ++ wd->ExtOffset, zfScanMgrEventScanCompleteCb); ++ ++ wd->sta.bChannelScan = FALSE; ++ ++ #if 1 ++ if (zfStaIsConnected(dev)) ++ { // Finish site survey, reset the variable to detect using wrong frequency ! ++ zfHpFinishSiteSurvey(dev, 1); ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssSiteSurveyStatus = 2; ++ wd->tickIbssReceiveBeacon = 0; ++ wd->sta.ibssReceiveBeaconCount = 0; ++ zmw_leave_critical_section(dev); ++ ++ /* #5 Re-enable RIFS function after the site survey ! */ ++ /* This is because switch band will reset the BB register to initial value */ ++ if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) ++ { ++ zfHpEnableRifs(dev, ((wd->sta.currentFrequency<3000)?1:0), wd->sta.EnableHT, wd->sta.HT2040); ++ } ++ } ++ else ++ { ++ zfHpFinishSiteSurvey(dev, 0); ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssSiteSurveyStatus = 0; ++ zmw_leave_critical_section(dev); ++ } ++ #endif ++ ++report_scan_result: ++ /* avoid lose receive packet when site survey */ ++ //if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) ++ //{ ++ // zfSendNullData(dev, 0); ++ //} ++ ++ if ( isExternalScan )//Quickly reboot ++ { ++ if (wd->zfcbScanNotify != NULL) ++ { ++ wd->zfcbScanNotify(dev, NULL); ++ } ++ } ++ ++ if ( isInternalScan ) ++ { ++ //wd->sta.InternalScanReq = 0; ++ zfStaReconnect(dev); ++ } ++ ++ return 0; ++ } ++ else ++ { ++ wd->sta.scanFrequency = nextScanFrequency; ++ ++ //zmw_enter_critical_section(dev); ++ zfTimerCancel(dev, ZM_EVENT_IN_SCAN); ++ zmw_leave_critical_section(dev); ++ ++ zm_debug_msg0("scan 2"); ++ zfCoreSetFrequencyV2(dev, wd->sta.scanFrequency, zfScanMgrEventSetFreqCompleteCb); ++ ++ return 1; ++ } ++} ++ ++void zfScanMgrScanEventStart(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if ( wd->sta.bChannelScan ) ++ { ++ return; ++ } ++ ++ zfPowerSavingMgrWakeup(dev); ++ ++ zmw_enter_critical_section(dev); ++ ++ if ( wd->sta.scanMgr.currScanType == ZM_SCAN_MGR_SCAN_NONE ) ++ { ++ goto no_scan; ++ } ++ ++ //zfBssInfoRefresh(dev); ++ zfBssInfoRefresh(dev, 0); ++ wd->sta.bChannelScan = TRUE; ++ wd->sta.bScheduleScan = FALSE; ++ zfTimerCancel(dev, ZM_EVENT_IN_SCAN); ++ zfTimerCancel(dev, ZM_EVENT_TIMEOUT_SCAN); ++ ++ //zm_debug_msg1("start scan = ", KeQueryInterruptTime()); ++ wd->sta.scanFrequency = zfChGetFirstChannel(dev, &wd->sta.bPassiveScan); ++ zmw_leave_critical_section(dev); ++ ++ /* avoid lose receive packet when site survey */ ++ //if ((zfStaIsConnected(dev)) && (!zfPowerSavingMgrIsSleeping(dev))) ++ //{ ++ // zfSendNullData(dev, 1); ++ //} ++// zm_debug_msg0("scan 0"); ++// zfCoreSetFrequencyV2(dev, wd->sta.scanFrequency, zfScanMgrEventSetFreqCompleteCb); ++ ++ #if 1 ++ if (zfStaIsConnected(dev)) ++ {// If doing site survey ! ++ zfHpBeginSiteSurvey(dev, 1); ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssSiteSurveyStatus = 1; ++ zmw_leave_critical_section(dev); ++ } ++ else ++ { ++ zfHpBeginSiteSurvey(dev, 0); ++ zmw_enter_critical_section(dev); ++ wd->sta.ibssSiteSurveyStatus = 0; ++ zmw_leave_critical_section(dev); ++ } ++ #endif ++ ++ zm_debug_msg0("scan 0"); ++ zfCoreSetFrequencyV2(dev, wd->sta.scanFrequency, zfScanMgrEventSetFreqCompleteCb); ++ ++ return; ++ ++no_scan: ++ zmw_leave_critical_section(dev); ++ return; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/ctkip.c +@@ -0,0 +1,598 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : ctkip.c */ ++/* */ ++/* Abstract */ ++/* This module contains Tx and Rx functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++ ++u16_t zgTkipSboxLower[256] = ++ { ++ 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, ++ 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, ++ 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, ++ 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, ++ 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, ++ 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, ++ 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, ++ 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, ++ 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, ++ 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, ++ 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, ++ 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, ++ 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, ++ 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, ++ 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, ++ 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, ++ 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, ++ 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, ++ 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, ++ 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, ++ 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, ++ 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, ++ 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, ++ 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, ++ 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, ++ 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, ++ 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, ++ 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, ++ 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, ++ 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, ++ 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, ++ 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A ++ }; ++ ++ ++u16_t zgTkipSboxUpper[256] = ++ { ++ 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, ++ 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, ++ 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, ++ 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, ++ 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, ++ 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, ++ 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, ++ 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, ++ 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, ++ 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, ++ 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, ++ 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, ++ 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, ++ 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, ++ 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, ++ 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, ++ 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, ++ 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, ++ 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, ++ 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, ++ 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, ++ 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, ++ 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, ++ 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, ++ 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, ++ 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, ++ 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, ++ 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, ++ 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, ++ 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, ++ 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, ++ 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C ++ }; ++ ++u16_t zfrotr1(u16_t a) ++// rotate right by 1 bit. ++{ ++ u16_t b; ++ ++ if (a & 0x01) ++ { ++ b = (a >> 1) | 0x8000; ++ } ++ else ++ { ++ b = (a >> 1) & 0x7fff; ++ } ++ return b; ++} ++ ++/*************************************************************/ ++/* zfTkipSbox() */ ++/* Returns a 16 bit value from a 64K entry table. The Table */ ++/* is synthesized from two 256 entry byte wide tables. */ ++/*************************************************************/ ++u16_t zfTkipSbox(u16_t index) ++{ ++ u16_t low; ++ u16_t high; ++ u16_t left, right; ++ ++ low = (index & 0xFF); ++ high = ((index >> 8) & 0xFF); ++ ++ left = zgTkipSboxLower[low] + (zgTkipSboxUpper[low] << 8 ); ++ right = zgTkipSboxUpper[high] + (zgTkipSboxLower[high] << 8 ); ++ ++ return (left ^ right); ++} ++ ++u8_t zfTkipPhase1KeyMix(u32_t iv32, struct zsTkipSeed* pSeed) ++{ ++ u16_t tsc0; ++ u16_t tsc1; ++ u16_t i, j; ++#if 0 ++ /* Need not proceed this function with the same iv32 */ ++ if ( iv32 == pSeed->iv32 ) ++ { ++ return 1; ++ } ++#endif ++ tsc0 = (u16_t) ((iv32 >> 16) & 0xffff); /* msb */ ++ tsc1 = (u16_t) (iv32 & 0xffff); ++ ++ /* Phase 1, step 1 */ ++ pSeed->ttak[0] = tsc1; ++ pSeed->ttak[1] = tsc0; ++ pSeed->ttak[2] = (u16_t) (pSeed->ta[0] + (pSeed->ta[1] <<8)); ++ pSeed->ttak[3] = (u16_t) (pSeed->ta[2] + (pSeed->ta[3] <<8)); ++ pSeed->ttak[4] = (u16_t) (pSeed->ta[4] + (pSeed->ta[5] <<8)); ++ ++ /* Phase 1, step 2 */ ++ for (i=0; i<8; i++) ++ { ++ j = 2*(i & 1); ++ pSeed->ttak[0] =(pSeed->ttak[0] + zfTkipSbox(pSeed->ttak[4] ++ ^ ZM_BYTE_TO_WORD(pSeed->tk[1+j], pSeed->tk[j]))) ++ & 0xffff; ++ pSeed->ttak[1] =(pSeed->ttak[1] + zfTkipSbox(pSeed->ttak[0] ++ ^ ZM_BYTE_TO_WORD(pSeed->tk[5+j], pSeed->tk[4+j] ))) ++ & 0xffff; ++ pSeed->ttak[2] =(pSeed->ttak[2] + zfTkipSbox(pSeed->ttak[1] ++ ^ ZM_BYTE_TO_WORD(pSeed->tk[9+j], pSeed->tk[8+j] ))) ++ & 0xffff; ++ pSeed->ttak[3] =(pSeed->ttak[3] + zfTkipSbox(pSeed->ttak[2] ++ ^ ZM_BYTE_TO_WORD(pSeed->tk[13+j], pSeed->tk[12+j]))) ++ & 0xffff; ++ pSeed->ttak[4] =(pSeed->ttak[4] + zfTkipSbox(pSeed->ttak[3] ++ ^ ZM_BYTE_TO_WORD(pSeed->tk[1+j], pSeed->tk[j] ))) ++ & 0xffff; ++ pSeed->ttak[4] =(pSeed->ttak[4] + i) & 0xffff; ++ } ++ ++ if ( iv32 == (pSeed->iv32+1) ) ++ { ++ pSeed->iv32tmp = iv32; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++u8_t zfTkipPhase2KeyMix(u16_t iv16, struct zsTkipSeed* pSeed) ++{ ++ u16_t tsc2; ++ ++ tsc2 = iv16; ++ ++ /* Phase 2, Step 1 */ ++ pSeed->ppk[0] = pSeed->ttak[0]; ++ pSeed->ppk[1] = pSeed->ttak[1]; ++ pSeed->ppk[2] = pSeed->ttak[2]; ++ pSeed->ppk[3] = pSeed->ttak[3]; ++ pSeed->ppk[4] = pSeed->ttak[4]; ++ pSeed->ppk[5] = (pSeed->ttak[4] + tsc2) & 0xffff; ++ ++ /* Phase2, Step 2 */ ++ pSeed->ppk[0] = pSeed->ppk[0] ++ + zfTkipSbox(pSeed->ppk[5] ^ ZM_BYTE_TO_WORD(pSeed->tk[1],pSeed->tk[0])); ++ pSeed->ppk[1] = pSeed->ppk[1] ++ + zfTkipSbox(pSeed->ppk[0] ^ ZM_BYTE_TO_WORD(pSeed->tk[3],pSeed->tk[2])); ++ pSeed->ppk[2] = pSeed->ppk[2] ++ + zfTkipSbox(pSeed->ppk[1] ^ ZM_BYTE_TO_WORD(pSeed->tk[5],pSeed->tk[4])); ++ pSeed->ppk[3] = pSeed->ppk[3] ++ + zfTkipSbox(pSeed->ppk[2] ^ ZM_BYTE_TO_WORD(pSeed->tk[7],pSeed->tk[6])); ++ pSeed->ppk[4] = pSeed->ppk[4] ++ + zfTkipSbox(pSeed->ppk[3] ^ ZM_BYTE_TO_WORD(pSeed->tk[9],pSeed->tk[8])); ++ pSeed->ppk[5] = pSeed->ppk[5] ++ + zfTkipSbox(pSeed->ppk[4] ^ ZM_BYTE_TO_WORD(pSeed->tk[11],pSeed->tk[10])); ++ ++ pSeed->ppk[0] = pSeed->ppk[0] ++ + zfrotr1(pSeed->ppk[5] ^ ZM_BYTE_TO_WORD(pSeed->tk[13],pSeed->tk[12])); ++ pSeed->ppk[1] = pSeed->ppk[1] ++ + zfrotr1(pSeed->ppk[0] ^ ZM_BYTE_TO_WORD(pSeed->tk[15],pSeed->tk[14])); ++ pSeed->ppk[2] = pSeed->ppk[2] + zfrotr1(pSeed->ppk[1]); ++ pSeed->ppk[3] = pSeed->ppk[3] + zfrotr1(pSeed->ppk[2]); ++ pSeed->ppk[4] = pSeed->ppk[4] + zfrotr1(pSeed->ppk[3]); ++ pSeed->ppk[5] = pSeed->ppk[5] + zfrotr1(pSeed->ppk[4]); ++ ++ if (iv16 == 0) ++ { ++ if (pSeed->iv16 == 0xffff) ++ { ++ pSeed->iv16tmp=0; ++ return 1; ++ } ++ else ++ return 0; ++ } ++ else if (iv16 == (pSeed->iv16+1)) ++ { ++ pSeed->iv16tmp = iv16; ++ return 1; ++ } ++ else ++ return 0; ++} ++ ++void zfTkipInit(u8_t* key, u8_t* ta, struct zsTkipSeed* pSeed, u8_t* initIv) ++{ ++ u16_t iv16; ++ u32_t iv32; ++ u16_t i; ++ ++ /* clear memory */ ++ zfZeroMemory((u8_t*) pSeed, sizeof(struct zsTkipSeed)); ++ /* set key to seed */ ++ zfMemoryCopy(pSeed->ta, ta, 6); ++ zfMemoryCopy(pSeed->tk, key, 16); ++ ++ iv16 = *initIv++; ++ iv16 += *initIv<<8; ++ initIv++; ++ ++ iv32=0; ++ ++ for(i=0; i<4; i++) // initiv is little endian ++ { ++ iv32 += *initIv<<(i*8); ++ *initIv++; ++ } ++ ++ pSeed->iv32 = iv32+1; // Force Recalculating on Tkip Phase1 ++ zfTkipPhase1KeyMix(iv32, pSeed); ++ ++ pSeed->iv16 = iv16; ++ pSeed->iv32 = iv32; ++} ++ ++u32_t zfGetU32t(u8_t* p) ++{ ++ u32_t res=0; ++ u16_t i; ++ ++ for( i=0; i<4; i++ ) ++ { ++ res |= (*p++) << (8*i); ++ } ++ ++ return res; ++ ++} ++ ++void zfPutU32t(u8_t* p, u32_t value) ++{ ++ u16_t i; ++ ++ for(i=0; i<4; i++) ++ { ++ *p++ = (u8_t) (value & 0xff); ++ value >>= 8; ++ } ++} ++ ++void zfMicClear(struct zsMicVar* pMic) ++{ ++ pMic->left = pMic->k0; ++ pMic->right = pMic->k1; ++ pMic->nBytes = 0; ++ pMic->m = 0; ++} ++ ++void zfMicSetKey(u8_t* key, struct zsMicVar* pMic) ++{ ++ pMic->k0 = zfGetU32t(key); ++ pMic->k1 = zfGetU32t(key+4); ++ zfMicClear(pMic); ++} ++ ++void zfMicAppendByte(u8_t b, struct zsMicVar* pMic) ++{ ++ // Append the byte to our word-sized buffer ++ pMic->m |= b << (8* pMic->nBytes); ++ pMic->nBytes++; ++ ++ // Process the word if it is full. ++ if ( pMic->nBytes >= 4 ) ++ { ++ pMic->left ^= pMic->m; ++ pMic->right ^= ZM_ROL32(pMic->left, 17 ); ++ pMic->left += pMic->right; ++ pMic->right ^= ((pMic->left & 0xff00ff00) >> 8) | ++ ((pMic->left & 0x00ff00ff) << 8); ++ pMic->left += pMic->right; ++ pMic->right ^= ZM_ROL32( pMic->left, 3 ); ++ pMic->left += pMic->right; ++ pMic->right ^= ZM_ROR32( pMic->left, 2 ); ++ pMic->left += pMic->right; ++ // Clear the buffer ++ pMic->m = 0; ++ pMic->nBytes = 0; ++ } ++} ++ ++void zfMicGetMic(u8_t* dst, struct zsMicVar* pMic) ++{ ++ // Append the minimum padding ++ zfMicAppendByte(0x5a, pMic); ++ zfMicAppendByte(0, pMic); ++ zfMicAppendByte(0, pMic); ++ zfMicAppendByte(0, pMic); ++ zfMicAppendByte(0, pMic); ++ ++ // and then zeroes until the length is a multiple of 4 ++ while( pMic->nBytes != 0 ) ++ { ++ zfMicAppendByte(0, pMic); ++ } ++ ++ // The appendByte function has already computed the result. ++ zfPutU32t(dst, pMic->left); ++ zfPutU32t(dst+4, pMic->right); ++ ++ // Reset to the empty message. ++ zfMicClear(pMic); ++ ++} ++ ++u8_t zfMicRxVerify(zdev_t* dev, zbuf_t* buf) ++{ ++ struct zsMicVar* pMicKey; ++ struct zsMicVar MyMicKey; ++ u8_t mic[8]; ++ u8_t da[6]; ++ u8_t sa[6]; ++ u8_t bValue; ++ u16_t i, payloadOffset, tailOffset; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* need not check MIC if pMicKEy is equal to NULL */ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ pMicKey = zfApGetRxMicKey(dev, buf); ++ ++ if ( pMicKey != NULL ) ++ { ++ zfCopyFromRxBuffer(dev, buf, sa, ZM_WLAN_HEADER_A2_OFFSET, 6); ++ zfCopyFromRxBuffer(dev, buf, da, ZM_WLAN_HEADER_A3_OFFSET, 6); ++ } ++ else ++ { ++ return ZM_MIC_SUCCESS; ++ } ++ } ++ else if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ pMicKey = zfStaGetRxMicKey(dev, buf); ++ ++ if ( pMicKey != NULL ) ++ { ++ zfCopyFromRxBuffer(dev, buf, sa, ZM_WLAN_HEADER_A3_OFFSET, 6); ++ zfCopyFromRxBuffer(dev, buf, da, ZM_WLAN_HEADER_A1_OFFSET, 6); ++ } ++ else ++ { ++ return ZM_MIC_SUCCESS; ++ } ++ } ++ else ++ { ++ return ZM_MIC_SUCCESS; ++ } ++ ++ MyMicKey.k0=pMicKey->k0; ++ MyMicKey.k1=pMicKey->k1; ++ pMicKey = &MyMicKey; ++ ++ zfMicClear(pMicKey); ++ tailOffset = zfwBufGetSize(dev, buf); ++ tailOffset -= 8; ++ ++ /* append DA */ ++ for(i=0; i<6; i++) ++ { ++ zfMicAppendByte(da[i], pMicKey); ++ } ++ /* append SA */ ++ for(i=0; i<6; i++) ++ { ++ zfMicAppendByte(sa[i], pMicKey); ++ } ++ ++ /* append for alignment */ ++ if ((zmw_rx_buf_readb(dev, buf, 0) & 0x80) != 0) ++ zfMicAppendByte(zmw_rx_buf_readb(dev, buf,24)&0x7, pMicKey); ++ else ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ ++ /* append payload */ ++ payloadOffset = ZM_SIZE_OF_WLAN_DATA_HEADER + ++ ZM_SIZE_OF_IV + ++ ZM_SIZE_OF_EXT_IV; ++ ++ if ((zmw_rx_buf_readb(dev, buf, 0) & 0x80) != 0) ++ { ++ /* Qos Packet, Plcpheader + 2 */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ /* TODO : Rx Qos element offset in software MIC check */ ++ } ++ else if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ if (wd->sta.wmeConnected != 0) ++ { ++ payloadOffset += 2; ++ } ++ } ++ } ++ ++ for(i=payloadOffset; ippk[5] ^ ZM_BYTE_TO_WORD(Seed->tk[1],Seed->tk[0]))>>1) & 0xff; ++ RC4Key[4] = Seed->ppk[0] & 0xff; ++ RC4Key[5] = Seed->ppk[0] >> 8; ++ RC4Key[6] = Seed->ppk[1] & 0xff; ++ RC4Key[7] = Seed->ppk[1] >> 8; ++ RC4Key[8] = Seed->ppk[2] & 0xff; ++ RC4Key[9] = Seed->ppk[2] >> 8; ++ RC4Key[10] = Seed->ppk[3] & 0xff; ++ RC4Key[11] = Seed->ppk[3] >> 8; ++ RC4Key[12] = Seed->ppk[4] & 0xff; ++ RC4Key[13] = Seed->ppk[4] >> 8; ++ RC4Key[14] = Seed->ppk[5] & 0xff; ++ RC4Key[15] = Seed->ppk[5] >> 8; ++} ++ ++void zfCalTxMic(zdev_t *dev, zbuf_t *buf, u8_t *snap, u16_t snapLen, u16_t offset, u16_t *da, u16_t *sa, u8_t up, u8_t *mic) ++{ ++ struct zsMicVar* pMicKey; ++ u16_t i; ++ u16_t len; ++ u8_t bValue; ++ u8_t qosType; ++ u8_t *pDa = (u8_t *)da; ++ u8_t *pSa = (u8_t *)sa; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* need not check MIC if pMicKEy is equal to NULL */ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ pMicKey = zfApGetTxMicKey(dev, buf, &qosType); ++ ++ if ( pMicKey == NULL ) ++ return; ++ } ++ else if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ pMicKey = zfStaGetTxMicKey(dev, buf); ++ ++ if ( pMicKey == NULL ) ++ { ++ zm_debug_msg0("pMicKey is NULL"); ++ return; ++ } ++ } ++ else ++ { ++ return; ++ } ++ ++ zfMicClear(pMicKey); ++ len = zfwBufGetSize(dev, buf); ++ ++ /* append DA */ ++ for(i = 0; i < 6; i++) ++ { ++ zfMicAppendByte(pDa[i], pMicKey); ++ } ++ ++ /* append SA */ ++ for(i = 0; i < 6; i++) ++ { ++ zfMicAppendByte(pSa[i], pMicKey); ++ } ++ ++ if (up != 0) ++ zfMicAppendByte((up&0x7), pMicKey); ++ else ++ zfMicAppendByte(0, pMicKey); ++ ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ ++ /* For Snap header */ ++ for(i = 0; i < snapLen; i++) ++ { ++ zfMicAppendByte(snap[i], pMicKey); ++ } ++ ++ for(i = offset; i < len; i++) ++ { ++ bValue = zmw_tx_buf_readb(dev, buf, i); ++ zfMicAppendByte(bValue, pMicKey); ++ } ++ ++ zfMicGetMic(mic, pMicKey); ++} ++ ++void zfTKIPEncrypt(zdev_t *dev, zbuf_t *buf, u8_t *snap, u16_t snapLen, u16_t offset, u8_t keyLen, u8_t* key, u32_t* icv) ++{ ++ u8_t iv[3]; ++ ++ iv[0] = key[0]; ++ iv[1] = key[1]; ++ iv[2] = key[2]; ++ ++ keyLen -= 3; ++ ++ zfWEPEncrypt(dev, buf, snap, snapLen, offset, keyLen, &key[3], iv); ++} ++ ++u16_t zfTKIPDecrypt(zdev_t *dev, zbuf_t *buf, u16_t offset, u8_t keyLen, u8_t* key) ++{ ++ u16_t ret = ZM_ICV_SUCCESS; ++ u8_t iv[3]; ++ ++ iv[0] = key[0]; ++ iv[1] = key[1]; ++ iv[2] = key[2]; ++ ++ keyLen -= 3; ++ ++ ret = zfWEPDecrypt(dev, buf, offset, keyLen, &key[3], iv); ++ ++ return ret; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/ctxrx.c +@@ -0,0 +1,4096 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : htr.c */ ++/* */ ++/* Abstract */ ++/* This module contains Tx and Rx functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++ ++u16_t zfWlanRxValidate(zdev_t* dev, zbuf_t* buf); ++u16_t zfWlanRxFilter(zdev_t* dev, zbuf_t* buf); ++ ++ ++ ++const u8_t zgSnapBridgeTunnel[6] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8 }; ++const u8_t zgSnap8021h[6] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00 }; ++/* Table for converting IP DSCP P2-P0 bits to 802.11e Access Category */ ++const u8_t zcUpToAc[8] = {0, 1, 1, 0, 2, 2, 3, 3}; //WMM default ++//const u8_t zcUpToAc[8] = {0, 1, 1, 0, 0, 0, 0, 0}; //For 2 TxQ ++//const u8_t zcUpToAc[8] = {0, 0, 0, 0, 0, 0, 0, 0}; //For single TxQ ++const u8_t zcMaxspToPktNum[4] = {8, 2, 4, 6}; ++ ++u8_t zfGetEncryModeFromRxStatus(struct zsAdditionInfo* addInfo) ++{ ++ u8_t securityByte; ++ u8_t encryMode; ++ ++ securityByte = (addInfo->Tail.Data.SAIndex & 0xc0) >> 4; /* byte4 */ ++ securityByte |= (addInfo->Tail.Data.DAIndex & 0xc0) >> 6; /* byte5 */ ++ ++ switch( securityByte ) ++ { ++ case ZM_NO_WEP: ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++#endif //ZM_ENABLE_CENC ++ case ZM_TKIP: ++ case ZM_AES: ++ ++ encryMode = securityByte; ++ break; ++ ++ default: ++ ++ if ( (securityByte & 0xf8) == 0x08 ) ++ { ++ // decrypted by software ++ } ++ ++ encryMode = ZM_NO_WEP; ++ break; ++ } ++ ++ return encryMode; ++} ++ ++void zfGetRxIvIcvLength(zdev_t* dev, zbuf_t* buf, u8_t vap, u16_t* pIvLen, ++ u16_t* pIcvLen, struct zsAdditionInfo* addInfo) ++{ ++ u16_t wdsPort; ++ u8_t encryMode; ++ ++ zmw_get_wlan_dev(dev); ++ ++ *pIvLen = 0; ++ *pIcvLen = 0; ++ ++ encryMode = zfGetEncryModeFromRxStatus(addInfo); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ if (vap < ZM_MAX_AP_SUPPORT) ++ { ++ if (( wd->ap.encryMode[vap] == ZM_WEP64 ) || ++ ( wd->ap.encryMode[vap] == ZM_WEP128 ) || ++ ( wd->ap.encryMode[vap] == ZM_WEP256 )) ++ { ++ *pIvLen = 4; ++ *pIcvLen = 4; ++ } ++ else ++ { ++ u16_t id; ++ u16_t addr[3]; ++ ++ addr[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); ++ addr[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2); ++ addr[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4); ++ ++ /* Find STA's information */ ++ if ((id = zfApFindSta(dev, addr)) != 0xffff) ++ { ++ if (wd->ap.staTable[id].encryMode == ZM_TKIP) ++ { ++ *pIvLen = 8; ++ *pIcvLen = 4; ++ } ++ else if (wd->ap.staTable[id].encryMode == ZM_AES) ++ { ++ *pIvLen = 8; ++ *pIcvLen = 8; // AES MIC ++ //*pIcvLen = 0; ++ } ++#ifdef ZM_ENABLE_CENC ++ else if (wd->ap.staTable[id].encryMode == ZM_CENC) ++ { ++ *pIvLen = 18; ++ *pIcvLen= 16; ++ } ++#endif //ZM_ENABLE_CENC ++ } ++ } ++ /* WDS port checking */ ++ if ((wdsPort = vap - 0x20) >= ZM_MAX_WDS_SUPPORT) ++ { ++ wdsPort = 0; ++ } ++ ++ switch (wd->ap.wds.encryMode[wdsPort]) ++ { ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++ *pIvLen = 4; ++ *pIcvLen = 4; ++ break; ++ case ZM_TKIP: ++ *pIvLen = 8; ++ *pIcvLen = 4; ++ break; ++ case ZM_AES: ++ *pIvLen = 8; ++ *pIcvLen = 0; ++ break; ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++ *pIvLen = 18; ++ *pIcvLen = 16; ++ break; ++#endif //ZM_ENABLE_CENC ++ }/* end of switch */ ++ } ++ } ++ else if ( wd->wlanMode == ZM_MODE_PSEUDO) ++ { ++ /* test: 6518 for QA auto test */ ++ switch (encryMode) ++ { ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++ *pIvLen = 4; ++ *pIcvLen = 4; ++ break; ++ case ZM_TKIP: ++ *pIvLen = 8; ++ *pIcvLen = 4; ++ break; ++ case ZM_AES: ++ *pIvLen = 8; ++ *pIcvLen = 0; ++ break; ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++ *pIvLen = 18; ++ *pIcvLen = 16; ++#endif //ZM_ENABLE_CENC ++ }/* end of switch */ ++ } ++ else ++ { ++ if ( (encryMode == ZM_WEP64)|| ++ (encryMode == ZM_WEP128)|| ++ (encryMode == ZM_WEP256) ) ++ { ++ *pIvLen = 4; ++ *pIcvLen = 4; ++ } ++ else if ( encryMode == ZM_TKIP ) ++ { ++ *pIvLen = 8; ++ *pIcvLen = 4; ++ } ++ else if ( encryMode == ZM_AES ) ++ { ++ *pIvLen = 8; ++ *pIcvLen = 8; // AES MIC ++ } ++#ifdef ZM_ENABLE_CENC ++ else if ( encryMode == ZM_CENC) ++ { ++ *pIvLen = 18; ++ *pIcvLen= 16; ++ } ++#endif //ZM_ENABLE_CENC ++ } ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAgingDefragList */ ++/* Force flushing whole defrag list or aging the buffer */ ++/* in the defrag list. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* flushFlag : 1=>flushing, 0=>Aging */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++void zfAgingDefragList(zdev_t* dev, u16_t flushFlag) ++{ ++ u16_t i, j; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ for(i=0; idefragTable.defragEntry[i].fragCount != 0 ) ++ { ++ if (((wd->tick - wd->defragTable.defragEntry[i].tick) > ++ (ZM_DEFRAG_AGING_TIME_SEC * ZM_TICK_PER_SECOND)) ++ || (flushFlag != 0)) ++ { ++ zm_msg1_rx(ZM_LV_2, "Aging defrag list :", i); ++ /* Free the buffers in the defrag list */ ++ for (j=0; jdefragTable.defragEntry[i].fragCount; j++) ++ { ++ zfwBufFree(dev, wd->defragTable.defragEntry[i].fragment[j], 0); ++ } ++ } ++ } ++ wd->defragTable.defragEntry[i].fragCount = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAddFirstFragToDefragList */ ++/* Add first fragment to defragment list, the first empty entry */ ++/* will be selected. If the list is full, sequentially select */ ++/* one entry for replacement. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : first fragment buffer */ ++/* addr : address of first fragment buffer */ ++/* seqNum : sequence of first fragment buffer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++void zfAddFirstFragToDefragList(zdev_t* dev, zbuf_t* buf, u8_t* addr, u16_t seqNum) ++{ ++ u16_t i, j; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ /* Find an empty one in defrag list */ ++ for(i=0; idefragTable.defragEntry[i].fragCount == 0 ) ++ { ++ break; ++ } ++ } ++ ++ /* If full, sequentially replace existing one */ ++ if (i == ZM_MAX_DEFRAG_ENTRIES) ++ { ++ i = wd->defragTable.replaceNum++ & (ZM_MAX_DEFRAG_ENTRIES-1); ++ /* Free the buffers in the defrag list to be replaced */ ++ for (j=0; jdefragTable.defragEntry[i].fragCount; j++) ++ { ++ zfwBufFree(dev, wd->defragTable.defragEntry[i].fragment[j], 0); ++ } ++ } ++ ++ wd->defragTable.defragEntry[i].fragCount = 1; ++ wd->defragTable.defragEntry[i].fragment[0] = buf; ++ wd->defragTable.defragEntry[i].seqNum = seqNum; ++ wd->defragTable.defragEntry[i].tick = wd->tick; ++ ++ for (j=0; j<6; j++) ++ { ++ wd->defragTable.defragEntry[i].addr[j] = addr[j]; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfAddFragToDefragList */ ++/* Add middle or last fragment to defragment list. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : first fragment buffer */ ++/* addr : address of fragment buffer */ ++/* seqNum : sequence fragment buffer */ ++/* fragNum : fragment number of fragment buffer */ ++/* moreFrag : more frag bit of fragment buffer */ ++/* addInfo : addition info of fragment buffer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++zbuf_t* zfAddFragToDefragList(zdev_t* dev, zbuf_t* buf, u8_t* addr, ++ u16_t seqNum, u8_t fragNum, u8_t moreFrag, ++ struct zsAdditionInfo* addInfo) ++{ ++ u16_t i, j, k; ++ zbuf_t* returnBuf = NULL; ++ u16_t defragDone = 0; ++ u16_t lenErr = 0; ++ u16_t startAddr, fragHead, frameLen, ivLen, icvLen; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ /* Find frag in the defrag list */ ++ for(i=0; idefragTable.defragEntry[i].fragCount != 0 ) ++ { ++ /* Compare address */ ++ for (j=0; j<6; j++) ++ { ++ if (addr[j] != wd->defragTable.defragEntry[i].addr[j]) ++ { ++ break; ++ } ++ } ++ if (j == 6) ++ { ++ /* Compare sequence and fragment number */ ++ if (seqNum == wd->defragTable.defragEntry[i].seqNum) ++ { ++ if ((fragNum == wd->defragTable.defragEntry[i].fragCount) ++ && (fragNum < 8)) ++ { ++ /* Add frag frame to defrag list */ ++ wd->defragTable.defragEntry[i].fragment[fragNum] = buf; ++ wd->defragTable.defragEntry[i].fragCount++; ++ defragDone = 1; ++ ++ if (moreFrag == 0) ++ { ++ /* merge all fragment if more data bit is cleared */ ++ returnBuf = wd->defragTable.defragEntry[i].fragment[0]; ++ startAddr = zfwBufGetSize(dev, returnBuf); ++ /* skip WLAN header 24(Data) or 26(QoS Data) */ ++ fragHead = 24 + ((zmw_rx_buf_readh(dev, returnBuf, 0) & 0x80) >> 6); ++ zfGetRxIvIcvLength(dev, returnBuf, 0, &ivLen, &icvLen, addInfo); ++ fragHead += ivLen; /* skip IV */ ++ for(k=1; kdefragTable.defragEntry[i].fragCount; k++) ++ { ++ frameLen = zfwBufGetSize(dev, ++ wd->defragTable.defragEntry[i].fragment[k]); ++ if ((startAddr+frameLen-fragHead) < 1560) ++ { ++ zfRxBufferCopy(dev, returnBuf, wd->defragTable.defragEntry[i].fragment[k], ++ startAddr, fragHead, frameLen-fragHead); ++ startAddr += (frameLen-fragHead); ++ } ++ else ++ { ++ lenErr = 1; ++ } ++ zfwBufFree(dev, wd->defragTable.defragEntry[i].fragment[k], 0); ++ } ++ ++ wd->defragTable.defragEntry[i].fragCount = 0; ++ zfwBufSetSize(dev, returnBuf, startAddr); ++ } ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (lenErr == 1) ++ { ++ zfwBufFree(dev, returnBuf, 0); ++ return NULL; ++ } ++ if (defragDone == 0) ++ { ++ zfwBufFree(dev, buf, 0); ++ return NULL; ++ } ++ ++ return returnBuf; ++} ++ ++ ++/* return value = NULL => save or free this frame */ ++zbuf_t* zfDefragment(zdev_t* dev, zbuf_t* buf, u8_t* pbIsDefrag, ++ struct zsAdditionInfo* addInfo) ++{ ++ u8_t fragNum; ++ u16_t seqNum; ++ u8_t moreFragBit; ++ u8_t addr[6]; ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ *pbIsDefrag = FALSE; ++ seqNum = zmw_buf_readh(dev, buf, 22); ++ fragNum = (u8_t)(seqNum & 0xf); ++ moreFragBit = (zmw_buf_readb(dev, buf, 1) & ZM_BIT_2) >> 2; ++ ++ if ((fragNum == 0) && (moreFragBit == 0)) ++ { ++ /* Not part of a fragmentation */ ++ ++ return buf; ++ } ++ else ++ { ++ wd->commTally.swRxFragmentCount++; ++ seqNum = seqNum >> 4; ++ for (i=0; i<6; i++) ++ { ++ addr[i] = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+i); ++ } ++ ++ if (fragNum == 0) ++ { ++ /* more frag = 1 */ ++ /* First part of a fragmentation */ ++ zm_msg1_rx(ZM_LV_2, "First Frag, seq=", seqNum); ++ zfAddFirstFragToDefragList(dev, buf, addr, seqNum); ++ buf = NULL; ++ } ++ else ++ { ++ /* Middle or last part of a fragmentation */ ++ zm_msg1_rx(ZM_LV_2, "Frag seq=", seqNum); ++ zm_msg1_rx(ZM_LV_2, "Frag moreFragBit=", moreFragBit); ++ buf = zfAddFragToDefragList(dev, buf, addr, seqNum, fragNum, moreFragBit, addInfo); ++ if (buf != NULL) ++ { ++ *pbIsDefrag = TRUE; ++ } ++ } ++ } ++ ++ return buf; ++} ++ ++ ++#if ZM_PROTOCOL_RESPONSE_SIMULATION ++u16_t zfSwap(u16_t num) ++{ ++ return ((num >> 8) + ((num & 0xff) << 8)); ++} ++ ++ ++void zfProtRspSim(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t ethType; ++ u16_t arpOp; ++ u16_t prot; ++ u16_t temp; ++ u16_t i; ++ u16_t dip[2]; ++ u16_t dstPort; ++ u16_t srcPort; ++ ++ ethType = zmw_rx_buf_readh(dev, buf, 12); ++ zm_msg2_rx(ZM_LV_2, "ethType=", ethType); ++ ++ /* ARP */ ++ if (ethType == 0x0608) ++ { ++ arpOp = zmw_rx_buf_readh(dev, buf, 20); ++ dip[0] = zmw_rx_buf_readh(dev, buf, 38); ++ dip[1] = zmw_rx_buf_readh(dev, buf, 40); ++ zm_msg2_rx(ZM_LV_2, "arpOp=", arpOp); ++ zm_msg2_rx(ZM_LV_2, "ip0=", dip[0]); ++ zm_msg2_rx(ZM_LV_2, "ip1=", dip[1]); ++ ++ //ARP request to 192.168.1.15 ++ if ((arpOp == 0x0100) && (dip[0] == 0xa8c0) && (dip[1] == 0x0f01)); ++ { ++ zm_msg0_rx(ZM_LV_2, "ARP"); ++ /* ARP response */ ++ zmw_rx_buf_writeh(dev, buf, 20, 0x0200); ++ ++ /* dst hardware address */ ++ ++ /* src hardware address */ ++ //zmw_rx_buf_writeh(dev, buf, 6, 0xa000); ++ //zmw_rx_buf_writeh(dev, buf, 8, 0x0000); ++ //zmw_rx_buf_writeh(dev, buf, 10, 0x0000); ++ ++ /* dst ip address */ ++ for (i=0; i<5; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 22+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, 32+(i*2), temp); ++ } ++ ++ /* src hardware address */ ++ zmw_rx_buf_writeh(dev, buf, 22, 0xa000); ++ zmw_rx_buf_writeh(dev, buf, 24, 0x0000); ++ zmw_rx_buf_writeh(dev, buf, 26, 0x0000); ++ ++ /* src ip address */ ++ zmw_rx_buf_writeh(dev, buf, 28, 0xa8c0); ++ zmw_rx_buf_writeh(dev, buf, 30, 0x0f01); ++ } ++ } ++ /* ICMP */ ++ else if (ethType == 0x0008) ++ { ++ zm_msg0_rx(ZM_LV_2, "IP"); ++ prot = zmw_rx_buf_readb(dev, buf, 23); ++ dip[0] = zmw_rx_buf_readh(dev, buf, 30); ++ dip[1] = zmw_rx_buf_readh(dev, buf, 32); ++ zm_msg2_rx(ZM_LV_2, "prot=", prot); ++ zm_msg2_rx(ZM_LV_2, "ip0=", dip[0]); ++ zm_msg2_rx(ZM_LV_2, "ip1=", dip[1]); ++ ++ /* PING request to 192.168.1.15 */ ++ if ((prot == 0x1) && (dip[0] == 0xa8c0) && (dip[1] == 0x0f01)) ++ { ++ zm_msg0_rx(ZM_LV_2, "ICMP"); ++ /* change dst */ ++ for (i=0; i<3; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 6+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, i*2, temp); ++ } ++ /* change src */ ++ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); ++ zmw_rx_buf_writeh(dev, buf, 8, 0x0000); ++ zmw_rx_buf_writeh(dev, buf, 10, 0x0000); ++ ++ /* exchange src ip and dst ip */ ++ for (i=0; i<2; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 26+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, 30+(i*2), temp); ++ } ++ zmw_rx_buf_writeh(dev, buf, 26, 0xa8c0); ++ zmw_rx_buf_writeh(dev, buf, 28, 0x0f01); ++ ++ /* change icmp type to echo reply */ ++ zmw_rx_buf_writeb(dev, buf, 34, 0x0); ++ ++ /* update icmp checksum */ ++ temp = zmw_rx_buf_readh(dev, buf, 36); ++ temp += 8; ++ zmw_rx_buf_writeh(dev, buf, 36, temp); ++ } ++ else if (prot == 0x6) ++ { ++ zm_msg0_rx(ZM_LV_2, "TCP"); ++ srcPort = zmw_rx_buf_readh(dev, buf, 34); ++ dstPort = zmw_rx_buf_readh(dev, buf, 36); ++ zm_msg2_rx(ZM_LV_2, "Src Port=", srcPort); ++ zm_msg2_rx(ZM_LV_2, "Dst Port=", dstPort); ++ if ((dstPort == 0x1500) || (srcPort == 0x1500)) ++ { ++ zm_msg0_rx(ZM_LV_2, "FTP"); ++ ++ /* change dst */ ++ for (i=0; i<3; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 6+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, i*2, temp); ++ } ++ /* change src */ ++ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); ++ zmw_rx_buf_writeh(dev, buf, 8, 0x0000); ++ zmw_rx_buf_writeh(dev, buf, 10, 0x0000); ++ ++ /* exchange src ip and dst ip */ ++ for (i=0; i<2; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 26+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, 30+(i*2), temp); ++ } ++ zmw_rx_buf_writeh(dev, buf, 26, 0xa8c0); ++ zmw_rx_buf_writeh(dev, buf, 28, 0x0f01); ++#if 0 ++ /* Patch src port */ ++ temp = zmw_rx_buf_readh(dev, buf, 34); ++ temp = zfSwap(zfSwap(temp) + 1); ++ zmw_rx_buf_writeh(dev, buf, 34, temp); ++ temp = zmw_rx_buf_readh(dev, buf, 38); ++ temp = zfSwap(zfSwap(temp) + 1); ++ zmw_rx_buf_writeh(dev, buf, 38, temp); ++ ++ /* Patch checksum */ ++ temp = zmw_rx_buf_readh(dev, buf, 50); ++ temp = zfSwap(temp); ++ temp = ~temp; ++ temp += 2; ++ temp = ~temp; ++ temp = zfSwap(temp); ++ zmw_rx_buf_writeh(dev, buf, 50, temp); ++#endif ++ } ++ ++ } ++ else if (prot == 0x11) ++ { ++ /* change dst */ ++ for (i=0; i<3; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 6+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, i*2, temp); ++ } ++ /* change src */ ++ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); ++ zmw_rx_buf_writeh(dev, buf, 8, 0x0000); ++ zmw_rx_buf_writeh(dev, buf, 10, 0x0000); ++ ++ zm_msg0_rx(ZM_LV_2, "UDP"); ++ srcPort = zmw_rx_buf_readh(dev, buf, 34); ++ dstPort = zmw_rx_buf_readh(dev, buf, 36); ++ zm_msg2_rx(ZM_LV_2, "Src Port=", srcPort); ++ zm_msg2_rx(ZM_LV_2, "Dst Port=", dstPort); ++ ++ /* exchange src ip and dst ip */ ++ for (i=0; i<2; i++) ++ { ++ temp = zmw_rx_buf_readh(dev, buf, 26+(i*2)); ++ zmw_rx_buf_writeh(dev, buf, 30+(i*2), temp); ++ } ++ zmw_rx_buf_writeh(dev, buf, 26, 0xa8c0); ++ zmw_rx_buf_writeh(dev, buf, 28, 0x0f01); ++ ++ /* exchange port */ ++ zmw_rx_buf_writeh(dev, buf, 34, srcPort+1); ++ zmw_rx_buf_writeh(dev, buf, 36, dstPort); ++ ++ /* checksum = 0 */ ++ zmw_rx_buf_writeh(dev, buf, 40, 0); ++ } ++ ++ } ++ else if (ethType == 0x0060) /* =>0x0060 is port */ ++ { ++ /* change src for Evl tool loop back receive */ ++ zmw_rx_buf_writeh(dev, buf, 6, 0xa000); ++ zmw_rx_buf_writeh(dev, buf, 8, 0x0000); ++ zmw_rx_buf_writeh(dev, buf, 10, 0x0000); ++ } ++ ++} ++#endif ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiTxSendEth */ ++/* Called to native 802.11 management frames */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer pointer */ ++/* port : WLAN port, 0=>standard, 0x1-0x7=>VAP, 0x20-0x25=>WDS */ ++/* */ ++/* OUTPUTS */ ++/* error code */ ++/* */ ++/* AUTHOR */ ++/* Ray ZyDAS Technology Corporation 2005.5 */ ++/* */ ++/************************************************************************/ ++u16_t zfiTxSend80211Mgmt(zdev_t* dev, zbuf_t* buf, u16_t port) ++{ ++ u16_t err; ++ //u16_t addrTblSize = 0; ++ //struct zsAddrTbl addrTbl; ++ u16_t hlen; ++ u16_t header[(24+25+1)/2]; ++ int i; ++ ++ for(i=0;i<12;i++) ++ { ++ header[i] = zmw_buf_readh(dev, buf, i); ++ } ++ hlen = 24; ++ ++ zfwBufRemoveHead(dev, buf, 24); ++ ++ if ((err = zfHpSend(dev, header, hlen, NULL, 0, NULL, 0, buf, 0, ++ ZM_EXTERNAL_ALLOC_BUF, 0, 0)) != ZM_SUCCESS) ++ { ++ goto zlError; ++ } ++ ++ return 0; ++ ++zlError: ++ ++ zfwBufFree(dev, buf, 0); ++ return 0; ++} ++ ++u8_t zfiIsTxQueueFull(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if ((((wd->vtxqHead[0] + 1) & ZM_VTXQ_SIZE_MASK) != wd->vtxqTail[0]) ) ++ { ++ zmw_leave_critical_section(dev); ++ return 0; ++ } ++ else ++ { ++ zmw_leave_critical_section(dev); ++ return 1; ++ } ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiTxSendEth */ ++/* Called to transmit Ethernet frame from upper layer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer pointer */ ++/* port : WLAN port, 0=>standard, 0x1-0x7=>VAP, 0x20-0x25=>WDS */ ++/* */ ++/* OUTPUTS */ ++/* error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.5 */ ++/* */ ++/************************************************************************/ ++u16_t zfiTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port) ++{ ++ u16_t err, ret; ++ ++ zmw_get_wlan_dev(dev); ++ ++ ZM_PERFORMANCE_TX_MSDU(dev, wd->tick); ++ zm_msg1_tx(ZM_LV_2, "zfiTxSendEth(), port=", port); ++ /* Return error if port is disabled */ ++ if ((err = zfTxPortControl(dev, buf, port)) == ZM_PORT_DISABLED) ++ { ++ err = ZM_ERR_TX_PORT_DISABLED; ++ goto zlError; ++ } ++ ++#if 1 ++ if ((wd->wlanMode == ZM_MODE_AP) && (port < 0x20)) ++ { ++ /* AP : Buffer frame for power saving STA */ ++ if ((ret = zfApBufferPsFrame(dev, buf, port)) == 1) ++ { ++ return ZM_SUCCESS; ++ } ++ } ++ else ++#endif ++ if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ if ( zfPowerSavingMgrIsSleeping(dev) ) ++ { ++ /*check ZM_ENABLE_POWER_SAVE flag*/ ++ zfPowerSavingMgrWakeup(dev); ++ } ++ } ++#ifdef ZM_ENABLE_IBSS_PS ++ /* IBSS power-saving mode */ ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ if ( zfStaIbssPSQueueData(dev, buf) ) ++ { ++ return ZM_SUCCESS; ++ } ++ } ++#endif ++ ++#if 1 ++ //if ( wd->bQoSEnable ) ++ if (1) ++ { ++ /* Put to VTXQ[ac] */ ++ ret = zfPutVtxq(dev, buf); ++ ++ /* Push VTXQ[ac] */ ++ zfPushVtxq(dev); ++ } ++ else ++ { ++ ret = zfTxSendEth(dev, buf, port, ZM_EXTERNAL_ALLOC_BUF, 0); ++ } ++ ++ return ret; ++#else ++ return zfTxSendEth(dev, buf, port, ZM_EXTERNAL_ALLOC_BUF, 0); ++#endif ++ ++zlError: ++ zm_msg2_tx(ZM_LV_1, "Tx Comp err=", err); ++ ++ zfwBufFree(dev, buf, err); ++ return err; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfTxSendEth */ ++/* Called to transmit Ethernet frame from upper layer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : buffer pointer */ ++/* port : WLAN port, 0=>standard, 0x10-0x17=>VAP, 0x20-0x25=>WDS */ ++/* */ ++/* OUTPUTS */ ++/* error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.5 */ ++/* */ ++/************************************************************************/ ++u16_t zfTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port, u16_t bufType, u16_t flag) ++{ ++ u16_t err; ++ //u16_t addrTblSize; ++ //struct zsAddrTbl addrTbl; ++ u16_t removeLen; ++ u16_t header[(8+30+2+18)/2]; /* ctr+(4+a1+a2+a3+2+a4)+qos+iv */ ++ u16_t headerLen; ++ u16_t mic[8/2]; ++ u16_t micLen; ++ u16_t snap[8/2]; ++ u16_t snapLen; ++ u16_t fragLen; ++ u16_t frameLen; ++ u16_t fragNum; ++ struct zsFrag frag; ++ u16_t i, j, id; ++ u16_t offset; ++ u16_t da[3]; ++ u16_t sa[3]; ++ u8_t up; ++ u8_t qosType, keyIdx = 0; ++ u16_t fragOff; ++ u16_t newFlag; ++ struct zsMicVar* pMicKey; ++ u8_t tkipFrameOffset = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ newFlag = flag & 0xff00; ++ flag = flag & 0xff; ++ ++ zm_msg1_tx(ZM_LV_2, "zfTxSendEth(), port=", port); ++ ++ /* Get IP TOS for QoS AC and IP frag offset */ ++ zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); ++ ++ //EOSP bit ++ if (newFlag & 0x100) ++ { ++ up |= 0x10; ++ } ++ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 16); ++ da[1] = zmw_tx_buf_readh(dev, buf, 18); ++ da[2] = zmw_tx_buf_readh(dev, buf, 20); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 10); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 12); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 14); ++ } ++ else if ( wd->wlanMode == ZM_MODE_IBSS ) ++ { ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 4); ++ da[1] = zmw_tx_buf_readh(dev, buf, 6); ++ da[2] = zmw_tx_buf_readh(dev, buf, 8); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 10); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 12); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 14); ++ } ++ else if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 4); ++ da[1] = zmw_tx_buf_readh(dev, buf, 6); ++ da[2] = zmw_tx_buf_readh(dev, buf, 8); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 16); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 18); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 20); ++ } ++ else ++ { ++ // ++ } ++#else ++ /* DA */ ++ da[0] = zmw_tx_buf_readh(dev, buf, 0); ++ da[1] = zmw_tx_buf_readh(dev, buf, 2); ++ da[2] = zmw_tx_buf_readh(dev, buf, 4); ++ /* SA */ ++ sa[0] = zmw_tx_buf_readh(dev, buf, 6); ++ sa[1] = zmw_tx_buf_readh(dev, buf, 8); ++ sa[2] = zmw_tx_buf_readh(dev, buf, 10); ++#endif ++ //Decide Key Index in ATOM, No meaning in OTUS--CWYang(m) ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ keyIdx = wd->ap.bcHalKeyIdx[port]; ++ id = zfApFindSta(dev, da); ++ if (id != 0xffff) ++ { ++ switch (wd->ap.staTable[id].encryMode) ++ { ++ case ZM_AES: ++ case ZM_TKIP: ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++#endif //ZM_ENABLE_CENC ++ keyIdx = wd->ap.staTable[id].keyIdx; ++ break; ++ } ++ } ++ } ++ else ++ { ++ switch (wd->sta.encryMode) ++ { ++ case ZM_WEP64: ++ case ZM_WEP128: ++ case ZM_WEP256: ++ keyIdx = wd->sta.keyId; ++ break; ++ case ZM_AES: ++ case ZM_TKIP: ++ if ((da[0] & 0x1)) ++ keyIdx = 5; ++ else ++ keyIdx = 4; ++ break; ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++ keyIdx = wd->sta.cencKeyId; ++ break; ++#endif //ZM_ENABLE_CENC ++ } ++ } ++ ++ /* Create SNAP */ ++ removeLen = zfTxGenWlanSnap(dev, buf, snap, &snapLen); ++ //zm_msg1_tx(ZM_LV_0, "fragOff=", fragOff); ++ ++ ++/* ********************************************************************************************** */ ++/* Add 20071025 Mxzeng */ ++/* ********************************************************************************************** */ ++/* ---------------------------------------------------------------------------------------------- */ ++/* Ethernet : frameLen = zfwBufGetSize(dev, buf); */ ++/* ---+--6--+--6--+--2--+-----20-----+-------------------------+------ Variable -------+--------- */ ++/* | DA | SA | Type| IP Header | TCP(20) UDP(12) ICMP(8) | Application Payload L | */ ++/* ---+-----+-----+-----+------------+-------------------------+-----------------------+--------- */ ++/* MSDU = 6 + 6 + 2 + ( Network Layer header ) + ( Transport Layer header ) + L */ ++/* */ ++/* MSDU - DA - SA : frameLen -= removeLen; */ ++/* ---+--2--+-----20-----+-------------------------+------ Variable -------+--------------------- */ ++/* | Type| IP Header | TCP(20) UDP(12) ICMP(8) | Application Payload L | */ ++/* ---+-----+------------+-------------------------+-----------------------+--------------------- */ ++/* */ ++/* MPDU : frameLen + mpduLengthOffset ; */ ++/* -+---2---+----2---+-6-+-6-+--6--+---2----+--1--+--1-+---1---+-------3------+-frameLen-+---4--+- */ ++/* | frame |duration| DA|SA |BSSID|sequence|SNAP |SNAP|Control| RFC 1042 | | FCS | */ ++/* |Control| | | | | number |DSAP |SSAP| | encapsulation| | | */ ++/* -+-------+--------+---+---+-----+--------+-----+----+-------+--------------+----------+------+- */ ++/* ----------------------------------------------------------------------------------------------- */ ++ ++ if ( wd->sta.encryMode == ZM_TKIP ) ++ tkipFrameOffset = 8; ++ ++ fragLen = wd->fragThreshold + tkipFrameOffset; // Fragmentation threshold for MPDU Lengths ++ frameLen = zfwBufGetSize(dev, buf); // MSDU Lengths ++ frameLen -= removeLen; // MSDU Lengths - DA - SA ++ ++ /* #1st create MIC Length manually */ ++ micLen = 0; ++ ++ /* Access Category */ ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ zfApGetStaQosType(dev, da, &qosType); ++ if (qosType == 0) ++ { ++ up = 0; ++ } ++ } ++ else if (wd->wlanMode == ZM_MODE_INFRASTRUCTURE) ++ { ++ if (wd->sta.wmeConnected == 0) ++ { ++ up = 0; ++ } ++ } ++ else ++ { ++ /* TODO : STA QoS control field */ ++ up = 0; ++ } ++ ++ /* #2nd Assign sequence number */ ++ zmw_enter_critical_section(dev); ++ frag.seq[0] = ((wd->seq[zcUpToAc[up&0x7]]++) << 4); ++ zmw_leave_critical_section(dev); ++ ++ /* #3rd Pass the total payload to generate MPDU length ! */ ++ frag.buf[0] = buf; ++ frag.bufType[0] = bufType; ++ frag.flag[0] = (u8_t)flag; ++ fragNum = 1; ++ ++ headerLen = zfTxGenWlanHeader(dev, frag.buf[0], header, frag.seq[0], ++ frag.flag[0], snapLen+micLen, removeLen, port, da, sa, ++ up, &micLen, snap, snapLen, NULL); ++ ++ //zm_debug_msg1("#1 headerLen = ", headerLen); ++ ++ /* #4th Check the HeaderLen and determine whether the MPDU Lengths bigger than Fragmentation threshold */ ++ /* If MPDU Lengths large than fragmentation threshold --> headerLen = 0 */ ++ if( headerLen != 0 ) ++ { ++ zf80211FrameSend(dev, frag.buf[0], header, snapLen, da, sa, up, ++ headerLen, snap, mic, micLen, removeLen, frag.bufType[0], ++ zcUpToAc[up&0x7], keyIdx); ++ } ++ else //if( headerLen == 0 ) // Need to be fragmented ++ { ++ u16_t mpduLengthOffset; ++ u16_t pseudSnapLen = 0; ++ ++ mpduLengthOffset = header[0] - frameLen; // For fragmentation threshold ! ++ ++ micLen = zfTxGenWlanTail(dev, buf, snap, snapLen, mic); // Get snap and mic information ++ ++ fragLen = fragLen - mpduLengthOffset; ++ ++ //zm_debug_msg1("#2 frameLen = ", frameLen); ++ //zm_debug_msg1("#3 fragThreshold = ", fragLen); ++ ++ /* fragmentation */ ++ if (frameLen >= fragLen) ++ { ++ //copy fragLen to frag ++ i = 0; ++ while( frameLen > 0 ) ++ { ++ if ((frag.buf[i] = zfwBufAllocate(dev, fragLen+32)) != NULL) ++ { ++ frag.bufType[i] = ZM_INTERNAL_ALLOC_BUF; ++ frag.seq[i] = frag.seq[0] + i; ++ offset = removeLen + i*fragLen; ++ ++ /* Consider the offset if we consider snap length to the other fragmented frame */ ++ if ( i >= 1 ) ++ offset = offset + pseudSnapLen*(i-1); ++ ++ if (frameLen > fragLen + pseudSnapLen) ++ { ++ frag.flag[i] = flag | 0x4; /* More data */ ++ /* First fragment */ ++ if (i == 0) ++ { ++ /* Add SNAP */ ++ for (j=0; j>1)]); ++ } ++ zfTxBufferCopy(dev, frag.buf[i], buf, snapLen, offset, fragLen); ++ zfwBufSetSize(dev, frag.buf[i], snapLen+fragLen); ++ ++ /* Add pseud snap length to the other fragmented frame */ ++ pseudSnapLen = snapLen; ++ ++ frameLen -= fragLen; ++ } ++ /* Intermediate Fragment */ ++ else ++ { ++ //zfTxBufferCopy(dev, frag.buf[i], buf, 0, offset, fragLen); ++ //zfwBufSetSize(dev, frag.buf[i], fragLen); ++ ++ zfTxBufferCopy(dev, frag.buf[i], buf, 0, offset, fragLen+pseudSnapLen ); ++ zfwBufSetSize(dev, frag.buf[i], fragLen+pseudSnapLen); ++ ++ frameLen -= (fragLen+pseudSnapLen); ++ } ++ //frameLen -= fragLen; ++ } ++ else ++ { ++ /* Last fragment */ ++ zfTxBufferCopy(dev, frag.buf[i], buf, 0, offset, frameLen); ++ /* Add MIC if need */ ++ if ( micLen ) ++ { ++ zfCopyToRxBuffer(dev, frag.buf[i], (u8_t*) mic, frameLen, micLen); ++ } ++ zfwBufSetSize(dev, frag.buf[i], frameLen+micLen); ++ frameLen = 0; ++ frag.flag[i] = (u8_t)flag; /* No more data */ ++ } ++ i++; ++ } ++ else ++ { ++ break; ++ } ++ ++ // Please pay attention to the index of the buf !!! ++ // If write to null buf , the OS will crash !!! ++ zfwCopyBufContext(dev, buf, frag.buf[i-1]); ++ } ++ fragNum = i; ++ snapLen = micLen = removeLen = 0; ++ ++ zfwBufFree(dev, buf, 0); ++ } ++ ++ for (i=0; istandard, 10-17=>Virtual AP, 20-25=>WDS */ ++/* */ ++/* OUTPUTS */ ++/* ZM_PORT_ENABLED or ZM_PORT_DISABLE */ ++/* */ ++/* AUTHOR */ ++/* Signature ZyDAS Technology Corporation 2005.4 */ ++/* */ ++/************************************************************************/ ++u16_t zfTxPortControl(zdev_t* dev, zbuf_t* buf, u16_t port) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ if ( wd->sta.adapterState == ZM_STA_STATE_DISCONNECT ) ++ { ++ zm_msg0_tx(ZM_LV_3, "Packets dropped due to disconnect state"); ++ return ZM_PORT_DISABLED; ++ } ++ } ++ ++ return ZM_PORT_ENABLED; ++} ++ ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfIdlRecv */ ++/* Do frame validation and filtering then pass to zfwRecv80211(). */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : received 802.11 frame buffer. */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++void zfCoreRecv(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo) ++{ ++ u16_t ret = 0; ++ u16_t bssid[3]; ++ struct agg_tid_rx *tid_rx; ++ zmw_get_wlan_dev(dev); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ /* tally */ ++ wd->commTally.DriverRxFrmCnt++; ++ ++ bssid[0] = zmw_buf_readh(dev, buf, 16); ++ bssid[1] = zmw_buf_readh(dev, buf, 18); ++ bssid[2] = zmw_buf_readh(dev, buf, 20); ++ ++ /* Validate Rx frame */ ++ if ((ret = zfWlanRxValidate(dev, buf)) != ZM_SUCCESS) ++ { ++ zm_msg1_rx(ZM_LV_1, "Rx invalid:", ret); ++ goto zlError; ++ } ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ //#ifndef ZM_ENABLE_FW_BA_RETRANSMISSION ++ /* ++ * add by honda ++ */ ++ tid_rx = zfAggRxEnabled(dev, buf); ++ if (tid_rx && wd->reorder) ++ { ++ zfAggRx(dev, buf, addInfo, tid_rx); ++ ++ return; ++ } ++ /* ++ * end of add by honda ++ */ ++ //#endif ++#endif ++ ++ /* Filter Rx frame */ ++ if ((ret = zfWlanRxFilter(dev, buf)) != ZM_SUCCESS) ++ { ++ zm_msg1_rx(ZM_LV_1, "Rx duplicated:", ret); ++ goto zlError; ++ } ++ ++ /* Discard error frame except mic failure */ ++ if ((addInfo->Tail.Data.ErrorIndication & 0x3f) != 0) ++ { ++ if ( wd->XLinkMode && ((addInfo->Tail.Data.ErrorIndication & 0x3f)==0x10) && ++ zfCompareWithBssid(dev, bssid) ) ++ { ++ // Bypass frames !!! ++ } ++ else ++ { ++ goto zlError; ++ } ++ } ++ ++ ++ /* OTUS command-8212 dump rx packet */ ++ if (wd->rxPacketDump) ++ { ++ zfwDumpBuf(dev, buf); ++ } ++ ++ /* Call zfwRecv80211() wrapper function to deliver Rx packet */ ++ /* to driver framework. */ ++ ++ if (wd->zfcbRecv80211 != NULL) ++ { ++ wd->zfcbRecv80211(dev, buf, addInfo); //CWYang(m) ++ } ++ else ++ { ++ zfiRecv80211(dev, buf, addInfo); ++ } ++ return; ++ ++zlError: ++ zm_msg1_rx(ZM_LV_1, "Free packet, error code:", ret); ++ ++ wd->commTally.DriverDiscardedFrm++; ++ ++ /* Free Rx buffer */ ++ zfwBufFree(dev, buf, 0); ++ ++ return; ++} ++ ++ ++void zfShowRxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u8_t packetType, keyType, code, identifier, type, flags; ++ u16_t packetLen, keyInfo, keyLen, keyDataLen, length, Op_Code; ++ u32_t replayCounterH, replayCounterL, vendorId, VendorType; ++ ++ /* EAPOL packet type */ ++ packetType = zmw_rx_buf_readb(dev, buf, offset+1); // 0: EAP-Packet ++ // 1: EAPOL-Start ++ // 2: EAPOL-Logoff ++ // 3: EAPOL-Key ++ // 4: EAPOL-Encapsulated-ASF-Alert ++ ++ /* EAPOL frame format */ ++ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ ++ /* ----------------------------------------------- */ ++ /* PAE Ethernet Type (0x888e) */ ++ /* ----------------------------------------------- 2 */ ++ /* Protocol Version | Type */ ++ /* ----------------------------------------------- 4 */ ++ /* Length */ ++ /* ----------------------------------------------- 6 */ ++ /* Packet Body */ ++ /* ----------------------------------------------- N */ ++ ++ /* EAPOL body length */ ++ packetLen = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+2)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+3); ++ ++ if( packetType == 0 ) ++ { // EAP-Packet ++ ++ /* EAP-Packet Code */ ++ code = zmw_rx_buf_readb(dev, buf, offset+4); // 1 : Request ++ // 2 : Response ++ // 3 : Success ++ // 4 : Failure ++ // An EAP packet of the type of Success and Failure has no Data field, and has a length of 4. ++ ++ /* EAP Packet format */ ++ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ ++ /* ----------------------------------------------- */ ++ /* Code | Identifier */ ++ /* ----------------------------------------------- 2 */ ++ /* Length */ ++ /* ----------------------------------------------- 4 */ ++ /* Data */ ++ /* ----------------------------------------------- N */ ++ ++ zm_debug_msg0("EAP-Packet"); ++ zm_debug_msg1("Packet Length = ", packetLen); ++ zm_debug_msg1("EAP-Packet Code = ", code); ++ ++ if( code == 1 ) ++ { ++ zm_debug_msg0("EAP-Packet Request"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_rx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+7); ++ /* EAP-Packet Type */ ++ type = zmw_rx_buf_readb(dev, buf, offset+8); // 1 : Identity ++ // 2 : Notification ++ // 3 : Nak (Response Only) ++ // 4 : MD5-Challenge ++ // 5 : One Time Password (OTP) ++ // 6 : Generic Token Card (GTC) ++ // 254 : (Expanded Types)Wi-Fi Protected Setup ++ // 255 : Experimental Use ++ ++ /* The data field in an EAP packet of the type of Request or Response is in the format shown bellowing */ ++ /* 0 1 2 3 4 5 6 7 N */ ++ /* ----------------------------------------------- */ ++ /* Type | Type Data */ ++ /* ----------------------------------------------- */ ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ zm_debug_msg1("EAP-Packet Type = ", type); ++ ++ if( type == 1 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Identity"); ++ } ++ else if( type == 2 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Notification"); ++ } ++ else if( type == 4 ) ++ { ++ zm_debug_msg0("EAP-Packet Request MD5-Challenge"); ++ } ++ else if( type == 5 ) ++ { ++ zm_debug_msg0("EAP-Packet Request One Time Password"); ++ } ++ else if( type == 6 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Generic Token Card"); ++ } ++ else if( type == 254 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Wi-Fi Protected Setup"); ++ ++ /* 0 1 2 3 */ ++ /* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ ++ /*| Type | Vendor-Id |*/ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ ++ /*| Vendor-Type |*/ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ ++ /*| Vendor data... */ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ ++ ++ /* EAP-Packet Vendor ID */ ++ vendorId = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+9)) << 16) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+10)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+11); ++ /* EAP-Packet Vendor Type */ ++ VendorType = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+12)) << 24) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+13)) << 16) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+14)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+15); ++ /* EAP-Packet Op Code */ ++ Op_Code = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+16)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+17); ++ /* EAP-Packet Flags */ ++ flags = zmw_rx_buf_readb(dev, buf, offset+18); ++ ++ zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); ++ zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); ++ zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); ++ zm_debug_msg1("EAP-Packet Flags = ", flags); ++ } ++ } ++ else if( code == 2 ) ++ { ++ zm_debug_msg0("EAP-Packet Response"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_rx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+7); ++ /* EAP-Packet Type */ ++ type = zmw_rx_buf_readb(dev, buf, offset+8); ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ zm_debug_msg1("EAP-Packet Type = ", type); ++ ++ if( type == 1 ) ++ { ++ zm_debug_msg0("EAP-Packet Response Identity"); ++ } ++ else if( type == 2 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Notification"); ++ } ++ else if( type == 3 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Nak"); ++ } ++ else if( type == 4 ) ++ { ++ zm_debug_msg0("EAP-Packet Request MD5-Challenge"); ++ } ++ else if( type == 5 ) ++ { ++ zm_debug_msg0("EAP-Packet Request One Time Password"); ++ } ++ else if( type == 6 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Generic Token Card"); ++ } ++ else if( type == 254 ) ++ { ++ zm_debug_msg0("EAP-Packet Response Wi-Fi Protected Setup"); ++ ++ /* EAP-Packet Vendor ID */ ++ vendorId = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+9)) << 16) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+10)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+11); ++ /* EAP-Packet Vendor Type */ ++ VendorType = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+12)) << 24) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+13)) << 16) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+14)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+15); ++ /* EAP-Packet Op Code */ ++ Op_Code = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+16)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+17); ++ /* EAP-Packet Flags */ ++ flags = zmw_rx_buf_readb(dev, buf, offset+18); ++ ++ zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); ++ zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); ++ zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); ++ zm_debug_msg1("EAP-Packet Flags = ", flags); ++ } ++ } ++ else if( code == 3 ) ++ { ++ zm_debug_msg0("EAP-Packet Success"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_rx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+7); ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ } ++ else if( code == 4 ) ++ { ++ zm_debug_msg0("EAP-Packet Failure"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_rx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+7); ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ } ++ } ++ else if( packetType == 1 ) ++ { // EAPOL-Start ++ zm_debug_msg0("EAPOL-Start"); ++ } ++ else if( packetType == 2 ) ++ { // EAPOL-Logoff ++ zm_debug_msg0("EAPOL-Logoff"); ++ } ++ else if( packetType == 3 ) ++ { // EAPOL-Key ++ /* EAPOL-Key type */ ++ keyType = zmw_rx_buf_readb(dev, buf, offset+4); ++ /* EAPOL-Key information */ ++ keyInfo = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+5)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+6); ++ /* EAPOL-Key length */ ++ keyLen = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+7)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+8); ++ /* EAPOL-Key replay counter (high double word) */ ++ replayCounterH = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+9)) << 24) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+10)) << 16) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+11)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+12); ++ /* EAPOL-Key replay counter (low double word) */ ++ replayCounterL = (((u32_t) zmw_rx_buf_readb(dev, buf, offset+13)) << 24) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+14)) << 16) + ++ (((u32_t) zmw_rx_buf_readb(dev, buf, offset+15)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+16); ++ /* EAPOL-Key data length */ ++ keyDataLen = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+97)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+98); ++ ++ zm_debug_msg0("EAPOL-Key"); ++ zm_debug_msg1("packet length = ", packetLen); ++ ++ if ( keyType == 254 ) ++ { ++ zm_debug_msg0("key type = 254 (SSN key descriptor)"); ++ } ++ else ++ { ++ zm_debug_msg2("key type = 0x", keyType); ++ } ++ ++ zm_debug_msg2("replay counter(L) = ", replayCounterL); ++ ++ zm_debug_msg2("key information = ", keyInfo); ++ ++ if ( keyInfo & ZM_BIT_3 ) ++ { ++ zm_debug_msg0(" - pairwise key"); ++ } ++ else ++ { ++ zm_debug_msg0(" - group key"); ++ } ++ ++ if ( keyInfo & ZM_BIT_6 ) ++ { ++ zm_debug_msg0(" - Tx key installed"); ++ } ++ else ++ { ++ zm_debug_msg0(" - Tx key not set"); ++ } ++ ++ if ( keyInfo & ZM_BIT_7 ) ++ { ++ zm_debug_msg0(" - Ack needed"); ++ } ++ else ++ { ++ zm_debug_msg0(" - Ack not needed"); ++ } ++ ++ if ( keyInfo & ZM_BIT_8 ) ++ { ++ zm_debug_msg0(" - MIC set"); ++ } ++ else ++ { ++ zm_debug_msg0(" - MIC not set"); ++ } ++ ++ if ( keyInfo & ZM_BIT_9 ) ++ { ++ zm_debug_msg0(" - packet encrypted"); ++ } ++ else ++ { ++ zm_debug_msg0(" - packet not encrypted"); ++ } ++ ++ zm_debug_msg1("keyLen = ", keyLen); ++ zm_debug_msg1("keyDataLen = ", keyDataLen); ++ } ++ else if( packetType == 4 ) ++ { ++ zm_debug_msg0("EAPOL-Encapsulated-ASF-Alert"); ++ } ++} ++ ++void zfShowTxEAPOL(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ u8_t packetType, keyType, code, identifier, type, flags; ++ u16_t packetLen, keyInfo, keyLen, keyDataLen, length, Op_Code; ++ u32_t replayCounterH, replayCounterL, vendorId, VendorType; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg1("EAPOL Packet size = ", zfwBufGetSize(dev, buf)); ++ ++ /* EAPOL packet type */ ++ // 0: EAP-Packet ++ // 1: EAPOL-Start ++ // 2: EAPOL-Logoff ++ // 3: EAPOL-Key ++ // 4: EAPOL-Encapsulated-ASF-Alert ++ ++ /* EAPOL frame format */ ++ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ ++ /* ----------------------------------------------- */ ++ /* PAE Ethernet Type (0x888e) */ ++ /* ----------------------------------------------- 2 */ ++ /* Protocol Version | Type */ ++ /* ----------------------------------------------- 4 */ ++ /* Length */ ++ /* ----------------------------------------------- 6 */ ++ /* Packet Body */ ++ /* ----------------------------------------------- N */ ++ ++ packetType = zmw_tx_buf_readb(dev, buf, offset+1); ++ /* EAPOL body length */ ++ packetLen = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+2)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+3); ++ ++ if( packetType == 0 ) ++ { // EAP-Packet ++ /* EAP-Packet Code */ ++ code = zmw_tx_buf_readb(dev, buf, offset+4); // 1 : Request ++ // 2 : Response ++ // 3 : Success ++ // 4 : Failure ++ ++ // An EAP packet of the type of Success and Failure has no Data field, and has a length of 4. ++ ++ /* EAP Packet format */ ++ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ ++ /* ----------------------------------------------- */ ++ /* Code | Identifier */ ++ /* ----------------------------------------------- 2 */ ++ /* Length */ ++ /* ----------------------------------------------- 4 */ ++ /* Data */ ++ /* ----------------------------------------------- N */ ++ ++ zm_debug_msg0("EAP-Packet"); ++ zm_debug_msg1("Packet Length = ", packetLen); ++ zm_debug_msg1("EAP-Packet Code = ", code); ++ ++ if( code == 1 ) ++ { ++ zm_debug_msg0("EAP-Packet Request"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_tx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+7); ++ /* EAP-Packet Type */ ++ type = zmw_tx_buf_readb(dev, buf, offset+8); // 1 : Identity ++ // 2 : Notification ++ // 3 : Nak (Response Only) ++ // 4 : MD5-Challenge ++ // 5 : One Time Password (OTP) ++ // 6 : Generic Token Card (GTC) ++ // 254 : (Expanded Types)Wi-Fi Protected Setup ++ // 255 : Experimental Use ++ ++ /* The data field in an EAP packet of the type of Request or Response is in the format shown bellowing */ ++ /* 0 1 2 3 4 5 6 7 N */ ++ /* ----------------------------------------------- */ ++ /* Type | Type Data */ ++ /* ----------------------------------------------- */ ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ zm_debug_msg1("EAP-Packet Type = ", type); ++ ++ if( type == 1 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Identity"); ++ } ++ else if( type == 2 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Notification"); ++ } ++ else if( type == 4 ) ++ { ++ zm_debug_msg0("EAP-Packet Request MD5-Challenge"); ++ } ++ else if( type == 5 ) ++ { ++ zm_debug_msg0("EAP-Packet Request One Time Password"); ++ } ++ else if( type == 6 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Generic Token Card"); ++ } ++ else if( type == 254 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Wi-Fi Protected Setup"); ++ ++ /* 0 1 2 3 */ ++ /* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ ++ /*| Type | Vendor-Id |*/ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ ++ /*| Vendor-Type |*/ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/ ++ /*| Vendor data... */ ++ /*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ ++ ++ /* EAP-Packet Vendor ID */ ++ vendorId = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+9)) << 16) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+10)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+11); ++ /* EAP-Packet Vendor Type */ ++ VendorType = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+12)) << 24) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+13)) << 16) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+14)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+15); ++ /* EAP-Packet Op Code */ ++ Op_Code = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+16)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+17); ++ /* EAP-Packet Flags */ ++ flags = zmw_tx_buf_readb(dev, buf, offset+18); ++ ++ zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); ++ zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); ++ zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); ++ zm_debug_msg1("EAP-Packet Flags = ", flags); ++ } ++ } ++ else if( code == 2 ) ++ { ++ zm_debug_msg0("EAP-Packet Response"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_tx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+7); ++ /* EAP-Packet Type */ ++ type = zmw_tx_buf_readb(dev, buf, offset+8); ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ zm_debug_msg1("EAP-Packet Type = ", type); ++ ++ if( type == 1 ) ++ { ++ zm_debug_msg0("EAP-Packet Response Identity"); ++ } ++ else if( type == 2 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Notification"); ++ } ++ else if( type == 3 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Nak"); ++ } ++ else if( type == 4 ) ++ { ++ zm_debug_msg0("EAP-Packet Request MD5-Challenge"); ++ } ++ else if( type == 5 ) ++ { ++ zm_debug_msg0("EAP-Packet Request One Time Password"); ++ } ++ else if( type == 6 ) ++ { ++ zm_debug_msg0("EAP-Packet Request Generic Token Card"); ++ } ++ else if( type == 254 ) ++ { ++ zm_debug_msg0("EAP-Packet Response Wi-Fi Protected Setup"); ++ ++ /* EAP-Packet Vendor ID */ ++ vendorId = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+9)) << 16) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+10)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+11); ++ /* EAP-Packet Vendor Type */ ++ VendorType = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+12)) << 24) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+13)) << 16) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+14)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+15); ++ /* EAP-Packet Op Code */ ++ Op_Code = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+16)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+17); ++ /* EAP-Packet Flags */ ++ flags = zmw_tx_buf_readb(dev, buf, offset+18); ++ ++ zm_debug_msg1("EAP-Packet Vendor ID = ", vendorId); ++ zm_debug_msg1("EAP-Packet Venodr Type = ", VendorType); ++ zm_debug_msg1("EAP-Packet Op Code = ", Op_Code); ++ zm_debug_msg1("EAP-Packet Flags = ", flags); ++ } ++ } ++ else if( code == 3 ) ++ { ++ zm_debug_msg0("EAP-Packet Success"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_rx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_rx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_rx_buf_readb(dev, buf, offset+7); ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ } ++ else if( code == 4 ) ++ { ++ zm_debug_msg0("EAP-Packet Failure"); ++ ++ /* EAP-Packet Identifier */ ++ identifier = zmw_tx_buf_readb(dev, buf, offset+5); ++ /* EAP-Packet Length */ ++ length = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+6)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+7); ++ ++ zm_debug_msg1("EAP-Packet Identifier = ", identifier); ++ zm_debug_msg1("EAP-Packet Length = ", length); ++ } ++ } ++ else if( packetType == 1 ) ++ { // EAPOL-Start ++ zm_debug_msg0("EAPOL-Start"); ++ } ++ else if( packetType == 2 ) ++ { // EAPOL-Logoff ++ zm_debug_msg0("EAPOL-Logoff"); ++ } ++ else if( packetType == 3 ) ++ { // EAPOL-Key ++ /* EAPOL-Key type */ ++ keyType = zmw_tx_buf_readb(dev, buf, offset+4); ++ /* EAPOL-Key information */ ++ keyInfo = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+5)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+6); ++ /* EAPOL-Key length */ ++ keyLen = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+7)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+8); ++ /* EAPOL-Key replay counter (high double word) */ ++ replayCounterH = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+9)) << 24) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+10)) << 16) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+11)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+12); ++ /* EAPOL-Key replay counter (low double word) */ ++ replayCounterL = (((u32_t) zmw_tx_buf_readb(dev, buf, offset+13)) << 24) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+14)) << 16) + ++ (((u32_t) zmw_tx_buf_readb(dev, buf, offset+15)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+16); ++ /* EAPOL-Key data length */ ++ keyDataLen = (((u16_t) zmw_tx_buf_readb(dev, buf, offset+97)) << 8) + ++ zmw_tx_buf_readb(dev, buf, offset+98); ++ ++ zm_debug_msg0("EAPOL-Key"); ++ zm_debug_msg1("packet length = ", packetLen); ++ ++ if ( keyType == 254 ) ++ { ++ zm_debug_msg0("key type = 254 (SSN key descriptor)"); ++ } ++ else ++ { ++ zm_debug_msg2("key type = 0x", keyType); ++ } ++ ++ zm_debug_msg2("replay counter(L) = ", replayCounterL); ++ ++ zm_debug_msg2("key information = ", keyInfo); ++ ++ if ( keyInfo & ZM_BIT_3 ) ++ { ++ zm_debug_msg0(" - pairwise key"); ++ } ++ else ++ { ++ zm_debug_msg0(" - group key"); ++ } ++ ++ if ( keyInfo & ZM_BIT_6 ) ++ { ++ zm_debug_msg0(" - Tx key installed"); ++ } ++ else ++ { ++ zm_debug_msg0(" - Tx key not set"); ++ } ++ ++ if ( keyInfo & ZM_BIT_7 ) ++ { ++ zm_debug_msg0(" - Ack needed"); ++ } ++ else ++ { ++ zm_debug_msg0(" - Ack not needed"); ++ } ++ ++ if ( keyInfo & ZM_BIT_8 ) ++ { ++ zm_debug_msg0(" - MIC set"); ++ } ++ else ++ { ++ zm_debug_msg0(" - MIC not set"); ++ } ++ ++ if ( keyInfo & ZM_BIT_9 ) ++ { ++ zm_debug_msg0(" - packet encrypted"); ++ } ++ else ++ { ++ zm_debug_msg0(" - packet not encrypted"); ++ } ++ ++ zm_debug_msg1("keyLen = ", keyLen); ++ zm_debug_msg1("keyDataLen = ", keyDataLen); ++ } ++ else if( packetType == 4 ) ++ { ++ zm_debug_msg0("EAPOL-Encapsulated-ASF-Alert"); ++ } ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiRecv80211 */ ++/* Called to receive 802.11 frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : received 802.11 frame buffer. */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.5 */ ++/* */ ++/************************************************************************/ ++void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo) ++{ ++ u8_t snapCase=0, encryMode; ++ u16_t frameType, typeLengthField; ++ u16_t frameCtrl; ++ u16_t frameSubtype; ++ u16_t ret; ++ u16_t len; ++ u8_t bIsDefrag = 0; ++ u16_t offset, tailLen; ++ u8_t vap = 0; ++ u16_t da[3], sa[3]; ++ u16_t ii; ++ u8_t uapsdTrig = 0; ++ zbuf_t* psBuf; ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ u8_t i; ++#endif ++ ++ zmw_get_wlan_dev(dev); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ //zm_msg2_rx(ZM_LV_2, "zfiRecv80211(), buf=", buf); ++ ++ //zm_msg2_rx(ZM_LV_0, "h[0]=", zmw_rx_buf_readh(dev, buf, 0)); ++ //zm_msg2_rx(ZM_LV_0, "h[2]=", zmw_rx_buf_readh(dev, buf, 2)); ++ //zm_msg2_rx(ZM_LV_0, "h[4]=", zmw_rx_buf_readh(dev, buf, 4)); ++ ++ frameCtrl = zmw_rx_buf_readb(dev, buf, 0); ++ frameType = frameCtrl & 0xf; ++ frameSubtype = frameCtrl & 0xf0; ++ ++#if 0 // Move to ProcessBeacon to judge if there's a new peer station ++ if ( (wd->wlanMode == ZM_MODE_IBSS)&& ++ (wd->sta.ibssPartnerStatus != ZM_IBSS_PARTNER_ALIVE) ) ++ { ++ zfStaIbssMonitoring(dev, buf); ++ } ++#endif ++ ++ /* If data frame */ ++ if (frameType == ZM_WLAN_DATA_FRAME) ++ { ++ wd->sta.TotalNumberOfReceivePackets++; ++ wd->sta.TotalNumberOfReceiveBytes += zfwBufGetSize(dev, buf); ++ //zm_debug_msg1("Receive packets = ", wd->sta.TotalNumberOfReceivePackets); ++ ++ //zm_msg0_rx(ZM_LV_0, "Rx data"); ++ if (wd->wlanMode == ZM_MODE_AP) ++ { ++ if ((ret = zfApUpdatePsBit(dev, buf, &vap, &uapsdTrig)) != ZM_SUCCESS) ++ { ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ if (((uapsdTrig&0xf) != 0) && ((frameSubtype & 0x80) != 0)) ++ { ++ u8_t ac = zcUpToAc[zmw_buf_readb(dev, buf, 24)&0x7]; ++ u8_t pktNum; ++ u8_t mb; ++ u16_t flag; ++ u8_t src[6]; ++ ++ //printk("QoS ctrl=%d\n", zmw_buf_readb(dev, buf, 24)); ++ //printk("UAPSD trigger, ac=%d\n", ac); ++ ++ if (((0x8>>ac) & uapsdTrig) != 0) ++ { ++ pktNum = zcMaxspToPktNum[(uapsdTrig>>4) & 0x3]; ++ ++ for (ii=0; ii<6; ii++) ++ { ++ src[ii] = zmw_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+ii); ++ } ++ ++ for (ii=0; iiap.uapsdQ)) != NULL) ++ if ((psBuf = zfQueueGetWithMac(dev, wd->ap.uapsdQ, src, &mb)) != NULL) ++ { ++ if ((ii+1) == pktNum) ++ { ++ //EOSP anyway ++ flag = 0x100 | (mb<<5); ++ } ++ else ++ { ++ if (mb != 0) ++ { ++ //more data, not EOSP ++ flag = 0x20; ++ } ++ else ++ { ++ //no more data, EOSP ++ flag = 0x100; ++ } ++ } ++ zfTxSendEth(dev, psBuf, 0, ZM_EXTERNAL_ALLOC_BUF, flag); ++ } ++ ++ if ((psBuf == NULL) || (mb == 0)) ++ { ++ if ((ii == 0) && (psBuf == NULL)) ++ { ++ zfSendMmFrame(dev, ZM_WLAN_FRAME_TYPE_QOS_NULL, (u16_t*)src, 0, 0, 0); ++ } ++ break; ++ } ++ } ++ } ++ } ++ ++ } ++ else if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ u16_t frameCtrlMSB; ++ u8_t bssid[6]; ++ ++ /* Check Is RIFS frame and decide to enable RIFS or not */ ++ if( wd->sta.EnableHT ) ++ zfCheckIsRIFSFrame(dev, buf, frameSubtype); ++ ++ if ( zfPowerSavingMgrIsSleeping(dev) || wd->sta.psMgr.tempWakeUp == 1) ++ { ++ frameCtrlMSB = zmw_rx_buf_readb(dev, buf, 1); ++ ++ /* check more data */ ++ if ( frameCtrlMSB & ZM_BIT_5 ) ++ { ++ //if rx frame's AC is not delivery-enabled ++ if ((wd->sta.qosInfo&0xf) != 0xf) ++ { ++ u8_t rxAc = 0; ++ if ((frameSubtype & 0x80) != 0) ++ { ++ rxAc = zcUpToAc[zmw_buf_readb(dev, buf, 24)&0x7]; ++ } ++ ++ if (((0x8>>rxAc) & wd->sta.qosInfo) == 0) ++ { ++ zfSendPSPoll(dev); ++ wd->sta.psMgr.tempWakeUp = 0; ++ } ++ } ++ } ++ } ++ /*increase beacon count when receive vaild data frame from AP*/ ++ ZM_MAC_WORD_TO_BYTE(wd->sta.bssid, bssid); ++ ++ if (zfStaIsConnected(dev)&& ++ zfRxBufferEqualToStr(dev, buf, bssid, ZM_WLAN_HEADER_A2_OFFSET, 6)) ++ { ++ wd->sta.rxBeaconCount++; ++ } ++ } ++ ++ zm_msg1_rx(ZM_LV_2, "Rx VAP=", vap); ++ ++ /* handle IV, EXT-IV, ICV, and EXT-ICV */ ++ zfGetRxIvIcvLength(dev, buf, vap, &offset, &tailLen, addInfo); ++ ++ zfStaIbssPSCheckState(dev, buf); ++ //QoS data frame ++ if ((frameSubtype & 0x80) == 0x80) ++ { ++ offset += 2; ++ } ++ ++ len = zfwBufGetSize(dev, buf); ++ /* remove ICV */ ++ if (tailLen > 0) ++ { ++ if (len > tailLen) ++ { ++ len -= tailLen; ++ zfwBufSetSize(dev, buf, len); ++ } ++ } ++ ++ /* Filter NULL data */ ++ if (((frameSubtype&0x40) != 0) || ((len = zfwBufGetSize(dev, buf))<=24)) ++ { ++ zm_msg1_rx(ZM_LV_1, "Free Rx NULL data, len=", len); ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ /* check and handle defragmentation */ ++ if ( wd->sta.bSafeMode && (wd->sta.wepStatus == ZM_ENCRYPTION_AES) && wd->sta.SWEncryptEnable ) ++ { ++ zm_msg0_rx(ZM_LV_1, "Bypass defragmentation packets in safe mode"); ++ } ++ else ++ { ++ if ( (buf = zfDefragment(dev, buf, &bIsDefrag, addInfo)) == NULL ) ++ { ++ /* In this case, the buffer has been freed in zfDefragment */ ++ return; ++ } ++ } ++ ++ ret = ZM_MIC_SUCCESS; ++ ++ /* If SW WEP/TKIP are not turned on */ ++ if ((wd->sta.SWEncryptEnable & ZM_SW_TKIP_DECRY_EN) == 0 && ++ (wd->sta.SWEncryptEnable & ZM_SW_WEP_DECRY_EN) == 0) ++ { ++ encryMode = zfGetEncryModeFromRxStatus(addInfo); ++ ++ /* check if TKIP */ ++ if ( encryMode == ZM_TKIP ) ++ { ++ if ( bIsDefrag ) ++ { ++ ret = zfMicRxVerify(dev, buf); ++ } ++ else ++ { ++ /* check MIC failure bit */ ++ if ( ZM_RX_STATUS_IS_MIC_FAIL(addInfo) ) ++ { ++ ret = ZM_MIC_FAILURE; ++ } ++ } ++ ++ if ( ret == ZM_MIC_FAILURE ) ++ { ++ u8_t Unicast_Pkt = 0x0; ++ ++ if ((zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) & 0x1) == 0) ++ { ++ wd->commTally.swRxUnicastMicFailCount++; ++ Unicast_Pkt = 0x1; ++ }/* ++ else if (zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) == 0xffff) ++ { ++ wd->commTally.swRxMulticastMicFailCount++; ++ }*/ ++ else ++ { ++ wd->commTally.swRxMulticastMicFailCount++; ++ } ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ u16_t idx; ++ u8_t addr[6]; ++ ++ for (idx=0; idx<6; idx++) ++ { ++ addr[idx] = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+idx); ++ } ++ ++ if (wd->zfcbApMicFailureNotify != NULL) ++ { ++ wd->zfcbApMicFailureNotify(dev, addr, buf); ++ } ++ } ++ else ++ { ++ if(Unicast_Pkt) ++ { ++ zm_debug_msg0("Countermeasure : Unicast_Pkt "); ++ } ++ else ++ { ++ zm_debug_msg0("Countermeasure : Non-Unicast_Pkt "); ++ } ++ ++ if((wd->TKIP_Group_KeyChanging == 0x0) || (Unicast_Pkt == 0x1)) ++ { ++ zm_debug_msg0("Countermeasure : Do MIC Check "); ++ zfStaMicFailureHandling(dev, buf); ++ } ++ else ++ { ++ zm_debug_msg0("Countermeasure : SKIP MIC Check due to Group Keychanging "); ++ } ++ } ++ /* Discard MIC failed frame */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ } ++ } ++ else ++ { ++ u8_t IsEncryFrame; ++ ++ /* TODO: Check whether WEP bit is turned on in MAC header */ ++ encryMode = ZM_NO_WEP; ++ ++ IsEncryFrame = (zmw_rx_buf_readb(dev, buf, 1) & 0x40); ++ ++ if (IsEncryFrame) ++ { ++ /* Software decryption for TKIP */ ++ if (wd->sta.SWEncryptEnable & ZM_SW_TKIP_DECRY_EN) ++ { ++ u16_t iv16; ++ u16_t iv32; ++ u8_t RC4Key[16]; ++ u16_t IvOffset; ++ struct zsTkipSeed *rxSeed; ++ ++ IvOffset = offset + ZM_SIZE_OF_WLAN_DATA_HEADER; ++ ++ rxSeed = zfStaGetRxSeed(dev, buf); ++ ++ if (rxSeed == NULL) ++ { ++ zm_debug_msg0("rxSeed is NULL"); ++ ++ /* Discard this frame */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ iv16 = (zmw_rx_buf_readb(dev, buf, IvOffset) << 8) + zmw_rx_buf_readb(dev, buf, IvOffset+2); ++ iv32 = zmw_rx_buf_readb(dev, buf, IvOffset+4) + ++ (zmw_rx_buf_readb(dev, buf, IvOffset+5) << 8) + ++ (zmw_rx_buf_readb(dev, buf, IvOffset+6) << 16) + ++ (zmw_rx_buf_readb(dev, buf, IvOffset+7) << 24); ++ ++ /* TKIP Key Mixing */ ++ zfTkipPhase1KeyMix(iv32, rxSeed); ++ zfTkipPhase2KeyMix(iv16, rxSeed); ++ zfTkipGetseeds(iv16, RC4Key, rxSeed); ++ ++ /* Decrypt Data */ ++ ret = zfTKIPDecrypt(dev, buf, IvOffset+ZM_SIZE_OF_IV+ZM_SIZE_OF_EXT_IV, 16, RC4Key); ++ ++ if (ret == ZM_ICV_FAILURE) ++ { ++ zm_debug_msg0("TKIP ICV fail"); ++ ++ /* Discard ICV failed frame */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ /* Remove ICV from buffer */ ++ zfwBufSetSize(dev, buf, len-4); ++ ++ /* Check MIC */ ++ ret = zfMicRxVerify(dev, buf); ++ ++ if (ret == ZM_MIC_FAILURE) ++ { ++ if ((zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) & 0x1) == 0) ++ { ++ wd->commTally.swRxUnicastMicFailCount++; ++ } ++ else if (zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) == 0xffff) ++ { ++ wd->commTally.swRxMulticastMicFailCount++; ++ } ++ else ++ { ++ wd->commTally.swRxMulticastMicFailCount++; ++ } ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ u16_t idx; ++ u8_t addr[6]; ++ ++ for (idx=0; idx<6; idx++) ++ { ++ addr[idx] = zmw_rx_buf_readb(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+idx); ++ } ++ ++ if (wd->zfcbApMicFailureNotify != NULL) ++ { ++ wd->zfcbApMicFailureNotify(dev, addr, buf); ++ } ++ } ++ else ++ { ++ zfStaMicFailureHandling(dev, buf); ++ } ++ ++ zm_debug_msg0("MIC fail"); ++ /* Discard MIC failed frame */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ encryMode = ZM_TKIP; ++ offset += ZM_SIZE_OF_IV + ZM_SIZE_OF_EXT_IV; ++ } ++ else if(wd->sta.SWEncryptEnable & ZM_SW_WEP_DECRY_EN) ++ { ++ u16_t IvOffset; ++ u8_t keyLen = 5; ++ u8_t iv[3]; ++ u8_t *wepKey; ++ u8_t keyIdx; ++ ++ IvOffset = offset + ZM_SIZE_OF_WLAN_DATA_HEADER; ++ ++ /* Retrieve IV */ ++ iv[0] = zmw_rx_buf_readb(dev, buf, IvOffset); ++ iv[1] = zmw_rx_buf_readb(dev, buf, IvOffset+1); ++ iv[2] = zmw_rx_buf_readb(dev, buf, IvOffset+2); ++ ++ keyIdx = ((zmw_rx_buf_readb(dev, buf, IvOffset+3) >> 6) & 0x03); ++ ++ IvOffset += ZM_SIZE_OF_IV; ++ ++ if (wd->sta.SWEncryMode[keyIdx] == ZM_WEP64) ++ { ++ keyLen = 5; ++ } ++ else if (wd->sta.SWEncryMode[keyIdx] == ZM_WEP128) ++ { ++ keyLen = 13; ++ } ++ else if (wd->sta.SWEncryMode[keyIdx] == ZM_WEP256) ++ { ++ keyLen = 29; ++ } ++ ++ zfWEPDecrypt(dev, buf, IvOffset, keyLen, wd->sta.wepKey[keyIdx], iv); ++ ++ if (ret == ZM_ICV_FAILURE) ++ { ++ zm_debug_msg0("WEP ICV fail"); ++ ++ /* Discard ICV failed frame */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ encryMode = wd->sta.SWEncryMode[keyIdx]; ++ ++ /* Remove ICV from buffer */ ++ zfwBufSetSize(dev, buf, len-4); ++ ++ offset += ZM_SIZE_OF_IV; ++ } ++ } ++ } ++ ++#ifdef ZM_ENABLE_CENC ++ //else if ( encryMode == ZM_CENC ) /* check if CENC */ ++ if ( encryMode == ZM_CENC ) ++ { ++ u32_t rxIV[4]; ++ ++ rxIV[0] = (zmw_rx_buf_readh(dev, buf, 28) << 16) ++ + zmw_rx_buf_readh(dev, buf, 26); ++ rxIV[1] = (zmw_rx_buf_readh(dev, buf, 32) << 16) ++ + zmw_rx_buf_readh(dev, buf, 30); ++ rxIV[2] = (zmw_rx_buf_readh(dev, buf, 36) << 16) ++ + zmw_rx_buf_readh(dev, buf, 34); ++ rxIV[3] = (zmw_rx_buf_readh(dev, buf, 40) << 16) ++ + zmw_rx_buf_readh(dev, buf, 38); ++ ++ //zm_debug_msg2("rxIV[0] = 0x", rxIV[0]); ++ //zm_debug_msg2("rxIV[1] = 0x", rxIV[1]); ++ //zm_debug_msg2("rxIV[2] = 0x", rxIV[2]); ++ //zm_debug_msg2("rxIV[3] = 0x", rxIV[3]); ++ ++ /* destination address*/ ++ da[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ da[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+2); ++ da[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+4); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ } ++ else ++ { ++ if ((da[0] & 0x1)) ++ { //multicast frame ++ /* Accumlate the PN sequence */ ++ wd->sta.rxivGK[0] ++; ++ ++ if (wd->sta.rxivGK[0] == 0) ++ { ++ wd->sta.rxivGK[1]++; ++ } ++ ++ if (wd->sta.rxivGK[1] == 0) ++ { ++ wd->sta.rxivGK[2]++; ++ } ++ ++ if (wd->sta.rxivGK[2] == 0) ++ { ++ wd->sta.rxivGK[3]++; ++ } ++ ++ if (wd->sta.rxivGK[3] == 0) ++ { ++ wd->sta.rxivGK[0] = 0; ++ wd->sta.rxivGK[1] = 0; ++ wd->sta.rxivGK[2] = 0; ++ } ++ ++ //zm_debug_msg2("wd->sta.rxivGK[0] = 0x", wd->sta.rxivGK[0]); ++ //zm_debug_msg2("wd->sta.rxivGK[1] = 0x", wd->sta.rxivGK[1]); ++ //zm_debug_msg2("wd->sta.rxivGK[2] = 0x", wd->sta.rxivGK[2]); ++ //zm_debug_msg2("wd->sta.rxivGK[3] = 0x", wd->sta.rxivGK[3]); ++ ++ if ( !((wd->sta.rxivGK[0] == rxIV[0]) ++ && (wd->sta.rxivGK[1] == rxIV[1]) ++ && (wd->sta.rxivGK[2] == rxIV[2]) ++ && (wd->sta.rxivGK[3] == rxIV[3]))) ++ { ++ u8_t PacketDiscard = 0; ++ /* Discard PN Code Error frame */ ++ if (rxIV[0] < wd->sta.rxivGK[0]) ++ { ++ PacketDiscard = 1; ++ } ++ if (wd->sta.rxivGK[0] > 0xfffffff0) ++ { //boundary case ++ if ((rxIV[0] < 0xfffffff0) ++ && (((0xffffffff - wd->sta.rxivGK[0]) + rxIV[0]) > 16)) ++ { ++ PacketDiscard = 1; ++ } ++ } ++ else ++ { //normal case ++ if ((rxIV[0] - wd->sta.rxivGK[0]) > 16) ++ { ++ PacketDiscard = 1; ++ } ++ } ++ // sync sta pn code with ap because of losting some packets ++ wd->sta.rxivGK[0] = rxIV[0]; ++ wd->sta.rxivGK[1] = rxIV[1]; ++ wd->sta.rxivGK[2] = rxIV[2]; ++ wd->sta.rxivGK[3] = rxIV[3]; ++ if (PacketDiscard) ++ { ++ zm_debug_msg0("Discard PN Code lost too much multicast frame"); ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ } ++ } ++ else ++ { //unicast frame ++ /* Accumlate the PN sequence */ ++ wd->sta.rxiv[0] += 2; ++ ++ if (wd->sta.rxiv[0] == 0 || wd->sta.rxiv[0] == 1) ++ { ++ wd->sta.rxiv[1]++; ++ } ++ ++ if (wd->sta.rxiv[1] == 0) ++ { ++ wd->sta.rxiv[2]++; ++ } ++ ++ if (wd->sta.rxiv[2] == 0) ++ { ++ wd->sta.rxiv[3]++; ++ } ++ ++ if (wd->sta.rxiv[3] == 0) ++ { ++ wd->sta.rxiv[0] = 0; ++ wd->sta.rxiv[1] = 0; ++ wd->sta.rxiv[2] = 0; ++ } ++ ++ //zm_debug_msg2("wd->sta.rxiv[0] = 0x", wd->sta.rxiv[0]); ++ //zm_debug_msg2("wd->sta.rxiv[1] = 0x", wd->sta.rxiv[1]); ++ //zm_debug_msg2("wd->sta.rxiv[2] = 0x", wd->sta.rxiv[2]); ++ //zm_debug_msg2("wd->sta.rxiv[3] = 0x", wd->sta.rxiv[3]); ++ ++ if ( !((wd->sta.rxiv[0] == rxIV[0]) ++ && (wd->sta.rxiv[1] == rxIV[1]) ++ && (wd->sta.rxiv[2] == rxIV[2]) ++ && (wd->sta.rxiv[3] == rxIV[3]))) ++ { ++ zm_debug_msg0("PN Code mismatch, lost unicast frame, sync pn code to recv packet"); ++ // sync sta pn code with ap because of losting some packets ++ wd->sta.rxiv[0] = rxIV[0]; ++ wd->sta.rxiv[1] = rxIV[1]; ++ wd->sta.rxiv[2] = rxIV[2]; ++ wd->sta.rxiv[3] = rxIV[3]; ++ /* Discard PN Code Error frame */ ++ //zm_debug_msg0("Discard PN Code mismatch unicast frame"); ++ //zfwBufFree(dev, buf, 0); ++ //return; ++ } ++ } ++ } ++ } ++#endif //ZM_ENABLE_CENC ++ ++ /* for tally */ ++ if ((zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) & 0x1) == 0) ++ { ++ /* for ACU to display RxRate */ ++ zfWlanUpdateRxRate(dev, addInfo); ++ ++ wd->commTally.rxUnicastFrm++; ++ wd->commTally.rxUnicastOctets += (len-24); ++ } ++ else if (zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET) == 0xffff) ++ { ++ wd->commTally.rxBroadcastFrm++; ++ wd->commTally.rxBroadcastOctets += (len-24); ++ } ++ else ++ { ++ wd->commTally.rxMulticastFrm++; ++ wd->commTally.rxMulticastOctets += (len-24); ++ } ++ wd->ledStruct.rxTraffic++; ++ ++ if ((frameSubtype & 0x80) == 0x80) ++ { ++ /* if QoS control bit-7 is 1 => A-MSDU frame */ ++ if ((zmw_rx_buf_readh(dev, buf, 24) & 0x80) != 0) ++ { ++ zfDeAmsdu(dev, buf, vap, encryMode); ++ return; ++ } ++ } ++ ++ // Remove MIC of TKIP ++ if ( encryMode == ZM_TKIP ) ++ { ++ zfwBufSetSize(dev, buf, zfwBufGetSize(dev, buf) - 8); ++ } ++ ++ /* Convert 802.11 and SNAP header to ethernet header */ ++ if ( (wd->wlanMode == ZM_MODE_INFRASTRUCTURE)|| ++ (wd->wlanMode == ZM_MODE_IBSS) ) ++ { ++ /* destination address*/ ++ da[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET); ++ da[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+2); ++ da[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A1_OFFSET+4); ++ ++ /* check broadcast frame */ ++ if ( (da[0] == 0xffff) && (da[1] == 0xffff) && (da[2] == 0xffff) ) ++ { ++ // Ap send broadcast frame to the DUT ! ++ } ++ /* check multicast frame */ ++ /* TODO : Remove these code, hardware should be able to block */ ++ /* multicast frame on the multicast address list */ ++ /* or bypass all multicast packet by flag bAllMulticast */ ++ else if ((da[0] & 0x01) && (wd->sta.bAllMulticast == 0)) ++ { ++ for(ii=0; iista.multicastList.size; ii++) ++ { ++ if ( zfMemoryIsEqual(wd->sta.multicastList.macAddr[ii].addr, ++ (u8_t*) da, 6)) ++ { ++ break; ++ } ++ } ++ ++ if ( ii == wd->sta.multicastList.size ) ++ { /* not found */ ++ zm_debug_msg0("discard unknown multicast frame"); ++ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ } ++ ++#ifdef ZM_ENABLE_NATIVE_WIFI //Native Wifi : 1, Ethernet format : 0 ++ //To remove IV ++ if (offset > 0) ++ { ++ for (i=12; i>0; i--) ++ { ++ zmw_rx_buf_writeh(dev, buf, ((i-1)*2)+offset, ++ zmw_rx_buf_readh(dev, buf, (i-1)*2)); ++ } ++ zfwBufRemoveHead(dev, buf, offset); ++ } ++#else ++ ++ if (zfRxBufferEqualToStr(dev, buf, zgSnapBridgeTunnel, ++ 24+offset, 6)) ++ { ++ snapCase = 1; ++ } ++ else if ( zfRxBufferEqualToStr(dev, buf, zgSnap8021h, ++ 24+offset, 6) ) ++ { ++ typeLengthField = ++ (((u16_t) zmw_rx_buf_readb(dev, buf, 30+offset)) << 8) + ++ zmw_rx_buf_readb(dev, buf, 31+offset); ++ ++ //zm_debug_msg2("tpyeLengthField = ", typeLengthField); ++ ++ //8137 : IPX, 80F3 : Appletalk ++ if ( (typeLengthField != 0x8137)&& ++ (typeLengthField != 0x80F3) ) ++ { ++ snapCase = 2; ++ } ++ ++ if ( typeLengthField == 0x888E ) ++ { ++ zfShowRxEAPOL(dev, buf, 32); ++ } ++ } ++ else ++ { ++ //zfwDumpBuf(dev, buf); ++ } ++ ++ /* source address */ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ /* SA = Address 3 */ ++ sa[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET); ++ sa[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+2); ++ sa[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A3_OFFSET+4); ++ } ++ else ++ { ++ /* SA = Address 2 */ ++ sa[0] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET); ++ sa[1] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+2); ++ sa[2] = zmw_rx_buf_readh(dev, buf, ZM_WLAN_HEADER_A2_OFFSET+4); ++ } ++ ++ if ( snapCase ) ++ { ++ /* SA */ ++ zmw_rx_buf_writeh(dev, buf, 24+offset, sa[0]); ++ zmw_rx_buf_writeh(dev, buf, 26+offset, sa[1]); ++ zmw_rx_buf_writeh(dev, buf, 28+offset, sa[2]); ++ ++ /* DA = Address 1 */ ++ zmw_rx_buf_writeh(dev, buf, 18+offset, da[0]); ++ zmw_rx_buf_writeh(dev, buf, 20+offset, da[1]); ++ zmw_rx_buf_writeh(dev, buf, 22+offset, da[2]); ++ zfwBufRemoveHead(dev, buf, 18+offset); ++ } ++ else ++ { ++ /* SA */ ++ zmw_rx_buf_writeh(dev, buf, 16+offset, sa[0]); ++ zmw_rx_buf_writeh(dev, buf, 18+offset, sa[1]); ++ zmw_rx_buf_writeh(dev, buf, 20+offset, sa[2]); ++ ++ /* DA = Address 1 */ ++ zmw_rx_buf_writeh(dev, buf, 10+offset, da[0]); ++ zmw_rx_buf_writeh(dev, buf, 12+offset, da[1]); ++ zmw_rx_buf_writeh(dev, buf, 14+offset, da[2]); ++ zfwBufRemoveHead(dev, buf, 10+offset); ++ /* Ethernet payload length */ ++ typeLengthField = zfwBufGetSize(dev, buf) - 14; ++ zmw_rx_buf_writeh(dev, buf, 12, (typeLengthField<<8)+(typeLengthField>>8)); ++ } ++#endif // ZM_ENABLE_NATIVE_WIFI ++ } ++ else if (wd->wlanMode == ZM_MODE_AP) ++ { ++ //if ((zmw_rx_buf_readb(dev, buf, 1) & 0x3) != 3) ++ if (vap < ZM_MAX_AP_SUPPORT) ++ /* AP mode */ ++ { ++#ifdef ZM_ENABLE_NATIVE_WIFI //Native Wifi : 1, Ethernet format : 0 ++ //To remove IV ++ if (offset > 0) ++ { ++ for (i=12; i>0; i--) ++ { ++ zmw_rx_buf_writeh(dev, buf, ((i-1)*2)+offset, ++ zmw_rx_buf_readh(dev, buf, (i-1)*2)); ++ } ++ zfwBufRemoveHead(dev, buf, offset); ++ } ++#else ++ /* SA = Address 2 */ ++ zmw_rx_buf_writeh(dev, buf, 24+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A2_OFFSET)); ++ zmw_rx_buf_writeh(dev, buf, 26+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A2_OFFSET+2)); ++ zmw_rx_buf_writeh(dev, buf, 28+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A2_OFFSET+4)); ++ /* DA = Address 3 */ ++ /* Seq : Read 20 write 22, read 18 write 20, read 16 write 18 */ ++ /* sequence must not be inverted */ ++ zmw_rx_buf_writeh(dev, buf, 22+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A3_OFFSET+4)); ++ zmw_rx_buf_writeh(dev, buf, 20+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A3_OFFSET+2)); ++ zmw_rx_buf_writeh(dev, buf, 18+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A3_OFFSET)); ++ zfwBufRemoveHead(dev, buf, 18+offset); ++#endif // ZM_ENABLE_NATIVE_WIFI ++ #if 1 ++ if ((ret = zfIntrabssForward(dev, buf, vap)) == 1) ++ { ++ /* Free Rx buffer if intra-BSS unicast frame */ ++ zm_msg0_rx(ZM_LV_2, "Free intra-BSS unicast frame"); ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ #endif ++ } ++ else ++ /* WDS mode */ ++ { ++ zm_msg0_rx(ZM_LV_2, "Rx WDS data"); ++ ++ /* SA = Address 4 */ ++ zmw_rx_buf_writeh(dev, buf, 30+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A4_OFFSET)); ++ zmw_rx_buf_writeh(dev, buf, 32+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A4_OFFSET+2)); ++ zmw_rx_buf_writeh(dev, buf, 34+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A4_OFFSET+4)); ++ /* DA = Address 3 */ ++ /* Seq : Read 20 write 22, read 18 write 20, read 16 write 18 */ ++ /* sequence must not be inverted */ ++ zmw_rx_buf_writeh(dev, buf, 28+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A3_OFFSET+4)); ++ zmw_rx_buf_writeh(dev, buf, 26+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A3_OFFSET+2)); ++ zmw_rx_buf_writeh(dev, buf, 24+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A3_OFFSET)); ++ zfwBufRemoveHead(dev, buf, 24+offset); ++ } ++ } ++ else if (wd->wlanMode == ZM_MODE_PSEUDO) ++ { ++ /* WDS test: remove add4 */ ++ if (wd->enableWDS) ++ { ++ offset += 6; ++ } ++ ++ /* SA = Address 2 */ ++ zmw_rx_buf_writeh(dev, buf, 24+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A2_OFFSET)); ++ zmw_rx_buf_writeh(dev, buf, 26+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A2_OFFSET+2)); ++ zmw_rx_buf_writeh(dev, buf, 28+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A2_OFFSET+4)); ++ /* DA = Address 1 */ ++ zmw_rx_buf_writeh(dev, buf, 18+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A1_OFFSET)); ++ zmw_rx_buf_writeh(dev, buf, 20+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A1_OFFSET+2)); ++ zmw_rx_buf_writeh(dev, buf, 22+offset, zmw_rx_buf_readh(dev, buf, ++ ZM_WLAN_HEADER_A1_OFFSET+4)); ++ zfwBufRemoveHead(dev, buf, 18+offset); ++ } ++ else ++ { ++ zm_assert(0); ++ } ++ ++ /* Call zfwRecvEth() to notify upper layer */ ++ //zm_msg2_rx(ZM_LV_2, "Call zfwRecvEth(), buf=", buf); ++ //zfwDumpBuf(dev, buf); ++ ++ #if ZM_PROTOCOL_RESPONSE_SIMULATION == 1 ++ zfProtRspSim(dev, buf); ++ #endif ++ //zfwDumpBuf(dev, buf); ++ ++ /* tally */ ++ wd->commTally.NotifyNDISRxFrmCnt++; ++ ++ if (wd->zfcbRecvEth != NULL) ++ { ++ wd->zfcbRecvEth(dev, buf, vap); ++ ZM_PERFORMANCE_RX_MSDU(dev, wd->tick) ++ } ++ } ++ /* if management frame */ ++ else if (frameType == ZM_WLAN_MANAGEMENT_FRAME) ++ { ++ zm_msg2_rx(ZM_LV_2, "Rx management,FC=", frameCtrl); ++ /* Call zfProcessManagement() to handle management frame */ ++ zfProcessManagement(dev, buf, addInfo); //CWYang(m) ++ zfwBufFree(dev, buf, 0); ++ } ++ /* PsPoll */ ++ else if ((wd->wlanMode == ZM_MODE_AP) && (frameCtrl == 0xa4)) ++ { ++ zm_msg0_rx(ZM_LV_0, "Rx PsPoll"); ++ zfApProcessPsPoll(dev, buf); ++ zfwBufFree(dev, buf, 0); ++ } ++ else ++ { ++ zm_msg0_rx(ZM_LV_1, "Rx discard!!"); ++ wd->commTally.DriverDiscardedFrm++; ++ ++ zfwBufFree(dev, buf, 0); ++ } ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfWlanRxValidate */ ++/* Validate Rx frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : received 802.11 frame buffer. */ ++/* */ ++/* OUTPUTS */ ++/* Error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfWlanRxValidate(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t frameType; ++ u16_t frameCtrl; ++ u16_t frameLen; ++ u16_t ret; ++ u8_t frameSubType; ++ ++ zmw_get_wlan_dev(dev); ++ ++ frameCtrl = zmw_rx_buf_readh(dev, buf, 0); ++ frameType = frameCtrl & 0xC; ++ frameSubType = (frameCtrl & 0xF0) >> 4; ++ ++ frameLen = zfwBufGetSize(dev, buf); ++ ++ /* Accept Data/Management frame with protocol version = 0 */ ++ if ((frameType == 0x8) || (frameType == 0x0)) ++ { ++ ++ /* TODO : check rx status => erro bit */ ++ ++ /* Check Minimum Length with Wep */ ++ if ((frameCtrl & 0x4000) != 0) ++ { ++ /* Minimum Length = */ ++ /* PLCP(5)+Header(24)+IV(4)+ICV(4)+CRC(4)+RxStatus(8) */ ++ if (frameLen < 32) ++ { ++ return ZM_ERR_MIN_RX_ENCRYPT_FRAME_LENGTH; ++ } ++ } ++ else if ( frameSubType == 0x5 || frameSubType == 0x8 ) ++ { ++ /* Minimum Length = PLCP(5)+MACHeader(24)+Timestamp(8)+BeaconInterval(2)+Cap(2)+CRC(4)+RxStatus(8) */ ++ if (frameLen < 36) ++ { ++ return ZM_ERR_MIN_RX_FRAME_LENGTH; ++ } ++ } ++ else ++ { ++ /* Minimum Length = PLCP(5)+MACHeader(24)+CRC(4)+RxStatus(8) */ ++ if (frameLen < 24) ++ { ++ return ZM_ERR_MIN_RX_FRAME_LENGTH; ++ } ++ } ++ ++ /* Check if frame Length > ZM_WLAN_MAX_RX_SIZE. */ ++ if (frameLen > ZM_WLAN_MAX_RX_SIZE) ++ { ++ return ZM_ERR_MAX_RX_FRAME_LENGTH; ++ } ++ } ++ else if ((frameCtrl&0xff) == 0xa4) ++ { ++ /* PsPoll */ ++ //zm_msg0_rx(ZM_LV_0, "rx pspoll"); ++ } ++ else if ((frameCtrl&0xff) == ZM_WLAN_FRAME_TYPE_BAR) ++ { ++ if (wd->sta.enableDrvBA == 1) ++ { ++ zfAggRecvBAR(dev, buf); ++ } ++ ++ return ZM_ERR_RX_BAR_FRAME; ++ } ++ else ++ { ++ return ZM_ERR_RX_FRAME_TYPE; ++ } ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ } ++ else if ( wd->wlanMode != ZM_MODE_PSEUDO ) ++ { ++ if ( (ret=zfStaRxValidateFrame(dev, buf))!=ZM_SUCCESS ) ++ { ++ //zm_debug_msg1("discard frame, code = ", ret); ++ return ret; ++ } ++ } ++ ++ return ZM_SUCCESS; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfWlanRxFilter */ ++/* Filter duplicated frame. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : received 802.11 frame buffer. */ ++/* */ ++/* OUTPUTS */ ++/* Error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u16_t zfWlanRxFilter(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t src[3]; ++ u16_t dst0; ++ u16_t frameType; ++ u16_t seq; ++ u16_t offset; ++ u16_t index; ++ u16_t col; ++ u16_t i; ++ u8_t up = 0; /* User priority */ ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ ZM_BUFFER_TRACE(dev, buf) ++ ++ /* RX PREFIX */ ++ offset = 0; ++ ++ frameType = zmw_rx_buf_readh(dev, buf, offset); ++ ++ // Don't divide 2^4 because we don't want the fragementation pkt to be treated as ++ // duplicated frames ++ seq = zmw_rx_buf_readh(dev, buf, offset+22); ++ dst0 = zmw_rx_buf_readh(dev, buf, offset+4); ++ src[0] = zmw_rx_buf_readh(dev, buf, offset+10); ++ src[1] = zmw_rx_buf_readh(dev, buf, offset+12); ++ src[2] = zmw_rx_buf_readh(dev, buf, offset+14); ++ ++ /* QoS data frame */ ++ if ((frameType & 0x88) == 0x88) ++ { ++ up = zmw_rx_buf_readb(dev, buf, offset+24); ++ up &= 0x7; ++ } ++ ++ index = (src[2]+up) & (ZM_FILTER_TABLE_ROW-1); ++ ++ /* TBD : filter frame with source address == own MAC adress */ ++ if ((wd->macAddr[0] == src[0]) && (wd->macAddr[1] == src[1]) ++ && (wd->macAddr[2] == src[2])) ++ { ++ //zm_msg0_rx(ZM_LV_0, "Rx filter=>src is own MAC"); ++ wd->trafTally.rxSrcIsOwnMac++; ++#if 0 ++ return ZM_ERR_RX_SRC_ADDR_IS_OWN_MAC; ++#endif ++ } ++ ++ zm_msg2_rx(ZM_LV_2, "Rx seq=", seq); ++ ++ /* Filter unicast frame only */ ++ if ((dst0 & 0x1) == 0) ++ { ++ zmw_enter_critical_section(dev); ++ ++ for(i=0; irxFilterTbl[i][index].addr[0] == src[0]) ++ && (wd->rxFilterTbl[i][index].addr[1] == src[1]) ++ && (wd->rxFilterTbl[i][index].addr[2] == src[2]) ++ && (wd->rxFilterTbl[i][index].up == up)) ++ { ++ if (((frameType&0x800)==0x800) ++ &&(wd->rxFilterTbl[i][index].seq==seq)) ++ { ++ zmw_leave_critical_section(dev); ++ /* hit : duplicated frame */ ++ zm_msg0_rx(ZM_LV_1, "Rx filter hit=>duplicated"); ++ wd->trafTally.rxDuplicate++; ++ return ZM_ERR_RX_DUPLICATE; ++ } ++ else ++ { ++ /* hit : not duplicated frame, update sequence number */ ++ wd->rxFilterTbl[i][index].seq = seq; ++ zmw_leave_critical_section(dev); ++ zm_msg0_rx(ZM_LV_2, "Rx filter hit"); ++ return ZM_SUCCESS; ++ } ++ } ++ } /* for(i=0; itick & (ZM_FILTER_TABLE_COL-1)); ++ wd->rxFilterTbl[col][index].addr[0] = src[0]; ++ wd->rxFilterTbl[col][index].addr[1] = src[1]; ++ wd->rxFilterTbl[col][index].addr[2] = src[2]; ++ wd->rxFilterTbl[col][index].seq = seq; ++ wd->rxFilterTbl[col][index].up = up; ++ ++ zmw_leave_critical_section(dev); ++ } /* if ((dst0 & 0x1) == 0) */ ++ ++ return ZM_SUCCESS; ++} ++ ++ ++ ++u16_t zfTxGenWlanTail(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t snaplen, ++ u16_t* mic) ++{ ++ struct zsMicVar* pMicKey; ++ u16_t i, length, payloadOffset; ++ u8_t bValue, qosType = 0; ++ u8_t snapByte[12]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ pMicKey = zfApGetTxMicKey(dev, buf, &qosType); ++ ++ if ( pMicKey == NULL ) ++ { ++ return 0; ++ } ++ } ++ else if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ pMicKey = zfStaGetTxMicKey(dev, buf); ++ ++ if ( pMicKey == NULL ) ++ { ++ return 0; ++ } ++ } ++ else ++ { ++ return 0; ++ } ++ ++ length = zfwBufGetSize(dev, buf); ++ ++ zfMicClear(pMicKey); ++ ++ /* append DA and SA */ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++ for(i=16; i<22; i++) ++ { // VISTA DA ++ bValue = zmw_tx_buf_readb(dev, buf, i); ++ zfMicAppendByte(bValue, pMicKey); ++ } ++ for(i=10; i<16; i++) ++ { // VISTA SA ++ bValue = zmw_tx_buf_readb(dev, buf, i); ++ zfMicAppendByte(bValue, pMicKey); ++ } ++#else ++ for(i=0; i<12; i++) ++ { ++ bValue = zmw_tx_buf_readb(dev, buf, i); ++ zfMicAppendByte(bValue, pMicKey); ++ } ++#endif ++ ++ /* append for alignment */ ++ if ( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ { ++ if (wd->sta.wmeConnected != 0) ++ zfMicAppendByte(zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET + 1) >> 5, pMicKey); ++ else ++ zfMicAppendByte(0, pMicKey); ++ } ++ else if ( wd->wlanMode == ZM_MODE_AP ) ++ { ++ if (qosType == 1) ++ zfMicAppendByte(zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET + 1) >> 5, pMicKey); ++ else ++ zfMicAppendByte(0, pMicKey); ++ } ++ else ++ { ++ /* TODO : Qos Software MIC in IBSS Mode */ ++ zfMicAppendByte(0, pMicKey); ++ } ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ zfMicAppendByte(0, pMicKey); ++ ++ if ( snaplen == 0 ) ++ { ++ payloadOffset = ZM_80211_FRAME_IP_OFFSET; ++ } ++ else ++ { ++ payloadOffset = ZM_80211_FRAME_TYPE_OFFSET; ++ ++ for(i=0; i<(snaplen>>1); i++) ++ { ++ snapByte[i*2] = (u8_t) (snap[i] & 0xff); ++ snapByte[i*2+1] = (u8_t) ((snap[i] >> 8) & 0xff); ++ } ++ ++ for(i=0; i= 34) //Minimum IPv4 packet size, 14(Ether header)+20(IPv4 header) ++ { ++ etherType = (((u16_t)zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_TYPE_OFFSET))<<8) ++ + zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_TYPE_OFFSET + 1); ++ ++ /* protocol type = IP */ ++ if (etherType == 0x0800) ++ { ++ ipv = zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET) >> 4; ++ if (ipv == 0x4) //IPv4 ++ { ++ tos = zmw_tx_buf_readb(dev, buf, ZM_80211_FRAME_IP_OFFSET + 1); ++ *up = (tos >> 5); ++ *fragOff = zmw_tx_buf_readh(dev, buf, ZM_80211_FRAME_IP_OFFSET + 6); ++ } ++ /* TODO : handle VLAN tag and IPv6 packet */ ++ } ++ } ++ return; ++} ++ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++u16_t zfTxGenWlanSnap(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t* snaplen) ++{ ++ snap[0] = zmw_buf_readh(dev, buf, ZM_80211_FRAME_HEADER_LEN + 0); ++ snap[1] = zmw_buf_readh(dev, buf, ZM_80211_FRAME_HEADER_LEN + 2); ++ snap[2] = zmw_buf_readh(dev, buf, ZM_80211_FRAME_HEADER_LEN + 4); ++ *snaplen = 6; ++ ++ return ZM_80211_FRAME_HEADER_LEN + *snaplen; ++} ++#else ++u16_t zfTxGenWlanSnap(zdev_t* dev, zbuf_t* buf, u16_t* snap, u16_t* snaplen) ++{ ++ u16_t removed; ++ u16_t etherType; ++ u16_t len; ++ ++ len = zfwBufGetSize(dev, buf); ++ if (len < 14) //Minimum Ethernet packet size, 14(Ether header) ++ { ++ /* TODO : Assert? */ ++ *snaplen = 0; ++ return 0; ++ } ++ ++ /* Generate RFC1042 header */ ++ etherType = (((u16_t)zmw_tx_buf_readb(dev, buf, 12))<<8) ++ + zmw_tx_buf_readb(dev, buf, 13); ++ ++ //zm_debug_msg2("ethernet type or length = ", etherType); ++ ++ if (etherType > 1500) ++ { ++ /* ETHERNET format */ ++ removed = 12; ++ snap[0] = 0xaaaa; ++ snap[1] = 0x0003; ++ if ((etherType ==0x8137) || (etherType == 0x80f3)) ++ { ++ /* Bridge Tunnel */ ++ snap[2] = 0xF800; ++ } ++ else ++ { ++ /* RFC 1042 */ ++ snap[2] = 0x0000; ++ } ++ *snaplen = 6; ++ ++ if ( etherType == 0x888E ) ++ { ++ zfShowTxEAPOL(dev, buf, 14); ++ } ++ } ++ else ++ { ++ /* 802.3 format */ ++ removed = 14; ++ *snaplen = 0; ++ } ++ ++ return removed; ++} ++#endif ++ ++u8_t zfIsVtxqEmpty(zdev_t* dev) ++{ ++ u8_t isEmpty = TRUE; ++ u8_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (wd->vmmqHead != wd->vmmqTail) ++ { ++ isEmpty = FALSE; ++ goto check_done; ++ } ++ ++ for(i=0; i < 4; i++) ++ { ++ if (wd->vtxqHead[i] != wd->vtxqTail[i]) ++ { ++ isEmpty = FALSE; ++ goto check_done; ++ } ++ } ++ ++check_done: ++ zmw_leave_critical_section(dev); ++ return isEmpty; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfPutVtxq */ ++/* Put Tx buffer to virtual TxQ */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : Tx buffer pointer */ ++/* */ ++/* OUTPUTS */ ++/* ZM_SUCCESS or error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++u16_t zfPutVtxq(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t ac; ++ u8_t up; ++ u16_t fragOff; ++#ifdef ZM_AGG_TALLY ++ struct aggTally *agg_tal; ++#endif ++#ifdef ZM_ENABLE_AGGREGATION ++ #ifndef ZM_BYPASS_AGGR_SCHEDULING ++ u16_t ret; ++ u16_t tid; ++ #endif ++#endif ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zfTxGetIpTosAndFrag(dev, buf, &up, &fragOff); ++ ++ if ( wd->zfcbClassifyTxPacket != NULL ) ++ { ++ ac = wd->zfcbClassifyTxPacket(dev, buf); ++ } ++ else ++ { ++ ac = zcUpToAc[up&0x7] & 0x3; ++ } ++ ++ /* ++ * add by honda ++ * main A-MPDU aggregation function ++ */ ++#ifdef ZM_AGG_TALLY ++ agg_tal = &wd->agg_tal; ++ agg_tal->got_packets_sum++; ++ ++#endif ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ #ifndef ZM_BYPASS_AGGR_SCHEDULING ++ tid = up&0x7; ++ if(wd->enableAggregation==0) ++ { ++ if( (wd->wlanMode == ZM_MODE_AP) || ++ (wd->wlanMode == ZM_MODE_INFRASTRUCTURE && wd->sta.EnableHT) || ++ (wd->wlanMode == ZM_MODE_PSEUDO) ) { ++ // (infrastructure_mode && connect_to_11n_ap) || (ap_mode && is_11n_ap) ++ //ret = zfAggPutVtxq(dev, buf); ++ ++ ++ ret = zfAggTx(dev, buf, tid); ++ if (ZM_SUCCESS == ret) ++ { ++ //zfwBufFree(dev, buf, ZM_SUCCESS); ++ ++ return ZM_SUCCESS; ++ } ++ if (ZM_ERR_EXCEED_PRIORITY_THRESHOLD == ret) ++ { ++ wd->commTally.txQosDropCount[ac]++; ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ ++ zm_msg1_tx(ZM_LV_1, "Packet discarded, VTXQ full, ac=", ac); ++ ++ return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; ++ } ++ if (ZM_ERR_TX_BUFFER_UNAVAILABLE == ret) ++ { ++ /* ++ * do nothing ++ * continue following procession, put into VTXQ ++ * return ZM_SUCCESS; ++ */ ++ } ++ } ++ } ++ #endif ++#endif ++ /* ++ * end of add by honda ++ */ ++ ++ /* First Ip frag */ ++ if ((fragOff & 0xff3f) == 0x0020) ++ { ++ /* Don't let ip frag in if VTXQ unable to hold */ ++ /* whole ip frag burst(assume 20 frag) */ ++ zmw_enter_critical_section(dev); ++ if (((wd->vtxqHead[ac] - wd->vtxqTail[ac])& ZM_VTXQ_SIZE_MASK) ++ > (ZM_VTXQ_SIZE-20)) ++ { ++ wd->qosDropIpFrag[ac] = 1; ++ } ++ else ++ { ++ wd->qosDropIpFrag[ac] = 0; ++ } ++ zmw_leave_critical_section(dev); ++ ++ if (wd->qosDropIpFrag[ac] == 1) ++ { ++ //zm_debug_msg2("vtQ full, drop buf = ", buf); ++ wd->commTally.txQosDropCount[ac]++; ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ zm_msg1_tx(ZM_LV_1, "Packet discarded, first ip frag, ac=", ac); ++ //VTXQ[] can not hold whold ip frag burst(assume 20 frags) ++ return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; ++ } ++ } ++ else if ((fragOff & 0xff3f) == 0) ++ { ++ wd->qosDropIpFrag[ac] = 0; ++ } ++ ++ if (((fragOff &= 0xff1f) != 0) && (wd->qosDropIpFrag[ac] == 1)) ++ { ++ wd->commTally.txQosDropCount[ac]++; ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ zm_msg1_tx(ZM_LV_1, "Packet discarded, ip frag, ac=", ac); ++ //Discard following ip frags ++ return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; ++ } ++ ++ zmw_enter_critical_section(dev); ++ if (((wd->vtxqHead[ac] + 1) & ZM_VTXQ_SIZE_MASK) != wd->vtxqTail[ac]) ++ { ++ wd->vtxq[ac][wd->vtxqHead[ac]] = buf; ++ wd->vtxqHead[ac] = ((wd->vtxqHead[ac] + 1) & ZM_VTXQ_SIZE_MASK); ++ zmw_leave_critical_section(dev); ++ return ZM_SUCCESS; ++ } ++ else ++ { ++ zmw_leave_critical_section(dev); ++ ++ wd->commTally.txQosDropCount[ac]++; ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ zm_msg1_tx(ZM_LV_1, "Packet discarded, VTXQ full, ac=", ac); ++ return ZM_ERR_EXCEED_PRIORITY_THRESHOLD; //VTXQ[] Full ++ } ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfGetVtxq */ ++/* Get Tx buffer from virtual TxQ */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* Tx buffer pointer */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++zbuf_t* zfGetVtxq(zdev_t* dev, u8_t ac) ++{ ++ zbuf_t* buf; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ ac &= 0x3; ++ zmw_enter_critical_section(dev); ++ if (wd->vtxqHead[ac] != wd->vtxqTail[ac]) ++ { ++ buf = wd->vtxq[ac][wd->vtxqTail[ac]]; ++ wd->vtxqTail[ac] = ((wd->vtxqTail[ac] + 1) & ZM_VTXQ_SIZE_MASK); ++ zmw_leave_critical_section(dev); ++ return buf; ++ } ++ else ++ { ++ zmw_leave_critical_section(dev); ++ return 0; //VTXQ[] empty ++ } ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfPutVmmq */ ++/* Put Tx buffer to virtual MmQ */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* buf : Tx buffer pointer */ ++/* */ ++/* OUTPUTS */ ++/* ZM_SUCCESS or error code */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.12 */ ++/* */ ++/************************************************************************/ ++u16_t zfPutVmmq(zdev_t* dev, zbuf_t* buf) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (((wd->vmmqHead + 1) & ZM_VMMQ_SIZE_MASK) != wd->vmmqTail) ++ { ++ wd->vmmq[wd->vmmqHead] = buf; ++ wd->vmmqHead = ((wd->vmmqHead + 1) & ZM_VMMQ_SIZE_MASK); ++ zmw_leave_critical_section(dev); ++ return ZM_SUCCESS; ++ } ++ else ++ { ++ zmw_leave_critical_section(dev); ++ ++ zfwBufFree(dev, buf, ZM_SUCCESS); ++ zm_msg0_mm(ZM_LV_0, "Packet discarded, VMmQ full"); ++ return ZM_ERR_VMMQ_FULL; //VTXQ[] Full ++ } ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfGetVmmq */ ++/* Get Tx buffer from virtual MmQ */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* Tx buffer pointer */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.12 */ ++/* */ ++/************************************************************************/ ++zbuf_t* zfGetVmmq(zdev_t* dev) ++{ ++ zbuf_t* buf; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if (wd->vmmqHead != wd->vmmqTail) ++ { ++ buf = wd->vmmq[wd->vmmqTail]; ++ wd->vmmqTail = ((wd->vmmqTail + 1) & ZM_VMMQ_SIZE_MASK); ++ zmw_leave_critical_section(dev); ++ return buf; ++ } ++ else ++ { ++ zmw_leave_critical_section(dev); ++ return 0; //VTXQ[] empty ++ } ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfPushVtxq */ ++/* Service Virtual TxQ (weighted round robin) */ ++/* Get Tx buffer form virtual TxQ and put to hardware TxD queue */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++void zfPushVtxq(zdev_t* dev) ++{ ++ zbuf_t* buf; ++ u16_t i; ++ u16_t txed; ++ u32_t freeTxd; ++ u16_t err; ++ u16_t skipFlag = 0; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ ++ ++ //zm_debug_msg1("zfHpGetFreeTxdCount = ", zfHpGetFreeTxdCount(dev)); ++ ++ if (wd->halState == ZM_HAL_STATE_INIT) ++ { ++ if (!wd->modeMDKEnable) ++ { ++ zm_debug_msg0("HAL is not ready for Tx"); ++ } ++ return; ++ } ++ else if (wd->sta.DFSDisableTx) ++ { ++ zm_debug_msg0("return because 802.11h DFS Disable Tx"); ++ return; ++ } ++ else if (wd->sta.flagFreqChanging != 0) ++ { ++ //Hold until RF frequency changed ++ return; ++ } ++ else if (( wd->sta.flagKeyChanging ) && ( wd->wlanMode != ZM_MODE_AP )) ++ { ++ return; ++ } ++#ifdef ZM_ENABLE_POWER_SAVE ++ else if ( zfPowerSavingMgrIsSleeping(dev) ) ++ { ++ //zm_debug_msg0("Packets queued since the MAC is in power-saving mode\n"); ++ return; ++ } ++#endif ++ ++ zmw_enter_critical_section(dev); ++ if (wd->vtxqPushing != 0) ++ { ++ skipFlag = 1; ++ } ++ else ++ { ++ wd->vtxqPushing = 1; ++ } ++ zmw_leave_critical_section(dev); ++ ++ if (skipFlag == 1) ++ { ++ return; ++ } ++ ++ while (1) ++ { ++ txed = 0; ++ ++ /* 2006.12.20, Serve Management queue */ ++ while( zfHpGetFreeTxdCount(dev) > 0 ) ++ { ++ if ((buf = zfGetVmmq(dev)) != 0) ++ { ++ txed = 1; ++ //zm_debug_msg2("send buf = ", buf); ++ if ((err = zfHpSend(dev, NULL, 0, NULL, 0, NULL, 0, buf, 0, ++ ZM_INTERNAL_ALLOC_BUF, 0, 0xff)) != ZM_SUCCESS) ++ { ++ zfwBufFree(dev, buf, 0); ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ if ((wd->sta.bScheduleScan) || ((wd->sta.bChannelScan == TRUE) && (zfStaIsConnected(dev)))) ++ { ++ //Hold until Scan Stop ++ wd->vtxqPushing = 0; ++ return; ++ } ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ #ifndef ZM_BYPASS_AGGR_SCHEDULING ++ if( (wd->wlanMode == ZM_MODE_AP) || ++ (wd->wlanMode == ZM_MODE_INFRASTRUCTURE && wd->sta.EnableHT) || ++ (wd->wlanMode == ZM_MODE_PSEUDO) ) { ++ ++ zfAggTxScheduler(dev, 0); ++ ++ if (txed == 0) { ++ wd->vtxqPushing = 0; ++ return; ++ } ++ else { ++ continue; ++ } ++ } ++ #endif ++#endif ++ ++ /* Service VTxQ[3] */ ++ for (i=0; i<4; i++) ++ { ++ if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= 3) ++ { ++ if ((buf = zfGetVtxq(dev, 3)) != 0) ++ { ++ txed = 1; ++ //zm_debug_msg2("send buf = ", buf); ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ /* Service VTxQ[2] */ ++ for (i=0; i<3; i++) ++ { ++ if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= (zfHpGetMaxTxdCount(dev)*1/4)) ++ { ++ if ((buf = zfGetVtxq(dev, 2)) != 0) ++ { ++ txed = 1; ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); ++ } ++ if (wd->sta.ac0PriorityHigherThanAc2 == 1) ++ { ++ if ((buf = zfGetVtxq(dev, 0)) != 0) ++ { ++ txed = 1; ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); ++ } ++ } ++ } ++ else ++ { ++ break; ++ } ++ } ++ ++ /* Service VTxQ[0] */ ++ for (i=0; i<2; i++) ++ { ++ if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= (zfHpGetMaxTxdCount(dev)*2/4)) ++ { ++ if ((buf = zfGetVtxq(dev, 0)) != 0) ++ { ++ txed = 1; ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); ++ } ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ ++ /* Service VTxQ[1] */ ++ if ((freeTxd = zfHpGetFreeTxdCount(dev)) >= (zfHpGetMaxTxdCount(dev)*3/4)) ++ { ++ if ((buf = zfGetVtxq(dev, 1)) != 0) ++ { ++ txed = 1; ++ zfTxSendEth(dev, buf, 0, ZM_EXTERNAL_ALLOC_BUF, 0); ++ ZM_PERFORMANCE_TX_MPDU(dev, wd->tick); ++ } ++ } ++ ++ /* All VTxQs are either empty or exceed their threshold */ ++ if (txed == 0) ++ { ++ wd->vtxqPushing = 0; ++ return; ++ } ++ } //while (1) ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfFlushVtxq */ ++/* Flush Virtual TxQ and MmQ */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.1 */ ++/* */ ++/************************************************************************/ ++void zfFlushVtxq(zdev_t* dev) ++{ ++ zbuf_t* buf; ++ u8_t i; ++ zmw_get_wlan_dev(dev); ++ ++ /* Flush MmQ */ ++ while ((buf = zfGetVmmq(dev)) != 0) ++ { ++ zfwBufFree(dev, buf, 0); ++ zm_debug_msg0("zfFlushVtxq: [Vmmq]"); ++ wd->queueFlushed |= 0x10; ++ } ++ ++ /* Flush VTxQ */ ++ for (i=0; i<4; i++) ++ { ++ while ((buf = zfGetVtxq(dev, i)) != 0) ++ { ++ zfwBufFree(dev, buf, 0); ++ zm_debug_msg1("zfFlushVtxq: [zfGetVtxq]- ", i); ++ wd->queueFlushed |= (1<commTally.txUnicastFrm++; ++ wd->commTally.txUnicastOctets += (fragLen+snapLen); ++ } ++ else if (da[0] == 0xffff) ++ { ++ wd->commTally.txBroadcastFrm++; ++ wd->commTally.txBroadcastOctets += (fragLen+snapLen); ++ } ++ else ++ { ++ wd->commTally.txMulticastFrm++; ++ wd->commTally.txMulticastOctets += (fragLen+snapLen); ++ } ++ wd->ledStruct.txTraffic++; ++ ++ if ((err = zfHpSend(dev, header, headerLen, snap, snapLen, ++ tail, tailLen, buf, offset, ++ bufType, ac, keyIdx)) != ZM_SUCCESS) ++ { ++ if (bufType == ZM_EXTERNAL_ALLOC_BUF) ++ { ++ zfwBufFree(dev, buf, err); ++ } ++ else if (bufType == ZM_INTERNAL_ALLOC_BUF) ++ { ++ zfwBufFree(dev, buf, 0); ++ } ++ else ++ { ++ zm_assert(0); ++ } ++ } ++} ++ ++void zfCheckIsRIFSFrame(zdev_t* dev, zbuf_t* buf, u16_t frameSubtype) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* #2 Record the sequence number to determine whether the unicast frame is separated by RIFS or not */ ++ if (frameSubtype & 0x80) ++ { //QoS data frame ++ u16_t sequenceNum; ++ u16_t qosControlField; ++ ++ sequenceNum = ( zmw_buf_readh(dev, buf, 22) >> 4 ); // Discard fragment number ! ++ qosControlField = zmw_buf_readh(dev, buf, 24); // Don't consider WDS (Wireless Distribution System) ++ //DbgPrint("The QoS Control Field : %d", qosControlField); ++ //DbgPrint("The RIFS Count : %d", wd->sta.rifsCount); ++ ++ if( qosControlField & ZM_BIT_5 ) ++ {// ACK policy is "No ACK" ++ /* RIFS-Like frame */ ++ wd->sta.rifsLikeFrameSequence[wd->sta.rifsLikeFrameCnt] = sequenceNum; ++ ++ if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTING ) ++ { ++ if( wd->sta.rifsLikeFrameSequence[2] != 0 ) ++ {// RIFS-like Pattern collected ++ if( ( wd->sta.rifsLikeFrameSequence[2] - wd->sta.rifsLikeFrameSequence[1] == 2 ) && ++ ( wd->sta.rifsLikeFrameSequence[1] - wd->sta.rifsLikeFrameSequence[0] == 2 ) ) ++ { ++ /* RIFS pattern matched */ ++ ++ /* #3 Enable RIFS function if the RIFS pattern matched */ ++ zfHpEnableRifs(dev, ((wd->sta.currentFrequency<3000)?1:0), wd->sta.EnableHT, wd->sta.HT2040); ++ ++ // Set RIFS timer ++ wd->sta.rifsTimer = wd->tick; ++ ++ wd->sta.rifsCount++; ++ ++ // Set state to be Detected ++ wd->sta.rifsState = ZM_RIFS_STATE_DETECTED; ++ } ++ } ++ } ++ else ++ {// state = Detected ++ // Reset RIFS timer ++ if( (wd->tick - wd->sta.rifsTimer) < ZM_RIFS_TIMER_TIMEOUT ) ++ wd->sta.rifsTimer = wd->tick; ++ } ++ ++ //DbgPrint("SN1 = %d, SN2 = %d, SN3 = %d\n", wd->sta.rifsLikeFrameSequence[0], ++ // wd->sta.rifsLikeFrameSequence[1], ++ // wd->sta.rifsLikeFrameSequence[2]); ++ ++ // Update RIFS-like sequence number ++ if( wd->sta.rifsLikeFrameSequence[2] != 0 ) ++ { ++ wd->sta.rifsLikeFrameSequence[0] = wd->sta.rifsLikeFrameSequence[1]; ++ wd->sta.rifsLikeFrameSequence[1] = wd->sta.rifsLikeFrameSequence[2]; ++ wd->sta.rifsLikeFrameSequence[2] = 0; ++ } ++ ++ // Only record three adjacent frame ++ if( wd->sta.rifsLikeFrameCnt < 2 ) ++ wd->sta.rifsLikeFrameCnt++; ++ } ++ } ++ ++ /* #4 Disable RIFS function if the timer TIMEOUT */ ++ if( wd->sta.rifsState == ZM_RIFS_STATE_DETECTED ) ++ { ++ if( ( wd->tick - wd->sta.rifsTimer ) > ZM_RIFS_TIMER_TIMEOUT ) ++ {// TIMEOUT ++ // Disable RIFS ++ zfHpDisableRifs(dev); ++ ++ // Reset RIFS-like sequence number FIFO ++ wd->sta.rifsLikeFrameSequence[0] = 0; ++ wd->sta.rifsLikeFrameSequence[1] = 0; ++ wd->sta.rifsLikeFrameSequence[2] = 0; ++ wd->sta.rifsLikeFrameCnt = 0; ++ ++ // Set state to be Detecting ++ wd->sta.rifsState = ZM_RIFS_STATE_DETECTING; ++ } ++ } ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cwep.c +@@ -0,0 +1,299 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : cwep.c */ ++/* */ ++/* Abstract */ ++/* This module contains Tx and Rx functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++ ++u32_t crc32_tab[] = ++{ ++ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, ++ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, ++ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, ++ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, ++ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, ++ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, ++ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, ++ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, ++ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, ++ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, ++ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, ++ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, ++ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, ++ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, ++ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, ++ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, ++ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, ++ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, ++ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, ++ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, ++ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, ++ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, ++ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, ++ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, ++ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, ++ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, ++ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, ++ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, ++ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, ++ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, ++ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, ++ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, ++ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, ++ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, ++ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, ++ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, ++ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, ++ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, ++ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, ++ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, ++ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, ++ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, ++ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, ++ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, ++ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, ++ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, ++ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, ++ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, ++ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, ++ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, ++ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, ++ 0x2d02ef8dL ++}; ++ ++void zfWEPEncrypt(zdev_t *dev, zbuf_t *buf, u8_t *snap, u16_t snapLen, u16_t offset, u8_t keyLen, u8_t* WepKey, u8_t *iv) ++{ ++ u8_t S[256],S2[256]; ++ u16_t ui; ++ u16_t i; ++ u16_t j; ++ u8_t temp; ++ u8_t K; ++ u32_t ltemp; ++ u16_t len; ++ u32_t icv; ++ u8_t key[32]; ++ ++ key[0] = iv[0]; ++ key[1] = iv[1]; ++ key[2] = iv[2]; ++ ++ /* Append Wep Key after IV */ ++ zfMemoryCopy(&key[3], WepKey, keyLen); ++ ++ keyLen += 3; ++ ++ for(i = 0; i < 256; i++) ++ { ++ S[i] = (u8_t)i; ++ S2[i] = key[i&(keyLen-1)]; ++ } ++ ++ j = 0; ++ for(i = 0; i < 256; i++) ++ { ++ j = (j + S[i] + S2[i]) ; ++ j&=255 ; ++ ++ // Swap S[i] and S[j] ++ temp = S[i]; ++ S[i] = S[j]; ++ S[j] = temp; ++ } ++ ++ i = j = 0; ++ icv = -1; ++ ++ /* For Snap Header */ ++ for (ui = 0; ui < snapLen; ui++) ++ { ++ u8_t In; ++ ++ i++; ++ i &= 255; ++ j += S[i]; ++ j &= 255; ++ ++ // Swap S[i] and S[j] ++ temp = S[i]; ++ S[i] = S[j]; ++ S[j] = temp; ++// temp = (S[i] + temp) & 255; ++ temp += S[i]; ++ temp &=255; ++ K = S[temp]; // Key used to Xor with input data ++ ++ In = snap[ui]; ++ icv = (icv>>8) ^ crc32_tab[(icv^In)&0xff]; ++ ++ snap[ui] = In ^ K; ++ //zmw_tx_buf_writeb(dev, buf, ui, In ^ K); ++ } ++ ++ len = zfwBufGetSize(dev, buf); ++ ++ for (ui = offset; ui < len; ui++) ++ { ++ u8_t In; ++ ++ i++; ++ i &= 255; ++ j += S[i]; ++ j &= 255; ++ ++ // Swap S[i] and S[j] ++ temp = S[i]; ++ S[i] = S[j]; ++ S[j] = temp; ++// temp = (S[i] + temp) & 255; ++ temp += S[i]; ++ temp &=255; ++ K = S[temp]; // Key used to Xor with input data ++ ++ In = zmw_tx_buf_readb(dev, buf, ui); ++ icv = (icv>>8) ^ crc32_tab[(icv^In)&0xff]; ++ ++ zmw_tx_buf_writeb(dev, buf, ui, In ^ K); ++ } //End of for (ui = 0; ui < Num_Bytes; ui++) ++ ++ icv = ~(icv); ++ ltemp = (u32_t) icv; ++ ++ for (ui = 0; ui < 4; ui++) ++ { ++ i ++; ++ i &= 255; ++ j += S[i]; ++ j &= 255; ++ ++ // Swap S[i] and S[j] ++ temp = S[i]; ++ S[i] = S[j]; ++ S[j] = temp; ++ temp += S[i]; ++ temp &= 255; ++ K = S[temp]; // Key used to Xor with input data ++ ++ //*Out++ = (u8_t)(ltemp ^ K)&0xff; ++ zmw_tx_buf_writeb(dev, buf, len+ui, (u8_t)(ltemp ^ K)&0xff); ++ ltemp >>= 8; ++ } ++ ++ zfwBufSetSize(dev, buf, len+4); ++} ++ ++u16_t zfWEPDecrypt(zdev_t *dev, zbuf_t *buf, u16_t offset, u8_t keyLen, u8_t* WepKey, u8_t *iv) ++{ ++ u8_t S[256]; ++ u8_t S2[256]; ++ u16_t ui; ++ u16_t i; ++ u16_t j; ++ u32_t icv_tmp; ++ u32_t *icv; ++ u32_t rxbuf_icv; ++ u8_t temp; ++ u8_t K; ++ u16_t len; ++ u8_t key[32]; ++ ++ /* Retrieve IV */ ++ key[0] = iv[0]; ++ key[1] = iv[1]; ++ key[2] = iv[2]; ++ ++ /* Append Wep Key after IV */ ++ zfMemoryCopy(&key[3], WepKey, keyLen); ++ ++ keyLen += 3; ++ ++ for(i = 0; i < 256; i++) ++ { ++ S[i] = (u8_t)i; ++ S2[i] = key[i&(keyLen-1)]; ++ } ++ ++ j = 0; ++ for(i = 0; i < 256; i++) ++ { ++ j = (j + S[i] + S2[i]); ++ j&=255 ; ++ ++ // Swap S[i] and S[j] ++ temp = S[i]; ++ S[i] = S[j]; ++ S[j] = temp; ++ } ++ ++ i = j = 0; ++ ++ len = zfwBufGetSize(dev, buf); ++ ++ for (ui = offset; ui < len; ui++) ++ { ++ u8_t In; ++ ++ i++; ++ i &= 255; ++ j += S[i]; ++ j &= 255; ++ ++ // Swap S[i] and S[j] ++ temp = S[i]; ++ S[i] = S[j]; ++ S[j] = temp; ++// temp = (S[i] + temp) & 255; ++ temp += S[i]; ++ temp &=255; ++ K = S[temp]; // Key used to Xor with input data ++ ++ In = zmw_rx_buf_readb(dev, buf, ui); ++ ++ zmw_rx_buf_writeb(dev, buf, ui, In ^ K); ++ } //End of for (ui = 0; ui < Num_Bytes; ui++) ++ ++ icv = &icv_tmp; ++ *icv = -1; ++ ++ for (ui = offset; ui < len - 4; ui++) ++ { ++ u8_t In; ++ ++ In = zmw_rx_buf_readb(dev, buf, ui); ++ *icv = (*icv>>8) ^ crc32_tab[(*icv^In)&0xff]; ++ } ++ ++ *icv = ~*icv; ++ ++ rxbuf_icv = (zmw_rx_buf_readb(dev, buf, len-4) | ++ zmw_rx_buf_readb(dev, buf, len-3) << 8 | ++ zmw_rx_buf_readb(dev, buf, len-2) << 16 | ++ zmw_rx_buf_readb(dev, buf, len-1) << 24); ++ ++ if (*icv != rxbuf_icv) ++ { ++ return ZM_ICV_FAILURE; ++ } ++ ++ return ZM_ICV_SUCCESS; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cwm.c +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : cwm.c */ ++/* */ ++/* Abstract */ ++/* This module contains channel width related functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#include "cprecomp.h" ++ ++ ++ ++void zfCwmInit(zdev_t* dev) { ++ //u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ switch (wd->wlanMode) { ++ case ZM_MODE_AP: ++ wd->cwm.cw_mode = CWM_MODE2040; ++ wd->cwm.cw_width = CWM_WIDTH40; ++ wd->cwm.cw_enable = 1; ++ break; ++ case ZM_MODE_INFRASTRUCTURE: ++ case ZM_MODE_PSEUDO: ++ case ZM_MODE_IBSS: ++ default: ++ wd->cwm.cw_mode = CWM_MODE2040; ++ wd->cwm.cw_width = CWM_WIDTH20; ++ wd->cwm.cw_enable = 1; ++ break; ++ } ++} ++ ++ ++void zfCoreCwmBusy(zdev_t* dev, u16_t busy) ++{ ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg1_mm(ZM_LV_0, "CwmBusy=", busy); ++ ++ if(wd->cwm.cw_mode == CWM_MODE20) { ++ wd->cwm.cw_width = CWM_WIDTH20; ++ return; ++ } ++ ++ if(wd->cwm.cw_mode == CWM_MODE40) { ++ wd->cwm.cw_width = CWM_WIDTH40; ++ return; ++ } ++ ++ if (busy) { ++ wd->cwm.cw_width = CWM_WIDTH20; ++ return; ++ } ++ ++ ++ if((wd->wlanMode == ZM_MODE_INFRASTRUCTURE || wd->wlanMode == ZM_MODE_PSEUDO || ++ wd->wlanMode == ZM_MODE_IBSS)) { ++ if (wd->sta.ie.HtCap.HtCapInfo && HTCAP_SupChannelWidthSet != 0 && ++ wd->sta.ie.HtInfo.ChannelInfo && ExtHtCap_RecomTxWidthSet != 0 && ++ (wd->sta.ie.HtInfo.ChannelInfo && ExtHtCap_ExtChannelOffsetAbove) == 1) { ++ ++ wd->cwm.cw_width = CWM_WIDTH40; ++ } ++ else { ++ wd->cwm.cw_width = CWM_WIDTH20; ++ } ++ ++ return; ++ } ++ ++ if(wd->wlanMode == ZM_MODE_AP) { ++ wd->cwm.cw_width = CWM_WIDTH40; ++ } ++ ++} ++ ++ ++ ++ ++u16_t zfCwmIsExtChanBusy(u32_t ctlBusy, u32_t extBusy) ++{ ++ u32_t busy; /* percentage */ ++ u32_t cycleTime, ctlClear; ++ ++ cycleTime = 1280000; //1.28 seconds ++ ++ if (cycleTime > ctlBusy) { ++ ctlClear = cycleTime - ctlBusy; ++ } ++ else ++ { ++ ctlClear = 0; ++ } ++ ++ /* Compute ratio of extension channel busy to control channel clear ++ * as an approximation to extension channel cleanliness. ++ * ++ * According to the hardware folks, ext rxclear is undefined ++ * if the ctrl rxclear is de-asserted (i.e. busy) ++ */ ++ if (ctlClear) { ++ busy = (extBusy * 100) / ctlClear; ++ } else { ++ busy = 0; ++ } ++ if (busy > ATH_CWM_EXTCH_BUSY_THRESHOLD) { ++ return TRUE; ++ } ++ ++ return FALSE; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/cwm.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : cwm.h */ ++/* */ ++/* Abstract */ ++/* This module contains channel width relatived functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/****************************************************************************/ ++/*Revision History: */ ++/* Who When What */ ++/* -------- -------- ----------------------------------------------*/ ++/* */ ++/* Honda 3-19-07 created */ ++/* */ ++/****************************************************************************/ ++ ++#ifndef _CWM_H ++#define _CWM_H ++ ++#define ATH_CWM_EXTCH_BUSY_THRESHOLD 30 /* Extension Channel Busy Threshold (0-100%) */ ++ ++void zfCwmInit(zdev_t* dev); ++void zfCoreCwmBusy(zdev_t* dev, u16_t busy); ++u16_t zfCwmIsExtChanBusy(u32_t ctlBusy, u32_t extBusy); ++ ++ ++ ++#endif /* #ifndef _CWM_H */ +--- /dev/null ++++ b/drivers/staging/otus/80211core/freqctrl.c +@@ -0,0 +1,259 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++ ++/* zfAddFreqChangeReq should be called inside the critical section */ ++static void zfAddFreqChangeReq(zdev_t* dev, u16_t frequency, u8_t bw40, ++ u8_t extOffset, zfpFreqChangeCompleteCb cb) ++{ ++ zmw_get_wlan_dev(dev); ++ ++//printk("zfAddFreqChangeReq freqReqQueueTail%d\n", wd->freqCtrl.freqReqQueueTail); ++ wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueTail] = frequency; ++ wd->freqCtrl.freqReqBw40[wd->freqCtrl.freqReqQueueTail] = bw40; ++ wd->freqCtrl.freqReqExtOffset[wd->freqCtrl.freqReqQueueTail] = extOffset; ++ wd->freqCtrl.freqChangeCompCb[wd->freqCtrl.freqReqQueueTail] = cb; ++ wd->freqCtrl.freqReqQueueTail++; ++ if ( wd->freqCtrl.freqReqQueueTail >= ZM_MAX_FREQ_REQ_QUEUE ) ++ { ++ wd->freqCtrl.freqReqQueueTail = 0; ++ } ++} ++ ++void zfCoreSetFrequencyV2(zdev_t* dev, u16_t frequency, zfpFreqChangeCompleteCb cb) ++{ ++ zfCoreSetFrequencyEx(dev, frequency, 0, 0, cb); ++} ++ ++void zfCoreSetFrequencyExV2(zdev_t* dev, u16_t frequency, u8_t bw40, ++ u8_t extOffset, zfpFreqChangeCompleteCb cb, u8_t forceSetFreq) ++{ ++ u8_t setFreqImmed = 0; ++ u8_t initRF = 0; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zm_msg1_scan(ZM_LV_1, "Freq=", frequency); ++ ++ zmw_enter_critical_section(dev); ++ if ((wd->sta.currentFrequency == frequency) ++ && (wd->sta.currentBw40 == bw40) ++ && (wd->sta.currentExtOffset == extOffset)) ++ { ++ if ( forceSetFreq == 0 && wd->sta.flagFreqChanging == 0 ) ++ { ++ goto done; ++ } ++ } ++#ifdef ZM_FB50 ++ /*if(frequency!=2437) { ++ zmw_leave_critical_section(dev); ++ return; ++ }*/ ++#endif ++ ++ zfAddFreqChangeReq(dev, frequency, bw40, extOffset, cb); ++ ++// zm_assert( wd->sta.flagFreqChanging == 0 ); ++ //wd->sta.flagFreqChanging = 1; ++ if ( wd->sta.flagFreqChanging == 0 ) ++ { ++ if ((wd->sta.currentBw40 != bw40) || (wd->sta.currentExtOffset != extOffset)) ++ { ++ initRF = 1; ++ } ++ wd->sta.currentFrequency = frequency; ++ wd->sta.currentBw40 = bw40; ++ wd->sta.currentExtOffset = extOffset; ++ setFreqImmed = 1; ++ } ++ wd->sta.flagFreqChanging++; ++ ++ zmw_leave_critical_section(dev); ++ ++ if ( setFreqImmed ) ++ { ++ //zfHpSetFrequency(dev, frequency, 0); ++ if ( forceSetFreq ) ++ { // Cold reset to reset the frequency after scanning ! ++ zm_debug_msg0("#6_1 20070917"); ++ zm_debug_msg0("It is happen!!! No error message"); ++ zfHpSetFrequencyEx(dev, frequency, bw40, extOffset, 2); ++ } ++ else ++ { ++ zfHpSetFrequencyEx(dev, frequency, bw40, extOffset, initRF); ++ } ++ ++ if ( zfStaIsConnected(dev) ++ && (frequency == wd->frequency)) { ++ wd->sta.connPowerInHalfDbm = zfHpGetTransmitPower(dev); ++ } ++ } ++ return; ++ ++done: ++ zmw_leave_critical_section(dev); ++ ++ if ( cb != NULL ) ++ { ++ cb(dev); ++ } ++ zfPushVtxq(dev); ++ return; ++} ++ ++void zfCoreSetFrequencyEx(zdev_t* dev, u16_t frequency, u8_t bw40, ++ u8_t extOffset, zfpFreqChangeCompleteCb cb) ++{ ++ zfCoreSetFrequencyExV2(dev, frequency, bw40, extOffset, cb, 0); ++} ++ ++void zfCoreSetFrequency(zdev_t* dev, u16_t frequency) ++{ ++ zfCoreSetFrequencyV2(dev, frequency, NULL); ++} ++ ++/* zfRemoveFreqChangeReq SHOULD NOT be called inside the critical section */ ++static void zfRemoveFreqChangeReq(zdev_t* dev) ++{ ++ zfpFreqChangeCompleteCb cb = NULL; ++ u16_t frequency; ++ u8_t bw40; ++ u8_t extOffset; ++ u16_t compFreq = 0; ++ u8_t compBw40 = 0; ++ u8_t compExtOffset = 0; ++ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (wd->freqCtrl.freqReqQueueHead != wd->freqCtrl.freqReqQueueTail) ++ { ++ zm_msg1_scan(ZM_LV_1, "Freq=", ++ wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueHead]); ++ compFreq = wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueHead]; ++ compBw40 = wd->freqCtrl.freqReqBw40[wd->freqCtrl.freqReqQueueHead]; ++ compExtOffset = wd->freqCtrl.freqReqExtOffset[wd->freqCtrl.freqReqQueueHead]; ++ ++ wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueHead] = 0; ++ cb = wd->freqCtrl.freqChangeCompCb[wd->freqCtrl.freqReqQueueHead]; ++ wd->freqCtrl.freqReqQueueHead++; ++ if ( wd->freqCtrl.freqReqQueueHead >= ZM_MAX_FREQ_REQ_QUEUE ) ++ { ++ wd->freqCtrl.freqReqQueueHead = 0; ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++ if ( cb != NULL ) ++ { ++ cb(dev); ++ } ++ ++ zmw_enter_critical_section(dev); ++ while (wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueHead] != 0) ++ { ++ frequency = wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueHead]; ++ bw40 = wd->freqCtrl.freqReqBw40[wd->freqCtrl.freqReqQueueHead]; ++ extOffset=wd->freqCtrl.freqReqExtOffset[wd->freqCtrl.freqReqQueueHead]; ++ if ((compFreq == frequency) ++ && (compBw40 == bw40) ++ && (compExtOffset == extOffset)) ++ { ++ /* Duplicated frequency command */ ++ zm_msg1_scan(ZM_LV_1, "Duplicated Freq=", frequency); ++ ++ cb = wd->freqCtrl.freqChangeCompCb[wd->freqCtrl.freqReqQueueHead]; ++ wd->freqCtrl.freqReqQueue[wd->freqCtrl.freqReqQueueHead] = 0; ++ wd->freqCtrl.freqReqQueueHead++; ++ ++ if ( wd->freqCtrl.freqReqQueueHead >= ZM_MAX_FREQ_REQ_QUEUE ) ++ { ++ wd->freqCtrl.freqReqQueueHead = 0; ++ } ++ ++ if ( wd->sta.flagFreqChanging != 0 ) ++ { ++ wd->sta.flagFreqChanging--; ++ } ++ ++ zmw_leave_critical_section(dev); ++ if ( cb != NULL ) ++ { ++ cb(dev); ++ } ++ zmw_enter_critical_section(dev); ++ } ++ else ++ { ++ u8_t initRF = 0; ++ if ((wd->sta.currentBw40 != bw40) || (wd->sta.currentExtOffset != extOffset)) ++ { ++ initRF = 1; ++ } ++ wd->sta.currentFrequency = frequency; ++ wd->sta.currentBw40 = bw40; ++ wd->sta.currentExtOffset = extOffset; ++ zmw_leave_critical_section(dev); ++ ++ zfHpSetFrequencyEx(dev, frequency, bw40, extOffset, initRF); ++ if ( zfStaIsConnected(dev) ++ && (frequency == wd->frequency)) { ++ wd->sta.connPowerInHalfDbm = zfHpGetTransmitPower(dev); ++ } ++ ++ return; ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++ return; ++} ++ ++void zfCoreSetFrequencyComplete(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zm_msg1_scan(ZM_LV_1, "flagFreqChanging=", wd->sta.flagFreqChanging); ++ ++ zmw_enter_critical_section(dev); ++ //wd->sta.flagFreqChanging = 0; ++ if ( wd->sta.flagFreqChanging != 0 ) ++ { ++ wd->sta.flagFreqChanging--; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ zfRemoveFreqChangeReq(dev); ++ ++ zfPushVtxq(dev); ++ return; ++} ++ ++void zfReSetCurrentFrequency(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg0("It is happen!!! No error message"); ++ ++ zfCoreSetFrequencyExV2(dev, wd->frequency, 0, 0, NULL, 1); ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/ledmgr.c +@@ -0,0 +1,557 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfLedCtrlType1 */ ++/* Traditional single-LED state */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.6 */ ++/* */ ++/************************************************************************/ ++// bit 15-12 : Toff for Scan state ++// 11-8 : Ton for Scan state ++// 7 : Reserved ++// 6 : mode ++//-------------------------------------- ++// bit 6 = 0 ++// 5-4 : Connect state ++// 00 => always off ++// 01 => always on ++// 10 => Idle off, acitve on ++// 11 => Idle on, active off ++//-------------------------------------- ++// bit 6 = 1 ++// 5-4 : freq ++// 00 => 1Hz ++// 01 => 0.5Hz ++// 10 => 0.25Hz ++// 11 => 0.125Hz ++//-------------------------------------- ++// 3 : Power save state ++// 0 => always off in power save state ++// 1 => works as connect state ++// 2 : Disable state ++// 1 : Reserved ++// 0 : Power-on state ++void zfLedCtrlType1(zdev_t* dev) ++{ ++ u16_t i; ++ u32_t ton, toff, tmp, period; ++ zmw_get_wlan_dev(dev); ++ ++ for (i=0; iledStruct.ledMode[i] & 0xf00) >> 8) * 5; ++ toff = ((wd->ledStruct.ledMode[i] & 0xf000) >> 12) * 5; ++ ++ if ((ton + toff) != 0) ++ { ++ tmp = wd->ledStruct.counter / (ton+toff); ++ tmp = wd->ledStruct.counter - (tmp * (ton+toff)); ++ if (tmp < ton) ++ { ++ zfHpLedCtrl(dev, i, 1); ++ } ++ else ++ { ++ zfHpLedCtrl(dev, i, 0); ++ } ++ } ++ } ++ else ++ { ++ if ((zfPowerSavingMgrIsSleeping(dev)) && ((wd->ledStruct.ledMode[i] & 0x8) == 0)) ++ { ++ zfHpLedCtrl(dev, i, 0); ++ } ++ else ++ { ++ //Connect state ++ if ((wd->ledStruct.ledMode[i] & 0x40) == 0) ++ { ++ if ((wd->ledStruct.counter & 1) == 0) ++ { ++ zfHpLedCtrl(dev, i, (wd->ledStruct.ledMode[i] & 0x10) >> 4); ++ } ++ else ++ { ++ if ((wd->ledStruct.txTraffic > 0) || (wd->ledStruct.rxTraffic > 0)) ++ { ++ wd->ledStruct.txTraffic = wd->ledStruct.rxTraffic = 0; ++ if ((wd->ledStruct.ledMode[i] & 0x20) != 0) ++ { ++ zfHpLedCtrl(dev, i, ((wd->ledStruct.ledMode[i] & 0x10) >> 4)^1); ++ } ++ } ++ } ++ }// if ((wd->ledStruct.ledMode[i] & 0x40) == 0) ++ else ++ { ++ period = 5 * (1 << ((wd->ledStruct.ledMode[i] & 0x30) >> 4)); ++ tmp = wd->ledStruct.counter / (period*2); ++ tmp = wd->ledStruct.counter - (tmp * (period*2)); ++ if (tmp < period) ++ { ++ if ((wd->ledStruct.counter & 1) == 0) ++ { ++ zfHpLedCtrl(dev, i, 0); ++ } ++ else ++ { ++ if ((wd->ledStruct.txTraffic > 0) || (wd->ledStruct.rxTraffic > 0)) ++ { ++ wd->ledStruct.txTraffic = wd->ledStruct.rxTraffic = 0; ++ zfHpLedCtrl(dev, i, 1); ++ } ++ } ++ } ++ else ++ { ++ if ((wd->ledStruct.counter & 1) == 0) ++ { ++ zfHpLedCtrl(dev, i, 1); ++ } ++ else ++ { ++ if ((wd->ledStruct.txTraffic > 0) || (wd->ledStruct.rxTraffic > 0)) ++ { ++ wd->ledStruct.txTraffic = wd->ledStruct.rxTraffic = 0; ++ zfHpLedCtrl(dev, i, 0); ++ } ++ } ++ } ++ } //else, if ((wd->ledStruct.ledMode[i] & 0x40) == 0) ++ } //else, if (zfPowerSavingMgrIsSleeping(dev)) ++ } //else : if (zfStaIsConnected(dev) != TRUE) ++ } //for (i=0; iSlow blinking, Amber then Blue per 500ms */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Shang-Chun Liu Atheros Communications, INC. 2007.11 */ ++/* */ ++/******************************************************************************/ ++void zfLedCtrlType2_scan(zdev_t* dev); ++ ++void zfLedCtrlType2(zdev_t* dev) ++{ ++ u32_t ton, toff, tmp, period; ++ u16_t OperateLED; ++ zmw_get_wlan_dev(dev); ++ ++ if (zfStaIsConnected(dev) != TRUE) ++ { ++ // Disconnect state ++ if(wd->ledStruct.counter % 4 != 0) ++ { ++ // Update LED each 400ms(4*100) ++ // Prevent this situation ++ // _______ ___ ++ // LED[0] ON | | | x | ++ // ------ OFF->+-+-+-+-+-+-+-+-+-+-+-+->>>... ++ // LED[1] ON ++ // ++ return; ++ } ++ ++ if (((wd->state == ZM_WLAN_STATE_DISABLED) && (wd->sta.bChannelScan)) ++ || ((wd->state != ZM_WLAN_STATE_DISABLED) && (wd->sta.bAutoReconnect))) ++ { ++ // Scan/AutoReconnect state ++ zfLedCtrlType2_scan(dev); ++ } ++ else ++ { ++ // Neither Connected nor Scan ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ } ++ else ++ { ++ if( wd->sta.bChannelScan ) ++ { ++ // Scan state ++ if(wd->ledStruct.counter % 4 != 0) ++ return; ++ zfLedCtrlType2_scan(dev); ++ return; ++ } ++ ++ if(wd->frequency < 3000) ++ { ++ OperateLED = 0; // LED[0]: work on 2.4G (b/g band) ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ else ++ { ++ OperateLED = 1; // LED[1]: work on 5G (a band) ++ zfHpLedCtrl(dev, 0, 0); ++ } ++ ++ if ((zfPowerSavingMgrIsSleeping(dev)) && ((wd->ledStruct.ledMode[OperateLED] & 0x8) == 0)) ++ { ++ // If Sleeping, turn OFF ++ zfHpLedCtrl(dev, OperateLED, 0); ++ } ++ else ++ { ++ //Connect state ++ if ((wd->ledStruct.counter & 1) == 0) // even ++ { ++ // No traffic, always ON ++ zfHpLedCtrl(dev, OperateLED, 1); ++ } ++ else // odd ++ { ++ if ((wd->ledStruct.txTraffic > 0) || (wd->ledStruct.rxTraffic > 0)) ++ { ++ // If have traffic, turn OFF ++ // _____ _ _ _ _____ ++ // LED[Operate] ON | | | | | | | | ++ // ------------ OFF->-+-+-+-+-+-+-+-+-+-+-+-+-+->>>... ++ // ++ wd->ledStruct.txTraffic = wd->ledStruct.rxTraffic = 0; ++ zfHpLedCtrl(dev, OperateLED, 0); ++ } ++ } ++ } ++ } ++} ++ ++void zfLedCtrlType2_scan(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ // When doing scan, blink(Amber/Blue) and off per 500ms (about 400ms in our driver) ++ // _______ _______ ++ // LED[0] ON | | 8 12 | | ++ // ------ OFF->-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+->>>... ++ // LED[1] ON 0 4 |_______| 0 3 ++ // ++ ++ switch(wd->ledStruct.counter % 16) ++ { ++ case 0: // case 0~3, LED[0] on ++ if(wd->supportMode & ZM_WIRELESS_MODE_24) ++ { ++ zfHpLedCtrl(dev, 0, 1); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ else ++ { ++ zfHpLedCtrl(dev, 1, 1); ++ zfHpLedCtrl(dev, 0, 0); ++ } ++ break; ++ ++ case 8: // case 8~11, LED[1] on ++ if(wd->supportMode & ZM_WIRELESS_MODE_5) ++ { ++ zfHpLedCtrl(dev, 1, 1); ++ zfHpLedCtrl(dev, 0, 0); ++ } ++ else ++ { ++ zfHpLedCtrl(dev, 0, 1); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ break; ++ ++ default: // others, all off ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ break; ++ } ++} ++ ++/**********************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfLedCtrlType3 */ ++/* Customize for Netgear Single-LED state ((bug#32243)) */ ++/* */ ++/* ¡EOff: when the adapter is disabled or hasn't started to associate with AP */ ++/* yet. */ ++/* ¡EOn: Once adpater associate with AP successfully */ ++/* ¡ESlow blinking: whenever adapters do site-survey or try to associate with AP */ ++/* - If there is a connection already, and adapters do site-survey or */ ++/* re-associate action, the LED should keep LED backgraoud as ON, thus */ ++/* the blinking behavior SHOULD be OFF (200ms) - ON (800ms) and continue this*/ ++/* cycle. */ ++/* - If there is no connection yet, and adapters start to do site-survey or */ ++/* associate action, the LED should keep LED background as OFF, thus the */ ++/* blinking behavior SHOULD be ON (200ms) - OFF (800ms) and continue this */ ++/* cycle. */ ++/* - For the case that associate fail, adpater should keep associating, and the*/ ++/* LED should also keep slow blinking. */ ++/* ¡EQuick blinking: to blink OFF-ON cycle for each time that traffic packet is */ ++/* received or is transmitted. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Shang-Chun Liu Atheros Communications, INC. 2008.01 */ ++/* */ ++/**********************************************************************************/ ++void zfLedCtrlType3_scan(zdev_t* dev, u16_t isConnect); ++ ++void zfLedCtrlType3(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ if (zfStaIsConnected(dev) != TRUE) ++ { ++ // Disconnect state ++ if(wd->ledStruct.counter % 2 != 0) ++ { ++ // Update LED each 200ms(2*100) ++ // Prevent this situation ++ // ___ _ ++ // LED[0] ON | | |x| ++ // ------ OFF->+-+-+-+-+-+-+->>>... ++ // ++ return; ++ } ++ ++ if (((wd->state == ZM_WLAN_STATE_DISABLED) && (wd->sta.bChannelScan)) ++ || ((wd->state != ZM_WLAN_STATE_DISABLED) && (wd->sta.bAutoReconnect))) ++ { ++ // Scan/AutoReconnect state ++ zfLedCtrlType3_scan(dev, 0); ++ } ++ else ++ { ++ // Neither Connected nor Scan ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ } ++ else ++ { ++ if( wd->sta.bChannelScan ) ++ { ++ // Scan state ++ if(wd->ledStruct.counter % 2 != 0) ++ return; ++ zfLedCtrlType3_scan(dev, 1); ++ return; ++ } ++ ++ if ((zfPowerSavingMgrIsSleeping(dev)) && ((wd->ledStruct.ledMode[0] & 0x8) == 0)) ++ { ++ // If Sleeping, turn OFF ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ else ++ { ++ //Connect state ++ if ((wd->ledStruct.counter & 1) == 0) // even ++ { ++ // No traffic, always ON ++ zfHpLedCtrl(dev, 0, 1); ++ zfHpLedCtrl(dev, 1, 1); ++ } ++ else // odd ++ { ++ if ((wd->ledStruct.txTraffic > 0) || (wd->ledStruct.rxTraffic > 0)) ++ { ++ // If have traffic, turn OFF ++ // _____ _ _ _ _____ ++ // LED[Operate] ON | | | | | | | | ++ // ------------ OFF->-+-+-+-+-+-+-+-+-+-+-+-+-+->>>... ++ // ++ wd->ledStruct.txTraffic = wd->ledStruct.rxTraffic = 0; ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ } ++ } ++ } ++} ++ ++void zfLedCtrlType3_scan(zdev_t* dev, u16_t isConnect) ++{ ++ u32_t ton, toff, tmp; ++ zmw_get_wlan_dev(dev); ++ ++ // Doing scan when : ++ // 1. Disconnected: ON (200ms) - OFF (800ms) (200ms-600ms in our driver) ++ // ___ ___ ___ ++ // LED[0] ON | | | | | | ++ // ------ OFF->-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+->>>... ++ // 0 2 4 6 8 10 12 14 16 ++ // 2. Connected: ON (800ms) - OFF (200ms) (600ms-200ms in our driver) ++ // ___________ ___________ ______ ++ // LED[0] ON | | | | | ++ // ------ OFF->-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+->>>... ++ // 0 2 4 6 8 10 12 14 16 ++ ++ //Scan state ++ if(!isConnect) ++ ton = 2, toff = 6; ++ else ++ ton = 6, toff = 2; ++ ++ if ((ton + toff) != 0) ++ { ++ tmp = wd->ledStruct.counter % (ton+toff); ++ if (tmp < ton) ++ { ++ zfHpLedCtrl(dev, 0, 1); ++ zfHpLedCtrl(dev, 1, 1); ++ } ++ else ++ { ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ } ++ } ++} ++ ++/******************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfLedCtrl_BlinkWhenScan_Alpha */ ++/* Customize for Alpha/DLink LED */ ++/* - Blink LED 12 times within 3 seconds when doing Active Scan */ ++/* ___ ___ ___ ___ */ ++/* LED[0] ON | | | | | | | | */ ++/* -------OFF->-+-+-+-+-+-+-+-+-+-+-+-+-+--+-->>>... */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Shang-Chun Liu Atheros Communications, INC. 2007.11 */ ++/* */ ++/******************************************************************************/ ++void zfLedCtrl_BlinkWhenScan_Alpha(zdev_t* dev) ++{ ++ static u32_t counter = 0; ++ zmw_get_wlan_dev(dev); ++ ++ if(counter > 34) // counter for 3 sec ++ { ++ wd->ledStruct.LEDCtrlFlag &= ~(u8_t)ZM_LED_CTRL_FLAG_ALPHA; ++ counter = 0; ++ } ++ ++ if( (counter % 3) < 2) ++ zfHpLedCtrl(dev, 0, 1); ++ else ++ zfHpLedCtrl(dev, 0, 0); ++ ++ counter++; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfLed100msCtrl */ ++/* LED 100 milliseconds timer. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.6 */ ++/* */ ++/************************************************************************/ ++void zfLed100msCtrl(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ wd->ledStruct.counter++; ++ ++ if(wd->ledStruct.LEDCtrlFlag) ++ { ++ switch(wd->ledStruct.LEDCtrlFlag) { ++ case ZM_LED_CTRL_FLAG_ALPHA: ++ zfLedCtrl_BlinkWhenScan_Alpha(dev); ++ break; ++ } ++ } ++ else ++ { ++ switch(wd->ledStruct.LEDCtrlType) { ++ case 1: // Traditional 1 LED ++ zfLedCtrlType1(dev); ++ break; ++ ++ case 2: // Dual-LEDs for Netgear ++ zfLedCtrlType2(dev); ++ break; ++ ++ case 3: // Single-LED for Netgear (WN111v2) ++ zfLedCtrlType3(dev); ++ break; ++ ++ default: ++ zfLedCtrlType1(dev); ++ break; ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/otus/80211core/performance.c +@@ -0,0 +1,431 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : performance.c */ ++/* */ ++/* Abstract */ ++/* This module performance evaluation functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#ifdef ZM_ENABLE_PERFORMANCE_EVALUATION ++ ++#define ZM_TP_SIZE 50 ++struct zsSummary zm_summary; ++struct zsVariation zm_var; ++struct zsThroughput zm_tp; ++ ++void zfiPerformanceInit(zdev_t* dev) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_summary.tick_base = wd->tick; ++ zm_summary.tx_msdu_count = 0; ++ zm_summary.tx_mpdu_count = 0; ++ zm_summary.rx_msdu_count = 0; ++ zm_summary.rx_mpdu_count = 0; ++ zm_summary.rx_broken_seq = 0; ++ zm_summary.rx_broken_sum = 0; ++ zm_summary.rx_seq_base = 0; ++ zm_summary.rx_broken_seq_dis = 0; ++ zm_summary.rx_duplicate_seq = 0; ++ zm_summary.rx_old_seq = 0; ++ zm_summary.reset_count = 0; ++ zm_summary.reset_sum = 0; ++ zm_summary.rx_lost_sum = 0; ++ zm_summary.rx_duplicate_error = 0; ++ zm_summary.rx_free = 0; ++ zm_summary.rx_amsdu_len = 0; ++ zm_summary.rx_flush = 0; ++ zm_summary.rx_clear = 0; ++ zm_summary.rx_reorder = 0; ++ ++ for (i=0; i<100; i++) ++ { ++ zm_var.tx_msdu_tick[i] = zm_var.tx_mpdu_tick[i] = 0; ++ zm_var.rx_msdu_tick[i] = zm_var.rx_mpdu_tick[i] = 0; ++ } ++ ++ zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_PERFORMANCE, 100); ++ ++ zm_tp.size = ZM_TP_SIZE; ++ zm_tp.head = zm_tp.size - 1; ++ zm_tp.tail = 0; ++ for (i=0; i0; i--) ++ { ++ s[0] = (i/10) + '0'; ++ s[1] = (i%10) + '0'; ++ s[2] = '0'; ++ s[3] = '|'; ++ for (j=0; jtick; ++ zm_summary.rx_broken_sum += zm_summary.rx_broken_seq; ++ zm_summary.rx_lost_sum += (zm_summary.rx_broken_seq - zm_summary.rx_duplicate_seq - zm_summary.rx_old_seq); ++ ++ zfiPerformanceGraph(dev); ++ ++ DbgPrint("******************************************************\n"); ++ DbgPrint("* TX: MSDU=%5d, VAR=%5d; MPDU=%5d, VAR=%5d\n", zm_summary.tx_msdu_count, ++ zm_var.tx_msdu_var, zm_summary.tx_mpdu_count, zm_var.tx_mpdu_var); ++ DbgPrint("* TX: idle=%5d,TxRate=%3d, PER=%5d\n", zm_summary.tx_idle_count, ++ wd->CurrentTxRateKbps/1000, ++ (u16_t)wd->PER[wd->sta.oppositeInfo[0].rcCell.currentRate]); ++ DbgPrint("* RX: MSDU=%5d, VAR=%5d; MPDU=%5d, VAR=%5d\n", zm_summary.rx_msdu_count, ++ zm_var.rx_msdu_var, zm_summary.rx_mpdu_count, zm_var.rx_mpdu_var); ++ DbgPrint("* RX: idle=%5d,RxRate=%3d,AMSDU=%5d\n", zm_summary.rx_idle_count, ++ wd->CurrentRxRateKbps/1000, zm_summary.rx_amsdu_len); ++ DbgPrint("* RX broken seq=%4d, distances=%4d, duplicates=%4d\n", zm_summary.rx_broken_seq, ++ zm_summary.rx_broken_seq_dis, zm_summary.rx_duplicate_seq); ++ DbgPrint("* RX old seq=%4d, lost=%4d, broken sum=%4d\n", zm_summary.rx_old_seq, ++ (zm_summary.rx_broken_seq - zm_summary.rx_duplicate_seq - zm_summary.rx_old_seq), ++ zm_summary.rx_broken_sum); ++ DbgPrint("* Rx lost sum=%4d,dup. error=%4d, free count=%4d\n", zm_summary.rx_lost_sum, ++ zm_summary.rx_duplicate_error, zm_summary.rx_free); ++ DbgPrint("* Rx flush sum=%4d, clear sum=%4d, reorder=%7d\n", zm_summary.rx_flush, ++ zm_summary.rx_clear, zm_summary.rx_reorder); ++ DbgPrint("* Firmware reset=%3d, reset sum=%4d\n", zm_summary.reset_count, ++ zm_summary.reset_sum); ++ DbgPrint("******************************************************\n\n"); ++ //reset count 11772c ++ zm_summary.tx_msdu_count = 0; ++ zm_summary.tx_mpdu_count = 0; ++ zm_summary.rx_msdu_count = 0; ++ zm_summary.rx_mpdu_count = 0; ++ zm_summary.rx_broken_seq = 0; ++ zm_summary.rx_broken_seq_dis = 0; ++ zm_summary.rx_duplicate_seq = 0; ++ zm_summary.rx_old_seq = 0; ++ zm_summary.reset_count = 0; ++ zm_summary.rx_amsdu_len = 0; ++ ++ for (i=0; i<100; i++) ++ { ++ zm_var.tx_msdu_tick[i] = zm_var.tx_mpdu_tick[i] = 0; ++ zm_var.rx_msdu_tick[i] = zm_var.rx_mpdu_tick[i] = 0; ++ } ++ ++ zfTimerSchedule(dev, ZM_EVENT_TIMEOUT_PERFORMANCE, 100); ++} ++ ++void zfiTxPerformanceMSDU(zdev_t* dev, u32_t tick) ++{ ++ u32_t index; ++ zm_summary.tx_msdu_count++; ++ ++ index = tick - zm_summary.tick_base; ++ ++ if (index < 100) ++ { ++ zm_var.tx_msdu_tick[index]++; ++ } ++ else ++ { ++ //DbgPrint("wd->tick exceeded tick_base+100!\n"); ++ } ++} ++ ++void zfiRxPerformanceMSDU(zdev_t* dev, u32_t tick) ++{ ++ u32_t index; ++ zm_summary.rx_msdu_count++; ++ ++ index = tick - zm_summary.tick_base; ++ ++ if (index < 100) ++ { ++ zm_var.rx_msdu_tick[index]++; ++ } ++ else ++ { ++ //DbgPrint("wd->tick exceeded tick_base+100!\n"); ++ } ++} ++ ++void zfiTxPerformanceMPDU(zdev_t* dev, u32_t tick) ++{ ++ u32_t index; ++ zm_summary.tx_mpdu_count++; ++ ++ index = tick - zm_summary.tick_base; ++ ++ if (index < 100) ++ { ++ zm_var.tx_mpdu_tick[index]++; ++ } ++ else ++ { ++ //DbgPrint("wd->tick exceeded tick_base+100!\n"); ++ } ++} ++ ++#ifndef ZM_INT_USE_EP2_HEADER_SIZE ++#define ZM_INT_USE_EP2_HEADER_SIZE 12 ++#endif ++void zfiRxPerformanceMPDU(zdev_t* dev, zbuf_t* buf) ++{ ++ u32_t index; ++ u16_t frameType; ++ u16_t frameCtrl; ++ u8_t mpduInd; ++ u16_t plcpHdrLen; ++ u16_t len; ++ ++ zmw_get_wlan_dev(dev); ++ ++ len = zfwBufGetSize(dev, buf); ++ mpduInd = zmw_rx_buf_readb(dev, buf, len-1); ++ /* First MPDU or Single MPDU */ ++ if(((mpduInd & 0x30) == 0x00) || ((mpduInd & 0x30) == 0x20)) ++ //if ((mpduInd & 0x10) == 0x00) ++ { ++ plcpHdrLen = 12; // PLCP header length ++ } ++ else ++ { ++ if (zmw_rx_buf_readh(dev, buf, 4) == wd->macAddr[0] && ++ zmw_rx_buf_readh(dev, buf, 6) == wd->macAddr[1] && ++ zmw_rx_buf_readh(dev, buf, 8) == wd->macAddr[2]) { ++ plcpHdrLen = 0; ++ } ++ else if (zmw_rx_buf_readh(dev, buf, 16) == wd->macAddr[0] && ++ zmw_rx_buf_readh(dev, buf, 18) == wd->macAddr[1] && ++ zmw_rx_buf_readh(dev, buf, 20) == wd->macAddr[2]){ ++ plcpHdrLen = 12; ++ } ++ else { ++ plcpHdrLen = 0; ++ } ++ } ++ ++ frameCtrl = zmw_rx_buf_readb(dev, buf, plcpHdrLen + 0); ++ frameType = frameCtrl & 0xf; ++ ++ if (frameType != ZM_WLAN_DATA_FRAME) ++ { ++ return; ++ } ++ ++ zm_summary.rx_mpdu_count++; ++ ++ index = wd->tick - zm_summary.tick_base; ++ ++ if (index < 100) ++ { ++ zm_var.rx_mpdu_tick[index]++; ++ } ++ else ++ { ++ //DbgPrint("wd->tick exceeded tick_base+100!\n"); ++ } ++} ++ ++void zfiRxPerformanceSeq(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t seq_no; ++ u16_t offset = 0; ++ u16_t old_dis = zm_summary.rx_broken_seq_dis; ++ //sys_time = KeQueryPerformanceCounter(&freq); ++ ++ seq_no = zmw_rx_buf_readh(dev, buf, offset+22) >> 4; ++ ++ ZM_SEQ_DEBUG("Out %5d\n", seq_no); ++ ++ if (seq_no < zm_summary.rx_seq_base) ++ { ++ if (seq_no == 0) ++ { ++ if (zm_summary.rx_seq_base != 4095) ++ { ++ zm_summary.rx_broken_seq++; ++ ZM_SEQ_DEBUG("Broken seq"); ++ zm_summary.rx_broken_seq_dis+=(4096 - zm_summary.rx_seq_base); ++ } ++ } ++ else if ((seq_no < 300) && (zm_summary.rx_seq_base > 3800)) ++ { ++ zm_summary.rx_broken_seq++; ++ ZM_SEQ_DEBUG("Broken seq"); ++ zm_summary.rx_broken_seq_dis+=(4096 - zm_summary.rx_seq_base + seq_no); ++ } ++ else ++ { ++ zm_summary.rx_broken_seq++; ++ ZM_SEQ_DEBUG("Broken seq"); ++ zm_summary.rx_broken_seq_dis+=(zm_summary.rx_seq_base - seq_no); ++ zm_summary.rx_old_seq++; ++ } ++ } ++ else ++ { ++ if (seq_no != (zm_summary.rx_seq_base + 1)) ++ { ++ if ((seq_no > 3800) && (zm_summary.rx_seq_base < 300)) ++ { ++ zm_summary.rx_broken_seq++; ++ ZM_SEQ_DEBUG("Broken seq"); ++ zm_summary.rx_broken_seq_dis+=(4096 - seq_no + zm_summary.rx_seq_base); ++ zm_summary.rx_old_seq++; ++ } ++ else ++ { ++ zm_summary.rx_broken_seq++; ++ ZM_SEQ_DEBUG("Broken seq"); ++ zm_summary.rx_broken_seq_dis+=(seq_no - zm_summary.rx_seq_base); ++ } ++ } ++ } ++ if (seq_no == zm_summary.rx_seq_base) ++ { ++ zm_summary.rx_duplicate_seq++; ++ } ++ ++ if ((zm_summary.rx_broken_seq_dis - old_dis) > 100) ++ { ++ DbgPrint("* seq_no=%4d, base_seq=%4d, dis_diff=%4d", seq_no, ++ zm_summary.rx_seq_base, zm_summary.rx_broken_seq_dis - old_dis); ++ } ++ zm_summary.rx_seq_base = seq_no; ++} ++ ++void zfiRxPerformanceReg(zdev_t* dev, u32_t reg, u32_t rsp) ++{ ++ zm_summary.reset_count = (u16_t)rsp - zm_summary.reset_sum; ++ zm_summary.reset_sum = (u16_t)rsp; ++} ++ ++void zfiRxPerformanceDup(zdev_t* dev, zbuf_t* buf1, zbuf_t* buf2) ++{ ++ u16_t seq_no1, seq_no2; ++ ++ seq_no1 = zmw_rx_buf_readh(dev, buf1, 22) >> 4; ++ seq_no2 = zmw_rx_buf_readh(dev, buf2, 22) >> 4; ++ if (seq_no1 != seq_no2) ++ { ++ zm_summary.rx_duplicate_error++; ++ } ++} ++ ++void zfiRxPerformanceFree(zdev_t* dev, zbuf_t* buf) ++{ ++ zm_summary.rx_free++; ++} ++ ++void zfiRxPerformanceAMSDU(zdev_t* dev, zbuf_t* buf, u16_t len) ++{ ++ if (zm_summary.rx_amsdu_len < len) ++ { ++ zm_summary.rx_amsdu_len = len; ++ } ++} ++void zfiRxPerformanceFlush(zdev_t* dev) ++{ ++ zm_summary.rx_flush++; ++} ++ ++void zfiRxPerformanceClear(zdev_t* dev) ++{ ++ zm_summary.rx_clear++; ++ ZM_SEQ_DEBUG("RxClear"); ++} ++ ++void zfiRxPerformanceReorder(zdev_t* dev) ++{ ++ zm_summary.rx_reorder++; ++} ++#endif /* end of ZM_ENABLE_PERFORMANCE_EVALUATION */ +--- /dev/null ++++ b/drivers/staging/otus/80211core/performance.h +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#ifndef _PERFORMANCE_H ++#define _PERFORMANCE_H ++ ++#ifdef ZM_ENABLE_PERFORMANCE_EVALUATION ++ ++struct zsSummary ++{ ++ u32_t tx_msdu_count; ++ u32_t tx_mpdu_count; ++ u32_t rx_msdu_count; ++ u32_t rx_mpdu_count; ++ u32_t tick_base; ++ u16_t rx_seq_base; ++ u16_t rx_broken_seq; ++ u16_t rx_broken_sum; ++ u16_t rx_broken_seq_dis; ++ u16_t rx_duplicate_seq; ++ u16_t rx_duplicate_error; ++ u16_t rx_old_seq; ++ u16_t rx_lost_sum; ++ u16_t tx_idle_count; ++ u16_t rx_idle_count; ++ u16_t reset_count; ++ u16_t reset_sum; ++ u16_t rx_free; ++ u16_t rx_amsdu_len; ++ u16_t rx_flush; ++ u16_t rx_clear; ++ u32_t rx_reorder; ++}; ++ ++struct zsVariation ++{ ++ u32_t tx_msdu_tick[100]; ++ u32_t tx_mpdu_tick[100]; ++ u32_t rx_msdu_tick[100]; ++ u32_t rx_mpdu_tick[100]; ++ ++ u32_t tx_msdu_mean; ++ u32_t tx_mpdu_mean; ++ u32_t rx_msdu_mean; ++ u32_t rx_mpdu_mean; ++ ++ u32_t tx_msdu_sum; ++ u32_t tx_mpdu_sum; ++ u32_t rx_msdu_sum; ++ u32_t rx_mpdu_sum; ++ ++ u32_t tx_msdu_var; ++ u32_t tx_mpdu_var; ++ u32_t rx_msdu_var; ++ u32_t rx_mpdu_var; ++}; ++ ++struct zsThroughput ++{ ++ u32_t tx[50]; ++ u32_t rx[50]; ++ u16_t head; ++ u16_t tail; ++ u16_t size; ++ LARGE_INTEGER sys_time; ++ LARGE_INTEGER freq; ++}; ++ ++void zfiPerformanceInit(zdev_t* dev); ++void zfiPerformanceRefresh(zdev_t* dev); ++ ++void zfiTxPerformanceMSDU(zdev_t* dev, u32_t tick); ++void zfiRxPerformanceMSDU(zdev_t* dev, u32_t tick); ++void zfiTxPerformanceMPDU(zdev_t* dev, u32_t tick); ++void zfiRxPerformanceMPDU(zdev_t* dev, zbuf_t* buf); ++void zfiRxPerformanceSeq(zdev_t* dev, zbuf_t* buf); ++void zfiRxPerformanceReg(zdev_t* dev, u32_t reg, u32_t rsp); ++void zfiRxPerformanceDup(zdev_t* dev, zbuf_t* buf1, zbuf_t* buf2); ++void zfiRxPerformanceFree(zdev_t* dev, zbuf_t* buf); ++void zfiRxPerformanceAMSDU(zdev_t* dev, zbuf_t* buf, u16_t len); ++void zfiRxPerformanceFlush(zdev_t* dev); ++void zfiRxPerformanceClear(zdev_t* dev); ++void zfiRxPerformanceReorder(zdev_t* dev); ++#endif /* end of ZM_ENABLE_PERFORMANCE_EVALUATION */ ++#endif /* end of _PERFORMANCE_H */ +--- /dev/null ++++ b/drivers/staging/otus/80211core/pub_usb.h +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _PUB_USB_H ++#define _PUB_USB_H ++ ++#include "../oal_dt.h" ++ ++#define ZM_HAL_80211_MODE_AP 0 ++#define ZM_HAL_80211_MODE_STA 1 ++#define ZM_HAL_80211_MODE_IBSS_GENERAL 2 ++#define ZM_HAL_80211_MODE_IBSS_WPA2PSK 3 ++ ++/* USB module description */ ++/* Queue Management */ ++/* 80211core requires OAL to implement a transmission queue in OAL's */ ++/* USB module. Because there is only limited on-chip memory, so USB */ ++/* data transfer may be pending until on-chip memory is available. */ ++/* 80211core also requires OAL's USB module to provide two functions */ ++/* zfwUsbGetFreeTxQSize() and zfwUsbGetMaxTxQSize() for 80211core to */ ++/* query the status of this transmission queue. The main purpose of */ ++/* this queue is for QoS/WMM. Though there are hardware priority */ ++/* queues on the chip, and also software priority queues in the */ ++/* 80211core. There is still one and only one USB channel. So */ ++/* 80211core will use the information that zfwUsbGetFreeTxQSize() */ ++/* returned to schedule the traffic from the software priority */ ++/* queues to the hardware priority queues. For example, if 80211core */ ++/* found that USB transmission queue is going to be full, it will */ ++/* not allow packets with lower priority to enter the USB channel. */ ++ ++ ++/* Structure for USB call back functions */ ++struct zfCbUsbFuncTbl { ++ void (*zfcbUsbRecv)(zdev_t *dev, zbuf_t *buf); ++ void (*zfcbUsbRegIn)(zdev_t* dev, u32_t* rsp, u16_t rspLen); ++ void (*zfcbUsbOutComplete)(zdev_t* dev, zbuf_t *buf, u8_t status, u8_t *hdr); ++ void (*zfcbUsbRegOutComplete)(zdev_t* dev); ++}; ++ ++/* Call back functions */ ++/* Below are the functions that should be called by the OAL */ ++ ++/* When data is available in endpoint 3, OAL shall embed the data in */ ++/* zbuf_t and supply to 80211core by calling this function */ ++/* void (*zfcbUsbRecv)(zdev_t *dev, zbuf_t *buf); */ ++ ++/* When data is available in endpoint 2, OAL shall call this function */ ++/* void (*zfcbUsbRegIn)(zdev_t* dev, u32_t* rsp, u16_t rspLen); */ ++ ++/* When USB data transfer completed in endpoint 1, OAL shall call this function */ ++/* void (*zfcbUsbOutComplete)(zdev_t* dev, zbuf_t *buf, u8_t status, u8_t *hdr); */ ++ ++ ++/* Call out functions */ ++/* Below are the functions that supply by the OAL for 80211core to */ ++/* manipulate the USB */ ++ ++/* Return OAL's USB TxQ size */ ++extern u32_t zfwUsbGetMaxTxQSize(zdev_t* dev); ++ ++/* Return OAL's TxQ available size */ ++extern u32_t zfwUsbGetFreeTxQSize(zdev_t* dev); ++ ++/* Register call back function */ ++extern void zfwUsbRegisterCallBack(zdev_t* dev, struct zfCbUsbFuncTbl *zfUsbFunc); ++ ++/* Enable USB interrupt endpoint */ ++extern u32_t zfwUsbEnableIntEpt(zdev_t *dev, u8_t endpt); ++ ++/* Enable USB Rx endpoint */ ++extern int zfwUsbEnableRxEpt(zdev_t* dev, u8_t endpt); ++ ++/* 80211core call this function to send a USB request over endpoint 0 */ ++extern u32_t zfwUsbSubmitControl(zdev_t* dev, u8_t req, u16_t value, ++ u16_t index, void *data, u32_t size); ++extern u32_t zfwUsbSubmitControlIo(zdev_t* dev, u8_t req, u8_t reqtype, ++ u16_t value, u16_t index, void *data, u32_t size); ++ ++/* 80211core call this function to transfer data out over endpoint 1 */ ++extern void zfwUsbCmd(zdev_t* dev, u8_t endpt, u32_t* cmd, u16_t cmdLen); ++ ++/* 80211core call this function to transfer data out over endpoint 4 */ ++extern u32_t zfwUsbSend(zdev_t* dev, u8_t endpt, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen, ++ u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset); ++ ++/* 80211core call this function to set USB configuration */ ++extern u32_t zfwUsbSetConfiguration(zdev_t *dev, u16_t value); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/otus/80211core/pub_zfi.h +@@ -0,0 +1,821 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _PUB_DEFS_H ++#define _PUB_DEFS_H ++ ++#include "../oal_dt.h" ++ ++/***** Section 1 : Tunable Parameters *****/ ++/* The defintions in this section are tunabel parameters */ ++ ++/* Maximum number of BSS that could be scaned */ ++#define ZM_MAX_BSS 128 ++ ++/* Maximum number of WPA2 PMKID that supported */ ++#define ZM_PMKID_MAX_BSS_CNT 8 ++ ++/* Enable aggregation and deaggregation */ ++#define ZM_ENABLE_AGGREGATION ++ ++#ifdef ZM_ENABLE_AGGREGATION ++ /* Enable BA failed retransmission in firmware */ ++ #define ZM_ENABLE_FW_BA_RETRANSMISSION ++ #define ZM_BYPASS_AGGR_SCHEDULING ++ //#define ZM_AGGR_BIT_ON ++#endif ++ ++ ++#ifndef ZM_FB50 ++//#define ZM_FB50 ++#endif ++ ++#ifndef ZM_AP_DEBUG ++//#define ZM_AP_DEBUG ++#endif ++ ++//#define ZM_ENABLE_BA_RATECTRL ++ ++/***** End of section 1 *****/ ++ ++ ++/***** Section 2 : Public Definitions, data structures and prototypes *****/ ++/* function return status */ ++#define ZM_STATUS_SUCCESS 0 ++#define ZM_STATUS_FAILURE 1 ++ ++// media connect status ++#define ZM_STATUS_MEDIA_CONNECT 0x00 ++#define ZM_STATUS_MEDIA_DISCONNECT 0x01 ++#define ZM_STATUS_MEDIA_DISCONNECT_NOT_FOUND 0x02 ++#define ZM_STATUS_MEDIA_DISABLED 0x03 ++#define ZM_STATUS_MEDIA_CONNECTION_DISABLED 0x04 ++#define ZM_STATUS_MEDIA_CONNECTION_RESET 0x05 ++#define ZM_STATUS_MEDIA_RESET 0x06 ++#define ZM_STATUS_MEDIA_DISCONNECT_DEAUTH 0x07 ++#define ZM_STATUS_MEDIA_DISCONNECT_DISASOC 0x08 ++#define ZM_STATUS_MEDIA_DISCONNECT_TIMEOUT 0x09 ++#define ZM_STATUS_MEDIA_DISCONNECT_AUTH_FAILED 0x0a ++#define ZM_STATUS_MEDIA_DISCONNECT_ASOC_FAILED 0x0b ++#define ZM_STATUS_MEDIA_DISCONNECT_MIC_FAIL 0x0c ++#define ZM_STATUS_MEDIA_DISCONNECT_UNREACHABLE 0x0d ++#define ZM_STATUS_MEDIA_DISCONNECT_BEACON_MISS 0x0e ++ ++// Packet Filter ++#define ZM_PACKET_TYPE_DIRECTED 0x00000001 ++#define ZM_PACKET_TYPE_MULTICAST 0x00000002 ++#define ZM_PACKET_TYPE_ALL_MULTICAST 0x00000004 ++#define ZM_PACKET_TYPE_BROADCAST 0x00000008 ++#define ZM_PACKET_TYPE_PROMISCUOUS 0x00000020 ++ ++/* BSS mode definition */ ++/* TODO : The definitions here are coupled with XP's NDIS OID. */ ++/* We can't be changed them freely, need to disarm this mine */ ++#define ZM_MODE_IBSS 0 ++#define ZM_MODE_INFRASTRUCTURE 1 ++#define ZM_MODE_UNKNOWN 2 ++#define ZM_MODE_INFRASTRUCTURE_MAX 3 ++#define ZM_MODE_AP 4 ++#define ZM_MODE_PSEUDO 5 ++ ++ ++/* Authentication mode */ ++#define ZM_AUTH_MODE_OPEN 0 ++#define ZM_AUTH_MODE_SHARED_KEY 1 ++#define ZM_AUTH_MODE_AUTO 2 ++#define ZM_AUTH_MODE_WPA 3 ++#define ZM_AUTH_MODE_WPAPSK 4 ++#define ZM_AUTH_MODE_WPA_NONE 5 ++#define ZM_AUTH_MODE_WPA2 6 ++#define ZM_AUTH_MODE_WPA2PSK 7 ++#ifdef ZM_ENABLE_CENC ++#define ZM_AUTH_MODE_CENC 8 ++#endif //ZM_ENABLE_CENC ++#define ZM_AUTH_MODE_WPA_AUTO 9 ++#define ZM_AUTH_MODE_WPAPSK_AUTO 10 ++ ++// Encryption mode ++#define ZM_NO_WEP 0x0 ++#define ZM_AES 0x4 ++#define ZM_TKIP 0x2 ++#define ZM_WEP64 0x1 ++#define ZM_WEP128 0x5 ++#define ZM_WEP256 0x6 ++#ifdef ZM_ENABLE_CENC ++#define ZM_CENC 0x7 ++#endif //ZM_ENABLE_CENC ++ ++/* Encryption type for wep status */ ++#define ZM_ENCRYPTION_WEP_DISABLED 0 ++#define ZM_ENCRYPTION_WEP_ENABLED 1 ++#define ZM_ENCRYPTION_WEP_KEY_ABSENT 2 ++#define ZM_ENCRYPTION_NOT_SUPPORTED 3 ++#define ZM_ENCRYPTION_TKIP 4 ++#define ZM_ENCRYPTION_TKIP_KEY_ABSENT 5 ++#define ZM_ENCRYPTION_AES 6 ++#define ZM_ENCRYPTION_AES_KEY_ABSENT 7 ++ ++#ifdef ZM_ENABLE_CENC ++#define ZM_ENCRYPTION_CENC 8 ++#endif //ZM_ENABLE_CENC ++ ++/* security type */ ++#define ZM_SECURITY_TYPE_NONE 0 ++#define ZM_SECURITY_TYPE_WEP 1 ++#define ZM_SECURITY_TYPE_WPA 2 ++ ++#ifdef ZM_ENABLE_CENC ++#define ZM_SECURITY_TYPE_CENC 3 ++#endif //ZM_ENABLE_CENC ++ ++/* Encryption Exemption Action Type */ ++#define ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION 0 ++#define ZM_ENCRYPTION_EXEMPT_ALWAYS 1 ++ ++/* MIC failure */ ++#define ZM_MIC_PAIRWISE_ERROR 0x06 ++#define ZM_MIC_GROUP_ERROR 0x0E ++ ++ ++/* power save mode */ ++#define ZM_STA_PS_NONE 0 ++#define ZM_STA_PS_MAX 1 ++#define ZM_STA_PS_FAST 2 ++#define ZM_STA_PS_LIGHT 3 ++ ++/* WME AC Type */ ++#define ZM_WME_AC_BK 0 /* Background AC */ ++#define ZM_WME_AC_BE 1 /* Best-effort AC */ ++#define ZM_WME_AC_VIDEO 2 /* Video AC */ ++#define ZM_WME_AC_VOICE 3 /* Voice AC */ ++ ++/* Preamble type */ ++#define ZM_PREAMBLE_TYPE_AUTO 0 ++#define ZM_PREAMBLE_TYPE_LONG 1 ++#define ZM_PREAMBLE_TYPE_SHORT 2 ++ ++/* wireless modes constants */ ++#define ZM_WIRELESS_MODE_5_54 0x01 ///< 5 GHz 54 Mbps ++#define ZM_WIRELESS_MODE_5_108 0x02 ///< 5 GHz 108 Mbps ++#define ZM_WIRELESS_MODE_24_11 0x04 ///< 2.4 GHz 11 Mbps ++#define ZM_WIRELESS_MODE_24_54 0x08 ///< 2.4 GHz 54 Mbps ++#define ZM_WIRELESS_MODE_24_108 0x10 ///< 2.4 GHz 108 Mbps ++#define ZM_WIRELESS_MODE_49_13 0x100 ///< 4.9 GHz 13.5 Mbps, quarter rate chn-bandwidth = 5 ++#define ZM_WIRELESS_MODE_49_27 0x200 ///< 4.9 GHz 27 Mbps, half rate chn-bandwidth = 10 ++#define ZM_WIRELESS_MODE_49_54 0x400 ///< 4.9 GHz 54 Mbps, full rate chn-bandwidth = 20 ++#define ZM_WIRELESS_MODE_5_300 0x1000 ///< 5 GHz 300 Mbps ++#define ZM_WIRELESS_MODE_24_300 0x2000 ///< 2.4 GHz 300 Mbps ++#define ZM_WIRELESS_MODE_5_130 0x4000 ///< 5 GHz 130 Mbps ++#define ZM_WIRELESS_MODE_24_130 0x8000 ///< 2.4 GHz 130 Mbps ++ ++#define ZM_WIRELESS_MODE_24_N (ZM_WIRELESS_MODE_24_130|ZM_WIRELESS_MODE_24_300) ++#define ZM_WIRELESS_MODE_5_N (ZM_WIRELESS_MODE_5_130|ZM_WIRELESS_MODE_5_300) ++#define ZM_WIRELESS_MODE_24 (ZM_WIRELESS_MODE_24_11|ZM_WIRELESS_MODE_24_54|ZM_WIRELESS_MODE_24_N) ++#define ZM_WIRELESS_MODE_5 (ZM_WIRELESS_MODE_5_54|ZM_WIRELESS_MODE_5_N) ++ ++/* AdHoc Mode with different band */ ++#define ZM_ADHOCBAND_A 1 ++#define ZM_ADHOCBAND_B 2 ++#define ZM_ADHOCBAND_G 3 ++#define ZM_ADHOCBAND_BG 4 ++#define ZM_ADHOCBAND_ABG 5 ++ ++/* Authentication algorithm in the field algNo of authentication frames */ ++#define ZM_AUTH_ALGO_OPEN_SYSTEM 0x10000 /* Open system */ ++#define ZM_AUTH_ALGO_SHARED_KEY 0x10001 /* Shared Key */ ++#define ZM_AUTH_ALGO_LEAP 0x10080 /* Leap */ ++ ++struct zsScanResult ++{ ++ u32_t reserved; ++}; ++ ++ ++struct zsStastics ++{ ++ u32_t reserved; ++}; ++ ++#define ZM_MAX_SUPP_RATES_IE_SIZE 12 ++#define ZM_MAX_IE_SIZE 50 //100 ++#define ZM_MAX_WPS_IE_SIZE 150 ++#define ZM_MAX_PROBE_FRAME_BODY_SIZE 512//300 ++#define ZM_MAX_COUNTRY_INFO_SIZE 20 ++ ++#define ZM_MAX_SSID_LENGTH 32 ++struct zsBssInfo ++{ ++ u8_t macaddr[6]; ++ u8_t bssid[6]; ++ u8_t beaconInterval[2]; ++ u8_t capability[2]; ++ u8_t timeStamp[8]; ++ u8_t ssid[ZM_MAX_SSID_LENGTH + 2]; // EID(1) + Length(1) + SSID(32) ++ u8_t supportedRates[ZM_MAX_SUPP_RATES_IE_SIZE + 2]; // EID(1) + Length(1) + supported rates [12] ++ u8_t channel; ++ u16_t frequency; ++ u16_t atimWindow; ++ u8_t erp; ++ u8_t extSupportedRates[ZM_MAX_SUPP_RATES_IE_SIZE + 2]; // EID(1) + Length(1) + extended supported rates [12] ++ u8_t wpaIe[ZM_MAX_IE_SIZE + 2]; ++ u8_t wscIe[ZM_MAX_WPS_IE_SIZE + 2]; ++ u8_t rsnIe[ZM_MAX_IE_SIZE + 2]; ++#ifdef ZM_ENABLE_CENC ++ u8_t cencIe[ZM_MAX_IE_SIZE + 2]; /* CENC */ /* half size because of memory exceed 64k boundary */ ++#endif //ZM_ENABLE_CENC ++ u8_t securityType; ++ u8_t signalStrength; ++ u8_t signalQuality; ++ u16_t sortValue; ++ u8_t wmeSupport; ++ u8_t flag; ++ u8_t EnableHT; ++ u8_t enableHT40; ++ u8_t SG40; ++ u8_t extChOffset; ++ u8_t apCap; // bit0:11N AP ++ u16_t frameBodysize; ++ u8_t frameBody[ZM_MAX_PROBE_FRAME_BODY_SIZE]; ++ u8_t countryInfo[ZM_MAX_COUNTRY_INFO_SIZE + 2]; ++ u16_t athOwlAp; ++ u16_t marvelAp; ++ u16_t broadcomHTAp; ++ u32_t tick; ++ struct zsBssInfo* next; ++}; ++ ++struct zsBssList ++{ ++ u8_t bssCount; ++ struct zsBssInfo* head; ++ struct zsBssInfo* tail; ++}; ++ ++struct zsBssListV1 ++{ ++ u8_t bssCount; ++ struct zsBssInfo bssInfo[ZM_MAX_BSS]; ++}; ++ ++#define ZM_KEY_FLAG_GK 0x0001 ++#define ZM_KEY_FLAG_PK 0X0002 ++#define ZM_KEY_FLAG_AUTHENTICATOR 0x0004 ++#define ZM_KEY_FLAG_INIT_IV 0x0008 ++#define ZM_KEY_FLAG_DEFAULT_KEY 0x0010 ++ ++#ifdef ZM_ENABLE_CENC ++#define ZM_KEY_FLAG_CENC 0x0020 ++#endif //ZM_ENABLE_CENC ++ ++// Comment: For TKIP, key[0]~key[15] => TKIP key ++// key[16]~key[23] => Tx MIC key ++// key[24]~key[31] => Rx MIC key ++struct zsKeyInfo ++{ ++ u8_t* key; ++ u8_t keyLength; ++ u8_t keyIndex; ++ u8_t* initIv; ++ u16_t flag; ++ u8_t vapId; ++ u16_t vapAddr[3]; ++ u16_t* macAddr; ++}; ++ ++ ++ ++/* ++ * Channels are specified by frequency. ++ */ ++typedef struct { ++ u16_t channel; /* setting in Mhz */ ++ u32_t channelFlags; /* see below */ ++ u8_t privFlags; ++ s8_t maxRegTxPower; /* max regulatory tx power in dBm */ ++ s8_t maxTxPower; /* max true tx power in 0.25 dBm */ ++ s8_t minTxPower; /* min true tx power in 0.25 dBm */ ++} ZM_HAL_CHANNEL; ++ ++struct zsRegulationTable ++{ ++ u16_t regionCode; ++ u16_t CurChIndex; ++ u16_t allowChannelCnt; ++ ZM_HAL_CHANNEL allowChannel[60]; /* 2.4GHz: 14 channels, 5 GHz: 31 channels */ ++}; ++ ++struct zsPartnerNotifyEvent ++{ ++ u8_t bssid[6]; // The BSSID of IBSS ++ u8_t peerMacAddr[6]; // The MAC address of peer station ++}; ++ ++#define ZM_RC_TRAINED_BIT 0x1 ++struct zsRcCell ++{ ++ u32_t txCount; ++ u32_t failCount; ++ u8_t currentRate; ++ u8_t currentRateIndex; ++ u32_t probingTime; ++ u8_t operationRateSet[24]; ++ u8_t operationRateCount; ++ u16_t rxRssi; ++ u8_t flag; ++ u32_t lasttxCount; ++ u32_t lastTime; ++}; ++ ++struct zsOppositeInfo ++{ ++ u8_t macAddr[6]; ++ struct zsRcCell rcCell; ++ u8_t valid; // This indicate if this opposite is still valid ++ u8_t aliveCounter; ++ u8_t pkInstalled; ++ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ /* For WPA2PSK ! */ ++ u8_t wpaState; ++ u8_t camIdx; ++ u8_t encryMode; ++ u16_t iv16; ++ u32_t iv32; ++#endif ++}; ++ ++typedef void (*zfpIBSSIteratePeerStationCb)( ++ zdev_t* dev, struct zsOppositeInfo *peerInfo, void *ctx, u8_t index); ++ ++typedef u16_t (*zfpStaRxSecurityCheckCb)(zdev_t* dev, zbuf_t* buf); ++ ++ ++/* Communication Tally data structure */ ++struct zsCommTally ++{ ++ u32_t txUnicastFrm; // 0 txUnicastFrames ++ u32_t txMulticastFrm; // 1 txMulticastFrames ++ u32_t txUnicastOctets; // 2 txUniOctets byte size ++ u32_t txMulticastOctets; // 3 txMultiOctets byte size ++ u32_t txFrmUpperNDIS; // 4 ++ u32_t txFrmDrvMgt; // 5 ++ u32_t RetryFailCnt; // 6 ++ u32_t Hw_TotalTxFrm; // 7 Hardware total Tx Frame ++ u32_t Hw_RetryCnt; // 8 txMultipleRetriesFrames ++ u32_t Hw_UnderrunCnt; // 9 ++ ++ u32_t DriverRxFrmCnt; // 10 ++ u32_t rxUnicastFrm; // 11 rxUnicastFrames ++ u32_t rxMulticastFrm; // 12rxMulticastFrames ++ ++ u32_t NotifyNDISRxFrmCnt; // 14 ++ u32_t rxUnicastOctets; // 15 rxUniOctets byte size ++ u32_t rxMulticastOctets; // 16 rxMultiOctets byte size ++ u32_t DriverDiscardedFrm; // 17 Discard by ValidateFrame ++ u32_t LessThanDataMinLen; // 18 ++ u32_t GreaterThanMaxLen; // 19 ++ u32_t DriverDiscardedFrmCauseByMulticastList; ++ u32_t DriverDiscardedFrmCauseByFrmCtrl; ++ u32_t rxNeedFrgFrm; // 22 need more frg frm ++ u32_t DriverRxMgtFrmCnt; ++ u32_t rxBroadcastFrm; // 24 Receive broadcast frame count ++ u32_t rxBroadcastOctets; // 25 Receive broadcast frame byte size ++ u32_t rx11bDataFrame; // 26 Measured quality 11b data frame count ++ u32_t rxOFDMDataFrame; // 27 Measured quality 11g data frame count ++ ++ ++ u32_t Hw_TotalRxFrm; // 28 ++ u32_t Hw_CRC16Cnt; // 29 rxPLCPCRCErrCnt ++ u32_t Hw_CRC32Cnt; // 30 rxCRC32ErrCnt ++ u32_t Hw_DecrypErr_UNI; // 31 ++ u32_t Hw_DecrypErr_Mul; // 32 ++ ++ u32_t Hw_RxFIFOOverrun; // 34 ++ u32_t Hw_RxTimeOut; // 35 ++ u32_t LossAP; // 36 ++ ++ u32_t Tx_MPDU; // 37 ++ u32_t BA_Fail; // 38 ++ u32_t Hw_Tx_AMPDU; // 39 ++ u32_t Hw_Tx_MPDU; // 40 ++ ++ u32_t RateCtrlTxMPDU; ++ u32_t RateCtrlBAFail; ++ ++ u32_t txQosDropCount[5]; //41 42 43 44 45 ++ ++ u32_t Hw_RxMPDU; // 46 ++ u32_t Hw_RxDropMPDU; // 47 ++ u32_t Hw_RxDelMPDU; // 48 ++ ++ u32_t Hw_RxPhyMiscError; // 49 ++ u32_t Hw_RxPhyXRError; // 50 ++ u32_t Hw_RxPhyOFDMError; // 51 ++ u32_t Hw_RxPhyCCKError; // 52 ++ u32_t Hw_RxPhyHTError; // 53 ++ u32_t Hw_RxPhyTotalCount; // 54 ++ ++ u32_t swRxFragmentCount; // 55 ++ u32_t swRxUnicastMicFailCount; // 56 ++ u32_t swRxMulticastMicFailCount; // 57 ++ u32_t swRxDropUnencryptedCount; // 58 ++ ++ u32_t txBroadcastFrm; ++ u32_t txBroadcastOctets; ++}; ++ ++/* Traffic Monitor Tally data structure */ ++struct zsTrafTally ++{ ++ u32_t rxDuplicate; ++ u32_t rxSrcIsOwnMac; ++ //u32_t rxDataFrameCount; ++ //u32_t rxDataByteCount; ++ //u32_t rxDataBytesIn1000ms; ++ //u32_t rxDataTmpFor1000ms; ++ //u32_t rxDataBytesIn2000ms; ++ //u32_t rxDataTmpFor2000ms; ++ ++ //u32_t txDataFrameCount; ++ //u32_t txDataByteCount; ++ //u32_t txDataBytesIn1000ms; ++ //u32_t txDataTmpFor1000ms; ++ u32_t txDataBytesIn2000ms; ++ u32_t txDataTmpFor2000ms; ++}; ++ ++/* Hal rx packet moniter information */ ++struct zsMonHalRxInfo ++{ ++ u32_t currentRSSI[7]; ++ u32_t currentRxEVM[14]; ++ u32_t currentRxDataMT; ++ u32_t currentRxDataMCS; ++ u32_t currentRxDataBW; ++ u32_t currentRxDataSG; ++}; ++ ++struct zsTail ++{ ++ u8_t SignalStrength1; ++ u8_t SignalStrength2; ++ u8_t SignalStrength3; ++ u8_t SignalQuality; ++ u8_t SAIndex; ++ u8_t DAIndex; ++ u8_t ErrorIndication; ++ u8_t RxMacStatus; ++}; ++ ++union zuTail ++{ ++ struct zsTail Data; ++ u8_t Byte[8]; ++}; ++ ++struct zsAdditionInfo ++{ ++ u8_t PlcpHeader[12]; ++ union zuTail Tail; ++}; ++ ++ ++struct zsPmkidBssidInfo ++{ ++ u16_t bssid[3]; ++ u8_t pmkid[16]; ++}; ++ ++struct zsPmkidInfo ++{ ++ u32_t bssidCount; ++ struct zsPmkidBssidInfo bssidInfo[ZM_PMKID_MAX_BSS_CNT]; ++}; ++ ++ ++struct zsCbFuncTbl ++{ ++ u16_t (*zfcbAuthNotify)(zdev_t* dev, u16_t* macAddr); ++ u16_t (*zfcbAsocNotify)(zdev_t* dev, u16_t* macAddr, u8_t* body, ++ u16_t bodySize, u16_t port); ++ u16_t (*zfcbDisAsocNotify)(zdev_t* dev, u8_t* macAddr, u16_t port); ++ u16_t (*zfcbApConnectNotify)(zdev_t* dev, u8_t* macAddr, u16_t port); ++ void (*zfcbConnectNotify)(zdev_t* dev, u16_t status, u16_t* bssid); ++ void (*zfcbScanNotify)(zdev_t* dev, struct zsScanResult* result); ++ void (*zfcbMicFailureNotify)(zdev_t* dev, u16_t* addr, u16_t status); ++ void (*zfcbApMicFailureNotify)(zdev_t* dev, u8_t* addr, zbuf_t* buf); ++ void (*zfcbIbssPartnerNotify)(zdev_t* dev, u16_t status, ++ struct zsPartnerNotifyEvent *event); ++ void (*zfcbMacAddressNotify)(zdev_t* dev, u8_t* addr); ++ void (*zfcbSendCompleteIndication)(zdev_t* dev, zbuf_t* buf); ++ void (*zfcbRecvEth)(zdev_t* dev, zbuf_t* buf, u16_t port); ++ void (*zfcbRecv80211)(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++ void (*zfcbRestoreBufData)(zdev_t* dev, zbuf_t* buf); ++#ifdef ZM_ENABLE_CENC ++ u16_t (*zfcbCencAsocNotify)(zdev_t* dev, u16_t* macAddr, u8_t* body, ++ u16_t bodySize, u16_t port); ++#endif //ZM_ENABLE_CENC ++ u8_t (*zfcbClassifyTxPacket)(zdev_t* dev, zbuf_t* buf); ++ ++ void (*zfcbHwWatchDogNotify)(zdev_t* dev); ++}; ++ ++extern void zfZeroMemory(u8_t* va, u16_t length); ++#define ZM_INIT_CB_FUNC_TABLE(p) zfZeroMemory((u8_t *)p, sizeof(struct zsCbFuncTbl)); ++ ++//extern struct zsWlanDev zgWlanDev; ++ ++/* Initialize WLAN hardware and software, resource will be allocated */ ++/* for WLAN operation, must be called first before other function. */ ++extern u16_t zfiWlanOpen(zdev_t* dev, struct zsCbFuncTbl* cbFuncTbl); ++ ++/* WLAN hardware will be shutdown and all resource will be release */ ++extern u16_t zfiWlanClose(zdev_t* dev); ++ ++/* Enable/disable Wlan operation */ ++extern u16_t zfiWlanEnable(zdev_t* dev); ++extern u16_t zfiWlanDisable(zdev_t* dev, u8_t ResetKeyCache); ++extern u16_t zfiWlanResume(zdev_t* dev, u8_t doReconn); ++extern u16_t zfiWlanSuspend(zdev_t* dev); ++ ++/* Enable/disable ISR interrupt */ ++extern u16_t zfiWlanInterruptEnable(zdev_t* dev); ++extern u16_t zfiWlanInterruptDisable(zdev_t* dev); ++ ++/* Do WLAN site survey */ ++extern u16_t zfiWlanScan(zdev_t* dev); ++ ++/* Get WLAN stastics */ ++extern u16_t zfiWlanGetStatistics(zdev_t* dev); ++ ++/* Reset WLAN */ ++extern u16_t zfiWlanReset(zdev_t* dev); ++ ++/* Deauthenticate a STA */ ++extern u16_t zfiWlanDeauth(zdev_t* dev, u16_t* macAddr, u16_t reason); ++ ++extern u16_t zfiTxSendEth(zdev_t* dev, zbuf_t* buf, u16_t port); ++extern u8_t zfiIsTxQueueFull(zdev_t* dev); ++extern u16_t zfiTxSend80211Mgmt(zdev_t* dev, zbuf_t* buf, u16_t port); ++ ++extern void zfiIsrPci(zdev_t* dev); ++ ++extern u8_t zfiWlanIBSSGetPeerStationsCount(zdev_t* dev); ++extern u8_t zfiWlanIBSSIteratePeerStations(zdev_t* dev, u8_t numToIterate, zfpIBSSIteratePeerStationCb callback, void *ctx); ++extern void zfiWlanFlushAllQueuedBuffers(zdev_t* dev); ++ ++/* coid.c */ ++extern void zfiWlanQueryMacAddress(zdev_t* dev, u8_t* addr); ++ ++extern u16_t zfiGlobalDataSize(zdev_t* dev); ++ ++extern void zfiHeartBeat(zdev_t* dev); ++ ++extern void zfiWlanSetWlanMode(zdev_t* dev, u8_t wlanMode); ++extern void zfiWlanSetAuthenticationMode(zdev_t* dev, u8_t authMode); ++extern void zfiWlanSetWepStatus(zdev_t* dev, u8_t wepStatus); ++extern void zfiWlanSetSSID(zdev_t* dev, u8_t* ssid, u8_t ssidLength); ++extern void zfiWlanSetFragThreshold(zdev_t* dev, u16_t fragThreshold); ++extern void zfiWlanSetRtsThreshold(zdev_t* dev, u16_t rtsThreshold); ++extern void zfiWlanSetFrequency(zdev_t* dev, u32_t frequency, u8_t bImmediate); ++extern void zfiWlanSetBssid(zdev_t* dev, u8_t* bssid); ++extern void zfiWlanSetBeaconInterval(zdev_t* dev, u16_t beaconInterval, ++ u8_t bImmediate); ++extern void zfiWlanSetDtimCount(zdev_t* dev, u8_t dtim); ++extern void zfiWlanSetAtimWindow(zdev_t* dev, u16_t atimWindow, u8_t bImmediate); ++extern void zfiWlanSetEncryMode(zdev_t* dev, u8_t encryMode); ++extern u8_t zfiWlanSetKey(zdev_t* dev, struct zsKeyInfo keyInfo); ++extern u8_t zfiWlanPSEUDOSetKey(zdev_t* dev, struct zsKeyInfo keyInfo); ++extern void zfiWlanSetPowerSaveMode(zdev_t* dev, u8_t mode); ++extern void zfiWlanQueryBssListV1(zdev_t* dev, struct zsBssListV1* bssListV1); ++extern void zfiWlanQueryBssList(zdev_t* dev, struct zsBssList* pBssList); ++extern void zfiWlanSetProtectionMode(zdev_t* dev, u8_t mode); ++extern void zfiWlanFlushBssList(zdev_t* dev); ++ ++void zfiWlanDisableDfsChannel(zdev_t* dev, u8_t disableFlag); ++ ++extern u8_t zfiWlanQueryWlanMode(zdev_t* dev); ++extern u16_t zfiWlanChannelToFrequency(zdev_t* dev, u8_t channel); ++extern u8_t zfiWlanFrequencyToChannel(zdev_t* dev, u16_t freq); ++ ++#define ZM_WLAN_STATE_OPENED 0 ++#define ZM_WLAN_STATE_ENABLED 1 ++#define ZM_WLAN_STATE_DISABLED 2 ++#define ZM_WLAN_STATE_CLOSEDED 3 ++extern u8_t zfiWlanQueryAdapterState(zdev_t* dev); ++extern u8_t zfiWlanQueryAuthenticationMode(zdev_t* dev, u8_t bWrapper); ++extern u8_t zfiWlanQueryWepStatus(zdev_t* dev, u8_t bWrapper); ++extern void zfiWlanQuerySSID(zdev_t* dev, u8_t* ssid, u8_t* pSsidLength); ++extern u16_t zfiWlanQueryFragThreshold(zdev_t* dev); ++extern u16_t zfiWlanQueryRtsThreshold(zdev_t* dev); ++extern u32_t zfiWlanQueryFrequency(zdev_t* dev); ++extern u32_t zfiWlanQueryCurrentFrequency(zdev_t* dev, u8_t qmode); ++extern u32_t zfiWlanQueryFrequencyAttribute(zdev_t* dev, u32_t frequency); ++extern void zfiWlanQueryFrequencyHT(zdev_t* dev, u32_t *bandWidth, u32_t *extOffset); ++extern u8_t zfiWlanQueryCWMode(zdev_t* dev); ++extern u32_t zfiWlanQueryCWEnable(zdev_t* dev); ++extern void zfiWlanQueryBssid(zdev_t* dev, u8_t* bssid); ++extern u16_t zfiWlanQueryBeaconInterval(zdev_t* dev); ++extern u32_t zfiWlanQueryRxBeaconTotal(zdev_t* dev); ++extern u16_t zfiWlanQueryAtimWindow(zdev_t* dev); ++extern u8_t zfiWlanQueryEncryMode(zdev_t* dev); ++extern u16_t zfiWlanQueryCapability(zdev_t* dev); ++extern u16_t zfiWlanQueryAid(zdev_t* dev); ++extern void zfiWlanQuerySupportRate(zdev_t* dev, u8_t* rateArray, u8_t* pLength); ++extern void zfiWlanQueryExtSupportRate(zdev_t* dev, u8_t* rateArray, u8_t* pLength); ++extern void zfiWlanQueryRsnIe(zdev_t* dev, u8_t* ie, u8_t* pLength); ++extern void zfiWlanQueryWpaIe(zdev_t* dev, u8_t* ie, u8_t* pLength); ++extern u8_t zfiWlanQueryHTMode(zdev_t* dev); ++extern u8_t zfiWlanQueryBandWidth40(zdev_t* dev); ++extern u8_t zfiWlanQueryMulticastCipherAlgo(zdev_t *dev); ++extern u16_t zfiWlanQueryRegionCode(zdev_t* dev); ++extern void zfiWlanSetWpaIe(zdev_t* dev, u8_t* ie, u8_t Length); ++extern void zfiWlanSetWpaSupport(zdev_t* dev, u8_t WpaSupport); ++extern void zfiWlanCheckStaWpaIe(zdev_t* dev); ++extern void zfiWlanSetBasicRate(zdev_t* dev, u8_t bRateSet, u8_t gRateSet, ++ u32_t nRateSet); ++extern void zfiWlanSetBGMode(zdev_t* dev, u8_t mode); ++extern void zfiWlanSetpreambleType(zdev_t* dev, u8_t type); ++extern u8_t zfiWlanQuerypreambleType(zdev_t* dev); ++extern u8_t zfiWlanQueryPowerSaveMode(zdev_t* dev); ++extern void zfiWlanSetMacAddress(zdev_t* dev, u16_t* mac); ++extern u16_t zfiWlanSetTxRate(zdev_t* dev, u16_t rate); ++extern u32_t zfiWlanQueryTxRate(zdev_t* dev); ++extern void zfWlanUpdateRxRate(zdev_t* dev, struct zsAdditionInfo* addInfo); ++extern u32_t zfiWlanQueryRxRate(zdev_t* dev); ++extern u8_t zfiWlanSetPmkidInfo(zdev_t* dev, u16_t* bssid, u8_t* pmkid); ++extern u32_t zfiWlanQueryPmkidInfo(zdev_t* dev, u8_t* buf, u32_t len); ++extern void zfiWlanSetAllMulticast(zdev_t* dev, u32_t setting); ++extern void zfiWlanSetHTCtrl(zdev_t* dev, u32_t *setting, u32_t forceTxTPC); ++extern void zfiWlanQueryHTCtrl(zdev_t* dev, u32_t *setting, u32_t *forceTxTPC); ++extern void zfiWlanDbg(zdev_t* dev, u8_t setting); ++ ++extern void zfiWlanResetTally(zdev_t* dev); ++extern void zfiWlanQueryTally(zdev_t* dev, struct zsCommTally *tally); ++extern void zfiWlanQueryTrafTally(zdev_t* dev, struct zsTrafTally *tally); ++extern void zfiWlanQueryMonHalRxInfo(zdev_t* dev, struct zsMonHalRxInfo *halRxInfo); ++ ++extern u32_t zfiFWConfig(zdev_t* dev, u32_t size); ++ ++extern void zfiDKEnable(zdev_t* dev, u32_t enable); ++ ++extern void zfiWlanSetMulticastList(zdev_t* dev, u8_t size, u8_t* pList); ++extern void zfiWlanRemoveKey(zdev_t* dev, u8_t keyType, u8_t keyId); ++extern u8_t zfiWlanQueryIsPKInstalled(zdev_t *dev, u8_t *staMacAddr); ++extern u32_t zfiWlanQueryPacketTypePromiscuous(zdev_t* dev); ++extern void zfiWlanSetPacketTypePromiscuous(zdev_t* dev, u32_t setValue); ++extern void zfiSetChannelManagement(zdev_t* dev, u32_t setting); ++extern void zfiSetRifs(zdev_t* dev, u16_t setting); ++extern void zfiCheckRifs(zdev_t* dev); ++extern void zfiSetReorder(zdev_t* dev, u16_t value); ++extern void zfiSetSeqDebug(zdev_t* dev, u16_t value); ++ ++extern u16_t zfiConfigWdsPort(zdev_t* dev, u8_t wdsPortId, u16_t flag, u16_t* wdsAddr, ++ u16_t encType, u32_t* wdsKey); ++extern void zfiWlanQueryRegulationTable(zdev_t* dev, struct zsRegulationTable* pEntry); ++extern void zfiWlanSetScanTimerPerChannel(zdev_t* dev, u16_t time); ++extern void zfiWlanSetAutoReconnect(zdev_t* dev, u8_t enable); ++extern u32_t zfiDebugCmd(zdev_t* dev, u32_t cmd, u32_t value); ++extern void zfiWlanSetProbingHiddenSsid(zdev_t* dev, u8_t* ssid, u8_t ssidLen, ++ u16_t entry); ++extern void zfiWlanSetDropUnencryptedPackets(zdev_t* dev, u8_t enable); ++extern void zfiWlanSetIBSSJoinOnly(zdev_t* dev, u8_t joinOnly); ++extern void zfiWlanSetDefaultKeyId(zdev_t* dev, u8_t keyId); ++extern void zfiWlanSetDisableProbingWithSsid(zdev_t* dev, u8_t mode); ++extern void zfiWlanQueryGSN(zdev_t* dev, u8_t *gsn, u16_t vapId); ++extern u16_t zfiStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType); ++extern u8_t zfiWlanSetDot11DMode(zdev_t* dev, u8_t mode); ++extern u8_t zfiWlanSetDot11HDFSMode(zdev_t* dev, u8_t mode); ++extern u8_t zfiWlanSetDot11HTPCMode(zdev_t* dev, u8_t mode); ++extern u8_t zfiWlanSetAniMode(zdev_t* dev, u8_t mode); ++extern void zfiWlanSetStaWme(zdev_t* dev, u8_t enable, u8_t uapsdInfo); ++extern void zfiWlanSetApWme(zdev_t* dev, u8_t enable); ++extern u8_t zfiWlanQuerywmeEnable(zdev_t* dev); ++#ifdef ZM_OS_LINUX_FUNC ++extern void zfiWlanShowTally(zdev_t* dev); ++#endif ++#ifdef ZM_ENABLE_CENC ++/* CENC */ ++extern u8_t zfiWlanSetCencPairwiseKey(zdev_t* dev, u8_t keyid, u32_t *txiv, u32_t *rxiv, ++ u8_t *key, u8_t *mic); ++extern u8_t zfiWlanSetCencGroupKey(zdev_t* dev, u8_t keyid, u32_t *rxiv, ++ u8_t *key, u8_t *mic); ++#endif //ZM_ENABLE_CENC ++extern void zfiWlanQuerySignalInfo(zdev_t* dev, u8_t *buffer); ++extern void zfiWlanQueryAdHocCreatedBssDesc(zdev_t* dev, struct zsBssInfo *pBssInfo); ++extern u8_t zfiWlanQueryAdHocIsCreator(zdev_t* dev); ++extern u32_t zfiWlanQuerySupportMode(zdev_t* dev); ++extern u32_t zfiWlanQueryTransmitPower(zdev_t* dev); ++extern void zfiWlanEnableLeapConfig(zdev_t* dev, u8_t leapEnabled); ++ ++/* returned buffer allocated by driver core */ ++extern void zfiRecvEthComplete(zdev_t* dev, zbuf_t* buf); ++ ++extern void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++ ++extern void zfiWlanSetMaxTxPower(zdev_t* dev, u8_t power2, u8_t power5); ++extern void zfiWlanQueryMaxTxPower(zdev_t* dev, u8_t *power2, u8_t *power5); ++extern void zfiWlanSetConnectMode(zdev_t* dev, u8_t mode); ++extern void zfiWlanSetSupportMode(zdev_t* dev, u32_t mode); ++extern void zfiWlanSetAdhocMode(zdev_t* dev, u32_t mode); ++extern u32_t zfiWlanQueryAdhocMode(zdev_t* dev, u8_t bWrapper); ++extern u8_t zfiWlanSetCountryIsoName(zdev_t* dev, u8_t *countryIsoName, u8_t length); ++extern const char* zfiWlanQueryCountryIsoName(zdev_t* dev); ++extern u8_t zfiWlanQueryregulatoryDomain(zdev_t* dev); ++extern u8_t zfiWlanQueryCCS(zdev_t* dev); ++extern void zfiWlanSetCCS(zdev_t* dev, u8_t mode); ++extern void zfiWlanSetRegulatory(zdev_t* dev, u8_t CCS, u16_t Code, u8_t bfirstChannel); ++extern const char* zfiHpGetisoNamefromregionCode(zdev_t* dev, u16_t regionCode); ++extern void zfiWlanSetLEDCtrlParam(zdev_t* dev, u8_t type, u8_t flag); ++extern u32_t zfiWlanQueryReceivedPacket(zdev_t* dev); ++extern void zfiWlanCheckSWEncryption(zdev_t* dev); ++extern u16_t zfiWlanQueryAllowChannels(zdev_t *dev, u16_t *channels); ++extern u16_t zfiWlanGetMulticastAddressCount(zdev_t* dev); ++extern void zfiWlanGetMulticastList(zdev_t* dev, u8_t* pMCList); ++extern void zfiWlanSetPacketFilter(zdev_t* dev, u32_t PacketFilter); ++extern u8_t zfiCompareWithMulticastListAddress(zdev_t* dev, u16_t* dstMacAddr); ++extern void zfiWlanSetSafeModeEnabled(zdev_t* dev, u8_t safeMode); ++extern void zfiWlanSetIBSSAdditionalIELength(zdev_t* dev, u32_t ibssAdditionalIESize, u8_t* ibssAdditionalIE); ++extern void zfiWlanSetXLinkMode(zdev_t* dev, u32_t setValue); ++ ++/* hprw.c */ ++extern u32_t zfiDbgWriteFlash(zdev_t* dev, u32_t addr, u32_t val); ++extern u32_t zfiDbgWriteReg(zdev_t* dev, u32_t addr, u32_t val); ++extern u32_t zfiDbgReadReg(zdev_t* dev, u32_t addr); ++ ++extern u32_t zfiDbgWriteEeprom(zdev_t* dev, u32_t addr, u32_t val); ++extern u32_t zfiDbgBlockWriteEeprom(zdev_t* dev, u32_t addr, u32_t* buf); ++extern u32_t zfiDbgBlockWriteEeprom_v2(zdev_t* dev, u32_t addr, u32_t* buf, u32_t wrlen); ++ ++extern u16_t zfiDbgChipEraseFlash(zdev_t *dev); ++extern u16_t zfiDbgProgramFlash(zdev_t *dev, u32_t offset, u32_t len, u32_t *data); ++extern u32_t zfiDbgGetFlashCheckSum(zdev_t *dev, u32_t addr, u32_t len); ++extern u32_t zfiDbgReadFlash(zdev_t *dev, u32_t addr, u32_t len); ++extern u32_t zfiDownloadFwSet(zdev_t *dev); ++ ++extern u32_t zfiDbgDelayWriteReg(zdev_t* dev, u32_t addr, u32_t val); ++extern u32_t zfiDbgFlushDelayWrite(zdev_t* dev); ++ ++extern u32_t zfiDbgSetIFSynthesizer(zdev_t* dev, u32_t value); ++extern u32_t zfiDbgReadTally(zdev_t* dev); ++ ++extern u32_t zfiDbgQueryHwTxBusy(zdev_t* dev); ++ ++extern u8_t zfiWlanGetDestAddrFromBuf(zdev_t *dev, zbuf_t *buf, u16_t *macAddr); ++ ++extern u32_t zfiWlanQueryHwCapability(zdev_t* dev); ++ ++extern void zfiWlanSetDynamicSIFSParam(zdev_t* dev, u8_t val); ++ ++/***** End of section 2 *****/ ++ ++/***** section 3 performace evaluation *****/ ++#ifdef ZM_ENABLE_PERFORMANCE_EVALUATION ++extern void zfiTxPerformanceMSDU(zdev_t* dev, u32_t tick); ++extern void zfiRxPerformanceMPDU(zdev_t* dev, zbuf_t* buf); ++extern void zfiRxPerformanceReg(zdev_t* dev, u32_t reg, u32_t rsp); ++#define ZM_PERFORMANCE_INIT(dev) zfiPerformanceInit(dev); ++#define ZM_PERFORMANCE_TX_MSDU(dev, tick) zfiTxPerformanceMSDU(dev, tick); ++#define ZM_PERFORMANCE_RX_MSDU(dev, tick) zfiRxPerformanceMSDU(dev, tick); ++#define ZM_PERFORMANCE_TX_MPDU(dev, tick) zfiTxPerformanceMPDU(dev, tick); ++#define ZM_PERFORMANCE_RX_MPDU(dev, buf) zfiRxPerformanceMPDU(dev, buf); ++#define ZM_PERFORMANCE_RX_SEQ(dev, buf) zfiRxPerformanceSeq(dev, buf); ++#define ZM_PERFORMANCE_REG(dev, reg, rsp) {if(cmd[1] == reg) zfiRxPerformanceReg(dev, reg, rsp);} ++#define ZM_PERFORMANCE_DUP(dev, buf1, buf2) zfiRxPerformanceDup(dev, buf1, buf2); ++#define ZM_PERFORMANCE_FREE(dev, buf) zfiRxPerformanceFree(dev, buf); ++#define ZM_PERFORMANCE_RX_AMSDU(dev, buf, len) zfiRxPerformanceAMSDU(dev, buf, len); ++#define ZM_PERFORMANCE_RX_FLUSH(dev) zfiRxPerformanceFlush(dev); ++#define ZM_PERFORMANCE_RX_CLEAR(dev) zfiRxPerformanceClear(dev); ++#define ZM_SEQ_DEBUG if (wd->seq_debug) DbgPrint ++#define ZM_PERFORMANCE_RX_REORDER(dev) zfiRxPerformanceReorder(dev); ++#else ++#define ZM_PERFORMANCE_INIT(dev) ++#define ZM_PERFORMANCE_TX_MSDU(dev, tick) ++#define ZM_PERFORMANCE_RX_MSDU(dev, tick) ++#define ZM_PERFORMANCE_TX_MPDU(dev, tick) ++#define ZM_PERFORMANCE_RX_MPDU(dev, buf) ++#define ZM_PERFORMANCE_RX_SEQ(dev, buf) ++#define ZM_PERFORMANCE_REG(dev, reg, rsp) ++#define ZM_PERFORMANCE_DUP(dev, buf1, buf2) ++#define ZM_PERFORMANCE_FREE(dev, buf) ++#define ZM_PERFORMANCE_RX_AMSDU(dev, buf, len) ++#define ZM_PERFORMANCE_RX_FLUSH(dev) ++#define ZM_PERFORMANCE_RX_CLEAR(dev) ++#define ZM_SEQ_DEBUG ++#define ZM_PERFORMANCE_RX_REORDER(dev) ++#endif ++/***** End of section 3 *****/ ++#endif +--- /dev/null ++++ b/drivers/staging/otus/80211core/pub_zfw.h +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _PUB_ZFW_H ++#define _PUB_ZFW_H ++ ++#include "../oal_dt.h" ++ ++ ++/* Buffer management */ ++#ifdef ZM_ENABLE_BUFFER_DEBUG ++extern zbuf_t* zfwBufAllocateWithContext(zdev_t* dev, u16_t len, u8_t *functionName, ULONG line); ++#define zfwBufAllocate(dev, len) zfwBufAllocateWithContext(dev, len, (u8_t *)__FUNCTION__, __LINE__) ++#else ++extern zbuf_t* zfwBufAllocate(zdev_t* dev, u16_t len); ++#endif ++extern void zfwBufFree(zdev_t* dev, zbuf_t* buf, u16_t errCode); ++extern u16_t zfwBufChain(zdev_t* dev, zbuf_t** head, zbuf_t* tail); ++extern u16_t zfwBufCopy(zdev_t* dev, zbuf_t* dst, zbuf_t* src); ++extern u16_t zfwBufSetSize(zdev_t* dev, zbuf_t* buf, u16_t size); ++extern u16_t zfwBufRemoveHead(zdev_t* dev, zbuf_t* buf, u16_t size); ++extern u16_t zfwBufGetSize(zdev_t* dev, zbuf_t* buf); ++extern void zfwCopyBufContext(zdev_t* dev, zbuf_t* source, zbuf_t* dest); ++ ++/* Memory management */ ++extern void* zfwMemAllocate(zdev_t* dev, u32_t size); ++extern void zfwMemFree(zdev_t* dev, void* mem, u32_t size); ++extern void zfwMemoryCopy(u8_t* dst, u8_t* src, u16_t length); ++extern void zfwMemoryMove(u8_t* dst, u8_t* src, u16_t length); ++extern void zfwZeroMemory(u8_t* va, u16_t length); ++extern u8_t zfwMemoryIsEqual(u8_t* m1, u8_t* m2, u16_t length); ++ ++/* Others */ ++extern void zfwSleep(zdev_t* dev, u32_t ms); ++extern u16_t zfwGetVapId(zdev_t* dev); ++extern u16_t zfwStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType); ++extern u32_t zfwWaitForEvent(zdev_t *dev, u32_t event, u32_t timeout); ++extern void zfwSendEvent(zdev_t* dev); ++extern void zfwGetActiveScanDur(zdev_t* dev, u8_t* Dur ); ++extern void zfwGetShowZeroLengthSSID(zdev_t* dev, u8_t* Dur ); ++/* For debugging */ ++extern void zfwDumpBuf(zdev_t* dev, zbuf_t* buf); ++extern void zfwDbgReadRegDone(zdev_t* dev, u32_t addr, u32_t val); ++/* For Evl */ ++extern void zfwDbgDownloadFwInitDone(zdev_t* dev); ++extern void zfwDbgReadFlashDone(zdev_t* dev, u32_t addr, u32_t* rspdata, u32_t datalen); ++extern void zfwDbgGetFlashChkSumDone(zdev_t* dev, u32_t* rspdata); ++extern void zfwDbgProgrameFlashDone(zdev_t* dev); ++extern void zfwDbgProgrameFlashChkDone(zdev_t* dev); ++extern void zfwDbgWriteRegDone(zdev_t* dev, u32_t addr, u32_t val); ++extern void zfwDbgWriteEepromDone(zdev_t* dev, u32_t addr, u32_t val); ++extern void zfwDbgReadTallyDone(zdev_t* dev); ++extern void zfwWlanReadRegDone(zdev_t* dev, u32_t addr, u32_t val); ++extern void zfwWlanWriteRegDone(zdev_t* dev, u32_t addr, u32_t val); ++extern void zfwWlanReadTallyDone(zdev_t* dev); ++extern void zfwDbgQueryHwTxBusyDone(zdev_t* dev, u32_t val); ++extern u32_t zfwReadReg(zdev_t* dev, u32_t offset); ++extern u32_t zfwReadEeprom(zdev_t* dev, u32_t addr); ++ ++/* Reserved for Vista, please return 0 */ ++extern u8_t zfwGetPktEncExemptionActionType(zdev_t* dev, zbuf_t* buf); ++ ++#ifdef ZM_ENABLE_CENC ++/* Reserved for CENC, please return 0 */ ++extern u8_t zfwCencHandleBeaconProbrespon(zdev_t* dev, u8_t *pWIEc, ++ u8_t *pPeerSSIDc, u8_t *pPeerAddrc); ++#endif //ZM_ENABLE_CENC ++ ++#ifdef ZM_HALPLUS_LOCK ++extern asmlinkage struct zsWlanDev *zfwGetWlanDev(zdev_t* dev); ++extern asmlinkage void zfwEnterCriticalSection(zdev_t* dev); ++extern asmlinkage void zfwLeaveCriticalSection(zdev_t* dev); ++extern asmlinkage u8_t zfwBufReadByte(zdev_t* dev, zbuf_t* buf, u16_t offset); ++extern asmlinkage u16_t zfwBufReadHalfWord(zdev_t* dev, zbuf_t* buf, u16_t offset); ++extern asmlinkage void zfwBufWriteByte(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t value); ++extern asmlinkage void zfwBufWriteHalfWord(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t value); ++extern asmlinkage u8_t *zfwGetBuffer(zdev_t* dev, zbuf_t* buf); ++#endif ++ ++#endif //_PUB_ZFW_H +--- /dev/null ++++ b/drivers/staging/otus/80211core/queue.c +@@ -0,0 +1,303 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : queue.c */ ++/* */ ++/* Abstract */ ++/* This module contains queue management functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "cprecomp.h" ++#include "queue.h" ++ ++ ++struct zsQueue* zfQueueCreate(zdev_t* dev, u16_t size) ++{ ++ struct zsQueue* q; ++ ++ if ((q = (struct zsQueue*)zfwMemAllocate(dev, sizeof(struct zsQueue) ++ + (sizeof(struct zsQueueCell)*(size-1)))) != NULL) ++ { ++ q->size = size; ++ q->sizeMask = size-1; ++ q->head = 0; ++ q->tail = 0; ++ } ++ return q; ++} ++ ++void zfQueueDestroy(zdev_t* dev, struct zsQueue* q) ++{ ++ u16_t size = sizeof(struct zsQueue) + (sizeof(struct zsQueueCell)*(q->size-1)); ++ ++ zfQueueFlush(dev, q); ++ zfwMemFree(dev, q, size); ++ ++ return; ++} ++ ++u16_t zfQueuePutNcs(zdev_t* dev, struct zsQueue* q, zbuf_t* buf, u32_t tick) ++{ ++ u16_t ret = ZM_ERR_QUEUE_FULL; ++ ++ zm_msg0_mm(ZM_LV_1, "zfQueuePutNcs()"); ++ ++ if (((q->tail+1)&q->sizeMask) != q->head) ++ { ++ q->cell[q->tail].buf = buf; ++ q->cell[q->tail].tick = tick; ++ q->tail = (q->tail+1) & q->sizeMask; ++ ret = ZM_SUCCESS; ++ } ++ ++ return ret; ++} ++ ++u16_t zfQueuePut(zdev_t* dev, struct zsQueue* q, zbuf_t* buf, u32_t tick) ++{ ++ u16_t ret; ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ ret = zfQueuePutNcs(dev, q, buf, tick); ++ ++ zmw_leave_critical_section(dev); ++ ++ return ret; ++} ++ ++zbuf_t* zfQueueGet(zdev_t* dev, struct zsQueue* q) ++{ ++ zbuf_t* buf = NULL; ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (q->head != q->tail) ++ { ++ buf = q->cell[q->head].buf; ++ q->head = (q->head+1) & q->sizeMask; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return buf; ++} ++ ++u16_t zfCompareDstwithBuf(zdev_t* dev, zbuf_t* buf, u8_t* addr) ++{ ++ u16_t i; ++ u8_t dst[6]; ++ ++ for (i=0; i<6; i++) ++ { ++ dst[i] = zmw_buf_readb(dev, buf, i); ++ if (dst[i] != addr[i]) ++ { ++ return 1+i; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++zbuf_t* zfQueueGetWithMac(zdev_t* dev, struct zsQueue* q, u8_t* addr, u8_t* mb) ++{ ++ zbuf_t* buf; ++ zbuf_t* retBuf = NULL; ++ u16_t index, next; ++ zmw_declare_for_critical_section(); ++ ++ *mb = 0; ++ ++ zmw_enter_critical_section(dev); ++ ++ index = q->head; ++ ++ while (1) ++ { ++ if (index != q->tail) ++ { ++ buf = q->cell[index].buf; ++ ++ //if buf's detination address == input addr ++ if (zfCompareDstwithBuf(dev, buf, addr) == 0) ++ { ++ retBuf = buf; ++ //Get it, and trace the whole queue to calculate more bit ++ while ((next =((index+1)&q->sizeMask)) != q->tail) ++ { ++ q->cell[index].buf = q->cell[next].buf; ++ q->cell[index].tick = q->cell[next].tick; ++ ++ if ((*mb == 0) && (zfCompareDstwithBuf(dev, ++ q->cell[next].buf, addr) == 0)) ++ { ++ *mb = 1; ++ } ++ ++ index = next; ++ } ++ q->tail = (q->tail-1) & q->sizeMask; ++ ++ zmw_leave_critical_section(dev); ++ return retBuf; ++ } ++ index = (index + 1) & q->sizeMask; ++ } //if (index != q->tail) ++ else ++ { ++ break; ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return retBuf; ++ ++} ++ ++void zfQueueFlush(zdev_t* dev, struct zsQueue* q) ++{ ++ zbuf_t* buf; ++ ++ while ((buf = zfQueueGet(dev, q)) != NULL) ++ { ++ zfwBufFree(dev, buf, 0); ++ } ++ ++ return; ++} ++ ++void zfQueueAge(zdev_t* dev, struct zsQueue* q, u32_t tick, u32_t msAge) ++{ ++ zbuf_t* buf; ++ u32_t buftick; ++ zmw_declare_for_critical_section(); ++ ++ while (1) ++ { ++ buf = NULL; ++ zmw_enter_critical_section(dev); ++ ++ if (q->head != q->tail) ++ { ++ buftick = q->cell[q->head].tick; ++ if (((tick - buftick)*ZM_MS_PER_TICK) > msAge) ++ { ++ buf = q->cell[q->head].buf; ++ q->head = (q->head+1) & q->sizeMask; ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (buf != NULL) ++ { ++ zm_msg0_mm(ZM_LV_0, "Age frame in queue!"); ++ zfwBufFree(dev, buf, 0); ++ } ++ else ++ { ++ break; ++ } ++ } ++ return; ++} ++ ++ ++u8_t zfQueueRemovewithIndex(zdev_t* dev, struct zsQueue* q, u16_t index, u8_t* addr) ++{ ++ u16_t next; ++ u8_t mb = 0; ++ ++ //trace the whole queue to calculate more bit ++ while ((next =((index+1)&q->sizeMask)) != q->tail) ++ { ++ q->cell[index].buf = q->cell[next].buf; ++ q->cell[index].tick = q->cell[next].tick; ++ ++ if ((mb == 0) && (zfCompareDstwithBuf(dev, ++ q->cell[next].buf, addr) == 0)) ++ { ++ mb = 1; ++ } ++ ++ index = next; ++ } ++ q->tail = (q->tail-1) & q->sizeMask; ++ ++ return mb; ++ ++} ++ ++void zfQueueGenerateUapsdTim(zdev_t* dev, struct zsQueue* q, ++ u8_t* uniBitMap, u16_t* highestByte) ++{ ++ zbuf_t* psBuf; ++ u8_t dst[6]; ++ u16_t id, aid, index, i; ++ u16_t bitPosition; ++ u16_t bytePosition; ++ zmw_get_wlan_dev(dev); ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ index = q->head; ++ ++ while (index != q->tail) ++ { ++ psBuf = q->cell[index].buf; ++ for (i=0; i<6; i++) ++ { ++ dst[i] = zmw_buf_readb(dev, psBuf, i); ++ } ++ /* TODO : use u8_t* fot MAC address */ ++ if (((id = zfApFindSta(dev, (u16_t*)dst)) != 0xffff) ++ && (wd->ap.staTable[id].psMode != 0)) ++ { ++ /* Calculate PVB only when all AC are delivery-enabled */ ++ if ((wd->ap.staTable[id].qosInfo & 0xf) == 0xf) ++ { ++ aid = id + 1; ++ bitPosition = (1 << (aid & 0x7)); ++ bytePosition = (aid >> 3); ++ uniBitMap[bytePosition] |= bitPosition; ++ ++ if (bytePosition>*highestByte) ++ { ++ *highestByte = bytePosition; ++ } ++ } ++ index = (index+1) & q->sizeMask; ++ } ++ else ++ { ++ /* Free garbage UAPSD frame */ ++ zfQueueRemovewithIndex(dev, q, index, dst); ++ zfwBufFree(dev, psBuf, 0); ++ } ++ } ++ zmw_leave_critical_section(dev); ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/otus/80211core/queue.h +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _QUEUE_H ++#define _QUEUE_H ++ ++#include "../oal_dt.h" ++ ++struct zsQueueCell ++{ ++ u32_t tick; ++ zbuf_t* buf; ++}; ++ ++struct zsQueue ++{ ++ u16_t size; ++ u16_t sizeMask; ++ u16_t head; ++ u16_t tail; ++ struct zsQueueCell cell[1]; ++}; ++ ++#endif //#ifndef _QUEUE_H +--- /dev/null ++++ b/drivers/staging/otus/80211core/ratectrl.c +@@ -0,0 +1,874 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include "cprecomp.h" ++#include "ratectrl.h" ++ ++const u32_t zcRateToPhyCtrl[] = ++ { ++ /* 1M, 2M, 5M, 11M , 0 1 2 3*/ ++ 0x00000, 0x10000, 0x20000, 0x30000, ++ /* 6M 9M 12M 18M , 4 5 6 7*/ ++ 0xb0001, 0xf0001, 0xa0001, 0xe0001, ++ /* 24M 36M 48M 54M , 8 9 10 11*/ ++ 0x90001, 0xd0001, 0x80001, 0xc0001, ++ /* MCS0 MCS1 MCS2 MCS3, 12 13 14 15*/ ++ 0x00002, 0x10002, 0x20002, 0x30002, ++ /* MCS4 MCS5 MCS6 MCS7, 16 17 18 19*/ ++ 0x40002, 0x50002, 0x60002, 0x70002, ++ /* MCS8 MCS9 MCS10 MCS11, 20 21 22 23*/ ++ 0x80002, 0x90002, 0xa0002, 0xb0002, ++ /* MCS12 MCS13 MCS14 MCS15, 24 25 26 27*/ ++ 0xc0002, 0xd0002, 0xe0002, 0xf0002, ++ /* MCS14SG, MCS15SG MCS7SG , 28 29, 30*/ ++ 0x800e0002, 0x800f0002, 0x80070002 ++ }; ++ ++ ++const u8_t zcHtRateTable[15][4] = ++ { /*[5G 20MHz] [5G 40MHz] [2.4G 20MHz] [2.4G 40MHz]*/ ++ { 4, 4, 0, 0}, /*OFDM6M OFDM6M CCK1M CCK1M */ ++ { 5, 5, 1, 1}, /*OFDM9M OFDM9M CCK2M CCK2M */ ++ { 13, 12, 2, 2}, /*MCS1 MCS0 CCK5M CCK5M */ ++ { 14, 13, 3, 3}, /*MCS2 MCS1 CCK11M CCK11M */ ++ { 15, 14, 13, 12}, /*MCS3 MCS2 MCS1 MCS0 */ ++ { 16, 15, 14, 13}, /*MCS4 MCS3 MCS2 MCS1 */ ++ { 23, 16, 15, 14}, /*MCS11 MCS4 MCS3 MCS2 */ ++ { 24, 23, 16, 15}, /*MCS12 MCS11 MCS4 MCS3 */ ++ { 25, 24, 23, 16}, /*MCS13 MCS12 MCS11 MCS4 */ ++ { 26, 25, 24, 23}, /*MCS14 MCS13 MCS12 MCS11 */ ++ { 27, 26, 25, 24}, /*MCS15 MCS14 MCS13 MCS12 */ ++ { 0, 27, 26, 25}, /*0 MCS15 MCS14 MCS13 */ ++ { 0, 29, 27, 26}, /*0 MCS15SG MCS15 MCS14 */ ++ { 0, 0, 0, 28}, /*0 0 0 MCS14SG*/ ++ { 0, 0, 0, 29} /*0 0 0 MCS15SG*/ ++ }; ++ ++const u8_t zcHtOneTxStreamRateTable[15][4] = ++ { /*[5G 20MHz] [5G 40MHz] [2.4G 20MHz] [2.4G 40MHz]*/ ++ { 4, 4, 0, 0}, /*OFDM6M OFDM6M CCK1M CCK1M */ ++ { 5, 5, 1, 1}, /*OFDM9M OFDM9M CCK2M CCK2M */ ++ { 13, 12, 2, 2}, /*MCS1 MCS0 CCK5M CCK5M */ ++ { 14, 13, 3, 3}, /*MCS2 MCS1 CCK11M CCK11M */ ++ { 15, 14, 13, 12}, /*MCS3 MCS2 MCS1 MCS0 */ ++ { 16, 15, 14, 13}, /*MCS4 MCS3 MCS2 MCS1 */ ++ { 17, 16, 15, 14}, /*MCS5 MCS4 MCS3 MCS2 */ ++ { 18, 17, 16, 15}, /*MCS6 MCS5 MCS4 MCS3 */ ++ { 19, 18, 17, 16}, /*MCS7 MCS6 MCS5 MCS4 */ ++ { 0, 19, 18, 17}, /*0 MCS7 MCS6 MCS5 */ ++ { 0, 30, 19, 18}, /*0 MCS7SG MCS7 MCS6 */ ++ { 0, 0, 0, 19}, /*0 0 0 MCS7 */ ++ { 0, 0, 0, 30}, /*0 0 0 MCS7SG */ ++ { 0, 0, 0, 0 }, /*0 0 0 0 */ ++ { 0, 0, 0, 0 } /*0 0 0 0 */ ++ }; ++ ++const u16_t zcRate[] = ++ { ++ 1, 2, 5, 11, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ ++ 6, 9, 12, 18, /* 6M 9M 12M 18M , 4 5 6 7*/ ++ 24, 36, 48, 54, /* 24M 36M 48M 54M , 8 9 10 11*/ ++ 13, 27, 40, 54, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ ++ 81, 108, 121, 135, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ ++ 27, 54, 81, 108, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ ++ 162, 216, 243, 270, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ ++ 270, 300, 150 /* MCS14SG, MCS15SG, MCS7SG , 28 29 30*/ ++ }; ++ ++const u16_t PERThreshold[] = ++ { ++ 100, 50, 50, 50, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ ++ 50, 50, 30, 30, /* 6M 9M 12M 18M , 4 5 6 7*/ ++ 25, 25, 25, 20, /* 24M 36M 48M 54M , 8 9 10 11*/ ++ 50, 50, 50, 40, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ ++ 30, 30, 30, 30, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ ++ 30, 30, 25, 25, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ ++ 25, 25, 15, 15, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ ++ 15, 15, 10 /* MCS14SG, MCS15SG , 28 29*/ ++ }; ++ ++const u16_t FailDiff[] = ++ { ++ 40, 46, 40, 0, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ ++ 24, 17, 22, 16, /* 6M 9M 12M 18M , 4 5 6 7*/ ++ 19, 13, 5, 0, /* 24M 36M 48M 54M , 8 9 10 11*/ ++ 36, 22, 15, 19, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ ++ 12, 5, 4, 7, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ ++ 0, 0, 0, 0, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ ++ 9, 4, 3, 3, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ ++ 3, 0, 0 /* MCS14SG, MCS15SG , 28 29*/ ++ }; ++ ++ ++#ifdef ZM_ENABLE_BA_RATECTRL ++u32_t TxMPDU[29]; ++u32_t BAFail[29]; ++u32_t BAPER[29]; ++const u16_t BADiff[] = ++ { ++ 0, 0, 0, 0, ++ 0, 0, 0, 0, ++ 0, 0, 0, 0, ++ 361, 220, 151, 187, ++ 122, 48, 41, 65, ++ 0, 0, 0, 0, ++ 88, 33, 27, 25, ++ 0 ++ }; ++#endif ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlInitCell */ ++/* Initialize rate control cell. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* type : 0=>11b, 1=>11a/g, 2=>11n, 3=>11n one Tx stream */ ++/* gBand : 1=>2.4G, 0=>5G */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++void zfRateCtrlInitCell(zdev_t* dev, struct zsRcCell* rcCell, u8_t type, ++ u8_t gBand, u8_t SG40) ++{ ++ u8_t i; ++ u8_t maxrate; ++ zmw_get_wlan_dev(dev); ++ ++ if (SG40) SG40 = 1; ++ ++ if (gBand != 0) ++ { ++ if (type == 1) //11g ++ { ++ for (i=0; i<4; i++) //1M 2M 5M 11M ++ { ++ rcCell->operationRateSet[i] = (u8_t)i; ++ } ++ for (i=4; i<10; i++) //12M 18M 24M 36M 48M 54M ++ { ++ rcCell->operationRateSet[i] = 2+i; ++ } ++ rcCell->operationRateCount = 10; ++ rcCell->currentRateIndex = 5; //18M ++ } ++ else if (type == 2) //11ng ++ { ++ if (wd->wlanMode == ZM_MODE_AP) //AP 11ng 40M ++ { ++ for (i=0; i<15; i++) ++ { ++ rcCell->operationRateSet[i] = zcHtRateTable[i][3]; ++ } ++ if(!SG40) rcCell->operationRateSet[13] = 27; ++ rcCell->operationRateCount = 14+SG40; ++ rcCell->currentRateIndex = 10; ++ } ++ else //STA ++ { ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11ng 40M ++ { ++ for (i=0; i<15; i++) ++ { ++ rcCell->operationRateSet[i] = zcHtRateTable[i][3]; ++ } ++ if(!SG40) rcCell->operationRateSet[13] = 27; ++ rcCell->operationRateCount = 14+SG40; ++ rcCell->currentRateIndex = 10; ++ } ++ else //11ng 20M ++ { ++ for (i=0; i<13; i++) ++ { ++ rcCell->operationRateSet[i] = zcHtRateTable[i][2]; ++ } ++ rcCell->operationRateCount = 13; ++ rcCell->currentRateIndex = 9; ++ } ++ } ++ } ++ else if (type == 3) //11ng one Tx stream ++ { ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11ng 40M one Tx stream ++ { ++ if(SG40 != 0) ++ { ++ maxrate = 13; ++ } ++ else ++ { ++ maxrate = 12; ++ } ++ for (i=0; ioperationRateSet[i] = zcHtOneTxStreamRateTable[i][3]; ++ } ++ rcCell->operationRateCount = i; ++ rcCell->currentRateIndex = ((i+1)*3)/4; ++ } ++ else //11ng 20M ++ { ++ for (i=0; i<11; i++) ++ { ++ rcCell->operationRateSet[i] = zcHtOneTxStreamRateTable[i][2]; ++ } ++ rcCell->operationRateCount = i; ++ rcCell->currentRateIndex = ((i+1)*3)/4; ++ } ++ } ++ else //if (type == 0) //11b ++ { ++ for (i=0; i<4; i++) ++ { ++ rcCell->operationRateSet[i] = (u8_t)i; ++ } ++ rcCell->operationRateCount = 4; ++ rcCell->currentRateIndex = rcCell->operationRateCount-1; ++ } ++ } ++ else ++ { ++ if (type == 2) //11na ++ { ++ if (wd->wlanMode == ZM_MODE_AP) //AP 11na 40M ++ { ++ for (i=0; i<(12+SG40); i++) ++ { ++ rcCell->operationRateSet[i] = zcHtRateTable[i][1]; ++ } ++ rcCell->operationRateCount = 12+SG40; ++ rcCell->currentRateIndex = 8; ++ } ++ else //STA ++ { ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11na 40M ++ { ++ for (i=0; i<(12+SG40); i++) ++ { ++ rcCell->operationRateSet[i] = zcHtRateTable[i][1]; ++ } ++ rcCell->operationRateCount = 12+SG40; ++ rcCell->currentRateIndex = 8; ++ } ++ else //11na 20M ++ { ++ for (i=0; i<11; i++) ++ { ++ rcCell->operationRateSet[i] = zcHtRateTable[i][0]; ++ } ++ rcCell->operationRateCount = 11; ++ rcCell->currentRateIndex = 7; ++ } ++ } ++ } ++ else if (type == 3) //11na one Tx stream ++ { ++ if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11na 40M one Tx stream ++ { ++ if(SG40 != 0) ++ { ++ maxrate = 11; ++ } ++ else ++ { ++ maxrate = 10; ++ } ++ for (i=0; ioperationRateSet[i] = zcHtOneTxStreamRateTable[i][1]; ++ } ++ rcCell->operationRateCount = i; ++ rcCell->currentRateIndex = ((i+1)*3)/4; ++ } ++ else //11ng 20M ++ { ++ for (i=0; i<9; i++) ++ { ++ rcCell->operationRateSet[i] = zcHtOneTxStreamRateTable[i][0]; ++ } ++ rcCell->operationRateCount = i; ++ rcCell->currentRateIndex = ((i+1)*3)/4; ++ } ++ } ++ else //if (type == 1) //11a ++ { ++ for (i=0; i<8; i++) //6M 9M 12M 18M 24M 36M 48M 54M ++ { ++ rcCell->operationRateSet[i] = i+4; ++ } ++ rcCell->operationRateCount = 8; ++ rcCell->currentRateIndex = 4; //24M ++ } ++ } ++ ++ rcCell->flag = 0; ++ rcCell->txCount = 0; ++ rcCell->failCount = 0; ++ rcCell->currentRate = rcCell->operationRateSet[rcCell->currentRateIndex]; ++ rcCell->lasttxCount = 0; ++ rcCell->lastTime = wd->tick; ++ rcCell->probingTime = wd->tick; ++ for (i=0; iPER[i] = 0; ++ wd->txMPDU[i] = wd->txFail[i] = 0; ++ } ++ wd->probeCount = 0; ++ wd->probeInterval = 0; ++#ifdef ZM_ENABLE_BA_RATECTRL ++ for (i=0; i<29; i++) { ++ TxMPDU[i]=0; ++ BAFail[i]=0; ++ BAPER[i]=0; ++ } ++#endif ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlGetHigherRate */ ++/* Get a higher rate. */ ++/* */ ++/* INPUTS */ ++/* rcCell : rate control cell */ ++/* */ ++/* OUTPUTS */ ++/* rate */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++u8_t zfRateCtrlGetHigherRate(struct zsRcCell* rcCell) ++{ ++ u8_t rateIndex; ++ ++ rateIndex = rcCell->currentRateIndex ++ + (((rcCell->currentRateIndex+1) < rcCell->operationRateCount)?1:0); ++ return rcCell->operationRateSet[rateIndex]; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlNextLowerRate */ ++/* Get a lower rate. */ ++/* */ ++/* INPUTS */ ++/* rcCell : rate control cell */ ++/* */ ++/* OUTPUTS */ ++/* rate */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++u8_t zfRateCtrlNextLowerRate(zdev_t* dev, struct zsRcCell* rcCell) ++{ ++ zmw_get_wlan_dev(dev); ++ if (rcCell->currentRateIndex > 0) ++ { ++ rcCell->currentRateIndex--; ++ rcCell->currentRate = rcCell->operationRateSet[rcCell->currentRateIndex]; ++ } ++ zm_msg1_tx(ZM_LV_0, "Lower Tx Rate=", rcCell->currentRate); ++ //DbgPrint("Lower Tx Rate=%d", rcCell->currentRate); ++ rcCell->failCount = rcCell->txCount = 0; ++ rcCell->lasttxCount = 0; ++ rcCell->lastTime = wd->tick; ++ return rcCell->currentRate; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlRateDiff */ ++/* Rate difference. */ ++/* */ ++/* INPUTS */ ++/* rcCell : rate control cell */ ++/* retryRate : retry rate */ ++/* */ ++/* OUTPUTS */ ++/* rate difference */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++u8_t zfRateCtrlRateDiff(struct zsRcCell* rcCell, u8_t retryRate) ++{ ++ u16_t i; ++ ++ /* Find retryRate in operationRateSet[] */ ++ for (i=0; ioperationRateCount; i++) ++ { ++ if (retryRate == rcCell->operationRateSet[i]) ++ { ++ if (i < rcCell->currentRateIndex) ++ { ++ return ((rcCell->currentRateIndex - i)+1)>>1; ++ } ++ else if (i == rcCell->currentRateIndex == 0) ++ { ++ return 1; ++ } ++ else ++ { ++ return 0; ++ } ++ } ++ } ++ /* TODO : retry rate not in operation rate set */ ++ zm_msg1_tx(ZM_LV_0, "Not in operation rate set:", retryRate); ++ return 1; ++ ++} ++ ++u32_t zfRateCtrlUDPTP(zdev_t* dev, u16_t Rate, u32_t PER) { ++ if ((PER < 100) && (Rate > 0) && PER) ++ return 1168000/(((12304/Rate)+197)*(100+100*PER/(100-PER))); ++ else ++ return 0; ++} ++ ++u8_t zfRateCtrlFindMaxUDPTP(zdev_t* dev, struct zsRcCell* rcCell) { ++ u8_t i, maxIndex=0, rateIndex; ++ u32_t max=0, UDPThroughput; ++ ++ zmw_get_wlan_dev(dev); ++ ++ rateIndex = zm_agg_min(rcCell->currentRateIndex+3, rcCell->operationRateCount-1); ++ for (i=rcCell->currentRateIndex; i < rateIndex; i++) { ++ UDPThroughput = zfRateCtrlUDPTP(dev, zcRate[rcCell->operationRateSet[i]], ++ wd->PER[rcCell->operationRateSet[i]]); ++ if (max < UDPThroughput) { ++ max = UDPThroughput; ++ maxIndex = i; ++ } ++ } ++ ++ return rcCell->operationRateSet[maxIndex]; ++} ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlGetTxRate */ ++/* Get transmission rate. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* rcCell : rate control cell */ ++/* probing : rate probing flag */ ++/* */ ++/* OUTPUTS */ ++/* Tx rate */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++u16_t zfRateCtrlGetTxRate(zdev_t* dev, struct zsRcCell* rcCell, u16_t* probing) ++{ ++ u8_t newRate, highRate; ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg1_tx(ZM_LV_3, "txCount=", rcCell->txCount); ++ zm_msg1_tx(ZM_LV_3, "probingTime=", rcCell->probingTime); ++ zm_msg1_tx(ZM_LV_3, "tick=", wd->tick); ++ *probing = 0; ++ newRate = rcCell->currentRate; ++ ++ if (wd->probeCount && (wd->probeCount < wd->success_probing)) ++ { ++ if (wd->probeInterval < 50) ++ { ++ wd->probeInterval++; ++ } ++ else ++ { ++ wd->probeInterval++; ++ if (wd->probeInterval > 52) //probe 51, 52, 53 three packets every 50 packets ++ { ++ wd->probeInterval = 0; ++ } ++ newRate=zfRateCtrlGetHigherRate(rcCell); ++ *probing = 1; ++ wd->probeCount++; ++ rcCell->probingTime = wd->tick; ++ } ++ } ++ /* Accumulate at least 1000ms and 8 packets or Accumulate over 1K packets */ ++ else if ((((wd->tick - rcCell->probingTime) > (ZM_RATE_CTRL_PROBING_INTERVAL_MS/ZM_MS_PER_TICK)) ++ && (rcCell->txCount >= ZM_RATE_CTRL_MIN_PROBING_PACKET)) ++ || (rcCell->txCount >= 1000)) ++ { ++#ifndef ZM_DISABLE_RATE_CTRL ++ /* PER = fail/total */ ++ wd->probeCount = 0; ++ wd->probeSuccessCount = 0; ++ if (wd->txMPDU[rcCell->currentRate] != 0) { ++ wd->PER[rcCell->currentRate] = zm_agg_min(100, ++ (wd->txFail[rcCell->currentRate]*100)/wd->txMPDU[rcCell->currentRate]); ++ if (!wd->PER[rcCell->currentRate]) wd->PER[rcCell->currentRate] ++; ++ } ++ ++ /* if PER < threshold, do rate probing, return probing rate */ ++ if ((wd->PER[rcCell->currentRate] <= (ZM_RATE_PROBING_THRESHOLD+15)) || ++ ((rcCell->currentRate <= 16) && ++ ((wd->PER[rcCell->currentRate]/2) <= ZM_RATE_PROBING_THRESHOLD))) ++ { ++ if ((newRate=zfRateCtrlGetHigherRate(rcCell)) != rcCell->currentRate) ++ { ++ *probing = 1; ++ wd->probeCount++; ++ wd->probeInterval = 0; ++ wd->success_probing = ++ (rcCell->currentRate <= 16)? (ZM_RATE_SUCCESS_PROBING/2) : ZM_RATE_SUCCESS_PROBING; ++ //DbgPrint("Start Probing"); ++ zm_msg1_tx(ZM_LV_0, "Probing Rate=", newRate); ++ } ++ } ++#endif ++ ++ zm_msg0_tx(ZM_LV_1, "Diminish counter"); ++ rcCell->failCount = rcCell->failCount>>1; ++ rcCell->txCount = rcCell->txCount>>1; ++ wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; ++ wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; ++ ++ ++ if (rcCell->currentRate > 15) { ++ highRate = zfRateCtrlGetHigherRate(rcCell); ++ if ((highRate != rcCell->currentRate) && wd->PER[highRate] && ++ ((wd->PER[rcCell->currentRate] + FailDiff[rcCell->currentRate]) > ++ wd->PER[highRate])) { ++ //DbgPrint("PER compare force raise rate to %d", highRate); ++ wd->probeSuccessCount = wd->probeCount = ZM_RATE_SUCCESS_PROBING; ++ zfRateCtrlTxSuccessEvent(dev, rcCell, highRate); ++ } ++ } ++ else { ++ highRate = zfRateCtrlFindMaxUDPTP(dev, rcCell); ++ if (rcCell->currentRate < highRate) { ++ //DbgPrint("UDP Throughput compare force raise rate to %d", highRate); ++ wd->probeSuccessCount = wd->probeCount = ZM_RATE_SUCCESS_PROBING; ++ zfRateCtrlTxSuccessEvent(dev, rcCell, highRate); ++ } ++ } ++ rcCell->probingTime = wd->tick; ++ } ++ ++ if( (wd->tick > 1000) ++ && ((wd->tick - rcCell->lastTime) > 3840) ) ++ { ++ if (rcCell->lasttxCount < 70) ++ { ++ rcCell->failCount = rcCell->failCount>>1; ++ rcCell->txCount = rcCell->txCount>>1; ++ wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; ++ wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; ++ ++ rcCell->failCount = (rcCell->failCount < rcCell->txCount)? ++ rcCell->failCount : rcCell->txCount; ++ wd->txFail[rcCell->currentRate] = (wd->txFail[rcCell->currentRate] < wd->txMPDU[rcCell->currentRate])? ++ wd->txFail[rcCell->currentRate] : wd->txMPDU[rcCell->currentRate]; ++ } ++ ++ rcCell->lastTime = wd->tick; ++ rcCell->lasttxCount = 0; ++ } ++ ++ rcCell->txCount++; ++ rcCell->lasttxCount++; ++ wd->txMPDU[rcCell->currentRate]++; ++ zm_msg1_tx(ZM_LV_1, "Get Tx Rate=", newRate); ++ return newRate; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlTxFailEvent */ ++/* Tx fail event. Calculate PER and lower Tx rate if under */ ++/* PER under threshold. */ ++/* */ ++/* INPUTS */ ++/* rcCell : rate control cell */ ++/* retryRate : retry rate */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++void zfRateCtrlTxFailEvent(zdev_t* dev, struct zsRcCell* rcCell, u8_t aggRate, u32_t retryRate) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++#ifndef ZM_DISABLE_RATE_CTRL ++ //DbgPrint("aggRate=%d, retryRate=%d", aggRate, retryRate); ++ if (aggRate && (aggRate != rcCell->currentRate)) { ++ wd->txFail[aggRate] += retryRate; ++ return; ++ } ++ ++ if (!aggRate) { ++ retryRate = (zfRateCtrlRateDiff(rcCell, (u8_t)retryRate)+1)>>1; ++ if (rcCell->currentRate <12) //legacy rate ++ { ++ retryRate*=2; ++ } ++ } ++ rcCell->failCount += retryRate; ++ wd->txFail[rcCell->currentRate] += retryRate; ++ ++ //DbgPrint("failCount=%d", rcCell->failCount); ++ if (rcCell->failCount > ZM_MIN_RATE_FAIL_COUNT) ++ { ++ if (wd->txMPDU[rcCell->currentRate] != 0) { ++ wd->PER[rcCell->currentRate] = zm_agg_min(100, ++ (wd->txFail[rcCell->currentRate]*100)/wd->txMPDU[rcCell->currentRate]); ++ if (!wd->PER[rcCell->currentRate]) wd->PER[rcCell->currentRate] ++; ++ } ++ //zm_msg1_tx(ZM_LV_1, "PER=", per); ++ //DbgPrint("PER=%d, txFail=%d, txMPDU=%d", wd->PER[rcCell->currentRate], wd->txFail[rcCell->currentRate], wd->txMPDU[rcCell->currentRate]); ++ if (wd->PER[rcCell->currentRate] > PERThreshold[rcCell->currentRate]) ++ { ++ /* Lower Tx Rate if PER < THRESHOLD */ ++ zfRateCtrlNextLowerRate(dev, rcCell); ++ rcCell->flag |= ZM_RC_TRAINED_BIT; ++ ++ // Resolve compatibility problem with Marvell ++ if(rcCell->currentRate == 15) ++ { ++ zmw_leave_critical_section(dev); ++ zfHpSetAggPktNum(dev, 8); ++ zmw_enter_critical_section(dev); ++ } ++ ++ wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; ++ wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; ++ ++ wd->probeCount = wd->probeSuccessCount = 0; ++ } ++ } ++ ++#endif ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlTxSuccessEvent */ ++/* Tx success event. Raise Tx rate because rate probing success. */ ++/* */ ++/* INPUTS */ ++/* rcCell : rate control cell */ ++/* successRate : success rate */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++void zfRateCtrlTxSuccessEvent(zdev_t* dev, struct zsRcCell* rcCell, u8_t successRate) ++{ ++ /* Raise Tx Rate */ ++ u16_t i, PERProbe; ++ u16_t pcount; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ //DbgPrint("Probing successRate=%d", successRate); ++ /* Find successRate in operationRateSet[] */ ++ wd->probeSuccessCount++; ++ if (wd->probeCount < wd->success_probing) ++ { ++ return; ++ } ++ ++ pcount = wd->probeCount; ++ if (pcount != 0) ++ { ++ PERProbe = wd->probeSuccessCount * 100 / pcount; ++ } ++ else ++ { ++ PERProbe = 1; ++ } ++ ++ if (PERProbe < ((rcCell->currentRate < 16)? 80:100)) ++ { ++ return; ++ } ++ //DbgPrint("wd->probeCount=%d, wd->probeSuccessCount=%d", wd->probeCount, wd->probeSuccessCount); ++ wd->probeCount = wd->probeSuccessCount = 0; ++ for (i=0; ioperationRateCount; i++) ++ { ++ if (successRate == rcCell->operationRateSet[i]) ++ { ++ if (i > rcCell->currentRateIndex) ++ { ++ /* Raise current Tx rate */ ++ zm_msg1_tx(ZM_LV_0, "Raise Tx Rate=", successRate); ++ //DbgPrint("Raise Tx Rate=%d", successRate); ++ ++ // Resolve compatibility problem with Marvell ++ if((rcCell->currentRate <= 15) && (successRate > 15)) ++ { ++ zmw_leave_critical_section(dev); ++ zfHpSetAggPktNum(dev, 16); ++ zmw_enter_critical_section(dev); ++ } ++ ++ rcCell->currentRate = successRate; ++ rcCell->currentRateIndex = (u8_t)i; ++ rcCell->failCount = rcCell->txCount = 0; ++ rcCell->lasttxCount = 0; ++ rcCell->lastTime = wd->tick; ++ wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; ++ wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; ++ } ++ } ++ } ++ ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfRateCtrlRxRssiEvent */ ++/* Rx RSSI event. Calculate RSSI moving average, accelarate */ ++/* rate probing if RSSI variation over threshold. */ ++/* */ ++/* INPUTS */ ++/* rcCell : rate control cell */ ++/* successRate : success rate */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen Atheros Communications, INC. 2007.2 */ ++/* */ ++/************************************************************************/ ++void zfRateCtrlRxRssiEvent(struct zsRcCell* rcCell, u16_t rxRssi) ++{ ++ /* if delta(rcCell->rxRssi, rxRssi) > ZM_RATE_CTRL_RSSI_VARIATION */ ++ if ((rcCell->rxRssi - rxRssi) > ZM_RATE_CTRL_RSSI_VARIATION) ++ { ++ /* Accelerate rate probing via decreaing rcCell->probingTime */ ++ rcCell->probingTime -= ZM_RATE_CTRL_PROBING_INTERVAL_MS/ZM_MS_PER_TICK; ++ } ++ ++ /* Update RSSI moving average */ ++ rcCell->rxRssi = (((rcCell->rxRssi*7) + rxRssi)+4) >> 3; ++ return; ++} ++ ++ ++#ifdef ZM_ENABLE_BA_RATECTRL ++u8_t HigherRate(u8_t Rate) { ++ if (Rate < 28) Rate++; //28=MCS15SG, 27=MCS15, 26=MCS14, 25=MCS13 ++ if (Rate > 28) Rate = 28; ++ while ((Rate >= 20) && (Rate <= 23)) { ++ Rate ++; ++ } ++ return Rate; ++} ++ ++u8_t LowerRate(u8_t Rate) { ++ if (Rate > 1) Rate--; ++ while ((Rate >= 20) && (Rate <= 23)) { ++ Rate --; ++ } ++ return Rate; ++} ++ ++u8_t RateMapToRateIndex(u8_t Rate, struct zsRcCell* rcCell) { ++ u8_t i; ++ for (i=0; ioperationRateCount; i++) { ++ if (Rate == rcCell->operationRateSet[i]) { ++ return i; ++ } ++ } ++ return 0; ++} ++ ++void zfRateCtrlAggrSta(zdev_t* dev) { ++ u8_t RateIndex, Rate; ++ u8_t HRate; ++ u8_t LRate; ++ u32_t RateCtrlTxMPDU, RateCtrlBAFail; ++ zmw_get_wlan_dev(dev); ++ ++ RateIndex = wd->sta.oppositeInfo[0].rcCell.currentRateIndex; ++ Rate = wd->sta.oppositeInfo[0].rcCell.operationRateSet[RateIndex]; ++ ++ TxMPDU[Rate] = (TxMPDU[Rate] / 5) + (wd->commTally.RateCtrlTxMPDU * 4 / 5); ++ BAFail[Rate] = (BAFail[Rate] / 5) + (wd->commTally.RateCtrlBAFail * 4 / 5); ++ RateCtrlTxMPDU = wd->commTally.RateCtrlTxMPDU; ++ RateCtrlBAFail = wd->commTally.RateCtrlBAFail; ++ wd->commTally.RateCtrlTxMPDU = 0; ++ wd->commTally.RateCtrlBAFail = 0; ++ if (TxMPDU[Rate] > 0) { ++ BAPER[Rate] = BAFail[Rate] * 1000 / TxMPDU[Rate]; //PER*1000 ++ BAPER[Rate] = (BAPER[Rate]>0)? BAPER[Rate]:1; ++ } ++ else { ++ return; ++ } ++ ++ HRate = HigherRate(Rate); ++ LRate = LowerRate(Rate); ++ if (BAPER[Rate]>200) { ++ if ((RateCtrlTxMPDU > 100) && (BAPER[Rate]<300) && (HRate != Rate) && BAPER[HRate] && ++ (BAPER[HRate] < BAPER[Rate] + BADiff[Rate])) { ++ Rate = HRate; ++ //DbgPrint("Rate improved to %d", Rate); ++ } ++ else { ++ Rate = LRate; ++ //DbgPrint("Rate decreased to %d", Rate); ++ } ++ } ++ else if (BAPER[Rate] && BAPER[Rate]<100) { ++ if (RateCtrlTxMPDU > 100) { ++ Rate = HRate; ++ //DbgPrint("Rate improved to %d", Rate); ++ } ++ } ++ wd->sta.oppositeInfo[0].rcCell.currentRate = Rate; ++ wd->sta.oppositeInfo[0].rcCell.currentRateIndex = RateMapToRateIndex(Rate, &wd->sta.oppositeInfo[0].rcCell); ++} ++#endif +--- /dev/null ++++ b/drivers/staging/otus/80211core/ratectrl.h +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _RATECTRL_H ++#define _RATECTRL_H ++ ++#define ZM_RATE_CTRL_PROBING_INTERVAL_MS 1000 //1000ms ++#define ZM_RATE_CTRL_MIN_PROBING_PACKET 8 ++ ++#define ZM_MIN_RATE_FAIL_COUNT 20 ++ ++#define ZM_RATE_PROBING_THRESHOLD 15 //6% ++#define ZM_RATE_SUCCESS_PROBING 10 ++ ++#define ZM_RATE_CTRL_RSSI_VARIATION 5 //TBD ++ ++extern const u32_t zcRateToPhyCtrl[]; ++ ++extern void zfRateCtrlInitCell(zdev_t* dev, struct zsRcCell* rcCell, u8_t type, u8_t gBand, u8_t SG40); ++extern u16_t zfRateCtrlGetTxRate(zdev_t* dev, struct zsRcCell* rcCell, u16_t* probing); ++extern void zfRateCtrlTxFailEvent(zdev_t* dev, struct zsRcCell* rcCell, u8_t aggRate, u32_t retryRate); ++extern void zfRateCtrlTxSuccessEvent(zdev_t* dev, struct zsRcCell* rcCell, u8_t successRate); ++extern void zfRateCtrlAggrSta(zdev_t* dev); ++#endif +--- /dev/null ++++ b/drivers/staging/otus/80211core/struct.h +@@ -0,0 +1,1315 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _STRUCT_H ++#define _STRUCT_H ++ ++#include "../oal_marc.h" ++ ++#define ZM_SW_LOOP_BACK 0 /* 1=>enable, 0=>disable */ ++#define ZM_PCI_LOOP_BACK 0 /* 1=>enable, 0=>disable */ ++#define ZM_PROTOCOL_RESPONSE_SIMULATION 0 ++ ++#define ZM_RX_FRAME_SIZE 1600 ++ ++extern const u8_t zg11bRateTbl[4]; ++extern const u8_t zg11gRateTbl[8]; ++ ++#define ZM_DRIVER_CORE_MAJOR_VERSION 1 ++#define ZM_DRIVER_CORE_MINOR_VERSION 1 ++#define ZM_DRIVER_CORE_BRANCH_MAJOR_VERSION 3 ++#define ZM_DRIVER_CORE_BRANCH_MINOR_VERSION 39 ++ ++#ifndef ZM_VTXQ_SIZE ++#define ZM_VTXQ_SIZE 1024 //2^N ++#endif ++ ++#define ZM_VTXQ_SIZE_MASK (ZM_VTXQ_SIZE-1) ++#define ZM_VMMQ_SIZE 8 //2^N ++#define ZM_VMMQ_SIZE_MASK (ZM_VMMQ_SIZE-1) ++ ++#include "cagg.h" ++ ++#define ZM_AGG_POOL_SIZE 20 ++#define ZM_RATE_TABLE_SIZE 32 ++ ++#define ZM_MAX_BUF_DISCRETE_NUMBER 5 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++/**********************************************************************************/ ++/* IBSS macros */ ++/**********************************************************************************/ ++#define ZM_IBSS_PEER_ALIVE_COUNTER 4 ++ ++/**********************************************************************************/ ++/* BIT mapping related macros */ ++/**********************************************************************************/ ++ ++#define ZM_BIT_0 0x1 ++#define ZM_BIT_1 0x2 ++#define ZM_BIT_2 0x4 ++#define ZM_BIT_3 0x8 ++#define ZM_BIT_4 0x10 ++#define ZM_BIT_5 0x20 ++#define ZM_BIT_6 0x40 ++#define ZM_BIT_7 0x80 ++#define ZM_BIT_8 0x100 ++#define ZM_BIT_9 0x200 ++#define ZM_BIT_10 0x400 ++#define ZM_BIT_11 0x800 ++#define ZM_BIT_12 0x1000 ++#define ZM_BIT_13 0x2000 ++#define ZM_BIT_14 0x4000 ++#define ZM_BIT_15 0x8000 ++#define ZM_BIT_16 0x10000 ++#define ZM_BIT_17 0x20000 ++#define ZM_BIT_18 0x40000 ++#define ZM_BIT_19 0x80000 ++#define ZM_BIT_20 0x100000 ++#define ZM_BIT_21 0x200000 ++#define ZM_BIT_22 0x400000 ++#define ZM_BIT_23 0x800000 ++#define ZM_BIT_24 0x1000000 ++#define ZM_BIT_25 0x2000000 ++#define ZM_BIT_26 0x4000000 ++#define ZM_BIT_27 0x8000000 ++#define ZM_BIT_28 0x10000000 ++#define ZM_BIT_29 0x20000000 //WPA support ++#define ZM_BIT_30 0x40000000 ++#define ZM_BIT_31 0x80000000 ++ ++ ++/**********************************************************************************/ ++/* MAC address related macros */ ++/**********************************************************************************/ ++#define ZM_MAC_BYTE_TO_WORD(macb, macw) macw[0] = macb[0] + (macb[1] << 8); \ ++ macw[1] = macb[2] + (macb[3] << 8); \ ++ macw[2] = macb[4] + (macb[5] << 8); ++ ++#define ZM_MAC_WORD_TO_BYTE(macw, macb) macb[0] = (u8_t) (macw[0] & 0xff); \ ++ macb[1] = (u8_t) (macw[0] >> 8); \ ++ macb[2] = (u8_t) (macw[1] & 0xff); \ ++ macb[3] = (u8_t) (macw[1] >> 8); \ ++ macb[4] = (u8_t) (macw[2] & 0xff); \ ++ macb[5] = (u8_t) (macw[2] >> 8); ++ ++#define ZM_MAC_0(macw) ((u8_t)(macw[0] & 0xff)) ++#define ZM_MAC_1(macw) ((u8_t)(macw[0] >> 8)) ++#define ZM_MAC_2(macw) ((u8_t)(macw[1] & 0xff)) ++#define ZM_MAC_3(macw) ((u8_t)(macw[1] >> 8)) ++#define ZM_MAC_4(macw) ((u8_t)(macw[2] & 0xff)) ++#define ZM_MAC_5(macw) ((u8_t)(macw[2] >> 8)) ++ ++#define ZM_IS_MULTICAST_OR_BROADCAST(mac) (mac[0] & 0x01) ++#define ZM_IS_MULTICAST(mac) ((mac[0] & 0x01) && (((u8_t)mac[0]) != 0xFF)) ++ ++#define ZM_MAC_EQUAL(mac1, mac2) ((mac1[0]==mac2[0])&&(mac1[1]==mac2[1])&&(mac1[2]==mac2[2])) ++#define ZM_MAC_NOT_EQUAL(mac1, mac2) ((mac1[0]!=mac2[0])||(mac1[1]!=mac2[1])||(mac1[2]!=mac2[2])) ++/**********************************************************************************/ ++/* MAC address related mac'ros (end) */ ++/**********************************************************************************/ ++#define ZM_BYTE_TO_WORD(A, B) ((A<<8)+B) ++#define ZM_ROL32( A, n ) \ ++ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) ++#define ZM_ROR32( A, n ) ZM_ROL32( (A), 32-(n) ) ++#define ZM_LO8(v16) ((u8_t)((v16) & 0xFF)) ++#define ZM_HI8(v16) ((u8_t)(((v16)>>8)&0xFF)) ++ ++#ifdef ZM_ENABLE_BUFFER_TRACE ++extern void zfwBufTrace(zdev_t* dev, zbuf_t *buf, u8_t *functionName); ++#define ZM_BUFFER_TRACE(dev, buf) zfwBufTrace(dev, buf, __FUNCTION__); ++#else ++#define ZM_BUFFER_TRACE(dev, buf) ++#endif ++ ++/* notification events to heart beat function */ ++#define ZM_BSSID_LIST_SCAN 0x01 ++ ++/* CAM mode */ ++#define ZM_CAM_AP 0x1 ++#define ZM_CAM_STA 0x2 ++#define ZM_CAM_HOST 0x4 ++ ++/* finite state machine for adapter */ ++#define ZM_STA_STATE_DISCONNECT 1 ++#define ZM_STA_STATE_CONNECTING 2 ++#define ZM_STA_STATE_CONNECTED 3 ++ ++/* Event definitions for finite state machine */ ++#define ZM_EVENT_TIMEOUT_SCAN 0x0000 ++#define ZM_EVENT_TIMEOUT_BG_SCAN 0x0001 ++#define ZN_EVENT_TIMEOUT_RECONNECT 0x0002 ++#define ZM_EVENT_TIMEOUT_INIT_SCAN 0x0003 ++#define ZM_EVENT_TIMEOUT_AUTH 0x0004 ++#define ZM_EVENT_TIMEOUT_ASSO 0x0005 ++#define ZM_EVENT_TIMEOUT_AUTO_SCAN 0x0006 ++#define ZM_EVENT_TIMEOUT_MIC_FAIL 0x0007 ++#define ZM_EVENT_TIMEOUT_CHECK_AP 0x0008 ++#define ZM_EVENT_CONNECT 0x0009 ++#define ZM_EVENT_INIT_SCAN 0x000a ++#define ZM_EVENT_SCAN 0x000b ++#define ZM_EVENT_BG_SCAN 0x000c ++#define ZM_EVENT_DISCONNECT 0x000d ++#define ZM_EVENT_WPA_MIC_FAIL 0x000e ++#define ZM_EVENT_AP_ALIVE 0x000f ++#define ZM_EVENT_CHANGE_TO_AP 0x0010 ++#define ZM_EVENT_CHANGE_TO_STA 0x0011 ++#define ZM_EVENT_IDLE 0x0012 ++#define ZM_EVENT_AUTH 0x0013 ++#define ZM_EVENT_ASSO_RSP 0x0014 ++#define ZM_EVENT_WPA_PK_OK 0x0015 ++#define ZM_EVENT_WPA_GK_OK 0x0016 ++#define ZM_EVENT_RCV_BEACON 0x0017 ++#define ZM_EVENT_RCV_PROBE_RSP 0x0018 ++#define ZM_EVENT_SEND_DATA 0x0019 ++#define ZM_EVENT_AUTO_SCAN 0x001a ++#define ZM_EVENT_MIC_FAIL1 0x001d ++#define ZM_EVENT_MIC_FAIL2 0x001e ++#define ZM_EVENT_IBSS_MONITOR 0x001f ++#define ZM_EVENT_IN_SCAN 0x0020 ++#define ZM_EVENT_CM_TIMER 0x0021 ++#define ZM_EVENT_CM_DISCONNECT 0x0022 ++#define ZM_EVENT_CM_BLOCK_TIMER 0x0023 ++#define ZM_EVENT_TIMEOUT_ADDBA 0x0024 ++#define ZM_EVENT_TIMEOUT_PERFORMANCE 0x0025 ++#define ZM_EVENT_SKIP_COUNTERMEASURE 0x0026 ++#define ZM_EVENT_NONE 0xffff ++ ++/* Actions after call finite state machine */ ++#define ZM_ACTION_NONE 0x0000 ++#define ZM_ACTION_QUEUE_DATA 0x0001 ++#define ZM_ACTION_DROP_DATA 0x0002 ++ ++/* Timers for finite state machine */ ++#define ZM_TICK_ZERO 0 ++#define ZM_TICK_INIT_SCAN_END 8 ++#define ZM_TICK_NEXT_BG_SCAN 50 ++#define ZM_TICK_BG_SCAN_END 8 ++#define ZM_TICK_AUTH_TIMEOUT 4 ++#define ZM_TICK_ASSO_TIMEOUT 4 ++#define ZM_TICK_AUTO_SCAN 300 ++#define ZM_TICK_MIC_FAIL_TIMEOUT 6000 ++#define ZM_TICK_CHECK_AP1 150 ++#define ZM_TICK_CHECK_AP2 350 ++#define ZM_TICK_CHECK_AP3 250 ++#define ZM_TICK_IBSS_MONITOR 160 ++#define ZM_TICK_IN_SCAN 4 ++#define ZM_TICK_CM_TIMEOUT 6000 ++#define ZM_TICK_CM_DISCONNECT 200 ++#define ZM_TICK_CM_BLOCK_TIMEOUT 6000 ++ ++/* Fix bug#33338 Counter Measure Issur */ ++#ifdef NDIS_CM_FOR_XP ++#define ZM_TICK_CM_TIMEOUT_OFFSET 2160 ++#define ZM_TICK_CM_DISCONNECT_OFFSET 72 ++#define ZM_TICK_CM_BLOCK_TIMEOUT_OFFSET 2160 ++#else ++#define ZM_TICK_CM_TIMEOUT_OFFSET 0 ++#define ZM_TICK_CM_DISCONNECT_OFFSET 0 ++#define ZM_TICK_CM_BLOCK_TIMEOUT_OFFSET 0 ++#endif ++ ++#define ZM_TIME_ACTIVE_SCAN 30 //ms ++#define ZM_TIME_PASSIVE_SCAN 110 //ms ++ ++/* finite state machine for BSS connect */ ++#define ZM_STA_CONN_STATE_NONE 0 ++#define ZM_STA_CONN_STATE_AUTH_OPEN 1 ++#define ZM_STA_CONN_STATE_AUTH_SHARE_1 2 ++#define ZM_STA_CONN_STATE_AUTH_SHARE_2 3 ++#define ZM_STA_CONN_STATE_ASSOCIATE 4 ++#define ZM_STA_CONN_STATE_SSID_NOT_FOUND 5 ++#define ZM_STA_CONN_STATE_AUTH_COMPLETED 6 ++ ++/* finite state machine for WPA handshaking */ ++#define ZM_STA_WPA_STATE_INIT 0 ++#define ZM_STA_WPA_STATE_PK_OK 1 ++#define ZM_STA_WPA_STATE_GK_OK 2 ++ ++/* various timers */ ++#define ZM_INTERVAL_CONNECT_TIMEOUT 20 /* 200 milisecond */ ++ ++/* IBSS definitions */ ++#define ZM_IBSS_PARTNER_LOST 0 ++#define ZM_IBSS_PARTNER_ALIVE 1 ++#define ZM_IBSS_PARTNER_CHECK 2 ++ ++#define ZM_BCMC_ARRAY_SIZE 16 /* Must be 2^N */ ++#define ZM_UNI_ARRAY_SIZE 16 /* Must be 2^N */ ++ ++#define ZM_MAX_DEFRAG_ENTRIES 4 /* 2^N */ ++#define ZM_DEFRAG_AGING_TIME_SEC 5 /* 5 seconds */ ++ ++#define ZM_MAX_WPAIE_SIZE 128 ++/* WEP related definitions */ ++#define ZM_USER_KEY_DEFAULT 64 ++#define ZM_USER_KEY_PK 0 /* Pairwise Key */ ++#define ZM_USER_KEY_GK 1 /* Group Key */ ++/* AP WLAN Type */ ++#define ZM_WLAN_TYPE_PURE_B 2 ++#define ZM_WLAN_TYPE_PURE_G 1 ++#define ZM_WLAN_TYPE_MIXED 0 ++ ++/* HAL State */ ++#define ZM_HAL_STATE_INIT 0 ++#define ZM_HAL_STATE_RUNNING 1 ++ ++/* AP Capability */ ++#define ZM_All11N_AP 0x01 ++#define ZM_XR_AP 0x02 ++#define ZM_SuperG_AP 0x04 ++ ++/* MPDU Density */ ++#define ZM_MPDU_DENSITY_NONE 0 ++#define ZM_MPDU_DENSITY_1_8US 1 ++#define ZM_MPDU_DENSITY_1_4US 2 ++#define ZM_MPDU_DENSITY_1_2US 3 ++#define ZM_MPDU_DENSITY_1US 4 ++#define ZM_MPDU_DENSITY_2US 5 ++#define ZM_MPDU_DENSITY_4US 6 ++#define ZM_MPDU_DENSITY_8US 7 ++ ++/* Software Encryption */ ++#define ZM_SW_TKIP_ENCRY_EN 0x01 ++#define ZM_SW_TKIP_DECRY_EN 0x02 ++#define ZM_SW_WEP_ENCRY_EN 0x04 ++#define ZM_SW_WEP_DECRY_EN 0x08 ++ ++/* Default Support Rate */ ++#define ZM_DEFAULT_SUPPORT_RATE_ZERO 0x0 ++#define ZM_DEFAULT_SUPPORT_RATE_DISCONNECT 0x1 ++#define ZM_DEFAULT_SUPPORT_RATE_IBSS_B 0x2 ++#define ZM_DEFAULT_SUPPORT_RATE_IBSS_AG 0x3 ++ ++/* security related definitions */ ++struct zsTkipSeed ++{ ++ u8_t tk[32]; /* key */ ++ u8_t ta[6]; ++ u16_t ttak[5]; ++ u16_t ppk[6]; ++ u16_t iv16,iv16tmp; ++ u32_t iv32,iv32tmp; ++}; ++ ++struct zsMicVar ++{ ++ u32_t k0, k1; // Key ++ u32_t left, right; // Current state ++ u32_t m; // Message accumulator (single word) ++ u16_t nBytes; // # bytes in M ++}; ++ ++struct zsDefragEntry ++{ ++ u8_t fragCount; ++ u8_t addr[6]; ++ u16_t seqNum; ++ zbuf_t* fragment[8]; ++ u32_t tick; ++}; ++ ++struct zsDefragList ++{ ++ struct zsDefragEntry defragEntry[ZM_MAX_DEFRAG_ENTRIES]; ++ u8_t replaceNum; ++}; ++ ++#define ZM_MAX_OPPOSITE_COUNT 16 ++#define ZM_MAX_TX_SAMPLES 15 ++#define ZM_TX_RATE_DOWN_CRITERIA 80 ++#define ZM_TX_RATE_UP_CRITERIA 200 ++ ++ ++#define ZM_MAX_PROBE_HIDDEN_SSID_SIZE 2 ++struct zsSsidList ++{ ++ u8_t ssid[32]; ++ u8_t ssidLen; ++}; ++ ++struct zsWrapperSetting ++{ ++ u8_t bDesiredBssid; ++ u8_t desiredBssid[6]; ++ u16_t bssid[3]; ++ u8_t ssid[32]; ++ u8_t ssidLen; ++ u8_t authMode; ++ u8_t wepStatus; ++ u8_t encryMode; ++ u8_t wlanMode; ++ u16_t frequency; ++ u16_t beaconInterval; ++ u8_t dtim; ++ u8_t preambleType; ++ u16_t atimWindow; ++ ++ struct zsSsidList probingSsidList[ZM_MAX_PROBE_HIDDEN_SSID_SIZE]; ++ ++ u8_t dropUnencryptedPkts; ++ u8_t ibssJoinOnly; ++ u32_t adhocMode; ++ u8_t countryIsoName[4]; ++ u16_t autoSetFrequency; ++ ++ /* AP */ ++ u8_t bRateBasic; ++ u8_t gRateBasic; ++ u32_t nRateBasic; ++ u8_t bgMode; ++ ++ /* Common */ ++ u8_t staWmeEnabled; ++ u8_t staWmeQosInfo; ++ u8_t apWmeEnabled; ++ ++ ++ /* rate information: added in the future */ ++}; ++ ++struct zsWrapperFeatureCtrl ++{ ++ u8_t bIbssGMode; ++}; ++ ++#define ZM_MAX_PS_STA 16 ++#define ZM_PS_QUEUE_SIZE 32 ++ ++struct zsStaPSEntity ++{ ++ u8_t bUsed; ++ u8_t macAddr[6]; ++ u8_t bDataQueued; ++}; ++ ++struct zsStaPSList ++{ ++ u8_t count; ++ struct zsStaPSEntity entity[ZM_MAX_PS_STA]; ++}; ++ ++#define ZM_MAX_TIMER_COUNT 32 ++ ++/* double linked list */ ++struct zsTimerEntry ++{ ++ u16_t event; ++ u32_t timer; ++ struct zsTimerEntry *pre; ++ struct zsTimerEntry *next; ++}; ++ ++struct zsTimerList ++{ ++ u8_t freeCount; ++ struct zsTimerEntry list[ZM_MAX_TIMER_COUNT]; ++ struct zsTimerEntry *head; ++ struct zsTimerEntry *tail; ++}; ++ ++/* Multicast list */ ++#define ZM_MAX_MULTICAST_LIST_SIZE 64 ++ ++struct zsMulticastAddr ++{ ++ u8_t addr[6]; ++}; ++ ++struct zsMulticastList ++{ ++ u8_t size; ++ struct zsMulticastAddr macAddr[ZM_MAX_MULTICAST_LIST_SIZE]; ++}; ++ ++enum ieee80211_cwm_mode { ++ CWM_MODE20, ++ CWM_MODE2040, ++ CWM_MODE40, ++ CWM_MODEMAX ++ ++}; ++ ++enum ieee80211_cwm_extprotspacing { ++ CWM_EXTPROTSPACING20, ++ CWM_EXTPROTSPACING25, ++ CWM_EXTPROTSPACINGMAX ++}; ++ ++enum ieee80211_cwm_width { ++ CWM_WIDTH20, ++ CWM_WIDTH40 ++}; ++ ++enum ieee80211_cwm_extprotmode { ++ CWM_EXTPROTNONE, /* no protection */ ++ CWM_EXTPROTCTSONLY, /* CTS to self */ ++ CWM_EXTPROTRTSCTS, /* RTS-CTS */ ++ CWM_EXTPROTMAX ++}; ++ ++struct ieee80211_cwm { ++ ++ /* Configuration */ ++ enum ieee80211_cwm_mode cw_mode; /* CWM mode */ ++ u8_t cw_extoffset; /* CWM Extension Channel Offset */ ++ enum ieee80211_cwm_extprotmode cw_extprotmode; /* CWM Extension Channel Protection Mode */ ++ enum ieee80211_cwm_extprotspacing cw_extprotspacing;/* CWM Extension Channel Protection Spacing */ ++ u32_t cw_enable; /* CWM State Machine Enabled */ ++ u32_t cw_extbusythreshold;/* CWM Extension Channel Busy Threshold */ ++ ++ /* State */ ++ enum ieee80211_cwm_width cw_width; /* CWM channel width */ ++}; ++ ++ ++/* AP : STA database structure */ ++struct zsStaTable ++{ ++ u32_t time; /* tick time */ ++ //u32_t phyCtrl; /* Tx PHY CTRL */ ++ u16_t addr[3]; /* STA MAC address */ ++ u16_t state; /* aut/asoc */ ++ //u16_t retry; /* Retry count */ ++ struct zsRcCell rcCell; ++ ++ u8_t valid; /* Valid flag : 1=>valid */ ++ u8_t psMode; /* STA power saving mode */ ++ u8_t staType; /* 0=>11b, 1=>11g, 2=>11n */ ++ u8_t qosType; /* 0=>Legacy, 1=>WME */ ++ u8_t qosInfo; /* WME QoS info */ ++ u8_t vap; /* Virtual AP ID */ ++ u8_t encryMode; /* Encryption type for this STA */ ++ u8_t keyIdx; ++ struct zsMicVar txMicKey; ++ struct zsMicVar rxMicKey; ++ u16_t iv16; ++ u32_t iv32; ++#ifdef ZM_ENABLE_CENC ++ /* CENC */ ++ u8_t cencKeyIdx; ++ u32_t txiv[4]; ++ u32_t rxiv[4]; ++#endif //ZM_ENABLE_CENC ++}; ++ ++struct zdStructWds ++{ ++ u8_t wdsBitmap; /* Set bit-N to 1 to enable WDS */ ++ u8_t encryMode[ZM_MAX_WDS_SUPPORT]; /* WDS encryption mode */ ++ u16_t macAddr[ZM_MAX_WDS_SUPPORT][3]; /* WDS neighbor MAC address */ ++}; ++ ++ // htcapinfo 16bits ++#define HTCAP_AdvCodingCap 0x0001 ++#define HTCAP_SupChannelWidthSet 0x0002 ++#define HTCAP_DynamicSMPS 0x0004 ++#define HTCAP_SMEnabled 0x000C ++#define HTCAP_GreenField 0x0010 ++#define HTCAP_ShortGIfor20MHz 0x0020 ++#define HTCAP_ShortGIfor40MHz 0x0040 ++#define HTCAP_TxSTBC 0x0080 ++#define HTCAP_RxOneStream 0x0100 ++#define HTCAP_RxTwoStream 0x0200 ++#define HTCAP_RxThreeStream 0x0300 ++#define HTCAP_DelayedBlockACK 0x0400 ++#define HTCAP_MaxAMSDULength 0x0800 ++#define HTCAP_DSSSandCCKin40MHz 0x1000 ++#define HTCAP_PSMPSup 0x2000 ++#define HTCAP_STBCControlFrameSup 0x4000 ++#define HTCAP_LSIGTXOPProtectionSUP 0x8000 ++ // Ampdu HT Parameter Info 8bits ++#define HTCAP_MaxRxAMPDU0 0x00 ++#define HTCAP_MaxRxAMPDU1 0x01 ++#define HTCAP_MaxRxAMPDU2 0x02 ++#define HTCAP_MaxRxAMPDU3 0x03 ++ // PCO 8bits ++#define HTCAP_PCO 0x01 ++#define HTCAP_TransmissionTime1 0x02 ++#define HTCAP_TransmissionTime2 0x04 ++#define HTCAP_TransmissionTime3 0x06 ++ // MCS FeedBack 8bits ++#define HTCAP_PlusHTCSupport 0x04 ++#define HTCAP_RDResponder 0x08 ++ // TX Beamforming 0 8bits ++#define HTCAP_TxBFCapable 0x01 ++#define HTCAP_RxStaggeredSoundCap 0x02 ++#define HTCAP_TxStaggeredSoundCap 0x04 ++#define HTCAP_RxZLFCapable 0x08 ++#define HTCAP_TxZLFCapable 0x10 ++#define HTCAP_ImplicitTxBFCapable 0x20 ++ // Tx Beamforming 1 8bits ++#define HTCAP_ExplicitCSITxBFCap 0x01 ++#define HTCAP_ExpUncompSteerMatrCap 0x02 ++ // Antenna Selection Capabilities 8bits ++#define HTCAP_AntennaSelectionCap 0x01 ++#define HTCAP_ExplicitCSITxASCap 0x02 ++#define HTCAP_AntennaIndFeeTxASCap 0x04 ++#define HTCAP_ExplicitCSIFeedbackCap 0x08 ++#define HTCAP_AntennaIndFeedbackCap 0x10 ++#define HTCAP_RxASCap 0x20 ++#define HTCAP_TxSoundPPDUsCap 0x40 ++ ++ ++ ++struct zsHTCapability ++{ ++ u8_t ElementID; ++ u8_t Length; ++ // HT Capability Info ++ u16_t HtCapInfo; ++ u8_t AMPDUParam; ++ u8_t MCSSet[16]; //16 bytes ++ // Extended HT Capability Info ++ u8_t PCO; ++ u8_t MCSFeedBack; ++ ++ u8_t TxBFCap[4]; ++ u8_t AselCap; ++}; ++ ++union zuHTCapability ++{ ++ struct zsHTCapability Data; ++ u8_t Byte[28]; ++}; ++ ++ //channelinfo 8bits ++#define ExtHtCap_ExtChannelOffsetAbove 0x01 ++#define ExtHtCap_ExtChannelOffsetBelow 0x03 ++#define ExtHtCap_RecomTxWidthSet 0x04 ++#define ExtHtCap_RIFSMode 0x08 ++#define ExtHtCap_ControlAccessOnly 0x10 ++ //operatinginfo 16bits ++#define ExtHtCap_NonGFDevicePresent 0x0004 ++ //beaconinfo 16bits ++#define ExtHtCap_DualBeacon 0x0040 ++#define ExtHtCap_DualSTBCProtection 0x0080 ++#define ExtHtCap_SecondaryBeacon 0x0100 ++#define ExtHtCap_LSIGTXOPProtectFullSup 0x0200 ++#define ExtHtCap_PCOActive 0x0400 ++#define ExtHtCap_PCOPhase 0x0800 ++ ++ ++struct zsExtHTCapability ++{ ++ u8_t ElementID; ++ u8_t Length; ++ u8_t ControlChannel; ++ u8_t ChannelInfo; ++ u16_t OperatingInfo; ++ u16_t BeaconInfo; ++ // Supported MCS Set ++ u8_t MCSSet[16]; ++}; ++ ++union zuExtHTCapability ++{ ++ struct zsExtHTCapability Data; ++ u8_t Byte[24]; ++}; ++ ++struct InformationElementSta { ++ struct zsHTCapability HtCap; ++ struct zsExtHTCapability HtInfo; ++}; ++ ++struct InformationElementAp { ++ struct zsHTCapability HtCap; ++}; ++ ++#define ZM_MAX_FREQ_REQ_QUEUE 32 ++typedef void (*zfpFreqChangeCompleteCb)(zdev_t* dev); ++ ++struct zsWlanDevFreqControl ++{ ++ u16_t freqReqQueue[ZM_MAX_FREQ_REQ_QUEUE]; ++ u8_t freqReqBw40[ZM_MAX_FREQ_REQ_QUEUE]; ++ u8_t freqReqExtOffset[ZM_MAX_FREQ_REQ_QUEUE]; ++ zfpFreqChangeCompleteCb freqChangeCompCb[ZM_MAX_FREQ_REQ_QUEUE]; ++ u8_t freqReqQueueHead; ++ u8_t freqReqQueueTail; ++}; ++ ++struct zsWlanDevAp ++{ ++ u16_t protectedObss; /* protected overlap BSS */ ++ u16_t staAgingTimeSec; /* in second, STA will be deathed if it does not */ ++ /* active for this long time */ ++ u16_t staProbingTimeSec;/* in second, STA will be probed if it does not */ ++ /* active for this long time */ ++ u8_t authSharing; /* authentication on going*/ ++ u8_t bStaAssociated; /* 11b STA associated */ ++ u8_t gStaAssociated; /* 11g STA associated */ ++ u8_t nStaAssociated; /* 11n STA associated */ ++ u16_t protectionMode; /* AP protection mode flag */ ++ u16_t staPowerSaving; /* Set associated power saving STA count */ ++ ++ ++ ++ zbuf_t* uniArray[ZM_UNI_ARRAY_SIZE]; /* array to store unicast frames */ ++ u16_t uniHead; ++ u16_t uniTail; ++ ++ /* HT Capability Info */ ++ union zuHTCapability HTCap; //CWYang(+) ++ ++ /* Extended HT Capability Info */ ++ union zuExtHTCapability ExtHTCap; //CWYang(+) ++ ++ /* STA table */ ++ struct zsStaTable staTable[ZM_MAX_STA_SUPPORT]; ++ ++ /* WDS */ ++ struct zdStructWds wds; ++ /* WPA */ ++ u8_t wpaIe[ZM_MAX_AP_SUPPORT][ZM_MAX_WPAIE_SIZE]; ++ u8_t wpaLen[ZM_MAX_AP_SUPPORT]; ++ u8_t stawpaIe[ZM_MAX_AP_SUPPORT][ZM_MAX_WPAIE_SIZE]; ++ u8_t stawpaLen[ZM_MAX_AP_SUPPORT]; ++ u8_t wpaSupport[ZM_MAX_AP_SUPPORT]; ++ ++ //struct zsTkipSeed bcSeed; ++ u8_t bcKeyIndex[ZM_MAX_AP_SUPPORT]; ++ u8_t bcHalKeyIdx[ZM_MAX_AP_SUPPORT]; ++ struct zsMicVar bcMicKey[ZM_MAX_AP_SUPPORT]; ++ u16_t iv16[ZM_MAX_AP_SUPPORT]; ++ u32_t iv32[ZM_MAX_AP_SUPPORT]; ++ ++#ifdef ZM_ENABLE_CENC ++ /* CENC */ ++ u32_t txiv[ZM_MAX_AP_SUPPORT][4]; ++#endif //ZM_ENABLE_CENC ++ ++ /* Virtual AP */ ++ u8_t beaconCounter; ++ u8_t vapNumber; ++ u8_t apBitmap; /* Set bit-N to 1 to enable VAP */ ++ u8_t hideSsid[ZM_MAX_AP_SUPPORT]; ++ u8_t authAlgo[ZM_MAX_AP_SUPPORT]; ++ u8_t ssid[ZM_MAX_AP_SUPPORT][32]; /* SSID */ ++ u8_t ssidLen[ZM_MAX_AP_SUPPORT]; /* SSID length */ ++ u8_t encryMode[ZM_MAX_AP_SUPPORT]; ++ u8_t wepStatus[ZM_MAX_AP_SUPPORT]; ++ u16_t capab[ZM_MAX_AP_SUPPORT]; /* Capability */ ++ u8_t timBcmcBit[ZM_MAX_AP_SUPPORT]; /* BMCM bit of TIM */ ++ u8_t wlanType[ZM_MAX_AP_SUPPORT]; ++ ++ /* Array to store BC or MC frames */ ++ zbuf_t* bcmcArray[ZM_MAX_AP_SUPPORT][ZM_BCMC_ARRAY_SIZE]; ++ u16_t bcmcHead[ZM_MAX_AP_SUPPORT]; ++ u16_t bcmcTail[ZM_MAX_AP_SUPPORT]; ++ ++ u8_t qosMode; /* 1=>WME */ ++ u8_t uapsdEnabled; ++ struct zsQueue* uapsdQ; ++ ++ u8_t challengeText[128]; ++ ++ struct InformationElementAp ie[ZM_MAX_STA_SUPPORT]; ++ ++ ++}; ++ ++#define ZM_MAX_BLOCKING_AP_LIST_SIZE 4 /* 2^N */ ++struct zsBlockingAp ++{ ++ u8_t addr[6]; ++ u8_t weight; ++}; ++ ++#define ZM_SCAN_MGR_SCAN_NONE 0 ++#define ZM_SCAN_MGR_SCAN_INTERNAL 1 ++#define ZM_SCAN_MGR_SCAN_EXTERNAL 2 ++ ++struct zsWlanDevStaScanMgr ++{ ++ u8_t scanReqs[2]; ++ u8_t currScanType; ++ u8_t scanStartDelay; ++}; ++ ++#define ZM_PS_MSG_STATE_ACTIVE 0 ++#define ZM_PS_MSG_STATE_SLEEP 1 ++#define ZM_PS_MSG_STATE_T1 2 ++#define ZM_PS_MSG_STATE_T2 3 ++#define ZM_PS_MSG_STATE_S1 4 ++ ++#define ZM_PS_MAX_SLEEP_PERIODS 3 // The number of beacon periods ++ ++struct zsWlanDevStaPSMgr ++{ ++ u8_t state; ++ u8_t isSleepAllowed; ++ u8_t maxSleepPeriods; ++ u8_t ticks; ++ u32_t lastTxUnicastFrm; ++ u32_t lastTxMulticastFrm; ++ u32_t lastTxBroadcastFrm; ++ u8_t tempWakeUp; /*enable when wake up but still in ps mode */ ++ u16_t sleepAllowedtick; ++}; ++ ++struct zsWlanDevSta ++{ ++ u32_t beaconTxCnt; /* Transmitted beacon counter (in IBSS) */ ++ u8_t txBeaconInd; /* In IBSS mode, true means that we just transmit a beacon during ++ last beacon period. ++ */ ++ u16_t beaconCnt; /* receive beacon count, will be perodically reset */ ++ u16_t bssid[3]; /* BSSID of connected AP */ ++ u8_t ssid[32]; /* SSID */ ++ u8_t ssidLen; /* SSID length */ ++ u8_t mTxRate; /* Tx rate for multicast */ ++ u8_t uTxRate; /* Tx rate for unicast */ ++ u8_t mmTxRate; /* Tx rate for management frame */ ++ u8_t bChannelScan; ++ u8_t bScheduleScan; ++ ++ u8_t InternalScanReq; ++ u16_t activescanTickPerChannel; ++ u16_t passiveScanTickPerChannel; ++ u16_t scanFrequency; ++ u32_t connPowerInHalfDbm; ++ ++ u16_t currentFrequency; ++ u16_t currentBw40; ++ u16_t currentExtOffset; ++ ++ u8_t bPassiveScan; ++ ++ struct zsBlockingAp blockingApList[ZM_MAX_BLOCKING_AP_LIST_SIZE]; ++ ++ //struct zsBssInfo bssInfoPool[ZM_MAX_BSS]; ++ struct zsBssInfo* bssInfoArray[ZM_MAX_BSS]; ++ struct zsBssList bssList; ++ u8_t bssInfoArrayHead; ++ u8_t bssInfoArrayTail; ++ u8_t bssInfoFreeCount; ++ ++ u8_t authMode; ++ u8_t currentAuthMode; ++ u8_t wepStatus; ++ u8_t encryMode; ++ u8_t keyId; ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ u8_t ibssWpa2Psk; ++#endif ++#ifdef ZM_ENABLE_CENC ++ u8_t cencKeyId; //CENC ++#endif //ZM_ENABLE_CENC ++ u8_t dropUnencryptedPkts; ++ u8_t ibssJoinOnly; ++ u8_t adapterState; ++ u8_t oldAdapterState; ++ u8_t connectState; ++ u8_t connectRetry; ++ u8_t wpaState; ++ u8_t wpaIe[ZM_MAX_IE_SIZE + 2]; ++ u8_t rsnIe[ZM_MAX_IE_SIZE + 2]; ++ u8_t challengeText[255+2]; ++ u8_t capability[2]; ++ //u8_t connectingHiddenAP; ++ //u8_t scanWithSSID; ++ u16_t aid; ++ u32_t mgtFrameCount; ++ u8_t bProtectionMode; ++ u32_t NonNAPcount; ++ u8_t RTSInAGGMode; ++ u32_t connectTimer; ++ u16_t atimWindow; ++ u8_t desiredBssid[6]; ++ u8_t bDesiredBssid; ++ struct zsTkipSeed txSeed; ++ struct zsTkipSeed rxSeed[4]; ++ struct zsMicVar txMicKey; ++ struct zsMicVar rxMicKey[4]; ++ u16_t iv16; ++ u32_t iv32; ++ struct zsOppositeInfo oppositeInfo[ZM_MAX_OPPOSITE_COUNT]; ++ u8_t oppositeCount; ++ u8_t bssNotFoundCount; /* sitesurvey for search desired ISBB threshold */ ++ u16_t rxBeaconCount; ++ u8_t beaconMissState; ++ u32_t rxBeaconTotal; ++ u8_t bIsSharedKey; ++ u8_t connectTimeoutCount; ++ ++ u8_t recvAtim; ++ ++ /* ScanMgr Control block */ ++ struct zsWlanDevStaScanMgr scanMgr; ++ struct zsWlanDevStaPSMgr psMgr; ++ ++ // The callback would be called if receiving an unencrypted packets but ++ // the station is in encrypted mode. The wrapper could decide whether ++ // to drop the packet by its OS setting. ++ zfpStaRxSecurityCheckCb pStaRxSecurityCheckCb; ++ ++ /* WME */ ++ u8_t apWmeCapability; //bit-0 => a WME AP ++ //bit-7 => a UAPSD AP ++ u8_t wmeParameterSetCount; ++ ++ u8_t wmeEnabled; ++ #define ZM_STA_WME_ENABLE_BIT 0x1 ++ #define ZM_STA_UAPSD_ENABLE_BIT 0x2 ++ u8_t wmeQosInfo; ++ ++ u8_t wmeConnected; ++ u8_t qosInfo; ++ struct zsQueue* uapsdQ; ++ ++ /* countermeasures */ ++ u8_t cmMicFailureCount; ++ u8_t cmDisallowSsidLength; ++ u8_t cmDisallowSsid[32]; ++ ++ /* power-saving mode */ ++ u8_t powerSaveMode; ++ zbuf_t* staPSDataQueue[ZM_PS_QUEUE_SIZE]; ++ u8_t staPSDataCount; ++ ++ /* IBSS power-saving mode */ ++ /* record the STA which has entered the PS mode */ ++ struct zsStaPSList staPSList; ++ /* queue the data of the PS STAs */ ++ zbuf_t* ibssPSDataQueue[ZM_PS_QUEUE_SIZE]; ++ u8_t ibssPSDataCount; ++ u8_t ibssPrevPSDataCount; ++ u8_t bIbssPSEnable; ++ /* BIT_15: ON/OFF, BIT_0~14: Atim Timer */ ++ u16_t ibssAtimTimer; ++ ++ /* WPA2 */ ++ struct zsPmkidInfo pmkidInfo; ++ ++ /* Multicast list related objects */ ++ struct zsMulticastList multicastList; ++ ++ /* XP packet filter feature : */ ++ /* 1=>enable: All multicast address packets, not just the ones enumerated in the multicast address list. */ ++ /* 0=>disable */ ++ u8_t bAllMulticast; ++ ++ /* reassociation flag */ ++ u8_t connectByReasso; ++ u8_t failCntOfReasso; ++ ++ /* for HT configure control setting */ ++ u8_t preambleTypeHT; /* HT: 0 Mixed mode 1 Green field */ ++ u8_t htCtrlBandwidth; ++ u8_t htCtrlSTBC; ++ u8_t htCtrlSG; ++ u8_t defaultTA; ++ ++ u8_t connection_11b; ++ ++ u8_t EnableHT; ++ u8_t SG40; ++ u8_t HT2040; ++ /* for WPA setting */ ++ u8_t wpaSupport; ++ u8_t wpaLen; ++ ++ /* IBSS related objects */ ++ u8_t ibssDelayedInd; ++ struct zsPartnerNotifyEvent ibssDelayedIndEvent; ++ u8_t ibssPartnerStatus; ++ ++ u8_t bAutoReconnect; ++ ++ u8_t flagFreqChanging; ++ u8_t flagKeyChanging; ++ struct zsBssInfo ibssBssDesc; ++ u8_t ibssBssIsCreator; ++ u16_t ibssReceiveBeaconCount; ++ u8_t ibssSiteSurveyStatus; ++ ++ u8_t disableProbingWithSsid; ++#ifdef ZM_ENABLE_CENC ++ /* CENC */ ++ u8_t cencIe[ZM_MAX_IE_SIZE + 2]; ++#endif //ZM_ENABLE_CENC ++ u32_t txiv[4]; //Tx PN Sequence ++ u32_t rxiv[4]; //Rx PN Sequence ++ u32_t rxivGK[4];//Broadcast Rx PN Sequence ++ u8_t wepKey[4][32]; // For Software WEP ++ u8_t SWEncryMode[4]; ++ ++ /* 802.11d */ ++ u8_t b802_11D; ++ ++ /* 802.11h */ ++ u8_t TPCEnable; ++ u8_t DFSEnable; ++ u8_t DFSDisableTx; ++ ++ /* Owl AP */ ++ u8_t athOwlAp; ++ ++ /* Enable BA response in driver */ ++ u8_t enableDrvBA; ++ ++ /* HT Capability Info */ ++ union zuHTCapability HTCap; //CWYang(+) ++ ++ /* Extended HT Capability Info */ ++ union zuExtHTCapability ExtHTCap; //CWYang(+) ++ ++ struct InformationElementSta ie; ++ ++#define ZM_CACHED_FRAMEBODY_SIZE 200 ++ u8_t asocReqFrameBody[ZM_CACHED_FRAMEBODY_SIZE]; ++ u16_t asocReqFrameBodySize; ++ u8_t asocRspFrameBody[ZM_CACHED_FRAMEBODY_SIZE]; ++ u16_t asocRspFrameBodySize; ++ u8_t beaconFrameBody[ZM_CACHED_FRAMEBODY_SIZE]; ++ u16_t beaconFrameBodySize; ++ ++ u8_t ac0PriorityHigherThanAc2; ++ u8_t SWEncryptEnable; ++ ++ u8_t leapEnabled; ++ ++ u32_t TotalNumberOfReceivePackets; ++ u32_t TotalNumberOfReceiveBytes; ++ u32_t avgSizeOfReceivePackets; ++ ++ u32_t ReceivedPacketRateCounter; ++ u32_t ReceivedPktRatePerSecond; ++ ++ /* #2 Record the sequence number to determine whether the unicast frame is separated by RIFS or not */ ++#define ZM_RIFS_STATE_DETECTING 0 ++#define ZM_RIFS_STATE_DETECTED 1 ++#define ZM_RIFS_TIMER_TIMEOUT 4480 // 4480ms 7s ++ u8_t rifsState; ++ u8_t rifsLikeFrameCnt; ++ u16_t rifsLikeFrameSequence[3]; ++ u32_t rifsTimer; ++ u32_t rifsCount; ++ ++ /* RX filter desired by upper layers. Note this contains some bits which must be filtered ++ by sw since the hw supports only a subset of possible filter actions.= */ ++ u32_t osRxFilter; ++ ++ u8_t bSafeMode; ++ ++ u32_t ibssAdditionalIESize; ++ u8_t ibssAdditionalIE[256]; ++}; //struct zsWlanDevSta ++ ++#define ZM_CMD_QUEUE_SIZE 256 //Roger Check, test 64 when ready ++ ++#define ZM_OID_READ 1 ++#define ZM_OID_WRITE 2 ++#define ZM_OID_INTERNAL_WRITE 3 ++#define ZM_CMD_SET_FREQUENCY 4 ++#define ZM_CMD_SET_KEY 5 ++#define ZM_CWM_READ 6 ++#define ZM_MAC_READ 7 ++#define ZM_ANI_READ 8 ++#define ZM_EEPROM_READ 9 ++#define ZM_EEPROM_WRITE 0x0A ++#define ZM_OID_CHAN 0x30 ++#define ZM_OID_SYNTH 0x32 ++#define ZM_OID_TALLY 0x81 ++#define ZM_OID_TALLY_APD 0x82 ++ ++#define ZM_OID_DKTX_STATUS 0x92 ++#define ZM_OID_FLASH_CHKSUM 0xD0 ++#define ZM_OID_FLASH_READ 0xD1 ++#define ZM_OID_FLASH_PROGRAM 0xD2 ++#define ZM_OID_FW_DL_INIT 0xD3 ++ ++/* Driver to Firmware OID */ ++#define ZM_CMD_ECHO 0x80 ++#define ZM_CMD_TALLY 0x81 ++#define ZM_CMD_TALLY_APD 0x82 ++#define ZM_CMD_CONFIG 0x83 ++#define ZM_CMD_RREG 0x00 ++#define ZM_CMD_WREG 0x01 ++#define ZM_CMD_RMEM 0x02 ++#define ZM_CMD_WMEM 0x03 ++#define ZM_CMD_BITAND 0x04 ++#define ZM_CMD_BITOR 0x05 ++#define ZM_CMD_EKEY 0x28 ++#define ZM_CMD_DKEY 0x29 ++#define ZM_CMD_FREQUENCY 0x30 ++#define ZM_CMD_RF_INIT 0x31 ++#define ZM_CMD_SYNTH 0x32 ++#define ZM_CMD_FREQ_STRAT 0x33 ++#define ZM_CMD_RESET 0x90 ++#define ZM_CMD_DKRESET 0x91 ++#define ZM_CMD_DKTX_STATUS 0x92 ++#define ZM_CMD_FDC 0xA0 ++#define ZM_CMD_WREEPROM 0xB0 ++#define ZM_CMD_WFLASH 0xB0 ++#define ZM_CMD_FLASH_ERASE 0xB1 ++#define ZM_CMD_FLASH_PROG 0xB2 ++#define ZM_CMD_FLASH_CHKSUM 0xB3 ++#define ZM_CMD_FLASH_READ 0xB4 ++#define ZM_CMD_FW_DL_INIT 0xB5 ++#define ZM_CMD_MEM_WREEPROM 0xBB ++ ++ ++/* duplicate filter table column */ ++#define ZM_FILTER_TABLE_COL 2 /* 2^n */ ++/* duplicate filter table Row */ ++#define ZM_FILTER_TABLE_ROW 8 /* 2^n */ ++ ++/* duplicate filter table structure */ ++struct zsRxFilter ++{ ++ u16_t addr[3]; ++ u16_t seq; ++ u8_t up; ++}; ++ ++struct zsWlanDev ++{ ++ /* AP global variables */ ++ struct zsWlanDevAp ap; ++ /* STA global variables */ ++ struct zsWlanDevSta sta; ++ /* save wrapper setting */ ++ struct zsWrapperSetting ws; ++ /* features determined by wrapper (vendor) */ ++ struct zsWrapperFeatureCtrl wfc; ++ /* Traffic Monitor tally */ ++ struct zsTrafTally trafTally; ++ /* Communication tally */ ++ struct zsCommTally commTally; ++ /* Duplicate frame filter table */ ++ struct zsRxFilter rxFilterTbl[ZM_FILTER_TABLE_COL][ZM_FILTER_TABLE_ROW]; ++ /* Regulatory table */ ++ struct zsRegulationTable regulationTable; ++ ++ /* */ ++ struct zsWlanDevFreqControl freqCtrl; ++ ++ enum devState state; ++ ++ u8_t halState; ++ u8_t wlanMode; /* AP/INFRASTRUCTURE/IBSS/PSEUDO */ ++ u16_t macAddr[3]; /* MAC address */ ++ u16_t beaconInterval; /* beacon Interval */ ++ u8_t dtim; /* DTIM period */ ++ u8_t CurrentDtimCount; ++ u8_t preambleType; ++ u8_t preambleTypeInUsed; ++ u8_t maxTxPower2; /* 2.4 GHz Max Tx power (Unit: 0.5 dBm) */ ++ u8_t maxTxPower5; /* 5 GHz Max Tx power (Unit: 0.5 dBm) */ ++ u8_t connectMode; ++ u32_t supportMode; ++ ++ u8_t bRate; /* 11b Support Rate bit map */ ++ u8_t bRateBasic; /* 11b Basic Rate bit map */ ++ u8_t gRate; /* 11g Support Rate bit map */ ++ u8_t gRateBasic; /* 11g Basic Rate bit map */ ++ /* channel index point to the item in regulation table */ ++ u8_t channelIndex; ++ ++ /* channel management */ ++ u8_t BandWidth40; ++ u8_t ExtOffset; //1 above, 3 below, 0 not present ++ u16_t frequency; /* operation frequency */ ++ ++ u8_t erpElement; /* ERP information element data */ ++ ++ u8_t disableSelfCts; /* set to 1 to disable Self-CTS */ ++ u8_t bgMode; ++ ++ /* private test flag */ ++ u32_t enableProtectionMode; /* force enable/disable self cts */ ++ u32_t checksumTest; /* OTUS checksum test 1=>zero checksum 0=>normal */ ++ u32_t rxPacketDump; /* rx packet dump */ ++ ++ u8_t enableAggregation; /* force enable/disable A-MSPU */ ++ u8_t enableWDS; /* force enable/disable WDS testing */ ++ u8_t enableTxPathMode; /* OTUS special testing mode 1=>diable, 0=>enable: ZM_SYSTEM_TEST_MODE */ ++ u8_t enableHALDbgInfo; /* */ ++ ++ u32_t forceTxTPC; /* force tx packet send TPC */ ++ ++ u16_t seq[4]; ++ u16_t mmseq; ++ ++ /* driver core time tick */ ++ u32_t tick; ++ u16_t tickIbssSendBeacon; ++ u16_t tickIbssReceiveBeacon; ++ ++ /* RTS threshold */ ++ u16_t rtsThreshold; ++ ++ /* fragmentation threshold, 256 <= value <= 2346, 0=disabled */ ++ u16_t fragThreshold; ++ ++ /* Tx Rate */ ++ u16_t txMCS; ++ u16_t txMT; ++ u32_t CurrentTxRateKbps; //CWYang(+) ++ /* Rx Rate */ ++ u32_t CurrentRxRateKbps; //Janet(+) ++ u8_t CurrentRxRateUpdated; ++ u8_t modulationType; ++ u8_t rxInfo; ++ u16_t rateField; ++ ++ /* timer related objects */ ++ struct zsTimerList timerList; ++ u8_t bTimerReady; ++ ++ /* for defragmentation */ ++ struct zsDefragList defragTable; ++ ++ /* Data struct for Interface Dependent Layer */ ++ //struct zsIdlStruct idlStruct; ++ ++ /* Signal Strength/Quality Related Parameters */ ++ u8_t SignalStrength; //CWYang(+) ++ u8_t SignalQuality; //CWYang(+) ++ ++ ++ ++ /* QoS */ ++ zbuf_t* vtxq[4][ZM_VTXQ_SIZE]; ++ u16_t vtxqHead[4]; ++ u16_t vtxqTail[4]; ++ u16_t qosDropIpFrag[4]; ++ ++ /* Management Tx queue */ ++ zbuf_t* vmmq[ZM_VMMQ_SIZE]; ++ u16_t vmmqHead; ++ u16_t vmmqTail; ++ ++ u8_t vtxqPushing; ++ ++ /* ++ * add by honda ++ * 1. Aggregate queues ++ * 2. STA's associated information and queue number ++ * 3. rx aggregation re-ordering queue ++ */ ++ struct aggQueue *aggQPool[ZM_AGG_POOL_SIZE]; ++ u8_t aggInitiated; ++ u8_t addbaComplete; ++ u8_t addbaCount; ++ u8_t aggState; ++ u8_t destLock; ++ struct aggSta aggSta[ZM_MAX_STA_SUPPORT]; ++ struct agg_tid_rx *tid_rx[ZM_AGG_POOL_SIZE]; ++ struct aggTally agg_tal; ++ struct destQ destQ; ++ struct baw_enabler *baw_enabler; ++ struct ieee80211_cwm cwm; ++ u16_t reorder; ++ u16_t seq_debug; ++ /* rate control */ ++ u32_t txMPDU[ZM_RATE_TABLE_SIZE]; ++ u32_t txFail[ZM_RATE_TABLE_SIZE]; ++ u32_t PER[ZM_RATE_TABLE_SIZE]; ++ u16_t probeCount; ++ u16_t probeSuccessCount; ++ u16_t probeInterval; ++ u16_t success_probing; ++ /* ++ * end of add by honda ++ */ ++ ++ /* airopeek sniffer mode for upper sw */ ++ u32_t swSniffer; /* window: airoPeek */ ++ u32_t XLinkMode; ++ ++ /* MDK mode */ ++ /* init by 0=>normal driver 1=>MDK driver */ ++ u32_t modeMDKEnable; ++ ++ u32_t heartBeatNotification; ++ ++ /* pointer for HAL Plus private memory */ ++ void* hpPrivate; ++ ++ /* for WPA setting */ ++ //u8_t wpaSupport[ZM_MAX_AP_SUPPORT]; ++ //u8_t wpaLen[ZM_MAX_AP_SUPPORT]; ++ //u8_t wpaIe[ZM_MAX_AP_SUPPORT][ZM_MAX_IE_SIZE]; ++ ++ struct zsLedStruct ledStruct; ++ ++ /* ani flag */ ++ u8_t aniEnable; ++ u16_t txq_threshold; ++ ++ //Skip Mic Error Check ++ u8_t TKIP_Group_KeyChanging; ++ ++ u8_t dynamicSIFSEnable; ++ ++ u8_t queueFlushed; ++ ++ u16_t (*zfcbAuthNotify)(zdev_t* dev, u16_t* macAddr); ++ u16_t (*zfcbAsocNotify)(zdev_t* dev, u16_t* macAddr, u8_t* body, u16_t bodySize, u16_t port); ++ u16_t (*zfcbDisAsocNotify)(zdev_t* dev, u8_t* macAddr, u16_t port); ++ u16_t (*zfcbApConnectNotify)(zdev_t* dev, u8_t* macAddr, u16_t port); ++ void (*zfcbConnectNotify)(zdev_t* dev, u16_t status, u16_t* bssid); ++ void (*zfcbScanNotify)(zdev_t* dev, struct zsScanResult* result); ++ void (*zfcbMicFailureNotify)(zdev_t* dev, u16_t* addr, u16_t status); ++ void (*zfcbApMicFailureNotify)(zdev_t* dev, u8_t* addr, zbuf_t* buf); ++ void (*zfcbIbssPartnerNotify)(zdev_t* dev, u16_t status, struct zsPartnerNotifyEvent *event); ++ void (*zfcbMacAddressNotify)(zdev_t* dev, u8_t* addr); ++ void (*zfcbSendCompleteIndication)(zdev_t* dev, zbuf_t* buf); ++ void (*zfcbRecvEth)(zdev_t* dev, zbuf_t* buf, u16_t port); ++ void (*zfcbRecv80211)(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++ void (*zfcbRestoreBufData)(zdev_t* dev, zbuf_t* buf); ++#ifdef ZM_ENABLE_CENC ++ u16_t (*zfcbCencAsocNotify)(zdev_t* dev, u16_t* macAddr, u8_t* body, ++ u16_t bodySize, u16_t port); ++#endif //ZM_ENABLE_CENC ++ u8_t (*zfcbClassifyTxPacket)(zdev_t* dev, zbuf_t* buf); ++ void (*zfcbHwWatchDogNotify)(zdev_t* dev); ++}; ++ ++ ++struct zsWlanKey ++{ ++ u8_t key; ++}; ++ ++ ++/* These macros are defined here for backward compatibility */ ++/* Please leave them alone */ ++/* For Tx packet allocated in upper layer layer */ ++#define zmw_tx_buf_readb(dev, buf, offset) zmw_buf_readb(dev, buf, offset) ++#define zmw_tx_buf_readh(dev, buf, offset) zmw_buf_readh(dev, buf, offset) ++#define zmw_tx_buf_writeb(dev, buf, offset, value) zmw_buf_writeb(dev, buf, offset, value) ++#define zmw_tx_buf_writeh(dev, buf, offset, value) zmw_buf_writeh(dev, buf, offset, value) ++ ++/* For Rx packet allocated in driver */ ++#define zmw_rx_buf_readb(dev, buf, offset) zmw_buf_readb(dev, buf, offset) ++#define zmw_rx_buf_readh(dev, buf, offset) zmw_buf_readh(dev, buf, offset) ++#define zmw_rx_buf_writeb(dev, buf, offset, value) zmw_buf_writeb(dev, buf, offset, value) ++#define zmw_rx_buf_writeh(dev, buf, offset, value) zmw_buf_writeh(dev, buf, offset, value) ++ ++#endif /* #ifndef _STRUCT_H */ +--- /dev/null ++++ b/drivers/staging/otus/80211core/wlan.h +@@ -0,0 +1,595 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : wlan_defs.h */ ++/* */ ++/* Abstract */ ++/* This module contains WLAN definitions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _WLAN_H ++#define _WLAN_H ++ ++ ++#define ZM_EXTERNAL_ALLOC_BUF 0 ++#define ZM_INTERNAL_ALLOC_BUF 1 ++ ++#define ZM_SIZE_OF_CTRL_SET 8 ++#define ZM_SIZE_OF_IV 4 ++#define ZM_SIZE_OF_EXT_IV 4 ++#define ZM_SIZE_OF_MIC 8 ++#define ZM_SIZE_OF_CCX_MIC 8 ++#define ZM_SIZE_OF_WLAN_DATA_HEADER 24 ++#define ZM_SIZE_OF_QOS_CTRL 2 ++ ++/* Header definition */ ++#define ZM_SIZE_OF_WLAN_WDS_HEADER 32 ++#define ZM_SIZE_OF_SNAP_HEADER 8 ++ ++#define ZM_WLAN_HEADER_A1_OFFSET 4 ++#define ZM_WLAN_HEADER_A2_OFFSET 10 ++#define ZM_WLAN_HEADER_A3_OFFSET 16 ++#define ZM_WLAN_HEADER_A4_OFFSET 24 ++#define ZM_WLAN_HEADER_IV_OFFSET 24 ++#define ZM_SIZE_OF_WLAN_DATA_HEADER 24 ++ ++/* Port definition */ ++#define ZM_PORT_DISABLED 0 ++#define ZM_PORT_ENABLED 1 ++ ++/* Frame Type */ ++#define ZM_WLAN_MANAGEMENT_FRAME 0x0 ++#define ZM_WLAN_CONTROL_FRAME 0x4 ++#define ZM_WLAN_DATA_FRAME 0x8 ++ ++/* Frame Subtype */ ++#define ZM_WLAN_FRAME_TYPE_ASOCREQ 0x00 ++#define ZM_WLAN_FRAME_TYPE_ASOCRSP 0x10 ++#define ZM_WLAN_FRAME_TYPE_REASOCREQ 0x20 ++#define ZM_WLAN_FRAME_TYPE_REASOCRSP 0x30 ++#define ZM_WLAN_FRAME_TYPE_PROBEREQ 0x40 ++#define ZM_WLAN_FRAME_TYPE_PROBERSP 0x50 ++/* 0x60, 0x70 => Reserved */ ++#define ZM_WLAN_FRAME_TYPE_BEACON 0x80 ++#define ZM_WLAN_FRAME_TYPE_ATIM 0x90 ++#define ZM_WLAN_FRAME_TYPE_DISASOC 0xA0 ++#define ZM_WLAN_FRAME_TYPE_AUTH 0xB0 ++#define ZM_WLAN_FRAME_TYPE_DEAUTH 0xC0 ++#define ZM_WLAN_FRAME_TYPE_ACTION 0xD0 ++ ++/* Frame type and subtype */ ++#define ZM_WLAN_FRAME_TYPE_NULL 0x48 ++#define ZM_WLAN_FRAME_TYPE_BAR 0x84 ++#define ZM_WLAN_FRAME_TYPE_BA 0x94 ++#define ZM_WLAN_FRAME_TYPE_PSPOLL 0xA4 ++#define ZM_WLAN_FRAME_TYPE_RTS 0xB4 ++#define ZM_WLAN_FRAME_TYPE_CTS 0xC4 ++#define ZM_WLAN_FRAME_TYPE_QOS_NULL 0xC8 ++ ++/* action frame */ ++#define ZM_WLAN_SPECTRUM_MANAGEMENT_ACTION_FRAME 0 ++#define ZM_WLAN_QOS_ACTION_FRAME 1 ++#define ZM_WLAN_DLS_ACTION_FRAME 2 ++#define ZM_WLAN_BLOCK_ACK_ACTION_FRAME 3 ++/* block ack action frame*/ ++#define ZM_WLAN_ADDBA_REQUEST_FRAME 0 ++#define ZM_WLAN_ADDBA_RESPONSE_FRAME 1 ++#define ZM_WLAN_DELBA_FRAME 2 ++ ++/* Element ID */ ++#define ZM_WLAN_EID_SSID 0 ++#define ZM_WLAN_EID_SUPPORT_RATE 1 ++#define ZM_WLAN_EID_FH 2 ++#define ZM_WLAN_EID_DS 3 ++#define ZM_WLAN_EID_CFS 4 ++#define ZM_WLAN_EID_TIM 5 ++#define ZM_WLAN_EID_IBSS 6 ++#define ZM_WLAN_EID_COUNTRY 7 ++/* reserved 8-15 */ ++#define ZM_WLAN_EID_CHALLENGE 16 ++/* reserved 17-31 */ ++#define ZM_WLAN_EID_POWER_CONSTRAINT 32 ++#define ZM_WLAN_EID_POWER_CAPABILITY 33 ++#define ZM_WLAN_EID_TPC_REQUEST 34 ++#define ZM_WLAN_EID_TPC_REPORT 35 ++#define ZM_WLAN_EID_SUPPORTED_CHANNELS 36 ++#define ZM_WLAN_EID_CHANNEL_SWITCH_ANNOUNCE 37 ++#define ZM_WLAN_EID_MEASUREMENT_REQUEST 38 ++#define ZM_WLAN_EID_MEASUREMENT_REPORT 39 ++#define ZM_WLAN_EID_QUIET 40 ++#define ZM_WLAN_EID_IBSS_DFS 41 ++#define ZM_WLAN_EID_ERP 42 ++#define ZM_WLAN_PREN2_EID_HTCAPABILITY 45 ++#define ZM_WLAN_EID_RSN_IE 48 ++#define ZM_WLAN_EID_EXTENDED_RATE 50 ++#define ZM_WLAN_EID_HT_CAPABILITY 51 ++#define ZM_WLAN_EID_EXTENDED_HT_CAPABILITY 52 ++#define ZM_WLAN_EID_NEW_EXT_CHANNEL_OFFSET 53 ++#define ZM_WLAN_PREN2_EID_HTINFORMATION 61 ++#define ZM_WLAN_PREN2_EID_SECONDCHOFFSET 62 ++#ifdef ZM_ENABLE_CENC ++#define ZM_WLAN_EID_CENC_IE 68 ++#endif //ZM_ENABLE_CENC ++#define ZM_WLAN_EID_VENDOR_PRIVATE 221 /* Vendor private space; must demux OUI */ ++#define ZM_WLAN_EID_WPA_IE 221 ++#define ZM_WLAN_EID_WPS_IE 221 ++#define ZM_WLAN_EID_WIFI_IE 221 ++ ++/* ERP information element */ ++#define ZM_WLAN_NON_ERP_PRESENT_BIT 0x1 ++#define ZM_WLAN_USE_PROTECTION_BIT 0x2 ++#define ZM_WLAN_BARKER_PREAMBLE_MODE_BIT 0x4 ++ ++/* Channel frequency, in MHz */ ++#define ZM_CH_G_1 2412 ++#define ZM_CH_G_2 2417 ++#define ZM_CH_G_3 2422 ++#define ZM_CH_G_4 2427 ++#define ZM_CH_G_5 2432 ++#define ZM_CH_G_6 2437 ++#define ZM_CH_G_7 2442 ++#define ZM_CH_G_8 2447 ++#define ZM_CH_G_9 2452 ++#define ZM_CH_G_10 2457 ++#define ZM_CH_G_11 2462 ++#define ZM_CH_G_12 2467 ++#define ZM_CH_G_13 2472 ++#define ZM_CH_G_14 2484 ++#define ZM_CH_A_184 4920 ++#define ZM_CH_A_188 4940 ++#define ZM_CH_A_192 4960 ++#define ZM_CH_A_196 4980 ++#define ZM_CH_A_8 5040 ++#define ZM_CH_A_12 5060 ++#define ZM_CH_A_16 5080 ++#define ZM_CH_A_36 5180 ++#define ZM_CH_A_40 5200 ++#define ZM_CH_A_44 5220 ++#define ZM_CH_A_48 5240 ++#define ZM_CH_A_52 5260 ++#define ZM_CH_A_56 5280 ++#define ZM_CH_A_60 5300 ++#define ZM_CH_A_64 5320 ++#define ZM_CH_A_100 5500 ++#define ZM_CH_A_104 5520 ++#define ZM_CH_A_108 5540 ++#define ZM_CH_A_112 5560 ++#define ZM_CH_A_116 5580 ++#define ZM_CH_A_120 5600 ++#define ZM_CH_A_124 5620 ++#define ZM_CH_A_128 5640 ++#define ZM_CH_A_132 5660 ++#define ZM_CH_A_136 5680 ++#define ZM_CH_A_140 5700 ++#define ZM_CH_A_149 5745 ++#define ZM_CH_A_153 5765 ++#define ZM_CH_A_157 5785 ++#define ZM_CH_A_161 5805 ++#define ZM_CH_A_165 5825 ++ ++ ++/* AP : STA table => STA Type */ ++#define ZM_11B_STA 0x0 ++#define ZM_11G_STA 0x2 ++#define ZM_11N_STA 0x4 ++ ++/* AP : timeout */ ++#define ZM_MS_PER_TICK 10 ++#define ZM_TICK_PER_SECOND (1000/ZM_MS_PER_TICK) ++#define ZM_TICK_PER_MINUTE (60*1000/ZM_MS_PER_TICK) ++#define ZM_PREAUTH_TIMEOUT_MS 1000 /* 1 sec */ ++#define ZM_AUTH_TIMEOUT_MS 1000 /* 1 sec */ ++ ++/* Error code */ ++#define ZM_SUCCESS 0 ++#define ZM_ERR_TX_PORT_DISABLED 1 ++#define ZM_ERR_BUFFER_DMA_ADDR 2 ++#define ZM_ERR_FREE_TXD_EXHAUSTED 3 ++#define ZM_ERR_TX_BUFFER_UNAVAILABLE 4 ++#define ZM_ERR_BCMC_PS_BUFFER_UNAVAILABLE 5 ++#define ZM_ERR_UNI_PS_BUFFER_UNAVAILABLE 6 ++#define ZM_ERR_EXCEED_PRIORITY_THRESHOLD 7 ++#define ZM_ERR_VMMQ_FULL 8 ++#define ZM_ERR_FLUSH_PS_QUEUE 9 ++#define ZM_ERR_CMD_INT_MISSED 15 /* Polling cmd int timeout*/ ++/* Rx */ ++#define ZM_ERR_RX_FRAME_TYPE 20 ++#define ZM_ERR_MIN_RX_ENCRYPT_FRAME_LENGTH 21 ++#define ZM_ERR_MIN_RX_FRAME_LENGTH 22 ++#define ZM_ERR_MAX_RX_FRAME_LENGTH 23 ++#define ZM_ERR_RX_DUPLICATE 24 ++#define ZM_ERR_RX_SRC_ADDR_IS_OWN_MAC 25 ++#define ZM_ERR_MIN_RX_PROTOCOL_VERSION 26 ++#define ZM_ERR_WPA_GK_NOT_INSTALLED 27 ++#define ZM_ERR_STA_NOT_ASSOCIATED 28 ++#define ZM_ERR_DATA_BEFORE_CONNECTED 29 ++#define ZM_ERR_DATA_NOT_ENCRYPTED 30 ++#define ZM_ERR_DATA_BSSID_NOT_MATCHED 31 ++#define ZM_ERR_RX_BAR_FRAME 32 ++#define ZM_ERR_OUT_OF_ORDER_NULL_DATA 33 ++ ++/* ZFI */ ++#define ZM_ERR_INVALID_TX_RATE 40 ++#define ZM_ERR_WDS_PORT_ID 41 ++ ++/* QUEUE */ ++#define ZM_ERR_QUEUE_FULL 50 ++#define ZM_ERR_STA_UAPSD_QUEUE_FULL 51 ++#define ZM_ERR_AP_UAPSD_QUEUE_FULL 52 ++ ++/* Maximum Rx frame length */ ++#if ZM_LARGEPAYLOAD_TEST == 1 ++#define ZM_WLAN_MAX_RX_SIZE 16384 ++#else ++#define ZM_WLAN_MAX_RX_SIZE 8192 ++#endif ++ ++/* PCI DMA test error code */ ++#define ZM_ERR_INTERRUPT_MISSED 100 ++#define ZM_ERR_OWN_BIT_NOT_CLEARED 101 ++#define ZM_ERR_RX_SEQ_NUMBER 102 ++#define ZM_ERR_RX_LENGTH 103 ++#define ZM_ERR_RX_DATA 104 ++#define ZM_ERR_RX_DESCRIPTOR_NUM 105 ++/* Common register test error code */ ++#define ZM_ERR_REGISTER_ACCESS 110 /* Register R/W test fail*/ ++#define ZM_ERR_CLEAR_INTERRUPT_FLAG 111 ++#define ZM_ERR_COMMAND_RESPONSE 112 ++#define ZM_ERR_INTERRUPT_GENERATE 113 ++#define ZM_ERR_INTERRUPT_ACK 114 ++#define ZM_ERR_SCRATCH_ACCESS 115 ++#define ZM_ERR_INTERRUPT_MASK_ACCESS 116 ++#define ZM_ERR_SHARE_MEMORY_PCI_ACCESS 117 ++#define ZM_ERR_SHARE_MEMORY_FW_ACCESS 118 ++#define ZM_ERR_SHARE_MEMORY_DISABLE 119 ++#define ZM_ERR_SHARE_MEMORY_TEST_RESPONSE 120 ++ ++/* Firmware Download error code */ ++#define ZM_ERR_FIRMWARE_DOWNLOAD_TIMEOUT 150 ++#define ZM_ERR_FIRMWARE_DOWNLOAD_INT_FLAG 151 ++#define ZM_ERR_FIRMWARE_READY_TIMEOUT 152 ++#define ZM_ERR_FIRMWARE_WRONG_TYPE 153 ++ ++/* Debug */ ++#define ZM_LV_0 0//Debug level 0, Disable debug message ++#define ZM_LV_1 1//Debug level 1, Show minimum information ++#define ZM_LV_2 2//Debug level 2, Show medium message ++#define ZM_LV_3 3//Debug level 3, Show all ++ ++#define ZM_SCANMSG_LEV ZM_LV_1 ++#define ZM_TXMSG_LEV ZM_LV_0//ZM_LV_0 ++#define ZM_RXMSG_LEV ZM_LV_0 ++#define ZM_MMMSG_LEV ZM_LV_0 ++#define ZM_DESMSG_LEV ZM_LV_0//ZM_LV_0 ++#define ZM_BUFMSG_LEV ZM_LV_0//ZM_LV_1 ++#define ZM_INITMSG_LEV ZM_LV_0 ++ ++#define zm_msg0_scan(lv, msg) if (ZM_SCANMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_scan(lv, msg, val) if (ZM_SCANMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_scan(lv, msg, val) if (ZM_SCANMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define zm_msg0_tx(lv, msg) if (ZM_TXMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_tx(lv, msg, val) if (ZM_TXMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_tx(lv, msg, val) if (ZM_TXMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define zm_msg0_rx(lv, msg) if (ZM_RXMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_rx(lv, msg, val) if (ZM_RXMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_rx(lv, msg, val) if (ZM_RXMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define zm_msg0_mm(lv, msg) if (ZM_MMMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_mm(lv, msg, val) if (ZM_MMMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_mm(lv, msg, val) if (ZM_MMMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define zm_msg0_des(lv, msg) if (ZM_DESMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_des(lv, msg, val) if (ZM_DESMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_des(lv, msg, val) if (ZM_DESMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define zm_msg0_buf(lv, msg) if (ZM_BUFMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_buf(lv, msg, val) if (ZM_BUFMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_buf(lv, msg, val) if (ZM_BUFMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define zm_msg0_init(lv, msg) if (ZM_INITMSG_LEV >= lv) \ ++ {zm_debug_msg0(msg);} ++#define zm_msg1_init(lv, msg, val) if (ZM_INITMSG_LEV >= lv) \ ++ {zm_debug_msg1(msg, val);} ++#define zm_msg2_init(lv, msg, val) if (ZM_INITMSG_LEV >= lv) \ ++ {zm_debug_msg2(msg, val);} ++ ++#define ZM_MAX_AP_SUPPORT 2 /* Must <= 8 */ ++#define ZM_MAX_WDS_SUPPORT 6 /* Must <= 6 */ ++#define ZM_MAX_STA_SUPPORT 16 /* Must <= 64 */ ++ ++/* STA table state */ ++#define ZM_STATE_AUTH 1 ++#define ZM_STATE_PREAUTH 2 ++#define ZM_STATE_ASOC 3 ++ ++/* Rate set */ ++#define ZM_RATE_SET_CCK 0 ++#define ZM_RATE_SET_OFDM 1 ++ ++/* HT PT */ ++#define ZM_PREAMBLE_TYPE_MIXED_MODE 0 ++#define ZM_PREAMBLE_TYPE_GREEN_FIELD 1 ++ ++/* HT bandwidth */ ++#define ZM_BANDWIDTH_20MHZ 0 ++#define ZM_BANDWIDTH_40MHZ 1 ++ ++/* MIC status */ ++#define ZM_MIC_SUCCESS 0 ++#define ZM_MIC_FAILURE 1 ++ ++/* ICV status */ ++#define ZM_ICV_SUCCESS 0 ++#define ZM_ICV_FAILURE 1 ++ ++/* definition check */ ++#if (ZM_MAX_AP_SUPPORT > 8) ++definition error, ZM_MAX_AP_SUPPORT > 8 ++#endif ++#if (ZM_MAX_AP_SUPPORT > 64) ++definition error, ZM_MAX_STA_SUPPORT > 64 ++#endif ++ ++/* Transmission Rate information */ ++ ++/* WLAN frame format */ ++#define ZM_PLCP_HEADER_SIZE 5 ++#define ZM_ETHERNET_ADDRESS_LENGTH 6 ++#define ZM_TIMESTAMP_OFFSET 0 ++#define ZM_BEACON_INTERVAL_OFFSET 8 ++#define ZM_CAPABILITY_OFFSET 10 ++ ++/* Reason Code */ ++/* An unsolicited notification management frame of */ ++/* type Disassocation or Deauthentication was generated. */ ++#ifdef ZM_REASON_CODE ++#define ZM_WLAN_REASON_CODE_UNSPECIFIED 1 ++#define ZM_WLAN_FRAME_DISASOC_DEAUTH_REASON_CODE 24 ++#endif ++ ++struct zsWlanManagementFrameHeader ++{ ++ //u8_t plcpHdr[ZM_PLCP_HEADER_SIZE]; ++ u8_t frameCtrl[2]; ++ u8_t duration[2]; ++ u8_t da[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t sa[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t bssid[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t seqCtrl[2]; ++ u8_t body[1]; ++}; ++ ++struct zsWlanProbeRspFrameHeader ++{ ++ //u8_t plcpHdr[ZM_PLCP_HEADER_SIZE]; ++ u8_t frameCtrl[2]; ++ u8_t duration[2]; ++ u8_t da[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t sa[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t bssid[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t seqCtrl[2]; ++ u8_t timeStamp[8]; ++ u8_t beaconInterval[2]; ++ u8_t capability[2]; ++ u8_t ssid[ZM_MAX_SSID_LENGTH + 2]; // EID(1) + Length(1) + SSID(32) ++} ; ++ ++#define zsWlanBeaconFrameHeader zsWlanProbeRspFrameHeader ++ ++struct zsWlanAuthFrameHeader ++{ ++ //u8_t plcpHdr[ZM_PLCP_HEADER_SIZE]; ++ u8_t frameCtrl[2]; ++ u8_t duration[2]; ++ u8_t address1[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t address2[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t address3[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t seqCtrl[2]; ++ u16_t algo; ++ u16_t seq; ++ u16_t status; ++ u8_t challengeText[255]; // the first 2 bytes are information ID, length ++}; ++ ++struct zsWlanAssoFrameHeader ++{ ++ //u8_t plcpHdr[PLCP_HEADER_SIZE]; ++ u8_t frameCtrl[2]; ++ u8_t duration[2]; ++ u8_t address1[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t address2[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t address3[ZM_ETHERNET_ADDRESS_LENGTH]; ++ u8_t seqCtrl[2]; ++ u8_t capability[2]; ++ u16_t status; ++ u16_t aid; ++ //u8_t supportedRates[10]; ++}; ++ ++struct zsFrag ++{ ++ zbuf_t* buf[16]; ++ u16_t bufType[16]; ++ u16_t seq[16]; ++ u8_t flag[16]; ++ ++}; ++ ++//================================ ++// Hardware related definitions ++//================================ ++#define ZM_MAC_REG_BASE 0x1c3000 ++ ++#define ZM_MAC_REG_ATIM_WINDOW (ZM_MAC_REG_BASE + 0x51C) ++#define ZM_MAC_REG_BCN_PERIOD (ZM_MAC_REG_BASE + 0x520) ++#define ZM_MAC_REG_PRETBTT (ZM_MAC_REG_BASE + 0x524) ++ ++#define ZM_MAC_REG_MAC_ADDR_L (ZM_MAC_REG_BASE + 0x610) ++#define ZM_MAC_REG_MAC_ADDR_H (ZM_MAC_REG_BASE + 0x614) ++ ++#define ZM_MAC_REG_GROUP_HASH_TBL_L (ZM_MAC_REG_BASE + 0x624) ++#define ZM_MAC_REG_GROUP_HASH_TBL_H (ZM_MAC_REG_BASE + 0x628) ++ ++#define ZM_MAC_REG_BASIC_RATE (ZM_MAC_REG_BASE + 0x630) ++#define ZM_MAC_REG_MANDATORY_RATE (ZM_MAC_REG_BASE + 0x634) ++#define ZM_MAC_REG_RTS_CTS_RATE (ZM_MAC_REG_BASE + 0x638) ++#define ZM_MAC_REG_BACKOFF_PROTECT (ZM_MAC_REG_BASE + 0x63c) ++#define ZM_MAC_REG_RX_THRESHOLD (ZM_MAC_REG_BASE + 0x640) ++#define ZM_MAC_REG_RX_PE_DELAY (ZM_MAC_REG_BASE + 0x64C) ++ ++#define ZM_MAC_REG_DYNAMIC_SIFS_ACK (ZM_MAC_REG_BASE + 0x658) ++#define ZM_MAC_REG_SNIFFER (ZM_MAC_REG_BASE + 0x674) ++#define ZM_MAC_REG_TX_UNDERRUN (ZM_MAC_REG_BASE + 0x688) ++#define ZM_MAC_REG_RX_TOTAL (ZM_MAC_REG_BASE + 0x6A0) ++#define ZM_MAC_REG_RX_CRC32 (ZM_MAC_REG_BASE + 0x6A4) ++#define ZM_MAC_REG_RX_CRC16 (ZM_MAC_REG_BASE + 0x6A8) ++#define ZM_MAC_REG_RX_ERR_UNI (ZM_MAC_REG_BASE + 0x6AC) ++#define ZM_MAC_REG_RX_OVERRUN (ZM_MAC_REG_BASE + 0x6B0) ++#define ZM_MAC_REG_RX_ERR_MUL (ZM_MAC_REG_BASE + 0x6BC) ++#define ZM_MAC_REG_TX_RETRY (ZM_MAC_REG_BASE + 0x6CC) ++#define ZM_MAC_REG_TX_TOTAL (ZM_MAC_REG_BASE + 0x6F4) ++ ++ ++#define ZM_MAC_REG_ACK_EXTENSION (ZM_MAC_REG_BASE + 0x690) ++#define ZM_MAC_REG_EIFS_AND_SIFS (ZM_MAC_REG_BASE + 0x698) ++ ++#define ZM_MAC_REG_SLOT_TIME (ZM_MAC_REG_BASE + 0x6F0) ++ ++#define ZM_MAC_REG_ROLL_CALL_TBL_L (ZM_MAC_REG_BASE + 0x704) ++#define ZM_MAC_REG_ROLL_CALL_TBL_H (ZM_MAC_REG_BASE + 0x708) ++ ++#define ZM_MAC_REG_AC0_CW (ZM_MAC_REG_BASE + 0xB00) ++#define ZM_MAC_REG_AC1_CW (ZM_MAC_REG_BASE + 0xB04) ++#define ZM_MAC_REG_AC2_CW (ZM_MAC_REG_BASE + 0xB08) ++#define ZM_MAC_REG_AC3_CW (ZM_MAC_REG_BASE + 0xB0C) ++#define ZM_MAC_REG_AC4_CW (ZM_MAC_REG_BASE + 0xB10) ++#define ZM_MAC_REG_AC1_AC0_AIFS (ZM_MAC_REG_BASE + 0xB14) ++#define ZM_MAC_REG_AC3_AC2_AIFS (ZM_MAC_REG_BASE + 0xB18) ++ ++#define ZM_MAC_REG_RETRY_MAX (ZM_MAC_REG_BASE + 0xB28) ++ ++#define ZM_MAC_REG_TXOP_NOT_ENOUGH_INDICATION (ZM_MAC_REG_BASE + 0xB30) ++ ++#define ZM_MAC_REG_AC1_AC0_TXOP (ZM_MAC_REG_BASE + 0xB44) ++#define ZM_MAC_REG_AC3_AC2_TXOP (ZM_MAC_REG_BASE + 0xB48) ++ ++#define ZM_MAC_REG_ACK_TABLE (ZM_MAC_REG_BASE + 0xC00) ++ ++#define ZM_MAC_REG_BCN_ADDR (ZM_MAC_REG_BASE + 0xD84) ++#define ZM_MAC_REG_BCN_LENGTH (ZM_MAC_REG_BASE + 0xD88) ++ ++#define ZM_MAC_REG_BCN_PLCP (ZM_MAC_REG_BASE + 0xD90) ++#define ZM_MAC_REG_BCN_CTRL (ZM_MAC_REG_BASE + 0xD94) ++ ++#define ZM_MAC_REG_BCN_HT1 (ZM_MAC_REG_BASE + 0xDA0) ++#define ZM_MAC_REG_BCN_HT2 (ZM_MAC_REG_BASE + 0xDA4) ++ ++ ++#define ZM_RX_STATUS_IS_MIC_FAIL(rxStatus) rxStatus->Tail.Data.ErrorIndication & ZM_BIT_6 ++ ++//================================ ++//================================ ++ ++#ifdef ZM_ENABLE_NATIVE_WIFI ++#define ZM_80211_FRAME_HEADER_LEN 24 ++#define ZM_80211_FRAME_TYPE_OFFSET 30 // ZM_80211_FRAME_HEADER_LEN + SNAP ++#define ZM_80211_FRAME_IP_OFFSET 32 // ZM_80211_FRAME_HEADER_LEN + SNAP + TYPE ++#else ++#define ZM_80211_FRAME_HEADER_LEN 14 ++#define ZM_80211_FRAME_TYPE_OFFSET 12 // ZM_80211_FRAME_HEADER_LEN + SNAP ++#define ZM_80211_FRAME_IP_OFFSET 14 // ZM_80211_FRAME_HEADER_LEN + SNAP + TYPE ++#endif ++ ++#define ZM_BSS_INFO_VALID_BIT 0x01 ++#define ZM_BSS_INFO_UPDATED_BIT 0x02 ++ ++ ++ ++ ++ ++#define ZM_ERROR_INDICATION_RX_TIMEOUT 0x01 ++#define ZM_ERROR_INDICATION_OVERRUN 0x02 ++#define ZM_ERROR_INDICATION_DECRYPT_ERROR 0x04 ++#define ZM_ERROR_INDICATION_CRC32_ERROR 0x08 ++#define ZM_ERROR_INDICATION_ADDR_NOT_MATCH 0x10 ++#define ZM_ERROR_INDICATION_CRC16_ERROR 0x20 ++#define ZM_ERROR_INDICATION_MIC_ERROR 0x40 ++ ++#define ZM_RXMAC_STATUS_MOD_TYPE_CCK 0x00 ++#define ZM_RXMAC_STATUS_MOD_TYPE_OFDM 0x01 ++#define ZM_RXMAC_STATUS_MOD_TYPE_HT_OFDM 0x02 ++#define ZM_RXMAC_STATUS_MOD_TYPE_DL_OFDM 0x03 ++#define ZM_RXMAC_STATUS_TOTAL_ERROR 0x80 ++ ++ ++ ++ ++ ++#define ZM_MAX_LED_NUMBER 2 ++ ++#define ZM_LED_DISABLE_MODE 0x0 ++#define ZM_LED_LINK_MODE 0x1 ++#define ZM_LED_LINK_TR_MODE 0x2 ++#define ZM_LED_TR_ON_MODE 0x3 ++#define ZM_LED_TR_OFF_MODE 0x4 ++ ++#define ZM_LED_CTRL_FLAG_ALPHA 0x1 ++ ++struct zsLedStruct ++{ ++ u32_t counter; ++ u32_t counter100ms; ++ u16_t ledLinkState; ++ u16_t ledMode[ZM_MAX_LED_NUMBER]; ++ u32_t txTraffic; ++ u32_t rxTraffic; ++ u8_t LEDCtrlType; ++ u8_t LEDCtrlFlag; // Control Flag for vendors ++ u8_t LEDCtrlFlagFromReg; // Control Flag for vendors in registry ++}; ++ ++ ++//HAL+ capability bits definition ++#define ZM_HP_CAP_11N 0x1 ++#define ZM_HP_CAP_11N_ONE_TX_STREAM 0x2 ++#define ZM_HP_CAP_2G 0x4 ++#define ZM_HP_CAP_5G 0x8 ++ ++#endif /* #ifndef _WLAN_H */ +--- /dev/null ++++ b/drivers/staging/otus/apdbg.c +@@ -0,0 +1,457 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : apdbg.c */ ++/* */ ++/* Abstract */ ++/* Debug tools */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define ZM_IOCTL_REG_READ 0x01 ++#define ZM_IOCTL_REG_WRITE 0x02 ++#define ZM_IOCTL_MEM_DUMP 0x03 ++#define ZM_IOCTL_REG_DUMP 0x05 ++#define ZM_IOCTL_TXD_DUMP 0x06 ++#define ZM_IOCTL_RXD_DUMP 0x07 ++#define ZM_IOCTL_MEM_READ 0x0B ++#define ZM_IOCTL_MEM_WRITE 0x0C ++#define ZM_IOCTL_DMA_TEST 0x10 ++#define ZM_IOCTL_REG_TEST 0x11 ++#define ZM_IOCTL_TEST 0x80 ++#define ZM_IOCTL_TALLY 0x81 //CWYang(+) ++#define ZM_IOCTL_RTS 0xA0 ++#define ZM_IOCTL_MIX_MODE 0xA1 ++#define ZM_IOCTL_FRAG 0xA2 ++#define ZM_IOCTL_SCAN 0xA3 ++#define ZM_IOCTL_KEY 0xA4 ++#define ZM_IOCTL_RATE 0xA5 ++#define ZM_IOCTL_ENCRYPTION_MODE 0xA6 ++#define ZM_IOCTL_GET_TXCNT 0xA7 ++#define ZM_IOCTL_GET_DEAGG_CNT 0xA8 ++#define ZM_IOCTL_DURATION_MODE 0xA9 ++#define ZM_IOCTL_SET_AES_KEY 0xAA ++#define ZM_IOCTL_SET_AES_MODE 0xAB ++#define ZM_IOCTL_SIGNAL_STRENGTH 0xAC //CWYang(+) ++#define ZM_IOCTL_SIGNAL_QUALITY 0xAD //CWYang(+) ++#define ZM_IOCTL_SET_PIBSS_MODE 0xAE ++#define ZDAPIOCTL SIOCDEVPRIVATE ++ ++struct zdap_ioctl { ++ unsigned short cmd; /* Command to run */ ++ unsigned int addr; /* Length of the data buffer */ ++ unsigned int value; /* Pointer to the data buffer */ ++ unsigned char data[0x100]; ++}; ++ ++/* Declaration of macro and function for handling WEP Keys */ ++ ++#if 0 ++ ++#define SKIP_ELEM { \ ++ while(isxdigit(*p)) \ ++ p++; \ ++} ++ ++#define SKIP_DELIMETER { \ ++ if(*p == ':' || *p == ' ') \ ++ p++; \ ++} ++ ++#endif ++ ++char hex(char); ++unsigned char asctohex(char *str); ++ ++char *prgname; ++ ++int set_ioctl(int sock, struct ifreq *req) ++{ ++ if (ioctl(sock, ZDAPIOCTL, req) < 0) { ++ fprintf(stderr, "%s: ioctl(SIOCGIFMAP): %s\n", ++ prgname, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++int read_reg(int sock, struct ifreq *req) ++{ ++ struct zdap_ioctl *zdreq = 0; ++ ++ if (!set_ioctl(sock, req)) ++ return -1; ++ ++ //zdreq = (struct zdap_ioctl *)req->ifr_data; ++ //printf( "reg = %4x, value = %4x\n", zdreq->addr, zdreq->value); ++ ++ return 0; ++} ++ ++ ++int read_mem(int sock, struct ifreq *req) ++{ ++ struct zdap_ioctl *zdreq = 0; ++ int i; ++ ++ if (!set_ioctl(sock, req)) ++ return -1; ++ ++ /*zdreq = (struct zdap_ioctl *)req->ifr_data; ++ printf( "dump mem from %x, length = %x\n", zdreq->addr, zdreq->value); ++ ++ for (i=0; ivalue; i++) { ++ printf("%02x", zdreq->data[i]); ++ printf(" "); ++ ++ if ((i>0) && ((i+1)%16 == 0)) ++ printf("\n"); ++ }*/ ++ ++ return 0; ++} ++ ++ ++int main(int argc, char **argv) ++{ ++ int sock; ++ int addr, value; ++ struct ifreq req; ++ char *action = NULL; ++ struct zdap_ioctl zdreq; ++ ++ prgname = argv[0]; ++ ++ if (argc < 3) { ++ fprintf(stderr,"%s: usage is \"%s [
] []\"\n", ++ prgname, prgname); ++ fprintf(stderr,"valid operation: read, write, mem, reg,\n"); ++ fprintf(stderr," : txd, rxd, rmem, wmem\n"); ++ fprintf(stderr," : dmat, regt, test\n"); ++ ++ fprintf(stderr," scan, Channel Scan\n"); ++ fprintf(stderr," rts , Set RTS Threshold\n"); ++ fprintf(stderr," frag , Set Fragment Threshold\n"); ++ fprintf(stderr," rate <0-28>, 0:AUTO, 1-4:CCK, 5-12:OFDM, 13-28:HT\n"); ++ fprintf(stderr," TBD mix <0 or 1>, Set 1 to enable mixed mode\n"); ++ fprintf(stderr," enc, <0-3>, 0=>OPEN, 1=>WEP64, 2=>WEP128, 3=>WEP256\n"); ++ fprintf(stderr," skey , Set WEP key\n"); ++ fprintf(stderr," txcnt, Get TxQ Cnt\n"); ++ fprintf(stderr," dagcnt, Get Deaggregate Cnt\n"); ++ fprintf(stderr," durmode , Set Duration Mode 0=>HW, 1=>SW\n"); ++ fprintf(stderr," aeskey \n"); ++ fprintf(stderr," aesmode \n"); ++ fprintf(stderr," wlanmode <0,1> 0:Station mode, 1:PIBSS mode\n"); ++ fprintf(stderr," tal <0,1>, Get Current Tally Info, 0=>read, 1=>read and reset\n"); ++ ++ exit(1); ++ } ++ ++ strcpy(req.ifr_name, argv[1]); ++ zdreq.addr = 0; ++ zdreq.value = 0; ++ ++ /* a silly raw socket just for ioctl()ling it */ ++ sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); ++ if (sock < 0) { ++ fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno)); ++ exit(1); ++ } ++ ++ if (argc >= 4) ++ { ++ sscanf(argv[3], "%x", &addr); ++ } ++ ++ if (argc >= 5) ++ { ++ sscanf(argv[4], "%x", &value); ++ } ++ ++ zdreq.addr = addr; ++ zdreq.value = value; ++ ++ if (!strcmp(argv[2], "read")) ++ { ++ zdreq.cmd = ZM_IOCTL_REG_READ; ++ } ++ else if (!strcmp(argv[2], "mem")) ++ { ++ zdreq.cmd = ZM_IOCTL_MEM_DUMP; ++ } ++ else if (!strcmp(argv[2], "write")) ++ { ++ zdreq.cmd = ZM_IOCTL_REG_WRITE; ++ } ++ else if (!strcmp(argv[2], "reg")) ++ { ++ zdreq.cmd = ZM_IOCTL_REG_DUMP; ++ } ++ else if (!strcmp(argv[2], "txd")) ++ { ++ zdreq.cmd = ZM_IOCTL_TXD_DUMP; ++ } ++ else if (!strcmp(argv[2], "rxd")) ++ { ++ zdreq.cmd = ZM_IOCTL_RXD_DUMP; ++ } ++ else if (!strcmp(argv[2], "rmem")) ++ { ++ zdreq.cmd = ZM_IOCTL_MEM_READ; ++ } ++ else if (!strcmp(argv[2], "wmem")) ++ { ++ zdreq.cmd = ZM_IOCTL_MEM_WRITE; ++ } ++ else if (!strcmp(argv[2], "dmat")) ++ { ++ zdreq.cmd = ZM_IOCTL_DMA_TEST; ++ } ++ else if (!strcmp(argv[2], "regt")) ++ { ++ zdreq.cmd = ZM_IOCTL_REG_TEST; ++ } ++ else if (!strcmp(argv[2], "test")) ++ { ++ zdreq.cmd = ZM_IOCTL_TEST; ++ } ++ else if (!strcmp(argv[2], "tal")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_TALLY; ++ } ++ else if (!strcmp(argv[2], "rts")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_RTS; ++ } ++ else if (!strcmp(argv[2], "mix")) ++ { ++ zdreq.cmd = ZM_IOCTL_MIX_MODE; ++ } ++ else if (!strcmp(argv[2], "frag")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_FRAG; ++ } ++ else if (!strcmp(argv[2], "scan")) ++ { ++ zdreq.cmd = ZM_IOCTL_SCAN; ++ } ++ else if (!strcmp(argv[2], "skey")) ++ { ++ zdreq.cmd = ZM_IOCTL_KEY; ++ ++ if (argc >= 4) ++ { ++ unsigned char temp[29]; ++ int i; ++ int keyLen; ++ int encType; ++ ++ keyLen = strlen(argv[3]); ++ ++ if (keyLen == 10) ++ { ++ sscanf(argv[3], "%02x%02x%02x%02x%02x", &temp[0], &temp[1], ++ &temp[2], &temp[3], &temp[4]); ++ } ++ else if (keyLen == 26) ++ { ++ sscanf(argv[3], "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", ++ &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], ++ &temp[5], &temp[6], &temp[7], &temp[8], &temp[9], ++ &temp[10], &temp[11], &temp[12]); ++ } ++ else if (keyLen == 58) ++ { ++ sscanf(argv[3], "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", ++ &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], ++ &temp[5], &temp[6], &temp[7], &temp[8], &temp[9], ++ &temp[10], &temp[11], &temp[12], &temp[13], &temp[14], ++ &temp[15], &temp[16], &temp[17], &temp[18], &temp[19], ++ &temp[20], &temp[21], &temp[22], &temp[23], &temp[24], ++ &temp[25], &temp[26], &temp[27], &temp[28]); ++ } ++ else ++ { ++ fprintf(stderr, "Invalid key length\n"); ++ exit(1); ++ } ++ zdreq.addr = keyLen/2; ++ ++ for(i=0; i 28) ++ { ++ fprintf(stderr, "Invalid rate, range:0~28\n"); ++ exit(1); ++ } ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_RATE; ++ } ++ else if (!strcmp(argv[2], "enc")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ ++ if (addr > 3) ++ { ++ fprintf(stderr, "Invalid encryption mode, range:0~3\n"); ++ exit(1); ++ } ++ ++ if (addr == 2) ++ { ++ addr = 5; ++ } ++ else if (addr == 3) ++ { ++ addr = 6; ++ } ++ ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_ENCRYPTION_MODE; ++ } ++ else if (!strcmp(argv[2], "txcnt")) ++ { ++ zdreq.cmd = ZM_IOCTL_GET_TXCNT; ++ } ++ else if (!strcmp(argv[2], "dagcnt")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ ++ if (addr != 0 && addr != 1) ++ { ++ fprintf(stderr, "The value should be 0 or 1\n"); ++ exit(0); ++ } ++ ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_GET_DEAGG_CNT; ++ } ++ else if (!strcmp(argv[2], "durmode")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ ++ if (addr != 0 && addr != 1) ++ { ++ fprintf(stderr, "The Duration mode should be 0 or 1\n"); ++ exit(0); ++ } ++ ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_DURATION_MODE; ++ } ++ else if (!strcmp(argv[2], "aeskey")) ++ { ++ unsigned char temp[16]; ++ int i; ++ ++ sscanf(argv[3], "%d", &addr); ++ ++ sscanf(argv[4], "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", &temp[0], &temp[1], &temp[2], &temp[3], &temp[4], &temp[5], &temp[6], &temp[7], &temp[8], &temp[9], &temp[10], &temp[11], &temp[12], &temp[13], &temp[14], &temp[15]); ++ ++ for(i = 0; i < 16; i++) ++ { ++ zdreq.data[i] = temp[i]; ++ } ++ ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_SET_AES_KEY; ++ } ++ else if (!strcmp(argv[2], "aesmode")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_SET_AES_MODE; ++ } ++ else if (!strcmp(argv[2], "wlanmode")) ++ { ++ sscanf(argv[3], "%d", &addr); ++ ++ zdreq.addr = addr; ++ zdreq.cmd = ZM_IOCTL_SET_PIBSS_MODE; ++ } ++ else ++ { ++ fprintf(stderr, "error action\n"); ++ exit(1); ++ } ++ ++ req.ifr_data = (char *)&zdreq; ++ set_ioctl(sock, &req); ++ ++fail: ++ exit(0); ++} ++ ++unsigned char asctohex(char *str) ++{ ++ unsigned char value; ++ ++ value = hex(*str) & 0x0f; ++ value = value << 4; ++ str++; ++ value |= hex(*str) & 0x0f; ++ ++ return value; ++} ++ ++char hex(char v) ++{ ++ if(isdigit(v)) ++ return v - '0'; ++ else if(isxdigit(v)) ++ return (tolower(v) - 'a' + 10); ++ else ++ return 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/otus/athr_common.h +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : athr_common.h */ ++/* */ ++/* Abstract */ ++/* WPA related function and data structure definitions. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _ATHR_COMMON_H ++#define _ATHR_COMMON_H ++ ++#define ZD_IOCTL_WPA (SIOCDEVPRIVATE + 1) ++#define ZD_IOCTL_PARAM (SIOCDEVPRIVATE + 2) ++#define ZD_IOCTL_GETWPAIE (SIOCDEVPRIVATE + 3) ++#define ZD_PARAM_ROAMING 0x0001 ++#define ZD_PARAM_PRIVACY 0x0002 ++#define ZD_PARAM_WPA 0x0003 ++#define ZD_PARAM_COUNTERMEASURES 0x0004 ++#define ZD_PARAM_DROPUNENCRYPTED 0x0005 ++#define ZD_PARAM_AUTH_ALGS 0x0006 ++ ++#define ZD_CMD_SET_ENCRYPT_KEY 0x0001 ++#define ZD_CMD_SET_MLME 0x0002 ++#define ZD_CMD_SCAN_REQ 0x0003 ++#define ZD_CMD_SET_GENERIC_ELEMENT 0x0004 ++#define ZD_CMD_GET_TSC 0x0005 ++ ++#define ZD_FLAG_SET_TX_KEY 0x0001 ++ ++#define ZD_GENERIC_ELEMENT_HDR_LEN \ ++((int) (&((struct athr_wlan_param *) 0)->u.generic_elem.data)) ++ ++#define ZD_CRYPT_ALG_NAME_LEN 16 ++#define ZD_MAX_KEY_SIZE 32 ++#define ZD_MAX_GENERIC_SIZE 64 ++ ++#define IEEE80211_ADDR_LEN 6 ++#define IEEE80211_MAX_IE_SIZE 256 ++ ++#ifdef ZM_ENALBE_WAPI ++#define ZM_CMD_WAPI_SETWAPI 0x0001 ++#define ZM_CMD_WAPI_GETWAPI 0x0002 ++#define ZM_CMD_WAPI_SETKEY 0x0003 ++#define ZM_CMD_WAPI_GETKEY 0x0004 ++#define ZM_CMD_WAPI_REKEY 0x0005 ++ ++#define ZM_WAPI_WAI_REQUEST 0x00f1 ++#define ZM_WAPI_UNICAST_REKEY 0x00f2 ++#define ZM_WAPI_STA_AGING 0x00f3 ++#define ZM_WAPI_MULTI_REKEY 0x00f4 ++ ++#define ZM_WAPI_KEY_SIZE 32 ++#define ZM_WAPI_IV_LEN 16 ++#endif //ZM_ENALBE_WAPI ++/* structure definition */ ++ ++struct athr_wlan_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 alg[ZD_CRYPT_ALG_NAME_LEN]; ++ u32 flags; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[ZD_MAX_KEY_SIZE]; ++ } crypt; ++ struct { ++ u32 flags_and; ++ u32 flags_or; ++ } set_flags_sta; ++ struct { ++ u8 len; ++ u8 data[ZD_MAX_GENERIC_SIZE]; ++ } generic_elem; ++ struct { ++#define MLME_STA_DEAUTH 0 ++#define MLME_STA_DISASSOC 1 ++ u16 cmd; ++ u16 reason_code; ++ } mlme; ++ struct { ++ u8 ssid_len; ++ u8 ssid[32]; ++ } scan_req; ++ } u; ++}; ++ ++struct ieee80211req_wpaie { ++ u8 wpa_macaddr[IEEE80211_ADDR_LEN]; ++ u8 wpa_ie[IEEE80211_MAX_IE_SIZE]; ++}; ++ ++#ifdef ZM_ENALBE_WAPI ++struct athr_wapi_param { ++ u16 cmd; ++ u16 len; ++ ++ union { ++ struct { ++ u8 sta_addr[ETH_ALEN]; ++ u8 reserved; ++ u8 keyid; ++ u8 key[ZM_WAPI_KEY_SIZE]; ++ } crypt; ++ struct { ++ u8 wapi_policy; ++ } info; ++ } u; ++}; ++ ++struct athr_wapi_sta_info ++{ ++ u16 msg_type; ++ u16 datalen; ++ u8 sta_mac[ETH_ALEN]; ++ u8 reserve_data[2]; ++ u8 gsn[ZM_WAPI_IV_LEN]; ++ u8 wie[256]; ++}; ++#endif //ZM_ENALBE_WAPI ++#endif +--- /dev/null ++++ b/drivers/staging/otus/hal/hpani.c +@@ -0,0 +1,732 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++#include "hpani.h" ++#include "hpusb.h" ++ ++ ++extern u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val); ++extern u16_t zfFlushDelayWrite(zdev_t* dev); ++ ++/* ++ * Anti noise immunity support. We track phy errors and react ++ * to excessive errors by adjusting the noise immunity parameters. ++ */ ++ ++/****************************************************************************** ++ * ++ * New Ani Algorithm for Station side only ++ * ++ *****************************************************************************/ ++ ++#define ZM_HAL_NOISE_IMMUNE_MAX 4 /* Max noise immunity level */ ++#define ZM_HAL_SPUR_IMMUNE_MAX 7 /* Max spur immunity level */ ++#define ZM_HAL_FIRST_STEP_MAX 2 /* Max first step level */ ++ ++#define ZM_HAL_ANI_OFDM_TRIG_HIGH 500 ++#define ZM_HAL_ANI_OFDM_TRIG_LOW 200 ++#define ZM_HAL_ANI_CCK_TRIG_HIGH 200 ++#define ZM_HAL_ANI_CCK_TRIG_LOW 100 ++#define ZM_HAL_ANI_NOISE_IMMUNE_LVL 4 ++#define ZM_HAL_ANI_USE_OFDM_WEAK_SIG TRUE ++#define ZM_HAL_ANI_CCK_WEAK_SIG_THR FALSE ++#define ZM_HAL_ANI_SPUR_IMMUNE_LVL 7 ++#define ZM_HAL_ANI_FIRSTEP_LVL 0 ++#define ZM_HAL_ANI_RSSI_THR_HIGH 40 ++#define ZM_HAL_ANI_RSSI_THR_LOW 7 ++#define ZM_HAL_ANI_PERIOD 100 ++ ++#define ZM_HAL_EP_RND(x, mul) \ ++ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) ++ ++s32_t BEACON_RSSI(zdev_t* dev) ++{ ++ s32_t rssi; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ rssi = ZM_HAL_EP_RND(HpPriv->stats.ast_nodestats.ns_avgbrssi, ZM_HAL_RSSI_EP_MULTIPLIER); ++ ++ return rssi; ++} ++ ++/* ++ * Setup ANI handling. Sets all thresholds and levels to default level AND ++ * resets the channel statistics ++ */ ++ ++void zfHpAniAttach(zdev_t* dev) ++{ ++#define N(a) (sizeof(a) / sizeof(a[0])) ++ u32_t i; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; ++ const int coarseHigh[] = { -14, -14, -14, -14, -12 }; ++ const int coarseLow[] = { -64, -64, -64, -64, -70 }; ++ const int firpwr[] = { -78, -78, -78, -78, -80 }; ++ ++ for (i = 0; i < 5; i++) ++ { ++ HpPriv->totalSizeDesired[i] = totalSizeDesired[i]; ++ HpPriv->coarseHigh[i] = coarseHigh[i]; ++ HpPriv->coarseLow[i] = coarseLow[i]; ++ HpPriv->firpwr[i] = firpwr[i]; ++ } ++ ++ /* owl has phy counters */ ++ HpPriv->hasHwPhyCounters = 1; ++ ++ memset((char *)&HpPriv->ani, 0, sizeof(HpPriv->ani)); ++ for (i = 0; i < N(wd->regulationTable.allowChannel); i++) ++ { ++ /* New ANI stuff */ ++ HpPriv->ani[i].ofdmTrigHigh = ZM_HAL_ANI_OFDM_TRIG_HIGH; ++ HpPriv->ani[i].ofdmTrigLow = ZM_HAL_ANI_OFDM_TRIG_LOW; ++ HpPriv->ani[i].cckTrigHigh = ZM_HAL_ANI_CCK_TRIG_HIGH; ++ HpPriv->ani[i].cckTrigLow = ZM_HAL_ANI_CCK_TRIG_LOW; ++ HpPriv->ani[i].rssiThrHigh = ZM_HAL_ANI_RSSI_THR_HIGH; ++ HpPriv->ani[i].rssiThrLow = ZM_HAL_ANI_RSSI_THR_LOW; ++ HpPriv->ani[i].ofdmWeakSigDetectOff = !ZM_HAL_ANI_USE_OFDM_WEAK_SIG; ++ HpPriv->ani[i].cckWeakSigThreshold = ZM_HAL_ANI_CCK_WEAK_SIG_THR; ++ HpPriv->ani[i].spurImmunityLevel = ZM_HAL_ANI_SPUR_IMMUNE_LVL; ++ HpPriv->ani[i].firstepLevel = ZM_HAL_ANI_FIRSTEP_LVL; ++ if (HpPriv->hasHwPhyCounters) ++ { ++ HpPriv->ani[i].ofdmPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_OFDM_TRIG_HIGH; ++ HpPriv->ani[i].cckPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_CCK_TRIG_HIGH; ++ } ++ } ++ if (HpPriv->hasHwPhyCounters) ++ { ++ //zm_debug_msg2("Setting OfdmErrBase = 0x", HpPriv->ani[0].ofdmPhyErrBase); ++ //zm_debug_msg2("Setting cckErrBase = 0x", HpPriv->ani[0].cckPhyErrBase); ++ //OS_REG_WRITE(ah, AR_PHY_ERR_1, HpPriv->ani[0].ofdmPhyErrBase); ++ //OS_REG_WRITE(ah, AR_PHY_ERR_2, HpPriv->ani[0].cckPhyErrBase); ++ } ++ HpPriv->aniPeriod = ZM_HAL_ANI_PERIOD; ++ //if (ath_hal_enableANI) ++ HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI; ++ ++ HpPriv->stats.ast_nodestats.ns_avgbrssi = ZM_RSSI_DUMMY_MARKER; ++ HpPriv->stats.ast_nodestats.ns_avgrssi = ZM_RSSI_DUMMY_MARKER; ++ HpPriv->stats.ast_nodestats.ns_avgtxrssi = ZM_RSSI_DUMMY_MARKER; ++#undef N ++} ++ ++/* ++ * Control Adaptive Noise Immunity Parameters ++ */ ++u8_t zfHpAniControl(zdev_t* dev, ZM_HAL_ANI_CMD cmd, int param) ++{ ++#define N(a) (sizeof(a)/sizeof(a[0])) ++ typedef s32_t TABLE[]; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ struct zsAniState *aniState = HpPriv->curani; ++ ++ switch (cmd) ++ { ++ case ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL: ++ { ++ u32_t level = param; ++ ++ if (level >= N(HpPriv->totalSizeDesired)) ++ { ++ zm_debug_msg1("level out of range, desired level : ", level); ++ zm_debug_msg1("max level : ", N(HpPriv->totalSizeDesired)); ++ return FALSE; ++ } ++ ++ zfDelayWriteInternalReg(dev, AR_PHY_DESIRED_SZ, ++ (HpPriv->regPHYDesiredSZ & ~AR_PHY_DESIRED_SZ_TOT_DES) ++ | ((HpPriv->totalSizeDesired[level] << AR_PHY_DESIRED_SZ_TOT_DES_S) ++ & AR_PHY_DESIRED_SZ_TOT_DES)); ++ zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1, ++ (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_LOW) ++ | ((HpPriv->coarseLow[level] << AR_PHY_AGC_CTL1_COARSE_LOW_S) ++ & AR_PHY_AGC_CTL1_COARSE_LOW)); ++ zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1, ++ (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_HIGH) ++ | ((HpPriv->coarseHigh[level] << AR_PHY_AGC_CTL1_COARSE_HIGH_S) ++ & AR_PHY_AGC_CTL1_COARSE_HIGH)); ++ zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG, ++ (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRPWR) ++ | ((HpPriv->firpwr[level] << AR_PHY_FIND_SIG_FIRPWR_S) ++ & AR_PHY_FIND_SIG_FIRPWR)); ++ zfFlushDelayWrite(dev); ++ ++ if (level > aniState->noiseImmunityLevel) ++ HpPriv->stats.ast_ani_niup++; ++ else if (level < aniState->noiseImmunityLevel) ++ HpPriv->stats.ast_ani_nidown++; ++ aniState->noiseImmunityLevel = (u8_t)level; ++ break; ++ } ++ case ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: ++ { ++ const TABLE m1ThreshLow = { 127, 50 }; ++ const TABLE m2ThreshLow = { 127, 40 }; ++ const TABLE m1Thresh = { 127, 0x4d }; ++ const TABLE m2Thresh = { 127, 0x40 }; ++ const TABLE m2CountThr = { 31, 16 }; ++ const TABLE m2CountThrLow = { 63, 48 }; ++ u32_t on = param ? 1 : 0; ++ ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, ++ (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M1_THRESH_LOW) ++ | ((m1ThreshLow[on] << AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S) ++ & AR_PHY_SFCORR_LOW_M1_THRESH_LOW)); ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, ++ (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2_THRESH_LOW) ++ | ((m2ThreshLow[on] << AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S) ++ & AR_PHY_SFCORR_LOW_M2_THRESH_LOW)); ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, ++ (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M1_THRESH) ++ | ((m1Thresh[on] << AR_PHY_SFCORR_M1_THRESH_S) ++ & AR_PHY_SFCORR_M1_THRESH)); ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, ++ (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2_THRESH) ++ | ((m2Thresh[on] << AR_PHY_SFCORR_M2_THRESH_S) ++ & AR_PHY_SFCORR_M2_THRESH)); ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR, ++ (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2COUNT_THR) ++ | ((m2CountThr[on] << AR_PHY_SFCORR_M2COUNT_THR_S) ++ & AR_PHY_SFCORR_M2COUNT_THR)); ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, ++ (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW) ++ | ((m2CountThrLow[on] << AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S) ++ & AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW)); ++ ++ if (on) ++ { ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, ++ HpPriv->regPHYSfcorrLow | AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW, ++ HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); ++ } ++ zfFlushDelayWrite(dev); ++ if (!on != aniState->ofdmWeakSigDetectOff) ++ { ++ if (on) ++ HpPriv->stats.ast_ani_ofdmon++; ++ else ++ HpPriv->stats.ast_ani_ofdmoff++; ++ aniState->ofdmWeakSigDetectOff = !on; ++ } ++ break; ++ } ++ case ZM_HAL_ANI_CCK_WEAK_SIGNAL_THR: ++ { ++ const TABLE weakSigThrCck = { 8, 6 }; ++ u32_t high = param ? 1 : 0; ++ ++ zfDelayWriteInternalReg(dev, AR_PHY_CCK_DETECT, ++ (HpPriv->regPHYCckDetect & ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK) ++ | ((weakSigThrCck[high] << AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S) ++ & AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK)); ++ zfFlushDelayWrite(dev); ++ if (high != aniState->cckWeakSigThreshold) ++ { ++ if (high) ++ HpPriv->stats.ast_ani_cckhigh++; ++ else ++ HpPriv->stats.ast_ani_ccklow++; ++ aniState->cckWeakSigThreshold = (u8_t)high; ++ } ++ break; ++ } ++ case ZM_HAL_ANI_FIRSTEP_LEVEL: ++ { ++ const TABLE firstep = { 0, 4, 8 }; ++ u32_t level = param; ++ ++ if (level >= N(firstep)) ++ { ++ zm_debug_msg1("level out of range, desired level : ", level); ++ zm_debug_msg1("max level : ", N(firstep)); ++ return FALSE; ++ } ++ zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG, ++ (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRSTEP) ++ | ((firstep[level] << AR_PHY_FIND_SIG_FIRSTEP_S) ++ & AR_PHY_FIND_SIG_FIRSTEP)); ++ zfFlushDelayWrite(dev); ++ if (level > aniState->firstepLevel) ++ HpPriv->stats.ast_ani_stepup++; ++ else if (level < aniState->firstepLevel) ++ HpPriv->stats.ast_ani_stepdown++; ++ aniState->firstepLevel = (u8_t)level; ++ break; ++ } ++ case ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL: ++ { ++ const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 }; ++ u32_t level = param; ++ ++ if (level >= N(cycpwrThr1)) ++ { ++ zm_debug_msg1("level out of range, desired level : ", level); ++ zm_debug_msg1("max level : ", N(cycpwrThr1)); ++ return FALSE; ++ } ++ zfDelayWriteInternalReg(dev, AR_PHY_TIMING5, ++ (HpPriv->regPHYTiming5 & ~AR_PHY_TIMING5_CYCPWR_THR1) ++ | ((cycpwrThr1[level] << AR_PHY_TIMING5_CYCPWR_THR1_S) ++ & AR_PHY_TIMING5_CYCPWR_THR1)); ++ zfFlushDelayWrite(dev); ++ if (level > aniState->spurImmunityLevel) ++ HpPriv->stats.ast_ani_spurup++; ++ else if (level < aniState->spurImmunityLevel) ++ HpPriv->stats.ast_ani_spurdown++; ++ aniState->spurImmunityLevel = (u8_t)level; ++ break; ++ } ++ case ZM_HAL_ANI_PRESENT: ++ break; ++#ifdef AH_PRIVATE_DIAG ++ case ZM_HAL_ANI_MODE: ++ if (param == 0) ++ { ++ HpPriv->procPhyErr &= ~ZM_HAL_PROCESS_ANI; ++ /* Turn off HW counters if we have them */ ++ zfHpAniDetach(dev); ++ //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR); ++ } ++ else ++ { /* normal/auto mode */ ++ HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI; ++ if (HpPriv->hasHwPhyCounters) ++ { ++ //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR); ++ } ++ else ++ { ++ //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) | HAL_RX_FILTER_PHYERR); ++ } ++ } ++ break; ++ case ZM_HAL_ANI_PHYERR_RESET: ++ HpPriv->stats.ast_ani_ofdmerrs = 0; ++ HpPriv->stats.ast_ani_cckerrs = 0; ++ break; ++#endif /* AH_PRIVATE_DIAG */ ++ default: ++ zm_debug_msg1("invalid cmd ", cmd); ++ return FALSE; ++ } ++ return TRUE; ++#undef N ++} ++ ++void zfHpAniRestart(zdev_t* dev) ++{ ++ struct zsAniState *aniState; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ aniState = HpPriv->curani; ++ ++ aniState->listenTime = 0; ++ if (HpPriv->hasHwPhyCounters) ++ { ++ //if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) ++ //{ ++ // aniState->ofdmPhyErrBase = 0; ++ // zm_debug_msg0("OFDM Trigger is too high for hw counters"); ++ //} ++ //else ++ // aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; ++ //if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) ++ //{ ++ // aniState->cckPhyErrBase = 0; ++ // zm_debug_msg0("CCK Trigger is too high for hw counters"); ++ //} ++ //else ++ // aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh; ++ //zm_debug_msg2("Writing ofdmbase = 0x", aniState->ofdmPhyErrBase); ++ //zm_debug_msg2("Writing cckbase = 0x", aniState->cckPhyErrBase); ++ //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); ++ //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); ++ //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); ++ //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); ++ aniState->ofdmPhyErrBase = 0; ++ aniState->cckPhyErrBase = 0; ++ } ++ aniState->ofdmPhyErrCount = 0; ++ aniState->cckPhyErrCount = 0; ++} ++ ++void zfHpAniOfdmErrTrigger(zdev_t* dev) ++{ ++ struct zsAniState *aniState; ++ s32_t rssi; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ //HALASSERT(chan != NULL); ++ ++ if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) ++ return; ++ ++ aniState = HpPriv->curani; ++ /* First, raise noise immunity level, up to max */ ++ if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1); ++ return; ++ } ++ /* then, raise spur immunity level, up to max */ ++ if (aniState->spurImmunityLevel < ZM_HAL_SPUR_IMMUNE_MAX) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1); ++ return; ++ } ++ rssi = BEACON_RSSI(dev); ++ if (rssi > aniState->rssiThrHigh) ++ { ++ /* ++ * Beacon rssi is high, can turn off ofdm weak sig detect. ++ */ ++ if (!aniState->ofdmWeakSigDetectOff) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE); ++ zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, 0); ++ return; ++ } ++ /* ++ * If weak sig detect is already off, as last resort, raise ++ * first step level ++ */ ++ if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); ++ return; ++ } ++ } ++ else if (rssi > aniState->rssiThrLow) ++ { ++ /* ++ * Beacon rssi in mid range, need ofdm weak signal detect, ++ * but we can raise firststepLevel ++ */ ++ if (aniState->ofdmWeakSigDetectOff) ++ zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE); ++ if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); ++ return; ++ } ++ else ++ { ++ /* ++ * Beacon rssi is low, if in 11b/g mode, turn off ofdm ++ * weak sign detction and zero firstepLevel to maximize ++ * CCK sensitivity ++ */ ++ if (wd->frequency < 3000) ++ { ++ if (!aniState->ofdmWeakSigDetectOff) ++ zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE); ++ if (aniState->firstepLevel > 0) ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0); ++ return; ++ } ++ } ++} ++ ++void zfHpAniCckErrTrigger(zdev_t* dev) ++{ ++ struct zsAniState *aniState; ++ s32_t rssi; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ //HALASSERT(chan != NULL); ++ ++ if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) ++ return; ++ ++ /* first, raise noise immunity level, up to max */ ++ aniState = HpPriv->curani; ++ if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, ++ aniState->noiseImmunityLevel + 1); ++ return; ++ } ++ rssi = BEACON_RSSI(dev); ++ if (rssi > aniState->rssiThrLow) ++ { ++ /* ++ * Beacon signal in mid and high range, raise firsteplevel. ++ */ ++ if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX) ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); ++ } ++ else ++ { ++ /* ++ * Beacon rssi is low, zero firstepLevel to maximize ++ * CCK sensitivity. ++ */ ++ if (wd->frequency < 3000) ++ { ++ if (aniState->firstepLevel > 0) ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0); ++ } ++ } ++} ++ ++void zfHpAniLowerImmunity(zdev_t* dev) ++{ ++ struct zsAniState *aniState; ++ s32_t rssi; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ aniState = HpPriv->curani; ++ ++ rssi = BEACON_RSSI(dev); ++ if (rssi > aniState->rssiThrHigh) ++ { ++ /* ++ * Beacon signal is high, leave ofdm weak signal detection off ++ * or it may oscillate. Let it fall through. ++ */ ++ } ++ else if (rssi > aniState->rssiThrLow) ++ { ++ /* ++ * Beacon rssi in mid range, turn on ofdm weak signal ++ * detection or lower first step level. ++ */ ++ if (aniState->ofdmWeakSigDetectOff) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE); ++ return; ++ } ++ if (aniState->firstepLevel > 0) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); ++ return; ++ } ++ } ++ else ++ { ++ /* ++ * Beacon rssi is low, reduce first step level. ++ */ ++ if (aniState->firstepLevel > 0) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1); ++ return; ++ } ++ } ++ /* then lower spur immunity level, down to zero */ ++ if (aniState->spurImmunityLevel > 0) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel - 1); ++ return; ++ } ++ /* ++ * if all else fails, lower noise immunity level down to a min value ++ * zero for now ++ */ ++ if (aniState->noiseImmunityLevel > 0) ++ { ++ zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel - 1); ++ return; ++ } ++} ++ ++#define CLOCK_RATE 44000 /* XXX use mac_usec or similar */ ++/* convert HW counter values to ms using 11g clock rate, goo9d enough ++ for 11a and Turbo */ ++ ++/* ++ * Return an approximation of the time spent ``listening'' by ++ * deducting the cycles spent tx'ing and rx'ing from the total ++ * cycle count since our last call. A return value <0 indicates ++ * an invalid/inconsistent time. ++ */ ++s32_t zfHpAniGetListenTime(zdev_t* dev) ++{ ++ struct zsAniState *aniState; ++ u32_t txFrameCount, rxFrameCount, cycleCount; ++ s32_t listenTime; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ txFrameCount = 0;//OS_REG_READ(ah, AR_TFCNT); ++ rxFrameCount = 0;//OS_REG_READ(ah, AR_RFCNT); ++ cycleCount = 0;//OS_REG_READ(ah, AR_CCCNT); ++ ++ aniState = HpPriv->curani; ++ if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) ++ { ++ /* ++ * Cycle counter wrap (or initial call); it's not possible ++ * to accurately calculate a value because the registers ++ * right shift rather than wrap--so punt and return 0. ++ */ ++ listenTime = 0; ++ HpPriv->stats.ast_ani_lzero++; ++ } ++ else ++ { ++ s32_t ccdelta = cycleCount - aniState->cycleCount; ++ s32_t rfdelta = rxFrameCount - aniState->rxFrameCount; ++ s32_t tfdelta = txFrameCount - aniState->txFrameCount; ++ listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE; ++ } ++ aniState->cycleCount = cycleCount; ++ aniState->txFrameCount = txFrameCount; ++ aniState->rxFrameCount = rxFrameCount; ++ return listenTime; ++} ++ ++/* ++ * Do periodic processing. This routine is called from the ++ * driver's rx interrupt handler after processing frames. ++ */ ++void zfHpAniArPoll(zdev_t* dev, u32_t listenTime, u32_t phyCnt1, u32_t phyCnt2) ++{ ++ struct zsAniState *aniState; ++ //s32_t listenTime; ++ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++ /* ++ * Since we're called from end of rx tasklet, we also check for ++ * AR processing now ++ */ ++ ++ aniState = HpPriv->curani; ++ //HpPriv->stats.ast_nodestats = *stats; /* XXX optimize? */ ++ ++ //listenTime = zfHpAniGetListenTime(dev); ++ //if (listenTime < 0) ++ //{ ++ // HpPriv->stats.ast_ani_lneg++; ++ // /* restart ANI period if listenTime is invalid */ ++ // zfHpAniRestart(dev); ++ // return; ++ //} ++ /* XXX beware of overflow? */ ++ aniState->listenTime += listenTime; ++ ++ if (HpPriv->hasHwPhyCounters) ++ { ++ //u32_t phyCnt1, phyCnt2; ++ u32_t ofdmPhyErrCnt, cckPhyErrCnt; ++ ++ /* NB: these are not reset-on-read */ ++ //phyCnt1 = 0;//OS_REG_READ(ah, AR_PHY_ERR_1); ++ //phyCnt2 = 0;//OS_REG_READ(ah, AR_PHY_ERR_2); ++ /* XXX sometimes zero, why? */ ++ //if (phyCnt1 < aniState->ofdmPhyErrBase || ++ // phyCnt2 < aniState->cckPhyErrBase) ++ //{ ++ // if (phyCnt1 < aniState->ofdmPhyErrBase) ++ // { ++ // zm_debug_msg2("phyCnt1 = 0x", phyCnt1); ++ // zm_debug_msg2("resetting counter value to 0x", aniState->ofdmPhyErrBase); ++ // //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); ++ // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); ++ // } ++ // if (phyCnt2 < aniState->cckPhyErrBase) ++ // { ++ // zm_debug_msg2("phyCnt2 = 0x", phyCnt2); ++ // zm_debug_msg2("resetting counter value to 0x", aniState->cckPhyErrBase); ++ // //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); ++ // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); ++ // } ++ // return; /* XXX */ ++ //} ++ /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ++ //ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; ++ //HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount; ++ //aniState->ofdmPhyErrCount = ofdmPhyErrCnt; ++ ofdmPhyErrCnt = phyCnt1; ++ HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt; ++ aniState->ofdmPhyErrCount += ofdmPhyErrCnt; ++ ++ //cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; ++ //HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount; ++ //aniState->cckPhyErrCount = cckPhyErrCnt; ++ cckPhyErrCnt = phyCnt2; ++ HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt; ++ aniState->cckPhyErrCount += cckPhyErrCnt; ++ } ++ /* ++ * If ani is not enabled, return after we've collected ++ * statistics ++ */ ++ if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0) ++ return; ++ if (aniState->listenTime > 5 * HpPriv->aniPeriod) ++ { ++ /* ++ * Check to see if need to lower immunity if ++ * 5 aniPeriods have passed ++ */ ++ if (aniState->ofdmPhyErrCount <= aniState->listenTime * ++ aniState->ofdmTrigLow/1000 && ++ aniState->cckPhyErrCount <= aniState->listenTime * ++ aniState->cckTrigLow/1000) ++ zfHpAniLowerImmunity(dev); ++ zfHpAniRestart(dev); ++ } ++ else if (aniState->listenTime > HpPriv->aniPeriod) ++ { ++ /* check to see if need to raise immunity */ ++ if (aniState->ofdmPhyErrCount > aniState->listenTime * ++ aniState->ofdmTrigHigh / 1000) ++ { ++ zfHpAniOfdmErrTrigger(dev); ++ zfHpAniRestart(dev); ++ } ++ else if (aniState->cckPhyErrCount > aniState->listenTime * ++ aniState->cckTrigHigh / 1000) ++ { ++ zfHpAniCckErrTrigger(dev); ++ zfHpAniRestart(dev); ++ } ++ } ++} +--- /dev/null ++++ b/drivers/staging/otus/hal/hpani.h +@@ -0,0 +1,420 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++ ++typedef struct { ++ u32_t ackrcv_bad; ++ u32_t rts_bad; ++ u32_t rts_good; ++ u32_t fcs_bad; ++ u32_t beacons; ++} ZM_HAL_MIB_STATS; ++ ++/* ++ * Per-node statistics maintained by the driver for use in ++ * optimizing signal quality and other operational aspects. ++ */ ++typedef struct { ++ u32_t ns_avgbrssi; /* average beacon rssi */ ++ u32_t ns_avgrssi; /* average data rssi */ ++ u32_t ns_avgtxrssi; /* average tx rssi */ ++} ZM_HAL_NODE_STATS; ++ ++#define ZM_HAL_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */ ++ ++struct zsAniStats { ++ u32_t ast_ani_niup; /* ANI increased noise immunity */ ++ u32_t ast_ani_nidown; /* ANI decreased noise immunity */ ++ u32_t ast_ani_spurup; /* ANI increased spur immunity */ ++ u32_t ast_ani_spurdown;/* ANI descreased spur immunity */ ++ u32_t ast_ani_ofdmon; /* ANI OFDM weak signal detect on */ ++ u32_t ast_ani_ofdmoff;/* ANI OFDM weak signal detect off */ ++ u32_t ast_ani_cckhigh;/* ANI CCK weak signal threshold high */ ++ u32_t ast_ani_ccklow; /* ANI CCK weak signal threshold low */ ++ u32_t ast_ani_stepup; /* ANI increased first step level */ ++ u32_t ast_ani_stepdown;/* ANI decreased first step level */ ++ u32_t ast_ani_ofdmerrs;/* ANI cumulative ofdm phy err count */ ++ u32_t ast_ani_cckerrs;/* ANI cumulative cck phy err count */ ++ u32_t ast_ani_reset; /* ANI parameters zero'd for non-STA */ ++ u32_t ast_ani_lzero; /* ANI listen time forced to zero */ ++ u32_t ast_ani_lneg; /* ANI listen time calculated < 0 */ ++ ZM_HAL_MIB_STATS ast_mibstats; /* MIB counter stats */ ++ ZM_HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */ ++}; ++ ++/* ++ * Per-channel ANI state private to the driver. ++ */ ++struct zsAniState { ++ ZM_HAL_CHANNEL c; ++ u8_t noiseImmunityLevel; ++ u8_t spurImmunityLevel; ++ u8_t firstepLevel; ++ u8_t ofdmWeakSigDetectOff; ++ u8_t cckWeakSigThreshold; ++ ++ /* Thresholds */ ++ u32_t listenTime; ++ u32_t ofdmTrigHigh; ++ u32_t ofdmTrigLow; ++ s32_t cckTrigHigh; ++ s32_t cckTrigLow; ++ s32_t rssiThrLow; ++ s32_t rssiThrHigh; ++ ++ u32_t noiseFloor; /* The current noise floor */ ++ u32_t txFrameCount; /* Last txFrameCount */ ++ u32_t rxFrameCount; /* Last rx Frame count */ ++ u32_t cycleCount; /* Last cycleCount (can detect wrap-around) */ ++ u32_t ofdmPhyErrCount;/* OFDM err count since last reset */ ++ u32_t cckPhyErrCount; /* CCK err count since last reset */ ++ u32_t ofdmPhyErrBase; /* Base value for ofdm err counter */ ++ u32_t cckPhyErrBase; /* Base value for cck err counters */ ++ s16_t pktRssi[2]; /* Average rssi of pkts for 2 antennas */ ++ s16_t ofdmErrRssi[2]; /* Average rssi of ofdm phy errs for 2 ant */ ++ s16_t cckErrRssi[2]; /* Average rssi of cck phy errs for 2 ant */ ++}; ++ ++typedef enum { ++ ZM_HAL_ANI_PRESENT, /* is ANI support present */ ++ ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, /* set level */ ++ ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, /* enable/disable */ ++ ZM_HAL_ANI_CCK_WEAK_SIGNAL_THR, /* enable/disable */ ++ ZM_HAL_ANI_FIRSTEP_LEVEL, /* set level */ ++ ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, /* set level */ ++ ZM_HAL_ANI_MODE, /* 0 => manual, 1 => auto */ ++ ZM_HAL_ANI_PHYERR_RESET, /* reset phy error stats */ ++} ZM_HAL_ANI_CMD; ++ ++#define AR_PHY_COUNTMAX (3 << 22) // Max counted before intr ++#define ZM_HAL_PROCESS_ANI 0x00000001 /* ANI state setup */ ++#define ZM_RSSI_DUMMY_MARKER 0x127 ++ ++/* PHY registers in ar5416, related base and register offsets ++ may need to be changed in otus BB */ ++#define AR_PHY_BASE 0x1C5800 /* base address of phy regs */ ++#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) ++ ++#define AR_PHY_TEST 0x1C5800 /* PHY test control */ ++#define PHY_AGC_CLR 0x10000000 /* disable AGC to A2 */ ++#define RFSILENT_BB 0x00002000 /* shush bb */ ++ ++#define AR_PHY_TURBO 0x1C5804 /* frame control register */ ++#define AR_PHY_FC_TURBO_MODE 0x00000001 /* Set turbo mode bits */ ++#define AR_PHY_FC_TURBO_SHORT 0x00000002 /* Set short symbols to turbo mode setting */ ++#define AR_PHY_FC_DYN2040_EN 0x00000004 /* Enable dyn 20/40 mode */ ++#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008 /* dyn 20/40 - primary only */ ++#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010 /* dyn 20/40 - primary ch offset (0=+10MHz, 1=-10MHz)*/ ++#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020 /* dyn 20/40 - ext ch spacing (0=20MHz/ 1=25MHz) */ ++#define AR_PHY_FC_HT_EN 0x00000040 /* ht enable */ ++#define AR_PHY_FC_SHORT_GI_40 0x00000080 /* allow short GI for HT 40 */ ++#define AR_PHY_FC_WALSH 0x00000100 /* walsh spatial spreading for 2 chains,2 streams TX */ ++#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 /* single length (4us) 1st HT long training symbol */ ++ ++#define AR_PHY_TIMING2 0x1C5810 /* Timing Control 2 */ ++#define AR_PHY_TIMING2_USE_FORCE 0x00001000 ++#define AR_PHY_TIMING2_FORCE_VAL 0x00000fff ++ ++#define AR_PHY_TIMING3 0x1C5814 /* Timing control 3 */ ++#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 ++#define AR_PHY_TIMING3_DSC_MAN_S 17 ++#define AR_PHY_TIMING3_DSC_EXP 0x0001E000 ++#define AR_PHY_TIMING3_DSC_EXP_S 13 ++ ++#define AR_PHY_CHIP_ID 0x1C5818 /* PHY chip revision ID */ ++#define AR_PHY_CHIP_ID_REV_0 0x80 /* 5416 Rev 0 (owl 1.0) BB */ ++#define AR_PHY_CHIP_ID_REV_1 0x81 /* 5416 Rev 1 (owl 2.0) BB */ ++ ++#define AR_PHY_ACTIVE 0x1C581C /* activation register */ ++#define AR_PHY_ACTIVE_EN 0x00000001 /* Activate PHY chips */ ++#define AR_PHY_ACTIVE_DIS 0x00000000 /* Deactivate PHY chips */ ++ ++#define AR_PHY_RF_CTL2 0x1C5824 ++#define AR_PHY_TX_END_DATA_START 0x000000FF ++#define AR_PHY_TX_END_DATA_START_S 0 ++#define AR_PHY_TX_END_PA_ON 0x0000FF00 ++#define AR_PHY_TX_END_PA_ON_S 8 ++ ++ ++#define AR_PHY_RF_CTL3 0x1C5828 ++#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000 ++#define AR_PHY_TX_END_TO_A2_RX_ON_S 16 ++ ++#define AR_PHY_ADC_CTL 0x1C582C ++#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003 ++#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0 ++#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000 ++#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000 /* BB Rev 4.2+ only */ ++#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000 /* BB Rev 4.2+ only */ ++#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000 ++#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16 ++ ++#define AR_PHY_ADC_SERIAL_CTL 0x1C5830 ++#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000 ++#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001 ++ ++#define AR_PHY_RF_CTL4 0x1C5834 ++#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000 ++#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24 ++#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000 ++#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16 ++#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00 ++#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8 ++#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF ++#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 ++ ++#define AR_PHY_SETTLING 0x1C5844 ++#define AR_PHY_SETTLING_SWITCH 0x00003F80 ++#define AR_PHY_SETTLING_SWITCH_S 7 ++ ++#define AR_PHY_RXGAIN 0x1C5848 ++#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000 ++#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12 ++#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000 ++#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18 ++ ++#define AR_PHY_DESIRED_SZ 0x1C5850 ++#define AR_PHY_DESIRED_SZ_ADC 0x000000FF ++#define AR_PHY_DESIRED_SZ_ADC_S 0 ++#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00 ++#define AR_PHY_DESIRED_SZ_PGA_S 8 ++#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000 ++#define AR_PHY_DESIRED_SZ_TOT_DES_S 20 ++ ++#define AR_PHY_FIND_SIG 0x1C5858 ++#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000 ++#define AR_PHY_FIND_SIG_FIRSTEP_S 12 ++#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000 ++#define AR_PHY_FIND_SIG_FIRPWR_S 18 ++ ++#define AR_PHY_AGC_CTL1 0x1C585C ++#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80 ++#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7 ++#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000 ++#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15 ++ ++#define AR_PHY_AGC_CONTROL 0x1C5860 /* chip calibration and noise floor setting */ ++#define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* do internal calibration */ ++#define AR_PHY_AGC_CONTROL_NF 0x00000002 /* do noise-floor calculation */ ++ ++#define AR_PHY_CCA 0x1C5864 ++#define AR_PHY_MINCCA_PWR 0x1FF00000 ++#define AR_PHY_MINCCA_PWR_S 19 ++#define AR_PHY_CCA_THRESH62 0x0007F000 ++#define AR_PHY_CCA_THRESH62_S 12 ++ ++#define AR_PHY_SFCORR_LOW 0x1C586C ++#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001 ++#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00 ++#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8 ++#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000 ++#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14 ++#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000 ++#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21 ++ ++#define AR_PHY_SFCORR 0x1C5868 ++#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F ++#define AR_PHY_SFCORR_M2COUNT_THR_S 0 ++#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000 ++#define AR_PHY_SFCORR_M1_THRESH_S 17 ++#define AR_PHY_SFCORR_M2_THRESH 0x7F000000 ++#define AR_PHY_SFCORR_M2_THRESH_S 24 ++ ++#define AR_PHY_SLEEP_CTR_CONTROL 0x1C5870 ++#define AR_PHY_SLEEP_CTR_LIMIT 0x1C5874 ++#define AR_PHY_SLEEP_SCAL 0x1C5878 ++ ++#define AR_PHY_PLL_CTL 0x1C587c /* PLL control register */ ++#define AR_PHY_PLL_CTL_40 0xaa /* 40 MHz */ ++#define AR_PHY_PLL_CTL_40_5413 0x04 ++#define AR_PHY_PLL_CTL_44 0xab /* 44 MHz for 11b, 11g */ ++#define AR_PHY_PLL_CTL_44_2133 0xeb /* 44 MHz for 11b, 11g */ ++#define AR_PHY_PLL_CTL_40_2133 0xea /* 40 MHz for 11a, turbos */ ++ ++#define AR_PHY_RX_DELAY 0x1C5914 /* analog pow-on time (100ns) */ ++#define AR_PHY_RX_DELAY_DELAY 0x00003FFF /* delay from wakeup to rx ena */ ++ ++#define AR_PHY_TIMING_CTRL4 0x1C5920 /* timing control */ ++#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F /* Mask for kcos_theta-1 for q correction */ ++#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0 /* shift for Q_COFF */ ++#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0 /* Mask for sin_theta for i correction */ ++#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5 /* Shift for sin_theta for i correction */ ++#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800 /* enable IQ correction */ ++#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000 /* Mask for max number of samples (logarithmic) */ ++#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12 /* Shift for max number of samples */ ++#define AR_PHY_TIMING_CTRL4_DO_IQCAL 0x10000 /* perform IQ calibration */ ++ ++#define AR_PHY_TIMING5 0x1C5924 ++#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE ++#define AR_PHY_TIMING5_CYCPWR_THR1_S 1 ++ ++#define AR_PHY_POWER_TX_RATE1 0x1C5934 ++#define AR_PHY_POWER_TX_RATE2 0x1C5938 ++#define AR_PHY_POWER_TX_RATE_MAX 0x1C593c ++#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 ++ ++#define AR_PHY_FRAME_CTL 0x1C5944 ++#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038 ++#define AR_PHY_FRAME_CTL_TX_CLIP_S 3 ++ ++#define AR_PHY_TXPWRADJ 0x1C594C /* BB Rev 4.2+ only */ ++#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0 ++#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6 ++#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000 ++#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18 ++ ++#define AR_PHY_RADAR_0 0x1C5954 /* radar detection settings */ ++#define AR_PHY_RADAR_0_ENA 0x00000001 /* Enable radar detection */ ++#define AR_PHY_RADAR_0_INBAND 0x0000003e /* Inband pulse threshold */ ++#define AR_PHY_RADAR_0_INBAND_S 1 ++#define AR_PHY_RADAR_0_PRSSI 0x00000FC0 /* Pulse rssi threshold */ ++#define AR_PHY_RADAR_0_PRSSI_S 6 ++#define AR_PHY_RADAR_0_HEIGHT 0x0003F000 /* Pulse height threshold */ ++#define AR_PHY_RADAR_0_HEIGHT_S 12 ++#define AR_PHY_RADAR_0_RRSSI 0x00FC0000 /* Radar rssi threshold */ ++#define AR_PHY_RADAR_0_RRSSI_S 18 ++#define AR_PHY_RADAR_0_FIRPWR 0x7F000000 /* Radar firpwr threshold */ ++#define AR_PHY_RADAR_0_FIRPWR_S 24 ++ ++#define AR_PHY_SWITCH_CHAIN_0 0x1C5960 ++#define AR_PHY_SWITCH_COM 0x1C5964 ++ ++#define AR_PHY_SIGMA_DELTA 0x1C596C /* AR5312 only */ ++#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003 ++#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0 ++#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8 ++#define AR_PHY_SIGMA_DELTA_FILT2_S 3 ++#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00 ++#define AR_PHY_SIGMA_DELTA_FILT1_S 8 ++#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000 ++#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13 ++ ++#define AR_PHY_RESTART 0x1C5970 /* restart */ ++#define AR_PHY_RESTART_DIV_GC 0x001C0000 /* bb_ant_fast_div_gc_limit */ ++#define AR_PHY_RESTART_DIV_GC_S 18 ++ ++#define AR_PHY_RFBUS_REQ 0x1C597C ++#define AR_PHY_RFBUS_REQ_EN 0x00000001 ++ ++#define AR_PHY_RX_CHAINMASK 0x1C59a4 ++ ++#define AR_PHY_EXT_CCA 0x1C59bc ++#define AR_PHY_EXT_MINCCA_PWR 0xFF800000 ++#define AR_PHY_EXT_MINCCA_PWR_S 23 ++ ++#define AR_PHY_HALFGI 0x1C59D0 /* Timing control 3 */ ++#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0 ++#define AR_PHY_HALFGI_DSC_MAN_S 4 ++#define AR_PHY_HALFGI_DSC_EXP 0x0000000F ++#define AR_PHY_HALFGI_DSC_EXP_S 0 ++ ++#define AR_PHY_HEAVY_CLIP_ENABLE 0x1C59E0 ++ ++#define AR_PHY_M_SLEEP 0x1C59f0 /* sleep control registers */ ++#define AR_PHY_REFCLKDLY 0x1C59f4 ++#define AR_PHY_REFCLKPD 0x1C59f8 ++ ++/* PHY IQ calibration results */ ++#define AR_PHY_IQCAL_RES_PWR_MEAS_I 0x1C5C10 /* power measurement for I */ ++#define AR_PHY_IQCAL_RES_PWR_MEAS_Q 0x1C5C14 /* power measurement for Q */ ++#define AR_PHY_IQCAL_RES_IQ_CORR_MEAS 0x1C5C18 /* IQ correlation measurement */ ++ ++#define AR_PHY_CURRENT_RSSI 0x1C5C1c /* rssi of current frame rx'd */ ++ ++#define AR_PHY_RFBUS_GRANT 0x1C5C20 ++#define AR_PHY_RFBUS_GRANT_EN 0x00000001 ++ ++#define AR_PHY_MODE 0x1C6200 /* Mode register */ ++#define AR_PHY_MODE_AR2133 0x08 /* AR2133 */ ++#define AR_PHY_MODE_AR5111 0x00 /* AR5111/AR2111 */ ++#define AR_PHY_MODE_AR5112 0x08 /* AR5112*/ ++#define AR_PHY_MODE_DYNAMIC 0x04 /* dynamic CCK/OFDM mode */ ++#define AR_PHY_MODE_RF2GHZ 0x02 /* 2.4 GHz */ ++#define AR_PHY_MODE_RF5GHZ 0x00 /* 5 GHz */ ++#define AR_PHY_MODE_CCK 0x01 /* CCK */ ++#define AR_PHY_MODE_OFDM 0x00 /* OFDM */ ++ ++#define AR_PHY_CCK_TX_CTRL 0x1C6204 ++#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 ++ ++#define AR_PHY_CCK_DETECT 0x1C6208 ++#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F ++#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 ++#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 // [12:6] settling time for antenna switch ++#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6 ++#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000 ++ ++#define AR_PHY_GAIN_2GHZ 0x1C620C ++#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000 ++#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18 ++#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00 ++#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10 ++#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F ++#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0 ++ ++#define AR_PHY_CCK_RXCTRL4 0x1C621C ++#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000 ++#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19 ++ ++#define AR_PHY_DAG_CTRLCCK 0x1C6228 ++#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200 /* BB Rev 4.2+ only */ ++#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00 /* BB Rev 4.2+ only */ ++#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10 /* BB Rev 4.2+ only */ ++ ++#define AR_PHY_POWER_TX_RATE3 0x1C6234 ++#define AR_PHY_POWER_TX_RATE4 0x1C6238 ++ ++#define AR_PHY_SCRM_SEQ_XR 0x1C623C ++#define AR_PHY_HEADER_DETECT_XR 0x1C6240 ++#define AR_PHY_CHIRP_DETECTED_XR 0x1C6244 ++#define AR_PHY_BLUETOOTH 0x1C6254 ++ ++#define AR_PHY_TPCRG1 0x1C6258 /* ar2413 power control */ ++#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000 ++#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14 ++ ++#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000 ++#define AR_PHY_TPCRG1_PD_GAIN_1_S 16 ++#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000 ++#define AR_PHY_TPCRG1_PD_GAIN_2_S 18 ++#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 ++#define AR_PHY_TPCRG1_PD_GAIN_3_S 20 ++// ++ ++#define AR_PHY_ANALOG_SWAP 0xa268 ++#define AR_PHY_SWAP_ALT_CHAIN 0x00000040 ++ ++#define AR_PHY_TPCRG5 0x1C626C /* ar2413 power control */ ++#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F ++#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 ++#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 ++ ++#define AR_PHY_POWER_TX_RATE5 0x1C638C ++#define AR_PHY_POWER_TX_RATE6 0x1C6390 ++ ++#define AR_PHY_CAL_CHAINMASK 0x1C639C ++ ++#define AR_PHY_POWER_TX_SUB 0x1C63C8 ++#define AR_PHY_POWER_TX_RATE7 0x1C63CC ++#define AR_PHY_POWER_TX_RATE8 0x1C63D0 ++#define AR_PHY_POWER_TX_RATE9 0x1C63D4 +--- /dev/null ++++ b/drivers/staging/otus/hal/hpDKfwu.c +@@ -0,0 +1,832 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++ ++const u32_t zcDKFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE3E7FFC, 0xE114D73E, ++0x1E13D43E, 0x1E4C470B, 0x0009B017, 0x956EE600, ++0xC84060E2, 0x2F028F03, 0x8FF93652, 0xD4387601, ++0x4E0BDE38, 0xD4380009, 0x00094E0B, 0x4E0BD437, ++0x7F040009, 0xA0364F26, 0x4F226EF6, 0x410BD134, ++0xD4340009, 0x0009440B, 0x450BD533, 0xD7330009, ++0xD233E1FF, 0x2712611D, 0xD4325029, 0xE1FFCB01, ++0x1209E501, 0x12112212, 0xD52F2452, 0xD22F9740, ++0xE7002572, 0xD42FD12E, 0x2270D62F, 0x2172E201, ++0x26202420, 0xE4FFD62D, 0xE6002641, 0xE104D52C, ++0x6063666D, 0x626D7601, 0x32124000, 0x05458FF8, ++0x000B4F26, 0xEAC80009, 0xDB266AAC, 0xDD27DC26, ++0xD828DE27, 0x4C0BE901, 0x4D0B0009, 0x4E0B0009, ++0x60B20009, 0x89078801, 0x6242D423, 0x890332A6, ++0x6050D522, 0x8BEE8801, 0x2B92D41F, 0x26686642, ++0x480B89E9, 0xD51D0009, 0xAFE4E200, 0x27102520, ++0x00000FA0, 0x001C001C, 0x00200ED4, 0x0000B38E, ++0x00202F90, 0x00201356, 0x00202F9C, 0x00202FB4, ++0x00201314, 0x00201412, 0x00200EF8, 0x001C3510, ++0x001C3624, 0x001E212C, 0x00202F00, 0x00202A9C, ++0x00202F08, 0x00202F14, 0x00202F20, 0x00202F22, ++0x00202F26, 0x001C1028, 0x00201220, 0x0020294C, ++0x00201D10, 0x00201EC8, 0x00203220, 0x00202F24, ++0x2FB62F96, 0x2FD62FC6, 0x4F222FE6, 0xDE947F80, ++0x61E0E024, 0x0F14D493, 0x710161E3, 0xD7926210, ++0x470BE028, 0xD5910F24, 0x0009450B, 0x6D032008, ++0x1F0B8F11, 0xD48FDC8E, 0xDD8F67C0, 0x657C4D0B, ++0xDD8FD18E, 0x6B9C6910, 0x420862B3, 0x32B84208, ++0x3D2C4208, 0xE0281FDB, 0xE58004FC, 0x604C66E2, ++0x3050655C, 0x2D628F13, 0x01FCE024, 0x641CE500, ++0x625DDE84, 0x8B013243, 0x0009A39E, 0x6753655D, ++0x607037EC, 0x39DC6953, 0xAFF27501, 0x20088094, ++0xE0248B13, 0xE50001FC, 0xA009DE7A, 0x655D641C, ++0x32EC6253, 0x6C536B22, 0x3CDC67B2, 0x75041C71, ++0x3243625D, 0xA37F8BF3, 0x88012D10, 0xE0248B16, ++0xE40001FC, 0x671C2D40, 0x624DDE6E, 0x8B013273, ++0x0009A372, 0x6CE3644D, 0x7C046943, 0x39EC6B43, ++0x65923BCC, 0x74086DB2, 0x25D2AFEF, 0x8B198804, ++0x01FCE024, 0x2D70E700, 0x1FD86D1C, 0x627DDE61, ++0x8B0132D3, 0x0009A358, 0x6B73677D, 0x3BEC61E3, ++0x710464B2, 0x3C1C6C73, 0x694265C2, 0x29597708, ++0x2492AFED, 0x8B188805, 0x01FCE024, 0x2D40E400, ++0xDE54671C, 0x3273624D, 0xA33D8B01, 0x644D0009, ++0x6BE36D43, 0x65D23DEC, 0x61437B04, 0x6C1231BC, ++0x74086952, 0xAFED29CB, 0x88312592, 0xDE4A8B20, ++0x65E6DB4A, 0x61E6DC4A, 0x67E2D94A, 0x62E27E04, ++0x1FEC7EE8, 0x7E0464E2, 0x6EE21FED, 0x5BFD2BE0, ++0x60B27B04, 0xC9011FBE, 0x6BB22C00, 0x29B04B09, ++0xDC412F26, 0x66134C0B, 0xE2007F04, 0x2D20A30C, ++0x8B218830, 0xD939DE38, 0xE06465E6, 0x720462E3, ++0x672666E2, 0x6E23DC36, 0x62227EE8, 0x6BE261E6, ++0x29B01FEF, 0x7E040F16, 0xC90160E2, 0x6EE22C00, ++0x4E09DC30, 0x2F262CE0, 0xD130E068, 0x04FE410B, ++0xE2007F04, 0x2D20A2E8, 0x8B058833, 0x4E0BDE2C, ++0xE1000009, 0x2D10A2E0, 0x89018828, 0x0009A106, ++0xE143DE20, 0xE04062E1, 0x3217622D, 0x0FE68F04, ++0x6023E240, 0x262106FE, 0x8B013217, 0x0009A0EF, ++0x02FEE040, 0x8521E401, 0x8B013046, 0x0009A0E7, ++0xE501E040, 0x2D5007FE, 0x6471B2C7, 0x09FEE040, ++0x6291E143, 0x652DE068, 0x8D6B3517, 0xE6400F56, ++0x8B273563, 0xE048E600, 0xE11A0F65, 0x72C0A031, ++0x00117800, 0x00202FB8, 0x00201356, 0x00202480, ++0x00202F1A, 0x00202FBC, 0x002013A2, 0x00202F19, ++0x00202B40, 0x00117804, 0x00117810, 0x00202F15, ++0x00202F16, 0x00202F17, 0x00200B84, 0x00200BD8, ++0x00200BD4, 0x41216153, 0x41214121, 0x41214121, ++0x45214521, 0x60534521, 0x6603C903, 0x0F65E048, ++0xE0077118, 0xE0442209, 0x641D0F25, 0x65F3E04C, ++0x0F46B314, 0x04FDE048, 0x0BFDE044, 0x61BD674D, ++0x41084708, 0x0F16E050, 0xD2936073, 0x420B09FE, ++0x6C07E00F, 0x607329C9, 0xE0400F96, 0x65F30EFE, ++0x6D0D85E2, 0x01FEE050, 0x60D3420B, 0x6073290B, ++0xE04C0F96, 0x04FEB2D9, 0x06FEE040, 0x6261E068, ++0x0F56652D, 0x3563E640, 0xE000894E, 0x602381F8, ++0x4008C903, 0x6B034000, 0xE0546103, 0xE0580FB6, ++0xECFFDD7D, 0x6CCC0FF6, 0x0FD6E06C, 0x4D0B60C3, ++0x42216253, 0x42214221, 0x64234221, 0x324C4200, ++0xE05C6E07, 0x45214200, 0xE0400FE6, 0x0BFE4521, ++0xC9036053, 0x30FC4008, 0x6D037B06, 0x85F81F05, ++0x6C2D1FB7, 0x1FC66E03, 0x0FC6E060, 0x05FEE058, ++0x64C3B2B4, 0x33FCE354, 0x563262D2, 0x22696132, ++0x67B42D22, 0x490B5936, 0x220B607C, 0x05FEE058, ++0x64C32D22, 0x7E01B289, 0xE70662ED, 0x8FE33273, ++0xE0407C01, 0x626106FE, 0x06FEE040, 0x85614200, ++0x302C760C, 0x6103701B, 0x64F3E500, 0x7501E704, ++0x6B5D6966, 0x24923B73, 0x74048FF9, 0xB26C65F3, ++0xE040641D, 0xB20506FE, 0xA1DD6461, 0xD44F0009, ++0xE201D74F, 0x2D20470B, 0x0009A1D6, 0x8B078829, ++0xEC00DE4C, 0x61E22DC0, 0x641DB1D7, 0x0009A1CC, ++0x622CE281, 0x8B013020, 0x0009A118, 0x06FCE028, ++0xE682626C, 0x3260666C, 0xA0EE8B01, 0xE6830009, ++0x3260666C, 0xA0DC8B01, 0xE6900009, 0x3260666C, ++0xA0D08B01, 0xE6910009, 0x3260666C, 0xA0B98B01, ++0xE6B00009, 0x3260666C, 0xA07F8B01, 0xE6BB0009, ++0x3260666C, 0xE6928920, 0x3260666C, 0xE4008B14, ++0xEB04D531, 0x52516652, 0x8B073620, 0x624D7401, ++0x8FF732B7, 0xE6007508, 0x52FBA002, 0xE60152FB, ++0xE6041261, 0x2260A188, 0xD229D428, 0xD4296542, ++0x0009420B, 0x0009A180, 0xE100E670, 0x601336FC, ++0xE0248162, 0x0BFCD21F, 0x6BBC6722, 0x26727BFC, ++0xEB0416B2, 0x06FEE078, 0x3263621D, 0xA16B8B01, ++0xDE1D0009, 0x31EC611D, 0xD41C6E12, 0x410BD114, ++0xE0700009, 0x450BD51A, 0xD41A04FE, 0x420BD210, ++0xD2170009, 0x64E3420B, 0xD60DD417, 0x0009460B, ++0x05FEE070, 0x01FDE074, 0x611DE600, 0x6253351C, ++0x326C666D, 0x22E07601, 0x32B3626D, 0x4E198FF7, ++0xE0747104, 0x0F15AFCE, 0x002029F8, 0x00202FDC, ++0x00201356, 0x00117804, 0x00202B10, 0x00117800, ++0x002013A2, 0x00203014, 0x00117808, 0x00202FF4, ++0x0020139A, 0x00203008, 0x00203010, 0x02FCE024, ++0x672CE07C, 0xEC000F76, 0xE07CEB04, 0x62CD07FE, ++0x8B013273, 0x0009A118, 0x6CCDD7B9, 0x357C65C3, ++0x62C37704, 0xD4B7327C, 0x6D52D7B7, 0x6E22470B, ++0x470BD7B6, 0xD4B664D3, 0x420BD2B3, 0xD2B30009, ++0x64E3420B, 0xD6B0D4B3, 0x0009460B, 0x67D3E600, ++0x376C666D, 0x626D7601, 0x27E032B3, 0x4E198FF7, ++0x7C08AFD3, 0x6212D1A6, 0x2228622C, 0xD2AA8B04, ++0x0009420B, 0x0009A003, 0x420BD2A8, 0x56FB0009, ++0xA0E1E200, 0xB1A62620, 0x56FB0009, 0xA0DBE200, ++0x52FB2620, 0xE500D69A, 0x65622250, 0x7604D2A0, ++0x62622252, 0xA0CFD69F, 0x56FB2620, 0x2610E124, ++0x5217D19D, 0x52181621, 0x52191622, 0x521A1623, ++0x551B1624, 0x1655E200, 0x1656551C, 0x1657551D, ++0x1658551E, 0x1659551F, 0x11281127, 0x112A1129, ++0x112C112B, 0x112E112D, 0x112FA0AE, 0xD68FD18E, ++0x6262E040, 0x76046512, 0x2152352C, 0x55116266, ++0x1151352C, 0x62626563, 0x75085612, 0x1162362C, ++0x56136252, 0x362C75EC, 0x62521163, 0x75105614, ++0x1164362C, 0x62526653, 0x76105515, 0x1155352C, ++0x56166262, 0x362CD57E, 0x62561166, 0x362C5617, ++0x66531167, 0x55186252, 0x352C7604, 0x62661158, ++0x352C5519, 0x65631159, 0x561A6262, 0x362C7504, ++0x6252116A, 0x7504561B, 0x116B362C, 0x561C6256, ++0x116C362C, 0x561D6256, 0x116D362C, 0x62526653, ++0x7604551E, 0x115E352C, 0x561F6262, 0x362CD569, ++0x6252116F, 0x7594061E, 0x0166362C, 0x6653E044, ++0x051E6252, 0x352C7644, 0xE0480156, 0x061E6262, ++0x0166362C, 0xE054D660, 0x051E6262, 0x352C4229, ++0x76040156, 0xE0586262, 0x4229061E, 0x0166362C, ++0xE23856FB, 0xE0442620, 0xE048021E, 0x62121621, ++0x55111622, 0x1653E200, 0x16545512, 0x16555515, ++0x16565513, 0x16575516, 0xE040051E, 0x051E1658, ++0x1659E050, 0x165A5514, 0xE04C051E, 0x051E165B, ++0x165CE054, 0xE058051E, 0x051E165D, 0x165EE044, ++0xE0480126, 0x11212122, 0x11251122, 0x11261123, ++0xE0400126, 0xE0500126, 0x01261124, 0x0126E04C, ++0x0126E054, 0x0126E058, 0x3F3C9358, 0x6EF64F26, ++0x6CF66DF6, 0x000B6BF6, 0x4F2269F6, 0xE240614D, ++0x89143123, 0x3127E21F, 0x8B09D734, 0xD434614D, ++0xE00171E0, 0x5671440B, 0x26596507, 0x1761A007, ++0xE001D42F, 0x6672440B, 0x26596507, 0x4F262762, ++0x0009000B, 0x614D4F22, 0x3123E240, 0xE21F8912, ++0xD7263127, 0x614D8B08, 0x5671D225, 0x420B71E0, ++0x260BE001, 0x1761A006, 0x6672D221, 0xE001420B, ++0x2762260B, 0x000B4F26, 0xE6400009, 0x46284618, ++0x6252D51C, 0x89FC2268, 0x0009000B, 0x4618E680, ++0xD5184628, 0x22686252, 0x000B89FC, 0xA0010009, ++0x7201E200, 0x8BFC3242, 0x0009000B, 0x00000080, ++0x00117804, 0x00202FF4, 0x00201356, 0x0020139A, ++0x00203008, 0x00203010, 0x00200C38, 0x00200C12, ++0x00202F00, 0x00202F14, 0x00202AA4, 0x001C36A0, ++0x001C3CA0, 0x001C36F4, 0x001C3B88, 0x001C3704, ++0x002029F8, 0x001C373C, 0x4618E680, 0xD52F4628, ++0x22686252, 0x000B8BFC, 0x2FE60009, 0x7FFC4F22, ++0xBFF16E53, 0x61E22F42, 0xE280D629, 0x54E11615, ++0x16464218, 0x422855E2, 0x57E31657, 0x16786EF2, ++0x26E22E2B, 0x4F267F04, 0x6EF6AFA8, 0x2FD62FC6, ++0x4F222FE6, 0x6C53DD1E, 0x6E43BFD6, 0x2DE2BF95, ++0x0009BFD2, 0x2C1251D5, 0x1C4154D6, 0x1C5255D7, ++0x1C6356D8, 0x6EF64F26, 0x000B6DF6, 0x61636CF6, ++0xA004E600, 0x62564109, 0x24227601, 0x36127404, ++0x000B8BF9, 0x4F220009, 0xD10FD40E, 0x0009410B, ++0xD40FD20E, 0xE5056022, 0x2202CB20, 0xD50D2452, ++0x450BE700, 0xD70C2472, 0x0009470B, 0xE601D10B, ++0x2162D20B, 0x4F264618, 0x2262000B, 0x001C3700, ++0x001C370C, 0x00203028, 0x00201356, 0x001C3500, ++0x001D4004, 0x002013CC, 0x00200EF8, 0x001E212C, ++0x001C3D30, 0x0009A1A9, 0x2FE62FD6, 0xDD8F4F22, ++0xA0049EA7, 0xD48E0009, 0x420BD28E, 0x62D265D2, ++0x8BF822E8, 0x0009A004, 0xD28AD48B, 0x55D1420B, ++0x22E852D1, 0xA0048BF8, 0xD4880009, 0x420BD285, ++0x52D255D2, 0x8BF822E8, 0x0009A004, 0xD281D484, ++0x55D3420B, 0x22E852D3, 0xA0048BF8, 0xD4810009, ++0x420BD27C, 0x52D455D4, 0x8BF822E8, 0x6EF64F26, ++0x6DF6000B, 0x2FD62FC6, 0x4F222FE6, 0x6E636D73, ++0x6C53B018, 0x64C357F4, 0xB05465E3, 0xB06A66D3, ++0xB09A0009, 0xB09E0009, 0xB0A20009, 0xB0BE0009, ++0xB0C10009, 0xB1240009, 0x4F260009, 0x6DF66EF6, ++0x6CF6A023, 0x3412D16C, 0xD66C0529, 0x2650D76C, ++0x2742000B, 0x0009A014, 0x2FD62FC6, 0x4F222FE6, ++0x6E636D73, 0x6C53BFEE, 0x64C357F4, 0xB02A65E3, ++0xB10666D3, 0x4F260009, 0x6DF66EF6, 0x6CF6A005, ++0xE603D260, 0x000B4618, 0xD25E2262, 0x000BE600, ++0x4F222262, 0xE40ABF7E, 0x0009BF7E, 0xE104D25A, ++0xE5004118, 0x2212E40A, 0x2252BF74, 0x6072D757, ++0x4F26CB20, 0x2702000B, 0xD1554F22, 0xE400410B, ++0x452BD554, 0x2FE64F26, 0x6E63D153, 0x44186612, ++0x45289210, 0x26294408, 0x44084500, 0x4400265B, ++0x4708264B, 0x47082162, 0x27EBD14C, 0x000B2172, ++0x03F06EF6, 0x2FE61FFF, 0xDE494F22, 0xE40AE101, ++0x2E12BF48, 0x726C62E3, 0xE401E100, 0x22122212, ++0x22122212, 0x22122212, 0xE7302242, 0xE40AE503, ++0x22122212, 0x22122212, 0x22122212, 0x22122212, ++0x22122212, 0x22122212, 0x22522272, 0x22122212, ++0x22122212, 0x22122212, 0x22122212, 0x121ABF22, ++0x2E62E600, 0x000B4F26, 0xD2326EF6, 0xE441E101, ++0x000B2212, 0xD1302242, 0xE605D430, 0x000B2162, ++0xD52F2462, 0x6050D22F, 0x8B0E8801, 0x6040D42E, ++0x8B078801, 0x9626D52D, 0x88016050, 0x96238B0C, ++0x0009A00A, 0xA0079621, 0xE6000009, 0x2262D426, ++0x88016040, 0xE6048B00, 0xAEF3E40A, 0xD2242262, ++0xE40AE601, 0x2262AEEE, 0x2FC62FB6, 0x2FE62FD6, ++0xDC204F22, 0x60C2ED00, 0xCB01EB64, 0x60C22C02, ++0xA041C901, 0x03C46E03, 0x034003D4, 0x001C3B88, ++0x0020302C, 0x002013A2, 0x00203034, 0x0020303C, ++0x00203044, 0x0020304C, 0x0025E720, 0x0020321C, ++0x00202F04, 0x001C5968, 0x001D4004, 0x001C3500, ++0x00201154, 0x00201180, 0x001C5814, 0x001C59D0, ++0x001C5830, 0x001C6268, 0x001C59A4, 0x001C639C, ++0x00202F16, 0x001C5804, 0x00202F15, 0x00202F17, ++0x001C581C, 0x001C5860, 0x89073DB2, 0xE40A60C2, ++0xBE9FC901, 0x7D016E03, 0x8BF52EE8, 0x8B033DB2, ++0xD23ED43D, 0x0009420B, 0x4F26E40A, 0x6DF66EF6, ++0xAE8F6CF6, 0x44116BF6, 0x604B8F01, 0x000B6043, ++0x2FB60009, 0x2FD62FC6, 0x4F222FE6, 0xDC347FFC, ++0x60C2ED00, 0xCB02EB64, 0x60C22C02, 0xC9022F02, ++0x6E03A009, 0x89083DB3, 0xE40A60C2, 0xC9022F02, ++0x6E03BE70, 0x2EE87D01, 0x3DB38BF4, 0xD4298B08, ++0x7F04D226, 0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, ++0x4F267F04, 0x6DF66EF6, 0x000B6CF6, 0xD5226BF6, ++0x60525651, 0x000B4628, 0x2FB6306C, 0x2FD62FC6, ++0x4F222FE6, 0x4F024F12, 0x6E43BFF1, 0xDC1B6B03, ++0xBFECDD1B, 0x30B80009, 0x060A3C05, 0x46094609, ++0x3D654601, 0x4209020A, 0x42094209, 0x8BF032E2, ++0x4F164F06, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x4F222FE6, 0xE102DE0F, 0xE403E500, 0xBFD42E12, ++0xE6062E52, 0xE7004618, 0x2E62E403, 0x4F262E72, ++0x6EF6AFCB, 0x0009000B, 0x00203054, 0x00201356, ++0x001C5860, 0x0020306C, 0x001C1040, 0xCCCCCCCD, ++0x10624DD3, 0x001D4004, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE5007FDC, 0x6453E110, ++0x6C534128, 0xED096E53, 0x6653655D, 0x365C4608, ++0x75014608, 0x6043361C, 0x0F66675D, 0xEB0060C3, ++0x26C137D3, 0x81628161, 0x16B28163, 0x16B416E3, ++0x74048FEA, 0xD9A668F2, 0x1981DAA6, 0x59F12982, ++0x1A91D1A5, 0x5AF22A92, 0x5DF45BF3, 0x54F65EF5, ++0x21A211A1, 0x11B211B3, 0x11D411D5, 0x11E611E7, ++0x11481149, 0x55F7EE00, 0x57F8DD9C, 0x64E3D29C, ++0xDB9DD99C, 0xE845EAB8, 0x2D521D51, 0x6AAC2272, ++0x6EED4808, 0x4D086DE3, 0x3DEC65E3, 0x4D084508, ++0x3D9C35EC, 0x450860C3, 0x81D12DC1, 0x4508E050, ++0x45084008, 0x60C381D2, 0xE60035BC, 0x81D334A2, ++0x1D531DD2, 0x8D01D489, 0xD4861D64, 0xB05C65D3, ++0x64ED7E01, 0x8BDC3482, 0xDB88D182, 0xD2806812, ++0x1B814829, 0x2FD26412, 0x2B92694D, 0xD97F6722, ++0x1B734729, 0xD77C6822, 0x1BA26A8D, 0xD2806B72, ++0x22B2D57B, 0xE0035D72, 0x5E7412D2, 0x12E44018, ++0xD67C5176, 0x54781216, 0x1248E103, 0xD4796792, ++0x6852127A, 0x28C1E7FF, 0x81916952, 0x6A52E050, ++0x81A24008, 0x60C36B52, 0x6C5281B3, 0x6E521CC2, ++0x62521E63, 0x1264E600, 0x46086563, 0x7501364C, ++0x665D2672, 0x8BF83613, 0x4F267F24, 0x6DF66EF6, ++0x6BF66CF6, 0x69F66AF6, 0x68F6000B, 0x60616642, ++0x8D04C803, 0x6061E500, 0x8802C903, 0x52628B03, ++0x51246563, 0x000B2412, 0x2FD66053, 0x4F222FE6, ++0x6E537FEC, 0xE5506253, 0xE4006D43, 0xA0014508, ++0x5224E101, 0x22116043, 0x81238121, 0x81226053, ++0x362056E2, 0xD2548BF5, 0x64F316E4, 0x420BE614, ++0x65E165E3, 0x2549E4FC, 0x61F12E51, 0x214965F3, ++0x54D12F11, 0x410BD14C, 0x57D1E614, 0xCB016071, ++0x1DE12701, 0x4F267F14, 0x000B6EF6, 0x2FD66DF6, ++0x4F222FE6, 0x6E537FEC, 0xE5FC6653, 0x60616D43, ++0xCB012059, 0x52E22601, 0x8B063260, 0x51E212E4, ++0x8B0431E0, 0xA00252D1, 0xAFF01E22, 0xD23A5664, ++0xE61464F3, 0x65E3420B, 0xE1FC67E1, 0x2E712719, ++0x54D167F1, 0xD1342719, 0xE61465F3, 0x2F71410B, ++0x602152D1, 0x2201CB01, 0x7F141DE1, 0x6EF64F26, ++0x6DF6000B, 0x4F222FE6, 0xDE23624C, 0x42004208, ++0x3E2CA005, 0xD41F5252, 0xBF8E5624, 0x65E22E62, ++0x352052E1, 0xD6228BF6, 0x4F262622, 0x6EF6000B, ++0x2FC62FB6, 0x2FE62FD6, 0xDC184F22, 0x52C1DB1F, ++0x362066C2, 0x6061891C, 0x8801C903, 0xDE138918, ++0xBF63DD1B, 0x650364E3, 0x66B28503, 0x3262620D, ++0xD40B8907, 0x0009BF9B, 0x4D0BD416, 0xAFE60009, ++0xBF620009, 0xD41464E3, 0x00094D0B, 0x0009AFDF, ++0x2262D212, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x00202B00, 0x00202B08, 0x00202B10, 0x00202B38, ++0x00202F1C, 0x001000B4, 0x00101680, 0x001E2108, ++0x001C3D00, 0x00117880, 0x00200A9E, 0x00202F00, ++0x00201356, 0x00203088, 0x0020308C, 0x001C3D28, ++0x2FC62FB6, 0x2FE62FD6, 0x7FFC4F22, 0x6022D22B, ++0x8D41C803, 0xDE2A2F01, 0xDB2BDC2A, 0xED01A017, ++0xC9036051, 0x89168801, 0xD128D426, 0x0009410B, ++0x61035503, 0xC8208551, 0xE0508903, 0x720102BE, ++0xD2230B26, 0x420B64E3, 0xD6226513, 0x52C126D2, ++0x352065C2, 0xDE208BE4, 0xDB21DD20, 0x52D1DC21, ++0x352065D2, 0x60518918, 0x8801C903, 0xD41B8914, ++0x460BD616, 0x57030009, 0x8F0437E0, 0xE2016503, ++0xAFEC2B20, 0xD4182C52, 0x420BD218, 0xD6110009, ++0x4118E101, 0x2612AFE3, 0xC80460F1, 0xD2148907, ++0x4F267F04, 0x6DF66EF6, 0x422B6CF6, 0x7F046BF6, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x001E2100, ++0x00202B10, 0x00202B08, 0x00202AA4, 0x0020106C, ++0x002010EE, 0x001C3D30, 0x00117880, 0x00202B00, ++0x00202F20, 0x00202F1C, 0x00202B38, 0x0020108A, ++0x00200170, 0xE601D203, 0x1265D503, 0x000B2252, ++0x00001266, 0x001C1010, 0x0000C34F, 0x0009000B, ++0x2FD62FC6, 0x4F222FE6, 0x6D436C53, 0xEE00A004, ++0x7E0164D4, 0x644CBFF2, 0x8BF93EC2, 0x6EF64F26, ++0x000B6DF6, 0xE5006CF6, 0x6643A002, 0x76017501, ++0x22286260, 0xAFE38BFA, 0x2FE60009, 0x75076253, ++0xE1086753, 0x6043EE0A, 0x4409C90F, 0x650330E2, ++0x8D014409, 0xE630E637, 0x4110365C, 0x8FF22760, ++0xE00077FF, 0x000B8028, 0x000B6EF6, 0x000BE000, ++0x2FE6E000, 0x7FEC4F22, 0x6E436253, 0xBFDC65F3, ++0xBFD06423, 0xBFCE64E3, 0xD40364F3, 0x0009BFCB, ++0x4F267F14, 0x6EF6000B, 0x00203090, 0xE4FDD59A, ++0xD69A6152, 0x25122149, 0x74016052, 0x2502CB01, ++0xD1976752, 0x25722749, 0xC8406010, 0x60628902, ++0x2602CB04, 0xE5016062, 0x2602CB08, 0xE4026062, ++0x2602C9CF, 0x45186062, 0x2602CB03, 0x000B1642, ++0xD58C1653, 0xD28DD78C, 0xE100D48D, 0x2511E600, ++0x22102711, 0x2461AFD2, 0xD28A664C, 0x362C4600, ++0xCB106060, 0x2600000B, 0xD286654C, 0x352C4500, ++0xE1EF6650, 0x000B2619, 0x664C2560, 0x4600D282, ++0x6060362C, 0x000BCB10, 0x654C2600, 0x4500D27E, ++0x6650352C, 0x2619E1EF, 0x2560000B, 0xD279664C, ++0x362C4600, 0xCB086060, 0x2600000B, 0xD275654C, ++0x352C4500, 0xE1F76650, 0x000B2619, 0x664C2560, ++0x4600D271, 0x6060362C, 0x000BCB08, 0x654C2600, ++0x4500D26D, 0x6650352C, 0x2619E1F7, 0x2560000B, ++0xD668624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0x624C600C, 0x4200D663, 0x6020326C, ++0x4021C908, 0x40214021, 0x600C000B, 0x644CD15F, ++0x6240341C, 0x602C000B, 0x644CD15D, 0x6240341C, ++0x602C000B, 0x4F222FE6, 0x645C6E43, 0x3467E60A, ++0xBFEB8914, 0x640C0009, 0x880160EC, 0xE00F8B02, ++0x2409A002, 0x44094409, 0xE60A624C, 0x89053263, ++0x644CBFE2, 0x6023620C, 0x8B00C880, 0x6023E200, ++0x000B4F26, 0x4F226EF6, 0x6062D64A, 0x8B038801, ++0x0009B246, 0x0009A003, 0xE640D247, 0xD6472260, ++0x4F26E200, 0x2622000B, 0xD6424F22, 0x88026062, ++0xB28F8B01, 0xD6410009, 0x4F26E200, 0x2622000B, ++0xD43DD53C, 0xE701E100, 0x000B2512, 0xD23A2470, ++0x000BE604, 0x4F222260, 0xD13AD439, 0x0009410B, ++0xE1FDD539, 0xD2396650, 0xE7002619, 0x4F262560, ++0x2270000B, 0xD4364F22, 0x410BD132, 0xD5320009, ++0x6650E7FB, 0x4F262679, 0x2560000B, 0xD4314F22, ++0x410BD12C, 0xD52C0009, 0x6650E7F7, 0x4F262679, ++0x2560000B, 0x942DD528, 0x22496250, 0x2520000B, ++0xE4BFD525, 0x22496250, 0x2520000B, 0xD2264F22, ++0x600D8522, 0x89112008, 0x89138801, 0x89158803, ++0x89438805, 0x89498806, 0x894F8808, 0x89558809, ++0x895B880A, 0x8961880B, 0x0009A068, 0x0009B06A, ++0x600CA065, 0x0009B078, 0x600CA061, 0x0009B081, ++0x600CA05D, 0x0000FF7F, 0x001E2148, 0x001E1108, ++0x001E1000, 0x00202F60, 0x00202F62, 0x00202F81, ++0x00202F44, 0x001E103F, 0x001E105F, 0x001E102F, ++0x001E1090, 0x00202F68, 0x001E100B, 0x00202F64, ++0x00203094, 0x00201356, 0x001E1028, 0x00202F80, ++0x002030A0, 0x002030B0, 0x00202F38, 0x6260D684, ++0x8B2B2228, 0x0009B061, 0x600CA029, 0x6260D680, ++0x8B232228, 0x0009B069, 0x600CA021, 0x6260D67C, ++0x8B1B2228, 0x0009B0C7, 0x600CA019, 0x6260D678, ++0x8B132228, 0x0009B0CD, 0x600CA011, 0x6260D674, ++0x8B0B2228, 0x0009B125, 0x600CA009, 0x6260D670, ++0x8B032228, 0x0009B13D, 0x600CA001, 0x4F26E000, ++0x0009000B, 0xD26CD16B, 0xD56C8412, 0x4000C90F, ++0xD76B012D, 0xE403D66B, 0xE20F611C, 0x2540E001, ++0x25202712, 0x2602000B, 0xE601D262, 0x30668523, ++0xE0008D05, 0xD663D260, 0xE0018122, 0x000B2602, ++0xD25C0009, 0x600D8523, 0x89052008, 0x8B0A8801, ++0x6060D65D, 0x2600CB01, 0xD457D65A, 0xE001E101, ++0x000B2612, 0x000B8142, 0xD152E000, 0x8513E501, ++0x640D4518, 0x66033453, 0xE0008D05, 0xD551D253, ++0x2260E001, 0x000B2502, 0x4F220009, 0x8513D149, ++0x6453650D, 0x62494419, 0x227D672E, 0x8801602C, ++0x88028909, 0x88038910, 0x8806891A, 0x88078935, ++0xA04C893B, 0xD5460009, 0x6652D746, 0x2762D446, ++0x622C6261, 0x2421A038, 0x2228625C, 0xD4438B3F, ++0x6642D540, 0x2562D440, 0x24018561, 0x6203A02C, ++0x2008605C, 0x88108907, 0x88208908, 0x88308909, ++0xA02C890A, 0xD23A0009, 0x6222A008, 0xA005D239, ++0xD2396222, 0x6222A002, 0x6262D638, 0xD432D531, ++0x66212522, 0xA00F626C, 0xD6352421, 0x6261D52D, ++0x622CD42D, 0xA0072562, 0xD6322421, 0x8561D529, ++0x2562D429, 0x62032401, 0x662D8515, 0x3617610D, ++0x65038F01, 0xB0CB2451, 0xA0010009, 0xE000E001, ++0x000B4F26, 0xD6190009, 0xD427E101, 0x65412610, ++0xD118D717, 0xE20F655D, 0x2752E001, 0x000B2620, ++0x2FE62102, 0xD20F4F22, 0x640C8523, 0x8B082448, ++0xD511D61D, 0x2621E200, 0x940F8451, 0xA0482049, ++0xDE0D8051, 0xC84060E0, 0xE2018D32, 0x89443427, ++0xD216D615, 0x2641420B, 0x0009A030, 0x0000FF7F, ++0x00202F81, 0x00202F38, 0x00202F44, 0x001E1100, ++0x001E100C, 0x00202F64, 0x001E1000, 0x001E1001, ++0x00202F6C, 0x00202F4C, 0x00202F50, 0x00202F54, ++0x00202F70, 0x00202F74, 0x00202F78, 0x00202F7C, ++0x00203280, 0x0020328A, 0x00202F5E, 0x0020225A, ++0x89123427, 0xD294D693, 0x2641420B, 0xCB8084E1, ++0x80E1B0F5, 0xD69160E0, 0x2E00CB04, 0xC93F6060, ++0xD68F2600, 0xA001E001, 0xE0002602, 0x000B4F26, ++0xD68C6EF6, 0xC8806060, 0xD2868919, 0x88016021, ++0xD2898B15, 0x8524E501, 0x89103056, 0xE203D187, ++0x2120D487, 0xE00B6541, 0x0656655D, 0xE40FD585, ++0x2140E702, 0xD77E2571, 0x000BE001, 0x000B2702, ++0x2FE6E000, 0xDE804F22, 0xC88084E1, 0xD57A892C, ++0x20088554, 0x61038F28, 0x8553D77C, 0x64036672, ++0x8566650C, 0x3520620C, 0xD6798B1E, 0x651CD774, ++0x2651644C, 0x60E02741, 0x8904C840, 0x420BD275, ++0xA0030009, 0xD2680009, 0x0009420B, 0x0009B09F, ++0xE201D167, 0x60E02122, 0xCB04D464, 0x60402E00, ++0x2400C93F, 0x6023A001, 0x4F26E000, 0x6EF6000B, ++0x2FB62FA6, 0x2FD62FC6, 0xDA622FE6, 0x66A1E240, ++0x3622DC5E, 0x62638900, 0x6ED36D2C, 0x4E2136D8, ++0x4E212A61, 0xDB61D460, 0xE700A00F, 0x770162B2, ++0x71026123, 0x66212B12, 0x71026213, 0x61212B12, ++0x651D666D, 0x356C4528, 0x627C2452, 0x8BED32E3, ++0xC90360D3, 0x8B108803, 0x617367B2, 0x2B127102, ++0x71026E13, 0x2B126571, 0x655D6DE1, 0x422862DD, ++0x325CE107, 0xA00C2C10, 0x88022422, 0xA0038B01, ++0x8801E203, 0xE2018B05, 0x66B22C20, 0x655D6561, ++0xE60F2452, 0x67A12C60, 0x8B052778, 0xDD38DC44, ++0xEB01EA00, 0x2DB22CA2, 0x6DF66EF6, 0x6BF66CF6, ++0x6AF6000B, 0x2FE62FD6, 0xE240DD36, 0x362266D1, ++0x62638900, 0x3678672C, 0x7703DE38, 0x47212D61, ++0x64E2D635, 0xA00E4721, 0x6562E100, 0x62537101, ++0x74012450, 0x24204219, 0x45297401, 0x74012450, ++0x24504519, 0x621C7401, 0x8BEE3273, 0x66E24200, ++0x420061D1, 0x2118362C, 0x2E628F06, 0xDD1CD728, ++0xE501E400, 0x2D522742, 0x000B6EF6, 0x2FD66DF6, ++0x4F222FE6, 0xED0AEE01, 0x64E3BC96, 0xBC9B64E3, ++0x62EC7E01, 0x8BF732D7, 0xBC9EEE01, 0x64E364E3, ++0x7E01BCA3, 0x32D762EC, 0x4F268BF7, 0x000B6EF6, ++0xD1186DF6, 0xD418920D, 0x72122122, 0x2422D617, ++0xD7177204, 0x72202622, 0x2722D116, 0x000B7230, ++0x137A2122, 0x00202F5E, 0x00202366, 0x001E1015, ++0x00202F64, 0x001E1001, 0x00202F38, 0x001E1100, ++0x00202F62, 0x00202F50, 0x001E1000, 0x00202F54, ++0x00202F60, 0x0020225A, 0x001E100C, 0x00202F4C, ++0x00202F68, 0x00202F6C, 0x00202F70, 0x00202F74, ++0x00202F78, 0x00202F7C, 0x4F222FE6, 0xD6507FFC, ++0x88016060, 0xE2018951, 0x2620BFBB, 0xD54ED14D, ++0xDE4E6010, 0x64E36552, 0x7402C840, 0x8D22D14C, ++0xD24C7502, 0xE601D74C, 0xE7042722, 0x76016255, ++0x626C2421, 0x8FF93273, 0xD4437402, 0x6242E601, ++0x640D8528, 0x67494419, 0x275D657E, 0x81E4607C, ++0xE417D542, 0x67557601, 0x3243626C, 0x8FF92171, ++0xA0207102, 0xD23E0009, 0xE601D73B, 0xE7042722, ++0x76016255, 0x626C2421, 0x8FF93273, 0xD4327402, ++0x6242E601, 0x640D8528, 0x67494419, 0x275D657E, ++0x81E4607C, 0xE417D533, 0x67557601, 0x3243626C, ++0x8FF92171, 0x924A7102, 0xD2262E21, 0x5E23D72E, ++0x64F22FE2, 0x604365F2, 0x2700C980, 0xC9606043, ++0x80716103, 0xC9036043, 0x80724519, 0x65F2605C, ++0x817266F2, 0x46194629, 0x606C4529, 0x4018645C, ++0x8173304C, 0x21185E23, 0x64F22FE2, 0x6E4C62F2, ++0x602C4219, 0x66F262F2, 0x46294018, 0x461930EC, ++0x42298174, 0x652C606C, 0x305C4018, 0x81758F07, ++0x0009BC9C, 0x2228620C, 0xA00A8908, 0x60130009, ++0x8B038840, 0x0009B009, 0x0009A003, 0xE202D60F, ++0x7F042622, 0x000B4F26, 0x000B6EF6, 0x060A0009, ++0x00202F80, 0x001E1000, 0x00202F6C, 0x00203280, ++0x0020328C, 0x00203224, 0x00202F54, 0x00203254, ++0x00203252, 0x00203226, 0x00202F38, 0x00202F64, ++0x4F222FE6, 0xDE937FFC, 0x200884E9, 0x2F008D06, ++0xD692D491, 0x0009460B, 0x64F0B194, 0x6620D290, ++0x89022668, 0xC9BF60E0, 0x7F042E00, 0x000B4F26, ++0x000B6EF6, 0x2FE60009, 0xDE8A4F22, 0x60E0D68A, ++0xCBC0D48A, 0x62602E00, 0xC803602C, 0x40218904, ++0x70014021, 0x6603A002, 0x66034009, 0xD684616D, ++0xE500A004, 0x75016262, 0x74042422, 0x3213625D, ++0xD2808BF8, 0x0009420B, 0xC9BF84E2, 0x4F2680E2, ++0x6EF6000B, 0x2FE62FD6, 0x7FFC4F22, 0x6260D67A, ++0x89442228, 0xD56FE100, 0x60502610, 0xCB40D477, ++0x2500440B, 0x8D052008, 0x62E06E03, 0x7104612C, ++0x2F11A006, 0xD472D66A, 0xDD726760, 0x657C4D0B, ++0xE23C6D1D, 0x8B033D27, 0xD264D46F, 0x0009420B, ++0x4D214D21, 0xA005D76D, 0x66E6E400, 0x357C4508, ++0x74012562, 0x35D3654D, 0xD7698BF7, 0x6172E003, ++0x81114018, 0x6E7260F1, 0x81E2700C, 0xD4656172, ++0xDD658113, 0x4D0BDE65, 0xE2016572, 0xD4642E22, ++0x420BD252, 0xD6530009, 0xC93F6060, 0x7F042600, ++0x6EF64F26, 0x6DF6000B, 0x2FC62FB6, 0x2FE62FD6, ++0xD25C4F22, 0x6B436E73, 0x420B6C53, 0x20086D63, ++0x61038F08, 0xD245D458, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6422B, 0x21B060C3, 0x60D38011, 0xE5008111, ++0x64BCA007, 0x6053655D, 0x665300EC, 0x7501361C, ++0x625D8064, 0x8BF53243, 0x6060D636, 0x2600C9BF, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x7FC44F22, ++0x720262F3, 0x22512F41, 0x45297202, 0x60632251, ++0xE5C4E682, 0x67F38121, 0x655C666C, 0xE408BFBC, ++0x4F267F3C, 0x0009000B, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE1007FC4, 0x6513ECFF, ++0x6B136CCD, 0xDE36D735, 0xEDFF64F3, 0xD835EA04, ++0x6053655C, 0x027D4000, 0x32C0622D, 0x66038D0D, ++0x09ED6063, 0x2491027D, 0x24217402, 0x698202ED, ++0x3928622D, 0x74022892, 0x75017104, 0x6063625C, ++0x07D532A2, 0x0EB58FE4, 0x2448641C, 0xE6808905, ++0x67F3E5C5, 0xBF7F666C, 0x7F3C655C, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0xD11E68F6, ++0x6012D21E, 0xCB20E405, 0x2102E500, 0x000B2242, ++0x00002252, 0x001E1017, 0x002030BC, 0x00201356, ++0x00202F1A, 0x001E1015, 0x001E10BF, 0x00117800, ++0x001E10FC, 0x00200170, 0x00202F20, 0x002024BE, ++0x002030C0, 0x002013A2, 0x002030DC, 0x0011788C, ++0x00202F1C, 0x00202B00, 0x002010EE, 0x001E2130, ++0x002030E4, 0x00202480, 0x002030E8, 0x00202F26, ++0x00202F2E, 0x00203220, 0x001C3500, 0x001D4004, ++0xD565D164, 0xE400D765, 0x2142E20F, 0x17411154, ++0xD5632722, 0x9669D763, 0x15412572, 0x96661562, ++0xE6011565, 0xD5601165, 0x666CE6F8, 0x25422542, ++0x25422542, 0x25422542, 0x25622542, 0x7601E727, ++0x67632572, 0x25627797, 0xE7042572, 0x2572E248, ++0xE2192522, 0xE2702522, 0x25422542, 0x25422542, ++0x25222542, 0x2522E20C, 0x25422542, 0x25422542, ++0x25422542, 0x25422542, 0x000B154A, 0xE2081145, ++0x0009422B, 0x2FE62FD6, 0x7FFC4F22, 0xC8206043, ++0x6E438D02, 0x0009BE6D, 0xC81060E3, 0xBE6A8901, ++0x60E30009, 0x8901C840, 0x0009BE8C, 0xC80160E3, ++0xDD3E8938, 0xC80260D0, 0x2F008D03, 0x460BD63C, ++0x60F00009, 0x8902C804, 0x460BD63A, 0x62F00009, ++0xC8806023, 0x60D08902, 0x2D00C97F, 0xC8016023, ++0xD6358906, 0x0009460B, 0x0009A007, 0x51630601, ++0x8902C808, 0x460BD631, 0x60F00009, 0x8902C810, ++0x420BD22F, 0xD52F0009, 0x88026052, 0xD22E8B03, ++0xA005E604, 0x88012260, 0xD22B8B02, 0x2260E601, ++0x2522E200, 0xC88060E3, 0xD628892E, 0x60E36E60, ++0x8902C880, 0x420BD226, 0x60E30009, 0x8902C840, ++0x420BD224, 0x60E30009, 0x8902C802, 0x420BD222, ++0x60E30009, 0x890EC804, 0x410BD120, 0xBF0E0009, ++0xBF4D0009, 0xD51E0009, 0x6050D41E, 0xC908D71E, ++0xBF842500, 0x60E32472, 0x8905C808, 0x7F04D21B, ++0x6EF64F26, 0x6DF6422B, 0x4F267F04, 0x000B6EF6, ++0x00006DF6, 0x001C581C, 0xA000A000, 0x001D0100, ++0x001D4000, 0x00040021, 0x001C589C, 0x001E1021, ++0x00201536, 0x00201558, 0x00201B98, 0x00201570, ++0x0020157E, 0x00202F64, 0x001E100B, 0x001E1028, ++0x002015D4, 0x002015E0, 0x00201586, 0x002015A4, ++0x001E1000, 0x0010F100, 0x12345678, 0x002015BC, ++0x644CD6A7, 0x000B346C, 0xD6A62450, 0x346C644C, ++0x2450000B, 0x644CD6A4, 0x000B346C, 0x625C2450, ++0x4208616D, 0x42084119, 0x42006019, 0x670E614C, ++0xD49E321C, 0x4200207D, 0x324CC90F, 0x2200000B, ++0x4208625C, 0x42004208, 0x324C644C, 0x4200D498, ++0x000B324C, 0x2FE62260, 0x614C4F12, 0x4100D493, ++0x6710314C, 0xE29F666D, 0x27294619, 0x6E536269, ++0x672E6573, 0x4221227D, 0x42214221, 0x7601662C, ++0xE4014608, 0x34E84608, 0x644C4600, 0x071A0467, ++0x2150257B, 0x000B4F16, 0x4F226EF6, 0xD2857FE8, ++0x88016021, 0xD2848B7B, 0x26686621, 0xD2838B77, ++0x26686621, 0xE50F8B73, 0xE401BFA2, 0xBFA4E501, ++0xE586E400, 0xE400655C, 0x2F50BFA4, 0xBFA1E401, ++0xE602E506, 0x60634618, 0x81F2E401, 0x6543BF9F, ++0xE40185F2, 0xBFAB6543, 0x85F26603, 0x6543E401, ++0x6603BFB1, 0xE40265F0, 0x6053756C, 0x80F8BF80, ++0xBF82E402, 0x84F8E512, 0x7090E402, 0x6503BF82, ++0x4618E602, 0x81F66063, 0xBF80E402, 0x85F6E500, ++0x6603E402, 0xE500BF8C, 0xE40285F6, 0xBF926603, ++0xE5FEE500, 0xE010655C, 0xBF61E403, 0xE5130F54, ++0xE40EBF63, 0x05FCE010, 0xBF63E40E, 0xE5007585, ++0xBF64E403, 0xE500E640, 0xBF71E403, 0xE500E640, ++0xBF78E403, 0xE5FFE640, 0xE014655C, 0xBF47E404, ++0xE40F0F54, 0xE504BF49, 0x05FCE014, 0xBF49E40F, ++0xE5017584, 0xBF4AE640, 0xE501E404, 0xBF57E640, ++0xE501E404, 0xE404E640, 0xAF5C7F18, 0x7F184F26, ++0x000B4F26, 0x4F220009, 0xD2427FF0, 0x88016021, ++0xD2418B71, 0x26686621, 0xD2408B6D, 0x26686621, ++0xE50F8B69, 0xE401BF1C, 0xBF1EE501, 0xE586E400, ++0xE400655C, 0x2F50BF1E, 0xBF1BE401, 0xE401E506, ++0xBF1C6543, 0xE401E640, 0xBF296543, 0xE401E640, ++0xBF306543, 0x65F0E640, 0x756CE402, 0xBEFF6053, ++0xE40280F4, 0xE512BF01, 0xE40284F4, 0xBF017090, ++0xE6406503, 0xBF02E402, 0xE640E500, 0xBF0FE402, ++0xE640E500, 0xBF16E402, 0xE5FEE500, 0x6053655C, ++0xBEE5E403, 0xE51380F8, 0xE40EBEE7, 0xE40E84F8, ++0xBEE77085, 0xE5006503, 0xBEE8E640, 0xE500E403, ++0xBEF5E640, 0xE500E403, 0xBEFCE640, 0xE5FFE403, ++0x6053655C, 0xBECBE404, 0xE40F80FC, 0xE504BECD, ++0xE40F84FC, 0xBECD7083, 0xE5016503, 0xBECEE640, ++0xE501E404, 0xBEDBE640, 0xE501E404, 0xE404E640, ++0xAEE07F10, 0x7F104F26, 0x000B4F26, 0x00000009, ++0x001E102F, 0x001E1080, 0x001E1090, 0x001E103F, ++0x001E103E, 0x00202F5E, 0x00202F60, 0x00202F62, ++0xD21DD11C, 0x66206010, 0x676C7001, 0x3700C90F, ++0xE5008D13, 0x67106210, 0x7701622C, 0x64232170, ++0xD6166010, 0x44084408, 0x3428C90F, 0x62602100, ++0x7201D513, 0x44082620, 0x000B354C, 0xD10F6053, ++0x25586510, 0xE6008D13, 0xD60DD40B, 0x655C6540, ++0x47086753, 0x37584708, 0x47086540, 0x24507501, ++0x367C6040, 0x2400C90F, 0x72FF6210, 0x000B2120, ++0x00006063, 0x00202F19, 0x00202F18, 0x00202F1A, ++0x00202B40, 0x7FFC4F22, 0xE680D1A8, 0x666C6212, ++0xD2A72F22, 0x67F36563, 0x420B7542, 0x7F04E404, ++0x000B4F26, 0xE6800009, 0xD2A1666C, 0xE7006563, ++0x422B7540, 0xE6806473, 0xD29D666C, 0xE7006563, ++0x422B7543, 0x2FB66473, 0x2FD62FC6, 0x4F222FE6, ++0x4D18ED01, 0xDB98DC97, 0x65C252C1, 0x89203520, ++0xC9036051, 0x891C8801, 0xD194DE92, 0x64E3410B, ++0x85036503, 0x670D66B2, 0x89073762, 0xD291D490, ++0x0009420B, 0xE701D190, 0x2172AFE6, 0xDE8F64E3, ++0x00094E0B, 0xD48FD68E, 0x410BD18F, 0xAFDB26D2, ++0x4F260009, 0x6DF66EF6, 0x000B6CF6, 0x4F226BF6, ++0x85467FF4, 0x2F01E681, 0x666C8547, 0x854881F1, ++0x81F2D27B, 0x67F38542, 0x854381F3, 0x81F4E40C, ++0x65636053, 0x420B81F5, 0x7F0C7540, 0x000B4F26, ++0x2F860009, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x7FEC4F22, 0xE000D176, 0xD4782F12, 0x81F26103, ++0xDC771F42, 0xD6776B13, 0xE0014B08, 0x460BDE76, ++0x3BEC4B00, 0x66C21F03, 0x362052C1, 0xA1818B01, ++0x60610009, 0x8801C903, 0xA17B8B01, 0x85610009, ++0x8B01C801, 0x0009A080, 0x85D25D63, 0xC9036603, ++0x85D36403, 0x6053650D, 0x40214021, 0x4500C93F, ++0x322A6103, 0x6053252D, 0xC901E510, 0xD95E3153, ++0x6E038D21, 0x4408D761, 0x44086870, 0x44006213, ++0x28884200, 0x342C8F0E, 0x6043D25D, 0x60E3072D, ++0x4A196A7D, 0x658E68A9, 0x285D8801, 0x6A7C8F0B, ++0x6A13A009, 0x6043D257, 0x61ED0E2D, 0x68194119, ++0x287D678E, 0xD1546AEC, 0x22286210, 0xEAFF8901, ++0xEEFF6AAC, 0x6EEC65AD, 0x8B0F35E0, 0x4D0BDD3F, ++0x540364C3, 0xBF72E502, 0xD44C6D03, 0x410BD13F, ++0xD74B65D3, 0xD44BEE01, 0x27E2A025, 0x2679E7FC, ++0x81D26063, 0x946085D3, 0x61032049, 0x4508268B, ++0x251B6063, 0x605381D2, 0x85D481D3, 0x4118E108, ++0x81D4201B, 0xEE0262C2, 0x20798521, 0x64C28121, ++0x6041678D, 0xCB0137E3, 0x24018D04, 0xEEE785D2, ++0x81D220E9, 0x490BD438, 0x60C20009, 0x52F366F2, ++0x2B02CB01, 0x2622AF6F, 0xD2208561, 0x8F02C802, ++0xA0D264C3, 0x420B0009, 0xD9300009, 0x5E036503, ++0x079EE04C, 0x7701DD2E, 0x69D20976, 0x7901D626, ++0x6D602D92, 0x89062DD8, 0xD218D424, 0xED01420B, ++0xA0B3D723, 0x625127D2, 0x4118E10F, 0x2219E402, ++0x32404418, 0x85518B46, 0x20D9EDFC, 0x60518151, ++0xCB017DE3, 0x85E12501, 0x20D9D60A, 0x460B81E1, ++0x69F264C3, 0xA09957F3, 0x7E032972, 0x001C3D9C, ++0x00201E38, 0x00202B38, 0x00202F00, 0x0020106C, ++0x00202B00, 0x002010EE, 0x001E2130, 0x0020108A, ++0x001C3D30, 0x00203200, 0x00201356, 0x0020320C, ++0x00202B10, 0x002029F8, 0x001C3D00, 0x0020321C, ++0x00203100, 0x00203180, 0x00202F14, 0x00202B08, ++0x001E212C, 0x00203204, 0x00203208, 0x00202AA4, ++0x00203220, 0x6DDD6D51, 0x6DD94D19, 0x2D6D66DE, ++0x60DC7D01, 0x41186103, 0x8F458801, 0xD65B2511, ++0x74016462, 0x85E32642, 0x6063660D, 0x40214021, ++0x4600C93F, 0x322A6D03, 0x6063262D, 0xD154C801, ++0x8901D954, 0x2D6B96A1, 0xE010E600, 0x64DD0F64, ++0x07FCE010, 0x4000607C, 0x622D021D, 0x8D123240, ++0x60636603, 0xE7FF021D, 0x8B013270, 0x01D5A00B, ++0x02FCE010, 0x7201E604, 0x622C0F24, 0x8BE73262, ++0x666C06FC, 0x60634600, 0x7101019D, 0xD1420915, ++0x697D6711, 0x89073940, 0x602D6211, 0x890388FF, ++0xDD3E21D1, 0x2D20E201, 0xEDFC8551, 0x815120D9, ++0xD23B6051, 0x64C3CB01, 0x2501420B, 0x02FCE010, ++0x612CD438, 0x440BE001, 0x270267F2, 0xD23685EF, ++0x420B54F2, 0xAE96650D, 0x420B0009, 0x54030009, ++0x85446E03, 0x4D18ED08, 0x30D020D9, 0xBE568B03, ++0xA007E501, 0x85410009, 0x620DDD2C, 0x890122D8, ++0xE500BE4D, 0xD22BD42A, 0x65E3420B, 0xED01D72A, ++0x27D2AE79, 0xEE0485F2, 0x610D7001, 0x81F231E7, ++0x7C088D02, 0x0009AE66, 0x4F267F14, 0x6DF66EF6, ++0x6BF66CF6, 0x69F66AF6, 0x68F6000B, 0x4F222FE6, ++0x6E22D21E, 0xC84060E3, 0x22E28D02, 0x0009BDD2, ++0x4218E240, 0x89012E28, 0x0009BDDD, 0xC81060E3, ++0xD4178905, 0x420BD217, 0xBDDC0009, 0x60E30009, ++0x8901C805, 0x0009BE2D, 0xC80260E3, 0x4F268902, ++0x6EF6ADD9, 0x000B4F26, 0x80006EF6, 0x00203220, ++0x00202F26, 0x00202F2E, 0x00202F22, 0x00202F24, ++0x002010EE, 0x002029F8, 0x002013A2, 0x00008000, ++0x00202B08, 0x0020108A, 0x001E212C, 0x001C3510, ++0x00203214, 0x00201356, 0x080A0C0E, 0x00020406, ++0x1A1C1E20, 0x12141618, 0x2E303234, 0x26282A2C, ++0x3A3C3E40, 0x6C625648, 0x41112F26, 0xE2208F18, ++0x890B3123, 0x321CD204, 0xD1026220, 0x412B312C, ++0x00090009, 0x00202A22, 0x002029D8, 0x000BE000, ++0x400062F6, 0x40004000, 0x40004000, 0x40004000, ++0x62F6000B, 0x40004000, 0x40004000, 0x40004000, ++0x40184000, 0x62F6000B, 0x40004000, 0x40004000, ++0x40004000, 0x40284000, 0x62F6000B, 0x40004000, ++0x40184000, 0x000B4028, 0xC90F62F6, 0x40054005, ++0x40054005, 0x62F6000B, 0x4005C907, 0x40054005, ++0x62F6000B, 0x4005C903, 0x000B4005, 0xC90162F6, ++0x000B4005, 0x000062F6, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x544F0D0A, 0x46205355, 0x00003A57, 0x20636544, ++0x32203231, 0x20373030, 0x333A3132, 0x34323A36, ++0x00000000, 0x00000D0A, 0x00000043, 0x42707372, ++0x3D206675, 0x554E203D, 0x202C4C4C, 0x6E49677A, ++0x4E497274, 0x6D754E51, 0x0000003D, 0x61766E49, ++0x2064696C, 0x72657375, 0x20726F20, 0x2079656B, ++0x00214449, 0x52504545, 0x57204D4F, 0x65746972, ++0x6461202C, 0x003D7264, 0x6C617620, 0x0000003D, ++0x00000A0D, 0x6E6B6E55, 0x206E776F, 0x6D6D6F63, ++0x3D646E61, 0x00000000, 0x000A0D52, 0x203A3051, ++0x00000020, 0x203A3151, 0x00000020, 0x203A3251, ++0x00000020, 0x203A3351, 0x00000020, 0x203A3451, ++0x00000020, 0x61437748, 0x7262696C, 0x6F697461, ++0x6620206E, 0x0A6C6961, 0x0000000D, 0x73696F4E, ++0x61432065, 0x7262696C, 0x6F697461, 0x6166206E, ++0x21216C69, 0x00000D0A, 0x00000072, 0x00205220, ++0x00000D0A, 0x62735576, 0x7473725F, 0x00000A0D, ++0x62735576, 0x7375735F, 0x646E6570, 0x00000A0D, ++0x62735576, 0x7365725F, 0x000A0D6D, 0x00000042, ++0x72746E49, 0x6D652051, 0x2C797470, 0x49677A20, ++0x4972746E, 0x754E514E, 0x00003D6D, 0x654C7245, ++0x0000006E, 0x00000049, 0x20746F4E, 0x756F6E65, ++0x49206867, 0x4220514E, 0x0A0D6675, 0x00000000, ++0x000000FF, 0x00020001, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00020003, 0x01090108, 0x0002010A, ++0x02000003, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C0207, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00FF010F, 0x01090108, 0x010B010A, ++0x020000FF, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00205220, 0x00000046, 0x00000059, 0x73204142, ++0x003D7165, 0x49544120, 0x0000204D, 0x00000000, ++0x00000000, 0x002E0209, 0x80000101, 0x000409FA, ++0x00FF0400, 0x05070000, 0x02000201, 0x82050700, ++0x00020002, 0x03830507, 0x07010040, 0x40020405, ++0x02090000, 0x0101002E, 0x09FA8000, 0x04000004, ++0x000000FF, 0x02010507, 0x07000040, 0x40028205, ++0x05070000, 0x00400383, 0x04050701, 0x00004002, ++0x00000000, 0x00000000, 0x07090000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, }; ++ ++const u32_t zcDKFwImageSize=12988; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfw2.c +@@ -0,0 +1,1018 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++ ++const u32_t zcP2FwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE947FFC, 0xE114D594, ++0x1E13D494, 0x67521E4C, 0xD494D693, 0x37402769, ++0x62528F06, 0x7201D692, 0x60602522, 0x2600C93F, ++0xD7906152, 0x2512611D, 0x264B6652, 0x2562470B, ++0x0009B00D, 0xE60095AC, 0xC84060E2, 0x2F028F03, ++0x8FF93652, 0x7F047601, 0xA05A4F26, 0x4F226EF6, ++0x410BD185, 0xD4850009, 0x0009440B, 0x450BD584, ++0xD7840009, 0xD284E1FF, 0x2712611D, 0xD4835029, ++0xE1FFCB01, 0x1209E501, 0x12112212, 0xE7202452, ++0x4718D57F, 0x2572D27F, 0xD17FE700, 0xD680D47F, ++0xE2012270, 0x24702172, 0xD67E2620, 0x2641E4FF, ++0xD57DE600, 0x666DE104, 0x76016063, 0x4000626D, ++0x8FF83212, 0xD5790545, 0x2520E201, 0xD279D778, ++0x2710E100, 0xE5802212, 0x655C6613, 0x666DD476, ++0x76046763, 0x374C626D, 0x8FF83253, 0xD4732712, ++0xD573E101, 0xD6732410, 0x2542E400, 0xE03AE501, ++0xD272D771, 0xE0390654, 0x27110654, 0x000B4F26, ++0x7FC82211, 0xD76FD16E, 0xDC70DB6F, 0xD271DE70, ++0xD572D471, 0x1F12D672, 0x1F76710C, 0x1FB877FC, ++0x1FEA1FC9, 0x72041F2B, 0xDE6FDC6E, 0x1F13EB10, ++0x1F511F44, 0x1F771F65, 0xD86C1F2C, 0xDD6DD96C, ++0xD26DEA00, 0x89003A22, 0xD1587A01, 0x88016010, ++0x56F98B03, 0x4218E201, 0xD1682622, 0x0009410B, ++0x440BD467, 0xD5670009, 0x0009450B, 0x6010D14C, ++0x8B108801, 0xE650D14B, 0x46186212, 0x8B083266, ++0x56FAD147, 0x2120E200, 0xCB016062, 0x2602A003, ++0x72012710, 0x60822122, 0x89098801, 0xE2C8D15A, ++0x622C6612, 0x89033626, 0x6010D158, 0x8BC88801, ++0x51F76792, 0x217252F6, 0xD6555191, 0x55FB2212, ++0x52FC6462, 0x55612542, 0x2252E400, 0x61436643, ++0x05DE6013, 0x36CC4608, 0x02DE2652, 0xC9036021, ++0x8B028801, 0x720162E2, 0x74012E22, 0x36B3664C, ++0x71048FEE, 0x66C2D147, 0x45286512, 0x265B4518, ++0x60822C62, 0x89018801, 0x0009A168, 0x6272D742, ++0x8B132228, 0xD726D541, 0x6552D441, 0x51436672, ++0x316C365C, 0x27622668, 0x14138D05, 0x6262D63D, ++0xB1A57201, 0xD61E2622, 0x2622E200, 0x52916692, ++0x8B013620, 0x0009A144, 0x6061A06E, 0x001C001C, ++0x001D4020, 0x0000B38E, 0xFFFF0000, 0x12340000, ++0x001E1015, 0x00201278, 0x002018A0, 0x00201922, ++0x0020128C, 0x001C3510, 0x001C3624, 0x001E212C, ++0x0020397C, 0x00203514, 0x00203984, 0x00203990, ++0x0020399C, 0x002039F8, 0x002039FC, 0x002039A4, ++0x002039A5, 0x002039A8, 0x00117700, 0x00203A12, ++0x00203578, 0x001142D8, 0x00203A14, 0x00203A16, ++0x001C3D30, 0x00117718, 0x001C3D00, 0x001C1000, ++0x001C36F8, 0x00117734, 0x001C3684, 0x00117710, ++0x001C3520, 0x00117600, 0x00117740, 0x001C1028, ++0x0020358C, 0x002039AC, 0x7FFFFFFF, 0x00201734, ++0x002032BE, 0x002022E8, 0x00203DC0, 0x002039FA, ++0x00203584, 0x002039EC, 0x001C3D2C, 0x001C36B0, ++0x0020351C, 0x0011775C, 0x8801C90F, 0xA0CF8901, ++0xD17C0009, 0x36206212, 0xD47B8904, 0x2421E200, ++0x2162A0CC, 0x6211D179, 0x89012228, 0x0009A0C3, ++0xE202D775, 0x75016571, 0x3123615D, 0x27518D02, ++0x0009A0BC, 0xD27255F2, 0x62226052, 0x40094019, ++0xC90F4009, 0x8F19880A, 0x52F31F2D, 0x40196022, ++0x40094009, 0x8808C90F, 0xA0A78901, 0x60630009, ++0x51F255F8, 0xE701CB01, 0x2502D263, 0xE1002172, ++0x2211D564, 0x74016452, 0x2542A098, 0x8B3F8805, ++0x602252F3, 0x40094019, 0xC90F4009, 0x8B168802, ++0xE5FFD45D, 0x655D6742, 0x8B102758, 0x6272D75B, ++0x8B0C3260, 0x55F257F8, 0x2762E101, 0xD5522512, ++0xD757E400, 0x62722541, 0xA0777201, 0x52F32722, ++0x40196022, 0x40094009, 0x8805C90F, 0x31B38B6E, ++0xD5508B6C, 0x615257F4, 0x7101E240, 0x64722512, ++0x1F4DD14D, 0x42182419, 0x8B033420, 0x6262D64B, ++0x26227201, 0xE200D640, 0x2621B0AA, 0x0009A056, ++0x3123E220, 0x88038B52, 0x52F38B1E, 0x40196022, ++0x40094009, 0x8803C90F, 0xD7418B16, 0x647251F4, ++0x7401D23D, 0x65122742, 0x1F5DE640, 0x46182529, ++0x8B033560, 0x6262D63B, 0x26227201, 0xE200D62E, ++0x2621B086, 0x0009A010, 0xD738D137, 0xD22A6412, ++0xE5007401, 0x21423A76, 0x22518F06, 0xEA00D634, ++0x72016262, 0x2622B074, 0x2FB2D532, 0x95406652, ++0xD4305BF1, 0x36205241, 0x60618910, 0x8B01C803, ++0x2B22E201, 0x8FF54510, 0x57F15664, 0x6272E1F0, ++0x41284118, 0x2722221B, 0x6BF2A008, 0x6BF2A006, ++0xE200D615, 0xD1152621, 0x2121E200, 0xE20256F5, ++0x42186662, 0x26284228, 0x1F6D8D0C, 0xD61FD11E, ++0x460B6511, 0x2008645D, 0x57F58904, 0x6272D11C, ++0x27222219, 0xD11BE201, 0x66122822, 0x8B012668, ++0x0009AE17, 0x450BD518, 0xD1180009, 0xAE10E600, ++0x07D12160, 0x00203A0C, 0x00203A10, 0x00203A18, ++0x001C3DC0, 0x0011772C, 0x001C3B88, 0x002039F4, ++0x0011773C, 0x00117744, 0x0000F000, 0x00117764, ++0x00117748, 0x00117768, 0x0011776C, 0x01FFFFFF, ++0x0011774C, 0x00203584, 0x001142D8, 0x00114774, ++0xFDFFFFFF, 0x00203DC0, 0x0020246C, 0x002039FA, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xD11F7FF4, 0x6212DE1F, 0x67E25411, 0xD41E1F41, ++0x1F722F22, 0x6743D51D, 0x7794D21D, 0x5A425841, ++0x6C726942, 0x6D225B16, 0xE6006052, 0x2502CB20, ++0x7601E540, 0x3253626D, 0x62F28BFB, 0x212255F1, ++0x55F21151, 0x2E52D613, 0x14A21481, 0xD4122492, ++0x11B627C2, 0x674226D2, 0xD911DA10, 0x2A72E801, ++0x1A8C490B, 0x4218E201, 0x7F0C1A2C, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x000068F6, ++0x001C3B9C, 0x001C3D98, 0x001C3700, 0x001C3500, ++0x001C5960, 0x001C8960, 0x0020358C, 0x001C3D00, ++0x00201610, 0x2F962F86, 0x2FC62FA6, 0x2FE62FD6, ++0x4F124F22, 0x7F884F02, 0xE018DEB2, 0xD4B261E0, ++0x61E30F14, 0x62107101, 0x440BE01C, 0x20080F24, ++0x8F126D03, 0xD4AD1F08, 0x6740DDAD, 0x657CD4AD, ++0x470BD7AD, 0xD2AD0009, 0x621C6120, 0x46086623, ++0x36284608, 0x3D6C4608, 0xE01C1FD8, 0xE58004FC, ++0x604C66E2, 0x3050655C, 0x2D628F17, 0x01FCE018, ++0xDEA3E500, 0x641CA008, 0x6753655D, 0x607037EC, ++0x31DC6153, 0x80147501, 0x3243625D, 0xD49D8BF4, ++0xE200D59D, 0xA27F2421, 0x20082521, 0xE0188B13, ++0xE50001FC, 0xA009DE96, 0x655D641C, 0x32EC6253, ++0x62536722, 0x32DC6672, 0x75041261, 0x3243625D, ++0xA2698BF3, 0x88012D10, 0xE0188B16, 0xE40001FC, ++0x671C2D40, 0x624DDE8A, 0x8B013273, 0x0009A25C, ++0x6DE3644D, 0x7D046243, 0x32EC6643, 0x652236DC, ++0x74086162, 0x2512AFEF, 0x8B198804, 0x01FCE018, ++0x2D70E700, 0x1FD56D1C, 0x627DDE7D, 0x8B0132D3, ++0x0009A242, 0x6173677D, 0x31EC65E3, 0x75046412, ++0x365C6673, 0x61426262, 0x21297708, 0x2412AFED, ++0x8B198805, 0x01FCE018, 0x2D70E700, 0x1FD46D1C, ++0x627DDE6F, 0x8B0132D3, 0x0009A226, 0x6173677D, ++0x31EC65E3, 0x75046412, 0x365C6673, 0x61426262, ++0x212B7708, 0x2412AFED, 0x8B598831, 0x61E6DE67, ++0x61E31F19, 0x64E27104, 0x1F4A6216, 0x1F2B6416, ++0x75E46513, 0x66536712, 0x1F4C7604, 0x64521F7D, ++0xD75F6E66, 0x27E0D25F, 0xDE5F6062, 0xC9013245, ++0x65622E00, 0x4609060A, 0x4609D15C, 0x46094509, ++0x21501F4E, 0xB2B0646D, 0x620D1F6F, 0x8B012228, ++0x0009A1EA, 0xD756DE55, 0x661C61E0, 0x6410D150, ++0x470B654C, 0x7FFC54FF, 0x2FE25EFE, 0x51FE7FFC, ++0x2F12E040, 0x55FBD14F, 0x57FD56FC, 0x04FE410B, ++0xD24D7F08, 0xE11C640D, 0x1D412D10, 0xD44B6522, ++0x67421D52, 0x1D73DE4A, 0xD24A65E2, 0x67221D54, ++0x1D75D249, 0xD2496E22, 0x66221DE6, 0x1D67A1BC, ++0x89018830, 0x0009A08E, 0xE340D538, 0x33FC6156, ++0x23126456, 0x71046153, 0x67521341, 0x13726416, ++0x7EE46E13, 0x65E66212, 0x66E3D731, 0x13246EE2, ++0x760427E0, 0x6062D22F, 0x3255DE2F, 0x2E00C901, ++0x060A6E62, 0xD12D4609, 0x4E094609, 0x13434609, ++0x646D21E0, 0xB2501F5E, 0x620D1F6F, 0x8B012228, ++0x0009A18A, 0xDE25D522, 0x61E06450, 0xD724654C, ++0x470B54FF, 0x7FFC661C, 0x06FEE054, 0x7FFC2F62, ++0xEE4001FE, 0x2F123EFC, 0x55E2D125, 0x57E456E3, ++0x64E2410B, 0xD21C7F08, 0xE11C640D, 0x1D412D10, ++0xD61A6522, 0x67621D52, 0x1D73DE19, 0xD2196EE2, ++0x62221DE4, 0xD2181D25, 0x1D266222, 0x6222D217, ++0x1D27A15A, 0x00117800, 0x00202A18, 0x00203996, ++0x002035BC, 0x00203A7C, 0x002018D0, 0x00203995, ++0x00117804, 0x00203A14, 0x00203A16, 0x00117810, ++0x00203991, 0x10624DD3, 0x00203992, 0x00203993, ++0x00114AA4, 0x00200F68, 0x001C5864, 0x001C6864, ++0x001C7864, 0x001C59BC, 0x001C69BC, 0x001C79BC, ++0x00200FC0, 0x8B048833, 0x470BD7A2, 0xA123EE00, ++0x88282DE0, 0xA0D38901, 0xDE9F0009, 0x62E1E143, ++0x3216E054, 0x0FE68F02, 0x2E21E240, 0x622D62E1, ++0x8B013217, 0x0009A0BC, 0xE50185E1, 0x8B013056, ++0x0009A0B6, 0x2D10E101, 0x64E1B111, 0x06FEE054, ++0x6261E143, 0x3517652D, 0xE6408945, 0x8B0C3563, ++0xE058E41A, 0xE5000F45, 0x72C0E05C, 0x60230F55, ++0x6703C907, 0xA014E060, 0x66530F75, 0x46214621, ++0x46214621, 0x45214621, 0xE0587618, 0x0F654521, ++0xE0034521, 0xE05C2509, 0xE0070F55, 0xE0602209, ++0xE8540F25, 0x858238FC, 0x640D65F3, 0x1844B170, ++0xDD7A8584, 0x85866C0D, 0x610D4C08, 0x410860C3, ++0xE00F0EFE, 0x18154D0B, 0x2E296207, 0x668260C3, ++0x85620FE6, 0x4D0B5185, 0x2E0B600D, 0x548460C3, ++0xB13C0FE6, 0xE05465F3, 0xE5400EFE, 0xE06C62E1, ++0x3653662D, 0x0F668D41, 0xC9036023, 0x40004008, ++0x61036403, 0xD965E070, 0x0F46E5FF, 0xE074655C, ++0x60530F96, 0x6263490B, 0x42214221, 0x42214221, ++0x42006723, 0x4200327C, 0x6C074621, 0x4621E054, ++0x606309FE, 0x4008C903, 0x790630FC, 0x6A036D2D, ++0x65F3E800, 0x64D3B124, 0xE0706EA2, 0x2AE22EC9, ++0x01FE6694, 0x666CE074, 0x470B07FE, 0x2E0B6063, ++0x65F32AE2, 0xB0FA64D3, 0x628D7801, 0x32E3EE06, ++0x7D018FE7, 0x0EFEE054, 0xE05462E1, 0x420006FE, ++0x760C8561, 0x701B302C, 0xE4006103, 0xE70465F3, ++0x68667401, 0x3973694D, 0x8FF92582, 0x65F37504, ++0x641DB0DD, 0x0EFEE054, 0x64E1B09C, 0x0009A054, ++0xD43B56F8, 0xEA01D23B, 0x26A0420B, 0x0009A04C, ++0x06FCE01C, 0x8829606C, 0x5CF88B08, 0xE200D636, ++0x52612C20, 0x642DB04B, 0x0009A03E, 0x666CE681, ++0x8B043060, 0x420BD231, 0xA03554F8, 0xE6820009, ++0x3060666C, 0xD22E8B04, 0x54F8420B, 0x0009A02C, ++0x666CE683, 0x8B0A3060, 0xDA2755F8, 0x2590E900, ++0xD82855A1, 0x2852D628, 0xA01D52A2, 0xE6922620, ++0x3060666C, 0xD2208B08, 0x5C21D824, 0x6CCC52F8, ++0x28C1E600, 0x2260A010, 0x666CE693, 0x8B063060, ++0xD61F59F8, 0xE201EA00, 0xA00529A0, 0xD6162621, ++0xD21DD41C, 0x6562420B, 0x4F067F78, 0x4F264F16, ++0x6DF66EF6, 0x6AF66CF6, 0x000B69F6, 0x4F2268F6, ++0xE240614D, 0x89323123, 0x3127E21F, 0x8B27D713, ++0xD406614D, 0xE00171E0, 0x5671440B, 0x26596507, ++0x1761A025, 0x00200FBC, 0x00117804, 0x00203470, ++0x00203A9C, 0x002018C0, 0x00117800, 0x00115F00, ++0x00116058, 0x0020397C, 0x00203990, 0x00203A1A, ++0x00203A16, 0x00203AB4, 0x002018D0, 0x001C3704, ++0xE001D490, 0x6672440B, 0x26596507, 0x4F262762, ++0x0009000B, 0x614D4F22, 0x3123E240, 0xE21F8912, ++0xD7893127, 0x614D8B08, 0x5671D286, 0x420B71E0, ++0x260BE001, 0x1761A006, 0x6672D282, 0xE001420B, ++0x2762260B, 0x000B4F26, 0xE6400009, 0x46284618, ++0x6252D57E, 0x89FC2268, 0x0009000B, 0x4618E680, ++0xD57A4628, 0x22686252, 0x000B89FC, 0xA0010009, ++0x7201E200, 0x8BFC3242, 0x0009000B, 0x4618E680, ++0xD5734628, 0x22686252, 0x000B8BFC, 0x2FE60009, ++0x7FFC4F22, 0xBFF16E53, 0x61E22F42, 0xE280D66D, ++0x54E11615, 0x16464218, 0x422855E2, 0x57E31657, ++0x16786EF2, 0x26E22E2B, 0x4F267F04, 0x6EF6AFCE, ++0x2FD62FC6, 0x4F222FE6, 0x6C53DD62, 0x6E43BFD6, ++0x2DE2BFBB, 0x0009BFD2, 0x2C1251D5, 0x1C4154D6, ++0x1C5255D7, 0x1C6356D8, 0x6EF64F26, 0x000B6DF6, ++0x61636CF6, 0xA004E600, 0x62564109, 0x24227601, ++0x36127404, 0x000B8BF9, 0xD6530009, 0x8562E500, ++0xA00B674D, 0x655D610D, 0x40006053, 0x305CD44F, ++0x024D4008, 0x3270622D, 0x75018905, 0x3213625D, ++0x000B8BF1, 0x000BE000, 0x2FE6E001, 0x54416743, ++0x4E08EE7F, 0x4E28D246, 0x25E96543, 0x60436E21, ++0x9E7562ED, 0x4529C903, 0xE60032E3, 0x8D456103, ++0x21184509, 0xD23F8B05, 0x002C6053, 0xA08AC93F, ++0x60136603, 0x8B268801, 0x880C6053, 0xD53A8B04, ++0xC93F8453, 0x6603A07F, 0x8B048808, 0x84E2DE36, ++0xA078C93F, 0x880D6603, 0x8B03D633, 0xC93F8461, ++0x6603A071, 0x88096260, 0x622C8F09, 0xE014DE2C, ++0x655C05EC, 0x60233258, 0xA064C93F, 0x60236603, ++0xA060C93F, 0x88026603, 0xE0078B5D, 0x60432509, ++0x8905C810, 0x6053D225, 0xC93F002C, 0x6603A053, ++0x6053DE23, 0xC93F00EC, 0x6603A04D, 0x88016013, ++0x60538B19, 0x8B04880C, 0x8423D21E, 0xA042C93F, ++0x88086603, 0xD51B8B04, 0xC93F8452, 0x6603A03B, ++0xD618880D, 0x84618B03, 0xA034C93F, 0x60606603, ++0xA030C93F, 0x88026603, 0xE0078B2D, 0x60432509, ++0x8923C810, 0x6053DE10, 0xC93F00EC, 0x6603A023, ++0x00000BB8, 0x00203470, 0x001C3704, 0x001C373C, ++0x001C3700, 0x001C370C, 0x00114000, 0x00114008, ++0x001142D8, 0x001142E4, 0x001142E8, 0x001142F5, ++0x001142ED, 0x001142FD, 0x00114309, 0x6053D209, ++0xC93F002C, 0x60136603, 0x8B038802, 0xC8106043, ++0x76028900, 0xC93F6063, 0x40004018, 0x1741240B, ++0x6EF6000B, 0x00114301, 0x0009A16E, 0x2FE62FD6, ++0xDD944F22, 0xA0049EB2, 0xD4930009, 0x420BD293, ++0x62D265D2, 0x8BF822E8, 0x0009A004, 0xD28FD490, ++0x55D1420B, 0x22E852D1, 0xA0048BF8, 0xD48D0009, ++0x420BD28A, 0x52D255D2, 0x8BF822E8, 0x0009A004, ++0xD286D489, 0x55D3420B, 0x22E852D3, 0xA0048BF8, ++0xD4860009, 0x420BD281, 0x52D455D4, 0x8BF822E8, ++0x6EF64F26, 0x6DF6000B, 0x2FD62FC6, 0x4F222FE6, ++0x6E636C73, 0x6D53B01A, 0x64D357F4, 0xB05F65E3, ++0xB07566C3, 0xB0A40009, 0xB0A80009, 0xB0AC0009, ++0xB0AC0009, 0xB0AF0009, 0xB03154F5, 0x6CCD6C03, ++0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, 0x3412D170, ++0xD6700529, 0x2650D770, 0x2742000B, 0x0009A018, ++0x2FD62FC6, 0x4F222FE6, 0x6E636C73, 0x6D53BFEE, ++0x64D357F4, 0xB03365E3, 0xB08D66C3, 0xB00F54F5, ++0x6CCD6C03, 0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, ++0xE503D162, 0xD763D462, 0x21524518, 0x2472000B, ++0xD45FD15E, 0x2162E600, 0x2462000B, 0xBF734F22, ++0xBF73E40A, 0xD25C0009, 0x4118E104, 0xE40AE500, ++0xBF692212, 0xD7592252, 0xCB206072, 0x000B4F26, ++0x4F222702, 0x410BD156, 0xD556E400, 0x4F26452B, ++0xD1552FE6, 0x66126E63, 0x92104418, 0x44084528, ++0x45002629, 0x265B4408, 0x264B4400, 0x21624708, ++0xD14E4708, 0x217227EB, 0x6EF6000B, 0x1FFF03F0, ++0x4F222FE6, 0xE101DE4A, 0xBF3DE40A, 0x67E32E12, ++0xE500776C, 0xE204E130, 0x2752E40A, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27222712, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x175ABF18, 0x2E62E600, 0x000B4F26, ++0xD2346EF6, 0xE441E101, 0x000B2212, 0xD1322242, ++0xE605D432, 0x000B2162, 0x000B2462, 0xD2300009, ++0xE40AE601, 0x2262AF00, 0x2FC62FB6, 0x2FE62FD6, ++0x7FFC4F22, 0x6C43DB2B, 0xED0060B2, 0x2B02CB03, ++0xC90360B2, 0x6E03A008, 0x89073DC2, 0xE46460B2, ++0xB07CC903, 0x7D016E03, 0x8BF52EE8, 0x8F043DC2, ++0xD4212FE1, 0x460BD621, 0x62F10009, 0x6023622D, ++0x89FFC801, 0x7F046023, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x001C3B88, 0x00203AC8, 0x002018D0, ++0x00203AD0, 0x00203AD8, 0x00203AE0, 0x00203AE8, ++0x0025E720, 0x00203DBC, 0x00203980, 0x001C5968, ++0x001C3B40, 0x000F8000, 0x001D4004, 0x001C3500, ++0x002015E4, 0x00201610, 0x001C5814, 0x001C59D0, ++0x001C5830, 0x001C6268, 0x001C59A4, 0x001C639C, ++0x001C581C, 0x001C5860, 0x00203AF0, 0x002018C0, ++0x8F014411, 0x6043604B, 0x0009000B, 0x5651D52B, ++0x46286052, 0x306C000B, 0x2FC62FB6, 0x2FE62FD6, ++0x4F124F22, 0xBFF14F02, 0x6B036E43, 0xDD25DC24, ++0x0009BFEC, 0x3C0530B8, 0x4609060A, 0x46014609, ++0x020A3D65, 0x42094209, 0x32E24209, 0x4F068BF0, ++0x4F264F16, 0x6DF66EF6, 0x000B6CF6, 0x2FC66BF6, ++0x2FE62FD6, 0x4F124F22, 0xBFCF4F02, 0x6C036E43, ++0xBFCBDD13, 0x30C80009, 0x060A3D05, 0x46094609, ++0x36E24601, 0x4F068BF5, 0x4F264F16, 0x6DF66EF6, ++0x6CF6000B, 0x4F222FE6, 0xE102DE0B, 0xE403E500, ++0xBFB92E12, 0xE6062E52, 0xE7004618, 0x2E62E403, ++0x4F262E72, 0x6EF6AFB0, 0x0009000B, 0x001C1040, ++0xCCCCCCCD, 0x10624DD3, 0x001D4004, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0xE5007F98, ++0x6453E710, 0x6B534728, 0xEE1ADCBC, 0x6153655D, ++0x315C4108, 0x75014108, 0x6043317C, 0x0F16665D, ++0xED0060B3, 0x21B136E3, 0x81128111, 0x11D28113, ++0x11D411D3, 0x74048FEA, 0xD8B167F2, 0x1871D9B1, ++0x58F12872, 0x1981D1B0, 0x59F22982, 0x5DF45AF3, ++0x54F65EF5, 0x21921191, 0x11A211A3, 0x11D411D5, ++0x11E611E7, 0x11481149, 0xDAA855F7, 0x57F8EE00, ++0x52F9DDA7, 0x64E3D6A7, 0x2A521A51, 0xD8A7D9A6, ++0x2D72EAEF, 0x6AAC2622, 0x6DE36EED, 0x61E34D08, ++0x41083DEC, 0x31EC4D08, 0x60B33D9C, 0x2DB14108, ++0xE05081D1, 0xE79F4108, 0x41084008, 0x81D2677C, ++0x318C60B3, 0x3472E200, 0x1DD281D3, 0xD4931D13, ++0x1D248D01, 0x65D3D48F, 0x7E01B0B2, 0x34A264ED, ++0xDA8C8BDA, 0x68A22FD2, 0x4829DD91, 0x64A22D82, ++0x694D7DFC, 0x2D92D286, 0x4E296E22, 0x2DE27D0C, ++0x6AD36822, 0xD784618D, 0x6D722A16, 0xD583D489, ++0x5E7224D2, 0x14E2D688, 0xEE005174, 0x58761414, ++0x1486D186, 0xE7105978, 0x62521498, 0x142A65E3, ++0x64E326E2, 0x644DE600, 0x48086843, 0x4808384C, ++0x6053381C, 0x28B10C86, 0x60B309CE, 0x60538191, ++0x60430ACE, 0x605381A2, 0x60B30DCE, 0x605381D3, ++0x740108CE, 0x09CE1882, 0x19E3624D, 0x32730ACE, ++0x8FE01A64, 0xD96A7504, 0x6C92E003, 0x2CB14018, ++0xDA6F6D92, 0xE05081D1, 0x40086E92, 0x619281E2, ++0x811360B3, 0xE6006492, 0x67921442, 0x17A3D468, ++0xE1FF6892, 0xE7031864, 0x46086563, 0x7501364C, ++0x665D2612, 0x8BF83673, 0xE003DC5A, 0x40186DC2, ++0x6EC22DB1, 0x81E1D25F, 0xEE0061C2, 0x64C21112, ++0x1423E024, 0xD45B65C2, 0x67C215E4, 0x8172E580, ++0x66E368C2, 0x655C8183, 0x6963666D, 0x6A6D7604, ++0x3A53394C, 0x29E28FF8, 0xDC54DB53, 0x740424B2, ++0x7F6824C2, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0x614268F6, 0xC8036011, 0xE5008F03, ++0x3420D23C, 0x60118B06, 0x8802C903, 0xD2398B06, ++0x8B033420, 0x65135612, 0x24225264, 0x6053000B, ++0x2FE62FD6, 0x7FEC4F22, 0x62536E53, 0x6D43E550, ++0x4508E400, 0xE101A001, 0x60435224, 0x81212211, ++0x60538123, 0x56E28122, 0x8BF53620, 0x16E4D238, ++0xE61464F3, 0x65E3420B, 0xE4FC65E1, 0x2E512549, ++0x65F361F1, 0x2F112149, 0xD13154D1, 0xE614410B, ++0x607157D1, 0x2701CB01, 0x7F141DE1, 0x6EF64F26, ++0x6DF6000B, 0x2FE62FD6, 0x7FEC4F22, 0x66536E53, ++0x6D43E5FC, 0x20596061, 0x2601CB01, 0x326052E2, ++0x12E48B06, 0x31E051E2, 0x52D18B04, 0x1E22A002, ++0x5664AFF0, 0x64F3D21E, 0x420BE614, 0x67E165E3, ++0x2719E1FC, 0x67F12E71, 0x271954D1, 0x65F3D118, ++0x410BE614, 0x52D12F71, 0xCB016021, 0x1DE12201, ++0x4F267F14, 0x000B6EF6, 0x00006DF6, 0x002039AC, ++0x0020357C, 0x00203584, 0x0020358C, 0x002035B4, ++0x00203998, 0x002039A0, 0x00100208, 0x001014C0, ++0x001E210C, 0x001C3D00, 0x002039EC, 0x001000C8, ++0x00117880, 0x00117780, 0x00040020, 0x0026C401, ++0x00200D42, 0x4F222FE6, 0xDE42624C, 0x42004208, ++0x3E2CA005, 0xD4405252, 0xBF695624, 0x65E22E62, ++0x352052E1, 0xD63D8BF6, 0x4F262622, 0x6EF6000B, ++0x2FC62FB6, 0x2FE62FD6, 0xDC394F22, 0x52C1DB39, ++0x362066C2, 0x6061891C, 0x8801C903, 0xDE348918, ++0xBF38DD35, 0x650364E3, 0x66B28503, 0x3262620D, ++0xD4328907, 0x0009BF76, 0x4D0BD431, 0xAFE60009, ++0xBF3D0009, 0xD42F64E3, 0x00094D0B, 0x0009AFDF, ++0x2262D22D, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x2FD62FC6, 0x4F222FE6, 0xDD29DC28, 0x6E4360C2, ++0x04DE4008, 0xE614D127, 0x65E3410B, 0xD127D726, ++0x55E227E2, 0x35E05254, 0x21228F04, 0x400860C2, ++0x122202DE, 0x605365C2, 0x75014008, 0x0DE606DE, ++0xC90F6053, 0x60632C02, 0x6EF64F26, 0x000B6DF6, ++0x85436CF6, 0x650D5643, 0x622D6262, 0x35277204, ++0xE1008F0C, 0x2268960C, 0xD6158B03, 0x72015261, ++0xD6131621, 0x6262E101, 0x26227201, 0x6013000B, ++0x000001FF, 0x0020358C, 0x00203584, 0x001C3D00, ++0x002035B4, 0x0020397C, 0x002018C0, 0x0020357C, ++0x00203B18, 0x00203B1C, 0x001C3D28, 0x002039EC, ++0x002039AC, 0x00200D42, 0x002039F0, 0x002039F4, ++0x00117754, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x7FF84F22, 0x6C22D241, 0xC80360C3, 0xDE40896E, ++0xDA41DB40, 0x52B1D941, 0x362066B2, 0x60618945, ++0x8801C903, 0xDD3B8941, 0x420BD23D, 0x650364D3, ++0x60A12F02, 0x89328801, 0x85145153, 0x8840600C, ++0x1F118F0C, 0xD5376191, 0x641D450B, 0x8B262008, ++0xD7356691, 0x646D470B, 0x8B202008, 0x420BD233, ++0x51F154F1, 0xC8208511, 0xD1318904, 0x021EE050, ++0x01267201, 0x420BD22F, 0x200864F2, 0x64D38907, ++0x4D0BDD2D, 0xD12D65F2, 0xAFC4E601, 0xD22C2162, ++0x420B65F2, 0xD72B64E3, 0xAFBCE601, 0xD2262762, ++0x420B65F2, 0xAFB664D3, 0xDE270009, 0xDA28DD27, ++0x52D1DB28, 0x362066D2, 0x60618918, 0x8801C903, ++0xD4228914, 0x450BD516, 0x56030009, 0x8F0436E0, ++0xE2016503, 0xAFEC2A20, 0xD41F2B52, 0x420BD216, ++0xD7180009, 0x4118E101, 0x2712AFE3, 0xC80460C3, ++0xD21A8902, 0x0009420B, 0x4F267F08, 0x6DF66EF6, ++0x6BF66CF6, 0x000B6AF6, 0x000069F6, 0x001E2100, ++0x0020358C, 0x00203584, 0x00203A14, 0x001142D8, ++0x002014A6, 0x00115EA2, 0x00114774, 0x00200D8A, ++0x0020351C, 0x002016C2, 0x002014D0, 0x001E212C, ++0x00201534, 0x001C3D30, 0x00117880, 0x0020357C, ++0x0020399C, 0x00203998, 0x002035B4, 0x00200644, ++0xE601D203, 0x1265D503, 0x000B2252, 0x00001266, ++0x001C1010, 0x0000C34F, 0x0009000B, 0x0009000B, ++0x0009000B, 0x0009000B, 0xE000000B, 0xE000000B, ++0x0009000B, 0xE4FDD59D, 0xD69D6152, 0x25122149, ++0x74016052, 0x2502CB01, 0xD19A6752, 0x25722749, ++0xC8406010, 0x60628902, 0x2602CB04, 0xE1F76462, ++0x26422419, 0xE7016062, 0x2602C9CF, 0xE5026062, ++0x2602CB10, 0x47186062, 0x2602CB03, 0x000B1652, ++0xD58D1673, 0xD28ED78D, 0xE100D48E, 0x2511E600, ++0x22102711, 0x2461AFCE, 0xD28B664C, 0x362C4600, ++0xCB106060, 0x2600000B, 0xD287654C, 0x352C4500, ++0xE1EF6650, 0x000B2619, 0x664C2560, 0x4600D283, ++0x6060362C, 0x000BCB10, 0x654C2600, 0x4500D27F, ++0x6650352C, 0x2619E1EF, 0x2560000B, 0xD27A664C, ++0x362C4600, 0xCB086060, 0x2600000B, 0xD276654C, ++0x352C4500, 0xE1F76650, 0x000B2619, 0x664C2560, ++0x4600D272, 0x6060362C, 0x000BCB08, 0x654C2600, ++0x4500D26E, 0x6650352C, 0x2619E1F7, 0x2560000B, ++0xD669624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0x624C600C, 0x4200D664, 0x6020326C, ++0x4021C908, 0x40214021, 0x600C000B, 0x644CD160, ++0x6240341C, 0x602C000B, 0x644CD15E, 0x6240341C, ++0x602C000B, 0x4F222FE6, 0x645C6E43, 0x3467E60A, ++0xBFEB8914, 0x640C0009, 0x880160EC, 0xE00F8B02, ++0x2409A002, 0x44094409, 0xE60A624C, 0x89053263, ++0x644CBFE2, 0x6023620C, 0x8B00C880, 0x6023E200, ++0x000B4F26, 0x4F226EF6, 0x6062D64B, 0x8B038801, ++0x0009B256, 0x0009A003, 0xE640D248, 0xD6482260, ++0x4F26E200, 0x2622000B, 0xD6434F22, 0x88026062, ++0xB29F8B01, 0xD6420009, 0x4F26E200, 0x2622000B, ++0xD43ED53D, 0xE701E100, 0x000B2512, 0xD23B2470, ++0x000BE604, 0x4F222260, 0xD13BD43A, 0x0009410B, ++0xE1FDD53A, 0xD23A6650, 0xE7002619, 0x4F262560, ++0x2270000B, 0xD5374F22, 0x6152D237, 0x611DD737, ++0x64522512, 0x242BE6FF, 0xD4352542, 0x666DD22E, ++0x2762420B, 0xE1FBD52D, 0x27196750, 0x000B4F26, ++0x4F222570, 0xD128D42F, 0x0009410B, 0xE7F7D527, ++0x26796650, 0x000B4F26, 0xD5242560, 0x62509425, ++0x000B2249, 0xD5212520, 0x6250E4BF, 0x000B2249, ++0x4F222520, 0x8522D224, 0x2008600D, 0x88018911, ++0x88038944, 0x88058946, 0x88068948, 0x8808894E, ++0x88098954, 0x880A895A, 0x880B8960, 0xA06D8966, ++0xB06F0009, 0xA06A0009, 0xFF7F600C, 0x001E2148, ++0x001E1108, 0x001E1000, 0x00203A4C, 0x00203A4E, ++0x00203A6D, 0x00203A30, 0x001E103F, 0x001E105F, ++0x001E102F, 0x001E1090, 0x00203A54, 0x001E100B, ++0x00203A50, 0x00203B20, 0x002018C0, 0x001E1028, ++0x00203A6C, 0x001D4020, 0x98760000, 0x001C1000, ++0x00203B2C, 0x00203B3C, 0x00203A24, 0x0009B04C, ++0x600CA035, 0x0009B055, 0x600CA031, 0x6260D684, ++0x8B2B2228, 0x0009B061, 0x600CA029, 0x6260D680, ++0x8B232228, 0x0009B069, 0x600CA021, 0x6260D67C, ++0x8B1B2228, 0x0009B0C7, 0x600CA019, 0x6260D678, ++0x8B132228, 0x0009B0CD, 0x600CA011, 0x6260D674, ++0x8B0B2228, 0x0009B125, 0x600CA009, 0x6260D670, ++0x8B032228, 0x0009B13D, 0x600CA001, 0x4F26E000, ++0x0009000B, 0xD26CD16B, 0xD56C8412, 0x4000C90F, ++0xD76B012D, 0xE403D66B, 0xE20F611C, 0x2540E001, ++0x25202712, 0x2602000B, 0xE601D262, 0x30668523, ++0xE0008D05, 0xD663D260, 0xE0018122, 0x000B2602, ++0xD25C0009, 0x600D8523, 0x89052008, 0x8B0A8801, ++0x6060D65D, 0x2600CB01, 0xD457D65A, 0xE001E101, ++0x000B2612, 0x000B8142, 0xD152E000, 0x8513E501, ++0x640D4518, 0x66033453, 0xE0008D05, 0xD551D253, ++0x2260E001, 0x000B2502, 0x4F220009, 0x8513D149, ++0x6453650D, 0x62494419, 0x227D672E, 0x8801602C, ++0x88028909, 0x88038910, 0x8806891A, 0x88078935, ++0xA04C893B, 0xD5460009, 0x6652D746, 0x2762D446, ++0x622C6261, 0x2421A038, 0x2228625C, 0xD4438B3F, ++0x6642D540, 0x2562D440, 0x24018561, 0x6203A02C, ++0x2008605C, 0x88108907, 0x88208908, 0x88308909, ++0xA02C890A, 0xD23A0009, 0x6222A008, 0xA005D239, ++0xD2396222, 0x6222A002, 0x6262D638, 0xD432D531, ++0x66212522, 0xA00F626C, 0xD6352421, 0x6261D52D, ++0x622CD42D, 0xA0072562, 0xD6322421, 0x8561D529, ++0x2562D429, 0x62032401, 0x662D8515, 0x3617610D, ++0x65038F01, 0xB0CB2451, 0xA0010009, 0xE000E001, ++0x000B4F26, 0xD6190009, 0xD427E101, 0x65412610, ++0xD118D717, 0xE20F655D, 0x2752E001, 0x000B2620, ++0x2FE62102, 0xD20F4F22, 0x640C8523, 0x8B082448, ++0xD511D61D, 0x2621E200, 0x940F8451, 0xA0482049, ++0xDE0D8051, 0xC84060E0, 0xE2018D32, 0x89443427, ++0xD216D615, 0x2641420B, 0x0009A030, 0x0000FF7F, ++0x00203A6D, 0x00203A24, 0x00203A30, 0x001E1100, ++0x001E100C, 0x00203A50, 0x001E1000, 0x001E1001, ++0x00203A58, 0x00203A38, 0x00203A3C, 0x00203A40, ++0x00203A5C, 0x00203A60, 0x00203A64, 0x00203A68, ++0x00203E20, 0x00203E2A, 0x00203A4A, 0x002027F2, ++0x89123427, 0xD294D693, 0x2641420B, 0xCB8084E1, ++0x80E1B0F5, 0xD69160E0, 0x2E00CB04, 0xC93F6060, ++0xD68F2600, 0xA001E001, 0xE0002602, 0x000B4F26, ++0xD68C6EF6, 0xC8806060, 0xD2868919, 0x88016021, ++0xD2898B15, 0x8524E501, 0x89103056, 0xE203D187, ++0x2120D487, 0xE00B6541, 0x0656655D, 0xE40FD585, ++0x2140E702, 0xD77E2571, 0x000BE001, 0x000B2702, ++0x2FE6E000, 0xDE804F22, 0xC88084E1, 0xD57A892C, ++0x20088554, 0x61038F28, 0x8553D77C, 0x64036672, ++0x8566650C, 0x3520620C, 0xD6798B1E, 0x651CD774, ++0x2651644C, 0x60E02741, 0x8904C840, 0x420BD275, ++0xA0030009, 0xD2680009, 0x0009420B, 0x0009B09F, ++0xE201D167, 0x60E02122, 0xCB04D464, 0x60402E00, ++0x2400C93F, 0x6023A001, 0x4F26E000, 0x6EF6000B, ++0x2FB62FA6, 0x2FD62FC6, 0xDA622FE6, 0x66A1E240, ++0x3622DC5E, 0x62638900, 0x6ED36D2C, 0x4E2136D8, ++0x4E212A61, 0xDB61D460, 0xE700A00F, 0x770162B2, ++0x71026123, 0x66212B12, 0x71026213, 0x61212B12, ++0x651D666D, 0x356C4528, 0x627C2452, 0x8BED32E3, ++0xC90360D3, 0x8B108803, 0x617367B2, 0x2B127102, ++0x71026E13, 0x2B126571, 0x655D6DE1, 0x422862DD, ++0x325CE107, 0xA00C2C10, 0x88022422, 0xA0038B01, ++0x8801E203, 0xE2018B05, 0x66B22C20, 0x655D6561, ++0xE60F2452, 0x67A12C60, 0x8B052778, 0xDD38DC44, ++0xEB01EA00, 0x2DB22CA2, 0x6DF66EF6, 0x6BF66CF6, ++0x6AF6000B, 0x2FE62FD6, 0xE240DD36, 0x362266D1, ++0x62638900, 0x3678672C, 0x7703DE38, 0x47212D61, ++0x64E2D635, 0xA00E4721, 0x6562E100, 0x62537101, ++0x74012450, 0x24204219, 0x45297401, 0x74012450, ++0x24504519, 0x621C7401, 0x8BEE3273, 0x66E24200, ++0x420061D1, 0x2118362C, 0x2E628F06, 0xDD1CD728, ++0xE501E400, 0x2D522742, 0x000B6EF6, 0x2FD66DF6, ++0x4F222FE6, 0xED0AEE01, 0x64E3BC86, 0xBC8B64E3, ++0x62EC7E01, 0x8BF732D7, 0xBC8EEE01, 0x64E364E3, ++0x7E01BC93, 0x32D762EC, 0x4F268BF7, 0x000B6EF6, ++0xD1186DF6, 0xD418920D, 0x72122122, 0x2422D617, ++0xD7177204, 0x72202622, 0x2722D116, 0x000B7230, ++0x137A2122, 0x00203A4A, 0x002028FE, 0x001E1015, ++0x00203A50, 0x001E1001, 0x00203A24, 0x001E1100, ++0x00203A4E, 0x00203A3C, 0x001E1000, 0x00203A40, ++0x00203A4C, 0x002027F2, 0x001E100C, 0x00203A38, ++0x00203A54, 0x00203A58, 0x00203A5C, 0x00203A60, ++0x00203A64, 0x00203A68, 0x4F222FE6, 0xD6707FFC, ++0x88016060, 0xE2018951, 0x2620BFBB, 0xD56ED16D, ++0xDE6E6010, 0x64E36552, 0x7402C840, 0x8D22D16C, ++0xD26C7502, 0xE601D76C, 0xE7042722, 0x76016255, ++0x626C2421, 0x8FF93273, 0xD4637402, 0x6242E601, ++0x640D8528, 0x67494419, 0x275D657E, 0x81E4607C, ++0xE417D562, 0x67557601, 0x3243626C, 0x8FF92171, ++0xA0207102, 0xD25E0009, 0xE601D75B, 0xE7042722, ++0x76016255, 0x626C2421, 0x8FF93273, 0xD4527402, ++0x6242E601, 0x640D8528, 0x67494419, 0x275D657E, ++0x81E4607C, 0xE417D553, 0x67557601, 0x3243626C, ++0x8FF92171, 0x92897102, 0xD2462E21, 0x5E23D74E, ++0x64F22FE2, 0x604365F2, 0x2700C980, 0xC9606043, ++0x80716103, 0xC9036043, 0x80724519, 0x65F2605C, ++0x817266F2, 0x46194629, 0x606C4529, 0x4018645C, ++0x8173304C, 0x21185E23, 0x64F22FE2, 0x6E4C62F2, ++0x602C4219, 0x66F262F2, 0x46294018, 0x461930EC, ++0x42298174, 0x652C606C, 0x305C4018, 0x81758F07, ++0x0009BC97, 0x2228620C, 0xA00A8908, 0x60130009, ++0x8B038840, 0x0009B009, 0x0009A003, 0xE202D62F, ++0x7F042622, 0x000B4F26, 0x4F226EF6, 0x8552D52A, ++0x8830600D, 0x88318903, 0xA0348923, 0x85550009, ++0xD428D727, 0x85532701, 0x610DD627, 0x24124118, ++0x460BD426, 0xD7230009, 0xD226D425, 0x6572420B, ++0xE230D120, 0x42286712, 0x2729E620, 0x37604628, ++0xD6218B03, 0xA016E200, 0xD61F2622, 0xA012E202, ++0xD1182622, 0x6212E530, 0xE6204528, 0x46282259, ++0x89083260, 0xD41AD119, 0xE601D513, 0x2160450B, ++0x472BD718, 0x4F264F26, 0x0009000B, 0x0000060A, ++0x00203A6C, 0x001E1000, 0x00203A58, 0x00203E20, ++0x00203E2C, 0x00203DC4, 0x00203A40, 0x00203DF4, ++0x00203DF2, 0x00203DC6, 0x00203A24, 0x00203A50, ++0x00203A3C, 0x00203A38, 0x002018C0, 0x00203B48, ++0x00203B4C, 0x002018D0, 0x00203A54, 0x001E100B, ++0x00203B60, 0x00114004, 0x4F222FE6, 0x84E9DE86, ++0x2448640C, 0xB17B8901, 0xD2840009, 0x26686620, ++0x60E08902, 0x2E00C9BF, 0x000B4F26, 0x000B6EF6, ++0x2FE60009, 0xDE7E4F22, 0x60E0D67E, 0xCBC0D47E, ++0x62602E00, 0xC803602C, 0x40218904, 0x70014021, ++0x6603A002, 0x66034009, 0xD678616D, 0xE500A004, ++0x75016262, 0x74042422, 0x3213625D, 0xD2748BF8, ++0x0009420B, 0xC9BF84E2, 0x4F2680E2, 0x6EF6000B, ++0x2FE62FD6, 0x7FFC4F22, 0x6260D66E, 0x89402228, ++0xD565E100, 0x60502610, 0xCB40D46B, 0x2500440B, ++0x8D052008, 0x62E06E03, 0x7104612C, 0x2F11A006, ++0xD466D65E, 0xDD666760, 0x657C4D0B, 0xE23C6D1D, ++0x8B033D27, 0xD264D463, 0x0009420B, 0x4D214D21, ++0xA005D762, 0x66E6E400, 0x357C4508, 0x74012562, ++0x35D3654D, 0xD75E8BF7, 0x6E72E003, 0x81E14018, ++0x6E7260F1, 0x81E2700C, 0xD45A6172, 0xDD5A8113, ++0x65724D0B, 0xD64AD259, 0x2212E101, 0xC93F6060, ++0x7F042600, 0x6EF64F26, 0x6DF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xD2524F22, 0x6B436E73, 0x420B6C53, ++0x20086D63, 0x64038D1C, 0xE50ED13C, 0x32526210, ++0x60C38916, 0x804124B0, 0x814160D3, 0xA007E500, ++0x655D61BC, 0x00EC6053, 0x364C6653, 0x80647501, ++0x3213625D, 0xD6308BF5, 0xC9BF6060, 0x2600A008, ++0xD239D440, 0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0xE1007FC4, ++0x6513ECFF, 0x6B136CCD, 0xDE34D733, 0xEDFF64F3, ++0xD833EA04, 0x6053655C, 0x027D4000, 0x32C0622D, ++0x66038D0D, 0x09ED6063, 0x2491027D, 0x24217402, ++0x698202ED, 0x3928622D, 0x74022892, 0x75017104, ++0x6063625C, 0x07D532A2, 0x0EB58FE4, 0x2448641C, ++0xE6808905, 0x67F3E5C5, 0xBF8F666C, 0x7F3C655C, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0xD11C68F6, 0x6012D21C, 0xCB20E405, 0x2102E500, ++0x000B2242, 0x00002252, 0x001E1017, 0x00203996, ++0x001E1015, 0x001E10BF, 0x00117800, 0x001E10FC, ++0x00200644, 0x0020399C, 0x00202A56, 0x00203B64, ++0x002018D0, 0x00203B80, 0x002018C0, 0x0011788C, ++0x00203998, 0x0020357C, 0x00201534, 0x001E2130, ++0x00202A18, 0x00203B88, 0x002039FC, 0x00203A04, ++0x00203DC0, 0x001C3500, 0x001D4004, 0xD564D163, ++0xE400D764, 0x2142E20F, 0x17411154, 0xD5622722, ++0x9669D762, 0x15412572, 0x96661562, 0xE6011565, ++0xD55F1165, 0x666CE6F8, 0x25422542, 0x25422542, ++0x25422542, 0x25622542, 0x7601E727, 0x67632572, ++0x25627797, 0xE7042572, 0x2572E248, 0xE2192522, ++0xE2702522, 0x25422542, 0x25422542, 0x25222542, ++0x2522E20C, 0x25422542, 0x25422542, 0x25422542, ++0x25422542, 0x000B154A, 0xE2081145, 0x0009422B, ++0x2FE62FD6, 0x7FFC4F22, 0xC8206043, 0x6E438D02, ++0x0009BE85, 0xC81060E3, 0xBE828901, 0x60E30009, ++0x8901C840, 0x0009BEA4, 0xC80160E3, 0xDD3D8938, ++0xC80260D0, 0x2F008D03, 0x460BD63B, 0x60F00009, ++0x8902C804, 0x460BD639, 0x62F00009, 0xC8806023, ++0x60D08902, 0x2D00C97F, 0xC8016023, 0xD6348906, ++0x0009460B, 0x0009A007, 0x51630601, 0x8902C808, ++0x460BD630, 0x60F00009, 0x8902C810, 0x420BD22E, ++0xD52E0009, 0x88026052, 0xD22D8B03, 0xA005E604, ++0x88012260, 0xD22A8B02, 0x2260E601, 0x2522E200, ++0xC88060E3, 0xD227892D, 0x60E36E20, 0x8902C880, ++0x420BD225, 0x60E30009, 0x8902C840, 0x420BD223, ++0x60E30009, 0x8902C802, 0x420BD221, 0x60E30009, ++0x890DC804, 0xDD20D11F, 0x0009410B, 0x0009BF11, ++0x0009BF4C, 0xD51ED41D, 0x2470E708, 0x25D2BF85, ++0xC80860E3, 0xD21B8905, 0x4F267F04, 0x422B6EF6, ++0x7F046DF6, 0x6EF64F26, 0x6DF6000B, 0x001C581C, ++0xA000A000, 0x001D0100, 0x001D4000, 0x00040021, ++0x001C589C, 0x001E1021, 0x00201A46, 0x00201A68, ++0x002020C8, 0x00201A80, 0x00201A8E, 0x00203A50, ++0x001E100B, 0x001E1028, 0x00201AFA, 0x00201B06, ++0x00201A96, 0x00201AB4, 0x12345678, 0x001E1000, ++0x0010F100, 0x00201AE2, 0x644CD6A7, 0x000B346C, ++0xD6A62450, 0x346C644C, 0x2450000B, 0x644CD6A4, ++0x000B346C, 0x625C2450, 0x4208616D, 0x42084119, ++0x42006019, 0x670E614C, 0xD49E321C, 0x4200207D, ++0x324CC90F, 0x2200000B, 0x4208625C, 0x42004208, ++0x324C644C, 0x4200D498, 0x000B324C, 0x2FE62260, ++0x614C4F12, 0x4100D493, 0x6710314C, 0xE29F666D, ++0x27294619, 0x6E536269, 0x672E6573, 0x4221227D, ++0x42214221, 0x7601662C, 0xE4014608, 0x34E84608, ++0x644C4600, 0x071A0467, 0x2150257B, 0x000B4F16, ++0x4F226EF6, 0xD2857FE8, 0x88016021, 0xD2848B7B, ++0x26686621, 0xD2838B77, 0x26686621, 0xE50F8B73, ++0xE401BFA2, 0xBFA4E501, 0xE586E400, 0xE400655C, ++0x2F50BFA4, 0xBFA1E401, 0xE602E506, 0x60634618, ++0x81F2E401, 0x6543BF9F, 0xE40185F2, 0xBFAB6543, ++0x85F26603, 0x6543E401, 0x6603BFB1, 0xE40265F0, ++0x6053756C, 0x80F8BF80, 0xBF82E402, 0x84F8E512, ++0x7090E402, 0x6503BF82, 0x4618E602, 0x81F66063, ++0xBF80E402, 0x85F6E500, 0x6603E402, 0xE500BF8C, ++0xE40285F6, 0xBF926603, 0xE5FEE500, 0xE010655C, ++0xBF61E403, 0xE5130F54, 0xE40EBF63, 0x05FCE010, ++0xBF63E40E, 0xE5007585, 0xBF64E403, 0xE500E640, ++0xBF71E403, 0xE500E640, 0xBF78E403, 0xE5FFE640, ++0xE014655C, 0xBF47E404, 0xE40F0F54, 0xE504BF49, ++0x05FCE014, 0xBF49E40F, 0xE5017584, 0xBF4AE640, ++0xE501E404, 0xBF57E640, 0xE501E404, 0xE404E640, ++0xAF5C7F18, 0x7F184F26, 0x000B4F26, 0x4F220009, ++0xD2427FF0, 0x88016021, 0xD2418B71, 0x26686621, ++0xD2408B6D, 0x26686621, 0xE50F8B69, 0xE401BF1C, ++0xBF1EE501, 0xE586E400, 0xE400655C, 0x2F50BF1E, ++0xBF1BE401, 0xE401E506, 0xBF1C6543, 0xE401E640, ++0xBF296543, 0xE401E640, 0xBF306543, 0x65F0E640, ++0x756CE402, 0xBEFF6053, 0xE40280F4, 0xE512BF01, ++0xE40284F4, 0xBF017090, 0xE6406503, 0xBF02E402, ++0xE640E500, 0xBF0FE402, 0xE640E500, 0xBF16E402, ++0xE5FEE500, 0x6053655C, 0xBEE5E403, 0xE51380F8, ++0xE40EBEE7, 0xE40E84F8, 0xBEE77085, 0xE5006503, ++0xBEE8E640, 0xE500E403, 0xBEF5E640, 0xE500E403, ++0xBEFCE640, 0xE5FFE403, 0x6053655C, 0xBECBE404, ++0xE40F80FC, 0xE504BECD, 0xE40F84FC, 0xBECD7083, ++0xE5016503, 0xBECEE640, 0xE501E404, 0xBEDBE640, ++0xE501E404, 0xE404E640, 0xAEE07F10, 0x7F104F26, ++0x000B4F26, 0x00000009, 0x001E102F, 0x001E1080, ++0x001E1090, 0x001E103F, 0x001E103E, 0x00203A4A, ++0x00203A4C, 0x00203A4E, 0xD21DD11C, 0x66206010, ++0x676C7001, 0x3700C90F, 0xE5008D13, 0x67106210, ++0x7701622C, 0x64232170, 0xD6166010, 0x44084408, ++0x3428C90F, 0x62602100, 0x7201D513, 0x44082620, ++0x000B354C, 0xD10F6053, 0x25586510, 0xE6008D13, ++0xD60DD40B, 0x655C6540, 0x47086753, 0x37584708, ++0x47086540, 0x24507501, 0x367C6040, 0x2400C90F, ++0x72FF6210, 0x000B2120, 0x00006063, 0x00203995, ++0x00203994, 0x00203996, 0x002035BC, 0x7FFC4F22, ++0xE680D1A8, 0x666C6212, 0xD2A72F22, 0x67F36563, ++0x420B7542, 0x7F04E404, 0x000B4F26, 0xE6800009, ++0xD2A1666C, 0xE7006563, 0x422B7540, 0xE6806473, ++0xD29D666C, 0xE7006563, 0x422B7543, 0x2F866473, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x7FC04F22, ++0xDB97D296, 0x72012F22, 0xD1961F21, 0x66125211, ++0x8B013620, 0x0009A0F9, 0xC9036061, 0x8B018801, ++0x0009A0F3, 0xD290DC8F, 0x64C3420B, 0x6503D18F, ++0x60111F02, 0x8B048801, 0x420BD28D, 0xAFE464C3, ++0x54530009, 0x844CEE84, 0x890130E0, 0x0009A0C3, ++0x6610D188, 0x6023626C, 0x8B718801, 0x6210D186, ++0x89662228, 0xDA86D285, 0xE0036122, 0x64221112, ++0x4018D881, 0xDD83E500, 0x814167A3, 0x77042850, ++0x647266A2, 0x6ED3D580, 0x1F457E04, 0x65521F56, ++0x64E368D2, 0x1F8874F8, 0x684369E2, 0x1F637894, ++0x1F991F74, 0x62826142, 0xD779D978, 0x1F2BD679, ++0x67726292, 0x1F1A6062, 0x2602CB20, 0xD176E600, ++0xE5401F57, 0x1F7D1F2C, 0x76011F1E, 0x3253626D, ++0x51F38BFB, 0x52F555F4, 0x25222A12, 0x55F757F6, ++0x27525AF8, 0x5DF92DA2, 0x2ED251FB, 0xD56B5EFA, ++0x54FC24E2, 0x281257FD, 0xD160D869, 0x25722942, ++0x69126782, 0x1974D866, 0xDD666A12, 0x56FE60A1, ++0x2A01CB01, 0xDA646412, 0xE9012842, 0x4A0B2D42, ++0x52FE2692, 0xD661EE01, 0x22E24E18, 0x72016262, ++0x60B22622, 0xCB01D14F, 0x2B02E202, 0x2120A03F, ++0x8B3C2228, 0xE601D55A, 0x2160E700, 0xE01C2572, ++0xC801004C, 0xD8578B0C, 0x1F8FD257, 0xE6002822, ++0x7601E57D, 0x3253626C, 0x56FF8BFB, 0x2622D253, ++0xE2FE69B2, 0x2B922929, 0x0A4CE01E, 0xE01F65F2, ++0x014C25A0, 0x741057F1, 0xEA062710, 0xDD4CE600, ++0x8446DE4C, 0x2D007601, 0x696C6844, 0x2E8039A3, ++0x8FF67E01, 0xDE487D01, 0x2EA0EA94, 0xE1007E01, ++0x7E0F2E10, 0xD12FE205, 0x64102E20, 0x6023624C, ++0x89088801, 0x55F2D22A, 0x64C3420B, 0xEE01D132, ++0xAF1A4E18, 0x55F221E2, 0x8553D13C, 0x620D6612, ++0x89063262, 0xD63BD43A, 0xE801460B, 0xAF0CD73A, ++0xD91F2782, 0x64C3490B, 0xEE01D127, 0xDA38D437, ++0x4A0B4E18, 0xAF0021E2, 0x7F400009, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x4F2268F6, ++0x85467FF4, 0x2F01E681, 0x666C8547, 0x854881F1, ++0x81F2D209, 0x67F38542, 0x854381F3, 0x81F4E40C, ++0x65636053, 0x420B81F5, 0x7F0C7540, 0x000B4F26, ++0x00000009, 0x001C3D9C, 0x002023FC, 0x0011779A, ++0x001C36F8, 0x002035B4, 0x002014A6, 0x00203A16, ++0x002014D0, 0x002039A5, 0x002039A4, 0x002039A0, ++0x001C3B9C, 0x001C3704, 0x001C3D98, 0x001C3BB4, ++0x001C5960, 0x001C3500, 0x001C3D30, 0x001C8960, ++0x0020358C, 0x001C3D00, 0x00201610, 0x00117730, ++0x002039A8, 0x001C582C, 0x2000A000, 0x0000A000, ++0x0011778C, 0x00117792, 0x00117788, 0x0020397C, ++0x0020357C, 0x00201534, 0x001E2130, 0x00203DA0, ++0x002018C0, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0xD19B7FEC, 0x2F12E000, 0x6103D49A, ++0x1F4281F2, 0xDD9ADA99, 0xD69A6813, 0xE0014808, ++0x460BDE99, 0x38EC4800, 0x65A21F03, 0x352052A1, ++0xA23E8B01, 0x60510009, 0x8801C903, 0xA2388B01, ++0x52530009, 0x32E0DE91, 0xD9918B10, 0x64A3490B, ++0x4B0BDB90, 0xDE906403, 0xD791D690, 0xEC01D591, ++0x2E02E100, 0x271026C0, 0x2502AFDF, 0xC8018551, ++0xA1578B01, 0x62510009, 0x4200622D, 0x5E53366A, ++0x85E2226D, 0xC903642C, 0x85E36603, 0x6053650D, ++0x40214021, 0x4500C93F, 0x322A6703, 0x6053252D, ++0xC901D17F, 0x60106C03, 0x8801D97F, 0xDB7F8B05, ++0x2120E200, 0xCB0160B2, 0xD17D2B02, 0x88016011, ++0x65A28B0A, 0x8D042448, 0x9B9E6251, 0xA00322B9, ++0x919B2521, 0x2521221B, 0x37B3EB10, 0x2448895E, ++0xD4738B07, 0x22286241, 0x60638903, 0xA05781F8, ++0xD5706473, 0x46084608, 0x85E26273, 0x46006B50, ++0x362C4200, 0x2BB8C910, 0x8F1F6463, 0x26686603, ++0xD2698911, 0x062D6043, 0x4119616D, 0x6B0E6019, ++0x81F820BD, 0x880160C3, 0x646C8F2C, 0x880F6073, ++0xA0278B1B, 0xD2610009, 0x052D6043, 0x4119615D, ++0x670E6019, 0x645C207D, 0x81F8A01C, 0x890F2668, ++0x6043D25B, 0x6B5D052D, 0x60B94B19, 0x201D610E, ++0x60C381F8, 0x8F0D8801, 0x6473645C, 0xEC00A00A, ++0x6043D254, 0x625D052D, 0x60294219, 0x207D670E, ++0x81F8645C, 0x880285F8, 0x85E1890A, 0x8D07C820, ++0xE6DC6203, 0x60232269, 0x81E1A002, 0x644CE4FF, ++0x6210D149, 0x89012228, 0x644CE4FF, 0x654DEBFF, ++0x35B06BBC, 0xDB368B2B, 0x64A34B0B, 0x410BD135, ++0x54036403, 0x85446E03, 0xC948DB40, 0xDC408808, ++0xBEAC8B01, 0x64B3E502, 0x65E34C0B, 0xDB3DEC01, ++0xD13D2DC2, 0x621260B2, 0x72017001, 0x21228805, ++0x2B028F08, 0x666CE680, 0x6563D238, 0x7549E700, ++0x6473420B, 0xA030D436, 0x7FFF0009, 0x85E28000, ++0x20B9EBFC, 0x610381E2, 0x942A85E3, 0x62032049, ++0x450885F8, 0x81E2201B, 0xC90160C3, 0x40084018, ++0x40084008, 0x4000225B, 0x6023220B, 0x85E481E3, ++0x4118E108, 0x81E4201B, 0xE40262A2, 0x20B98521, ++0x67A28121, 0xCB016071, 0x85F82701, 0x89033042, ++0xECE785E2, 0x81E220C9, 0x490BD41E, 0xA03B0009, ++0x7E030009, 0x001C3D30, 0x00203DAC, 0x0020358C, ++0x001E212C, 0x00203470, 0x001C3D00, 0x00117780, ++0x002014A6, 0x00201670, 0x0011770C, 0x002039A4, ++0x002039A5, 0x002039A0, 0x002018C0, 0x001C36F8, ++0x00203A1A, 0x00203DBC, 0x00203BA0, 0x00203C20, ++0x00203CA0, 0x00203D20, 0x00203990, 0x00203584, ++0x002014D0, 0x00203A1C, 0x00203A20, 0x002023FC, ++0x00203DA4, 0x00203DA8, 0x602262F2, 0x40094019, ++0xC90F4009, 0x8B0B880A, 0x60E2DE8C, 0x40094019, ++0xC90F4009, 0x8B038808, 0xCB0160A2, 0x2802A006, ++0x65E2DE87, 0x2E527501, 0x286266A2, 0x52F366F2, ++0x2622AE83, 0xD2838551, 0xDE83C802, 0xA0958B01, ++0x420B0009, 0x4E0B64A3, 0x5E036403, 0x85E46503, ++0x4918E908, 0xD77D209B, 0xE04C81E4, 0xDC7C0B7E, ++0x7B01D97C, 0x61C207B6, 0x71016690, 0x8D062668, ++0xD4792C12, 0x420BD279, 0xA070EB01, 0x62512DB2, ++0x4B18EB0F, 0x22B9E102, 0x32104118, 0x85518B0F, ++0x2029E2FC, 0x60518151, 0xCB0172E0, 0x85E12501, ++0x202994A3, 0x85E481E1, 0xA0522049, 0x675181E4, ++0x4719677D, 0x667E6779, 0x7701276D, 0x6903607C, ++0x88014918, 0x25918F3E, 0x6B12D161, 0x21B27B01, ++0x660D85E3, 0x40216063, 0xC93F4021, 0x6C034600, ++0x262D322A, 0xC8016063, 0xDB5ED15D, 0x967D8901, ++0xE6002C6B, 0x666C67CD, 0x40006063, 0x622D021D, ++0x8D0E3270, 0x60436403, 0xE9FF021D, 0x8B013290, ++0x01C5A007, 0x626C7601, 0x3292E904, 0x646C8BEB, ++0x60434400, 0xD15004BD, 0x0B457401, 0x669D6911, ++0x89073670, 0x602D6211, 0x890388FF, 0xE201DB4B, ++0x2B2021C1, 0xECFC8551, 0x815120C9, 0xCB016051, ++0xDC472501, 0x64A34C0B, 0x51F366F2, 0x85EF2612, ++0x54F2D244, 0x650D420B, 0x0009ADE7, 0xE500DC42, ++0x420B2C52, 0x4E0B64A3, 0x54036403, 0x85446E03, ++0x6703E908, 0x65034918, 0x27998541, 0xDB323790, ++0x8F0BD932, 0x6013610D, 0x8B07C820, 0xC9486053, ++0x8B038808, 0xE501BD4B, 0x0009A005, 0x2128D233, ++0xBD448901, 0x64B3E500, 0x490B65E3, 0xADBCEC01, ++0x85F22DC2, 0x7001EE04, 0x31E7610D, 0x8D0281F2, ++0xADA97A08, 0x7F140009, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x000B69F6, 0xF7FF68F6, 0x2FE68000, ++0xD2234F22, 0x60E36E22, 0x8D02C840, 0xBBE522E2, ++0xE2400009, 0x2E284218, 0xBBF08901, 0x60E30009, ++0x8905C810, 0xD21CD41B, 0x0009420B, 0x0009BBEF, ++0xC80560E3, 0xBD6D8901, 0x60E30009, 0x8902C802, ++0xABEC4F26, 0x4F266EF6, 0x6EF6000B, 0x001C3D3C, ++0x00117760, 0x002014A6, 0x00201670, 0x0020351C, ++0x00203DC0, 0x00203990, 0x00203584, 0x002014D0, ++0x002039FC, 0x00203A04, 0x002039F8, 0x002039FA, ++0x00201534, 0x002018D0, 0x00203A1C, 0x00008000, ++0x001C3510, 0x00203DB4, 0x002018C0, 0x89014F22, ++0x611B600B, 0x611BB00A, 0x000B4F26, 0x600B600B, ++0x611BA004, 0x8DF12107, 0x8BF84011, 0x620D2F26, ++0x8F3E3020, 0x40180019, 0x8B0B3016, 0x31043104, ++0x31043104, 0x31043104, 0x31043104, 0x412462F6, ++0x601C000B, 0x41296219, 0x20084018, 0x31048926, ++0x31043104, 0x31043104, 0x31043104, 0x31043104, ++0x31043104, 0x31043104, 0x31043104, 0x61193104, ++0x3204221D, 0x32043204, 0x32043204, 0x32043204, ++0x32043204, 0x32043204, 0x32043204, 0x32043204, ++0x212D3204, 0x601962F6, 0x4024000B, 0x000BE000, ++0x621362F6, 0x41294228, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x602D4224, 0x62F6000B, ++0x080A0C0E, 0x00020406, 0x1A1C1E20, 0x12141618, ++0x2E303234, 0x26282A2C, 0x3A3C3E40, 0x6C625648, ++0x41112F26, 0xE2208F18, 0x890B3123, 0x321CD204, ++0xD1026220, 0x412B312C, 0x00090009, 0x0020349A, ++0x00203450, 0x000BE000, 0x400062F6, 0x40004000, ++0x40004000, 0x40004000, 0x62F6000B, 0x40004000, ++0x40004000, 0x40004000, 0x40184000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40284000, ++0x62F6000B, 0x40004000, 0x40184000, 0x000B4028, ++0xC90F62F6, 0x40054005, 0x40054005, 0x62F6000B, ++0x4005C907, 0x40054005, 0x62F6000B, 0x4005C903, ++0x000B4005, 0xC90162F6, 0x000B4005, 0x000062F6, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x42707372, ++0x3D206675, 0x554E203D, 0x202C4C4C, 0x6E49677A, ++0x4E497274, 0x6D754E51, 0x0000003D, 0x61766E49, ++0x2064696C, 0x72657375, 0x20726F20, 0x2079656B, ++0x00214449, 0x6E6B6E55, 0x206E776F, 0x6D6D6F63, ++0x3D646E61, 0x00000000, 0x203A3051, 0x00000020, ++0x203A3151, 0x00000020, 0x203A3251, 0x00000020, ++0x203A3351, 0x00000020, 0x203A3451, 0x00000020, ++0x2B434741, 0x73696F4E, 0x61432065, 0x7262696C, ++0x6F697461, 0x6166206E, 0x6F206C69, 0x6974206E, ++0x0D0A656D, 0x00000000, 0x00000072, 0x00205220, ++0x62735576, 0x7473725F, 0x00000A0D, 0x62735576, ++0x7375735F, 0x646E6570, 0x00000A0D, 0x62735576, ++0x7365725F, 0x000A0D6D, 0x00000044, 0x44387570, ++0x72637365, 0x6F747069, 0x3D584572, 0x00000000, ++0x00000047, 0x72746E49, 0x6D652051, 0x2C797470, ++0x49677A20, 0x4972746E, 0x754E514E, 0x00003D6D, ++0x654C7245, 0x0000006E, 0x20746F4E, 0x756F6E65, ++0x49206867, 0x4220514E, 0x0A0D6675, 0x00000000, ++0x000000FF, 0x00020001, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00020003, 0x01090108, 0x0002010A, ++0x02000003, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x000000FF, 0x00020001, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00020003, 0x01090108, 0x0002010A, ++0x00030003, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00FF010F, 0x01090108, 0x010B010A, ++0x0200010F, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00FF010F, 0x01090108, 0x010B010A, ++0x010F010F, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00205220, 0x00000046, 0x00000059, 0x73204142, ++0x003D7165, 0x49544120, 0x0000204D, 0x00000000, ++0x00000000, 0x002E0209, 0x80000101, 0x000409FA, ++0x00FF0400, 0x05070000, 0x02000201, 0x82050700, ++0x00020002, 0x03830507, 0x07010040, 0x40030405, ++0x02090100, 0x0101002E, 0x09FA8000, 0x04000004, ++0x000000FF, 0x02010507, 0x07000040, 0x40028205, ++0x05070000, 0x00400383, 0x04050701, 0x00004002, ++0x00000000, 0x00000000, 0x07090000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, }; ++ ++const u32_t zcP2FwImageSize=15964; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwbu.c +@@ -0,0 +1,5269 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++ ++const u32_t zcFwBufImage[] = { ++0x3A4BCF18, 0xF44C076E, 0xF59452EA, 0x451BA755, ++0x140AC87A, 0xC07EE942, 0x3EF978AB, 0xF5B03DC6, ++0xB70080F0, 0xA89064EA, 0x54E2C1D6, 0xEB047DF4, ++0x1798390C, 0x00350624, 0x35B3ECF0, 0x59F2FABF, ++0xAF9D248E, 0xF9BDB9F0, 0xD05C8B47, 0xC08B5A16, ++0x990093C7, 0xD335A160, 0x1C04942C, 0xBF6E7A88, ++0xFD232B0F, 0x5C224387, 0xBF1E156C, 0xF24F2A27, ++0xFF56421D, 0xB213037C, 0x2BA67BA0, 0x4950CF8A, ++0x05F00F25, 0xA5E82085, 0x74168A0C, 0x2F2AB30B, ++0xC80C57EE, 0xB6BDF570, 0x89BC5A99, 0x7F3B5A67, ++0xF6C943B8, 0x0C9C9201, 0xE8383747, 0x0C9A72D6, ++0xE0520704, 0xA66D7F30, 0xE444A434, 0xE0C94AB7, ++0x8DD7751C, 0x1A659464, 0x6C9ABA4F, 0x792F2D2D, ++0x5936F66B, 0x061E580E, 0x59903F6C, 0x1FBFB8A0, ++0xCC822EFE, 0x4B030CAF, 0xB62457C9, 0x27E9BF15, ++0xB113A487, 0xFA0FC915, 0x447B184A, 0x5330CD51, ++0x00BCC622, 0xF30DE149, 0xFF718E1C, 0x7B5D2861, ++0xDBCA573E, 0xFB0D7BF9, 0xE1CFBAAC, 0xF99D4583, ++0x4BA7498A, 0x7CAEA7EB, 0xBA958E32, 0x36C530FF, ++0x8F88CA99, 0xF93CABC2, 0x8E47EF11, 0xFB0EED6F, ++0x5B3668A1, 0x9D63ADDE, 0xA0EEAB8C, 0x084915F1, ++0xFACAAA27, 0x209638FE, 0x1CED9EFF, 0xEEBD2335, ++0x38C6F424, 0x2D1F3D7E, 0x976E8106, 0xBE087AD2, ++0x32194845, 0x756066DB, 0xC70E3165, 0xC568DCB1, ++0x3212E4E1, 0xB5D991AD, 0x07C3CEF8, 0xDB4ABB38, ++0x1574C232, 0xF8C792BC, 0x14E62DBE, 0x5A48E7DC, ++0xEFDC5407, 0xC45B4017, 0x3B814E89, 0xF0936466, ++0x89491B2B, 0x9A359A41, 0x82287675, 0xA0F338D3, ++0x523FDD3C, 0x4E40B795, 0x458ADAA4, 0xED812957, ++0x7ADC73BC, 0x6FD7DB78, 0x2740FC04, 0x6392AEA3, ++0x185ABCEA, 0x6B50ABC3, 0x3681F07F, 0xC840F8CE, ++0x5733E7EC, 0x0805FA71, 0x0B34530A, 0x8CB3D033, ++0x81451551, 0x53B0B4EC, 0x908646D0, 0x10A3E642, ++0xF358DC34, 0xC1FA570C, 0x2B1284B0, 0x592322BB, ++0x9D587783, 0xE7D77988, 0xE1BE5D7B, 0x44B93E23, ++0xF8BE94A2, 0x506DC723, 0x6E0A7D09, 0x3FB1046F, ++0xDB3A166F, 0x9CB7D6A0, 0xE278DE6D, 0x88459334, ++0xB52BA3C9, 0x284740A2, 0x04D30792, 0x944D79CA, ++0x1D050EA9, 0xA404DB1B, 0x99526023, 0xBACE24E7, ++0xB9F20704, 0x284E6432, 0x47A593D1, 0x95F8DFCB, ++0x220C9167, 0x8FAABBBC, 0x93D34E8C, 0xCE077138, ++0x4FC18081, 0xE76DD7E5, 0x67465F6C, 0x7A479D77, ++0x74D61F82, 0x00559214, 0x2F66E42E, 0x8742A96B, ++0x62063950, 0xA2DBFAE5, 0x368B966F, 0xAB5FCCE1, ++0xCB4023B1, 0x1E7AF542, 0x05953E30, 0x8CA51CFC, ++0x2216547D, 0x29D562D4, 0xE9C9F8EE, 0xA90505C9, ++0x088D0EEB, 0xD7A290FA, 0x95E5B567, 0x53FAD3C0, ++0xB89FC625, 0x69A7519B, 0x3687C7EF, 0x7188CB55, ++0xCE5DB97E, 0xA260574A, 0xD453D173, 0x145D970B, ++0x12112CC6, 0x399839E0, 0x29C55BEB, 0xE467C71F, ++0x10B3C9D4, 0x8F1C9662, 0xF207A826, 0xE0245600, ++0x688B1812, 0x5A483031, 0x7048380A, 0x78E3D5BB, ++0x1951533D, 0x8FA5D8E3, 0xC5BE500D, 0x71DB5B2B, ++0xA17AA000, 0x408C9BE8, 0x161E12F5, 0xB1C38C45, ++0x22A88F05, 0xDE3F4405, 0x5078ADBB, 0xCE1BF1A6, ++0xB7A75B04, 0x6B8364E8, 0x0CE32E3E, 0x9BF65504, ++0x28C18157, 0x78359AC6, 0x617BF202, 0x1E76FA09, ++0x0F8E61A8, 0x6D02F0D5, 0x80356459, 0x79CEFAE7, ++0x7D00F155, 0x5C1C0128, 0xC75CA073, 0x32816090, ++0x9FF78DFC, 0x848D269C, 0xF811B314, 0xA86920FC, ++0x6F885D01, 0xACFE6525, 0xC726074D, 0xFED68599, ++0xF1D5C76A, 0x8799E5F5, 0xF85F5171, 0xD8DE2D3B, ++0xE7DD8E75, 0x43F8614A, 0x0684FC8D, 0x9683B8C8, ++0x74BE786B, 0x2514762D, 0x7D866682, 0xE711FE1F, ++0x0DE9E273, 0x12F53167, 0x4FA3A7FE, 0x2A00EB61, ++0xB3984A28, 0x4319F2B0, 0x42BA0CA2, 0x848771B6, ++0x995E945E, 0xD41115F5, 0x43D9834B, 0x54EEDC36, ++0x5C3C5407, 0x671B540E, 0xDCF18948, 0x150ED973, ++0x2D4922DE, 0xF93CA17D, 0xB24A76E5, 0xD1C01C22, ++0xF2963DD6, 0x3B860066, 0x08EF0EA4, 0x609B60CC, ++0xE2E901FA, 0x25BE9B93, 0xDF96D9BC, 0x86D415DF, ++0x75CCF6BB, 0x882D54B2, 0x7976E9AF, 0x88A0B178, ++0x5ADE5A55, 0x8A8C0112, 0xD896755A, 0xCB6789B3, ++0x8B63AE2F, 0x2545036C, 0xE4655B94, 0x20959977, ++0x29DFB4D1, 0xCDAAEBF4, 0x1C07EC05, 0x5A6F607D, ++0x88A9B31D, 0x118C74D2, 0x000BB065, 0x75C46712, ++0xEF1A58BD, 0x50ECA262, 0xCCE393B9, 0x6EDB92E8, ++0x700EF517, 0xBF6CF4AD, 0x57456DC0, 0xF629517C, ++0x40331F8B, 0xC10A454D, 0x6CCB02CF, 0x9BF11B1C, ++0xE0871437, 0x23623585, 0xF519F09C, 0x4DB2AFC8, ++0x88FCBD7B, 0xB512FE8D, 0xDE445894, 0x078AD03C, ++0x44375FB0, 0x0BABEDB1, 0x40D5E8E1, 0x13F20A86, ++0xF1406303, 0x7205C322, 0x3FC43779, 0x7A60D510, ++0x14469E04, 0xF4E77873, 0x2EAD7ECE, 0xA135D6EA, ++0x3F4C4B30, 0x21488077, 0x69F64F1C, 0xEEF4876E, ++0x63610C0B, 0xB7B24C5C, 0x324A76FE, 0x0CF651D3, ++0x9460F0B1, 0x81A83230, 0x0839CFF9, 0x70722F04, ++0xC278FB3B, 0x5DD1BDA4, 0x1E4B3DBA, 0xAE161A93, ++0x9E1033C3, 0xD938FCEC, 0xDA2B2F93, 0x28CD82EA, ++0x14AD1FAF, 0xE4EC9CB8, 0xE770AFDF, 0xEFB12898, ++0x500BE181, 0x602625C5, 0xF160631B, 0x78D3643F, ++0x4E13ED37, 0x647BB223, 0xCF18D75C, 0xF477F94C, ++0x786ECB89, 0xB3ED21F8, 0x1BEF3916, 0x240FB35A, ++0x5C69B7D9, 0x8E96290A, 0xD40DC98C, 0xD1370291, ++0x5870021E, 0x3F7CF23F, 0xFD4A6ADA, 0x36482457, ++0x926600AF, 0xDC8618BC, 0x67D3779F, 0x3422830C, ++0x87A41FBA, 0xCA0AFF53, 0x63BC45F3, 0x520BBBAE, ++0xEDE2E031, 0xB6FA9450, 0x258CA712, 0xD709C4E4, ++0x617709B2, 0xAACE0B41, 0x363DBF55, 0x701D6583, ++0x39F3C885, 0x7CD6297B, 0x078FE13B, 0xA398DABF, ++0xDB97C514, 0x039102E3, 0x5CA545AF, 0x9298BA18, ++0xD18DAF86, 0x3D70EEA2, 0x5266AD68, 0xB04945B5, ++0x402DDA5B, 0x01DC6CD1, 0x93AC5053, 0x08DF9EA9, ++0x485EBE97, 0xA5D05853, 0x6CBEE910, 0xD485F4E2, ++0x8F201D07, 0xEFC384A3, 0x7272AFBE, 0xC0B41FD7, ++0x8E54A971, 0xA7F9E0F7, 0xC21700B4, 0xC24A4ED0, ++0x5419EACF, 0xBC2D8FB1, 0x2C5B5AFF, 0x0345274C, ++0xC41DF47A, 0x37658AFF, 0x24CF3BE7, 0xA3086248, ++0xF82B5928, 0xB49A9B04, 0xD4105AEF, 0x444EBE8D, ++0x348368DF, 0xDC77A7A0, 0x68D37E0D, 0xD2EB54EE, ++0xDDAC8C33, 0xE5C93C79, 0xE4706ABF, 0x17536EFD, ++0x6C2B2B16, 0x038AA806, 0xDAD42458, 0xAE1D76A1, ++0xCC8DE95C, 0x1BA20647, 0x0521068C, 0x306FBE44, ++0x4E29D881, 0xD2A14D53, 0xA155853E, 0x44500CC4, ++0xFC4466B7, 0x5AACD51D, 0x506D3A73, 0x3F61E0FE, ++0x58F11F9D, 0xC92A2CAD, 0xD9A4F86B, 0x1FA747B1, ++0x77DEC5D2, 0xDFAB369A, 0xD471EA01, 0x724502DA, ++0x618CE21A, 0x52388BEB, 0x2E8A4CC5, 0x58332211, ++0x3FCC46E1, 0x501210E2, 0xE9D51D1A, 0x37237B55, ++0x8CE3E2F1, 0x6B2E98CC, 0xB56A11E5, 0x8819036B, ++0xA6AA2F27, 0xB0124A0E, 0x92F17364, 0xD4A89238, ++0x0507E337, 0x8ED95DEC, 0x9C014BA8, 0xBA5B11C6, ++0x9C15D38C, 0x52596C98, 0x9330DD3D, 0xD6147570, ++0x21701F1B, 0x5A2385F1, 0xE2F38C6C, 0xB3E94698, ++0x2F9C63FA, 0x7E0234D8, 0x4CDD3288, 0xE1969B5F, ++0x853B3C1D, 0xF61465A7, 0xF281C419, 0x46C5F072, ++0x9F1722DD, 0x64F2A994, 0x86AEE8A8, 0x55895E17, ++0x6047D1AC, 0x3375A934, 0x336BEACA, 0x90791174, ++0x4DACC4D2, 0x24253860, 0x2A7876FB, 0x9DBDF98D, ++0xD5BCE182, 0x67EB5F70, 0xCC06BA38, 0xE8F78715, ++0xFEB0EB44, 0xE9776E03, 0x892A0898, 0x7A070650, ++0x6D04DDC4, 0x99A5B7EA, 0x3B416BB6, 0xDADCE834, ++0xB3B03278, 0xDB73B70E, 0xB0F0224E, 0x538A4AF9, ++0xD25D6A37, 0x8F627FB0, 0x11ED9387, 0xB8C88457, ++0x0CF320CA, 0xA20E62A2, 0x1DACDD4A, 0xAB84575D, ++0x740DAF75, 0xAB9DB955, 0xFF787314, 0xA680B8E3, ++0xC976D38E, 0x1FD38F4D, 0x0AEB6633, 0xB69A03DF, ++0xB6CA8610, 0x106354C2, 0xC37D48C8, 0x3E5EED54, ++0x534CC9BA, 0xE37DFFAD, 0x9F69EB05, 0xF67217EE, ++0x50180B3D, 0xCC61C127, 0xC3598D73, 0xE5C00F01, ++0xFFE9B111, 0x5E23EA2F, 0xF6C45DCE, 0x44585E39, ++0xB02C6004, 0x37233902, 0x4F374C0D, 0x34288898, ++0xE274937D, 0xC81D472C, 0x17A43151, 0x2638F7D3, ++0x5304E5B5, 0xD5CE5EDE, 0x357FA7B3, 0xFBE27986, ++0x64E65D1F, 0xC28D1237, 0xA73D9AB3, 0x124CA6C8, ++0x770D7415, 0x5788C32C, 0x18DEFC00, 0xB3B2B06A, ++0x55CC86A0, 0x8D929309, 0x84AB381A, 0x9DEFE8DD, ++0x26C742C8, 0x952BAC34, 0x0A3B140F, 0x82A9304B, ++0x52CEC9F4, 0x47DF4D08, 0x15A116D8, 0x7B890B18, ++0xC87BEF1A, 0xB59601B6, 0xD37BFB28, 0x5D9F564D, ++0xFB002F8D, 0xE7602E57, 0xE429C852, 0x9C0A8C75, ++0xE02611DC, 0x8A1C9861, 0x7495D6DE, 0xCA059710, ++0xAE5969B8, 0xE5B2CBDC, 0xA49F6EC1, 0x85D2A553, ++0xE4719B0F, 0x40F68BBC, 0x092E24B5, 0x7B132678, ++0xD70C17E1, 0x309E6AA1, 0xE009657F, 0xA7238C7A, ++0xE0575D78, 0x1D6980E7, 0xEFCDD368, 0x19F08D93, ++0xFAC03B85, 0x51BADA8F, 0x037DF839, 0x8F4D29F4, ++0x1DC8A913, 0x50C55402, 0xDEE578F0, 0x2BA1C091, ++0x9ACA567E, 0xA8FFECFA, 0xA3C05D12, 0xF18C6283, ++0xEAAE6662, 0xB4DC6A79, 0xCEC5E782, 0x93A2E384, ++0x8F8A5E6F, 0xCA8379D5, 0x81BCD49E, 0x5FCE174B, ++0xD1543A5B, 0x845D635F, 0xD53125B9, 0x3B2121AE, ++0xF8ECDD01, 0xF84D2D11, 0x6579BC21, 0x5C2DC220, ++0x9EC1A688, 0x1148D831, 0x6C087799, 0x58944357, ++0x56F79FC6, 0x6B689B55, 0x740B5FD1, 0x9F7BFB5F, ++0x6B2F3E2D, 0x10E09273, 0x2E9E3213, 0xF3436AA0, ++0x14A9F681, 0x9087D3CE, 0x68D0430B, 0x9FAFE3EF, ++0xD45B8C61, 0xB982724A, 0x04448D7F, 0x8712E47A, ++0x2C188D15, 0x9C3F06CC, 0x6343B130, 0x56C6765C, ++0xF657BC9A, 0x15F1E973, 0x47E71181, 0x8639F5D7, ++0xC1F3FDD5, 0xDC522441, 0x56BB2908, 0xAA48AEC6, ++0xEC04087A, 0x8D375875, 0xE2941F88, 0xED31CC72, ++0x09BD8794, 0x4C81D5C1, 0x1CC96D9C, 0x98A89022, ++0xAA362C57, 0x924D583D, 0x270430E6, 0x0FD4040A, ++0xAF561155, 0x38DCD1CF, 0xE861D2AC, 0x24A2EF3C, ++0x2B7E3868, 0x13DA6C12, 0x69202EB6, 0x4A5FEC66, ++0x185417A9, 0x3C92EFF4, 0x949842E6, 0x02115D93, ++0xAD1726FF, 0x4E093D7D, 0xC3E41B9C, 0x27BBC1C1, ++0x4FFA49C7, 0x6C63D24C, 0x84255444, 0x282C3BA2, ++0x3D679D86, 0x03B410B1, 0x64DB454C, 0x535499D4, ++0x25B421A1, 0x7E68C8FE, 0x0477E3B9, 0xCEFB087D, ++0x9E59B89C, 0xBB787559, 0x1A550EE4, 0x078B48AB, ++0x73A865FE, 0xD7227471, 0x3A864049, 0xE5EE3A1D, ++0x201BC19D, 0xEB8DAE2C, 0x0E2AB31D, 0xCDAC2D79, ++0xDAAB08B1, 0x63ECD4F2, 0xC00F9716, 0xD415C6BB, ++0x8C20C39F, 0xDED8F5A2, 0x1D6A4190, 0x3D319167, ++0x56B3A26B, 0x0547BF52, 0xA056924F, 0x4DAA539A, ++0x557241D1, 0x42C9124E, 0x18723323, 0x6AD6E7EC, ++0x8E039337, 0xF6FDDD65, 0x5F3525F9, 0xC0AD9704, ++0x810EF049, 0xCE022EE0, 0x41CE7E52, 0x8E172A44, ++0x648808E2, 0xC7FF6896, 0x2AD0985C, 0x304B9631, ++0xD21EA39B, 0x279F5089, 0xCDB5C390, 0x21716A40, ++0x5E34B278, 0x39475D72, 0xBA4F4DB1, 0x8B25818F, ++0xE6E466F4, 0xC4A09DF8, 0x59F18AC7, 0x887AB5FE, ++0xEEA4BA42, 0x17371DA8, 0xA82193D1, 0x6DC30EF7, ++0xDEB9D349, 0x2B3271D4, 0x1FE83836, 0xEC755A29, ++0x05F07FCD, 0xC331D3AE, 0xC6208B76, 0x497FF280, ++0x4C579C5A, 0x22B71F94, 0x30FD620B, 0x31B71AE3, ++0xDF7D1A41, 0xF041ACA5, 0x9533261B, 0x3262D291, ++0x060E9672, 0x7D191A55, 0x6D0F0945, 0xF8C7777C, ++0x1C173808, 0x78308E77, 0xC1EEAD3B, 0x059CCD9D, ++0xA8FDBE19, 0xE47630FA, 0x88A49DE5, 0x03347DAB, ++0x4F31F969, 0xF9C62B12, 0x93AB126F, 0x8A7A3BFB, ++0x82591545, 0x2A1A2131, 0x1DEBB134, 0x449E28DD, ++0xFA7E0248, 0xC1E3A5BC, 0x1747E097, 0x4C69AA5C, ++0x1FD71B4B, 0xAC64CA6C, 0x5545F9F9, 0x5E5886F2, ++0x243DBA6C, 0x495BE163, 0x4ECF5A6C, 0x430C9019, ++0x89A980FA, 0x528945AE, 0x00CE6936, 0x9F9A73B2, ++0x9E59DC6B, 0xD57740CD, 0x0E0CB735, 0xB1202BE3, ++0xAA26C2A9, 0x267A77A6, 0x3FA12CF0, 0x4587C0AF, ++0x354ED831, 0xFFD8BD8E, 0x56CC0F26, 0x75717AE3, ++0x51B10674, 0x3E33EC26, 0x26CE80DB, 0x5C4A9140, ++0x017F6C2F, 0xF9038D9A, 0x0A22C29F, 0xBA1F7C8D, ++0x125CC934, 0x6CF66BFF, 0x48C13DCD, 0x63FC3D81, ++0x258C181D, 0x1A4C3DDD, 0x2E24BECC, 0x7C86A9ED, ++0x5BD1989C, 0x57CE595C, 0xDF291AFE, 0xEAF00887, ++0xD8DD4259, 0xDF67331E, 0x50D0CE88, 0x1FD090AE, ++0x632DA5F0, 0x95272A5B, 0x31172F25, 0x547FD7DF, ++0xAFBE11D9, 0x97189DFC, 0xC4881191, 0x1C92365D, ++0x843DEFDE, 0xCF0A399B, 0xCF327CAF, 0xDDAF0BCE, ++0x03AA7A2E, 0x411A8664, 0x6CCF7CD9, 0x61097EF5, ++0x07F3941E, 0x5BC3EB75, 0x2791945F, 0xBEBB526E, ++0x18631A34, 0x25FEBF10, 0x419834CF, 0xF642D176, ++0x372FFF10, 0x2A1BEA1B, 0x400FF345, 0x257A234A, ++0x9F15E99D, 0xE06AA1DB, 0x3A0DB315, 0x2BA30D99, ++0x0E9E831E, 0x1B25EE41, 0x8DB30E70, 0x9FBA6D64, ++0xAB8AA5E3, 0x5A96177A, 0x6BE03535, 0x97E37DCE, ++0xACA24F26, 0x5F0096F7, 0x5D02722F, 0xAF8F3EC7, ++0xA6824151, 0x70FAD406, 0xDEBA8513, 0x99C63E34, ++0x1CC4A3DF, 0x7F756508, 0xB7386527, 0x647C7FB8, ++0x43F1F4DF, 0xC7E4EC18, 0x302BA109, 0xD5E9175B, ++0x82856F77, 0x0F6D45D9, 0x95AE28B9, 0xE63385C3, ++0x8FB26619, 0xBD99F298, 0xC884B948, 0x0B596FF1, ++0xE061C3F9, 0xBC2F9A81, 0xC488CD91, 0x372EF590, ++0x3DA1BFE5, 0x10DE037B, 0x7210B4DC, 0x74E4EFF8, ++0x6365AFD2, 0x8CEABC85, 0x1D8FFD43, 0x4DE243F8, ++0xEC976FD9, 0xAD827765, 0xC679F15D, 0xC125EC31, ++0x95D3481C, 0xC4EA6EAC, 0xC8FC014F, 0x1352EB66, ++0x9C400EB5, 0x227BFAB9, 0xB12BF958, 0x85B6D782, ++0x78B6E44D, 0xE2232EEE, 0x4F101711, 0x9ABEBF69, ++0x66ACC682, 0x04AD5F55, 0xE4FC6238, 0xBA3D2266, ++0xA2BA3170, 0x083F39AB, 0xFF2075C4, 0x945C4B05, ++0x41E8C113, 0xEC7CAD67, 0x3653733E, 0x03510C3B, ++0x1E973158, 0xFBE507F3, 0x2CCD8D9A, 0x6EA9442F, ++0x0D48DE95, 0xC517BFAE, 0x04EBB5C9, 0xEFAB1823, ++0xD5FBFC0A, 0x6890F212, 0xA1C00CCD, 0x6DD561E6, ++0x20D39B1C, 0x56113FBA, 0xCF3A7FD7, 0x3AB5A0DB, ++0x3656572E, 0x7BC48CD3, 0x8902AE36, 0xD3E94AFF, ++0xC06EB447, 0xCC513C0C, 0x2544B7DD, 0x6F168877, ++0x53162607, 0x461DCEF0, 0xF47AF2BB, 0x8AF9F3CC, ++0x1EEFF9E6, 0x57CFB6B6, 0x7F712439, 0xAB20C93D, ++0x043F9003, 0x60C808BC, 0x86C2137C, 0x46ADB474, ++0x848B65F2, 0x5544789B, 0x18E9AEC7, 0xC889913E, ++0xFEB79B2F, 0xA3FBE518, 0x67922463, 0x93746398, ++0x968E160F, 0x8CA856A4, 0xA040202E, 0x660C00C6, ++0x8F0A8E62, 0xE2BA54DE, 0x4BD0C117, 0x1A1A3092, ++0x086CAA3A, 0x2BBA5676, 0x89610176, 0x00ED2F97, ++0xC72130C7, 0x5A053880, 0x7298E553, 0xD67971EA, ++0x0D41E477, 0x2FA8285F, 0xB856A190, 0x132DB916, ++0xCDFFDD11, 0xB5519A81, 0x1BC7001B, 0x97C824DC, ++0xBB4C707F, 0x90166DC2, 0x42DFAB7A, 0x90E33184, ++0x6C6B940C, 0xDC553814, 0xC4F5E7AA, 0x99434AE9, ++0x82BB09D4, 0xCB0A7DA3, 0x3A8033AE, 0x054D3481, ++0xE20AF761, 0x25F5F254, 0x7AD3AF3A, 0x23A34C29, ++0xA19C57BC, 0x39B57AD9, 0x55E1EC59, 0x5ECA4198, ++0xDB908BCD, 0x4871C3F4, 0xE7091328, 0x64A9B6EC, ++0x1CCAB2F3, 0xEDB22423, 0xFFB6A717, 0x6FA13548, ++0x361FF711, 0x24664017, 0xCBBF9970, 0x83A7B7DE, ++0x9B704690, 0x01A0B877, 0x95041B60, 0xC048F3E1, ++0xA31625F2, 0xE3DFBE27, 0xF657295B, 0x1F5C3AF5, ++0x60EE1637, 0x575EDFAC, 0x725844FB, 0x242723D0, ++0x04FA46FC, 0x1A8C3F44, 0x0E03A5FE, 0x8778079F, ++0x606E4E1A, 0x7C0AF3D5, 0x9578B266, 0x63BCE765, ++0xA8ED66D9, 0x9242377A, 0x817A5D5E, 0xD0981A98, ++0xC07F2E7F, 0x0E66F84A, 0x3635F854, 0xD7AD8359, ++0xDCF23230, 0xC1B9084C, 0xA7987FE5, 0xC3B27EB4, ++0x1F747061, 0xFD278601, 0xB6ED3B5A, 0x9CEF8AA0, ++0xA5023C46, 0xB49832AF, 0xB12055FD, 0xD85310E1, ++0x2C19ADE6, 0xEFBB17A8, 0xC246A4C7, 0xBE4B2666, ++0x13C2D7F9, 0x50063BA1, 0x9B00E02D, 0x335B9DF8, ++0xD424AF25, 0xBAE40C92, 0xE87BD6B7, 0x384D1EB1, ++0x8B91E8F4, 0x9E3FC6D5, 0x6BB1A51E, 0x21AE5533, ++0xFCB8E713, 0x188B66B1, 0x6572E9ED, 0x98829178, ++0x7BAE8CBF, 0xE00C32B4, 0xDAFC14D5, 0xEA8FC746, ++0x2C8D712E, 0x89A05FC9, 0x9A274641, 0xAC2450AD, ++0x2437784F, 0x3B1B80F0, 0x0B4A31FD, 0x277C0232, ++0xFDDC6829, 0x3F3C606C, 0x0EF62352, 0x3D07D04A, ++0x4E0939E8, 0xD59BF115, 0xA02752E7, 0x42BF7133, ++0x9FA0939E, 0x64764109, 0xD5D03EBA, 0x3D4433A3, ++0x1749B437, 0x137298B1, 0x677BE344, 0xA83CEF7E, ++0x17813A39, 0xBC71823F, 0x2070E9A7, 0x3873AEF8, ++0x5AF1E21B, 0x1F0CC692, 0xB8EFB04D, 0x1A1CC514, ++0xADED6C3D, 0xDF35A8D7, 0x6D93275E, 0x9C362545, ++0x62BF7583, 0xFC56D990, 0x0CD6A324, 0xF12A7939, ++0x52587029, 0xD00D5F16, 0x51622555, 0x1178E887, ++0x81E7BCC8, 0x92BB1C11, 0x097330E4, 0xCF8C5CAF, ++0xD076D6BC, 0xBA292918, 0xF835A829, 0x4280A51E, ++0x09CD7827, 0x11583487, 0xB8BA2CEF, 0xD598AE93, ++0x99F4FD77, 0xEB151110, 0x1571B076, 0x63F2103A, ++0x56C6BF44, 0x9E63B556, 0xFB981238, 0x5D8C978B, ++0x9501D936, 0x82A1E971, 0xE5A4F7E2, 0xC6E3727A, ++0x03329F07, 0x248ACDD6, 0x437E917B, 0x23B02B20, ++0x73F76AA0, 0x75EA06C5, 0xD7C662B3, 0x267777F8, ++0xDC96BF06, 0x54020346, 0xCBDF069B, 0x030133EC, ++0xA7EF1C2E, 0x568959AB, 0x4FC31DE0, 0x3A22890E, ++0x280F8652, 0x1BD8CB24, 0x9A8D92C9, 0x52718DE1, ++0x12033FC7, 0xD48490CC, 0x681ADEE2, 0xF91BF7B8, ++0xB8609B38, 0x34CF4BCA, 0x8F123290, 0x0D0F4FCD, ++0xC4F43323, 0x2FC04F1C, 0x4669B890, 0x1E8D2A7F, ++0x0658CAE6, 0x5489F3A3, 0x9CD362FE, 0xBA5190B1, ++0x06A58820, 0x7A9AF759, 0xDC94E672, 0xEB284B85, ++0xF8EFA022, 0x3837C379, 0x7C9E9A2A, 0xD2ED96BC, ++0x5D1E4C7E, 0x97F2169F, 0xFC3C37C2, 0xE039EDF1, ++0xDBE93909, 0x81FEAC6B, 0xFCD383FC, 0x170B91FB, ++0x05BA3243, 0x8FB2ADE1, 0x52AFB984, 0xE8262E9A, ++0x1E704638, 0x89B8DFD8, 0x18C0C641, 0x2760C7E6, ++0xD3AFF3C9, 0xC4E3543B, 0x0C0B7910, 0x1DEF7792, ++0x483D7194, 0x9AAF5864, 0x08607947, 0x626F0CF3, ++0xC0F6A486, 0xEB4525CE, 0xA8BBA8F8, 0xE450DA14, ++0x2DC4D114, 0xBCA527C9, 0x6682AA4D, 0xCBB48A5F, ++0x1B474C99, 0x7F5B526C, 0xEC435C0C, 0x9E8D3E1A, ++0x67D2EA29, 0xA3B7ADCD, 0x8328590E, 0x7345607B, ++0xB6057588, 0x1A8B034C, 0x5C8CA534, 0x8115DC5F, ++0x189C2ABE, 0xF1B92927, 0x78A3B62F, 0x4B621D49, ++0xDC176A68, 0xCBD3C1DC, 0xD82348BB, 0xEEF05FA7, ++0xC0DD3D83, 0xC1F2A7BF, 0xB2079D00, 0x14B5730E, ++0x73203CD7, 0xA8672433, 0xA171FFED, 0x9F181200, ++0x4E16A5C8, 0x56D8AC31, 0x73803D86, 0xD4685CA4, ++0xE8DE9FE2, 0xA35D2CE8, 0x808CF3E2, 0x198700AE, ++0x0034163F, 0x57BC76FE, 0x271ACF93, 0xAA3AF6D0, ++0x37003A7E, 0x450B74F4, 0x157401CB, 0xB79DDDA8, ++0xD60AB7A4, 0x3A4C8779, 0xB6990FC8, 0xA1668D5A, ++0x05B7965F, 0x7814376D, 0xFA0D2D8A, 0xD97A1142, ++0xE804DE3D, 0x4939089E, 0x78D40CAC, 0x01DEF5EA, ++0x3DD1CADA, 0x96465956, 0x6358CFB6, 0xACE02DE5, ++0xB4C9F6CE, 0xE9C95AFF, 0x70EAD28E, 0x58803693, ++0x89EF9972, 0x58F0273F, 0xDB17A277, 0x0B082B98, ++0xAAB13ABD, 0xE86381EC, 0xC18924D4, 0xE28D4348, ++0xC21895AB, 0xE17073AD, 0x9417539B, 0xA043E5F5, ++0x88FFD026, 0xD972F017, 0xD0C8B8D3, 0xB34F3D67, ++0xC525E4B5, 0x0189A5A1, 0x59224A35, 0xAA18F2D5, ++0xFC9E170C, 0x16D3795A, 0x35DB09FA, 0x1624DB1D, ++0x4A6E059F, 0xC5C88A93, 0x9051D373, 0x4B12B09C, ++0x4088AF39, 0x705394F6, 0x360F2BAC, 0x8A1F2420, ++0x641D4FA5, 0xA78B78F9, 0xA5A5302E, 0x691D2108, ++0x7CFB57FD, 0x1812FE68, 0x8A2BB5E0, 0xF181CA14, ++0x1846848E, 0xDC044F67, 0x17FCCA28, 0x21D7C5AC, ++0x4C43432F, 0xC457E26E, 0xB0C9ADD2, 0x791EE2B4, ++0x620F27BE, 0x229E0B1E, 0x746B4FFC, 0x02038738, ++0x1C7B971B, 0x05193430, 0x8645DBD7, 0x58678F98, ++0x141E912D, 0xD89C587E, 0x9FD7B43F, 0x21851D56, ++0x725311A7, 0x0605B1B2, 0xC18BF2B7, 0xC6F79EA9, ++0xBD84A01B, 0xC9B7F2DA, 0x04E47EE8, 0x1C1A14F5, ++0xBD5B4FF1, 0xE15FBC2E, 0xC4D43F01, 0x5D39AD4A, ++0xBD3BD983, 0xB2314A4B, 0x8DABA67E, 0xB5263B5A, ++0x9912F262, 0x82659C80, 0xC3610181, 0x3F229014, ++0x2685532F, 0xCE4EC210, 0xF46AB09A, 0xFAFA69C8, ++0xD1292944, 0x2EF880D9, 0xD03AAEAB, 0x0E83C435, ++0x842C482C, 0xA70951A1, 0x0E4EA07D, 0xE0332D0C, ++0x3EA27E55, 0x04721425, 0x7C8B56DC, 0x96391312, ++0xF600D78C, 0xC850517C, 0xB3F9F2AE, 0x59A99351, ++0x8D6AA838, 0xF586672E, 0xD81FE525, 0x3CEF31DF, ++0xABDC7079, 0x6E1BB8F6, 0x6B45B87B, 0x9FD2CAC4, ++0x648E357A, 0x6C57D30B, 0x23766B64, 0x8C8BD9C1, ++0x9A29001A, 0x206F47E3, 0x5F423D75, 0x293A32C4, ++0xDCC6432B, 0xA4280954, 0x457790B8, 0x11E84CEF, ++0xAB11D0BF, 0xD04258E3, 0xFB44C0CE, 0xED8231B2, ++0x0277A6B2, 0xD8E5C517, 0xCEDF4C8B, 0x19D90170, ++0x20555532, 0xFCB610B9, 0x88D5F5A9, 0xD35DC77E, ++0xEF5EA686, 0xD866959C, 0xF0886B56, 0x005CFB90, ++0x582AD255, 0x7381289F, 0xC18CED4D, 0x444F0A6B, ++0x9917AE56, 0x505A7BCD, 0xCBDC903B, 0x51EF0F3C, ++0xC4E6AF5A, 0xB148AD2F, 0x609A124A, 0xB5DA89E4, ++0x3A68C7D4, 0x98694F02, 0xE85B1766, 0x754BA5FF, ++0x1296A58E, 0x27736843, 0x9B6280BD, 0x2686032D, ++0xB428AC04, 0xB06DBA5C, 0x625FE034, 0xD4BCB25E, ++0xC91C5B3C, 0x73BB70E5, 0xA26A479A, 0x73173229, ++0x3AA1235C, 0xE16171D1, 0x42D0D42F, 0xFC624752, ++0xF1F5DCC2, 0x1B6F20A9, 0xFF9D626D, 0xDBF052C0, ++0x90E38D23, 0xFB72CC5E, 0x9186519C, 0xF2330093, ++0xE5251385, 0xA0094977, 0xE83FA066, 0x2E389CE2, ++0xD3A62E72, 0xA9422A8B, 0xC61CFD5B, 0x1B3A516A, ++0x58087800, 0x3A47462C, 0x557DDD8B, 0x94FD21D4, ++0xE1AEA942, 0x4B2CC532, 0xB2185B36, 0xDCA15259, ++0x1D044D7D, 0x781317B8, 0x49CB13E7, 0xDAAFFBC6, ++0x30A05644, 0x77B05F37, 0x065A567C, 0x94721C79, ++0x47316C60, 0x58AAC7C9, 0x410081AB, 0x7D4A36FA, ++0xCDF23455, 0x1873EF87, 0x186982B5, 0x7C78D9DA, ++0x3567D966, 0x10FF5E8E, 0xDB88E5B3, 0xFF1D39A1, ++0xB8A345A3, 0x7A7258F3, 0x9706B3CE, 0xB5ADCC26, ++0x4561EF5B, 0xB002FBF6, 0xF3F4C6FA, 0x57EC75AD, ++0xBCF37924, 0xBC05B0AD, 0x2AB19DAA, 0x0EBD25EA, ++0xF335D08C, 0xDFF79E19, 0xDD86D418, 0xECE11951, ++0xC06F4D50, 0xFD698DF8, 0xBA6192EF, 0x365A28CE, ++0x74DEC0B7, 0xE971F67B, 0xBF89DD42, 0x1E683399, ++0x164A7158, 0xA1E48475, 0xBE139E8E, 0xBDEBA7FE, ++0x74E03AEC, 0x88EA9618, 0x9B0048C2, 0x68C1DD20, ++0x8DC9FC85, 0x24B55E3B, 0x51C38BDA, 0x2ECD7B13, ++0x54D66C89, 0x69A3EBC1, 0x4B4E4F13, 0xAD37B7DF, ++0x030A1D8B, 0x85A114D9, 0x403BE495, 0xB5E40331, ++0x316E7310, 0xB36AA494, 0xDBFFCB9A, 0x5C0E5DA5, ++0x099BA9E8, 0x66826E9D, 0x0BC5849B, 0x1A20CBAB, ++0x0744FBE6, 0x2CB52040, 0x8B88533F, 0xA8A44BF1, ++0x62FEB4A8, 0xDB2ABC4D, 0x46F0B676, 0xCBD06470, ++0xDB6D71EF, 0x5DC3551A, 0x71B31A5B, 0x046D4C7F, ++0xC051A998, 0x1EC19FF9, 0xA9E21F9F, 0x7951E081, ++0x78BCBA62, 0x91B623F2, 0x8EF6A81D, 0x1023755E, ++0xCE47F5AA, 0x0EF27527, 0xE9E488D5, 0xD53E4A29, ++0x78A276E1, 0xB2100585, 0x01208E3C, 0xA38BCAFF, ++0x36221FB7, 0xB3C9194E, 0x51BD75D4, 0x9C8C73AC, ++0x7ACA9964, 0x17890C94, 0x9FDA51F4, 0xC4FDF688, ++0x2C8244B2, 0x0D834C74, 0x290973D3, 0x7F134553, ++0x296D2FC2, 0x4E08ED27, 0x1C51E53D, 0x3D892F49, ++0x945F76CC, 0x2E531E63, 0x71EE37E0, 0x9C47F346, ++0x2D8D920C, 0xC3E465BA, 0x3A72D142, 0x5B6AB80D, ++0x364C2AE7, 0x3B18389B, 0xB9442484, 0x5D687BB5, ++0x97C65A4F, 0xC7DBE8BE, 0x0F840061, 0x5A73EA89, ++0xCBBDD954, 0xAFE9CABD, 0x06ABDF95, 0xF139302D, ++0x3804FEA8, 0x7CE6542F, 0xDE47B8ED, 0xD34BE509, ++0x5EB9C9E1, 0xDC582534, 0xE77D7FC8, 0x2BEFED7E, ++0x4EA26DFD, 0x54670B81, 0x665C4531, 0x5B7A7023, ++0xA05D9A2E, 0x71BDDB2E, 0x9D51D8C2, 0xD8A665CC, ++0xA9B87A22, 0x581D28BF, 0xF9D40373, 0xE04D8F63, ++0x117B9842, 0x8868B9BE, 0x8397FAB9, 0xEF5CED75, ++0xF70F90D8, 0xD3DFD3A6, 0x1779F576, 0x3059520D, ++0xC38F4AA9, 0x6B7A6D0A, 0x4E73112A, 0x4FF9DCED, ++0xAEA1383A, 0xBAB0AA93, 0x41DBCBED, 0x266775A6, ++0x8EE0D5D5, 0xB522CB9E, 0xC6E5D0D3, 0x86E4C8FD, ++0xA894642F, 0xF69821A9, 0x88B41798, 0x4585A188, ++0x9D2130FC, 0xC5B18E0D, 0x6B92C9EE, 0x3C9289FB, ++0x1F02CBB6, 0x31FA86DE, 0x1B2295CD, 0x5B4DA19C, ++0x3134D8FC, 0xE5EABC44, 0xDF8C5095, 0xF6571881, ++0x1F2FBD62, 0xE585FE61, 0x020CEDF6, 0xD70ABC83, ++0x5F37746A, 0x6FDA3BF7, 0x5434E503, 0x44CF6915, ++0x561B2393, 0xEA4A2251, 0xA988C080, 0xE47B1791, ++0xD335CFBE, 0xEDA9DEE2, 0x4F70FB22, 0x83A2C29F, ++0xF44FA002, 0x069D25EC, 0x4D5043F5, 0x887464CA, ++0x661D1E9F, 0x98B856AD, 0x81A23FB0, 0x3693BD42, ++0xCE0AEB0B, 0x1F6E8322, 0xCBDF571B, 0x93688909, ++0xFA16A774, 0x25834437, 0xEE77FA98, 0x8DC68C60, ++0x155A8760, 0x22B8FCA3, 0x1B1BB054, 0xCA3AFFCA, ++0xC8EACEA4, 0xC86BADD9, 0x473770AB, 0x41D6E398, ++0x568B397D, 0x065C0BE5, 0x51D38A0D, 0x3BB3A0E1, ++0xBC386DCB, 0x7DCBA6B0, 0x19007254, 0x3F4FC726, ++0xF27DAE85, 0xF7FDA72A, 0x6D0B5C07, 0x64A0ED12, ++0xE26D8878, 0x210E4F6B, 0x65F92C0D, 0x4E4E2CA6, ++0x5E479D49, 0x7B287050, 0xE9A4836C, 0xC3A111A2, ++0x9B90D6FD, 0xA5F362E0, 0xADC9526B, 0x79B736E9, ++0x72A9A57B, 0x181B4E70, 0x5236F32A, 0x5567E3C9, ++0x23EFD063, 0x87113163, 0xCDF6D4F4, 0xF53A8722, ++0xB70CF941, 0x757F40C8, 0x6A652BE7, 0xD71DA5AA, ++0xF87D51C2, 0xB4A68E16, 0x763D8FEB, 0xB6DE5436, ++0x12184DCD, 0x38D1DE90, 0xB39E5209, 0x1600492A, ++0x073AE8F5, 0x0366AC0E, 0x1AD5014F, 0x398E0873, ++0xD653928E, 0x30B5B4DE, 0xAC68A06E, 0x8DAEF4D3, ++0x76A880D8, 0xF3B3BCC5, 0x2B631F58, 0x340914DB, ++0xB4771DCC, 0x7C9D4A43, 0xAFDB1138, 0x014B5A83, ++0x0D44185D, 0x20C89576, 0x994B4367, 0xA84BD792, ++0xB2E17CB1, 0x00CE5214, 0xFB93E54F, 0x03CCA7F1, ++0x956A82E6, 0x22329A71, 0x2A634374, 0xF18B7AD9, ++0x1F168BC4, 0xC2CB1EDC, 0x8E0AF6CD, 0x211AF22A, ++0xAB5DA374, 0x63F1F25E, 0xEC58D4CC, 0x48C65C46, ++0x5A7F7574, 0x7BA60047, 0x279EF299, 0xE0B77F48, ++0x647A03C3, 0xAE7C4D8F, 0xF65149D0, 0xAC9EF228, ++0xCD90B1CD, 0xCEEDA54C, 0xD8FD0A6A, 0x8D7C2291, ++0xB38EF6C1, 0x7F38E676, 0xDADD0A8F, 0x1125713C, ++0xAA78A299, 0x54033F20, 0x199C76C5, 0xCAF82A17, ++0x16F2EE8B, 0x20071D0F, 0x2CA000F8, 0x0178A24B, ++0x0029EE46, 0xA9D8C738, 0x123D2BBD, 0xEF7CAC52, ++0xBD241869, 0x435F8FF7, 0xB573A190, 0x402BFB2F, ++0xFDA3097C, 0xF3765889, 0x68E2C7D5, 0x4C26F858, ++0xD6814D1F, 0x6B043C7B, 0x173DB091, 0x95126C7C, ++0x0FE8E1BE, 0xFDEB233C, 0xB979B0CB, 0x00E00659, ++0x19952E52, 0xA0976F7E, 0x02FB462C, 0x798815C8, ++0xA2504EFE, 0x0F4811AD, 0xBA8F122E, 0x5EE5864F, ++0xD39B6799, 0x5319F6A3, 0xF6A66685, 0x988D106F, ++0x7ABA5220, 0x0320384B, 0x4DE48C79, 0xF5CB36E6, ++0x2B33270F, 0xFF4E6965, 0xD4D843D5, 0x7EEE861C, ++0xA96AE5EE, 0x310E5215, 0x6D20068E, 0xB149AE8B, ++0x0997D9EF, 0x5043FFFA, 0x0516E2B6, 0x3FCCDA32, ++0x8E604A04, 0x23012778, 0x9444A474, 0xB7F5DC24, ++0x3A58E6FB, 0x17B759FB, 0xF29C1EE7, 0x8893D2D1, ++0xC6CD235B, 0xAAB0CBCE, 0x2D84474C, 0x8A0BE027, ++0xFDB87FB5, 0xE6B507BD, 0x19B41927, 0x783FF4DA, ++0x485A1D5D, 0x8ED285C2, 0x25AFC4C5, 0xBF0D662B, ++0xC4238532, 0x4339FCCF, 0x14A784B6, 0x71665819, ++0xED76E473, 0x5F1BAE9E, 0xD0AEC17B, 0x4CE78814, ++0xD3609F61, 0xD4E49EB0, 0xE4E3EFDA, 0x9B7CAD1D, ++0xEF01ABB7, 0xD137BEE9, 0xEE87A81D, 0xD4B204FF, ++0x00B25737, 0x2770FBD1, 0x174AFF7F, 0x0A77A21C, ++0xF1B370E7, 0x9C093CB0, 0x080C1FFA, 0x83CE92D9, ++0x1707470C, 0x3303479F, 0x25F1B6AF, 0xF40EEB7F, ++0xB98A1677, 0xA54A1BA2, 0x43B4144A, 0x2F092A35, ++0x33286A77, 0xA0AB9C93, 0x4F8D70DC, 0x3A47BF6F, ++0xB6209AB5, 0xA4C94557, 0x5E757055, 0x706EAD9F, ++0x467BC02A, 0x6472A857, 0x42055C57, 0x66F2BA60, ++0x33C0536F, 0x3240BFBD, 0x3DD74E6B, 0x1F58A552, ++0x822E9577, 0xF49BFE77, 0x5490DC6D, 0x1D32BBA0, ++0x1C30B072, 0x78A4A5C0, 0x1EE88A57, 0x97CAC3C8, ++0x9912861F, 0xC916BBAF, 0xFC3A7F0E, 0xCA5E1F3A, ++0x630F09CD, 0xF6C8C210, 0xF0A12A72, 0xF3148619, ++0xDF1672E1, 0xFCE5C390, 0x29CAE554, 0xE984A45C, ++0x8A1F0A3A, 0x6A02C707, 0x8CFB3ED6, 0xC0A741BD, ++0x7A871FE5, 0x91021A69, 0x505FB05A, 0x8F85227B, ++0xC300ACF1, 0x0A1B201B, 0x224614B2, 0x54A23576, ++0x5360A5BA, 0xDCD23A31, 0xF98DF638, 0x79FF79D7, ++0xEAC8EAC3, 0x4D22C65D, 0xDFFBF1D9, 0x55FD8848, ++0x4BFD2347, 0xE2A08287, 0xE6A48824, 0x80625EA9, ++0x71AB3F7E, 0x99B84DE5, 0x6512ADBE, 0xFBF24C47, ++0x3EEF2564, 0x23DF9F1B, 0x24BE5199, 0xDEDD72D5, ++0xA2FE063B, 0x4FE520B1, 0x9E4E7BBE, 0xD615BDBE, ++0xC14E8184, 0x40F86FB1, 0xD403A65A, 0xC5AF6386, ++0x412F8434, 0x6D6012B0, 0x4EC57107, 0x3F76AF19, ++0x54A305BD, 0xEA9C4EB2, 0x584E0176, 0x20759805, ++0x1A16C84A, 0x50BB10DB, 0xE610AF45, 0x98CF1EA0, ++0x3F8C7756, 0xF9056BE0, 0xBAA66B7D, 0xF7076DCF, ++0x67F1994D, 0x92BFEB62, 0x86FBDE17, 0x389DB311, ++0x2A171F5A, 0xE14898B1, 0x4D11723F, 0x29889062, ++0xCBF3DD79, 0x2B7468FC, 0x4FB93770, 0xC5FCEFE8, ++0x8FEE6678, 0x9F4ABA9C, 0x6A6B23E1, 0xFEA7077F, ++0xC835F734, 0xCA67807C, 0x1BFBEB49, 0xB8B1E842, ++0x6A850623, 0x001C1E8D, 0x782AC01E, 0xA28A72D8, ++0x6CD66FC1, 0x77EF6F13, 0xFF40D7CF, 0x4A163DFB, ++0xDB21AA89, 0x29D03A9E, 0x3A4D1D57, 0x7A89CDC9, ++0xC5623E10, 0x8A444799, 0x1F620DF4, 0xFF876758, ++0xC9DEEF2E, 0x7F86911E, 0xE3196093, 0xA00EB422, ++0xCDB1743F, 0x4AAD1988, 0x70167700, 0x70595C5F, ++0x8E648013, 0x401D8770, 0xC762F0E7, 0xDB776926, ++0x2BDC55B3, 0x8F4AD2C1, 0x1A2EEB50, 0xBD4BF2A4, ++0xA43FFE90, 0x752935E7, 0xB02C7801, 0xDD4CD3DB, ++0x3815C394, 0xAF427695, 0x7455A8F9, 0xC444C7EC, ++0x9BC9B2C5, 0x08423BA7, 0x5D91ADD8, 0x59D866DB, ++0x0AD32258, 0x7BC397F6, 0x0EF7DB59, 0xC1034320, ++0x79073406, 0x991A12B9, 0x9D6776A0, 0x6348A5EB, ++0xBD98CDC4, 0x81A6C5C5, 0x76A3ABA6, 0xFA9CDF77, ++0x97772B59, 0xD987E42B, 0xA4B893D4, 0x61F78E38, ++0x82567691, 0xCB91CD58, 0xEEFA69AE, 0xF7D51178, ++0xA436C578, 0x99E86E08, 0xA8C3B16B, 0xD609054F, ++0x1E0ADCE8, 0x5DF6EF20, 0xEB3CC45B, 0x9FAEA24F, ++0x97F57F19, 0x66E2713F, 0x42A423C3, 0x2A21B17C, ++0x6A4C6B40, 0xFA0F4F2B, 0xD1F3F64A, 0xD0AAFA50, ++0x767D3AC2, 0x837E626D, 0x3B21279C, 0xCAE18855, ++0xFA8CA385, 0xA91BDE45, 0x1A953327, 0x733948CC, ++0x158B8CD2, 0x904AC43D, 0xA6BC8F82, 0x55F027DA, ++0x95B6BB32, 0x9265FF80, 0x8EEF0D24, 0x28F6796E, ++0x1D736700, 0xB621D4D6, 0xAB2F1A4A, 0xECD7DB83, ++0x35CAD419, 0x60604917, 0x5DE51335, 0xA3D7E122, ++0x685D04D4, 0x494739D4, 0x0060722C, 0x59149718, ++0x03C9F144, 0x43328818, 0xBB1AE189, 0xCA7B9250, ++0xC835666D, 0x83950220, 0xD774405F, 0xF6F4FCCE, ++0x0E38794D, 0xAF184A7E, 0xEF66E15B, 0xA0C2A74F, ++0x876112D5, 0x7D68C9CF, 0x8902011C, 0x6AB0E128, ++0x2A515520, 0xA99D1DA0, 0x9EACEB4D, 0xB669AA8F, ++0x6F96DCE2, 0xCFEB5CDF, 0x46EB36BD, 0xEDDF8317, ++0x4FA30C3E, 0x9541A8A1, 0xA5F75533, 0xEFE1FEF6, ++0x7F21B481, 0xDA11D5EA, 0x64642069, 0x083D2137, ++0xDF508726, 0x8F6CCC4B, 0xC5412D0A, 0x6A9F6BEA, ++0x3E3CC54F, 0x078BBB1E, 0xA6047468, 0xF1FA39C2, ++0x26143435, 0x90132EB3, 0x4216580C, 0xF6773B8C, ++0xA6B188BF, 0xE3B49523, 0x89E4563F, 0xD0B16538, ++0x2D9079FD, 0x69ABDE36, 0x669AC5EB, 0xD0618DD9, ++0x5080BFEF, 0xADC056D6, 0x72402C9C, 0x0AE79E07, ++0x8D6DF48E, 0x0502837E, 0x79BA17AD, 0xE4871C89, ++0xC4554CD5, 0x23FCB2A4, 0x646FA999, 0x212A9DB8, ++0xBD23DF0A, 0x890B5FE6, 0xB5D03292, 0x9FA3FD59, ++0xD612F8B1, 0x611365FB, 0x7E7C9FAB, 0x024194D2, ++0x46C2C617, 0xAEB0FAD9, 0xAE5D3A7E, 0xEA8B0ABB, ++0x760730A4, 0x50443E76, 0xECA64341, 0x538E5256, ++0x8A8505F5, 0xE0E4DC29, 0x105DC564, 0xC73D93D9, ++0xE3F27C90, 0x8CC01FC8, 0x400D0F76, 0xDCD01130, ++0x1E3416D4, 0x4C612E03, 0x0BFE7A5C, 0xFDB15334, ++0x5326A77F, 0x99549BDA, 0xDDE90BAB, 0x920BD872, ++0xC4B4F5DF, 0x7B39BAC2, 0x777C6694, 0xB4971103, ++0x9E7806A1, 0xD3141F2D, 0x2B40BAD0, 0x74AF248F, ++0xD1AEED43, 0x2F453736, 0x1880104E, 0xF9CD502F, ++0x7691FE59, 0x39C3FEC7, 0x72EA7BF2, 0x0C94BAB5, ++0x35D6F509, 0xAE86AC96, 0x0624C181, 0xA69DF699, ++0x5991FCE3, 0xAB20D4F1, 0xF30F1BC9, 0xB094CF62, ++0xA3B5A732, 0x3BC8C32F, 0xE7710370, 0x429A8D96, ++0xD8913A42, 0xCFBD0E4F, 0x710B7078, 0xC6501E93, ++0x241224AF, 0x978D2320, 0x8EF1064B, 0x273FAE07, ++0x316EC02C, 0xB3C16C0B, 0x8249C245, 0x21AD11CB, ++0x6265FE57, 0xA9F1D5FC, 0x0B52F1CD, 0x0381D983, ++0x2931D6B1, 0xD126CD94, 0x69D95197, 0x7CFB6AD0, ++0x46E6D50D, 0xE60BCBD2, 0x72FBB436, 0xC971A4CA, ++0xA580B9B9, 0xBC823514, 0x5D15A840, 0x87A91622, ++0x63490D13, 0x277189A8, 0x22CA2EDC, 0x1C56456D, ++0x1B5EB836, 0xD8BBF2EB, 0x20F56DFB, 0x99321E4B, ++0x9238B783, 0xE5E5D085, 0xC81DAA11, 0xEF8DD032, ++0xCEC28645, 0xFC40AAA5, 0xBFA5FC68, 0x1C2CF7C7, ++0xC0DFD194, 0x5AB730DA, 0xE3FB56A9, 0xA0AD00E9, ++0xB7BA2E2E, 0x579C8722, 0x04AA07FD, 0xF55C6C5C, ++0xE56CD6DD, 0xA7DA5100, 0x2A6BA1E5, 0x9B7E5104, ++0x81410420, 0xDC6130A8, 0x3EC8935B, 0xCC2EC782, ++0x142344EF, 0xF016E0CA, 0xA3ACFA8E, 0x019A7009, ++0xA0DAEC5D, 0xFA503565, 0xC907794E, 0x77AA4E69, ++0xB45B7E54, 0x929A056A, 0x46AA4AE1, 0x55E56EDF, ++0xFDD9D726, 0x35744D5C, 0xD6854700, 0x9A6E1EEE, ++0x0B00F6FB, 0x6BE65BFB, 0x9CF98DE0, 0xD80ACE66, ++0x1E5300E4, 0x745338DD, 0x4CB925DE, 0xB369B0D4, ++0x7A53A606, 0xD2B96E54, 0x88F96B30, 0xB72C3E19, ++0xC2A41177, 0x6206F879, 0xC1F6CD78, 0x879DA74F, ++0x763F9417, 0xD109B779, 0x6A58B34C, 0xDCD7C21A, ++0x1B0A0154, 0x45EE3A9C, 0x62C60161, 0x79E47020, ++0x42250A39, 0x9E2C2C59, 0xCE4F6206, 0xC2970386, ++0x983CC2C3, 0x0DAF0A85, 0x388626DA, 0x06A56D27, ++0x9223203A, 0x96E0148C, 0x22F0D052, 0xD5F1AA88, ++0x394BC8B9, 0x03CF58FA, 0xC0B1073C, 0xC16B35C7, ++0x7B7CF9F8, 0x2E3A24A5, 0xA19089C9, 0x4223FAE9, ++0x7751D977, 0x802E7062, 0x6D3651EF, 0x39E9B52E, ++0x946D07F8, 0x8E2EAEB7, 0xF9279A65, 0x14DEE911, ++0x8B92A149, 0x9611756E, 0x067DD22D, 0x59907967, ++0xB3417E3C, 0x3B72AB7A, 0x825D87C7, 0xCE5FA852, ++0x5D88C5F8, 0xE792BF66, 0x28DB3A4A, 0x118CA3A2, ++0xCC86284E, 0xA0AC4AE8, 0x33394B70, 0x974F96C2, ++0x86ADD3B5, 0xC87295B9, 0x1447D26F, 0xC9ECAE80, ++0x10CA01D7, 0xE04ECC68, 0xAE56597E, 0xAAA1248C, ++0x81C35460, 0x0087CA93, 0x943AABA2, 0x0AFCBFAA, ++0xEA77D5AB, 0x020D36D6, 0xF1CCBBB6, 0x8DF1426F, ++0xAE726D96, 0xA6E4C915, 0x58F15F91, 0x5B696D6F, ++0x00042B30, 0xC6AC90C3, 0xBD8E0187, 0xE73ED2E2, ++0xCEE64CF6, 0x48B56436, 0xA33994CA, 0xB3E3B7AB, ++0x060D5E14, 0xC1B176C6, 0x4A76C391, 0xD7C8DB1D, ++0x333E4998, 0xC20BAC4F, 0x523BE3E0, 0x237E87BC, ++0xE6CDBEC0, 0xC506F19C, 0x262C0039, 0x7F85A4AC, ++0x46160693, 0x2EA1BC36, 0x4CAC0DF2, 0x0066B83F, ++0xBCBC778D, 0x7F4AB507, 0x99CADB2F, 0xC95520D0, ++0xC5CBF067, 0x903ECD68, 0xF5D7B0FC, 0x08198C8F, ++0xA17879EC, 0x18C2723D, 0x5A4D6D37, 0x080198B6, ++0x3525186C, 0xEF8BE144, 0x44B05851, 0x28B5025A, ++0x0FDF085D, 0xDEB1F249, 0xA7C00F42, 0x7614A735, ++0x3BEBF467, 0x7871D305, 0xD4F63809, 0x9D044079, ++0xE585D3D6, 0xA89952F3, 0xF42C2B8E, 0x04179DA4, ++0x00A6CE87, 0x96CA92B8, 0x9DF2B156, 0x3ECF18BC, ++0xDE2509CF, 0x5CD85FCA, 0xF8A7CEEF, 0xCB7DC25E, ++0xF2847474, 0x35B501D1, 0x137BBB3E, 0x451E1BB9, ++0xD360D811, 0x792B3464, 0x4BF89A81, 0xA7E9C450, ++0x628BCB0C, 0x2AF7037D, 0xA45F628E, 0xF0EC875D, ++0x9CE3677D, 0x2CD0EA59, 0xA50A0217, 0x8BA45DD7, ++0x1735ACF1, 0x5804C4D9, 0xE619B352, 0x948F44A8, ++0xA9BF5C7F, 0x614D4F6C, 0x6D9FCA79, 0x29717B0C, ++0x50BF2D5C, 0xD5847B52, 0x0D4FAAA5, 0x1AABCA5D, ++0x779399E0, 0x58A90CD6, 0x37EC2615, 0x61B68C07, ++0xC49F4AEE, 0xFAC4D897, 0x9C68CC6D, 0xBB3352F6, ++0xF933436D, 0xD310078E, 0x2FBFA17A, 0x3D839C4C, ++0x186E69EF, 0xCBE7CC6A, 0x7434231A, 0x80F8130B, ++0x58CD7EA2, 0x2E46D714, 0x367286E2, 0xA6E2044D, ++0xC2ABC50A, 0x6FEDC9C4, 0xE2F26F03, 0x3B030D52, ++0x3674D8E7, 0x9096DF78, 0x90902892, 0x44A32190, ++0xD08D2649, 0xEFE0ED0A, 0xCE1BF4E9, 0x62C19753, ++0xFBF3D1A8, 0xD4AA5390, 0x4B32E77F, 0x9894F05E, ++0x41B9DBBE, 0xE9B09561, 0x46C883A0, 0xADD5D60F, ++0x69CE5BBE, 0xFD29CCF1, 0x2F209371, 0x4C6716E9, ++0x31E9A09F, 0x04089795, 0xB9EF9025, 0x97C6267D, ++0x63823150, 0x3AB346BA, 0xED3E0579, 0x85FC7062, ++0x37B35761, 0x4A32B6CD, 0xC38EB479, 0x203642CC, ++0x568FCAD7, 0x67D92B5D, 0xE51B8C3E, 0x02104078, ++0x026BC607, 0x5A06CDA7, 0xE27435D0, 0xC7C20CE7, ++0xFEA74022, 0x77310076, 0x35C6F953, 0xE1B199C5, ++0x262F139B, 0xFD2FE2C7, 0x3EEE02EB, 0x915A873F, ++0x2DE4AB8E, 0x2421DC15, 0xD1DD0D9E, 0xDE02B5AD, ++0x151C76CF, 0x798B90B7, 0x82EDDF4C, 0x795E18CF, ++0xF09CEC5A, 0x070ADF8F, 0xCDCF5232, 0xD498D43C, ++0xB4FC2662, 0x25678E54, 0x5D200482, 0xC31F21C9, ++0x35E5AF29, 0x8CC0E603, 0x995351AD, 0xD8EB54F6, ++0x564E35D9, 0x0C13E321, 0x34CFA33D, 0x33D1E5F9, ++0x2EAC9748, 0xFFB950D6, 0x2032206F, 0x4F871AE3, ++0xBD464C61, 0x06356EA0, 0xA15A290D, 0xA78456D0, ++0xD2F4EE88, 0x4D835908, 0x15DC87B3, 0x79EDB6C3, ++0xAEAF0F9E, 0x5C3E7EF9, 0x639A099E, 0xD375D8DA, ++0xB718510B, 0x090DF965, 0x9C8A362E, 0x25AD10BB, ++0xF9A42BE9, 0x8ADE3DF0, 0x5527424E, 0x301F0D0F, ++0x2F691C9A, 0x534FE1FC, 0x7D406016, 0xF98820A2, ++0x4D204871, 0xED145173, 0xD67ECE9A, 0x35F9F990, ++0x8ED4D787, 0x1F3F46E1, 0x5A68F171, 0x9A9D28B0, ++0xE726BD5C, 0x8119228D, 0x0ADBA4D2, 0xEA243204, ++0xE523C0D6, 0x261E3664, 0xB2D1211C, 0xB4D9293A, ++0x9C89D924, 0x15A6A3A9, 0x0D8C6C66, 0xEC04AD36, ++0x0CDF0F98, 0x9262C7DF, 0x8EE0E09B, 0x6B929EE9, ++0xDCC713BC, 0x75FD34FF, 0x2784E694, 0x23C23044, ++0xB7B04F09, 0xF10B753E, 0x2EC774DA, 0x470BE72E, ++0x054510E9, 0x9C7DDF10, 0x1466C277, 0x9F52F493, ++0x7F298608, 0xF1BA10D3, 0x8847A319, 0xEE8A63CA, ++0x8E64B34E, 0xEBB66933, 0x575ADB24, 0x041BFD76, ++0x727ED364, 0x00F4A008, 0x8F5EDA92, 0x21477637, ++0x0B360617, 0x56DC8978, 0x27F88944, 0x69B799EF, ++0xEA1E943B, 0x6FDD60B0, 0xCE2AD89F, 0xB98CCF43, ++0x2A3796BF, 0x4DD02535, 0xC6B524EA, 0x6B173341, ++0xDCE0A457, 0x91770646, 0x57A8D138, 0xFC218331, ++0xDC6B712D, 0x14C0B3B9, 0x30CA09AD, 0x759EB942, ++0xBC9634AB, 0x8F92A7E5, 0xF7F85B53, 0x6C831B3B, ++0x56A75B18, 0x43DB9F1C, 0xF81FC212, 0xB8EB9026, ++0x78A74B51, 0x870655E3, 0xA17B536D, 0xBDE866CF, ++0xFC609F11, 0xF34A7016, 0x7C4FD4DD, 0x236312F6, ++0xB50520A8, 0x4BEEA2C3, 0x2B690BA3, 0x18701667, ++0xBD791FA9, 0x236D36CF, 0x49E576CC, 0x316A77E1, ++0x93E9B0BF, 0x52715603, 0x83B9AAF2, 0x0F8F2A80, ++0xA87F764A, 0xD2079BEB, 0x48A24AB6, 0xAC370950, ++0x3077FB2F, 0x4BAFF3F5, 0x1A79926D, 0x8B369956, ++0xAD78F739, 0xED88CE42, 0xB96A7C15, 0xA7BBA2EE, ++0x47CC3233, 0x804DE962, 0xE0B431A3, 0x4A8257B8, ++0xA4B0E8E2, 0x2FFC49B8, 0xF0CDF5E5, 0xF089C32A, ++0x46328288, 0xEACBC054, 0xA48CB5CC, 0x77996530, ++0x83A4E184, 0x3C2F47D9, 0x5106177C, 0x33F1A787, ++0xA2266E7A, 0xEBC426C8, 0xD7E8ADD3, 0x2DF40477, ++0xF9E8D7BD, 0x80BD8EAB, 0xE61CE55F, 0xF6A7EF6F, ++0x5C67E1C0, 0xFBD0088A, 0x7ED37B24, 0xF5BFD58E, ++0xC29CFB0F, 0x61ECE08B, 0xA776CFD8, 0x9E0F3A05, ++0x8FC8B02F, 0xFDF82702, 0x028C2F2C, 0x169D3094, ++0xE4AA3228, 0xF2CD142D, 0x9C70574E, 0x057BFE78, ++0x782B9039, 0x0D01311F, 0x97552050, 0x6A097F2F, ++0x1B3242B8, 0xF43F32FB, 0x96004287, 0xC3DC0939, ++0x4215A0E1, 0xACD1A28A, 0x189932EC, 0x9BBA0475, ++0xFA154E5B, 0x4B4E8D01, 0x4D6B18B1, 0x31545B3C, ++0xC849C52D, 0x60958B9B, 0xE92CF090, 0xAC3E1B58, ++0x251D02A3, 0xFAEE4F8B, 0xB1CF6CCC, 0xC2A0D8B0, ++0x0501DF46, 0xD0369D94, 0xF3E11479, 0x397599F8, ++0xB90064D2, 0x341F6D57, 0x31F0141A, 0x2F899029, ++0xBC9EF6E8, 0x13B47347, 0xB93D59BB, 0x556E990F, ++0x5727BDFC, 0xBA9F5121, 0xD67BE7CA, 0xB167E84D, ++0x2C0ED0FF, 0x251FFD4A, 0xC98719F2, 0xD379D976, ++0x8B3A0A9B, 0x40BA5F66, 0xE40A93E8, 0x2F89FC04, ++0xFCBAFDD4, 0xF2424270, 0x1BDBDD15, 0x7F1459B0, ++0x5ACB6C6A, 0xFA20719F, 0x2F16FFB4, 0x820DDE50, ++0x468AAC15, 0x7816134C, 0x978D9570, 0x6745CD6D, ++0xC1E768C1, 0x15E243B5, 0xBA30AD61, 0x483FB6FE, ++0xCAA17D0F, 0x2F8F0974, 0x34AB68B4, 0xB3E864B0, ++0xC1DA3828, 0x5DAD43B0, 0x72D13B81, 0x01F274AB, ++0x9C0651AD, 0x0FC30C10, 0x0E7AA3CB, 0xDBE6B9D9, ++0xF423B9A7, 0x457B4E32, 0x40E8E269, 0x91DA042A, ++0x9DBF41E9, 0x308C0F2E, 0xCABFAC0D, 0x0E2C86B2, ++0x117BC3C6, 0xEEA538F8, 0xF31585DF, 0x0DF50281, ++0xEAA9601E, 0x8F408AFA, 0xF1144F9A, 0xA2AB2ECD, ++0xACB88685, 0x6F4EFFBD, 0x81EEF886, 0x46B02240, ++0x3C09D916, 0x4F0DAF68, 0x8337B3E3, 0x9A011BA6, ++0x4C63AC66, 0x2FCC669E, 0x0C7D15BB, 0x51279D9F, ++0xC1354779, 0xEFF940AF, 0xA956CB37, 0x0DB797E2, ++0xE665EE55, 0x79AF879D, 0x21BBC902, 0x30B264BF, ++0x411CDC98, 0xE453389F, 0x47C2C197, 0x3E6015F8, ++0xF9E7AA2B, 0xA9302474, 0x04C6888F, 0x4D118BF9, ++0x0DB7AAC0, 0x52A38EDB, 0x4DAB22F2, 0x7DBB6EAB, ++0xD4D17851, 0xFD944314, 0x40C5838C, 0xBA6EB0EF, ++0x9AA287A5, 0xF6D236F0, 0x41D9E2BA, 0x6968D776, ++0x31B1D129, 0x42C3F963, 0x27CCAD30, 0xCD61BF4E, ++0x2C7DABAB, 0xA78A9CC3, 0x7F856B6F, 0xB6D444A5, ++0x90CBB312, 0x95611781, 0x4916D531, 0xC496C30E, ++0x706D0CB7, 0x35D0064B, 0xFE26C36A, 0x6211F14B, ++0x2C2340BA, 0x58633567, 0x06B6BA8E, 0xA7EC3D8D, ++0x1071B0CD, 0x388EEFA8, 0x60D8FB1C, 0x5F99D147, ++0x52CA6EBF, 0xFA73602E, 0x0376C15C, 0x3C91B57D, ++0x9386AF17, 0x14A35A1A, 0xBDB42A39, 0x0E83C257, ++0xD4C5C775, 0xA607FA46, 0x91B9AD40, 0x7623C5D6, ++0xE3D53E6A, 0xA3C663E7, 0x5AD39BCE, 0x03B58394, ++0x38862C7A, 0x01D50B9F, 0xEAAB38EC, 0xAB3DFB8B, ++0x06795385, 0xB17F485E, 0xE2F57914, 0xB79A3BAA, ++0x13DA7886, 0x7136C7EB, 0x5E748AF7, 0xD34F16FC, ++0x968F6701, 0x99C5D7BE, 0x530F7FAC, 0xCDF5D567, ++0xE31DE0D3, 0xCF93BC68, 0x34C578AA, 0xA201F761, ++0x5CB8DC00, 0xCA24DB98, 0xF8AD7E4F, 0x808EC476, ++0x603BA751, 0x489555C6, 0xF2A03FF0, 0xD2461E9A, ++0x102C33BE, 0x7673933C, 0xC11A2424, 0x6A23C8C6, ++0x69499812, 0x19AA8510, 0xC8CDA75F, 0x34B5216A, ++0xD87F7420, 0xC8CEDB53, 0x8DF11BA2, 0xB10911C6, ++0x3F1E5955, 0xF075F4EB, 0x17874FC5, 0x0D55685B, ++0x5EE521E5, 0x46C72924, 0xF8540210, 0x5D5E4C5C, ++0xE87A133C, 0x91633DC9, 0x36B54D5D, 0xA8B5D440, ++0x7DB7D6C4, 0x5FA82C17, 0xAD679039, 0x86B3B839, ++0xDF5121B7, 0xC08B768A, 0x338A512F, 0xCF9A4F9A, ++0x5DEFBB5B, 0x4C9301B2, 0x08023702, 0x5B1D7E28, ++0xEC800505, 0x3A869E80, 0x4C50C8AE, 0xB1AE9064, ++0xAFFA34EB, 0xF2F006B9, 0xD8A9A3D1, 0x2C6C2134, ++0x677EE648, 0xBB6B6D5C, 0xA285136C, 0x6C47BF4C, ++0xAF158DC1, 0x0EF75E2B, 0x5B9C74D5, 0x9B8D4BE3, ++0xE495BE19, 0x5940B228, 0x55E62656, 0x3247E060, ++0xBF7094CD, 0x1C1AB380, 0xECEA2275, 0xB6DD8251, ++0xCCA39DD2, 0xAB85D992, 0x278197D2, 0xFB6C9FD0, ++0xBD53B458, 0x89EFE0EC, 0x52A3DFFD, 0xA6B7FF7B, ++0xFB043649, 0x93C93F79, 0xAEB4CD6D, 0x71DB5C90, ++0x9E8DFE92, 0x0F1A5B91, 0x55C5CF5D, 0x1A1847AC, ++0x8D25CF6C, 0x914FD316, 0x39FCFE20, 0xD8F66A07, ++0x2CDD3DC6, 0xE415AC72, 0x3D1BD09B, 0xA8322C59, ++0xBD3A826A, 0x2A988A40, 0xEBD8B1DD, 0x9F53EEEF, ++0xDF571816, 0xD4FCCDAE, 0xB85A1E50, 0xBE1A571F, ++0x0ED07534, 0x4C1E471A, 0x8B4D36F6, 0x0E388FC6, ++0x9ED2BC4D, 0x3E2D7F72, 0x752ACA15, 0x8960B48E, ++0x5892B3D7, 0x70F6F3CD, 0x26C485EF, 0xC83839B9, ++0xFE6C224B, 0x3547203F, 0xF73ACA84, 0x065DCDBC, ++0x8986EBDC, 0xCD59EA14, 0xC0EF58A8, 0xC5587229, ++0x484FBCEF, 0x9B8BF24D, 0x351CF946, 0xE10AA973, ++0x17919640, 0x95FF7B1C, 0x82AB65E5, 0x070BCC98, ++0x0E7CDB8D, 0x38DB27DE, 0xCA543C2B, 0x0131EB41, ++0x8300996B, 0x88B63D66, 0x03ADAC1D, 0xB205A87B, ++0xD8BDC0C6, 0x443F6071, 0x2CE69D2A, 0x6E1E5A53, ++0x4EFF93AC, 0x70322657, 0x5CCDD146, 0x04C435B6, ++0x5BF3CD69, 0x51E09115, 0x2545DFB2, 0xA52EF448, ++0x8D387046, 0x7C4F1F25, 0x2EFFD8AA, 0xFD6422B0, ++0xB82E26A7, 0xCF01CC45, 0x88899EBE, 0xDB621966, ++0xBBA1822F, 0xB264AAEB, 0x1076EAA5, 0xC24B0CD5, ++0x54D554B0, 0x4ECA7C05, 0xC8C9B053, 0x70A86D97, ++0x4E3265CA, 0xEA24F810, 0x873B172D, 0x79A74D18, ++0xEC3F49D5, 0xD1799602, 0xA21A28B6, 0x3FB99AD1, ++0xC2DB35B3, 0x63EC2E51, 0x17E4489F, 0xE8E19164, ++0x79ADD819, 0x10D66157, 0x5F621A73, 0x1CD063BA, ++0x6665815F, 0xFA0B7081, 0x6E0FA473, 0x0CE3571E, ++0xB5EAEF46, 0xAA04CF54, 0x336680CA, 0xDABBFF11, ++0x2259E797, 0xB57B4470, 0x111EB4BF, 0xC171D42B, ++0x5889A7A4, 0x419CCB3E, 0xBEA1F366, 0x41FE414B, ++0xA65CB898, 0x6C28363A, 0x8F82FC84, 0xDBED5A9C, ++0x4DBF3526, 0xF2F34E66, 0x9D2C9B11, 0x0C0D4DFB, ++0x4DBF79D4, 0xA256E86D, 0x6407376C, 0x3F3E8AFF, ++0x474B3593, 0xE55965C8, 0xCB20D358, 0x0C671A9B, ++0x169F8342, 0xD2E1C9E7, 0xBDDBAAEB, 0x93DF0C75, ++0xF27707F7, 0x5108305B, 0x4FF2C060, 0xEB9C08DE, ++0xDF11020E, 0xD2271046, 0x6D1BFD27, 0xED020CDC, ++0x2C22659B, 0x692050D9, 0xD14BE291, 0x3EBF8E86, ++0x8344B625, 0x7840B91C, 0xB702BD5F, 0x4935D318, ++0x01A22013, 0xF2A20B08, 0x651A1C38, 0x004FE633, ++0xE51DCC06, 0xF5B86138, 0x9FBFF118, 0x6F7B3CD4, ++0x028938B4, 0x071E96AE, 0xDF33DC9E, 0x79001AC7, ++0x7B5D20FC, 0x3F137794, 0x81165B04, 0x973F8FD4, ++0x0AE4CBF5, 0x7C48180B, 0x4A96BC89, 0x58066E74, ++0x86669DC6, 0xDC55A218, 0x858C3130, 0x99AEAC91, ++0x26983FC4, 0xEE4D4F06, 0xD8D6D657, 0x18EF262B, ++0x374A620F, 0x85995F9C, 0xCC814AC1, 0x39F487E0, ++0xC628177B, 0x2FAE2C39, 0x642525A2, 0xC1474F2D, ++0xBC7CD49E, 0xE81E13F7, 0x83F42BDB, 0x8AB7D99A, ++0xA8040B11, 0xD8AA68EC, 0x983B3739, 0xEE42ECDB, ++0xC9513498, 0xCAA06A14, 0xE4784094, 0xE6BEBB9E, ++0x13BE8018, 0x59E3D5D4, 0x0CF1728F, 0x963413BE, ++0x319533B7, 0x14662ABE, 0x3363B45D, 0x59A99687, ++0xBBB0FDA4, 0xCDBB8B21, 0x0240F3B1, 0x226DAC3B, ++0x30E1C49E, 0x76E076D7, 0x4B91C598, 0xB3C46E2F, ++0x4A657CC7, 0x66C3875A, 0xCBC6FC54, 0xF832EBE8, ++0xDD1EAD3D, 0xFEFDAF85, 0x8DE51B88, 0xAEAFD5D3, ++0x3E4CEA82, 0x55F47934, 0x9F8314CA, 0xD0220BC0, ++0x5ACEF81F, 0x71FDD8E9, 0x13A14ED8, 0x6F1FC1E4, ++0x75046A04, 0xC6C4FDAF, 0x4FFFF724, 0xF44FEDD6, ++0x7E1C5CBC, 0x784C6B4C, 0x8D85F220, 0x38B65C3E, ++0x8C992050, 0x2DE34C13, 0x9F2A4547, 0x48E58F65, ++0xA280B689, 0x6F540D8A, 0x10B61B39, 0x1C8A2849, ++0xA7316358, 0xDBFB7862, 0x182C553D, 0x92F04389, ++0x1FE7BADD, 0x6A724CBA, 0x970BE020, 0x93760058, ++0x2DF9E0AD, 0xCFF1F8B1, 0x170D810A, 0x45F4E6A2, ++0x37A0E8FD, 0x86D11C6D, 0x4F3C6A3A, 0x4B144452, ++0xCE9B87A1, 0x7C08C30D, 0x9CB9B0AB, 0xD55F2CC5, ++0xFF95180F, 0xF35505BD, 0xED5BDB96, 0x85CA2E41, ++0x8708B264, 0xD6079734, 0xCA76AB3D, 0xFD6CDF4F, ++0x9AAB840B, 0x92D3A5F7, 0x93A92C38, 0x0419AA7A, ++0x1D50006E, 0x126F48FF, 0xACDA412C, 0x01139454, ++0x8E23C486, 0x01D44F51, 0x7A5F6F10, 0x377D4D5E, ++0xB784E72F, 0xA9AC925F, 0xB9C66C79, 0x057331E6, ++0xCFF040E4, 0x77E8A960, 0x35E31EEC, 0xEB807A44, ++0x8594FFFC, 0xD27629B7, 0x5DDF526E, 0xBCF2F484, ++0x88805013, 0x41047850, 0xB8574ECD, 0x3E15082F, ++0x309C16DC, 0x297B6904, 0x30C39ECB, 0xD20B61AF, ++0x51A578AF, 0x4E0D24A9, 0xC61FBE5F, 0x7A89F4C6, ++0x9432299D, 0xFE261B95, 0xDD1FC4CA, 0x044BFB92, ++0x41BE56CA, 0x0A2B6831, 0xE135D75D, 0xAB2D00A0, ++0xB4374080, 0xFAA6DBD0, 0xA704C4A9, 0xD81385A4, ++0x51533312, 0xED5EDAF7, 0xE4EDFAEB, 0x74B7DAFE, ++0x9D810AA7, 0x40B91827, 0x65219BCB, 0x75431C16, ++0x94D923D3, 0x00B7AA4E, 0xB8A88FDA, 0x927278D7, ++0x7A237697, 0x45B14097, 0x2E3A562F, 0x93003322, ++0x0B88A5FF, 0xD13D4ADD, 0x6D7B7579, 0x72D834C4, ++0x0BCAA361, 0xC02E00B8, 0x15023551, 0x481C5E93, ++0x02E81A16, 0x8A846A33, 0x1239A971, 0x994818B4, ++0xFC3DBB6D, 0x43C8D2F2, 0xE3AE548C, 0x408032F1, ++0x02B05636, 0xE361A60C, 0xFE2CA292, 0x061D2374, ++0xDB285556, 0x70627EA4, 0x7FC64AF0, 0xFE100B6D, ++0x71AEB3F2, 0xA565A412, 0xA698731F, 0x49DD9767, ++0xC3627EBC, 0x75FB2DBF, 0xFDC0E971, 0xF6ED12A6, ++0xA23DC00F, 0x897E917B, 0x7F2031E0, 0x17DCE568, ++0xDF69CAD3, 0xC6FB5B6D, 0x097268B0, 0xE1102444, ++0x86DF9383, 0xBD7B9CC2, 0xBAAF7DCF, 0x985B45D1, ++0x4218E95A, 0xB2455EF4, 0xDB015F9B, 0x54CCCE76, ++0x56EDF561, 0x6F66F95E, 0xF8B1EBD0, 0xF7A39AE0, ++0xF66D8346, 0xA4677007, 0x02C4B3EB, 0x829987B0, ++0x7C0E1919, 0x51F7060B, 0x4B30F1D6, 0x85A4E0CA, ++0xEC049FA0, 0x17CBF1E4, 0x7A1AAD95, 0xEBA4C513, ++0xE8462E78, 0x54CDDA0C, 0xEE7B8378, 0x9858C8C1, ++0xBA33587C, 0x4D6F1B14, 0x7A2C0525, 0x7E6EE4D2, ++0xACA18692, 0xDD186820, 0x41198B03, 0x8AC85AB7, ++0xBD86900B, 0x36E2C354, 0xE65F9115, 0xB10645DA, ++0x7971D230, 0xC83D3583, 0x8C60C81D, 0x94DB5741, ++0x4FCB8934, 0x9A520FE2, 0xCE49446D, 0x8864E641, ++0xF5EF25A5, 0xC1DEED0A, 0xC8057F37, 0xFB305C73, ++0x392E670D, 0xA4D00D2A, 0x356A46F0, 0x2F675567, ++0xB7997CF0, 0x88AF3A4E, 0x56C9D51E, 0xDD746ECD, ++0x40CFA453, 0x5EA740CD, 0xE4DD6BB1, 0xCCB31429, ++0xA2227F3F, 0x18A1EAF0, 0xC155417B, 0x41FE735F, ++0x16D40B00, 0xC9F72AFC, 0x86B1D62D, 0x6A99A82A, ++0x09D33248, 0xEC44639C, 0x9B0AB2B2, 0x6969164C, ++0xEF602BB1, 0x0208FC6F, 0xC1109578, 0x2997AB87, ++0xE5626B14, 0xCDAF48E1, 0x20781633, 0x2EBE0A41, ++0x7379261E, 0xF216F7A1, 0x714D8258, 0x936FE68F, ++0x160856F9, 0x2A4D1416, 0xB558E412, 0x7DB196DF, ++0xDC88CCB2, 0xF37AB612, 0x7423F214, 0xD3B06A43, ++0x25A8012D, 0xC1C69FFA, 0x936F2C18, 0x56D77C19, ++0x774BFC69, 0xF5E85E24, 0xD79158C9, 0xA67C3E15, ++0xB958819E, 0x69F81278, 0xF2B35107, 0xBF2F4085, ++0x1C997A06, 0x6C238C3B, 0xC756D56E, 0xD15C1149, ++0x351E6EC4, 0x2311303F, 0x0621602C, 0xB11B6DD1, ++0xBE8E50B5, 0x34A5F589, 0xE4D308AE, 0x4344B297, ++0xA33AE98D, 0x0A303CDB, 0x388EA17B, 0x0107B5A5, ++0x38B39042, 0xFE678995, 0xB426FE69, 0x221FCF06, ++0xC45926AB, 0x21A430F9, 0x6D192D2E, 0x4168C10B, ++0x5BA6B132, 0x0519ECA7, 0x21127582, 0xF6C447E0, ++0x0C72FC31, 0x0941B3F0, 0x76F23877, 0x86CF0677, ++0xE7785105, 0xA4637864, 0x94C82B45, 0xF60FD6A0, ++0x46941C27, 0x7A33A698, 0xE1DF8BFB, 0x5249970B, ++0xDFE65E1C, 0xF4A4FB22, 0x599639F4, 0xFE0E9722, ++0x7BB48F58, 0x533465E3, 0x9E884B35, 0x2620429C, ++0x2875FFC1, 0xF11EC0CA, 0x663AF5F0, 0xB2C59C38, ++0x03556ED9, 0x271E9E39, 0x8556E062, 0x08207682, ++0xE5797F00, 0x66A362B5, 0x7ED8394D, 0x2922C374, ++0x271657BE, 0xAC15071B, 0xE296691E, 0x0FE2C740, ++0x19120FB5, 0x9ABD888A, 0xA200762C, 0x7837F41C, ++0xC6F4EA19, 0xF286ABF4, 0xFCA8998F, 0x97B0E7D5, ++0x1339C79F, 0xFED05D43, 0xB3392E71, 0xFC2A01EB, ++0xB720CBED, 0x4FA71358, 0x04A57F62, 0x3D558B0A, ++0x1DEB4D40, 0xC9C823F1, 0x470F630A, 0x08F22975, ++0x2BD85107, 0x3288A628, 0xB0C89675, 0x32D957C1, ++0x80B78426, 0x98A46953, 0xA493AF60, 0xC2B84AC4, ++0x486D658F, 0xFE119FF9, 0xB2FE565F, 0xEADB58CD, ++0x1F45F9B4, 0xCEAE62B6, 0x68EC702D, 0xF52ADDF7, ++0x0FFC0715, 0x4129E42C, 0x956AC4D9, 0x0035CD9C, ++0xF8FEBAA1, 0x29C58397, 0x7C2E2E41, 0x7BE74DAF, ++0x2791D34D, 0xB6D67B0D, 0x8F557528, 0x9DDEED5B, ++0xB3AA4BB7, 0x05E22E43, 0x4CDA600D, 0x432E2D32, ++0x405DA5BD, 0xAF23818C, 0x2F73FE09, 0xD4624626, ++0x653EFCB3, 0x77D65D3F, 0x51A3DCB3, 0x767F407C, ++0xC66452E3, 0x10B6842E, 0x93A0840E, 0xE453AD10, ++0xDE58FC3D, 0x6C227215, 0x1EE130EA, 0xB0BF64BE, ++0xA11E5D38, 0x0131B755, 0x191F70D0, 0xDB483959, ++0xAA8D2F9E, 0x5A002AA0, 0xF5A2996D, 0xFD0F95F9, ++0xD6A12864, 0x3AA48B74, 0x50F6679F, 0x0ADF5C49, ++0xE2F8CE68, 0xBF213E67, 0x5E9ACEEA, 0xCACD0EBE, ++0x6DF766A5, 0x33C0A156, 0x720868EA, 0x3112A0DC, ++0xB382350A, 0x369D9C50, 0xE8F890D0, 0x0A121399, ++0x2AB458EA, 0x51C8233D, 0xBF46403C, 0x0728CD55, ++0x23F6774B, 0x2FB59DB0, 0xFA2CF724, 0xB49FA848, ++0x5FFFA125, 0xDE2C0D15, 0x76B78C41, 0x192BA62C, ++0x4C9563E2, 0x8F742507, 0x882104E0, 0x357AD078, ++0x799E25A2, 0xEF3ED021, 0x69D54B46, 0x5EC57870, ++0x0FF418E0, 0x07C5AC7F, 0xC1ACBF9A, 0x80A830D9, ++0x837C7C5A, 0x04C11D86, 0xC14C8BC7, 0x92BA650B, ++0x94D34FA8, 0xDBDD5EDC, 0x9ED2A08F, 0xA1FAE485, ++0x5FD66C3D, 0x4CCB6F9F, 0xB7AA56B0, 0x0FB3C73A, ++0x03AF96E6, 0xDB2D38F9, 0x7AF20D60, 0xB57CBE90, ++0x20EB2D6E, 0xCF934452, 0x82EC26F6, 0x84B3737A, ++0x0972F1B7, 0x39B6DB4D, 0x13E53CC0, 0x67C41D72, ++0x94BAAC78, 0x663A9C6C, 0x36927448, 0xCFBC2610, ++0x980F53BA, 0x7E56C96A, 0x04C62DFB, 0xA471D579, ++0xDF9B2EE1, 0xE12DEBB7, 0x2DB9B042, 0xF0C74B96, ++0x6A3762E9, 0xF4DC39D9, 0x761A5884, 0xFA363D3B, ++0x92766759, 0xF3EAD441, 0x878269ED, 0x1AFFAFE5, ++0xCB432764, 0xFE19475C, 0xCF8776DA, 0x1F0AD906, ++0x7D99AC20, 0xC27317FB, 0x439944A4, 0x65D14C2D, ++0x43E45262, 0xCDE6B3BD, 0xE25C67CD, 0x321AA2E6, ++0x352A2764, 0x5569EF42, 0x005C370D, 0x290801E0, ++0x61883035, 0x2A2DBC48, 0xE2D559FF, 0x01F5DF13, ++0x69B61558, 0xE94BF364, 0x3CA76FCA, 0x2E016483, ++0xDB675F9C, 0x4FA5B6DC, 0x59A6C3EC, 0x56C6E6CF, ++0x24CD59F5, 0x46911834, 0x683B9E39, 0xB5AF6174, ++0x5C31E269, 0x679C9A12, 0x3787D3E6, 0xF1727EE6, ++0xB070882F, 0xFC37EACA, 0xBEE0783F, 0xF6218369, ++0x19372940, 0x3FF7D890, 0x69736919, 0xDD961CB9, ++0x883010F1, 0x6E472D5B, 0x2447E00D, 0xF39E1F0E, ++0x1DBD442F, 0xBE1977E0, 0xC8655F42, 0x37C84253, ++0x3480DAC4, 0x4CFE1DC8, 0xF1521AD5, 0xA45C4F8C, ++0x87FBAEE0, 0x3E41E9E2, 0xF47771E5, 0x16C74CDF, ++0xA33D4035, 0x38513A10, 0xABF3264D, 0xB8D80DF6, ++0xD9AD7256, 0xF78375B8, 0xD7661CF7, 0x1C363AF9, ++0xD425FA32, 0x001D7B98, 0xDB96A1CC, 0xA092E683, ++0x65CF5316, 0x5F282689, 0x9F52F912, 0x8958A1B7, ++0x6457A3F7, 0xAB43FADD, 0x061328C7, 0x9D31B5E3, ++0x75A77F6D, 0x4A764D4A, 0x488CE83E, 0x29887218, ++0x9A04BDD0, 0xEF331070, 0xBCD2F884, 0x6BF66A6F, ++0xB85143CB, 0xFA529278, 0x9EA3A354, 0x4A73BDAF, ++0x0CBB7563, 0xD01AE35F, 0xD2AC3DAA, 0xFC8243B7, ++0xD805D97B, 0xC162A75F, 0x1D49AC67, 0x9E1BC38C, ++0x1D06AAE8, 0xEAF80CD8, 0xCE825DD4, 0xACA3F06A, ++0x83D092EE, 0x3F2BAABC, 0x2482D120, 0xF301680C, ++0x7DAC373F, 0xF5D6178D, 0xB7E9217F, 0xCCFE8C13, ++0x976024E0, 0xA2F39F8C, 0xB6C65734, 0x10AE514A, ++0x696584CF, 0x2542113C, 0x479CB20F, 0x8D3A22E3, ++0xF7C4B88C, 0xF4F7FBE2, 0x2F553308, 0x9EA71E3A, ++0x7B958F48, 0x0927DAAB, 0xF08949B7, 0x7CD46C0E, ++0x7A892BBC, 0x882F32CE, 0x34C490C8, 0x8483ED04, ++0x07EB4EFC, 0x4BEBCD82, 0x83B15EE8, 0x8F3B78AC, ++0xF95EFDA9, 0x816BEBF9, 0x269BDA58, 0xEE373342, ++0xE09FDA9F, 0xC7651AAB, 0xB8D398B2, 0xC7F449B2, ++0x031310F5, 0xC869706F, 0xDA22F127, 0x8C68DF91, ++0xE676068A, 0xB85AAAC7, 0xD32F35BC, 0xE22DF031, ++0xFE142BD9, 0xD4FB2700, 0x2D197707, 0xA3A43A64, ++0x0C02B050, 0xE945AD56, 0x7DEE0A5D, 0x1075DE3E, ++0xD99AD91C, 0x6A7BB71D, 0x1774B3B8, 0x2228B112, ++0x0DEEE844, 0x38074EBE, 0x6DACF57B, 0x7E0094B7, ++0xCE46F8EC, 0x4DAF34F4, 0x5B961907, 0xC8236FF7, ++0xFD380AA7, 0x61EBA84A, 0xAE4892EB, 0x0F1B6365, ++0xB0C4C9A0, 0x04E6012D, 0xA5F90D01, 0xD6C8882E, ++0xBCB9C1EB, 0x0E5E0FEC, 0x53A46889, 0xA2C0FA51, ++0x520DA459, 0x3FD95FA2, 0x6E1D6FE8, 0xBC093220, ++0xAB16390A, 0x163E3D6D, 0x0A63517C, 0x3BF38F3D, ++0x88A1F66D, 0x96263536, 0x412DF008, 0x12FB126D, ++0x44441D7A, 0x31C9F726, 0xF66F60CF, 0xAE1453D4, ++0xDAEAD71B, 0x54EAEE0F, 0x948B73BB, 0x31EA3E74, ++0x355D4FDC, 0x2A1F3A9E, 0x586D08DF, 0x123AC2E8, ++0xF5AC0065, 0x8874ACAB, 0x05B03D63, 0x01BD6A4C, ++0x7A6A9880, 0x2BC16F93, 0xC4112F0C, 0x8287B40D, ++0x48EABF08, 0x29E56860, 0x0F505C84, 0x447DC08B, ++0x1665119C, 0x00347E37, 0x482EF03E, 0x01B15D44, ++0xE6C1B9FF, 0xB165E436, 0x0CF690F7, 0x7FC5BD01, ++0xB784C7F4, 0x9BE04EBB, 0x9F614431, 0x6C37A5A9, ++0x2D0DB87D, 0xF6511369, 0xE115073A, 0xF96C6AB6, ++0x04A13C3C, 0xBF30B2DA, 0x93D18FC6, 0xF67D2E47, ++0xCA089151, 0x51A6BC39, 0x8C1FCA93, 0xFBF2F2BB, ++0xAD0A3F33, 0x82AA2767, 0x81BF2313, 0x758A82B8, ++0xE103788E, 0xC00C4B5C, 0x5F52FF58, 0xABAD38F7, ++0xDA68EE9A, 0x9B6D405D, 0x803449D9, 0x6178B345, ++0x3C785FB4, 0xFEBABE55, 0x0E2458AB, 0x021F0D71, ++0x39201ED1, 0x741B1A7D, 0xE0B0AFF4, 0x45652CFF, ++0x907DA678, 0x313A93B4, 0x0B0D6B0D, 0x42C96E43, ++0xEEE3E7E1, 0xE83C83E9, 0x9052B867, 0xF9514243, ++0x61F20CB2, 0x57E1AC64, 0xC2443123, 0x432C96D4, ++0x616A824F, 0x3C8D1E06, 0x8E64222A, 0x65C1A21D, ++0x8686308A, 0x2A576A2F, 0x1CA0FF20, 0x2C8F9D3A, ++0xC98C9C69, 0x35322A29, 0xDFD33C93, 0x9634F411, ++0x0B4F8FFC, 0x3AED4B01, 0xEBBC7012, 0xED2387EA, ++0x48BF42AF, 0xD60399D6, 0x7A9B8CA9, 0x53886337, ++0x2DBB9429, 0x0A6AF764, 0xDE4D8F78, 0x1EDECEE4, ++0x4F8EE99E, 0xAF23EAFD, 0x929550B1, 0x2CBD8621, ++0x22A8FAA2, 0xBE2A0A8D, 0x06F7E794, 0x16E1F3EC, ++0x093AAEAA, 0x92D429F8, 0xBB79A7E7, 0x43EF89BB, ++0x0E097511, 0x748E68B0, 0x322C00AC, 0xA62EF42A, ++0xD03BB8BC, 0x9FF67810, 0xDE24BF03, 0x140CA6FD, ++0x68F16B41, 0x1B7C68C7, 0x32646342, 0xC5E714F8, ++0xEFFFD2B8, 0x27843628, 0xF8445F51, 0xB9E8519B, ++0x8EB01D04, 0x356FBF2F, 0x32E96BAD, 0x6A629BDE, ++0x52063313, 0x200069B0, 0xE161CF71, 0x84FB7A12, ++0x1805ADC0, 0x80F75012, 0xFE9E629E, 0x93395C33, ++0xFF075A91, 0xB61E46B8, 0xCA9FE7C8, 0x97DCCBCA, ++0xCEFFB6F8, 0x30EE7985, 0x1FABC829, 0x20B3F57B, ++0x27042B07, 0xE12C5151, 0x23482B8A, 0x7B9B8EB2, ++0xC997FEB3, 0x76AB2497, 0xD5CDA590, 0x9EBE90FD, ++0xE3732B18, 0xFF28CEC9, 0xC6582320, 0x6EF106FA, ++0x8ED74023, 0x1A0B69E5, 0x4A95DD91, 0xB41AF82C, ++0x83DF69D3, 0xC548861C, 0x2F60BA93, 0xFC815984, ++0x1A848B67, 0x1EAE87C4, 0xF7479103, 0x8E16DB51, ++0x040B95B9, 0x2A9DB812, 0x987AFCD1, 0x866DF413, ++0xBF9558ED, 0xACF1AF2F, 0xA65305CC, 0x168336F3, ++0x1E59B97F, 0x3F9F447C, 0x3D54B30D, 0xE939D598, ++0x36A40885, 0x02396794, 0xEB0F0A67, 0xCEAEA12F, ++0xC58B4AC8, 0xE6D49760, 0x0F8F2776, 0x66A8F436, ++0x31BACD7D, 0x376993DE, 0x32BD0431, 0x68BDC728, ++0x63EA6748, 0xE6B00E29, 0x7448CABC, 0x42A6517D, ++0xBB1313C4, 0xA04DC8FF, 0x3D402237, 0xA382645F, ++0x52ED55D6, 0x92D7D7B7, 0x541230FF, 0x7AFC0420, ++0x3DC4624F, 0xD9B2193D, 0xA73B9704, 0xBBDE0FF1, ++0x9EB56615, 0x8AB080B6, 0x3C4D8E14, 0x5001B43D, ++0x1EBFAA23, 0xD4AACD27, 0xCFAAB4BB, 0x6FFEE61F, ++0xAE5A7426, 0xDB942949, 0x452C0B16, 0x738E0637, ++0x36A5122D, 0xFF1F7A4E, 0x743D35CF, 0x847D54A9, ++0x42C3EABA, 0xD46728C5, 0x30B2708D, 0x4F6BE0BC, ++0x3C26790D, 0xB0B67C8A, 0xEE07EFDC, 0x9E380611, ++0xEAD6804C, 0x4EF66024, 0x8459AE38, 0x1DEAAFFB, ++0xF76573AE, 0x6CB1C8F0, 0xFFCC267E, 0x26A215F7, ++0x0B1A057C, 0x7DAB9CB7, 0xD40BCBA9, 0xE561F9FE, ++0xA44013A6, 0x7B22C0B9, 0x998A921F, 0xBD25244B, ++0x15E07FED, 0xF15B2E31, 0x54E80016, 0xA12BCE7F, ++0x658A2093, 0xB642C47B, 0xD731FC00, 0xC00E302D, ++0x55B251DC, 0x342939EB, 0x6EADB2F7, 0x0CF93318, ++0x61EBD85A, 0x99B715EF, 0x679C8D3A, 0x9CC1B803, ++0xABEF955E, 0xB8CFF9D4, 0x707A839F, 0xF5D02A7E, ++0x59E0D903, 0x5A425E3B, 0xBB61163C, 0x96ECE9AA, ++0x797B82AA, 0xA9FA6BB6, 0x797C00DC, 0xC1C1FC4C, ++0x8F7FDA66, 0x77902514, 0x6D1B843D, 0x4F881FA4, ++0xC24AD625, 0xBC237A45, 0x9A2E0F44, 0x82FAA3F3, ++0xD70E3489, 0x4F2B3417, 0x65CF65E4, 0xEAAE6A93, ++0x4BEAEC2C, 0x4918723D, 0x7D8F30B4, 0x7706F59A, ++0xCB2A7452, 0x5083D2D6, 0x4724B426, 0x84EB15DC, ++0xBAA2C6CF, 0x71FA984A, 0xDDF7A3DF, 0xB115BF1A, ++0x258AF0E3, 0xA1637D87, 0x03585DF8, 0x5EA4B80D, ++0x8641F318, 0x66EE2F24, 0xC81E505E, 0x5E640639, ++0xDB7739B8, 0x1A3B861F, 0x0F5ECC51, 0xB21C00DD, ++0x680FF30B, 0xDE697468, 0x57A43B33, 0xD7EF6B3B, ++0x4BFC7D25, 0x710F0752, 0xABAA9752, 0xCFCFD84D, ++0x3BCC1CDC, 0x2381C524, 0xB60CAD92, 0xE05BC1AA, ++0x2B887D88, 0xCD4566C5, 0x0D2976E7, 0xCB000A2C, ++0x667BECF6, 0xEFC7F221, 0x7A7584D1, 0xC41D8B2E, ++0xD9BB7D3F, 0x7CEB5626, 0x7D8165A0, 0xEE178F99, ++0x3E8A8CB7, 0x693D4501, 0xB0E228A5, 0xD55B73C1, ++0xAF9043BF, 0x6C627A2C, 0x7B9F490C, 0x7EA61899, ++0x92B980AF, 0x6D13C758, 0x2C007C73, 0x74336E0D, ++0xA39F13AC, 0x533F05D7, 0x75536CFB, 0x9708DE27, ++0xE2A14E87, 0x36673FEF, 0x71BA654F, 0xB98CD2FC, ++0x27F29A6E, 0x82478171, 0x1C2815F0, 0x8A8F4549, ++0x048A8D9B, 0x7CEE51F2, 0xA1648AC3, 0x004F8B8F, ++0xB6FE8EF0, 0x6D10A0A1, 0xAD7A24D8, 0x75039717, ++0x97847786, 0x2791CC05, 0x6937FD6F, 0x60F98115, ++0x5FAB6D35, 0xC0550A70, 0xC0F4D817, 0x7B5BFDDB, ++0xEF63B4D2, 0x6C87C6C5, 0x956D6B87, 0x69179257, ++0x10973C90, 0x8CDBE860, 0xC7C761EE, 0xF823E34E, ++0x6FA2CF3B, 0xA903ABCB, 0xC82C9B01, 0x60FE96E6, ++0xE5EC33C0, 0x73A3011C, 0x2A1B9054, 0xCF16F92D, ++0x4FAF6CC8, 0xD9DD74FE, 0xB3C639ED, 0x3F47AF63, ++0xC8E99D12, 0x92D95986, 0x835ACA6F, 0xD52930A2, ++0xC7DD54A5, 0x617FDD15, 0xE9A6D295, 0xF56C6087, ++0x7813B662, 0x1F8EA244, 0x1CDE3BAD, 0x58FC0F7B, ++0x02E31A5A, 0xA78EAC74, 0x10C06107, 0x22BA3C63, ++0xF84AD224, 0x6A8BF66C, 0x2A5CAAC5, 0x8ADC3FB5, ++0x9683451A, 0x1B52FCB4, 0x95491BA5, 0xFE6C3713, ++0xE9098CEF, 0x73C01EF9, 0x6E85EF1A, 0xEE189743, ++0x2E9E5286, 0xC1FAA665, 0xD861E384, 0x701C834D, ++0xDC5CA5CC, 0x52A3A6C4, 0xF2AF2C43, 0xC37C6465, ++0x6E94AD69, 0x98808AF4, 0xED8A99F2, 0x377257D3, ++0xE60F2096, 0x615EFCB8, 0x67A2BB3A, 0xB4DDD40F, ++0x1D47F918, 0x86F77D6E, 0xFD05D2B8, 0xE18C330C, ++0xA48260A4, 0x5615B83B, 0xBCD7D855, 0xF8073219, ++0x8622BB89, 0xD35CE05B, 0x17162483, 0x137BDB69, ++0xECD0F226, 0x61F8982A, 0x3C10ABD4, 0x2F33ABF4, ++0x9358B547, 0x58B277A7, 0x92456A7C, 0x4384B49A, ++0x5F1FF0EC, 0xA153EA4D, 0xA8E49100, 0xD3A75723, ++0xD1ADC606, 0x76C314B7, 0xBC6AB227, 0x257312AF, ++0x8B6AA1E3, 0xD87FF5E8, 0x2BAED373, 0xC848AB63, ++0xB72B1E5E, 0x730A73D8, 0x4915E5B6, 0xDF7D77AD, ++0xEAE247D7, 0x9556DDA8, 0xDE0C9C47, 0xA4E3296E, ++0x31F5BC94, 0x05258B24, 0x2837374F, 0xC7E4C81B, ++0x5A1AC819, 0x068074AE, 0xDF876732, 0xC0192EF9, ++0x7FFD84D8, 0xFF1CE148, 0x821B4AA3, 0x56674838, ++0xF9A147F4, 0x182EF58B, 0x16E17174, 0xDE27029E, ++0x8BEC55AD, 0x40646F89, 0xDBFF92FC, 0x9F24C017, ++0x711EAD18, 0xA663E1EF, 0xEF92F684, 0x4BD05E67, ++0x7E089B13, 0xCBF619BE, 0xCEBEF231, 0xC947586C, ++0x0F526C47, 0x6672600F, 0xDAAB63DD, 0x950D4FD0, ++0x199C3EC2, 0x0F201C9D, 0x06BCC8D3, 0xA7672C6D, ++0xB39C7D0C, 0xC74B0805, 0xC9BBD249, 0xACDD5396, ++0xAB7BDF8E, 0x12012B8E, 0x67236047, 0x0AE0741B, ++0x1D747E56, 0x7EC6C00C, 0xD08E8341, 0xB0ABDAD6, ++0x4FA4BDF6, 0x90CE8D0E, 0x6E734117, 0x3EF9192E, ++0xACA32DA2, 0xFDB9C58E, 0x256626B5, 0x5EA961B3, ++0xFBC15776, 0x36602B5F, 0xF8D08644, 0x5B693C23, ++0xC62EA3B1, 0xC664C7C3, 0x73BE8859, 0x17F44E8F, ++0xF9B8D923, 0xD168A3A5, 0x6CCD110C, 0xD353181F, ++0xC0E774EC, 0x5F9E127C, 0x6C824511, 0xFDA13494, ++0xCB588BA6, 0x47148694, 0xAB877E87, 0xE97F757B, ++0xF54D0A2A, 0x0FE11891, 0x5D8747FB, 0xE7800C7E, ++0xEF96298F, 0x400F458A, 0xE2D04518, 0x4B4E6EFC, ++0x9B15002C, 0x3CE1B537, 0xF5ACB9B8, 0x67030647, ++0x475FD148, 0x1E03A40A, 0x896C7C05, 0x85F70B68, ++0xC590CA84, 0x53B5440E, 0x1400F78F, 0x3ABE7F8A, ++0x19CA67FF, 0x68B54A34, 0x555988AC, 0x4AB16B4A, ++0x7511FA63, 0x248EC9EC, 0xC25AFE4F, 0x19F578E1, ++0xE92AF03D, 0xAF9DE18F, 0x2798C7A7, 0x6B46990F, ++0x41D45894, 0x74696A0A, 0xC6AAF5F8, 0x72CC10E0, ++0xDB9CA283, 0xD6BBD0F3, 0x58EA4C06, 0xDEA5E8B9, ++0x1908EBDB, 0x95D33DD5, 0x20D7013C, 0xE725C282, ++0xFD48C92F, 0xDBBA7D19, 0xC7BEBEA9, 0xB186B799, ++0xDD0DD17B, 0xD8090A41, 0xF98BC20B, 0xDD7E4B9D, ++0xEBAE4247, 0x4376FDC4, 0x7F3EFAC6, 0xA9B9A951, ++0x4AE390C4, 0x651863AF, 0x2CD42DBC, 0xC2A13962, ++0xEF0FC443, 0xAEE63246, 0x09B83E19, 0xC3C940AB, ++0x00B12826, 0xC0A30412, 0xFCF6ABCC, 0x3CFE721A, ++0x62C1F4C6, 0xE963A359, 0xAE11F3D6, 0xE490D12A, ++0xC45C928B, 0x05CCA78A, 0x1982E93F, 0x577F81CA, ++0x66D50D6E, 0xB4C7030F, 0x93092C3E, 0x118B08FF, ++0x178545B7, 0xEED74838, 0xF7D2CE48, 0x238969BC, ++0xB8EFAEAE, 0x75726A3B, 0xB1E0220F, 0xC4D60EB6, ++0x0EBC0243, 0x5FE0D6CA, 0x35456B45, 0x1F64AC2A, ++0x58484A1F, 0x2A11455D, 0x33BC4403, 0x56E4E62D, ++0x60B41E2B, 0xDB65D3F8, 0x7EC18D34, 0xF575DC85, ++0x6E0B9995, 0x1C14C91E, 0xB2A94718, 0xAEC4A823, ++0x993D374E, 0xF1E4210B, 0x8CFCC03A, 0x99BD1C28, ++0xA928E3F9, 0xBB957D0E, 0x77C865EF, 0x7FF50A45, ++0x4279A638, 0xE628FFA1, 0xBCCA171E, 0x284C9CEC, ++0xA476E346, 0x7E2F9C08, 0xBF65044F, 0x5B7C3D5B, ++0x6E60EE5D, 0xF5C99509, 0xFA352B7E, 0x6FDE8E8A, ++0xF2340FE1, 0xDF542B6C, 0x510CB30B, 0x367E7016, ++0x198A0A95, 0xA4DF508E, 0x593C2338, 0xB12BCDE1, ++0x554AD3C0, 0x4DDAB1C1, 0xD2BD1850, 0xF6E126CA, ++0xF87289C7, 0x86EC92A5, 0x4E033906, 0x52DC5F3F, ++0xCC6E2E59, 0xFF751753, 0xDF8B8BA2, 0xDBF5954A, ++0xBD367488, 0x6A0CDF1F, 0x4103139C, 0xDE49DBB0, ++0x5A8428F4, 0xA26872B1, 0x96BF7203, 0x99D5E78E, ++0x243850A6, 0x389DAD80, 0x6335D33F, 0xEC67B0A5, ++0x029C0CA9, 0xF5F6F6C9, 0xDF574C15, 0xE6D3EC29, ++0x1AA349BA, 0x453E7258, 0x7DB79BE3, 0x51FCA7F6, ++0x2B42FCA5, 0xBF0E4871, 0x58063C40, 0x193580E2, ++0x25605322, 0xBC49C479, 0x0ED70FC4, 0xA78B59A0, ++0xE6CE3E8C, 0x92EE657A, 0x63D12529, 0xF95DAF45, ++0xF92C3BF3, 0x7D514200, 0x694DF84A, 0xEF177E2D, ++0x4E119CCF, 0xA025C55D, 0xF96974D6, 0x26D13E7F, ++0x799ADC27, 0xD7925EC1, 0x8AE60BF7, 0xF9EF1A2E, ++0x89EADD3A, 0x9C28CACF, 0x63377EB7, 0x6D1EF7E5, ++0x6585B16C, 0x9972D115, 0x65F8F5E6, 0xF93DECB4, ++0x6D71605D, 0xC6FDBCB8, 0xD937BA31, 0xCED727EE, ++0xC34C5605, 0x25FA70B6, 0x5C0B7FB0, 0x8F9340F5, ++0xA3376693, 0x4498B66A, 0x2D21F377, 0xC0A4C6EA, ++0x0780736B, 0xF42D7F07, 0xE56D47E5, 0xB48C25D6, ++0xA48DA0DA, 0xFE69693F, 0xF01E19CA, 0x8A0C5C8F, ++0xDF702C23, 0xE18A93F0, 0xD4D5C91E, 0xD2A706F7, ++0x674F9E28, 0xAF0F80C7, 0x648D49E8, 0x6BE8640F, ++0xF5FCFFD5, 0x8EDC391E, 0xE583D8BC, 0x8426C090, ++0xF456A27D, 0x07249BF4, 0x054A2F45, 0xAC46B73B, ++0xB89EEDFB, 0x48EAF867, 0x69B2D7CC, 0xCA0CA0F1, ++0x38CD0428, 0x029808CF, 0x86EE75DC, 0xF4FEE9F0, ++0x6987D5E9, 0x56AB5537, 0x3DDD0940, 0x4742FF89, ++0x2C3B179E, 0xD05B5CB1, 0x3C4E9033, 0x6BCF0141, ++0xF2F6D3E2, 0xAD297B1F, 0xB1CC23D4, 0x5452038B, ++0x1751FCBE, 0x24AA465F, 0x94C62D18, 0xF49B2EC8, ++0x97AC47DF, 0xD66C19B5, 0x09AAB297, 0x89936144, ++0xD15C026B, 0x4CEC8778, 0x94050D61, 0xD812E96F, ++0xB6BD7B12, 0xA5F9BE77, 0x531A5C7A, 0x3605BA71, ++0xD500CE54, 0xE325964C, 0x323432FE, 0x580A9DC8, ++0xD25A3135, 0x089D6C9C, 0x58856F73, 0x7DFCEE30, ++0x7DE2580F, 0xF4E4488B, 0x71821DDF, 0xD194F5DC, ++0x7D070394, 0xBA28BF76, 0xAAF0A38E, 0xD4F6275E, ++0x1B742E66, 0xD9E68EA9, 0x68B0F939, 0x52AF9D7B, ++0x54A39705, 0x20F844C1, 0xE6981DDC, 0x80322E62, ++0x536235B9, 0x7A57F4FC, 0x14EBF376, 0x64BE2E5A, ++0x70A18910, 0x0FE09587, 0x10E9CA78, 0x8F90D3D2, ++0xAE74717D, 0xA544EAED, 0x6746AF3E, 0x430CB3FC, ++0xBC185576, 0xEAA35DC3, 0xDA6309D2, 0x40643F87, ++0x68859117, 0xA17AC84D, 0xD7922CA8, 0xEF7C0BEF, ++0x83337348, 0x9B4B1790, 0x8876A77E, 0xF293C9C7, ++0x20D399CD, 0xA78224BA, 0xFD1279C8, 0x8B7837C1, ++0x0F1DD415, 0xAE3FBD2E, 0xC4F77B52, 0x51E79FB3, ++0x7A856D9D, 0x14BFDAD7, 0x993FB625, 0x667C65EF, ++0x32F83338, 0xAA06EDCE, 0xACE7A099, 0xD26DAE89, ++0xDC6891CE, 0xCD2F6F04, 0x27425FB8, 0x7C301D8D, ++0x1EDEBE1A, 0xBE540AF8, 0x1D356C6A, 0x963E8639, ++0x9920CA55, 0xDEFE5F44, 0x107D5545, 0x3D079BE4, ++0xEF673F66, 0xDB3C2954, 0xDD76D666, 0x1DFBEF59, ++0x8F384B34, 0xBE6F773C, 0x079DD187, 0x2314AC8B, ++0x5FEB0114, 0x59E85CF3, 0x9BFE9190, 0xB360A31B, ++0x4F7EF967, 0xFEB0D561, 0xBFE779F2, 0xF33702B3, ++0xBB263417, 0x09607C65, 0xA877F109, 0xBB43CFF1, ++0x4A190DB2, 0x9B7BD38F, 0xAEB7C449, 0x3DB3A460, ++0x7D928522, 0xD18AC966, 0x187FE766, 0x97629792, ++0xF59D506E, 0x6FBA202C, 0x77035FF3, 0xDA068CDE, ++0xE195779A, 0xAEB92298, 0xD2A44EDD, 0x12577D85, ++0xA3B47B9E, 0x5BD07CB7, 0x4B6AE3FC, 0xBE35B6E2, ++0x9D7F7AF2, 0x9A38EA75, 0xD87FB055, 0x3339F2A3, ++0xD7CB82B4, 0x357721E4, 0xBEF46553, 0x9DE28CA3, ++0x1B1EC2DF, 0xE29B9CC0, 0xEFAE347E, 0xE5864917, ++0xA097B712, 0x6B67041E, 0x5B29542F, 0x01D96EED, ++0xF9A6DC07, 0xC0B5E3F0, 0x21E1899C, 0xE9373A86, ++0xF3176509, 0x950844A2, 0x7D24FFEB, 0x5DC0BCA0, ++0xC442B7C1, 0x37DC6EC1, 0xC65C8BA5, 0x18F0FA85, ++0x2AD80D2D, 0xC68CDCBB, 0x6AE5EC93, 0xE3955DBD, ++0x3E80C4B3, 0x50FED127, 0x743CABC0, 0xD0E91707, ++0x9BF7EB4B, 0x7A632755, 0x9A192482, 0x8F923E9E, ++0xE2E70FE5, 0x5F50AA16, 0x0EC496D1, 0xC6EC4862, ++0x040A0274, 0x2FC951C2, 0xF65D3A80, 0x8D585163, ++0xC6B529D1, 0xD2CAEE6E, 0xE3E112B7, 0x3244312F, ++0x1B393E58, 0x2444D538, 0xBE69AC21, 0xC92A0506, ++0xD1A74434, 0x49C3EA05, 0x0E53B319, 0x3843CE03, ++0x8DB8415E, 0x766B6FC7, 0x515B9E7A, 0x3BA05B32, ++0xBFAFC449, 0x31302A57, 0x1960A211, 0x66A097E0, ++0xBC65A9B4, 0x89E83065, 0x36FDBF2C, 0xDCD4664A, ++0x0ED6CFBF, 0xDD4DC6DC, 0xD76D2F00, 0xB6DA6540, ++0x9A396444, 0x28F185DE, 0xA0FEFA1D, 0xF476E0ED, ++0xEF15505A, 0x183365BF, 0x481FFD90, 0x29ABEE75, ++0x1EC90B07, 0xC10B2657, 0x0DBF6DDB, 0x52AD02B7, ++0xE87DDB54, 0xD3704106, 0xD4E2C592, 0x0CB2DD05, ++0x4BAA2FFB, 0x02611368, 0xD50F8F1C, 0x416FF25C, ++0x9A69782D, 0x268C6474, 0x2ECD4D64, 0x196DE2F5, ++0x47A8561C, 0x8C7CE6C9, 0xD2B1E2D2, 0xA038C165, ++0x3AB8844B, 0x4A699830, 0x0FFC0B17, 0x89B685AA, ++0xDA276D85, 0xE934C4CD, 0xF511226F, 0x9CDD2B1F, ++0x94F75492, 0x55ECEB42, 0x42F0A3D3, 0xD7EB482C, ++0xA78D0373, 0x62F088A6, 0x7ECF4602, 0x7A3404B6, ++0x40B36495, 0x60441DF4, 0x6722F539, 0xCFE76C48, ++0xB6B94C9F, 0x9ADB4B6A, 0x1EBBA65F, 0x5B5081AF, ++0xB764423C, 0xB6F910E3, 0x14AC4B6F, 0x5C811E82, ++0xAA36E5F1, 0x24EC82AF, 0xA2F1C050, 0x0504324C, ++0x304CED0F, 0x01E31DD9, 0xC82EC7E6, 0xD55AFFF9, ++0xFFB3047B, 0x3006F2E9, 0xC725BCD1, 0x7DCC1082, ++0xA9A22CF8, 0x64D5AF9D, 0x389C34AD, 0x7DFF37C6, ++0x41F1509D, 0x1845B3FE, 0x055C23F0, 0xC6291F5F, ++0xCDD3C7DD, 0x5F0356B4, 0x7FD2C387, 0x494A091E, ++0x50C69D3E, 0xFE769A5A, 0x63904701, 0x8960ABF2, ++0xE68EDF3A, 0x0AB57C8E, 0x0B9D0A6C, 0x51888148, ++0x50C5D533, 0xC69038FA, 0x3ACBE661, 0x0CAEB601, ++0x8C14AB6C, 0xBA86D94F, 0x0724056B, 0x0FEFFCBA, ++0x12449DDB, 0xABFFECCE, 0xB12A2BD7, 0x7260A0E8, ++0xBE184A48, 0xCFD3CA3F, 0xDF088660, 0x78EE9B67, ++0xA9EDB113, 0x4FD5D353, 0x8E348CC6, 0xD578C337, ++0xF0493BE9, 0xCCFB54EC, 0x9CEEF85C, 0x0CAAE15E, ++0x371AD12F, 0x9C5B9270, 0x2495F0DE, 0x06DE2DBB, ++0x911AE7EC, 0xEEDE3363, 0x6DD38D6C, 0x2AF7F3D9, ++0x51C8D118, 0xF23818A7, 0x95438AEA, 0x3A8A798F, ++0x230D2BEF, 0x3D16273C, 0x9C36FF83, 0x785C9537, ++0x3E42AF2F, 0x12A16741, 0xE58D0DC4, 0x33EBEFF9, ++0x6F1972DA, 0x128C9BAA, 0x858D6032, 0xDAF185E1, ++0xAE355065, 0xDE0086F3, 0x0F661A65, 0xF4334169, ++0xB1559BA6, 0x3892109A, 0xE903BA00, 0xAE0CBD58, ++0x073C21A0, 0xFCADB299, 0xB4E39AF1, 0x78475459, ++0xB46DC847, 0xDBA97661, 0x15D118F5, 0x01ED48D0, ++0x99F658BC, 0x399FDC8E, 0x44D4A919, 0x7C2CE4B9, ++0xCA0367CC, 0xCC2B9828, 0x16AACAA6, 0x7AA5B6BA, ++0xFEC77C66, 0x231B22F9, 0xC8BE0D04, 0x6FF2788C, ++0x5F9CEBB5, 0x901EAA5D, 0xDE682BBF, 0x998E70D4, ++0xBD9CCCDA, 0x6995441E, 0x5702F360, 0xBC035EED, ++0x20F60B51, 0xD57361D8, 0xC071113B, 0x73CE6CE4, ++0xC6569DC9, 0xD24B89ED, 0xA6052276, 0x8CEE2026, ++0xFBF5B58E, 0xF692DF81, 0x6B7CDD7C, 0xF5B6C04C, ++0xEC1BBA29, 0xD6AC8CDD, 0x320491F8, 0x1D812AC7, ++0x631B0051, 0xD08A4D2A, 0x569746DD, 0xAA653FCF, ++0xA92E8E70, 0xC59A6705, 0x278EA1FF, 0x63E5FA17, ++0x1C20E82D, 0x550F7CE3, 0x55CED415, 0x5F9C4C4A, ++0x7D746311, 0x5B07976A, 0x12477E31, 0xAB8113AA, ++0x796EDCEA, 0x4A90E4B4, 0xB36E6188, 0xEE7D5E0F, ++0x15CEA060, 0xB81AB2CA, 0x296D22B0, 0xFA0753E2, ++0x0D0D15BB, 0xD4AF8BD7, 0x951FA575, 0xCBEBD58A, ++0x0AF5C362, 0x9EF43FB0, 0xD97E5184, 0xA14469BC, ++0xCAE5D55E, 0x93D4CDF9, 0x95B013A8, 0x6998F35C, ++0xF1DDC0B1, 0x476F9FC7, 0xB6472B70, 0x1D55AC5C, ++0xF0E0C0C8, 0x95372BF5, 0x75CCCDBE, 0x9F9D2003, ++0xCAAD0D51, 0xEE54CC2E, 0xE5EBDBF0, 0x9B248BB3, ++0x4BF07D19, 0x542997E9, 0x17447C4B, 0xCF2B2768, ++0x86118A5B, 0x57579F12, 0xC5CD9E74, 0x97ED5724, ++0x01BD2EE4, 0x2A0403A6, 0x01833741, 0xA1E8D364, ++0x4D1A2EEA, 0x62760377, 0xA10D6861, 0x09C68E2F, ++0xAB482850, 0xACD24B74, 0x5038C8CA, 0x71DE3A93, ++0x671D25E4, 0x9EA7AC1A, 0x3E7287F5, 0x9FC963CF, ++0x73F90AB6, 0xC775D840, 0x00B868D9, 0xF6A9BE3D, ++0x17FFB472, 0x5D2389E3, 0x0D42A149, 0x2FAB1235, ++0x90A7998E, 0xD895F6EE, 0x19921013, 0xEE42EA48, ++0xC5D19A17, 0x5507890A, 0x9F893B29, 0x4FF39F19, ++0xD6EF85AD, 0x3FFB1599, 0xF1761017, 0xFC51B90D, ++0x8F6C566B, 0x44BAC7A4, 0x2B2E3755, 0xABECB8DB, ++0x5C4A1629, 0x837CC4F7, 0x3E732B0A, 0x803CE303, ++0x71865D8D, 0x346665AB, 0x58BF809B, 0x100626AA, ++0x9446AB13, 0xD53ADCDA, 0x75C0BFCD, 0x95853304, ++0xF4758E87, 0xD6B64517, 0x13293D0D, 0xEC9368FB, ++0xD449A2CC, 0xAA17B0BE, 0x9D0B85C0, 0x77BEED16, ++0x7699CAE7, 0xC776D10D, 0x962D48CE, 0x838D00BE, ++0x279AEBF9, 0x22EF837B, 0x58E46DAD, 0xB56B6305, ++0x3232D58B, 0x167969DB, 0x5B63F5B5, 0x7E82B175, ++0x05DDB402, 0x5AB29BBA, 0xF3B627D5, 0x97168C85, ++0xAD9EE022, 0x48F0CEEA, 0x84104C22, 0x690FCC19, ++0xCA2F2474, 0x76F95539, 0x9FD2B987, 0x79EFC557, ++0xCEE5DA4D, 0x27EB98F6, 0xA0628916, 0x8E05614F, ++0x8AC89026, 0x7705135E, 0x3F7E42B8, 0x7BCD773B, ++0xF98B9741, 0xCB8A514E, 0x9298220D, 0x5665FA3A, ++0xE66A1FF7, 0xAC4ECB71, 0xA7E56FEF, 0x9D1EF7F8, ++0x23566B64, 0xB4FE822E, 0x1AA53208, 0xF4545E5D, ++0xEA86C879, 0x18F6B7C2, 0xE10A17AC, 0xBD37011F, ++0xFBDF81B8, 0xA978A4EB, 0xD42437A7, 0x474E6A41, ++0xF8885248, 0xF750BAA9, 0xD238EA62, 0xD69BA74D, ++0x266EC6BF, 0xE7EDE077, 0xE8F0A303, 0x8B56A96D, ++0x41380980, 0xDDF0B16C, 0x00E83594, 0xA503EBF5, ++0x960A258E, 0x499827BD, 0x6C8E6F7B, 0x166C845D, ++0xC842C934, 0xBAEFC699, 0xD9846213, 0x832EC19B, ++0x1EAD7599, 0x221E7EE9, 0x8176A313, 0xB28D8E39, ++0xBAC29A96, 0xB964F91F, 0x3F268150, 0xD4BB7011, ++0x347EC445, 0x7FDC9E82, 0xEB70F4C9, 0xA6F38EBF, ++0x398CF137, 0xD7F88CF5, 0xCBDDCB3F, 0xA0DAFA74, ++0xD29D30AD, 0x822B6919, 0xCE059949, 0x3A946183, ++0xDE4C572D, 0xD1E6D844, 0xC43C7DAC, 0xDBBEEDD0, ++0xA656DF6D, 0x454C22A9, 0x9FA48790, 0x69B04531, ++0x99BB305F, 0x80500F71, 0xFE2363C2, 0xB67F538F, ++0x302EC0C3, 0x4A6E3458, 0x57E4CFD4, 0xE65CDAEB, ++0xF31ABB31, 0x62DF98AC, 0x894AE781, 0xB1588AB1, ++0x45D5CC3E, 0x3520F5B0, 0xC72D0CB7, 0xA1D6CBF9, ++0x742FFA63, 0xA0A5224F, 0x5EA1C85A, 0xB81E9F77, ++0x31D76C4F, 0x525257F5, 0xBFF85009, 0x2125B270, ++0x16E47E6E, 0x9128B981, 0x0D5FBE39, 0xF67A418C, ++0xCF3C71CB, 0xAC04ABE1, 0x9B550AAF, 0xB5077F18, ++0xFB7C5EC0, 0x64784DB4, 0x1E668B48, 0x84659836, ++0x604457BF, 0xF6F69C8D, 0x394301DC, 0xED0211BD, ++0x8BAC1A3A, 0xBB752FD2, 0x78B8C036, 0xBCB98E8A, ++0x33C595DE, 0xB3F3C5F8, 0x698666AC, 0xA1F42D7A, ++0x5751ACC8, 0xC069575B, 0x35D50F99, 0xB294BF38, ++0x82A4A331, 0x05147751, 0xCAE18C12, 0x9E89AAF1, ++0x3531C372, 0xB2114A88, 0x41797201, 0xDDDDEC10, ++0x01185F2A, 0xDED50CDC, 0x72156BAD, 0x88F3DB94, ++0x50450DDF, 0x6B1E7ABF, 0x3D317708, 0xFDFF5A15, ++0xDC8B1697, 0xCC2248FD, 0xD9196272, 0x4445195D, ++0x54D90281, 0x7A891C9D, 0x69FF98D5, 0xADE6D74B, ++0x26D27973, 0x0F14734F, 0x3F957FC8, 0x812AC874, ++0xEDC0F9B4, 0xD31D6D75, 0x7A2608C3, 0xD89984B1, ++0xF581081A, 0xEDB9DF6F, 0x16ECC191, 0x6B945724, ++0x1BCE8269, 0x02E6DB68, 0x56362541, 0x9D247CF4, ++0xA5265E72, 0x2C8B9413, 0x1157DB4B, 0x3145CFB2, ++0xFBDEBCF5, 0x1042B117, 0x284DAE18, 0x10575C21, ++0x1DDE578E, 0x80F59EDE, 0xCAB51C04, 0xB594BDA8, ++0x08ACEF85, 0x08C8D4C7, 0x7304D433, 0xE87D3A88, ++0x31CCFED8, 0x1D8E71E5, 0xC5A2F02C, 0xACBF3B5E, ++0xAA161BCA, 0xA10BE577, 0xF9CE41D2, 0x2B86F031, ++0x3D4A8D23, 0xED926DE4, 0x3844E21F, 0xFE57BCD0, ++0x36DC309D, 0x17137409, 0x9F6A8507, 0x14CF12EB, ++0xA770AFB5, 0x7C6DA2E4, 0x856B48B8, 0x2EA235DF, ++0x55BD1164, 0x5BD9FF0C, 0x5228C552, 0x9E719AFA, ++0x3EC3703B, 0xE06A94F3, 0x296FF0D9, 0xE468D9C9, ++0xD2A15CDC, 0x6C4EAAA2, 0x2AF3B8BF, 0x6B6EDC78, ++0x42B78972, 0x4C97A66C, 0x161C30BF, 0xCD2816DC, ++0x431BDA17, 0xD9653022, 0x67D95E39, 0xBCB18342, ++0x227982E7, 0x23C5B11B, 0x514420AB, 0x089F3A5C, ++0x2B2F8244, 0x2F2A80C8, 0xB0A90558, 0x75BAA243, ++0xE2FC4F62, 0xEB0A6104, 0xB7F221B2, 0x4ECD79DF, ++0xB3E08B8B, 0xBA25E1CB, 0xD39F3431, 0xB50202FE, ++0x78F15ECE, 0xEFF61ECF, 0xB3CDDD50, 0x3FD064A8, ++0x96B028BC, 0xB29DD4E1, 0x7E9EC629, 0xC407F4D1, ++0x8C21785B, 0xE11767BA, 0xCFE6DE26, 0x0DA98E22, ++0x33AC5670, 0x0FDBC175, 0xF11F8EF5, 0x60638843, ++0x8B67E55A, 0x3F27F75B, 0x6691FB98, 0x635A35A9, ++0xB317459C, 0xE7419C01, 0x8BAB28D7, 0xE347D791, ++0xEFC019A0, 0x45009041, 0xA6DEB3E8, 0x6F7379FF, ++0x0FF50390, 0x810BEE78, 0xAD13716B, 0xA7DBD7AB, ++0xEF439D4B, 0xDDA744A5, 0x31EDDE8D, 0xA85B71F2, ++0xDF439C70, 0xA7E3DA94, 0x525ED453, 0x3D913C32, ++0xD104CE61, 0x42F5FFED, 0x14C7625A, 0x4E5B314B, ++0xA7EAD1ED, 0xFA01D595, 0xE67BCF06, 0xE63685E2, ++0x3A32E9D3, 0x374C25F0, 0xA8E8A41D, 0xA403AEF5, ++0x901A194C, 0x17605BC9, 0x8522DD12, 0x27096BAA, ++0x017434B7, 0x99C8D2DA, 0x7F96B068, 0x8521CD09, ++0x529B46D6, 0x47852810, 0x021BC8BF, 0x93C98329, ++0x6FE73A78, 0x44DB69A9, 0xC839D490, 0xCAC42AFE, ++0xCF1ECCF4, 0x6F2E5F44, 0x795C8219, 0xA06C667B, ++0x80411F31, 0xB09926E1, 0xC62B6C18, 0x77C6E6DD, ++0x7622FC07, 0x02162DB2, 0x3EA31334, 0x6CC02B4A, ++0xAA6B81C3, 0x4424A9A5, 0x26BD2EF3, 0x334896D6, ++0xADDD2711, 0x76035757, 0x80AA328E, 0x2F39C06E, ++0x357520CB, 0xF62BDF46, 0xC59343C4, 0x7CA4CAE2, ++0x89B03EF3, 0x251A785B, 0xA4755BB9, 0x262D478D, ++0x462E6252, 0x6B5F6BED, 0xCA46E77B, 0xA2CF08AD, ++0x561E19EA, 0xBF31AA15, 0xD376F44C, 0xCC332150, ++0x8C0AEE42, 0xC06D5F91, 0xDADF8613, 0xBE0FA22C, ++0xF50AE482, 0xE3615501, 0xECC8D5AA, 0x58A7FD3E, ++0xD59B8CC9, 0x09DB0987, 0xF1D9753D, 0x9C79E20E, ++0x9A222AEA, 0xC4E58914, 0x6712E0A2, 0x8CD5C80E, ++0xEAB8AA56, 0xDBFA8D9C, 0x3515BD21, 0xB65B9E0C, ++0xF0D27FEE, 0xE33871C1, 0xEE8FE52F, 0x02ACCB3F, ++0xE9197277, 0xB7B70770, 0xA26E3581, 0x82481E7F, ++0x005AF99F, 0x8B970B4B, 0xEC74B662, 0x2F21C5A3, ++0x049DBA83, 0x495B3E1B, 0x112234B8, 0x95B42A5F, ++0x2C8FA833, 0x6D706E30, 0x2AAAEC09, 0xDE7C3377, ++0x06CE9D46, 0x7574EAAB, 0xFCB1A08D, 0x462AFB6C, ++0x192847B2, 0xCC149AC3, 0x427834CE, 0xE90180A0, ++0x946E526E, 0x6018BE4E, 0x20442F52, 0x1D39FA05, ++0x35F690AD, 0x29DB3A53, 0x6360158C, 0x3EC815F8, ++0xDED650AF, 0xFA168B37, 0x233F8A3D, 0x245009CF, ++0x71BB2237, 0x4989A01C, 0xD58AE4F1, 0x62C99EA0, ++0x48E9056E, 0x7E1A786D, 0xBF6CBAAB, 0x22669A6B, ++0x57857590, 0xE4558CE3, 0xBC6C63EC, 0x6AE02A61, ++0xA2ABFBBB, 0xD2B2FE90, 0xDF8BDB43, 0xEC2D59AC, ++0x7B6AFDC3, 0x6B001D5F, 0x3DFEE08F, 0xB9A597D6, ++0x09DEAC68, 0xE42D9E73, 0x2E33507C, 0x6525F051, ++0x0D7143C6, 0x01DD115B, 0x94180279, 0x28FC60D7, ++0xC0900603, 0xED4FBE53, 0xFC0677BD, 0x7DA2A878, ++0xA8D0EC73, 0xF6A09B2A, 0x24A129EE, 0x169BCA2F, ++0xE0BAE526, 0x5C8E2FCB, 0xA218EFFA, 0x842B61FB, ++0x87B860CD, 0x106E9B86, 0x930685F0, 0xC5A72109, ++0xFB977BD5, 0x9D3B4AC6, 0xDA378FE0, 0x0AAF747B, ++0x0408D50D, 0x488785B9, 0x81AE971D, 0x12ADFEF3, ++0xF0B64128, 0x3D4C90BB, 0xC994AAA1, 0xB854400E, ++0x901AE3DD, 0x7A4A0DE7, 0x18E07456, 0x20C38BCD, ++0x94441976, 0xE2E419C2, 0xDBD3C92F, 0x4DD63841, ++0xE2994959, 0xF41F196D, 0x0835431A, 0x93A2E9CF, ++0xB01FABED, 0xD0135535, 0xEBCEA18D, 0xC4F83A1B, ++0x5D72845C, 0x04335E3A, 0x68C4C987, 0x77178710, ++0xC5293A9A, 0x44E40AE1, 0xCE454FDE, 0x71DE89B7, ++0xA373D9D3, 0x6D19E483, 0x812896D6, 0xC3231C14, ++0xE960ABA4, 0xB7FB6F83, 0x1F7C4EB8, 0xD10DBE69, ++0x8575CF6E, 0xC03B15D5, 0x4D7F4EF3, 0xF0615F31, ++0x34E21762, 0x22D5A7A1, 0x729FA3F8, 0x2E1050FB, ++0x8A9F46DC, 0x535EB5A7, 0xD143560E, 0xF8EC3A4B, ++0x2249FD06, 0xE8E2AB08, 0x1E734127, 0xBA5B635A, ++0xD8F419DB, 0x0B5200D0, 0x8110304F, 0x3497DA80, ++0x35CA71CD, 0x0FD8227E, 0x086C74E2, 0xAB68A1AF, ++0xE3BD57EC, 0x83B42D29, 0x3C2D672D, 0x05D85CED, ++0x64F04926, 0x91364A12, 0x7FC73349, 0xEBA1FC77, ++0xECE0D20D, 0xB1DDDB9B, 0xEB6B492B, 0x0FC02BB6, ++0x56201D76, 0xED20F79E, 0xFC6034FB, 0x6A539F1D, ++0x520FECBF, 0x4E3AECF6, 0x76B01C74, 0xEFC421D4, ++0x82AC989A, 0x407A77CD, 0x6D287BFE, 0x26617425, ++0xEA2316C3, 0x8616554E, 0x9F4C4535, 0x88C0C6C1, ++0xEAC4F0F7, 0x32C7DD93, 0x41D9C37E, 0x2A9CBB2E, ++0x0591BAEF, 0x2BE43F21, 0x5E06EE4D, 0xDDDF5525, ++0xEC137DBE, 0xF0AA295C, 0xF2C9FDE2, 0x5DF9D693, ++0x10A6CAC0, 0xC6846D09, 0xF1DDABF3, 0xD56F8BBC, ++0xAA5DCE9D, 0x6F59004F, 0xB8A035BC, 0x61F47282, ++0xC89DAC9E, 0xFC7E5B3D, 0x4C5406DD, 0x54CFD147, ++0xBB44AB2A, 0x791269C0, 0x8CF66B4D, 0xD01A3190, ++0x636F45CA, 0xB32FC209, 0xCB8B9F49, 0xF46D74B9, ++0x5AFC9BD0, 0xC4C716C1, 0xF98C54F3, 0x36AFF013, ++0xB4D6D90B, 0x5F1299B6, 0xA3BFCFA4, 0xEA336AAD, ++0xCCD443DA, 0x74CA40B4, 0x31EF1614, 0x36D3FFEE, ++0x876AE252, 0xC8D62E9F, 0x6424F397, 0x1F730F2D, ++0xB20FDA53, 0xFCFEE60F, 0x676A61C3, 0x26C5E143, ++0xC201573E, 0x4A8C46BE, 0xEF87D0A9, 0xE07E80B4, ++0x34F20109, 0x8B936A70, 0x9F8E0305, 0xF3297CA0, ++0x4E7BF0E9, 0x0F374BB9, 0xCE78A01E, 0x5FE26DD8, ++0xA3826ACF, 0x321F69AB, 0x441AF14E, 0x8AC19CF7, ++0x4BFD1AD6, 0x5951ABD1, 0x098C17F0, 0xA9B75F76, ++0xA462551B, 0x6B703A12, 0xEDCB57B2, 0x8CD4C933, ++0xD338D3D8, 0xE343FC24, 0x9CDD52EB, 0x17A41942, ++0x63A8EF50, 0x215BB11A, 0xE1E25CB6, 0xB62C0A88, ++0xE58CDEC3, 0xC0E6389A, 0x2B7BEE55, 0xA3FCBD07, ++0x7CD451FE, 0xB06F6724, 0x5675A7EA, 0x141D52FC, ++0x05E86E9B, 0x53D75C3A, 0xE799AA2A, 0xE474384C, ++0x8C85E6E6, 0xA477A8D7, 0xA1E6AB0C, 0x9033E7CD, ++0x2F55D504, 0x4DAE81FB, 0xBD229A64, 0x862765C9, ++0x5B6A85F0, 0x95A39328, 0x38826CFB, 0xBF7DEBA4, ++0x42EFAB62, 0x2D0BBA60, 0xB06731AF, 0x16D4C4B0, ++0xCA4B9264, 0x3DF24AE2, 0xFED93848, 0x7CB33B08, ++0xAC9CAE9F, 0xA0F80B61, 0xA66CF713, 0x9364865F, ++0xDFA1E0B3, 0xFE6DF33F, 0x8039A612, 0x119F60BF, ++0xCEEDE309, 0xD28316A8, 0xCD61D2F5, 0x3CBEB015, ++0x85C0BF51, 0x6EDBBC15, 0x79F3D207, 0x485EE4FA, ++0xCEC302EA, 0x59D8B92D, 0x51C1FB36, 0xF4FE8B71, ++0x2DBD5718, 0x84024040, 0xFDD6590F, 0xA1CE9CC9, ++0xC4AEAB72, 0x0A2FE8BF, 0x28C33618, 0xBA4E15FB, ++0xA9C72819, 0xA3EE45D7, 0xD2DC52F1, 0x3FC84A2E, ++0x1C9DF73E, 0x632F9BDE, 0x7E9FBD20, 0x0D689B79, ++0x91E8D5C0, 0x6EE7952C, 0x905F192E, 0x2D79E712, ++0x8670A7A2, 0x1DBFC4D9, 0x64634429, 0xE636043B, ++0x643C6B0F, 0x50AF327B, 0x0E734D61, 0x2D7D6E46, ++0xB877DCD6, 0x7CCF4F1A, 0xDF4D8CF8, 0x0E7FA78E, ++0x0CBC4EC2, 0xAE9B4A22, 0x4F02D49C, 0x48F09C43, ++0x5031B1A0, 0xDCB8A1FC, 0x91C73599, 0xCF00A64D, ++0xDFCE561E, 0x8B18157D, 0xE1ED6A81, 0xCF94EF36, ++0xB412CE1A, 0x602E2076, 0x716B0F3F, 0xADEB32C0, ++0xD4E16094, 0xEC95D41F, 0x75858767, 0x438AD1A1, ++0xE61C5527, 0x0D71FBB2, 0x2A99D070, 0x5C018826, ++0xCCCC27FD, 0x053883D9, 0xF1D30EF5, 0x676AD38A, ++0xDF81AB28, 0x2257FB9D, 0x373313AE, 0x67E1FE8A, ++0xF4F66B02, 0xAFF8C7FA, 0x3B60D94D, 0xD44D0FE2, ++0x5FCDFE4B, 0xC63010B6, 0x06CFCCF4, 0x09D8DD85, ++0xAB79F2BE, 0xD5C0C498, 0x7364E4FD, 0xB295CEDF, ++0xDB89A068, 0x59A6A0C7, 0x0C823207, 0x7380FCFE, ++0x6E33C4B9, 0x0744E4F2, 0xF663BB33, 0x9EE512CE, ++0x870ED35B, 0xB4502654, 0x367CD4FD, 0x5D4238D9, ++0xEAB2B86E, 0x6E8ADDAA, 0xF080EDD6, 0x1DC90F46, ++0xB1FC9127, 0x63771392, 0x96729BF6, 0xD18E1413, ++0x5D85938D, 0xB8CED349, 0xF9B886C1, 0xCA486562, ++0xBAA9ED7A, 0x049718D8, 0x7CF8E67A, 0x1702843C, ++0x6DCDC34E, 0x93C51F83, 0x2415A4F3, 0xA8D77B3A, ++0x0FB823E8, 0x424F03C3, 0x9CAA503C, 0x7AA5433F, ++0x3BDD74FE, 0x99D3332E, 0x1E62231B, 0x90A4E595, ++0x7EDA974D, 0x43E2CD14, 0x27DB9D9F, 0x561F5CC6, ++0xA77EABA6, 0x97867B48, 0xAD6533CE, 0xEB726CF4, ++0x5857B217, 0x2D7DA10B, 0xD939C20E, 0x81F1F073, ++0xF42DEAF2, 0x3AD7780E, 0x88C77661, 0xD2E819B2, ++0xF872F581, 0x999F0C5A, 0x3887ABA4, 0x27F95B6D, ++0x991D9458, 0x9D1BB131, 0x6ECC5298, 0x9E9A7B26, ++0x6E65F271, 0xE90FA04C, 0x7B692AA0, 0x878943D5, ++0x924895E5, 0x041BC73A, 0x448E28B2, 0x61D22D1F, ++0xE7969773, 0xBC8E5980, 0x9A198852, 0xB94415C9, ++0xA02374BA, 0x340BD5F3, 0x27F2A0FF, 0x39BDB33F, ++0xCC042BCF, 0x83D6C135, 0x9C7A8D8E, 0x05823C23, ++0x2D7A3F91, 0xE792BCCA, 0xA2D82177, 0x73C82E7E, ++0xBEBC9613, 0x9F596CB0, 0x6E784AA7, 0x1B7BDA9F, ++0x846391F7, 0x852AD070, 0xF831E8CA, 0x16A78223, ++0xF68F5250, 0xE2554493, 0xD38F2AFB, 0x764BA7A8, ++0x3CAEFC55, 0x6E9B9037, 0xD87D486E, 0x7352AEA9, ++0x11987EE0, 0xDF7E84DA, 0x2838E736, 0xA8C7BAC2, ++0xF49E21EE, 0xFAD106E9, 0x7363AC6F, 0x5E9974CB, ++0xBA008BB0, 0xAF5DB3FC, 0x7AC3CFD7, 0x2D55EDC6, ++0x2C1C9AD7, 0x6A3AA494, 0x5F0E0A3A, 0x37422BFA, ++0x83B4D594, 0xB7ECCF66, 0x82FCCDD0, 0x8ECBFD79, ++0x664B9341, 0x02F178A2, 0x2095C8E0, 0xFC5F17B7, ++0x1810BA9B, 0x964E4CD1, 0xFBAED808, 0xDEE87796, ++0x63DE4F69, 0xC99275DD, 0x65242304, 0x7AB5C28B, ++0x01BB7A3B, 0xC85D7716, 0x32AFB9A3, 0x2ED2CBB1, ++0xB194218F, 0x21FE560D, 0xCB4503A5, 0x5CE0464D, ++0xC4AE9A3C, 0x061530CB, 0xEDA38E6B, 0x4029D3E6, ++0xB0C20336, 0xA37825C0, 0xC68F8B37, 0x9405AD3B, ++0x8B1A8F99, 0xA761DE8B, 0x683B3259, 0xA154C554, ++0x6BD835C9, 0x6DEAE35A, 0xBEAE6D49, 0x21D8B074, ++0x46C01B31, 0xBE9B3A16, 0x1D611EAA, 0x423AB74C, ++0x931F5AF5, 0xBB9E289A, 0xA4101132, 0x4A8BE0D7, ++0x3307E4B2, 0xDE78DB5E, 0x347EB5CE, 0x13EEE999, ++0x2C2D7955, 0xBA893EBA, 0x5DFC2EC1, 0xE7DD7A5F, ++0x5E1C64D8, 0x4552E447, 0x1837D8E4, 0x9711836B, ++0x3219F893, 0x04392C84, 0x3E94848C, 0x15E5F481, ++0x0EC58819, 0x7341D458, 0x4AE63711, 0x85C1FD1F, ++0x97B58BD7, 0xB0550EBE, 0xB9108743, 0x6F53B386, ++0x7A73F31B, 0xE07CF8B9, 0x61FF27C8, 0x06A9A8B4, ++0xEB0F2BB9, 0x46D275FB, 0xCF39B474, 0xC34F3B6D, ++0x52F2F119, 0xD87963BF, 0xC60BF16C, 0x7797D0AD, ++0x7EA4DBF0, 0xD21409C7, 0xF678A927, 0x638E67CD, ++0x93261AED, 0xEA9B25FE, 0x1EBCAFDC, 0x580CC829, ++0x58D1DA1A, 0x658881F8, 0xC48DB682, 0xD42E8CB4, ++0x1DF33D74, 0x31C04F68, 0x7D871E29, 0xAE11FD72, ++0xD7E8F8F6, 0x530D9D9C, 0x580A0715, 0x0F17B1A3, ++0xB863F42F, 0xA6A4DC08, 0x82773E76, 0x9354B309, ++0xE17D0770, 0x04E4DE5B, 0x712EA396, 0x49D37B55, ++0xAE4109BA, 0x03862DC9, 0x7BCF61D2, 0x43CA2017, ++0x23BDD50F, 0x74577459, 0x4E8F4E23, 0xBF924C1A, ++0xE4EC70CE, 0x37FBEC66, 0xA6DA8935, 0xE11F4090, ++0x5C8F9EE3, 0x19D167EC, 0x9EE4F2C5, 0x64A81E6C, ++0xB35642BB, 0x82083A01, 0x001CA1F6, 0xAA69C7E8, ++0x685F24D9, 0xE6868E31, 0x38ADD8F0, 0xA2FDD44E, ++0xEE0C491D, 0xC60B1E9A, 0xF7A89268, 0xFD784F35, ++0xC6B7335C, 0x75EFCEC1, 0xE2D9F7CF, 0xE1C364F8, ++0x7CC63B2C, 0xC179E2AD, 0x56C193A5, 0x5134FB69, ++0x35058BB5, 0x36F4BCD5, 0xDF4A08C2, 0x14AA2330, ++0x760C8CD8, 0x2C562394, 0x0BEB669B, 0x2301973A, ++0xAF5C4FF2, 0x1C770AAB, 0x25DD2087, 0x732AADC4, ++0x59054958, 0x59DDCBE4, 0x74CFC8A8, 0x7C015016, ++0x32A0276E, 0x8F1C2E93, 0x0CE91F71, 0x055C307A, ++0x435D967E, 0xF4C33704, 0x5BDF2AD7, 0x8855099C, ++0x307B2736, 0xBB6B19CB, 0x626349D3, 0x8F52ABFA, ++0x251A1ED6, 0xE0587BC0, 0x12831408, 0xDA83CABF, ++0xAB2C7DFD, 0x6BCF0271, 0x72058DF0, 0x17AFC1DD, ++0xFFC52C30, 0x551401E0, 0x9EED54DF, 0x14E951E4, ++0x14624B3F, 0x4C24650B, 0x5A65F86B, 0xE94F6143, ++0xDC7CE9CF, 0x94D5D8F3, 0x093B0A04, 0x22098D01, ++0xEDF09E7C, 0x165EDB0F, 0xD09CA774, 0xB96AA141, ++0xB5745978, 0x9D820434, 0x42B0E026, 0x96938A25, ++0x72E8634B, 0xBE36EC02, 0x42F3F74B, 0x358FA621, ++0xBD451484, 0xB43A75D1, 0xB0A57F91, 0x701A7C82, ++0x484B3F46, 0x047F78AD, 0x65F7371C, 0xEAC8A954, ++0xE59F6354, 0x3EEEFB4E, 0xF131954B, 0x1C00BAC2, ++0xE3897637, 0x5FEC83AB, 0x58CFA2C4, 0x1F4C0A6A, ++0x97956BC6, 0x63D11D7D, 0xB46179D0, 0x11039A75, ++0x1B50E088, 0x68E9476B, 0xAA68DB55, 0x8A4A051E, ++0xEFA0DDF5, 0x05A2A674, 0xFFE03E72, 0xC5A0295C, ++0x6FD4D834, 0x8E42BB94, 0xF3DFD88E, 0xBA691AD2, ++0x3458473E, 0x6269A348, 0x72962FB6, 0x86D5064B, ++0x8A153740, 0x54AC97D8, 0xED2CE057, 0x68200474, ++0xBBA8E19D, 0xBFDD08F3, 0xB0DF76D1, 0x62F29649, ++0x5AB77030, 0x1EE9A00E, 0x7DAB1C90, 0xAB608FFD, ++0x8506A853, 0x75B9339B, 0x1AE0CCBA, 0xFB60BB79, ++0x8650F92F, 0x4819E1F7, 0x0A7045A8, 0xB5BCE5F1, ++0x77A98B27, 0x03DE21E4, 0x3FE3F132, 0x106827EC, ++0xD4DC1469, 0xAAC82F9B, 0x1D5953A1, 0x8034B369, ++0xD4412B6F, 0x90FB9F25, 0x14279070, 0x6D98AF1C, ++0x3D286F37, 0x8324A732, 0x58123E4E, 0xEB051032, ++0xC15CD557, 0xEB82DE99, 0x6213434E, 0x39F0FC9C, ++0x5EBFE1C5, 0x8CEBF470, 0xFF7D8D8A, 0x740A6A3E, ++0x720D080C, 0xB73B74FA, 0x5173F96E, 0x9FC01794, ++0xDABF1C81, 0xCA813295, 0xBEA2DB8D, 0x4C7E0CE4, ++0x8051BA67, 0xE63399E2, 0x83A15EE4, 0x47F4A718, ++0xD8246E6A, 0x0B4F87BE, 0x031648B8, 0x99E3E3E6, ++0x4ABCC64F, 0x52768181, 0xE708372B, 0x2D0B1D2C, ++0x4DF52402, 0x389BE9F6, 0xDE2F3232, 0x5D43D74E, ++0xD37BB898, 0xE7272645, 0x9B5432DA, 0x9D7A9473, ++0xA69628A5, 0x583555A7, 0x255B08BD, 0xAD68EAE3, ++0x1A79982D, 0xACE09726, 0x15E576AD, 0x260EB406, ++0xA7440B46, 0x66B6D317, 0xBE6ECA3B, 0x3ADEA1C1, ++0xD80399C3, 0x0EF198D0, 0xFAEE2010, 0xEF2E8E56, ++0x5B6CC402, 0x3FD27BE2, 0x970AAB5F, 0x618C17C6, ++0x7F5022FB, 0x552FC1FA, 0x5DD82984, 0x09769539, ++0x98812D1F, 0xBD8B2539, 0xD78AD9A6, 0x1CE41D07, ++0x272A0AB7, 0x5CB7E101, 0x6F42D56A, 0x001D930E, ++0x3C17C305, 0x30AAE354, 0x2A4AABE0, 0x922BCB94, ++0x73F34C1C, 0xE07E1501, 0xCB55A3E1, 0x0CDC3669, ++0xD9C07DE7, 0x2DAB82BF, 0x963EACAA, 0x9B05E0F1, ++0xE2DA0EFA, 0x0613BFE5, 0xDFB605E9, 0x5DCCA8FD, ++0x6D433873, 0x81A9B4C5, 0xD1D1CB14, 0x9B6A9906, ++0xC104767C, 0x30101D37, 0x186FBB79, 0x8F95D488, ++0xA3094F43, 0x7F17C981, 0xFD92B3FE, 0xADAB3AB5, ++0x20D1406C, 0x9462C8E7, 0x5D64819D, 0xB3E85196, ++0x67B854FE, 0x7D039FC6, 0xAD98A85E, 0xF672E041, ++0x30FA19A9, 0x4A276EB8, 0xB7041D2E, 0x57BB21E2, ++0x4E251667, 0x15C5401E, 0xDAB59431, 0xD6C6FD1F, ++0x1726EB70, 0x900F4E84, 0xD327DE33, 0x7A0AE04B, ++0x76B1174E, 0xFD547B94, 0x370832DC, 0xDDE65CDD, ++0x74672C02, 0x164703FE, 0x34CAD31F, 0x3E692DED, ++0x4BC38FA5, 0x143F99E5, 0x61BB640E, 0xB957BC8D, ++0xC9DD9E35, 0x2B5CB310, 0xADD6EAD0, 0x91981D46, ++0xED803D57, 0x61D7737C, 0x92D3AC3E, 0x36A034CB, ++0xE1395DC5, 0x5F2070F8, 0xC5EE9F8A, 0x70546B88, ++0xC9EA230C, 0x58DC3073, 0x57CBBEB7, 0xA0B78CFE, ++0x0B3FE75B, 0x07ADACCD, 0xC292C338, 0xD70CD7E5, ++0x729D8F4E, 0x218FA041, 0x10EC1199, 0xAC1EC51D, ++0x5DECC8D1, 0xBA36230A, 0xBC41F5A5, 0x75864896, ++0xB4403D4A, 0xFEEE8F44, 0x8D94A256, 0x62BA0115, ++0x3A570C61, 0x9221C583, 0xD2981A6B, 0xFD8AAF5A, ++0x2A102D59, 0x64083BDD, 0xBD1AADE6, 0x7E6D1E99, ++0x20568A6D, 0x8DFA704B, 0x87D27122, 0x2EFDAB7D, ++0xF3AF9D39, 0xD8DED0B2, 0x2D4B34B9, 0x12F3E32C, ++0xA6BCBE65, 0x680029A1, 0x094B07B3, 0xDA5918ED, ++0xF7D0A86D, 0x1A7E18C8, 0x9285A97F, 0x2040282C, ++0x5B133531, 0xA48237AC, 0x3557BC1B, 0x7E6ED77B, ++0x436234C7, 0x9B2094DE, 0x5D967593, 0x8867D1C4, ++0x88EC3948, 0xE7F84AD4, 0x1871B3E6, 0xE8E992C6, ++0xA16DC2F8, 0x0DFDF590, 0x9B56238D, 0x329017F5, ++0xBF9BD409, 0x68BD9B1C, 0x4036C4FF, 0x3BF6D93C, ++0xAE100602, 0x90B43508, 0xA85B4013, 0x2C66EA54, ++0x227D32D7, 0x0BA526D1, 0x075213B8, 0x1A3DED07, ++0xD458DFFD, 0xDC8ACD43, 0xAC7809AB, 0x2D25408A, ++0xD8F0C887, 0xAD8CD30D, 0x4054F61E, 0xA9F0CCA3, ++0xBFEBD31D, 0x6D2BAB1E, 0xF8E42D8B, 0x6C94A4E4, ++0x1158D2A3, 0x93F44EFE, 0x8AD05A25, 0x8C229D32, ++0xB213D76E, 0xDFE63822, 0x561986EC, 0x806CA082, ++0x6DB3BF8D, 0x1E850D30, 0x8F7A44C0, 0x75BB3328, ++0x86C7BE12, 0xDE5C44BD, 0xDF4D048E, 0x968712C3, ++0xB1B41CF8, 0xCC194FE9, 0xDA2E1A8D, 0x72A08662, ++0x5ABA2536, 0x223E2013, 0xA5A923A5, 0x7565B5DD, ++0xBCA0A2B0, 0x0C29864B, 0xAAD8CB87, 0xE4C7E559, ++0x77E19E51, 0x194E54ED, 0x54DD1B54, 0x0FAD37A7, ++0x0EF6B0E3, 0x0E3A2FC8, 0xA0063995, 0xE17AE20E, ++0xDC11B7F8, 0x85F1A76D, 0xD97858D4, 0xB763E49C, ++0xB5BE7EC4, 0x3CE924C4, 0x4246019D, 0xD33DBB27, ++0x737863A7, 0x32C26BDD, 0x714897A3, 0x36091018, ++0xF26BC990, 0xDDB640B0, 0x448F5B12, 0xD7A5EB4B, ++0x5614EEA4, 0xCA4912FB, 0x011F9D6C, 0xA4FC90AB, ++0x9FB4982D, 0x20AD146F, 0x4B7AB74E, 0x107A9411, ++0x71DBA90A, 0xD510E3D2, 0x248D0D35, 0xB666229E, ++0x61EE1EEA, 0x702031B5, 0x36992A7B, 0xC90C08CB, ++0x6478995A, 0xE6C2BA7A, 0x8A9179AC, 0xC8EE2956, ++0x27B042C8, 0x48DB81D9, 0xAA39F2CB, 0x5E4D5F3C, ++0x24FFD6B9, 0x5B562C2F, 0x00FD33B6, 0x435F5F52, ++0xF392FFC1, 0x0E927C40, 0x5508CBAB, 0x976AA567, ++0xA13E7C52, 0x532109E9, 0x16B9021F, 0x60C615A1, ++0x1D23C258, 0xFD783147, 0x63600FB1, 0xAAA245F0, ++0x9B3DC1E1, 0x7B270D0D, 0x5B1632CE, 0x8B871F7F, ++0xC535EFF8, 0x73109C6A, 0xEB83D02D, 0xF7AE76FB, ++0x2E39E502, 0xA4128216, 0xF90D57E5, 0xFF0C465E, ++0x02008029, 0xE5CBBA1F, 0x4280FA3C, 0xCDBD75C8, ++0xCB4AF342, 0x17695A4E, 0xAA6162B5, 0x8660A679, ++0xD1A8701C, 0x47694CA7, 0xDA8D43FD, 0x44A4BC1B, ++0xAB34B9AA, 0xE55563DD, 0x08D4142B, 0x81197AC8, ++0x997B1DC2, 0x2E7CC50A, 0x7A326A21, 0xA76419DB, ++0xEA8B5428, 0x65729140, 0x051DAF66, 0x8871BCA9, ++0xA175E5BF, 0x60310C98, 0xB7DE8929, 0x35E2459E, ++0x08EB4547, 0x904D7B2B, 0x29382CC4, 0xCEC8664E, ++0x1E8C9C2C, 0x3B942134, 0x9CEC5D55, 0xDA548376, ++0x2E4EFD61, 0x26F65F09, 0x5A3DD7CA, 0x2FD4E58D, ++0x6B71B8C2, 0x13189115, 0x2B5542BA, 0x1CE85C2C, ++0x5B9FE09D, 0x68704BFE, 0xB15313B9, 0x3EF2729E, ++0x583ECC31, 0xA3DED8CA, 0xFCD27C3D, 0x904DAB39, ++0xFE1069A4, 0xE99A57BA, 0x112EB80C, 0xE1483C74, ++0x8A27B0D7, 0xA58F7325, 0x7CD050A1, 0x626D4F3E, ++0x51643657, 0xA967FC59, 0x5BACBC0B, 0x2CF3E459, ++0x7D8988D9, 0x53913DF8, 0x2381A6FC, 0x64D6D441, ++0x48AE9101, 0x185D9539, 0x1B044AEC, 0xB5ABCEDD, ++0xFA8ECA52, 0x8CCDD142, 0x96FD4442, 0xD865FEDF, ++0xCE4EE2FA, 0xA5160AE9, 0xC91B2B3A, 0xF993F45F, ++0x1509132C, 0x920ECC5F, 0xD813DDC1, 0x834B68E4, ++0xD5E876A0, 0x61DE0E41, 0x4C143913, 0xC7293985, ++0x17E226E7, 0x38830927, 0xDC604DF2, 0x799D1430, ++0x846585AB, 0xE5D21E38, 0x6381D136, 0x1B60633B, ++0x23B7AE14, 0x554E53CC, 0x5807A210, 0x30560866, ++0x12F79E62, 0xE27B5D45, 0x3889C1E5, 0x47F845FF, ++0xFFD9DE98, 0xB10E09D2, 0x4A184A72, 0x083D2971, ++0x8AB7478D, 0x92380377, 0x57A724EC, 0xBBBD5CA6, ++0xE2FB9D32, 0xAB6ADFC6, 0x3916DED4, 0x4E19438F, ++0xE21E15CF, 0x6AF4BCC9, 0x8D08924A, 0x1662BAA9, ++0x3064AD27, 0xB86D7EE4, 0x88624C62, 0x1A0BF3E7, ++0xF3E4A287, 0x6787F006, 0x01375D4B, 0x998BB38F, ++0x6D669A29, 0xD760B093, 0xC4768853, 0xF041100F, ++0x35DE10DD, 0xE06C8BB8, 0x2C79A902, 0x60600DAD, ++0x6E11CF5C, 0x18778777, 0x7CCE406C, 0xE54AF2EA, ++0x7472C475, 0x73DBEE7E, 0xE533DC40, 0xB07407DD, ++0xF6ACA8D3, 0xE71BD7D1, 0x4BD3514D, 0xC5C362CA, ++0x0690E5A1, 0x0FFDC8D8, 0x58188645, 0x8636413C, ++0x3412A033, 0xAF4FC340, 0xA5DFEAB8, 0xB87272E3, ++0xA4A9219F, 0x29696E90, 0x35D2F627, 0x8794DBD7, ++0x5D2D87F8, 0xFA73559D, 0x7D22F440, 0xF50197E9, ++0xEB74B829, 0x8F9649CF, 0x16F47D30, 0x5C7D9870, ++0x36FF6C0B, 0x313A92ED, 0x303B3654, 0xE3E33CCA, ++0x02C26ECC, 0x26949920, 0x4445DF20, 0x01FDBC98, ++0x49138C6F, 0x1B5555E2, 0x122B45D2, 0x4B2E0202, ++0x7B6014D4, 0xFAE0CD09, 0x77E165A0, 0xFBE76980, ++0xF5808BD3, 0xFD110E5E, 0x97450E11, 0x297F9B1F, ++0x607A2C41, 0xE384DFC9, 0x25D9A8DC, 0xF919D955, ++0x5E025993, 0xCC318847, 0x9717D2D5, 0x48F0DD1F, ++0x6CC4A8EB, 0x9BD0F4E1, 0x506F2A93, 0x18B8748E, ++0x16FFBA48, 0x552E4955, 0xB963F64F, 0xA1A34AC8, ++0x62E95CC7, 0x4D87EA89, 0x21E8C031, 0xC1F0ED07, ++0x28B7BB22, 0x0B838D04, 0x6361B440, 0xA653521C, ++0x92DA3F78, 0x4241CFED, 0xFAFCBD41, 0x3EFAB6BC, ++0x25F30607, 0x41BB70DA, 0x9FF3440A, 0x2502039E, ++0x3813EC82, 0xC6A4FD6B, 0xF8537C8C, 0x098ED49F, ++0xE0A0BD6E, 0x6BA2F2B3, 0xC35C9D9D, 0x1256E66A, ++0x790B2490, 0xD5C69889, 0x39E712FE, 0xCF73DE0B, ++0x41B3B614, 0x745ABD73, 0x654C79D8, 0x5B15923D, ++0x8C15F218, 0x585CCCF0, 0x624F7B44, 0x76BDDFDB, ++0x96F26B52, 0xE13058A1, 0x086C950E, 0x29519DEA, ++0xA42CFE04, 0x0D7A190B, 0xD0678C6A, 0xABB78679, ++0xBA48A2E4, 0x5F3DA10A, 0x11F04183, 0xAC720A3F, ++0x6A807781, 0x6F146BFB, 0xE8A67934, 0x54578834, ++0xAA60C8F0, 0x2061A1E6, 0x9E87799B, 0x68D91F86, ++0x8974F540, 0xB1C3F101, 0x99C21E56, 0xB57BA73F, ++0x8B2DAA3E, 0xF1E2D24E, 0x48F7D4EE, 0x7039FDB3, ++0xC666EEDC, 0x251F972E, 0x4D53F6BF, 0x6CC73EE7, ++0xCB07F7B9, 0x69ECB8CA, 0x363FD80C, 0x3B587AB3, ++0x738C1E5C, 0x5C9C1D92, 0xE7B52396, 0xEDE6324B, ++0xFE5B5045, 0xC90D8B3E, 0x371A0128, 0xF2C8DCF8, ++0x5B648CB5, 0x12F8E8FF, 0x5FE4BA71, 0xB925CFBE, ++0x7416E14F, 0x76489FFE, 0x1F4DE367, 0xA400F039, ++0x66390E83, 0x1AE79CEC, 0xDB573E98, 0xB6021F29, ++0xD01615E5, 0x02A2281F, 0xE85019C1, 0x027BB41F, ++0x8D9177C3, 0x79026E78, 0xF158B623, 0xBEFF5858, ++0x7B63518E, 0x8F42C08C, 0xB388227D, 0x940D607A, ++0xA4C79541, 0x9800CC91, 0xA356B535, 0x285BABB9, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0xE411E520, 0xA0024528, 0x442B4428, 0x96070009, ++0x46106246, 0x8FFB2522, 0xD4027504, 0x0009AFF5, ++0x00000FB3, 0x00200004, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x16D49357, ++0x0009000B, 0x4F222FE6, 0xDE947FFC, 0xE114D594, ++0x1E13D494, 0x67521E4C, 0xD494D693, 0x37402769, ++0x62528F06, 0x7201D692, 0x60602522, 0x2600C93F, ++0xD7906152, 0x2512611D, 0x264B6652, 0x2562470B, ++0x0009B00D, 0xE60095AC, 0xC84060E2, 0x2F028F03, ++0x8FF93652, 0x7F047601, 0xA05A4F26, 0x4F226EF6, ++0x410BD185, 0xD4850009, 0x0009440B, 0x450BD584, ++0xD7840009, 0xD284E1FF, 0x2712611D, 0xD4835029, ++0xE1FFCB01, 0x1209E501, 0x12112212, 0xE7202452, ++0x4718D57F, 0x2572D27F, 0xD17FE700, 0xD680D47F, ++0xE2012270, 0x24702172, 0xD67E2620, 0x2641E4FF, ++0xD57DE600, 0x666DE104, 0x76016063, 0x4000626D, ++0x8FF83212, 0xD5790545, 0x2520E201, 0xD279D778, ++0x2710E100, 0xE5802212, 0x655C6613, 0x666DD476, ++0x76046763, 0x374C626D, 0x8FF83253, 0xD4732712, ++0xD573E101, 0xD6732410, 0x2542E400, 0xE03AE501, ++0xD272D771, 0xE0390654, 0x27110654, 0x000B4F26, ++0x7FC82211, 0xD76FD16E, 0xDC70DB6F, 0xD271DE70, ++0xD572D471, 0x1F12D672, 0x1F76710C, 0x1FB877FC, ++0x1FEA1FC9, 0x72041F2B, 0xDE6FDC6E, 0x1F13EB10, ++0x1F511F44, 0x1F771F65, 0xD86C1F2C, 0xDD6DD96C, ++0xD26DEA00, 0x89003A22, 0xD1587A01, 0x88016010, ++0x56F98B03, 0x4218E201, 0xD1682622, 0x0009410B, ++0x440BD467, 0xD5670009, 0x0009450B, 0x6010D14C, ++0x8B108801, 0xE650D14B, 0x46186212, 0x8B083266, ++0x56FAD147, 0x2120E200, 0xCB016062, 0x2602A003, ++0x72012710, 0x60822122, 0x89098801, 0xE2C8D15A, ++0x622C6612, 0x89033626, 0x6010D158, 0x8BC88801, ++0x51F76792, 0x217252F6, 0xD6555191, 0x55FB2212, ++0x52FC6462, 0x55612542, 0x2252E400, 0x61436643, ++0x05DE6013, 0x36CC4608, 0x02DE2652, 0xC9036021, ++0x8B028801, 0x720162E2, 0x74012E22, 0x36B3664C, ++0x71048FEE, 0x66C2D147, 0x45286512, 0x265B4518, ++0x60822C62, 0x89018801, 0x0009A168, 0x6272D742, ++0x8B132228, 0xD726D541, 0x6552D441, 0x51436672, ++0x316C365C, 0x27622668, 0x14138D05, 0x6262D63D, ++0xB1A57201, 0xD61E2622, 0x2622E200, 0x52916692, ++0x8B013620, 0x0009A144, 0x6061A06E, 0x001C001C, ++0x001D4020, 0x0000B38E, 0xFFFF0000, 0x12340000, ++0x001E1015, 0x00201278, 0x002018A0, 0x00201922, ++0x0020128C, 0x001C3510, 0x001C3624, 0x001E212C, ++0x0020397C, 0x00203514, 0x00203984, 0x00203990, ++0x0020399C, 0x002039F8, 0x002039FC, 0x002039A4, ++0x002039A5, 0x002039A8, 0x00117700, 0x00203A12, ++0x00203578, 0x001142D8, 0x00203A14, 0x00203A16, ++0x001C3D30, 0x00117718, 0x001C3D00, 0x001C1000, ++0x001C36F8, 0x00117734, 0x001C3684, 0x00117710, ++0x001C3520, 0x00117600, 0x00117740, 0x001C1028, ++0x0020358C, 0x002039AC, 0x7FFFFFFF, 0x00201734, ++0x002032BE, 0x002022E8, 0x00203DC0, 0x002039FA, ++0x00203584, 0x002039EC, 0x001C3D2C, 0x001C36B0, ++0x0020351C, 0x0011775C, 0x8801C90F, 0xA0CF8901, ++0xD17C0009, 0x36206212, 0xD47B8904, 0x2421E200, ++0x2162A0CC, 0x6211D179, 0x89012228, 0x0009A0C3, ++0xE202D775, 0x75016571, 0x3123615D, 0x27518D02, ++0x0009A0BC, 0xD27255F2, 0x62226052, 0x40094019, ++0xC90F4009, 0x8F19880A, 0x52F31F2D, 0x40196022, ++0x40094009, 0x8808C90F, 0xA0A78901, 0x60630009, ++0x51F255F8, 0xE701CB01, 0x2502D263, 0xE1002172, ++0x2211D564, 0x74016452, 0x2542A098, 0x8B3F8805, ++0x602252F3, 0x40094019, 0xC90F4009, 0x8B168802, ++0xE5FFD45D, 0x655D6742, 0x8B102758, 0x6272D75B, ++0x8B0C3260, 0x55F257F8, 0x2762E101, 0xD5522512, ++0xD757E400, 0x62722541, 0xA0777201, 0x52F32722, ++0x40196022, 0x40094009, 0x8805C90F, 0x31B38B6E, ++0xD5508B6C, 0x615257F4, 0x7101E240, 0x64722512, ++0x1F4DD14D, 0x42182419, 0x8B033420, 0x6262D64B, ++0x26227201, 0xE200D640, 0x2621B0AA, 0x0009A056, ++0x3123E220, 0x88038B52, 0x52F38B1E, 0x40196022, ++0x40094009, 0x8803C90F, 0xD7418B16, 0x647251F4, ++0x7401D23D, 0x65122742, 0x1F5DE640, 0x46182529, ++0x8B033560, 0x6262D63B, 0x26227201, 0xE200D62E, ++0x2621B086, 0x0009A010, 0xD738D137, 0xD22A6412, ++0xE5007401, 0x21423A76, 0x22518F06, 0xEA00D634, ++0x72016262, 0x2622B074, 0x2FB2D532, 0x95406652, ++0xD4305BF1, 0x36205241, 0x60618910, 0x8B01C803, ++0x2B22E201, 0x8FF54510, 0x57F15664, 0x6272E1F0, ++0x41284118, 0x2722221B, 0x6BF2A008, 0x6BF2A006, ++0xE200D615, 0xD1152621, 0x2121E200, 0xE20256F5, ++0x42186662, 0x26284228, 0x1F6D8D0C, 0xD61FD11E, ++0x460B6511, 0x2008645D, 0x57F58904, 0x6272D11C, ++0x27222219, 0xD11BE201, 0x66122822, 0x8B012668, ++0x0009AE17, 0x450BD518, 0xD1180009, 0xAE10E600, ++0x07D12160, 0x00203A0C, 0x00203A10, 0x00203A18, ++0x001C3DC0, 0x0011772C, 0x001C3B88, 0x002039F4, ++0x0011773C, 0x00117744, 0x0000F000, 0x00117764, ++0x00117748, 0x00117768, 0x0011776C, 0x01FFFFFF, ++0x0011774C, 0x00203584, 0x001142D8, 0x00114774, ++0xFDFFFFFF, 0x00203DC0, 0x0020246C, 0x002039FA, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xD11F7FF4, 0x6212DE1F, 0x67E25411, 0xD41E1F41, ++0x1F722F22, 0x6743D51D, 0x7794D21D, 0x5A425841, ++0x6C726942, 0x6D225B16, 0xE6006052, 0x2502CB20, ++0x7601E540, 0x3253626D, 0x62F28BFB, 0x212255F1, ++0x55F21151, 0x2E52D613, 0x14A21481, 0xD4122492, ++0x11B627C2, 0x674226D2, 0xD911DA10, 0x2A72E801, ++0x1A8C490B, 0x4218E201, 0x7F0C1A2C, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x000068F6, ++0x001C3B9C, 0x001C3D98, 0x001C3700, 0x001C3500, ++0x001C5960, 0x001C8960, 0x0020358C, 0x001C3D00, ++0x00201610, 0x2F962F86, 0x2FC62FA6, 0x2FE62FD6, ++0x4F124F22, 0x7F884F02, 0xE018DEB2, 0xD4B261E0, ++0x61E30F14, 0x62107101, 0x440BE01C, 0x20080F24, ++0x8F126D03, 0xD4AD1F08, 0x6740DDAD, 0x657CD4AD, ++0x470BD7AD, 0xD2AD0009, 0x621C6120, 0x46086623, ++0x36284608, 0x3D6C4608, 0xE01C1FD8, 0xE58004FC, ++0x604C66E2, 0x3050655C, 0x2D628F17, 0x01FCE018, ++0xDEA3E500, 0x641CA008, 0x6753655D, 0x607037EC, ++0x31DC6153, 0x80147501, 0x3243625D, 0xD49D8BF4, ++0xE200D59D, 0xA27F2421, 0x20082521, 0xE0188B13, ++0xE50001FC, 0xA009DE96, 0x655D641C, 0x32EC6253, ++0x62536722, 0x32DC6672, 0x75041261, 0x3243625D, ++0xA2698BF3, 0x88012D10, 0xE0188B16, 0xE40001FC, ++0x671C2D40, 0x624DDE8A, 0x8B013273, 0x0009A25C, ++0x6DE3644D, 0x7D046243, 0x32EC6643, 0x652236DC, ++0x74086162, 0x2512AFEF, 0x8B198804, 0x01FCE018, ++0x2D70E700, 0x1FD56D1C, 0x627DDE7D, 0x8B0132D3, ++0x0009A242, 0x6173677D, 0x31EC65E3, 0x75046412, ++0x365C6673, 0x61426262, 0x21297708, 0x2412AFED, ++0x8B198805, 0x01FCE018, 0x2D70E700, 0x1FD46D1C, ++0x627DDE6F, 0x8B0132D3, 0x0009A226, 0x6173677D, ++0x31EC65E3, 0x75046412, 0x365C6673, 0x61426262, ++0x212B7708, 0x2412AFED, 0x8B598831, 0x61E6DE67, ++0x61E31F19, 0x64E27104, 0x1F4A6216, 0x1F2B6416, ++0x75E46513, 0x66536712, 0x1F4C7604, 0x64521F7D, ++0xD75F6E66, 0x27E0D25F, 0xDE5F6062, 0xC9013245, ++0x65622E00, 0x4609060A, 0x4609D15C, 0x46094509, ++0x21501F4E, 0xB2B0646D, 0x620D1F6F, 0x8B012228, ++0x0009A1EA, 0xD756DE55, 0x661C61E0, 0x6410D150, ++0x470B654C, 0x7FFC54FF, 0x2FE25EFE, 0x51FE7FFC, ++0x2F12E040, 0x55FBD14F, 0x57FD56FC, 0x04FE410B, ++0xD24D7F08, 0xE11C640D, 0x1D412D10, 0xD44B6522, ++0x67421D52, 0x1D73DE4A, 0xD24A65E2, 0x67221D54, ++0x1D75D249, 0xD2496E22, 0x66221DE6, 0x1D67A1BC, ++0x89018830, 0x0009A08E, 0xE340D538, 0x33FC6156, ++0x23126456, 0x71046153, 0x67521341, 0x13726416, ++0x7EE46E13, 0x65E66212, 0x66E3D731, 0x13246EE2, ++0x760427E0, 0x6062D22F, 0x3255DE2F, 0x2E00C901, ++0x060A6E62, 0xD12D4609, 0x4E094609, 0x13434609, ++0x646D21E0, 0xB2501F5E, 0x620D1F6F, 0x8B012228, ++0x0009A18A, 0xDE25D522, 0x61E06450, 0xD724654C, ++0x470B54FF, 0x7FFC661C, 0x06FEE054, 0x7FFC2F62, ++0xEE4001FE, 0x2F123EFC, 0x55E2D125, 0x57E456E3, ++0x64E2410B, 0xD21C7F08, 0xE11C640D, 0x1D412D10, ++0xD61A6522, 0x67621D52, 0x1D73DE19, 0xD2196EE2, ++0x62221DE4, 0xD2181D25, 0x1D266222, 0x6222D217, ++0x1D27A15A, 0x00117800, 0x00202A18, 0x00203996, ++0x002035BC, 0x00203A7C, 0x002018D0, 0x00203995, ++0x00117804, 0x00203A14, 0x00203A16, 0x00117810, ++0x00203991, 0x10624DD3, 0x00203992, 0x00203993, ++0x00114AA4, 0x00200F68, 0x001C5864, 0x001C6864, ++0x001C7864, 0x001C59BC, 0x001C69BC, 0x001C79BC, ++0x00200FC0, 0x8B048833, 0x470BD7A2, 0xA123EE00, ++0x88282DE0, 0xA0D38901, 0xDE9F0009, 0x62E1E143, ++0x3216E054, 0x0FE68F02, 0x2E21E240, 0x622D62E1, ++0x8B013217, 0x0009A0BC, 0xE50185E1, 0x8B013056, ++0x0009A0B6, 0x2D10E101, 0x64E1B111, 0x06FEE054, ++0x6261E143, 0x3517652D, 0xE6408945, 0x8B0C3563, ++0xE058E41A, 0xE5000F45, 0x72C0E05C, 0x60230F55, ++0x6703C907, 0xA014E060, 0x66530F75, 0x46214621, ++0x46214621, 0x45214621, 0xE0587618, 0x0F654521, ++0xE0034521, 0xE05C2509, 0xE0070F55, 0xE0602209, ++0xE8540F25, 0x858238FC, 0x640D65F3, 0x1844B170, ++0xDD7A8584, 0x85866C0D, 0x610D4C08, 0x410860C3, ++0xE00F0EFE, 0x18154D0B, 0x2E296207, 0x668260C3, ++0x85620FE6, 0x4D0B5185, 0x2E0B600D, 0x548460C3, ++0xB13C0FE6, 0xE05465F3, 0xE5400EFE, 0xE06C62E1, ++0x3653662D, 0x0F668D41, 0xC9036023, 0x40004008, ++0x61036403, 0xD965E070, 0x0F46E5FF, 0xE074655C, ++0x60530F96, 0x6263490B, 0x42214221, 0x42214221, ++0x42006723, 0x4200327C, 0x6C074621, 0x4621E054, ++0x606309FE, 0x4008C903, 0x790630FC, 0x6A036D2D, ++0x65F3E800, 0x64D3B124, 0xE0706EA2, 0x2AE22EC9, ++0x01FE6694, 0x666CE074, 0x470B07FE, 0x2E0B6063, ++0x65F32AE2, 0xB0FA64D3, 0x628D7801, 0x32E3EE06, ++0x7D018FE7, 0x0EFEE054, 0xE05462E1, 0x420006FE, ++0x760C8561, 0x701B302C, 0xE4006103, 0xE70465F3, ++0x68667401, 0x3973694D, 0x8FF92582, 0x65F37504, ++0x641DB0DD, 0x0EFEE054, 0x64E1B09C, 0x0009A054, ++0xD43B56F8, 0xEA01D23B, 0x26A0420B, 0x0009A04C, ++0x06FCE01C, 0x8829606C, 0x5CF88B08, 0xE200D636, ++0x52612C20, 0x642DB04B, 0x0009A03E, 0x666CE681, ++0x8B043060, 0x420BD231, 0xA03554F8, 0xE6820009, ++0x3060666C, 0xD22E8B04, 0x54F8420B, 0x0009A02C, ++0x666CE683, 0x8B0A3060, 0xDA2755F8, 0x2590E900, ++0xD82855A1, 0x2852D628, 0xA01D52A2, 0xE6922620, ++0x3060666C, 0xD2208B08, 0x5C21D824, 0x6CCC52F8, ++0x28C1E600, 0x2260A010, 0x666CE693, 0x8B063060, ++0xD61F59F8, 0xE201EA00, 0xA00529A0, 0xD6162621, ++0xD21DD41C, 0x6562420B, 0x4F067F78, 0x4F264F16, ++0x6DF66EF6, 0x6AF66CF6, 0x000B69F6, 0x4F2268F6, ++0xE240614D, 0x89323123, 0x3127E21F, 0x8B27D713, ++0xD406614D, 0xE00171E0, 0x5671440B, 0x26596507, ++0x1761A025, 0x00200FBC, 0x00117804, 0x00203470, ++0x00203A9C, 0x002018C0, 0x00117800, 0x00115F00, ++0x00116058, 0x0020397C, 0x00203990, 0x00203A1A, ++0x00203A16, 0x00203AB4, 0x002018D0, 0x001C3704, ++0xE001D490, 0x6672440B, 0x26596507, 0x4F262762, ++0x0009000B, 0x614D4F22, 0x3123E240, 0xE21F8912, ++0xD7893127, 0x614D8B08, 0x5671D286, 0x420B71E0, ++0x260BE001, 0x1761A006, 0x6672D282, 0xE001420B, ++0x2762260B, 0x000B4F26, 0xE6400009, 0x46284618, ++0x6252D57E, 0x89FC2268, 0x0009000B, 0x4618E680, ++0xD57A4628, 0x22686252, 0x000B89FC, 0xA0010009, ++0x7201E200, 0x8BFC3242, 0x0009000B, 0x4618E680, ++0xD5734628, 0x22686252, 0x000B8BFC, 0x2FE60009, ++0x7FFC4F22, 0xBFF16E53, 0x61E22F42, 0xE280D66D, ++0x54E11615, 0x16464218, 0x422855E2, 0x57E31657, ++0x16786EF2, 0x26E22E2B, 0x4F267F04, 0x6EF6AFCE, ++0x2FD62FC6, 0x4F222FE6, 0x6C53DD62, 0x6E43BFD6, ++0x2DE2BFBB, 0x0009BFD2, 0x2C1251D5, 0x1C4154D6, ++0x1C5255D7, 0x1C6356D8, 0x6EF64F26, 0x000B6DF6, ++0x61636CF6, 0xA004E600, 0x62564109, 0x24227601, ++0x36127404, 0x000B8BF9, 0xD6530009, 0x8562E500, ++0xA00B674D, 0x655D610D, 0x40006053, 0x305CD44F, ++0x024D4008, 0x3270622D, 0x75018905, 0x3213625D, ++0x000B8BF1, 0x000BE000, 0x2FE6E001, 0x54416743, ++0x4E08EE7F, 0x4E28D246, 0x25E96543, 0x60436E21, ++0x9E7562ED, 0x4529C903, 0xE60032E3, 0x8D456103, ++0x21184509, 0xD23F8B05, 0x002C6053, 0xA08AC93F, ++0x60136603, 0x8B268801, 0x880C6053, 0xD53A8B04, ++0xC93F8453, 0x6603A07F, 0x8B048808, 0x84E2DE36, ++0xA078C93F, 0x880D6603, 0x8B03D633, 0xC93F8461, ++0x6603A071, 0x88096260, 0x622C8F09, 0xE014DE2C, ++0x655C05EC, 0x60233258, 0xA064C93F, 0x60236603, ++0xA060C93F, 0x88026603, 0xE0078B5D, 0x60432509, ++0x8905C810, 0x6053D225, 0xC93F002C, 0x6603A053, ++0x6053DE23, 0xC93F00EC, 0x6603A04D, 0x88016013, ++0x60538B19, 0x8B04880C, 0x8423D21E, 0xA042C93F, ++0x88086603, 0xD51B8B04, 0xC93F8452, 0x6603A03B, ++0xD618880D, 0x84618B03, 0xA034C93F, 0x60606603, ++0xA030C93F, 0x88026603, 0xE0078B2D, 0x60432509, ++0x8923C810, 0x6053DE10, 0xC93F00EC, 0x6603A023, ++0x00000BB8, 0x00203470, 0x001C3704, 0x001C373C, ++0x001C3700, 0x001C370C, 0x00114000, 0x00114008, ++0x001142D8, 0x001142E4, 0x001142E8, 0x001142F5, ++0x001142ED, 0x001142FD, 0x00114309, 0x6053D209, ++0xC93F002C, 0x60136603, 0x8B038802, 0xC8106043, ++0x76028900, 0xC93F6063, 0x40004018, 0x1741240B, ++0x6EF6000B, 0x00114301, 0x0009A16E, 0x2FE62FD6, ++0xDD944F22, 0xA0049EB2, 0xD4930009, 0x420BD293, ++0x62D265D2, 0x8BF822E8, 0x0009A004, 0xD28FD490, ++0x55D1420B, 0x22E852D1, 0xA0048BF8, 0xD48D0009, ++0x420BD28A, 0x52D255D2, 0x8BF822E8, 0x0009A004, ++0xD286D489, 0x55D3420B, 0x22E852D3, 0xA0048BF8, ++0xD4860009, 0x420BD281, 0x52D455D4, 0x8BF822E8, ++0x6EF64F26, 0x6DF6000B, 0x2FD62FC6, 0x4F222FE6, ++0x6E636C73, 0x6D53B01A, 0x64D357F4, 0xB05F65E3, ++0xB07566C3, 0xB0A40009, 0xB0A80009, 0xB0AC0009, ++0xB0AC0009, 0xB0AF0009, 0xB03154F5, 0x6CCD6C03, ++0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, 0x3412D170, ++0xD6700529, 0x2650D770, 0x2742000B, 0x0009A018, ++0x2FD62FC6, 0x4F222FE6, 0x6E636C73, 0x6D53BFEE, ++0x64D357F4, 0xB03365E3, 0xB08D66C3, 0xB00F54F5, ++0x6CCD6C03, 0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, ++0xE503D162, 0xD763D462, 0x21524518, 0x2472000B, ++0xD45FD15E, 0x2162E600, 0x2462000B, 0xBF734F22, ++0xBF73E40A, 0xD25C0009, 0x4118E104, 0xE40AE500, ++0xBF692212, 0xD7592252, 0xCB206072, 0x000B4F26, ++0x4F222702, 0x410BD156, 0xD556E400, 0x4F26452B, ++0xD1552FE6, 0x66126E63, 0x92104418, 0x44084528, ++0x45002629, 0x265B4408, 0x264B4400, 0x21624708, ++0xD14E4708, 0x217227EB, 0x6EF6000B, 0x1FFF03F0, ++0x4F222FE6, 0xE101DE4A, 0xBF3DE40A, 0x67E32E12, ++0xE500776C, 0xE204E130, 0x2752E40A, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27222712, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x175ABF18, 0x2E62E600, 0x000B4F26, ++0xD2346EF6, 0xE441E101, 0x000B2212, 0xD1322242, ++0xE605D432, 0x000B2162, 0x000B2462, 0xD2300009, ++0xE40AE601, 0x2262AF00, 0x2FC62FB6, 0x2FE62FD6, ++0x7FFC4F22, 0x6C43DB2B, 0xED0060B2, 0x2B02CB03, ++0xC90360B2, 0x6E03A008, 0x89073DC2, 0xE46460B2, ++0xB07CC903, 0x7D016E03, 0x8BF52EE8, 0x8F043DC2, ++0xD4212FE1, 0x460BD621, 0x62F10009, 0x6023622D, ++0x89FFC801, 0x7F046023, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x001C3B88, 0x00203AC8, 0x002018D0, ++0x00203AD0, 0x00203AD8, 0x00203AE0, 0x00203AE8, ++0x0025E720, 0x00203DBC, 0x00203980, 0x001C5968, ++0x001C3B40, 0x000F8000, 0x001D4004, 0x001C3500, ++0x002015E4, 0x00201610, 0x001C5814, 0x001C59D0, ++0x001C5830, 0x001C6268, 0x001C59A4, 0x001C639C, ++0x001C581C, 0x001C5860, 0x00203AF0, 0x002018C0, ++0x8F014411, 0x6043604B, 0x0009000B, 0x5651D52B, ++0x46286052, 0x306C000B, 0x2FC62FB6, 0x2FE62FD6, ++0x4F124F22, 0xBFF14F02, 0x6B036E43, 0xDD25DC24, ++0x0009BFEC, 0x3C0530B8, 0x4609060A, 0x46014609, ++0x020A3D65, 0x42094209, 0x32E24209, 0x4F068BF0, ++0x4F264F16, 0x6DF66EF6, 0x000B6CF6, 0x2FC66BF6, ++0x2FE62FD6, 0x4F124F22, 0xBFCF4F02, 0x6C036E43, ++0xBFCBDD13, 0x30C80009, 0x060A3D05, 0x46094609, ++0x36E24601, 0x4F068BF5, 0x4F264F16, 0x6DF66EF6, ++0x6CF6000B, 0x4F222FE6, 0xE102DE0B, 0xE403E500, ++0xBFB92E12, 0xE6062E52, 0xE7004618, 0x2E62E403, ++0x4F262E72, 0x6EF6AFB0, 0x0009000B, 0x001C1040, ++0xCCCCCCCD, 0x10624DD3, 0x001D4004, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0xE5007F98, ++0x6453E710, 0x6B534728, 0xEE1ADCBC, 0x6153655D, ++0x315C4108, 0x75014108, 0x6043317C, 0x0F16665D, ++0xED0060B3, 0x21B136E3, 0x81128111, 0x11D28113, ++0x11D411D3, 0x74048FEA, 0xD8B167F2, 0x1871D9B1, ++0x58F12872, 0x1981D1B0, 0x59F22982, 0x5DF45AF3, ++0x54F65EF5, 0x21921191, 0x11A211A3, 0x11D411D5, ++0x11E611E7, 0x11481149, 0xDAA855F7, 0x57F8EE00, ++0x52F9DDA7, 0x64E3D6A7, 0x2A521A51, 0xD8A7D9A6, ++0x2D72EAEF, 0x6AAC2622, 0x6DE36EED, 0x61E34D08, ++0x41083DEC, 0x31EC4D08, 0x60B33D9C, 0x2DB14108, ++0xE05081D1, 0xE79F4108, 0x41084008, 0x81D2677C, ++0x318C60B3, 0x3472E200, 0x1DD281D3, 0xD4931D13, ++0x1D248D01, 0x65D3D48F, 0x7E01B0B2, 0x34A264ED, ++0xDA8C8BDA, 0x68A22FD2, 0x4829DD91, 0x64A22D82, ++0x694D7DFC, 0x2D92D286, 0x4E296E22, 0x2DE27D0C, ++0x6AD36822, 0xD784618D, 0x6D722A16, 0xD583D489, ++0x5E7224D2, 0x14E2D688, 0xEE005174, 0x58761414, ++0x1486D186, 0xE7105978, 0x62521498, 0x142A65E3, ++0x64E326E2, 0x644DE600, 0x48086843, 0x4808384C, ++0x6053381C, 0x28B10C86, 0x60B309CE, 0x60538191, ++0x60430ACE, 0x605381A2, 0x60B30DCE, 0x605381D3, ++0x740108CE, 0x09CE1882, 0x19E3624D, 0x32730ACE, ++0x8FE01A64, 0xD96A7504, 0x6C92E003, 0x2CB14018, ++0xDA6F6D92, 0xE05081D1, 0x40086E92, 0x619281E2, ++0x811360B3, 0xE6006492, 0x67921442, 0x17A3D468, ++0xE1FF6892, 0xE7031864, 0x46086563, 0x7501364C, ++0x665D2612, 0x8BF83673, 0xE003DC5A, 0x40186DC2, ++0x6EC22DB1, 0x81E1D25F, 0xEE0061C2, 0x64C21112, ++0x1423E024, 0xD45B65C2, 0x67C215E4, 0x8172E580, ++0x66E368C2, 0x655C8183, 0x6963666D, 0x6A6D7604, ++0x3A53394C, 0x29E28FF8, 0xDC54DB53, 0x740424B2, ++0x7F6824C2, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0x614268F6, 0xC8036011, 0xE5008F03, ++0x3420D23C, 0x60118B06, 0x8802C903, 0xD2398B06, ++0x8B033420, 0x65135612, 0x24225264, 0x6053000B, ++0x2FE62FD6, 0x7FEC4F22, 0x62536E53, 0x6D43E550, ++0x4508E400, 0xE101A001, 0x60435224, 0x81212211, ++0x60538123, 0x56E28122, 0x8BF53620, 0x16E4D238, ++0xE61464F3, 0x65E3420B, 0xE4FC65E1, 0x2E512549, ++0x65F361F1, 0x2F112149, 0xD13154D1, 0xE614410B, ++0x607157D1, 0x2701CB01, 0x7F141DE1, 0x6EF64F26, ++0x6DF6000B, 0x2FE62FD6, 0x7FEC4F22, 0x66536E53, ++0x6D43E5FC, 0x20596061, 0x2601CB01, 0x326052E2, ++0x12E48B06, 0x31E051E2, 0x52D18B04, 0x1E22A002, ++0x5664AFF0, 0x64F3D21E, 0x420BE614, 0x67E165E3, ++0x2719E1FC, 0x67F12E71, 0x271954D1, 0x65F3D118, ++0x410BE614, 0x52D12F71, 0xCB016021, 0x1DE12201, ++0x4F267F14, 0x000B6EF6, 0x00006DF6, 0x002039AC, ++0x0020357C, 0x00203584, 0x0020358C, 0x002035B4, ++0x00203998, 0x002039A0, 0x00100208, 0x001014C0, ++0x001E210C, 0x001C3D00, 0x002039EC, 0x001000C8, ++0x00117880, 0x00117780, 0x00040020, 0x0026C401, ++0x00200D42, 0x4F222FE6, 0xDE42624C, 0x42004208, ++0x3E2CA005, 0xD4405252, 0xBF695624, 0x65E22E62, ++0x352052E1, 0xD63D8BF6, 0x4F262622, 0x6EF6000B, ++0x2FC62FB6, 0x2FE62FD6, 0xDC394F22, 0x52C1DB39, ++0x362066C2, 0x6061891C, 0x8801C903, 0xDE348918, ++0xBF38DD35, 0x650364E3, 0x66B28503, 0x3262620D, ++0xD4328907, 0x0009BF76, 0x4D0BD431, 0xAFE60009, ++0xBF3D0009, 0xD42F64E3, 0x00094D0B, 0x0009AFDF, ++0x2262D22D, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x2FD62FC6, 0x4F222FE6, 0xDD29DC28, 0x6E4360C2, ++0x04DE4008, 0xE614D127, 0x65E3410B, 0xD127D726, ++0x55E227E2, 0x35E05254, 0x21228F04, 0x400860C2, ++0x122202DE, 0x605365C2, 0x75014008, 0x0DE606DE, ++0xC90F6053, 0x60632C02, 0x6EF64F26, 0x000B6DF6, ++0x85436CF6, 0x650D5643, 0x622D6262, 0x35277204, ++0xE1008F0C, 0x2268960C, 0xD6158B03, 0x72015261, ++0xD6131621, 0x6262E101, 0x26227201, 0x6013000B, ++0x000001FF, 0x0020358C, 0x00203584, 0x001C3D00, ++0x002035B4, 0x0020397C, 0x002018C0, 0x0020357C, ++0x00203B18, 0x00203B1C, 0x001C3D28, 0x002039EC, ++0x002039AC, 0x00200D42, 0x002039F0, 0x002039F4, ++0x00117754, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x7FF84F22, 0x6C22D241, 0xC80360C3, 0xDE40896E, ++0xDA41DB40, 0x52B1D941, 0x362066B2, 0x60618945, ++0x8801C903, 0xDD3B8941, 0x420BD23D, 0x650364D3, ++0x60A12F02, 0x89328801, 0x85145153, 0x8840600C, ++0x1F118F0C, 0xD5376191, 0x641D450B, 0x8B262008, ++0xD7356691, 0x646D470B, 0x8B202008, 0x420BD233, ++0x51F154F1, 0xC8208511, 0xD1318904, 0x021EE050, ++0x01267201, 0x420BD22F, 0x200864F2, 0x64D38907, ++0x4D0BDD2D, 0xD12D65F2, 0xAFC4E601, 0xD22C2162, ++0x420B65F2, 0xD72B64E3, 0xAFBCE601, 0xD2262762, ++0x420B65F2, 0xAFB664D3, 0xDE270009, 0xDA28DD27, ++0x52D1DB28, 0x362066D2, 0x60618918, 0x8801C903, ++0xD4228914, 0x450BD516, 0x56030009, 0x8F0436E0, ++0xE2016503, 0xAFEC2A20, 0xD41F2B52, 0x420BD216, ++0xD7180009, 0x4118E101, 0x2712AFE3, 0xC80460C3, ++0xD21A8902, 0x0009420B, 0x4F267F08, 0x6DF66EF6, ++0x6BF66CF6, 0x000B6AF6, 0x000069F6, 0x001E2100, ++0x0020358C, 0x00203584, 0x00203A14, 0x001142D8, ++0x002014A6, 0x00115EA2, 0x00114774, 0x00200D8A, ++0x0020351C, 0x002016C2, 0x002014D0, 0x001E212C, ++0x00201534, 0x001C3D30, 0x00117880, 0x0020357C, ++0x0020399C, 0x00203998, 0x002035B4, 0x00200644, ++0xE601D203, 0x1265D503, 0x000B2252, 0x00001266, ++0x001C1010, 0x0000C34F, 0x0009000B, 0x0009000B, ++0x0009000B, 0x0009000B, 0xE000000B, 0xE000000B, ++0x0009000B, 0xE4FDD59D, 0xD69D6152, 0x25122149, ++0x74016052, 0x2502CB01, 0xD19A6752, 0x25722749, ++0xC8406010, 0x60628902, 0x2602CB04, 0xE1F76462, ++0x26422419, 0xE7016062, 0x2602C9CF, 0xE5026062, ++0x2602CB10, 0x47186062, 0x2602CB03, 0x000B1652, ++0xD58D1673, 0xD28ED78D, 0xE100D48E, 0x2511E600, ++0x22102711, 0x2461AFCE, 0xD28B664C, 0x362C4600, ++0xCB106060, 0x2600000B, 0xD287654C, 0x352C4500, ++0xE1EF6650, 0x000B2619, 0x664C2560, 0x4600D283, ++0x6060362C, 0x000BCB10, 0x654C2600, 0x4500D27F, ++0x6650352C, 0x2619E1EF, 0x2560000B, 0xD27A664C, ++0x362C4600, 0xCB086060, 0x2600000B, 0xD276654C, ++0x352C4500, 0xE1F76650, 0x000B2619, 0x664C2560, ++0x4600D272, 0x6060362C, 0x000BCB08, 0x654C2600, ++0x4500D26E, 0x6650352C, 0x2619E1F7, 0x2560000B, ++0xD669624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0x624C600C, 0x4200D664, 0x6020326C, ++0x4021C908, 0x40214021, 0x600C000B, 0x644CD160, ++0x6240341C, 0x602C000B, 0x644CD15E, 0x6240341C, ++0x602C000B, 0x4F222FE6, 0x645C6E43, 0x3467E60A, ++0xBFEB8914, 0x640C0009, 0x880160EC, 0xE00F8B02, ++0x2409A002, 0x44094409, 0xE60A624C, 0x89053263, ++0x644CBFE2, 0x6023620C, 0x8B00C880, 0x6023E200, ++0x000B4F26, 0x4F226EF6, 0x6062D64B, 0x8B038801, ++0x0009B256, 0x0009A003, 0xE640D248, 0xD6482260, ++0x4F26E200, 0x2622000B, 0xD6434F22, 0x88026062, ++0xB29F8B01, 0xD6420009, 0x4F26E200, 0x2622000B, ++0xD43ED53D, 0xE701E100, 0x000B2512, 0xD23B2470, ++0x000BE604, 0x4F222260, 0xD13BD43A, 0x0009410B, ++0xE1FDD53A, 0xD23A6650, 0xE7002619, 0x4F262560, ++0x2270000B, 0xD5374F22, 0x6152D237, 0x611DD737, ++0x64522512, 0x242BE6FF, 0xD4352542, 0x666DD22E, ++0x2762420B, 0xE1FBD52D, 0x27196750, 0x000B4F26, ++0x4F222570, 0xD128D42F, 0x0009410B, 0xE7F7D527, ++0x26796650, 0x000B4F26, 0xD5242560, 0x62509425, ++0x000B2249, 0xD5212520, 0x6250E4BF, 0x000B2249, ++0x4F222520, 0x8522D224, 0x2008600D, 0x88018911, ++0x88038944, 0x88058946, 0x88068948, 0x8808894E, ++0x88098954, 0x880A895A, 0x880B8960, 0xA06D8966, ++0xB06F0009, 0xA06A0009, 0xFF7F600C, 0x001E2148, ++0x001E1108, 0x001E1000, 0x00203A4C, 0x00203A4E, ++0x00203A6D, 0x00203A30, 0x001E103F, 0x001E105F, ++0x001E102F, 0x001E1090, 0x00203A54, 0x001E100B, ++0x00203A50, 0x00203B20, 0x002018C0, 0x001E1028, ++0x00203A6C, 0x001D4020, 0x98760000, 0x001C1000, ++0x00203B2C, 0x00203B3C, 0x00203A24, 0x0009B04C, ++0x600CA035, 0x0009B055, 0x600CA031, 0x6260D684, ++0x8B2B2228, 0x0009B061, 0x600CA029, 0x6260D680, ++0x8B232228, 0x0009B069, 0x600CA021, 0x6260D67C, ++0x8B1B2228, 0x0009B0C7, 0x600CA019, 0x6260D678, ++0x8B132228, 0x0009B0CD, 0x600CA011, 0x6260D674, ++0x8B0B2228, 0x0009B125, 0x600CA009, 0x6260D670, ++0x8B032228, 0x0009B13D, 0x600CA001, 0x4F26E000, ++0x0009000B, 0xD26CD16B, 0xD56C8412, 0x4000C90F, ++0xD76B012D, 0xE403D66B, 0xE20F611C, 0x2540E001, ++0x25202712, 0x2602000B, 0xE601D262, 0x30668523, ++0xE0008D05, 0xD663D260, 0xE0018122, 0x000B2602, ++0xD25C0009, 0x600D8523, 0x89052008, 0x8B0A8801, ++0x6060D65D, 0x2600CB01, 0xD457D65A, 0xE001E101, ++0x000B2612, 0x000B8142, 0xD152E000, 0x8513E501, ++0x640D4518, 0x66033453, 0xE0008D05, 0xD551D253, ++0x2260E001, 0x000B2502, 0x4F220009, 0x8513D149, ++0x6453650D, 0x62494419, 0x227D672E, 0x8801602C, ++0x88028909, 0x88038910, 0x8806891A, 0x88078935, ++0xA04C893B, 0xD5460009, 0x6652D746, 0x2762D446, ++0x622C6261, 0x2421A038, 0x2228625C, 0xD4438B3F, ++0x6642D540, 0x2562D440, 0x24018561, 0x6203A02C, ++0x2008605C, 0x88108907, 0x88208908, 0x88308909, ++0xA02C890A, 0xD23A0009, 0x6222A008, 0xA005D239, ++0xD2396222, 0x6222A002, 0x6262D638, 0xD432D531, ++0x66212522, 0xA00F626C, 0xD6352421, 0x6261D52D, ++0x622CD42D, 0xA0072562, 0xD6322421, 0x8561D529, ++0x2562D429, 0x62032401, 0x662D8515, 0x3617610D, ++0x65038F01, 0xB0CB2451, 0xA0010009, 0xE000E001, ++0x000B4F26, 0xD6190009, 0xD427E101, 0x65412610, ++0xD118D717, 0xE20F655D, 0x2752E001, 0x000B2620, ++0x2FE62102, 0xD20F4F22, 0x640C8523, 0x8B082448, ++0xD511D61D, 0x2621E200, 0x940F8451, 0xA0482049, ++0xDE0D8051, 0xC84060E0, 0xE2018D32, 0x89443427, ++0xD216D615, 0x2641420B, 0x0009A030, 0x0000FF7F, ++0x00203A6D, 0x00203A24, 0x00203A30, 0x001E1100, ++0x001E100C, 0x00203A50, 0x001E1000, 0x001E1001, ++0x00203A58, 0x00203A38, 0x00203A3C, 0x00203A40, ++0x00203A5C, 0x00203A60, 0x00203A64, 0x00203A68, ++0x00203E20, 0x00203E2A, 0x00203A4A, 0x002027F2, ++0x89123427, 0xD294D693, 0x2641420B, 0xCB8084E1, ++0x80E1B0F5, 0xD69160E0, 0x2E00CB04, 0xC93F6060, ++0xD68F2600, 0xA001E001, 0xE0002602, 0x000B4F26, ++0xD68C6EF6, 0xC8806060, 0xD2868919, 0x88016021, ++0xD2898B15, 0x8524E501, 0x89103056, 0xE203D187, ++0x2120D487, 0xE00B6541, 0x0656655D, 0xE40FD585, ++0x2140E702, 0xD77E2571, 0x000BE001, 0x000B2702, ++0x2FE6E000, 0xDE804F22, 0xC88084E1, 0xD57A892C, ++0x20088554, 0x61038F28, 0x8553D77C, 0x64036672, ++0x8566650C, 0x3520620C, 0xD6798B1E, 0x651CD774, ++0x2651644C, 0x60E02741, 0x8904C840, 0x420BD275, ++0xA0030009, 0xD2680009, 0x0009420B, 0x0009B09F, ++0xE201D167, 0x60E02122, 0xCB04D464, 0x60402E00, ++0x2400C93F, 0x6023A001, 0x4F26E000, 0x6EF6000B, ++0x2FB62FA6, 0x2FD62FC6, 0xDA622FE6, 0x66A1E240, ++0x3622DC5E, 0x62638900, 0x6ED36D2C, 0x4E2136D8, ++0x4E212A61, 0xDB61D460, 0xE700A00F, 0x770162B2, ++0x71026123, 0x66212B12, 0x71026213, 0x61212B12, ++0x651D666D, 0x356C4528, 0x627C2452, 0x8BED32E3, ++0xC90360D3, 0x8B108803, 0x617367B2, 0x2B127102, ++0x71026E13, 0x2B126571, 0x655D6DE1, 0x422862DD, ++0x325CE107, 0xA00C2C10, 0x88022422, 0xA0038B01, ++0x8801E203, 0xE2018B05, 0x66B22C20, 0x655D6561, ++0xE60F2452, 0x67A12C60, 0x8B052778, 0xDD38DC44, ++0xEB01EA00, 0x2DB22CA2, 0x6DF66EF6, 0x6BF66CF6, ++0x6AF6000B, 0x2FE62FD6, 0xE240DD36, 0x362266D1, ++0x62638900, 0x3678672C, 0x7703DE38, 0x47212D61, ++0x64E2D635, 0xA00E4721, 0x6562E100, 0x62537101, ++0x74012450, 0x24204219, 0x45297401, 0x74012450, ++0x24504519, 0x621C7401, 0x8BEE3273, 0x66E24200, ++0x420061D1, 0x2118362C, 0x2E628F06, 0xDD1CD728, ++0xE501E400, 0x2D522742, 0x000B6EF6, 0x2FD66DF6, ++0x4F222FE6, 0xED0AEE01, 0x64E3BC86, 0xBC8B64E3, ++0x62EC7E01, 0x8BF732D7, 0xBC8EEE01, 0x64E364E3, ++0x7E01BC93, 0x32D762EC, 0x4F268BF7, 0x000B6EF6, ++0xD1186DF6, 0xD418920D, 0x72122122, 0x2422D617, ++0xD7177204, 0x72202622, 0x2722D116, 0x000B7230, ++0x137A2122, 0x00203A4A, 0x002028FE, 0x001E1015, ++0x00203A50, 0x001E1001, 0x00203A24, 0x001E1100, ++0x00203A4E, 0x00203A3C, 0x001E1000, 0x00203A40, ++0x00203A4C, 0x002027F2, 0x001E100C, 0x00203A38, ++0x00203A54, 0x00203A58, 0x00203A5C, 0x00203A60, ++0x00203A64, 0x00203A68, 0x4F222FE6, 0xD6707FFC, ++0x88016060, 0xE2018951, 0x2620BFBB, 0xD56ED16D, ++0xDE6E6010, 0x64E36552, 0x7402C840, 0x8D22D16C, ++0xD26C7502, 0xE601D76C, 0xE7042722, 0x76016255, ++0x626C2421, 0x8FF93273, 0xD4637402, 0x6242E601, ++0x640D8528, 0x67494419, 0x275D657E, 0x81E4607C, ++0xE417D562, 0x67557601, 0x3243626C, 0x8FF92171, ++0xA0207102, 0xD25E0009, 0xE601D75B, 0xE7042722, ++0x76016255, 0x626C2421, 0x8FF93273, 0xD4527402, ++0x6242E601, 0x640D8528, 0x67494419, 0x275D657E, ++0x81E4607C, 0xE417D553, 0x67557601, 0x3243626C, ++0x8FF92171, 0x92897102, 0xD2462E21, 0x5E23D74E, ++0x64F22FE2, 0x604365F2, 0x2700C980, 0xC9606043, ++0x80716103, 0xC9036043, 0x80724519, 0x65F2605C, ++0x817266F2, 0x46194629, 0x606C4529, 0x4018645C, ++0x8173304C, 0x21185E23, 0x64F22FE2, 0x6E4C62F2, ++0x602C4219, 0x66F262F2, 0x46294018, 0x461930EC, ++0x42298174, 0x652C606C, 0x305C4018, 0x81758F07, ++0x0009BC97, 0x2228620C, 0xA00A8908, 0x60130009, ++0x8B038840, 0x0009B009, 0x0009A003, 0xE202D62F, ++0x7F042622, 0x000B4F26, 0x4F226EF6, 0x8552D52A, ++0x8830600D, 0x88318903, 0xA0348923, 0x85550009, ++0xD428D727, 0x85532701, 0x610DD627, 0x24124118, ++0x460BD426, 0xD7230009, 0xD226D425, 0x6572420B, ++0xE230D120, 0x42286712, 0x2729E620, 0x37604628, ++0xD6218B03, 0xA016E200, 0xD61F2622, 0xA012E202, ++0xD1182622, 0x6212E530, 0xE6204528, 0x46282259, ++0x89083260, 0xD41AD119, 0xE601D513, 0x2160450B, ++0x472BD718, 0x4F264F26, 0x0009000B, 0x0000060A, ++0x00203A6C, 0x001E1000, 0x00203A58, 0x00203E20, ++0x00203E2C, 0x00203DC4, 0x00203A40, 0x00203DF4, ++0x00203DF2, 0x00203DC6, 0x00203A24, 0x00203A50, ++0x00203A3C, 0x00203A38, 0x002018C0, 0x00203B48, ++0x00203B4C, 0x002018D0, 0x00203A54, 0x001E100B, ++0x00203B60, 0x00114004, 0x4F222FE6, 0x84E9DE86, ++0x2448640C, 0xB17B8901, 0xD2840009, 0x26686620, ++0x60E08902, 0x2E00C9BF, 0x000B4F26, 0x000B6EF6, ++0x2FE60009, 0xDE7E4F22, 0x60E0D67E, 0xCBC0D47E, ++0x62602E00, 0xC803602C, 0x40218904, 0x70014021, ++0x6603A002, 0x66034009, 0xD678616D, 0xE500A004, ++0x75016262, 0x74042422, 0x3213625D, 0xD2748BF8, ++0x0009420B, 0xC9BF84E2, 0x4F2680E2, 0x6EF6000B, ++0x2FE62FD6, 0x7FFC4F22, 0x6260D66E, 0x89402228, ++0xD565E100, 0x60502610, 0xCB40D46B, 0x2500440B, ++0x8D052008, 0x62E06E03, 0x7104612C, 0x2F11A006, ++0xD466D65E, 0xDD666760, 0x657C4D0B, 0xE23C6D1D, ++0x8B033D27, 0xD264D463, 0x0009420B, 0x4D214D21, ++0xA005D762, 0x66E6E400, 0x357C4508, 0x74012562, ++0x35D3654D, 0xD75E8BF7, 0x6E72E003, 0x81E14018, ++0x6E7260F1, 0x81E2700C, 0xD45A6172, 0xDD5A8113, ++0x65724D0B, 0xD64AD259, 0x2212E101, 0xC93F6060, ++0x7F042600, 0x6EF64F26, 0x6DF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xD2524F22, 0x6B436E73, 0x420B6C53, ++0x20086D63, 0x64038D1C, 0xE50ED13C, 0x32526210, ++0x60C38916, 0x804124B0, 0x814160D3, 0xA007E500, ++0x655D61BC, 0x00EC6053, 0x364C6653, 0x80647501, ++0x3213625D, 0xD6308BF5, 0xC9BF6060, 0x2600A008, ++0xD239D440, 0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0xE1007FC4, ++0x6513ECFF, 0x6B136CCD, 0xDE34D733, 0xEDFF64F3, ++0xD833EA04, 0x6053655C, 0x027D4000, 0x32C0622D, ++0x66038D0D, 0x09ED6063, 0x2491027D, 0x24217402, ++0x698202ED, 0x3928622D, 0x74022892, 0x75017104, ++0x6063625C, 0x07D532A2, 0x0EB58FE4, 0x2448641C, ++0xE6808905, 0x67F3E5C5, 0xBF8F666C, 0x7F3C655C, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0xD11C68F6, 0x6012D21C, 0xCB20E405, 0x2102E500, ++0x000B2242, 0x00002252, 0x001E1017, 0x00203996, ++0x001E1015, 0x001E10BF, 0x00117800, 0x001E10FC, ++0x00200644, 0x0020399C, 0x00202A56, 0x00203B64, ++0x002018D0, 0x00203B80, 0x002018C0, 0x0011788C, ++0x00203998, 0x0020357C, 0x00201534, 0x001E2130, ++0x00202A18, 0x00203B88, 0x002039FC, 0x00203A04, ++0x00203DC0, 0x001C3500, 0x001D4004, 0xD564D163, ++0xE400D764, 0x2142E20F, 0x17411154, 0xD5622722, ++0x9669D762, 0x15412572, 0x96661562, 0xE6011565, ++0xD55F1165, 0x666CE6F8, 0x25422542, 0x25422542, ++0x25422542, 0x25622542, 0x7601E727, 0x67632572, ++0x25627797, 0xE7042572, 0x2572E248, 0xE2192522, ++0xE2702522, 0x25422542, 0x25422542, 0x25222542, ++0x2522E20C, 0x25422542, 0x25422542, 0x25422542, ++0x25422542, 0x000B154A, 0xE2081145, 0x0009422B, ++0x2FE62FD6, 0x7FFC4F22, 0xC8206043, 0x6E438D02, ++0x0009BE85, 0xC81060E3, 0xBE828901, 0x60E30009, ++0x8901C840, 0x0009BEA4, 0xC80160E3, 0xDD3D8938, ++0xC80260D0, 0x2F008D03, 0x460BD63B, 0x60F00009, ++0x8902C804, 0x460BD639, 0x62F00009, 0xC8806023, ++0x60D08902, 0x2D00C97F, 0xC8016023, 0xD6348906, ++0x0009460B, 0x0009A007, 0x51630601, 0x8902C808, ++0x460BD630, 0x60F00009, 0x8902C810, 0x420BD22E, ++0xD52E0009, 0x88026052, 0xD22D8B03, 0xA005E604, ++0x88012260, 0xD22A8B02, 0x2260E601, 0x2522E200, ++0xC88060E3, 0xD227892D, 0x60E36E20, 0x8902C880, ++0x420BD225, 0x60E30009, 0x8902C840, 0x420BD223, ++0x60E30009, 0x8902C802, 0x420BD221, 0x60E30009, ++0x890DC804, 0xDD20D11F, 0x0009410B, 0x0009BF11, ++0x0009BF4C, 0xD51ED41D, 0x2470E708, 0x25D2BF85, ++0xC80860E3, 0xD21B8905, 0x4F267F04, 0x422B6EF6, ++0x7F046DF6, 0x6EF64F26, 0x6DF6000B, 0x001C581C, ++0xA000A000, 0x001D0100, 0x001D4000, 0x00040021, ++0x001C589C, 0x001E1021, 0x00201A46, 0x00201A68, ++0x002020C8, 0x00201A80, 0x00201A8E, 0x00203A50, ++0x001E100B, 0x001E1028, 0x00201AFA, 0x00201B06, ++0x00201A96, 0x00201AB4, 0x12345678, 0x001E1000, ++0x0010F100, 0x00201AE2, 0x644CD6A7, 0x000B346C, ++0xD6A62450, 0x346C644C, 0x2450000B, 0x644CD6A4, ++0x000B346C, 0x625C2450, 0x4208616D, 0x42084119, ++0x42006019, 0x670E614C, 0xD49E321C, 0x4200207D, ++0x324CC90F, 0x2200000B, 0x4208625C, 0x42004208, ++0x324C644C, 0x4200D498, 0x000B324C, 0x2FE62260, ++0x614C4F12, 0x4100D493, 0x6710314C, 0xE29F666D, ++0x27294619, 0x6E536269, 0x672E6573, 0x4221227D, ++0x42214221, 0x7601662C, 0xE4014608, 0x34E84608, ++0x644C4600, 0x071A0467, 0x2150257B, 0x000B4F16, ++0x4F226EF6, 0xD2857FE8, 0x88016021, 0xD2848B7B, ++0x26686621, 0xD2838B77, 0x26686621, 0xE50F8B73, ++0xE401BFA2, 0xBFA4E501, 0xE586E400, 0xE400655C, ++0x2F50BFA4, 0xBFA1E401, 0xE602E506, 0x60634618, ++0x81F2E401, 0x6543BF9F, 0xE40185F2, 0xBFAB6543, ++0x85F26603, 0x6543E401, 0x6603BFB1, 0xE40265F0, ++0x6053756C, 0x80F8BF80, 0xBF82E402, 0x84F8E512, ++0x7090E402, 0x6503BF82, 0x4618E602, 0x81F66063, ++0xBF80E402, 0x85F6E500, 0x6603E402, 0xE500BF8C, ++0xE40285F6, 0xBF926603, 0xE5FEE500, 0xE010655C, ++0xBF61E403, 0xE5130F54, 0xE40EBF63, 0x05FCE010, ++0xBF63E40E, 0xE5007585, 0xBF64E403, 0xE500E640, ++0xBF71E403, 0xE500E640, 0xBF78E403, 0xE5FFE640, ++0xE014655C, 0xBF47E404, 0xE40F0F54, 0xE504BF49, ++0x05FCE014, 0xBF49E40F, 0xE5017584, 0xBF4AE640, ++0xE501E404, 0xBF57E640, 0xE501E404, 0xE404E640, ++0xAF5C7F18, 0x7F184F26, 0x000B4F26, 0x4F220009, ++0xD2427FF0, 0x88016021, 0xD2418B71, 0x26686621, ++0xD2408B6D, 0x26686621, 0xE50F8B69, 0xE401BF1C, ++0xBF1EE501, 0xE586E400, 0xE400655C, 0x2F50BF1E, ++0xBF1BE401, 0xE401E506, 0xBF1C6543, 0xE401E640, ++0xBF296543, 0xE401E640, 0xBF306543, 0x65F0E640, ++0x756CE402, 0xBEFF6053, 0xE40280F4, 0xE512BF01, ++0xE40284F4, 0xBF017090, 0xE6406503, 0xBF02E402, ++0xE640E500, 0xBF0FE402, 0xE640E500, 0xBF16E402, ++0xE5FEE500, 0x6053655C, 0xBEE5E403, 0xE51380F8, ++0xE40EBEE7, 0xE40E84F8, 0xBEE77085, 0xE5006503, ++0xBEE8E640, 0xE500E403, 0xBEF5E640, 0xE500E403, ++0xBEFCE640, 0xE5FFE403, 0x6053655C, 0xBECBE404, ++0xE40F80FC, 0xE504BECD, 0xE40F84FC, 0xBECD7083, ++0xE5016503, 0xBECEE640, 0xE501E404, 0xBEDBE640, ++0xE501E404, 0xE404E640, 0xAEE07F10, 0x7F104F26, ++0x000B4F26, 0x00000009, 0x001E102F, 0x001E1080, ++0x001E1090, 0x001E103F, 0x001E103E, 0x00203A4A, ++0x00203A4C, 0x00203A4E, 0xD21DD11C, 0x66206010, ++0x676C7001, 0x3700C90F, 0xE5008D13, 0x67106210, ++0x7701622C, 0x64232170, 0xD6166010, 0x44084408, ++0x3428C90F, 0x62602100, 0x7201D513, 0x44082620, ++0x000B354C, 0xD10F6053, 0x25586510, 0xE6008D13, ++0xD60DD40B, 0x655C6540, 0x47086753, 0x37584708, ++0x47086540, 0x24507501, 0x367C6040, 0x2400C90F, ++0x72FF6210, 0x000B2120, 0x00006063, 0x00203995, ++0x00203994, 0x00203996, 0x002035BC, 0x7FFC4F22, ++0xE680D1A8, 0x666C6212, 0xD2A72F22, 0x67F36563, ++0x420B7542, 0x7F04E404, 0x000B4F26, 0xE6800009, ++0xD2A1666C, 0xE7006563, 0x422B7540, 0xE6806473, ++0xD29D666C, 0xE7006563, 0x422B7543, 0x2F866473, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x7FC04F22, ++0xDB97D296, 0x72012F22, 0xD1961F21, 0x66125211, ++0x8B013620, 0x0009A0F9, 0xC9036061, 0x8B018801, ++0x0009A0F3, 0xD290DC8F, 0x64C3420B, 0x6503D18F, ++0x60111F02, 0x8B048801, 0x420BD28D, 0xAFE464C3, ++0x54530009, 0x844CEE84, 0x890130E0, 0x0009A0C3, ++0x6610D188, 0x6023626C, 0x8B718801, 0x6210D186, ++0x89662228, 0xDA86D285, 0xE0036122, 0x64221112, ++0x4018D881, 0xDD83E500, 0x814167A3, 0x77042850, ++0x647266A2, 0x6ED3D580, 0x1F457E04, 0x65521F56, ++0x64E368D2, 0x1F8874F8, 0x684369E2, 0x1F637894, ++0x1F991F74, 0x62826142, 0xD779D978, 0x1F2BD679, ++0x67726292, 0x1F1A6062, 0x2602CB20, 0xD176E600, ++0xE5401F57, 0x1F7D1F2C, 0x76011F1E, 0x3253626D, ++0x51F38BFB, 0x52F555F4, 0x25222A12, 0x55F757F6, ++0x27525AF8, 0x5DF92DA2, 0x2ED251FB, 0xD56B5EFA, ++0x54FC24E2, 0x281257FD, 0xD160D869, 0x25722942, ++0x69126782, 0x1974D866, 0xDD666A12, 0x56FE60A1, ++0x2A01CB01, 0xDA646412, 0xE9012842, 0x4A0B2D42, ++0x52FE2692, 0xD661EE01, 0x22E24E18, 0x72016262, ++0x60B22622, 0xCB01D14F, 0x2B02E202, 0x2120A03F, ++0x8B3C2228, 0xE601D55A, 0x2160E700, 0xE01C2572, ++0xC801004C, 0xD8578B0C, 0x1F8FD257, 0xE6002822, ++0x7601E57D, 0x3253626C, 0x56FF8BFB, 0x2622D253, ++0xE2FE69B2, 0x2B922929, 0x0A4CE01E, 0xE01F65F2, ++0x014C25A0, 0x741057F1, 0xEA062710, 0xDD4CE600, ++0x8446DE4C, 0x2D007601, 0x696C6844, 0x2E8039A3, ++0x8FF67E01, 0xDE487D01, 0x2EA0EA94, 0xE1007E01, ++0x7E0F2E10, 0xD12FE205, 0x64102E20, 0x6023624C, ++0x89088801, 0x55F2D22A, 0x64C3420B, 0xEE01D132, ++0xAF1A4E18, 0x55F221E2, 0x8553D13C, 0x620D6612, ++0x89063262, 0xD63BD43A, 0xE801460B, 0xAF0CD73A, ++0xD91F2782, 0x64C3490B, 0xEE01D127, 0xDA38D437, ++0x4A0B4E18, 0xAF0021E2, 0x7F400009, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x4F2268F6, ++0x85467FF4, 0x2F01E681, 0x666C8547, 0x854881F1, ++0x81F2D209, 0x67F38542, 0x854381F3, 0x81F4E40C, ++0x65636053, 0x420B81F5, 0x7F0C7540, 0x000B4F26, ++0x00000009, 0x001C3D9C, 0x002023FC, 0x0011779A, ++0x001C36F8, 0x002035B4, 0x002014A6, 0x00203A16, ++0x002014D0, 0x002039A5, 0x002039A4, 0x002039A0, ++0x001C3B9C, 0x001C3704, 0x001C3D98, 0x001C3BB4, ++0x001C5960, 0x001C3500, 0x001C3D30, 0x001C8960, ++0x0020358C, 0x001C3D00, 0x00201610, 0x00117730, ++0x002039A8, 0x001C582C, 0x2000A000, 0x0000A000, ++0x0011778C, 0x00117792, 0x00117788, 0x0020397C, ++0x0020357C, 0x00201534, 0x001E2130, 0x00203DA0, ++0x002018C0, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0xD19B7FEC, 0x2F12E000, 0x6103D49A, ++0x1F4281F2, 0xDD9ADA99, 0xD69A6813, 0xE0014808, ++0x460BDE99, 0x38EC4800, 0x65A21F03, 0x352052A1, ++0xA23E8B01, 0x60510009, 0x8801C903, 0xA2388B01, ++0x52530009, 0x32E0DE91, 0xD9918B10, 0x64A3490B, ++0x4B0BDB90, 0xDE906403, 0xD791D690, 0xEC01D591, ++0x2E02E100, 0x271026C0, 0x2502AFDF, 0xC8018551, ++0xA1578B01, 0x62510009, 0x4200622D, 0x5E53366A, ++0x85E2226D, 0xC903642C, 0x85E36603, 0x6053650D, ++0x40214021, 0x4500C93F, 0x322A6703, 0x6053252D, ++0xC901D17F, 0x60106C03, 0x8801D97F, 0xDB7F8B05, ++0x2120E200, 0xCB0160B2, 0xD17D2B02, 0x88016011, ++0x65A28B0A, 0x8D042448, 0x9B9E6251, 0xA00322B9, ++0x919B2521, 0x2521221B, 0x37B3EB10, 0x2448895E, ++0xD4738B07, 0x22286241, 0x60638903, 0xA05781F8, ++0xD5706473, 0x46084608, 0x85E26273, 0x46006B50, ++0x362C4200, 0x2BB8C910, 0x8F1F6463, 0x26686603, ++0xD2698911, 0x062D6043, 0x4119616D, 0x6B0E6019, ++0x81F820BD, 0x880160C3, 0x646C8F2C, 0x880F6073, ++0xA0278B1B, 0xD2610009, 0x052D6043, 0x4119615D, ++0x670E6019, 0x645C207D, 0x81F8A01C, 0x890F2668, ++0x6043D25B, 0x6B5D052D, 0x60B94B19, 0x201D610E, ++0x60C381F8, 0x8F0D8801, 0x6473645C, 0xEC00A00A, ++0x6043D254, 0x625D052D, 0x60294219, 0x207D670E, ++0x81F8645C, 0x880285F8, 0x85E1890A, 0x8D07C820, ++0xE6DC6203, 0x60232269, 0x81E1A002, 0x644CE4FF, ++0x6210D149, 0x89012228, 0x644CE4FF, 0x654DEBFF, ++0x35B06BBC, 0xDB368B2B, 0x64A34B0B, 0x410BD135, ++0x54036403, 0x85446E03, 0xC948DB40, 0xDC408808, ++0xBEAC8B01, 0x64B3E502, 0x65E34C0B, 0xDB3DEC01, ++0xD13D2DC2, 0x621260B2, 0x72017001, 0x21228805, ++0x2B028F08, 0x666CE680, 0x6563D238, 0x7549E700, ++0x6473420B, 0xA030D436, 0x7FFF0009, 0x85E28000, ++0x20B9EBFC, 0x610381E2, 0x942A85E3, 0x62032049, ++0x450885F8, 0x81E2201B, 0xC90160C3, 0x40084018, ++0x40084008, 0x4000225B, 0x6023220B, 0x85E481E3, ++0x4118E108, 0x81E4201B, 0xE40262A2, 0x20B98521, ++0x67A28121, 0xCB016071, 0x85F82701, 0x89033042, ++0xECE785E2, 0x81E220C9, 0x490BD41E, 0xA03B0009, ++0x7E030009, 0x001C3D30, 0x00203DAC, 0x0020358C, ++0x001E212C, 0x00203470, 0x001C3D00, 0x00117780, ++0x002014A6, 0x00201670, 0x0011770C, 0x002039A4, ++0x002039A5, 0x002039A0, 0x002018C0, 0x001C36F8, ++0x00203A1A, 0x00203DBC, 0x00203BA0, 0x00203C20, ++0x00203CA0, 0x00203D20, 0x00203990, 0x00203584, ++0x002014D0, 0x00203A1C, 0x00203A20, 0x002023FC, ++0x00203DA4, 0x00203DA8, 0x602262F2, 0x40094019, ++0xC90F4009, 0x8B0B880A, 0x60E2DE8C, 0x40094019, ++0xC90F4009, 0x8B038808, 0xCB0160A2, 0x2802A006, ++0x65E2DE87, 0x2E527501, 0x286266A2, 0x52F366F2, ++0x2622AE83, 0xD2838551, 0xDE83C802, 0xA0958B01, ++0x420B0009, 0x4E0B64A3, 0x5E036403, 0x85E46503, ++0x4918E908, 0xD77D209B, 0xE04C81E4, 0xDC7C0B7E, ++0x7B01D97C, 0x61C207B6, 0x71016690, 0x8D062668, ++0xD4792C12, 0x420BD279, 0xA070EB01, 0x62512DB2, ++0x4B18EB0F, 0x22B9E102, 0x32104118, 0x85518B0F, ++0x2029E2FC, 0x60518151, 0xCB0172E0, 0x85E12501, ++0x202994A3, 0x85E481E1, 0xA0522049, 0x675181E4, ++0x4719677D, 0x667E6779, 0x7701276D, 0x6903607C, ++0x88014918, 0x25918F3E, 0x6B12D161, 0x21B27B01, ++0x660D85E3, 0x40216063, 0xC93F4021, 0x6C034600, ++0x262D322A, 0xC8016063, 0xDB5ED15D, 0x967D8901, ++0xE6002C6B, 0x666C67CD, 0x40006063, 0x622D021D, ++0x8D0E3270, 0x60436403, 0xE9FF021D, 0x8B013290, ++0x01C5A007, 0x626C7601, 0x3292E904, 0x646C8BEB, ++0x60434400, 0xD15004BD, 0x0B457401, 0x669D6911, ++0x89073670, 0x602D6211, 0x890388FF, 0xE201DB4B, ++0x2B2021C1, 0xECFC8551, 0x815120C9, 0xCB016051, ++0xDC472501, 0x64A34C0B, 0x51F366F2, 0x85EF2612, ++0x54F2D244, 0x650D420B, 0x0009ADE7, 0xE500DC42, ++0x420B2C52, 0x4E0B64A3, 0x54036403, 0x85446E03, ++0x6703E908, 0x65034918, 0x27998541, 0xDB323790, ++0x8F0BD932, 0x6013610D, 0x8B07C820, 0xC9486053, ++0x8B038808, 0xE501BD4B, 0x0009A005, 0x2128D233, ++0xBD448901, 0x64B3E500, 0x490B65E3, 0xADBCEC01, ++0x85F22DC2, 0x7001EE04, 0x31E7610D, 0x8D0281F2, ++0xADA97A08, 0x7F140009, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x000B69F6, 0xF7FF68F6, 0x2FE68000, ++0xD2234F22, 0x60E36E22, 0x8D02C840, 0xBBE522E2, ++0xE2400009, 0x2E284218, 0xBBF08901, 0x60E30009, ++0x8905C810, 0xD21CD41B, 0x0009420B, 0x0009BBEF, ++0xC80560E3, 0xBD6D8901, 0x60E30009, 0x8902C802, ++0xABEC4F26, 0x4F266EF6, 0x6EF6000B, 0x001C3D3C, ++0x00117760, 0x002014A6, 0x00201670, 0x0020351C, ++0x00203DC0, 0x00203990, 0x00203584, 0x002014D0, ++0x002039FC, 0x00203A04, 0x002039F8, 0x002039FA, ++0x00201534, 0x002018D0, 0x00203A1C, 0x00008000, ++0x001C3510, 0x00203DB4, 0x002018C0, 0x89014F22, ++0x611B600B, 0x611BB00A, 0x000B4F26, 0x600B600B, ++0x611BA004, 0x8DF12107, 0x8BF84011, 0x620D2F26, ++0x8F3E3020, 0x40180019, 0x8B0B3016, 0x31043104, ++0x31043104, 0x31043104, 0x31043104, 0x412462F6, ++0x601C000B, 0x41296219, 0x20084018, 0x31048926, ++0x31043104, 0x31043104, 0x31043104, 0x31043104, ++0x31043104, 0x31043104, 0x31043104, 0x61193104, ++0x3204221D, 0x32043204, 0x32043204, 0x32043204, ++0x32043204, 0x32043204, 0x32043204, 0x32043204, ++0x212D3204, 0x601962F6, 0x4024000B, 0x000BE000, ++0x621362F6, 0x41294228, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x31044224, 0x31044224, ++0x31044224, 0x31044224, 0x602D4224, 0x62F6000B, ++0x080A0C0E, 0x00020406, 0x1A1C1E20, 0x12141618, ++0x2E303234, 0x26282A2C, 0x3A3C3E40, 0x6C625648, ++0x41112F26, 0xE2208F18, 0x890B3123, 0x321CD204, ++0xD1026220, 0x412B312C, 0x00090009, 0x0020349A, ++0x00203450, 0x000BE000, 0x400062F6, 0x40004000, ++0x40004000, 0x40004000, 0x62F6000B, 0x40004000, ++0x40004000, 0x40004000, 0x40184000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40284000, ++0x62F6000B, 0x40004000, 0x40184000, 0x000B4028, ++0xC90F62F6, 0x40054005, 0x40054005, 0x62F6000B, ++0x4005C907, 0x40054005, 0x62F6000B, 0x4005C903, ++0x000B4005, 0xC90162F6, 0x000B4005, 0x000062F6, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x42707372, ++0x3D206675, 0x554E203D, 0x202C4C4C, 0x6E49677A, ++0x4E497274, 0x6D754E51, 0x0000003D, 0x61766E49, ++0x2064696C, 0x72657375, 0x20726F20, 0x2079656B, ++0x00214449, 0x6E6B6E55, 0x206E776F, 0x6D6D6F63, ++0x3D646E61, 0x00000000, 0x203A3051, 0x00000020, ++0x203A3151, 0x00000020, 0x203A3251, 0x00000020, ++0x203A3351, 0x00000020, 0x203A3451, 0x00000020, ++0x2B434741, 0x73696F4E, 0x61432065, 0x7262696C, ++0x6F697461, 0x6166206E, 0x6F206C69, 0x6974206E, ++0x0D0A656D, 0x00000000, 0x00000072, 0x00205220, ++0x62735576, 0x7473725F, 0x00000A0D, 0x62735576, ++0x7375735F, 0x646E6570, 0x00000A0D, 0x62735576, ++0x7365725F, 0x000A0D6D, 0x00000044, 0x44387570, ++0x72637365, 0x6F747069, 0x3D584572, 0x00000000, ++0x00000047, 0x72746E49, 0x6D652051, 0x2C797470, ++0x49677A20, 0x4972746E, 0x754E514E, 0x00003D6D, ++0x654C7245, 0x0000006E, 0x20746F4E, 0x756F6E65, ++0x49206867, 0x4220514E, 0x0A0D6675, 0x00000000, ++0x000000FF, 0x00020001, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00020003, 0x01090108, 0x0002010A, ++0x02000003, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x000000FF, 0x00020001, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00020003, 0x01090108, 0x0002010A, ++0x00030003, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00FF010F, 0x01090108, 0x010B010A, ++0x0200010F, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00FF010F, 0x01090108, 0x010B010A, ++0x010F010F, 0x02020201, 0x02040203, 0x02060205, ++0x02020200, 0x02040203, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00205220, 0x00000046, 0x00000059, 0x73204142, ++0x003D7165, 0x49544120, 0x0000204D, 0x00000000, ++0x00000000, 0x002E0209, 0x80000101, 0x000409FA, ++0x00FF0400, 0x05070000, 0x02000201, 0x82050700, ++0x00020002, 0x03830507, 0x07010040, 0x40030405, ++0x02090100, 0x0101002E, 0x09FA8000, 0x04000004, ++0x000000FF, 0x02010507, 0x07000040, 0x40028205, ++0x05070000, 0x00400383, 0x04050701, 0x00004002, ++0x00000000, 0x00000000, 0x07090000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x6621D2A8, 0x2008606D, 0xA1B18B01, 0x88100009, ++0x88118922, 0x88128920, 0x8813891E, 0x8821891C, ++0x8822891A, 0x883A8918, 0x883B8916, 0xE6448914, ++0x30604608, 0xE6488910, 0x30604608, 0xE658890C, ++0x30604608, 0x963D8908, 0x89053060, 0x3060963B, ++0x96398902, 0x8B013060, 0xE010000B, 0x8B018820, ++0xE020000B, 0x892B8837, 0x89298832, 0x89278835, ++0x89258836, 0x89238830, 0x89218838, 0x891F8839, ++0x891D8834, 0x891B8833, 0x4608E64C, 0x89173060, ++0x3060961B, 0x96198914, 0x89113060, 0x30609617, ++0x9615890E, 0x890B3060, 0x30609613, 0x96118908, ++0x89053060, 0x3060960F, 0x960D8902, 0x8B0C3060, ++0xE030000B, 0x05100165, 0x02300A10, 0x04300330, ++0x06300530, 0x0B300A30, 0x88400C30, 0xA1428B01, ++0x88410009, 0xA13E8B01, 0x88430009, 0xA13A8B01, ++0x88480009, 0xA1368B01, 0x884A0009, 0xA1328B01, ++0x884B0009, 0xA12E8B01, 0x884C0009, 0xA12A8B01, ++0xE6800009, 0x3060666C, 0xA1248B01, 0xE6810009, ++0x3060666C, 0xA11E8B01, 0xE6820009, 0x3060666C, ++0xA1188B01, 0xE6830009, 0x3060666C, 0xA1128B01, ++0xE6840009, 0x3060666C, 0xA10C8B01, 0xE6850009, ++0x3060666C, 0xA1068B01, 0xE6860009, 0x3060666C, ++0xA1008B01, 0xE6870009, 0x3060666C, 0xA0FA8B01, ++0xE6880009, 0x3060666C, 0xA0F48B01, 0xE6890009, ++0x3060666C, 0xA0EE8B01, 0xE68A0009, 0x3060666C, ++0xA0E88B01, 0xE68B0009, 0x3060666C, 0xA0E28B01, ++0xE68C0009, 0x3060666C, 0xA0DC8B01, 0xE68D0009, ++0x3060666C, 0xA0D68B01, 0xE68E0009, 0x3060666C, ++0xA0D08B01, 0xE68F0009, 0x3060666C, 0xA0CA8B01, ++0xE6900009, 0x3060666C, 0xA0C48B01, 0xE6910009, ++0x3060666C, 0xA0BE8B01, 0xE6F80009, 0x3060666C, ++0xA0B88B01, 0xE6F90009, 0x3060666C, 0xA0B28B01, ++0xE6FA0009, 0x3060666C, 0xA0AC8B01, 0xE6FB0009, ++0x3060666C, 0xA0A68B01, 0xE6FC0009, 0x3060666C, ++0xA0A08B01, 0xE6FD0009, 0x3060666C, 0xA09A8B01, ++0xE6FE0009, 0x3060666C, 0xA0948B01, 0xE6FF0009, ++0x3060666C, 0xA08E8B01, 0xE6D00009, 0x3060666C, ++0xA0888B01, 0xE6D10009, 0x3060666C, 0xA0828B01, ++0xE6D20009, 0x3060666C, 0xA07C8B01, 0xE6D30009, ++0x3060666C, 0xE6D48977, 0x3060666C, 0xE6D58973, ++0x3060666C, 0xE6D6896F, 0x3060666C, 0xE6D7896B, ++0x3060666C, 0xE6D88967, 0x3060666C, 0xA0038963, ++0x00000009, 0x00114000, 0x666CE6D9, 0x895A3060, ++0x666CE6DA, 0x89563060, 0x666CE6DB, 0x89523060, ++0x666CE6DC, 0x894E3060, 0x666CE6DD, 0x894A3060, ++0x666CE6F0, 0x89463060, 0x666CE6F1, 0x89423060, ++0x666CE6F2, 0x893E3060, 0x666CE6F3, 0x893A3060, ++0x666CE6F4, 0x89363060, 0x666CE6F5, 0x89323060, ++0x666CE6F6, 0x892E3060, 0x666CE6F7, 0x892A3060, ++0x4608E650, 0x89263060, 0x3060969A, 0x96988923, ++0x89203060, 0x30609696, 0x9694891D, 0x891A3060, ++0x30609692, 0x96908917, 0x89143060, 0x3060968E, ++0x968C8911, 0x890E3060, 0x3060968A, 0x9688890B, ++0x89083060, 0x30609686, 0x96848905, 0x89023060, ++0x30609682, 0x000B8B01, 0xE0FFE040, 0x600C000B, ++0xE000000B, 0x6243D157, 0xE4028512, 0x662D670D, ++0xE500A00E, 0x6053655D, 0x305C4000, 0x4008D152, ++0x622D021D, 0x8B023260, 0xA0047108, 0x7501041C, ++0x3273625D, 0x60438BEE, 0xC90A000B, 0x674C76FE, ++0x025C606C, 0x3723622C, 0x20088906, 0x70FF8902, ++0x6603AFF6, 0xE000000B, 0x0009000B, 0x4F124F22, ++0x326052F2, 0x34508910, 0x3470890E, 0x3750890D, ++0x3268890A, 0x04273458, 0x60733758, 0x440BD43B, ++0x306C011A, 0x6203A001, 0x4F166263, 0x000B4F26, ++0x2FE66023, 0x4F124F22, 0x6E434F02, 0x614C54F4, ++0x2F164118, 0x666C677C, 0x64EC655C, 0x46184718, ++0xBFD34518, 0x65034418, 0x60537F04, 0xC980E702, ++0x6E034718, 0x37ED4728, 0x62594519, 0x010A652E, ++0x312C225D, 0x4F06601C, 0x4F264F16, 0x6EF6000B, ++0x03400240, 0x05400440, 0x07400640, 0x09400840, ++0x11400B40, 0x0A401240, 0x4F220A50, 0x614C8451, ++0x3127620C, 0xA00C8901, 0x8452E400, 0x3127620C, ++0xA0068901, 0x8453E401, 0x3127620C, 0xE4038D01, ++0x6263E402, 0x60437201, 0x677C072C, 0x62532F76, ++0x072C7201, 0x055C066C, 0x666C677C, 0xBFA8655C, ++0x7F046413, 0x000B4F26, 0x605C600C, 0x8F068801, ++0x606C6243, 0x8B018801, 0x720AA001, 0x000B72F6, ++0x00006023, 0x00114000, 0x00114008, 0x00203374, ++0xE040D690, 0x056E614C, 0x9274D78F, 0x352C357C, ++0xE400E718, 0x626C6650, 0x89043120, 0x624C7401, ++0x8FF73273, 0x000B7501, 0xE2FF6043, 0x622C644C, ++0x890D3420, 0x8801605C, 0x965D8B03, 0xA005346C, ++0x62436243, 0x324C4208, 0x326C9657, 0x6023000B, ++0x6043000B, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0x92497FF4, 0x6B533526, 0x00296943, ++0xE13FCA01, 0x6E03EAFF, 0x6AAC2F10, 0x6D43EC00, ++0x62D0E808, 0x34A0642C, 0xBFCE8939, 0x3B0065E3, ++0x6CCC8F0A, 0x420062C3, 0x362C6693, 0x1FC18461, ++0x4109610C, 0x2F10A02D, 0x891C2CC8, 0x65E364D0, ++0x644CBFBB, 0x89163B02, 0x70FF60C3, 0x049C4000, ++0x644C65E3, 0x1F02BFB1, 0x8D1A30B2, 0x56F21FC1, ++0x356C6593, 0xC9038451, 0x89122008, 0x660C8451, ++0xA00E4609, 0x7C012F60, 0x328362CC, 0x8FC87D02, ++0xA0061F21, 0x06250009, 0x12C008FC, 0x62CC09B4, ++0x50F11F21, 0x8B128808, 0x7CFF6CCC, 0x60C34C00, ++0x65E3049C, 0x644CBF89, 0x8B083B06, 0x849139CC, ++0x2008C903, 0x84918903, 0x4209620C, 0x60F02F20, ++0x4F267F0C, 0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, ++0x68F6000B, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0x92727FFC, 0x3426E100, 0x6B436953, ++0x2F12666C, 0xCA010029, 0x8D032668, 0xE2F06E03, ++0x2F22622C, 0x6AACEAFF, 0x6C93ED00, 0x66C0E808, ++0x34A0646C, 0xBF508913, 0x3B0065E3, 0x6DDC8B0A, ++0x39DC4D00, 0xC9038491, 0x8B082008, 0xCB0F60F2, ++0x2F02A005, 0x62DC7D01, 0x8FE83283, 0x60F27C02, ++0x4F267F04, 0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, ++0x68F6000B, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0x4F024F12, 0x3F3C9332, 0x4308E35B, ++0x605333FC, 0x80341351, 0xE7606063, 0x80381362, ++0x4708E012, 0xE03F8136, 0xD11237FC, 0x27008138, ++0x80788074, 0xE9166053, 0x60638012, 0x21414918, ++0x6B938013, 0xEDFF6AB4, 0x6AAC61B0, 0x6C1C4A18, ++0x68C82CAB, 0x6DDD688D, 0x234238D0, 0x8B131398, ++0xD207D406, 0x0009420B, 0x432BD306, 0x09B40009, ++0x0000FE10, 0x001142D8, 0x000DDD00, 0x001160B0, ++0x002018C0, 0x00115E88, 0x342292E3, 0x8F02E100, ++0xA1616593, 0x92DD0009, 0x352CE7FF, 0xEE04677C, ++0x622C6250, 0x89043270, 0x621C7101, 0x8FF732E3, ++0xE8FC7501, 0x3488688C, 0x9ACBE064, 0x40086893, ++0x0F4438AC, 0x661C6583, 0x644CBE18, 0x64E36E0C, ++0x65E37401, 0x45086643, 0x35EC4608, 0x4508364C, ++0x45004608, 0x369C4600, 0x61A39AB5, 0xE0656763, ++0x400837AC, 0x62637114, 0x321C0F76, 0x94AB7004, ++0x61430F26, 0x359C6263, 0x7004324C, 0x0F267114, ++0x7004361C, 0x0F666753, 0x700437AC, 0x7A140F76, ++0x37AC6753, 0x66537004, 0x364C0F76, 0x74147004, ++0x354C0F66, 0x0F567004, 0x395C958F, 0xED006A93, ++0x6BD3E956, 0xEC054908, 0x4008E065, 0x60B302FE, ++0x644C042C, 0x60E32F46, 0xE06A07AC, 0x01FE4008, ++0x061C60B3, 0x058C60E3, 0x4008E065, 0x677C01FC, ++0x655C666C, 0x641CBDED, 0x7F046403, 0x60D36DDC, ++0xE0660F44, 0x04FE4008, 0x054C60B3, 0x2F56655C, ++0x07AC60E3, 0x4008E06B, 0x60B301FE, 0x60E3061C, ++0xE065058C, 0x01FC4008, 0x666C677C, 0xBDD0655C, ++0x6403641C, 0x65F37F04, 0x60D37510, 0xE0650544, ++0x07FE4008, 0x057C60C3, 0x2F56655C, 0x07AC60E3, ++0x4008E06A, 0x60C301FE, 0x60E3061C, 0xE065058C, ++0x01FC4008, 0x666C677C, 0xBDB2655C, 0x6403641C, ++0x61F37F04, 0x60D37120, 0xE0660144, 0x02FE4008, ++0x052C60C3, 0x2F56655C, 0x07AC60E3, 0x4008E06B, ++0x60C301FE, 0x60E3061C, 0xE065058C, 0x01FC4008, ++0x666C677C, 0xBD94655C, 0x6503641C, 0x64F37F04, ++0x60D3349C, 0xE0670454, 0x07FE4008, 0x057C60B3, ++0x2F56655C, 0x07AC60E3, 0x4008E06C, 0xA00501FE, ++0x0BB860B3, 0x03C2013E, 0x013F0462, 0x60E3061C, ++0xE065058C, 0x01FC4008, 0x666C677C, 0xBD70655C, ++0x6203641C, 0xE1B87F04, 0x64F3611C, 0x60D3341C, ++0xE0680424, 0x05FE4008, 0x075C60B3, 0x2F76677C, ++0x07AC60E3, 0x4008E06D, 0x60B301FE, 0x60E3061C, ++0xE065058C, 0x02FC4008, 0x666C677C, 0xBD50655C, ++0x6703642C, 0xE2C07F04, 0x66F3622C, 0x60D3362C, ++0xE0670674, 0x07FE4008, 0x027C60C3, 0x2F26622C, ++0x07AC60E3, 0x4008E06C, 0x60C302FE, 0x60E3062C, ++0xE065058C, 0x02FC4008, 0x666C677C, 0xBD30655C, ++0x6203642C, 0xE7C87F04, 0x66F3677C, 0x60D3367C, ++0xE0680624, 0x06FE4008, 0x026C60C3, 0x2F26622C, ++0x07AC60E3, 0x4008E06D, 0x60C302FE, 0x60E3062C, ++0xE065058C, 0x02FC4008, 0x666C677C, 0xBD10655C, ++0x6103642C, 0x66937F04, 0x62F37608, 0x60D3326C, ++0x02147D01, 0xE60562DC, 0x7C013263, 0x7B018D02, ++0x0009AEFA, 0x0009A17B, 0xE7FF9BD5, 0x677C35BC, ++0x6250EE08, 0x3270622C, 0x71018904, 0x32E3621C, ++0x75018FF7, 0xDDD89CC8, 0x3D4534C8, 0x4008E064, ++0x4E090E0A, 0x0FE46593, 0x702435BC, 0x64EC661C, ++0x0F56BCB4, 0x64E36E0C, 0x65E37401, 0x45086243, ++0x35EC4208, 0x4508324C, 0x45004208, 0x329C4200, ++0x61B37B0C, 0x38BC6823, 0x7114E06E, 0x40086B23, ++0x91A23B1C, 0x70040F86, 0x68236413, 0x0FB6359C, ++0x7004381C, 0x0F867414, 0x7004342C, 0x67539896, ++0x0F466253, 0x7004378C, 0x6B537814, 0x7114321C, ++0x3B8C0F76, 0x351C7004, 0x0FB69789, 0x397C7004, ++0x70040F26, 0xED006893, 0x0F56EC05, 0x6AD3E956, ++0xE06E4908, 0x02FE4008, 0x012C60A3, 0x2F16611C, ++0x078C60E3, 0x4008E073, 0x60A304FE, 0xE06E064C, ++0x0BFE4008, 0x05BC60E3, 0x4008E065, 0x677C01FC, ++0x655C666C, 0x641CBC85, 0x7F046403, 0x60D36DDC, ++0xE06F0F44, 0x04FE4008, 0x054C60A3, 0x2F56655C, ++0x078C60E3, 0x4008E074, 0x60A30BFE, 0xE06E06BC, ++0x0BFE4008, 0x05BC60E3, 0x4008E065, 0x677C01FC, ++0x655C666C, 0x641CBC65, 0x7F046403, 0x751065F3, ++0x054460D3, 0x4008E06E, 0x60C307FE, 0x655C057C, ++0x60E32F56, 0xE073078C, 0x0BFE4008, 0x06BC60C3, ++0x4008E06E, 0x60E301FE, 0xE065051C, 0x0BFC4008, ++0x666C677C, 0xBC44655C, 0x610364BC, 0x6BF37F04, ++0x60D37B20, 0xE06F0B14, 0x01FE4008, 0x041C60C3, ++0x2F46644C, 0x078C60E3, 0x4008E074, 0x60C301FE, ++0xE06E061C, 0x0BFE4008, 0x05BC60E3, 0x4008E065, ++0xA00501FC, 0x0136677C, 0x028212C0, 0x01370142, ++0x655C666C, 0x641CBC1D, 0x7F046203, 0x349C64F3, ++0x042460D3, 0x4008E070, 0x60A304FE, 0x655C054C, ++0x60E32F56, 0xE075078C, 0x0BFE4008, 0x06BC60A3, ++0x4008E06E, 0x60E301FE, 0xE065051C, 0x0BFC4008, ++0x666C677C, 0xBBFC655C, 0x610364BC, 0xEBB87F04, ++0x65F36BBC, 0x60D335BC, 0xE0710514, 0x07FE4008, ++0x047C60A3, 0x2F46644C, 0x078C60E3, 0x4008E076, ++0x60A30BFE, 0xE06E06BC, 0x01FE4008, 0x051C60E3, ++0x4008E065, 0x677C0BFC, 0x655C666C, 0x64BCBBD9, ++0x7F046103, 0x622CE2C0, 0x3B2C6BF3, 0x0B1460D3, ++0x4008E070, 0x60C302FE, 0x677C072C, 0x60E32F76, ++0xE075078C, 0x02FE4008, 0x062C60C3, 0x4008E06E, ++0x60E302FE, 0xE065052C, 0x02FC4008, 0x666C677C, ++0xBBB6655C, 0x6703642C, 0xEBC87F04, 0x66F36BBC, ++0x60D336BC, 0xE0710674, 0x06FE4008, 0x026C60C3, ++0x2F26622C, 0x078C60E3, 0x4008E076, 0x60C302FE, ++0xE06E062C, 0x02FE4008, 0x052C60E3, 0x4008E065, ++0x677C02FC, 0x655C666C, 0x642CBB93, 0x7F046103, ++0x72086293, 0x362C66F3, 0x7D0160D3, 0x62DC0614, ++0x3263E605, 0x8D027C01, 0xAEE27A01, 0x6EF30009, ++0xE2B068F3, 0x6AF3E05A, 0x389C7E18, 0x69F3622C, ++0x7A084008, 0x67F36DF3, 0x392C61F3, 0x6CA30FE6, ++0x77207D10, 0xE4007128, 0xEB0565F3, 0x604C6654, ++0x66D4626C, 0x2E604221, 0x048C6674, 0x626C2C20, ++0x09444221, 0x21207001, 0x32B3620C, 0x71016403, ++0x8FEB7E01, 0xE05A7C01, 0x6EF34008, 0x7E300BFE, ++0xEC19ED00, 0x66B365A3, 0xBB7E64DC, 0x62DC7D01, ++0x2E0032C3, 0x7E018FF6, 0x666CE6B0, 0x6BF36EF3, ++0x7B283E6C, 0xEC4CA010, 0xCCCCCCCD, 0x64D36DDC, ++0x644C74F4, 0xBB6865B3, 0x67F366E3, 0x77306503, ++0x075460D3, 0x62DC7D01, 0x8BEF32C3, 0x7B306BF3, ++0x61B367B3, 0xED8064B3, 0x71027701, 0x6DDC7403, ++0xDC37E500, 0x605CDE37, 0x091C084C, 0x0A7C668C, ++0x699C4628, 0x49284618, 0x05BC6AAC, 0x4A18269B, ++0x70046803, 0x655C26AB, 0x620C38CC, 0x38EC265B, ++0x286232D3, 0x65038FE7, 0x644CE4B8, 0x3C4C6CF3, ++0x6EF37408, 0xE2B0E658, 0x3E4C6AF3, 0x74086BF3, ++0x460861F3, 0x622C68F3, 0x7A0869F3, 0x314C7B18, ++0x386C64F3, 0x6DA3392C, 0x742867B3, 0x66C4E500, ++0x626C605C, 0x422166E4, 0x66142760, 0x2D20058C, ++0x4221626C, 0x70010954, 0x620C2420, 0x3263E605, ++0x74016503, 0x8FEA7701, 0xE05E7D01, 0x02FD4008, ++0x6D2DE9D0, 0x699C7D07, 0xEE00A00B, 0x66B365A3, ++0x64ECBAFB, 0x620367F3, 0x60EC379C, 0x70010724, ++0x62EC6E03, 0x8BF132D3, 0x4008E05F, 0xEAB008FD, ++0x6DF36AAC, 0x6BF36C8D, 0x7C0D3DAC, 0x7B28A012, ++0x0000A280, 0x001BC000, 0x64E36EEC, 0x644C74F4, ++0xBADA65B3, 0x62F366D3, 0x329C6103, 0x7E0160E3, ++0x62EC0214, 0x8BEF32C3, 0x3D9C6DF3, 0x67D36ED3, ++0xEC8061D3, 0x77027E01, 0x6CCC7103, 0xDBB9E400, ++0x604CDAB9, 0x067C041C, 0x08EC654C, 0x666C4528, ++0x46284518, 0x09DC688C, 0x4818256B, 0x70046603, ++0x699C258B, 0x620C36BC, 0x36AC259B, 0x265232C3, ++0x64038FE7, 0x4008E064, 0x70E007FC, 0x706C0CFC, ++0x0F8668CC, 0x0DFC7098, 0x6ADC706C, 0x708C0FA6, ++0x9BBF0EFE, 0xE2543EB2, 0x697CE100, 0x42088F02, ++0x0009A163, 0x4008E063, 0x6EF305FE, 0x3E2C96B3, ++0x64E3356C, 0xEDFFE703, 0x32D06250, 0x622C8D07, ++0x681C7101, 0x24203873, 0x8FF57505, 0xE0647401, ++0x0AFC4008, 0x64AC65E3, 0x661CBA18, 0xE063670C, ++0x62734008, 0x42080BFE, 0x7701327C, 0x3A2C6AB3, ++0x48086873, 0x948F6EA3, 0x3E4C387C, 0x3B8C74FF, ++0x38283A4C, 0xEC003B4C, 0x6083DD88, 0x655C05EC, ++0xE0652F56, 0x67B04008, 0x65A066E4, 0x677C01FC, ++0x655C666C, 0x641CBA1D, 0x7C017F04, 0xE40462CC, ++0x2D003243, 0x7D018FE9, 0xE063E554, 0x67F34508, ++0x375C4008, 0x966805FE, 0x356CEDFF, 0x6DDC6473, ++0xEE04E100, 0x666C6650, 0x890636D0, 0x621C7101, ++0x246032E3, 0x8FF57505, 0xE0647401, 0x02FC4008, ++0x642C6573, 0x661CB9CA, 0x6E23620C, 0xE0634E08, ++0x72013E2C, 0x0BFE4008, 0x47086723, 0x6AB3372C, ++0x68733AEC, 0x6EA338E8, 0x3E1C9140, 0x3B7C71FF, ++0x3B1C3A1C, 0x0F96704C, 0xEC00E904, 0x6083DD60, ++0x644C04EC, 0xE0652F46, 0x67B04008, 0x65A066E4, ++0x677C01FC, 0x655C666C, 0x641CB9CB, 0x7C017F04, ++0x329362CC, 0x8FEA2D00, 0xE0767D01, 0x09FE4008, ++0x70B4E454, 0x67F34408, 0x374C05FE, 0xEDFF9617, ++0x356C6473, 0xE1006DDC, 0x6650EE04, 0x36D0666C, ++0x71018906, 0x32E3621C, 0x75092460, 0x74018FF5, ++0xE064A006, 0x05BA0BB8, 0x05C905BB, 0x05DD05CA, ++0x65734008, 0x661C07FC, 0x647CB970, 0x6623620C, ++0x4608E063, 0x46004008, 0x362C0BFE, 0x68237201, ++0x3A6C6AB3, 0x48004808, 0x91676EA3, 0x3E1C382C, ++0x3B8C71FF, 0x38683A1C, 0xEC003B1C, 0x6083DD35, ++0x644C04EC, 0xE0652F46, 0x67B04008, 0x65A066E4, ++0x677C01FC, 0x655C666C, 0x641CB973, 0x7C017F04, ++0xE50862CC, 0x2D003253, 0x7D018FE9, 0x4008E063, ++0x05FEE654, 0x64F34608, 0xECFF9741, 0x357C346C, ++0xEE006CCC, 0x6250ED04, 0x32C0622C, 0x7E018906, ++0x38D368EC, 0x75092420, 0x74018FF5, 0x4008E077, ++0x700405FE, 0x649306FE, 0xEA54B9A7, 0x65F34A08, ++0x640C35AC, 0x66ECB91A, 0x6613610C, 0x4608E063, ++0x46004008, 0x361C0BFE, 0x68137101, 0x3A6C6AB3, ++0x48004808, 0x92136EA3, 0x3E2C381C, 0x3B8C72FF, ++0x38683A2C, 0xEC003B2C, 0xE077DD0B, 0x05FE4008, ++0x06FE7004, 0x6493B981, 0x0009A010, 0x060105DE, ++0x00000602, 0x0000B280, 0x001BC000, 0x001142E4, ++0x001142E8, 0x001142ED, 0x001142F5, 0x60836403, ++0x677C07EC, 0x67B02F76, 0x65A066E4, 0x666C677C, ++0xB906655C, 0x7F04644C, 0x61CC7C01, 0x3123E208, ++0x8FD22D00, 0xA0FC7D01, 0xE0630009, 0x05FE4008, ++0x96D067F3, 0x356C372C, 0xEEFF6473, 0x32E06250, ++0x622C8D08, 0x681C7101, 0x3863E608, 0x75052420, ++0x74018FF4, 0x4008E064, 0x657302FC, 0xB8B5642C, ++0x650C661C, 0x4008E063, 0x0BFE6253, 0x325C4208, ++0x6AB37501, 0x68533A2C, 0x6EA34808, 0x385C94AC, ++0x74FF3E4C, 0x3A4C3B8C, 0x3B4C3828, 0xDD96EC00, ++0x06EC6083, 0x2F66666C, 0x4008E065, 0x66E467B0, ++0x01FC65A0, 0x666C677C, 0xB8BA655C, 0x7F04641C, ++0x62CC7C01, 0x3243E404, 0x8FE92D00, 0xE5547D01, ++0x4508E063, 0x400867F3, 0x05FE375C, 0xEEFF9685, ++0x6473356C, 0xE1006EEC, 0x666C6650, 0x890736E0, ++0x621C7101, 0x3283E808, 0x75092460, 0x74018FF4, ++0x4008E064, 0x65730AFC, 0xB86764AC, 0x620C661C, ++0xE0636623, 0x40084608, 0x0BFE4600, 0x7201362C, ++0x6AB36823, 0x48083A6C, 0x6EA34800, 0x382C915E, ++0x71FF3E1C, 0x3A1C3B8C, 0x3B1C3868, 0xDD6FEC00, ++0x04EC6083, 0x2F46644C, 0x4008E065, 0x66E467B0, ++0x01FC65A0, 0x666C677C, 0xB86A655C, 0x7F04641C, ++0x62CC7C01, 0x3253E508, 0x8FE92D00, 0xE0637D01, ++0xE6544008, 0x460805FE, 0x973864F3, 0x346CECFF, ++0x6CCC357C, 0xED08EE00, 0x666C6650, 0x890636C0, ++0x62EC7E01, 0x246032D3, 0x8FF57509, 0xE0777401, ++0x05FE4008, 0x06FE7004, 0xB89E6493, 0x4808E854, ++0x358C65F3, 0xB811640C, 0x610C66EC, 0xE0636613, ++0x40084608, 0x0BFE4600, 0x7101361C, 0x6AB36813, ++0x48083A6C, 0x6EA34800, 0x381C920A, 0x72FF3E2C, ++0xA0063B8C, 0x05023A2C, 0x052A0503, 0x0572052B, ++0x38680573, 0xEC003B2C, 0xE077DD41, 0x05FE4008, ++0x06FE7004, 0x6493B871, 0x60836403, 0x677C07EC, ++0x67B02F76, 0x65A066E4, 0x666C677C, 0xB808655C, ++0x7F04644C, 0x61CC7C01, 0x3123E208, 0x8FE42D00, ++0xD3347D01, 0x0009430B, 0xE079620C, 0x0F244008, ++0x88306023, 0xA24D8B01, 0x88400009, 0xA2498B01, ++0x22280009, 0xA2458B01, 0xE5FF0009, 0x655CD42A, ++0xE03AE601, 0x8F043250, 0xE0790464, 0x4008E210, ++0xE05B0F24, 0x05FE4008, 0x3566963B, 0xA1498B01, ++0x60230009, 0x640CCB01, 0x6E23B842, 0xE118660C, ++0x890F3613, 0x4008E063, 0x04FE4608, 0x97294608, ++0x460070E0, 0x05FE347C, 0x346CB85C, 0xE0606203, ++0x0F244008, 0xCB0260E3, 0x640CB82A, 0xE118660C, ++0x890F3613, 0x4008E063, 0x04FE4608, 0x91114608, ++0x460070E0, 0x05FE341C, 0x346CB844, 0xE0616203, ++0x0F244008, 0xCB0560E3, 0x640CB812, 0xA00D660C, ++0x09B4E07A, 0x0000064D, 0x001142FD, 0x00114301, ++0x00114309, 0x00114400, 0x001142D8, 0x4008E118, ++0x8F043613, 0xE0610F64, 0xA0104008, 0xE07A0DFC, ++0x06FC4008, 0x626C70A4, 0x04FE4208, 0x97B44208, ++0x420070E0, 0x05FE347C, 0x342CB814, 0xE0796D03, ++0x00FC4008, 0xCB07DB8E, 0x430BD38E, 0x610C640C, ++0x4008E07A, 0x709C0F14, 0xE61802FC, 0x8D1C3163, ++0xE05D682C, 0x01FC4008, 0x09FC70FC, 0x04FE70FC, ++0xD385661C, 0x659C430B, 0xE07A6503, 0x01FC4008, ++0x611C70A4, 0x04FE4108, 0x97864108, 0x347C4100, ++0x430BD37E, 0xA003341C, 0xE0616C03, 0x0CFC4008, ++0xE500D67B, 0x640D8562, 0x4008E05B, 0x0AFEA036, ++0x6053655C, 0x305C4000, 0x4008D676, 0x622D026D, ++0x8F2A32A0, 0xD3746E03, 0x64AD430B, 0x2228620D, ++0xD6728927, 0x066C60E3, 0x4008E060, 0x460002FC, ++0x3E676E2C, 0x62638B00, 0x4008E060, 0x0F243867, ++0x62638D03, 0x4008E061, 0xE06102FC, 0x400861DC, ++0x0F243167, 0x8F01682C, 0x626362D3, 0x346764CC, ++0x6D238D01, 0xA00466C3, 0x75016C63, 0x3243625C, ++0xE0608BC6, 0x07FC4008, 0x617CE400, 0xE904D55C, ++0x666C6650, 0x8B013617, 0x6673677C, 0x624C7401, ++0x25603293, 0x75018FF4, 0xE03AD656, 0xE400056C, ++0x8D012558, 0xE2026243, 0x4008E061, 0x67830EFC, ++0x3E283828, 0x9119E500, 0x6053655C, 0x3A1002BC, ++0x622C8D0B, 0x3A609613, 0x32778907, 0xE0618B02, ++0x02FC4008, 0xA01D6053, 0x25580B24, 0x32878908, ++0x62838B00, 0xA0156053, 0x064D0B24, 0x099E096C, ++0x8F083277, 0xE07B6623, 0x0F164008, 0x02FC7098, ++0x01FE7068, 0x626C662C, 0x32876053, 0x0B648F02, ++0x646336E8, 0x625C7501, 0x8BCD3293, 0xE014D635, ++0xE4000644, 0xD53461DC, 0x6250E708, 0x3217622C, ++0x6DDC8B01, 0x740162D3, 0x3673664C, 0x8FF42520, ++0xE4007501, 0xD52D61CC, 0x622C6250, 0x8B013217, ++0x62C36CCC, 0x664C7401, 0x25203673, 0x75018FF4, ++0x0009A0EC, 0x4008E079, 0x642C02FC, 0x430BD319, ++0x660C6E43, 0x3653E518, 0xE0638910, 0x46084008, ++0x460804FE, 0x70E09722, 0x347C4600, 0xD31305FE, ++0x346C430B, 0xE0626203, 0x0F244008, 0xCB0660E3, ++0x430BD30C, 0x660C6403, 0x3653E518, 0xE0638928, ++0x46084008, 0x460804FE, 0x70E09708, 0x347C4600, ++0xD30605FE, 0x346C430B, 0x6C03A01D, 0x0000064D, ++0x001142E8, 0x001148E0, 0x001148BA, 0x00114934, ++0x00114000, 0x00114008, 0x00114774, 0x00114011, ++0x001142E4, 0x001142D8, 0x001142ED, 0x001142F5, ++0x4008E062, 0x60E30CFC, 0xD39CCB08, 0x6403430B, ++0xE07A610C, 0x4008E618, 0x8D1C3163, 0xE05D0F14, ++0x07FC4008, 0x09FC70FC, 0x04FE70FC, 0xD394667C, ++0x659C430B, 0xE07A6503, 0x01FC4008, 0x611C70A4, ++0x04FE4108, 0x9D744108, 0x34DC4100, 0x430BD38D, ++0xA003341C, 0xE0626D03, 0x0DFC4008, 0xE500D68A, ++0x640D8562, 0x4008E05B, 0x01FEA02C, 0x6053655C, ++0x305C4000, 0x4008D685, 0x622D026D, 0x8F203210, ++0xD3836E03, 0x641D430B, 0x2228620D, 0xD681891D, ++0x066C60E3, 0x4008E062, 0x460002FC, 0x3167612C, ++0x62638B00, 0x64CCE062, 0x34674008, 0x8F010F24, ++0x626362C3, 0x356765DC, 0x6C238D01, 0xA00466D3, ++0x75016D63, 0x3243625C, 0xE0628BD0, 0x07FC4008, ++0x617CE400, 0xE904D570, 0x622C6250, 0x8B013217, ++0x6273677C, 0x664C7401, 0x25203693, 0x75018FF4, ++0x61CCE400, 0xE708D569, 0x666C6650, 0x8B013617, ++0x66C36CCC, 0x624C7401, 0x25603273, 0x75018FF4, ++0x61DCE400, 0x6650D562, 0x3617666C, 0x6DDC8B01, ++0x740166D3, 0x3273624C, 0x8FF42560, 0xA0057501, ++0x064D0009, 0xE200D65B, 0x0624E03A, 0xE03AD659, ++0x2228026C, 0xE039894B, 0x2228026C, 0xE05B8947, ++0x0EFE4008, 0x3E669690, 0xE0798941, 0x00FC4008, ++0x8D023E66, 0xCB02640C, 0xD344640C, 0x0009430B, ++0xE05C660C, 0x07FC4008, 0x4608701C, 0x617C05FE, ++0x977A4608, 0x357C4600, 0x6613356C, 0x430BD346, ++0xD54464E3, 0x62032008, 0x0029150F, 0x6603CA01, ++0x2668E03B, 0x05648D20, 0xC8F06023, 0xD53F8909, ++0x76FF6650, 0x84512560, 0x805170FF, 0x70FF8452, ++0x60238052, 0x890FC80F, 0x6260D639, 0x26207201, ++0x70018461, 0x84628061, 0xA0057001, 0xD6318062, ++0xE03BE200, 0x162F0624, 0x4008E05B, 0x964302FE, ++0x8B653266, 0xD72BD428, 0xD52E6040, 0x4028C93F, ++0x40084008, 0x50726203, 0xC802D12B, 0xE604891A, ++0x46284618, 0x2522226B, 0xE2086040, 0x6503C93F, ++0x66034508, 0x45004508, 0x46284218, 0x6263252B, ++0x42084208, 0x252B4200, 0x4218E208, 0x252B4228, ++0x2152A062, 0x4618E614, 0x226B4628, 0x60402522, ++0xC93FE428, 0x45086503, 0x45084028, 0x45004008, ++0x40084418, 0x254BE728, 0x47184000, 0x4728250B, ++0xD412257B, 0x2152A044, 0x064D09B4, 0x001148E0, ++0x001148BA, 0x00114934, 0x00114000, 0x00114008, ++0x00114774, 0x00114011, 0x001142FD, 0x00114301, ++0x00114309, 0x001142D8, 0x00114A24, 0x001142F5, ++0x001142ED, 0x001C3694, 0x001C3BB4, 0x001142E8, ++0xE214D429, 0x42186040, 0x4028C93F, 0x40084008, ++0xD6264228, 0x2602202B, 0xE7286040, 0x6503C93F, ++0x45084508, 0x45004028, 0x40084718, 0x4008257B, ++0x4000E728, 0x250B4718, 0xD21D4728, 0x2252257B, ++0xD71C6240, 0x0724E044, 0x3F3C932C, 0x4F164F06, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x2FE668F6, 0x6243D114, 0xE4028512, 0x6E2D670D, ++0xE500A00F, 0x6053655D, 0x305C4000, 0x4008D10F, ++0x622D021D, 0x8B0332E0, 0x041C7108, 0x644CA004, ++0x625D7501, 0x8BED3273, 0x4618E602, 0x604D2469, ++0x6EF6000B, 0x000001F0, 0x001142E8, 0x001C3694, ++0x001C3BB4, 0x001142D8, 0x00114000, 0x00114008, ++0xD766D565, 0x62725151, 0x321CE340, 0x51522722, ++0x337C5271, 0x1721321C, 0x52725153, 0x321C644C, ++0x1722D15F, 0x66125255, 0x2162362C, 0x316C5173, ++0x61521713, 0xD65B5274, 0x1724321C, 0x52755154, ++0x1725321C, 0x52765158, 0x1726321C, 0x51776262, ++0x1717312C, 0x51785261, 0x1718312C, 0x51795262, ++0x1719312C, 0x517A5263, 0x171A312C, 0x517B5264, ++0x171B312C, 0x517C5265, 0x171C312C, 0x517D5266, ++0x171D312C, 0x517E5267, 0x171E312C, 0x527F5168, ++0x321CD645, 0x6262172F, 0x76946132, 0x2312312C, ++0x52316162, 0x321CD641, 0x515C1321, 0x351C5532, ++0x61621352, 0x41295235, 0x1325321C, 0x56365561, ++0x365C4529, 0x1366E538, 0x55312450, 0x71046143, ++0x66722152, 0x75086543, 0x56712562, 0x750C6543, ++0x56722562, 0x75106543, 0x56752562, 0x75146543, ++0x56732562, 0x75186543, 0x56762562, 0x751C6543, ++0x56322562, 0x75206543, 0x66322562, 0x75246543, ++0x56742562, 0x75286543, 0x56342562, 0x752C6543, ++0x55332562, 0x72306243, 0x55352252, 0x72346243, ++0x56362252, 0x24627438, 0x1341E400, 0x17412742, ++0x17451742, 0x17461743, 0x23421342, 0x13441744, ++0x13451343, 0x1346000B, 0xD510E124, 0x51572410, ++0x52581411, 0x57591422, 0x515A1473, 0x525B1414, ++0x575C1425, 0x525D1476, 0x1427E700, 0x1468565E, ++0x1469565F, 0x15781577, 0x157A1579, 0x157C157B, ++0x157E157D, 0x157F000B, 0x001C369C, 0x0020351C, ++0x00203578, 0x001C3CA0, 0x001C36F4, 0x001C3B88, ++0x6E726157, 0x21676E69, 0x69685420, 0x6F642073, ++0x656C676E, 0x746F6E20, 0x65656220, 0x6163206E, ++0x7262696C, 0x64657461, 0x0000000A, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++}; ++ ++const u32_t zcFwBufImageSize=83968; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwspiu.c +@@ -0,0 +1,655 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++ ++const u32_t zcFwImageSPI[]={ ++0x0009000B, 0x4F222FE6, 0xB0187FFC, 0xE6000009, ++0x943DD520, 0xC8406052, 0x2F028F03, 0x8FF93642, ++0xD41D7601, 0x4E0BDE1D, 0xD41D0009, 0x00094E0B, ++0x4E0BD41C, 0x7F040009, 0xA0214F26, 0x4F226EF6, ++0xE205D119, 0x2122E400, 0x92222142, 0x8BFD4210, ++0x450BD516, 0xD6160009, 0x0009460B, 0xE5FFD715, ++0x2752655D, 0xE1FFD714, 0xD4145079, 0x1709CB01, ++0x17112712, 0x2412E101, 0x4F26D411, 0x2410000B, ++0xDE11DD10, 0x00094D0B, 0x00094E0B, 0x0009AFFA, ++0x03E82710, 0x001C001C, 0x00116594, 0x00114EBE, ++0x001165A4, 0x001165BC, 0x001D4004, 0x00114FA0, ++0x00114378, 0x001C3510, 0x001C3624, 0x001E212C, ++0x001164FC, 0x00114700, 0x0011589C, 0x2FA62F96, ++0x2FC62FB6, 0x2FE62FD6, 0x7FC84F22, 0xD28DDD8C, ++0x61D360D0, 0x80F47101, 0x420B6010, 0x200880F8, ++0x6E038F10, 0xDB89D488, 0xD4896A40, 0x4B0BDC89, ++0x67C065AC, 0x697CDE88, 0x41086193, 0x31984108, ++0x3E1C4108, 0x66D284F8, 0x2008600C, 0x2E628F13, ++0xE40084F4, 0xDA81670C, 0x3273624D, 0xA0D38B01, ++0x644D0009, 0x35AC6543, 0x69436652, 0x39EC6B62, ++0xAFF119B1, 0x88017404, 0x84F48B15, 0x2E70E700, ++0xDA766E0C, 0x32E3627D, 0xA0C48B01, 0x677D0009, ++0x6C7366A3, 0x65737604, 0x356C3CAC, 0x6D5264C2, ++0xAFEF7708, 0xE2B024D2, 0x3020622C, 0x84F48B30, ++0x650CEC00, 0xDA691F53, 0x55F3E904, 0x325362CD, ++0xA0A88B01, 0x6CCD0009, 0x67C36EA3, 0x6BC37E04, ++0x3BEC37AC, 0x6EB26D72, 0xDB62D461, 0x00094B0B, ++0x410BD161, 0xD46164D3, 0x00094B0B, 0x450BD55E, ++0xD45F64E3, 0x00094B0B, 0x61D3E600, 0x316C666D, ++0x646D7601, 0x21E03493, 0x4E198FF7, 0x7C08AFD5, ++0x622CE2B1, 0x8B113020, 0xD552D456, 0xDA56DC4F, ++0x0009450B, 0x4A0BE400, 0xD75467C2, 0x470BDB52, ++0x4B0B0009, 0xE900E403, 0x2E90A06D, 0x622CE2B2, ++0x89683020, 0x622CE2B3, 0x8B1D3020, 0xDA45D44C, ++0x4A0BD942, 0x65960009, 0x6792D44A, 0x1F74DD3B, ++0x1F5D4D0B, 0xD639D448, 0x460BDB48, 0x55F455F4, ++0x4B0BD936, 0xD44654FD, 0x490B6503, 0x5DF51F05, ++0x1ED1EC04, 0x2EC0A047, 0x622CE2B4, 0x8B3E3020, ++0xDA34D440, 0x4A0BDD31, 0x84F40009, 0x600C6CD2, ++0x1F072F02, 0x1FC6C903, 0xE6001F08, 0xD73AE030, ++0x6CF2DB3A, 0x1F790F65, 0xA0211FBA, 0x51F6E904, ++0x6D63666D, 0x4C1536EC, 0xD2353D1C, 0x1F6B8F05, ++0x89023C93, 0xA00264D3, 0xE50455F8, 0x420B64D3, ++0x5BFB0009, 0xD61954FA, 0x460B65D3, 0x54F91B01, ++0xDA1655B1, 0x7CFC4A0B, 0x06FDE030, 0x0F657604, ++0x626D55F7, 0x8BDA3253, 0xA00484F4, 0xD4252E00, ++0x420BD20E, 0x7F3865D2, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x69F6000B, 0xE6006163, 0x4109A004, ++0x76016256, 0x74042422, 0x8BF93612, 0x0009000B, ++0x00117800, 0x00115FF0, 0x001164F6, 0x00114F2C, ++0x001165C0, 0x001164F5, 0x0011611C, 0x00117804, ++0x001165E0, 0x00114EBE, 0x00114F02, 0x001165F4, ++0x001165FC, 0x00116600, 0x00114BF0, 0x001148FC, ++0x00116618, 0x00116634, 0x00116640, 0x00114E56, ++0x0011664C, 0x00116658, 0x0011667C, 0x00116670, ++0x00114BC4, 0x00116688, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE5007FD8, 0x6453E110, ++0x6C534128, 0x655DEE0A, 0x46086653, 0x4608365C, ++0x361C7501, 0x675D6043, 0x60C30F66, 0x37E3ED00, ++0x816126C1, 0x81638162, 0x16D316D2, 0x8FEA16D4, ++0x68F27404, 0xDAB3D9B2, 0x29821981, 0xD1B259F1, ++0x2A921A91, 0x5BF35AF2, 0x5EF55DF4, 0x11A154F6, ++0x11B321A2, 0x11D511B2, 0x11E711D4, 0x114911E6, ++0x55F71148, 0xEE00DBA9, 0xDDA957F8, 0xD6A952F9, ++0x1B5164E3, 0xDBA82B52, 0xEAB8D8A8, 0x2D72E945, ++0x6AAC2622, 0x6EED4908, 0x4D086DE3, 0x3DEC61E3, ++0x4D084108, 0x3DBC31EC, 0x410860C3, 0x81D12DC1, ++0x4108E050, 0x41084008, 0x60C381D2, 0xE500318C, ++0x81D334A2, 0x1D131DD2, 0x8D01D494, 0xD4911D54, ++0xB08165D3, 0x64ED7E01, 0x8BDC3492, 0xDB94D18D, ++0xD28B6812, 0x1B814829, 0x2FD26412, 0x2B92694D, ++0xD98A6722, 0x1B734729, 0xD7876822, 0x1BA26A8D, ++0xD28C6B72, 0x22B2D586, 0xE0035D72, 0x5E7412D2, ++0x12E44018, 0xD6885176, 0x54781216, 0x1248E1FF, ++0xD4856792, 0x6852127A, 0x28C1E703, 0x81916952, ++0x6A52E050, 0x81A24008, 0x60C36B52, 0x6D5281B3, ++0x6E521DD2, 0x62521E63, 0x1264E600, 0x46086563, ++0x7501364C, 0x665D2612, 0x8BF83673, 0xE003D471, ++0x40186542, 0x674225C1, 0x8171D274, 0xEE006842, ++0x69421882, 0x1923E024, 0xE5806A42, 0x6B421AE4, ++0x81B266E3, 0xD46D6C42, 0x655C81C3, 0x6D63666D, ++0x616D7604, 0x31533D4C, 0x2DE28FF8, 0xD569D268, ++0x74042422, 0x7F282452, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x000B69F6, 0x664268F6, 0xC8036061, ++0xE5008D04, 0xC9036061, 0x8B038802, 0x65635262, ++0x24125124, 0x6053000B, 0x2FE62FD6, 0x7FEC4F22, ++0x62536E53, 0x6D43E550, 0x4508E400, 0xE101A001, ++0x60435224, 0x81212211, 0x60538123, 0x56E28122, ++0x8BF53620, 0x16E4D250, 0xE61464F3, 0x65E3420B, ++0xE4FC65E1, 0x2E512549, 0x65F361F1, 0x2F112149, ++0xD14954D1, 0xE614410B, 0x607157D1, 0x2701CB01, ++0x7F141DE1, 0x6EF64F26, 0x6DF6000B, 0x2FE62FD6, ++0x7FEC4F22, 0x66536E53, 0x6D43E5FC, 0x20596061, ++0x2601CB01, 0x326052E2, 0x12E48B06, 0x31E051E2, ++0x52D18B04, 0x1E22A002, 0x5664AFF0, 0x64F3D236, ++0x420BE614, 0x67E165E3, 0x2719E1FC, 0x67F12E71, ++0x271954D1, 0x65F3D130, 0x410BE614, 0x52D12F71, ++0xCB016021, 0x1DE12201, 0x4F267F14, 0x000B6EF6, ++0x2FE66DF6, 0x624C4F22, 0x4208DE1B, 0xA0054200, ++0x52523E2C, 0x5624D417, 0x2E62BF8E, 0x52E165E2, ++0x8BF63520, 0x2622D61B, 0x000B4F26, 0x2FB66EF6, ++0x2FD62FC6, 0x4F222FE6, 0xDB1CDC10, 0x66C252C1, ++0x89403620, 0xC9036061, 0x893C8801, 0xDD18DE0B, ++0x64E3BF63, 0x85036503, 0x620D66B2, 0x892B3262, ++0xBF9BD403, 0xD4130009, 0x00094D0B, 0x0009AFE6, ++0x001160DC, 0x001160E4, 0x001160EC, 0x00116114, ++0x001164F8, 0x00116500, 0x001000C8, 0x00101680, ++0x001E2108, 0x001C3D00, 0x00117880, 0x00117780, ++0x00040020, 0x0026C401, 0x001142F8, 0x001164DC, ++0x00114EBE, 0x0011669C, 0x64E3BF3E, 0x4D0BD406, ++0xAFBB0009, 0xD2050009, 0x4F262262, 0x6DF66EF6, ++0x000B6CF6, 0x00006BF6, 0x001166A0, 0x001C3D28, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xD23C7FFC, 0xC8036022, 0x2F018F3D, 0x0009A061, ++0xC9036061, 0x893B8801, 0xD238D837, 0x420BD938, ++0xE4006483, 0x6A036D03, 0x5C02490B, 0xD236DB35, ++0x56D385D2, 0x650D6422, 0x4B0BE740, 0xD1326E03, ++0x64126EED, 0x214234EC, 0x3DC05DD4, 0x85D28BEF, ++0x70FF56D3, 0xE740650D, 0x6C034B0B, 0x490BDB2A, ++0x66B2E403, 0x36CC6CCD, 0xE700D928, 0x2B62E5C8, ++0x6473E650, 0x490BDC26, 0x6483655C, 0x65A34C0B, ++0xEE01D124, 0xD11C21E2, 0x66125211, 0x8BBF3620, ++0xDD22DE21, 0xDC23DB22, 0x65D252D1, 0x89183520, ++0xC9036051, 0x89148801, 0xD114D41C, 0x0009410B, ++0x36E05603, 0x65038F04, 0x2B20E201, 0x2C52AFEC, ++0xD213D419, 0x0009420B, 0xE101D618, 0xAFE34118, ++0x60F12612, 0x8902C804, 0x420BD215, 0x7F040009, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x000068F6, 0x001E2100, 0x001160E4, 0x0011453A, ++0x00114BF0, 0x00114E0C, 0x00116714, 0x001159B0, ++0x00114558, 0x001E212C, 0x00117880, 0x001160DC, ++0x001164FC, 0x001164F8, 0x00116114, 0x001C3D30, ++0x001140CC, 0xD6C2D5C1, 0x26226252, 0xC8016060, ++0x000B8BFA, 0x2FE60009, 0xBFF34F22, 0xD2BD0009, ++0xE405E100, 0x22402212, 0x6422DEB8, 0xE700D5B8, ++0x25721E42, 0xC98F8451, 0xC9F0CB10, 0x8051CB02, ++0xCB026050, 0x62522500, 0x2E22BFDC, 0xD6B250E4, ++0x4F262602, 0x6EF6000B, 0x4F222FD6, 0x0009BFDB, ++0x620CDDAE, 0x60D02D22, 0x8906C801, 0x0009BFD3, ++0x2D22620C, 0xC80160D0, 0x4F268BF8, 0x6DF6000B, ++0x4F222FE6, 0x6E43BFE8, 0xE100D2A2, 0x22E02212, ++0x6422D59E, 0xE600DE9E, 0x2E621542, 0xC9F084E1, ++0x80E1CB01, 0xCB0260E0, 0x67E22E00, 0x4F262572, ++0x6EF6AFA8, 0xE406AFE4, 0xE404AFE2, 0xBFF94F22, ++0xE4C70009, 0x644CBFDC, 0x4F26AFF6, 0xE406AFD8, ++0xE404AFD6, 0x4F222FE6, 0x6E43BFF8, 0xD58DD28D, ++0xE401E100, 0x221260E3, 0x80512240, 0x6622D187, ++0xE700DE87, 0x2E721162, 0xC9F084E1, 0x80E1CB02, ++0xCB0260E0, 0x62E22E00, 0x2122BF7C, 0xAFDF4F26, ++0x2FD66EF6, 0x4F222FE6, 0xBFCB6D53, 0xBF9B6E43, ++0xD27C0009, 0x22E061D3, 0x6022DE7D, 0x411821E9, ++0x201BC9FF, 0x2202D577, 0xD6768453, 0x60D38051, ++0xD4728053, 0xD1726762, 0x1472ED00, 0x841121D2, ++0xCB04C9F0, 0x60108011, 0x2100CB02, 0xBF516212, ++0x4F262422, 0xAFA76EF6, 0x65436DF6, 0xAFD0E4D8, ++0x6543644C, 0xAFCCE4D8, 0x2FC6644C, 0x2FE62FD6, ++0x6E534F22, 0xBF676D43, 0xD7626C63, 0x27D0D264, ++0x61E36072, 0x41182129, 0x201BC9FF, 0x2702D45D, ++0xD15B8443, 0x60E38041, 0xDE588043, 0xE6006472, ++0x21621E42, 0x65DC8411, 0x60C36203, 0x4008C907, ++0x67034008, 0xE29F6023, 0x622CC98F, 0x3520207B, ++0x80118D18, 0x7C048411, 0x60C36603, 0x6203C90F, ++0xC9F06063, 0x8011202B, 0x880B6053, 0x84118B14, ++0xC90F6603, 0xC90F7001, 0x60636203, 0x202BC9F0, ++0x8011A00A, 0x7C018411, 0x60C36603, 0x6203C90F, ++0xC9F06063, 0x8011202B, 0xCB026010, 0x62122100, ++0x2E22BEF0, 0xD63C50E4, 0x4F262602, 0x6DF66EF6, ++0x6CF6000B, 0x2FC62FB6, 0x2FE62FD6, 0x6C634F22, ++0x6E436D53, 0x6B73BF36, 0x0009BF06, 0x61D3D231, ++0xDE3322E0, 0x21E96022, 0xC9FF4118, 0xD42D201B, ++0x84432202, 0x8041D72F, 0x804360D3, 0x6622D427, ++0x1462D127, 0x14C327C2, 0x21C2EC00, 0x7B048411, ++0x60B36D03, 0x6503C90F, 0xC9F060D3, 0x8011205B, ++0xCB026010, 0x62122100, 0x4F262422, 0x6DF66EF6, ++0xAEAF6CF6, 0x2FB66BF6, 0x2FD62FC6, 0x4F222FE6, ++0x6C536D63, 0xBEFD6E43, 0xBECD6B73, 0xD2150009, ++0x22E061C3, 0x6022DE16, 0x411821E9, 0x201BC9FF, ++0x2202D110, 0xD60F8413, 0x60C38011, 0xDE0B8013, ++0xD40B6762, 0xEC006BBD, 0x1EB51E72, 0x844124C2, ++0xC9F04B21, 0x8041CB04, 0xE1406040, 0x2400CB06, ++0xE5006242, 0x4B212E22, 0x4128A014, 0x001D1200, ++0x00116528, 0x00116530, 0x00116538, 0x00116544, ++0x00FFFFFF, 0x00116534, 0x6053655D, 0x06DE4008, ++0x21627501, 0x32B3625D, 0x4F268BF6, 0x6DF66EF6, ++0xAE5F6CF6, 0x4F226BF6, 0xBF73677C, 0xAEB3644C, ++0x4F224F26, 0xBFA6677D, 0xAEAD644C, 0x4F224F26, ++0xE500E49F, 0xBF08E603, 0x4F26644C, 0x600C000B, ++0xE49F4F22, 0xE603E500, 0x644CBEFF, 0x4F264019, ++0x600D000B, 0x6543665C, 0xE403AEF7, 0x6543665C, ++0xE40BAEF3, 0xD175D674, 0x60436262, 0xC8012122, ++0x8F016010, 0xC9EFCB10, 0x62122100, 0x2622000B, ++0x4F222FE6, 0xE0004F13, 0xBE2C401E, 0xD56C6E43, ++0x2522620C, 0xE401BFE6, 0x6063D669, 0x60ECCF80, ++0x89072008, 0x89098801, 0x890D8802, 0x89118803, ++0x0009A013, 0xC9E36060, 0x2600A00F, 0xCB106060, ++0xCB04C9F7, 0x2600A009, 0xCB106060, 0xCB08C9FB, ++0x2600A003, 0xCB1C6060, 0xD5592600, 0xBE616252, ++0xE400642C, 0x4F264F17, 0x6EF6AFBC, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0x60C36C7C, ++0x6A638802, 0x69538F09, 0x65436290, 0x662CE4AF, ++0xBEF7E701, 0xA00A644C, 0x2CC80009, 0x88018901, ++0x65438B05, 0xE600E4AF, 0xBEEBE701, 0xBDD1644C, ++0xED010009, 0xDE43EBAF, 0xE800A02C, 0x0009BDF4, ++0x60C3D141, 0x8802E200, 0xD5402122, 0x21B08D06, ++0x89082CC8, 0x890A8801, 0x0009A00C, 0x009C60D3, ++0xA007D639, 0xD2388061, 0xA0036083, 0xD2368021, ++0x802160D3, 0xD1356412, 0x1E42E600, 0x84512162, ++0xC9F07D01, 0x8051CB02, 0xCB026050, 0x67122500, ++0x2E72BDA0, 0x8BD13DA2, 0x0009BDF6, 0x0009BDA3, ++0x620CD627, 0x4F262622, 0x6DF66EF6, 0x6BF66CF6, ++0x69F66AF6, 0x68F6000B, 0xE702AF98, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0x3F3C9331, ++0x0F569030, 0xE8FF70FC, 0x688C0F46, 0xE900A049, ++0x4018E010, 0xE50404FE, 0xBF33349C, 0x88FF6A43, ++0x901F893E, 0xE1100CFE, 0x41183C98, 0x8B033C16, ++0x64A3BE1B, 0x0009A031, 0x4018E010, 0xED000BFE, ++0xA0073BCC, 0x64D36EF3, 0xBF1F34BC, 0x2E00E501, ++0x7E017D01, 0x8BF63DC2, 0x64A3BE07, 0xA01AED00, ++0xEFF86EF3, 0x00001004, 0x001D1204, 0x0011652C, ++0x00116544, 0x001D1200, 0x00116530, 0x00116528, ++0x666C66E0, 0x89043680, 0x35BC65D3, 0xBE51E701, ++0x7D01E402, 0x3DC27E01, 0xE1108BF2, 0x391C4118, ++0x90547904, 0x391201FE, 0x93518BB2, 0x4F263F3C, ++0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, 0x68F6000B, ++0x676D6253, 0x66236543, 0xE402AEC3, 0x2FA62F96, ++0x2FC62FB6, 0x2FE62FD6, 0x697D4F22, 0x4A216A93, ++0x4A084A21, 0x6C436D63, 0xA0086B73, 0x64C36E53, ++0x669365D3, 0x6BBDBFE4, 0x3DAC3CBC, 0x6EEF3EB8, ++0x8BF42EE8, 0x4F26E000, 0x6DF66EF6, 0x6BF66CF6, ++0x000B6AF6, 0x2FA669F6, 0x2FC62FB6, 0x2FE62FD6, ++0xEC004F22, 0x6B536EC3, 0xA0066D43, 0x64D3EA01, ++0x65A3BEA8, 0x7D013C0C, 0x3EB27E01, 0x60C38BF7, ++0x6EF64F26, 0x6CF66DF6, 0x000B6BF6, 0x10046AF6, ++0x00001008, 0x0009000B, 0x2FD62FC6, 0x4F222FE6, ++0x6D436C53, 0xEE00A004, 0x7E0164D4, 0x644CBFF2, ++0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, 0xE5006CF6, ++0x6643A002, 0x76017501, 0x22286260, 0xAFE38BFA, ++0x2FE60009, 0x75076253, 0xE1086753, 0x6043EE0A, ++0x4409C90F, 0x650330E2, 0x8D014409, 0xE630E637, ++0x4110365C, 0x8FF22760, 0xE00077FF, 0x000B8028, ++0x4F226EF6, 0xBFE47FEC, 0xBFD865F3, 0x7F1464F3, ++0x000B4F26, 0x4F22E000, 0xBFDA7FEC, 0x64F365F3, ++0x7406BFCD, 0x4F267F14, 0xE000000B, 0x4F222FE6, ++0x62537FEC, 0x65F36E43, 0x6423BFCB, 0x64E3BFBF, ++0x64F3BFBD, 0xBFBAD403, 0x7F140009, 0x000B4F26, ++0x00006EF6, 0x001166A4, 0xE4FDD29A, 0xD79A6122, ++0x22122149, 0x74016022, 0x2202CB01, 0xD5976622, ++0x22622649, 0xC8406070, 0x60528902, 0x2502CB04, ++0xE1F76452, 0x25422419, 0xE7016052, 0x2502C9CF, ++0xE6026052, 0x2502CB03, 0x15624718, 0x1573000B, ++0xD78CD58B, 0xD48DD28C, 0xE600E100, 0x27112511, ++0xAFD12210, 0x664C2461, 0x4600D289, 0x6060362C, ++0x000BCB10, 0x654C2600, 0x4500D285, 0x6650352C, ++0x2619E1EF, 0x2560000B, 0xD282664C, 0x362C4600, ++0xCB106060, 0x2600000B, 0xD27E654C, 0x352C4500, ++0xE1EF6650, 0x000B2619, 0x664C2560, 0x4600D278, ++0x6060362C, 0x000BCB08, 0x654C2600, 0x4500D274, ++0x6650352C, 0x2619E1F7, 0x2560000B, 0xD271664C, ++0x362C4600, 0xCB086060, 0x2600000B, 0xD26D654C, ++0x352C4500, 0xE1F76650, 0x000B2619, 0x624C2560, ++0x4200D667, 0x6020326C, 0x4021C908, 0x40214021, ++0x600C000B, 0xD663624C, 0x326C4200, 0xC9086020, ++0x40214021, 0x000B4021, 0xD15F600C, 0x341C644C, ++0x000B6240, 0xD15D602C, 0x341C644C, 0x000B6240, ++0x2FE6602C, 0x6E434F22, 0xE60A645C, 0x89143467, ++0x0009BFEB, 0x60EC640C, 0x8B028801, 0xA002E00F, ++0x44092409, 0x624C4409, 0x3263E60A, 0xBFE28905, ++0x620C644C, 0xC8806023, 0xE2008B00, 0x4F266023, ++0x6EF6000B, 0xD64A4F22, 0x88016062, 0xB2458B03, ++0xA0030009, 0xD2470009, 0x2260E640, 0xE200D646, ++0x000B4F26, 0x4F222622, 0x6062D641, 0x8B018802, ++0x0009B28E, 0xE200D640, 0x000B4F26, 0xD53C2622, ++0xE100D43C, 0x2512E701, 0x2470000B, 0xE604D239, ++0x2260000B, 0xD4394F22, 0x410BD139, 0xD5390009, ++0x6650E1FD, 0x2619D238, 0x2560E700, 0x000B4F26, ++0x4F222270, 0xD132D435, 0x0009410B, 0xE7FBD531, ++0x26796650, 0x000B4F26, 0x4F222560, 0xD12CD430, ++0x0009410B, 0xE7F7D52B, 0x26796650, 0x000B4F26, ++0xD5282560, 0x6250942D, 0x000B2249, 0xD5252520, ++0x6250E4BF, 0x000B2249, 0x4F222520, 0x8522D225, ++0x2008600D, 0x88018911, 0x88038913, 0x88058915, ++0x88068942, 0x88088948, 0x8809894E, 0x880A8954, ++0x880B895A, 0xA0678960, 0xB0690009, 0xA0640009, ++0xB077600C, 0xA0600009, 0xB080600C, 0xA05C0009, ++0xFF7F600C, 0x001E2148, 0x001E1000, 0x001E1108, ++0x00116570, 0x00116572, 0x00116591, 0x00116554, ++0x001E103F, 0x001E105F, 0x001E102F, 0x001E1090, ++0x00116578, 0x001E100B, 0x00116574, 0x001166A8, ++0x00114EBE, 0x001E1028, 0x00116590, 0x001166B4, ++0x001166C4, 0x00116548, 0x6260D684, 0x8B2B2228, ++0x0009B061, 0x600CA029, 0x6260D680, 0x8B232228, ++0x0009B069, 0x600CA021, 0x6260D67C, 0x8B1B2228, ++0x0009B0C7, 0x600CA019, 0x6260D678, 0x8B132228, ++0x0009B0CD, 0x600CA011, 0x6260D674, 0x8B0B2228, ++0x0009B125, 0x600CA009, 0x6260D670, 0x8B032228, ++0x0009B13D, 0x600CA001, 0x4F26E000, 0x0009000B, ++0xD26CD16B, 0xD56C8412, 0x4000C90F, 0xD76B012D, ++0xE403D66B, 0xE20F611C, 0x2540E001, 0x25202712, ++0x2602000B, 0xE601D262, 0x30668523, 0xE0008D05, ++0xD663D260, 0xE0018122, 0x000B2602, 0xD25C0009, ++0x600D8523, 0x89052008, 0x8B0A8801, 0x6060D65D, ++0x2600CB01, 0xD457D65A, 0xE001E101, 0x000B2612, ++0x000B8142, 0xD152E000, 0x8513E501, 0x640D4518, ++0x66033453, 0xE0008D05, 0xD551D253, 0x2260E001, ++0x000B2502, 0x4F220009, 0x8513D149, 0x6453650D, ++0x62494419, 0x227D672E, 0x8801602C, 0x88028909, ++0x88038910, 0x8806891A, 0x88078935, 0xA04C893B, ++0xD5460009, 0x6652D746, 0x2762D446, 0x622C6261, ++0x2421A038, 0x2228625C, 0xD4438B3F, 0x6642D540, ++0x2562D440, 0x24018561, 0x6203A02C, 0x2008605C, ++0x88108907, 0x88208908, 0x88308909, 0xA02C890A, ++0xD23A0009, 0x6222A008, 0xA005D239, 0xD2396222, ++0x6222A002, 0x6262D638, 0xD432D531, 0x66212522, ++0xA00F626C, 0xD6352421, 0x6261D52D, 0x622CD42D, ++0xA0072562, 0xD6322421, 0x8561D529, 0x2562D429, ++0x62032401, 0x662D8515, 0x3617610D, 0x65038F01, ++0xB0CB2451, 0xA0010009, 0xE000E001, 0x000B4F26, ++0xD6190009, 0xD427E101, 0x65412610, 0xD118D717, ++0xE20F655D, 0x2752E001, 0x000B2620, 0x2FE62102, ++0xD20F4F22, 0x640C8523, 0x8B082448, 0xD511D61D, ++0x2621E200, 0x940F8451, 0xA0482049, 0xDE0D8051, ++0xC84060E0, 0xE2018D32, 0x89443427, 0xD216D615, ++0x2641420B, 0x0009A030, 0x0000FF7F, 0x00116591, ++0x00116548, 0x00116554, 0x001E1100, 0x001E100C, ++0x00116574, 0x001E1000, 0x001E1001, 0x0011657C, ++0x0011655C, 0x00116560, 0x00116564, 0x00116580, ++0x00116584, 0x00116588, 0x0011658C, 0x00116774, ++0x0011677E, 0x0011656E, 0x00115DCA, 0x89123427, ++0xD294D693, 0x2641420B, 0xCB8084E1, 0x80E1B0F5, ++0xD69160E0, 0x2E00CB04, 0xC93F6060, 0xD68F2600, ++0xA001E001, 0xE0002602, 0x000B4F26, 0xD68C6EF6, ++0xC8806060, 0xD2868919, 0x88016021, 0xD2898B15, ++0x8524E501, 0x89103056, 0xE203D187, 0x2120D487, ++0xE00B6541, 0x0656655D, 0xE40FD585, 0x2140E702, ++0xD77E2571, 0x000BE001, 0x000B2702, 0x2FE6E000, ++0xDE804F22, 0xC88084E1, 0xD57A892C, 0x20088554, ++0x61038F28, 0x8553D77C, 0x64036672, 0x8566650C, ++0x3520620C, 0xD6798B1E, 0x651CD774, 0x2651644C, ++0x60E02741, 0x8904C840, 0x420BD275, 0xA0030009, ++0xD2680009, 0x0009420B, 0x0009B09F, 0xE201D167, ++0x60E02122, 0xCB04D464, 0x60402E00, 0x2400C93F, ++0x6023A001, 0x4F26E000, 0x6EF6000B, 0x2FB62FA6, ++0x2FD62FC6, 0xDA622FE6, 0x66A1E240, 0x3622DC5E, ++0x62638900, 0x6ED36D2C, 0x4E2136D8, 0x4E212A61, ++0xDB61D460, 0xE700A00F, 0x770162B2, 0x71026123, ++0x66212B12, 0x71026213, 0x61212B12, 0x651D666D, ++0x356C4528, 0x627C2452, 0x8BED32E3, 0xC90360D3, ++0x8B108803, 0x617367B2, 0x2B127102, 0x71026E13, ++0x2B126571, 0x655D6DE1, 0x422862DD, 0x325CE107, ++0xA00C2C10, 0x88022422, 0xA0038B01, 0x8801E203, ++0xE2018B05, 0x66B22C20, 0x655D6561, 0xE60F2452, ++0x67A12C60, 0x8B052778, 0xDD38DC44, 0xEB01EA00, ++0x2DB22CA2, 0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, ++0x2FE62FD6, 0xE240DD36, 0x362266D1, 0x62638900, ++0x3678672C, 0x7703DE38, 0x47212D61, 0x64E2D635, ++0xA00E4721, 0x6562E100, 0x62537101, 0x74012450, ++0x24204219, 0x45297401, 0x74012450, 0x24504519, ++0x621C7401, 0x8BEE3273, 0x66E24200, 0x420061D1, ++0x2118362C, 0x2E628F06, 0xDD1CD728, 0xE501E400, ++0x2D522742, 0x000B6EF6, 0x2FD66DF6, 0x4F222FE6, ++0xED0AEE01, 0x64E3BC97, 0xBC9C64E3, 0x62EC7E01, ++0x8BF732D7, 0xBC9FEE01, 0x64E364E3, 0x7E01BCA4, ++0x32D762EC, 0x4F268BF7, 0x000B6EF6, 0xD1186DF6, ++0xD418920D, 0x72122122, 0x2422D617, 0xD7177204, ++0x72202622, 0x2722D116, 0x000B7230, 0x137A2122, ++0x0011656E, 0x00115ED6, 0x001E1015, 0x00116574, ++0x001E1001, 0x00116548, 0x001E1100, 0x00116572, ++0x00116560, 0x001E1000, 0x00116564, 0x00116570, ++0x00115DCA, 0x001E100C, 0x0011655C, 0x00116578, ++0x0011657C, 0x00116580, 0x00116584, 0x00116588, ++0x0011658C, 0x4F222FE6, 0xD6507FFC, 0x88016060, ++0xE2018951, 0x2620BFBB, 0xD54ED14D, 0xDE4E6010, ++0x64E36552, 0x7402C840, 0x8D22D14C, 0xD24C7502, ++0xE601D74C, 0xE7042722, 0x76016255, 0x626C2421, ++0x8FF93273, 0xD4437402, 0x6242E601, 0x640D8528, ++0x67494419, 0x275D657E, 0x81E4607C, 0xE417D542, ++0x67557601, 0x3243626C, 0x8FF92171, 0xA0207102, ++0xD23E0009, 0xE601D73B, 0xE7042722, 0x76016255, ++0x626C2421, 0x8FF93273, 0xD4327402, 0x6242E601, ++0x640D8528, 0x67494419, 0x275D657E, 0x81E4607C, ++0xE417D533, 0x67557601, 0x3243626C, 0x8FF92171, ++0x924A7102, 0xD2262E21, 0x5E23D72E, 0x64F22FE2, ++0x604365F2, 0x2700C980, 0xC9606043, 0x80716103, ++0xC9036043, 0x80724519, 0x65F2605C, 0x817266F2, ++0x46194629, 0x606C4529, 0x4018645C, 0x8173304C, ++0x21185E23, 0x64F22FE2, 0x6E4C62F2, 0x602C4219, ++0x66F262F2, 0x46294018, 0x461930EC, 0x42298174, ++0x652C606C, 0x305C4018, 0x81758F07, 0x0009BC9D, ++0x2228620C, 0xA00A8908, 0x60130009, 0x8B038840, ++0x0009B009, 0x0009A003, 0xE202D60F, 0x7F042622, ++0x000B4F26, 0x000B6EF6, 0x060A0009, 0x00116590, ++0x001E1000, 0x0011657C, 0x00116774, 0x00116780, ++0x00116718, 0x00116564, 0x00116748, 0x00116746, ++0x0011671A, 0x00116548, 0x00116574, 0x4F222FE6, ++0x84E9DE8E, 0x2448640C, 0xB18B8901, 0xD28C0009, ++0x26686620, 0x60E08902, 0x2E00C9BF, 0x000B4F26, ++0x000B6EF6, 0x2FE60009, 0xDE864F22, 0x60E0D686, ++0xCBC0D486, 0x62602E00, 0xC803602C, 0x40218904, ++0x70014021, 0x6603A002, 0x66034009, 0xD680616D, ++0xE500A004, 0x75016262, 0x74042422, 0x3213625D, ++0xD27C8BF8, 0x0009420B, 0xC9BF84E2, 0x4F2680E2, ++0x6EF6000B, 0x2FE62FD6, 0x7FFC4F22, 0x6260D676, ++0x89402228, 0xD56DE100, 0x60502610, 0xCB40D473, ++0x2500440B, 0x8D052008, 0x62E06E03, 0x7104612C, ++0x2F11A006, 0xD46ED666, 0xDD6E6760, 0x657C4D0B, ++0xE23C6D1D, 0x8B033D27, 0xD26CD46B, 0x0009420B, ++0x4D214D21, 0xA005D76A, 0x66E6E400, 0x357C4508, ++0x74012562, 0x35D3654D, 0xD7668BF7, 0x6E72E003, ++0x81E14018, 0x6E7260F1, 0x81E2700C, 0xD4626172, ++0xDD628113, 0x65724D0B, 0xD652D261, 0x2212E101, ++0xC93F6060, 0x7F042600, 0x6EF64F26, 0x6DF6000B, ++0x2FC62FB6, 0x2FE62FD6, 0xD25A4F22, 0x6B436E73, ++0x420B6C53, 0x20086D63, 0x61038F08, 0xD24FD456, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, 0x21B060C3, ++0x60D38011, 0xE5008111, 0x64BCA007, 0x6053655D, ++0x665300EC, 0x7501361C, 0x625D8064, 0x8BF53243, ++0x6060D636, 0x2600C9BF, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x7FC44F22, 0x720262F3, 0x22512F41, ++0x45297202, 0x60632251, 0xE5C4E682, 0x67F38121, ++0x655C666C, 0xE408BFBC, 0x4F267F3C, 0x0009000B, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xE1007FC4, 0x6513ECFF, 0x6B136CCD, 0xDE34D733, ++0xEDFF64F3, 0xD833EA04, 0x6053655C, 0x027D4000, ++0x32C0622D, 0x66038D0D, 0x09ED6063, 0x2491027D, ++0x24217402, 0x698202ED, 0x3928622D, 0x74022892, ++0x75017104, 0x6063625C, 0x07D532A2, 0x0EB58FE4, ++0x2448641C, 0xE6808905, 0x67F3E5C5, 0xBF7F666C, ++0x7F3C655C, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0xD11C68F6, 0x6012D21C, 0xCB20E405, ++0x2102E500, 0x000B2242, 0x00002252, 0x001E1017, ++0x001164F6, 0x001E1015, 0x001E10BF, 0x00117800, ++0x001E10FC, 0x001140CC, 0x001164FC, 0x0011602E, ++0x001166D0, 0x00114F2C, 0x001166EC, 0x00114EBE, ++0x0011788C, 0x001164F8, 0x001160DC, 0x001145BC, ++0x001E2130, 0x00115FF0, 0x001166F4, 0x00116510, ++0x00116518, 0x00116710, 0x001C3500, 0x001D4004, ++0xD565D164, 0xE400D765, 0x2142E20F, 0x17411154, ++0xD5632722, 0x9669D763, 0x15412572, 0x96661562, ++0xE6011565, 0xD5601165, 0x666CE6F8, 0x25422542, ++0x25422542, 0x25422542, 0x25622542, 0x7601E727, ++0x67632572, 0x25627797, 0xE7042572, 0x2572E248, ++0xE2192522, 0xE2702522, 0x25422542, 0x25422542, ++0x25222542, 0x2522E20C, 0x25422542, 0x25422542, ++0x25422542, 0x25422542, 0x000B154A, 0xE2081145, ++0x0009422B, 0x2FE62FD6, 0x7FFC4F22, 0xC8206043, ++0x6E438D02, 0x0009BE75, 0xC81060E3, 0xBE728901, ++0x60E30009, 0x8901C840, 0x0009BE94, 0xC80160E3, ++0xDD3E8938, 0xC80260D0, 0x2F008D03, 0x460BD63C, ++0x60F00009, 0x8902C804, 0x460BD63A, 0x62F00009, ++0xC8806023, 0x60D08902, 0x2D00C97F, 0xC8016023, ++0xD6358906, 0x0009460B, 0x0009A007, 0x51630601, ++0x8902C808, 0x460BD631, 0x60F00009, 0x8902C810, ++0x420BD22F, 0xD52F0009, 0x88026052, 0xD22E8B03, ++0xA005E604, 0x88012260, 0xD22B8B02, 0x2260E601, ++0x2522E200, 0xC88060E3, 0xD628892E, 0x60E36E60, ++0x8902C880, 0x420BD226, 0x60E30009, 0x8902C840, ++0x420BD224, 0x60E30009, 0x8902C802, 0x420BD222, ++0x60E30009, 0x890EC804, 0x410BD120, 0xBF120009, ++0xBF4D0009, 0xD51E0009, 0x6050D41E, 0xC908D71E, ++0xBF842500, 0x60E32472, 0x8905C808, 0x7F04D21B, ++0x6EF64F26, 0x6DF6422B, 0x4F267F04, 0x000B6EF6, ++0x00006DF6, 0x001C581C, 0xA000A000, 0x001D0100, ++0x001D4000, 0x00040021, 0x001C589C, 0x001E1021, ++0x001150C4, 0x001150E6, 0x00115724, 0x001150FE, ++0x0011510C, 0x00116574, 0x001E100B, 0x001E1028, ++0x00115162, 0x0011516E, 0x00115114, 0x00115132, ++0x001E1000, 0x0010F100, 0x12345678, 0x0011514A, ++0x644CD6A7, 0x000B346C, 0xD6A62450, 0x346C644C, ++0x2450000B, 0x644CD6A4, 0x000B346C, 0x625C2450, ++0x4208616D, 0x42084119, 0x42006019, 0x670E614C, ++0xD49E321C, 0x4200207D, 0x324CC90F, 0x2200000B, ++0x4208625C, 0x42004208, 0x324C644C, 0x4200D498, ++0x000B324C, 0x2FE62260, 0x614C4F12, 0x4100D493, ++0x6710314C, 0xE29F666D, 0x27294619, 0x6E536269, ++0x672E6573, 0x4221227D, 0x42214221, 0x7601662C, ++0xE4014608, 0x34E84608, 0x644C4600, 0x071A0467, ++0x2150257B, 0x000B4F16, 0x4F226EF6, 0xD2857FE8, ++0x88016021, 0xD2848B7B, 0x26686621, 0xD2838B77, ++0x26686621, 0xE50F8B73, 0xE401BFA2, 0xBFA4E501, ++0xE586E400, 0xE400655C, 0x2F50BFA4, 0xBFA1E401, ++0xE602E506, 0x60634618, 0x81F2E401, 0x6543BF9F, ++0xE40185F2, 0xBFAB6543, 0x85F26603, 0x6543E401, ++0x6603BFB1, 0xE40265F0, 0x6053756C, 0x80F8BF80, ++0xBF82E402, 0x84F8E512, 0x7090E402, 0x6503BF82, ++0x4618E602, 0x81F66063, 0xBF80E402, 0x85F6E500, ++0x6603E402, 0xE500BF8C, 0xE40285F6, 0xBF926603, ++0xE5FEE500, 0xE010655C, 0xBF61E403, 0xE5130F54, ++0xE40EBF63, 0x05FCE010, 0xBF63E40E, 0xE5007585, ++0xBF64E403, 0xE500E640, 0xBF71E403, 0xE500E640, ++0xBF78E403, 0xE5FFE640, 0xE014655C, 0xBF47E404, ++0xE40F0F54, 0xE504BF49, 0x05FCE014, 0xBF49E40F, ++0xE5017584, 0xBF4AE640, 0xE501E404, 0xBF57E640, ++0xE501E404, 0xE404E640, 0xAF5C7F18, 0x7F184F26, ++0x000B4F26, 0x4F220009, 0xD2427FF0, 0x88016021, ++0xD2418B71, 0x26686621, 0xD2408B6D, 0x26686621, ++0xE50F8B69, 0xE401BF1C, 0xBF1EE501, 0xE586E400, ++0xE400655C, 0x2F50BF1E, 0xBF1BE401, 0xE401E506, ++0xBF1C6543, 0xE401E640, 0xBF296543, 0xE401E640, ++0xBF306543, 0x65F0E640, 0x756CE402, 0xBEFF6053, ++0xE40280F4, 0xE512BF01, 0xE40284F4, 0xBF017090, ++0xE6406503, 0xBF02E402, 0xE640E500, 0xBF0FE402, ++0xE640E500, 0xBF16E402, 0xE5FEE500, 0x6053655C, ++0xBEE5E403, 0xE51380F8, 0xE40EBEE7, 0xE40E84F8, ++0xBEE77085, 0xE5006503, 0xBEE8E640, 0xE500E403, ++0xBEF5E640, 0xE500E403, 0xBEFCE640, 0xE5FFE403, ++0x6053655C, 0xBECBE404, 0xE40F80FC, 0xE504BECD, ++0xE40F84FC, 0xBECD7083, 0xE5016503, 0xBECEE640, ++0xE501E404, 0xBEDBE640, 0xE501E404, 0xE404E640, ++0xAEE07F10, 0x7F104F26, 0x000B4F26, 0x00000009, ++0x001E102F, 0x001E1080, 0x001E1090, 0x001E103F, ++0x001E103E, 0x0011656E, 0x00116570, 0x00116572, ++0xD21DD11C, 0x66206010, 0x676C7001, 0x3700C90F, ++0xE5008D13, 0x67106210, 0x7701622C, 0x64232170, ++0xD6166010, 0x44084408, 0x3428C90F, 0x62602100, ++0x7201D513, 0x44082620, 0x000B354C, 0xD10F6053, ++0x25586510, 0xE6008D13, 0xD60DD40B, 0x655C6540, ++0x47086753, 0x37584708, 0x47086540, 0x24507501, ++0x367C6040, 0x2400C90F, 0x72FF6210, 0x000B2120, ++0x00006063, 0x001164F5, 0x001164F4, 0x001164F6, ++0x0011611C, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x544F0D0A, 0x53205355, 0x46204950, ++0x00003A57, 0x2074634F, 0x32203220, 0x20373030, ++0x333A3831, 0x36343A32, 0x00000000, 0x00000D0A, ++0x42707372, 0x3D206675, 0x554E203D, 0x202C4C4C, ++0x6E49677A, 0x4E497274, 0x6D754E51, 0x0000003D, ++0x52504545, 0x57204D4F, 0x65746972, 0x6461202C, ++0x003D7264, 0x6C617620, 0x0000003D, 0x00000A0D, ++0x5A205746, 0x4D435F4D, 0x4C465F44, 0x5F485341, ++0x53415245, 0x000A0D45, 0x5A205746, 0x4D435F4D, ++0x4C465F44, 0x5F485341, 0x534B4843, 0x0A0D4D55, ++0x00000000, 0x2D495053, 0x72646461, 0x0000003D, ++0x2D495053, 0x676E656C, 0x003D6874, 0x2D495053, ++0x736B6863, 0x003D6D75, 0x5A205746, 0x4D435F4D, ++0x4C465F44, 0x5F485341, 0x44414552, 0x00000A0D, ++0x61202072, 0x3D726464, 0x00000000, 0x72202020, ++0x75427073, 0x00003D66, 0x6E6B6E55, 0x206E776F, ++0x6D6D6F63, 0x3D646E61, 0x00000000, 0x00000072, ++0x00205220, 0x00000D0A, 0x62735576, 0x7473725F, ++0x00000A0D, 0x62735576, 0x7375735F, 0x646E6570, ++0x00000A0D, 0x62735576, 0x7365725F, 0x000A0D6D, ++0x72746E49, 0x6D652051, 0x2C797470, 0x49677A20, ++0x4972746E, 0x754E514E, 0x00003D6D, 0x654C7245, ++0x0000006E, 0x20746F4E, 0x756F6E65, 0x49206867, ++0x4220514E, 0x0A0D6675, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x002E0209, 0x80000101, ++0x000409FA, 0x00FF0400, 0x05070000, 0x02000201, ++0x82050700, 0x00020002, 0x03830507, 0x07010040, ++0x40020405, 0x02090000, 0x0101002E, 0x09FA8000, ++0x04000004, 0x000000FF, 0x02010507, 0x07000040, ++0x40028205, 0x05070000, 0x00400383, 0x04050701, ++0x00004002, 0x00000000, 0x00000000, 0x07090000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, }; ++ ++const u32_t zcFwImageSPISize=10156; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu_2k.c +@@ -0,0 +1,1016 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE947FFC, 0xE114D594, ++0x1E13D494, 0x67521E4C, 0xD494D693, 0x37402769, ++0x62528F06, 0x7201D692, 0x60602522, 0x2600C93F, ++0xD7906152, 0x2512611D, 0x264B6652, 0x2562470B, ++0x0009B017, 0xE60095AC, 0xC84060E2, 0x2F028F03, ++0x8FF93652, 0xD4887601, 0x4E0BDE88, 0xD4880009, ++0x00094E0B, 0x4E0BD487, 0x7F040009, 0xA0524F26, ++0x4F226EF6, 0x410BD184, 0xD4840009, 0x0009440B, ++0x450BD583, 0xD7830009, 0xD283E1FF, 0x2712611D, ++0xD4825029, 0xE1FFCB01, 0x1209E501, 0x12112212, ++0xE7202452, 0x4718D57E, 0x2572D27E, 0xD17EE700, ++0xD67FD47E, 0xE2012270, 0x24702172, 0xD67D2620, ++0x2641E4FF, 0xD57CE600, 0x666DE104, 0x76016063, ++0x4000626D, 0x8FF83212, 0xD5780545, 0x2520E201, ++0xD278D777, 0xE480E100, 0x22122710, 0x6613D576, ++0x666D644C, 0x76046763, 0x375C626D, 0x8FF83243, ++0xD5722712, 0xD273D772, 0xE400E101, 0x27102511, ++0x000B4F26, 0x7FCC2242, 0xD170D56F, 0xD271DB70, ++0x1F51D471, 0xD6717508, 0x1F12D771, 0x1F55710C, ++0x1FB975FC, 0x72041F2A, 0x1F13EB10, 0x1F561F44, ++0x1F781F67, 0xD86B1F2B, 0xDD6CD96B, 0xDC6CEA00, ++0xD26DDE6C, 0x89003A22, 0xD15D7A01, 0x88016010, ++0x56F88B03, 0x4218E201, 0xD1682622, 0x0009410B, ++0x440BD467, 0xD5670009, 0x0009450B, 0x6010D150, ++0x8B108801, 0xE650D14F, 0x46186212, 0x8B083266, ++0x56F9D14B, 0x2120E200, 0xCB016062, 0x2602A003, ++0x72012710, 0x60822122, 0x89098801, 0xE2C8D15A, ++0x622C6612, 0x89033626, 0x6010D158, 0x8BC88801, ++0x51F66792, 0x217252F5, 0xD6555191, 0x55FA2212, ++0x52FB6462, 0x55612542, 0x2252E400, 0x61436643, ++0x05DE6013, 0x36CC4608, 0x07DE2652, 0xC9036071, ++0x8B028801, 0x720162E2, 0x74012E22, 0x36B3664C, ++0x71048FEE, 0x66C2D147, 0x45286512, 0x265B4518, ++0x60822C62, 0x89018801, 0x0009A168, 0x6272D742, ++0x8B132228, 0xD42BD741, 0x6772D541, 0x51536242, ++0x312C327C, 0x24222228, 0x15138D05, 0x6262D63D, ++0xB1627201, 0xD6232622, 0x2622E200, 0x52916692, ++0x8B013620, 0x0009A144, 0x6061A06E, 0x001C001C, ++0x001D4020, 0x0000B38E, 0xFFFF0000, 0x12340000, ++0x001E1015, 0x00201274, 0x002039EC, 0x002018A2, ++0x002039F8, 0x00203A10, 0x00201860, 0x00201964, ++0x00201288, 0x001C3510, 0x001C3624, 0x001E212C, ++0x002038EC, 0x00203484, 0x002038F4, 0x00203900, ++0x0020390C, 0x00203968, 0x0020396C, 0x00203914, ++0x00203915, 0x00203918, 0x00117700, 0x00203984, ++0x00203982, 0x002034E8, 0x00117710, 0x001C3D30, ++0x001C36F8, 0x00117734, 0x001C3684, 0x001C3D00, ++0x001C1000, 0x001C1028, 0x002034FC, 0x0020391C, ++0x00117600, 0x00117740, 0x7FFFFFFF, 0x00201730, ++0x00203322, 0x0020232C, 0x00203D9C, 0x0020396A, ++0x002034F4, 0x0020395C, 0x001C3D2C, 0x001C36B0, ++0x0020348C, 0x0011775C, 0x8801C90F, 0xA0CF8901, ++0xD1960009, 0x36206212, 0xD4958904, 0x2421E200, ++0x2162A0CC, 0x6211D193, 0x89012228, 0x0009A0C3, ++0xE202D78F, 0x75016571, 0x3123615D, 0x27518D02, ++0x0009A0BC, 0xD28C57F2, 0x62226072, 0x40094019, ++0xC90F4009, 0x8F19880A, 0x52F31F2C, 0x40196022, ++0x40094009, 0x8808C90F, 0xA0A78901, 0x60630009, ++0xCB0154F7, 0xD27E55F2, 0xE7012402, 0xD47FE100, ++0x22112572, 0x72016242, 0x2422A098, 0x8B3F8805, ++0x602252F3, 0x40094019, 0xC90F4009, 0x8B168802, ++0xE4FFD577, 0x644D6752, 0x8B102748, 0x6272D775, ++0x8B0C3260, 0x51F255F7, 0xD26DE701, 0x21722562, ++0xD571E100, 0x64522211, 0xA0777401, 0x52F32542, ++0x40196022, 0x40094009, 0x8805C90F, 0x31B38B6E, ++0xD26A8B6C, 0x672254F4, 0x7701D569, 0x61422272, ++0x1F1CE640, 0x46182159, 0x8B033160, 0x6262D665, ++0x26227201, 0xE200D65A, 0x2621B067, 0x0009A056, ++0x3123E220, 0x88038B52, 0x52F38B1E, 0x40196022, ++0x40094009, 0x8803C90F, 0xD25B8B16, 0x672254F4, ++0x7701D557, 0x61422272, 0x1F1CE640, 0x46182159, ++0x8B033160, 0x6262D655, 0x26227201, 0xE200D648, ++0x2621B043, 0x0009A010, 0xD452D551, 0xD2446752, ++0xE1007701, 0x25723A46, 0x22118F06, 0xEA00D64E, ++0x72016262, 0x2622B031, 0x2FB2D54C, 0x95736652, ++0xD44A5BF1, 0x36205241, 0x60618910, 0x8B01C803, ++0x2B22E201, 0x8FF54510, 0x57F15664, 0x6272E1F0, ++0x41284118, 0x2722221B, 0x6BF2A008, 0x6BF2A006, ++0xE200D62F, 0xD12F2621, 0x2121E200, 0xD13CE201, ++0x66122822, 0x8B012668, 0x0009AE2B, 0x450BD539, ++0xD1390009, 0xAE24E600, 0x2F862160, 0x2FA62F96, ++0x2FC62FB6, 0x2FE62FD6, 0x7FF44F22, 0xDE34D133, ++0x54116212, 0x1F4167E2, 0x2F22D432, 0xD5321F72, ++0xD2326743, 0x58417794, 0x69425A42, 0x5B166C72, ++0x60526D22, 0xCB20E600, 0xE5402502, 0x626D7601, ++0x8BFB3253, 0x55F162F2, 0x11512122, 0xD62855F2, ++0x14812E52, 0x249214A2, 0x27C2D426, 0x26D211B6, ++0xDA256742, 0xE801D925, 0x490B2A72, 0xE2011A8C, ++0x1A2C4218, 0x4F267F0C, 0x6DF66EF6, 0x6BF66CF6, ++0x69F66AF6, 0x68F6000B, 0x000007D1, 0x0020397C, ++0x00203980, 0x00203986, 0x001C3DC0, 0x0011772C, ++0x001C3B88, 0x00203964, 0x0011773C, 0x00117744, ++0x0000F000, 0x00117764, 0x00117748, 0x00117768, ++0x0011776C, 0x01FFFFFF, 0x0011774C, 0x002034F4, ++0x00203D9C, 0x002024F0, 0x0020396A, 0x001C3B9C, ++0x001C3D98, 0x001C3700, 0x001C3500, 0x001C5960, ++0x001C8960, 0x002034FC, 0x001C3D00, 0x0020160C, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xDE957FAC, 0x61E0E014, 0x0F14D494, 0x710161E3, ++0xE0186210, 0xD2920F24, 0x0009420B, 0x450BD591, ++0x20080009, 0x8F126D03, 0xD28F1F07, 0x6720D48F, ++0x657CDD8F, 0x470BD78F, 0xD18F0009, 0x619C6910, ++0x46086613, 0x36184608, 0x3D6C4608, 0xE0181FD7, ++0xE58004FC, 0x604C66E2, 0x3050655C, 0x2D628F15, ++0x01FCE014, 0xDE85E500, 0x641CA008, 0x6753655D, ++0x607037EC, 0x39DC6953, 0x80947501, 0x3243625D, ++0xD67F8BF4, 0xA34EE200, 0x20082621, 0xE0148B13, ++0xE40001FC, 0xA009DE79, 0x644D671C, 0x35EC6543, ++0x69436652, 0x39DC6262, 0x74041921, 0x3273624D, ++0xA3388BF3, 0x88012D10, 0xE0148B17, 0xE70001FC, ++0x6D1C2D70, 0xDE6D1FD4, 0x32D3627D, 0xA32A8B01, ++0x677D0009, 0x667365E3, 0x61737504, 0x315C36EC, ++0x69126462, 0xAFEF7708, 0x88042492, 0xE0148B18, ++0xE40001FC, 0x671C2D40, 0x624DDE60, 0x8B013273, ++0x0009A311, 0x6943644D, 0x39EC62E3, 0x72046592, ++0x3D2C6D43, 0x615266D2, 0x21697408, 0x2512AFED, ++0x8B188805, 0x01FCE014, 0x2D40E400, 0xDE53671C, ++0x3273624D, 0xA2F68B01, 0x644D0009, 0x62E36943, ++0x659239EC, 0x6D437204, 0x66D23D2C, 0x74086152, ++0xAFED216B, 0x88312512, 0xD44A8B3A, 0x6146D94A, ++0x75046543, 0x67566442, 0x6E531F48, 0x65527E04, ++0x7EE462E2, 0x7E0464E2, 0x6EE21FE9, 0x5EF929E0, ++0x7E04D942, 0x1FEA60E2, 0x2900C901, 0xD9406EE2, ++0x29E04E09, 0x2F562F26, 0x56FAD93E, 0x6513490B, ++0xD13D7F08, 0xE71C6E0D, 0x1DE12D70, 0xDE3B6912, ++0x64E21D92, 0x1D43D13A, 0xD23A6512, 0x67221D54, ++0x1D75D239, 0x1D666622, 0x6262D638, 0x1D27A2AB, ++0x8B398830, 0x6596D92B, 0x67926696, 0x61967904, ++0x74E46493, 0x6E436992, 0x1F9B7E04, 0x1FEC6442, ++0xD9256EE2, 0x5EFC29E0, 0x7E04D924, 0x1FED60E2, ++0x2900C901, 0xD9226EE2, 0x29E04E09, 0x59FC7FFC, ++0xDE272F92, 0x2F164E0B, 0xD41F7F08, 0xE21C610D, ++0x1D112D20, 0xD2206442, 0xD41C1D42, 0x1D536542, ++0x6752D51B, 0xD71B1D74, 0x1D156172, 0x1D666622, ++0x6262D61A, 0x1D27A26F, 0x8B358833, 0x490BD919, ++0xA268EE00, 0x00002DE0, 0x00117800, 0x00203A14, ++0x002018A2, 0x00202AA4, 0x00203906, 0x00203A18, ++0x0020352C, 0x002018EE, 0x00203905, 0x00117804, ++0x00203984, 0x00117810, 0x00203901, 0x00203902, ++0x00203903, 0x00200F64, 0x001C5864, 0x001C6864, ++0x001C7864, 0x001C59BC, 0x001C69BC, 0x001C79BC, ++0x00200FBC, 0x00200FB8, 0x89018828, 0x0009A0C0, ++0xE643DEB5, 0x326662E1, 0x1FEE8F02, 0x2E21E240, ++0x622D62E1, 0x8B013267, 0x0009A0AA, 0xE50185E1, ++0x8B013056, 0x0009A0A4, 0x2D10E101, 0x64E1B225, ++0xE64357FE, 0x652D6271, 0x89443567, 0x3563E640, ++0xE6008B05, 0x0F65E040, 0xA00FE11A, 0x615372C0, ++0x41214121, 0x41214121, 0x45214121, 0x45214521, ++0xC9036053, 0xE0406603, 0x71180F65, 0x2209E007, ++0x0F25E03C, 0xE044641D, 0xB2A365F3, 0xE33C0F46, ++0x853233FC, 0x620DDE95, 0x42086031, 0x6023610D, ++0x1323E944, 0x06FE4108, 0xE00F39FC, 0x13144E0B, ++0x67075D91, 0x60D32679, 0x0F6654FE, 0x51928542, ++0x600D4E0B, 0x60D3260B, 0x0F666492, 0x65F3B237, ++0x696156FE, 0xE640659D, 0x89383563, 0xD78359FE, ++0x79066591, 0xC9036053, 0x40004008, 0x61036203, ++0x0F26E050, 0x470BE0FF, 0x6C07600C, 0x6603605D, ++0x46214621, 0x46214621, 0x42006263, 0x4200326C, ++0x40214021, 0x4008C903, 0x6D2D30FC, 0xE8006A03, ++0xB25765F3, 0x6EA264D3, 0x2EC9E050, 0x66942AE2, ++0xD76E01FE, 0x606C470B, 0x2AE22E0B, 0x64D365F3, ++0x7801B1FD, 0xEE06628D, 0x8FE932E3, 0x5EFE7D01, ++0x61E1E400, 0x410085E1, 0x66E3310C, 0x760C711B, ++0xE70465F3, 0x68667401, 0x3A736A4D, 0x8FF92582, ++0x65F37504, 0x641DB1E3, 0x64E1B1A4, 0x0009A17B, ++0xD45B56F7, 0xEC01D25B, 0x26C0420B, 0x0009A173, ++0x06FCE018, 0x8829606C, 0x58F78B08, 0xE400D252, ++0x66222840, 0x646DB171, 0x0009A165, 0x666CE681, ++0x89013060, 0x0009A0AC, 0xD550D14F, 0x62126A56, ++0x212232AC, 0x54116C56, 0x34CC6253, 0x64521141, ++0x72085812, 0xD44A384C, 0x68221182, 0x5A136C42, ++0x3ACC3C8C, 0x11A324C2, 0x6C2272EC, 0x72105814, ++0x118438CC, 0x5A156822, 0x11A53A8C, 0x6A227210, ++0xD6405816, 0x118638AC, 0x52176C62, 0x112732CC, ++0x5A185861, 0x11A83A8C, 0x5C195A62, 0x11C93CAC, ++0x521A5C63, 0x112A32CC, 0x5A1B5864, 0x11AB3A8C, ++0x5C1C5A65, 0x11CC3CAC, 0x521D5C66, 0x112D32CC, ++0x5A1E5867, 0x11AE3A8C, 0x561F5A68, 0x36ACE840, ++0x116FDA2D, 0x6CA2381C, 0x7A946682, 0x286236CC, ++0x5C8162A2, 0x18C13C2C, 0x62A27A44, 0x362C5682, ++0xD6261862, 0x5A856262, 0x3A2C4229, 0x760418A5, ++0x56866262, 0x362C4229, 0x56F71866, 0x2620E238, ++0x16C15C81, 0x16226212, 0xE2005C11, 0x551216C3, ++0x55151654, 0x55131655, 0x55161656, 0x55821657, ++0x65821658, 0x55141659, 0x5584165A, 0x5583165B, ++0x5585165C, 0x5586165D, 0x1821165E, 0x11212122, ++0x11251122, 0x11261123, 0x28221822, 0x18241124, ++0x18251823, 0x1826A0C7, 0x00117804, 0x002033E0, ++0x00203A38, 0x002018A2, 0x0020348C, 0x001C36A0, ++0x002034E8, 0x001C3CA0, 0x001C36F4, 0x001C3B88, ++0x666CE682, 0x8B203060, 0xEA2456F7, 0x26A0D194, ++0x16C15C17, 0x16225218, 0x16835819, 0x16A45A1A, ++0x16C55C1B, 0x1626521C, 0xE200581D, 0x551E1687, ++0x551F1658, 0x11271659, 0x11291128, 0x112B112A, ++0x112D112C, 0xA08E112E, 0xE683112F, 0x3060666C, ++0x52F78B0B, 0xEA00D883, 0x658222A0, 0x7804DC82, ++0x62822C52, 0xA07ED681, 0xE6902620, 0x3060666C, ++0xDA7F8B06, 0x00094A0B, 0xE20056F7, 0x2620A073, ++0x666CE691, 0x8B103060, 0x6222D276, 0x2228622C, ++0xD2788904, 0x0009420B, 0x0009A003, 0x420BD276, ++0x56F70009, 0xA05EE200, 0xE6922620, 0x3060666C, ++0xE0188951, 0xE6B00BFC, 0x666C62BC, 0x8B2A3260, ++0x02FCE014, 0x682CEA00, 0x62ADE904, 0x894A3283, ++0x6AADDD64, 0x3CDC6CA3, 0x7D046EC2, 0xDB68D467, ++0x32DC62A3, 0x4B0BDC67, 0x4C0B6D22, 0xD46664E3, ++0x00094B0B, 0x64D34C0B, 0x4B0BD464, 0xE6000009, ++0x666D6BE3, 0x76013B6C, 0x3293626D, 0x8FF72BD0, ++0xAFDA4D19, 0xE6B57A08, 0x3260666C, 0xD45C8B13, ++0x4B0BDB57, 0xD25B0009, 0x6022DB5B, 0xCB20E6FF, ++0x2202666D, 0xDB592B62, 0xE014E200, 0x56F72B20, ++0xA01002FC, 0xD4562620, 0x6542D256, 0x420BD456, ++0xA0080009, 0xDB520009, 0x52B1E600, 0x622CDB53, ++0x52F72B21, 0x7F542260, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x000B69F6, 0x4F2268F6, 0xE240614D, ++0x89143123, 0x3127E21F, 0x8B09D749, 0xD449614D, ++0xE00171E0, 0x5671440B, 0x26596507, 0x1761A007, ++0xE001D444, 0x6672440B, 0x26596507, 0x4F262762, ++0x0009000B, 0x614D4F22, 0x3123E240, 0xE21F8912, ++0xD73B3127, 0x614D8B08, 0x5671D23A, 0x420B71E0, ++0x260BE001, 0x1761A006, 0x6672D236, 0xE001420B, ++0x2762260B, 0x000B4F26, 0xE6400009, 0x46284618, ++0x6252D531, 0x89FC2268, 0x0009000B, 0x4618E680, ++0xD52D4628, 0x22686252, 0x000B89FC, 0xA0010009, ++0x7201E200, 0x8BFC3242, 0x0009000B, 0x4618E680, ++0xD5264628, 0x22686252, 0x000B8BFC, 0x2FE60009, ++0x7FFC4F22, 0xBFF16E53, 0x61E22F42, 0xE280D620, ++0x54E11615, 0x16464218, 0x422855E2, 0x57E31657, ++0x16786EF2, 0x26E22E2B, 0x4F267F04, 0x6EF6AFCE, ++0x0020348C, 0x00117804, 0x002038EC, 0x00203900, ++0x0020050A, 0x00201008, 0x0020102E, 0x00203A50, ++0x002018A2, 0x002018E6, 0x00203A64, 0x00203A6C, ++0x00203A70, 0x001C3500, 0x001C1000, 0x00203982, ++0x00117800, 0x002018EE, 0x00203A84, 0x00203988, ++0x001C3704, 0x002033E0, 0x001C373C, 0x001C3700, ++0x001C370C, 0x2FD62FC6, 0x4F222FE6, 0x6C53DD10, ++0x6E43BFA4, 0x2DE2BF89, 0x0009BFA0, 0x2C1251D5, ++0x1C4154D6, 0x1C5255D7, 0x1C6356D8, 0x6EF64F26, ++0x000B6DF6, 0x61636CF6, 0xA004E600, 0x62564109, ++0x24227601, 0x36127404, 0x000B8BF9, 0x00000009, ++0x001C370C, 0x0009A16E, 0x2FE62FD6, 0xDD944F22, ++0xA0049EB2, 0xD4930009, 0x420BD293, 0x62D265D2, ++0x8BF822E8, 0x0009A004, 0xD28FD490, 0x55D1420B, ++0x22E852D1, 0xA0048BF8, 0xD48D0009, 0x420BD28A, ++0x52D255D2, 0x8BF822E8, 0x0009A004, 0xD286D489, ++0x55D3420B, 0x22E852D3, 0xA0048BF8, 0xD4860009, ++0x420BD281, 0x52D455D4, 0x8BF822E8, 0x6EF64F26, ++0x6DF6000B, 0x2FD62FC6, 0x4F222FE6, 0x6E636C73, ++0x6D53B01A, 0x64D357F4, 0xB05F65E3, 0xB07566C3, ++0xB0A40009, 0xB0A80009, 0xB0AC0009, 0xB0AC0009, ++0xB0AF0009, 0xB03154F5, 0x6CCD6C03, 0x4F2660C3, ++0x6DF66EF6, 0x6CF6000B, 0x3412D170, 0xD6700529, ++0x2650D770, 0x2742000B, 0x0009A018, 0x2FD62FC6, ++0x4F222FE6, 0x6E636C73, 0x6D53BFEE, 0x64D357F4, ++0xB03365E3, 0xB08D66C3, 0xB00F54F5, 0x6CCD6C03, ++0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, 0xE503D162, ++0xD763D462, 0x21524518, 0x2472000B, 0xD45FD15E, ++0x2162E600, 0x2462000B, 0xBF734F22, 0xBF73E40A, ++0xD25C0009, 0x4118E104, 0xE40AE500, 0xBF692212, ++0xD7592252, 0xCB206072, 0x000B4F26, 0x4F222702, ++0x410BD156, 0xD556E400, 0x4F26452B, 0xD1552FE6, ++0x66126E63, 0x92104418, 0x44084528, 0x45002629, ++0x265B4408, 0x264B4400, 0x21624708, 0xD14E4708, ++0x217227EB, 0x6EF6000B, 0x1FFF03F0, 0x4F222FE6, ++0xE101DE4A, 0xBF3DE40A, 0x67E32E12, 0xE500776C, ++0xE204E130, 0x2752E40A, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27222712, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x175ABF18, 0x2E62E600, 0x000B4F26, 0xD2346EF6, ++0xE441E101, 0x000B2212, 0xD1322242, 0xE605D432, ++0x000B2162, 0x000B2462, 0xD2300009, 0xE40AE601, ++0x2262AF00, 0x2FC62FB6, 0x2FE62FD6, 0x7FFC4F22, ++0x6C43DB2B, 0xED0060B2, 0x2B02CB03, 0xC90360B2, ++0x6E03A008, 0x89073DC2, 0xE46460B2, 0xB07CC903, ++0x7D016E03, 0x8BF52EE8, 0x8F043DC2, 0xD4212FE1, ++0x460BD621, 0x62F10009, 0x6023622D, 0x89FFC801, ++0x7F046023, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x001C3B88, 0x00203A98, 0x002018EE, 0x00203AA0, ++0x00203AA8, 0x00203AB0, 0x00203AB8, 0x0025E720, ++0x00203D98, 0x002038F0, 0x001C5968, 0x001C3B40, ++0x000F8000, 0x001D4004, 0x001C3500, 0x002015E0, ++0x0020160C, 0x001C5814, 0x001C59D0, 0x001C5830, ++0x001C6268, 0x001C59A4, 0x001C639C, 0x001C581C, ++0x001C5860, 0x00203AC0, 0x002018A2, 0x8F014411, ++0x6043604B, 0x0009000B, 0x5651D52B, 0x46286052, ++0x306C000B, 0x2FC62FB6, 0x2FE62FD6, 0x4F124F22, ++0xBFF14F02, 0x6B036E43, 0xDD25DC24, 0x0009BFEC, ++0x3C0530B8, 0x4609060A, 0x46014609, 0x020A3D65, ++0x42094209, 0x32E24209, 0x4F068BF0, 0x4F264F16, ++0x6DF66EF6, 0x000B6CF6, 0x2FC66BF6, 0x2FE62FD6, ++0x4F124F22, 0xBFCF4F02, 0x6C036E43, 0xBFCBDD13, ++0x30C80009, 0x060A3D05, 0x46094609, 0x36E24601, ++0x4F068BF5, 0x4F264F16, 0x6DF66EF6, 0x6CF6000B, ++0x4F222FE6, 0xE102DE0B, 0xE403E500, 0xBFB92E12, ++0xE6062E52, 0xE7004618, 0x2E62E403, 0x4F262E72, ++0x6EF6AFB0, 0x0009000B, 0x001C1040, 0xCCCCCCCD, ++0x10624DD3, 0x001D4004, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE5007F98, 0x6453E710, ++0x6B534728, 0xEE1ADCBC, 0x6153655D, 0x315C4108, ++0x75014108, 0x6043317C, 0x0F16665D, 0xED0060B3, ++0x21B136E3, 0x81128111, 0x11D28113, 0x11D411D3, ++0x74048FEA, 0xD8B167F2, 0x1871D9B1, 0x58F12872, ++0x1981D1B0, 0x59F22982, 0x5DF45AF3, 0x54F65EF5, ++0x21921191, 0x11A211A3, 0x11D411D5, 0x11E611E7, ++0x11481149, 0xDAA855F7, 0x57F8EE00, 0x52F9DDA7, ++0x64E3D6A7, 0x2A521A51, 0xD8A7D9A6, 0x2D729AD5, ++0x6EED2622, 0x4D086DE3, 0x3DEC61E3, 0x4D084108, ++0x3D9C31EC, 0x410860B3, 0x81D12DB1, 0x4108E050, ++0x4008E7B7, 0x677C4108, 0x60B381D2, 0xE200318C, ++0x81D33472, 0x1D131DD2, 0x8D01D493, 0xD4901D24, ++0xB0B365D3, 0x64ED7E01, 0x8BDA34A2, 0x2FD2DA8C, ++0xDD9268A2, 0x2D824829, 0x7DFC64A2, 0xD287694D, ++0x6E222D92, 0x7D0C4E29, 0x68222DE2, 0x618D6AD3, ++0x2A16D784, 0xD48A6D72, 0x24D2D583, 0xD6895E72, ++0x517414E2, 0x1414EE00, 0xD1875876, 0x59781486, ++0x1498E710, 0x65E36252, 0x26E2142A, 0xE60064E3, ++0x6843644D, 0x384C4808, 0x381C4808, 0x0C866053, ++0x09CE28B1, 0x819160B3, 0x0ACE6053, 0x81A26043, ++0x0DCE6053, 0x81D360B3, 0x08CE6053, 0x18827401, ++0x624D09CE, 0x0ACE19E3, 0x1A643273, 0x75048FE0, ++0xE003D96A, 0x40186C92, 0x6D922CB1, 0x81D1DA6F, ++0x6E92E050, 0x81E24008, 0x60B36192, 0x64928113, ++0x1442E600, 0xD4696792, 0x689217A3, 0x1864E1FF, ++0x6563E703, 0x364C4608, 0x26127501, 0x3673665D, ++0xDC5B8BF8, 0x6DC2E003, 0x2DB14018, 0xD2606EC2, ++0x61C281E1, 0x1112EE00, 0xE02464C2, 0x65C21423, ++0x15E4D45B, 0xE58067C2, 0x68C28172, 0x818366E3, ++0x666D655C, 0x76046963, 0x394C6A6D, 0x8FF83A53, ++0xDB5429E2, 0x24B2DC54, 0x24C27404, 0x4F267F68, ++0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, 0x68F6000B, ++0x60116142, 0x8F03C803, 0xD23DE500, 0x8B063420, ++0xC9036011, 0x8B068802, 0x3420D239, 0x56128B03, ++0x52646513, 0x000B2422, 0x01136053, 0x2FE62FD6, ++0x7FEC4F22, 0x62536E53, 0x6D43E550, 0x4508E400, ++0xE101A001, 0x60435224, 0x81212211, 0x60538123, ++0x56E28122, 0x8BF53620, 0x16E4D238, 0xE61464F3, ++0x65E3420B, 0xE4FC65E1, 0x2E512549, 0x65F361F1, ++0x2F112149, 0xD13154D1, 0xE614410B, 0x607157D1, ++0x2701CB01, 0x7F141DE1, 0x6EF64F26, 0x6DF6000B, ++0x2FE62FD6, 0x7FEC4F22, 0x66536E53, 0x6D43E5FC, ++0x20596061, 0x2601CB01, 0x326052E2, 0x12E48B06, ++0x31E051E2, 0x52D18B04, 0x1E22A002, 0x5664AFF0, ++0x64F3D21E, 0x420BE614, 0x67E165E3, 0x2719E1FC, ++0x67F12E71, 0x271954D1, 0x65F3D118, 0x410BE614, ++0x52D12F71, 0xCB016021, 0x1DE12201, 0x4F267F14, ++0x000B6EF6, 0x00006DF6, 0x0020391C, 0x002034EC, ++0x002034F4, 0x002034FC, 0x00203524, 0x00203908, ++0x00203910, 0x00100208, 0x001017C0, 0x001E210C, ++0x001C3D00, 0x0020395C, 0x001000C8, 0x00117880, ++0x00117780, 0x00040020, 0x0026C401, 0x00200ED6, ++0x4F222FE6, 0xDE42624C, 0x42004208, 0x3E2CA005, ++0xD4405252, 0xBF695624, 0x65E22E62, 0x352052E1, ++0xD63D8BF6, 0x4F262622, 0x6EF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xDC394F22, 0x52C1DB39, 0x362066C2, ++0x6061891C, 0x8801C903, 0xDE348918, 0xBF37DD35, ++0x650364E3, 0x66B28503, 0x3262620D, 0xD4328907, ++0x0009BF76, 0x4D0BD431, 0xAFE60009, 0xBF3D0009, ++0xD42F64E3, 0x00094D0B, 0x0009AFDF, 0x2262D22D, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x2FD62FC6, ++0x4F222FE6, 0xDD29DC28, 0x6E4360C2, 0x04DE4008, ++0xE614D127, 0x65E3410B, 0xD127D726, 0x55E227E2, ++0x35E05254, 0x21228F04, 0x400860C2, 0x122202DE, ++0x605365C2, 0x75014008, 0x0DE606DE, 0xC90F6053, ++0x60632C02, 0x6EF64F26, 0x000B6DF6, 0x85436CF6, ++0x650D5643, 0x622D6262, 0x35277204, 0xE1008F0C, ++0x2268960C, 0xD6158B03, 0x72015261, 0xD6131621, ++0x6262E101, 0x26227201, 0x6013000B, 0x000001FF, ++0x002034FC, 0x002034F4, 0x001C3D00, 0x00203524, ++0x002038EC, 0x002018A2, 0x002034EC, 0x00203AE8, ++0x00203AEC, 0x001C3D28, 0x0020395C, 0x0020391C, ++0x00200ED6, 0x00203960, 0x00203964, 0x00117754, ++0x2FC62FB6, 0x2FE62FD6, 0x7FF84F22, 0x6022D237, ++0x8D58C803, 0xDE362F01, 0xDB37DC36, 0x66C252C1, ++0x892F3620, 0xC9036061, 0x892B8801, 0xD233DD31, ++0x64D3420B, 0x1F016503, 0x880160B1, 0xD2308B04, ++0x64D3420B, 0x0009AFEA, 0x85615653, 0x8904C820, ++0xE050D72C, 0x7201027E, 0xD22B0726, 0x6453420B, ++0x89072008, 0x55F1D126, 0x64D3410B, 0xE601D727, ++0x2762AFD4, 0x55F1D226, 0x64E3420B, 0xE601D125, ++0x2162AFCC, 0xDD25DE24, 0xDC26DB25, 0x66D252D1, ++0x89183620, 0xC9036061, 0x89148801, 0xD117D41F, ++0x0009410B, 0x36E05603, 0x65038F04, 0x2B20E201, ++0x2C52AFEC, 0xD712D41C, 0x0009470B, 0xE601D115, ++0xAFE34618, 0x60F12162, 0x8907C804, 0x7F08D217, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, 0x4F267F08, ++0x6DF66EF6, 0x000B6CF6, 0x00006BF6, 0x001E2100, ++0x002034FC, 0x002034F4, 0x00203984, 0x002014A0, ++0x002014CC, 0x0020348C, 0x002016BE, 0x001E212C, ++0x00201530, 0x001C3D30, 0x00117880, 0x002034EC, ++0x0020390C, 0x00203908, 0x00203524, 0x00200610, ++0xE601D203, 0x1265D503, 0x000B2252, 0x00001266, ++0x001C1010, 0x0000C34F, 0x0009000B, 0x2FD62FC6, ++0x4F222FE6, 0x6D436C53, 0xEE00A004, 0x7E0164D4, ++0x644CBFF2, 0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, ++0xE5006CF6, 0x6643A002, 0x76017501, 0x22286260, ++0xAFE38BFA, 0x2FE60009, 0x75076253, 0xE1086753, ++0x6043EE0A, 0x4409C90F, 0x650330E2, 0x8D014409, ++0xE630E637, 0x4110365C, 0x8FF22760, 0xE00077FF, ++0x000B8028, 0x000B6EF6, 0x000BE000, 0x2FE6E000, ++0x7FEC4F22, 0x6E436253, 0xBFDC65F3, 0xBFD06423, ++0xBFCE64E3, 0xD40364F3, 0x0009BFCB, 0x4F267F14, ++0x6EF6000B, 0x00203AF0, 0xE4FDD29D, 0xD79D6122, ++0x22122149, 0x74016022, 0x2202CB01, 0xD59A6622, ++0x22622649, 0xC8406070, 0x60528902, 0x2502CB04, ++0xE6016052, 0x2502CB08, 0xE4026052, 0x2502C9CF, ++0x46186052, 0x2502CB10, 0xCB036052, 0x15422502, ++0x1563000B, 0xD78ED58D, 0xD48FD28E, 0xE600E100, ++0x27112511, 0xAFCF2210, 0x664C2461, 0x4600D28B, ++0x6060362C, 0x000BCB10, 0x654C2600, 0x4500D287, ++0x6650352C, 0x2619E1EF, 0x2560000B, 0xD284664C, ++0x362C4600, 0xCB106060, 0x2600000B, 0xD280654C, ++0x352C4500, 0xE1EF6650, 0x000B2619, 0x664C2560, ++0x4600D27A, 0x6060362C, 0x000BCB08, 0x654C2600, ++0x4500D276, 0x6650352C, 0x2619E1F7, 0x2560000B, ++0xD273664C, 0x362C4600, 0xCB086060, 0x2600000B, ++0xD26F654C, 0x352C4500, 0xE1F76650, 0x000B2619, ++0x624C2560, 0x4200D669, 0x6020326C, 0x4021C908, ++0x40214021, 0x600C000B, 0xD665624C, 0x326C4200, ++0xC9086020, 0x40214021, 0x000B4021, 0xD161600C, ++0x341C644C, 0x000B6240, 0xD15F602C, 0x341C644C, ++0x000B6240, 0x2FE6602C, 0x6E434F22, 0xE60A645C, ++0x89143467, 0x0009BFEB, 0x60EC640C, 0x8B028801, ++0xA002E00F, 0x44092409, 0x624C4409, 0x3263E60A, ++0xBFE28905, 0x620C644C, 0xC8806023, 0xE2008B00, ++0x4F266023, 0x6EF6000B, 0xD64C4F22, 0x88016062, ++0xB2578B03, 0xA0030009, 0xD2490009, 0x2260E640, ++0xE200D648, 0x000B4F26, 0x4F222622, 0x6062D643, ++0x8B018802, 0x0009B2A0, 0xE200D642, 0x000B4F26, ++0xD53E2622, 0xE100D43E, 0x2512E701, 0x2470000B, ++0xE604D23B, 0x2260000B, 0xD43B4F22, 0x410BD13B, ++0xD53B0009, 0x6650E1FD, 0x2619D23A, 0x2560E700, ++0x000B4F26, 0x4F222270, 0xD238D537, 0xD7386152, ++0x2512611D, 0xE6FF6452, 0x2542242B, 0xD22FD435, ++0x420B666D, 0xD52E2762, 0x6750E1FB, 0x4F262719, ++0x2570000B, 0xD4304F22, 0x410BD128, 0xD5280009, ++0x6650E7F7, 0x4F262679, 0x2560000B, 0x9425D524, ++0x22496250, 0x2520000B, 0xE4BFD521, 0x22496250, ++0x2520000B, 0xD2254F22, 0x600D8522, 0x89112008, ++0x89458801, 0x89478803, 0x89498805, 0x894F8806, ++0x89558808, 0x895B8809, 0x8961880A, 0x8967880B, ++0x0009A06E, 0x0009B070, 0x600CA06B, 0x0000FF7F, ++0x001E2148, 0x001E1000, 0x001E1108, 0x002039BC, ++0x002039BE, 0x002039DD, 0x002039A0, 0x001E103F, ++0x001E105F, 0x001E102F, 0x001E1090, 0x002039C4, ++0x001E100B, 0x002039C0, 0x00203AF4, 0x002018A2, ++0x001E1028, 0x002039DC, 0x001D4020, 0x98760000, ++0x001C1000, 0x00203B00, 0x00203B10, 0x00203994, ++0x0009B04C, 0x600CA035, 0x0009B055, 0x600CA031, ++0x6260D684, 0x8B2B2228, 0x0009B061, 0x600CA029, ++0x6260D680, 0x8B232228, 0x0009B069, 0x600CA021, ++0x6260D67C, 0x8B1B2228, 0x0009B0C7, 0x600CA019, ++0x6260D678, 0x8B132228, 0x0009B0CD, 0x600CA011, ++0x6260D674, 0x8B0B2228, 0x0009B125, 0x600CA009, ++0x6260D670, 0x8B032228, 0x0009B13D, 0x600CA001, ++0x4F26E000, 0x0009000B, 0xD26CD16B, 0xD56C8412, ++0x4000C90F, 0xD76B012D, 0xE403D66B, 0xE20F611C, ++0x2540E001, 0x25202712, 0x2602000B, 0xE601D262, ++0x30668523, 0xE0008D05, 0xD663D260, 0xE0018122, ++0x000B2602, 0xD25C0009, 0x600D8523, 0x89052008, ++0x8B0A8801, 0x6060D65D, 0x2600CB01, 0xD457D65A, ++0xE001E101, 0x000B2612, 0x000B8142, 0xD152E000, ++0x8513E501, 0x640D4518, 0x66033453, 0xE0008D05, ++0xD551D253, 0x2260E001, 0x000B2502, 0x4F220009, ++0x8513D149, 0x6453650D, 0x62494419, 0x227D672E, ++0x8801602C, 0x88028909, 0x88038910, 0x8806891A, ++0x88078935, 0xA04C893B, 0xD5460009, 0x6652D746, ++0x2762D446, 0x622C6261, 0x2421A038, 0x2228625C, ++0xD4438B3F, 0x6642D540, 0x2562D440, 0x24018561, ++0x6203A02C, 0x2008605C, 0x88108907, 0x88208908, ++0x88308909, 0xA02C890A, 0xD23A0009, 0x6222A008, ++0xA005D239, 0xD2396222, 0x6222A002, 0x6262D638, ++0xD432D531, 0x66212522, 0xA00F626C, 0xD6352421, ++0x6261D52D, 0x622CD42D, 0xA0072562, 0xD6322421, ++0x8561D529, 0x2562D429, 0x62032401, 0x662D8515, ++0x3617610D, 0x65038F01, 0xB0CB2451, 0xA0010009, ++0xE000E001, 0x000B4F26, 0xD6190009, 0xD427E101, ++0x65412610, 0xD118D717, 0xE20F655D, 0x2752E001, ++0x000B2620, 0x2FE62102, 0xD20F4F22, 0x640C8523, ++0x8B082448, 0xD511D61D, 0x2621E200, 0x940F8451, ++0xA0482049, 0xDE0D8051, 0xC84060E0, 0xE2018D32, ++0x89443427, 0xD216D615, 0x2641420B, 0x0009A030, ++0x0000FF7F, 0x002039DD, 0x00203994, 0x002039A0, ++0x001E1100, 0x001E100C, 0x002039C0, 0x001E1000, ++0x001E1001, 0x002039C8, 0x002039A8, 0x002039AC, ++0x002039B0, 0x002039CC, 0x002039D0, 0x002039D4, ++0x002039D8, 0x00203DFC, 0x00203E06, 0x002039BA, ++0x0020287E, 0x89123427, 0xD294D693, 0x2641420B, ++0xCB8084E1, 0x80E1B0F5, 0xD69160E0, 0x2E00CB04, ++0xC93F6060, 0xD68F2600, 0xA001E001, 0xE0002602, ++0x000B4F26, 0xD68C6EF6, 0xC8806060, 0xD2868919, ++0x88016021, 0xD2898B15, 0x8524E501, 0x89103056, ++0xE203D187, 0x2120D487, 0xE00B6541, 0x0656655D, ++0xE40FD585, 0x2140E702, 0xD77E2571, 0x000BE001, ++0x000B2702, 0x2FE6E000, 0xDE804F22, 0xC88084E1, ++0xD57A892C, 0x20088554, 0x61038F28, 0x8553D77C, ++0x64036672, 0x8566650C, 0x3520620C, 0xD6798B1E, ++0x651CD774, 0x2651644C, 0x60E02741, 0x8904C840, ++0x420BD275, 0xA0030009, 0xD2680009, 0x0009420B, ++0x0009B09F, 0xE201D167, 0x60E02122, 0xCB04D464, ++0x60402E00, 0x2400C93F, 0x6023A001, 0x4F26E000, ++0x6EF6000B, 0x2FB62FA6, 0x2FD62FC6, 0xDA622FE6, ++0x66A1E240, 0x3622DC5E, 0x62638900, 0x6ED36D2C, ++0x4E2136D8, 0x4E212A61, 0xDB61D460, 0xE700A00F, ++0x770162B2, 0x71026123, 0x66212B12, 0x71026213, ++0x61212B12, 0x651D666D, 0x356C4528, 0x627C2452, ++0x8BED32E3, 0xC90360D3, 0x8B108803, 0x617367B2, ++0x2B127102, 0x71026E13, 0x2B126571, 0x655D6DE1, ++0x422862DD, 0x325CE107, 0xA00C2C10, 0x88022422, ++0xA0038B01, 0x8801E203, 0xE2018B05, 0x66B22C20, ++0x655D6561, 0xE60F2452, 0x67A12C60, 0x8B052778, ++0xDD38DC44, 0xEB01EA00, 0x2DB22CA2, 0x6DF66EF6, ++0x6BF66CF6, 0x6AF6000B, 0x2FE62FD6, 0xE240DD36, ++0x362266D1, 0x62638900, 0x3678672C, 0x7703DE38, ++0x47212D61, 0x64E2D635, 0xA00E4721, 0x6562E100, ++0x62537101, 0x74012450, 0x24204219, 0x45297401, ++0x74012450, 0x24504519, 0x621C7401, 0x8BEE3273, ++0x66E24200, 0x420061D1, 0x2118362C, 0x2E628F06, ++0xDD1CD728, 0xE501E400, 0x2D522742, 0x000B6EF6, ++0x2FD66DF6, 0x4F222FE6, 0xED0AEE01, 0x64E3BC85, ++0xBC8A64E3, 0x62EC7E01, 0x8BF732D7, 0xBC8DEE01, ++0x64E364E3, 0x7E01BC92, 0x32D762EC, 0x4F268BF7, ++0x000B6EF6, 0xD1186DF6, 0xD418920D, 0x72122122, ++0x2422D617, 0xD7177204, 0x72202622, 0x2722D116, ++0x000B7230, 0x137A2122, 0x002039BA, 0x0020298A, ++0x001E1015, 0x002039C0, 0x001E1001, 0x00203994, ++0x001E1100, 0x002039BE, 0x002039AC, 0x001E1000, ++0x002039B0, 0x002039BC, 0x0020287E, 0x001E100C, ++0x002039A8, 0x002039C4, 0x002039C8, 0x002039CC, ++0x002039D0, 0x002039D4, 0x002039D8, 0x4F222FE6, ++0xD6707FFC, 0x88016060, 0xE2018951, 0x2620BFBB, ++0xD56ED16D, 0xDE6E6010, 0x64E36552, 0x7402C840, ++0x8D22D16C, 0xD26C7502, 0xE601D76C, 0xE7042722, ++0x76016255, 0x626C2421, 0x8FF93273, 0xD4637402, ++0x6242E601, 0x640D8528, 0x67494419, 0x275D657E, ++0x81E4607C, 0xE417D562, 0x67557601, 0x3243626C, ++0x8FF92171, 0xA0207102, 0xD25E0009, 0xE601D75B, ++0xE7042722, 0x76016255, 0x626C2421, 0x8FF93273, ++0xD4527402, 0x6242E601, 0x640D8528, 0x67494419, ++0x275D657E, 0x81E4607C, 0xE417D553, 0x67557601, ++0x3243626C, 0x8FF92171, 0x92897102, 0xD2462E21, ++0x5E23D74E, 0x64F22FE2, 0x604365F2, 0x2700C980, ++0xC9606043, 0x80716103, 0xC9036043, 0x80724519, ++0x65F2605C, 0x817266F2, 0x46194629, 0x606C4529, ++0x4018645C, 0x8173304C, 0x21185E23, 0x64F22FE2, ++0x6E4C62F2, 0x602C4219, 0x66F262F2, 0x46294018, ++0x461930EC, 0x42298174, 0x652C606C, 0x305C4018, ++0x81758F07, 0x0009BC96, 0x2228620C, 0xA00A8908, ++0x60130009, 0x8B038840, 0x0009B009, 0x0009A003, ++0xE202D62F, 0x7F042622, 0x000B4F26, 0x4F226EF6, ++0x8552D52A, 0x8830600D, 0x88318903, 0xA0348923, ++0x85550009, 0xD428D727, 0x85532701, 0x610DD627, ++0x24124118, 0x460BD426, 0xD7230009, 0xD226D425, ++0x6572420B, 0xE230D120, 0x42286712, 0x2729E620, ++0x37604628, 0xD6218B03, 0xA016E200, 0xD61F2622, ++0xA012E202, 0xD1182622, 0x6212E530, 0xE6204528, ++0x46282259, 0x89083260, 0xD41AD119, 0xE601D513, ++0x2160450B, 0x472BD718, 0x4F264F26, 0x0009000B, ++0x0000060A, 0x002039DC, 0x001E1000, 0x002039C8, ++0x00203DFC, 0x00203E08, 0x00203DA0, 0x002039B0, ++0x00203DD0, 0x00203DCE, 0x00203DA2, 0x00203994, ++0x002039C0, 0x002039AC, 0x002039A8, 0x002018A2, ++0x00203B1C, 0x00203B20, 0x002018EE, 0x002039C4, ++0x001E100B, 0x00203B34, 0x00114004, 0x4F222FE6, ++0xDE967FFC, 0x200884E9, 0x2F008D06, 0xD695D494, ++0x0009460B, 0x64F0B19A, 0x6620D293, 0x89022668, ++0xC9BF60E0, 0x7F042E00, 0x000B4F26, 0x000B6EF6, ++0x2FE60009, 0xDE8D4F22, 0x60E0D68D, 0xCBC0D48D, ++0x62602E00, 0xC803602C, 0x40218904, 0x70014021, ++0x6603A002, 0x66034009, 0xD687616D, 0xE500A004, ++0x75016262, 0x74042422, 0x3213625D, 0xD2838BF8, ++0x0009420B, 0xC9BF84E2, 0x4F2680E2, 0x6EF6000B, ++0x2FE62FD6, 0x7FFC4F22, 0x6260D67D, 0x89442228, ++0xD572E100, 0x60502610, 0xCB40D47A, 0x2500440B, ++0x8D052008, 0x62E06E03, 0x7104612C, 0x2F11A006, ++0xD475D66D, 0xDD756760, 0x657C4D0B, 0xE23C6D1D, ++0x8B033D27, 0xD267D472, 0x0009420B, 0x4D214D21, ++0xA005D770, 0x66E6E400, 0x357C4508, 0x74012562, ++0x35D3654D, 0xD76C8BF7, 0x6172E003, 0x81114018, ++0x6E7260F1, 0x81E2700C, 0xD4686172, 0xDD688113, ++0x4D0BDE68, 0xE2016572, 0xD4672E22, 0x420BD255, ++0xD6560009, 0xC93F6060, 0x7F042600, 0x6EF64F26, ++0x6DF6000B, 0x2FC62FB6, 0x2FE62FD6, 0xD25F4F22, ++0x6B436E73, 0x420B6C53, 0x20086D63, 0x64038D1C, ++0xE50ED149, 0x32526210, 0x60C38916, 0x804124B0, ++0x814160D3, 0xA007E500, 0x655D61BC, 0x00EC6053, ++0x364C6653, 0x80647501, 0x3213625D, 0xD63B8BF5, ++0xC9BF6060, 0x2600A008, 0xD23AD44D, 0x6EF64F26, ++0x6CF66DF6, 0x6BF6422B, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x7FC44F22, 0x720262F3, 0x22512F41, ++0x45297202, 0x60632251, 0xE5C4E682, 0x67F38121, ++0x655C666C, 0xE408BFB6, 0x4F267F3C, 0x0009000B, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xE1007FC4, 0x6513ECFF, 0x6B136CCD, 0xDE36D735, ++0xEDFF64F3, 0xD835EA04, 0x6053655C, 0x027D4000, ++0x32C0622D, 0x66038D0D, 0x09ED6063, 0x2491027D, ++0x24217402, 0x698202ED, 0x3928622D, 0x74022892, ++0x75017104, 0x6063625C, 0x07D532A2, 0x0EB58FE4, ++0x2448641C, 0xE6808905, 0x67F3E5C5, 0xBF79666C, ++0x7F3C655C, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0xD11E68F6, 0x6012D21E, 0xCB20E405, ++0x2102E500, 0x000B2242, 0x00002252, 0x001E1017, ++0x00203B38, 0x002018A2, 0x00203906, 0x001E1015, ++0x001E10BF, 0x00117800, 0x001E10FC, 0x00200610, ++0x0020390C, 0x00202AE2, 0x00203B3C, 0x002018EE, ++0x00203B58, 0x0011788C, 0x00203908, 0x002034EC, ++0x00201530, 0x001E2130, 0x00203B60, 0x00202AA4, ++0x00203B64, 0x0020396C, 0x00203974, 0x00203D9C, ++0x001C3500, 0x001D4004, 0xD564D163, 0xE400D764, ++0x2142E20F, 0x17411154, 0xD5622722, 0x9669D762, ++0x15412572, 0x96661562, 0xE6011565, 0xD55F1165, ++0x666CE6F8, 0x25422542, 0x25422542, 0x25422542, ++0x25622542, 0x7601E727, 0x67632572, 0x25627797, ++0xE7042572, 0x2572E248, 0xE2192522, 0xE2702522, ++0x25422542, 0x25422542, 0x25222542, 0x2522E20C, ++0x25422542, 0x25422542, 0x25422542, 0x25422542, ++0x000B154A, 0xE2081145, 0x0009422B, 0x2FE62FD6, ++0x7FFC4F22, 0xC8206043, 0x6E438D02, 0x0009BE67, ++0xC81060E3, 0xBE648901, 0x60E30009, 0x8901C840, ++0x0009BE86, 0xC80160E3, 0xDD3D8938, 0xC80260D0, ++0x2F008D03, 0x460BD63B, 0x60F00009, 0x8902C804, ++0x460BD639, 0x62F00009, 0xC8806023, 0x60D08902, ++0x2D00C97F, 0xC8016023, 0xD6348906, 0x0009460B, ++0x0009A007, 0x51630601, 0x8902C808, 0x460BD630, ++0x60F00009, 0x8902C810, 0x420BD22E, 0xD52E0009, ++0x88026052, 0xD22D8B03, 0xA005E604, 0x88012260, ++0xD22A8B02, 0x2260E601, 0x2522E200, 0xC88060E3, ++0xD227892D, 0x60E36E20, 0x8902C880, 0x420BD225, ++0x60E30009, 0x8902C840, 0x420BD223, 0x60E30009, ++0x8902C802, 0x420BD221, 0x60E30009, 0x890DC804, ++0xDD20D11F, 0x0009410B, 0x0009BF0D, 0x0009BF4C, ++0xD51ED41D, 0x2470E708, 0x25D2BF85, 0xC80860E3, ++0xD21B8905, 0x4F267F04, 0x422B6EF6, 0x7F046DF6, ++0x6EF64F26, 0x6DF6000B, 0x001C581C, 0xA000A000, ++0x001D0100, 0x001D4000, 0x00040021, 0x001C589C, ++0x001E1021, 0x00201A88, 0x00201AAA, 0x0020210C, ++0x00201AC2, 0x00201AD0, 0x002039C0, 0x001E100B, ++0x001E1028, 0x00201B3C, 0x00201B48, 0x00201AD8, ++0x00201AF6, 0x12345678, 0x001E1000, 0x0010F100, ++0x00201B24, 0x644CD6A7, 0x000B346C, 0xD6A62450, ++0x346C644C, 0x2450000B, 0x644CD6A4, 0x000B346C, ++0x625C2450, 0x4208616D, 0x42084119, 0x42006019, ++0x670E614C, 0xD49E321C, 0x4200207D, 0x324CC90F, ++0x2200000B, 0x4208625C, 0x42004208, 0x324C644C, ++0x4200D498, 0x000B324C, 0x2FE62260, 0x614C4F12, ++0x4100D493, 0x6710314C, 0xE29F666D, 0x27294619, ++0x6E536269, 0x672E6573, 0x4221227D, 0x42214221, ++0x7601662C, 0xE4014608, 0x34E84608, 0x644C4600, ++0x071A0467, 0x2150257B, 0x000B4F16, 0x4F226EF6, ++0xD2857FE8, 0x88016021, 0xD2848B7B, 0x26686621, ++0xD2838B77, 0x26686621, 0xE50F8B73, 0xE401BFA2, ++0xBFA4E501, 0xE586E400, 0xE400655C, 0x2F50BFA4, ++0xBFA1E401, 0xE602E506, 0x60634618, 0x81F2E401, ++0x6543BF9F, 0xE40185F2, 0xBFAB6543, 0x85F26603, ++0x6543E401, 0x6603BFB1, 0xE40265F0, 0x6053756C, ++0x80F8BF80, 0xBF82E402, 0x84F8E512, 0x7090E402, ++0x6503BF82, 0x4618E602, 0x81F66063, 0xBF80E402, ++0x85F6E500, 0x6603E402, 0xE500BF8C, 0xE40285F6, ++0xBF926603, 0xE5FEE500, 0xE010655C, 0xBF61E403, ++0xE5130F54, 0xE40EBF63, 0x05FCE010, 0xBF63E40E, ++0xE5007585, 0xBF64E403, 0xE500E640, 0xBF71E403, ++0xE500E640, 0xBF78E403, 0xE5FFE640, 0xE014655C, ++0xBF47E404, 0xE40F0F54, 0xE504BF49, 0x05FCE014, ++0xBF49E40F, 0xE5017584, 0xBF4AE640, 0xE501E404, ++0xBF57E640, 0xE501E404, 0xE404E640, 0xAF5C7F18, ++0x7F184F26, 0x000B4F26, 0x4F220009, 0xD2427FF0, ++0x88016021, 0xD2418B71, 0x26686621, 0xD2408B6D, ++0x26686621, 0xE50F8B69, 0xE401BF1C, 0xBF1EE501, ++0xE586E400, 0xE400655C, 0x2F50BF1E, 0xBF1BE401, ++0xE401E506, 0xBF1C6543, 0xE401E640, 0xBF296543, ++0xE401E640, 0xBF306543, 0x65F0E640, 0x756CE402, ++0xBEFF6053, 0xE40280F4, 0xE512BF01, 0xE40284F4, ++0xBF017090, 0xE6406503, 0xBF02E402, 0xE640E500, ++0xBF0FE402, 0xE640E500, 0xBF16E402, 0xE5FEE500, ++0x6053655C, 0xBEE5E403, 0xE51380F8, 0xE40EBEE7, ++0xE40E84F8, 0xBEE77085, 0xE5006503, 0xBEE8E640, ++0xE500E403, 0xBEF5E640, 0xE500E403, 0xBEFCE640, ++0xE5FFE403, 0x6053655C, 0xBECBE404, 0xE40F80FC, ++0xE504BECD, 0xE40F84FC, 0xBECD7083, 0xE5016503, ++0xBECEE640, 0xE501E404, 0xBEDBE640, 0xE501E404, ++0xE404E640, 0xAEE07F10, 0x7F104F26, 0x000B4F26, ++0x00000009, 0x001E102F, 0x001E1080, 0x001E1090, ++0x001E103F, 0x001E103E, 0x002039BA, 0x002039BC, ++0x002039BE, 0xD21DD11C, 0x66206010, 0x676C7001, ++0x3700C90F, 0xE5008D13, 0x67106210, 0x7701622C, ++0x64232170, 0xD6166010, 0x44084408, 0x3428C90F, ++0x62602100, 0x7201D513, 0x44082620, 0x000B354C, ++0xD10F6053, 0x25586510, 0xE6008D13, 0xD60DD40B, ++0x655C6540, 0x47086753, 0x37584708, 0x47086540, ++0x24507501, 0x367C6040, 0x2400C90F, 0x72FF6210, ++0x000B2120, 0x00006063, 0x00203905, 0x00203904, ++0x00203906, 0x0020352C, 0x7FFC4F22, 0xE680D19F, ++0x666C6212, 0xD29E2F22, 0x67F36563, 0x420B7542, ++0x7F04E404, 0x000B4F26, 0xE6800009, 0xD298666C, ++0xE7006563, 0x422B7540, 0xE6806473, 0xD294666C, ++0xE7006563, 0x422B7543, 0x2F866473, 0x2FA62F96, ++0x2FC62FB6, 0x2FE62FD6, 0x7FCC4F22, 0xDC8ED28D, ++0x72011F21, 0xDB8D1F22, 0xD18EDE8D, 0x66125211, ++0x8B013620, 0x0009A0E5, 0xC9036061, 0x8B018801, ++0x0009A0DF, 0xD288D487, 0xED84420B, 0x2F025503, ++0x30D0845C, 0xA0B88901, 0xD1840009, 0x626C6610, ++0x88016023, 0xD1828B68, 0x62101FC3, 0x895B2228, ++0xE003D480, 0x40186742, 0x68421772, 0xD57EE900, ++0x81816DB3, 0x7D042190, 0x67D26AB2, 0x64E26852, ++0x1F491F57, 0x740464E3, 0x1FA46542, 0x65431F5A, ++0x625275F8, 0x1F761FD5, 0x6D531F2B, 0xDA74D773, ++0x7D94D274, 0x68D21F88, 0x6AA26972, 0xD1726022, ++0x2202CB20, 0xE1401F1C, 0x7601E600, 0x3213626D, ++0x56F48BFB, 0x52F651F5, 0x21222B62, 0x52F851F7, ++0x212256F9, 0x2E6251FA, 0x51FB2412, 0x2D822512, ++0xD9662792, 0x29A2DD5F, 0x6AD2D965, 0xD9646892, ++0x68D21A84, 0x6081DA63, 0x2801CB01, 0xD86266D2, ++0x2A622962, 0xED015AFC, 0x2AD2480B, 0x2AD24D18, ++0x62D2DD5E, 0x2D227201, 0xD15056F3, 0xE2026062, ++0x2602CB01, 0x2120A03D, 0x8B3A2228, 0xE401DD58, ++0x2140E600, 0xE01C2D62, 0xC801005C, 0xD4558B0A, ++0xE600D755, 0xED7D2472, 0x626C7601, 0x8BFB32D3, ++0x24D2DD52, 0xE2FE68C2, 0x2C822829, 0x095CE01E, ++0xE01F5DF1, 0x0A5C2D90, 0x751051F2, 0xED0621A0, ++0xD74BE600, 0x8456D44B, 0x27007601, 0x696C6854, ++0x248039D3, 0x8FF67401, 0xDA477701, 0x2A10E194, ++0xE2007A01, 0x7A0F2A20, 0xD130E805, 0x66102A80, ++0x6023626C, 0x89088801, 0xD240D42A, 0x420B65F2, ++0xD131ED01, 0xAF304D18, 0x65F221D2, 0x8553D43C, ++0x620D6642, 0x89073262, 0xD13BD43A, 0x0009410B, ++0xE601D73A, 0x2762AF1A, 0xD134D41E, 0x410B65F2, ++0xD125ED01, 0xD637D436, 0x460B4D18, 0xAF0D21D2, ++0x7F340009, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0x4F2268F6, 0x85467FF4, 0x2F01E681, ++0x666C8547, 0x854881F1, 0x81F2D209, 0x67F38542, ++0x854381F3, 0x81F4E40C, 0x65636053, 0x420B81F5, ++0x7F0C7540, 0x000B4F26, 0x00000009, 0x001C3D9C, ++0x00202454, 0x0011779A, 0x001C36F8, 0x001C3B9C, ++0x001C3704, 0x00203524, 0x002014A0, 0x00203915, ++0x00203914, 0x00203910, 0x001C3D98, 0x001C3BB4, ++0x001C5960, 0x001C3500, 0x001C3D30, 0x001C8960, ++0x002034FC, 0x001C3D00, 0x0020160C, 0x00117730, ++0x00203918, 0x001C582C, 0x2000A000, 0x0000A000, ++0x0011778C, 0x00117792, 0x00117788, 0x002014CC, ++0x002038EC, 0x002034EC, 0x00201530, 0x001E2130, ++0x00203D7C, 0x002018A2, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xD19B7FEC, 0x2F12E000, ++0x6103D49A, 0x1F4281F2, 0xDD9ADA99, 0xD69A6813, ++0xE0014808, 0x460BDE99, 0x38EC4800, 0x65A21F03, ++0x352052A1, 0xA23E8B01, 0x60510009, 0x8801C903, ++0xA2388B01, 0x52530009, 0x32E0DE91, 0xD9918B10, ++0x64A3490B, 0x4B0BDB90, 0xDE906403, 0xD791D690, ++0xEC01D591, 0x2E02E100, 0x271026C0, 0x2502AFDF, ++0xC8018551, 0xA1578B01, 0x62510009, 0x4200622D, ++0x5E53366A, 0x85E2226D, 0xC903642C, 0x85E36603, ++0x6053650D, 0x40214021, 0x4500C93F, 0x322A6703, ++0x6053252D, 0xC901D17F, 0x60106C03, 0x8801D97F, ++0xDB7F8B05, 0x2120E200, 0xCB0160B2, 0xD17D2B02, ++0x88016011, 0x65A28B0A, 0x8D042448, 0x9B9E6251, ++0xA00322B9, 0x919B2521, 0x2521221B, 0x37B3EB10, ++0x2448895E, 0xD4738B07, 0x22286241, 0x60638903, ++0xA05781F8, 0xD5706473, 0x46084608, 0x85E26273, ++0x46006B50, 0x362C4200, 0x2BB8C910, 0x8F1F6463, ++0x26686603, 0xD2698911, 0x062D6043, 0x4119616D, ++0x6B0E6019, 0x81F820BD, 0x880160C3, 0x646C8F2C, ++0x880F6073, 0xA0278B1B, 0xD2610009, 0x052D6043, ++0x4119615D, 0x670E6019, 0x645C207D, 0x81F8A01C, ++0x890F2668, 0x6043D25B, 0x6B5D052D, 0x60B94B19, ++0x201D610E, 0x60C381F8, 0x8F0D8801, 0x6473645C, ++0xEC00A00A, 0x6043D254, 0x625D052D, 0x60294219, ++0x207D670E, 0x81F8645C, 0x880285F8, 0x85E1890A, ++0x8D07C820, 0xE6DC6203, 0x60232269, 0x81E1A002, ++0x644CE4FF, 0x6210D149, 0x89012228, 0x644CE4FF, ++0x654DEBFF, 0x35B06BBC, 0xDB368B2B, 0x64A34B0B, ++0x410BD135, 0x54036403, 0x85446E03, 0xC948DB40, ++0xDC408808, 0xBEAE8B01, 0x64B3E502, 0x65E34C0B, ++0xDB3DEC01, 0xD13D2DC2, 0x621260B2, 0x72017001, ++0x21228805, 0x2B028F08, 0x666CE680, 0x6563D238, ++0x7549E700, 0x6473420B, 0xA030D436, 0x7FFF0009, ++0x85E28000, 0x20B9EBFC, 0x610381E2, 0x942A85E3, ++0x62032049, 0x450885F8, 0x81E2201B, 0xC90160C3, ++0x40084018, 0x40084008, 0x4000225B, 0x6023220B, ++0x85E481E3, 0x4118E108, 0x81E4201B, 0xE40262A2, ++0x20B98521, 0x67A28121, 0xCB016071, 0x85F82701, ++0x89033042, 0xECE785E2, 0x81E220C9, 0x490BD41E, ++0xA03B0009, 0x7E030009, 0x001C3D30, 0x00203D88, ++0x002034FC, 0x001E212C, 0x002033E0, 0x001C3D00, ++0x00117780, 0x002014A0, 0x0020166C, 0x0011770C, ++0x00203914, 0x00203915, 0x00203910, 0x002018A2, ++0x001C36F8, 0x00203988, 0x00203D98, 0x00203B7C, ++0x00203BFC, 0x00203C7C, 0x00203CFC, 0x00203900, ++0x002034F4, 0x002014CC, 0x0020398C, 0x00203990, ++0x00202454, 0x00203D80, 0x00203D84, 0x602262F2, ++0x40094019, 0xC90F4009, 0x8B0B880A, 0x60E2DE8C, ++0x40094019, 0xC90F4009, 0x8B038808, 0xCB0160A2, ++0x2802A006, 0x65E2DE87, 0x2E527501, 0x286266A2, ++0x52F366F2, 0x2622AE83, 0xD2838551, 0xDE83C802, ++0xA0958B01, 0x420B0009, 0x4E0B64A3, 0x5E036403, ++0x85E46503, 0x4918E908, 0xD77D209B, 0xE04C81E4, ++0xDC7C0B7E, 0x7B01D97C, 0x61C207B6, 0x71016690, ++0x8D062668, 0xD4792C12, 0x420BD279, 0xA070EB01, ++0x62512DB2, 0x4B18EB0F, 0x22B9E102, 0x32104118, ++0x85518B0F, 0x2029E2FC, 0x60518151, 0xCB0172E0, ++0x85E12501, 0x202994A3, 0x85E481E1, 0xA0522049, ++0x675181E4, 0x4719677D, 0x667E6779, 0x7701276D, ++0x6903607C, 0x88014918, 0x25918F3E, 0x6B12D161, ++0x21B27B01, 0x660D85E3, 0x40216063, 0xC93F4021, ++0x6C034600, 0x262D322A, 0xC8016063, 0xDB5ED15D, ++0x967D8901, 0xE6002C6B, 0x666C67CD, 0x40006063, ++0x622D021D, 0x8D0E3270, 0x60436403, 0xE9FF021D, ++0x8B013290, 0x01C5A007, 0x626C7601, 0x3292E904, ++0x646C8BEB, 0x60434400, 0xD15004BD, 0x0B457401, ++0x669D6911, 0x89073670, 0x602D6211, 0x890388FF, ++0xE201DB4B, 0x2B2021C1, 0xECFC8551, 0x815120C9, ++0xCB016051, 0xDC472501, 0x64A34C0B, 0x51F366F2, ++0x85EF2612, 0x54F2D244, 0x650D420B, 0x0009ADE7, ++0xE500DC42, 0x420B2C52, 0x4E0B64A3, 0x54036403, ++0x85446E03, 0x6703E908, 0x65034918, 0x27998541, ++0xDB323790, 0x8F0BD932, 0x6013610D, 0x8B07C820, ++0xC9486053, 0x8B038808, 0xE501BD4D, 0x0009A005, ++0x2128D233, 0xBD468901, 0x64B3E500, 0x490B65E3, ++0xADBCEC01, 0x85F22DC2, 0x7001EE04, 0x31E7610D, ++0x8D0281F2, 0xADA97A08, 0x7F140009, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0xF7FF68F6, ++0x2FE68000, 0xD2234F22, 0x60E36E22, 0x8D02C840, ++0xBBF922E2, 0xE2400009, 0x2E284218, 0xBC048901, ++0x60E30009, 0x8905C810, 0xD21CD41B, 0x0009420B, ++0x0009BC03, 0xC80560E3, 0xBD6D8901, 0x60E30009, ++0x8902C802, 0xAC004F26, 0x4F266EF6, 0x6EF6000B, ++0x001C3D3C, 0x00117760, 0x002014A0, 0x0020166C, ++0x0020348C, 0x00203D9C, 0x00203900, 0x002034F4, ++0x002014CC, 0x0020396C, 0x00203974, 0x00203968, ++0x0020396A, 0x00201530, 0x002018EE, 0x0020398C, ++0x00008000, 0x001C3510, 0x00203D90, 0x002018A2, ++0x080A0C0E, 0x00020406, 0x1A1C1E20, 0x12141618, ++0x2E303234, 0x26282A2C, 0x3A3C3E40, 0x6C625648, ++0x41112F26, 0xE2208F18, 0x890B3123, 0x321CD204, ++0xD1026220, 0x412B312C, 0x00090009, 0x0020340A, ++0x002033C0, 0x000BE000, 0x400062F6, 0x40004000, ++0x40004000, 0x40004000, 0x62F6000B, 0x40004000, ++0x40004000, 0x40004000, 0x40184000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40284000, ++0x62F6000B, 0x40004000, 0x40184000, 0x000B4028, ++0xC90F62F6, 0x40054005, 0x40054005, 0x62F6000B, ++0x4005C907, 0x40054005, 0x62F6000B, 0x4005C903, ++0x000B4005, 0xC90162F6, 0x000B4005, 0x000062F6, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x544F0D0A, ++0x46205355, 0x00003A57, 0x206C754A, 0x32203120, ++0x20383030, 0x323A3132, 0x32313A37, 0x00000000, ++0x00000D0A, 0x00000043, 0x42707372, 0x3D206675, ++0x554E203D, 0x202C4C4C, 0x6E49677A, 0x4E497274, ++0x6D754E51, 0x0000003D, 0x61766E49, 0x2064696C, ++0x72657375, 0x20726F20, 0x2079656B, 0x00214449, ++0x52504545, 0x57204D4F, 0x65746972, 0x6461202C, ++0x003D7264, 0x6C617620, 0x0000003D, 0x00000A0D, ++0x435F4D5A, 0x465F444D, 0x4C445F57, 0x494E495F, ++0x00000054, 0x6E6B6E55, 0x206E776F, 0x6D6D6F63, ++0x3D646E61, 0x00000000, 0x203A3051, 0x00000020, ++0x203A3151, 0x00000020, 0x203A3251, 0x00000020, ++0x203A3351, 0x00000020, 0x203A3451, 0x00000020, ++0x2B434741, 0x73696F4E, 0x61432065, 0x7262696C, ++0x6F697461, 0x6166206E, 0x6F206C69, 0x6974206E, ++0x0D0A656D, 0x00000000, 0x00000072, 0x00205220, ++0x00000D0A, 0x62735576, 0x7473725F, 0x00000A0D, ++0x62735576, 0x7375735F, 0x646E6570, 0x00000A0D, ++0x62735576, 0x7365725F, 0x000A0D6D, 0x00000044, ++0x44387570, 0x72637365, 0x6F747069, 0x3D584572, ++0x00000000, 0x00000047, 0x00000042, 0x72746E49, ++0x6D652051, 0x2C797470, 0x49677A20, 0x4972746E, ++0x754E514E, 0x00003D6D, 0x654C7245, 0x0000006E, ++0x00000049, 0x20746F4E, 0x756F6E65, 0x49206867, ++0x4220514E, 0x0A0D6675, 0x00000000, 0x000000FF, ++0x00020001, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x010E010D, ++0x00020003, 0x01090108, 0x0002010A, 0x02000003, ++0x02020201, 0x02040203, 0x02060205, 0x02020200, ++0x02040203, 0x020C020B, 0x020E020D, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x000000FF, ++0x00020001, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x010E010D, ++0x00020003, 0x01090108, 0x0002010A, 0x00030003, ++0x02020201, 0x02040203, 0x02060205, 0x02020200, ++0x02040203, 0x020C020B, 0x020E020D, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x010E010D, ++0x00FF010F, 0x01090108, 0x010B010A, 0x0200010F, ++0x02020201, 0x02040203, 0x02060205, 0x02020200, ++0x02040203, 0x020C020B, 0x020E020D, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x010E010D, ++0x00FF010F, 0x01090108, 0x010B010A, 0x010F010F, ++0x02020201, 0x02040203, 0x02060205, 0x02020200, ++0x02040203, 0x020C020B, 0x020E020D, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00205220, ++0x00000046, 0x00000059, 0x73204142, 0x003D7165, ++0x49544120, 0x0000204D, 0x00000000, 0x00000000, ++0x002E0209, 0x80000101, 0x000409FA, 0x00FF0400, ++0x05070000, 0x02000201, 0x82050700, 0x00020002, ++0x03830507, 0x07010040, 0x40030405, 0x02090100, ++0x0101002E, 0x09FA8000, 0x04000004, 0x000000FF, ++0x02010507, 0x07000040, 0x40028205, 0x05070000, ++0x00400383, 0x04050701, 0x00004002, 0x00000000, ++0x00000000, 0x07090000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, }; ++ ++const u32_t zcFwImageSize=15928; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu_BA.c +@@ -0,0 +1,874 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE917FFC, 0xE114D791, ++0x1E13D491, 0x1E4C470B, 0x0009B017, 0x95C2E600, ++0xC84060E2, 0x2F028F03, 0x8FF93652, 0xD48B7601, ++0x4E0BDE8B, 0xD48B0009, 0x00094E0B, 0x4E0BD48A, ++0x7F040009, 0xA0474F26, 0x4F226EF6, 0x410BD187, ++0xD4870009, 0x0009440B, 0x450BD586, 0xD7860009, ++0x611DE1FF, 0xD1852712, 0x6012E2FF, 0xCB01D484, ++0x71DC2102, 0x71042122, 0x2122E501, 0xD5812452, ++0xD2819792, 0xE7002572, 0xD481D180, 0x2270D681, ++0x2172E201, 0x26202470, 0xE4FFD67F, 0xE6002641, ++0xE104D57E, 0x6063666D, 0x626D7601, 0x32124000, ++0x05458FF8, 0xE501D27A, 0xD17A2250, 0xD57BD47A, ++0xE700E600, 0x25722470, 0x11622162, 0x11691166, ++0x4F26116A, 0x116E000B, 0xD1757FC4, 0x2F12D875, ++0xD476D175, 0xD577D676, 0x1F87D777, 0xD97778FC, ++0x1F1BD277, 0x1F417104, 0x1F647404, 0x1F887604, ++0x71F41F1C, 0x1F42E8C8, 0x1F651F53, 0x1F991F76, ++0x1F1D1F2A, 0xDD6F688C, 0xDA70DE6F, 0xDC71DB70, ++0x00094A0B, 0x00094B0B, 0x00094C0B, 0x6010D15E, ++0x8B0F8801, 0xE950D15D, 0x49186212, 0x8B073296, ++0x56FAD159, 0x2120E200, 0xCB016062, 0x2602A002, ++0x21227201, 0x880160D2, 0xD1638907, 0x32866212, ++0xD1628903, 0x88016010, 0x64E28BDA, 0x52F751F8, ++0x55E12142, 0x2252D15E, 0x661254FB, 0x246259FC, ++0x29725711, 0x880160D2, 0x66E28B53, 0x362052E1, ++0x6061894C, 0x8801C90F, 0xD1568B48, 0x36206212, ++0xA0438903, 0x27102162, 0xD5530FA0, 0x6651E710, ++0x626D7601, 0x8F3C3273, 0x65F22561, 0x695251F2, ++0x54F359F1, 0x679252F4, 0x61426512, 0x56F66922, ++0x642252F5, 0xCB206062, 0xE6002602, 0x76011F1E, ++0x626DE110, 0x32134118, 0x51FE8FF8, 0x267256F1, ++0x56F457F2, 0x55F32752, 0x251257F5, 0x27422692, ++0x51F969E2, 0x2192D43D, 0xE90161F2, 0x2192440B, ++0x491865F2, 0xD9382592, 0xE200D539, 0x62512921, ++0x720154FD, 0x622D2521, 0x2422A003, 0xE200D932, ++0xE9012921, 0x2D92D12C, 0x26686612, 0xAF6F8B01, ++0xD6300009, 0x0009460B, 0xE700D128, 0x2170AF68, ++0x001C001C, 0x00200F7C, 0x0000B38E, 0x0020322C, ++0x0020145E, 0x00203238, 0x00203250, 0x0020141C, ++0x0020151C, 0x00200FA0, 0x001C3510, 0x001C3648, ++0x001E212C, 0x00203188, 0x00202D24, 0x00203190, ++0x0020319C, 0x002031A8, 0x002031B8, 0x002031BC, ++0x002031B0, 0x00117708, 0x002031B1, 0x002031B4, ++0x001C3D30, 0x00117718, 0x00117734, 0x001C3B9C, ++0x001C3704, 0x001C3D98, 0x001C3500, 0x001C3D00, ++0x001C36F8, 0x001C1028, 0x00202D98, 0x00201328, ++0x00202C04, 0x00201E18, 0x002034BC, 0x002031BA, ++0x00202D90, 0x002031CC, 0x002031D0, 0x00201276, ++0x002031D2, 0x00201FD0, 0x2FB62F96, 0x2FD62FC6, ++0x4F222FE6, 0xDE947F8C, 0x61E0E024, 0x0F14D493, ++0x710161E3, 0xD7926210, 0x470BE028, 0xD5910F24, ++0x0009450B, 0x6D032008, 0x1F0B8F11, 0xD48FDC8E, ++0xDD8F67C0, 0x657C4D0B, 0xDD8FD18E, 0x6B9C6910, ++0x420862B3, 0x32B84208, 0x3D2C4208, 0xE0281FDB, ++0xE58004FC, 0x604C66E2, 0x3050655C, 0x2D628F13, ++0x01FCE024, 0x641CE500, 0x625DDE84, 0x8B013243, ++0x0009A33D, 0x6753655D, 0x607037EC, 0x39DC6953, ++0xAFF27501, 0x20088094, 0xE0248B13, 0xE50001FC, ++0xA009DE7A, 0x655D641C, 0x32EC6253, 0x6C536B22, ++0x3CDC67B2, 0x75041C71, 0x3243625D, 0xA31E8BF3, ++0x88012D10, 0xE0248B16, 0xE40001FC, 0x671C2D40, ++0x624DDE6E, 0x8B013273, 0x0009A311, 0x6CE3644D, ++0x7C046943, 0x39EC6B43, 0x65923BCC, 0x74086DB2, ++0x25D2AFEF, 0x8B198804, 0x01FCE024, 0x2D70E700, ++0x1FD86D1C, 0x627DDE61, 0x8B0132D3, 0x0009A2F7, ++0x6B73677D, 0x3BEC61E3, 0x710464B2, 0x3C1C6C73, ++0x694265C2, 0x29597708, 0x2492AFED, 0x8B188805, ++0x01FCE024, 0x2D40E400, 0xDE54671C, 0x3273624D, ++0xA2DC8B01, 0x644D0009, 0x6BE36D43, 0x65D23DEC, ++0x61437B04, 0x6C1231BC, 0x74086952, 0xAFED29CB, ++0x88312592, 0xDE4A8B20, 0x65E6DB4A, 0x61E6DC4A, ++0x67E2D94A, 0x62E27E04, 0x1FEC7EE8, 0x7E0464E2, ++0x6EE21FED, 0x5BFD2BE0, 0x60B27B04, 0xC9011FBE, ++0x6BB22C00, 0x29B04B09, 0xDC412F26, 0x66134C0B, ++0xE2007F04, 0x2D20A2AB, 0x8B218830, 0xD939DE38, ++0xE06465E6, 0x720462E3, 0x672666E2, 0x6E23DC36, ++0x62227EE8, 0x6BE261E6, 0x29B01FEF, 0x7E040F16, ++0xC90160E2, 0x6EE22C00, 0x4E09DC30, 0x2F262CE0, ++0xD130E068, 0x04FE410B, 0xE2007F04, 0x2D20A287, ++0x8B058833, 0x4E0BDE2C, 0xE1000009, 0x2D10A27F, ++0x89018828, 0x0009A106, 0xE143DE20, 0xE04062E1, ++0x3217622D, 0x0FE68F04, 0x6023E240, 0x262106FE, ++0x8B013217, 0x0009A0EF, 0x02FEE040, 0x8521E401, ++0x8B013046, 0x0009A0E7, 0xE501E040, 0x2D5007FE, ++0x6471B265, 0x09FEE040, 0x6291E143, 0x652DE068, ++0x8D6B3517, 0xE6400F56, 0x8B273563, 0xE048E600, ++0xE11A0F65, 0x72C0A031, 0x00117800, 0x00203254, ++0x0020145E, 0x00202588, 0x002031A2, 0x00203258, ++0x002014AA, 0x002031A1, 0x00202DC8, 0x00117804, ++0x00117810, 0x0020319D, 0x0020319E, 0x0020319F, ++0x00200C2C, 0x00200C80, 0x00200C7C, 0x41216153, ++0x41214121, 0x41214121, 0x45214521, 0x60534521, ++0x6603C903, 0x0F65E048, 0xE0077118, 0xE0442209, ++0x641D0F25, 0x65F3E04C, 0x0F46B28C, 0x04FDE048, ++0x0BFDE044, 0x61BD674D, 0x41084708, 0x0F16E050, ++0xD29B6073, 0x420B09FE, 0x6C07E00F, 0x607329C9, ++0xE0400F96, 0x65F30EFE, 0x6D0D85E2, 0x01FEE050, ++0x60D3420B, 0x6073290B, 0xE04C0F96, 0x04FEB251, ++0x06FEE040, 0x6261E068, 0x0F56652D, 0x3563E640, ++0xE000894E, 0x602381F8, 0x4008C903, 0x6B034000, ++0xE0546103, 0xE0580FB6, 0xECFFDD85, 0x6CCC0FF6, ++0x0FD6E06C, 0x4D0B60C3, 0x42216253, 0x42214221, ++0x64234221, 0x324C4200, 0xE05C6E07, 0x45214200, ++0xE0400FE6, 0x0BFE4521, 0xC9036053, 0x30FC4008, ++0x6D037B06, 0x85F81F05, 0x6C2D1FB7, 0x1FC66E03, ++0x0FC6E060, 0x05FEE058, 0x64C3B22C, 0x33FCE354, ++0x563262D2, 0x22696132, 0x67B42D22, 0x490B5936, ++0x220B607C, 0x05FEE058, 0x64C32D22, 0x7E01B201, ++0xE70662ED, 0x8FE33273, 0xE0407C01, 0x626106FE, ++0x06FEE040, 0x85614200, 0x302C760C, 0x6103701B, ++0x64F3E500, 0x7501E704, 0x6B5D6966, 0x24923B73, ++0x74048FF9, 0xB1E465F3, 0xE040641D, 0xB1A306FE, ++0xA17C6461, 0xD4570009, 0xE201D757, 0x2D20470B, ++0x0009A175, 0x8B078829, 0xEC00DE54, 0x61E22DC0, ++0x641DB175, 0x0009A16B, 0x622CE281, 0x8B013020, ++0x0009A0B6, 0x06FCE028, 0xE682626C, 0x3260666C, ++0x56FB8B20, 0x2610E124, 0x5217D149, 0x52181621, ++0x52191622, 0x521A1623, 0x551B1624, 0x1655E200, ++0x1656551C, 0x1657551D, 0x1658551E, 0x1659551F, ++0x11281127, 0x112A1129, 0x112C112B, 0x112E112D, ++0x112FA13D, 0x666CE683, 0x8B0B3260, 0xD63752FB, ++0x2250E500, 0xD2376562, 0x22527604, 0xD6366262, ++0x2620A12D, 0x666CE690, 0x8B033260, 0x0009B1C7, ++0x0009A011, 0x666CE691, 0x8B103260, 0x6252D52B, ++0x2228622C, 0xD22D8904, 0x0009420B, 0x0009A003, ++0x420BD22B, 0x56FB0009, 0xA110E200, 0xE6B02620, ++0x3260666C, 0xE0248B34, 0xE07002FC, 0x0F16612C, ++0xEB04EC00, 0x01FEE070, 0x321362CD, 0xA0FE8B01, ++0xD21A0009, 0x6DC36CCD, 0x72043D2C, 0x312C61C3, ++0x6D126ED2, 0xD114D41B, 0x0009410B, 0x410BD11A, ++0xD41A64E3, 0x420BD210, 0xD2170009, 0x64D3420B, ++0xD60DD417, 0x0009460B, 0x61E3E600, 0x316C666D, ++0x626D7601, 0x21D032B3, 0x4D198FF7, 0x7C08AFD2, ++0xD211D410, 0xD4116542, 0x0009420B, 0x0009A0CF, ++0x00202C80, 0x00203278, 0x0020145E, 0x00117804, ++0x00202D2C, 0x00203188, 0x0020319C, 0x00200CBA, ++0x00200CE0, 0x00203290, 0x002014A2, 0x002032A4, ++0x002032AC, 0x00117800, 0x002014AA, 0x002032B0, ++0xD5B5D1B4, 0x6252E040, 0x75046612, 0x2162362C, ++0x56116256, 0x1161362C, 0x62526653, 0x76085512, ++0x1152352C, 0x55136262, 0x352C76EC, 0x65631153, ++0x56146262, 0x362C7510, 0x66531164, 0x55156252, ++0x352C7610, 0x62621155, 0x362C5616, 0xD6A31166, ++0x55176262, 0x352C7604, 0x62661157, 0x352C5518, ++0x65631158, 0x56196262, 0x362C7504, 0x62561169, ++0x362C561A, 0x6256116A, 0x362C561B, 0x6653116B, ++0x551C6252, 0x352C7604, 0x6266115C, 0x352C551D, ++0x6263115D, 0x551E6662, 0x356C7204, 0x6622115E, ++0xD58F521F, 0x112F326C, 0x061E6252, 0x362C7594, ++0xE0440166, 0x62526653, 0x7644051E, 0x0156352C, ++0x6262E048, 0x362C061E, 0xD6860166, 0x6262E054, ++0x4229051E, 0x0156352C, 0x62627604, 0x061EE058, ++0x362C4229, 0x56FB0166, 0x2620E238, 0x021EE044, ++0x1621E048, 0x16226212, 0x16235211, 0xE2005512, ++0x55151654, 0x55131655, 0x55161656, 0x051E1657, ++0x1658E040, 0xE050051E, 0x55141659, 0x051E165A, ++0x165BE04C, 0xE054051E, 0x051E165C, 0x165DE058, ++0xE044051E, 0x0126165E, 0x2122E048, 0x11221121, ++0x11231125, 0x01261126, 0x0126E040, 0x1124E050, ++0xE04C0126, 0xE0540126, 0xE0580126, 0x7F740126, ++0x6EF64F26, 0x6CF66DF6, 0x000B6BF6, 0x4F2269F6, ++0xE240614D, 0x89143123, 0x3127E21F, 0x8B09D75A, ++0xD45A614D, 0xE00171E0, 0x5671440B, 0x26596507, ++0x1761A007, 0xE001D455, 0x6672440B, 0x26596507, ++0x4F262762, 0x0009000B, 0x614D4F22, 0x3123E240, ++0xE21F8912, 0xD74C3127, 0x614D8B08, 0x5671D24B, ++0x420B71E0, 0x260BE001, 0x1761A006, 0x6672D247, ++0xE001420B, 0x2762260B, 0x000B4F26, 0xE6400009, ++0x46284618, 0x6252D542, 0x89FC2268, 0x0009000B, ++0x4618E680, 0xD53E4628, 0x22686252, 0x000B89FC, ++0xA0010009, 0x7201E200, 0x8BFC3242, 0x0009000B, ++0x4618E680, 0xD5374628, 0x22686252, 0x000B8BFC, ++0x2FE60009, 0x7FFC4F22, 0xBFF16E53, 0x61E22F42, ++0xE280D631, 0x54E11615, 0x16464218, 0x422855E2, ++0x57E31657, 0x16786EF2, 0x26E22E2B, 0x4F267F04, ++0x6EF6AFCE, 0x2FD62FC6, 0x4F222FE6, 0x6C53DD26, ++0x6E43BFD6, 0x2DE2BFBB, 0x0009BFD2, 0x2C1251D5, ++0x1C4154D6, 0x1C5255D7, 0x1C6356D8, 0x6EF64F26, ++0x000B6DF6, 0x61636CF6, 0xA004E600, 0x62564109, ++0x24227601, 0x36127404, 0x000B8BF9, 0x4F220009, ++0xD117D416, 0x0009410B, 0xD417D216, 0xE5056022, ++0x2202CB20, 0xD5152452, 0x450BE700, 0xD7142472, ++0x0009470B, 0xE601D113, 0x2162D213, 0x4F264618, ++0x2262000B, 0x00202D2C, 0x001C36A0, 0x001C3CA0, ++0x001C36F4, 0x001C3B88, 0x001C3704, 0x00202C80, ++0x001C373C, 0x001C3700, 0x001C370C, 0x002032C4, ++0x0020145E, 0x001C3500, 0x001D4004, 0x002014D4, ++0x00200FA0, 0x001E212C, 0x001C3D30, 0x0009A1A9, ++0x2FE62FD6, 0xDD8F4F22, 0xA0049EA7, 0xD48E0009, ++0x420BD28E, 0x62D265D2, 0x8BF822E8, 0x0009A004, ++0xD28AD48B, 0x55D1420B, 0x22E852D1, 0xA0048BF8, ++0xD4880009, 0x420BD285, 0x52D255D2, 0x8BF822E8, ++0x0009A004, 0xD281D484, 0x55D3420B, 0x22E852D3, ++0xA0048BF8, 0xD4810009, 0x420BD27C, 0x52D455D4, ++0x8BF822E8, 0x6EF64F26, 0x6DF6000B, 0x2FD62FC6, ++0x4F222FE6, 0x6E636D73, 0x6C53B018, 0x64C357F4, ++0xB05465E3, 0xB06A66D3, 0xB09A0009, 0xB09E0009, ++0xB0A20009, 0xB0BE0009, 0xB0C10009, 0xB1240009, ++0x4F260009, 0x6DF66EF6, 0x6CF6A023, 0x3412D16C, ++0xD66C0529, 0x2650D76C, 0x2742000B, 0x0009A014, ++0x2FD62FC6, 0x4F222FE6, 0x6E636D73, 0x6C53BFEE, ++0x64C357F4, 0xB02A65E3, 0xB10666D3, 0x4F260009, ++0x6DF66EF6, 0x6CF6A005, 0xE603D260, 0x000B4618, ++0xD25E2262, 0x000BE600, 0x4F222262, 0xE40ABF7E, ++0x0009BF7E, 0xE104D25A, 0xE5004118, 0x2212E40A, ++0x2252BF74, 0x6072D757, 0x4F26CB20, 0x2702000B, ++0xD1554F22, 0xE400410B, 0x452BD554, 0x2FE64F26, ++0x6E63D153, 0x44186612, 0x45289210, 0x26294408, ++0x44084500, 0x4400265B, 0x4708264B, 0x47082162, ++0x27EBD14C, 0x000B2172, 0x03F06EF6, 0x2FE61FFF, ++0xDE494F22, 0xE40AE101, 0x2E12BF48, 0x726C62E3, ++0xE401E100, 0x22122212, 0x22122212, 0x22122212, ++0xE7302242, 0xE40AE503, 0x22122212, 0x22122212, ++0x22122212, 0x22122212, 0x22122212, 0x22122212, ++0x22522272, 0x22122212, 0x22122212, 0x22122212, ++0x22122212, 0x121ABF22, 0x2E62E600, 0x000B4F26, ++0xD2326EF6, 0xE441E101, 0x000B2212, 0xD1302242, ++0xE605D430, 0x000B2162, 0xD52F2462, 0x6050D22F, ++0x8B0E8801, 0x6040D42E, 0x8B078801, 0x9626D52D, ++0x88016050, 0x96238B0C, 0x0009A00A, 0xA0079621, ++0xE6000009, 0x2262D426, 0x88016040, 0xE6048B00, ++0xAEF3E40A, 0xD2242262, 0xE40AE601, 0x2262AEEE, ++0x2FC62FB6, 0x2FE62FD6, 0xDC204F22, 0x60C2ED00, ++0xCB01EB64, 0x60C22C02, 0xA041C901, 0x03C46E03, ++0x034003D4, 0x001C3B88, 0x002032C8, 0x002014AA, ++0x002032D0, 0x002032D8, 0x002032E0, 0x002032E8, ++0x0025E720, 0x002034B8, 0x0020318C, 0x001C5968, ++0x001D4004, 0x001C3500, 0x0020124A, 0x00201276, ++0x001C5814, 0x001C59D0, 0x001C5830, 0x001C6268, ++0x001C59A4, 0x001C639C, 0x0020319E, 0x001C5804, ++0x0020319D, 0x0020319F, 0x001C581C, 0x001C5860, ++0x89073DB2, 0xE40A60C2, 0xBE9FC901, 0x7D016E03, ++0x8BF52EE8, 0x8B033DB2, 0xD23ED43D, 0x0009420B, ++0x4F26E40A, 0x6DF66EF6, 0xAE8F6CF6, 0x44116BF6, ++0x604B8F01, 0x000B6043, 0x2FB60009, 0x2FD62FC6, ++0x4F222FE6, 0xDC347FFC, 0x60C2ED00, 0xCB02EB64, ++0x60C22C02, 0xC9022F02, 0x6E03A009, 0x89083DB3, ++0xE40A60C2, 0xC9022F02, 0x6E03BE70, 0x2EE87D01, ++0x3DB38BF4, 0xD4298B08, 0x7F04D226, 0x6EF64F26, ++0x6CF66DF6, 0x6BF6422B, 0x4F267F04, 0x6DF66EF6, ++0x000B6CF6, 0xD5226BF6, 0x60525651, 0x000B4628, ++0x2FB6306C, 0x2FD62FC6, 0x4F222FE6, 0x4F024F12, ++0x6E43BFF1, 0xDC1B6B03, 0xBFECDD1B, 0x30B80009, ++0x060A3C05, 0x46094609, 0x3D654601, 0x4209020A, ++0x42094209, 0x8BF032E2, 0x4F164F06, 0x6EF64F26, ++0x6CF66DF6, 0x6BF6000B, 0x4F222FE6, 0xE102DE0F, ++0xE403E500, 0xBFD42E12, 0xE6062E52, 0xE7004618, ++0x2E62E403, 0x4F262E72, 0x6EF6AFCB, 0x0009000B, ++0x002032F0, 0x0020145E, 0x001C5860, 0x00203308, ++0x001C1040, 0xCCCCCCCD, 0x10624DD3, 0x001D4004, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xE5007FD8, 0x6453E110, 0x6C534128, 0x655DEE0A, ++0x46086653, 0x4608365C, 0x361C7501, 0x675D6043, ++0x60C30F66, 0x37E3ED00, 0x816126C1, 0x81638162, ++0x16D316D2, 0x8FEA16D4, 0x68F27404, 0xDAB3D9B2, ++0x29821981, 0xD1B259F1, 0x2A921A91, 0x5BF35AF2, ++0x5EF55DF4, 0x11A154F6, 0x11B321A2, 0x11D511B2, ++0x11E711D4, 0x114911E6, 0x55F71148, 0xEE00DBA9, ++0xDDA957F8, 0xD6A952F9, 0x1B5164E3, 0xDBA82B52, ++0xEAB8D8A8, 0x2D72E945, 0x6AAC2622, 0x6EED4908, ++0x4D086DE3, 0x3DEC61E3, 0x4D084108, 0x3DBC31EC, ++0x410860C3, 0x81D12DC1, 0x4108E050, 0x41084008, ++0x60C381D2, 0xE500318C, 0x81D334A2, 0x1D131DD2, ++0x8D01D494, 0xD4911D54, 0xB08165D3, 0x64ED7E01, ++0x8BDC3492, 0xDB94D18D, 0xD28B6812, 0x1B814829, ++0x2FD26412, 0x2B92694D, 0xD98A6722, 0x1B734729, ++0xD7876822, 0x1BA26A8D, 0xD28C6B72, 0x22B2D586, ++0xE0035D72, 0x5E7412D2, 0x12E44018, 0xD6885176, ++0x54781216, 0x1248E1FF, 0xD4856792, 0x6852127A, ++0x28C1E703, 0x81916952, 0x6A52E050, 0x81A24008, ++0x60C36B52, 0x6D5281B3, 0x6E521DD2, 0x62521E63, ++0x1264E600, 0x46086563, 0x7501364C, 0x665D2612, ++0x8BF83673, 0xE003D471, 0x40186542, 0x674225C1, ++0x8171D274, 0xEE006842, 0x69421882, 0x1923E024, ++0xE5806A42, 0x6B421AE4, 0x81B266E3, 0xD46D6C42, ++0x655C81C3, 0x6D63666D, 0x616D7604, 0x31533D4C, ++0x2DE28FF8, 0xD569D268, 0x74042422, 0x7F282452, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x664268F6, 0xC8036061, 0xE5008D04, 0xC9036061, ++0x8B038802, 0x65635262, 0x24125124, 0x6053000B, ++0x2FE62FD6, 0x7FEC4F22, 0x62536E53, 0x6D43E550, ++0x4508E400, 0xE101A001, 0x60435224, 0x81212211, ++0x60538123, 0x56E28122, 0x8BF53620, 0x16E4D250, ++0xE61464F3, 0x65E3420B, 0xE4FC65E1, 0x2E512549, ++0x65F361F1, 0x2F112149, 0xD14954D1, 0xE614410B, ++0x607157D1, 0x2701CB01, 0x7F141DE1, 0x6EF64F26, ++0x6DF6000B, 0x2FE62FD6, 0x7FEC4F22, 0x66536E53, ++0x6D43E5FC, 0x20596061, 0x2601CB01, 0x326052E2, ++0x12E48B06, 0x31E051E2, 0x52D18B04, 0x1E22A002, ++0x5664AFF0, 0x64F3D236, 0x420BE614, 0x67E165E3, ++0x2719E1FC, 0x67F12E71, 0x271954D1, 0x65F3D130, ++0x410BE614, 0x52D12F71, 0xCB016021, 0x1DE12201, ++0x4F267F14, 0x000B6EF6, 0x2FE66DF6, 0x624C4F22, ++0x4208DE1B, 0xA0054200, 0x52523E2C, 0x5624D417, ++0x2E62BF8E, 0x52E165E2, 0x8BF63520, 0x2622D61B, ++0x000B4F26, 0x2FB66EF6, 0x2FD62FC6, 0x4F222FE6, ++0xDB1CDC10, 0x66C252C1, 0x89403620, 0xC9036061, ++0x893C8801, 0xDD18DE0B, 0x64E3BF63, 0x85036503, ++0x620D66B2, 0x892B3262, 0xBF9BD403, 0xD4130009, ++0x00094D0B, 0x0009AFE6, 0x00202D88, 0x00202D90, ++0x00202D98, 0x00202DC0, 0x002031A4, 0x002031AC, ++0x001000C8, 0x00101680, 0x001E2108, 0x001C3D00, ++0x00117880, 0x00117780, 0x00040020, 0x0026C401, ++0x00200B26, 0x00203188, 0x0020145E, 0x00203324, ++0x64E3BF3E, 0x4D0BD406, 0xAFBB0009, 0xD2050009, ++0x4F262262, 0x6DF66EF6, 0x000B6CF6, 0x00006BF6, ++0x00203328, 0x001C3D28, 0x2FC62FB6, 0x2FE62FD6, ++0x7FFC4F22, 0x6022D22B, 0x8D41C803, 0xDE2A2F01, ++0xDB2BDC2A, 0xED01A017, 0xC9036051, 0x89168801, ++0xD128D426, 0x0009410B, 0x61035503, 0xC8208551, ++0xE0508903, 0x720102BE, 0xD2230B26, 0x420B64E3, ++0xD6226513, 0x52C126D2, 0x352065C2, 0xDE208BE4, ++0xDB21DD20, 0x52D1DC21, 0x352065D2, 0x60518918, ++0x8801C903, 0xD41B8914, 0x460BD616, 0x57030009, ++0x8F0437E0, 0xE2016503, 0xAFEC2B20, 0xD4182C52, ++0x420BD218, 0xD6110009, 0x4118E101, 0x2612AFE3, ++0xC80460F1, 0xD2148907, 0x4F267F04, 0x6DF66EF6, ++0x422B6CF6, 0x7F046BF6, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x001E2100, 0x00202D98, 0x00202D90, ++0x00202D2C, 0x00201162, 0x002011E4, 0x001C3D30, ++0x00117880, 0x00202D88, 0x002031A8, 0x002031A4, ++0x00202DC0, 0x00201180, 0x00200308, 0xE601D203, ++0x1265D503, 0x000B2252, 0x00001266, 0x001C1010, ++0x0000C34F, 0x0009000B, 0x2FD62FC6, 0x4F222FE6, ++0x6D436C53, 0xEE00A004, 0x7E0164D4, 0x644CBFF2, ++0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, 0xE5006CF6, ++0x6643A002, 0x76017501, 0x22286260, 0xAFE38BFA, ++0x2FE60009, 0x75076253, 0xE1086753, 0x6043EE0A, ++0x4409C90F, 0x650330E2, 0x8D014409, 0xE630E637, ++0x4110365C, 0x8FF22760, 0xE00077FF, 0x000B8028, ++0x000B6EF6, 0x000BE000, 0x2FE6E000, 0x7FEC4F22, ++0x6E436253, 0xBFDC65F3, 0xBFD06423, 0xBFCE64E3, ++0xD40364F3, 0x0009BFCB, 0x4F267F14, 0x6EF6000B, ++0x0020332C, 0xE4FDD29A, 0xD79A6122, 0x22122149, ++0x74016022, 0x2202CB01, 0xD5976622, 0x22622649, ++0xC8406070, 0x60528902, 0x2502CB04, 0xE1F76452, ++0x25422419, 0xE7016052, 0x2502C9CF, 0xE6026052, ++0x2502CB03, 0x15624718, 0x1573000B, 0xD78CD58B, ++0xD48DD28C, 0xE600E100, 0x27112511, 0xAFD12210, ++0x664C2461, 0x4600D289, 0x6060362C, 0x000BCB10, ++0x654C2600, 0x4500D285, 0x6650352C, 0x2619E1EF, ++0x2560000B, 0xD282664C, 0x362C4600, 0xCB106060, ++0x2600000B, 0xD27E654C, 0x352C4500, 0xE1EF6650, ++0x000B2619, 0x664C2560, 0x4600D278, 0x6060362C, ++0x000BCB08, 0x654C2600, 0x4500D274, 0x6650352C, ++0x2619E1F7, 0x2560000B, 0xD271664C, 0x362C4600, ++0xCB086060, 0x2600000B, 0xD26D654C, 0x352C4500, ++0xE1F76650, 0x000B2619, 0x624C2560, 0x4200D667, ++0x6020326C, 0x4021C908, 0x40214021, 0x600C000B, ++0xD663624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0xD15F600C, 0x341C644C, 0x000B6240, ++0xD15D602C, 0x341C644C, 0x000B6240, 0x2FE6602C, ++0x6E434F22, 0xE60A645C, 0x89143467, 0x0009BFEB, ++0x60EC640C, 0x8B028801, 0xA002E00F, 0x44092409, ++0x624C4409, 0x3263E60A, 0xBFE28905, 0x620C644C, ++0xC8806023, 0xE2008B00, 0x4F266023, 0x6EF6000B, ++0xD64A4F22, 0x88016062, 0xB2458B03, 0xA0030009, ++0xD2470009, 0x2260E640, 0xE200D646, 0x000B4F26, ++0x4F222622, 0x6062D641, 0x8B018802, 0x0009B28E, ++0xE200D640, 0x000B4F26, 0xD53C2622, 0xE100D43C, ++0x2512E701, 0x2470000B, 0xE604D239, 0x2260000B, ++0xD4394F22, 0x410BD139, 0xD5390009, 0x6650E1FD, ++0x2619D238, 0x2560E700, 0x000B4F26, 0x4F222270, ++0xD132D435, 0x0009410B, 0xE7FBD531, 0x26796650, ++0x000B4F26, 0x4F222560, 0xD12CD430, 0x0009410B, ++0xE7F7D52B, 0x26796650, 0x000B4F26, 0xD5282560, ++0x6250942D, 0x000B2249, 0xD5252520, 0x6250E4BF, ++0x000B2249, 0x4F222520, 0x8522D225, 0x2008600D, ++0x88018911, 0x88038913, 0x88058915, 0x88068942, ++0x88088948, 0x8809894E, 0x880A8954, 0x880B895A, ++0xA0678960, 0xB0690009, 0xA0640009, 0xB077600C, ++0xA0600009, 0xB080600C, 0xA05C0009, 0xFF7F600C, ++0x001E2148, 0x001E1000, 0x001E1108, 0x002031FC, ++0x002031FE, 0x0020321D, 0x002031E0, 0x001E103F, ++0x001E105F, 0x001E102F, 0x001E1090, 0x00203204, ++0x001E100B, 0x00203200, 0x00203330, 0x0020145E, ++0x001E1028, 0x0020321C, 0x0020333C, 0x0020334C, ++0x002031D4, 0x6260D684, 0x8B2B2228, 0x0009B061, ++0x600CA029, 0x6260D680, 0x8B232228, 0x0009B069, ++0x600CA021, 0x6260D67C, 0x8B1B2228, 0x0009B0C7, ++0x600CA019, 0x6260D678, 0x8B132228, 0x0009B0CD, ++0x600CA011, 0x6260D674, 0x8B0B2228, 0x0009B125, ++0x600CA009, 0x6260D670, 0x8B032228, 0x0009B13D, ++0x600CA001, 0x4F26E000, 0x0009000B, 0xD26CD16B, ++0xD56C8412, 0x4000C90F, 0xD76B012D, 0xE403D66B, ++0xE20F611C, 0x2540E001, 0x25202712, 0x2602000B, ++0xE601D262, 0x30668523, 0xE0008D05, 0xD663D260, ++0xE0018122, 0x000B2602, 0xD25C0009, 0x600D8523, ++0x89052008, 0x8B0A8801, 0x6060D65D, 0x2600CB01, ++0xD457D65A, 0xE001E101, 0x000B2612, 0x000B8142, ++0xD152E000, 0x8513E501, 0x640D4518, 0x66033453, ++0xE0008D05, 0xD551D253, 0x2260E001, 0x000B2502, ++0x4F220009, 0x8513D149, 0x6453650D, 0x62494419, ++0x227D672E, 0x8801602C, 0x88028909, 0x88038910, ++0x8806891A, 0x88078935, 0xA04C893B, 0xD5460009, ++0x6652D746, 0x2762D446, 0x622C6261, 0x2421A038, ++0x2228625C, 0xD4438B3F, 0x6642D540, 0x2562D440, ++0x24018561, 0x6203A02C, 0x2008605C, 0x88108907, ++0x88208908, 0x88308909, 0xA02C890A, 0xD23A0009, ++0x6222A008, 0xA005D239, 0xD2396222, 0x6222A002, ++0x6262D638, 0xD432D531, 0x66212522, 0xA00F626C, ++0xD6352421, 0x6261D52D, 0x622CD42D, 0xA0072562, ++0xD6322421, 0x8561D529, 0x2562D429, 0x62032401, ++0x662D8515, 0x3617610D, 0x65038F01, 0xB0CB2451, ++0xA0010009, 0xE000E001, 0x000B4F26, 0xD6190009, ++0xD427E101, 0x65412610, 0xD118D717, 0xE20F655D, ++0x2752E001, 0x000B2620, 0x2FE62102, 0xD20F4F22, ++0x640C8523, 0x8B082448, 0xD511D61D, 0x2621E200, ++0x940F8451, 0xA0482049, 0xDE0D8051, 0xC84060E0, ++0xE2018D32, 0x89443427, 0xD216D615, 0x2641420B, ++0x0009A030, 0x0000FF7F, 0x0020321D, 0x002031D4, ++0x002031E0, 0x001E1100, 0x001E100C, 0x00203200, ++0x001E1000, 0x001E1001, 0x00203208, 0x002031E8, ++0x002031EC, 0x002031F0, 0x0020320C, 0x00203210, ++0x00203214, 0x00203218, 0x0020351C, 0x00203526, ++0x002031FA, 0x00202362, 0x89123427, 0xD294D693, ++0x2641420B, 0xCB8084E1, 0x80E1B0F5, 0xD69160E0, ++0x2E00CB04, 0xC93F6060, 0xD68F2600, 0xA001E001, ++0xE0002602, 0x000B4F26, 0xD68C6EF6, 0xC8806060, ++0xD2868919, 0x88016021, 0xD2898B15, 0x8524E501, ++0x89103056, 0xE203D187, 0x2120D487, 0xE00B6541, ++0x0656655D, 0xE40FD585, 0x2140E702, 0xD77E2571, ++0x000BE001, 0x000B2702, 0x2FE6E000, 0xDE804F22, ++0xC88084E1, 0xD57A892C, 0x20088554, 0x61038F28, ++0x8553D77C, 0x64036672, 0x8566650C, 0x3520620C, ++0xD6798B1E, 0x651CD774, 0x2651644C, 0x60E02741, ++0x8904C840, 0x420BD275, 0xA0030009, 0xD2680009, ++0x0009420B, 0x0009B09F, 0xE201D167, 0x60E02122, ++0xCB04D464, 0x60402E00, 0x2400C93F, 0x6023A001, ++0x4F26E000, 0x6EF6000B, 0x2FB62FA6, 0x2FD62FC6, ++0xDA622FE6, 0x66A1E240, 0x3622DC5E, 0x62638900, ++0x6ED36D2C, 0x4E2136D8, 0x4E212A61, 0xDB61D460, ++0xE700A00F, 0x770162B2, 0x71026123, 0x66212B12, ++0x71026213, 0x61212B12, 0x651D666D, 0x356C4528, ++0x627C2452, 0x8BED32E3, 0xC90360D3, 0x8B108803, ++0x617367B2, 0x2B127102, 0x71026E13, 0x2B126571, ++0x655D6DE1, 0x422862DD, 0x325CE107, 0xA00C2C10, ++0x88022422, 0xA0038B01, 0x8801E203, 0xE2018B05, ++0x66B22C20, 0x655D6561, 0xE60F2452, 0x67A12C60, ++0x8B052778, 0xDD38DC44, 0xEB01EA00, 0x2DB22CA2, ++0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, 0x2FE62FD6, ++0xE240DD36, 0x362266D1, 0x62638900, 0x3678672C, ++0x7703DE38, 0x47212D61, 0x64E2D635, 0xA00E4721, ++0x6562E100, 0x62537101, 0x74012450, 0x24204219, ++0x45297401, 0x74012450, 0x24504519, 0x621C7401, ++0x8BEE3273, 0x66E24200, 0x420061D1, 0x2118362C, ++0x2E628F06, 0xDD1CD728, 0xE501E400, 0x2D522742, ++0x000B6EF6, 0x2FD66DF6, 0x4F222FE6, 0xED0AEE01, ++0x64E3BC97, 0xBC9C64E3, 0x62EC7E01, 0x8BF732D7, ++0xBC9FEE01, 0x64E364E3, 0x7E01BCA4, 0x32D762EC, ++0x4F268BF7, 0x000B6EF6, 0xD1186DF6, 0xD418920D, ++0x72122122, 0x2422D617, 0xD7177204, 0x72202622, ++0x2722D116, 0x000B7230, 0x137A2122, 0x002031FA, ++0x0020246E, 0x001E1015, 0x00203200, 0x001E1001, ++0x002031D4, 0x001E1100, 0x002031FE, 0x002031EC, ++0x001E1000, 0x002031F0, 0x002031FC, 0x00202362, ++0x001E100C, 0x002031E8, 0x00203204, 0x00203208, ++0x0020320C, 0x00203210, 0x00203214, 0x00203218, ++0x4F222FE6, 0xD6507FFC, 0x88016060, 0xE2018951, ++0x2620BFBB, 0xD54ED14D, 0xDE4E6010, 0x64E36552, ++0x7402C840, 0x8D22D14C, 0xD24C7502, 0xE601D74C, ++0xE7042722, 0x76016255, 0x626C2421, 0x8FF93273, ++0xD4437402, 0x6242E601, 0x640D8528, 0x67494419, ++0x275D657E, 0x81E4607C, 0xE417D542, 0x67557601, ++0x3243626C, 0x8FF92171, 0xA0207102, 0xD23E0009, ++0xE601D73B, 0xE7042722, 0x76016255, 0x626C2421, ++0x8FF93273, 0xD4327402, 0x6242E601, 0x640D8528, ++0x67494419, 0x275D657E, 0x81E4607C, 0xE417D533, ++0x67557601, 0x3243626C, 0x8FF92171, 0x924A7102, ++0xD2262E21, 0x5E23D72E, 0x64F22FE2, 0x604365F2, ++0x2700C980, 0xC9606043, 0x80716103, 0xC9036043, ++0x80724519, 0x65F2605C, 0x817266F2, 0x46194629, ++0x606C4529, 0x4018645C, 0x8173304C, 0x21185E23, ++0x64F22FE2, 0x6E4C62F2, 0x602C4219, 0x66F262F2, ++0x46294018, 0x461930EC, 0x42298174, 0x652C606C, ++0x305C4018, 0x81758F07, 0x0009BC9D, 0x2228620C, ++0xA00A8908, 0x60130009, 0x8B038840, 0x0009B009, ++0x0009A003, 0xE202D60F, 0x7F042622, 0x000B4F26, ++0x000B6EF6, 0x060A0009, 0x0020321C, 0x001E1000, ++0x00203208, 0x0020351C, 0x00203528, 0x002034C0, ++0x002031F0, 0x002034F0, 0x002034EE, 0x002034C2, ++0x002031D4, 0x00203200, 0x4F222FE6, 0xDE937FFC, ++0x200884E9, 0x2F008D06, 0xD692D491, 0x0009460B, ++0x64F0B194, 0x6620D290, 0x89022668, 0xC9BF60E0, ++0x7F042E00, 0x000B4F26, 0x000B6EF6, 0x2FE60009, ++0xDE8A4F22, 0x60E0D68A, 0xCBC0D48A, 0x62602E00, ++0xC803602C, 0x40218904, 0x70014021, 0x6603A002, ++0x66034009, 0xD684616D, 0xE500A004, 0x75016262, ++0x74042422, 0x3213625D, 0xD2808BF8, 0x0009420B, ++0xC9BF84E2, 0x4F2680E2, 0x6EF6000B, 0x2FE62FD6, ++0x7FFC4F22, 0x6260D67A, 0x89442228, 0xD56FE100, ++0x60502610, 0xCB40D477, 0x2500440B, 0x8D052008, ++0x62E06E03, 0x7104612C, 0x2F11A006, 0xD472D66A, ++0xDD726760, 0x657C4D0B, 0xE23C6D1D, 0x8B033D27, ++0xD264D46F, 0x0009420B, 0x4D214D21, 0xA005D76D, ++0x66E6E400, 0x357C4508, 0x74012562, 0x35D3654D, ++0xD7698BF7, 0x6172E003, 0x81114018, 0x6E7260F1, ++0x81E2700C, 0xD4656172, 0xDD658113, 0x4D0BDE65, ++0xE2016572, 0xD4642E22, 0x420BD252, 0xD6530009, ++0xC93F6060, 0x7F042600, 0x6EF64F26, 0x6DF6000B, ++0x2FC62FB6, 0x2FE62FD6, 0xD25C4F22, 0x6B436E73, ++0x420B6C53, 0x20086D63, 0x61038F08, 0xD245D458, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, 0x21B060C3, ++0x60D38011, 0xE5008111, 0x64BCA007, 0x6053655D, ++0x665300EC, 0x7501361C, 0x625D8064, 0x8BF53243, ++0x6060D636, 0x2600C9BF, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x7FC44F22, 0x720262F3, 0x22512F41, ++0x45297202, 0x60632251, 0xE5C4E682, 0x67F38121, ++0x655C666C, 0xE408BFBC, 0x4F267F3C, 0x0009000B, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xE1007FC4, 0x6513ECFF, 0x6B136CCD, 0xDE36D735, ++0xEDFF64F3, 0xD835EA04, 0x6053655C, 0x027D4000, ++0x32C0622D, 0x66038D0D, 0x09ED6063, 0x2491027D, ++0x24217402, 0x698202ED, 0x3928622D, 0x74022892, ++0x75017104, 0x6063625C, 0x07D532A2, 0x0EB58FE4, ++0x2448641C, 0xE6808905, 0x67F3E5C5, 0xBF7F666C, ++0x7F3C655C, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0xD11E68F6, 0x6012D21E, 0xCB20E405, ++0x2102E500, 0x000B2242, 0x00002252, 0x001E1017, ++0x00203358, 0x0020145E, 0x002031A2, 0x001E1015, ++0x001E10BF, 0x00117800, 0x001E10FC, 0x00200308, ++0x002031A8, 0x002025C6, 0x0020335C, 0x002014AA, ++0x00203378, 0x0011788C, 0x002031A4, 0x00202D88, ++0x002011E4, 0x001E2130, 0x00203380, 0x00202588, ++0x00203384, 0x002031BC, 0x002031C4, 0x002034BC, ++0x001C3500, 0x001D4004, 0xD565D164, 0xE400D765, ++0x2142E20F, 0x17411154, 0xD5632722, 0x9669D763, ++0x15412572, 0x96661562, 0xE6011565, 0xD5601165, ++0x666CE6F8, 0x25422542, 0x25422542, 0x25422542, ++0x25622542, 0x7601E727, 0x67632572, 0x25627797, ++0xE7042572, 0x2572E248, 0xE2192522, 0xE2702522, ++0x25422542, 0x25422542, 0x25222542, 0x2522E20C, ++0x25422542, 0x25422542, 0x25422542, 0x25422542, ++0x000B154A, 0xE2081145, 0x0009422B, 0x2FE62FD6, ++0x7FFC4F22, 0xC8206043, 0x6E438D02, 0x0009BE6D, ++0xC81060E3, 0xBE6A8901, 0x60E30009, 0x8901C840, ++0x0009BE8C, 0xC80160E3, 0xDD3E8938, 0xC80260D0, ++0x2F008D03, 0x460BD63C, 0x60F00009, 0x8902C804, ++0x460BD63A, 0x62F00009, 0xC8806023, 0x60D08902, ++0x2D00C97F, 0xC8016023, 0xD6358906, 0x0009460B, ++0x0009A007, 0x51630601, 0x8902C808, 0x460BD631, ++0x60F00009, 0x8902C810, 0x420BD22F, 0xD52F0009, ++0x88026052, 0xD22E8B03, 0xA005E604, 0x88012260, ++0xD22B8B02, 0x2260E601, 0x2522E200, 0xC88060E3, ++0xD628892E, 0x60E36E60, 0x8902C880, 0x420BD226, ++0x60E30009, 0x8902C840, 0x420BD224, 0x60E30009, ++0x8902C802, 0x420BD222, 0x60E30009, 0x890EC804, ++0x410BD120, 0xBF0E0009, 0xBF4D0009, 0xD51E0009, ++0x6050D41E, 0xC908D71E, 0xBF842500, 0x60E32472, ++0x8905C808, 0x7F04D21B, 0x6EF64F26, 0x6DF6422B, ++0x4F267F04, 0x000B6EF6, 0x00006DF6, 0x001C581C, ++0xA000A000, 0x001D0100, 0x001D4000, 0x00040021, ++0x001C589C, 0x001E1021, 0x00201640, 0x00201662, ++0x00201CA0, 0x0020167A, 0x00201688, 0x00203200, ++0x001E100B, 0x001E1028, 0x002016DE, 0x002016EA, ++0x00201690, 0x002016AE, 0x001E1000, 0x0010F100, ++0x12345678, 0x002016C6, 0x644CD6A7, 0x000B346C, ++0xD6A62450, 0x346C644C, 0x2450000B, 0x644CD6A4, ++0x000B346C, 0x625C2450, 0x4208616D, 0x42084119, ++0x42006019, 0x670E614C, 0xD49E321C, 0x4200207D, ++0x324CC90F, 0x2200000B, 0x4208625C, 0x42004208, ++0x324C644C, 0x4200D498, 0x000B324C, 0x2FE62260, ++0x614C4F12, 0x4100D493, 0x6710314C, 0xE29F666D, ++0x27294619, 0x6E536269, 0x672E6573, 0x4221227D, ++0x42214221, 0x7601662C, 0xE4014608, 0x34E84608, ++0x644C4600, 0x071A0467, 0x2150257B, 0x000B4F16, ++0x4F226EF6, 0xD2857FE8, 0x88016021, 0xD2848B7B, ++0x26686621, 0xD2838B77, 0x26686621, 0xE50F8B73, ++0xE401BFA2, 0xBFA4E501, 0xE586E400, 0xE400655C, ++0x2F50BFA4, 0xBFA1E401, 0xE602E506, 0x60634618, ++0x81F2E401, 0x6543BF9F, 0xE40185F2, 0xBFAB6543, ++0x85F26603, 0x6543E401, 0x6603BFB1, 0xE40265F0, ++0x6053756C, 0x80F8BF80, 0xBF82E402, 0x84F8E512, ++0x7090E402, 0x6503BF82, 0x4618E602, 0x81F66063, ++0xBF80E402, 0x85F6E500, 0x6603E402, 0xE500BF8C, ++0xE40285F6, 0xBF926603, 0xE5FEE500, 0xE010655C, ++0xBF61E403, 0xE5130F54, 0xE40EBF63, 0x05FCE010, ++0xBF63E40E, 0xE5007585, 0xBF64E403, 0xE500E640, ++0xBF71E403, 0xE500E640, 0xBF78E403, 0xE5FFE640, ++0xE014655C, 0xBF47E404, 0xE40F0F54, 0xE504BF49, ++0x05FCE014, 0xBF49E40F, 0xE5017584, 0xBF4AE640, ++0xE501E404, 0xBF57E640, 0xE501E404, 0xE404E640, ++0xAF5C7F18, 0x7F184F26, 0x000B4F26, 0x4F220009, ++0xD2427FF0, 0x88016021, 0xD2418B71, 0x26686621, ++0xD2408B6D, 0x26686621, 0xE50F8B69, 0xE401BF1C, ++0xBF1EE501, 0xE586E400, 0xE400655C, 0x2F50BF1E, ++0xBF1BE401, 0xE401E506, 0xBF1C6543, 0xE401E640, ++0xBF296543, 0xE401E640, 0xBF306543, 0x65F0E640, ++0x756CE402, 0xBEFF6053, 0xE40280F4, 0xE512BF01, ++0xE40284F4, 0xBF017090, 0xE6406503, 0xBF02E402, ++0xE640E500, 0xBF0FE402, 0xE640E500, 0xBF16E402, ++0xE5FEE500, 0x6053655C, 0xBEE5E403, 0xE51380F8, ++0xE40EBEE7, 0xE40E84F8, 0xBEE77085, 0xE5006503, ++0xBEE8E640, 0xE500E403, 0xBEF5E640, 0xE500E403, ++0xBEFCE640, 0xE5FFE403, 0x6053655C, 0xBECBE404, ++0xE40F80FC, 0xE504BECD, 0xE40F84FC, 0xBECD7083, ++0xE5016503, 0xBECEE640, 0xE501E404, 0xBEDBE640, ++0xE501E404, 0xE404E640, 0xAEE07F10, 0x7F104F26, ++0x000B4F26, 0x00000009, 0x001E102F, 0x001E1080, ++0x001E1090, 0x001E103F, 0x001E103E, 0x002031FA, ++0x002031FC, 0x002031FE, 0xD21DD11C, 0x66206010, ++0x676C7001, 0x3700C90F, 0xE5008D13, 0x67106210, ++0x7701622C, 0x64232170, 0xD6166010, 0x44084408, ++0x3428C90F, 0x62602100, 0x7201D513, 0x44082620, ++0x000B354C, 0xD10F6053, 0x25586510, 0xE6008D13, ++0xD60DD40B, 0x655C6540, 0x47086753, 0x37584708, ++0x47086540, 0x24507501, 0x367C6040, 0x2400C90F, ++0x72FF6210, 0x000B2120, 0x00006063, 0x002031A1, ++0x002031A0, 0x002031A2, 0x00202DC8, 0x7FFC4F22, ++0xE680D19D, 0x666C6212, 0xD29C2F22, 0x67F36563, ++0x420B7542, 0x7F04E404, 0x000B4F26, 0xE6800009, ++0xD296666C, 0xE7006563, 0x422B7540, 0xE6806473, ++0xD292666C, 0xE7006563, 0x422B7543, 0x2F866473, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x7FF44F22, ++0xDD8CD28B, 0x72011F21, 0xDB8B1F22, 0x6AF2E840, ++0x5211D18A, 0x36206612, 0xA0A78B01, 0x60610009, ++0x8801C903, 0xA0A18B01, 0xD9840009, 0x420BD284, ++0x55036493, 0x845C6A03, 0x30E0EE84, 0xD1818B79, ++0x606C6610, 0x8B3D8801, 0x6210D17F, 0x892F2228, ++0xD57EE701, 0x64522B72, 0x1442E003, 0xD57C6252, ++0xE6004018, 0x21608121, 0xD17A6453, 0x6E527404, ++0x60126742, 0xCB20DC78, 0x76012102, 0x3283626D, ++0x25E28BFB, 0x2472DE71, 0x62E267C2, 0x1274D173, ++0x604164E2, 0x2401CB01, 0xEE0066E2, 0xDC702C62, ++0xEC012C62, 0x2DC2410B, 0x4C18EC01, 0x2BE22DC2, ++0xD764DE6C, 0xD16C60E2, 0xCB01E202, 0x27202E02, ++0x2122A02F, 0x8B2C2008, 0xE701DE68, 0xD466EC00, ++0x2170D264, 0xEE012EC2, 0x612224E2, 0x2169E6FE, ++0xE01E2212, 0x54F10C5C, 0x24C0E01F, 0x56F2025C, ++0x26207510, 0xD75EE600, 0xEE06D45E, 0x76018456, ++0x6C542700, 0x31E3616C, 0x740124C0, 0x77018FF6, ++0xE494D259, 0x72012240, 0x2250E500, 0xE605720F, ++0xD2562260, 0x65A36493, 0xEE01420B, 0xAF6F4E18, ++0x2FA22DE2, 0xD45265F2, 0x66428553, 0x3262620D, ++0xD4508907, 0x410BD150, 0xD7500009, 0xAF57E601, ++0xD43A2762, 0xDD37D149, 0x65F2410B, 0xD44CEE01, ++0x4E18D64C, 0x2DE2460B, 0x0009AF4A, 0x7F0C2FA2, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x4F2268F6, 0x85467FF4, 0x2F01E681, 0x666C8547, ++0x854881F1, 0x81F2D225, 0x67F38542, 0x854381F3, ++0x81F4E40C, 0x65636053, 0x420B81F5, 0x7F0C7540, ++0x000B4F26, 0x2F860009, 0x2FA62F96, 0x2FC62FB6, ++0x2FE62FD6, 0x7FEC4F22, 0xE800D11A, 0xD4322F12, ++0x1F416183, 0x6A13DB20, 0x4A08D630, 0xDE20E001, ++0x4A00460B, 0x1F023AEC, 0x52B166B2, 0x8B013620, ++0x0009A19B, 0xC9036061, 0x8B018801, 0x0009A195, ++0xDE275263, 0x8B4F32E0, 0x420BD20D, 0xDE2564B3, ++0xD70DD50E, 0xED01DC0B, 0x2E02E100, 0x27D02502, ++0xAFE12C10, 0x00002E16, 0x001C3D9C, 0x00201F40, ++0x0011779A, 0x001C3D30, 0x001D0104, 0x00202DC0, ++0x00201162, 0x002031B1, 0x002031B0, 0x002031AC, ++0x001C3B9C, 0x001C3500, 0x00202D98, 0x00201276, ++0x001C3D00, 0x001C36F8, 0x00117708, 0x002031B4, ++0x0011778C, 0x00117792, 0x00117788, 0x00201180, ++0x00203188, 0x00202D88, 0x002011E4, 0x001E2130, ++0x0020349C, 0x0020145E, 0x002034A8, 0x00202C80, ++0x00117780, 0x0011770C, 0xC8018561, 0x5C63897A, ++0x660385C2, 0x6403C903, 0x650D85C3, 0x40216053, ++0xC93F4021, 0x6E034500, 0x252D322A, 0xE2106053, ++0x3E23C901, 0x6D038D23, 0x4408D79D, 0x44086570, ++0x440062E3, 0x25584200, 0x342C8F0F, 0x6043D299, ++0x697D072D, 0x60994919, 0x201D610E, 0x60D381F6, ++0x8F0C8801, 0xA00A697C, 0xD29369E3, 0x052D6043, ++0x4219625D, 0x670E6029, 0x81F6207D, 0xD18F695C, ++0x22286210, 0xE9FF8901, 0xEEFF699C, 0x6EEC659D, ++0x8B0F35E0, 0x4C0BDC8A, 0x540364B3, 0xBF20E502, ++0xD4886E03, 0x410BD188, 0xD78865E3, 0xD488ED01, ++0x27D2A01E, 0x26E9EEFC, 0x81C26063, 0x97C585C3, ++0x62032079, 0x450885F6, 0x6063260B, 0x81C2252B, ++0x81C36053, 0xE10885C4, 0x201B4118, 0x62B281C4, ++0x20E98521, 0x64B28121, 0xCB016041, 0xD4792401, ++0x450BD579, 0x60B20009, 0x57F266F2, 0x2A02CB01, ++0x2672AF22, 0xD26E8561, 0x8F02C802, 0xA09F64B3, ++0x420B0009, 0xDC710009, 0x5E036503, 0x07CEE04C, ++0x7701DD6F, 0x6CD20C76, 0x7C01D664, 0x6D602DC2, ++0x89062DD8, 0xD264D463, 0xED01420B, 0xA07ED763, ++0x625127D2, 0x4118E10F, 0x2219E402, 0x32404418, ++0x85518B11, 0x20D9EDFC, 0x60518151, 0xCB017DE3, ++0x85E12501, 0x20D9D65F, 0x460B81E1, 0x6CF264B3, ++0xA06457F2, 0x6D512C72, 0x4D196DDD, 0x66DE6DD9, ++0x7D012D6D, 0x610360DC, 0x88014118, 0x25118F45, ++0x6462D653, 0x26427401, 0x660D85E3, 0x40216063, ++0xC93F4021, 0x6D034600, 0x262D322A, 0xC8016063, ++0xDC4ED14D, 0x964A8901, 0xE6002D6B, 0x0F64E010, ++0xE01064DD, 0x607C07FC, 0x021D4000, 0x3240622D, ++0x66038D12, 0x021D6063, 0x3270E7FF, 0xA00B8B01, ++0xE01001D5, 0xE60402FC, 0x0F247201, 0x3262622C, ++0x06FC8BE7, 0x4600666C, 0x01CD6063, 0x0C157101, ++0x6711D13B, 0x3C406C7D, 0x62118907, 0x88FF602D, ++0x21D18903, 0xE201DD37, 0x85512D20, 0x20D9EDFC, ++0x60518151, 0xCB01D22F, 0x420B64B3, 0xE0102501, ++0xD43102FC, 0xE001612C, 0x67F2440B, 0x85EF2702, ++0x54F1D22E, 0x650D420B, 0x0009AE7E, 0x80007E03, ++0x0009420B, 0x6E035403, 0xED088544, 0x20D94D18, ++0x8B0330D0, 0xE501BE3D, 0x0009A007, 0xDD248541, ++0x22D8620D, 0xBE348901, 0xD412E500, 0x420BD212, ++0xD71265E3, 0xAE5FED01, 0x780127D2, 0xEE04618D, ++0x8D0231E7, 0xAE4E7B08, 0x7F140009, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x000068F6, ++0x002034B8, 0x0020339C, 0x0020341C, 0x0020319C, ++0x00201162, 0x00202D90, 0x00201180, 0x001E212C, ++0x002034A0, 0x002034A4, 0x0020145E, 0x00202D2C, ++0x002034BC, 0x002011E4, 0x002031BC, 0x002031C4, ++0x002031B8, 0x002031BA, 0x00202C80, 0x002014AA, ++0x00008000, 0x4F222FE6, 0x6E22D212, 0xC84060E3, ++0x22E28D02, 0x0009BCFA, 0x4218E240, 0x89012E28, ++0x0009BD05, 0xC81060E3, 0xD40B8905, 0x420BD20B, ++0xBD040009, 0x60E30009, 0x8901C805, 0x0009BDEB, ++0xC80260E3, 0x4F268902, 0x6EF6AD01, 0x000B4F26, ++0x00006EF6, 0x001C3510, 0x002034B0, 0x0020145E, ++0x080A0C0E, 0x00020406, 0x1A1C1E20, 0x12141618, ++0x2E303234, 0x26282A2C, 0x3A3C3E40, 0x6C625648, ++0x41112F26, 0xE2208F18, 0x890B3123, 0x321CD204, ++0xD1026220, 0x412B312C, 0x00090009, 0x00202CAA, ++0x00202C60, 0x000BE000, 0x400062F6, 0x40004000, ++0x40004000, 0x40004000, 0x62F6000B, 0x40004000, ++0x40004000, 0x40004000, 0x40184000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40284000, ++0x62F6000B, 0x40004000, 0x40184000, 0x000B4028, ++0xC90F62F6, 0x40054005, 0x40054005, 0x62F6000B, ++0x4005C907, 0x40054005, 0x62F6000B, 0x4005C903, ++0x000B4005, 0xC90162F6, 0x000B4005, 0x000062F6, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x544F0D0A, ++0x46205355, 0x00003A57, 0x206C754A, 0x32203532, ++0x20373030, 0x313A3132, 0x37323A32, 0x00000000, ++0x00000D0A, 0x00000043, 0x42707372, 0x3D206675, ++0x554E203D, 0x202C4C4C, 0x6E49677A, 0x4E497274, ++0x6D754E51, 0x0000003D, 0x61766E49, 0x2064696C, ++0x72657375, 0x20726F20, 0x2079656B, 0x00214449, ++0x52504545, 0x57204D4F, 0x65746972, 0x6461202C, ++0x003D7264, 0x6C617620, 0x0000003D, 0x00000A0D, ++0x6E6B6E55, 0x206E776F, 0x6D6D6F63, 0x3D646E61, ++0x00000000, 0x000A0D52, 0x203A3051, 0x00000020, ++0x203A3151, 0x00000020, 0x203A3251, 0x00000020, ++0x203A3351, 0x00000020, 0x203A3451, 0x00000020, ++0x61437748, 0x7262696C, 0x6F697461, 0x6620206E, ++0x0A6C6961, 0x0000000D, 0x73696F4E, 0x61432065, ++0x7262696C, 0x6F697461, 0x6166206E, 0x21216C69, ++0x00000D0A, 0x00000072, 0x00205220, 0x00000D0A, ++0x62735576, 0x7473725F, 0x00000A0D, 0x62735576, ++0x7375735F, 0x646E6570, 0x00000A0D, 0x62735576, ++0x7365725F, 0x000A0D6D, 0x00000042, 0x72746E49, ++0x6D652051, 0x2C797470, 0x49677A20, 0x4972746E, ++0x754E514E, 0x00003D6D, 0x654C7245, 0x0000006E, ++0x00000049, 0x20746F4E, 0x756F6E65, 0x49206867, ++0x4220514E, 0x0A0D6675, 0x00000000, 0x000000FF, ++0x00020001, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x010E010D, ++0x00020003, 0x01090108, 0x0002010A, 0x02000003, ++0x02020201, 0x02040203, 0x02060205, 0x02020200, ++0x02040203, 0x020C0207, 0x020E020D, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x010E010D, ++0x00FF010F, 0x01090108, 0x010B010A, 0x020000FF, ++0x02020201, 0x02040203, 0x02060205, 0x02020200, ++0x02040203, 0x020C020B, 0x020E020D, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00205220, ++0x00000046, 0x00000059, 0x73204142, 0x003D7165, ++0x49544120, 0x0000204D, 0x00000000, 0x00000000, ++0x002E0209, 0x80000101, 0x000409FA, 0x00FF0400, ++0x05070000, 0x02000201, 0x82050700, 0x00020002, ++0x03830507, 0x07010040, 0x40020405, 0x02090000, ++0x0101002E, 0x09FA8000, 0x04000004, 0x000000FF, ++0x02010507, 0x07000040, 0x40028205, 0x05070000, ++0x00400383, 0x04050701, 0x00004002, 0x00000000, ++0x00000000, 0x07090000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, }; ++ ++const u32_t zcFwImageSize=13656; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu.c +@@ -0,0 +1,1017 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE947FFC, 0xE114D594, ++0x1E13D494, 0x67521E4C, 0xD494D693, 0x37402769, ++0x62528F06, 0x7201D692, 0x60602522, 0x2600C93F, ++0xD7906152, 0x2512611D, 0x264B6652, 0x2562470B, ++0x0009B017, 0xE60095AC, 0xC84060E2, 0x2F028F03, ++0x8FF93652, 0xD4887601, 0x4E0BDE88, 0xD4880009, ++0x00094E0B, 0x4E0BD487, 0x7F040009, 0xA0524F26, ++0x4F226EF6, 0x410BD184, 0xD4840009, 0x0009440B, ++0x450BD583, 0xD7830009, 0xD283E1FF, 0x2712611D, ++0xD4825029, 0xE1FFCB01, 0x1209E501, 0x12112212, ++0xE7202452, 0x4718D57E, 0x2572D27E, 0xD17EE700, ++0xD67FD47E, 0xE2012270, 0x24702172, 0xD67D2620, ++0x2641E4FF, 0xD57CE600, 0x666DE104, 0x76016063, ++0x4000626D, 0x8FF83212, 0xD5780545, 0x2520E201, ++0xD278D777, 0xE480E100, 0x22122710, 0x6613D576, ++0x666D644C, 0x76046763, 0x375C626D, 0x8FF83243, ++0xD5722712, 0xD273D772, 0xE400E101, 0x27102511, ++0x000B4F26, 0x7FCC2242, 0xD170D56F, 0xD271DB70, ++0x1F51D471, 0xD6717508, 0x1F12D771, 0x1F55710C, ++0x1FB975FC, 0x72041F2A, 0x1F13EB10, 0x1F561F44, ++0x1F781F67, 0xD86B1F2B, 0xDD6CD96B, 0xDC6CEA00, ++0xD26DDE6C, 0x89003A22, 0xD15D7A01, 0x88016010, ++0x56F88B03, 0x4218E201, 0xD1682622, 0x0009410B, ++0x440BD467, 0xD5670009, 0x0009450B, 0x6010D150, ++0x8B108801, 0xE650D14F, 0x46186212, 0x8B083266, ++0x56F9D14B, 0x2120E200, 0xCB016062, 0x2602A003, ++0x72012710, 0x60822122, 0x89098801, 0xE2C8D15A, ++0x622C6612, 0x89033626, 0x6010D158, 0x8BC88801, ++0x51F66792, 0x217252F5, 0xD6555191, 0x55FA2212, ++0x52FB6462, 0x55612542, 0x2252E400, 0x61436643, ++0x05DE6013, 0x36CC4608, 0x07DE2652, 0xC9036071, ++0x8B028801, 0x720162E2, 0x74012E22, 0x36B3664C, ++0x71048FEE, 0x66C2D147, 0x45286512, 0x265B4518, ++0x60822C62, 0x89018801, 0x0009A168, 0x6272D742, ++0x8B132228, 0xD42BD741, 0x6772D541, 0x51536242, ++0x312C327C, 0x24222228, 0x15138D05, 0x6262D63D, ++0xB1627201, 0xD6232622, 0x2622E200, 0x52916692, ++0x8B013620, 0x0009A144, 0x6061A06E, 0x001C001C, ++0x001D4020, 0x0000B38E, 0xFFFF0000, 0x12340000, ++0x001E1015, 0x00201274, 0x002039F4, 0x002018A2, ++0x00203A00, 0x00203A18, 0x00201860, 0x0020196C, ++0x00201288, 0x001C3510, 0x001C3624, 0x001E212C, ++0x002038F4, 0x0020348C, 0x002038FC, 0x00203908, ++0x00203914, 0x00203970, 0x00203974, 0x0020391C, ++0x0020391D, 0x00203920, 0x00117700, 0x0020398C, ++0x0020398A, 0x002034F0, 0x00117710, 0x001C3D30, ++0x001C36F8, 0x00117734, 0x001C3684, 0x001C3D00, ++0x001C1000, 0x001C1028, 0x00203504, 0x00203924, ++0x00117600, 0x00117740, 0x7FFFFFFF, 0x00201730, ++0x0020332A, 0x00202334, 0x00203DA4, 0x00203972, ++0x002034FC, 0x00203964, 0x001C3D2C, 0x001C36B0, ++0x00203494, 0x0011775C, 0x8801C90F, 0xA0CF8901, ++0xD1960009, 0x36206212, 0xD4958904, 0x2421E200, ++0x2162A0CC, 0x6211D193, 0x89012228, 0x0009A0C3, ++0xE202D78F, 0x75016571, 0x3123615D, 0x27518D02, ++0x0009A0BC, 0xD28C57F2, 0x62226072, 0x40094019, ++0xC90F4009, 0x8F19880A, 0x52F31F2C, 0x40196022, ++0x40094009, 0x8808C90F, 0xA0A78901, 0x60630009, ++0xCB0154F7, 0xD27E55F2, 0xE7012402, 0xD47FE100, ++0x22112572, 0x72016242, 0x2422A098, 0x8B3F8805, ++0x602252F3, 0x40094019, 0xC90F4009, 0x8B168802, ++0xE4FFD577, 0x644D6752, 0x8B102748, 0x6272D775, ++0x8B0C3260, 0x51F255F7, 0xD26DE701, 0x21722562, ++0xD571E100, 0x64522211, 0xA0777401, 0x52F32542, ++0x40196022, 0x40094009, 0x8805C90F, 0x31B38B6E, ++0xD26A8B6C, 0x672254F4, 0x7701D569, 0x61422272, ++0x1F1CE640, 0x46182159, 0x8B033160, 0x6262D665, ++0x26227201, 0xE200D65A, 0x2621B067, 0x0009A056, ++0x3123E220, 0x88038B52, 0x52F38B1E, 0x40196022, ++0x40094009, 0x8803C90F, 0xD25B8B16, 0x672254F4, ++0x7701D557, 0x61422272, 0x1F1CE640, 0x46182159, ++0x8B033160, 0x6262D655, 0x26227201, 0xE200D648, ++0x2621B043, 0x0009A010, 0xD452D551, 0xD2446752, ++0xE1007701, 0x25723A46, 0x22118F06, 0xEA00D64E, ++0x72016262, 0x2622B031, 0x2FB2D54C, 0x95736652, ++0xD44A5BF1, 0x36205241, 0x60618910, 0x8B01C803, ++0x2B22E201, 0x8FF54510, 0x57F15664, 0x6272E1F0, ++0x41284118, 0x2722221B, 0x6BF2A008, 0x6BF2A006, ++0xE200D62F, 0xD12F2621, 0x2121E200, 0xD13CE201, ++0x66122822, 0x8B012668, 0x0009AE2B, 0x450BD539, ++0xD1390009, 0xAE24E600, 0x2F862160, 0x2FA62F96, ++0x2FC62FB6, 0x2FE62FD6, 0x7FF44F22, 0xDE34D133, ++0x54116212, 0x1F4167E2, 0x2F22D432, 0xD5321F72, ++0xD2326743, 0x58417794, 0x69425A42, 0x5B166C72, ++0x60526D22, 0xCB20E600, 0xE5402502, 0x626D7601, ++0x8BFB3253, 0x55F162F2, 0x11512122, 0xD62855F2, ++0x14812E52, 0x249214A2, 0x27C2D426, 0x26D211B6, ++0xDA256742, 0xE801D925, 0x490B2A72, 0xE2011A8C, ++0x1A2C4218, 0x4F267F0C, 0x6DF66EF6, 0x6BF66CF6, ++0x69F66AF6, 0x68F6000B, 0x000007D1, 0x00203984, ++0x00203988, 0x0020398E, 0x001C3DC0, 0x0011772C, ++0x001C3B88, 0x0020396C, 0x0011773C, 0x00117744, ++0x0000F000, 0x00117764, 0x00117748, 0x00117768, ++0x0011776C, 0x01FFFFFF, 0x0011774C, 0x002034FC, ++0x00203DA4, 0x002024F8, 0x00203972, 0x001C3B9C, ++0x001C3D98, 0x001C3700, 0x001C3500, 0x001C5960, ++0x001C8960, 0x00203504, 0x001C3D00, 0x0020160C, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xDE957FAC, 0x61E0E014, 0x0F14D494, 0x710161E3, ++0xE0186210, 0xD2920F24, 0x0009420B, 0x450BD591, ++0x20080009, 0x8F126D03, 0xD28F1F07, 0x6720D48F, ++0x657CDD8F, 0x470BD78F, 0xD18F0009, 0x619C6910, ++0x46086613, 0x36184608, 0x3D6C4608, 0xE0181FD7, ++0xE58004FC, 0x604C66E2, 0x3050655C, 0x2D628F15, ++0x01FCE014, 0xDE85E500, 0x641CA008, 0x6753655D, ++0x607037EC, 0x39DC6953, 0x80947501, 0x3243625D, ++0xD67F8BF4, 0xA34EE200, 0x20082621, 0xE0148B13, ++0xE40001FC, 0xA009DE79, 0x644D671C, 0x35EC6543, ++0x69436652, 0x39DC6262, 0x74041921, 0x3273624D, ++0xA3388BF3, 0x88012D10, 0xE0148B17, 0xE70001FC, ++0x6D1C2D70, 0xDE6D1FD4, 0x32D3627D, 0xA32A8B01, ++0x677D0009, 0x667365E3, 0x61737504, 0x315C36EC, ++0x69126462, 0xAFEF7708, 0x88042492, 0xE0148B18, ++0xE40001FC, 0x671C2D40, 0x624DDE60, 0x8B013273, ++0x0009A311, 0x6943644D, 0x39EC62E3, 0x72046592, ++0x3D2C6D43, 0x615266D2, 0x21697408, 0x2512AFED, ++0x8B188805, 0x01FCE014, 0x2D40E400, 0xDE53671C, ++0x3273624D, 0xA2F68B01, 0x644D0009, 0x62E36943, ++0x659239EC, 0x6D437204, 0x66D23D2C, 0x74086152, ++0xAFED216B, 0x88312512, 0xD44A8B3A, 0x6146D94A, ++0x75046543, 0x67566442, 0x6E531F48, 0x65527E04, ++0x7EE462E2, 0x7E0464E2, 0x6EE21FE9, 0x5EF929E0, ++0x7E04D942, 0x1FEA60E2, 0x2900C901, 0xD9406EE2, ++0x29E04E09, 0x2F562F26, 0x56FAD93E, 0x6513490B, ++0xD13D7F08, 0xE71C6E0D, 0x1DE12D70, 0xDE3B6912, ++0x64E21D92, 0x1D43D13A, 0xD23A6512, 0x67221D54, ++0x1D75D239, 0x1D666622, 0x6262D638, 0x1D27A2AB, ++0x8B398830, 0x6596D92B, 0x67926696, 0x61967904, ++0x74E46493, 0x6E436992, 0x1F9B7E04, 0x1FEC6442, ++0xD9256EE2, 0x5EFC29E0, 0x7E04D924, 0x1FED60E2, ++0x2900C901, 0xD9226EE2, 0x29E04E09, 0x59FC7FFC, ++0xDE272F92, 0x2F164E0B, 0xD41F7F08, 0xE21C610D, ++0x1D112D20, 0xD2206442, 0xD41C1D42, 0x1D536542, ++0x6752D51B, 0xD71B1D74, 0x1D156172, 0x1D666622, ++0x6262D61A, 0x1D27A26F, 0x8B358833, 0x490BD919, ++0xA268EE00, 0x00002DE0, 0x00117800, 0x00203A1C, ++0x002018A2, 0x00202AAC, 0x0020390E, 0x00203A20, ++0x00203534, 0x002018EE, 0x0020390D, 0x00117804, ++0x0020398C, 0x00117810, 0x00203909, 0x0020390A, ++0x0020390B, 0x00200F64, 0x001C5864, 0x001C6864, ++0x001C7864, 0x001C59BC, 0x001C69BC, 0x001C79BC, ++0x00200FBC, 0x00200FB8, 0x89018828, 0x0009A0C0, ++0xE643DEB5, 0x326662E1, 0x1FEE8F02, 0x2E21E240, ++0x622D62E1, 0x8B013267, 0x0009A0AA, 0xE50185E1, ++0x8B013056, 0x0009A0A4, 0x2D10E101, 0x64E1B225, ++0xE64357FE, 0x652D6271, 0x89443567, 0x3563E640, ++0xE6008B05, 0x0F65E040, 0xA00FE11A, 0x615372C0, ++0x41214121, 0x41214121, 0x45214121, 0x45214521, ++0xC9036053, 0xE0406603, 0x71180F65, 0x2209E007, ++0x0F25E03C, 0xE044641D, 0xB2A365F3, 0xE33C0F46, ++0x853233FC, 0x620DDE95, 0x42086031, 0x6023610D, ++0x1323E944, 0x06FE4108, 0xE00F39FC, 0x13144E0B, ++0x67075D91, 0x60D32679, 0x0F6654FE, 0x51928542, ++0x600D4E0B, 0x60D3260B, 0x0F666492, 0x65F3B237, ++0x696156FE, 0xE640659D, 0x89383563, 0xD78359FE, ++0x79066591, 0xC9036053, 0x40004008, 0x61036203, ++0x0F26E050, 0x470BE0FF, 0x6C07600C, 0x6603605D, ++0x46214621, 0x46214621, 0x42006263, 0x4200326C, ++0x40214021, 0x4008C903, 0x6D2D30FC, 0xE8006A03, ++0xB25765F3, 0x6EA264D3, 0x2EC9E050, 0x66942AE2, ++0xD76E01FE, 0x606C470B, 0x2AE22E0B, 0x64D365F3, ++0x7801B1FD, 0xEE06628D, 0x8FE932E3, 0x5EFE7D01, ++0x61E1E400, 0x410085E1, 0x66E3310C, 0x760C711B, ++0xE70465F3, 0x68667401, 0x3A736A4D, 0x8FF92582, ++0x65F37504, 0x641DB1E3, 0x64E1B1A4, 0x0009A17B, ++0xD45B56F7, 0xEC01D25B, 0x26C0420B, 0x0009A173, ++0x06FCE018, 0x8829606C, 0x58F78B08, 0xE400D252, ++0x66222840, 0x646DB171, 0x0009A165, 0x666CE681, ++0x89013060, 0x0009A0AC, 0xD550D14F, 0x62126A56, ++0x212232AC, 0x54116C56, 0x34CC6253, 0x64521141, ++0x72085812, 0xD44A384C, 0x68221182, 0x5A136C42, ++0x3ACC3C8C, 0x11A324C2, 0x6C2272EC, 0x72105814, ++0x118438CC, 0x5A156822, 0x11A53A8C, 0x6A227210, ++0xD6405816, 0x118638AC, 0x52176C62, 0x112732CC, ++0x5A185861, 0x11A83A8C, 0x5C195A62, 0x11C93CAC, ++0x521A5C63, 0x112A32CC, 0x5A1B5864, 0x11AB3A8C, ++0x5C1C5A65, 0x11CC3CAC, 0x521D5C66, 0x112D32CC, ++0x5A1E5867, 0x11AE3A8C, 0x561F5A68, 0x36ACE840, ++0x116FDA2D, 0x6CA2381C, 0x7A946682, 0x286236CC, ++0x5C8162A2, 0x18C13C2C, 0x62A27A44, 0x362C5682, ++0xD6261862, 0x5A856262, 0x3A2C4229, 0x760418A5, ++0x56866262, 0x362C4229, 0x56F71866, 0x2620E238, ++0x16C15C81, 0x16226212, 0xE2005C11, 0x551216C3, ++0x55151654, 0x55131655, 0x55161656, 0x55821657, ++0x65821658, 0x55141659, 0x5584165A, 0x5583165B, ++0x5585165C, 0x5586165D, 0x1821165E, 0x11212122, ++0x11251122, 0x11261123, 0x28221822, 0x18241124, ++0x18251823, 0x1826A0C7, 0x00117804, 0x002033E8, ++0x00203A40, 0x002018A2, 0x00203494, 0x001C36A0, ++0x002034F0, 0x001C3CA0, 0x001C36F4, 0x001C3B88, ++0x666CE682, 0x8B203060, 0xEA2456F7, 0x26A0D194, ++0x16C15C17, 0x16225218, 0x16835819, 0x16A45A1A, ++0x16C55C1B, 0x1626521C, 0xE200581D, 0x551E1687, ++0x551F1658, 0x11271659, 0x11291128, 0x112B112A, ++0x112D112C, 0xA08E112E, 0xE683112F, 0x3060666C, ++0x52F78B0B, 0xEA00D883, 0x658222A0, 0x7804DC82, ++0x62822C52, 0xA07ED681, 0xE6902620, 0x3060666C, ++0xDA7F8B06, 0x00094A0B, 0xE20056F7, 0x2620A073, ++0x666CE691, 0x8B103060, 0x6222D276, 0x2228622C, ++0xD2788904, 0x0009420B, 0x0009A003, 0x420BD276, ++0x56F70009, 0xA05EE200, 0xE6922620, 0x3060666C, ++0xE0188951, 0xE6B00BFC, 0x666C62BC, 0x8B2A3260, ++0x02FCE014, 0x682CEA00, 0x62ADE904, 0x894A3283, ++0x6AADDD64, 0x3CDC6CA3, 0x7D046EC2, 0xDB68D467, ++0x32DC62A3, 0x4B0BDC67, 0x4C0B6D22, 0xD46664E3, ++0x00094B0B, 0x64D34C0B, 0x4B0BD464, 0xE6000009, ++0x666D6BE3, 0x76013B6C, 0x3293626D, 0x8FF72BD0, ++0xAFDA4D19, 0xE6B57A08, 0x3260666C, 0xD45C8B13, ++0x4B0BDB57, 0xD25B0009, 0x6022DB5B, 0xCB20E6FF, ++0x2202666D, 0xDB592B62, 0xE014E200, 0x56F72B20, ++0xA01002FC, 0xD4562620, 0x6542D256, 0x420BD456, ++0xA0080009, 0xDB520009, 0x52B1E600, 0x622CDB53, ++0x52F72B21, 0x7F542260, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x000B69F6, 0x4F2268F6, 0xE240614D, ++0x89143123, 0x3127E21F, 0x8B09D749, 0xD449614D, ++0xE00171E0, 0x5671440B, 0x26596507, 0x1761A007, ++0xE001D444, 0x6672440B, 0x26596507, 0x4F262762, ++0x0009000B, 0x614D4F22, 0x3123E240, 0xE21F8912, ++0xD73B3127, 0x614D8B08, 0x5671D23A, 0x420B71E0, ++0x260BE001, 0x1761A006, 0x6672D236, 0xE001420B, ++0x2762260B, 0x000B4F26, 0xE6400009, 0x46284618, ++0x6252D531, 0x89FC2268, 0x0009000B, 0x4618E680, ++0xD52D4628, 0x22686252, 0x000B89FC, 0xA0010009, ++0x7201E200, 0x8BFC3242, 0x0009000B, 0x4618E680, ++0xD5264628, 0x22686252, 0x000B8BFC, 0x2FE60009, ++0x7FFC4F22, 0xBFF16E53, 0x61E22F42, 0xE280D620, ++0x54E11615, 0x16464218, 0x422855E2, 0x57E31657, ++0x16786EF2, 0x26E22E2B, 0x4F267F04, 0x6EF6AFCE, ++0x00203494, 0x00117804, 0x002038F4, 0x00203908, ++0x0020050A, 0x00201008, 0x0020102E, 0x00203A58, ++0x002018A2, 0x002018E6, 0x00203A6C, 0x00203A74, ++0x00203A78, 0x001C3500, 0x001C1000, 0x0020398A, ++0x00117800, 0x002018EE, 0x00203A8C, 0x00203990, ++0x001C3704, 0x002033E8, 0x001C373C, 0x001C3700, ++0x001C370C, 0x2FD62FC6, 0x4F222FE6, 0x6C53DD10, ++0x6E43BFA4, 0x2DE2BF89, 0x0009BFA0, 0x2C1251D5, ++0x1C4154D6, 0x1C5255D7, 0x1C6356D8, 0x6EF64F26, ++0x000B6DF6, 0x61636CF6, 0xA004E600, 0x62564109, ++0x24227601, 0x36127404, 0x000B8BF9, 0x00000009, ++0x001C370C, 0x0009A16E, 0x2FE62FD6, 0xDD944F22, ++0xA0049EB2, 0xD4930009, 0x420BD293, 0x62D265D2, ++0x8BF822E8, 0x0009A004, 0xD28FD490, 0x55D1420B, ++0x22E852D1, 0xA0048BF8, 0xD48D0009, 0x420BD28A, ++0x52D255D2, 0x8BF822E8, 0x0009A004, 0xD286D489, ++0x55D3420B, 0x22E852D3, 0xA0048BF8, 0xD4860009, ++0x420BD281, 0x52D455D4, 0x8BF822E8, 0x6EF64F26, ++0x6DF6000B, 0x2FD62FC6, 0x4F222FE6, 0x6E636C73, ++0x6D53B01A, 0x64D357F4, 0xB05F65E3, 0xB07566C3, ++0xB0A40009, 0xB0A80009, 0xB0AC0009, 0xB0AC0009, ++0xB0AF0009, 0xB03154F5, 0x6CCD6C03, 0x4F2660C3, ++0x6DF66EF6, 0x6CF6000B, 0x3412D170, 0xD6700529, ++0x2650D770, 0x2742000B, 0x0009A018, 0x2FD62FC6, ++0x4F222FE6, 0x6E636C73, 0x6D53BFEE, 0x64D357F4, ++0xB03365E3, 0xB08D66C3, 0xB00F54F5, 0x6CCD6C03, ++0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, 0xE503D162, ++0xD763D462, 0x21524518, 0x2472000B, 0xD45FD15E, ++0x2162E600, 0x2462000B, 0xBF734F22, 0xBF73E40A, ++0xD25C0009, 0x4118E104, 0xE40AE500, 0xBF692212, ++0xD7592252, 0xCB206072, 0x000B4F26, 0x4F222702, ++0x410BD156, 0xD556E400, 0x4F26452B, 0xD1552FE6, ++0x66126E63, 0x92104418, 0x44084528, 0x45002629, ++0x265B4408, 0x264B4400, 0x21624708, 0xD14E4708, ++0x217227EB, 0x6EF6000B, 0x1FFF03F0, 0x4F222FE6, ++0xE101DE4A, 0xBF3DE40A, 0x67E32E12, 0xE500776C, ++0xE204E130, 0x2752E40A, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27222712, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x175ABF18, 0x2E62E600, 0x000B4F26, 0xD2346EF6, ++0xE441E101, 0x000B2212, 0xD1322242, 0xE605D432, ++0x000B2162, 0x000B2462, 0xD2300009, 0xE40AE601, ++0x2262AF00, 0x2FC62FB6, 0x2FE62FD6, 0x7FFC4F22, ++0x6C43DB2B, 0xED0060B2, 0x2B02CB03, 0xC90360B2, ++0x6E03A008, 0x89073DC2, 0xE46460B2, 0xB07CC903, ++0x7D016E03, 0x8BF52EE8, 0x8F043DC2, 0xD4212FE1, ++0x460BD621, 0x62F10009, 0x6023622D, 0x89FFC801, ++0x7F046023, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x001C3B88, 0x00203AA0, 0x002018EE, 0x00203AA8, ++0x00203AB0, 0x00203AB8, 0x00203AC0, 0x0025E720, ++0x00203DA0, 0x002038F8, 0x001C5968, 0x001C3B40, ++0x000F8000, 0x001D4004, 0x001C3500, 0x002015E0, ++0x0020160C, 0x001C5814, 0x001C59D0, 0x001C5830, ++0x001C6268, 0x001C59A4, 0x001C639C, 0x001C581C, ++0x001C5860, 0x00203AC8, 0x002018A2, 0x8F014411, ++0x6043604B, 0x0009000B, 0x5651D52B, 0x46286052, ++0x306C000B, 0x2FC62FB6, 0x2FE62FD6, 0x4F124F22, ++0xBFF14F02, 0x6B036E43, 0xDD25DC24, 0x0009BFEC, ++0x3C0530B8, 0x4609060A, 0x46014609, 0x020A3D65, ++0x42094209, 0x32E24209, 0x4F068BF0, 0x4F264F16, ++0x6DF66EF6, 0x000B6CF6, 0x2FC66BF6, 0x2FE62FD6, ++0x4F124F22, 0xBFCF4F02, 0x6C036E43, 0xBFCBDD13, ++0x30C80009, 0x060A3D05, 0x46094609, 0x36E24601, ++0x4F068BF5, 0x4F264F16, 0x6DF66EF6, 0x6CF6000B, ++0x4F222FE6, 0xE102DE0B, 0xE403E500, 0xBFB92E12, ++0xE6062E52, 0xE7004618, 0x2E62E403, 0x4F262E72, ++0x6EF6AFB0, 0x0009000B, 0x001C1040, 0xCCCCCCCD, ++0x10624DD3, 0x001D4004, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE5007F98, 0x6453E710, ++0x6B534728, 0xEE1ADCBC, 0x6153655D, 0x315C4108, ++0x75014108, 0x6043317C, 0x0F16665D, 0xED0060B3, ++0x21B136E3, 0x81128111, 0x11D28113, 0x11D411D3, ++0x74048FEA, 0xD8B167F2, 0x1871D9B1, 0x58F12872, ++0x1981D1B0, 0x59F22982, 0x5DF45AF3, 0x54F65EF5, ++0x21921191, 0x11A211A3, 0x11D411D5, 0x11E611E7, ++0x11481149, 0xDAA855F7, 0x57F8EE00, 0x52F9DDA7, ++0x64E3D6A7, 0x2A521A51, 0xD8A7D9A6, 0x2D729AD5, ++0x6EED2622, 0x4D086DE3, 0x3DEC61E3, 0x4D084108, ++0x3D9C31EC, 0x410860B3, 0x81D12DB1, 0x4108E050, ++0x4008E7B7, 0x677C4108, 0x60B381D2, 0xE200318C, ++0x81D33472, 0x1D131DD2, 0x8D01D493, 0xD4901D24, ++0xB0B365D3, 0x64ED7E01, 0x8BDA34A2, 0x2FD2DA8C, ++0xDD9268A2, 0x2D824829, 0x7DFC64A2, 0xD287694D, ++0x6E222D92, 0x7D0C4E29, 0x68222DE2, 0x618D6AD3, ++0x2A16D784, 0xD48A6D72, 0x24D2D583, 0xD6895E72, ++0x517414E2, 0x1414EE00, 0xD1875876, 0x59781486, ++0x1498E710, 0x65E36252, 0x26E2142A, 0xE60064E3, ++0x6843644D, 0x384C4808, 0x381C4808, 0x0C866053, ++0x09CE28B1, 0x819160B3, 0x0ACE6053, 0x81A26043, ++0x0DCE6053, 0x81D360B3, 0x08CE6053, 0x18827401, ++0x624D09CE, 0x0ACE19E3, 0x1A643273, 0x75048FE0, ++0xE003D96A, 0x40186C92, 0x6D922CB1, 0x81D1DA6F, ++0x6E92E050, 0x81E24008, 0x60B36192, 0x64928113, ++0x1442E600, 0xD4696792, 0x689217A3, 0x1864E1FF, ++0x6563E703, 0x364C4608, 0x26127501, 0x3673665D, ++0xDC5B8BF8, 0x6DC2E003, 0x2DB14018, 0xD2606EC2, ++0x61C281E1, 0x1112EE00, 0xE02464C2, 0x65C21423, ++0x15E4D45B, 0xE58067C2, 0x68C28172, 0x818366E3, ++0x666D655C, 0x76046963, 0x394C6A6D, 0x8FF83A53, ++0xDB5429E2, 0x24B2DC54, 0x24C27404, 0x4F267F68, ++0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, 0x68F6000B, ++0x60116142, 0x8F03C803, 0xD23DE500, 0x8B063420, ++0xC9036011, 0x8B068802, 0x3420D239, 0x56128B03, ++0x52646513, 0x000B2422, 0x01136053, 0x2FE62FD6, ++0x7FEC4F22, 0x62536E53, 0x6D43E550, 0x4508E400, ++0xE101A001, 0x60435224, 0x81212211, 0x60538123, ++0x56E28122, 0x8BF53620, 0x16E4D238, 0xE61464F3, ++0x65E3420B, 0xE4FC65E1, 0x2E512549, 0x65F361F1, ++0x2F112149, 0xD13154D1, 0xE614410B, 0x607157D1, ++0x2701CB01, 0x7F141DE1, 0x6EF64F26, 0x6DF6000B, ++0x2FE62FD6, 0x7FEC4F22, 0x66536E53, 0x6D43E5FC, ++0x20596061, 0x2601CB01, 0x326052E2, 0x12E48B06, ++0x31E051E2, 0x52D18B04, 0x1E22A002, 0x5664AFF0, ++0x64F3D21E, 0x420BE614, 0x67E165E3, 0x2719E1FC, ++0x67F12E71, 0x271954D1, 0x65F3D118, 0x410BE614, ++0x52D12F71, 0xCB016021, 0x1DE12201, 0x4F267F14, ++0x000B6EF6, 0x00006DF6, 0x00203924, 0x002034F4, ++0x002034FC, 0x00203504, 0x0020352C, 0x00203910, ++0x00203918, 0x00100208, 0x001017C0, 0x001E210C, ++0x001C3D00, 0x00203964, 0x001000C8, 0x00117880, ++0x00117780, 0x00040020, 0x0026C401, 0x00200ED6, ++0x4F222FE6, 0xDE42624C, 0x42004208, 0x3E2CA005, ++0xD4405252, 0xBF695624, 0x65E22E62, 0x352052E1, ++0xD63D8BF6, 0x4F262622, 0x6EF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xDC394F22, 0x52C1DB39, 0x362066C2, ++0x6061891C, 0x8801C903, 0xDE348918, 0xBF37DD35, ++0x650364E3, 0x66B28503, 0x3262620D, 0xD4328907, ++0x0009BF76, 0x4D0BD431, 0xAFE60009, 0xBF3D0009, ++0xD42F64E3, 0x00094D0B, 0x0009AFDF, 0x2262D22D, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x2FD62FC6, ++0x4F222FE6, 0xDD29DC28, 0x6E4360C2, 0x04DE4008, ++0xE614D127, 0x65E3410B, 0xD127D726, 0x55E227E2, ++0x35E05254, 0x21228F04, 0x400860C2, 0x122202DE, ++0x605365C2, 0x75014008, 0x0DE606DE, 0xC90F6053, ++0x60632C02, 0x6EF64F26, 0x000B6DF6, 0x85436CF6, ++0x650D5643, 0x622D6262, 0x35277204, 0xE1008F0C, ++0x2268960C, 0xD6158B03, 0x72015261, 0xD6131621, ++0x6262E101, 0x26227201, 0x6013000B, 0x000001FF, ++0x00203504, 0x002034FC, 0x001C3D00, 0x0020352C, ++0x002038F4, 0x002018A2, 0x002034F4, 0x00203AF0, ++0x00203AF4, 0x001C3D28, 0x00203964, 0x00203924, ++0x00200ED6, 0x00203968, 0x0020396C, 0x00117754, ++0x2FC62FB6, 0x2FE62FD6, 0x7FF84F22, 0x6022D237, ++0x8D58C803, 0xDE362F01, 0xDB37DC36, 0x66C252C1, ++0x892F3620, 0xC9036061, 0x892B8801, 0xD233DD31, ++0x64D3420B, 0x1F016503, 0x880160B1, 0xD2308B04, ++0x64D3420B, 0x0009AFEA, 0x85615653, 0x8904C820, ++0xE050D72C, 0x7201027E, 0xD22B0726, 0x6453420B, ++0x89072008, 0x55F1D126, 0x64D3410B, 0xE601D727, ++0x2762AFD4, 0x55F1D226, 0x64E3420B, 0xE601D125, ++0x2162AFCC, 0xDD25DE24, 0xDC26DB25, 0x66D252D1, ++0x89183620, 0xC9036061, 0x89148801, 0xD117D41F, ++0x0009410B, 0x36E05603, 0x65038F04, 0x2B20E201, ++0x2C52AFEC, 0xD712D41C, 0x0009470B, 0xE601D115, ++0xAFE34618, 0x60F12162, 0x8907C804, 0x7F08D217, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, 0x4F267F08, ++0x6DF66EF6, 0x000B6CF6, 0x00006BF6, 0x001E2100, ++0x00203504, 0x002034FC, 0x0020398C, 0x002014A0, ++0x002014CC, 0x00203494, 0x002016BE, 0x001E212C, ++0x00201530, 0x001C3D30, 0x00117880, 0x002034F4, ++0x00203914, 0x00203910, 0x0020352C, 0x00200610, ++0xE601D203, 0x1265D503, 0x000B2252, 0x00001266, ++0x001C1010, 0x0000C34F, 0x0009000B, 0x2FD62FC6, ++0x4F222FE6, 0x6D436C53, 0xEE00A004, 0x7E0164D4, ++0x644CBFF2, 0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, ++0xE5006CF6, 0x6643A002, 0x76017501, 0x22286260, ++0xAFE38BFA, 0x2FE60009, 0x75076253, 0xE1086753, ++0x6043EE0A, 0x4409C90F, 0x650330E2, 0x8D014409, ++0xE630E637, 0x4110365C, 0x8FF22760, 0xE00077FF, ++0x000B8028, 0x000B6EF6, 0x000BE000, 0x2FE6E000, ++0x7FEC4F22, 0x6E436253, 0xBFDC65F3, 0xBFD06423, ++0xBFCE64E3, 0xD40364F3, 0x0009BFCB, 0x4F267F14, ++0x6EF6000B, 0x00203AF8, 0xE4FDD29F, 0xD79F6122, ++0x22122149, 0x74016022, 0x2202CB01, 0xD59C6622, ++0x22622649, 0xC8406070, 0x60528902, 0x2502CB04, ++0xE1F76452, 0x25422419, 0xE7016052, 0x2502CB40, ++0xE6026052, 0x2502C9CF, 0x47186052, 0x2502CB10, ++0xCB036052, 0x15622502, 0x1573000B, 0xD78ED58D, ++0xD48FD28E, 0xE600E100, 0x27112511, 0xAFCB2210, ++0x664C2461, 0x4600D28B, 0x6060362C, 0x000BCB10, ++0x654C2600, 0x4500D287, 0x6650352C, 0x2619E1EF, ++0x2560000B, 0xD284664C, 0x362C4600, 0xCB106060, ++0x2600000B, 0xD280654C, 0x352C4500, 0xE1EF6650, ++0x000B2619, 0x664C2560, 0x4600D27A, 0x6060362C, ++0x000BCB08, 0x654C2600, 0x4500D276, 0x6650352C, ++0x2619E1F7, 0x2560000B, 0xD273664C, 0x362C4600, ++0xCB086060, 0x2600000B, 0xD26F654C, 0x352C4500, ++0xE1F76650, 0x000B2619, 0x624C2560, 0x4200D669, ++0x6020326C, 0x4021C908, 0x40214021, 0x600C000B, ++0xD665624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0xD161600C, 0x341C644C, 0x000B6240, ++0xD15F602C, 0x341C644C, 0x000B6240, 0x2FE6602C, ++0x6E434F22, 0xE60A645C, 0x89143467, 0x0009BFEB, ++0x60EC640C, 0x8B028801, 0xA002E00F, 0x44092409, ++0x624C4409, 0x3263E60A, 0xBFE28905, 0x620C644C, ++0xC8806023, 0xE2008B00, 0x4F266023, 0x6EF6000B, ++0xD64C4F22, 0x88016062, 0xB2578B03, 0xA0030009, ++0xD2490009, 0x2260E640, 0xE200D648, 0x000B4F26, ++0x4F222622, 0x6062D643, 0x8B018802, 0x0009B2A0, ++0xE200D642, 0x000B4F26, 0xD53E2622, 0xE100D43E, ++0x2512E701, 0x2470000B, 0xE604D23B, 0x2260000B, ++0xD43B4F22, 0x410BD13B, 0xD53B0009, 0x6650E1FD, ++0x2619D23A, 0x2560E700, 0x000B4F26, 0x4F222270, ++0xD238D537, 0xD7386152, 0x2512611D, 0xE6FF6452, ++0x2542242B, 0xD22FD435, 0x420B666D, 0xD52E2762, ++0x6750E1FB, 0x4F262719, 0x2570000B, 0xD4304F22, ++0x410BD128, 0xD5280009, 0x6650E7F7, 0x4F262679, ++0x2560000B, 0x9425D524, 0x22496250, 0x2520000B, ++0xE4BFD521, 0x22496250, 0x2520000B, 0xD2254F22, ++0x600D8522, 0x89112008, 0x89458801, 0x89478803, ++0x89498805, 0x894F8806, 0x89558808, 0x895B8809, ++0x8961880A, 0x8967880B, 0x0009A06E, 0x0009B070, ++0x600CA06B, 0x0000FF7F, 0x001E2148, 0x001E1000, ++0x001E1108, 0x002039C4, 0x002039C6, 0x002039E5, ++0x002039A8, 0x001E103F, 0x001E105F, 0x001E102F, ++0x001E1090, 0x002039CC, 0x001E100B, 0x002039C8, ++0x00203AFC, 0x002018A2, 0x001E1028, 0x002039E4, ++0x001D4020, 0x98760000, 0x001C1000, 0x00203B08, ++0x00203B18, 0x0020399C, 0x0009B04C, 0x600CA035, ++0x0009B055, 0x600CA031, 0x6260D684, 0x8B2B2228, ++0x0009B061, 0x600CA029, 0x6260D680, 0x8B232228, ++0x0009B069, 0x600CA021, 0x6260D67C, 0x8B1B2228, ++0x0009B0C7, 0x600CA019, 0x6260D678, 0x8B132228, ++0x0009B0CD, 0x600CA011, 0x6260D674, 0x8B0B2228, ++0x0009B125, 0x600CA009, 0x6260D670, 0x8B032228, ++0x0009B13D, 0x600CA001, 0x4F26E000, 0x0009000B, ++0xD26CD16B, 0xD56C8412, 0x4000C90F, 0xD76B012D, ++0xE403D66B, 0xE20F611C, 0x2540E001, 0x25202712, ++0x2602000B, 0xE601D262, 0x30668523, 0xE0008D05, ++0xD663D260, 0xE0018122, 0x000B2602, 0xD25C0009, ++0x600D8523, 0x89052008, 0x8B0A8801, 0x6060D65D, ++0x2600CB01, 0xD457D65A, 0xE001E101, 0x000B2612, ++0x000B8142, 0xD152E000, 0x8513E501, 0x640D4518, ++0x66033453, 0xE0008D05, 0xD551D253, 0x2260E001, ++0x000B2502, 0x4F220009, 0x8513D149, 0x6453650D, ++0x62494419, 0x227D672E, 0x8801602C, 0x88028909, ++0x88038910, 0x8806891A, 0x88078935, 0xA04C893B, ++0xD5460009, 0x6652D746, 0x2762D446, 0x622C6261, ++0x2421A038, 0x2228625C, 0xD4438B3F, 0x6642D540, ++0x2562D440, 0x24018561, 0x6203A02C, 0x2008605C, ++0x88108907, 0x88208908, 0x88308909, 0xA02C890A, ++0xD23A0009, 0x6222A008, 0xA005D239, 0xD2396222, ++0x6222A002, 0x6262D638, 0xD432D531, 0x66212522, ++0xA00F626C, 0xD6352421, 0x6261D52D, 0x622CD42D, ++0xA0072562, 0xD6322421, 0x8561D529, 0x2562D429, ++0x62032401, 0x662D8515, 0x3617610D, 0x65038F01, ++0xB0CB2451, 0xA0010009, 0xE000E001, 0x000B4F26, ++0xD6190009, 0xD427E101, 0x65412610, 0xD118D717, ++0xE20F655D, 0x2752E001, 0x000B2620, 0x2FE62102, ++0xD20F4F22, 0x640C8523, 0x8B082448, 0xD511D61D, ++0x2621E200, 0x940F8451, 0xA0482049, 0xDE0D8051, ++0xC84060E0, 0xE2018D32, 0x89443427, 0xD216D615, ++0x2641420B, 0x0009A030, 0x0000FF7F, 0x002039E5, ++0x0020399C, 0x002039A8, 0x001E1100, 0x001E100C, ++0x002039C8, 0x001E1000, 0x001E1001, 0x002039D0, ++0x002039B0, 0x002039B4, 0x002039B8, 0x002039D4, ++0x002039D8, 0x002039DC, 0x002039E0, 0x00203E04, ++0x00203E0E, 0x002039C2, 0x00202886, 0x89123427, ++0xD294D693, 0x2641420B, 0xCB8084E1, 0x80E1B0F5, ++0xD69160E0, 0x2E00CB04, 0xC93F6060, 0xD68F2600, ++0xA001E001, 0xE0002602, 0x000B4F26, 0xD68C6EF6, ++0xC8806060, 0xD2868919, 0x88016021, 0xD2898B15, ++0x8524E501, 0x89103056, 0xE203D187, 0x2120D487, ++0xE00B6541, 0x0656655D, 0xE40FD585, 0x2140E702, ++0xD77E2571, 0x000BE001, 0x000B2702, 0x2FE6E000, ++0xDE804F22, 0xC88084E1, 0xD57A892C, 0x20088554, ++0x61038F28, 0x8553D77C, 0x64036672, 0x8566650C, ++0x3520620C, 0xD6798B1E, 0x651CD774, 0x2651644C, ++0x60E02741, 0x8904C840, 0x420BD275, 0xA0030009, ++0xD2680009, 0x0009420B, 0x0009B09F, 0xE201D167, ++0x60E02122, 0xCB04D464, 0x60402E00, 0x2400C93F, ++0x6023A001, 0x4F26E000, 0x6EF6000B, 0x2FB62FA6, ++0x2FD62FC6, 0xDA622FE6, 0x66A1E240, 0x3622DC5E, ++0x62638900, 0x6ED36D2C, 0x4E2136D8, 0x4E212A61, ++0xDB61D460, 0xE700A00F, 0x770162B2, 0x71026123, ++0x66212B12, 0x71026213, 0x61212B12, 0x651D666D, ++0x356C4528, 0x627C2452, 0x8BED32E3, 0xC90360D3, ++0x8B108803, 0x617367B2, 0x2B127102, 0x71026E13, ++0x2B126571, 0x655D6DE1, 0x422862DD, 0x325CE107, ++0xA00C2C10, 0x88022422, 0xA0038B01, 0x8801E203, ++0xE2018B05, 0x66B22C20, 0x655D6561, 0xE60F2452, ++0x67A12C60, 0x8B052778, 0xDD38DC44, 0xEB01EA00, ++0x2DB22CA2, 0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, ++0x2FE62FD6, 0xE240DD36, 0x362266D1, 0x62638900, ++0x3678672C, 0x7703DE38, 0x47212D61, 0x64E2D635, ++0xA00E4721, 0x6562E100, 0x62537101, 0x74012450, ++0x24204219, 0x45297401, 0x74012450, 0x24504519, ++0x621C7401, 0x8BEE3273, 0x66E24200, 0x420061D1, ++0x2118362C, 0x2E628F06, 0xDD1CD728, 0xE501E400, ++0x2D522742, 0x000B6EF6, 0x2FD66DF6, 0x4F222FE6, ++0xED0AEE01, 0x64E3BC85, 0xBC8A64E3, 0x62EC7E01, ++0x8BF732D7, 0xBC8DEE01, 0x64E364E3, 0x7E01BC92, ++0x32D762EC, 0x4F268BF7, 0x000B6EF6, 0xD1186DF6, ++0xD418920D, 0x72122122, 0x2422D617, 0xD7177204, ++0x72202622, 0x2722D116, 0x000B7230, 0x137A2122, ++0x002039C2, 0x00202992, 0x001E1015, 0x002039C8, ++0x001E1001, 0x0020399C, 0x001E1100, 0x002039C6, ++0x002039B4, 0x001E1000, 0x002039B8, 0x002039C4, ++0x00202886, 0x001E100C, 0x002039B0, 0x002039CC, ++0x002039D0, 0x002039D4, 0x002039D8, 0x002039DC, ++0x002039E0, 0x4F222FE6, 0xD6707FFC, 0x88016060, ++0xE2018951, 0x2620BFBB, 0xD56ED16D, 0xDE6E6010, ++0x64E36552, 0x7402C840, 0x8D22D16C, 0xD26C7502, ++0xE601D76C, 0xE7042722, 0x76016255, 0x626C2421, ++0x8FF93273, 0xD4637402, 0x6242E601, 0x640D8528, ++0x67494419, 0x275D657E, 0x81E4607C, 0xE417D562, ++0x67557601, 0x3243626C, 0x8FF92171, 0xA0207102, ++0xD25E0009, 0xE601D75B, 0xE7042722, 0x76016255, ++0x626C2421, 0x8FF93273, 0xD4527402, 0x6242E601, ++0x640D8528, 0x67494419, 0x275D657E, 0x81E4607C, ++0xE417D553, 0x67557601, 0x3243626C, 0x8FF92171, ++0x92897102, 0xD2462E21, 0x5E23D74E, 0x64F22FE2, ++0x604365F2, 0x2700C980, 0xC9606043, 0x80716103, ++0xC9036043, 0x80724519, 0x65F2605C, 0x817266F2, ++0x46194629, 0x606C4529, 0x4018645C, 0x8173304C, ++0x21185E23, 0x64F22FE2, 0x6E4C62F2, 0x602C4219, ++0x66F262F2, 0x46294018, 0x461930EC, 0x42298174, ++0x652C606C, 0x305C4018, 0x81758F07, 0x0009BC96, ++0x2228620C, 0xA00A8908, 0x60130009, 0x8B038840, ++0x0009B009, 0x0009A003, 0xE202D62F, 0x7F042622, ++0x000B4F26, 0x4F226EF6, 0x8552D52A, 0x8830600D, ++0x88318903, 0xA0348923, 0x85550009, 0xD428D727, ++0x85532701, 0x610DD627, 0x24124118, 0x460BD426, ++0xD7230009, 0xD226D425, 0x6572420B, 0xE230D120, ++0x42286712, 0x2729E620, 0x37604628, 0xD6218B03, ++0xA016E200, 0xD61F2622, 0xA012E202, 0xD1182622, ++0x6212E530, 0xE6204528, 0x46282259, 0x89083260, ++0xD41AD119, 0xE601D513, 0x2160450B, 0x472BD718, ++0x4F264F26, 0x0009000B, 0x0000060A, 0x002039E4, ++0x001E1000, 0x002039D0, 0x00203E04, 0x00203E10, ++0x00203DA8, 0x002039B8, 0x00203DD8, 0x00203DD6, ++0x00203DAA, 0x0020399C, 0x002039C8, 0x002039B4, ++0x002039B0, 0x002018A2, 0x00203B24, 0x00203B28, ++0x002018EE, 0x002039CC, 0x001E100B, 0x00203B3C, ++0x00114004, 0x4F222FE6, 0xDE967FFC, 0x200884E9, ++0x2F008D06, 0xD695D494, 0x0009460B, 0x64F0B19A, ++0x6620D293, 0x89022668, 0xC9BF60E0, 0x7F042E00, ++0x000B4F26, 0x000B6EF6, 0x2FE60009, 0xDE8D4F22, ++0x60E0D68D, 0xCBC0D48D, 0x62602E00, 0xC803602C, ++0x40218904, 0x70014021, 0x6603A002, 0x66034009, ++0xD687616D, 0xE500A004, 0x75016262, 0x74042422, ++0x3213625D, 0xD2838BF8, 0x0009420B, 0xC9BF84E2, ++0x4F2680E2, 0x6EF6000B, 0x2FE62FD6, 0x7FFC4F22, ++0x6260D67D, 0x89442228, 0xD572E100, 0x60502610, ++0xCB40D47A, 0x2500440B, 0x8D052008, 0x62E06E03, ++0x7104612C, 0x2F11A006, 0xD475D66D, 0xDD756760, ++0x657C4D0B, 0xE23C6D1D, 0x8B033D27, 0xD267D472, ++0x0009420B, 0x4D214D21, 0xA005D770, 0x66E6E400, ++0x357C4508, 0x74012562, 0x35D3654D, 0xD76C8BF7, ++0x6172E003, 0x81114018, 0x6E7260F1, 0x81E2700C, ++0xD4686172, 0xDD688113, 0x4D0BDE68, 0xE2016572, ++0xD4672E22, 0x420BD255, 0xD6560009, 0xC93F6060, ++0x7F042600, 0x6EF64F26, 0x6DF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xD25F4F22, 0x6B436E73, 0x420B6C53, ++0x20086D63, 0x64038D1C, 0xE50ED149, 0x32526210, ++0x60C38916, 0x804124B0, 0x814160D3, 0xA007E500, ++0x655D61BC, 0x00EC6053, 0x364C6653, 0x80647501, ++0x3213625D, 0xD63B8BF5, 0xC9BF6060, 0x2600A008, ++0xD23AD44D, 0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x7FC44F22, ++0x720262F3, 0x22512F41, 0x45297202, 0x60632251, ++0xE5C4E682, 0x67F38121, 0x655C666C, 0xE408BFB6, ++0x4F267F3C, 0x0009000B, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE1007FC4, 0x6513ECFF, ++0x6B136CCD, 0xDE36D735, 0xEDFF64F3, 0xD835EA04, ++0x6053655C, 0x027D4000, 0x32C0622D, 0x66038D0D, ++0x09ED6063, 0x2491027D, 0x24217402, 0x698202ED, ++0x3928622D, 0x74022892, 0x75017104, 0x6063625C, ++0x07D532A2, 0x0EB58FE4, 0x2448641C, 0xE6808905, ++0x67F3E5C5, 0xBF79666C, 0x7F3C655C, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0xD11E68F6, ++0x6012D21E, 0xCB20E405, 0x2102E500, 0x000B2242, ++0x00002252, 0x001E1017, 0x00203B40, 0x002018A2, ++0x0020390E, 0x001E1015, 0x001E10BF, 0x00117800, ++0x001E10FC, 0x00200610, 0x00203914, 0x00202AEA, ++0x00203B44, 0x002018EE, 0x00203B60, 0x0011788C, ++0x00203910, 0x002034F4, 0x00201530, 0x001E2130, ++0x00203B68, 0x00202AAC, 0x00203B6C, 0x00203974, ++0x0020397C, 0x00203DA4, 0x001C3500, 0x001D4004, ++0xD564D163, 0xE400D764, 0x2142E20F, 0x17411154, ++0xD5622722, 0x9669D762, 0x15412572, 0x96661562, ++0xE6011565, 0xD55F1165, 0x666CE6F8, 0x25422542, ++0x25422542, 0x25422542, 0x25622542, 0x7601E727, ++0x67632572, 0x25627797, 0xE7042572, 0x2572E248, ++0xE2192522, 0xE2702522, 0x25422542, 0x25422542, ++0x25222542, 0x2522E20C, 0x25422542, 0x25422542, ++0x25422542, 0x25422542, 0x000B154A, 0xE2081145, ++0x0009422B, 0x2FE62FD6, 0x7FFC4F22, 0xC8206043, ++0x6E438D02, 0x0009BE67, 0xC81060E3, 0xBE648901, ++0x60E30009, 0x8901C840, 0x0009BE86, 0xC80160E3, ++0xDD3D8938, 0xC80260D0, 0x2F008D03, 0x460BD63B, ++0x60F00009, 0x8902C804, 0x460BD639, 0x62F00009, ++0xC8806023, 0x60D08902, 0x2D00C97F, 0xC8016023, ++0xD6348906, 0x0009460B, 0x0009A007, 0x51630601, ++0x8902C808, 0x460BD630, 0x60F00009, 0x8902C810, ++0x420BD22E, 0xD52E0009, 0x88026052, 0xD22D8B03, ++0xA005E604, 0x88012260, 0xD22A8B02, 0x2260E601, ++0x2522E200, 0xC88060E3, 0xD227892D, 0x60E36E20, ++0x8902C880, 0x420BD225, 0x60E30009, 0x8902C840, ++0x420BD223, 0x60E30009, 0x8902C802, 0x420BD221, ++0x60E30009, 0x890DC804, 0xDD20D11F, 0x0009410B, ++0x0009BF0D, 0x0009BF4C, 0xD51ED41D, 0x2470E708, ++0x25D2BF85, 0xC80860E3, 0xD21B8905, 0x4F267F04, ++0x422B6EF6, 0x7F046DF6, 0x6EF64F26, 0x6DF6000B, ++0x001C581C, 0xA000A000, 0x001D0100, 0x001D4000, ++0x00040021, 0x001C589C, 0x001E1021, 0x00201A90, ++0x00201AB2, 0x00202114, 0x00201ACA, 0x00201AD8, ++0x002039C8, 0x001E100B, 0x001E1028, 0x00201B44, ++0x00201B50, 0x00201AE0, 0x00201AFE, 0x12345678, ++0x001E1000, 0x0010F100, 0x00201B2C, 0x644CD6A7, ++0x000B346C, 0xD6A62450, 0x346C644C, 0x2450000B, ++0x644CD6A4, 0x000B346C, 0x625C2450, 0x4208616D, ++0x42084119, 0x42006019, 0x670E614C, 0xD49E321C, ++0x4200207D, 0x324CC90F, 0x2200000B, 0x4208625C, ++0x42004208, 0x324C644C, 0x4200D498, 0x000B324C, ++0x2FE62260, 0x614C4F12, 0x4100D493, 0x6710314C, ++0xE29F666D, 0x27294619, 0x6E536269, 0x672E6573, ++0x4221227D, 0x42214221, 0x7601662C, 0xE4014608, ++0x34E84608, 0x644C4600, 0x071A0467, 0x2150257B, ++0x000B4F16, 0x4F226EF6, 0xD2857FE8, 0x88016021, ++0xD2848B7B, 0x26686621, 0xD2838B77, 0x26686621, ++0xE50F8B73, 0xE401BFA2, 0xBFA4E501, 0xE586E400, ++0xE400655C, 0x2F50BFA4, 0xBFA1E401, 0xE602E506, ++0x60634618, 0x81F2E401, 0x6543BF9F, 0xE40185F2, ++0xBFAB6543, 0x85F26603, 0x6543E401, 0x6603BFB1, ++0xE40265F0, 0x6053756C, 0x80F8BF80, 0xBF82E402, ++0x84F8E512, 0x7090E402, 0x6503BF82, 0x4618E602, ++0x81F66063, 0xBF80E402, 0x85F6E500, 0x6603E402, ++0xE500BF8C, 0xE40285F6, 0xBF926603, 0xE5FEE500, ++0xE010655C, 0xBF61E403, 0xE5130F54, 0xE40EBF63, ++0x05FCE010, 0xBF63E40E, 0xE5007585, 0xBF64E403, ++0xE500E640, 0xBF71E403, 0xE500E640, 0xBF78E403, ++0xE5FFE640, 0xE014655C, 0xBF47E404, 0xE40F0F54, ++0xE504BF49, 0x05FCE014, 0xBF49E40F, 0xE5017584, ++0xBF4AE640, 0xE501E404, 0xBF57E640, 0xE501E404, ++0xE404E640, 0xAF5C7F18, 0x7F184F26, 0x000B4F26, ++0x4F220009, 0xD2427FF0, 0x88016021, 0xD2418B71, ++0x26686621, 0xD2408B6D, 0x26686621, 0xE50F8B69, ++0xE401BF1C, 0xBF1EE501, 0xE586E400, 0xE400655C, ++0x2F50BF1E, 0xBF1BE401, 0xE401E506, 0xBF1C6543, ++0xE401E640, 0xBF296543, 0xE401E640, 0xBF306543, ++0x65F0E640, 0x756CE402, 0xBEFF6053, 0xE40280F4, ++0xE512BF01, 0xE40284F4, 0xBF017090, 0xE6406503, ++0xBF02E402, 0xE640E500, 0xBF0FE402, 0xE640E500, ++0xBF16E402, 0xE5FEE500, 0x6053655C, 0xBEE5E403, ++0xE51380F8, 0xE40EBEE7, 0xE40E84F8, 0xBEE77085, ++0xE5006503, 0xBEE8E640, 0xE500E403, 0xBEF5E640, ++0xE500E403, 0xBEFCE640, 0xE5FFE403, 0x6053655C, ++0xBECBE404, 0xE40F80FC, 0xE504BECD, 0xE40F84FC, ++0xBECD7083, 0xE5016503, 0xBECEE640, 0xE501E404, ++0xBEDBE640, 0xE501E404, 0xE404E640, 0xAEE07F10, ++0x7F104F26, 0x000B4F26, 0x00000009, 0x001E102F, ++0x001E1080, 0x001E1090, 0x001E103F, 0x001E103E, ++0x002039C2, 0x002039C4, 0x002039C6, 0xD21DD11C, ++0x66206010, 0x676C7001, 0x3700C90F, 0xE5008D13, ++0x67106210, 0x7701622C, 0x64232170, 0xD6166010, ++0x44084408, 0x3428C90F, 0x62602100, 0x7201D513, ++0x44082620, 0x000B354C, 0xD10F6053, 0x25586510, ++0xE6008D13, 0xD60DD40B, 0x655C6540, 0x47086753, ++0x37584708, 0x47086540, 0x24507501, 0x367C6040, ++0x2400C90F, 0x72FF6210, 0x000B2120, 0x00006063, ++0x0020390D, 0x0020390C, 0x0020390E, 0x00203534, ++0x7FFC4F22, 0xE680D19F, 0x666C6212, 0xD29E2F22, ++0x67F36563, 0x420B7542, 0x7F04E404, 0x000B4F26, ++0xE6800009, 0xD298666C, 0xE7006563, 0x422B7540, ++0xE6806473, 0xD294666C, 0xE7006563, 0x422B7543, ++0x2F866473, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x7FCC4F22, 0xDC8ED28D, 0x72011F21, 0xDB8D1F22, ++0xD18EDE8D, 0x66125211, 0x8B013620, 0x0009A0E5, ++0xC9036061, 0x8B018801, 0x0009A0DF, 0xD288D487, ++0xED84420B, 0x2F025503, 0x30D0845C, 0xA0B88901, ++0xD1840009, 0x626C6610, 0x88016023, 0xD1828B68, ++0x62101FC3, 0x895B2228, 0xE003D480, 0x40186742, ++0x68421772, 0xD57EE900, 0x81816DB3, 0x7D042190, ++0x67D26AB2, 0x64E26852, 0x1F491F57, 0x740464E3, ++0x1FA46542, 0x65431F5A, 0x625275F8, 0x1F761FD5, ++0x6D531F2B, 0xDA74D773, 0x7D94D274, 0x68D21F88, ++0x6AA26972, 0xD1726022, 0x2202CB20, 0xE1401F1C, ++0x7601E600, 0x3213626D, 0x56F48BFB, 0x52F651F5, ++0x21222B62, 0x52F851F7, 0x212256F9, 0x2E6251FA, ++0x51FB2412, 0x2D822512, 0xD9662792, 0x29A2DD5F, ++0x6AD2D965, 0xD9646892, 0x68D21A84, 0x6081DA63, ++0x2801CB01, 0xD86266D2, 0x2A622962, 0xED015AFC, ++0x2AD2480B, 0x2AD24D18, 0x62D2DD5E, 0x2D227201, ++0xD15056F3, 0xE2026062, 0x2602CB01, 0x2120A03D, ++0x8B3A2228, 0xE401DD58, 0x2140E600, 0xE01C2D62, ++0xC801005C, 0xD4558B0A, 0xE600D755, 0xED7D2472, ++0x626C7601, 0x8BFB32D3, 0x24D2DD52, 0xE2FE68C2, ++0x2C822829, 0x095CE01E, 0xE01F5DF1, 0x0A5C2D90, ++0x751051F2, 0xED0621A0, 0xD74BE600, 0x8456D44B, ++0x27007601, 0x696C6854, 0x248039D3, 0x8FF67401, ++0xDA477701, 0x2A10E194, 0xE2007A01, 0x7A0F2A20, ++0xD130E805, 0x66102A80, 0x6023626C, 0x89088801, ++0xD240D42A, 0x420B65F2, 0xD131ED01, 0xAF304D18, ++0x65F221D2, 0x8553D43C, 0x620D6642, 0x89073262, ++0xD13BD43A, 0x0009410B, 0xE601D73A, 0x2762AF1A, ++0xD134D41E, 0x410B65F2, 0xD125ED01, 0xD637D436, ++0x460B4D18, 0xAF0D21D2, 0x7F340009, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x4F2268F6, ++0x85467FF4, 0x2F01E681, 0x666C8547, 0x854881F1, ++0x81F2D209, 0x67F38542, 0x854381F3, 0x81F4E40C, ++0x65636053, 0x420B81F5, 0x7F0C7540, 0x000B4F26, ++0x00000009, 0x001C3D9C, 0x0020245C, 0x0011779A, ++0x001C36F8, 0x001C3B9C, 0x001C3704, 0x0020352C, ++0x002014A0, 0x0020391D, 0x0020391C, 0x00203918, ++0x001C3D98, 0x001C3BB4, 0x001C5960, 0x001C3500, ++0x001C3D30, 0x001C8960, 0x00203504, 0x001C3D00, ++0x0020160C, 0x00117730, 0x00203920, 0x001C582C, ++0x2000A000, 0x0000A000, 0x0011778C, 0x00117792, ++0x00117788, 0x002014CC, 0x002038F4, 0x002034F4, ++0x00201530, 0x001E2130, 0x00203D84, 0x002018A2, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xD19B7FEC, 0x2F12E000, 0x6103D49A, 0x1F4281F2, ++0xDD9ADA99, 0xD69A6813, 0xE0014808, 0x460BDE99, ++0x38EC4800, 0x65A21F03, 0x352052A1, 0xA23E8B01, ++0x60510009, 0x8801C903, 0xA2388B01, 0x52530009, ++0x32E0DE91, 0xD9918B10, 0x64A3490B, 0x4B0BDB90, ++0xDE906403, 0xD791D690, 0xEC01D591, 0x2E02E100, ++0x271026C0, 0x2502AFDF, 0xC8018551, 0xA1578B01, ++0x62510009, 0x4200622D, 0x5E53366A, 0x85E2226D, ++0xC903642C, 0x85E36603, 0x6053650D, 0x40214021, ++0x4500C93F, 0x322A6703, 0x6053252D, 0xC901D17F, ++0x60106C03, 0x8801D97F, 0xDB7F8B05, 0x2120E200, ++0xCB0160B2, 0xD17D2B02, 0x88016011, 0x65A28B0A, ++0x8D042448, 0x9B9E6251, 0xA00322B9, 0x919B2521, ++0x2521221B, 0x37B3EB10, 0x2448895E, 0xD4738B07, ++0x22286241, 0x60638903, 0xA05781F8, 0xD5706473, ++0x46084608, 0x85E26273, 0x46006B50, 0x362C4200, ++0x2BB8C910, 0x8F1F6463, 0x26686603, 0xD2698911, ++0x062D6043, 0x4119616D, 0x6B0E6019, 0x81F820BD, ++0x880160C3, 0x646C8F2C, 0x880F6073, 0xA0278B1B, ++0xD2610009, 0x052D6043, 0x4119615D, 0x670E6019, ++0x645C207D, 0x81F8A01C, 0x890F2668, 0x6043D25B, ++0x6B5D052D, 0x60B94B19, 0x201D610E, 0x60C381F8, ++0x8F0D8801, 0x6473645C, 0xEC00A00A, 0x6043D254, ++0x625D052D, 0x60294219, 0x207D670E, 0x81F8645C, ++0x880285F8, 0x85E1890A, 0x8D07C820, 0xE6DC6203, ++0x60232269, 0x81E1A002, 0x644CE4FF, 0x6210D149, ++0x89012228, 0x644CE4FF, 0x654DEBFF, 0x35B06BBC, ++0xDB368B2B, 0x64A34B0B, 0x410BD135, 0x54036403, ++0x85446E03, 0xC948DB40, 0xDC408808, 0xBEAE8B01, ++0x64B3E502, 0x65E34C0B, 0xDB3DEC01, 0xD13D2DC2, ++0x621260B2, 0x72017001, 0x21228805, 0x2B028F08, ++0x666CE680, 0x6563D238, 0x7549E700, 0x6473420B, ++0xA030D436, 0x7FFF0009, 0x85E28000, 0x20B9EBFC, ++0x610381E2, 0x942A85E3, 0x62032049, 0x450885F8, ++0x81E2201B, 0xC90160C3, 0x40084018, 0x40084008, ++0x4000225B, 0x6023220B, 0x85E481E3, 0x4118E108, ++0x81E4201B, 0xE40262A2, 0x20B98521, 0x67A28121, ++0xCB016071, 0x85F82701, 0x89033042, 0xECE785E2, ++0x81E220C9, 0x490BD41E, 0xA03B0009, 0x7E030009, ++0x001C3D30, 0x00203D90, 0x00203504, 0x001E212C, ++0x002033E8, 0x001C3D00, 0x00117780, 0x002014A0, ++0x0020166C, 0x0011770C, 0x0020391C, 0x0020391D, ++0x00203918, 0x002018A2, 0x001C36F8, 0x00203990, ++0x00203DA0, 0x00203B84, 0x00203C04, 0x00203C84, ++0x00203D04, 0x00203908, 0x002034FC, 0x002014CC, ++0x00203994, 0x00203998, 0x0020245C, 0x00203D88, ++0x00203D8C, 0x602262F2, 0x40094019, 0xC90F4009, ++0x8B0B880A, 0x60E2DE8C, 0x40094019, 0xC90F4009, ++0x8B038808, 0xCB0160A2, 0x2802A006, 0x65E2DE87, ++0x2E527501, 0x286266A2, 0x52F366F2, 0x2622AE83, ++0xD2838551, 0xDE83C802, 0xA0958B01, 0x420B0009, ++0x4E0B64A3, 0x5E036403, 0x85E46503, 0x4918E908, ++0xD77D209B, 0xE04C81E4, 0xDC7C0B7E, 0x7B01D97C, ++0x61C207B6, 0x71016690, 0x8D062668, 0xD4792C12, ++0x420BD279, 0xA070EB01, 0x62512DB2, 0x4B18EB0F, ++0x22B9E102, 0x32104118, 0x85518B0F, 0x2029E2FC, ++0x60518151, 0xCB0172E0, 0x85E12501, 0x202994A3, ++0x85E481E1, 0xA0522049, 0x675181E4, 0x4719677D, ++0x667E6779, 0x7701276D, 0x6903607C, 0x88014918, ++0x25918F3E, 0x6B12D161, 0x21B27B01, 0x660D85E3, ++0x40216063, 0xC93F4021, 0x6C034600, 0x262D322A, ++0xC8016063, 0xDB5ED15D, 0x967D8901, 0xE6002C6B, ++0x666C67CD, 0x40006063, 0x622D021D, 0x8D0E3270, ++0x60436403, 0xE9FF021D, 0x8B013290, 0x01C5A007, ++0x626C7601, 0x3292E904, 0x646C8BEB, 0x60434400, ++0xD15004BD, 0x0B457401, 0x669D6911, 0x89073670, ++0x602D6211, 0x890388FF, 0xE201DB4B, 0x2B2021C1, ++0xECFC8551, 0x815120C9, 0xCB016051, 0xDC472501, ++0x64A34C0B, 0x51F366F2, 0x85EF2612, 0x54F2D244, ++0x650D420B, 0x0009ADE7, 0xE500DC42, 0x420B2C52, ++0x4E0B64A3, 0x54036403, 0x85446E03, 0x6703E908, ++0x65034918, 0x27998541, 0xDB323790, 0x8F0BD932, ++0x6013610D, 0x8B07C820, 0xC9486053, 0x8B038808, ++0xE501BD4D, 0x0009A005, 0x2128D233, 0xBD468901, ++0x64B3E500, 0x490B65E3, 0xADBCEC01, 0x85F22DC2, ++0x7001EE04, 0x31E7610D, 0x8D0281F2, 0xADA97A08, ++0x7F140009, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0xF7FF68F6, 0x2FE68000, 0xD2234F22, ++0x60E36E22, 0x8D02C840, 0xBBF922E2, 0xE2400009, ++0x2E284218, 0xBC048901, 0x60E30009, 0x8905C810, ++0xD21CD41B, 0x0009420B, 0x0009BC03, 0xC80560E3, ++0xBD6D8901, 0x60E30009, 0x8902C802, 0xAC004F26, ++0x4F266EF6, 0x6EF6000B, 0x001C3D3C, 0x00117760, ++0x002014A0, 0x0020166C, 0x00203494, 0x00203DA4, ++0x00203908, 0x002034FC, 0x002014CC, 0x00203974, ++0x0020397C, 0x00203970, 0x00203972, 0x00201530, ++0x002018EE, 0x00203994, 0x00008000, 0x001C3510, ++0x00203D98, 0x002018A2, 0x080A0C0E, 0x00020406, ++0x1A1C1E20, 0x12141618, 0x2E303234, 0x26282A2C, ++0x3A3C3E40, 0x6C625648, 0x41112F26, 0xE2208F18, ++0x890B3123, 0x321CD204, 0xD1026220, 0x412B312C, ++0x00090009, 0x00203412, 0x002033C8, 0x000BE000, ++0x400062F6, 0x40004000, 0x40004000, 0x40004000, ++0x62F6000B, 0x40004000, 0x40004000, 0x40004000, ++0x40184000, 0x62F6000B, 0x40004000, 0x40004000, ++0x40004000, 0x40284000, 0x62F6000B, 0x40004000, ++0x40184000, 0x000B4028, 0xC90F62F6, 0x40054005, ++0x40054005, 0x62F6000B, 0x4005C907, 0x40054005, ++0x62F6000B, 0x4005C903, 0x000B4005, 0xC90162F6, ++0x000B4005, 0x000062F6, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x544F0D0A, 0x46205355, 0x00003A57, ++0x206C754A, 0x32203120, 0x20383030, 0x323A3132, ++0x34333A38, 0x00000000, 0x00000D0A, 0x00000043, ++0x42707372, 0x3D206675, 0x554E203D, 0x202C4C4C, ++0x6E49677A, 0x4E497274, 0x6D754E51, 0x0000003D, ++0x61766E49, 0x2064696C, 0x72657375, 0x20726F20, ++0x2079656B, 0x00214449, 0x52504545, 0x57204D4F, ++0x65746972, 0x6461202C, 0x003D7264, 0x6C617620, ++0x0000003D, 0x00000A0D, 0x435F4D5A, 0x465F444D, ++0x4C445F57, 0x494E495F, 0x00000054, 0x6E6B6E55, ++0x206E776F, 0x6D6D6F63, 0x3D646E61, 0x00000000, ++0x203A3051, 0x00000020, 0x203A3151, 0x00000020, ++0x203A3251, 0x00000020, 0x203A3351, 0x00000020, ++0x203A3451, 0x00000020, 0x2B434741, 0x73696F4E, ++0x61432065, 0x7262696C, 0x6F697461, 0x6166206E, ++0x6F206C69, 0x6974206E, 0x0D0A656D, 0x00000000, ++0x00000072, 0x00205220, 0x00000D0A, 0x62735576, ++0x7473725F, 0x00000A0D, 0x62735576, 0x7375735F, ++0x646E6570, 0x00000A0D, 0x62735576, 0x7365725F, ++0x000A0D6D, 0x00000044, 0x44387570, 0x72637365, ++0x6F747069, 0x3D584572, 0x00000000, 0x00000047, ++0x00000042, 0x72746E49, 0x6D652051, 0x2C797470, ++0x49677A20, 0x4972746E, 0x754E514E, 0x00003D6D, ++0x654C7245, 0x0000006E, 0x00000049, 0x20746F4E, ++0x756F6E65, 0x49206867, 0x4220514E, 0x0A0D6675, ++0x00000000, 0x000000FF, 0x00020001, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00020003, 0x01090108, ++0x0002010A, 0x02000003, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x000000FF, 0x00020001, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00020003, 0x01090108, ++0x0002010A, 0x00030003, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00FF010F, 0x01090108, ++0x010B010A, 0x0200010F, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00FF010F, 0x01090108, ++0x010B010A, 0x010F010F, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00205220, 0x00000046, 0x00000059, ++0x73204142, 0x003D7165, 0x49544120, 0x0000204D, ++0x00000000, 0x00000000, 0x002E0209, 0x80000101, ++0x000409FA, 0x00FF0400, 0x05070000, 0x02000201, ++0x82050700, 0x00020002, 0x03830507, 0x07010040, ++0x40030405, 0x02090100, 0x0101002E, 0x09FA8000, ++0x04000004, 0x000000FF, 0x02010507, 0x07000040, ++0x40028205, 0x05070000, 0x00400383, 0x04050701, ++0x00004002, 0x00000000, 0x00000000, 0x07090000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++}; ++ ++const u32_t zcFwImageSize=15936; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu.c.drv_ba_resend +@@ -0,0 +1,742 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE297FFC, 0xE114D729, ++0x1E13D429, 0x1E4C470B, 0x0009B018, 0xA0039545, ++0x3652E600, 0x76018D04, 0xC84060E2, 0x2F028DF9, ++0xDE23D422, 0x00094E0B, 0x4E0BD422, 0xD4220009, ++0x00094E0B, 0x4F267F04, 0x6EF6A024, 0xD11F4F22, ++0x0009410B, 0x440BD41E, 0xD51E0009, 0x0009450B, ++0xE1FFD71D, 0xD21D611D, 0x50292712, 0xCB01D41C, ++0xE501E1FF, 0x22121209, 0x24521211, 0xD61AD519, ++0xE2009714, 0xD4192572, 0xD6192620, 0x4F262422, ++0x2622000B, 0xDD18DC17, 0x4C0BDE18, 0x4D0B0009, ++0x4E0B0009, 0xAFF80009, 0x27100009, 0x00000640, ++0x001C001C, 0x00200BC4, 0x0000B38E, 0x002029F8, ++0x00200F72, 0x00202A04, 0x00202A1C, 0x00200F20, ++0x00201056, 0x00200C1C, 0x001C3510, 0x001C3624, ++0x001E212C, 0x00202994, 0x00202530, 0x0020299C, ++0x002029A8, 0x00200E50, 0x002023E6, 0x00201920, ++0x2FC62F96, 0x2FE62FD6, 0x7F904F22, 0xE020DE8D, ++0xD48D61E0, 0x61E30F14, 0x62107101, 0xE024D78B, ++0x0F24470B, 0x450BD58A, 0x20080009, 0x8F116D03, ++0xDD881F0A, 0x67D0D488, 0x410BD188, 0xD288657C, ++0x6920DD88, 0x66C36C9C, 0x46084608, 0x460836C8, ++0x1FDA3D6C, 0x04FCE024, 0x66E2E580, 0x655C604C, ++0x8F163050, 0xE0202D62, 0xE50001FC, 0xDE7E641C, ++0x3243625D, 0xA32C8B01, 0x655D0009, 0x36EC6653, ++0xE02C6760, 0x69530F74, 0x39DC607E, 0xAFEF8094, ++0x20087501, 0xE0208B14, 0xE50001FC, 0xA00ADE72, ++0x655D641C, 0x39EC6953, 0x67536C92, 0x37DC62C2, ++0x75041721, 0x625D1F2C, 0x8BF23243, 0x2D10A309, ++0x8B178801, 0x01FCE020, 0x2D70E700, 0x1FD76D1C, ++0x627DDE65, 0x8B0132D3, 0x0009A2FB, 0x65E3677D, ++0x75046673, 0x36EC6C73, 0x64623C5C, 0x770869C2, ++0x2492AFEF, 0x8B188804, 0x01FCE020, 0x2D40E400, ++0xDE59671C, 0x3273624D, 0xA2E28B01, 0x644D0009, ++0x6CE36D43, 0x65D23DEC, 0x61437C04, 0x621231CC, ++0x74086952, 0xAFED2929, 0x88052592, 0xE0208B18, ++0xE40001FC, 0x671C2D40, 0x624DDE4B, 0x8B013273, ++0x0009A2C7, 0x6943644D, 0x39EC61E3, 0x71046592, ++0x3C1C6C43, 0x6D5262C2, 0x2D2B7408, 0x25D2AFED, ++0x8B1B8831, 0xD942D241, 0x72046422, 0x72046622, ++0x72046722, 0x72E86C22, 0x1F2E1F4D, 0x72046422, ++0x72046E22, 0x652229E0, 0x2950D93A, 0xDE3A2FC6, ++0x55FE4E0B, 0xE2007F04, 0x2D20A29B, 0x8B1D8830, ++0xDE33D232, 0x72046522, 0x72046122, 0x72046722, ++0x72E86922, 0x72046422, 0x72046C22, 0x6E222EC0, ++0x1F9FD62C, 0x7FFC26E0, 0x09FEE040, 0x2F92DC2B, ++0x66134C0B, 0xE2007F04, 0x2D20A27B, 0x89018828, ++0x0009A109, 0xE143DE20, 0xE04062E1, 0x3617662D, ++0x0FE68F03, 0x660302FE, 0x36172201, 0xA0F38B01, ++0xE0400009, 0xE50104FE, 0x30568541, 0xA0EB8B01, ++0xE0400009, 0x09FEE701, 0xB2612D70, 0xE0406491, ++0xE1430CFE, 0xE06862C1, 0x3517652D, 0x0F568D68, ++0x3563E640, 0xE6008B24, 0x0F65E048, 0xA02EE11A, ++0x000072C0, 0x00117800, 0x00202A20, 0x00200F72, ++0x00201FDC, 0x002029B0, 0x00202A24, 0x00200FBC, ++0x002029AF, 0x002025D4, 0x00117804, 0x00117810, ++0x002029AC, 0x002029AD, 0x00200948, 0x00200994, ++0x41216153, 0x41214121, 0x41214121, 0x45214521, ++0x60534521, 0x6603C903, 0x0F65E048, 0xE0077118, ++0xE0442209, 0x641D0F25, 0x65F3E04C, 0x0F46B291, ++0x0EFDE048, 0x0DFDE044, 0x61DD67ED, 0x41084708, ++0x0F16E050, 0xDD946073, 0x4D0B06FE, 0x6E07E00F, ++0x607326E9, 0xE0400F66, 0x65F30CFE, 0x690D85C2, ++0x01FEE050, 0x60934D0B, 0x6073260B, 0xE04C0F66, ++0x04FEB256, 0x07FEE040, 0x6271E068, 0x0F56652D, ++0x3563E640, 0xED008954, 0x0FD5E064, 0xC9036023, ++0x40004008, 0x61036903, 0x0F96E054, 0xDE7EE058, ++0x0FF6ECFF, 0xE06C6CCC, 0x60C30FE6, 0x62534E0B, ++0x42214221, 0x42214221, 0x42006723, 0x6107327C, ++0x4200E05C, 0x0F164521, 0x4521E040, 0x60530CFE, ++0x4008C903, 0x7C0630FC, 0x6E031FC6, 0x1FD56D2D, ++0x1F04A01E, 0x0FD6E060, 0x05FEE058, 0x64D3B231, ++0x62E2E05C, 0xE05409FE, 0x2E222299, 0x64D361C4, ++0x01FE661C, 0x07FEE06C, 0x6063470B, 0xE058220B, ++0xB20505FE, 0xE0642E22, 0x7D0102FD, 0x0F257201, ++0x02FDE064, 0x3262E606, 0xE0408BDC, 0x626106FE, ++0x05FEE040, 0x85514200, 0x302C750C, 0x6103701B, ++0x64F3E600, 0xE704A004, 0x76016256, 0x74042422, ++0x3273626D, 0x65F38BF8, 0x641DB1E2, 0x06FEE040, ++0x6461B19E, 0x0009A175, 0xD74DD44C, 0x470BE201, ++0xA16E2D20, 0x88290009, 0xDE4A8B07, 0x2D20E200, ++0xB16D66E2, 0xA164646D, 0xE2810009, 0x3020622C, ++0xA0A78B01, 0xE0240009, 0x626C06FC, 0x666CE682, ++0x8B213260, 0xE42452FA, 0xD43F2240, 0x12615647, ++0x12625648, 0x12635649, 0x1264564A, 0x1265564B, ++0x1266564C, 0x1267564D, 0x1268564E, 0x1269564F, ++0x1427E200, 0x14291428, 0x142B142A, 0x142D142C, ++0x142F142E, 0x1F6CA135, 0x666CE683, 0x8B073260, ++0xE60052FA, 0xD22B2260, 0x6222D62C, 0x2622A129, ++0x666CE690, 0x8B183260, 0xE60052FA, 0xD2282260, ++0x6022E605, 0x2202CB20, 0x2262D226, 0x2262E600, ++0x460BD625, 0xD2250009, 0x0009420B, 0xE601D224, ++0xD2242262, 0xA10C4618, 0xE6B02262, 0x3260666C, ++0xD5188B22, 0xD216D420, 0x75046D52, 0x6E52420B, ++0x420BD21E, 0xD41E64D3, 0x450BD511, 0xD21B0009, ++0x64E3420B, 0xD60ED41B, 0x0009460B, 0xE600E504, ++0x3253626D, 0xA0EC8B01, 0x666D0009, 0x326C62D3, ++0x22E07601, 0x4E19AFF4, 0xD214D413, 0xD4146542, ++0x0009420B, 0x0009A0DD, 0x0020248C, 0x00202A44, ++0x00200F72, 0x00117804, 0x00202538, 0x00202994, ++0x001C3500, 0x001D4004, 0x00201056, 0x00200C1C, ++0x001E212C, 0x001C3D30, 0x00202A5C, 0x00200FB4, ++0x00202A70, 0x00202A78, 0x00117800, 0x00200FBC, ++0x00202A7C, 0xD6AED4AD, 0x6262E040, 0x76046542, ++0x2452352C, 0x62626563, 0x75045641, 0x1461362C, ++0x62526653, 0x76085542, 0x1452352C, 0x55436262, ++0x352C76EC, 0x65631453, 0x56446262, 0x362C7510, ++0x66531464, 0x55456252, 0x352C7610, 0x65621455, ++0xD69C5246, 0x1426325C, 0x55476262, 0x352C7604, ++0x62621457, 0x76045548, 0x1458352C, 0x62626563, ++0x75045649, 0x1469362C, 0x564A6252, 0x362C7504, ++0x6653146A, 0x554B6252, 0x352C7604, 0x6262145B, ++0x7604554C, 0x145C352C, 0x62626563, 0x7504564D, ++0x146D362C, 0x62526653, 0x7604554E, 0x145E352C, ++0x524F6562, 0x325CD684, 0x6262142F, 0x7694054E, ++0x0456352C, 0x6263E044, 0x054E6662, 0x356C7244, ++0xE0480456, 0x054E6622, 0xD67C356C, 0x62620456, ++0x054EE054, 0x352C4229, 0x76040456, 0xE0586262, ++0x4229064E, 0x52FA362C, 0xE6380466, 0xE0442260, ++0xE048064E, 0x66421261, 0x56411262, 0x56421263, ++0x56451264, 0x56431265, 0x56461266, 0x064E1267, ++0x1268E040, 0xE050064E, 0x56441269, 0x064E126A, ++0x126BE04C, 0xE054064E, 0x064E126C, 0x126DE058, ++0xE044064E, 0xE200126E, 0xE0480426, 0x14212422, ++0x14251422, 0x14261423, 0xE0400426, 0xE0500426, ++0x04261424, 0x0426E04C, 0x0426E054, 0x0426E058, ++0x7F701F6C, 0x6EF64F26, 0x6CF66DF6, 0x69F6000B, ++0x614D4F22, 0x3123E240, 0xE21F8917, 0x89083127, ++0xD550D44F, 0x450BE001, 0x67076642, 0xA00C2679, ++0xE23F2462, 0x89083127, 0xD64AD749, 0xE00171E0, ++0x5571460B, 0x25296207, 0x4F261751, 0x0009000B, ++0x614D4F22, 0x3123E240, 0xE21F8915, 0x89073127, ++0xD240D43F, 0x420B6642, 0x260BE001, 0x2462A00B, ++0x3127E23F, 0xD73A8907, 0x5571D63A, 0x460B71E0, ++0x250BE001, 0x4F261751, 0x0009000B, 0x4618E640, ++0xD5354628, 0x22686252, 0x000B89FC, 0xE6800009, ++0x46284618, 0x6252D530, 0x89FC2268, 0x0009000B, ++0xE200A001, 0x32427201, 0x000B8BFC, 0xE6800009, ++0x46284618, 0x6252D529, 0x8BFC2268, 0x0009000B, ++0x4F222FE6, 0x6E537FFC, 0x2F42BFF1, 0xD62461E2, ++0x1615E280, 0x421854E1, 0x55E21646, 0x16574228, ++0x6EF257E3, 0x2E2B1678, 0x7F0426E2, 0xAFCE4F26, ++0x2FC66EF6, 0x2FE62FD6, 0xDD194F22, 0xBFD66C53, ++0xBFBB6E43, 0xBFD22DE2, 0x51D50009, 0x54D62C12, ++0x55D71C41, 0x56D81C52, 0x4F261C63, 0x6DF66EF6, ++0x6CF6000B, 0xE6006163, 0x4109A004, 0x76016256, ++0x74042422, 0x8BF93612, 0x0009000B, 0x00202538, ++0x001C36A0, 0x001C3CA0, 0x001C36F4, 0x001C3B88, ++0x001C3704, 0x0020248C, 0x001C373C, 0x001C3700, ++0x001C370C, 0x0009A109, 0x2FD62FC6, 0x4F222FE6, ++0x6E636D73, 0x6C53B016, 0x64C357F4, 0xB02965E3, ++0xB03D66D3, 0xB06D0009, 0xB0710009, 0xB0750009, ++0xB08A0009, 0xB08D0009, 0x4F260009, 0x6DF66EF6, ++0x6CF6A0B4, 0x3412D190, 0xD6900529, 0x2650D790, ++0x2742000B, 0x2FD62FC6, 0x4F222FE6, 0x6E636D73, ++0x6C53BFF0, 0x64C357F4, 0x66D365E3, 0x6EF64F26, ++0x6CF66DF6, 0xD1872FE6, 0x66126E63, 0x92BC4418, ++0x44084528, 0x45002629, 0x265B4408, 0x264B4400, ++0x21624708, 0xD1804708, 0x217227EB, 0x6EF6000B, ++0x4F222FE6, 0xE101DE7D, 0xBFABE40A, 0x62E32E12, ++0xE100726C, 0x2212E401, 0x22122212, 0x22122212, ++0x22422212, 0xE503E730, 0x2212E40A, 0x22122212, ++0x22122212, 0x22122212, 0x22122212, 0x22122212, ++0x22722212, 0x22122252, 0x22122212, 0x22122212, ++0x22122212, 0xBF852212, 0xE600121A, 0x4F262E62, ++0x6EF6000B, 0xE101D266, 0x2212E441, 0x2242000B, ++0xD465D164, 0x2162E605, 0x2462000B, 0xD264D563, ++0x88016050, 0xD4638B07, 0x60409668, 0x8B098801, ++0xA0079665, 0xE6000009, 0x2262D45E, 0x88016040, ++0xE6048B00, 0xAF5DE40A, 0xD25B2262, 0xE40AE601, ++0x2262AF58, 0x2FC62FB6, 0x2FE62FD6, 0xDC574F22, ++0x60C2ED00, 0xCB01EB64, 0x60C22C02, 0xA008C901, ++0x3DB26E03, 0x60C28907, 0xC901E40A, 0x6E03BF42, ++0x2EE87D01, 0x3DB28BF5, 0xD44D8B03, 0x420BD24D, ++0xE40A0009, 0x6EF64F26, 0x6CF66DF6, 0x6BF6AF32, ++0x8F014411, 0x6043604B, 0x0009000B, 0x2FC62FB6, ++0x2FE62FD6, 0x7FFC4F22, 0xED00DC40, 0xEB6460C2, ++0x2C02CB02, 0x2F0260C2, 0xA009C902, 0x3DB36E03, ++0x60C28908, 0x2F02E40A, 0xBF13C902, 0x7D016E03, ++0x8BF42EE8, 0x8B0B3DB3, 0xD236D437, 0x4F267F04, ++0x6DF66EF6, 0x422B6CF6, 0x1FFF6BF6, 0x03C40340, ++0x4F267F04, 0x6DF66EF6, 0x000B6CF6, 0xD52F6BF6, ++0x60525651, 0x000B4628, 0x2FB6306C, 0x2FD62FC6, ++0x4F222FE6, 0x4F024F12, 0x6E43BFF1, 0xDC286B03, ++0xBFECDD28, 0x30B80009, 0x060A3C05, 0x46094609, ++0x3D654601, 0x4209020A, 0x42094209, 0x8BF032E2, ++0x4F164F06, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x4F222FE6, 0xE102DE1C, 0xE403E500, 0xBFD42E12, ++0xE6062E52, 0xE7004618, 0x2E62E403, 0x4F262E72, ++0x6EF6AFCB, 0x0009000B, 0x0025E720, 0x00202C3C, ++0x00202998, 0x001C5814, 0x001C59D0, 0x001C5830, ++0x001C6268, 0x001C59A4, 0x001C639C, 0x002029AD, ++0x001C5804, 0x002029AC, 0x001C581C, 0x001C5860, ++0x00202A90, 0x00200F72, 0x00202AA8, 0x001C1040, ++0xCCCCCCCD, 0x10624DD3, 0x001D4004, 0x2F962F86, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0xE4007FE0, ++0x4528E510, 0x67436C43, 0xE108A00F, 0x6043644D, ++0x0F564008, 0xEE0060C3, 0x815125C1, 0x81538152, ++0x157315E2, 0x751415E4, 0x624D7401, 0x8BED3213, ++0xDA7251F1, 0x1A1154F2, 0xD1712A12, 0x56F455F3, ++0x58F657F5, 0x21421141, 0x11521153, 0x11641165, ++0x11761177, 0x11881189, 0xD96A6DF2, 0xDB6A52F7, ++0x29D219D1, 0x2B221B21, 0xD868EB45, 0xE9B8EA50, ++0x4A084B08, 0xA020699C, 0x6EEDEE00, 0x61E36DE3, ++0x41084D08, 0x31EC3DEC, 0x41084D08, 0x60C33D8C, ++0xD75F4108, 0x81D12DC1, 0x410860A3, 0x60C381D2, ++0xE200317C, 0x81D33492, 0x1D131DD2, 0x8D01D456, ++0xD4521D24, 0x65D3B03C, 0x64ED7E01, 0x8BDC34B2, ++0xDB54D14E, 0xD24F6512, 0x1B514529, 0xD14C6412, ++0x2B72674D, 0xD6506722, 0x1B734729, 0x2FD26922, ++0x1B82689D, 0x26926912, 0x16A25A12, 0xDA465B14, ++0x5C1616B4, 0x5D1816C6, 0x6EA216D8, 0x7F2016EA, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x664268F6, 0xC8036061, 0xE5008D04, 0xC9036061, ++0x8B038802, 0x65635262, 0x24125124, 0x6053000B, ++0x2FE62FD6, 0x7FEC4F22, 0x62536E53, 0x6D43E550, ++0x4508E400, 0xE101A001, 0x60435224, 0x81212211, ++0x60538123, 0x56E28122, 0x8BF53620, 0x16E4D22F, ++0xE61464F3, 0x65E3420B, 0xE4FC65E1, 0x2E512549, ++0x65F361F1, 0x2F112149, 0xD12854D1, 0xE614410B, ++0x607157D1, 0x2701CB01, 0x7F141DE1, 0x6EF64F26, ++0x6DF6000B, 0x2FE62FD6, 0x7FEC4F22, 0x66536E53, ++0x6D43E5FC, 0x20596061, 0x2601CB01, 0x326052E2, ++0x12E48B06, 0x31E051E2, 0x52D18B04, 0x1E22A002, ++0x5664AFF0, 0x64F3D215, 0x420BE614, 0x67E165E3, ++0x2719E1FC, 0x67F12E71, 0x271954D1, 0x65F3D10F, ++0x410BE614, 0x52D12F71, 0xCB016021, 0x1DE12201, ++0x4F267F14, 0x000B6EF6, 0x00006DF6, 0x0020259C, ++0x002025A4, 0x00202594, 0x002025CC, 0x001000A0, ++0x00101640, 0x001E2108, 0x001C3D00, 0x00200904, ++0x2FC62FB6, 0x2FE62FD6, 0x7FFC4F22, 0x6022D225, ++0x8D35C803, 0xDE242F01, 0xDB25DC24, 0xED01A016, ++0xC9036061, 0x89158801, 0xD122D420, 0x0009410B, ++0x65035603, 0xC8208561, 0xE0508903, 0x720102BE, ++0xD21D0B26, 0x64E3420B, 0x21D2D11C, 0x66C252C1, ++0x8BE53620, 0xDD1AEE01, 0x4E18A00E, 0xC9036061, ++0x890D8801, 0xD713D416, 0x470BDB16, 0xD4160009, ++0x65034B0B, 0x21E2D111, 0x66D252D1, 0x8BED3620, ++0xC80460F1, 0xD2118907, 0x4F267F04, 0x6DF66EF6, ++0x422B6CF6, 0x7F046BF6, 0x6EF64F26, 0x6CF66DF6, ++0x6BF6000B, 0x001E2100, 0x002025A4, 0x0020259C, ++0x00202538, 0x00200D42, 0x00200DC4, 0x001C3D30, ++0x00202594, 0x00200D60, 0x002025CC, 0x00200100, ++0xE601D203, 0x1265D503, 0x000B2252, 0x00001266, ++0x001C1010, 0x0000C34F, 0xD62A7FFC, 0x2642644C, ++0xC8205066, 0x2F028DFC, 0x7F04000B, 0x2FD62FC6, ++0x4F222FE6, 0x6D436C53, 0xEE00A004, 0x7E0164D4, ++0x644CBFEA, 0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, ++0xA0016CF6, 0x76016643, 0x22286260, 0x36488BFB, ++0x6563AFE4, 0x62532FE6, 0x67537507, 0xEE0AE108, ++0xC90F6043, 0x30E24409, 0x44096503, 0xE6378D01, ++0x365CE630, 0x27604110, 0x77FF8FF2, 0x8028E000, ++0x6EF6000B, 0xE000000B, 0xE000000B, 0x4F222FE6, ++0x62537FEC, 0x65F36E43, 0x6423BFDC, 0x64E3BFD1, ++0x64F3BFCF, 0xBFCCD404, 0x7F140009, 0x000B4F26, ++0x00006EF6, 0x001C0004, 0x00202AC4, 0xE110D5A1, ++0xE6406050, 0x2500C9FD, 0xE0FF75E9, 0x80516453, ++0x80538052, 0x80568055, 0x251075EF, 0xE1EF6250, ++0x2219E001, 0xE7202520, 0x24608052, 0x2570000B, ++0xE4FDD595, 0xE7026152, 0x25122149, 0x74016052, ++0x2502CB01, 0xD1916652, 0x25622649, 0x92C46012, ++0x2102CB08, 0xC9CF6012, 0x60122102, 0x2102CB03, ++0x000B1172, 0x4F221123, 0xD78AD589, 0xD48BD28A, ++0xE600E100, 0x27112511, 0xBFBF2210, 0xAFD72461, ++0x664C4F26, 0x4600D286, 0x6060362C, 0x000BCB10, ++0x654C2600, 0x4500D282, 0x6650352C, 0x2619E1EF, ++0x2560000B, 0xD27F664C, 0x362C4600, 0xCB106060, ++0x2600000B, 0xD27B654C, 0x352C4500, 0xE1EF6650, ++0x000B2619, 0x664C2560, 0x4600D275, 0x6060362C, ++0x000BCB08, 0x654C2600, 0x4500D271, 0x6650352C, ++0x2619E1F7, 0x2560000B, 0xD26E664C, 0x362C4600, ++0xCB086060, 0x2600000B, 0xD26A654C, 0x352C4500, ++0xE1F76650, 0x000B2619, 0x624C2560, 0x4200D664, ++0x6020326C, 0x4021C908, 0x40214021, 0x600C000B, ++0xD660624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0x644C600C, 0x74FFD15B, 0x6240341C, ++0x602C000B, 0x644CD159, 0x6240341C, 0x602C000B, ++0x4F222FE6, 0xE60A655C, 0x8D153567, 0xBFEA6E43, ++0x640C6453, 0x880160EC, 0xE00F8B02, 0x2409A002, ++0x44094409, 0xE60A624C, 0x89053263, 0x644CBFE2, ++0x6023620C, 0x8B00C880, 0x6023E200, 0x000B4F26, ++0x4F226EF6, 0x6062D646, 0x8B038801, 0x0009B241, ++0x0009A003, 0xE640D243, 0xD6432260, 0x4F26E200, ++0x2622000B, 0xD63E4F22, 0x88026062, 0xB28B8B01, ++0xD63D0009, 0x4F26E200, 0x2622000B, 0xD439D538, ++0xE701E100, 0x000B2512, 0x0FFF2470, 0xE604D235, ++0x2260000B, 0xD4354F22, 0x410BD135, 0xD5250009, ++0x6650E1FD, 0x2619D233, 0x2560E700, 0x000B4F26, ++0x4F222270, 0xD12ED430, 0x0009410B, 0xE7FBD51D, ++0x26796650, 0x000B4F26, 0x4F222560, 0xD128D42B, ++0x0009410B, 0xE7F7D517, 0x26796650, 0x000B4F26, ++0xD5142560, 0x62509425, 0x000B2249, 0xD5112520, ++0x6250E4BF, 0x000B2249, 0x4F222520, 0x8522D220, ++0x2008600D, 0x88018911, 0x8803893C, 0x8805893E, ++0x88068940, 0x88088946, 0x8809894C, 0x880A8952, ++0x880B8958, 0xA065895E, 0xB0670009, 0xA0620009, ++0xFF7F600C, 0x001E1028, 0x001E2148, 0x001E1108, ++0x002029DC, 0x002029DE, 0x002029E9, 0x002029C0, ++0x001E103F, 0x001E105F, 0x001E1030, 0x001E1090, ++0x002029E4, 0x001E100B, 0x002029E0, 0x00202AC8, ++0x00200F72, 0x002029E8, 0x00202AD4, 0x00202AE4, ++0x002029B4, 0x0009B04C, 0x600CA035, 0x0009B056, ++0x600CA031, 0x6260D67C, 0x8B2B2228, 0x0009B062, ++0x600CA029, 0x6260D678, 0x8B232228, 0x0009B06A, ++0x600CA021, 0x6260D674, 0x8B1B2228, 0x0009B0B4, ++0x600CA019, 0x6260D670, 0x8B132228, 0x0009B0BA, ++0x600CA011, 0x6260D66C, 0x8B0B2228, 0x0009B11A, ++0x600CA009, 0x6260D668, 0x8B032228, 0x0009B132, ++0x600CA001, 0x4F26E000, 0x0009000B, 0xD264D163, ++0xD5648412, 0x4000C90F, 0xD763012D, 0x611CE403, ++0xD662E20F, 0x27122540, 0xE0012520, 0x2602000B, ++0xE601D25A, 0x30668523, 0xE0008D06, 0xE000D258, ++0x8122D65A, 0x2602E001, 0x0009000B, 0x8523D253, ++0x2008600D, 0x88018905, 0xD6558B0A, 0xCB016060, ++0xD6522600, 0xE101D44E, 0x2612E001, 0x8142000B, ++0xE000000B, 0xE501D149, 0x45188513, 0x3453640D, ++0x8D056603, 0xD24BE000, 0xE001D548, 0x25022260, ++0x0009000B, 0xD1414F22, 0x650D8513, 0x44196453, ++0x672E6249, 0x602C227D, 0x89098801, 0x890C8802, ++0x89108803, 0x89268806, 0x89298807, 0x0009A038, ++0xD63ED53D, 0xA027E212, 0x625C2652, 0x8B2F2228, ++0xA01ED63B, 0x605C6262, 0x89052008, 0x89088810, ++0x890B8820, 0x0009A024, 0xD634D436, 0xA013E204, ++0xD7352642, 0xE20CD631, 0x2672A00E, 0xD62FD533, ++0xA009E218, 0xD4322652, 0xE20AD62C, 0x2642A004, ++0xD62AD230, 0xE22E2622, 0xD42F8515, 0x3277670D, ++0x8F012421, 0x24516503, 0x0009B0DB, 0xE001A001, ++0x4F26E000, 0x0009000B, 0xE101D61A, 0x2610D427, ++0xD7196541, 0x655DD119, 0xE001E20F, 0x26202752, ++0x2102000B, 0x4F222FE6, 0x8523D210, 0x2448640C, ++0xD61E8B08, 0xE200D512, 0x84512621, 0x20499412, ++0x8051A050, 0x60E0DE0E, 0x8D35C840, 0x3427E201, ++0xD116894C, 0x420BD216, 0xD5162141, 0xCB046052, ++0x2502A035, 0x0000FF7F, 0x002029E9, 0x002029B4, ++0x002029C0, 0x001E1100, 0x001E100C, 0x002029E0, ++0x001E1000, 0x001E1001, 0x00202C40, 0x002029C8, ++0x002029D0, 0x00202CAE, 0x00202CB2, 0x00202CBE, ++0x00202CD6, 0x00202CE0, 0x002029CC, 0x002029DA, ++0x00201DB6, 0x001E1108, 0x89173427, 0xD794D293, ++0x2241470B, 0xE5FBD693, 0x21596162, 0x84E12612, ++0xB0FFCB80, 0x60E080E1, 0xCB04D68F, 0x60602E00, ++0x2600C93F, 0xE001D68D, 0x2602A001, 0x4F26E000, ++0x6EF6000B, 0x6060D68A, 0x8919C880, 0x6021D283, ++0x8B158801, 0xE501D287, 0x30568524, 0xD1868910, ++0xD486E203, 0x65412120, 0x655DE00B, 0xD5840656, ++0xE702E40F, 0x25712140, 0xE001D77C, 0x2702000B, ++0xE000000B, 0x4F222FE6, 0x84E1DE7E, 0x8934C880, ++0x8554D578, 0x8F302008, 0xD77B6103, 0x66728553, ++0x650C6403, 0x620C8566, 0x8B263520, 0xD773D677, ++0x644C651C, 0x27412651, 0xC84060E0, 0xD2748907, ++0x0009420B, 0x6062D667, 0xA008CB04, 0xD1642602, ++0x0009410B, 0xE5FBD663, 0x24596462, 0xB0A12642, ++0xD5620009, 0x2522E201, 0xD75F60E0, 0x2E00CB04, ++0xC93F6070, 0xA0012700, 0xE0006023, 0x000B4F26, ++0x2FA66EF6, 0x2FC62FB6, 0x2FE62FD6, 0xE240DA5C, ++0xDC5966A1, 0x3123616D, 0x62638900, 0x6ED36D2C, ++0x4E2136D8, 0x4E212A61, 0xDB5BD45A, 0xE700A00F, ++0x770166B2, 0x71026163, 0x65612B12, 0x71026613, ++0x62612B12, 0x622D655D, 0x325C4228, 0x627C2422, ++0x8BED32E3, 0xC90360D3, 0x8B108803, 0xED076EB2, ++0x710261E3, 0x67132B12, 0x62E17102, 0x65712B12, ++0x655D622D, 0x352C4528, 0xA00C2CD0, 0x88022452, ++0xA0038B01, 0x8801E203, 0xE2018B05, 0x66B22C20, ++0x677D6761, 0xEB0F2472, 0x6DA12CB0, 0x8B052DD8, ++0xD432D23E, 0xE101EE00, 0x241222E2, 0x6DF66EF6, ++0x6BF66CF6, 0x6AF6000B, 0x2FE62FD6, 0xE240DD30, ++0x616D66D1, 0x89003123, 0x672C6263, 0xDE323678, ++0x2D617703, 0xD62F4721, 0x472164E2, 0xE100A00E, ++0x71016562, 0x24506253, 0x42197401, 0x74012420, ++0x24504529, 0x45197401, 0x74012450, 0x3273621C, ++0x42008BEE, 0x64D166E2, 0x362C4200, 0x8F062448, ++0xDD222E62, 0xE500DE15, 0x2D52E701, 0x6EF62E72, ++0x6DF6000B, 0x2FE62FD6, 0xEE014F22, 0xED0AA005, ++0x64E3BC97, 0x64E3BC9D, 0x62EC7E01, 0x8BF732D7, ++0xEE01A005, 0x64E3BC9E, 0x64E3BCA4, 0x62EC7E01, ++0x8BF732D7, 0x6EF64F26, 0x6DF6000B, 0x002029DA, ++0x00201EC2, 0x001E1108, 0x001E1015, 0x002029E0, ++0x001E1001, 0x002029B4, 0x001E1100, 0x002029DE, ++0x002029CC, 0x001E1000, 0x002029D0, 0x002029DC, ++0x00201DB6, 0x001E100C, 0x002029C8, 0x002029E4, ++0x2FE62FD6, 0x7FFC4F22, 0x6060D64C, 0x89488801, ++0xE101D44B, 0xD74B8548, 0x650D2610, 0x45196070, ++0x6659DD49, 0x61D3626E, 0xC840262D, 0x74027102, ++0x8D1AD746, 0xD246666C, 0xE501DE46, 0xA0042E22, ++0x6245EE04, 0x21217501, 0x625C7102, 0x8BF832E3, ++0x81D46063, 0xD540E601, 0x626CE417, 0x891E3243, ++0x76016255, 0xAFF82721, 0xD23C7702, 0xE501DE39, ++0xA0042E22, 0x6245EE04, 0x21217501, 0x625C7102, ++0x8BF832E3, 0x81D46063, 0xD535E601, 0xE417A004, ++0x76016255, 0x77022721, 0x3243626C, 0x924B8BF8, ++0xD4302D21, 0x6142D730, 0x65F22F12, 0x60536DF2, ++0x2700C980, 0xC9606053, 0x80716103, 0x6EF26053, ++0xC90365F2, 0x45294D19, 0x60DC8072, 0x81724519, ++0x605C4E29, 0x401862EC, 0x8173302C, 0x21186D42, ++0x6EF22FD2, 0x66F262F2, 0x46294219, 0x66F2656C, ++0x64EC602C, 0x46294018, 0x4619304C, 0x606C8174, ++0x305C4018, 0x81758F07, 0x0009BCBF, 0x2228620C, ++0xA00A8908, 0x60130009, 0x8B038840, 0x0009B00A, ++0x0009A003, 0xE202D611, 0x7F042622, 0x6EF64F26, ++0x6DF6000B, 0x0009000B, 0x0000060A, 0x002029E8, ++0x00202C40, 0x001E1000, 0x00202CD6, 0x00202CE2, ++0x00202C52, 0x002029D0, 0x00202C82, 0x00202C80, ++0x00202C54, 0x001E100C, 0x002029B4, 0x002029E0, ++0x4F222FE6, 0xDE907FFC, 0x200884E9, 0x2F008D06, ++0xD68FD48E, 0x0009460B, 0x64F0B146, 0x6620D28D, ++0x89022668, 0xC9BF60E0, 0x7F042E00, 0x000B4F26, ++0x000B6EF6, 0x2FE60009, 0xDE874F22, 0x60E0D687, ++0xCBC0D487, 0x62602E00, 0xC803602C, 0x40218904, ++0x70014021, 0x6603A002, 0x66034009, 0xD681616D, ++0xE500A004, 0x75016262, 0x74042422, 0x3213625D, ++0xD27D8BF8, 0x0009420B, 0xC9BF84E2, 0x4F2680E2, ++0x6EF6000B, 0x2FD62FC6, 0x4F222FE6, 0xDC727FFC, ++0x84C2D276, 0xCB40DD76, 0x80C2420B, 0x8D042008, ++0x62E06E03, 0xA006642C, 0xD66A7404, 0x6160D471, ++0x470BD771, 0x644D651C, 0x45216543, 0xA0044521, ++0x62E6E600, 0x2F227601, 0x626D2D22, 0x8BF83253, ++0xC9036043, 0x89122008, 0x89058803, 0x89068802, ++0x89078801, 0x0009A008, 0xA005E007, 0xE00380D8, ++0x80D8A002, 0x80D8E001, 0x2F2262E2, 0xE00F2D22, ++0x80D8D65E, 0xCB086060, 0x60C02600, 0x2C00C93F, ++0x4F267F04, 0x6DF66EF6, 0x6CF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xD2564F22, 0x6E436D73, 0x420B6B53, ++0x20086C63, 0x64038F08, 0xD245D452, 0x6EF64F26, ++0x6CF66DF6, 0x6BF6422B, 0x24E060B3, 0x60C38041, ++0xA0078141, 0x655DE500, 0x00DC6053, 0x324C6253, ++0x80247501, 0x6EEC625D, 0x8BF432E3, 0x6060D636, ++0x2600C9BF, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x7FC44F22, 0x720262F3, 0x22512F41, 0x45297202, ++0x60632251, 0xE5C4E682, 0x67F38121, 0x655C666C, ++0xE408BFBC, 0x4F267F3C, 0x0009000B, 0xD237D136, ++0xE4056012, 0xE500CB20, 0x22422102, 0x2252000B, ++0xD534D133, 0xE400D734, 0x2142E20F, 0x17411154, ++0xD5322722, 0x9635D732, 0x15412572, 0x96321562, ++0xE6011565, 0xD52F1165, 0x666CE6F8, 0x25422542, ++0x25422542, 0x25422542, 0x25622542, 0x7601E727, ++0x67632572, 0x25627797, 0xE7042572, 0x2572E248, ++0xE2192522, 0xE2702522, 0x25422542, 0x25422542, ++0x25222542, 0x2522E20C, 0x25422542, 0x25422542, ++0x25422542, 0x25422542, 0x000B154A, 0xE2081145, ++0x0009422B, 0x51630601, 0x001E1017, 0x00202AF0, ++0x00200F72, 0x002029B0, 0x001E1015, 0x001E10BF, ++0x00117800, 0x001E10FC, 0x00200100, 0x0020201A, ++0x001E10F8, 0x00202AF4, 0x00200FBC, 0x001E10AE, ++0x00201FDC, 0x00202B10, 0x001C3500, 0x001D4004, ++0x001C581C, 0xA000A000, 0x001D0100, 0x001D4000, ++0x00040021, 0x001C589C, 0x2FE62FD6, 0x7FFC4F22, ++0xC8206043, 0x6E438D02, 0x0009BEBB, 0xC81060E3, ++0xBEB88901, 0x60E30009, 0x8901C840, 0x0009BEDA, ++0xC80160E3, 0xDD378936, 0xC80260D0, 0x2F008D03, ++0x460BD635, 0x60F00009, 0x8902C804, 0x460BD633, ++0x62F00009, 0xC8806023, 0x60D08902, 0x2D00C97F, ++0xC8016023, 0xD62E8904, 0x0009460B, 0x0009A005, ++0x8902C808, 0x460BD62B, 0x60F00009, 0x8902C810, ++0x420BD229, 0xD5290009, 0x88026052, 0xD2288B03, ++0xA005E604, 0x88012260, 0xD2258B02, 0x2260E601, ++0x2522E200, 0xC88060E3, 0xD622892E, 0x60E36E60, ++0x8902C880, 0x420BD220, 0x60E30009, 0x8902C840, ++0x420BD21E, 0x60E30009, 0x8902C802, 0x420BD21C, ++0x60E30009, 0x890EC804, 0x410BD11A, 0xBF150009, ++0xBF1D0009, 0xD5180009, 0x6050D418, 0xC908D718, ++0xBF542500, 0x60E32472, 0x8905C808, 0x7F04D215, ++0x6EF64F26, 0x6DF6422B, 0x4F267F04, 0x000B6EF6, ++0x00006DF6, 0x001E1021, 0x00201182, 0x002011A4, ++0x002017B0, 0x002011BC, 0x002011CC, 0x002029E0, ++0x001E100B, 0x001E1028, 0x00201222, 0x0020122E, ++0x002011D4, 0x002011F2, 0x001E1000, 0x0010F100, ++0x12345678, 0x0020120A, 0xD6A8644C, 0x346C74FF, ++0x2450000B, 0x644CD6A6, 0x000B346C, 0xD6A52450, ++0x346C644C, 0x2450000B, 0x616D625C, 0x41194208, ++0x60194208, 0x644C4200, 0x324C670E, 0x207DD19E, ++0xC90F4200, 0x000B321C, 0x67632200, 0x4208625C, ++0x42004208, 0x324C644C, 0x4200D198, 0x000B321C, ++0x2FE62270, 0x614C4F12, 0x4100D493, 0x6710314C, ++0x2729E29F, 0x65736E53, 0x4719676D, 0x672E6279, ++0x4221227D, 0x42214221, 0x7601662C, 0xE4014608, ++0x34E84608, 0x644C4600, 0x0E1A0467, 0x215025EB, ++0x000B4F16, 0x4F226EF6, 0xD2857FE8, 0x88016021, ++0xD2848B7B, 0x26686621, 0xD2838B77, 0x26686621, ++0xE50F8B73, 0xE401BFA0, 0xBFA3E501, 0xE586E400, ++0xE400655C, 0x2F50BFA3, 0xBFA0E401, 0xE602E506, ++0x60634618, 0x81F2E401, 0x6543BF9E, 0xE40185F2, ++0xBFAA6543, 0x85F26603, 0x6543E401, 0x6603BFB1, ++0xE40265F0, 0x6053756C, 0x80F8BF7E, 0xBF81E402, ++0x84F8E512, 0x7090E402, 0x6503BF81, 0x4618E602, ++0x81F66063, 0xBF7FE402, 0x85F6E500, 0x6603E402, ++0xE500BF8B, 0xE40285F6, 0xBF926603, 0xE5FEE500, ++0xE010655C, 0xBF5FE403, 0xE5130F54, 0xE40EBF62, ++0x05FCE010, 0xBF62E40E, 0xE5007585, 0xBF63E403, ++0xE500E640, 0xBF70E403, 0xE500E640, 0xBF78E403, ++0xE5FFE640, 0xE014655C, 0xBF45E404, 0xE40F0F54, ++0xE504BF48, 0x05FCE014, 0xBF48E40F, 0xE5017584, ++0xBF49E640, 0xE501E404, 0xBF56E640, 0xE501E404, ++0xE404E640, 0xAF5C7F18, 0x7F184F26, 0x000B4F26, ++0x4F220009, 0xD2427FF0, 0x88016021, 0xD2418B71, ++0x26686621, 0xD2408B6D, 0x26686621, 0xE50F8B69, ++0xE401BF1A, 0xBF1DE501, 0xE586E400, 0xE400655C, ++0x2F50BF1D, 0xBF1AE401, 0xE401E506, 0xBF1B6543, ++0xE401E640, 0xBF286543, 0xE401E640, 0xBF306543, ++0x65F0E640, 0x756CE402, 0xBEFD6053, 0xE40280F4, ++0xE512BF00, 0xE40284F4, 0xBF007090, 0xE6406503, ++0xBF01E402, 0xE640E500, 0xBF0EE402, 0xE640E500, ++0xBF16E402, 0xE5FEE500, 0x6053655C, 0xBEE3E403, ++0xE51380F8, 0xE40EBEE6, 0xE40E84F8, 0xBEE67085, ++0xE5006503, 0xBEE7E640, 0xE500E403, 0xBEF4E640, ++0xE500E403, 0xBEFCE640, 0xE5FFE403, 0x6053655C, ++0xBEC9E404, 0xE40F80FC, 0xE504BECC, 0xE40F84FC, ++0xBECC7083, 0xE5016503, 0xBECDE640, 0xE501E404, ++0xBEDAE640, 0xE501E404, 0xE404E640, 0xAEE07F10, ++0x7F104F26, 0x000B4F26, 0x00000009, 0x001E1030, ++0x001E1080, 0x001E1090, 0x001E103F, 0x001E103E, ++0x002029DA, 0x002029DC, 0x002029DE, 0xD21DD11C, ++0x66206010, 0x676C7001, 0x3700C90F, 0xE5008D13, ++0x67106210, 0x7701622C, 0x64232170, 0xD6166010, ++0x44084408, 0x3428C90F, 0x62602100, 0x7201D513, ++0x44082620, 0x000B354C, 0xD10F6053, 0x25586510, ++0xE6008D13, 0xD60DD40B, 0x655C6540, 0x47086753, ++0x37584708, 0x47086540, 0x24507501, 0x367C6040, ++0x2400C90F, 0x72FF6210, 0x000B2120, 0x00006063, ++0x002029AF, 0x002029AE, 0x002029B0, 0x002025D4, ++0x7FFC4F22, 0xE680D19D, 0x666C6212, 0xD29C2F22, ++0x67F36563, 0x420B7542, 0x7F04E404, 0x000B4F26, ++0xE6800009, 0xD296666C, 0xE7006563, 0x422B7540, ++0xE6806473, 0xD292666C, 0xE7006563, 0x422B7543, ++0x2FB66473, 0x2FD62FC6, 0x4F222FE6, 0x4D18ED01, ++0xDB8DDC8C, 0x65C252C1, 0x89203520, 0xC9036051, ++0x891C8801, 0xD189DE87, 0x64E3410B, 0x85036503, ++0x670D66B2, 0x89073762, 0xD286D485, 0x0009420B, ++0xE701D185, 0x2172AFE6, 0xDE8464E3, 0x00094E0B, ++0xD484D683, 0x410BD184, 0xAFDB26D2, 0x4F260009, ++0x6DF66EF6, 0x000B6CF6, 0x4F226BF6, 0x85467FF4, ++0x2F01E681, 0x666C8547, 0x854881F1, 0x81F2D270, ++0x67F38542, 0x854381F3, 0x81F4E40C, 0x65636053, ++0x420B81F5, 0x7F0C7540, 0x000B4F26, 0x2F860009, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x7FF44F22, ++0xDC6EE200, 0x2F21A136, 0xDD6D6A13, 0xE0014A08, ++0x4D0BD96C, 0x3A9C4A00, 0x1F917930, 0x66C21F02, ++0x362052C1, 0xA1218B01, 0x60610009, 0x8801C903, ++0xA11B8B01, 0x85610009, 0x8977C801, 0x85D25D63, ++0xC9036603, 0x85D36403, 0x6053650D, 0x40214021, ++0x4500C93F, 0x322A6103, 0x6053252D, 0xC901E210, ++0xD9553123, 0x6E038D21, 0x4408D757, 0x44086570, ++0x44006213, 0x25584200, 0x342C8F0E, 0x6043D253, ++0x60E3072D, 0x4B196B7D, 0x658E68B9, 0x285D8801, ++0x6B7C8F0B, 0x6B13A009, 0x6043D24D, 0x61ED0E2D, ++0x68194119, 0x287D678E, 0xD14A6BEC, 0x22286212, ++0xEBFF8901, 0xEEFF6BBC, 0x6EEC65BD, 0x8B0F35E0, ++0x4D0BDD36, 0x540364C3, 0xBF76E502, 0xD4426D03, ++0x410BD136, 0xD74165D3, 0xD441EE01, 0x27E2A01D, ++0x26E9EEFC, 0x81D26063, 0x914E85D3, 0x81D32019, ++0x450885D2, 0x81D2208B, 0xE20885D3, 0x81D3205B, ++0x421885D4, 0x81D4202B, 0x854164C2, 0x814120E9, ++0xD43465C2, 0xCB016051, 0x490B2501, 0x60C20009, ++0x52F256F1, 0x2A02CB01, 0x2622AF79, 0x420BD21B, ++0x5E0364C3, 0x85E16D03, 0x6053650D, 0x897BC820, ++0x6210D129, 0x8B112228, 0xD72785EF, 0x4221620D, ++0x42214221, 0xE501D625, 0x27504221, 0xD725D924, ++0x2621D425, 0x2960E600, 0x24612762, 0x852162C2, ++0x8B43C802, 0xD912D71E, 0xE0016270, 0x612C490B, ++0x6692D91C, 0xA03E260B, 0x7E032962, 0x001C3D9C, ++0x00201A3C, 0x002025CC, 0x00202994, 0x00200D42, ++0x00202594, 0x00200DC4, 0x001E2130, 0x00200D60, ++0x001C3D30, 0x00202C28, 0x00200F72, 0x002025A4, ++0x0020248C, 0x001C3D00, 0x00202C3C, 0x00202B28, ++0x00202BA8, 0x002029A8, 0x0020259C, 0x001E212C, ++0x00202C2C, 0x00202C30, 0x00202D10, 0x002029EE, ++0x002029EC, 0x002029F0, 0x002029F4, 0xE04CD139, ++0x7201021E, 0xD9380126, 0x6290D438, 0x72016541, ++0x29207501, 0x85E12451, 0x4618E640, 0x891D2068, ++0xD934D733, 0x665D6171, 0x6592D733, 0x641D470B, ++0xE200DE32, 0x2E20A012, 0xE90885E4, 0x49186203, ++0x32902299, 0xE5018B04, 0x64E3BEB7, 0x0009A006, ++0x2598D92B, 0xE5008902, 0x64E3BEAF, 0xD22AD429, ++0x65D3420B, 0xEE01D729, 0x27E2AED9, 0x7C0862F1, ++0x2F217201, 0xEE0462F1, 0x31E7612D, 0xAEC38901, ++0x7F0C0009, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0x2FE668F6, 0xD21D4F22, 0x60E36E22, ++0x8D02C840, 0xBE3322E2, 0xE2400009, 0x2E284218, ++0xBE3E8901, 0x60E30009, 0x8905C810, 0xD216D415, ++0x0009420B, 0x0009BE3D, 0xC80560E3, 0xBE8E8901, ++0x60E30009, 0x8902C802, 0xAE3A4F26, 0x4F266EF6, ++0x6EF6000B, 0x00202538, 0x002029EC, 0x002029F4, ++0x002029EE, 0x002029F0, 0x00201AA0, 0x00202D10, ++0x00008000, 0x0020259C, 0x00200D60, 0x001E212C, ++0x001C3510, 0x00202C34, 0x00200F72, 0x080A0C0E, ++0x00020406, 0x1A1C1E20, 0x12141618, 0x2E303234, ++0x26282A2C, 0x3A3C3E40, 0x6C625648, 0x41112F26, ++0xE2208F18, 0x890B3123, 0x321CD204, 0xD1026220, ++0x412B312C, 0x00090009, 0x002024B6, 0x0020246C, ++0x000BE000, 0x400062F6, 0x40004000, 0x40004000, ++0x40004000, 0x62F6000B, 0x40004000, 0x40004000, ++0x40004000, 0x40184000, 0x62F6000B, 0x40004000, ++0x40004000, 0x40004000, 0x40284000, 0x62F6000B, ++0x40004000, 0x40184000, 0x000B4028, 0xC90F62F6, ++0x40054005, 0x40054005, 0x62F6000B, 0x4005C907, ++0x40054005, 0x62F6000B, 0x4005C903, 0x000B4005, ++0xC90162F6, 0x000B4005, 0x000062F6, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x544F0D0A, 0x46205355, ++0x00003A57, 0x2079614D, 0x32203033, 0x20373030, ++0x333A3231, 0x38313A37, 0x00000000, 0x00000D0A, ++0x00000043, 0x42707372, 0x3D206675, 0x554E203D, ++0x202C4C4C, 0x6E49677A, 0x4E497274, 0x6D754E51, ++0x0000003D, 0x61766E49, 0x2064696C, 0x72657375, ++0x20726F20, 0x2079656B, 0x00214449, 0x52504545, ++0x57204D4F, 0x65746972, 0x6461202C, 0x003D7264, ++0x6C617620, 0x0000003D, 0x00000A0D, 0x6E6B6E55, ++0x206E776F, 0x6D6D6F63, 0x3D646E61, 0x00000000, ++0x61437748, 0x7262696C, 0x6F697461, 0x6620206E, ++0x0A6C6961, 0x0000000D, 0x73696F4E, 0x61432065, ++0x7262696C, 0x6F697461, 0x6166206E, 0x21216C69, ++0x00000D0A, 0x00000D0A, 0x62735576, 0x7473725F, ++0x00000A0D, 0x62735576, 0x7375735F, 0x646E6570, ++0x00000A0D, 0x62735576, 0x7365725F, 0x000A0D6D, ++0x00000042, 0x72746E49, 0x6D652051, 0x2C797470, ++0x49677A20, 0x4972746E, 0x754E514E, 0x00003D6D, ++0x20746F4E, 0x756F6E65, 0x49206867, 0x4220514E, ++0x0A0D6675, 0x00000000, 0x000000FF, 0x00020001, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x010E010D, 0x00020003, ++0x01090108, 0x0002010A, 0x00030002, 0x02020201, ++0x02040203, 0x02060205, 0x02080207, 0x020A0209, ++0x020C020B, 0x020E020D, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x010E010D, 0x00FF010F, ++0x01090108, 0x010B010A, 0x00030002, 0x02020201, ++0x02040203, 0x02060205, 0x02080207, 0x020A0209, ++0x020C020B, 0x020E020D, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00205220, 0x00000046, ++0x00000059, 0x49544120, 0x0000204D, 0x00000000, ++0x02000112, 0x40FFFFFF, 0x91700CF3, 0x20104890, ++0x02090100, 0x0101002E, 0x09FA8000, 0x04000004, ++0x000000FF, 0x02010507, 0x07000200, 0x00028205, ++0x05070002, 0x00400383, 0x04050701, 0x01004003, ++0x002E0209, 0x80000101, 0x000409FA, 0x00FF0400, ++0x05070000, 0x00400201, 0x82050700, 0x00004002, ++0x03830507, 0x07010040, 0x40030405, 0x03040100, ++0x030C0409, 0x0079005A, 0x00410044, 0x03180053, ++0x00530055, 0x00320042, 0x0030002E, 0x00570020, ++0x0041004C, 0x0000004E, 0x00000000, 0x00000000, ++0x00000709, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, }; ++ ++const u32_t zcFwImageSize=11540; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu_FB50_mdk.c +@@ -0,0 +1,721 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xD2287FFC, 0x0009420B, ++0x0009B019, 0x9446D526, 0xE600A003, 0x8D043642, ++0x60527601, 0x8DF9C840, 0xD4222F02, 0x4E0BDE22, ++0xD4220009, 0x00094E0B, 0x4E0BD421, 0x7F040009, ++0xA0254F26, 0x4F226EF6, 0x410BD11E, 0xD41E0009, ++0x0009440B, 0x450BD51D, 0xD71D0009, 0x611DE1FF, ++0x2712D21C, 0xD41C5029, 0xE1FFCB01, 0x1209E501, ++0x12112212, 0xD5192452, 0xD6199716, 0xE7002572, ++0x2670D218, 0x2272D618, 0x4F26E201, 0x2622000B, ++0xDD17DC16, 0x4C0BDE17, 0x4D0B0009, 0x4E0B0009, ++0xAFF80009, 0x27100009, 0x00000640, 0x0020095A, ++0x001C001C, 0x00202940, 0x00200E2A, 0x0020294C, ++0x00202964, 0x00200CF0, 0x00200F26, 0x002009C4, ++0x001C3510, 0x001C3624, 0x001E212C, 0x002028EC, ++0x00202850, 0x002028F4, 0x00202900, 0x00200BEC, ++0x00201FD4, 0x002017B8, 0x2FD62FC6, 0x4F222FE6, ++0xDEA17FA4, 0x61E0E01C, 0x7D016DE3, 0x61D00F14, ++0xD59FD49E, 0x450BE020, 0xE0200F14, 0xE78004FC, ++0x604C66E2, 0x7D7F677C, 0x1F693070, 0x2D628F17, ++0x01FCE01C, 0x641CE500, 0xD797DE96, 0x3243625D, ++0xA21A8B01, 0x655D0009, 0x31EC6153, 0xE0286C10, ++0x6D530FC4, 0x3D7C62CE, 0xAFEF2D20, 0x20087501, ++0xE01C8B15, 0xE50001FC, 0xD78BDE8A, 0x641CA00A, ++0x6C53655D, 0x66C23CEC, 0x66626253, 0x2262327C, ++0x1F697504, 0x3243625D, 0xA1F68BF2, 0x88012D10, ++0xE01C8B16, 0xE40001FC, 0x671C2D40, 0x624DDE7D, ++0x8B013273, 0x0009A1E9, 0x62E3644D, 0x72046D43, ++0x3DEC6143, 0x65D2312C, 0x74086C12, 0x25C2AFEF, ++0x8B188804, 0x01FCE01C, 0x2D40E400, 0xDE71671C, ++0x3273624D, 0xA1D08B01, 0x644D0009, 0x62E36D43, ++0x65D23DEC, 0x61437204, 0x6612312C, 0x74086C52, ++0xAFED2C69, 0x880525C2, 0xE01C8B18, 0xE40001FC, ++0x671C2D40, 0x624DDE63, 0x8B013273, 0x0009A1B5, ++0x6C43644D, 0x3CEC62E3, 0x720465C2, 0x3D2C6D43, ++0x615266D2, 0x216B7408, 0x2512AFED, 0x8B138830, ++0xE200DE58, 0x64E22D20, 0x8B042448, 0x420BD257, ++0xA19A0009, 0x55E10009, 0x57E356E2, 0xDD545CE4, ++0x2FC64D0B, 0x7F04A191, 0x89018828, 0x0009A0EA, ++0xE143DE4C, 0x622D62E1, 0x8F033217, 0x56FB1FEB, ++0x2621E240, 0x8B013217, 0x0009A0D5, 0xE1015EFB, ++0x301685E1, 0xA0CE8B01, 0xE4010009, 0x2D4055FB, ++0x6451B179, 0xE14357FB, 0xE0546271, 0x3517652D, ++0x0F568D41, 0x3563E640, 0xE6008B05, 0x0F65E034, ++0xA00FE11A, 0x615372C0, 0x41214121, 0x41214121, ++0x45214121, 0x45214521, 0xC9036053, 0xE0346603, ++0x71180F65, 0x2209E007, 0x641DE030, 0x0F2565F3, ++0x1F4EB1F1, 0x04FDE034, 0x674DE030, 0x47080CFD, ++0x607361CD, 0x4108D22B, 0xE00F0CFE, 0x1F1F420B, ++0x2CD96D07, 0x5EFB6073, 0x85E20FC6, 0x420B51FF, ++0x2C0B600D, 0x54FE6073, 0xB1BB0FC6, 0xE05465F3, ++0x652D62E1, 0xE6400F56, 0x89623563, 0xE050E100, ++0x60230F15, 0x4008C903, 0x6D034000, 0xE0406103, ++0xE0440FD6, 0xD217EEFF, 0x6EEC0FF6, 0x0F26E058, ++0x60E3420B, 0x42216253, 0x42214221, 0x66234221, ++0x326C4200, 0x45214200, 0xE0486707, 0x0F764521, ++0xC9036053, 0x40085CFB, 0x7C0630FC, 0x6E036D2D, ++0x1FD51FC6, 0x1F04A02E, 0x00117D00, 0x00202968, ++0x00200E2A, 0x00117D04, 0x00117D84, 0x00200700, ++0x0020074C, 0x00202034, 0x0FD6E04C, 0x05FEE044, ++0x64D3B189, 0x64E2E048, 0xE04006FE, 0x2E422469, ++0x01FE67C4, 0x667CE058, 0x420B02FE, 0x240B6063, ++0x05FEE044, 0xB15D2E42, 0xE05064D3, 0x7D0101FD, ++0x0F157101, 0x02FDE050, 0x3262E606, 0x56FB8BDC, ++0x55FB6261, 0x85514200, 0x302C750C, 0x6103701B, ++0x64F3E600, 0xE704A004, 0x76016256, 0x74042422, ++0x3273626D, 0x65F38BF8, 0x641DB13C, 0xB0D256FB, ++0xA0AA6461, 0xD4880009, 0xE201D588, 0x2D20450B, ++0x0009A0A3, 0x8B078829, 0xE200DE85, 0x66E22D20, ++0x646DB0A1, 0x0009A099, 0x622CE281, 0x8B3D3020, ++0xD680E738, 0xE0442D70, 0xE0480C6E, 0x6E621DC1, ++0x51611DE2, 0x54621D13, 0x55651D44, 0x57631D55, ++0x5C661D76, 0x0E6E1DC7, 0x1DE8E040, 0xE050016E, ++0x54641D19, 0x056E1D4A, 0x1D5BE04C, 0xE054076E, ++0x0C6E1D7C, 0x1DCDE058, 0xE044026E, 0xED001D2E, ++0xE04806D6, 0x16D126D2, 0x16D516D2, 0x16D616D3, ++0xE04006D6, 0xE05006D6, 0x06D616D4, 0x06D6E04C, ++0x06D6E054, 0x06D6E058, 0x1F29A057, 0x622CE282, ++0x89313020, 0x05FCE020, 0x625CE683, 0x3260666C, ++0xD65D8B07, 0x2650E500, 0x52617680, 0xA044D65B, ++0xE6902622, 0x3260666C, 0xD2578B16, 0xE500D658, ++0x60622250, 0xCB20D257, 0xE6052602, 0xD6562262, ++0x2252460B, 0x420BD255, 0xD2550009, 0x2262E601, ++0x4618D254, 0x2262A029, 0xD254D453, 0xD4546542, ++0x0009420B, 0x0009A021, 0xE524D647, 0xD5452650, ++0x16215257, 0x16225258, 0x16235259, 0x1624525A, ++0x1625525B, 0x1626525C, 0x1627525D, 0x1628525E, ++0x1F29525F, 0xE2001629, 0x15281527, 0x152A1529, ++0x152C152B, 0x152E152D, 0x7F5C152F, 0x6EF64F26, ++0x000B6DF6, 0x4F226CF6, 0xE240614D, 0x89173123, ++0x3127E21F, 0xD43B8908, 0xE001D53B, 0x6642450B, ++0x26796707, 0x2462A00C, 0x3127E23F, 0xD7358908, ++0x71E0D635, 0x460BE001, 0x62075571, 0x17512529, ++0x000B4F26, 0x4F220009, 0xE240614D, 0x89153123, ++0x3127E21F, 0xD42B8907, 0x6642D22B, 0xE001420B, ++0xA00B260B, 0xE23F2462, 0x89073127, 0xD626D725, ++0x71E05571, 0xE001460B, 0x1751250B, 0x000B4F26, ++0xE6400009, 0x46284618, 0x6252D520, 0x89FC2268, ++0x0009000B, 0x4618E680, 0xD51C4628, 0x22686252, ++0x000B89FC, 0xA0010009, 0x7201E200, 0x8BFC3242, ++0x0009000B, 0x4618E680, 0xD5154628, 0x22686252, ++0x000B8BFC, 0x00000009, 0x0020296C, 0x00200E2A, ++0x00117D04, 0x00202858, 0x00117D80, 0x002028EC, ++0x001C3500, 0x001D4004, 0x00200F26, 0x002009C4, ++0x001E212C, 0x001C3D28, 0x00117D00, 0x00200E8A, ++0x00202984, 0x001C3704, 0x00202034, 0x001C373C, ++0x001C3700, 0x4F222FE6, 0x6E537FFC, 0x2F42BFCA, ++0xD61561E2, 0x1615E280, 0x421854E1, 0x55E21646, ++0x16574228, 0x6EF257E3, 0x2E2B1678, 0x7F0426E2, ++0xAFA74F26, 0x2FC66EF6, 0x2FE62FD6, 0xDD0A4F22, ++0xBFAF6C53, 0xBF946E43, 0xBFAB2DE2, 0x51D50009, ++0x54D62C12, 0x55D71C41, 0x56D81C52, 0x4F261C63, ++0x6DF66EF6, 0x6CF6000B, 0x001C370C, 0x0009A0F8, ++0xD19B4F22, 0xD49B9299, 0x2122B00D, 0x9795E605, ++0xB0229595, 0xB0366463, 0xB03A0009, 0xB03D0009, ++0xA06C0009, 0x4F124F26, 0xD1934F02, 0x94873145, ++0x4609060A, 0x46094609, 0x00293646, 0xD78CD58F, ++0x2500CA01, 0x4F062762, 0x4F16000B, 0xBFEA4F22, ++0xB0230009, 0xA0520009, 0x2FE64F26, 0x6E63D188, ++0x44186612, 0x4528926D, 0x26294408, 0x44084500, ++0x4400265B, 0x4708264B, 0x47082162, 0x27EBD181, ++0x000B2172, 0xD1806EF6, 0xE603D480, 0x000B2162, ++0xD27F2462, 0xE40A9656, 0x2262AFB0, 0x2FC62FB6, ++0x2FE62FD6, 0xDC7B4F22, 0x2C22E201, 0xBFA5E40A, ++0x60C27C44, 0xCB01ED00, 0x60C22C02, 0xC901EB64, ++0x6E03A008, 0x89073DB2, 0xE40160C2, 0xBF95C901, ++0x7D016E03, 0x8BF52EE8, 0x8B033DB2, 0xD26FD46E, ++0x0009420B, 0x4F26E40A, 0x6DF66EF6, 0xAF856CF6, ++0x44116BF6, 0x604B8F01, 0x000B6043, 0x2F860009, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x7FFC4F22, ++0x6DA3EA00, 0xDC626BA3, 0x9914E864, 0x8B4E2BB8, ++0x3AE3EE0A, 0x60C2894B, 0xCB02ED00, 0x62C22C02, ++0x2F0260C2, 0xA010C902, 0x096C6E03, 0x5BB45288, ++0x1FFF09B4, 0x01FF03C4, 0x89083D83, 0xE46460C2, ++0xC9022F02, 0x6E03BF52, 0x2EE87D01, 0xD1518BF4, ++0x54C1D551, 0x66526412, 0x6269EE01, 0x4220622F, ++0x622F4219, 0x4E182299, 0x8D0322E8, 0xE4FF6423, ++0x3428229A, 0x6572D749, 0x622F6259, 0x42194220, ++0x2299622F, 0x8D0322E8, 0xE6FF6623, 0x3628229A, ++0x3468BFA7, 0x30E2EE02, 0xAFB78901, 0xD240EB01, ++0x6EECEEE6, 0xBF21E40A, 0xAFAF22E2, 0xEE0A7A01, ++0x89013AE3, 0x8B033D83, 0xD234D43A, 0x0009420B, ++0x4F267F04, 0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, ++0x68F6000B, 0x5651D534, 0x46286052, 0x306C000B, ++0x2FC62FB6, 0x2FE62FD6, 0x4F124F22, 0xBFF14F02, ++0x6B036E43, 0xDD1CDC2D, 0x0009BFEC, 0x3C0530B8, ++0x4609060A, 0x46014609, 0x020A3D65, 0x42094209, ++0x32E24209, 0x4F068BF0, 0x4F264F16, 0x6DF66EF6, ++0x000B6CF6, 0x2FE66BF6, 0xDE214F22, 0xE500E102, ++0x2E12E403, 0x2E52BFD4, 0x4618E606, 0xE403E700, ++0x2E722E62, 0xAFCB4F26, 0x4F226EF6, 0x0009BFEB, ++0xE6E6D213, 0xE40A666C, 0x2262BFC2, 0x4F26AFE3, ++0x002028F0, 0x0024CDE0, 0x10624DD3, 0x00202AF0, ++0x001C5814, 0x001C59D0, 0x001C59A4, 0x001C639C, ++0x001C5804, 0x001C581C, 0x00202998, 0x00200E2A, ++0x001C5860, 0x001C6864, 0x001C59BC, 0x001C69BC, ++0x001C947C, 0x002029B0, 0x001C1040, 0xCCCCCCCD, ++0x001D4004, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0xE4007FE4, 0x4528E510, 0x67436C43, ++0xE107A00F, 0x6043644D, 0x0F564008, 0xEE0060C3, ++0x815125C1, 0x81538152, 0x157315E2, 0x751415E4, ++0x624D7401, 0x8BED3213, 0xDA6F51F1, 0x1A1154F2, ++0xD16E2A12, 0x57F455F3, 0x6DF258F5, 0x1141D96C, ++0x11532142, 0x11751152, 0x11871174, 0x52F61186, ++0x19D1D668, 0xD86829D2, 0xDA68E950, 0x1621EBB4, ++0x6BBC2622, 0xA0214908, 0x6EEDEE00, 0x61E36DE3, ++0x41084D08, 0x31EC3DEC, 0x41084D08, 0x60C33D8C, ++0xE7904108, 0x81D12DC1, 0x41086093, 0x81D2677C, ++0x31AC60C3, 0x3472E200, 0x1DD281D3, 0xD4551D13, ++0x1D248D01, 0xB03AD450, 0x7E0165D3, 0x34B264ED, ++0xD14D8BDB, 0x6512DB52, 0x4529D24D, 0x64121B51, ++0x674DD14A, 0x67222B72, 0x4729D64E, 0x69221B73, ++0x689D2FD2, 0x69121B82, 0x5A122692, 0x5B1416A2, ++0x16B4DA44, 0x16C65C16, 0x16EA6EA2, 0x4F267F1C, ++0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, 0x68F6000B, ++0x60616642, 0x8D04C803, 0x6061E500, 0x8802C903, ++0x52628B03, 0x51246563, 0x000B2412, 0x2FD66053, ++0x4F222FE6, 0x6E537FEC, 0xE5506253, 0xE4006D43, ++0xA0014508, 0x5224E101, 0x22116043, 0x81238121, ++0x81226053, 0x362056E2, 0xD22F8BF5, 0x64F316E4, ++0x420BE614, 0x65E165E3, 0x2549E4FC, 0x61F12E51, ++0x214965F3, 0x54D12F11, 0x410BD127, 0x57D1E614, ++0xCB016071, 0x1DE12701, 0x4F267F14, 0x000B6EF6, ++0x2FD66DF6, 0x4F222FE6, 0x6E537FEC, 0xE5FC6653, ++0x60616D43, 0xCB012059, 0x52E22601, 0x8B063260, ++0x51E212E4, 0x8B0431E0, 0xA00252D1, 0xAFF01E22, ++0xD2155664, 0xE61464F3, 0x65E3420B, 0xE1FC67E1, ++0x2E712719, 0x54D167F1, 0xD10F2719, 0xE61465F3, ++0x2F71410B, 0x602152D1, 0x2201CB01, 0x7F141DE1, ++0x6EF64F26, 0x6DF6000B, 0x002028BC, 0x002028C4, ++0x002028B4, 0x002028E4, 0x0010008C, 0x00100EC0, ++0x001E2108, 0x001C3D00, 0x00202194, 0x2FC62FB6, ++0x2FE62FD6, 0xD6314F22, 0x60D36D62, 0x894DC803, ++0xDB30DC2F, 0x0009A02C, 0xC9036061, 0x892B8801, ++0xD22DD42B, 0x0009420B, 0x65035603, 0xC8208561, ++0xE0508903, 0x720102BE, 0x85620B26, 0x4000600D, ++0x4000366A, 0x40004624, 0x206D4624, 0xD423C903, ++0x40086E03, 0xD1224000, 0x340C410B, 0x61E3D521, ++0xD721E001, 0x450BD221, 0x64E37E30, 0x2702420B, ++0x66C252C1, 0x8BCF3620, 0x4E18EE01, 0xA011DB1C, ++0x6061EC75, 0x8801C903, 0xD4198910, 0x460BD612, ++0xD4180009, 0x470BD718, 0xD2136503, 0x64C3D113, ++0x22E2410B, 0x66B252B1, 0x8BEA3620, 0xC80460D3, ++0xD2128906, 0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x001E2100, ++0x002028BC, 0x00202858, 0x00200AE0, 0x002028C4, ++0x00200B62, 0x00202034, 0x001C3D30, 0x00200DF0, ++0x002028B4, 0x002028E4, 0x00200AFE, 0x002000F8, ++0xE601D237, 0x1265D537, 0x000B2252, 0xD6361266, ++0x88016062, 0xE1018B62, 0xD5342612, 0x5451D134, ++0xE0406212, 0x2122324C, 0x54115752, 0x1141347C, ++0x57125453, 0x1172374C, 0x52135755, 0x1123327C, ++0x56146452, 0x1164364C, 0x54155754, 0x1145347C, ++0x56165458, 0x1166364C, 0x6762D626, 0x327C5217, ++0x57611127, 0x327C5218, 0x57621128, 0x327C5219, ++0x57631129, 0x347C541A, 0x5764114A, 0x347C541B, ++0x5765114B, 0x347C541C, 0x5266114C, 0x372C571D, ++0x5267117D, 0x342C541E, 0x5268114E, 0x362C561F, ++0xD615116F, 0x041E6262, 0x342C7694, 0xE0440146, ++0x061E6262, 0x0166362C, 0x525CE048, 0xD60F051E, ++0x0156352C, 0xE0546262, 0x4229051E, 0x0156352C, ++0xE0585561, 0x4529061E, 0x0166365C, 0x0009000B, ++0x001C1010, 0x0000C34F, 0x001C1028, 0x001C369C, ++0x00202858, 0x001C3CA0, 0x001C36F4, 0x001C3B88, ++0xD62F7FFC, 0x2642644C, 0xC8205066, 0x2F028DFC, ++0x7F04000B, 0x2FD62FC6, 0x4F222FE6, 0x6D436C53, ++0xEE00A004, 0x7E0164D4, 0x644CBFEA, 0x8BF93EC2, ++0x6EF64F26, 0x000B6DF6, 0xA0016CF6, 0x76016643, ++0x22286260, 0x36488BFB, 0x6563AFE4, 0x2FB62F96, ++0x2FD62FC6, 0x4F222FE6, 0xEC1CED08, 0xDB196E53, ++0x61C3E90A, 0x60434B0B, 0x3092C90F, 0x66038D02, ++0x7630A001, 0x4D107637, 0x7E012E60, 0x7CFC8FF1, ++0x8058E000, 0x6EF64F26, 0x6CF66DF6, 0x000B6BF6, ++0x000B69F6, 0x000BE000, 0x2FE6E000, 0x7FEC4F22, ++0x6E436253, 0xBFD165F3, 0xBFC66423, 0xBFC464E3, ++0xD40564F3, 0x0009BFC1, 0x4F267F14, 0x6EF6000B, ++0x001C0004, 0x002020F4, 0x002029CC, 0xE110D59C, ++0xE6406050, 0x2500C9FD, 0xE0FF75E9, 0x80516453, ++0x80538052, 0x80568055, 0x251075EF, 0xE1EF6250, ++0x2219E001, 0xE7202520, 0x24608052, 0x2570000B, ++0xE4FDD590, 0xE7026152, 0x25122149, 0x74016052, ++0x2502CB01, 0xD18C6652, 0x25622649, 0x92C26012, ++0x2102CB08, 0xC9CF6012, 0x60122102, 0x2102CB03, ++0x000B1172, 0x4F221123, 0xE100D484, 0xD285D784, ++0xD5852410, 0x2711D485, 0x2211E700, 0xBFBD2511, ++0xD5832471, 0x2560E600, 0x4F26AFD2, 0xD281664C, ++0x362C4600, 0xCB106060, 0x2600000B, 0xD27D654C, ++0x352C4500, 0xE1EF6650, 0x000B2619, 0x664C2560, ++0x4600D279, 0x6060362C, 0x000BCB10, 0x654C2600, ++0x4500D275, 0x6650352C, 0x2619E1EF, 0x2560000B, ++0xD270664C, 0x362C4600, 0xCB086060, 0x2600000B, ++0xD26C654C, 0x352C4500, 0xE1F76650, 0x000B2619, ++0x664C2560, 0x4600D268, 0x6060362C, 0x000BCB08, ++0x654C2600, 0x4500D264, 0x6650352C, 0x2619E1F7, ++0x2560000B, 0xD65F624C, 0x326C4200, 0xC9086020, ++0x40214021, 0x000B4021, 0x624C600C, 0x4200D65A, ++0x6020326C, 0x4021C908, 0x40214021, 0x600C000B, ++0xD156644C, 0x341C74FF, 0x000B6240, 0xD154602C, ++0x341C644C, 0x000B6240, 0x2FE6602C, 0x655C4F22, ++0x3567E60A, 0x6E438D15, 0x6453BFEA, 0x60EC640C, ++0x8B028801, 0xA002E00F, 0x44092409, 0x624C4409, ++0x3263E60A, 0xBFE28905, 0x620C644C, 0xC8806023, ++0xE2008B00, 0x4F266023, 0x6EF6000B, 0xD6414F22, ++0x88016062, 0xB2228B03, 0xA0030009, 0xD23E0009, ++0x2260E640, 0xE200D63D, 0x000B4F26, 0x4F222622, ++0x6062D638, 0x8B018802, 0x0009B26C, 0xE200D637, ++0x000B4F26, 0x0FFF2622, 0xD433D532, 0xE701E100, ++0x000B2512, 0xD2302470, 0x000BE604, 0xD5202260, ++0x6150E4FD, 0x2149D62E, 0x2510E700, 0x2670000B, ++0xE4FBD51B, 0x22496250, 0x2520000B, 0xE4F7D518, ++0x22496250, 0x2520000B, 0xD2264F22, 0x600D8522, ++0x89112008, 0x89138801, 0x89158803, 0x89178805, ++0x89418806, 0x89478808, 0x894D8809, 0x8953880A, ++0x8959880B, 0x0009A060, 0x0009B062, 0x600CA05D, ++0x0009B070, 0x600CA059, 0x0009B07A, 0x600CA055, ++0x6260D606, 0x8B4F2228, 0x0009B086, 0x600CA04D, ++0x001E1028, 0x001E2148, 0x001E1108, 0x0020293D, ++0x0020292C, 0x0020292E, 0x00202930, 0x00202910, ++0x001E1008, 0x001E103F, 0x001E105F, 0x001E1030, ++0x001E1090, 0x00202938, 0x001E100B, 0x00202934, ++0x0020293C, 0x00202904, 0x6260D687, 0x8B232228, ++0x0009B06A, 0x600CA021, 0x6260D683, 0x8B1B2228, ++0x0009B0B4, 0x600CA019, 0x6260D67F, 0x8B132228, ++0x0009B0BA, 0x600CA011, 0x6260D67B, 0x8B0B2228, ++0x0009B11E, 0x600CA009, 0x6260D677, 0x8B032228, ++0x0009B136, 0x600CA001, 0x4F26E000, 0x0009000B, ++0xD273D172, 0xD5738412, 0x4000C90F, 0xD772012D, ++0x611CE403, 0xD671E20F, 0x27122540, 0xE0012520, ++0x2602000B, 0xE601D269, 0x30668523, 0xE0008D06, ++0xE000D267, 0x8122D669, 0x2602E001, 0x0009000B, ++0x8523D262, 0x2008600D, 0x88018905, 0xD6648B0A, ++0xCB016060, 0xD6612600, 0xE101D45D, 0x2612E001, ++0x8142000B, 0xE000000B, 0xE501D158, 0x45188513, ++0x3453640D, 0x8D056603, 0xD25AE000, 0xE001D557, ++0x25022260, 0x0009000B, 0xD1504F22, 0x650D8513, ++0x44196453, 0x672E6249, 0x602C227D, 0x89098801, ++0x890C8802, 0x89108803, 0x89268806, 0x89298807, ++0x0009A038, 0xD64DD54C, 0xA027E212, 0x625C2652, ++0x8B2F2228, 0xA01ED64A, 0x605C6262, 0x89052008, ++0x89088810, 0x890B8820, 0x0009A024, 0xD643D445, ++0xA013E204, 0xD7442642, 0xE20CD640, 0x2672A00E, ++0xD63ED542, 0xA009E218, 0xD4412652, 0xE20AD63B, ++0x2642A004, 0xD639D23F, 0xE22E2622, 0xD43E8515, ++0x3277670D, 0x8F012421, 0x24516503, 0x0009B0DF, ++0xE001A001, 0x4F26E000, 0x0009000B, 0xE101D629, ++0x2610D436, 0xD7286541, 0x655DD128, 0xE001E20F, ++0x26202752, 0x2102000B, 0x4F222FE6, 0x8523D21F, ++0x2448640C, 0xD62D8B08, 0xE200D521, 0x84512621, ++0x20499430, 0x8051A026, 0x60E0DE1D, 0x8D0BC840, ++0x3427E201, 0xD1258922, 0x420BD225, 0xD5252141, ++0xCB046052, 0x2502A00B, 0x89173427, 0xD722D21F, ++0x2241470B, 0xE5FBD61F, 0x21596162, 0x84E12612, ++0xB12DCB80, 0x60E080E1, 0xCB04D61C, 0x60602E00, ++0x2600C93F, 0xE001D609, 0x2602A001, 0x4F26E000, ++0x6EF6000B, 0x0000FF7F, 0x0020293D, 0x00202904, ++0x00202910, 0x001E1100, 0x001E100C, 0x00202934, ++0x001E1000, 0x001E1001, 0x00202AF4, 0x00202918, ++0x00202920, 0x00202B62, 0x00202B66, 0x00202B72, ++0x00202B8A, 0x00202B94, 0x0020291C, 0x0020292A, ++0x00201AB6, 0x001E1108, 0x00201BC2, 0x001E1015, ++0x6060D696, 0x8919C880, 0x6021D295, 0x8B158801, ++0xE501D294, 0x30568524, 0xD1938910, 0xD493E203, ++0x65412120, 0x655DE00B, 0xD5910656, 0xE702E40F, ++0x25712140, 0xE001D78F, 0x2702000B, 0xE000000B, ++0x4F222FE6, 0x84E1DE8C, 0x8934C880, 0x8554D585, ++0x8F302008, 0xD7896103, 0x66728553, 0x650C6403, ++0x620C8566, 0x8B263520, 0xD780D685, 0x644C651C, ++0x27412651, 0xC84060E0, 0xD2828907, 0x0009420B, ++0x6062D681, 0xA008CB04, 0xD1802602, 0x0009410B, ++0xE5FBD67D, 0x24596462, 0xB0A12642, 0xD5750009, ++0x2522E201, 0xD77A60E0, 0x2E00CB04, 0xC93F6070, ++0xA0012700, 0xE0006023, 0x000B4F26, 0x2FA66EF6, ++0x2FC62FB6, 0x2FE62FD6, 0xE240DA69, 0xDC6666A1, ++0x3123616D, 0x62638900, 0x6ED36D2C, 0x4E2136D8, ++0x4E212A61, 0xDB6CD46B, 0xE700A00F, 0x770166B2, ++0x71026163, 0x65612B12, 0x71026613, 0x62612B12, ++0x622D655D, 0x325C4228, 0x627C2422, 0x8BED32E3, ++0xC90360D3, 0x8B108803, 0xED076EB2, 0x710261E3, ++0x67132B12, 0x62E17102, 0x65712B12, 0x655D622D, ++0x352C4528, 0xA00C2CD0, 0x88022452, 0xA0038B01, ++0x8801E203, 0xE2018B05, 0x66B22C20, 0x677D6761, ++0xEB0F2472, 0x6DA12CB0, 0x8B052DD8, 0xD445D24F, ++0xE101EE00, 0x241222E2, 0x6DF66EF6, 0x6BF66CF6, ++0x6AF6000B, 0x2FE62FD6, 0xE240DD3D, 0x616D66D1, ++0x89003123, 0x672C6263, 0xDE433678, 0x2D617703, ++0xD6404721, 0x472164E2, 0xE100A00E, 0x71016562, ++0x24506253, 0x42197401, 0x74012420, 0x24504529, ++0x45197401, 0x74012450, 0x3273621C, 0x42008BEE, ++0x64D166E2, 0x362C4200, 0x8F062448, 0xDD332E62, ++0xE500DE28, 0x2D52E701, 0x6EF62E72, 0x6DF6000B, ++0x2FE62FD6, 0xEE014F22, 0xED0AA005, 0x64E3BCB6, ++0x64E3BCBC, 0x62EC7E01, 0x8BF732D7, 0xEE01A005, ++0x64E3BCBD, 0x64E3BCC3, 0x62EC7E01, 0x8BF732D7, ++0x6EF64F26, 0x6DF6000B, 0x2FE62FD6, 0x7FFC4F22, ++0x6060D61F, 0x89758801, 0xE101D41E, 0xD7128548, ++0x650D2610, 0x45196070, 0x6659DD1B, 0x61D3626E, ++0xC840262D, 0x74027102, 0x8D47D718, 0xD218666C, ++0xE501DE0A, 0xA0312E22, 0x0000EE04, 0x001E1001, ++0x0020292A, 0x00202904, 0x001E1100, 0x0020292E, ++0x0020291C, 0x00202934, 0x001E1000, 0x00202920, ++0x0020292C, 0x00201AB6, 0x001E1108, 0x00201BC2, ++0x001E1015, 0x001E100C, 0x00202918, 0x00202938, ++0x0020293C, 0x00202AF4, 0x00202B8A, 0x00202B96, ++0x00202B06, 0x75016245, 0x71022121, 0x32E3625C, ++0x60638BF8, 0xE60181D4, 0xE417D538, 0x3243626C, ++0x6255891E, 0x27217601, 0x7702AFF8, 0xDE35D234, ++0x2E22E501, 0xEE04A004, 0x75016245, 0x71022121, ++0x32E3625C, 0x60638BF8, 0xE60181D4, 0xA004D52E, ++0x6255E417, 0x27217601, 0x626C7702, 0x8BF83243, ++0x2D21924B, 0xD72AD429, 0x2F126142, 0x6DF265F2, ++0xC9806053, 0x60532700, 0x6103C960, 0x60538071, ++0x65F26EF2, 0x4D19C903, 0x80724529, 0x451960DC, ++0x4E298172, 0x62EC605C, 0x302C4018, 0x6D428173, ++0x2FD22118, 0x62F26EF2, 0x421966F2, 0x656C4629, ++0x602C66F2, 0x401864EC, 0x304C4629, 0x81744619, ++0x4018606C, 0x8F07305C, 0xBCB58175, 0x620C0009, ++0x89082228, 0x0009A00A, 0x88406013, 0xB00A8B03, ++0xA0030009, 0xD60B0009, 0x2622E202, 0x4F267F04, ++0x000B6EF6, 0x000B6DF6, 0x060A0009, 0x00202B36, ++0x00202B34, 0x00202920, 0x00202B08, 0x001E100C, ++0x00202904, 0x00202934, 0x7FFC4F22, 0x6620D27E, ++0x8D082668, 0xD47D2F60, 0x420BD27D, 0x64F00009, ++0xA0907F04, 0x7F044F26, 0x000B4F26, 0x000B0009, ++0x2FE60009, 0xDE774F22, 0x60E0D677, 0xCBC0D477, ++0x62602E00, 0xC803602C, 0x40218904, 0x70014021, ++0x6603A002, 0x66034009, 0xD671616D, 0xE500A004, ++0x75016262, 0x74042422, 0x3213625D, 0xD16D8BF8, ++0x0009410B, 0xE401D66C, 0x84E22641, 0x80E2C9BF, ++0x000B4F26, 0x2FE66EF6, 0xD5687FFC, 0x6250DE61, ++0x642C84E2, 0xCB407404, 0x80E2614D, 0x44216413, ++0xD7634421, 0xE600A004, 0x76016256, 0x27222F22, ++0x3243626D, 0x60138BF8, 0x2008C903, 0x88038912, ++0x88028905, 0x88018906, 0xA0088907, 0xE0070009, ++0x8078A005, 0xA002E003, 0xE0018078, 0x62528078, ++0x27222F22, 0xD650E00F, 0x60618078, 0x8B018801, ++0x2621E200, 0x6060D64F, 0x2600CB08, 0xC93F60E0, ++0x7F042E00, 0x6EF6000B, 0x6021D247, 0x8D188801, ++0xD2466143, 0x22106053, 0x60638021, 0xD4468121, ++0xE500A007, 0x027C605D, 0x364C6603, 0x26207001, ++0x625D6503, 0x3213611C, 0xD6408BF4, 0xC9BF6060, ++0x000B2600, 0x2FD60009, 0x4F222FE6, 0x60437FFC, ++0x8D02C820, 0xBF6A6E43, 0x60E30009, 0x8901C810, ++0x0009BF67, 0xC84060E3, 0xBF8C8901, 0x60E30009, ++0x8929C801, 0x60D0DD32, 0x8D03C802, 0xD6312F00, ++0x0009460B, 0xC80460F0, 0xD62F8902, 0x0009460B, ++0x602362F0, 0x8902C880, 0xC97F60D0, 0x60232D00, ++0x8902C801, 0x420BD229, 0xD5290009, 0x88026052, ++0xD2288B03, 0xA005E604, 0x88012260, 0xD2258B02, ++0x2260E601, 0x2522E200, 0xC88060E3, 0xD2228916, ++0x60E36E20, 0x8902C802, 0x420BD220, 0x60E30009, ++0x8902C804, 0x420BD21E, 0x60E30009, 0x8905C808, ++0x7F04D21C, 0x6EF64F26, 0x6DF6422B, 0x4F267F04, ++0x000B6EF6, 0x00006DF6, 0x001E1020, 0x002029D0, ++0x00200E2A, 0x001E1015, 0x001E10BF, 0x00117D00, ++0x001E10FC, 0x002000F8, 0x00202930, 0x00117D80, ++0x001E10F8, 0x001E10AE, 0x00117D84, 0x001E1017, ++0x001E1021, 0x0020105C, 0x0020107E, 0x00201608, ++0x00202934, 0x001E100B, 0x001E1028, 0x002010AE, ++0x002010C0, 0x002010CC, 0xD6A8644C, 0x346C74FF, ++0x2450000B, 0x644CD6A6, 0x000B346C, 0xD6A52450, ++0x346C644C, 0x2450000B, 0x616D625C, 0x41194208, ++0x60194208, 0x644C4200, 0x324C670E, 0x207DD19E, ++0xC90F4200, 0x000B321C, 0x67632200, 0x4208625C, ++0x42004208, 0x324C644C, 0x4200D198, 0x000B321C, ++0x2FE62270, 0x614C4F12, 0x4100D493, 0x6710314C, ++0x2729E29F, 0x65736E53, 0x4719676D, 0x672E6279, ++0x4221227D, 0x42214221, 0x7601662C, 0xE4014608, ++0x34E84608, 0x644C4600, 0x0E1A0467, 0x215025EB, ++0x000B4F16, 0x4F226EF6, 0xD2857FE8, 0x88016021, ++0xD2848B7B, 0x26686621, 0xD2838B77, 0x26686621, ++0xE50F8B73, 0xE401BFA0, 0xBFA3E501, 0xE586E400, ++0xE400655C, 0x2F50BFA3, 0xBFA0E401, 0xE602E506, ++0x60634618, 0x81F2E401, 0x6543BF9E, 0xE40185F2, ++0xBFAA6543, 0x85F26603, 0x6543E401, 0x6603BFB1, ++0xE40265F0, 0x6053756C, 0x80F8BF7E, 0xBF81E402, ++0x84F8E512, 0x7090E402, 0x6503BF81, 0x4618E602, ++0x81F66063, 0xBF7FE402, 0x85F6E500, 0x6603E402, ++0xE500BF8B, 0xE40285F6, 0xBF926603, 0xE5FEE500, ++0xE010655C, 0xBF5FE403, 0xE5130F54, 0xE40EBF62, ++0x05FCE010, 0xBF62E40E, 0xE5007585, 0xBF63E403, ++0xE500E640, 0xBF70E403, 0xE500E640, 0xBF78E403, ++0xE5FFE640, 0xE014655C, 0xBF45E404, 0xE40F0F54, ++0xE504BF48, 0x05FCE014, 0xBF48E40F, 0xE5017584, ++0xBF49E640, 0xE501E404, 0xBF56E640, 0xE501E404, ++0xE404E640, 0xAF5C7F18, 0x7F184F26, 0x000B4F26, ++0x4F220009, 0xD2427FF0, 0x88016021, 0xD2418B71, ++0x26686621, 0xD2408B6D, 0x26686621, 0xE50F8B69, ++0xE401BF1A, 0xBF1DE501, 0xE586E400, 0xE400655C, ++0x2F50BF1D, 0xBF1AE401, 0xE401E506, 0xBF1B6543, ++0xE401E640, 0xBF286543, 0xE401E640, 0xBF306543, ++0x65F0E640, 0x756CE402, 0xBEFD6053, 0xE40280F4, ++0xE512BF00, 0xE40284F4, 0xBF007090, 0xE6406503, ++0xBF01E402, 0xE640E500, 0xBF0EE402, 0xE640E500, ++0xBF16E402, 0xE5FEE500, 0x6053655C, 0xBEE3E403, ++0xE51380F8, 0xE40EBEE6, 0xE40E84F8, 0xBEE67085, ++0xE5006503, 0xBEE7E640, 0xE500E403, 0xBEF4E640, ++0xE500E403, 0xBEFCE640, 0xE5FFE403, 0x6053655C, ++0xBEC9E404, 0xE40F80FC, 0xE504BECC, 0xE40F84FC, ++0xBECC7083, 0xE5016503, 0xBECDE640, 0xE501E404, ++0xBEDAE640, 0xE501E404, 0xE404E640, 0xAEE07F10, ++0x7F104F26, 0x000B4F26, 0x00000009, 0x001E1030, ++0x001E1080, 0x001E1090, 0x001E103F, 0x001E103E, ++0x0020292A, 0x0020292C, 0x0020292E, 0x0009000B, ++0x666CE680, 0x6563D2A0, 0x7540E700, 0x6473422B, ++0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, 0x4C18EC01, ++0xDA9BDB9A, 0x65B252B1, 0x89223520, 0xC9036051, ++0x891E8801, 0xD197DE95, 0x64E3410B, 0x85036503, ++0x670D66A2, 0xDD943762, 0xD494890A, 0x420BD294, ++0xD1940009, 0xE701D494, 0x21724D0B, 0x0009AFE2, ++0x420BD292, 0xD69264E3, 0x4D0BD492, 0xAFD926C2, ++0x4F260009, 0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, ++0x7FF44F22, 0xE6818546, 0x85472F01, 0x81F1666C, ++0xD27D8548, 0x854281F2, 0x81F367F3, 0xE40C8543, ++0x605381F4, 0x81F56563, 0x7540420B, 0x4F267F0C, ++0x0009000B, 0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, ++0x4F222FE6, 0xE2007FEC, 0xA0CBDB7B, 0x6A132F21, ++0x4A08D27A, 0xDE7AE001, 0x4A00420B, 0x7E303AEC, ++0x1F021FE1, 0x66B2DD77, 0x362052B1, 0xA0B58B01, ++0x60610009, 0x8801C903, 0xA0AF8B01, 0x85610009, ++0x8974C801, 0xEE105163, 0xDC638512, 0xC9036603, ++0x85136403, 0x4021600D, 0xC93F4021, 0x8D2030E3, ++0xD7696503, 0x62704408, 0x44004408, 0x22284500, ++0x345C8F0C, 0x6043D265, 0x625D052D, 0x60294219, ++0x207D670E, 0x605C81F6, 0x81F8A00B, 0x6043D260, ++0x685D052D, 0x60894819, 0x209D690E, 0x605C81F6, ++0xD75C81F8, 0x22286272, 0xE0FF8902, 0x81F8600C, ++0xEEFF85F8, 0x6EEC650D, 0x8B0F35E0, 0x4E0BDE45, ++0x540364B3, 0xBF7BE502, 0xD4536803, 0x410BD147, ++0xD7526583, 0xD452E901, 0x2792A020, 0x26E9EEFC, ++0x81126063, 0x946E8513, 0x81132049, 0x45088512, ++0x62036953, 0xE50885F6, 0x8112202B, 0x45188513, ++0x8113209B, 0xD4478514, 0x8114205B, 0x851161B2, ++0x811120E9, 0x602162B2, 0x2201CB01, 0x00094C0B, ++0x56F160B2, 0xCB0152F2, 0xAF7C2A02, 0x85612622, ++0xC802DC3A, 0xD938D227, 0x8D0FD82C, 0x420B64B3, ++0x65030009, 0x480B6493, 0xE8015E03, 0x85EF2C82, ++0x650DD635, 0x64D3460B, 0x0009AF65, 0x0009420B, ++0x6E035403, 0xE5088544, 0x45186103, 0x31502159, ++0xBF258B03, 0xA007E501, 0x85410009, 0x620DD52B, ++0x89012258, 0xE500BF1C, 0x480B6493, 0xD42865E3, ++0xE801D611, 0x2C82460B, 0x0009AF45, 0x7B0862F1, ++0x2F217201, 0xEE0362F1, 0x31E7612D, 0xAF2E8901, ++0x7F140009, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0xFE0368F6, 0x002018B8, 0x002028E4, ++0x002028EC, 0x00200AE0, 0x00200E2A, 0x002028B4, ++0x00200B62, 0x001E2130, 0x00202AD4, 0x00200AFE, ++0x001C3D30, 0x00202AD8, 0x002028C4, 0x00202034, ++0x001C3D00, 0x00202AE4, 0x00202AF0, 0x002029D4, ++0x00202A54, 0x00202900, 0x002028BC, 0x001E212C, ++0x00202ADC, 0x00202AE0, 0x00200E8A, 0x00008000, ++0x00202AEC, 0x4F222FE6, 0x6E22D20D, 0xC84060E3, ++0x22E28D02, 0x0009BE7A, 0x4218E240, 0x89012E28, ++0x0009BE76, 0xC80560E3, 0xBECB8901, 0x60E30009, ++0x8902C802, 0xAE734F26, 0x4F266EF6, 0x6EF6000B, ++0x001C3510, 0x080A0C0E, 0x00020406, 0x1A1C1E20, ++0x12141618, 0x2E303234, 0x26282A2C, 0x3A3C3E40, ++0x6C625648, 0x41112F26, 0xE2208F18, 0x890B3123, ++0x321CD204, 0xD1026220, 0x412B312C, 0x00090009, ++0x0020205E, 0x00202014, 0x000BE000, 0x400062F6, ++0x40004000, 0x40004000, 0x40004000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40184000, ++0x62F6000B, 0x40004000, 0x40004000, 0x40004000, ++0x40284000, 0x62F6000B, 0x40004000, 0x40184000, ++0x000B4028, 0xC90F62F6, 0x40054005, 0x40054005, ++0x62F6000B, 0x4005C907, 0x40054005, 0x62F6000B, ++0x4005C903, 0x000B4005, 0xC90162F6, 0x000B4005, ++0x000062F6, 0x080A0C0E, 0x00020406, 0x1A1C1E20, ++0x12141618, 0x2E303234, 0x26282A2C, 0x3A3C3E40, ++0x6C625648, 0x41112F26, 0xE2208F18, 0x890B3123, ++0x321CD204, 0xD1026220, 0x412B312C, 0x00090009, ++0x0020211E, 0x002020D4, 0x000BE000, 0x400162F6, ++0x40014001, 0x40014001, 0x40014001, 0x62F6000B, ++0x40014001, 0x40014001, 0x40014001, 0x40194001, ++0x62F6000B, 0x40014001, 0x40014001, 0x40014001, ++0x40294001, 0x62F6000B, 0x40014001, 0x40194001, ++0x000B4029, 0x400462F6, 0x40044004, 0xC90F4004, ++0x62F6000B, 0x40044004, 0xC9074004, 0x62F6000B, ++0x40044004, 0x000BC903, 0x400462F6, 0x000BC901, ++0x000062F6, 0x3622E218, 0x67438F12, 0x0009A004, ++0x76FF6254, 0x74012420, 0xC8036053, 0x60438BF8, ++0x8902C803, 0x422BD22B, 0xD22B0009, 0x0009422B, ++0x2FE66473, 0x8D4A3450, 0x27786763, 0x62438947, ++0x227B225B, 0xC9016023, 0x8D203452, 0x2EE86E03, ++0x60238B15, 0x8B08C803, 0x47096643, 0x47106256, ++0x8FFB2622, 0xA0327604, 0x47010009, 0x61436673, ++0x46106255, 0x8FFB2121, 0xA0287102, 0x66430009, ++0x47106254, 0x8FFB2620, 0xA0207601, 0x61430009, ++0x2EE8357C, 0x8F15317C, 0x60236653, 0x8B07C803, ++0x76FC4709, 0x47106262, 0x21268FFB, 0x0009A00F, ++0x65634701, 0x75FE6673, 0x46106251, 0x21258FFB, ++0x0009A005, 0x626076FF, 0x8FFB4710, 0x60432124, ++0x6EF6000B, 0x00202306, 0x002027B2, 0xE21E2FE6, ++0x67633626, 0x8D1B6153, 0x3E106E43, 0x3E128916, ++0x65E38908, 0x3672E600, 0x62148910, 0x25207601, ++0x7501AFF9, 0x317C64E3, 0x6513347C, 0xE600A004, ++0x625075FF, 0x24247601, 0x8BF93672, 0x60E3A011, ++0x890831E2, 0x327C6213, 0x8B0432E6, 0x651364E3, ++0xA0086673, 0xD28F6EF6, 0x651364E3, 0x422B6673, ++0x000B6EF6, 0xE2046EF6, 0x67433622, 0x8F10356C, ++0xA004346C, 0x75FF0009, 0x76FF6250, 0x60532424, ++0x8BF8C803, 0xC8036043, 0xA1058901, 0xA2770009, ++0xA2990009, 0x2FB60009, 0x2FD62FC6, 0x7FE42FE6, ++0x6C636043, 0x66521F62, 0xC9037504, 0x1F516E53, ++0x45086503, 0xE1FC6D43, 0x2D194500, 0x1F732558, ++0x1F651F44, 0x2FD28D0B, 0x88086053, 0x88108923, ++0x8818895B, 0xA0898B01, 0xA0BD0009, 0x62630009, ++0x2D22E600, 0x7CFC7D04, 0xEB10A00D, 0xE60064E6, ++0x7CF065E6, 0x62E261E6, 0x1D512D42, 0x1D231D12, ++0x7E047D10, 0x3CB21FE1, 0x1F6589F0, 0x2FD21FC2, ++0xA0A11FE6, 0x64D21FD4, 0x44286263, 0x44294418, ++0x42184419, 0x4629242B, 0x2D424619, 0x65637D04, ++0xA0217CFD, 0x67E6EB10, 0x62E67CF0, 0x64E66673, ++0x256B4618, 0x2D5261E2, 0x65234729, 0x45184719, ++0x4229275B, 0x42191D71, 0x47186743, 0x4429227B, ++0x44196713, 0x247B4718, 0x1D431D22, 0x41194129, ++0x65137D10, 0x1FE17E04, 0x89DC3CB2, 0x1FE67EFF, ++0x1FC21F55, 0xA0672FD2, 0x6CF21FD4, 0x66C257F5, ++0x46286273, 0x42284629, 0x2C62262B, 0x7C045DF2, ++0x7DFE4729, 0xA01CEB10, 0x65E65EF1, 0x66E66273, ++0x47286753, 0x6763227B, 0x452961E6, 0x257B4728, ++0x2C2264E6, 0x65131C51, 0x45284629, 0x1C62265B, ++0x41296643, 0x216B4628, 0x44291C13, 0x67437C10, ++0x3DB27DF0, 0x1FD289E1, 0x7EFEA034, 0x51F56CF2, ++0x621366C2, 0x42284618, 0x42184619, 0x2C62262B, ++0x7C045DF2, 0x7DFF4119, 0xA01FEB10, 0x65E65EF1, ++0x64E67DF0, 0x42286253, 0x421867E6, 0x66E6212B, ++0x61432C12, 0x45194128, 0x251B4118, 0x65731C51, ++0x44194528, 0x245B4518, 0x64631C42, 0x47194428, ++0x274B4418, 0x46191C73, 0x61637C10, 0x89DE3DB2, ++0x7EFD1FD2, 0x1FC41FE6, 0x5DF2E704, 0xA00D5EF6, ++0x62E451F4, 0x66E47DFC, 0x65E464E4, 0x71012120, ++0x71012160, 0x71012140, 0x71012150, 0x89F03D72, ++0x66D357F3, 0x641365E3, 0x6EF67F1C, 0x6CF66DF6, ++0x6BF6A190, 0x00202194, 0x2FC62FB6, 0x2FE62FD6, ++0x60437FE4, 0x6C63C903, 0x66031F62, 0x460875FC, ++0x61526E43, 0x4600E2FC, 0x26682E29, 0x1F441F73, ++0x1F516D53, 0x8D0B1F15, 0x60632FE2, 0x891F8808, ++0x89538810, 0x8B018818, 0x0009A081, 0x0009A0B9, ++0xEB10A00D, 0x52D37DF0, 0x54D156D2, 0x2E1665D2, ++0x2E662E26, 0x2E427EFC, 0x1FD16153, 0x3CB27CF0, ++0x7D0489F0, 0x1F151FD6, 0x2FE21FC2, 0x1FE4A0A1, ++0x621366E2, 0x42294619, 0x42194618, 0x2E62262B, ++0x7CFF4118, 0xEB10A021, 0x54D37DF0, 0x624357D2, ++0x42194229, 0x55D1212B, 0x2E1666D2, 0x41296173, ++0x41194418, 0x2E46241B, 0x44296453, 0x44194718, ++0x2E76274B, 0x47296763, 0x47194518, 0x257B7EFC, ++0x46182E52, 0x1FD16163, 0x3CB27CF0, 0x7D0389DC, ++0x1F151FD6, 0x2FE21FC2, 0x1FE4A06B, 0x57F56EF2, ++0x627366E2, 0x46284629, 0x262B4229, 0x2E625CF2, ++0x7CFE4728, 0xA01BEB10, 0x7DF05DF1, 0x55D251D3, ++0x46296613, 0x54D1276B, 0x2E7662D2, 0x41286753, ++0x217B4729, 0x61432E16, 0x41294528, 0x2E56251B, ++0x44286523, 0x245B4529, 0x42282E46, 0x7CF06723, ++0x89E23CB2, 0x1FD67D02, 0xA03A1FC2, 0x67F21FE4, ++0x657251F5, 0x45296213, 0x45284519, 0x42194518, ++0x5CF2252B, 0x41282752, 0x7CFD4118, 0xA022EB10, ++0x7DF05DF1, 0x54D256D3, 0x45196563, 0x52D14628, ++0x4618215B, 0x6ED26543, 0x45192716, 0x265B4428, ++0x65436163, 0x45186423, 0x42284419, 0x4218254B, ++0x271664E3, 0x44196623, 0x264B2756, 0x4E282766, ++0x61E34E18, 0x3CB27CF0, 0x7D0189DB, 0x1FC21FD6, ++0xE7041F74, 0x51F45DF2, 0x5EF6A00D, 0x84E27EFC, ++0x620364E0, 0x7DFC84E1, 0x84E36503, 0x21646603, ++0x21542124, 0x3D722144, 0x57F389F0, 0x641366D3, ++0x7F1C65E3, 0x6DF66EF6, 0xA09D6CF6, 0x2F866BF6, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x614374E0, ++0x6A636873, 0x6B56E920, 0x6C567AE0, 0x6D567120, ++0x6E563A92, 0x64566756, 0x62566656, 0x11C121B2, ++0x11E311D2, 0x11451174, 0x8DEC1166, 0x71201127, ++0x6613A004, 0x7AFF6254, 0x76012620, 0x8BF92AA8, ++0x6EF66083, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x2F8668F6, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x6A636873, 0x75E0E920, 0x56565257, 0x57545155, ++0x5D525E53, 0x6B525C51, 0x24662426, 0x24762416, ++0x7AE024E6, 0x24C624D6, 0x8DEC3A92, 0x66A324B6, ++0x6EF66783, 0x6CF66DF6, 0x6AF66BF6, 0xA04369F6, ++0x2FE668F6, 0xC8046063, 0x8D046E63, 0x62166153, ++0x24227EFC, 0x60E37404, 0x8908C818, 0x71046513, ++0x62526616, 0x24227EF8, 0xAFF41461, 0xE2047408, ++0x65133E22, 0x66E38D02, 0x6EF6A01C, 0x6EF6AF87, ++0xC8046063, 0x61638D04, 0x625275FC, 0x242671FC, ++0xC8186013, 0x75F88906, 0x66525251, 0x24662426, ++0x71F8AFF6, 0x3122E204, 0x66138F02, 0x0009AFA1, ++0x0009A00A, 0x0009A004, 0x76FF6254, 0x74012420, ++0x8BF92668, 0x6073000B, 0x0009A004, 0x625075FF, ++0x242476FF, 0x8BF92668, 0x6073000B, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x544F0D0A, 0x46205355, 0x00003A57, 0x2072614D, ++0x32203232, 0x20373030, 0x353A3731, 0x37333A32, ++0x00000000, 0x00000D0A, 0x00000043, 0x61766E49, ++0x2064696C, 0x72657375, 0x20726F20, 0x2079656B, ++0x00214449, 0x6E6B6E55, 0x206E776F, 0x6D6D6F63, ++0x3D646E61, 0x00000000, 0x61437748, 0x7262696C, ++0x6F697461, 0x6620206E, 0x0A6C6961, 0x0000000D, ++0x73696F4E, 0x61432065, 0x7262696C, 0x6F697461, ++0x6166206E, 0x21216C69, 0x00000D0A, 0x00000D0A, ++0x00000042, 0x000000FF, 0x00020001, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00020003, 0x01090108, ++0x0002010A, 0x00030002, 0x02020201, 0x02040203, ++0x02060205, 0x02080207, 0x020A0209, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00FF010F, 0x01090108, ++0x010B010A, 0x00030002, 0x02020201, 0x02040203, ++0x02060205, 0x02080207, 0x020A0209, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00000072, 0x00205220, 0x00000046, ++0x00000059, 0x73204142, 0x003D7165, 0x00000074, ++0x00000000, 0x02000112, 0x40FFFFFF, 0x12210ACE, ++0x20104890, 0x02090100, 0x0101002E, 0x09FA8000, ++0x04000004, 0x000000FF, 0x02010507, 0x07000200, ++0x00028205, 0x05070002, 0x00400383, 0x04050701, ++0x01004003, 0x002E0209, 0x80000101, 0x000409FA, ++0x00FF0400, 0x05070000, 0x00400201, 0x82050700, ++0x00004002, 0x03830507, 0x07010040, 0x40030405, ++0x03040100, 0x030C0409, 0x0079005A, 0x00410044, ++0x03180053, 0x00530055, 0x00320042, 0x0030002E, ++0x00570020, 0x0041004C, 0x0000004E, 0x00000000, ++0x00000000, 0x00000709, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, }; ++ ++const u32_t zcFwImageSize=11204; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwuinit.c +@@ -0,0 +1,240 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x7FFC4F22, 0xD695D494, 0x0009460B, ++0xD494E570, 0x4518B01E, 0x89042008, 0xD690D492, ++0x462B7F04, 0xB0124F26, 0xD2900009, 0x420BD490, ++0xE6000009, 0x949AD58F, 0xC8406052, 0x2F028F03, ++0x8FF93642, 0x7F047601, 0x000B4F26, 0xD28A0009, ++0x0009422B, 0x2FD62FC6, 0x4F222FE6, 0xD6877FEC, ++0x626061F3, 0x2F208461, 0x846280F1, 0x80F27110, ++0x6D438463, 0x846480F3, 0x80F46413, 0x6C538465, ++0x846680F5, 0x80F6E500, 0xD77D8467, 0x846880F7, ++0x80F8EE04, 0x80F98469, 0x80FA846A, 0x80FB846B, ++0x80FC846C, 0x80FD846D, 0x80FE846E, 0x80FF846F, ++0x6653655C, 0x7501367C, 0x665C6260, 0x242036E3, ++0x74018FF6, 0x66F32F16, 0xE7107604, 0xB00D65C3, ++0x6E0364D3, 0xD46B7F04, 0x420BD26B, 0x60E36503, ++0x4F267F14, 0x6DF66EF6, 0x6CF6000B, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0x3F3C933A, 0x4108E141, ++0x31FCE200, 0x11733526, 0x21521162, 0x11418D02, ++0xE0FFA098, 0x4A18EA01, 0x262066F3, 0x32A27201, ++0x76018FFB, 0x6BE3EE00, 0xE0446CF3, 0x00FE4008, ++0x450BD556, 0x660361B3, 0x4008E043, 0x6DC004FE, ++0x014C6063, 0x31EC3EDC, 0x60E36E1C, 0x7B0107FC, ++0x2C703BA2, 0x8FE80FD4, 0xE0427C01, 0xEB004008, ++0x70FC07FE, 0x6EB36CB3, 0xA0200AFE, 0x2710EDFF, ++0x7C01FEE0, 0x60C36CCC, 0x657002FC, 0x6BBC3B2C, ++0x01FC60B3, 0x0F1460C3, 0x0F2460B3, 0x04FC60C3, ++0x342C7E01, 0x01FC604C, 0x251A62D3, 0xD43C225A, ++0x2750602C, 0x064E4008, 0x2D6A4D19, 0x3EA27701, ++0x66D78BDF, 0x4018E001, 0x0F646563, 0x70014519, ++0x0F544629, 0x0F647001, 0x70014619, 0x90420F64, ++0xE0450EFE, 0xEA014008, 0xE0460FF6, 0x4A184008, ++0xED0067F3, 0x0FF637AC, 0x0FF67004, 0xE345E104, ++0x7C014308, 0x6CCC33FC, 0x60C36432, 0x5531024C, ++0x6BBC3B2C, 0x045C60B3, 0x60C35A32, 0x60B30A44, ++0x60C30F24, 0x6A7006FC, 0x606C362C, 0x66E005FC, ++0x6A5C64AC, 0x626C24AA, 0x89053420, 0x4D084D08, ++0xCB0460D3, 0x600BA006, 0x7D014110, 0x8FD67701, ++0xE0007E01, 0x3F3C9308, 0x6EF64F26, 0x6CF66DF6, ++0x000B6BF6, 0x01386AF6, 0x00000120, 0x00200D54, ++0x002002BE, 0x00102800, 0x00200D64, 0x0010F00A, ++0x0010F000, 0x001C001C, 0x00103252, 0x00200DA0, ++0x0010FFFC, 0x00200D7C, 0x0020032C, 0x00200370, ++0x00200954, 0x0009000B, 0x2FD62FC6, 0x4F222FE6, ++0x6D436C53, 0xEE00A004, 0x7E0164D4, 0x644CBFF2, ++0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, 0xE5006CF6, ++0x6643A002, 0x76017501, 0x22286260, 0xAFE38BFA, ++0x2FE60009, 0x75076253, 0xE1086753, 0x6043EE0A, ++0x4409C90F, 0x650330E2, 0x8D014409, 0xE630E637, ++0x4110365C, 0x8FF22760, 0xE00077FF, 0x000B8028, ++0x4F226EF6, 0xBFE47FEC, 0xBFD865F3, 0x7F1464F3, ++0x000B4F26, 0x4F22E000, 0xBFDA7FEC, 0x64F365F3, ++0x7406BFCD, 0x4F267F14, 0xE000000B, 0x4F222FE6, ++0x62537FEC, 0x65F36E43, 0x6423BFCB, 0x64E3BFBF, ++0x64F3BFBD, 0xBFBAD403, 0x7F140009, 0x000B4F26, ++0x00006EF6, 0x00200DB0, 0x89004011, 0x4111600B, ++0x4F228906, 0x611BB004, 0x000B4F26, 0x0009600B, ++0x620D2F26, 0x8F413020, 0x40180019, 0x8B0D3016, ++0x31043104, 0x31043104, 0x31043104, 0x31043104, ++0x890062F6, 0x4119310C, 0x6013000B, 0x41296219, ++0x20084018, 0x31048927, 0x31043104, 0x31043104, ++0x31043104, 0x31043104, 0x31043104, 0x31043104, ++0x31043104, 0x61193104, 0x3204221D, 0x32043204, ++0x32043204, 0x32043204, 0x32043204, 0x32043204, ++0x32043204, 0x32043204, 0x89003204, 0x4229320C, ++0x000B6023, 0xE00062F6, 0x62F6000B, 0x42286213, ++0x42244129, 0x42243104, 0x42243104, 0x42243104, ++0x42243104, 0x42243104, 0x42243104, 0x42243104, ++0x42243104, 0x42243104, 0x42243104, 0x42243104, ++0x42243104, 0x42243104, 0x42243104, 0x42243104, ++0x89003104, 0x6013310C, 0x62F6000B, 0x2F262F16, ++0x51F552F3, 0x52F22129, 0x52F41210, 0x212951F6, ++0x121152F2, 0x000B62F6, 0x000061F6, 0x51F32F16, ++0x310050F1, 0x51F48B02, 0x310050F2, 0x000B0029, ++0x000061F6, 0x51F32F16, 0x310050F1, 0x51F48B06, ++0x310050F2, 0xCA010029, 0x61F6000B, 0x000BE001, ++0x000061F6, 0x50F0000B, 0x2F262F16, 0xE10052F2, ++0x12001211, 0x000B62F6, 0x000061F6, 0x2F162F06, ++0x8B264115, 0x3103E040, 0x2F26892B, 0x52F62F36, ++0xE02053F5, 0x8B053103, 0xE3006233, 0x89093100, ++0x3108A002, 0x8B0F2338, 0xD0064F22, 0x6023400B, ++0x4F266203, 0x112151F4, 0x63F61130, 0x61F662F6, ++0x60F6000B, 0x002007F4, 0x4100C709, 0x0123011D, ++0x51F20009, 0x110150F4, 0x110050F3, 0x000B61F6, ++0x51F260F6, 0x1101E000, 0x61F61100, 0x60F6000B, ++0x01300000, 0x0128012C, 0x01200124, 0x0118011C, ++0x0106010A, 0x00FE0102, 0x00E200E6, 0x00DA00DE, ++0x00CC00D0, 0x00C400C8, 0x00A800AC, 0x00A000A4, ++0x008C0090, 0x00840088, 0x0066006A, 0x005E0062, ++0x42244300, 0x42244300, 0x42244300, 0x43286133, ++0x43084318, 0x42284308, 0x42084218, 0x41094208, ++0xAFAF4109, 0x4300221B, 0x43004224, 0x43004224, ++0x61334224, 0x43184328, 0x42184228, 0xAFA14119, ++0x4300221B, 0x43004224, 0x43004224, 0x61334224, ++0x43084328, 0x42284308, 0x42084208, 0x41094119, ++0xAF8F4109, 0x4300221B, 0x43004224, 0x43004224, ++0x61334224, 0x212D4328, 0x6213AF84, 0x42244300, ++0x42244300, 0x42244300, 0x43186133, 0x43084308, ++0x42084218, 0x41294208, 0x41094109, 0x221BAF72, ++0x42244300, 0x42244300, 0x42244300, 0x43186133, ++0x41294218, 0xAF654119, 0x4300221B, 0x43004224, ++0x43004224, 0x43004224, 0x43004224, 0x43004224, ++0x43004224, 0x4224AF56, 0x2F162F06, 0x8B264115, ++0x3103E040, 0x2F26892B, 0x52F62F36, 0xE02053F5, ++0x8B053103, 0xE2006323, 0x89093100, 0x3108A002, ++0x8B0F2228, 0xD0064F22, 0x6033400B, 0x4F266303, ++0x112151F4, 0x63F61130, 0x61F662F6, 0x60F6000B, ++0x002008B4, 0x4100C709, 0x0123011D, 0x51F20009, ++0x110150F4, 0x110050F3, 0x000B61F6, 0x51F260F6, ++0x1101E000, 0x61F61100, 0x60F6000B, 0x012E0000, ++0x0126012A, 0x011E0122, 0x0116011A, 0x01040108, ++0x00FC0100, 0x00E000E4, 0x00D800DC, 0x00CC00D0, ++0x00C400C8, 0x00A800AC, 0x00A000A4, 0x008C0090, ++0x00840088, 0x0066006A, 0x005E0062, 0x43254201, ++0x43254201, 0x43254201, 0x42296123, 0x42094219, ++0x43294209, 0x43094319, 0x41084309, 0xAFAF4108, ++0x4201231B, 0x42014325, 0x42014325, 0x61234325, ++0x42194229, 0x43194329, 0xAFA14118, 0x4201231B, ++0x42014325, 0x42014325, 0x61234325, 0x42094229, ++0x43294209, 0x43094309, 0x41084118, 0xAF8F4108, ++0x4201231B, 0x42014325, 0x42014325, 0x61234325, ++0xAF854229, 0x4201231D, 0x42014325, 0x42014325, ++0x61234325, 0x42094219, 0x43194209, 0x43094309, ++0x41084128, 0xAF734108, 0x4201231B, 0x42014325, ++0x42014325, 0x61234325, 0x43194219, 0x41184128, ++0x231BAF66, 0x43254201, 0x43254201, 0x43254201, ++0x43254201, 0x43254201, 0x43254201, 0xAF574201, ++0x00004325, 0x080A0C0E, 0x00020406, 0x1A1C1E20, ++0x12141618, 0x2E303234, 0x26282A2C, 0x3A3C3E40, ++0x6C625648, 0x41112F26, 0xE2208F18, 0x890B3123, ++0x321CD204, 0xD1026220, 0x412B312C, 0x00090009, ++0x0020081E, 0x002007D4, 0x000BE000, 0x400062F6, ++0x40004000, 0x40004000, 0x40004000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40184000, ++0x62F6000B, 0x40004000, 0x40004000, 0x40004000, ++0x40284000, 0x62F6000B, 0x40004000, 0x40184000, ++0x000B4028, 0xC90F62F6, 0x40054005, 0x40054005, ++0x62F6000B, 0x4005C907, 0x40054005, 0x62F6000B, ++0x4005C903, 0x000B4005, 0xC90162F6, 0x000B4005, ++0x000062F6, 0x080A0C0E, 0x00020406, 0x1A1C1E20, ++0x12141618, 0x2E303234, 0x26282A2C, 0x3A3C3E40, ++0x6C625648, 0x41112F26, 0xE2208F18, 0x890B3123, ++0x321CD204, 0xD1026220, 0x412B312C, 0x00090009, ++0x002008DE, 0x00200894, 0x000BE000, 0x400162F6, ++0x40014001, 0x40014001, 0x40014001, 0x62F6000B, ++0x40014001, 0x40014001, 0x40014001, 0x40194001, ++0x62F6000B, 0x40014001, 0x40014001, 0x40014001, ++0x40294001, 0x62F6000B, 0x40014001, 0x40194001, ++0x000B4029, 0x400462F6, 0x40044004, 0xC90F4004, ++0x62F6000B, 0x40044004, 0xC9074004, 0x62F6000B, ++0x40044004, 0x000BC903, 0x400462F6, 0x000BC901, ++0x000062F6, 0x00000000, 0x77073096, 0xEE0E612C, ++0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, ++0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, ++0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, ++0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, ++0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, ++0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, ++0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, ++0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, ++0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, ++0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, ++0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, ++0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, ++0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, ++0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, ++0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, ++0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, ++0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, ++0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, ++0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, ++0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, ++0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, ++0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, ++0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, ++0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, ++0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, ++0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, ++0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, ++0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, ++0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, ++0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, ++0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, ++0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, ++0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, ++0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, ++0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, ++0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, ++0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, ++0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, ++0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, ++0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, ++0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, ++0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, ++0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, ++0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, ++0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, ++0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, ++0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, ++0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, ++0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, ++0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, ++0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, ++0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, ++0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, ++0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, ++0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, ++0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, ++0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, ++0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, ++0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, ++0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, ++0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, ++0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, ++0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, ++0x2D02EF8D, 0x544F0D0A, 0x50205355, 0x20312D48, ++0x003A5746, 0x72636564, 0x69747079, 0x65206E6F, ++0x726F7272, 0x0A0D2121, 0x00000000, 0x6564667A, ++0x70797263, 0x65725F74, 0x616C7567, 0x79726F74, ++0x6261745F, 0x7220656C, 0x203D7465, 0x00000000, ++0x45485441, 0x38731652, 0x89ACFF91, 0xEE55D178, ++0xEE000D0A, }; ++ ++const u32_t zcFwImageSize=3508; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu_OTUS_RC.c +@@ -0,0 +1,715 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE287FFC, 0xE114D728, ++0x1E13D428, 0x1E4C470B, 0x0009B018, 0xA0039543, ++0x3652E600, 0x76018D04, 0xC84060E2, 0x2F028DF9, ++0xDE22D421, 0x00094E0B, 0x4E0BD421, 0xD4210009, ++0x00094E0B, 0x4F267F04, 0x6EF6A022, 0xD11E4F22, ++0x0009410B, 0x440BD41D, 0xD51D0009, 0x0009450B, ++0xE1FFD71C, 0xD21C611D, 0x50292712, 0xCB01E1FF, ++0xD61BD41A, 0x22121209, 0xE5011211, 0x2452E200, ++0xD5182622, 0x970FD618, 0x4F262572, 0x2620000B, ++0xDD17DC16, 0x4C0BDE17, 0x4D0B0009, 0x4E0B0009, ++0xAFF80009, 0x27100009, 0x00000640, 0x001C001C, ++0x002008EA, 0x0000B38E, 0x002028DC, 0x00200DA6, ++0x002028E8, 0x00202900, 0x00200C6C, 0x00200EA2, ++0x00200940, 0x001C3510, 0x001C3624, 0x001E212C, ++0x00202894, 0x0020288C, 0x002027F0, 0x00200B68, ++0x00201F74, 0x00201734, 0x2FD62FC6, 0x4F222FE6, ++0xDEA17FA4, 0x61E0E01C, 0x7D016DE3, 0x61D00F14, ++0xD59FD49E, 0x450BE020, 0xE0200F14, 0xE78004FC, ++0x604C66E2, 0x7D7F677C, 0x1F693070, 0x2D628F17, ++0x01FCE01C, 0x641CE500, 0xD797DE96, 0x3243625D, ++0xA21A8B01, 0x655D0009, 0x31EC6153, 0xE0286C10, ++0x6D530FC4, 0x3D7C62CE, 0xAFEF2D20, 0x20087501, ++0xE01C8B15, 0xE50001FC, 0xD78BDE8A, 0x641CA00A, ++0x6C53655D, 0x66C23CEC, 0x66626253, 0x2262327C, ++0x1F697504, 0x3243625D, 0xA1F68BF2, 0x88012D10, ++0xE01C8B16, 0xE40001FC, 0x671C2D40, 0x624DDE7D, ++0x8B013273, 0x0009A1E9, 0x62E3644D, 0x72046D43, ++0x3DEC6143, 0x65D2312C, 0x74086C12, 0x25C2AFEF, ++0x8B188804, 0x01FCE01C, 0x2D40E400, 0xDE71671C, ++0x3273624D, 0xA1D08B01, 0x644D0009, 0x62E36D43, ++0x65D23DEC, 0x61437204, 0x6612312C, 0x74086C52, ++0xAFED2C69, 0x880525C2, 0xE01C8B18, 0xE40001FC, ++0x671C2D40, 0x624DDE63, 0x8B013273, 0x0009A1B5, ++0x6C43644D, 0x3CEC62E3, 0x720465C2, 0x3D2C6D43, ++0x615266D2, 0x216B7408, 0x2512AFED, 0x8B138830, ++0xE200DE58, 0x64E22D20, 0x8B042448, 0x420BD257, ++0xA19A0009, 0x55E10009, 0x57E356E2, 0xDD545CE4, ++0x2FC64D0B, 0x7F04A191, 0x89018828, 0x0009A0EA, ++0xE143DE4C, 0x622D62E1, 0x8F033217, 0x56FB1FEB, ++0x2621E240, 0x8B013217, 0x0009A0D5, 0xE1015EFB, ++0x301685E1, 0xA0CE8B01, 0xE4010009, 0x2D4055FB, ++0x6451B179, 0xE14357FB, 0xE0546271, 0x3517652D, ++0x0F568D41, 0x3563E640, 0xE6008B05, 0x0F65E034, ++0xA00FE11A, 0x615372C0, 0x41214121, 0x41214121, ++0x45214121, 0x45214521, 0xC9036053, 0xE0346603, ++0x71180F65, 0x2209E007, 0x641DE030, 0x0F2565F3, ++0x1F4EB1F1, 0x04FDE034, 0x674DE030, 0x47080CFD, ++0x607361CD, 0x4108D22B, 0xE00F0CFE, 0x1F1F420B, ++0x2CD96D07, 0x5EFB6073, 0x85E20FC6, 0x420B51FF, ++0x2C0B600D, 0x54FE6073, 0xB1BB0FC6, 0xE05465F3, ++0x652D62E1, 0xE6400F56, 0x89623563, 0xE050E100, ++0x60230F15, 0x4008C903, 0x6D034000, 0xE0406103, ++0xE0440FD6, 0xD217EEFF, 0x6EEC0FF6, 0x0F26E058, ++0x60E3420B, 0x42216253, 0x42214221, 0x66234221, ++0x326C4200, 0x45214200, 0xE0486707, 0x0F764521, ++0xC9036053, 0x40085CFB, 0x7C0630FC, 0x6E036D2D, ++0x1FD51FC6, 0x1F04A02E, 0x00117D00, 0x00202904, ++0x00200DA6, 0x00117D04, 0x00117D84, 0x00200700, ++0x0020074C, 0x00201FD4, 0x0FD6E04C, 0x05FEE044, ++0x64D3B189, 0x64E2E048, 0xE04006FE, 0x2E422469, ++0x01FE67C4, 0x667CE058, 0x420B02FE, 0x240B6063, ++0x05FEE044, 0xB15D2E42, 0xE05064D3, 0x7D0101FD, ++0x0F157101, 0x02FDE050, 0x3262E606, 0x56FB8BDC, ++0x55FB6261, 0x85514200, 0x302C750C, 0x6103701B, ++0x64F3E600, 0xE704A004, 0x76016256, 0x74042422, ++0x3273626D, 0x65F38BF8, 0x641DB13C, 0xB0D256FB, ++0xA0AA6461, 0xD4880009, 0xE201D588, 0x2D20450B, ++0x0009A0A3, 0x8B078829, 0xE200DE85, 0x66E22D20, ++0x646DB0A1, 0x0009A099, 0x622CE281, 0x8B3D3020, ++0xD680E738, 0xE0442D70, 0xE0480C6E, 0x6E621DC1, ++0x51611DE2, 0x54621D13, 0x55651D44, 0x57631D55, ++0x5C661D76, 0x0E6E1DC7, 0x1DE8E040, 0xE050016E, ++0x54641D19, 0x056E1D4A, 0x1D5BE04C, 0xE054076E, ++0x0C6E1D7C, 0x1DCDE058, 0xE044026E, 0xED001D2E, ++0xE04806D6, 0x16D126D2, 0x16D516D2, 0x16D616D3, ++0xE04006D6, 0xE05006D6, 0x06D616D4, 0x06D6E04C, ++0x06D6E054, 0x06D6E058, 0x1F29A057, 0x622CE282, ++0x89313020, 0x05FCE020, 0x625CE683, 0x3260666C, ++0xD65D8B07, 0x2650E500, 0x52617680, 0xA044D65B, ++0xE6902622, 0x3260666C, 0xD2578B16, 0xE500D658, ++0x60622250, 0xCB20D257, 0xE6052602, 0xD6562262, ++0x2252460B, 0x420BD255, 0xD2550009, 0x2262E601, ++0x4618D254, 0x2262A029, 0xD254D453, 0xD4546542, ++0x0009420B, 0x0009A021, 0xE524D647, 0xD5452650, ++0x16215257, 0x16225258, 0x16235259, 0x1624525A, ++0x1625525B, 0x1626525C, 0x1627525D, 0x1628525E, ++0x1F29525F, 0xE2001629, 0x15281527, 0x152A1529, ++0x152C152B, 0x152E152D, 0x7F5C152F, 0x6EF64F26, ++0x000B6DF6, 0x4F226CF6, 0xE240614D, 0x89173123, ++0x3127E21F, 0xD43B8908, 0xE001D53B, 0x6642450B, ++0x26796707, 0x2462A00C, 0x3127E23F, 0xD7358908, ++0x71E0D635, 0x460BE001, 0x62075571, 0x17512529, ++0x000B4F26, 0x4F220009, 0xE240614D, 0x89153123, ++0x3127E21F, 0xD42B8907, 0x6642D22B, 0xE001420B, ++0xA00B260B, 0xE23F2462, 0x89073127, 0xD626D725, ++0x71E05571, 0xE001460B, 0x1751250B, 0x000B4F26, ++0xE6400009, 0x46284618, 0x6252D520, 0x89FC2268, ++0x0009000B, 0x4618E680, 0xD51C4628, 0x22686252, ++0x000B89FC, 0xA0010009, 0x7201E200, 0x8BFC3242, ++0x0009000B, 0x4618E680, 0xD5154628, 0x22686252, ++0x000B8BFC, 0x00000009, 0x00202908, 0x00200DA6, ++0x00117D04, 0x002027F8, 0x00117D80, 0x0020288C, ++0x001C3500, 0x001D4004, 0x00200EA2, 0x00200940, ++0x001E212C, 0x001C3D28, 0x00117D00, 0x00200E06, ++0x00202920, 0x001C3704, 0x00201FD4, 0x001C373C, ++0x001C3700, 0x4F222FE6, 0x6E537FFC, 0x2F42BFCA, ++0xD61561E2, 0x1615E280, 0x421854E1, 0x55E21646, ++0x16574228, 0x6EF257E3, 0x2E2B1678, 0x7F0426E2, ++0xAFA74F26, 0x2FC66EF6, 0x2FE62FD6, 0xDD0A4F22, ++0xBFAF6C53, 0xBF946E43, 0xBFAB2DE2, 0x51D50009, ++0x54D62C12, 0x55D71C41, 0x56D81C52, 0x4F261C63, ++0x6DF66EF6, 0x6CF6000B, 0x001C370C, 0x0009A0C0, ++0xD17B4F22, 0xD47B92B6, 0x2122B00D, 0x97B2E605, ++0xB02295B2, 0xB0366463, 0xB0360009, 0xB0390009, ++0xA0680009, 0x4F124F26, 0xD1734F02, 0x94A43145, ++0x4609060A, 0x46094609, 0x00293646, 0xD76CD56F, ++0x2500CA01, 0x4F062762, 0x4F16000B, 0xBFEA4F22, ++0xB01F0009, 0xA04E0009, 0x2FE64F26, 0x6E63D168, ++0x44186612, 0x4528928A, 0x26294408, 0x44084500, ++0x4400265B, 0x4708264B, 0x47082162, 0x27EBD161, ++0x000B2172, 0x000B6EF6, 0xD25F0009, 0xE40A9677, ++0x2262AFB4, 0x2FC62FB6, 0x2FE62FD6, 0xDC5B4F22, ++0x2C22E201, 0xBFA9E40A, 0x60C27C44, 0xCB01ED00, ++0x60C22C02, 0xC901EB64, 0x6E03A008, 0x89073DB2, ++0xE40160C2, 0xBF99C901, 0x7D016E03, 0x8BF52EE8, ++0x8B033DB2, 0xD24FD44E, 0x0009420B, 0x4F26E40A, ++0x6DF66EF6, 0xAF896CF6, 0x44116BF6, 0x604B8F01, ++0x000B6043, 0x2FB60009, 0x2FD62FC6, 0x4F222FE6, ++0xDC457FFC, 0x60C2ED00, 0xCB02EB64, 0x60C22C02, ++0xC9022F02, 0x6E03A009, 0x89083DB3, 0xE46460C2, ++0xC9022F02, 0x6E03BF6A, 0x2EE87D01, 0xD73B8BF4, ++0x617251C1, 0xDE3BDC3A, 0xD23CD13B, 0x64C23DB3, ++0x651264E2, 0x65228F09, 0xD232D439, 0x4F267F04, ++0x6DF66EF6, 0x422B6CF6, 0x7F046BF6, 0x6EF64F26, ++0x6CF66DF6, 0x6BF6000B, 0x5651D532, 0x46286052, ++0x306C000B, 0x5288096C, 0x09B45BB4, 0x03C41FFF, ++0x2FC62FB6, 0x2FE62FD6, 0x4F124F22, 0xBFEB4F02, ++0x6B036E43, 0xDD18DC28, 0x0009BFE6, 0x3C0530B8, ++0x4609060A, 0x46014609, 0x020A3D65, 0x42094209, ++0x32E24209, 0x4F068BF0, 0x4F264F16, 0x6DF66EF6, ++0x000B6CF6, 0x2FE66BF6, 0xDE1C4F22, 0xE500E102, ++0x2E12E403, 0x2E52BFD4, 0x4618E606, 0xE403E700, ++0x2E722E62, 0xAFCB4F26, 0x000B6EF6, 0x00000009, ++0x00202890, 0x0024CDE0, 0x10624DD3, 0x00202A8C, ++0x001C5814, 0x001C59D0, 0x001C5804, 0x001C581C, ++0x00202934, 0x00200DA6, 0x001C5860, 0x001C6864, ++0x001C7864, 0x001C59BC, 0x001C69BC, 0x001C79BC, ++0x0020294C, 0x001C1040, 0xCCCCCCCD, 0x001D4004, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xE4007FE4, 0x4528E510, 0x67436C43, 0xE107A00F, ++0x6043644D, 0x0F564008, 0xEE0060C3, 0x815125C1, ++0x81538152, 0x157315E2, 0x751415E4, 0x624D7401, ++0x8BED3213, 0xDA6F51F1, 0x1A1154F2, 0xD16E2A12, ++0x57F455F3, 0x6DF258F5, 0x1141D96C, 0x11532142, ++0x11751152, 0x11871174, 0x52F61186, 0x19D1D668, ++0xD86829D2, 0xDA68E950, 0x1621EBB4, 0x6BBC2622, ++0xA0214908, 0x6EEDEE00, 0x61E36DE3, 0x41084D08, ++0x31EC3DEC, 0x41084D08, 0x60C33D8C, 0xE7904108, ++0x81D12DC1, 0x41086093, 0x81D2677C, 0x31AC60C3, ++0x3472E200, 0x1DD281D3, 0xD4551D13, 0x1D248D01, ++0xB03AD450, 0x7E0165D3, 0x34B264ED, 0xD14D8BDB, ++0x6512DB52, 0x4529D24D, 0x64121B51, 0x674DD14A, ++0x67222B72, 0x4729D64E, 0x69221B73, 0x689D2FD2, ++0x69121B82, 0x5A122692, 0x5B1416A2, 0x16B4DA44, ++0x16C65C16, 0x16EA6EA2, 0x4F267F1C, 0x6DF66EF6, ++0x6BF66CF6, 0x69F66AF6, 0x68F6000B, 0x60616642, ++0x8D04C803, 0x6061E500, 0x8802C903, 0x52628B03, ++0x51246563, 0x000B2412, 0x2FD66053, 0x4F222FE6, ++0x6E537FEC, 0xE5506253, 0xE4006D43, 0xA0014508, ++0x5224E101, 0x22116043, 0x81238121, 0x81226053, ++0x362056E2, 0xD22F8BF5, 0x64F316E4, 0x420BE614, ++0x65E165E3, 0x2549E4FC, 0x61F12E51, 0x214965F3, ++0x54D12F11, 0x410BD127, 0x57D1E614, 0xCB016071, ++0x1DE12701, 0x4F267F14, 0x000B6EF6, 0x2FD66DF6, ++0x4F222FE6, 0x6E537FEC, 0xE5FC6653, 0x60616D43, ++0xCB012059, 0x52E22601, 0x8B063260, 0x51E212E4, ++0x8B0431E0, 0xA00252D1, 0xAFF01E22, 0xD2155664, ++0xE61464F3, 0x65E3420B, 0xE1FC67E1, 0x2E712719, ++0x54D167F1, 0xD10F2719, 0xE61465F3, 0x2F71410B, ++0x602152D1, 0x2201CB01, 0x7F141DE1, 0x6EF64F26, ++0x6DF6000B, 0x0020285C, 0x00202864, 0x00202854, ++0x00202884, 0x0010008C, 0x00100EC0, 0x001E2108, ++0x001C3D00, 0x00202134, 0x2FC62FB6, 0x2FE62FD6, ++0xD6314F22, 0x60D36D62, 0x894DC803, 0xDB30DC2F, ++0x0009A02C, 0xC9036061, 0x892B8801, 0xD22DD42B, ++0x0009420B, 0x65035603, 0xC8208561, 0xE0508903, ++0x720102BE, 0x85620B26, 0x4000600D, 0x4000366A, ++0x40004624, 0x206D4624, 0xD423C903, 0x40086E03, ++0xD1224000, 0x340C410B, 0x61E3D521, 0xD721E001, ++0x450BD221, 0x64E37E30, 0x2702420B, 0x66C252C1, ++0x8BCF3620, 0x4E18EE01, 0xA011DB1C, 0x6061EC75, ++0x8801C903, 0xD4198910, 0x460BD612, 0xD4180009, ++0x470BD718, 0xD2136503, 0x64C3D113, 0x22E2410B, ++0x66B252B1, 0x8BEA3620, 0xC80460D3, 0xD2128906, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, 0x6EF64F26, ++0x6CF66DF6, 0x6BF6000B, 0x001E2100, 0x0020285C, ++0x002027F8, 0x00200A5C, 0x00202864, 0x00200ADE, ++0x00201FD4, 0x001C3D30, 0x00200D6C, 0x00202854, ++0x00202884, 0x00200A7A, 0x002000F8, 0xE601D237, ++0x1265D537, 0x000B2252, 0xD6361266, 0x88016062, ++0xE1018B62, 0xD5342612, 0x5451D134, 0xE0406212, ++0x2122324C, 0x54115752, 0x1141347C, 0x57125453, ++0x1172374C, 0x52135755, 0x1123327C, 0x56146452, ++0x1164364C, 0x54155754, 0x1145347C, 0x56165458, ++0x1166364C, 0x6762D626, 0x327C5217, 0x57611127, ++0x327C5218, 0x57621128, 0x327C5219, 0x57631129, ++0x347C541A, 0x5764114A, 0x347C541B, 0x5765114B, ++0x347C541C, 0x5266114C, 0x372C571D, 0x5267117D, ++0x342C541E, 0x5268114E, 0x362C561F, 0xD615116F, ++0x041E6262, 0x342C7694, 0xE0440146, 0x061E6262, ++0x0166362C, 0x525CE048, 0xD60F051E, 0x0156352C, ++0xE0546262, 0x4229051E, 0x0156352C, 0xE0585561, ++0x4529061E, 0x0166365C, 0x0009000B, 0x001C1010, ++0x0000C34F, 0x001C1028, 0x001C369C, 0x002027F8, ++0x001C3CA0, 0x001C36F4, 0x001C3B88, 0xD62F7FFC, ++0x2642644C, 0xC8205066, 0x2F028DFC, 0x7F04000B, ++0x2FD62FC6, 0x4F222FE6, 0x6D436C53, 0xEE00A004, ++0x7E0164D4, 0x644CBFEA, 0x8BF93EC2, 0x6EF64F26, ++0x000B6DF6, 0xA0016CF6, 0x76016643, 0x22286260, ++0x36488BFB, 0x6563AFE4, 0x2FB62F96, 0x2FD62FC6, ++0x4F222FE6, 0xEC1CED08, 0xDB196E53, 0x61C3E90A, ++0x60434B0B, 0x3092C90F, 0x66038D02, 0x7630A001, ++0x4D107637, 0x7E012E60, 0x7CFC8FF1, 0x8058E000, ++0x6EF64F26, 0x6CF66DF6, 0x000B6BF6, 0x000B69F6, ++0x000BE000, 0x2FE6E000, 0x7FEC4F22, 0x6E436253, ++0xBFD165F3, 0xBFC66423, 0xBFC464E3, 0xD40564F3, ++0x0009BFC1, 0x4F267F14, 0x6EF6000B, 0x001C0004, ++0x00202094, 0x00202968, 0xE110D59C, 0xE6406050, ++0x2500C9FD, 0xE0FF75E9, 0x80516453, 0x80538052, ++0x80568055, 0x251075EF, 0xE1EF6250, 0x2219E001, ++0xE7202520, 0x24608052, 0x2570000B, 0xE4FDD590, ++0xE7026152, 0x25122149, 0x74016052, 0x2502CB01, ++0xD18C6652, 0x25622649, 0x92C26012, 0x2102CB08, ++0xC9CF6012, 0x60122102, 0x2102CB03, 0x000B1172, ++0x4F221123, 0xE100D484, 0xD285D784, 0xD5852410, ++0x2711D485, 0x2211E700, 0xBFBD2511, 0xD5832471, ++0x2560E600, 0x4F26AFD2, 0xD281664C, 0x362C4600, ++0xCB106060, 0x2600000B, 0xD27D654C, 0x352C4500, ++0xE1EF6650, 0x000B2619, 0x664C2560, 0x4600D279, ++0x6060362C, 0x000BCB10, 0x654C2600, 0x4500D275, ++0x6650352C, 0x2619E1EF, 0x2560000B, 0xD270664C, ++0x362C4600, 0xCB086060, 0x2600000B, 0xD26C654C, ++0x352C4500, 0xE1F76650, 0x000B2619, 0x664C2560, ++0x4600D268, 0x6060362C, 0x000BCB08, 0x654C2600, ++0x4500D264, 0x6650352C, 0x2619E1F7, 0x2560000B, ++0xD65F624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0x624C600C, 0x4200D65A, 0x6020326C, ++0x4021C908, 0x40214021, 0x600C000B, 0xD156644C, ++0x341C74FF, 0x000B6240, 0xD154602C, 0x341C644C, ++0x000B6240, 0x2FE6602C, 0x655C4F22, 0x3567E60A, ++0x6E438D15, 0x6453BFEA, 0x60EC640C, 0x8B028801, ++0xA002E00F, 0x44092409, 0x624C4409, 0x3263E60A, ++0xBFE28905, 0x620C644C, 0xC8806023, 0xE2008B00, ++0x4F266023, 0x6EF6000B, 0xD6414F22, 0x88016062, ++0xB2228B03, 0xA0030009, 0xD23E0009, 0x2260E640, ++0xE200D63D, 0x000B4F26, 0x4F222622, 0x6062D638, ++0x8B018802, 0x0009B26C, 0xE200D637, 0x000B4F26, ++0x0FFF2622, 0xD433D532, 0xE701E100, 0x000B2512, ++0xD2302470, 0x000BE604, 0xD5202260, 0x6150E4FD, ++0x2149D62E, 0x2510E700, 0x2670000B, 0xE4FBD51B, ++0x22496250, 0x2520000B, 0xE4F7D518, 0x22496250, ++0x2520000B, 0xD2264F22, 0x600D8522, 0x89112008, ++0x89138801, 0x89158803, 0x89178805, 0x89418806, ++0x89478808, 0x894D8809, 0x8953880A, 0x8959880B, ++0x0009A060, 0x0009B062, 0x600CA05D, 0x0009B070, ++0x600CA059, 0x0009B07A, 0x600CA055, 0x6260D606, ++0x8B4F2228, 0x0009B086, 0x600CA04D, 0x001E1028, ++0x001E2148, 0x001E1108, 0x002028D9, 0x002028C8, ++0x002028CA, 0x002028CC, 0x002028AC, 0x001E1008, ++0x001E103F, 0x001E105F, 0x001E1030, 0x001E1090, ++0x002028D4, 0x001E100B, 0x002028D0, 0x002028D8, ++0x002028A0, 0x6260D687, 0x8B232228, 0x0009B06A, ++0x600CA021, 0x6260D683, 0x8B1B2228, 0x0009B0B4, ++0x600CA019, 0x6260D67F, 0x8B132228, 0x0009B0BA, ++0x600CA011, 0x6260D67B, 0x8B0B2228, 0x0009B11E, ++0x600CA009, 0x6260D677, 0x8B032228, 0x0009B136, ++0x600CA001, 0x4F26E000, 0x0009000B, 0xD273D172, ++0xD5738412, 0x4000C90F, 0xD772012D, 0x611CE403, ++0xD671E20F, 0x27122540, 0xE0012520, 0x2602000B, ++0xE601D269, 0x30668523, 0xE0008D06, 0xE000D267, ++0x8122D669, 0x2602E001, 0x0009000B, 0x8523D262, ++0x2008600D, 0x88018905, 0xD6648B0A, 0xCB016060, ++0xD6612600, 0xE101D45D, 0x2612E001, 0x8142000B, ++0xE000000B, 0xE501D158, 0x45188513, 0x3453640D, ++0x8D056603, 0xD25AE000, 0xE001D557, 0x25022260, ++0x0009000B, 0xD1504F22, 0x650D8513, 0x44196453, ++0x672E6249, 0x602C227D, 0x89098801, 0x890C8802, ++0x89108803, 0x89268806, 0x89298807, 0x0009A038, ++0xD64DD54C, 0xA027E212, 0x625C2652, 0x8B2F2228, ++0xA01ED64A, 0x605C6262, 0x89052008, 0x89088810, ++0x890B8820, 0x0009A024, 0xD643D445, 0xA013E204, ++0xD7442642, 0xE20CD640, 0x2672A00E, 0xD63ED542, ++0xA009E218, 0xD4412652, 0xE20AD63B, 0x2642A004, ++0xD639D23F, 0xE22E2622, 0xD43E8515, 0x3277670D, ++0x8F012421, 0x24516503, 0x0009B0DF, 0xE001A001, ++0x4F26E000, 0x0009000B, 0xE101D629, 0x2610D436, ++0xD7286541, 0x655DD128, 0xE001E20F, 0x26202752, ++0x2102000B, 0x4F222FE6, 0x8523D21F, 0x2448640C, ++0xD62D8B08, 0xE200D521, 0x84512621, 0x20499430, ++0x8051A026, 0x60E0DE1D, 0x8D0BC840, 0x3427E201, ++0xD1258922, 0x420BD225, 0xD5252141, 0xCB046052, ++0x2502A00B, 0x89173427, 0xD722D21F, 0x2241470B, ++0xE5FBD61F, 0x21596162, 0x84E12612, 0xB12DCB80, ++0x60E080E1, 0xCB04D61C, 0x60602E00, 0x2600C93F, ++0xE001D609, 0x2602A001, 0x4F26E000, 0x6EF6000B, ++0x0000FF7F, 0x002028D9, 0x002028A0, 0x002028AC, ++0x001E1100, 0x001E100C, 0x002028D0, 0x001E1000, ++0x001E1001, 0x00202A90, 0x002028B4, 0x002028BC, ++0x00202AFE, 0x00202B02, 0x00202B0E, 0x00202B26, ++0x00202B30, 0x002028B8, 0x002028C6, 0x00201A32, ++0x001E1108, 0x00201B3E, 0x001E1015, 0x6060D696, ++0x8919C880, 0x6021D295, 0x8B158801, 0xE501D294, ++0x30568524, 0xD1938910, 0xD493E203, 0x65412120, ++0x655DE00B, 0xD5910656, 0xE702E40F, 0x25712140, ++0xE001D78F, 0x2702000B, 0xE000000B, 0x4F222FE6, ++0x84E1DE8C, 0x8934C880, 0x8554D585, 0x8F302008, ++0xD7896103, 0x66728553, 0x650C6403, 0x620C8566, ++0x8B263520, 0xD780D685, 0x644C651C, 0x27412651, ++0xC84060E0, 0xD2828907, 0x0009420B, 0x6062D681, ++0xA008CB04, 0xD1802602, 0x0009410B, 0xE5FBD67D, ++0x24596462, 0xB0A12642, 0xD5750009, 0x2522E201, ++0xD77A60E0, 0x2E00CB04, 0xC93F6070, 0xA0012700, ++0xE0006023, 0x000B4F26, 0x2FA66EF6, 0x2FC62FB6, ++0x2FE62FD6, 0xE240DA69, 0xDC6666A1, 0x3123616D, ++0x62638900, 0x6ED36D2C, 0x4E2136D8, 0x4E212A61, ++0xDB6CD46B, 0xE700A00F, 0x770166B2, 0x71026163, ++0x65612B12, 0x71026613, 0x62612B12, 0x622D655D, ++0x325C4228, 0x627C2422, 0x8BED32E3, 0xC90360D3, ++0x8B108803, 0xED076EB2, 0x710261E3, 0x67132B12, ++0x62E17102, 0x65712B12, 0x655D622D, 0x352C4528, ++0xA00C2CD0, 0x88022452, 0xA0038B01, 0x8801E203, ++0xE2018B05, 0x66B22C20, 0x677D6761, 0xEB0F2472, ++0x6DA12CB0, 0x8B052DD8, 0xD445D24F, 0xE101EE00, ++0x241222E2, 0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, ++0x2FE62FD6, 0xE240DD3D, 0x616D66D1, 0x89003123, ++0x672C6263, 0xDE433678, 0x2D617703, 0xD6404721, ++0x472164E2, 0xE100A00E, 0x71016562, 0x24506253, ++0x42197401, 0x74012420, 0x24504529, 0x45197401, ++0x74012450, 0x3273621C, 0x42008BEE, 0x64D166E2, ++0x362C4200, 0x8F062448, 0xDD332E62, 0xE500DE28, ++0x2D52E701, 0x6EF62E72, 0x6DF6000B, 0x2FE62FD6, ++0xEE014F22, 0xED0AA005, 0x64E3BCB6, 0x64E3BCBC, ++0x62EC7E01, 0x8BF732D7, 0xEE01A005, 0x64E3BCBD, ++0x64E3BCC3, 0x62EC7E01, 0x8BF732D7, 0x6EF64F26, ++0x6DF6000B, 0x2FE62FD6, 0x7FFC4F22, 0x6060D61F, ++0x89758801, 0xE101D41E, 0xD7128548, 0x650D2610, ++0x45196070, 0x6659DD1B, 0x61D3626E, 0xC840262D, ++0x74027102, 0x8D47D718, 0xD218666C, 0xE501DE0A, ++0xA0312E22, 0x0000EE04, 0x001E1001, 0x002028C6, ++0x002028A0, 0x001E1100, 0x002028CA, 0x002028B8, ++0x002028D0, 0x001E1000, 0x002028BC, 0x002028C8, ++0x00201A32, 0x001E1108, 0x00201B3E, 0x001E1015, ++0x001E100C, 0x002028B4, 0x002028D4, 0x002028D8, ++0x00202A90, 0x00202B26, 0x00202B32, 0x00202AA2, ++0x75016245, 0x71022121, 0x32E3625C, 0x60638BF8, ++0xE60181D4, 0xE417D538, 0x3243626C, 0x6255891E, ++0x27217601, 0x7702AFF8, 0xDE35D234, 0x2E22E501, ++0xEE04A004, 0x75016245, 0x71022121, 0x32E3625C, ++0x60638BF8, 0xE60181D4, 0xA004D52E, 0x6255E417, ++0x27217601, 0x626C7702, 0x8BF83243, 0x2D21924B, ++0xD72AD429, 0x2F126142, 0x6DF265F2, 0xC9806053, ++0x60532700, 0x6103C960, 0x60538071, 0x65F26EF2, ++0x4D19C903, 0x80724529, 0x451960DC, 0x4E298172, ++0x62EC605C, 0x302C4018, 0x6D428173, 0x2FD22118, ++0x62F26EF2, 0x421966F2, 0x656C4629, 0x602C66F2, ++0x401864EC, 0x304C4629, 0x81744619, 0x4018606C, ++0x8F07305C, 0xBCB58175, 0x620C0009, 0x89082228, ++0x0009A00A, 0x88406013, 0xB00A8B03, 0xA0030009, ++0xD60B0009, 0x2622E202, 0x4F267F04, 0x000B6EF6, ++0x000B6DF6, 0x060A0009, 0x00202AD2, 0x00202AD0, ++0x002028BC, 0x00202AA4, 0x001E100C, 0x002028A0, ++0x002028D0, 0x7FFC4F22, 0x6620D27E, 0x8D082668, ++0xD47D2F60, 0x420BD27D, 0x64F00009, 0xA0907F04, ++0x7F044F26, 0x000B4F26, 0x000B0009, 0x2FE60009, ++0xDE774F22, 0x60E0D677, 0xCBC0D477, 0x62602E00, ++0xC803602C, 0x40218904, 0x70014021, 0x6603A002, ++0x66034009, 0xD671616D, 0xE500A004, 0x75016262, ++0x74042422, 0x3213625D, 0xD16D8BF8, 0x0009410B, ++0xE401D66C, 0x84E22641, 0x80E2C9BF, 0x000B4F26, ++0x2FE66EF6, 0xD5687FFC, 0x6250DE61, 0x642C84E2, ++0xCB407404, 0x80E2614D, 0x44216413, 0xD7634421, ++0xE600A004, 0x76016256, 0x27222F22, 0x3243626D, ++0x60138BF8, 0x2008C903, 0x88038912, 0x88028905, ++0x88018906, 0xA0088907, 0xE0070009, 0x8078A005, ++0xA002E003, 0xE0018078, 0x62528078, 0x27222F22, ++0xD650E00F, 0x60618078, 0x8B018801, 0x2621E200, ++0x6060D64F, 0x2600CB08, 0xC93F60E0, 0x7F042E00, ++0x6EF6000B, 0x6021D247, 0x8D188801, 0xD2466143, ++0x22106053, 0x60638021, 0xD4468121, 0xE500A007, ++0x027C605D, 0x364C6603, 0x26207001, 0x625D6503, ++0x3213611C, 0xD6408BF4, 0xC9BF6060, 0x000B2600, ++0x2FD60009, 0x4F222FE6, 0x60437FFC, 0x8D02C820, ++0xBF6A6E43, 0x60E30009, 0x8901C810, 0x0009BF67, ++0xC84060E3, 0xBF8C8901, 0x60E30009, 0x8929C801, ++0x60D0DD32, 0x8D03C802, 0xD6312F00, 0x0009460B, ++0xC80460F0, 0xD62F8902, 0x0009460B, 0x602362F0, ++0x8902C880, 0xC97F60D0, 0x60232D00, 0x8902C801, ++0x420BD229, 0xD5290009, 0x88026052, 0xD2288B03, ++0xA005E604, 0x88012260, 0xD2258B02, 0x2260E601, ++0x2522E200, 0xC88060E3, 0xD2228916, 0x60E36E20, ++0x8902C802, 0x420BD220, 0x60E30009, 0x8902C804, ++0x420BD21E, 0x60E30009, 0x8905C808, 0x7F04D21C, ++0x6EF64F26, 0x6DF6422B, 0x4F267F04, 0x000B6EF6, ++0x00006DF6, 0x001E1020, 0x0020296C, 0x00200DA6, ++0x001E1015, 0x001E10BF, 0x00117D00, 0x001E10FC, ++0x002000F8, 0x002028CC, 0x00117D80, 0x001E10F8, ++0x001E10AE, 0x00117D84, 0x001E1017, 0x001E1021, ++0x00200FD8, 0x00200FFA, 0x00201584, 0x002028D0, ++0x001E100B, 0x001E1028, 0x0020102A, 0x0020103C, ++0x00201048, 0xD6A8644C, 0x346C74FF, 0x2450000B, ++0x644CD6A6, 0x000B346C, 0xD6A52450, 0x346C644C, ++0x2450000B, 0x616D625C, 0x41194208, 0x60194208, ++0x644C4200, 0x324C670E, 0x207DD19E, 0xC90F4200, ++0x000B321C, 0x67632200, 0x4208625C, 0x42004208, ++0x324C644C, 0x4200D198, 0x000B321C, 0x2FE62270, ++0x614C4F12, 0x4100D493, 0x6710314C, 0x2729E29F, ++0x65736E53, 0x4719676D, 0x672E6279, 0x4221227D, ++0x42214221, 0x7601662C, 0xE4014608, 0x34E84608, ++0x644C4600, 0x0E1A0467, 0x215025EB, 0x000B4F16, ++0x4F226EF6, 0xD2857FE8, 0x88016021, 0xD2848B7B, ++0x26686621, 0xD2838B77, 0x26686621, 0xE50F8B73, ++0xE401BFA0, 0xBFA3E501, 0xE586E400, 0xE400655C, ++0x2F50BFA3, 0xBFA0E401, 0xE602E506, 0x60634618, ++0x81F2E401, 0x6543BF9E, 0xE40185F2, 0xBFAA6543, ++0x85F26603, 0x6543E401, 0x6603BFB1, 0xE40265F0, ++0x6053756C, 0x80F8BF7E, 0xBF81E402, 0x84F8E512, ++0x7090E402, 0x6503BF81, 0x4618E602, 0x81F66063, ++0xBF7FE402, 0x85F6E500, 0x6603E402, 0xE500BF8B, ++0xE40285F6, 0xBF926603, 0xE5FEE500, 0xE010655C, ++0xBF5FE403, 0xE5130F54, 0xE40EBF62, 0x05FCE010, ++0xBF62E40E, 0xE5007585, 0xBF63E403, 0xE500E640, ++0xBF70E403, 0xE500E640, 0xBF78E403, 0xE5FFE640, ++0xE014655C, 0xBF45E404, 0xE40F0F54, 0xE504BF48, ++0x05FCE014, 0xBF48E40F, 0xE5017584, 0xBF49E640, ++0xE501E404, 0xBF56E640, 0xE501E404, 0xE404E640, ++0xAF5C7F18, 0x7F184F26, 0x000B4F26, 0x4F220009, ++0xD2427FF0, 0x88016021, 0xD2418B71, 0x26686621, ++0xD2408B6D, 0x26686621, 0xE50F8B69, 0xE401BF1A, ++0xBF1DE501, 0xE586E400, 0xE400655C, 0x2F50BF1D, ++0xBF1AE401, 0xE401E506, 0xBF1B6543, 0xE401E640, ++0xBF286543, 0xE401E640, 0xBF306543, 0x65F0E640, ++0x756CE402, 0xBEFD6053, 0xE40280F4, 0xE512BF00, ++0xE40284F4, 0xBF007090, 0xE6406503, 0xBF01E402, ++0xE640E500, 0xBF0EE402, 0xE640E500, 0xBF16E402, ++0xE5FEE500, 0x6053655C, 0xBEE3E403, 0xE51380F8, ++0xE40EBEE6, 0xE40E84F8, 0xBEE67085, 0xE5006503, ++0xBEE7E640, 0xE500E403, 0xBEF4E640, 0xE500E403, ++0xBEFCE640, 0xE5FFE403, 0x6053655C, 0xBEC9E404, ++0xE40F80FC, 0xE504BECC, 0xE40F84FC, 0xBECC7083, ++0xE5016503, 0xBECDE640, 0xE501E404, 0xBEDAE640, ++0xE501E404, 0xE404E640, 0xAEE07F10, 0x7F104F26, ++0x000B4F26, 0x00000009, 0x001E1030, 0x001E1080, ++0x001E1090, 0x001E103F, 0x001E103E, 0x002028C6, ++0x002028C8, 0x002028CA, 0x0009000B, 0x666CE680, ++0x6563D2A8, 0x7540E700, 0x6473422B, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0x4C18EC01, 0xDAA3DBA2, ++0x65B252B1, 0x89223520, 0xC9036051, 0x891E8801, ++0xD19FDE9D, 0x64E3410B, 0x85036503, 0x670D66A2, ++0xDD9C3762, 0xD49C890A, 0x420BD29C, 0xD19C0009, ++0xE701D49C, 0x21724D0B, 0x0009AFE2, 0x420BD29A, ++0xD69A64E3, 0x4D0BD49A, 0xAFD926C2, 0x4F260009, ++0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, 0x7FF44F22, ++0xE6818546, 0x85472F01, 0x81F1666C, 0xD2858548, ++0x854281F2, 0x81F367F3, 0xE40C8543, 0x605381F4, ++0x81F56563, 0x7540420B, 0x4F267F0C, 0x0009000B, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xDC847FF0, 0xE800A0DD, 0xD2836B13, 0xE0014B08, ++0x4B00420B, 0x1F03DE81, 0x3BEC85F2, 0x2F827E30, ++0x1FE26803, 0x66C2DD7E, 0x362052C1, 0xA0C38B01, ++0x60610009, 0x8801C903, 0xA0BD8B01, 0x85610009, ++0x8965C801, 0xEE105163, 0xDA6A8512, 0xC9036603, ++0x85136403, 0x4021600D, 0xC93F4021, 0x8D1C30E3, ++0xD7706503, 0x62704408, 0x44004408, 0x22284500, ++0x345C8F0A, 0x6043D26C, 0x697D072D, 0x68994919, ++0x697C6E8E, 0x28EDA009, 0x6043D268, 0x697D072D, ++0x68994919, 0x697C6E8E, 0xEEFF28ED, 0x6EEC629D, ++0x8B0F32E0, 0x410BD152, 0x540364C3, 0xBF85E502, ++0xD45F6E03, 0x460BD654, 0xD75E65E3, 0xD45EEE01, ++0x27E2A01D, 0x26E9EEFC, 0x81126063, 0x97888513, ++0x20794208, 0x85128113, 0x8112208B, 0x202B8513, ++0x85148113, 0x4218E208, 0x8114202B, 0x854164C2, ++0x814120E9, 0xD45165C2, 0xCB016051, 0x4A0B2501, ++0x60C20009, 0x52F356F2, 0x2B02CB01, 0x2622AF8B, ++0xD2378561, 0x8D2EC802, 0x420B64C3, 0xD6480009, ++0x5E036503, 0x076EE04C, 0x7701D146, 0x60120676, ++0x8B058801, 0xEA0C85E1, 0x20AB4A18, 0x81E1A007, ++0x88026012, 0x85E18B03, 0x20A9EADF, 0x855181E1, ++0x20A9EAFC, 0x60518151, 0xCB01DA28, 0x4A0B64C3, ++0x56F22501, 0xD73851F3, 0x85EF2612, 0x470B64D3, ++0xAF58650D, 0x420B0009, 0x54030009, 0x85446E03, ++0x4A18EA08, 0x30A020A9, 0x8B03DA1A, 0xE501BF16, ++0x0009A007, 0xD62D8541, 0x2268620D, 0xBF0D8901, ++0xD423E500, 0x420BD218, 0xD72265E3, 0xEE01D428, ++0x27E24A0B, 0x0009AF37, 0x68F26083, 0x780181F2, ++0x618D7C08, 0x31E7EE03, 0xAF1D8901, 0x7F100009, ++0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0xFE0368F6, 0x00201834, 0x00202884, 0x0020288C, ++0x00200A5C, 0x00200DA6, 0x00202854, 0x00200ADE, ++0x001E2130, 0x00202A70, 0x00200A7A, 0x001C3D30, ++0x00202A74, 0x00202864, 0x00201FD4, 0x001C3D00, ++0x00202A80, 0x00202A8C, 0x00202970, 0x002029F0, ++0x0020285C, 0x001E212C, 0x00202A78, 0x00202A7C, ++0x002027F8, 0x002027F4, 0x00200E06, 0x00008000, ++0x00202A88, 0x4F222FE6, 0x6E22D20D, 0xC84060E3, ++0x22E28D02, 0x0009BE68, 0x4218E240, 0x89012E28, ++0x0009BE64, 0xC80560E3, 0xBEB98901, 0x60E30009, ++0x8902C802, 0xAE614F26, 0x4F266EF6, 0x6EF6000B, ++0x001C3510, 0x080A0C0E, 0x00020406, 0x1A1C1E20, ++0x12141618, 0x2E303234, 0x26282A2C, 0x3A3C3E40, ++0x6C625648, 0x41112F26, 0xE2208F18, 0x890B3123, ++0x321CD204, 0xD1026220, 0x412B312C, 0x00090009, ++0x00201FFE, 0x00201FB4, 0x000BE000, 0x400062F6, ++0x40004000, 0x40004000, 0x40004000, 0x62F6000B, ++0x40004000, 0x40004000, 0x40004000, 0x40184000, ++0x62F6000B, 0x40004000, 0x40004000, 0x40004000, ++0x40284000, 0x62F6000B, 0x40004000, 0x40184000, ++0x000B4028, 0xC90F62F6, 0x40054005, 0x40054005, ++0x62F6000B, 0x4005C907, 0x40054005, 0x62F6000B, ++0x4005C903, 0x000B4005, 0xC90162F6, 0x000B4005, ++0x000062F6, 0x080A0C0E, 0x00020406, 0x1A1C1E20, ++0x12141618, 0x2E303234, 0x26282A2C, 0x3A3C3E40, ++0x6C625648, 0x41112F26, 0xE2208F18, 0x890B3123, ++0x321CD204, 0xD1026220, 0x412B312C, 0x00090009, ++0x002020BE, 0x00202074, 0x000BE000, 0x400162F6, ++0x40014001, 0x40014001, 0x40014001, 0x62F6000B, ++0x40014001, 0x40014001, 0x40014001, 0x40194001, ++0x62F6000B, 0x40014001, 0x40014001, 0x40014001, ++0x40294001, 0x62F6000B, 0x40014001, 0x40194001, ++0x000B4029, 0x400462F6, 0x40044004, 0xC90F4004, ++0x62F6000B, 0x40044004, 0xC9074004, 0x62F6000B, ++0x40044004, 0x000BC903, 0x400462F6, 0x000BC901, ++0x000062F6, 0x3622E218, 0x67438F12, 0x0009A004, ++0x76FF6254, 0x74012420, 0xC8036053, 0x60438BF8, ++0x8902C803, 0x422BD22B, 0xD22B0009, 0x0009422B, ++0x2FE66473, 0x8D4A3450, 0x27786763, 0x62438947, ++0x227B225B, 0xC9016023, 0x8D203452, 0x2EE86E03, ++0x60238B15, 0x8B08C803, 0x47096643, 0x47106256, ++0x8FFB2622, 0xA0327604, 0x47010009, 0x61436673, ++0x46106255, 0x8FFB2121, 0xA0287102, 0x66430009, ++0x47106254, 0x8FFB2620, 0xA0207601, 0x61430009, ++0x2EE8357C, 0x8F15317C, 0x60236653, 0x8B07C803, ++0x76FC4709, 0x47106262, 0x21268FFB, 0x0009A00F, ++0x65634701, 0x75FE6673, 0x46106251, 0x21258FFB, ++0x0009A005, 0x626076FF, 0x8FFB4710, 0x60432124, ++0x6EF6000B, 0x002022A6, 0x00202752, 0xE21E2FE6, ++0x67633626, 0x8D1B6153, 0x3E106E43, 0x3E128916, ++0x65E38908, 0x3672E600, 0x62148910, 0x25207601, ++0x7501AFF9, 0x317C64E3, 0x6513347C, 0xE600A004, ++0x625075FF, 0x24247601, 0x8BF93672, 0x60E3A011, ++0x890831E2, 0x327C6213, 0x8B0432E6, 0x651364E3, ++0xA0086673, 0xD28F6EF6, 0x651364E3, 0x422B6673, ++0x000B6EF6, 0xE2046EF6, 0x67433622, 0x8F10356C, ++0xA004346C, 0x75FF0009, 0x76FF6250, 0x60532424, ++0x8BF8C803, 0xC8036043, 0xA1058901, 0xA2770009, ++0xA2990009, 0x2FB60009, 0x2FD62FC6, 0x7FE42FE6, ++0x6C636043, 0x66521F62, 0xC9037504, 0x1F516E53, ++0x45086503, 0xE1FC6D43, 0x2D194500, 0x1F732558, ++0x1F651F44, 0x2FD28D0B, 0x88086053, 0x88108923, ++0x8818895B, 0xA0898B01, 0xA0BD0009, 0x62630009, ++0x2D22E600, 0x7CFC7D04, 0xEB10A00D, 0xE60064E6, ++0x7CF065E6, 0x62E261E6, 0x1D512D42, 0x1D231D12, ++0x7E047D10, 0x3CB21FE1, 0x1F6589F0, 0x2FD21FC2, ++0xA0A11FE6, 0x64D21FD4, 0x44286263, 0x44294418, ++0x42184419, 0x4629242B, 0x2D424619, 0x65637D04, ++0xA0217CFD, 0x67E6EB10, 0x62E67CF0, 0x64E66673, ++0x256B4618, 0x2D5261E2, 0x65234729, 0x45184719, ++0x4229275B, 0x42191D71, 0x47186743, 0x4429227B, ++0x44196713, 0x247B4718, 0x1D431D22, 0x41194129, ++0x65137D10, 0x1FE17E04, 0x89DC3CB2, 0x1FE67EFF, ++0x1FC21F55, 0xA0672FD2, 0x6CF21FD4, 0x66C257F5, ++0x46286273, 0x42284629, 0x2C62262B, 0x7C045DF2, ++0x7DFE4729, 0xA01CEB10, 0x65E65EF1, 0x66E66273, ++0x47286753, 0x6763227B, 0x452961E6, 0x257B4728, ++0x2C2264E6, 0x65131C51, 0x45284629, 0x1C62265B, ++0x41296643, 0x216B4628, 0x44291C13, 0x67437C10, ++0x3DB27DF0, 0x1FD289E1, 0x7EFEA034, 0x51F56CF2, ++0x621366C2, 0x42284618, 0x42184619, 0x2C62262B, ++0x7C045DF2, 0x7DFF4119, 0xA01FEB10, 0x65E65EF1, ++0x64E67DF0, 0x42286253, 0x421867E6, 0x66E6212B, ++0x61432C12, 0x45194128, 0x251B4118, 0x65731C51, ++0x44194528, 0x245B4518, 0x64631C42, 0x47194428, ++0x274B4418, 0x46191C73, 0x61637C10, 0x89DE3DB2, ++0x7EFD1FD2, 0x1FC41FE6, 0x5DF2E704, 0xA00D5EF6, ++0x62E451F4, 0x66E47DFC, 0x65E464E4, 0x71012120, ++0x71012160, 0x71012140, 0x71012150, 0x89F03D72, ++0x66D357F3, 0x641365E3, 0x6EF67F1C, 0x6CF66DF6, ++0x6BF6A190, 0x00202134, 0x2FC62FB6, 0x2FE62FD6, ++0x60437FE4, 0x6C63C903, 0x66031F62, 0x460875FC, ++0x61526E43, 0x4600E2FC, 0x26682E29, 0x1F441F73, ++0x1F516D53, 0x8D0B1F15, 0x60632FE2, 0x891F8808, ++0x89538810, 0x8B018818, 0x0009A081, 0x0009A0B9, ++0xEB10A00D, 0x52D37DF0, 0x54D156D2, 0x2E1665D2, ++0x2E662E26, 0x2E427EFC, 0x1FD16153, 0x3CB27CF0, ++0x7D0489F0, 0x1F151FD6, 0x2FE21FC2, 0x1FE4A0A1, ++0x621366E2, 0x42294619, 0x42194618, 0x2E62262B, ++0x7CFF4118, 0xEB10A021, 0x54D37DF0, 0x624357D2, ++0x42194229, 0x55D1212B, 0x2E1666D2, 0x41296173, ++0x41194418, 0x2E46241B, 0x44296453, 0x44194718, ++0x2E76274B, 0x47296763, 0x47194518, 0x257B7EFC, ++0x46182E52, 0x1FD16163, 0x3CB27CF0, 0x7D0389DC, ++0x1F151FD6, 0x2FE21FC2, 0x1FE4A06B, 0x57F56EF2, ++0x627366E2, 0x46284629, 0x262B4229, 0x2E625CF2, ++0x7CFE4728, 0xA01BEB10, 0x7DF05DF1, 0x55D251D3, ++0x46296613, 0x54D1276B, 0x2E7662D2, 0x41286753, ++0x217B4729, 0x61432E16, 0x41294528, 0x2E56251B, ++0x44286523, 0x245B4529, 0x42282E46, 0x7CF06723, ++0x89E23CB2, 0x1FD67D02, 0xA03A1FC2, 0x67F21FE4, ++0x657251F5, 0x45296213, 0x45284519, 0x42194518, ++0x5CF2252B, 0x41282752, 0x7CFD4118, 0xA022EB10, ++0x7DF05DF1, 0x54D256D3, 0x45196563, 0x52D14628, ++0x4618215B, 0x6ED26543, 0x45192716, 0x265B4428, ++0x65436163, 0x45186423, 0x42284419, 0x4218254B, ++0x271664E3, 0x44196623, 0x264B2756, 0x4E282766, ++0x61E34E18, 0x3CB27CF0, 0x7D0189DB, 0x1FC21FD6, ++0xE7041F74, 0x51F45DF2, 0x5EF6A00D, 0x84E27EFC, ++0x620364E0, 0x7DFC84E1, 0x84E36503, 0x21646603, ++0x21542124, 0x3D722144, 0x57F389F0, 0x641366D3, ++0x7F1C65E3, 0x6DF66EF6, 0xA09D6CF6, 0x2F866BF6, ++0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, 0x614374E0, ++0x6A636873, 0x6B56E920, 0x6C567AE0, 0x6D567120, ++0x6E563A92, 0x64566756, 0x62566656, 0x11C121B2, ++0x11E311D2, 0x11451174, 0x8DEC1166, 0x71201127, ++0x6613A004, 0x7AFF6254, 0x76012620, 0x8BF92AA8, ++0x6EF66083, 0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, ++0x2F8668F6, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x6A636873, 0x75E0E920, 0x56565257, 0x57545155, ++0x5D525E53, 0x6B525C51, 0x24662426, 0x24762416, ++0x7AE024E6, 0x24C624D6, 0x8DEC3A92, 0x66A324B6, ++0x6EF66783, 0x6CF66DF6, 0x6AF66BF6, 0xA04369F6, ++0x2FE668F6, 0xC8046063, 0x8D046E63, 0x62166153, ++0x24227EFC, 0x60E37404, 0x8908C818, 0x71046513, ++0x62526616, 0x24227EF8, 0xAFF41461, 0xE2047408, ++0x65133E22, 0x66E38D02, 0x6EF6A01C, 0x6EF6AF87, ++0xC8046063, 0x61638D04, 0x625275FC, 0x242671FC, ++0xC8186013, 0x75F88906, 0x66525251, 0x24662426, ++0x71F8AFF6, 0x3122E204, 0x66138F02, 0x0009AFA1, ++0x0009A00A, 0x0009A004, 0x76FF6254, 0x74012420, ++0x8BF92668, 0x6073000B, 0x0009A004, 0x625075FF, ++0x242476FF, 0x8BF92668, 0x6073000B, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x544F0D0A, ++0x46205355, 0x00003A57, 0x2072614D, 0x32203232, ++0x20373030, 0x353A3431, 0x33353A34, 0x00000000, ++0x00000D0A, 0x00000043, 0x61766E49, 0x2064696C, ++0x72657375, 0x20726F20, 0x2079656B, 0x00214449, ++0x6E6B6E55, 0x206E776F, 0x6D6D6F63, 0x3D646E61, ++0x00000000, 0x61437748, 0x7262696C, 0x6F697461, ++0x6620206E, 0x0A6C6961, 0x0000000D, 0x73696F4E, ++0x61432065, 0x7262696C, 0x6F697461, 0x6166206E, ++0x21216C69, 0x00000D0A, 0x00000D0A, 0x00000042, ++0x000000FF, 0x00020001, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00020003, 0x01090108, 0x0002010A, ++0x00030002, 0x02020201, 0x02040203, 0x02060205, ++0x02080207, 0x020A0209, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x010E010D, 0x00FF010F, 0x01090108, 0x010B010A, ++0x00030002, 0x02020201, 0x02040203, 0x02060205, ++0x02080207, 0x020A0209, 0x020C020B, 0x020E020D, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00000072, 0x00205220, 0x00000046, 0x00000059, ++0x73204142, 0x003D7165, 0x00000074, 0x00000000, ++0x02000112, 0x40FFFFFF, 0x12210ACE, 0x20104890, ++0x02090100, 0x0101002E, 0x09FA8000, 0x04000004, ++0x000000FF, 0x02010507, 0x07000200, 0x00028205, ++0x05070002, 0x00400383, 0x04050701, 0x01004003, ++0x002E0209, 0x80000101, 0x000409FA, 0x00FF0400, ++0x05070000, 0x00400201, 0x82050700, 0x00004002, ++0x03830507, 0x07010040, 0x40030405, 0x03040100, ++0x030C0409, 0x0079005A, 0x00410044, 0x03180053, ++0x00530055, 0x00320042, 0x0030002E, 0x00570020, ++0x0041004C, 0x0000004E, 0x00000000, 0x00000000, ++0x00000709, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++}; ++ ++const u32_t zcFwImageSize=11104; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpfwu_txstream.c +@@ -0,0 +1,1017 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "cprecomp.h" ++ ++const u32_t zcFwImage[] = { ++0x0009000B, 0x4F222FE6, 0xDE947FFC, 0xE114D594, ++0x1E13D494, 0x67521E4C, 0xD494D693, 0x37402769, ++0x62528F06, 0x7201D692, 0x60602522, 0x2600C93F, ++0xD7906152, 0x2512611D, 0x264B6652, 0x2562470B, ++0x0009B017, 0xE60095AC, 0xC84060E2, 0x2F028F03, ++0x8FF93652, 0xD4887601, 0x4E0BDE88, 0xD4880009, ++0x00094E0B, 0x4E0BD487, 0x7F040009, 0xA0524F26, ++0x4F226EF6, 0x410BD184, 0xD4840009, 0x0009440B, ++0x450BD583, 0xD7830009, 0xD283E1FF, 0x2712611D, ++0xD4825029, 0xE1FFCB01, 0x1209E501, 0x12112212, ++0xE7202452, 0x4718D57E, 0x2572D27E, 0xD17EE700, ++0xD67FD47E, 0xE2012270, 0x24702172, 0xD67D2620, ++0x2641E4FF, 0xD57CE600, 0x666DE104, 0x76016063, ++0x4000626D, 0x8FF83212, 0xD5780545, 0x2520E201, ++0xD278D777, 0xE480E100, 0x22122710, 0x6613D576, ++0x666D644C, 0x76046763, 0x375C626D, 0x8FF83243, ++0xD5722712, 0xD273D772, 0xE400E101, 0x27102511, ++0x000B4F26, 0x7FCC2242, 0xD170D56F, 0xD271DB70, ++0x1F51D471, 0xD6717508, 0x1F12D771, 0x1F55710C, ++0x1FB975FC, 0x72041F2A, 0x1F13EB10, 0x1F561F44, ++0x1F781F67, 0xD86B1F2B, 0xDD6CD96B, 0xDC6CEA00, ++0xD26DDE6C, 0x89003A22, 0xD15D7A01, 0x88016010, ++0x56F88B03, 0x4218E201, 0xD1682622, 0x0009410B, ++0x440BD467, 0xD5670009, 0x0009450B, 0x6010D150, ++0x8B108801, 0xE650D14F, 0x46186212, 0x8B083266, ++0x56F9D14B, 0x2120E200, 0xCB016062, 0x2602A003, ++0x72012710, 0x60822122, 0x89098801, 0xE2C8D15A, ++0x622C6612, 0x89033626, 0x6010D158, 0x8BC88801, ++0x51F66792, 0x217252F5, 0xD6555191, 0x55FA2212, ++0x52FB6462, 0x55612542, 0x2252E400, 0x61436643, ++0x05DE6013, 0x36CC4608, 0x07DE2652, 0xC9036071, ++0x8B028801, 0x720162E2, 0x74012E22, 0x36B3664C, ++0x71048FEE, 0x66C2D147, 0x45286512, 0x265B4518, ++0x60822C62, 0x89018801, 0x0009A168, 0x6272D742, ++0x8B132228, 0xD42BD741, 0x6772D541, 0x51536242, ++0x312C327C, 0x24222228, 0x15138D05, 0x6262D63D, ++0xB1627201, 0xD6232622, 0x2622E200, 0x52916692, ++0x8B013620, 0x0009A144, 0x6061A06E, 0x001C001C, ++0x001D4020, 0x0000B38E, 0xFFFF0000, 0x12340000, ++0x001E1015, 0x00201274, 0x002039F4, 0x002018A2, ++0x00203A00, 0x00203A18, 0x00201860, 0x0020196C, ++0x00201288, 0x001C3510, 0x001C3624, 0x001E212C, ++0x002038F4, 0x0020348C, 0x002038FC, 0x00203908, ++0x00203914, 0x00203970, 0x00203974, 0x0020391C, ++0x0020391D, 0x00203920, 0x00117700, 0x0020398C, ++0x0020398A, 0x002034F0, 0x00117710, 0x001C3D30, ++0x001C36F8, 0x00117734, 0x001C3684, 0x001C3D00, ++0x001C1000, 0x001C1028, 0x00203504, 0x00203924, ++0x00117600, 0x00117740, 0x7FFFFFFF, 0x00201730, ++0x0020332A, 0x00202334, 0x00203DA4, 0x00203972, ++0x002034FC, 0x00203964, 0x001C3D2C, 0x001C36B0, ++0x00203494, 0x0011775C, 0x8801C90F, 0xA0CF8901, ++0xD1960009, 0x36206212, 0xD4958904, 0x2421E200, ++0x2162A0CC, 0x6211D193, 0x89012228, 0x0009A0C3, ++0xE202D78F, 0x75016571, 0x3123615D, 0x27518D02, ++0x0009A0BC, 0xD28C57F2, 0x62226072, 0x40094019, ++0xC90F4009, 0x8F19880A, 0x52F31F2C, 0x40196022, ++0x40094009, 0x8808C90F, 0xA0A78901, 0x60630009, ++0xCB0154F7, 0xD27E55F2, 0xE7012402, 0xD47FE100, ++0x22112572, 0x72016242, 0x2422A098, 0x8B3F8805, ++0x602252F3, 0x40094019, 0xC90F4009, 0x8B168802, ++0xE4FFD577, 0x644D6752, 0x8B102748, 0x6272D775, ++0x8B0C3260, 0x51F255F7, 0xD26DE701, 0x21722562, ++0xD571E100, 0x64522211, 0xA0777401, 0x52F32542, ++0x40196022, 0x40094009, 0x8805C90F, 0x31B38B6E, ++0xD26A8B6C, 0x672254F4, 0x7701D569, 0x61422272, ++0x1F1CE640, 0x46182159, 0x8B033160, 0x6262D665, ++0x26227201, 0xE200D65A, 0x2621B067, 0x0009A056, ++0x3123E220, 0x88038B52, 0x52F38B1E, 0x40196022, ++0x40094009, 0x8803C90F, 0xD25B8B16, 0x672254F4, ++0x7701D557, 0x61422272, 0x1F1CE640, 0x46182159, ++0x8B033160, 0x6262D655, 0x26227201, 0xE200D648, ++0x2621B043, 0x0009A010, 0xD452D551, 0xD2446752, ++0xE1007701, 0x25723A46, 0x22118F06, 0xEA00D64E, ++0x72016262, 0x2622B031, 0x2FB2D54C, 0x95736652, ++0xD44A5BF1, 0x36205241, 0x60618910, 0x8B01C803, ++0x2B22E201, 0x8FF54510, 0x57F15664, 0x6272E1F0, ++0x41284118, 0x2722221B, 0x6BF2A008, 0x6BF2A006, ++0xE200D62F, 0xD12F2621, 0x2121E200, 0xD13CE201, ++0x66122822, 0x8B012668, 0x0009AE2B, 0x450BD539, ++0xD1390009, 0xAE24E600, 0x2F862160, 0x2FA62F96, ++0x2FC62FB6, 0x2FE62FD6, 0x7FF44F22, 0xDE34D133, ++0x54116212, 0x1F4167E2, 0x2F22D432, 0xD5321F72, ++0xD2326743, 0x58417794, 0x69425A42, 0x5B166C72, ++0x60526D22, 0xCB20E600, 0xE5402502, 0x626D7601, ++0x8BFB3253, 0x55F162F2, 0x11512122, 0xD62855F2, ++0x14812E52, 0x249214A2, 0x27C2D426, 0x26D211B6, ++0xDA256742, 0xE801D925, 0x490B2A72, 0xE2011A8C, ++0x1A2C4218, 0x4F267F0C, 0x6DF66EF6, 0x6BF66CF6, ++0x69F66AF6, 0x68F6000B, 0x000007D1, 0x00203984, ++0x00203988, 0x0020398E, 0x001C3DC0, 0x0011772C, ++0x001C3B88, 0x0020396C, 0x0011773C, 0x00117744, ++0x0000F000, 0x00117764, 0x00117748, 0x00117768, ++0x0011776C, 0x01FFFFFF, 0x0011774C, 0x002034FC, ++0x00203DA4, 0x002024F8, 0x00203972, 0x001C3B9C, ++0x001C3D98, 0x001C3700, 0x001C3500, 0x001C5960, ++0x001C8960, 0x00203504, 0x001C3D00, 0x0020160C, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xDE957FAC, 0x61E0E014, 0x0F14D494, 0x710161E3, ++0xE0186210, 0xD2920F24, 0x0009420B, 0x450BD591, ++0x20080009, 0x8F126D03, 0xD28F1F07, 0x6720D48F, ++0x657CDD8F, 0x470BD78F, 0xD18F0009, 0x619C6910, ++0x46086613, 0x36184608, 0x3D6C4608, 0xE0181FD7, ++0xE58004FC, 0x604C66E2, 0x3050655C, 0x2D628F15, ++0x01FCE014, 0xDE85E500, 0x641CA008, 0x6753655D, ++0x607037EC, 0x39DC6953, 0x80947501, 0x3243625D, ++0xD67F8BF4, 0xA34EE200, 0x20082621, 0xE0148B13, ++0xE40001FC, 0xA009DE79, 0x644D671C, 0x35EC6543, ++0x69436652, 0x39DC6262, 0x74041921, 0x3273624D, ++0xA3388BF3, 0x88012D10, 0xE0148B17, 0xE70001FC, ++0x6D1C2D70, 0xDE6D1FD4, 0x32D3627D, 0xA32A8B01, ++0x677D0009, 0x667365E3, 0x61737504, 0x315C36EC, ++0x69126462, 0xAFEF7708, 0x88042492, 0xE0148B18, ++0xE40001FC, 0x671C2D40, 0x624DDE60, 0x8B013273, ++0x0009A311, 0x6943644D, 0x39EC62E3, 0x72046592, ++0x3D2C6D43, 0x615266D2, 0x21697408, 0x2512AFED, ++0x8B188805, 0x01FCE014, 0x2D40E400, 0xDE53671C, ++0x3273624D, 0xA2F68B01, 0x644D0009, 0x62E36943, ++0x659239EC, 0x6D437204, 0x66D23D2C, 0x74086152, ++0xAFED216B, 0x88312512, 0xD44A8B3A, 0x6146D94A, ++0x75046543, 0x67566442, 0x6E531F48, 0x65527E04, ++0x7EE462E2, 0x7E0464E2, 0x6EE21FE9, 0x5EF929E0, ++0x7E04D942, 0x1FEA60E2, 0x2900C901, 0xD9406EE2, ++0x29E04E09, 0x2F562F26, 0x56FAD93E, 0x6513490B, ++0xD13D7F08, 0xE71C6E0D, 0x1DE12D70, 0xDE3B6912, ++0x64E21D92, 0x1D43D13A, 0xD23A6512, 0x67221D54, ++0x1D75D239, 0x1D666622, 0x6262D638, 0x1D27A2AB, ++0x8B398830, 0x6596D92B, 0x67926696, 0x61967904, ++0x74E46493, 0x6E436992, 0x1F9B7E04, 0x1FEC6442, ++0xD9256EE2, 0x5EFC29E0, 0x7E04D924, 0x1FED60E2, ++0x2900C901, 0xD9226EE2, 0x29E04E09, 0x59FC7FFC, ++0xDE272F92, 0x2F164E0B, 0xD41F7F08, 0xE21C610D, ++0x1D112D20, 0xD2206442, 0xD41C1D42, 0x1D536542, ++0x6752D51B, 0xD71B1D74, 0x1D156172, 0x1D666622, ++0x6262D61A, 0x1D27A26F, 0x8B358833, 0x490BD919, ++0xA268EE00, 0x00002DE0, 0x00117800, 0x00203A1C, ++0x002018A2, 0x00202AAC, 0x0020390E, 0x00203A20, ++0x00203534, 0x002018EE, 0x0020390D, 0x00117804, ++0x0020398C, 0x00117810, 0x00203909, 0x0020390A, ++0x0020390B, 0x00200F64, 0x001C5864, 0x001C6864, ++0x001C7864, 0x001C59BC, 0x001C69BC, 0x001C79BC, ++0x00200FBC, 0x00200FB8, 0x89018828, 0x0009A0C0, ++0xE643DEB5, 0x326662E1, 0x1FEE8F02, 0x2E21E240, ++0x622D62E1, 0x8B013267, 0x0009A0AA, 0xE50185E1, ++0x8B013056, 0x0009A0A4, 0x2D10E101, 0x64E1B225, ++0xE64357FE, 0x652D6271, 0x89443567, 0x3563E640, ++0xE6008B05, 0x0F65E040, 0xA00FE11A, 0x615372C0, ++0x41214121, 0x41214121, 0x45214121, 0x45214521, ++0xC9036053, 0xE0406603, 0x71180F65, 0x2209E007, ++0x0F25E03C, 0xE044641D, 0xB2A365F3, 0xE33C0F46, ++0x853233FC, 0x620DDE95, 0x42086031, 0x6023610D, ++0x1323E944, 0x06FE4108, 0xE00F39FC, 0x13144E0B, ++0x67075D91, 0x60D32679, 0x0F6654FE, 0x51928542, ++0x600D4E0B, 0x60D3260B, 0x0F666492, 0x65F3B237, ++0x696156FE, 0xE640659D, 0x89383563, 0xD78359FE, ++0x79066591, 0xC9036053, 0x40004008, 0x61036203, ++0x0F26E050, 0x470BE0FF, 0x6C07600C, 0x6603605D, ++0x46214621, 0x46214621, 0x42006263, 0x4200326C, ++0x40214021, 0x4008C903, 0x6D2D30FC, 0xE8006A03, ++0xB25765F3, 0x6EA264D3, 0x2EC9E050, 0x66942AE2, ++0xD76E01FE, 0x606C470B, 0x2AE22E0B, 0x64D365F3, ++0x7801B1FD, 0xEE06628D, 0x8FE932E3, 0x5EFE7D01, ++0x61E1E400, 0x410085E1, 0x66E3310C, 0x760C711B, ++0xE70465F3, 0x68667401, 0x3A736A4D, 0x8FF92582, ++0x65F37504, 0x641DB1E3, 0x64E1B1A4, 0x0009A17B, ++0xD45B56F7, 0xEC01D25B, 0x26C0420B, 0x0009A173, ++0x06FCE018, 0x8829606C, 0x58F78B08, 0xE400D252, ++0x66222840, 0x646DB171, 0x0009A165, 0x666CE681, ++0x89013060, 0x0009A0AC, 0xD550D14F, 0x62126A56, ++0x212232AC, 0x54116C56, 0x34CC6253, 0x64521141, ++0x72085812, 0xD44A384C, 0x68221182, 0x5A136C42, ++0x3ACC3C8C, 0x11A324C2, 0x6C2272EC, 0x72105814, ++0x118438CC, 0x5A156822, 0x11A53A8C, 0x6A227210, ++0xD6405816, 0x118638AC, 0x52176C62, 0x112732CC, ++0x5A185861, 0x11A83A8C, 0x5C195A62, 0x11C93CAC, ++0x521A5C63, 0x112A32CC, 0x5A1B5864, 0x11AB3A8C, ++0x5C1C5A65, 0x11CC3CAC, 0x521D5C66, 0x112D32CC, ++0x5A1E5867, 0x11AE3A8C, 0x561F5A68, 0x36ACE840, ++0x116FDA2D, 0x6CA2381C, 0x7A946682, 0x286236CC, ++0x5C8162A2, 0x18C13C2C, 0x62A27A44, 0x362C5682, ++0xD6261862, 0x5A856262, 0x3A2C4229, 0x760418A5, ++0x56866262, 0x362C4229, 0x56F71866, 0x2620E238, ++0x16C15C81, 0x16226212, 0xE2005C11, 0x551216C3, ++0x55151654, 0x55131655, 0x55161656, 0x55821657, ++0x65821658, 0x55141659, 0x5584165A, 0x5583165B, ++0x5585165C, 0x5586165D, 0x1821165E, 0x11212122, ++0x11251122, 0x11261123, 0x28221822, 0x18241124, ++0x18251823, 0x1826A0C7, 0x00117804, 0x002033E8, ++0x00203A40, 0x002018A2, 0x00203494, 0x001C36A0, ++0x002034F0, 0x001C3CA0, 0x001C36F4, 0x001C3B88, ++0x666CE682, 0x8B203060, 0xEA2456F7, 0x26A0D194, ++0x16C15C17, 0x16225218, 0x16835819, 0x16A45A1A, ++0x16C55C1B, 0x1626521C, 0xE200581D, 0x551E1687, ++0x551F1658, 0x11271659, 0x11291128, 0x112B112A, ++0x112D112C, 0xA08E112E, 0xE683112F, 0x3060666C, ++0x52F78B0B, 0xEA00D883, 0x658222A0, 0x7804DC82, ++0x62822C52, 0xA07ED681, 0xE6902620, 0x3060666C, ++0xDA7F8B06, 0x00094A0B, 0xE20056F7, 0x2620A073, ++0x666CE691, 0x8B103060, 0x6222D276, 0x2228622C, ++0xD2788904, 0x0009420B, 0x0009A003, 0x420BD276, ++0x56F70009, 0xA05EE200, 0xE6922620, 0x3060666C, ++0xE0188951, 0xE6B00BFC, 0x666C62BC, 0x8B2A3260, ++0x02FCE014, 0x682CEA00, 0x62ADE904, 0x894A3283, ++0x6AADDD64, 0x3CDC6CA3, 0x7D046EC2, 0xDB68D467, ++0x32DC62A3, 0x4B0BDC67, 0x4C0B6D22, 0xD46664E3, ++0x00094B0B, 0x64D34C0B, 0x4B0BD464, 0xE6000009, ++0x666D6BE3, 0x76013B6C, 0x3293626D, 0x8FF72BD0, ++0xAFDA4D19, 0xE6B57A08, 0x3260666C, 0xD45C8B13, ++0x4B0BDB57, 0xD25B0009, 0x6022DB5B, 0xCB20E6FF, ++0x2202666D, 0xDB592B62, 0xE014E200, 0x56F72B20, ++0xA01002FC, 0xD4562620, 0x6542D256, 0x420BD456, ++0xA0080009, 0xDB520009, 0x52B1E600, 0x622CDB53, ++0x52F72B21, 0x7F542260, 0x6EF64F26, 0x6CF66DF6, ++0x6AF66BF6, 0x000B69F6, 0x4F2268F6, 0xE240614D, ++0x89143123, 0x3127E21F, 0x8B09D749, 0xD449614D, ++0xE00171E0, 0x5671440B, 0x26596507, 0x1761A007, ++0xE001D444, 0x6672440B, 0x26596507, 0x4F262762, ++0x0009000B, 0x614D4F22, 0x3123E240, 0xE21F8912, ++0xD73B3127, 0x614D8B08, 0x5671D23A, 0x420B71E0, ++0x260BE001, 0x1761A006, 0x6672D236, 0xE001420B, ++0x2762260B, 0x000B4F26, 0xE6400009, 0x46284618, ++0x6252D531, 0x89FC2268, 0x0009000B, 0x4618E680, ++0xD52D4628, 0x22686252, 0x000B89FC, 0xA0010009, ++0x7201E200, 0x8BFC3242, 0x0009000B, 0x4618E680, ++0xD5264628, 0x22686252, 0x000B8BFC, 0x2FE60009, ++0x7FFC4F22, 0xBFF16E53, 0x61E22F42, 0xE280D620, ++0x54E11615, 0x16464218, 0x422855E2, 0x57E31657, ++0x16786EF2, 0x26E22E2B, 0x4F267F04, 0x6EF6AFCE, ++0x00203494, 0x00117804, 0x002038F4, 0x00203908, ++0x0020050A, 0x00201008, 0x0020102E, 0x00203A58, ++0x002018A2, 0x002018E6, 0x00203A6C, 0x00203A74, ++0x00203A78, 0x001C3500, 0x001C1000, 0x0020398A, ++0x00117800, 0x002018EE, 0x00203A8C, 0x00203990, ++0x001C3704, 0x002033E8, 0x001C373C, 0x001C3700, ++0x001C370C, 0x2FD62FC6, 0x4F222FE6, 0x6C53DD10, ++0x6E43BFA4, 0x2DE2BF89, 0x0009BFA0, 0x2C1251D5, ++0x1C4154D6, 0x1C5255D7, 0x1C6356D8, 0x6EF64F26, ++0x000B6DF6, 0x61636CF6, 0xA004E600, 0x62564109, ++0x24227601, 0x36127404, 0x000B8BF9, 0x00000009, ++0x001C370C, 0x0009A16E, 0x2FE62FD6, 0xDD944F22, ++0xA0049EB2, 0xD4930009, 0x420BD293, 0x62D265D2, ++0x8BF822E8, 0x0009A004, 0xD28FD490, 0x55D1420B, ++0x22E852D1, 0xA0048BF8, 0xD48D0009, 0x420BD28A, ++0x52D255D2, 0x8BF822E8, 0x0009A004, 0xD286D489, ++0x55D3420B, 0x22E852D3, 0xA0048BF8, 0xD4860009, ++0x420BD281, 0x52D455D4, 0x8BF822E8, 0x6EF64F26, ++0x6DF6000B, 0x2FD62FC6, 0x4F222FE6, 0x6E636C73, ++0x6D53B01A, 0x64D357F4, 0xB05F65E3, 0xB07566C3, ++0xB0A40009, 0xB0A80009, 0xB0AC0009, 0xB0AC0009, ++0xB0AF0009, 0xB03154F5, 0x6CCD6C03, 0x4F2660C3, ++0x6DF66EF6, 0x6CF6000B, 0x3412D170, 0xD6700529, ++0x2650D770, 0x2742000B, 0x0009A018, 0x2FD62FC6, ++0x4F222FE6, 0x6E636C73, 0x6D53BFEE, 0x64D357F4, ++0xB03365E3, 0xB08D66C3, 0xB00F54F5, 0x6CCD6C03, ++0x4F2660C3, 0x6DF66EF6, 0x6CF6000B, 0xE503D162, ++0xD763D462, 0x21524518, 0x2472000B, 0xD45FD15E, ++0x2162E600, 0x2462000B, 0xBF734F22, 0xBF73E40A, ++0xD25C0009, 0x4118E104, 0xE40AE500, 0xBF692212, ++0xD7592252, 0xCB206072, 0x000B4F26, 0x4F222702, ++0x410BD156, 0xD556E400, 0x4F26452B, 0xD1552FE6, ++0x66126E63, 0x92104418, 0x44084528, 0x45002629, ++0x265B4408, 0x264B4400, 0x21624708, 0xD14E4708, ++0x217227EB, 0x6EF6000B, 0x1FFF03F0, 0x4F222FE6, ++0xE101DE4A, 0xBF3DE40A, 0x67E32E12, 0xE500776C, ++0xE204E130, 0x2752E40A, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x27522752, 0x27522752, 0x27522752, 0x27222712, ++0x27522752, 0x27522752, 0x27522752, 0x27522752, ++0x175ABF18, 0x2E62E600, 0x000B4F26, 0xD2346EF6, ++0xE441E101, 0x000B2212, 0xD1322242, 0xE605D432, ++0x000B2162, 0x000B2462, 0xD2300009, 0xE40AE601, ++0x2262AF00, 0x2FC62FB6, 0x2FE62FD6, 0x7FFC4F22, ++0x6C43DB2B, 0xED0060B2, 0x2B02CB03, 0xC90360B2, ++0x6E03A008, 0x89073DC2, 0xE46460B2, 0xB07CC903, ++0x7D016E03, 0x8BF52EE8, 0x8F043DC2, 0xD4212FE1, ++0x460BD621, 0x62F10009, 0x6023622D, 0x89FFC801, ++0x7F046023, 0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, ++0x001C3B88, 0x00203AA0, 0x002018EE, 0x00203AA8, ++0x00203AB0, 0x00203AB8, 0x00203AC0, 0x0025E720, ++0x00203DA0, 0x002038F8, 0x001C5968, 0x001C3B40, ++0x000F8000, 0x001D4004, 0x001C3500, 0x002015E0, ++0x0020160C, 0x001C5814, 0x001C59D0, 0x001C5830, ++0x001C6268, 0x001C59A4, 0x001C639C, 0x001C581C, ++0x001C5860, 0x00203AC8, 0x002018A2, 0x8F014411, ++0x6043604B, 0x0009000B, 0x5651D52B, 0x46286052, ++0x306C000B, 0x2FC62FB6, 0x2FE62FD6, 0x4F124F22, ++0xBFF14F02, 0x6B036E43, 0xDD25DC24, 0x0009BFEC, ++0x3C0530B8, 0x4609060A, 0x46014609, 0x020A3D65, ++0x42094209, 0x32E24209, 0x4F068BF0, 0x4F264F16, ++0x6DF66EF6, 0x000B6CF6, 0x2FC66BF6, 0x2FE62FD6, ++0x4F124F22, 0xBFCF4F02, 0x6C036E43, 0xBFCBDD13, ++0x30C80009, 0x060A3D05, 0x46094609, 0x36E24601, ++0x4F068BF5, 0x4F264F16, 0x6DF66EF6, 0x6CF6000B, ++0x4F222FE6, 0xE102DE0B, 0xE403E500, 0xBFB92E12, ++0xE6062E52, 0xE7004618, 0x2E62E403, 0x4F262E72, ++0x6EF6AFB0, 0x0009000B, 0x001C1040, 0xCCCCCCCD, ++0x10624DD3, 0x001D4004, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE5007F98, 0x6453E710, ++0x6B534728, 0xEE1ADCBC, 0x6153655D, 0x315C4108, ++0x75014108, 0x6043317C, 0x0F16665D, 0xED0060B3, ++0x21B136E3, 0x81128111, 0x11D28113, 0x11D411D3, ++0x74048FEA, 0xD8B167F2, 0x1871D9B1, 0x58F12872, ++0x1981D1B0, 0x59F22982, 0x5DF45AF3, 0x54F65EF5, ++0x21921191, 0x11A211A3, 0x11D411D5, 0x11E611E7, ++0x11481149, 0xDAA855F7, 0x57F8EE00, 0x52F9DDA7, ++0x64E3D6A7, 0x2A521A51, 0xD8A7D9A6, 0x2D729AD5, ++0x6EED2622, 0x4D086DE3, 0x3DEC61E3, 0x4D084108, ++0x3D9C31EC, 0x410860B3, 0x81D12DB1, 0x4108E050, ++0x4008E7B7, 0x677C4108, 0x60B381D2, 0xE200318C, ++0x81D33472, 0x1D131DD2, 0x8D01D493, 0xD4901D24, ++0xB0B365D3, 0x64ED7E01, 0x8BDA34A2, 0x2FD2DA8C, ++0xDD9268A2, 0x2D824829, 0x7DFC64A2, 0xD287694D, ++0x6E222D92, 0x7D0C4E29, 0x68222DE2, 0x618D6AD3, ++0x2A16D784, 0xD48A6D72, 0x24D2D583, 0xD6895E72, ++0x517414E2, 0x1414EE00, 0xD1875876, 0x59781486, ++0x1498E710, 0x65E36252, 0x26E2142A, 0xE60064E3, ++0x6843644D, 0x384C4808, 0x381C4808, 0x0C866053, ++0x09CE28B1, 0x819160B3, 0x0ACE6053, 0x81A26043, ++0x0DCE6053, 0x81D360B3, 0x08CE6053, 0x18827401, ++0x624D09CE, 0x0ACE19E3, 0x1A643273, 0x75048FE0, ++0xE003D96A, 0x40186C92, 0x6D922CB1, 0x81D1DA6F, ++0x6E92E050, 0x81E24008, 0x60B36192, 0x64928113, ++0x1442E600, 0xD4696792, 0x689217A3, 0x1864E1FF, ++0x6563E703, 0x364C4608, 0x26127501, 0x3673665D, ++0xDC5B8BF8, 0x6DC2E003, 0x2DB14018, 0xD2606EC2, ++0x61C281E1, 0x1112EE00, 0xE02464C2, 0x65C21423, ++0x15E4D45B, 0xE58067C2, 0x68C28172, 0x818366E3, ++0x666D655C, 0x76046963, 0x394C6A6D, 0x8FF83A53, ++0xDB5429E2, 0x24B2DC54, 0x24C27404, 0x4F267F68, ++0x6DF66EF6, 0x6BF66CF6, 0x69F66AF6, 0x68F6000B, ++0x60116142, 0x8F03C803, 0xD23DE500, 0x8B063420, ++0xC9036011, 0x8B068802, 0x3420D239, 0x56128B03, ++0x52646513, 0x000B2422, 0x01136053, 0x2FE62FD6, ++0x7FEC4F22, 0x62536E53, 0x6D43E550, 0x4508E400, ++0xE101A001, 0x60435224, 0x81212211, 0x60538123, ++0x56E28122, 0x8BF53620, 0x16E4D238, 0xE61464F3, ++0x65E3420B, 0xE4FC65E1, 0x2E512549, 0x65F361F1, ++0x2F112149, 0xD13154D1, 0xE614410B, 0x607157D1, ++0x2701CB01, 0x7F141DE1, 0x6EF64F26, 0x6DF6000B, ++0x2FE62FD6, 0x7FEC4F22, 0x66536E53, 0x6D43E5FC, ++0x20596061, 0x2601CB01, 0x326052E2, 0x12E48B06, ++0x31E051E2, 0x52D18B04, 0x1E22A002, 0x5664AFF0, ++0x64F3D21E, 0x420BE614, 0x67E165E3, 0x2719E1FC, ++0x67F12E71, 0x271954D1, 0x65F3D118, 0x410BE614, ++0x52D12F71, 0xCB016021, 0x1DE12201, 0x4F267F14, ++0x000B6EF6, 0x00006DF6, 0x00203924, 0x002034F4, ++0x002034FC, 0x00203504, 0x0020352C, 0x00203910, ++0x00203918, 0x00100208, 0x001017C0, 0x001E210C, ++0x001C3D00, 0x00203964, 0x001000C8, 0x00117880, ++0x00117780, 0x00040020, 0x0026C401, 0x00200ED6, ++0x4F222FE6, 0xDE42624C, 0x42004208, 0x3E2CA005, ++0xD4405252, 0xBF695624, 0x65E22E62, 0x352052E1, ++0xD63D8BF6, 0x4F262622, 0x6EF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xDC394F22, 0x52C1DB39, 0x362066C2, ++0x6061891C, 0x8801C903, 0xDE348918, 0xBF37DD35, ++0x650364E3, 0x66B28503, 0x3262620D, 0xD4328907, ++0x0009BF76, 0x4D0BD431, 0xAFE60009, 0xBF3D0009, ++0xD42F64E3, 0x00094D0B, 0x0009AFDF, 0x2262D22D, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x2FD62FC6, ++0x4F222FE6, 0xDD29DC28, 0x6E4360C2, 0x04DE4008, ++0xE614D127, 0x65E3410B, 0xD127D726, 0x55E227E2, ++0x35E05254, 0x21228F04, 0x400860C2, 0x122202DE, ++0x605365C2, 0x75014008, 0x0DE606DE, 0xC90F6053, ++0x60632C02, 0x6EF64F26, 0x000B6DF6, 0x85436CF6, ++0x650D5643, 0x622D6262, 0x35277204, 0xE1008F0C, ++0x2268960C, 0xD6158B03, 0x72015261, 0xD6131621, ++0x6262E101, 0x26227201, 0x6013000B, 0x000001FF, ++0x00203504, 0x002034FC, 0x001C3D00, 0x0020352C, ++0x002038F4, 0x002018A2, 0x002034F4, 0x00203AF0, ++0x00203AF4, 0x001C3D28, 0x00203964, 0x00203924, ++0x00200ED6, 0x00203968, 0x0020396C, 0x00117754, ++0x2FC62FB6, 0x2FE62FD6, 0x7FF84F22, 0x6022D237, ++0x8D58C803, 0xDE362F01, 0xDB37DC36, 0x66C252C1, ++0x892F3620, 0xC9036061, 0x892B8801, 0xD233DD31, ++0x64D3420B, 0x1F016503, 0x880160B1, 0xD2308B04, ++0x64D3420B, 0x0009AFEA, 0x85615653, 0x8904C820, ++0xE050D72C, 0x7201027E, 0xD22B0726, 0x6453420B, ++0x89072008, 0x55F1D126, 0x64D3410B, 0xE601D727, ++0x2762AFD4, 0x55F1D226, 0x64E3420B, 0xE601D125, ++0x2162AFCC, 0xDD25DE24, 0xDC26DB25, 0x66D252D1, ++0x89183620, 0xC9036061, 0x89148801, 0xD117D41F, ++0x0009410B, 0x36E05603, 0x65038F04, 0x2B20E201, ++0x2C52AFEC, 0xD712D41C, 0x0009470B, 0xE601D115, ++0xAFE34618, 0x60F12162, 0x8907C804, 0x7F08D217, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, 0x4F267F08, ++0x6DF66EF6, 0x000B6CF6, 0x00006BF6, 0x001E2100, ++0x00203504, 0x002034FC, 0x0020398C, 0x002014A0, ++0x002014CC, 0x00203494, 0x002016BE, 0x001E212C, ++0x00201530, 0x001C3D30, 0x00117880, 0x002034F4, ++0x00203914, 0x00203910, 0x0020352C, 0x00200610, ++0xE601D203, 0x1265D503, 0x000B2252, 0x00001266, ++0x001C1010, 0x0000C34F, 0x0009000B, 0x2FD62FC6, ++0x4F222FE6, 0x6D436C53, 0xEE00A004, 0x7E0164D4, ++0x644CBFF2, 0x8BF93EC2, 0x6EF64F26, 0x000B6DF6, ++0xE5006CF6, 0x6643A002, 0x76017501, 0x22286260, ++0xAFE38BFA, 0x2FE60009, 0x75076253, 0xE1086753, ++0x6043EE0A, 0x4409C90F, 0x650330E2, 0x8D014409, ++0xE630E637, 0x4110365C, 0x8FF22760, 0xE00077FF, ++0x000B8028, 0x000B6EF6, 0x000BE000, 0x2FE6E000, ++0x7FEC4F22, 0x6E436253, 0xBFDC65F3, 0xBFD06423, ++0xBFCE64E3, 0xD40364F3, 0x0009BFCB, 0x4F267F14, ++0x6EF6000B, 0x00203AF8, 0xE4FDD29F, 0xD79F6122, ++0x22122149, 0x74016022, 0x2202CB01, 0xD59C6622, ++0x22622649, 0xC8406070, 0x60528902, 0x2502CB04, ++0xE1F76452, 0x25422419, 0xE7016052, 0x2502CB40, ++0xE6026052, 0x2502C9CF, 0x47186052, 0x2502CB10, ++0xCB036052, 0x15622502, 0x1573000B, 0xD78ED58D, ++0xD48FD28E, 0xE600E100, 0x27112511, 0xAFCB2210, ++0x664C2461, 0x4600D28B, 0x6060362C, 0x000BCB10, ++0x654C2600, 0x4500D287, 0x6650352C, 0x2619E1EF, ++0x2560000B, 0xD284664C, 0x362C4600, 0xCB106060, ++0x2600000B, 0xD280654C, 0x352C4500, 0xE1EF6650, ++0x000B2619, 0x664C2560, 0x4600D27A, 0x6060362C, ++0x000BCB08, 0x654C2600, 0x4500D276, 0x6650352C, ++0x2619E1F7, 0x2560000B, 0xD273664C, 0x362C4600, ++0xCB086060, 0x2600000B, 0xD26F654C, 0x352C4500, ++0xE1F76650, 0x000B2619, 0x624C2560, 0x4200D669, ++0x6020326C, 0x4021C908, 0x40214021, 0x600C000B, ++0xD665624C, 0x326C4200, 0xC9086020, 0x40214021, ++0x000B4021, 0xD161600C, 0x341C644C, 0x000B6240, ++0xD15F602C, 0x341C644C, 0x000B6240, 0x2FE6602C, ++0x6E434F22, 0xE60A645C, 0x89143467, 0x0009BFEB, ++0x60EC640C, 0x8B028801, 0xA002E00F, 0x44092409, ++0x624C4409, 0x3263E60A, 0xBFE28905, 0x620C644C, ++0xC8806023, 0xE2008B00, 0x4F266023, 0x6EF6000B, ++0xD64C4F22, 0x88016062, 0xB2578B03, 0xA0030009, ++0xD2490009, 0x2260E640, 0xE200D648, 0x000B4F26, ++0x4F222622, 0x6062D643, 0x8B018802, 0x0009B2A0, ++0xE200D642, 0x000B4F26, 0xD53E2622, 0xE100D43E, ++0x2512E701, 0x2470000B, 0xE604D23B, 0x2260000B, ++0xD43B4F22, 0x410BD13B, 0xD53B0009, 0x6650E1FD, ++0x2619D23A, 0x2560E700, 0x000B4F26, 0x4F222270, ++0xD238D537, 0xD7386152, 0x2512611D, 0xE6FF6452, ++0x2542242B, 0xD22FD435, 0x420B666D, 0xD52E2762, ++0x6750E1FB, 0x4F262719, 0x2570000B, 0xD4304F22, ++0x410BD128, 0xD5280009, 0x6650E7F7, 0x4F262679, ++0x2560000B, 0x9425D524, 0x22496250, 0x2520000B, ++0xE4BFD521, 0x22496250, 0x2520000B, 0xD2254F22, ++0x600D8522, 0x89112008, 0x89458801, 0x89478803, ++0x89498805, 0x894F8806, 0x89558808, 0x895B8809, ++0x8961880A, 0x8967880B, 0x0009A06E, 0x0009B070, ++0x600CA06B, 0x0000FF7F, 0x001E2148, 0x001E1000, ++0x001E1108, 0x002039C4, 0x002039C6, 0x002039E5, ++0x002039A8, 0x001E103F, 0x001E105F, 0x001E102F, ++0x001E1090, 0x002039CC, 0x001E100B, 0x002039C8, ++0x00203AFC, 0x002018A2, 0x001E1028, 0x002039E4, ++0x001D4020, 0x98760000, 0x001C1000, 0x00203B08, ++0x00203B18, 0x0020399C, 0x0009B04C, 0x600CA035, ++0x0009B055, 0x600CA031, 0x6260D684, 0x8B2B2228, ++0x0009B061, 0x600CA029, 0x6260D680, 0x8B232228, ++0x0009B069, 0x600CA021, 0x6260D67C, 0x8B1B2228, ++0x0009B0C7, 0x600CA019, 0x6260D678, 0x8B132228, ++0x0009B0CD, 0x600CA011, 0x6260D674, 0x8B0B2228, ++0x0009B125, 0x600CA009, 0x6260D670, 0x8B032228, ++0x0009B13D, 0x600CA001, 0x4F26E000, 0x0009000B, ++0xD26CD16B, 0xD56C8412, 0x4000C90F, 0xD76B012D, ++0xE403D66B, 0xE20F611C, 0x2540E001, 0x25202712, ++0x2602000B, 0xE601D262, 0x30668523, 0xE0008D05, ++0xD663D260, 0xE0018122, 0x000B2602, 0xD25C0009, ++0x600D8523, 0x89052008, 0x8B0A8801, 0x6060D65D, ++0x2600CB01, 0xD457D65A, 0xE001E101, 0x000B2612, ++0x000B8142, 0xD152E000, 0x8513E501, 0x640D4518, ++0x66033453, 0xE0008D05, 0xD551D253, 0x2260E001, ++0x000B2502, 0x4F220009, 0x8513D149, 0x6453650D, ++0x62494419, 0x227D672E, 0x8801602C, 0x88028909, ++0x88038910, 0x8806891A, 0x88078935, 0xA04C893B, ++0xD5460009, 0x6652D746, 0x2762D446, 0x622C6261, ++0x2421A038, 0x2228625C, 0xD4438B3F, 0x6642D540, ++0x2562D440, 0x24018561, 0x6203A02C, 0x2008605C, ++0x88108907, 0x88208908, 0x88308909, 0xA02C890A, ++0xD23A0009, 0x6222A008, 0xA005D239, 0xD2396222, ++0x6222A002, 0x6262D638, 0xD432D531, 0x66212522, ++0xA00F626C, 0xD6352421, 0x6261D52D, 0x622CD42D, ++0xA0072562, 0xD6322421, 0x8561D529, 0x2562D429, ++0x62032401, 0x662D8515, 0x3617610D, 0x65038F01, ++0xB0CB2451, 0xA0010009, 0xE000E001, 0x000B4F26, ++0xD6190009, 0xD427E101, 0x65412610, 0xD118D717, ++0xE20F655D, 0x2752E001, 0x000B2620, 0x2FE62102, ++0xD20F4F22, 0x640C8523, 0x8B082448, 0xD511D61D, ++0x2621E200, 0x940F8451, 0xA0482049, 0xDE0D8051, ++0xC84060E0, 0xE2018D32, 0x89443427, 0xD216D615, ++0x2641420B, 0x0009A030, 0x0000FF7F, 0x002039E5, ++0x0020399C, 0x002039A8, 0x001E1100, 0x001E100C, ++0x002039C8, 0x001E1000, 0x001E1001, 0x002039D0, ++0x002039B0, 0x002039B4, 0x002039B8, 0x002039D4, ++0x002039D8, 0x002039DC, 0x002039E0, 0x00203E04, ++0x00203E0E, 0x002039C2, 0x00202886, 0x89123427, ++0xD294D693, 0x2641420B, 0xCB8084E1, 0x80E1B0F5, ++0xD69160E0, 0x2E00CB04, 0xC93F6060, 0xD68F2600, ++0xA001E001, 0xE0002602, 0x000B4F26, 0xD68C6EF6, ++0xC8806060, 0xD2868919, 0x88016021, 0xD2898B15, ++0x8524E501, 0x89103056, 0xE203D187, 0x2120D487, ++0xE00B6541, 0x0656655D, 0xE40FD585, 0x2140E702, ++0xD77E2571, 0x000BE001, 0x000B2702, 0x2FE6E000, ++0xDE804F22, 0xC88084E1, 0xD57A892C, 0x20088554, ++0x61038F28, 0x8553D77C, 0x64036672, 0x8566650C, ++0x3520620C, 0xD6798B1E, 0x651CD774, 0x2651644C, ++0x60E02741, 0x8904C840, 0x420BD275, 0xA0030009, ++0xD2680009, 0x0009420B, 0x0009B09F, 0xE201D167, ++0x60E02122, 0xCB04D464, 0x60402E00, 0x2400C93F, ++0x6023A001, 0x4F26E000, 0x6EF6000B, 0x2FB62FA6, ++0x2FD62FC6, 0xDA622FE6, 0x66A1E240, 0x3622DC5E, ++0x62638900, 0x6ED36D2C, 0x4E2136D8, 0x4E212A61, ++0xDB61D460, 0xE700A00F, 0x770162B2, 0x71026123, ++0x66212B12, 0x71026213, 0x61212B12, 0x651D666D, ++0x356C4528, 0x627C2452, 0x8BED32E3, 0xC90360D3, ++0x8B108803, 0x617367B2, 0x2B127102, 0x71026E13, ++0x2B126571, 0x655D6DE1, 0x422862DD, 0x325CE107, ++0xA00C2C10, 0x88022422, 0xA0038B01, 0x8801E203, ++0xE2018B05, 0x66B22C20, 0x655D6561, 0xE60F2452, ++0x67A12C60, 0x8B052778, 0xDD38DC44, 0xEB01EA00, ++0x2DB22CA2, 0x6DF66EF6, 0x6BF66CF6, 0x6AF6000B, ++0x2FE62FD6, 0xE240DD36, 0x362266D1, 0x62638900, ++0x3678672C, 0x7703DE38, 0x47212D61, 0x64E2D635, ++0xA00E4721, 0x6562E100, 0x62537101, 0x74012450, ++0x24204219, 0x45297401, 0x74012450, 0x24504519, ++0x621C7401, 0x8BEE3273, 0x66E24200, 0x420061D1, ++0x2118362C, 0x2E628F06, 0xDD1CD728, 0xE501E400, ++0x2D522742, 0x000B6EF6, 0x2FD66DF6, 0x4F222FE6, ++0xED0AEE01, 0x64E3BC85, 0xBC8A64E3, 0x62EC7E01, ++0x8BF732D7, 0xBC8DEE01, 0x64E364E3, 0x7E01BC92, ++0x32D762EC, 0x4F268BF7, 0x000B6EF6, 0xD1186DF6, ++0xD418920D, 0x72122122, 0x2422D617, 0xD7177204, ++0x72202622, 0x2722D116, 0x000B7230, 0x137A2122, ++0x002039C2, 0x00202992, 0x001E1015, 0x002039C8, ++0x001E1001, 0x0020399C, 0x001E1100, 0x002039C6, ++0x002039B4, 0x001E1000, 0x002039B8, 0x002039C4, ++0x00202886, 0x001E100C, 0x002039B0, 0x002039CC, ++0x002039D0, 0x002039D4, 0x002039D8, 0x002039DC, ++0x002039E0, 0x4F222FE6, 0xD6707FFC, 0x88016060, ++0xE2018951, 0x2620BFBB, 0xD56ED16D, 0xDE6E6010, ++0x64E36552, 0x7402C840, 0x8D22D16C, 0xD26C7502, ++0xE601D76C, 0xE7042722, 0x76016255, 0x626C2421, ++0x8FF93273, 0xD4637402, 0x6242E601, 0x640D8528, ++0x67494419, 0x275D657E, 0x81E4607C, 0xE417D562, ++0x67557601, 0x3243626C, 0x8FF92171, 0xA0207102, ++0xD25E0009, 0xE601D75B, 0xE7042722, 0x76016255, ++0x626C2421, 0x8FF93273, 0xD4527402, 0x6242E601, ++0x640D8528, 0x67494419, 0x275D657E, 0x81E4607C, ++0xE417D553, 0x67557601, 0x3243626C, 0x8FF92171, ++0x92897102, 0xD2462E21, 0x5E23D74E, 0x64F22FE2, ++0x604365F2, 0x2700C980, 0xC9606043, 0x80716103, ++0xC9036043, 0x80724519, 0x65F2605C, 0x817266F2, ++0x46194629, 0x606C4529, 0x4018645C, 0x8173304C, ++0x21185E23, 0x64F22FE2, 0x6E4C62F2, 0x602C4219, ++0x66F262F2, 0x46294018, 0x461930EC, 0x42298174, ++0x652C606C, 0x305C4018, 0x81758F07, 0x0009BC96, ++0x2228620C, 0xA00A8908, 0x60130009, 0x8B038840, ++0x0009B009, 0x0009A003, 0xE202D62F, 0x7F042622, ++0x000B4F26, 0x4F226EF6, 0x8552D52A, 0x8830600D, ++0x88318903, 0xA0348923, 0x85550009, 0xD428D727, ++0x85532701, 0x610DD627, 0x24124118, 0x460BD426, ++0xD7230009, 0xD226D425, 0x6572420B, 0xE230D120, ++0x42286712, 0x2729E620, 0x37604628, 0xD6218B03, ++0xA016E200, 0xD61F2622, 0xA012E202, 0xD1182622, ++0x6212E530, 0xE6204528, 0x46282259, 0x89083260, ++0xD41AD119, 0xE601D513, 0x2160450B, 0x472BD718, ++0x4F264F26, 0x0009000B, 0x0000060A, 0x002039E4, ++0x001E1000, 0x002039D0, 0x00203E04, 0x00203E10, ++0x00203DA8, 0x002039B8, 0x00203DD8, 0x00203DD6, ++0x00203DAA, 0x0020399C, 0x002039C8, 0x002039B4, ++0x002039B0, 0x002018A2, 0x00203B24, 0x00203B28, ++0x002018EE, 0x002039CC, 0x001E100B, 0x00203B3C, ++0x00114004, 0x4F222FE6, 0xDE967FFC, 0x200884E9, ++0x2F008D06, 0xD695D494, 0x0009460B, 0x64F0B19A, ++0x6620D293, 0x89022668, 0xC9BF60E0, 0x7F042E00, ++0x000B4F26, 0x000B6EF6, 0x2FE60009, 0xDE8D4F22, ++0x60E0D68D, 0xCBC0D48D, 0x62602E00, 0xC803602C, ++0x40218904, 0x70014021, 0x6603A002, 0x66034009, ++0xD687616D, 0xE500A004, 0x75016262, 0x74042422, ++0x3213625D, 0xD2838BF8, 0x0009420B, 0xC9BF84E2, ++0x4F2680E2, 0x6EF6000B, 0x2FE62FD6, 0x7FFC4F22, ++0x6260D67D, 0x89442228, 0xD572E100, 0x60502610, ++0xCB40D47A, 0x2500440B, 0x8D052008, 0x62E06E03, ++0x7104612C, 0x2F11A006, 0xD475D66D, 0xDD756760, ++0x657C4D0B, 0xE23C6D1D, 0x8B033D27, 0xD267D472, ++0x0009420B, 0x4D214D21, 0xA005D770, 0x66E6E400, ++0x357C4508, 0x74012562, 0x35D3654D, 0xD76C8BF7, ++0x6172E003, 0x81114018, 0x6E7260F1, 0x81E2700C, ++0xD4686172, 0xDD688113, 0x4D0BDE68, 0xE2016572, ++0xD4672E22, 0x420BD255, 0xD6560009, 0xC93F6060, ++0x7F042600, 0x6EF64F26, 0x6DF6000B, 0x2FC62FB6, ++0x2FE62FD6, 0xD25F4F22, 0x6B436E73, 0x420B6C53, ++0x20086D63, 0x64038D1C, 0xE50ED149, 0x32526210, ++0x60C38916, 0x804124B0, 0x814160D3, 0xA007E500, ++0x655D61BC, 0x00EC6053, 0x364C6653, 0x80647501, ++0x3213625D, 0xD63B8BF5, 0xC9BF6060, 0x2600A008, ++0xD23AD44D, 0x6EF64F26, 0x6CF66DF6, 0x6BF6422B, ++0x6EF64F26, 0x6CF66DF6, 0x6BF6000B, 0x7FC44F22, ++0x720262F3, 0x22512F41, 0x45297202, 0x60632251, ++0xE5C4E682, 0x67F38121, 0x655C666C, 0xE408BFB6, ++0x4F267F3C, 0x0009000B, 0x2F962F86, 0x2FB62FA6, ++0x2FD62FC6, 0x4F222FE6, 0xE1007FC4, 0x6513ECFF, ++0x6B136CCD, 0xDE36D735, 0xEDFF64F3, 0xD835EA04, ++0x6053655C, 0x027D4000, 0x32C0622D, 0x66038D0D, ++0x09ED6063, 0x2491027D, 0x24217402, 0x698202ED, ++0x3928622D, 0x74022892, 0x75017104, 0x6063625C, ++0x07D532A2, 0x0EB58FE4, 0x2448641C, 0xE6808905, ++0x67F3E5C5, 0xBF79666C, 0x7F3C655C, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0xD11E68F6, ++0x6012D21E, 0xCB20E405, 0x2102E500, 0x000B2242, ++0x00002252, 0x001E1017, 0x00203B40, 0x002018A2, ++0x0020390E, 0x001E1015, 0x001E10BF, 0x00117800, ++0x001E10FC, 0x00200610, 0x00203914, 0x00202AEA, ++0x00203B44, 0x002018EE, 0x00203B60, 0x0011788C, ++0x00203910, 0x002034F4, 0x00201530, 0x001E2130, ++0x00203B68, 0x00202AAC, 0x00203B6C, 0x00203974, ++0x0020397C, 0x00203DA4, 0x001C3500, 0x001D4004, ++0xD564D163, 0xE400D764, 0x2142E20F, 0x17411154, ++0xD5622722, 0x9669D762, 0x15412572, 0x96661562, ++0xE6011565, 0xD55F1165, 0x666CE6F8, 0x25422542, ++0x25422542, 0x25422542, 0x25622542, 0x7601E727, ++0x67632572, 0x25627797, 0xE7042572, 0x2572E248, ++0xE2192522, 0xE2702522, 0x25422542, 0x25422542, ++0x25222542, 0x2522E20C, 0x25422542, 0x25422542, ++0x25422542, 0x25422542, 0x000B154A, 0xE2081145, ++0x0009422B, 0x2FE62FD6, 0x7FFC4F22, 0xC8206043, ++0x6E438D02, 0x0009BE67, 0xC81060E3, 0xBE648901, ++0x60E30009, 0x8901C840, 0x0009BE86, 0xC80160E3, ++0xDD3D8938, 0xC80260D0, 0x2F008D03, 0x460BD63B, ++0x60F00009, 0x8902C804, 0x460BD639, 0x62F00009, ++0xC8806023, 0x60D08902, 0x2D00C97F, 0xC8016023, ++0xD6348906, 0x0009460B, 0x0009A007, 0x51630601, ++0x8902C808, 0x460BD630, 0x60F00009, 0x8902C810, ++0x420BD22E, 0xD52E0009, 0x88026052, 0xD22D8B03, ++0xA005E604, 0x88012260, 0xD22A8B02, 0x2260E601, ++0x2522E200, 0xC88060E3, 0xD227892D, 0x60E36E20, ++0x8902C880, 0x420BD225, 0x60E30009, 0x8902C840, ++0x420BD223, 0x60E30009, 0x8902C802, 0x420BD221, ++0x60E30009, 0x890DC804, 0xDD20D11F, 0x0009410B, ++0x0009BF0D, 0x0009BF4C, 0xD51ED41D, 0x2470E708, ++0x25D2BF85, 0xC80860E3, 0xD21B8905, 0x4F267F04, ++0x422B6EF6, 0x7F046DF6, 0x6EF64F26, 0x6DF6000B, ++0x001C581C, 0xA000A000, 0x001D0100, 0x001D4000, ++0x00040021, 0x001C589C, 0x001E1021, 0x00201A90, ++0x00201AB2, 0x00202114, 0x00201ACA, 0x00201AD8, ++0x002039C8, 0x001E100B, 0x001E1028, 0x00201B44, ++0x00201B50, 0x00201AE0, 0x00201AFE, 0x12345678, ++0x001E1000, 0x0010F100, 0x00201B2C, 0x644CD6A7, ++0x000B346C, 0xD6A62450, 0x346C644C, 0x2450000B, ++0x644CD6A4, 0x000B346C, 0x625C2450, 0x4208616D, ++0x42084119, 0x42006019, 0x670E614C, 0xD49E321C, ++0x4200207D, 0x324CC90F, 0x2200000B, 0x4208625C, ++0x42004208, 0x324C644C, 0x4200D498, 0x000B324C, ++0x2FE62260, 0x614C4F12, 0x4100D493, 0x6710314C, ++0xE29F666D, 0x27294619, 0x6E536269, 0x672E6573, ++0x4221227D, 0x42214221, 0x7601662C, 0xE4014608, ++0x34E84608, 0x644C4600, 0x071A0467, 0x2150257B, ++0x000B4F16, 0x4F226EF6, 0xD2857FE8, 0x88016021, ++0xD2848B7B, 0x26686621, 0xD2838B77, 0x26686621, ++0xE50F8B73, 0xE401BFA2, 0xBFA4E501, 0xE586E400, ++0xE400655C, 0x2F50BFA4, 0xBFA1E401, 0xE602E506, ++0x60634618, 0x81F2E401, 0x6543BF9F, 0xE40185F2, ++0xBFAB6543, 0x85F26603, 0x6543E401, 0x6603BFB1, ++0xE40265F0, 0x6053756C, 0x80F8BF80, 0xBF82E402, ++0x84F8E512, 0x7090E402, 0x6503BF82, 0x4618E602, ++0x81F66063, 0xBF80E402, 0x85F6E500, 0x6603E402, ++0xE500BF8C, 0xE40285F6, 0xBF926603, 0xE5FEE500, ++0xE010655C, 0xBF61E403, 0xE5130F54, 0xE40EBF63, ++0x05FCE010, 0xBF63E40E, 0xE5007585, 0xBF64E403, ++0xE500E640, 0xBF71E403, 0xE500E640, 0xBF78E403, ++0xE5FFE640, 0xE014655C, 0xBF47E404, 0xE40F0F54, ++0xE504BF49, 0x05FCE014, 0xBF49E40F, 0xE5017584, ++0xBF4AE640, 0xE501E404, 0xBF57E640, 0xE501E404, ++0xE404E640, 0xAF5C7F18, 0x7F184F26, 0x000B4F26, ++0x4F220009, 0xD2427FF0, 0x88016021, 0xD2418B71, ++0x26686621, 0xD2408B6D, 0x26686621, 0xE50F8B69, ++0xE401BF1C, 0xBF1EE501, 0xE586E400, 0xE400655C, ++0x2F50BF1E, 0xBF1BE401, 0xE401E506, 0xBF1C6543, ++0xE401E640, 0xBF296543, 0xE401E640, 0xBF306543, ++0x65F0E640, 0x756CE402, 0xBEFF6053, 0xE40280F4, ++0xE512BF01, 0xE40284F4, 0xBF017090, 0xE6406503, ++0xBF02E402, 0xE640E500, 0xBF0FE402, 0xE640E500, ++0xBF16E402, 0xE5FEE500, 0x6053655C, 0xBEE5E403, ++0xE51380F8, 0xE40EBEE7, 0xE40E84F8, 0xBEE77085, ++0xE5006503, 0xBEE8E640, 0xE500E403, 0xBEF5E640, ++0xE500E403, 0xBEFCE640, 0xE5FFE403, 0x6053655C, ++0xBECBE404, 0xE40F80FC, 0xE504BECD, 0xE40F84FC, ++0xBECD7083, 0xE5016503, 0xBECEE640, 0xE501E404, ++0xBEDBE640, 0xE501E404, 0xE404E640, 0xAEE07F10, ++0x7F104F26, 0x000B4F26, 0x00000009, 0x001E102F, ++0x001E1080, 0x001E1090, 0x001E103F, 0x001E103E, ++0x002039C2, 0x002039C4, 0x002039C6, 0xD21DD11C, ++0x66206010, 0x676C7001, 0x3700C90F, 0xE5008D13, ++0x67106210, 0x7701622C, 0x64232170, 0xD6166010, ++0x44084408, 0x3428C90F, 0x62602100, 0x7201D513, ++0x44082620, 0x000B354C, 0xD10F6053, 0x25586510, ++0xE6008D13, 0xD60DD40B, 0x655C6540, 0x47086753, ++0x37584708, 0x47086540, 0x24507501, 0x367C6040, ++0x2400C90F, 0x72FF6210, 0x000B2120, 0x00006063, ++0x0020390D, 0x0020390C, 0x0020390E, 0x00203534, ++0x7FFC4F22, 0xE680D19F, 0x666C6212, 0xD29E2F22, ++0x67F36563, 0x420B7542, 0x7F04E404, 0x000B4F26, ++0xE6800009, 0xD298666C, 0xE7006563, 0x422B7540, ++0xE6806473, 0xD294666C, 0xE7006563, 0x422B7543, ++0x2F866473, 0x2FA62F96, 0x2FC62FB6, 0x2FE62FD6, ++0x7FCC4F22, 0xDC8ED28D, 0x72011F21, 0xDB8D1F22, ++0xD18EDE8D, 0x66125211, 0x8B013620, 0x0009A0E5, ++0xC9036061, 0x8B018801, 0x0009A0DF, 0xD288D487, ++0xED84420B, 0x2F025503, 0x30D0845C, 0xA0B88901, ++0xD1840009, 0x626C6610, 0x88016023, 0xD1828B68, ++0x62101FC3, 0x895B2228, 0xE003D480, 0x40186742, ++0x68421772, 0xD57EE900, 0x81816DB3, 0x7D042190, ++0x67D26AB2, 0x64E26852, 0x1F491F57, 0x740464E3, ++0x1FA46542, 0x65431F5A, 0x625275F8, 0x1F761FD5, ++0x6D531F2B, 0xDA74D773, 0x7D94D274, 0x68D21F88, ++0x6AA26972, 0xD1726022, 0x2202CB20, 0xE1401F1C, ++0x7601E600, 0x3213626D, 0x56F48BFB, 0x52F651F5, ++0x21222B62, 0x52F851F7, 0x212256F9, 0x2E6251FA, ++0x51FB2412, 0x2D822512, 0xD9662792, 0x29A2DD5F, ++0x6AD2D965, 0xD9646892, 0x68D21A84, 0x6081DA63, ++0x2801CB01, 0xD86266D2, 0x2A622962, 0xED015AFC, ++0x2AD2480B, 0x2AD24D18, 0x62D2DD5E, 0x2D227201, ++0xD15056F3, 0xE2026062, 0x2602CB01, 0x2120A03D, ++0x8B3A2228, 0xE401DD58, 0x2140E600, 0xE01C2D62, ++0xC801005C, 0xD4558B0A, 0xE600D755, 0xED7D2472, ++0x626C7601, 0x8BFB32D3, 0x24D2DD52, 0xE2FE68C2, ++0x2C822829, 0x095CE01E, 0xE01F5DF1, 0x0A5C2D90, ++0x751051F2, 0xED0621A0, 0xD74BE600, 0x8456D44B, ++0x27007601, 0x696C6854, 0x248039D3, 0x8FF67401, ++0xDA477701, 0x2A10E194, 0xE2007A01, 0x7A0F2A20, ++0xD130E805, 0x66102A80, 0x6023626C, 0x89088801, ++0xD240D42A, 0x420B65F2, 0xD131ED01, 0xAF304D18, ++0x65F221D2, 0x8553D43C, 0x620D6642, 0x89073262, ++0xD13BD43A, 0x0009410B, 0xE601D73A, 0x2762AF1A, ++0xD134D41E, 0x410B65F2, 0xD125ED01, 0xD637D436, ++0x460B4D18, 0xAF0D21D2, 0x7F340009, 0x6EF64F26, ++0x6CF66DF6, 0x6AF66BF6, 0x000B69F6, 0x4F2268F6, ++0x85467FF4, 0x2F01E681, 0x666C8547, 0x854881F1, ++0x81F2D209, 0x67F38542, 0x854381F3, 0x81F4E40C, ++0x65636053, 0x420B81F5, 0x7F0C7540, 0x000B4F26, ++0x00000009, 0x001C3D9C, 0x0020245C, 0x0011779A, ++0x001C36F8, 0x001C3B9C, 0x001C3704, 0x0020352C, ++0x002014A0, 0x0020391D, 0x0020391C, 0x00203918, ++0x001C3D98, 0x001C3BB4, 0x001C5960, 0x001C3500, ++0x001C3D30, 0x001C8960, 0x00203504, 0x001C3D00, ++0x0020160C, 0x00117730, 0x00203920, 0x001C582C, ++0x2000A000, 0x0000A000, 0x0011778C, 0x00117792, ++0x00117788, 0x002014CC, 0x002038F4, 0x002034F4, ++0x00201530, 0x001E2130, 0x00203D84, 0x002018A2, ++0x2F962F86, 0x2FB62FA6, 0x2FD62FC6, 0x4F222FE6, ++0xD19B7FEC, 0x2F12E000, 0x6103D49A, 0x1F4281F2, ++0xDD9ADA99, 0xD69A6813, 0xE0014808, 0x460BDE99, ++0x38EC4800, 0x65A21F03, 0x352052A1, 0xA23E8B01, ++0x60510009, 0x8801C903, 0xA2388B01, 0x52530009, ++0x32E0DE91, 0xD9918B10, 0x64A3490B, 0x4B0BDB90, ++0xDE906403, 0xD791D690, 0xEC01D591, 0x2E02E100, ++0x271026C0, 0x2502AFDF, 0xC8018551, 0xA1578B01, ++0x62510009, 0x4200622D, 0x5E53366A, 0x85E2226D, ++0xC903642C, 0x85E36603, 0x6053650D, 0x40214021, ++0x4500C93F, 0x322A6703, 0x6053252D, 0xC901D17F, ++0x60106C03, 0x8801D97F, 0xDB7F8B05, 0x2120E200, ++0xCB0160B2, 0xD17D2B02, 0x88016011, 0x65A28B0A, ++0x8D042448, 0x9B9E6251, 0xA00322B9, 0x919B2521, ++0x2521221B, 0x37B3EB10, 0x2448895E, 0xD4738B07, ++0x22286241, 0x60638903, 0xA05781F8, 0xD5706473, ++0x46084608, 0x85E26273, 0x46006B50, 0x362C4200, ++0x2BB8C910, 0x8F1F6463, 0x26686603, 0xD2698911, ++0x062D6043, 0x4119616D, 0x6B0E6019, 0x81F820BD, ++0x880160C3, 0x646C8F2C, 0x880F6073, 0xA0278B1B, ++0xD2610009, 0x052D6043, 0x4119615D, 0x670E6019, ++0x645C207D, 0x81F8A01C, 0x890F2668, 0x6043D25B, ++0x6B5D052D, 0x60B94B19, 0x201D610E, 0x60C381F8, ++0x8F0D8801, 0x6473645C, 0xEC00A00A, 0x6043D254, ++0x625D052D, 0x60294219, 0x207D670E, 0x81F8645C, ++0x880285F8, 0x85E1890A, 0x8D07C820, 0xE6DC6203, ++0x60232269, 0x81E1A002, 0x644CE4FF, 0x6210D149, ++0x89012228, 0x644CE4FF, 0x654DEBFF, 0x35B06BBC, ++0xDB368B2B, 0x64A34B0B, 0x410BD135, 0x54036403, ++0x85446E03, 0xC948DB40, 0xDC408808, 0xBEAE8B01, ++0x64B3E502, 0x65E34C0B, 0xDB3DEC01, 0xD13D2DC2, ++0x621260B2, 0x72017001, 0x21228805, 0x2B028F08, ++0x666CE680, 0x6563D238, 0x7549E700, 0x6473420B, ++0xA030D436, 0x7FFF0009, 0x85E28000, 0x20B9EBFC, ++0x610381E2, 0x942A85E3, 0x62032049, 0x450885F8, ++0x81E2201B, 0xC90160C3, 0x40084018, 0x40084008, ++0x4000225B, 0x6023220B, 0x85E481E3, 0x4118E108, ++0x81E4201B, 0xE40262A2, 0x20B98521, 0x67A28121, ++0xCB016071, 0x85F82701, 0x89033042, 0xECE785E2, ++0x81E220C9, 0x490BD41E, 0xA03B0009, 0x7E030009, ++0x001C3D30, 0x00203D90, 0x00203504, 0x001E212C, ++0x002033E8, 0x001C3D00, 0x00117780, 0x002014A0, ++0x0020166C, 0x0011770C, 0x0020391C, 0x0020391D, ++0x00203918, 0x002018A2, 0x001C36F8, 0x00203990, ++0x00203DA0, 0x00203B84, 0x00203C04, 0x00203C84, ++0x00203D04, 0x00203908, 0x002034FC, 0x002014CC, ++0x00203994, 0x00203998, 0x0020245C, 0x00203D88, ++0x00203D8C, 0x602262F2, 0x40094019, 0xC90F4009, ++0x8B0B880A, 0x60E2DE8C, 0x40094019, 0xC90F4009, ++0x8B038808, 0xCB0160A2, 0x2802A006, 0x65E2DE87, ++0x2E527501, 0x286266A2, 0x52F366F2, 0x2622AE83, ++0xD2838551, 0xDE83C802, 0xA0958B01, 0x420B0009, ++0x4E0B64A3, 0x5E036403, 0x85E46503, 0x4918E908, ++0xD77D209B, 0xE04C81E4, 0xDC7C0B7E, 0x7B01D97C, ++0x61C207B6, 0x71016690, 0x8D062668, 0xD4792C12, ++0x420BD279, 0xA070EB01, 0x62512DB2, 0x4B18EB0F, ++0x22B9E102, 0x32104118, 0x85518B0F, 0x2029E2FC, ++0x60518151, 0xCB0172E0, 0x85E12501, 0x202994A3, ++0x85E481E1, 0xA0522049, 0x675181E4, 0x4719677D, ++0x667E6779, 0x7701276D, 0x6903607C, 0x88014918, ++0x25918F3E, 0x6B12D161, 0x21B27B01, 0x660D85E3, ++0x40216063, 0xC93F4021, 0x6C034600, 0x262D322A, ++0xC8016063, 0xDB5ED15D, 0x967D8901, 0xE6002C6B, ++0x666C67CD, 0x40006063, 0x622D021D, 0x8D0E3270, ++0x60436403, 0xE9FF021D, 0x8B013290, 0x01C5A007, ++0x626C7601, 0x3292E904, 0x646C8BEB, 0x60434400, ++0xD15004BD, 0x0B457401, 0x669D6911, 0x89073670, ++0x602D6211, 0x890388FF, 0xE201DB4B, 0x2B2021C1, ++0xECFC8551, 0x815120C9, 0xCB016051, 0xDC472501, ++0x64A34C0B, 0x51F366F2, 0x85EF2612, 0x54F2D244, ++0x650D420B, 0x0009ADE7, 0xE500DC42, 0x420B2C52, ++0x4E0B64A3, 0x54036403, 0x85446E03, 0x6703E908, ++0x65034918, 0x27998541, 0xDB323790, 0x8F0BD932, ++0x6013610D, 0x8B07C820, 0xC9486053, 0x8B038808, ++0xE501BD4D, 0x0009A005, 0x2128D233, 0xBD468901, ++0x64B3E500, 0x490B65E3, 0xADBCEC01, 0x85F22DC2, ++0x7001EE04, 0x31E7610D, 0x8D0281F2, 0xADA97A08, ++0x7F140009, 0x6EF64F26, 0x6CF66DF6, 0x6AF66BF6, ++0x000B69F6, 0xF7FF68F6, 0x2FE68000, 0xD2234F22, ++0x60E36E22, 0x8D02C840, 0xBBF922E2, 0xE2400009, ++0x2E284218, 0xBC048901, 0x60E30009, 0x8905C810, ++0xD21CD41B, 0x0009420B, 0x0009BC03, 0xC80560E3, ++0xBD6D8901, 0x60E30009, 0x8902C802, 0xAC004F26, ++0x4F266EF6, 0x6EF6000B, 0x001C3D3C, 0x00117760, ++0x002014A0, 0x0020166C, 0x00203494, 0x00203DA4, ++0x00203908, 0x002034FC, 0x002014CC, 0x00203974, ++0x0020397C, 0x00203970, 0x00203972, 0x00201530, ++0x002018EE, 0x00203994, 0x00008000, 0x001C3510, ++0x00203D98, 0x002018A2, 0x080A0C0E, 0x00020406, ++0x1A1C1E20, 0x12141618, 0x2E303234, 0x26282A2C, ++0x3A3C3E40, 0x6C625648, 0x41112F26, 0xE2208F18, ++0x890B3123, 0x321CD204, 0xD1026220, 0x412B312C, ++0x00090009, 0x00203412, 0x002033C8, 0x000BE000, ++0x400062F6, 0x40004000, 0x40004000, 0x40004000, ++0x62F6000B, 0x40004000, 0x40004000, 0x40004000, ++0x40184000, 0x62F6000B, 0x40004000, 0x40004000, ++0x40004000, 0x40284000, 0x62F6000B, 0x40004000, ++0x40184000, 0x000B4028, 0xC90F62F6, 0x40054005, ++0x40054005, 0x62F6000B, 0x4005C907, 0x40054005, ++0x62F6000B, 0x4005C903, 0x000B4005, 0xC90162F6, ++0x000B4005, 0x000062F6, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x544F0D0A, 0x46205355, 0x00003A57, ++0x206C754A, 0x32203120, 0x20383030, 0x323A3132, ++0x34333A38, 0x00000000, 0x00000D0A, 0x00000043, ++0x42707372, 0x3D206675, 0x554E203D, 0x202C4C4C, ++0x6E49677A, 0x4E497274, 0x6D754E51, 0x0000003D, ++0x61766E49, 0x2064696C, 0x72657375, 0x20726F20, ++0x2079656B, 0x00214449, 0x52504545, 0x57204D4F, ++0x65746972, 0x6461202C, 0x003D7264, 0x6C617620, ++0x0000003D, 0x00000A0D, 0x435F4D5A, 0x465F444D, ++0x4C445F57, 0x494E495F, 0x00000054, 0x6E6B6E55, ++0x206E776F, 0x6D6D6F63, 0x3D646E61, 0x00000000, ++0x203A3051, 0x00000020, 0x203A3151, 0x00000020, ++0x203A3251, 0x00000020, 0x203A3351, 0x00000020, ++0x203A3451, 0x00000020, 0x2B434741, 0x73696F4E, ++0x61432065, 0x7262696C, 0x6F697461, 0x6166206E, ++0x6F206C69, 0x6974206E, 0x0D0A656D, 0x00000000, ++0x00000072, 0x00205220, 0x00000D0A, 0x62735576, ++0x7473725F, 0x00000A0D, 0x62735576, 0x7375735F, ++0x646E6570, 0x00000A0D, 0x62735576, 0x7365725F, ++0x000A0D6D, 0x00000044, 0x44387570, 0x72637365, ++0x6F747069, 0x3D584572, 0x00000000, 0x00000047, ++0x00000042, 0x72746E49, 0x6D652051, 0x2C797470, ++0x49677A20, 0x4972746E, 0x754E514E, 0x00003D6D, ++0x654C7245, 0x0000006E, 0x00000049, 0x20746F4E, ++0x756F6E65, 0x49206867, 0x4220514E, 0x0A0D6675, ++0x00000000, 0x000000FF, 0x00020001, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00020003, 0x01090108, ++0x0002010A, 0x02000003, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x000000FF, 0x00020001, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00020003, 0x01090108, ++0x0002010A, 0x00030003, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00FF010F, 0x01090108, ++0x010B010A, 0x0200010F, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x010E010D, 0x00FF010F, 0x01090108, ++0x010B010A, 0x010F010F, 0x02020201, 0x02040203, ++0x02060205, 0x02020200, 0x02040203, 0x020C020B, ++0x020E020D, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, ++0x00FF00FF, 0x00205220, 0x00000046, 0x00000059, ++0x73204142, 0x003D7165, 0x49544120, 0x0000204D, ++0x00000000, 0x00000000, 0x002E0209, 0x80000101, ++0x000409FA, 0x00FF0400, 0x05070000, 0x02000201, ++0x82050700, 0x00020002, 0x03830507, 0x07010040, ++0x40030405, 0x02090100, 0x0101002E, 0x09FA8000, ++0x04000004, 0x000000FF, 0x02010507, 0x07000040, ++0x40028205, 0x05070000, 0x00400383, 0x04050701, ++0x00004002, 0x00000000, 0x00000000, 0x07090000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++0x00000000, 0x00000000, 0x00000000, 0x00000000, ++}; ++ ++const u32_t zcFwImageSize=15936; +--- /dev/null ++++ b/drivers/staging/otus/hal/hpmain.c +@@ -0,0 +1,4643 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++#include "hpani.h" ++#include "hpusb.h" ++#include "otus.ini" ++ ++extern const u32_t zcFwImage[]; ++extern const u32_t zcFwImageSize; ++extern const u32_t zcDKFwImage[]; ++extern const u32_t zcDKFwImageSize; ++extern const u32_t zcFwImageSPI[]; ++extern const u32_t zcFwImageSPISize; ++ ++#ifdef ZM_OTUS_LINUX_PHASE_2 ++extern const u32_t zcFwBufImage[]; ++extern const u32_t zcFwBufImageSize; ++extern const u32_t zcP2FwImage[]; ++extern const u32_t zcP2FwImageSize; ++#endif ++extern void zfInitCmdQueue(zdev_t* dev); ++extern u16_t zfIssueCmd(zdev_t* dev, u32_t* cmd, u16_t cmdLen, ++ u16_t src, u8_t* buf); ++extern void zfIdlRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen); ++extern u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val); ++extern u16_t zfFlushDelayWrite(zdev_t* dev); ++extern void zfUsbInit(zdev_t* dev); ++extern u16_t zfFirmwareDownload(zdev_t* dev, u32_t* fw, u32_t len, u32_t offset); ++extern u16_t zfFirmwareDownloadNotJump(zdev_t* dev, u32_t* fw, u32_t len, u32_t offset); ++extern void zfUsbFree(zdev_t* dev); ++extern u16_t zfCwmIsExtChanBusy(u32_t ctlBusy, u32_t extBusy); ++extern void zfCoreCwmBusy(zdev_t* dev, u16_t busy); ++ ++/* Prototypes */ ++void zfInitRf(zdev_t* dev, u32_t frequency); ++void zfInitPhy(zdev_t* dev, u32_t frequency, u8_t bw40); ++void zfInitMac(zdev_t* dev); ++ ++void zfSetPowerCalTable(zdev_t* dev, u32_t frequency, u8_t bw40, u8_t extOffset); ++void zfInitPowerCal(zdev_t* dev); ++ ++#ifdef ZM_DRV_INIT_USB_MODE ++void zfInitUsbMode(zdev_t* dev); ++u16_t zfHpUsbReset(zdev_t* dev); ++#endif ++ ++/* Bank 0 1 2 3 5 6 7 */ ++void zfSetRfRegs(zdev_t* dev, u32_t frequency); ++/* Bank 4 */ ++void zfSetBank4AndPowerTable(zdev_t* dev, u32_t frequency, u8_t bw40, ++ u8_t extOffset); ++/* Get param for turnoffdyn */ ++void zfGetHwTurnOffdynParam(zdev_t* dev, ++ u32_t frequency, u8_t bw40, u8_t extOffset, ++ int* delta_slope_coeff_exp, ++ int* delta_slope_coeff_man, ++ int* delta_slope_coeff_exp_shgi, ++ int* delta_slope_coeff_man_shgi); ++ ++void zfSelAdcClk(zdev_t* dev, u8_t bw40, u32_t frequency); ++u32_t zfHpEchoCommand(zdev_t* dev, u32_t value); ++ ++ ++ ++#define zm_hp_priv(x) (((struct zsHpPriv*)wd->hpPrivate)->x) ++struct zsHpPriv zgHpPriv; ++ ++#define ZM_FIRMWARE_WLAN_ADDR 0x200000 ++#define ZM_FIRMWARE_SPI_ADDR 0x114000 ++/* 0: real chip 1: FPGA test */ ++#define ZM_FPGA_PHY 0 ++ ++#define reg_write(addr, val) zfDelayWriteInternalReg(dev, addr+0x1bc000, val) ++#define zm_min(A, B) ((A>B)? B:A) ++ ++ ++/******************** Intialization ********************/ ++u16_t zfHpInit(zdev_t* dev, u32_t frequency) ++{ ++ u16_t ret; ++ zmw_get_wlan_dev(dev); ++ ++ /* Initializa HAL Plus private variables */ ++ wd->hpPrivate = &zgHpPriv; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->halCapability = ZM_HP_CAP_11N; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->hwFrequency = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->hwBw40 = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->hwExtOffset = 0; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->disableDfsCh = 0; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->ledMode[0] = 1; ++ ((struct zsHpPriv*)wd->hpPrivate)->ledMode[1] = 1; ++ ((struct zsHpPriv*)wd->hpPrivate)->strongRSSI = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->rxStrongRSSI = 0; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->slotType = 1; ++ ((struct zsHpPriv*)wd->hpPrivate)->aggPktNum = 0x10000a; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->eepromImageIndex = 0; ++ ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->eepromImageRdReq = 0; ++#ifdef ZM_OTUS_RX_STREAM_MODE ++ ((struct zsHpPriv*)wd->hpPrivate)->remainBuf = NULL; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxRemainLen = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxPktLen = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxPadLen = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxTransferLen = 0; ++#endif ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->enableBBHeavyClip = 1; ++ ((struct zsHpPriv*)wd->hpPrivate)->hwBBHeavyClip = 1; // force enable 8107 ++ ((struct zsHpPriv*)wd->hpPrivate)->doBBHeavyClip = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->setValueHeavyClip = 0; ++ ++ ++ /* Initialize driver core */ ++ zfInitCmdQueue(dev); ++ ++ /* Initialize USB */ ++ zfUsbInit(dev); ++ ++#if ZM_SW_LOOP_BACK != 1 ++ ++ /* TODO : [Download FW] */ ++ if (wd->modeMDKEnable) ++ { ++ /* download the MDK firmware */ ++ if ((ret = zfFirmwareDownload(dev, (u32_t*)zcDKFwImage, ++ (u32_t)zcDKFwImageSize, ZM_FIRMWARE_WLAN_ADDR)) != ZM_SUCCESS) ++ { ++ /* TODO : exception handling */ ++ //return 1; ++ } ++ } ++ else ++ { ++ #ifndef ZM_OTUS_LINUX_PHASE_2 ++ /* donwload the normal frimware */ ++ if ((ret = zfFirmwareDownload(dev, (u32_t*)zcFwImage, ++ (u32_t)zcFwImageSize, ZM_FIRMWARE_WLAN_ADDR)) != ZM_SUCCESS) ++ { ++ /* TODO : exception handling */ ++ //return 1; ++ } ++ #else ++ ++ // 1-PH fw: ReadMac() store some global variable ++ if ((ret = zfFirmwareDownloadNotJump(dev, (u32_t*)zcFwBufImage, ++ (u32_t)zcFwBufImageSize, 0x102800)) != ZM_SUCCESS) ++ { ++ DbgPrint("Dl zcFwBufImage failed!"); ++ } ++ ++ zfwSleep(dev, 1000); ++ ++ if ((ret = zfFirmwareDownload(dev, (u32_t*)zcFwImage, ++ (u32_t)zcFwImageSize, ZM_FIRMWARE_WLAN_ADDR)) != ZM_SUCCESS) ++ { ++ DbgPrint("Dl zcFwBufImage failed!"); ++ } ++ #endif ++ } ++#endif ++ ++#ifdef ZM_DRV_INIT_USB_MODE ++ /* Init USB Mode */ ++ zfInitUsbMode(dev); ++ ++ /* Do the USB Reset */ ++ zfHpUsbReset(dev); ++#endif ++ ++/* Register setting */ ++/* ZM_DRIVER_MODEL_TYPE_MDK ++ * 1=>for MDK, disable init RF, PHY, and MAC, ++ * 0=>normal init ++ */ ++//#if ((ZM_SW_LOOP_BACK != 1) && (ZM_DRIVER_MODEL_TYPE_MDK !=1)) ++#if ZM_SW_LOOP_BACK != 1 ++ if(!wd->modeMDKEnable) ++ { ++ /* Init MAC */ ++ zfInitMac(dev); ++ ++ #if ZM_FW_LOOP_BACK != 1 ++ /* Init PHY */ ++ zfInitPhy(dev, frequency, 0); ++ ++ /* Init RF */ ++ zfInitRf(dev, frequency); ++ ++ #if ZM_FPGA_PHY == 0 ++ /* BringUp issue */ ++ //zfDelayWriteInternalReg(dev, 0x9800+0x1bc000, 0x10000007); ++ //zfFlushDelayWrite(dev); ++ #endif ++ ++ #endif /* end of ZM_FW_LOOP_BACK != 1 */ ++ } ++#endif /* end of ((ZM_SW_LOOP_BACK != 1) && (ZM_DRIVER_MODEL_TYPE_MDK !=1)) */ ++ ++ zfHpEchoCommand(dev, 0xAABBCCDD); ++ ++ return 0; ++} ++ ++ ++u16_t zfHpReinit(zdev_t* dev, u32_t frequency) ++{ ++ u16_t ret; ++ zmw_get_wlan_dev(dev); ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->halReInit = 1; ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->strongRSSI = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->rxStrongRSSI = 0; ++ ++#ifdef ZM_OTUS_RX_STREAM_MODE ++ if (((struct zsHpPriv*)wd->hpPrivate)->remainBuf != NULL) ++ { ++ zfwBufFree(dev, ((struct zsHpPriv*)wd->hpPrivate)->remainBuf, 0); ++ } ++ ((struct zsHpPriv*)wd->hpPrivate)->remainBuf = NULL; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxRemainLen = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxPktLen = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxPadLen = 0; ++ ((struct zsHpPriv*)wd->hpPrivate)->usbRxTransferLen = 0; ++#endif ++ ++ zfInitCmdQueue(dev); ++ zfCoreReinit(dev); ++ ++ #ifndef ZM_OTUS_LINUX_PHASE_2 ++ /* Download firmware */ ++ if ((ret = zfFirmwareDownload(dev, (u32_t*)zcFwImage, ++ (u32_t)zcFwImageSize, ZM_FIRMWARE_WLAN_ADDR)) != ZM_SUCCESS) ++ { ++ /* TODO : exception handling */ ++ //return 1; ++ } ++ #else ++ if ((ret = zfFirmwareDownload(dev, (u32_t*)zcP2FwImage, ++ (u32_t)zcP2FwImageSize, ZM_FIRMWARE_WLAN_ADDR)) != ZM_SUCCESS) ++ { ++ /* TODO : exception handling */ ++ //return 1; ++ } ++ #endif ++ ++#ifdef ZM_DRV_INIT_USB_MODE ++ /* Init USB Mode */ ++ zfInitUsbMode(dev); ++ ++ /* Do the USB Reset */ ++ zfHpUsbReset(dev); ++#endif ++ ++ /* Init MAC */ ++ zfInitMac(dev); ++ ++ /* Init PHY */ ++ zfInitPhy(dev, frequency, 0); ++ /* Init RF */ ++ zfInitRf(dev, frequency); ++ ++ #if ZM_FPGA_PHY == 0 ++ /* BringUp issue */ ++ //zfDelayWriteInternalReg(dev, 0x9800+0x1bc000, 0x10000007); ++ //zfFlushDelayWrite(dev); ++ #endif ++ ++ zfHpEchoCommand(dev, 0xAABBCCDD); ++ ++ return 0; ++} ++ ++ ++u16_t zfHpRelease(zdev_t* dev) ++{ ++ /* Free USB resource */ ++ zfUsbFree(dev); ++ ++ return 0; ++} ++ ++/* MDK mode setting for dontRetransmit */ ++void zfHpConfigFM(zdev_t* dev, u32_t RxMaxSize, u32_t DontRetransmit) ++{ ++ u32_t cmd[3]; ++ u16_t ret; ++ ++ cmd[0] = 8 | (ZM_CMD_CONFIG << 8); ++ cmd[1] = RxMaxSize; /* zgRxMaxSize */ ++ cmd[2] = DontRetransmit; /* zgDontRetransmit */ ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_INTERNAL_WRITE, 0); ++} ++ ++const u8_t zcXpdToPd[16] = ++{ ++ /* 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF */ ++ 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2, 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2 ++}; ++ ++/******************** RF and PHY ********************/ ++ ++void zfInitPhy(zdev_t* dev, u32_t frequency, u8_t bw40) ++{ ++ u16_t i, j, k; ++ u16_t entries; ++ u16_t modesIndex = 0; ++ u16_t freqIndex = 0; ++ u32_t tmp, tmp1; ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ u32_t eepromBoardData[15][6] = { ++ /* Register A-20 A-20/40 G-20/40 G-20 G-Turbo */ ++ {0x9964, 0, 0, 0, 0, 0}, ++ {0x9960, 0, 0, 0, 0, 0}, ++ {0xb960, 0, 0, 0, 0, 0}, ++ {0x9844, 0, 0, 0, 0, 0}, ++ {0x9850, 0, 0, 0, 0, 0}, ++ {0x9834, 0, 0, 0, 0, 0}, ++ {0x9828, 0, 0, 0, 0, 0}, ++ {0xc864, 0, 0, 0, 0, 0}, ++ {0x9848, 0, 0, 0, 0, 0}, ++ {0xb848, 0, 0, 0, 0, 0}, ++ {0xa20c, 0, 0, 0, 0, 0}, ++ {0xc20c, 0, 0, 0, 0, 0}, ++ {0x9920, 0, 0, 0, 0, 0}, ++ {0xb920, 0, 0, 0, 0, 0}, ++ {0xa258, 0, 0, 0, 0, 0}, ++ }; ++ ++ /* #1 Save the initial value of the related RIFS register settings */ ++ //((struct zsHpPriv*)wd->hpPrivate)->isInitialPhy++; ++ ++ /* ++ * Setup the indices for the next set of register array writes ++ * PHY mode is static20 / 2040 ++ * Frequency is 2.4GHz (B) / 5GHz (A) ++ */ ++ if ( frequency > ZM_CH_G_14 ) ++ { ++ /* 5GHz */ ++ freqIndex = 1; ++ if (bw40) ++ { ++ modesIndex = 2; ++ zm_debug_msg0("init ar5416Modes in 2: A-20/40"); ++ } ++ else ++ { ++ modesIndex = 1; ++ zm_debug_msg0("init ar5416Modes in 1: A-20"); ++ } ++ } ++ else ++ { ++ /* 2.4GHz */ ++ freqIndex = 2; ++ if (bw40) ++ { ++ modesIndex = 3; ++ zm_debug_msg0("init ar5416Modes in 3: G-20/40"); ++ } ++ else ++ { ++ modesIndex = 4; ++ zm_debug_msg0("init ar5416Modes in 4: G-20"); ++ } ++ } ++ ++ ++#if ZM_FPGA_PHY == 1 ++ /* Starting External Hainan Register Initialization */ ++ /* TODO: */ ++ ++ zfwSleep(dev, 10); ++#endif ++ ++ /* ++ *Set correct Baseband to analog shift setting to access analog chips. ++ */ ++ //reg_write(PHY_BASE, 0x00000007); ++// reg_write(0x9800, 0x00000007); ++ ++ /* ++ * Write addac shifts ++ */ ++ // do this in firmware ++ ++ ++ ++ /* Zeroize board data */ ++ for (j=0; j<15; j++) ++ { ++ for (k=1; k<=4; k++) ++ { ++ eepromBoardData[j][k] = 0; ++ } ++ } ++ /* ++ * Register setting by mode ++ */ ++ ++ entries = sizeof(ar5416Modes) / sizeof(*ar5416Modes); ++ zm_msg1_scan(ZM_LV_2, "Modes register setting entries=", entries); ++ for (i=0; ihpPrivate)->hwNotFirstInit && (ar5416Modes[i][0] == 0xa27c) ) ++ { ++ /* Force disable CR671 bit20 / 7823 */ ++ /* The bug has to do with the polarity of the pdadc offset calibration. There */ ++ /* is an initial calibration that is OK, and there is a continuous */ ++ /* calibration that updates the pddac with the wrong polarity. Fortunately */ ++ /* the second loop can be disabled with a bit called en_pd_dc_offset_thr. */ ++ ++ reg_write(ar5416Modes[i][0], (ar5416Modes[i][modesIndex]& 0xffefffff) ); ++ ((struct zsHpPriv*)wd->hpPrivate)->hwNotFirstInit = 1; ++ } ++ else ++ { ++#endif ++ /* FirstTime Init or not 0xa27c(CR671) */ ++ reg_write(ar5416Modes[i][0], ar5416Modes[i][modesIndex]); ++// } ++ /* Initialize board data */ ++ for (j=0; j<15; j++) ++ { ++ if (ar5416Modes[i][0] == eepromBoardData[j][0]) ++ { ++ for (k=1; k<=4; k++) ++ { ++ eepromBoardData[j][k] = ar5416Modes[i][k]; ++ } ++ } ++ } ++ /* #1 Save the initial value of the related RIFS register settings */ ++ //if( ((struct zsHpPriv*)wd->hpPrivate)->isInitialPhy == 1 ) ++ { ++ switch(ar5416Modes[i][0]) ++ { ++ case 0x9850 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initDesiredSigSize = ar5416Modes[i][modesIndex]; ++ break; ++ case 0x985c : ++ ((struct zsHpPriv*)wd->hpPrivate)->initAGC = ar5416Modes[i][modesIndex]; ++ break; ++ case 0x9860 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initAgcControl = ar5416Modes[i][modesIndex]; ++ break; ++ case 0x9918 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initSearchStartDelay = ar5416Modes[i][modesIndex]; ++ break; ++ case 0x99ec : ++ ((struct zsHpPriv*)wd->hpPrivate)->initRIFSSearchParams = ar5416Modes[i][modesIndex]; ++ break; ++ case 0xa388 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initFastChannelChangeControl = ar5416Modes[i][modesIndex]; ++ default : ++ break; ++ } ++ } ++ } ++#if 0 ++ zfFlushDelayWrite(dev); ++ ++ /* ++ * Common Register setting ++ */ ++ entries = sizeof(ar5416Common) / sizeof(*ar5416Common); ++ for (i=0; ieepromImage[0x100+0x144*2/4]; ++ eepromBoardData[0][1] = tmp; ++ eepromBoardData[0][2] = tmp; ++ //Ant control chain 0 ++ tmp = hpPriv->eepromImage[0x100+0x140*2/4]; ++ eepromBoardData[1][1] = tmp; ++ eepromBoardData[1][2] = tmp; ++ //Ant control chain 2 ++ tmp = hpPriv->eepromImage[0x100+0x142*2/4]; ++ eepromBoardData[2][1] = tmp; ++ eepromBoardData[2][2] = tmp; ++ //SwSettle ++ tmp = hpPriv->eepromImage[0x100+0x146*2/4]; ++ tmp = (tmp >> 16) & 0x7f; ++ eepromBoardData[3][1] &= (~((u32_t)0x3f80)); ++ eepromBoardData[3][1] |= (tmp << 7); ++#if 0 ++ //swSettleHt40 ++ tmp = hpPriv->eepromImage[0x100+0x158*2/4]; ++ tmp = (tmp) & 0x7f; ++ eepromBoardData[3][2] &= (~((u32_t)0x3f80)); ++ eepromBoardData[3][2] |= (tmp << 7); ++#endif ++ //adcDesired, pdaDesired ++ tmp = hpPriv->eepromImage[0x100+0x148*2/4]; ++ tmp = (tmp >> 24); ++ tmp1 = hpPriv->eepromImage[0x100+0x14a*2/4]; ++ tmp1 = tmp1 & 0xff; ++ tmp = tmp + (tmp1<<8); ++ eepromBoardData[4][1] &= (~((u32_t)0xffff)); ++ eepromBoardData[4][1] |= tmp; ++ eepromBoardData[4][2] &= (~((u32_t)0xffff)); ++ eepromBoardData[4][2] |= tmp; ++ //TxEndToXpaOff, TxFrameToXpaOn ++ tmp = hpPriv->eepromImage[0x100+0x14a*2/4]; ++ tmp = (tmp >> 24) & 0xff; ++ tmp1 = hpPriv->eepromImage[0x100+0x14c*2/4]; ++ tmp1 = (tmp1 >> 8) & 0xff; ++ tmp = (tmp<<24) + (tmp<<16) + (tmp1<<8) + tmp1; ++ eepromBoardData[5][1] = tmp; ++ eepromBoardData[5][2] = tmp; ++ //TxEnaToRxOm ++ tmp = hpPriv->eepromImage[0x100+0x14c*2/4] & 0xff; ++ eepromBoardData[6][1] &= (~((u32_t)0xff0000)); ++ eepromBoardData[6][1] |= (tmp<<16); ++ eepromBoardData[6][2] &= (~((u32_t)0xff0000)); ++ eepromBoardData[6][2] |= (tmp<<16); ++ //Thresh62 ++ tmp = hpPriv->eepromImage[0x100+0x14c*2/4]; ++ tmp = (tmp >> 16) & 0x7f; ++ eepromBoardData[7][1] &= (~((u32_t)0x7f000)); ++ eepromBoardData[7][1] |= (tmp<<12); ++ eepromBoardData[7][2] &= (~((u32_t)0x7f000)); ++ eepromBoardData[7][2] |= (tmp<<12); ++ //TxRxAtten chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x146*2/4]; ++ tmp = (tmp >> 24) & 0x3f; ++ eepromBoardData[8][1] &= (~((u32_t)0x3f000)); ++ eepromBoardData[8][1] |= (tmp<<12); ++ eepromBoardData[8][2] &= (~((u32_t)0x3f000)); ++ eepromBoardData[8][2] |= (tmp<<12); ++ //TxRxAtten chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x148*2/4] & 0x3f; ++ eepromBoardData[9][1] &= (~((u32_t)0x3f000)); ++ eepromBoardData[9][1] |= (tmp<<12); ++ eepromBoardData[9][2] &= (~((u32_t)0x3f000)); ++ eepromBoardData[9][2] |= (tmp<<12); ++ //TxRxMargin chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x148*2/4]; ++ tmp = (tmp >> 8) & 0x3f; ++ eepromBoardData[10][1] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[10][1] |= (tmp<<18); ++ eepromBoardData[10][2] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[10][2] |= (tmp<<18); ++ //TxRxMargin chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x148*2/4]; ++ tmp = (tmp >> 16) & 0x3f; ++ eepromBoardData[11][1] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[11][1] |= (tmp<<18); ++ eepromBoardData[11][2] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[11][2] |= (tmp<<18); ++ //iqCall chain_0, iqCallQ chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x14e*2/4]; ++ tmp = (tmp >> 24) & 0x3f; ++ tmp1 = hpPriv->eepromImage[0x100+0x150*2/4]; ++ tmp1 = (tmp1 >> 8) & 0x1f; ++ tmp = (tmp<<5) + tmp1; ++ eepromBoardData[12][1] &= (~((u32_t)0x7ff)); ++ eepromBoardData[12][1] |= (tmp); ++ eepromBoardData[12][2] &= (~((u32_t)0x7ff)); ++ eepromBoardData[12][2] |= (tmp); ++ //iqCall chain_2, iqCallQ chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x150*2/4]; ++ tmp = tmp & 0x3f; ++ tmp1 = hpPriv->eepromImage[0x100+0x150*2/4]; ++ tmp1 = (tmp1 >> 16) & 0x1f; ++ tmp = (tmp<<5) + tmp1; ++ eepromBoardData[13][1] &= (~((u32_t)0x7ff)); ++ eepromBoardData[13][1] |= (tmp); ++ eepromBoardData[13][2] &= (~((u32_t)0x7ff)); ++ eepromBoardData[13][2] |= (tmp); ++ //bsw_Margin chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x156*2/4]; ++ tmp = (tmp >> 16) & 0xf; ++ eepromBoardData[10][1] &= (~((u32_t)0x3c00)); ++ eepromBoardData[10][1] |= (tmp << 10); ++ eepromBoardData[10][2] &= (~((u32_t)0x3c00)); ++ eepromBoardData[10][2] |= (tmp << 10); ++ //xpd gain mask ++ tmp = hpPriv->eepromImage[0x100+0x14e*2/4]; ++ tmp = (tmp >> 8) & 0xf; ++ eepromBoardData[14][1] &= (~((u32_t)0xf0000)); ++ eepromBoardData[14][1] |= (zcXpdToPd[tmp] << 16); ++ eepromBoardData[14][2] &= (~((u32_t)0xf0000)); ++ eepromBoardData[14][2] |= (zcXpdToPd[tmp] << 16); ++#if 0 ++ //bsw_Atten chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x156*2/4]; ++ tmp = (tmp) & 0x1f; ++ eepromBoardData[10][1] &= (~((u32_t)0x1f)); ++ eepromBoardData[10][1] |= (tmp); ++ eepromBoardData[10][2] &= (~((u32_t)0x1f)); ++ eepromBoardData[10][2] |= (tmp); ++ //bsw_Margin chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x156*2/4]; ++ tmp = (tmp >> 24) & 0xf; ++ eepromBoardData[11][1] &= (~((u32_t)0x3c00)); ++ eepromBoardData[11][1] |= (tmp << 10); ++ eepromBoardData[11][2] &= (~((u32_t)0x3c00)); ++ eepromBoardData[11][2] |= (tmp << 10); ++ //bsw_Atten chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x156*2/4]; ++ tmp = (tmp >> 8) & 0x1f; ++ eepromBoardData[11][1] &= (~((u32_t)0x1f)); ++ eepromBoardData[11][1] |= (tmp); ++ eepromBoardData[11][2] &= (~((u32_t)0x1f)); ++ eepromBoardData[11][2] |= (tmp); ++#endif ++ ++ /* Update 2.4G board data */ ++ //Ant control common ++ tmp = hpPriv->eepromImage[0x100+0x170*2/4]; ++ tmp = tmp >> 24; ++ tmp1 = hpPriv->eepromImage[0x100+0x172*2/4]; ++ tmp = tmp + (tmp1 << 8); ++ eepromBoardData[0][3] = tmp; ++ eepromBoardData[0][4] = tmp; ++ //Ant control chain 0 ++ tmp = hpPriv->eepromImage[0x100+0x16c*2/4]; ++ tmp = tmp >> 24; ++ tmp1 = hpPriv->eepromImage[0x100+0x16e*2/4]; ++ tmp = tmp + (tmp1 << 8); ++ eepromBoardData[1][3] = tmp; ++ eepromBoardData[1][4] = tmp; ++ //Ant control chain 2 ++ tmp = hpPriv->eepromImage[0x100+0x16e*2/4]; ++ tmp = tmp >> 24; ++ tmp1 = hpPriv->eepromImage[0x100+0x170*2/4]; ++ tmp = tmp + (tmp1 << 8); ++ eepromBoardData[2][3] = tmp; ++ eepromBoardData[2][4] = tmp; ++ //SwSettle ++ tmp = hpPriv->eepromImage[0x100+0x174*2/4]; ++ tmp = (tmp >> 8) & 0x7f; ++ eepromBoardData[3][4] &= (~((u32_t)0x3f80)); ++ eepromBoardData[3][4] |= (tmp << 7); ++#if 0 ++ //swSettleHt40 ++ tmp = hpPriv->eepromImage[0x100+0x184*2/4]; ++ tmp = (tmp >> 24) & 0x7f; ++ eepromBoardData[3][3] &= (~((u32_t)0x3f80)); ++ eepromBoardData[3][3] |= (tmp << 7); ++#endif ++ //adcDesired, pdaDesired ++ tmp = hpPriv->eepromImage[0x100+0x176*2/4]; ++ tmp = (tmp >> 16) & 0xff; ++ tmp1 = hpPriv->eepromImage[0x100+0x176*2/4]; ++ tmp1 = tmp1 >> 24; ++ tmp = tmp + (tmp1<<8); ++ eepromBoardData[4][3] &= (~((u32_t)0xffff)); ++ eepromBoardData[4][3] |= tmp; ++ eepromBoardData[4][4] &= (~((u32_t)0xffff)); ++ eepromBoardData[4][4] |= tmp; ++ //TxEndToXpaOff, TxFrameToXpaOn ++ tmp = hpPriv->eepromImage[0x100+0x178*2/4]; ++ tmp = (tmp >> 16) & 0xff; ++ tmp1 = hpPriv->eepromImage[0x100+0x17a*2/4]; ++ tmp1 = tmp1 & 0xff; ++ tmp = (tmp << 24) + (tmp << 16) + (tmp1 << 8) + tmp1; ++ eepromBoardData[5][3] = tmp; ++ eepromBoardData[5][4] = tmp; ++ //TxEnaToRxOm ++ tmp = hpPriv->eepromImage[0x100+0x178*2/4]; ++ tmp = (tmp >> 24); ++ eepromBoardData[6][3] &= (~((u32_t)0xff0000)); ++ eepromBoardData[6][3] |= (tmp<<16); ++ eepromBoardData[6][4] &= (~((u32_t)0xff0000)); ++ eepromBoardData[6][4] |= (tmp<<16); ++ //Thresh62 ++ tmp = hpPriv->eepromImage[0x100+0x17a*2/4]; ++ tmp = (tmp >> 8) & 0x7f; ++ eepromBoardData[7][3] &= (~((u32_t)0x7f000)); ++ eepromBoardData[7][3] |= (tmp<<12); ++ eepromBoardData[7][4] &= (~((u32_t)0x7f000)); ++ eepromBoardData[7][4] |= (tmp<<12); ++ //TxRxAtten chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x174*2/4]; ++ tmp = (tmp >> 16) & 0x3f; ++ eepromBoardData[8][3] &= (~((u32_t)0x3f000)); ++ eepromBoardData[8][3] |= (tmp<<12); ++ eepromBoardData[8][4] &= (~((u32_t)0x3f000)); ++ eepromBoardData[8][4] |= (tmp<<12); ++ //TxRxAtten chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x174*2/4]; ++ tmp = (tmp >> 24) & 0x3f; ++ eepromBoardData[9][3] &= (~((u32_t)0x3f000)); ++ eepromBoardData[9][3] |= (tmp<<12); ++ eepromBoardData[9][4] &= (~((u32_t)0x3f000)); ++ eepromBoardData[9][4] |= (tmp<<12); ++ //TxRxMargin chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x176*2/4]; ++ tmp = (tmp) & 0x3f; ++ eepromBoardData[10][3] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[10][3] |= (tmp<<18); ++ eepromBoardData[10][4] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[10][4] |= (tmp<<18); ++ //TxRxMargin chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x176*2/4]; ++ tmp = (tmp >> 8) & 0x3f; ++ eepromBoardData[11][3] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[11][3] |= (tmp<<18); ++ eepromBoardData[11][4] &= (~((u32_t)0xfc0000)); ++ eepromBoardData[11][4] |= (tmp<<18); ++ //iqCall chain_0, iqCallQ chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x17c*2/4]; ++ tmp = (tmp >> 16) & 0x3f; ++ tmp1 = hpPriv->eepromImage[0x100+0x17e*2/4]; ++ tmp1 = (tmp1) & 0x1f; ++ tmp = (tmp<<5) + tmp1; ++ eepromBoardData[12][3] &= (~((u32_t)0x7ff)); ++ eepromBoardData[12][3] |= (tmp); ++ eepromBoardData[12][4] &= (~((u32_t)0x7ff)); ++ eepromBoardData[12][4] |= (tmp); ++ //iqCall chain_2, iqCallQ chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x17c*2/4]; ++ tmp = (tmp>>24) & 0x3f; ++ tmp1 = hpPriv->eepromImage[0x100+0x17e*2/4]; ++ tmp1 = (tmp1 >> 8) & 0x1f; ++ tmp = (tmp<<5) + tmp1; ++ eepromBoardData[13][3] &= (~((u32_t)0x7ff)); ++ eepromBoardData[13][3] |= (tmp); ++ eepromBoardData[13][4] &= (~((u32_t)0x7ff)); ++ eepromBoardData[13][4] |= (tmp); ++ //xpd gain mask ++ tmp = hpPriv->eepromImage[0x100+0x17c*2/4]; ++ tmp = tmp & 0xf; ++ DbgPrint("xpd=0x%x, pd=0x%x\n", tmp, zcXpdToPd[tmp]); ++ eepromBoardData[14][3] &= (~((u32_t)0xf0000)); ++ eepromBoardData[14][3] |= (zcXpdToPd[tmp] << 16); ++ eepromBoardData[14][4] &= (~((u32_t)0xf0000)); ++ eepromBoardData[14][4] |= (zcXpdToPd[tmp] << 16); ++#if 0 ++ //bsw_Margin chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x184*2/4]; ++ tmp = (tmp >> 8) & 0xf; ++ eepromBoardData[10][3] &= (~((u32_t)0x3c00)); ++ eepromBoardData[10][3] |= (tmp << 10); ++ eepromBoardData[10][4] &= (~((u32_t)0x3c00)); ++ eepromBoardData[10][4] |= (tmp << 10); ++ //bsw_Atten chain_0 ++ tmp = hpPriv->eepromImage[0x100+0x182*2/4]; ++ tmp = (tmp>>24) & 0x1f; ++ eepromBoardData[10][3] &= (~((u32_t)0x1f)); ++ eepromBoardData[10][3] |= (tmp); ++ eepromBoardData[10][4] &= (~((u32_t)0x1f)); ++ eepromBoardData[10][4] |= (tmp); ++ //bsw_Margin chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x184*2/4]; ++ tmp = (tmp >> 16) & 0xf; ++ eepromBoardData[11][3] &= (~((u32_t)0x3c00)); ++ eepromBoardData[11][3] |= (tmp << 10); ++ eepromBoardData[11][4] &= (~((u32_t)0x3c00)); ++ eepromBoardData[11][4] |= (tmp << 10); ++ //bsw_Atten chain_2 ++ tmp = hpPriv->eepromImage[0x100+0x184*2/4]; ++ tmp = (tmp) & 0x1f; ++ eepromBoardData[11][3] &= (~((u32_t)0x1f)); ++ eepromBoardData[11][3] |= (tmp); ++ eepromBoardData[11][4] &= (~((u32_t)0x1f)); ++ eepromBoardData[11][4] |= (tmp); ++#endif ++ ++#if 0 ++ for (j=0; j<14; j++) ++ { ++ DbgPrint("%04x, %08x, %08x, %08x, %08x\n", eepromBoardData[j][0], eepromBoardData[j][1], eepromBoardData[j][2], eepromBoardData[j][3], eepromBoardData[j][4]); ++ } ++#endif ++ ++ if ((hpPriv->eepromImage[0x100+0x110*2/4]&0xff) == 0x80) //FEM TYPE ++ { ++ /* Update board data to registers */ ++ for (j=0; j<15; j++) ++ { ++ reg_write(eepromBoardData[j][0], eepromBoardData[j][modesIndex]); ++ ++ /* #1 Save the initial value of the related RIFS register settings */ ++ //if( ((struct zsHpPriv*)wd->hpPrivate)->isInitialPhy == 1 ) ++ { ++ switch(eepromBoardData[j][0]) ++ { ++ case 0x9850 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initDesiredSigSize = eepromBoardData[j][modesIndex]; ++ break; ++ case 0x985c : ++ ((struct zsHpPriv*)wd->hpPrivate)->initAGC = eepromBoardData[j][modesIndex]; ++ break; ++ case 0x9860 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initAgcControl = eepromBoardData[j][modesIndex]; ++ break; ++ case 0x9918 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initSearchStartDelay = eepromBoardData[j][modesIndex]; ++ break; ++ case 0x99ec : ++ ((struct zsHpPriv*)wd->hpPrivate)->initRIFSSearchParams = eepromBoardData[j][modesIndex]; ++ break; ++ case 0xa388 : ++ ((struct zsHpPriv*)wd->hpPrivate)->initFastChannelChangeControl = eepromBoardData[j][modesIndex]; ++ default : ++ break; ++ } ++ } ++ } ++ } /* if ((hpPriv->eepromImage[0x100+0x110*2/4]&0xff) == 0x80) //FEM TYPE */ ++ ++ ++ /* Bringup issue : force tx gain */ ++ //reg_write(0xa258, 0x0cc65381); ++ //reg_write(0xa274, 0x0a1a7c15); ++ zfInitPowerCal(dev); ++ ++ if(frequency > ZM_CH_G_14) ++ { ++ zfDelayWriteInternalReg(dev, 0x1d4014, 0x5143); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1d4014, 0x5163); ++ } ++ ++ zfFlushDelayWrite(dev); ++} ++ ++ ++void zfInitRf(zdev_t* dev, u32_t frequency) ++{ ++ u32_t cmd[8]; ++ u16_t ret; ++ int delta_slope_coeff_exp; ++ int delta_slope_coeff_man; ++ int delta_slope_coeff_exp_shgi; ++ int delta_slope_coeff_man_shgi; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zm_debug_msg1(" initRf frequency = ", frequency); ++ ++ if (frequency == 0) ++ { ++ frequency = 2412; ++ } ++ ++ /* Bank 0 1 2 3 5 6 7 */ ++ zfSetRfRegs(dev, frequency); ++ /* Bank 4 */ ++ zfSetBank4AndPowerTable(dev, frequency, 0, 0); ++ ++ /* stroe frequency */ ++ ((struct zsHpPriv*)wd->hpPrivate)->hwFrequency = (u16_t)frequency; ++ ++ zfGetHwTurnOffdynParam(dev, ++ frequency, 0, 0, ++ &delta_slope_coeff_exp, ++ &delta_slope_coeff_man, ++ &delta_slope_coeff_exp_shgi, ++ &delta_slope_coeff_man_shgi); ++ ++ /* related functions */ ++ frequency = frequency*1000; ++ cmd[0] = 28 | (ZM_CMD_RF_INIT << 8); ++ cmd[1] = frequency; ++ cmd[2] = 0;//((struct zsHpPriv*)wd->hpPrivate)->hw_DYNAMIC_HT2040_EN; ++ cmd[3] = 1;//((wd->ExtOffset << 2) | ((struct zsHpPriv*)wd->hpPrivate)->hw_HT_ENABLE); ++ cmd[4] = delta_slope_coeff_exp; ++ cmd[5] = delta_slope_coeff_man; ++ cmd[6] = delta_slope_coeff_exp_shgi; ++ cmd[7] = delta_slope_coeff_man_shgi; ++ ++ ret = zfIssueCmd(dev, cmd, 32, ZM_OID_INTERNAL_WRITE, 0); ++ ++ // delay temporarily, wait for new PHY and RF ++ zfwSleep(dev, 1000); ++} ++ ++int tn(int exp) ++{ ++ int i; ++ int tmp = 1; ++ for(i=0; i>(7-i) & 0x1) << i); ++ return chansel; ++} ++ ++/* Bank 0 1 2 3 5 6 7 */ ++void zfSetRfRegs(zdev_t* dev, u32_t frequency) ++{ ++ u16_t entries; ++ u16_t freqIndex = 0; ++ u16_t i; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ if ( frequency > ZM_CH_G_14 ) ++ { ++ /* 5G */ ++ freqIndex = 1; ++ zm_msg0_scan(ZM_LV_2, "Set to 5GHz"); ++ ++ } ++ else ++ { ++ /* 2.4G */ ++ freqIndex = 2; ++ zm_msg0_scan(ZM_LV_2, "Set to 2.4GHz"); ++ } ++ ++#if 1 ++ entries = sizeof(otusBank) / sizeof(*otusBank); ++ for (i=0; ista.DFSEnable) ++ { ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel == frequency) ++ break; ++ } ++ wd->regulationTable.CurChIndex = i; ++ } ++ ++ if (bw40 == 1) ++ { ++ if (extOffset == 1) ++ { ++ frequency += 10; ++ } ++ else ++ { ++ frequency -= 10; ++ } ++ ++ } ++ ++ ++ if ( frequency > 3000 ) ++ { ++ if ( frequency % 10 ) ++ { ++ /* 5M */ ++ chan_sel = (u8_t)((frequency - 4800)/5); ++ chan_sel = (u8_t)(chan_sel & 0xff); ++ chansel = (u8_t)reverse_bits(chan_sel); ++ } ++ else ++ { ++ /* 10M : improve Tx EVM */ ++ chan_sel = (u8_t)((frequency - 4800)/10); ++ chan_sel = (u8_t)(chan_sel & 0xff)<<1; ++ chansel = (u8_t)reverse_bits(chan_sel); ++ ++ amode_refsel_1 = 1; ++ amode_refsel_0 = 0; ++ } ++ } ++ else ++ { ++ //temp_chan_sel = (((frequency - 672)*2) - 3040)/10; ++ if (frequency == 2484) ++ { ++ temp_chan_sel = 10 + (frequency - 2274)/5 ; ++ bmode_LF_synth_freq = 1; ++ } ++ else ++ { ++ temp_chan_sel = 16 + (frequency - 2272)/5 ; ++ bmode_LF_synth_freq = 0; ++ } ++ chan_sel = (u8_t)(temp_chan_sel << 2) & 0xff; ++ chansel = (u8_t)reverse_bits(chan_sel); ++ } ++ ++ d1 = chansel; //# 8 bits of chan ++ d0 = addr0<<7 | addr1<<6 | addr2<<5 ++ | amode_refsel_0<<3 | amode_refsel_1<<2 ++ | bmode_LF_synth_freq<<1 | chup; ++ ++ tmp_0 = d0 & 0x1f; //# 5-1 ++ tmp_1 = d1 & 0x1f; //# 5-1 ++ data0 = tmp_1<<5 | tmp_0; ++ ++ tmp_0 = d0>>5 & 0x7; //# 8-6 ++ tmp_1 = d1>>5 & 0x7; //# 8-6 ++ data1 = tmp_1<<5 | tmp_0; ++ ++ /* Bank4 */ ++ reg_write (0x9800+(0x2c<<2), data0); ++ reg_write (0x9800+(0x3a<<2), data1); ++ //zm_debug_msg1("0x9800+(0x2c<<2 = ", data0); ++ //zm_debug_msg1("0x9800+(0x3a<<2 = ", data1); ++ ++ ++ zfFlushDelayWrite(dev); ++ ++ zfwSleep(dev, 10); ++ ++ return; ++} ++ ++ ++struct zsPhyFreqPara ++{ ++ u32_t coeff_exp; ++ u32_t coeff_man; ++ u32_t coeff_exp_shgi; ++ u32_t coeff_man_shgi; ++}; ++ ++struct zsPhyFreqTable ++{ ++ u32_t frequency; ++ struct zsPhyFreqPara FpgaDynamicHT; ++ struct zsPhyFreqPara FpgaStaticHT; ++ struct zsPhyFreqPara ChipST20Mhz; ++ struct zsPhyFreqPara Chip2040Mhz; ++ struct zsPhyFreqPara Chip2040ExtAbove; ++}; ++ ++const struct zsPhyFreqTable zgPhyFreqCoeff[] = ++{ ++/*Index freq FPGA DYNAMIC_HT2040_EN FPGA STATIC_HT20 Real Chip static20MHz Real Chip 2040MHz Real Chip 2040Mhz */ ++ /* fclk = 10.8 21.6 40 ext below 40 ext above 40 */ ++/* 0 */ {2412, {5, 23476, 5, 21128}, {4, 23476, 4, 21128}, {3, 21737, 3, 19563}, {3, 21827, 3, 19644}, {3, 21647, 3, 19482}}, ++/* 1 */ {2417, {5, 23427, 5, 21084}, {4, 23427, 4, 21084}, {3, 21692, 3, 19523}, {3, 21782, 3, 19604}, {3, 21602, 3, 19442}}, ++/* 2 */ {2422, {5, 23379, 5, 21041}, {4, 23379, 4, 21041}, {3, 21647, 3, 19482}, {3, 21737, 3, 19563}, {3, 21558, 3, 19402}}, ++/* 3 */ {2427, {5, 23330, 5, 20997}, {4, 23330, 4, 20997}, {3, 21602, 3, 19442}, {3, 21692, 3, 19523}, {3, 21514, 3, 19362}}, ++/* 4 */ {2432, {5, 23283, 5, 20954}, {4, 23283, 4, 20954}, {3, 21558, 3, 19402}, {3, 21647, 3, 19482}, {3, 21470, 3, 19323}}, ++/* 5 */ {2437, {5, 23235, 5, 20911}, {4, 23235, 4, 20911}, {3, 21514, 3, 19362}, {3, 21602, 3, 19442}, {3, 21426, 3, 19283}}, ++/* 6 */ {2442, {5, 23187, 5, 20868}, {4, 23187, 4, 20868}, {3, 21470, 3, 19323}, {3, 21558, 3, 19402}, {3, 21382, 3, 19244}}, ++/* 7 */ {2447, {5, 23140, 5, 20826}, {4, 23140, 4, 20826}, {3, 21426, 3, 19283}, {3, 21514, 3, 19362}, {3, 21339, 3, 19205}}, ++/* 8 */ {2452, {5, 23093, 5, 20783}, {4, 23093, 4, 20783}, {3, 21382, 3, 19244}, {3, 21470, 3, 19323}, {3, 21295, 3, 19166}}, ++/* 9 */ {2457, {5, 23046, 5, 20741}, {4, 23046, 4, 20741}, {3, 21339, 3, 19205}, {3, 21426, 3, 19283}, {3, 21252, 3, 19127}}, ++/* 10 */ {2462, {5, 22999, 5, 20699}, {4, 22999, 4, 20699}, {3, 21295, 3, 19166}, {3, 21382, 3, 19244}, {3, 21209, 3, 19088}}, ++/* 11 */ {2467, {5, 22952, 5, 20657}, {4, 22952, 4, 20657}, {3, 21252, 3, 19127}, {3, 21339, 3, 19205}, {3, 21166, 3, 19050}}, ++/* 12 */ {2472, {5, 22906, 5, 20615}, {4, 22906, 4, 20615}, {3, 21209, 3, 19088}, {3, 21295, 3, 19166}, {3, 21124, 3, 19011}}, ++/* 13 */ {2484, {5, 22795, 5, 20516}, {4, 22795, 4, 20516}, {3, 21107, 3, 18996}, {3, 21192, 3, 19073}, {3, 21022, 3, 18920}}, ++/* 14 */ {4920, {6, 23018, 6, 20716}, {5, 23018, 5, 20716}, {4, 21313, 4, 19181}, {4, 21356, 4, 19220}, {4, 21269, 4, 19142}}, ++/* 15 */ {4940, {6, 22924, 6, 20632}, {5, 22924, 5, 20632}, {4, 21226, 4, 19104}, {4, 21269, 4, 19142}, {4, 21183, 4, 19065}}, ++/* 16 */ {4960, {6, 22832, 6, 20549}, {5, 22832, 5, 20549}, {4, 21141, 4, 19027}, {4, 21183, 4, 19065}, {4, 21098, 4, 18988}}, ++/* 17 */ {4980, {6, 22740, 6, 20466}, {5, 22740, 5, 20466}, {4, 21056, 4, 18950}, {4, 21098, 4, 18988}, {4, 21014, 4, 18912}}, ++/* 18 */ {5040, {6, 22469, 6, 20223}, {5, 22469, 5, 20223}, {4, 20805, 4, 18725}, {4, 20846, 4, 18762}, {4, 20764, 4, 18687}}, ++/* 19 */ {5060, {6, 22381, 6, 20143}, {5, 22381, 5, 20143}, {4, 20723, 4, 18651}, {4, 20764, 4, 18687}, {4, 20682, 4, 18614}}, ++/* 20 */ {5080, {6, 22293, 6, 20063}, {5, 22293, 5, 20063}, {4, 20641, 4, 18577}, {4, 20682, 4, 18614}, {4, 20601, 4, 18541}}, ++/* 21 */ {5180, {6, 21862, 6, 19676}, {5, 21862, 5, 19676}, {4, 20243, 4, 18219}, {4, 20282, 4, 18254}, {4, 20204, 4, 18183}}, ++/* 22 */ {5200, {6, 21778, 6, 19600}, {5, 21778, 5, 19600}, {4, 20165, 4, 18148}, {4, 20204, 4, 18183}, {4, 20126, 4, 18114}}, ++/* 23 */ {5220, {6, 21695, 6, 19525}, {5, 21695, 5, 19525}, {4, 20088, 4, 18079}, {4, 20126, 4, 18114}, {4, 20049, 4, 18044}}, ++/* 24 */ {5240, {6, 21612, 6, 19451}, {5, 21612, 5, 19451}, {4, 20011, 4, 18010}, {4, 20049, 4, 18044}, {4, 19973, 4, 17976}}, ++/* 25 */ {5260, {6, 21530, 6, 19377}, {5, 21530, 5, 19377}, {4, 19935, 4, 17941}, {4, 19973, 4, 17976}, {4, 19897, 4, 17907}}, ++/* 26 */ {5280, {6, 21448, 6, 19303}, {5, 21448, 5, 19303}, {4, 19859, 4, 17873}, {4, 19897, 4, 17907}, {4, 19822, 4, 17840}}, ++/* 27 */ {5300, {6, 21367, 6, 19230}, {5, 21367, 5, 19230}, {4, 19784, 4, 17806}, {4, 19822, 4, 17840}, {4, 19747, 4, 17772}}, ++/* 28 */ {5320, {6, 21287, 6, 19158}, {5, 21287, 5, 19158}, {4, 19710, 4, 17739}, {4, 19747, 4, 17772}, {4, 19673, 4, 17706}}, ++/* 29 */ {5500, {6, 20590, 6, 18531}, {5, 20590, 5, 18531}, {4, 19065, 4, 17159}, {4, 19100, 4, 17190}, {4, 19030, 4, 17127}}, ++/* 30 */ {5520, {6, 20516, 6, 18464}, {5, 20516, 5, 18464}, {4, 18996, 4, 17096}, {4, 19030, 4, 17127}, {4, 18962, 4, 17065}}, ++/* 31 */ {5540, {6, 20442, 6, 18397}, {5, 20442, 5, 18397}, {4, 18927, 4, 17035}, {4, 18962, 4, 17065}, {4, 18893, 4, 17004}}, ++/* 32 */ {5560, {6, 20368, 6, 18331}, {5, 20368, 5, 18331}, {4, 18859, 4, 16973}, {4, 18893, 4, 17004}, {4, 18825, 4, 16943}}, ++/* 33 */ {5580, {6, 20295, 6, 18266}, {5, 20295, 5, 18266}, {4, 18792, 4, 16913}, {4, 18825, 4, 16943}, {4, 18758, 4, 16882}}, ++/* 34 */ {5600, {6, 20223, 6, 18200}, {5, 20223, 5, 18200}, {4, 18725, 4, 16852}, {4, 18758, 4, 16882}, {4, 18691, 4, 16822}}, ++/* 35 */ {5620, {6, 20151, 6, 18136}, {5, 20151, 5, 18136}, {4, 18658, 4, 16792}, {4, 18691, 4, 16822}, {4, 18625, 4, 16762}}, ++/* 36 */ {5640, {6, 20079, 6, 18071}, {5, 20079, 5, 18071}, {4, 18592, 4, 16733}, {4, 18625, 4, 16762}, {4, 18559, 4, 16703}}, ++/* 37 */ {5660, {6, 20008, 6, 18007}, {5, 20008, 5, 18007}, {4, 18526, 4, 16673}, {4, 18559, 4, 16703}, {4, 18493, 4, 16644}}, ++/* 38 */ {5680, {6, 19938, 6, 17944}, {5, 19938, 5, 17944}, {4, 18461, 4, 16615}, {4, 18493, 4, 16644}, {4, 18428, 4, 16586}}, ++/* 39 */ {5700, {6, 19868, 6, 17881}, {5, 19868, 5, 17881}, {4, 18396, 4, 16556}, {4, 18428, 4, 16586}, {4, 18364, 4, 16527}}, ++/* 40 */ {5745, {6, 19712, 6, 17741}, {5, 19712, 5, 17741}, {4, 18252, 4, 16427}, {4, 18284, 4, 16455}, {4, 18220, 4, 16398}}, ++/* 41 */ {5765, {6, 19644, 6, 17679}, {5, 19644, 5, 17679}, {4, 18189, 5, 32740}, {4, 18220, 4, 16398}, {4, 18157, 5, 32683}}, ++/* 42 */ {5785, {6, 19576, 6, 17618}, {5, 19576, 5, 17618}, {4, 18126, 5, 32626}, {4, 18157, 5, 32683}, {4, 18094, 5, 32570}}, ++/* 43 */ {5805, {6, 19508, 6, 17558}, {5, 19508, 5, 17558}, {4, 18063, 5, 32514}, {4, 18094, 5, 32570}, {4, 18032, 5, 32458}}, ++/* 44 */ {5825, {6, 19441, 6, 17497}, {5, 19441, 5, 17497}, {4, 18001, 5, 32402}, {4, 18032, 5, 32458}, {4, 17970, 5, 32347}}, ++/* 45 */ {5170, {6, 21904, 6, 19714}, {5, 21904, 5, 19714}, {4, 20282, 4, 18254}, {4, 20321, 4, 18289}, {4, 20243, 4, 18219}}, ++/* 46 */ {5190, {6, 21820, 6, 19638}, {5, 21820, 5, 19638}, {4, 20204, 4, 18183}, {4, 20243, 4, 18219}, {4, 20165, 4, 18148}}, ++/* 47 */ {5210, {6, 21736, 6, 19563}, {5, 21736, 5, 19563}, {4, 20126, 4, 18114}, {4, 20165, 4, 18148}, {4, 20088, 4, 18079}}, ++/* 48 */ {5230, {6, 21653, 6, 19488}, {5, 21653, 5, 19488}, {4, 20049, 4, 18044}, {4, 20088, 4, 18079}, {4, 20011, 4, 18010}} ++}; ++/* to reduce search time, please modify this define if you add or delete channel in table */ ++#define First5GChannelIndex 14 ++ ++void zfGetHwTurnOffdynParam(zdev_t* dev, ++ u32_t frequency, u8_t bw40, u8_t extOffset, ++ int* delta_slope_coeff_exp, ++ int* delta_slope_coeff_man, ++ int* delta_slope_coeff_exp_shgi, ++ int* delta_slope_coeff_man_shgi) ++{ ++ /* Get param for turnoffdyn */ ++ u16_t i, arraySize; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ arraySize = sizeof(zgPhyFreqCoeff)/sizeof(struct zsPhyFreqTable); ++ if (frequency < 3000) ++ { ++ /* 2.4GHz Channel */ ++ for (i = 0; i < First5GChannelIndex; i++) ++ { ++ if (frequency == zgPhyFreqCoeff[i].frequency) ++ break; ++ } ++ ++ if (i < First5GChannelIndex) ++ { ++ } ++ else ++ { ++ zm_msg1_scan(ZM_LV_0, "Unsupported 2.4G frequency = ", frequency); ++ return; ++ } ++ } ++ else ++ { ++ /* 5GHz Channel */ ++ for (i = First5GChannelIndex; i < arraySize; i++) ++ { ++ if (frequency == zgPhyFreqCoeff[i].frequency) ++ break; ++ } ++ ++ if (i < arraySize) ++ { ++ } ++ else ++ { ++ zm_msg1_scan(ZM_LV_0, "Unsupported 5G frequency = ", frequency); ++ return; ++ } ++ } ++ ++ /* FPGA DYNAMIC_HT2040_EN fclk = 10.8 */ ++ /* FPGA STATIC_HT20_ fclk = 21.6 */ ++ /* Real Chip fclk = 40 */ ++ #if ZM_FPGA_PHY == 1 ++ //fclk = 10.8; ++ *delta_slope_coeff_exp = zgPhyFreqCoeff[i].FpgaDynamicHT.coeff_exp; ++ *delta_slope_coeff_man = zgPhyFreqCoeff[i].FpgaDynamicHT.coeff_man; ++ *delta_slope_coeff_exp_shgi = zgPhyFreqCoeff[i].FpgaDynamicHT.coeff_exp_shgi; ++ *delta_slope_coeff_man_shgi = zgPhyFreqCoeff[i].FpgaDynamicHT.coeff_man_shgi; ++ #else ++ //fclk = 40; ++ if (bw40) ++ { ++ /* ht2040 */ ++ if (extOffset == 1) { ++ *delta_slope_coeff_exp = zgPhyFreqCoeff[i].Chip2040ExtAbove.coeff_exp; ++ *delta_slope_coeff_man = zgPhyFreqCoeff[i].Chip2040ExtAbove.coeff_man; ++ *delta_slope_coeff_exp_shgi = zgPhyFreqCoeff[i].Chip2040ExtAbove.coeff_exp_shgi; ++ *delta_slope_coeff_man_shgi = zgPhyFreqCoeff[i].Chip2040ExtAbove.coeff_man_shgi; ++ } ++ else { ++ *delta_slope_coeff_exp = zgPhyFreqCoeff[i].Chip2040Mhz.coeff_exp; ++ *delta_slope_coeff_man = zgPhyFreqCoeff[i].Chip2040Mhz.coeff_man; ++ *delta_slope_coeff_exp_shgi = zgPhyFreqCoeff[i].Chip2040Mhz.coeff_exp_shgi; ++ *delta_slope_coeff_man_shgi = zgPhyFreqCoeff[i].Chip2040Mhz.coeff_man_shgi; ++ } ++ } ++ else ++ { ++ /* static 20 */ ++ *delta_slope_coeff_exp = zgPhyFreqCoeff[i].ChipST20Mhz.coeff_exp; ++ *delta_slope_coeff_man = zgPhyFreqCoeff[i].ChipST20Mhz.coeff_man; ++ *delta_slope_coeff_exp_shgi = zgPhyFreqCoeff[i].ChipST20Mhz.coeff_exp_shgi; ++ *delta_slope_coeff_man_shgi = zgPhyFreqCoeff[i].ChipST20Mhz.coeff_man_shgi; ++ } ++ #endif ++} ++ ++/* Main routin frequency setting function */ ++/* If 2.4G/5G switch, PHY need resetting BB and RF for band switch */ ++/* Do the setting switch in zfSendFrequencyCmd() */ ++void zfHpSetFrequencyEx(zdev_t* dev, u32_t frequency, u8_t bw40, ++ u8_t extOffset, u8_t initRF) ++{ ++ u32_t cmd[9]; ++ u32_t cmdB[3]; ++ u16_t ret; ++ u8_t old_band; ++ u8_t new_band; ++ u32_t checkLoopCount; ++ u32_t tmpValue; ++ ++ int delta_slope_coeff_exp; ++ int delta_slope_coeff_man; ++ int delta_slope_coeff_exp_shgi; ++ int delta_slope_coeff_man_shgi; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ zm_msg1_scan(ZM_LV_1, "Frequency = ", frequency); ++ zm_msg1_scan(ZM_LV_1, "bw40 = ", bw40); ++ zm_msg1_scan(ZM_LV_1, "extOffset = ", extOffset); ++ ++ if ( hpPriv->coldResetNeedFreq ) ++ { ++ hpPriv->coldResetNeedFreq = 0; ++ initRF = 2; ++ zm_debug_msg0("zfHpSetFrequencyEx: Do ColdReset "); ++ } ++ if ( hpPriv->isSiteSurvey == 2 ) ++ { ++ /* wait time for AGC and noise calibration : not in sitesurvey and connected */ ++ checkLoopCount = 2000; /* 2000*100 = 200ms */ ++ } ++ else ++ { ++ /* wait time for AGC and noise calibration : in sitesurvey */ ++ checkLoopCount = 1000; /* 1000*100 = 100ms */ ++ } ++ ++ hpPriv->latestFrequency = frequency; ++ hpPriv->latestBw40 = bw40; ++ hpPriv->latestExtOffset = extOffset; ++ ++ if ((hpPriv->dot11Mode == ZM_HAL_80211_MODE_IBSS_GENERAL) || ++ (hpPriv->dot11Mode == ZM_HAL_80211_MODE_IBSS_WPA2PSK)) ++ { ++ if ( frequency <= ZM_CH_G_14 ) ++ { ++ /* workaround for 11g Ad Hoc beacon distribution */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, 0x7f0007); ++ //zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_AIFS, 0x1c04901c); ++ } ++ } ++ ++ /* AHB, DAC, ADC clock selection by static20/ht2040 */ ++ zfSelAdcClk(dev, bw40, frequency); ++ ++ /* clear bb_heavy_clip_enable */ ++ reg_write(0x99e0, 0x200); ++ zfFlushDelayWrite(dev); ++ ++ /* Set CTS/RTS rate */ ++ if ( frequency > ZM_CH_G_14 ) ++ { ++ //zfHpSetRTSCTSRate(dev, 0x10b010b); /* OFDM 6M */ ++ new_band = 1; ++ } ++ else ++ { ++ //zfHpSetRTSCTSRate(dev, 0x30003); /* CCK 11M */ ++ new_band = 0; ++ } ++ ++ if (((struct zsHpPriv*)wd->hpPrivate)->hwFrequency > ZM_CH_G_14) ++ old_band = 1; ++ else ++ old_band = 0; ++ ++ //Workaround for 2.4GHz only device ++ if ((hpPriv->OpFlags & 0x1) == 0) ++ { ++ if ((((struct zsHpPriv*)wd->hpPrivate)->hwFrequency == ZM_CH_G_1) && (frequency == ZM_CH_G_2)) ++ { ++ /* Force to do band switching */ ++ old_band = 1; ++ } ++ } ++ ++ /* Notify channel switch to firmware */ ++ /* TX/RX must be stopped by now */ ++ cmd[0] = 0 | (ZM_CMD_FREQ_STRAT << 8); ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_INTERNAL_WRITE, 0); ++ ++ if ((initRF != 0) || (new_band != old_band) ++ || (((struct zsHpPriv*)wd->hpPrivate)->hwBw40 != bw40)) ++ { ++ /* band switch */ ++ zm_msg0_scan(ZM_LV_1, "=====band switch====="); ++ ++ if (initRF == 2 ) ++ { ++ //Cold reset BB/ADDA ++ zfDelayWriteInternalReg(dev, 0x1d4004, 0x800); ++ zfFlushDelayWrite(dev); ++ zm_msg0_scan(ZM_LV_1, "Do cold reset BB/ADDA"); ++ } ++ else ++ { ++ //Warm reset BB/ADDA ++ zfDelayWriteInternalReg(dev, 0x1d4004, 0x400); ++ zfFlushDelayWrite(dev); ++ } ++ ++ /* reset workaround state to default */ ++ hpPriv->rxStrongRSSI = 0; ++ hpPriv->strongRSSI = 0; ++ ++ zfDelayWriteInternalReg(dev, 0x1d4004, 0x0); ++ zfFlushDelayWrite(dev); ++ ++ zfInitPhy(dev, frequency, bw40); ++ ++// zfiCheckRifs(dev); ++ ++ /* Bank 0 1 2 3 5 6 7 */ ++ zfSetRfRegs(dev, frequency); ++ /* Bank 4 */ ++ zfSetBank4AndPowerTable(dev, frequency, bw40, extOffset); ++ ++ cmd[0] = 32 | (ZM_CMD_RF_INIT << 8); ++ } ++ else //((new_band == old_band) && !initRF) ++ { ++ /* same band */ ++ ++ /* Force disable CR671 bit20 / 7823 */ ++ /* The bug has to do with the polarity of the pdadc offset calibration. There */ ++ /* is an initial calibration that is OK, and there is a continuous */ ++ /* calibration that updates the pddac with the wrong polarity. Fortunately */ ++ /* the second loop can be disabled with a bit called en_pd_dc_offset_thr. */ ++#if 0 ++ cmdB[0] = 8 | (ZM_CMD_BITAND << 8);; ++ cmdB[1] = (0xa27c + 0x1bc000); ++ cmdB[2] = 0xffefffff; ++ ret = zfIssueCmd(dev, cmdB, 12, ZM_OID_INTERNAL_WRITE, 0); ++#endif ++ ++ /* Bank 4 */ ++ zfSetBank4AndPowerTable(dev, frequency, bw40, extOffset); ++ ++ ++ cmd[0] = 32 | (ZM_CMD_FREQUENCY << 8); ++ } ++ ++ /* Compatibility for new layout UB83 */ ++ /* Setting code at CR1 here move from the func:zfHwHTEnable() in firmware */ ++ if (((struct zsHpPriv*)wd->hpPrivate)->halCapability & ZM_HP_CAP_11N_ONE_TX_STREAM) ++ { ++ /* UB83 : one stream */ ++ tmpValue = 0; ++ } ++ else ++ { ++ /* UB81, UB82 : two stream */ ++ tmpValue = 0x100; ++ } ++ ++ if (1) //if (((struct zsHpPriv*)wd->hpPrivate)->hw_HT_ENABLE == 1) ++ { ++ if (bw40 == 1) ++ { ++ if (extOffset == 1) { ++ reg_write(0x9804, tmpValue | 0x2d4); //3d4 for real ++ } ++ else { ++ reg_write(0x9804, tmpValue | 0x2c4); //3c4 for real ++ } ++ //# Dyn HT2040.Refer to Reg 1. ++ //#[3]:single length (4us) 1st HT long training symbol; use Walsh spatial spreading for 2 chains 2 streams TX ++ //#[c]:allow short GI for HT40 packets; enable HT detection. ++ //#[4]:enable 20/40 MHz channel detection. ++ } ++ else ++ { ++ reg_write(0x9804, tmpValue | 0x240); ++ //# Static HT20 ++ //#[3]:single length (4us) 1st HT long training symbol; use Walsh spatial spreading for 2 chains 2 streams TX ++ //#[4]:Otus don't allow short GI for HT20 packets yet; enable HT detection. ++ //#[0]:disable 20/40 MHz channel detection. ++ } ++ } ++ else ++ { ++ reg_write(0x9804, 0x0); ++ //# Legacy;# Direct Mapping for each chain. ++ //#Be modified by Oligo to add dynanic for legacy. ++ if (bw40 == 1) ++ { ++ reg_write(0x9804, 0x4); //# Dyn Legacy .Refer to reg 1. ++ } ++ else ++ { ++ reg_write(0x9804, 0x0); //# Static Legacy ++ } ++ } ++ zfFlushDelayWrite(dev); ++ /* end of ub83 compatibility */ ++ ++ /* Set Power, TPC, Gain table... */ ++ zfSetPowerCalTable(dev, frequency, bw40, extOffset); ++ ++ ++ /* store frequency */ ++ ((struct zsHpPriv*)wd->hpPrivate)->hwFrequency = (u16_t)frequency; ++ ((struct zsHpPriv*)wd->hpPrivate)->hwBw40 = bw40; ++ ((struct zsHpPriv*)wd->hpPrivate)->hwExtOffset = extOffset; ++ ++ zfGetHwTurnOffdynParam(dev, ++ frequency, bw40, extOffset, ++ &delta_slope_coeff_exp, ++ &delta_slope_coeff_man, ++ &delta_slope_coeff_exp_shgi, ++ &delta_slope_coeff_man_shgi); ++ ++ /* related functions */ ++ frequency = frequency*1000; ++ /* len[36] : type[0x30] : seq[?] */ ++// cmd[0] = 28 | (ZM_CMD_FREQUENCY << 8); ++ cmd[1] = frequency; ++ cmd[2] = bw40;//((struct zsHpPriv*)wd->hpPrivate)->hw_DYNAMIC_HT2040_EN; ++ cmd[3] = (extOffset<<2)|0x1;//((wd->ExtOffset << 2) | ((struct zsHpPriv*)wd->hpPrivate)->hw_HT_ENABLE); ++ cmd[4] = delta_slope_coeff_exp; ++ cmd[5] = delta_slope_coeff_man; ++ cmd[6] = delta_slope_coeff_exp_shgi; ++ cmd[7] = delta_slope_coeff_man_shgi; ++ cmd[8] = checkLoopCount; ++ ++ ret = zfIssueCmd(dev, cmd, 36, ZM_CMD_SET_FREQUENCY, 0); ++ ++ // delay temporarily, wait for new PHY and RF ++ //zfwSleep(dev, 1000); ++} ++ ++ ++/******************** Key ********************/ ++ ++u16_t zfHpResetKeyCache(zdev_t* dev) ++{ ++ u8_t i; ++ u32_t key[4] = {0, 0, 0, 0}; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ for(i=0;i<4;i++) ++ { ++ zfHpSetDefaultKey(dev, i, ZM_WEP64, key, NULL); ++ } ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ROLL_CALL_TBL_L, 0x00); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ROLL_CALL_TBL_H, 0x00); ++ zfFlushDelayWrite(dev); ++ ++ hpPriv->camRollCallTable = (u64_t) 0; ++ ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfSetKey */ ++/* Set key. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2006.1 */ ++/* */ ++/************************************************************************/ ++/* ! please use zfCoreSetKey() in 80211Core for SetKey */ ++u32_t zfHpSetKey(zdev_t* dev, u8_t user, u8_t keyId, u8_t type, ++ u16_t* mac, u32_t* key) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++#if 0 /* remove to zfCoreSetKey() */ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ wd->sta.flagKeyChanging++; ++ zm_debug_msg1(" zfHpSetKey++++ ", wd->sta.flagKeyChanging); ++ zmw_leave_critical_section(dev); ++#endif ++ ++ cmd[0] = 0x0000281C; ++ cmd[1] = ((u32_t)keyId<<16) + (u32_t)user; ++ cmd[2] = ((u32_t)mac[0]<<16) + (u32_t)type; ++ cmd[3] = ((u32_t)mac[2]<<16) + ((u32_t)mac[1]); ++ ++ for (i=0; i<4; i++) ++ { ++ cmd[4+i] = key[i]; ++ } ++ ++ if (user < 64) ++ { ++ hpPriv->camRollCallTable |= ((u64_t) 1) << user; ++ } ++ ++ //ret = zfIssueCmd(dev, cmd, 32, ZM_OID_INTERNAL_WRITE, NULL); ++ ret = zfIssueCmd(dev, cmd, 32, ZM_CMD_SET_KEY, NULL); ++ return ret; ++} ++ ++ ++u32_t zfHpSetApPairwiseKey(zdev_t* dev, u16_t* staMacAddr, u8_t type, ++ u32_t* key, u32_t* micKey, u16_t staAid) ++{ ++ if ((staAid!=0) && (staAid<64)) ++ { ++ zfHpSetKey(dev, (staAid-1), 0, type, staMacAddr, key); ++ if ((type == ZM_TKIP) ++#ifdef ZM_ENABLE_CENC ++ || (type == ZM_CENC) ++#endif //ZM_ENABLE_CENC ++ ) ++ zfHpSetKey(dev, (staAid-1), 1, type, staMacAddr, micKey); ++ return 0; ++ } ++ return 1; ++} ++ ++u32_t zfHpSetApGroupKey(zdev_t* dev, u16_t* apMacAddr, u8_t type, ++ u32_t* key, u32_t* micKey, u16_t vapId) ++{ ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT - 1 - vapId, 0, type, apMacAddr, key); // 6D18 modify from 0 to 1 ?? ++ if ((type == ZM_TKIP) ++#ifdef ZM_ENABLE_CENC ++ || (type == ZM_CENC) ++#endif //ZM_ENABLE_CENC ++ ) ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT - 1 - vapId, 1, type, apMacAddr, micKey); ++ return 0; ++} ++ ++u32_t zfHpSetDefaultKey(zdev_t* dev, u8_t keyId, u8_t type, u32_t* key, u32_t* micKey) ++{ ++ u16_t macAddr[3] = {0, 0, 0}; ++ ++ #ifdef ZM_ENABLE_IBSS_WPA2PSK ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ if ( hpPriv->dot11Mode == ZM_HAL_80211_MODE_IBSS_WPA2PSK ) ++ { /* If not wpa2psk , use traditional */ ++ /* Because the bug of chip , defaultkey should follow the key map rule in register 700 */ ++ if ( keyId == 0 ) ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT+keyId, 0, type, macAddr, key); ++ else ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT+keyId, 1, type, macAddr, key); ++ } ++ else ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT+keyId, 0, type, macAddr, key); ++ #else ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT+keyId, 0, type, macAddr, key); ++ #endif ++ if ((type == ZM_TKIP) ++ ++#ifdef ZM_ENABLE_CENC ++ || (type == ZM_CENC) ++#endif //ZM_ENABLE_CENC ++ ) ++ { ++ zfHpSetKey(dev, ZM_USER_KEY_DEFAULT+keyId, 1, type, macAddr, micKey); ++ } ++ ++ return 0; ++} ++ ++u32_t zfHpSetPerUserKey(zdev_t* dev, u8_t user, u8_t keyId, u8_t* mac, u8_t type, u32_t* key, u32_t* micKey) ++{ ++#ifdef ZM_ENABLE_IBSS_WPA2PSK ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ if ( hpPriv->dot11Mode == ZM_HAL_80211_MODE_IBSS_WPA2PSK ) ++ { /* If not wpa2psk , use traditional */ ++ if(keyId) ++ { /* Set Group Key */ ++ zfHpSetKey(dev, user, 1, type, (u16_t *)mac, key); ++ } ++ else if(keyId == 0) ++ { /* Set Pairwise Key */ ++ zfHpSetKey(dev, user, 0, type, (u16_t *)mac, key); ++ } ++ } ++ else ++ { ++ zfHpSetKey(dev, user, keyId, type, (u16_t *)mac, key); ++ } ++#else ++ zfHpSetKey(dev, user, keyId, type, (u16_t *)mac, key); ++#endif ++ ++ if ((type == ZM_TKIP) ++#ifdef ZM_ENABLE_CENC ++ || (type == ZM_CENC) ++#endif //ZM_ENABLE_CENC ++ ) ++ { ++ zfHpSetKey(dev, user, keyId + 1, type, (u16_t *)mac, micKey); ++ } ++ return 0; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfHpRemoveKey */ ++/* Remove key. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Yuan-Gu Wei ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++u16_t zfHpRemoveKey(zdev_t* dev, u16_t user) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret = 0; ++ ++ cmd[0] = 0x00002904; ++ cmd[1] = (u32_t)user; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++ ++ ++ ++/******************** DMA ********************/ ++u16_t zfHpStartRecv(zdev_t* dev) ++{ ++ zfDelayWriteInternalReg(dev, 0x1c3d30, 0x100); ++ zfFlushDelayWrite(dev); ++ ++ return 0; ++} ++ ++u16_t zfHpStopRecv(zdev_t* dev) ++{ ++ return 0; ++} ++ ++ ++/******************** MAC ********************/ ++void zfInitMac(zdev_t* dev) ++{ ++ /* ACK extension register */ ++ // jhlee temp : change value 0x2c -> 0x40 ++ // honda resolve short preamble problem : 0x40 -> 0x75 ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ACK_EXTENSION, 0x40); // 0x28 -> 0x2c 6522:yflee ++ ++ /* TxQ0/1/2/3 Retry MAX=2 => transmit 3 times and degrade rate for retry */ ++ /* PB42 AP crash issue: */ ++ /* Workaround the crash issue by CTS/RTS, set retry max to zero for */ ++ /* workaround tx underrun which enable CTS/RTS */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RETRY_MAX, 0); // 0x11111 => 0 ++ ++ /* use hardware MIC check */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_SNIFFER, 0x2000000); ++ ++ /* Set Rx threshold to 1600 */ ++#if ZM_LARGEPAYLOAD_TEST == 1 ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RX_THRESHOLD, 0xc4000); ++#else ++ #ifndef ZM_DISABLE_AMSDU8K_SUPPORT ++ /* The maximum A-MSDU length is 3839/7935 */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RX_THRESHOLD, 0xc1f80); ++ #else ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RX_THRESHOLD, 0xc0f80); ++ #endif ++#endif ++ ++ //zfDelayWriteInternalReg(dev, ZM_MAC_REG_DYNAMIC_SIFS_ACK, 0x10A); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RX_PE_DELAY, 0x70); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, 0xa144000); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_SLOT_TIME, 9<<10); ++ ++ /* CF-END mode */ ++ zfDelayWriteInternalReg(dev, 0x1c3b2c, 0x19000000); ++ ++ //NAV protects ACK only (in TXOP) ++ zfDelayWriteInternalReg(dev, 0x1c3b38, 0x201); ++ ++ ++ /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ ++ /* OTUS set AM to 0x1 */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_HT1, 0x8000170); ++ ++ /* TODO : wep backoff protection 0x63c */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BACKOFF_PROTECT, 0x105); ++ ++ /* AGG test code*/ ++ /* Aggregation MAX number and timeout */ ++ zfDelayWriteInternalReg(dev, 0x1c3b9c, 0x10000a); ++ /* Filter any control frames, BAR is bit 24 */ ++ zfDelayWriteInternalReg(dev, 0x1c368c, 0x0500ffff); ++ /* Enable deaggregator */ ++ zfDelayWriteInternalReg(dev, 0x1c3c40, 0x1); ++ ++ /* Basic rate */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BASIC_RATE, 0x150f); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MANDATORY_RATE, 0x150f); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RTS_CTS_RATE, 0x10b01bb); ++ ++ /* MIMO resposne control */ ++ zfDelayWriteInternalReg(dev, 0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ ++ ++ /* Enable LED0 and LED1 */ ++ zfDelayWriteInternalReg(dev, 0x1d0100, 0x3); ++ zfDelayWriteInternalReg(dev, 0x1d0104, 0x3); ++ ++ /* switch MAC to OTUS interface */ ++ zfDelayWriteInternalReg(dev, 0x1c3600, 0x3); ++ ++ /* RXMAC A-MPDU length threshold */ ++ zfDelayWriteInternalReg(dev, 0x1c3c50, 0xffff); ++ ++ /* Phy register read timeout */ ++ zfDelayWriteInternalReg(dev, 0x1c3680, 0xf00008); ++ ++ /* Disable Rx TimeOut : workaround for BB. ++ * OTUS would interrupt the rx frame that sent by OWL TxUnderRun ++ * because OTUS rx timeout behavior, then OTUS would not ack the BA for ++ * this AMPDU from OWL. ++ * Fix by Perry Hwang. 2007/05/10. ++ * 0x1c362c : Rx timeout value : bit 27~16 ++ */ ++ zfDelayWriteInternalReg(dev, 0x1c362c, 0x0); ++ ++ //Set USB Rx stream mode MAX packet number to 2 ++ // Max packet number = *0x1e1110 + 1 ++ zfDelayWriteInternalReg(dev, 0x1e1110, 0x4); ++ //Set USB Rx stream mode timeout to 10us ++ zfDelayWriteInternalReg(dev, 0x1e1114, 0x80); ++ ++ //Set CPU clock frequency to 88/80MHz ++ zfDelayWriteInternalReg(dev, 0x1D4008, 0x73); ++ ++ //Set WLAN DMA interrupt mode : generate int per packet ++ zfDelayWriteInternalReg(dev, 0x1c3d7c, 0x110011); ++ ++ /* 7807 */ ++ /* enable func : Reset FIFO1 and FIFO2 when queue-gnt is low */ ++ /* 0x1c3bb0 Bit2 */ ++ /* Disable SwReset in firmware for TxHang, enable reset FIFO func. */ ++ zfDelayWriteInternalReg(dev, 0x1c3bb0, 0x4); ++ ++ /* Disables the CF_END frame */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_TXOP_NOT_ENOUGH_INDICATION, 0x141E0F48); ++ ++ /* Disable the SW Decrypt*/ ++ zfDelayWriteInternalReg(dev, 0x1c3678, 0x70); ++ zfFlushDelayWrite(dev); ++ //--------------------- ++ ++ /* Set TxQs CWMIN, CWMAX, AIFS and TXO to WME STA default. */ ++ zfUpdateDefaultQosParameter(dev, 0); ++ ++ //zfSelAdcClk(dev, 0); ++ ++ return; ++} ++ ++ ++u16_t zfHpSetSnifferMode(zdev_t* dev, u16_t on) ++{ ++ if (on != 0) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_SNIFFER, 0x2000001); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_SNIFFER, 0x2000000); ++ } ++ zfFlushDelayWrite(dev); ++ return 0; ++} ++ ++ ++u16_t zfHpSetApStaMode(zdev_t* dev, u8_t mode) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ hpPriv->dot11Mode = mode; ++ ++ switch(mode) ++ { ++ case ZM_HAL_80211_MODE_AP: ++ zfDelayWriteInternalReg(dev, 0x1c3700, 0x0f0000a1); ++ zfDelayWriteInternalReg(dev, 0x1c3c40, 0x1); ++ break; ++ ++ case ZM_HAL_80211_MODE_STA: ++ zfDelayWriteInternalReg(dev, 0x1c3700, 0x0f000002); ++ zfDelayWriteInternalReg(dev, 0x1c3c40, 0x1); ++ break; ++ ++ case ZM_HAL_80211_MODE_IBSS_GENERAL: ++ zfDelayWriteInternalReg(dev, 0x1c3700, 0x0f000000); ++ zfDelayWriteInternalReg(dev, 0x1c3c40, 0x1); ++ break; ++ ++ case ZM_HAL_80211_MODE_IBSS_WPA2PSK: ++ zfDelayWriteInternalReg(dev, 0x1c3700, 0x0f0000e0); ++ zfDelayWriteInternalReg(dev, 0x1c3c40, 0x41); // for multiple ( > 2 ) stations IBSS network ++ break; ++ ++ default: ++ goto skip; ++ } ++ ++ zfFlushDelayWrite(dev); ++ ++skip: ++ return 0; ++} ++ ++ ++u16_t zfHpSetBssid(zdev_t* dev, u8_t* bssidSrc) ++{ ++ u32_t address; ++ u16_t *bssid = (u16_t *)bssidSrc; ++ ++ address = bssid[0] + (((u32_t)bssid[1]) << 16); ++ zfDelayWriteInternalReg(dev, 0x1c3618, address); ++ ++ address = (u32_t)bssid[2]; ++ zfDelayWriteInternalReg(dev, 0x1c361C, address); ++ zfFlushDelayWrite(dev); ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfHpUpdateQosParameter */ ++/* Update TxQs CWMIN, CWMAX, AIFS and TXOP. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* cwminTbl : CWMIN parameter for TxQs */ ++/* cwmaxTbl : CWMAX parameter for TxQs */ ++/* aifsTbl: AIFS parameter for TxQs */ ++/* txopTbl : TXOP parameter for TxQs */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++u8_t zfHpUpdateQosParameter(zdev_t* dev, u16_t* cwminTbl, u16_t* cwmaxTbl, ++ u16_t* aifsTbl, u16_t* txopTbl) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ zm_msg0_mm(ZM_LV_0, "zfHalUpdateQosParameter()"); ++ ++ /* Note : Do not change cwmin for Q0 in Ad Hoc mode */ ++ /* otherwise driver will fail in Wifi beacon distribution */ ++ if (hpPriv->dot11Mode == ZM_HAL_80211_MODE_STA) ++ { ++#if 0 //Restore CWmin to improve down link throughput ++ //cheating in BE traffic ++ if (wd->sta.EnableHT == 1) ++ { ++ //cheating in BE traffic ++ cwminTbl[0] = 7;//15; ++ } ++#endif ++ cwmaxTbl[0] = 127;//1023; ++ aifsTbl[0] = 2*9+10;//3 * 9 + 10; ++ } ++ ++ /* CWMIN and CWMAX */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, cwminTbl[0] ++ + ((u32_t)cwmaxTbl[0]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_CW, cwminTbl[1] ++ + ((u32_t)cwmaxTbl[1]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC2_CW, cwminTbl[2] ++ + ((u32_t)cwmaxTbl[2]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC3_CW, cwminTbl[3] ++ + ((u32_t)cwmaxTbl[3]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC4_CW, cwminTbl[4] ++ + ((u32_t)cwmaxTbl[4]<<16)); ++ ++ /* AIFS */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_AIFS, aifsTbl[0] ++ +((u32_t)aifsTbl[0]<<12)+((u32_t)aifsTbl[0]<<24)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC3_AC2_AIFS, (aifsTbl[0]>>8) ++ +((u32_t)aifsTbl[0]<<4)+((u32_t)aifsTbl[0]<<16)); ++ ++ /* TXOP */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_TXOP, txopTbl[0] ++ + ((u32_t)txopTbl[1]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC3_AC2_TXOP, txopTbl[2] ++ + ((u32_t)txopTbl[3]<<16)); ++ ++ zfFlushDelayWrite(dev); ++ ++ hpPriv->txop[0] = txopTbl[0]; ++ hpPriv->txop[1] = txopTbl[1]; ++ hpPriv->txop[2] = txopTbl[2]; ++ hpPriv->txop[3] = txopTbl[3]; ++ hpPriv->cwmin[0] = cwminTbl[0]; ++ hpPriv->cwmax[0] = cwmaxTbl[0]; ++ hpPriv->cwmin[1] = cwminTbl[1]; ++ hpPriv->cwmax[1] = cwmaxTbl[1]; ++ ++ return 0; ++} ++ ++ ++void zfHpSetAtimWindow(zdev_t* dev, u16_t atimWin) ++{ ++ zm_msg1_mm(ZM_LV_0, "Set ATIM window to ", atimWin); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ATIM_WINDOW, atimWin); ++ zfFlushDelayWrite(dev); ++} ++ ++ ++void zfHpSetBasicRateSet(zdev_t* dev, u16_t bRateBasic, u16_t gRateBasic) ++{ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BASIC_RATE, bRateBasic ++ | ((u16_t)gRateBasic<<8)); ++ zfFlushDelayWrite(dev); ++} ++ ++ ++/* HT40 send by OFDM 6M */ ++/* otherwise use reg 0x638 */ ++void zfHpSetRTSCTSRate(zdev_t* dev, u32_t rate) ++{ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_RTS_CTS_RATE, rate); ++ zfFlushDelayWrite(dev); ++} ++ ++void zfHpSetMacAddress(zdev_t* dev, u16_t* macAddr, u16_t macAddrId) ++{ ++ if (macAddrId == 0) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MAC_ADDR_L, ++ (((u32_t)macAddr[1])<<16) | macAddr[0]); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MAC_ADDR_H, macAddr[2]); ++ } ++ else if (macAddrId <= 7) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ACK_TABLE+((macAddrId-1)*8), ++ macAddr[0] + ((u32_t)macAddr[1]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ACK_TABLE+((macAddrId-1)*8)+4, ++ macAddr[2]); ++ } ++ zfFlushDelayWrite(dev); ++} ++ ++void zfHpSetMulticastList(zdev_t* dev, u8_t size, u8_t* pList, u8_t bAllMulticast) ++{ ++ struct zsMulticastAddr* pMacList = (struct zsMulticastAddr*) pList; ++ u8_t i; ++ u32_t value; ++ u32_t swRegMulHashValueH, swRegMulHashValueL; ++ ++ swRegMulHashValueH = 0x80000000; ++ swRegMulHashValueL = 0; ++ ++ if ( bAllMulticast ) ++ { ++ swRegMulHashValueH = swRegMulHashValueL = ~0; ++ } ++ else ++ { ++ for(i=0; i> 2; ++ ++ if ( value < 32 ) ++ { ++ swRegMulHashValueL |= (1 << value); ++ } ++ else ++ { ++ swRegMulHashValueH |= (1 << (value-32)); ++ } ++ } ++ } ++ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_GROUP_HASH_TBL_L, ++ swRegMulHashValueL); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_GROUP_HASH_TBL_H, ++ swRegMulHashValueH); ++ zfFlushDelayWrite(dev); ++ return; ++} ++ ++/******************** Beacon ********************/ ++void zfHpEnableBeacon(zdev_t* dev, u16_t mode, u16_t bcnInterval, u16_t dtim, u8_t enableAtim) ++{ ++ u32_t value; ++ ++ zmw_get_wlan_dev(dev); ++ ++ /* Beacon Ready */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_CTRL, 0); ++ /* Beacon DMA buffer address */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_ADDR, ZM_BEACON_BUFFER_ADDRESS); ++ ++ value = bcnInterval; ++ ++ value |= (((u32_t) dtim) << 16); ++ ++ if (mode == ZM_MODE_AP) ++ { ++ ++ value |= 0x1000000; ++ } ++ else if (mode == ZM_MODE_IBSS) ++ { ++ value |= 0x2000000; ++ ++ if ( enableAtim ) ++ { ++ value |= 0x4000000; ++ } ++ ((struct zsHpPriv*)wd->hpPrivate)->ibssBcnEnabled = 1; ++ ((struct zsHpPriv*)wd->hpPrivate)->ibssBcnInterval = value; ++ } ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_PRETBTT, (bcnInterval-6)<<16); ++ ++ /* Beacon period and beacon enable */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PERIOD, value); ++ zfFlushDelayWrite(dev); ++} ++ ++void zfHpDisableBeacon(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ ((struct zsHpPriv*)wd->hpPrivate)->ibssBcnEnabled = 0; ++ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PERIOD, 0); ++ zfFlushDelayWrite(dev); ++} ++ ++void zfHpLedCtrl(zdev_t* dev, u16_t ledId, u8_t mode) ++{ ++ u16_t state; ++ zmw_get_wlan_dev(dev); ++ ++ //zm_debug_msg1("LED ID=", ledId); ++ //zm_debug_msg1("LED mode=", mode); ++ if (ledId < 2) ++ { ++ if (((struct zsHpPriv*)wd->hpPrivate)->ledMode[ledId] != mode) ++ { ++ ((struct zsHpPriv*)wd->hpPrivate)->ledMode[ledId] = mode; ++ ++ state = ((struct zsHpPriv*)wd->hpPrivate)->ledMode[0] ++ | (((struct zsHpPriv*)wd->hpPrivate)->ledMode[1]<<1); ++ zfDelayWriteInternalReg(dev, 0x1d0104, state); ++ zfFlushDelayWrite(dev); ++ //zm_debug_msg0("Update LED"); ++ } ++ } ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfHpResetTxRx */ ++/* Reset Tx and Rx Desc. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Chao-Wen Yang ZyDAS Technology Corporation 2007.3 */ ++/* */ ++/************************************************************************/ ++u16_t zfHpUsbReset(zdev_t* dev) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret = 0; ++ ++ //zm_debug_msg0("CWY - Reset Tx and Rx"); ++ ++ cmd[0] = 0 | (ZM_CMD_RESET << 8); ++ ++ ret = zfIssueCmd(dev, cmd, 4, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++ ++u16_t zfHpDKReset(zdev_t* dev, u8_t flag) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret = 0; ++ ++ //zm_debug_msg0("CWY - Reset Tx and Rx"); ++ ++ cmd[0] = 4 | (ZM_CMD_DKRESET << 8); ++ cmd[1] = flag; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++ ++u32_t zfHpCwmUpdate(zdev_t* dev) ++{ ++ //u32_t cmd[3]; ++ //u16_t ret; ++ // ++ //cmd[0] = 0x00000008; ++ //cmd[1] = 0x1c36e8; ++ //cmd[2] = 0x1c36ec; ++ // ++ //ret = zfIssueCmd(dev, cmd, 12, ZM_CWM_READ, 0); ++ //return ret; ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zfCoreCwmBusy(dev, zfCwmIsExtChanBusy(hpPriv->ctlBusy, hpPriv->extBusy)); ++ ++ hpPriv->ctlBusy = 0; ++ hpPriv->extBusy = 0; ++ ++ return 0; ++} ++ ++u32_t zfHpAniUpdate(zdev_t* dev) ++{ ++ u32_t cmd[5]; ++ u16_t ret; ++ ++ cmd[0] = 0x00000010; ++ cmd[1] = 0x1c36e8; ++ cmd[2] = 0x1c36ec; ++ cmd[3] = 0x1c3cb4; ++ cmd[4] = 0x1c3cb8; ++ ++ ret = zfIssueCmd(dev, cmd, 20, ZM_ANI_READ, 0); ++ return ret; ++} ++ ++/* ++ * Update Beacon RSSI in ANI ++ */ ++u32_t zfHpAniUpdateRssi(zdev_t* dev, u8_t rssi) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ hpPriv->stats.ast_nodestats.ns_avgbrssi = rssi; ++ ++ return 0; ++} ++ ++#define ZM_SEEPROM_MAC_ADDRESS_OFFSET (0x1400 + (0x106<<1)) ++#define ZM_SEEPROM_REGDOMAIN_OFFSET (0x1400 + (0x104<<1)) ++#define ZM_SEEPROM_VERISON_OFFSET (0x1400 + (0x102<<1)) ++#define ZM_SEEPROM_HARDWARE_TYPE_OFFSET (0x1374) ++#define ZM_SEEPROM_HW_HEAVY_CLIP (0x161c) ++ ++u32_t zfHpGetMacAddress(zdev_t* dev) ++{ ++ u32_t cmd[7]; ++ u16_t ret; ++ ++ cmd[0] = 0x00000000 | 24; ++ cmd[1] = ZM_SEEPROM_MAC_ADDRESS_OFFSET; ++ cmd[2] = ZM_SEEPROM_MAC_ADDRESS_OFFSET+4; ++ cmd[3] = ZM_SEEPROM_REGDOMAIN_OFFSET; ++ cmd[4] = ZM_SEEPROM_VERISON_OFFSET; ++ cmd[5] = ZM_SEEPROM_HARDWARE_TYPE_OFFSET; ++ cmd[6] = ZM_SEEPROM_HW_HEAVY_CLIP; ++ ++ ret = zfIssueCmd(dev, cmd, 28, ZM_MAC_READ, 0); ++ return ret; ++} ++ ++u32_t zfHpGetTransmitPower(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ u16_t tpc = 0; ++ ++ if (hpPriv->hwFrequency < 3000) { ++ tpc = hpPriv->tPow2x2g[0] & 0x3f; ++ wd->maxTxPower2 &= 0x3f; ++ tpc = (tpc > wd->maxTxPower2)? wd->maxTxPower2 : tpc; ++ } else { ++ tpc = hpPriv->tPow2x5g[0] & 0x3f; ++ wd->maxTxPower5 &= 0x3f; ++ tpc = (tpc > wd->maxTxPower5)? wd->maxTxPower5 : tpc; ++ } ++ ++ return tpc; ++} ++ ++u8_t zfHpGetMinTxPower(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ u8_t tpc = 0; ++ ++ if (hpPriv->hwFrequency < 3000) ++ { ++ if(wd->BandWidth40) ++ { ++ //40M ++ tpc = (hpPriv->tPow2x2gHt40[7]&0x3f); ++ } ++ else ++ { ++ //20M ++ tpc = (hpPriv->tPow2x2gHt20[7]&0x3f); ++ } ++ } ++ else ++ { ++ if(wd->BandWidth40) ++ { ++ //40M ++ tpc = (hpPriv->tPow2x5gHt40[7]&0x3f); ++ } ++ else ++ { ++ //20M ++ tpc = (hpPriv->tPow2x5gHt20[7]&0x3f); ++ } ++ } ++ ++ return tpc; ++} ++ ++u8_t zfHpGetMaxTxPower(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ u8_t tpc = 0; ++ ++ if (hpPriv->hwFrequency < 3000) ++ { ++ tpc = (hpPriv->tPow2xCck[0]&0x3f); ++ } ++ else ++ { ++ tpc =(hpPriv->tPow2x5g[0]&0x3f); ++ } ++ ++ return tpc; ++} ++ ++u32_t zfHpLoadEEPROMFromFW(zdev_t* dev) ++{ ++ u32_t cmd[16]; ++ u32_t ret=0, i, j; ++ zmw_get_wlan_dev(dev); ++ ++ i = ((struct zsHpPriv*)wd->hpPrivate)->eepromImageRdReq; ++ ++ cmd[0] = ZM_HAL_MAX_EEPROM_PRQ*4; ++ ++ for (j=0; jhpPrivate; ++ u8_t polluted = 0; ++ u8_t ackTpc; ++ ++ /* Workaround : Make OTUS fire more beacon in ad hoc mode in 2.4GHz */ ++ if (hpPriv->ibssBcnEnabled != 0) ++ { ++ if (hpPriv->hwFrequency <= ZM_CH_G_14) ++ { ++ if ((wd->tick % 10) == 0) ++ { ++ if ((wd->tick % 40) == 0) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PERIOD, hpPriv->ibssBcnInterval-1); ++ polluted = 1; ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PERIOD, hpPriv->ibssBcnInterval); ++ polluted = 1; ++ } ++ } ++ } ++ } ++ ++ if ((wd->tick & 0x3f) == 0x25) ++ { ++ /* Workaround for beacon stuck after SW reset */ ++ if (hpPriv->ibssBcnEnabled != 0) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_ADDR, ZM_BEACON_BUFFER_ADDRESS); ++ polluted = 1; ++ } ++ ++ //DbgPrint("hpPriv->aggMaxDurationBE=%d", hpPriv->aggMaxDurationBE); ++ //DbgPrint("wd->sta.avgSizeOfReceivePackets=%d", wd->sta.avgSizeOfReceivePackets); ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->sta.EnableHT == 1) //11n mode ++ && (wd->BandWidth40 == 1) //40MHz mode ++ && (wd->sta.enableDrvBA ==0) //Marvel AP ++ && (hpPriv->aggMaxDurationBE > 2000) //BE TXOP > 2ms ++ && (wd->sta.avgSizeOfReceivePackets > 1420)) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c3b9c, 0x8000a); ++ polluted = 1; ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c3b9c, hpPriv->aggPktNum); ++ polluted = 1; ++ } ++ ++ if (wd->dynamicSIFSEnable == 0) ++ { ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->sta.EnableHT == 1) //11n mode ++ && (wd->BandWidth40 == 0) //20MHz mode ++ && (wd->sta.enableDrvBA ==0)) //Marvel AP ++ { ++ zfDelayWriteInternalReg(dev, 0x1c3698, 0x5144000); ++ polluted = 1; ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c3698, 0xA144000); ++ polluted = 1; ++ } ++ } ++ else ++ { ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->sta.EnableHT == 1) //11n mode ++ && (wd->sta.athOwlAp == 1)) //Atheros AP ++ { ++ if (hpPriv->retransmissionEvent) ++ { ++ switch(hpPriv->latestSIFS) ++ { ++ case 0: ++ hpPriv->latestSIFS = 1; ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, 0x8144000); ++ break; ++ case 1: ++ hpPriv->latestSIFS = 2; ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, 0xa144000); ++ break; ++ case 2: ++ hpPriv->latestSIFS = 3; ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, 0xc144000); ++ break; ++ case 3: ++ hpPriv->latestSIFS = 0; ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, 0xa144000); ++ break; ++ default: ++ hpPriv->latestSIFS = 0; ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, 0xa144000); ++ break; ++ } ++ polluted = 1; ++ zm_debug_msg1("##### Correct Tx retransmission issue #####, ", hpPriv->latestSIFS); ++ hpPriv->retransmissionEvent = 0; ++ } ++ } ++ else ++ { ++ hpPriv->latestSIFS = 0; ++ hpPriv->retransmissionEvent = 0; ++ zfDelayWriteInternalReg(dev, 0x1c3698, 0xA144000); ++ polluted = 1; ++ } ++ } ++ ++ if ((wd->sta.bScheduleScan == FALSE) && (wd->sta.bChannelScan == FALSE)) ++ { ++#define ZM_SIGNAL_THRESHOLD 66 ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->SignalStrength > ZM_SIGNAL_THRESHOLD)) ++ { ++ /* remove state handle, always rewrite register setting */ ++ //if (hpPriv->strongRSSI == 0) ++ { ++ hpPriv->strongRSSI = 1; ++ /* Strong RSSI, set ACK to one Tx stream and lower Tx power 7dbm */ ++ if (hpPriv->currentAckRtsTpc > (14+10)) ++ { ++ ackTpc = hpPriv->currentAckRtsTpc - 14; ++ } ++ else ++ { ++ ackTpc = 10; ++ } ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((ackTpc) << 20) | (0x1<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((ackTpc) << 5 ) | (0x1<<11) | ++ ((ackTpc) << 21) | (0x1<<27) ); ++ polluted = 1; ++ } ++ } ++ else ++ { ++ /* remove state handle, always rewrite register setting */ ++ //if (hpPriv->strongRSSI == 1) ++ { ++ hpPriv->strongRSSI = 0; ++ if (hpPriv->halCapability & ZM_HP_CAP_11N_ONE_TX_STREAM) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->currentAckRtsTpc&0x3f) << 20) | (0x1<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->currentAckRtsTpc&0x3f) << 5 ) | (0x1<<11) | ++ ((hpPriv->currentAckRtsTpc&0x3f) << 21) | (0x1<<27) ); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->currentAckRtsTpc&0x3f) << 20) | (0x5<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->currentAckRtsTpc&0x3f) << 5 ) | (0x5<<11) | ++ ((hpPriv->currentAckRtsTpc&0x3f) << 21) | (0x5<<27) ); ++ } ++ polluted = 1; ++ } ++ } ++#undef ZM_SIGNAL_THRESHOLD ++ } ++ ++ if ((hpPriv->halCapability & ZM_HP_CAP_11N_ONE_TX_STREAM) == 0) ++ { ++ if ((wd->sta.bScheduleScan == FALSE) && (wd->sta.bChannelScan == FALSE)) ++ { ++ #define ZM_RX_SIGNAL_THRESHOLD_H 71 ++ #define ZM_RX_SIGNAL_THRESHOLD_L 66 ++ u8_t rxSignalThresholdH = ZM_RX_SIGNAL_THRESHOLD_H; ++ u8_t rxSignalThresholdL = ZM_RX_SIGNAL_THRESHOLD_L; ++ #undef ZM_RX_SIGNAL_THRESHOLD_H ++ #undef ZM_RX_SIGNAL_THRESHOLD_L ++ ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->SignalStrength > rxSignalThresholdH) ++ )//&& (hpPriv->rxStrongRSSI == 0)) ++ { ++ hpPriv->rxStrongRSSI = 1; ++ //zfDelayWriteInternalReg(dev, 0x1c5964, 0x1220); ++ //zfDelayWriteInternalReg(dev, 0x1c5960, 0x900); ++ //zfDelayWriteInternalReg(dev, 0x1c6960, 0x900); ++ //zfDelayWriteInternalReg(dev, 0x1c7960, 0x900); ++ if ((hpPriv->eepromImage[0x100+0x110*2/4]&0xff) == 0x80) //FEM TYPE ++ { ++ if (hpPriv->hwFrequency <= ZM_CH_G_14) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x900); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x9b49); ++ } ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x0900); ++ } ++ polluted = 1; ++ } ++ else if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->SignalStrength > rxSignalThresholdL) ++ )//&& (hpPriv->rxStrongRSSI == 1)) ++ { ++ //Do nothing to prevent frequently Rx switching ++ } ++ else ++ { ++ /* remove state handle, always rewrite register setting */ ++ //if (hpPriv->rxStrongRSSI == 1) ++ { ++ hpPriv->rxStrongRSSI = 0; ++ //zfDelayWriteInternalReg(dev, 0x1c5964, 0x1120); ++ //zfDelayWriteInternalReg(dev, 0x1c5960, 0x9b40); ++ //zfDelayWriteInternalReg(dev, 0x1c6960, 0x9b40); ++ //zfDelayWriteInternalReg(dev, 0x1c7960, 0x9b40); ++ if ((hpPriv->eepromImage[0x100+0x110*2/4]&0xff) == 0x80) //FEM TYPE ++ { ++ if (hpPriv->hwFrequency <= ZM_CH_G_14) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x9b49); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x0900); ++ } ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x9b40); ++ } ++ polluted = 1; ++ } ++ } ++ ++ } ++ } ++ ++ if (hpPriv->usbAcSendBytes[3] > (hpPriv->usbAcSendBytes[0]*2)) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_TXOP, hpPriv->txop[3]); ++ polluted = 1; ++ } ++ else if (hpPriv->usbAcSendBytes[2] > (hpPriv->usbAcSendBytes[0]*2)) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_TXOP, hpPriv->txop[2]); ++ polluted = 1; ++ } ++ else if (hpPriv->usbAcSendBytes[1] > (hpPriv->usbAcSendBytes[0]*2)) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, hpPriv->cwmin[1]+((u32_t)hpPriv->cwmax[1]<<16)); ++ polluted = 1; ++ } ++ else ++ { ++ if (hpPriv->slotType == 1) ++ { ++ if ((wd->sta.enableDrvBA ==0) //Marvel AP ++ && (hpPriv->aggMaxDurationBE > 2000)) //BE TXOP > 2ms ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, (hpPriv->cwmin[0]/2)+((u32_t)hpPriv->cwmax[0]<<16)); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, hpPriv->cwmin[0]+((u32_t)hpPriv->cwmax[0]<<16)); ++ } ++ polluted = 1; ++ } ++ else ++ { ++ /* Compensation for 20us slot time */ ++ //zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, 58+((u32_t)hpPriv->cwmax[0]<<16)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC0_CW, hpPriv->cwmin[0]+((u32_t)hpPriv->cwmax[0]<<16)); ++ polluted = 1; ++ } ++ ++ if ((wd->sta.SWEncryptEnable & (ZM_SW_TKIP_ENCRY_EN|ZM_SW_WEP_ENCRY_EN)) == 0) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_TXOP, hpPriv->txop[0]); ++ polluted = 1; ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_AC1_AC0_TXOP, 0x30); ++ polluted = 1; ++ } ++ ++ } ++ hpPriv->usbAcSendBytes[3] = 0; ++ hpPriv->usbAcSendBytes[2] = 0; ++ hpPriv->usbAcSendBytes[1] = 0; ++ hpPriv->usbAcSendBytes[0] = 0; ++ } ++ ++ if (polluted == 1) ++ { ++ zfFlushDelayWrite(dev); ++ } ++ ++ return; ++} ++ ++/* ++ * 0x1d4008 : AHB, DAC, ADC clock selection ++ * bit1~0 AHB_CLK : AHB clock selection, ++ * 00 : OSC 40MHz; ++ * 01 : 20MHz in A mode, 22MHz in G mode; ++ * 10 : 40MHz in A mode, 44MHz in G mode; ++ * 11 : 80MHz in A mode, 88MHz in G mode. ++ * bit3~2 CLK_SEL : Select the clock source of clk160 in ADDAC. ++ * 00 : PLL divider's output; ++ * 01 : PLL divider's output divided by 2; ++ * 10 : PLL divider's output divided by 4; ++ * 11 : REFCLK from XTALOSCPAD. ++ */ ++void zfSelAdcClk(zdev_t* dev, u8_t bw40, u32_t frequency) ++{ ++ if(bw40 == 1) ++ { ++ //zfDelayWriteInternalReg(dev, 0x1D4008, 0x73); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_DYNAMIC_SIFS_ACK, 0x10A); ++ zfFlushDelayWrite(dev); ++ } ++ else ++ { ++ //zfDelayWriteInternalReg(dev, 0x1D4008, 0x70); ++ if ( frequency <= ZM_CH_G_14 ) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_DYNAMIC_SIFS_ACK, 0x105); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_DYNAMIC_SIFS_ACK, 0x104); ++ } ++ zfFlushDelayWrite(dev); ++ } ++} ++ ++u32_t zfHpEchoCommand(zdev_t* dev, u32_t value) ++{ ++ u32_t cmd[2]; ++ u16_t ret; ++ ++ cmd[0] = 0x00008004; ++ cmd[1] = value; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_CMD_ECHO, NULL); ++ return ret; ++} ++ ++#ifdef ZM_DRV_INIT_USB_MODE ++ ++#define ZM_USB_US_STREAM_MODE 0x00000000 ++#define ZM_USB_US_PACKET_MODE 0x00000008 ++#define ZM_USB_DS_ENABLE 0x00000001 ++#define ZM_USB_US_ENABLE 0x00000002 ++ ++#define ZM_USB_RX_STREAM_4K 0x00000000 ++#define ZM_USB_RX_STREAM_8K 0x00000010 ++#define ZM_USB_RX_STREAM_16K 0x00000020 ++#define ZM_USB_RX_STREAM_32K 0x00000030 ++ ++#define ZM_USB_TX_STREAM_MODE 0x00000040 ++ ++#define ZM_USB_MODE_CTRL_REG 0x001E1108 ++ ++void zfInitUsbMode(zdev_t* dev) ++{ ++ u32_t mode; ++ zmw_get_wlan_dev(dev); ++ ++ /* TODO: Set USB mode by reading registery */ ++ mode = ZM_USB_DS_ENABLE | ZM_USB_US_ENABLE | ZM_USB_US_PACKET_MODE; ++ ++ zfDelayWriteInternalReg(dev, ZM_USB_MODE_CTRL_REG, mode); ++ zfFlushDelayWrite(dev); ++} ++#endif ++ ++void zfDumpEepBandEdges(struct ar5416Eeprom* eepromImage); ++void zfPrintTargetPower2G(u8_t* tPow2xCck, u8_t* tPow2x2g, u8_t* tPow2x2gHt20, u8_t* tPow2x2gHt40); ++void zfPrintTargetPower5G(u8_t* tPow2x5g, u8_t* tPow2x5gHt20, u8_t* tPow2x5gHt40); ++ ++ ++s32_t zfInterpolateFunc(s32_t x, s32_t x1, s32_t y1, s32_t x2, s32_t y2) ++{ ++ s32_t y; ++ ++ if (y2 == y1) ++ { ++ y = y1; ++ } ++ else if (x == x1) ++ { ++ y = y1; ++ } ++ else if (x == x2) ++ { ++ y = y2; ++ } ++ else if (x2 != x1) ++ { ++ y = y1 + (((y2-y1) * (x-x1))/(x2-x1)); ++ } ++ else ++ { ++ y = y1; ++ } ++ ++ return y; ++} ++ ++//#define ZM_ENABLE_TPC_WINDOWS_DEBUG ++//#define ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ ++/* the tx power offset workaround for ART vs NDIS/MDK */ ++#define HALTX_POWER_OFFSET 0 ++ ++u8_t zfInterpolateFuncX(u8_t x, u8_t x1, u8_t y1, u8_t x2, u8_t y2) ++{ ++ s32_t y; ++ s32_t inc; ++ ++ #define ZM_MULTIPLIER 8 ++ y = zfInterpolateFunc((s32_t)x<> (ZM_MULTIPLIER-1); ++ y = (y >> ZM_MULTIPLIER) + inc; ++ #undef ZM_MULTIPLIER ++ ++ return (u8_t)y; ++} ++ ++u8_t zfGetInterpolatedValue(u8_t x, u8_t* x_array, u8_t* y_array) ++{ ++ s32_t y; ++ u16_t xIndex; ++ ++ if (x <= x_array[1]) ++ { ++ xIndex = 0; ++ } ++ else if (x <= x_array[2]) ++ { ++ xIndex = 1; ++ } ++ else if (x <= x_array[3]) ++ { ++ xIndex = 2; ++ } ++ else //(x > x_array[3]) ++ { ++ xIndex = 3; ++ } ++ ++ y = zfInterpolateFuncX(x, ++ x_array[xIndex], ++ y_array[xIndex], ++ x_array[xIndex+1], ++ y_array[xIndex+1]); ++ ++ return (u8_t)y; ++} ++ ++u8_t zfFindFreqIndex(u8_t f, u8_t* fArray, u8_t fArraySize) ++{ ++ u8_t i; ++#ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("f=%d ", f); ++ for (i=0; i= fArray[i]) ++ { ++ return i; ++ } ++ if (i!=0) ++ { ++ i--; ++ } ++ else ++ { ++ return 0; ++ } ++ } ++} ++ ++ ++ ++ ++void zfInitPowerCal(zdev_t* dev) ++{ ++ //Program PHY Tx power relatives registers ++#define zm_write_phy_reg(cr, val) reg_write((cr*4)+0x9800, val) ++ ++ zm_write_phy_reg(79, 0x7f); ++ zm_write_phy_reg(77, 0x3f3f3f3f); ++ zm_write_phy_reg(78, 0x3f3f3f3f); ++ zm_write_phy_reg(653, 0x3f3f3f3f); ++ zm_write_phy_reg(654, 0x3f3f3f3f); ++ zm_write_phy_reg(739, 0x3f3f3f3f); ++ zm_write_phy_reg(740, 0x3f3f3f3f); ++ zm_write_phy_reg(755, 0x3f3f3f3f); ++ zm_write_phy_reg(756, 0x3f3f3f3f); ++ zm_write_phy_reg(757, 0x3f3f3f3f); ++ ++#undef zm_write_phy_reg ++} ++ ++ ++ ++void zfPrintTp(u8_t* pwr0, u8_t* vpd0, u8_t* pwr1, u8_t* vpd1) ++{ ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("pwr0 : %d, %d, %d, %d ,%d\n", pwr0[0], pwr0[1], pwr0[2], pwr0[3], pwr0[4]); ++ DbgPrint("vpd0 : %d, %d, %d, %d ,%d\n", vpd0[0], vpd0[1], vpd0[2], vpd0[3], vpd0[4]); ++ DbgPrint("pwr1 : %d, %d, %d, %d ,%d\n", pwr1[0], pwr1[1], pwr1[2], pwr1[3], pwr1[4]); ++ DbgPrint("vpd1 : %d, %d, %d, %d ,%d\n", vpd1[0], vpd1[1], vpd1[2], vpd1[3], vpd1[4]); ++ #endif ++} ++ ++ ++/* ++ * To find CTL index(0~23) ++ * return 24(AR5416_NUM_CTLS)=>no desired index found ++ */ ++u8_t zfFindCtlEdgesIndex(zdev_t* dev, u8_t desired_CtlIndex) ++{ ++ u8_t i; ++ struct zsHpPriv* hpPriv; ++ struct ar5416Eeprom* eepromImage; ++ ++ zmw_get_wlan_dev(dev); ++ ++ hpPriv = wd->hpPrivate; ++ ++ eepromImage = (struct ar5416Eeprom*)&(hpPriv->eepromImage[(1024+512)/4]); ++ ++ //for (i = 0; (i < AR5416_NUM_CTLS) && eepromImage->ctlIndex[i]; i++) ++ for (i = 0; i < AR5416_NUM_CTLS; i++) ++ { ++ if(desired_CtlIndex == eepromImage->ctlIndex[i]) ++ break; ++ } ++ return i; ++} ++ ++/************************************************************************** ++ * fbin2freq ++ * ++ * Get channel value from binary representation held in eeprom ++ * RETURNS: the frequency in MHz ++ */ ++u32_t ++fbin2freq(u8_t fbin, u8_t is2GHz) ++{ ++ /* ++ * Reserved value 0xFF provides an empty definition both as ++ * an fbin and as a frequency - do not convert ++ */ ++ if (fbin == AR5416_BCHAN_UNUSED) { ++ return fbin; ++ } ++ ++ return (u32_t)((is2GHz==1) ? (2300 + fbin) : (4800 + 5 * fbin)); ++} ++ ++ ++u8_t zfGetMaxEdgePower(zdev_t* dev, CAL_CTL_EDGES *pCtlEdges, u32_t freq) ++{ ++ u8_t i; ++ u8_t maxEdgePower; ++ u8_t is2GHz; ++ struct zsHpPriv* hpPriv; ++ struct ar5416Eeprom* eepromImage; ++ ++ zmw_get_wlan_dev(dev); ++ ++ hpPriv = wd->hpPrivate; ++ ++ eepromImage = (struct ar5416Eeprom*)&(hpPriv->eepromImage[(1024+512)/4]); ++ ++ if(freq > ZM_CH_G_14) ++ is2GHz = 0; ++ else ++ is2GHz = 1; ++ ++ maxEdgePower = AR5416_MAX_RATE_POWER; ++ ++ /* Get the edge power */ ++ for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pCtlEdges[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) ++ { ++ /* ++ * If there's an exact channel match or an inband flag set ++ * on the lower channel use the given rdEdgePower ++ */ ++ if (freq == fbin2freq(pCtlEdges[i].bChannel, is2GHz)) ++ { ++ maxEdgePower = pCtlEdges[i].tPower; ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("zfGetMaxEdgePower index i = %d \n", i)); ++ #endif ++ break; ++ } ++ else if ((i > 0) && (freq < fbin2freq(pCtlEdges[i].bChannel, is2GHz))) ++ { ++ if (fbin2freq(pCtlEdges[i - 1].bChannel, is2GHz) < freq && pCtlEdges[i - 1].flag) ++ { ++ maxEdgePower = pCtlEdges[i - 1].tPower; ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("zfGetMaxEdgePower index i-1 = %d \n", i-1)); ++ #endif ++ } ++ /* Leave loop - no more affecting edges possible in this monotonic increasing list */ ++ break; ++ } ++ ++ } ++ ++ if( i == AR5416_NUM_BAND_EDGES ) ++ { ++ if (freq > fbin2freq(pCtlEdges[i - 1].bChannel, is2GHz) && pCtlEdges[i - 1].flag) ++ { ++ maxEdgePower = pCtlEdges[i - 1].tPower; ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("zfGetMaxEdgePower index=>i-1 = %d \n", i-1)); ++ #endif ++ } ++ } ++ ++ zm_assert(maxEdgePower > 0); ++ ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ if ( maxEdgePower == AR5416_MAX_RATE_POWER ) ++ { ++ zm_dbg(("zfGetMaxEdgePower = %d !!!\n", AR5416_MAX_RATE_POWER)); ++ } ++ #endif ++ return maxEdgePower; ++} ++ ++u32_t zfAdjustHT40FreqOffset(zdev_t* dev, u32_t frequency, u8_t bw40, u8_t extOffset) ++{ ++ u32_t newFreq = frequency; ++ ++ if (bw40 == 1) ++ { ++ if (extOffset == 1) ++ { ++ newFreq += 10; ++ } ++ else ++ { ++ newFreq -= 10; ++ } ++ } ++ return newFreq; ++} ++ ++u32_t zfHpCheckDoHeavyClip(zdev_t* dev, u32_t freq, CAL_CTL_EDGES *pCtlEdges, u8_t bw40) ++{ ++ u32_t ret = 0; ++ u8_t i; ++ u8_t is2GHz; ++ struct zsHpPriv* hpPriv; ++ ++ zmw_get_wlan_dev(dev); ++ ++ hpPriv = wd->hpPrivate; ++ ++ if(freq > ZM_CH_G_14) ++ is2GHz = 0; ++ else ++ is2GHz = 1; ++ ++ /* HT40 force enable heavy clip */ ++ if (bw40) ++ { ++ ret |= 0xf0; ++ } ++#if 1 ++ /* HT20 : frequency bandedge */ ++ for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pCtlEdges[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) ++ { ++ if (freq == fbin2freq(pCtlEdges[i].bChannel, is2GHz)) ++ { ++ if (pCtlEdges[i].flag == 0) ++ { ++ ret |= 0xf; ++ } ++ break; ++ } ++ } ++#endif ++ ++ return ret; ++} ++ ++ ++void zfSetPowerCalTable(zdev_t* dev, u32_t frequency, u8_t bw40, u8_t extOffset) ++{ ++ struct ar5416Eeprom* eepromImage; ++ u8_t pwr0[5]; ++ u8_t pwr1[5]; ++ u8_t vpd0[5]; ++ u8_t vpd1[5]; ++ u8_t vpd_chain1[128]; ++ u8_t vpd_chain3[128]; ++ u16_t boundary1 = 18; //CR 667 ++ u16_t powerTxMax = 63; //CR 79 ++ u8_t i; ++ struct zsHpPriv* hpPriv; ++ u8_t fbin; ++ u8_t index, max2gIndex, max5gIndex; ++ u8_t chain0pwrPdg0[5]; ++ u8_t chain0vpdPdg0[5]; ++ u8_t chain0pwrPdg1[5]; ++ u8_t chain0vpdPdg1[5]; ++ u8_t chain2pwrPdg0[5]; ++ u8_t chain2vpdPdg0[5]; ++ u8_t chain2pwrPdg1[5]; ++ u8_t chain2vpdPdg1[5]; ++ u8_t fbinArray[8]; ++ ++ /* 4 CTL */ ++ u8_t ctl_i; ++ u8_t desired_CtlIndex; ++ ++ u8_t ctlEdgesMaxPowerCCK = AR5416_MAX_RATE_POWER; ++ u8_t ctlEdgesMaxPower2G = AR5416_MAX_RATE_POWER; ++ u8_t ctlEdgesMaxPower2GHT20 = AR5416_MAX_RATE_POWER; ++ u8_t ctlEdgesMaxPower2GHT40 = AR5416_MAX_RATE_POWER; ++ u8_t ctlEdgesMaxPower5G = AR5416_MAX_RATE_POWER; ++ u8_t ctlEdgesMaxPower5GHT20 = AR5416_MAX_RATE_POWER; ++ u8_t ctlEdgesMaxPower5GHT40 = AR5416_MAX_RATE_POWER; ++ ++ u8_t ctlOffset; ++ ++ zmw_get_wlan_dev(dev); ++ ++ hpPriv = wd->hpPrivate; ++ ++ eepromImage = (struct ar5416Eeprom*)&(hpPriv->eepromImage[(1024+512)/4]); ++ ++ // Check the total bytes of the EEPROM structure to see the dongle have been calibrated or not. ++ if (eepromImage->baseEepHeader.length == 0xffff) ++ { ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("Warning! This dongle not been calibrated\n")); ++ #endif ++ return; ++ } ++ ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("-----zfSetPowerCalTable : frequency=%d-----\n", frequency); ++ #endif ++ /* TODO : 1. boundary1 and powerTxMax should be refered to CR667 and CR79 */ ++ /* in otus.ini file */ ++ ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ /* 2. Interpolate pwr and vpd test points from frequency */ ++ DbgPrint("calFreqPier5G : %d, %d, %d, %d ,%d, %d, %d, %d\n", ++ eepromImage->calFreqPier5G[0]*5+4800, ++ eepromImage->calFreqPier5G[1]*5+4800, ++ eepromImage->calFreqPier5G[2]*5+4800, ++ eepromImage->calFreqPier5G[3]*5+4800, ++ eepromImage->calFreqPier5G[4]*5+4800, ++ eepromImage->calFreqPier5G[5]*5+4800, ++ eepromImage->calFreqPier5G[6]*5+4800, ++ eepromImage->calFreqPier5G[7]*5+4800 ++ ); ++ DbgPrint("calFreqPier2G : %d, %d, %d, %d\n", ++ eepromImage->calFreqPier2G[0]+2300, ++ eepromImage->calFreqPier2G[1]+2300, ++ eepromImage->calFreqPier2G[2]+2300, ++ eepromImage->calFreqPier2G[3]+2300 ++ ); ++ #endif ++ if (frequency < 3000) ++ { ++ for (i=0; i<4; i++) ++ { ++ if (eepromImage->calFreqPier2G[i] == 0xff) ++ { ++ break; ++ } ++ } ++ max2gIndex = i; ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("max2gIndex : %d\n", max2gIndex); ++ #endif ++ fbin = (u8_t)(frequency - 2300); ++ index = zfFindFreqIndex(fbin, eepromImage->calFreqPier2G, max2gIndex); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("2G index : %d\n", index); ++ DbgPrint("chain 0 index\n"); ++ #endif ++ zfPrintTp(&eepromImage->calPierData2G[0][index].pwrPdg[0][0], ++ &eepromImage->calPierData2G[0][index].vpdPdg[0][0], ++ &eepromImage->calPierData2G[0][index].pwrPdg[1][0], ++ &eepromImage->calPierData2G[0][index].vpdPdg[1][0] ++ ); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("chain 0 index+1\n"); ++ #endif ++ zfPrintTp(&eepromImage->calPierData2G[0][index+1].pwrPdg[0][0], ++ &eepromImage->calPierData2G[0][index+1].vpdPdg[0][0], ++ &eepromImage->calPierData2G[0][index+1].pwrPdg[1][0], ++ &eepromImage->calPierData2G[0][index+1].vpdPdg[1][0] ++ ); ++ ++ for (i=0; i<5; i++) ++ { ++ chain0pwrPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[0][index].pwrPdg[0][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[0][index+1].pwrPdg[0][i] ++ ); ++ chain0vpdPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[0][index].vpdPdg[0][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[0][index+1].vpdPdg[0][i] ++ ); ++ chain0pwrPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[0][index].pwrPdg[1][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[0][index+1].pwrPdg[1][i] ++ ); ++ chain0vpdPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[0][index].vpdPdg[1][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[0][index+1].vpdPdg[1][i] ++ ); ++ ++ chain2pwrPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[1][index].pwrPdg[0][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[1][index+1].pwrPdg[0][i] ++ ); ++ chain2vpdPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[1][index].vpdPdg[0][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[1][index+1].vpdPdg[0][i] ++ ); ++ chain2pwrPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[1][index].pwrPdg[1][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[1][index+1].pwrPdg[1][i] ++ ); ++ chain2vpdPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier2G[index], ++ eepromImage->calPierData2G[1][index].vpdPdg[1][i], ++ eepromImage->calFreqPier2G[index+1], ++ eepromImage->calPierData2G[1][index+1].vpdPdg[1][i] ++ ); ++ } ++ } ++ else ++ { ++ for (i=0; i<8; i++) ++ { ++ if (eepromImage->calFreqPier5G[i] == 0xff) ++ { ++ break; ++ } ++ } ++ max5gIndex = i; ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("max5gIndex : %d\n", max5gIndex); ++ #endif ++ fbin = (u8_t)((frequency - 4800)/5); ++ index = zfFindFreqIndex(fbin, eepromImage->calFreqPier5G, max5gIndex); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("5G index : %d\n", index); ++ #endif ++ ++ for (i=0; i<5; i++) ++ { ++ chain0pwrPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[0][index].pwrPdg[0][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[0][index+1].pwrPdg[0][i] ++ ); ++ chain0vpdPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[0][index].vpdPdg[0][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[0][index+1].vpdPdg[0][i] ++ ); ++ chain0pwrPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[0][index].pwrPdg[1][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[0][index+1].pwrPdg[1][i] ++ ); ++ chain0vpdPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[0][index].vpdPdg[1][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[0][index+1].vpdPdg[1][i] ++ ); ++ ++ chain2pwrPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[1][index].pwrPdg[0][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[1][index+1].pwrPdg[0][i] ++ ); ++ chain2vpdPdg0[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[1][index].vpdPdg[0][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[1][index+1].vpdPdg[0][i] ++ ); ++ chain2pwrPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[1][index].pwrPdg[1][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[1][index+1].pwrPdg[1][i] ++ ); ++ chain2vpdPdg1[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calFreqPier5G[index], ++ eepromImage->calPierData5G[1][index].vpdPdg[1][i], ++ eepromImage->calFreqPier5G[index+1], ++ eepromImage->calPierData5G[1][index+1].vpdPdg[1][i] ++ ); ++ } ++ ++ } ++ ++ ++ /* Chain 1 */ ++ /* Get pwr and vpd test points from frequency */ ++ for (i=0; i<5; i++) ++ { ++ pwr0[i] = chain0pwrPdg0[i]>>1; ++ vpd0[i] = chain0vpdPdg0[i]; ++ pwr1[i] = chain0pwrPdg1[i]>>1; ++ vpd1[i] = chain0vpdPdg1[i]; ++ } ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("Test Points\n"); ++ DbgPrint("pwr0 : %d, %d, %d, %d ,%d\n", pwr0[0], pwr0[1], pwr0[2], pwr0[3], pwr0[4]); ++ DbgPrint("vpd0 : %d, %d, %d, %d ,%d\n", vpd0[0], vpd0[1], vpd0[2], vpd0[3], vpd0[4]); ++ DbgPrint("pwr1 : %d, %d, %d, %d ,%d\n", pwr1[0], pwr1[1], pwr1[2], pwr1[3], pwr1[4]); ++ DbgPrint("vpd1 : %d, %d, %d, %d ,%d\n", vpd1[0], vpd1[1], vpd1[2], vpd1[3], vpd1[4]); ++ #endif ++ /* Generate the vpd arrays */ ++ for (i=0; i>1; ++ vpd0[i] = chain2vpdPdg0[i]; ++ pwr1[i] = chain2pwrPdg1[i]>>1; ++ vpd1[i] = chain2vpdPdg1[i]; ++ } ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("Test Points\n"); ++ DbgPrint("pwr0 : %d, %d, %d, %d ,%d\n", pwr0[0], pwr0[1], pwr0[2], pwr0[3], pwr0[4]); ++ DbgPrint("vpd0 : %d, %d, %d, %d ,%d\n", vpd0[0], vpd0[1], vpd0[2], vpd0[3], vpd0[4]); ++ DbgPrint("pwr1 : %d, %d, %d, %d ,%d\n", pwr1[0], pwr1[1], pwr1[2], pwr1[3], pwr1[4]); ++ DbgPrint("vpd1 : %d, %d, %d, %d ,%d\n", vpd1[0], vpd1[1], vpd1[2], vpd1[3], vpd1[4]); ++ #endif ++ /* Generate the vpd arrays */ ++ for (i=0; icalTargetPowerCck[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPowerCck[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex(fbin, fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("CCK index=%d\n", index); ++ #endif ++ for (i=0; i<4; i++) ++ { ++ hpPriv->tPow2xCck[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calTargetPowerCck[index].bChannel, ++ eepromImage->calTargetPowerCck[index].tPow2x[i], ++ eepromImage->calTargetPowerCck[index+1].bChannel, ++ eepromImage->calTargetPowerCck[index+1].tPow2x[i] ++ ); ++ } ++ ++ for (i=0; i<4; i++) ++ { ++ if (eepromImage->calTargetPower2G[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPower2G[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex(fbin, fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("2G index=%d\n", index); ++ #endif ++ for (i=0; i<4; i++) ++ { ++ hpPriv->tPow2x2g[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calTargetPower2G[index].bChannel, ++ eepromImage->calTargetPower2G[index].tPow2x[i], ++ eepromImage->calTargetPower2G[index+1].bChannel, ++ eepromImage->calTargetPower2G[index+1].tPow2x[i] ++ ); ++ } ++ ++ for (i=0; i<4; i++) ++ { ++ if (eepromImage->calTargetPower2GHT20[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPower2GHT20[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex(fbin, fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("2G HT20 index=%d\n", index); ++ #endif ++ for (i=0; i<8; i++) ++ { ++ hpPriv->tPow2x2gHt20[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calTargetPower2GHT20[index].bChannel, ++ eepromImage->calTargetPower2GHT20[index].tPow2x[i], ++ eepromImage->calTargetPower2GHT20[index+1].bChannel, ++ eepromImage->calTargetPower2GHT20[index+1].tPow2x[i] ++ ); ++ } ++ ++ for (i=0; i<4; i++) ++ { ++ if (eepromImage->calTargetPower2GHT40[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPower2GHT40[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex( (u8_t)zfAdjustHT40FreqOffset(dev, fbin, bw40, extOffset), fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("2G HT40 index=%d\n", index); ++ #endif ++ for (i=0; i<8; i++) ++ { ++ hpPriv->tPow2x2gHt40[i] = zfInterpolateFuncX( ++ (u8_t)zfAdjustHT40FreqOffset(dev, fbin, bw40, extOffset), ++ eepromImage->calTargetPower2GHT40[index].bChannel, ++ eepromImage->calTargetPower2GHT40[index].tPow2x[i], ++ eepromImage->calTargetPower2GHT40[index+1].bChannel, ++ eepromImage->calTargetPower2GHT40[index+1].tPow2x[i] ++ ); ++ } ++ ++ zfPrintTargetPower2G(hpPriv->tPow2xCck, ++ hpPriv->tPow2x2g, ++ hpPriv->tPow2x2gHt20, ++ hpPriv->tPow2x2gHt40); ++ } ++ else ++ { ++ /* 5G */ ++ for (i=0; i<8; i++) ++ { ++ if (eepromImage->calTargetPower5G[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPower5G[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex(fbin, fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("5G index=%d\n", index); ++ #endif ++ for (i=0; i<4; i++) ++ { ++ hpPriv->tPow2x5g[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calTargetPower5G[index].bChannel, ++ eepromImage->calTargetPower5G[index].tPow2x[i], ++ eepromImage->calTargetPower5G[index+1].bChannel, ++ eepromImage->calTargetPower5G[index+1].tPow2x[i] ++ ); ++ } ++ ++ for (i=0; i<8; i++) ++ { ++ if (eepromImage->calTargetPower5GHT20[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPower5GHT20[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex(fbin, fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("5G HT20 index=%d\n", index); ++ #endif ++ for (i=0; i<8; i++) ++ { ++ hpPriv->tPow2x5gHt20[i] = zfInterpolateFuncX(fbin, ++ eepromImage->calTargetPower5GHT20[index].bChannel, ++ eepromImage->calTargetPower5GHT20[index].tPow2x[i], ++ eepromImage->calTargetPower5GHT20[index+1].bChannel, ++ eepromImage->calTargetPower5GHT20[index+1].tPow2x[i] ++ ); ++ } ++ ++ for (i=0; i<8; i++) ++ { ++ if (eepromImage->calTargetPower5GHT40[i].bChannel != 0xff) ++ { ++ fbinArray[i] = eepromImage->calTargetPower5GHT40[i].bChannel; ++ } ++ else ++ { ++ break; ++ } ++ ++ } ++ index = zfFindFreqIndex((u8_t)zfAdjustHT40FreqOffset(dev, fbin, bw40, extOffset), fbinArray, i); ++ #ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ DbgPrint("5G HT40 index=%d\n", index); ++ #endif ++ for (i=0; i<8; i++) ++ { ++ hpPriv->tPow2x5gHt40[i] = zfInterpolateFuncX( ++ (u8_t)zfAdjustHT40FreqOffset(dev, fbin, bw40, extOffset), ++ eepromImage->calTargetPower5GHT40[index].bChannel, ++ eepromImage->calTargetPower5GHT40[index].tPow2x[i], ++ eepromImage->calTargetPower5GHT40[index+1].bChannel, ++ eepromImage->calTargetPower5GHT40[index+1].tPow2x[i] ++ ); ++ } ++ ++ zfPrintTargetPower5G( ++ hpPriv->tPow2x5g, ++ hpPriv->tPow2x5gHt20, ++ hpPriv->tPow2x5gHt40); ++ } ++ ++ ++ ++ /* 4. CTL */ ++ /* ++ * 4.1 Get the bandedges tx power by frequency ++ * 2.4G we get ctlEdgesMaxPowerCCK ++ * ctlEdgesMaxPower2G ++ * ctlEdgesMaxPower2GHT20 ++ * ctlEdgesMaxPower2GHT40 ++ * 5G we get ctlEdgesMaxPower5G ++ * ctlEdgesMaxPower5GHT20 ++ * ctlEdgesMaxPower5GHT40 ++ * 4.2 Update (3.) target power table by 4.1 ++ * 4.3 Tx power offset for ART - NDIS/MDK ++ * 4.4 Write MAC reg 0x694 for ACK's TPC ++ * ++ */ ++ ++ //zfDumpEepBandEdges(eepromImage); ++ ++ /* get the cfg from Eeprom: regionCode => RegulatoryDomain : 0x10-FFC 0x30-eu 0x40-jap */ ++ desired_CtlIndex = zfHpGetRegulatoryDomain(dev); ++ if ((desired_CtlIndex == 0x30) || (desired_CtlIndex == 0x40) || (desired_CtlIndex == 0x0)) ++ { ++ /* skip CTL and heavy clip */ ++ hpPriv->enableBBHeavyClip = 0; ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("RegulatoryDomain = 0, skip CTL and heavy clip\n")); ++ #endif ++ } ++ else ++ { ++ hpPriv->enableBBHeavyClip = 1; ++ ++ if (desired_CtlIndex == 0xff) ++ { ++ /* desired index not found */ ++ desired_CtlIndex = 0x10; ++ } ++ ++ /* first part : 2.4G */ ++ if (frequency <= ZM_CH_G_14) ++ { ++ /* 2.4G - CTL_11B */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_11B); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], frequency); ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_11B ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ /* 2.4G - CTL_11G */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_11G); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], frequency); ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_11G ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ /* 2.4G - CTL_2GHT20 */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_2GHT20); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], frequency); ++ } ++ else ++ { ++ /* workaround for no data in Eeprom, replace by normal 2G */ ++ ctlEdgesMaxPower2GHT20 = ctlEdgesMaxPower2G; ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_2GHT20 ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ /* 2.4G - CTL_2GHT40 */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_2GHT40); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], ++ zfAdjustHT40FreqOffset(dev, frequency, bw40, extOffset)); ++ } ++ else ++ { ++ /* workaround for no data in Eeprom, replace by normal 2G */ ++ ctlEdgesMaxPower2GHT40 = ctlEdgesMaxPower2G; ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_2GHT40 ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ ++ /* 7a17 : */ ++ /* Max power (dBm) for channel range when using DFS define by madwifi*/ ++ for (i=0; iregulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel == frequency) ++ { ++ if (zfHpIsDfsChannel(dev, (u16_t)frequency)) ++ { ++ zm_debug_msg1("frequency use DFS -- ", frequency); ++ ctlEdgesMaxPowerCCK = zm_min(ctlEdgesMaxPowerCCK, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ ctlEdgesMaxPower2G = zm_min(ctlEdgesMaxPower2G, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ ctlEdgesMaxPower2GHT20 = zm_min(ctlEdgesMaxPower2GHT20, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ ctlEdgesMaxPower2GHT40 = zm_min(ctlEdgesMaxPower2GHT40, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ } ++ break; ++ } ++ } ++ ++ /* Apply ctl mode to correct target power set */ ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_debug_msg1("ctlEdgesMaxPowerCCK = ", ctlEdgesMaxPowerCCK); ++ zm_debug_msg1("ctlEdgesMaxPower2G = ", ctlEdgesMaxPower2G); ++ zm_debug_msg1("ctlEdgesMaxPower2GHT20 = ", ctlEdgesMaxPower2GHT20); ++ zm_debug_msg1("ctlEdgesMaxPower2GHT40 = ", ctlEdgesMaxPower2GHT40); ++ #endif ++ for (i=0; i<4; i++) ++ { ++ hpPriv->tPow2xCck[i] = zm_min(hpPriv->tPow2xCck[i], ctlEdgesMaxPowerCCK) + HALTX_POWER_OFFSET; ++ } ++ hpPriv->tPow2x2g24HeavyClipOffset = 0; ++ if (hpPriv->enableBBHeavyClip) ++ { ++ ctlOffset = 2; ++ } ++ else ++ { ++ ctlOffset = 0; ++ } ++ for (i=0; i<4; i++) ++ { ++ if (((frequency == 2412) || (frequency == 2462))) ++ { ++ if (i != 0) ++ { ++ hpPriv->tPow2x2g[i] = zm_min(hpPriv->tPow2x2g[i], ctlEdgesMaxPower2G-ctlOffset) + HALTX_POWER_OFFSET; ++ } ++ else ++ { ++ hpPriv->tPow2x2g[i] = zm_min(hpPriv->tPow2x2g[i], ctlEdgesMaxPower2G) + HALTX_POWER_OFFSET; ++ if (hpPriv->tPow2x2g[i] > (ctlEdgesMaxPower2G-ctlOffset)) ++ { ++ hpPriv->tPow2x2g24HeavyClipOffset = hpPriv->tPow2x2g[i] - (ctlEdgesMaxPower2G-ctlOffset); ++ } ++ } ++ } ++ else ++ { ++ hpPriv->tPow2x2g[i] = zm_min(hpPriv->tPow2x2g[i], ctlEdgesMaxPower2G) + HALTX_POWER_OFFSET; ++ } ++ } ++ for (i=0; i<8; i++) ++ { ++ if (((frequency == 2412) || (frequency == 2462)) && (i>=3)) ++ { ++ hpPriv->tPow2x2gHt20[i] = zm_min(hpPriv->tPow2x2gHt20[i], ctlEdgesMaxPower2GHT20-ctlOffset) + HALTX_POWER_OFFSET; ++ } ++ else ++ { ++ hpPriv->tPow2x2gHt20[i] = zm_min(hpPriv->tPow2x2gHt20[i], ctlEdgesMaxPower2GHT20) + HALTX_POWER_OFFSET; ++ } ++ } ++ for (i=0; i<8; i++) ++ { ++ if ((frequency == 2412) && (i>=3)) ++ { ++ hpPriv->tPow2x2gHt40[i] = zm_min(hpPriv->tPow2x2gHt40[i], ctlEdgesMaxPower2GHT40-ctlOffset) + HALTX_POWER_OFFSET; ++ } ++ else if ((frequency == 2462) && (i>=3)) ++ { ++ hpPriv->tPow2x2gHt40[i] = zm_min(hpPriv->tPow2x2gHt40[i], ctlEdgesMaxPower2GHT40-(ctlOffset*2)) + HALTX_POWER_OFFSET; ++ } ++ else ++ { ++ hpPriv->tPow2x2gHt40[i] = zm_min(hpPriv->tPow2x2gHt40[i], ctlEdgesMaxPower2GHT40) + HALTX_POWER_OFFSET; ++ } ++ } ++ } ++ else ++ { ++ /* 5G - CTL_11A */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_11A); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], frequency); ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_11A ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ /* 5G - CTL_5GHT20 */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_5GHT20); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], frequency); ++ } ++ else ++ { ++ /* workaround for no data in Eeprom, replace by normal 5G */ ++ ctlEdgesMaxPower5GHT20 = ctlEdgesMaxPower5G; ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_5GHT20 ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ /* 5G - CTL_5GHT40 */ ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_5GHT40); ++ if(ctl_ictlData[ctl_i].ctlEdges[1], ++ zfAdjustHT40FreqOffset(dev, frequency, bw40, extOffset)); ++ } ++ else ++ { ++ /* workaround for no data in Eeprom, replace by normal 5G */ ++ ctlEdgesMaxPower5GHT40 = ctlEdgesMaxPower5G; ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("CTL_5GHT40 ctl_i = %d\n", ctl_i)); ++ #endif ++ ++ /* 7a17 : */ ++ /* Max power (dBm) for channel range when using DFS define by madwifi*/ ++ for (i=0; iregulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel == frequency) ++ { ++ if (zfHpIsDfsChannel(dev, (u16_t)frequency)) ++ { ++ zm_debug_msg1("frequency use DFS -- ", frequency); ++ ctlEdgesMaxPower5G = zm_min(ctlEdgesMaxPower5G, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ ctlEdgesMaxPower5GHT20 = zm_min(ctlEdgesMaxPower5GHT20, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ ctlEdgesMaxPower5GHT40 = zm_min(ctlEdgesMaxPower5GHT40, wd->regulationTable.allowChannel[i].maxRegTxPower*2); ++ } ++ break; ++ } ++ } ++ ++ ++ /* Apply ctl mode to correct target power set */ ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_debug_msg1("ctlEdgesMaxPower5G = ", ctlEdgesMaxPower5G); ++ zm_debug_msg1("ctlEdgesMaxPower5GHT20 = ", ctlEdgesMaxPower5GHT20); ++ zm_debug_msg1("ctlEdgesMaxPower5GHT40 = ", ctlEdgesMaxPower5GHT40); ++ #endif ++ for (i=0; i<4; i++) ++ { ++ hpPriv->tPow2x5g[i] = zm_min(hpPriv->tPow2x5g[i], ctlEdgesMaxPower5G) + HALTX_POWER_OFFSET; ++ } ++ for (i=0; i<8; i++) ++ { ++ hpPriv->tPow2x5gHt20[i] = zm_min(hpPriv->tPow2x5gHt20[i], ctlEdgesMaxPower5GHT20) + HALTX_POWER_OFFSET; ++ } ++ for (i=0; i<8; i++) ++ { ++ hpPriv->tPow2x5gHt40[i] = zm_min(hpPriv->tPow2x5gHt40[i], ctlEdgesMaxPower5GHT40) + HALTX_POWER_OFFSET; ++ } ++ ++ }/* end of bandedges of 5G */ ++ }/* end of if ((desired_CtlIndex = zfHpGetRegulatoryDomain(dev)) == 0) */ ++ ++ /* workaround */ ++ /* 5. BB heavy clip */ ++ /* only 2.4G do heavy clip */ ++ if (hpPriv->enableBBHeavyClip && hpPriv->hwBBHeavyClip && (frequency <= ZM_CH_G_14)) ++ { ++ if (frequency <= ZM_CH_G_14) ++ { ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_11G); ++ } ++ else ++ { ++ ctl_i = zfFindCtlEdgesIndex(dev, desired_CtlIndex|CTL_11A); ++ } ++ ++ hpPriv->setValueHeavyClip = zfHpCheckDoHeavyClip(dev, frequency, eepromImage->ctlData[ctl_i].ctlEdges[1], bw40); ++ ++ if (hpPriv->setValueHeavyClip) ++ { ++ hpPriv->doBBHeavyClip = 1; ++ } ++ else ++ { ++ hpPriv->doBBHeavyClip = 0; ++ } ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ zm_dbg(("zfHpCheckDoHeavyClip ret = %02x, doBBHeavyClip = %d\n", ++ hpPriv->setValueHeavyClip, hpPriv->doBBHeavyClip)); ++ #endif ++ ++ if (hpPriv->doBBHeavyClip) ++ { ++ if (hpPriv->setValueHeavyClip & 0xf0) ++ { ++ hpPriv->tPow2x2gHt40[0] -= 1; ++ hpPriv->tPow2x2gHt40[1] -= 1; ++ hpPriv->tPow2x2gHt40[2] -= 1; ++ } ++ ++ if (hpPriv->setValueHeavyClip & 0xf) ++ { ++ hpPriv->tPow2x2gHt20[0] += 1; ++ hpPriv->tPow2x2gHt20[1] += 1; ++ hpPriv->tPow2x2gHt20[2] += 1; ++ } ++ } ++ } ++ else ++ { ++ hpPriv->doBBHeavyClip = 0; ++ hpPriv->setValueHeavyClip = 0; ++ } ++ ++ /* Final : write MAC register for some ctrl frame Tx power */ ++ /* first part : 2.4G */ ++ if (frequency <= ZM_CH_G_14) ++ { ++ /* Write MAC reg 0x694 for ACK's TPC */ ++ /* Write MAC reg 0xbb4 RTS and SF-CTS frame power control */ ++ /* Always use two stream for low legacy rate */ ++ #if 0 ++ //if (hpPriv->halCapability & ZM_HP_CAP_11N_ONE_TX_STREAM) ++ //{ ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->tPow2x2g[0]&0x3f) << 20) | (0x1<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->tPow2x2g[0]&0x3f) << 5 ) | (0x1<<11) | ++ ((hpPriv->tPow2x2g[0]&0x3f) << 21) | (0x1<<27) ); ++ //} ++ #endif ++ #if 1 ++ //else ++ { ++ #ifndef ZM_OTUS_LINUX_PHASE_2 ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->tPow2x2g[0]&0x3f) << 20) | (0x5<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->tPow2x2g[0]&0x3f) << 5 ) | (0x5<<11) | ++ ((hpPriv->tPow2x2g[0]&0x3f) << 21) | (0x5<<27) ); ++ #endif ++ hpPriv->currentAckRtsTpc = hpPriv->tPow2x2g[0]; ++ } ++ #endif ++ zfFlushDelayWrite(dev); ++ ++ zfPrintTargetPower2G(hpPriv->tPow2xCck, ++ hpPriv->tPow2x2g, ++ hpPriv->tPow2x2gHt20, ++ hpPriv->tPow2x2gHt40); ++ } ++ else ++ { ++ /* Write MAC reg 0x694 for ACK's TPC */ ++ /* Write MAC reg 0xbb4 RTS and SF-CTS frame power control */ ++ /* Always use two stream for low legacy rate */ ++ if (hpPriv->halCapability & ZM_HP_CAP_11N_ONE_TX_STREAM) ++ { ++ #ifndef ZM_OTUS_LINUX_PHASE_2 ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->tPow2x5g[0]&0x3f) << 20) | (0x1<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->tPow2x5g[0]&0x3f) << 5 ) | (0x1<<11) | ++ ((hpPriv->tPow2x5g[0]&0x3f) << 21) | (0x1<<27) ); ++ #endif ++ } ++ else ++ { ++ #ifndef ZM_OTUS_LINUX_PHASE_2 ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->tPow2x5g[0]&0x3f) << 20) | (0x5<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->tPow2x5g[0]&0x3f) << 5 ) | (0x5<<11) | ++ ((hpPriv->tPow2x5g[0]&0x3f) << 21) | (0x5<<27) ); ++ #endif ++ hpPriv->currentAckRtsTpc = hpPriv->tPow2x2g[0]; ++ } ++ ++ ++ zfFlushDelayWrite(dev); ++ ++ zfPrintTargetPower5G( ++ hpPriv->tPow2x5g, ++ hpPriv->tPow2x5gHt20, ++ hpPriv->tPow2x5gHt40); ++ }/* end of bandedges of 5G */ ++ ++} ++ ++void zfDumpEepBandEdges(struct ar5416Eeprom* eepromImage) ++{ ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ u8_t i, j, k; ++ ++#if 0 ++ zm_dbg(("\n === BandEdges index dump ==== \n")); ++ ++ for (i = 0; i < AR5416_NUM_CTLS; i++) ++ { ++ zm_dbg(("%02x ", eepromImage->ctlIndex[i])); ++ } ++ ++ zm_dbg(("\n === BandEdges data dump ==== \n")); ++ ++ for (i = 0; i < AR5416_NUM_CTLS; i++) ++ { ++ for (j = 0; j < 2; j++) ++ { ++ for(k = 0; k < AR5416_NUM_BAND_EDGES; k++) ++ { ++ u8_t *pdata = (u8_t*)&(eepromImage->ctlData[i].ctlEdges[j][k]); ++ zm_dbg(("(%02x %02x)", pdata[0], pdata[1])); ++ } ++ zm_dbg(("\n")); ++ } ++ } ++#else ++ zm_dbg(("\n === BandEdges index dump ==== \n")); ++ for (i = 0; i < 24; i+=8) ++ { ++ zm_dbg(("%02x %02x %02x %02x %02x %02x %02x %02x", ++ eepromImage->ctlIndex[i+0], eepromImage->ctlIndex[i+1], eepromImage->ctlIndex[i+2], eepromImage->ctlIndex[i+3], ++ eepromImage->ctlIndex[i+4], eepromImage->ctlIndex[i+5], eepromImage->ctlIndex[i+6], eepromImage->ctlIndex[i+7] ++ )); ++ } ++ ++ zm_dbg(("\n === BandEdges data dump ==== \n")); ++ ++ for (i = 0; i < AR5416_NUM_CTLS; i++) ++ { ++ for (j = 0; j < 2; j++) ++ { ++ u8_t *pdata = (u8_t*)&(eepromImage->ctlData[i].ctlEdges[j]); ++ zm_dbg(("(%03d %02x) (%03d %02x) (%03d %02x) (%03d %02x) \n", ++ pdata[0], pdata[1], pdata[2], pdata[3], ++ pdata[4], pdata[5], pdata[6], pdata[7] ++ )); ++ zm_dbg(("(%03d %02x) (%03d %02x) (%03d %02x) (%03d %02x) \n", ++ pdata[8], pdata[9], pdata[10], pdata[11], ++ pdata[12], pdata[13], pdata[14], pdata[15] ++ )); ++ } ++ } ++#endif ++ #endif ++} ++ ++void zfPrintTargetPower2G(u8_t* tPow2xCck, u8_t* tPow2x2g, u8_t* tPow2x2gHt20, u8_t* tPow2x2gHt40) ++{ ++ //#ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ DbgPrint("targetPwr CCK : %d, %d, %d, %d\n", ++ tPow2xCck[0], ++ tPow2xCck[1], ++ tPow2xCck[2], ++ tPow2xCck[3] ++ ); ++ DbgPrint("targetPwr 2G : %d, %d, %d, %d\n", ++ tPow2x2g[0], ++ tPow2x2g[1], ++ tPow2x2g[2], ++ tPow2x2g[3] ++ ); ++ DbgPrint("targetPwr 2GHT20 : %d, %d, %d, %d, %d, %d, %d, %d\n", ++ tPow2x2gHt20[0], ++ tPow2x2gHt20[1], ++ tPow2x2gHt20[2], ++ tPow2x2gHt20[3], ++ tPow2x2gHt20[4], ++ tPow2x2gHt20[5], ++ tPow2x2gHt20[6], ++ tPow2x2gHt20[7] ++ ); ++ DbgPrint("targetPwr 2GHT40 : %d, %d, %d, %d, %d, %d, %d, %d\n", ++ tPow2x2gHt40[0], ++ tPow2x2gHt40[1], ++ tPow2x2gHt40[2], ++ tPow2x2gHt40[3], ++ tPow2x2gHt40[4], ++ tPow2x2gHt40[5], ++ tPow2x2gHt40[6], ++ tPow2x2gHt40[7] ++ ); ++ #endif ++ return; ++} ++ ++void zfPrintTargetPower5G(u8_t* tPow2x5g, u8_t* tPow2x5gHt20, u8_t* tPow2x5gHt40) ++{ ++ //#ifdef ZM_ENABLE_TPC_WINDOWS_DEBUG ++ #ifdef ZM_ENABLE_BANDEDGES_WINDOWS_DEBUG ++ DbgPrint("targetPwr 5G : %d, %d, %d, %d\n", ++ tPow2x5g[0], ++ tPow2x5g[1], ++ tPow2x5g[2], ++ tPow2x5g[3] ++ ); ++ DbgPrint("targetPwr 5GHT20 : %d, %d, %d, %d, %d, %d, %d, %d\n", ++ tPow2x5gHt20[0], ++ tPow2x5gHt20[1], ++ tPow2x5gHt20[2], ++ tPow2x5gHt20[3], ++ tPow2x5gHt20[4], ++ tPow2x5gHt20[5], ++ tPow2x5gHt20[6], ++ tPow2x5gHt20[7] ++ ); ++ DbgPrint("targetPwr 5GHT40 : %d, %d, %d, %d, %d, %d, %d, %d\n", ++ tPow2x5gHt40[0], ++ tPow2x5gHt40[1], ++ tPow2x5gHt40[2], ++ tPow2x5gHt40[3], ++ tPow2x5gHt40[4], ++ tPow2x5gHt40[5], ++ tPow2x5gHt40[6], ++ tPow2x5gHt40[7] ++ ); ++ #endif ++ return; ++} ++ ++void zfHpPowerSaveSetMode(zdev_t* dev, u8_t staMode, u8_t psMode, u16_t bcnInterval) ++{ ++ if ( staMode == 0 ) ++ { ++ if ( psMode == 0 ) ++ { ++ // Turn off pre-TBTT interrupt ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_PRETBTT, 0); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PERIOD, 0); ++ zfFlushDelayWrite(dev); ++ } ++ else ++ { ++ // Turn on pre-TBTT interrupt ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_PRETBTT, (bcnInterval-6)<<16); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PERIOD, bcnInterval); ++ zfFlushDelayWrite(dev); ++ } ++ } ++} ++ ++void zfHpPowerSaveSetState(zdev_t* dev, u8_t psState) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ //DbgPrint("INTO zfHpPowerSaveSetState"); ++ ++ if ( psState == 0 ) //power up ++ { ++ //DbgPrint("zfHpPowerSaveSetState Wake up from PS\n"); ++ reg_write(0x982C, 0x0000a000); //wake up ADDAC ++ reg_write(0x9808, 0x0); //enable all agc gain and offset updates to a2 ++ //# bank 3 ++ if (((struct zsHpPriv*)wd->hpPrivate)->hwFrequency <= ZM_CH_G_14) ++ { ++ /* 11g */ ++ //reg_write (0x98f0, 0x01c00018); ++ reg_write (0x98f0, 0x01c20098);//syn_on+RX_ON ++ } ++ else ++ { ++ /* 11a */ ++ //reg_write (0x98f0, 0x01400018); ++ reg_write (0x98f0, 0x01420098);//syn_on+RX_ON ++ } ++ ++ ////#bank 5 ++ //reg_write(0x98b0, 0x00000013); ++ //reg_write(0x98e4, 0x00000002); ++ ++ ++ zfFlushDelayWrite(dev); ++ } ++ else //power down ++ { ++ //DbgPrint("zfHpPowerSaveSetState Go to PS\n"); ++ //reg_write(0x982C, 0xa000a000); ++ reg_write(0x9808, 0x8000000); //disable all agc gain and offset updates to a2 ++ reg_write(0x982C, 0xa000a000); //power down ADDAC ++ //# bank 3 ++ if (((struct zsHpPriv*)wd->hpPrivate)->hwFrequency <= ZM_CH_G_14) ++ { ++ /* 11g */ ++ reg_write (0x98f0, 0x00c00018);//syn_off+RX_off ++ } ++ else ++ { ++ /* 11a */ ++ reg_write (0x98f0, 0x00400018);//syn_off+RX_off ++ } ++ ++ ////#bank 5 ++ //reg_write(0x98b0, 0x000e0013); ++ //reg_write(0x98e4, 0x00018002); ++ ++ ++ zfFlushDelayWrite(dev); ++ } ++} ++ ++void zfHpSetAggPktNum(zdev_t* dev, u32_t num) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ num = (num << 16) | (0xa); ++ ++ hpPriv->aggPktNum = num; ++ ++ //aggregation number will be update in HAL heart beat ++ //zfDelayWriteInternalReg(dev, 0x1c3b9c, num); ++ //zfFlushDelayWrite(dev); ++} ++ ++void zfHpSetMPDUDensity(zdev_t* dev, u8_t density) ++{ ++ u32_t value; ++ ++ if (density > ZM_MPDU_DENSITY_8US) ++ { ++ return; ++ } ++ ++ /* Default value in this register */ ++ value = 0x140A00 | density; ++ ++ zfDelayWriteInternalReg(dev, 0x1c3ba0, value); ++ zfFlushDelayWrite(dev); ++ return; ++} ++ ++void zfHpSetSlotTime(zdev_t* dev, u8_t type) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = wd->hpPrivate; ++ ++ if (type == 0) ++ { ++ //normal slot = 20us ++ hpPriv->slotType = 0; ++ } ++ else //if (type == 1) ++ { ++ //short slot = 9us ++ hpPriv->slotType = 1; ++ } ++ ++ return; ++} ++ ++void zfHpSetSlotTimeRegister(zdev_t* dev, u8_t type) ++{ ++ if(type == 0) ++ { ++ //normal slot = 20us ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_SLOT_TIME, 20<<10); ++ } ++ else ++ { ++ //short slot = 9us ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_SLOT_TIME, 9<<10); ++ } ++} ++ ++void zfHpSetRifs(zdev_t* dev, u8_t ht_enable, u8_t ht2040, u8_t g_mode) ++{ ++ zfDelayWriteInternalReg(dev, 0x1c6388, 0x0c000000); ++ ++ zfDelayWriteInternalReg(dev, 0x1c59ec, 0x0cc80caa); ++ ++ if (ht_enable) ++ { ++ if (ht2040) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c5918, 40); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c5918, 20); ++ } ++ } ++ ++ if (g_mode) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c5850, 0xec08b4e2); ++ zfDelayWriteInternalReg(dev, 0x1c585c, 0x313a5d5e); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c5850, 0xede8b4e0); ++ zfDelayWriteInternalReg(dev, 0x1c585c, 0x3139605e); ++ } ++ ++ zfFlushDelayWrite(dev); ++ return; ++} ++ ++void zfHpBeginSiteSurvey(zdev_t* dev, u8_t status) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ if ( status == 1 ) ++ { // Connected ++ hpPriv->isSiteSurvey = 1; ++ } ++ else ++ { // Not connected ++ hpPriv->isSiteSurvey = 0; ++ } ++ ++ /* reset workaround state to default */ ++// if (hpPriv->rxStrongRSSI == 1) ++ { ++ hpPriv->rxStrongRSSI = 0; ++ if ((hpPriv->eepromImage[0x100+0x110*2/4]&0xff) == 0x80) //FEM TYPE ++ { ++ if (hpPriv->hwFrequency <= ZM_CH_G_14) ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x9b49); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x0900); ++ } ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, 0x1c8960, 0x9b40); ++ } ++ zfFlushDelayWrite(dev); ++ } ++// if (hpPriv->strongRSSI == 1) ++ { ++ hpPriv->strongRSSI = 0; ++ zfDelayWriteInternalReg(dev, 0x1c3694, ((hpPriv->currentAckRtsTpc&0x3f) << 20) | (0x5<<26)); ++ zfDelayWriteInternalReg(dev, 0x1c3bb4, ((hpPriv->currentAckRtsTpc&0x3f) << 5 ) | (0x5<<11) | ++ ((hpPriv->currentAckRtsTpc&0x3f) << 21) | (0x5<<27) ); ++ zfFlushDelayWrite(dev); ++ } ++} ++ ++void zfHpFinishSiteSurvey(zdev_t* dev, u8_t status) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ if ( status == 1 ) ++ { ++ hpPriv->isSiteSurvey = 2; ++ } ++ else ++ { ++ hpPriv->isSiteSurvey = 0; ++ } ++ zmw_leave_critical_section(dev); ++} ++ ++u16_t zfFwRetry(zdev_t* dev, u8_t enable) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret = 0; ++ ++ cmd[0] = 4 | (0x92 << 8); ++ cmd[1] = (enable == 1) ? 0x01 : 0x00; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++ ++u16_t zfHpEnableHwRetry(zdev_t* dev) ++{ ++ u16_t ret; ++ ++ ret = zfFwRetry(dev, 0); ++ ++ zfDelayWriteInternalReg(dev, 0x1c3b28, 0x33333); ++ zfFlushDelayWrite(dev); ++ ++ return ret; ++} ++ ++u16_t zfHpDisableHwRetry(zdev_t* dev) ++{ ++ u16_t ret; ++ ++ ret = zfFwRetry(dev, 1); ++ ++ zfDelayWriteInternalReg(dev, 0x1c3b28, 0x00000); ++ zfFlushDelayWrite(dev); ++ ++ return ret; ++} ++ ++/* Download SPI Fw */ ++#define ZM_FIRMWARE_WLAN 0 ++#define ZM_FIRMWARE_SPI_FLASH 1 ++ ++ ++u16_t zfHpFirmwareDownload(zdev_t* dev, u8_t fwType) ++{ ++ u16_t ret = ZM_SUCCESS; ++ ++ if (fwType == ZM_FIRMWARE_WLAN) ++ { ++ ret = zfFirmwareDownload(dev, (u32_t*)zcFwImage, ++ (u32_t)zcFwImageSize, ZM_FIRMWARE_WLAN_ADDR); ++ } ++ else if (fwType == ZM_FIRMWARE_SPI_FLASH) ++ { ++ ret = zfFirmwareDownload(dev, (u32_t*)zcFwImageSPI, ++ (u32_t)zcFwImageSPISize, ZM_FIRMWARE_SPI_ADDR); ++ } ++ else ++ { ++ zm_debug_msg1("Unknown firmware type = ", fwType); ++ ret = ZM_ERR_FIRMWARE_WRONG_TYPE; ++ } ++ ++ return ret; ++} ++ ++/* Enable software decryption */ ++void zfHpSWDecrypt(zdev_t* dev, u8_t enable) ++{ ++ u32_t value = 0x70; ++ ++ /* Bit 4 for enable software decryption */ ++ if (enable == 1) ++ { ++ value = 0x78; ++ } ++ ++ zfDelayWriteInternalReg(dev, 0x1c3678, value); ++ zfFlushDelayWrite(dev); ++} ++ ++/* Enable software encryption */ ++void zfHpSWEncrypt(zdev_t* dev, u8_t enable) ++{ ++ /* Because encryption by software or hardware is judged by driver in Otus, ++ we don't need to do anything in the HAL layer. ++ */ ++} ++ ++u32_t zfHpCapability(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ return hpPriv->halCapability; ++} ++ ++void zfHpSetRollCallTable(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ if (hpPriv->camRollCallTable != (u64_t) 0) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ROLL_CALL_TBL_L, (u32_t)(hpPriv->camRollCallTable & 0xffffffff)); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_ROLL_CALL_TBL_H, (u32_t)((hpPriv->camRollCallTable >> 32) & 0xffffffff)); ++ zfFlushDelayWrite(dev); ++ } ++} ++ ++void zfHpSetTTSIFSTime(zdev_t* dev, u8_t sifs_time) ++{ ++ u32_t reg_value = 0; ++ zmw_get_wlan_dev(dev); ++ ++ sifs_time &= 0x3f; ++ reg_value = 0x14400b | (((u32_t)sifs_time)<<24); ++ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_EIFS_AND_SIFS, reg_value); ++ zfFlushDelayWrite(dev); ++} ++ ++/* #3 Enable RIFS function if the RIFS pattern matched ! */ ++void zfHpEnableRifs(zdev_t* dev, u8_t mode24g, u8_t modeHt, u8_t modeHt2040) ++{ ++ ++ /* # Enable Reset TDOMAIN ++ * $rddata = &$phyreg_read(0x9800+(738<<2)); ++ * $wrdata = $rddata | (0x1 << 26) | (0x1 << 27); ++ * &$phyreg_write(0x9800+(738<<2), $wrdata); ++ */ ++ reg_write (0x9800+(738<<2), 0x08000000 | (0x1 << 26) | (0x1 << 27)); ++ //reg_write (0x9800+(738<<2), 0x08000000 | (0x1 << 26)); ++ ++ /* # reg 123: heavy clip factor, xr / RIFS search parameters */ ++ reg_write (0x99ec, 0x0cc80caa); ++ ++ /* # Reduce Search Start Delay for RIFS */ ++ if (modeHt == 1) /* ($HT_ENABLE == 1) */ ++ { ++ if (modeHt2040 == 0x1) /* ($DYNAMIC_HT2040_EN == 0x1) */ ++ { ++ reg_write(0x9800+(70<<2), 40);/*40*/ ++ } ++ else ++ { ++ reg_write(0x9800+(70<<2), 20); ++ if(mode24g == 0x0) ++ { ++ /* $rddata = &$phyreg_read(0x9800+(24<<2));#0x9860;0x1c5860 ++ *$wrdata = ($rddata & 0xffffffc7) | (0x4 << 3); ++ * &$phyreg_write(0x9800+(24<<2), $wrdata); ++ */ ++ reg_write(0x9800+(24<<2), (0x0004dd10 & 0xffffffc7) | (0x4 << 3)); ++ } ++ } ++ } ++ ++ if (mode24g == 0x1) ++ { ++ reg_write(0x9850, 0xece8b4e4);/*org*/ ++ //reg_write(0x9850, 0xece8b4e2); ++ reg_write(0x985c, 0x313a5d5e); ++ } ++ else ++ { ++ reg_write(0x9850, 0xede8b4e4); ++ reg_write(0x985c, 0x3139605e); ++ } ++ ++ zfFlushDelayWrite(dev); ++ ++ return; ++} ++ ++/* #4 Disable RIFS function if the RIFS timer is timeout ! */ ++void zfHpDisableRifs(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ /* Disable RIFS function is to store these HW register initial value while the device plug-in and ++ re-write to these register if the RIFS function is disabled */ ++ ++ // reg : 9850 ++ reg_write(0x9850, ((struct zsHpPriv*)wd->hpPrivate)->initDesiredSigSize); ++ ++ // reg : 985c ++ reg_write(0x985c, ((struct zsHpPriv*)wd->hpPrivate)->initAGC); ++ ++ // reg : 9860 ++ reg_write(0x9800+(24<<2), ((struct zsHpPriv*)wd->hpPrivate)->initAgcControl); ++ ++ // reg : 9918 ++ reg_write(0x9800+(70<<2), ((struct zsHpPriv*)wd->hpPrivate)->initSearchStartDelay); ++ ++ // reg : 991c ++ reg_write (0x99ec, ((struct zsHpPriv*)wd->hpPrivate)->initRIFSSearchParams); ++ ++ // reg : a388 ++ reg_write (0x9800+(738<<2), ((struct zsHpPriv*)wd->hpPrivate)->initFastChannelChangeControl); ++ ++ zfFlushDelayWrite(dev); ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/otus/hal/hpreg.c +@@ -0,0 +1,2481 @@ ++/* ++ * Copyright (c) 2000-2005 ZyDAS Technology Corporation ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : hpreg.c */ ++/* */ ++/* Abstract */ ++/* This module contains Regulatory Table and related function. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "../80211core/cprecomp.h" ++#include "hpani.h" ++#include "hpreg.h" ++#include "hpusb.h" ++ ++/* used throughout this file... */ ++#define N(a) (sizeof (a) / sizeof (a[0])) ++ ++#define HAL_MODE_11A_TURBO HAL_MODE_108A ++#define HAL_MODE_11G_TURBO HAL_MODE_108G ++ ++#if 0 ++enum { ++ /* test groups */ ++ FCC = 0x10, ++ MKK = 0x40, ++ ETSI = 0x30, ++ SD_NO_CTL = 0xe0, ++ NO_CTL = 0xff, ++ /* test modes */ ++ CTL_MODE_M = 0x0f, ++ CTL_11A = 0, ++ CTL_11B = 1, ++ CTL_11G = 2, ++ CTL_TURBO = 3, ++ CTL_108G = 4, ++ CTL_2GHT20 = 5, ++ CTL_5GHT20 = 6, ++ CTL_2GHT40 = 7, ++ CTL_5GHT40 = 8 ++}; ++#endif ++ ++/* ++ * The following are flags for different requirements per reg domain. ++ * These requirements are either inhereted from the reg domain pair or ++ * from the unitary reg domain if the reg domain pair flags value is ++ * 0 ++ */ ++ ++enum { ++ NO_REQ = 0x00000000, ++ DISALLOW_ADHOC_11A = 0x00000001, ++ DISALLOW_ADHOC_11A_TURB = 0x00000002, ++ NEED_NFC = 0x00000004, ++ ++ ADHOC_PER_11D = 0x00000008, /* Start Ad-Hoc mode */ ++ ADHOC_NO_11A = 0x00000010, ++ ++ PUBLIC_SAFETY_DOMAIN = 0x00000020, /* public safety domain */ ++ LIMIT_FRAME_4MS = 0x00000040, /* 4msec limit on the frame length */ ++}; ++ ++#define MKK5GHZ_FLAG1 (DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS) ++#define MKK5GHZ_FLAG2 (DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC| LIMIT_FRAME_4MS) ++ ++typedef enum { ++ DFS_UNINIT_DOMAIN = 0, /* Uninitialized dfs domain */ ++ DFS_FCC_DOMAIN = 1, /* FCC3 dfs domain */ ++ DFS_ETSI_DOMAIN = 2, /* ETSI dfs domain */ ++} HAL_DFS_DOMAIN; ++ ++/* ++ * Used to set the RegDomain bitmask which chooses which frequency ++ * band specs are used. ++ */ ++ ++#define BMLEN 2 /* Use 2 64 bit uint for channel bitmask ++ NB: Must agree with macro below (BM) */ ++#define BMZERO {(u64_t) 0, (u64_t) 0} /* BMLEN zeros */ ++ ++#if 0 ++ ++#define BM(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh, _fi, _fj, _fk, _fl) \ ++ {((((_fa >= 0) && (_fa < 64)) ? (((u64_t) 1) << _fa) : (u64_t) 0) | \ ++ (((_fb >= 0) && (_fb < 64)) ? (((u64_t) 1) << _fb) : (u64_t) 0) | \ ++ (((_fc >= 0) && (_fc < 64)) ? (((u64_t) 1) << _fc) : (u64_t) 0) | \ ++ (((_fd >= 0) && (_fd < 64)) ? (((u64_t) 1) << _fd) : (u64_t) 0) | \ ++ (((_fe >= 0) && (_fe < 64)) ? (((u64_t) 1) << _fe) : (u64_t) 0) | \ ++ (((_ff >= 0) && (_ff < 64)) ? (((u64_t) 1) << _ff) : (u64_t) 0) | \ ++ (((_fg >= 0) && (_fg < 64)) ? (((u64_t) 1) << _fg) : (u64_t) 0) | \ ++ (((_fh >= 0) && (_fh < 64)) ? (((u64_t) 1) << _fh) : (u64_t) 0) | \ ++ (((_fi >= 0) && (_fi < 64)) ? (((u64_t) 1) << _fi) : (u64_t) 0) | \ ++ (((_fj >= 0) && (_fj < 64)) ? (((u64_t) 1) << _fj) : (u64_t) 0) | \ ++ (((_fk >= 0) && (_fk < 64)) ? (((u64_t) 1) << _fk) : (u64_t) 0) | \ ++ (((_fl >= 0) && (_fl < 64)) ? (((u64_t) 1) << _fl) : (u64_t) 0) | \ ++ ((((_fa > 63) && (_fa < 128)) ? (((u64_t) 1) << (_fa - 64)) : (u64_t) 0) | \ ++ (((_fb > 63) && (_fb < 128)) ? (((u64_t) 1) << (_fb - 64)) : (u64_t) 0) | \ ++ (((_fc > 63) && (_fc < 128)) ? (((u64_t) 1) << (_fc - 64)) : (u64_t) 0) | \ ++ (((_fd > 63) && (_fd < 128)) ? (((u64_t) 1) << (_fd - 64)) : (u64_t) 0) | \ ++ (((_fe > 63) && (_fe < 128)) ? (((u64_t) 1) << (_fe - 64)) : (u64_t) 0) | \ ++ (((_ff > 63) && (_ff < 128)) ? (((u64_t) 1) << (_ff - 64)) : (u64_t) 0) | \ ++ (((_fg > 63) && (_fg < 128)) ? (((u64_t) 1) << (_fg - 64)) : (u64_t) 0) | \ ++ (((_fh > 63) && (_fh < 128)) ? (((u64_t) 1) << (_fh - 64)) : (u64_t) 0) | \ ++ (((_fi > 63) && (_fi < 128)) ? (((u64_t) 1) << (_fi - 64)) : (u64_t) 0) | \ ++ (((_fj > 63) && (_fj < 128)) ? (((u64_t) 1) << (_fj - 64)) : (u64_t) 0) | \ ++ (((_fk > 63) && (_fk < 128)) ? (((u64_t) 1) << (_fk - 64)) : (u64_t) 0) | \ ++ (((_fl > 63) && (_fl < 128)) ? (((u64_t) 1) << (_fl - 64)) : (u64_t) 0)))} ++ ++#else ++ ++#define BM(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh, _fi, _fj, _fk, _fl) \ ++ {((((_fa >= 0) && (_fa < 64)) ? (((u64_t) 1) << (_fa&0x3f)) : (u64_t) 0) | \ ++ (((_fb >= 0) && (_fb < 64)) ? (((u64_t) 1) << (_fb&0x3f)) : (u64_t) 0) | \ ++ (((_fc >= 0) && (_fc < 64)) ? (((u64_t) 1) << (_fc&0x3f)) : (u64_t) 0) | \ ++ (((_fd >= 0) && (_fd < 64)) ? (((u64_t) 1) << (_fd&0x3f)) : (u64_t) 0) | \ ++ (((_fe >= 0) && (_fe < 64)) ? (((u64_t) 1) << (_fe&0x3f)) : (u64_t) 0) | \ ++ (((_ff >= 0) && (_ff < 64)) ? (((u64_t) 1) << (_ff&0x3f)) : (u64_t) 0) | \ ++ (((_fg >= 0) && (_fg < 64)) ? (((u64_t) 1) << (_fg&0x3f)) : (u64_t) 0) | \ ++ (((_fh >= 0) && (_fh < 64)) ? (((u64_t) 1) << (_fh&0x3f)) : (u64_t) 0) | \ ++ (((_fi >= 0) && (_fi < 64)) ? (((u64_t) 1) << (_fi&0x3f)) : (u64_t) 0) | \ ++ (((_fj >= 0) && (_fj < 64)) ? (((u64_t) 1) << (_fj&0x3f)) : (u64_t) 0) | \ ++ (((_fk >= 0) && (_fk < 64)) ? (((u64_t) 1) << (_fk&0x3f)) : (u64_t) 0) | \ ++ (((_fl >= 0) && (_fl < 64)) ? (((u64_t) 1) << (_fl&0x3f)) : (u64_t) 0) | \ ++ ((((_fa > 63) && (_fa < 128)) ? (((u64_t) 1) << ((_fa - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fb > 63) && (_fb < 128)) ? (((u64_t) 1) << ((_fb - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fc > 63) && (_fc < 128)) ? (((u64_t) 1) << ((_fc - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fd > 63) && (_fd < 128)) ? (((u64_t) 1) << ((_fd - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fe > 63) && (_fe < 128)) ? (((u64_t) 1) << ((_fe - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_ff > 63) && (_ff < 128)) ? (((u64_t) 1) << ((_ff - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fg > 63) && (_fg < 128)) ? (((u64_t) 1) << ((_fg - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fh > 63) && (_fh < 128)) ? (((u64_t) 1) << ((_fh - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fi > 63) && (_fi < 128)) ? (((u64_t) 1) << ((_fi - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fj > 63) && (_fj < 128)) ? (((u64_t) 1) << ((_fj - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fk > 63) && (_fk < 128)) ? (((u64_t) 1) << ((_fk - 64)&0x3f)) : (u64_t) 0) | \ ++ (((_fl > 63) && (_fl < 128)) ? (((u64_t) 1) << ((_fl - 64)&0x3f)) : (u64_t) 0)))} ++ ++#endif ++ ++/* Mask to check whether a domain is a multidomain or a single ++ domain */ ++ ++#define MULTI_DOMAIN_MASK 0xFF00 ++ ++ ++/* ++ * The following describe the bit masks for different passive scan ++ * capability/requirements per regdomain. ++ */ ++#define NO_PSCAN 0x0ULL ++#define PSCAN_FCC 0x0000000000000001ULL ++#define PSCAN_FCC_T 0x0000000000000002ULL ++#define PSCAN_ETSI 0x0000000000000004ULL ++#define PSCAN_MKK1 0x0000000000000008ULL ++#define PSCAN_MKK2 0x0000000000000010ULL ++#define PSCAN_MKKA 0x0000000000000020ULL ++#define PSCAN_MKKA_G 0x0000000000000040ULL ++#define PSCAN_ETSIA 0x0000000000000080ULL ++#define PSCAN_ETSIB 0x0000000000000100ULL ++#define PSCAN_ETSIC 0x0000000000000200ULL ++#define PSCAN_WWR 0x0000000000000400ULL ++#define PSCAN_MKKA1 0x0000000000000800ULL ++#define PSCAN_MKKA1_G 0x0000000000001000ULL ++#define PSCAN_MKKA2 0x0000000000002000ULL ++#define PSCAN_MKKA2_G 0x0000000000004000ULL ++#define PSCAN_MKK3 0x0000000000008000ULL ++#define PSCAN_DEFER 0x7FFFFFFFFFFFFFFFULL ++#define IS_ECM_CHAN 0x8000000000000000ULL ++ ++/* ++ * THE following table is the mapping of regdomain pairs specified by ++ * an 8 bit regdomain value to the individual unitary reg domains ++ */ ++ ++typedef struct reg_dmn_pair_mapping { ++ u16_t regDmnEnum; /* 16 bit reg domain pair */ ++ u16_t regDmn5GHz; /* 5GHz reg domain */ ++ u16_t regDmn2GHz; /* 2GHz reg domain */ ++ u32_t flags5GHz; /* Requirements flags (AdHoc ++ disallow, noise floor cal needed, ++ etc) */ ++ u32_t flags2GHz; /* Requirements flags (AdHoc ++ disallow, noise floor cal needed, ++ etc) */ ++ u64_t pscanMask; /* Passive Scan flags which ++ can override unitary domain ++ passive scan flags. This ++ value is used as a mask on ++ the unitary flags*/ ++ u16_t singleCC; /* Country code of single country if ++ a one-on-one mapping exists */ ++} REG_DMN_PAIR_MAPPING; ++ ++static REG_DMN_PAIR_MAPPING regDomainPairs[] = { ++ {NO_ENUMRD, FCC2, DEBUG_REG_DMN, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {NULL1_WORLD, NULL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {NULL1_ETSIB, NULL1, ETSIB, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {NULL1_ETSIC, NULL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ ++ {FCC2_FCCA, FCC2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC2_WORLD, FCC2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC2_ETSIC, FCC2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC3_FCCA, FCC3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC3_WORLD, FCC3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC4_FCCA, FCC4, FCCA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC5_FCCA, FCC5, FCCA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC6_FCCA, FCC6, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC6_WORLD, FCC6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ ++ {ETSI1_WORLD, ETSI1, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {ETSI2_WORLD, ETSI2, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {ETSI3_WORLD, ETSI3, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {ETSI4_WORLD, ETSI4, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {ETSI5_WORLD, ETSI5, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {ETSI6_WORLD, ETSI6, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ ++ {ETSI3_ETSIA, ETSI3, WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {FRANCE_RES, ETSI3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ ++ {FCC1_WORLD, FCC1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {FCC1_FCCA, FCC1, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL1_WORLD, APL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL2_WORLD, APL2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL3_WORLD, APL3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL4_WORLD, APL4, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL5_WORLD, APL5, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL6_WORLD, APL6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL8_WORLD, APL8, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL9_WORLD, APL9, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ ++ {APL3_FCCA, APL3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL1_ETSIC, APL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL2_ETSIC, APL2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL2_FCCA, APL2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {APL2_APLD, APL2, APLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, ++ {APL7_FCCA, APL7, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ ++ {MKK1_MKKA, MKK1, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA, CTRY_JAPAN }, ++ {MKK1_MKKB, MKK1, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN1 }, ++ {MKK1_FCCA, MKK1, FCCA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1, CTRY_JAPAN2 }, ++ {MKK1_MKKA1, MKK1, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN4 }, ++ {MKK1_MKKA2, MKK1, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN5 }, ++ {MKK1_MKKC, MKK1, MKKC, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1, CTRY_JAPAN6 }, ++ ++ /* MKK2 */ ++ {MKK2_MKKA, MKK2, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK2 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN3 }, ++ ++ /* MKK3 */ ++ {MKK3_MKKA, MKK3, MKKA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN25 }, ++ {MKK3_MKKB, MKK3, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN7 }, ++ {MKK3_MKKA1, MKK3, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN26 }, ++ {MKK3_MKKA2, MKK3, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN8 }, ++ {MKK3_MKKC, MKK3, MKKC, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN9 }, ++ {MKK3_FCCA, MKK3, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN27 }, ++ ++ /* MKK4 */ ++ {MKK4_MKKB, MKK4, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN10 }, ++ {MKK4_MKKA1, MKK4, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN28 }, ++ {MKK4_MKKA2, MKK4, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK3 |PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN11 }, ++ {MKK4_MKKC, MKK4, MKKC, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN12 }, ++ {MKK4_FCCA, MKK4, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN29 }, ++ {MKK4_MKKA, MKK4, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA, CTRY_JAPAN36 }, ++ ++ /* MKK5 */ ++ {MKK5_MKKB, MKK5, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN13 }, ++ {MKK5_MKKA2, MKK5, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN14 }, ++ {MKK5_MKKC, MKK5, MKKC, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN15 }, ++ ++ /* MKK6 */ ++ {MKK6_MKKB, MKK6, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN16 }, ++ {MKK6_MKKA2, MKK6, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN17 }, ++ {MKK6_MKKC, MKK6, MKKC, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1, CTRY_JAPAN18 }, ++ {MKK6_MKKA1, MKK6, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN30 }, ++ {MKK6_FCCA, MKK6, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN31 }, ++ ++ /* MKK7 */ ++ {MKK7_MKKB, MKK7, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN19 }, ++ {MKK7_MKKA, MKK7, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN20 }, ++ {MKK7_MKKC, MKK7, MKKC, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN21 }, ++ {MKK7_MKKA1, MKK7, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN32 }, ++ {MKK7_FCCA, MKK7, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN33 }, ++ ++ /* MKK8 */ ++ {MKK8_MKKB, MKK8, MKKA, MKK5GHZ_FLAG2, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN22 }, ++ {MKK8_MKKA2, MKK8, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN23 }, ++ {MKK8_MKKC, MKK8, MKKC, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 , CTRY_JAPAN24 }, ++ ++ /* MKK9 */ ++ {MKK9_MKKA, MKK9, MKKA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN34 }, ++ {MKK9_FCCA, MKK9, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN37 }, ++ {MKK9_MKKA1, MKK9, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN38 }, ++ {MKK9_MKKC, MKK9, MKKC, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN39 }, ++ {MKK9_MKKA2, MKK9, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN40 }, ++ ++ /* MKK10 */ ++ {MKK10_MKKA, MKK10, MKKA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN35 }, ++ {MKK10_FCCA, MKK10, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN41 }, ++ {MKK10_MKKA1, MKK10, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN42 }, ++ {MKK10_MKKC, MKK10, MKKC, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN43 }, ++ {MKK10_MKKA2, MKK10, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN44 }, ++ ++ /* MKK11 */ ++ {MKK11_MKKA, MKK11, MKKA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN45 }, ++ {MKK11_FCCA, MKK11, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN46 }, ++ {MKK11_MKKA1, MKK11, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN47 }, ++ {MKK11_MKKC, MKK11, MKKC, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN48 }, ++ {MKK11_MKKA2, MKK11, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN49 }, ++ ++ /* MKK12 */ ++ {MKK12_MKKA, MKK12, MKKA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN50 }, ++ {MKK12_FCCA, MKK12, FCCA, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN51 }, ++ {MKK12_MKKA1, MKK12, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN52 }, ++ {MKK12_MKKC, MKK12, MKKC, MKK5GHZ_FLAG1, NEED_NFC, NO_PSCAN, CTRY_JAPAN53 }, ++ {MKK12_MKKA2, MKK12, MKKA, MKK5GHZ_FLAG1, NEED_NFC, PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN54 }, ++ ++ ++ /* These are super domains */ ++ {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR4_WORLD, WOR4_WORLD, WOR4_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {EU1_WORLD, EU1_WORLD, EU1_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0 }, ++ {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++ {WORA_WORLD, WORA_WORLD, WORA_WORLD, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0 }, ++}; ++ ++/* ++ * The following table is the master list for all different freqeuncy ++ * bands with the complete matrix of all possible flags and settings ++ * for each band if it is used in ANY reg domain. ++ */ ++ ++#define DEF_REGDMN FCC1_FCCA ++#define DEF_DMN_5 FCC1 ++#define DEF_DMN_2 FCCA ++#define COUNTRY_ERD_FLAG 0x8000 ++#define WORLDWIDE_ROAMING_FLAG 0x4000 ++#define SUPER_DOMAIN_MASK 0x0fff ++#define COUNTRY_CODE_MASK 0x03ff ++#define CF_INTERFERENCE (CHANNEL_CW_INT | CHANNEL_RADAR_INT) ++#define CHANNEL_14 (2484) /* 802.11g operation is not permitted on channel 14 */ ++#define IS_11G_CH14(_ch,_cf) \ ++ (((_ch) == CHANNEL_14) && ((_cf) == CHANNEL_G)) ++ ++#define YES TRUE ++#define NO FALSE ++ ++enum { ++ CTRY_DEBUG = 0x1ff, /* debug country code */ ++ CTRY_DEFAULT = 0 /* default country code */ ++}; ++ ++typedef struct { ++ HAL_CTRY_CODE countryCode; ++ HAL_REG_DOMAIN regDmnEnum; ++ const char* isoName; ++ const char* name; ++ HAL_BOOL allow11g; ++ HAL_BOOL allow11aTurbo; ++ HAL_BOOL allow11gTurbo; ++ HAL_BOOL allow11na; /* HT-40 allowed in 5GHz? */ ++ HAL_BOOL allow11ng; /* HT-40 allowed in 2GHz? */ ++ u16_t outdoorChanStart; ++} COUNTRY_CODE_TO_ENUM_RD; ++ ++static COUNTRY_CODE_TO_ENUM_RD allCountries[] = { ++ {CTRY_DEBUG, NO_ENUMRD, "DB", "DEBUG", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_DEFAULT, DEF_REGDMN, "NA", "NO_COUNTRY_SET", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_ALBANIA, NULL1_WORLD, "AL", "ALBANIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ALGERIA, NULL1_WORLD, "DZ", "ALGERIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ARGENTINA, APL3_WORLD, "AR", "ARGENTINA", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_AUSTRALIA, FCC6_WORLD, "AU", "AUSTRALIA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_AUSTRIA, ETSI2_WORLD, "AT", "AUSTRIA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_BAHRAIN, APL6_WORLD, "BH", "BAHRAIN", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_BELARUS, ETSI1_WORLD, "BY", "BELARUS", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_BELIZE, APL1_ETSIC, "BZ", "BELIZE", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_BOLIVIA, APL1_ETSIC, "BO", "BOLVIA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_BRAZIL, FCC3_WORLD, "BR", "BRAZIL", NO, NO, NO, NO, NO, 7000 }, ++ {CTRY_BRUNEI_DARUSSALAM,APL1_WORLD,"BN", "BRUNEI DARUSSALAM", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_BULGARIA, ETSI6_WORLD, "BG", "BULGARIA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_CANADA, FCC6_FCCA, "CA", "CANADA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_CHILE, APL6_WORLD, "CL", "CHILE", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_CHINA, APL1_WORLD, "CN", "CHINA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_COLOMBIA, FCC1_FCCA, "CO", "COLOMBIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_COSTA_RICA, FCC1_WORLD, "CR", "COSTA RICA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_CROATIA, ETSI3_WORLD, "HR", "CROATIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_CYPRUS, ETSI3_WORLD, "CY", "CYPRUS", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_CZECH, ETSI3_WORLD, "CZ", "CZECH REPUBLIC", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_DOMINICAN_REPUBLIC,FCC1_FCCA,"DO", "DOMINICAN REPUBLIC", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_ECUADOR, FCC1_WORLD, "EC", "ECUADOR", YES, NO, NO, NO, YES, 7000 }, ++ {CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_EL_SALVADOR, FCC1_WORLD, "SV", "EL SALVADOR", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_FRANCE, ETSI1_WORLD, "FR", "FRANCE", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_FRANCE2, ETSI3_WORLD, "F2", "FRANCE_RES", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_GUATEMALA, FCC1_FCCA, "GT", "GUATEMALA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_HONDURAS, NULL1_WORLD, "HN", "HONDURAS", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_HONG_KONG, FCC2_WORLD, "HK", "HONG KONG", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_HUNGARY, ETSI4_WORLD, "HU", "HUNGARY", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_INDIA, APL6_WORLD, "IN", "INDIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_INDONESIA, APL1_WORLD, "ID", "INDONESIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_IRAN, APL1_WORLD, "IR", "IRAN", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_ISRAEL, ETSI3_WORLD, "IL", "ISRAEL", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ISRAEL2, NULL1_ETSIB, "ISR","ISRAEL_RES", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_JAMAICA, ETSI1_WORLD, "JM", "JAMAICA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_JAPAN, MKK1_MKKA, "JP", "JAPAN", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN1, MKK1_MKKB, "J1", "JAPAN1", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN2, MKK1_FCCA, "J2", "JAPAN2", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN3, MKK2_MKKA, "J3", "JAPAN3", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN4, MKK1_MKKA1, "J4", "JAPAN4", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN5, MKK1_MKKA2, "J5", "JAPAN5", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN6, MKK1_MKKC, "J6", "JAPAN6", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN7, MKK3_MKKB, "J7", "JAPAN7", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN8, MKK3_MKKA2, "J8", "JAPAN8", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN9, MKK3_MKKC, "J9", "JAPAN9", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN10, MKK4_MKKB, "J10", "JAPAN10", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN11, MKK4_MKKA2, "J11", "JAPAN11", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN12, MKK4_MKKC, "J12", "JAPAN12", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN13, MKK5_MKKB, "J13", "JAPAN13", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN14, MKK5_MKKA2, "J14", "JAPAN14", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN15, MKK5_MKKC, "J15", "JAPAN15", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN16, MKK6_MKKB, "J16", "JAPAN16", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN17, MKK6_MKKA2, "J17", "JAPAN17", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN18, MKK6_MKKC, "J18", "JAPAN18", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN19, MKK7_MKKB, "J19", "JAPAN19", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN20, MKK7_MKKA, "J20", "JAPAN20", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN21, MKK7_MKKC, "J21", "JAPAN21", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN22, MKK8_MKKB, "J22", "JAPAN22", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN23, MKK8_MKKA2, "J23", "JAPAN23", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN24, MKK8_MKKC, "J24", "JAPAN24", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN25, MKK3_MKKA, "J25", "JAPAN25", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN26, MKK3_MKKA1, "J26", "JAPAN26", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN27, MKK3_FCCA, "J27", "JAPAN27", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN28, MKK4_MKKA1, "J28", "JAPAN28", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN29, MKK4_FCCA, "J29", "JAPAN29", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN30, MKK6_MKKA1, "J30", "JAPAN30", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN31, MKK6_FCCA, "J31", "JAPAN31", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN32, MKK7_MKKA1, "J32", "JAPAN32", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN33, MKK7_FCCA, "J33", "JAPAN33", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN34, MKK9_MKKA, "J34", "JAPAN34", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN35, MKK10_MKKA, "J35", "JAPAN35", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN36, MKK4_MKKA, "J36", "JAPAN36", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN37, MKK9_FCCA, "J37", "JAPAN37", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN38, MKK9_MKKA1, "J38", "JAPAN38", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN39, MKK9_MKKC, "J39", "JAPAN39", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN40, MKK10_MKKA2, "J40", "JAPAN40", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN41, MKK10_FCCA, "J41", "JAPAN41", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN42, MKK10_MKKA1, "J42", "JAPAN42", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN43, MKK10_MKKC, "J43", "JAPAN43", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN44, MKK10_MKKA2, "J44", "JAPAN44", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN45, MKK11_MKKA, "J45", "JAPAN45", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN46, MKK11_FCCA, "J46", "JAPAN46", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN47, MKK11_MKKA1, "J47", "JAPAN47", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN48, MKK11_MKKC, "J48", "JAPAN48", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN49, MKK11_MKKA2, "J49", "JAPAN49", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN50, MKK12_MKKA, "J50", "JAPAN50", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN51, MKK12_FCCA, "J51", "JAPAN51", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN52, MKK12_MKKA1, "J52", "JAPAN52", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN53, MKK12_MKKC, "J53", "JAPAN53", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JAPAN54, MKK12_MKKA2, "J54", "JAPAN54", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_JORDAN, ETSI2_WORLD, "JO", "JORDAN", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_KOREA_NORTH, APL9_WORLD, "KP", "NORTH KOREA", YES, NO, NO, YES, YES, 7000 }, ++ {CTRY_KOREA_ROC, APL9_WORLD, "KR", "KOREA REPUBLIC", YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_KOREA_ROC2, APL2_APLD, "K2", "KOREA REPUBLIC2",YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_KOREA_ROC3, APL9_WORLD, "K3", "KOREA REPUBLIC3",YES, NO, NO, NO, NO, 7000 }, ++ {CTRY_KUWAIT, NULL1_WORLD, "KW", "KUWAIT", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_LEBANON, NULL1_WORLD, "LB", "LEBANON", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_LIECHTENSTEIN,ETSI1_WORLD, "LI", "LIECHTENSTEIN", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_MACAU, FCC2_WORLD, "MO", "MACAU", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_MACEDONIA, NULL1_WORLD, "MK", "MACEDONIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_MALAYSIA, APL8_WORLD, "MY", "MALAYSIA", NO, NO, NO, NO, NO, 7000 }, ++ {CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_MEXICO, FCC1_FCCA, "MX", "MEXICO", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_MONACO, ETSI4_WORLD, "MC", "MONACO", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_MOROCCO, NULL1_WORLD, "MA", "MOROCCO", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_NETHERLANDS_ANT, ETSI1_WORLD, "AN", "NETHERLANDS-ANTILLES", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ", "NEW ZEALAND", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_OMAN, APL6_WORLD, "OM", "OMAN", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_PAKISTAN, NULL1_WORLD, "PK", "PAKISTAN", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_PANAMA, FCC1_FCCA, "PA", "PANAMA", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_PERU, APL1_WORLD, "PE", "PERU", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_PHILIPPINES, APL1_WORLD, "PH", "PHILIPPINES", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_PUERTO_RICO, FCC1_FCCA, "PR", "PUERTO RICO", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_QATAR, NULL1_WORLD, "QA", "QATAR", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ROMANIA, NULL1_WORLD, "RO", "ROMANIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_RUSSIA, NULL1_WORLD, "RU", "RUSSIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_SAUDI_ARABIA,NULL1_WORLD, "SA", "SAUDI ARABIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_SERBIA_MONT, ETSI1_WORLD, "CS", "SERBIA & MONTENEGRO", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_SINGAPORE, APL6_WORLD, "SG", "SINGAPORE", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAK REPUBLIC",YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_SOUTH_AFRICA,FCC3_WORLD, "ZA", "SOUTH AFRICA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_SRILANKA, FCC3_WORLD, "LK", "SRI LANKA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND", YES, NO, YES, YES, YES, 7000 }, ++ {CTRY_SYRIA, NULL1_WORLD, "SY", "SYRIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_TAIWAN, APL3_FCCA, "TW", "TAIWAN", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_THAILAND, NULL1_WORLD, "TH", "THAILAND", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_TRINIDAD_Y_TOBAGO,ETSI4_WORLD,"TT", "TRINIDAD & TOBAGO", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_TURKEY, ETSI3_WORLD, "TR", "TURKEY", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_UKRAINE, NULL1_WORLD, "UA", "UKRAINE", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_UAE, NULL1_WORLD, "AE", "UNITED ARAB EMIRATES", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_UNITED_KINGDOM, ETSI1_WORLD,"GB", "UNITED KINGDOM", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_UNITED_STATES, FCC3_FCCA, "US", "UNITED STATES", YES, YES, YES, YES, YES, 5825 }, ++ {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS", "UNITED STATES (PUBLIC SAFETY)", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_URUGUAY, FCC1_WORLD, "UY", "URUGUAY", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ", "UZBEKISTAN", YES, YES, YES, YES, YES, 7000 }, ++ {CTRY_VENEZUELA, APL2_ETSIC, "VE", "VENEZUELA", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_VIET_NAM, NULL1_WORLD, "VN", "VIET NAM", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN", YES, NO, YES, NO, YES, 7000 }, ++ {CTRY_ZIMBABWE, NULL1_WORLD, "ZW", "ZIMBABWE", YES, NO, YES, NO, YES, 7000 } ++}; ++ ++typedef struct RegDmnFreqBand { ++ u16_t lowChannel; /* Low channel center in MHz */ ++ u16_t highChannel; /* High Channel center in MHz */ ++ u8_t powerDfs; /* Max power (dBm) for channel ++ range when using DFS */ ++ u8_t antennaMax; /* Max allowed antenna gain */ ++ u8_t channelBW; /* Bandwidth of the channel */ ++ u8_t channelSep; /* Channel separation within ++ the band */ ++ u64_t useDfs; /* Use DFS in the RegDomain ++ if corresponding bit is set */ ++ u64_t usePassScan; /* Use Passive Scan in the RegDomain ++ if corresponding bit is set */ ++ u8_t regClassId; /* Regulatory class id */ ++ u8_t useExtChanDfs; /* Regulatory class id */ ++} REG_DMN_FREQ_BAND; ++ ++/* Bit masks for DFS per regdomain */ ++ ++enum { ++ NO_DFS = 0x0000000000000000ULL, ++ DFS_FCC3 = 0x0000000000000001ULL, ++ DFS_ETSI = 0x0000000000000002ULL, ++ DFS_MKK4 = 0x0000000000000004ULL, ++}; ++ ++/* The table of frequency bands is indexed by a bitmask. The ordering ++ * must be consistent with the enum below. When adding a new ++ * frequency band, be sure to match the location in the enum with the ++ * comments ++ */ ++ ++/* ++ * 5GHz 11A channel tags ++ */ ++ ++enum { ++ F1_4915_4925, ++ F1_4935_4945, ++ F1_4920_4980, ++ F1_4942_4987, ++ F1_4945_4985, ++ F1_4950_4980, ++ F1_5035_5040, ++ F1_5040_5080, ++ F1_5055_5055, ++ ++ F1_5120_5240, ++ ++ F1_5170_5230, ++ F2_5170_5230, ++ ++ F1_5180_5240, ++ F2_5180_5240, ++ F3_5180_5240, ++ F4_5180_5240, ++ F5_5180_5240, ++ F6_5180_5240, ++ F7_5180_5240, ++ ++ F1_5180_5320, ++ ++ F1_5240_5280, ++ ++ F1_5260_5280, ++ ++ F1_5260_5320, ++ F2_5260_5320, ++ F3_5260_5320, ++ F4_5260_5320, ++ F5_5260_5320, ++ F6_5260_5320, ++ F7_5260_5320, ++ ++ F1_5260_5700, ++ ++ F1_5280_5320, ++ ++ F1_5500_5580, ++ ++ F1_5500_5620, ++ ++ F1_5500_5700, ++ F2_5500_5700, ++ F3_5500_5700, ++ F4_5500_5700, ++ ++ F1_5660_5700, ++ ++ F1_5745_5805, ++ F2_5745_5805, ++ F3_5745_5805, ++ ++ F1_5745_5825, ++ F2_5745_5825, ++ F3_5745_5825, ++ F4_5745_5825, ++ F5_5745_5825, ++ F6_5745_5825, ++ ++ W1_4920_4980, ++ W1_5040_5080, ++ W1_5170_5230, ++ W1_5180_5240, ++ W1_5260_5320, ++ W1_5745_5825, ++ W1_5500_5700, ++ W2_5260_5320, ++ W2_5180_5240, ++ W2_5825_5825, ++}; ++ ++static REG_DMN_FREQ_BAND regDmn5GhzFreq[] = { ++ { 4915, 4925, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16, 0 }, /* F1_4915_4925 */ ++ { 4935, 4945, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16, 0 }, /* F1_4935_4945 */ ++ { 4920, 4980, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7, 0 }, /* F1_4920_4980 */ ++ { 4942, 4987, 27, 6, 5, 5, DFS_FCC3, PSCAN_FCC, 0, 0 }, /* F1_4942_4987 */ ++ { 4945, 4985, 30, 6, 10, 5, DFS_FCC3, PSCAN_FCC, 0, 0 }, /* F1_4945_4985 */ ++ { 4950, 4980, 33, 6, 20, 5, DFS_FCC3, PSCAN_FCC, 0, 0 }, /* F1_4950_4980 */ ++ { 5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12, 0 }, /* F1_5035_5040 */ ++ { 5040, 5080, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 2, 0 }, /* F1_5040_5080 */ ++ { 5055, 5055, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12, 0 }, /* F1_5055_5055 */ ++ ++ { 5120, 5240, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F1_5120_5240 */ ++ ++ { 5170, 5230, 23, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1, 0 }, /* F1_5170_5230 */ ++ { 5170, 5230, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1, 0 }, /* F2_5170_5230 */ ++ ++ { 5180, 5240, 15, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F1_5180_5240 */ ++ { 5180, 5240, 17, 6, 20, 20, NO_DFS, PSCAN_FCC, 1, 0 }, /* F2_5180_5240 */ ++ { 5180, 5240, 18, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F3_5180_5240 */ ++ { 5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F4_5180_5240 */ ++ { 5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F5_5180_5240 */ ++ { 5180, 5240, 23, 6, 20, 20, NO_DFS, PSCAN_FCC, 0, 0 }, /* F6_5180_5240 */ ++ { 5180, 5240, 23, 6, 20, 20, NO_DFS, NO_PSCAN, 0 }, /* F7_5180_5240 */ ++ ++ { 5180, 5320, 20, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0, 0 }, /* F1_5180_5320 */ ++ ++ { 5240, 5280, 23, 0, 20, 20, DFS_FCC3, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F1_5240_5280 */ ++ ++ { 5260, 5280, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F1_5260_5280 */ ++ ++ { 5260, 5320, 18, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F1_5260_5320 */ ++ ++ { 5260, 5320, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3 , 0, 0 }, ++ /* F2_5260_5320 */ ++ ++ { 5260, 5320, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2, 0 }, /* F3_5260_5320 */ ++ { 5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2, 0 }, /* F4_5260_5320 */ ++ { 5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0, 0 }, /* F5_5260_5320 */ ++ { 5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F6_5260_5320 */ ++ { 5260, 5320, 17, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0, 0 }, /* F7_5260_5320 */ ++ ++ { 5260, 5700, 5, 6, 20, 20, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0, 0 }, /* F1_5260_5700 */ ++ ++ { 5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0, 0 }, /* F1_5280_5320 */ ++ ++ { 5500, 5580, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 0}, /* F1_5500_5580 */ ++ ++ { 5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0, 0 }, /* F1_5500_5620 */ ++ ++ { 5500, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 4, 0 }, /* F1_5500_5700 */ ++ { 5500, 5700, 27, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F2_5500_5700 */ ++ { 5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0, 0 }, /* F3_5500_5700 */ ++ { 5500, 5700, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_MKK3 | PSCAN_FCC, 0, 0 }, ++ /* F4_5500_5700 */ ++ ++ { 5660, 5700, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 0}, /* F1_5660_5700 */ ++ ++ { 5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F1_5745_5805 */ ++ { 5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F2_5745_5805 */ ++ { 5745, 5805, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0, 0 }, /* F3_5745_5805 */ ++ { 5745, 5825, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F1_5745_5825 */ ++ { 5745, 5825, 17, 0, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F2_5745_5825 */ ++ { 5745, 5825, 20, 0, 20, 20, DFS_ETSI, NO_PSCAN, 0, 0 }, /* F3_5745_5825 */ ++ { 5745, 5825, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F4_5745_5825 */ ++ { 5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 3, 0 }, /* F5_5745_5825 */ ++ { 5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* F6_5745_5825 */ ++ ++ /* ++ * Below are the world roaming channels ++ * All WWR domains have no power limit, instead use the card's CTL ++ * or max power settings. ++ */ ++ { 4920, 4980, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0, 0 }, /* W1_4920_4980 */ ++ { 5040, 5080, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0 }, /* W1_5040_5080 */ ++ { 5170, 5230, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0 }, /* W1_5170_5230 */ ++ { 5180, 5240, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0 }, /* W1_5180_5240 */ ++ { 5260, 5320, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0 }, /* W1_5260_5320 */ ++ { 5745, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0, 0 }, /* W1_5745_5825 */ ++ { 5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0 }, /* W1_5500_5700 */ ++ { 5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* W2_5260_5320 */ ++ { 5180, 5240, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0, 0 }, /* W2_5180_5240 */ ++ { 5825, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0, 0 }, /* W2_5825_5825 */ ++}; ++/* ++ * 5GHz Turbo (dynamic & static) tags ++ */ ++ ++enum { ++ T1_5130_5210, ++ T1_5250_5330, ++ T1_5370_5490, ++ T1_5530_5650, ++ ++ T1_5150_5190, ++ T1_5230_5310, ++ T1_5350_5470, ++ T1_5510_5670, ++ ++ T1_5200_5240, ++ T2_5200_5240, ++ T1_5210_5210, ++ T2_5210_5210, ++ ++ T1_5280_5280, ++ T2_5280_5280, ++ T1_5250_5250, ++ T1_5290_5290, ++ T1_5250_5290, ++ T2_5250_5290, ++ ++ T1_5540_5660, ++ T1_5760_5800, ++ T2_5760_5800, ++ ++ T1_5765_5805, ++ ++ WT1_5210_5250, ++ WT1_5290_5290, ++ WT1_5540_5660, ++ WT1_5760_5800, ++}; ++ ++static REG_DMN_FREQ_BAND regDmn5GhzTurboFreq[] = { ++ { 5130, 5210, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5130_5210 */ ++ { 5250, 5330, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5250_5330 */ ++ { 5370, 5490, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5370_5490 */ ++ { 5530, 5650, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5530_5650 */ ++ ++ { 5150, 5190, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5150_5190 */ ++ { 5230, 5310, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5230_5310 */ ++ { 5350, 5470, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5350_5470 */ ++ { 5510, 5670, 5, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 0}, /* T1_5510_5670 */ ++ ++ { 5200, 5240, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5200_5240 */ ++ { 5200, 5240, 23, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_5200_5240 */ ++ { 5210, 5210, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5210_5210 */ ++ { 5210, 5210, 23, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_5210_5210 */ ++ ++ { 5280, 5280, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5280_5280 */ ++ { 5280, 5280, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T2_5280_5280 */ ++ { 5250, 5250, 17, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5250_5250 */ ++ { 5290, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5290_5290 */ ++ { 5250, 5290, 20, 0, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5250_5290 */ ++ { 5250, 5290, 23, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T2_5250_5290 */ ++ ++ { 5540, 5660, 20, 6, 40, 40, DFS_FCC3, PSCAN_FCC_T, 0, 0}, /* T1_5540_5660 */ ++ { 5760, 5800, 20, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5760_5800 */ ++ { 5760, 5800, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_5760_5800 */ ++ ++ { 5765, 5805, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_5765_5805 */ ++ ++ /* ++ * Below are the WWR frequencies ++ */ ++ ++ { 5210, 5250, 15, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0}, /* WT1_5210_5250 */ ++ { 5290, 5290, 18, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0}, /* WT1_5290_5290 */ ++ { 5540, 5660, 20, 0, 40, 40, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0, 0}, /* WT1_5540_5660 */ ++ { 5760, 5800, 20, 0, 40, 40, NO_DFS, PSCAN_WWR, 0, 0}, /* WT1_5760_5800 */ ++}; ++ ++/* ++ * 2GHz 11b channel tags ++ */ ++enum { ++ F1_2312_2372, ++ F2_2312_2372, ++ ++ F1_2412_2472, ++ F2_2412_2472, ++ F3_2412_2472, ++ ++ F1_2412_2462, ++ F2_2412_2462, ++ ++ F1_2432_2442, ++ ++ F1_2457_2472, ++ ++ F1_2467_2472, ++ ++ F1_2484_2484, ++ F2_2484_2484, ++ ++ F1_2512_2732, ++ ++ W1_2312_2372, ++ W1_2412_2412, ++ W1_2417_2432, ++ W1_2437_2442, ++ W1_2447_2457, ++ W1_2462_2462, ++ W1_2467_2467, ++ W2_2467_2467, ++ W1_2472_2472, ++ W2_2472_2472, ++ W1_2484_2484, ++ W2_2484_2484, ++}; ++ ++static REG_DMN_FREQ_BAND regDmn2GhzFreq[] = { ++ { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2312_2372 */ ++ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F2_2312_2372 */ ++ ++ { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2412_2472 */ ++ { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0, 0}, /* F2_2412_2472 */ ++ { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F3_2412_2472 */ ++ ++ { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2412_2462 */ ++ { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0, 0}, /* F2_2412_2462 */ ++ { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2432_2442 */ ++ ++ { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2457_2472 */ ++ ++ { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0, 0}, /* F1_2467_2472 */ ++ ++ { 2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2484_2484 */ ++ { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 0, 0}, /* F2_2484_2484 */ ++ ++ { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* F1_2512_2732 */ ++ ++ /* ++ * WWR have powers opened up to 20dBm. Limits should often come from CTL/Max powers ++ */ ++ ++ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2312_2372 */ ++ { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2412_2412 */ ++ { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2417_2432 */ ++ { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2437_2442 */ ++ { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2447_2457 */ ++ { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* W1_2462_2462 */ ++ { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* W1_2467_2467 */ ++ { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* W2_2467_2467 */ ++ { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* W1_2472_2472 */ ++ { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* W2_2472_2472 */ ++ { 2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* W1_2484_2484 */ ++ { 2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* W2_2484_2484 */ ++}; ++ ++ ++/* ++ * 2GHz 11g channel tags ++ */ ++ ++enum { ++ G1_2312_2372, ++ G2_2312_2372, ++ ++ G1_2412_2472, ++ G2_2412_2472, ++ G3_2412_2472, ++ ++ G1_2412_2462, ++ G2_2412_2462, ++ ++ G1_2432_2442, ++ ++ G1_2457_2472, ++ ++ G1_2512_2732, ++ ++ G1_2467_2472 , ++ ++ WG1_2312_2372, ++ WG1_2412_2412, ++ WG1_2417_2432, ++ WG1_2437_2442, ++ WG1_2447_2457, ++ WG1_2462_2462, ++ WG1_2467_2467, ++ WG2_2467_2467, ++ WG1_2472_2472, ++ WG2_2472_2472, ++ ++}; ++static REG_DMN_FREQ_BAND regDmn2Ghz11gFreq[] = { ++ { 2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G1_2312_2372 */ ++ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G2_2312_2372 */ ++ ++ { 2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G1_2412_2472 */ ++ { 2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0, 0}, /* G2_2412_2472 */ ++ { 2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G3_2412_2472 */ ++ ++ { 2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G1_2412_2462 */ ++ { 2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0, 0}, /* G2_2412_2462 */ ++ { 2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G1_2432_2442 */ ++ ++ { 2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G1_2457_2472 */ ++ ++ { 2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* G1_2512_2732 */ ++ ++ { 2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0, 0 }, /* G1_2467_2472 */ ++ ++ /* ++ * WWR open up the power to 20dBm ++ */ ++ ++ { 2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* WG1_2312_2372 */ ++ { 2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* WG1_2412_2412 */ ++ { 2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* WG1_2417_2432 */ ++ { 2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* WG1_2437_2442 */ ++ { 2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* WG1_2447_2457 */ ++ { 2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* WG1_2462_2462 */ ++ { 2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* WG1_2467_2467 */ ++ { 2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* WG2_2467_2467 */ ++ { 2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0, 0}, /* WG1_2472_2472 */ ++ { 2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0, 0}, /* WG2_2472_2472 */ ++}; ++/* ++ * 2GHz Dynamic turbo tags ++ */ ++ ++enum { ++ T1_2312_2372, ++ T1_2437_2437, ++ T2_2437_2437, ++ T3_2437_2437, ++ T1_2512_2732 ++}; ++ ++static REG_DMN_FREQ_BAND regDmn2Ghz11gTurboFreq[] = { ++ { 2312, 2372, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_2312_2372 */ ++ { 2437, 2437, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_2437_2437 */ ++ { 2437, 2437, 20, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T2_2437_2437 */ ++ { 2437, 2437, 18, 6, 40, 40, NO_DFS, PSCAN_WWR, 0, 0}, /* T3_2437_2437 */ ++ { 2512, 2732, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* T1_2512_2732 */ ++}; ++ ++ ++ ++/* ++ * 2GHz 11n frequency tags ++ */ ++enum { ++ NG1_2422_2452, ++ NG2_2422_2452, ++ NG3_2422_2452, ++ ++ NG_DEMO_ALL_CHANNELS, ++}; ++ ++static REG_DMN_FREQ_BAND regDmn2Ghz11ngFreq[] = { ++ { 2422, 2452, 20, 0, 40, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG1_2422_2452 */ ++ { 2422, 2452, 27, 0, 40, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG2_2422_2452 */ ++ { 2422, 2452, 30, 0, 40, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG3_2422_2452 */ ++ ++ { 2312, 2732, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0, 0}, /* NG_DEMO_ALL_CHANNELS */ ++}; ++ ++ ++/* ++ * 5GHz 11n frequency tags ++ */ ++enum { ++ NA1_5190_5230, ++ NA2_5190_5230, ++ NA3_5190_5230, ++ NA4_5190_5230, ++ NA5_5190_5230, ++ ++ NA1_5270_5270, ++ ++ NA1_5270_5310, ++ NA2_5270_5310, ++ NA3_5270_5310, ++ NA4_5270_5310, ++ ++ NA1_5310_5310, ++ ++ NA1_5510_5630, ++ ++ NA1_5510_5670, ++ NA2_5510_5670, ++ NA3_5510_5670, ++ ++ NA1_5755_5795, ++ NA2_5755_5795, ++ NA3_5755_5795, ++ NA4_5755_5795, ++ NA5_5755_5795, ++ ++ NA1_5795_5795, ++ ++ NA_DEMO_ALL_CHANNELS, ++}; ++ ++static REG_DMN_FREQ_BAND regDmn5Ghz11naFreq[] = { ++ /* ++ * ToDo: This table needs to be completely populated with 5GHz 11n properties ++ */ ++ { 5190, 5230, 15, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA1_5190_5230 */ ++ { 5190, 5230, 17, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA2_5190_5230 */ ++ { 5190, 5230, 18, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA3_5190_5230 */ ++ { 5190, 5230, 20, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA4_5190_5230 */ ++ { 5190, 5230, 23, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA5_5190_5230 */ ++ ++ { 5270, 5270, 23, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5270_5270 */ ++ ++ { 5270, 5310, 18, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5270_5310 */ ++ { 5270, 5310, 20, 0, 40, 40, DFS_FCC3|DFS_ETSI|DFS_MKK4, NO_PSCAN, 0, 1}, /* NA2_5270_5310 */ ++ { 5270, 5310, 23, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA3_5270_5310 */ ++ { 5270, 5310, 30, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA4_5270_5310 */ ++ ++ { 5310, 5310, 17, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5310_5310 */ ++ ++ { 5510, 5630, 30, 6, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA1_5510_5630 */ ++ ++ { 5510, 5670, 20, 6, 40, 40, DFS_FCC3|DFS_ETSI|DFS_MKK4, NO_PSCAN, 0, 1}, /* NA1_5510_5670 */ ++ { 5510, 5670, 27, 0, 40, 40, DFS_FCC3|DFS_ETSI, NO_PSCAN, 0, 1}, /* NA2_5510_5670 */ ++ { 5510, 5670, 30, 6, 40, 40, DFS_FCC3, NO_PSCAN, 0, 1}, /* NA3_5510_5670 */ ++ ++ { 5755, 5795, 17, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA1_5755_5795 */ ++ { 5755, 5795, 20, 6, 40, 40, DFS_ETSI, NO_PSCAN, 0, 0}, /* NA2_5755_5795 */ ++ { 5755, 5795, 23, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA3_5755_5795 */ ++ { 5755, 5795, 30, 0, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA4_5755_5795 */ ++ { 5755, 5795, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA5_5755_5795 */ ++ ++ { 5795, 5795, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA1_5795_5795 */ ++ ++ { 4920, 6100, 30, 6, 40, 40, NO_DFS, NO_PSCAN, 0, 0}, /* NA_DEMO_ALL_CHANNELS */ ++}; ++ ++typedef struct regDomain { ++ u16_t regDmnEnum; /* value from EnumRd table */ ++ u8_t conformanceTestLimit; ++ u64_t dfsMask; /* DFS bitmask for 5Ghz tables */ ++ u64_t pscan; /* Bitmask for passive scan */ ++ u32_t flags; /* Requirement flags (AdHoc disallow, noise ++ floor cal needed, etc) */ ++ u64_t chan11a[BMLEN];/* 128 bit bitmask for channel/band ++ selection */ ++ u64_t chan11a_turbo[BMLEN];/* 128 bit bitmask for channel/band ++ selection */ ++ u64_t chan11a_dyn_turbo[BMLEN]; /* 128 bit bitmask for channel/band ++ selection */ ++ u64_t chan11b[BMLEN];/* 128 bit bitmask for channel/band ++ selection */ ++ u64_t chan11g[BMLEN];/* 128 bit bitmask for channel/band ++ selection */ ++ u64_t chan11g_turbo[BMLEN];/* 128 bit bitmask for channel/band ++ selection */ ++ u64_t chan11ng[BMLEN];/* 128 bit bitmask for 11n in 2GHz */ ++ u64_t chan11na[BMLEN];/* 128 bit bitmask for 11n in 5GHz */ ++} REG_DOMAIN; ++ ++static REG_DOMAIN regDomains[] = { ++ ++ {DEBUG_REG_DMN, FCC, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F1_5120_5240, F1_5260_5700, F1_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T1_5130_5210, T1_5250_5330, T1_5370_5490, T1_5530_5650, T1_5150_5190, T1_5230_5310, T1_5350_5470, T1_5510_5670, -1, -1, -1, -1), ++ BM(T1_5200_5240, T1_5280_5280, T1_5540_5660, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(F1_2312_2372, F1_2412_2472, F1_2484_2484, F1_2512_2732, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(G1_2312_2372, G1_2412_2472, G1_2512_2732, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T1_2312_2372, T1_2437_2437, T1_2512_2732, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(NG_DEMO_ALL_CHANNELS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(NA_DEMO_ALL_CHANNELS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL1, ETSI, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL2, ETSI, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F1_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA3_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL3, FCC, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F1_5280_5320, F2_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA1_5310_5310, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL4, ETSI, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F4_5180_5240, F3_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL5, ETSI, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F2_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA1_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL6, ETSI, DFS_ETSI, PSCAN_FCC_T | PSCAN_FCC , NO_REQ, ++ BM(F4_5180_5240, F2_5260_5320, F3_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T2_5210_5210, T1_5250_5290, T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, NA2_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL7, FCC, NO_DFS, PSCAN_FCC_T | PSCAN_FCC , NO_REQ, ++ BM(F7_5260_5320, F4_5500_5700, F3_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA1_5310_5310, NA2_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ {APL8, ETSI, NO_DFS, NO_PSCAN, DISALLOW_ADHOC_11A|DISALLOW_ADHOC_11A_TURB, ++ BM(F6_5260_5320, F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5270_5310, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {APL9, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A|DISALLOW_ADHOC_11A_TURB, ++ BM(F1_5180_5320, F1_5500_5620, F3_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, NA1_5510_5630, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {ETSI1, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BM(W2_5180_5240, F2_5260_5320, F2_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, NA2_5510_5670, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {ETSI2, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BM(F3_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA3_5190_5230, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {ETSI3, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BM(W2_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {ETSI4, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BM(F3_5180_5240, F1_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA3_5190_5230, NA1_5270_5310, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {ETSI5, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BM(F1_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA1_5190_5230, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {ETSI6, ETSI, DFS_ETSI, PSCAN_ETSI, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BM(F5_5180_5240, F1_5260_5280, F3_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA5_5190_5230, NA1_5270_5270, NA3_5510_5670, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {FCC1, FCC, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F2_5180_5240, F4_5260_5320, F5_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T1_5210_5210, T2_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T1_5200_5240, T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA2_5190_5230, NA3_5270_5310, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {FCC2, FCC, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F6_5180_5240, F5_5260_5320, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T2_5200_5240, T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA5_5190_5230, NA3_5270_5310, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {FCC3, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ, ++ BM(F2_5180_5240, F3_5260_5320, F1_5500_5700, F5_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T1_5210_5210, T1_5250_5250, T1_5290_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T1_5200_5240, T2_5280_5280, T1_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA2_5190_5230, NA2_5270_5310, NA3_5510_5670, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {FCC4, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ, ++ BM(F1_4942_4987, F1_4945_4985, F1_4950_4980, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ {FCC5, FCC, NO_DFS, NO_PSCAN, NO_REQ, ++ BM(F2_5180_5240, F5_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA2_5190_5230, NA4_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {FCC6, FCC, DFS_FCC3, PSCAN_FCC, NO_REQ, ++ BM(F7_5180_5240, F5_5260_5320, F1_5500_5580, F1_5660_5700, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1), ++ BM(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T2_5200_5240, T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA5_5190_5230, NA5_5755_5795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ {MKK1, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, ++ BM(F1_5170_5230, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ {MKK2, MKK, NO_DFS, PSCAN_MKK2, DISALLOW_ADHOC_11A_TURB, ++ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F1_5170_5230, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ /* UNI-1 even */ ++ {MKK3, MKK, NO_DFS, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, ++ BM(F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ /* UNI-1 even + UNI-2 */ ++ {MKK4, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, ++ BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ /* UNI-1 even + UNI-2 + mid-band */ ++ {MKK5, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, ++ BM(F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, NA1_5510_5670, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ /* UNI-1 odd + even */ ++ {MKK6, MKK, DFS_MKK4, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, ++ BM(F2_5170_5230, F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ /* UNI-1 odd + UNI-1 even + UNI-2 */ ++ {MKK7, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3 , DISALLOW_ADHOC_11A_TURB, ++ BM(F2_5170_5230, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ /* UNI-1 odd + UNI-1 even + UNI-2 + mid-band */ ++ {MKK8, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3 , DISALLOW_ADHOC_11A_TURB, ++ BM(F2_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(NA4_5190_5230, NA2_5270_5310, NA1_5510_5670, -1, -1, -1, -1, -1, -1, -1, -1, -1)}, ++ ++ /* UNI-1 even + 4.9 GHZ */ ++ {MKK9, MKK, NO_DFS, NO_PSCAN, DISALLOW_ADHOC_11A_TURB, ++ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F4_5180_5240, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ /* UNI-1 even + UNI-2 + 4.9 GHZ */ ++ {MKK10, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, ++ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ /* UNI-1 even + UNI-2 + 4.9 GHZ + mid-band */ ++ {MKK11, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, ++ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ /* UNI-1 even + UNI-1 odd + UNI-2 + 4.9 GHZ + mid-band */ ++ {MKK12, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, ++ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040, F1_5055_5055, F1_5040_5080, F1_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ /* Defined here to use when 2G channels are authorised for country K2 */ ++ {APLD, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F2_2312_2372,F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(G2_2312_2372,G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++ ++ {ETSIA, NO_CTL, NO_DFS, PSCAN_ETSIA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F1_2457_2472,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(G1_2457_2472,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {ETSIB, ETSI, NO_DFS, PSCAN_ETSIB, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F1_2432_2442,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(G1_2432_2442,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {ETSIC, ETSI, NO_DFS, PSCAN_ETSIC, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F3_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(G3_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {FCCA, FCC, NO_DFS, NO_PSCAN, NO_REQ, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F1_2412_2462,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(G1_2412_2462,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(NG2_2422_2452,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO}, ++ ++ {MKKA, MKK, NO_DFS, PSCAN_MKKA | PSCAN_MKKA_G | PSCAN_MKKA1 | PSCAN_MKKA1_G | PSCAN_MKKA2 | PSCAN_MKKA2_G, DISALLOW_ADHOC_11A_TURB, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F2_2412_2462, F1_2467_2472, F2_2484_2484, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(G2_2412_2462, G1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(NG1_2422_2452,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO}, ++ ++ {MKKC, MKK, NO_DFS, NO_PSCAN, NO_REQ, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(G2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(NG1_2422_2452,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO}, ++ ++ {WORLD, ETSI, NO_DFS, NO_PSCAN, NO_REQ, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BM(F2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(G2_2412_2472,-1,-1,-1,-1,-1,-1,-1, -1, -1, -1, -1), ++ BM(T2_2437_2437,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(NG1_2422_2452,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO}, ++ ++ {WOR0_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, ++ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR01_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, ++ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, W1_2447_2457, -1, -1, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2417_2432, WG1_2447_2457, -1, -1, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR02_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, ++ BM(W1_5260_5320, W1_5180_5240,W1_5170_5230,W1_5745_5825,W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462, W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462, WG1_2472_2472,WG1_2417_2432, WG1_2447_2457, WG1_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {EU1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, ++ BM(W1_5260_5320, W1_5180_5240,W1_5170_5230,W1_5745_5825,W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462, W2_2472_2472,W1_2417_2432, W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462, WG2_2472_2472,WG1_2417_2432, WG1_2447_2457, WG2_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, ++ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR2_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, ++ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR3_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, ++ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462,W1_2472_2472,W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462,WG1_2472_2472,WG1_2417_2432,WG1_2447_2457,WG1_2467_2467,-1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR4_WORLD, NO_CTL, DFS_FCC3, PSCAN_WWR, ADHOC_NO_11A, ++ BM(W2_5260_5320, W2_5180_5240, F2_5745_5805, W2_5825_5825, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412,W1_2437_2442,W1_2462_2462, W1_2417_2432,W1_2447_2457,-1, -1, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412,WG1_2437_2442,WG1_2462_2462, WG1_2417_2432,WG1_2447_2457,-1, -1, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR5_ETSIC, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, ++ BM(W1_5260_5320, W2_5180_5240, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W2_2472_2472, W1_2417_2432, W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2472_2472, WG1_2417_2432, WG1_2447_2457, WG1_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WOR9_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, ++ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1), ++ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, W1_2447_2457, -1, -1, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2417_2432, WG1_2447_2457, -1, -1, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {WORA_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, ++ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO, ++ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), ++ BM(WG1_2412_2412, WG1_2437_2442, WG1_2462_2462, WG1_2472_2472, WG1_2417_2432, WG1_2447_2457, WG1_2467_2467, -1, -1, -1, -1, -1), ++ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), ++ BMZERO, ++ BMZERO}, ++ ++ {NULL1, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO, ++ BMZERO}, ++}; ++ ++struct cmode { ++ u16_t mode; ++ u32_t flags; ++}; ++ ++static const struct cmode modes[] = { ++ { HAL_MODE_TURBO, CHANNEL_ST}, /* TURBO means 11a Static Turbo */ ++ { HAL_MODE_11A, CHANNEL_A}, ++ { HAL_MODE_11B, CHANNEL_B}, ++ { HAL_MODE_11G, CHANNEL_G}, ++ { HAL_MODE_11G_TURBO, CHANNEL_108G}, ++ { HAL_MODE_11A_TURBO, CHANNEL_108A}, ++ { HAL_MODE_11NA, CHANNEL_A_HT40}, ++ { HAL_MODE_11NA, CHANNEL_A_HT20}, ++ { HAL_MODE_11NG, CHANNEL_G_HT40}, ++ { HAL_MODE_11NG, CHANNEL_G_HT20}, ++}; ++ ++/* ++ * Return the Wireless Mode Regulatory Domain based ++ * on the country code and the wireless mode. ++ */ ++u8_t GetWmRD(u16_t regionCode, u16_t channelFlag, REG_DOMAIN *rd) ++{ ++ s16_t i, found, regDmn; ++ u64_t flags=NO_REQ; ++ REG_DMN_PAIR_MAPPING *regPair=NULL; ++ ++ for (i=0, found=0; (iregDmn2GHz; ++ flags = regPair->flags2GHz; ++ } ++ else ++ { ++ regDmn = regPair->regDmn5GHz; ++ flags = regPair->flags5GHz; ++ } ++ ++ /* ++ * We either started with a unitary reg domain or we've found the ++ * unitary reg domain of the pair ++ */ ++ ++ for (i=0;ipscan &= regPair->pscanMask; ++ rd->flags = (u32_t)flags; ++ return TRUE; ++} ++ ++/* ++ * Test to see if the bitmask array is all zeros ++ */ ++u8_t isChanBitMaskZero(u64_t *bitmask) ++{ ++ u16_t i; ++ ++ for (i=0; ihpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ if (!GetWmRD(regionCode, ~ZM_REG_FLAG_CHANNEL_2GHZ, &rd5GHz)) ++ { ++ zm_debug_msg1("couldn't find unitary 5GHz reg domain for Region Code ", regionCode); ++ return; ++ } ++ if (!GetWmRD(regionCode, ZM_REG_FLAG_CHANNEL_2GHZ, &rd2GHz)) ++ { ++ zm_debug_msg1("couldn't find unitary 2GHz reg domain for Region Code ", regionCode); ++ return; ++ } ++ if (wd->regulationTable.regionCode == regionCode) ++ { ++ zm_debug_msg1("current region code is the same with Region Code ", regionCode); ++ return; ++ } ++ else ++ { ++ wd->regulationTable.regionCode = regionCode; ++ } ++ ++ next = 0; ++ ++ zmw_enter_critical_section(dev); ++ ++ for (cm = modes; cm < &modes[N(modes)]; cm++) ++ { ++ u16_t c; ++ u64_t *channelBM=NULL; ++ REG_DOMAIN *rd=NULL; ++ REG_DMN_FREQ_BAND *fband=NULL,*freqs=NULL; ++ ++ switch (cm->mode) ++ { ++ case HAL_MODE_TURBO: ++ //we don't have turbo mode so we disable it ++ //zm_debug_msg0("CWY - HAL_MODE_TURBO"); ++ channelBM = NULL; ++ //rd = &rd5GHz; ++ //channelBM = rd->chan11a_turbo; ++ //freqs = ®Dmn5GhzTurboFreq[0]; ++ //ctl = rd->conformanceTestLimit | CTL_TURBO; ++ break; ++ case HAL_MODE_11A: ++ if ((hpPriv->OpFlags & 0x1) != 0) ++ { ++ rd = &rd5GHz; ++ channelBM = rd->chan11a; ++ freqs = ®Dmn5GhzFreq[0]; ++ c_lo = 4920; //from channel 184 ++ c_hi = 5825; //to channel 165 ++ //ctl = rd->conformanceTestLimit; ++ //zm_debug_msg2("CWY - HAL_MODE_11A, channelBM = 0x", *channelBM); ++ } ++ //else ++ { ++ //channelBM = NULL; ++ } ++ break; ++ case HAL_MODE_11B: ++ //Disable 11B mode because it only has difference with 11G in PowerDFS Data, ++ //and we don't use this now. ++ //zm_debug_msg0("CWY - HAL_MODE_11B"); ++ channelBM = NULL; ++ //rd = &rd2GHz; ++ //channelBM = rd->chan11b; ++ //freqs = ®Dmn2GhzFreq[0]; ++ //ctl = rd->conformanceTestLimit | CTL_11B; ++ //zm_debug_msg2("CWY - HAL_MODE_11B, channelBM = 0x", *channelBM); ++ break; ++ case HAL_MODE_11G: ++ if ((hpPriv->OpFlags & 0x2) != 0) ++ { ++ rd = &rd2GHz; ++ channelBM = rd->chan11g; ++ freqs = ®Dmn2Ghz11gFreq[0]; ++ c_lo = 2412; //from channel 1 ++ //c_hi = 2462; //to channel 11 ++ c_hi = 2472; //to channel 13 ++ //ctl = rd->conformanceTestLimit | CTL_11G; ++ //zm_debug_msg2("CWY - HAL_MODE_11G, channelBM = 0x", *channelBM); ++ } ++ //else ++ { ++ //channelBM = NULL; ++ } ++ break; ++ case HAL_MODE_11G_TURBO: ++ //we don't have turbo mode so we disable it ++ //zm_debug_msg0("CWY - HAL_MODE_11G_TURBO"); ++ channelBM = NULL; ++ //rd = &rd2GHz; ++ //channelBM = rd->chan11g_turbo; ++ //freqs = ®Dmn2Ghz11gTurboFreq[0]; ++ //ctl = rd->conformanceTestLimit | CTL_108G; ++ break; ++ case HAL_MODE_11A_TURBO: ++ //we don't have turbo mode so we disable it ++ //zm_debug_msg0("CWY - HAL_MODE_11A_TURBO"); ++ channelBM = NULL; ++ //rd = &rd5GHz; ++ //channelBM = rd->chan11a_dyn_turbo; ++ //freqs = ®Dmn5GhzTurboFreq[0]; ++ //ctl = rd->conformanceTestLimit | CTL_108G; ++ break; ++ default: ++ zm_debug_msg1("Unkonwn HAL mode ", cm->mode); ++ continue; ++ } ++ if (channelBM == NULL) ++ { ++ //zm_debug_msg0("CWY - channelBM is NULL"); ++ continue; ++ } ++ if (isChanBitMaskZero(channelBM)) ++ { ++ //zm_debug_msg0("CWY - BitMask is Zero"); ++ continue; ++ } ++ ++ // RAY:Is it ok?? ++ if (freqs == NULL ) ++ { ++ continue; ++ } ++ ++ for (b=0;b<64*BMLEN; b++) ++ { ++ if (IS_BIT_SET(b,channelBM)) ++ { ++ fband = &freqs[b]; ++ ++ //zm_debug_msg1("CWY - lowChannel = ", fband->lowChannel); ++ //zm_debug_msg1("CWY - highChannel = ", fband->highChannel); ++ //zm_debug_msg1("CWY - channelSep = ", fband->channelSep); ++ for (c=fband->lowChannel; c <= fband->highChannel; ++ c += fband->channelSep) ++ { ++ ZM_HAL_CHANNEL icv; ++ ++ //Disable all DFS channel ++ if ((hpPriv->disableDfsCh==0) || (!(fband->useDfs & rd->dfsMask))) ++ { ++ if( fband->channelBW < 20 ) ++ { ++ /**************************************************************/ ++ /* */ ++ /* Temporary discard channel that BW < 20MHz (5 or 10MHz) */ ++ /* Our architecture does not implemnt it !!! */ ++ /* */ ++ /**************************************************************/ ++ continue; ++ } ++ if ((c >= c_lo) && (c <= c_hi)) ++ { ++ icv.channel = c; ++ icv.channelFlags = cm->flags; ++ icv.maxRegTxPower = fband->powerDfs; ++ if (fband->usePassScan & rd->pscan) ++ icv.channelFlags |= ZM_REG_FLAG_CHANNEL_PASSIVE; ++ else ++ icv.channelFlags &= ~ZM_REG_FLAG_CHANNEL_PASSIVE; ++ if (fband->useDfs & rd->dfsMask) ++ icv.privFlags = ZM_REG_FLAG_CHANNEL_DFS; ++ else ++ icv.privFlags = 0; ++ ++ /* For now disable radar for FCC3 */ ++ if (fband->useDfs & rd->dfsMask & DFS_FCC3) ++ { ++ icv.privFlags &= ~ZM_REG_FLAG_CHANNEL_DFS; ++ icv.privFlags |= ZM_REG_FLAG_CHANNEL_DFS_CLEAR; ++ } ++ ++ if(rd->flags & LIMIT_FRAME_4MS) ++ icv.privFlags |= ZM_REG_FLAG_CHANNEL_DFS_CLEAR; ++ ++ icv.minTxPower = 0; ++ icv.maxTxPower = 0; ++ ++ zm_assert(next < 60); ++ ++ wd->regulationTable.allowChannel[next++] = icv; ++ } ++ } ++ } ++ } ++ } ++ } ++ wd->regulationTable.allowChannelCnt = next; ++ ++ #if 0 ++ { ++ /* debug print */ ++ u32_t i; ++ DbgPrint("\n-------------------------------------------\n"); ++ DbgPrint("zfHpGetRegulationTable print all channel info regincode = 0x%x\n", wd->regulationTable.regionCode); ++ DbgPrint("index channel channelFlags maxRegTxPower privFlags useDFS\n"); ++ ++ for (i=0; iregulationTable.allowChannelCnt; i++) ++ { ++ DbgPrint("%02d %d %04x %02d %x %x\n", ++ i, ++ wd->regulationTable.allowChannel[i].channel, ++ wd->regulationTable.allowChannel[i].channelFlags, ++ wd->regulationTable.allowChannel[i].maxRegTxPower, ++ wd->regulationTable.allowChannel[i].privFlags, ++ wd->regulationTable.allowChannel[i].privFlags & ZM_REG_FLAG_CHANNEL_DFS); ++ } ++ } ++ #endif ++ ++ zmw_leave_critical_section(dev); ++} ++ ++void zfHpGetRegulationTablefromRegionCode(zdev_t* dev, u16_t regionCode) ++{ ++ u16_t c_lo = 2000, c_hi = 6000; //default channel is all enable ++ u8_t isoName[3] = {'N', 'A', 0}; ++ ++ zfCoreSetIsoName(dev, isoName); ++ ++ zfHpGetRegulationTable(dev, regionCode, c_lo, c_hi); ++} ++ ++void zfHpGetRegulationTablefromCountry(zdev_t* dev, u16_t CountryCode) ++{ ++ u16_t i; ++ u16_t c_lo = 2000, c_hi = 6000; //default channel is all enable ++ u16_t RegDomain; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ for (i = 0; i < N(allCountries); i++) ++ { ++ if (CountryCode == allCountries[i].countryCode) ++ { ++ RegDomain = allCountries[i].regDmnEnum; ++ ++ // read the ACU country code from EEPROM ++ zfCoreSetIsoName(dev, (u8_t*)allCountries[i].isoName); ++ ++ //zm_debug_msg_s("CWY - Country Name = ", allCountries[i].name); ++ ++ if (wd->regulationTable.regionCode != RegDomain) ++ { ++ //zm_debug_msg0("CWY - Change regulatory table"); ++ ++ zfHpGetRegulationTable(dev, RegDomain, c_lo, c_hi); ++ } ++ return; ++ } ++ } ++ zm_debug_msg1("Invalid CountryCode = ", CountryCode); ++} ++ ++u8_t zfHpGetRegulationTablefromISO(zdev_t* dev, u8_t *countryInfo, u8_t length) ++{ ++ u16_t i; ++ u16_t RegDomain; ++ u16_t c_lo = 2000, c_hi = 6000; //default channel is all enable ++ //u8_t strLen = 2; ++ ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ if (countryInfo[4] != 0x20) ++ { // with (I)ndoor/(O)utdoor info ++ //strLen = 3; ++ } ++ //zm_debug_msg_s("Desired iso name = ", isoName); ++ for (i = 0; i < N(allCountries); i++) ++ { ++ //zm_debug_msg_s("Current iso name = ", allCountries[i].isoName); ++ if (zfMemoryIsEqual((u8_t *)allCountries[i].isoName, (u8_t *)&countryInfo[2], length-1)) ++ { ++ //DbgPrint("Set current iso name = %s\n", allCountries[i].isoName); ++ //zm_debug_msg0("iso name hit!!"); ++ ++ RegDomain = allCountries[i].regDmnEnum; ++ ++ if (wd->regulationTable.regionCode != RegDomain) ++ { ++ zfHpGetRegulationTable(dev, RegDomain, c_lo, c_hi); ++ } ++ ++ //while (index < (countryInfo[1]+2)) ++ //{ ++ // if (countryInfo[index] <= 14) ++ // { ++ // /* calculate 2.4GHz low boundary channel frequency */ ++ // ch = countryInfo[index]; ++ // if ( ch == 14 ) ++ // c_lo = ZM_CH_G_14; ++ // else ++ // c_lo = ZM_CH_G_1 + (ch - 1) * 5; ++ // /* calculate 2.4GHz high boundary channel frequency */ ++ // ch = countryInfo[index] + countryInfo[index + 1] - 1; ++ // if ( ch == 14 ) ++ // c_hi = ZM_CH_G_14; ++ // else ++ // c_hi = ZM_CH_G_1 + (ch - 1) * 5; ++ // } ++ // else ++ // { ++ // /* calculate 5GHz low boundary channel frequency */ ++ // ch = countryInfo[index]; ++ // if ( (ch >= 184)&&(ch <= 196) ) ++ // c_lo = 4000 + ch*5; ++ // else ++ // c_lo = 5000 + ch*5; ++ // /* calculate 5GHz high boundary channel frequency */ ++ // ch = countryInfo[index] + countryInfo[index + 1] - 1; ++ // if ( (ch >= 184)&&(ch <= 196) ) ++ // c_hi = 4000 + ch*5; ++ // else ++ // c_hi = 5000 + ch*5; ++ // } ++ // ++ // zfHpGetRegulationTable(dev, RegDomain, c_lo, c_hi); ++ // ++ // index+=3; ++ //} ++ ++ return 0; ++ } ++ } ++ //zm_debug_msg_s("Invalid iso name = ", &countryInfo[2]); ++ return 1; ++} ++ ++const char* zfHpGetisoNamefromregionCode(zdev_t* dev, u16_t regionCode) ++{ ++ u16_t i; ++ ++ for (i = 0; i < N(allCountries); i++) ++ { ++ if (allCountries[i].regDmnEnum == regionCode) ++ { ++ return allCountries[i].isoName; ++ } ++ } ++ /* no matching item, return default */ ++ return allCountries[0].isoName; ++} ++ ++u16_t zfHpGetRegionCodeFromIsoName(zdev_t* dev, u8_t *countryIsoName) ++{ ++ u16_t i; ++ u16_t regionCode; ++ ++ /* if no matching item, return default */ ++ regionCode = DEF_REGDMN; ++ ++ for (i = 0; i < N(allCountries); i++) ++ { ++ if (zfMemoryIsEqual((u8_t *)allCountries[i].isoName, countryIsoName, 2)) ++ { ++ regionCode = allCountries[i].regDmnEnum; ++ break; ++ } ++ } ++ ++ return regionCode; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfHpDeleteAllowChannel */ ++/* Delete Allow Channel. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* freq : frequency */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Chao-Wen Yang ZyDAS Technology Corporation 2007.3 */ ++/* */ ++/************************************************************************/ ++u16_t zfHpDeleteAllowChannel(zdev_t* dev, u16_t freq) ++{ ++ u16_t i, bandIndex = 0; ++ u16_t dfs5GBand[][2] = {{5150, 5240}, {5260, 5350}, {5450, 5700}, {5725, 5825}}; ++ ++ zmw_get_wlan_dev(dev); ++ /* Find which band does this frequency belong */ ++ for (i = 0; i < 4; i++) ++ { ++ if ((freq >= dfs5GBand[i][0]) && (freq <= dfs5GBand[i][1])) ++ bandIndex = i + 1; ++ } ++ ++ if (bandIndex == 0) ++ { ++ /* 2.4G, don't care */ ++ return 0; ++ } ++ else ++ { ++ bandIndex--; ++ } ++ /* Set all channels in this band to passive scan */ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if ((wd->regulationTable.allowChannel[i].channel >= dfs5GBand[bandIndex][0]) && ++ (wd->regulationTable.allowChannel[i].channel <= dfs5GBand[bandIndex][1])) ++ { ++ /* if channel is not passive, set it to be passive and mark it */ ++ if ((wd->regulationTable.allowChannel[i].channelFlags & ++ ZM_REG_FLAG_CHANNEL_PASSIVE) == 0) ++ { ++ wd->regulationTable.allowChannel[i].channelFlags |= ++ (ZM_REG_FLAG_CHANNEL_PASSIVE | ZM_REG_FLAG_CHANNEL_CSA); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++u16_t zfHpAddAllowChannel(zdev_t* dev, u16_t freq) ++{ ++ u16_t i, j, arrayIndex; ++ ++ zmw_get_wlan_dev(dev); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel == freq) ++ break; ++ } ++ ++ if ( i == wd->regulationTable.allowChannelCnt) ++ { ++ for (j = 0; j < wd->regulationTable.allowChannelCnt; j++) ++ { ++ if (wd->regulationTable.allowChannel[j].channel > freq) ++ break; ++ } ++ ++ //zm_debug_msg1("CWY - add frequency = ", freq); ++ //zm_debug_msg1("CWY - channel array index = ", j); ++ ++ arrayIndex = j; ++ ++ if (arrayIndex < wd->regulationTable.allowChannelCnt) ++ { ++ for (j = wd->regulationTable.allowChannelCnt; j > arrayIndex; j--) ++ wd->regulationTable.allowChannel[j] = wd->regulationTable.allowChannel[j - 1]; ++ } ++ wd->regulationTable.allowChannel[arrayIndex].channel = freq; ++ ++ wd->regulationTable.allowChannelCnt++; ++ } ++ ++ return 0; ++} ++ ++u16_t zfHpIsDfsChannelNCS(zdev_t* dev, u16_t freq) ++{ ++ u8_t flag = ZM_REG_FLAG_CHANNEL_DFS; ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ //DbgPrint("DFS:freq=%d, chan=%d", freq, wd->regulationTable.allowChannel[i].channel); ++ if (wd->regulationTable.allowChannel[i].channel == freq) ++ { ++ flag = wd->regulationTable.allowChannel[i].privFlags; ++ break; ++ } ++ } ++ ++ return (flag & (ZM_REG_FLAG_CHANNEL_DFS|ZM_REG_FLAG_CHANNEL_DFS_CLEAR)); ++} ++ ++u16_t zfHpIsDfsChannel(zdev_t* dev, u16_t freq) ++{ ++ u8_t flag = ZM_REG_FLAG_CHANNEL_DFS; ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ //DbgPrint("DFS:freq=%d, chan=%d", freq, wd->regulationTable.allowChannel[i].channel); ++ if (wd->regulationTable.allowChannel[i].channel == freq) ++ { ++ flag = wd->regulationTable.allowChannel[i].privFlags; ++ break; ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return (flag & (ZM_REG_FLAG_CHANNEL_DFS|ZM_REG_FLAG_CHANNEL_DFS_CLEAR)); ++} ++ ++u16_t zfHpIsAllowedChannel(zdev_t* dev, u16_t freq) ++{ ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if (wd->regulationTable.allowChannel[i].channel == freq) ++ { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++u16_t zfHpFindFirstNonDfsChannel(zdev_t* dev, u16_t aBand) ++{ ++ u16_t chan = 2412; ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ for (i = 0; i < wd->regulationTable.allowChannelCnt; i++) ++ { ++ if ((wd->regulationTable.allowChannel[i].privFlags & ZM_REG_FLAG_CHANNEL_DFS) != 0) ++ { ++ if (aBand) ++ { ++ if (wd->regulationTable.allowChannel[i].channel > 3000) ++ { ++ chan = wd->regulationTable.allowChannel[i].channel; ++ break; ++ } ++ } ++ else ++ { ++ if (wd->regulationTable.allowChannel[i].channel < 3000) ++ { ++ chan = wd->regulationTable.allowChannel[i].channel; ++ break; ++ } ++ } ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ return chan; ++} ++ ++ ++/* porting from ACU */ ++/* save RegulatoryDomain in hpriv */ ++u8_t zfHpGetRegulatoryDomain(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ switch (wd->regulationTable.regionCode) ++ { ++ case NO_ENUMRD: ++ return 0; ++ break; ++ case FCC1_FCCA: ++ case FCC1_WORLD: ++ case FCC4_FCCA: ++ case FCC5_FCCA: ++ case FCC2_WORLD: ++ case FCC2_ETSIC: ++ case FCC3_FCCA: ++ case FCC3_WORLD: ++ case FCC1: ++ case FCC2: ++ case FCC3: ++ case FCC4: ++ case FCC5: ++ case FCCA: ++ return 0x10;//WG_AMERICAS DOT11_REG_DOMAIN_FCC United States ++ break; ++ ++ case FCC2_FCCA: ++ return 0x20;//DOT11_REG_DOMAIN_DOC Canada ++ break; ++ ++ case ETSI1_WORLD: ++ case ETSI3_ETSIA: ++ case ETSI2_WORLD: ++ case ETSI3_WORLD: ++ case ETSI4_WORLD: ++ case ETSI4_ETSIC: ++ case ETSI5_WORLD: ++ case ETSI6_WORLD: ++ case ETSI_RESERVED: ++ case ETSI1: ++ case ETSI2: ++ case ETSI3: ++ case ETSI4: ++ case ETSI5: ++ case ETSI6: ++ case ETSIA: ++ case ETSIB: ++ case ETSIC: ++ return 0x30;//WG_EMEA DOT11_REG_DOMAIN_ETSI Most of Europe ++ break; ++ ++ case MKK1_MKKA: ++ case MKK1_MKKB: ++ case MKK2_MKKA: ++ case MKK1_FCCA: ++ case MKK1_MKKA1: ++ case MKK1_MKKA2: ++ case MKK1_MKKC: ++ case MKK3_MKKB: ++ case MKK3_MKKA2: ++ case MKK3_MKKC: ++ case MKK4_MKKB: ++ case MKK4_MKKA2: ++ case MKK4_MKKC: ++ case MKK5_MKKB: ++ case MKK5_MKKA2: ++ case MKK5_MKKC: ++ case MKK6_MKKB: ++ case MKK6_MKKA2: ++ case MKK6_MKKC: ++ case MKK7_MKKB: ++ case MKK7_MKKA: ++ case MKK7_MKKC: ++ case MKK8_MKKB: ++ case MKK8_MKKA2: ++ case MKK8_MKKC: ++ case MKK6_MKKA1: ++ case MKK6_FCCA: ++ case MKK7_MKKA1: ++ case MKK7_FCCA: ++ case MKK9_FCCA: ++ case MKK9_MKKA1: ++ case MKK9_MKKC: ++ case MKK9_MKKA2: ++ case MKK10_FCCA: ++ case MKK10_MKKA1: ++ case MKK10_MKKC: ++ case MKK10_MKKA2: ++ case MKK11_MKKA: ++ case MKK11_FCCA: ++ case MKK11_MKKA1: ++ case MKK11_MKKC: ++ case MKK11_MKKA2: ++ case MKK12_MKKA: ++ case MKK12_FCCA: ++ case MKK12_MKKA1: ++ case MKK12_MKKC: ++ case MKK12_MKKA2: ++ case MKK3_MKKA: ++ case MKK3_MKKA1: ++ case MKK3_FCCA: ++ case MKK4_MKKA: ++ case MKK4_MKKA1: ++ case MKK4_FCCA: ++ case MKK9_MKKA: ++ case MKK10_MKKA: ++ case MKK1: ++ case MKK2: ++ case MKK3: ++ case MKK4: ++ case MKK5: ++ case MKK6: ++ case MKK7: ++ case MKK8: ++ case MKK9: ++ case MKK10: ++ case MKK11: ++ case MKK12: ++ case MKKA: ++ case MKKC: ++ return 0x40;//WG_JAPAN DOT11_REG_DOMAIN_MKK Japan ++ break; ++ ++ default: ++ break; ++ } ++ return 0xFF;// Didn't input RegDmn by mean to distinguish by customer ++ ++} ++ ++ ++void zfHpDisableDfsChannel(zdev_t* dev, u8_t disableFlag) ++{ ++ zmw_get_wlan_dev(dev); ++ ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ hpPriv->disableDfsCh = disableFlag; ++ return; ++} +--- /dev/null ++++ b/drivers/staging/otus/hal/hpreg.h +@@ -0,0 +1,524 @@ ++/* ++ * Copyright (c) 2000-2005 ZyDAS Technology Corporation ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : hpreg.h */ ++/* */ ++/* Abstract */ ++/* This module contains Regulatory Table definitions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _HPREG_H ++#define _HPREG_H ++ ++typedef u16_t HAL_CTRY_CODE; /* country code */ ++typedef u16_t HAL_REG_DOMAIN; /* regulatory domain code */ ++typedef enum { ++ AH_FALSE = 0, /* NB: lots of code assumes false is zero */ ++ AH_TRUE = 1, ++} HAL_BOOL; ++ ++ ++/* ++ * Country/Region Codes from MS WINNLS.H ++ * Numbering from ISO 3166 ++ */ ++enum CountryCode { ++ CTRY_ALBANIA = 8, /* Albania */ ++ CTRY_ALGERIA = 12, /* Algeria */ ++ CTRY_ARGENTINA = 32, /* Argentina */ ++ CTRY_ARMENIA = 51, /* Armenia */ ++ CTRY_AUSTRALIA = 36, /* Australia */ ++ CTRY_AUSTRIA = 40, /* Austria */ ++ CTRY_AZERBAIJAN = 31, /* Azerbaijan */ ++ CTRY_BAHRAIN = 48, /* Bahrain */ ++ CTRY_BELARUS = 112, /* Belarus */ ++ CTRY_BELGIUM = 56, /* Belgium */ ++ CTRY_BELIZE = 84, /* Belize */ ++ CTRY_BOLIVIA = 68, /* Bolivia */ ++ CTRY_BOSNIA = 70, /* Bosnia */ ++ CTRY_BRAZIL = 76, /* Brazil */ ++ CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */ ++ CTRY_BULGARIA = 100, /* Bulgaria */ ++ CTRY_CANADA = 124, /* Canada */ ++ CTRY_CHILE = 152, /* Chile */ ++ CTRY_CHINA = 156, /* People's Republic of China */ ++ CTRY_COLOMBIA = 170, /* Colombia */ ++ CTRY_COSTA_RICA = 188, /* Costa Rica */ ++ CTRY_CROATIA = 191, /* Croatia */ ++ CTRY_CYPRUS = 196, /* Cyprus */ ++ CTRY_CZECH = 203, /* Czech Republic */ ++ CTRY_DENMARK = 208, /* Denmark */ ++ CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */ ++ CTRY_ECUADOR = 218, /* Ecuador */ ++ CTRY_EGYPT = 818, /* Egypt */ ++ CTRY_EL_SALVADOR = 222, /* El Salvador */ ++ CTRY_ESTONIA = 233, /* Estonia */ ++ CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */ ++ CTRY_FINLAND = 246, /* Finland */ ++ CTRY_FRANCE = 250, /* France */ ++ CTRY_FRANCE2 = 255, /* France2 */ ++ CTRY_GEORGIA = 268, /* Georgia */ ++ CTRY_GERMANY = 276, /* Germany */ ++ CTRY_GREECE = 300, /* Greece */ ++ CTRY_GUATEMALA = 320, /* Guatemala */ ++ CTRY_HONDURAS = 340, /* Honduras */ ++ CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */ ++ CTRY_HUNGARY = 348, /* Hungary */ ++ CTRY_ICELAND = 352, /* Iceland */ ++ CTRY_INDIA = 356, /* India */ ++ CTRY_INDONESIA = 360, /* Indonesia */ ++ CTRY_IRAN = 364, /* Iran */ ++ CTRY_IRAQ = 368, /* Iraq */ ++ CTRY_IRELAND = 372, /* Ireland */ ++ CTRY_ISRAEL = 376, /* Israel */ ++ CTRY_ISRAEL2 = 377, /* Israel2 */ ++ CTRY_ITALY = 380, /* Italy */ ++ CTRY_JAMAICA = 388, /* Jamaica */ ++ CTRY_JAPAN = 392, /* Japan */ ++ CTRY_JAPAN1 = 393, /* Japan (JP1) */ ++ CTRY_JAPAN2 = 394, /* Japan (JP0) */ ++ CTRY_JAPAN3 = 395, /* Japan (JP1-1) */ ++ CTRY_JAPAN4 = 396, /* Japan (JE1) */ ++ CTRY_JAPAN5 = 397, /* Japan (JE2) */ ++ CTRY_JAPAN6 = 399, /* Japan (JP6) */ ++ ++ CTRY_JAPAN7 = 4007, /* Japan (J7) */ ++ CTRY_JAPAN8 = 4008, /* Japan (J8) */ ++ CTRY_JAPAN9 = 4009, /* Japan (J9) */ ++ ++ CTRY_JAPAN10 = 4010, /* Japan (J10) */ ++ CTRY_JAPAN11 = 4011, /* Japan (J11) */ ++ CTRY_JAPAN12 = 4012, /* Japan (J12) */ ++ ++ CTRY_JAPAN13 = 4013, /* Japan (J13) */ ++ CTRY_JAPAN14 = 4014, /* Japan (J14) */ ++ CTRY_JAPAN15 = 4015, /* Japan (J15) */ ++ ++ CTRY_JAPAN16 = 4016, /* Japan (J16) */ ++ CTRY_JAPAN17 = 4017, /* Japan (J17) */ ++ CTRY_JAPAN18 = 4018, /* Japan (J18) */ ++ ++ CTRY_JAPAN19 = 4019, /* Japan (J19) */ ++ CTRY_JAPAN20 = 4020, /* Japan (J20) */ ++ CTRY_JAPAN21 = 4021, /* Japan (J21) */ ++ ++ CTRY_JAPAN22 = 4022, /* Japan (J22) */ ++ CTRY_JAPAN23 = 4023, /* Japan (J23) */ ++ CTRY_JAPAN24 = 4024, /* Japan (J24) */ ++ ++ CTRY_JAPAN25 = 4025, /* Japan (J25) */ ++ CTRY_JAPAN26 = 4026, /* Japan (J26) */ ++ CTRY_JAPAN27 = 4027, /* Japan (J27) */ ++ ++ CTRY_JAPAN28 = 4028, /* Japan (J28) */ ++ CTRY_JAPAN29 = 4029, /* Japan (J29) */ ++ CTRY_JAPAN30 = 4030, /* Japan (J30) */ ++ ++ CTRY_JAPAN31 = 4031, /* Japan (J31) */ ++ CTRY_JAPAN32 = 4032, /* Japan (J32) */ ++ CTRY_JAPAN33 = 4033, /* Japan (J33) */ ++ ++ CTRY_JAPAN34 = 4034, /* Japan (J34) */ ++ CTRY_JAPAN35 = 4035, /* Japan (J35) */ ++ CTRY_JAPAN36 = 4036, /* Japan (J36) */ ++ ++ CTRY_JAPAN37 = 4037, /* Japan (J37) */ ++ CTRY_JAPAN38 = 4038, /* Japan (J38) */ ++ CTRY_JAPAN39 = 4039, /* Japan (J39) */ ++ ++ CTRY_JAPAN40 = 4040, /* Japan (J40) */ ++ CTRY_JAPAN41 = 4041, /* Japan (J41) */ ++ CTRY_JAPAN42 = 4042, /* Japan (J42) */ ++ CTRY_JAPAN43 = 4043, /* Japan (J43) */ ++ CTRY_JAPAN44 = 4044, /* Japan (J44) */ ++ CTRY_JAPAN45 = 4045, /* Japan (J45) */ ++ CTRY_JAPAN46 = 4046, /* Japan (J46) */ ++ CTRY_JAPAN47 = 4047, /* Japan (J47) */ ++ CTRY_JAPAN48 = 4048, /* Japan (J48) */ ++ CTRY_JAPAN49 = 4049, /* Japan (J49) */ ++ ++ CTRY_JAPAN50 = 4050, /* Japan (J50) */ ++ CTRY_JAPAN51 = 4051, /* Japan (J51) */ ++ CTRY_JAPAN52 = 4052, /* Japan (J52) */ ++ CTRY_JAPAN53 = 4053, /* Japan (J53) */ ++ CTRY_JAPAN54 = 4054, /* Japan (J54) */ ++ ++ CTRY_JORDAN = 400, /* Jordan */ ++ CTRY_KAZAKHSTAN = 398, /* Kazakhstan */ ++ CTRY_KENYA = 404, /* Kenya */ ++ CTRY_KOREA_NORTH = 408, /* North Korea */ ++ CTRY_KOREA_ROC = 410, /* South Korea */ ++ CTRY_KOREA_ROC2 = 411, /* South Korea */ ++ CTRY_KOREA_ROC3 = 412, /* South Korea */ ++ CTRY_KUWAIT = 414, /* Kuwait */ ++ CTRY_LATVIA = 428, /* Latvia */ ++ CTRY_LEBANON = 422, /* Lebanon */ ++ CTRY_LIBYA = 434, /* Libya */ ++ CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */ ++ CTRY_LITHUANIA = 440, /* Lithuania */ ++ CTRY_LUXEMBOURG = 442, /* Luxembourg */ ++ CTRY_MACAU = 446, /* Macau */ ++ CTRY_MACEDONIA = 807, /* the Former Yugoslav Republic of Macedonia */ ++ CTRY_MALAYSIA = 458, /* Malaysia */ ++ CTRY_MALTA = 470, /* Malta */ ++ CTRY_MEXICO = 484, /* Mexico */ ++ CTRY_MONACO = 492, /* Principality of Monaco */ ++ CTRY_MOROCCO = 504, /* Morocco */ ++ CTRY_NETHERLANDS = 528, /* Netherlands */ ++ CTRY_NETHERLANDS_ANT = 530, /* Netherlands-Antellis */ ++ CTRY_NEW_ZEALAND = 554, /* New Zealand */ ++ CTRY_NICARAGUA = 558, /* Nicaragua */ ++ CTRY_NORWAY = 578, /* Norway */ ++ CTRY_OMAN = 512, /* Oman */ ++ CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */ ++ CTRY_PANAMA = 591, /* Panama */ ++ CTRY_PARAGUAY = 600, /* Paraguay */ ++ CTRY_PERU = 604, /* Peru */ ++ CTRY_PHILIPPINES = 608, /* Republic of the Philippines */ ++ CTRY_POLAND = 616, /* Poland */ ++ CTRY_PORTUGAL = 620, /* Portugal */ ++ CTRY_PUERTO_RICO = 630, /* Puerto Rico */ ++ CTRY_QATAR = 634, /* Qatar */ ++ CTRY_ROMANIA = 642, /* Romania */ ++ CTRY_RUSSIA = 643, /* Russia */ ++ CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */ ++ CTRY_SERBIA_MONT = 891, /* Serbia and Montenegro */ ++ CTRY_SINGAPORE = 702, /* Singapore */ ++ CTRY_SLOVAKIA = 703, /* Slovak Republic */ ++ CTRY_SLOVENIA = 705, /* Slovenia */ ++ CTRY_SOUTH_AFRICA = 710, /* South Africa */ ++ CTRY_SPAIN = 724, /* Spain */ ++ CTRY_SRILANKA = 144, /* Srilanka */ ++ CTRY_SWEDEN = 752, /* Sweden */ ++ CTRY_SWITZERLAND = 756, /* Switzerland */ ++ CTRY_SYRIA = 760, /* Syria */ ++ CTRY_TAIWAN = 158, /* Taiwan */ ++ CTRY_THAILAND = 764, /* Thailand */ ++ CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */ ++ CTRY_TUNISIA = 788, /* Tunisia */ ++ CTRY_TURKEY = 792, /* Turkey */ ++ CTRY_UAE = 784, /* U.A.E. */ ++ CTRY_UKRAINE = 804, /* Ukraine */ ++ CTRY_UNITED_KINGDOM = 826, /* United Kingdom */ ++ CTRY_UNITED_STATES = 840, /* United States */ ++ CTRY_UNITED_STATES_FCC49 = 842, /* United States (Public Safety)*/ ++ CTRY_URUGUAY = 858, /* Uruguay */ ++ CTRY_UZBEKISTAN = 860, /* Uzbekistan */ ++ CTRY_VENEZUELA = 862, /* Venezuela */ ++ CTRY_VIET_NAM = 704, /* Viet Nam */ ++ CTRY_YEMEN = 887, /* Yemen */ ++ CTRY_ZIMBABWE = 716 /* Zimbabwe */ ++}; ++ ++/* Enumerated Regulatory Domain Information 8 bit values indicate that ++ * the regdomain is really a pair of unitary regdomains. 12 bit values ++ * are the real unitary regdomains and are the only ones which have the ++ * frequency bitmasks and flags set. ++ */ ++enum EnumRd { ++ /* ++ * The following regulatory domain definitions are ++ * found in the EEPROM. Each regulatory domain ++ * can operate in either a 5GHz or 2.4GHz wireless mode or ++ * both 5GHz and 2.4GHz wireless modes. ++ * In general, the value holds no special ++ * meaning and is used to decode into either specific ++ * 2.4GHz or 5GHz wireless mode for that particular ++ * regulatory domain. ++ */ ++ NO_ENUMRD = 0x00, ++ NULL1_WORLD = 0x03, /* For 11b-only countries (no 11a allowed) */ ++ NULL1_ETSIB = 0x07, /* Israel */ ++ NULL1_ETSIC = 0x08, ++ FCC1_FCCA = 0x10, /* USA */ ++ FCC1_WORLD = 0x11, /* Hong Kong */ ++ FCC4_FCCA = 0x12, /* USA - Public Safety */ ++ FCC5_FCCA = 0x13, /* USA - with no DFS (UNII-1 + UNII-3 only) */ ++ FCC6_FCCA = 0x14, /* Canada */ ++ ++ FCC2_FCCA = 0x20, /* Canada */ ++ FCC2_WORLD = 0x21, /* Australia & HK */ ++ FCC2_ETSIC = 0x22, ++ FCC6_WORLD = 0x23, /* Australia */ ++ ++ FRANCE_RES = 0x31, /* Legacy France for OEM */ ++ FCC3_FCCA = 0x3A, /* USA & Canada w/5470 band, 11h, DFS enabled */ ++ FCC3_WORLD = 0x3B, /* USA & Canada w/5470 band, 11h, DFS enabled */ ++ ++ ETSI1_WORLD = 0x37, ++ ETSI3_ETSIA = 0x32, /* France (optional) */ ++ ETSI2_WORLD = 0x35, /* Hungary & others */ ++ ETSI3_WORLD = 0x36, /* France & others */ ++ ETSI4_WORLD = 0x30, ++ ETSI4_ETSIC = 0x38, ++ ETSI5_WORLD = 0x39, ++ ETSI6_WORLD = 0x34, /* Bulgaria */ ++ ETSI_RESERVED = 0x33, /* Reserved (Do not used) */ ++ ++ MKK1_MKKA = 0x40, /* Japan (JP1) */ ++ MKK1_MKKB = 0x41, /* Japan (JP0) */ ++ APL4_WORLD = 0x42, /* Singapore */ ++ MKK2_MKKA = 0x43, /* Japan with 4.9G channels */ ++ APL_RESERVED = 0x44, /* Reserved (Do not used) */ ++ APL2_WORLD = 0x45, /* Korea */ ++ APL2_APLC = 0x46, ++ APL3_WORLD = 0x47, ++ MKK1_FCCA = 0x48, /* Japan (JP1-1) */ ++ APL2_APLD = 0x49, /* Korea with 2.3G channels */ ++ MKK1_MKKA1 = 0x4A, /* Japan (JE1) */ ++ MKK1_MKKA2 = 0x4B, /* Japan (JE2) */ ++ MKK1_MKKC = 0x4C, /* Japan (MKK1_MKKA,except Ch14) */ ++ ++ APL3_FCCA = 0x50, ++ APL1_WORLD = 0x52, /* Latin America */ ++ APL1_FCCA = 0x53, ++ APL1_APLA = 0x54, ++ APL1_ETSIC = 0x55, ++ APL2_ETSIC = 0x56, /* Venezuela */ ++ APL2_FCCA = 0x57, /* new Latin America */ ++ APL5_WORLD = 0x58, /* Chile */ ++ APL6_WORLD = 0x5B, /* Singapore */ ++ APL7_FCCA = 0x5C, /* Taiwan 5.47 Band */ ++ APL8_WORLD = 0x5D, /* Malaysia 5GHz */ ++ APL9_WORLD = 0x5E, /* Korea 5GHz */ ++ ++ /* ++ * World mode SKUs ++ */ ++ WOR0_WORLD = 0x60, /* World0 (WO0 SKU) */ ++ WOR1_WORLD = 0x61, /* World1 (WO1 SKU) */ ++ WOR2_WORLD = 0x62, /* World2 (WO2 SKU) */ ++ WOR3_WORLD = 0x63, /* World3 (WO3 SKU) */ ++ WOR4_WORLD = 0x64, /* World4 (WO4 SKU) */ ++ WOR5_ETSIC = 0x65, /* World5 (WO5 SKU) */ ++ ++ WOR01_WORLD = 0x66, /* World0-1 (WW0-1 SKU) */ ++ WOR02_WORLD = 0x67, /* World0-2 (WW0-2 SKU) */ ++ EU1_WORLD = 0x68, /* Same as World0-2 (WW0-2 SKU), except active scan ch1-13. No ch14 */ ++ ++ WOR9_WORLD = 0x69, /* World9 (WO9 SKU) */ ++ WORA_WORLD = 0x6A, /* WorldA (WOA SKU) */ ++ ++ MKK3_MKKB = 0x80, /* Japan UNI-1 even + MKKB */ ++ MKK3_MKKA2 = 0x81, /* Japan UNI-1 even + MKKA2 */ ++ MKK3_MKKC = 0x82, /* Japan UNI-1 even + MKKC */ ++ ++ MKK4_MKKB = 0x83, /* Japan UNI-1 even + UNI-2 + MKKB */ ++ MKK4_MKKA2 = 0x84, /* Japan UNI-1 even + UNI-2 + MKKA2 */ ++ MKK4_MKKC = 0x85, /* Japan UNI-1 even + UNI-2 + MKKC */ ++ ++ MKK5_MKKB = 0x86, /* Japan UNI-1 even + UNI-2 + mid-band + MKKB */ ++ MKK5_MKKA2 = 0x87, /* Japan UNI-1 even + UNI-2 + mid-band + MKKA2 */ ++ MKK5_MKKC = 0x88, /* Japan UNI-1 even + UNI-2 + mid-band + MKKC */ ++ ++ MKK6_MKKB = 0x89, /* Japan UNI-1 even + UNI-1 odd MKKB */ ++ MKK6_MKKA2 = 0x8A, /* Japan UNI-1 even + UNI-1 odd + MKKA2 */ ++ MKK6_MKKC = 0x8B, /* Japan UNI-1 even + UNI-1 odd + MKKC */ ++ ++ MKK7_MKKB = 0x8C, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKB */ ++ MKK7_MKKA = 0x8D, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA2 */ ++ MKK7_MKKC = 0x8E, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKC */ ++ ++ MKK8_MKKB = 0x8F, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB */ ++ MKK8_MKKA2 = 0x90, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKA2 */ ++ MKK8_MKKC = 0x91, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKC */ ++ ++ MKK6_MKKA1 = 0xF8, /* Japan UNI-1 even + UNI-1 odd + MKKA1 */ ++ MKK6_FCCA = 0xF9, /* Japan UNI-1 even + UNI-1 odd + FCCA */ ++ MKK7_MKKA1 = 0xFA, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA1 */ ++ MKK7_FCCA = 0xFB, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + FCCA */ ++ MKK9_FCCA = 0xFC, /* Japan UNI-1 even + 4.9GHz + FCCA */ ++ MKK9_MKKA1 = 0xFD, /* Japan UNI-1 even + 4.9GHz + MKKA1 */ ++ MKK9_MKKC = 0xFE, /* Japan UNI-1 even + 4.9GHz + MKKC */ ++ MKK9_MKKA2 = 0xFF, /* Japan UNI-1 even + 4.9GHz + MKKA2 */ ++ ++ MKK10_FCCA = 0xD0, /* Japan UNI-1 even + UNI-2 + 4.9GHz + FCCA */ ++ MKK10_MKKA1 = 0xD1, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA1 */ ++ MKK10_MKKC = 0xD2, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKC */ ++ MKK10_MKKA2 = 0xD3, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA2 */ ++ ++ MKK11_MKKA = 0xD4, /* Japan UNI-1 even + UNI-2 + Midband + 4.9GHz + MKKA */ ++ MKK11_FCCA = 0xD5, /* Japan UNI-1 even + UNI-2 + Midband + 4.9GHz + FCCA */ ++ MKK11_MKKA1 = 0xD6, /* Japan UNI-1 even + UNI-2 + Midband + 4.9GHz + MKKA1 */ ++ MKK11_MKKC = 0xD7, /* Japan UNI-1 even + UNI-2 + Midband + 4.9GHz + MKKC */ ++ MKK11_MKKA2 = 0xD8, /* Japan UNI-1 even + UNI-2 + Midband + 4.9GHz + MKKA2 */ ++ ++ MKK12_MKKA = 0xD9, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + Midband + 4.9GHz + MKKA */ ++ MKK12_FCCA = 0xDA, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + Midband + 4.9GHz + FCCA */ ++ MKK12_MKKA1 = 0xDB, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + Midband + 4.9GHz + MKKA1 */ ++ MKK12_MKKC = 0xDC, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + Midband + 4.9GHz + MKKC */ ++ MKK12_MKKA2 = 0xDD, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + Midband + 4.9GHz + MKKA2 */ ++ ++ /* Following definitions are used only by s/w to map old ++ * Japan SKUs. ++ */ ++ MKK3_MKKA = 0xF0, /* Japan UNI-1 even + MKKA */ ++ MKK3_MKKA1 = 0xF1, /* Japan UNI-1 even + MKKA1 */ ++ MKK3_FCCA = 0xF2, /* Japan UNI-1 even + FCCA */ ++ MKK4_MKKA = 0xF3, /* Japan UNI-1 even + UNI-2 + MKKA */ ++ MKK4_MKKA1 = 0xF4, /* Japan UNI-1 even + UNI-2 + MKKA1 */ ++ MKK4_FCCA = 0xF5, /* Japan UNI-1 even + UNI-2 + FCCA */ ++ MKK9_MKKA = 0xF6, /* Japan UNI-1 even + 4.9GHz + MKKA*/ ++ MKK10_MKKA = 0xF7, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA */ ++ ++ /* ++ * Regulator domains ending in a number (e.g. APL1, ++ * MK1, ETSI4, etc) apply to 5GHz channel and power ++ * information. Regulator domains ending in a letter ++ * (e.g. APLA, FCCA, etc) apply to 2.4GHz channel and ++ * power information. ++ */ ++ APL1 = 0x0150, /* LAT & Asia */ ++ APL2 = 0x0250, /* LAT & Asia */ ++ APL3 = 0x0350, /* Taiwan */ ++ APL4 = 0x0450, /* Jordan */ ++ APL5 = 0x0550, /* Chile */ ++ APL6 = 0x0650, /* Singapore */ ++ APL7 = 0x0750, /* Taiwan Middle */ ++ APL8 = 0x0850, /* Malaysia */ ++ APL9 = 0x0950, /* Korea (South) ROC 3 */ ++ ++ ETSI1 = 0x0130, /* Europe & others */ ++ ETSI2 = 0x0230, /* Europe & others */ ++ ETSI3 = 0x0330, /* Europe & others */ ++ ETSI4 = 0x0430, /* Europe & others */ ++ ETSI5 = 0x0530, /* Europe & others */ ++ ETSI6 = 0x0630, /* Europe & others */ ++ ETSIA = 0x0A30, /* France */ ++ ETSIB = 0x0B30, /* Israel */ ++ ETSIC = 0x0C30, /* Latin America */ ++ ++ FCC1 = 0x0110, /* US & others */ ++ FCC2 = 0x0120, /* Canada, Australia & New Zealand */ ++ FCC3 = 0x0160, /* US w/new middle band & DFS */ ++ FCC4 = 0x0165, /* US Public Safety */ ++ FCC5 = 0x0510, /* US no DFS */ ++ FCC6 = 0x0610, /* Canada & Australia */ ++ ++ FCCA = 0x0A10, ++ ++ APLD = 0x0D50, /* South Korea */ ++ ++ MKK1 = 0x0140, /* Japan (UNI-1 odd)*/ ++ MKK2 = 0x0240, /* Japan (4.9 GHz + UNI-1 odd) */ ++ MKK3 = 0x0340, /* Japan (UNI-1 even) */ ++ MKK4 = 0x0440, /* Japan (UNI-1 even + UNI-2) */ ++ MKK5 = 0x0540, /* Japan (UNI-1 even + UNI-2 + mid-band) */ ++ MKK6 = 0x0640, /* Japan (UNI-1 odd + UNI-1 even) */ ++ MKK7 = 0x0740, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 */ ++ MKK8 = 0x0840, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 + mid-band) */ ++ MKK9 = 0x0940, /* Japan (UNI-1 even + 4.9 GHZ) */ ++ MKK10 = 0x0B40, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ ++ MKK11 = 0x1140, /* Japan (UNI-1 even + UNI-2 + mid-band + 4.9 GHZ) */ ++ MKK12 = 0x1240, /* Japan (UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9 GHZ) */ ++ MKKA = 0x0A40, /* Japan */ ++ MKKC = 0x0A50, ++ ++ NULL1 = 0x0198, ++ WORLD = 0x0199, ++ DEBUG_REG_DMN = 0x01ff, ++}; ++ ++/* channelFlags */ ++#define ZM_REG_FLAG_CHANNEL_CW_INT 0x0002 /* CW interference detected on channel */ ++#define ZM_REG_FLAG_CHANNEL_TURBO 0x0010 /* Turbo Channel */ ++#define ZM_REG_FLAG_CHANNEL_CCK 0x0020 /* CCK channel */ ++#define ZM_REG_FLAG_CHANNEL_OFDM 0x0040 /* OFDM channel */ ++#define ZM_REG_FLAG_CHANNEL_2GHZ 0x0080 /* 2 GHz spectrum channel. */ ++#define ZM_REG_FLAG_CHANNEL_5GHZ 0x0100 /* 5 GHz spectrum channel */ ++#define ZM_REG_FLAG_CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed in the channel */ ++#define ZM_REG_FLAG_CHANNEL_DYN 0x0400 /* dynamic CCK-OFDM channel */ ++#define ZM_REG_FLAG_CHANNEL_XR 0x0800 /* XR channel */ ++#define ZM_REG_FLAG_CHANNEL_CSA 0x1000 /* Channel by CSA(Channel Switch Announcement) */ ++#define ZM_REG_FLAG_CHANNEL_STURBO 0x2000 /* Static turbo, no 11a-only usage */ ++#define ZM_REG_FLAG_CHANNEL_HALF 0x4000 /* Half rate channel */ ++#define ZM_REG_FLAG_CHANNEL_QUARTER 0x8000 /* Quarter rate channel */ ++ ++/* channelFlags */ ++#define CHANNEL_CW_INT 0x0002 /* CW interference detected on channel */ ++#define CHANNEL_TURBO 0x0010 /* Turbo Channel */ ++#define CHANNEL_CCK 0x0020 /* CCK channel */ ++#define CHANNEL_OFDM 0x0040 /* OFDM channel */ ++#define CHANNEL_2GHZ 0x0080 /* 2 GHz spectrum channel. */ ++#define CHANNEL_5GHZ 0x0100 /* 5 GHz spectrum channel */ ++#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed in the channel */ ++#define CHANNEL_DYN 0x0400 /* dynamic CCK-OFDM channel */ ++#define CHANNEL_XR 0x0800 /* XR channel */ ++#define CHANNEL_STURBO 0x2000 /* Static turbo, no 11a-only usage */ ++#define CHANNEL_HALF 0x4000 /* Half rate channel */ ++#define CHANNEL_QUARTER 0x8000 /* Quarter rate channel */ ++#define CHANNEL_HT20 0x10000 /* HT20 channel */ ++#define CHANNEL_HT40 0x20000 /* HT40 channel */ ++#define CHANNEL_HT40U 0x40000 /* control channel can be upper channel */ ++#define CHANNEL_HT40L 0x80000 /* control channel can be lower channel */ ++ ++/* privFlags */ ++#define ZM_REG_FLAG_CHANNEL_INTERFERENCE 0x01 /* Software use: channel interference ++ used for as AR as well as RADAR ++ interference detection */ ++#define ZM_REG_FLAG_CHANNEL_DFS 0x02 /* DFS required on channel */ ++#define ZM_REG_FLAG_CHANNEL_4MS_LIMIT 0x04 /* 4msec packet limit on this channel */ ++#define ZM_REG_FLAG_CHANNEL_DFS_CLEAR 0x08 /* if channel has been checked for DFS */ ++ ++#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) ++#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) ++#define CHANNEL_PUREG (CHANNEL_2GHZ|CHANNEL_OFDM) ++#ifdef notdef ++#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_DYN) ++#else ++#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) ++#endif ++#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) ++#define CHANNEL_ST (CHANNEL_T|CHANNEL_STURBO) ++#define CHANNEL_108G (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO) ++#define CHANNEL_108A CHANNEL_T ++#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR) ++#define CHANNEL_G_HT (CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_HT20) ++#define CHANNEL_A_HT (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_HT20) ++ ++#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) ++#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) ++#define CHANNEL_G_HT40 (CHANNEL_2GHZ|CHANNEL_HT20|CHANNEL_HT40) ++#define CHANNEL_A_HT40 (CHANNEL_5GHZ|CHANNEL_HT20|CHANNEL_HT40) ++#define CHANNEL_ALL \ ++ (CHANNEL_OFDM|CHANNEL_CCK| CHANNEL_2GHZ | CHANNEL_5GHZ | CHANNEL_TURBO | CHANNEL_HT20 | CHANNEL_HT40) ++#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL &~ CHANNEL_TURBO) ++ ++enum { ++ HAL_MODE_11A = 0x001, /* 11a channels */ ++ HAL_MODE_TURBO = 0x002, /* 11a turbo-only channels */ ++ HAL_MODE_11B = 0x004, /* 11b channels */ ++ HAL_MODE_PUREG = 0x008, /* 11g channels (OFDM only) */ ++#ifdef notdef ++ HAL_MODE_11G = 0x010, /* 11g channels (OFDM/CCK) */ ++#else ++ HAL_MODE_11G = 0x008, /* XXX historical */ ++#endif ++ HAL_MODE_108G = 0x020, /* 11a+Turbo channels */ ++ HAL_MODE_108A = 0x040, /* 11g+Turbo channels */ ++ HAL_MODE_XR = 0x100, /* XR channels */ ++ HAL_MODE_11A_HALF_RATE = 0x200, /* 11A half rate channels */ ++ HAL_MODE_11A_QUARTER_RATE = 0x400, /* 11A quarter rate channels */ ++ HAL_MODE_11NG = 0x4000, /* 11ng channels */ ++ HAL_MODE_11NA = 0x8000, /* 11na channels */ ++ HAL_MODE_ALL = 0xffff ++}; ++ ++#endif /* #ifndef _HPREG_H */ +--- /dev/null ++++ b/drivers/staging/otus/hal/hprw.c +@@ -0,0 +1,1557 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "../80211core/cprecomp.h" ++#include "hpani.h" ++#include "hpusb.h" ++#include "hpreg.h" ++#include "../80211core/ratectrl.h" ++ ++extern void zfIdlCmd(zdev_t* dev, u32_t* cmd, u16_t cmdLen); ++ ++extern void zfCoreCwmBusy(zdev_t* dev, u16_t busy); ++u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val); ++u16_t zfFlushDelayWrite(zdev_t* dev); ++ ++//#define zm_hp_priv(x) struct zsHpPriv* hpPriv=zgWlanDev.hpPrivate; ++ ++void zfInitCmdQueue(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv = (struct zsHpPriv*)(wd->hpPrivate); ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++#ifdef ZM_XP_USB_MULTCMD ++ hpPriv->cmdTail = hpPriv->cmdHead = hpPriv->cmdSend = 0; ++#else ++ hpPriv->cmdTail = hpPriv->cmdHead = 0; ++#endif ++ hpPriv->cmdPending = 0; ++ hpPriv->cmd.delayWcmdCount = 0; ++ zmw_leave_critical_section(dev); ++} ++ ++u16_t zfPutCmd(zdev_t* dev, u32_t* cmd, u16_t cmdLen, u16_t src, u8_t* buf) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ /* Make sure command length < ZM_MAX_CMD_SIZE */ ++ zm_assert(cmdLen <= ZM_MAX_CMD_SIZE); ++ /* Make sure command queue not full */ ++ //zm_assert(((hpPriv->cmdTail+1) & (ZM_CMD_QUEUE_SIZE-1)) != hpPriv->cmdHead); ++ if (((hpPriv->cmdTail+1) & (ZM_CMD_QUEUE_SIZE-1)) == hpPriv->cmdHead ) { ++ zm_debug_msg0("CMD queue full!!"); ++ return 0; ++ } ++ ++ hpPriv->cmdQ[hpPriv->cmdTail].cmdLen = cmdLen; ++ hpPriv->cmdQ[hpPriv->cmdTail].src = src; ++ hpPriv->cmdQ[hpPriv->cmdTail].buf = buf; ++ for (i=0; i<(cmdLen>>2); i++) ++ { ++ hpPriv->cmdQ[hpPriv->cmdTail].cmd[i] = cmd[i]; ++ } ++ ++ hpPriv->cmdTail = (hpPriv->cmdTail+1) & (ZM_CMD_QUEUE_SIZE-1); ++ ++ return 0; ++} ++ ++u16_t zfGetCmd(zdev_t* dev, u32_t* cmd, u16_t* cmdLen, u16_t* src, u8_t** buf) ++{ ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ if (hpPriv->cmdTail == hpPriv->cmdHead) ++ { ++ return 3; ++ } ++ ++ *cmdLen = hpPriv->cmdQ[hpPriv->cmdHead].cmdLen; ++ *src = hpPriv->cmdQ[hpPriv->cmdHead].src; ++ *buf = hpPriv->cmdQ[hpPriv->cmdHead].buf; ++ for (i=0; i<((*cmdLen)>>2); i++) ++ { ++ cmd[i] = hpPriv->cmdQ[hpPriv->cmdHead].cmd[i]; ++ } ++ ++ hpPriv->cmdHead = (hpPriv->cmdHead+1) & (ZM_CMD_QUEUE_SIZE-1); ++ ++ return 0; ++} ++ ++#ifdef ZM_XP_USB_MULTCMD ++void zfSendCmdEx(zdev_t* dev) ++{ ++ u32_t ncmd[ZM_MAX_CMD_SIZE/4]; ++ u16_t ncmdLen = 0; ++ u16_t cmdFlag = 0; ++ u16_t i; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ if (hpPriv->cmdPending == 0) ++ { ++ if (hpPriv->cmdTail != hpPriv->cmdSend) ++ { ++ cmdFlag = 1; ++ /* Get queueing command */ ++ ncmdLen= hpPriv->cmdQ[hpPriv->cmdSend].cmdLen; ++ for (i=0; i<(ncmdLen>>2); i++) ++ { ++ ncmd[i] = hpPriv->cmdQ[hpPriv->cmdSend].cmd[i]; ++ } ++ hpPriv->cmdSend = (hpPriv->cmdSend+1) & (ZM_CMD_QUEUE_SIZE-1); ++ ++ hpPriv->cmdPending = 1; ++ } ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if ((cmdFlag == 1)) ++ { ++ zfIdlCmd(dev, ncmd, ncmdLen); ++ } ++} ++ ++void zfiSendCmdComp(zdev_t* dev) ++{ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ hpPriv->cmdPending = 0; ++ zmw_leave_critical_section(dev); ++ ++ zfSendCmdEx(dev); ++} ++#endif ++ ++u16_t zfIssueCmd(zdev_t* dev, u32_t* cmd, u16_t cmdLen, u16_t src, u8_t* buf) ++{ ++ u16_t cmdFlag = 0; ++ u16_t ret; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ zm_msg2_mm(ZM_LV_1, "cmdLen=", cmdLen); ++ ++ zmw_enter_critical_section(dev); ++ ++#ifdef ZM_XP_USB_MULTCMD ++ ret = zfPutCmd(dev, cmd, cmdLen, src, buf); ++ zmw_leave_critical_section(dev); ++ ++ if (ret != 0) ++ { ++ return 1; ++ } ++ ++ zfSendCmdEx(dev); ++#else ++ if (hpPriv->cmdPending == 0) ++ { ++ hpPriv->cmdPending = 1; ++ cmdFlag = 1; ++ } ++ ret = zfPutCmd(dev, cmd, cmdLen, src, buf); ++ ++ zmw_leave_critical_section(dev); ++ ++ if (ret != 0) ++ { ++ return 1; ++ } ++ ++ if (cmdFlag == 1) ++ { ++ zfIdlCmd(dev, cmd, cmdLen); ++ } ++#endif ++ return 0; ++} ++ ++void zfIdlRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen) ++{ ++ u32_t cmd[ZM_MAX_CMD_SIZE/4]; ++ u16_t cmdLen; ++ u16_t src; ++ u8_t* buf; ++ u32_t ncmd[ZM_MAX_CMD_SIZE/4]; ++ u16_t ncmdLen = 0; ++ u16_t ret; ++ u16_t cmdFlag = 0; ++ u16_t i; ++ s32_t nf; ++ s32_t noisefloor[4]; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ ++ zmw_declare_for_critical_section(); ++ ++ zmw_enter_critical_section(dev); ++ ++ ret = zfGetCmd(dev, cmd, &cmdLen, &src, &buf); ++ #if 0 ++ zm_assert(ret == 0); ++ #else ++ if (ret != 0) ++ { ++ zm_debug_msg0("Error IdlRsp because none cmd!!\n"); ++ #ifndef ZM_XP_USB_MULTCMD ++ zmw_leave_critical_section(dev); ++ return; ++ #endif ++ } ++ #endif ++#ifdef ZM_XP_USB_MULTCMD ++ zmw_leave_critical_section(dev); ++#else ++ if (hpPriv->cmdTail != hpPriv->cmdHead) ++ { ++ cmdFlag = 1; ++ /* Get queueing command */ ++ ncmdLen= hpPriv->cmdQ[hpPriv->cmdHead].cmdLen; ++ for (i=0; i<(ncmdLen>>2); i++) ++ { ++ ncmd[i] = hpPriv->cmdQ[hpPriv->cmdHead].cmd[i]; ++ } ++ } ++ else ++ { ++ hpPriv->cmdPending = 0; ++ } ++ ++ zmw_leave_critical_section(dev); ++ ++ if (cmdFlag == 1) ++ { ++ zfIdlCmd(dev, ncmd, ncmdLen); ++ } ++#endif ++ if (src == ZM_OID_READ) ++ { ++ ZM_PERFORMANCE_REG(dev, 0x11772c, rsp[1]); ++ zfwDbgReadRegDone(dev, cmd[1], rsp[1]); ++ } ++ else if (src == ZM_OID_FLASH_CHKSUM) ++ { ++ zfwDbgGetFlashChkSumDone(dev, rsp+1); ++ } ++ else if (src == ZM_OID_FLASH_READ) ++ { ++ u32_t datalen; ++ u16_t i; ++ ++ datalen = (rsp[0] & 255); ++ ++ zfwDbgReadFlashDone(dev, cmd[1], rsp+1, datalen); ++ } ++ else if (src == ZM_OID_FLASH_PROGRAM) ++ { ++ /* Non do */ ++ } ++ else if (src == ZM_OID_WRITE) ++ { ++ zfwDbgWriteRegDone(dev, cmd[1], cmd[2]); ++ } ++ else if (src == ZM_OID_TALLY) ++ { ++ zfCollectHWTally(dev, rsp, 0); ++ } ++ else if (src == ZM_OID_TALLY_APD) ++ { ++ zfCollectHWTally(dev, rsp, 1); ++ zfwDbgReadTallyDone(dev); ++#ifdef ZM_ENABLE_BA_RATECTRL ++ zfRateCtrlAggrSta(dev); ++#endif ++ } ++ else if (src == ZM_OID_DKTX_STATUS) ++ { ++ zm_debug_msg0("src = zm_OID_DKTX_STATUS"); ++ zfwDbgQueryHwTxBusyDone(dev, rsp[1]); ++ } ++ else if (src == ZM_CMD_SET_FREQUENCY) ++ { ++ ++//#ifdef ZM_OTUS_ENABLE_RETRY_FREQ_CHANGE ++#if 0 ++ zm_debug_msg1("Retry Set Frequency = ", rsp[1]); ++ ++ #if 1 ++ // Read the Noise Floor value ! ++ nf = ((rsp[2]>>19) & 0x1ff); ++ if ((nf & 0x100) != 0x0) ++ { ++ noisefloor[0] = 0 - ((nf ^ 0x1ff) + 1); ++ } ++ else ++ { ++ noisefloor[0] = nf; ++ } ++ ++ zm_debug_msg1("Noise Floor[1] = ", noisefloor[0]); ++ ++ nf = ((rsp[3]>>19) & 0x1ff); ++ if ((nf & 0x100) != 0x0) ++ { ++ noisefloor[1] = 0 - ((nf ^ 0x1ff) + 1); ++ } ++ else ++ { ++ noisefloor[1] = nf; ++ } ++ ++ zm_debug_msg1("Noise Floor[2] = ", noisefloor[1]); ++ zm_debug_msg1("Is Site Survey = ", hpPriv->isSiteSurvey); ++ #endif ++ ++ if ( (rsp[1] && hpPriv->freqRetryCounter == 0) || ++ (((noisefloor[0]>-60)||(noisefloor[1]>-60)) && hpPriv->freqRetryCounter==0) || ++ ((abs(noisefloor[0]-noisefloor[1])>=9) && hpPriv->freqRetryCounter==0) ) ++ { ++ zm_debug_msg0("Retry to issue the frequency change command"); ++ ++ if ( hpPriv->recordFreqRetryCounter == 1 ) ++ { ++ zm_debug_msg0("Cold Reset"); ++ ++ zfHpSetFrequencyEx(dev, hpPriv->latestFrequency, ++ hpPriv->latestBw40, ++ hpPriv->latestExtOffset, ++ 2); ++ ++ if ( hpPriv->isSiteSurvey != 2 ) ++ { ++ hpPriv->freqRetryCounter++; ++ } ++ hpPriv->recordFreqRetryCounter = 0; ++ } ++ else ++ { ++ zfHpSetFrequencyEx(dev, hpPriv->latestFrequency, ++ hpPriv->latestBw40, ++ hpPriv->latestExtOffset, ++ 0); ++ } ++ hpPriv->recordFreqRetryCounter++; ++ } ++ else ++#endif ++ ++/* ret: Bit0: AGC calibration 0=>finish 1=>unfinish */ ++/* Bit1: Noise calibration 0=>finish 1=>unfinish */ ++/* Bit2: Noise calibration finish, but NF value unexcepted => 1 */ ++ if ( (rsp[1] & 0x1) || (rsp[1] & 0x4) ) ++ { ++ zm_debug_msg1("Set Frequency fail : ret = ", rsp[1]); ++ ++ /* 1. AGC Calibration fail */ ++ /* 2. Noise Calibration finish but error NoiseFloor value */ ++ /* and not in sitesurvey, try more twice */ ++ if ( hpPriv->isSiteSurvey == 2 ) ++ { ++ if ( hpPriv->recordFreqRetryCounter < 2 ) ++ { ++ /* cold reset */ ++ zfHpSetFrequencyEx(dev, hpPriv->latestFrequency, ++ hpPriv->latestBw40, ++ hpPriv->latestExtOffset, ++ 2); ++ hpPriv->recordFreqRetryCounter++; ++ zm_debug_msg1("Retry to issue the frequency change command(cold reset) counter = ", hpPriv->recordFreqRetryCounter); ++ } ++ else ++ { ++ /* Fail : we would not accept this result! */ ++ zm_debug_msg0("\n\n\n\n Fail twice cold reset \n\n\n\n"); ++ hpPriv->coldResetNeedFreq = 0; ++ hpPriv->recordFreqRetryCounter = 0; ++ zfCoreSetFrequencyComplete(dev); ++ } ++ } ++ else ++ { ++ /* in sitesurvey, coldreset in next channel */ ++ hpPriv->coldResetNeedFreq = 1; ++ hpPriv->recordFreqRetryCounter = 0; ++ zfCoreSetFrequencyComplete(dev); ++ } ++ } ++ else if (rsp[1] & 0x2) ++ { ++ zm_debug_msg1("Set Frequency fail 2 : ret = ", rsp[1]); ++ ++ /* Noise Calibration un-finish */ ++ /* and not in sitesurvey, try more once */ ++ if ( hpPriv->isSiteSurvey == 2 ) ++ { ++ if ( hpPriv->recordFreqRetryCounter < 1 ) ++ { ++ /* cold reset */ ++ zfHpSetFrequencyEx(dev, hpPriv->latestFrequency, ++ hpPriv->latestBw40, ++ hpPriv->latestExtOffset, ++ 2); ++ hpPriv->recordFreqRetryCounter++; ++ zm_debug_msg1("2 Retry to issue the frequency change command(cold reset) counter = ", hpPriv->recordFreqRetryCounter); ++ } ++ else ++ { ++ /* Fail : we would not accept this result! */ ++ zm_debug_msg0("\n\n\n\n 2 Fail twice cold reset \n\n\n\n"); ++ hpPriv->coldResetNeedFreq = 0; ++ hpPriv->recordFreqRetryCounter = 0; ++ zfCoreSetFrequencyComplete(dev); ++ } ++ } ++ else ++ { ++ /* in sitesurvey, skip this frequency */ ++ hpPriv->coldResetNeedFreq = 0; ++ hpPriv->recordFreqRetryCounter = 0; ++ zfCoreSetFrequencyComplete(dev); ++ } ++ } ++ //else if (rsp[1] & 0x4) ++ //{ ++ // zm_debug_msg1("Set Frequency fail 3 : ret = ", rsp[1]); ++ // hpPriv->coldResetNeedFreq = 0; ++ // hpPriv->recordFreqRetryCounter = 0; ++ // zfCoreSetFrequencyComplete(dev); ++ //} ++ else ++ { ++ //hpPriv->freqRetryCounter = 0; ++ zm_debug_msg2(" return complete, ret = ", rsp[1]); ++ ++ /* set bb_heavy_clip_enable */ ++ if (hpPriv->enableBBHeavyClip && hpPriv->hwBBHeavyClip && ++ hpPriv->doBBHeavyClip) ++ { ++ u32_t setValue = 0x200; ++ ++ setValue |= hpPriv->setValueHeavyClip; ++ ++ //zm_dbg(("Do heavy clip setValue = %d\n", setValue)); ++ ++ zfDelayWriteInternalReg(dev, 0x99e0+0x1bc000, setValue); ++ zfFlushDelayWrite(dev); ++ } ++ ++ hpPriv->coldResetNeedFreq = 0; ++ hpPriv->recordFreqRetryCounter = 0; ++ zfCoreSetFrequencyComplete(dev); ++ } ++ ++ #if 1 ++ // Read the Noise Floor value ! ++ nf = ((rsp[2]>>19) & 0x1ff); ++ if ((nf & 0x100) != 0x0) ++ { ++ noisefloor[0] = 0 - ((nf ^ 0x1ff) + 1); ++ } ++ else ++ { ++ noisefloor[0] = nf; ++ } ++ ++ //zm_debug_msg1("Noise Floor[1] = ", noisefloor[0]); ++ ++ nf = ((rsp[3]>>19) & 0x1ff); ++ if ((nf & 0x100) != 0x0) ++ { ++ noisefloor[1] = 0 - ((nf ^ 0x1ff) + 1); ++ } ++ else ++ { ++ noisefloor[1] = nf; ++ } ++ ++ //zm_debug_msg1("Noise Floor[2] = ", noisefloor[1]); ++ ++ nf = ((rsp[5]>>23) & 0x1ff); ++ if ((nf & 0x100) != 0x0) ++ { ++ noisefloor[2] = 0 - ((nf ^ 0x1ff) + 1); ++ } ++ else ++ { ++ noisefloor[2] = nf; ++ } ++ ++ //zm_debug_msg1("Noise Floor ext[1] = ", noisefloor[2]); ++ ++ nf = ((rsp[6]>>23) & 0x1ff); ++ if ((nf & 0x100) != 0x0) ++ { ++ noisefloor[3] = 0 - ((nf ^ 0x1ff) + 1); ++ } ++ else ++ { ++ noisefloor[3] = nf; ++ } ++ ++ //zm_debug_msg1("Noise Floor ext[2] = ", noisefloor[3]); ++ ++ //zm_debug_msg1("Is Site Survey = ", hpPriv->isSiteSurvey); ++ #endif ++ } ++ else if (src == ZM_CMD_SET_KEY) ++ { ++ zfCoreSetKeyComplete(dev); ++ } ++ else if (src == ZM_CWM_READ) ++ { ++ zm_msg2_mm(ZM_LV_0, "CWM rsp[1]=", rsp[1]); ++ zm_msg2_mm(ZM_LV_0, "CWM rsp[2]=", rsp[2]); ++ zfCoreCwmBusy(dev, zfCwmIsExtChanBusy(rsp[1], rsp[2])); ++ } ++ else if (src == ZM_MAC_READ) ++ { ++ /* rsp[1] = ZM_SEEPROM_MAC_ADDRESS_OFFSET; */ ++ /* rsp[2] = ZM_SEEPROM_MAC_ADDRESS_OFFSET+4; */ ++ /* rsp[3] = ZM_SEEPROM_REGDOMAIN_OFFSET; */ ++ /* rsp[4] = ZM_SEEPROM_VERISON_OFFSET; */ ++ /* rsp[5] = ZM_SEEPROM_HARDWARE_TYPE_OFFSET; */ ++ /* rsp[6] = ZM_SEEPROM_HW_HEAVY_CLIP; */ ++ ++ u8_t addr[6], CCS, WWR; ++ u16_t CountryDomainCode; ++ ++ /* BB heavy clip */ ++ //hpPriv->eepromHeavyClipFlag = (u8_t)((rsp[6]>>24) & 0xff); // force enable 8107 ++ //zm_msg2_mm(ZM_LV_0, "eepromHeavyClipFlag", hpPriv->eepromHeavyClipFlag); ++ #if 0 ++ if (hpPriv->hwBBHeavyClip) ++ { ++ zm_msg0_mm(ZM_LV_0, "enable BB Heavy Clip"); ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_0, "Not enable BB Heavy Clip"); ++ } ++ #endif ++ zm_msg2_mm(ZM_LV_0, "MAC rsp[1]=", rsp[1]); ++ zm_msg2_mm(ZM_LV_0, "MAC rsp[2]=", rsp[2]); ++ ++ addr[0] = (u8_t)(rsp[1] & 0xff); ++ addr[1] = (u8_t)((rsp[1]>>8) & 0xff); ++ addr[2] = (u8_t)((rsp[1]>>16) & 0xff); ++ addr[3] = (u8_t)((rsp[1]>>24) & 0xff); ++ addr[4] = (u8_t)(rsp[2] & 0xff); ++ addr[5] = (u8_t)((rsp[2]>>8) & 0xff); ++/*#ifdef ZM_FB50 ++ addr[0] = (u8_t)(0 & 0xff); ++ addr[1] = (u8_t)(3 & 0xff); ++ addr[2] = (u8_t)(127 & 0xff); ++ addr[3] = (u8_t)(0 & 0xff); ++ addr[4] = (u8_t)(9 & 0xff); ++ addr[5] = (u8_t)(11 & 0xff); ++#endif*/ ++ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MAC_ADDR_L, ++ ((((u32_t)addr[3])<<24) | (((u32_t)addr[2])<<16) | (((u32_t)addr[1])<<8) | addr[0])); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MAC_ADDR_H, ++ ((((u32_t)addr[5])<<8) | addr[4])); ++ zfFlushDelayWrite(dev); ++ ++ wd->ledStruct.ledMode[0] = (u16_t)(rsp[5]&0xffff); ++ wd->ledStruct.ledMode[1] = (u16_t)(rsp[5]>>16); ++ zm_msg2_mm(ZM_LV_0, "ledMode[0]=", wd->ledStruct.ledMode[0]); ++ zm_msg2_mm(ZM_LV_0, "ledMode[1]=", wd->ledStruct.ledMode[1]); ++ ++ /* Regulatory Related Setting */ ++ zm_msg2_mm(ZM_LV_0, "RegDomain rsp=", rsp[3]); ++ zm_msg2_mm(ZM_LV_0, "OpFlags+EepMisc=", rsp[4]); ++ hpPriv->OpFlags = (u8_t)((rsp[4]>>16) & 0xff); ++ if ((rsp[2] >> 24) == 0x1) //Tx mask == 0x1 ++ { ++ zm_msg0_mm(ZM_LV_0, "OTUS 1x2"); ++ hpPriv->halCapability |= ZM_HP_CAP_11N_ONE_TX_STREAM; ++ } ++ else ++ { ++ zm_msg0_mm(ZM_LV_0, "OTUS 2x2"); ++ } ++ if (hpPriv->OpFlags & 0x1) ++ { ++ hpPriv->halCapability |= ZM_HP_CAP_5G; ++ } ++ if (hpPriv->OpFlags & 0x2) ++ { ++ hpPriv->halCapability |= ZM_HP_CAP_2G; ++ } ++ ++ ++ CCS = (u8_t)((rsp[3] & 0x8000) >> 15); ++ WWR = (u8_t)((rsp[3] & 0x4000) >> 14); ++ CountryDomainCode = (u16_t)(rsp[3] & 0x3FFF); ++ ++ if (rsp[3] != 0xffffffff) ++ { ++ if (CCS) ++ { ++ //zm_debug_msg0("CWY - Get Regulation Table from Country Code"); ++ zfHpGetRegulationTablefromCountry(dev, CountryDomainCode); ++ } ++ else ++ { ++ //zm_debug_msg0("CWY - Get Regulation Table from Reg Domain"); ++ zfHpGetRegulationTablefromRegionCode(dev, CountryDomainCode); ++ } ++ if (WWR) ++ { ++ //zm_debug_msg0("CWY - Enable 802.11d"); ++ /* below line shall be unmarked after A band is ready */ ++ //zfiWlanSetDot11DMode(dev, 1); ++ } ++ } ++ else ++ { ++ zfHpGetRegulationTablefromRegionCode(dev, NO_ENUMRD); ++ } ++ ++ zfCoreMacAddressNotify(dev, addr); ++ ++ } ++ else if (src == ZM_EEPROM_READ) ++ { ++#if 0 ++ u8_t addr[6], CCS, WWR; ++ u16_t CountryDomainCode; ++#endif ++ for (i=0; ieepromImageIndex < 1024) ++ { ++ hpPriv->eepromImage[hpPriv->eepromImageIndex++] = rsp[i+1]; ++ } ++ } ++ ++ if (hpPriv->eepromImageIndex == (ZM_HAL_MAX_EEPROM_REQ*ZM_HAL_MAX_EEPROM_PRQ)) ++ { ++ #if 0 ++ for (i=0; i<1024; i++) ++ { ++ zm_msg2_mm(ZM_LV_0, "index=", i); ++ zm_msg2_mm(ZM_LV_0, "eepromImage=", hpPriv->eepromImage[i]); ++ } ++ #endif ++ zm_msg2_mm(ZM_LV_0, "MAC [1]=", hpPriv->eepromImage[0x20c/4]); ++ zm_msg2_mm(ZM_LV_0, "MAC [2]=", hpPriv->eepromImage[0x210/4]); ++#if 0 ++ addr[0] = (u8_t)(hpPriv->eepromImage[0x20c/4] & 0xff); ++ addr[1] = (u8_t)((hpPriv->eepromImage[0x20c/4]>>8) & 0xff); ++ addr[2] = (u8_t)((hpPriv->eepromImage[0x20c/4]>>16) & 0xff); ++ addr[3] = (u8_t)((hpPriv->eepromImage[0x20c/4]>>24) & 0xff); ++ addr[4] = (u8_t)(hpPriv->eepromImage[0x210/4] & 0xff); ++ addr[5] = (u8_t)((hpPriv->eepromImage[0x210/4]>>8) & 0xff); ++ ++ zfCoreMacAddressNotify(dev, addr); ++ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MAC_ADDR_L, ++ ((((u32_t)addr[3])<<24) | (((u32_t)addr[2])<<16) | (((u32_t)addr[1])<<8) | addr[0])); ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_MAC_ADDR_H, ++ ((((u32_t)addr[5])<<8) | addr[4])); ++ zfFlushDelayWrite(dev); ++ ++ /* Regulatory Related Setting */ ++ zm_msg2_mm(ZM_LV_0, "RegDomain =", hpPriv->eepromImage[0x208/4]); ++ CCS = (u8_t)((hpPriv->eepromImage[0x208/4] & 0x8000) >> 15); ++ WWR = (u8_t)((hpPriv->eepromImage[0x208/4] & 0x4000) >> 14); ++ /* below line shall be unmarked after A band is ready */ ++ //CountryDomainCode = (u16_t)(hpPriv->eepromImage[0x208/4] & 0x3FFF); ++ CountryDomainCode = 8; ++ if (CCS) ++ { ++ //zm_debug_msg0("CWY - Get Regulation Table from Country Code"); ++ zfHpGetRegulationTablefromCountry(dev, CountryDomainCode); ++ } ++ else ++ { ++ //zm_debug_msg0("CWY - Get Regulation Table from Reg Domain"); ++ zfHpGetRegulationTablefromRegionCode(dev, CountryDomainCode); ++ } ++ if (WWR) ++ { ++ //zm_debug_msg0("CWY - Enable 802.11d"); ++ /* below line shall be unmarked after A band is ready */ ++ //zfiWlanSetDot11DMode(dev, 1); ++ } ++#endif ++ zfCoreHalInitComplete(dev); ++ } ++ else ++ { ++ hpPriv->eepromImageRdReq++; ++ zfHpLoadEEPROMFromFW(dev); ++ } ++ } ++ else if (src == ZM_EEPROM_WRITE) ++ { ++ zfwDbgWriteEepromDone(dev, cmd[1], cmd[2]); ++ } ++ else if (src == ZM_ANI_READ) ++ { ++ u32_t cycleTime, ctlClear; ++ ++ zm_msg2_mm(ZM_LV_0, "ANI rsp[1]=", rsp[1]); ++ zm_msg2_mm(ZM_LV_0, "ANI rsp[2]=", rsp[2]); ++ zm_msg2_mm(ZM_LV_0, "ANI rsp[3]=", rsp[3]); ++ zm_msg2_mm(ZM_LV_0, "ANI rsp[4]=", rsp[4]); ++ ++ hpPriv->ctlBusy += rsp[1]; ++ hpPriv->extBusy += rsp[2]; ++ ++ cycleTime = 100000; //100 miniseconds ++ ++ if (cycleTime > rsp[1]) ++ { ++ ctlClear = (cycleTime - rsp[1]) / 100; ++ } ++ else ++ { ++ ctlClear = 0; ++ } ++ if (wd->aniEnable) ++ zfHpAniArPoll(dev, ctlClear, rsp[3], rsp[4]); ++ } ++ else if (src == ZM_CMD_ECHO) ++ { ++ if ( ((struct zsHpPriv*)wd->hpPrivate)->halReInit ) ++ { ++ zfCoreHalInitComplete(dev); ++ ((struct zsHpPriv*)wd->hpPrivate)->halReInit = 0; ++ } ++ else ++ { ++ zfHpLoadEEPROMFromFW(dev); ++ } ++ } ++ else if (src == ZM_OID_FW_DL_INIT) ++ { ++ zfwDbgDownloadFwInitDone(dev); ++ } ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfWriteRegInternalReg */ ++/* Write on chip internal register immediately. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : register address */ ++/* val : value */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u32_t zfWriteRegInternalReg(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ u32_t cmd[3]; ++ u16_t ret; ++ ++ cmd[0] = 0x00000108; ++ cmd[1] = addr; ++ cmd[2] = val; ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfDelayWriteInternalReg */ ++/* Write on chip internal register, write operation may be */ ++/* postponed to form a multiple write command. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : register address */ ++/* val : value */ ++/* */ ++/* OUTPUTS */ ++/* 0 : command been postponed */ ++/* 1 : commands been executed */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t i; ++ u16_t ret; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ /* enter critical section */ ++ zmw_enter_critical_section(dev); ++ ++ /* Store command to global buffer */ ++ hpPriv->cmd.delayWcmdAddr[hpPriv->cmd.delayWcmdCount] = addr; ++ hpPriv->cmd.delayWcmdVal[hpPriv->cmd.delayWcmdCount++] = val; ++ ++ /* If pending command reach size limit */ ++ if ((hpPriv->cmd.delayWcmdCount) >= ((ZM_MAX_CMD_SIZE - 4) >> 3)) ++ { ++ cmd[0] = 0x00000100 + (hpPriv->cmd.delayWcmdCount<<3); ++ ++ /* copy command to cmd buffer */ ++ for (i=0; icmd.delayWcmdCount; i++) ++ { ++ cmd[1+(i<<1)] = hpPriv->cmd.delayWcmdAddr[i]; ++ cmd[2+(i<<1)] = hpPriv->cmd.delayWcmdVal[i]; ++ } ++ /* reset pending command */ ++ hpPriv->cmd.delayWcmdCount = 0; ++ ++ /* leave critical section */ ++ zmw_leave_critical_section(dev); ++ ++ /* issue write command */ ++ ret = zfIssueCmd(dev, cmd, 4+(i<<3), ZM_OID_INTERNAL_WRITE, NULL); ++ ++ return 1; ++ } ++ else ++ { ++ /* leave critical section */ ++ zmw_leave_critical_section(dev); ++ ++ return 0; ++ } ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfFlushDelayWrite */ ++/* Flush pending write command. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : no pending command */ ++/* 1 : commands been executed */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.11 */ ++/* */ ++/************************************************************************/ ++u16_t zfFlushDelayWrite(zdev_t* dev) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t i; ++ u16_t ret; ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zmw_declare_for_critical_section(); ++ ++ /* enter critical section */ ++ zmw_enter_critical_section(dev); ++ ++ /* If there is pending command */ ++ if (hpPriv->cmd.delayWcmdCount > 0) ++ { ++ cmd[0] = 0x00000100 + (hpPriv->cmd.delayWcmdCount<<3); ++ ++ /* copy command to cmd buffer */ ++ for (i=0; icmd.delayWcmdCount; i++) ++ { ++ cmd[1+(i<<1)] = hpPriv->cmd.delayWcmdAddr[i]; ++ cmd[2+(i<<1)] = hpPriv->cmd.delayWcmdVal[i]; ++ } ++ /* reset pending command */ ++ hpPriv->cmd.delayWcmdCount = 0; ++ ++ /* leave critical section */ ++ zmw_leave_critical_section(dev); ++ ++ /* issue write command */ ++ ret = zfIssueCmd(dev, cmd, 4+(i<<3), ZM_OID_INTERNAL_WRITE, NULL); ++ ++ return 1; ++ } ++ else ++ { ++ /* leave critical section */ ++ zmw_leave_critical_section(dev); ++ ++ return 0; ++ } ++} ++ ++ ++u32_t zfiDbgDelayWriteReg(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ zfDelayWriteInternalReg(dev, addr, val); ++ return 0; ++} ++ ++u32_t zfiDbgFlushDelayWrite(zdev_t* dev) ++{ ++ zfFlushDelayWrite(dev); ++ return 0; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgWriteReg */ ++/* Write register. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : register address */ ++/* val : value */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++u32_t zfiDbgWriteReg(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ u32_t cmd[3]; ++ u16_t ret; ++ ++ cmd[0] = 0x00000108; ++ cmd[1] = addr; ++ cmd[2] = val; ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_WRITE, 0); ++ return ret; ++} ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgWriteFlash */ ++/* Write flash. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : register address */ ++/* val : value */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Yjsung ZyDAS Technology Corporation 2007.02 */ ++/* */ ++/************************************************************************/ ++u32_t zfiDbgWriteFlash(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ u32_t cmd[3]; ++ u16_t ret; ++ ++ //cmd[0] = 0x0000B008; ++ /* len[0] : type[0xB0] : seq[?] */ ++ cmd[0] = 8 | (ZM_CMD_WFLASH << 8); ++ cmd[1] = addr; ++ cmd[2] = val; ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_WRITE, 0); ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgWriteEeprom */ ++/* Write EEPROM. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : register address */ ++/* val : value */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Paul ZyDAS Technology Corporation 2007.06 */ ++/* */ ++/************************************************************************/ ++u32_t zfiDbgWriteEeprom(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ u32_t cmd[3]; ++ u16_t ret; ++ ++ //cmd[0] = 0x0000B008; ++ /* len[0] : type[0xB0] : seq[?] */ ++ cmd[0] = 8 | (ZM_CMD_WREEPROM << 8); ++ cmd[1] = addr; ++ cmd[2] = val; ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_EEPROM_WRITE, 0); ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgBlockWriteEeprom */ ++/* Block Write Eeprom. */ ++/* */ ++/* p.s: now,it will write 16 bytes register data per block (N=4) */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : register address */ ++/* buf : input data buffer pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Paul ZyDAS Technology Corporation 2007.06 */ ++/* */ ++/************************************************************************/ ++//#define N buflen/4 ++//#define SIZE (2*N+1) ++ ++u32_t zfiDbgBlockWriteEeprom(zdev_t* dev, u32_t addr, u32_t* buf) ++{ ++ u32_t cmd[9]; //2N+1 ++ u16_t ret,i; ++ ++ //cmd[0] = 0x0000B008; ++ /* len[0] : type[0xB0] : seq[?] */ ++ ++ //cmd[0] = (8*N) | (ZM_CMD_WFLASH << 8); ++ cmd[0] = 32 | (ZM_CMD_WREEPROM << 8); //8N ++ ++ for (i=0; i<4; i++) // i 0x2000) ++ { ++ return 1; ++ } ++ ++ for(i=0; ihpPrivate)->halReInit ) ++ { ++ return 1; ++ } ++ ++ /* len[0] : type[0x81] : seq[?] */ ++ cmd[0] = 0 | (ZM_CMD_TALLY << 8); ++ ret = zfIssueCmd(dev, cmd, 4, ZM_OID_TALLY, 0); ++ ++ /* len[0] : type[0x82] : seq[?] */ ++ cmd[0] = 0 | (ZM_CMD_TALLY_APD << 8); ++ ret = zfIssueCmd(dev, cmd, 4, ZM_OID_TALLY_APD, 0); ++ ++ return ret; ++} ++ ++ ++u32_t zfiDbgSetIFSynthesizer(zdev_t* dev, u32_t value) ++{ ++ u32_t cmd[2]; ++ u16_t ret; ++ ++ /* len[4] : type[0x32] : seq[?] */ ++ cmd[0] = 0x4 | (ZM_OID_SYNTH << 8); ++ cmd[1] = value; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_SYNTH, 0); ++ return ret; ++} ++ ++u32_t zfiDbgQueryHwTxBusy(zdev_t* dev) ++{ ++ u32_t cmd[1]; ++ u16_t ret; ++ ++ /* len[4] : type[0xC0] : seq[?] */ ++ cmd[0] = 0 | (ZM_CMD_DKTX_STATUS << 8); ++ ++ ret = zfIssueCmd(dev, cmd, 4, ZM_OID_DKTX_STATUS, 0); ++ return ret; ++} ++ ++//Paul++ ++#if 0 ++u16_t zfHpBlockEraseFlash(zdev_t *dev, u32_t addr) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret; ++ ++ cmd[0] = 0x00000004 | (ZM_CMD_FLASH_ERASE << 8); ++ cmd[1] = addr; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++#endif ++ ++#if 0 ++u16_t zfiDbgProgramFlash(zdev_t *dev, u32_t offset, u32_t len, u32_t *data) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret; ++ u16_t i; ++ ++ ++ cmd[0] = (ZM_CMD_FLASH_PROG << 8) | ((len+8) & 0xff); ++ cmd[1] = offset; ++ cmd[2] = len; ++ ++ for (i = 0; i < (len >> 2); i++) ++ { ++ cmd[3+i] = data[i]; ++ } ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_FLASH_PROGRAM, NULL); ++ ++ return ret; ++} ++#endif ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgChipEraseFlash */ ++/* Chip Erase Flash. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Paul Atheros Technology Corporation 2007.09 */ ++/* */ ++/************************************************************************/ ++u16_t zfiDbgChipEraseFlash(zdev_t *dev) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u16_t ret; ++ ++ cmd[0] = 0x00000000 | (ZM_CMD_FLASH_ERASE << 8); ++ ++ ret = zfIssueCmd(dev, cmd, 4, ZM_OID_INTERNAL_WRITE, NULL); ++ return ret; ++} ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgGetFlashCheckSum */ ++/* Get FlashCheckSum. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : Start address of getchksum */ ++/* len : total lenth of calculate getchksum */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Paul Atheros Technology Corporation 2007.08 */ ++/* */ ++/************************************************************************/ ++u32_t zfiDbgGetFlashCheckSum(zdev_t *dev, u32_t addr, u32_t len) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u32_t ret; ++ ++ cmd[0] = 0x00000008 | (ZM_CMD_FLASH_CHKSUM << 8); ++ cmd[1] = addr; ++ cmd[2] = len; ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_FLASH_CHKSUM, NULL); ++ ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDbgReadFlash */ ++/* Read Flash. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* addr : Start address of read flash */ ++/* len : total lenth of read flash data */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Paul Atheros Technology Corporation 2007.09 */ ++/* */ ++/************************************************************************/ ++u32_t zfiDbgReadFlash(zdev_t *dev, u32_t addr, u32_t len) ++{ ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u32_t ret; ++ ++ cmd[0] = len | (ZM_CMD_FLASH_READ << 8); ++ cmd[1] = addr; ++ ++ ret = zfIssueCmd(dev, cmd, 8, ZM_OID_FLASH_READ, NULL); ++ return ret; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiDownloadFwSet */ ++/* Before Download FW, */ ++/* Command FW to Software reset and close watch dog control. */ ++/* */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* 0 : success */ ++/* other : fail */ ++/* */ ++/* AUTHOR */ ++/* Paul Atheros Technology Corporation 2007.09 */ ++/* */ ++/************************************************************************/ ++u32_t zfiDownloadFwSet(zdev_t *dev) ++{ ++//softwarereset ++//close watch dog ++ u32_t cmd[(ZM_MAX_CMD_SIZE/4)]; ++ u32_t ret; ++ ++ cmd[0] = 0x00000008 | (ZM_CMD_FW_DL_INIT << 8); ++ ++ ret = zfIssueCmd(dev, cmd, 12, ZM_OID_FW_DL_INIT, NULL); ++ ++ return ret; ++} ++//Paul-- +--- /dev/null ++++ b/drivers/staging/otus/hal/hpusb.c +@@ -0,0 +1,1584 @@ ++/* ++ * Copyright (c) 2000-2005 ZyDAS Technology Corporation ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : ud.c */ ++/* */ ++/* Abstract */ ++/* This module contains USB descriptor functions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++#include "../80211core/cprecomp.h" ++#include "hpani.h" ++#include "hpusb.h" ++ ++extern void zfwUsbCmd(zdev_t* dev, u8_t endpt, u32_t* cmd, u16_t cmdLen); ++ ++extern void zfIdlRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen); ++extern u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val); ++extern u16_t zfFlushDelayWrite(zdev_t* dev); ++ ++ ++#define USB_ENDPOINT_TX_INDEX 1 ++#define USB_ENDPOINT_RX_INDEX 2 ++#define USB_ENDPOINT_INT_INDEX 3 ++#define USB_ENDPOINT_CMD_INDEX 4 ++ ++void zfIdlCmd(zdev_t* dev, u32_t* cmd, u16_t cmdLen) ++{ ++#if ZM_SW_LOOP_BACK != 1 ++ zfwUsbCmd(dev, USB_ENDPOINT_CMD_INDEX, cmd, cmdLen); ++#endif ++ ++ return; ++} ++ ++ ++/* zfAdjustCtrlSetting: fit OUTS format */ ++/* convert MIMO2 to OUTS */ ++void zfAdjustCtrlSetting(zdev_t* dev, u16_t* header, zbuf_t* buf) ++{ ++ /* MIMO2 => OUTS FB-50 */ ++ /* length not change, only modify format */ ++ ++ u32_t oldMT; ++ u32_t oldMCS; ++ ++ u32_t phyCtrl; ++ u32_t oldPhyCtrl; ++ ++ u16_t tpc = 0; ++ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ /* mm */ ++ if (header == NULL) ++ { ++ oldPhyCtrl = zmw_buf_readh(dev, buf, 4) | ((u32_t)zmw_buf_readh(dev, buf, 6) << 16); ++ } ++ else ++ { ++ oldPhyCtrl = header[2] | ((u32_t)header[3] <<16); ++ } ++ ++ phyCtrl = 0; ++ ++ ++ /* MT : Bit[1~0] */ ++ oldMT = oldPhyCtrl&0x3; ++ phyCtrl |= oldMT; ++ if ( oldMT == 0x3 ) /* DL-OFDM (Duplicate Legacy OFDM) */ ++ phyCtrl |= 0x1; ++ ++ ++ /* PT : Bit[2] HT PT: 0 Mixed mode 1 Green field */ ++ phyCtrl |= (oldPhyCtrl&0x4); ++ ++ /* Bandwidth control : Bit[4~3] */ ++ if ( oldPhyCtrl&0x800000 ) /* Bit23 : 40M */ ++ { ++ #if 0 ++ if (oldMT == 0x3) /* DL-OFDM */ ++ phyCtrl |= (0x3<<3); /* 40M duplicate */ ++ else ++ phyCtrl |= (0x2<<3); /* 40M shared */ ++ #else ++ if (oldMT == 0x2 && ((struct zsHpPriv*)wd->hpPrivate)->hwBw40) ++ { ++ phyCtrl |= (0x2<<3); /* 40M shared */ ++ } ++ #endif ++ } ++ else { ++ oldPhyCtrl &= ~0x80000000; ++ } ++ ++ /* MCS : Bit[24~18] */ ++ oldMCS = (oldPhyCtrl&0x7f0000)>>16; /* Bit[22~16] */ ++ phyCtrl |= (oldMCS<<18); ++ ++ /* Short GI : Bit[31]*/ ++ phyCtrl |= (oldPhyCtrl&0x80000000); ++ ++ /* AM : Antenna mask */ ++ //if ((oldMT == 2) && (oldMCS > 7)) ++ if (hpPriv->halCapability & ZM_HP_CAP_11N_ONE_TX_STREAM) ++ { ++ phyCtrl |= (0x1<<15); ++ } ++ else ++ { ++ /* HT Tx 2 chain */ ++ /* OFDM 6M/9M/12M/18M/24M Tx 2 chain */ ++ /* OFDM 36M/48M/54M/ Tx 1 chain */ ++ /* CCK Tx 2 chain */ ++ if ((oldMT == 2) || (oldMT == 3)) ++ { ++ phyCtrl |= (0x5<<15); ++ } ++ else if (oldMT == 1) ++ { ++ if ((oldMCS == 0xb) || (oldMCS == 0xf) || ++ (oldMCS == 0xa) || (oldMCS == 0xe) || ++ (oldMCS == 0x9)) //6M/9M/12M/18M/24M ++ { ++ phyCtrl |= (0x5<<15); ++ } ++ else ++ { ++ phyCtrl |= (0x1<<15); ++ } ++ } ++ else //(oldMT==0) ++ { ++ phyCtrl |= (0x5<<15); ++ } ++ } ++ //else ++ // phyCtrl |= (0x1<<15); ++ ++ /* TPC */ ++ /* TODO : accelerating these code */ ++ if (hpPriv->hwFrequency < 3000) ++ { ++ if (oldMT == 0) ++ { ++ /* CCK */ ++ tpc = (hpPriv->tPow2xCck[oldMCS]&0x3f); ++ } ++ else if (oldMT == 1) ++ { ++ /* OFDM */ ++ if (oldMCS == 0xc) ++ { ++ tpc = (hpPriv->tPow2x2g[3]&0x3f); ++ } ++ else if (oldMCS == 0x8) ++ { ++ tpc = (hpPriv->tPow2x2g[2]&0x3f); ++ } ++ else if (oldMCS == 0xd) ++ { ++ tpc = (hpPriv->tPow2x2g[1]&0x3f); ++ } ++ else if (oldMCS == 0x9) ++ { ++ tpc = ((hpPriv->tPow2x2g[0]-hpPriv->tPow2x2g24HeavyClipOffset)&0x3f); ++ } ++ else ++ { ++ tpc = (hpPriv->tPow2x2g[0]&0x3f); ++ } ++ } ++ else if (oldMT == 2) ++ { ++ if ( oldPhyCtrl&0x800000 ) /* Bit23 : 40M */ ++ { ++ /* HT 40 */ ++ tpc = (hpPriv->tPow2x2gHt40[oldMCS&0x7]&0x3f); ++ } ++ else ++ { ++ /* HT 20 */ ++ tpc = (hpPriv->tPow2x2gHt20[oldMCS&0x7]&0x3f); ++ } ++ } ++ } ++ else //5GHz ++ { ++ if (oldMT == 1) ++ { ++ /* OFDM */ ++ if (oldMCS == 0xc) ++ { ++ tpc = (hpPriv->tPow2x5g[3]&0x3f); ++ } ++ else if (oldMCS == 0x8) ++ { ++ tpc = (hpPriv->tPow2x5g[2]&0x3f); ++ } ++ else if (oldMCS == 0xd) ++ { ++ tpc = (hpPriv->tPow2x5g[1]&0x3f); ++ } ++ else ++ { ++ tpc = (hpPriv->tPow2x5g[0]&0x3f); ++ } ++ } ++ else if (oldMT == 2) ++ { ++ if ( oldPhyCtrl&0x800000 ) /* Bit23 : 40M */ ++ { ++ /* HT 40 */ ++ tpc = (hpPriv->tPow2x5gHt40[oldMCS&0x7]&0x3f); ++ } ++ else ++ { ++ /* HT 20 */ ++ tpc = (hpPriv->tPow2x5gHt20[oldMCS&0x7]&0x3f); ++ } ++ } ++ } ++ ++ /* Tx power adjust for HT40 */ ++ /* HT40 +1dBm */ ++ if ((oldMT==2) && (oldPhyCtrl&0x800000) ) ++ { ++ tpc += 2; ++ } ++ tpc &= 0x3f; ++ ++ /* Evl force tx TPC */ ++ if(wd->forceTxTPC) ++ { ++ tpc = (u16_t)(wd->forceTxTPC & 0x3f); ++ } ++ ++ if (hpPriv->hwFrequency < 3000) { ++ wd->maxTxPower2 &= 0x3f; ++ tpc = (tpc > wd->maxTxPower2)? wd->maxTxPower2 : tpc; ++ } else { ++ wd->maxTxPower5 &= 0x3f; ++ tpc = (tpc > wd->maxTxPower5)? wd->maxTxPower5 : tpc; ++ } ++ ++ ++#define ZM_MIN_TPC 5 ++#define ZM_TPC_OFFSET 5 ++#define ZM_SIGNAL_THRESHOLD 56 ++ if ((wd->sta.bScheduleScan == FALSE) && (wd->sta.bChannelScan == FALSE)) ++ { ++ if (( wd->wlanMode == ZM_MODE_INFRASTRUCTURE ) ++ && (zfStaIsConnected(dev)) ++ && (wd->SignalStrength > ZM_SIGNAL_THRESHOLD)) ++ { ++ if (tpc > ((ZM_MIN_TPC+ZM_TPC_OFFSET)*2)) ++ { ++ tpc -= (ZM_TPC_OFFSET*2); ++ } ++ else if (tpc > (ZM_MIN_TPC*2)) ++ { ++ tpc = (ZM_MIN_TPC*2); ++ } ++ } ++ } ++#undef ZM_MIN_TPC ++#undef ZM_TPC_OFFSET ++#undef ZM_SIGNAL_THRESHOLD ++ ++ #ifndef ZM_OTUS_LINUX_PHASE_2 ++ phyCtrl |= (tpc & 0x3f) << 9; ++ #endif ++ ++ /* Set bits[8:6]BF-MCS for heavy clip */ ++ if ((phyCtrl&0x3) == 2) ++ { ++ phyCtrl |= ((phyCtrl >> 12) & 0x1c0); ++ } ++ ++ /* PHY control */ ++ if (header == NULL) ++ { ++ zmw_buf_writeh(dev, buf, 4, (u16_t) (phyCtrl&0xffff)); ++ zmw_buf_writeh(dev, buf, 6, (u16_t) (phyCtrl>>16)); ++ } ++ else ++ { ++ //PHY control L ++ header[2] = (u16_t) (phyCtrl&0xffff); ++ //PHY control H ++ header[3] = (u16_t) (phyCtrl>>16); ++ } ++ ++ zm_msg2_tx(ZM_LV_2, "old phy ctrl = ", oldPhyCtrl); ++ zm_msg2_tx(ZM_LV_2, "new phy ctrl = ", phyCtrl); ++ //DbgPrint("old phy ctrl =%08x \n", oldPhyCtrl); ++ //DbgPrint("new phy ctrl =%08x \n", phyCtrl); ++} ++ ++ ++#define EXTRA_INFO_LEN 24 //RSSI(7) + EVM(12) + PHY(1) + MACStatus(4) ++u16_t zfHpSend(zdev_t* dev, u16_t* header, u16_t headerLen, ++ u16_t* snap, u16_t snapLen, ++ u16_t* tail, u16_t tailLen, zbuf_t* buf, u16_t offset, ++ u16_t bufType, u8_t ac, u8_t keyIdx) ++{ ++#if ZM_SW_LOOP_BACK == 1 ++ zbuf_t *rxbuf; ++ u8_t *puRxBuf; ++ u8_t *pHdr; ++ u8_t *psnap; ++ u16_t plcplen = 12; ++ u16_t i; ++ u16_t swlpOffset; ++#endif /* #if ZM_SW_LOOP_BACK == 1 */ ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zm_msg1_tx(ZM_LV_1, "zfHpSend(), len = ", 12 + headerLen-8 + snapLen + zfwBufGetSize(dev, buf) + 4 + 8); ++ ++ /* Adjust ctrl setting : 6N14 yjsung */ ++ zfAdjustCtrlSetting(dev, header, buf); ++ ++#if ZM_SW_LOOP_BACK != 1 ++ hpPriv->usbSendBytes += zfwBufGetSize(dev, buf); ++ hpPriv->usbAcSendBytes[ac&0x3] += zfwBufGetSize(dev, buf); ++ ++ /* Submit USB Out Urb */ ++ zfwUsbSend(dev, USB_ENDPOINT_TX_INDEX, (u8_t *)header, headerLen, ++ (u8_t *)snap, snapLen, (u8_t *)tail, tailLen, buf, offset); ++#endif ++ ++#if ZM_SW_LOOP_BACK == 1 ++ ++ rxbuf = zfwBufAllocate(dev, plcplen + headerLen-8 + snapLen + (zfwBufGetSize(dev, buf)-offset) + 4 + EXTRA_INFO_LEN); ++ pHdr = (u8_t *) header+8; ++ psnap = (u8_t *) snap; ++ ++ zmw_enter_critical_section(dev); ++ /* software loop back */ ++ /* Copy WLAN header and packet buffer */ ++ swlpOffset = plcplen; ++ ++ for(i = 0; i < headerLen-8; i++) ++ { ++ zmw_rx_buf_writeb(dev, rxbuf, swlpOffset+i, pHdr[i]); ++ } ++ ++ swlpOffset += headerLen-8; ++ ++ /* Copy SNAP header */ ++ for(i = 0; i < snapLen; i++) ++ { ++ zmw_rx_buf_writeb(dev, rxbuf, swlpOffset+i, psnap[i]); ++ } ++ ++ swlpOffset += snapLen; ++ ++ /* Copy body from tx buf to rxbuf */ ++ for(i = 0; i < (zfwBufGetSize(dev, buf)-offset); i++) ++ { ++ u8_t value = zmw_rx_buf_readb(dev, buf, i+offset); ++ zmw_rx_buf_writeb(dev, rxbuf, swlpOffset+i, value); ++ } ++ ++ /* total length = PLCP + MacHeader + Payload + FCS + RXstatus */ ++ /* 12 + headerLen-8 + snapLen + buf length + 4 + 8 */ ++ zfwSetBufSetSize(dev, rxbuf, swlpOffset + (zfwBufGetSize(dev, buf)-offset) + 4 + EXTRA_INFO_LEN ); ++ ++ zmw_leave_critical_section(dev); ++ ++ zfwBufFree(dev, buf, 0); ++ ++ //zfwDumpBuf(dev, rxbuf); ++ //------------------------------------------------- ++ ++ //zfCoreRecv(dev, rxbuf); ++ ++#endif /* #if ZM_SW_LOOP_BACK */ ++ ++ return ZM_SUCCESS; ++} ++ ++/* Report moniter Hal rx information about rssi, evm, bandwidth, SG etc */ ++void zfHpQueryMonHalRxInfo(zdev_t* dev, u8_t *monHalRxInfo) ++{ ++ zmw_get_wlan_dev(dev); ++ zfMemoryCopy(monHalRxInfo, ++ (u8_t*)&(((struct zsHpPriv*)wd->hpPrivate)->halRxInfo), ++ sizeof(struct zsHalRxInfo)); ++} ++ ++ ++u8_t zfIsDataFrame(zdev_t* dev, zbuf_t* buf) ++{ ++ u8_t frameType; ++ u8_t mpduInd; ++ ++ mpduInd = zmw_rx_buf_readb(dev, buf, zfwBufGetSize(dev, buf)-1); ++ ++ /* sinlge or First */ ++ if ((mpduInd & 0x30) == 0x00 || (mpduInd & 0x30) == 0x20) ++ { ++ frameType = zmw_rx_buf_readb(dev, buf, 12); ++ } ++ else ++ { ++ frameType = zmw_rx_buf_readb(dev, buf, 0); ++ } ++ ++ if((frameType & 0xf) == ZM_WLAN_DATA_FRAME) ++ return 1; ++ else ++ return 0; ++} ++ ++u32_t zfcConvertRateOFDM(zdev_t* dev, zbuf_t* buf) ++{ ++ // What's the default value?? ++ u32_t MCS = 0; ++ ++ switch(zmw_rx_buf_readb(dev, buf, 0)& 0xf) ++ { ++ case 0xb: ++ MCS = 0x4; ++ break; ++ case 0xf: ++ MCS = 0x5; ++ break; ++ case 0xa: ++ MCS = 0x6; ++ break; ++ case 0xe: ++ MCS = 0x7; ++ break; ++ case 0x9: ++ MCS = 0x8; ++ break; ++ case 0xd: ++ MCS = 0x9; ++ break; ++ case 0x8: ++ MCS = 0xa; ++ break; ++ case 0xc: ++ MCS = 0xb; ++ break; ++ } ++ return MCS; ++} ++ ++u16_t zfHpGetPayloadLen(zdev_t* dev, ++ zbuf_t* buf, ++ u16_t len, ++ u16_t plcpHdrLen, ++ u32_t *rxMT, ++ u32_t *rxMCS, ++ u32_t *rxBW, ++ u32_t *rxSG ++ ) ++{ ++ u8_t modulation,mpduInd; ++ u16_t low, high, msb; ++ s16_t payloadLen = 0; ++ ++ zmw_get_wlan_dev(dev); ++ ++ mpduInd = zmw_rx_buf_readb(dev, buf, len-1); ++ modulation = zmw_rx_buf_readb(dev, buf, (len-1)) & 0x3; ++ *rxMT = modulation; ++ ++ //zm_debug_msg1(" modulation= ", modulation); ++ switch (modulation) { ++ case 0: /* CCK Mode */ ++ low = zmw_rx_buf_readb(dev, buf, 2); ++ high = zmw_rx_buf_readb(dev, buf, 3); ++ payloadLen = (low | high << 8) - 4; ++ if (wd->enableHALDbgInfo) ++ { ++ *rxMCS = zmw_rx_buf_readb(dev, buf, 0); ++ *rxBW = 0; ++ *rxSG = 0; ++ } ++ break; ++ case 1: /* Legacy-OFDM mode */ ++ low = zmw_rx_buf_readb(dev, buf, 0) >> 5; ++ high = zmw_rx_buf_readb(dev, buf, 1); ++ msb = zmw_rx_buf_readb(dev, buf, 2) & 0x1; ++ payloadLen = (low | (high << 3) | (msb << 11)) - 4; ++ if (wd->enableHALDbgInfo) ++ { ++ *rxMCS = zfcConvertRateOFDM(dev, buf); ++ *rxBW = 0; ++ *rxSG = 0; ++ } ++ break; ++ case 2: /* HT OFDM mode */ ++ //zm_debug_msg1("aggregation= ", (zmw_rx_buf_readb(dev, buf, 6) >> 3) &0x1 ); ++ if ((mpduInd & 0x30) == 0x00 || (mpduInd & 0x30) == 0x10) //single or last mpdu ++ payloadLen = len - 24 - 4 - plcpHdrLen; // - rxStatus - fcs ++ else { ++ payloadLen = len - 4 - 4 - plcpHdrLen; // - rxStatus - fcs ++ //zm_debug_msg1("first or middle mpdu, plcpHdrLen= ", plcpHdrLen); ++ } ++ if (wd->enableHALDbgInfo) ++ { ++ *rxMCS = zmw_rx_buf_readb(dev, buf, 3) & 0x7f; ++ *rxBW = (zmw_rx_buf_readb(dev, buf, 3) >> 7) & 0x1; ++ *rxSG = (zmw_rx_buf_readb(dev, buf, 6) >> 7) & 0x1; ++ } ++ break; ++ default: ++ break; ++ ++ } ++ /* return the payload length - FCS */ ++ if (payloadLen < 0) payloadLen = 0; ++ return payloadLen; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfiUsbRecv */ ++/* Callback function for USB IN Transfer. */ ++/* */ ++/* INPUTS */ ++/* dev: device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Yuan-Gu Wei ZyDAS Technology Corporation 2005.10 */ ++/* */ ++/************************************************************************/ ++#define ZM_INT_USE_EP2 1 ++#define ZM_INT_USE_EP2_HEADER_SIZE 12 ++ ++#if ZM_INT_USE_EP2 == 1 ++void zfiUsbRegIn(zdev_t* dev, u32_t* rsp, u16_t rspLen); ++#endif ++ ++#ifdef ZM_OTUS_RX_STREAM_MODE ++void zfiUsbRecvPerPkt(zdev_t *dev, zbuf_t *buf) ++#else ++void zfiUsbRecv(zdev_t *dev, zbuf_t *buf) ++#endif ++{ ++ ++ ++#if ZM_FW_LOOP_BACK != 1 ++ u8_t mpduInd; ++ u16_t plcpHdrLen; ++ u16_t crcPlusRxStatusLen; ++ u16_t len, payloadLen=0; ++ u16_t i; //CWYang(+) ++ struct zsAdditionInfo addInfo; ++ u32_t rxMT; ++ u32_t rxMCS; ++ u32_t rxBW; ++ u32_t rxSG; ++ zmw_get_wlan_dev(dev); ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ //zm_msg0_rx(ZM_LV_0, "zfiUsbRecv()"); ++ ++#if ZM_INT_USE_EP2 == 1 ++ ++ for (i=0; i<(ZM_INT_USE_EP2_HEADER_SIZE>>1); i++) ++ { ++ if (zmw_rx_buf_readh(dev, buf, i*2) != 0xffff) ++ break; ++ } ++ ++ if (i==(ZM_INT_USE_EP2_HEADER_SIZE>>1)) ++ { ++ u32_t rsp[ZM_USB_MAX_EPINT_BUFFER/4]; ++ u16_t rspLen; ++ u32_t rspi; ++ u8_t* pdst = (u8_t*)rsp; ++ ++ /* Interrupt Rsp */ ++ rspLen = (u16_t) zfwBufGetSize(dev, buf)-ZM_INT_USE_EP2_HEADER_SIZE; ++ ++ if (rspLen > 60) ++ { ++ zm_debug_msg1("Get error len by EP2 = \n", rspLen); ++ /* free USB buf */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ for (rspi=0; rspizfcbUsbRegIn) ++ // adapter->zfcbUsbRegIn(adapter, rsp, rspLen); ++ zfiUsbRegIn(dev, rsp, rspLen); ++ ++ /* free USB buf */ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++#endif /* end of #if ZM_INT_USE_EP2 == 1 */ ++ ++ ZM_PERFORMANCE_RX_MPDU(dev, buf); ++ ++ if (wd->swSniffer) ++ { ++ /* airopeek: Report everything up */ ++ if (wd->zfcbRecv80211 != NULL) ++ { ++ wd->zfcbRecv80211(dev, buf, NULL); ++ } ++ } ++ ++ /* Read the last byte */ ++ len = zfwBufGetSize(dev, buf); ++ mpduInd = zmw_rx_buf_readb(dev, buf, len-1); ++ ++ /* First MPDU */ ++ if((mpduInd & 0x30) == 0x20) ++ { ++ u16_t duration; ++ if (zmw_rx_buf_readb(dev, buf, 36) == 0) //AC = BE ++ { ++ duration = zmw_rx_buf_readh(dev, buf, 14); ++ if (duration > hpPriv->aggMaxDurationBE) ++ { ++ hpPriv->aggMaxDurationBE = duration; ++ } ++ else ++ { ++ if (hpPriv->aggMaxDurationBE > 10) ++ { ++ hpPriv->aggMaxDurationBE--; ++ } ++ } ++ //DbgPrint("aggMaxDurationBE=%d", hpPriv->aggMaxDurationBE); ++ } ++ } ++ ++#if 1 ++ /* First MPDU or Single MPDU */ ++ if(((mpduInd & 0x30) == 0x00) || ((mpduInd & 0x30) == 0x20)) ++ //if ((mpduInd & 0x10) == 0x00) ++ { ++ plcpHdrLen = 12; // PLCP header length ++ } ++ else ++ { ++ if (zmw_rx_buf_readh(dev, buf, 4) == wd->macAddr[0] && ++ zmw_rx_buf_readh(dev, buf, 6) == wd->macAddr[1] && ++ zmw_rx_buf_readh(dev, buf, 8) == wd->macAddr[2]) { ++ plcpHdrLen = 0; ++ } ++ else if (zmw_rx_buf_readh(dev, buf, 16) == wd->macAddr[0] && ++ zmw_rx_buf_readh(dev, buf, 18) == wd->macAddr[1] && ++ zmw_rx_buf_readh(dev, buf, 20) == wd->macAddr[2]){ ++ plcpHdrLen = 12; ++ } ++ else { ++ plcpHdrLen = 0; ++ } ++ } ++ ++ /* Last MPDU or Single MPDU */ ++ if ((mpduInd & 0x30) == 0x00 || (mpduInd & 0x30) == 0x10) ++ { ++ crcPlusRxStatusLen = EXTRA_INFO_LEN + 4; // Extra bytes + FCS ++ } ++ else ++ { ++ crcPlusRxStatusLen = 4 + 4; // Extra 4 bytes + FCS ++ } ++#else ++ plcpHdrLen = 12; ++ crcPlusRxStatusLen = EXTRA_INFO_LEN + 4; // Extra bytes + FCS ++#endif ++ ++ if (len < (plcpHdrLen+10+crcPlusRxStatusLen)) ++ { ++ zm_msg1_rx(ZM_LV_0, "Invalid Rx length=", len); ++ //zfwDumpBuf(dev, buf); ++ ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ /* display RSSI combined */ ++ /* ++ * ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++ * ¢x PLCP Header ¢x MPDU ¢x RSSI ¢x EVM ¢x PHY Err ¢x MAC Status ¢x ++ * ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++ * ¢x 12 ¢x n ¢x 7 ¢x 12 ¢x 1 ¢x 4 ¢x ++ * ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++ * RSSI filed (From BB and MAC just pass them to host) ++ * Byte1: RSSI for antenna 0. ++ * Byte2: RSSI for antenna 1. ++ * Byte3: RSSI for antenna 2. ++ * Byte4: RSSI for antenna 0 extension. ++ * Byte5: RSSI for antenna 1 extension. ++ * Byte6: RSSI for antenna 2 extension. ++ * Byte7: RSSI for antenna combined. ++ */ ++ ++ //zm_debug_msg1(" recv RSSI = ", zmw_rx_buf_readb(dev, buf, (len-1)-17)); ++ ++ payloadLen = zfHpGetPayloadLen(dev, buf, len, plcpHdrLen, &rxMT, &rxMCS, &rxBW, &rxSG); ++ ++ /* Hal Rx info */ ++ /* First MPDU or Single MPDU */ ++ if(((mpduInd & 0x30) == 0x00) || ((mpduInd & 0x30) == 0x20)) ++ { ++ if (wd->enableHALDbgInfo && zfIsDataFrame(dev, buf)) ++ { ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxDataMT = rxMT; ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxDataMCS = rxMCS; ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxDataBW = rxBW; ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxDataSG = rxSG; ++ } ++ } ++ ++ if ((plcpHdrLen + payloadLen) > len) { ++ zm_msg1_rx(ZM_LV_0, "Invalid payload length=", payloadLen); ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ //Store Rx Tail Infomation before Remove--CWYang(+) ++ ++#if 0 ++ for (i = 0; i < crcPlusRxStatusLen-4; i++) ++ { ++ addInfo.Tail.Byte[i] = ++ zmw_rx_buf_readb(dev, buf, len - crcPlusRxStatusLen + 4 + i); ++ } ++#else ++/* ++* Brief format of OUTS chip ++* ¢z¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢s¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢{ ++* ¢x PLCP Header ¢x MPDU ¢x RSSI ¢x EVM ¢x PHY Err ¢x MAC Status ¢x ++* ¢u¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢q¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢t ++* ¢x 12 ¢x n ¢x 7 ¢x 12 ¢x 1 ¢x 4 ¢x ++* ¢|¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢r¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢w¢} ++* RSSI: ++* Byte 1 antenna 0 ++* Byte 2 antenna 1 ++* Byte 3 antenna 2 ++* Byte 4 antenna 0 extension ++* Byte 5 antenna 1 extension ++* Byte 6 antenna 2 extension ++* Byte 7 antenna combined ++* EVM: ++* Byte 1 Stream 0 pilot 0 ++* Byte 2 Stream 0 pilot 1 ++* Byte 3 Stream 0 pilot 2 ++* Byte 4 Stream 0 pilot 3 ++* Byte 5 Stream 0 pilot 4 ++* Byte 6 Stream 0 pilot 5 ++* Byte 7 Stream 1 pilot 0 ++* Byte 8 Stream 1 pilot 1 ++* Byte 9 Stream 1 pilot 2 ++* Byte 10 Stream 1 pilot 3 ++* Byte 11 Stream 1 pilot 4 ++* Byte 12 Stream 1 pilot 5 ++*/ ++ ++ /* Fill the Tail information */ ++ /* Last MPDU or Single MPDU */ ++ if ((mpduInd & 0x30) == 0x00 || (mpduInd & 0x30) == 0x10) ++ { ++#define ZM_RX_RSSI_COMPENSATION 27 ++ u8_t zm_rx_rssi_compensation = ZM_RX_RSSI_COMPENSATION; ++ ++ /* RSSI information */ ++ addInfo.Tail.Data.SignalStrength1 = zmw_rx_buf_readb(dev, buf, ++ (len-1) - 17) + ((hpPriv->rxStrongRSSI == 1)?zm_rx_rssi_compensation:0); ++#undef ZM_RX_RSSI_COMPENSATION ++ ++ /* EVM */ ++ ++ /* TODO: for RD/BB debug message */ ++ /* save current rx hw infomration, report to DrvCore/Application */ ++ if (wd->enableHALDbgInfo && zfIsDataFrame(dev, buf)) ++ { ++ u8_t trssi; ++ for (i=0; i<7; i++) ++ { ++ trssi = zmw_rx_buf_readb(dev, buf, (len-1) - 23 + i); ++ if (trssi&0x80) ++ { ++ trssi = ((~((u8_t)trssi) & 0x7f) + 1) & 0x7f; ++ } ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[i] = trssi; ++ ++ } ++ if (rxMT==2) ++ { ++ //if (rxBW) ++ //{ ++ for (i=0; i<12; i++) ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[i] = ++ zmw_rx_buf_readb(dev, buf, (len-1) - 16 + i); ++ //} ++ //else ++ //{ ++ // for (i=0; i<4; i++) ++ // ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[i] = ++ // zmw_rx_buf_readb(dev, buf, (len-1) - 16 + i); ++ //} ++ } ++ ++ #if 0 ++ /* print */ ++ zm_dbg(("MT(%d) MCS(%d) BW(%d) SG(%d) RSSI:%d,%d,%d,%d,%d,%d,%d EVM:(%d,%d,%d,%d,%d,%d)(%d,%d,%d,%d,%d,%d)\n", ++ rxMT, ++ rxMCS, ++ rxBW, ++ rxSG, ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[0], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[1], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[2], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[3], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[4], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[5], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRSSI[6], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[0], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[1], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[2], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[3], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[4], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[5], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[6], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[7], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[8], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[9], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[10], ++ ((struct zsHpPriv*)wd->hpPrivate)->halRxInfo.currentRxEVM[11] ++ )); ++ #endif ++ } /* if (wd->enableHALDbgInfo && zfIsDataFrame(dev, buf)) */ ++ ++ } ++ else ++ { ++ /* Mid or First aggregate frame without phy rx information */ ++ addInfo.Tail.Data.SignalStrength1 = 0; ++ } ++ ++ addInfo.Tail.Data.SignalStrength2 = 0; ++ addInfo.Tail.Data.SignalStrength3 = 0; ++ addInfo.Tail.Data.SignalQuality = 0; ++ ++ addInfo.Tail.Data.SAIndex = zmw_rx_buf_readb(dev, buf, len - 4); ++ addInfo.Tail.Data.DAIndex = zmw_rx_buf_readb(dev, buf, len - 3); ++ addInfo.Tail.Data.ErrorIndication = zmw_rx_buf_readb(dev, buf, len - 2); ++ addInfo.Tail.Data.RxMacStatus = zmw_rx_buf_readb(dev, buf, len - 1); ++ ++#endif ++ /* Remove CRC and Rx Status */ ++ zfwBufSetSize(dev, buf, (len-crcPlusRxStatusLen)); ++ //zfwBufSetSize(dev, buf, payloadLen + plcpHdrLen); /* payloadLen + PLCP 12 - FCS 4*/ ++ ++ //Store PLCP Header Infomation before Remove--CWYang(+) ++ if (plcpHdrLen != 0) ++ { ++ for (i = 0; i < plcpHdrLen; i++) ++ { ++ addInfo.PlcpHeader[i] = zmw_rx_buf_readb(dev, buf, i); ++ } ++ } ++ else ++ { ++ addInfo.PlcpHeader[0] = 0; ++ } ++ /* Remove PLCP header */ ++ zfwBufRemoveHead(dev, buf, plcpHdrLen); ++ ++ /* handle 802.11 frame */ ++ zfCoreRecv(dev, buf, &addInfo); ++ ++#else ++ /* Firmware loopback: Rx frame = Tx frame */ ++ /* convert Rx frame to fit receive frame format */ ++ zbuf_t *new_buf; ++ u8_t ctrl_offset = 8; ++ u8_t PLCP_Len = 12; ++ u8_t data; ++ u8_t i; ++ ++ ++ /* Tx: | ctrl_setting | Mac hdr | data | */ ++ /* 8 24 x */ ++ ++ /* Rx: | PLCP | Mac hdr | data | FCS | Rxstatus | */ ++ /* 12 24 x 4 8 */ ++ ++ /* new allocate a rx format size buf */ ++ new_buf = zfwBufAllocate(dev, zfwBufGetSize(dev, buf)-8+12+4+EXTRA_INFO_LEN); ++ ++ for (i=0; ihpPrivate; ++ srcBufPtr = zmw_buf_get_buffer(dev, buf); ++ ++ bufferLength = zfwBufGetSize(dev, buf); ++ ++ /* Zero Length Transfer */ ++ if (!bufferLength) ++ { ++ zfwBufFree(dev, buf, 0); ++ return; ++ } ++ ++ usbRxRemainLen = halPriv->usbRxRemainLen; ++ usbRxPktLen = halPriv->usbRxTransferLen; ++ ++ /* Check whether there is any data in the last transfer */ ++ if (usbRxRemainLen != 0 ) ++ { ++ zbuf_t *remainBufPtr = halPriv->remainBuf; ++ u8_t* BufPtr = NULL; ++ ++ if ( remainBufPtr != NULL ) ++ { ++ BufPtr = zmw_buf_get_buffer(dev, remainBufPtr); ++ } ++ ++ index = usbRxRemainLen; ++ usbRxRemainLen -= halPriv->usbRxPadLen; ++ ++ /* Copy data */ ++ if ( BufPtr != NULL ) ++ { ++ zfwMemoryCopy(&(BufPtr[usbRxPktLen]), srcBufPtr, usbRxRemainLen); ++ } ++ ++ usbRxPktLen += usbRxRemainLen; ++ halPriv->usbRxRemainLen = 0; ++ ++ if ( remainBufPtr != NULL ) ++ { ++ zfwBufSetSize(dev, remainBufPtr, usbRxPktLen); ++ rxBufPool[rxBufPoolIndex++] = remainBufPtr; ++ } ++ halPriv->remainBuf = NULL; ++ } ++ ++ //zm_debug_msg1("length: %d\n", (int)pUsbRxTransfer->pRxUrb->UrbBulkOrInterruptTransfer.TransferBufferLength); ++ ++ bufferLength = zfwBufGetSize(dev, buf); ++//printk("bufferLength %d\n", bufferLength); ++ while(index < bufferLength) ++ { ++ u16_t pktLen; ++ u16_t pktTag; ++ //u8_t *ptr = (u8_t*)((struct zsBuffer*)pUsbRxTransfer->buf)->data; ++ u8_t *ptr = srcBufPtr; ++ ++ /* Retrieve packet length and tag */ ++ pktLen = ptr[index] + (ptr[index+1] << 8); ++ pktTag = ptr[index+2] + (ptr[index+3] << 8); ++ ++ if (pktTag == ZM_USB_STREAM_MODE_TAG) ++ { ++ u16_t padLen; ++ ++ zm_assert(pktLen < ZM_WLAN_MAX_RX_SIZE); ++ ++ //printk("Get a packet, pktLen: 0x%04x\n", pktLen); ++ #if 0 ++ /* Dump data */ ++ for (ii = index; ii < pkt_len+4;) ++ { ++ DbgPrint("0x%02x ", ++ (zmw_rx_buf_readb(adapter, pUsbRxTransfer->buf, ii) & 0xff)); ++ ++ if ((++ii % 16) == 0) ++ DbgPrint("\n"); ++ } ++ ++ DbgPrint("\n"); ++ #endif ++ ++ /* Calcuate the padding length, in the current design, ++ the length should be padded to 4 byte boundray. */ ++ padLen = ZM_USB_STREAM_MODE_TAG_LEN - (pktLen & 0x3); ++ ++ if(padLen == ZM_USB_STREAM_MODE_TAG_LEN) ++ padLen = 0; ++ ++ chkIdx = index; ++ index = index + ZM_USB_STREAM_MODE_TAG_LEN + pktLen + padLen; ++ ++ if (chkIdx > ZM_MAX_USB_IN_TRANSFER_SIZE) ++ { ++ zm_debug_msg1("chkIdx is too large, chkIdx: %d\n", chkIdx); ++ zm_assert(0); ++ status = 1; ++ break; ++ } ++ ++ if (index > ZM_MAX_USB_IN_TRANSFER_SIZE) ++ { ++ //struct zsBuffer* BufPtr; ++ //struct zsBuffer* UsbBufPtr; ++ u8_t *BufPtr; ++ u8_t *UsbBufPtr; ++ ++ halPriv->usbRxRemainLen = index - ZM_MAX_USB_IN_TRANSFER_SIZE; // - padLen; ++ halPriv->usbRxTransferLen = ZM_MAX_USB_IN_TRANSFER_SIZE - ++ chkIdx - ZM_USB_STREAM_MODE_TAG_LEN; ++ halPriv->usbRxPadLen = padLen; ++ //check_index = index; ++ ++ if (halPriv->usbRxTransferLen > ZM_WLAN_MAX_RX_SIZE) ++ { ++ zm_debug_msg1("check_len is too large, chk_len: %d\n", ++ halPriv->usbRxTransferLen); ++ status = 1; ++ break; ++ } ++ ++ /* Allocate a skb buffer */ ++ newBuf = zfwBufAllocate(dev, ZM_WLAN_MAX_RX_SIZE); ++ ++ if ( newBuf != NULL ) ++ { ++ BufPtr = zmw_buf_get_buffer(dev, newBuf); ++ UsbBufPtr = srcBufPtr; ++ ++ /* Copy the buffer */ ++ zfwMemoryCopy(BufPtr, &(UsbBufPtr[chkIdx+ZM_USB_STREAM_MODE_TAG_LEN]), halPriv->usbRxTransferLen); ++ ++ /* Record the buffer pointer */ ++ halPriv->remainBuf = newBuf; ++ } ++ } ++ else ++ { ++ u8_t* BufPtr; ++ u8_t* UsbBufPtr; ++ ++ /* Allocate a skb buffer */ ++ newBuf = zfwBufAllocate(dev, ZM_WLAN_MAX_RX_SIZE); ++ if ( newBuf != NULL ) ++ { ++ BufPtr = zmw_buf_get_buffer(dev, newBuf); ++ UsbBufPtr = srcBufPtr; ++ ++ /* Copy the buffer */ ++ zfwMemoryCopy(BufPtr, &(UsbBufPtr[chkIdx+ZM_USB_STREAM_MODE_TAG_LEN]), pktLen); ++ ++ zfwBufSetSize(dev, newBuf, pktLen); ++ rxBufPool[rxBufPoolIndex++] = newBuf; ++ } ++ } ++ } ++ else ++ { ++ u16_t i; ++ ++ DbgPrint("Can't find tag, pkt_len: 0x%04x, tag: 0x%04x\n", ++ pktLen, pktTag); ++ ++ #if 0 ++ for(i = 0; i < 32; i++) ++ { ++ DbgPrint("%02x ", buf->data[index-16+i]); ++ ++ if ((i & 0xf) == 0xf) ++ DbgPrint("\n"); ++ } ++ #endif ++ ++ break; ++ } ++ } ++ ++ /* Free buffer */ ++ //zfwBufFree(adapter, pUsbRxTransfer->buf, 0); ++ zfwBufFree(dev, buf, 0); ++ ++ for(ii = 0; ii < rxBufPoolIndex; ii++) ++ { ++ zfiUsbRecvPerPkt(dev, rxBufPool[ii]); ++ } ++} ++#endif ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfUsbInit */ ++/* Initialize USB resource. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.12 */ ++/* */ ++/************************************************************************/ ++void zfUsbInit(zdev_t* dev) ++{ ++ /* Initialize Rx & INT endpoint for receiving data & interrupt */ ++ zfwUsbEnableRxEpt(dev, USB_ENDPOINT_RX_INDEX); ++ zfwUsbEnableIntEpt(dev, USB_ENDPOINT_INT_INDEX); ++ ++ return; ++} ++ ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfUsbFree */ ++/* Free PCI resource. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen Chen ZyDAS Technology Corporation 2005.12 */ ++/* */ ++/************************************************************************/ ++void zfUsbFree(zdev_t* dev) ++{ ++ struct zsHpPriv *halPriv; ++ ++ zmw_get_wlan_dev(dev); ++ ++ halPriv = (struct zsHpPriv*)wd->hpPrivate; ++ ++#ifdef ZM_OTUS_RX_STREAM_MODE ++ if ( halPriv->remainBuf != NULL ) ++ { ++ zfwBufFree(dev, halPriv->remainBuf, 0); ++ } ++#endif ++ ++ return; ++} ++ ++void zfHpSendBeacon(zdev_t* dev, zbuf_t* buf, u16_t len) ++{ ++ u32_t hw, lw; ++ u16_t i; ++ zmw_get_wlan_dev(dev); ++ ++ /* Write to beacon buffer (ZM_BEACON_BUFFER_ADDRESS) */ ++ for (i = 0; ihpPrivate)->hwFrequency < 3000) ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PLCP, ((len+4)<<(3+16))+0x0400); ++ } ++ else ++ { ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_PLCP, ((len+4)<<(16))+0x001b); ++ } ++ ++ /* Beacon length (include CRC32) */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_LENGTH, len+4); ++ ++ /* Beacon Ready */ ++ zfDelayWriteInternalReg(dev, ZM_MAC_REG_BCN_CTRL, 1); ++ zfFlushDelayWrite(dev); ++ ++ /* Free beacon buf */ ++ zfwBufFree(dev, buf, 0); ++ ++ return; ++} ++ ++ ++#define ZM_STATUS_TX_COMP 0x00 ++#define ZM_STATUS_RETRY_COMP 0x01 ++#define ZM_STATUS_TX_FAILED 0x02 ++void zfiUsbRegIn(zdev_t* dev, u32_t* rsp, u16_t rspLen) ++{ ++ //u8_t len, type, i; ++ u8_t type; ++ u8_t *u8rsp; ++ u16_t status; ++ u32_t bitmap; ++ zmw_get_wlan_dev(dev); ++ ++ zm_msg0_mm(ZM_LV_3, "zfiUsbRegIn()"); ++ ++ u8rsp = (u8_t *)rsp; ++ ++ //len = *u8rsp; ++ type = *(u8rsp+1); ++ u8rsp = u8rsp+4; ++ ++ ++ /* Interrupt event */ ++ if ((type & 0xC0) == 0xC0) ++ { ++ if (type == 0xC0) ++ { ++ zfCoreEvent(dev, 0, u8rsp); ++ ++ } ++ else if (type == 0xC1) ++ { ++#if 0 ++ { ++ u16_t i; ++ DbgPrint("rspLen=%d\n", rspLen); ++ for (i=0; i<(rspLen/4); i++) ++ { ++ DbgPrint("rsp[%d]=0x%lx\n", i, rsp[i]); ++ } ++ } ++#endif ++ status = (u16_t)(rsp[3] >> 16); ++ ++ ////6789 ++ rsp[8] = rsp[8] >> 2 | (rsp[9] & 0x1) << 6; ++ switch (status) ++ { ++ case ZM_STATUS_RETRY_COMP : ++ zfCoreEvent(dev, 1, u8rsp); ++ break; ++ case ZM_STATUS_TX_FAILED : ++ zfCoreEvent(dev, 2, u8rsp); ++ break; ++ case ZM_STATUS_TX_COMP : ++ zfCoreEvent(dev, 3, u8rsp); ++ break; ++ } ++ } ++ else if (type == 0xC2) ++ { ++ zfBeaconCfgInterrupt(dev, u8rsp); ++ } ++ else if (type == 0xC3) ++ { ++ zfEndOfAtimWindowInterrupt(dev); ++ } ++ else if (type == 0xC4) ++ { ++#if 0 ++ { ++ u16_t i; ++ DbgPrint("0xC2:rspLen=%d\n", rspLen); ++ for (i=0; i<(rspLen/4); i++) ++ { ++ DbgPrint("0xC2:rsp[%d]=0x%lx\n", i, rsp[i]); ++ } ++ } ++#endif ++ bitmap = (rsp[1] >> 16) + ((rsp[2] & 0xFFFF) << 16 ); ++ //zfBawCore(dev, (u16_t)rsp[1] & 0xFFFF, bitmap, (u16_t)(rsp[2] >> 16) & 0xFF); ++ } ++ else if (type == 0xC5) ++ { ++ u16_t i; ++#if 0 ++ ++ for (i=0; i<(rspLen/4); i++) { ++ DbgPrint("0xC5:rsp[%d]=0x%lx\n", i, rsp[i]); ++ } ++#endif ++ for (i=1; i<(rspLen/4); i++) { ++ u8rsp = (u8_t *)(rsp+i); ++ //DbgPrint("0xC5:rsp[%d]=0x%lx\n", i, ((u32_t*)u8rsp)[0]); ++ zfCoreEvent(dev, 4, u8rsp); ++ } ++ } ++ else if (type == 0xC6) ++ { ++ zm_debug_msg0("\n\n WatchDog interrupt!!! : 0xC6 \n\n"); ++ if (wd->zfcbHwWatchDogNotify != NULL) ++ { ++ wd->zfcbHwWatchDogNotify(dev); ++ } ++ } ++ else if (type == 0xC8) ++ { ++ //PZSW_ADAPTER adapter; ++ ++ // for SPI flash program chk Flag ++ zfwDbgProgrameFlashChkDone(dev); ++ } ++ else if (type == 0xC9) ++ { ++ struct zsHpPriv* hpPriv=wd->hpPrivate; ++ ++ zm_debug_msg0("##### Tx retransmission 5 times event #####"); ++ ++ /* correct tx retransmission issue */ ++ hpPriv->retransmissionEvent = 1; ++ } ++ } ++ else ++ { ++ zfIdlRsp(dev, rsp, rspLen); ++ } ++} ++ ++ ++#define ZM_PROGRAM_RAM_ADDR 0x200000 //0x1000 //0x700000 ++#define FIRMWARE_DOWNLOAD 0x30 ++#define FIRMWARE_DOWNLOAD_COMP 0x31 ++#define FIRMWARE_CONFIRM 0x32 ++ ++u16_t zfFirmwareDownload(zdev_t* dev, u32_t* fw, u32_t len, u32_t offset) ++{ ++ u16_t ret = ZM_SUCCESS; ++ u32_t uCodeOfst = offset; ++ u8_t *image, *ptr; ++ u32_t result; ++ ++ image = (u8_t*) fw; ++ ptr = image; ++ ++ while (len > 0) ++ { ++ u32_t translen = (len > 4096) ? 4096 : len; ++ ++ result = zfwUsbSubmitControl(dev, FIRMWARE_DOWNLOAD, ++ (u16_t) (uCodeOfst >> 8), ++ 0, image, translen); ++ ++ if (result != ZM_SUCCESS) ++ { ++ zm_msg0_init(ZM_LV_0, "FIRMWARE_DOWNLOAD failed"); ++ ret = 1; ++ goto exit; ++ } ++ ++ len -= translen; ++ image += translen; ++ uCodeOfst += translen; // in Word (16 bit) ++ ++ result = 0; ++ } ++ ++ /* If download firmware success, issue a command to firmware */ ++ if (ret == 0) ++ { ++ result = zfwUsbSubmitControl(dev, FIRMWARE_DOWNLOAD_COMP, ++ 0, 0, NULL, 0); ++ ++ if (result != ZM_SUCCESS) ++ { ++ zm_msg0_init(ZM_LV_0, "FIRMWARE_DOWNLOAD_COMP failed"); ++ ret = 1; ++ goto exit; ++ } ++ } ++ ++#if 0 ++ /* PCI code */ ++ /* Wait for firmware ready */ ++ result = zfwUsbSubmitControl(dev, FIRMWARE_CONFIRM, USB_DIR_IN | 0x40, ++ 0, 0, &ret_value, sizeof(ret_value), HZ); ++ ++ if (result != 0) ++ { ++ zm_msg0_init(ZM_LV_0, "Can't receive firmware ready: ", result); ++ ret = 1; ++ } ++#endif ++ ++exit: ++ ++ return ret; ++ ++} ++ ++u16_t zfFirmwareDownloadNotJump(zdev_t* dev, u32_t* fw, u32_t len, u32_t offset) ++{ ++ u16_t ret = ZM_SUCCESS; ++ u32_t uCodeOfst = offset; ++ u8_t *image, *ptr; ++ u32_t result; ++ ++ image = (u8_t*) fw; ++ ptr = image; ++ ++ while (len > 0) ++ { ++ u32_t translen = (len > 4096) ? 4096 : len; ++ ++ result = zfwUsbSubmitControl(dev, FIRMWARE_DOWNLOAD, ++ (u16_t) (uCodeOfst >> 8), ++ 0, image, translen); ++ ++ if (result != ZM_SUCCESS) ++ { ++ zm_msg0_init(ZM_LV_0, "FIRMWARE_DOWNLOAD failed"); ++ ret = 1; ++ goto exit; ++ } ++ ++ len -= translen; ++ image += translen; ++ uCodeOfst += translen; // in Word (16 bit) ++ ++ result = 0; ++ } ++ ++exit: ++ ++ return ret; ++ ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfIdlGetFreeTxdCount */ ++/* Get free PCI PCI TxD count. */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* None */ ++/* */ ++/* AUTHOR */ ++/* Stephen ZyDAS Technology Corporation 2006.6 */ ++/* */ ++/************************************************************************/ ++u32_t zfHpGetFreeTxdCount(zdev_t* dev) ++{ ++ return zfwUsbGetFreeTxQSize(dev); ++} ++ ++u32_t zfHpGetMaxTxdCount(zdev_t* dev) ++{ ++ //return 8; ++ return zfwUsbGetMaxTxQSize(dev); ++} ++ ++void zfiUsbRegOutComplete(zdev_t* dev) ++{ ++ return; ++} ++ ++extern void zfPushVtxq(zdev_t* dev); ++ ++void zfiUsbOutComplete(zdev_t* dev, zbuf_t *buf, u8_t status, u8_t *hdr) { ++#ifndef ZM_ENABLE_AGGREGATION ++ if (buf) { ++ zfwBufFree(dev, buf, 0); ++ } ++#else ++ #ifdef ZM_BYPASS_AGGR_SCHEDULING ++ //Simply free the buf since BA retransmission is done in the firmware ++ if (buf) ++ { ++ zfwBufFree(dev, buf, 0); ++ } ++ zfPushVtxq(dev); ++ #else ++ zmw_get_wlan_dev(dev); ++ ++ #ifdef ZM_ENABLE_FW_BA_RETRANSMISSION ++ //Simply free the buf since BA retransmission is done in the firmware ++ if (buf) ++ { ++ zfwBufFree(dev, buf, 0); ++ } ++ #else ++ u8_t agg; ++ u16_t frameType; ++ ++ if(!hdr && buf) { ++ zfwBufFree(dev, buf, 0); ++ //zm_debug_msg0("buf Free due to hdr == NULL"); ++ return; ++ } ++ ++ if(hdr && buf) { ++ frameType = hdr[8] & 0xf; ++ agg = (u8_t)(hdr[2] >> 5 ) & 0x1; ++ //zm_debug_msg1("AGG=", agg); ++ ++ if (!status) { ++ if (agg) { ++ //delete buf in ba fail queue?? ++ //not ganna happen? ++ } ++ else { ++ zfwBufFree(dev, buf, 0); ++ } ++ } ++ else { ++ if (agg) { ++ //don't do anything ++ //zfwBufFree(dev, buf, 0); ++ } ++ else { ++ zfwBufFree(dev, buf, 0); ++ } ++ } ++ } ++ #endif ++ ++ if (wd->state != ZM_WLAN_STATE_ENABLED) { ++ return; ++ } ++ ++ if( (wd->wlanMode == ZM_MODE_AP) || ++ (wd->wlanMode == ZM_MODE_INFRASTRUCTURE && wd->sta.EnableHT) || ++ (wd->wlanMode == ZM_MODE_PSEUDO) ) { ++ zfAggTxScheduler(dev, 0); ++ } ++ #endif ++#endif ++ ++ return; ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/otus/hal/hpusb.h +@@ -0,0 +1,437 @@ ++/* ++ * Copyright (c) 2000-2005 ZyDAS Technology Corporation ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : ud_defs.h */ ++/* */ ++/* Abstract */ ++/* This module contains USB data structure definitions. */ ++/* */ ++/* NOTES */ ++/* None */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _HPUSB_H ++#define _HPUSB_H ++ ++#define ZM_OTUS_ENABLE_RETRY_FREQ_CHANGE ++#define ZM_BEACON_BUFFER_ADDRESS 0x117900 ++ ++#define ZM_MAX_CMD_SIZE 64 ++#define ZM_HAL_MAX_EEPROM_REQ 510 ++#define ZM_HAL_MAX_EEPROM_PRQ 2 ++ ++/* For USB STREAM mode */ ++#ifdef ZM_DISABLE_AMSDU8K_SUPPORT ++#define ZM_MAX_USB_IN_TRANSFER_SIZE 4096 ++#else ++#define ZM_MAX_USB_IN_TRANSFER_SIZE 8192 ++#endif ++#define ZM_USB_STREAM_MODE_TAG_LEN 4 ++#define ZM_USB_STREAM_MODE_TAG 0x4e00 ++#define ZM_USB_MAX_EPINT_BUFFER 64 ++ ++struct zsCmdQ ++{ ++ u16_t src; ++ u16_t cmdLen; ++ u8_t* buf; ++ u32_t cmd[ZM_MAX_CMD_SIZE/4]; ++}; ++ ++struct zsCommand ++{ ++ u16_t delayWcmdCount; ++ u32_t delayWcmdAddr[(ZM_CMD_QUEUE_SIZE-4)/4]; ++ u32_t delayWcmdVal[(ZM_CMD_QUEUE_SIZE-4)/4]; ++}; ++ ++struct zsHalRxInfo ++{ ++ u32_t currentRSSI[7]; /* RSSI combined */ ++ u32_t currentRxEVM[14]; ++ u32_t currentRxDataMT; ++ u32_t currentRxDataMCS; ++ u32_t currentRxDataBW; ++ u32_t currentRxDataSG; ++}; ++ ++struct zsHpPriv ++{ ++ u16_t hwFrequency; ++ u8_t hwBw40; ++ u8_t hwExtOffset; ++ ++ u8_t disableDfsCh; ++ ++ u32_t halCapability; ++ ++ /* Fortunately the second loop can be disabled with a bit */ ++ /* called en_pd_dc_offset_thr */ ++ u8_t hwNotFirstInit; ++ ++ /* command queue */ ++ u16_t cmdHead; ++ u16_t cmdTail; ++#ifdef ZM_XP_USB_MULTCMD ++ u16_t cmdSend; // Used for Mult send USB cmd ++#endif ++ struct zsCmdQ cmdQ[ZM_CMD_QUEUE_SIZE]; ++ u16_t cmdPending; ++ struct zsCommand cmd; /* buffer for delayed commands */ ++ u8_t ledMode[2]; ++ u32_t ctlBusy; ++ u32_t extBusy; ++ ++ /* ++ * ANI & Radar support. ++ */ ++ u32_t procPhyErr; /* Process Phy errs */ ++ u8_t hasHwPhyCounters; /* Hardware has phy counters */ ++ u32_t aniPeriod; /* ani update list period */ ++ struct zsAniStats stats; /* various statistics */ ++ struct zsAniState *curani; /* cached last reference */ ++ struct zsAniState ani[50]; /* per-channel state */ ++ ++ /* ++ * Ani tables that change between the 5416 and 5312. ++ * These get set at attach time. ++ * XXX don't belong here ++ * XXX need better explanation ++ */ ++ s32_t totalSizeDesired[5]; ++ s32_t coarseHigh[5]; ++ s32_t coarseLow[5]; ++ s32_t firpwr[5]; ++ ++ /* ++ * ANI related PHY register value. ++ */ ++ u32_t regPHYDesiredSZ; ++ u32_t regPHYFindSig; ++ u32_t regPHYAgcCtl1; ++ u32_t regPHYSfcorr; ++ u32_t regPHYSfcorrLow; ++ u32_t regPHYTiming5; ++ u32_t regPHYCckDetect; ++ ++ u32_t eepromImage[1024]; ++ u32_t eepromImageIndex; ++ u32_t eepromImageRdReq; ++ ++ u8_t halReInit; ++ ++ u8_t OpFlags; ++ ++ u8_t tPow2xCck[4]; ++ u8_t tPow2x2g[4]; ++ u8_t tPow2x2g24HeavyClipOffset; ++ u8_t tPow2x2gHt20[8]; ++ u8_t tPow2x2gHt40[8]; ++ u8_t tPow2x5g[4]; ++ u8_t tPow2x5gHt20[8]; ++ u8_t tPow2x5gHt40[8]; ++ ++ /* hwBBHeavyClip : used compatibility */ ++ /* 0 : dongle not support. */ ++ /* !0: support heavy clip. */ ++ u8_t hwBBHeavyClip; ++ u8_t enableBBHeavyClip; /* 0=>force disable 1=>enable */ ++ u8_t doBBHeavyClip; /* set 1 if heavy clip need by each frequency switch */ ++ u32_t setValueHeavyClip; /* save setting value for heavy clip when completed routine */ ++ ++ /* ++ * Rxdata RSSI, EVM, Rate etc... ++ */ ++ struct zsHalRxInfo halRxInfo; ++ ++ u32_t usbSendBytes; ++ u32_t usbAcSendBytes[4]; ++ ++ u16_t aggMaxDurationBE; ++ u32_t aggPktNum; ++ ++ u16_t txop[4]; ++ u16_t cwmin[4]; ++ u16_t cwmax[4]; ++ u8_t strongRSSI; ++ u8_t rxStrongRSSI; ++ ++ u8_t slotType; //0->20us, 1=>9us ++ ++#ifdef ZM_OTUS_RX_STREAM_MODE ++ u16_t usbRxRemainLen; ++ u16_t usbRxPktLen; ++ u16_t usbRxPadLen; ++ u16_t usbRxTransferLen; ++ zbuf_t *remainBuf; ++#endif ++ ++ u8_t dot11Mode; ++ ++ u8_t ibssBcnEnabled; ++ u32_t ibssBcnInterval; ++ ++ // For re-issue the frequency change command ++ u32_t latestFrequency; ++ u8_t latestBw40; ++ u8_t latestExtOffset; ++ u8_t freqRetryCounter; ++ ++ u8_t recordFreqRetryCounter; ++ u8_t isSiteSurvey; ++ u8_t coldResetNeedFreq; ++ ++ u64_t camRollCallTable; ++ u8_t currentAckRtsTpc; ++ ++ /* #1 Save the initial value of the related RIFS register settings */ ++ //u32_t isInitialPhy; ++ u32_t initDesiredSigSize; ++ u32_t initAGC; ++ u32_t initAgcControl; ++ u32_t initSearchStartDelay; ++ u32_t initRIFSSearchParams; ++ u32_t initFastChannelChangeControl; ++ ++ /* Dynamic SIFS for retransmission event */ ++ u8_t retransmissionEvent; ++ u8_t latestSIFS; ++}; ++ ++extern u32_t zfHpLoadEEPROMFromFW(zdev_t* dev); ++ ++ ++typedef u8_t A_UINT8; ++typedef s8_t A_INT8; ++typedef u16_t A_UINT16; ++typedef u32_t A_UINT32; ++#define __ATTRIB_PACK ++ ++#pragma pack (push, 1) ++ ++#define AR5416_EEP_VER 0xE ++#define AR5416_EEP_VER_MINOR_MASK 0xFFF ++#define AR5416_EEP_NO_BACK_VER 0x1 ++#define AR5416_EEP_MINOR_VER_2 0x2 // Adds modal params txFrameToPaOn, txFrametoDataStart, ht40PowerInc ++#define AR5416_EEP_MINOR_VER_3 0x3 // Adds modal params bswAtten, bswMargin, swSettle and base OpFlags for HT20/40 Disable ++ ++// 16-bit offset location start of calibration struct ++#define AR5416_EEP_START_LOC 256 ++#define AR5416_NUM_5G_CAL_PIERS 8 ++#define AR5416_NUM_2G_CAL_PIERS 4 ++#define AR5416_NUM_5G_20_TARGET_POWERS 8 ++#define AR5416_NUM_5G_40_TARGET_POWERS 8 ++#define AR5416_NUM_2G_CCK_TARGET_POWERS 3 ++#define AR5416_NUM_2G_20_TARGET_POWERS 4 ++#define AR5416_NUM_2G_40_TARGET_POWERS 4 ++#define AR5416_NUM_CTLS 24 ++#define AR5416_NUM_BAND_EDGES 8 ++#define AR5416_NUM_PD_GAINS 4 ++#define AR5416_PD_GAINS_IN_MASK 4 ++#define AR5416_PD_GAIN_ICEPTS 5 ++#define AR5416_EEPROM_MODAL_SPURS 5 ++#define AR5416_MAX_RATE_POWER 63 ++#define AR5416_NUM_PDADC_VALUES 128 ++#define AR5416_NUM_RATES 16 ++#define AR5416_BCHAN_UNUSED 0xFF ++#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 ++#define AR5416_OPFLAGS_11A 0x01 ++#define AR5416_OPFLAGS_11G 0x02 ++#define AR5416_OPFLAGS_5G_HT40 0x04 ++#define AR5416_OPFLAGS_2G_HT40 0x08 ++#define AR5416_OPFLAGS_5G_HT20 0x10 ++#define AR5416_OPFLAGS_2G_HT20 0x20 ++#define AR5416_EEPMISC_BIG_ENDIAN 0x01 ++#define FREQ2FBIN(x,y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) ++#define AR5416_MAX_CHAINS 2 ++#define AR5416_ANT_16S 25 ++ ++#define AR5416_NUM_ANT_CHAIN_FIELDS 7 ++#define AR5416_NUM_ANT_COMMON_FIELDS 4 ++#define AR5416_SIZE_ANT_CHAIN_FIELD 3 ++#define AR5416_SIZE_ANT_COMMON_FIELD 4 ++#define AR5416_ANT_CHAIN_MASK 0x7 ++#define AR5416_ANT_COMMON_MASK 0xf ++#define AR5416_CHAIN_0_IDX 0 ++#define AR5416_CHAIN_1_IDX 1 ++#define AR5416_CHAIN_2_IDX 2 ++ ++ ++/* Capabilities Enum */ ++typedef enum { ++ EEPCAP_COMPRESS_DIS = 0x0001, ++ EEPCAP_AES_DIS = 0x0002, ++ EEPCAP_FASTFRAME_DIS = 0x0004, ++ EEPCAP_BURST_DIS = 0x0008, ++ EEPCAP_MAXQCU_M = 0x01F0, ++ EEPCAP_MAXQCU_S = 4, ++ EEPCAP_HEAVY_CLIP_EN = 0x0200, ++ EEPCAP_KC_ENTRIES_M = 0xF000, ++ EEPCAP_KC_ENTRIES_S = 12, ++} EEPROM_CAPABILITIES; ++ ++typedef enum Ar5416_Rates { ++ rate6mb, rate9mb, rate12mb, rate18mb, ++ rate24mb, rate36mb, rate48mb, rate54mb, ++ rate1l, rate2l, rate2s, rate5_5l, ++ rate5_5s, rate11l, rate11s, rateXr, ++ rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3, ++ rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7, ++ rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3, ++ rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7, ++ rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm, ++ Ar5416RateSize ++} AR5416_RATES; ++ ++typedef struct eepFlags { ++ A_UINT8 opFlags; ++ A_UINT8 eepMisc; ++} __ATTRIB_PACK EEP_FLAGS; ++ ++#define AR5416_CHECKSUM_LOCATION (AR5416_EEP_START_LOC + 1) ++typedef struct BaseEepHeader { ++ A_UINT16 length; ++ A_UINT16 checksum; ++ A_UINT16 version; ++ EEP_FLAGS opCapFlags; ++ A_UINT16 regDmn[2]; ++ A_UINT8 macAddr[6]; ++ A_UINT8 rxMask; ++ A_UINT8 txMask; ++ A_UINT16 rfSilent; ++ A_UINT16 blueToothOptions; ++ A_UINT16 deviceCap; ++ A_UINT32 binBuildNumber; ++ A_UINT8 deviceType; ++ A_UINT8 futureBase[33]; ++} __ATTRIB_PACK BASE_EEP_HEADER; // 64 B ++ ++typedef struct spurChanStruct { ++ A_UINT16 spurChan; ++ A_UINT8 spurRangeLow; ++ A_UINT8 spurRangeHigh; ++} __ATTRIB_PACK SPUR_CHAN; ++ ++typedef struct ModalEepHeader { ++ A_UINT32 antCtrlChain[AR5416_MAX_CHAINS]; // 12 ++ A_UINT32 antCtrlCommon; // 4 ++ A_INT8 antennaGainCh[AR5416_MAX_CHAINS]; // 3 ++ A_UINT8 switchSettling; // 1 ++ A_UINT8 txRxAttenCh[AR5416_MAX_CHAINS]; // 3 ++ A_UINT8 rxTxMarginCh[AR5416_MAX_CHAINS]; // 3 ++ A_INT8 adcDesiredSize; // 1 ++ A_INT8 pgaDesiredSize; // 1 ++ A_UINT8 xlnaGainCh[AR5416_MAX_CHAINS]; // 3 ++ A_UINT8 txEndToXpaOff; // 1 ++ A_UINT8 txEndToRxOn; // 1 ++ A_UINT8 txFrameToXpaOn; // 1 ++ A_UINT8 thresh62; // 1 ++ A_INT8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; // 3 ++ A_UINT8 xpdGain; // 1 ++ A_UINT8 xpd; // 1 ++ A_INT8 iqCalICh[AR5416_MAX_CHAINS]; // 1 ++ A_INT8 iqCalQCh[AR5416_MAX_CHAINS]; // 1 ++ A_UINT8 pdGainOverlap; // 1 ++ A_UINT8 ob; // 1 ++ A_UINT8 db; // 1 ++ A_UINT8 xpaBiasLvl; // 1 ++ A_UINT8 pwrDecreaseFor2Chain; // 1 ++ A_UINT8 pwrDecreaseFor3Chain; // 1 -> 48 B ++ A_UINT8 txFrameToDataStart; // 1 ++ A_UINT8 txFrameToPaOn; // 1 ++ A_UINT8 ht40PowerIncForPdadc; // 1 ++ A_UINT8 bswAtten[AR5416_MAX_CHAINS]; // 3 ++ A_UINT8 bswMargin[AR5416_MAX_CHAINS]; // 3 ++ A_UINT8 swSettleHt40; // 1 ++ A_UINT8 futureModal[22]; // ++ SPUR_CHAN spurChans[AR5416_EEPROM_MODAL_SPURS]; // 20 B ++} __ATTRIB_PACK MODAL_EEP_HEADER; // == 100 B ++ ++typedef struct calDataPerFreq { ++ A_UINT8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; ++ A_UINT8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; ++} __ATTRIB_PACK CAL_DATA_PER_FREQ; ++ ++typedef struct CalTargetPowerLegacy { ++ A_UINT8 bChannel; ++ A_UINT8 tPow2x[4]; ++} __ATTRIB_PACK CAL_TARGET_POWER_LEG; ++ ++typedef struct CalTargetPowerHt { ++ A_UINT8 bChannel; ++ A_UINT8 tPow2x[8]; ++} __ATTRIB_PACK CAL_TARGET_POWER_HT; ++ ++#if defined(ARCH_BIG_ENDIAN) || defined(BIG_ENDIAN) ++typedef struct CalCtlEdges { ++ A_UINT8 bChannel; ++ A_UINT8 flag :2, ++ tPower :6; ++} __ATTRIB_PACK CAL_CTL_EDGES; ++#else ++typedef struct CalCtlEdges { ++ A_UINT8 bChannel; ++ A_UINT8 tPower :6, ++ flag :2; ++} __ATTRIB_PACK CAL_CTL_EDGES; ++#endif ++ ++typedef struct CalCtlData { ++ CAL_CTL_EDGES ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; ++} __ATTRIB_PACK CAL_CTL_DATA; ++ ++typedef struct ar5416Eeprom { ++ BASE_EEP_HEADER baseEepHeader; // 64 B ++ A_UINT8 custData[64]; // 64 B ++ MODAL_EEP_HEADER modalHeader[2]; // 200 B ++ A_UINT8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS]; ++ A_UINT8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS]; ++ CAL_DATA_PER_FREQ calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS]; ++ CAL_DATA_PER_FREQ calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; ++ CAL_TARGET_POWER_LEG calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS]; ++ CAL_TARGET_POWER_HT calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS]; ++ CAL_TARGET_POWER_HT calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS]; ++ CAL_TARGET_POWER_LEG calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS]; ++ CAL_TARGET_POWER_LEG calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS]; ++ CAL_TARGET_POWER_HT calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS]; ++ CAL_TARGET_POWER_HT calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS]; ++ A_UINT8 ctlIndex[AR5416_NUM_CTLS]; ++ CAL_CTL_DATA ctlData[AR5416_NUM_CTLS]; ++ A_UINT8 padding; ++} __ATTRIB_PACK AR5416_EEPROM; ++ ++#pragma pack (pop) ++ ++typedef enum ConformanceTestLimits { ++ FCC = 0x10, ++ MKK = 0x40, ++ ETSI = 0x30, ++ SD_NO_CTL = 0xE0, ++ NO_CTL = 0xFF, ++ CTL_MODE_M = 0xF, ++ CTL_11A = 0, ++ CTL_11B = 1, ++ CTL_11G = 2, ++ CTL_TURBO = 3, ++ CTL_108G = 4, ++ CTL_2GHT20 = 5, ++ CTL_5GHT20 = 6, ++ CTL_2GHT40 = 7, ++ CTL_5GHT40 = 8, ++} ATH_CTLS; ++ ++#endif /* #ifndef _HPUSB_H */ +--- /dev/null ++++ b/drivers/staging/otus/hal/otus.ini +@@ -0,0 +1,414 @@ ++/* 8602 : update mismatch register between NDIS and ART */ ++static const u32_t ar5416Modes[][6] = { ++/* Register A-20 A-20/40 G-20/40 G-20 G-Turbo */ ++ {0x9800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0}, ++ {0x9804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0}, ++ {0x9808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x980c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, 0}, ++ {0x9810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0}, ++ {0x9814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0}, ++ {0x9818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, 0}, ++ {0x981c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0}, ++ {0x9824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0}, ++ {0x9828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0}, ++ {0x982c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0}, ++ {0x9830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0}, ++ {0x9838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0}, ++ {0x983c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, 0}, ++ {0x9840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, 0}, ++ {0x9844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, 0}, ++ {0x9848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0}, ++ {0x984c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, 0}, ++ {0x9850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, 0}, ++ {0x9854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, 0}, ++ {0x9858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0}, ++ {0x985c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0}, ++ {0x9860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, 0}, ++ {0x9868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0}, ++ {0x986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0}, ++ {0x9900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x990c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0}, ++ {0x9918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, 0}, ++ {0x991c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, 0}, ++ {0x9920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, 0}, ++ {0x9924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0}, ++ {0x9928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0}, ++ {0x992c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0}, ++ {0x9934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0x9938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0x993c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0}, ++ {0x9944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0}, ++ {0x9948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, 0}, ++ {0x994c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, 0}, ++ {0x9954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0}, ++ {0x9958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, 0}, ++ {0x9960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0}, ++ {0x9964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0}, ++ {0x9970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, 0}, ++ {0x9974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0}, ++ {0x997c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x998c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x999c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x99a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x99a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0}, ++ {0x99a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, 0}, ++ {0x99ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0}, ++ {0x99b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, 0}, ++ {0x99b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, 0}, ++ {0x99c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0}, ++ {0x99c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0}, ++ {0x99c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0}, ++ {0x99cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0}, ++ {0x99d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0}, ++ {0x99d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x99d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x99dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x99e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0}, ++ {0x99e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, 0}, ++ {0x99e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, 0}, ++ {0x99ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, 0}, ++ {0x99f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x99fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, 0}, ++ {0x9a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0}, ++ {0x9a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0}, ++ {0x9a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, 0}, ++ {0x9a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, 0}, ++ {0x9a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, 0}, ++ {0x9a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, 0}, ++ {0x9a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, 0}, ++ {0x9a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, 0}, ++ {0x9a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, 0}, ++ {0x9a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, 0}, ++ {0x9a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, 0}, ++ {0x9a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, 0}, ++ {0x9a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, 0}, ++ {0x9a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, 0}, ++ {0x9a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, 0}, ++ {0x9a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, 0}, ++ {0x9a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, 0}, ++ {0x9a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, 0}, ++ {0x9a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, 0}, ++ {0x9a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, 0}, ++ {0x9a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, 0}, ++ {0x9a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, 0}, ++ {0x9a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, 0}, ++ {0x9a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, 0}, ++ {0x9a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, 0}, ++ {0x9a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, 0}, ++ {0x9a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, 0}, ++ {0x9a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, 0}, ++ {0x9a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, 0}, ++ {0x9a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, 0}, ++ {0x9a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, 0}, ++ {0x9a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, 0}, ++ {0x9a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, 0}, ++ {0x9a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, 0}, ++ {0x9a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, 0}, ++ {0x9a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, 0}, ++ {0x9a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, 0}, ++ {0x9a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, 0}, ++ {0x9a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, 0}, ++ {0x9aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, 0}, ++ {0x9b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0}, ++ {0x9b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0}, ++ {0x9b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0}, ++ {0x9b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0}, ++ {0x9b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0}, ++ {0x9b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0}, ++ {0x9b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, 0}, ++ {0x9b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, 0}, ++ {0x9b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, 0}, ++ {0x9b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, 0}, ++ {0x9b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, 0}, ++ {0x9b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0}, ++ {0x9b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0}, ++ {0x9b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0}, ++ {0x9b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, 0}, ++ {0x9b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0}, ++ {0x9b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0}, ++ {0x9b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0}, ++ {0x9b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, 0}, ++ {0x9b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0}, ++ {0x9b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, 0}, ++ {0x9b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0}, ++ {0x9b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, 0}, ++ {0x9b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0}, ++ {0x9b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, 0}, ++ {0x9b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0}, ++ {0x9b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0}, ++ {0x9b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, 0}, ++ {0x9b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, 0}, ++ {0x9b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, 0}, ++ {0x9b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0}, ++ {0x9b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, 0}, ++ {0x9b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0}, ++ {0x9b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, 0}, ++ {0x9b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, 0}, ++ {0x9b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, 0}, ++ {0x9b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, 0}, ++ {0x9b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, 0}, ++ {0x9b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, 0}, ++ {0x9ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, 0}, ++ {0x9ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, 0}, ++ {0x9bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0}, ++ {0x9bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0}, ++ {0x9c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0x9cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, 0}, ++ {0xa204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, 0}, ++ {0xa208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0}, ++ {0xa20c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, 0}, ++ {0xa210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, 0}, ++ {0xa214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, 0}, ++ {0xa218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, 0}, ++ {0xa21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0}, ++ {0xa220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, 0}, ++ {0xa224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0}, ++ {0xa228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, 0}, ++ {0xa22c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, 0}, ++ {0xa234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa23c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0}, ++ {0xa240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, 0}, ++ {0xa244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0}, ++ {0xa248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0}, ++ {0xa24c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0}, ++ {0xa250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0}, ++ {0xa254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0}, ++ {0xa25c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0}, ++ {0xa260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0}, ++ {0xa264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, 0}, ++ {0xa268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa26c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, 0}, ++ {0xa274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0}, ++ {0xa278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0}, ++ {0xa27c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, 0}, ++ {0xa300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0}, ++ {0xa304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0}, ++ {0xa308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0}, ++ {0xa30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0}, ++ {0xa310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0}, ++ {0xa314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0}, ++ {0xa318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0}, ++ {0xa31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0}, ++ {0xa320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0}, ++ {0xa324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0}, ++ {0xa328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0}, ++ {0xa32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa33c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0}, ++ {0xa34c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0}, ++ {0xa350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0}, ++ {0xa354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0}, ++ {0xa358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0}, ++ {0xa388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0}, ++ {0xa38c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0}, ++ {0xa398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0}, ++ {0xa39c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0}, ++ {0xa3a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa3d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa3d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0}, ++ {0xa3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0}, ++ {0xa3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0}, ++ {0xa3e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, 0}, ++ {0xa848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, 0}, ++ {0xa920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, 0}, ++ {0xa960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0}, ++ {0xb20c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, 0}, ++ {0xb26c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, 0}, ++ {0xb848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, 0}, ++ {0xb920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, 0}, ++ {0xb960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0}, ++ {0xc20c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, 0}, ++ {0xc26c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, 0}, ++ //{0xc864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0}, ++ {0xc864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, 0}, ++ {0xc95c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0}, ++ {0xc968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, 0}, ++ {0xc9bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, 0}, ++ {0xd270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, 0}, ++ {0xd35c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, 0}, ++ {0xd360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, 0}, ++ {0xd364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, 0}, ++ {0xd368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, 0}, ++ {0xd36c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0}, ++ {0xd370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0}, ++ {0xd374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, 0}, ++ {0xd378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0}, ++ {0xd37c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0}, ++ {0xd380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0}, ++ {0xd384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0} ++}; ++ ++ ++static const u32_t otusBank[][3] = { ++ //# bank 0 ++ {0x98b0, 0x1e5795e5, 0x1e5795e5}, ++ {0x98e0, 0x02008020, 0x02008020}, ++ //# bank 1 ++ {0x98b0, 0x02108421, 0x02108421}, ++ {0x98ec, 0x00000008, 0x00000008}, ++ //# bank 2 ++ {0x98b0, 0x0e73ff17, 0x0e73ff17}, ++ {0x98e0, 0x00000420, 0x00000420}, ++ //# bank 3 ++ {0x98f0, 0x01400018, 0x01c00018}, ++ //# bank 4 ++ {0x98b0, 0x000001a1, 0x000001a1}, ++ {0x98e8, 0x00000001, 0x00000001}, ++ //# bank 5 ++ {0x98b0, 0x00000013, 0x00000013}, ++ {0x98e4, 0x00000002, 0x00000002}, ++ //# bank 6 ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00004000, 0x00004000}, ++ {0x98b0, 0x00006c00, 0x00006c00}, ++ {0x98b0, 0x00002c00, 0x00002c00}, ++ {0x98b0, 0x00004800, 0x00004800}, ++ {0x98b0, 0x00004000, 0x00004000}, ++ {0x98b0, 0x00006000, 0x00006000}, ++ {0x98b0, 0x00001000, 0x00001000}, ++ {0x98b0, 0x00004000, 0x00004000}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00087c00, 0x00087c00}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00005400, 0x00005400}, ++ {0x98b0, 0x00000c00, 0x00000c00}, ++ {0x98b0, 0x00001800, 0x00001800}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00006c00, 0x00006c00}, ++ {0x98b0, 0x00006c00, 0x00006c00}, ++ {0x98b0, 0x00007c00, 0x00007c00}, ++ {0x98b0, 0x00002c00, 0x00002c00}, ++ {0x98b0, 0x00003c00, 0x00003c00}, ++ {0x98b0, 0x00003800, 0x00003800}, ++ {0x98b0, 0x00001c00, 0x00001c00}, ++ {0x98b0, 0x00000800, 0x00000800}, ++ {0x98b0, 0x00000408, 0x00000408}, ++ {0x98b0, 0x00004c15, 0x00004c15}, ++ {0x98b0, 0x00004188, 0x00004188}, ++ {0x98b0, 0x0000201e, 0x0000201e}, ++ {0x98b0, 0x00010408, 0x00010408}, ++ {0x98b0, 0x00000801, 0x00000801}, ++ {0x98b0, 0x00000c08, 0x00000c08}, ++ {0x98b0, 0x0000181e, 0x0000181e}, ++ {0x98b0, 0x00001016, 0x00001016}, ++ {0x98b0, 0x00002800, 0x00002800}, ++ {0x98b0, 0x00004010, 0x00004010}, ++ {0x98b0, 0x0000081c, 0x0000081c}, ++ {0x98b0, 0x00000115, 0x00000115}, ++ {0x98b0, 0x00000015, 0x00000015}, ++ {0x98b0, 0x00000066, 0x00000066}, ++ {0x98b0, 0x0000001c, 0x0000001c}, ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00000004, 0x00000004}, ++ {0x98b0, 0x00000015, 0x00000015}, ++ {0x98b0, 0x0000001f, 0x0000001f}, ++ {0x98e0, 0x00000000, 0x00000400}, ++ //# bank 7 ++ {0x98b0, 0x000000a0, 0x000000a0}, ++ {0x98b0, 0x00000000, 0x00000000}, ++ {0x98b0, 0x00000040, 0x00000040}, ++ {0x98f0, 0x0000001c, 0x0000001c} ++}; +--- /dev/null ++++ b/drivers/staging/otus/ioctl.c +@@ -0,0 +1,2936 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : ioctl.c */ ++/* */ ++/* Abstract */ ++/* This module contains Linux wireless extension related functons. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++#include ++#include ++#include ++ ++#include "usbdrv.h" ++ ++#define ZD_IOCTL_WPA (SIOCDEVPRIVATE + 1) ++#define ZD_IOCTL_PARAM (SIOCDEVPRIVATE + 2) ++#define ZD_IOCTL_GETWPAIE (SIOCDEVPRIVATE + 3) ++#ifdef ZM_ENABLE_CENC ++#define ZM_IOCTL_CENC (SIOCDEVPRIVATE + 4) ++#endif //ZM_ENABLE_CENC ++#define ZD_PARAM_ROAMING 0x0001 ++#define ZD_PARAM_PRIVACY 0x0002 ++#define ZD_PARAM_WPA 0x0003 ++#define ZD_PARAM_COUNTERMEASURES 0x0004 ++#define ZD_PARAM_DROPUNENCRYPTED 0x0005 ++#define ZD_PARAM_AUTH_ALGS 0x0006 ++#define ZD_PARAM_WPS_FILTER 0x0007 ++ ++#ifdef ZM_ENABLE_CENC ++#define P80211_PACKET_CENCFLAG 0x0001 ++#endif //ZM_ENABLE_CENC ++#define P80211_PACKET_SETKEY 0x0003 ++ ++#define ZD_CMD_SET_ENCRYPT_KEY 0x0001 ++#define ZD_CMD_SET_MLME 0x0002 ++#define ZD_CMD_SCAN_REQ 0x0003 ++#define ZD_CMD_SET_GENERIC_ELEMENT 0x0004 ++#define ZD_CMD_GET_TSC 0x0005 ++ ++#define ZD_CRYPT_ALG_NAME_LEN 16 ++#define ZD_MAX_KEY_SIZE 32 ++#define ZD_MAX_GENERIC_SIZE 64 ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++extern u16_t zfLnxGetVapId(zdev_t* dev); ++ ++static const u32_t channel_frequency_11A[] = ++{ ++//Even element for Channel Number, Odd for Frequency ++ 36,5180, ++ 40,5200, ++ 44,5220, ++ 48,5240, ++ 52,5260, ++ 56,5280, ++ 60,5300, ++ 64,5320, ++ 100,5500, ++ 104,5520, ++ 108,5540, ++ 112,5560, ++ 116,5580, ++ 120,5600, ++ 124,5620, ++ 128,5640, ++ 132,5660, ++ 136,5680, ++ 140,5700, ++// ++ 184,4920, ++ 188,4940, ++ 192,4960, ++ 196,4980, ++ 8,5040, ++ 12,5060, ++ 16,5080, ++ 34,5170, ++ 38,5190, ++ 42,5210, ++ 46,5230, ++// ++ 149,5745, ++ 153,5765, ++ 157,5785, ++ 161,5805, ++ 165,5825 ++// ++}; ++ ++int usbdrv_freq2chan(u32_t freq) ++{ ++ /* 2.4G Hz */ ++ if (freq > 2400 && freq < 3000) ++ { ++ return ((freq-2412)/5) + 1; ++ } ++ else ++ { ++ u16_t ii; ++ u16_t num_chan = sizeof(channel_frequency_11A)/sizeof(u32_t); ++ ++ for(ii = 1; ii < num_chan; ii += 2) ++ { ++ if (channel_frequency_11A[ii] == freq) ++ return channel_frequency_11A[ii-1]; ++ } ++ } ++ ++ return 0; ++} ++ ++int usbdrv_chan2freq(int chan) ++{ ++ int freq; ++ ++ /* If channel number is out of range */ ++ if (chan > 165 || chan <= 0) ++ return -1; ++ ++ /* 2.4G band */ ++ if (chan >= 1 && chan <= 13) ++ { ++ freq = (2412 + (chan - 1) * 5); ++ return freq; ++ } ++ else if (chan >= 36 && chan <= 165) ++ { ++ u16_t ii; ++ u16_t num_chan = sizeof(channel_frequency_11A)/sizeof(u32_t); ++ ++ for(ii = 0; ii < num_chan; ii += 2) ++ { ++ if (channel_frequency_11A[ii] == chan) ++ return channel_frequency_11A[ii+1]; ++ } ++ ++ /* Can't find desired frequency */ ++ if (ii == num_chan) ++ return -1; ++ } ++ ++ /* Can't find deisred frequency */ ++ return -1; ++} ++ ++int usbdrv_ioctl_setessid(struct net_device *dev, struct iw_point *erq) ++{ ++#ifdef ZM_HOSTAPD_SUPPORT ++ //struct usbdrv_private *macp = dev->priv; ++ char essidbuf[IW_ESSID_MAX_SIZE+1]; ++ int i; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ memset(essidbuf, 0, sizeof(essidbuf)); ++ ++ printk(KERN_ERR "usbdrv_ioctl_setessid\n"); ++ ++ //printk("ssidlen=%d\n", erq->length); //for any, it is 1. ++ if (erq->flags) { ++ if (erq->length > (IW_ESSID_MAX_SIZE+1)) ++ return -E2BIG; ++ ++ if (copy_from_user(essidbuf, erq->pointer, erq->length)) ++ return -EFAULT; ++ } ++ ++ //zd_DisasocAll(2); ++ //wait_ms(100); ++ ++ printk(KERN_ERR "essidbuf: "); ++ ++ for(i = 0; i < erq->length; i++) ++ { ++ printk(KERN_ERR "%02x ", essidbuf[i]); ++ } ++ ++ printk(KERN_ERR "\n"); ++ ++ essidbuf[erq->length] = '\0'; ++ //memcpy(macp->wd.ws.ssid, essidbuf, erq->length); ++ //macp->wd.ws.ssidLen = strlen(essidbuf)+2; ++ //macp->wd.ws.ssid[1] = strlen(essidbuf); // Update ssid length ++ ++ zfiWlanSetSSID(dev, essidbuf, erq->length); ++#if 0 ++ printk(KERN_ERR "macp->wd.ws.ssid: "); ++ ++ for(i = 0; i < macp->wd.ws.ssidLen; i++) ++ { ++ printk(KERN_ERR "%02x ", macp->wd.ws.ssid[i]); ++ } ++ ++ printk(KERN_ERR "\n"); ++#endif ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ ++#endif ++ ++ return 0; ++} ++ ++int usbdrv_ioctl_getessid(struct net_device *dev, struct iw_point *erq) ++{ ++ //struct usbdrv_private *macp = dev->priv; ++ u8_t essidbuf[IW_ESSID_MAX_SIZE+1]; ++ u8_t len; ++ u8_t i; ++ ++ ++ //len = macp->wd.ws.ssidLen; ++ //memcpy(essidbuf, macp->wd.ws.ssid, macp->wd.ws.ssidLen); ++ zfiWlanQuerySSID(dev, essidbuf, &len); ++ ++ essidbuf[len] = 0; ++ ++ printk(KERN_ERR "ESSID: "); ++ ++ for(i = 0; i < len; i++) ++ { ++ printk(KERN_ERR "%c", essidbuf[i]); ++ } ++ ++ printk(KERN_ERR "\n"); ++ ++ erq->flags= 1; ++ erq->length = strlen(essidbuf) + 1; ++ ++ if (erq->pointer) ++ if (copy_to_user(erq->pointer, essidbuf, erq->length)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++ ++int usbdrv_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) ++{ ++ ++ return 0; ++} ++ ++#if WIRELESS_EXT > 14 ++/* ++ * Encode a WPA or RSN information element as a custom ++ * element using the hostap format. ++ */ ++u32 encode_ie(void *buf, u32 bufsize, const u8 *ie, u32 ielen, const u8 *leader, u32 leader_len) ++{ ++ u8 *p; ++ u32 i; ++ ++ if (bufsize < leader_len) ++ return 0; ++ p = buf; ++ memcpy(p, leader, leader_len); ++ bufsize -= leader_len; ++ p += leader_len; ++ for (i = 0; i < ielen && bufsize > 2; i++) ++ p += sprintf(p, "%02x", ie[i]); ++ return (i == ielen ? p - (u8 *)buf : 0); ++} ++#endif /* WIRELESS_EXT > 14 */ ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Translate scan data returned from the card to a card independent ++ * format that the Wireless Tools will understand ++ */ ++char *usbdrv_translate_scan(struct net_device *dev, ++ struct iw_request_info *info, char *current_ev, ++ char *end_buf, struct zsBssInfo *list) ++{ ++ struct iw_event iwe; /* Temporary buffer */ ++ u16_t capabilities; ++ char *current_val; /* For rates */ ++ char *last_ev; ++ int i; ++#if WIRELESS_EXT > 14 ++ char buf[64*2 + 30]; ++#endif ++ ++ last_ev = current_ev; ++ ++/* First entry *MUST* be the AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN); ++ current_ev = iwe_stream_add_event( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, ++ end_buf, &iwe, IW_EV_ADDR_LEN); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++/* Other entries will be displayed in the order we give them */ ++ ++/* Add the ESSID */ ++ iwe.u.data.length = list->ssid[1]; ++ if(iwe.u.data.length > 32) ++ iwe.u.data.length = 32; ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ current_ev = iwe_stream_add_point( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, &list->ssid[2]); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++/* Add mode */ ++ iwe.cmd = SIOCGIWMODE; ++ capabilities = (list->capability[1] << 8) + list->capability[0]; ++ if(capabilities & (0x01 | 0x02)) ++ { ++ if(capabilities & 0x01) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ current_ev = iwe_stream_add_event( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++/* Add frequency */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = list->channel; ++/* Channel frequency in KHz */ ++ if (iwe.u.freq.m > 14) ++ { ++ if ((184 <= iwe.u.freq.m) && (iwe.u.freq.m<=196)) ++ iwe.u.freq.m = 4000 + iwe.u.freq.m * 5; ++ else ++ iwe.u.freq.m = 5000 + iwe.u.freq.m * 5; ++ } ++ else ++ { ++ if (iwe.u.freq.m == 14) ++ iwe.u.freq.m = 2484; ++ else ++ iwe.u.freq.m = 2412 + (iwe.u.freq.m - 1) * 5; ++ } ++ iwe.u.freq.e = 6; ++ current_ev = iwe_stream_add_event( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++/* Add quality statistics */ ++ iwe.cmd = IWEVQUAL; ++#if WIRELESS_EXT > 18 ++ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED ++ |IW_QUAL_NOISE_UPDATED; ++#endif ++ iwe.u.qual.level = list->signalStrength; ++ iwe.u.qual.noise = 0; ++ iwe.u.qual.qual = list->signalQuality; ++ current_ev = iwe_stream_add_event( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++/* Add encryption capability */ ++ ++ iwe.cmd = SIOCGIWENCODE; ++ if(capabilities & 0x10) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ ++ iwe.u.data.length = 0; ++ current_ev = iwe_stream_add_point( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, list->ssid); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++/* Rate : stuffing multiple values in a single event require a bit ++ * more of magic */ ++ current_val = current_ev + IW_EV_LCP_LEN; ++ ++ iwe.cmd = SIOCGIWRATE; ++/* Those two flags are ignored... */ ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ ++ for(i = 0 ; i < list->supportedRates[1] ; i++) ++ { ++/* Bit rate given in 500 kb/s units (+ 0x80) */ ++ iwe.u.bitrate.value = ((list->supportedRates[i+2] & 0x7f) * 500000); ++/* Add new value to event */ ++ current_val = iwe_stream_add_value( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_val) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_val; ++ } ++ ++ for (i = 0 ; i < list->extSupportedRates[1] ; i++) ++ { ++/* Bit rate given in 500 kb/s units (+ 0x80) */ ++ iwe.u.bitrate.value = ((list->extSupportedRates[i+2] & 0x7f) * 500000); ++/* Add new value to event */ ++ current_val = iwe_stream_add_value( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_val) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ } ++ ++/* Check if we added any event */ ++ if((current_val - current_ev) > IW_EV_LCP_LEN) ++ current_ev = current_val; ++#if WIRELESS_EXT > 14 ++#define IEEE80211_ELEMID_RSN 0x30 ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ snprintf(buf, sizeof(buf), "bcn_int=%d", (list->beaconInterval[1] << 8) + list->beaconInterval[0]); ++ iwe.u.data.length = strlen(buf); ++ current_ev = iwe_stream_add_point( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, buf); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ ++ if (list->wpaIe[1] != 0) ++ { ++ static const char rsn_leader[] = "rsn_ie="; ++ static const char wpa_leader[] = "wpa_ie="; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ if (list->wpaIe[0] == IEEE80211_ELEMID_RSN) ++ iwe.u.data.length = encode_ie(buf, sizeof(buf), ++ list->wpaIe, list->wpaIe[1]+2, ++ rsn_leader, sizeof(rsn_leader)-1); ++ else ++ iwe.u.data.length = encode_ie(buf, sizeof(buf), ++ list->wpaIe, list->wpaIe[1]+2, ++ wpa_leader, sizeof(wpa_leader)-1); ++ ++ if (iwe.u.data.length != 0) ++ current_ev = iwe_stream_add_point( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, buf); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ } ++ if (list->rsnIe[1] != 0) ++ { ++ static const char rsn_leader[] = "rsn_ie="; ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ ++ if (list->rsnIe[0] == IEEE80211_ELEMID_RSN) ++ { ++ iwe.u.data.length = encode_ie(buf, sizeof(buf), ++ list->rsnIe, list->rsnIe[1]+2, ++ rsn_leader, sizeof(rsn_leader)-1); ++ if (iwe.u.data.length != 0) ++ current_ev = iwe_stream_add_point( ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) ++ info, ++#endif ++ current_ev, end_buf, &iwe, buf); ++ ++ /* Ran out of buffer */ ++ if (last_ev == current_ev) ++ { ++ return end_buf; ++ } ++ ++ last_ev = current_ev; ++ } ++ } ++#endif ++/* The other data in the scan result are not really ++ * interesting, so for now drop it */ ++ return current_ev; ++} ++ ++int usbdrvwext_giwname(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrq, char *extra) ++{ ++ //struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ strcpy(wrq->name, "IEEE 802.11-MIMO"); ++ ++ return 0; ++} ++ ++int usbdrvwext_siwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ u32_t FreqKHz; ++ struct usbdrv_private *macp = dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (freq->e > 1) ++ return -EINVAL; ++ ++ if (freq->e == 1) ++ { ++ FreqKHz = (freq->m / 100000); ++ ++ if (FreqKHz > 4000000) ++ { ++ if (FreqKHz > 5825000) ++ FreqKHz = 5825000; ++ else if (FreqKHz < 4920000) ++ FreqKHz = 4920000; ++ else if (FreqKHz < 5000000) ++ FreqKHz = (((FreqKHz - 4000000) / 5000) * 5000) + 4000000; ++ else ++ FreqKHz = (((FreqKHz - 5000000) / 5000) * 5000) + 5000000; ++ } ++ else ++ { ++ if (FreqKHz > 2484000) ++ FreqKHz = 2484000; ++ else if (FreqKHz < 2412000) ++ FreqKHz = 2412000; ++ else ++ FreqKHz = (((FreqKHz - 2412000) / 5000) * 5000) + 2412000; ++ } ++ ++ } ++ else ++ { ++ FreqKHz = usbdrv_chan2freq(freq->m); ++ ++ if (FreqKHz != -1) ++ FreqKHz *= 1000; ++ else ++ FreqKHz = 2412000; ++ } ++ ++ //printk("freq->m: %d, freq->e: %d\n", freq->m, freq->e); ++ //printk("FreqKHz: %d\n", FreqKHz); ++ ++ if (macp->DeviceOpened == 1) ++ { ++ zfiWlanSetFrequency(dev, FreqKHz, 0); // Immediate ++ //u8_t wpaieLen,wpaie[50]; ++ //zfiWlanQueryWpaIe(dev, wpaie, &wpaieLen); ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ //if (wpaieLen > 2) ++ // zfiWlanSetWpaIe(dev, wpaie, wpaieLen); ++ } ++ ++ return 0; ++} ++ ++int usbdrvwext_giwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ freq->m = zfiWlanQueryFrequency(dev); ++ freq->e = 3; ++ ++ return 0; ++} ++ ++int usbdrvwext_siwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrq, char *extra) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u8_t WlanMode; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ switch(wrq->mode) ++ { ++ case IW_MODE_MASTER: ++ WlanMode = ZM_MODE_AP; ++ break; ++ case IW_MODE_INFRA: ++ WlanMode = ZM_MODE_INFRASTRUCTURE; ++ break; ++ case IW_MODE_ADHOC: ++ WlanMode = ZM_MODE_IBSS; ++ break; ++ default: ++ WlanMode = ZM_MODE_IBSS; ++ break; ++ } ++ ++ zfiWlanSetWlanMode(dev,WlanMode); ++ zfiWlanDisable(dev, 1); ++ zfiWlanEnable(dev); ++ ++ return 0; ++} ++ ++int usbdrvwext_giwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ unsigned long irqFlag; ++ struct usbdrv_private *macp = dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ switch(zfiWlanQueryWlanMode(dev)) ++ { ++ case ZM_MODE_AP: ++ *mode = IW_MODE_MASTER; ++ break; ++ case ZM_MODE_INFRASTRUCTURE: ++ *mode = IW_MODE_INFRA; ++ break; ++ case ZM_MODE_IBSS: ++ *mode = IW_MODE_ADHOC; ++ break; ++ default: ++ *mode = IW_MODE_ADHOC; ++ break; ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ return 0; ++} ++ ++int usbdrvwext_siwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *sens, char *extra) ++{ ++ return 0; ++} ++ ++int usbdrvwext_giwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *sens, char *extra) ++{ ++ sens->value = 0; ++ sens->fixed = 1; ++ ++ return 0; ++} ++ ++int usbdrvwext_giwrange(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *) extra; ++ int i, val; ++ //int num_band_a; ++ u16_t channels[60]; ++ u16_t channel_num; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++#if WIRELESS_EXT > 9 ++ range->txpower_capa = IW_TXPOW_DBM; ++// XXX what about min/max_pmp, min/max_pmt, etc. ++#endif ++ ++#if WIRELESS_EXT > 10 ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 13; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++#endif /* WIRELESS_EXT > 10 */ ++ ++ channel_num = zfiWlanQueryAllowChannels(dev, channels); ++ ++ /* Gurantee reported channel numbers is less or equal to IW_MAX_FREQUENCIES */ ++ if (channel_num > IW_MAX_FREQUENCIES) ++ channel_num = IW_MAX_FREQUENCIES; ++ ++ val = 0; ++ ++ for (i = 0; i < channel_num; i++) ++ { ++ range->freq[val].i = usbdrv_freq2chan(channels[i]); ++ range->freq[val].m = channels[i]; ++ range->freq[val].e = 6; ++ val++; ++ } ++ ++ range->num_channels = channel_num; ++ range->num_frequency = channel_num; ++ ++#if 0 ++ range->num_channels = 14; // Only 2.4G ++ ++/* XXX need to filter against the regulatory domain &| active set */ ++ val = 0; ++ for (i = 1; i <= 14; i++) // B,G Bands ++ { ++ range->freq[val].i = i; ++ if (i == 14) ++ range->freq[val].m = 2484000; ++ else ++ range->freq[val].m = (2412+(i-1)*5)*1000; ++ range->freq[val].e = 3; ++ val++; ++ } ++ ++ num_band_a = (IW_MAX_FREQUENCIES - val); ++ ++ for (i = 0; i < num_band_a; i++) // A Bands ++ { ++ range->freq[val].i = channel_frequency_11A[2 * i]; ++ range->freq[val].m = channel_frequency_11A[2 * i + 1] * 1000; ++ range->freq[val].e = 3; ++ val++; ++ } ++ // MIMO Rate Not Defined Now ++ //For 802.11a, there are too more frequency. We can't return them all ++ range->num_frequency = val; ++#endif ++ ++/* Max of /proc/net/wireless */ ++ range->max_qual.qual = 100; //?? //92; ++ range->max_qual.level = 154; //?? ++ range->max_qual.noise = 154; //?? ++ range->sensitivity = 3; //?? ++ ++// XXX these need to be nsd-specific! ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ range->max_encoding_tokens = 4/*NUM_WEPKEYS*/; //?? ++ range->num_encoding_sizes = 2; //?? ++ ++ range->encoding_size[0] = 5; //?? //WEP Key Encoding Size ++ range->encoding_size[1] = 13;//?? ++ ++// XXX what about num_bitrates/throughput? ++ range->num_bitrates = 0; //?? ++ ++/* estimated max throughput */ ++// XXX need to cap it if we're running at ~2Mbps.. ++ ++ range->throughput = 300000000; ++ ++ return 0; ++} ++ ++int usbdrvwext_siwap(struct net_device *dev, struct iw_request_info *info, ++ struct sockaddr *MacAddr, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (zfiWlanQueryWlanMode(dev) == ZM_MODE_AP) // AP Mode ++ zfiWlanSetMacAddress(dev,(u16_t *)&MacAddr->sa_data[0]); ++ else //STA Mode ++ zfiWlanSetBssid(dev,&MacAddr->sa_data[0]); ++ ++ if (macp->DeviceOpened == 1) ++ { ++ //u8_t wpaieLen,wpaie[80]; ++ //zfiWlanQueryWpaIe(dev, wpaie, &wpaieLen); ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ //if (wpaieLen > 2) ++ // zfiWlanSetWpaIe(dev, wpaie, wpaieLen); ++ } ++ ++ return 0; ++} ++ ++int usbdrvwext_giwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *MacAddr, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ if (zfiWlanQueryWlanMode(dev) == ZM_MODE_AP) // AP Mode ++ zfiWlanQueryMacAddress(dev, &MacAddr->sa_data[0]); ++ else //STA Mode ++ { ++ if (macp->adapterState == ZM_STATUS_MEDIA_CONNECT) ++ { ++ zfiWlanQueryBssid(dev, &MacAddr->sa_data[0]); ++ } ++ else ++ { ++ u8_t zero_addr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ memcpy(&MacAddr->sa_data[0], zero_addr, sizeof(zero_addr)); ++ } ++ } ++ ++ return 0; ++} ++ ++int usbdrvwext_iwaplist(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ //Don't know how to do yet--CWYang(+) ++ return 0; ++ ++} ++ ++int usbdrvwext_siwscan(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ printk("CWY - usbdrvwext_siwscan\n"); ++ ++ zfiWlanScan(dev); ++ ++ return 0; ++} ++ ++int usbdrvwext_giwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ //struct zsWlanDev* wd = (struct zsWlanDev*) zmw_wlan_dev(dev); ++ char *current_ev = extra; ++ char *end_buf; ++ int i; ++ //struct zsBssList BssList; ++ struct zsBssListV1 *pBssList = kmalloc(sizeof(struct zsBssListV1), GFP_KERNEL); ++ //BssList = wd->sta.pBssList; ++ //zmw_get_wlan_dev(dev); ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ if (data->length == 0) ++ { ++ end_buf = extra + IW_SCAN_MAX_DATA; ++ } ++ else ++ { ++ end_buf = extra + data->length; ++ } ++ ++ printk("giwscan - Report Scan Results\n"); ++ //printk("giwscan - BssList Sreucture Len : %d\n", sizeof(BssList)); ++ //printk("giwscan - BssList Count : %d\n", wd->sta.pBssList->bssCount); ++ //printk("giwscan - UpdateBssList Count : %d\n", wd->sta.pUpdateBssList->bssCount); ++ zfiWlanQueryBssListV1(dev, pBssList); ++ //zfiWlanQueryBssList(dev, &BssList); ++ ++/* Read and parse all entries */ ++ printk("giwscan - pBssList->bssCount : %d\n", pBssList->bssCount); ++ //printk("giwscan - BssList.bssCount : %d\n", BssList.bssCount); ++ ++ for (i = 0; i < pBssList->bssCount; i++) ++ { ++/* Translate to WE format this entry */ ++ //current_ev = usbdrv_translate_scan(dev, info, current_ev, ++ // extra + IW_SCAN_MAX_DATA, &pBssList->bssInfo[i]); ++ current_ev = usbdrv_translate_scan(dev, info, current_ev, ++ end_buf, &pBssList->bssInfo[i]); ++ ++#if WIRELESS_EXT > 16 ++ if (current_ev == end_buf) ++ { ++ kfree(pBssList); ++ data->length = current_ev - extra; ++ return -E2BIG; ++ } ++#endif ++ } ++ ++/* Length of data */ ++ data->length = (current_ev - extra); ++ data->flags = 0; /* todo */ ++ ++ kfree(pBssList); ++ ++ return 0; ++} ++ ++int usbdrvwext_siwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *essid, char *extra) ++{ ++ char EssidBuf[IW_ESSID_MAX_SIZE+1]; ++ struct usbdrv_private *macp = dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (essid->flags == 1) ++ { ++ if (essid->length > (IW_ESSID_MAX_SIZE+1)) ++ return -E2BIG; ++ ++ if (copy_from_user(&EssidBuf, essid->pointer, essid->length)) ++ return -EFAULT; ++ ++ EssidBuf[essid->length] = '\0'; ++ //printk("siwessid - Set Essid : %s\n",EssidBuf); ++ //printk("siwessid - Essid Len : %d\n",essid->length); ++ //printk("siwessid - Essid Flag : %x\n",essid->flags); ++ if (macp->DeviceOpened == 1) ++ { ++ zfiWlanSetSSID(dev, EssidBuf, strlen(EssidBuf)); ++ zfiWlanSetFrequency(dev, zfiWlanQueryFrequency(dev), FALSE); ++ zfiWlanSetEncryMode(dev, zfiWlanQueryEncryMode(dev)); ++ //u8_t wpaieLen,wpaie[50]; ++ //zfiWlanQueryWpaIe(dev, wpaie, &wpaieLen); ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ //if (wpaieLen > 2) ++ // zfiWlanSetWpaIe(dev, wpaie, wpaieLen); ++ } ++ } ++ ++ return 0; ++} ++ ++int usbdrvwext_giwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *essid, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ u8_t EssidLen; ++ char EssidBuf[IW_ESSID_MAX_SIZE+1]; ++ int ssid_len; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ zfiWlanQuerySSID(dev, &EssidBuf[0], &EssidLen); ++ ++ /* Convert type from unsigned char to char */ ++ ssid_len = (int)EssidLen; ++ ++ /* Make sure the essid length is not greater than IW_ESSID_MAX_SIZE */ ++ if (ssid_len > IW_ESSID_MAX_SIZE) ++ ssid_len = IW_ESSID_MAX_SIZE; ++ ++ EssidBuf[ssid_len] = '\0'; ++ ++ essid->flags = 1; ++ essid->length = strlen(EssidBuf); ++ ++ memcpy(extra, EssidBuf, essid->length); ++ // wireless.c in Kernel would handle copy_to_user -- line 679 ++ /*if (essid->pointer) ++ { ++ if ( copy_to_user(essid->pointer, EssidBuf, essid->length) ) ++ { ++ printk("giwessid - copy_to_user Fail\n"); ++ return -EFAULT; ++ } ++ }*/ ++ ++ return 0; ++} ++ ++int usbdrvwext_siwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ //Exist but junk--CWYang(+) ++ return 0; ++} ++ ++int usbdrvwext_giwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ u8_t EssidLen; ++ char EssidBuf[IW_ESSID_MAX_SIZE+1]; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ zfiWlanQuerySSID(dev, &EssidBuf[0], &EssidLen); ++ EssidBuf[EssidLen] = 0; ++ ++ data->flags = 1; ++ data->length = strlen(EssidBuf); ++ ++ memcpy(nickname, EssidBuf, data->length); ++ ++ return 0; ++} ++ ++int usbdrvwext_siwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frq, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ //Array to Define Rate Number that Send to Driver ++ u16_t zcIndextoRateBG[16] = {1000, 2000, 5500, 11000, 0, 0, 0, 0, 48000, ++ 24000, 12000, 6000, 54000, 36000, 18000, 9000}; ++ u16_t zcRateToMCS[] = {0xff, 0, 1, 2, 3, 0xb, 0xf, 0xa, 0xe, 0x9, 0xd, ++ 0x8, 0xc}; ++ u8_t i,RateIndex = 4; ++ u16_t RateKbps; ++ ++ //printk("frq->disabled : 0x%x\n",frq->disabled); ++ //printk("frq->value : 0x%x\n",frq->value); ++ ++ RateKbps = frq->value / 1000; ++ //printk("RateKbps : %d\n", RateKbps); ++ for (i = 0; i < 16; i++) ++ { ++ if (RateKbps == zcIndextoRateBG[i]) ++ RateIndex = i; ++ } ++ if (zcIndextoRateBG[RateIndex] == 0) ++ RateIndex = 0xff; ++ //printk("RateIndex : %x\n", RateIndex); ++ for (i = 0; i < 13; i++) ++ if (RateIndex == zcRateToMCS[i]) ++ break; ++ //printk("Index : %x\n", i); ++ if (RateKbps == 65000) ++ { ++ RateIndex = 20; ++ printk("RateIndex : %d\n", RateIndex); ++ } ++ if (macp->DeviceOpened == 1) ++ { ++ zfiWlanSetTxRate(dev, i); ++ //zfiWlanDisable(dev); ++ //zfiWlanEnable(dev); ++ } ++ ++ return 0; ++} ++ ++int usbdrvwext_giwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frq, char *extra) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ frq->fixed = 0; ++ frq->disabled = 0; ++ frq->value = zfiWlanQueryRxRate(dev) * 1000; ++ ++ return 0; ++} ++ ++int usbdrvwext_siwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ int val = rts->value; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ if (rts->disabled) ++ val = 2347; ++ ++ if ((val < 0) || (val > 2347)) ++ return -EINVAL; ++ ++ zfiWlanSetRtsThreshold(dev,val); ++ ++ return 0; ++} ++ ++int usbdrvwext_giwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ rts->value = zfiWlanQueryRtsThreshold(dev); ++ rts->disabled = (rts->value >= 2347); ++ rts->fixed = 1; ++ ++ return 0; ++ ++} ++ ++int usbdrvwext_siwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ u16_t fragThreshold; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ if (frag->disabled) ++ fragThreshold = 0; ++ else ++ fragThreshold = frag->value; ++ ++ zfiWlanSetFragThreshold(dev,fragThreshold); ++ ++ return 0; ++} ++ ++int usbdrvwext_giwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ u16 val; ++ unsigned long irqFlag; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ val = zfiWlanQueryFragThreshold(dev); ++ ++ frag->value = val; ++ ++ frag->disabled = (val >= 2346); ++ frag->fixed = 1; ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ return 0; ++} ++ ++int usbdrvwext_siwtxpow(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ //Not support yet--CWYng(+) ++ return 0; ++} ++ ++int usbdrvwext_giwtxpow(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ //Not support yet--CWYng(+) ++ return 0; ++} ++ ++int usbdrvwext_siwretry(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ //Do nothing--CWYang(+) ++ return 0; ++} ++ ++int usbdrvwext_giwretry(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rrq, char *extra) ++{ ++ //Do nothing--CWYang(+) ++ return 0; ++} ++ ++int usbdrvwext_siwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ struct zsKeyInfo keyInfo; ++ int i, WepState = ZM_ENCRYPTION_WEP_DISABLED; ++ struct usbdrv_private *macp = dev->priv; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ if ((erq->flags & IW_ENCODE_DISABLED) == 0) ++ { ++ keyInfo.key = key; ++ keyInfo.keyLength = erq->length; ++ keyInfo.keyIndex = (erq->flags & IW_ENCODE_INDEX) - 1; ++ if (keyInfo.keyIndex >= 4) ++ keyInfo.keyIndex = 0; ++ keyInfo.flag = ZM_KEY_FLAG_DEFAULT_KEY; ++ ++ zfiWlanSetKey(dev, keyInfo); ++ WepState = ZM_ENCRYPTION_WEP_ENABLED; ++ } ++ else ++ { ++ for (i = 1; i < 4; i++) ++ zfiWlanRemoveKey(dev, 0, i); ++ WepState = ZM_ENCRYPTION_WEP_DISABLED; ++ //zfiWlanSetEncryMode(dev, ZM_NO_WEP); ++ } ++ ++ if (macp->DeviceOpened == 1) ++ { ++ zfiWlanSetWepStatus(dev, WepState); ++ zfiWlanSetFrequency(dev, zfiWlanQueryFrequency(dev), FALSE); ++ //zfiWlanSetEncryMode(dev, zfiWlanQueryEncryMode(dev)); ++ //u8_t wpaieLen,wpaie[50]; ++ //zfiWlanQueryWpaIe(dev, wpaie, &wpaieLen); ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ //if (wpaieLen > 2) ++ // zfiWlanSetWpaIe(dev, wpaie, wpaieLen); ++ } ++ ++ return 0; ++} ++ ++int usbdrvwext_giwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u8_t EncryptionMode; ++ u8_t keyLen = 0; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ EncryptionMode = zfiWlanQueryEncryMode(dev); ++ ++ if (EncryptionMode) ++ { ++ erq->flags = IW_ENCODE_ENABLED; ++ } ++ else ++ { ++ erq->flags = IW_ENCODE_DISABLED; ++ } ++ ++/* We can't return the key, so set the proper flag and return zero */ ++ erq->flags |= IW_ENCODE_NOKEY; ++ memset(key, 0, 16); ++ ++/* Copy the key to the user buffer */ ++ switch(EncryptionMode) ++ { ++ case ZM_WEP64: ++ keyLen = 5; ++ break; ++ case ZM_WEP128: ++ keyLen = 13; ++ break; ++ case ZM_WEP256: ++ keyLen = 29; ++ break; ++ case ZM_AES: ++ keyLen = 16; ++ break; ++ case ZM_TKIP: ++ keyLen = 32; ++ break; ++#ifdef ZM_ENABLE_CENC ++ case ZM_CENC: ++ keyLen = 32; ++ break; ++#endif //ZM_ENABLE_CENC ++ case ZM_NO_WEP: ++ keyLen = 0; ++ break; ++ default : ++ keyLen = 0; ++ printk("Unknown EncryMode\n"); ++ break; ++ ++ } ++ erq->length = keyLen; ++ ++ return 0; ++} ++ ++int usbdrvwext_siwpower(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frq, char *extra) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u8_t PSMode; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ if (frq->disabled) ++ PSMode = ZM_STA_PS_NONE; ++ else ++ PSMode = ZM_STA_PS_MAX; ++ ++ zfiWlanSetPowerSaveMode(dev,PSMode); ++ ++ return 0; ++} ++ ++int usbdrvwext_giwpower(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frq, char *extra) ++{ ++ unsigned long irqFlag; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ if (macp->DeviceOpened != 1) ++ return 0; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ if (zfiWlanQueryPowerSaveMode(dev) == ZM_STA_PS_NONE) ++ frq->disabled = 1; ++ else ++ frq->disabled = 0; ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ return 0; ++} ++ ++//int usbdrvwext_setparam(struct net_device *dev, struct iw_request_info *info, ++// void *w, char *extra) ++//{ ++// struct ieee80211vap *vap = dev->priv; ++// struct ieee80211com *ic = vap->iv_ic; ++// struct ieee80211_rsnparms *rsn = &vap->iv_bss->ni_rsn; ++// int *i = (int *) extra; ++// int param = i[0]; /* parameter id is 1st */ ++// int value = i[1]; /* NB: most values are TYPE_INT */ ++// int retv = 0; ++// int j, caps; ++// const struct ieee80211_authenticator *auth; ++// const struct ieee80211_aclator *acl; ++// ++// switch (param) { ++// case IEEE80211_PARAM_AUTHMODE: ++// switch (value) { ++// case IEEE80211_AUTH_WPA: /* WPA */ ++// case IEEE80211_AUTH_8021X: /* 802.1x */ ++// case IEEE80211_AUTH_OPEN: /* open */ ++// case IEEE80211_AUTH_SHARED: /* shared-key */ ++// case IEEE80211_AUTH_AUTO: /* auto */ ++// auth = ieee80211_authenticator_get(value); ++// if (auth == NULL) ++// return -EINVAL; ++// break; ++// default: ++// return -EINVAL; ++// } ++// switch (value) { ++// case IEEE80211_AUTH_WPA: /* WPA w/ 802.1x */ ++// vap->iv_flags |= IEEE80211_F_PRIVACY; ++// value = IEEE80211_AUTH_8021X; ++// break; ++// case IEEE80211_AUTH_OPEN: /* open */ ++// vap->iv_flags &= ~(IEEE80211_F_WPA|IEEE80211_F_PRIVACY); ++// break; ++// case IEEE80211_AUTH_SHARED: /* shared-key */ ++// case IEEE80211_AUTH_AUTO: /* auto */ ++// case IEEE80211_AUTH_8021X: /* 802.1x */ ++// vap->iv_flags &= ~IEEE80211_F_WPA; ++// /* both require a key so mark the PRIVACY capability */ ++// vap->iv_flags |= IEEE80211_F_PRIVACY; ++// break; ++// } ++// /* NB: authenticator attach/detach happens on state change */ ++// vap->iv_bss->ni_authmode = value; ++// /* XXX mixed/mode/usage? */ ++// vap->iv_auth = auth; ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_PROTMODE: ++// if (value > IEEE80211_PROT_RTSCTS) ++// return -EINVAL; ++// ic->ic_protmode = value; ++// /* NB: if not operating in 11g this can wait */ ++// if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && ++// IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_MCASTCIPHER: ++// if ((vap->iv_caps & cipher2cap(value)) == 0 && ++// !ieee80211_crypto_available(value)) ++// return -EINVAL; ++// rsn->rsn_mcastcipher = value; ++// if (vap->iv_flags & IEEE80211_F_WPA) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_MCASTKEYLEN: ++// if (!(0 < value && value < IEEE80211_KEYBUF_SIZE)) ++// return -EINVAL; ++// /* XXX no way to verify driver capability */ ++// rsn->rsn_mcastkeylen = value; ++// if (vap->iv_flags & IEEE80211_F_WPA) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_UCASTCIPHERS: ++// /* ++// * Convert cipher set to equivalent capabilities. ++// * NB: this logic intentionally ignores unknown and ++// * unsupported ciphers so folks can specify 0xff or ++// * similar and get all available ciphers. ++// */ ++// caps = 0; ++// for (j = 1; j < 32; j++) /* NB: skip WEP */ ++// if ((value & (1<iv_caps & cipher2cap(j)) || ++// ieee80211_crypto_available(j))) ++// caps |= 1<rsn_ucastcipherset = caps; ++// if (vap->iv_flags & IEEE80211_F_WPA) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_UCASTCIPHER: ++// if ((rsn->rsn_ucastcipherset & cipher2cap(value)) == 0) ++// return -EINVAL; ++// rsn->rsn_ucastcipher = value; ++// break; ++// case IEEE80211_PARAM_UCASTKEYLEN: ++// if (!(0 < value && value < IEEE80211_KEYBUF_SIZE)) ++// return -EINVAL; ++// /* XXX no way to verify driver capability */ ++// rsn->rsn_ucastkeylen = value; ++// break; ++// case IEEE80211_PARAM_KEYMGTALGS: ++// /* XXX check */ ++// rsn->rsn_keymgmtset = value; ++// if (vap->iv_flags & IEEE80211_F_WPA) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_RSNCAPS: ++// /* XXX check */ ++// rsn->rsn_caps = value; ++// if (vap->iv_flags & IEEE80211_F_WPA) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_WPA: ++// if (value > 3) ++// return -EINVAL; ++// /* XXX verify ciphers available */ ++// vap->iv_flags &= ~IEEE80211_F_WPA; ++// switch (value) { ++// case 1: ++// vap->iv_flags |= IEEE80211_F_WPA1; ++// break; ++// case 2: ++// vap->iv_flags |= IEEE80211_F_WPA2; ++// break; ++// case 3: ++// vap->iv_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2; ++// break; ++// } ++// retv = ENETRESET; /* XXX? */ ++// break; ++// case IEEE80211_PARAM_ROAMING: ++// if (!(IEEE80211_ROAMING_DEVICE <= value && ++// value <= IEEE80211_ROAMING_MANUAL)) ++// return -EINVAL; ++// ic->ic_roaming = value; ++// break; ++// case IEEE80211_PARAM_PRIVACY: ++// if (value) { ++// /* XXX check for key state? */ ++// vap->iv_flags |= IEEE80211_F_PRIVACY; ++// } else ++// vap->iv_flags &= ~IEEE80211_F_PRIVACY; ++// break; ++// case IEEE80211_PARAM_DROPUNENCRYPTED: ++// if (value) ++// vap->iv_flags |= IEEE80211_F_DROPUNENC; ++// else ++// vap->iv_flags &= ~IEEE80211_F_DROPUNENC; ++// break; ++// case IEEE80211_PARAM_COUNTERMEASURES: ++// if (value) { ++// if ((vap->iv_flags & IEEE80211_F_WPA) == 0) ++// return -EINVAL; ++// vap->iv_flags |= IEEE80211_F_COUNTERM; ++// } else ++// vap->iv_flags &= ~IEEE80211_F_COUNTERM; ++// break; ++// case IEEE80211_PARAM_DRIVER_CAPS: ++// vap->iv_caps = value; /* NB: for testing */ ++// break; ++// case IEEE80211_PARAM_MACCMD: ++// acl = vap->iv_acl; ++// switch (value) { ++// case IEEE80211_MACCMD_POLICY_OPEN: ++// case IEEE80211_MACCMD_POLICY_ALLOW: ++// case IEEE80211_MACCMD_POLICY_DENY: ++// if (acl == NULL) { ++// acl = ieee80211_aclator_get("mac"); ++// if (acl == NULL || !acl->iac_attach(vap)) ++// return -EINVAL; ++// vap->iv_acl = acl; ++// } ++// acl->iac_setpolicy(vap, value); ++// break; ++// case IEEE80211_MACCMD_FLUSH: ++// if (acl != NULL) ++// acl->iac_flush(vap); ++// /* NB: silently ignore when not in use */ ++// break; ++// case IEEE80211_MACCMD_DETACH: ++// if (acl != NULL) { ++// vap->iv_acl = NULL; ++// acl->iac_detach(vap); ++// } ++// break; ++// } ++// break; ++// case IEEE80211_PARAM_WMM: ++// if (ic->ic_caps & IEEE80211_C_WME){ ++// if (value) { ++// vap->iv_flags |= IEEE80211_F_WME; ++// vap->iv_ic->ic_flags |= IEEE80211_F_WME; /* XXX needed by ic_reset */ ++// } ++// else { ++// vap->iv_flags &= ~IEEE80211_F_WME; ++// vap->iv_ic->ic_flags &= ~IEEE80211_F_WME; /* XXX needed by ic_reset */ ++// } ++// retv = ENETRESET; /* Renegotiate for capabilities */ ++// } ++// break; ++// case IEEE80211_PARAM_HIDESSID: ++// if (value) ++// vap->iv_flags |= IEEE80211_F_HIDESSID; ++// else ++// vap->iv_flags &= ~IEEE80211_F_HIDESSID; ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_APBRIDGE: ++// if (value == 0) ++// vap->iv_flags |= IEEE80211_F_NOBRIDGE; ++// else ++// vap->iv_flags &= ~IEEE80211_F_NOBRIDGE; ++// break; ++// case IEEE80211_PARAM_INACT: ++// vap->iv_inact_run = value / IEEE80211_INACT_WAIT; ++// break; ++// case IEEE80211_PARAM_INACT_AUTH: ++// vap->iv_inact_auth = value / IEEE80211_INACT_WAIT; ++// break; ++// case IEEE80211_PARAM_INACT_INIT: ++// vap->iv_inact_init = value / IEEE80211_INACT_WAIT; ++// break; ++// case IEEE80211_PARAM_ABOLT: ++// caps = 0; ++// /* ++// * Map abolt settings to capability bits; ++// * this also strips unknown/unwanted bits. ++// */ ++// if (value & IEEE80211_ABOLT_TURBO_PRIME) ++// caps |= IEEE80211_ATHC_TURBOP; ++// if (value & IEEE80211_ABOLT_COMPRESSION) ++// caps |= IEEE80211_ATHC_COMP; ++// if (value & IEEE80211_ABOLT_FAST_FRAME) ++// caps |= IEEE80211_ATHC_FF; ++// if (value & IEEE80211_ABOLT_XR) ++// caps |= IEEE80211_ATHC_XR; ++// if (value & IEEE80211_ABOLT_AR) ++// caps |= IEEE80211_ATHC_AR; ++// if (value & IEEE80211_ABOLT_BURST) ++// caps |= IEEE80211_ATHC_BURST; ++// if (value & IEEE80211_ABOLT_WME_ELE) ++// caps |= IEEE80211_ATHC_WME; ++// /* verify requested capabilities are supported */ ++// if ((caps & ic->ic_ath_cap) != caps) ++// return -EINVAL; ++// if (vap->iv_ath_cap != caps) { ++// if ((vap->iv_ath_cap ^ caps) & IEEE80211_ATHC_TURBOP) { ++// if (ieee80211_set_turbo(dev, caps & IEEE80211_ATHC_TURBOP)) ++// return -EINVAL; ++// ieee80211_scan_flush(ic); ++// } ++// vap->iv_ath_cap = caps; ++// ic->ic_athcapsetup(vap->iv_ic, vap->iv_ath_cap); ++// retv = ENETRESET; ++// } ++// break; ++// case IEEE80211_PARAM_DTIM_PERIOD: ++// if (vap->iv_opmode != IEEE80211_M_HOSTAP && ++// vap->iv_opmode != IEEE80211_M_IBSS) ++// return -EINVAL; ++// if (IEEE80211_DTIM_MIN <= value && ++// value <= IEEE80211_DTIM_MAX) { ++// vap->iv_dtim_period = value; ++// retv = ENETRESET; /* requires restart */ ++// } else ++// retv = EINVAL; ++// break; ++// case IEEE80211_PARAM_BEACON_INTERVAL: ++// if (vap->iv_opmode != IEEE80211_M_HOSTAP && ++// vap->iv_opmode != IEEE80211_M_IBSS) ++// return -EINVAL; ++// if (IEEE80211_BINTVAL_MIN <= value && ++// value <= IEEE80211_BINTVAL_MAX) { ++// ic->ic_lintval = value; /* XXX multi-bss */ ++// retv = ENETRESET; /* requires restart */ ++// } else ++// retv = EINVAL; ++// break; ++// case IEEE80211_PARAM_DOTH: ++// if (value) { ++// ic->ic_flags |= IEEE80211_F_DOTH; ++// } ++// else ++// ic->ic_flags &= ~IEEE80211_F_DOTH; ++// retv = ENETRESET; /* XXX: need something this drastic? */ ++// break; ++// case IEEE80211_PARAM_PWRTARGET: ++// ic->ic_curchanmaxpwr = value; ++// break; ++// case IEEE80211_PARAM_GENREASSOC: ++// IEEE80211_SEND_MGMT(vap->iv_bss, IEEE80211_FC0_SUBTYPE_REASSOC_REQ, 0); ++// break; ++// case IEEE80211_PARAM_COMPRESSION: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_COMP, value); ++// break; ++// case IEEE80211_PARAM_WMM_AGGRMODE: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_WME, value); ++// break; ++// case IEEE80211_PARAM_FF: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_FF, value); ++// break; ++// case IEEE80211_PARAM_TURBO: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_TURBOP, value); ++// if (retv == ENETRESET) { ++// if(ieee80211_set_turbo(dev,value)) ++// return -EINVAL; ++// ieee80211_scan_flush(ic); ++// } ++// break; ++// case IEEE80211_PARAM_XR: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_XR, value); ++// break; ++// case IEEE80211_PARAM_BURST: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_BURST, value); ++// break; ++// case IEEE80211_PARAM_AR: ++// retv = ieee80211_setathcap(vap, IEEE80211_ATHC_AR, value); ++// break; ++// case IEEE80211_PARAM_PUREG: ++// if (value) ++// vap->iv_flags |= IEEE80211_F_PUREG; ++// else ++// vap->iv_flags &= ~IEEE80211_F_PUREG; ++// /* NB: reset only if we're operating on an 11g channel */ ++// if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && ++// IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_WDS: ++// if (value) ++// vap->iv_flags_ext |= IEEE80211_FEXT_WDS; ++// else ++// vap->iv_flags_ext &= ~IEEE80211_FEXT_WDS; ++// break; ++// case IEEE80211_PARAM_BGSCAN: ++// if (value) { ++// if ((vap->iv_caps & IEEE80211_C_BGSCAN) == 0) ++// return -EINVAL; ++// vap->iv_flags |= IEEE80211_F_BGSCAN; ++// } else { ++// /* XXX racey? */ ++// vap->iv_flags &= ~IEEE80211_F_BGSCAN; ++// ieee80211_cancel_scan(vap); /* anything current */ ++// } ++// break; ++// case IEEE80211_PARAM_BGSCAN_IDLE: ++// if (value >= IEEE80211_BGSCAN_IDLE_MIN) ++// vap->iv_bgscanidle = value*HZ/1000; ++// else ++// retv = EINVAL; ++// break; ++// case IEEE80211_PARAM_BGSCAN_INTERVAL: ++// if (value >= IEEE80211_BGSCAN_INTVAL_MIN) ++// vap->iv_bgscanintvl = value*HZ; ++// else ++// retv = EINVAL; ++// break; ++// case IEEE80211_PARAM_MCAST_RATE: ++// /* units are in KILObits per second */ ++// if (value >= 256 && value <= 54000) ++// vap->iv_mcast_rate = value; ++// else ++// retv = EINVAL; ++// break; ++// case IEEE80211_PARAM_COVERAGE_CLASS: ++// if (value >= 0 && value <= IEEE80211_COVERAGE_CLASS_MAX) { ++// ic->ic_coverageclass = value; ++// if (IS_UP_AUTO(vap)) ++// ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); ++// retv = 0; ++// } ++// else ++// retv = EINVAL; ++// break; ++// case IEEE80211_PARAM_COUNTRY_IE: ++// if (value) ++// ic->ic_flags_ext |= IEEE80211_FEXT_COUNTRYIE; ++// else ++// ic->ic_flags_ext &= ~IEEE80211_FEXT_COUNTRYIE; ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_REGCLASS: ++// if (value) ++// ic->ic_flags_ext |= IEEE80211_FEXT_REGCLASS; ++// else ++// ic->ic_flags_ext &= ~IEEE80211_FEXT_REGCLASS; ++// retv = ENETRESET; ++// break; ++// case IEEE80211_PARAM_SCANVALID: ++// vap->iv_scanvalid = value*HZ; ++// break; ++// case IEEE80211_PARAM_ROAM_RSSI_11A: ++// vap->iv_roam.rssi11a = value; ++// break; ++// case IEEE80211_PARAM_ROAM_RSSI_11B: ++// vap->iv_roam.rssi11bOnly = value; ++// break; ++// case IEEE80211_PARAM_ROAM_RSSI_11G: ++// vap->iv_roam.rssi11b = value; ++// break; ++// case IEEE80211_PARAM_ROAM_RATE_11A: ++// vap->iv_roam.rate11a = value; ++// break; ++// case IEEE80211_PARAM_ROAM_RATE_11B: ++// vap->iv_roam.rate11bOnly = value; ++// break; ++// case IEEE80211_PARAM_ROAM_RATE_11G: ++// vap->iv_roam.rate11b = value; ++// break; ++// case IEEE80211_PARAM_UAPSDINFO: ++// if (vap->iv_opmode == IEEE80211_M_HOSTAP) { ++// if (ic->ic_caps & IEEE80211_C_UAPSD) { ++// if (value) ++// IEEE80211_VAP_UAPSD_ENABLE(vap); ++// else ++// IEEE80211_VAP_UAPSD_DISABLE(vap); ++// retv = ENETRESET; ++// } ++// } ++// else if (vap->iv_opmode == IEEE80211_M_STA) { ++// vap->iv_uapsdinfo = value; ++// IEEE80211_VAP_UAPSD_ENABLE(vap); ++// retv = ENETRESET; ++// } ++// break; ++// case IEEE80211_PARAM_SLEEP: ++// /* XXX: Forced sleep for testing. Does not actually place the ++// * HW in sleep mode yet. this only makes sense for STAs. ++// */ ++// if (value) { ++// /* goto sleep */ ++// IEEE80211_VAP_GOTOSLEEP(vap); ++// } ++// else { ++// /* wakeup */ ++// IEEE80211_VAP_WAKEUP(vap); ++// } ++// ieee80211_send_nulldata(ieee80211_ref_node(vap->iv_bss)); ++// break; ++// case IEEE80211_PARAM_QOSNULL: ++// /* Force a QoS Null for testing. */ ++// ieee80211_send_qosnulldata(vap->iv_bss, value); ++// break; ++// case IEEE80211_PARAM_PSPOLL: ++// /* Force a PS-POLL for testing. */ ++// ieee80211_send_pspoll(vap->iv_bss); ++// break; ++// case IEEE80211_PARAM_EOSPDROP: ++// if (vap->iv_opmode == IEEE80211_M_HOSTAP) { ++// if (value) IEEE80211_VAP_EOSPDROP_ENABLE(vap); ++// else IEEE80211_VAP_EOSPDROP_DISABLE(vap); ++// } ++// break; ++// case IEEE80211_PARAM_MARKDFS: ++// if (value) ++// ic->ic_flags_ext |= IEEE80211_FEXT_MARKDFS; ++// else ++// ic->ic_flags_ext &= ~IEEE80211_FEXT_MARKDFS; ++// break; ++// case IEEE80211_PARAM_CHANBW: ++// switch (value) { ++// case 0: ++// ic->ic_chanbwflag = 0; ++// break; ++// case 1: ++// ic->ic_chanbwflag = IEEE80211_CHAN_HALF; ++// break; ++// case 2: ++// ic->ic_chanbwflag = IEEE80211_CHAN_QUARTER; ++// break; ++// default: ++// retv = EINVAL; ++// break; ++// } ++// break; ++// case IEEE80211_PARAM_SHORTPREAMBLE: ++// if (value) { ++// ic->ic_caps |= IEEE80211_C_SHPREAMBLE; ++// } else { ++// ic->ic_caps &= ~IEEE80211_C_SHPREAMBLE; ++// } ++// retv = ENETRESET; ++// break; ++// default: ++// retv = EOPNOTSUPP; ++// break; ++// } ++// /* XXX should any of these cause a rescan? */ ++// if (retv == ENETRESET) ++// retv = IS_UP_AUTO(vap) ? ieee80211_open(vap->iv_dev) : 0; ++// return -retv; ++//} ++ ++int usbdrvwext_setmode(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ return 0; ++} ++ ++int usbdrvwext_getmode(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ //struct usbdrv_private *macp = dev->priv; ++ struct iw_point *wri = (struct iw_point *)extra; ++ char mode[8]; ++ ++ strcpy(mode,"11g"); ++ return (copy_to_user(wri->pointer, mode, 6) ? -EFAULT : 0); ++} ++ ++int zfLnxPrivateIoctl(struct net_device *dev, struct zdap_ioctl* zdreq) ++{ ++ //void* regp = macp->regp; ++ u16_t cmd; ++ //u32_t temp; ++ u32_t* p; ++ u32_t i; ++ ++ cmd = zdreq->cmd; ++ switch(cmd) ++ { ++ case ZM_IOCTL_REG_READ: ++ zfiDbgReadReg(dev, zdreq->addr); ++ break; ++ ++ case ZM_IOCTL_REG_WRITE: ++ zfiDbgWriteReg(dev, zdreq->addr, zdreq->value); ++ break; ++ ++ case ZM_IOCTL_MEM_READ: ++ p = (u32_t *) bus_to_virt(zdreq->addr); ++ printk(KERN_DEBUG "usbdrv: read memory addr: 0x%08x value: 0x%08x\n", zdreq->addr, *p); ++ break; ++ ++ case ZM_IOCTL_MEM_WRITE: ++ p = (u32_t *) bus_to_virt(zdreq->addr); ++ *p = zdreq->value; ++ printk(KERN_DEBUG "usbdrv: write value: 0x%08x to memory addr: 0x%08x\n", zdreq->value, zdreq->addr); ++ break; ++ ++ case ZM_IOCTL_TALLY : ++ zfiWlanShowTally(dev); ++ if (zdreq->addr) ++ zfiWlanResetTally(dev); ++ break; ++ ++ case ZM_IOCTL_TEST : ++ printk(KERN_DEBUG "ZM_IOCTL_TEST:len=%d\n", zdreq->addr); ++ //zfiWlanReadReg(dev, 0x10f400); ++ //zfiWlanReadReg(dev, 0x10f404); ++ printk("IOCTL TEST\n"); ++ #if 1 ++ //print packet ++ for (i=0; iaddr; i++) ++ { ++ if ((i&0x7) == 0) ++ { ++ printk("\n"); ++ } ++ printk("%02X ", (unsigned char)zdreq->data[i]); ++ } ++ printk("\n"); ++ #endif ++ ++ ++ #if 0 //For Test?? 1 to 0 by CWYang(-) ++ { ++ struct sk_buff* s; ++ ++ /* Allocate a skb */ ++ s = alloc_skb(2000, GFP_ATOMIC); ++ ++ /* Copy data to skb */ ++ for (i=0; iaddr; i++) ++ { ++ s->data[i] = zdreq->data[i]; ++ } ++ s->len = zdreq->addr; ++ ++ /* Call zfIdlRecv() */ ++ zfiRecv80211(dev, s, NULL); ++ } ++ #endif ++ ++ break; ++ ++ ++/****************************** ZDCONFIG ******************************/ ++ case ZM_IOCTL_FRAG : ++ zfiWlanSetFragThreshold(dev, zdreq->addr); ++ break; ++ ++ case ZM_IOCTL_RTS : ++ zfiWlanSetRtsThreshold(dev, zdreq->addr); ++ break; ++ ++ case ZM_IOCTL_SCAN : ++ zfiWlanScan(dev); ++ break; ++ ++ case ZM_IOCTL_KEY : ++ { ++ u8_t key[29]; ++ struct zsKeyInfo keyInfo; ++ u32_t i; ++ ++ for (i=0; i<29; i++) ++ { ++ key[i] = 0; ++ } ++ ++ for (i=0; iaddr; i++) ++ { ++ key[i] = zdreq->data[i]; ++ } ++ ++ printk("key len=%d, key=%02x%02x%02x%02x%02x...\n", ++ zdreq->addr, key[0], key[1], key[2], key[3], key[4]); ++ ++ keyInfo.keyLength = zdreq->addr; ++ keyInfo.keyIndex = 0; ++ keyInfo.flag = 0; ++ keyInfo.key = key; ++ zfiWlanSetKey(dev, keyInfo); ++ } ++ break; ++ ++ case ZM_IOCTL_RATE : ++ zfiWlanSetTxRate(dev, zdreq->addr); ++ break; ++ ++ case ZM_IOCTL_ENCRYPTION_MODE : ++ zfiWlanSetEncryMode(dev, zdreq->addr); ++ ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ break; ++ //CWYang(+) ++ case ZM_IOCTL_SIGNAL_STRENGTH : ++ { ++ u8_t buffer[2]; ++ zfiWlanQuerySignalInfo(dev, &buffer[0]); ++ printk("Current Signal Strength : %02d\n", buffer[0]); ++ } ++ break; ++ //CWYang(+) ++ case ZM_IOCTL_SIGNAL_QUALITY : ++ { ++ u8_t buffer[2]; ++ zfiWlanQuerySignalInfo(dev, &buffer[0]); ++ printk("Current Signal Quality : %02d\n", buffer[1]); ++ } ++ break; ++ ++ case ZM_IOCTL_SET_PIBSS_MODE: ++ if (zdreq->addr == 1) ++ zfiWlanSetWlanMode(dev, ZM_MODE_PSEUDO); ++ else ++ zfiWlanSetWlanMode(dev, ZM_MODE_INFRASTRUCTURE); ++ ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ ++ break; ++/****************************** ZDCONFIG ******************************/ ++ ++ default : ++ printk(KERN_ERR "usbdrv: error command = %x\n", cmd); ++ break; ++ } ++ ++ return 0; ++} ++ ++int usbdrv_wpa_ioctl(struct net_device *dev, struct athr_wlan_param *zdparm) ++{ ++ int ret = 0; ++ u8_t bc_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ u8_t mac_addr[80]; ++ struct zsKeyInfo keyInfo; ++ struct usbdrv_private *macp = dev->priv; ++ u16_t vapId = 0; ++ ++ //zmw_get_wlan_dev(dev); ++ ++ switch(zdparm->cmd) ++ { ++ case ZD_CMD_SET_ENCRYPT_KEY: ++ ++ /* Set up key information */ ++ keyInfo.keyLength = zdparm->u.crypt.key_len; ++ keyInfo.keyIndex = zdparm->u.crypt.idx; ++ if (zfiWlanQueryWlanMode(dev) == ZM_MODE_AP) // AP Mode ++ keyInfo.flag = ZM_KEY_FLAG_AUTHENTICATOR; ++ else ++ keyInfo.flag = 0; ++ keyInfo.key = zdparm->u.crypt.key; ++ keyInfo.initIv = zdparm->u.crypt.seq; ++ keyInfo.macAddr = (u16_t *)zdparm->sta_addr; ++ ++ /* Identify the MAC address information */ ++ if (memcmp(zdparm->sta_addr, bc_addr, sizeof(bc_addr)) == 0) ++ { ++ keyInfo.flag |= ZM_KEY_FLAG_GK; ++ } ++ else ++ { ++ keyInfo.flag |= ZM_KEY_FLAG_PK; ++ } ++ ++ if (!strcmp(zdparm->u.crypt.alg, "NONE")) ++ { ++ //u8_t zero_mac[]={0,0,0,0,0,0}; ++ ++ /* Set key length to zero */ ++ keyInfo.keyLength = 0; ++ ++ if (zdparm->sta_addr[0] & 1)//del group key ++ { ++ //if (macp->cardSetting.WPAIeLen==0) ++ //{//802.1x dynamic WEP ++ // mDynKeyMode = 0; ++ // mKeyFormat[0] = 0; ++ // mPrivacyInvoked[0]=FALSE; ++ // mCap[0] &= ~CAP_PRIVACY; ++ // macp->cardSetting.EncryOnOff[0]=0; ++ //} ++ //mWpaBcKeyLen = mGkInstalled = 0; ++ } ++ else ++ { ++ //if (memcmp(zero_mac,zdparm->sta_addr, 6)==0) ++ //{ ++ // mDynKeyMode=0; ++ // mKeyFormat[0]=0; ++ // pSetting->DynKeyMode=0; ++ // pSetting->EncryMode[0]=0; ++ // mDynKeyMode=0; ++ //} ++ } ++ ++ printk(KERN_ERR "Set Encryption Type NONE\n"); ++ return ret; ++ } ++ else if (!strcmp(zdparm->u.crypt.alg, "TKIP")) ++ { ++ zfiWlanSetEncryMode(dev, ZM_TKIP); ++ //Linux Supplicant will inverse Tx/Rx key ++ //So we inverse it back //CWYang(+) ++ //zfMemoryCopy(&temp[0], &keyInfo.key[16], 8); ++ //zfMemoryCopy(&keyInfo.key[16], keyInfo.key[24], 8); ++ //zfMemoryCopy(&keyInfo.key[24], &temp[0], 8); ++ //u8_t temp; ++ //int k; ++ //for (k = 0; k < 8; k++) ++ //{ ++ // temp = keyInfo.key[16 + k]; ++ // keyInfo.key[16 + k] = keyInfo.key[24 + k]; ++ // keyInfo.key[24 + k] = temp; ++ //} ++ //CamEncryType = ZM_TKIP; ++ ////if (idx == 0) ++ //{// Pairwise key ++ // mKeyFormat[0] = CamEncryType; ++ // mDynKeyMode = pSetting->DynKeyMode = DYN_KEY_TKIP; ++ //} ++ } ++ else if (!strcmp(zdparm->u.crypt.alg, "CCMP")) ++ { ++ zfiWlanSetEncryMode(dev, ZM_AES); ++ //CamEncryType = ZM_AES; ++ ////if (idx == 0) ++ //{// Pairwise key ++ // mKeyFormat[0] = CamEncryType; ++ // mDynKeyMode = pSetting->DynKeyMode = DYN_KEY_AES; ++ //} ++ } ++ else if (!strcmp(zdparm->u.crypt.alg, "WEP")) ++ { ++ if (keyInfo.keyLength == 5) ++ { // WEP 64 ++ zfiWlanSetEncryMode(dev, ZM_WEP64); ++ // CamEncryType = ZM_WEP64; ++ // tmpDynKeyMode=DYN_KEY_WEP64; ++ } ++ else if (keyInfo.keyLength == 13) ++ {//keylen=13, WEP 128 ++ zfiWlanSetEncryMode(dev, ZM_WEP128); ++ // CamEncryType = ZM_WEP128; ++ // tmpDynKeyMode=DYN_KEY_WEP128; ++ } ++ else ++ { ++ zfiWlanSetEncryMode(dev, ZM_WEP256); ++ } ++ ++ // For Dynamic WEP key (Non-WPA Radius), the key ID range: 0-3 ++ // In WPA/RSN mode, the key ID range: 1-3, usually, a broadcast key. ++ // For WEP key setting: we set mDynKeyMode and mKeyFormat in following case: ++ // 1. For 802.1x dynamically generated WEP key method. ++ // 2. For WPA/RSN mode, but key id == 0. (But this is an impossible case) ++ // So, only check case 1. ++ //if (macp->cardSetting.WPAIeLen==0) ++ //{ ++ // mKeyFormat[0] = CamEncryType; ++ // mDynKeyMode = pSetting->DynKeyMode = tmpDynKeyMode; ++ // mPrivacyInvoked[0]=TRUE; ++ // mCap[0] |= CAP_PRIVACY; ++ // macp->cardSetting.EncryOnOff[0]=1; ++ //} ++ } ++ ++ /* DUMP key context */ ++//#ifdef WPA_DEBUG ++ if (keyInfo.keyLength > 0) ++ { ++ int ii; ++ printk("Otus: Key Context:\n"); ++ for(ii = 0; ii < keyInfo.keyLength;) ++ { ++ printk("0x%02x ", keyInfo.key[ii]); ++ if((++ii % 16) == 0) ++ printk("\n"); ++ } ++ printk("\n"); ++ } ++//#endif ++ ++ /* Set encrypt mode */ ++ //zfiWlanSetEncryMode(dev, CamEncryType); ++ vapId = zfLnxGetVapId(dev); ++ if (vapId == 0xffff) ++ keyInfo.vapId = 0; ++ else ++ keyInfo.vapId = vapId + 1; ++ keyInfo.vapAddr[0] = keyInfo.macAddr[0]; ++ keyInfo.vapAddr[1] = keyInfo.macAddr[1]; ++ keyInfo.vapAddr[2] = keyInfo.macAddr[2]; ++ ++ zfiWlanSetKey(dev, keyInfo); ++ ++ //zfiWlanDisable(dev); ++ //zfiWlanEnable(dev); ++ break; ++ ++ case ZD_CMD_SET_MLME: ++ printk(KERN_ERR "usbdrv_wpa_ioctl: ZD_CMD_SET_MLME\n"); ++ ++ /* Translate STA's address */ ++ sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", zdparm->sta_addr[0], zdparm->sta_addr[1], ++ zdparm->sta_addr[2], zdparm->sta_addr[3], zdparm->sta_addr[4], zdparm->sta_addr[5]); ++ ++ switch(zdparm->u.mlme.cmd) ++ { ++ case MLME_STA_DEAUTH: ++ printk(" -------Call zfiWlanDeauth, reason:%d\n",zdparm->u.mlme.reason_code); ++ if(zfiWlanDeauth(dev, (u16_t*) zdparm->sta_addr, zdparm->u.mlme.reason_code) != 0) ++ printk(KERN_ERR "Can't deauthencate STA: %s\n", mac_addr); ++ else ++ printk(KERN_ERR "Deauthenticate STA: %s with reason code: %d\n", mac_addr, zdparm->u.mlme.reason_code); ++ break; ++ ++ case MLME_STA_DISASSOC: ++ printk(" -------Call zfiWlanDeauth, reason:%d\n",zdparm->u.mlme.reason_code); ++ if(zfiWlanDeauth(dev, (u16_t*) zdparm->sta_addr, zdparm->u.mlme.reason_code) != 0) ++ printk(KERN_ERR "Can't disassociate STA: %s\n", mac_addr); ++ else ++ printk(KERN_ERR "Disassociate STA: %s with reason code: %d\n", mac_addr, zdparm->u.mlme.reason_code); ++ break; ++ ++ default: ++ printk(KERN_ERR "MLME command: 0x%04x not support\n", zdparm->u.mlme.cmd); ++ break; ++ } ++ ++ break; ++ ++ case ZD_CMD_SCAN_REQ: ++ printk(KERN_ERR "usbdrv_wpa_ioctl: ZD_CMD_SCAN_REQ\n"); ++ break; ++ ++ case ZD_CMD_SET_GENERIC_ELEMENT: ++ printk(KERN_ERR "usbdrv_wpa_ioctl: ZD_CMD_SET_GENERIC_ELEMENT\n"); ++ ++ /* Copy the WPA IE */ ++ //zm_msg1_mm(ZM_LV_0, "CWY - wpaie Length : ", zdparm->u.generic_elem.len); ++ printk(KERN_ERR "wpaie Length : %d\n", zdparm->u.generic_elem.len); ++ if (zfiWlanQueryWlanMode(dev) == ZM_MODE_AP) // AP Mode ++ { ++ zfiWlanSetWpaIe(dev, zdparm->u.generic_elem.data, zdparm->u.generic_elem.len); ++ } ++ else ++ { ++ macp->supLen = zdparm->u.generic_elem.len; ++ memcpy(macp->supIe, zdparm->u.generic_elem.data, zdparm->u.generic_elem.len); ++ } ++ zfiWlanSetWpaSupport(dev, 1); ++ //zfiWlanSetWpaIe(dev, zdparm->u.generic_elem.data, zdparm->u.generic_elem.len); ++ { ++ int ii; ++ u8_t len = zdparm->u.generic_elem.len; ++ u8_t *wpaie = (u8_t *)zdparm->u.generic_elem.data; ++ ++ printk(KERN_ERR "wd->ap.wpaLen: %d\n", len); ++ ++ /* DUMP WPA IE */ ++ for(ii = 0; ii < len;) ++ { ++ printk(KERN_ERR "0x%02x ", wpaie[ii]); ++ ++ if((++ii % 16) == 0) ++ printk(KERN_ERR "\n"); ++ } ++ printk(KERN_ERR "\n"); ++ } ++ ++// #ifdef ZM_HOSTAPD_SUPPORT ++ //if (wd->wlanMode == ZM_MODE_AP) ++ //{// Update Beacon FIFO in the next TBTT. ++ // memcpy(&mWPAIe, pSetting->WPAIe, pSetting->WPAIeLen); ++ // printk(KERN_ERR "Copy WPA IE into mWPAIe\n"); ++ //} ++// #endif ++ break; ++ ++// #ifdef ZM_HOSTAPD_SUPPORT ++ case ZD_CMD_GET_TSC: ++ printk(KERN_ERR "usbdrv_wpa_ioctl: ZD_CMD_GET_TSC\n"); ++ break; ++// #endif ++ ++ default: ++ printk(KERN_ERR "usbdrv_wpa_ioctl default: 0x%04x\n", zdparm->cmd); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef ZM_ENABLE_CENC ++int usbdrv_cenc_ioctl(struct net_device *dev, struct zydas_cenc_param *zdparm) ++{ ++ //struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ struct zsKeyInfo keyInfo; ++ u16_t apId; ++ u8_t bc_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++ int ret = 0; ++ int ii; ++ ++ /* Get the AP Id */ ++ apId = zfLnxGetVapId(dev); ++ ++ if (apId == 0xffff) ++ { ++ apId = 0; ++ } ++ else ++ { ++ apId = apId+1; ++ } ++ ++ switch (zdparm->cmd) ++ { ++ case ZM_CMD_CENC_SETCENC: ++ printk(KERN_ERR "ZM_CMD_CENC_SETCENC\n"); ++ printk(KERN_ERR "length: %d\n", zdparm->len); ++ printk(KERN_ERR "policy: %d\n", zdparm->u.info.cenc_policy); ++ break; ++ case ZM_CMD_CENC_SETKEY: ++ //ret = wai_ioctl_setkey(vap, ioctl_msg); ++ printk(KERN_ERR "ZM_CMD_CENC_SETKEY\n"); ++ ++ printk(KERN_ERR "MAC address= "); ++ for(ii = 0; ii < 6; ii++) ++ { ++ printk(KERN_ERR "0x%02x ", zdparm->u.crypt.sta_addr[ii]); ++ } ++ printk(KERN_ERR "\n"); ++ ++ printk(KERN_ERR "Key Index: %d\n", zdparm->u.crypt.keyid); ++ printk(KERN_ERR "Encryption key= "); ++ for(ii = 0; ii < 16; ii++) ++ { ++ printk(KERN_ERR "0x%02x ", zdparm->u.crypt.key[ii]); ++ } ++ printk(KERN_ERR "\n"); ++ ++ printk(KERN_ERR "MIC key= "); ++ for(ii = 16; ii < ZM_CENC_KEY_SIZE; ii++) ++ { ++ printk(KERN_ERR "0x%02x ", zdparm->u.crypt.key[ii]); ++ } ++ printk(KERN_ERR "\n"); ++ ++ /* Set up key information */ ++ keyInfo.keyLength = ZM_CENC_KEY_SIZE; ++ keyInfo.keyIndex = zdparm->u.crypt.keyid; ++ keyInfo.flag = ZM_KEY_FLAG_AUTHENTICATOR | ZM_KEY_FLAG_CENC; ++ keyInfo.key = zdparm->u.crypt.key; ++ keyInfo.macAddr = (u16_t *)zdparm->u.crypt.sta_addr; ++ ++ /* Identify the MAC address information */ ++ if (memcmp(zdparm->u.crypt.sta_addr, bc_addr, sizeof(bc_addr)) == 0) ++ { ++ keyInfo.flag |= ZM_KEY_FLAG_GK; ++ keyInfo.vapId = apId; ++ memcpy(keyInfo.vapAddr, dev->dev_addr, ETH_ALEN); ++ } ++ else ++ { ++ keyInfo.flag |= ZM_KEY_FLAG_PK; ++ } ++ ++ zfiWlanSetKey(dev, keyInfo); ++ ++ break; ++ case ZM_CMD_CENC_REKEY: ++ //ret = wai_ioctl_rekey(vap, ioctl_msg); ++ printk(KERN_ERR "ZM_CMD_CENC_REKEY\n"); ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ ++ } ++ ++ //if (retv == ENETRESET) ++ // retv = IS_UP_AUTO(vap) ? ieee80211_open(vap->iv_dev) : 0; ++ ++ return ret; ++} ++#endif //ZM_ENABLE_CENC ++///////////////////////////////////////// ++int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++// struct usbdrv_private *macp; ++// void *regp; ++ struct zdap_ioctl zdreq; ++ struct iwreq *wrq = (struct iwreq *)ifr; ++ struct athr_wlan_param zdparm; ++ struct usbdrv_private *macp = dev->priv; ++ ++ int err = 0; ++ int changed = 0; ++ ++// macp = dev->priv; ++// regp = macp->regp; ++ ++ if(!netif_running(dev)) ++ return -EINVAL; ++ ++ switch (cmd) ++ { ++ case SIOCGIWNAME: ++ strcpy(wrq->u.name, "IEEE 802.11-DS"); ++ break; ++ ++ case SIOCGIWAP: ++ err = usbdrvwext_giwap(dev, NULL, &wrq->u.ap_addr, NULL); ++ break; ++ ++ ++ case SIOCSIWAP: ++ err = usbdrvwext_siwap(dev, NULL, &wrq->u.ap_addr, NULL); ++ break; ++ ++ ++ case SIOCGIWMODE: ++ err = usbdrvwext_giwmode(dev, NULL, &wrq->u.mode, NULL); ++ break; ++ ++ ++ case SIOCSIWESSID: ++ printk(KERN_ERR "CWY - usbdrvwext_siwessid\n"); ++ //err = usbdrv_ioctl_setessid(dev, &wrq->u.essid); ++ err = usbdrvwext_siwessid(dev, NULL, &wrq->u.essid, NULL); ++ ++ if (! err) ++ changed = 1; ++ break; ++ ++ ++ case SIOCGIWESSID: ++ err = usbdrvwext_giwessid(dev, NULL, &wrq->u.essid, NULL); ++ break; ++ ++ ++ case SIOCSIWRTS: ++ ++ err = usbdrv_ioctl_setrts(dev, &wrq->u.rts); ++ if (! err) ++ changed = 1; ++ break; ++ ++ ++ case SIOCIWFIRSTPRIV + 0x2: /* set_auth */ ++ { ++ //printk("CWY - SIOCIWFIRSTPRIV + 0x2 (set_auth)\n"); ++ if (! capable(CAP_NET_ADMIN)) ++ { ++ err = -EPERM; ++ break; ++ } ++ { ++ int val = *( (int *) wrq->u.name ); ++ if ((val < 0) || (val > 2)) ++ { ++ err = -EINVAL; ++ break; ++ } ++ else ++ { ++ zfiWlanSetAuthenticationMode(dev, val); ++ ++ if (macp->DeviceOpened == 1) ++ { ++ zfiWlanDisable(dev, 0); ++ zfiWlanEnable(dev); ++ } ++ ++ err = 0; ++ changed = 1; ++ } ++ } ++ } ++ break; ++ ++ case SIOCIWFIRSTPRIV + 0x3: /* get_auth */ ++ { ++ int AuthMode = ZM_AUTH_MODE_OPEN; ++ ++ //printk("CWY - SIOCIWFIRSTPRIV + 0x3 (get_auth)\n"); ++ ++ if (wrq->u.data.pointer) ++ { ++ wrq->u.data.flags = 1; ++ ++ AuthMode = zfiWlanQueryAuthenticationMode(dev, 0); ++ if (AuthMode == ZM_AUTH_MODE_OPEN) ++ { ++ wrq->u.data.length = 12; ++ ++ if (copy_to_user(wrq->u.data.pointer, "open system", 12)) ++ { ++ return -EFAULT; ++ } ++ } ++ else if (AuthMode == ZM_AUTH_MODE_SHARED_KEY) ++ { ++ wrq->u.data.length = 11; ++ ++ if (copy_to_user(wrq->u.data.pointer, "shared key", 11)) ++ { ++ return -EFAULT; ++ } ++ } ++ else if (AuthMode == ZM_AUTH_MODE_AUTO) ++ { ++ wrq->u.data.length = 10; ++ ++ if (copy_to_user(wrq->u.data.pointer, "auto mode", 10)) ++ { ++ return -EFAULT; ++ } ++ } ++ else ++ { ++ return -EFAULT; ++ } ++ } ++ } ++ break; ++ ++ ++ case ZDAPIOCTL: //debug command ++ if (copy_from_user(&zdreq, ifr->ifr_data, sizeof (zdreq))) ++ { ++ printk(KERN_ERR "usbdrv: copy_from_user error\n"); ++ return -EFAULT; ++ } ++ ++ //printk(KERN_DEBUG "usbdrv: cmd=%2x, reg=0x%04lx, value=0x%08lx\n", ++ // zdreq.cmd, zdreq.addr, zdreq.value); ++ ++ zfLnxPrivateIoctl(dev, &zdreq); ++ ++ err = 0; ++ break; ++ ++ case ZD_IOCTL_WPA: ++ if (copy_from_user(&zdparm, ifr->ifr_data, sizeof(struct athr_wlan_param))) ++ { ++ printk(KERN_ERR "usbdrv: copy_from_user error\n"); ++ return -EFAULT; ++ } ++ ++ usbdrv_wpa_ioctl(dev, &zdparm); ++ err = 0; ++ break; ++ ++ case ZD_IOCTL_PARAM: ++ { ++ int *p; ++ int op; ++ int arg; ++ ++ /* Point to the name field and retrieve the ++ * op and arg elements. */ ++ p = (int *)wrq->u.name; ++ op = *p++; ++ arg = *p; ++ ++ if(op == ZD_PARAM_ROAMING) ++ { ++ printk(KERN_ERR "************* ZD_PARAM_ROAMING: %d\n", arg); ++ //macp->cardSetting.ap_scan=(U8)arg; ++ } ++ if(op == ZD_PARAM_PRIVACY) ++ { ++ printk(KERN_ERR "ZD_IOCTL_PRIVACY: "); ++ ++ /* Turn on the privacy invoke flag */ ++ if(arg) ++ { ++ // mCap[0] |= CAP_PRIVACY; ++ // macp->cardSetting.EncryOnOff[0] = 1; ++ printk(KERN_ERR "enable\n"); ++ ++ } ++ else ++ { ++ // mCap[0] &= ~CAP_PRIVACY; ++ // macp->cardSetting.EncryOnOff[0] = 0; ++ printk(KERN_ERR "disable\n"); ++ } ++ //changed=1; ++ } ++ if(op == ZD_PARAM_WPA) ++ { ++ printk(KERN_ERR "ZD_PARAM_WPA: "); ++ ++ if(arg) ++ { ++ printk(KERN_ERR "enable\n"); ++ ++ if (zfiWlanQueryWlanMode(dev) != ZM_MODE_AP) ++ { ++ printk(KERN_ERR "Station Mode\n"); ++ //zfiWlanQueryWpaIe(dev, (u8_t *)&wpaIe, &wpalen); ++ //printk("wpaIe : %2x,%2x,%2x\n", wpaIe[21], wpaIe[22], wpaIe[23]); ++ //printk("rsnIe : %2x,%2x,%2x\n", wpaIe[17], wpaIe[18], wpaIe[19]); ++ if ((macp->supIe[21] == 0x50) && ++ (macp->supIe[22] == 0xf2) && ++ (macp->supIe[23] == 0x2)) ++ { ++ printk(KERN_ERR "wd->sta.authMode = ZM_AUTH_MODE_WPAPSK\n"); ++ //wd->sta.authMode = ZM_AUTH_MODE_WPAPSK; ++ //wd->ws.authMode = ZM_AUTH_MODE_WPAPSK; ++ zfiWlanSetAuthenticationMode(dev, ZM_AUTH_MODE_WPAPSK); ++ } ++ else if ((macp->supIe[21] == 0x50) && ++ (macp->supIe[22] == 0xf2) && ++ (macp->supIe[23] == 0x1)) ++ { ++ printk(KERN_ERR "wd->sta.authMode = ZM_AUTH_MODE_WPA\n"); ++ //wd->sta.authMode = ZM_AUTH_MODE_WPA; ++ //wd->ws.authMode = ZM_AUTH_MODE_WPA; ++ zfiWlanSetAuthenticationMode(dev, ZM_AUTH_MODE_WPA); ++ } ++ else if ((macp->supIe[17] == 0xf) && ++ (macp->supIe[18] == 0xac) && ++ (macp->supIe[19] == 0x2)) ++ { ++ printk(KERN_ERR "wd->sta.authMode = ZM_AUTH_MODE_WPA2PSK\n"); ++ //wd->sta.authMode = ZM_AUTH_MODE_WPA2PSK; ++ //wd->ws.authMode = ZM_AUTH_MODE_WPA2PSK; ++ zfiWlanSetAuthenticationMode(dev, ZM_AUTH_MODE_WPA2PSK); ++ } ++ else if ((macp->supIe[17] == 0xf) && ++ (macp->supIe[18] == 0xac) && ++ (macp->supIe[19] == 0x1)) ++ { ++ printk(KERN_ERR "wd->sta.authMode = ZM_AUTH_MODE_WPA2\n"); ++ //wd->sta.authMode = ZM_AUTH_MODE_WPA2; ++ //wd->ws.authMode = ZM_AUTH_MODE_WPA2; ++ zfiWlanSetAuthenticationMode(dev, ZM_AUTH_MODE_WPA2); ++ } ++ if ((macp->supIe[21] == 0x50) || (macp->supIe[22] == 0xf2))//WPA or WPAPSK ++ { ++ if (macp->supIe[11] == 0x2) ++ { ++ printk(KERN_ERR "wd->sta.wepStatus = ZM_ENCRYPTION_TKIP\n"); ++ //wd->sta.wepStatus = ZM_ENCRYPTION_TKIP; ++ //wd->ws.wepStatus = ZM_ENCRYPTION_TKIP; ++ zfiWlanSetWepStatus(dev, ZM_ENCRYPTION_TKIP); ++ } ++ else ++ { ++ printk(KERN_ERR "wd->sta.wepStatus = ZM_ENCRYPTION_AES\n"); ++ //wd->sta.wepStatus = ZM_ENCRYPTION_AES; ++ //wd->ws.wepStatus = ZM_ENCRYPTION_AES; ++ zfiWlanSetWepStatus(dev, ZM_ENCRYPTION_AES); ++ } ++ } ++ if ((macp->supIe[17] == 0xf) || (macp->supIe[18] == 0xac)) //WPA2 or WPA2PSK ++ { ++ if (macp->supIe[13] == 0x2) ++ { ++ printk(KERN_ERR "wd->sta.wepStatus = ZM_ENCRYPTION_TKIP\n"); ++ //wd->sta.wepStatus = ZM_ENCRYPTION_TKIP; ++ //wd->ws.wepStatus = ZM_ENCRYPTION_TKIP; ++ zfiWlanSetWepStatus(dev, ZM_ENCRYPTION_TKIP); ++ } ++ else ++ { ++ printk(KERN_ERR "wd->sta.wepStatus = ZM_ENCRYPTION_AES\n"); ++ //wd->sta.wepStatus = ZM_ENCRYPTION_AES; ++ //wd->ws.wepStatus = ZM_ENCRYPTION_AES; ++ zfiWlanSetWepStatus(dev, ZM_ENCRYPTION_AES); ++ } ++ } ++ } ++ zfiWlanSetWpaSupport(dev, 1); ++ } ++ else ++ { ++ /* Reset the WPA related variables */ ++ printk(KERN_ERR "disable\n"); ++ ++ zfiWlanSetWpaSupport(dev, 0); ++ zfiWlanSetAuthenticationMode(dev, ZM_AUTH_MODE_OPEN); ++ zfiWlanSetWepStatus(dev, ZM_ENCRYPTION_WEP_DISABLED); ++ ++ /* Now we only set the length in the WPA IE ++ * field to zero. */ ++ //macp->cardSetting.WPAIe[1] = 0; ++ } ++ } ++ if(op == ZD_PARAM_COUNTERMEASURES) ++ { ++ printk(KERN_ERR "================ZD_PARAM_COUNTERMEASURES: "); ++ ++ if(arg) ++ { ++ // mCounterMeasureState=1; ++ printk(KERN_ERR "enable\n"); ++ } ++ else ++ { ++ // mCounterMeasureState=0; ++ printk(KERN_ERR "disable\n"); ++ } ++ } ++ if(op == ZD_PARAM_DROPUNENCRYPTED) ++ { ++ printk(KERN_ERR "ZD_PARAM_DROPUNENCRYPTED: "); ++ ++ if(arg) ++ { ++ printk(KERN_ERR "enable\n"); ++ } ++ else ++ { ++ printk(KERN_ERR "disable\n"); ++ } ++ } ++ if(op == ZD_PARAM_AUTH_ALGS) ++ { ++ printk(KERN_ERR "ZD_PARAM_AUTH_ALGS: "); ++ ++ if(arg == 0) ++ { ++ printk(KERN_ERR "OPEN_SYSTEM\n"); ++ } ++ else ++ { ++ printk(KERN_ERR "SHARED_KEY\n"); ++ } ++ } ++ if(op == ZD_PARAM_WPS_FILTER) ++ { ++ printk(KERN_ERR "ZD_PARAM_WPS_FILTER: "); ++ ++ if(arg) ++ { ++ // mCounterMeasureState=1; ++ macp->forwardMgmt = 1; ++ printk(KERN_ERR "enable\n"); ++ } ++ else ++ { ++ // mCounterMeasureState=0; ++ macp->forwardMgmt = 0; ++ printk(KERN_ERR "disable\n"); ++ } ++ } ++ } ++ err = 0; ++ break; ++ ++ case ZD_IOCTL_GETWPAIE: ++ { ++ struct ieee80211req_wpaie req_wpaie; ++ u16_t apId, i, j; ++ ++ /* Get the AP Id */ ++ apId = zfLnxGetVapId(dev); ++ ++ if (apId == 0xffff) ++ { ++ apId = 0; ++ } ++ else ++ { ++ apId = apId+1; ++ } ++ ++ if (copy_from_user(&req_wpaie, ifr->ifr_data, sizeof(struct ieee80211req_wpaie))){ ++ printk(KERN_ERR "usbdrv: copy_from_user error\n"); ++ return -EFAULT; ++ } ++ ++ for(i = 0; i < ZM_OAL_MAX_STA_SUPPORT; i++) ++ { ++ for(j = 0; j < IEEE80211_ADDR_LEN; j++) ++ { ++ if (macp->stawpaie[i].wpa_macaddr[j] != req_wpaie.wpa_macaddr[j]) ++ break; ++ } ++ if (j == 6) ++ break; ++ } ++ if (i < ZM_OAL_MAX_STA_SUPPORT) ++ { ++ //printk("ZD_IOCTL_GETWPAIE - sta index = %d\n", i); ++ memcpy(req_wpaie.wpa_ie, macp->stawpaie[i].wpa_ie, IEEE80211_MAX_IE_SIZE); ++ } ++ ++ if (copy_to_user(wrq->u.data.pointer, &req_wpaie, sizeof(struct ieee80211req_wpaie))) ++ { ++ return -EFAULT; ++ } ++ } ++ ++ err = 0; ++ break; ++#ifdef ZM_ENABLE_CENC ++ case ZM_IOCTL_CENC: ++ if (copy_from_user(&macp->zd_wpa_req, ifr->ifr_data, sizeof(struct athr_wlan_param))) ++ { ++ printk(KERN_ERR "usbdrv: copy_from_user error\n"); ++ return -EFAULT; ++ } ++ ++ usbdrv_cenc_ioctl(dev, (struct zydas_cenc_param *)&macp->zd_wpa_req); ++ err = 0; ++ break; ++#endif //ZM_ENABLE_CENC ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ ++ return err; ++} +--- /dev/null ++++ b/drivers/staging/otus/Kconfig +@@ -0,0 +1,32 @@ ++config OTUS ++ tristate "Atheros OTUS 802.11n USB wireless support" ++ depends on USB && WLAN_80211 && MAC80211 ++ default N ++ ---help--- ++ Enable support for Atheros 802.11n USB hardware: ++ * UB81 - 2x2 2.4 GHz ++ * UB82 - 2x2 2.4 GHz and 5 GHz ++ * UB83 - 1x2 2.4 GHz ++ ++ This includes the following devices currently on the market: ++ Dlink DWA-160A1, Netgear WNDA3100 and WN111v2, TP-Link ++ TL-WN821N, and AVM FRITZ!WLAN N USB Stick. ++ ++ This driver requires its own supplicant driver for ++ wpa_supplicant 0.4.8. For your convenience you can find the ++ tarball here: ++ ++ http://www.kernel.org/pub/linux/kernel/people/mcgrof/otus/wpa_supplicant-0.4.8_otus.tar.bz2 ++ ++ Before compiling wpa_supplicant, ensure your .config has at ++ least the following: ++ CONFIG_WIRELESS_EXTENSION=y ++ CONFIG_EAP_WSC=y ++ CONFIG_WSC_IE=y ++ CONFIG_DRIVER_WEXT=y ++ CONFIG_DRIVER_OTUS=y ++ ++ After a successful compile, you can use the Atheros device as ++ shown in the example: ++ $ wpa_supplicant -Dotus -i -c /path/to/wpa_supplicant.conf -d ++ +--- /dev/null ++++ b/drivers/staging/otus/Makefile +@@ -0,0 +1,67 @@ ++obj-$(CONFIG_OTUS) += arusb_lnx.o ++ ++EXTRA_CFLAGS += -DAMAC ++EXTRA_CFLAGS += -DGCCK ++EXTRA_CFLAGS += -DOFDM ++EXTRA_CFLAGS += -DTXQ_IN_ISR ++EXTRA_CFLAGS += -DWLAN_HOSTIF=0 #0:USB, 1:PCI ++ ++#Test Mode ++EXTRA_CFLAGS += -DZM_USB_STREAM_MODE=1 ++EXTRA_CFLAGS += -DZM_USB_TX_STREAM_MODE=0 ++EXTRA_CFLAGS += -DZM_PCI_DMA_TEST=0 ++EXTRA_CFLAGS += -DZM_LARGEPAYLOAD_TEST=0 ++EXTRA_CFLAGS += -DZM_FW_LOOP_BACK=0 ++EXTRA_CFLAGS += -DZM_LINUX_TPC=1 ++#EXTRA_CFLAGS += -DZM_DONT_COPY_RX_BUFFER ++ ++EXTRA_CFLAGS += -DZM_HOSTAPD_SUPPORT ++#EXTRA_CFLAGS += -DfTX_GAIN_OFDM=0 ++#EXTRA_CFLAGS += -DZM_CONFIG_BIG_ENDIAN -DBIG_ENDIAN ++EXTRA_CFLAGS += -DZM_HALPLUS_LOCK ++EXTRA_CFLAGS += -DZM_OTUS_LINUX_PHASE_2 ++ ++arusb_lnx-objs := \ ++ usbdrv.o \ ++ zdusb.o \ ++ ioctl.o \ ++ wrap_buf.o \ ++ wrap_mem.o \ ++ wrap_ev.o \ ++ wrap_usb.o \ ++ wrap_pkt.o \ ++ wrap_dbg.o \ ++ wrap_mis.o \ ++ wrap_sec.o \ ++ wwrap.o \ ++ 80211core/ccmd.o \ ++ 80211core/chb.o \ ++ 80211core/cinit.o \ ++ 80211core/cmm.o \ ++ 80211core/cmmap.o \ ++ 80211core/cmmsta.o \ ++ 80211core/cfunc.o \ ++ 80211core/coid.o \ ++ 80211core/ctkip.o \ ++ 80211core/ctxrx.o \ ++ 80211core/cic.o \ ++ 80211core/cpsmgr.o \ ++ 80211core/cscanmgr.o \ ++ 80211core/ratectrl.o \ ++ 80211core/ledmgr.o \ ++ 80211core/amsdu.o \ ++ 80211core/cwm.o \ ++ 80211core/cagg.o \ ++ 80211core/queue.o \ ++ 80211core/freqctrl.o \ ++ 80211core/cwep.o \ ++ hal/hprw.o \ ++ hal/hpmain.o \ ++ hal/hpusb.o \ ++ hal/hpreg.o \ ++ hal/hpfwuinit.o \ ++ hal/hpfwbu.o \ ++ hal/hpfw2.o \ ++ hal/hpDKfwu.o \ ++ hal/hpfwspiu.o \ ++ hal/hpani.o +--- /dev/null ++++ b/drivers/staging/otus/oal_dt.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : oal_dt.h */ ++/* */ ++/* Abstract */ ++/* This module contains data type definition. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _OAL_DT_H ++#define _OAL_DT_H ++ ++/* Please include header files for buffer type in the beginning of this file */ ++/* Please include header files for device type here */ ++#include ++ ++typedef unsigned long long u64_t; ++typedef unsigned int u32_t; ++typedef unsigned short u16_t; ++typedef unsigned char u8_t; ++typedef long long s64_t; ++typedef long s32_t; ++typedef short s16_t; ++typedef char s8_t; ++ ++#ifndef TRUE ++#define TRUE (1==1) ++#endif ++ ++#ifndef FALSE ++#define FALSE (1==0) ++#endif ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++/* Please include header files for buffer type in the beginning of this file */ ++typedef struct sk_buff zbuf_t; ++ ++/* Please include header files for device type in the beginning of this file */ ++typedef struct net_device zdev_t; ++ ++#endif /* #ifndef _OAL_DT_H */ +--- /dev/null ++++ b/drivers/staging/otus/oal_marc.h +@@ -0,0 +1,135 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : oal_marc.h */ ++/* */ ++/* Abstract */ ++/* This module contains warpper definitions. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _OAL_MARC_H ++#define _OAL_MARC_H ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#define ZM_OS_LINUX_FUNC ++ ++/***** Critical section *****/ ++/* Declare for critical section */ ++#ifndef ZM_HALPLUS_LOCK ++#define zmw_get_wlan_dev(dev) struct zsWlanDev *wd = (struct zsWlanDev*) ((((struct usbdrv_private*)dev->priv)->wd)) ++ ++#define zmw_declare_for_critical_section() unsigned long irqFlag; ++ ++/* Enter critical section */ ++#define zmw_enter_critical_section(dev) \ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++/* leave critical section */ ++#define zmw_leave_critical_section(dev) \ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++#else ++#define zmw_get_wlan_dev(dev) struct zsWlanDev *wd = zfwGetWlanDev(dev); ++ ++/* Declare for critical section */ ++#define zmw_declare_for_critical_section() ++ ++/* Enter critical section */ ++#define zmw_enter_critical_section(dev) \ ++ zfwEnterCriticalSection(dev); ++ ++/* leave critical section */ ++#define zmw_leave_critical_section(dev) \ ++ zfwLeaveCriticalSection(dev); ++#endif ++ ++/***** Byte order converting *****/ ++#ifdef ZM_CONFIG_BIG_ENDIAN ++#define zmw_cpu_to_le32(v) (((v & 0xff000000) >> 24) | \ ++ ((v & 0x00ff0000) >> 8) | \ ++ ((v & 0x0000ff00) << 8) | \ ++ ((v & 0x000000ff) << 24)) ++ ++#define zmw_le32_to_cpu(v) (((v & 0xff000000) >> 24) | \ ++ ((v & 0x00ff0000) >> 8) | \ ++ ((v & 0x0000ff00) << 8) | \ ++ ((v & 0x000000ff) << 24)) ++ ++#define zmw_cpu_to_le16(v) (((v & 0xff00) >> 8) | \ ++ ((v & 0x00ff) << 8)) ++ ++#define zmw_le16_to_cpu(v) (((v & 0xff00) >> 8) | \ ++ ((v & 0x00ff) << 8)) ++#else ++#define zmw_cpu_to_le32(v) (v) ++#define zmw_le32_to_cpu(v) (v) ++#define zmw_cpu_to_le16(v) (v) ++#define zmw_le16_to_cpu(v) (v) ++#endif ++ ++/***** Buffer access *****/ ++/* Called to read/write buffer */ ++#ifndef ZM_HALPLUS_LOCK ++ ++#define zmw_buf_readb(dev, buf, offset) *(u8_t*)((u8_t*)buf->data+offset) ++#define zmw_buf_readh(dev, buf, offset) zmw_cpu_to_le16(*(u16_t*)((u8_t*)buf->data+offset)) ++#define zmw_buf_writeb(dev, buf, offset, value) *(u8_t*)((u8_t*)buf->data+offset) = value ++#define zmw_buf_writeh(dev, buf, offset, value) *(u16_t*)((u8_t*)buf->data+offset) = zmw_cpu_to_le16(value) ++#define zmw_buf_get_buffer(dev, buf) (u8_t*)(buf->data) ++ ++#else ++ ++#define zmw_buf_readb(dev, buf, offset) zfwBufReadByte(dev, buf, offset) ++#define zmw_buf_readh(dev, buf, offset) zfwBufReadHalfWord(dev, buf, offset) ++#define zmw_buf_writeb(dev, buf, offset, value) zfwBufWriteByte(dev, buf, offset, value) ++#define zmw_buf_writeh(dev, buf, offset, value) zfwBufWriteHalfWord(dev, buf, offset, value) ++#define zmw_buf_get_buffer(dev, buf) zfwGetBuffer(dev, buf) ++ ++#endif ++ ++/***** Debug message *****/ ++#if 0 ++#define zm_debug_msg0(msg) printk("%s:%s\n", __FUNCTION__, msg); ++#define zm_debug_msg1(msg, val) printk("%s:%s%ld\n", __FUNCTION__, \ ++ msg, (u32_t)val); ++#define zm_debug_msg2(msg, val) printk("%s:%s%lxh\n", __FUNCTION__, \ ++ msg, (u32_t)val); ++#define zm_debug_msg_s(msg, val) printk("%s:%s%s\n", __FUNCTION__, \ ++ msg, val); ++#define zm_debug_msg_p(msg, val1, val2) printk("%s:%s%01ld.%02ld\n", __FUNCTION__, \ ++ msg, (val1/val2), (((val1*100)/val2)%100)); ++#define zm_dbg(S) printk S ++#else ++#define zm_debug_msg0(msg) ++#define zm_debug_msg1(msg, val) ++#define zm_debug_msg2(msg, val) ++#define zm_debug_msg_s(msg, val) ++#define zm_debug_msg_p(msg, val1, val2) ++#define zm_dbg(S) ++#endif ++ ++#define zm_assert(expr) if(!(expr)) { \ ++ printk( "Atheors Assertion failed! %s,%s,%s,line=%d\n", \ ++ #expr,__FILE__,__FUNCTION__,__LINE__); \ ++ } ++ ++#define DbgPrint printk ++ ++#endif /* #ifndef _OAL_MARC_H */ +--- /dev/null ++++ b/drivers/staging/otus/TODO +@@ -0,0 +1,9 @@ ++TODO: ++ - checkpatch.pl cleanups ++ - sparse cleanups ++ - port to in-kernel 80211 stack ++ - proper network developer maintainer ++ ++Please send any patches to Greg Kroah-Hartman and ++Luis Rodriguez and the ++otus-devel@lists.madwifi-project.org mailing list. +--- /dev/null ++++ b/drivers/staging/otus/usbdrv.c +@@ -0,0 +1,1210 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : usbdrv.c */ ++/* */ ++/* Abstract */ ++/* This module contains network interface up/down related functions.*/ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++/* src/usbdrv.c */ ++ ++#define ZM_PIBSS_MODE 0 ++#define ZM_AP_MODE 0 ++#define ZM_CHANNEL 11 ++#define ZM_WEP_MOME 0 ++#define ZM_SHARE_AUTH 0 ++#define ZM_DISABLE_XMIT 0 ++ ++#include "usbdrv.h" ++#include "oal_dt.h" ++#include "80211core/pub_zfi.h" ++ ++#include "linux/netlink.h" ++#include "linux/rtnetlink.h" ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++#ifdef ZM_HOSTAPD_SUPPORT ++#include "athr_common.h" ++#endif ++ ++extern void zfDumpDescriptor(zdev_t* dev, u16_t type); ++//extern void zfiWlanQueryMacAddress(zdev_t* dev, u8_t* addr); ++ ++// ISR handler ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)) ++irqreturn_t usbdrv_intr(int, void *, struct pt_regs *); ++#else ++void usbdrv_intr(int, void *, struct pt_regs *); ++#endif ++ ++// Network Device interface related function ++int usbdrv_open(struct net_device *); ++int usbdrv_close(struct net_device *); ++int usbdrv_change_mtu(struct net_device *, int); ++int usbdrv_set_mac(struct net_device *, void *); ++int usbdrv_xmit_frame(struct sk_buff *, struct net_device *); ++void usbdrv_set_multi(struct net_device *); ++struct net_device_stats *usbdrv_get_stats(struct net_device *); ++ ++//wireless extension helper functions ++int usbdrv_ioctl_setessid(struct net_device *dev, struct iw_point *erq); ++int usbdrv_ioctl_getessid(struct net_device *dev, struct iw_point *erq); ++int usbdrv_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); ++/* Wireless Extension Handler functions */ ++int usbdrvwext_giwmode(struct net_device *dev, struct iw_request_info* info, ++ __u32 *mode, char *extra); ++int zfLnxPrivateIoctl(struct usbdrv_private *macp, struct zdap_ioctl *zdreq); ++ ++void zfLnx10msTimer(struct net_device* dev); ++int zfUnregisterWdsDev(struct net_device* parentDev, u16_t wdsId); ++int zfRegisterWdsDev(struct net_device* parentDev, u16_t wdsId); ++int zfWdsOpen(struct net_device *dev); ++int zfWdsClose(struct net_device *dev); ++int zfLnxVapOpen(struct net_device *dev); ++int zfLnxVapClose(struct net_device *dev); ++int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev); ++int zfLnxRegisterVapDev(struct net_device* parentDev, u16_t vapId); ++int usbdrv_wpa_ioctl(struct net_device *dev, struct athr_wlan_param *zdparm); ++extern u16_t zfLnxGetVapId(zdev_t* dev); ++extern u16_t zfLnxCheckTxBufferCnt(zdev_t *dev); ++extern UsbTxQ_t *zfLnxGetUsbTxBuffer(zdev_t *dev); ++ ++extern u16_t zfLnxAuthNotify(zdev_t* dev, u16_t* macAddr); ++extern u16_t zfLnxAsocNotify(zdev_t* dev, u16_t* macAddr, u8_t* body, u16_t bodySize, u16_t port); ++extern u16_t zfLnxDisAsocNotify(zdev_t* dev, u8_t* macAddr, u16_t port); ++extern u16_t zfLnxApConnectNotify(zdev_t* dev, u8_t* macAddr, u16_t port); ++extern void zfLnxConnectNotify(zdev_t* dev, u16_t status, u16_t* bssid); ++extern void zfLnxScanNotify(zdev_t* dev, struct zsScanResult* result); ++extern void zfLnxStatisticsNotify(zdev_t* dev, struct zsStastics* result); ++extern void zfLnxMicFailureNotify(zdev_t* dev, u16_t* addr, u16_t status); ++extern void zfLnxApMicFailureNotify(zdev_t* dev, u8_t* addr, zbuf_t* buf); ++extern void zfLnxIbssPartnerNotify(zdev_t* dev, u16_t status, struct zsPartnerNotifyEvent *event); ++extern void zfLnxMacAddressNotify(zdev_t* dev, u8_t* addr); ++extern void zfLnxSendCompleteIndication(zdev_t* dev, zbuf_t* buf); ++extern void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port); ++extern void zfLnxRestoreBufData(zdev_t* dev, zbuf_t* buf); ++#ifdef ZM_ENABLE_CENC ++extern u16_t zfLnxCencAsocNotify(zdev_t* dev, u16_t* macAddr, u8_t* body, u16_t bodySize, u16_t port); ++#endif //ZM_ENABLE_CENC ++extern void zfLnxWatchDogNotify(zdev_t* dev); ++extern void zfLnxRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++extern u8_t zfLnxCreateThread(zdev_t *dev); ++ ++/****************************************************************************** ++* P U B L I C D A T A ++******************************************************************************* ++*/ ++ ++/* Definition of Wireless Extension */ ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++//wireless extension helper functions ++extern int usbdrv_ioctl_setessid(struct net_device *dev, struct iw_point *erq); ++extern int usbdrv_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); ++/* Wireless Extension Handler functions */ ++extern int usbdrvwext_giwname(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrq, char *extra); ++extern int usbdrvwext_siwfreq(struct net_device *dev, struct iw_request_info *info, ++ struct iw_freq *freq, char *extra); ++extern int usbdrvwext_giwfreq(struct net_device *dev, struct iw_request_info *info, ++ struct iw_freq *freq, char *extra); ++extern int usbdrvwext_siwmode(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrq, char *extra); ++extern int usbdrvwext_giwmode(struct net_device *dev, struct iw_request_info *info, ++ __u32 *mode, char *extra); ++extern int usbdrvwext_siwsens(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *sens, char *extra); ++extern int usbdrvwext_giwsens(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *sens, char *extra); ++extern int usbdrvwext_giwrange(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *extra); ++extern int usbdrvwext_siwap(struct net_device *dev, struct iw_request_info *info, ++ struct sockaddr *MacAddr, char *extra); ++extern int usbdrvwext_giwap(struct net_device *dev, struct iw_request_info *info, ++ struct sockaddr *MacAddr, char *extra); ++extern int usbdrvwext_iwaplist(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *extra); ++extern int usbdrvwext_siwscan(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *extra); ++extern int usbdrvwext_giwscan(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *extra); ++extern int usbdrvwext_siwessid(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *essid, char *extra); ++extern int usbdrvwext_giwessid(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *essid, char *extra); ++extern int usbdrvwext_siwnickn(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *nickname); ++extern int usbdrvwext_giwnickn(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *data, char *nickname); ++extern int usbdrvwext_siwrate(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *frq, char *extra); ++extern int usbdrvwext_giwrate(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *frq, char *extra); ++extern int usbdrvwext_siwrts(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *rts, char *extra); ++extern int usbdrvwext_giwrts(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *rts, char *extra); ++extern int usbdrvwext_siwfrag(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *frag, char *extra); ++extern int usbdrvwext_giwfrag(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *frag, char *extra); ++extern int usbdrvwext_siwtxpow(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *rrq, char *extra); ++extern int usbdrvwext_giwtxpow(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *rrq, char *extra); ++extern int usbdrvwext_siwretry(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *rrq, char *extra); ++extern int usbdrvwext_giwretry(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *rrq, char *extra); ++extern int usbdrvwext_siwencode(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *erq, char *key); ++extern int usbdrvwext_giwencode(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *erq, char *key); ++extern int usbdrvwext_siwpower(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *frq, char *extra); ++extern int usbdrvwext_giwpower(struct net_device *dev, struct iw_request_info *info, ++ struct iw_param *frq, char *extra); ++extern int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ++/* ++ * Structures to export the Wireless Handlers ++ */ ++ ++struct iw_priv_args usbdrv_private_args[] = { ++// { SIOCIWFIRSTPRIV + 0x0, 0, 0, "list_bss" }, ++// { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, ++ { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_auth" }, /* 0 - open, 1 - shared key */ ++ { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_CHAR | 12, "get_auth" }, ++// { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble" }, /* 0 - long, 1 - short */ ++// { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_CHAR | 6, "get_preamble" }, ++// { SIOCIWFIRSTPRIV + 0x6, 0, 0, "cnt" }, ++// { SIOCIWFIRSTPRIV + 0x7, 0, 0, "regs" }, ++// { SIOCIWFIRSTPRIV + 0x8, 0, 0, "probe" }, ++// { SIOCIWFIRSTPRIV + 0x9, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dbg_flag" }, ++// { SIOCIWFIRSTPRIV + 0xA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "connect" }, ++// { SIOCIWFIRSTPRIV + 0xB, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_mac_mode" }, ++// { SIOCIWFIRSTPRIV + 0xC, 0, IW_PRIV_TYPE_CHAR | 12, "get_mac_mode" }, ++}; ++ ++#if WIRELESS_EXT > 12 ++static iw_handler usbdrvwext_handler[] = { ++ (iw_handler) NULL, /* SIOCSIWCOMMIT */ ++ (iw_handler) usbdrvwext_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) usbdrvwext_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) usbdrvwext_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) usbdrvwext_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) usbdrvwext_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) usbdrvwext_siwsens, /* SIOCSIWSENS */ ++ (iw_handler) usbdrvwext_giwsens, /* SIOCGIWSENS */ ++ (iw_handler) NULL, /* not used */ /* SIOCSIWRANGE */ ++ (iw_handler) usbdrvwext_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL, /* not used */ /* SIOCSIWPRIV */ ++ (iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */ ++ (iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */ ++ (iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */ ++ (iw_handler) NULL, /* SIOCSIWSPY */ ++ (iw_handler) NULL, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) usbdrvwext_siwap, /* SIOCSIWAP */ ++ (iw_handler) usbdrvwext_giwap, /* SIOCGIWAP */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) usbdrvwext_iwaplist, /* SIOCGIWAPLIST */ ++#if WIRELESS_EXT > 13 ++ (iw_handler) usbdrvwext_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) usbdrvwext_giwscan, /* SIOCGIWSCAN */ ++#else /* WIRELESS_EXT > 13 */ ++ (iw_handler) NULL, /* null */ /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* null */ /* SIOCGIWSCAN */ ++#endif /* WIRELESS_EXT > 13 */ ++ (iw_handler) usbdrvwext_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) usbdrvwext_giwessid, /* SIOCGIWESSID */ ++ ++ (iw_handler) usbdrvwext_siwnickn, /* SIOCSIWNICKN */ ++ (iw_handler) usbdrvwext_giwnickn, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) usbdrvwext_siwrate, /* SIOCSIWRATE */ ++ (iw_handler) usbdrvwext_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) usbdrvwext_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) usbdrvwext_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) usbdrvwext_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) usbdrvwext_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) usbdrvwext_siwtxpow, /* SIOCSIWTXPOW */ ++ (iw_handler) usbdrvwext_giwtxpow, /* SIOCGIWTXPOW */ ++ (iw_handler) usbdrvwext_siwretry, /* SIOCSIWRETRY */ ++ (iw_handler) usbdrvwext_giwretry, /* SIOCGIWRETRY */ ++ (iw_handler) usbdrvwext_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) usbdrvwext_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) usbdrvwext_siwpower, /* SIOCSIWPOWER */ ++ (iw_handler) usbdrvwext_giwpower, /* SIOCGIWPOWER */ ++}; ++ ++static const iw_handler usbdrv_private_handler[] = ++{ ++ //(iw_handler) usbdrvwext_setparam, /* SIOCWFIRSTPRIV+0 */ ++ //(iw_handler) usbdrvwext_getparam, /* SIOCWFIRSTPRIV+1 */ ++ //(iw_handler) usbdrvwext_setkey, /* SIOCWFIRSTPRIV+2 */ ++ //(iw_handler) usbdrvwext_setwmmparams, /* SIOCWFIRSTPRIV+3 */ ++ //(iw_handler) usbdrvwext_delkey, /* SIOCWFIRSTPRIV+4 */ ++ //(iw_handler) usbdrvwext_getwmmparams, /* SIOCWFIRSTPRIV+5 */ ++ //(iw_handler) usbdrvwext_setmlme, /* SIOCWFIRSTPRIV+6 */ ++ //(iw_handler) usbdrvwext_getchaninfo, /* SIOCWFIRSTPRIV+7 */ ++ //(iw_handler) usbdrvwext_setoptie, /* SIOCWFIRSTPRIV+8 */ ++ //(iw_handler) usbdrvwext_getoptie, /* SIOCWFIRSTPRIV+9 */ ++ //(iw_handler) usbdrvwext_addmac, /* SIOCWFIRSTPRIV+10 */ ++ //(iw_handler) usbdrvwext_getscanresults, /* SIOCWFIRSTPRIV+11 */ ++ //(iw_handler) usbdrvwext_delmac, /* SIOCWFIRSTPRIV+12 */ ++ //(iw_handler) usbdrvwext_getchanlist, /* SIOCWFIRSTPRIV+13 */ ++ //(iw_handler) usbdrvwext_setchanlist, /* SIOCWFIRSTPRIV+14 */ ++ //(iw_handler) NULL, /* SIOCWFIRSTPRIV+15 */ ++ //(iw_handler) usbdrvwext_chanswitch, /* SIOCWFIRSTPRIV+16 */ ++ //(iw_handler) usbdrvwext_setmode, /* SIOCWFIRSTPRIV+17 */ ++ //(iw_handler) usbdrvwext_getmode, /* SIOCWFIRSTPRIV+18 */ ++ NULL, /* SIOCIWFIRSTPRIV */ ++}; ++ ++struct iw_handler_def p80211wext_handler_def = { ++ .num_standard = sizeof(usbdrvwext_handler) / sizeof(iw_handler), ++ .num_private = sizeof(usbdrv_private_handler)/sizeof(iw_handler), ++ .num_private_args = sizeof(usbdrv_private_args)/sizeof(struct iw_priv_args), ++ .standard = usbdrvwext_handler, ++ .private = (iw_handler *) usbdrv_private_handler, ++ .private_args = (struct iw_priv_args *) usbdrv_private_args ++}; ++#endif ++ ++/* WDS */ ++//struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER]; ++//void zfInitWdsStruct(void); ++ ++/* VAP */ ++struct zsVapStruct vap[ZM_VAP_PORT_NUMBER]; ++void zfLnxInitVapStruct(void); ++ ++ ++/** ++ * usbdrv_intr - interrupt handler ++ * @irq: the IRQ number ++ * @dev_inst: the net_device struct ++ * @regs: registers (unused) ++ * ++ * This routine is the ISR for the usbdrv board. It services ++ * the RX & TX queues & starts the RU if it has stopped due ++ * to no resources. ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++irqreturn_t usbdrv_intr(int irq, void *dev_inst, struct pt_regs *regs) ++#else ++void usbdrv_intr(int irq, void *dev_inst, struct pt_regs *regs) ++#endif ++{ ++ struct net_device *dev; ++ struct usbdrv_private *macp; ++ ++ dev = dev_inst; ++ macp = dev->priv; ++ ++ ++ /* Read register error, card may be unpluged */ ++ if (0)//(intr_status == -1) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ return IRQ_NONE; ++#else ++ return; ++#endif ++ ++ /* the device is closed, don't continue or else bad things may happen. */ ++ if (!netif_running(dev)) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ return IRQ_NONE; ++#else ++ return; ++#endif ++ } ++ ++ if (macp->driver_isolated) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ return IRQ_NONE; ++#else ++ return; ++#endif ++ } ++ ++#if (WLAN_HOSTIF == WLAN_PCI) ++ //zfiIsrPci(dev); ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ return IRQ_HANDLED; ++#else ++ return; ++#endif ++} ++ ++int usbdrv_open(struct net_device *dev) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ int rc = 0; ++ u16_t size; ++ void* mem; ++ //unsigned char addr[6]; ++ struct zsCbFuncTbl cbFuncTbl; ++ ++ printk("Enter open()\n"); ++ ++//#ifndef CONFIG_SMP ++// read_lock(&(macp->isolate_lock)); ++//#endif ++ if (macp->driver_isolated) { ++ rc = -EBUSY; ++ goto exit; ++ } ++ ++ size = zfiGlobalDataSize(dev); ++ if ((mem = kmalloc(size, GFP_KERNEL)) == NULL) ++ { ++ rc = -EBUSY; ++ goto exit; ++ } ++ macp->wd = mem; ++ ++ memset(&cbFuncTbl, 0, sizeof(struct zsCbFuncTbl)); ++ cbFuncTbl.zfcbAuthNotify = zfLnxAuthNotify; ++ cbFuncTbl.zfcbAuthNotify = zfLnxAuthNotify; ++ cbFuncTbl.zfcbAsocNotify = zfLnxAsocNotify; ++ cbFuncTbl.zfcbDisAsocNotify = zfLnxDisAsocNotify; ++ cbFuncTbl.zfcbApConnectNotify = zfLnxApConnectNotify; ++ cbFuncTbl.zfcbConnectNotify = zfLnxConnectNotify; ++ cbFuncTbl.zfcbScanNotify = zfLnxScanNotify; ++ cbFuncTbl.zfcbMicFailureNotify = zfLnxMicFailureNotify; ++ cbFuncTbl.zfcbApMicFailureNotify = zfLnxApMicFailureNotify; ++ cbFuncTbl.zfcbIbssPartnerNotify = zfLnxIbssPartnerNotify; ++ cbFuncTbl.zfcbMacAddressNotify = zfLnxMacAddressNotify; ++ cbFuncTbl.zfcbSendCompleteIndication = zfLnxSendCompleteIndication; ++ cbFuncTbl.zfcbRecvEth = zfLnxRecvEth; ++ cbFuncTbl.zfcbRecv80211 = zfLnxRecv80211; ++ cbFuncTbl.zfcbRestoreBufData = zfLnxRestoreBufData; ++#ifdef ZM_ENABLE_CENC ++ cbFuncTbl.zfcbCencAsocNotify = zfLnxCencAsocNotify; ++#endif //ZM_ENABLE_CENC ++ cbFuncTbl.zfcbHwWatchDogNotify = zfLnxWatchDogNotify; ++ zfiWlanOpen(dev, &cbFuncTbl); ++ ++#if 0 ++ { ++ //u16_t mac[3] = {0x1300, 0xb6d4, 0x5aaf}; ++ u16_t mac[3] = {0x8000, 0x00ab, 0x0000}; ++ //zfiWlanSetMacAddress(dev, mac); ++ } ++ /* MAC address */ ++ zfiWlanQueryMacAddress(dev, addr); ++ dev->dev_addr[0] = addr[0]; ++ dev->dev_addr[1] = addr[1]; ++ dev->dev_addr[2] = addr[2]; ++ dev->dev_addr[3] = addr[3]; ++ dev->dev_addr[4] = addr[4]; ++ dev->dev_addr[5] = addr[5]; ++#endif ++ //zfwMacAddressNotify() will be called to setup dev->dev_addr[] ++ ++ zfLnxCreateThread(dev); ++ ++ mod_timer(&(macp->hbTimer10ms), jiffies + (1*HZ)/100); //10 ms ++ ++ netif_carrier_on(dev); ++ ++ netif_start_queue(dev); ++ ++#if ZM_AP_MODE == 1 ++ zfiWlanSetWlanMode(dev, ZM_MODE_AP); ++ zfiWlanSetBasicRate(dev, 0xf, 0, 0); ++ zfiWlanSetSSID(dev, "OTUS_CWY", 8); ++ zfiWlanSetDtimCount(dev, 3); ++ ++ #if ZM_WEP_MOME == 1 ++ { ++ u8_t key[16] = {0x12, 0x34, 0x56, 0x78, 0x90}; ++ struct zsKeyInfo keyInfo; ++ ++ keyInfo.keyLength = 5; ++ keyInfo.keyIndex = 0; ++ keyInfo.flag = 0; ++ keyInfo.key = key; ++ zfiWlanSetKey(dev, keyInfo); ++ ++ zfiWlanSetEncryMode(dev, ZM_WEP64); ++ } ++ ++ #if ZM_SHARE_AUTH == 1 ++ zfiWlanSetAuthenticationMode(dev, 1); ++ #endif //#if ZM_SHARE_AUTH == 1 ++ #endif //#if ZM_WEP_MOME == 1 ++ ++#elif ZM_PIBSS_MODE == 1 ++ zfiWlanSetWlanMode(dev, ZM_MODE_PSEUDO); ++#else ++ zfiWlanSetWlanMode(dev, ZM_MODE_INFRASTRUCTURE); ++#endif ++ //zfiWlanSetChannel(dev, ZM_CHANNEL, FALSE); ++ zfiWlanSetFrequency(dev, 2462000, FALSE); ++ zfiWlanSetRtsThreshold(dev, 32767); ++ zfiWlanSetFragThreshold(dev, 0); ++ ++ zfiWlanEnable(dev); ++ ++#ifdef ZM_ENABLE_CENC ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ++ macp->netlink_sk = netlink_kernel_create(NETLINK_USERSOCK, NULL); ++#else ++ macp->netlink_sk = netlink_kernel_create(NETLINK_USERSOCK, 1, NULL, THIS_MODULE); ++#endif ++ ++ if (macp->netlink_sk == NULL) ++ { ++ printk(KERN_ERR "Can't create NETLINK socket\n"); ++ } ++#endif ++ ++ macp->DeviceOpened = 1; ++exit: ++//#ifndef CONFIG_SMP ++// read_unlock(&(macp->isolate_lock)); ++//#endif ++ //zfRegisterWdsDev(dev, 0); ++ //zfLnxRegisterVapDev(dev, 0); ++ ++ return rc; ++} ++ ++ ++ ++ ++/** ++ * usbdrv_get_stats - get driver statistics ++ * @dev: adapter's net_device struct ++ * ++ * This routine is called when the OS wants the adapter's stats returned. ++ * It returns the address of the net_device_stats stucture for the device. ++ * If the statistics are currently being updated, then they might be incorrect ++ * for a short while. However, since this cannot actually cause damage, no ++ * locking is used. ++ */ ++ ++struct net_device_stats * usbdrv_get_stats(struct net_device *dev) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ macp->drv_stats.net_stats.tx_errors = ++ macp->drv_stats.net_stats.tx_carrier_errors + ++ macp->drv_stats.net_stats.tx_aborted_errors; ++ ++ macp->drv_stats.net_stats.rx_errors = ++ macp->drv_stats.net_stats.rx_crc_errors + ++ macp->drv_stats.net_stats.rx_frame_errors + ++ macp->drv_stats.net_stats.rx_length_errors; ++ ++ ++ return &(macp->drv_stats.net_stats); ++} ++ ++ ++/** ++ * usbdrv_set_mac - set the MAC address ++ * @dev: adapter's net_device struct ++ * @addr: the new address ++ * ++ * This routine sets the ethernet address of the board ++ * Returns: ++ * 0 - if successful ++ * -1 - otherwise ++ */ ++ ++int usbdrv_set_mac(struct net_device *dev, void *addr) ++{ ++ struct usbdrv_private *macp; ++ int rc = -1; ++ ++ macp = dev->priv; ++ read_lock(&(macp->isolate_lock)); ++ ++ if (macp->driver_isolated) { ++ goto exit; ++ } ++ ++ rc = 0; ++ ++ ++exit: ++ read_unlock(&(macp->isolate_lock)); ++ return rc; ++} ++ ++ ++ ++void ++usbdrv_isolate_driver(struct usbdrv_private *macp) ++{ ++#ifndef CONFIG_SMP ++ write_lock_irq(&(macp->isolate_lock)); ++#endif ++ macp->driver_isolated = TRUE; ++#ifndef CONFIG_SMP ++ write_unlock_irq(&(macp->isolate_lock)); ++#endif ++ ++ if (netif_running(macp->device)) ++ { ++ netif_carrier_off(macp->device); ++ netif_stop_queue(macp->device); ++ } ++} ++ ++#define VLAN_SIZE 4 ++int usbdrv_change_mtu(struct net_device *dev, int new_mtu) ++{ ++ if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) ++ return -EINVAL; ++ ++ dev->mtu = new_mtu; ++ return 0; ++} ++ ++void zfLnxUnlinkAllUrbs(struct usbdrv_private *macp); ++ ++int usbdrv_close(struct net_device *dev) ++{ ++extern void zfHpLedCtrl(struct net_device *dev, u16_t ledId, u8_t mode); ++ ++ struct usbdrv_private *macp = dev->priv; ++ ++ printk(KERN_DEBUG "usbdrv_close\n"); ++ ++ netif_carrier_off(macp->device); ++ ++ del_timer_sync(&macp->hbTimer10ms); ++ ++ printk(KERN_DEBUG "usbdrv_netif_carrier_off\n"); ++ ++ usbdrv_isolate_driver(macp); ++ ++ printk(KERN_DEBUG "usbdrv_isolate_driver\n"); ++ ++ netif_carrier_off(macp->device); ++#ifdef ZM_ENABLE_CENC ++ /* CENC */ ++ if (macp->netlink_sk != NULL) ++ { ++ // sock_release(macp->netlink_sk); ++ printk(KERN_ERR "usbdrv close netlink socket\n"); ++ } ++#endif //ZM_ENABLE_CENC ++#if (WLAN_HOSTIF == WLAN_PCI) ++ //free_irq(dev->irq, dev); ++#endif ++ ++ /* Turn off LED */ ++ zfHpLedCtrl(dev, 0, 0); ++ zfHpLedCtrl(dev, 1, 0); ++ ++ /* Delay for a while */ ++ mdelay(10); ++ ++ /* clear WPA/RSN IE */ ++ macp->supIe[1] = 0; ++ ++ /* set the isolate flag to false, so usbdrv_open can be called */ ++ macp->driver_isolated = FALSE; ++ ++ zfiWlanClose(dev); ++ kfree(macp->wd); ++ ++ zfLnxUnlinkAllUrbs(macp); ++ ++ return 0; ++} ++ ++ ++ ++ ++int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev) ++{ ++ int notify_stop = FALSE; ++ struct usbdrv_private *macp = dev->priv; ++ ++#if 0 ++ /* Test code */ ++ { ++ struct sk_buff* s; ++ ++ s = skb_copy_expand(skb, 8, 0, GFP_ATOMIC); ++ skb_push(s, 8); ++ s->data[0] = 'z'; ++ s->data[1] = 'y'; ++ s->data[2] = 'd'; ++ s->data[3] = 'a'; ++ s->data[4] = 's'; ++ printk("len1=%d, len2=%d", skb->len, s->len); ++ netlink_broadcast(rtnl, s, 0, RTMGRP_LINK, GFP_ATOMIC); ++ } ++#endif ++ ++#if ZM_DISABLE_XMIT ++ dev_kfree_skb_irq(skb); ++#else ++ zfiTxSendEth(dev, skb, 0); ++#endif ++ macp->drv_stats.net_stats.tx_bytes += skb->len; ++ macp->drv_stats.net_stats.tx_packets++; ++ ++ //dev_kfree_skb_irq(skb); ++ ++ if (notify_stop) { ++ netif_carrier_off(dev); ++ netif_stop_queue(dev); ++ } ++ ++ return 0; ++} ++ ++ ++ ++ ++void usbdrv_set_multi(struct net_device *dev) ++{ ++ ++ ++ if (!(dev->flags & IFF_UP)) ++ return; ++ ++ return; ++ ++} ++ ++ ++ ++/** ++ * usbdrv_clear_structs - free resources ++ ++ * @dev: adapter's net_device struct ++ * ++ * Free all device specific structs, unmap i/o address, etc. ++ */ ++void usbdrv_clear_structs(struct net_device *dev) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ ++#if (WLAN_HOSTIF == WLAN_PCI) ++ iounmap(macp->regp); ++ ++ pci_release_regions(macp->pdev); ++ pci_disable_device(macp->pdev); ++ pci_set_drvdata(macp->pdev, NULL); ++#endif ++ ++ kfree(macp); ++ ++ kfree(dev); ++ ++} ++ ++void usbdrv_remove1(struct pci_dev *pcid) ++{ ++ struct net_device *dev; ++ struct usbdrv_private *macp; ++ ++ if (!(dev = (struct net_device *) pci_get_drvdata(pcid))) ++ return; ++ ++ macp = dev->priv; ++ unregister_netdev(dev); ++ ++ usbdrv_clear_structs(dev); ++} ++ ++ ++void zfLnx10msTimer(struct net_device* dev) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ ++ mod_timer(&(macp->hbTimer10ms), jiffies + (1*HZ)/100); //10 ms ++ zfiHeartBeat(dev); ++ return; ++} ++ ++void zfLnxInitVapStruct(void) ++{ ++ u16_t i; ++ ++ for (i=0; iname, vapId); ++ zfiWlanSetSSID(dev, "vap1", 4); ++ zfiWlanEnable(dev); ++ netif_start_queue(dev); ++ } ++ else ++ { ++ printk("VAP opened error : vap ID=%d\n", vapId); ++ } ++ return 0; ++} ++ ++int zfLnxVapClose(struct net_device *dev) ++{ ++ u16_t vapId; ++ ++ vapId = zfLnxGetVapId(dev); ++ ++ if (vapId != 0xffff) ++ { ++ if (vap[vapId].openFlag == 1) ++ { ++ printk("zfLnxVapClose: device name=%s, vap ID=%d\n", dev->name, vapId); ++ ++ netif_stop_queue(dev); ++ vap[vapId].openFlag = 0; ++ } ++ else ++ { ++ printk("VAP port was not opened : vap ID=%d\n", vapId); ++ } ++ } ++ return 0; ++} ++ ++int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev) ++{ ++ int notify_stop = FALSE; ++ struct usbdrv_private *macp = dev->priv; ++ u16_t vapId; ++ ++ vapId = zfLnxGetVapId(dev); ++ //printk("zfLnxVapXmitFrame: vap ID=%d\n", vapId); ++ //printk("zfLnxVapXmitFrame(), skb=%lxh\n", (u32_t)skb); ++ ++ if (vapId >= ZM_VAP_PORT_NUMBER) ++ { ++ dev_kfree_skb_irq(skb); ++ return 0; ++ } ++#if 1 ++ if (vap[vapId].openFlag == 0) ++ { ++ dev_kfree_skb_irq(skb); ++ return 0; ++ } ++#endif ++ ++ ++ zfiTxSendEth(dev, skb, 0x1); ++ ++ macp->drv_stats.net_stats.tx_bytes += skb->len; ++ macp->drv_stats.net_stats.tx_packets++; ++ ++ //dev_kfree_skb_irq(skb); ++ ++ if (notify_stop) { ++ netif_carrier_off(dev); ++ netif_stop_queue(dev); ++ } ++ ++ return 0; ++} ++ ++int zfLnxRegisterVapDev(struct net_device* parentDev, u16_t vapId) ++{ ++ /* Allocate net device structure */ ++ vap[vapId].dev = alloc_etherdev(0); ++ printk("Register vap dev=%x\n", (u32_t)vap[vapId].dev); ++ ++ if(vap[vapId].dev == NULL) { ++ printk("alloc_etherdev fail\n"); ++ return -ENOMEM; ++ } ++ ++ /* Setup the default settings */ ++ ether_setup(vap[vapId].dev); ++ ++ /* MAC address */ ++ memcpy(vap[vapId].dev->dev_addr, parentDev->dev_addr, ETH_ALEN); ++ ++ vap[vapId].dev->irq = parentDev->irq; ++ vap[vapId].dev->base_addr = parentDev->base_addr; ++ vap[vapId].dev->mem_start = parentDev->mem_start; ++ vap[vapId].dev->mem_end = parentDev->mem_end; ++ vap[vapId].dev->priv = parentDev->priv; ++ ++ //dev->hard_start_xmit = &zd1212_wds_xmit_frame; ++ vap[vapId].dev->hard_start_xmit = &zfLnxVapXmitFrame; ++ vap[vapId].dev->open = &zfLnxVapOpen; ++ vap[vapId].dev->stop = &zfLnxVapClose; ++ vap[vapId].dev->get_stats = &usbdrv_get_stats; ++ vap[vapId].dev->change_mtu = &usbdrv_change_mtu; ++#ifdef ZM_HOSTAPD_SUPPORT ++ vap[vapId].dev->do_ioctl = usbdrv_ioctl; ++#else ++ vap[vapId].dev->do_ioctl = NULL; ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ vap[vapId].dev->destructor = free_netdev; ++#else ++ vap[vapId].dev->features |= NETIF_F_DYNALLOC; ++#endif ++ ++ vap[vapId].dev->tx_queue_len = 0; ++ ++ vap[vapId].dev->dev_addr[0] = parentDev->dev_addr[0]; ++ vap[vapId].dev->dev_addr[1] = parentDev->dev_addr[1]; ++ vap[vapId].dev->dev_addr[2] = parentDev->dev_addr[2]; ++ vap[vapId].dev->dev_addr[3] = parentDev->dev_addr[3]; ++ vap[vapId].dev->dev_addr[4] = parentDev->dev_addr[4]; ++ vap[vapId].dev->dev_addr[5] = parentDev->dev_addr[5] + (vapId+1); ++ ++ /* Stop the network queue first */ ++ netif_stop_queue(vap[vapId].dev); ++ ++ sprintf(vap[vapId].dev->name, "vap%d", vapId); ++ printk("Register VAP dev success : %s\n", vap[vapId].dev->name); ++ ++ if(register_netdevice(vap[vapId].dev) != 0) { ++ printk("register VAP device fail\n"); ++ vap[vapId].dev = NULL; ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int zfLnxUnregisterVapDev(struct net_device* parentDev, u16_t vapId) ++{ ++ int ret = 0; ++ ++ printk("Unregister VAP dev : %s\n", vap[vapId].dev->name); ++ ++ if(vap[vapId].dev != NULL) { ++ printk("Unregister vap dev=%x\n", (u32_t)vap[vapId].dev); ++ // ++ //unregister_netdevice(wds[wdsId].dev); ++ unregister_netdev(vap[vapId].dev); ++ ++ printk("VAP unregister_netdevice\n"); ++ vap[vapId].dev = NULL; ++ } ++ else { ++ printk("unregister VAP device: %d fail\n", vapId); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* tune me! */ ++# define SUBMIT_URB(u,f) usb_submit_urb(u,f) ++# define USB_ALLOC_URB(u,f) usb_alloc_urb(u,f) ++#else ++# define SUBMIT_URB(u,f) usb_submit_urb(u) ++# define USB_ALLOC_URB(u,f) usb_alloc_urb(u) ++#endif ++ ++//extern void zfiWlanQueryMacAddress(zdev_t* dev, u8_t* addr); ++extern struct iw_handler_def p80211wext_handler_def; ++ ++extern int usbdrv_open(struct net_device *dev); ++extern int usbdrv_close(struct net_device *dev); ++extern int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev); ++extern int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev); ++extern int usbdrv_change_mtu(struct net_device *dev, int new_mtu); ++extern void usbdrv_set_multi(struct net_device *dev); ++extern int usbdrv_set_mac(struct net_device *dev, void *addr); ++extern struct net_device_stats * usbdrv_get_stats(struct net_device *dev); ++extern int usbdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ++extern UsbTxQ_t *zfLnxGetUsbTxBuffer(struct net_device *dev); ++ ++int zfLnxAllocAllUrbs(struct usbdrv_private *macp) ++{ ++ struct usb_interface *interface = macp->interface; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ struct usb_interface_descriptor *iface_desc = &interface->altsetting[0]; ++#else ++ struct usb_host_interface *iface_desc = &interface->altsetting[0]; ++#endif ++ ++ struct usb_endpoint_descriptor *endpoint; ++ int i; ++ ++ /* descriptor matches, let's find the endpoints needed */ ++ /* check out the endpoints */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ for (i = 0; i < iface_desc->bNumEndpoints; ++i) ++ { ++ endpoint = &iface_desc->endpoint[i]; ++#else ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) ++ { ++ endpoint = &iface_desc->endpoint[i].desc; ++#endif ++ if ((endpoint->bEndpointAddress & 0x80) && ++ ((endpoint->bmAttributes & 3) == 0x02)) ++ { ++ /* we found a bulk in endpoint */ ++ printk(KERN_ERR "bulk in: wMaxPacketSize = %x\n", le16_to_cpu(endpoint->wMaxPacketSize)); ++ } ++ ++ if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ++ ((endpoint->bmAttributes & 3) == 0x02)) ++ { ++ /* we found a bulk out endpoint */ ++ printk(KERN_ERR "bulk out: wMaxPacketSize = %x\n", le16_to_cpu(endpoint->wMaxPacketSize)); ++ } ++ ++ if ((endpoint->bEndpointAddress & 0x80) && ++ ((endpoint->bmAttributes & 3) == 0x03)) ++ { ++ /* we found a interrupt in endpoint */ ++ printk(KERN_ERR "interrupt in: wMaxPacketSize = %x\n", le16_to_cpu(endpoint->wMaxPacketSize)); ++ printk(KERN_ERR "interrupt in: int_interval = %d\n", endpoint->bInterval); ++ } ++ ++ if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ++ ((endpoint->bmAttributes & 3) == 0x03)) ++ { ++ /* we found a interrupt out endpoint */ ++ printk(KERN_ERR "interrupt out: wMaxPacketSize = %x\n", le16_to_cpu(endpoint->wMaxPacketSize)); ++ printk(KERN_ERR "interrupt out: int_interval = %d\n", endpoint->bInterval); ++ } ++ } ++ ++ /* Allocate all Tx URBs */ ++ for (i = 0; i < ZM_MAX_TX_URB_NUM; i++) ++ { ++ macp->WlanTxDataUrb[i] = USB_ALLOC_URB(0, GFP_KERNEL); ++ ++ if (macp->WlanTxDataUrb[i] == 0) ++ { ++ int j; ++ ++ /* Free all urbs */ ++ for (j = 0; j < i; j++) ++ { ++ usb_free_urb(macp->WlanTxDataUrb[j]); ++ } ++ ++ return 0; ++ } ++ } ++ ++ /* Allocate all Rx URBs */ ++ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) ++ { ++ macp->WlanRxDataUrb[i] = USB_ALLOC_URB(0, GFP_KERNEL); ++ ++ if (macp->WlanRxDataUrb[i] == 0) ++ { ++ int j; ++ ++ /* Free all urbs */ ++ for (j = 0; j < i; j++) ++ { ++ usb_free_urb(macp->WlanRxDataUrb[j]); ++ } ++ ++ for (j = 0; j < ZM_MAX_TX_URB_NUM; j++) ++ { ++ usb_free_urb(macp->WlanTxDataUrb[j]); ++ } ++ ++ return 0; ++ } ++ } ++ ++ /* Allocate Register Read/Write USB */ ++ macp->RegOutUrb = USB_ALLOC_URB(0, GFP_KERNEL); ++ macp->RegInUrb = USB_ALLOC_URB(0, GFP_KERNEL); ++ ++ return 1; ++} ++ ++void zfLnxFreeAllUrbs(struct usbdrv_private *macp) ++{ ++ int i; ++ ++ /* Free all Tx URBs */ ++ for (i = 0; i < ZM_MAX_TX_URB_NUM; i++) ++ { ++ if (macp->WlanTxDataUrb[i] != NULL) ++ { ++ usb_free_urb(macp->WlanTxDataUrb[i]); ++ } ++ } ++ ++ /* Free all Rx URBs */ ++ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) ++ { ++ if (macp->WlanRxDataUrb[i] != NULL) ++ { ++ usb_free_urb(macp->WlanRxDataUrb[i]); ++ } ++ } ++ ++ /* Free USB Register Read/Write URB */ ++ usb_free_urb(macp->RegOutUrb); ++ usb_free_urb(macp->RegInUrb); ++} ++ ++void zfLnxUnlinkAllUrbs(struct usbdrv_private *macp) ++{ ++ int i; ++ ++ /* Unlink all Tx URBs */ ++ for (i = 0; i < ZM_MAX_TX_URB_NUM; i++) ++ { ++ if (macp->WlanTxDataUrb[i] != NULL) ++ { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ macp->WlanTxDataUrb[i]->transfer_flags &= ~URB_ASYNC_UNLINK; ++#endif ++ usb_unlink_urb(macp->WlanTxDataUrb[i]); ++ } ++ } ++ ++ /* Unlink all Rx URBs */ ++ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) ++ { ++ if (macp->WlanRxDataUrb[i] != NULL) ++ { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ macp->WlanRxDataUrb[i]->transfer_flags &= ~URB_ASYNC_UNLINK; ++#endif ++ usb_unlink_urb(macp->WlanRxDataUrb[i]); ++ } ++ } ++ ++ /* Unlink USB Register Read/Write URB */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ macp->RegOutUrb->transfer_flags &= ~URB_ASYNC_UNLINK; ++#endif ++ usb_unlink_urb(macp->RegOutUrb); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ macp->RegInUrb->transfer_flags &= ~URB_ASYNC_UNLINK; ++#endif ++ usb_unlink_urb(macp->RegInUrb); ++} ++ ++u8_t zfLnxInitSetup(struct net_device *dev, struct usbdrv_private *macp) ++{ ++ //unsigned char addr[6]; ++ ++ //init_MUTEX(&macp->ps_sem); ++ //init_MUTEX(&macp->reg_sem); ++ //init_MUTEX(&macp->bcn_sem); ++ //init_MUTEX(&macp->config_sem); ++ ++ spin_lock_init(&(macp->cs_lock)); ++#if 0 ++ /* MAC address */ ++ zfiWlanQueryMacAddress(dev, addr); ++ dev->dev_addr[0] = addr[0]; ++ dev->dev_addr[1] = addr[1]; ++ dev->dev_addr[2] = addr[2]; ++ dev->dev_addr[3] = addr[3]; ++ dev->dev_addr[4] = addr[4]; ++ dev->dev_addr[5] = addr[5]; ++#endif ++#if WIRELESS_EXT > 12 ++ dev->wireless_handlers = (struct iw_handler_def *)&p80211wext_handler_def; ++#endif ++ ++ dev->open = usbdrv_open; ++ dev->hard_start_xmit = usbdrv_xmit_frame; ++ dev->stop = usbdrv_close; ++ dev->change_mtu = &usbdrv_change_mtu; ++ dev->get_stats = usbdrv_get_stats; ++ dev->set_multicast_list = usbdrv_set_multi; ++ dev->set_mac_address = usbdrv_set_mac; ++ dev->do_ioctl = usbdrv_ioctl; ++ ++ dev->flags |= IFF_MULTICAST; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) ++ dev->dev_addr[0] = 0x00; ++ dev->dev_addr[1] = 0x03; ++ dev->dev_addr[2] = 0x7f; ++ dev->dev_addr[3] = 0x11; ++ dev->dev_addr[4] = 0x22; ++ dev->dev_addr[5] = 0x33; ++#endif ++ ++ /* Initialize Heart Beat timer */ ++ init_timer(&macp->hbTimer10ms); ++ macp->hbTimer10ms.data = (unsigned long)dev; ++ macp->hbTimer10ms.function = (void *)&zfLnx10msTimer; ++ ++ /* Initialize WDS and VAP data structure */ ++ //zfInitWdsStruct(); ++ zfLnxInitVapStruct(); ++ ++ return 1; ++} ++ ++u8_t zfLnxClearStructs(struct net_device *dev) ++{ ++ u16_t ii; ++ u16_t TxQCnt; ++ ++ TxQCnt = zfLnxCheckTxBufferCnt(dev); ++ ++ printk(KERN_ERR "TxQCnt: %d\n", TxQCnt); ++ ++ for(ii = 0; ii < TxQCnt; ii++) ++ { ++ UsbTxQ_t *TxQ = zfLnxGetUsbTxBuffer(dev); ++ ++ printk(KERN_ERR "dev_kfree_skb_any\n"); ++ /* Free buffer */ ++ dev_kfree_skb_any(TxQ->buf); ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/staging/otus/usbdrv.h +@@ -0,0 +1,257 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : usbdrv.h */ ++/* */ ++/* Abstract */ ++/* This module contains network interface up/down related definition*/ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _USBDRV_H ++#define _USBDRV_H ++ ++#define WLAN_USB 0 ++#define WLAN_PCI 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ #include ++#endif ++ ++#include "zdcompat.h" ++ ++#include "oal_dt.h" ++#include "oal_marc.h" ++#include "80211core/pub_zfi.h" ++//#include "pub_zfw.h" ++#include "80211core/pub_usb.h" ++ ++#include ++/* Please include header files for device type in the beginning of this file */ ++#define urb_t struct urb ++ ++#define usb_complete_t usb_complete_t ++#define pipe_t u32_t ++ ++/* USB Endpoint definition */ ++#define USB_WLAN_TX_PIPE 1 ++#define USB_WLAN_RX_PIPE 2 ++#define USB_REG_IN_PIPE 3 ++#define USB_REG_OUT_PIPE 4 ++ ++#if (WLAN_HOSTIF == WLAN_USB) ++#include ++#endif ++ ++#ifdef ZM_HOSTAPD_SUPPORT ++#include "athr_common.h" ++#endif ++ ++/************************************************************************** ++** Descriptor Data Structure ++***************************************************************************/ ++struct driver_stats { ++ struct net_device_stats net_stats; ++}; ++ ++#define ZM_MAX_RX_BUFFER_SIZE 8192 ++ ++#if ZM_USB_TX_STREAM_MODE == 1 ++#define ZM_MAX_TX_AGGREGATE_NUM 4 ++#define ZM_USB_TX_BUF_SIZE 8096 ++#define ZM_MAX_TX_URB_NUM 4 ++#else ++#define ZM_USB_TX_BUF_SIZE 2048 ++#define ZM_MAX_TX_URB_NUM 8 ++#endif ++#define ZM_USB_REG_MAX_BUF_SIZE 64 ++#define ZM_MAX_RX_URB_NUM 16 ++#define ZM_MAX_TX_BUF_NUM 128 ++ ++typedef struct UsbTxQ ++{ ++ zbuf_t *buf; ++ u8_t hdr[80]; ++ u16_t hdrlen; ++ u8_t snap[8]; ++ u16_t snapLen; ++ u8_t tail[16]; ++ u16_t tailLen; ++ u16_t offset; ++} UsbTxQ_t; ++ ++ ++struct zdap_ioctl { ++ u16_t cmd; /* Command to run */ ++ u32_t addr; /* Length of the data buffer */ ++ u32_t value; /* Pointer to the data buffer */ ++ u8_t data[0x100]; ++}; ++ ++#define ZM_OAL_MAX_STA_SUPPORT 16 ++ ++struct usbdrv_private ++{ ++ //linux used ++ struct net_device *device; ++#if (WLAN_HOSTIF == WLAN_PCI) ++ struct pci_dev *pdev; ++#endif ++#if (WLAN_HOSTIF == WLAN_USB) ++ struct usb_device *udev; ++ struct usb_interface *interface; ++#endif ++ struct driver_stats drv_stats; ++ char ifname[IFNAMSIZ]; ++ int using_dac; ++ u8_t rev_id; /* adapter PCI revision ID */ ++ rwlock_t isolate_lock; ++ spinlock_t cs_lock; ++ int driver_isolated; ++#if (WLAN_HOSTIF == WLAN_PCI) ++ void *regp; ++#endif ++ ++ /* timer for heart beat */ ++ struct timer_list hbTimer10ms; ++ ++ /* For driver core */ ++ void* wd; ++ ++#if (WLAN_HOSTIF == WLAN_USB) ++ u8_t txUsbBuf[ZM_MAX_TX_URB_NUM][ZM_USB_TX_BUF_SIZE]; ++ u8_t regUsbReadBuf[ZM_USB_REG_MAX_BUF_SIZE]; ++ u8_t regUsbWriteBuf[ZM_USB_REG_MAX_BUF_SIZE]; ++ urb_t *WlanTxDataUrb[ZM_MAX_TX_URB_NUM]; ++ urb_t *WlanRxDataUrb[ZM_MAX_RX_URB_NUM]; ++ urb_t *RegOutUrb; ++ urb_t *RegInUrb; ++ UsbTxQ_t UsbTxBufQ[ZM_MAX_TX_BUF_NUM]; ++ zbuf_t *UsbRxBufQ[ZM_MAX_RX_URB_NUM]; ++ u16_t TxBufHead; ++ u16_t TxBufTail; ++ u16_t TxBufCnt; ++ u16_t TxUrbHead; ++ u16_t TxUrbTail; ++ u16_t TxUrbCnt; ++ u16_t RxBufHead; ++ u16_t RxBufTail; ++ u16_t RxBufCnt; ++#endif ++ ++#if ZM_USB_STREAM_MODE == 1 ++ zbuf_t *reamin_buf; ++#endif ++ ++#ifdef ZM_HOSTAPD_SUPPORT ++ struct athr_wlan_param athr_wpa_req; ++#endif ++ struct sock *netlink_sk; ++ u8_t DeviceOpened; //CWYang(+) ++ u8_t supIe[50]; ++ u8_t supLen; ++ struct ieee80211req_wpaie stawpaie[ZM_OAL_MAX_STA_SUPPORT]; ++ u8_t forwardMgmt; ++ ++ struct zfCbUsbFuncTbl usbCbFunctions; ++ ++ /* For keventd */ ++ u32_t flags; ++ unsigned long kevent_flags; ++ u16_t kevent_ready; ++ ++ struct semaphore ioctl_sem; ++ struct work_struct kevent; ++ wait_queue_head_t wait_queue_event; ++#ifdef ZM_HALPLUS_LOCK ++ unsigned long hal_irqFlag; ++#endif ++ u16_t adapterState; ++}; ++ ++/* WDS */ ++#define ZM_WDS_PORT_NUMBER 6 ++ ++struct zsWdsStruct ++{ ++ struct net_device* dev; ++ u16_t openFlag; ++}; ++ ++/* VAP */ ++#define ZM_VAP_PORT_NUMBER 7 ++ ++struct zsVapStruct ++{ ++ struct net_device* dev; ++ u16_t openFlag; ++}; ++ ++/***************************************/ ++ ++#define ZM_IOCTL_REG_READ 0x01 ++#define ZM_IOCTL_REG_WRITE 0x02 ++#define ZM_IOCTL_MEM_DUMP 0x03 ++#define ZM_IOCTL_REG_DUMP 0x05 ++#define ZM_IOCTL_TXD_DUMP 0x06 ++#define ZM_IOCTL_RXD_DUMP 0x07 ++#define ZM_IOCTL_MEM_READ 0x0B ++#define ZM_IOCTL_MEM_WRITE 0x0C ++#define ZM_IOCTL_DMA_TEST 0x10 ++#define ZM_IOCTL_REG_TEST 0x11 ++#define ZM_IOCTL_TEST 0x80 ++#define ZM_IOCTL_TALLY 0x81 //CWYang(+) ++#define ZM_IOCTL_RTS 0xA0 ++#define ZM_IOCTL_MIX_MODE 0xA1 ++#define ZM_IOCTL_FRAG 0xA2 ++#define ZM_IOCTL_SCAN 0xA3 ++#define ZM_IOCTL_KEY 0xA4 ++#define ZM_IOCTL_RATE 0xA5 ++#define ZM_IOCTL_ENCRYPTION_MODE 0xA6 ++#define ZM_IOCTL_GET_TXCNT 0xA7 ++#define ZM_IOCTL_GET_DEAGG_CNT 0xA8 ++#define ZM_IOCTL_DURATION_MODE 0xA9 ++#define ZM_IOCTL_SET_AES_KEY 0xAA ++#define ZM_IOCTL_SET_AES_MODE 0xAB ++#define ZM_IOCTL_SIGNAL_STRENGTH 0xAC //CWYang(+) ++#define ZM_IOCTL_SIGNAL_QUALITY 0xAD //CWYang(+) ++#define ZM_IOCTL_SET_PIBSS_MODE 0xAE ++ ++#define ZDAPIOCTL SIOCDEVPRIVATE ++ ++enum devState { ++ Opened, ++ Enabled, ++ Disabled, ++ Closed ++}; ++ ++#endif /* _USBDRV_H */ ++ +--- /dev/null ++++ b/drivers/staging/otus/wrap_buf.c +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : wrap_buf.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for buffer management */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++ ++ ++/* Called to allocate buffer, must return a continue buffer space */ ++zbuf_t* zfwBufAllocate(zdev_t* dev, u16_t len) ++{ ++ zbuf_t* buf; ++ ++ /* Allocate SKB for packet*/ ++ buf = dev_alloc_skb(len); ++ ++ return buf; ++} ++ ++ ++/* Called to free buffer, replace below 3 functions */ ++void zfwBufFree(zdev_t* dev, zbuf_t* buf, u16_t status) ++{ ++ dev_kfree_skb_any(buf); ++} ++ ++/* Called to adjust buffer size and head pointer */ ++u16_t zfwBufRemoveHead(zdev_t* dev, zbuf_t* buf, u16_t size) ++{ ++ //zm_assert(buf->len > size); ++ ++ buf->data += size; ++ buf->len -= size; ++ return 0; ++} ++ ++ ++ ++ ++/* return tail if head==NULL, called to chain multiple buffer together */ ++/* Used to chain Rx buffer to form a frame. if the prepared Rx buffer */ ++/* is greater than an ethernet frame(1518+32 byte), then this function */ ++/* will only be called with head=NULL. */ ++u16_t zfwBufChain(zdev_t* dev, zbuf_t** head, zbuf_t* tail) ++{ ++ ++ *head = tail; ++ return 0; ++} ++ ++ ++/* Called when doing infra-bss forwarding */ ++u16_t zfwBufCopy(zdev_t* dev, zbuf_t* dst, zbuf_t* src) ++{ ++ memcpy(dst->data, src->data, src->len); ++ dst->tail = dst->data; ++ skb_put(dst, src->len); ++ return 0; ++} ++ ++ ++/* Called to adjust buffer size and tail pointer */ ++u16_t zfwBufSetSize(zdev_t* dev, zbuf_t* buf, u16_t size) ++{ ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ buf->tail = 0; ++ buf->len = 0; ++#else ++ buf->tail = buf->data; ++ buf->len = 0; ++#endif ++ ++ skb_put(buf, size); ++ return 0; ++} ++ ++u16_t zfwBufGetSize(zdev_t* dev, zbuf_t* buf) ++{ ++ return buf->len; ++} ++ ++void zfwCopyBufContext(zdev_t* dev, zbuf_t* source, zbuf_t* dst) ++{ ++} +--- /dev/null ++++ b/drivers/staging/otus/wrap_dbg.c +@@ -0,0 +1,101 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : wrap_dbg.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for debug functions */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++void zfwDumpBuf(zdev_t* dev, zbuf_t* buf) ++{ ++ u16_t i; ++ ++ for (i=0; ilen; i++) ++ { ++ printk("%02x ", *(((u8_t*)buf->data)+i)); ++ if ((i&0xf)==0xf) ++ { ++ printk("\n"); ++ } ++ } ++ printk("\n"); ++} ++ ++ ++void zfwDbgReadRegDone(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ printk("Read addr:%x = %x\n", addr, val); ++} ++ ++void zfwDbgWriteRegDone(zdev_t* dev, u32_t addr, u32_t val) ++{ ++ printk("Write addr:%x = %x\n", addr, val); ++} ++ ++void zfwDbgReadTallyDone(zdev_t* dev) ++{ ++ //printk("Read Tall Done\n"); ++} ++ ++void zfwDbgWriteEepromDone(zdev_t* dev, u32_t addr, u32_t val) ++{ ++} ++ ++void zfwDbgQueryHwTxBusyDone(zdev_t* dev, u32_t val) ++{ ++} ++ ++//For Evl ++ ++void zfwDbgReadFlashDone(zdev_t* dev, u32_t addr, u32_t* rspdata, u32_t datalen) ++{ ++ printk("Read Flash addr:%x length:%x\n", addr, datalen); ++} ++ ++void zfwDbgProgrameFlashDone(zdev_t* dev) ++{ ++ printk("Program Flash Done\n"); ++} ++ ++void zfwDbgProgrameFlashChkDone(zdev_t* dev) ++{ ++ printk("Program Flash Done\n"); ++} ++ ++void zfwDbgGetFlashChkSumDone(zdev_t* dev, u32_t* rspdata) ++{ ++ printk("Get Flash ChkSum Done\n"); ++} ++ ++void zfwDbgDownloadFwInitDone(zdev_t* dev) ++{ ++ printk("Download FW Init Done\n"); ++} ++//For Evl -- ++ ++/* Leave an empty line below to remove warning message on some compiler */ +--- /dev/null ++++ b/drivers/staging/otus/wrap_ev.c +@@ -0,0 +1,283 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : wrap_ev.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for events */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++ ++/***** Management *****/ ++u16_t zfLnxAuthNotify(zdev_t* dev, u16_t* macAddr) ++{ ++ return 0; ++} ++ ++u16_t zfLnxAsocNotify(zdev_t* dev, u16_t* macAddr, u8_t* body, u16_t bodySize, u16_t port) ++{ ++//#ifdef ZM_HOSTAPD_SUPPORT ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ union iwreq_data wreq; ++ u8_t *addr = (u8_t *) macAddr; ++ u16_t i, j; ++ ++ memset(&wreq, 0, sizeof(wreq)); ++ memcpy(wreq.addr.sa_data, macAddr, ETH_ALEN); ++ wreq.addr.sa_family = ARPHRD_ETHER; ++ printk(KERN_DEBUG "join_event of MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ ++ for(i = 0; i < ZM_OAL_MAX_STA_SUPPORT; i++) ++ { ++ for(j = 0; j < IEEE80211_ADDR_LEN; j++) ++ { ++ if ((macp->stawpaie[i].wpa_macaddr[j] != 0) && ++ (macp->stawpaie[i].wpa_macaddr[j] != addr[j])) ++ break; ++ } ++ if (j == 6) ++ break; ++ } ++ if (i < ZM_OAL_MAX_STA_SUPPORT) ++ { ++ //printk("zfwAsocNotify - store wpa ie in macp, index = %d\n", i); ++ memcpy(macp->stawpaie[i].wpa_macaddr, macAddr, IEEE80211_ADDR_LEN); ++ memcpy(macp->stawpaie[i].wpa_ie, body, bodySize); ++ } ++ //if(macp->cardSetting.BssType == INFRASTRUCTURE_BSS) { ++ // //wireless_send_event(macp->device, SIOCGIWSCAN, &wreq, NULL); ++ // wireless_send_event(macp->device, SIOCGIWAP, &wreq, NULL); ++ //} ++#if WIRELESS_EXT >= 15 ++ //else if(macp->cardSetting.BssType == AP_BSS) { ++// if (port == 0) ++// { ++ wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL); ++// } ++// else ++// { ++// /* Check whether the VAP device is valid */ ++// if (vap[port].dev != NULL) ++// { ++// wireless_send_event(vap[port].dev, IWEVREGISTERED, &wreq, NULL); ++// } ++// else ++// { ++// printk(KERN_ERR "Can' find a valid VAP device, port: %d\n", port); ++// } ++// } ++ //} ++#endif ++//#endif ++ ++ return 0; ++} ++ ++ ++/* Notification that a STA is disassociated from AP */ ++/* AP mode only */ ++u16_t zfLnxDisAsocNotify(zdev_t* dev, u8_t* macAddr, u16_t port) ++{ ++ union iwreq_data wreq; ++ u8_t *addr = (u8_t *) macAddr; ++ ++ memset(&wreq, 0, sizeof(wreq)); ++ memcpy(wreq.addr.sa_data, macAddr, ETH_ALEN); ++ wreq.addr.sa_family = ARPHRD_ETHER; ++ printk(KERN_DEBUG "zfwDisAsocNotify(), MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ ++ ++ return 0; ++} ++ ++/* Notification that a STA is connect to AP */ ++/* AP mode only */ ++u16_t zfLnxApConnectNotify(zdev_t* dev, u8_t* macAddr, u16_t port) ++{ ++ union iwreq_data wreq; ++ u8_t *addr = (u8_t *) macAddr; ++ ++ memset(&wreq, 0, sizeof(wreq)); ++ memcpy(wreq.addr.sa_data, macAddr, ETH_ALEN); ++ wreq.addr.sa_family = ARPHRD_ETHER; ++ printk(KERN_DEBUG "zfwApConnectNotify(), MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ ++ ++ return 0; ++} ++ ++ ++ ++void zfLnxConnectNotify(zdev_t* dev, u16_t status, u16_t* bssid) ++{ ++ union iwreq_data wreq; ++ u8_t *addr = (u8_t *) bssid; ++ struct usbdrv_private *macp = dev->priv; ++ ++ if (bssid != NULL) ++ { ++ memset(&wreq, 0, sizeof(wreq)); ++ if (status == ZM_STATUS_MEDIA_CONNECT) ++ memcpy(wreq.addr.sa_data, bssid, ETH_ALEN); ++ wreq.addr.sa_family = ARPHRD_ETHER; ++ ++ if (status == ZM_STATUS_MEDIA_CONNECT) ++ { ++#ifdef ZM_CONFIG_BIG_ENDIAN ++ printk(KERN_DEBUG "Connected to AP, MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ addr[1], addr[0], addr[3], addr[2], addr[5], addr[4]); ++#else ++ printk(KERN_DEBUG "Connected to AP, MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++#endif ++ ++ netif_start_queue(dev); ++ } ++ else if ((status == ZM_STATUS_MEDIA_DISCONNECT) || ++ (status == ZM_STATUS_MEDIA_DISABLED) || ++ (status == ZM_STATUS_MEDIA_CONNECTION_DISABLED) || ++ (status == ZM_STATUS_MEDIA_CONNECTION_RESET) || ++ (status == ZM_STATUS_MEDIA_RESET) || ++ (status == ZM_STATUS_MEDIA_DISCONNECT_DEAUTH) || ++ (status == ZM_STATUS_MEDIA_DISCONNECT_DISASOC) || ++ (status == ZM_STATUS_MEDIA_DISCONNECT_BEACON_MISS) || ++ (status == ZM_STATUS_MEDIA_DISCONNECT_NOT_FOUND) || ++ (status == ZM_STATUS_MEDIA_DISCONNECT_TIMEOUT)) ++ { ++ printk(KERN_DEBUG "Disconnection Notify\n"); ++ ++ netif_stop_queue(dev); ++ } ++ ++ /* Save the connected status */ ++ macp->adapterState = status; ++ ++ if(zfiWlanQueryWlanMode(dev) == ZM_MODE_INFRASTRUCTURE) { ++ // //wireless_send_event(dev, SIOCGIWSCAN, &wreq, NULL); ++ wireless_send_event(dev, SIOCGIWAP, &wreq, NULL); ++ } ++#if WIRELESS_EXT >= 15 ++ else if(zfiWlanQueryWlanMode(dev) == ZM_MODE_AP) { ++ //if (port == 0) ++ //{ ++ wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL); ++ //} ++ //else ++ //{ ++ // /* Check whether the VAP device is valid */ ++ // if (vap[port].dev != NULL) ++ // { ++ // wireless_send_event(vap[port].dev, IWEVREGISTERED, &wreq, NULL); ++ // } ++ // else ++ // { ++ // printk(KERN_ERR "Can' find a valid VAP device, port: %d\n", port); ++ // } ++ //} ++ } ++#endif ++ } ++ //return 0; ++} ++ ++void zfLnxScanNotify(zdev_t* dev, struct zsScanResult* result) ++{ ++ return; ++} ++ ++void zfLnxStatisticsNotify(zdev_t* dev, struct zsStastics* result) ++{ ++ return; ++} ++ ++//void zfwMicFailureNotify(zdev_t* dev, u8_t* message, u16_t event) ++void zfLnxMicFailureNotify(zdev_t* dev, u16_t* addr, u16_t status) ++{ ++ static const char *tag = "MLME-MICHAELMICFAILURE.indication"; ++ union iwreq_data wrqu; ++ char buf[128]; ++ ++ /* TODO: needed parameters: count, type, src address */ ++ //snprintf(buf, sizeof(buf), "%s(%scast addr=%s)", tag, ++ // (status == ZM_MIC_GROUP_ERROR) ? "broad" : "uni", ++ // ether_sprintf((u8_t *)addr)); ++ ++ if (zfiWlanQueryWlanMode(dev) == ZM_MODE_INFRASTRUCTURE) ++ { ++ strcpy(buf, tag); ++ } ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = strlen(buf); ++ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); ++} ++ ++ ++void zfLnxApMicFailureNotify(zdev_t* dev, u8_t* addr, zbuf_t* buf) ++{ ++ union iwreq_data wreq; ++ ++ memset(&wreq, 0, sizeof(wreq)); ++ memcpy(wreq.addr.sa_data, addr, ETH_ALEN); ++ wreq.addr.sa_family = ARPHRD_ETHER; ++ printk(KERN_DEBUG "zfwApMicFailureNotify(), MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ ++ return; ++} ++ ++// status = 0 => partner lost ++// = 1 => partner alive ++//void zfwIbssPartnerNotify(zdev_t* dev, u8_t status) ++void zfLnxIbssPartnerNotify(zdev_t* dev, u16_t status, struct zsPartnerNotifyEvent *event) ++{ ++} ++ ++void zfLnxMacAddressNotify(zdev_t* dev, u8_t* addr) ++{ ++ dev->dev_addr[0] = addr[0]; ++ dev->dev_addr[1] = addr[1]; ++ dev->dev_addr[2] = addr[2]; ++ dev->dev_addr[3] = addr[3]; ++ dev->dev_addr[4] = addr[4]; ++ dev->dev_addr[5] = addr[5]; ++} ++ ++void zfLnxSendCompleteIndication(zdev_t* dev, zbuf_t* buf) ++{ ++} ++ ++ ++void zfLnxRestoreBufData(zdev_t* dev, zbuf_t* buf) { ++ ++} ++/* Leave an empty line below to remove warning message on some compiler */ +--- /dev/null ++++ b/drivers/staging/otus/wrap_mem.c +@@ -0,0 +1,101 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : wrap_mem.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for memory management */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++/* Memory management */ ++/* Called to allocate uncached memory, allocated memory must */ ++/* in 4-byte boundary */ ++void* zfwMemAllocate(zdev_t* dev, u32_t size) ++{ ++ void* mem = NULL; ++ mem = kmalloc(size, GFP_ATOMIC); ++ return mem; ++} ++ ++ ++/* Called to free allocated memory */ ++void zfwMemFree(zdev_t* dev, void* mem, u32_t size) ++{ ++ kfree(mem); ++ return; ++} ++ ++void zfwMemoryCopy(u8_t* dst, u8_t* src, u16_t length) ++{ ++ //u16_t i; ++ ++ memcpy(dst, src, length); ++ //for(i=0; i ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++//extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER]; ++extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER]; ++extern u16_t zfLnxGetVapId(zdev_t* dev); ++ ++/* Simply return 0xffff if VAP function is not supported */ ++u16_t zfwGetVapId(zdev_t* dev) ++{ ++ return zfLnxGetVapId(dev); ++} ++ ++void zfwSleep(zdev_t* dev, u32_t ms) ++{ ++ if (in_interrupt() == 0) ++ { ++ mdelay(ms); ++ } ++ else ++ { ++ int ii; ++ int iter = 100000 * ms; ++ ++ for (ii = 0; ii < iter; ii++) ++ { ++ ++ } ++ } ++} ++ ++#ifdef ZM_HALPLUS_LOCK ++asmlinkage struct zsWlanDev *zfwGetWlanDev(zdev_t* dev) ++{ ++ return ((struct zsWlanDev*)(((struct usbdrv_private*)dev->priv)->wd)); ++} ++ ++asmlinkage void zfwEnterCriticalSection(zdev_t* dev) ++{ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), ++ (((struct usbdrv_private *)(dev->priv))->hal_irqFlag)); ++} ++ ++asmlinkage void zfwLeaveCriticalSection(zdev_t* dev) ++{ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), ++ (((struct usbdrv_private *)(dev->priv))->hal_irqFlag)); ++} ++ ++asmlinkage u8_t zfwBufReadByte(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ return *(u8_t*)((u8_t*)buf->data+offset); ++} ++ ++asmlinkage u16_t zfwBufReadHalfWord(zdev_t* dev, zbuf_t* buf, u16_t offset) ++{ ++ return zmw_cpu_to_le16(*(u16_t*)((u8_t*)buf->data+offset)); ++} ++ ++asmlinkage void zfwBufWriteByte(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t value) ++{ ++ *(u8_t*)((u8_t*)buf->data+offset) = value; ++} ++ ++asmlinkage void zfwBufWriteHalfWord(zdev_t* dev, zbuf_t* buf, u16_t offset, u16_t value) ++{ ++ *(u16_t*)((u8_t*)buf->data+offset) = zmw_cpu_to_le16(value); ++} ++ ++asmlinkage u8_t *zfwGetBuffer(zdev_t* dev, zbuf_t* buf) ++{ ++ return (u8_t*)(buf->data); ++} ++#endif ++ ++/* Leave an empty line below to remove warning message on some compiler */ +--- /dev/null ++++ b/drivers/staging/otus/wrap_pkt.c +@@ -0,0 +1,178 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : wrap_pkt.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for packet handling */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++ ++ ++//extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER]; ++extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER]; ++ ++ ++/***** Rx *****/ ++void zfLnxRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo) ++{ ++ u16_t frameType; ++ u16_t frameCtrl; ++ u16_t frameSubtype; ++ zbuf_t *skb1; ++ struct usbdrv_private *macp = dev->priv; ++ ++ //frameCtrl = zmw_buf_readb(dev, buf, 0); ++ frameCtrl = *(u8_t*)((u8_t*)buf->data); ++ frameType = frameCtrl & 0xf; ++ frameSubtype = frameCtrl & 0xf0; ++ ++ if ((frameType == 0x0) && (macp->forwardMgmt)) ++ { ++ switch (frameSubtype) ++ { ++ /* Beacon */ ++ case 0x80 : ++ /* Probe response */ ++ case 0x50 : ++ skb1 = skb_copy(buf, GFP_ATOMIC); ++ if(skb1 != NULL) ++ { ++ skb1->dev = dev; ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) ++ skb1->mac.raw = skb1->data; ++ #else ++ skb1->mac_header = skb1->data; ++ #endif ++ skb1->ip_summed = CHECKSUM_NONE; ++ skb1->pkt_type = PACKET_OTHERHOST; ++ skb1->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ ++ netif_rx(skb1); ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ ++ zfiRecv80211(dev, buf, addInfo); ++ return; ++} ++ ++#define ZM_AVOID_UDP_LARGE_PACKET_FAIL ++void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port) ++{ ++#ifdef ZM_AVOID_UDP_LARGE_PACKET_FAIL ++ zbuf_t *new_buf; ++ ++ //new_buf = dev_alloc_skb(2048); ++ new_buf = dev_alloc_skb(buf->len); ++ ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ new_buf->tail = 0; ++ new_buf->len = 0; ++#else ++ new_buf->tail = new_buf->data; ++ new_buf->len = 0; ++#endif ++ ++ skb_put(new_buf, buf->len); ++ memcpy(new_buf->data, buf->data, buf->len); ++ ++ /* Free buffer */ ++ dev_kfree_skb_any(buf); ++ ++ if (port == 0) ++ { ++ new_buf->dev = dev; ++ new_buf->protocol = eth_type_trans(new_buf, dev); ++ } ++ else ++ { ++ /* VAP */ ++ if (vap[0].dev != NULL) ++ { ++ new_buf->dev = vap[0].dev; ++ new_buf->protocol = eth_type_trans(new_buf, vap[0].dev); ++ } ++ else ++ { ++ new_buf->dev = dev; ++ new_buf->protocol = eth_type_trans(new_buf, dev); ++ } ++ } ++ ++ new_buf->ip_summed = CHECKSUM_NONE; ++ dev->last_rx = jiffies; ++ ++ switch(netif_rx(new_buf)) ++#else ++ if (port == 0) ++ { ++ buf->dev = dev; ++ buf->protocol = eth_type_trans(buf, dev); ++ } ++ else ++ { ++ /* VAP */ ++ if (vap[0].dev != NULL) ++ { ++ buf->dev = vap[0].dev; ++ buf->protocol = eth_type_trans(buf, vap[0].dev); ++ } ++ else ++ { ++ buf->dev = dev; ++ buf->protocol = eth_type_trans(buf, dev); ++ } ++ } ++ ++ buf->ip_summed = CHECKSUM_NONE; ++ dev->last_rx = jiffies; ++ ++ switch(netif_rx(buf)) ++#endif ++ { ++ case NET_RX_BAD: ++ case NET_RX_DROP: ++ case NET_RX_CN_MOD: ++ case NET_RX_CN_HIGH: ++ break; ++ default: ++ ((struct usbdrv_private*)(dev->priv))-> ++ drv_stats.net_stats.rx_packets++; ++ ((struct usbdrv_private*)(dev->priv))-> ++ drv_stats.net_stats.rx_bytes += buf->len; ++ break; ++ } ++ ++ return; ++} ++ ++/* Leave an empty line below to remove warning message on some compiler */ +--- /dev/null ++++ b/drivers/staging/otus/wrap_sec.c +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : wrap_sec.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for CENC. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++#ifdef ZM_ENABLE_CENC ++extern int zfLnxCencSendMsg(struct sock *netlink_sk, u_int8_t *msg, int len); ++ ++u16_t zfLnxCencAsocNotify(zdev_t* dev, u16_t* macAddr, u8_t* body, u16_t bodySize, u16_t port) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ struct zydas_cenc_sta_info cenc_info; ++ //struct sock *netlink_sk; ++ u8_t ie_len; ++ int ii; ++ ++ /* Create NETLINK socket */ ++ //netlink_sk = netlink_kernel_create(NETLINK_USERSOCK, NULL); ++ ++ if (macp->netlink_sk == NULL) ++ { ++ printk(KERN_ERR "NETLINK Socket is NULL\n"); ++ return -1; ++ } ++ ++ memset(&cenc_info, 0, sizeof(cenc_info)); ++ ++ //memcpy(cenc_info.gsn, vap->iv_cencmsk_keys.wk_txiv, ZM_CENC_IV_LEN); ++ zfiWlanQueryGSN(dev, cenc_info.gsn, port); ++ cenc_info.datalen += ZM_CENC_IV_LEN; ++ ie_len = body[1] + 2; ++ memcpy(cenc_info.wie, body, ie_len); ++ cenc_info.datalen += ie_len; ++ ++ memcpy(cenc_info.sta_mac, macAddr, 6); ++ cenc_info.msg_type = ZM_CENC_WAI_REQUEST; ++ cenc_info.datalen += 6 + 2; ++ ++ printk(KERN_ERR "===== zfwCencSendMsg, bodySize: %d =====\n", bodySize); ++ ++ for(ii = 0; ii < bodySize; ii++) ++ { ++ printk(KERN_ERR "%02x ", body[ii]); ++ ++ if ((ii & 0xf) == 0xf) ++ { ++ printk(KERN_ERR "\n"); ++ } ++ } ++ ++ zfLnxCencSendMsg(macp->netlink_sk, (u8_t *)&cenc_info, cenc_info.datalen+4); ++ ++ /* Close NETLINK socket */ ++ //sock_release(netlink_sk); ++ ++ return 0; ++} ++#endif //ZM_ENABLE_CENC ++ ++u8_t zfwCencHandleBeaconProbrespon(zdev_t* dev, u8_t *pWIEc, ++ u8_t *pPeerSSIDc, u8_t *pPeerAddrc) ++{ ++ return 0; ++} ++ ++u8_t zfwGetPktEncExemptionActionType(zdev_t* dev, zbuf_t* buf) ++{ ++ return ZM_ENCRYPTION_EXEMPT_NO_EXEMPTION; ++} ++ ++void copyToIntTxBuffer(zdev_t* dev, zbuf_t* buf, u8_t* src, ++ u16_t offset, u16_t length) ++{ ++ u16_t i; ++ ++ for(i=0; idata+offset+i) = src[i]; ++ } ++} ++ ++u16_t zfwStaAddIeWpaRsn(zdev_t* dev, zbuf_t* buf, u16_t offset, u8_t frameType) ++{ ++ struct usbdrv_private *macp = dev->priv; ++ //zm_msg1_mm(ZM_LV_0, "CWY - add wpaie content Length : ", macp->supIe[1]); ++ if (macp->supIe[1] != 0) ++ { ++ copyToIntTxBuffer(dev, buf, macp->supIe, offset, macp->supIe[1]+2); ++ //memcpy(buf->data[offset], macp->supIe, macp->supIe[1]+2); ++ offset += (macp->supIe[1]+2); ++ } ++ ++ return offset; ++} ++ ++/* Leave an empty line below to remove warning message on some compiler */ +--- /dev/null ++++ b/drivers/staging/otus/wrap_usb.c +@@ -0,0 +1,195 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : wrap_usb.c */ ++/* */ ++/* Abstract */ ++/* This module contains wrapper functions for USB management */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++extern void zfLnxInitUsbTxQ(zdev_t* dev); ++extern void zfLnxInitUsbRxQ(zdev_t* dev); ++extern u32_t zfLnxSubmitRegInUrb(zdev_t *dev); ++u32_t zfLnxUsbOut(zdev_t* dev, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen, ++ u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset); ++u32_t zfLnxUsbWriteReg(zdev_t* dev, u32_t* cmd, u16_t cmdLen); ++ ++void zfwUsbRegisterCallBack(zdev_t* dev, struct zfCbUsbFuncTbl *zfUsbFunc) { ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ macp->usbCbFunctions.zfcbUsbRecv = zfUsbFunc->zfcbUsbRecv; ++ macp->usbCbFunctions.zfcbUsbRegIn = zfUsbFunc->zfcbUsbRegIn; ++ macp->usbCbFunctions.zfcbUsbOutComplete = zfUsbFunc->zfcbUsbOutComplete; ++ ++ return; ++} ++ ++u32_t zfwUsbGetFreeTxQSize(zdev_t* dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u32_t freeTxQSize; ++ unsigned long irqFlag; ++ //zmw_declare_for_critical_section(); ++ ++ //zmw_enter_critical_section(dev); ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ freeTxQSize = ZM_MAX_TX_BUF_NUM - macp->TxBufCnt; ++ ++ //zmw_leave_critical_section(dev); ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ return freeTxQSize; ++} ++ ++u32_t zfwUsbGetMaxTxQSize(zdev_t* dev) ++{ ++ return ZM_MAX_TX_BUF_NUM; ++} ++ ++u32_t zfwUsbEnableIntEpt(zdev_t *dev, u8_t endpt) ++{ ++ /* Initialize USB TxQ */ ++ zfLnxInitUsbTxQ(dev); ++ ++ /* Initialize USB RxQ */ ++ zfLnxInitUsbRxQ(dev); ++ ++ /* Initialize USB Register In URB */ ++ //zfwUsbSubmitRegIn(dev); ++ /* Initialize USB Register In URB */ ++ zfLnxSubmitRegInUrb(dev); ++ ++ return 0; ++} ++ ++int zfwUsbEnableRxEpt(zdev_t* dev, u8_t endpt) ++{ ++ return 0; ++} ++ ++u32_t zfwUsbSubmitControl(zdev_t* dev, u8_t req, u16_t value, u16_t index, void *data, u32_t size) ++{ ++ int result = 0; ++ u32_t ret = 0; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u8_t* buf; ++ ++ if (size > 0) ++ { ++ buf = kmalloc(size, GFP_KERNEL); ++ memcpy(buf, (u8_t*)data, size); ++ } ++ else ++ { ++ buf = NULL; ++ } ++ ++#if 0 ++ printk(KERN_ERR "req = 0x%02x\n", req); ++ printk(KERN_ERR "value = 0x%04x\n", value); ++ printk(KERN_ERR "index = 0x%04x\n", index); ++ printk(KERN_ERR "data = 0x%lx\n", (u32_t) data); ++ printk(KERN_ERR "size = %ld\n", size); ++#endif ++ ++ result = usb_control_msg(macp->udev, usb_sndctrlpipe(macp->udev, 0), ++ req, USB_DIR_OUT | 0x40, value, index, buf, size, HZ); ++ ++ if (result < 0) ++ { ++ printk("zfwUsbSubmitControl() failed, result=0x%x\n", result); ++ ret = 1; ++ } ++ kfree(buf); ++ ++ return ret; ++} ++ ++void zfwUsbCmd(zdev_t* dev, u8_t endpt, u32_t* cmd, u16_t cmdLen) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u32_t ret; ++ ++ //MPUsbCommand(dev, endpt, cmd, cmdLen); ++ ret = zfLnxUsbWriteReg(dev, cmd, cmdLen); ++ ++ /* if zfLnxUsbWriteReg() return error, free and allocate urb, resend again */ ++ if (ret != 0) ++ { ++ usb_free_urb(macp->RegOutUrb); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* tune me! */ ++ macp->RegOutUrb = usb_alloc_urb(0, GFP_ATOMIC); ++#else ++ macp->RegOutUrb = usb_alloc_urb(0); ++#endif ++ ret = zfLnxUsbWriteReg(dev, cmd, cmdLen); ++ } ++} ++ ++u32_t zfwUsbSend(zdev_t* dev, u8_t endpt, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen, ++ u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset) ++{ ++ u32_t status; ++ ++#ifdef ZM_CONFIG_BIG_ENDIAN ++ u32_t ii = 0; ++ u16_t *pc = NULL; ++ ++ pc = (u16_t *)hdr; ++ for(ii=0; ii<(hdrlen>>1); ii++) ++ { ++ pc[ii] = cpu_to_le16(pc[ii]); ++ } ++ ++ pc = (u16_t *)snap; ++ for(ii=0; ii<(snapLen>>1); ii++) ++ { ++ pc[ii] = cpu_to_le16(pc[ii]); ++ } ++ ++ pc = (u16_t *)tail; ++ for(ii=0; ii<(tailLen>>1); ii++) ++ { ++ pc[ii] = cpu_to_le16(pc[ii]); ++ } ++#endif ++ ++ status = zfLnxUsbOut(dev, hdr, hdrlen, snap, snapLen, tail, tailLen, buf, offset); ++ if ( status == 0 ) ++ { ++ return 0; ++ } ++ else ++ { ++ return 1; ++ } ++} ++ ++/* Leave an empty line below to remove warning message on some compiler */ +--- /dev/null ++++ b/drivers/staging/otus/wwrap.c +@@ -0,0 +1,1207 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* Module Name : wwrap.c */ ++/* Abstract */ ++/* This module contains wrapper functions. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++ ++/* Please include your header files here */ ++#include "oal_dt.h" ++#include "usbdrv.h" ++ ++#include ++ ++#if WIRELESS_EXT > 12 ++#include ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#define URB_ZERO_PACKET USB_ZERO_PACKET ++#endif ++ ++extern void zfiRecv80211(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++extern void zfCoreRecv(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo* addInfo); ++extern void zfIdlChkRsp(zdev_t* dev, u32_t* rsp, u16_t rspLen); ++extern void zfIdlRsp(zdev_t* dev, u32_t *rsp, u16_t rspLen); ++ ++ ++ ++//extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER]; ++extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER]; ++ ++u32_t zfLnxUsbSubmitTxData(zdev_t* dev); ++u32_t zfLnxUsbIn(zdev_t* dev, urb_t *urb, zbuf_t *buf); ++u32_t zfLnxSubmitRegInUrb(zdev_t *dev); ++u32_t zfLnxUsbSubmitBulkUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, ++ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context); ++u32_t zfLnxUsbSubmitIntUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, ++ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context, ++ u32_t interval); ++ ++u16_t zfLnxGetFreeTxUrb(zdev_t *dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u16_t idx; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ //idx = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1)); ++ ++ //if (idx != macp->TxUrbHead) ++ if (macp->TxUrbCnt != 0) ++ { ++ idx = macp->TxUrbTail; ++ macp->TxUrbTail = ((macp->TxUrbTail + 1) & (ZM_MAX_TX_URB_NUM - 1)); ++ macp->TxUrbCnt--; ++ } ++ else ++ { ++ //printk(KERN_ERR "macp->TxUrbCnt: %d\n", macp->TxUrbCnt); ++ idx = 0xffff; ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return idx; ++} ++ ++void zfLnxPutTxUrb(zdev_t *dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u16_t idx; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ idx = ((macp->TxUrbHead + 1) & (ZM_MAX_TX_URB_NUM - 1)); ++ ++ //if (idx != macp->TxUrbTail) ++ if (macp->TxUrbCnt < ZM_MAX_TX_URB_NUM) ++ { ++ macp->TxUrbHead = idx; ++ macp->TxUrbCnt++; ++ } ++ else ++ { ++ printk("UsbTxUrbQ inconsistent: TxUrbHead: %d, TxUrbTail: %d\n", ++ macp->TxUrbHead, macp->TxUrbTail); ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++} ++ ++u16_t zfLnxCheckTxBufferCnt(zdev_t *dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u16_t TxBufCnt; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ TxBufCnt = macp->TxBufCnt; ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return TxBufCnt; ++} ++ ++UsbTxQ_t *zfLnxGetUsbTxBuffer(zdev_t *dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u16_t idx; ++ UsbTxQ_t *TxQ; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ idx = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1)); ++ ++ //if (idx != macp->TxBufTail) ++ if (macp->TxBufCnt > 0) ++ { ++ //printk("CWY - zfwGetUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt); ++ TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufHead]); ++ macp->TxBufHead = ((macp->TxBufHead+1) & (ZM_MAX_TX_BUF_NUM - 1)); ++ macp->TxBufCnt--; ++ } ++ else ++ { ++ if (macp->TxBufHead != macp->TxBufTail) ++ { ++ printk(KERN_ERR "zfwGetUsbTxBuf UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d\n", ++ macp->TxBufHead, macp->TxBufTail); ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return NULL; ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return TxQ; ++} ++ ++u16_t zfLnxPutUsbTxBuffer(zdev_t *dev, u8_t *hdr, u16_t hdrlen, ++ u8_t *snap, u16_t snapLen, u8_t *tail, u16_t tailLen, ++ zbuf_t *buf, u16_t offset) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u16_t idx; ++ UsbTxQ_t *TxQ; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ idx = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1)); ++ ++ /* For Tx debug */ ++ //zm_assert(macp->TxBufCnt >= 0); // deleted because of always true ++ ++ //if (idx != macp->TxBufHead) ++ if (macp->TxBufCnt < ZM_MAX_TX_BUF_NUM) ++ { ++ //printk("CWY - zfwPutUsbTxBuffer ,macp->TxBufCnt = %d\n", macp->TxBufCnt); ++ TxQ = (UsbTxQ_t *)&(macp->UsbTxBufQ[macp->TxBufTail]); ++ memcpy(TxQ->hdr, hdr, hdrlen); ++ TxQ->hdrlen = hdrlen; ++ memcpy(TxQ->snap, snap, snapLen); ++ TxQ->snapLen = snapLen; ++ memcpy(TxQ->tail, tail, tailLen); ++ TxQ->tailLen = tailLen; ++ TxQ->buf = buf; ++ TxQ->offset = offset; ++ ++ macp->TxBufTail = ((macp->TxBufTail+1) & (ZM_MAX_TX_BUF_NUM - 1)); ++ macp->TxBufCnt++; ++ } ++ else ++ { ++ printk(KERN_ERR "zfLnxPutUsbTxBuffer UsbTxBufQ inconsistent: TxBufHead: %d, TxBufTail: %d, TxBufCnt: %d\n", ++ macp->TxBufHead, macp->TxBufTail, macp->TxBufCnt); ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return 0xffff; ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return 0; ++} ++ ++zbuf_t *zfLnxGetUsbRxBuffer(zdev_t *dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ //u16_t idx; ++ zbuf_t *buf; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ //idx = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1)); ++ ++ //if (idx != macp->RxBufTail) ++ if (macp->RxBufCnt != 0) ++ { ++ buf = macp->UsbRxBufQ[macp->RxBufHead]; ++ macp->RxBufHead = ((macp->RxBufHead+1) & (ZM_MAX_RX_URB_NUM - 1)); ++ macp->RxBufCnt--; ++ } ++ else ++ { ++ printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n", ++ macp->RxBufHead, macp->RxBufTail); ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return NULL; ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return buf; ++} ++ ++u32_t zfLnxPutUsbRxBuffer(zdev_t *dev, zbuf_t *buf) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u16_t idx; ++ unsigned long irqFlag; ++ ++ spin_lock_irqsave(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ ++ idx = ((macp->RxBufTail+1) & (ZM_MAX_RX_URB_NUM - 1)); ++ ++ //if (idx != macp->RxBufHead) ++ if (macp->RxBufCnt != ZM_MAX_RX_URB_NUM) ++ { ++ macp->UsbRxBufQ[macp->RxBufTail] = buf; ++ macp->RxBufTail = idx; ++ macp->RxBufCnt++; ++ } ++ else ++ { ++ printk("RxBufQ inconsistent: RxBufHead: %d, RxBufTail: %d\n", ++ macp->RxBufHead, macp->RxBufTail); ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return 0xffff; ++ } ++ ++ spin_unlock_irqrestore(&(((struct usbdrv_private *)(dev->priv))->cs_lock), irqFlag); ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++void zfLnxUsbDataOut_callback(urb_t *urb) ++#else ++void zfLnxUsbDataOut_callback(urb_t *urb, struct pt_regs *regs) ++#endif ++{ ++ zdev_t* dev = urb->context; ++ //UsbTxQ_t *TxData; ++ ++ /* Give the urb back */ ++ zfLnxPutTxUrb(dev); ++ ++ /* Check whether there is any pending buffer needed */ ++ /* to be sent */ ++ if (zfLnxCheckTxBufferCnt(dev) != 0) ++ { ++ //TxData = zfwGetUsbTxBuffer(dev); ++ ++ //if (TxData == NULL) ++ //{ ++ // printk("Get a NULL buffer from zfwGetUsbTxBuffer\n"); ++ // return; ++ //} ++ //else ++ //{ ++ zfLnxUsbSubmitTxData(dev); ++ //} ++ } ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++void zfLnxUsbDataIn_callback(urb_t *urb) ++#else ++void zfLnxUsbDataIn_callback(urb_t *urb, struct pt_regs *regs) ++#endif ++{ ++ zdev_t* dev = urb->context; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ zbuf_t *buf; ++ zbuf_t *new_buf; ++ int status; ++ ++#if ZM_USB_STREAM_MODE == 1 ++ static int remain_len = 0, check_pad = 0, check_len = 0; ++ int index = 0; ++ int chk_idx; ++ u16_t pkt_len; ++ u16_t pkt_tag; ++ u16_t ii; ++ zbuf_t *rxBufPool[8]; ++ u16_t rxBufPoolIndex = 0; ++#endif ++ ++ /* Check status for URB */ ++ if (urb->status != 0){ ++ printk("zfLnxUsbDataIn_callback() : status=0x%x\n", urb->status); ++ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET) ++ && (urb->status != -ESHUTDOWN)) ++ { ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ if (urb->status == USB_ST_INTERNALERROR) ++ status = -1; ++ #else ++ if (urb->status == -EPIPE){ ++ //printk(KERN_ERR "nonzero read bulk status received: -EPIPE"); ++ status = -1; ++ } ++ ++ if (urb->status == -EPROTO){ ++ //printk(KERN_ERR "nonzero read bulk status received: -EPROTO"); ++ status = -1; ++ } ++ #endif ++ } ++ ++ //printk(KERN_ERR "urb->status: 0x%08x\n", urb->status); ++ ++ /* Dequeue skb buffer */ ++ buf = zfLnxGetUsbRxBuffer(dev); ++ dev_kfree_skb_any(buf); ++ #if 0 ++ /* Enqueue skb buffer */ ++ zfLnxPutUsbRxBuffer(dev, buf); ++ ++ /* Submit a Rx urb */ ++ zfLnxUsbIn(dev, urb, buf); ++ #endif ++ return; ++ } ++ ++ if (urb->actual_length == 0) ++ { ++ printk(KERN_ERR "Get an URB whose length is zero"); ++ status = -1; ++ } ++ ++ /* Dequeue skb buffer */ ++ buf = zfLnxGetUsbRxBuffer(dev); ++ ++ //zfwBufSetSize(dev, buf, urb->actual_length); ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ buf->tail = 0; ++ buf->len = 0; ++#else ++ buf->tail = buf->data; ++ buf->len = 0; ++#endif ++ ++ if ((buf->tail + urb->actual_length) > buf->end) ++ BUG(); ++ ++ skb_put(buf, urb->actual_length); ++ ++#if ZM_USB_STREAM_MODE == 1 ++ if (remain_len != 0) ++ { ++ zbuf_t *remain_buf = macp->reamin_buf; ++ ++ index = remain_len; ++ remain_len -= check_pad; ++ ++ /* Copy data */ ++ memcpy(&(remain_buf->data[check_len]), buf->data, remain_len); ++ check_len += remain_len; ++ remain_len = 0; ++ ++ rxBufPool[rxBufPoolIndex++] = remain_buf; ++ } ++ ++ while(index < urb->actual_length) ++ { ++ pkt_len = buf->data[index] + (buf->data[index+1] << 8); ++ pkt_tag = buf->data[index+2] + (buf->data[index+3] << 8); ++ ++ if (pkt_tag == 0x4e00) ++ { ++ int pad_len; ++ ++ //printk("Get a packet, index: %d, pkt_len: 0x%04x\n", index, pkt_len); ++ #if 0 ++ /* Dump data */ ++ for (ii = index; ii < pkt_len+4;) ++ { ++ printk("%02x ", (buf->data[ii] & 0xff)); ++ ++ if ((++ii % 16) == 0) ++ printk("\n"); ++ } ++ ++ printk("\n"); ++ #endif ++ ++ pad_len = 4 - (pkt_len & 0x3); ++ ++ if(pad_len == 4) ++ pad_len = 0; ++ ++ chk_idx = index; ++ index = index + 4 + pkt_len + pad_len; ++ ++ if (index > ZM_MAX_RX_BUFFER_SIZE) ++ { ++ remain_len = index - ZM_MAX_RX_BUFFER_SIZE; // - pad_len; ++ check_len = ZM_MAX_RX_BUFFER_SIZE - chk_idx - 4; ++ check_pad = pad_len; ++ ++ /* Allocate a skb buffer */ ++ //new_buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE); ++ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); ++ ++ /* Set skb buffer length */ ++ #ifdef NET_SKBUFF_DATA_USES_OFFSET ++ new_buf->tail = 0; ++ new_buf->len = 0; ++ #else ++ new_buf->tail = new_buf->data; ++ new_buf->len = 0; ++ #endif ++ ++ skb_put(new_buf, pkt_len); ++ ++ /* Copy the buffer */ ++ memcpy(new_buf->data, &(buf->data[chk_idx+4]), check_len); ++ ++ /* Record the buffer pointer */ ++ macp->reamin_buf = new_buf; ++ } ++ else ++ { ++ #ifdef ZM_DONT_COPY_RX_BUFFER ++ if (rxBufPoolIndex == 0) ++ { ++ new_buf = skb_clone(buf, GFP_ATOMIC); ++ ++ new_buf->data = &(buf->data[chk_idx+4]); ++ new_buf->len = pkt_len; ++ } ++ else ++ { ++ #endif ++ /* Allocate a skb buffer */ ++ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); ++ ++ /* Set skb buffer length */ ++ #ifdef NET_SKBUFF_DATA_USES_OFFSET ++ new_buf->tail = 0; ++ new_buf->len = 0; ++ #else ++ new_buf->tail = new_buf->data; ++ new_buf->len = 0; ++ #endif ++ ++ skb_put(new_buf, pkt_len); ++ ++ /* Copy the buffer */ ++ memcpy(new_buf->data, &(buf->data[chk_idx+4]), pkt_len); ++ ++ #ifdef ZM_DONT_COPY_RX_BUFFER ++ } ++ #endif ++ rxBufPool[rxBufPoolIndex++] = new_buf; ++ } ++ } ++ else ++ { ++ printk(KERN_ERR "Can't find tag, pkt_len: 0x%04x, tag: 0x%04x\n", pkt_len, pkt_tag); ++ ++ /* Free buffer */ ++ dev_kfree_skb_any(buf); ++ ++ /* Allocate a skb buffer */ ++ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); ++ ++ /* Enqueue skb buffer */ ++ zfLnxPutUsbRxBuffer(dev, new_buf); ++ ++ /* Submit a Rx urb */ ++ zfLnxUsbIn(dev, urb, new_buf); ++ ++ return; ++ } ++ } ++ ++ /* Free buffer */ ++ dev_kfree_skb_any(buf); ++#endif ++ ++ /* Allocate a skb buffer */ ++ new_buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); ++ ++ /* Enqueue skb buffer */ ++ zfLnxPutUsbRxBuffer(dev, new_buf); ++ ++ /* Submit a Rx urb */ ++ zfLnxUsbIn(dev, urb, new_buf); ++ ++#if ZM_USB_STREAM_MODE == 1 ++ for(ii = 0; ii < rxBufPoolIndex; ii++) ++ { ++ macp->usbCbFunctions.zfcbUsbRecv(dev, rxBufPool[ii]); ++ } ++#else ++ /* pass data to upper layer */ ++ macp->usbCbFunctions.zfcbUsbRecv(dev, buf); ++#endif ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++void zfLnxUsbRegOut_callback(urb_t *urb) ++#else ++void zfLnxUsbRegOut_callback(urb_t *urb, struct pt_regs *regs) ++#endif ++{ ++ //dev_t* dev = urb->context; ++ ++ //printk(KERN_ERR "zfwUsbRegOut_callback\n"); ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++void zfLnxUsbRegIn_callback(urb_t *urb) ++#else ++void zfLnxUsbRegIn_callback(urb_t *urb, struct pt_regs *regs) ++#endif ++{ ++ zdev_t* dev = urb->context; ++ u32_t rsp[64/4]; ++ int status; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ /* Check status for URB */ ++ if (urb->status != 0){ ++ printk("zfLnxUsbRegIn_callback() : status=0x%x\n", urb->status); ++ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET) ++ && (urb->status != -ESHUTDOWN)) ++ { ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ if (urb->status == USB_ST_INTERNALERROR) ++ status = -1; ++ #else ++ if (urb->status == -EPIPE){ ++ //printk(KERN_ERR "nonzero read bulk status received: -EPIPE"); ++ status = -1; ++ } ++ ++ if (urb->status == -EPROTO){ ++ //printk(KERN_ERR "nonzero read bulk status received: -EPROTO"); ++ status = -1; ++ } ++ #endif ++ } ++ ++ //printk(KERN_ERR "urb->status: 0x%08x\n", urb->status); ++ return; ++ } ++ ++ if (urb->actual_length == 0) ++ { ++ printk(KERN_ERR "Get an URB whose length is zero"); ++ status = -1; ++ } ++ ++ /* Copy data into respone buffer */ ++ memcpy(rsp, macp->regUsbReadBuf, urb->actual_length); ++ ++ /* Notify to upper layer */ ++ //zfIdlChkRsp(dev, rsp, (u16_t)urb->actual_length); ++ //zfiUsbRegIn(dev, rsp, (u16_t)urb->actual_length); ++ macp->usbCbFunctions.zfcbUsbRegIn(dev, rsp, (u16_t)urb->actual_length); ++ ++ /* Issue another USB IN URB */ ++ zfLnxSubmitRegInUrb(dev); ++} ++ ++u32_t zfLnxSubmitRegInUrb(zdev_t *dev) ++{ ++ u32_t ret; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ /* Submit a rx urb */ ++ //ret = zfLnxUsbSubmitBulkUrb(macp->RegInUrb, macp->udev, ++ // USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf, ++ // ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev); ++ //CWYang(-) ++ //if (ret != 0) ++ // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret); ++ ++ ret = zfLnxUsbSubmitIntUrb(macp->RegInUrb, macp->udev, ++ USB_REG_IN_PIPE, USB_DIR_IN, macp->regUsbReadBuf, ++ ZM_USB_REG_MAX_BUF_SIZE, zfLnxUsbRegIn_callback, dev, 1); ++ ++ return ret; ++} ++ ++u32_t zfLnxUsbSubmitTxData(zdev_t* dev) ++{ ++ u32_t i; ++ u32_t ret; ++ u16_t freeTxUrb; ++ u8_t *puTxBuf = NULL; ++ UsbTxQ_t *TxData; ++ int len = 0; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++#if ZM_USB_TX_STREAM_MODE == 1 ++ u8_t ii; ++ u16_t offset = 0; ++ u16_t usbTxAggCnt; ++ u16_t *pUsbTxHdr; ++ UsbTxQ_t *TxQPool[ZM_MAX_TX_AGGREGATE_NUM]; ++#endif ++ ++ /* First check whether there is a free URB */ ++ freeTxUrb = zfLnxGetFreeTxUrb(dev); ++ ++ /* If there is no any free Tx Urb */ ++ if (freeTxUrb == 0xffff) ++ { ++ //printk(KERN_ERR "Can't get free Tx Urb\n"); ++ //printk("CWY - Can't get free Tx Urb\n"); ++ return 0xffff; ++ } ++ ++#if ZM_USB_TX_STREAM_MODE == 1 ++ usbTxAggCnt = zfLnxCheckTxBufferCnt(dev); ++ ++ if (usbTxAggCnt >= ZM_MAX_TX_AGGREGATE_NUM) ++ { ++ usbTxAggCnt = ZM_MAX_TX_AGGREGATE_NUM; ++ } ++ else ++ { ++ usbTxAggCnt = 1; ++ } ++ ++ //printk("usbTxAggCnt: %d\n", usbTxAggCnt); ++#endif ++ ++#if ZM_USB_TX_STREAM_MODE == 1 ++ for(ii = 0; ii < usbTxAggCnt; ii++) ++ { ++#endif ++ /* Dequeue the packet from UsbTxBufQ */ ++ TxData = zfLnxGetUsbTxBuffer(dev); ++ if (TxData == NULL) ++ { ++ /* Give the urb back */ ++ zfLnxPutTxUrb(dev); ++ return 0xffff; ++ } ++ ++ /* Point to the freeTxUrb buffer */ ++ puTxBuf = macp->txUsbBuf[freeTxUrb]; ++ ++#if ZM_USB_TX_STREAM_MODE == 1 ++ puTxBuf += offset; ++ pUsbTxHdr = (u16_t *)puTxBuf; ++ ++ /* Add the packet length and tag information */ ++ *pUsbTxHdr++ = TxData->hdrlen + TxData->snapLen + ++ (TxData->buf->len - TxData->offset) + TxData->tailLen; ++ ++ *pUsbTxHdr++ = 0x697e; ++ ++ puTxBuf += 4; ++#endif // #ifdef ZM_USB_TX_STREAM_MODE ++ ++ /* Copy WLAN header and packet buffer into USB buffer */ ++ for(i = 0; i < TxData->hdrlen; i++) ++ { ++ *puTxBuf++ = TxData->hdr[i]; ++ } ++ ++ /* Copy SNAP header */ ++ for(i = 0; i < TxData->snapLen; i++) ++ { ++ *puTxBuf++ = TxData->snap[i]; ++ } ++ ++ /* Copy packet buffer */ ++ for(i = 0; i < TxData->buf->len - TxData->offset; i++) ++ { ++ //*puTxBuf++ = zmw_rx_buf_readb(dev, TxData->buf, i); ++ *puTxBuf++ = *(u8_t*)((u8_t*)TxData->buf->data+i+TxData->offset); ++ } ++ ++ /* Copy tail */ ++ for(i = 0; i < TxData->tailLen; i++) ++ { ++ *puTxBuf++ = TxData->tail[i]; ++ } ++ ++ len = TxData->hdrlen+TxData->snapLen+TxData->buf->len+TxData->tailLen-TxData->offset; ++ ++ #if 0 ++ if (TxData->hdrlen != 0) ++ { ++ puTxBuf = macp->txUsbBuf[freeTxUrb]; ++ for (i = 0; i < len; i++) ++ { ++ printk("%02x ", puTxBuf[i]); ++ if (i % 16 == 15) ++ printk("\n"); ++ } ++ printk("\n"); ++ } ++ #endif ++ #if 0 ++ /* For debug purpose */ ++ if(TxData->hdr[9] & 0x40) ++ { ++ int i; ++ u16_t ctrlLen = TxData->hdr[0] + (TxData->hdr[1] << 8); ++ ++ if (ctrlLen != len + 4) ++ { ++ /* Dump control setting */ ++ for(i = 0; i < 8; i++) ++ { ++ printk(KERN_ERR "0x%02x ", TxData->hdr[i]); ++ } ++ printk(KERN_ERR "\n"); ++ ++ printk(KERN_ERR "ctrLen: %d, hdrLen: %d, snapLen: %d\n", ctrlLen, TxData->hdrlen, TxData->snapLen); ++ printk(KERN_ERR "bufLen: %d, tailLen: %d, len: %d\n", TxData->buf->len, TxData->tailLen, len); ++ } ++ } ++ #endif ++ ++#if ZM_USB_TX_STREAM_MODE == 1 ++ // Add the Length and Tag ++ len += 4; ++ ++ //printk("%d packet, length: %d\n", ii+1, len); ++ ++ if (ii < (ZM_MAX_TX_AGGREGATE_NUM-1)) ++ { ++ /* Pad the buffer to firmware descriptor boundary */ ++ offset += (((len-1) / 4) + 1) * 4; ++ } ++ ++ if (ii == (ZM_MAX_TX_AGGREGATE_NUM-1)) ++ { ++ len += offset; ++ } ++ ++ TxQPool[ii] = TxData; ++ ++ //DbgPrint("%d packet, offset: %d\n", ii+1, pUsbTxTransfer->offset); ++ ++ /* free packet */ ++ //zfBufFree(dev, txData->buf); ++ } ++#endif ++ //printk("CWY - call zfwUsbSubmitBulkUrb(), len = 0x%d\n", len); ++ /* Submit a tx urb */ ++ ret = zfLnxUsbSubmitBulkUrb(macp->WlanTxDataUrb[freeTxUrb], macp->udev, ++ USB_WLAN_TX_PIPE, USB_DIR_OUT, macp->txUsbBuf[freeTxUrb], ++ len, zfLnxUsbDataOut_callback, dev); ++ //CWYang(-) ++ //if (ret != 0) ++ // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret); ++ ++ /* free packet */ ++ //dev_kfree_skb_any(TxData->buf); ++#if ZM_USB_TX_STREAM_MODE == 1 ++ for(ii = 0; ii < usbTxAggCnt; ii++) ++ macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxQPool[ii]->buf, 1, TxQPool[ii]->hdr); ++#else ++ macp->usbCbFunctions.zfcbUsbOutComplete(dev, TxData->buf, 1, TxData->hdr); ++#endif ++ ++ return ret; ++} ++ ++ ++ ++u32_t zfLnxUsbIn(zdev_t* dev, urb_t *urb, zbuf_t *buf) ++{ ++ u32_t ret; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ /* Submit a rx urb */ ++ ret = zfLnxUsbSubmitBulkUrb(urb, macp->udev, USB_WLAN_RX_PIPE, ++ USB_DIR_IN, buf->data, ZM_MAX_RX_BUFFER_SIZE, ++ zfLnxUsbDataIn_callback, dev); ++ //CWYang(-) ++ //if (ret != 0) ++ // printk("zfwUsbSubmitBulkUrb fail, status: 0x%08x\n", (int)ret); ++ ++ return ret; ++} ++ ++u32_t zfLnxUsbWriteReg(zdev_t* dev, u32_t* cmd, u16_t cmdLen) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ u32_t ret; ++ ++#ifdef ZM_CONFIG_BIG_ENDIAN ++ int ii = 0; ++ ++ for(ii=0; ii<(cmdLen>>2); ii++) ++ cmd[ii] = cpu_to_le32(cmd[ii]); ++#endif ++ ++ memcpy(macp->regUsbWriteBuf, cmd, cmdLen); ++ ++ /* Issue an USB Out transfer */ ++ /* Submit a tx urb */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ ret = zfLnxUsbSubmitBulkUrb(macp->RegOutUrb, macp->udev, ++ USB_REG_OUT_PIPE, USB_DIR_OUT, macp->regUsbWriteBuf, ++ cmdLen, zfLnxUsbRegOut_callback, dev); ++#else ++ ret = zfLnxUsbSubmitIntUrb(macp->RegOutUrb, macp->udev, ++ USB_REG_OUT_PIPE, USB_DIR_OUT, macp->regUsbWriteBuf, ++ cmdLen, zfLnxUsbRegOut_callback, dev, 1); ++#endif ++ ++ return ret; ++} ++ ++ ++u32_t zfLnxUsbOut(zdev_t* dev, u8_t *hdr, u16_t hdrlen, u8_t *snap, u16_t snapLen, ++ u8_t *tail, u16_t tailLen, zbuf_t *buf, u16_t offset) ++{ ++ u32_t ret; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ /* Check length of tail buffer */ ++ //zm_assert((tailLen <= 16)); ++ ++ /* Enqueue the packet into UsbTxBufQ */ ++ if (zfLnxPutUsbTxBuffer(dev, hdr, hdrlen, snap, snapLen, tail, tailLen, buf, offset) == 0xffff) ++ { ++ /* free packet */ ++ //printk("CWY - zfwPutUsbTxBuffer Error, free packet\n"); ++ //dev_kfree_skb_any(buf); ++ macp->usbCbFunctions.zfcbUsbOutComplete(dev, buf, 0, hdr); ++ return 0xffff; ++ } ++ ++ //return 0; ++ //printk("CWY - call zfwUsbSubmitTxData()\n"); ++ ret = zfLnxUsbSubmitTxData(dev); ++ return ret; ++} ++ ++void zfLnxInitUsbTxQ(zdev_t* dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ printk(KERN_ERR "zfwInitUsbTxQ\n"); ++ ++ /* Zero memory for UsbTxBufQ */ ++ memset(macp->UsbTxBufQ, 0, sizeof(UsbTxQ_t) * ZM_MAX_TX_URB_NUM); ++ ++ macp->TxBufHead = 0; ++ macp->TxBufTail = 0; ++ macp->TxUrbHead = 0; ++ macp->TxUrbTail = 0; ++ macp->TxUrbCnt = ZM_MAX_TX_URB_NUM; ++} ++ ++void zfLnxInitUsbRxQ(zdev_t* dev) ++{ ++ u16_t i; ++ zbuf_t *buf; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ /* Zero memory for UsbRxBufQ */ ++ memset(macp->UsbRxBufQ, 0, sizeof(zbuf_t *) * ZM_MAX_RX_URB_NUM); ++ ++ macp->RxBufHead = 0; ++ ++ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) ++ { ++ //buf = zfwBufAllocate(dev, ZM_MAX_RX_BUFFER_SIZE); ++ buf = dev_alloc_skb(ZM_MAX_RX_BUFFER_SIZE); ++ macp->UsbRxBufQ[i] = buf; ++ } ++ ++ //macp->RxBufTail = ZM_MAX_RX_URB_NUM - 1; ++ macp->RxBufTail = 0; ++ ++ /* Submit all Rx urbs */ ++ for (i = 0; i < ZM_MAX_RX_URB_NUM; i++) ++ { ++ zfLnxPutUsbRxBuffer(dev, macp->UsbRxBufQ[i]); ++ zfLnxUsbIn(dev, macp->WlanRxDataUrb[i], macp->UsbRxBufQ[i]); ++ } ++} ++ ++ ++ ++u32_t zfLnxUsbSubmitBulkUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, ++ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context) ++{ ++ u32_t ret; ++ ++ if(direction == USB_DIR_OUT) ++ { ++ usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, epnum), ++ transfer_buffer, buffer_length, complete, context); ++ ++ urb->transfer_flags |= URB_ZERO_PACKET; ++ } ++ else ++ { ++ usb_fill_bulk_urb(urb, usb, usb_rcvbulkpipe(usb, epnum), ++ transfer_buffer, buffer_length, complete, context); ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ urb->transfer_flags |= URB_ASYNC_UNLINK; ++#endif ++ ++ if (epnum == 4) ++ { ++ if (urb->hcpriv) ++ { ++ //printk("CWY - urb->hcpriv set by unknown reason, reset it\n"); ++ //urb->hcpriv = 0; ++ } ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ ret = usb_submit_urb(urb, GFP_ATOMIC); ++#else ++ ret = usb_submit_urb(urb); ++#endif ++ if ((epnum == 4) & (ret != 0)) ++ { ++ //printk("CWY - ret = %x\n", ret); ++ } ++ return ret; ++} ++ ++u32_t zfLnxUsbSubmitIntUrb(urb_t *urb, struct usb_device *usb, u16_t epnum, u16_t direction, ++ void *transfer_buffer, int buffer_length, usb_complete_t complete, void *context, ++ u32_t interval) ++{ ++ u32_t ret; ++ ++ if(direction == USB_DIR_OUT) ++ { ++ usb_fill_int_urb(urb, usb, usb_sndbulkpipe(usb, epnum), ++ transfer_buffer, buffer_length, complete, context, interval); ++ } ++ else ++ { ++ usb_fill_int_urb(urb, usb, usb_rcvbulkpipe(usb, epnum), ++ transfer_buffer, buffer_length, complete, context, interval); ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ urb->transfer_flags |= URB_ASYNC_UNLINK; ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ ret = usb_submit_urb(urb, GFP_ATOMIC); ++#else ++ ret = usb_submit_urb(urb); ++#endif ++ ++ return ret; ++} ++ ++#ifdef ZM_ENABLE_CENC ++int zfLnxCencSendMsg(struct sock *netlink_sk, u_int8_t *msg, int len) ++{ ++#define COMMTYPE_GROUP 8 ++#define WAI_K_MSG 0x11 ++ ++ int ret = -1; ++ int size; ++ unsigned char *old_tail; ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ char *pos = NULL; ++ ++ size = NLMSG_SPACE(len); ++ skb = alloc_skb(size, GFP_ATOMIC); ++ ++ if(skb == NULL) ++ { ++ printk("dev_alloc_skb failure \n"); ++ goto out; ++ } ++ old_tail = skb->tail; ++ ++ /*ÌîдÊý¾Ý±¨Ïà¹ØÐÅÏ¢*/ ++ nlh = NLMSG_PUT(skb, 0, 0, WAI_K_MSG, size-sizeof(*nlh)); ++ pos = NLMSG_DATA(nlh); ++ memset(pos, 0, len); ++ ++ /*´«Êäµ½Óû§¿Õ¼äµÄÊý¾Ý*/ ++ memcpy(pos, msg, len); ++ /*¼ÆËã¾­¹ý×Ö½Ú¶ÔÆäºóµÄÊý¾Ýʵ¼Ê³¤¶È*/ ++ nlh->nlmsg_len = skb->tail - old_tail; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ++ NETLINK_CB(skb).dst_groups = COMMTYPE_GROUP; ++#else ++ NETLINK_CB(skb).dst_group = COMMTYPE_GROUP; ++#endif ++ netlink_broadcast(netlink_sk, skb, 0, COMMTYPE_GROUP, GFP_ATOMIC); ++ ret = 0; ++out: ++ return ret; ++nlmsg_failure: /*NLMSG_PUT ʧ°Ü£¬Ôò³·ÏúÌ×½Ó×Ö»º´æ*/ ++ if(skb) ++ kfree_skb(skb); ++ goto out; ++ ++#undef COMMTYPE_GROUP ++#undef WAI_K_MSG ++} ++#endif //ZM_ENABLE_CENC ++ ++/* Simply return 0xffff if VAP function is not supported */ ++u16_t zfLnxGetVapId(zdev_t* dev) ++{ ++ u16_t i; ++ ++ for (i=0; i KERNEL_VERSION(2,6,20)) ++void kevent(struct work_struct *work) ++#else ++void kevent(void *data) ++#endif ++{ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) ++ struct usbdrv_private *macp = ++ container_of(work, struct usbdrv_private, kevent); ++ zdev_t *dev = macp->device; ++#else ++ zdev_t *dev = (zdev_t *) data; ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++#endif ++ ++ if (macp == NULL) ++ { ++ return; ++ } ++ ++ if (test_and_set_bit(0, (void *)&smp_kevent_Lock)) ++ { ++ //schedule_work(&macp->kevent); ++ return; ++ } ++ ++ down(&macp->ioctl_sem); ++ ++ if (test_and_clear_bit(KEVENT_WATCHDOG, &macp->kevent_flags)) ++ { ++ extern u16_t zfHpStartRecv(zdev_t *dev); ++ //zfiHwWatchDogReinit(dev); ++ printk(("\n ************ Hw watchDog occur!! ************** \n")); ++ zfiWlanSuspend(dev); ++ zfiWlanResume(dev,0); ++ zfHpStartRecv(dev); ++ } ++ ++ clear_bit(0, (void *)&smp_kevent_Lock); ++ up(&macp->ioctl_sem); ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfLnxCreateThread */ ++/* Create a Thread */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* */ ++/* OUTPUTS */ ++/* always 0 */ ++/* */ ++/* AUTHOR */ ++/* Yuan-Gu Wei Atheros Communications, INC. 2007.3 */ ++/* */ ++/************************************************************************/ ++u8_t zfLnxCreateThread(zdev_t *dev) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ /* Create Mutex and keventd */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++ INIT_WORK(&macp->kevent, kevent, dev); ++#else ++ INIT_WORK(&macp->kevent, kevent); ++#endif ++ init_MUTEX(&macp->ioctl_sem); ++ ++ return 0; ++} ++ ++/************************************************************************/ ++/* */ ++/* FUNCTION DESCRIPTION zfLnxSignalThread */ ++/* Signal Thread with Flag */ ++/* */ ++/* INPUTS */ ++/* dev : device pointer */ ++/* flag : signal thread flag */ ++/* */ ++/* OUTPUTS */ ++/* none */ ++/* */ ++/* AUTHOR */ ++/* Yuan-Gu Wei Atheros Communications, INC. 2007.3 */ ++/* */ ++/************************************************************************/ ++void zfLnxSignalThread(zdev_t *dev, int flag) ++{ ++ struct usbdrv_private *macp = (struct usbdrv_private *)dev->priv; ++ ++ if (macp == NULL) ++ { ++ printk("macp is NULL\n"); ++ return; ++ } ++ ++ if (0 && macp->kevent_ready != 1) ++ { ++ printk("Kevent not ready\n"); ++ return; ++ } ++ ++ set_bit(flag, &macp->kevent_flags); ++ ++ if (!schedule_work(&macp->kevent)) ++ { ++ //Fails is Normal ++ //printk(KERN_ERR "schedule_task failed, flag = %x\n", flag); ++ } ++} ++ ++/* Notify wrapper todo redownload firmware and reinit procedure when */ ++/* hardware watchdog occur : zfiHwWatchDogReinit() */ ++void zfLnxWatchDogNotify(zdev_t* dev) ++{ ++ zfLnxSignalThread(dev, KEVENT_WATCHDOG); ++} ++ ++/* Query Durantion of Active Scan */ ++void zfwGetActiveScanDur(zdev_t* dev, u8_t* Dur) ++{ ++ *Dur = 30; // default 30 ms ++} ++ ++void zfwGetShowZeroLengthSSID(zdev_t* dev, u8_t* Dur) ++{ ++ *Dur = 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/otus/zdcompat.h +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : zdcompat.h */ ++/* */ ++/* Abstract */ ++/* This module contains function defintion for compatibility. */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _ZDCOMPAT_H ++#define _ZDCOMPAT_H ++ ++#ifndef KERNEL_VERSION ++#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#ifndef INIT_TQUEUE ++#define INIT_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ (_tq)->next = NULL; \ ++ (_tq)->sync = 0; \ ++ PREPARE_TQUEUE((_tq), (_routine), (_data)); \ ++ } while (0) ++#define PREPARE_TQUEUE(_tq, _routine, _data) \ ++ do { \ ++ (_tq)->routine = _routine; \ ++ (_tq)->data = _data; \ ++ } while (0) ++#endif ++ ++#ifndef INIT_WORK ++#define work_struct tq_struct ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) ++#define schedule_work(a) queue_task(a, &tq_scheduler) ++#else ++#define schedule_work(a) schedule_task(a) ++#endif ++ ++#define flush_scheduled_work flush_scheduled_tasks ++#define INIT_WORK(_wq, _routine, _data) INIT_TQUEUE(_wq, _routine, _data) ++#define PREPARE_WORK(_wq, _routine, _data) PREPARE_TQUEUE(_wq, _routine, _data) ++#endif ++#endif // < 2.5 kernel ++ ++ ++#ifndef DECLARE_TASKLET ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) ++#define tasklet_schedule(a) queue_task(a, &tq_scheduler) ++#else ++#define tasklet_schedule(a) schedule_task(a) ++#endif ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38)) ++typedef struct device netdevice_t; ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)) ++typedef struct net_device netdevice_t; ++#else ++#undef netdevice_t ++typedef struct net_device netdevice_t; ++#endif ++ ++#ifdef WIRELESS_EXT ++#if (WIRELESS_EXT < 13) ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++#endif ++#endif ++ ++/* linux < 2.5.69 */ ++#ifndef IRQ_NONE ++typedef void irqreturn_t; ++#define IRQ_NONE ++#define IRQ_HANDLED ++#define IRQ_RETVAL(x) ++#endif ++ ++#ifndef in_atomic ++#define in_atomic() 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) // fixme ++#define URB_ASYNC_UNLINK USB_ASYNC_UNLINK ++#else ++#define USB_QUEUE_BULK 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) ++#define free_netdev(x) kfree(x) ++#endif ++ ++ ++#endif +--- /dev/null ++++ b/drivers/staging/otus/zdusb.c +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : zdusb.c */ ++/* */ ++/* Abstract */ ++/* This module contains plug and play handling for USB device driver*/ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#include ++#ifdef MODVERSIONS ++#include ++#endif ++ ++#include ++#include ++ ++#include "usbdrv.h" ++#include "zdusb.h" ++ ++int zfLnxAllocAllUrbs(struct usbdrv_private *macp); ++void zfLnxFreeAllUrbs(struct usbdrv_private *macp); ++void zfLnxUnlinkAllUrbs(struct usbdrv_private *macp); ++ ++MODULE_AUTHOR("Atheros Communications"); ++MODULE_DESCRIPTION("Atheros 802.11n Wireless LAN adapter"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++static const char driver_name[] = "Otus"; ++ ++/* table of devices that work with this driver */ ++static struct usb_device_id zd1221_ids [] = { ++ { USB_DEVICE(VENDOR_ATHR, PRODUCT_AR9170) }, ++ { USB_DEVICE(VENDOR_DLINK, PRODUCT_DWA160A) }, ++ { USB_DEVICE(0x0846, 0x9010) }, ++ { } /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, zd1221_ids); ++ ++extern u8_t zfLnxInitSetup(struct net_device *dev, struct usbdrv_private *macp); ++extern int usbdrv_close(struct net_device *dev); ++extern u8_t zfLnxClearStructs(struct net_device *dev); ++extern int zfWdsClose(struct net_device *dev); ++extern int zfUnregisterWdsDev(struct net_device* parentDev, u16_t wdsId); ++extern int zfLnxVapClose(struct net_device *dev); ++extern int zfLnxUnregisterVapDev(struct net_device* parentDev, u16_t vapId); ++ ++/* WDS */ ++extern struct zsWdsStruct wds[ZM_WDS_PORT_NUMBER]; ++ ++/* VAP */ ++extern struct zsVapStruct vap[ZM_VAP_PORT_NUMBER]; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++static void *zfLnxProbe(struct usb_device *dev, unsigned int ifnum, ++ const struct usb_device_id *id) ++{ ++ struct usb_interface *interface = &dev->actconfig->interface[ifnum]; ++#else ++static int zfLnxProbe(struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *dev = interface_to_usbdev(interface); ++#endif ++ ++ struct net_device *net = NULL; ++ struct usbdrv_private *macp = NULL; ++ int vendor_id, product_id; ++ int result = 0; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ usb_get_dev(dev); ++#endif ++ ++ vendor_id = dev->descriptor.idVendor; ++ product_id = dev->descriptor.idProduct; ++ ++#ifdef HMAC_DEBUG ++ printk(KERN_NOTICE "vendor_id = %04x\n", vendor_id); ++ printk(KERN_NOTICE "product_id = %04x\n", product_id); ++ ++ if (dev->speed == USB_SPEED_HIGH) ++ printk(KERN_NOTICE "USB 2.0 Host\n"); ++ else ++ printk(KERN_NOTICE "USB 1.1 Host\n"); ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) ++ { ++ printk(KERN_ERR "usb_set_configuration() failed\n"); ++ result = -EIO; ++ goto fail; ++ } ++#endif ++ ++ if (!(macp = kmalloc(sizeof(struct usbdrv_private), GFP_KERNEL))) ++ { ++ printk(KERN_ERR "out of memory allocating device structure\n"); ++ result = -ENOMEM; ++ goto fail; ++ } ++ ++ /* Zero the memory */ ++ memset(macp, 0, sizeof(struct usbdrv_private)); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ usb_inc_dev_use(dev); ++#endif ++ ++ net = alloc_etherdev(0); ++ ++ if (net == NULL) ++ { ++ printk(KERN_ERR "zfLnxProbe: Not able to alloc etherdev struct\n"); ++ result = -ENOMEM; ++ goto fail1; ++ } ++ ++ strcpy(net->name, "ath%d"); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ SET_MODULE_OWNER(net); ++#endif ++ ++ net->priv = macp; //kernel 2.6 ++ macp->udev = dev; ++ macp->device = net; ++ ++ /* set up the endpoint information */ ++ /* check out the endpoints */ ++ macp->interface = interface; ++ ++ //init_waitqueue_head(&macp->regSet_wait); ++ //init_waitqueue_head(&macp->iorwRsp_wait); ++ //init_waitqueue_head(&macp->term_wait); ++ ++ if (!zfLnxAllocAllUrbs(macp)) ++ { ++ result = -ENOMEM; ++ goto fail2; ++ } ++ ++ if (!zfLnxInitSetup(net, macp)) ++ { ++ result = -EIO; ++ goto fail3; ++ } ++ else ++ { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ usb_set_intfdata(interface, macp); ++ SET_NETDEV_DEV(net, &interface->dev); ++#endif ++ ++ if (register_netdev(net) != 0) ++ { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ usb_set_intfdata(interface, NULL); ++#endif ++ goto fail3; ++ } ++ } ++ ++ netif_carrier_off(net); ++ goto done; ++ ++fail3: ++ zfLnxFreeAllUrbs(macp); ++fail2: ++ free_netdev(net); //kernel 2.6 ++fail1: ++ kfree(macp); ++ ++fail: ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ usb_put_dev(dev); ++#endif ++ macp = NULL; ++ ++done: ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ return macp; ++#else ++ return result; ++#endif ++} ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++static void zfLnxDisconnect(struct usb_device *dev, void *ptr) ++#else ++static void zfLnxDisconnect(struct usb_interface *interface) ++#endif ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct usbdrv_private *macp = (struct usbdrv_private *) usb_get_intfdata(interface); ++#else ++ struct usbdrv_private *macp = (struct usbdrv_private *)ptr; ++#endif ++ ++ printk(KERN_DEBUG "zfLnxDisconnect\n"); ++ ++ if (!macp) ++ { ++ printk(KERN_ERR "unregistering non-existant device\n"); ++ return; ++ } ++ ++ if (macp->driver_isolated) ++ { ++ if (macp->device->flags & IFF_UP) ++ usbdrv_close(macp->device); ++ } ++ ++#if 0 ++ /* Close WDS */ ++ //zfWdsClose(wds[0].dev); ++ /* Unregister WDS */ ++ //zfUnregisterWdsDev(macp->device, 0); ++ ++ /* Close VAP */ ++ zfLnxVapClose(vap[0].dev); ++ /* Unregister VAP */ ++ zfLnxUnregisterVapDev(macp->device, 0); ++#endif ++ ++ zfLnxClearStructs(macp->device); ++ ++ unregister_netdev(macp->device); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ usb_dec_dev_use(dev); ++#else ++ usb_put_dev(interface_to_usbdev(interface)); ++#endif ++ ++ //printk(KERN_ERR "3. zfLnxUnlinkAllUrbs\n"); ++ //zfLnxUnlinkAllUrbs(macp); ++ ++ /* Free network interface */ ++ free_netdev(macp->device); ++ ++ zfLnxFreeAllUrbs(macp); ++ //zfLnxClearStructs(macp->device); ++ kfree(macp); ++ macp = NULL; ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ usb_set_intfdata(interface, NULL); ++#endif ++} ++ ++static struct usb_driver zd1221_driver = { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) ++ .owner = THIS_MODULE, ++ #endif ++#endif ++ .name = driver_name, ++ .probe = zfLnxProbe, ++ .disconnect = zfLnxDisconnect, ++ .id_table = zd1221_ids, ++}; ++ ++int __init zfLnxIinit(void) ++{ ++ printk(KERN_NOTICE "%s - version %s\n", DRIVER_NAME, VERSIONID); ++ return usb_register(&zd1221_driver); ++} ++ ++void __exit zfLnxExit(void) ++{ ++ usb_deregister(&zd1221_driver); ++} ++ ++module_init(zfLnxIinit); ++module_exit(zfLnxExit); +--- /dev/null ++++ b/drivers/staging/otus/zdusb.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2007-2008 Atheros Communications Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* */ ++/* Module Name : zdusb.h */ ++/* */ ++/* Abstract */ ++/* This module contains definitions for USB device driver */ ++/* */ ++/* NOTES */ ++/* Platform dependent. */ ++/* */ ++/************************************************************************/ ++ ++#ifndef _ZDUSB_H ++#define _ZDUSB_H ++ ++#ifndef DRIVER_NAME ++#define DRIVER_NAME "arusb" ++#endif ++ ++#define VERSIONID "0.0.0.999" ++ ++/* Define these values to match your device */ ++#define VENDOR_ATHR 0x0CF3 //Atheros ++#define PRODUCT_AR9170 0x9170 ++ ++#define VENDOR_DLINK 0x07D1 //Dlink ++#define PRODUCT_DWA160A 0x3C10 ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-realtek-8192-pci-wireless-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-realtek-8192-pci-wireless-driver.patch new file mode 100644 index 000000000..4e5ac76e0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-realtek-8192-pci-wireless-driver.patch @@ -0,0 +1,54619 @@ +From 182d8c60e20c48eadc68a1e83432dd0680b9e6cd Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Tue, 4 Aug 2009 15:57:55 -0700 +Subject: Staging: add Realtek 8192 PCI wireless driver +Patch-mainline: 2.6.32 +References: bnc#525903 + +From: Greg Kroah-Hartman + +This wireless driver should work for the Realtek 8192 PCI devices. + +It comes directly from Realtek and has been tested to work on at least +one laptop in the wild. + +Cc: Anthony Wong +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/rtl8192e/Kconfig | 6 + drivers/staging/rtl8192e/Makefile | 34 + drivers/staging/rtl8192e/dot11d.h | 102 + drivers/staging/rtl8192e/ieee80211.h | 2802 +++++ + drivers/staging/rtl8192e/ieee80211/EndianFree.h | 199 + drivers/staging/rtl8192e/ieee80211/aes.c | 469 + drivers/staging/rtl8192e/ieee80211/api.c | 246 + drivers/staging/rtl8192e/ieee80211/arc4.c | 103 + drivers/staging/rtl8192e/ieee80211/autoload.c | 40 + drivers/staging/rtl8192e/ieee80211/cipher.c | 299 + drivers/staging/rtl8192e/ieee80211/compress.c | 64 + drivers/staging/rtl8192e/ieee80211/crypto_compat.h | 90 + drivers/staging/rtl8192e/ieee80211/digest.c | 108 + drivers/staging/rtl8192e/ieee80211/dot11d.c | 239 + drivers/staging/rtl8192e/ieee80211/dot11d.h | 102 + drivers/staging/rtl8192e/ieee80211/ieee80211.h | 2802 +++++ + drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c | 273 + drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h | 93 + drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c | 534 + + drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c | 1034 ++ + drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c | 397 + drivers/staging/rtl8192e/ieee80211/ieee80211_module.c | 432 + drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c | 2802 +++++ + drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c | 3548 +++++++ + drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c | 692 + + drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c | 933 + + drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c | 1032 ++ + drivers/staging/rtl8192e/ieee80211/internal.h | 115 + drivers/staging/rtl8192e/ieee80211/kmap_types.h | 20 + drivers/staging/rtl8192e/ieee80211/michael_mic.c | 194 + drivers/staging/rtl8192e/ieee80211/proc.c | 116 + drivers/staging/rtl8192e/ieee80211/rtl819x_BA.h | 69 + drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c | 779 + + drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h | 481 + drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c | 1719 +++ + drivers/staging/rtl8192e/ieee80211/rtl819x_Qos.h | 749 + + drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h | 56 + drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c | 659 + + drivers/staging/rtl8192e/ieee80211/rtl_crypto.h | 399 + drivers/staging/rtl8192e/ieee80211/scatterwalk.c | 126 + drivers/staging/rtl8192e/ieee80211/scatterwalk.h | 51 + drivers/staging/rtl8192e/ieee80211_crypt.h | 86 + drivers/staging/rtl8192e/r8180_93cx6.c | 146 + drivers/staging/rtl8192e/r8180_93cx6.h | 40 + drivers/staging/rtl8192e/r8190_rtl8256.c | 1161 ++ + drivers/staging/rtl8192e/r8190_rtl8256.h | 28 + drivers/staging/rtl8192e/r8192E.h | 1554 +++ + drivers/staging/rtl8192e/r8192E_core.c | 6928 ++++++++++++++ + drivers/staging/rtl8192e/r8192E_dm.c | 4115 ++++++++ + drivers/staging/rtl8192e/r8192E_dm.h | 320 + drivers/staging/rtl8192e/r8192E_hw.h | 811 + + drivers/staging/rtl8192e/r8192E_wx.c | 1409 ++ + drivers/staging/rtl8192e/r8192E_wx.h | 22 + drivers/staging/rtl8192e/r8192_pm.c | 181 + drivers/staging/rtl8192e/r8192_pm.h | 28 + drivers/staging/rtl8192e/r819xE_cmdpkt.c | 820 + + drivers/staging/rtl8192e/r819xE_cmdpkt.h | 207 + drivers/staging/rtl8192e/r819xE_firmware.c | 620 + + drivers/staging/rtl8192e/r819xE_firmware.h | 68 + drivers/staging/rtl8192e/r819xE_firmware_img.h | 2778 +++++ + drivers/staging/rtl8192e/r819xE_phy.c | 3352 ++++++ + drivers/staging/rtl8192e/r819xE_phy.h | 125 + drivers/staging/rtl8192e/r819xE_phyreg.h | 878 + + drivers/staging/rtl8192e/r819xP_firmware_img.h | 3637 +++++++ + 66 files changed, 54325 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -57,6 +57,8 @@ source "drivers/staging/benet/Kconfig" + + source "drivers/staging/rtl8187se/Kconfig" + ++source "drivers/staging/rtl8192e/Kconfig" ++ + source "drivers/staging/hv/Kconfig" + + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -20,4 +20,5 @@ obj-$(CONFIG_RT2870) += rt2870/ + obj-$(CONFIG_RT3070) += rt3070/ + obj-$(CONFIG_BENET) += benet/ + obj-$(CONFIG_RTL8187SE) += rtl8187se/ ++obj-$(CONFIG_RTL8192E) += rtl8192e/ + obj-$(CONFIG_HYPERV) += hv/ +--- /dev/null ++++ b/drivers/staging/rtl8192e/Kconfig +@@ -0,0 +1,6 @@ ++config RTL8192E ++ tristate "RealTek RTL8192E Wireless LAN NIC driver" ++ depends on PCI ++ depends on WIRELESS_EXT ++ default N ++ ---help--- +--- /dev/null ++++ b/drivers/staging/rtl8192e/Makefile +@@ -0,0 +1,34 @@ ++NIC_SELECT = RTL8192E ++ ++ ++EXTRA_CFLAGS += -DRTL8192E ++EXTRA_CFLAGS += -std=gnu89 ++EXTRA_CFLAGS += -O2 ++EXTRA_CFLAGS += -DTHOMAS_TURBO ++EXTRA_CFLAGS += -DENABLE_DOT11D ++ ++r8192_pci-objs := \ ++ r8192E_core.o \ ++ r8180_93cx6.o \ ++ r8192E_wx.o \ ++ r8190_rtl8256.o \ ++ r819xE_phy.o \ ++ r819xE_firmware.o \ ++ r819xE_cmdpkt.o \ ++ r8192E_dm.o \ ++ ieee80211/ieee80211_rx.o \ ++ ieee80211/ieee80211_softmac.o \ ++ ieee80211/ieee80211_tx.o \ ++ ieee80211/ieee80211_wx.o \ ++ ieee80211/ieee80211_module.o \ ++ ieee80211/ieee80211_softmac_wx.o \ ++ ieee80211/rtl819x_HTProc.o \ ++ ieee80211/rtl819x_TSProc.o \ ++ ieee80211/rtl819x_BAProc.o \ ++ ieee80211/dot11d.o \ ++ ieee80211/ieee80211_crypt.o \ ++ ieee80211/ieee80211_crypt_tkip.o \ ++ ieee80211/ieee80211_crypt_ccmp.o \ ++ ieee80211/ieee80211_crypt_wep.o ++ ++obj-$(CONFIG_RTL8192E) += r8192_pci.o +--- /dev/null ++++ b/drivers/staging/rtl8192e/dot11d.h +@@ -0,0 +1,102 @@ ++#ifndef __INC_DOT11D_H ++#define __INC_DOT11D_H ++ ++#ifdef ENABLE_DOT11D ++#include "ieee80211.h" ++ ++//#define ENABLE_DOT11D ++ ++//#define DOT11D_MAX_CHNL_NUM 83 ++ ++typedef struct _CHNL_TXPOWER_TRIPLE { ++ u8 FirstChnl; ++ u8 NumChnls; ++ u8 MaxTxPowerInDbm; ++}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; ++ ++typedef enum _DOT11D_STATE { ++ DOT11D_STATE_NONE = 0, ++ DOT11D_STATE_LEARNED, ++ DOT11D_STATE_DONE, ++}DOT11D_STATE; ++ ++typedef struct _RT_DOT11D_INFO { ++ //DECLARE_RT_OBJECT(RT_DOT11D_INFO); ++ ++ bool bEnabled; // dot11MultiDomainCapabilityEnabled ++ ++ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. ++ u8 CountryIeBuf[MAX_IE_LEN]; ++ u8 CountryIeSrcAddr[6]; // Source AP of the country IE. ++ u8 CountryIeWatchdog; ++ ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) ++ //u8 ChnlListLen; // #Bytes valid in ChnlList[]. ++ //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; ++ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; ++ ++ DOT11D_STATE State; ++}RT_DOT11D_INFO, *PRT_DOT11D_INFO; ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) ++#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) ++ ++#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled ++#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) ++ ++#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++ ++#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ ++ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ ++ FALSE : \ ++ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) ++ ++#define CIE_WATCHDOG_TH 1 ++#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog ++#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 ++#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) ++ ++#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) ++ ++ ++void ++Dot11d_Init( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_Reset( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_UpdateCountryIe( ++ struct ieee80211_device *dev, ++ u8 * pTaddr, ++ u16 CoutryIeLen, ++ u8 * pCoutryIe ++ ); ++ ++u8 ++DOT11D_GetMaxTxPwrInDbm( ++ struct ieee80211_device *dev, ++ u8 Channel ++ ); ++ ++void ++DOT11D_ScanComplete( ++ struct ieee80211_device * dev ++ ); ++ ++int IsLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++ ++int ToLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++#endif //ENABLE_DOT11D ++#endif // #ifndef __INC_DOT11D_H +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211.h +@@ -0,0 +1,2802 @@ ++/* ++ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 ++ * remains copyright by the original authors ++ * ++ * Portions of the merged code are based on Host AP (software wireless ++ * LAN access point) driver for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * Modified for Realtek's wi-fi cards by Andrea Merello ++ * ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++#ifndef IEEE80211_H ++#define IEEE80211_H ++#include /* ETH_ALEN */ ++#include /* ARRAY_SIZE */ ++#include ++#include ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++#include ++#else ++#include ++#include ++#endif ++#include ++#include ++ ++#include ++#include ++ ++#include "ieee80211/rtl819x_HT.h" ++#include "ieee80211/rtl819x_BA.h" ++#include "ieee80211/rtl819x_TS.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#ifndef bool ++typedef enum{false = 0, true} bool; ++#endif ++#endif ++ ++#ifndef IW_MODE_MONITOR ++#define IW_MODE_MONITOR 6 ++#endif ++ ++#ifndef IWEVCUSTOM ++#define IWEVCUSTOM 0x8c02 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#ifndef __bitwise ++#define __bitwise __attribute__((bitwise)) ++#endif ++typedef __u16 __le16; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)) ++struct iw_spy_data{ ++ /* --- Standard spy support --- */ ++ int spy_number; ++ u_char spy_address[IW_MAX_SPY][ETH_ALEN]; ++ struct iw_quality spy_stat[IW_MAX_SPY]; ++ /* --- Enhanced spy support (event) */ ++ struct iw_quality spy_thr_low; /* Low threshold */ ++ struct iw_quality spy_thr_high; /* High threshold */ ++ u_char spy_thr_under[IW_MAX_SPY]; ++}; ++#endif ++#endif ++ ++#ifndef container_of ++/** ++ * container_of - cast a member of a structure out to the containing structure ++ * ++ * @ptr: the pointer to the member. ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ * ++ */ ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++#endif ++ ++#define KEY_TYPE_NA 0x0 ++#define KEY_TYPE_WEP40 0x1 ++#define KEY_TYPE_TKIP 0x2 ++#define KEY_TYPE_CCMP 0x4 ++#define KEY_TYPE_WEP104 0x5 ++ ++/* added for rtl819x tx procedure */ ++#define MAX_QUEUE_SIZE 0x10 ++ ++// ++// 8190 queue mapping ++// ++#define BK_QUEUE 0 ++#define BE_QUEUE 1 ++#define VI_QUEUE 2 ++#define VO_QUEUE 3 ++#define HCCA_QUEUE 4 ++#define TXCMD_QUEUE 5 ++#define MGNT_QUEUE 6 ++#define HIGH_QUEUE 7 ++#define BEACON_QUEUE 8 ++ ++#define LOW_QUEUE BE_QUEUE ++#define NORMAL_QUEUE MGNT_QUEUE ++ ++//added by amy for ps ++#define SWRF_TIMEOUT 50 ++ ++//added by amy for LEAP related ++#define IE_CISCO_FLAG_POSITION 0x08 // Flag byte: byte 8, numbered from 0. ++#define SUPPORT_CKIP_MIC 0x08 // bit3 ++#define SUPPORT_CKIP_PK 0x10 // bit4 ++/* defined for skb cb field */ ++/* At most 28 byte */ ++typedef struct cb_desc { ++ /* Tx Desc Related flags (8-9) */ ++ u8 bLastIniPkt:1; ++ u8 bCmdOrInit:1; ++ u8 bFirstSeg:1; ++ u8 bLastSeg:1; ++ u8 bEncrypt:1; ++ u8 bTxDisableRateFallBack:1; ++ u8 bTxUseDriverAssingedRate:1; ++ u8 bHwSec:1; //indicate whether use Hw security. WB ++ ++ u8 reserved1; ++ ++ /* Tx Firmware Relaged flags (10-11)*/ ++ u8 bCTSEnable:1; ++ u8 bRTSEnable:1; ++ u8 bUseShortGI:1; ++ u8 bUseShortPreamble:1; ++ u8 bTxEnableFwCalcDur:1; ++ u8 bAMPDUEnable:1; ++ u8 bRTSSTBC:1; ++ u8 RTSSC:1; ++ ++ u8 bRTSBW:1; ++ u8 bPacketBW:1; ++ u8 bRTSUseShortPreamble:1; ++ u8 bRTSUseShortGI:1; ++ u8 bMulticast:1; ++ u8 bBroadcast:1; ++ //u8 reserved2:2; ++ u8 drv_agg_enable:1; ++ u8 reserved2:1; ++ ++ /* Tx Desc related element(12-19) */ ++ u8 rata_index; ++ u8 queue_index; ++ //u8 reserved3; ++ //u8 reserved4; ++ u16 txbuf_size; ++ //u8 reserved5; ++ u8 RATRIndex; ++ u8 reserved6; ++ u8 reserved7; ++ u8 reserved8; ++ ++ /* Tx firmware related element(20-27) */ ++ u8 data_rate; ++ u8 rts_rate; ++ u8 ampdu_factor; ++ u8 ampdu_density; ++ //u8 reserved9; ++ //u8 reserved10; ++ //u8 reserved11; ++ u8 DrvAggrNum; ++ u16 pkt_size; ++ u8 reserved12; ++}cb_desc, *pcb_desc; ++ ++/*--------------------------Define -------------------------------------------*/ ++#define MGN_1M 0x02 ++#define MGN_2M 0x04 ++#define MGN_5_5M 0x0b ++#define MGN_11M 0x16 ++ ++#define MGN_6M 0x0c ++#define MGN_9M 0x12 ++#define MGN_12M 0x18 ++#define MGN_18M 0x24 ++#define MGN_24M 0x30 ++#define MGN_36M 0x48 ++#define MGN_48M 0x60 ++#define MGN_54M 0x6c ++ ++#define MGN_MCS0 0x80 ++#define MGN_MCS1 0x81 ++#define MGN_MCS2 0x82 ++#define MGN_MCS3 0x83 ++#define MGN_MCS4 0x84 ++#define MGN_MCS5 0x85 ++#define MGN_MCS6 0x86 ++#define MGN_MCS7 0x87 ++#define MGN_MCS8 0x88 ++#define MGN_MCS9 0x89 ++#define MGN_MCS10 0x8a ++#define MGN_MCS11 0x8b ++#define MGN_MCS12 0x8c ++#define MGN_MCS13 0x8d ++#define MGN_MCS14 0x8e ++#define MGN_MCS15 0x8f ++ ++//---------------------------------------------------------------------------- ++// 802.11 Management frame Reason Code field ++//---------------------------------------------------------------------------- ++enum _ReasonCode{ ++ unspec_reason = 0x1, ++ auth_not_valid = 0x2, ++ deauth_lv_ss = 0x3, ++ inactivity = 0x4, ++ ap_overload = 0x5, ++ class2_err = 0x6, ++ class3_err = 0x7, ++ disas_lv_ss = 0x8, ++ asoc_not_auth = 0x9, ++ ++ //----MIC_CHECK ++ mic_failure = 0xe, ++ //----END MIC_CHECK ++ ++ // Reason code defined in 802.11i D10.0 p.28. ++ invalid_IE = 0x0d, ++ four_way_tmout = 0x0f, ++ two_way_tmout = 0x10, ++ IE_dismatch = 0x11, ++ invalid_Gcipher = 0x12, ++ invalid_Pcipher = 0x13, ++ invalid_AKMP = 0x14, ++ unsup_RSNIEver = 0x15, ++ invalid_RSNIE = 0x16, ++ auth_802_1x_fail= 0x17, ++ ciper_reject = 0x18, ++ ++ // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. ++ QoS_unspec = 0x20, // 32 ++ QAP_bandwidth = 0x21, // 33 ++ poor_condition = 0x22, // 34 ++ no_facility = 0x23, // 35 ++ // Where is 36??? ++ req_declined = 0x25, // 37 ++ invalid_param = 0x26, // 38 ++ req_not_honored= 0x27, // 39 ++ TS_not_created = 0x2F, // 47 ++ DL_not_allowed = 0x30, // 48 ++ dest_not_exist = 0x31, // 49 ++ dest_not_QSTA = 0x32, // 50 ++}; ++ ++ ++ ++#define aSifsTime (((priv->ieee80211->current_network.mode == IEEE_A)||(priv->ieee80211->current_network.mode == IEEE_N_24G)||(priv->ieee80211->current_network.mode == IEEE_N_5G))? 16 : 10) ++ ++#define MGMT_QUEUE_NUM 5 ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++//It should consistent with the driver_XXX.c ++// David, 2006.9.26 ++#define IEEE_PARAM_WPAX_SELECT 7 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_PROTO_WPA 1 ++#define IEEE_PROTO_RSN 2 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_WPAX_USEGROUP 0 ++#define IEEE_WPAX_WEP40 1 ++#define IEEE_WPAX_TKIP 2 ++#define IEEE_WPAX_WRAP 3 ++#define IEEE_WPAX_CCMP 4 ++#define IEEE_WPAX_WEP104 5 ++ ++#define IEEE_KEY_MGMT_IEEE8021X 1 ++#define IEEE_KEY_MGMT_PSK 2 ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++#define MAX_IE_LEN 0xff ++ ++// added for kernel conflict ++#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rsl ++#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rsl ++#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rsl ++#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rsl ++#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rsl ++#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rsl ++ ++#define ieee80211_ccmp_null ieee80211_ccmp_null_rsl ++ ++#define ieee80211_tkip_null ieee80211_tkip_null_rsl ++ ++#define ieee80211_wep_null ieee80211_wep_null_rsl ++ ++#define free_ieee80211 free_ieee80211_rsl ++#define alloc_ieee80211 alloc_ieee80211_rsl ++ ++#define ieee80211_rx ieee80211_rx_rsl ++#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl ++ ++#define ieee80211_get_beacon ieee80211_get_beacon_rsl ++#define ieee80211_wake_queue ieee80211_wake_queue_rsl ++#define ieee80211_stop_queue ieee80211_stop_queue_rsl ++#define ieee80211_reset_queue ieee80211_reset_queue_rsl ++#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl ++#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl ++#define ieee80211_is_shortslot ieee80211_is_shortslot_rsl ++#define ieee80211_is_54g ieee80211_is_54g_rsl ++#define ieee80211_wpa_supplicant_ioctl ieee80211_wpa_supplicant_ioctl_rsl ++#define ieee80211_ps_tx_ack ieee80211_ps_tx_ack_rsl ++#define ieee80211_softmac_xmit ieee80211_softmac_xmit_rsl ++#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rsl ++#define notify_wx_assoc_event notify_wx_assoc_event_rsl ++#define SendDisassociation SendDisassociation_rsl ++#define ieee80211_disassociate ieee80211_disassociate_rsl ++#define ieee80211_start_send_beacons ieee80211_start_send_beacons_rsl ++#define ieee80211_stop_scan ieee80211_stop_scan_rsl ++#define ieee80211_send_probe_requests ieee80211_send_probe_requests_rsl ++#define ieee80211_softmac_scan_syncro ieee80211_softmac_scan_syncro_rsl ++#define ieee80211_start_scan_syncro ieee80211_start_scan_syncro_rsl ++ ++#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rsl ++#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rsl ++#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rsl ++#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rsl ++#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rsl ++#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rsl ++#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rsl ++#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rsl ++#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rsl ++#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rsl ++#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rsl ++#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rsl ++#define ieee80211_wx_get_name ieee80211_wx_get_name_rsl ++#define ieee80211_wx_set_power ieee80211_wx_set_power_rsl ++#define ieee80211_wx_get_power ieee80211_wx_get_power_rsl ++#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rsl ++#define ieee80211_wx_set_rts ieee80211_wx_set_rts_rsl ++#define ieee80211_wx_get_rts ieee80211_wx_get_rts_rsl ++ ++#define ieee80211_txb_free ieee80211_txb_free_rsl ++ ++#define ieee80211_wx_set_gen_ie ieee80211_wx_set_gen_ie_rsl ++#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rsl ++#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rsl ++#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rsl ++#if WIRELESS_EXT >= 18 ++#define ieee80211_wx_set_mlme ieee80211_wx_set_mlme_rsl ++#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rsl ++#define ieee80211_wx_set_encode_ext ieee80211_wx_set_encode_ext_rsl ++#define ieee80211_wx_get_encode_ext ieee80211_wx_get_encode_ext_rsl ++#endif ++ ++ ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ } u; ++}ieee_param; ++ ++ ++#if WIRELESS_EXT < 17 ++#define IW_QUAL_QUAL_INVALID 0x10 ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#define IW_QUAL_QUAL_UPDATED 0x1 ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++static inline void tq_init(struct tq_struct * task, void(*func)(void *), void *data) ++{ ++ task->routine = func; ++ task->data = data; ++ //task->next = NULL; ++ INIT_LIST_HEAD(&task->list); ++ task->sync = 0; ++} ++#endif ++ ++// linux under 2.6.9 release may not support it, so modify it for common use ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) ++//#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) ++#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) ++static inline unsigned long msleep_interruptible_rsl(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++ return timeout; ++} ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31)) ++static inline void msleep(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++} ++#endif ++#else ++#define MSECS(t) msecs_to_jiffies(t) ++#define msleep_interruptible_rsl msleep_interruptible ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++#define IEEE80211_1ADDR_LEN 10 ++#define IEEE80211_2ADDR_LEN 16 ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++ ++/* Frame control field constants */ ++#define IEEE80211_FCTL_VERS 0x0003 ++#define IEEE80211_FCTL_FTYPE 0x000c ++#define IEEE80211_FCTL_STYPE 0x00f0 ++#define IEEE80211_FCTL_FRAMETYPE 0x00fc ++#define IEEE80211_FCTL_TODS 0x0100 ++#define IEEE80211_FCTL_FROMDS 0x0200 ++#define IEEE80211_FCTL_DSTODS 0x0300 //added by david ++#define IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define IEEE80211_FCTL_RETRY 0x0800 ++#define IEEE80211_FCTL_PM 0x1000 ++#define IEEE80211_FCTL_MOREDATA 0x2000 ++#define IEEE80211_FCTL_WEP 0x4000 ++#define IEEE80211_FCTL_ORDER 0x8000 ++ ++#define IEEE80211_FTYPE_MGMT 0x0000 ++#define IEEE80211_FTYPE_CTL 0x0004 ++#define IEEE80211_FTYPE_DATA 0x0008 ++ ++/* management */ ++#define IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define IEEE80211_STYPE_BEACON 0x0080 ++#define IEEE80211_STYPE_ATIM 0x0090 ++#define IEEE80211_STYPE_DISASSOC 0x00A0 ++#define IEEE80211_STYPE_AUTH 0x00B0 ++#define IEEE80211_STYPE_DEAUTH 0x00C0 ++#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 ++ ++/* control */ ++#define IEEE80211_STYPE_PSPOLL 0x00A0 ++#define IEEE80211_STYPE_RTS 0x00B0 ++#define IEEE80211_STYPE_CTS 0x00C0 ++#define IEEE80211_STYPE_ACK 0x00D0 ++#define IEEE80211_STYPE_CFEND 0x00E0 ++#define IEEE80211_STYPE_CFENDACK 0x00F0 ++#define IEEE80211_STYPE_BLOCKACK 0x0094 ++ ++/* data */ ++#define IEEE80211_STYPE_DATA 0x0000 ++#define IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define IEEE80211_STYPE_NULLFUNC 0x0040 ++#define IEEE80211_STYPE_CFACK 0x0050 ++#define IEEE80211_STYPE_CFPOLL 0x0060 ++#define IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 ++#define IEEE80211_STYPE_QOS_NULL 0x00C0 ++ ++#define IEEE80211_SCTL_FRAG 0x000F ++#define IEEE80211_SCTL_SEQ 0xFFF0 ++ ++/* QOS control */ ++#define IEEE80211_QCTL_TID 0x000F ++ ++#define FC_QOS_BIT BIT7 ++#define IsDataFrame(pdu) ( ((pdu[0] & 0x0C)==0x08) ? true : false ) ++#define IsLegacyDataFrame(pdu) (IsDataFrame(pdu) && (!(pdu[0]&FC_QOS_BIT)) ) ++//added by wb. Is this right? ++#define IsQoSDataFrame(pframe) ((*(u16*)pframe&(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) == (IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) ++#define Frame_Order(pframe) (*(u16*)pframe&IEEE80211_FCTL_ORDER) ++#define SN_LESS(a, b) (((a-b)&0x800)!=0) ++#define SN_EQUAL(a, b) (a == b) ++#define MAX_DEV_ADDR_SIZE 8 ++typedef enum _ACT_CATEGORY{ ++ ACT_CAT_QOS = 1, ++ ACT_CAT_DLS = 2, ++ ACT_CAT_BA = 3, ++ ACT_CAT_HT = 7, ++ ACT_CAT_WMM = 17, ++} ACT_CATEGORY, *PACT_CATEGORY; ++ ++typedef enum _TS_ACTION{ ++ ACT_ADDTSREQ = 0, ++ ACT_ADDTSRSP = 1, ++ ACT_DELTS = 2, ++ ACT_SCHEDULE = 3, ++} TS_ACTION, *PTS_ACTION; ++ ++typedef enum _BA_ACTION{ ++ ACT_ADDBAREQ = 0, ++ ACT_ADDBARSP = 1, ++ ACT_DELBA = 2, ++} BA_ACTION, *PBA_ACTION; ++ ++typedef enum _InitialGainOpType{ ++ IG_Backup=0, ++ IG_Restore, ++ IG_Max ++}InitialGainOpType; ++ ++/* debug macros */ ++#define CONFIG_IEEE80211_DEBUG ++#ifdef CONFIG_IEEE80211_DEBUG ++extern u32 ieee80211_debug_level; ++#define IEEE80211_DEBUG(level, fmt, args...) \ ++do { if (ieee80211_debug_level & (level)) \ ++ printk(KERN_DEBUG "ieee80211: " fmt, ## args); } while (0) ++//wb added to debug out data buf ++//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA ++#define IEEE80211_DEBUG_DATA(level, data, datalen) \ ++ do{ if ((ieee80211_debug_level & (level)) == (level)) \ ++ { \ ++ int i; \ ++ u8* pdata = (u8*) data; \ ++ printk(KERN_DEBUG "ieee80211: %s()\n", __FUNCTION__); \ ++ for(i=0; i<(int)(datalen); i++) \ ++ { \ ++ printk("%2x ", pdata[i]); \ ++ if ((i+1)%16 == 0) printk("\n"); \ ++ } \ ++ printk("\n"); \ ++ } \ ++ } while (0) ++#else ++#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) ++#define IEEE80211_DEBUG_DATA(level, data, datalen) do {} while(0) ++#endif /* CONFIG_IEEE80211_DEBUG */ ++ ++/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ ++ ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++ ++/* ++ * To use the debug system; ++ * ++ * If you are defining a new debug classification, simply add it to the #define ++ * list here in the form of: ++ * ++ * #define IEEE80211_DL_xxxx VALUE ++ * ++ * shifting value to the left one bit from the previous entry. xxxx should be ++ * the name of the classification (for example, WEP) ++ * ++ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your ++ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want ++ * to send output to that classification. ++ * ++ * To add your debug level to the list of levels seen when you perform ++ * ++ * % cat /proc/net/ipw/debug_level ++ * ++ * you simply need to add your entry to the ipw_debug_levels array. ++ * ++ * If you do not see debug_level in /proc/net/ipw then you do not have ++ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration ++ * ++ */ ++ ++#define IEEE80211_DL_INFO (1<<0) ++#define IEEE80211_DL_WX (1<<1) ++#define IEEE80211_DL_SCAN (1<<2) ++#define IEEE80211_DL_STATE (1<<3) ++#define IEEE80211_DL_MGMT (1<<4) ++#define IEEE80211_DL_FRAG (1<<5) ++#define IEEE80211_DL_EAP (1<<6) ++#define IEEE80211_DL_DROP (1<<7) ++ ++#define IEEE80211_DL_TX (1<<8) ++#define IEEE80211_DL_RX (1<<9) ++ ++#define IEEE80211_DL_HT (1<<10) //HT ++#define IEEE80211_DL_BA (1<<11) //ba ++#define IEEE80211_DL_TS (1<<12) //TS ++#define IEEE80211_DL_QOS (1<<13) ++#define IEEE80211_DL_REORDER (1<<14) ++#define IEEE80211_DL_IOT (1<<15) ++#define IEEE80211_DL_IPS (1<<16) ++#define IEEE80211_DL_TRACE (1<<29) //trace function, need to user net_ratelimit() together in order not to print too much to the screen ++#define IEEE80211_DL_DATA (1<<30) //use this flag to control whether print data buf out. ++#define IEEE80211_DL_ERR (1<<31) //always open ++#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) ++#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) ++#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) ++ ++#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) ++#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) ++#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) ++#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) ++#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) ++#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) ++#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) ++#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) ++#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) ++#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++/* Added by Annie, 2005-11-22. */ ++#define MAX_STR_LEN 64 ++/* I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22.*/ ++#define PRINTABLE(_ch) (_ch>'!' && _ch<'~') ++#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) \ ++ if((_Comp) & level) \ ++ { \ ++ int __i; \ ++ u8 buffer[MAX_STR_LEN]; \ ++ int length = (_Len\n", _Len, buffer); \ ++ } ++#else ++#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) do {} while (0) ++#endif ++ ++#include ++#include /* ARPHRD_ETHER */ ++ ++#ifndef WIRELESS_SPY ++#define WIRELESS_SPY // enable iwspy support ++#endif ++#include // new driver API ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++} __attribute__ ((packed)); ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) ++#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) ++ ++#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & IEEE80211_FCTL_FRAMETYPE) ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++#define WLAN_AUTH_LEAP 2 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) ++#define WLAN_CAPABILITY_QOS (1<<9) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) ++ ++/* 802.11g ERP information element */ ++#define WLAN_ERP_NON_ERP_PRESENT (1<<0) ++#define WLAN_ERP_USE_PROTECTION (1<<1) ++#define WLAN_ERP_BARKER_PREAMBLE (1<<2) ++ ++/* Status codes */ ++enum ieee80211_statuscode { ++ WLAN_STATUS_SUCCESS = 0, ++ WLAN_STATUS_UNSPECIFIED_FAILURE = 1, ++ WLAN_STATUS_CAPS_UNSUPPORTED = 10, ++ WLAN_STATUS_REASSOC_NO_ASSOC = 11, ++ WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, ++ WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, ++ WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, ++ WLAN_STATUS_CHALLENGE_FAIL = 15, ++ WLAN_STATUS_AUTH_TIMEOUT = 16, ++ WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, ++ WLAN_STATUS_ASSOC_DENIED_RATES = 18, ++ /* 802.11b */ ++ WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, ++ WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, ++ WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, ++ /* 802.11h */ ++ WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, ++ WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, ++ WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, ++ /* 802.11g */ ++ WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, ++ WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, ++ /* 802.11i */ ++ WLAN_STATUS_INVALID_IE = 40, ++ WLAN_STATUS_INVALID_GROUP_CIPHER = 41, ++ WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, ++ WLAN_STATUS_INVALID_AKMP = 43, ++ WLAN_STATUS_UNSUPP_RSN_VERSION = 44, ++ WLAN_STATUS_INVALID_RSN_IE_CAP = 45, ++ WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, ++}; ++ ++/* Reason codes */ ++enum ieee80211_reasoncode { ++ WLAN_REASON_UNSPECIFIED = 1, ++ WLAN_REASON_PREV_AUTH_NOT_VALID = 2, ++ WLAN_REASON_DEAUTH_LEAVING = 3, ++ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, ++ WLAN_REASON_DISASSOC_AP_BUSY = 5, ++ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, ++ WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, ++ WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, ++ /* 802.11h */ ++ WLAN_REASON_DISASSOC_BAD_POWER = 10, ++ WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, ++ /* 802.11i */ ++ WLAN_REASON_INVALID_IE = 13, ++ WLAN_REASON_MIC_FAILURE = 14, ++ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, ++ WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, ++ WLAN_REASON_IE_DIFFERENT = 17, ++ WLAN_REASON_INVALID_GROUP_CIPHER = 18, ++ WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, ++ WLAN_REASON_INVALID_AKMP = 20, ++ WLAN_REASON_UNSUPP_RSN_VERSION = 21, ++ WLAN_REASON_INVALID_RSN_IE_CAP = 22, ++ WLAN_REASON_IEEE8021X_FAILED = 23, ++ WLAN_REASON_CIPHER_SUITE_REJECTED = 24, ++}; ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++ ++/* this is stolen and modified from the madwifi driver*/ ++#define IEEE80211_FC0_TYPE_MASK 0x0c ++#define IEEE80211_FC0_TYPE_DATA 0x08 ++#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 ++#define IEEE80211_FC0_SUBTYPE_QOS 0x80 ++ ++#define IEEE80211_QOS_HAS_SEQ(fc) \ ++ (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ ++ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num[17]; ++ u16 frag_num[17]; ++ unsigned long packet_time[17]; ++ struct list_head list; ++}; ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++#if 1 ++ u32 mac_time[2]; ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u16 rate; /* in 100 kbps */ ++ u8 received_channel; ++ u8 control; ++ u8 mask; ++ u8 freq; ++ u16 len; ++ u64 tsf; ++ u32 beacon_time; ++ u8 nic_type; ++ u16 Length; ++ // u8 DataRate; // In 0.5 Mbps ++ u8 SignalQuality; // in 0-100 index. ++ s32 RecvSignalPower; // Real power in dBm for this packet, no beautification and aggregation. ++ s8 RxPower; // in dBm Translate from PWdB ++ u8 SignalStrength; // in 0-100 index. ++ u16 bHwError:1; ++ u16 bCRC:1; ++ u16 bICV:1; ++ u16 bShortPreamble:1; ++ u16 Antenna:1; //for rtl8185 ++ u16 Decrypted:1; //for rtl8185, rtl8187 ++ u16 Wakeup:1; //for rtl8185 ++ u16 Reserved0:1; //for rtl8185 ++ u8 AGC; ++ u32 TimeStampLow; ++ u32 TimeStampHigh; ++ bool bShift; ++ bool bIsQosData; // Added by Annie, 2005-12-22. ++ u8 UserPriority; ++ ++ //1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ //1Attention Please!!!<11n or 8190 specific code should be put below this line> ++ //1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ ++ u8 RxDrvInfoSize; ++ u8 RxBufShift; ++ bool bIsAMPDU; ++ bool bFirstMPDU; ++ bool bContainHTC; ++ bool RxIs40MHzPacket; ++ u32 RxPWDBAll; ++ u8 RxMIMOSignalStrength[4]; // in 0~100 index ++ s8 RxMIMOSignalQuality[2]; ++ bool bPacketMatchBSSID; ++ bool bIsCCK; ++ bool bPacketToSelf; ++ //added by amy ++ u8* virtual_address; ++ u16 packetlength; // Total packet length: Must equal to sum of all FragLength ++ u16 fraglength; // FragLength should equal to PacketLength in non-fragment case ++ u16 fragoffset; // Data offset for this fragment ++ u16 ntotalfrag; ++ bool bisrxaggrsubframe; ++ bool bPacketBeacon; //cosa add for rssi ++ bool bToSelfBA; //cosa add for rssi ++ char cck_adc_pwdb[4]; //cosa add for rx path selection ++ u16 Seq_Num; ++#endif ++ ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ unsigned long first_frag_time; ++ unsigned int seq; ++ unsigned int last_frag; ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ unsigned int tx_unicast_frames; ++ unsigned int tx_multicast_frames; ++ unsigned int tx_fragments; ++ unsigned int tx_unicast_octets; ++ unsigned int tx_multicast_octets; ++ unsigned int tx_deferred_transmissions; ++ unsigned int tx_single_retry_frames; ++ unsigned int tx_multiple_retry_frames; ++ unsigned int tx_retry_limit_exceeded; ++ unsigned int tx_discards; ++ unsigned int rx_unicast_frames; ++ unsigned int rx_multicast_frames; ++ unsigned int rx_fragments; ++ unsigned int rx_unicast_octets; ++ unsigned int rx_multicast_octets; ++ unsigned int rx_fcs_errors; ++ unsigned int rx_discards_no_buffer; ++ unsigned int tx_discards_wrong_sa; ++ unsigned int rx_discards_undecryptable; ++ unsigned int rx_message_in_msg_fragments; ++ unsigned int rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_device; ++ ++#include "ieee80211_crypt.h" ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++#define SEC_ENCRYPT (1<<9) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define SEC_ALG_NONE 0 ++#define SEC_ALG_WEP 1 ++#define SEC_ALG_TKIP 2 ++#define SEC_ALG_CCMP 3 ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++#define SCM_KEY_LEN 32 ++#define SCM_TEMPORAL_KEY_LENGTH 16 ++ ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1, ++ encrypt:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][SCM_KEY_LEN]; ++ u8 level; ++ u16 flags; ++} __attribute__ ((packed)); ++ ++ ++/* ++ 802.11 data frame from AP ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++Total: 28-2340 bytes ++*/ ++ ++/* Management Frame Information Element Types */ ++enum ieee80211_mfie { ++ MFIE_TYPE_SSID = 0, ++ MFIE_TYPE_RATES = 1, ++ MFIE_TYPE_FH_SET = 2, ++ MFIE_TYPE_DS_SET = 3, ++ MFIE_TYPE_CF_SET = 4, ++ MFIE_TYPE_TIM = 5, ++ MFIE_TYPE_IBSS_SET = 6, ++ MFIE_TYPE_COUNTRY = 7, ++ MFIE_TYPE_HOP_PARAMS = 8, ++ MFIE_TYPE_HOP_TABLE = 9, ++ MFIE_TYPE_REQUEST = 10, ++ MFIE_TYPE_CHALLENGE = 16, ++ MFIE_TYPE_POWER_CONSTRAINT = 32, ++ MFIE_TYPE_POWER_CAPABILITY = 33, ++ MFIE_TYPE_TPC_REQUEST = 34, ++ MFIE_TYPE_TPC_REPORT = 35, ++ MFIE_TYPE_SUPP_CHANNELS = 36, ++ MFIE_TYPE_CSA = 37, ++ MFIE_TYPE_MEASURE_REQUEST = 38, ++ MFIE_TYPE_MEASURE_REPORT = 39, ++ MFIE_TYPE_QUIET = 40, ++ MFIE_TYPE_IBSS_DFS = 41, ++ MFIE_TYPE_ERP = 42, ++ MFIE_TYPE_RSN = 48, ++ MFIE_TYPE_RATES_EX = 50, ++ MFIE_TYPE_HT_CAP= 45, ++ MFIE_TYPE_HT_INFO= 61, ++ MFIE_TYPE_AIRONET=133, ++ MFIE_TYPE_GENERIC = 221, ++ MFIE_TYPE_QOS_PARAMETER = 222, ++}; ++ ++/* Minimal header; can be used for passing 802.11 frames with sufficient ++ * information to determine what type of underlying data type is actually ++ * stored in the data. */ ++struct ieee80211_hdr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_1addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_2addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_4addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addrqos { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 payload[0]; ++ __le16 qos_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_4addrqos { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u8 payload[0]; ++ __le16 qos_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_authentication { ++ struct ieee80211_hdr_3addr header; ++ __le16 algorithm; ++ __le16 transaction; ++ __le16 status; ++ /*challenge*/ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_disassoc { ++ struct ieee80211_hdr_3addr header; ++ __le16 reason; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_request { ++ struct ieee80211_hdr_3addr header; ++ /* SSID, supported rates */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_response { ++ struct ieee80211_hdr_3addr header; ++ u32 time_stamp[2]; ++ __le16 beacon_interval; ++ __le16 capability; ++ /* SSID, supported rates, FH params, DS params, ++ * CF params, IBSS params, TIM (if beacon), RSN */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++/* Alias beacon for probe_response */ ++#define ieee80211_beacon ieee80211_probe_response ++ ++struct ieee80211_assoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ __le16 capability; ++ __le16 listen_interval; ++ /* SSID, supported rates, RSN */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_reassoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ __le16 capability; ++ __le16 listen_interval; ++ u8 current_ap[ETH_ALEN]; ++ /* SSID, supported rates, RSN */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_response_frame { ++ struct ieee80211_hdr_3addr header; ++ __le16 capability; ++ __le16 status; ++ __le16 aid; ++ struct ieee80211_info_element info_element[0]; /* supported rates */ ++} __attribute__ ((packed)); ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u8 queue_index; ++ u8 rts_included; ++ u16 reserved; ++ __le16 frag_size; ++ __le16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++#define MAX_TX_AGG_COUNT 16 ++struct ieee80211_drv_agg_txb { ++ u8 nr_drv_agg_frames; ++ struct sk_buff *tx_agg_frames[MAX_TX_AGG_COUNT]; ++}__attribute__((packed)); ++ ++#define MAX_SUBFRAME_COUNT 64 ++struct ieee80211_rxb { ++ u8 nr_subframes; ++ struct sk_buff *subframes[MAX_SUBFRAME_COUNT]; ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++}__attribute__((packed)); ++ ++typedef union _frameqos { ++ u16 shortdata; ++ u8 chardata[2]; ++ struct { ++ u16 tid:4; ++ u16 eosp:1; ++ u16 ack_policy:2; ++ u16 reserved:1; ++ u16 txop:8; ++ }field; ++}frameqos,*pframeqos; ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++ ++#define MAX_CHANNEL_NUMBER 161 ++#define IEEE80211_SOFTMAC_SCAN_TIME 100 ++//(HZ / 2) ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN 64 ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++/* QoS structure */ ++#define NETWORK_HAS_QOS_PARAMETERS (1<<3) ++#define NETWORK_HAS_QOS_INFORMATION (1<<4) ++#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ ++ NETWORK_HAS_QOS_INFORMATION) ++/* 802.11h */ ++#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) ++#define NETWORK_HAS_CSA (1<<6) ++#define NETWORK_HAS_QUIET (1<<7) ++#define NETWORK_HAS_IBSS_DFS (1<<8) ++#define NETWORK_HAS_TPC_REPORT (1<<9) ++ ++#define NETWORK_HAS_ERP_VALUE (1<<10) ++ ++#define QOS_QUEUE_NUM 4 ++#define QOS_OUI_LEN 3 ++#define QOS_OUI_TYPE 2 ++#define QOS_ELEMENT_ID 221 ++#define QOS_OUI_INFO_SUB_TYPE 0 ++#define QOS_OUI_PARAM_SUB_TYPE 1 ++#define QOS_VERSION_1 1 ++#define QOS_AIFSN_MIN_VALUE 2 ++#if 1 ++struct ieee80211_qos_information_element { ++ u8 elementID; ++ u8 length; ++ u8 qui[QOS_OUI_LEN]; ++ u8 qui_type; ++ u8 qui_subtype; ++ u8 version; ++ u8 ac_info; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_ac_parameter { ++ u8 aci_aifsn; ++ u8 ecw_min_max; ++ __le16 tx_op_limit; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_parameter_info { ++ struct ieee80211_qos_information_element info_element; ++ u8 reserved; ++ struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_parameters { ++ __le16 cw_min[QOS_QUEUE_NUM]; ++ __le16 cw_max[QOS_QUEUE_NUM]; ++ u8 aifs[QOS_QUEUE_NUM]; ++ u8 flag[QOS_QUEUE_NUM]; ++ __le16 tx_op_limit[QOS_QUEUE_NUM]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_data { ++ struct ieee80211_qos_parameters parameters; ++ int active; ++ int supported; ++ u8 param_count; ++ u8 old_param_count; ++}; ++ ++struct ieee80211_tim_parameters { ++ u8 tim_count; ++ u8 tim_period; ++} __attribute__ ((packed)); ++ ++//#else ++struct ieee80211_wmm_ac_param { ++ u8 ac_aci_acm_aifsn; ++ u8 ac_ecwmin_ecwmax; ++ u16 ac_txop_limit; ++}; ++ ++struct ieee80211_wmm_ts_info { ++ u8 ac_dir_tid; ++ u8 ac_up_psb; ++ u8 reserved; ++} __attribute__ ((packed)); ++ ++struct ieee80211_wmm_tspec_elem { ++ struct ieee80211_wmm_ts_info ts_info; ++ u16 norm_msdu_size; ++ u16 max_msdu_size; ++ u32 min_serv_inter; ++ u32 max_serv_inter; ++ u32 inact_inter; ++ u32 suspen_inter; ++ u32 serv_start_time; ++ u32 min_data_rate; ++ u32 mean_data_rate; ++ u32 peak_data_rate; ++ u32 max_burst_size; ++ u32 delay_bound; ++ u32 min_phy_rate; ++ u16 surp_band_allow; ++ u16 medium_time; ++}__attribute__((packed)); ++#endif ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++static const char *eap_types[] = { ++ [EAP_PACKET] = "EAP-Packet", ++ [EAPOL_START] = "EAPOL-Start", ++ [EAPOL_LOGOFF] = "EAPOL-Logoff", ++ [EAPOL_KEY] = "EAPOL-Key", ++ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" ++}; ++ ++static inline const char *eap_get_type(int type) ++{ ++ return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; ++} ++//added by amy for reorder ++static inline u8 Frame_QoSTID(u8* buf) ++{ ++ struct ieee80211_hdr_3addr *hdr; ++ u16 fc; ++ hdr = (struct ieee80211_hdr_3addr *)buf; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ return (u8)((frameqos*)(buf + (((fc & IEEE80211_FCTL_TODS)&&(fc & IEEE80211_FCTL_FROMDS))? 30 : 24)))->field.tid; ++} ++ ++//added by amy for reorder ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++struct ieee80211_softmac_stats{ ++ unsigned int rx_ass_ok; ++ unsigned int rx_ass_err; ++ unsigned int rx_probe_rq; ++ unsigned int tx_probe_rs; ++ unsigned int tx_beacons; ++ unsigned int rx_auth_rq; ++ unsigned int rx_auth_rs_ok; ++ unsigned int rx_auth_rs_err; ++ unsigned int tx_auth_rq; ++ unsigned int no_auth_rs; ++ unsigned int no_ass_rs; ++ unsigned int tx_ass_rq; ++ unsigned int rx_ass_rq; ++ unsigned int tx_probe_rq; ++ unsigned int reassoc; ++ unsigned int swtxstop; ++ unsigned int swtxawake; ++ unsigned char CurrentShowTxate; ++ unsigned char last_packet_rate; ++ unsigned int txretrycount; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __attribute__ ((packed)); ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __attribute__ ((packed)); ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 2 //1Mbps ++ ++enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; ++#define MAX_SP_Len (WMM_all_frame << 4) ++#define IEEE80211_QOS_TID 0x0f ++#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++ ++//added by David for QoS 2006/6/30 ++//#define WMM_Hang_8187 ++#ifdef WMM_Hang_8187 ++#undef WMM_Hang_8187 ++#endif ++ ++#define WME_AC_BK 0x00 ++#define WME_AC_BE 0x01 ++#define WME_AC_VI 0x02 ++#define WME_AC_VO 0x03 ++#define WME_ACI_MASK 0x03 ++#define WME_AIFSN_MASK 0x03 ++#define WME_AC_PRAM_LEN 16 ++ ++#define MAX_RECEIVE_BUFFER_SIZE 9100 ++ ++//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP ++//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) ++#if 1 ++#define UP2AC(up) ( \ ++ ((up) < 1) ? WME_AC_BE : \ ++ ((up) < 3) ? WME_AC_BK : \ ++ ((up) < 4) ? WME_AC_BE : \ ++ ((up) < 6) ? WME_AC_VI : \ ++ WME_AC_VO) ++#endif ++//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue ++#define AC2UP(_ac) ( \ ++ ((_ac) == WME_AC_VO) ? 6 : \ ++ ((_ac) == WME_AC_VI) ? 5 : \ ++ ((_ac) == WME_AC_BK) ? 1 : \ ++ 0) ++ ++#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ ++#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address plus ether type*/ ++ ++struct ether_header { ++ u8 ether_dhost[ETHER_ADDR_LEN]; ++ u8 ether_shost[ETHER_ADDR_LEN]; ++ u16 ether_type; ++} __attribute__((packed)); ++ ++#ifndef ETHERTYPE_PAE ++#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ ++#endif ++#ifndef ETHERTYPE_IP ++#define ETHERTYPE_IP 0x0800 /* IP protocol */ ++#endif ++ ++typedef struct _bss_ht{ ++ ++ bool support_ht; ++ ++ // HT related elements ++ u8 ht_cap_buf[32]; ++ u16 ht_cap_len; ++ u8 ht_info_buf[32]; ++ u16 ht_info_len; ++ ++ HT_SPEC_VER ht_spec_ver; ++ //HT_CAPABILITY_ELE bdHTCapEle; ++ //HT_INFORMATION_ELE bdHTInfoEle; ++ ++ bool aggregation; ++ bool long_slot_time; ++}bss_ht, *pbss_ht; ++ ++typedef enum _erp_t{ ++ ERP_NonERPpresent = 0x01, ++ ERP_UseProtection = 0x02, ++ ERP_BarkerPreambleMode = 0x04, ++} erp_t; ++ ++ ++struct ieee80211_network { ++ /* These entries are used to identify a unique network */ ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ /* Ensure null-terminated for any debug msgs */ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++#if 1 ++ struct ieee80211_qos_data qos_data; ++#else ++ // Qos related. Added by Annie, 2005-11-01. ++ BSS_QOS BssQos; ++#endif ++ ++ //added by amy for LEAP ++ bool bWithAironetIE; ++ bool bCkipSupported; ++ bool bCcxRmEnable; ++ u16 CcxRmState[2]; ++ // CCXv4 S59, MBSSID. ++ bool bMBssidValid; ++ u8 MBssidMask; ++ u8 MBssid[6]; ++ // CCX 2 S38, WLAN Device Version Number element. Annie, 2006-08-20. ++ bool bWithCcxVerNum; ++ u8 BssCcxVerNumber; ++ /* These are network statistics */ ++ struct ieee80211_rx_stats stats; ++ u16 capability; ++ u8 rates[MAX_RATES_LENGTH]; ++ u8 rates_len; ++ u8 rates_ex[MAX_RATES_EX_LENGTH]; ++ u8 rates_ex_len; ++ unsigned long last_scanned; ++ u8 mode; ++ u32 flags; ++ u32 last_associate; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 erp_value; ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ size_t wpa_ie_len; ++ u8 rsn_ie[MAX_WPA_IE_LEN]; ++ size_t rsn_ie_len; ++ ++ struct ieee80211_tim_parameters tim; ++ u8 dtim_period; ++ u8 dtim_data; ++ u32 last_dtim_sta_time[2]; ++ ++ //appeded for QoS ++ u8 wmm_info; ++ struct ieee80211_wmm_ac_param wmm_param[4]; ++ u8 QoS_Enable; ++#ifdef THOMAS_TURBO ++ u8 Turbo_Enable;//enable turbo mode, added by thomas ++#endif ++#ifdef ENABLE_DOT11D ++ u16 CountryIeLen; ++ u8 CountryIeBuf[MAX_IE_LEN]; ++#endif ++ // HT Related, by amy, 2008.04.29 ++ BSS_HT bssht; ++ // Add to handle broadcom AP management frame CCK rate. ++ bool broadcom_cap_exist; ++ bool ralink_cap_exist; ++ bool atheros_cap_exist; ++ bool cisco_cap_exist; ++ bool unknown_cap_exist; ++// u8 berp_info; ++ bool berp_info_valid; ++ bool buseprotection; ++ //put at the end of the structure. ++ struct list_head list; ++}; ++ ++#if 1 ++enum ieee80211_state { ++ ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++ ++}; ++#else ++enum ieee80211_state { ++ IEEE80211_UNINITIALIZED = 0, ++ IEEE80211_INITIALIZED, ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATED, ++ IEEE80211_AUTHENTICATING, ++ IEEE80211_AUTHENTICATED, ++ IEEE80211_SHUTDOWN ++}; ++#endif ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++#define CFG_IEEE80211_RTS (1<<2) ++ ++#define IEEE80211_24GHZ_MIN_CHANNEL 1 ++#define IEEE80211_24GHZ_MAX_CHANNEL 14 ++#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ ++ IEEE80211_24GHZ_MIN_CHANNEL + 1) ++ ++#define IEEE80211_52GHZ_MIN_CHANNEL 34 ++#define IEEE80211_52GHZ_MAX_CHANNEL 165 ++#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ ++ IEEE80211_52GHZ_MIN_CHANNEL + 1) ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) ++extern inline int is_multicast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) ++extern inline int is_broadcast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++#endif ++ ++typedef struct tx_pending_t{ ++ int frag; ++ struct ieee80211_txb *txb; ++}tx_pending_t; ++ ++typedef struct _bandwidth_autoswitch ++{ ++ long threshold_20Mhzto40Mhz; ++ long threshold_40Mhzto20Mhz; ++ bool bforced_tx20Mhz; ++ bool bautoswitch_enable; ++}bandwidth_autoswitch,*pbandwidth_autoswitch; ++ ++ ++//added by amy for order ++ ++#define REORDER_WIN_SIZE 128 ++#define REORDER_ENTRY_NUM 128 ++typedef struct _RX_REORDER_ENTRY ++{ ++ struct list_head List; ++ u16 SeqNum; ++ struct ieee80211_rxb* prxb; ++} RX_REORDER_ENTRY, *PRX_REORDER_ENTRY; ++//added by amy for order ++typedef enum _Fsync_State{ ++ Default_Fsync, ++ HW_Fsync, ++ SW_Fsync ++}Fsync_State; ++ ++// Power save mode configured. ++typedef enum _RT_PS_MODE ++{ ++ eActive, // Active/Continuous access. ++ eMaxPs, // Max power save mode. ++ eFastPs // Fast power save mode. ++}RT_PS_MODE; ++ ++typedef enum _IPS_CALLBACK_FUNCION ++{ ++ IPS_CALLBACK_NONE = 0, ++ IPS_CALLBACK_MGNT_LINK_REQUEST = 1, ++ IPS_CALLBACK_JOIN_REQUEST = 2, ++}IPS_CALLBACK_FUNCION; ++ ++typedef enum _RT_JOIN_ACTION{ ++ RT_JOIN_INFRA = 1, ++ RT_JOIN_IBSS = 2, ++ RT_START_IBSS = 3, ++ RT_NO_ACTION = 4, ++}RT_JOIN_ACTION; ++ ++typedef struct _IbssParms{ ++ u16 atimWin; ++}IbssParms, *PIbssParms; ++#define MAX_NUM_RATES 264 // Max num of support rates element: 8, Max num of ext. support rate: 255. 061122, by rcnjko. ++ ++// RF state. ++typedef enum _RT_RF_POWER_STATE ++{ ++ eRfOn, ++ eRfSleep, ++ eRfOff ++}RT_RF_POWER_STATE; ++ ++typedef struct _RT_POWER_SAVE_CONTROL ++{ ++ ++ // ++ // Inactive Power Save(IPS) : Disable RF when disconnected ++ // ++ bool bInactivePs; ++ bool bIPSModeBackup; ++ bool bSwRfProcessing; ++ RT_RF_POWER_STATE eInactivePowerState; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct InactivePsWorkItem; ++#else ++ struct tq_struct InactivePsWorkItem; ++#endif ++ struct timer_list InactivePsTimer; ++ ++ // Return point for join action ++ IPS_CALLBACK_FUNCION ReturnPoint; ++ ++ // Recored Parameters for rescheduled JoinRequest ++ bool bTmpBssDesc; ++ RT_JOIN_ACTION tmpJoinAction; ++ struct ieee80211_network tmpBssDesc; ++ ++ // Recored Parameters for rescheduled MgntLinkRequest ++ bool bTmpScanOnly; ++ bool bTmpActiveScan; ++ bool bTmpFilterHiddenAP; ++ bool bTmpUpdateParms; ++ u8 tmpSsidBuf[33]; ++ OCTET_STRING tmpSsid2Scan; ++ bool bTmpSsid2Scan; ++ u8 tmpNetworkType; ++ u8 tmpChannelNumber; ++ u16 tmpBcnPeriod; ++ u8 tmpDtimPeriod; ++ u16 tmpmCap; ++ OCTET_STRING tmpSuppRateSet; ++ u8 tmpSuppRateBuf[MAX_NUM_RATES]; ++ bool bTmpSuppRate; ++ IbssParms tmpIbpm; ++ bool bTmpIbpm; ++ ++ // ++ // Leisre Poswer Save : Disable RF if connected but traffic is not busy ++ // ++ bool bLeisurePs; ++ ++}RT_POWER_SAVE_CONTROL,*PRT_POWER_SAVE_CONTROL; ++ ++typedef u32 RT_RF_CHANGE_SOURCE; ++#define RF_CHANGE_BY_SW BIT31 ++#define RF_CHANGE_BY_HW BIT30 ++#define RF_CHANGE_BY_PS BIT29 ++#define RF_CHANGE_BY_IPS BIT28 ++#define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17. ++ ++#ifdef ENABLE_DOT11D ++typedef enum ++{ ++ COUNTRY_CODE_FCC = 0, ++ COUNTRY_CODE_IC = 1, ++ COUNTRY_CODE_ETSI = 2, ++ COUNTRY_CODE_SPAIN = 3, ++ COUNTRY_CODE_FRANCE = 4, ++ COUNTRY_CODE_MKK = 5, ++ COUNTRY_CODE_MKK1 = 6, ++ COUNTRY_CODE_ISRAEL = 7, ++ COUNTRY_CODE_TELEC, ++ COUNTRY_CODE_MIC, ++ COUNTRY_CODE_GLOBAL_DOMAIN ++}country_code_type_t; ++#endif ++ ++#define RT_MAX_LD_SLOT_NUM 10 ++typedef struct _RT_LINK_DETECT_T{ ++ ++ u32 NumRecvBcnInPeriod; ++ u32 NumRecvDataInPeriod; ++ ++ u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; // number of Rx beacon / CheckForHang_period to determine link status ++ u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; // number of Rx data / CheckForHang_period to determine link status ++ u16 SlotNum; // number of CheckForHang period to determine link status ++ u16 SlotIndex; ++ ++ u32 NumTxOkInPeriod; ++ u32 NumRxOkInPeriod; ++ bool bBusyTraffic; ++}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; ++ ++ ++struct ieee80211_device { ++ struct net_device *dev; ++ struct ieee80211_security sec; ++ ++ //hw security related ++// u8 hwsec_support; //support? ++ u8 hwsec_active; //hw security active. ++ bool is_silent_reset; ++ bool is_roaming; ++ bool ieee_up; ++ //added by amy ++ bool bSupportRemoteWakeUp; ++ RT_PS_MODE dot11PowerSaveMode; // Power save mode configured. ++ bool actscanning; ++ bool beinretry; ++ RT_RF_POWER_STATE eRFPowerState; ++ RT_RF_CHANGE_SOURCE RfOffReason; ++ bool is_set_key; ++ //11n spec related I wonder if These info structure need to be moved out of ieee80211_device ++ ++ //11n HT below ++ PRT_HIGH_THROUGHPUT pHTInfo; ++ //struct timer_list SwBwTimer; ++// spinlock_t chnlop_spinlock; ++ spinlock_t bw_spinlock; ++ ++ spinlock_t reorder_spinlock; ++ // for HT operation rate set. we use this one for HT data rate to seperate different descriptors ++ //the way fill this is the same as in the IE ++ u8 Regdot11HTOperationalRateSet[16]; //use RATR format ++ u8 dot11HTOperationalRateSet[16]; //use RATR format ++ u8 RegHTSuppRateSet[16]; ++ u8 HTCurrentOperaRate; ++ u8 HTHighestOperaRate; ++ //wb added for rate operation mode to firmware ++ u8 bTxDisableRateFallBack; ++ u8 bTxUseDriverAssingedRate; ++ atomic_t atm_chnlop; ++ atomic_t atm_swbw; ++// u8 HTHighestOperaRate; ++// u8 HTCurrentOperaRate; ++ ++ // 802.11e and WMM Traffic Stream Info (TX) ++ struct list_head Tx_TS_Admit_List; ++ struct list_head Tx_TS_Pending_List; ++ struct list_head Tx_TS_Unused_List; ++ TX_TS_RECORD TxTsRecord[TOTAL_TS_NUM]; ++ // 802.11e and WMM Traffic Stream Info (RX) ++ struct list_head Rx_TS_Admit_List; ++ struct list_head Rx_TS_Pending_List; ++ struct list_head Rx_TS_Unused_List; ++ RX_TS_RECORD RxTsRecord[TOTAL_TS_NUM]; ++//#ifdef TO_DO_LIST ++ RX_REORDER_ENTRY RxReorderEntry[128]; ++ struct list_head RxReorder_Unused_List; ++//#endif ++ // Qos related. Added by Annie, 2005-11-01. ++// PSTA_QOS pStaQos; ++ u8 ForcedPriority; // Force per-packet priority 1~7. (default: 0, not to force it.) ++ ++ ++ /* Bookkeeping structures */ ++ struct net_device_stats stats; ++ struct ieee80211_stats ieee_stats; ++ struct ieee80211_softmac_stats softmac_stats; ++ ++ /* Probe / Beacon management */ ++ struct list_head network_free_list; ++ struct list_head network_list; ++ struct ieee80211_network *networks; ++ int scans; ++ int scan_age; ++ ++ int iw_mode; /* operating mode (IW_MODE_*) */ ++ struct iw_spy_data spy_data; ++ ++ spinlock_t lock; ++ spinlock_t wpax_suitlist_lock; ++ ++ int tx_headroom; /* Set to size of any additional room needed at front ++ * of allocated Tx SKBs */ ++ u32 config; ++ ++ /* WEP and other encryption related settings at the device level */ ++ int open_wep; /* Set to 1 to allow unencrypted frames */ ++ int auth_mode; ++ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on ++ * WEP key changes */ ++ ++ /* If the host performs {en,de}cryption, then set to 1 */ ++ int host_encrypt; ++ int host_encrypt_msdu; ++ int host_decrypt; ++ /* host performs multicast decryption */ ++ int host_mc_decrypt; ++ ++ /* host should strip IV and ICV from protected frames */ ++ /* meaningful only when hardware decryption is being used */ ++ int host_strip_iv_icv; ++ ++ int host_open_frag; ++ int host_build_iv; ++ int ieee802_1x; /* is IEEE 802.1X used */ ++ ++ /* WPA data */ ++ bool bHalfWirelessN24GMode; ++ int wpa_enabled; ++ int drop_unencrypted; ++ int tkip_countermeasures; ++ int privacy_invoked; ++ size_t wpa_ie_len; ++ u8 *wpa_ie; ++ u8 ap_mac_addr[6]; ++ u16 pairwise_key_type; ++ u16 group_key_type; ++ struct list_head crypt_deinit_list; ++ struct ieee80211_crypt_data *crypt[WEP_KEYS]; ++ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ ++ struct timer_list crypt_deinit_timer; ++ int crypt_quiesced; ++ ++ int bcrx_sta_key; /* use individual keys to override default keys even ++ * with RX of broad/multicast frames */ ++ ++ /* Fragmentation structures */ ++ // each streaming contain a entry ++ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; ++ unsigned int frag_next_idx[17]; ++ u16 fts; /* Fragmentation Threshold */ ++#define DEFAULT_RTS_THRESHOLD 2346U ++#define MIN_RTS_THRESHOLD 1 ++#define MAX_RTS_THRESHOLD 2346U ++ u16 rts; /* RTS threshold */ ++ ++ /* Association info */ ++ u8 bssid[ETH_ALEN]; ++ ++ /* This stores infos for the current network. ++ * Either the network we are associated in INFRASTRUCTURE ++ * or the network that we are creating in MASTER mode. ++ * ad-hoc is a mixture ;-). ++ * Note that in infrastructure mode, even when not associated, ++ * fields bssid and essid may be valid (if wpa_set and essid_set ++ * are true) as thy carry the value set by the user via iwconfig ++ */ ++ struct ieee80211_network current_network; ++ ++ enum ieee80211_state state; ++ ++ int short_slot; ++ int reg_mode; ++ int mode; /* A, B, G */ ++ int modulation; /* CCK, OFDM */ ++ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ ++ int abg_true; /* ABG flag */ ++ ++ /* used for forcing the ibss workqueue to terminate ++ * without wait for the syncro scan to terminate ++ */ ++ short sync_scan_hurryup; ++ ++ int perfect_rssi; ++ int worst_rssi; ++ ++ u16 prev_seq_ctl; /* used to drop duplicate frames */ ++ ++ /* map of allowed channels. 0 is dummy */ ++ // FIXME: remeber to default to a basic channel plan depending of the PHY type ++#ifdef ENABLE_DOT11D ++ void* pDot11dInfo; ++ bool bGlobalDomain; ++#else ++ int channel_map[MAX_CHANNEL_NUMBER+1]; ++#endif ++ int rate; /* current rate */ ++ int basic_rate; ++ //FIXME: pleace callback, see if redundant with softmac_features ++ short active_scan; ++ ++ /* this contains flags for selectively enable softmac support */ ++ u16 softmac_features; ++ ++ /* if the sequence control field is not filled by HW */ ++ u16 seq_ctrl[5]; ++ ++ /* association procedure transaction sequence number */ ++ u16 associate_seq; ++ ++ /* AID for RTXed association responses */ ++ u16 assoc_id; ++ ++ /* power save mode related*/ ++ u8 ack_tx_to_ieee; ++ short ps; ++ short sta_sleep; ++ int ps_timeout; ++ int ps_period; ++ struct tasklet_struct ps_task; ++ u32 ps_th; ++ u32 ps_tl; ++ ++ short raw_tx; ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ short queue_stop; ++ short scanning; ++ short proto_started; ++ ++ struct semaphore wx_sem; ++ struct semaphore scan_sem; ++ ++ spinlock_t mgmt_tx_lock; ++ spinlock_t beacon_lock; ++ ++ short beacon_txing; ++ ++ short wap_set; ++ short ssid_set; ++ ++ u8 wpax_type_set; //{added by David, 2006.9.28} ++ u32 wpax_type_notify; //{added by David, 2006.9.26} ++ ++ /* QoS related flag */ ++ char init_wmmparam_flag; ++ /* set on initialization */ ++ u8 qos_support; ++ ++ /* for discarding duplicated packets in IBSS */ ++ struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; ++ ++ /* for discarding duplicated packets in BSS */ ++ u16 last_rxseq_num[17]; /* rx seq previous per-tid */ ++ u16 last_rxfrag_num[17];/* tx frag previous per-tid */ ++ unsigned long last_packet_time[17]; ++ ++ /* for PS mode */ ++ unsigned long last_rx_ps_time; ++ ++ /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ ++ struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; ++ int mgmt_queue_head; ++ int mgmt_queue_tail; ++//{ added for rtl819x ++#define IEEE80211_QUEUE_LIMIT 128 ++ u8 AsocRetryCount; ++ unsigned int hw_header; ++ struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE]; ++ struct sk_buff_head skb_aggQ[MAX_QUEUE_SIZE]; ++ struct sk_buff_head skb_drv_aggQ[MAX_QUEUE_SIZE]; ++ u32 sta_edca_param[4]; ++ bool aggregation; ++ // Enable/Disable Rx immediate BA capability. ++ bool enable_rx_imm_BA; ++ bool bibsscoordinator; ++ ++ //+by amy for DM ,080515 ++ //Dynamic Tx power for near/far range enable/Disable , by amy , 2008-05-15 ++ bool bdynamic_txpower_enable; ++ ++ bool bCTSToSelfEnable; ++ u8 CTSToSelfTH; ++ ++ u32 fsync_time_interval; ++ u32 fsync_rate_bitmap; ++ u8 fsync_rssi_threshold; ++ bool bfsync_enable; ++ ++ u8 fsync_multiple_timeinterval; // FsyncMultipleTimeInterval * FsyncTimeInterval ++ u32 fsync_firstdiff_ratethreshold; // low threshold ++ u32 fsync_seconddiff_ratethreshold; // decrease threshold ++ Fsync_State fsync_state; ++ bool bis_any_nonbepkts; ++ //20Mhz 40Mhz AutoSwitch Threshold ++ bandwidth_autoswitch bandwidth_auto_switch; ++ //for txpower tracking ++ bool FwRWRF; ++ ++ //added by amy for AP roaming ++ RT_LINK_DETECT_T LinkDetectInfo; ++ //added by amy for ps ++ RT_POWER_SAVE_CONTROL PowerSaveControl; ++//} ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ struct tx_pending_t tx_pending; ++ ++ /* used if IEEE_SOFTMAC_ASSOCIATE is set */ ++ struct timer_list associate_timer; ++ ++ /* used if IEEE_SOFTMAC_BEACONS is set */ ++ struct timer_list beacon_timer; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct associate_complete_wq; ++ struct work_struct associate_procedure_wq; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct delayed_work softmac_scan_wq; ++ struct delayed_work associate_retry_wq; ++ struct delayed_work start_ibss_wq; ++ struct delayed_work hw_wakeup_wq; ++ struct delayed_work hw_sleep_wq; ++#else ++ struct work_struct softmac_scan_wq; ++ struct work_struct associate_retry_wq; ++ struct work_struct start_ibss_wq; ++ struct work_struct hw_wakeup_wq; ++ struct work_struct hw_sleep_wq; ++#endif ++ struct work_struct wx_sync_scan_wq; ++ struct workqueue_struct *wq; ++#else ++ /* used for periodly scan */ ++ struct timer_list scan_timer; ++ ++ struct tq_struct associate_complete_wq; ++ struct tq_struct associate_retry_wq; ++ struct tq_struct start_ibss_wq; ++ struct tq_struct associate_procedure_wq; ++ struct tq_struct softmac_scan_wq; ++ struct tq_struct wx_sync_scan_wq; ++ ++#endif ++ // Qos related. Added by Annie, 2005-11-01. ++ //STA_QOS StaQos; ++ ++ //u32 STA_EDCA_PARAM[4]; ++ //CHANNEL_ACCESS_SETTING ChannelAccessSetting; ++ ++ ++ /* Callback functions */ ++ void (*set_security)(struct net_device *dev, ++ struct ieee80211_security *sec); ++ ++ /* Used to TX data frame by using txb structs. ++ * this is not used if in the softmac_features ++ * is set the flag IEEE_SOFTMAC_TX_QUEUE ++ */ ++ int (*hard_start_xmit)(struct ieee80211_txb *txb, ++ struct net_device *dev); ++ ++ int (*reset_port)(struct net_device *dev); ++ int (*is_queue_full) (struct net_device * dev, int pri); ++ ++ int (*handle_management) (struct net_device * dev, ++ struct ieee80211_network * network, u16 type); ++ int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); ++ ++ /* Softmac-generated frames (mamagement) are TXed via this ++ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is ++ * not set. As some cards may have different HW queues that ++ * one might want to use for data and management frames ++ * the option to have two callbacks might be useful. ++ * This fucntion can't sleep. ++ */ ++ int (*softmac_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* used instead of hard_start_xmit (not softmac_hard_start_xmit) ++ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data ++ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set ++ * then also management frames are sent via this callback. ++ * This function can't sleep. ++ */ ++ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev,int rate); ++ ++ /* stops the HW queue for DATA frames. Useful to avoid ++ * waste time to TX data frame when we are reassociating ++ * This function can sleep. ++ */ ++ void (*data_hard_stop)(struct net_device *dev); ++ ++ /* OK this is complementar to data_poll_hard_stop */ ++ void (*data_hard_resume)(struct net_device *dev); ++ ++ /* ask to the driver to retune the radio . ++ * This function can sleep. the driver should ensure ++ * the radio has been swithced before return. ++ */ ++ void (*set_chan)(struct net_device *dev,short ch); ++ ++ /* These are not used if the ieee stack takes care of ++ * scanning (IEEE_SOFTMAC_SCAN feature set). ++ * In this case only the set_chan is used. ++ * ++ * The syncro version is similar to the start_scan but ++ * does not return until all channels has been scanned. ++ * this is called in user context and should sleep, ++ * it is called in a work_queue when swithcing to ad-hoc mode ++ * or in behalf of iwlist scan when the card is associated ++ * and root user ask for a scan. ++ * the fucntion stop_scan should stop both the syncro and ++ * background scanning and can sleep. ++ * The fucntion start_scan should initiate the background ++ * scanning and can't sleep. ++ */ ++ void (*scan_syncro)(struct net_device *dev); ++ void (*start_scan)(struct net_device *dev); ++ void (*stop_scan)(struct net_device *dev); ++ ++ /* indicate the driver that the link state is changed ++ * for example it may indicate the card is associated now. ++ * Driver might be interested in this to apply RX filter ++ * rules or simply light the LINK led ++ */ ++ void (*link_change)(struct net_device *dev); ++ ++ /* these two function indicates to the HW when to start ++ * and stop to send beacons. This is used when the ++ * IEEE_SOFTMAC_BEACONS is not set. For now the ++ * stop_send_bacons is NOT guaranteed to be called only ++ * after start_send_beacons. ++ */ ++ void (*start_send_beacons) (struct net_device *dev); ++ void (*stop_send_beacons) (struct net_device *dev); ++ ++ /* power save mode related */ ++ void (*sta_wake_up) (struct net_device *dev); ++// void (*ps_request_tx_ack) (struct net_device *dev); ++ void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); ++ short (*ps_is_queue_empty) (struct net_device *dev); ++#if 0 ++ /* Typical STA methods */ ++ int (*handle_auth) (struct net_device * dev, ++ struct ieee80211_auth * auth); ++ int (*handle_deauth) (struct net_device * dev, ++ struct ieee80211_deauth * auth); ++ int (*handle_action) (struct net_device * dev, ++ struct ieee80211_action * action, ++ struct ieee80211_rx_stats * stats); ++ int (*handle_disassoc) (struct net_device * dev, ++ struct ieee80211_disassoc * assoc); ++#endif ++ int (*handle_beacon) (struct net_device * dev, struct ieee80211_beacon * beacon, struct ieee80211_network * network); ++#if 0 ++ int (*handle_probe_response) (struct net_device * dev, ++ struct ieee80211_probe_response * resp, ++ struct ieee80211_network * network); ++ int (*handle_probe_request) (struct net_device * dev, ++ struct ieee80211_probe_request * req, ++ struct ieee80211_rx_stats * stats); ++#endif ++ int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network); ++ ++#if 0 ++ /* Typical AP methods */ ++ int (*handle_assoc_request) (struct net_device * dev); ++ int (*handle_reassoc_request) (struct net_device * dev, ++ struct ieee80211_reassoc_request * req); ++#endif ++ ++ /* check whether Tx hw resouce available */ ++ short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); ++ //added by wb for HT related ++// void (*SwChnlByTimerHandler)(struct net_device *dev, int channel); ++ void (*SetBWModeHandler)(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); ++// void (*UpdateHalRATRTableHandler)(struct net_device* dev, u8* pMcsRate); ++ bool (*GetNmodeSupportBySecCfg)(struct net_device* dev); ++ void (*SetWirelessMode)(struct net_device* dev, u8 wireless_mode); ++ bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device* dev); ++ void (*InitialGainHandler)(struct net_device *dev, u8 Operation); ++ ++ /* This must be the last item so that it points to the data ++ * allocated beyond this structure by alloc_ieee80211 */ ++ u8 priv[0]; ++}; ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_N_24G (1<<4) ++#define IEEE_N_5G (1<<5) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++/* Generate a 802.11 header */ ++ ++/* Uses the channel change callback directly ++ * instead of [start/stop] scan callbacks ++ */ ++#define IEEE_SOFTMAC_SCAN (1<<2) ++ ++/* Perform authentication and association handshake */ ++#define IEEE_SOFTMAC_ASSOCIATE (1<<3) ++ ++/* Generate probe requests */ ++#define IEEE_SOFTMAC_PROBERQ (1<<4) ++ ++/* Generate respones to probe requests */ ++#define IEEE_SOFTMAC_PROBERS (1<<5) ++ ++/* The ieee802.11 stack will manages the netif queue ++ * wake/stop for the driver, taking care of 802.11 ++ * fragmentation. See softmac.c for details. */ ++#define IEEE_SOFTMAC_TX_QUEUE (1<<7) ++ ++/* Uses only the softmac_data_hard_start_xmit ++ * even for TX management frames. ++ */ ++#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) ++ ++/* Generate beacons. The stack will enqueue beacons ++ * to the card ++ */ ++#define IEEE_SOFTMAC_BEACONS (1<<6) ++ ++static inline void *ieee80211_priv(struct net_device *dev) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ return ((struct ieee80211_device *)netdev_priv(dev))->priv; ++#else ++ return ((struct ieee80211_device *)dev->priv)->priv; ++#endif ++} ++ ++extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) ++{ ++ /* ++ * It is possible for both access points and our device to support ++ * combinations of modes, so as long as there is one valid combination ++ * of ap/device supported modes, then return success ++ * ++ */ ++ if ((mode & IEEE_A) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_52GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_G) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_B) && ++ (ieee->modulation & IEEE80211_CCK_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ return 0; ++} ++ ++extern inline int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = IEEE80211_3ADDR_LEN; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case IEEE80211_FTYPE_DATA: ++ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) ++ hdrlen = IEEE80211_4ADDR_LEN; /* Addr4 */ ++ if(IEEE80211_QOS_HAS_SEQ(fc)) ++ hdrlen += 2; /* QOS ctrl*/ ++ break; ++ case IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case IEEE80211_STYPE_CTS: ++ case IEEE80211_STYPE_ACK: ++ hdrlen = IEEE80211_1ADDR_LEN; ++ break; ++ default: ++ hdrlen = IEEE80211_2ADDR_LEN; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) ++{ ++ switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { ++ case IEEE80211_1ADDR_LEN: ++ return ((struct ieee80211_hdr_1addr *)hdr)->payload; ++ case IEEE80211_2ADDR_LEN: ++ return ((struct ieee80211_hdr_2addr *)hdr)->payload; ++ case IEEE80211_3ADDR_LEN: ++ return ((struct ieee80211_hdr_3addr *)hdr)->payload; ++ case IEEE80211_4ADDR_LEN: ++ return ((struct ieee80211_hdr_4addr *)hdr)->payload; ++ } ++ return NULL; ++} ++ ++static inline int ieee80211_is_ofdm_rate(u8 rate) ++{ ++ switch (rate & ~IEEE80211_BASIC_RATE_MASK) { ++ case IEEE80211_OFDM_RATE_6MB: ++ case IEEE80211_OFDM_RATE_9MB: ++ case IEEE80211_OFDM_RATE_12MB: ++ case IEEE80211_OFDM_RATE_18MB: ++ case IEEE80211_OFDM_RATE_24MB: ++ case IEEE80211_OFDM_RATE_36MB: ++ case IEEE80211_OFDM_RATE_48MB: ++ case IEEE80211_OFDM_RATE_54MB: ++ return 1; ++ } ++ return 0; ++} ++ ++static inline int ieee80211_is_cck_rate(u8 rate) ++{ ++ switch (rate & ~IEEE80211_BASIC_RATE_MASK) { ++ case IEEE80211_CCK_RATE_1MB: ++ case IEEE80211_CCK_RATE_2MB: ++ case IEEE80211_CCK_RATE_5MB: ++ case IEEE80211_CCK_RATE_11MB: ++ return 1; ++ } ++ return 0; ++} ++ ++ ++/* ieee80211.c */ ++extern void free_ieee80211(struct net_device *dev); ++extern struct net_device *alloc_ieee80211(int sizeof_priv); ++ ++extern int ieee80211_set_encryption(struct ieee80211_device *ieee); ++ ++/* ieee80211_tx.c */ ++ ++extern int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len); ++ ++extern int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev); ++extern void ieee80211_txb_free(struct ieee80211_txb *); ++ ++ ++/* ieee80211_rx.c */ ++extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats); ++extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr_4addr *header, ++ struct ieee80211_rx_stats *stats); ++ ++/* ieee80211_wx.c */ ++extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++#if WIRELESS_EXT >= 18 ++extern int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++extern int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra); ++extern int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++#endif ++extern int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); ++ ++/* ieee80211_softmac.c */ ++extern short ieee80211_is_54g(struct ieee80211_network net); ++extern short ieee80211_is_shortslot(struct ieee80211_network net); ++extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype); ++extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); ++ ++void SendDisassociation(struct ieee80211_device *ieee, u8* asSta, u8 asRsn); ++extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); ++ ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_ibss(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_init(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_free(struct ieee80211_device *ieee); ++extern void ieee80211_associate_abort(struct ieee80211_device *ieee); ++extern void ieee80211_disassociate(struct ieee80211_device *ieee); ++extern void ieee80211_stop_scan(struct ieee80211_device *ieee); ++extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); ++extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_reset_queue(struct ieee80211_device *ieee); ++extern void ieee80211_wake_queue(struct ieee80211_device *ieee); ++extern void ieee80211_stop_queue(struct ieee80211_device *ieee); ++extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); ++extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); ++ ++extern void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee); ++ ++/* ieee80211_crypt_ccmp&tkip&wep.c */ ++extern void ieee80211_tkip_null(void); ++extern void ieee80211_wep_null(void); ++extern void ieee80211_ccmp_null(void); ++ ++/* ieee80211_softmac_wx.c */ ++ ++extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *ext); ++ ++extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra); ++ ++extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); ++ ++extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); ++#else ++ extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#endif ++ ++ ++extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_rts(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rts(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++//HT ++#define MAX_RECEIVE_BUFFER_SIZE 9100 // ++extern void HTDebugHTCapability(u8* CapIE, u8* TitleString ); ++extern void HTDebugHTInfo(u8* InfoIE, u8* TitleString); ++ ++void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); ++extern void HTUpdateDefaultSetting(struct ieee80211_device* ieee); ++extern void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u8* len, u8 isEncrypt); ++extern void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* len, u8 isEncrypt); ++extern void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg, u8* len); ++extern void HTOnAssocRsp(struct ieee80211_device *ieee); ++extern void HTInitializeHTInfo(struct ieee80211_device* ieee); ++extern void HTInitializeBssDesc(PBSS_HT pBssHT); ++extern void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); ++extern void HTUpdateSelfAndPeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); ++extern u8 HTGetHighestMCSRate(struct ieee80211_device* ieee, u8* pMCSRateSet, u8* pMCSFilter); ++extern u8 MCS_FILTER_ALL[]; ++extern u16 MCS_DATA_RATE[2][2][77] ; ++extern u8 HTCCheck(struct ieee80211_device* ieee, u8* pFrame); ++//extern void HTSetConnectBwModeCallback(unsigned long data); ++extern void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo); ++extern bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee); ++extern u16 HTHalfMcsToDataRate(struct ieee80211_device* ieee, u8 nMcsRate); ++extern u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate); ++extern u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate); ++//function in BAPROC.c ++extern int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb); ++extern int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb); ++extern int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb); ++extern void TsInitAddBA( struct ieee80211_device* ieee, PTX_TS_RECORD pTS, u8 Policy, u8 bOverwritePending); ++extern void TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect); ++extern void BaSetupTimeOut(unsigned long data); ++extern void TxBaInactTimeout(unsigned long data); ++extern void RxBaInactTimeout(unsigned long data); ++extern void ResetBaEntry( PBA_RECORD pBA); ++//function in TS.c ++extern bool GetTs( ++ struct ieee80211_device* ieee, ++ PTS_COMMON_INFO *ppTS, ++ u8* Addr, ++ u8 TID, ++ TR_SELECT TxRxSelect, //Rx:1, Tx:0 ++ bool bAddNewTs ++ ); ++extern void TSInitialize(struct ieee80211_device *ieee); ++extern void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS); ++extern void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr); ++extern void RemoveAllTS(struct ieee80211_device* ieee); ++void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee); ++ ++extern const long ieee80211_wlan_frequencies[]; ++ ++extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) ++{ ++ ieee->scans++; ++} ++ ++extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) ++{ ++ return ieee->scans; ++} ++ ++static inline const char *escape_essid(const char *essid, u8 essid_len) { ++ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; ++ const char *s = essid; ++ char *d = escaped; ++ ++ if (ieee80211_is_empty_essid(essid, essid_len)) { ++ memcpy(escaped, "", sizeof("")); ++ return escaped; ++ } ++ ++ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); ++ while (essid_len--) { ++ if (*s == '\0') { ++ *d++ = '\\'; ++ *d++ = '0'; ++ s++; ++ } else { ++ *d++ = *s++; ++ } ++ } ++ *d = '\0'; ++ return escaped; ++} ++ ++/* For the function is more related to hardware setting, it's better to use the ++ * ieee handler to refer to it. ++ */ ++extern short check_nic_enough_desc(struct net_device *dev, int queue_index); ++extern int ieee80211_data_xmit(struct sk_buff *skb, struct net_device *dev); ++extern int ieee80211_parse_info_param(struct ieee80211_device *ieee, ++ struct ieee80211_info_element *info_element, ++ u16 length, ++ struct ieee80211_network *network, ++ struct ieee80211_rx_stats *stats); ++ ++void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index); ++#define RT_ASOC_RETRY_LIMIT 5 ++#endif /* IEEE80211_H */ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/EndianFree.h +@@ -0,0 +1,199 @@ ++#ifndef __INC_ENDIANFREE_H ++#define __INC_ENDIANFREE_H ++ ++/* ++ * Call endian free function when ++ * 1. Read/write packet content. ++ * 2. Before write integer to IO. ++ * 3. After read integer from IO. ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#ifndef bool ++typedef enum{false = 0, true} bool; ++#endif ++#endif ++ ++#define __MACHINE_LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ ++#define __MACHINE_BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net, ppc */ ++ ++#define BYTE_ORDER __MACHINE_LITTLE_ENDIAN ++ ++#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN ++// Convert data ++#define EF1Byte(_val) ((u8)(_val)) ++#define EF2Byte(_val) ((u16)(_val)) ++#define EF4Byte(_val) ((u32)(_val)) ++ ++#else ++// Convert data ++#define EF1Byte(_val) ((u8)(_val)) ++#define EF2Byte(_val) (((((u16)(_val))&0x00ff)<<8)|((((u16)(_val))&0xff00)>>8)) ++#define EF4Byte(_val) (((((u32)(_val))&0x000000ff)<<24)|\ ++ ((((u32)(_val))&0x0000ff00)<<8)|\ ++ ((((u32)(_val))&0x00ff0000)>>8)|\ ++ ((((u32)(_val))&0xff000000)>>24)) ++#endif ++ ++// Read data from memory ++#define ReadEF1Byte(_ptr) EF1Byte(*((u8 *)(_ptr))) ++#define ReadEF2Byte(_ptr) EF2Byte(*((u16 *)(_ptr))) ++#define ReadEF4Byte(_ptr) EF4Byte(*((u32 *)(_ptr))) ++ ++// Write data to memory ++#define WriteEF1Byte(_ptr, _val) (*((u8 *)(_ptr)))=EF1Byte(_val) ++#define WriteEF2Byte(_ptr, _val) (*((u16 *)(_ptr)))=EF2Byte(_val) ++#define WriteEF4Byte(_ptr, _val) (*((u32 *)(_ptr)))=EF4Byte(_val) ++// Convert Host system specific byte ording (litten or big endia) to Network byte ording (big endian). ++// 2006.05.07, by rcnjko. ++#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN ++#define H2N1BYTE(_val) ((u8)(_val)) ++#define H2N2BYTE(_val) (((((u16)(_val))&0x00ff)<<8)|\ ++ ((((u16)(_val))&0xff00)>>8)) ++#define H2N4BYTE(_val) (((((u32)(_val))&0x000000ff)<<24)|\ ++ ((((u32)(_val))&0x0000ff00)<<8) |\ ++ ((((u32)(_val))&0x00ff0000)>>8) |\ ++ ((((u32)(_val))&0xff000000)>>24)) ++#else ++#define H2N1BYTE(_val) ((u8)(_val)) ++#define H2N2BYTE(_val) ((u16)(_val)) ++#define H2N4BYTE(_val) ((u32)(_val)) ++#endif ++ ++// Convert from Network byte ording (big endian) to Host system specific byte ording (litten or big endia). ++// 2006.05.07, by rcnjko. ++#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN ++#define N2H1BYTE(_val) ((u8)(_val)) ++#define N2H2BYTE(_val) (((((u16)(_val))&0x00ff)<<8)|\ ++ ((((u16)(_val))&0xff00)>>8)) ++#define N2H4BYTE(_val) (((((u32)(_val))&0x000000ff)<<24)|\ ++ ((((u32)(_val))&0x0000ff00)<<8) |\ ++ ((((u32)(_val))&0x00ff0000)>>8) |\ ++ ((((u32)(_val))&0xff000000)>>24)) ++#else ++#define N2H1BYTE(_val) ((u8)(_val)) ++#define N2H2BYTE(_val) ((u16)(_val)) ++#define N2H4BYTE(_val) ((u32)(_val)) ++#endif ++ ++// ++// Example: ++// BIT_LEN_MASK_32(0) => 0x00000000 ++// BIT_LEN_MASK_32(1) => 0x00000001 ++// BIT_LEN_MASK_32(2) => 0x00000003 ++// BIT_LEN_MASK_32(32) => 0xFFFFFFFF ++// ++#define BIT_LEN_MASK_32(__BitLen) (0xFFFFFFFF >> (32 - (__BitLen))) ++// ++// Example: ++// BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 ++// BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 ++// ++#define BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) (BIT_LEN_MASK_32(__BitLen) << (__BitOffset)) ++ ++// ++// Description: ++// Return 4-byte value in host byte ordering from ++// 4-byte pointer in litten-endian system. ++// ++#define LE_P4BYTE_TO_HOST_4BYTE(__pStart) (EF4Byte(*((u32 *)(__pStart)))) ++ ++// ++// Description: ++// Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to ++// 4-byte value in host byte ordering. ++// ++#define LE_BITS_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ ( LE_P4BYTE_TO_HOST_4BYTE(__pStart) >> (__BitOffset) ) \ ++ & \ ++ BIT_LEN_MASK_32(__BitLen) \ ++ ) ++ ++// ++// Description: ++// Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering ++// and return the result in 4-byte value in host byte ordering. ++// ++#define LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P4BYTE_TO_HOST_4BYTE(__pStart) \ ++ & \ ++ ( ~BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) ) \ ++ ) ++ ++// ++// Description: ++// Set subfield of little-endian 4-byte value to specified value. ++// ++#define SET_BITS_TO_LE_4BYTE(__pStart, __BitOffset, __BitLen, __Value) \ ++ *((u32 *)(__pStart)) = \ ++ EF4Byte( \ ++ LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ( (((u32)__Value) & BIT_LEN_MASK_32(__BitLen)) << (__BitOffset) ) \ ++ ); ++ ++ ++#define BIT_LEN_MASK_16(__BitLen) \ ++ (0xFFFF >> (16 - (__BitLen))) ++ ++#define BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) \ ++ (BIT_LEN_MASK_16(__BitLen) << (__BitOffset)) ++ ++#define LE_P2BYTE_TO_HOST_2BYTE(__pStart) \ ++ (EF2Byte(*((u16 *)(__pStart)))) ++ ++#define LE_BITS_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ ( LE_P2BYTE_TO_HOST_2BYTE(__pStart) >> (__BitOffset) ) \ ++ & \ ++ BIT_LEN_MASK_16(__BitLen) \ ++ ) ++ ++#define LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P2BYTE_TO_HOST_2BYTE(__pStart) \ ++ & \ ++ ( ~BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) ) \ ++ ) ++ ++#define SET_BITS_TO_LE_2BYTE(__pStart, __BitOffset, __BitLen, __Value) \ ++ *((u16 *)(__pStart)) = \ ++ EF2Byte( \ ++ LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ( (((u16)__Value) & BIT_LEN_MASK_16(__BitLen)) << (__BitOffset) ) \ ++ ); ++ ++#define BIT_LEN_MASK_8(__BitLen) \ ++ (0xFF >> (8 - (__BitLen))) ++ ++#define BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) \ ++ (BIT_LEN_MASK_8(__BitLen) << (__BitOffset)) ++ ++#define LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ ++ (EF1Byte(*((u8 *)(__pStart)))) ++ ++#define LE_BITS_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ ( LE_P1BYTE_TO_HOST_1BYTE(__pStart) >> (__BitOffset) ) \ ++ & \ ++ BIT_LEN_MASK_8(__BitLen) \ ++ ) ++ ++#define LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ ++ ( \ ++ LE_P1BYTE_TO_HOST_1BYTE(__pStart) \ ++ & \ ++ ( ~BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) ) \ ++ ) ++ ++#define SET_BITS_TO_LE_1BYTE(__pStart, __BitOffset, __BitLen, __Value) \ ++ *((u8 *)(__pStart)) = \ ++ EF1Byte( \ ++ LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \ ++ | \ ++ ( (((u8)__Value) & BIT_LEN_MASK_8(__BitLen)) << (__BitOffset) ) \ ++ ); ++ ++#endif // #ifndef __INC_ENDIANFREE_H +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/aes.c +@@ -0,0 +1,469 @@ ++/* ++ * Cryptographic API. ++ * ++ * AES Cipher Algorithm. ++ * ++ * Based on Brian Gladman's code. ++ * ++ * Linux developers: ++ * Alexander Kjeldaas ++ * Herbert Valerio Riedel ++ * Kyle McMartin ++ * Adam J. Richter (conversion to 2.5 API). ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * --------------------------------------------------------------------------- ++ * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. ++ * All rights reserved. ++ * ++ * LICENSE TERMS ++ * ++ * The free distribution and use of this software in both source and binary ++ * form is allowed (with or without changes) provided that: ++ * ++ * 1. distributions of this source code include the above copyright ++ * notice, this list of conditions and the following disclaimer; ++ * ++ * 2. distributions in binary form include the above copyright ++ * notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other associated materials; ++ * ++ * 3. the copyright holder's name is not used to endorse products ++ * built using this software without specific written permission. ++ * ++ * ALTERNATIVELY, provided that this notice is retained in full, this product ++ * may be distributed under the terms of the GNU General Public License (GPL), ++ * in which case the provisions of the GPL apply INSTEAD OF those given above. ++ * ++ * DISCLAIMER ++ * ++ * This software is provided 'as is' with no explicit or implied warranties ++ * in respect of its properties, including, but not limited to, correctness ++ * and/or fitness for purpose. ++ * --------------------------------------------------------------------------- ++ */ ++ ++/* Some changes from the Gladman version: ++ s/RIJNDAEL(e_key)/E_KEY/g ++ s/RIJNDAEL(d_key)/D_KEY/g ++*/ ++ ++#include ++#include ++#include ++#include ++//#include ++#include "rtl_crypto.h" ++#include ++ ++#define AES_MIN_KEY_SIZE 16 ++#define AES_MAX_KEY_SIZE 32 ++ ++#define AES_BLOCK_SIZE 16 ++ ++static inline ++u32 generic_rotr32 (const u32 x, const unsigned bits) ++{ ++ const unsigned n = bits % 32; ++ return (x >> n) | (x << (32 - n)); ++} ++ ++static inline ++u32 generic_rotl32 (const u32 x, const unsigned bits) ++{ ++ const unsigned n = bits % 32; ++ return (x << n) | (x >> (32 - n)); ++} ++ ++#define rotl generic_rotl32 ++#define rotr generic_rotr32 ++ ++/* ++ * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) ++ */ ++inline static u8 ++byte(const u32 x, const unsigned n) ++{ ++ return x >> (n << 3); ++} ++ ++#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) ++#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from)) ++ ++struct aes_ctx { ++ int key_length; ++ u32 E[60]; ++ u32 D[60]; ++}; ++ ++#define E_KEY ctx->E ++#define D_KEY ctx->D ++ ++static u8 pow_tab[256] __initdata; ++static u8 log_tab[256] __initdata; ++static u8 sbx_tab[256] __initdata; ++static u8 isb_tab[256] __initdata; ++static u32 rco_tab[10]; ++static u32 ft_tab[4][256]; ++static u32 it_tab[4][256]; ++ ++static u32 fl_tab[4][256]; ++static u32 il_tab[4][256]; ++ ++static inline u8 __init ++f_mult (u8 a, u8 b) ++{ ++ u8 aa = log_tab[a], cc = aa + log_tab[b]; ++ ++ return pow_tab[cc + (cc < aa ? 1 : 0)]; ++} ++ ++#define ff_mult(a,b) (a && b ? f_mult(a, b) : 0) ++ ++#define f_rn(bo, bi, n, k) \ ++ bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ ++ ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ ++ ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ ++ ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) ++ ++#define i_rn(bo, bi, n, k) \ ++ bo[n] = it_tab[0][byte(bi[n],0)] ^ \ ++ it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ ++ it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ ++ it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) ++ ++#define ls_box(x) \ ++ ( fl_tab[0][byte(x, 0)] ^ \ ++ fl_tab[1][byte(x, 1)] ^ \ ++ fl_tab[2][byte(x, 2)] ^ \ ++ fl_tab[3][byte(x, 3)] ) ++ ++#define f_rl(bo, bi, n, k) \ ++ bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ ++ fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ ++ fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ ++ fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) ++ ++#define i_rl(bo, bi, n, k) \ ++ bo[n] = il_tab[0][byte(bi[n],0)] ^ \ ++ il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ ++ il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ ++ il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) ++ ++static void __init ++gen_tabs (void) ++{ ++ u32 i, t; ++ u8 p, q; ++ ++ /* log and power tables for GF(2**8) finite field with ++ 0x011b as modular polynomial - the simplest primitive ++ root is 0x03, used here to generate the tables */ ++ ++ for (i = 0, p = 1; i < 256; ++i) { ++ pow_tab[i] = (u8) p; ++ log_tab[p] = (u8) i; ++ ++ p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); ++ } ++ ++ log_tab[1] = 0; ++ ++ for (i = 0, p = 1; i < 10; ++i) { ++ rco_tab[i] = p; ++ ++ p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); ++ } ++ ++ for (i = 0; i < 256; ++i) { ++ p = (i ? pow_tab[255 - log_tab[i]] : 0); ++ q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); ++ p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); ++ sbx_tab[i] = p; ++ isb_tab[p] = (u8) i; ++ } ++ ++ for (i = 0; i < 256; ++i) { ++ p = sbx_tab[i]; ++ ++ t = p; ++ fl_tab[0][i] = t; ++ fl_tab[1][i] = rotl (t, 8); ++ fl_tab[2][i] = rotl (t, 16); ++ fl_tab[3][i] = rotl (t, 24); ++ ++ t = ((u32) ff_mult (2, p)) | ++ ((u32) p << 8) | ++ ((u32) p << 16) | ((u32) ff_mult (3, p) << 24); ++ ++ ft_tab[0][i] = t; ++ ft_tab[1][i] = rotl (t, 8); ++ ft_tab[2][i] = rotl (t, 16); ++ ft_tab[3][i] = rotl (t, 24); ++ ++ p = isb_tab[i]; ++ ++ t = p; ++ il_tab[0][i] = t; ++ il_tab[1][i] = rotl (t, 8); ++ il_tab[2][i] = rotl (t, 16); ++ il_tab[3][i] = rotl (t, 24); ++ ++ t = ((u32) ff_mult (14, p)) | ++ ((u32) ff_mult (9, p) << 8) | ++ ((u32) ff_mult (13, p) << 16) | ++ ((u32) ff_mult (11, p) << 24); ++ ++ it_tab[0][i] = t; ++ it_tab[1][i] = rotl (t, 8); ++ it_tab[2][i] = rotl (t, 16); ++ it_tab[3][i] = rotl (t, 24); ++ } ++} ++ ++#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) ++ ++#define imix_col(y,x) \ ++ u = star_x(x); \ ++ v = star_x(u); \ ++ w = star_x(v); \ ++ t = w ^ (x); \ ++ (y) = u ^ v ^ w; \ ++ (y) ^= rotr(u ^ t, 8) ^ \ ++ rotr(v ^ t, 16) ^ \ ++ rotr(t,24) ++ ++/* initialise the key schedule from the user supplied key */ ++ ++#define loop4(i) \ ++{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ ++ t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ ++ t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ ++ t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ ++ t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ ++} ++ ++#define loop6(i) \ ++{ t = rotr(t, 8); t = ls_box(t) ^ rco_tab[i]; \ ++ t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ ++ t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ ++ t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ ++ t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ ++ t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ ++ t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ ++} ++ ++#define loop8(i) \ ++{ t = rotr(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ ++ t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ ++ t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ ++ t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ ++ t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ ++ t = E_KEY[8 * i + 4] ^ ls_box(t); \ ++ E_KEY[8 * i + 12] = t; \ ++ t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ ++ t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ ++ t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ ++} ++ ++static int ++aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) ++{ ++ struct aes_ctx *ctx = ctx_arg; ++ u32 i, t, u, v, w; ++ ++ if (key_len != 16 && key_len != 24 && key_len != 32) { ++ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; ++ return -EINVAL; ++ } ++ ++ ctx->key_length = key_len; ++ ++ E_KEY[0] = u32_in (in_key); ++ E_KEY[1] = u32_in (in_key + 4); ++ E_KEY[2] = u32_in (in_key + 8); ++ E_KEY[3] = u32_in (in_key + 12); ++ ++ switch (key_len) { ++ case 16: ++ t = E_KEY[3]; ++ for (i = 0; i < 10; ++i) ++ loop4 (i); ++ break; ++ ++ case 24: ++ E_KEY[4] = u32_in (in_key + 16); ++ t = E_KEY[5] = u32_in (in_key + 20); ++ for (i = 0; i < 8; ++i) ++ loop6 (i); ++ break; ++ ++ case 32: ++ E_KEY[4] = u32_in (in_key + 16); ++ E_KEY[5] = u32_in (in_key + 20); ++ E_KEY[6] = u32_in (in_key + 24); ++ t = E_KEY[7] = u32_in (in_key + 28); ++ for (i = 0; i < 7; ++i) ++ loop8 (i); ++ break; ++ } ++ ++ D_KEY[0] = E_KEY[0]; ++ D_KEY[1] = E_KEY[1]; ++ D_KEY[2] = E_KEY[2]; ++ D_KEY[3] = E_KEY[3]; ++ ++ for (i = 4; i < key_len + 24; ++i) { ++ imix_col (D_KEY[i], E_KEY[i]); ++ } ++ ++ return 0; ++} ++ ++/* encrypt a block of text */ ++ ++#define f_nround(bo, bi, k) \ ++ f_rn(bo, bi, 0, k); \ ++ f_rn(bo, bi, 1, k); \ ++ f_rn(bo, bi, 2, k); \ ++ f_rn(bo, bi, 3, k); \ ++ k += 4 ++ ++#define f_lround(bo, bi, k) \ ++ f_rl(bo, bi, 0, k); \ ++ f_rl(bo, bi, 1, k); \ ++ f_rl(bo, bi, 2, k); \ ++ f_rl(bo, bi, 3, k) ++ ++static void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in) ++{ ++ const struct aes_ctx *ctx = ctx_arg; ++ u32 b0[4], b1[4]; ++ const u32 *kp = E_KEY + 4; ++ ++ b0[0] = u32_in (in) ^ E_KEY[0]; ++ b0[1] = u32_in (in + 4) ^ E_KEY[1]; ++ b0[2] = u32_in (in + 8) ^ E_KEY[2]; ++ b0[3] = u32_in (in + 12) ^ E_KEY[3]; ++ ++ if (ctx->key_length > 24) { ++ f_nround (b1, b0, kp); ++ f_nround (b0, b1, kp); ++ } ++ ++ if (ctx->key_length > 16) { ++ f_nround (b1, b0, kp); ++ f_nround (b0, b1, kp); ++ } ++ ++ f_nround (b1, b0, kp); ++ f_nround (b0, b1, kp); ++ f_nround (b1, b0, kp); ++ f_nround (b0, b1, kp); ++ f_nround (b1, b0, kp); ++ f_nround (b0, b1, kp); ++ f_nround (b1, b0, kp); ++ f_nround (b0, b1, kp); ++ f_nround (b1, b0, kp); ++ f_lround (b0, b1, kp); ++ ++ u32_out (out, b0[0]); ++ u32_out (out + 4, b0[1]); ++ u32_out (out + 8, b0[2]); ++ u32_out (out + 12, b0[3]); ++} ++ ++/* decrypt a block of text */ ++ ++#define i_nround(bo, bi, k) \ ++ i_rn(bo, bi, 0, k); \ ++ i_rn(bo, bi, 1, k); \ ++ i_rn(bo, bi, 2, k); \ ++ i_rn(bo, bi, 3, k); \ ++ k -= 4 ++ ++#define i_lround(bo, bi, k) \ ++ i_rl(bo, bi, 0, k); \ ++ i_rl(bo, bi, 1, k); \ ++ i_rl(bo, bi, 2, k); \ ++ i_rl(bo, bi, 3, k) ++ ++static void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in) ++{ ++ const struct aes_ctx *ctx = ctx_arg; ++ u32 b0[4], b1[4]; ++ const int key_len = ctx->key_length; ++ const u32 *kp = D_KEY + key_len + 20; ++ ++ b0[0] = u32_in (in) ^ E_KEY[key_len + 24]; ++ b0[1] = u32_in (in + 4) ^ E_KEY[key_len + 25]; ++ b0[2] = u32_in (in + 8) ^ E_KEY[key_len + 26]; ++ b0[3] = u32_in (in + 12) ^ E_KEY[key_len + 27]; ++ ++ if (key_len > 24) { ++ i_nround (b1, b0, kp); ++ i_nround (b0, b1, kp); ++ } ++ ++ if (key_len > 16) { ++ i_nround (b1, b0, kp); ++ i_nround (b0, b1, kp); ++ } ++ ++ i_nround (b1, b0, kp); ++ i_nround (b0, b1, kp); ++ i_nround (b1, b0, kp); ++ i_nround (b0, b1, kp); ++ i_nround (b1, b0, kp); ++ i_nround (b0, b1, kp); ++ i_nround (b1, b0, kp); ++ i_nround (b0, b1, kp); ++ i_nround (b1, b0, kp); ++ i_lround (b0, b1, kp); ++ ++ u32_out (out, b0[0]); ++ u32_out (out + 4, b0[1]); ++ u32_out (out + 8, b0[2]); ++ u32_out (out + 12, b0[3]); ++} ++ ++ ++static struct crypto_alg aes_alg = { ++ .cra_name = "aes", ++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct aes_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), ++ .cra_u = { ++ .cipher = { ++ .cia_min_keysize = AES_MIN_KEY_SIZE, ++ .cia_max_keysize = AES_MAX_KEY_SIZE, ++ .cia_setkey = aes_set_key, ++ .cia_encrypt = aes_encrypt, ++ .cia_decrypt = aes_decrypt ++ } ++ } ++}; ++ ++static int __init aes_init(void) ++{ ++ gen_tabs(); ++ return crypto_register_alg(&aes_alg); ++} ++ ++static void __exit aes_fini(void) ++{ ++ crypto_unregister_alg(&aes_alg); ++} ++ ++module_init(aes_init); ++module_exit(aes_fini); ++ ++MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); ++MODULE_LICENSE("Dual BSD/GPL"); ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/api.c +@@ -0,0 +1,246 @@ ++/* ++ * Scatterlist Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris ++ * Copyright (c) 2002 David S. Miller (davem@redhat.com) ++ * ++ * Portions derived from Cryptoapi, by Alexander Kjeldaas ++ * and Nettle, by Niels M鰈ler. ++ * ++ * 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. ++ * ++ */ ++#include "kmap_types.h" ++ ++#include ++#include ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include "internal.h" ++ ++LIST_HEAD(crypto_alg_list); ++DECLARE_RWSEM(crypto_alg_sem); ++ ++static inline int crypto_alg_get(struct crypto_alg *alg) ++{ ++ return try_inc_mod_count(alg->cra_module); ++} ++ ++static inline void crypto_alg_put(struct crypto_alg *alg) ++{ ++ if (alg->cra_module) ++ __MOD_DEC_USE_COUNT(alg->cra_module); ++} ++ ++struct crypto_alg *crypto_alg_lookup(const char *name) ++{ ++ struct crypto_alg *q, *alg = NULL; ++ ++ if (!name) ++ return NULL; ++ ++ down_read(&crypto_alg_sem); ++ ++ list_for_each_entry(q, &crypto_alg_list, cra_list) { ++ if (!(strcmp(q->cra_name, name))) { ++ if (crypto_alg_get(q)) ++ alg = q; ++ break; ++ } ++ } ++ ++ up_read(&crypto_alg_sem); ++ return alg; ++} ++ ++static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) ++{ ++ tfm->crt_flags = 0; ++ ++ switch (crypto_tfm_alg_type(tfm)) { ++ case CRYPTO_ALG_TYPE_CIPHER: ++ return crypto_init_cipher_flags(tfm, flags); ++ ++ case CRYPTO_ALG_TYPE_DIGEST: ++ return crypto_init_digest_flags(tfm, flags); ++ ++ case CRYPTO_ALG_TYPE_COMPRESS: ++ return crypto_init_compress_flags(tfm, flags); ++ ++ default: ++ break; ++ } ++ ++ BUG(); ++ return -EINVAL; ++} ++ ++static int crypto_init_ops(struct crypto_tfm *tfm) ++{ ++ switch (crypto_tfm_alg_type(tfm)) { ++ case CRYPTO_ALG_TYPE_CIPHER: ++ return crypto_init_cipher_ops(tfm); ++ ++ case CRYPTO_ALG_TYPE_DIGEST: ++ return crypto_init_digest_ops(tfm); ++ ++ case CRYPTO_ALG_TYPE_COMPRESS: ++ return crypto_init_compress_ops(tfm); ++ ++ default: ++ break; ++ } ++ ++ BUG(); ++ return -EINVAL; ++} ++ ++static void crypto_exit_ops(struct crypto_tfm *tfm) ++{ ++ switch (crypto_tfm_alg_type(tfm)) { ++ case CRYPTO_ALG_TYPE_CIPHER: ++ crypto_exit_cipher_ops(tfm); ++ break; ++ ++ case CRYPTO_ALG_TYPE_DIGEST: ++ crypto_exit_digest_ops(tfm); ++ break; ++ ++ case CRYPTO_ALG_TYPE_COMPRESS: ++ crypto_exit_compress_ops(tfm); ++ break; ++ ++ default: ++ BUG(); ++ ++ } ++} ++ ++struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ++{ ++ struct crypto_tfm *tfm = NULL; ++ struct crypto_alg *alg; ++ ++ alg = crypto_alg_mod_lookup(name); ++ if (alg == NULL) ++ goto out; ++ ++ tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL); ++ if (tfm == NULL) ++ goto out_put; ++ ++ memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); ++ ++ tfm->__crt_alg = alg; ++ ++ if (crypto_init_flags(tfm, flags)) ++ goto out_free_tfm; ++ ++ if (crypto_init_ops(tfm)) { ++ crypto_exit_ops(tfm); ++ goto out_free_tfm; ++ } ++ ++ goto out; ++ ++out_free_tfm: ++ kfree(tfm); ++ tfm = NULL; ++out_put: ++ crypto_alg_put(alg); ++out: ++ return tfm; ++} ++ ++void crypto_free_tfm(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ int size = sizeof(*tfm) + alg->cra_ctxsize; ++ ++ crypto_exit_ops(tfm); ++ crypto_alg_put(alg); ++ memset(tfm, 0, size); ++ kfree(tfm); ++} ++ ++int crypto_register_alg(struct crypto_alg *alg) ++{ ++ int ret = 0; ++ struct crypto_alg *q; ++ ++ down_write(&crypto_alg_sem); ++ ++ list_for_each_entry(q, &crypto_alg_list, cra_list) { ++ if (!(strcmp(q->cra_name, alg->cra_name))) { ++ ret = -EEXIST; ++ goto out; ++ } ++ } ++ ++ list_add_tail(&alg->cra_list, &crypto_alg_list); ++out: ++ up_write(&crypto_alg_sem); ++ return ret; ++} ++ ++int crypto_unregister_alg(struct crypto_alg *alg) ++{ ++ int ret = -ENOENT; ++ struct crypto_alg *q; ++ ++ BUG_ON(!alg->cra_module); ++ ++ down_write(&crypto_alg_sem); ++ list_for_each_entry(q, &crypto_alg_list, cra_list) { ++ if (alg == q) { ++ list_del(&alg->cra_list); ++ ret = 0; ++ goto out; ++ } ++ } ++out: ++ up_write(&crypto_alg_sem); ++ return ret; ++} ++ ++int crypto_alg_available(const char *name, u32 flags) ++{ ++ int ret = 0; ++ struct crypto_alg *alg = crypto_alg_mod_lookup(name); ++ ++ if (alg) { ++ crypto_alg_put(alg); ++ ret = 1; ++ } ++ ++ return ret; ++} ++ ++static int __init init_crypto(void) ++{ ++ printk(KERN_INFO "Initializing Cryptographic API\n"); ++ crypto_init_proc(); ++ return 0; ++} ++ ++__initcall(init_crypto); ++ ++/* ++EXPORT_SYMBOL_GPL(crypto_register_alg); ++EXPORT_SYMBOL_GPL(crypto_unregister_alg); ++EXPORT_SYMBOL_GPL(crypto_alloc_tfm); ++EXPORT_SYMBOL_GPL(crypto_free_tfm); ++EXPORT_SYMBOL_GPL(crypto_alg_available); ++*/ ++ ++EXPORT_SYMBOL_NOVERS(crypto_register_alg); ++EXPORT_SYMBOL_NOVERS(crypto_unregister_alg); ++EXPORT_SYMBOL_NOVERS(crypto_alloc_tfm); ++EXPORT_SYMBOL_NOVERS(crypto_free_tfm); ++EXPORT_SYMBOL_NOVERS(crypto_alg_available); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/arc4.c +@@ -0,0 +1,103 @@ ++/* ++ * Cryptographic API ++ * ++ * ARC4 Cipher Algorithm ++ * ++ * Jon Oberheide ++ * ++ * 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. ++ * ++ */ ++#include ++#include ++#include "rtl_crypto.h" ++ ++#define ARC4_MIN_KEY_SIZE 1 ++#define ARC4_MAX_KEY_SIZE 256 ++#define ARC4_BLOCK_SIZE 1 ++ ++struct arc4_ctx { ++ u8 S[256]; ++ u8 x, y; ++}; ++ ++static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) ++{ ++ struct arc4_ctx *ctx = ctx_arg; ++ int i, j = 0, k = 0; ++ ++ ctx->x = 1; ++ ctx->y = 0; ++ ++ for(i = 0; i < 256; i++) ++ ctx->S[i] = i; ++ ++ for(i = 0; i < 256; i++) ++ { ++ u8 a = ctx->S[i]; ++ j = (j + in_key[k] + a) & 0xff; ++ ctx->S[i] = ctx->S[j]; ++ ctx->S[j] = a; ++ if((unsigned int)++k >= key_len) ++ k = 0; ++ } ++ ++ return 0; ++} ++ ++static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in) ++{ ++ struct arc4_ctx *ctx = ctx_arg; ++ ++ u8 *const S = ctx->S; ++ u8 x = ctx->x; ++ u8 y = ctx->y; ++ u8 a, b; ++ ++ a = S[x]; ++ y = (y + a) & 0xff; ++ b = S[y]; ++ S[x] = b; ++ S[y] = a; ++ x = (x + 1) & 0xff; ++ *out++ = *in ^ S[(a + b) & 0xff]; ++ ++ ctx->x = x; ++ ctx->y = y; ++} ++ ++static struct crypto_alg arc4_alg = { ++ .cra_name = "arc4", ++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, ++ .cra_blocksize = ARC4_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct arc4_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), ++ .cra_u = { .cipher = { ++ .cia_min_keysize = ARC4_MIN_KEY_SIZE, ++ .cia_max_keysize = ARC4_MAX_KEY_SIZE, ++ .cia_setkey = arc4_set_key, ++ .cia_encrypt = arc4_crypt, ++ .cia_decrypt = arc4_crypt } } ++}; ++ ++static int __init arc4_init(void) ++{ ++ return crypto_register_alg(&arc4_alg); ++} ++ ++ ++static void __exit arc4_exit(void) ++{ ++ crypto_unregister_alg(&arc4_alg); ++} ++ ++module_init(arc4_init); ++module_exit(arc4_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); ++MODULE_AUTHOR("Jon Oberheide "); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/autoload.c +@@ -0,0 +1,40 @@ ++/* ++ * Cryptographic API. ++ * ++ * Algorithm autoloader. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++#include "kmap_types.h" ++ ++#include ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include "internal.h" ++ ++/* ++ * A far more intelligent version of this is planned. For now, just ++ * try an exact match on the name of the algorithm. ++ */ ++void crypto_alg_autoload(const char *name) ++{ ++ request_module(name); ++} ++ ++struct crypto_alg *crypto_alg_mod_lookup(const char *name) ++{ ++ struct crypto_alg *alg = crypto_alg_lookup(name); ++ if (alg == NULL) { ++ crypto_alg_autoload(name); ++ alg = crypto_alg_lookup(name); ++ } ++ return alg; ++} +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/cipher.c +@@ -0,0 +1,299 @@ ++/* ++ * Cryptographic API. ++ * ++ * Cipher operations. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++#include ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include ++#include "internal.h" ++#include "scatterwalk.h" ++ ++typedef void (cryptfn_t)(void *, u8 *, const u8 *); ++typedef void (procfn_t)(struct crypto_tfm *, u8 *, ++ u8*, cryptfn_t, int enc, void *, int); ++ ++static inline void xor_64(u8 *a, const u8 *b) ++{ ++ ((u32 *)a)[0] ^= ((u32 *)b)[0]; ++ ((u32 *)a)[1] ^= ((u32 *)b)[1]; ++} ++ ++static inline void xor_128(u8 *a, const u8 *b) ++{ ++ ((u32 *)a)[0] ^= ((u32 *)b)[0]; ++ ((u32 *)a)[1] ^= ((u32 *)b)[1]; ++ ((u32 *)a)[2] ^= ((u32 *)b)[2]; ++ ((u32 *)a)[3] ^= ((u32 *)b)[3]; ++} ++ ++ ++/* ++ * Generic encrypt/decrypt wrapper for ciphers, handles operations across ++ * multiple page boundaries by using temporary blocks. In user context, ++ * the kernel is given a chance to schedule us once per block. ++ */ ++static int crypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, cryptfn_t crfn, ++ procfn_t prfn, int enc, void *info) ++{ ++ struct scatter_walk walk_in, walk_out; ++ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); ++ u8 tmp_src[bsize]; ++ u8 tmp_dst[bsize]; ++ ++ if (!nbytes) ++ return 0; ++ ++ if (nbytes % bsize) { ++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; ++ return -EINVAL; ++ } ++ ++ scatterwalk_start(&walk_in, src); ++ scatterwalk_start(&walk_out, dst); ++ ++ for(;;) { ++ u8 *src_p, *dst_p; ++ int in_place; ++ ++ scatterwalk_map(&walk_in, 0); ++ scatterwalk_map(&walk_out, 1); ++ src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); ++ dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); ++ in_place = scatterwalk_samebuf(&walk_in, &walk_out, ++ src_p, dst_p); ++ ++ nbytes -= bsize; ++ ++ scatterwalk_copychunks(src_p, &walk_in, bsize, 0); ++ ++ prfn(tfm, dst_p, src_p, crfn, enc, info, in_place); ++ ++ scatterwalk_done(&walk_in, 0, nbytes); ++ ++ scatterwalk_copychunks(dst_p, &walk_out, bsize, 1); ++ scatterwalk_done(&walk_out, 1, nbytes); ++ ++ if (!nbytes) ++ return 0; ++ ++ crypto_yield(tfm); ++ } ++} ++ ++static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, ++ cryptfn_t fn, int enc, void *info, int in_place) ++{ ++ u8 *iv = info; ++ ++ /* Null encryption */ ++ if (!iv) ++ return; ++ ++ if (enc) { ++ tfm->crt_u.cipher.cit_xor_block(iv, src); ++ fn(crypto_tfm_ctx(tfm), dst, iv); ++ memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm)); ++ } else { ++ u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0]; ++ u8 *buf = in_place ? stack : dst; ++ ++ fn(crypto_tfm_ctx(tfm), buf, src); ++ tfm->crt_u.cipher.cit_xor_block(buf, iv); ++ memcpy(iv, src, crypto_tfm_alg_blocksize(tfm)); ++ if (buf != dst) ++ memcpy(dst, buf, crypto_tfm_alg_blocksize(tfm)); ++ } ++} ++ ++static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, ++ cryptfn_t fn, int enc, void *info, int in_place) ++{ ++ fn(crypto_tfm_ctx(tfm), dst, src); ++} ++ ++static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) ++{ ++ struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; ++ ++ if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { ++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; ++ return -EINVAL; ++ } else ++ return cia->cia_setkey(crypto_tfm_ctx(tfm), key, keylen, ++ &tfm->crt_flags); ++} ++ ++static int ecb_encrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ return crypt(tfm, dst, src, nbytes, ++ tfm->__crt_alg->cra_cipher.cia_encrypt, ++ ecb_process, 1, NULL); ++} ++ ++static int ecb_decrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ return crypt(tfm, dst, src, nbytes, ++ tfm->__crt_alg->cra_cipher.cia_decrypt, ++ ecb_process, 1, NULL); ++} ++ ++static int cbc_encrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ return crypt(tfm, dst, src, nbytes, ++ tfm->__crt_alg->cra_cipher.cia_encrypt, ++ cbc_process, 1, tfm->crt_cipher.cit_iv); ++} ++ ++static int cbc_encrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ return crypt(tfm, dst, src, nbytes, ++ tfm->__crt_alg->cra_cipher.cia_encrypt, ++ cbc_process, 1, iv); ++} ++ ++static int cbc_decrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ return crypt(tfm, dst, src, nbytes, ++ tfm->__crt_alg->cra_cipher.cia_decrypt, ++ cbc_process, 0, tfm->crt_cipher.cit_iv); ++} ++ ++static int cbc_decrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ return crypt(tfm, dst, src, nbytes, ++ tfm->__crt_alg->cra_cipher.cia_decrypt, ++ cbc_process, 0, iv); ++} ++ ++static int nocrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ return -ENOSYS; ++} ++ ++static int nocrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ return -ENOSYS; ++} ++ ++int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) ++{ ++ u32 mode = flags & CRYPTO_TFM_MODE_MASK; ++ ++ tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; ++ if (flags & CRYPTO_TFM_REQ_WEAK_KEY) ++ tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY; ++ ++ return 0; ++} ++ ++int crypto_init_cipher_ops(struct crypto_tfm *tfm) ++{ ++ int ret = 0; ++ struct cipher_tfm *ops = &tfm->crt_cipher; ++ ++ ops->cit_setkey = setkey; ++ ++ switch (tfm->crt_cipher.cit_mode) { ++ case CRYPTO_TFM_MODE_ECB: ++ ops->cit_encrypt = ecb_encrypt; ++ ops->cit_decrypt = ecb_decrypt; ++ break; ++ ++ case CRYPTO_TFM_MODE_CBC: ++ ops->cit_encrypt = cbc_encrypt; ++ ops->cit_decrypt = cbc_decrypt; ++ ops->cit_encrypt_iv = cbc_encrypt_iv; ++ ops->cit_decrypt_iv = cbc_decrypt_iv; ++ break; ++ ++ case CRYPTO_TFM_MODE_CFB: ++ ops->cit_encrypt = nocrypt; ++ ops->cit_decrypt = nocrypt; ++ ops->cit_encrypt_iv = nocrypt_iv; ++ ops->cit_decrypt_iv = nocrypt_iv; ++ break; ++ ++ case CRYPTO_TFM_MODE_CTR: ++ ops->cit_encrypt = nocrypt; ++ ops->cit_decrypt = nocrypt; ++ ops->cit_encrypt_iv = nocrypt_iv; ++ ops->cit_decrypt_iv = nocrypt_iv; ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { ++ ++ switch (crypto_tfm_alg_blocksize(tfm)) { ++ case 8: ++ ops->cit_xor_block = xor_64; ++ break; ++ ++ case 16: ++ ops->cit_xor_block = xor_128; ++ break; ++ ++ default: ++ printk(KERN_WARNING "%s: block size %u not supported\n", ++ crypto_tfm_alg_name(tfm), ++ crypto_tfm_alg_blocksize(tfm)); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); ++ ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL); ++ if (ops->cit_iv == NULL) ++ ret = -ENOMEM; ++ } ++ ++out: ++ return ret; ++} ++ ++void crypto_exit_cipher_ops(struct crypto_tfm *tfm) ++{ ++ if (tfm->crt_cipher.cit_iv) ++ kfree(tfm->crt_cipher.cit_iv); ++} +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/compress.c +@@ -0,0 +1,64 @@ ++/* ++ * Cryptographic API. ++ * ++ * Compression operations. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++#include ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include "internal.h" ++ ++static int crypto_compress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm), ++ src, slen, dst, ++ dlen); ++} ++ ++static int crypto_decompress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm), ++ src, slen, dst, ++ dlen); ++} ++ ++int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) ++{ ++ return flags ? -EINVAL : 0; ++} ++ ++int crypto_init_compress_ops(struct crypto_tfm *tfm) ++{ ++ int ret = 0; ++ struct compress_tfm *ops = &tfm->crt_compress; ++ ++ ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm)); ++ if (ret) ++ goto out; ++ ++ ops->cot_compress = crypto_compress; ++ ops->cot_decompress = crypto_decompress; ++ ++out: ++ return ret; ++} ++ ++void crypto_exit_compress_ops(struct crypto_tfm *tfm) ++{ ++ tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm)); ++} +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/crypto_compat.h +@@ -0,0 +1,90 @@ ++/* ++ * Header file to maintain compatibility among different kernel versions. ++ * ++ * Copyright (c) 2004-2006 ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++#include ++ ++static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); ++} ++ ++ ++static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); ++} ++ ++#if 0 ++/* ++ * crypto_free_tfm - Free crypto transform ++ * @tfm: Transform to free ++ * ++ * crypto_free_tfm() frees up the transform and any associated resources, ++ * then drops the refcount on the associated algorithm. ++ */ ++void crypto_free_tfm(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg; ++ int size; ++ ++ if (unlikely(!tfm)) ++ return; ++ ++ alg = tfm->__crt_alg; ++ size = sizeof(*tfm) + alg->cra_ctxsize; ++ ++ if (alg->cra_exit) ++ alg->cra_exit(tfm); ++ crypto_exit_ops(tfm); ++ crypto_mod_put(alg); ++ memset(tfm, 0, size); ++ kfree(tfm); ++} ++ ++#endif ++#if 1 ++ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ++{ ++ struct crypto_tfm *tfm = NULL; ++ int err; ++ printk("call crypto_alloc_tfm!!!\n"); ++ do { ++ struct crypto_alg *alg; ++ ++ alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); ++ err = PTR_ERR(alg); ++ if (IS_ERR(alg)) ++ continue; ++ ++ tfm = __crypto_alloc_tfm(alg, flags); ++ err = 0; ++ if (IS_ERR(tfm)) { ++ crypto_mod_put(alg); ++ err = PTR_ERR(tfm); ++ tfm = NULL; ++ } ++ } while (err == -EAGAIN && !signal_pending(current)); ++ ++ return tfm; ++} ++#endif ++//EXPORT_SYMBOL_GPL(crypto_alloc_tfm); ++//EXPORT_SYMBOL_GPL(crypto_free_tfm); ++ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/digest.c +@@ -0,0 +1,108 @@ ++/* ++ * Cryptographic API. ++ * ++ * Digest operations. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include ++#include "internal.h" ++ ++static void init(struct crypto_tfm *tfm) ++{ ++ tfm->__crt_alg->cra_digest.dia_init(crypto_tfm_ctx(tfm)); ++} ++ ++static void update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nsg; i++) { ++ ++ struct page *pg = sg[i].page; ++ unsigned int offset = sg[i].offset; ++ unsigned int l = sg[i].length; ++ ++ do { ++ unsigned int bytes_from_page = min(l, ((unsigned int) ++ (PAGE_SIZE)) - ++ offset); ++ char *p = crypto_kmap(pg, 0) + offset; ++ ++ tfm->__crt_alg->cra_digest.dia_update ++ (crypto_tfm_ctx(tfm), p, ++ bytes_from_page); ++ crypto_kunmap(p, 0); ++ crypto_yield(tfm); ++ offset = 0; ++ pg++; ++ l -= bytes_from_page; ++ } while (l > 0); ++ } ++} ++ ++static void final(struct crypto_tfm *tfm, u8 *out) ++{ ++ tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out); ++} ++ ++static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) ++{ ++ u32 flags; ++ if (tfm->__crt_alg->cra_digest.dia_setkey == NULL) ++ return -ENOSYS; ++ return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm), ++ key, keylen, &flags); ++} ++ ++static void digest(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg, u8 *out) ++{ ++ unsigned int i; ++ ++ tfm->crt_digest.dit_init(tfm); ++ ++ for (i = 0; i < nsg; i++) { ++ char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset; ++ tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), ++ p, sg[i].length); ++ crypto_kunmap(p, 0); ++ crypto_yield(tfm); ++ } ++ crypto_digest_final(tfm, out); ++} ++ ++int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) ++{ ++ return flags ? -EINVAL : 0; ++} ++ ++int crypto_init_digest_ops(struct crypto_tfm *tfm) ++{ ++ struct digest_tfm *ops = &tfm->crt_digest; ++ ++ ops->dit_init = init; ++ ops->dit_update = update; ++ ops->dit_final = final; ++ ops->dit_digest = digest; ++ ops->dit_setkey = setkey; ++ ++ return crypto_alloc_hmac_block(tfm); ++} ++ ++void crypto_exit_digest_ops(struct crypto_tfm *tfm) ++{ ++ crypto_free_hmac_block(tfm); ++} +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/dot11d.c +@@ -0,0 +1,239 @@ ++#ifdef ENABLE_DOT11D ++//----------------------------------------------------------------------------- ++// File: ++// Dot11d.c ++// ++// Description: ++// Implement 802.11d. ++// ++//----------------------------------------------------------------------------- ++ ++#include "dot11d.h" ++ ++void ++Dot11d_Init(struct ieee80211_device *ieee) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); ++ ++ pDot11dInfo->bEnabled = 0; ++ ++ pDot11dInfo->State = DOT11D_STATE_NONE; ++ pDot11dInfo->CountryIeLen = 0; ++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); ++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); ++ RESET_CIE_WATCHDOG(ieee); ++ ++ printk("Dot11d_Init()\n"); ++} ++ ++// ++// Description: ++// Reset to the state as we are just entering a regulatory domain. ++// ++void ++Dot11d_Reset(struct ieee80211_device *ieee) ++{ ++ u32 i; ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); ++#if 0 ++ if(!pDot11dInfo->bEnabled) ++ return; ++#endif ++ // Clear old channel map ++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); ++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); ++ // Set new channel map ++ for (i=1; i<=11; i++) { ++ (pDot11dInfo->channel_map)[i] = 1; ++ } ++ for (i=12; i<=14; i++) { ++ (pDot11dInfo->channel_map)[i] = 2; ++ } ++ ++ pDot11dInfo->State = DOT11D_STATE_NONE; ++ pDot11dInfo->CountryIeLen = 0; ++ RESET_CIE_WATCHDOG(ieee); ++ ++ //printk("Dot11d_Reset()\n"); ++} ++ ++// ++// Description: ++// Update country IE from Beacon or Probe Resopnse ++// and configure PHY for operation in the regulatory domain. ++// ++// TODO: ++// Configure Tx power. ++// ++// Assumption: ++// 1. IS_DOT11D_ENABLE() is TRUE. ++// 2. Input IE is an valid one. ++// ++void ++Dot11d_UpdateCountryIe( ++ struct ieee80211_device *dev, ++ u8 * pTaddr, ++ u16 CoutryIeLen, ++ u8 * pCoutryIe ++ ) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ u8 i, j, NumTriples, MaxChnlNum; ++ PCHNL_TXPOWER_TRIPLE pTriple; ++ ++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); ++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); ++ MaxChnlNum = 0; ++ NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string. ++ pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3); ++ for(i = 0; i < NumTriples; i++) ++ { ++ if(MaxChnlNum >= pTriple->FirstChnl) ++ { // It is not in a monotonically increasing order, so stop processing. ++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); ++ return; ++ } ++ if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls)) ++ { // It is not a valid set of channel id, so stop processing. ++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n"); ++ return; ++ } ++ ++ for(j = 0 ; j < pTriple->NumChnls; j++) ++ { ++ pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1; ++ pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm; ++ MaxChnlNum = pTriple->FirstChnl + j; ++ } ++ ++ pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3); ++ } ++#if 1 ++ //printk("Dot11d_UpdateCountryIe(): Channel List:\n"); ++ printk("Channel List:"); ++ for(i=1; i<= MAX_CHANNEL_NUMBER; i++) ++ if(pDot11dInfo->channel_map[i] > 0) ++ printk(" %d", i); ++ printk("\n"); ++#endif ++ ++ UPDATE_CIE_SRC(dev, pTaddr); ++ ++ pDot11dInfo->CountryIeLen = CoutryIeLen; ++ memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen); ++ pDot11dInfo->State = DOT11D_STATE_LEARNED; ++} ++ ++ ++u8 ++DOT11D_GetMaxTxPwrInDbm( ++ struct ieee80211_device *dev, ++ u8 Channel ++ ) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ u8 MaxTxPwrInDbm = 255; ++ ++ if(MAX_CHANNEL_NUMBER < Channel) ++ { ++ printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); ++ return MaxTxPwrInDbm; ++ } ++ if(pDot11dInfo->channel_map[Channel]) ++ { ++ MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; ++ } ++ ++ return MaxTxPwrInDbm; ++} ++ ++ ++void ++DOT11D_ScanComplete( ++ struct ieee80211_device * dev ++ ) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ ++ switch(pDot11dInfo->State) ++ { ++ case DOT11D_STATE_LEARNED: ++ pDot11dInfo->State = DOT11D_STATE_DONE; ++ break; ++ ++ case DOT11D_STATE_DONE: ++ if( GET_CIE_WATCHDOG(dev) == 0 ) ++ { // Reset country IE if previous one is gone. ++ Dot11d_Reset(dev); ++ } ++ break; ++ case DOT11D_STATE_NONE: ++ break; ++ } ++} ++ ++int IsLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ ++ if(MAX_CHANNEL_NUMBER < channel) ++ { ++ printk("IsLegalChannel(): Invalid Channel\n"); ++ return 0; ++ } ++ if(pDot11dInfo->channel_map[channel] > 0) ++ return 1; ++ return 0; ++} ++ ++int ToLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ u8 default_chn = 0; ++ u32 i = 0; ++ ++ for (i=1; i<= MAX_CHANNEL_NUMBER; i++) ++ { ++ if(pDot11dInfo->channel_map[i] > 0) ++ { ++ default_chn = i; ++ break; ++ } ++ } ++ ++ if(MAX_CHANNEL_NUMBER < channel) ++ { ++ printk("IsLegalChannel(): Invalid Channel\n"); ++ return default_chn; ++ } ++ ++ if(pDot11dInfo->channel_map[channel] > 0) ++ return channel; ++ ++ return default_chn; ++} ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(Dot11d_Init); ++//EXPORT_SYMBOL(Dot11d_Reset); ++//EXPORT_SYMBOL(Dot11d_UpdateCountryIe); ++//EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm); ++//EXPORT_SYMBOL(DOT11D_ScanComplete); ++//EXPORT_SYMBOL(IsLegalChannel); ++//EXPORT_SYMBOL(ToLegalChannel); ++#else ++EXPORT_SYMBOL_NOVERS(Dot11d_Init); ++EXPORT_SYMBOL_NOVERS(Dot11d_Reset); ++EXPORT_SYMBOL_NOVERS(Dot11d_UpdateCountryIe); ++EXPORT_SYMBOL_NOVERS(DOT11D_GetMaxTxPwrInDbm); ++EXPORT_SYMBOL_NOVERS(DOT11D_ScanComplete); ++EXPORT_SYMBOL_NOVERS(IsLegalChannel); ++EXPORT_SYMBOL_NOVERS(ToLegalChannel); ++#endif ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/dot11d.h +@@ -0,0 +1,102 @@ ++#ifndef __INC_DOT11D_H ++#define __INC_DOT11D_H ++ ++#ifdef ENABLE_DOT11D ++#include "ieee80211.h" ++ ++//#define ENABLE_DOT11D ++ ++//#define DOT11D_MAX_CHNL_NUM 83 ++ ++typedef struct _CHNL_TXPOWER_TRIPLE { ++ u8 FirstChnl; ++ u8 NumChnls; ++ u8 MaxTxPowerInDbm; ++}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; ++ ++typedef enum _DOT11D_STATE { ++ DOT11D_STATE_NONE = 0, ++ DOT11D_STATE_LEARNED, ++ DOT11D_STATE_DONE, ++}DOT11D_STATE; ++ ++typedef struct _RT_DOT11D_INFO { ++ //DECLARE_RT_OBJECT(RT_DOT11D_INFO); ++ ++ bool bEnabled; // dot11MultiDomainCapabilityEnabled ++ ++ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. ++ u8 CountryIeBuf[MAX_IE_LEN]; ++ u8 CountryIeSrcAddr[6]; // Source AP of the country IE. ++ u8 CountryIeWatchdog; ++ ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) ++ //u8 ChnlListLen; // #Bytes valid in ChnlList[]. ++ //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; ++ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; ++ ++ DOT11D_STATE State; ++}RT_DOT11D_INFO, *PRT_DOT11D_INFO; ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) ++#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) ++ ++#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled ++#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) ++ ++#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++ ++#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ ++ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ ++ FALSE : \ ++ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) ++ ++#define CIE_WATCHDOG_TH 1 ++#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog ++#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 ++#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) ++ ++#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) ++ ++ ++void ++Dot11d_Init( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_Reset( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_UpdateCountryIe( ++ struct ieee80211_device *dev, ++ u8 * pTaddr, ++ u16 CoutryIeLen, ++ u8 * pCoutryIe ++ ); ++ ++u8 ++DOT11D_GetMaxTxPwrInDbm( ++ struct ieee80211_device *dev, ++ u8 Channel ++ ); ++ ++void ++DOT11D_ScanComplete( ++ struct ieee80211_device * dev ++ ); ++ ++int IsLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++ ++int ToLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++#endif //ENABLE_DOT11D ++#endif // #ifndef __INC_DOT11D_H +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211.h +@@ -0,0 +1,2802 @@ ++/* ++ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 ++ * remains copyright by the original authors ++ * ++ * Portions of the merged code are based on Host AP (software wireless ++ * LAN access point) driver for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * Modified for Realtek's wi-fi cards by Andrea Merello ++ * ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++#ifndef IEEE80211_H ++#define IEEE80211_H ++#include /* ETH_ALEN */ ++#include /* ARRAY_SIZE */ ++#include ++#include ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++#include ++#else ++#include ++#include ++#endif ++#include ++#include ++ ++#include ++#include ++ ++#include "rtl819x_HT.h" ++#include "rtl819x_BA.h" ++#include "rtl819x_TS.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#ifndef bool ++typedef enum{false = 0, true} bool; ++#endif ++#endif ++ ++#ifndef IW_MODE_MONITOR ++#define IW_MODE_MONITOR 6 ++#endif ++ ++#ifndef IWEVCUSTOM ++#define IWEVCUSTOM 0x8c02 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#ifndef __bitwise ++#define __bitwise __attribute__((bitwise)) ++#endif ++typedef __u16 __le16; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,27)) ++struct iw_spy_data{ ++ /* --- Standard spy support --- */ ++ int spy_number; ++ u_char spy_address[IW_MAX_SPY][ETH_ALEN]; ++ struct iw_quality spy_stat[IW_MAX_SPY]; ++ /* --- Enhanced spy support (event) */ ++ struct iw_quality spy_thr_low; /* Low threshold */ ++ struct iw_quality spy_thr_high; /* High threshold */ ++ u_char spy_thr_under[IW_MAX_SPY]; ++}; ++#endif ++#endif ++ ++#ifndef container_of ++/** ++ * container_of - cast a member of a structure out to the containing structure ++ * ++ * @ptr: the pointer to the member. ++ * @type: the type of the container struct this is embedded in. ++ * @member: the name of the member within the struct. ++ * ++ */ ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++#endif ++ ++#define KEY_TYPE_NA 0x0 ++#define KEY_TYPE_WEP40 0x1 ++#define KEY_TYPE_TKIP 0x2 ++#define KEY_TYPE_CCMP 0x4 ++#define KEY_TYPE_WEP104 0x5 ++ ++/* added for rtl819x tx procedure */ ++#define MAX_QUEUE_SIZE 0x10 ++ ++// ++// 8190 queue mapping ++// ++#define BK_QUEUE 0 ++#define BE_QUEUE 1 ++#define VI_QUEUE 2 ++#define VO_QUEUE 3 ++#define HCCA_QUEUE 4 ++#define TXCMD_QUEUE 5 ++#define MGNT_QUEUE 6 ++#define HIGH_QUEUE 7 ++#define BEACON_QUEUE 8 ++ ++#define LOW_QUEUE BE_QUEUE ++#define NORMAL_QUEUE MGNT_QUEUE ++ ++//added by amy for ps ++#define SWRF_TIMEOUT 50 ++ ++//added by amy for LEAP related ++#define IE_CISCO_FLAG_POSITION 0x08 // Flag byte: byte 8, numbered from 0. ++#define SUPPORT_CKIP_MIC 0x08 // bit3 ++#define SUPPORT_CKIP_PK 0x10 // bit4 ++/* defined for skb cb field */ ++/* At most 28 byte */ ++typedef struct cb_desc { ++ /* Tx Desc Related flags (8-9) */ ++ u8 bLastIniPkt:1; ++ u8 bCmdOrInit:1; ++ u8 bFirstSeg:1; ++ u8 bLastSeg:1; ++ u8 bEncrypt:1; ++ u8 bTxDisableRateFallBack:1; ++ u8 bTxUseDriverAssingedRate:1; ++ u8 bHwSec:1; //indicate whether use Hw security. WB ++ ++ u8 reserved1; ++ ++ /* Tx Firmware Relaged flags (10-11)*/ ++ u8 bCTSEnable:1; ++ u8 bRTSEnable:1; ++ u8 bUseShortGI:1; ++ u8 bUseShortPreamble:1; ++ u8 bTxEnableFwCalcDur:1; ++ u8 bAMPDUEnable:1; ++ u8 bRTSSTBC:1; ++ u8 RTSSC:1; ++ ++ u8 bRTSBW:1; ++ u8 bPacketBW:1; ++ u8 bRTSUseShortPreamble:1; ++ u8 bRTSUseShortGI:1; ++ u8 bMulticast:1; ++ u8 bBroadcast:1; ++ //u8 reserved2:2; ++ u8 drv_agg_enable:1; ++ u8 reserved2:1; ++ ++ /* Tx Desc related element(12-19) */ ++ u8 rata_index; ++ u8 queue_index; ++ //u8 reserved3; ++ //u8 reserved4; ++ u16 txbuf_size; ++ //u8 reserved5; ++ u8 RATRIndex; ++ u8 reserved6; ++ u8 reserved7; ++ u8 reserved8; ++ ++ /* Tx firmware related element(20-27) */ ++ u8 data_rate; ++ u8 rts_rate; ++ u8 ampdu_factor; ++ u8 ampdu_density; ++ //u8 reserved9; ++ //u8 reserved10; ++ //u8 reserved11; ++ u8 DrvAggrNum; ++ u16 pkt_size; ++ u8 reserved12; ++}cb_desc, *pcb_desc; ++ ++/*--------------------------Define -------------------------------------------*/ ++#define MGN_1M 0x02 ++#define MGN_2M 0x04 ++#define MGN_5_5M 0x0b ++#define MGN_11M 0x16 ++ ++#define MGN_6M 0x0c ++#define MGN_9M 0x12 ++#define MGN_12M 0x18 ++#define MGN_18M 0x24 ++#define MGN_24M 0x30 ++#define MGN_36M 0x48 ++#define MGN_48M 0x60 ++#define MGN_54M 0x6c ++ ++#define MGN_MCS0 0x80 ++#define MGN_MCS1 0x81 ++#define MGN_MCS2 0x82 ++#define MGN_MCS3 0x83 ++#define MGN_MCS4 0x84 ++#define MGN_MCS5 0x85 ++#define MGN_MCS6 0x86 ++#define MGN_MCS7 0x87 ++#define MGN_MCS8 0x88 ++#define MGN_MCS9 0x89 ++#define MGN_MCS10 0x8a ++#define MGN_MCS11 0x8b ++#define MGN_MCS12 0x8c ++#define MGN_MCS13 0x8d ++#define MGN_MCS14 0x8e ++#define MGN_MCS15 0x8f ++ ++//---------------------------------------------------------------------------- ++// 802.11 Management frame Reason Code field ++//---------------------------------------------------------------------------- ++enum _ReasonCode{ ++ unspec_reason = 0x1, ++ auth_not_valid = 0x2, ++ deauth_lv_ss = 0x3, ++ inactivity = 0x4, ++ ap_overload = 0x5, ++ class2_err = 0x6, ++ class3_err = 0x7, ++ disas_lv_ss = 0x8, ++ asoc_not_auth = 0x9, ++ ++ //----MIC_CHECK ++ mic_failure = 0xe, ++ //----END MIC_CHECK ++ ++ // Reason code defined in 802.11i D10.0 p.28. ++ invalid_IE = 0x0d, ++ four_way_tmout = 0x0f, ++ two_way_tmout = 0x10, ++ IE_dismatch = 0x11, ++ invalid_Gcipher = 0x12, ++ invalid_Pcipher = 0x13, ++ invalid_AKMP = 0x14, ++ unsup_RSNIEver = 0x15, ++ invalid_RSNIE = 0x16, ++ auth_802_1x_fail= 0x17, ++ ciper_reject = 0x18, ++ ++ // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. ++ QoS_unspec = 0x20, // 32 ++ QAP_bandwidth = 0x21, // 33 ++ poor_condition = 0x22, // 34 ++ no_facility = 0x23, // 35 ++ // Where is 36??? ++ req_declined = 0x25, // 37 ++ invalid_param = 0x26, // 38 ++ req_not_honored= 0x27, // 39 ++ TS_not_created = 0x2F, // 47 ++ DL_not_allowed = 0x30, // 48 ++ dest_not_exist = 0x31, // 49 ++ dest_not_QSTA = 0x32, // 50 ++}; ++ ++ ++ ++#define aSifsTime (((priv->ieee80211->current_network.mode == IEEE_A)||(priv->ieee80211->current_network.mode == IEEE_N_24G)||(priv->ieee80211->current_network.mode == IEEE_N_5G))? 16 : 10) ++ ++#define MGMT_QUEUE_NUM 5 ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++//It should consistent with the driver_XXX.c ++// David, 2006.9.26 ++#define IEEE_PARAM_WPAX_SELECT 7 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_PROTO_WPA 1 ++#define IEEE_PROTO_RSN 2 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_WPAX_USEGROUP 0 ++#define IEEE_WPAX_WEP40 1 ++#define IEEE_WPAX_TKIP 2 ++#define IEEE_WPAX_WRAP 3 ++#define IEEE_WPAX_CCMP 4 ++#define IEEE_WPAX_WEP104 5 ++ ++#define IEEE_KEY_MGMT_IEEE8021X 1 ++#define IEEE_KEY_MGMT_PSK 2 ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++#define MAX_IE_LEN 0xff ++ ++// added for kernel conflict ++#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rsl ++#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rsl ++#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rsl ++#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rsl ++#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rsl ++#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rsl ++ ++#define ieee80211_ccmp_null ieee80211_ccmp_null_rsl ++ ++#define ieee80211_tkip_null ieee80211_tkip_null_rsl ++ ++#define ieee80211_wep_null ieee80211_wep_null_rsl ++ ++#define free_ieee80211 free_ieee80211_rsl ++#define alloc_ieee80211 alloc_ieee80211_rsl ++ ++#define ieee80211_rx ieee80211_rx_rsl ++#define ieee80211_rx_mgt ieee80211_rx_mgt_rsl ++ ++#define ieee80211_get_beacon ieee80211_get_beacon_rsl ++#define ieee80211_wake_queue ieee80211_wake_queue_rsl ++#define ieee80211_stop_queue ieee80211_stop_queue_rsl ++#define ieee80211_reset_queue ieee80211_reset_queue_rsl ++#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl ++#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl ++#define ieee80211_is_shortslot ieee80211_is_shortslot_rsl ++#define ieee80211_is_54g ieee80211_is_54g_rsl ++#define ieee80211_wpa_supplicant_ioctl ieee80211_wpa_supplicant_ioctl_rsl ++#define ieee80211_ps_tx_ack ieee80211_ps_tx_ack_rsl ++#define ieee80211_softmac_xmit ieee80211_softmac_xmit_rsl ++#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rsl ++#define notify_wx_assoc_event notify_wx_assoc_event_rsl ++#define SendDisassociation SendDisassociation_rsl ++#define ieee80211_disassociate ieee80211_disassociate_rsl ++#define ieee80211_start_send_beacons ieee80211_start_send_beacons_rsl ++#define ieee80211_stop_scan ieee80211_stop_scan_rsl ++#define ieee80211_send_probe_requests ieee80211_send_probe_requests_rsl ++#define ieee80211_softmac_scan_syncro ieee80211_softmac_scan_syncro_rsl ++#define ieee80211_start_scan_syncro ieee80211_start_scan_syncro_rsl ++ ++#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rsl ++#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rsl ++#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rsl ++#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rsl ++#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rsl ++#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rsl ++#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rsl ++#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rsl ++#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rsl ++#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rsl ++#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rsl ++#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rsl ++#define ieee80211_wx_get_name ieee80211_wx_get_name_rsl ++#define ieee80211_wx_set_power ieee80211_wx_set_power_rsl ++#define ieee80211_wx_get_power ieee80211_wx_get_power_rsl ++#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rsl ++#define ieee80211_wx_set_rts ieee80211_wx_set_rts_rsl ++#define ieee80211_wx_get_rts ieee80211_wx_get_rts_rsl ++ ++#define ieee80211_txb_free ieee80211_txb_free_rsl ++ ++#define ieee80211_wx_set_gen_ie ieee80211_wx_set_gen_ie_rsl ++#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rsl ++#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rsl ++#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rsl ++#if WIRELESS_EXT >= 18 ++#define ieee80211_wx_set_mlme ieee80211_wx_set_mlme_rsl ++#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rsl ++#define ieee80211_wx_set_encode_ext ieee80211_wx_set_encode_ext_rsl ++#define ieee80211_wx_get_encode_ext ieee80211_wx_get_encode_ext_rsl ++#endif ++ ++ ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ } u; ++}ieee_param; ++ ++ ++#if WIRELESS_EXT < 17 ++#define IW_QUAL_QUAL_INVALID 0x10 ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#define IW_QUAL_QUAL_UPDATED 0x1 ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++static inline void tq_init(struct tq_struct * task, void(*func)(void *), void *data) ++{ ++ task->routine = func; ++ task->data = data; ++ //task->next = NULL; ++ INIT_LIST_HEAD(&task->list); ++ task->sync = 0; ++} ++#endif ++ ++// linux under 2.6.9 release may not support it, so modify it for common use ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) ++//#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) ++#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) ++static inline unsigned long msleep_interruptible_rsl(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++ return timeout; ++} ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31)) ++static inline void msleep(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++} ++#endif ++#else ++#define MSECS(t) msecs_to_jiffies(t) ++#define msleep_interruptible_rsl msleep_interruptible ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++#define IEEE80211_1ADDR_LEN 10 ++#define IEEE80211_2ADDR_LEN 16 ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++ ++/* Frame control field constants */ ++#define IEEE80211_FCTL_VERS 0x0003 ++#define IEEE80211_FCTL_FTYPE 0x000c ++#define IEEE80211_FCTL_STYPE 0x00f0 ++#define IEEE80211_FCTL_FRAMETYPE 0x00fc ++#define IEEE80211_FCTL_TODS 0x0100 ++#define IEEE80211_FCTL_FROMDS 0x0200 ++#define IEEE80211_FCTL_DSTODS 0x0300 //added by david ++#define IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define IEEE80211_FCTL_RETRY 0x0800 ++#define IEEE80211_FCTL_PM 0x1000 ++#define IEEE80211_FCTL_MOREDATA 0x2000 ++#define IEEE80211_FCTL_WEP 0x4000 ++#define IEEE80211_FCTL_ORDER 0x8000 ++ ++#define IEEE80211_FTYPE_MGMT 0x0000 ++#define IEEE80211_FTYPE_CTL 0x0004 ++#define IEEE80211_FTYPE_DATA 0x0008 ++ ++/* management */ ++#define IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define IEEE80211_STYPE_BEACON 0x0080 ++#define IEEE80211_STYPE_ATIM 0x0090 ++#define IEEE80211_STYPE_DISASSOC 0x00A0 ++#define IEEE80211_STYPE_AUTH 0x00B0 ++#define IEEE80211_STYPE_DEAUTH 0x00C0 ++#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 ++ ++/* control */ ++#define IEEE80211_STYPE_PSPOLL 0x00A0 ++#define IEEE80211_STYPE_RTS 0x00B0 ++#define IEEE80211_STYPE_CTS 0x00C0 ++#define IEEE80211_STYPE_ACK 0x00D0 ++#define IEEE80211_STYPE_CFEND 0x00E0 ++#define IEEE80211_STYPE_CFENDACK 0x00F0 ++#define IEEE80211_STYPE_BLOCKACK 0x0094 ++ ++/* data */ ++#define IEEE80211_STYPE_DATA 0x0000 ++#define IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define IEEE80211_STYPE_NULLFUNC 0x0040 ++#define IEEE80211_STYPE_CFACK 0x0050 ++#define IEEE80211_STYPE_CFPOLL 0x0060 ++#define IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 ++#define IEEE80211_STYPE_QOS_NULL 0x00C0 ++ ++#define IEEE80211_SCTL_FRAG 0x000F ++#define IEEE80211_SCTL_SEQ 0xFFF0 ++ ++/* QOS control */ ++#define IEEE80211_QCTL_TID 0x000F ++ ++#define FC_QOS_BIT BIT7 ++#define IsDataFrame(pdu) ( ((pdu[0] & 0x0C)==0x08) ? true : false ) ++#define IsLegacyDataFrame(pdu) (IsDataFrame(pdu) && (!(pdu[0]&FC_QOS_BIT)) ) ++//added by wb. Is this right? ++#define IsQoSDataFrame(pframe) ((*(u16*)pframe&(IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) == (IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA)) ++#define Frame_Order(pframe) (*(u16*)pframe&IEEE80211_FCTL_ORDER) ++#define SN_LESS(a, b) (((a-b)&0x800)!=0) ++#define SN_EQUAL(a, b) (a == b) ++#define MAX_DEV_ADDR_SIZE 8 ++typedef enum _ACT_CATEGORY{ ++ ACT_CAT_QOS = 1, ++ ACT_CAT_DLS = 2, ++ ACT_CAT_BA = 3, ++ ACT_CAT_HT = 7, ++ ACT_CAT_WMM = 17, ++} ACT_CATEGORY, *PACT_CATEGORY; ++ ++typedef enum _TS_ACTION{ ++ ACT_ADDTSREQ = 0, ++ ACT_ADDTSRSP = 1, ++ ACT_DELTS = 2, ++ ACT_SCHEDULE = 3, ++} TS_ACTION, *PTS_ACTION; ++ ++typedef enum _BA_ACTION{ ++ ACT_ADDBAREQ = 0, ++ ACT_ADDBARSP = 1, ++ ACT_DELBA = 2, ++} BA_ACTION, *PBA_ACTION; ++ ++typedef enum _InitialGainOpType{ ++ IG_Backup=0, ++ IG_Restore, ++ IG_Max ++}InitialGainOpType; ++ ++/* debug macros */ ++#define CONFIG_IEEE80211_DEBUG ++#ifdef CONFIG_IEEE80211_DEBUG ++extern u32 ieee80211_debug_level; ++#define IEEE80211_DEBUG(level, fmt, args...) \ ++do { if (ieee80211_debug_level & (level)) \ ++ printk(KERN_DEBUG "ieee80211: " fmt, ## args); } while (0) ++//wb added to debug out data buf ++//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA ++#define IEEE80211_DEBUG_DATA(level, data, datalen) \ ++ do{ if ((ieee80211_debug_level & (level)) == (level)) \ ++ { \ ++ int i; \ ++ u8* pdata = (u8*) data; \ ++ printk(KERN_DEBUG "ieee80211: %s()\n", __FUNCTION__); \ ++ for(i=0; i<(int)(datalen); i++) \ ++ { \ ++ printk("%2x ", pdata[i]); \ ++ if ((i+1)%16 == 0) printk("\n"); \ ++ } \ ++ printk("\n"); \ ++ } \ ++ } while (0) ++#else ++#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) ++#define IEEE80211_DEBUG_DATA(level, data, datalen) do {} while(0) ++#endif /* CONFIG_IEEE80211_DEBUG */ ++ ++/* debug macros not dependent on CONFIG_IEEE80211_DEBUG */ ++ ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++ ++/* ++ * To use the debug system; ++ * ++ * If you are defining a new debug classification, simply add it to the #define ++ * list here in the form of: ++ * ++ * #define IEEE80211_DL_xxxx VALUE ++ * ++ * shifting value to the left one bit from the previous entry. xxxx should be ++ * the name of the classification (for example, WEP) ++ * ++ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your ++ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want ++ * to send output to that classification. ++ * ++ * To add your debug level to the list of levels seen when you perform ++ * ++ * % cat /proc/net/ipw/debug_level ++ * ++ * you simply need to add your entry to the ipw_debug_levels array. ++ * ++ * If you do not see debug_level in /proc/net/ipw then you do not have ++ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration ++ * ++ */ ++ ++#define IEEE80211_DL_INFO (1<<0) ++#define IEEE80211_DL_WX (1<<1) ++#define IEEE80211_DL_SCAN (1<<2) ++#define IEEE80211_DL_STATE (1<<3) ++#define IEEE80211_DL_MGMT (1<<4) ++#define IEEE80211_DL_FRAG (1<<5) ++#define IEEE80211_DL_EAP (1<<6) ++#define IEEE80211_DL_DROP (1<<7) ++ ++#define IEEE80211_DL_TX (1<<8) ++#define IEEE80211_DL_RX (1<<9) ++ ++#define IEEE80211_DL_HT (1<<10) //HT ++#define IEEE80211_DL_BA (1<<11) //ba ++#define IEEE80211_DL_TS (1<<12) //TS ++#define IEEE80211_DL_QOS (1<<13) ++#define IEEE80211_DL_REORDER (1<<14) ++#define IEEE80211_DL_IOT (1<<15) ++#define IEEE80211_DL_IPS (1<<16) ++#define IEEE80211_DL_TRACE (1<<29) //trace function, need to user net_ratelimit() together in order not to print too much to the screen ++#define IEEE80211_DL_DATA (1<<30) //use this flag to control whether print data buf out. ++#define IEEE80211_DL_ERR (1<<31) //always open ++#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) ++#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) ++#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) ++ ++#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) ++#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) ++#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) ++#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) ++#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) ++#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) ++#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) ++#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) ++#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) ++#define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++/* Added by Annie, 2005-11-22. */ ++#define MAX_STR_LEN 64 ++/* I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22.*/ ++#define PRINTABLE(_ch) (_ch>'!' && _ch<'~') ++#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) \ ++ if((_Comp) & level) \ ++ { \ ++ int __i; \ ++ u8 buffer[MAX_STR_LEN]; \ ++ int length = (_Len\n", _Len, buffer); \ ++ } ++#else ++#define IEEE80211_PRINT_STR(_Comp, _TitleString, _Ptr, _Len) do {} while (0) ++#endif ++ ++#include ++#include /* ARPHRD_ETHER */ ++ ++#ifndef WIRELESS_SPY ++#define WIRELESS_SPY // enable iwspy support ++#endif ++#include // new driver API ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++} __attribute__ ((packed)); ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS) ++#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) ++ ++#define WLAN_FC_GET_FRAMETYPE(fc) ((fc) & IEEE80211_FCTL_FRAMETYPE) ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++#define WLAN_AUTH_LEAP 2 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) ++#define WLAN_CAPABILITY_QOS (1<<9) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) ++ ++/* 802.11g ERP information element */ ++#define WLAN_ERP_NON_ERP_PRESENT (1<<0) ++#define WLAN_ERP_USE_PROTECTION (1<<1) ++#define WLAN_ERP_BARKER_PREAMBLE (1<<2) ++ ++/* Status codes */ ++enum ieee80211_statuscode { ++ WLAN_STATUS_SUCCESS = 0, ++ WLAN_STATUS_UNSPECIFIED_FAILURE = 1, ++ WLAN_STATUS_CAPS_UNSUPPORTED = 10, ++ WLAN_STATUS_REASSOC_NO_ASSOC = 11, ++ WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, ++ WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, ++ WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, ++ WLAN_STATUS_CHALLENGE_FAIL = 15, ++ WLAN_STATUS_AUTH_TIMEOUT = 16, ++ WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, ++ WLAN_STATUS_ASSOC_DENIED_RATES = 18, ++ /* 802.11b */ ++ WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, ++ WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, ++ WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, ++ /* 802.11h */ ++ WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, ++ WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, ++ WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, ++ /* 802.11g */ ++ WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, ++ WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, ++ /* 802.11i */ ++ WLAN_STATUS_INVALID_IE = 40, ++ WLAN_STATUS_INVALID_GROUP_CIPHER = 41, ++ WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, ++ WLAN_STATUS_INVALID_AKMP = 43, ++ WLAN_STATUS_UNSUPP_RSN_VERSION = 44, ++ WLAN_STATUS_INVALID_RSN_IE_CAP = 45, ++ WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, ++}; ++ ++/* Reason codes */ ++enum ieee80211_reasoncode { ++ WLAN_REASON_UNSPECIFIED = 1, ++ WLAN_REASON_PREV_AUTH_NOT_VALID = 2, ++ WLAN_REASON_DEAUTH_LEAVING = 3, ++ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, ++ WLAN_REASON_DISASSOC_AP_BUSY = 5, ++ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, ++ WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, ++ WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, ++ /* 802.11h */ ++ WLAN_REASON_DISASSOC_BAD_POWER = 10, ++ WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, ++ /* 802.11i */ ++ WLAN_REASON_INVALID_IE = 13, ++ WLAN_REASON_MIC_FAILURE = 14, ++ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, ++ WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, ++ WLAN_REASON_IE_DIFFERENT = 17, ++ WLAN_REASON_INVALID_GROUP_CIPHER = 18, ++ WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, ++ WLAN_REASON_INVALID_AKMP = 20, ++ WLAN_REASON_UNSUPP_RSN_VERSION = 21, ++ WLAN_REASON_INVALID_RSN_IE_CAP = 22, ++ WLAN_REASON_IEEE8021X_FAILED = 23, ++ WLAN_REASON_CIPHER_SUITE_REJECTED = 24, ++}; ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++ ++/* this is stolen and modified from the madwifi driver*/ ++#define IEEE80211_FC0_TYPE_MASK 0x0c ++#define IEEE80211_FC0_TYPE_DATA 0x08 ++#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 ++#define IEEE80211_FC0_SUBTYPE_QOS 0x80 ++ ++#define IEEE80211_QOS_HAS_SEQ(fc) \ ++ (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ ++ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num[17]; ++ u16 frag_num[17]; ++ unsigned long packet_time[17]; ++ struct list_head list; ++}; ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++#if 1 ++ u32 mac_time[2]; ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u16 rate; /* in 100 kbps */ ++ u8 received_channel; ++ u8 control; ++ u8 mask; ++ u8 freq; ++ u16 len; ++ u64 tsf; ++ u32 beacon_time; ++ u8 nic_type; ++ u16 Length; ++ // u8 DataRate; // In 0.5 Mbps ++ u8 SignalQuality; // in 0-100 index. ++ s32 RecvSignalPower; // Real power in dBm for this packet, no beautification and aggregation. ++ s8 RxPower; // in dBm Translate from PWdB ++ u8 SignalStrength; // in 0-100 index. ++ u16 bHwError:1; ++ u16 bCRC:1; ++ u16 bICV:1; ++ u16 bShortPreamble:1; ++ u16 Antenna:1; //for rtl8185 ++ u16 Decrypted:1; //for rtl8185, rtl8187 ++ u16 Wakeup:1; //for rtl8185 ++ u16 Reserved0:1; //for rtl8185 ++ u8 AGC; ++ u32 TimeStampLow; ++ u32 TimeStampHigh; ++ bool bShift; ++ bool bIsQosData; // Added by Annie, 2005-12-22. ++ u8 UserPriority; ++ ++ //1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ //1Attention Please!!!<11n or 8190 specific code should be put below this line> ++ //1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ ++ u8 RxDrvInfoSize; ++ u8 RxBufShift; ++ bool bIsAMPDU; ++ bool bFirstMPDU; ++ bool bContainHTC; ++ bool RxIs40MHzPacket; ++ u32 RxPWDBAll; ++ u8 RxMIMOSignalStrength[4]; // in 0~100 index ++ s8 RxMIMOSignalQuality[2]; ++ bool bPacketMatchBSSID; ++ bool bIsCCK; ++ bool bPacketToSelf; ++ //added by amy ++ u8* virtual_address; ++ u16 packetlength; // Total packet length: Must equal to sum of all FragLength ++ u16 fraglength; // FragLength should equal to PacketLength in non-fragment case ++ u16 fragoffset; // Data offset for this fragment ++ u16 ntotalfrag; ++ bool bisrxaggrsubframe; ++ bool bPacketBeacon; //cosa add for rssi ++ bool bToSelfBA; //cosa add for rssi ++ char cck_adc_pwdb[4]; //cosa add for rx path selection ++ u16 Seq_Num; ++#endif ++ ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ unsigned long first_frag_time; ++ unsigned int seq; ++ unsigned int last_frag; ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ unsigned int tx_unicast_frames; ++ unsigned int tx_multicast_frames; ++ unsigned int tx_fragments; ++ unsigned int tx_unicast_octets; ++ unsigned int tx_multicast_octets; ++ unsigned int tx_deferred_transmissions; ++ unsigned int tx_single_retry_frames; ++ unsigned int tx_multiple_retry_frames; ++ unsigned int tx_retry_limit_exceeded; ++ unsigned int tx_discards; ++ unsigned int rx_unicast_frames; ++ unsigned int rx_multicast_frames; ++ unsigned int rx_fragments; ++ unsigned int rx_unicast_octets; ++ unsigned int rx_multicast_octets; ++ unsigned int rx_fcs_errors; ++ unsigned int rx_discards_no_buffer; ++ unsigned int tx_discards_wrong_sa; ++ unsigned int rx_discards_undecryptable; ++ unsigned int rx_message_in_msg_fragments; ++ unsigned int rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_device; ++ ++#include "ieee80211_crypt.h" ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++#define SEC_ENCRYPT (1<<9) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define SEC_ALG_NONE 0 ++#define SEC_ALG_WEP 1 ++#define SEC_ALG_TKIP 2 ++#define SEC_ALG_CCMP 3 ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++#define SCM_KEY_LEN 32 ++#define SCM_TEMPORAL_KEY_LENGTH 16 ++ ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1, ++ encrypt:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][SCM_KEY_LEN]; ++ u8 level; ++ u16 flags; ++} __attribute__ ((packed)); ++ ++ ++/* ++ 802.11 data frame from AP ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++Total: 28-2340 bytes ++*/ ++ ++/* Management Frame Information Element Types */ ++enum ieee80211_mfie { ++ MFIE_TYPE_SSID = 0, ++ MFIE_TYPE_RATES = 1, ++ MFIE_TYPE_FH_SET = 2, ++ MFIE_TYPE_DS_SET = 3, ++ MFIE_TYPE_CF_SET = 4, ++ MFIE_TYPE_TIM = 5, ++ MFIE_TYPE_IBSS_SET = 6, ++ MFIE_TYPE_COUNTRY = 7, ++ MFIE_TYPE_HOP_PARAMS = 8, ++ MFIE_TYPE_HOP_TABLE = 9, ++ MFIE_TYPE_REQUEST = 10, ++ MFIE_TYPE_CHALLENGE = 16, ++ MFIE_TYPE_POWER_CONSTRAINT = 32, ++ MFIE_TYPE_POWER_CAPABILITY = 33, ++ MFIE_TYPE_TPC_REQUEST = 34, ++ MFIE_TYPE_TPC_REPORT = 35, ++ MFIE_TYPE_SUPP_CHANNELS = 36, ++ MFIE_TYPE_CSA = 37, ++ MFIE_TYPE_MEASURE_REQUEST = 38, ++ MFIE_TYPE_MEASURE_REPORT = 39, ++ MFIE_TYPE_QUIET = 40, ++ MFIE_TYPE_IBSS_DFS = 41, ++ MFIE_TYPE_ERP = 42, ++ MFIE_TYPE_RSN = 48, ++ MFIE_TYPE_RATES_EX = 50, ++ MFIE_TYPE_HT_CAP= 45, ++ MFIE_TYPE_HT_INFO= 61, ++ MFIE_TYPE_AIRONET=133, ++ MFIE_TYPE_GENERIC = 221, ++ MFIE_TYPE_QOS_PARAMETER = 222, ++}; ++ ++/* Minimal header; can be used for passing 802.11 frames with sufficient ++ * information to determine what type of underlying data type is actually ++ * stored in the data. */ ++struct ieee80211_hdr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_1addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_2addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_4addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u8 payload[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addrqos { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 payload[0]; ++ __le16 qos_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_4addrqos { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ __le16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u8 payload[0]; ++ __le16 qos_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_authentication { ++ struct ieee80211_hdr_3addr header; ++ __le16 algorithm; ++ __le16 transaction; ++ __le16 status; ++ /*challenge*/ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_disassoc { ++ struct ieee80211_hdr_3addr header; ++ __le16 reason; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_request { ++ struct ieee80211_hdr_3addr header; ++ /* SSID, supported rates */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_response { ++ struct ieee80211_hdr_3addr header; ++ u32 time_stamp[2]; ++ __le16 beacon_interval; ++ __le16 capability; ++ /* SSID, supported rates, FH params, DS params, ++ * CF params, IBSS params, TIM (if beacon), RSN */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++/* Alias beacon for probe_response */ ++#define ieee80211_beacon ieee80211_probe_response ++ ++struct ieee80211_assoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ __le16 capability; ++ __le16 listen_interval; ++ /* SSID, supported rates, RSN */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_reassoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ __le16 capability; ++ __le16 listen_interval; ++ u8 current_ap[ETH_ALEN]; ++ /* SSID, supported rates, RSN */ ++ struct ieee80211_info_element info_element[0]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_response_frame { ++ struct ieee80211_hdr_3addr header; ++ __le16 capability; ++ __le16 status; ++ __le16 aid; ++ struct ieee80211_info_element info_element[0]; /* supported rates */ ++} __attribute__ ((packed)); ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u8 queue_index; ++ u8 rts_included; ++ u16 reserved; ++ __le16 frag_size; ++ __le16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++#define MAX_TX_AGG_COUNT 16 ++struct ieee80211_drv_agg_txb { ++ u8 nr_drv_agg_frames; ++ struct sk_buff *tx_agg_frames[MAX_TX_AGG_COUNT]; ++}__attribute__((packed)); ++ ++#define MAX_SUBFRAME_COUNT 64 ++struct ieee80211_rxb { ++ u8 nr_subframes; ++ struct sk_buff *subframes[MAX_SUBFRAME_COUNT]; ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++}__attribute__((packed)); ++ ++typedef union _frameqos { ++ u16 shortdata; ++ u8 chardata[2]; ++ struct { ++ u16 tid:4; ++ u16 eosp:1; ++ u16 ack_policy:2; ++ u16 reserved:1; ++ u16 txop:8; ++ }field; ++}frameqos,*pframeqos; ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++ ++#define MAX_CHANNEL_NUMBER 161 ++#define IEEE80211_SOFTMAC_SCAN_TIME 100 ++//(HZ / 2) ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN 64 ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++/* QoS structure */ ++#define NETWORK_HAS_QOS_PARAMETERS (1<<3) ++#define NETWORK_HAS_QOS_INFORMATION (1<<4) ++#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ ++ NETWORK_HAS_QOS_INFORMATION) ++/* 802.11h */ ++#define NETWORK_HAS_POWER_CONSTRAINT (1<<5) ++#define NETWORK_HAS_CSA (1<<6) ++#define NETWORK_HAS_QUIET (1<<7) ++#define NETWORK_HAS_IBSS_DFS (1<<8) ++#define NETWORK_HAS_TPC_REPORT (1<<9) ++ ++#define NETWORK_HAS_ERP_VALUE (1<<10) ++ ++#define QOS_QUEUE_NUM 4 ++#define QOS_OUI_LEN 3 ++#define QOS_OUI_TYPE 2 ++#define QOS_ELEMENT_ID 221 ++#define QOS_OUI_INFO_SUB_TYPE 0 ++#define QOS_OUI_PARAM_SUB_TYPE 1 ++#define QOS_VERSION_1 1 ++#define QOS_AIFSN_MIN_VALUE 2 ++#if 1 ++struct ieee80211_qos_information_element { ++ u8 elementID; ++ u8 length; ++ u8 qui[QOS_OUI_LEN]; ++ u8 qui_type; ++ u8 qui_subtype; ++ u8 version; ++ u8 ac_info; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_ac_parameter { ++ u8 aci_aifsn; ++ u8 ecw_min_max; ++ __le16 tx_op_limit; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_parameter_info { ++ struct ieee80211_qos_information_element info_element; ++ u8 reserved; ++ struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_parameters { ++ __le16 cw_min[QOS_QUEUE_NUM]; ++ __le16 cw_max[QOS_QUEUE_NUM]; ++ u8 aifs[QOS_QUEUE_NUM]; ++ u8 flag[QOS_QUEUE_NUM]; ++ __le16 tx_op_limit[QOS_QUEUE_NUM]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_qos_data { ++ struct ieee80211_qos_parameters parameters; ++ int active; ++ int supported; ++ u8 param_count; ++ u8 old_param_count; ++}; ++ ++struct ieee80211_tim_parameters { ++ u8 tim_count; ++ u8 tim_period; ++} __attribute__ ((packed)); ++ ++//#else ++struct ieee80211_wmm_ac_param { ++ u8 ac_aci_acm_aifsn; ++ u8 ac_ecwmin_ecwmax; ++ u16 ac_txop_limit; ++}; ++ ++struct ieee80211_wmm_ts_info { ++ u8 ac_dir_tid; ++ u8 ac_up_psb; ++ u8 reserved; ++} __attribute__ ((packed)); ++ ++struct ieee80211_wmm_tspec_elem { ++ struct ieee80211_wmm_ts_info ts_info; ++ u16 norm_msdu_size; ++ u16 max_msdu_size; ++ u32 min_serv_inter; ++ u32 max_serv_inter; ++ u32 inact_inter; ++ u32 suspen_inter; ++ u32 serv_start_time; ++ u32 min_data_rate; ++ u32 mean_data_rate; ++ u32 peak_data_rate; ++ u32 max_burst_size; ++ u32 delay_bound; ++ u32 min_phy_rate; ++ u16 surp_band_allow; ++ u16 medium_time; ++}__attribute__((packed)); ++#endif ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++static const char *eap_types[] = { ++ [EAP_PACKET] = "EAP-Packet", ++ [EAPOL_START] = "EAPOL-Start", ++ [EAPOL_LOGOFF] = "EAPOL-Logoff", ++ [EAPOL_KEY] = "EAPOL-Key", ++ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" ++}; ++ ++static inline const char *eap_get_type(int type) ++{ ++ return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; ++} ++//added by amy for reorder ++static inline u8 Frame_QoSTID(u8* buf) ++{ ++ struct ieee80211_hdr_3addr *hdr; ++ u16 fc; ++ hdr = (struct ieee80211_hdr_3addr *)buf; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ return (u8)((frameqos*)(buf + (((fc & IEEE80211_FCTL_TODS)&&(fc & IEEE80211_FCTL_FROMDS))? 30 : 24)))->field.tid; ++} ++ ++//added by amy for reorder ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++struct ieee80211_softmac_stats{ ++ unsigned int rx_ass_ok; ++ unsigned int rx_ass_err; ++ unsigned int rx_probe_rq; ++ unsigned int tx_probe_rs; ++ unsigned int tx_beacons; ++ unsigned int rx_auth_rq; ++ unsigned int rx_auth_rs_ok; ++ unsigned int rx_auth_rs_err; ++ unsigned int tx_auth_rq; ++ unsigned int no_auth_rs; ++ unsigned int no_ass_rs; ++ unsigned int tx_ass_rq; ++ unsigned int rx_ass_rq; ++ unsigned int tx_probe_rq; ++ unsigned int reassoc; ++ unsigned int swtxstop; ++ unsigned int swtxawake; ++ unsigned char CurrentShowTxate; ++ unsigned char last_packet_rate; ++ unsigned int txretrycount; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __attribute__ ((packed)); ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __attribute__ ((packed)); ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 2 //1Mbps ++ ++enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; ++#define MAX_SP_Len (WMM_all_frame << 4) ++#define IEEE80211_QOS_TID 0x0f ++#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++ ++//added by David for QoS 2006/6/30 ++//#define WMM_Hang_8187 ++#ifdef WMM_Hang_8187 ++#undef WMM_Hang_8187 ++#endif ++ ++#define WME_AC_BK 0x00 ++#define WME_AC_BE 0x01 ++#define WME_AC_VI 0x02 ++#define WME_AC_VO 0x03 ++#define WME_ACI_MASK 0x03 ++#define WME_AIFSN_MASK 0x03 ++#define WME_AC_PRAM_LEN 16 ++ ++#define MAX_RECEIVE_BUFFER_SIZE 9100 ++ ++//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP ++//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) ++#if 1 ++#define UP2AC(up) ( \ ++ ((up) < 1) ? WME_AC_BE : \ ++ ((up) < 3) ? WME_AC_BK : \ ++ ((up) < 4) ? WME_AC_BE : \ ++ ((up) < 6) ? WME_AC_VI : \ ++ WME_AC_VO) ++#endif ++//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue ++#define AC2UP(_ac) ( \ ++ ((_ac) == WME_AC_VO) ? 6 : \ ++ ((_ac) == WME_AC_VI) ? 5 : \ ++ ((_ac) == WME_AC_BK) ? 1 : \ ++ 0) ++ ++#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ ++#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address plus ether type*/ ++ ++struct ether_header { ++ u8 ether_dhost[ETHER_ADDR_LEN]; ++ u8 ether_shost[ETHER_ADDR_LEN]; ++ u16 ether_type; ++} __attribute__((packed)); ++ ++#ifndef ETHERTYPE_PAE ++#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ ++#endif ++#ifndef ETHERTYPE_IP ++#define ETHERTYPE_IP 0x0800 /* IP protocol */ ++#endif ++ ++typedef struct _bss_ht{ ++ ++ bool support_ht; ++ ++ // HT related elements ++ u8 ht_cap_buf[32]; ++ u16 ht_cap_len; ++ u8 ht_info_buf[32]; ++ u16 ht_info_len; ++ ++ HT_SPEC_VER ht_spec_ver; ++ //HT_CAPABILITY_ELE bdHTCapEle; ++ //HT_INFORMATION_ELE bdHTInfoEle; ++ ++ bool aggregation; ++ bool long_slot_time; ++}bss_ht, *pbss_ht; ++ ++typedef enum _erp_t{ ++ ERP_NonERPpresent = 0x01, ++ ERP_UseProtection = 0x02, ++ ERP_BarkerPreambleMode = 0x04, ++} erp_t; ++ ++ ++struct ieee80211_network { ++ /* These entries are used to identify a unique network */ ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ /* Ensure null-terminated for any debug msgs */ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++#if 1 ++ struct ieee80211_qos_data qos_data; ++#else ++ // Qos related. Added by Annie, 2005-11-01. ++ BSS_QOS BssQos; ++#endif ++ ++ //added by amy for LEAP ++ bool bWithAironetIE; ++ bool bCkipSupported; ++ bool bCcxRmEnable; ++ u16 CcxRmState[2]; ++ // CCXv4 S59, MBSSID. ++ bool bMBssidValid; ++ u8 MBssidMask; ++ u8 MBssid[6]; ++ // CCX 2 S38, WLAN Device Version Number element. Annie, 2006-08-20. ++ bool bWithCcxVerNum; ++ u8 BssCcxVerNumber; ++ /* These are network statistics */ ++ struct ieee80211_rx_stats stats; ++ u16 capability; ++ u8 rates[MAX_RATES_LENGTH]; ++ u8 rates_len; ++ u8 rates_ex[MAX_RATES_EX_LENGTH]; ++ u8 rates_ex_len; ++ unsigned long last_scanned; ++ u8 mode; ++ u32 flags; ++ u32 last_associate; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 erp_value; ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ size_t wpa_ie_len; ++ u8 rsn_ie[MAX_WPA_IE_LEN]; ++ size_t rsn_ie_len; ++ ++ struct ieee80211_tim_parameters tim; ++ u8 dtim_period; ++ u8 dtim_data; ++ u32 last_dtim_sta_time[2]; ++ ++ //appeded for QoS ++ u8 wmm_info; ++ struct ieee80211_wmm_ac_param wmm_param[4]; ++ u8 QoS_Enable; ++#ifdef THOMAS_TURBO ++ u8 Turbo_Enable;//enable turbo mode, added by thomas ++#endif ++#ifdef ENABLE_DOT11D ++ u16 CountryIeLen; ++ u8 CountryIeBuf[MAX_IE_LEN]; ++#endif ++ // HT Related, by amy, 2008.04.29 ++ BSS_HT bssht; ++ // Add to handle broadcom AP management frame CCK rate. ++ bool broadcom_cap_exist; ++ bool ralink_cap_exist; ++ bool atheros_cap_exist; ++ bool cisco_cap_exist; ++ bool unknown_cap_exist; ++// u8 berp_info; ++ bool berp_info_valid; ++ bool buseprotection; ++ //put at the end of the structure. ++ struct list_head list; ++}; ++ ++#if 1 ++enum ieee80211_state { ++ ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++ ++}; ++#else ++enum ieee80211_state { ++ IEEE80211_UNINITIALIZED = 0, ++ IEEE80211_INITIALIZED, ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATED, ++ IEEE80211_AUTHENTICATING, ++ IEEE80211_AUTHENTICATED, ++ IEEE80211_SHUTDOWN ++}; ++#endif ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++#define CFG_IEEE80211_RTS (1<<2) ++ ++#define IEEE80211_24GHZ_MIN_CHANNEL 1 ++#define IEEE80211_24GHZ_MAX_CHANNEL 14 ++#define IEEE80211_24GHZ_CHANNELS (IEEE80211_24GHZ_MAX_CHANNEL - \ ++ IEEE80211_24GHZ_MIN_CHANNEL + 1) ++ ++#define IEEE80211_52GHZ_MIN_CHANNEL 34 ++#define IEEE80211_52GHZ_MAX_CHANNEL 165 ++#define IEEE80211_52GHZ_CHANNELS (IEEE80211_52GHZ_MAX_CHANNEL - \ ++ IEEE80211_52GHZ_MIN_CHANNEL + 1) ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) ++extern inline int is_multicast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) ++extern inline int is_broadcast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++#endif ++ ++typedef struct tx_pending_t{ ++ int frag; ++ struct ieee80211_txb *txb; ++}tx_pending_t; ++ ++typedef struct _bandwidth_autoswitch ++{ ++ long threshold_20Mhzto40Mhz; ++ long threshold_40Mhzto20Mhz; ++ bool bforced_tx20Mhz; ++ bool bautoswitch_enable; ++}bandwidth_autoswitch,*pbandwidth_autoswitch; ++ ++ ++//added by amy for order ++ ++#define REORDER_WIN_SIZE 128 ++#define REORDER_ENTRY_NUM 128 ++typedef struct _RX_REORDER_ENTRY ++{ ++ struct list_head List; ++ u16 SeqNum; ++ struct ieee80211_rxb* prxb; ++} RX_REORDER_ENTRY, *PRX_REORDER_ENTRY; ++//added by amy for order ++typedef enum _Fsync_State{ ++ Default_Fsync, ++ HW_Fsync, ++ SW_Fsync ++}Fsync_State; ++ ++// Power save mode configured. ++typedef enum _RT_PS_MODE ++{ ++ eActive, // Active/Continuous access. ++ eMaxPs, // Max power save mode. ++ eFastPs // Fast power save mode. ++}RT_PS_MODE; ++ ++typedef enum _IPS_CALLBACK_FUNCION ++{ ++ IPS_CALLBACK_NONE = 0, ++ IPS_CALLBACK_MGNT_LINK_REQUEST = 1, ++ IPS_CALLBACK_JOIN_REQUEST = 2, ++}IPS_CALLBACK_FUNCION; ++ ++typedef enum _RT_JOIN_ACTION{ ++ RT_JOIN_INFRA = 1, ++ RT_JOIN_IBSS = 2, ++ RT_START_IBSS = 3, ++ RT_NO_ACTION = 4, ++}RT_JOIN_ACTION; ++ ++typedef struct _IbssParms{ ++ u16 atimWin; ++}IbssParms, *PIbssParms; ++#define MAX_NUM_RATES 264 // Max num of support rates element: 8, Max num of ext. support rate: 255. 061122, by rcnjko. ++ ++// RF state. ++typedef enum _RT_RF_POWER_STATE ++{ ++ eRfOn, ++ eRfSleep, ++ eRfOff ++}RT_RF_POWER_STATE; ++ ++typedef struct _RT_POWER_SAVE_CONTROL ++{ ++ ++ // ++ // Inactive Power Save(IPS) : Disable RF when disconnected ++ // ++ bool bInactivePs; ++ bool bIPSModeBackup; ++ bool bSwRfProcessing; ++ RT_RF_POWER_STATE eInactivePowerState; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct InactivePsWorkItem; ++#else ++ struct tq_struct InactivePsWorkItem; ++#endif ++ struct timer_list InactivePsTimer; ++ ++ // Return point for join action ++ IPS_CALLBACK_FUNCION ReturnPoint; ++ ++ // Recored Parameters for rescheduled JoinRequest ++ bool bTmpBssDesc; ++ RT_JOIN_ACTION tmpJoinAction; ++ struct ieee80211_network tmpBssDesc; ++ ++ // Recored Parameters for rescheduled MgntLinkRequest ++ bool bTmpScanOnly; ++ bool bTmpActiveScan; ++ bool bTmpFilterHiddenAP; ++ bool bTmpUpdateParms; ++ u8 tmpSsidBuf[33]; ++ OCTET_STRING tmpSsid2Scan; ++ bool bTmpSsid2Scan; ++ u8 tmpNetworkType; ++ u8 tmpChannelNumber; ++ u16 tmpBcnPeriod; ++ u8 tmpDtimPeriod; ++ u16 tmpmCap; ++ OCTET_STRING tmpSuppRateSet; ++ u8 tmpSuppRateBuf[MAX_NUM_RATES]; ++ bool bTmpSuppRate; ++ IbssParms tmpIbpm; ++ bool bTmpIbpm; ++ ++ // ++ // Leisre Poswer Save : Disable RF if connected but traffic is not busy ++ // ++ bool bLeisurePs; ++ ++}RT_POWER_SAVE_CONTROL,*PRT_POWER_SAVE_CONTROL; ++ ++typedef u32 RT_RF_CHANGE_SOURCE; ++#define RF_CHANGE_BY_SW BIT31 ++#define RF_CHANGE_BY_HW BIT30 ++#define RF_CHANGE_BY_PS BIT29 ++#define RF_CHANGE_BY_IPS BIT28 ++#define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17. ++ ++#ifdef ENABLE_DOT11D ++typedef enum ++{ ++ COUNTRY_CODE_FCC = 0, ++ COUNTRY_CODE_IC = 1, ++ COUNTRY_CODE_ETSI = 2, ++ COUNTRY_CODE_SPAIN = 3, ++ COUNTRY_CODE_FRANCE = 4, ++ COUNTRY_CODE_MKK = 5, ++ COUNTRY_CODE_MKK1 = 6, ++ COUNTRY_CODE_ISRAEL = 7, ++ COUNTRY_CODE_TELEC, ++ COUNTRY_CODE_MIC, ++ COUNTRY_CODE_GLOBAL_DOMAIN ++}country_code_type_t; ++#endif ++ ++#define RT_MAX_LD_SLOT_NUM 10 ++typedef struct _RT_LINK_DETECT_T{ ++ ++ u32 NumRecvBcnInPeriod; ++ u32 NumRecvDataInPeriod; ++ ++ u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; // number of Rx beacon / CheckForHang_period to determine link status ++ u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; // number of Rx data / CheckForHang_period to determine link status ++ u16 SlotNum; // number of CheckForHang period to determine link status ++ u16 SlotIndex; ++ ++ u32 NumTxOkInPeriod; ++ u32 NumRxOkInPeriod; ++ bool bBusyTraffic; ++}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T; ++ ++ ++struct ieee80211_device { ++ struct net_device *dev; ++ struct ieee80211_security sec; ++ ++ //hw security related ++// u8 hwsec_support; //support? ++ u8 hwsec_active; //hw security active. ++ bool is_silent_reset; ++ bool is_roaming; ++ bool ieee_up; ++ //added by amy ++ bool bSupportRemoteWakeUp; ++ RT_PS_MODE dot11PowerSaveMode; // Power save mode configured. ++ bool actscanning; ++ bool beinretry; ++ RT_RF_POWER_STATE eRFPowerState; ++ RT_RF_CHANGE_SOURCE RfOffReason; ++ bool is_set_key; ++ //11n spec related I wonder if These info structure need to be moved out of ieee80211_device ++ ++ //11n HT below ++ PRT_HIGH_THROUGHPUT pHTInfo; ++ //struct timer_list SwBwTimer; ++// spinlock_t chnlop_spinlock; ++ spinlock_t bw_spinlock; ++ ++ spinlock_t reorder_spinlock; ++ // for HT operation rate set. we use this one for HT data rate to seperate different descriptors ++ //the way fill this is the same as in the IE ++ u8 Regdot11HTOperationalRateSet[16]; //use RATR format ++ u8 dot11HTOperationalRateSet[16]; //use RATR format ++ u8 RegHTSuppRateSet[16]; ++ u8 HTCurrentOperaRate; ++ u8 HTHighestOperaRate; ++ //wb added for rate operation mode to firmware ++ u8 bTxDisableRateFallBack; ++ u8 bTxUseDriverAssingedRate; ++ atomic_t atm_chnlop; ++ atomic_t atm_swbw; ++// u8 HTHighestOperaRate; ++// u8 HTCurrentOperaRate; ++ ++ // 802.11e and WMM Traffic Stream Info (TX) ++ struct list_head Tx_TS_Admit_List; ++ struct list_head Tx_TS_Pending_List; ++ struct list_head Tx_TS_Unused_List; ++ TX_TS_RECORD TxTsRecord[TOTAL_TS_NUM]; ++ // 802.11e and WMM Traffic Stream Info (RX) ++ struct list_head Rx_TS_Admit_List; ++ struct list_head Rx_TS_Pending_List; ++ struct list_head Rx_TS_Unused_List; ++ RX_TS_RECORD RxTsRecord[TOTAL_TS_NUM]; ++//#ifdef TO_DO_LIST ++ RX_REORDER_ENTRY RxReorderEntry[128]; ++ struct list_head RxReorder_Unused_List; ++//#endif ++ // Qos related. Added by Annie, 2005-11-01. ++// PSTA_QOS pStaQos; ++ u8 ForcedPriority; // Force per-packet priority 1~7. (default: 0, not to force it.) ++ ++ ++ /* Bookkeeping structures */ ++ struct net_device_stats stats; ++ struct ieee80211_stats ieee_stats; ++ struct ieee80211_softmac_stats softmac_stats; ++ ++ /* Probe / Beacon management */ ++ struct list_head network_free_list; ++ struct list_head network_list; ++ struct ieee80211_network *networks; ++ int scans; ++ int scan_age; ++ ++ int iw_mode; /* operating mode (IW_MODE_*) */ ++ struct iw_spy_data spy_data; ++ ++ spinlock_t lock; ++ spinlock_t wpax_suitlist_lock; ++ ++ int tx_headroom; /* Set to size of any additional room needed at front ++ * of allocated Tx SKBs */ ++ u32 config; ++ ++ /* WEP and other encryption related settings at the device level */ ++ int open_wep; /* Set to 1 to allow unencrypted frames */ ++ int auth_mode; ++ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on ++ * WEP key changes */ ++ ++ /* If the host performs {en,de}cryption, then set to 1 */ ++ int host_encrypt; ++ int host_encrypt_msdu; ++ int host_decrypt; ++ /* host performs multicast decryption */ ++ int host_mc_decrypt; ++ ++ /* host should strip IV and ICV from protected frames */ ++ /* meaningful only when hardware decryption is being used */ ++ int host_strip_iv_icv; ++ ++ int host_open_frag; ++ int host_build_iv; ++ int ieee802_1x; /* is IEEE 802.1X used */ ++ ++ /* WPA data */ ++ bool bHalfWirelessN24GMode; ++ int wpa_enabled; ++ int drop_unencrypted; ++ int tkip_countermeasures; ++ int privacy_invoked; ++ size_t wpa_ie_len; ++ u8 *wpa_ie; ++ u8 ap_mac_addr[6]; ++ u16 pairwise_key_type; ++ u16 group_key_type; ++ struct list_head crypt_deinit_list; ++ struct ieee80211_crypt_data *crypt[WEP_KEYS]; ++ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ ++ struct timer_list crypt_deinit_timer; ++ int crypt_quiesced; ++ ++ int bcrx_sta_key; /* use individual keys to override default keys even ++ * with RX of broad/multicast frames */ ++ ++ /* Fragmentation structures */ ++ // each streaming contain a entry ++ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; ++ unsigned int frag_next_idx[17]; ++ u16 fts; /* Fragmentation Threshold */ ++#define DEFAULT_RTS_THRESHOLD 2346U ++#define MIN_RTS_THRESHOLD 1 ++#define MAX_RTS_THRESHOLD 2346U ++ u16 rts; /* RTS threshold */ ++ ++ /* Association info */ ++ u8 bssid[ETH_ALEN]; ++ ++ /* This stores infos for the current network. ++ * Either the network we are associated in INFRASTRUCTURE ++ * or the network that we are creating in MASTER mode. ++ * ad-hoc is a mixture ;-). ++ * Note that in infrastructure mode, even when not associated, ++ * fields bssid and essid may be valid (if wpa_set and essid_set ++ * are true) as thy carry the value set by the user via iwconfig ++ */ ++ struct ieee80211_network current_network; ++ ++ enum ieee80211_state state; ++ ++ int short_slot; ++ int reg_mode; ++ int mode; /* A, B, G */ ++ int modulation; /* CCK, OFDM */ ++ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ ++ int abg_true; /* ABG flag */ ++ ++ /* used for forcing the ibss workqueue to terminate ++ * without wait for the syncro scan to terminate ++ */ ++ short sync_scan_hurryup; ++ ++ int perfect_rssi; ++ int worst_rssi; ++ ++ u16 prev_seq_ctl; /* used to drop duplicate frames */ ++ ++ /* map of allowed channels. 0 is dummy */ ++ // FIXME: remeber to default to a basic channel plan depending of the PHY type ++#ifdef ENABLE_DOT11D ++ void* pDot11dInfo; ++ bool bGlobalDomain; ++#else ++ int channel_map[MAX_CHANNEL_NUMBER+1]; ++#endif ++ int rate; /* current rate */ ++ int basic_rate; ++ //FIXME: pleace callback, see if redundant with softmac_features ++ short active_scan; ++ ++ /* this contains flags for selectively enable softmac support */ ++ u16 softmac_features; ++ ++ /* if the sequence control field is not filled by HW */ ++ u16 seq_ctrl[5]; ++ ++ /* association procedure transaction sequence number */ ++ u16 associate_seq; ++ ++ /* AID for RTXed association responses */ ++ u16 assoc_id; ++ ++ /* power save mode related*/ ++ u8 ack_tx_to_ieee; ++ short ps; ++ short sta_sleep; ++ int ps_timeout; ++ int ps_period; ++ struct tasklet_struct ps_task; ++ u32 ps_th; ++ u32 ps_tl; ++ ++ short raw_tx; ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ short queue_stop; ++ short scanning; ++ short proto_started; ++ ++ struct semaphore wx_sem; ++ struct semaphore scan_sem; ++ ++ spinlock_t mgmt_tx_lock; ++ spinlock_t beacon_lock; ++ ++ short beacon_txing; ++ ++ short wap_set; ++ short ssid_set; ++ ++ u8 wpax_type_set; //{added by David, 2006.9.28} ++ u32 wpax_type_notify; //{added by David, 2006.9.26} ++ ++ /* QoS related flag */ ++ char init_wmmparam_flag; ++ /* set on initialization */ ++ u8 qos_support; ++ ++ /* for discarding duplicated packets in IBSS */ ++ struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; ++ ++ /* for discarding duplicated packets in BSS */ ++ u16 last_rxseq_num[17]; /* rx seq previous per-tid */ ++ u16 last_rxfrag_num[17];/* tx frag previous per-tid */ ++ unsigned long last_packet_time[17]; ++ ++ /* for PS mode */ ++ unsigned long last_rx_ps_time; ++ ++ /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ ++ struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; ++ int mgmt_queue_head; ++ int mgmt_queue_tail; ++//{ added for rtl819x ++#define IEEE80211_QUEUE_LIMIT 128 ++ u8 AsocRetryCount; ++ unsigned int hw_header; ++ struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE]; ++ struct sk_buff_head skb_aggQ[MAX_QUEUE_SIZE]; ++ struct sk_buff_head skb_drv_aggQ[MAX_QUEUE_SIZE]; ++ u32 sta_edca_param[4]; ++ bool aggregation; ++ // Enable/Disable Rx immediate BA capability. ++ bool enable_rx_imm_BA; ++ bool bibsscoordinator; ++ ++ //+by amy for DM ,080515 ++ //Dynamic Tx power for near/far range enable/Disable , by amy , 2008-05-15 ++ bool bdynamic_txpower_enable; ++ ++ bool bCTSToSelfEnable; ++ u8 CTSToSelfTH; ++ ++ u32 fsync_time_interval; ++ u32 fsync_rate_bitmap; ++ u8 fsync_rssi_threshold; ++ bool bfsync_enable; ++ ++ u8 fsync_multiple_timeinterval; // FsyncMultipleTimeInterval * FsyncTimeInterval ++ u32 fsync_firstdiff_ratethreshold; // low threshold ++ u32 fsync_seconddiff_ratethreshold; // decrease threshold ++ Fsync_State fsync_state; ++ bool bis_any_nonbepkts; ++ //20Mhz 40Mhz AutoSwitch Threshold ++ bandwidth_autoswitch bandwidth_auto_switch; ++ //for txpower tracking ++ bool FwRWRF; ++ ++ //added by amy for AP roaming ++ RT_LINK_DETECT_T LinkDetectInfo; ++ //added by amy for ps ++ RT_POWER_SAVE_CONTROL PowerSaveControl; ++//} ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ struct tx_pending_t tx_pending; ++ ++ /* used if IEEE_SOFTMAC_ASSOCIATE is set */ ++ struct timer_list associate_timer; ++ ++ /* used if IEEE_SOFTMAC_BEACONS is set */ ++ struct timer_list beacon_timer; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct associate_complete_wq; ++ struct work_struct associate_procedure_wq; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct delayed_work softmac_scan_wq; ++ struct delayed_work associate_retry_wq; ++ struct delayed_work start_ibss_wq; ++ struct delayed_work hw_wakeup_wq; ++ struct delayed_work hw_sleep_wq; ++#else ++ struct work_struct softmac_scan_wq; ++ struct work_struct associate_retry_wq; ++ struct work_struct start_ibss_wq; ++ struct work_struct hw_wakeup_wq; ++ struct work_struct hw_sleep_wq; ++#endif ++ struct work_struct wx_sync_scan_wq; ++ struct workqueue_struct *wq; ++#else ++ /* used for periodly scan */ ++ struct timer_list scan_timer; ++ ++ struct tq_struct associate_complete_wq; ++ struct tq_struct associate_retry_wq; ++ struct tq_struct start_ibss_wq; ++ struct tq_struct associate_procedure_wq; ++ struct tq_struct softmac_scan_wq; ++ struct tq_struct wx_sync_scan_wq; ++ ++#endif ++ // Qos related. Added by Annie, 2005-11-01. ++ //STA_QOS StaQos; ++ ++ //u32 STA_EDCA_PARAM[4]; ++ //CHANNEL_ACCESS_SETTING ChannelAccessSetting; ++ ++ ++ /* Callback functions */ ++ void (*set_security)(struct net_device *dev, ++ struct ieee80211_security *sec); ++ ++ /* Used to TX data frame by using txb structs. ++ * this is not used if in the softmac_features ++ * is set the flag IEEE_SOFTMAC_TX_QUEUE ++ */ ++ int (*hard_start_xmit)(struct ieee80211_txb *txb, ++ struct net_device *dev); ++ ++ int (*reset_port)(struct net_device *dev); ++ int (*is_queue_full) (struct net_device * dev, int pri); ++ ++ int (*handle_management) (struct net_device * dev, ++ struct ieee80211_network * network, u16 type); ++ int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); ++ ++ /* Softmac-generated frames (mamagement) are TXed via this ++ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is ++ * not set. As some cards may have different HW queues that ++ * one might want to use for data and management frames ++ * the option to have two callbacks might be useful. ++ * This fucntion can't sleep. ++ */ ++ int (*softmac_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* used instead of hard_start_xmit (not softmac_hard_start_xmit) ++ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data ++ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set ++ * then also management frames are sent via this callback. ++ * This function can't sleep. ++ */ ++ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev,int rate); ++ ++ /* stops the HW queue for DATA frames. Useful to avoid ++ * waste time to TX data frame when we are reassociating ++ * This function can sleep. ++ */ ++ void (*data_hard_stop)(struct net_device *dev); ++ ++ /* OK this is complementar to data_poll_hard_stop */ ++ void (*data_hard_resume)(struct net_device *dev); ++ ++ /* ask to the driver to retune the radio . ++ * This function can sleep. the driver should ensure ++ * the radio has been swithced before return. ++ */ ++ void (*set_chan)(struct net_device *dev,short ch); ++ ++ /* These are not used if the ieee stack takes care of ++ * scanning (IEEE_SOFTMAC_SCAN feature set). ++ * In this case only the set_chan is used. ++ * ++ * The syncro version is similar to the start_scan but ++ * does not return until all channels has been scanned. ++ * this is called in user context and should sleep, ++ * it is called in a work_queue when swithcing to ad-hoc mode ++ * or in behalf of iwlist scan when the card is associated ++ * and root user ask for a scan. ++ * the fucntion stop_scan should stop both the syncro and ++ * background scanning and can sleep. ++ * The fucntion start_scan should initiate the background ++ * scanning and can't sleep. ++ */ ++ void (*scan_syncro)(struct net_device *dev); ++ void (*start_scan)(struct net_device *dev); ++ void (*stop_scan)(struct net_device *dev); ++ ++ /* indicate the driver that the link state is changed ++ * for example it may indicate the card is associated now. ++ * Driver might be interested in this to apply RX filter ++ * rules or simply light the LINK led ++ */ ++ void (*link_change)(struct net_device *dev); ++ ++ /* these two function indicates to the HW when to start ++ * and stop to send beacons. This is used when the ++ * IEEE_SOFTMAC_BEACONS is not set. For now the ++ * stop_send_bacons is NOT guaranteed to be called only ++ * after start_send_beacons. ++ */ ++ void (*start_send_beacons) (struct net_device *dev,u16 tx_rate); ++ void (*stop_send_beacons) (struct net_device *dev); ++ ++ /* power save mode related */ ++ void (*sta_wake_up) (struct net_device *dev); ++// void (*ps_request_tx_ack) (struct net_device *dev); ++ void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); ++ short (*ps_is_queue_empty) (struct net_device *dev); ++#if 0 ++ /* Typical STA methods */ ++ int (*handle_auth) (struct net_device * dev, ++ struct ieee80211_auth * auth); ++ int (*handle_deauth) (struct net_device * dev, ++ struct ieee80211_deauth * auth); ++ int (*handle_action) (struct net_device * dev, ++ struct ieee80211_action * action, ++ struct ieee80211_rx_stats * stats); ++ int (*handle_disassoc) (struct net_device * dev, ++ struct ieee80211_disassoc * assoc); ++#endif ++ int (*handle_beacon) (struct net_device * dev, struct ieee80211_beacon * beacon, struct ieee80211_network * network); ++#if 0 ++ int (*handle_probe_response) (struct net_device * dev, ++ struct ieee80211_probe_response * resp, ++ struct ieee80211_network * network); ++ int (*handle_probe_request) (struct net_device * dev, ++ struct ieee80211_probe_request * req, ++ struct ieee80211_rx_stats * stats); ++#endif ++ int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network); ++ ++#if 0 ++ /* Typical AP methods */ ++ int (*handle_assoc_request) (struct net_device * dev); ++ int (*handle_reassoc_request) (struct net_device * dev, ++ struct ieee80211_reassoc_request * req); ++#endif ++ ++ /* check whether Tx hw resouce available */ ++ short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); ++ //added by wb for HT related ++// void (*SwChnlByTimerHandler)(struct net_device *dev, int channel); ++ void (*SetBWModeHandler)(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); ++// void (*UpdateHalRATRTableHandler)(struct net_device* dev, u8* pMcsRate); ++ bool (*GetNmodeSupportBySecCfg)(struct net_device* dev); ++ void (*SetWirelessMode)(struct net_device* dev, u8 wireless_mode); ++ bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device* dev); ++ void (*InitialGainHandler)(struct net_device *dev, u8 Operation); ++ ++ /* This must be the last item so that it points to the data ++ * allocated beyond this structure by alloc_ieee80211 */ ++ u8 priv[0]; ++}; ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_N_24G (1<<4) ++#define IEEE_N_5G (1<<5) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++/* Generate a 802.11 header */ ++ ++/* Uses the channel change callback directly ++ * instead of [start/stop] scan callbacks ++ */ ++#define IEEE_SOFTMAC_SCAN (1<<2) ++ ++/* Perform authentication and association handshake */ ++#define IEEE_SOFTMAC_ASSOCIATE (1<<3) ++ ++/* Generate probe requests */ ++#define IEEE_SOFTMAC_PROBERQ (1<<4) ++ ++/* Generate respones to probe requests */ ++#define IEEE_SOFTMAC_PROBERS (1<<5) ++ ++/* The ieee802.11 stack will manages the netif queue ++ * wake/stop for the driver, taking care of 802.11 ++ * fragmentation. See softmac.c for details. */ ++#define IEEE_SOFTMAC_TX_QUEUE (1<<7) ++ ++/* Uses only the softmac_data_hard_start_xmit ++ * even for TX management frames. ++ */ ++#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) ++ ++/* Generate beacons. The stack will enqueue beacons ++ * to the card ++ */ ++#define IEEE_SOFTMAC_BEACONS (1<<6) ++ ++static inline void *ieee80211_priv(struct net_device *dev) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ return ((struct ieee80211_device *)netdev_priv(dev))->priv; ++#else ++ return ((struct ieee80211_device *)dev->priv)->priv; ++#endif ++} ++ ++extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) ++{ ++ /* ++ * It is possible for both access points and our device to support ++ * combinations of modes, so as long as there is one valid combination ++ * of ap/device supported modes, then return success ++ * ++ */ ++ if ((mode & IEEE_A) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_52GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_G) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_B) && ++ (ieee->modulation & IEEE80211_CCK_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ return 0; ++} ++ ++extern inline int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = IEEE80211_3ADDR_LEN; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case IEEE80211_FTYPE_DATA: ++ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) ++ hdrlen = IEEE80211_4ADDR_LEN; /* Addr4 */ ++ if(IEEE80211_QOS_HAS_SEQ(fc)) ++ hdrlen += 2; /* QOS ctrl*/ ++ break; ++ case IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case IEEE80211_STYPE_CTS: ++ case IEEE80211_STYPE_ACK: ++ hdrlen = IEEE80211_1ADDR_LEN; ++ break; ++ default: ++ hdrlen = IEEE80211_2ADDR_LEN; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) ++{ ++ switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { ++ case IEEE80211_1ADDR_LEN: ++ return ((struct ieee80211_hdr_1addr *)hdr)->payload; ++ case IEEE80211_2ADDR_LEN: ++ return ((struct ieee80211_hdr_2addr *)hdr)->payload; ++ case IEEE80211_3ADDR_LEN: ++ return ((struct ieee80211_hdr_3addr *)hdr)->payload; ++ case IEEE80211_4ADDR_LEN: ++ return ((struct ieee80211_hdr_4addr *)hdr)->payload; ++ } ++ return NULL; ++} ++ ++static inline int ieee80211_is_ofdm_rate(u8 rate) ++{ ++ switch (rate & ~IEEE80211_BASIC_RATE_MASK) { ++ case IEEE80211_OFDM_RATE_6MB: ++ case IEEE80211_OFDM_RATE_9MB: ++ case IEEE80211_OFDM_RATE_12MB: ++ case IEEE80211_OFDM_RATE_18MB: ++ case IEEE80211_OFDM_RATE_24MB: ++ case IEEE80211_OFDM_RATE_36MB: ++ case IEEE80211_OFDM_RATE_48MB: ++ case IEEE80211_OFDM_RATE_54MB: ++ return 1; ++ } ++ return 0; ++} ++ ++static inline int ieee80211_is_cck_rate(u8 rate) ++{ ++ switch (rate & ~IEEE80211_BASIC_RATE_MASK) { ++ case IEEE80211_CCK_RATE_1MB: ++ case IEEE80211_CCK_RATE_2MB: ++ case IEEE80211_CCK_RATE_5MB: ++ case IEEE80211_CCK_RATE_11MB: ++ return 1; ++ } ++ return 0; ++} ++ ++ ++/* ieee80211.c */ ++extern void free_ieee80211(struct net_device *dev); ++extern struct net_device *alloc_ieee80211(int sizeof_priv); ++ ++extern int ieee80211_set_encryption(struct ieee80211_device *ieee); ++ ++/* ieee80211_tx.c */ ++ ++extern int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len); ++ ++extern int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev); ++extern void ieee80211_txb_free(struct ieee80211_txb *); ++ ++ ++/* ieee80211_rx.c */ ++extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats); ++extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr_4addr *header, ++ struct ieee80211_rx_stats *stats); ++ ++/* ieee80211_wx.c */ ++extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++#if WIRELESS_EXT >= 18 ++extern int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++extern int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra); ++extern int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++#endif ++extern int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); ++ ++/* ieee80211_softmac.c */ ++extern short ieee80211_is_54g(struct ieee80211_network net); ++extern short ieee80211_is_shortslot(struct ieee80211_network net); ++extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype); ++extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); ++ ++void SendDisassociation(struct ieee80211_device *ieee, u8* asSta, u8 asRsn); ++extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); ++ ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_ibss(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_init(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_free(struct ieee80211_device *ieee); ++extern void ieee80211_associate_abort(struct ieee80211_device *ieee); ++extern void ieee80211_disassociate(struct ieee80211_device *ieee); ++extern void ieee80211_stop_scan(struct ieee80211_device *ieee); ++extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); ++extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_reset_queue(struct ieee80211_device *ieee); ++extern void ieee80211_wake_queue(struct ieee80211_device *ieee); ++extern void ieee80211_stop_queue(struct ieee80211_device *ieee); ++extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); ++extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); ++ ++extern void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee); ++ ++/* ieee80211_crypt_ccmp&tkip&wep.c */ ++extern void ieee80211_tkip_null(void); ++extern void ieee80211_wep_null(void); ++extern void ieee80211_ccmp_null(void); ++ ++/* ieee80211_softmac_wx.c */ ++ ++extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *ext); ++ ++extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra); ++ ++extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); ++ ++extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); ++#else ++ extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#endif ++ ++ ++extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_rts(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rts(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++//HT ++#define MAX_RECEIVE_BUFFER_SIZE 9100 // ++extern void HTDebugHTCapability(u8* CapIE, u8* TitleString ); ++extern void HTDebugHTInfo(u8* InfoIE, u8* TitleString); ++ ++void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); ++extern void HTUpdateDefaultSetting(struct ieee80211_device* ieee); ++extern void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u8* len, u8 isEncrypt); ++extern void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* len, u8 isEncrypt); ++extern void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg, u8* len); ++extern void HTOnAssocRsp(struct ieee80211_device *ieee); ++extern void HTInitializeHTInfo(struct ieee80211_device* ieee); ++extern void HTInitializeBssDesc(PBSS_HT pBssHT); ++extern void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); ++extern void HTUpdateSelfAndPeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork); ++extern u8 HTGetHighestMCSRate(struct ieee80211_device* ieee, u8* pMCSRateSet, u8* pMCSFilter); ++extern u8 MCS_FILTER_ALL[]; ++extern u16 MCS_DATA_RATE[2][2][77] ; ++extern u8 HTCCheck(struct ieee80211_device* ieee, u8* pFrame); ++//extern void HTSetConnectBwModeCallback(unsigned long data); ++extern void HTResetIOTSetting(PRT_HIGH_THROUGHPUT pHTInfo); ++extern bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee); ++extern u16 HTHalfMcsToDataRate(struct ieee80211_device* ieee, u8 nMcsRate); ++extern u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate); ++extern u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate); ++//function in BAPROC.c ++extern int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb); ++extern int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb); ++extern int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb); ++extern void TsInitAddBA( struct ieee80211_device* ieee, PTX_TS_RECORD pTS, u8 Policy, u8 bOverwritePending); ++extern void TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect); ++extern void BaSetupTimeOut(unsigned long data); ++extern void TxBaInactTimeout(unsigned long data); ++extern void RxBaInactTimeout(unsigned long data); ++extern void ResetBaEntry( PBA_RECORD pBA); ++//function in TS.c ++extern bool GetTs( ++ struct ieee80211_device* ieee, ++ PTS_COMMON_INFO *ppTS, ++ u8* Addr, ++ u8 TID, ++ TR_SELECT TxRxSelect, //Rx:1, Tx:0 ++ bool bAddNewTs ++ ); ++extern void TSInitialize(struct ieee80211_device *ieee); ++extern void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS); ++extern void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr); ++extern void RemoveAllTS(struct ieee80211_device* ieee); ++void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee); ++ ++extern const long ieee80211_wlan_frequencies[]; ++ ++extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) ++{ ++ ieee->scans++; ++} ++ ++extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) ++{ ++ return ieee->scans; ++} ++ ++static inline const char *escape_essid(const char *essid, u8 essid_len) { ++ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; ++ const char *s = essid; ++ char *d = escaped; ++ ++ if (ieee80211_is_empty_essid(essid, essid_len)) { ++ memcpy(escaped, "", sizeof("")); ++ return escaped; ++ } ++ ++ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); ++ while (essid_len--) { ++ if (*s == '\0') { ++ *d++ = '\\'; ++ *d++ = '0'; ++ s++; ++ } else { ++ *d++ = *s++; ++ } ++ } ++ *d = '\0'; ++ return escaped; ++} ++ ++/* For the function is more related to hardware setting, it's better to use the ++ * ieee handler to refer to it. ++ */ ++extern short check_nic_enough_desc(struct net_device *dev, int queue_index); ++extern int ieee80211_data_xmit(struct sk_buff *skb, struct net_device *dev); ++extern int ieee80211_parse_info_param(struct ieee80211_device *ieee, ++ struct ieee80211_info_element *info_element, ++ u16 length, ++ struct ieee80211_network *network, ++ struct ieee80211_rx_stats *stats); ++ ++void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index); ++#define RT_ASOC_RETRY_LIMIT 5 ++#endif /* IEEE80211_H */ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.c +@@ -0,0 +1,273 @@ ++/* ++ * Host AP crypto routines ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Portions Copyright (C) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ * ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++//MODULE_AUTHOR("Jouni Malinen"); ++//MODULE_DESCRIPTION("HostAP crypto"); ++//MODULE_LICENSE("GPL"); ++ ++struct ieee80211_crypto_alg { ++ struct list_head list; ++ struct ieee80211_crypto_ops *ops; ++}; ++ ++ ++struct ieee80211_crypto { ++ struct list_head algs; ++ spinlock_t lock; ++}; ++ ++static struct ieee80211_crypto *hcrypt; ++ ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, ++ int force) ++{ ++ struct list_head *ptr, *n; ++ struct ieee80211_crypt_data *entry; ++ ++ for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; ++ ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { ++ entry = list_entry(ptr, struct ieee80211_crypt_data, list); ++ ++ if (atomic_read(&entry->refcnt) != 0 && !force) ++ continue; ++ ++ list_del(ptr); ++ ++ if (entry->ops) { ++ entry->ops->deinit(entry->priv); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ module_put(entry->ops->owner); ++#else ++ __MOD_DEC_USE_COUNT(entry->ops->owner); ++#endif ++ } ++ kfree(entry); ++ } ++} ++ ++void ieee80211_crypt_deinit_handler(unsigned long data) ++{ ++ struct ieee80211_device *ieee = (struct ieee80211_device *)data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ieee80211_crypt_deinit_entries(ieee, 0); ++ if (!list_empty(&ieee->crypt_deinit_list)) { ++ printk(KERN_DEBUG "%s: entries remaining in delayed crypt " ++ "deletion list\n", ieee->dev->name); ++ ieee->crypt_deinit_timer.expires = jiffies + HZ; ++ add_timer(&ieee->crypt_deinit_timer); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt) ++{ ++ struct ieee80211_crypt_data *tmp; ++ unsigned long flags; ++ ++ if (*crypt == NULL) ++ return; ++ ++ tmp = *crypt; ++ *crypt = NULL; ++ ++ /* must not run ops->deinit() while there may be pending encrypt or ++ * decrypt operations. Use a list of delayed deinits to avoid needing ++ * locking. */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ list_add(&tmp->list, &ieee->crypt_deinit_list); ++ if (!timer_pending(&ieee->crypt_deinit_timer)) { ++ ieee->crypt_deinit_timer.expires = jiffies + HZ; ++ add_timer(&ieee->crypt_deinit_timer); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) ++{ ++ unsigned long flags; ++ struct ieee80211_crypto_alg *alg; ++ ++ if (hcrypt == NULL) ++ return -1; ++ ++ alg = kmalloc(sizeof(*alg), GFP_KERNEL); ++ if (alg == NULL) ++ return -ENOMEM; ++ ++ memset(alg, 0, sizeof(*alg)); ++ alg->ops = ops; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ list_add(&alg->list, &hcrypt->algs); ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", ++ ops->name); ++ ++ return 0; ++} ++ ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) ++{ ++ unsigned long flags; ++ struct list_head *ptr; ++ struct ieee80211_crypto_alg *del_alg = NULL; ++ ++ if (hcrypt == NULL) ++ return -1; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ if (alg->ops == ops) { ++ list_del(&alg->list); ++ del_alg = alg; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ if (del_alg) { ++ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " ++ "'%s'\n", ops->name); ++ kfree(del_alg); ++ } ++ ++ return del_alg ? 0 : -1; ++} ++ ++ ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name) ++{ ++ unsigned long flags; ++ struct list_head *ptr; ++ struct ieee80211_crypto_alg *found_alg = NULL; ++ ++ if (hcrypt == NULL) ++ return NULL; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ if (strcmp(alg->ops->name, name) == 0) { ++ found_alg = alg; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ if (found_alg) ++ return found_alg->ops; ++ else ++ return NULL; ++} ++ ++ ++static void * ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } ++static void ieee80211_crypt_null_deinit(void *priv) {} ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_null = { ++ .name = "NULL", ++ .init = ieee80211_crypt_null_init, ++ .deinit = ieee80211_crypt_null_deinit, ++ .encrypt_mpdu = NULL, ++ .decrypt_mpdu = NULL, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = NULL, ++ .get_key = NULL, ++ .extra_prefix_len = 0, ++ .extra_postfix_len = 0, ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_init(void) ++{ ++ int ret = -ENOMEM; ++ ++ hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); ++ if (!hcrypt) ++ goto out; ++ ++ memset(hcrypt, 0, sizeof(*hcrypt)); ++ INIT_LIST_HEAD(&hcrypt->algs); ++ spin_lock_init(&hcrypt->lock); ++ ++ ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); ++ if (ret < 0) { ++ kfree(hcrypt); ++ hcrypt = NULL; ++ } ++out: ++ return ret; ++} ++ ++ ++void __exit ieee80211_crypto_deinit(void) ++{ ++ struct list_head *ptr, *n; ++ ++ if (hcrypt == NULL) ++ return; ++ ++ for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; ++ ptr = n, n = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ list_del(ptr); ++ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " ++ "'%s' (deinit)\n", alg->ops->name); ++ kfree(alg); ++ } ++ ++ kfree(hcrypt); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); ++//EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); ++//EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); ++ ++//EXPORT_SYMBOL(ieee80211_register_crypto_ops); ++//EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); ++//EXPORT_SYMBOL(ieee80211_get_crypto_ops); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_entries); ++EXPORT_SYMBOL_NOVERS(ieee80211_crypt_deinit_handler); ++EXPORT_SYMBOL_NOVERS(ieee80211_crypt_delayed_deinit); ++ ++EXPORT_SYMBOL_NOVERS(ieee80211_register_crypto_ops); ++EXPORT_SYMBOL_NOVERS(ieee80211_unregister_crypto_ops); ++EXPORT_SYMBOL_NOVERS(ieee80211_get_crypto_ops); ++#endif ++ ++//module_init(ieee80211_crypto_init); ++//module_exit(ieee80211_crypto_deinit); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt.h +@@ -0,0 +1,93 @@ ++/* ++ * Original code based on Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++/* ++ * This file defines the interface to the ieee80211 crypto module. ++ */ ++#ifndef IEEE80211_CRYPT_H ++#define IEEE80211_CRYPT_H ++ ++#include ++ ++struct ieee80211_crypto_ops { ++ const char *name; ++ ++ /* init new crypto context (e.g., allocate private data space, ++ * select IV, etc.); returns NULL on failure or pointer to allocated ++ * private data on success */ ++ void * (*init)(int keyidx); ++ ++ /* deinitialize crypto context and free allocated private data */ ++ void (*deinit)(void *priv); ++ ++ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return ++ * value from decrypt_mpdu is passed as the keyidx value for ++ * decrypt_msdu. skb must have enough head and tail room for the ++ * encryption; if not, error will be returned; these functions are ++ * called for all MPDUs (i.e., fragments). ++ */ ++ int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ ++ /* These functions are called for full MSDUs, i.e. full frames. ++ * These can be NULL if full MSDU operations are not needed. */ ++ int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, ++ void *priv); ++ ++ int (*set_key)(void *key, int len, u8 *seq, void *priv); ++ int (*get_key)(void *key, int len, u8 *seq, void *priv); ++ ++ /* procfs handler for printing out key information and possible ++ * statistics */ ++ char * (*print_stats)(char *p, void *priv); ++ ++ /* maximum number of bytes added by encryption; encrypt buf is ++ * allocated with extra_prefix_len bytes, copy of in_buf, and ++ * extra_postfix_len; encrypt need not use all this space, but ++ * the result must start at the beginning of the buffer and correct ++ * length must be returned */ ++ int extra_prefix_len, extra_postfix_len; ++ ++ struct module *owner; ++}; ++ ++struct ieee80211_crypt_data { ++ struct list_head list; /* delayed deletion list */ ++ struct ieee80211_crypto_ops *ops; ++ void *priv; ++ atomic_t refcnt; ++}; ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); ++void ieee80211_crypt_deinit_handler(unsigned long); ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,31)) ++#define crypto_alloc_tfm crypto_alloc_tfm_rsl ++#define crypto_free_tfm crypto_free_tfm_rsl ++#endif ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_ccmp.c +@@ -0,0 +1,534 @@ ++/* ++ * Host AP crypt: host-based CCMP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2003-2004, Jouni Malinen ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include ++#else ++ #include ++#endif ++//#include ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: CCMP"); ++MODULE_LICENSE("GPL"); ++ ++#ifndef OPENSUSE_SLED ++#define OPENSUSE_SLED 0 ++#endif ++ ++#define AES_BLOCK_LEN 16 ++#define CCMP_HDR_LEN 8 ++#define CCMP_MIC_LEN 8 ++#define CCMP_TK_LEN 16 ++#define CCMP_PN_LEN 6 ++ ++struct ieee80211_ccmp_data { ++ u8 key[CCMP_TK_LEN]; ++ int key_set; ++ ++ u8 tx_pn[CCMP_PN_LEN]; ++ u8 rx_pn[CCMP_PN_LEN]; ++ ++ u32 dot11RSNAStatsCCMPFormatErrors; ++ u32 dot11RSNAStatsCCMPReplays; ++ u32 dot11RSNAStatsCCMPDecryptErrors; ++ ++ int key_idx; ++ ++ struct crypto_tfm *tfm; ++ ++ /* scratch buffers for virt_to_page() (crypto API) */ ++ u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], ++ tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; ++ u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; ++}; ++ ++void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, ++ const u8 pt[16], u8 ct[16]) ++{ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ struct scatterlist src, dst; ++ ++ src.page = virt_to_page(pt); ++ src.offset = offset_in_page(pt); ++ src.length = AES_BLOCK_LEN; ++ ++ dst.page = virt_to_page(ct); ++ dst.offset = offset_in_page(ct); ++ dst.length = AES_BLOCK_LEN; ++ ++ crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); ++#else ++ crypto_cipher_encrypt_one((void*)tfm, ct, pt); ++#endif ++} ++ ++static void * ieee80211_ccmp_init(int key_idx) ++{ ++ struct ieee80211_ccmp_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = key_idx; ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ priv->tfm = crypto_alloc_tfm("aes", 0); ++ if (priv->tfm == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " ++ "crypto API aes\n"); ++ goto fail; ++ } ++ #else ++ priv->tfm = (void*)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " ++ "crypto API aes\n"); ++ priv->tfm = NULL; ++ goto fail; ++ } ++ #endif ++ return priv; ++ ++fail: ++ if (priv) { ++ if (priv->tfm) ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_free_tfm(priv->tfm); ++ #else ++ crypto_free_cipher((void*)priv->tfm); ++ #endif ++ kfree(priv); ++ } ++ ++ return NULL; ++} ++ ++ ++static void ieee80211_ccmp_deinit(void *priv) ++{ ++ struct ieee80211_ccmp_data *_priv = priv; ++ if (_priv && _priv->tfm) ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ crypto_free_tfm(_priv->tfm); ++#else ++ crypto_free_cipher((void*)_priv->tfm); ++#endif ++ kfree(priv); ++} ++ ++ ++static inline void xor_block(u8 *b, u8 *a, size_t len) ++{ ++ int i; ++ for (i = 0; i < len; i++) ++ b[i] ^= a[i]; ++} ++ ++ ++ ++static void ccmp_init_blocks(struct crypto_tfm *tfm, ++ struct ieee80211_hdr_4addr *hdr, ++ u8 *pn, size_t dlen, u8 *b0, u8 *auth, ++ u8 *s0) ++{ ++ u8 *pos, qc = 0; ++ size_t aad_len; ++ u16 fc; ++ int a4_included, qc_included; ++ u8 aad[2 * AES_BLOCK_LEN]; ++ ++ fc = le16_to_cpu(hdr->frame_ctl); ++ a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); ++ /* ++ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && ++ (WLAN_FC_GET_STYPE(fc) & 0x08)); ++ */ ++ // fixed by David :2006.9.6 ++ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && ++ (WLAN_FC_GET_STYPE(fc) & 0x80)); ++ aad_len = 22; ++ if (a4_included) ++ aad_len += 6; ++ if (qc_included) { ++ pos = (u8 *) &hdr->addr4; ++ if (a4_included) ++ pos += 6; ++ qc = *pos & 0x0f; ++ aad_len += 2; ++ } ++ /* CCM Initial Block: ++ * Flag (Include authentication header, M=3 (8-octet MIC), ++ * L=1 (2-octet Dlen)) ++ * Nonce: 0x00 | A2 | PN ++ * Dlen */ ++ b0[0] = 0x59; ++ b0[1] = qc; ++ memcpy(b0 + 2, hdr->addr2, ETH_ALEN); ++ memcpy(b0 + 8, pn, CCMP_PN_LEN); ++ b0[14] = (dlen >> 8) & 0xff; ++ b0[15] = dlen & 0xff; ++ ++ /* AAD: ++ * FC with bits 4..6 and 11..13 masked to zero; 14 is always one ++ * A1 | A2 | A3 ++ * SC with bits 4..15 (seq#) masked to zero ++ * A4 (if present) ++ * QC (if present) ++ */ ++ pos = (u8 *) hdr; ++ aad[0] = 0; /* aad_len >> 8 */ ++ aad[1] = aad_len & 0xff; ++ aad[2] = pos[0] & 0x8f; ++ aad[3] = pos[1] & 0xc7; ++ memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); ++ pos = (u8 *) &hdr->seq_ctl; ++ aad[22] = pos[0] & 0x0f; ++ aad[23] = 0; /* all bits masked */ ++ memset(aad + 24, 0, 8); ++ if (a4_included) ++ memcpy(aad + 24, hdr->addr4, ETH_ALEN); ++ if (qc_included) { ++ aad[a4_included ? 30 : 24] = qc; ++ /* rest of QC masked */ ++ } ++ ++ /* Start with the first block and AAD */ ++ ieee80211_ccmp_aes_encrypt(tfm, b0, auth); ++ xor_block(auth, aad, AES_BLOCK_LEN); ++ ieee80211_ccmp_aes_encrypt(tfm, auth, auth); ++ xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); ++ ieee80211_ccmp_aes_encrypt(tfm, auth, auth); ++ b0[0] &= 0x07; ++ b0[14] = b0[15] = 0; ++ ieee80211_ccmp_aes_encrypt(tfm, b0, s0); ++} ++ ++ ++ ++static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_ccmp_data *key = priv; ++ int data_len, i; ++ u8 *pos; ++ struct ieee80211_hdr_4addr *hdr; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ ++ if (skb_headroom(skb) < CCMP_HDR_LEN || ++ skb_tailroom(skb) < CCMP_MIC_LEN || ++ skb->len < hdr_len) ++ return -1; ++ ++ data_len = skb->len - hdr_len; ++ pos = skb_push(skb, CCMP_HDR_LEN); ++ memmove(pos, pos + CCMP_HDR_LEN, hdr_len); ++ pos += hdr_len; ++// mic = skb_put(skb, CCMP_MIC_LEN); ++ ++ i = CCMP_PN_LEN - 1; ++ while (i >= 0) { ++ key->tx_pn[i]++; ++ if (key->tx_pn[i] != 0) ++ break; ++ i--; ++ } ++ ++ *pos++ = key->tx_pn[5]; ++ *pos++ = key->tx_pn[4]; ++ *pos++ = 0; ++ *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; ++ *pos++ = key->tx_pn[3]; ++ *pos++ = key->tx_pn[2]; ++ *pos++ = key->tx_pn[1]; ++ *pos++ = key->tx_pn[0]; ++ ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ if (!tcb_desc->bHwSec) ++ { ++ int blocks, last, len; ++ u8 *mic; ++ u8 *b0 = key->tx_b0; ++ u8 *b = key->tx_b; ++ u8 *e = key->tx_e; ++ u8 *s0 = key->tx_s0; ++ ++ //mic is moved to here by john ++ mic = skb_put(skb, CCMP_MIC_LEN); ++ ++ ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); ++ ++ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; ++ last = data_len % AES_BLOCK_LEN; ++ ++ for (i = 1; i <= blocks; i++) { ++ len = (i == blocks && last) ? last : AES_BLOCK_LEN; ++ /* Authentication */ ++ xor_block(b, pos, len); ++ ieee80211_ccmp_aes_encrypt(key->tfm, b, b); ++ /* Encryption, with counter */ ++ b0[14] = (i >> 8) & 0xff; ++ b0[15] = i & 0xff; ++ ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); ++ xor_block(pos, e, len); ++ pos += len; ++ } ++ ++ for (i = 0; i < CCMP_MIC_LEN; i++) ++ mic[i] = b[i] ^ s0[i]; ++ } ++ return 0; ++} ++ ++ ++static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_ccmp_data *key = priv; ++ u8 keyidx, *pos; ++ struct ieee80211_hdr_4addr *hdr; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ u8 pn[6]; ++ ++ if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { ++ key->dot11RSNAStatsCCMPFormatErrors++; ++ return -1; ++ } ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ pos = skb->data + hdr_len; ++ keyidx = pos[3]; ++ if (!(keyidx & (1 << 5))) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: received packet without ExtIV" ++ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ key->dot11RSNAStatsCCMPFormatErrors++; ++ return -2; ++ } ++ keyidx >>= 6; ++ if (key->key_idx != keyidx) { ++ printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " ++ "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); ++ return -6; ++ } ++ if (!key->key_set) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT ++ " with keyid=%d that does not have a configured" ++ " key\n", MAC_ARG(hdr->addr2), keyidx); ++ } ++ return -3; ++ } ++ ++ pn[0] = pos[7]; ++ pn[1] = pos[6]; ++ pn[2] = pos[5]; ++ pn[3] = pos[4]; ++ pn[4] = pos[1]; ++ pn[5] = pos[0]; ++ pos += 8; ++ ++ if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT ++ " previous PN %02x%02x%02x%02x%02x%02x " ++ "received PN %02x%02x%02x%02x%02x%02x\n", ++ MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), ++ MAC_ARG(pn)); ++ } ++ key->dot11RSNAStatsCCMPReplays++; ++ return -4; ++ } ++ if (!tcb_desc->bHwSec) ++ { ++ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; ++ u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; ++ u8 *b0 = key->rx_b0; ++ u8 *b = key->rx_b; ++ u8 *a = key->rx_a; ++ int i, blocks, last, len; ++ ++ ++ ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); ++ xor_block(mic, b, CCMP_MIC_LEN); ++ ++ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; ++ last = data_len % AES_BLOCK_LEN; ++ ++ for (i = 1; i <= blocks; i++) { ++ len = (i == blocks && last) ? last : AES_BLOCK_LEN; ++ /* Decrypt, with counter */ ++ b0[14] = (i >> 8) & 0xff; ++ b0[15] = i & 0xff; ++ ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); ++ xor_block(pos, b, len); ++ /* Authentication */ ++ xor_block(a, pos, len); ++ ieee80211_ccmp_aes_encrypt(key->tfm, a, a); ++ pos += len; ++ } ++ ++ if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: decrypt failed: STA=" ++ MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ key->dot11RSNAStatsCCMPDecryptErrors++; ++ return -5; ++ } ++ ++ memcpy(key->rx_pn, pn, CCMP_PN_LEN); ++ } ++ /* Remove hdr and MIC */ ++ memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); ++ skb_pull(skb, CCMP_HDR_LEN); ++ skb_trim(skb, skb->len - CCMP_MIC_LEN); ++ ++ return keyidx; ++} ++ ++ ++static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_ccmp_data *data = priv; ++ int keyidx; ++ struct crypto_tfm *tfm = data->tfm; ++ ++ keyidx = data->key_idx; ++ memset(data, 0, sizeof(*data)); ++ data->key_idx = keyidx; ++ data->tfm = tfm; ++ if (len == CCMP_TK_LEN) { ++ memcpy(data->key, key, CCMP_TK_LEN); ++ data->key_set = 1; ++ if (seq) { ++ data->rx_pn[0] = seq[5]; ++ data->rx_pn[1] = seq[4]; ++ data->rx_pn[2] = seq[3]; ++ data->rx_pn[3] = seq[2]; ++ data->rx_pn[4] = seq[1]; ++ data->rx_pn[5] = seq[0]; ++ } ++ crypto_cipher_setkey((void*)data->tfm, data->key, CCMP_TK_LEN); ++ } else if (len == 0) ++ data->key_set = 0; ++ else ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_ccmp_data *data = priv; ++ ++ if (len < CCMP_TK_LEN) ++ return -1; ++ ++ if (!data->key_set) ++ return 0; ++ memcpy(key, data->key, CCMP_TK_LEN); ++ ++ if (seq) { ++ seq[0] = data->tx_pn[5]; ++ seq[1] = data->tx_pn[4]; ++ seq[2] = data->tx_pn[3]; ++ seq[3] = data->tx_pn[2]; ++ seq[4] = data->tx_pn[1]; ++ seq[5] = data->tx_pn[0]; ++ } ++ ++ return CCMP_TK_LEN; ++} ++ ++ ++static char * ieee80211_ccmp_print_stats(char *p, void *priv) ++{ ++ struct ieee80211_ccmp_data *ccmp = priv; ++ p += sprintf(p, "key[%d] alg=CCMP key_set=%d " ++ "tx_pn=%02x%02x%02x%02x%02x%02x " ++ "rx_pn=%02x%02x%02x%02x%02x%02x " ++ "format_errors=%d replays=%d decrypt_errors=%d\n", ++ ccmp->key_idx, ccmp->key_set, ++ MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), ++ ccmp->dot11RSNAStatsCCMPFormatErrors, ++ ccmp->dot11RSNAStatsCCMPReplays, ++ ccmp->dot11RSNAStatsCCMPDecryptErrors); ++ ++ return p; ++} ++ ++void ieee80211_ccmp_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { ++ .name = "CCMP", ++ .init = ieee80211_ccmp_init, ++ .deinit = ieee80211_ccmp_deinit, ++ .encrypt_mpdu = ieee80211_ccmp_encrypt, ++ .decrypt_mpdu = ieee80211_ccmp_decrypt, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = ieee80211_ccmp_set_key, ++ .get_key = ieee80211_ccmp_get_key, ++ .print_stats = ieee80211_ccmp_print_stats, ++ .extra_prefix_len = CCMP_HDR_LEN, ++ .extra_postfix_len = CCMP_MIC_LEN, ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_ccmp_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); ++} ++ ++ ++void __exit ieee80211_crypto_ccmp_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_ccmp_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null); ++#endif ++ ++//module_init(ieee80211_crypto_ccmp_init); ++//module_exit(ieee80211_crypto_ccmp_exit); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_tkip.c +@@ -0,0 +1,1034 @@ ++/* ++ * Host AP crypt: host-based TKIP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2003-2004, Jouni Malinen ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) ++//#include "crypto_compat.h" ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++//#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include ++#else ++ #include ++#endif ++ ++#include ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: TKIP"); ++MODULE_LICENSE("GPL"); ++ ++#ifndef OPENSUSE_SLED ++#define OPENSUSE_SLED 0 ++#endif ++ ++struct ieee80211_tkip_data { ++#define TKIP_KEY_LEN 32 ++ u8 key[TKIP_KEY_LEN]; ++ int key_set; ++ ++ u32 tx_iv32; ++ u16 tx_iv16; ++ u16 tx_ttak[5]; ++ int tx_phase1_done; ++ ++ u32 rx_iv32; ++ u16 rx_iv16; ++ u16 rx_ttak[5]; ++ int rx_phase1_done; ++ u32 rx_iv32_new; ++ u16 rx_iv16_new; ++ ++ u32 dot11RSNAStatsTKIPReplays; ++ u32 dot11RSNAStatsTKIPICVErrors; ++ u32 dot11RSNAStatsTKIPLocalMICFailures; ++ ++ int key_idx; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) ++ struct crypto_blkcipher *rx_tfm_arc4; ++ struct crypto_hash *rx_tfm_michael; ++ struct crypto_blkcipher *tx_tfm_arc4; ++ struct crypto_hash *tx_tfm_michael; ++#else ++ struct crypto_tfm *tx_tfm_arc4; ++ struct crypto_tfm *tx_tfm_michael; ++ struct crypto_tfm *rx_tfm_arc4; ++ struct crypto_tfm *rx_tfm_michael; ++#endif ++ /* scratch buffers for virt_to_page() (crypto API) */ ++ u8 rx_hdr[16], tx_hdr[16]; ++}; ++ ++static void * ieee80211_tkip_init(int key_idx) ++{ ++ struct ieee80211_tkip_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = key_idx; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ priv->tx_tfm_arc4 = crypto_alloc_tfm("arc4", 0); ++ if (priv->tx_tfm_arc4 == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ ++ priv->tx_tfm_michael = crypto_alloc_tfm("michael_mic", 0); ++ if (priv->tx_tfm_michael == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ goto fail; ++ } ++ ++ priv->rx_tfm_arc4 = crypto_alloc_tfm("arc4", 0); ++ if (priv->rx_tfm_arc4 == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ ++ priv->rx_tfm_michael = crypto_alloc_tfm("michael_mic", 0); ++ if (priv->rx_tfm_michael == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ goto fail; ++ } ++#else ++ priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm_arc4)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ priv->tx_tfm_arc4 = NULL; ++ goto fail; ++ } ++ ++ priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm_michael)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ priv->tx_tfm_michael = NULL; ++ goto fail; ++ } ++ ++ priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm_arc4)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ priv->rx_tfm_arc4 = NULL; ++ goto fail; ++ } ++ ++ priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm_michael)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ priv->rx_tfm_michael = NULL; ++ goto fail; ++ } ++#endif ++ return priv; ++ ++fail: ++ if (priv) { ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ if (priv->tx_tfm_michael) ++ crypto_free_tfm(priv->tx_tfm_michael); ++ if (priv->tx_tfm_arc4) ++ crypto_free_tfm(priv->tx_tfm_arc4); ++ if (priv->rx_tfm_michael) ++ crypto_free_tfm(priv->rx_tfm_michael); ++ if (priv->rx_tfm_arc4) ++ crypto_free_tfm(priv->rx_tfm_arc4); ++ ++#else ++ if (priv->tx_tfm_michael) ++ crypto_free_hash(priv->tx_tfm_michael); ++ if (priv->tx_tfm_arc4) ++ crypto_free_blkcipher(priv->tx_tfm_arc4); ++ if (priv->rx_tfm_michael) ++ crypto_free_hash(priv->rx_tfm_michael); ++ if (priv->rx_tfm_arc4) ++ crypto_free_blkcipher(priv->rx_tfm_arc4); ++#endif ++ kfree(priv); ++ } ++ ++ return NULL; ++} ++ ++ ++static void ieee80211_tkip_deinit(void *priv) ++{ ++ struct ieee80211_tkip_data *_priv = priv; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ if (_priv->tx_tfm_michael) ++ crypto_free_tfm(_priv->tx_tfm_michael); ++ if (_priv->tx_tfm_arc4) ++ crypto_free_tfm(_priv->tx_tfm_arc4); ++ if (_priv->rx_tfm_michael) ++ crypto_free_tfm(_priv->rx_tfm_michael); ++ if (_priv->rx_tfm_arc4) ++ crypto_free_tfm(_priv->rx_tfm_arc4); ++#else ++ if (_priv) { ++ if (_priv->tx_tfm_michael) ++ crypto_free_hash(_priv->tx_tfm_michael); ++ if (_priv->tx_tfm_arc4) ++ crypto_free_blkcipher(_priv->tx_tfm_arc4); ++ if (_priv->rx_tfm_michael) ++ crypto_free_hash(_priv->rx_tfm_michael); ++ if (_priv->rx_tfm_arc4) ++ crypto_free_blkcipher(_priv->rx_tfm_arc4); ++ } ++#endif ++ kfree(priv); ++} ++ ++ ++static inline u16 RotR1(u16 val) ++{ ++ return (val >> 1) | (val << 15); ++} ++ ++ ++static inline u8 Lo8(u16 val) ++{ ++ return val & 0xff; ++} ++ ++ ++static inline u8 Hi8(u16 val) ++{ ++ return val >> 8; ++} ++ ++ ++static inline u16 Lo16(u32 val) ++{ ++ return val & 0xffff; ++} ++ ++ ++static inline u16 Hi16(u32 val) ++{ ++ return val >> 16; ++} ++ ++ ++static inline u16 Mk16(u8 hi, u8 lo) ++{ ++ return lo | (((u16) hi) << 8); ++} ++ ++ ++static inline u16 Mk16_le(u16 *v) ++{ ++ return le16_to_cpu(*v); ++} ++ ++ ++static const u16 Sbox[256] = ++{ ++ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, ++ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, ++ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, ++ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, ++ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, ++ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, ++ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, ++ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, ++ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, ++ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, ++ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, ++ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, ++ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, ++ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, ++ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, ++ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, ++ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, ++ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, ++ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, ++ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, ++ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, ++ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, ++ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, ++ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, ++ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, ++ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, ++ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, ++ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, ++ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, ++ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, ++ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, ++ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, ++}; ++ ++ ++static inline u16 _S_(u16 v) ++{ ++ u16 t = Sbox[Hi8(v)]; ++ return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); ++} ++ ++ ++#define PHASE1_LOOP_COUNT 8 ++ ++ ++static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) ++{ ++ int i, j; ++ ++ /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ ++ TTAK[0] = Lo16(IV32); ++ TTAK[1] = Hi16(IV32); ++ TTAK[2] = Mk16(TA[1], TA[0]); ++ TTAK[3] = Mk16(TA[3], TA[2]); ++ TTAK[4] = Mk16(TA[5], TA[4]); ++ ++ for (i = 0; i < PHASE1_LOOP_COUNT; i++) { ++ j = 2 * (i & 1); ++ TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); ++ TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); ++ TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); ++ TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); ++ TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; ++ } ++} ++ ++ ++static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, ++ u16 IV16) ++{ ++ /* Make temporary area overlap WEP seed so that the final copy can be ++ * avoided on little endian hosts. */ ++ u16 *PPK = (u16 *) &WEPSeed[4]; ++ ++ /* Step 1 - make copy of TTAK and bring in TSC */ ++ PPK[0] = TTAK[0]; ++ PPK[1] = TTAK[1]; ++ PPK[2] = TTAK[2]; ++ PPK[3] = TTAK[3]; ++ PPK[4] = TTAK[4]; ++ PPK[5] = TTAK[4] + IV16; ++ ++ /* Step 2 - 96-bit bijective mixing using S-box */ ++ PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); ++ PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); ++ PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); ++ PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); ++ PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); ++ PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); ++ ++ PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); ++ PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); ++ PPK[2] += RotR1(PPK[1]); ++ PPK[3] += RotR1(PPK[2]); ++ PPK[4] += RotR1(PPK[3]); ++ PPK[5] += RotR1(PPK[4]); ++ ++ /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value ++ * WEPSeed[0..2] is transmitted as WEP IV */ ++ WEPSeed[0] = Hi8(IV16); ++ WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; ++ WEPSeed[2] = Lo8(IV16); ++ WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); ++ ++#ifdef __BIG_ENDIAN ++ { ++ int i; ++ for (i = 0; i < 6; i++) ++ PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); ++ } ++#endif ++} ++ ++ ++static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ int len; ++ u8 *pos; ++ struct ieee80211_hdr_4addr *hdr; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; ++ int ret = 0; ++ #endif ++ u8 rc4key[16], *icv; ++ u32 crc; ++ struct scatterlist sg; ++ ++ if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || ++ skb->len < hdr_len) ++ return -1; ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ ++#if 0 ++printk("@@ tkey\n"); ++printk("%x|", ((u32*)tkey->key)[0]); ++printk("%x|", ((u32*)tkey->key)[1]); ++printk("%x|", ((u32*)tkey->key)[2]); ++printk("%x|", ((u32*)tkey->key)[3]); ++printk("%x|", ((u32*)tkey->key)[4]); ++printk("%x|", ((u32*)tkey->key)[5]); ++printk("%x|", ((u32*)tkey->key)[6]); ++printk("%x\n", ((u32*)tkey->key)[7]); ++#endif ++ ++ if (!tcb_desc->bHwSec) ++ { ++ if (!tkey->tx_phase1_done) { ++ tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, ++ tkey->tx_iv32); ++ tkey->tx_phase1_done = 1; ++ } ++ tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); ++ } ++ else ++ tkey->tx_phase1_done = 1; ++ ++ ++ len = skb->len - hdr_len; ++ pos = skb_push(skb, 8); ++ memmove(pos, pos + 8, hdr_len); ++ pos += hdr_len; ++ ++ if (tcb_desc->bHwSec) ++ { ++ *pos++ = Hi8(tkey->tx_iv16); ++ *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; ++ *pos++ = Lo8(tkey->tx_iv16); ++ } ++ else ++ { ++ *pos++ = rc4key[0]; ++ *pos++ = rc4key[1]; ++ *pos++ = rc4key[2]; ++ } ++ ++ *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; ++ *pos++ = tkey->tx_iv32 & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 8) & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 16) & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 24) & 0xff; ++ ++ if (!tcb_desc->bHwSec) ++ { ++ icv = skb_put(skb, 4); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, len); ++#else ++ crc = ~ether_crc_le(len, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ crypto_cipher_encrypt(tkey->tx_tfm_arc4, &sg, &sg, len + 4); ++#else ++ crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++#else ++ sg_init_one(&sg, pos, len+4); ++#endif ++ ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); ++#endif ++ ++ } ++ ++ tkey->tx_iv16++; ++ if (tkey->tx_iv16 == 0) { ++ tkey->tx_phase1_done = 0; ++ tkey->tx_iv32++; ++ } ++ ++ if (!tcb_desc->bHwSec) ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ return 0; ++ #else ++ return ret; ++ #endif ++ else ++ return 0; ++ ++ ++} ++ ++static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 keyidx, *pos; ++ u32 iv32; ++ u16 iv16; ++ struct ieee80211_hdr_4addr *hdr; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4}; ++ #endif ++ u8 rc4key[16]; ++ u8 icv[4]; ++ u32 crc; ++ struct scatterlist sg; ++ int plen; ++ if (skb->len < hdr_len + 8 + 4) ++ return -1; ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ pos = skb->data + hdr_len; ++ keyidx = pos[3]; ++ if (!(keyidx & (1 << 5))) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: received packet without ExtIV" ++ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ return -2; ++ } ++ keyidx >>= 6; ++ if (tkey->key_idx != keyidx) { ++ printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " ++ "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); ++ return -6; ++ } ++ if (!tkey->key_set) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT ++ " with keyid=%d that does not have a configured" ++ " key\n", MAC_ARG(hdr->addr2), keyidx); ++ } ++ return -3; ++ } ++ iv16 = (pos[0] << 8) | pos[2]; ++ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); ++ pos += 8; ++ ++ if (!tcb_desc->bHwSec) ++ { ++ if (iv32 < tkey->rx_iv32 || ++ (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT ++ " previous TSC %08x%04x received TSC " ++ "%08x%04x\n", MAC_ARG(hdr->addr2), ++ tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); ++ } ++ tkey->dot11RSNAStatsTKIPReplays++; ++ return -4; ++ } ++ ++ if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { ++ tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); ++ tkey->rx_phase1_done = 1; ++ } ++ tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); ++ ++ plen = skb->len - hdr_len - 12; ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ crypto_cipher_decrypt(tkey->rx_tfm_arc4, &sg, &sg, plen + 4); ++#else ++ crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++#else ++ sg_init_one(&sg, pos, plen+4); ++#endif ++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG ": TKIP: failed to decrypt " ++ "received packet from " MAC_FMT "\n", ++ MAC_ARG(hdr->addr2)); ++ } ++ return -7; ++ } ++#endif ++ ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, plen); ++ #else ++ crc = ~ether_crc_le(plen, pos); ++ #endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++ if (memcmp(icv, pos + plen, 4) != 0) { ++ if (iv32 != tkey->rx_iv32) { ++ /* Previously cached Phase1 result was already lost, so ++ * it needs to be recalculated for the next packet. */ ++ tkey->rx_phase1_done = 0; ++ } ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: ICV error detected: STA=" ++ MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ tkey->dot11RSNAStatsTKIPICVErrors++; ++ return -5; ++ } ++ ++ } ++ ++ /* Update real counters only after Michael MIC verification has ++ * completed */ ++ tkey->rx_iv32_new = iv32; ++ tkey->rx_iv16_new = iv16; ++ ++ /* Remove IV and ICV */ ++ memmove(skb->data + 8, skb->data, hdr_len); ++ skb_pull(skb, 8); ++ skb_trim(skb, skb->len - 4); ++ ++//john's test ++#ifdef JOHN_DUMP ++if( ((u16*)skb->data)[0] & 0x4000){ ++ printk("@@ rx decrypted skb->data"); ++ int i; ++ for(i=0;ilen;i++){ ++ if( (i%24)==0 ) printk("\n"); ++ printk("%2x ", ((u8*)skb->data)[i]); ++ } ++ printk("\n"); ++} ++#endif /*JOHN_DUMP*/ ++ return keyidx; ++} ++ ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++static int michael_mic(struct crypto_tfm * tfm_michael, u8 *key, u8 *hdr, ++ u8 *data, size_t data_len, u8 *mic) ++{ ++ struct scatterlist sg[2]; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct hash_desc desc; ++ int ret = 0; ++#endif ++ ++ if (tfm_michael == NULL){ ++ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); ++ return -1; ++ } ++ sg[0].page = virt_to_page(hdr); ++ sg[0].offset = offset_in_page(hdr); ++ sg[0].length = 16; ++ ++ sg[1].page = virt_to_page(data); ++ sg[1].offset = offset_in_page(data); ++ sg[1].length = data_len; ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ crypto_digest_init(tfm_michael); ++ crypto_digest_setkey(tfm_michael, key, 8); ++ crypto_digest_update(tfm_michael, sg, 2); ++ crypto_digest_final(tfm_michael, mic); ++ return 0; ++#else ++if (crypto_hash_setkey(tkey->tfm_michael, key, 8)) ++ return -1; ++ ++// return 0; ++ desc.tfm = tkey->tfm_michael; ++ desc.flags = 0; ++ ret = crypto_hash_digest(&desc, sg, data_len + 16, mic); ++ return ret; ++#endif ++} ++#else ++static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, ++ u8 * data, size_t data_len, u8 * mic) ++{ ++ struct hash_desc desc; ++ struct scatterlist sg[2]; ++ ++ if (tfm_michael == NULL) { ++ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); ++ return -1; ++ } ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ sg[0].page = virt_to_page(hdr); ++ sg[0].offset = offset_in_page(hdr); ++ sg[0].length = 16; ++ ++ sg[1].page = virt_to_page(data); ++ sg[1].offset = offset_in_page(data); ++ sg[1].length = data_len; ++#else ++ sg_init_table(sg, 2); ++ sg_set_buf(&sg[0], hdr, 16); ++ sg_set_buf(&sg[1], data, data_len); ++#endif ++ ++ if (crypto_hash_setkey(tfm_michael, key, 8)) ++ return -1; ++ ++ desc.tfm = tfm_michael; ++ desc.flags = 0; ++ return crypto_hash_digest(&desc, sg, data_len + 16, mic); ++} ++#endif ++ ++ ++ ++static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) ++{ ++ struct ieee80211_hdr_4addr *hdr11; ++ ++ hdr11 = (struct ieee80211_hdr_4addr *) skb->data; ++ switch (le16_to_cpu(hdr11->frame_ctl) & ++ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { ++ case IEEE80211_FCTL_TODS: ++ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ ++ break; ++ case IEEE80211_FCTL_FROMDS: ++ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ ++ break; ++ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: ++ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ ++ break; ++ case 0: ++ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ ++ break; ++ } ++ ++ hdr[12] = 0; /* priority */ ++ ++ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ ++} ++ ++ ++static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 *pos; ++ struct ieee80211_hdr_4addr *hdr; ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ ++ if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { ++ printk(KERN_DEBUG "Invalid packet for Michael MIC add " ++ "(tailroom=%d hdr_len=%d skb->len=%d)\n", ++ skb_tailroom(skb), hdr_len, skb->len); ++ return -1; ++ } ++ ++ michael_mic_hdr(skb, tkey->tx_hdr); ++ ++ // { david, 2006.9.1 ++ // fix the wpa process with wmm enabled. ++ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { ++ tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; ++ } ++ // } ++ pos = skb_put(skb, 8); ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) ++#else ++ if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) ++#endif ++ return -1; ++ ++ return 0; ++} ++ ++ ++#if WIRELESS_EXT >= 18 ++static void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr_4addr *hdr, ++ int keyidx) ++{ ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure ev; ++ ++ /* TODO: needed parameters: count, keyid, key type, TSC */ ++ memset(&ev, 0, sizeof(ev)); ++ ev.flags = keyidx & IW_MICFAILURE_KEY_ID; ++ if (hdr->addr1[0] & 0x01) ++ ev.flags |= IW_MICFAILURE_GROUP; ++ else ++ ev.flags |= IW_MICFAILURE_PAIRWISE; ++ ev.src_addr.sa_family = ARPHRD_ETHER; ++ memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(ev); ++ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); ++} ++#elif WIRELESS_EXT >= 15 ++static void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr_4addr *hdr, ++ int keyidx) ++{ ++ union iwreq_data wrqu; ++ char buf[128]; ++ ++ /* TODO: needed parameters: count, keyid, key type, TSC */ ++ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" ++ MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", ++ MAC_ARG(hdr->addr2)); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = strlen(buf); ++ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); ++} ++#else /* WIRELESS_EXT >= 15 */ ++static inline void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr_4addr *hdr, ++ int keyidx) ++{ ++} ++#endif /* WIRELESS_EXT >= 15 */ ++ ++static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, ++ int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 mic[8]; ++ struct ieee80211_hdr_4addr *hdr; ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ ++ if (!tkey->key_set) ++ return -1; ++ ++ michael_mic_hdr(skb, tkey->rx_hdr); ++ // { david, 2006.9.1 ++ // fix the wpa process with wmm enabled. ++ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { ++ tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; ++ } ++ // } ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) ++#else ++ if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) ++#endif ++ return -1; ++ if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { ++ struct ieee80211_hdr_4addr *hdr; ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ printk(KERN_DEBUG "%s: Michael MIC verification failed for " ++ "MSDU from " MAC_FMT " keyidx=%d\n", ++ skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), ++ keyidx); ++ if (skb->dev) ++ ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); ++ tkey->dot11RSNAStatsTKIPLocalMICFailures++; ++ return -1; ++ } ++ ++ /* Update TSC counters for RX now that the packet verification has ++ * completed. */ ++ tkey->rx_iv32 = tkey->rx_iv32_new; ++ tkey->rx_iv16 = tkey->rx_iv16_new; ++ ++ skb_trim(skb, skb->len - 8); ++ ++ return 0; ++} ++ ++ ++static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ int keyidx; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ struct crypto_tfm *tfm = tkey->tx_tfm_michael; ++ struct crypto_tfm *tfm2 = tkey->tx_tfm_arc4; ++ struct crypto_tfm *tfm3 = tkey->rx_tfm_michael; ++ struct crypto_tfm *tfm4 = tkey->rx_tfm_arc4; ++#else ++ struct crypto_hash *tfm = tkey->tx_tfm_michael; ++ struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; ++ struct crypto_hash *tfm3 = tkey->rx_tfm_michael; ++ struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; ++#endif ++ ++ keyidx = tkey->key_idx; ++ memset(tkey, 0, sizeof(*tkey)); ++ tkey->key_idx = keyidx; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ tkey->tx_tfm_michael = tfm; ++ tkey->tx_tfm_arc4 = tfm2; ++ tkey->rx_tfm_michael = tfm3; ++ tkey->rx_tfm_arc4 = tfm4; ++#else ++ tkey->tx_tfm_michael = tfm; ++ tkey->tx_tfm_arc4 = tfm2; ++ tkey->rx_tfm_michael = tfm3; ++ tkey->rx_tfm_arc4 = tfm4; ++#endif ++ ++ if (len == TKIP_KEY_LEN) { ++ memcpy(tkey->key, key, TKIP_KEY_LEN); ++ tkey->key_set = 1; ++ tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ ++ if (seq) { ++ tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | ++ (seq[3] << 8) | seq[2]; ++ tkey->rx_iv16 = (seq[1] << 8) | seq[0]; ++ } ++ } else if (len == 0) ++ tkey->key_set = 0; ++ else ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ ++ if (len < TKIP_KEY_LEN) ++ return -1; ++ ++ if (!tkey->key_set) ++ return 0; ++ memcpy(key, tkey->key, TKIP_KEY_LEN); ++ ++ if (seq) { ++ /* Return the sequence number of the last transmitted frame. */ ++ u16 iv16 = tkey->tx_iv16; ++ u32 iv32 = tkey->tx_iv32; ++ if (iv16 == 0) ++ iv32--; ++ iv16--; ++ seq[0] = tkey->tx_iv16; ++ seq[1] = tkey->tx_iv16 >> 8; ++ seq[2] = tkey->tx_iv32; ++ seq[3] = tkey->tx_iv32 >> 8; ++ seq[4] = tkey->tx_iv32 >> 16; ++ seq[5] = tkey->tx_iv32 >> 24; ++ } ++ ++ return TKIP_KEY_LEN; ++} ++ ++ ++static char * ieee80211_tkip_print_stats(char *p, void *priv) ++{ ++ struct ieee80211_tkip_data *tkip = priv; ++ p += sprintf(p, "key[%d] alg=TKIP key_set=%d " ++ "tx_pn=%02x%02x%02x%02x%02x%02x " ++ "rx_pn=%02x%02x%02x%02x%02x%02x " ++ "replays=%d icv_errors=%d local_mic_failures=%d\n", ++ tkip->key_idx, tkip->key_set, ++ (tkip->tx_iv32 >> 24) & 0xff, ++ (tkip->tx_iv32 >> 16) & 0xff, ++ (tkip->tx_iv32 >> 8) & 0xff, ++ tkip->tx_iv32 & 0xff, ++ (tkip->tx_iv16 >> 8) & 0xff, ++ tkip->tx_iv16 & 0xff, ++ (tkip->rx_iv32 >> 24) & 0xff, ++ (tkip->rx_iv32 >> 16) & 0xff, ++ (tkip->rx_iv32 >> 8) & 0xff, ++ tkip->rx_iv32 & 0xff, ++ (tkip->rx_iv16 >> 8) & 0xff, ++ tkip->rx_iv16 & 0xff, ++ tkip->dot11RSNAStatsTKIPReplays, ++ tkip->dot11RSNAStatsTKIPICVErrors, ++ tkip->dot11RSNAStatsTKIPLocalMICFailures); ++ return p; ++} ++ ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { ++ .name = "TKIP", ++ .init = ieee80211_tkip_init, ++ .deinit = ieee80211_tkip_deinit, ++ .encrypt_mpdu = ieee80211_tkip_encrypt, ++ .decrypt_mpdu = ieee80211_tkip_decrypt, ++ .encrypt_msdu = ieee80211_michael_mic_add, ++ .decrypt_msdu = ieee80211_michael_mic_verify, ++ .set_key = ieee80211_tkip_set_key, ++ .get_key = ieee80211_tkip_get_key, ++ .print_stats = ieee80211_tkip_print_stats, ++ .extra_prefix_len = 4 + 4, /* IV + ExtIV */ ++ .extra_postfix_len = 8 + 4, /* MIC + ICV */ ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_tkip_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); ++} ++ ++ ++void __exit ieee80211_crypto_tkip_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); ++} ++ ++void ieee80211_tkip_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_tkip_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null); ++#endif ++ ++//module_init(ieee80211_crypto_tkip_init); ++//module_exit(ieee80211_crypto_tkip_exit); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_crypt_wep.c +@@ -0,0 +1,397 @@ ++/* ++ * Host AP crypt: host-based WEP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2002-2004, Jouni Malinen ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20)) ++//#include "crypto_compat.h" ++#endif ++ ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include ++#else ++ #include ++#endif ++//#include ++#include ++// ++/* ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++ ++#include ++#include ++*/ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: WEP"); ++MODULE_LICENSE("GPL"); ++#ifndef OPENSUSE_SLED ++#define OPENSUSE_SLED 0 ++#endif ++ ++struct prism2_wep_data { ++ u32 iv; ++#define WEP_KEY_LEN 13 ++ u8 key[WEP_KEY_LEN + 1]; ++ u8 key_len; ++ u8 key_idx; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ struct crypto_tfm *tfm; ++ #else ++ struct crypto_blkcipher *tx_tfm; ++ struct crypto_blkcipher *rx_tfm; ++ #endif ++}; ++ ++ ++static void * prism2_wep_init(int keyidx) ++{ ++ struct prism2_wep_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = keyidx; ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ priv->tfm = crypto_alloc_tfm("arc4", 0); ++ if (priv->tfm == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ #else ++ priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ priv->tx_tfm = NULL; ++ goto fail; ++ } ++ priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ priv->rx_tfm = NULL; ++ goto fail; ++ } ++ #endif ++ ++ /* start WEP IV from a random value */ ++ get_random_bytes(&priv->iv, 4); ++ ++ return priv; ++ ++fail: ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ if (priv) { ++ if (priv->tfm) ++ crypto_free_tfm(priv->tfm); ++ kfree(priv); ++ } ++ #else ++ if (priv) { ++ if (priv->tx_tfm) ++ crypto_free_blkcipher(priv->tx_tfm); ++ if (priv->rx_tfm) ++ crypto_free_blkcipher(priv->rx_tfm); ++ kfree(priv); ++ } ++ #endif ++ return NULL; ++} ++ ++ ++static void prism2_wep_deinit(void *priv) ++{ ++ struct prism2_wep_data *_priv = priv; ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ if (_priv && _priv->tfm) ++ crypto_free_tfm(_priv->tfm); ++ #else ++ if (_priv) { ++ if (_priv->tx_tfm) ++ crypto_free_blkcipher(_priv->tx_tfm); ++ if (_priv->rx_tfm) ++ crypto_free_blkcipher(_priv->rx_tfm); ++ } ++ #endif ++ kfree(priv); ++} ++ ++/* Perform WEP encryption on given skb that has at least 4 bytes of headroom ++ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, ++ * so the payload length increases with 8 bytes. ++ * ++ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) ++ */ ++static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ u32 klen, len; ++ u8 key[WEP_KEY_LEN + 3]; ++ u8 *pos; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; ++ #endif ++ u32 crc; ++ u8 *icv; ++ struct scatterlist sg; ++ if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || ++ skb->len < hdr_len) ++ return -1; ++ ++ len = skb->len - hdr_len; ++ pos = skb_push(skb, 4); ++ memmove(pos, pos + 4, hdr_len); ++ pos += hdr_len; ++ ++ klen = 3 + wep->key_len; ++ ++ wep->iv++; ++ ++ /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key ++ * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) ++ * can be used to speedup attacks, so avoid using them. */ ++ if ((wep->iv & 0xff00) == 0xff00) { ++ u8 B = (wep->iv >> 16) & 0xff; ++ if (B >= 3 && B < klen) ++ wep->iv += 0x0100; ++ } ++ ++ /* Prepend 24-bit IV to RC4 key and TX frame */ ++ *pos++ = key[0] = (wep->iv >> 16) & 0xff; ++ *pos++ = key[1] = (wep->iv >> 8) & 0xff; ++ *pos++ = key[2] = wep->iv & 0xff; ++ *pos++ = wep->key_idx << 6; ++ ++ /* Copy rest of the WEP key (the secret part) */ ++ memcpy(key + 3, wep->key, wep->key_len); ++ ++ if (!tcb_desc->bHwSec) ++ { ++ ++ /* Append little-endian CRC32 and encrypt it to produce ICV */ ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, len); ++ #else ++ crc = ~ether_crc_le(len, pos); ++ #endif ++ icv = skb_put(skb, 4); ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ crypto_cipher_setkey(wep->tfm, key, klen); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); ++ return 0; ++ #else ++ crypto_blkcipher_setkey(wep->tx_tfm, key, klen); ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ #else ++ sg_init_one(&sg, pos, len+4); ++ #endif ++ return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); ++ #endif ++ } ++ ++ return 0; ++} ++ ++ ++/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of ++ * the frame: IV (4 bytes), encrypted payload (including SNAP header), ++ * ICV (4 bytes). len includes both IV and ICV. ++ * ++ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on ++ * failure. If frame is OK, IV and ICV will be removed. ++ */ ++static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ u32 klen, plen; ++ u8 key[WEP_KEY_LEN + 3]; ++ u8 keyidx, *pos; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) || (OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; ++ #endif ++ u32 crc; ++ u8 icv[4]; ++ struct scatterlist sg; ++ if (skb->len < hdr_len + 8) ++ return -1; ++ ++ pos = skb->data + hdr_len; ++ key[0] = *pos++; ++ key[1] = *pos++; ++ key[2] = *pos++; ++ keyidx = *pos++ >> 6; ++ if (keyidx != wep->key_idx) ++ return -1; ++ ++ klen = 3 + wep->key_len; ++ ++ /* Copy rest of the WEP key (the secret part) */ ++ memcpy(key + 3, wep->key, wep->key_len); ++ ++ /* Apply RC4 to data and compute CRC32 over decrypted data */ ++ plen = skb->len - hdr_len - 8; ++ ++ if (!tcb_desc->bHwSec) ++ { ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!OPENSUSE_SLED)) ++ crypto_cipher_setkey(wep->tfm, key, klen); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); ++ #else ++ crypto_blkcipher_setkey(wep->rx_tfm, key, klen); ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ #else ++ sg_init_one(&sg, pos, plen+4); ++ #endif ++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) ++ return -7; ++ #endif ++ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, plen); ++ #else ++ crc = ~ether_crc_le(plen, pos); ++ #endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ if (memcmp(icv, pos + plen, 4) != 0) { ++ /* ICV mismatch - drop frame */ ++ return -2; ++ } ++ } ++ /* Remove IV and ICV */ ++ memmove(skb->data + 4, skb->data, hdr_len); ++ skb_pull(skb, 4); ++ skb_trim(skb, skb->len - 4); ++ ++ return 0; ++} ++ ++ ++static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ ++ if (len < 0 || len > WEP_KEY_LEN) ++ return -1; ++ ++ memcpy(wep->key, key, len); ++ wep->key_len = len; ++ ++ return 0; ++} ++ ++ ++static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ ++ if (len < wep->key_len) ++ return -1; ++ ++ memcpy(key, wep->key, wep->key_len); ++ ++ return wep->key_len; ++} ++ ++ ++static char * prism2_wep_print_stats(char *p, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ p += sprintf(p, "key[%d] alg=WEP len=%d\n", ++ wep->key_idx, wep->key_len); ++ return p; ++} ++ ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_wep = { ++ .name = "WEP", ++ .init = prism2_wep_init, ++ .deinit = prism2_wep_deinit, ++ .encrypt_mpdu = prism2_wep_encrypt, ++ .decrypt_mpdu = prism2_wep_decrypt, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = prism2_wep_set_key, ++ .get_key = prism2_wep_get_key, ++ .print_stats = prism2_wep_print_stats, ++ .extra_prefix_len = 4, /* IV */ ++ .extra_postfix_len = 4, /* ICV */ ++ .owner = THIS_MODULE, ++}; ++ ++ ++int __init ieee80211_crypto_wep_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); ++} ++ ++ ++void __exit ieee80211_crypto_wep_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); ++} ++ ++void ieee80211_wep_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_wep_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_wep_null); ++#endif ++ ++//module_init(ieee80211_crypto_wep_init); ++//module_exit(ieee80211_crypto_wep_exit); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c +@@ -0,0 +1,432 @@ ++/******************************************************************************* ++ ++ Copyright(c) 2004 Intel Corporation. All rights reserved. ++ ++ Portions of this file are based on the WEP enablement code provided by the ++ Host AP project hostap-drivers v0.1.3 ++ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ ++ Copyright (c) 2002-2003, Jouni Malinen ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., 59 ++ Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++MODULE_DESCRIPTION("802.11 data/management/control stack"); ++MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation "); ++MODULE_LICENSE("GPL"); ++ ++#define DRV_NAME "ieee80211" ++ ++static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) ++{ ++ if (ieee->networks) ++ return 0; ++ ++ ieee->networks = kmalloc( ++ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), ++ GFP_KERNEL); ++ if (!ieee->networks) { ++ printk(KERN_WARNING "%s: Out of memory allocating beacons\n", ++ ieee->dev->name); ++ return -ENOMEM; ++ } ++ ++ memset(ieee->networks, 0, ++ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network)); ++ ++ return 0; ++} ++ ++static inline void ieee80211_networks_free(struct ieee80211_device *ieee) ++{ ++ if (!ieee->networks) ++ return; ++ kfree(ieee->networks); ++ ieee->networks = NULL; ++} ++ ++static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) ++{ ++ int i; ++ ++ INIT_LIST_HEAD(&ieee->network_free_list); ++ INIT_LIST_HEAD(&ieee->network_list); ++ for (i = 0; i < MAX_NETWORK_COUNT; i++) ++ list_add_tail(&ieee->networks[i].list, &ieee->network_free_list); ++} ++ ++ ++struct net_device *alloc_ieee80211(int sizeof_priv) ++{ ++ struct ieee80211_device *ieee; ++ struct net_device *dev; ++ int i,err; ++ ++ IEEE80211_DEBUG_INFO("Initializing...\n"); ++ ++ dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); ++ if (!dev) { ++ IEEE80211_ERROR("Unable to network device.\n"); ++ goto failed; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ ieee = netdev_priv(dev); ++#else ++ ieee = (struct ieee80211_device *)dev->priv; ++#endif ++#if 0 ++ dev->hard_start_xmit = ieee80211_xmit; ++#endif ++ ++ memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv); ++ ieee->dev = dev; ++ ++ err = ieee80211_networks_allocate(ieee); ++ if (err) { ++ IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", ++ err); ++ goto failed; ++ } ++ ieee80211_networks_initialize(ieee); ++ ++ ++ /* Default fragmentation threshold is maximum payload size */ ++ ieee->fts = DEFAULT_FTS; ++ ieee->scan_age = DEFAULT_MAX_SCAN_AGE; ++ ieee->open_wep = 1; ++ ++ /* Default to enabling full open WEP with host based encrypt/decrypt */ ++ ieee->host_encrypt = 1; ++ ieee->host_decrypt = 1; ++ ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ ++ ++ INIT_LIST_HEAD(&ieee->crypt_deinit_list); ++ init_timer(&ieee->crypt_deinit_timer); ++ ieee->crypt_deinit_timer.data = (unsigned long)ieee; ++ ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; ++ ++ spin_lock_init(&ieee->lock); ++ spin_lock_init(&ieee->wpax_suitlist_lock); ++ spin_lock_init(&ieee->bw_spinlock); ++ spin_lock_init(&ieee->reorder_spinlock); ++ //added by WB ++ atomic_set(&(ieee->atm_chnlop), 0); ++ atomic_set(&(ieee->atm_swbw), 0); ++ ++ ieee->wpax_type_set = 0; ++ ieee->wpa_enabled = 0; ++ ieee->tkip_countermeasures = 0; ++ ieee->drop_unencrypted = 0; ++ ieee->privacy_invoked = 0; ++ ieee->ieee802_1x = 1; ++ ieee->raw_tx = 0; ++ //ieee->hwsec_support = 1; //defalt support hw security. //use module_param instead. ++ ieee->hwsec_active = 0; //disable hwsec, switch it on when necessary. ++ ++ ieee80211_softmac_init(ieee); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) ++ ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kzalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL); ++#else ++ ieee->pHTInfo = (RT_HIGH_THROUGHPUT*)kmalloc(sizeof(RT_HIGH_THROUGHPUT), GFP_KERNEL); ++ memset(ieee->pHTInfo,0,sizeof(RT_HIGH_THROUGHPUT)); ++#endif ++ if (ieee->pHTInfo == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n"); ++ return NULL; ++ } ++ HTUpdateDefaultSetting(ieee); ++ HTInitializeHTInfo(ieee); //may move to other place. ++ TSInitialize(ieee); ++#if 0 ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++ INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq); ++#else ++ INIT_WORK(&ieee->ht_onAssRsp, (void(*)(void*)) HTOnAssocRsp_wq, ieee); ++#endif ++#endif ++ for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) ++ INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); ++ ++ for (i = 0; i < 17; i++) { ++ ieee->last_rxseq_num[i] = -1; ++ ieee->last_rxfrag_num[i] = -1; ++ ieee->last_packet_time[i] = 0; ++ } ++ ++//These function were added to load crypte module autoly ++ ieee80211_tkip_null(); ++ ieee80211_wep_null(); ++ ieee80211_ccmp_null(); ++ ++ return dev; ++ ++ failed: ++ if (dev) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ free_netdev(dev); ++#else ++ kfree(dev); ++#endif ++ return NULL; ++} ++ ++ ++void free_ieee80211(struct net_device *dev) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ int i; ++ //struct list_head *p, *q; ++// del_timer_sync(&ieee->SwBwTimer); ++#if 1 ++ if (ieee->pHTInfo != NULL) ++ { ++ kfree(ieee->pHTInfo); ++ ieee->pHTInfo = NULL; ++ } ++#endif ++ RemoveAllTS(ieee); ++ ieee80211_softmac_free(ieee); ++ del_timer_sync(&ieee->crypt_deinit_timer); ++ ieee80211_crypt_deinit_entries(ieee, 1); ++ ++ for (i = 0; i < WEP_KEYS; i++) { ++ struct ieee80211_crypt_data *crypt = ieee->crypt[i]; ++ if (crypt) { ++ if (crypt->ops) { ++ crypt->ops->deinit(crypt->priv); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ module_put(crypt->ops->owner); ++#else ++ __MOD_DEC_USE_COUNT(crypt->ops->owner); ++#endif ++ } ++ kfree(crypt); ++ ieee->crypt[i] = NULL; ++ } ++ } ++ ++ ieee80211_networks_free(ieee); ++#if 0 ++ for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) { ++ list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) { ++ kfree(list_entry(p, struct ieee_ibss_seq, list)); ++ list_del(p); ++ } ++ } ++ ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ free_netdev(dev); ++#else ++ kfree(dev); ++#endif ++} ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ ++u32 ieee80211_debug_level = 0; ++static int debug = \ ++ // IEEE80211_DL_INFO | ++ // IEEE80211_DL_WX | ++ // IEEE80211_DL_SCAN | ++ // IEEE80211_DL_STATE | ++ // IEEE80211_DL_MGMT | ++ // IEEE80211_DL_FRAG | ++ // IEEE80211_DL_EAP | ++ // IEEE80211_DL_DROP | ++ // IEEE80211_DL_TX | ++ // IEEE80211_DL_RX | ++ //IEEE80211_DL_QOS | ++ // IEEE80211_DL_HT | ++ // IEEE80211_DL_TS | ++// IEEE80211_DL_BA | ++ // IEEE80211_DL_REORDER| ++// IEEE80211_DL_TRACE | ++ //IEEE80211_DL_DATA | ++ IEEE80211_DL_ERR //awayls open this flags to show error out ++ ; ++struct proc_dir_entry *ieee80211_proc = NULL; ++ ++static int show_debug_level(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); ++} ++ ++static int store_debug_level(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char buf[] = "0x00000000"; ++ unsigned long len = min(sizeof(buf) - 1, (u32)count); ++ char *p = (char *)buf; ++ unsigned long val; ++ ++ if (copy_from_user(buf, buffer, len)) ++ return count; ++ buf[len] = 0; ++ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { ++ p++; ++ if (p[0] == 'x' || p[0] == 'X') ++ p++; ++ val = simple_strtoul(p, &p, 16); ++ } else ++ val = simple_strtoul(p, &p, 10); ++ if (p == buf) ++ printk(KERN_INFO DRV_NAME ++ ": %s is not in hex or decimal form.\n", buf); ++ else ++ ieee80211_debug_level = val; ++ ++ return strnlen(buf, count); ++} ++ ++extern int ieee80211_crypto_init(void); ++extern void ieee80211_crypto_deinit(void); ++extern int ieee80211_crypto_tkip_init(void); ++extern void ieee80211_crypto_tkip_exit(void); ++extern int ieee80211_crypto_ccmp_init(void); ++extern void ieee80211_crypto_ccmp_exit(void); ++extern int ieee80211_crypto_wep_init(void); ++extern void ieee80211_crypto_wep_exit(void); ++ ++int __init ieee80211_init(void) ++{ ++ struct proc_dir_entry *e; ++ int retval; ++ ++ retval = ieee80211_crypto_init(); ++ if (retval) ++ return retval; ++ retval = ieee80211_crypto_tkip_init(); ++ if (retval) { ++ ieee80211_crypto_deinit(); ++ return retval; ++ } ++ retval = ieee80211_crypto_ccmp_init(); ++ if (retval) { ++ ieee80211_crypto_tkip_exit(); ++ ieee80211_crypto_deinit(); ++ return retval; ++ } ++ retval = ieee80211_crypto_wep_init(); ++ if (retval) { ++ ieee80211_crypto_ccmp_exit(); ++ ieee80211_crypto_tkip_exit(); ++ ieee80211_crypto_deinit(); ++ return retval; ++ } ++ ++ ieee80211_debug_level = debug; ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net); ++#else ++ ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, init_net.proc_net); ++#endif ++ if (ieee80211_proc == NULL) { ++ IEEE80211_ERROR("Unable to create " DRV_NAME ++ " proc directory\n"); ++ return -EIO; ++ } ++ e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, ++ ieee80211_proc); ++ if (!e) { ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ remove_proc_entry(DRV_NAME, proc_net); ++#else ++ remove_proc_entry(DRV_NAME, init_net.proc_net); ++#endif ++ ieee80211_proc = NULL; ++ return -EIO; ++ } ++ e->read_proc = show_debug_level; ++ e->write_proc = store_debug_level; ++ e->data = NULL; ++ ++ return 0; ++} ++ ++void __exit ieee80211_exit(void) ++{ ++ if (ieee80211_proc) { ++ remove_proc_entry("debug_level", ieee80211_proc); ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ remove_proc_entry(DRV_NAME, proc_net); ++#else ++ remove_proc_entry(DRV_NAME, init_net.proc_net); ++#endif ++ ieee80211_proc = NULL; ++ } ++ ieee80211_crypto_wep_exit(); ++ ieee80211_crypto_ccmp_exit(); ++ ieee80211_crypto_tkip_exit(); ++ ieee80211_crypto_deinit(); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++#include ++module_param(debug, int, 0444); ++MODULE_PARM_DESC(debug, "debug output mask"); ++ ++ ++//module_exit(ieee80211_exit); ++//module_init(ieee80211_init); ++#endif ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(alloc_ieee80211); ++//EXPORT_SYMBOL(free_ieee80211); ++#else ++EXPORT_SYMBOL_NOVERS(alloc_ieee80211); ++EXPORT_SYMBOL_NOVERS(free_ieee80211); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c +@@ -0,0 +1,2802 @@ ++/* ++ * Original code based Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3 - hostap.o module, common routines ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ ****************************************************************************** ++ ++ Few modifications for Realtek's Wi-Fi drivers by ++ Andrea Merello ++ ++ A special thanks goes to Realtek for their support ! ++ ++******************************************************************************/ ++ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, ++ struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats) ++{ ++ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ ++ skb->dev = ieee->dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++ skb_reset_mac_header(skb); ++#else ++ skb->mac.raw = skb->data; ++#endif ++ ++ skb_pull(skb, ieee80211_get_hdrlen(fc)); ++ skb->pkt_type = PACKET_OTHERHOST; ++ skb->protocol = __constant_htons(ETH_P_80211_RAW); ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ netif_rx(skb); ++} ++ ++ ++/* Called only as a tasklet (software IRQ) */ ++static struct ieee80211_frag_entry * ++ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq, ++ unsigned int frag, u8 tid,u8 *src, u8 *dst) ++{ ++ struct ieee80211_frag_entry *entry; ++ int i; ++ ++ for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { ++ entry = &ieee->frag_cache[tid][i]; ++ if (entry->skb != NULL && ++ time_after(jiffies, entry->first_frag_time + 2 * HZ)) { ++ IEEE80211_DEBUG_FRAG( ++ "expiring fragment cache entry " ++ "seq=%u last_frag=%u\n", ++ entry->seq, entry->last_frag); ++ dev_kfree_skb_any(entry->skb); ++ entry->skb = NULL; ++ } ++ ++ if (entry->skb != NULL && entry->seq == seq && ++ (entry->last_frag + 1 == frag || frag == -1) && ++ memcmp(entry->src_addr, src, ETH_ALEN) == 0 && ++ memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) ++ return entry; ++ } ++ ++ return NULL; ++} ++ ++/* Called only as a tasklet (software IRQ) */ ++static struct sk_buff * ++ieee80211_frag_cache_get(struct ieee80211_device *ieee, ++ struct ieee80211_hdr_4addr *hdr) ++{ ++ struct sk_buff *skb = NULL; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ u16 sc = le16_to_cpu(hdr->seq_ctl); ++ unsigned int frag = WLAN_GET_SEQ_FRAG(sc); ++ unsigned int seq = WLAN_GET_SEQ_SEQ(sc); ++ struct ieee80211_frag_entry *entry; ++ struct ieee80211_hdr_3addrqos *hdr_3addrqos; ++ struct ieee80211_hdr_4addrqos *hdr_4addrqos; ++ u8 tid; ++ ++ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)hdr; ++ tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)hdr; ++ tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { ++ tid = 0; ++ } ++ ++ if (frag == 0) { ++ /* Reserve enough space to fit maximum frame length */ ++ skb = dev_alloc_skb(ieee->dev->mtu + ++ sizeof(struct ieee80211_hdr_4addr) + ++ 8 /* LLC */ + ++ 2 /* alignment */ + ++ 8 /* WEP */ + ++ ETH_ALEN /* WDS */ + ++ (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */); ++ if (skb == NULL) ++ return NULL; ++ ++ entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; ++ ieee->frag_next_idx[tid]++; ++ if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN) ++ ieee->frag_next_idx[tid] = 0; ++ ++ if (entry->skb != NULL) ++ dev_kfree_skb_any(entry->skb); ++ ++ entry->first_frag_time = jiffies; ++ entry->seq = seq; ++ entry->last_frag = frag; ++ entry->skb = skb; ++ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); ++ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); ++ } else { ++ /* received a fragment of a frame for which the head fragment ++ * should have already been received */ ++ entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2, ++ hdr->addr1); ++ if (entry != NULL) { ++ entry->last_frag = frag; ++ skb = entry->skb; ++ } ++ } ++ ++ return skb; ++} ++ ++ ++/* Called only as a tasklet (software IRQ) */ ++static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, ++ struct ieee80211_hdr_4addr *hdr) ++{ ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ u16 sc = le16_to_cpu(hdr->seq_ctl); ++ unsigned int seq = WLAN_GET_SEQ_SEQ(sc); ++ struct ieee80211_frag_entry *entry; ++ struct ieee80211_hdr_3addrqos *hdr_3addrqos; ++ struct ieee80211_hdr_4addrqos *hdr_4addrqos; ++ u8 tid; ++ ++ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)hdr; ++ tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)hdr; ++ tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { ++ tid = 0; ++ } ++ ++ entry = ieee80211_frag_cache_find(ieee, seq, -1, tid,hdr->addr2, ++ hdr->addr1); ++ ++ if (entry == NULL) { ++ IEEE80211_DEBUG_FRAG( ++ "could not invalidate fragment cache " ++ "entry (seq=%u)\n", seq); ++ return -1; ++ } ++ ++ entry->skb = NULL; ++ return 0; ++} ++ ++ ++ ++/* ieee80211_rx_frame_mgtmt ++ * ++ * Responsible for handling management control frames ++ * ++ * Called by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype) ++{ ++ /* On the struct stats definition there is written that ++ * this is not mandatory.... but seems that the probe ++ * response parser uses it ++ */ ++ struct ieee80211_hdr_3addr * hdr = (struct ieee80211_hdr_3addr *)skb->data; ++ ++ rx_stats->len = skb->len; ++ ieee80211_rx_mgt(ieee,(struct ieee80211_hdr_4addr *)skb->data,rx_stats); ++ //if ((ieee->state == IEEE80211_LINKED) && (memcmp(hdr->addr3, ieee->current_network.bssid, ETH_ALEN))) ++ if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN)))//use ADDR1 to perform address matching for Management frames ++ { ++ dev_kfree_skb_any(skb); ++ return 0; ++ } ++ ++ ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype); ++ ++ dev_kfree_skb_any(skb); ++ ++ return 0; ++ ++ #ifdef NOT_YET ++ if (ieee->iw_mode == IW_MODE_MASTER) { ++ printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", ++ ieee->dev->name); ++ return 0; ++/* ++ hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr_4addr *) ++ skb->data);*/ ++ } ++ ++ if (ieee->hostapd && type == IEEE80211_TYPE_MGMT) { ++ if (stype == WLAN_FC_STYPE_BEACON && ++ ieee->iw_mode == IW_MODE_MASTER) { ++ struct sk_buff *skb2; ++ /* Process beacon frames also in kernel driver to ++ * update STA(AP) table statistics */ ++ skb2 = skb_clone(skb, GFP_ATOMIC); ++ if (skb2) ++ hostap_rx(skb2->dev, skb2, rx_stats); ++ } ++ ++ /* send management frames to the user space daemon for ++ * processing */ ++ ieee->apdevstats.rx_packets++; ++ ieee->apdevstats.rx_bytes += skb->len; ++ prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); ++ return 0; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MASTER) { ++ if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { ++ printk(KERN_DEBUG "%s: unknown management frame " ++ "(type=0x%02x, stype=0x%02x) dropped\n", ++ skb->dev->name, type, stype); ++ return -1; ++ } ++ ++ hostap_rx(skb->dev, skb, rx_stats); ++ return 0; ++ } ++ ++ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " ++ "received in non-Host AP mode\n", skb->dev->name); ++ return -1; ++ #endif ++} ++ ++ ++ ++/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ ++/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ ++static unsigned char rfc1042_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ++/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ ++static unsigned char bridge_tunnel_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; ++/* No encapsulation header if EtherType < 0x600 (=length) */ ++ ++/* Called by ieee80211_rx_frame_decrypt */ ++static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, ++ struct sk_buff *skb, size_t hdrlen) ++{ ++ struct net_device *dev = ieee->dev; ++ u16 fc, ethertype; ++ struct ieee80211_hdr_4addr *hdr; ++ u8 *pos; ++ ++ if (skb->len < 24) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ ++ /* check that the frame is unicast frame to us */ ++ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_TODS && ++ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && ++ memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { ++ /* ToDS frame with own addr BSSID and DA */ ++ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_FROMDS && ++ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { ++ /* FromDS frame with own addr as DA */ ++ } else ++ return 0; ++ ++ if (skb->len < 24 + 8) ++ return 0; ++ ++ /* check for port access entity Ethernet type */ ++// pos = skb->data + 24; ++ pos = skb->data + hdrlen; ++ ethertype = (pos[6] << 8) | pos[7]; ++ if (ethertype == ETH_P_PAE) ++ return 1; ++ ++ return 0; ++} ++ ++/* Called only as a tasklet (software IRQ), by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, ++ struct ieee80211_crypt_data *crypt) ++{ ++ struct ieee80211_hdr_4addr *hdr; ++ int res, hdrlen; ++ ++ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) ++ return 0; ++#if 1 ++ if (ieee->hwsec_active) ++ { ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE); ++ tcb_desc->bHwSec = 1; ++ } ++#endif ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); ++ ++#ifdef CONFIG_IEEE80211_CRYPT_TKIP ++ if (ieee->tkip_countermeasures && ++ strcmp(crypt->ops->name, "TKIP") == 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ++ "received packet from " MAC_FMT "\n", ++ ieee->dev->name, MAC_ARG(hdr->addr2)); ++ } ++ return -1; ++ } ++#endif ++ ++ atomic_inc(&crypt->refcnt); ++ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ IEEE80211_DEBUG_DROP( ++ "decryption failed (SA=" MAC_FMT ++ ") res=%d\n", MAC_ARG(hdr->addr2), res); ++ if (res == -2) ++ IEEE80211_DEBUG_DROP("Decryption failed ICV " ++ "mismatch (key %d)\n", ++ skb->data[hdrlen + 3] >> 6); ++ ieee->ieee_stats.rx_discards_undecryptable++; ++ return -1; ++ } ++ ++ return res; ++} ++ ++ ++/* Called only as a tasklet (software IRQ), by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb, ++ int keyidx, struct ieee80211_crypt_data *crypt) ++{ ++ struct ieee80211_hdr_4addr *hdr; ++ int res, hdrlen; ++ ++ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) ++ return 0; ++ if (ieee->hwsec_active) ++ { ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb+ MAX_DEV_ADDR_SIZE); ++ tcb_desc->bHwSec = 1; ++ } ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); ++ ++ atomic_inc(&crypt->refcnt); ++ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" ++ " (SA=" MAC_FMT " keyidx=%d)\n", ++ ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/* this function is stolen from ipw2200 driver*/ ++#define IEEE_PACKET_RETRY_TIME (5*HZ) ++static int is_duplicate_packet(struct ieee80211_device *ieee, ++ struct ieee80211_hdr_4addr *header) ++{ ++ u16 fc = le16_to_cpu(header->frame_ctl); ++ u16 sc = le16_to_cpu(header->seq_ctl); ++ u16 seq = WLAN_GET_SEQ_SEQ(sc); ++ u16 frag = WLAN_GET_SEQ_FRAG(sc); ++ u16 *last_seq, *last_frag; ++ unsigned long *last_time; ++ struct ieee80211_hdr_3addrqos *hdr_3addrqos; ++ struct ieee80211_hdr_4addrqos *hdr_4addrqos; ++ u8 tid; ++ ++ ++ //TO2DS and QoS ++ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)header; ++ tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QCTL_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS ++ hdr_3addrqos = (struct ieee80211_hdr_3addrqos*)header; ++ tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QCTL_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { // no QoS ++ tid = 0; ++ } ++ ++ switch (ieee->iw_mode) { ++ case IW_MODE_ADHOC: ++ { ++ struct list_head *p; ++ struct ieee_ibss_seq *entry = NULL; ++ u8 *mac = header->addr2; ++ int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; ++ //for (pos = (head)->next; pos != (head); pos = pos->next) ++ //__list_for_each(p, &ieee->ibss_mac_hash[index]) { ++ list_for_each(p, &ieee->ibss_mac_hash[index]) { ++ entry = list_entry(p, struct ieee_ibss_seq, list); ++ if (!memcmp(entry->mac, mac, ETH_ALEN)) ++ break; ++ } ++ // if (memcmp(entry->mac, mac, ETH_ALEN)){ ++ if (p == &ieee->ibss_mac_hash[index]) { ++ entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); ++ if (!entry) { ++ printk(KERN_WARNING "Cannot malloc new mac entry\n"); ++ return 0; ++ } ++ memcpy(entry->mac, mac, ETH_ALEN); ++ entry->seq_num[tid] = seq; ++ entry->frag_num[tid] = frag; ++ entry->packet_time[tid] = jiffies; ++ list_add(&entry->list, &ieee->ibss_mac_hash[index]); ++ return 0; ++ } ++ last_seq = &entry->seq_num[tid]; ++ last_frag = &entry->frag_num[tid]; ++ last_time = &entry->packet_time[tid]; ++ break; ++ } ++ ++ case IW_MODE_INFRA: ++ last_seq = &ieee->last_rxseq_num[tid]; ++ last_frag = &ieee->last_rxfrag_num[tid]; ++ last_time = &ieee->last_packet_time[tid]; ++ ++ break; ++ default: ++ return 0; ++ } ++ ++// if(tid != 0) { ++// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl); ++// } ++ if ((*last_seq == seq) && ++ time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { ++ if (*last_frag == frag){ ++ //printk(KERN_WARNING "[1] go drop!\n"); ++ goto drop; ++ ++ } ++ if (*last_frag + 1 != frag) ++ /* out-of-order fragment */ ++ //printk(KERN_WARNING "[2] go drop!\n"); ++ goto drop; ++ } else ++ *last_seq = seq; ++ ++ *last_frag = frag; ++ *last_time = jiffies; ++ return 0; ++ ++drop: ++// BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); ++// printk("DUP\n"); ++ ++ return 1; ++} ++bool ++AddReorderEntry( ++ PRX_TS_RECORD pTS, ++ PRX_REORDER_ENTRY pReorderEntry ++ ) ++{ ++ struct list_head *pList = &pTS->RxPendingPktList; ++#if 1 ++ while(pList->next != &pTS->RxPendingPktList) ++ { ++ if( SN_LESS(pReorderEntry->SeqNum, ((PRX_REORDER_ENTRY)list_entry(pList->next,RX_REORDER_ENTRY,List))->SeqNum) ) ++ { ++ pList = pList->next; ++ } ++ else if( SN_EQUAL(pReorderEntry->SeqNum, ((PRX_REORDER_ENTRY)list_entry(pList->next,RX_REORDER_ENTRY,List))->SeqNum) ) ++ { ++ return false; ++ } ++ else ++ { ++ break; ++ } ++ } ++#endif ++ pReorderEntry->List.next = pList->next; ++ pReorderEntry->List.next->prev = &pReorderEntry->List; ++ pReorderEntry->List.prev = pList; ++ pList->next = &pReorderEntry->List; ++ ++ return true; ++} ++ ++void ieee80211_indicate_packets(struct ieee80211_device *ieee, struct ieee80211_rxb** prxbIndicateArray,u8 index) ++{ ++ u8 i = 0 , j=0; ++ u16 ethertype; ++// if(index > 1) ++// IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): hahahahhhh, We indicate packet from reorder list, index is %u\n",__FUNCTION__,index); ++ for(j = 0; jnr_subframes; i++) { ++ struct sk_buff *sub_skb = prxb->subframes[i]; ++ ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; ++ if (sub_skb->len >= 8 && ++ ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && ++ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ++ memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and ++ * replace EtherType */ ++ skb_pull(sub_skb, SNAP_SIZE); ++ memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ len = htons(sub_skb->len); ++ memcpy(skb_push(sub_skb, 2), &len, 2); ++ memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); ++ } ++ //stats->rx_packets++; ++ //stats->rx_bytes += sub_skb->len; ++ ++ /* Indicat the packets to upper layer */ ++ if (sub_skb) { ++ //printk("0skb_len(%d)\n", skb->len); ++ sub_skb->protocol = eth_type_trans(sub_skb, ieee->dev); ++ memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); ++ sub_skb->dev = ieee->dev; ++ sub_skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ ++ //skb->ip_summed = CHECKSUM_UNNECESSARY; /* 802.11 crc not sufficient */ ++ ieee->last_rx_ps_time = jiffies; ++ //printk("1skb_len(%d)\n", skb->len); ++ netif_rx(sub_skb); ++ } ++ } ++ kfree(prxb); ++ prxb = NULL; ++ } ++} ++ ++ ++void RxReorderIndicatePacket( struct ieee80211_device *ieee, ++ struct ieee80211_rxb* prxb, ++ PRX_TS_RECORD pTS, ++ u16 SeqNum) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ PRX_REORDER_ENTRY pReorderEntry = NULL; ++ struct ieee80211_rxb* prxbIndicateArray[REORDER_WIN_SIZE]; ++ u8 WinSize = pHTInfo->RxReorderWinSize; ++ u16 WinEnd = (pTS->RxIndicateSeq + WinSize -1)%4096; ++ u8 index = 0; ++ bool bMatchWinStart = false, bPktInBuf = false; ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): Seq is %d,pTS->RxIndicateSeq is %d, WinSize is %d\n",__FUNCTION__,SeqNum,pTS->RxIndicateSeq,WinSize); ++#if 0 ++ if(!list_empty(&ieee->RxReorder_Unused_List)) ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): ieee->RxReorder_Unused_List is nut NULL\n"); ++#endif ++ /* Rx Reorder initialize condition.*/ ++ if(pTS->RxIndicateSeq == 0xffff) { ++ pTS->RxIndicateSeq = SeqNum; ++ } ++ ++ /* Drop out the packet which SeqNum is smaller than WinStart */ ++ if(SN_LESS(SeqNum, pTS->RxIndicateSeq)) { ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"Packet Drop! IndicateSeq: %d, NewSeq: %d\n", ++ pTS->RxIndicateSeq, SeqNum); ++ pHTInfo->RxReorderDropCounter++; ++ { ++ int i; ++ for(i =0; i < prxb->nr_subframes; i++) { ++ dev_kfree_skb(prxb->subframes[i]); ++ } ++ kfree(prxb); ++ prxb = NULL; ++ } ++ return; ++ } ++ ++ /* ++ * Sliding window manipulation. Conditions includes: ++ * 1. Incoming SeqNum is equal to WinStart =>Window shift 1 ++ * 2. Incoming SeqNum is larger than the WinEnd => Window shift N ++ */ ++ if(SN_EQUAL(SeqNum, pTS->RxIndicateSeq)) { ++ pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; ++ bMatchWinStart = true; ++ } else if(SN_LESS(WinEnd, SeqNum)) { ++ if(SeqNum >= (WinSize - 1)) { ++ pTS->RxIndicateSeq = SeqNum + 1 -WinSize; ++ } else { ++ pTS->RxIndicateSeq = 4095 - (WinSize - (SeqNum +1)) + 1; ++ } ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n",pTS->RxIndicateSeq, SeqNum); ++ } ++ ++ /* ++ * Indication process. ++ * After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets ++ * with the SeqNum smaller than latest WinStart and buffer other packets. ++ */ ++ /* For Rx Reorder condition: ++ * 1. All packets with SeqNum smaller than WinStart => Indicate ++ * 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. ++ */ ++ if(bMatchWinStart) { ++ /* Current packet is going to be indicated.*/ ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n",\ ++ pTS->RxIndicateSeq, SeqNum); ++ prxbIndicateArray[0] = prxb; ++// printk("========================>%s(): SeqNum is %d\n",__FUNCTION__,SeqNum); ++ index = 1; ++ } else { ++ /* Current packet is going to be inserted into pending list.*/ ++ //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to orderd list\n",__FUNCTION__); ++ if(!list_empty(&ieee->RxReorder_Unused_List)) { ++ pReorderEntry = (PRX_REORDER_ENTRY)list_entry(ieee->RxReorder_Unused_List.next,RX_REORDER_ENTRY,List); ++ list_del_init(&pReorderEntry->List); ++ ++ /* Make a reorder entry and insert into a the packet list.*/ ++ pReorderEntry->SeqNum = SeqNum; ++ pReorderEntry->prxb = prxb; ++ // IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): pREorderEntry->SeqNum is %d\n",__FUNCTION__,pReorderEntry->SeqNum); ++ ++#if 1 ++ if(!AddReorderEntry(pTS, pReorderEntry)) { ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", ++ __FUNCTION__, pTS->RxIndicateSeq, SeqNum); ++ list_add_tail(&pReorderEntry->List,&ieee->RxReorder_Unused_List); ++ { ++ int i; ++ for(i =0; i < prxb->nr_subframes; i++) { ++ dev_kfree_skb(prxb->subframes[i]); ++ } ++ kfree(prxb); ++ prxb = NULL; ++ } ++ } else { ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER, ++ "Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n",pTS->RxIndicateSeq, SeqNum); ++ } ++#endif ++ } ++ else { ++ /* ++ * Packets are dropped if there is not enough reorder entries. ++ * This part shall be modified!! We can just indicate all the ++ * packets in buffer and get reorder entries. ++ */ ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n"); ++ { ++ int i; ++ for(i =0; i < prxb->nr_subframes; i++) { ++ dev_kfree_skb(prxb->subframes[i]); ++ } ++ kfree(prxb); ++ prxb = NULL; ++ } ++ } ++ } ++ ++ /* Check if there is any packet need indicate.*/ ++ while(!list_empty(&pTS->RxPendingPktList)) { ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): start RREORDER indicate\n",__FUNCTION__); ++#if 1 ++ pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); ++ if( SN_LESS(pReorderEntry->SeqNum, pTS->RxIndicateSeq) || ++ SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) ++ { ++ /* This protect buffer from overflow. */ ++ if(index >= REORDER_WIN_SIZE) { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Buffer overflow!! \n"); ++ bPktInBuf = true; ++ break; ++ } ++ ++ list_del_init(&pReorderEntry->List); ++ ++ if(SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) ++ pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096; ++ ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"Packets indication!! IndicateSeq: %d, NewSeq: %d\n",pTS->RxIndicateSeq, SeqNum); ++ prxbIndicateArray[index] = pReorderEntry->prxb; ++ // printk("========================>%s(): pReorderEntry->SeqNum is %d\n",__FUNCTION__,pReorderEntry->SeqNum); ++ index++; ++ ++ list_add_tail(&pReorderEntry->List,&ieee->RxReorder_Unused_List); ++ } else { ++ bPktInBuf = true; ++ break; ++ } ++#endif ++ } ++ ++ /* Handling pending timer. Set this timer to prevent from long time Rx buffering.*/ ++ if(index>0) { ++ // Cancel previous pending timer. ++ if (timer_pending(&pTS->RxPktPendingTimer)) ++ del_timer_sync(&pTS->RxPktPendingTimer); ++ pTS->RxTimeoutIndicateSeq = 0xffff; ++ ++ // Indicate packets ++ if(index>REORDER_WIN_SIZE){ ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorer buffer full!! \n"); ++ return; ++ } ++ ieee80211_indicate_packets(ieee, prxbIndicateArray, index); ++ bPktInBuf = false; ++ } ++ ++#if 1 ++ if(bPktInBuf && pTS->RxTimeoutIndicateSeq==0xffff) { ++ // Set new pending timer. ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): SET rx timeout timer\n", __FUNCTION__); ++ pTS->RxTimeoutIndicateSeq = pTS->RxIndicateSeq; ++#if 0 ++ if(timer_pending(&pTS->RxPktPendingTimer)) ++ del_timer_sync(&pTS->RxPktPendingTimer); ++ pTS->RxPktPendingTimer.expires = jiffies + MSECS(pHTInfo->RxReorderPendingTime); ++ add_timer(&pTS->RxPktPendingTimer); ++#else ++ mod_timer(&pTS->RxPktPendingTimer, jiffies + MSECS(pHTInfo->RxReorderPendingTime)); ++#endif ++ } ++#endif ++} ++ ++u8 parse_subframe(struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, ++ struct ieee80211_rxb *rxb,u8* src,u8* dst) ++{ ++ struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr* )skb->data; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ ++ u16 LLCOffset= sizeof(struct ieee80211_hdr_3addr); ++ u16 ChkLength; ++ bool bIsAggregateFrame = false; ++ u16 nSubframe_Length; ++ u8 nPadding_Length = 0; ++ u16 SeqNum=0; ++ ++ struct sk_buff *sub_skb; ++ u8 *data_ptr; ++ /* just for debug purpose */ ++ SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctl)); ++ ++ if((IEEE80211_QOS_HAS_SEQ(fc))&&\ ++ (((frameqos *)(skb->data + IEEE80211_3ADDR_LEN))->field.reserved)) { ++ bIsAggregateFrame = true; ++ } ++ ++ if(IEEE80211_QOS_HAS_SEQ(fc)) { ++ LLCOffset += 2; ++ } ++ ++ if(rx_stats->bContainHTC) { ++ LLCOffset += sHTCLng; ++ } ++ //printk("ChkLength = %d\n", LLCOffset); ++ // Null packet, don't indicate it to upper layer ++ ChkLength = LLCOffset;/* + (Frame_WEP(frame)!=0 ?Adapter->MgntInfo.SecurityInfo.EncryptionHeadOverhead:0);*/ ++ ++ if( skb->len <= ChkLength ) { ++ return 0; ++ } ++ ++ skb_pull(skb, LLCOffset); ++ ++ if(!bIsAggregateFrame) { ++ rxb->nr_subframes = 1; ++#ifdef JOHN_NOCPY ++ rxb->subframes[0] = skb; ++#else ++ rxb->subframes[0] = skb_copy(skb, GFP_ATOMIC); ++#endif ++ ++ memcpy(rxb->src,src,ETH_ALEN); ++ memcpy(rxb->dst,dst,ETH_ALEN); ++ //IEEE80211_DEBUG_DATA(IEEE80211_DL_RX,skb->data,skb->len); ++ return 1; ++ } else { ++ rxb->nr_subframes = 0; ++ memcpy(rxb->src,src,ETH_ALEN); ++ memcpy(rxb->dst,dst,ETH_ALEN); ++ while(skb->len > ETHERNET_HEADER_SIZE) { ++ /* Offset 12 denote 2 mac address */ ++ nSubframe_Length = *((u16*)(skb->data + 12)); ++ //==m==>change the length order ++ nSubframe_Length = (nSubframe_Length>>8) + (nSubframe_Length<<8); ++ ++ if(skb->len<(ETHERNET_HEADER_SIZE + nSubframe_Length)) { ++#if 0//cosa ++ RT_ASSERT( ++ (nRemain_Length>=(ETHERNET_HEADER_SIZE + nSubframe_Length)), ++ ("ParseSubframe(): A-MSDU subframe parse error!! Subframe Length: %d\n", nSubframe_Length) ); ++#endif ++ printk("%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n",\ ++ __FUNCTION__,rxb->nr_subframes); ++ printk("%s: A-MSDU parse error!! Subframe Length: %d\n",__FUNCTION__, nSubframe_Length); ++ printk("nRemain_Length is %d and nSubframe_Length is : %d\n",skb->len,nSubframe_Length); ++ printk("The Packet SeqNum is %d\n",SeqNum); ++ return 0; ++ } ++ ++ /* move the data point to data content */ ++ skb_pull(skb, ETHERNET_HEADER_SIZE); ++ ++#ifdef JOHN_NOCPY ++ sub_skb = skb_clone(skb, GFP_ATOMIC); ++ sub_skb->len = nSubframe_Length; ++ sub_skb->tail = sub_skb->data + nSubframe_Length; ++#else ++ /* Allocate new skb for releasing to upper layer */ ++ sub_skb = dev_alloc_skb(nSubframe_Length + 12); ++ skb_reserve(sub_skb, 12); ++ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); ++ memcpy(data_ptr,skb->data,nSubframe_Length); ++#endif ++ rxb->subframes[rxb->nr_subframes++] = sub_skb; ++ if(rxb->nr_subframes >= MAX_SUBFRAME_COUNT) { ++ IEEE80211_DEBUG_RX("ParseSubframe(): Too many Subframes! Packets dropped!\n"); ++ break; ++ } ++ skb_pull(skb,nSubframe_Length); ++ ++ if(skb->len != 0) { ++ nPadding_Length = 4 - ((nSubframe_Length + ETHERNET_HEADER_SIZE) % 4); ++ if(nPadding_Length == 4) { ++ nPadding_Length = 0; ++ } ++ ++ if(skb->len < nPadding_Length) { ++ return 0; ++ } ++ ++ skb_pull(skb,nPadding_Length); ++ } ++ } ++#ifdef JOHN_NOCPY ++ dev_kfree_skb(skb); ++#endif ++ //{just for debug added by david ++ //printk("AMSDU::rxb->nr_subframes = %d\n",rxb->nr_subframes); ++ //} ++ return rxb->nr_subframes; ++ } ++} ++ ++/* All received frames are sent to this function. @skb contains the frame in ++ * IEEE 802.11 format, i.e., in the format it was sent over air. ++ * This function is called only as a tasklet (software IRQ). */ ++int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats) ++{ ++ struct net_device *dev = ieee->dev; ++ struct ieee80211_hdr_4addr *hdr; ++ //struct ieee80211_hdr_3addrqos *hdr; ++ ++ size_t hdrlen; ++ u16 fc, type, stype, sc; ++ struct net_device_stats *stats; ++ unsigned int frag; ++ u8 *payload; ++ u16 ethertype; ++ //added by amy for reorder ++ u8 TID = 0; ++ u16 SeqNum = 0; ++ PRX_TS_RECORD pTS = NULL; ++ //bool bIsAggregateFrame = false; ++ //added by amy for reorder ++#ifdef NOT_YET ++ struct net_device *wds = NULL; ++ struct sk_buff *skb2 = NULL; ++ struct net_device *wds = NULL; ++ int frame_authorized = 0; ++ int from_assoc_ap = 0; ++ void *sta = NULL; ++#endif ++// u16 qos_ctl = 0; ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++ u8 bssid[ETH_ALEN]; ++ struct ieee80211_crypt_data *crypt = NULL; ++ int keyidx = 0; ++ ++ int i; ++ struct ieee80211_rxb* rxb = NULL; ++ // cheat the the hdr type ++ hdr = (struct ieee80211_hdr_4addr *)skb->data; ++ stats = &ieee->stats; ++ ++ if (skb->len < 10) { ++ printk(KERN_INFO "%s: SKB length < 10\n", ++ dev->name); ++ goto rx_dropped; ++ } ++ ++ fc = le16_to_cpu(hdr->frame_ctl); ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ sc = le16_to_cpu(hdr->seq_ctl); ++ ++ frag = WLAN_GET_SEQ_FRAG(sc); ++ hdrlen = ieee80211_get_hdrlen(fc); ++ ++ if(HTCCheck(ieee, skb->data)) ++ { ++ if(net_ratelimit()) ++ printk("find HTCControl\n"); ++ hdrlen += 4; ++ rx_stats->bContainHTC = 1; ++ } ++ ++ //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); ++#ifdef NOT_YET ++#if WIRELESS_EXT > 15 ++ /* Put this code here so that we avoid duplicating it in all ++ * Rx paths. - Jean II */ ++#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ ++ /* If spy monitoring on */ ++ if (iface->spy_data.spy_number > 0) { ++ struct iw_quality wstats; ++ wstats.level = rx_stats->rssi; ++ wstats.noise = rx_stats->noise; ++ wstats.updated = 6; /* No qual value */ ++ /* Update spy records */ ++ wireless_spy_update(dev, hdr->addr2, &wstats); ++ } ++#endif /* IW_WIRELESS_SPY */ ++#endif /* WIRELESS_EXT > 15 */ ++ hostap_update_rx_stats(local->ap, hdr, rx_stats); ++#endif ++ ++#if WIRELESS_EXT > 15 ++ if (ieee->iw_mode == IW_MODE_MONITOR) { ++ ieee80211_monitor_rx(ieee, skb, rx_stats); ++ stats->rx_packets++; ++ stats->rx_bytes += skb->len; ++ return 1; ++ } ++#endif ++ if (ieee->host_decrypt) { ++ int idx = 0; ++ if (skb->len >= hdrlen + 3) ++ idx = skb->data[hdrlen + 3] >> 6; ++ crypt = ieee->crypt[idx]; ++#ifdef NOT_YET ++ sta = NULL; ++ ++ /* Use station specific key to override default keys if the ++ * receiver address is a unicast address ("individual RA"). If ++ * bcrx_sta_key parameter is set, station specific key is used ++ * even with broad/multicast targets (this is against IEEE ++ * 802.11, but makes it easier to use different keys with ++ * stations that do not support WEP key mapping). */ ++ ++ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) ++ (void) hostap_handle_sta_crypto(local, hdr, &crypt, ++ &sta); ++#endif ++ ++ /* allow NULL decrypt to indicate an station specific override ++ * for default encryption */ ++ if (crypt && (crypt->ops == NULL || ++ crypt->ops->decrypt_mpdu == NULL)) ++ crypt = NULL; ++ ++ if (!crypt && (fc & IEEE80211_FCTL_WEP)) { ++ /* This seems to be triggered by some (multicast?) ++ * frames from other than current BSS, so just drop the ++ * frames silently instead of filling system log with ++ * these reports. */ ++ IEEE80211_DEBUG_DROP("Decryption failed (not set)" ++ " (SA=" MAC_FMT ")\n", ++ MAC_ARG(hdr->addr2)); ++ ieee->ieee_stats.rx_discards_undecryptable++; ++ goto rx_dropped; ++ } ++ } ++ ++ if (skb->len < IEEE80211_DATA_HDR3_LEN) ++ goto rx_dropped; ++ ++ // if QoS enabled, should check the sequence for each of the AC ++ if( (ieee->pHTInfo->bCurRxReorderEnable == false) || !ieee->current_network.qos_data.active|| !IsDataFrame(skb->data) || IsLegacyDataFrame(skb->data)){ ++ if (is_duplicate_packet(ieee, hdr)) ++ goto rx_dropped; ++ ++ } ++ else ++ { ++ PRX_TS_RECORD pRxTS = NULL; ++ #if 0 ++ struct ieee80211_hdr_3addr *hdr; ++ u16 fc; ++ hdr = (struct ieee80211_hdr_3addr *)skb->data; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ u8 tmp = (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS); ++ ++ u8 tid = (*((u8*)skb->data + (((fc& IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))?30:24)))&0xf; ++ printk("====================>fc:%x, tid:%d, tmp:%d\n", fc, tid, tmp); ++ //u8 tid = (u8)((frameqos*)(buf + ((fc & IEEE80211_FCTL_TODS)&&(fc & IEEE80211_FCTL_FROMDS))? 30 : 24))->field.tid; ++ #endif ++ //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): QOS ENABLE AND RECEIVE QOS DATA , we will get Ts, tid:%d\n",__FUNCTION__, tid); ++#if 1 ++ if(GetTs( ++ ieee, ++ (PTS_COMMON_INFO*) &pRxTS, ++ hdr->addr2, ++ (u8)Frame_QoSTID((u8*)(skb->data)), ++ RX_DIR, ++ true)) ++ { ++ ++ // IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): pRxTS->RxLastFragNum is %d,frag is %d,pRxTS->RxLastSeqNum is %d,seq is %d\n",__FUNCTION__,pRxTS->RxLastFragNum,frag,pRxTS->RxLastSeqNum,WLAN_GET_SEQ_SEQ(sc)); ++ if( (fc & (1<<11)) && ++ (frag == pRxTS->RxLastFragNum) && ++ (WLAN_GET_SEQ_SEQ(sc) == pRxTS->RxLastSeqNum) ) ++ { ++ goto rx_dropped; ++ } ++ else ++ { ++ pRxTS->RxLastFragNum = frag; ++ pRxTS->RxLastSeqNum = WLAN_GET_SEQ_SEQ(sc); ++ } ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s(): No TS!! Skip the check!!\n",__FUNCTION__); ++ goto rx_dropped; ++ } ++ } ++#endif ++ if (type == IEEE80211_FTYPE_MGMT) { ++ ++ #if 0 ++ if ( stype == IEEE80211_STYPE_AUTH && ++ fc & IEEE80211_FCTL_WEP && ieee->host_decrypt && ++ (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) ++ { ++ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " ++ "from " MAC_FMT "\n", dev->name, ++ MAC_ARG(hdr->addr2)); ++ /* TODO: could inform hostapd about this so that it ++ * could send auth failure report */ ++ goto rx_dropped; ++ } ++ #endif ++ ++ //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); ++ if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) ++ goto rx_dropped; ++ else ++ goto rx_exit; ++ } ++ ++ /* Data frame - extract src/dst addresses */ ++ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { ++ case IEEE80211_FCTL_FROMDS: ++ memcpy(dst, hdr->addr1, ETH_ALEN); ++ memcpy(src, hdr->addr3, ETH_ALEN); ++ memcpy(bssid, hdr->addr2, ETH_ALEN); ++ break; ++ case IEEE80211_FCTL_TODS: ++ memcpy(dst, hdr->addr3, ETH_ALEN); ++ memcpy(src, hdr->addr2, ETH_ALEN); ++ memcpy(bssid, hdr->addr1, ETH_ALEN); ++ break; ++ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: ++ if (skb->len < IEEE80211_DATA_HDR4_LEN) ++ goto rx_dropped; ++ memcpy(dst, hdr->addr3, ETH_ALEN); ++ memcpy(src, hdr->addr4, ETH_ALEN); ++ memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); ++ break; ++ case 0: ++ memcpy(dst, hdr->addr1, ETH_ALEN); ++ memcpy(src, hdr->addr2, ETH_ALEN); ++ memcpy(bssid, hdr->addr3, ETH_ALEN); ++ break; ++ } ++ ++#ifdef NOT_YET ++ if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) ++ goto rx_dropped; ++ if (wds) { ++ skb->dev = dev = wds; ++ stats = hostap_get_stats(dev); ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ++ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && ++ ieee->stadev && ++ memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { ++ /* Frame from BSSID of the AP for which we are a client */ ++ skb->dev = dev = ieee->stadev; ++ stats = hostap_get_stats(dev); ++ from_assoc_ap = 1; ++ } ++#endif ++ ++ dev->last_rx = jiffies; ++ ++#ifdef NOT_YET ++ if ((ieee->iw_mode == IW_MODE_MASTER || ++ ieee->iw_mode == IW_MODE_REPEAT) && ++ !from_assoc_ap) { ++ switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, ++ wds != NULL)) { ++ case AP_RX_CONTINUE_NOT_AUTHORIZED: ++ frame_authorized = 0; ++ break; ++ case AP_RX_CONTINUE: ++ frame_authorized = 1; ++ break; ++ case AP_RX_DROP: ++ goto rx_dropped; ++ case AP_RX_EXIT: ++ goto rx_exit; ++ } ++ } ++#endif ++ //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); ++ /* Nullfunc frames may have PS-bit set, so they must be passed to ++ * hostap_handle_sta_rx() before being dropped here. */ ++ if (stype != IEEE80211_STYPE_DATA && ++ stype != IEEE80211_STYPE_DATA_CFACK && ++ stype != IEEE80211_STYPE_DATA_CFPOLL && ++ stype != IEEE80211_STYPE_DATA_CFACKPOLL&& ++ stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4 ++ ) { ++ if (stype != IEEE80211_STYPE_NULLFUNC) ++ IEEE80211_DEBUG_DROP( ++ "RX: dropped data frame " ++ "with no data (type=0x%02x, " ++ "subtype=0x%02x, len=%d)\n", ++ type, stype, skb->len); ++ goto rx_dropped; ++ } ++ if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN)) ++ goto rx_dropped; ++ ++ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ ++ ++ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) ++ { ++ printk("decrypt frame error\n"); ++ goto rx_dropped; ++ } ++ ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ ++ /* skb: hdr + (possibly fragmented) plaintext payload */ ++ // PR: FIXME: hostap has additional conditions in the "if" below: ++ // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { ++ int flen; ++ struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); ++ IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); ++ ++ if (!frag_skb) { ++ IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, ++ "Rx cannot get skb from fragment " ++ "cache (morefrag=%d seq=%u frag=%u)\n", ++ (fc & IEEE80211_FCTL_MOREFRAGS) != 0, ++ WLAN_GET_SEQ_SEQ(sc), frag); ++ goto rx_dropped; ++ } ++ flen = skb->len; ++ if (frag != 0) ++ flen -= hdrlen; ++ ++ if (frag_skb->tail + flen > frag_skb->end) { ++ printk(KERN_WARNING "%s: host decrypted and " ++ "reassembled frame did not fit skb\n", ++ dev->name); ++ ieee80211_frag_cache_invalidate(ieee, hdr); ++ goto rx_dropped; ++ } ++ ++ if (frag == 0) { ++ /* copy first fragment (including full headers) into ++ * beginning of the fragment cache skb */ ++ memcpy(skb_put(frag_skb, flen), skb->data, flen); ++ } else { ++ /* append frame payload to the end of the fragment ++ * cache skb */ ++ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, ++ flen); ++ } ++ dev_kfree_skb_any(skb); ++ skb = NULL; ++ ++ if (fc & IEEE80211_FCTL_MOREFRAGS) { ++ /* more fragments expected - leave the skb in fragment ++ * cache for now; it will be delivered to upper layers ++ * after all fragments have been received */ ++ goto rx_exit; ++ } ++ ++ /* this was the last fragment and the frame will be ++ * delivered, so remove skb from fragment cache */ ++ skb = frag_skb; ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ ieee80211_frag_cache_invalidate(ieee, hdr); ++ } ++ ++ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still ++ * encrypted/authenticated */ ++ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) ++ { ++ printk("==>decrypt msdu error\n"); ++ goto rx_dropped; ++ } ++ ++ //added by amy for AP roaming ++ ieee->LinkDetectInfo.NumRecvDataInPeriod++; ++ ieee->LinkDetectInfo.NumRxOkInPeriod++; ++ ++ hdr = (struct ieee80211_hdr_4addr *) skb->data; ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) { ++ if (/*ieee->ieee802_1x &&*/ ++ ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ /* pass unencrypted EAPOL frames even if encryption is ++ * configured */ ++ struct eapol *eap = (struct eapol *)(skb->data + ++ 24); ++ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++#endif ++ } else { ++ IEEE80211_DEBUG_DROP( ++ "encryption configured, but RX " ++ "frame not encrypted (SA=" MAC_FMT ")\n", ++ MAC_ARG(hdr->addr2)); ++ goto rx_dropped; ++ } ++ } ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && ++ ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ struct eapol *eap = (struct eapol *)(skb->data + ++ 24); ++ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++ } ++#endif ++ ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep && ++ !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ IEEE80211_DEBUG_DROP( ++ "dropped unencrypted RX data " ++ "frame from " MAC_FMT ++ " (drop_unencrypted=1)\n", ++ MAC_ARG(hdr->addr2)); ++ goto rx_dropped; ++ } ++/* ++ if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n"); ++ } ++*/ ++//added by amy for reorder ++#if 1 ++ if(ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data) ++ && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1)) ++ { ++ TID = Frame_QoSTID(skb->data); ++ SeqNum = WLAN_GET_SEQ_SEQ(sc); ++ GetTs(ieee,(PTS_COMMON_INFO*) &pTS,hdr->addr2,TID,RX_DIR,true); ++ if(TID !=0 && TID !=3) ++ { ++ ieee->bis_any_nonbepkts = true; ++ } ++ } ++#endif ++//added by amy for reorder ++ /* skb: hdr + (possible reassembled) full plaintext payload */ ++ payload = skb->data + hdrlen; ++ //ethertype = (payload[6] << 8) | payload[7]; ++ rxb = (struct ieee80211_rxb*)kmalloc(sizeof(struct ieee80211_rxb),GFP_ATOMIC); ++ if(rxb == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR,"%s(): kmalloc rxb error\n",__FUNCTION__); ++ goto rx_dropped; ++ } ++ /* to parse amsdu packets */ ++ /* qos data packets & reserved bit is 1 */ ++ if(parse_subframe(skb,rx_stats,rxb,src,dst) == 0) { ++ /* only to free rxb, and not submit the packets to upper layer */ ++ for(i =0; i < rxb->nr_subframes; i++) { ++ dev_kfree_skb(rxb->subframes[i]); ++ } ++ kfree(rxb); ++ rxb = NULL; ++ goto rx_dropped; ++ } ++ ++ ieee->last_rx_ps_time = jiffies; ++//added by amy for reorder ++ if(ieee->pHTInfo->bCurRxReorderEnable == false ||pTS == NULL){ ++//added by amy for reorder ++ for(i = 0; inr_subframes; i++) { ++ struct sk_buff *sub_skb = rxb->subframes[i]; ++ ++ if (sub_skb) { ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; ++ if (sub_skb->len >= 8 && ++ ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && ++ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ++ memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and ++ * replace EtherType */ ++ skb_pull(sub_skb, SNAP_SIZE); ++ memcpy(skb_push(sub_skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ len = htons(sub_skb->len); ++ memcpy(skb_push(sub_skb, 2), &len, 2); ++ memcpy(skb_push(sub_skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), dst, ETH_ALEN); ++ } ++ ++ stats->rx_packets++; ++ stats->rx_bytes += sub_skb->len; ++ if(is_multicast_ether_addr(dst)) { ++ stats->multicast++; ++ } ++ ++ /* Indicat the packets to upper layer */ ++ //printk("0skb_len(%d)\n", skb->len); ++ sub_skb->protocol = eth_type_trans(sub_skb, dev); ++ memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); ++ sub_skb->dev = dev; ++ sub_skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ ++ //skb->ip_summed = CHECKSUM_UNNECESSARY; /* 802.11 crc not sufficient */ ++ //printk("1skb_len(%d)\n", skb->len); ++ netif_rx(sub_skb); ++ } ++ } ++ kfree(rxb); ++ rxb = NULL; ++ ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): REORDER ENABLE AND PTS not NULL, and we will enter RxReorderIndicatePacket()\n",__FUNCTION__); ++ RxReorderIndicatePacket(ieee, rxb, pTS, SeqNum); ++ } ++#ifndef JOHN_NOCPY ++ dev_kfree_skb(skb); ++#endif ++ ++ rx_exit: ++#ifdef NOT_YET ++ if (sta) ++ hostap_handle_sta_release(sta); ++#endif ++ return 1; ++ ++ rx_dropped: ++ if (rxb != NULL) ++ { ++ kfree(rxb); ++ rxb = NULL; ++ } ++ stats->rx_dropped++; ++ ++ /* Returning 0 indicates to caller that we have not handled the SKB-- ++ * so it is still allocated and can be used again by underlying ++ * hardware as a DMA target */ ++ return 0; ++} ++ ++#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 ++ ++static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; ++ ++/* ++* Make ther structure we read from the beacon packet has ++* the right values ++*/ ++static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element ++ *info_element, int sub_type) ++{ ++ ++ if (info_element->qui_subtype != sub_type) ++ return -1; ++ if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) ++ return -1; ++ if (info_element->qui_type != QOS_OUI_TYPE) ++ return -1; ++ if (info_element->version != QOS_VERSION_1) ++ return -1; ++ ++ return 0; ++} ++ ++ ++/* ++ * Parse a QoS parameter element ++ */ ++static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info ++ *element_param, struct ieee80211_info_element ++ *info_element) ++{ ++ int ret = 0; ++ u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; ++ ++ if ((info_element == NULL) || (element_param == NULL)) ++ return -1; ++ ++ if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { ++ memcpy(element_param->info_element.qui, info_element->data, ++ info_element->len); ++ element_param->info_element.elementID = info_element->id; ++ element_param->info_element.length = info_element->len; ++ } else ++ ret = -1; ++ if (ret == 0) ++ ret = ieee80211_verify_qos_info(&element_param->info_element, ++ QOS_OUI_PARAM_SUB_TYPE); ++ return ret; ++} ++ ++/* ++ * Parse a QoS information element ++ */ ++static int ieee80211_read_qos_info_element(struct ++ ieee80211_qos_information_element ++ *element_info, struct ieee80211_info_element ++ *info_element) ++{ ++ int ret = 0; ++ u16 size = sizeof(struct ieee80211_qos_information_element) - 2; ++ ++ if (element_info == NULL) ++ return -1; ++ if (info_element == NULL) ++ return -1; ++ ++ if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { ++ memcpy(element_info->qui, info_element->data, ++ info_element->len); ++ element_info->elementID = info_element->id; ++ element_info->length = info_element->len; ++ } else ++ ret = -1; ++ ++ if (ret == 0) ++ ret = ieee80211_verify_qos_info(element_info, ++ QOS_OUI_INFO_SUB_TYPE); ++ return ret; ++} ++ ++ ++/* ++ * Write QoS parameters from the ac parameters. ++ */ ++static int ieee80211_qos_convert_ac_to_parameters(struct ++ ieee80211_qos_parameter_info ++ *param_elm, struct ++ ieee80211_qos_parameters ++ *qos_param) ++{ ++ int rc = 0; ++ int i; ++ struct ieee80211_qos_ac_parameter *ac_params; ++ u8 aci; ++ //u8 cw_min; ++ //u8 cw_max; ++ ++ for (i = 0; i < QOS_QUEUE_NUM; i++) { ++ ac_params = &(param_elm->ac_params_record[i]); ++ ++ aci = (ac_params->aci_aifsn & 0x60) >> 5; ++ ++ if(aci >= QOS_QUEUE_NUM) ++ continue; ++ qos_param->aifs[aci] = (ac_params->aci_aifsn) & 0x0f; ++ ++ /* WMM spec P.11: The minimum value for AIFSN shall be 2 */ ++ qos_param->aifs[aci] = (qos_param->aifs[aci] < 2) ? 2:qos_param->aifs[aci]; ++ ++ qos_param->cw_min[aci] = ac_params->ecw_min_max & 0x0F; ++ ++ qos_param->cw_max[aci] = (ac_params->ecw_min_max & 0xF0) >> 4; ++ ++ qos_param->flag[aci] = ++ (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; ++ qos_param->tx_op_limit[aci] = le16_to_cpu(ac_params->tx_op_limit); ++ } ++ return rc; ++} ++ ++/* ++ * we have a generic data element which it may contain QoS information or ++ * parameters element. check the information element length to decide ++ * which type to read ++ */ ++static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element ++ *info_element, ++ struct ieee80211_network *network) ++{ ++ int rc = 0; ++ struct ieee80211_qos_parameters *qos_param = NULL; ++ struct ieee80211_qos_information_element qos_info_element; ++ ++ rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); ++ ++ if (rc == 0) { ++ network->qos_data.param_count = qos_info_element.ac_info & 0x0F; ++ network->flags |= NETWORK_HAS_QOS_INFORMATION; ++ } else { ++ struct ieee80211_qos_parameter_info param_element; ++ ++ rc = ieee80211_read_qos_param_element(¶m_element, ++ info_element); ++ if (rc == 0) { ++ qos_param = &(network->qos_data.parameters); ++ ieee80211_qos_convert_ac_to_parameters(¶m_element, ++ qos_param); ++ network->flags |= NETWORK_HAS_QOS_PARAMETERS; ++ network->qos_data.param_count = ++ param_element.info_element.ac_info & 0x0F; ++ } ++ } ++ ++ if (rc == 0) { ++ IEEE80211_DEBUG_QOS("QoS is supported\n"); ++ network->qos_data.supported = 1; ++ } ++ return rc; ++} ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x ++ ++static const char *get_info_element_string(u16 id) ++{ ++ switch (id) { ++ MFIE_STRING(SSID); ++ MFIE_STRING(RATES); ++ MFIE_STRING(FH_SET); ++ MFIE_STRING(DS_SET); ++ MFIE_STRING(CF_SET); ++ MFIE_STRING(TIM); ++ MFIE_STRING(IBSS_SET); ++ MFIE_STRING(COUNTRY); ++ MFIE_STRING(HOP_PARAMS); ++ MFIE_STRING(HOP_TABLE); ++ MFIE_STRING(REQUEST); ++ MFIE_STRING(CHALLENGE); ++ MFIE_STRING(POWER_CONSTRAINT); ++ MFIE_STRING(POWER_CAPABILITY); ++ MFIE_STRING(TPC_REQUEST); ++ MFIE_STRING(TPC_REPORT); ++ MFIE_STRING(SUPP_CHANNELS); ++ MFIE_STRING(CSA); ++ MFIE_STRING(MEASURE_REQUEST); ++ MFIE_STRING(MEASURE_REPORT); ++ MFIE_STRING(QUIET); ++ MFIE_STRING(IBSS_DFS); ++ // MFIE_STRING(ERP_INFO); ++ MFIE_STRING(RSN); ++ MFIE_STRING(RATES_EX); ++ MFIE_STRING(GENERIC); ++ MFIE_STRING(QOS_PARAMETER); ++ default: ++ return "UNKNOWN"; ++ } ++} ++#endif ++ ++#ifdef ENABLE_DOT11D ++static inline void ieee80211_extract_country_ie( ++ struct ieee80211_device *ieee, ++ struct ieee80211_info_element *info_element, ++ struct ieee80211_network *network, ++ u8 * addr2 ++) ++{ ++ if(IS_DOT11D_ENABLE(ieee)) ++ { ++ if(info_element->len!= 0) ++ { ++ memcpy(network->CountryIeBuf, info_element->data, info_element->len); ++ network->CountryIeLen = info_element->len; ++ ++ if(!IS_COUNTRY_IE_VALID(ieee)) ++ { ++ Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); ++ } ++ } ++ ++ // ++ // 070305, rcnjko: I update country IE watch dog here because ++ // some AP (e.g. Cisco 1242) don't include country IE in their ++ // probe response frame. ++ // ++ if(IS_EQUAL_CIE_SRC(ieee, addr2) ) ++ { ++ UPDATE_CIE_WATCHDOG(ieee); ++ } ++ } ++ ++} ++#endif ++ ++int ieee80211_parse_info_param(struct ieee80211_device *ieee, ++ struct ieee80211_info_element *info_element, ++ u16 length, ++ struct ieee80211_network *network, ++ struct ieee80211_rx_stats *stats) ++{ ++ u8 i; ++ short offset; ++ u16 tmp_htcap_len=0; ++ u16 tmp_htinfo_len=0; ++ u16 ht_realtek_agg_len=0; ++ u8 ht_realtek_agg_buf[MAX_IE_LEN]; ++// u16 broadcom_len = 0; ++#ifdef CONFIG_IEEE80211_DEBUG ++ char rates_str[64]; ++ char *p; ++#endif ++ ++ while (length >= sizeof(*info_element)) { ++ if (sizeof(*info_element) + info_element->len > length) { ++ IEEE80211_DEBUG_MGMT("Info elem: parse failed: " ++ "info_element->len + 2 > left : " ++ "info_element->len+2=%zd left=%d, id=%d.\n", ++ info_element->len + ++ sizeof(*info_element), ++ length, info_element->id); ++ /* We stop processing but don't return an error here ++ * because some misbehaviour APs break this rule. ie. ++ * Orinoco AP1000. */ ++ break; ++ } ++ ++ switch (info_element->id) { ++ case MFIE_TYPE_SSID: ++ if (ieee80211_is_empty_essid(info_element->data, ++ info_element->len)) { ++ network->flags |= NETWORK_EMPTY_ESSID; ++ break; ++ } ++ ++ network->ssid_len = min(info_element->len, ++ (u8) IW_ESSID_MAX_SIZE); ++ memcpy(network->ssid, info_element->data, network->ssid_len); ++ if (network->ssid_len < IW_ESSID_MAX_SIZE) ++ memset(network->ssid + network->ssid_len, 0, ++ IW_ESSID_MAX_SIZE - network->ssid_len); ++ ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", ++ network->ssid, network->ssid_len); ++ break; ++ ++ case MFIE_TYPE_RATES: ++#ifdef CONFIG_IEEE80211_DEBUG ++ p = rates_str; ++#endif ++ network->rates_len = min(info_element->len, ++ MAX_RATES_LENGTH); ++ for (i = 0; i < network->rates_len; i++) { ++ network->rates[i] = info_element->data[i]; ++#ifdef CONFIG_IEEE80211_DEBUG ++ p += snprintf(p, sizeof(rates_str) - ++ (p - rates_str), "%02X ", ++ network->rates[i]); ++#endif ++ if (ieee80211_is_ofdm_rate ++ (info_element->data[i])) { ++ network->flags |= NETWORK_HAS_OFDM; ++ if (info_element->data[i] & ++ IEEE80211_BASIC_RATE_MASK) ++ network->flags &= ++ ~NETWORK_HAS_CCK; ++ } ++ } ++ ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n", ++ rates_str, network->rates_len); ++ break; ++ ++ case MFIE_TYPE_RATES_EX: ++#ifdef CONFIG_IEEE80211_DEBUG ++ p = rates_str; ++#endif ++ network->rates_ex_len = min(info_element->len, ++ MAX_RATES_EX_LENGTH); ++ for (i = 0; i < network->rates_ex_len; i++) { ++ network->rates_ex[i] = info_element->data[i]; ++#ifdef CONFIG_IEEE80211_DEBUG ++ p += snprintf(p, sizeof(rates_str) - ++ (p - rates_str), "%02X ", ++ network->rates[i]); ++#endif ++ if (ieee80211_is_ofdm_rate ++ (info_element->data[i])) { ++ network->flags |= NETWORK_HAS_OFDM; ++ if (info_element->data[i] & ++ IEEE80211_BASIC_RATE_MASK) ++ network->flags &= ++ ~NETWORK_HAS_CCK; ++ } ++ } ++ ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n", ++ rates_str, network->rates_ex_len); ++ break; ++ ++ case MFIE_TYPE_DS_SET: ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n", ++ info_element->data[0]); ++ network->channel = info_element->data[0]; ++ break; ++ ++ case MFIE_TYPE_FH_SET: ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_CF_SET: ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_TIM: ++ if(info_element->len < 4) ++ break; ++ ++ network->tim.tim_count = info_element->data[0]; ++ network->tim.tim_period = info_element->data[1]; ++ ++ network->dtim_period = info_element->data[1]; ++ if(ieee->state != IEEE80211_LINKED) ++ break; ++#if 0 ++ network->last_dtim_sta_time[0] = stats->mac_time[0]; ++#else ++ //we use jiffies for legacy Power save ++ network->last_dtim_sta_time[0] = jiffies; ++#endif ++ network->last_dtim_sta_time[1] = stats->mac_time[1]; ++ ++ network->dtim_data = IEEE80211_DTIM_VALID; ++ ++ if(info_element->data[0] != 0) ++ break; ++ ++ if(info_element->data[2] & 1) ++ network->dtim_data |= IEEE80211_DTIM_MBCAST; ++ ++ offset = (info_element->data[2] >> 1)*2; ++ ++ //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id); ++ ++ if(ieee->assoc_id < 8*offset || ++ ieee->assoc_id > 8*(offset + info_element->len -3)) ++ ++ break; ++ ++ offset = (ieee->assoc_id / 8) - offset;// + ((aid % 8)? 0 : 1) ; ++ ++ if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) ++ network->dtim_data |= IEEE80211_DTIM_UCAST; ++ ++ //IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n"); ++ break; ++ ++ case MFIE_TYPE_ERP: ++ network->erp_value = info_element->data[0]; ++ network->flags |= NETWORK_HAS_ERP_VALUE; ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", ++ network->erp_value); ++ break; ++ case MFIE_TYPE_IBSS_SET: ++ network->atim_window = info_element->data[0]; ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n", ++ network->atim_window); ++ break; ++ ++ case MFIE_TYPE_CHALLENGE: ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_GENERIC: ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n", ++ info_element->len); ++ if (!ieee80211_parse_qos_info_param_IE(info_element, ++ network)) ++ break; ++ ++ if (info_element->len >= 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x01) { ++ network->wpa_ie_len = min(info_element->len + 2, ++ MAX_WPA_IE_LEN); ++ memcpy(network->wpa_ie, info_element, ++ network->wpa_ie_len); ++ break; ++ } ++ ++#ifdef THOMAS_TURBO ++ if (info_element->len == 7 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0xe0 && ++ info_element->data[2] == 0x4c && ++ info_element->data[3] == 0x01 && ++ info_element->data[4] == 0x02) { ++ network->Turbo_Enable = 1; ++ } ++#endif ++ ++ //for HTcap and HTinfo parameters ++ if(tmp_htcap_len == 0){ ++ if(info_element->len >= 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x90 && ++ info_element->data[2] == 0x4c && ++ info_element->data[3] == 0x033){ ++ ++ tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN); ++ if(tmp_htcap_len != 0){ ++ network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; ++ network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\ ++ sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len; ++ memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen); ++ } ++ } ++ if(tmp_htcap_len != 0) ++ network->bssht.bdSupportHT = true; ++ else ++ network->bssht.bdSupportHT = false; ++ } ++ ++ ++ if(tmp_htinfo_len == 0){ ++ if(info_element->len >= 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x90 && ++ info_element->data[2] == 0x4c && ++ info_element->data[3] == 0x034){ ++ ++ tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN); ++ if(tmp_htinfo_len != 0){ ++ network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; ++ if(tmp_htinfo_len){ ++ network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\ ++ sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len; ++ memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen); ++ } ++ ++ } ++ ++ } ++ } ++ ++ if(ieee->aggregation){ ++ if(network->bssht.bdSupportHT){ ++ if(info_element->len >= 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0xe0 && ++ info_element->data[2] == 0x4c && ++ info_element->data[3] == 0x02){ ++ ++ ht_realtek_agg_len = min(info_element->len,(u8)MAX_IE_LEN); ++ memcpy(ht_realtek_agg_buf,info_element->data,info_element->len); ++ ++ } ++ if(ht_realtek_agg_len >= 5){ ++ network->bssht.bdRT2RTAggregation = true; ++ ++ if((ht_realtek_agg_buf[4] == 1) && (ht_realtek_agg_buf[5] & 0x02)) ++ network->bssht.bdRT2RTLongSlotTime = true; ++ } ++ } ++ ++ } ++ ++ //if(tmp_htcap_len !=0 || tmp_htinfo_len != 0) ++ { ++ if((info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x05 && ++ info_element->data[2] == 0xb5) || ++ (info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x0a && ++ info_element->data[2] == 0xf7) || ++ (info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x10 && ++ info_element->data[2] == 0x18)){ ++ ++ network->broadcom_cap_exist = true; ++ ++ } ++ } ++#if 0 ++ if (tmp_htcap_len !=0) ++ { ++ u16 cap_ext = ((PHT_CAPABILITY_ELE)&info_element->data[0])->ExtHTCapInfo; ++ if ((cap_ext & 0x0c00) == 0x0c00) ++ { ++ network->ralink_cap_exist = true; ++ } ++ } ++#endif ++ if(info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x0c && ++ info_element->data[2] == 0x43) ++ { ++ network->ralink_cap_exist = true; ++ } ++ else ++ network->ralink_cap_exist = false; ++ //added by amy for atheros AP ++ if((info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x03 && ++ info_element->data[2] == 0x7f) || ++ (info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x13 && ++ info_element->data[2] == 0x74)) ++ { ++ printk("========>%s(): athros AP is exist\n",__FUNCTION__); ++ network->atheros_cap_exist = true; ++ } ++ else ++ network->atheros_cap_exist = false; ++ ++ if(info_element->len >= 3 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x40 && ++ info_element->data[2] == 0x96) ++ { ++ network->cisco_cap_exist = true; ++ } ++ else ++ network->cisco_cap_exist = false; ++ //added by amy for LEAP of cisco ++ if(info_element->len > 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x40 && ++ info_element->data[2] == 0x96 && ++ info_element->data[3] == 0x01) ++ { ++ if(info_element->len == 6) ++ { ++ memcpy(network->CcxRmState, &info_element[4], 2); ++ if(network->CcxRmState[0] != 0) ++ { ++ network->bCcxRmEnable = true; ++ } ++ else ++ network->bCcxRmEnable = false; ++ // ++ // CCXv4 Table 59-1 MBSSID Masks. ++ // ++ network->MBssidMask = network->CcxRmState[1] & 0x07; ++ if(network->MBssidMask != 0) ++ { ++ network->bMBssidValid = true; ++ network->MBssidMask = 0xff << (network->MBssidMask); ++ cpMacAddr(network->MBssid, network->bssid); ++ network->MBssid[5] &= network->MBssidMask; ++ } ++ else ++ { ++ network->bMBssidValid = false; ++ } ++ } ++ else ++ { ++ network->bCcxRmEnable = false; ++ } ++ } ++ if(info_element->len > 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x40 && ++ info_element->data[2] == 0x96 && ++ info_element->data[3] == 0x03) ++ { ++ if(info_element->len == 5) ++ { ++ network->bWithCcxVerNum = true; ++ network->BssCcxVerNumber = info_element->data[4]; ++ } ++ else ++ { ++ network->bWithCcxVerNum = false; ++ network->BssCcxVerNumber = 0; ++ } ++ } ++ break; ++ ++ case MFIE_TYPE_RSN: ++ IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n", ++ info_element->len); ++ network->rsn_ie_len = min(info_element->len + 2, ++ MAX_WPA_IE_LEN); ++ memcpy(network->rsn_ie, info_element, ++ network->rsn_ie_len); ++ break; ++ ++ //HT related element. ++ case MFIE_TYPE_HT_CAP: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_CAP: %d bytes\n", ++ info_element->len); ++ tmp_htcap_len = min(info_element->len,(u8)MAX_IE_LEN); ++ if(tmp_htcap_len != 0){ ++ network->bssht.bdHTSpecVer = HT_SPEC_VER_EWC; ++ network->bssht.bdHTCapLen = tmp_htcap_len > sizeof(network->bssht.bdHTCapBuf)?\ ++ sizeof(network->bssht.bdHTCapBuf):tmp_htcap_len; ++ memcpy(network->bssht.bdHTCapBuf,info_element->data,network->bssht.bdHTCapLen); ++ ++ //If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT() ++ // windows driver will update WMM parameters each beacon received once connected ++ // Linux driver is a bit different. ++ network->bssht.bdSupportHT = true; ++ } ++ else ++ network->bssht.bdSupportHT = false; ++ break; ++ ++ ++ case MFIE_TYPE_HT_INFO: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_HT_INFO: %d bytes\n", ++ info_element->len); ++ tmp_htinfo_len = min(info_element->len,(u8)MAX_IE_LEN); ++ if(tmp_htinfo_len){ ++ network->bssht.bdHTSpecVer = HT_SPEC_VER_IEEE; ++ network->bssht.bdHTInfoLen = tmp_htinfo_len > sizeof(network->bssht.bdHTInfoBuf)?\ ++ sizeof(network->bssht.bdHTInfoBuf):tmp_htinfo_len; ++ memcpy(network->bssht.bdHTInfoBuf,info_element->data,network->bssht.bdHTInfoLen); ++ } ++ break; ++ ++ case MFIE_TYPE_AIRONET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_AIRONET: %d bytes\n", ++ info_element->len); ++ if(info_element->len >IE_CISCO_FLAG_POSITION) ++ { ++ network->bWithAironetIE = true; ++ ++ // CCX 1 spec v1.13, A01.1 CKIP Negotiation (page23): ++ // "A Cisco access point advertises support for CKIP in beacon and probe response packets, ++ // by adding an Aironet element and setting one or both of the CKIP negotiation bits." ++ if( (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_MIC) || ++ (info_element->data[IE_CISCO_FLAG_POSITION]&SUPPORT_CKIP_PK) ) ++ { ++ network->bCkipSupported = true; ++ } ++ else ++ { ++ network->bCkipSupported = false; ++ } ++ } ++ else ++ { ++ network->bWithAironetIE = false; ++ network->bCkipSupported = false; ++ } ++ break; ++ case MFIE_TYPE_QOS_PARAMETER: ++ printk(KERN_ERR ++ "QoS Error need to parse QOS_PARAMETER IE\n"); ++ break; ++ ++#ifdef ENABLE_DOT11D ++ case MFIE_TYPE_COUNTRY: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", ++ info_element->len); ++ //printk("=====>Receive <%s> Country IE\n",network->ssid); ++ ieee80211_extract_country_ie(ieee, info_element, network, network->bssid);//addr2 is same as addr3 when from an AP ++ break; ++#endif ++/* TODO */ ++#if 0 ++ /* 802.11h */ ++ case MFIE_TYPE_POWER_CONSTRAINT: ++ network->power_constraint = info_element->data[0]; ++ network->flags |= NETWORK_HAS_POWER_CONSTRAINT; ++ break; ++ ++ case MFIE_TYPE_CSA: ++ network->power_constraint = info_element->data[0]; ++ network->flags |= NETWORK_HAS_CSA; ++ break; ++ ++ case MFIE_TYPE_QUIET: ++ network->quiet.count = info_element->data[0]; ++ network->quiet.period = info_element->data[1]; ++ network->quiet.duration = info_element->data[2]; ++ network->quiet.offset = info_element->data[3]; ++ network->flags |= NETWORK_HAS_QUIET; ++ break; ++ ++ case MFIE_TYPE_IBSS_DFS: ++ if (network->ibss_dfs) ++ break; ++ network->ibss_dfs = kmemdup(info_element->data, ++ info_element->len, ++ GFP_ATOMIC); ++ if (!network->ibss_dfs) ++ return 1; ++ network->flags |= NETWORK_HAS_IBSS_DFS; ++ break; ++ ++ case MFIE_TYPE_TPC_REPORT: ++ network->tpc_report.transmit_power = ++ info_element->data[0]; ++ network->tpc_report.link_margin = info_element->data[1]; ++ network->flags |= NETWORK_HAS_TPC_REPORT; ++ break; ++#endif ++ default: ++ IEEE80211_DEBUG_MGMT ++ ("Unsupported info element: %s (%d)\n", ++ get_info_element_string(info_element->id), ++ info_element->id); ++ break; ++ } ++ ++ length -= sizeof(*info_element) + info_element->len; ++ info_element = ++ (struct ieee80211_info_element *)&info_element-> ++ data[info_element->len]; ++ } ++ ++ if(!network->atheros_cap_exist && !network->broadcom_cap_exist && ++ !network->cisco_cap_exist && !network->ralink_cap_exist && !network->bssht.bdRT2RTAggregation) ++ { ++ network->unknown_cap_exist = true; ++ } ++ else ++ { ++ network->unknown_cap_exist = false; ++ } ++ return 0; ++} ++ ++static inline u8 ieee80211_SignalStrengthTranslate( ++ u8 CurrSS ++ ) ++{ ++ u8 RetSS; ++ ++ // Step 1. Scale mapping. ++ if(CurrSS >= 71 && CurrSS <= 100) ++ { ++ RetSS = 90 + ((CurrSS - 70) / 3); ++ } ++ else if(CurrSS >= 41 && CurrSS <= 70) ++ { ++ RetSS = 78 + ((CurrSS - 40) / 3); ++ } ++ else if(CurrSS >= 31 && CurrSS <= 40) ++ { ++ RetSS = 66 + (CurrSS - 30); ++ } ++ else if(CurrSS >= 21 && CurrSS <= 30) ++ { ++ RetSS = 54 + (CurrSS - 20); ++ } ++ else if(CurrSS >= 5 && CurrSS <= 20) ++ { ++ RetSS = 42 + (((CurrSS - 5) * 2) / 3); ++ } ++ else if(CurrSS == 4) ++ { ++ RetSS = 36; ++ } ++ else if(CurrSS == 3) ++ { ++ RetSS = 27; ++ } ++ else if(CurrSS == 2) ++ { ++ RetSS = 18; ++ } ++ else if(CurrSS == 1) ++ { ++ RetSS = 9; ++ } ++ else ++ { ++ RetSS = CurrSS; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ // Step 2. Smoothing. ++ ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ return RetSS; ++} ++ ++long ieee80211_translate_todbm(u8 signal_strength_index )// 0-100 index. ++{ ++ long signal_power; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ signal_power = (long)((signal_strength_index + 1) >> 1); ++ signal_power -= 95; ++ ++ return signal_power; ++} ++ ++static inline int ieee80211_network_init( ++ struct ieee80211_device *ieee, ++ struct ieee80211_probe_response *beacon, ++ struct ieee80211_network *network, ++ struct ieee80211_rx_stats *stats) ++{ ++#ifdef CONFIG_IEEE80211_DEBUG ++ //char rates_str[64]; ++ //char *p; ++#endif ++ ++ network->qos_data.active = 0; ++ network->qos_data.supported = 0; ++ network->qos_data.param_count = 0; ++ network->qos_data.old_param_count = 0; ++ ++ /* Pull out fixed field data */ ++ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); ++ network->capability = le16_to_cpu(beacon->capability); ++ network->last_scanned = jiffies; ++ network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]); ++ network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]); ++ network->beacon_interval = le32_to_cpu(beacon->beacon_interval); ++ /* Where to pull this? beacon->listen_interval;*/ ++ network->listen_interval = 0x0A; ++ network->rates_len = network->rates_ex_len = 0; ++ network->last_associate = 0; ++ network->ssid_len = 0; ++ network->flags = 0; ++ network->atim_window = 0; ++ network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? ++ 0x3 : 0x0; ++ network->berp_info_valid = false; ++ network->broadcom_cap_exist = false; ++ network->ralink_cap_exist = false; ++ network->atheros_cap_exist = false; ++ network->cisco_cap_exist = false; ++ network->unknown_cap_exist = false; ++#ifdef THOMAS_TURBO ++ network->Turbo_Enable = 0; ++#endif ++#ifdef ENABLE_DOT11D ++ network->CountryIeLen = 0; ++ memset(network->CountryIeBuf, 0, MAX_IE_LEN); ++#endif ++//Initialize HT parameters ++ //ieee80211_ht_initialize(&network->bssht); ++ HTInitializeBssDesc(&network->bssht); ++ if (stats->freq == IEEE80211_52GHZ_BAND) { ++ /* for A band (No DS info) */ ++ network->channel = stats->received_channel; ++ } else ++ network->flags |= NETWORK_HAS_CCK; ++ ++ network->wpa_ie_len = 0; ++ network->rsn_ie_len = 0; ++ ++ if (ieee80211_parse_info_param ++ (ieee,beacon->info_element, stats->len - sizeof(*beacon), network, stats)) ++ return 1; ++ ++ network->mode = 0; ++ if (stats->freq == IEEE80211_52GHZ_BAND) ++ network->mode = IEEE_A; ++ else { ++ if (network->flags & NETWORK_HAS_OFDM) ++ network->mode |= IEEE_G; ++ if (network->flags & NETWORK_HAS_CCK) ++ network->mode |= IEEE_B; ++ } ++ ++ if (network->mode == 0) { ++ IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " ++ "network.\n", ++ escape_essid(network->ssid, ++ network->ssid_len), ++ MAC_ARG(network->bssid)); ++ return 1; ++ } ++ ++ if(network->bssht.bdSupportHT){ ++ if(network->mode == IEEE_A) ++ network->mode = IEEE_N_5G; ++ else if(network->mode & (IEEE_G | IEEE_B)) ++ network->mode = IEEE_N_24G; ++ } ++ if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) ++ network->flags |= NETWORK_EMPTY_ESSID; ++ ++#if 1 ++ stats->signal = 30 + (stats->SignalStrength * 70) / 100; ++ //stats->signal = ieee80211_SignalStrengthTranslate(stats->signal); ++ stats->noise = ieee80211_translate_todbm((u8)(100-stats->signal)) -25; ++#endif ++ ++ memcpy(&network->stats, stats, sizeof(network->stats)); ++ ++ return 0; ++} ++ ++static inline int is_same_network(struct ieee80211_network *src, ++ struct ieee80211_network *dst, struct ieee80211_device* ieee) ++{ ++ /* A network is only a duplicate if the channel, BSSID, ESSID ++ * and the capability field (in particular IBSS and BSS) all match. ++ * We treat all with the same BSSID and channel ++ * as one network */ ++ return //((src->ssid_len == dst->ssid_len) && ++ (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && ++ (src->channel == dst->channel) && ++ !memcmp(src->bssid, dst->bssid, ETH_ALEN) && ++ //!memcmp(src->ssid, dst->ssid, src->ssid_len) && ++ (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && ++ ((src->capability & WLAN_CAPABILITY_IBSS) == ++ (dst->capability & WLAN_CAPABILITY_IBSS)) && ++ ((src->capability & WLAN_CAPABILITY_BSS) == ++ (dst->capability & WLAN_CAPABILITY_BSS))); ++} ++ ++static inline void update_network(struct ieee80211_network *dst, ++ struct ieee80211_network *src) ++{ ++ int qos_active; ++ u8 old_param; ++ ++ memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); ++ dst->capability = src->capability; ++ memcpy(dst->rates, src->rates, src->rates_len); ++ dst->rates_len = src->rates_len; ++ memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); ++ dst->rates_ex_len = src->rates_ex_len; ++ if(src->ssid_len > 0) ++ { ++ memset(dst->ssid, 0, dst->ssid_len); ++ dst->ssid_len = src->ssid_len; ++ memcpy(dst->ssid, src->ssid, src->ssid_len); ++ } ++ dst->mode = src->mode; ++ dst->flags = src->flags; ++ dst->time_stamp[0] = src->time_stamp[0]; ++ dst->time_stamp[1] = src->time_stamp[1]; ++ if (src->flags & NETWORK_HAS_ERP_VALUE) ++ { ++ dst->erp_value = src->erp_value; ++ dst->berp_info_valid = src->berp_info_valid = true; ++ } ++ dst->beacon_interval = src->beacon_interval; ++ dst->listen_interval = src->listen_interval; ++ dst->atim_window = src->atim_window; ++ dst->dtim_period = src->dtim_period; ++ dst->dtim_data = src->dtim_data; ++ dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0]; ++ dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1]; ++ memcpy(&dst->tim, &src->tim, sizeof(struct ieee80211_tim_parameters)); ++ ++ dst->bssht.bdSupportHT = src->bssht.bdSupportHT; ++ dst->bssht.bdRT2RTAggregation = src->bssht.bdRT2RTAggregation; ++ dst->bssht.bdHTCapLen= src->bssht.bdHTCapLen; ++ memcpy(dst->bssht.bdHTCapBuf,src->bssht.bdHTCapBuf,src->bssht.bdHTCapLen); ++ dst->bssht.bdHTInfoLen= src->bssht.bdHTInfoLen; ++ memcpy(dst->bssht.bdHTInfoBuf,src->bssht.bdHTInfoBuf,src->bssht.bdHTInfoLen); ++ dst->bssht.bdHTSpecVer = src->bssht.bdHTSpecVer; ++ dst->bssht.bdRT2RTLongSlotTime = src->bssht.bdRT2RTLongSlotTime; ++ dst->broadcom_cap_exist = src->broadcom_cap_exist; ++ dst->ralink_cap_exist = src->ralink_cap_exist; ++ dst->atheros_cap_exist = src->atheros_cap_exist; ++ dst->cisco_cap_exist = src->cisco_cap_exist; ++ dst->unknown_cap_exist = src->unknown_cap_exist; ++ memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); ++ dst->wpa_ie_len = src->wpa_ie_len; ++ memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); ++ dst->rsn_ie_len = src->rsn_ie_len; ++ ++ dst->last_scanned = jiffies; ++ /* qos related parameters */ ++ //qos_active = src->qos_data.active; ++ qos_active = dst->qos_data.active; ++ //old_param = dst->qos_data.old_param_count; ++ old_param = dst->qos_data.param_count; ++ if(dst->flags & NETWORK_HAS_QOS_MASK){ ++ //not update QOS paramter in beacon, as most AP will set all these parameter to 0.//WB ++ // printk("====>%s(), aifs:%x, %x\n", __FUNCTION__, dst->qos_data.parameters.aifs[0], src->qos_data.parameters.aifs[0]); ++ // memcpy(&dst->qos_data, &src->qos_data, ++ // sizeof(struct ieee80211_qos_data)); ++ } ++ else { ++ dst->qos_data.supported = src->qos_data.supported; ++ dst->qos_data.param_count = src->qos_data.param_count; ++ } ++ ++ if(dst->qos_data.supported == 1) { ++ dst->QoS_Enable = 1; ++ if(dst->ssid_len) ++ IEEE80211_DEBUG_QOS ++ ("QoS the network %s is QoS supported\n", ++ dst->ssid); ++ else ++ IEEE80211_DEBUG_QOS ++ ("QoS the network is QoS supported\n"); ++ } ++ dst->qos_data.active = qos_active; ++ dst->qos_data.old_param_count = old_param; ++ ++ /* dst->last_associate is not overwritten */ ++#if 1 ++ dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame. ++ if(src->wmm_param[0].ac_aci_acm_aifsn|| \ ++ src->wmm_param[1].ac_aci_acm_aifsn|| \ ++ src->wmm_param[2].ac_aci_acm_aifsn|| \ ++ src->wmm_param[1].ac_aci_acm_aifsn) { ++ memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); ++ } ++ //dst->QoS_Enable = src->QoS_Enable; ++#else ++ dst->QoS_Enable = 1;//for Rtl8187 simulation ++#endif ++#ifdef THOMAS_TURBO ++ dst->Turbo_Enable = src->Turbo_Enable; ++#endif ++ ++#ifdef ENABLE_DOT11D ++ dst->CountryIeLen = src->CountryIeLen; ++ memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); ++#endif ++ ++ //added by amy for LEAP ++ dst->bWithAironetIE = src->bWithAironetIE; ++ dst->bCkipSupported = src->bCkipSupported; ++ memcpy(dst->CcxRmState,src->CcxRmState,2); ++ dst->bCcxRmEnable = src->bCcxRmEnable; ++ dst->MBssidMask = src->MBssidMask; ++ dst->bMBssidValid = src->bMBssidValid; ++ memcpy(dst->MBssid,src->MBssid,6); ++ dst->bWithCcxVerNum = src->bWithCcxVerNum; ++ dst->BssCcxVerNumber = src->BssCcxVerNumber; ++ ++} ++ ++static inline int is_beacon(__le16 fc) ++{ ++ return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON); ++} ++ ++static inline void ieee80211_process_probe_response( ++ struct ieee80211_device *ieee, ++ struct ieee80211_probe_response *beacon, ++ struct ieee80211_rx_stats *stats) ++{ ++ struct ieee80211_network network; ++ struct ieee80211_network *target; ++ struct ieee80211_network *oldest = NULL; ++#ifdef CONFIG_IEEE80211_DEBUG ++ struct ieee80211_info_element *info_element = &beacon->info_element[0]; ++#endif ++ unsigned long flags; ++ short renew; ++ //u8 wmm_info; ++ ++ memset(&network, 0, sizeof(struct ieee80211_network)); ++ IEEE80211_DEBUG_SCAN( ++ "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", ++ escape_essid(info_element->data, info_element->len), ++ MAC_ARG(beacon->header.addr3), ++ (beacon->capability & (1<<0xf)) ? '1' : '0', ++ (beacon->capability & (1<<0xe)) ? '1' : '0', ++ (beacon->capability & (1<<0xd)) ? '1' : '0', ++ (beacon->capability & (1<<0xc)) ? '1' : '0', ++ (beacon->capability & (1<<0xb)) ? '1' : '0', ++ (beacon->capability & (1<<0xa)) ? '1' : '0', ++ (beacon->capability & (1<<0x9)) ? '1' : '0', ++ (beacon->capability & (1<<0x8)) ? '1' : '0', ++ (beacon->capability & (1<<0x7)) ? '1' : '0', ++ (beacon->capability & (1<<0x6)) ? '1' : '0', ++ (beacon->capability & (1<<0x5)) ? '1' : '0', ++ (beacon->capability & (1<<0x4)) ? '1' : '0', ++ (beacon->capability & (1<<0x3)) ? '1' : '0', ++ (beacon->capability & (1<<0x2)) ? '1' : '0', ++ (beacon->capability & (1<<0x1)) ? '1' : '0', ++ (beacon->capability & (1<<0x0)) ? '1' : '0'); ++ ++ if (ieee80211_network_init(ieee, beacon, &network, stats)) { ++ IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(info_element->data, ++ info_element->len), ++ MAC_ARG(beacon->header.addr3), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++ return; ++ } ++ ++#ifdef ENABLE_DOT11D ++ // For Asus EeePc request, ++ // (1) if wireless adapter receive get any 802.11d country code in AP beacon, ++ // wireless adapter should follow the country code. ++ // (2) If there is no any country code in beacon, ++ // then wireless adapter should do active scan from ch1~11 and ++ // passive scan from ch12~14 ++ ++ if( !IsLegalChannel(ieee, network.channel) ) ++ return; ++ if(ieee->bGlobalDomain) ++ { ++ if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) ++ { ++ // Case 1: Country code ++ if(IS_COUNTRY_IE_VALID(ieee) ) ++ { ++ if( !IsLegalChannel(ieee, network.channel) ) ++ { ++ printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ // Case 2: No any country code. ++ else ++ { ++ // Filter over channel ch12~14 ++ if(network.channel > 11) ++ { ++ printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ } ++ else ++ { ++ // Case 1: Country code ++ if(IS_COUNTRY_IE_VALID(ieee) ) ++ { ++ if( !IsLegalChannel(ieee, network.channel) ) ++ { ++ printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel); ++ return; ++ } ++ } ++ // Case 2: No any country code. ++ else ++ { ++ // Filter over channel ch12~14 ++ if(network.channel > 14) ++ { ++ printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel); ++ return; ++ } ++ } ++ } ++ } ++#endif ++ ++ /* The network parsed correctly -- so now we scan our known networks ++ * to see if we can find it in our list. ++ * ++ * NOTE: This search is definitely not optimized. Once its doing ++ * the "right thing" we'll optimize it for efficiency if ++ * necessary */ ++ ++ /* Search for this entry in the list and update it if it is ++ * already there. */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(is_same_network(&ieee->current_network, &network, ieee)) { ++ update_network(&ieee->current_network, &network); ++ if((ieee->current_network.mode == IEEE_N_24G || ieee->current_network.mode == IEEE_G) ++ && ieee->current_network.berp_info_valid){ ++ if(ieee->current_network.erp_value& ERP_UseProtection) ++ ieee->current_network.buseprotection = true; ++ else ++ ieee->current_network.buseprotection = false; ++ } ++ if(is_beacon(beacon->header.frame_ctl)) ++ { ++ if(ieee->state == IEEE80211_LINKED) ++ ieee->LinkDetectInfo.NumRecvBcnInPeriod++; ++ } ++ else //hidden AP ++ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); ++ } ++ ++ list_for_each_entry(target, &ieee->network_list, list) { ++ if (is_same_network(target, &network, ieee)) ++ break; ++ if ((oldest == NULL) || ++ (target->last_scanned < oldest->last_scanned)) ++ oldest = target; ++ } ++ ++ /* If we didn't find a match, then get a new network slot to initialize ++ * with this beacon's information */ ++ if (&target->list == &ieee->network_list) { ++ if (list_empty(&ieee->network_free_list)) { ++ /* If there are no more slots, expire the oldest */ ++ list_del(&oldest->list); ++ target = oldest; ++ IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " ++ "network list.\n", ++ escape_essid(target->ssid, ++ target->ssid_len), ++ MAC_ARG(target->bssid)); ++ } else { ++ /* Otherwise just pull from the free list */ ++ target = list_entry(ieee->network_free_list.next, ++ struct ieee80211_network, list); ++ list_del(ieee->network_free_list.next); ++ } ++ ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(network.ssid, ++ network.ssid_len), ++ MAC_ARG(network.bssid), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++#endif ++ memcpy(target, &network, sizeof(*target)); ++ list_add_tail(&target->list, &ieee->network_list); ++ if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) ++ ieee80211_softmac_new_net(ieee,&network); ++ } else { ++ IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(target->ssid, ++ target->ssid_len), ++ MAC_ARG(target->bssid), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++ ++ /* we have an entry and we are going to update it. But this entry may ++ * be already expired. In this case we do the same as we found a new ++ * net and call the new_net handler ++ */ ++ renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); ++ //YJ,add,080819,for hidden ap ++ if(is_beacon(beacon->header.frame_ctl) == 0) ++ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); ++ //if(strncmp(network.ssid, "linksys-c",9) == 0) ++ // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); ++ if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ ++ && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ ++ ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) ++ renew = 1; ++ //YJ,add,080819,for hidden ap,end ++ ++ update_network(target, &network); ++ if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) ++ ieee80211_softmac_new_net(ieee,&network); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ if (is_beacon(beacon->header.frame_ctl)&&is_same_network(&ieee->current_network, &network, ieee)&&\ ++ (ieee->state == IEEE80211_LINKED)) { ++ if(ieee->handle_beacon != NULL) { ++ ieee->handle_beacon(ieee->dev,beacon,&ieee->current_network); ++ } ++ } ++} ++ ++void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr_4addr *header, ++ struct ieee80211_rx_stats *stats) ++{ ++ if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && ++ ieee->iw_mode == IW_MODE_INFRA && ++ ieee->state == IEEE80211_LINKED)) ++ { ++ tasklet_schedule(&ieee->ps_task); ++ } ++ ++ if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && ++ WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) ++ ieee->last_rx_ps_time = jiffies; ++ ++ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { ++ ++ case IEEE80211_STYPE_BEACON: ++ IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Beacon\n"); ++ ieee80211_process_probe_response( ++ ieee, (struct ieee80211_probe_response *)header, stats); ++ break; ++ ++ case IEEE80211_STYPE_PROBE_RESP: ++ IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Probe response\n"); ++ ieee80211_process_probe_response( ++ ieee, (struct ieee80211_probe_response *)header, stats); ++ break; ++ ++ } ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_rx_mgt); ++//EXPORT_SYMBOL(ieee80211_rx); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_rx_mgt); ++EXPORT_SYMBOL_NOVERS(ieee80211_rx); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c +@@ -0,0 +1,3548 @@ ++/* IEEE 802.11 SoftMAC layer ++ * Copyright (c) 2005 Andrea Merello ++ * ++ * Mostly extracted from the rtl8180-sa2400 driver for the ++ * in-kernel generic ieee802.11 stack. ++ * ++ * Few lines might be stolen from other part of the ieee80211 ++ * stack. Copyright who own it's copyright ++ * ++ * WPA code stolen from the ipw2200 driver. ++ * Copyright who own it's copyright. ++ * ++ * released under the GPL ++ */ ++ ++ ++#include "ieee80211.h" ++ ++#include ++#include ++#include ++#include ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++u8 rsn_authen_cipher_suite[16][4] = { ++ {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved ++ {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default ++ {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default} ++ {0x00,0x0F,0xAC,0x03}, //WRAP-historical ++ {0x00,0x0F,0xAC,0x04}, //CCMP ++ {0x00,0x0F,0xAC,0x05}, //WEP-104 ++}; ++ ++short ieee80211_is_54g(struct ieee80211_network net) ++{ ++ return ((net.rates_ex_len > 0) || (net.rates_len > 4)); ++} ++ ++short ieee80211_is_shortslot(struct ieee80211_network net) ++{ ++ return (net.capability & WLAN_CAPABILITY_SHORT_SLOT); ++} ++ ++/* returns the total length needed for pleacing the RATE MFIE ++ * tag and the EXTENDED RATE MFIE tag if needed. ++ * It encludes two bytes per tag for the tag itself and its len ++ */ ++unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) ++{ ++ unsigned int rate_len = 0; ++ ++ if (ieee->modulation & IEEE80211_CCK_MODULATION) ++ rate_len = IEEE80211_CCK_RATE_LEN + 2; ++ ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION) ++ ++ rate_len += IEEE80211_OFDM_RATE_LEN + 2; ++ ++ return rate_len; ++} ++ ++/* pleace the MFIE rate, tag to the memory (double) poined. ++ * Then it updates the pointer so that ++ * it points after the new MFIE tag added. ++ */ ++void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p) ++{ ++ u8 *tag = *tag_p; ++ ++ if (ieee->modulation & IEEE80211_CCK_MODULATION){ ++ *tag++ = MFIE_TYPE_RATES; ++ *tag++ = 4; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; ++ } ++ ++ /* We may add an option for custom rates that specific HW might support */ ++ *tag_p = tag; ++} ++ ++void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p) ++{ ++ u8 *tag = *tag_p; ++ ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ++ *tag++ = MFIE_TYPE_RATES_EX; ++ *tag++ = 8; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; ++ ++ } ++ ++ /* We may add an option for custom rates that specific HW might support */ ++ *tag_p = tag; ++} ++ ++ ++void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) { ++ u8 *tag = *tag_p; ++ ++ *tag++ = MFIE_TYPE_GENERIC; //0 ++ *tag++ = 7; ++ *tag++ = 0x00; ++ *tag++ = 0x50; ++ *tag++ = 0xf2; ++ *tag++ = 0x02;//5 ++ *tag++ = 0x00; ++ *tag++ = 0x01; ++#ifdef SUPPORT_USPD ++ if(ieee->current_network.wmm_info & 0x80) { ++ *tag++ = 0x0f|MAX_SP_Len; ++ } else { ++ *tag++ = MAX_SP_Len; ++ } ++#else ++ *tag++ = MAX_SP_Len; ++#endif ++ *tag_p = tag; ++} ++ ++#ifdef THOMAS_TURBO ++void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) { ++ u8 *tag = *tag_p; ++ ++ *tag++ = MFIE_TYPE_GENERIC; //0 ++ *tag++ = 7; ++ *tag++ = 0x00; ++ *tag++ = 0xe0; ++ *tag++ = 0x4c; ++ *tag++ = 0x01;//5 ++ *tag++ = 0x02; ++ *tag++ = 0x11; ++ *tag++ = 0x00; ++ ++ *tag_p = tag; ++ printk(KERN_ALERT "This is enable turbo mode IE process\n"); ++} ++#endif ++ ++void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ int nh; ++ nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM; ++ ++/* ++ * if the queue is full but we have newer frames then ++ * just overwrites the oldest. ++ * ++ * if (nh == ieee->mgmt_queue_tail) ++ * return -1; ++ */ ++ ieee->mgmt_queue_head = nh; ++ ieee->mgmt_queue_ring[nh] = skb; ++ ++ //return 0; ++} ++ ++struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *ret; ++ ++ if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head) ++ return NULL; ++ ++ ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; ++ ++ ieee->mgmt_queue_tail = ++ (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; ++ ++ return ret; ++} ++ ++void init_mgmt_queue(struct ieee80211_device *ieee) ++{ ++ ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; ++} ++ ++u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ u8 rate; ++ ++ // 2008/01/25 MH For broadcom, MGNT frame set as OFDM 6M. ++ if(pHTInfo->IOTAction & HT_IOT_ACT_MGNT_USE_CCK_6M) ++ rate = 0x0c; ++ else ++ rate = ieee->basic_rate & 0x7f; ++ ++ if(rate == 0){ ++ // 2005.01.26, by rcnjko. ++ if(ieee->mode == IEEE_A|| ++ ieee->mode== IEEE_N_5G|| ++ (ieee->mode== IEEE_N_24G&&!pHTInfo->bCurSuppCCK)) ++ rate = 0x0c; ++ else ++ rate = 0x02; ++ } ++ ++ /* ++ // Data rate of ProbeReq is already decided. Annie, 2005-03-31 ++ if( pMgntInfo->bScanInProgress || (pMgntInfo->bDualModeScanStep!=0) ) ++ { ++ if(pMgntInfo->dot11CurrentWirelessMode==WIRELESS_MODE_A) ++ rate = 0x0c; ++ else ++ rate = 0x02; ++ } ++ */ ++ return rate; ++} ++ ++ ++void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); ++ ++inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; ++ struct ieee80211_hdr_3addr *header= ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8); ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ /* called with 2nd param 0, no mgmt lock required */ ++ ieee80211_sta_wakeup(ieee,0); ++ ++ tcb_desc->queue_index = MGNT_QUEUE; ++ tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); ++ tcb_desc->RATRIndex = 7; ++ tcb_desc->bTxDisableRateFallBack = 1; ++ tcb_desc->bTxUseDriverAssingedRate = 1; ++ ++ if(single){ ++ if(ieee->queue_stop){ ++ enqueue_mgmt(ieee,skb); ++ }else{ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ // ieee->dev->trans_start = jiffies; ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ }else{ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* check wether the managed packet queued greater than 5 */ ++ if(!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\ ++ (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\ ++ (ieee->queue_stop) ) { ++ /* insert the skb packet to the management queue */ ++ /* as for the completion function, it does not need ++ * to check it any more. ++ * */ ++ printk("%s():insert to waitqueue!\n",__FUNCTION__); ++ skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index], skb); ++ } else { ++ //printk("TX packet!\n"); ++ ieee->softmac_hard_start_xmit(skb,ieee->dev); ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); ++ } ++} ++ ++inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) ++{ ++ ++ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; ++ struct ieee80211_hdr_3addr *header = ++ (struct ieee80211_hdr_3addr *) skb->data; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8); ++ ++ tcb_desc->queue_index = MGNT_QUEUE; ++ tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); ++ tcb_desc->RATRIndex = 7; ++ tcb_desc->bTxDisableRateFallBack = 1; ++ tcb_desc->bTxUseDriverAssingedRate = 1; ++ //printk("=============>%s()\n", __FUNCTION__); ++ if(single){ ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ // ieee->dev->trans_start = jiffies; ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ ++ }else{ ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ ieee->softmac_hard_start_xmit(skb,ieee->dev); ++ ++ } ++ //dev_kfree_skb_any(skb);//edit by thomas ++} ++ ++inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) ++{ ++ unsigned int len,rate_len; ++ u8 *tag; ++ struct sk_buff *skb; ++ struct ieee80211_probe_request *req; ++ ++ len = ieee->current_network.ssid_len; ++ ++ rate_len = ieee80211_MFIE_rate_len(ieee); ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len + ieee->tx_headroom); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, ieee->tx_headroom); ++ ++ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); ++ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); ++ req->header.duration_id = 0; //FIXME: is this OK ? ++ ++ memset(req->header.addr1, 0xff, ETH_ALEN); ++ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memset(req->header.addr3, 0xff, ETH_ALEN); ++ ++ tag = (u8 *) skb_put(skb,len+2+rate_len); ++ ++ *tag++ = MFIE_TYPE_SSID; ++ *tag++ = len; ++ memcpy(tag, ieee->current_network.ssid, len); ++ tag += len; ++ ++ ieee80211_MFIE_Brate(ieee,&tag); ++ ieee80211_MFIE_Grate(ieee,&tag); ++ return skb; ++} ++ ++struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); ++void ieee80211_send_beacon(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ if(!ieee->ieee_up) ++ return; ++ //unsigned long flags; ++ skb = ieee80211_get_beacon_(ieee); ++ ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_beacons++; ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++// ieee->beacon_timer.expires = jiffies + ++// (MSECS( ieee->current_network.beacon_interval -5)); ++ ++ //spin_lock_irqsave(&ieee->beacon_lock,flags); ++ if(ieee->beacon_txing && ieee->ieee_up){ ++// if(!timer_pending(&ieee->beacon_timer)) ++// add_timer(&ieee->beacon_timer); ++ mod_timer(&ieee->beacon_timer,jiffies+(MSECS(ieee->current_network.beacon_interval-5))); ++ } ++ //spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++ ++void ieee80211_send_beacon_cb(unsigned long _ieee) ++{ ++ struct ieee80211_device *ieee = ++ (struct ieee80211_device *) _ieee; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock, flags); ++ ieee80211_send_beacon(ieee); ++ spin_unlock_irqrestore(&ieee->beacon_lock, flags); ++} ++ ++ ++void ieee80211_send_probe(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ ++ skb = ieee80211_probe_req(ieee); ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_probe_rq++; ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++void ieee80211_send_probe_requests(struct ieee80211_device *ieee) ++{ ++ if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){ ++ ieee80211_send_probe(ieee); ++ ieee80211_send_probe(ieee); ++ } ++} ++ ++/* this performs syncro scan blocking the caller until all channels ++ * in the allowed channel map has been checked. ++ */ ++void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) ++{ ++ short ch = 0; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++ down(&ieee->scan_sem); ++ ++ while(1) ++ { ++ ++ do{ ++ ch++; ++ if (ch > MAX_CHANNEL_NUMBER) ++ goto out; /* scan completed */ ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ch]); ++#else ++ }while(!ieee->channel_map[ch]); ++#endif ++ ++ /* this fuction can be called in two situations ++ * 1- We have switched to ad-hoc mode and we are ++ * performing a complete syncro scan before conclude ++ * there are no interesting cell and to create a ++ * new one. In this case the link state is ++ * IEEE80211_NOLINK until we found an interesting cell. ++ * If so the ieee8021_new_net, called by the RX path ++ * will set the state to IEEE80211_LINKED, so we stop ++ * scanning ++ * 2- We are linked and the root uses run iwlist scan. ++ * So we switch to IEEE80211_LINKED_SCANNING to remember ++ * that we are still logically linked (not interested in ++ * new network events, despite for updating the net list, ++ * but we are temporarly 'unlinked' as the driver shall ++ * not filter RX frames and the channel is changing. ++ * So the only situation in witch are interested is to check ++ * if the state become LINKED because of the #1 situation ++ */ ++ ++ if (ieee->state == IEEE80211_LINKED) ++ goto out; ++ ieee->set_chan(ieee->dev, ch); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ch] == 1) ++#endif ++ ieee80211_send_probe_requests(ieee); ++ ++ /* this prevent excessive time wait when we ++ * need to wait for a syncro scan to end.. ++ */ ++ if(ieee->state < IEEE80211_LINKED) ++ ; ++ else ++ if (ieee->sync_scan_hurryup) ++ goto out; ++ ++ ++ msleep_interruptible_rsl(IEEE80211_SOFTMAC_SCAN_TIME); ++ ++ } ++out: ++ if(ieee->state < IEEE80211_LINKED){ ++ ieee->actscanning = false; ++ up(&ieee->scan_sem); ++ } ++ else{ ++ ieee->sync_scan_hurryup = 0; ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++ up(&ieee->scan_sem); ++} ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++/* called both by wq with ieee->lock held */ ++void ieee80211_softmac_scan(struct ieee80211_device *ieee) ++{ ++#if 0 ++ short watchdog = 0; ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (watchdog++ > MAX_CHANNEL_NUMBER) ++ return; /* no good chans */ ++ ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ ++ schedule_task(&ieee->softmac_scan_wq); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_softmac_scan_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); ++#else ++void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ static short watchdog = 0; ++ u8 last_channel = ieee->current_network.channel; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++ if(!ieee->ieee_up) ++ return; ++ down(&ieee->scan_sem); ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (watchdog++ > MAX_CHANNEL_NUMBER) ++ { ++ //if current channel is not in channel map, set to default channel. ++ #ifdef ENABLE_DOT11D ++ if (!channel_map[ieee->current_network.channel]); ++ #else ++ if (!ieee->channel_map[ieee->current_network.channel]); ++ #endif ++ ieee->current_network.channel = 6; ++ goto out; /* no good chans */ ++ } ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ieee->current_network.channel]); ++#else ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ if (ieee->scanning == 0 ) ++ goto out; ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ieee->current_network.channel] == 1) ++#endif ++ ieee80211_send_probe_requests(ieee); ++ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); ++#else ++ //ieee->scan_timer.expires = jiffies + MSECS(IEEE80211_SOFTMAC_SCAN_TIME); ++ if (ieee->scanning == 1) ++ mod_timer(&ieee->scan_timer,(jiffies + MSECS(IEEE80211_SOFTMAC_SCAN_TIME))); ++#endif ++ ++ up(&ieee->scan_sem); ++ return; ++out: ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++ ieee->current_network.channel = last_channel; ++ ieee->actscanning = false; ++ watchdog = 0; ++ ieee->scanning = 0; ++ up(&ieee->scan_sem); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++void ieee80211_softmac_scan_cb(unsigned long _dev) ++{ ++ unsigned long flags; ++ struct ieee80211_device *ieee = (struct ieee80211_device *)_dev; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ieee80211_softmac_scan(ieee); ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++#endif ++ ++ ++void ieee80211_beacons_start(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&ieee->beacon_lock,flags); ++ ++ ieee->beacon_txing = 1; ++ ieee80211_send_beacon(ieee); ++ ++ spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++void ieee80211_beacons_stop(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock,flags); ++ ++ ieee->beacon_txing = 0; ++ del_timer_sync(&ieee->beacon_timer); ++ ++ spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++ ++} ++ ++ ++void ieee80211_stop_send_beacons(struct ieee80211_device *ieee) ++{ ++ if(ieee->stop_send_beacons) ++ ieee->stop_send_beacons(ieee->dev); ++ if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) ++ ieee80211_beacons_stop(ieee); ++} ++ ++ ++void ieee80211_start_send_beacons(struct ieee80211_device *ieee) ++{ ++ if(ieee->start_send_beacons) ++ ieee->start_send_beacons(ieee->dev,ieee->basic_rate); ++ if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS) ++ ieee80211_beacons_start(ieee); ++} ++ ++ ++void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) ++{ ++// unsigned long flags; ++ ++ //ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->scan_sem); ++// spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->scanning == 1){ ++ ieee->scanning = 0; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->softmac_scan_wq); ++#else ++ del_timer_sync(&ieee->scan_timer); ++#endif ++ } ++ ++// spin_unlock_irqrestore(&ieee->lock, flags); ++ up(&ieee->scan_sem); ++} ++ ++void ieee80211_stop_scan(struct ieee80211_device *ieee) ++{ ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ++ ieee80211_softmac_stop_scan(ieee); ++ else ++ ieee->stop_scan(ieee->dev); ++} ++ ++/* called with ieee->lock held */ ++void ieee80211_start_scan(struct ieee80211_device *ieee) ++{ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee) ) ++ { ++ if(IS_COUNTRY_IE_VALID(ieee)) ++ { ++ RESET_CIE_WATCHDOG(ieee); ++ } ++ } ++#endif ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ ++ if (ieee->scanning == 0){ ++ ieee->scanning = 1; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, 0); ++#else ++ ++ queue_work(ieee->wq, &ieee->softmac_scan_wq); ++#endif ++#else ++ ieee80211_softmac_scan(ieee); ++#endif ++ } ++ }else ++ ieee->start_scan(ieee->dev); ++ ++} ++ ++/* called with wx_sem held */ ++void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) ++{ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee) ) ++ { ++ if(IS_COUNTRY_IE_VALID(ieee)) ++ { ++ RESET_CIE_WATCHDOG(ieee); ++ } ++ } ++#endif ++ ieee->sync_scan_hurryup = 0; ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ++ ieee80211_softmac_scan_syncro(ieee); ++ else ++ ieee->scan_syncro(ieee->dev); ++ ++} ++ ++inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon, ++ struct ieee80211_device *ieee, int challengelen) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_authentication *auth; ++ int len = sizeof(struct ieee80211_authentication) + challengelen + ieee->tx_headroom; ++ ++ ++ skb = dev_alloc_skb(len); ++ if (!skb) return NULL; ++ ++ skb_reserve(skb, ieee->tx_headroom); ++ auth = (struct ieee80211_authentication *) ++ skb_put(skb, sizeof(struct ieee80211_authentication)); ++ ++ auth->header.frame_ctl = IEEE80211_STYPE_AUTH; ++ if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP; ++ ++ auth->header.duration_id = 0x013a; //FIXME ++ ++ memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); ++ ++ //auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ if(ieee->auth_mode == 0) ++ auth->algorithm = WLAN_AUTH_OPEN; ++ else if(ieee->auth_mode == 1) ++ auth->algorithm = WLAN_AUTH_SHARED_KEY; ++ else if(ieee->auth_mode == 2) ++ auth->algorithm = WLAN_AUTH_OPEN;//0x80; ++ printk("=================>%s():auth->algorithm is %d\n",__FUNCTION__,auth->algorithm); ++ auth->transaction = cpu_to_le16(ieee->associate_seq); ++ ieee->associate_seq++; ++ ++ auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); ++ ++ return skb; ++ ++} ++ ++ ++static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest) ++{ ++ u8 *tag; ++ int beacon_size; ++ struct ieee80211_probe_response *beacon_buf; ++ struct sk_buff *skb = NULL; ++ int encrypt; ++ int atim_len,erp_len; ++ struct ieee80211_crypt_data* crypt; ++ ++ char *ssid = ieee->current_network.ssid; ++ int ssid_len = ieee->current_network.ssid_len; ++ int rate_len = ieee->current_network.rates_len+2; ++ int rate_ex_len = ieee->current_network.rates_ex_len; ++ int wpa_ie_len = ieee->wpa_ie_len; ++ u8 erpinfo_content = 0; ++ ++ u8* tmp_ht_cap_buf; ++ u8 tmp_ht_cap_len=0; ++ u8* tmp_ht_info_buf; ++ u8 tmp_ht_info_len=0; ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ u8* tmp_generic_ie_buf=NULL; ++ u8 tmp_generic_ie_len=0; ++ ++ if(rate_ex_len > 0) rate_ex_len+=2; ++ ++ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) ++ atim_len = 4; ++ else ++ atim_len = 0; ++ ++#if 1 ++ if(ieee80211_is_54g(ieee->current_network)) ++ erp_len = 3; ++ else ++ erp_len = 0; ++#else ++ if((ieee->current_network.mode == IEEE_G) ++ ||( ieee->current_network.mode == IEEE_N_24G && ieee->pHTInfo->bCurSuppCCK)) { ++ erp_len = 3; ++ erpinfo_content = 0; ++ if(ieee->current_network.buseprotection) ++ erpinfo_content |= ERP_UseProtection; ++ } ++ else ++ erp_len = 0; ++#endif ++ ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ ++ ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ++ ((0 == strcmp(crypt->ops->name, "WEP") || wpa_ie_len)); ++ //HT ralated element ++#if 1 ++ tmp_ht_cap_buf =(u8*) &(ieee->pHTInfo->SelfHTCap); ++ tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); ++ tmp_ht_info_buf =(u8*) &(ieee->pHTInfo->SelfHTInfo); ++ tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo); ++ HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, &tmp_ht_cap_len,encrypt); ++ HTConstructInfoElement(ieee,tmp_ht_info_buf,&tmp_ht_info_len, encrypt); ++ ++ ++ if(pHTInfo->bRegRT2RTAggregation) ++ { ++ tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; ++ tmp_generic_ie_len = sizeof(ieee->pHTInfo->szRT2RTAggBuffer); ++ HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, &tmp_generic_ie_len); ++ } ++// printk("===============>tmp_ht_cap_len is %d,tmp_ht_info_len is %d, tmp_generic_ie_len is %d\n",tmp_ht_cap_len,tmp_ht_info_len,tmp_generic_ie_len); ++#endif ++ beacon_size = sizeof(struct ieee80211_probe_response)+2+ ++ ssid_len ++ +3 //channel ++ +rate_len ++ +rate_ex_len ++ +atim_len ++ +erp_len ++ +wpa_ie_len ++ // +tmp_ht_cap_len ++ // +tmp_ht_info_len ++ // +tmp_generic_ie_len ++// +wmm_len+2 ++ +ieee->tx_headroom; ++ skb = dev_alloc_skb(beacon_size); ++ if (!skb) ++ return NULL; ++ skb_reserve(skb, ieee->tx_headroom); ++ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, (beacon_size - ieee->tx_headroom)); ++ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); ++ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ beacon_buf->header.duration_id = 0; //FIXME ++ beacon_buf->beacon_interval = ++ cpu_to_le16(ieee->current_network.beacon_interval); ++ beacon_buf->capability = ++ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); ++ beacon_buf->capability |= ++ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE); //add short preamble here ++ ++ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++#if 0 ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ++ (0 == strcmp(crypt->ops->name, "WEP")); ++#endif ++ if (encrypt) ++ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ ++ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); ++ beacon_buf->info_element[0].id = MFIE_TYPE_SSID; ++ beacon_buf->info_element[0].len = ssid_len; ++ ++ tag = (u8*) beacon_buf->info_element[0].data; ++ ++ memcpy(tag, ssid, ssid_len); ++ ++ tag += ssid_len; ++ ++ *(tag++) = MFIE_TYPE_RATES; ++ *(tag++) = rate_len-2; ++ memcpy(tag,ieee->current_network.rates,rate_len-2); ++ tag+=rate_len-2; ++ ++ *(tag++) = MFIE_TYPE_DS_SET; ++ *(tag++) = 1; ++ *(tag++) = ieee->current_network.channel; ++ ++ if(atim_len){ ++ u16 val16; ++ *(tag++) = MFIE_TYPE_IBSS_SET; ++ *(tag++) = 2; ++ //*((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); ++ val16 = cpu_to_le16(ieee->current_network.atim_window); ++ memcpy((u8 *)tag, (u8 *)&val16, 2); ++ tag+=2; ++ } ++ ++ if(erp_len){ ++ *(tag++) = MFIE_TYPE_ERP; ++ *(tag++) = 1; ++ *(tag++) = erpinfo_content; ++ } ++#if 0 ++ //Include High Throuput capability ++ ++ *(tag++) = MFIE_TYPE_HT_CAP; ++ *(tag++) = tmp_ht_cap_len - 2; ++ memcpy(tag, tmp_ht_cap_buf, tmp_ht_cap_len - 2); ++ tag += tmp_ht_cap_len - 2; ++#endif ++ if(rate_ex_len){ ++ *(tag++) = MFIE_TYPE_RATES_EX; ++ *(tag++) = rate_ex_len-2; ++ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); ++ tag+=rate_ex_len-2; ++ } ++ ++#if 0 ++ //Include High Throuput info ++ ++ *(tag++) = MFIE_TYPE_HT_INFO; ++ *(tag++) = tmp_ht_info_len - 2; ++ memcpy(tag, tmp_ht_info_buf, tmp_ht_info_len -2); ++ tag += tmp_ht_info_len - 2; ++#endif ++ if (wpa_ie_len) ++ { ++ if (ieee->iw_mode == IW_MODE_ADHOC) ++ {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07 ++ memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); ++ } ++ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); ++ tag += wpa_ie_len; ++ } ++ ++#if 0 ++ // ++ // Construct Realtek Proprietary Aggregation mode (Set AMPDU Factor to 2, 32k) ++ // ++ if(pHTInfo->bRegRT2RTAggregation) ++ { ++ (*tag++) = 0xdd; ++ (*tag++) = tmp_generic_ie_len - 2; ++ memcpy(tag,tmp_generic_ie_buf,tmp_generic_ie_len -2); ++ tag += tmp_generic_ie_len -2; ++ ++ } ++#endif ++#if 0 ++ if(ieee->qos_support) ++ { ++ (*tag++) = 0xdd; ++ (*tag++) = wmm_len; ++ memcpy(tag,QosOui,wmm_len); ++ tag += wmm_len; ++ } ++#endif ++ //skb->dev = ieee->dev; ++ return skb; ++} ++ ++ ++struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) ++{ ++ struct sk_buff *skb; ++ u8* tag; ++ ++ struct ieee80211_crypt_data* crypt; ++ struct ieee80211_assoc_response_frame *assoc; ++ short encrypt; ++ ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len + ieee->tx_headroom; ++ ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, ieee->tx_headroom); ++ ++ assoc = (struct ieee80211_assoc_response_frame *) ++ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); ++ ++ assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); ++ memcpy(assoc->header.addr1, dest,ETH_ALEN); ++ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? ++ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); ++ ++ ++ if(ieee->short_slot) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++ if (ieee->host_encrypt) ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ else crypt = NULL; ++ ++ encrypt = ( crypt && crypt->ops); ++ ++ if (encrypt) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ assoc->status = 0; ++ assoc->aid = cpu_to_le16(ieee->assoc_id); ++ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; ++ else ieee->assoc_id++; ++ ++ tag = (u8*) skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ return skb; ++} ++ ++struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_authentication *auth; ++ int len = ieee->tx_headroom + sizeof(struct ieee80211_authentication)+1; ++ ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ skb->len = sizeof(struct ieee80211_authentication); ++ ++ auth = (struct ieee80211_authentication *)skb->data; ++ ++ auth->status = cpu_to_le16(status); ++ auth->transaction = cpu_to_le16(2); ++ auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); ++ ++ memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr1, dest, ETH_ALEN); ++ auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); ++ return skb; ++ ++ ++} ++ ++struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr* hdr; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr)); ++ ++ if (!skb) ++ return NULL; ++ ++ hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr)); ++ ++ memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); ++ memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | ++ IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | ++ (pwr ? IEEE80211_FCTL_PM:0)); ++ ++ return skb; ++ ++ ++} ++ ++ ++void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest) ++{ ++ struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest); ++ ++ if (buf) ++ softmac_mgmt_xmit(buf, ieee); ++} ++ ++ ++void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest) ++{ ++ struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest); ++ ++ if (buf) ++ softmac_mgmt_xmit(buf, ieee); ++} ++ ++ ++void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest) ++{ ++ ++ ++ struct sk_buff *buf = ieee80211_probe_resp(ieee, dest); ++ if (buf) ++ softmac_mgmt_xmit(buf, ieee); ++} ++ ++ ++inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ //unsigned long flags; ++ ++ struct ieee80211_assoc_request_frame *hdr; ++ u8 *tag;//,*rsn_ie; ++ //short info_addr = 0; ++ //int i; ++ //u16 suite_count = 0; ++ //u8 suit_select = 0; ++ //unsigned int wpa_len = beacon->wpa_ie_len; ++ //for HT ++ u8* ht_cap_buf = NULL; ++ u8 ht_cap_len=0; ++ u8* realtek_ie_buf=NULL; ++ u8 realtek_ie_len=0; ++ int wpa_ie_len= ieee->wpa_ie_len; ++ unsigned int ckip_ie_len=0; ++ unsigned int ccxrm_ie_len=0; ++ unsigned int cxvernum_ie_len=0; ++ struct ieee80211_crypt_data* crypt; ++ int encrypt; ++ ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ unsigned int wmm_info_len = beacon->qos_data.supported?9:0; ++#ifdef THOMAS_TURBO ++ unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; ++#endif ++ ++ int len = 0; ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ((0 == strcmp(crypt->ops->name,"WEP") || wpa_ie_len)); ++ ++ //Include High Throuput capability && Realtek proprietary ++ if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT) ++ { ++ ht_cap_buf = (u8*)&(ieee->pHTInfo->SelfHTCap); ++ ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); ++ HTConstructCapabilityElement(ieee, ht_cap_buf, &ht_cap_len, encrypt); ++ if(ieee->pHTInfo->bCurrentRT2RTAggregation) ++ { ++ realtek_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; ++ realtek_ie_len = sizeof( ieee->pHTInfo->szRT2RTAggBuffer); ++ HTConstructRT2RTAggElement(ieee, realtek_ie_buf, &realtek_ie_len); ++ ++ } ++ } ++ if(ieee->qos_support){ ++ wmm_info_len = beacon->qos_data.supported?9:0; ++ } ++ ++ ++ if(beacon->bCkipSupported) ++ { ++ ckip_ie_len = 30+2; ++ } ++ if(beacon->bCcxRmEnable) ++ { ++ ccxrm_ie_len = 6+2; ++ } ++ if( beacon->BssCcxVerNumber >= 2 ) ++ { ++ cxvernum_ie_len = 5+2; ++ } ++#ifdef THOMAS_TURBO ++ len = sizeof(struct ieee80211_assoc_request_frame)+ 2 ++ + beacon->ssid_len//essid tagged val ++ + rate_len//rates tagged val ++ + wpa_ie_len ++ + wmm_info_len ++ + turbo_info_len ++ + ht_cap_len ++ + realtek_ie_len ++ + ckip_ie_len ++ + ccxrm_ie_len ++ + cxvernum_ie_len ++ + ieee->tx_headroom; ++#else ++ len = sizeof(struct ieee80211_assoc_request_frame)+ 2 ++ + beacon->ssid_len//essid tagged val ++ + rate_len//rates tagged val ++ + wpa_ie_len ++ + wmm_info_len ++ + ht_cap_len ++ + realtek_ie_len ++ + ckip_ie_len ++ + ccxrm_ie_len ++ + cxvernum_ie_len ++ + ieee->tx_headroom; ++#endif ++ ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, ieee->tx_headroom); ++ ++ hdr = (struct ieee80211_assoc_request_frame *) ++ skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2); ++ ++ ++ hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; ++ hdr->header.duration_id= 37; //FIXME ++ memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); ++ ++ memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John ++ ++ hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS); ++ if (beacon->capability & WLAN_CAPABILITY_PRIVACY ) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); //add short_preamble here ++ ++ if(ieee->short_slot) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ if (wmm_info_len) //QOS ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_QOS); ++ ++ hdr->listen_interval = 0xa; //FIXME ++ ++ hdr->info_element[0].id = MFIE_TYPE_SSID; ++ ++ hdr->info_element[0].len = beacon->ssid_len; ++ tag = skb_put(skb, beacon->ssid_len); ++ memcpy(tag, beacon->ssid, beacon->ssid_len); ++ ++ tag = skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ // For CCX 1 S13, CKIP. Added by Annie, 2006-08-14. ++ if( beacon->bCkipSupported ) ++ { ++ static u8 AironetIeOui[] = {0x00, 0x01, 0x66}; // "4500-client" ++ u8 CcxAironetBuf[30]; ++ OCTET_STRING osCcxAironetIE; ++ ++ memset(CcxAironetBuf, 0,30); ++ osCcxAironetIE.Octet = CcxAironetBuf; ++ osCcxAironetIE.Length = sizeof(CcxAironetBuf); ++ // ++ // Ref. CCX test plan v3.61, 3.2.3.1 step 13. ++ // We want to make the device type as "4500-client". 060926, by CCW. ++ // ++ memcpy(osCcxAironetIE.Octet, AironetIeOui, sizeof(AironetIeOui)); ++ ++ // CCX1 spec V1.13, A01.1 CKIP Negotiation (page23): ++ // "The CKIP negotiation is started with the associate request from the client to the access point, ++ // containing an Aironet element with both the MIC and KP bits set." ++ osCcxAironetIE.Octet[IE_CISCO_FLAG_POSITION] |= (SUPPORT_CKIP_PK|SUPPORT_CKIP_MIC) ; ++ tag = skb_put(skb, ckip_ie_len); ++ *tag++ = MFIE_TYPE_AIRONET; ++ *tag++ = osCcxAironetIE.Length; ++ memcpy(tag,osCcxAironetIE.Octet,osCcxAironetIE.Length); ++ tag += osCcxAironetIE.Length; ++ } ++ ++ if(beacon->bCcxRmEnable) ++ { ++ static u8 CcxRmCapBuf[] = {0x00, 0x40, 0x96, 0x01, 0x01, 0x00}; ++ OCTET_STRING osCcxRmCap; ++ ++ osCcxRmCap.Octet = CcxRmCapBuf; ++ osCcxRmCap.Length = sizeof(CcxRmCapBuf); ++ tag = skb_put(skb,ccxrm_ie_len); ++ *tag++ = MFIE_TYPE_GENERIC; ++ *tag++ = osCcxRmCap.Length; ++ memcpy(tag,osCcxRmCap.Octet,osCcxRmCap.Length); ++ tag += osCcxRmCap.Length; ++ } ++ ++ if( beacon->BssCcxVerNumber >= 2 ) ++ { ++ u8 CcxVerNumBuf[] = {0x00, 0x40, 0x96, 0x03, 0x00}; ++ OCTET_STRING osCcxVerNum; ++ CcxVerNumBuf[4] = beacon->BssCcxVerNumber; ++ osCcxVerNum.Octet = CcxVerNumBuf; ++ osCcxVerNum.Length = sizeof(CcxVerNumBuf); ++ tag = skb_put(skb,cxvernum_ie_len); ++ *tag++ = MFIE_TYPE_GENERIC; ++ *tag++ = osCcxVerNum.Length; ++ memcpy(tag,osCcxVerNum.Octet,osCcxVerNum.Length); ++ tag += osCcxVerNum.Length; ++ } ++ //HT cap element ++ if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){ ++ if(ieee->pHTInfo->ePeerHTSpecVer != HT_SPEC_VER_EWC) ++ { ++ tag = skb_put(skb, ht_cap_len); ++ *tag++ = MFIE_TYPE_HT_CAP; ++ *tag++ = ht_cap_len - 2; ++ memcpy(tag, ht_cap_buf,ht_cap_len -2); ++ tag += ht_cap_len -2; ++ } ++ } ++ ++ ++ //choose what wpa_supplicant gives to associate. ++ tag = skb_put(skb, wpa_ie_len); ++ if (wpa_ie_len){ ++ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); ++ } ++ ++ tag = skb_put(skb,wmm_info_len); ++ if(wmm_info_len) { ++ ieee80211_WMM_Info(ieee, &tag); ++ } ++#ifdef THOMAS_TURBO ++ tag = skb_put(skb,turbo_info_len); ++ if(turbo_info_len) { ++ ieee80211_TURBO_Info(ieee, &tag); ++ } ++#endif ++ ++ if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){ ++ if(ieee->pHTInfo->ePeerHTSpecVer == HT_SPEC_VER_EWC) ++ { ++ tag = skb_put(skb, ht_cap_len); ++ *tag++ = MFIE_TYPE_GENERIC; ++ *tag++ = ht_cap_len - 2; ++ memcpy(tag, ht_cap_buf,ht_cap_len - 2); ++ tag += ht_cap_len -2; ++ } ++ ++ if(ieee->pHTInfo->bCurrentRT2RTAggregation){ ++ tag = skb_put(skb, realtek_ie_len); ++ *tag++ = MFIE_TYPE_GENERIC; ++ *tag++ = realtek_ie_len - 2; ++ memcpy(tag, realtek_ie_buf,realtek_ie_len -2 ); ++ } ++ } ++// printk("<=====%s(), %p, %p\n", __FUNCTION__, ieee->dev, ieee->dev->dev_addr); ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); ++ return skb; ++} ++ ++void ieee80211_associate_abort(struct ieee80211_device *ieee) ++{ ++ ++ unsigned long flags; ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ ieee->associate_seq++; ++ ++ /* don't scan, and avoid to have the RX path possibily ++ * try again to associate. Even do not react to AUTH or ++ * ASSOC response. Just wait for the retry wq to be scheduled. ++ * Here we will check if there are good nets to associate ++ * with, so we retry or just get back to NO_LINK and scanning ++ */ ++ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){ ++ IEEE80211_DEBUG_MGMT("Authentication failed\n"); ++ ieee->softmac_stats.no_auth_rs++; ++ }else{ ++ IEEE80211_DEBUG_MGMT("Association failed\n"); ++ ieee->softmac_stats.no_ass_rs++; ++ } ++ ++ ieee->state = IEEE80211_ASSOCIATING_RETRY; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, \ ++ IEEE80211_SOFTMAC_ASSOC_RETRY_TIME); ++#else ++ schedule_task(&ieee->associate_retry_wq); ++#endif ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++void ieee80211_associate_abort_cb(unsigned long dev) ++{ ++ ieee80211_associate_abort((struct ieee80211_device *) dev); ++} ++ ++ ++void ieee80211_associate_step1(struct ieee80211_device *ieee) ++{ ++ struct ieee80211_network *beacon = &ieee->current_network; ++ struct sk_buff *skb; ++ ++ IEEE80211_DEBUG_MGMT("Stopping scan\n"); ++ ++ ieee->softmac_stats.tx_auth_rq++; ++ skb=ieee80211_authentication_req(beacon, ieee, 0); ++ ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ; ++ IEEE80211_DEBUG_MGMT("Sending authentication request\n"); ++ //printk(KERN_WARNING "Sending authentication request\n"); ++ softmac_mgmt_xmit(skb, ieee); ++ //BUGON when you try to add_timer twice, using mod_timer may be better, john0709 ++ if(!timer_pending(&ieee->associate_timer)){ ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) ++{ ++ u8 *c; ++ struct sk_buff *skb; ++ struct ieee80211_network *beacon = &ieee->current_network; ++// int hlen = sizeof(struct ieee80211_authentication); ++ ++ ieee->associate_seq++; ++ ieee->softmac_stats.tx_auth_rq++; ++ ++ skb = ieee80211_authentication_req(beacon, ieee, chlen+2); ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ c = skb_put(skb, chlen+2); ++ *(c++) = MFIE_TYPE_CHALLENGE; ++ *(c++) = chlen; ++ memcpy(c, challenge, chlen); ++ ++ IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n"); ++ ++ ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr )); ++ ++ softmac_mgmt_xmit(skb, ieee); ++ mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); ++#if 0 ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++#endif ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++ kfree(challenge); ++} ++ ++void ieee80211_associate_step2(struct ieee80211_device *ieee) ++{ ++ struct sk_buff* skb; ++ struct ieee80211_network *beacon = &ieee->current_network; ++ ++ del_timer_sync(&ieee->associate_timer); ++ ++ IEEE80211_DEBUG_MGMT("Sending association request\n"); ++ ++ ieee->softmac_stats.tx_ass_rq++; ++ skb=ieee80211_association_req(beacon, ieee); ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ softmac_mgmt_xmit(skb, ieee); ++ mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); ++#if 0 ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++#endif ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_complete_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq); ++#else ++void ieee80211_associate_complete_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ printk(KERN_INFO "Associated successfully\n"); ++ ieee->is_roaming = false; ++ if(ieee80211_is_54g(ieee->current_network) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION)){ ++ ++ ieee->rate = 108; ++ printk(KERN_INFO"Using G rates:%d\n", ieee->rate); ++ }else{ ++ ieee->rate = 22; ++ printk(KERN_INFO"Using B rates:%d\n", ieee->rate); ++ } ++ if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT) ++ { ++ printk("Successfully associated, ht enabled\n"); ++ HTOnAssocRsp(ieee); ++ } ++ else ++ { ++ printk("Successfully associated, ht not enabled(%d, %d)\n", ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bEnableHT); ++ memset(ieee->dot11HTOperationalRateSet, 0, 16); ++ //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ } ++ ieee->LinkDetectInfo.SlotNum = 2 * (1 + ieee->current_network.beacon_interval/500); ++ // To prevent the immediately calling watch_dog after association. ++ if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 ) ++ { ++ ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; ++ ieee->LinkDetectInfo.NumRecvDataInPeriod= 1; ++ } ++ ieee->link_change(ieee->dev); ++ if(ieee->is_silent_reset == 0){ ++ printk("============>normal associate\n"); ++ notify_wx_assoc_event(ieee); ++ } ++ else if(ieee->is_silent_reset == 1) ++ { ++ printk("==================>silent reset associate\n"); ++ ieee->is_silent_reset = 0; ++ } ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ netif_carrier_on(ieee->dev); ++} ++ ++void ieee80211_associate_complete(struct ieee80211_device *ieee) ++{ ++// int i; ++// struct net_device* dev = ieee->dev; ++ del_timer_sync(&ieee->associate_timer); ++ ++#if 0 ++ for(i = 0; i < 6; i++) { ++ ieee->seq_ctrl[i] = 0; ++ } ++#endif ++ ieee->state = IEEE80211_LINKED; ++#if 0 ++ if (ieee->pHTInfo->bCurrentHTSupport) ++ { ++ printk("Successfully associated, ht enabled\n"); ++ queue_work(ieee->wq, &ieee->ht_onAssRsp); ++ } ++ else ++ { ++ printk("Successfully associated, ht not enabled\n"); ++ memset(ieee->dot11HTOperationalRateSet, 0, 16); ++ HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ } ++#endif ++ //ieee->UpdateHalRATRTableHandler(dev, ieee->dot11HTOperationalRateSet); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_complete_wq); ++#else ++ schedule_task(&ieee->associate_complete_wq); ++#endif ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_procedure_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); ++#else ++void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_scan(ieee); ++ printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel); ++ //ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ ++ ieee->associate_seq = 1; ++ ieee80211_associate_step1(ieee); ++ ++ up(&ieee->wx_sem); ++} ++ ++inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net) ++{ ++ u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; ++ int tmp_ssid_len = 0; ++ ++ short apset,ssidset,ssidbroad,apmatch,ssidmatch; ++ ++ /* we are interested in new new only if we are not associated ++ * and we are not associating / authenticating ++ */ ++ if (ieee->state != IEEE80211_NOLINK) ++ return; ++ ++ if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS)) ++ return; ++ ++ if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) ++ return; ++ ++ ++ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){ ++ /* if the user specified the AP MAC, we need also the essid ++ * This could be obtained by beacons or, if the network does not ++ * broadcast it, it can be put manually. ++ */ ++ apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 ); ++ ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0'; ++ ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0'); ++ apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0); ++ ssidmatch = (ieee->current_network.ssid_len == net->ssid_len)&&\ ++ (!strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); ++ ++ ++ if ( /* if the user set the AP check if match. ++ * if the network does not broadcast essid we check the user supplyed ANY essid ++ * if the network does broadcast and the user does not set essid it is OK ++ * if the network does broadcast and the user did set essid chech if essid match ++ */ ++ ( apset && apmatch && ++ ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || ++ /* if the ap is not set, check that the user set the bssid ++ * and the network does bradcast and that those two bssid matches ++ */ ++ (!apset && ssidset && ssidbroad && ssidmatch) ++ ){ ++ /* if the essid is hidden replace it with the ++ * essid provided by the user. ++ */ ++ if (!ssidbroad){ ++ strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); ++ tmp_ssid_len = ieee->current_network.ssid_len; ++ } ++ memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network)); ++ ++ if (!ssidbroad){ ++ strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); ++ ieee->current_network.ssid_len = tmp_ssid_len; ++ } ++ printk(KERN_INFO"Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d\n",ieee->current_network.ssid,ieee->current_network.channel, ieee->current_network.qos_data.supported, ieee->pHTInfo->bEnableHT, ieee->current_network.bssht.bdSupportHT); ++ ++ //ieee->pHTInfo->IOTAction = 0; ++ HTResetIOTSetting(ieee->pHTInfo); ++ if (ieee->iw_mode == IW_MODE_INFRA){ ++ /* Join the network for the first time */ ++ ieee->AsocRetryCount = 0; ++ //for HT by amy 080514 ++ if((ieee->current_network.qos_data.supported == 1) && ++ // (ieee->pHTInfo->bEnableHT && ieee->current_network.bssht.bdSupportHT)) ++ ieee->current_network.bssht.bdSupportHT) ++/*WB, 2008.09.09:bCurrentHTSupport and bEnableHT two flags are going to put together to check whether we are in HT now, so needn't to check bEnableHT flags here. That's is to say we will set to HT support whenever joined AP has the ability to support HT. And whether we are in HT or not, please check bCurrentHTSupport&&bEnableHT now please.*/ ++ { ++ // ieee->pHTInfo->bCurrentHTSupport = true; ++ HTResetSelfAndSavePeerSetting(ieee, &(ieee->current_network)); ++ } ++ else ++ { ++ ieee->pHTInfo->bCurrentHTSupport = false; ++ } ++ ++ ieee->state = IEEE80211_ASSOCIATING; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++#else ++ schedule_task(&ieee->associate_procedure_wq); ++#endif ++ }else{ ++ if(ieee80211_is_54g(ieee->current_network) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION)){ ++ ieee->rate = 108; ++ ieee->SetWirelessMode(ieee->dev, IEEE_G); ++ printk(KERN_INFO"Using G rates\n"); ++ }else{ ++ ieee->rate = 22; ++ ieee->SetWirelessMode(ieee->dev, IEEE_B); ++ printk(KERN_INFO"Using B rates\n"); ++ } ++ memset(ieee->dot11HTOperationalRateSet, 0, 16); ++ //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ ieee->state = IEEE80211_LINKED; ++ } ++ ++ } ++ } ++ ++} ++ ++void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ struct ieee80211_network *target; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ list_for_each_entry(target, &ieee->network_list, list) { ++ ++ /* if the state become different that NOLINK means ++ * we had found what we are searching for ++ */ ++ ++ if (ieee->state != IEEE80211_NOLINK) ++ break; ++ ++ if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) ++ ieee80211_softmac_new_net(ieee, target); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++ ++static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen) ++{ ++ struct ieee80211_authentication *a; ++ u8 *t; ++ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len); ++ return 0xcafe; ++ } ++ *challenge = NULL; ++ a = (struct ieee80211_authentication*) skb->data; ++ if(skb->len > (sizeof(struct ieee80211_authentication) +3)){ ++ t = skb->data + sizeof(struct ieee80211_authentication); ++ ++ if(*(t++) == MFIE_TYPE_CHALLENGE){ ++ *chlen = *(t++); ++ *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC); ++ memcpy(*challenge, t, *chlen); ++ } ++ } ++ ++ return cpu_to_le16(a->status); ++ ++} ++ ++ ++int auth_rq_parse(struct sk_buff *skb,u8* dest) ++{ ++ struct ieee80211_authentication *a; ++ ++ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len); ++ return -1; ++ } ++ a = (struct ieee80211_authentication*) skb->data; ++ ++ memcpy(dest,a->header.addr2, ETH_ALEN); ++ ++ if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) ++ return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src) ++{ ++ u8 *tag; ++ u8 *skbend; ++ u8 *ssid=NULL; ++ u8 ssidlen = 0; ++ ++ struct ieee80211_hdr_3addr *header = ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ if (skb->len < sizeof (struct ieee80211_hdr_3addr )) ++ return -1; /* corrupted */ ++ ++ memcpy(src,header->addr2, ETH_ALEN); ++ ++ skbend = (u8*)skb->data + skb->len; ++ ++ tag = skb->data + sizeof (struct ieee80211_hdr_3addr ); ++ ++ while (tag+1 < skbend){ ++ if (*tag == 0){ ++ ssid = tag+2; ++ ssidlen = *(tag+1); ++ break; ++ } ++ tag++; /* point to the len field */ ++ tag = tag + *(tag); /* point to the last data byte of the tag */ ++ tag++; /* point to the next tag */ ++ } ++ ++ //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src)); ++ if (ssidlen == 0) return 1; ++ ++ if (!ssid) return 1; /* ssid not found in tagged param */ ++ return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); ++ ++} ++ ++int assoc_rq_parse(struct sk_buff *skb,u8* dest) ++{ ++ struct ieee80211_assoc_request_frame *a; ++ ++ if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) - ++ sizeof(struct ieee80211_info_element))) { ++ ++ IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len); ++ return -1; ++ } ++ ++ a = (struct ieee80211_assoc_request_frame*) skb->data; ++ ++ memcpy(dest,a->header.addr2,ETH_ALEN); ++ ++ return 0; ++} ++ ++static inline u16 assoc_parse(struct ieee80211_device *ieee, struct sk_buff *skb, int *aid) ++{ ++ struct ieee80211_assoc_response_frame *response_head; ++ u16 status_code; ++ ++ if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); ++ return 0xcafe; ++ } ++ ++ response_head = (struct ieee80211_assoc_response_frame*) skb->data; ++ *aid = le16_to_cpu(response_head->aid) & 0x3fff; ++ ++ status_code = le16_to_cpu(response_head->status); ++ if((status_code==WLAN_STATUS_ASSOC_DENIED_RATES || \ ++ status_code==WLAN_STATUS_CAPS_UNSUPPORTED)&& ++ ((ieee->mode == IEEE_G) && ++ (ieee->current_network.mode == IEEE_N_24G) && ++ (ieee->AsocRetryCount++ < (RT_ASOC_RETRY_LIMIT-1)))) { ++ ieee->pHTInfo->IOTAction |= HT_IOT_ACT_PURE_N_MODE; ++ }else { ++ ieee->AsocRetryCount = 0; ++ } ++ ++ return le16_to_cpu(response_head->status); ++} ++ ++static inline void ++ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ u8 dest[ETH_ALEN]; ++ ++ //IEEE80211DMESG("Rx probe"); ++ ieee->softmac_stats.rx_probe_rq++; ++ //DMESG("Dest is "MACSTR, MAC2STR(dest)); ++ if (probe_rq_parse(ieee, skb, dest)){ ++ //IEEE80211DMESG("Was for me!"); ++ ieee->softmac_stats.tx_probe_rs++; ++ ieee80211_resp_to_probe(ieee, dest); ++ } ++} ++ ++static inline void ++ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ u8 dest[ETH_ALEN]; ++ int status; ++ //IEEE80211DMESG("Rx probe"); ++ ieee->softmac_stats.rx_auth_rq++; ++ ++ if ((status = auth_rq_parse(skb, dest))!= -1){ ++ ieee80211_resp_to_auth(ieee, status, dest); ++ } ++ //DMESG("Dest is "MACSTR, MAC2STR(dest)); ++ ++} ++ ++static inline void ++ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ ++ u8 dest[ETH_ALEN]; ++ //unsigned long flags; ++ ++ ieee->softmac_stats.rx_ass_rq++; ++ if (assoc_rq_parse(skb,dest) != -1){ ++ ieee80211_resp_to_assoc_rq(ieee, dest); ++ } ++ ++ printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest)); ++ //FIXME ++ #if 0 ++ spin_lock_irqsave(&ieee->lock,flags); ++ add_associate(ieee,dest); ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ #endif ++} ++ ++ ++ ++void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr) ++{ ++ ++ struct sk_buff *buf = ieee80211_null_func(ieee, pwr); ++ ++ if (buf) ++ softmac_ps_mgmt_xmit(buf, ieee); ++ ++} ++ ++ ++short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l) ++{ ++ int timeout = ieee->ps_timeout; ++ u8 dtim; ++ /*if(ieee->ps == IEEE80211_PS_DISABLED || ++ ieee->iw_mode != IW_MODE_INFRA || ++ ieee->state != IEEE80211_LINKED) ++ ++ return 0; ++ */ ++ dtim = ieee->current_network.dtim_data; ++ //printk("DTIM\n"); ++ if(!(dtim & IEEE80211_DTIM_VALID)) ++ return 0; ++ timeout = ieee->current_network.beacon_interval; //should we use ps_timeout value or beacon_interval ++ //printk("VALID\n"); ++ ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID; ++ ++ if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps)) ++ return 2; ++ ++ if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))) ++ return 0; ++ ++ if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))) ++ return 0; ++ ++ if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) && ++ (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) ++ return 0; ++ ++ if(time_l){ ++ *time_l = ieee->current_network.last_dtim_sta_time[0] ++ + (ieee->current_network.beacon_interval); ++ // * ieee->current_network.dtim_period) * 1000; ++ } ++ ++ if(time_h){ ++ *time_h = ieee->current_network.last_dtim_sta_time[1]; ++ if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) ++ *time_h += 1; ++ } ++ ++ return 1; ++ ++ ++} ++ ++inline void ieee80211_sta_ps(struct ieee80211_device *ieee) ++{ ++ ++ u32 th,tl; ++ short sleep; ++ ++ unsigned long flags,flags2; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if((ieee->ps == IEEE80211_PS_DISABLED || ++ ieee->iw_mode != IW_MODE_INFRA || ++ ieee->state != IEEE80211_LINKED)){ ++ ++ // #warning CHECK_LOCK_HERE ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ ieee80211_sta_wakeup(ieee, 1); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ ++ sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl); ++ /* 2 wake, 1 sleep, 0 do nothing */ ++ if(sleep == 0) ++ goto out; ++ ++ if(sleep == 1){ ++ ++ if(ieee->sta_sleep == 1) ++ ieee->enter_sleep_state(ieee->dev,th,tl); ++ ++ else if(ieee->sta_sleep == 0){ ++ // printk("send null 1\n"); ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ if(ieee->ps_is_queue_empty(ieee->dev)){ ++ ++ ++ ieee->sta_sleep = 2; ++ ++ ieee->ack_tx_to_ieee = 1; ++ ++ ieee80211_sta_ps_send_null_frame(ieee,1); ++ ++ ieee->ps_th = th; ++ ieee->ps_tl = tl; ++ } ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ ++ } ++ ++ ++ }else if(sleep == 2){ ++//#warning CHECK_LOCK_HERE ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ ieee80211_sta_wakeup(ieee,1); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ ++out: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl) ++{ ++ if(ieee->sta_sleep == 0){ ++ if(nl){ ++ printk("Warning: driver is probably failing to report TX ps error\n"); ++ ieee->ack_tx_to_ieee = 1; ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ } ++ return; ++ ++ } ++ ++ if(ieee->sta_sleep == 1) ++ ieee->sta_wake_up(ieee->dev); ++ ++ ieee->sta_sleep = 0; ++ ++ if(nl){ ++ ieee->ack_tx_to_ieee = 1; ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ } ++} ++ ++void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success) ++{ ++ unsigned long flags,flags2; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(ieee->sta_sleep == 2){ ++ /* Null frame with PS bit set */ ++ if(success){ ++ ieee->sta_sleep = 1; ++ ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl); ++ } ++ /* if the card report not success we can't be sure the AP ++ * has not RXed so we can't assume the AP believe us awake ++ */ ++ } ++ /* 21112005 - tx again null without PS bit if lost */ ++ else { ++ ++ if((ieee->sta_sleep == 0) && !success){ ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++void ieee80211_process_action(struct ieee80211_device* ieee, struct sk_buff* skb) ++{ ++ struct ieee80211_hdr* header = (struct ieee80211_hdr*)skb->data; ++ u8* act = ieee80211_get_payload(header); ++ u8 tmp = 0; ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); ++ if (act == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "error to get payload of action frame\n"); ++ return; ++ } ++ tmp = *act; ++ act ++; ++ switch (tmp) ++ { ++ case ACT_CAT_BA: ++ if (*act == ACT_ADDBAREQ) ++ ieee80211_rx_ADDBAReq(ieee, skb); ++ else if (*act == ACT_ADDBARSP) ++ ieee80211_rx_ADDBARsp(ieee, skb); ++ else if (*act == ACT_DELBA) ++ ieee80211_rx_DELBA(ieee, skb); ++ break; ++ default: ++// if (net_ratelimit()) ++// IEEE80211_DEBUG(IEEE80211_DL_BA, "unknown action frame(%d)\n", tmp); ++ break; ++ } ++ return; ++ ++} ++inline int ++ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype) ++{ ++ struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data; ++ u16 errcode; ++ u8* challenge; ++ int chlen=0; ++ int aid; ++ struct ieee80211_assoc_response_frame *assoc_resp; ++// struct ieee80211_info_element *info_element; ++ bool bSupportNmode = true, bHalfSupportNmode = false; //default support N mode, disable halfNmode ++ ++ if(!ieee->proto_started) ++ return 0; ++#if 0 ++ printk("%d, %d, %d, %d\n", ieee->sta_sleep, ieee->ps, ieee->iw_mode, ieee->state); ++ if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && ++ ieee->iw_mode == IW_MODE_INFRA && ++ ieee->state == IEEE80211_LINKED)) ++ ++ tasklet_schedule(&ieee->ps_task); ++ ++ if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && ++ WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) ++ ieee->last_rx_ps_time = jiffies; ++#endif ++ ++ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { ++ ++ case IEEE80211_STYPE_ASSOC_RESP: ++ case IEEE80211_STYPE_REASSOC_RESP: ++ ++ IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ struct ieee80211_network network_resp; ++ struct ieee80211_network *network = &network_resp; ++ ++ if (0 == (errcode=assoc_parse(ieee,skb, &aid))){ ++ ieee->state=IEEE80211_LINKED; ++ ieee->assoc_id = aid; ++ ieee->softmac_stats.rx_ass_ok++; ++ /* station support qos */ ++ /* Let the register setting defaultly with Legacy station */ ++ if(ieee->qos_support) { ++ assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data; ++ memset(network, 0, sizeof(*network)); ++ if (ieee80211_parse_info_param(ieee,assoc_resp->info_element,\ ++ rx_stats->len - sizeof(*assoc_resp),\ ++ network,rx_stats)){ ++ return 1; ++ } ++ else ++ { //filling the PeerHTCap. //maybe not neccesary as we can get its info from current_network. ++ memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen); ++ memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen); ++ } ++ if (ieee->handle_assoc_response != NULL) ++ ieee->handle_assoc_response(ieee->dev, (struct ieee80211_assoc_response_frame*)header, network); ++ } ++ ieee80211_associate_complete(ieee); ++ } else { ++ /* aid could not been allocated */ ++ ieee->softmac_stats.rx_ass_err++; ++ printk( ++ "Association response status code 0x%x\n", ++ errcode); ++ IEEE80211_DEBUG_MGMT( ++ "Association response status code 0x%x\n", ++ errcode); ++ if(ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT) { ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++#else ++ schedule_task(&ieee->associate_procedure_wq); ++#endif ++ } else { ++ ieee80211_associate_abort(ieee); ++ } ++ } ++ } ++ break; ++ ++ case IEEE80211_STYPE_ASSOC_REQ: ++ case IEEE80211_STYPE_REASSOC_REQ: ++ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->iw_mode == IW_MODE_MASTER) ++ ++ ieee80211_rx_assoc_rq(ieee, skb); ++ break; ++ ++ case IEEE80211_STYPE_AUTH: ++ ++ if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){ ++ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ ++ IEEE80211_DEBUG_MGMT("Received authentication response"); ++ ++ if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){ ++ if(ieee->open_wep || !challenge){ ++ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED; ++ ieee->softmac_stats.rx_auth_rs_ok++; ++ if(!(ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE)) ++ { ++ if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) ++ { ++ // WEP or TKIP encryption ++ if(IsHTHalfNmodeAPs(ieee)) ++ { ++ bSupportNmode = true; ++ bHalfSupportNmode = true; ++ } ++ else ++ { ++ bSupportNmode = false; ++ bHalfSupportNmode = false; ++ } ++ printk("==========>to link with AP using SEC(%d, %d)", bSupportNmode, bHalfSupportNmode); ++ } ++ } ++ /* Dummy wirless mode setting to avoid encryption issue */ ++ if(bSupportNmode) { ++ //N mode setting ++ ieee->SetWirelessMode(ieee->dev, \ ++ ieee->current_network.mode); ++ }else{ ++ //b/g mode setting ++ /*TODO*/ ++ ieee->SetWirelessMode(ieee->dev, IEEE_G); ++ } ++ ++ if (ieee->current_network.mode == IEEE_N_24G && bHalfSupportNmode == true) ++ { ++ printk("===============>entern half N mode\n"); ++ ieee->bHalfWirelessN24GMode = true; ++ } ++ else ++ ieee->bHalfWirelessN24GMode = false; ++ ++ ieee80211_associate_step2(ieee); ++ }else{ ++ ieee80211_auth_challenge(ieee, challenge, chlen); ++ } ++ }else{ ++ ieee->softmac_stats.rx_auth_rs_err++; ++ IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); ++ ++ printk("Authentication respose status code 0x%x",errcode); ++ ieee80211_associate_abort(ieee); ++ } ++ ++ }else if (ieee->iw_mode == IW_MODE_MASTER){ ++ ieee80211_rx_auth_rq(ieee, skb); ++ } ++ } ++ break; ++ ++ case IEEE80211_STYPE_PROBE_REQ: ++ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && ++ ((ieee->iw_mode == IW_MODE_ADHOC || ++ ieee->iw_mode == IW_MODE_MASTER) && ++ ieee->state == IEEE80211_LINKED)){ ++ ieee80211_rx_probe_rq(ieee, skb); ++ } ++ break; ++ ++ case IEEE80211_STYPE_DISASSOC: ++ case IEEE80211_STYPE_DEAUTH: ++ /* FIXME for now repeat all the association procedure ++ * both for disassociation and deauthentication ++ */ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->state == IEEE80211_LINKED && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ ++ ieee->state = IEEE80211_ASSOCIATING; ++ ieee->softmac_stats.reassoc++; ++ ieee->is_roaming = true; ++ ieee80211_disassociate(ieee); ++ // notify_wx_assoc_event(ieee); ++ //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ RemovePeerTS(ieee, header->addr2); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++#else ++ schedule_task(&ieee->associate_procedure_wq); ++#endif ++ } ++ break; ++ case IEEE80211_STYPE_MANAGE_ACT: ++ ieee80211_process_action(ieee,skb); ++ break; ++ default: ++ return -1; ++ break; ++ } ++ ++ //dev_kfree_skb_any(skb); ++ return 0; ++} ++ ++/* following are for a simplier TX queue management. ++ * Instead of using netif_[stop/wake]_queue the driver ++ * will uses these two function (plus a reset one), that ++ * will internally uses the kernel netif_* and takes ++ * care of the ieee802.11 fragmentation. ++ * So the driver receives a fragment per time and might ++ * call the stop function when it want without take care ++ * to have enought room to TX an entire packet. ++ * This might be useful if each fragment need it's own ++ * descriptor, thus just keep a total free memory > than ++ * the max fragmentation treshold is not enought.. If the ++ * ieee802.11 stack passed a TXB struct then you needed ++ * to keep N free descriptors where ++ * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD ++ * In this way you need just one and the 802.11 stack ++ * will take care of buffering fragments and pass them to ++ * to the driver later, when it wakes the queue. ++ */ ++void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee) ++{ ++ ++ unsigned int queue_index = txb->queue_index; ++ unsigned long flags; ++ int i; ++ cb_desc *tcb_desc = NULL; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ ++ /* called with 2nd parm 0, no tx mgmt lock required */ ++ ieee80211_sta_wakeup(ieee,0); ++ ++ /* update the tx status */ ++// ieee->stats.tx_bytes += txb->payload_size; ++// ieee->stats.tx_packets++; ++ tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); ++ if(tcb_desc->bMulticast) { ++ ieee->stats.multicast++; ++ } ++#if 1 ++ /* if xmit available, just xmit it immediately, else just insert it to the wait queue */ ++ for(i = 0; i < txb->nr_frags; i++) { ++#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE ++ if ((skb_queue_len(&ieee->skb_drv_aggQ[queue_index]) != 0) || ++#else ++ if ((skb_queue_len(&ieee->skb_waitQ[queue_index]) != 0) || ++#endif ++ (!ieee->check_nic_enough_desc(ieee->dev,queue_index))||\ ++ (ieee->queue_stop)) { ++ /* insert the skb packet to the wait queue */ ++ /* as for the completion function, it does not need ++ * to check it any more. ++ * */ ++ //printk("error:no descriptor left@queue_index %d\n", queue_index); ++ //ieee80211_stop_queue(ieee); ++#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE ++ skb_queue_tail(&ieee->skb_drv_aggQ[queue_index], txb->fragments[i]); ++#else ++ skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]); ++#endif ++ }else{ ++ ieee->softmac_data_hard_start_xmit( ++ txb->fragments[i], ++ ieee->dev,ieee->rate); ++ //ieee->stats.tx_packets++; ++ //ieee->stats.tx_bytes += txb->fragments[i]->len; ++ //ieee->dev->trans_start = jiffies; ++ } ++ } ++#endif ++ ieee80211_txb_free(txb); ++ ++//exit: ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++/* called with ieee->lock acquired */ ++void ieee80211_resume_tx(struct ieee80211_device *ieee) ++{ ++ int i; ++ for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { ++ ++ if (ieee->queue_stop){ ++ ieee->tx_pending.frag = i; ++ return; ++ }else{ ++ ++ ieee->softmac_data_hard_start_xmit( ++ ieee->tx_pending.txb->fragments[i], ++ ieee->dev,ieee->rate); ++ //(i+1)tx_pending.txb->nr_frags); ++ ieee->stats.tx_packets++; ++ // ieee->dev->trans_start = jiffies; ++ } ++ } ++ ++ ++ ieee80211_txb_free(ieee->tx_pending.txb); ++ ieee->tx_pending.txb = NULL; ++} ++ ++ ++void ieee80211_reset_queue(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ init_mgmt_queue(ieee); ++ if (ieee->tx_pending.txb){ ++ ieee80211_txb_free(ieee->tx_pending.txb); ++ ieee->tx_pending.txb = NULL; ++ } ++ ieee->queue_stop = 0; ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++void ieee80211_wake_queue(struct ieee80211_device *ieee) ++{ ++ ++ unsigned long flags; ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr *header; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ if (! ieee->queue_stop) goto exit; ++ ++ ieee->queue_stop = 0; ++ ++ if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){ ++ while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){ ++ ++ header = (struct ieee80211_hdr_3addr *) skb->data; ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++ } ++ if (!ieee->queue_stop && ieee->tx_pending.txb) ++ ieee80211_resume_tx(ieee); ++ ++ if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){ ++ ieee->softmac_stats.swtxawake++; ++ netif_wake_queue(ieee->dev); ++ } ++ ++exit : ++ spin_unlock_irqrestore(&ieee->lock,flags); ++} ++ ++ ++void ieee80211_stop_queue(struct ieee80211_device *ieee) ++{ ++ //unsigned long flags; ++ //spin_lock_irqsave(&ieee->lock,flags); ++ ++ if (! netif_queue_stopped(ieee->dev)){ ++ netif_stop_queue(ieee->dev); ++ ieee->softmac_stats.swtxstop++; ++ } ++ ieee->queue_stop = 1; ++ //spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++ ++inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) ++{ ++ ++ get_random_bytes(ieee->current_network.bssid, ETH_ALEN); ++ ++ /* an IBSS cell address must have the two less significant ++ * bits of the first byte = 2 ++ */ ++ ieee->current_network.bssid[0] &= ~0x01; ++ ieee->current_network.bssid[0] |= 0x02; ++} ++ ++/* called in user context only */ ++void ieee80211_start_master_bss(struct ieee80211_device *ieee) ++{ ++ ieee->assoc_id = 1; ++ ++ if (ieee->current_network.ssid_len == 0){ ++ strncpy(ieee->current_network.ssid, ++ IEEE80211_DEFAULT_TX_ESSID, ++ IW_ESSID_MAX_SIZE); ++ ++ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); ++ ieee->ssid_set = 1; ++ } ++ ++ memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); ++ ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->state = IEEE80211_LINKED; ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++} ++ ++void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) ++{ ++ if(ieee->raw_tx){ ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_start_ibss_wq(struct work_struct *work) ++{ ++ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); ++#else ++void ieee80211_start_ibss_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ /* iwconfig mode ad-hoc will schedule this and return ++ * on the other hand this will block further iwconfig SET ++ * operations because of the wx_sem hold. ++ * Anyway some most set operations set a flag to speed-up ++ * (abort) this wq (when syncro scanning) before sleeping ++ * on the semaphore ++ */ ++ if(!ieee->proto_started){ ++ printk("==========oh driver down return\n"); ++ return; ++ } ++ down(&ieee->wx_sem); ++ ++ if (ieee->current_network.ssid_len == 0){ ++ strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID); ++ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); ++ ieee->ssid_set = 1; ++ } ++ ++ /* check if we have this cell in our network list */ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ ++#ifdef ENABLE_DOT11D //if creating an ad-hoc, set its channel to 10 temporarily--this is the requirement for ASUS, not 11D, so disable 11d. ++// if((IS_DOT11D_ENABLE(ieee)) && (ieee->state == IEEE80211_NOLINK)) ++ if (ieee->state == IEEE80211_NOLINK) ++ ieee->current_network.channel = 6; ++#endif ++ /* if not then the state is not linked. Maybe the user swithced to ++ * ad-hoc mode just after being in monitor mode, or just after ++ * being very few time in managed mode (so the card have had no ++ * time to scan all the chans..) or we have just run up the iface ++ * after setting ad-hoc mode. So we have to give another try.. ++ * Here, in ibss mode, should be safe to do this without extra care ++ * (in bss mode we had to make sure no-one tryed to associate when ++ * we had just checked the ieee->state and we was going to start the ++ * scan) beacause in ibss mode the ieee80211_new_net function, when ++ * finds a good net, just set the ieee->state to IEEE80211_LINKED, ++ * so, at worst, we waste a bit of time to initiate an unneeded syncro ++ * scan, that will stop at the first round because it sees the state ++ * associated. ++ */ ++ if (ieee->state == IEEE80211_NOLINK) ++ ieee80211_start_scan_syncro(ieee); ++ ++ /* the network definitively is not here.. create a new cell */ ++ if (ieee->state == IEEE80211_NOLINK){ ++ printk("creating new IBSS cell\n"); ++ if(!ieee->wap_set) ++ ieee80211_randomize_cell(ieee); ++ ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ ++ ieee->current_network.rates_len = 4; ++ ++ ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; ++ ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; ++ ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; ++ ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; ++ ++ }else ++ ieee->current_network.rates_len = 0; ++ ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ieee->current_network.rates_ex_len = 8; ++ ++ ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; ++ ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; ++ ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; ++ ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; ++ ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; ++ ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; ++ ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; ++ ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; ++ ++ ieee->rate = 108; ++ }else{ ++ ieee->current_network.rates_ex_len = 0; ++ ieee->rate = 22; ++ } ++ ++ // By default, WMM function will be disabled in IBSS mode ++ ieee->current_network.QoS_Enable = 0; ++ ieee->SetWirelessMode(ieee->dev, IEEE_G); ++ ieee->current_network.atim_window = 0; ++ ieee->current_network.capability = WLAN_CAPABILITY_IBSS; ++ if(ieee->short_slot) ++ ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT; ++ ++ } ++ ++ ieee->state = IEEE80211_LINKED; ++ ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->link_change(ieee->dev); ++ ++ notify_wx_assoc_event(ieee); ++ ++ ieee80211_start_send_beacons(ieee); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ netif_carrier_on(ieee->dev); ++ ++ up(&ieee->wx_sem); ++} ++ ++inline void ieee80211_start_ibss(struct ieee80211_device *ieee) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 150); ++#else ++ schedule_task(&ieee->start_ibss_wq); ++#endif ++} ++ ++/* this is called only in user context, with wx_sem held */ ++void ieee80211_start_bss(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++#ifdef ENABLE_DOT11D ++ // ++ // Ref: 802.11d 11.1.3.3 ++ // STA shall not start a BSS unless properly formed Beacon frame including a Country IE. ++ // ++ if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) ++ { ++ if(! ieee->bGlobalDomain) ++ { ++ return; ++ } ++ } ++#endif ++ /* check if we have already found the net we ++ * are interested in (if any). ++ * if not (we are disassociated and we are not ++ * in associating / authenticating phase) start the background scanning. ++ */ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ /* ensure no-one start an associating process (thus setting ++ * the ieee->state to ieee80211_ASSOCIATING) while we ++ * have just cheked it and we are going to enable scan. ++ * The ieee80211_new_net function is always called with ++ * lock held (from both ieee80211_softmac_check_all_nets and ++ * the rx path), so we cannot be in the middle of such function ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->state == IEEE80211_NOLINK){ ++ ieee->actscanning = true; ++ ieee80211_start_scan(ieee); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++/* called only in userspace context */ ++void ieee80211_disassociate(struct ieee80211_device *ieee) ++{ ++ ++ ++ netif_carrier_off(ieee->dev); ++ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) ++ ieee80211_reset_queue(ieee); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ Dot11d_Reset(ieee); ++#endif ++ ieee->state = IEEE80211_NOLINK; ++ ieee->is_set_key = false; ++ ieee->link_change(ieee->dev); ++ //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ notify_wx_assoc_event(ieee); ++ ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_retry_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); ++#else ++void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ unsigned long flags; ++ ++ down(&ieee->wx_sem); ++ if(!ieee->proto_started) ++ goto exit; ++ ++ if(ieee->state != IEEE80211_ASSOCIATING_RETRY) ++ goto exit; ++ ++ /* until we do not set the state to IEEE80211_NOLINK ++ * there are no possibility to have someone else trying ++ * to start an association procdure (we get here with ++ * ieee->state = IEEE80211_ASSOCIATING). ++ * When we set the state to IEEE80211_NOLINK it is possible ++ * that the RX path run an attempt to associate, but ++ * both ieee80211_softmac_check_all_nets and the ++ * RX path works with ieee->lock held so there are no ++ * problems. If we are still disassociated then start a scan. ++ * the lock here is necessary to ensure no one try to start ++ * an association procedure when we have just checked the ++ * state and we are going to start the scan. ++ */ ++ ieee->beinretry = true; ++ ieee->state = IEEE80211_NOLINK; ++ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(ieee->state == IEEE80211_NOLINK) ++ { ++ ieee->is_roaming= false; ++ ieee->actscanning = true; ++ ieee80211_start_scan(ieee); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ ieee->beinretry = false; ++exit: ++ up(&ieee->wx_sem); ++} ++ ++struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) ++{ ++ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ struct sk_buff *skb; ++ struct ieee80211_probe_response *b; ++ ++ skb = ieee80211_probe_resp(ieee, broadcast_addr); ++ ++ if (!skb) ++ return NULL; ++ ++ b = (struct ieee80211_probe_response *) skb->data; ++ b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); ++ ++ return skb; ++ ++} ++ ++struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_probe_response *b; ++ ++ skb = ieee80211_get_beacon_(ieee); ++ if(!skb) ++ return NULL; ++ ++ b = (struct ieee80211_probe_response *) skb->data; ++ b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ return skb; ++} ++ ++void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) ++{ ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ieee80211_stop_protocol(ieee); ++ up(&ieee->wx_sem); ++} ++ ++ ++void ieee80211_stop_protocol(struct ieee80211_device *ieee) ++{ ++ if (!ieee->proto_started) ++ return; ++ ++ ieee->proto_started = 0; ++ ++ ieee80211_stop_send_beacons(ieee); ++ del_timer_sync(&ieee->associate_timer); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->associate_retry_wq); ++ cancel_delayed_work(&ieee->start_ibss_wq); ++#endif ++ ieee80211_stop_scan(ieee); ++ ++ ieee80211_disassociate(ieee); ++ RemoveAllTS(ieee); //added as we disconnect from the previous BSS, Remove all TS ++} ++ ++void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) ++{ ++ ieee->sync_scan_hurryup = 0; ++ down(&ieee->wx_sem); ++ ieee80211_start_protocol(ieee); ++ up(&ieee->wx_sem); ++} ++ ++void ieee80211_start_protocol(struct ieee80211_device *ieee) ++{ ++ short ch = 0; ++ int i = 0; ++ if (ieee->proto_started) ++ return; ++ ++ ieee->proto_started = 1; ++ ++ if (ieee->current_network.channel == 0){ ++ do{ ++ ch++; ++ if (ch > MAX_CHANNEL_NUMBER) ++ return; /* no channel found */ ++#ifdef ENABLE_DOT11D ++ }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]); ++#else ++ }while(!ieee->channel_map[ch]); ++#endif ++ ieee->current_network.channel = ch; ++ } ++ ++ if (ieee->current_network.beacon_interval == 0) ++ ieee->current_network.beacon_interval = 100; ++// printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel); ++// ieee->set_chan(ieee->dev,ieee->current_network.channel); ++ ++ for(i = 0; i < 17; i++) { ++ ieee->last_rxseq_num[i] = -1; ++ ieee->last_rxfrag_num[i] = -1; ++ ieee->last_packet_time[i] = 0; ++ } ++ ++ ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers. ++ ++ ++ /* if the user set the MAC of the ad-hoc cell and then ++ * switch to managed mode, shall we make sure that association ++ * attempts does not fail just because the user provide the essid ++ * and the nic is still checking for the AP MAC ?? ++ */ ++ if (ieee->iw_mode == IW_MODE_INFRA) ++ ieee80211_start_bss(ieee); ++ ++ else if (ieee->iw_mode == IW_MODE_ADHOC) ++ ieee80211_start_ibss(ieee); ++ ++ else if (ieee->iw_mode == IW_MODE_MASTER) ++ ieee80211_start_master_bss(ieee); ++ ++ else if(ieee->iw_mode == IW_MODE_MONITOR) ++ ieee80211_start_monitor_mode(ieee); ++} ++ ++ ++#define DRV_NAME "Ieee80211" ++void ieee80211_softmac_init(struct ieee80211_device *ieee) ++{ ++ int i; ++ memset(&ieee->current_network, 0, sizeof(struct ieee80211_network)); ++ ++ ieee->state = IEEE80211_NOLINK; ++ ieee->sync_scan_hurryup = 0; ++ for(i = 0; i < 5; i++) { ++ ieee->seq_ctrl[i] = 0; ++ } ++#ifdef ENABLE_DOT11D ++ ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); ++ if (!ieee->pDot11dInfo) ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for DOT11D\n"); ++ memset(ieee->pDot11dInfo, 0, sizeof(RT_DOT11D_INFO)); ++#endif ++ //added for AP roaming ++ ieee->LinkDetectInfo.SlotNum = 2; ++ ieee->LinkDetectInfo.NumRecvBcnInPeriod=0; ++ ieee->LinkDetectInfo.NumRecvDataInPeriod=0; ++ ++ ieee->assoc_id = 0; ++ ieee->queue_stop = 0; ++ ieee->scanning = 0; ++ ieee->softmac_features = 0; //so IEEE2100-like driver are happy ++ ieee->wap_set = 0; ++ ieee->ssid_set = 0; ++ ieee->proto_started = 0; ++ ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE; ++ ieee->rate = 22; ++ ieee->ps = IEEE80211_PS_DISABLED; ++ ieee->sta_sleep = 0; ++ ieee->Regdot11HTOperationalRateSet[0]= 0xff;//support MCS 0~7 ++ ieee->Regdot11HTOperationalRateSet[1]= 0xff;//support MCS 8~15 ++ ieee->Regdot11HTOperationalRateSet[4]= 0x01; ++ //added by amy ++ ieee->actscanning = false; ++ ieee->beinretry = false; ++ ieee->is_set_key = false; ++ init_mgmt_queue(ieee); ++ ++ ieee->sta_edca_param[0] = 0x0000A403; ++ ieee->sta_edca_param[1] = 0x0000A427; ++ ieee->sta_edca_param[2] = 0x005E4342; ++ ieee->sta_edca_param[3] = 0x002F3262; ++ ieee->aggregation = true; ++ ieee->enable_rx_imm_BA = 1; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ init_timer(&ieee->scan_timer); ++ ieee->scan_timer.data = (unsigned long)ieee; ++ ieee->scan_timer.function = ieee80211_softmac_scan_cb; ++#endif ++ ieee->tx_pending.txb = NULL; ++ ++ init_timer(&ieee->associate_timer); ++ ieee->associate_timer.data = (unsigned long)ieee; ++ ieee->associate_timer.function = ieee80211_associate_abort_cb; ++ ++ init_timer(&ieee->beacon_timer); ++ ieee->beacon_timer.data = (unsigned long) ieee; ++ ieee->beacon_timer.function = ieee80211_send_beacon_cb; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#ifdef PF_SYNCTHREAD ++ ieee->wq = create_workqueue(DRV_NAME,0); ++#else ++ ieee->wq = create_workqueue(DRV_NAME); ++#endif ++#endif ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ INIT_DELAYED_WORK(&ieee->start_ibss_wq,ieee80211_start_ibss_wq); ++ INIT_WORK(&ieee->associate_complete_wq, ieee80211_associate_complete_wq); ++ INIT_WORK(&ieee->associate_procedure_wq, ieee80211_associate_procedure_wq); ++ INIT_DELAYED_WORK(&ieee->softmac_scan_wq,ieee80211_softmac_scan_wq); ++ INIT_DELAYED_WORK(&ieee->associate_retry_wq, ieee80211_associate_retry_wq); ++ INIT_WORK(&ieee->wx_sync_scan_wq,ieee80211_wx_sync_scan_wq); ++ ++#else ++ INIT_WORK(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee); ++ INIT_WORK(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee); ++ INIT_WORK(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee); ++ INIT_WORK(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee); ++ INIT_WORK(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee); ++ INIT_WORK(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee); ++#endif ++ ++#else ++ tq_init(&ieee->start_ibss_wq,(void(*)(void*)) ieee80211_start_ibss_wq,ieee); ++ tq_init(&ieee->associate_retry_wq,(void(*)(void*)) ieee80211_associate_retry_wq,ieee); ++ tq_init(&ieee->associate_complete_wq,(void(*)(void*)) ieee80211_associate_complete_wq,ieee); ++ tq_init(&ieee->associate_procedure_wq,(void(*)(void*)) ieee80211_associate_procedure_wq,ieee); ++ tq_init(&ieee->softmac_scan_wq,(void(*)(void*)) ieee80211_softmac_scan_wq,ieee); ++ tq_init(&ieee->wx_sync_scan_wq,(void(*)(void*)) ieee80211_wx_sync_scan_wq,ieee); ++#endif ++ sema_init(&ieee->wx_sem, 1); ++ sema_init(&ieee->scan_sem, 1); ++ ++ spin_lock_init(&ieee->mgmt_tx_lock); ++ spin_lock_init(&ieee->beacon_lock); ++ ++ tasklet_init(&ieee->ps_task, ++ (void(*)(unsigned long)) ieee80211_sta_ps, ++ (unsigned long)ieee); ++ ++} ++ ++void ieee80211_softmac_free(struct ieee80211_device *ieee) ++{ ++ down(&ieee->wx_sem); ++#ifdef ENABLE_DOT11D ++ if(NULL != ieee->pDot11dInfo) ++ { ++ kfree(ieee->pDot11dInfo); ++ ieee->pDot11dInfo = NULL; ++ } ++#endif ++ del_timer_sync(&ieee->associate_timer); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->associate_retry_wq); ++ destroy_workqueue(ieee->wq); ++#endif ++ ++ up(&ieee->wx_sem); ++} ++ ++/******************************************************** ++ * Start of WPA code. * ++ * this is stolen from the ipw2200 driver * ++ ********************************************************/ ++ ++ ++static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value) ++{ ++ /* This is called when wpa_supplicant loads and closes the driver ++ * interface. */ ++ printk("%s WPA\n",value ? "enabling" : "disabling"); ++ ieee->wpa_enabled = value; ++ return 0; ++} ++ ++ ++void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len) ++{ ++ /* make sure WPA is enabled */ ++ ieee80211_wpa_enable(ieee, 1); ++ ++ ieee80211_disassociate(ieee); ++} ++ ++ ++static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason) ++{ ++ ++ int ret = 0; ++ ++ switch (command) { ++ case IEEE_MLME_STA_DEAUTH: ++ // silently ignore ++ break; ++ ++ case IEEE_MLME_STA_DISASSOC: ++ ieee80211_disassociate(ieee); ++ break; ++ ++ default: ++ printk("Unknown MLME request: %d\n", command); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++ ++static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee, ++ struct ieee_param *param, int plen) ++{ ++ u8 *buf; ++ ++ if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || ++ (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) ++ return -EINVAL; ++ ++ if (param->u.wpa_ie.len) { ++ buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = buf; ++ ieee->wpa_ie_len = param->u.wpa_ie.len; ++ } else { ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = NULL; ++ ieee->wpa_ie_len = 0; ++ } ++ ++ ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); ++ return 0; ++} ++ ++#define AUTH_ALG_OPEN_SYSTEM 0x1 ++#define AUTH_ALG_SHARED_KEY 0x2 ++ ++static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value) ++{ ++ ++ struct ieee80211_security sec = { ++ .flags = SEC_AUTH_MODE, ++ }; ++ int ret = 0; ++ ++ if (value & AUTH_ALG_SHARED_KEY) { ++ sec.auth_mode = WLAN_AUTH_SHARED_KEY; ++ ieee->open_wep = 0; ++ ieee->auth_mode = 1; ++ } else if (value & AUTH_ALG_OPEN_SYSTEM){ ++ sec.auth_mode = WLAN_AUTH_OPEN; ++ ieee->open_wep = 1; ++ ieee->auth_mode = 0; ++ } ++ else if (value & IW_AUTH_ALG_LEAP){ ++ sec.auth_mode = WLAN_AUTH_LEAP; ++ ieee->open_wep = 1; ++ ieee->auth_mode = 2; ++ } ++ ++ ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ //else ++ // ret = -EOPNOTSUPP; ++ ++ return ret; ++} ++ ++static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value) ++{ ++ int ret=0; ++ unsigned long flags; ++ ++ switch (name) { ++ case IEEE_PARAM_WPA_ENABLED: ++ ret = ieee80211_wpa_enable(ieee, value); ++ break; ++ ++ case IEEE_PARAM_TKIP_COUNTERMEASURES: ++ ieee->tkip_countermeasures=value; ++ break; ++ ++ case IEEE_PARAM_DROP_UNENCRYPTED: { ++ /* HACK: ++ * ++ * wpa_supplicant calls set_wpa_enabled when the driver ++ * is loaded and unloaded, regardless of if WPA is being ++ * used. No other calls are made which can be used to ++ * determine if encryption will be used or not prior to ++ * association being expected. If encryption is not being ++ * used, drop_unencrypted is set to false, else true -- we ++ * can use this to determine if the CAP_PRIVACY_ON bit should ++ * be set. ++ */ ++ struct ieee80211_security sec = { ++ .flags = SEC_ENABLED, ++ .enabled = value, ++ }; ++ ieee->drop_unencrypted = value; ++ /* We only change SEC_LEVEL for open mode. Others ++ * are set by ipw_wpa_set_encryption. ++ */ ++ if (!value) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_0; ++ } ++ else { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ break; ++ } ++ ++ case IEEE_PARAM_PRIVACY_INVOKED: ++ ieee->privacy_invoked=value; ++ break; ++ ++ case IEEE_PARAM_AUTH_ALGS: ++ ret = ieee80211_wpa_set_auth_algs(ieee, value); ++ break; ++ ++ case IEEE_PARAM_IEEE_802_1X: ++ ieee->ieee802_1x=value; ++ break; ++ case IEEE_PARAM_WPAX_SELECT: ++ // added for WPA2 mixed mode ++ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); ++ ieee->wpax_type_set = 1; ++ ieee->wpax_type_notify = value; ++ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); ++ break; ++ ++ default: ++ printk("Unknown WPA param: %d\n",name); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++/* implementation borrowed from hostap driver */ ++ ++static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ++ struct ieee_param *param, int param_len) ++{ ++ int ret = 0; ++ ++ struct ieee80211_crypto_ops *ops; ++ struct ieee80211_crypt_data **crypt; ++ ++ struct ieee80211_security sec = { ++ .flags = 0, ++ }; ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len != ++ (int) ((char *) param->u.crypt.key - (char *) param) + ++ param->u.crypt.key_len) { ++ printk("Len mismatch %d, %d\n", param_len, ++ param->u.crypt.key_len); ++ return -EINVAL; ++ } ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { ++ if (param->u.crypt.idx >= WEP_KEYS) ++ return -EINVAL; ++ crypt = &ieee->crypt[param->u.crypt.idx]; ++ } else { ++ return -EINVAL; ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0) { ++ if (crypt) { ++ sec.enabled = 0; ++ // FIXME FIXME ++ //sec.encrypt = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_ENABLED | SEC_LEVEL; ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } ++ goto done; ++ } ++ sec.enabled = 1; ++// FIXME FIXME ++// sec.encrypt = 1; ++ sec.flags |= SEC_ENABLED; ++ ++ /* IPW HW cannot build TKIP MIC, host decryption still needed. */ ++ if (!(ieee->host_encrypt || ieee->host_decrypt) && ++ strcmp(param->u.crypt.alg, "TKIP")) ++ goto skip_host_crypt; ++ ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { ++ request_module("ieee80211_crypt_wep"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ //set WEP40 first, it will be modified according to WEP104 or WEP40 at other place ++ } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { ++ request_module("ieee80211_crypt_tkip"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { ++ request_module("ieee80211_crypt_ccmp"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } ++ if (ops == NULL) { ++ printk("unknown crypto alg '%s'\n", param->u.crypt.alg); ++ param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ if (*crypt == NULL || (*crypt)->ops != ops) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ new_crypt = (struct ieee80211_crypt_data *) ++ kmalloc(sizeof(*new_crypt), GFP_KERNEL); ++ if (new_crypt == NULL) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); ++ new_crypt->ops = ops; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++#else ++ if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner)) ++#endif ++ new_crypt->priv = ++ new_crypt->ops->init(param->u.crypt.idx); ++ ++ if (new_crypt->priv == NULL) { ++ kfree(new_crypt); ++ param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ *crypt = new_crypt; ++ } ++ ++ if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && ++ (*crypt)->ops->set_key(param->u.crypt.key, ++ param->u.crypt.key_len, param->u.crypt.seq, ++ (*crypt)->priv) < 0) { ++ printk("key setting failed\n"); ++ param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ skip_host_crypt: ++ if (param->u.crypt.set_tx) { ++ ieee->tx_keyidx = param->u.crypt.idx; ++ sec.active_key = param->u.crypt.idx; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } else ++ sec.flags &= ~SEC_ACTIVE_KEY; ++ ++ if (param->u.crypt.alg != NULL) { ++ memcpy(sec.keys[param->u.crypt.idx], ++ param->u.crypt.key, ++ param->u.crypt.key_len); ++ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; ++ sec.flags |= (1 << param->u.crypt.idx); ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_2; ++ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_3; ++ } ++ } ++ done: ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ ++ /* Do not reset port if card is in Managed mode since resetting will ++ * generate new IEEE 802.11 authentication which may end up in looping ++ * with IEEE 802.1X. If your hardware requires a reset after WEP ++ * configuration (for example... Prism2), implement the reset_port in ++ * the callbacks structures used to initialize the 802.11 stack. */ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ++ ieee->reset_port(ieee->dev)) { ++ printk("reset_port failed\n"); ++ param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++inline struct sk_buff *ieee80211_disassociate_skb( ++ struct ieee80211_network *beacon, ++ struct ieee80211_device *ieee, ++ u8 asRsn) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_disassoc *disass; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc)); ++ if (!skb) ++ return NULL; ++ ++ disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc)); ++ disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); ++ disass->header.duration_id = 0; ++ ++ memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); ++ ++ disass->reason = asRsn; ++ return skb; ++} ++ ++ ++void ++SendDisassociation( ++ struct ieee80211_device *ieee, ++ u8* asSta, ++ u8 asRsn ++) ++{ ++ struct ieee80211_network *beacon = &ieee->current_network; ++ struct sk_buff *skb; ++ skb = ieee80211_disassociate_skb(beacon,ieee,asRsn); ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ int ret=0; ++ ++ down(&ieee->wx_sem); ++ //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); ++ ++ if (p->length < sizeof(struct ieee_param) || !p->pointer){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); ++ if (param == NULL){ ++ ret = -ENOMEM; ++ goto out; ++ } ++ if (copy_from_user(param, p->pointer, p->length)) { ++ kfree(param); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ switch (param->cmd) { ++ ++ case IEEE_CMD_SET_WPA_PARAM: ++ ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name, ++ param->u.wpa_param.value); ++ break; ++ ++ case IEEE_CMD_SET_WPA_IE: ++ ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length); ++ break; ++ ++ case IEEE_CMD_SET_ENCRYPTION: ++ ret = ieee80211_wpa_set_encryption(ieee, param, p->length); ++ break; ++ ++ case IEEE_CMD_MLME: ++ ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command, ++ param->u.mlme.reason_code); ++ break; ++ ++ default: ++ printk("Unknown WPA supplicant request: %d\n",param->cmd); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ++ ret = -EFAULT; ++ ++ kfree(param); ++out: ++ up(&ieee->wx_sem); ++ ++ return ret; ++} ++ ++void notify_wx_assoc_event(struct ieee80211_device *ieee) ++{ ++ union iwreq_data wrqu; ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ if (ieee->state == IEEE80211_LINKED) ++ memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); ++ else ++ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_get_beacon); ++//EXPORT_SYMBOL(ieee80211_wake_queue); ++//EXPORT_SYMBOL(ieee80211_stop_queue); ++//EXPORT_SYMBOL(ieee80211_reset_queue); ++//EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); ++//EXPORT_SYMBOL(ieee80211_softmac_start_protocol); ++//EXPORT_SYMBOL(ieee80211_is_shortslot); ++//EXPORT_SYMBOL(ieee80211_is_54g); ++//EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl); ++//EXPORT_SYMBOL(ieee80211_ps_tx_ack); ++//EXPORT_SYMBOL(ieee80211_softmac_xmit); ++//EXPORT_SYMBOL(ieee80211_stop_send_beacons); ++//EXPORT_SYMBOL(notify_wx_assoc_event); ++//EXPORT_SYMBOL(SendDisassociation); ++//EXPORT_SYMBOL(ieee80211_disassociate); ++//EXPORT_SYMBOL(ieee80211_start_send_beacons); ++//EXPORT_SYMBOL(ieee80211_stop_scan); ++//EXPORT_SYMBOL(ieee80211_send_probe_requests); ++//EXPORT_SYMBOL(ieee80211_softmac_scan_syncro); ++//EXPORT_SYMBOL(ieee80211_start_scan_syncro); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon); ++EXPORT_SYMBOL_NOVERS(ieee80211_wake_queue); ++EXPORT_SYMBOL_NOVERS(ieee80211_stop_queue); ++EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue); ++EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol); ++EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol); ++EXPORT_SYMBOL_NOVERS(ieee80211_is_shortslot); ++EXPORT_SYMBOL_NOVERS(ieee80211_is_54g); ++EXPORT_SYMBOL_NOVERS(ieee80211_wpa_supplicant_ioctl); ++EXPORT_SYMBOL_NOVERS(ieee80211_ps_tx_ack); ++EXPORT_SYMBOL_NOVERS(ieee80211_softmac_xmit); ++EXPORT_SYMBOL_NOVERS(ieee80211_stop_send_beacons); ++EXPORT_SYMBOL_NOVERS(notify_wx_assoc_event); ++EXPORT_SYMBOL_NOVERS(SendDisassociation); ++EXPORT_SYMBOL_NOVERS(ieee80211_disassociate); ++EXPORT_SYMBOL_NOVERS(ieee80211_start_send_beacons); ++EXPORT_SYMBOL_NOVERS(ieee80211_stop_scan); ++EXPORT_SYMBOL_NOVERS(ieee80211_send_probe_requests); ++EXPORT_SYMBOL_NOVERS(ieee80211_softmac_scan_syncro); ++EXPORT_SYMBOL_NOVERS(ieee80211_start_scan_syncro); ++#endif ++//EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac_wx.c +@@ -0,0 +1,692 @@ ++/* IEEE 802.11 SoftMAC layer ++ * Copyright (c) 2005 Andrea Merello ++ * ++ * Mostly extracted from the rtl8180-sa2400 driver for the ++ * in-kernel generic ieee802.11 stack. ++ * ++ * Some pieces of code might be stolen from ipw2100 driver ++ * copyright of who own it's copyright ;-) ++ * ++ * PS wx handler mostly stolen from hostap, copyright who ++ * own it's copyright ;-) ++ * ++ * released under the GPL ++ */ ++ ++ ++#include "ieee80211.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++/* FIXME: add A freqs */ ++ ++const long ieee80211_wlan_frequencies[] = { ++ 2412, 2417, 2422, 2427, ++ 2432, 2437, 2442, 2447, ++ 2452, 2457, 2462, 2467, ++ 2472, 2484 ++}; ++ ++ ++int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct iw_freq *fwrq = & wrqu->freq; ++ ++ down(&ieee->wx_sem); ++ ++ if(ieee->iw_mode == IW_MODE_INFRA){ ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ /* if setting by freq convert to channel */ ++ if (fwrq->e == 1) { ++ if ((fwrq->m >= (int) 2.412e8 && ++ fwrq->m <= (int) 2.487e8)) { ++ int f = fwrq->m / 100000; ++ int c = 0; ++ ++ while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) ++ c++; ++ ++ /* hack to fall through */ ++ fwrq->e = 0; ++ fwrq->m = c + 1; ++ } ++ } ++ ++ if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ ++ ret = -EOPNOTSUPP; ++ goto out; ++ ++ }else { /* Set the channel */ ++ ++#ifdef ENABLE_DOT11D ++ if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) { ++ ret = -EINVAL; ++ goto out; ++ } ++#endif ++ ieee->current_network.channel = fwrq->m; ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) ++ if(ieee->state == IEEE80211_LINKED){ ++ ++ ieee80211_stop_send_beacons(ieee); ++ ieee80211_start_send_beacons(ieee); ++ } ++ } ++ ++ ret = 0; ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ ++int ieee80211_wx_get_freq(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct iw_freq *fwrq = & wrqu->freq; ++ ++ if (ieee->current_network.channel == 0) ++ return -1; ++ //NM 0.7.0 will not accept channel any more. ++ fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000; ++ fwrq->e = 1; ++// fwrq->m = ieee->current_network.channel; ++// fwrq->e = 0; ++ ++ return 0; ++} ++ ++int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ unsigned long flags; ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ /* We want avoid to give to the user inconsistent infos*/ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->state != IEEE80211_LINKED && ++ ieee->state != IEEE80211_LINKED_SCANNING && ++ ieee->wap_set == 0) ++ ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ else ++ memcpy(wrqu->ap_addr.sa_data, ++ ieee->current_network.bssid, ETH_ALEN); ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ return 0; ++} ++ ++ ++int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ ++ int ret = 0; ++ u8 zero[] = {0,0,0,0,0,0}; ++ unsigned long flags; ++ ++ short ifup = ieee->proto_started;//dev->flags & IFF_UP; ++ struct sockaddr *temp = (struct sockaddr *)awrq; ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ /* use ifconfig hw ether */ ++ if (ieee->iw_mode == IW_MODE_MASTER){ ++ ret = -1; ++ goto out; ++ } ++ ++ if (temp->sa_family != ARPHRD_ETHER){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (ifup) ++ ieee80211_stop_protocol(ieee); ++ ++ /* just to avoid to give inconsistent infos in the ++ * get wx method. not really needed otherwise ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); ++ ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ if (ifup) ++ ieee80211_start_protocol(ieee); ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) ++{ ++ int len,ret = 0; ++ unsigned long flags; ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ /* We want avoid to give to the user inconsistent infos*/ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->current_network.ssid[0] == '\0' || ++ ieee->current_network.ssid_len == 0){ ++ ret = -1; ++ goto out; ++ } ++ ++ if (ieee->state != IEEE80211_LINKED && ++ ieee->state != IEEE80211_LINKED_SCANNING && ++ ieee->ssid_set == 0){ ++ ret = -1; ++ goto out; ++ } ++ len = ieee->current_network.ssid_len; ++ wrqu->essid.length = len; ++ strncpy(b,ieee->current_network.ssid,len); ++ wrqu->essid.flags = 1; ++ ++out: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ return ret; ++ ++} ++ ++int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ u32 target_rate = wrqu->bitrate.value; ++ ++ ieee->rate = target_rate/100000; ++ //FIXME: we might want to limit rate also in management protocols. ++ return 0; ++} ++ ++ ++ ++int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 tmp_rate; ++#if 0 ++ printk("===>mode:%d, halfNmode:%d\n", ieee->mode, ieee->bHalfWirelessN24GMode); ++ if (ieee->mode & (IEEE_A | IEEE_B | IEEE_G)) ++ tmp_rate = ieee->rate; ++ else if (ieee->mode & IEEE_N_5G) ++ tmp_rate = 580; ++ else if (ieee->mode & IEEE_N_24G) ++ { ++ if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) ++ tmp_rate = HTHalfMcsToDataRate(ieee, 15); ++ else ++ tmp_rate = HTMcsToDataRate(ieee, 15); ++ } ++#else ++ tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate); ++ ++#endif ++ wrqu->bitrate.value = tmp_rate * 500000; ++ ++ return 0; ++} ++ ++ ++int ieee80211_wx_set_rts(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ if (wrqu->rts.disabled || !wrqu->rts.fixed) ++ ieee->rts = DEFAULT_RTS_THRESHOLD; ++ else ++ { ++ if (wrqu->rts.value < MIN_RTS_THRESHOLD || ++ wrqu->rts.value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ ieee->rts = wrqu->rts.value; ++ } ++ return 0; ++} ++ ++int ieee80211_wx_get_rts(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wrqu->rts.value = ieee->rts; ++ wrqu->rts.fixed = 0; /* no auto select */ ++ wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); ++ return 0; ++} ++int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ ++ if (wrqu->mode == ieee->iw_mode) ++ goto out; ++ ++ if (wrqu->mode == IW_MODE_MONITOR){ ++ ++ ieee->dev->type = ARPHRD_IEEE80211; ++ }else{ ++ ieee->dev->type = ARPHRD_ETHER; ++ } ++ ++ if (!ieee->proto_started){ ++ ieee->iw_mode = wrqu->mode; ++ }else{ ++ ieee80211_stop_protocol(ieee); ++ ieee->iw_mode = wrqu->mode; ++ ieee80211_start_protocol(ieee); ++ } ++ ++out: ++ up(&ieee->wx_sem); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void ieee80211_wx_sync_scan_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); ++#else ++void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ short chan; ++ HT_EXTCHNL_OFFSET chan_offset=0; ++ HT_CHANNEL_WIDTH bandwidth=0; ++ int b40M = 0; ++ static int count = 0; ++ chan = ieee->current_network.channel; ++ netif_carrier_off(ieee->dev); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_send_beacons(ieee); ++ ++ ieee->state = IEEE80211_LINKED_SCANNING; ++ ieee->link_change(ieee->dev); ++ ieee->InitialGainHandler(ieee->dev,IG_Backup); ++ if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) { ++ b40M = 1; ++ chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset; ++ bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz; ++ printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth); ++ ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ } ++ ieee80211_start_scan_syncro(ieee); ++ if (b40M) { ++ printk("Scan in 20M, back to 40M\n"); ++ if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) ++ ieee->set_chan(ieee->dev, chan + 2); ++ else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) ++ ieee->set_chan(ieee->dev, chan - 2); ++ else ++ ieee->set_chan(ieee->dev, chan); ++ ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset); ++ } else { ++ ieee->set_chan(ieee->dev, chan); ++ } ++ ++ ieee->InitialGainHandler(ieee->dev,IG_Restore); ++ ieee->state = IEEE80211_LINKED; ++ ieee->link_change(ieee->dev); ++ // To prevent the immediately calling watch_dog after scan. ++ if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 ) ++ { ++ ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; ++ ieee->LinkDetectInfo.NumRecvDataInPeriod= 1; ++ } ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) ++ ieee80211_start_send_beacons(ieee); ++ ++ netif_carrier_on(ieee->dev); ++ count = 0; ++ up(&ieee->wx_sem); ++ ++} ++ ++int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret = 0; ++ ++ down(&ieee->wx_sem); ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ ++ ret = -1; ++ goto out; ++ } ++ ++ if ( ieee->state == IEEE80211_LINKED){ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->wx_sync_scan_wq); ++#else ++ schedule_task(&ieee->wx_sync_scan_wq); ++#endif ++ /* intentionally forget to up sem */ ++ return 0; ++ } ++ ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret=0,len; ++ short proto_started; ++ unsigned long flags; ++ ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ++ proto_started = ieee->proto_started; ++ ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ ++ ret= -E2BIG; ++ goto out; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR){ ++ ret= -1; ++ goto out; ++ } ++ ++ if(proto_started) ++ ieee80211_stop_protocol(ieee); ++ ++ ++ /* this is just to be sure that the GET wx callback ++ * has consisten infos. not needed otherwise ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (wrqu->essid.flags && wrqu->essid.length) { ++ //first flush current network.ssid ++ len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ strncpy(ieee->current_network.ssid, extra, len); ++ ieee->current_network.ssid_len = len; ++#if 0 ++ { ++ int i; ++ for (i=0; icurrent_network.ssid, extra, len+1); ++ ieee->current_network.ssid_len = len+1; ++#if 0 ++ { ++ int i; ++ for (i=0; issid_set = 1; ++ } ++ else{ ++ ieee->ssid_set = 0; ++ ieee->current_network.ssid[0] = '\0'; ++ ieee->current_network.ssid_len = 0; ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ if (proto_started) ++ ieee80211_start_protocol(ieee); ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ wrqu->mode = ieee->iw_mode; ++ return 0; ++} ++ ++ int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int *parms = (int *)extra; ++ int enable = (parms[0] > 0); ++ short prev = ieee->raw_tx; ++ ++ down(&ieee->wx_sem); ++ ++ if(enable) ++ ieee->raw_tx = 1; ++ else ++ ieee->raw_tx = 0; ++ ++ printk(KERN_INFO"raw TX is %s\n", ++ ieee->raw_tx ? "enabled" : "disabled"); ++ ++ if(ieee->iw_mode == IW_MODE_MONITOR) ++ { ++ if(prev == 0 && ieee->raw_tx){ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } ++ ++ if(prev && ieee->raw_tx == 1) ++ netif_carrier_off(ieee->dev); ++ } ++ ++ up(&ieee->wx_sem); ++ ++ return 0; ++} ++ ++int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ strcpy(wrqu->name, "802.11"); ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ strcat(wrqu->name, "b"); ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(wrqu->name, "/g"); ++ }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(wrqu->name, "g"); ++ if (ieee->mode & (IEEE_N_24G | IEEE_N_5G)) ++ strcat(wrqu->name, "/n"); ++ ++ if((ieee->state == IEEE80211_LINKED) || ++ (ieee->state == IEEE80211_LINKED_SCANNING)) ++ strcat(wrqu->name," linked"); ++ else if(ieee->state != IEEE80211_NOLINK) ++ strcat(wrqu->name," link.."); ++ ++ ++ return 0; ++} ++ ++ ++/* this is mostly stolen from hostap */ ++int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++#if 1 ++ if( ++ (!ieee->sta_wake_up) || ++ // (!ieee->ps_request_tx_ack) || ++ (!ieee->enter_sleep_state) || ++ (!ieee->ps_is_queue_empty)){ ++ ++ // printk("ERROR. PS mode is tryied to be use but driver missed a callback\n\n"); ++ ++ return -1; ++ } ++#endif ++ down(&ieee->wx_sem); ++ ++ if (wrqu->power.disabled){ ++ ieee->ps = IEEE80211_PS_DISABLED; ++ goto exit; ++ } ++ if (wrqu->power.flags & IW_POWER_TIMEOUT) { ++ //ieee->ps_period = wrqu->power.value / 1000; ++ ieee->ps_timeout = wrqu->power.value / 1000; ++ } ++ ++ if (wrqu->power.flags & IW_POWER_PERIOD) { ++ ++ //ieee->ps_timeout = wrqu->power.value / 1000; ++ ieee->ps_period = wrqu->power.value / 1000; ++ //wrq->value / 1024; ++ ++ } ++ switch (wrqu->power.flags & IW_POWER_MODE) { ++ case IW_POWER_UNICAST_R: ++ ieee->ps = IEEE80211_PS_UNICAST; ++ break; ++ case IW_POWER_MULTICAST_R: ++ ieee->ps = IEEE80211_PS_MBCAST; ++ break; ++ case IW_POWER_ALL_R: ++ ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; ++ break; ++ ++ case IW_POWER_ON: ++ // ieee->ps = IEEE80211_PS_DISABLED; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ goto exit; ++ ++ } ++exit: ++ up(&ieee->wx_sem); ++ return ret; ++ ++} ++ ++/* this is stolen from hostap */ ++int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret =0; ++ ++ down(&ieee->wx_sem); ++ ++ if(ieee->ps == IEEE80211_PS_DISABLED){ ++ wrqu->power.disabled = 1; ++ goto exit; ++ } ++ ++ wrqu->power.disabled = 0; ++ ++ if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { ++ wrqu->power.flags = IW_POWER_TIMEOUT; ++ wrqu->power.value = ieee->ps_timeout * 1000; ++ } else { ++// ret = -EOPNOTSUPP; ++// goto exit; ++ wrqu->power.flags = IW_POWER_PERIOD; ++ wrqu->power.value = ieee->ps_period * 1000; ++//ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024; ++ } ++ ++ if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) ++ wrqu->power.flags |= IW_POWER_ALL_R; ++ else if (ieee->ps & IEEE80211_PS_MBCAST) ++ wrqu->power.flags |= IW_POWER_MULTICAST_R; ++ else ++ wrqu->power.flags |= IW_POWER_UNICAST_R; ++ ++exit: ++ up(&ieee->wx_sem); ++ return ret; ++ ++} ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_wx_get_essid); ++//EXPORT_SYMBOL(ieee80211_wx_set_essid); ++//EXPORT_SYMBOL(ieee80211_wx_set_rate); ++//EXPORT_SYMBOL(ieee80211_wx_get_rate); ++//EXPORT_SYMBOL(ieee80211_wx_set_wap); ++//EXPORT_SYMBOL(ieee80211_wx_get_wap); ++//EXPORT_SYMBOL(ieee80211_wx_set_mode); ++//EXPORT_SYMBOL(ieee80211_wx_get_mode); ++//EXPORT_SYMBOL(ieee80211_wx_set_scan); ++//EXPORT_SYMBOL(ieee80211_wx_get_freq); ++//EXPORT_SYMBOL(ieee80211_wx_set_freq); ++//EXPORT_SYMBOL(ieee80211_wx_set_rawtx); ++//EXPORT_SYMBOL(ieee80211_wx_get_name); ++//EXPORT_SYMBOL(ieee80211_wx_set_power); ++//EXPORT_SYMBOL(ieee80211_wx_get_power); ++//EXPORT_SYMBOL(ieee80211_wlan_frequencies); ++//EXPORT_SYMBOL(ieee80211_wx_set_rts); ++//EXPORT_SYMBOL(ieee80211_wx_get_rts); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_essid); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_essid); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rate); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rate); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_wap); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_wap); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mode); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_mode); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_scan); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_freq); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_freq); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rawtx); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_name); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_power); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_power); ++EXPORT_SYMBOL_NOVERS(ieee80211_wlan_frequencies); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_rts); ++EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_rts); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c +@@ -0,0 +1,933 @@ ++/****************************************************************************** ++ ++ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., 59 ++ Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++****************************************************************************** ++ ++ Few modifications for Realtek's Wi-Fi drivers by ++ Andrea Merello ++ ++ A special thanks goes to Realtek for their support ! ++ ++******************************************************************************/ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++ ++/* ++ ++ ++802.11 Data Frame ++ ++ ++802.11 frame_contorl for data frames - 2 bytes ++ ,-----------------------------------------------------------------------------------------. ++bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | ++ |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| ++val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | ++ |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| ++desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | ++ | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | ++ '-----------------------------------------------------------------------------------------' ++ /\ ++ | ++802.11 Data Frame | ++ ,--------- 'ctrl' expands to >-----------' ++ | ++ ,--'---,-------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `--------------------------------------------------| |------' ++Total: 28 non-data bytes `----.----' ++ | ++ .- 'Frame data' expands to <---------------------------' ++ | ++ V ++ ,---------------------------------------------------. ++Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | ++ |------|------|---------|----------|------|---------| ++Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | ++ | DSAP | SSAP | | | | Packet | ++ | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | ++ `-----------------------------------------| | ++Total: 8 non-data bytes `----.----' ++ | ++ .- 'IP Packet' expands, if WEP enabled, to <--' ++ | ++ V ++ ,-----------------------. ++Bytes | 4 | 0-2296 | 4 | ++ |-----|-----------|-----| ++Desc. | IV | Encrypted | ICV | ++ | | IP Packet | | ++ `-----------------------' ++Total: 8 non-data bytes ++ ++ ++802.3 Ethernet Data Frame ++ ++ ,-----------------------------------------. ++Bytes | 6 | 6 | 2 | Variable | 4 | ++ |-------|-------|------|-----------|------| ++Desc. | Dest. | Source| Type | IP Packet | fcs | ++ | MAC | MAC | | | | ++ `-----------------------------------------' ++Total: 18 non-data bytes ++ ++In the event that fragmentation is required, the incoming payload is split into ++N parts of size ieee->fts. The first fragment contains the SNAP header and the ++remaining packets are just data. ++ ++If encryption is enabled, each fragment payload size is reduced by enough space ++to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) ++So if you have 1500 bytes of payload with ieee->fts set to 500 without ++encryption it will take 3 frames. With WEP it will take 4 frames as the ++payload of each frame is reduced to 492 bytes. ++ ++* SKB visualization ++* ++* ,- skb->data ++* | ++* | ETHERNET HEADER ,-<-- PAYLOAD ++* | | 14 bytes from skb->data ++* | 2 bytes for Type --> ,T. | (sizeof ethhdr) ++* | | | | ++* |,-Dest.--. ,--Src.---. | | | ++* | 6 bytes| | 6 bytes | | | | ++* v | | | | | | ++* 0 | v 1 | v | v 2 ++* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ++* ^ | ^ | ^ | ++* | | | | | | ++* | | | | `T' <---- 2 bytes for Type ++* | | | | ++* | | '---SNAP--' <-------- 6 bytes for SNAP ++* | | ++* `-IV--' <-------------------- 4 bytes for IV (WEP) ++* ++* SNAP HEADER ++* ++*/ ++ ++static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; ++static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; ++ ++static inline int ieee80211_put_snap(u8 *data, u16 h_proto) ++{ ++ struct ieee80211_snap_hdr *snap; ++ u8 *oui; ++ ++ snap = (struct ieee80211_snap_hdr *)data; ++ snap->dsap = 0xaa; ++ snap->ssap = 0xaa; ++ snap->ctrl = 0x03; ++ ++ if (h_proto == 0x8137 || h_proto == 0x80f3) ++ oui = P802_1H_OUI; ++ else ++ oui = RFC1042_OUI; ++ snap->oui[0] = oui[0]; ++ snap->oui[1] = oui[1]; ++ snap->oui[2] = oui[2]; ++ ++ *(u16 *)(data + SNAP_SIZE) = htons(h_proto); ++ ++ return SNAP_SIZE + sizeof(u16); ++} ++ ++int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len) ++{ ++ struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; ++ int res; ++ ++ if (!(crypt && crypt->ops)) ++ { ++ printk("=========>%s(), crypt is null\n", __FUNCTION__); ++ return -1; ++ } ++#ifdef CONFIG_IEEE80211_CRYPT_TKIP ++ struct ieee80211_hdr *header; ++ ++ if (ieee->tkip_countermeasures && ++ crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { ++ header = (struct ieee80211_hdr *) frag->data; ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ++ "TX packet to " MAC_FMT "\n", ++ ieee->dev->name, MAC_ARG(header->addr1)); ++ } ++ return -1; ++ } ++#endif ++ /* To encrypt, frame format is: ++ * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ ++ ++ // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. ++ /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so ++ * call both MSDU and MPDU encryption functions from here. */ ++ atomic_inc(&crypt->refcnt); ++ res = 0; ++ if (crypt->ops->encrypt_msdu) ++ res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); ++ if (res == 0 && crypt->ops->encrypt_mpdu) ++ res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); ++ ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ printk(KERN_INFO "%s: Encryption failed: len=%d.\n", ++ ieee->dev->name, frag->len); ++ ieee->ieee_stats.tx_discards++; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++void ieee80211_txb_free(struct ieee80211_txb *txb) { ++ //int i; ++ if (unlikely(!txb)) ++ return; ++#if 0 ++ for (i = 0; i < txb->nr_frags; i++) ++ if (txb->fragments[i]) ++ dev_kfree_skb_any(txb->fragments[i]); ++#endif ++ kfree(txb); ++} ++ ++struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, ++ int gfp_mask) ++{ ++ struct ieee80211_txb *txb; ++ int i; ++ txb = kmalloc( ++ sizeof(struct ieee80211_txb) + (sizeof(u8*) * nr_frags), ++ gfp_mask); ++ if (!txb) ++ return NULL; ++ ++ memset(txb, 0, sizeof(struct ieee80211_txb)); ++ txb->nr_frags = nr_frags; ++ txb->frag_size = txb_size; ++ ++ for (i = 0; i < nr_frags; i++) { ++ txb->fragments[i] = dev_alloc_skb(txb_size); ++ if (unlikely(!txb->fragments[i])) { ++ i--; ++ break; ++ } ++ memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb)); ++ } ++ if (unlikely(i != nr_frags)) { ++ while (i >= 0) ++ dev_kfree_skb_any(txb->fragments[i--]); ++ kfree(txb); ++ return NULL; ++ } ++ return txb; ++} ++ ++// Classify the to-be send data packet ++// Need to acquire the sent queue index. ++static int ++ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) ++{ ++ struct ethhdr *eth; ++ struct iphdr *ip; ++ eth = (struct ethhdr *)skb->data; ++ if (eth->h_proto != htons(ETH_P_IP)) ++ return 0; ++ ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, skb->data, skb->len); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)) ++ ip = ip_hdr(skb); ++#else ++ ip = (struct iphdr*)(skb->data + sizeof(struct ether_header)); ++#endif ++ switch (ip->tos & 0xfc) { ++ case 0x20: ++ return 2; ++ case 0x40: ++ return 1; ++ case 0x60: ++ return 3; ++ case 0x80: ++ return 4; ++ case 0xa0: ++ return 5; ++ case 0xc0: ++ return 6; ++ case 0xe0: ++ return 7; ++ default: ++ return 0; ++ } ++} ++ ++#define SN_LESS(a, b) (((a-b)&0x800)!=0) ++void ieee80211_tx_query_agg_cap(struct ieee80211_device* ieee, struct sk_buff* skb, cb_desc* tcb_desc) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ PTX_TS_RECORD pTxTs = NULL; ++ struct ieee80211_hdr_1addr* hdr = (struct ieee80211_hdr_1addr*)skb->data; ++ ++ if (!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT) ++ return; ++ if (!IsQoSDataFrame(skb->data)) ++ return; ++ ++ if (is_multicast_ether_addr(hdr->addr1) || is_broadcast_ether_addr(hdr->addr1)) ++ return; ++ //check packet and mode later ++#ifdef TO_DO_LIST ++ if(pTcb->PacketLength >= 4096) ++ return; ++ // For RTL819X, if pairwisekey = wep/tkip, we don't aggrregation. ++ if(!Adapter->HalFunc.GetNmodeSupportBySecCfgHandler(Adapter)) ++ return; ++#endif ++#if 1 ++ if(!ieee->GetNmodeSupportBySecCfg(ieee->dev)) ++ { ++ return; ++ } ++#endif ++ if(pHTInfo->bCurrentAMPDUEnable) ++ { ++ if (!GetTs(ieee, (PTS_COMMON_INFO*)(&pTxTs), hdr->addr1, skb->priority, TX_DIR, true)) ++ { ++ printk("===>can't get TS\n"); ++ return; ++ } ++ if (pTxTs->TxAdmittedBARecord.bValid == false) ++ { ++ //as some AP will refuse our action frame until key handshake has been finished. WB ++ if (ieee->wpa_ie_len && (ieee->pairwise_key_type == KEY_TYPE_NA)) ++ ; ++ else ++ TsStartAddBaProcess(ieee, pTxTs); ++ goto FORCED_AGG_SETTING; ++ } ++ else if (pTxTs->bUsingBa == false) ++ { ++ if (SN_LESS(pTxTs->TxAdmittedBARecord.BaStartSeqCtrl.field.SeqNum, (pTxTs->TxCurSeq+1)%4096)) ++ pTxTs->bUsingBa = true; ++ else ++ goto FORCED_AGG_SETTING; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_INFRA) ++ { ++ tcb_desc->bAMPDUEnable = true; ++ tcb_desc->ampdu_factor = pHTInfo->CurrentAMPDUFactor; ++ tcb_desc->ampdu_density = pHTInfo->CurrentMPDUDensity; ++ } ++ } ++FORCED_AGG_SETTING: ++ switch(pHTInfo->ForcedAMPDUMode ) ++ { ++ case HT_AGG_AUTO: ++ break; ++ ++ case HT_AGG_FORCE_ENABLE: ++ tcb_desc->bAMPDUEnable = true; ++ tcb_desc->ampdu_density = pHTInfo->ForcedMPDUDensity; ++ tcb_desc->ampdu_factor = pHTInfo->ForcedAMPDUFactor; ++ break; ++ ++ case HT_AGG_FORCE_DISABLE: ++ tcb_desc->bAMPDUEnable = false; ++ tcb_desc->ampdu_density = 0; ++ tcb_desc->ampdu_factor = 0; ++ break; ++ ++ } ++ return; ++} ++ ++extern void ieee80211_qurey_ShortPreambleMode(struct ieee80211_device* ieee, cb_desc* tcb_desc) ++{ ++ tcb_desc->bUseShortPreamble = false; ++ if (tcb_desc->data_rate == 2) ++ {//// 1M can only use Long Preamble. 11B spec ++ return; ++ } ++ else if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ { ++ tcb_desc->bUseShortPreamble = true; ++ } ++ return; ++} ++extern void ++ieee80211_query_HTCapShortGI(struct ieee80211_device *ieee, cb_desc *tcb_desc) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ tcb_desc->bUseShortGI = false; ++ ++ if(!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT) ++ return; ++ ++ if(pHTInfo->bForcedShortGI) ++ { ++ tcb_desc->bUseShortGI = true; ++ return; ++ } ++ ++ if((pHTInfo->bCurBW40MHz==true) && pHTInfo->bCurShortGI40MHz) ++ tcb_desc->bUseShortGI = true; ++ else if((pHTInfo->bCurBW40MHz==false) && pHTInfo->bCurShortGI20MHz) ++ tcb_desc->bUseShortGI = true; ++} ++ ++void ieee80211_query_BandwidthMode(struct ieee80211_device* ieee, cb_desc *tcb_desc) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ tcb_desc->bPacketBW = false; ++ ++ if(!pHTInfo->bCurrentHTSupport||!pHTInfo->bEnableHT) ++ return; ++ ++ if(tcb_desc->bMulticast || tcb_desc->bBroadcast) ++ return; ++ ++ if((tcb_desc->data_rate & 0x80)==0) // If using legacy rate, it shall use 20MHz channel. ++ return; ++ //BandWidthAutoSwitch is for auto switch to 20 or 40 in long distance ++ if(pHTInfo->bCurBW40MHz && pHTInfo->bCurTxBW40MHz && !ieee->bandwidth_auto_switch.bforced_tx20Mhz) ++ tcb_desc->bPacketBW = true; ++ return; ++} ++ ++void ieee80211_query_protectionmode(struct ieee80211_device* ieee, cb_desc* tcb_desc, struct sk_buff* skb) ++{ ++ // Common Settings ++ tcb_desc->bRTSSTBC = false; ++ tcb_desc->bRTSUseShortGI = false; // Since protection frames are always sent by legacy rate, ShortGI will never be used. ++ tcb_desc->bCTSEnable = false; // Most of protection using RTS/CTS ++ tcb_desc->RTSSC = 0; // 20MHz: Don't care; 40MHz: Duplicate. ++ tcb_desc->bRTSBW = false; // RTS frame bandwidth is always 20MHz ++ ++ if(tcb_desc->bBroadcast || tcb_desc->bMulticast)//only unicast frame will use rts/cts ++ return; ++ ++ if (is_broadcast_ether_addr(skb->data+16)) //check addr3 as infrastructure add3 is DA. ++ return; ++ ++ if (ieee->mode < IEEE_N_24G) //b, g mode ++ { ++ // (1) RTS_Threshold is compared to the MPDU, not MSDU. ++ // (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. ++ // Other fragments are protected by previous fragment. ++ // So we only need to check the length of first fragment. ++ if (skb->len > ieee->rts) ++ { ++ tcb_desc->bRTSEnable = true; ++ tcb_desc->rts_rate = MGN_24M; ++ } ++ else if (ieee->current_network.buseprotection) ++ { ++ // Use CTS-to-SELF in protection mode. ++ tcb_desc->bRTSEnable = true; ++ tcb_desc->bCTSEnable = true; ++ tcb_desc->rts_rate = MGN_24M; ++ } ++ //otherwise return; ++ return; ++ } ++ else ++ {// 11n High throughput case. ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ while (true) ++ { ++ //check ERP protection ++ if (ieee->current_network.buseprotection) ++ {// CTS-to-SELF ++ tcb_desc->bRTSEnable = true; ++ tcb_desc->bCTSEnable = true; ++ tcb_desc->rts_rate = MGN_24M; ++ break; ++ } ++ //check HT op mode ++ if(pHTInfo->bCurrentHTSupport && pHTInfo->bEnableHT) ++ { ++ u8 HTOpMode = pHTInfo->CurrentOpMode; ++ if((pHTInfo->bCurBW40MHz && (HTOpMode == 2 || HTOpMode == 3)) || ++ (!pHTInfo->bCurBW40MHz && HTOpMode == 3) ) ++ { ++ tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps. ++ tcb_desc->bRTSEnable = true; ++ break; ++ } ++ } ++ //check rts ++ if (skb->len > ieee->rts) ++ { ++ tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps. ++ tcb_desc->bRTSEnable = true; ++ break; ++ } ++ //to do list: check MIMO power save condition. ++ //check AMPDU aggregation for TXOP ++ if(tcb_desc->bAMPDUEnable) ++ { ++ tcb_desc->rts_rate = MGN_24M; // Rate is 24Mbps. ++ // According to 8190 design, firmware sends CF-End only if RTS/CTS is enabled. However, it degrads ++ // throughput around 10M, so we disable of this mechanism. 2007.08.03 by Emily ++ tcb_desc->bRTSEnable = false; ++ break; ++ } ++ //check IOT action ++ if(pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) ++ { ++ tcb_desc->bCTSEnable = true; ++ tcb_desc->rts_rate = MGN_24M; ++ tcb_desc->bRTSEnable = true; ++ break; ++ } ++ // Totally no protection case!! ++ goto NO_PROTECTION; ++ } ++ } ++ // For test , CTS replace with RTS ++ if( 0 ) ++ { ++ tcb_desc->bCTSEnable = true; ++ tcb_desc->rts_rate = MGN_24M; ++ tcb_desc->bRTSEnable = true; ++ } ++ if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ tcb_desc->bUseShortPreamble = true; ++ if (ieee->mode == IW_MODE_MASTER) ++ goto NO_PROTECTION; ++ return; ++NO_PROTECTION: ++ tcb_desc->bRTSEnable = false; ++ tcb_desc->bCTSEnable = false; ++ tcb_desc->rts_rate = 0; ++ tcb_desc->RTSSC = 0; ++ tcb_desc->bRTSBW = false; ++} ++ ++ ++void ieee80211_txrate_selectmode(struct ieee80211_device* ieee, cb_desc* tcb_desc) ++{ ++#ifdef TO_DO_LIST ++ if(!IsDataFrame(pFrame)) ++ { ++ pTcb->bTxDisableRateFallBack = TRUE; ++ pTcb->bTxUseDriverAssingedRate = TRUE; ++ pTcb->RATRIndex = 7; ++ return; ++ } ++ ++ if(pMgntInfo->ForcedDataRate!= 0) ++ { ++ pTcb->bTxDisableRateFallBack = TRUE; ++ pTcb->bTxUseDriverAssingedRate = TRUE; ++ return; ++ } ++#endif ++ if(ieee->bTxDisableRateFallBack) ++ tcb_desc->bTxDisableRateFallBack = true; ++ ++ if(ieee->bTxUseDriverAssingedRate) ++ tcb_desc->bTxUseDriverAssingedRate = true; ++ if(!tcb_desc->bTxDisableRateFallBack || !tcb_desc->bTxUseDriverAssingedRate) ++ { ++ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) ++ tcb_desc->RATRIndex = 0; ++ } ++} ++ ++void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u8* dst) ++{ ++ if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) ++ return; ++ if (IsQoSDataFrame(skb->data)) //we deal qos data only ++ { ++ PTX_TS_RECORD pTS = NULL; ++ if (!GetTs(ieee, (PTS_COMMON_INFO*)(&pTS), dst, skb->priority, TX_DIR, true)) ++ { ++ return; ++ } ++ pTS->TxCurSeq = (pTS->TxCurSeq+1)%4096; ++ } ++} ++ ++int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addrqos *frag_hdr; ++ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; ++ unsigned long flags; ++ struct net_device_stats *stats = &ieee->stats; ++ int ether_type = 0, encrypt; ++ int bytes, fc, qos_ctl = 0, hdr_len; ++ struct sk_buff *skb_frag; ++ struct ieee80211_hdr_3addrqos header = { /* Ensure zero initialized */ ++ .duration_id = 0, ++ .seq_ctl = 0, ++ .qos_ctl = 0 ++ }; ++ u8 dest[ETH_ALEN], src[ETH_ALEN]; ++ int qos_actived = ieee->current_network.qos_data.active; ++ ++ struct ieee80211_crypt_data* crypt; ++ ++ cb_desc *tcb_desc; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ /* If there is no driver handler to take the TXB, dont' bother ++ * creating it... */ ++ if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))|| ++ ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { ++ printk(KERN_WARNING "%s: No xmit handler.\n", ++ ieee->dev->name); ++ goto success; ++ } ++ ++ ++ if(likely(ieee->raw_tx == 0)){ ++ if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { ++ printk(KERN_WARNING "%s: skb too small (%d).\n", ++ ieee->dev->name, skb->len); ++ goto success; ++ } ++ ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ ++ encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ++ ieee->host_encrypt && crypt && crypt->ops; ++ ++ if (!encrypt && ieee->ieee802_1x && ++ ieee->drop_unencrypted && ether_type != ETH_P_PAE) { ++ stats->tx_dropped++; ++ goto success; ++ } ++ #ifdef CONFIG_IEEE80211_DEBUG ++ if (crypt && !encrypt && ether_type == ETH_P_PAE) { ++ struct eapol *eap = (struct eapol *)(skb->data + ++ sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16)); ++ IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++ } ++ #endif ++ ++ /* Save source and destination addresses */ ++ memcpy(&dest, skb->data, ETH_ALEN); ++ memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ if (encrypt) ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_WEP; ++ else ++ ++ fc = IEEE80211_FTYPE_DATA; ++ ++ //if(ieee->current_network.QoS_Enable) ++ if(qos_actived) ++ fc |= IEEE80211_STYPE_QOS_DATA; ++ else ++ fc |= IEEE80211_STYPE_DATA; ++ ++ if (ieee->iw_mode == IW_MODE_INFRA) { ++ fc |= IEEE80211_FCTL_TODS; ++ /* To DS: Addr1 = BSSID, Addr2 = SA, ++ Addr3 = DA */ ++ memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN); ++ memcpy(&header.addr2, &src, ETH_ALEN); ++ memcpy(&header.addr3, &dest, ETH_ALEN); ++ } else if (ieee->iw_mode == IW_MODE_ADHOC) { ++ /* not From/To DS: Addr1 = DA, Addr2 = SA, ++ Addr3 = BSSID */ ++ memcpy(&header.addr1, dest, ETH_ALEN); ++ memcpy(&header.addr2, src, ETH_ALEN); ++ memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ } ++ ++ header.frame_ctl = cpu_to_le16(fc); ++ ++ /* Determine fragmentation size based on destination (multicast ++ * and broadcast are not fragmented) */ ++ if (is_multicast_ether_addr(header.addr1) || ++ is_broadcast_ether_addr(header.addr1)) { ++ frag_size = MAX_FRAG_THRESHOLD; ++ qos_ctl |= QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ frag_size = ieee->fts;//default:392 ++ qos_ctl = 0; ++ } ++ ++ //if (ieee->current_network.QoS_Enable) ++ if(qos_actived) ++ { ++ hdr_len = IEEE80211_3ADDR_LEN + 2; ++ ++ skb->priority = ieee80211_classify(skb, &ieee->current_network); ++ qos_ctl |= skb->priority; //set in the ieee80211_classify ++ header.qos_ctl = cpu_to_le16(qos_ctl & IEEE80211_QOS_TID); ++ } else { ++ hdr_len = IEEE80211_3ADDR_LEN; ++ } ++ /* Determine amount of payload per fragment. Regardless of if ++ * this stack is providing the full 802.11 header, one will ++ * eventually be affixed to this fragment -- so we must account for ++ * it when determining the amount of payload space. */ ++ bytes_per_frag = frag_size - hdr_len; ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ bytes_per_frag -= IEEE80211_FCS_LEN; ++ ++ /* Each fragment may need to have room for encryptiong pre/postfix */ ++ if (encrypt) ++ bytes_per_frag -= crypt->ops->extra_prefix_len + ++ crypt->ops->extra_postfix_len; ++ ++ /* Number of fragments is the total bytes_per_frag / ++ * payload_per_fragment */ ++ nr_frags = bytes / bytes_per_frag; ++ bytes_last_frag = bytes % bytes_per_frag; ++ if (bytes_last_frag) ++ nr_frags++; ++ else ++ bytes_last_frag = bytes_per_frag; ++ ++ /* When we allocate the TXB we allocate enough space for the reserve ++ * and full fragment bytes (bytes_per_frag doesn't include prefix, ++ * postfix, header, FCS, etc.) */ ++ txb = ieee80211_alloc_txb(nr_frags, frag_size + ieee->tx_headroom, GFP_ATOMIC); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ goto failed; ++ } ++ txb->encrypted = encrypt; ++ txb->payload_size = bytes; ++ ++ //if (ieee->current_network.QoS_Enable) ++ if(qos_actived) ++ { ++ txb->queue_index = UP2AC(skb->priority); ++ } else { ++ txb->queue_index = WME_AC_BK;; ++ } ++ ++ ++ ++ for (i = 0; i < nr_frags; i++) { ++ skb_frag = txb->fragments[i]; ++ tcb_desc = (cb_desc *)(skb_frag->cb + MAX_DEV_ADDR_SIZE); ++ if(qos_actived){ ++ skb_frag->priority = skb->priority;//UP2AC(skb->priority); ++ tcb_desc->queue_index = UP2AC(skb->priority); ++ } else { ++ skb_frag->priority = WME_AC_BK; ++ tcb_desc->queue_index = WME_AC_BK; ++ } ++ skb_reserve(skb_frag, ieee->tx_headroom); ++ ++ if (encrypt){ ++ if (ieee->hwsec_active) ++ tcb_desc->bHwSec = 1; ++ else ++ tcb_desc->bHwSec = 0; ++ skb_reserve(skb_frag, crypt->ops->extra_prefix_len); ++ } ++ else ++ { ++ tcb_desc->bHwSec = 0; ++ } ++ frag_hdr = (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); ++ memcpy(frag_hdr, &header, hdr_len); ++ ++ /* If this is not the last fragment, then add the MOREFRAGS ++ * bit to the frame control */ ++ if (i != nr_frags - 1) { ++ frag_hdr->frame_ctl = cpu_to_le16( ++ fc | IEEE80211_FCTL_MOREFRAGS); ++ bytes = bytes_per_frag; ++ ++ } else { ++ /* The last fragment takes the remaining length */ ++ bytes = bytes_last_frag; ++ } ++ //if(ieee->current_network.QoS_Enable) ++ if(qos_actived) ++ { ++ // add 1 only indicate to corresponding seq number control 2006/7/12 ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i); ++ } else { ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); ++ } ++ ++ /* Put a SNAP header on the first fragment */ ++ if (i == 0) { ++ ieee80211_put_snap( ++ skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ++ ether_type); ++ bytes -= SNAP_SIZE + sizeof(u16); ++ } ++ ++ memcpy(skb_put(skb_frag, bytes), skb->data, bytes); ++ ++ /* Advance the SKB... */ ++ skb_pull(skb, bytes); ++ ++ /* Encryption routine will move the header forward in order ++ * to insert the IV between the header and the payload */ ++ if (encrypt) ++ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ skb_put(skb_frag, 4); ++ } ++ ++ if(qos_actived) ++ { ++ if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) ++ ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; ++ else ++ ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; ++ } else { ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ } ++ }else{ ++ if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) { ++ printk(KERN_WARNING "%s: skb too small (%d).\n", ++ ieee->dev->name, skb->len); ++ goto success; ++ } ++ ++ txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC); ++ if(!txb){ ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ goto failed; ++ } ++ ++ txb->encrypted = 0; ++ txb->payload_size = skb->len; ++ memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len); ++ } ++ ++ success: ++//WB add to fill data tcb_desc here. only first fragment is considered, need to change, and you may remove to other place. ++ if (txb) ++ { ++#if 1 ++ cb_desc *tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); ++ tcb_desc->bTxEnableFwCalcDur = 1; ++ if (is_multicast_ether_addr(header.addr1)) ++ tcb_desc->bMulticast = 1; ++ if (is_broadcast_ether_addr(header.addr1)) ++ tcb_desc->bBroadcast = 1; ++ ieee80211_txrate_selectmode(ieee, tcb_desc); ++ if ( tcb_desc->bMulticast || tcb_desc->bBroadcast) ++ tcb_desc->data_rate = ieee->basic_rate; ++ else ++ //tcb_desc->data_rate = CURRENT_RATE(ieee->current_network.mode, ieee->rate, ieee->HTCurrentOperaRate); ++ tcb_desc->data_rate = CURRENT_RATE(ieee->mode, ieee->rate, ieee->HTCurrentOperaRate); ++ ieee80211_qurey_ShortPreambleMode(ieee, tcb_desc); ++ ieee80211_tx_query_agg_cap(ieee, txb->fragments[0], tcb_desc); ++ ieee80211_query_HTCapShortGI(ieee, tcb_desc); ++ ieee80211_query_BandwidthMode(ieee, tcb_desc); ++ ieee80211_query_protectionmode(ieee, tcb_desc, txb->fragments[0]); ++ ieee80211_query_seqnum(ieee, txb->fragments[0], header.addr1); ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, txb->fragments[0]->data, txb->fragments[0]->len); ++ //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, tcb_desc, sizeof(cb_desc)); ++#endif ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ dev_kfree_skb_any(skb); ++ if (txb) { ++ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){ ++ ieee80211_softmac_xmit(txb, ieee); ++ }else{ ++ if ((*ieee->hard_start_xmit)(txb, dev) == 0) { ++ stats->tx_packets++; ++ stats->tx_bytes += txb->payload_size; ++ return 0; ++ } ++ ieee80211_txb_free(txb); ++ } ++ } ++ ++ return 0; ++ ++ failed: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ netif_stop_queue(dev); ++ stats->tx_errors++; ++ return 1; ++ ++} ++ ++//EXPORT_SYMBOL(ieee80211_txb_free); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c +@@ -0,0 +1,1032 @@ ++/****************************************************************************** ++ ++ Copyright(c) 2004 Intel Corporation. All rights reserved. ++ ++ Portions of this file are based on the WEP enablement code provided by the ++ Host AP project hostap-drivers v0.1.3 ++ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ ++ Copyright (c) 2002-2003, Jouni Malinen ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., 59 ++ Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++******************************************************************************/ ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++#if 0 ++static const char *ieee80211_modes[] = { ++ "?", "a", "b", "ab", "g", "ag", "bg", "abg" ++}; ++#endif ++struct modes_unit { ++ char *mode_string; ++ int mode_size; ++}; ++struct modes_unit ieee80211_modes[] = { ++ {"a",1}, ++ {"b",1}, ++ {"g",1}, ++ {"?",1}, ++ {"N-24G",5}, ++ {"N-5G",4}, ++}; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++static inline char * ++iwe_stream_add_event_rsl(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ ndelay(1); //new ++ memcpy(stream, (char *) iwe, event_len); ++ stream += event_len; ++ } ++ return stream; ++} ++#else ++#define iwe_stream_add_event_rsl iwe_stream_add_event ++#endif ++ ++#define MAX_CUSTOM_LEN 64 ++static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, ++ char *start, char *stop, ++ struct ieee80211_network *network, ++ struct iw_request_info *info) ++{ ++ char custom[MAX_CUSTOM_LEN]; ++ char proto_name[IFNAMSIZ]; ++ char *pname = proto_name; ++ char *p; ++ struct iw_event iwe; ++ int i, j; ++ u16 max_rate, rate; ++ static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; ++ ++ /* First entry *MUST* be the AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN); ++#else ++ start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_ADDR_LEN); ++#endif ++ /* Remaining entries will be displayed in the order we provide them */ ++ ++ /* Add the ESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++// if (network->flags & NETWORK_EMPTY_ESSID) { ++ if (network->ssid_len == 0) { ++ iwe.u.data.length = sizeof(""); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, ""); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, ""); ++#endif ++ } else { ++ iwe.u.data.length = min(network->ssid_len, (u8)32); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, network->ssid); ++#endif ++ } ++ /* Add the protocol name */ ++ iwe.cmd = SIOCGIWNAME; ++ for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) { ++ if(network->mode&(1<= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN); ++#else ++ start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_CHAR_LEN); ++#endif ++ /* Add mode */ ++ iwe.cmd = SIOCGIWMODE; ++ if (network->capability & ++ (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { ++ if (network->capability & WLAN_CAPABILITY_BSS) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN); ++#else ++ start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_UINT_LEN); ++#endif ++ } ++ ++ /* Add frequency/channel */ ++ iwe.cmd = SIOCGIWFREQ; ++/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); ++ iwe.u.freq.e = 3; */ ++ iwe.u.freq.m = network->channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN); ++#else ++ start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_FREQ_LEN); ++#endif ++ /* Add encryption capability */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (network->capability & WLAN_CAPABILITY_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, network->ssid); ++#endif ++ /* Add basic and extended rates */ ++ max_rate = 0; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); ++ for (i = 0, j = 0; i < network->rates_len; ) { ++ if (j < network->rates_ex_len && ++ ((network->rates_ex[j] & 0x7F) < ++ (network->rates[i] & 0x7F))) ++ rate = network->rates_ex[j++] & 0x7F; ++ else ++ rate = network->rates[i++] & 0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ } ++ for (; j < network->rates_ex_len; j++) { ++ rate = network->rates_ex[j] & 0x7F; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ if (rate > max_rate) ++ max_rate = rate; ++ } ++ ++ if (network->mode >= IEEE_N_24G)//add N rate here; ++ { ++ PHT_CAPABILITY_ELE ht_cap = NULL; ++ bool is40M = false, isShortGI = false; ++ u8 max_mcs = 0; ++ if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4)) ++ ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4]; ++ else ++ ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0]; ++ is40M = (ht_cap->ChlWidth)?1:0; ++ isShortGI = (ht_cap->ChlWidth)? ++ ((ht_cap->ShortGI40Mhz)?1:0): ++ ((ht_cap->ShortGI20Mhz)?1:0); ++ ++ max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL); ++ rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f]; ++ if (rate > max_rate) ++ max_rate = rate; ++ } ++#if 0 ++ printk("max rate:%d ===basic rate:\n", max_rate); ++ for (i=0;irates_len;i++) ++ printk(" %x", network->rates[i]); ++ printk("\n=======extend rate\n"); ++ for (i=0; irates_ex_len; i++) ++ printk(" %x", network->rates_ex[i]); ++ printk("\n"); ++#endif ++ iwe.cmd = SIOCGIWRATE; ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ iwe.u.bitrate.value = max_rate * 500000; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_event_rsl(info, start, stop, &iwe, ++ IW_EV_PARAM_LEN); ++#else ++ start = iwe_stream_add_event_rsl(start, stop, &iwe, ++ IW_EV_PARAM_LEN); ++#endif ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ /* Add quality statistics */ ++ /* TODO: Fix these values... */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.qual = network->stats.signal; ++ iwe.u.qual.level = network->stats.rssi; ++ iwe.u.qual.noise = network->stats.noise; ++ iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; ++ if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) ++ iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; ++ if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) ++ iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; ++ if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) ++ iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; ++ iwe.u.qual.updated = 7; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN); ++#else ++ start = iwe_stream_add_event_rsl(start, stop, &iwe, IW_EV_QUAL_LEN); ++#endif ++ iwe.cmd = IWEVCUSTOM; ++ p = custom; ++ ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++#if (WIRELESS_EXT < 18) ++ if (ieee->wpa_enabled && network->wpa_ie_len){ ++ char buf[MAX_WPA_IE_LEN * 2 + 30]; ++ // printk("WPA IE\n"); ++ u8 *p = buf; ++ p += sprintf(p, "wpa_ie="); ++ for (i = 0; i < network->wpa_ie_len; i++) { ++ p += sprintf(p, "%02x", network->wpa_ie[i]); ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ ++ if (ieee->wpa_enabled && network->rsn_ie_len){ ++ char buf[MAX_WPA_IE_LEN * 2 + 30]; ++ ++ u8 *p = buf; ++ p += sprintf(p, "rsn_ie="); ++ for (i = 0; i < network->rsn_ie_len; i++) { ++ p += sprintf(p, "%02x", network->rsn_ie[i]); ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++#else ++ memset(&iwe, 0, sizeof(iwe)); ++ if (network->wpa_ie_len) ++ { ++ char buf[MAX_WPA_IE_LEN]; ++ memcpy(buf, network->wpa_ie, network->wpa_ie_len); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = network->wpa_ie_len; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ memset(&iwe, 0, sizeof(iwe)); ++ if (network->rsn_ie_len) ++ { ++ char buf[MAX_WPA_IE_LEN]; ++ memcpy(buf, network->rsn_ie, network->rsn_ie_len); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = network->rsn_ie_len; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++#endif ++ ++ ++ /* Add EXTRA: Age to display seconds since last beacon/probe response ++ * for given network. */ ++ iwe.cmd = IWEVCUSTOM; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ ++ return start; ++} ++ ++int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ieee80211_network *network; ++ unsigned long flags; ++ ++ char *ev = extra; ++// char *stop = ev + IW_SCAN_MAX_DATA; ++ char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA; ++ //char *stop = ev + IW_SCAN_MAX_DATA; ++ int i = 0; ++ int err = 0; ++ IEEE80211_DEBUG_WX("Getting scan\n"); ++ down(&ieee->wx_sem); ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ list_for_each_entry(network, &ieee->network_list, list) { ++ i++; ++ if((stop-ev)<200) ++ { ++ err = -E2BIG; ++ break; ++ } ++ if (ieee->scan_age == 0 || ++ time_after(network->last_scanned + ieee->scan_age, jiffies)) ++ ev = rtl819x_translate_scan(ieee, ev, stop, network, info); ++ else ++ IEEE80211_DEBUG_SCAN( ++ "Not showing network '%s (" ++ MAC_FMT ")' due to age (%lums).\n", ++ escape_essid(network->ssid, ++ network->ssid_len), ++ MAC_ARG(network->bssid), ++ (jiffies - network->last_scanned) / (HZ / 100)); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ up(&ieee->wx_sem); ++ wrqu->data.length = ev - extra; ++ wrqu->data.flags = 0; ++ ++ IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); ++ ++ return err; ++} ++ ++int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ struct iw_point *erq = &(wrqu->encoding); ++ struct net_device *dev = ieee->dev; ++ struct ieee80211_security sec = { ++ .flags = 0 ++ }; ++ int i, key, key_provided, len; ++ struct ieee80211_crypt_data **crypt; ++ ++ IEEE80211_DEBUG_WX("SET_ENCODE\n"); ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ key_provided = 1; ++ } else { ++ key_provided = 0; ++ key = ieee->tx_keyidx; ++ } ++ ++ IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? ++ "provided" : "default"); ++ crypt = &ieee->crypt[key]; ++ ++ if (erq->flags & IW_ENCODE_DISABLED) { ++ if (key_provided && *crypt) { ++ IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", ++ key); ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } else ++ IEEE80211_DEBUG_WX("Disabling encryption.\n"); ++ ++ /* Check all the keys to see if any are still configured, ++ * and if no key index was provided, de-init them all */ ++ for (i = 0; i < WEP_KEYS; i++) { ++ if (ieee->crypt[i] != NULL) { ++ if (key_provided) ++ break; ++ ieee80211_crypt_delayed_deinit( ++ ieee, &ieee->crypt[i]); ++ } ++ } ++ ++ if (i == WEP_KEYS) { ++ sec.enabled = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_ENABLED | SEC_LEVEL; ++ } ++ ++ goto done; ++ } ++ ++ ++ ++ sec.enabled = 1; ++ sec.flags |= SEC_ENABLED; ++ ++ if (*crypt != NULL && (*crypt)->ops != NULL && ++ strcmp((*crypt)->ops->name, "WEP") != 0) { ++ /* changing to use WEP; deinit previously used algorithm ++ * on this key */ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } ++ ++ if (*crypt == NULL) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ /* take WEP into use */ ++ new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), ++ GFP_KERNEL); ++ if (new_crypt == NULL) ++ return -ENOMEM; ++ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); ++ new_crypt->ops = ieee80211_get_crypto_ops("WEP"); ++ if (!new_crypt->ops) { ++ request_module("ieee80211_crypt_wep"); ++ new_crypt->ops = ieee80211_get_crypto_ops("WEP"); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++#else ++ if (new_crypt->ops && try_inc_mod_count(new_crypt->ops->owner)) ++#endif ++ new_crypt->priv = new_crypt->ops->init(key); ++ ++ if (!new_crypt->ops || !new_crypt->priv) { ++ kfree(new_crypt); ++ new_crypt = NULL; ++ ++ printk(KERN_WARNING "%s: could not initialize WEP: " ++ "load module ieee80211_crypt_wep\n", ++ dev->name); ++ return -EOPNOTSUPP; ++ } ++ *crypt = new_crypt; ++ } ++ ++ /* If a new key was provided, set it up */ ++ if (erq->length > 0) { ++ len = erq->length <= 5 ? 5 : 13; ++ memcpy(sec.keys[key], keybuf, erq->length); ++ if (len > erq->length) ++ memset(sec.keys[key] + erq->length, 0, ++ len - erq->length); ++ IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", ++ key, escape_essid(sec.keys[key], len), ++ erq->length, len); ++ sec.key_sizes[key] = len; ++ (*crypt)->ops->set_key(sec.keys[key], len, NULL, ++ (*crypt)->priv); ++ sec.flags |= (1 << key); ++ /* This ensures a key will be activated if no key is ++ * explicitely set */ ++ if (key == sec.active_key) ++ sec.flags |= SEC_ACTIVE_KEY; ++ ieee->tx_keyidx = key; ++ ++ } else { ++ len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, ++ NULL, (*crypt)->priv); ++ if (len == 0) { ++ /* Set a default key of all 0 */ ++ printk("Setting key %d to all zero.\n", ++ key); ++ ++ IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", ++ key); ++ memset(sec.keys[key], 0, 13); ++ (*crypt)->ops->set_key(sec.keys[key], 13, NULL, ++ (*crypt)->priv); ++ sec.key_sizes[key] = 13; ++ sec.flags |= (1 << key); ++ } ++ ++ /* No key data - just set the default TX key index */ ++ if (key_provided) { ++ IEEE80211_DEBUG_WX( ++ "Setting key %d to default Tx key.\n", key); ++ ieee->tx_keyidx = key; ++ sec.active_key = key; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } ++ } ++ ++ done: ++ ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); ++ ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ sec.flags |= SEC_AUTH_MODE; ++ IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? ++ "OPEN" : "SHARED KEY"); ++ ++ /* For now we just support WEP, so only set that security level... ++ * TODO: When WPA is added this is one place that needs to change */ ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ ++ ++ if (ieee->set_security) ++ ieee->set_security(dev, &sec); ++ ++ /* Do not reset port if card is in Managed mode since resetting will ++ * generate new IEEE 802.11 authentication which may end up in looping ++ * with IEEE 802.1X. If your hardware requires a reset after WEP ++ * configuration (for example... Prism2), implement the reset_port in ++ * the callbacks structures used to initialize the 802.11 stack. */ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ieee->reset_port(dev)) { ++ printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ struct iw_point *erq = &(wrqu->encoding); ++ int len, key; ++ struct ieee80211_crypt_data *crypt; ++ ++ IEEE80211_DEBUG_WX("GET_ENCODE\n"); ++ ++ if(ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ } else ++ key = ieee->tx_keyidx; ++ ++ crypt = ieee->crypt[key]; ++ erq->flags = key + 1; ++ ++ if (crypt == NULL || crypt->ops == NULL) { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ return 0; ++ } ++#if 0 ++ if (strcmp(crypt->ops->name, "WEP") != 0) { ++ /* only WEP is supported with wireless extensions, so just ++ * report that encryption is used */ ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_ENABLED; ++ return 0; ++ } ++#endif ++ len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv); ++ erq->length = (len >= 0 ? len : 0); ++ ++ erq->flags |= IW_ENCODE_ENABLED; ++ ++ if (ieee->open_wep) ++ erq->flags |= IW_ENCODE_OPEN; ++ else ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ ++ return 0; ++} ++#if (WIRELESS_EXT >= 18) ++int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct net_device *dev = ieee->dev; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int i, idx; ++ int group_key = 0; ++ const char *alg, *module; ++ struct ieee80211_crypto_ops *ops; ++ struct ieee80211_crypt_data **crypt; ++ ++ struct ieee80211_security sec = { ++ .flags = 0, ++ }; ++ //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg); ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) { ++ if (idx < 1 || idx > WEP_KEYS) ++ return -EINVAL; ++ idx--; ++ } else ++ idx = ieee->tx_keyidx; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ ++ crypt = &ieee->crypt[idx]; ++ ++ group_key = 1; ++ } else { ++ /* some Cisco APs use idx>0 for unicast in dynamic WEP */ ++ //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg); ++ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) ++ return -EINVAL; ++ if (ieee->iw_mode == IW_MODE_INFRA) ++ ++ crypt = &ieee->crypt[idx]; ++ ++ else ++ return -EINVAL; ++ } ++ ++ sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; ++ if ((encoding->flags & IW_ENCODE_DISABLED) || ++ ext->alg == IW_ENCODE_ALG_NONE) { ++ if (*crypt) ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ for (i = 0; i < WEP_KEYS; i++) ++ ++ if (ieee->crypt[i] != NULL) ++ ++ break; ++ ++ if (i == WEP_KEYS) { ++ sec.enabled = 0; ++ // sec.encrypt = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_LEVEL; ++ } ++ //printk("disabled: flag:%x\n", encoding->flags); ++ goto done; ++ } ++ ++ sec.enabled = 1; ++ // sec.encrypt = 1; ++#if 0 ++ if (group_key ? !ieee->host_mc_decrypt : ++ !(ieee->host_encrypt || ieee->host_decrypt || ++ ieee->host_encrypt_msdu)) ++ goto skip_host_crypt; ++#endif ++ switch (ext->alg) { ++ case IW_ENCODE_ALG_WEP: ++ alg = "WEP"; ++ module = "ieee80211_crypt_wep"; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ alg = "TKIP"; ++ module = "ieee80211_crypt_tkip"; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ alg = "CCMP"; ++ module = "ieee80211_crypt_ccmp"; ++ break; ++ default: ++ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", ++ dev->name, ext->alg); ++ ret = -EINVAL; ++ goto done; ++ } ++ printk("alg name:%s\n",alg); ++ ++ ops = ieee80211_get_crypto_ops(alg); ++ if (ops == NULL) { ++ request_module(module); ++ ops = ieee80211_get_crypto_ops(alg); ++ } ++ if (ops == NULL) { ++ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", ++ dev->name, ext->alg); ++ printk("========>unknown crypto alg %d\n", ext->alg); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ if (*crypt == NULL || (*crypt)->ops != ops) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) ++ new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); ++#else ++ new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL); ++ memset(new_crypt,0,sizeof(*new_crypt)); ++#endif ++ if (new_crypt == NULL) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ new_crypt->ops = ops; ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++ new_crypt->priv = new_crypt->ops->init(idx); ++ if (new_crypt->priv == NULL) { ++ kfree(new_crypt); ++ ret = -EINVAL; ++ goto done; ++ } ++ *crypt = new_crypt; ++ ++ } ++ ++ if (ext->key_len > 0 && (*crypt)->ops->set_key && ++ (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, ++ (*crypt)->priv) < 0) { ++ IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); ++ printk("key setting failed\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++#if 1 ++ //skip_host_crypt: ++ //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ ieee->tx_keyidx = idx; ++ sec.active_key = idx; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } ++ ++ if (ext->alg != IW_ENCODE_ALG_NONE) { ++ //memcpy(sec.keys[idx], ext->key, ext->key_len); ++ sec.key_sizes[idx] = ext->key_len; ++ sec.flags |= (1 << idx); ++ if (ext->alg == IW_ENCODE_ALG_WEP) { ++ // sec.encode_alg[idx] = SEC_ALG_WEP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } else if (ext->alg == IW_ENCODE_ALG_TKIP) { ++ // sec.encode_alg[idx] = SEC_ALG_TKIP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_2; ++ } else if (ext->alg == IW_ENCODE_ALG_CCMP) { ++ // sec.encode_alg[idx] = SEC_ALG_CCMP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_3; ++ } ++ /* Don't set sec level for group keys. */ ++ if (group_key) ++ sec.flags &= ~SEC_LEVEL; ++ } ++#endif ++done: ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ieee->reset_port(dev)) { ++ IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); ++ return -EINVAL; ++ } ++#endif ++ return ret; ++} ++ ++int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ struct ieee80211_crypt_data *crypt; ++ int idx, max_key_len; ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) { ++ if (idx < 1 || idx > WEP_KEYS) ++ return -EINVAL; ++ idx--; ++ } else ++ idx = ieee->tx_keyidx; ++ ++ if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY && ++ ext->alg != IW_ENCODE_ALG_WEP) ++ if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA) ++ return -EINVAL; ++ ++ crypt = ieee->crypt[idx]; ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ if (crypt == NULL || crypt->ops == NULL ) { ++ ext->alg = IW_ENCODE_ALG_NONE; ++ ext->key_len = 0; ++ encoding->flags |= IW_ENCODE_DISABLED; ++ } else { ++ if (strcmp(crypt->ops->name, "WEP") == 0 ) ++ ext->alg = IW_ENCODE_ALG_WEP; ++ else if (strcmp(crypt->ops->name, "TKIP")) ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ else if (strcmp(crypt->ops->name, "CCMP")) ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ else ++ return -EINVAL; ++ ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv); ++ encoding->flags |= IW_ENCODE_ENABLED; ++ if (ext->key_len && ++ (ext->alg == IW_ENCODE_ALG_TKIP || ++ ext->alg == IW_ENCODE_ALG_CCMP)) ++ ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID; ++ ++ } ++ ++ return 0; ++} ++ ++int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct iw_mlme *mlme = (struct iw_mlme *) extra; ++ switch (mlme->cmd) { ++ case IW_MLME_DEAUTH: ++ case IW_MLME_DISASSOC: ++ ieee80211_disassociate(ieee); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ return 0; ++} ++ ++int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ switch (data->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ /*need to support wpa2 here*/ ++ //printk("wpa version:%x\n", data->value); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * * Host AP driver does not use these parameters and allows ++ * * wpa_supplicant to control them internally. ++ * */ ++ break; ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ ieee->tkip_countermeasures = data->value; ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ ieee->drop_unencrypted = data->value; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value); ++ // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; ++ if(data->value & IW_AUTH_ALG_SHARED_KEY){ ++ ieee->open_wep = 0; ++ ieee->auth_mode = 1; ++ } ++ else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){ ++ ieee->open_wep = 1; ++ ieee->auth_mode = 0; ++ } ++ else if(data->value & IW_AUTH_ALG_LEAP){ ++ ieee->open_wep = 1; ++ ieee->auth_mode = 2; ++ //printk("hahahaa:LEAP\n"); ++ } ++ else ++ return -EINVAL; ++ //printk("open_wep:%d\n", ieee->open_wep); ++ break; ++ ++#if 1 ++ case IW_AUTH_WPA_ENABLED: ++ ieee->wpa_enabled = (data->value)?1:0; ++ //printk("enalbe wpa:%d\n", ieee->wpa_enabled); ++ break; ++ ++#endif ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ ieee->ieee802_1x = data->value; ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ ieee->privacy_invoked = data->value; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ return 0; ++} ++#endif ++#if 1 ++int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) ++{ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#if 0 ++ printk("====>%s()\n", __FUNCTION__); ++ { ++ int i; ++ for (i=0; iMAX_WPA_IE_LEN || (len && ie == NULL)) ++ { ++ // printk("return error out, len:%d\n", len); ++ return -EINVAL; ++ } ++ ++ ++ if (len) ++ { ++ if (len != ie[1]+2) ++ { ++ printk("len:%d, ie:%d\n", len, ie[1]); ++ return -EINVAL; ++ } ++ buf = kmalloc(len, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ memcpy(buf, ie, len); ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = buf; ++ ieee->wpa_ie_len = len; ++ } ++ else{ ++ if (ieee->wpa_ie) ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = NULL; ++ ieee->wpa_ie_len = 0; ++ } ++#endif ++ return 0; ++ ++} ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++//EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); ++#if (WIRELESS_EXT >= 18) ++//EXPORT_SYMBOL(ieee80211_wx_set_mlme); ++//EXPORT_SYMBOL(ieee80211_wx_set_auth); ++//EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); ++//EXPORT_SYMBOL(ieee80211_wx_get_encode_ext); ++#endif ++//EXPORT_SYMBOL(ieee80211_wx_get_scan); ++//EXPORT_SYMBOL(ieee80211_wx_set_encode); ++//EXPORT_SYMBOL(ieee80211_wx_get_encode); ++#else ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_gen_ie); ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_mlme); ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_auth); ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode_ext); ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_scan); ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_set_encode); ++//EXPORT_SYMBOL_NOVERS(ieee80211_wx_get_encode); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/internal.h +@@ -0,0 +1,115 @@ ++/* ++ * Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++#ifndef _CRYPTO_INTERNAL_H ++#define _CRYPTO_INTERNAL_H ++ ++ ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ prefetch(pos->member.next); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member), \ ++ prefetch(pos->member.next)) ++ ++static inline void cond_resched(void) ++{ ++ if (need_resched()) { ++ set_current_state(TASK_RUNNING); ++ schedule(); ++ } ++} ++#endif ++ ++extern enum km_type crypto_km_types[]; ++ ++static inline enum km_type crypto_kmap_type(int out) ++{ ++ return crypto_km_types[(in_softirq() ? 2 : 0) + out]; ++} ++ ++static inline void *crypto_kmap(struct page *page, int out) ++{ ++ return kmap_atomic(page, crypto_kmap_type(out)); ++} ++ ++static inline void crypto_kunmap(void *vaddr, int out) ++{ ++ kunmap_atomic(vaddr, crypto_kmap_type(out)); ++} ++ ++static inline void crypto_yield(struct crypto_tfm *tfm) ++{ ++ if (!in_softirq()) ++ cond_resched(); ++} ++ ++static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) ++{ ++ return (void *)&tfm[1]; ++} ++ ++struct crypto_alg *crypto_alg_lookup(const char *name); ++ ++#ifdef CONFIG_KMOD ++void crypto_alg_autoload(const char *name); ++struct crypto_alg *crypto_alg_mod_lookup(const char *name); ++#else ++static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) ++{ ++ return crypto_alg_lookup(name); ++} ++#endif ++ ++#ifdef CONFIG_CRYPTO_HMAC ++int crypto_alloc_hmac_block(struct crypto_tfm *tfm); ++void crypto_free_hmac_block(struct crypto_tfm *tfm); ++#else ++static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm) ++{ ++ return 0; ++} ++ ++static inline void crypto_free_hmac_block(struct crypto_tfm *tfm) ++{ } ++#endif ++ ++#ifdef CONFIG_PROC_FS ++void __init crypto_init_proc(void); ++#else ++static inline void crypto_init_proc(void) ++{ } ++#endif ++ ++int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); ++int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); ++int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); ++ ++int crypto_init_digest_ops(struct crypto_tfm *tfm); ++int crypto_init_cipher_ops(struct crypto_tfm *tfm); ++int crypto_init_compress_ops(struct crypto_tfm *tfm); ++ ++void crypto_exit_digest_ops(struct crypto_tfm *tfm); ++void crypto_exit_cipher_ops(struct crypto_tfm *tfm); ++void crypto_exit_compress_ops(struct crypto_tfm *tfm); ++ ++#endif /* _CRYPTO_INTERNAL_H */ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/kmap_types.h +@@ -0,0 +1,20 @@ ++#ifndef __KMAP_TYPES_H ++ ++#define __KMAP_TYPES_H ++ ++ ++enum km_type { ++ KM_BOUNCE_READ, ++ KM_SKB_SUNRPC_DATA, ++ KM_SKB_DATA_SOFTIRQ, ++ KM_USER0, ++ KM_USER1, ++ KM_BH_IRQ, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++ KM_TYPE_NR ++}; ++ ++#define _ASM_KMAP_TYPES_H ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/michael_mic.c +@@ -0,0 +1,194 @@ ++/* ++ * Cryptographic API ++ * ++ * Michael MIC (IEEE 802.11i/TKIP) keyed digest ++ * ++ * Copyright (c) 2004 Jouni Malinen ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++//#include ++#include "rtl_crypto.h" ++ ++ ++struct michael_mic_ctx { ++ u8 pending[4]; ++ size_t pending_len; ++ ++ u32 l, r; ++}; ++ ++ ++static inline u32 rotl(u32 val, int bits) ++{ ++ return (val << bits) | (val >> (32 - bits)); ++} ++ ++ ++static inline u32 rotr(u32 val, int bits) ++{ ++ return (val >> bits) | (val << (32 - bits)); ++} ++ ++ ++static inline u32 xswap(u32 val) ++{ ++ return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); ++} ++ ++ ++#define michael_block(l, r) \ ++do { \ ++ r ^= rotl(l, 17); \ ++ l += r; \ ++ r ^= xswap(l); \ ++ l += r; \ ++ r ^= rotl(l, 3); \ ++ l += r; \ ++ r ^= rotr(l, 2); \ ++ l += r; \ ++} while (0) ++ ++ ++static inline u32 get_le32(const u8 *p) ++{ ++ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); ++} ++ ++ ++static inline void put_le32(u8 *p, u32 v) ++{ ++ p[0] = v; ++ p[1] = v >> 8; ++ p[2] = v >> 16; ++ p[3] = v >> 24; ++} ++ ++ ++static void michael_init(void *ctx) ++{ ++ struct michael_mic_ctx *mctx = ctx; ++ mctx->pending_len = 0; ++} ++ ++ ++static void michael_update(void *ctx, const u8 *data, unsigned int len) ++{ ++ struct michael_mic_ctx *mctx = ctx; ++ ++ if (mctx->pending_len) { ++ int flen = 4 - mctx->pending_len; ++ if (flen > len) ++ flen = len; ++ memcpy(&mctx->pending[mctx->pending_len], data, flen); ++ mctx->pending_len += flen; ++ data += flen; ++ len -= flen; ++ ++ if (mctx->pending_len < 4) ++ return; ++ ++ mctx->l ^= get_le32(mctx->pending); ++ michael_block(mctx->l, mctx->r); ++ mctx->pending_len = 0; ++ } ++ ++ while (len >= 4) { ++ mctx->l ^= get_le32(data); ++ michael_block(mctx->l, mctx->r); ++ data += 4; ++ len -= 4; ++ } ++ ++ if (len > 0) { ++ mctx->pending_len = len; ++ memcpy(mctx->pending, data, len); ++ } ++} ++ ++ ++static void michael_final(void *ctx, u8 *out) ++{ ++ struct michael_mic_ctx *mctx = ctx; ++ u8 *data = mctx->pending; ++ ++ /* Last block and padding (0x5a, 4..7 x 0) */ ++ switch (mctx->pending_len) { ++ case 0: ++ mctx->l ^= 0x5a; ++ break; ++ case 1: ++ mctx->l ^= data[0] | 0x5a00; ++ break; ++ case 2: ++ mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000; ++ break; ++ case 3: ++ mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | ++ 0x5a000000; ++ break; ++ } ++ michael_block(mctx->l, mctx->r); ++ /* l ^= 0; */ ++ michael_block(mctx->l, mctx->r); ++ ++ put_le32(out, mctx->l); ++ put_le32(out + 4, mctx->r); ++} ++ ++ ++static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen, ++ u32 *flags) ++{ ++ struct michael_mic_ctx *mctx = ctx; ++ if (keylen != 8) { ++ if (flags) ++ *flags = CRYPTO_TFM_RES_BAD_KEY_LEN; ++ return -EINVAL; ++ } ++ mctx->l = get_le32(key); ++ mctx->r = get_le32(key + 4); ++ return 0; ++} ++ ++ ++static struct crypto_alg michael_mic_alg = { ++ .cra_name = "michael_mic", ++ .cra_flags = CRYPTO_ALG_TYPE_DIGEST, ++ .cra_blocksize = 8, ++ .cra_ctxsize = sizeof(struct michael_mic_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list), ++ .cra_u = { .digest = { ++ .dia_digestsize = 8, ++ .dia_init = michael_init, ++ .dia_update = michael_update, ++ .dia_final = michael_final, ++ .dia_setkey = michael_setkey } } ++}; ++ ++ ++static int __init michael_mic_init(void) ++{ ++ return crypto_register_alg(&michael_mic_alg); ++} ++ ++ ++static void __exit michael_mic_exit(void) ++{ ++ crypto_unregister_alg(&michael_mic_alg); ++} ++ ++ ++module_init(michael_mic_init); ++module_exit(michael_mic_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Michael MIC"); ++MODULE_AUTHOR("Jouni Malinen "); +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/proc.c +@@ -0,0 +1,116 @@ ++/* ++ * Scatterlist Cryptographic API. ++ * ++ * Procfs information. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++#include ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include "internal.h" ++ ++extern struct list_head crypto_alg_list; ++extern struct rw_semaphore crypto_alg_sem; ++ ++static void *c_start(struct seq_file *m, loff_t *pos) ++{ ++ struct list_head *v; ++ loff_t n = *pos; ++ ++ down_read(&crypto_alg_sem); ++ list_for_each(v, &crypto_alg_list) ++ if (!n--) ++ return list_entry(v, struct crypto_alg, cra_list); ++ return NULL; ++} ++ ++static void *c_next(struct seq_file *m, void *p, loff_t *pos) ++{ ++ struct list_head *v = p; ++ ++ (*pos)++; ++ v = v->next; ++ return (v == &crypto_alg_list) ? ++ NULL : list_entry(v, struct crypto_alg, cra_list); ++} ++ ++static void c_stop(struct seq_file *m, void *p) ++{ ++ up_read(&crypto_alg_sem); ++} ++ ++static int c_show(struct seq_file *m, void *p) ++{ ++ struct crypto_alg *alg = (struct crypto_alg *)p; ++ ++ seq_printf(m, "name : %s\n", alg->cra_name); ++ seq_printf(m, "module : %s\n", ++ (alg->cra_module ? ++ alg->cra_module->name : ++ "kernel")); ++ ++ switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { ++ case CRYPTO_ALG_TYPE_CIPHER: ++ seq_printf(m, "type : cipher\n"); ++ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); ++ seq_printf(m, "min keysize : %u\n", ++ alg->cra_cipher.cia_min_keysize); ++ seq_printf(m, "max keysize : %u\n", ++ alg->cra_cipher.cia_max_keysize); ++ break; ++ ++ case CRYPTO_ALG_TYPE_DIGEST: ++ seq_printf(m, "type : digest\n"); ++ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); ++ seq_printf(m, "digestsize : %u\n", ++ alg->cra_digest.dia_digestsize); ++ break; ++ case CRYPTO_ALG_TYPE_COMPRESS: ++ seq_printf(m, "type : compression\n"); ++ break; ++ default: ++ seq_printf(m, "type : unknown\n"); ++ break; ++ } ++ ++ seq_putc(m, '\n'); ++ return 0; ++} ++ ++static struct seq_operations crypto_seq_ops = { ++ .start = c_start, ++ .next = c_next, ++ .stop = c_stop, ++ .show = c_show ++}; ++ ++static int crypto_info_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &crypto_seq_ops); ++} ++ ++static struct file_operations proc_crypto_ops = { ++ .open = crypto_info_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release ++}; ++ ++void __init crypto_init_proc(void) ++{ ++ struct proc_dir_entry *proc; ++ ++ proc = create_proc_entry("crypto", 0, NULL); ++ if (proc) ++ proc->proc_fops = &proc_crypto_ops; ++} +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_BA.h +@@ -0,0 +1,69 @@ ++#ifndef _BATYPE_H_ ++#define _BATYPE_H_ ++ ++#define TOTAL_TXBA_NUM 16 ++#define TOTAL_RXBA_NUM 16 ++ ++#define BA_SETUP_TIMEOUT 200 ++#define BA_INACT_TIMEOUT 60000 ++ ++#define BA_POLICY_DELAYED 0 ++#define BA_POLICY_IMMEDIATE 1 ++ ++#define ADDBA_STATUS_SUCCESS 0 ++#define ADDBA_STATUS_REFUSED 37 ++#define ADDBA_STATUS_INVALID_PARAM 38 ++ ++#define DELBA_REASON_QSTA_LEAVING 36 ++#define DELBA_REASON_END_BA 37 ++#define DELBA_REASON_UNKNOWN_BA 38 ++#define DELBA_REASON_TIMEOUT 39 ++/* whether need define BA Action frames here? ++struct ieee80211_ADDBA_Req{ ++ struct ieee80211_header_data header; ++ u8 category; ++ u8 ++} __attribute__ ((packed)); ++*/ ++//Is this need?I put here just to make it easier to define structure BA_RECORD //WB ++typedef union _SEQUENCE_CONTROL{ ++ u16 ShortData; ++ struct ++ { ++ u16 FragNum:4; ++ u16 SeqNum:12; ++ }field; ++}SEQUENCE_CONTROL, *PSEQUENCE_CONTROL; ++ ++typedef union _BA_PARAM_SET { ++ u8 charData[2]; ++ u16 shortData; ++ struct { ++ u16 AMSDU_Support:1; ++ u16 BAPolicy:1; ++ u16 TID:4; ++ u16 BufferSize:10; ++ } field; ++} BA_PARAM_SET, *PBA_PARAM_SET; ++ ++typedef union _DELBA_PARAM_SET { ++ u8 charData[2]; ++ u16 shortData; ++ struct { ++ u16 Reserved:11; ++ u16 Initiator:1; ++ u16 TID:4; ++ } field; ++} DELBA_PARAM_SET, *PDELBA_PARAM_SET; ++ ++typedef struct _BA_RECORD { ++ struct timer_list Timer; ++ u8 bValid; ++ u8 DialogToken; ++ BA_PARAM_SET BaParamSet; ++ u16 BaTimeoutValue; ++ SEQUENCE_CONTROL BaStartSeqCtrl; ++} BA_RECORD, *PBA_RECORD; ++ ++#endif //end _BATYPE_H_ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c +@@ -0,0 +1,779 @@ ++/******************************************************************************************************************************** ++ * This file is created to process BA Action Frame. According to 802.11 spec, there are 3 BA action types at all. And as BA is ++ * related to TS, this part need some struture defined in QOS side code. Also TX RX is going to be resturctured, so how to send ++ * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue. ++ * WB 2008-05-27 ++ * *****************************************************************************************************************************/ ++#include "ieee80211.h" ++#include "rtl819x_BA.h" ++ ++/******************************************************************************************************************** ++ *function: Activate BA entry. And if Time is nozero, start timer. ++ * input: PBA_RECORD pBA //BA entry to be enabled ++ * u16 Time //indicate time delay. ++ * output: none ++********************************************************************************************************************/ ++void ActivateBAEntry(struct ieee80211_device* ieee, PBA_RECORD pBA, u16 Time) ++{ ++ pBA->bValid = true; ++ if(Time != 0) ++ mod_timer(&pBA->Timer, jiffies + MSECS(Time)); ++} ++ ++/******************************************************************************************************************** ++ *function: deactivate BA entry, including its timer. ++ * input: PBA_RECORD pBA //BA entry to be disabled ++ * output: none ++********************************************************************************************************************/ ++void DeActivateBAEntry( struct ieee80211_device* ieee, PBA_RECORD pBA) ++{ ++ pBA->bValid = false; ++ del_timer_sync(&pBA->Timer); ++} ++/******************************************************************************************************************** ++ *function: deactivete BA entry in Tx Ts, and send DELBA. ++ * input: ++ * PTX_TS_RECORD pTxTs //Tx Ts which is to deactivate BA entry. ++ * output: none ++ * notice: As PTX_TS_RECORD structure will be defined in QOS, so wait to be merged. //FIXME ++********************************************************************************************************************/ ++u8 TxTsDeleteBA( struct ieee80211_device* ieee, PTX_TS_RECORD pTxTs) ++{ ++ PBA_RECORD pAdmittedBa = &pTxTs->TxAdmittedBARecord; //These two BA entries must exist in TS structure ++ PBA_RECORD pPendingBa = &pTxTs->TxPendingBARecord; ++ u8 bSendDELBA = false; ++ ++ // Delete pending BA ++ if(pPendingBa->bValid) ++ { ++ DeActivateBAEntry(ieee, pPendingBa); ++ bSendDELBA = true; ++ } ++ ++ // Delete admitted BA ++ if(pAdmittedBa->bValid) ++ { ++ DeActivateBAEntry(ieee, pAdmittedBa); ++ bSendDELBA = true; ++ } ++ ++ return bSendDELBA; ++} ++ ++/******************************************************************************************************************** ++ *function: deactivete BA entry in Tx Ts, and send DELBA. ++ * input: ++ * PRX_TS_RECORD pRxTs //Rx Ts which is to deactivate BA entry. ++ * output: none ++ * notice: As PRX_TS_RECORD structure will be defined in QOS, so wait to be merged. //FIXME, same with above ++********************************************************************************************************************/ ++u8 RxTsDeleteBA( struct ieee80211_device* ieee, PRX_TS_RECORD pRxTs) ++{ ++ PBA_RECORD pBa = &pRxTs->RxAdmittedBARecord; ++ u8 bSendDELBA = false; ++ ++ if(pBa->bValid) ++ { ++ DeActivateBAEntry(ieee, pBa); ++ bSendDELBA = true; ++ } ++ ++ return bSendDELBA; ++} ++ ++/******************************************************************************************************************** ++ *function: reset BA entry ++ * input: ++ * PBA_RECORD pBA //entry to be reset ++ * output: none ++********************************************************************************************************************/ ++void ResetBaEntry( PBA_RECORD pBA) ++{ ++ pBA->bValid = false; ++ pBA->BaParamSet.shortData = 0; ++ pBA->BaTimeoutValue = 0; ++ pBA->DialogToken = 0; ++ pBA->BaStartSeqCtrl.ShortData = 0; ++} ++//These functions need porting here or not? ++/******************************************************************************************************************************* ++ *function: construct ADDBAREQ and ADDBARSP frame here together. ++ * input: u8* Dst //ADDBA frame's destination ++ * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA. ++ * u16 StatusCode //status code in RSP and I will use it to indicate whether it's RSP or REQ(will I?) ++ * u8 type //indicate whether it's RSP(ACT_ADDBARSP) ow REQ(ACT_ADDBAREQ) ++ * output: none ++ * return: sk_buff* skb //return constructed skb to xmit ++*******************************************************************************************************************************/ ++static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, PBA_RECORD pBA, u16 StatusCode, u8 type) ++{ ++ struct sk_buff *skb = NULL; ++ struct ieee80211_hdr_3addr* BAReq = NULL; ++ u8* tag = NULL; ++ u16 tmp = 0; ++ u16 len = ieee->tx_headroom + 9; ++ //category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2)) ++ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:"MAC_FMT", ieee->dev:%p\n", __FUNCTION__, type, MAC_ARG(Dst), ieee->dev); ++ if (pBA == NULL||ieee == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee); ++ return NULL; ++ } ++ skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME ++ if (skb == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); ++ return NULL; ++ } ++ ++ memset(skb->data, 0, sizeof( struct ieee80211_hdr_3addr)); //I wonder whether it's necessary. Apparently kernel will not do it when alloc a skb. ++ skb_reserve(skb, ieee->tx_headroom); ++ ++ BAReq = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); ++ ++ memcpy(BAReq->addr1, Dst, ETH_ALEN); ++ memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); ++ ++ memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame ++ ++ //tag += sizeof( struct ieee80211_hdr_3addr); //move to action field ++ tag = (u8*)skb_put(skb, 9); ++ *tag ++= ACT_CAT_BA; ++ *tag ++= type; ++ // Dialog Token ++ *tag ++= pBA->DialogToken; ++ ++ if (ACT_ADDBARSP == type) ++ { ++ // Status Code ++ printk("=====>to send ADDBARSP\n"); ++ tmp = cpu_to_le16(StatusCode); ++ memcpy(tag, (u8*)&tmp, 2); ++ tag += 2; ++ } ++ // BA Parameter Set ++ tmp = cpu_to_le16(pBA->BaParamSet.shortData); ++ memcpy(tag, (u8*)&tmp, 2); ++ tag += 2; ++ // BA Timeout Value ++ tmp = cpu_to_le16(pBA->BaTimeoutValue); ++ memcpy(tag, (u8*)&tmp, 2); ++ tag += 2; ++ ++ if (ACT_ADDBAREQ == type) ++ { ++ // BA Start SeqCtrl ++ memcpy(tag,(u8*)&(pBA->BaStartSeqCtrl), 2); ++ tag += 2; ++ } ++ ++ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); ++ return skb; ++ //return NULL; ++} ++ ++#if 0 //I try to merge ADDBA_REQ and ADDBA_RSP frames together.. ++/******************************************************************************************************************** ++ *function: construct ADDBAREQ frame ++ * input: u8* dst //ADDBARsp frame's destination ++ * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA_RSP. ++ * u16 StatusCode //status code. ++ * output: none ++ * return: sk_buff* skb //return constructed skb to xmit ++********************************************************************************************************************/ ++static struct sk_buff* ieee80211_ADDBA_Rsp( IN struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, u16 StatusCode) ++{ ++ OCTET_STRING osADDBAFrame, tmp; ++ ++ FillOctetString(osADDBAFrame, Buffer, 0); ++ *pLength = 0; ++ ++ ConstructMaFrameHdr( ++ Adapter, ++ Addr, ++ ACT_CAT_BA, ++ ACT_ADDBARSP, ++ &osADDBAFrame ); ++ ++ // Dialog Token ++ FillOctetString(tmp, &pBA->DialogToken, 1); ++ PacketAppendData(&osADDBAFrame, tmp); ++ ++ // Status Code ++ FillOctetString(tmp, &StatusCode, 2); ++ PacketAppendData(&osADDBAFrame, tmp); ++ ++ // BA Parameter Set ++ FillOctetString(tmp, &pBA->BaParamSet, 2); ++ PacketAppendData(&osADDBAFrame, tmp); ++ ++ // BA Timeout Value ++ FillOctetString(tmp, &pBA->BaTimeoutValue, 2); ++ PacketAppendData(&osADDBAFrame, tmp); ++ ++ *pLength = osADDBAFrame.Length; ++} ++#endif ++ ++/******************************************************************************************************************** ++ *function: construct DELBA frame ++ * input: u8* dst //DELBA frame's destination ++ * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA ++ * TR_SELECT TxRxSelect //TX RX direction ++ * u16 ReasonCode //status code. ++ * output: none ++ * return: sk_buff* skb //return constructed skb to xmit ++********************************************************************************************************************/ ++static struct sk_buff* ieee80211_DELBA( ++ struct ieee80211_device* ieee, ++ u8* dst, ++ PBA_RECORD pBA, ++ TR_SELECT TxRxSelect, ++ u16 ReasonCode ++ ) ++{ ++ DELBA_PARAM_SET DelbaParamSet; ++ struct sk_buff *skb = NULL; ++ struct ieee80211_hdr_3addr* Delba = NULL; ++ u8* tag = NULL; ++ u16 tmp = 0; ++ //len = head len + DELBA Parameter Set(2) + Reason Code(2) ++ u16 len = 6 + ieee->tx_headroom; ++ ++ if (net_ratelimit()) ++ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:"MAC_FMT"\n", __FUNCTION__, ReasonCode, MAC_ARG(dst)); ++ ++ memset(&DelbaParamSet, 0, 2); ++ ++ DelbaParamSet.field.Initiator = (TxRxSelect==TX_DIR)?1:0; ++ DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; ++ ++ skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME ++ if (skb == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); ++ return NULL; ++ } ++// memset(skb->data, 0, len+sizeof( struct ieee80211_hdr_3addr)); ++ skb_reserve(skb, ieee->tx_headroom); ++ ++ Delba = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); ++ ++ memcpy(Delba->addr1, dst, ETH_ALEN); ++ memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); ++ Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame ++ ++ tag = (u8*)skb_put(skb, 6); ++ ++ *tag ++= ACT_CAT_BA; ++ *tag ++= ACT_DELBA; ++ ++ // DELBA Parameter Set ++ tmp = cpu_to_le16(DelbaParamSet.shortData); ++ memcpy(tag, (u8*)&tmp, 2); ++ tag += 2; ++ // Reason Code ++ tmp = cpu_to_le16(ReasonCode); ++ memcpy(tag, (u8*)&tmp, 2); ++ tag += 2; ++ ++ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); ++ if (net_ratelimit()) ++ IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __FUNCTION__); ++ return skb; ++} ++ ++/******************************************************************************************************************** ++ *function: send ADDBAReq frame out ++ * input: u8* dst //ADDBAReq frame's destination ++ * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA ++ * output: none ++ * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does ++********************************************************************************************************************/ ++void ieee80211_send_ADDBAReq(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA) ++{ ++ struct sk_buff *skb = NULL; ++ skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); //construct ACT_ADDBAREQ frames so set statuscode zero. ++ ++ if (skb) ++ { ++ softmac_mgmt_xmit(skb, ieee); ++ //add statistic needed here. ++ //and skb will be freed in softmac_mgmt_xmit(), so omit all dev_kfree_skb_any() outside softmac_mgmt_xmit() ++ //WB ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); ++ } ++ return; ++} ++ ++/******************************************************************************************************************** ++ *function: send ADDBARSP frame out ++ * input: u8* dst //DELBA frame's destination ++ * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA ++ * u16 StatusCode //RSP StatusCode ++ * output: none ++ * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does ++********************************************************************************************************************/ ++void ieee80211_send_ADDBARsp(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, u16 StatusCode) ++{ ++ struct sk_buff *skb = NULL; ++ skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); //construct ACT_ADDBARSP frames ++ if (skb) ++ { ++ softmac_mgmt_xmit(skb, ieee); ++ //same above ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); ++ } ++ ++ return; ++ ++} ++/******************************************************************************************************************** ++ *function: send ADDBARSP frame out ++ * input: u8* dst //DELBA frame's destination ++ * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA ++ * TR_SELECT TxRxSelect //TX or RX ++ * u16 ReasonCode //DEL ReasonCode ++ * output: none ++ * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does ++********************************************************************************************************************/ ++ ++void ieee80211_send_DELBA(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, TR_SELECT TxRxSelect, u16 ReasonCode) ++{ ++ struct sk_buff *skb = NULL; ++ skb = ieee80211_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); //construct ACT_ADDBARSP frames ++ if (skb) ++ { ++ softmac_mgmt_xmit(skb, ieee); ++ //same above ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); ++ } ++ return ; ++} ++ ++/******************************************************************************************************************** ++ *function: RX ADDBAReq ++ * input: struct sk_buff * skb //incoming ADDBAReq skb. ++ * return: 0(pass), other(fail) ++ * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. ++********************************************************************************************************************/ ++int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb) ++{ ++ struct ieee80211_hdr_3addr* req = NULL; ++ u16 rc = 0; ++ u8 * dst = NULL, *pDialogToken = NULL, *tag = NULL; ++ PBA_RECORD pBA = NULL; ++ PBA_PARAM_SET pBaParamSet = NULL; ++ u16* pBaTimeoutVal = NULL; ++ PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL; ++ PRX_TS_RECORD pTS = NULL; ++ ++ if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); ++ return -1; ++ } ++ ++ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); ++ ++ req = ( struct ieee80211_hdr_3addr*) skb->data; ++ tag = (u8*)req; ++ dst = (u8*)(&req->addr2[0]); ++ tag += sizeof( struct ieee80211_hdr_3addr); ++ pDialogToken = tag + 2; //category+action ++ pBaParamSet = (PBA_PARAM_SET)(tag + 3); //+DialogToken ++ pBaTimeoutVal = (u16*)(tag + 5); ++ pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7); ++ ++ printk("====================>rx ADDBAREQ from :"MAC_FMT"\n", MAC_ARG(dst)); ++//some other capability is not ready now. ++ if( (ieee->current_network.qos_data.active == 0) || ++ (ieee->pHTInfo->bCurrentHTSupport == false)) //|| ++ // (ieee->pStaQos->bEnableRxImmBA == false) ) ++ { ++ rc = ADDBA_STATUS_REFUSED; ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); ++ goto OnADDBAReq_Fail; ++ } ++ // Search for related traffic stream. ++ // If there is no matched TS, reject the ADDBA request. ++ if( !GetTs( ++ ieee, ++ (PTS_COMMON_INFO*)(&pTS), ++ dst, ++ (u8)(pBaParamSet->field.TID), ++ RX_DIR, ++ true) ) ++ { ++ rc = ADDBA_STATUS_REFUSED; ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); ++ goto OnADDBAReq_Fail; ++ } ++ pBA = &pTS->RxAdmittedBARecord; ++ // To Determine the ADDBA Req content ++ // We can do much more check here, including BufferSize, AMSDU_Support, Policy, StartSeqCtrl... ++ // I want to check StartSeqCtrl to make sure when we start aggregation!!! ++ // ++ if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) ++ { ++ rc = ADDBA_STATUS_INVALID_PARAM; ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __FUNCTION__); ++ goto OnADDBAReq_Fail; ++ } ++ // Admit the ADDBA Request ++ // ++ DeActivateBAEntry(ieee, pBA); ++ pBA->DialogToken = *pDialogToken; ++ pBA->BaParamSet = *pBaParamSet; ++ pBA->BaTimeoutValue = *pBaTimeoutVal; ++ pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; ++ //for half N mode we only aggregate 1 frame ++ if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) ++ pBA->BaParamSet.field.BufferSize = 1; ++ else ++ pBA->BaParamSet.field.BufferSize = 32; ++ ActivateBAEntry(ieee, pBA, pBA->BaTimeoutValue); ++ ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); ++ ++ // End of procedure. ++ return 0; ++ ++OnADDBAReq_Fail: ++ { ++ BA_RECORD BA; ++ BA.BaParamSet = *pBaParamSet; ++ BA.BaTimeoutValue = *pBaTimeoutVal; ++ BA.DialogToken = *pDialogToken; ++ BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; ++ ieee80211_send_ADDBARsp(ieee, dst, &BA, rc); ++ return 0; //we send RSP out. ++ } ++ ++} ++ ++/******************************************************************************************************************** ++ *function: RX ADDBARSP ++ * input: struct sk_buff * skb //incoming ADDBAReq skb. ++ * return: 0(pass), other(fail) ++ * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. ++********************************************************************************************************************/ ++int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb) ++{ ++ struct ieee80211_hdr_3addr* rsp = NULL; ++ PBA_RECORD pPendingBA, pAdmittedBA; ++ PTX_TS_RECORD pTS = NULL; ++ u8* dst = NULL, *pDialogToken = NULL, *tag = NULL; ++ u16* pStatusCode = NULL, *pBaTimeoutVal = NULL; ++ PBA_PARAM_SET pBaParamSet = NULL; ++ u16 ReasonCode; ++ ++ if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); ++ return -1; ++ } ++ rsp = ( struct ieee80211_hdr_3addr*)skb->data; ++ tag = (u8*)rsp; ++ dst = (u8*)(&rsp->addr2[0]); ++ tag += sizeof( struct ieee80211_hdr_3addr); ++ pDialogToken = tag + 2; ++ pStatusCode = (u16*)(tag + 3); ++ pBaParamSet = (PBA_PARAM_SET)(tag + 5); ++ pBaTimeoutVal = (u16*)(tag + 7); ++ ++ // Check the capability ++ // Since we can always receive A-MPDU, we just check if it is under HT mode. ++ if( ieee->current_network.qos_data.active == 0 || ++ ieee->pHTInfo->bCurrentHTSupport == false || ++ ieee->pHTInfo->bCurrentAMPDUEnable == false ) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bCurrentAMPDUEnable); ++ ReasonCode = DELBA_REASON_UNKNOWN_BA; ++ goto OnADDBARsp_Reject; ++ } ++ ++ ++ // ++ // Search for related TS. ++ // If there is no TS found, we wil reject ADDBA Rsp by sending DELBA frame. ++ // ++ if (!GetTs( ++ ieee, ++ (PTS_COMMON_INFO*)(&pTS), ++ dst, ++ (u8)(pBaParamSet->field.TID), ++ TX_DIR, ++ false) ) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); ++ ReasonCode = DELBA_REASON_UNKNOWN_BA; ++ goto OnADDBARsp_Reject; ++ } ++ ++ pTS->bAddBaReqInProgress = false; ++ pPendingBA = &pTS->TxPendingBARecord; ++ pAdmittedBA = &pTS->TxAdmittedBARecord; ++ ++ ++ // ++ // Check if related BA is waiting for setup. ++ // If not, reject by sending DELBA frame. ++ // ++ if((pAdmittedBA->bValid==true)) ++ { ++ // Since BA is already setup, we ignore all other ADDBA Response. ++ IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n"); ++ return -1; ++ } ++ else if((pPendingBA->bValid == false) ||(*pDialogToken != pPendingBA->DialogToken)) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n"); ++ ReasonCode = DELBA_REASON_UNKNOWN_BA; ++ goto OnADDBARsp_Reject; ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", *pStatusCode); ++ DeActivateBAEntry(ieee, pPendingBA); ++ } ++ ++ ++ if(*pStatusCode == ADDBA_STATUS_SUCCESS) ++ { ++ // ++ // Determine ADDBA Rsp content here. ++ // We can compare the value of BA parameter set that Peer returned and Self sent. ++ // If it is OK, then admitted. Or we can send DELBA to cancel BA mechanism. ++ // ++ if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) ++ { ++ // Since this is a kind of ADDBA failed, we delay next ADDBA process. ++ pTS->bAddBaReqDelayed = true; ++ DeActivateBAEntry(ieee, pAdmittedBA); ++ ReasonCode = DELBA_REASON_END_BA; ++ goto OnADDBARsp_Reject; ++ } ++ ++ ++ // ++ // Admitted condition ++ // ++ pAdmittedBA->DialogToken = *pDialogToken; ++ pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; ++ pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; ++ pAdmittedBA->BaParamSet = *pBaParamSet; ++ DeActivateBAEntry(ieee, pAdmittedBA); ++ ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); ++ } ++ else ++ { ++ // Delay next ADDBA process. ++ pTS->bAddBaReqDelayed = true; ++ } ++ ++ // End of procedure ++ return 0; ++ ++OnADDBARsp_Reject: ++ { ++ BA_RECORD BA; ++ BA.BaParamSet = *pBaParamSet; ++ ieee80211_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); ++ return 0; ++ } ++ ++} ++ ++/******************************************************************************************************************** ++ *function: RX DELBA ++ * input: struct sk_buff * skb //incoming ADDBAReq skb. ++ * return: 0(pass), other(fail) ++ * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. ++********************************************************************************************************************/ ++int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb) ++{ ++ struct ieee80211_hdr_3addr* delba = NULL; ++ PDELBA_PARAM_SET pDelBaParamSet = NULL; ++ u16* pReasonCode = NULL; ++ u8* dst = NULL; ++ ++ if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); ++ return -1; ++ } ++ ++ if(ieee->current_network.qos_data.active == 0 || ++ ieee->pHTInfo->bCurrentHTSupport == false ) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "received DELBA while QOS or HT is not supported(%d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); ++ return -1; ++ } ++ ++ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); ++ delba = ( struct ieee80211_hdr_3addr*)skb->data; ++ dst = (u8*)(&delba->addr2[0]); ++ delba += sizeof( struct ieee80211_hdr_3addr); ++ pDelBaParamSet = (PDELBA_PARAM_SET)(delba+2); ++ pReasonCode = (u16*)(delba+4); ++ ++ if(pDelBaParamSet->field.Initiator == 1) ++ { ++ PRX_TS_RECORD pRxTs; ++ ++ if( !GetTs( ++ ieee, ++ (PTS_COMMON_INFO*)&pRxTs, ++ dst, ++ (u8)pDelBaParamSet->field.TID, ++ RX_DIR, ++ false) ) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for RXTS in %s()\n", __FUNCTION__); ++ return -1; ++ } ++ ++ RxTsDeleteBA(ieee, pRxTs); ++ } ++ else ++ { ++ PTX_TS_RECORD pTxTs; ++ ++ if(!GetTs( ++ ieee, ++ (PTS_COMMON_INFO*)&pTxTs, ++ dst, ++ (u8)pDelBaParamSet->field.TID, ++ TX_DIR, ++ false) ) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for TXTS in %s()\n", __FUNCTION__); ++ return -1; ++ } ++ ++ pTxTs->bUsingBa = false; ++ pTxTs->bAddBaReqInProgress = false; ++ pTxTs->bAddBaReqDelayed = false; ++ del_timer_sync(&pTxTs->TsAddBaTimer); ++ //PlatformCancelTimer(Adapter, &pTxTs->TsAddBaTimer); ++ TxTsDeleteBA(ieee, pTxTs); ++ } ++ return 0; ++} ++ ++// ++// ADDBA initiate. This can only be called by TX side. ++// ++void ++TsInitAddBA( ++ struct ieee80211_device* ieee, ++ PTX_TS_RECORD pTS, ++ u8 Policy, ++ u8 bOverwritePending ++ ) ++{ ++ PBA_RECORD pBA = &pTS->TxPendingBARecord; ++ ++ if(pBA->bValid==true && bOverwritePending==false) ++ return; ++ ++ // Set parameters to "Pending" variable set ++ DeActivateBAEntry(ieee, pBA); ++ ++ pBA->DialogToken++; // DialogToken: Only keep the latest dialog token ++ pBA->BaParamSet.field.AMSDU_Support = 0; // Do not support A-MSDU with A-MPDU now!! ++ pBA->BaParamSet.field.BAPolicy = Policy; // Policy: Delayed or Immediate ++ pBA->BaParamSet.field.TID = pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; // TID ++ // BufferSize: This need to be set according to A-MPDU vector ++ pBA->BaParamSet.field.BufferSize = 32; // BufferSize: This need to be set according to A-MPDU vector ++ pBA->BaTimeoutValue = 0; // Timeout value: Set 0 to disable Timer ++ pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; // Block Ack will start after 3 packets later. ++ ++ ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); ++ ++ ieee80211_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA); ++} ++ ++void ++TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect) ++{ ++ ++ if(TxRxSelect == TX_DIR) ++ { ++ PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)pTsCommonInfo; ++ ++ if(TxTsDeleteBA(ieee, pTxTs)) ++ ieee80211_send_DELBA( ++ ieee, ++ pTsCommonInfo->Addr, ++ (pTxTs->TxAdmittedBARecord.bValid)?(&pTxTs->TxAdmittedBARecord):(&pTxTs->TxPendingBARecord), ++ TxRxSelect, ++ DELBA_REASON_END_BA); ++ } ++ else if(TxRxSelect == RX_DIR) ++ { ++ PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)pTsCommonInfo; ++ if(RxTsDeleteBA(ieee, pRxTs)) ++ ieee80211_send_DELBA( ++ ieee, ++ pTsCommonInfo->Addr, ++ &pRxTs->RxAdmittedBARecord, ++ TxRxSelect, ++ DELBA_REASON_END_BA ); ++ } ++} ++/******************************************************************************************************************** ++ *function: BA setup timer ++ * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer ++ * return: NULL ++ * notice: ++********************************************************************************************************************/ ++void BaSetupTimeOut(unsigned long data) ++{ ++ PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; ++ ++ pTxTs->bAddBaReqInProgress = false; ++ pTxTs->bAddBaReqDelayed = true; ++ pTxTs->TxPendingBARecord.bValid = false; ++} ++ ++void TxBaInactTimeout(unsigned long data) ++{ ++ PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; ++ struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[pTxTs->num]); ++ TxTsDeleteBA(ieee, pTxTs); ++ ieee80211_send_DELBA( ++ ieee, ++ pTxTs->TsCommonInfo.Addr, ++ &pTxTs->TxAdmittedBARecord, ++ TX_DIR, ++ DELBA_REASON_TIMEOUT); ++} ++ ++void RxBaInactTimeout(unsigned long data) ++{ ++ PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)data; ++ struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]); ++ ++ RxTsDeleteBA(ieee, pRxTs); ++ ieee80211_send_DELBA( ++ ieee, ++ pRxTs->TsCommonInfo.Addr, ++ &pRxTs->RxAdmittedBARecord, ++ RX_DIR, ++ DELBA_REASON_TIMEOUT); ++ return ; ++} ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h +@@ -0,0 +1,481 @@ ++#ifndef _RTL819XU_HTTYPE_H_ ++#define _RTL819XU_HTTYPE_H_ ++ ++//------------------------------------------------------------ ++// The HT Capability element is present in beacons, association request, ++// reassociation request and probe response frames ++//------------------------------------------------------------ ++ ++// ++// Operation mode value ++// ++#define HT_OPMODE_NO_PROTECT 0 ++#define HT_OPMODE_OPTIONAL 1 ++#define HT_OPMODE_40MHZ_PROTECT 2 ++#define HT_OPMODE_MIXED 3 ++ ++// ++// MIMO Power Save Setings ++// ++#define MIMO_PS_STATIC 0 ++#define MIMO_PS_DYNAMIC 1 ++#define MIMO_PS_NOLIMIT 3 ++ ++ ++// ++// There should be 128 bits to cover all of the MCS rates. However, since ++// 8190 does not support too much rates, one integer is quite enough. ++// ++ ++#define sHTCLng 4 ++ ++ ++#define HT_SUPPORTED_MCS_1SS_BITMAP 0x000000ff ++#define HT_SUPPORTED_MCS_2SS_BITMAP 0x0000ff00 ++#define HT_SUPPORTED_MCS_1SS_2SS_BITMAP HT_MCS_1SS_BITMAP|HT_MCS_1SS_2SS_BITMAP ++ ++ ++typedef enum _HT_MCS_RATE{ ++ HT_MCS0 = 0x00000001, ++ HT_MCS1 = 0x00000002, ++ HT_MCS2 = 0x00000004, ++ HT_MCS3 = 0x00000008, ++ HT_MCS4 = 0x00000010, ++ HT_MCS5 = 0x00000020, ++ HT_MCS6 = 0x00000040, ++ HT_MCS7 = 0x00000080, ++ HT_MCS8 = 0x00000100, ++ HT_MCS9 = 0x00000200, ++ HT_MCS10 = 0x00000400, ++ HT_MCS11 = 0x00000800, ++ HT_MCS12 = 0x00001000, ++ HT_MCS13 = 0x00002000, ++ HT_MCS14 = 0x00004000, ++ HT_MCS15 = 0x00008000, ++ // Do not define MCS32 here although 8190 support MCS32 ++}HT_MCS_RATE,*PHT_MCS_RATE; ++ ++// ++// Represent Channel Width in HT Capabilities ++// ++typedef enum _HT_CHANNEL_WIDTH{ ++ HT_CHANNEL_WIDTH_20 = 0, ++ HT_CHANNEL_WIDTH_20_40 = 1, ++}HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; ++ ++// ++// Represent Extention Channel Offset in HT Capabilities ++// This is available only in 40Mhz mode. ++// ++typedef enum _HT_EXTCHNL_OFFSET{ ++ HT_EXTCHNL_OFFSET_NO_EXT = 0, ++ HT_EXTCHNL_OFFSET_UPPER = 1, ++ HT_EXTCHNL_OFFSET_NO_DEF = 2, ++ HT_EXTCHNL_OFFSET_LOWER = 3, ++}HT_EXTCHNL_OFFSET, *PHT_EXTCHNL_OFFSET; ++ ++typedef enum _CHNLOP{ ++ CHNLOP_NONE = 0, // No Action now ++ CHNLOP_SCAN = 1, // Scan in progress ++ CHNLOP_SWBW = 2, // Bandwidth switching in progress ++ CHNLOP_SWCHNL = 3, // Software Channel switching in progress ++} CHNLOP, *PCHNLOP; ++ ++// Determine if the Channel Operation is in progress ++#define CHHLOP_IN_PROGRESS(_pHTInfo) \ ++ ((_pHTInfo)->ChnlOp > CHNLOP_NONE) ? TRUE : FALSE ++ ++/* ++typedef union _HT_CAPABILITY{ ++ u16 ShortData; ++ u8 CharData[2]; ++ struct ++ { ++ u16 AdvCoding:1; ++ u16 ChlWidth:1; ++ u16 MimoPwrSave:2; ++ u16 GreenField:1; ++ u16 ShortGI20Mhz:1; ++ u16 ShortGI40Mhz:1; ++ u16 STBC:1; ++ u16 BeamForm:1; ++ u16 DelayBA:1; ++ u16 MaxAMSDUSize:1; ++ u16 DssCCk:1; ++ u16 PSMP:1; ++ u16 Rsvd:3; ++ }Field; ++}HT_CAPABILITY, *PHT_CAPABILITY; ++ ++typedef union _HT_CAPABILITY_MACPARA{ ++ u8 ShortData; ++ u8 CharData[1]; ++ struct ++ { ++ u8 MaxRxAMPDU:2; ++ u8 MPDUDensity:2; ++ u8 Rsvd:4; ++ }Field; ++}HT_CAPABILITY_MACPARA, *PHT_CAPABILITY_MACPARA; ++*/ ++ ++typedef enum _HT_ACTION{ ++ ACT_RECOMMAND_WIDTH = 0, ++ ACT_MIMO_PWR_SAVE = 1, ++ ACT_PSMP = 2, ++ ACT_SET_PCO_PHASE = 3, ++ ACT_MIMO_CHL_MEASURE = 4, ++ ACT_RECIPROCITY_CORRECT = 5, ++ ACT_MIMO_CSI_MATRICS = 6, ++ ACT_MIMO_NOCOMPR_STEER = 7, ++ ACT_MIMO_COMPR_STEER = 8, ++ ACT_ANTENNA_SELECT = 9, ++} HT_ACTION, *PHT_ACTION; ++ ++ ++/* 2007/06/07 MH Define sub-carrier mode for 40MHZ. */ ++typedef enum _HT_Bandwidth_40MHZ_Sub_Carrier{ ++ SC_MODE_DUPLICATE = 0, ++ SC_MODE_LOWER = 1, ++ SC_MODE_UPPER = 2, ++ SC_MODE_FULL40MHZ = 3, ++}HT_BW40_SC_E; ++ ++typedef struct _HT_CAPABILITY_ELE{ ++ ++ //HT capability info ++ u8 AdvCoding:1; ++ u8 ChlWidth:1; ++ u8 MimoPwrSave:2; ++ u8 GreenField:1; ++ u8 ShortGI20Mhz:1; ++ u8 ShortGI40Mhz:1; ++ u8 TxSTBC:1; ++ u8 RxSTBC:2; ++ u8 DelayBA:1; ++ u8 MaxAMSDUSize:1; ++ u8 DssCCk:1; ++ u8 PSMP:1; ++ u8 Rsvd1:1; ++ u8 LSigTxopProtect:1; ++ ++ //MAC HT parameters info ++ u8 MaxRxAMPDUFactor:2; ++ u8 MPDUDensity:3; ++ u8 Rsvd2:3; ++ ++ //Supported MCS set ++ u8 MCS[16]; ++ ++ ++ //Extended HT Capability Info ++ u16 ExtHTCapInfo; ++ ++ //TXBF Capabilities ++ u8 TxBFCap[4]; ++ ++ //Antenna Selection Capabilities ++ u8 ASCap; ++ ++} __attribute__ ((packed)) HT_CAPABILITY_ELE, *PHT_CAPABILITY_ELE; ++ ++//------------------------------------------------------------ ++// The HT Information element is present in beacons ++// Only AP is required to include this element ++//------------------------------------------------------------ ++ ++typedef struct _HT_INFORMATION_ELE{ ++ u8 ControlChl; ++ ++ u8 ExtChlOffset:2; ++ u8 RecommemdedTxWidth:1; ++ u8 RIFS:1; ++ u8 PSMPAccessOnly:1; ++ u8 SrvIntGranularity:3; ++ ++ u8 OptMode:2; ++ u8 NonGFDevPresent:1; ++ u8 Revd1:5; ++ u8 Revd2:8; ++ ++ u8 Rsvd3:6; ++ u8 DualBeacon:1; ++ u8 DualCTSProtect:1; ++ ++ u8 SecondaryBeacon:1; ++ u8 LSigTxopProtectFull:1; ++ u8 PcoActive:1; ++ u8 PcoPhase:1; ++ u8 Rsvd4:4; ++ ++ u8 BasicMSC[16]; ++} __attribute__ ((packed)) HT_INFORMATION_ELE, *PHT_INFORMATION_ELE; ++ ++// ++// MIMO Power Save control field. ++// This is appear in MIMO Power Save Action Frame ++// ++typedef struct _MIMOPS_CTRL{ ++ u8 MimoPsEnable:1; ++ u8 MimoPsMode:1; ++ u8 Reserved:6; ++} MIMOPS_CTRL, *PMIMOPS_CTRL; ++ ++typedef enum _HT_SPEC_VER{ ++ HT_SPEC_VER_IEEE = 0, ++ HT_SPEC_VER_EWC = 1, ++}HT_SPEC_VER, *PHT_SPEC_VER; ++ ++typedef enum _HT_AGGRE_MODE_E{ ++ HT_AGG_AUTO = 0, ++ HT_AGG_FORCE_ENABLE = 1, ++ HT_AGG_FORCE_DISABLE = 2, ++}HT_AGGRE_MODE_E, *PHT_AGGRE_MODE_E; ++ ++//------------------------------------------------------------ ++// The Data structure is used to keep HT related variables when card is ++// configured as non-AP STA mode. **Note** Current_xxx should be set ++// to default value in HTInitializeHTInfo() ++//------------------------------------------------------------ ++ ++typedef struct _RT_HIGH_THROUGHPUT{ ++ u8 bEnableHT; ++ u8 bCurrentHTSupport; ++ ++ u8 bRegBW40MHz; // Tx 40MHz channel capablity ++ u8 bCurBW40MHz; // Tx 40MHz channel capability ++ ++ u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz ++ u8 bCurShortGI40MHz; // Tx Short GI for 40MHz ++ ++ u8 bRegShortGI20MHz; // Tx Short GI for 20MHz ++ u8 bCurShortGI20MHz; // Tx Short GI for 20MHz ++ ++ u8 bRegSuppCCK; // Tx CCK rate capability ++ u8 bCurSuppCCK; // Tx CCK rate capability ++ ++ // 802.11n spec version for "peer" ++ HT_SPEC_VER ePeerHTSpecVer; ++ ++ ++ // HT related information for "Self" ++ HT_CAPABILITY_ELE SelfHTCap; // This is HT cap element sent to peer STA, which also indicate HT Rx capabilities. ++ HT_INFORMATION_ELE SelfHTInfo; // This is HT info element sent to peer STA, which also indicate HT Rx capabilities. ++ ++ // HT related information for "Peer" ++ u8 PeerHTCapBuf[32]; ++ u8 PeerHTInfoBuf[32]; ++ ++ ++ // A-MSDU related ++ u8 bAMSDU_Support; // This indicates Tx A-MSDU capability ++ u16 nAMSDU_MaxSize; // This indicates Tx A-MSDU capability ++ u8 bCurrent_AMSDU_Support; // This indicates Tx A-MSDU capability ++ u16 nCurrent_AMSDU_MaxSize; // This indicates Tx A-MSDU capability ++ ++ ++ // AMPDU related <2006.08.10 Emily> ++ u8 bAMPDUEnable; // This indicate Tx A-MPDU capability ++ u8 bCurrentAMPDUEnable; // This indicate Tx A-MPDU capability ++ u8 AMPDU_Factor; // This indicate Tx A-MPDU capability ++ u8 CurrentAMPDUFactor; // This indicate Tx A-MPDU capability ++ u8 MPDU_Density; // This indicate Tx A-MPDU capability ++ u8 CurrentMPDUDensity; // This indicate Tx A-MPDU capability ++ ++ // Forced A-MPDU enable ++ HT_AGGRE_MODE_E ForcedAMPDUMode; ++ u8 ForcedAMPDUFactor; ++ u8 ForcedMPDUDensity; ++ ++ // Forced A-MSDU enable ++ HT_AGGRE_MODE_E ForcedAMSDUMode; ++ u16 ForcedAMSDUMaxSize; ++ ++ u8 bForcedShortGI; ++ ++ u8 CurrentOpMode; ++ ++ // MIMO PS related ++ u8 SelfMimoPs; ++ u8 PeerMimoPs; ++ ++ // 40MHz Channel Offset settings. ++ HT_EXTCHNL_OFFSET CurSTAExtChnlOffset; ++ u8 bCurTxBW40MHz; // If we use 40 MHz to Tx ++ u8 PeerBandwidth; ++ ++ // For Bandwidth Switching ++ u8 bSwBwInProgress; ++ CHNLOP ChnlOp; // software switching channel in progress. By Bruce, 2008-02-15. ++ u8 SwBwStep; ++ //struct timer_list SwBwTimer; //moved to ieee80211_device. as timer_list need include some header file here. ++ ++ // For Realtek proprietary A-MPDU factor for aggregation ++ u8 bRegRT2RTAggregation; ++ u8 bCurrentRT2RTAggregation; ++ u8 bCurrentRT2RTLongSlotTime; ++ u8 szRT2RTAggBuffer[10]; ++ ++ // Rx Reorder control ++ u8 bRegRxReorderEnable; ++ u8 bCurRxReorderEnable; ++ u8 RxReorderWinSize; ++ u8 RxReorderPendingTime; ++ u16 RxReorderDropCounter; ++ ++#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE ++ u8 UsbTxAggrNum; ++#endif ++#ifdef USB_RX_AGGREGATION_SUPPORT ++ u8 UsbRxFwAggrEn; ++ u8 UsbRxFwAggrPageNum; ++ u8 UsbRxFwAggrPacketNum; ++ u8 UsbRxFwAggrTimeout; ++#endif ++ ++ // Add for Broadcom(Linksys) IOT. Joseph ++ u8 bIsPeerBcm; ++ ++ // For IOT issue. ++ u8 IOTPeer; ++ u32 IOTAction; ++} __attribute__ ((packed)) RT_HIGH_THROUGHPUT, *PRT_HIGH_THROUGHPUT; ++ ++ ++//------------------------------------------------------------ ++// The Data structure is used to keep HT related variable for "each Sta" ++// when card is configured as "AP mode" ++//------------------------------------------------------------ ++ ++typedef struct _RT_HTINFO_STA_ENTRY{ ++ u8 bEnableHT; ++ ++ u8 bSupportCck; ++ ++ u16 AMSDU_MaxSize; ++ ++ u8 AMPDU_Factor; ++ u8 MPDU_Density; ++ ++ u8 HTHighestOperaRate; ++ ++ u8 bBw40MHz; ++ ++ u8 MimoPs; ++ ++ u8 McsRateSet[16]; ++ ++ ++}RT_HTINFO_STA_ENTRY, *PRT_HTINFO_STA_ENTRY; ++ ++ ++ ++ ++ ++//------------------------------------------------------------ ++// The Data structure is used to keep HT related variable for "each AP" ++// when card is configured as "STA mode" ++//------------------------------------------------------------ ++ ++typedef struct _BSS_HT{ ++ ++ u8 bdSupportHT; ++ ++ // HT related elements ++ u8 bdHTCapBuf[32]; ++ u16 bdHTCapLen; ++ u8 bdHTInfoBuf[32]; ++ u16 bdHTInfoLen; ++ ++ HT_SPEC_VER bdHTSpecVer; ++ //HT_CAPABILITY_ELE bdHTCapEle; ++ //HT_INFORMATION_ELE bdHTInfoEle; ++ ++ u8 bdRT2RTAggregation; ++ u8 bdRT2RTLongSlotTime; ++} __attribute__ ((packed)) BSS_HT, *PBSS_HT; ++ ++typedef struct _MIMO_RSSI{ ++ u32 EnableAntenna; ++ u32 AntennaA; ++ u32 AntennaB; ++ u32 AntennaC; ++ u32 AntennaD; ++ u32 Average; ++}MIMO_RSSI, *PMIMO_RSSI; ++ ++typedef struct _MIMO_EVM{ ++ u32 EVM1; ++ u32 EVM2; ++}MIMO_EVM, *PMIMO_EVM; ++ ++typedef struct _FALSE_ALARM_STATISTICS{ ++ u32 Cnt_Parity_Fail; ++ u32 Cnt_Rate_Illegal; ++ u32 Cnt_Crc8_fail; ++ u32 Cnt_all; ++}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; ++ ++ ++extern u8 MCS_FILTER_ALL[16]; ++extern u8 MCS_FILTER_1SS[16]; ++ ++/* 2007/07/11 MH Modify the macro. Becaus STA may link with a N-AP. If we set ++ STA in A/B/G mode and AP is still in N mode. The macro will be wrong. We have ++ to add a macro to judge wireless mode. */ ++#define PICK_RATE(_nLegacyRate, _nMcsRate) \ ++ (_nMcsRate==0)?(_nLegacyRate&0x7f):(_nMcsRate) ++/* 2007/07/12 MH We only define legacy and HT wireless mode now. */ ++#define LEGACY_WIRELESS_MODE IEEE_MODE_MASK ++ ++#define CURRENT_RATE(WirelessMode, LegacyRate, HTRate) \ ++ ((WirelessMode & (LEGACY_WIRELESS_MODE))!=0)?\ ++ (LegacyRate):\ ++ (PICK_RATE(LegacyRate, HTRate)) ++ ++ ++ ++// MCS Bw 40 {1~7, 12~15,32} ++#define RATE_ADPT_1SS_MASK 0xFF ++#define RATE_ADPT_2SS_MASK 0xF0 //Skip MCS8~11 because mcs7 > mcs6, 9, 10, 11. 2007.01.16 by Emily ++#define RATE_ADPT_MCS32_MASK 0x01 ++ ++#define IS_11N_MCS_RATE(rate) (rate&0x80) ++ ++typedef enum _HT_AGGRE_SIZE{ ++ HT_AGG_SIZE_8K = 0, ++ HT_AGG_SIZE_16K = 1, ++ HT_AGG_SIZE_32K = 2, ++ HT_AGG_SIZE_64K = 3, ++}HT_AGGRE_SIZE_E, *PHT_AGGRE_SIZE_E; ++ ++/* Indicate different AP vendor for IOT issue */ ++typedef enum _HT_IOT_PEER ++{ ++ HT_IOT_PEER_UNKNOWN = 0, ++ HT_IOT_PEER_REALTEK = 1, ++ HT_IOT_PEER_BROADCOM = 2, ++ HT_IOT_PEER_RALINK = 3, ++ HT_IOT_PEER_ATHEROS = 4, ++ HT_IOT_PEER_CISCO= 5, ++ HT_IOT_PEER_MAX = 6 ++}HT_IOT_PEER_E, *PHTIOT_PEER_E; ++ ++// ++// IOT Action for different AP ++// ++typedef enum _HT_IOT_ACTION{ ++ HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001, ++ HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002, ++ HT_IOT_ACT_DISABLE_MCS14 = 0x00000004, ++ HT_IOT_ACT_DISABLE_MCS15 = 0x00000008, ++ HT_IOT_ACT_DISABLE_ALL_2SS = 0x00000010, ++ HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000020, ++ HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000040, ++ HT_IOT_ACT_CDD_FSYNC = 0x00000080, ++ HT_IOT_ACT_PURE_N_MODE = 0x00000100, ++ HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200, ++}HT_IOT_ACTION_E, *PHT_IOT_ACTION_E; ++ ++#endif //_RTL819XU_HTTYPE_H_ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c +@@ -0,0 +1,1719 @@ ++ ++//As this function is mainly ported from Windows driver, so leave the name little changed. If any confusion caused, tell me. Created by WB. 2008.05.08 ++#include "ieee80211.h" ++#include "rtl819x_HT.h" ++u8 MCS_FILTER_ALL[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++u8 MCS_FILTER_1SS[16] = {0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++u16 MCS_DATA_RATE[2][2][77] = ++ { { {13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78 ,104, 156, 208, 234, 260, ++ 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, 468, 520, ++ 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182, 182, 208, 156, 195, ++ 195, 234, 273, 273, 312, 130, 156, 181, 156, 181, 208, 234, 208, 234, 260, 260, ++ 286, 195, 234, 273, 234, 273, 312, 351, 312, 351, 390, 390, 429}, // Long GI, 20MHz ++ {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289, ++ 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, 578, ++ 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, 173, 217, ++ 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, 231, 260, 289, 289, ++ 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, 433, 433, 477} }, // Short GI, 20MHz ++ { {27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, ++ 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, 864, 972, 1080, ++ 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, 378, 378, 432, 324, 405, ++ 405, 486, 567, 567, 648, 270, 324, 378, 324, 378, 432, 486, 432, 486, 540, 540, ++ 594, 405, 486, 567, 486, 567, 648, 729, 648, 729, 810, 810, 891}, // Long GI, 40MHz ++ {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, ++ 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, 960, 1080, 1200, ++ 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, 420, 420, 480, 360, 450, ++ 450, 540, 630, 630, 720, 300, 360, 420, 360, 420, 480, 540, 480, 540, 600, 600, ++ 660, 450, 540, 630, 540, 630, 720, 810, 720, 810, 900, 900, 990} } // Short GI, 40MHz ++ }; ++ ++static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf}; ++static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70}; ++static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e}; ++static u8 NETGEAR834Bv2_BROADCOM[3] = {0x00, 0x1b, 0x2f}; ++static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; //cosa 03202008 ++static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf}; ++static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc}; ++static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e}; ++static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02}; ++static u8 DLINK_ATHEROS[3] = {0x00, 0x1c, 0xf0}; ++static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94}; ++ ++// 2008/04/01 MH For Cisco G mode RX TP We need to change FW duration. Shoud we put the ++// code in other place?? ++//static u8 WIFI_CISCO_G_AP[3] = {0x00, 0x40, 0x96}; ++/******************************************************************************************************************** ++ *function: This function update default settings in pHTInfo structure ++ * input: PRT_HIGH_THROUGHPUT pHTInfo ++ * output: none ++ * return: none ++ * notice: These value need be modified if any changes. ++ * *****************************************************************************************************************/ ++void HTUpdateDefaultSetting(struct ieee80211_device* ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ //const typeof( ((struct ieee80211_device *)0)->pHTInfo ) *__mptr = &pHTInfo; ++ ++ //printk("pHTinfo:%p, &pHTinfo:%p, mptr:%p, offsetof:%x\n", pHTInfo, &pHTInfo, __mptr, offsetof(struct ieee80211_device, pHTInfo)); ++ //printk("===>ieee:%p,\n", ieee); ++ // ShortGI support ++ pHTInfo->bRegShortGI20MHz= 1; ++ pHTInfo->bRegShortGI40MHz= 1; ++ ++ // 40MHz channel support ++ pHTInfo->bRegBW40MHz = 1; ++ ++ // CCK rate support in 40MHz channel ++ if(pHTInfo->bRegBW40MHz) ++ pHTInfo->bRegSuppCCK = 1; ++ else ++ pHTInfo->bRegSuppCCK = true; ++ ++ // AMSDU related ++ pHTInfo->nAMSDU_MaxSize = 7935UL; ++ pHTInfo->bAMSDU_Support = 0; ++ ++ // AMPDU related ++ pHTInfo->bAMPDUEnable = 1; ++ pHTInfo->AMPDU_Factor = 2; //// 0: 2n13(8K), 1:2n14(16K), 2:2n15(32K), 3:2n16(64k) ++ pHTInfo->MPDU_Density = 0;// 0: No restriction, 1: 1/8usec, 2: 1/4usec, 3: 1/2usec, 4: 1usec, 5: 2usec, 6: 4usec, 7:8usec ++ ++ // MIMO Power Save ++ pHTInfo->SelfMimoPs = 3;// 0: Static Mimo Ps, 1: Dynamic Mimo Ps, 3: No Limitation, 2: Reserved(Set to 3 automatically.) ++ if(pHTInfo->SelfMimoPs == 2) ++ pHTInfo->SelfMimoPs = 3; ++ // 8190 only. Assign rate operation mode to firmware ++ ieee->bTxDisableRateFallBack = 0; ++ ieee->bTxUseDriverAssingedRate = 0; ++ ++#ifdef TO_DO_LIST ++ // 8190 only. Assign duration operation mode to firmware ++ pMgntInfo->bTxEnableFwCalcDur = (BOOLEAN)pNdisCommon->bRegTxEnableFwCalcDur; ++#endif ++ // 8190 only, Realtek proprietary aggregation mode ++ // Set MPDUDensity=2, 1: Set MPDUDensity=2(32k) for Realtek AP and set MPDUDensity=0(8k) for others ++ pHTInfo->bRegRT2RTAggregation = 1;//0: Set MPDUDensity=2, 1: Set MPDUDensity=2(32k) for Realtek AP and set MPDUDensity=0(8k) for others ++ ++ // For Rx Reorder Control ++ pHTInfo->bRegRxReorderEnable = 1; ++ pHTInfo->RxReorderWinSize = 64; ++ pHTInfo->RxReorderPendingTime = 30; ++ ++#ifdef USB_TX_DRIVER_AGGREGATION_ENABLE ++ pHTInfo->UsbTxAggrNum = 4; ++#endif ++#ifdef USB_RX_AGGREGATION_SUPPORT ++ pHTInfo->UsbRxFwAggrEn = 1; ++ pHTInfo->UsbRxFwAggrPageNum = 24; ++ pHTInfo->UsbRxFwAggrPacketNum = 8; ++ pHTInfo->UsbRxFwAggrTimeout = 16; ////usb rx FW aggregation timeout threshold.It's in units of 64us ++#endif ++ ++ ++} ++/******************************************************************************************************************** ++ *function: This function print out each field on HT capability IE mainly from (Beacon/ProbeRsp/AssocReq) ++ * input: u8* CapIE //Capability IE to be printed out ++ * u8* TitleString //mainly print out caller function ++ * output: none ++ * return: none ++ * notice: Driver should not print out this message by default. ++ * *****************************************************************************************************************/ ++void HTDebugHTCapability(u8* CapIE, u8* TitleString ) ++{ ++ ++ static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily ++ PHT_CAPABILITY_ELE pCapELE; ++ ++ if(!memcmp(CapIE, EWC11NHTCap, sizeof(EWC11NHTCap))) ++ { ++ //EWC IE ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "EWC IE in %s()\n", __FUNCTION__); ++ pCapELE = (PHT_CAPABILITY_ELE)(&CapIE[4]); ++ }else ++ pCapELE = (PHT_CAPABILITY_ELE)(&CapIE[0]); ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, ". Called by %s\n", TitleString ); ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupported Channel Width = %s\n", (pCapELE->ChlWidth)?"20MHz": "20/40MHz"); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport Short GI for 20M = %s\n", (pCapELE->ShortGI20Mhz)?"YES": "NO"); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport Short GI for 40M = %s\n", (pCapELE->ShortGI40Mhz)?"YES": "NO"); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport TX STBC = %s\n", (pCapELE->TxSTBC)?"YES": "NO"); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMax AMSDU Size = %s\n", (pCapELE->MaxAMSDUSize)?"3839": "7935"); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSupport CCK in 20/40 mode = %s\n", (pCapELE->DssCCk)?"YES": "NO"); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMax AMPDU Factor = %d\n", pCapELE->MaxRxAMPDUFactor); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMPDU Density = %d\n", pCapELE->MPDUDensity); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tMCS Rate Set = [%x][%x][%x][%x][%x]\n", pCapELE->MCS[0],\ ++ pCapELE->MCS[1], pCapELE->MCS[2], pCapELE->MCS[3], pCapELE->MCS[4]); ++ return; ++ ++} ++/******************************************************************************************************************** ++ *function: This function print out each field on HT Information IE mainly from (Beacon/ProbeRsp) ++ * input: u8* InfoIE //Capability IE to be printed out ++ * u8* TitleString //mainly print out caller function ++ * output: none ++ * return: none ++ * notice: Driver should not print out this message by default. ++ * *****************************************************************************************************************/ ++void HTDebugHTInfo(u8* InfoIE, u8* TitleString) ++{ ++ ++ static u8 EWC11NHTInfo[] = {0x00, 0x90, 0x4c, 0x34}; // For 11n EWC definition, 2007.07.17, by Emily ++ PHT_INFORMATION_ELE pHTInfoEle; ++ ++ if(!memcmp(InfoIE, EWC11NHTInfo, sizeof(EWC11NHTInfo))) ++ { ++ // Not EWC IE ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "EWC IE in %s()\n", __FUNCTION__); ++ pHTInfoEle = (PHT_INFORMATION_ELE)(&InfoIE[4]); ++ }else ++ pHTInfoEle = (PHT_INFORMATION_ELE)(&InfoIE[0]); ++ ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, ". Called by %s\n", TitleString); ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tPrimary channel = %d\n", pHTInfoEle->ControlChl); ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tSenondary channel ="); ++ switch(pHTInfoEle->ExtChlOffset) ++ { ++ case 0: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "Not Present\n"); ++ break; ++ case 1: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "Upper channel\n"); ++ break; ++ case 2: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "Reserved. Eooro!!!\n"); ++ break; ++ case 3: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "Lower Channel\n"); ++ break; ++ } ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tRecommended channel width = %s\n", (pHTInfoEle->RecommemdedTxWidth)?"20Mhz": "40Mhz"); ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tOperation mode for protection = "); ++ switch(pHTInfoEle->OptMode) ++ { ++ case 0: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "No Protection\n"); ++ break; ++ case 1: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "HT non-member protection mode\n"); ++ break; ++ case 2: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "Suggest to open protection\n"); ++ break; ++ case 3: ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "HT mixed mode\n"); ++ break; ++ } ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "\tBasic MCS Rate Set = [%x][%x][%x][%x][%x]\n", pHTInfoEle->BasicMSC[0],\ ++ pHTInfoEle->BasicMSC[1], pHTInfoEle->BasicMSC[2], pHTInfoEle->BasicMSC[3], pHTInfoEle->BasicMSC[4]); ++ return; ++} ++ ++/* ++* Return: true if station in half n mode and AP supports 40 bw ++*/ ++bool IsHTHalfNmode40Bandwidth(struct ieee80211_device* ieee) ++{ ++ bool retValue = false; ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ if(pHTInfo->bCurrentHTSupport == false ) // wireless is n mode ++ retValue = false; ++ else if(pHTInfo->bRegBW40MHz == false) // station supports 40 bw ++ retValue = false; ++ else if(!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode ++ retValue = false; ++ else if(((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ChlWidth) // ap support 40 bw ++ retValue = true; ++ else ++ retValue = false; ++ ++ return retValue; ++} ++ ++bool IsHTHalfNmodeSGI(struct ieee80211_device* ieee, bool is40MHz) ++{ ++ bool retValue = false; ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ if(pHTInfo->bCurrentHTSupport == false ) // wireless is n mode ++ retValue = false; ++ else if(!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode ++ retValue = false; ++ else if(is40MHz) // ap support 40 bw ++ { ++ if(((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ShortGI40Mhz) // ap support 40 bw short GI ++ retValue = true; ++ else ++ retValue = false; ++ } ++ else ++ { ++ if(((PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf))->ShortGI20Mhz) // ap support 40 bw short GI ++ retValue = true; ++ else ++ retValue = false; ++ } ++ ++ return retValue; ++} ++ ++u16 HTHalfMcsToDataRate(struct ieee80211_device* ieee, u8 nMcsRate) ++{ ++ ++ u8 is40MHz; ++ u8 isShortGI; ++ ++ is40MHz = (IsHTHalfNmode40Bandwidth(ieee))?1:0; ++ isShortGI = (IsHTHalfNmodeSGI(ieee, is40MHz))? 1:0; ++ ++ return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate&0x7f)]; ++} ++ ++ ++u16 HTMcsToDataRate( struct ieee80211_device* ieee, u8 nMcsRate) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ u8 is40MHz = (pHTInfo->bCurBW40MHz)?1:0; ++ u8 isShortGI = (pHTInfo->bCurBW40MHz)? ++ ((pHTInfo->bCurShortGI40MHz)?1:0): ++ ((pHTInfo->bCurShortGI20MHz)?1:0); ++ return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate&0x7f)]; ++} ++ ++/******************************************************************************************************************** ++ *function: This function returns current datarate. ++ * input: struct ieee80211_device* ieee ++ * u8 nDataRate ++ * output: none ++ * return: tx rate ++ * notice: quite unsure about how to use this function //wb ++ * *****************************************************************************************************************/ ++u16 TxCountToDataRate( struct ieee80211_device* ieee, u8 nDataRate) ++{ ++ //PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ u16 CCKOFDMRate[12] = {0x02 , 0x04 , 0x0b , 0x16 , 0x0c , 0x12 , 0x18 , 0x24 , 0x30 , 0x48 , 0x60 , 0x6c}; ++ u8 is40MHz = 0; ++ u8 isShortGI = 0; ++ ++ if(nDataRate < 12) ++ { ++ return CCKOFDMRate[nDataRate]; ++ } ++ else ++ { ++ if (nDataRate >= 0x10 && nDataRate <= 0x1f)//if(nDataRate > 11 && nDataRate < 28 ) ++ { ++ is40MHz = 0; ++ isShortGI = 0; ++ ++ // nDataRate = nDataRate - 12; ++ } ++ else if(nDataRate >=0x20 && nDataRate <= 0x2f ) //(27, 44) ++ { ++ is40MHz = 1; ++ isShortGI = 0; ++ ++ //nDataRate = nDataRate - 28; ++ } ++ else if(nDataRate >= 0x30 && nDataRate <= 0x3f ) //(43, 60) ++ { ++ is40MHz = 0; ++ isShortGI = 1; ++ ++ //nDataRate = nDataRate - 44; ++ } ++ else if(nDataRate >= 0x40 && nDataRate <= 0x4f ) //(59, 76) ++ { ++ is40MHz = 1; ++ isShortGI = 1; ++ ++ //nDataRate = nDataRate - 60; ++ } ++ return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate&0xf]; ++ } ++} ++ ++ ++ ++bool IsHTHalfNmodeAPs(struct ieee80211_device* ieee) ++{ ++ bool retValue = false; ++ struct ieee80211_network* net = &ieee->current_network; ++#if 0 ++ if(pMgntInfo->bHalfNMode == false) ++ retValue = false; ++ else ++#endif ++ if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) || ++ (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) || ++ (memcmp(net->bssid, PCI_RALINK, 3)==0) || ++ (memcmp(net->bssid, EDIMAX_RALINK, 3)==0) || ++ (memcmp(net->bssid, AIRLINK_RALINK, 3)==0) || ++ (net->ralink_cap_exist)) ++ retValue = true; ++ else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) || ++ (memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)|| ++ (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)|| ++ (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) || ++ (net->broadcom_cap_exist)) ++ retValue = true; ++ else if(net->bssht.bdRT2RTAggregation) ++ retValue = true; ++ else ++ retValue = false; ++ ++ return retValue; ++} ++ ++/******************************************************************************************************************** ++ *function: This function returns peer IOT. ++ * input: struct ieee80211_device* ieee ++ * output: none ++ * return: ++ * notice: ++ * *****************************************************************************************************************/ ++void HTIOTPeerDetermine(struct ieee80211_device* ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ struct ieee80211_network* net = &ieee->current_network; ++ if(net->bssht.bdRT2RTAggregation) ++ pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK; ++ else if(net->broadcom_cap_exist) ++ pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; ++ else if((memcmp(net->bssid, UNKNOWN_BORADCOM, 3)==0) || ++ (memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)|| ++ (memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)|| ++ (memcmp(net->bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ) ++ pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; ++ else if((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3)==0) || ++ (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3)==0) || ++ (memcmp(net->bssid, PCI_RALINK, 3)==0) || ++ (memcmp(net->bssid, EDIMAX_RALINK, 3)==0) || ++ (memcmp(net->bssid, AIRLINK_RALINK, 3)==0) || ++ net->ralink_cap_exist) ++ pHTInfo->IOTPeer = HT_IOT_PEER_RALINK; ++ else if((net->atheros_cap_exist )|| (memcmp(net->bssid, DLINK_ATHEROS, 3) == 0)) ++ pHTInfo->IOTPeer = HT_IOT_PEER_ATHEROS; ++ else if(memcmp(net->bssid, CISCO_BROADCOM, 3)==0) ++ pHTInfo->IOTPeer = HT_IOT_PEER_CISCO; ++ else ++ pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; ++ ++ IEEE80211_DEBUG(IEEE80211_DL_IOT, "Joseph debug!! IOTPEER: %x\n", pHTInfo->IOTPeer); ++} ++/******************************************************************************************************************** ++ *function: Check whether driver should declare received rate up to MCS13 only since some chipset is not good ++ * at receiving MCS14~15 frame from some AP. ++ * input: struct ieee80211_device* ieee ++ * u8 * PeerMacAddr ++ * output: none ++ * return: return 1 if driver should declare MCS13 only(otherwise return 0) ++ * *****************************************************************************************************************/ ++u8 HTIOTActIsDisableMCS14(struct ieee80211_device* ieee, u8* PeerMacAddr) ++{ ++ u8 ret = 0; ++#if 0 ++ // Apply for 819u only ++#if (HAL_CODE_BASE==RTL8192 && DEV_BUS_TYPE==USB_INTERFACE) ++ if((memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0) || ++ (memcmp(PeerMacAddr, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0) ++ ) ++ { ++ ret = 1; ++ } ++ ++ ++ if(pHTInfo->bCurrentRT2RTAggregation) ++ { ++ // The parameter of pHTInfo->bCurrentRT2RTAggregation must be decided previously ++ ret = 1; ++ } ++#endif ++#endif ++ return ret; ++ } ++ ++ ++/** ++* Function: HTIOTActIsDisableMCS15 ++* ++* Overview: Check whether driver should declare capability of receving MCS15 ++* ++* Input: ++* PADAPTER Adapter, ++* ++* Output: None ++* Return: true if driver should disable MCS15 ++* 2008.04.15 Emily ++*/ ++bool HTIOTActIsDisableMCS15(struct ieee80211_device* ieee) ++{ ++ bool retValue = false; ++ ++#ifdef TODO ++ // Apply for 819u only ++#if (HAL_CODE_BASE==RTL8192) ++ ++#if (DEV_BUS_TYPE == USB_INTERFACE) ++ // Alway disable MCS15 by Jerry Chang's request.by Emily, 2008.04.15 ++ retValue = true; ++#elif (DEV_BUS_TYPE == PCI_INTERFACE) ++ // Enable MCS15 if the peer is Cisco AP. by Emily, 2008.05.12 ++// if(pBssDesc->bCiscoCapExist) ++// retValue = false; ++// else ++ retValue = false; ++#endif ++#endif ++#endif ++ // Jerry Chang suggest that 8190 1x2 does not need to disable MCS15 ++ ++ return retValue; ++} ++ ++/** ++* Function: HTIOTActIsDisableMCSTwoSpatialStream ++* ++* Overview: Check whether driver should declare capability of receving All 2 ss packets ++* ++* Input: ++* PADAPTER Adapter, ++* ++* Output: None ++* Return: true if driver should disable all two spatial stream packet ++* 2008.04.21 Emily ++*/ ++bool HTIOTActIsDisableMCSTwoSpatialStream(struct ieee80211_device* ieee, u8 *PeerMacAddr) ++{ ++ bool retValue = false; ++ ++#ifdef TODO ++ // Apply for 819u only ++//#if (HAL_CODE_BASE==RTL8192) ++ ++ //This rule only apply to Belkin(Ralink) AP ++ if(IS_UNDER_11N_AES_MODE(Adapter)) ++ { ++ if((PlatformCompareMemory(PeerMacAddr, BELKINF5D8233V1_RALINK, 3)==0) || ++ (PlatformCompareMemory(PeerMacAddr, PCI_RALINK, 3)==0) || ++ (PlatformCompareMemory(PeerMacAddr, EDIMAX_RALINK, 3)==0)) ++ { ++ //Set True to disable this function. Disable by default, Emily, 2008.04.23 ++ retValue = false; ++ } ++ } ++ ++//#endif ++#endif ++ return retValue; ++} ++ ++/******************************************************************************************************************** ++ *function: Check whether driver should disable EDCA turbo mode ++ * input: struct ieee80211_device* ieee ++ * u8* PeerMacAddr ++ * output: none ++ * return: return 1 if driver should disable EDCA turbo mode(otherwise return 0) ++ * *****************************************************************************************************************/ ++u8 HTIOTActIsDisableEDCATurbo(struct ieee80211_device* ieee, u8* PeerMacAddr) ++{ ++ u8 retValue = false; // default enable EDCA Turbo mode. ++ // Set specific EDCA parameter for different AP in DM handler. ++ ++ return retValue; ++#if 0 ++ if((memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0)|| ++ (memcmp(PeerMacAddr, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0)|| ++ (memcmp(PeerMacAddr, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)==0)|| ++ (memcmp(PeerMacAddr, NETGEAR834Bv2_BROADCOM, 3)==0)) ++ ++ { ++ retValue = 1; //Linksys disable EDCA turbo mode ++ } ++ ++ return retValue; ++#endif ++} ++ ++/******************************************************************************************************************** ++ *function: Check whether we need to use OFDM to sned MGNT frame for broadcom AP ++ * input: struct ieee80211_network *network //current network we live ++ * output: none ++ * return: return 1 if true ++ * *****************************************************************************************************************/ ++u8 HTIOTActIsMgntUseCCK6M(struct ieee80211_network *network) ++{ ++ u8 retValue = 0; ++ ++ // 2008/01/25 MH Judeg if we need to use OFDM to sned MGNT frame for broadcom AP. ++ // 2008/01/28 MH We must prevent that we select null bssid to link. ++ ++ if(network->broadcom_cap_exist) ++ { ++ retValue = 1; ++ } ++ ++ return retValue; ++} ++ ++u8 HTIOTActIsCCDFsync(u8* PeerMacAddr) ++{ ++ u8 retValue = 0; ++ if( (memcmp(PeerMacAddr, UNKNOWN_BORADCOM, 3)==0) || ++ (memcmp(PeerMacAddr, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3)==0) || ++ (memcmp(PeerMacAddr, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) ==0)) ++ { ++ retValue = 1; ++ } ++ ++ return retValue; ++} ++ ++void HTResetIOTSetting( ++ PRT_HIGH_THROUGHPUT pHTInfo ++) ++{ ++ pHTInfo->IOTAction = 0; ++ pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; ++} ++ ++ ++/******************************************************************************************************************** ++ *function: Construct Capablility Element in Beacon... if HTEnable is turned on ++ * input: struct ieee80211_device* ieee ++ * u8* posHTCap //pointer to store Capability Ele ++ * u8* len //store length of CE ++ * u8 IsEncrypt //whether encrypt, needed further ++ * output: none ++ * return: none ++ * notice: posHTCap can't be null and should be initialized before. ++ * *****************************************************************************************************************/ ++void HTConstructCapabilityElement(struct ieee80211_device* ieee, u8* posHTCap, u8* len, u8 IsEncrypt) ++{ ++ PRT_HIGH_THROUGHPUT pHT = ieee->pHTInfo; ++ PHT_CAPABILITY_ELE pCapELE = NULL; ++ //u8 bIsDeclareMCS13; ++ ++ if ((posHTCap == NULL) || (pHT == NULL)) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "posHTCap or pHTInfo can't be null in HTConstructCapabilityElement()\n"); ++ return; ++ } ++ memset(posHTCap, 0, *len); ++ if(pHT->ePeerHTSpecVer == HT_SPEC_VER_EWC) ++ { ++ u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily ++ memcpy(posHTCap, EWC11NHTCap, sizeof(EWC11NHTCap)); ++ pCapELE = (PHT_CAPABILITY_ELE)&(posHTCap[4]); ++ }else ++ { ++ pCapELE = (PHT_CAPABILITY_ELE)posHTCap; ++ } ++ ++ ++ //HT capability info ++ pCapELE->AdvCoding = 0; // This feature is not supported now!! ++ if(ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) ++ { ++ pCapELE->ChlWidth = 0; ++ } ++ else ++ { ++ pCapELE->ChlWidth = (pHT->bRegBW40MHz?1:0); ++ } ++ ++// pCapELE->ChlWidth = (pHT->bRegBW40MHz?1:0); ++ pCapELE->MimoPwrSave = pHT->SelfMimoPs; ++ pCapELE->GreenField = 0; // This feature is not supported now!! ++ pCapELE->ShortGI20Mhz = 1; // We can receive Short GI!! ++ pCapELE->ShortGI40Mhz = 1; // We can receive Short GI!! ++ //DbgPrint("TX HT cap/info ele BW=%d SG20=%d SG40=%d\n\r", ++ //pCapELE->ChlWidth, pCapELE->ShortGI20Mhz, pCapELE->ShortGI40Mhz); ++ pCapELE->TxSTBC = 1; ++ pCapELE->RxSTBC = 0; ++ pCapELE->DelayBA = 0; // Do not support now!! ++ pCapELE->MaxAMSDUSize = (MAX_RECEIVE_BUFFER_SIZE>=7935)?1:0; ++ pCapELE->DssCCk = ((pHT->bRegBW40MHz)?(pHT->bRegSuppCCK?1:0):0); ++ pCapELE->PSMP = 0; // Do not support now!! ++ pCapELE->LSigTxopProtect = 0; // Do not support now!! ++ ++ ++ //MAC HT parameters info ++ // TODO: Nedd to take care of this part ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "TX HT cap/info ele BW=%d MaxAMSDUSize:%d DssCCk:%d\n", pCapELE->ChlWidth, pCapELE->MaxAMSDUSize, pCapELE->DssCCk); ++ ++ if( IsEncrypt) ++ { ++ pCapELE->MPDUDensity = 7; // 8us ++ pCapELE->MaxRxAMPDUFactor = 2; // 2 is for 32 K and 3 is 64K ++ } ++ else ++ { ++ pCapELE->MaxRxAMPDUFactor = 3; // 2 is for 32 K and 3 is 64K ++ pCapELE->MPDUDensity = 0; // no density ++ } ++ ++ //Supported MCS set ++ memcpy(pCapELE->MCS, ieee->Regdot11HTOperationalRateSet, 16); ++ if(pHT->IOTAction & HT_IOT_ACT_DISABLE_MCS15) ++ pCapELE->MCS[1] &= 0x7f; ++ ++ if(pHT->IOTAction & HT_IOT_ACT_DISABLE_MCS14) ++ pCapELE->MCS[1] &= 0xbf; ++ ++ if(pHT->IOTAction & HT_IOT_ACT_DISABLE_ALL_2SS) ++ pCapELE->MCS[1] &= 0x00; ++ ++ // 2008.06.12 ++ // For RTL819X, if pairwisekey = wep/tkip, ap is ralink, we support only MCS0~7. ++ if(ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) ++ { ++ int i; ++ for(i = 1; i< 16; i++) ++ pCapELE->MCS[i] = 0; ++ } ++ ++ //Extended HT Capability Info ++ memset(&pCapELE->ExtHTCapInfo, 0, 2); ++ ++ ++ //TXBF Capabilities ++ memset(pCapELE->TxBFCap, 0, 4); ++ ++ //Antenna Selection Capabilities ++ pCapELE->ASCap = 0; ++//add 2 to give space for element ID and len when construct frames ++ if(pHT->ePeerHTSpecVer == HT_SPEC_VER_EWC) ++ *len = 30 + 2; ++ else ++ *len = 26 + 2; ++ ++ ++ ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, posHTCap, *len -2); ++ ++ //Print each field in detail. Driver should not print out this message by default ++// HTDebugHTCapability(posHTCap, (u8*)"HTConstructCapability()"); ++ return; ++ ++} ++/******************************************************************************************************************** ++ *function: Construct Information Element in Beacon... if HTEnable is turned on ++ * input: struct ieee80211_device* ieee ++ * u8* posHTCap //pointer to store Information Ele ++ * u8* len //store len of ++ * u8 IsEncrypt //whether encrypt, needed further ++ * output: none ++ * return: none ++ * notice: posHTCap can't be null and be initialized before. only AP and IBSS sta should do this ++ * *****************************************************************************************************************/ ++void HTConstructInfoElement(struct ieee80211_device* ieee, u8* posHTInfo, u8* len, u8 IsEncrypt) ++{ ++ PRT_HIGH_THROUGHPUT pHT = ieee->pHTInfo; ++ PHT_INFORMATION_ELE pHTInfoEle = (PHT_INFORMATION_ELE)posHTInfo; ++ if ((posHTInfo == NULL) || (pHTInfoEle == NULL)) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "posHTInfo or pHTInfoEle can't be null in HTConstructInfoElement()\n"); ++ return; ++ } ++ ++ memset(posHTInfo, 0, *len); ++ if ( (ieee->iw_mode == IW_MODE_ADHOC) || (ieee->iw_mode == IW_MODE_MASTER)) //ap mode is not currently supported ++ { ++ pHTInfoEle->ControlChl = ieee->current_network.channel; ++ pHTInfoEle->ExtChlOffset = ((pHT->bRegBW40MHz == false)?HT_EXTCHNL_OFFSET_NO_EXT: ++ (ieee->current_network.channel<=6)? ++ HT_EXTCHNL_OFFSET_UPPER:HT_EXTCHNL_OFFSET_LOWER); ++ pHTInfoEle->RecommemdedTxWidth = pHT->bRegBW40MHz; ++ pHTInfoEle->RIFS = 0; ++ pHTInfoEle->PSMPAccessOnly = 0; ++ pHTInfoEle->SrvIntGranularity = 0; ++ pHTInfoEle->OptMode = pHT->CurrentOpMode; ++ pHTInfoEle->NonGFDevPresent = 0; ++ pHTInfoEle->DualBeacon = 0; ++ pHTInfoEle->SecondaryBeacon = 0; ++ pHTInfoEle->LSigTxopProtectFull = 0; ++ pHTInfoEle->PcoActive = 0; ++ pHTInfoEle->PcoPhase = 0; ++ ++ memset(pHTInfoEle->BasicMSC, 0, 16); ++ ++ ++ *len = 22 + 2; //same above ++ ++ } ++ else ++ { ++ //STA should not generate High Throughput Information Element ++ *len = 0; ++ } ++ //IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA | IEEE80211_DL_HT, posHTInfo, *len - 2); ++ //HTDebugHTInfo(posHTInfo, "HTConstructInforElement"); ++ return; ++} ++ ++/* ++ * According to experiment, Realtek AP to STA (based on rtl8190) may achieve best performance ++ * if both STA and AP set limitation of aggregation size to 32K, that is, set AMPDU density to 2 ++ * (Ref: IEEE 11n specification). However, if Realtek STA associates to other AP, STA should set ++ * limitation of aggregation size to 8K, otherwise, performance of traffic stream from STA to AP ++ * will be much less than the traffic stream from AP to STA if both of the stream runs concurrently ++ * at the same time. ++ * ++ * Frame Format ++ * Element ID Length OUI Type1 Reserved ++ * 1 byte 1 byte 3 bytes 1 byte 1 byte ++ * ++ * OUI = 0x00, 0xe0, 0x4c, ++ * Type = 0x02 ++ * Reserved = 0x00 ++ * ++ * 2007.8.21 by Emily ++*/ ++/******************************************************************************************************************** ++ *function: Construct Information Element in Beacon... in RT2RT condition ++ * input: struct ieee80211_device* ieee ++ * u8* posRT2RTAgg //pointer to store Information Ele ++ * u8* len //store len ++ * output: none ++ * return: none ++ * notice: ++ * *****************************************************************************************************************/ ++void HTConstructRT2RTAggElement(struct ieee80211_device* ieee, u8* posRT2RTAgg, u8* len) ++{ ++ if (posRT2RTAgg == NULL) { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "posRT2RTAgg can't be null in HTConstructRT2RTAggElement()\n"); ++ return; ++ } ++ memset(posRT2RTAgg, 0, *len); ++ *posRT2RTAgg++ = 0x00; ++ *posRT2RTAgg++ = 0xe0; ++ *posRT2RTAgg++ = 0x4c; ++ *posRT2RTAgg++ = 0x02; ++ *posRT2RTAgg++ = 0x01; ++ *posRT2RTAgg = 0x10;//*posRT2RTAgg = 0x02; ++ ++ if(ieee->bSupportRemoteWakeUp) { ++ *posRT2RTAgg |= 0x08;//RT_HT_CAP_USE_WOW; ++ } ++ ++ *len = 6 + 2; ++ return; ++#ifdef TODO ++#if(HAL_CODE_BASE == RTL8192 && DEV_BUS_TYPE == USB_INTERFACE) ++ /* ++ //Emily. If it is required to Ask Realtek AP to send AMPDU during AES mode, enable this ++ section of code. ++ if(IS_UNDER_11N_AES_MODE(Adapter)) ++ { ++ posRT2RTAgg->Octet[5] |=RT_HT_CAP_USE_AMPDU; ++ }else ++ { ++ posRT2RTAgg->Octet[5] &= 0xfb; ++ } ++ */ ++ ++#else ++ // Do Nothing ++#endif ++ ++ posRT2RTAgg->Length = 6; ++#endif ++ ++ ++ ++ ++} ++ ++ ++/******************************************************************************************************************** ++ *function: Pick the right Rate Adaptive table to use ++ * input: struct ieee80211_device* ieee ++ * u8* pOperateMCS //A pointer to MCS rate bitmap ++ * return: always we return true ++ * notice: ++ * *****************************************************************************************************************/ ++u8 HT_PickMCSRate(struct ieee80211_device* ieee, u8* pOperateMCS) ++{ ++ u8 i; ++ if (pOperateMCS == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "pOperateMCS can't be null in HT_PickMCSRate()\n"); ++ return false; ++ } ++ ++ switch(ieee->mode) ++ { ++ case IEEE_A: ++ case IEEE_B: ++ case IEEE_G: ++ //legacy rate routine handled at selectedrate ++ ++ //no MCS rate ++ for(i=0;i<=15;i++){ ++ pOperateMCS[i] = 0; ++ } ++ break; ++ ++ case IEEE_N_24G: //assume CCK rate ok ++ case IEEE_N_5G: ++ // Legacy part we only use 6, 5.5,2,1 for N_24G and 6 for N_5G. ++ // Legacy part shall be handled at SelectRateSet(). ++ ++ //HT part ++ // TODO: may be different if we have different number of antenna ++ pOperateMCS[0] &=RATE_ADPT_1SS_MASK; //support MCS 0~7 ++ pOperateMCS[1] &=RATE_ADPT_2SS_MASK; ++ pOperateMCS[3] &=RATE_ADPT_MCS32_MASK; ++ break; ++ ++ //should never reach here ++ default: ++ ++ break; ++ ++ } ++ ++ return true; ++} ++ ++/* ++* Description: ++* This function will get the highest speed rate in input MCS set. ++* ++* /param Adapter Pionter to Adapter entity ++* pMCSRateSet Pointer to MCS rate bitmap ++* pMCSFilter Pointer to MCS rate filter ++* ++* /return Highest MCS rate included in pMCSRateSet and filtered by pMCSFilter. ++* ++*/ ++/******************************************************************************************************************** ++ *function: This function will get the highest speed rate in input MCS set. ++ * input: struct ieee80211_device* ieee ++ * u8* pMCSRateSet //Pointer to MCS rate bitmap ++ * u8* pMCSFilter //Pointer to MCS rate filter ++ * return: Highest MCS rate included in pMCSRateSet and filtered by pMCSFilter ++ * notice: ++ * *****************************************************************************************************************/ ++u8 HTGetHighestMCSRate(struct ieee80211_device* ieee, u8* pMCSRateSet, u8* pMCSFilter) ++{ ++ u8 i, j; ++ u8 bitMap; ++ u8 mcsRate = 0; ++ u8 availableMcsRate[16]; ++ if (pMCSRateSet == NULL || pMCSFilter == NULL) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "pMCSRateSet or pMCSFilter can't be null in HTGetHighestMCSRate()\n"); ++ return false; ++ } ++ for(i=0; i<16; i++) ++ availableMcsRate[i] = pMCSRateSet[i] & pMCSFilter[i]; ++ ++ for(i = 0; i < 16; i++) ++ { ++ if(availableMcsRate[i] != 0) ++ break; ++ } ++ if(i == 16) ++ return false; ++ ++ for(i = 0; i < 16; i++) ++ { ++ if(availableMcsRate[i] != 0) ++ { ++ bitMap = availableMcsRate[i]; ++ for(j = 0; j < 8; j++) ++ { ++ if((bitMap%2) != 0) ++ { ++ if(HTMcsToDataRate(ieee, (8*i+j)) > HTMcsToDataRate(ieee, mcsRate)) ++ mcsRate = (8*i+j); ++ } ++ bitMap = bitMap>>1; ++ } ++ } ++ } ++ return (mcsRate|0x80); ++} ++ ++ ++ ++/* ++** ++**1.Filter our operation rate set with AP's rate set ++**2.shall reference channel bandwidth, STBC, Antenna number ++**3.generate rate adative table for firmware ++**David 20060906 ++** ++** \pHTSupportedCap: the connected STA's supported rate Capability element ++*/ ++u8 HTFilterMCSRate( struct ieee80211_device* ieee, u8* pSupportMCS, u8* pOperateMCS) ++{ ++ ++ u8 i=0; ++ ++ // filter out operational rate set not supported by AP, the lenth of it is 16 ++ for(i=0;i<=15;i++){ ++ pOperateMCS[i] = ieee->Regdot11HTOperationalRateSet[i]&pSupportMCS[i]; ++ } ++ ++ ++ // TODO: adjust our operational rate set according to our channel bandwidth, STBC and Antenna number ++ ++ // TODO: fill suggested rate adaptive rate index and give firmware info using Tx command packet ++ // we also shall suggested the first start rate set according to our singal strength ++ HT_PickMCSRate(ieee, pOperateMCS); ++ ++ // For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7. ++ if(ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) ++ pOperateMCS[1] = 0; ++ ++ // ++ // For RTL819X, we support only MCS0~15. ++ // And also, we do not know how to use MCS32 now. ++ // ++ for(i=2; i<=15; i++) ++ pOperateMCS[i] = 0; ++ ++ return true; ++} ++void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); ++#if 0 ++//I need move this function to other places, such as rx? ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void HTOnAssocRsp_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ht_onAssRsp); ++#else ++void HTOnAssocRsp_wq(struct ieee80211_device *ieee) ++{ ++#endif ++#endif ++void HTOnAssocRsp(struct ieee80211_device *ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ PHT_CAPABILITY_ELE pPeerHTCap = NULL; ++ PHT_INFORMATION_ELE pPeerHTInfo = NULL; ++ u16 nMaxAMSDUSize = 0; ++ u8* pMcsFilter = NULL; ++ ++ static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily ++ static u8 EWC11NHTInfo[] = {0x00, 0x90, 0x4c, 0x34}; // For 11n EWC definition, 2007.07.17, by Emily ++ ++ if( pHTInfo->bCurrentHTSupport == false ) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "<=== HTOnAssocRsp(): HT_DISABLE\n"); ++ return; ++ } ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "===> HTOnAssocRsp_wq(): HT_ENABLE\n"); ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTCapBuf, sizeof(HT_CAPABILITY_ELE)); ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA, pHTInfo->PeerHTInfoBuf, sizeof(HT_INFORMATION_ELE)); ++ ++// HTDebugHTCapability(pHTInfo->PeerHTCapBuf,"HTOnAssocRsp_wq"); ++// HTDebugHTInfo(pHTInfo->PeerHTInfoBuf,"HTOnAssocRsp_wq"); ++ // ++ if(!memcmp(pHTInfo->PeerHTCapBuf,EWC11NHTCap, sizeof(EWC11NHTCap))) ++ pPeerHTCap = (PHT_CAPABILITY_ELE)(&pHTInfo->PeerHTCapBuf[4]); ++ else ++ pPeerHTCap = (PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf); ++ ++ if(!memcmp(pHTInfo->PeerHTInfoBuf, EWC11NHTInfo, sizeof(EWC11NHTInfo))) ++ pPeerHTInfo = (PHT_INFORMATION_ELE)(&pHTInfo->PeerHTInfoBuf[4]); ++ else ++ pPeerHTInfo = (PHT_INFORMATION_ELE)(pHTInfo->PeerHTInfoBuf); ++ ++ ++ //////////////////////////////////////////////////////// ++ // Configurations: ++ //////////////////////////////////////////////////////// ++ IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTCap, sizeof(HT_CAPABILITY_ELE)); ++// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_HT, pPeerHTInfo, sizeof(HT_INFORMATION_ELE)); ++ // Config Supported Channel Width setting ++ // ++ HTSetConnectBwMode(ieee, (HT_CHANNEL_WIDTH)(pPeerHTCap->ChlWidth), (HT_EXTCHNL_OFFSET)(pPeerHTInfo->ExtChlOffset)); ++ ++// if(pHTInfo->bCurBW40MHz == true) ++ pHTInfo->bCurTxBW40MHz = ((pPeerHTInfo->RecommemdedTxWidth == 1)?true:false); ++ ++ // ++ // Update short GI/ long GI setting ++ // ++ // TODO: ++ pHTInfo->bCurShortGI20MHz= ++ ((pHTInfo->bRegShortGI20MHz)?((pPeerHTCap->ShortGI20Mhz==1)?true:false):false); ++ pHTInfo->bCurShortGI40MHz= ++ ((pHTInfo->bRegShortGI40MHz)?((pPeerHTCap->ShortGI40Mhz==1)?true:false):false); ++ ++ // ++ // Config TX STBC setting ++ // ++ // TODO: ++ ++ // ++ // Config DSSS/CCK mode in 40MHz mode ++ // ++ // TODO: ++ pHTInfo->bCurSuppCCK = ++ ((pHTInfo->bRegSuppCCK)?((pPeerHTCap->DssCCk==1)?true:false):false); ++ ++ ++ // ++ // Config and configure A-MSDU setting ++ // ++ pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; ++ ++ nMaxAMSDUSize = (pPeerHTCap->MaxAMSDUSize==0)?3839:7935; ++ ++ if(pHTInfo->nAMSDU_MaxSize > nMaxAMSDUSize ) ++ pHTInfo->nCurrent_AMSDU_MaxSize = nMaxAMSDUSize; ++ else ++ pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; ++ ++ ++ // ++ // Config A-MPDU setting ++ // ++ pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; ++ ++ // <1> Decide AMPDU Factor ++ ++ // By Emily ++ if(!pHTInfo->bRegRT2RTAggregation) ++ { ++ // Decide AMPDU Factor according to protocol handshake ++ if(pHTInfo->AMPDU_Factor > pPeerHTCap->MaxRxAMPDUFactor) ++ pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; ++ else ++ pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; ++ ++ }else ++ { ++ // Set MPDU density to 2 to Realtek AP, and set it to 0 for others ++ // Replace MPDU factor declared in original association response frame format. 2007.08.20 by Emily ++#if 0 ++ osTmp= PacketGetElement( asocpdu, EID_Vendor, OUI_SUB_REALTEK_AGG, OUI_SUBTYPE_DONT_CARE); ++ if(osTmp.Length >= 5) //00:e0:4c:02:00 ++#endif ++ if (ieee->current_network.bssht.bdRT2RTAggregation) ++ { ++ if( ieee->pairwise_key_type != KEY_TYPE_NA) ++ // Realtek may set 32k in security mode and 64k for others ++ pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; ++ else ++ pHTInfo->CurrentAMPDUFactor = HT_AGG_SIZE_64K; ++ }else ++ { ++ if(pPeerHTCap->MaxRxAMPDUFactor < HT_AGG_SIZE_32K) ++ pHTInfo->CurrentAMPDUFactor = pPeerHTCap->MaxRxAMPDUFactor; ++ else ++ pHTInfo->CurrentAMPDUFactor = HT_AGG_SIZE_32K; ++ } ++ } ++ ++ // <2> Set AMPDU Minimum MPDU Start Spacing ++ // 802.11n 3.0 section 9.7d.3 ++#if 1 ++ if(pHTInfo->MPDU_Density > pPeerHTCap->MPDUDensity) ++ pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; ++ else ++ pHTInfo->CurrentMPDUDensity = pPeerHTCap->MPDUDensity; ++ if(ieee->pairwise_key_type != KEY_TYPE_NA ) ++ pHTInfo->CurrentMPDUDensity = 7; // 8us ++#else ++ if(pHTInfo->MPDU_Density > pPeerHTCap->MPDUDensity) ++ pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; ++ else ++ pHTInfo->CurrentMPDUDensity = pPeerHTCap->MPDUDensity; ++#endif ++ // Force TX AMSDU ++ ++ // Lanhsin: mark for tmp to avoid deauth by ap from s3 ++ //if(memcmp(pMgntInfo->Bssid, NETGEAR834Bv2_BROADCOM, 3)==0) ++ if(0) ++ { ++ ++ pHTInfo->bCurrentAMPDUEnable = false; ++ pHTInfo->ForcedAMSDUMode = HT_AGG_FORCE_ENABLE; ++ pHTInfo->ForcedAMSDUMaxSize = 7935; ++ ++ pHTInfo->IOTAction |= HT_IOT_ACT_TX_USE_AMSDU_8K; ++ } ++ ++ // Rx Reorder Setting ++ pHTInfo->bCurRxReorderEnable = pHTInfo->bRegRxReorderEnable; ++ ++ // ++ // Filter out unsupported HT rate for this AP ++ // Update RATR table ++ // This is only for 8190 ,8192 or later product which using firmware to handle rate adaptive mechanism. ++ // ++ ++ // Handle Ralink AP bad MCS rate set condition. Joseph. ++ // This fix the bug of Ralink AP. This may be removed in the future. ++ if(pPeerHTCap->MCS[0] == 0) ++ pPeerHTCap->MCS[0] = 0xff; ++ ++ HTFilterMCSRate(ieee, pPeerHTCap->MCS, ieee->dot11HTOperationalRateSet); ++ ++ // ++ // Config MIMO Power Save setting ++ // ++ pHTInfo->PeerMimoPs = pPeerHTCap->MimoPwrSave; ++ if(pHTInfo->PeerMimoPs == MIMO_PS_STATIC) ++ pMcsFilter = MCS_FILTER_1SS; ++ else ++ pMcsFilter = MCS_FILTER_ALL; ++ //WB add for MCS8 bug ++// pMcsFilter = MCS_FILTER_1SS; ++ ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, ieee->dot11HTOperationalRateSet, pMcsFilter); ++ ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; ++ ++ // ++ // Config current operation mode. ++ // ++ pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; ++ ++ ++ ++} ++ ++void HTSetConnectBwModeCallback(struct ieee80211_device* ieee); ++/******************************************************************************************************************** ++ *function: initialize HT info(struct PRT_HIGH_THROUGHPUT) ++ * input: struct ieee80211_device* ieee ++ * output: none ++ * return: none ++ * notice: This function is called when * (1) MPInitialization Phase * (2) Receiving of Deauthentication from AP ++********************************************************************************************************************/ ++// TODO: Should this funciton be called when receiving of Disassociation? ++void HTInitializeHTInfo(struct ieee80211_device* ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ // ++ // These parameters will be reset when receiving deauthentication packet ++ // ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "===========>%s()\n", __FUNCTION__); ++ pHTInfo->bCurrentHTSupport = false; ++ ++ // 40MHz channel support ++ pHTInfo->bCurBW40MHz = false; ++ pHTInfo->bCurTxBW40MHz = false; ++ ++ // Short GI support ++ pHTInfo->bCurShortGI20MHz = false; ++ pHTInfo->bCurShortGI40MHz = false; ++ pHTInfo->bForcedShortGI = false; ++ ++ // CCK rate support ++ // This flag is set to true to support CCK rate by default. ++ // It will be affected by "pHTInfo->bRegSuppCCK" and AP capabilities only when associate to ++ // 11N BSS. ++ pHTInfo->bCurSuppCCK = true; ++ ++ // AMSDU related ++ pHTInfo->bCurrent_AMSDU_Support = false; ++ pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; ++ ++ // AMPUD related ++ pHTInfo->CurrentMPDUDensity = pHTInfo->MPDU_Density; ++ pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; ++ ++ ++ ++ // Initialize all of the parameters related to 11n ++ memset((void*)(&(pHTInfo->SelfHTCap)), 0, sizeof(pHTInfo->SelfHTCap)); ++ memset((void*)(&(pHTInfo->SelfHTInfo)), 0, sizeof(pHTInfo->SelfHTInfo)); ++ memset((void*)(&(pHTInfo->PeerHTCapBuf)), 0, sizeof(pHTInfo->PeerHTCapBuf)); ++ memset((void*)(&(pHTInfo->PeerHTInfoBuf)), 0, sizeof(pHTInfo->PeerHTInfoBuf)); ++ ++ pHTInfo->bSwBwInProgress = false; ++ pHTInfo->ChnlOp = CHNLOP_NONE; ++ ++ // Set default IEEE spec for Draft N ++ pHTInfo->ePeerHTSpecVer = HT_SPEC_VER_IEEE; ++ ++ // Realtek proprietary aggregation mode ++ pHTInfo->bCurrentRT2RTAggregation = false; ++ pHTInfo->bCurrentRT2RTLongSlotTime = false; ++ pHTInfo->IOTPeer = 0; ++ pHTInfo->IOTAction = 0; ++ ++ //MCS rate initialized here ++ { ++ u8* RegHTSuppRateSets = &(ieee->RegHTSuppRateSet[0]); ++ RegHTSuppRateSets[0] = 0xFF; //support MCS 0~7 ++ RegHTSuppRateSets[1] = 0xFF; //support MCS 8~15 ++ RegHTSuppRateSets[4] = 0x01; //support MCS 32 ++ } ++} ++/******************************************************************************************************************** ++ *function: initialize Bss HT structure(struct PBSS_HT) ++ * input: PBSS_HT pBssHT //to be initialized ++ * output: none ++ * return: none ++ * notice: This function is called when initialize network structure ++********************************************************************************************************************/ ++void HTInitializeBssDesc(PBSS_HT pBssHT) ++{ ++ ++ pBssHT->bdSupportHT = false; ++ memset(pBssHT->bdHTCapBuf, 0, sizeof(pBssHT->bdHTCapBuf)); ++ pBssHT->bdHTCapLen = 0; ++ memset(pBssHT->bdHTInfoBuf, 0, sizeof(pBssHT->bdHTInfoBuf)); ++ pBssHT->bdHTInfoLen = 0; ++ ++ pBssHT->bdHTSpecVer= HT_SPEC_VER_IEEE; ++ ++ pBssHT->bdRT2RTAggregation = false; ++ pBssHT->bdRT2RTLongSlotTime = false; ++} ++#if 0 ++//below function has merged into ieee80211_network_init() in ieee80211_rx.c ++void ++HTParsingHTCapElement( ++ IN PADAPTER Adapter, ++ IN OCTET_STRING HTCapIE, ++ OUT PRT_WLAN_BSS pBssDesc ++) ++{ ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ ++ if( HTCapIE.Length > sizeof(pBssDesc->BssHT.bdHTCapBuf) ) ++ { ++ RT_TRACE( COMP_HT, DBG_LOUD, ("HTParsingHTCapElement(): HT Capability Element length is too long!\n") ); ++ return; ++ } ++ ++ // TODO: Check the correctness of HT Cap ++ //Print each field in detail. Driver should not print out this message by default ++ if(!pMgntInfo->mActingAsAp && !pMgntInfo->mAssoc) ++ HTDebugHTCapability(DBG_TRACE, Adapter, &HTCapIE, (pu8)"HTParsingHTCapElement()"); ++ ++ HTCapIE.Length = HTCapIE.Length > sizeof(pBssDesc->BssHT.bdHTCapBuf)?\ ++ sizeof(pBssDesc->BssHT.bdHTCapBuf):HTCapIE.Length; //prevent from overflow ++ ++ CopyMem(pBssDesc->BssHT.bdHTCapBuf, HTCapIE.Octet, HTCapIE.Length); ++ pBssDesc->BssHT.bdHTCapLen = HTCapIE.Length; ++ ++} ++ ++ ++void ++HTParsingHTInfoElement( ++ PADAPTER Adapter, ++ OCTET_STRING HTInfoIE, ++ PRT_WLAN_BSS pBssDesc ++) ++{ ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ ++ if( HTInfoIE.Length > sizeof(pBssDesc->BssHT.bdHTInfoBuf)) ++ { ++ RT_TRACE( COMP_HT, DBG_LOUD, ("HTParsingHTInfoElement(): HT Information Element length is too long!\n") ); ++ return; ++ } ++ ++ // TODO: Check the correctness of HT Info ++ //Print each field in detail. Driver should not print out this message by default ++ if(!pMgntInfo->mActingAsAp && !pMgntInfo->mAssoc) ++ HTDebugHTInfo(DBG_TRACE, Adapter, &HTInfoIE, (pu8)"HTParsingHTInfoElement()"); ++ ++ HTInfoIE.Length = HTInfoIE.Length > sizeof(pBssDesc->BssHT.bdHTInfoBuf)?\ ++ sizeof(pBssDesc->BssHT.bdHTInfoBuf):HTInfoIE.Length; //prevent from overflow ++ ++ CopyMem( pBssDesc->BssHT.bdHTInfoBuf, HTInfoIE.Octet, HTInfoIE.Length); ++ pBssDesc->BssHT.bdHTInfoLen = HTInfoIE.Length; ++} ++ ++/* ++ * Get HT related information from beacon and save it in BssDesc ++ * ++ * (1) Parse HTCap, and HTInfo, and record whether it is 11n AP ++ * (2) If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT() ++ * (3) Check whether peer is Realtek AP (for Realtek proprietary aggregation mode). ++ * Input: ++ * PADAPTER Adapter ++ * ++ * Output: ++ * PRT_TCB BssDesc ++ * ++*/ ++void HTGetValueFromBeaconOrProbeRsp( ++ PADAPTER Adapter, ++ POCTET_STRING pSRCmmpdu, ++ PRT_WLAN_BSS bssDesc ++) ++{ ++ PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; ++ PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo); ++ OCTET_STRING HTCapIE, HTInfoIE, HTRealtekAgg, mmpdu; ++ OCTET_STRING BroadcomElement, CiscoElement; ++ ++ mmpdu.Octet = pSRCmmpdu->Octet; ++ mmpdu.Length = pSRCmmpdu->Length; ++ ++ //2Note: ++ // Mark for IOT testing using Linksys WRT350N, This AP does not contain WMM IE when ++ // it is configured at pure-N mode. ++ // if(bssDesc->BssQos.bdQoSMode & QOS_WMM) ++ // ++ ++ HTInitializeBssDesc (&bssDesc->BssHT); ++ ++ //2<1> Parse HTCap, and HTInfo ++ // Get HT Capability IE: (1) Get IEEE Draft N IE or (2) Get EWC IE ++ HTCapIE = PacketGetElement(mmpdu, EID_HTCapability, OUI_SUB_DONT_CARE, OUI_SUBTYPE_DONT_CARE); ++ if(HTCapIE.Length == 0) ++ { ++ HTCapIE = PacketGetElement(mmpdu, EID_Vendor, OUI_SUB_11N_EWC_HT_CAP, OUI_SUBTYPE_DONT_CARE); ++ if(HTCapIE.Length != 0) ++ bssDesc->BssHT.bdHTSpecVer= HT_SPEC_VER_EWC; ++ } ++ if(HTCapIE.Length != 0) ++ HTParsingHTCapElement(Adapter, HTCapIE, bssDesc); ++ ++ // Get HT Information IE: (1) Get IEEE Draft N IE or (2) Get EWC IE ++ HTInfoIE = PacketGetElement(mmpdu, EID_HTInfo, OUI_SUB_DONT_CARE, OUI_SUBTYPE_DONT_CARE); ++ if(HTInfoIE.Length == 0) ++ { ++ HTInfoIE = PacketGetElement(mmpdu, EID_Vendor, OUI_SUB_11N_EWC_HT_INFO, OUI_SUBTYPE_DONT_CARE); ++ if(HTInfoIE.Length != 0) ++ bssDesc->BssHT.bdHTSpecVer = HT_SPEC_VER_EWC; ++ } ++ if(HTInfoIE.Length != 0) ++ HTParsingHTInfoElement(Adapter, HTInfoIE, bssDesc); ++ ++ //2<2>If peer is HT, but not WMM, call QosSetLegacyWMMParamWithHT() ++ if(HTCapIE.Length != 0) ++ { ++ bssDesc->BssHT.bdSupportHT = true; ++ if(bssDesc->BssQos.bdQoSMode == QOS_DISABLE) ++ QosSetLegacyWMMParamWithHT(Adapter, bssDesc); ++ } ++ else ++ { ++ bssDesc->BssHT.bdSupportHT = false; ++ } ++ ++ //2<3>Check whether the peer is Realtek AP/STA ++ if(pHTInfo->bRegRT2RTAggregation) ++ { ++ if(bssDesc->BssHT.bdSupportHT) ++ { ++ HTRealtekAgg = PacketGetElement(mmpdu, EID_Vendor, OUI_SUB_REALTEK_AGG, OUI_SUBTYPE_DONT_CARE); ++ if(HTRealtekAgg.Length >=5 ) ++ { ++ bssDesc->BssHT.bdRT2RTAggregation = true; ++ ++ if((HTRealtekAgg.Octet[4]==1) && (HTRealtekAgg.Octet[5] & 0x02)) ++ bssDesc->BssHT.bdRT2RTLongSlotTime = true; ++ } ++ } ++ } ++ ++ // ++ // 2008/01/25 MH Get Broadcom AP IE for manamgent frame CCK rate problem. ++ // AP can not receive CCK managemtn from from 92E. ++ // ++ ++ // Initialize every new bss broadcom cap exist as false.. ++ bssDesc->bBroadcomCapExist= false; ++ ++ if(HTCapIE.Length != 0 || HTInfoIE.Length != 0) ++ { ++ u4Byte Length = 0; ++ ++ FillOctetString(BroadcomElement, NULL, 0); ++ ++ BroadcomElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_BROADCOM_IE_1, OUI_SUBTYPE_DONT_CARE); ++ Length += BroadcomElement.Length; ++ BroadcomElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_BROADCOM_IE_2, OUI_SUBTYPE_DONT_CARE); ++ Length += BroadcomElement.Length; ++ BroadcomElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_BROADCOM_IE_3, OUI_SUBTYPE_DONT_CARE); ++ Length += BroadcomElement.Length; ++ ++ if(Length > 0) ++ bssDesc->bBroadcomCapExist = true; ++ } ++ ++ ++ // For Cisco IOT issue ++ CiscoElement = PacketGetElement( mmpdu, EID_Vendor, OUI_SUB_CISCO_IE, OUI_SUBTYPE_DONT_CARE); ++ if(CiscoElement.Length != 0){ // 3: 0x00, 0x40, 0x96 .... ++ bssDesc->bCiscoCapExist = true; ++ }else{ ++ bssDesc->bCiscoCapExist = false; ++ } ++} ++ ++ ++#endif ++/******************************************************************************************************************** ++ *function: initialize Bss HT structure(struct PBSS_HT) ++ * input: struct ieee80211_device *ieee ++ * struct ieee80211_network *pNetwork //usually current network we are live in ++ * output: none ++ * return: none ++ * notice: This function should ONLY be called before association ++********************************************************************************************************************/ ++void HTResetSelfAndSavePeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++// u16 nMaxAMSDUSize; ++// PHT_CAPABILITY_ELE pPeerHTCap = (PHT_CAPABILITY_ELE)pNetwork->bssht.bdHTCapBuf; ++// PHT_INFORMATION_ELE pPeerHTInfo = (PHT_INFORMATION_ELE)pNetwork->bssht.bdHTInfoBuf; ++// u8* pMcsFilter; ++ u8 bIOTAction = 0; ++ ++ // ++ // Save Peer Setting before Association ++ // ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "==============>%s()\n", __FUNCTION__); ++ /*unmark bEnableHT flag here is the same reason why unmarked in function ieee80211_softmac_new_net. WB 2008.09.10*/ ++// if( pHTInfo->bEnableHT && pNetwork->bssht.bdSupportHT) ++ if (pNetwork->bssht.bdSupportHT) ++ { ++ pHTInfo->bCurrentHTSupport = true; ++ pHTInfo->ePeerHTSpecVer = pNetwork->bssht.bdHTSpecVer; ++ ++ // Save HTCap and HTInfo information Element ++ if(pNetwork->bssht.bdHTCapLen > 0 && pNetwork->bssht.bdHTCapLen <= sizeof(pHTInfo->PeerHTCapBuf)) ++ memcpy(pHTInfo->PeerHTCapBuf, pNetwork->bssht.bdHTCapBuf, pNetwork->bssht.bdHTCapLen); ++ ++ if(pNetwork->bssht.bdHTInfoLen > 0 && pNetwork->bssht.bdHTInfoLen <= sizeof(pHTInfo->PeerHTInfoBuf)) ++ memcpy(pHTInfo->PeerHTInfoBuf, pNetwork->bssht.bdHTInfoBuf, pNetwork->bssht.bdHTInfoLen); ++ ++ // Check whether RT to RT aggregation mode is enabled ++ if(pHTInfo->bRegRT2RTAggregation) ++ { ++ pHTInfo->bCurrentRT2RTAggregation = pNetwork->bssht.bdRT2RTAggregation; ++ pHTInfo->bCurrentRT2RTLongSlotTime = pNetwork->bssht.bdRT2RTLongSlotTime; ++ } ++ else ++ { ++ pHTInfo->bCurrentRT2RTAggregation = false; ++ pHTInfo->bCurrentRT2RTLongSlotTime = false; ++ } ++ ++ // Determine the IOT Peer Vendor. ++ HTIOTPeerDetermine(ieee); ++ ++ // Decide IOT Action ++ // Must be called after the parameter of pHTInfo->bCurrentRT2RTAggregation is decided ++ pHTInfo->IOTAction = 0; ++ bIOTAction = HTIOTActIsDisableMCS14(ieee, pNetwork->bssid); ++ if(bIOTAction) ++ pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS14; ++ ++ bIOTAction = HTIOTActIsDisableMCS15(ieee); ++ if(bIOTAction) ++ pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_MCS15; ++ ++ bIOTAction = HTIOTActIsDisableMCSTwoSpatialStream(ieee, pNetwork->bssid); ++ if(bIOTAction) ++ pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_ALL_2SS; ++ ++ ++ bIOTAction = HTIOTActIsDisableEDCATurbo(ieee, pNetwork->bssid); ++ if(bIOTAction) ++ pHTInfo->IOTAction |= HT_IOT_ACT_DISABLE_EDCA_TURBO; ++ ++ bIOTAction = HTIOTActIsMgntUseCCK6M(pNetwork); ++ if(bIOTAction) ++ pHTInfo->IOTAction |= HT_IOT_ACT_MGNT_USE_CCK_6M; ++ ++ bIOTAction = HTIOTActIsCCDFsync(pNetwork->bssid); ++ if(bIOTAction) ++ pHTInfo->IOTAction |= HT_IOT_ACT_CDD_FSYNC; ++ ++ ++ } ++ else ++ { ++ pHTInfo->bCurrentHTSupport = false; ++ pHTInfo->bCurrentRT2RTAggregation = false; ++ pHTInfo->bCurrentRT2RTLongSlotTime = false; ++ ++ pHTInfo->IOTAction = 0; ++ } ++ ++} ++ ++void HTUpdateSelfAndPeerSetting(struct ieee80211_device* ieee, struct ieee80211_network * pNetwork) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++// PHT_CAPABILITY_ELE pPeerHTCap = (PHT_CAPABILITY_ELE)pNetwork->bssht.bdHTCapBuf; ++ PHT_INFORMATION_ELE pPeerHTInfo = (PHT_INFORMATION_ELE)pNetwork->bssht.bdHTInfoBuf; ++ ++ if(pHTInfo->bCurrentHTSupport) ++ { ++ // ++ // Config current operation mode. ++ // ++ if(pNetwork->bssht.bdHTInfoLen != 0) ++ pHTInfo->CurrentOpMode = pPeerHTInfo->OptMode; ++ ++ // ++ // ++ // ++ } ++} ++ ++void HTUseDefaultSetting(struct ieee80211_device* ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++// u8 regBwOpMode; ++ ++ if(pHTInfo->bEnableHT) ++ { ++ pHTInfo->bCurrentHTSupport = true; ++ ++ pHTInfo->bCurSuppCCK = pHTInfo->bRegSuppCCK; ++ ++ pHTInfo->bCurBW40MHz = pHTInfo->bRegBW40MHz; ++ ++ pHTInfo->bCurShortGI20MHz= pHTInfo->bRegShortGI20MHz; ++ ++ pHTInfo->bCurShortGI40MHz= pHTInfo->bRegShortGI40MHz; ++ ++ pHTInfo->bCurrent_AMSDU_Support = pHTInfo->bAMSDU_Support; ++ ++ pHTInfo->nCurrent_AMSDU_MaxSize = pHTInfo->nAMSDU_MaxSize; ++ ++ pHTInfo->bCurrentAMPDUEnable = pHTInfo->bAMPDUEnable; ++ ++ pHTInfo->CurrentAMPDUFactor = pHTInfo->AMPDU_Factor; ++ ++ pHTInfo->CurrentMPDUDensity = pHTInfo->CurrentMPDUDensity; ++ ++ // Set BWOpMode register ++ ++ //update RATR index0 ++ HTFilterMCSRate(ieee, ieee->Regdot11HTOperationalRateSet, ieee->dot11HTOperationalRateSet); ++ //function below is not implemented at all. WB ++#ifdef TODO ++ Adapter->HalFunc.InitHalRATRTableHandler( Adapter, &pMgntInfo->dot11OperationalRateSet, pMgntInfo->dot11HTOperationalRateSet); ++#endif ++ ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee, ieee->dot11HTOperationalRateSet, MCS_FILTER_ALL); ++ ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate; ++ ++ } ++ else ++ { ++ pHTInfo->bCurrentHTSupport = false; ++ } ++ return; ++} ++/******************************************************************************************************************** ++ *function: check whether HT control field exists ++ * input: struct ieee80211_device *ieee ++ * u8* pFrame //coming skb->data ++ * output: none ++ * return: return true if HT control field exists(false otherwise) ++ * notice: ++********************************************************************************************************************/ ++u8 HTCCheck(struct ieee80211_device* ieee, u8* pFrame) ++{ ++ if(ieee->pHTInfo->bCurrentHTSupport) ++ { ++ if( (IsQoSDataFrame(pFrame) && Frame_Order(pFrame)) == 1) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "HT CONTROL FILED EXIST!!\n"); ++ return true; ++ } ++ } ++ return false; ++} ++ ++// ++// This function set bandwidth mode in protocol layer. ++// ++void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++// u32 flags = 0; ++ ++ if(pHTInfo->bRegBW40MHz == false) ++ return; ++ ++ ++ ++ // To reduce dummy operation ++// if((pHTInfo->bCurBW40MHz==false && Bandwidth==HT_CHANNEL_WIDTH_20) || ++// (pHTInfo->bCurBW40MHz==true && Bandwidth==HT_CHANNEL_WIDTH_20_40 && Offset==pHTInfo->CurSTAExtChnlOffset)) ++// return; ++ ++// spin_lock_irqsave(&(ieee->bw_spinlock), flags); ++ if(pHTInfo->bSwBwInProgress) { ++// spin_unlock_irqrestore(&(ieee->bw_spinlock), flags); ++ return; ++ } ++ //if in half N mode, set to 20M bandwidth please 09.08.2008 WB. ++ if(Bandwidth==HT_CHANNEL_WIDTH_20_40 && (!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))) ++ { ++ // Handle Illegal extention channel offset!! ++ if(ieee->current_network.channel<2 && Offset==HT_EXTCHNL_OFFSET_LOWER) ++ Offset = HT_EXTCHNL_OFFSET_NO_EXT; ++ if(Offset==HT_EXTCHNL_OFFSET_UPPER || Offset==HT_EXTCHNL_OFFSET_LOWER) { ++ pHTInfo->bCurBW40MHz = true; ++ pHTInfo->CurSTAExtChnlOffset = Offset; ++ } else { ++ pHTInfo->bCurBW40MHz = false; ++ pHTInfo->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT; ++ } ++ } else { ++ pHTInfo->bCurBW40MHz = false; ++ pHTInfo->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT; ++ } ++ ++ pHTInfo->bSwBwInProgress = true; ++ ++ // TODO: 2007.7.13 by Emily Wait 2000ms in order to garantee that switching ++ // bandwidth is executed after scan is finished. It is a temporal solution ++ // because software should ganrantee the last operation of switching bandwidth ++ // is executed properlly. ++ HTSetConnectBwModeCallback(ieee); ++ ++// spin_unlock_irqrestore(&(ieee->bw_spinlock), flags); ++} ++ ++void HTSetConnectBwModeCallback(struct ieee80211_device* ieee) ++{ ++ PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; ++ ++ IEEE80211_DEBUG(IEEE80211_DL_HT, "======>%s()\n", __FUNCTION__); ++ ++ if(pHTInfo->bCurBW40MHz) ++ { ++ if(pHTInfo->CurSTAExtChnlOffset==HT_EXTCHNL_OFFSET_UPPER) ++ ieee->set_chan(ieee->dev, ieee->current_network.channel+2); ++ else if(pHTInfo->CurSTAExtChnlOffset==HT_EXTCHNL_OFFSET_LOWER) ++ ieee->set_chan(ieee->dev, ieee->current_network.channel-2); ++ else ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20_40, pHTInfo->CurSTAExtChnlOffset); ++ } else { ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); ++ } ++ ++ pHTInfo->bSwBwInProgress = false; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++//EXPORT_SYMBOL_NOVERS(HTUpdateSelfAndPeerSetting); ++#else ++//EXPORT_SYMBOL(HTUpdateSelfAndPeerSetting); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_Qos.h +@@ -0,0 +1,749 @@ ++#ifndef __INC_QOS_TYPE_H ++#define __INC_QOS_TYPE_H ++ ++//#include "EndianFree.h" ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++ ++#define MAX_WMMELE_LENGTH 64 ++ ++// ++// QoS mode. ++// enum 0, 1, 2, 4: since we can use the OR(|) operation. ++// ++// QOS_MODE is redefined for enum can't be ++, | under C++ compiler, 2006.05.17, by rcnjko. ++//typedef enum _QOS_MODE{ ++// QOS_DISABLE = 0, ++// QOS_WMM = 1, ++// QOS_EDCA = 2, ++// QOS_HCCA = 4, ++//}QOS_MODE,*PQOS_MODE; ++// ++typedef u32 QOS_MODE, *PQOS_MODE; ++#define QOS_DISABLE 0 ++#define QOS_WMM 1 ++#define QOS_WMMSA 2 ++#define QOS_EDCA 4 ++#define QOS_HCCA 8 ++#define QOS_WMM_UAPSD 16 //WMM Power Save, 2006-06-14 Isaiah ++ ++#define AC_PARAM_SIZE 4 ++#define WMM_PARAM_ELE_BODY_LEN 18 ++ ++// ++// QoS ACK Policy Field Values ++// Ref: WMM spec 2.1.6: QoS Control Field, p.10. ++// ++typedef enum _ACK_POLICY{ ++ eAckPlc0_ACK = 0x00, ++ eAckPlc1_NoACK = 0x01, ++}ACK_POLICY,*PACK_POLICY; ++ ++#define WMM_PARAM_ELEMENT_SIZE (8+(4*AC_PARAM_SIZE)) ++#if 0 ++#define GET_QOS_CTRL(_pStart) ReadEF2Byte((u8 *)(_pStart) + 24) ++#define SET_QOS_CTRL(_pStart, _value) WriteEF2Byte((u8 *)(_pStart) + 24, _value) ++ ++// WMM control field. ++#define GET_QOS_CTRL_WMM_UP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 3)) ++#define SET_QOS_CTRL_WMM_UP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 3, (u8)(_value)) ++ ++#define GET_QOS_CTRL_WMM_EOSP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) ++#define SET_QOS_CTRL_WMM_EOSP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) ++ ++#define GET_QOS_CTRL_WMM_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) ++#define SET_QOS_CTRL_WMM_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) ++ ++// 802.11e control field (by STA, data) ++#define GET_QOS_CTRL_STA_DATA_TID(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 4)) ++#define SET_QOS_CTRL_STA_DATA_TID(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 4, (u8)(_value)) ++ ++#define GET_QOS_CTRL_STA_DATA_QSIZE_FLAG(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) ++#define SET_QOS_CTRL_STA_DATA_QSIZE_FLAG(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) ++ ++#define GET_QOS_CTRL_STA_DATA_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) ++#define SET_QOS_CTRL_STA_DATA_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) ++ ++#define GET_QOS_CTRL_STA_DATA_TXOP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 8, 8)) ++#define SET_QOS_CTRL_STA_DATA_TXOP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 8, 8, (u8)(_value)) ++ ++#define GET_QOS_CTRL_STA_DATA_QSIZE(_pStart) GET_QOS_CTRL_STA_DATA_TXOP(_pStart) ++#define SET_QOS_CTRL_STA_DATA_QSIZE(_pStart, _value) SET_QOS_CTRL_STA_DATA_TXOP(_pStart) ++ ++// 802.11e control field (by HC, data) ++#define GET_QOS_CTRL_HC_DATA_TID(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 4)) ++#define SET_QOS_CTRL_HC_DATA_TID(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 4, (u8)(_value)) ++ ++#define GET_QOS_CTRL_HC_DATA_EOSP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) ++#define SET_QOS_CTRL_HC_DATA_EOSP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) ++ ++#define GET_QOS_CTRL_HC_DATA_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) ++#define SET_QOS_CTRL_HC_DATA_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) ++ ++#define GET_QOS_CTRL_HC_DATA_PS_BUFSTATE(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 8, 8)) ++#define SET_QOS_CTRL_HC_DATA_PS_BUFSTATE(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 8, 8, (u8)(_value)) ++ ++// 802.11e control field (by HC, CFP) ++#define GET_QOS_CTRL_HC_CFP_TID(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 0, 4)) ++#define SET_QOS_CTRL_HC_CFP_TID(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 0, 4, (u8)(_value)) ++ ++#define GET_QOS_CTRL_HC_CFP_EOSP(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 4, 1)) ++#define SET_QOS_CTRL_HC_CFP_EOSP(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 4, 1, (u8)(_value)) ++ ++#define GET_QOS_CTRL_HC_CFP_ACK_POLICY(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 5, 2)) ++#define SET_QOS_CTRL_HC_CFP_ACK_POLICY(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 5, 2, (u8)(_value)) ++ ++#define GET_QOS_CTRL_HC_CFP_TXOP_LIMIT(_pStart) ((u8)LE_BITS_TO_2BYTE((u8 *)(_pStart)+24, 8, 8)) ++#define SET_QOS_CTRL_HC_CFP_TXOP_LIMIT(_pStart, _value) SET_BITS_TO_LE_2BYTE((u8 *)(_pStart)+24, 8, 8, (u8)(_value)) ++ ++#define SET_WMM_QOS_INFO_FIELD(_pStart, _val) WriteEF1Byte(_pStart, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_PARAMETERSET_COUNT(_pStart) LE_BITS_TO_1BYTE(_pStart, 0, 4) ++#define SET_WMM_QOS_INFO_FIELD_PARAMETERSET_COUNT(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 0, 4, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_AP_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 7, 1) ++#define SET_WMM_QOS_INFO_FIELD_AP_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 7, 1, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_STA_AC_VO_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 0, 1) ++#define SET_WMM_QOS_INFO_FIELD_STA_AC_VO_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 0, 1, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_STA_AC_VI_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 1, 1) ++#define SET_WMM_QOS_INFO_FIELD_STA_AC_VI_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 1, 1, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_STA_AC_BE_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 2, 1) ++#define SET_WMM_QOS_INFO_FIELD_STA_AC_BE_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 2, 1, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_STA_AC_BK_UAPSD(_pStart) LE_BITS_TO_1BYTE(_pStart, 3, 1) ++#define SET_WMM_QOS_INFO_FIELD_STA_AC_BK_UAPSD(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 3, 1, _val) ++ ++#define GET_WMM_QOS_INFO_FIELD_STA_MAX_SP_LEN(_pStart) LE_BITS_TO_1BYTE(_pStart, 5, 2) ++#define SET_WMM_QOS_INFO_FIELD_STA_MAX_SP_LEN(_pStart, _val) SET_BITS_TO_LE_1BYTE(_pStart, 5, 2, _val) ++ ++ ++#define WMM_INFO_ELEMENT_SIZE 7 ++ ++#define GET_WMM_INFO_ELE_OUI(_pStart) ((u8 *)(_pStart)) ++#define SET_WMM_INFO_ELE_OUI(_pStart, _pVal) PlatformMoveMemory(_pStart, _pVal, 3); ++ ++#define GET_WMM_INFO_ELE_OUI_TYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+3) ) ) ++#define SET_WMM_INFO_ELE_OUI_TYPE(_pStart, _val) ( *((u8 *)(_pStart)+3) = EF1Byte(_val) ) ++ ++#define GET_WMM_INFO_ELE_OUI_SUBTYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+4) ) ) ++#define SET_WMM_INFO_ELE_OUI_SUBTYPE(_pStart, _val) ( *((u8 *)(_pStart)+4) = EF1Byte(_val) ) ++ ++#define GET_WMM_INFO_ELE_VERSION(_pStart) ( EF1Byte( *((u8 *)(_pStart)+5) ) ) ++#define SET_WMM_INFO_ELE_VERSION(_pStart, _val) ( *((u8 *)(_pStart)+5) = EF1Byte(_val) ) ++ ++#define GET_WMM_INFO_ELE_QOS_INFO_FIELD(_pStart) ( EF1Byte( *((u8 *)(_pStart)+6) ) ) ++#define SET_WMM_INFO_ELE_QOS_INFO_FIELD(_pStart, _val) ( *((u8 *)(_pStart)+6) = EF1Byte(_val) ) ++ ++ ++ ++#define GET_WMM_AC_PARAM_AIFSN(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 0, 4) ) ++#define SET_WMM_AC_PARAM_AIFSN(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 0, 4, _val) ++ ++#define GET_WMM_AC_PARAM_ACM(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 4, 1) ) ++#define SET_WMM_AC_PARAM_ACM(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 4, 1, _val) ++ ++#define GET_WMM_AC_PARAM_ACI(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 5, 2) ) ++#define SET_WMM_AC_PARAM_ACI(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 5, 2, _val) ++ ++#define GET_WMM_AC_PARAM_ACI_AIFSN(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 0, 8) ) ++#define SET_WMM_AC_PARAM_ACI_AIFSN(_pStart, _val) SET_BTIS_TO_LE_4BYTE(_pStart, 0, 8, _val) ++ ++#define GET_WMM_AC_PARAM_ECWMIN(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 8, 4) ) ++#define SET_WMM_AC_PARAM_ECWMIN(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 8, 4, _val) ++ ++#define GET_WMM_AC_PARAM_ECWMAX(_pStart) ( (u8)LE_BITS_TO_4BYTE(_pStart, 12, 4) ) ++#define SET_WMM_AC_PARAM_ECWMAX(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 12, 4, _val) ++ ++#define GET_WMM_AC_PARAM_TXOP_LIMIT(_pStart) ( (u16)LE_BITS_TO_4BYTE(_pStart, 16, 16) ) ++#define SET_WMM_AC_PARAM_TXOP_LIMIT(_pStart, _val) SET_BITS_TO_LE_4BYTE(_pStart, 16, 16, _val) ++ ++ ++ ++ ++#define GET_WMM_PARAM_ELE_OUI(_pStart) ((u8 *)(_pStart)) ++#define SET_WMM_PARAM_ELE_OUI(_pStart, _pVal) PlatformMoveMemory(_pStart, _pVal, 3) ++ ++#define GET_WMM_PARAM_ELE_OUI_TYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+3) ) ) ++#define SET_WMM_PARAM_ELE_OUI_TYPE(_pStart, _val) ( *((u8 *)(_pStart)+3) = EF1Byte(_val) ) ++ ++#define GET_WMM_PARAM_ELE_OUI_SUBTYPE(_pStart) ( EF1Byte( *((u8 *)(_pStart)+4) ) ) ++#define SET_WMM_PARAM_ELE_OUI_SUBTYPE(_pStart, _val) ( *((u8 *)(_pStart)+4) = EF1Byte(_val) ) ++ ++#define GET_WMM_PARAM_ELE_VERSION(_pStart) ( EF1Byte( *((u8 *)(_pStart)+5) ) ) ++#define SET_WMM_PARAM_ELE_VERSION(_pStart, _val) ( *((u8 *)(_pStart)+5) = EF1Byte(_val) ) ++ ++#define GET_WMM_PARAM_ELE_QOS_INFO_FIELD(_pStart) ( EF1Byte( *((u8 *)(_pStart)+6) ) ) ++#define SET_WMM_PARAM_ELE_QOS_INFO_FIELD(_pStart, _val) ( *((u8 *)(_pStart)+6) = EF1Byte(_val) ) ++ ++#define GET_WMM_PARAM_ELE_AC_PARAM(_pStart) ( (u8 *)(_pStart)+8 ) ++#define SET_WMM_PARAM_ELE_AC_PARAM(_pStart, _pVal) PlatformMoveMemory((_pStart)+8, _pVal, 16) ++#endif ++ ++// ++// QoS Control Field ++// Ref: ++// 1. WMM spec 2.1.6: QoS Control Field, p.9. ++// 2. 802.11e/D13.0 7.1.3.5, p.26. ++// ++typedef union _QOS_CTRL_FIELD{ ++ u8 charData[2]; ++ u16 shortData; ++ ++ // WMM spec ++ struct ++ { ++ u8 UP:3; ++ u8 usRsvd1:1; ++ u8 EOSP:1; ++ u8 AckPolicy:2; ++ u8 usRsvd2:1; ++ u8 ucRsvdByte; ++ }WMM; ++ ++ // 802.11e: QoS data type frame sent by non-AP QSTAs. ++ struct ++ { ++ u8 TID:4; ++ u8 bIsQsize:1;// 0: BIT[8:15] is TXOP Duration Requested, 1: BIT[8:15] is Queue Size. ++ u8 AckPolicy:2; ++ u8 usRsvd:1; ++ u8 TxopOrQsize; // (BIT4=0)TXOP Duration Requested or (BIT4=1)Queue Size. ++ }BySta; ++ ++ // 802.11e: QoS data, QoS Null, and QoS Data+CF-Ack frames sent by HC. ++ struct ++ { ++ u8 TID:4; ++ u8 EOSP:1; ++ u8 AckPolicy:2; ++ u8 usRsvd:1; ++ u8 PSBufState; // QAP PS Buffer State. ++ }ByHc_Data; ++ ++ // 802.11e: QoS (+) CF-Poll frames sent by HC. ++ struct ++ { ++ u8 TID:4; ++ u8 EOSP:1; ++ u8 AckPolicy:2; ++ u8 usRsvd:1; ++ u8 TxopLimit; // TXOP Limit. ++ }ByHc_CFP; ++ ++}QOS_CTRL_FIELD, *PQOS_CTRL_FIELD; ++ ++ ++// ++// QoS Info Field ++// Ref: ++// 1. WMM spec 2.2.1: WME Information Element, p.11. ++// 2. 8185 QoS code: QOS_INFO [def. in QoS_mp.h] ++// ++typedef union _QOS_INFO_FIELD{ ++ u8 charData; ++ ++ struct ++ { ++ u8 ucParameterSetCount:4; ++ u8 ucReserved:4; ++ }WMM; ++ ++ struct ++ { ++ //Ref WMM_Specification_1-1.pdf, 2006-06-13 Isaiah ++ u8 ucAC_VO_UAPSD:1; ++ u8 ucAC_VI_UAPSD:1; ++ u8 ucAC_BE_UAPSD:1; ++ u8 ucAC_BK_UAPSD:1; ++ u8 ucReserved1:1; ++ u8 ucMaxSPLen:2; ++ u8 ucReserved2:1; ++ ++ }ByWmmPsSta; ++ ++ struct ++ { ++ //Ref WMM_Specification_1-1.pdf, 2006-06-13 Isaiah ++ u8 ucParameterSetCount:4; ++ u8 ucReserved:3; ++ u8 ucApUapsd:1; ++ }ByWmmPsAp; ++ ++ struct ++ { ++ u8 ucAC3_UAPSD:1; ++ u8 ucAC2_UAPSD:1; ++ u8 ucAC1_UAPSD:1; ++ u8 ucAC0_UAPSD:1; ++ u8 ucQAck:1; ++ u8 ucMaxSPLen:2; ++ u8 ucMoreDataAck:1; ++ } By11eSta; ++ ++ struct ++ { ++ u8 ucParameterSetCount:4; ++ u8 ucQAck:1; ++ u8 ucQueueReq:1; ++ u8 ucTXOPReq:1; ++ u8 ucReserved:1; ++ } By11eAp; ++ ++ struct ++ { ++ u8 ucReserved1:4; ++ u8 ucQAck:1; ++ u8 ucReserved2:2; ++ u8 ucMoreDataAck:1; ++ } ByWmmsaSta; ++ ++ struct ++ { ++ u8 ucReserved1:4; ++ u8 ucQAck:1; ++ u8 ucQueueReq:1; ++ u8 ucTXOPReq:1; ++ u8 ucReserved2:1; ++ } ByWmmsaAp; ++ ++ struct ++ { ++ u8 ucAC3_UAPSD:1; ++ u8 ucAC2_UAPSD:1; ++ u8 ucAC1_UAPSD:1; ++ u8 ucAC0_UAPSD:1; ++ u8 ucQAck:1; ++ u8 ucMaxSPLen:2; ++ u8 ucMoreDataAck:1; ++ } ByAllSta; ++ ++ struct ++ { ++ u8 ucParameterSetCount:4; ++ u8 ucQAck:1; ++ u8 ucQueueReq:1; ++ u8 ucTXOPReq:1; ++ u8 ucApUapsd:1; ++ } ByAllAp; ++ ++}QOS_INFO_FIELD, *PQOS_INFO_FIELD; ++ ++#if 0 ++// ++// WMM Information Element ++// Ref: WMM spec 2.2.1: WME Information Element, p.10. ++// ++typedef struct _WMM_INFO_ELEMENT{ ++// u8 ElementID; ++// u8 Length; ++ u8 OUI[3]; ++ u8 OUI_Type; ++ u8 OUI_SubType; ++ u8 Version; ++ QOS_INFO_FIELD QosInfo; ++}WMM_INFO_ELEMENT, *PWMM_INFO_ELEMENT; ++#endif ++ ++// ++// ACI to AC coding. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. ++// ++// AC_CODING is redefined for enum can't be ++, | under C++ compiler, 2006.05.17, by rcnjko. ++//typedef enum _AC_CODING{ ++// AC0_BE = 0, // ACI: 0x00 // Best Effort ++// AC1_BK = 1, // ACI: 0x01 // Background ++// AC2_VI = 2, // ACI: 0x10 // Video ++// AC3_VO = 3, // ACI: 0x11 // Voice ++// AC_MAX = 4, // Max: define total number; Should not to be used as a real enum. ++//}AC_CODING,*PAC_CODING; ++// ++typedef u32 AC_CODING; ++#define AC0_BE 0 // ACI: 0x00 // Best Effort ++#define AC1_BK 1 // ACI: 0x01 // Background ++#define AC2_VI 2 // ACI: 0x10 // Video ++#define AC3_VO 3 // ACI: 0x11 // Voice ++#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. ++ ++// ++// ACI/AIFSN Field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _ACI_AIFSN{ ++ u8 charData; ++ ++ struct ++ { ++ u8 AIFSN:4; ++ u8 ACM:1; ++ u8 ACI:2; ++ u8 Reserved:1; ++ }f; // Field ++}ACI_AIFSN, *PACI_AIFSN; ++ ++// ++// ECWmin/ECWmax field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. ++// ++typedef union _ECW{ ++ u8 charData; ++ struct ++ { ++ u8 ECWmin:4; ++ u8 ECWmax:4; ++ }f; // Field ++}ECW, *PECW; ++ ++// ++// AC Parameters Record Format. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _AC_PARAM{ ++ u32 longData; ++ u8 charData[4]; ++ ++ struct ++ { ++ ACI_AIFSN AciAifsn; ++ ECW Ecw; ++ u16 TXOPLimit; ++ }f; // Field ++}AC_PARAM, *PAC_PARAM; ++ ++ ++ ++// ++// QoS element subtype ++// ++typedef enum _QOS_ELE_SUBTYPE{ ++ QOSELE_TYPE_INFO = 0x00, // 0x00: Information element ++ QOSELE_TYPE_PARAM = 0x01, // 0x01: parameter element ++}QOS_ELE_SUBTYPE,*PQOS_ELE_SUBTYPE; ++ ++ ++// ++// Direction Field Values. ++// Ref: WMM spec 2.2.11: WME TSPEC Element, p.18. ++// ++typedef enum _DIRECTION_VALUE{ ++ DIR_UP = 0, // 0x00 // UpLink ++ DIR_DOWN = 1, // 0x01 // DownLink ++ DIR_DIRECT = 2, // 0x10 // DirectLink ++ DIR_BI_DIR = 3, // 0x11 // Bi-Direction ++}DIRECTION_VALUE,*PDIRECTION_VALUE; ++ ++ ++// ++// TS Info field in WMM TSPEC Element. ++// Ref: ++// 1. WMM spec 2.2.11: WME TSPEC Element, p.18. ++// 2. 8185 QoS code: QOS_TSINFO [def. in QoS_mp.h] ++// ++typedef union _QOS_TSINFO{ ++ u8 charData[3]; ++ struct { ++ u8 ucTrafficType:1; //WMM is reserved ++ u8 ucTSID:4; ++ u8 ucDirection:2; ++ u8 ucAccessPolicy:2; //WMM: bit8=0, bit7=1 ++ u8 ucAggregation:1; //WMM is reserved ++ u8 ucPSB:1; //WMMSA is APSD ++ u8 ucUP:3; ++ u8 ucTSInfoAckPolicy:2; //WMM is reserved ++ u8 ucSchedule:1; //WMM is reserved ++ u8 ucReserved:7; ++ }field; ++}QOS_TSINFO, *PQOS_TSINFO; ++ ++// ++// WMM TSPEC Body. ++// Ref: WMM spec 2.2.11: WME TSPEC Element, p.16. ++// ++typedef union _TSPEC_BODY{ ++ u8 charData[55]; ++ ++ struct ++ { ++ QOS_TSINFO TSInfo; //u8 TSInfo[3]; ++ u16 NominalMSDUsize; ++ u16 MaxMSDUsize; ++ u32 MinServiceItv; ++ u32 MaxServiceItv; ++ u32 InactivityItv; ++ u32 SuspenItv; ++ u32 ServiceStartTime; ++ u32 MinDataRate; ++ u32 MeanDataRate; ++ u32 PeakDataRate; ++ u32 MaxBurstSize; ++ u32 DelayBound; ++ u32 MinPhyRate; ++ u16 SurplusBandwidthAllowance; ++ u16 MediumTime; ++ } f; // Field ++}TSPEC_BODY, *PTSPEC_BODY; ++ ++ ++// ++// WMM TSPEC Element. ++// Ref: WMM spec 2.2.11: WME TSPEC Element, p.16. ++// ++typedef struct _WMM_TSPEC{ ++ u8 ID; ++ u8 Length; ++ u8 OUI[3]; ++ u8 OUI_Type; ++ u8 OUI_SubType; ++ u8 Version; ++ TSPEC_BODY Body; ++} WMM_TSPEC, *PWMM_TSPEC; ++ ++// ++// ACM implementation method. ++// Annie, 2005-12-13. ++// ++typedef enum _ACM_METHOD{ ++ eAcmWay0_SwAndHw = 0, // By SW and HW. ++ eAcmWay1_HW = 1, // By HW. ++ eAcmWay2_SW = 2, // By SW. ++}ACM_METHOD,*PACM_METHOD; ++ ++ ++typedef struct _ACM{ ++// u8 RegEnableACM; ++ u64 UsedTime; ++ u64 MediumTime; ++ u8 HwAcmCtl; // TRUE: UsedTime exceed => Do NOT USE this AC. It wll be written to ACM_CONTROL(0xBF BIT 0/1/2 in 8185B). ++}ACM, *PACM; ++ ++typedef u8 AC_UAPSD, *PAC_UAPSD; ++ ++#define GET_VO_UAPSD(_apsd) ((_apsd) & BIT0) ++#define SET_VO_UAPSD(_apsd) ((_apsd) |= BIT0) ++ ++#define GET_VI_UAPSD(_apsd) ((_apsd) & BIT1) ++#define SET_VI_UAPSD(_apsd) ((_apsd) |= BIT1) ++ ++#define GET_BK_UAPSD(_apsd) ((_apsd) & BIT2) ++#define SET_BK_UAPSD(_apsd) ((_apsd) |= BIT2) ++ ++#define GET_BE_UAPSD(_apsd) ((_apsd) & BIT3) ++#define SET_BE_UAPSD(_apsd) ((_apsd) |= BIT3) ++ ++ ++//typedef struct _TCLASS{ ++// TODO ++//} TCLASS, *PTCLASS; ++typedef union _QOS_TCLAS{ ++ ++ struct _TYPE_GENERAL{ ++ u8 Priority; ++ u8 ClassifierType; ++ u8 Mask; ++ } TYPE_GENERAL; ++ ++ struct _TYPE0_ETH{ ++ u8 Priority; ++ u8 ClassifierType; ++ u8 Mask; ++ u8 SrcAddr[6]; ++ u8 DstAddr[6]; ++ u16 Type; ++ } TYPE0_ETH; ++ ++ struct _TYPE1_IPV4{ ++ u8 Priority; ++ u8 ClassifierType; ++ u8 Mask; ++ u8 Version; ++ u8 SrcIP[4]; ++ u8 DstIP[4]; ++ u16 SrcPort; ++ u16 DstPort; ++ u8 DSCP; ++ u8 Protocol; ++ u8 Reserved; ++ } TYPE1_IPV4; ++ ++ struct _TYPE1_IPV6{ ++ u8 Priority; ++ u8 ClassifierType; ++ u8 Mask; ++ u8 Version; ++ u8 SrcIP[16]; ++ u8 DstIP[16]; ++ u16 SrcPort; ++ u16 DstPort; ++ u8 FlowLabel[3]; ++ } TYPE1_IPV6; ++ ++ struct _TYPE2_8021Q{ ++ u8 Priority; ++ u8 ClassifierType; ++ u8 Mask; ++ u16 TagType; ++ } TYPE2_8021Q; ++} QOS_TCLAS, *PQOS_TCLAS; ++ ++//typedef struct _WMM_TSTREAM{ ++// ++//- TSPEC ++//- AC (which to mapping) ++//} WMM_TSTREAM, *PWMM_TSTREAM; ++typedef struct _QOS_TSTREAM{ ++ u8 AC; ++ WMM_TSPEC TSpec; ++ QOS_TCLAS TClass; ++} QOS_TSTREAM, *PQOS_TSTREAM; ++ ++//typedef struct _U_APSD{ ++//- TriggerEnable [4] ++//- MaxSPLength ++//- HighestAcBuffered ++//} U_APSD, *PU_APSD; ++ ++//joseph TODO: ++// UAPSD function should be implemented by 2 data structure ++// "Qos control field" and "Qos info field" ++//typedef struct _QOS_UAPSD{ ++// u8 bTriggerEnable[4]; ++// u8 MaxSPLength; ++// u8 HighestBufAC; ++//} QOS_UAPSD, *PQOS_APSD; ++ ++//---------------------------------------------------------------------------- ++// 802.11 Management frame Status Code field ++//---------------------------------------------------------------------------- ++typedef struct _OCTET_STRING{ ++ u8 *Octet; ++ u16 Length; ++}OCTET_STRING, *POCTET_STRING; ++#if 0 ++#define FillOctetString(_os,_octet,_len) \ ++ (_os).Octet=(u8 *)(_octet); \ ++ (_os).Length=(_len); ++ ++#define WMM_ELEM_HDR_LEN 6 ++#define WMMElemSkipHdr(_osWMMElem) \ ++ (_osWMMElem).Octet += WMM_ELEM_HDR_LEN; \ ++ (_osWMMElem).Length -= WMM_ELEM_HDR_LEN; ++#endif ++// ++// STA QoS data. ++// Ref: DOT11_QOS in 8185 code. [def. in QoS_mp.h] ++// ++typedef struct _STA_QOS{ ++ //DECLARE_RT_OBJECT(STA_QOS); ++ u8 WMMIEBuf[MAX_WMMELE_LENGTH]; ++ u8* WMMIE; ++ ++ // Part 1. Self QoS Mode. ++ QOS_MODE QosCapability; //QoS Capability, 2006-06-14 Isaiah ++ QOS_MODE CurrentQosMode; ++ ++ // For WMM Power Save Mode : ++ // ACs are trigger/delivery enabled or legacy power save enabled. 2006-06-13 Isaiah ++ AC_UAPSD b4ac_Uapsd; //VoUapsd(bit0), ViUapsd(bit1), BkUapsd(bit2), BeUapsd(bit3), ++ AC_UAPSD Curr4acUapsd; ++ u8 bInServicePeriod; ++ u8 MaxSPLength; ++ int NumBcnBeforeTrigger; ++ ++ // Part 2. EDCA Parameter (perAC) ++ u8 * pWMMInfoEle; ++ u8 WMMParamEle[WMM_PARAM_ELEMENT_SIZE]; ++ u8 WMMPELength; ++ ++ // ++ //2 ToDo: remove the Qos Info Field and replace it by the above WMM Info element. ++ // By Bruce, 2008-01-30. ++ // Part 2. EDCA Parameter (perAC) ++ QOS_INFO_FIELD QosInfoField_STA; // Maintained by STA ++ QOS_INFO_FIELD QosInfoField_AP; // Retrieved from AP ++ ++ AC_PARAM CurAcParameters[4]; ++ ++ // Part 3. ACM ++ ACM acm[4]; ++ ACM_METHOD AcmMethod; ++ ++ // Part 4. Per TID (Part 5: TCLASS will be described by TStream) ++ QOS_TSTREAM TStream[16]; ++ WMM_TSPEC TSpec; ++ ++ u32 QBssWirelessMode; ++ ++ // No Ack Setting ++ u8 bNoAck; ++ ++ // Enable/Disable Rx immediate BA capability. ++ u8 bEnableRxImmBA; ++ ++}STA_QOS, *PSTA_QOS; ++ ++// ++// BSS QOS data. ++// Ref: BssDscr in 8185 code. [def. in BssDscr.h] ++// ++typedef struct _BSS_QOS{ ++ QOS_MODE bdQoSMode; ++ ++ u8 bdWMMIEBuf[MAX_WMMELE_LENGTH]; ++ u8* bdWMMIE; ++ ++ QOS_ELE_SUBTYPE EleSubType; ++ ++ u8 * pWMMInfoEle; ++ u8 * pWMMParamEle; ++ ++ QOS_INFO_FIELD QosInfoField; ++ AC_PARAM AcParameter[4]; ++}BSS_QOS, *PBSS_QOS; ++ ++ ++// ++// Ref: sQoSCtlLng and QoSCtl definition in 8185 QoS code. ++//#define QoSCtl (( (Adapter->bRegQoS) && (Adapter->dot11QoS.QoSMode &(QOS_EDCA|QOS_HCCA)) ) ?sQoSCtlLng:0) ++// ++#define sQoSCtlLng 2 ++#define QOS_CTRL_LEN(_QosMode) ((_QosMode > QOS_DISABLE)? sQoSCtlLng : 0) ++ ++ ++//Added by joseph ++//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP ++//#define UP2AC(up) ((up<3)?((up==0)?1:0):(up>>1)) ++#define IsACValid(ac) ((ac<=7 )?true:false ) ++ ++#endif // #ifndef __INC_QOS_TYPE_H +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h +@@ -0,0 +1,56 @@ ++#ifndef _TSTYPE_H_ ++#define _TSTYPE_H_ ++#include "rtl819x_Qos.h" ++#define TS_SETUP_TIMEOUT 60 // In millisecond ++#define TS_INACT_TIMEOUT 60 ++#define TS_ADDBA_DELAY 60 ++ ++#define TOTAL_TS_NUM 16 ++#define TCLAS_NUM 4 ++ ++// This define the Tx/Rx directions ++typedef enum _TR_SELECT { ++ TX_DIR = 0, ++ RX_DIR = 1, ++} TR_SELECT, *PTR_SELECT; ++ ++typedef struct _TS_COMMON_INFO{ ++ struct list_head List; ++ struct timer_list SetupTimer; ++ struct timer_list InactTimer; ++ u8 Addr[6]; ++ TSPEC_BODY TSpec; ++ QOS_TCLAS TClass[TCLAS_NUM]; ++ u8 TClasProc; ++ u8 TClasNum; ++} TS_COMMON_INFO, *PTS_COMMON_INFO; ++ ++typedef struct _TX_TS_RECORD{ ++ TS_COMMON_INFO TsCommonInfo; ++ u16 TxCurSeq; ++ BA_RECORD TxPendingBARecord; // For BA Originator ++ BA_RECORD TxAdmittedBARecord; // For BA Originator ++// QOS_DL_RECORD DLRecord; ++ u8 bAddBaReqInProgress; ++ u8 bAddBaReqDelayed; ++ u8 bUsingBa; ++ struct timer_list TsAddBaTimer; ++ u8 num; ++} TX_TS_RECORD, *PTX_TS_RECORD; ++ ++typedef struct _RX_TS_RECORD { ++ TS_COMMON_INFO TsCommonInfo; ++ u16 RxIndicateSeq; ++ u16 RxTimeoutIndicateSeq; ++ struct list_head RxPendingPktList; ++ struct timer_list RxPktPendingTimer; ++ BA_RECORD RxAdmittedBARecord; // For BA Recepient ++ u16 RxLastSeqNum; ++ u8 RxLastFragNum; ++ u8 num; ++// QOS_DL_RECORD DLRecord; ++} RX_TS_RECORD, *PRX_TS_RECORD; ++ ++ ++#endif ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c +@@ -0,0 +1,659 @@ ++#include "ieee80211.h" ++#include ++#include "rtl819x_TS.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++#define list_for_each_entry_safe(pos, n, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ n = list_entry(pos->member.next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = n, n = list_entry(n->member.next, typeof(*n), member)) ++#endif ++void TsSetupTimeOut(unsigned long data) ++{ ++ // Not implement yet ++ // This is used for WMMSA and ACM , that would send ADDTSReq frame. ++} ++ ++void TsInactTimeout(unsigned long data) ++{ ++ // Not implement yet ++ // This is used for WMMSA and ACM. ++ // This function would be call when TS is no Tx/Rx for some period of time. ++} ++ ++/******************************************************************************************************************** ++ *function: I still not understand this function, so wait for further implementation ++ * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer ++ * return: NULL ++ * notice: ++********************************************************************************************************************/ ++#if 1 ++void RxPktPendingTimeout(unsigned long data) ++{ ++ PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)data; ++ struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]); ++ ++ PRX_REORDER_ENTRY pReorderEntry = NULL; ++ ++ //u32 flags = 0; ++ unsigned long flags = 0; ++ struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE]; ++ u8 index = 0; ++ bool bPktInBuf = false; ++ ++ ++ spin_lock_irqsave(&(ieee->reorder_spinlock), flags); ++ //PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"==================>%s()\n",__FUNCTION__); ++ if(pRxTs->RxTimeoutIndicateSeq != 0xffff) ++ { ++ // Indicate the pending packets sequentially according to SeqNum until meet the gap. ++ while(!list_empty(&pRxTs->RxPendingPktList)) ++ { ++ pReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTs->RxPendingPktList.prev,RX_REORDER_ENTRY,List); ++ if(index == 0) ++ pRxTs->RxIndicateSeq = pReorderEntry->SeqNum; ++ ++ if( SN_LESS(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) || ++ SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq) ) ++ { ++ list_del_init(&pReorderEntry->List); ++ ++ if(SN_EQUAL(pReorderEntry->SeqNum, pRxTs->RxIndicateSeq)) ++ pRxTs->RxIndicateSeq = (pRxTs->RxIndicateSeq + 1) % 4096; ++ ++ IEEE80211_DEBUG(IEEE80211_DL_REORDER,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum); ++ stats_IndicateArray[index] = pReorderEntry->prxb; ++ index++; ++ ++ list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List); ++ } ++ else ++ { ++ bPktInBuf = true; ++ break; ++ } ++ } ++ } ++ ++ if(index>0) ++ { ++ // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now. ++ pRxTs->RxTimeoutIndicateSeq = 0xffff; ++ ++ // Indicate packets ++ if(index > REORDER_WIN_SIZE){ ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorer buffer full!! \n"); ++ spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); ++ return; ++ } ++ ieee80211_indicate_packets(ieee, stats_IndicateArray, index); ++ bPktInBuf = false; ++ } ++ ++ if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff)) ++ { ++ pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq; ++#if 0 ++ if(timer_pending(&pRxTs->RxPktPendingTimer)) ++ del_timer_sync(&pRxTs->RxPktPendingTimer); ++ pRxTs->RxPktPendingTimer.expires = jiffies + ieee->pHTInfo->RxReorderPendingTime; ++ add_timer(&pRxTs->RxPktPendingTimer); ++#else ++ mod_timer(&pRxTs->RxPktPendingTimer, jiffies + MSECS(ieee->pHTInfo->RxReorderPendingTime)); ++#endif ++ } ++ spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); ++ //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); ++} ++#endif ++ ++/******************************************************************************************************************** ++ *function: Add BA timer function ++ * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer ++ * return: NULL ++ * notice: ++********************************************************************************************************************/ ++void TsAddBaProcess(unsigned long data) ++{ ++ PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; ++ u8 num = pTxTs->num; ++ struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]); ++ ++ TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); ++ IEEE80211_DEBUG(IEEE80211_DL_BA, "TsAddBaProcess(): ADDBA Req is started!! \n"); ++} ++ ++ ++void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo) ++{ ++ memset(pTsCommonInfo->Addr, 0, 6); ++ memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY)); ++ memset(&pTsCommonInfo->TClass, 0, sizeof(QOS_TCLAS)*TCLAS_NUM); ++ pTsCommonInfo->TClasProc = 0; ++ pTsCommonInfo->TClasNum = 0; ++} ++ ++void ResetTxTsEntry(PTX_TS_RECORD pTS) ++{ ++ ResetTsCommonInfo(&pTS->TsCommonInfo); ++ pTS->TxCurSeq = 0; ++ pTS->bAddBaReqInProgress = false; ++ pTS->bAddBaReqDelayed = false; ++ pTS->bUsingBa = false; ++ ResetBaEntry(&pTS->TxAdmittedBARecord); //For BA Originator ++ ResetBaEntry(&pTS->TxPendingBARecord); ++} ++ ++void ResetRxTsEntry(PRX_TS_RECORD pTS) ++{ ++ ResetTsCommonInfo(&pTS->TsCommonInfo); ++ pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!! ++ pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!! ++ ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recepient ++} ++ ++void TSInitialize(struct ieee80211_device *ieee) ++{ ++ PTX_TS_RECORD pTxTS = ieee->TxTsRecord; ++ PRX_TS_RECORD pRxTS = ieee->RxTsRecord; ++ PRX_REORDER_ENTRY pRxReorderEntry = ieee->RxReorderEntry; ++ u8 count = 0; ++ IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __FUNCTION__); ++ // Initialize Tx TS related info. ++ INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); ++ INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); ++ INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); ++ ++ for(count = 0; count < TOTAL_TS_NUM; count++) ++ { ++ // ++ pTxTS->num = count; ++ // The timers for the operation of Traffic Stream and Block Ack. ++ // DLS related timer will be add here in the future!! ++ init_timer(&pTxTS->TsCommonInfo.SetupTimer); ++ pTxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pTxTS; ++ pTxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut; ++ ++ init_timer(&pTxTS->TsCommonInfo.InactTimer); ++ pTxTS->TsCommonInfo.InactTimer.data = (unsigned long)pTxTS; ++ pTxTS->TsCommonInfo.InactTimer.function = TsInactTimeout; ++ ++ init_timer(&pTxTS->TsAddBaTimer); ++ pTxTS->TsAddBaTimer.data = (unsigned long)pTxTS; ++ pTxTS->TsAddBaTimer.function = TsAddBaProcess; ++ ++ init_timer(&pTxTS->TxPendingBARecord.Timer); ++ pTxTS->TxPendingBARecord.Timer.data = (unsigned long)pTxTS; ++ pTxTS->TxPendingBARecord.Timer.function = BaSetupTimeOut; ++ ++ init_timer(&pTxTS->TxAdmittedBARecord.Timer); ++ pTxTS->TxAdmittedBARecord.Timer.data = (unsigned long)pTxTS; ++ pTxTS->TxAdmittedBARecord.Timer.function = TxBaInactTimeout; ++ ++ ResetTxTsEntry(pTxTS); ++ list_add_tail(&pTxTS->TsCommonInfo.List, &ieee->Tx_TS_Unused_List); ++ pTxTS++; ++ } ++ ++ // Initialize Rx TS related info. ++ INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); ++ INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); ++ INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); ++ for(count = 0; count < TOTAL_TS_NUM; count++) ++ { ++ pRxTS->num = count; ++ INIT_LIST_HEAD(&pRxTS->RxPendingPktList); ++ ++ init_timer(&pRxTS->TsCommonInfo.SetupTimer); ++ pRxTS->TsCommonInfo.SetupTimer.data = (unsigned long)pRxTS; ++ pRxTS->TsCommonInfo.SetupTimer.function = TsSetupTimeOut; ++ ++ init_timer(&pRxTS->TsCommonInfo.InactTimer); ++ pRxTS->TsCommonInfo.InactTimer.data = (unsigned long)pRxTS; ++ pRxTS->TsCommonInfo.InactTimer.function = TsInactTimeout; ++ ++ init_timer(&pRxTS->RxAdmittedBARecord.Timer); ++ pRxTS->RxAdmittedBARecord.Timer.data = (unsigned long)pRxTS; ++ pRxTS->RxAdmittedBARecord.Timer.function = RxBaInactTimeout; ++ ++ init_timer(&pRxTS->RxPktPendingTimer); ++ pRxTS->RxPktPendingTimer.data = (unsigned long)pRxTS; ++ pRxTS->RxPktPendingTimer.function = RxPktPendingTimeout; ++ ++ ResetRxTsEntry(pRxTS); ++ list_add_tail(&pRxTS->TsCommonInfo.List, &ieee->Rx_TS_Unused_List); ++ pRxTS++; ++ } ++ // Initialize unused Rx Reorder List. ++ INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); ++//#ifdef TO_DO_LIST ++ for(count = 0; count < REORDER_ENTRY_NUM; count++) ++ { ++ list_add_tail( &pRxReorderEntry->List,&ieee->RxReorder_Unused_List); ++ if(count == (REORDER_ENTRY_NUM-1)) ++ break; ++ pRxReorderEntry = &ieee->RxReorderEntry[count+1]; ++ } ++//#endif ++ ++} ++ ++void AdmitTS(struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, u32 InactTime) ++{ ++ del_timer_sync(&pTsCommonInfo->SetupTimer); ++ del_timer_sync(&pTsCommonInfo->InactTimer); ++ ++ if(InactTime!=0) ++ mod_timer(&pTsCommonInfo->InactTimer, jiffies + MSECS(InactTime)); ++} ++ ++ ++PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee, u8* Addr, u8 TID, TR_SELECT TxRxSelect) ++{ ++ //DIRECTION_VALUE dir; ++ u8 dir; ++ bool search_dir[4] = {0, 0, 0, 0}; ++ struct list_head* psearch_list; //FIXME ++ PTS_COMMON_INFO pRet = NULL; ++ if(ieee->iw_mode == IW_MODE_MASTER) //ap mode ++ { ++ if(TxRxSelect == TX_DIR) ++ { ++ search_dir[DIR_DOWN] = true; ++ search_dir[DIR_BI_DIR]= true; ++ } ++ else ++ { ++ search_dir[DIR_UP] = true; ++ search_dir[DIR_BI_DIR]= true; ++ } ++ } ++ else if(ieee->iw_mode == IW_MODE_ADHOC) ++ { ++ if(TxRxSelect == TX_DIR) ++ search_dir[DIR_UP] = true; ++ else ++ search_dir[DIR_DOWN] = true; ++ } ++ else ++ { ++ if(TxRxSelect == TX_DIR) ++ { ++ search_dir[DIR_UP] = true; ++ search_dir[DIR_BI_DIR]= true; ++ search_dir[DIR_DIRECT]= true; ++ } ++ else ++ { ++ search_dir[DIR_DOWN] = true; ++ search_dir[DIR_BI_DIR]= true; ++ search_dir[DIR_DIRECT]= true; ++ } ++ } ++ ++ if(TxRxSelect == TX_DIR) ++ psearch_list = &ieee->Tx_TS_Admit_List; ++ else ++ psearch_list = &ieee->Rx_TS_Admit_List; ++ ++ //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++) ++ for(dir = 0; dir <= DIR_BI_DIR; dir++) ++ { ++ if(search_dir[dir] ==false ) ++ continue; ++ list_for_each_entry(pRet, psearch_list, List){ ++ // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:"MAC_FMT", TID:%d, dir:%d\n", MAC_ARG(pRet->Addr), pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection); ++ if (memcmp(pRet->Addr, Addr, 6) == 0) ++ if (pRet->TSpec.f.TSInfo.field.ucTSID == TID) ++ if(pRet->TSpec.f.TSInfo.field.ucDirection == dir) ++ { ++ // printk("Bingo! got it\n"); ++ break; ++ } ++ ++ } ++ if(&pRet->List != psearch_list) ++ break; ++ } ++ ++ if(&pRet->List != psearch_list){ ++ return pRet ; ++ } ++ else ++ return NULL; ++} ++ ++void MakeTSEntry( ++ PTS_COMMON_INFO pTsCommonInfo, ++ u8* Addr, ++ PTSPEC_BODY pTSPEC, ++ PQOS_TCLAS pTCLAS, ++ u8 TCLAS_Num, ++ u8 TCLAS_Proc ++ ) ++{ ++ u8 count; ++ ++ if(pTsCommonInfo == NULL) ++ return; ++ ++ memcpy(pTsCommonInfo->Addr, Addr, 6); ++ ++ if(pTSPEC != NULL) ++ memcpy((u8*)(&(pTsCommonInfo->TSpec)), (u8*)pTSPEC, sizeof(TSPEC_BODY)); ++ ++ for(count = 0; count < TCLAS_Num; count++) ++ memcpy((u8*)(&(pTsCommonInfo->TClass[count])), (u8*)pTCLAS, sizeof(QOS_TCLAS)); ++ ++ pTsCommonInfo->TClasProc = TCLAS_Proc; ++ pTsCommonInfo->TClasNum = TCLAS_Num; ++} ++ ++ ++bool GetTs( ++ struct ieee80211_device* ieee, ++ PTS_COMMON_INFO *ppTS, ++ u8* Addr, ++ u8 TID, ++ TR_SELECT TxRxSelect, //Rx:1, Tx:0 ++ bool bAddNewTs ++ ) ++{ ++ u8 UP = 0; ++ // ++ // We do not build any TS for Broadcast or Multicast stream. ++ // So reject these kinds of search here. ++ // ++ if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n"); ++ return false; ++ } ++#if 0 ++ if(ieee->pStaQos->CurrentQosMode == QOS_DISABLE) ++ { UP = 0; } //only use one TS ++ else if(ieee->pStaQos->CurrentQosMode & QOS_WMM) ++ { ++#else ++ if (ieee->current_network.qos_data.supported == 0) ++ UP = 0; ++ else ++ { ++#endif ++ // In WMM case: we use 4 TID only ++ if (!IsACValid(TID)) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __FUNCTION__, TID); ++ return false; ++ } ++ ++ switch(TID) ++ { ++ case 0: ++ case 3: ++ UP = 0; ++ break; ++ ++ case 1: ++ case 2: ++ UP = 2; ++ break; ++ ++ case 4: ++ case 5: ++ UP = 5; ++ break; ++ ++ case 6: ++ case 7: ++ UP = 7; ++ break; ++ } ++ } ++ ++ *ppTS = SearchAdmitTRStream( ++ ieee, ++ Addr, ++ UP, ++ TxRxSelect); ++ if(*ppTS != NULL) ++ { ++ return true; ++ } ++ else ++ { ++ if(bAddNewTs == false) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP); ++ return false; ++ } ++ else ++ { ++ // ++ // Create a new Traffic stream for current Tx/Rx ++ // This is for EDCA and WMM to add a new TS. ++ // For HCCA or WMMSA, TS cannot be addmit without negotiation. ++ // ++ TSPEC_BODY TSpec; ++ PQOS_TSINFO pTSInfo = &TSpec.f.TSInfo; ++ struct list_head* pUnusedList = ++ (TxRxSelect == TX_DIR)? ++ (&ieee->Tx_TS_Unused_List): ++ (&ieee->Rx_TS_Unused_List); ++ ++ struct list_head* pAddmitList = ++ (TxRxSelect == TX_DIR)? ++ (&ieee->Tx_TS_Admit_List): ++ (&ieee->Rx_TS_Admit_List); ++ ++ DIRECTION_VALUE Dir = (ieee->iw_mode == IW_MODE_MASTER)? ++ ((TxRxSelect==TX_DIR)?DIR_DOWN:DIR_UP): ++ ((TxRxSelect==TX_DIR)?DIR_UP:DIR_DOWN); ++ IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n"); ++ if(!list_empty(pUnusedList)) ++ { ++ (*ppTS) = list_entry(pUnusedList->next, TS_COMMON_INFO, List); ++ list_del_init(&(*ppTS)->List); ++ if(TxRxSelect==TX_DIR) ++ { ++ PTX_TS_RECORD tmp = container_of(*ppTS, TX_TS_RECORD, TsCommonInfo); ++ ResetTxTsEntry(tmp); ++ } ++ else{ ++ PRX_TS_RECORD tmp = container_of(*ppTS, RX_TS_RECORD, TsCommonInfo); ++ ResetRxTsEntry(tmp); ++ } ++ ++ IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:"MAC_FMT"\n", UP, Dir, MAC_ARG(Addr)); ++ // Prepare TS Info releated field ++ pTSInfo->field.ucTrafficType = 0; // Traffic type: WMM is reserved in this field ++ pTSInfo->field.ucTSID = UP; // TSID ++ pTSInfo->field.ucDirection = Dir; // Direction: if there is DirectLink, this need additional consideration. ++ pTSInfo->field.ucAccessPolicy = 1; // Access policy ++ pTSInfo->field.ucAggregation = 0; // Aggregation ++ pTSInfo->field.ucPSB = 0; // Aggregation ++ pTSInfo->field.ucUP = UP; // User priority ++ pTSInfo->field.ucTSInfoAckPolicy = 0; // Ack policy ++ pTSInfo->field.ucSchedule = 0; // Schedule ++ ++ MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); ++ AdmitTS(ieee, *ppTS, 0); ++ list_add_tail(&((*ppTS)->List), pAddmitList); ++ // if there is DirectLink, we need to do additional operation here!! ++ ++ return true; ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __FUNCTION__); ++ return false; ++ } ++ } ++ } ++} ++ ++void RemoveTsEntry( ++ struct ieee80211_device* ieee, ++ PTS_COMMON_INFO pTs, ++ TR_SELECT TxRxSelect ++ ) ++{ ++ //u32 flags = 0; ++ unsigned long flags = 0; ++ del_timer_sync(&pTs->SetupTimer); ++ del_timer_sync(&pTs->InactTimer); ++ TsInitDelBA(ieee, pTs, TxRxSelect); ++ ++ if(TxRxSelect == RX_DIR) ++ { ++//#ifdef TO_DO_LIST ++ PRX_REORDER_ENTRY pRxReorderEntry; ++ PRX_TS_RECORD pRxTS = (PRX_TS_RECORD)pTs; ++ if(timer_pending(&pRxTS->RxPktPendingTimer)) ++ del_timer_sync(&pRxTS->RxPktPendingTimer); ++ ++ while(!list_empty(&pRxTS->RxPendingPktList)) ++ { ++ // PlatformAcquireSpinLock(Adapter, RT_RX_SPINLOCK); ++ spin_lock_irqsave(&(ieee->reorder_spinlock), flags); ++ //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); ++ pRxReorderEntry = (PRX_REORDER_ENTRY)list_entry(pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List); ++ list_del_init(&pRxReorderEntry->List); ++ { ++ int i = 0; ++ struct ieee80211_rxb * prxb = pRxReorderEntry->prxb; ++ if (unlikely(!prxb)) ++ { ++ spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); ++ return; ++ } ++ for(i =0; i < prxb->nr_subframes; i++) { ++ dev_kfree_skb(prxb->subframes[i]); ++ } ++ kfree(prxb); ++ prxb = NULL; ++ } ++ list_add_tail(&pRxReorderEntry->List,&ieee->RxReorder_Unused_List); ++ //PlatformReleaseSpinLock(Adapter, RT_RX_SPINLOCK); ++ spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); ++ } ++ ++//#endif ++ } ++ else ++ { ++ PTX_TS_RECORD pTxTS = (PTX_TS_RECORD)pTs; ++ del_timer_sync(&pTxTS->TsAddBaTimer); ++ } ++} ++ ++void RemovePeerTS(struct ieee80211_device* ieee, u8* Addr) ++{ ++ PTS_COMMON_INFO pTS, pTmpTS; ++ printk("===========>RemovePeerTS,"MAC_FMT"\n", MAC_ARG(Addr)); ++#if 1 ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) ++ { ++ if (memcmp(pTS->Addr, Addr, 6) == 0) ++ { ++ RemoveTsEntry(ieee, pTS, TX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); ++ } ++ } ++ ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) ++ { ++ if (memcmp(pTS->Addr, Addr, 6) == 0) ++ { ++ printk("====>remove Tx_TS_admin_list\n"); ++ RemoveTsEntry(ieee, pTS, TX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); ++ } ++ } ++ ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) ++ { ++ if (memcmp(pTS->Addr, Addr, 6) == 0) ++ { ++ RemoveTsEntry(ieee, pTS, RX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); ++ } ++ } ++ ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) ++ { ++ if (memcmp(pTS->Addr, Addr, 6) == 0) ++ { ++ RemoveTsEntry(ieee, pTS, RX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); ++ } ++ } ++#endif ++} ++ ++void RemoveAllTS(struct ieee80211_device* ieee) ++{ ++ PTS_COMMON_INFO pTS, pTmpTS; ++#if 1 ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) ++ { ++ RemoveTsEntry(ieee, pTS, TX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); ++ } ++ ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) ++ { ++ RemoveTsEntry(ieee, pTS, TX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List); ++ } ++ ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) ++ { ++ RemoveTsEntry(ieee, pTS, RX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); ++ } ++ ++ list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) ++ { ++ RemoveTsEntry(ieee, pTS, RX_DIR); ++ list_del_init(&pTS->List); ++ list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List); ++ } ++#endif ++} ++ ++void TsStartAddBaProcess(struct ieee80211_device* ieee, PTX_TS_RECORD pTxTS) ++{ ++ if(pTxTS->bAddBaReqInProgress == false) ++ { ++ pTxTS->bAddBaReqInProgress = true; ++#if 1 ++ if(pTxTS->bAddBaReqDelayed) ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_BA, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n"); ++ mod_timer(&pTxTS->TsAddBaTimer, jiffies + MSECS(TS_ADDBA_DELAY)); ++ } ++ else ++ { ++ IEEE80211_DEBUG(IEEE80211_DL_BA,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n"); ++ mod_timer(&pTxTS->TsAddBaTimer, jiffies+10); //set 10 ticks ++ } ++#endif ++ } ++ else ++ IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __FUNCTION__); ++} ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++EXPORT_SYMBOL_NOVERS(RemovePeerTS); ++#else ++//EXPORT_SYMBOL(RemovePeerTS); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/rtl_crypto.h +@@ -0,0 +1,399 @@ ++/* ++ * Scatterlist Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris ++ * Copyright (c) 2002 David S. Miller (davem@redhat.com) ++ * ++ * Portions derived from Cryptoapi, by Alexander Kjeldaas ++ * and Nettle, by Niels M鰈ler. ++ * ++ * 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. ++ * ++ */ ++#ifndef _LINUX_CRYPTO_H ++#define _LINUX_CRYPTO_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define crypto_register_alg crypto_register_alg_rsl ++#define crypto_unregister_alg crypto_unregister_alg_rsl ++#define crypto_alloc_tfm crypto_alloc_tfm_rsl ++#define crypto_free_tfm crypto_free_tfm_rsl ++#define crypto_alg_available crypto_alg_available_rsl ++ ++/* ++ * Algorithm masks and types. ++ */ ++#define CRYPTO_ALG_TYPE_MASK 0x000000ff ++#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 ++#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 ++#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 ++ ++/* ++ * Transform masks and values (for crt_flags). ++ */ ++#define CRYPTO_TFM_MODE_MASK 0x000000ff ++#define CRYPTO_TFM_REQ_MASK 0x000fff00 ++#define CRYPTO_TFM_RES_MASK 0xfff00000 ++ ++#define CRYPTO_TFM_MODE_ECB 0x00000001 ++#define CRYPTO_TFM_MODE_CBC 0x00000002 ++#define CRYPTO_TFM_MODE_CFB 0x00000004 ++#define CRYPTO_TFM_MODE_CTR 0x00000008 ++ ++#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 ++#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 ++#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 ++#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 ++#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 ++#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 ++ ++/* ++ * Miscellaneous stuff. ++ */ ++#define CRYPTO_UNSPEC 0 ++#define CRYPTO_MAX_ALG_NAME 64 ++ ++struct scatterlist; ++ ++/* ++ * Algorithms: modular crypto algorithm implementations, managed ++ * via crypto_register_alg() and crypto_unregister_alg(). ++ */ ++struct cipher_alg { ++ unsigned int cia_min_keysize; ++ unsigned int cia_max_keysize; ++ int (*cia_setkey)(void *ctx, const u8 *key, ++ unsigned int keylen, u32 *flags); ++ void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); ++ void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); ++}; ++ ++struct digest_alg { ++ unsigned int dia_digestsize; ++ void (*dia_init)(void *ctx); ++ void (*dia_update)(void *ctx, const u8 *data, unsigned int len); ++ void (*dia_final)(void *ctx, u8 *out); ++ int (*dia_setkey)(void *ctx, const u8 *key, ++ unsigned int keylen, u32 *flags); ++}; ++ ++struct compress_alg { ++ int (*coa_init)(void *ctx); ++ void (*coa_exit)(void *ctx); ++ int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++ int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++}; ++ ++#define cra_cipher cra_u.cipher ++#define cra_digest cra_u.digest ++#define cra_compress cra_u.compress ++ ++struct crypto_alg { ++ struct list_head cra_list; ++ u32 cra_flags; ++ unsigned int cra_blocksize; ++ unsigned int cra_ctxsize; ++ const char cra_name[CRYPTO_MAX_ALG_NAME]; ++ ++ union { ++ struct cipher_alg cipher; ++ struct digest_alg digest; ++ struct compress_alg compress; ++ } cra_u; ++ ++ struct module *cra_module; ++}; ++ ++/* ++ * Algorithm registration interface. ++ */ ++int crypto_register_alg(struct crypto_alg *alg); ++int crypto_unregister_alg(struct crypto_alg *alg); ++ ++/* ++ * Algorithm query interface. ++ */ ++int crypto_alg_available(const char *name, u32 flags); ++ ++/* ++ * Transforms: user-instantiated objects which encapsulate algorithms ++ * and core processing logic. Managed via crypto_alloc_tfm() and ++ * crypto_free_tfm(), as well as the various helpers below. ++ */ ++struct crypto_tfm; ++ ++struct cipher_tfm { ++ void *cit_iv; ++ unsigned int cit_ivsize; ++ u32 cit_mode; ++ int (*cit_setkey)(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen); ++ int (*cit_encrypt)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes); ++ int (*cit_encrypt_iv)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv); ++ int (*cit_decrypt)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes); ++ int (*cit_decrypt_iv)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv); ++ void (*cit_xor_block)(u8 *dst, const u8 *src); ++}; ++ ++struct digest_tfm { ++ void (*dit_init)(struct crypto_tfm *tfm); ++ void (*dit_update)(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg); ++ void (*dit_final)(struct crypto_tfm *tfm, u8 *out); ++ void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, ++ unsigned int nsg, u8 *out); ++ int (*dit_setkey)(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen); ++#ifdef CONFIG_CRYPTO_HMAC ++ void *dit_hmac_block; ++#endif ++}; ++ ++struct compress_tfm { ++ int (*cot_compress)(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++ int (*cot_decompress)(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++}; ++ ++#define crt_cipher crt_u.cipher ++#define crt_digest crt_u.digest ++#define crt_compress crt_u.compress ++ ++struct crypto_tfm { ++ ++ u32 crt_flags; ++ ++ union { ++ struct cipher_tfm cipher; ++ struct digest_tfm digest; ++ struct compress_tfm compress; ++ } crt_u; ++ ++ struct crypto_alg *__crt_alg; ++}; ++ ++/* ++ * Transform user interface. ++ */ ++ ++/* ++ * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm. ++ * If that fails and the kernel supports dynamically loadable modules, it ++ * will then attempt to load a module of the same name or alias. A refcount ++ * is grabbed on the algorithm which is then associated with the new transform. ++ * ++ * crypto_free_tfm() frees up the transform and any associated resources, ++ * then drops the refcount on the associated algorithm. ++ */ ++struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); ++void crypto_free_tfm(struct crypto_tfm *tfm); ++ ++/* ++ * Transform helpers which query the underlying algorithm. ++ */ ++static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_name; ++} ++ ++static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ ++ if (alg->cra_module) ++ return alg->cra_module->name; ++ else ++ return NULL; ++} ++ ++static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; ++} ++ ++static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->__crt_alg->cra_cipher.cia_min_keysize; ++} ++ ++static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->__crt_alg->cra_cipher.cia_max_keysize; ++} ++ ++static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_ivsize; ++} ++ ++static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_blocksize; ++} ++ ++static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ return tfm->__crt_alg->cra_digest.dia_digestsize; ++} ++ ++/* ++ * API wrappers. ++ */ ++static inline void crypto_digest_init(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_init(tfm); ++} ++ ++static inline void crypto_digest_update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, ++ unsigned int nsg) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_update(tfm, sg, nsg); ++} ++ ++static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_final(tfm, out); ++} ++ ++static inline void crypto_digest_digest(struct crypto_tfm *tfm, ++ struct scatterlist *sg, ++ unsigned int nsg, u8 *out) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_digest(tfm, sg, nsg, out); ++} ++ ++static inline int crypto_digest_setkey(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ if (tfm->crt_digest.dit_setkey == NULL) ++ return -ENOSYS; ++ return tfm->crt_digest.dit_setkey(tfm, key, keylen); ++} ++ ++static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_setkey(tfm, key, keylen); ++} ++ ++static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); ++} ++ ++static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); ++ return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); ++} ++ ++static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); ++} ++ ++static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); ++ return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); ++} ++ ++static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int len) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ memcpy(tfm->crt_cipher.cit_iv, src, len); ++} ++ ++static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, ++ u8 *dst, unsigned int len) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ memcpy(dst, tfm->crt_cipher.cit_iv, len); ++} ++ ++static inline int crypto_comp_compress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); ++ return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); ++} ++ ++static inline int crypto_comp_decompress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); ++ return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); ++} ++ ++/* ++ * HMAC support. ++ */ ++#ifdef CONFIG_CRYPTO_HMAC ++void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen); ++void crypto_hmac_update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg); ++void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ++ unsigned int *keylen, u8 *out); ++void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, ++ struct scatterlist *sg, unsigned int nsg, u8 *out); ++#endif /* CONFIG_CRYPTO_HMAC */ ++ ++#endif /* _LINUX_CRYPTO_H */ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/scatterwalk.c +@@ -0,0 +1,126 @@ ++/* ++ * Cryptographic API. ++ * ++ * Cipher operations. ++ * ++ * Copyright (c) 2002 James Morris ++ * 2002 Adam J. Richter ++ * 2004 Jean-Luc Cooke ++ * ++ * 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. ++ * ++ */ ++#include "kmap_types.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include "internal.h" ++#include "scatterwalk.h" ++ ++enum km_type crypto_km_types[] = { ++ KM_USER0, ++ KM_USER1, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++}; ++ ++void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) ++{ ++ if (nbytes <= walk->len_this_page && ++ (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <= ++ PAGE_CACHE_SIZE) ++ return walk->data; ++ else ++ return scratch; ++} ++ ++static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) ++{ ++ if (out) ++ memcpy(sgdata, buf, nbytes); ++ else ++ memcpy(buf, sgdata, nbytes); ++} ++ ++void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) ++{ ++ unsigned int rest_of_page; ++ ++ walk->sg = sg; ++ ++ walk->page = sg->page; ++ walk->len_this_segment = sg->length; ++ ++ rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); ++ walk->len_this_page = min(sg->length, rest_of_page); ++ walk->offset = sg->offset; ++} ++ ++void scatterwalk_map(struct scatter_walk *walk, int out) ++{ ++ walk->data = crypto_kmap(walk->page, out) + walk->offset; ++} ++ ++static void scatterwalk_pagedone(struct scatter_walk *walk, int out, ++ unsigned int more) ++{ ++ /* walk->data may be pointing the first byte of the next page; ++ however, we know we transfered at least one byte. So, ++ walk->data - 1 will be a virtual address in the mapped page. */ ++ ++ if (out) ++ flush_dcache_page(walk->page); ++ ++ if (more) { ++ walk->len_this_segment -= walk->len_this_page; ++ ++ if (walk->len_this_segment) { ++ walk->page++; ++ walk->len_this_page = min(walk->len_this_segment, ++ (unsigned)PAGE_CACHE_SIZE); ++ walk->offset = 0; ++ } ++ else ++ scatterwalk_start(walk, sg_next(walk->sg)); ++ } ++} ++ ++void scatterwalk_done(struct scatter_walk *walk, int out, int more) ++{ ++ crypto_kunmap(walk->data, out); ++ if (walk->len_this_page == 0 || !more) ++ scatterwalk_pagedone(walk, out, more); ++} ++ ++/* ++ * Do not call this unless the total length of all of the fragments ++ * has been verified as multiple of the block size. ++ */ ++int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, ++ size_t nbytes, int out) ++{ ++ if (buf != walk->data) { ++ while (nbytes > walk->len_this_page) { ++ memcpy_dir(buf, walk->data, walk->len_this_page, out); ++ buf += walk->len_this_page; ++ nbytes -= walk->len_this_page; ++ ++ crypto_kunmap(walk->data, out); ++ scatterwalk_pagedone(walk, out, 1); ++ scatterwalk_map(walk, out); ++ } ++ ++ memcpy_dir(buf, walk->data, nbytes, out); ++ } ++ ++ walk->offset += nbytes; ++ walk->len_this_page -= nbytes; ++ walk->len_this_segment -= nbytes; ++ return 0; ++} +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211/scatterwalk.h +@@ -0,0 +1,51 @@ ++/* ++ * Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris ++ * Copyright (c) 2002 Adam J. Richter ++ * Copyright (c) 2004 Jean-Luc Cooke ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _CRYPTO_SCATTERWALK_H ++#define _CRYPTO_SCATTERWALK_H ++#include ++#include ++ ++struct scatter_walk { ++ struct scatterlist *sg; ++ struct page *page; ++ void *data; ++ unsigned int len_this_page; ++ unsigned int len_this_segment; ++ unsigned int offset; ++}; ++ ++/* Define sg_next is an inline routine now in case we want to change ++ scatterlist to a linked list later. */ ++static inline struct scatterlist *sg_next(struct scatterlist *sg) ++{ ++ return sg + 1; ++} ++ ++static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, ++ struct scatter_walk *walk_out, ++ void *src_p, void *dst_p) ++{ ++ return walk_in->page == walk_out->page && ++ walk_in->offset == walk_out->offset && ++ walk_in->data == src_p && walk_out->data == dst_p; ++} ++ ++void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch); ++void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); ++int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); ++void scatterwalk_map(struct scatter_walk *walk, int out); ++void scatterwalk_done(struct scatter_walk *walk, int out, int more); ++ ++#endif /* _CRYPTO_SCATTERWALK_H */ +--- /dev/null ++++ b/drivers/staging/rtl8192e/ieee80211_crypt.h +@@ -0,0 +1,86 @@ ++/* ++ * Original code based on Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++/* ++ * This file defines the interface to the ieee80211 crypto module. ++ */ ++#ifndef IEEE80211_CRYPT_H ++#define IEEE80211_CRYPT_H ++ ++#include ++ ++struct ieee80211_crypto_ops { ++ const char *name; ++ ++ /* init new crypto context (e.g., allocate private data space, ++ * select IV, etc.); returns NULL on failure or pointer to allocated ++ * private data on success */ ++ void * (*init)(int keyidx); ++ ++ /* deinitialize crypto context and free allocated private data */ ++ void (*deinit)(void *priv); ++ ++ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return ++ * value from decrypt_mpdu is passed as the keyidx value for ++ * decrypt_msdu. skb must have enough head and tail room for the ++ * encryption; if not, error will be returned; these functions are ++ * called for all MPDUs (i.e., fragments). ++ */ ++ int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ ++ /* These functions are called for full MSDUs, i.e. full frames. ++ * These can be NULL if full MSDU operations are not needed. */ ++ int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, ++ void *priv); ++ ++ int (*set_key)(void *key, int len, u8 *seq, void *priv); ++ int (*get_key)(void *key, int len, u8 *seq, void *priv); ++ ++ /* procfs handler for printing out key information and possible ++ * statistics */ ++ char * (*print_stats)(char *p, void *priv); ++ ++ /* maximum number of bytes added by encryption; encrypt buf is ++ * allocated with extra_prefix_len bytes, copy of in_buf, and ++ * extra_postfix_len; encrypt need not use all this space, but ++ * the result must start at the beginning of the buffer and correct ++ * length must be returned */ ++ int extra_prefix_len, extra_postfix_len; ++ ++ struct module *owner; ++}; ++ ++struct ieee80211_crypt_data { ++ struct list_head list; /* delayed deletion list */ ++ struct ieee80211_crypto_ops *ops; ++ void *priv; ++ atomic_t refcnt; ++}; ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); ++void ieee80211_crypt_deinit_handler(unsigned long); ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8180_93cx6.c +@@ -0,0 +1,146 @@ ++/* ++ This files contains card eeprom (93c46 or 93c56) programming routines, ++ memory is addressed by 16 bits words. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#include "r8180_93cx6.h" ++ ++static void eprom_cs(struct net_device *dev, short bit) ++{ ++ if(bit) ++ write_nic_byte(dev, EPROM_CMD, ++ (1<epromtype==EPROM_93c56){ ++ addr_str[7]=addr & 1; ++ addr_str[6]=addr & (1<<1); ++ addr_str[5]=addr & (1<<2); ++ addr_str[4]=addr & (1<<3); ++ addr_str[3]=addr & (1<<4); ++ addr_str[2]=addr & (1<<5); ++ addr_str[1]=addr & (1<<6); ++ addr_str[0]=addr & (1<<7); ++ addr_len=8; ++ }else{ ++ addr_str[5]=addr & 1; ++ addr_str[4]=addr & (1<<1); ++ addr_str[3]=addr & (1<<2); ++ addr_str[2]=addr & (1<<3); ++ addr_str[1]=addr & (1<<4); ++ addr_str[0]=addr & (1<<5); ++ addr_len=6; ++ } ++ eprom_cs(dev, 1); ++ eprom_ck_cycle(dev); ++ eprom_send_bits_string(dev, read_cmd, 3); ++ eprom_send_bits_string(dev, addr_str, addr_len); ++ ++ //keep chip pin D to low state while reading. ++ //I'm unsure if it is necessary, but anyway shouldn't hurt ++ eprom_w(dev, 0); ++ ++ for(i=0;i<16;i++){ ++ //eeprom needs a clk cycle between writing opcode&adr ++ //and reading data. (eeprom outs a dummy 0) ++ eprom_ck_cycle(dev); ++ ret |= (eprom_r(dev)<<(15-i)); ++ } ++ ++ eprom_cs(dev, 0); ++ eprom_ck_cycle(dev); ++ ++ //disable EPROM programming ++ write_nic_byte(dev, EPROM_CMD, ++ (EPROM_CMD_NORMAL< ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++/*This files contains card eeprom (93c46 or 93c56) programming routines*/ ++/*memory is addressed by WORDS*/ ++ ++#include "r8192E.h" ++#include "r8192E_hw.h" ++ ++#define EPROM_DELAY 10 ++ ++#define EPROM_ANAPARAM_ADDRLWORD 0xd ++#define EPROM_ANAPARAM_ADDRHWORD 0xe ++ ++#define EPROM_RFCHIPID 0x6 ++#define EPROM_TXPW_BASE 0x05 ++#define EPROM_RFCHIPID_RTL8225U 5 ++#define EPROM_RF_PARAM 0x4 ++#define EPROM_CONFIG2 0xc ++ ++#define EPROM_VERSION 0x1E ++#define MAC_ADR 0x7 ++ ++#define CIS 0x18 ++ ++#define EPROM_TXPW0 0x16 ++#define EPROM_TXPW2 0x1b ++#define EPROM_TXPW1 0x3d ++ ++ ++u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8190_rtl8256.c +@@ -0,0 +1,1161 @@ ++/* ++ This is part of the rtl8192 driver ++ released under the GPL (See file COPYING for details). ++ ++ This files contains programming code for the rtl8256 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#include "r8192E.h" ++#include "r8192E_hw.h" ++#include "r819xE_phyreg.h" ++#include "r819xE_phy.h" ++#include "r8190_rtl8256.h" ++ ++/*-------------------------------------------------------------------------- ++ * Overview: set RF band width (20M or 40M) ++ * Input: struct net_device* dev ++ * WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M ++ * Output: NONE ++ * Return: NONE ++ * Note: 8226 support both 20M and 40 MHz ++ *---------------------------------------------------------------------------*/ ++void PHY_SetRF8256Bandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth) //20M or 40M ++{ ++ u8 eRFPath; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ { ++ if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) ++ continue; ++ ++ switch(Bandwidth) ++ { ++ case HT_CHANNEL_WIDTH_20: ++ if(priv->card_8192_version == VERSION_8190_BD || priv->card_8192_version == VERSION_8190_BE)// 8256 D-cut, E-cut, xiong: consider it later! ++ { ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0b, bMask12Bits, 0x100); //phy para:1ba ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3d7); ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0e, bMask12Bits, 0x021); ++ ++ //cosa add for sd3's request 01/23/2008 ++ //rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x5ab); ++ } ++ else ++ { ++ RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n"); ++ } ++ ++ break; ++ case HT_CHANNEL_WIDTH_20_40: ++ if(priv->card_8192_version == VERSION_8190_BD ||priv->card_8192_version == VERSION_8190_BE)// 8256 D-cut, E-cut, xiong: consider it later! ++ { ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0b, bMask12Bits, 0x300); //phy para:3ba ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3ff); ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x0e, bMask12Bits, 0x0e1); ++ ++ //cosa add for sd3's request 01/23/2008 ++ #if 0 ++ if(priv->chan == 3 || priv->chan == 9) //I need to set priv->chan whenever current channel changes ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x59b); ++ else ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x5ab); ++ #endif ++ } ++ else ++ { ++ RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n"); ++ } ++ ++ ++ break; ++ default: ++ RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth ); ++ break; ++ ++ } ++ } ++ return; ++} ++/*-------------------------------------------------------------------------- ++ * Overview: Interface to config 8256 ++ * Input: struct net_device* dev ++ * Output: NONE ++ * Return: NONE ++ *---------------------------------------------------------------------------*/ ++RT_STATUS PHY_RF8256_Config(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ // Initialize general global value ++ // ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ // TODO: Extend RF_PATH_C and RF_PATH_D in the future ++ priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; ++ // Config BB and RF ++ rtStatus = phy_RF8256_Config_ParaFile(dev); ++ ++ return rtStatus; ++} ++/*-------------------------------------------------------------------------- ++ * Overview: Interface to config 8256 ++ * Input: struct net_device* dev ++ * Output: NONE ++ * Return: NONE ++ *---------------------------------------------------------------------------*/ ++RT_STATUS phy_RF8256_Config_ParaFile(struct net_device* dev) ++{ ++ u32 u4RegValue = 0; ++ u8 eRFPath; ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ BB_REGISTER_DEFINITION_T *pPhyReg; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 RegOffSetToBeCheck = 0x3; ++ u32 RegValueToBeCheck = 0x7f1; ++ u32 RF3_Final_Value = 0; ++ u8 ConstRetryTimes = 5, RetryTimes = 5; ++ u8 ret = 0; ++ //3//----------------------------------------------------------------- ++ //3// <2> Initialize RF ++ //3//----------------------------------------------------------------- ++ for(eRFPath = (RF90_RADIO_PATH_E)RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) ++ { ++ if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) ++ continue; ++ ++ pPhyReg = &priv->PHYRegDef[eRFPath]; ++ ++ // Joseph test for shorten RF config ++ // pHalData->RfReg0Value[eRFPath] = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, rGlobalCtrl, bMaskDWord); ++ ++ /*----Store original RFENV control type----*/ ++ switch(eRFPath) ++ { ++ case RF90_PATH_A: ++ case RF90_PATH_C: ++ u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV); ++ break; ++ case RF90_PATH_B : ++ case RF90_PATH_D: ++ u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16); ++ break; ++ } ++ ++ /*----Set RF_ENV enable----*/ ++ rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); ++ ++ /*----Set RF_ENV output high----*/ ++ rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); ++ ++ /* Set bit number of Address and Data for RF register */ ++ rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 0 to 4 bits for Z-serial and set 1 to 6 bits for 8258 ++ rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for Z-serial and 8258, and set 1 to 14 bits for ??? ++ ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E) eRFPath, 0x0, bMask12Bits, 0xbf); ++ ++ /*----Check RF block (for FPGA platform only)----*/ ++ // TODO: this function should be removed on ASIC , Emily 2007.2.2 ++ rtStatus = rtl8192_phy_checkBBAndRF(dev, HW90_BLOCK_RF, (RF90_RADIO_PATH_E)eRFPath); ++ if(rtStatus!= RT_STATUS_SUCCESS) ++ { ++ RT_TRACE(COMP_ERR, "PHY_RF8256_Config():Check Radio[%d] Fail!!\n", eRFPath); ++ goto phy_RF8256_Config_ParaFile_Fail; ++ } ++ ++ RetryTimes = ConstRetryTimes; ++ RF3_Final_Value = 0; ++ /*----Initialize RF fom connfiguration file----*/ ++ switch(eRFPath) ++ { ++ case RF90_PATH_A: ++ while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) ++ { ++ ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); ++ RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); ++ RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); ++ RetryTimes--; ++ } ++ break; ++ case RF90_PATH_B: ++ while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) ++ { ++ ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); ++ RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); ++ RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); ++ RetryTimes--; ++ } ++ break; ++ case RF90_PATH_C: ++ while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) ++ { ++ ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); ++ RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); ++ RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); ++ RetryTimes--; ++ } ++ break; ++ case RF90_PATH_D: ++ while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0) ++ { ++ ret = rtl8192_phy_ConfigRFWithHeaderFile(dev,(RF90_RADIO_PATH_E)eRFPath); ++ RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits); ++ RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value); ++ RetryTimes--; ++ } ++ break; ++ } ++ ++ /*----Restore RFENV control type----*/; ++ switch(eRFPath) ++ { ++ case RF90_PATH_A: ++ case RF90_PATH_C: ++ rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); ++ break; ++ case RF90_PATH_B : ++ case RF90_PATH_D: ++ rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); ++ break; ++ } ++ ++ if(ret){ ++ RT_TRACE(COMP_ERR, "phy_RF8256_Config_ParaFile():Radio[%d] Fail!!", eRFPath); ++ goto phy_RF8256_Config_ParaFile_Fail; ++ } ++ ++ } ++ ++ RT_TRACE(COMP_PHY, "PHY Initialization Success\n") ; ++ return RT_STATUS_SUCCESS; ++ ++phy_RF8256_Config_ParaFile_Fail: ++ RT_TRACE(COMP_ERR, "PHY Initialization failed\n") ; ++ return RT_STATUS_FAILURE; ++} ++ ++ ++void PHY_SetRF8256CCKTxPower(struct net_device* dev, u8 powerlevel) ++{ ++ u32 TxAGC=0; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#ifdef RTL8190P ++ u8 byte0, byte1; ++ ++ TxAGC |= ((powerlevel<<8)|powerlevel); ++ TxAGC += priv->CCKTxPowerLevelOriginalOffset; ++ ++ if(priv->bDynamicTxLowPower == true //cosa 04282008 for cck long range ++ /*pMgntInfo->bScanInProgress == TRUE*/ ) //cosa 05/22/2008 for scan ++ { ++ if(priv->CustomerID == RT_CID_819x_Netcore) ++ TxAGC = 0x2222; ++ else ++ TxAGC += ((priv->CckPwEnl<<8)|priv->CckPwEnl); ++ } ++ ++ byte0 = (u8)(TxAGC & 0xff); ++ byte1 = (u8)((TxAGC & 0xff00)>>8); ++ if(byte0 > 0x24) ++ byte0 = 0x24; ++ if(byte1 > 0x24) ++ byte1 = 0x24; ++ if(priv->rf_type == RF_2T4R) //Only 2T4R you have to care the Antenna Tx Power offset ++ { // check antenna C over the max index 0x24 ++ if(priv->RF_C_TxPwDiff > 0) ++ { ++ if( (byte0 + (u8)priv->RF_C_TxPwDiff) > 0x24) ++ byte0 = 0x24 - priv->RF_C_TxPwDiff; ++ if( (byte1 + (u8)priv->RF_C_TxPwDiff) > 0x24) ++ byte1 = 0x24 - priv->RF_C_TxPwDiff; ++ } ++ } ++ TxAGC = (byte1<<8) |byte0; ++ write_nic_dword(dev, CCK_TXAGC, TxAGC); ++#else ++ #ifdef RTL8192E ++ ++ TxAGC = powerlevel; ++ if(priv->bDynamicTxLowPower == true)//cosa 04282008 for cck long range ++ { ++ if(priv->CustomerID == RT_CID_819x_Netcore) ++ TxAGC = 0x22; ++ else ++ TxAGC += priv->CckPwEnl; ++ } ++ if(TxAGC > 0x24) ++ TxAGC = 0x24; ++ rtl8192_setBBreg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); ++ #endif ++#endif ++} ++ ++ ++void PHY_SetRF8256OFDMTxPower(struct net_device* dev, u8 powerlevel) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //Joseph TxPower for 8192 testing ++#ifdef RTL8190P ++ u32 TxAGC1=0, TxAGC2=0, TxAGC2_tmp = 0; ++ u8 i, byteVal1[4], byteVal2[4], byteVal3[4]; ++ ++ if(priv->bDynamicTxHighPower == true) //Add by Jacken 2008/03/06 ++ { ++ TxAGC1 |= ((powerlevel<<24)|(powerlevel<<16)|(powerlevel<<8)|powerlevel); ++ //for tx power track ++ TxAGC2_tmp = TxAGC1; ++ ++ TxAGC1 += priv->MCSTxPowerLevelOriginalOffset[0]; ++ TxAGC2 =0x03030303; ++ ++ //for tx power track ++ TxAGC2_tmp += priv->MCSTxPowerLevelOriginalOffset[1]; ++ } ++ else ++ { ++ TxAGC1 |= ((powerlevel<<24)|(powerlevel<<16)|(powerlevel<<8)|powerlevel); ++ TxAGC2 = TxAGC1; ++ ++ TxAGC1 += priv->MCSTxPowerLevelOriginalOffset[0]; ++ TxAGC2 += priv->MCSTxPowerLevelOriginalOffset[1]; ++ ++ TxAGC2_tmp = TxAGC2; ++ ++ } ++ for(i=0; i<4; i++) ++ { ++ byteVal1[i] = (u8)( (TxAGC1 & (0xff<<(i*8))) >>(i*8) ); ++ if(byteVal1[i] > 0x24) ++ byteVal1[i] = 0x24; ++ byteVal2[i] = (u8)( (TxAGC2 & (0xff<<(i*8))) >>(i*8) ); ++ if(byteVal2[i] > 0x24) ++ byteVal2[i] = 0x24; ++ ++ //for tx power track ++ byteVal3[i] = (u8)( (TxAGC2_tmp & (0xff<<(i*8))) >>(i*8) ); ++ if(byteVal3[i] > 0x24) ++ byteVal3[i] = 0x24; ++ } ++ ++ if(priv->rf_type == RF_2T4R) //Only 2T4R you have to care the Antenna Tx Power offset ++ { // check antenna C over the max index 0x24 ++ if(priv->RF_C_TxPwDiff > 0) ++ { ++ for(i=0; i<4; i++) ++ { ++ if( (byteVal1[i] + (u8)priv->RF_C_TxPwDiff) > 0x24) ++ byteVal1[i] = 0x24 - priv->RF_C_TxPwDiff; ++ if( (byteVal2[i] + (u8)priv->RF_C_TxPwDiff) > 0x24) ++ byteVal2[i] = 0x24 - priv->RF_C_TxPwDiff; ++ if( (byteVal3[i] + (u8)priv->RF_C_TxPwDiff) > 0x24) ++ byteVal3[i] = 0x24 - priv->RF_C_TxPwDiff; ++ } ++ } ++ } ++ ++ TxAGC1 = (byteVal1[3]<<24) | (byteVal1[2]<<16) |(byteVal1[1]<<8) |byteVal1[0]; ++ TxAGC2 = (byteVal2[3]<<24) | (byteVal2[2]<<16) |(byteVal2[1]<<8) |byteVal2[0]; ++ ++ //for tx power track ++ TxAGC2_tmp = (byteVal3[3]<<24) | (byteVal3[2]<<16) |(byteVal3[1]<<8) |byteVal3[0]; ++ priv->Pwr_Track = TxAGC2_tmp; ++ //DbgPrint("TxAGC2_tmp = 0x%x\n", TxAGC2_tmp); ++ ++ //DbgPrint("TxAGC1/TxAGC2 = 0x%x/0x%x\n", TxAGC1, TxAGC2); ++ write_nic_dword(dev, MCS_TXAGC, TxAGC1); ++ write_nic_dword(dev, MCS_TXAGC+4, TxAGC2); ++#else ++#ifdef RTL8192E ++ u32 writeVal, powerBase0, powerBase1, writeVal_tmp; ++ u8 index = 0; ++ u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; ++ u8 byte0, byte1, byte2, byte3; ++ ++ powerBase0 = powerlevel + priv->LegacyHTTxPowerDiff; //OFDM rates ++ powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0; ++ powerBase1 = powerlevel; //MCS rates ++ powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1; ++ ++ for(index=0; index<6; index++) ++ { ++ writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index<2)?powerBase0:powerBase1); ++ byte0 = (u8)(writeVal & 0x7f); ++ byte1 = (u8)((writeVal & 0x7f00)>>8); ++ byte2 = (u8)((writeVal & 0x7f0000)>>16); ++ byte3 = (u8)((writeVal & 0x7f000000)>>24); ++ if(byte0 > 0x24) // Max power index = 0x24 ++ byte0 = 0x24; ++ if(byte1 > 0x24) ++ byte1 = 0x24; ++ if(byte2 > 0x24) ++ byte2 = 0x24; ++ if(byte3 > 0x24) ++ byte3 = 0x24; ++ ++ if(index == 3) ++ { ++ writeVal_tmp = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0; ++ priv->Pwr_Track = writeVal_tmp; ++ } ++ ++ if(priv->bDynamicTxHighPower == true) //Add by Jacken 2008/03/06 //when DM implement, add this ++ { ++ writeVal = 0x03030303; ++ } ++ else ++ { ++ writeVal = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0; ++ } ++ rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); ++ } ++ ++#endif ++#endif ++ return; ++} ++ ++#define MAX_DOZE_WAITING_TIMES_9x 64 ++static bool ++SetRFPowerState8190( ++ struct net_device* dev, ++ RT_RF_POWER_STATE eRFPowerState ++ ) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl)); ++ bool bResult = true; ++ //u8 eRFPath; ++ u8 i = 0, QueueID = 0; ++ ptx_ring head=NULL,tail=NULL; ++ ++ if(priv->SetRFPowerStateInProgress == true) ++ return false; ++ RT_TRACE(COMP_POWER, "===========> SetRFPowerState8190()!\n"); ++ priv->SetRFPowerStateInProgress = true; ++ ++ switch(priv->rf_chip) ++ { ++ case RF_8256: ++ switch( eRFPowerState ) ++ { ++ case eRfOn: ++ RT_TRACE(COMP_POWER, "SetRFPowerState8190() eRfOn !\n"); ++ //RXTX enable control: On ++ //for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ // PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x2); ++ #ifdef RTL8190P ++ if(priv->rf_type == RF_2T4R) ++ { ++ //enable RF-Chip A/B ++ rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4] ++ //enable RF-Chip C/D ++ rtl8192_setBBreg(dev, rFPGA0_XC_RFInterfaceOE, BIT4, 0x1); // 0x868[4] ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0xf);// 0x88c[11:8] ++ //digital to analog on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1e0, 0xf); // 0x880[8:5] ++ //rx antenna on ++ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0xf);// 0xc04[3:0] ++ //rx antenna on ++ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0xf);// 0xd04[3:0] ++ //analog to digital part2 on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1e00, 0xf); // 0x880[12:9] ++ } ++ else if(priv->rf_type == RF_1T2R) //RF-C, RF-D ++ { ++ //enable RF-Chip C/D ++ rtl8192_setBBreg(dev, rFPGA0_XC_RFInterfaceOE, BIT4, 0x1); // 0x868[4] ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xc00, 0x3);// 0x88c[11:10] ++ //digital to analog on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x180, 0x3); // 0x880[8:7] ++ //rx antenna on ++ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xc, 0x3);// 0xc04[3:2] ++ //rx antenna on ++ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xc, 0x3);// 0xd04[3:2] ++ //analog to digital part2 on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1800, 0x3); // 0x880[12:11] ++ } ++ #else ++ write_nic_byte(dev, ANAPAR, 0x37);//160MHz ++ write_nic_byte(dev, MacBlkCtrl, 0x17); // 0x403 ++ mdelay(1); ++ //enable clock 80/88 MHz ++ ++ priv->bHwRfOffAction = 0; ++ //} ++ ++ // Baseband reset 2008.09.30 add ++ write_nic_byte(dev, BB_RESET, (read_nic_byte(dev, BB_RESET)|BIT0)); ++ ++ //2 AFE ++ // 2008.09.30 add ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x20000000, 0x1); // 0x884 ++ //analog to digital part2 on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5] ++ //digital to analog on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x98, 0x13); // 0x880[4:3] ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf03, 0xf03);// 0x88c[9:8] ++ //rx antenna on ++ //PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0x3, 0x3);// 0xc04[1:0] ++ //rx antenna on 2008.09.30 mark ++ //PHY_SetBBReg(Adapter, rOFDM1_TRxPathEnable, 0x3, 0x3);// 0xd04[1:0] ++ ++ //2 RF ++ //enable RF-Chip A/B ++ rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4] ++ rtl8192_setBBreg(dev, rFPGA0_XB_RFInterfaceOE, BIT4, 0x1); // 0x864[4] ++ #endif ++ break; ++ ++ // ++ // In current solution, RFSleep=RFOff in order to save power under 802.11 power save. ++ // By Bruce, 2008-01-16. ++ // ++ case eRfSleep: ++ case eRfOff: ++ RT_TRACE(COMP_POWER, "SetRFPowerState8190() eRfOff/Sleep !\n"); ++ if (pPSC->bLeisurePs) ++ { ++ for(QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) ++ { ++ switch(QueueID) { ++ case MGNT_QUEUE: ++ tail=priv->txmapringtail; ++ head=priv->txmapringhead; ++ break; ++ ++ case BK_QUEUE: ++ tail=priv->txbkpringtail; ++ head=priv->txbkpringhead; ++ break; ++ ++ case BE_QUEUE: ++ tail=priv->txbepringtail; ++ head=priv->txbepringhead; ++ break; ++ ++ case VI_QUEUE: ++ tail=priv->txvipringtail; ++ head=priv->txvipringhead; ++ break; ++ ++ case VO_QUEUE: ++ tail=priv->txvopringtail; ++ head=priv->txvopringhead; ++ break; ++ ++ default: ++ tail=head=NULL; ++ break; ++ } ++ if(tail == head) ++ { ++ //DbgPrint("QueueID = %d", QueueID); ++ QueueID++; ++ continue; ++ } ++ else ++ { ++ RT_TRACE(COMP_POWER, "eRf Off/Sleep: %d times BusyQueue[%d] !=0 before doze!\n", (i+1), QueueID); ++ udelay(10); ++ i++; ++ } ++ ++ if(i >= MAX_DOZE_WAITING_TIMES_9x) ++ { ++ RT_TRACE(COMP_POWER, "\n\n\n TimeOut!! SetRFPowerState8190(): eRfOff: %d times BusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_9x, QueueID); ++ break; ++ } ++ } ++ } ++ #ifdef RTL8190P ++ if(priv->rf_type == RF_2T4R) ++ { ++ //disable RF-Chip A/B ++ rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); // 0x860[4] ++ } ++ //disable RF-Chip C/D ++ rtl8192_setBBreg(dev, rFPGA0_XC_RFInterfaceOE, BIT4, 0x0); // 0x868[4] ++ //analog to digital off, for power save ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] ++ //digital to analog off, for power save ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1e0, 0x0); // 0x880[8:5] ++ //rx antenna off ++ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0);// 0xc04[3:0] ++ //rx antenna off ++ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0);// 0xd04[3:0] ++ //analog to digital part2 off, for power save ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x1e00, 0x0); // 0x880[12:9] ++#else //8192E ++ //2 RF ++ //disable RF-Chip A/B ++ rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); // 0x860[4] ++ rtl8192_setBBreg(dev, rFPGA0_XB_RFInterfaceOE, BIT4, 0x0); // 0x864[4] ++ //2 AFE ++ //analog to digital off, for power save ++ //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf03, 0x0); // 2008.09.30 Modify ++ //digital to analog off, for power save ++ //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter1, 0x18, 0x0); // 0x880[4:3] ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x98, 0x0); // 0x880 2008.09.30 Modify ++ //rx antenna off 2008.09.30 mark ++ //PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf, 0x0);// 0xc04[3:0] ++ //rx antenna off 2008.09.30 mark ++ //PHY_SetBBReg(Adapter, rOFDM1_TRxPathEnable, 0xf, 0x0);// 0xd04[3:0] ++ //analog to digital part2 off, for power save ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); // 0x880[6:5] ++ // 2008.09.30 add ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, 0x20000000, 0x0); // 0x884 ++ ++ ++ //disable clock 80/88 MHz 2008.09.30 mark ++ //PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter1, 0x4, 0x0); // 0x880[2] ++ //2 BB ++ // Baseband reset 2008.09.30 add ++ write_nic_byte(dev, BB_RESET, (read_nic_byte(dev, BB_RESET)|BIT0)); // 0x101 ++ //MAC: off ++ write_nic_byte(dev, MacBlkCtrl, 0x0); // 0x403 ++ //slow down cpu/lbus clock from 160MHz to Lower ++ write_nic_byte(dev, ANAPAR, 0x07); // 0x 17 40MHz ++ priv->bHwRfOffAction = 0; ++ //} ++ #endif ++ break; ++ ++ default: ++ bResult = false; ++ RT_TRACE(COMP_ERR, "SetRFPowerState8190(): unknow state to set: 0x%X!!!\n", eRFPowerState); ++ break; ++ } ++ ++ break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "SetRFPowerState8190(): Unknown RF type\n"); ++ break; ++ } ++ ++ if(bResult) ++ { ++ // Update current RF state variable. ++ priv->ieee80211->eRFPowerState = eRFPowerState; ++ ++ switch(priv->rf_chip ) ++ { ++ case RF_8256: ++ switch(priv->ieee80211->eRFPowerState) ++ { ++ case eRfOff: ++ // ++ //If Rf off reason is from IPS, Led should blink with no link, by Maddest 071015 ++ // ++ if(priv->ieee80211->RfOffReason==RF_CHANGE_BY_IPS ) ++ { ++ #ifdef TO_DO ++ Adapter->HalFunc.LedControlHandler(Adapter,LED_CTL_NO_LINK); ++ #endif ++ } ++ else ++ { ++ // Turn off LED if RF is not ON. ++ #ifdef TO_DO ++ Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_OFF); ++ #endif ++ } ++ break; ++ ++ case eRfOn: ++ // Turn on RF we are still linked, which might happen when ++ // we quickly turn off and on HW RF. 2006.05.12, by rcnjko. ++ if( priv->ieee80211->state == IEEE80211_LINKED) ++ { ++ #ifdef TO_DO ++ Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_LINK); ++ #endif ++ } ++ else ++ { ++ // Turn off LED if RF is not ON. ++ #ifdef TO_DO ++ Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_NO_LINK); ++ #endif ++ } ++ break; ++ ++ default: ++ // do nothing. ++ break; ++ }// Switch RF state ++ ++ break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "SetRFPowerState8190(): Unknown RF type\n"); ++ break; ++ }// Switch RFChipID ++ } ++ ++ priv->SetRFPowerStateInProgress = false; ++ RT_TRACE(COMP_POWER, "<=========== SetRFPowerState8190() bResult = %d!\n", bResult); ++ return bResult; ++} ++ ++ ++ ++// ++// Description: ++// Change RF power state. ++// ++// Assumption: ++// This function must be executed in re-schdulable context, ++// ie. PASSIVE_LEVEL. ++// ++// 050823, by rcnjko. ++// ++static bool ++SetRFPowerState( ++ struct net_device* dev, ++ RT_RF_POWER_STATE eRFPowerState ++ ) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ bool bResult = false; ++ ++ RT_TRACE(COMP_RF,"---------> SetRFPowerState(): eRFPowerState(%d)\n", eRFPowerState); ++#ifdef RTL8192E ++ if(eRFPowerState == priv->ieee80211->eRFPowerState && priv->bHwRfOffAction == 0) ++#else ++ if(eRFPowerState == priv->ieee80211->eRFPowerState) ++#endif ++ { ++ RT_TRACE(COMP_POWER, "<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState); ++ return bResult; ++ } ++ ++ bResult = SetRFPowerState8190(dev, eRFPowerState); ++ ++ RT_TRACE(COMP_POWER, "<--------- SetRFPowerState(): bResult(%d)\n", bResult); ++ ++ return bResult; ++} ++ ++static void ++MgntDisconnectIBSS( ++ struct net_device* dev ++) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //RT_OP_MODE OpMode; ++ u8 i; ++ bool bFilterOutNonAssociatedBSSID = false; ++ ++ //IEEE80211_DEBUG(IEEE80211_DL_TRACE, "XXXXXXXXXX MgntDisconnect IBSS\n"); ++ ++ priv->ieee80211->state = IEEE80211_NOLINK; ++ ++// PlatformZeroMemory( pMgntInfo->Bssid, 6 ); ++ for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i]= 0x55; ++ priv->OpMode = RT_OP_MODE_NO_LINK; ++ write_nic_word(dev, BSSIDR, ((u16*)priv->ieee80211->current_network.bssid)[0]); ++ write_nic_dword(dev, BSSIDR+2, ((u32*)(priv->ieee80211->current_network.bssid+2))[0]); ++ { ++ RT_OP_MODE OpMode = priv->OpMode; ++ //LED_CTL_MODE LedAction = LED_CTL_NO_LINK; ++ u8 btMsr = read_nic_byte(dev, MSR); ++ ++ btMsr &= 0xfc; ++ ++ switch(OpMode) ++ { ++ case RT_OP_MODE_INFRASTRUCTURE: ++ btMsr |= MSR_LINK_MANAGED; ++ //LedAction = LED_CTL_LINK; ++ break; ++ ++ case RT_OP_MODE_IBSS: ++ btMsr |= MSR_LINK_ADHOC; ++ // led link set seperate ++ break; ++ ++ case RT_OP_MODE_AP: ++ btMsr |= MSR_LINK_MASTER; ++ //LedAction = LED_CTL_LINK; ++ break; ++ ++ default: ++ btMsr |= MSR_LINK_NONE; ++ break; ++ } ++ ++ write_nic_byte(dev, MSR, btMsr); ++ ++ // LED control ++ //Adapter->HalFunc.LedControlHandler(Adapter, LedAction); ++ } ++ ieee80211_stop_send_beacons(priv->ieee80211); ++ ++ // If disconnect, clear RCR CBSSID bit ++ bFilterOutNonAssociatedBSSID = false; ++ { ++ u32 RegRCR, Type; ++ Type = bFilterOutNonAssociatedBSSID; ++ RegRCR = read_nic_dword(dev,RCR); ++ priv->ReceiveConfig = RegRCR; ++ if (Type == true) ++ RegRCR |= (RCR_CBSSID); ++ else if (Type == false) ++ RegRCR &= (~RCR_CBSSID); ++ ++ { ++ write_nic_dword(dev, RCR,RegRCR); ++ priv->ReceiveConfig = RegRCR; ++ } ++ ++ } ++ //MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE ); ++ notify_wx_assoc_event(priv->ieee80211); ++ ++} ++ ++static void ++MlmeDisassociateRequest( ++ struct net_device* dev, ++ u8* asSta, ++ u8 asRsn ++ ) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 i; ++ ++ RemovePeerTS(priv->ieee80211, asSta); ++ ++ SendDisassociation( priv->ieee80211, asSta, asRsn ); ++ ++ if(memcpy(priv->ieee80211->current_network.bssid,asSta,6) == NULL) ++ { ++ //ShuChen TODO: change media status. ++ //ShuChen TODO: What to do when disassociate. ++ priv->ieee80211->state = IEEE80211_NOLINK; ++ //pMgntInfo->AsocTimestamp = 0; ++ for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x22; ++// pMgntInfo->mBrates.Length = 0; ++// Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_BASIC_RATE, (pu1Byte)(&pMgntInfo->mBrates) ); ++ priv->OpMode = RT_OP_MODE_NO_LINK; ++ { ++ RT_OP_MODE OpMode = priv->OpMode; ++ //LED_CTL_MODE LedAction = LED_CTL_NO_LINK; ++ u8 btMsr = read_nic_byte(dev, MSR); ++ ++ btMsr &= 0xfc; ++ ++ switch(OpMode) ++ { ++ case RT_OP_MODE_INFRASTRUCTURE: ++ btMsr |= MSR_LINK_MANAGED; ++ //LedAction = LED_CTL_LINK; ++ break; ++ ++ case RT_OP_MODE_IBSS: ++ btMsr |= MSR_LINK_ADHOC; ++ // led link set seperate ++ break; ++ ++ case RT_OP_MODE_AP: ++ btMsr |= MSR_LINK_MASTER; ++ //LedAction = LED_CTL_LINK; ++ break; ++ ++ default: ++ btMsr |= MSR_LINK_NONE; ++ break; ++ } ++ ++ write_nic_byte(dev, MSR, btMsr); ++ ++ // LED control ++ //Adapter->HalFunc.LedControlHandler(Adapter, LedAction); ++ } ++ ieee80211_disassociate(priv->ieee80211); ++ ++ write_nic_word(dev, BSSIDR, ((u16*)priv->ieee80211->current_network.bssid)[0]); ++ write_nic_dword(dev, BSSIDR+2, ((u32*)(priv->ieee80211->current_network.bssid+2))[0]); ++ ++ } ++ ++} ++ ++ ++static void ++MgntDisconnectAP( ++ struct net_device* dev, ++ u8 asRsn ++) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ bool bFilterOutNonAssociatedBSSID = false; ++ ++// ++// Commented out by rcnjko, 2005.01.27: ++// I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE(). ++// ++// //2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success ++// SecClearAllKeys(Adapter); ++ ++ // In WPA WPA2 need to Clear all key ... because new key will set after new handshaking. ++#ifdef TO_DO ++ if( pMgntInfo->SecurityInfo.AuthMode > RT_802_11AuthModeAutoSwitch || ++ (pMgntInfo->bAPSuportCCKM && pMgntInfo->bCCX8021xenable) ) // In CCKM mode will Clear key ++ { ++ SecClearAllKeys(Adapter); ++ RT_TRACE(COMP_SEC, DBG_LOUD,("======>CCKM clear key...")) ++ } ++#endif ++ // If disconnect, clear RCR CBSSID bit ++ bFilterOutNonAssociatedBSSID = false; ++ { ++ u32 RegRCR, Type; ++ ++ Type = bFilterOutNonAssociatedBSSID; ++ //Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_RCR, (pu1Byte)(&RegRCR)); ++ RegRCR = read_nic_dword(dev,RCR); ++ priv->ReceiveConfig = RegRCR; ++ ++ if (Type == true) ++ RegRCR |= (RCR_CBSSID); ++ else if (Type == false) ++ RegRCR &= (~RCR_CBSSID); ++ ++ write_nic_dword(dev, RCR,RegRCR); ++ priv->ReceiveConfig = RegRCR; ++ ++ ++ } ++ // 2004.10.11, by rcnjko. ++ //MlmeDisassociateRequest( Adapter, pMgntInfo->Bssid, disas_lv_ss ); ++ MlmeDisassociateRequest( dev, priv->ieee80211->current_network.bssid, asRsn ); ++ ++ priv->ieee80211->state = IEEE80211_NOLINK; ++ //pMgntInfo->AsocTimestamp = 0; ++} ++ ++ ++static bool ++MgntDisconnect( ++ struct net_device* dev, ++ u8 asRsn ++) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ // ++ // Schedule an workitem to wake up for ps mode, 070109, by rcnjko. ++ // ++#ifdef TO_DO ++ if(pMgntInfo->mPss != eAwake) ++ { ++ // ++ // Using AwkaeTimer to prevent mismatch ps state. ++ // In the timer the state will be changed according to the RF is being awoke or not. By Bruce, 2007-10-31. ++ // ++ // PlatformScheduleWorkItem( &(pMgntInfo->AwakeWorkItem) ); ++ PlatformSetTimer( Adapter, &(pMgntInfo->AwakeTimer), 0 ); ++ } ++#endif ++ // Follow 8180 AP mode, 2005.05.30, by rcnjko. ++#ifdef TO_DO ++ if(pMgntInfo->mActingAsAp) ++ { ++ RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> AP_DisassociateAllStation\n")); ++ AP_DisassociateAllStation(Adapter, unspec_reason); ++ return TRUE; ++ } ++#endif ++ // Indication of disassociation event. ++ //DrvIFIndicateDisassociation(Adapter, asRsn); ++ ++ // In adhoc mode, update beacon frame. ++ if( priv->ieee80211->state == IEEE80211_LINKED ) ++ { ++ if( priv->ieee80211->iw_mode == IW_MODE_ADHOC ) ++ { ++ //RT_TRACE(COMP_MLME, "MgntDisconnect() ===> MgntDisconnectIBSS\n"); ++ MgntDisconnectIBSS(dev); ++ } ++ if( priv->ieee80211->iw_mode == IW_MODE_INFRA ) ++ { ++ // We clear key here instead of MgntDisconnectAP() because that ++ // MgntActSet_802_11_DISASSOCIATE() is an interface called by OS, ++ // e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is ++ // used to handle disassociation related things to AP, e.g. send Disassoc ++ // frame to AP. 2005.01.27, by rcnjko. ++ //IEEE80211_DEBUG(IEEE80211_DL_TRACE,"MgntDisconnect() ===> MgntDisconnectAP\n"); ++ MgntDisconnectAP(dev, asRsn); ++ } ++ ++ // Inidicate Disconnect, 2005.02.23, by rcnjko. ++ //MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE); ++ } ++ ++ return true; ++} ++ ++// ++// Description: ++// Chang RF Power State. ++// Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE. ++// ++// Assumption: ++// PASSIVE LEVEL. ++// ++bool ++MgntActSet_RF_State( ++ struct net_device* dev, ++ RT_RF_POWER_STATE StateToSet, ++ RT_RF_CHANGE_SOURCE ChangeSource ++ ) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ bool bActionAllowed = false; ++ bool bConnectBySSID = false; ++ RT_RF_POWER_STATE rtState; ++ u16 RFWaitCounter = 0; ++ unsigned long flag; ++ RT_TRACE(COMP_POWER, "===>MgntActSet_RF_State(): StateToSet(%d)\n",StateToSet); ++ ++ //1// ++ //1//<1>Prevent the race condition of RF state change. ++ //1// ++ // Only one thread can change the RF state at one time, and others should wait to be executed. By Bruce, 2007-11-28. ++ ++ while(true) ++ { ++ spin_lock_irqsave(&priv->rf_ps_lock,flag); ++ if(priv->RFChangeInProgress) ++ { ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ RT_TRACE(COMP_POWER, "MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", StateToSet); ++ ++ // Set RF after the previous action is done. ++ while(priv->RFChangeInProgress) ++ { ++ RFWaitCounter ++; ++ RT_TRACE(COMP_POWER, "MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", RFWaitCounter); ++ udelay(1000); // 1 ms ++ ++ // Wait too long, return FALSE to avoid to be stuck here. ++ if(RFWaitCounter > 100) ++ { ++ RT_TRACE(COMP_ERR, "MgntActSet_RF_State(): Wait too logn to set RF\n"); ++ // TODO: Reset RF state? ++ return false; ++ } ++ } ++ } ++ else ++ { ++ priv->RFChangeInProgress = true; ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ break; ++ } ++ } ++ ++ rtState = priv->ieee80211->eRFPowerState; ++ ++ switch(StateToSet) ++ { ++ case eRfOn: ++ // ++ // Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or ++ // the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02. ++ // ++ ++ priv->ieee80211->RfOffReason &= (~ChangeSource); ++ ++ if(! priv->ieee80211->RfOffReason) ++ { ++ priv->ieee80211->RfOffReason = 0; ++ bActionAllowed = true; ++ ++ ++ if(rtState == eRfOff && ChangeSource >=RF_CHANGE_BY_HW ) ++ { ++ bConnectBySSID = true; ++ } ++ } ++ else ++ RT_TRACE(COMP_POWER, "MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", priv->ieee80211->RfOffReason, ChangeSource); ++ ++ break; ++ ++ case eRfOff: ++ ++ if (priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ // ++ // 060808, Annie: ++ // Disconnect to current BSS when radio off. Asked by QuanTa. ++ // ++ // Set all link status falg, by Bruce, 2007-06-26. ++ //MgntActSet_802_11_DISASSOCIATE( Adapter, disas_lv_ss ); ++ MgntDisconnect(dev, disas_lv_ss); ++ ++ // Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. ++ // 2007.05.28, by shien chang. ++ ++ } ++ ++ ++ priv->ieee80211->RfOffReason |= ChangeSource; ++ bActionAllowed = true; ++ break; ++ ++ case eRfSleep: ++ priv->ieee80211->RfOffReason |= ChangeSource; ++ bActionAllowed = true; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if(bActionAllowed) ++ { ++ RT_TRACE(COMP_POWER, "MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->ieee80211->RfOffReason); ++ // Config HW to the specified mode. ++ SetRFPowerState(dev, StateToSet); ++ // Turn on RF. ++ if(StateToSet == eRfOn) ++ { ++ //Adapter->HalFunc.HalEnableRxHandler(Adapter); ++ if(bConnectBySSID) ++ { ++ //MgntActSet_802_11_SSID(Adapter, Adapter->MgntInfo.Ssid.Octet, Adapter->MgntInfo.Ssid.Length, TRUE ); ++ } ++ } ++ // Turn off RF. ++ else if(StateToSet == eRfOff) ++ { ++ //Adapter->HalFunc.HalDisableRxHandler(Adapter); ++ } ++ } ++ else ++ { ++ RT_TRACE(COMP_POWER, "MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", StateToSet, ChangeSource, priv->ieee80211->RfOffReason); ++ } ++ ++ // Release RF spinlock ++ spin_lock_irqsave(&priv->rf_ps_lock,flag); ++ priv->RFChangeInProgress = false; ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ ++ RT_TRACE(COMP_POWER, "<===MgntActSet_RF_State()\n"); ++ return bActionAllowed; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8190_rtl8256.h +@@ -0,0 +1,28 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello ++ ++ This files contains programming code for the rtl8256 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#ifndef RTL8225H ++#define RTL8225H ++ ++#ifdef RTL8190P ++#define RTL819X_TOTAL_RF_PATH 4 ++#else ++#define RTL819X_TOTAL_RF_PATH 2 //for 8192E ++#endif ++extern void PHY_SetRF8256Bandwidth(struct net_device* dev , HT_CHANNEL_WIDTH Bandwidth); ++extern RT_STATUS PHY_RF8256_Config(struct net_device* dev); ++extern RT_STATUS phy_RF8256_Config_ParaFile(struct net_device* dev); ++extern void PHY_SetRF8256CCKTxPower(struct net_device* dev, u8 powerlevel); ++extern void PHY_SetRF8256OFDMTxPower(struct net_device* dev, u8 powerlevel); ++extern bool MgntActSet_RF_State(struct net_device* dev, RT_RF_POWER_STATE StateToSet, RT_RF_CHANGE_SOURCE ChangeSource); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E.h +@@ -0,0 +1,1554 @@ ++/* ++ This is part of rtl8187 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver ++ ++ Parts of this driver are based on the rtl8192 driver skeleton ++ from Patric Schenke & Andres Salomon ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#ifndef R819xU_H ++#define R819xU_H ++ ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include //for rtnl_lock() ++#include ++#include ++#include // Necessary because we use the proc fs ++#include ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)) ++#include ++#endif ++#include "ieee80211.h" ++ ++ ++ ++ ++#define RTL819xE_MODULE_NAME "rtl819xE" ++//added for HW security, john.0629 ++#define FALSE 0 ++#define TRUE 1 ++#define MAX_KEY_LEN 61 ++#define KEY_BUF_SIZE 5 ++ ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++// Rx smooth factor ++#define Rx_Smooth_Factor 20 ++/* 2007/06/04 MH Define sliding window for RSSI history. */ ++#define PHY_RSSI_SLID_WIN_MAX 100 ++#define PHY_Beacon_RSSI_SLID_WIN_MAX 10 ++ ++#define IC_VersionCut_D 0x3 ++#define IC_VersionCut_E 0x4 ++ ++#if 0 //we need to use RT_TRACE instead DMESG as RT_TRACE will clearly show debug level wb. ++#define DMESG(x,a...) printk(KERN_INFO RTL819xE_MODULE_NAME ": " x "\n", ## a) ++#define DMESGW(x,a...) printk(KERN_WARNING RTL819xE_MODULE_NAME ": WW:" x "\n", ## a) ++#define DMESGE(x,a...) printk(KERN_WARNING RTL819xE_MODULE_NAME ": EE:" x "\n", ## a) ++#else ++#define DMESG(x,a...) ++#define DMESGW(x,a...) ++#define DMESGE(x,a...) ++extern u32 rt_global_debug_component; ++#define RT_TRACE(component, x, args...) \ ++do { if(rt_global_debug_component & component) \ ++ printk(KERN_DEBUG RTL819xE_MODULE_NAME ":" x "\n" , \ ++ ##args);\ ++}while(0); ++ ++#define COMP_TRACE BIT0 // For function call tracing. ++#define COMP_DBG BIT1 // Only for temporary debug message. ++#define COMP_INIT BIT2 // during driver initialization / halt / reset. ++ ++ ++#define COMP_RECV BIT3 // Reveive part data path. ++#define COMP_SEND BIT4 // Send part path. ++#define COMP_IO BIT5 // I/O Related. Added by Annie, 2006-03-02. ++#define COMP_POWER BIT6 // 802.11 Power Save mode or System/Device Power state related. ++#define COMP_EPROM BIT7 // 802.11 link related: join/start BSS, leave BSS. ++#define COMP_SWBW BIT8 // For bandwidth switch. ++#define COMP_SEC BIT9// For Security. ++ ++ ++#define COMP_TURBO BIT10 // For Turbo Mode related. By Annie, 2005-10-21. ++#define COMP_QOS BIT11 // For QoS. ++ ++#define COMP_RATE BIT12 // For Rate Adaptive mechanism, 2006.07.02, by rcnjko. #define COMP_EVENTS 0x00000080 // Event handling ++#define COMP_RXDESC BIT13 // Show Rx desc information for SD3 debug. Added by Annie, 2006-07-15. ++#define COMP_PHY BIT14 ++#define COMP_DIG BIT15 // For DIG, 2006.09.25, by rcnjko. ++#define COMP_TXAGC BIT16 // For Tx power, 060928, by rcnjko. ++#define COMP_HALDM BIT17 // For HW Dynamic Mechanism, 061010, by rcnjko. ++#define COMP_POWER_TRACKING BIT18 //FOR 8190 TX POWER TRACKING ++#define COMP_EVENTS BIT19 // Event handling ++ ++#define COMP_RF BIT20 // For RF. ++//1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++//1//1Attention Please!!!<11n or 8190 specific code should be put below this line> ++//1!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ ++#define COMP_FIRMWARE BIT21 //for firmware downloading ++#define COMP_HT BIT22 // For 802.11n HT related information. by Emily 2006-8-11 ++ ++#define COMP_RESET BIT23 ++#define COMP_CMDPKT BIT24 ++#define COMP_SCAN BIT25 ++#define COMP_IPS BIT26 ++#define COMP_DOWN BIT27 // for rm driver module ++#define COMP_INTR BIT28 // for interrupt ++#define COMP_ERR BIT31 // for error out, always on ++#endif ++ ++#define RTL819x_DEBUG ++#ifdef RTL819x_DEBUG ++#define assert(expr) \ ++ if (!(expr)) { \ ++ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ ++ #expr,__FILE__,__FUNCTION__,__LINE__); \ ++ } ++//wb added to debug out data buf ++//if you want print DATA buffer related BA, please set ieee80211_debug_level to DATA|BA ++#define RT_DEBUG_DATA(level, data, datalen) \ ++ do{ if ((rt_global_debug_component & (level)) == (level)) \ ++ { \ ++ int i; \ ++ u8* pdata = (u8*) data; \ ++ printk(KERN_DEBUG RTL819xE_MODULE_NAME ": %s()\n", __FUNCTION__); \ ++ for(i=0; i<(int)(datalen); i++) \ ++ { \ ++ printk("%2x ", pdata[i]); \ ++ if ((i+1)%16 == 0) printk("\n"); \ ++ } \ ++ printk("\n"); \ ++ } \ ++ } while (0) ++#else ++#define assert(expr) do {} while (0) ++#define RT_DEBUG_DATA(level, data, datalen) do {} while(0) ++#endif /* RTL8169_DEBUG */ ++ ++ ++// ++// Queue Select Value in TxDesc ++// ++#define QSLT_BK 0x1 ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x4 ++#define QSLT_VO 0x6 ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++#define DESC90_RATE1M 0x00 ++#define DESC90_RATE2M 0x01 ++#define DESC90_RATE5_5M 0x02 ++#define DESC90_RATE11M 0x03 ++#define DESC90_RATE6M 0x04 ++#define DESC90_RATE9M 0x05 ++#define DESC90_RATE12M 0x06 ++#define DESC90_RATE18M 0x07 ++#define DESC90_RATE24M 0x08 ++#define DESC90_RATE36M 0x09 ++#define DESC90_RATE48M 0x0a ++#define DESC90_RATE54M 0x0b ++#define DESC90_RATEMCS0 0x00 ++#define DESC90_RATEMCS1 0x01 ++#define DESC90_RATEMCS2 0x02 ++#define DESC90_RATEMCS3 0x03 ++#define DESC90_RATEMCS4 0x04 ++#define DESC90_RATEMCS5 0x05 ++#define DESC90_RATEMCS6 0x06 ++#define DESC90_RATEMCS7 0x07 ++#define DESC90_RATEMCS8 0x08 ++#define DESC90_RATEMCS9 0x09 ++#define DESC90_RATEMCS10 0x0a ++#define DESC90_RATEMCS11 0x0b ++#define DESC90_RATEMCS12 0x0c ++#define DESC90_RATEMCS13 0x0d ++#define DESC90_RATEMCS14 0x0e ++#define DESC90_RATEMCS15 0x0f ++#define DESC90_RATEMCS32 0x20 ++ ++#define RTL819X_DEFAULT_RF_TYPE RF_1T2R ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x4 ++#define IEEE80211_WATCH_DOG_TIME 2000 ++ ++/* For rtl819x */ ++typedef struct _tx_desc_819x_pci { ++ //DWORD 0 ++ u16 PktSize; ++ u8 Offset; ++ u8 Reserved1:3; ++ u8 CmdInit:1; ++ u8 LastSeg:1; ++ u8 FirstSeg:1; ++ u8 LINIP:1; ++ u8 OWN:1; ++ ++ //DWORD 1 ++ u8 TxFWInfoSize; ++ u8 RATid:3; ++ u8 DISFB:1; ++ u8 USERATE:1; ++ u8 MOREFRAG:1; ++ u8 NoEnc:1; ++ u8 PIFS:1; ++ u8 QueueSelect:5; ++ u8 NoACM:1; ++ u8 Resv:2; ++ u8 SecCAMID:5; ++ u8 SecDescAssign:1; ++ u8 SecType:2; ++ ++ //DWORD 2 ++ u16 TxBufferSize; ++ u8 PktId:7; ++ u8 Resv1:1; ++ u8 Reserved2; ++ ++ //DWORD 3 ++ u32 TxBuffAddr; ++ ++ //DWORD 4 ++ u32 NextDescAddress; ++ ++ //DWORD 5,6,7 ++ u32 Reserved5; ++ u32 Reserved6; ++ u32 Reserved7; ++}tx_desc_819x_pci, *ptx_desc_819x_pci; ++ ++ ++typedef struct _tx_desc_cmd_819x_pci { ++ //DWORD 0 ++ u16 PktSize; ++ u8 Reserved1; ++ u8 CmdType:3; ++ u8 CmdInit:1; ++ u8 LastSeg:1; ++ u8 FirstSeg:1; ++ u8 LINIP:1; ++ u8 OWN:1; ++ ++ //DOWRD 1 ++ u16 ElementReport; ++ u16 Reserved2; ++ ++ //DOWRD 2 ++ u16 TxBufferSize; ++ u16 Reserved3; ++ ++ //DWORD 3,4,5 ++ u32 TxBufferAddr; ++ u32 NextDescAddress; ++ u32 Reserved4; ++ u32 Reserved5; ++ u32 Reserved6; ++}tx_desc_cmd_819x_pci, *ptx_desc_cmd_819x_pci; ++ ++ ++typedef struct _tx_fwinfo_819x_pci { ++ //DOWRD 0 ++ u8 TxRate:7; ++ u8 CtsEnable:1; ++ u8 RtsRate:7; ++ u8 RtsEnable:1; ++ u8 TxHT:1; ++ u8 Short:1; //Short PLCP for CCK, or short GI for 11n MCS ++ u8 TxBandwidth:1; // This is used for HT MCS rate only. ++ u8 TxSubCarrier:2; // This is used for legacy OFDM rate only. ++ u8 STBC:2; ++ u8 AllowAggregation:1; ++ u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate ++ u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS ++ u8 RtsBandwidth:1; // This is used for HT MCS rate only. ++ u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only. ++ u8 RtsSTBC:2; ++ u8 EnableCPUDur:1; //Enable firmware to recalculate and assign packet duration ++ ++ //DWORD 1 ++ u8 RxMF:2; ++ u8 RxAMD:3; ++ u8 Reserved1:3; ++ u8 Reserved2; ++ u8 Reserved3; ++ u8 Reserved4; ++ ++ //u32 Reserved; ++}tx_fwinfo_819x_pci, *ptx_fwinfo_819x_pci; ++ ++typedef struct rtl8192_rx_info { ++ struct urb *urb; ++ struct net_device *dev; ++ u8 out_pipe; ++}rtl8192_rx_info ; ++typedef struct _rx_desc_819x_pci{ ++ //DOWRD 0 ++ u16 Length:14; ++ u16 CRC32:1; ++ u16 ICV:1; ++ u8 RxDrvInfoSize; ++ u8 Shift:2; ++ u8 PHYStatus:1; ++ u8 SWDec:1; ++ u8 LastSeg:1; ++ u8 FirstSeg:1; ++ u8 EOR:1; ++ u8 OWN:1; ++ ++ //DWORD 1 ++ u32 Reserved2; ++ ++ //DWORD 2 ++ u32 Reserved3; ++ ++ //DWORD 3 ++ u32 BufferAddress; ++ ++}rx_desc_819x_pci, *prx_desc_819x_pci; ++ ++typedef struct _rx_fwinfo_819x_pci{ ++ //DWORD 0 ++ u16 Reserved1:12; ++ u16 PartAggr:1; ++ u16 FirstAGGR:1; ++ u16 Reserved2:2; ++ ++ u8 RxRate:7; ++ u8 RxHT:1; ++ ++ u8 BW:1; ++ u8 SPLCP:1; ++ u8 Reserved3:2; ++ u8 PAM:1; ++ u8 Mcast:1; ++ u8 Bcast:1; ++ u8 Reserved4:1; ++ ++ //DWORD 1 ++ u32 TSFL; ++ ++}rx_fwinfo_819x_pci, *prx_fwinfo_819x_pci; ++ ++#define MAX_DEV_ADDR_SIZE 8 /* support till 64 bit bus width OS */ ++#define MAX_FIRMWARE_INFORMATION_SIZE 32 /*2006/04/30 by Emily forRTL8190*/ ++#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE) ++#define ENCRYPTION_MAX_OVERHEAD 128 ++//#define USB_HWDESC_HEADER_LEN sizeof(tx_desc_819x_usb) ++//#define TX_PACKET_SHIFT_BYTES (USB_HWDESC_HEADER_LEN + sizeof(tx_fwinfo_819x_usb)) ++#define MAX_FRAGMENT_COUNT 8 ++#define MAX_TRANSMIT_BUFFER_SIZE (1600+(MAX_802_11_HEADER_LENGTH+ENCRYPTION_MAX_OVERHEAD)*MAX_FRAGMENT_COUNT) ++ ++#define scrclng 4 // octets for crc32 (FCS, ICV) ++/* 8190 Loopback Mode definition */ ++typedef enum _rtl819x_loopback{ ++ RTL819X_NO_LOOPBACK = 0, ++ RTL819X_MAC_LOOPBACK = 1, ++ RTL819X_DMA_LOOPBACK = 2, ++ RTL819X_CCK_LOOPBACK = 3, ++}rtl819x_loopback_e; ++ ++/* due to rtl8192 firmware */ ++typedef enum _desc_packet_type_e{ ++ DESC_PACKET_TYPE_INIT = 0, ++ DESC_PACKET_TYPE_NORMAL = 1, ++}desc_packet_type_e; ++ ++typedef enum _firmware_source{ ++ FW_SOURCE_IMG_FILE = 0, ++ FW_SOURCE_HEADER_FILE = 1, //from header file ++}firmware_source_e, *pfirmware_source_e; ++ ++typedef enum _firmware_status{ ++ FW_STATUS_0_INIT = 0, ++ FW_STATUS_1_MOVE_BOOT_CODE = 1, ++ FW_STATUS_2_MOVE_MAIN_CODE = 2, ++ FW_STATUS_3_TURNON_CPU = 3, ++ FW_STATUS_4_MOVE_DATA_CODE = 4, ++ FW_STATUS_5_READY = 5, ++}firmware_status_e; ++ ++typedef struct _rt_firmare_seg_container { ++ u16 seg_size; ++ u8 *seg_ptr; ++}fw_seg_container, *pfw_seg_container; ++ ++typedef struct _rt_firmware{ ++ firmware_status_e firmware_status; ++ u16 cmdpacket_frag_thresold; ++#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k ++#define MAX_FW_INIT_STEP 3 ++ u8 firmware_buf[MAX_FW_INIT_STEP][RTL8190_MAX_FIRMWARE_CODE_SIZE]; ++ u16 firmware_buf_size[MAX_FW_INIT_STEP]; ++}rt_firmware, *prt_firmware; ++//+by amy 080507 ++#define MAX_RECEIVE_BUFFER_SIZE 9100 // Add this to 9100 bytes to receive A-MSDU from RT-AP ++ ++/* Firmware Queue Layout */ ++#define NUM_OF_FIRMWARE_QUEUE 10 ++#define NUM_OF_PAGES_IN_FW 0x100 ++#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x0aa ++#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x007 ++#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x024 ++#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x007 ++#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0 ++#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x2 ++#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x10 ++#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0 ++#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4 ++#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xd ++#define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000 ++#define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00 ++#define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08 ++#define RSVD_FW_QUEUE_PAGE_VI_SHIFT 0x10 ++#define RSVD_FW_QUEUE_PAGE_VO_SHIFT 0x18 ++#define RSVD_FW_QUEUE_PAGE_MGNT_SHIFT 0x10 ++#define RSVD_FW_QUEUE_PAGE_CMD_SHIFT 0x08 ++#define RSVD_FW_QUEUE_PAGE_BCN_SHIFT 0x00 ++#define RSVD_FW_QUEUE_PAGE_PUB_SHIFT 0x08 ++ ++//8187B Security ++//#define RWCAM 0xA0 // Software read/write CAM config ++//#define WCAMI 0xA4 // Software write CAM input content ++//#define RCAMO 0xA8 // Output value from CAM according to 0xa0 setting ++#define DCAM 0xAC // Debug CAM Interface ++#define AESMSK_FC 0xB2 // AES Mask register for frame control (0xB2~0xB3). Added by Annie, 2006-03-06. ++ ++ ++#define CAM_CONTENT_COUNT 8 ++//#define CFG_DEFAULT_KEY BIT5 ++#define CFG_VALID BIT15 ++#if 0 ++//---------------------------------------------------------------------------- ++// 8187B WPA Config Register (offset 0xb0, 1 byte) ++//---------------------------------------------------------------------------- ++#define SCR_UseDK 0x01 ++#define SCR_TxSecEnable 0x02 ++#define SCR_RxSecEnable 0x04 ++ ++//---------------------------------------------------------------------------- ++// 8187B CAM Config Setting (offset 0xb0, 1 byte) ++//---------------------------------------------------------------------------- ++#define CAM_VALID 0x8000 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK 0x0020 ++ ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++ ++//#define CAM_SIZE 16 ++#define TOTAL_CAM_ENTRY 16 ++#define CAM_ENTRY_LEN_IN_DW 6 // 6, unit: in u4byte. Added by Annie, 2006-05-25. ++#define CAM_ENTRY_LEN_IN_BYTE (CAM_ENTRY_LEN_IN_DW*sizeof(u32)) // 24, unit: in u1byte. Added by Annie, 2006-05-25. ++ ++#define CAM_CONFIG_USEDK 1 ++#define CAM_CONFIG_NO_USEDK 0 ++ ++#define CAM_WRITE 0x00010000 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG 0x80000000 ++ ++//================================================================= ++//================================================================= ++ ++#endif ++#define EPROM_93c46 0 ++#define EPROM_93c56 1 ++ ++#define DEFAULT_FRAG_THRESHOLD 2342U ++#define MIN_FRAG_THRESHOLD 256U ++#define DEFAULT_BEACONINTERVAL 0x64U ++#define DEFAULT_BEACON_ESSID "Rtl819xU" ++ ++#define DEFAULT_SSID "" ++#define DEFAULT_RETRY_RTS 7 ++#define DEFAULT_RETRY_DATA 7 ++#define PRISM_HDR_SIZE 64 ++ ++#define PHY_RSSI_SLID_WIN_MAX 100 ++ ++ ++typedef enum _WIRELESS_MODE { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_A = 0x01, ++ WIRELESS_MODE_B = 0x02, ++ WIRELESS_MODE_G = 0x04, ++ WIRELESS_MODE_AUTO = 0x08, ++ WIRELESS_MODE_N_24G = 0x10, ++ WIRELESS_MODE_N_5G = 0x20 ++} WIRELESS_MODE; ++ ++#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 ++ ++typedef struct buffer ++{ ++ struct buffer *next; ++ u32 *buf; ++ dma_addr_t dma; ++ ++} buffer; ++ ++typedef struct rtl_reg_debug{ ++ unsigned int cmd; ++ struct { ++ unsigned char type; ++ unsigned char addr; ++ unsigned char page; ++ unsigned char length; ++ } head; ++ unsigned char buf[0xff]; ++}rtl_reg_debug; ++ ++#if 0 ++ ++typedef struct tx_pendingbuf ++{ ++ struct ieee80211_txb *txb; ++ short ispending; ++ short descfrag; ++} tx_pendigbuf; ++ ++#endif ++ ++typedef struct _rt_9x_tx_rate_history { ++ u32 cck[4]; ++ u32 ofdm[8]; ++ // HT_MCS[0][]: BW=0 SG=0 ++ // HT_MCS[1][]: BW=1 SG=0 ++ // HT_MCS[2][]: BW=0 SG=1 ++ // HT_MCS[3][]: BW=1 SG=1 ++ u32 ht_mcs[4][16]; ++}rt_tx_rahis_t, *prt_tx_rahis_t; ++ ++typedef struct _RT_SMOOTH_DATA_4RF { ++ char elements[4][100];//array to store values ++ u32 index; //index to current array to store ++ u32 TotalNum; //num of valid elements ++ u32 TotalVal[4]; //sum of valid elements ++}RT_SMOOTH_DATA_4RF, *PRT_SMOOTH_DATA_4RF; ++ ++typedef enum _tag_TxCmd_Config_Index{ ++ TXCMD_TXRA_HISTORY_CTRL = 0xFF900000, ++ TXCMD_RESET_TX_PKT_BUFF = 0xFF900001, ++ TXCMD_RESET_RX_PKT_BUFF = 0xFF900002, ++ TXCMD_SET_TX_DURATION = 0xFF900003, ++ TXCMD_SET_RX_RSSI = 0xFF900004, ++ TXCMD_SET_TX_PWR_TRACKING = 0xFF900005, ++ TXCMD_XXXX_CTRL, ++}DCMD_TXCMD_OP; ++ ++typedef struct Stats ++{ ++ unsigned long txrdu; ++ unsigned long rxrdu; ++ //unsigned long rxnolast; ++ //unsigned long rxnodata; ++// unsigned long rxreset; ++// unsigned long rxnopointer; ++ unsigned long rxok; ++ unsigned long rxframgment; ++ unsigned long rxcmdpkt[4]; //08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query ++ unsigned long rxurberr; ++ unsigned long rxstaterr; ++ unsigned long rxcrcerrmin;//crc error (0-500) ++ unsigned long rxcrcerrmid;//crc error (500-1000) ++ unsigned long rxcrcerrmax;//crc error (>1000) ++ unsigned long received_rate_histogram[4][32]; //0: Total, 1:OK, 2:CRC, 3:ICV, 2007 07 03 cosa ++ unsigned long received_preamble_GI[2][32]; //0: Long preamble/GI, 1:Short preamble/GI ++ unsigned long rx_AMPDUsize_histogram[5]; // level: (<4K), (4K~8K), (8K~16K), (16K~32K), (32K~64K) ++ unsigned long rx_AMPDUnum_histogram[5]; // level: (<5), (5~10), (10~20), (20~40), (>40) ++ unsigned long numpacket_matchbssid; // debug use only. ++ unsigned long numpacket_toself; // debug use only. ++ unsigned long num_process_phyinfo; // debug use only. ++ unsigned long numqry_phystatus; ++ unsigned long numqry_phystatusCCK; ++ unsigned long numqry_phystatusHT; ++ unsigned long received_bwtype[5]; //0: 20M, 1: funn40M, 2: upper20M, 3: lower20M, 4: duplicate ++ unsigned long txnperr; ++ unsigned long txnpdrop; ++ unsigned long txresumed; ++// unsigned long rxerr; ++ unsigned long rxoverflow; ++ unsigned long rxint; ++ unsigned long txnpokint; ++// unsigned long txhpokint; ++// unsigned long txhperr; ++ unsigned long ints; ++ unsigned long shints; ++ unsigned long txoverflow; ++// unsigned long rxdmafail; ++// unsigned long txbeacon; ++// unsigned long txbeaconerr; ++ unsigned long txlpokint; ++ unsigned long txlpdrop; ++ unsigned long txlperr; ++ unsigned long txbeokint; ++ unsigned long txbedrop; ++ unsigned long txbeerr; ++ unsigned long txbkokint; ++ unsigned long txbkdrop; ++ unsigned long txbkerr; ++ unsigned long txviokint; ++ unsigned long txvidrop; ++ unsigned long txvierr; ++ unsigned long txvookint; ++ unsigned long txvodrop; ++ unsigned long txvoerr; ++ unsigned long txbeaconokint; ++ unsigned long txbeacondrop; ++ unsigned long txbeaconerr; ++ unsigned long txmanageokint; ++ unsigned long txmanagedrop; ++ unsigned long txmanageerr; ++ unsigned long txcmdpktokint; ++ unsigned long txdatapkt; ++ unsigned long txfeedback; ++ unsigned long txfeedbackok; ++ unsigned long txoktotal; ++ unsigned long txokbytestotal; ++ unsigned long txokinperiod; ++ unsigned long txmulticast; ++ unsigned long txbytesmulticast; ++ unsigned long txbroadcast; ++ unsigned long txbytesbroadcast; ++ unsigned long txunicast; ++ unsigned long txbytesunicast; ++ unsigned long rxbytesunicast; ++ unsigned long txfeedbackfail; ++ unsigned long txerrtotal; ++ unsigned long txerrbytestotal; ++ unsigned long txerrmulticast; ++ unsigned long txerrbroadcast; ++ unsigned long txerrunicast; ++ unsigned long txretrycount; ++ unsigned long txfeedbackretry; ++ u8 last_packet_rate; ++ unsigned long slide_signal_strength[100]; ++ unsigned long slide_evm[100]; ++ unsigned long slide_rssi_total; // For recording sliding window's RSSI value ++ unsigned long slide_evm_total; // For recording sliding window's EVM value ++ long signal_strength; // Transformed, in dbm. Beautified signal strength for UI, not correct. ++ long signal_quality; ++ long last_signal_strength_inpercent; ++ long recv_signal_power; // Correct smoothed ss in Dbm, only used in driver to report real power now. ++ u8 rx_rssi_percentage[4]; ++ u8 rx_evm_percentage[2]; ++ long rxSNRdB[4]; ++ rt_tx_rahis_t txrate; ++ u32 Slide_Beacon_pwdb[100]; //cosa add for beacon rssi ++ u32 Slide_Beacon_Total; //cosa add for beacon rssi ++ RT_SMOOTH_DATA_4RF cck_adc_pwdb; ++ u32 CurrentShowTxate; ++ ++ ++} Stats; ++ ++ ++// Bandwidth Offset ++#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 ++#define HAL_PRIME_CHNL_OFFSET_LOWER 1 ++#define HAL_PRIME_CHNL_OFFSET_UPPER 2 ++ ++//+by amy 080507 ++ ++typedef struct ChnlAccessSetting { ++ u16 SIFS_Timer; ++ u16 DIFS_Timer; ++ u16 SlotTimeTimer; ++ u16 EIFS_Timer; ++ u16 CWminIndex; ++ u16 CWmaxIndex; ++}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING; ++ ++typedef struct _BB_REGISTER_DEFINITION{ ++ u32 rfintfs; // set software control: // 0x870~0x877[8 bytes] ++ u32 rfintfi; // readback data: // 0x8e0~0x8e7[8 bytes] ++ u32 rfintfo; // output data: // 0x860~0x86f [16 bytes] ++ u32 rfintfe; // output enable: // 0x860~0x86f [16 bytes] ++ u32 rf3wireOffset; // LSSI data: // 0x840~0x84f [16 bytes] ++ u32 rfLSSI_Select; // BB Band Select: // 0x878~0x87f [8 bytes] ++ u32 rfTxGainStage; // Tx gain stage: // 0x80c~0x80f [4 bytes] ++ u32 rfHSSIPara1; // wire parameter control1 : // 0x820~0x823,0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] ++ u32 rfHSSIPara2; // wire parameter control2 : // 0x824~0x827,0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] ++ u32 rfSwitchControl; //Tx Rx antenna control : // 0x858~0x85f [16 bytes] ++ u32 rfAGCControl1; //AGC parameter control1 : // 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] ++ u32 rfAGCControl2; //AGC parameter control2 : // 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] ++ u32 rfRxIQImbalance; //OFDM Rx IQ imbalance matrix : // 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] ++ u32 rfRxAFE; //Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : // 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] ++ u32 rfTxIQImbalance; //OFDM Tx IQ imbalance matrix // 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] ++ u32 rfTxAFE; //Tx IQ DC Offset and Tx DFIR type // 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] ++ u32 rfLSSIReadBack; //LSSI RF readback data // 0x8a0~0x8af [16 bytes] ++}BB_REGISTER_DEFINITION_T, *PBB_REGISTER_DEFINITION_T; ++ ++typedef enum _RT_RF_TYPE_819xU{ ++ RF_TYPE_MIN = 0, ++ RF_8225, ++ RF_8256, ++ RF_8258, ++ RF_PSEUDO_11N = 4, ++}RT_RF_TYPE_819xU, *PRT_RF_TYPE_819xU; ++ ++ ++typedef struct _rate_adaptive ++{ ++ u8 rate_adaptive_disabled; ++ u8 ratr_state; ++ u16 reserve; ++ ++ u32 high_rssi_thresh_for_ra; ++ u32 high2low_rssi_thresh_for_ra; ++ u8 low2high_rssi_thresh_for_ra40M; ++ u32 low_rssi_thresh_for_ra40M; ++ u8 low2high_rssi_thresh_for_ra20M; ++ u32 low_rssi_thresh_for_ra20M; ++ u32 upper_rssi_threshold_ratr; ++ u32 middle_rssi_threshold_ratr; ++ u32 low_rssi_threshold_ratr; ++ u32 low_rssi_threshold_ratr_40M; ++ u32 low_rssi_threshold_ratr_20M; ++ u8 ping_rssi_enable; //cosa add for test ++ u32 ping_rssi_ratr; //cosa add for test ++ u32 ping_rssi_thresh_for_ra;//cosa add for test ++ u32 last_ratr; ++ ++} rate_adaptive, *prate_adaptive; ++#define TxBBGainTableLength 37 ++#define CCKTxBBGainTableLength 23 ++typedef struct _txbbgain_struct ++{ ++ long txbb_iq_amplifygain; ++ u32 txbbgain_value; ++} txbbgain_struct, *ptxbbgain_struct; ++ ++typedef struct _ccktxbbgain_struct ++{ ++ //The Value is from a22 to a29 one Byte one time is much Safer ++ u8 ccktxbb_valuearray[8]; ++} ccktxbbgain_struct,*pccktxbbgain_struct; ++ ++ ++typedef struct _init_gain ++{ ++ u8 xaagccore1; ++ u8 xbagccore1; ++ u8 xcagccore1; ++ u8 xdagccore1; ++ u8 cca; ++ ++} init_gain, *pinit_gain; ++ ++/* 2007/11/02 MH Define RF mode temporarily for test. */ ++typedef enum tag_Rf_Operatetion_State ++{ ++ RF_STEP_INIT = 0, ++ RF_STEP_NORMAL, ++ RF_STEP_MAX ++}RF_STEP_E; ++ ++typedef enum _RT_STATUS{ ++ RT_STATUS_SUCCESS, ++ RT_STATUS_FAILURE, ++ RT_STATUS_PENDING, ++ RT_STATUS_RESOURCE ++}RT_STATUS,*PRT_STATUS; ++ ++typedef enum _RT_CUSTOMER_ID ++{ ++ RT_CID_DEFAULT = 0, ++ RT_CID_8187_ALPHA0 = 1, ++ RT_CID_8187_SERCOMM_PS = 2, ++ RT_CID_8187_HW_LED = 3, ++ RT_CID_8187_NETGEAR = 4, ++ RT_CID_WHQL = 5, ++ RT_CID_819x_CAMEO = 6, ++ RT_CID_819x_RUNTOP = 7, ++ RT_CID_819x_Senao = 8, ++ RT_CID_TOSHIBA = 9, // Merge by Jacken, 2008/01/31. ++ RT_CID_819x_Netcore = 10, ++ RT_CID_Nettronix = 11, ++ RT_CID_DLINK = 12, ++ RT_CID_PRONET = 13, ++ RT_CID_COREGA = 14, ++}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID; ++ ++//================================================================================ ++// LED customization. ++//================================================================================ ++ ++typedef enum _LED_STRATEGY_8190{ ++ SW_LED_MODE0, // SW control 1 LED via GPIO0. It is default option. ++ SW_LED_MODE1, // SW control for PCI Express ++ SW_LED_MODE2, // SW control for Cameo. ++ SW_LED_MODE3, // SW contorl for RunTop. ++ SW_LED_MODE4, // SW control for Netcore ++ SW_LED_MODE5, //added by vivi, for led new mode, DLINK ++ SW_LED_MODE6, //added by vivi, for led new mode, PRONET ++ HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes) ++}LED_STRATEGY_8190, *PLED_STRATEGY_8190; ++ ++#define CHANNEL_PLAN_LEN 10 ++ ++#define sCrcLng 4 ++ ++typedef struct _TX_FWINFO_STRUCUTRE{ ++ //DOWRD 0 ++ u8 TxRate:7; ++ u8 CtsEnable:1; ++ u8 RtsRate:7; ++ u8 RtsEnable:1; ++ u8 TxHT:1; ++ u8 Short:1; ++ u8 TxBandwidth:1; ++ u8 TxSubCarrier:2; ++ u8 STBC:2; ++ u8 AllowAggregation:1; ++ u8 RtsHT:1; ++ u8 RtsShort:1; ++ u8 RtsBandwidth:1; ++ u8 RtsSubcarrier:2; ++ u8 RtsSTBC:2; ++ u8 EnableCPUDur:1; ++ ++ //DWORD 1 ++ u32 RxMF:2; ++ u32 RxAMD:3; ++ u32 Reserved1:3; ++ u32 TxAGCOffset:4; ++ u32 TxAGCSign:1; ++ u32 Tx_INFO_RSVD:6; ++ u32 PacketID:13; ++}TX_FWINFO_T; ++ ++ ++typedef struct _TX_FWINFO_8190PCI{ ++ //DOWRD 0 ++ u8 TxRate:7; ++ u8 CtsEnable:1; ++ u8 RtsRate:7; ++ u8 RtsEnable:1; ++ u8 TxHT:1; ++ u8 Short:1; //Short PLCP for CCK, or short GI for 11n MCS ++ u8 TxBandwidth:1; // This is used for HT MCS rate only. ++ u8 TxSubCarrier:2; // This is used for legacy OFDM rate only. ++ u8 STBC:2; ++ u8 AllowAggregation:1; ++ u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate ++ u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS ++ u8 RtsBandwidth:1; // This is used for HT MCS rate only. ++ u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only. ++ u8 RtsSTBC:2; ++ u8 EnableCPUDur:1; //Enable firmware to recalculate and assign packet duration ++ ++ //DWORD 1 ++ u32 RxMF:2; ++ u32 RxAMD:3; ++ u32 TxPerPktInfoFeedback:1; // 1: indicate that the transimission info of this packet should be gathered by Firmware and retured by Rx Cmd. ++ u32 Reserved1:2; ++ u32 TxAGCOffset:4; // Only 90 support ++ u32 TxAGCSign:1; // Only 90 support ++ u32 RAW_TXD:1; // MAC will send data in txpktbuffer without any processing,such as CRC check ++ u32 Retry_Limit:4; // CCX Support relative retry limit FW page only support 4 bits now. ++ u32 Reserved2:1; ++ u32 PacketID:13; ++ ++ // DW 2 ++ ++}TX_FWINFO_8190PCI, *PTX_FWINFO_8190PCI; ++ ++typedef struct _phy_ofdm_rx_status_report_819xpci ++{ ++ u8 trsw_gain_X[4]; ++ u8 pwdb_all; ++ u8 cfosho_X[4]; ++ u8 cfotail_X[4]; ++ u8 rxevm_X[2]; ++ u8 rxsnr_X[4]; ++ u8 pdsnr_X[2]; ++ u8 csi_current_X[2]; ++ u8 csi_target_X[2]; ++ u8 sigevm; ++ u8 max_ex_pwr; ++ u8 sgi_en; ++ u8 rxsc_sgien_exflg; ++}phy_sts_ofdm_819xpci_t; ++ ++typedef struct _phy_cck_rx_status_report_819xpci ++{ ++ /* For CCK rate descriptor. This is a unsigned 8:1 variable. LSB bit presend ++ 0.5. And MSB 7 bts presend a signed value. Range from -64~+63.5. */ ++ u8 adc_pwdb_X[4]; ++ u8 sq_rpt; ++ u8 cck_agc_rpt; ++}phy_sts_cck_819xpci_t; ++ ++typedef struct _phy_ofdm_rx_status_rxsc_sgien_exintfflag{ ++ u8 reserved:4; ++ u8 rxsc:2; ++ u8 sgi_en:1; ++ u8 ex_intf_flag:1; ++}phy_ofdm_rx_status_rxsc_sgien_exintfflag; ++ ++typedef enum _RT_OP_MODE{ ++ RT_OP_MODE_AP, ++ RT_OP_MODE_INFRASTRUCTURE, ++ RT_OP_MODE_IBSS, ++ RT_OP_MODE_NO_LINK, ++}RT_OP_MODE, *PRT_OP_MODE; ++ ++ ++/* 2007/11/02 MH Define RF mode temporarily for test. */ ++typedef enum tag_Rf_OpType ++{ ++ RF_OP_By_SW_3wire = 0, ++ RF_OP_By_FW, ++ RF_OP_MAX ++}RF_OpType_E; ++ ++typedef enum _RESET_TYPE { ++ RESET_TYPE_NORESET = 0x00, ++ RESET_TYPE_NORMAL = 0x01, ++ RESET_TYPE_SILENT = 0x02 ++} RESET_TYPE; ++ ++typedef struct _tx_ring{ ++ u32 * desc; ++ u8 nStuckCount; ++ struct _tx_ring * next; ++}__attribute__ ((packed)) tx_ring, * ptx_ring; ++ ++struct rtl8192_tx_ring { ++ tx_desc_819x_pci *desc; ++ dma_addr_t dma; ++ unsigned int idx; ++ unsigned int entries; ++ struct sk_buff_head queue; ++}; ++ ++#define NIC_SEND_HANG_THRESHOLD_NORMAL 4 ++#define NIC_SEND_HANG_THRESHOLD_POWERSAVE 8 ++#define MAX_TX_QUEUE 9 // BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. ++ ++#define MAX_RX_COUNT 64 ++#define MAX_TX_QUEUE_COUNT 9 ++ ++typedef struct r8192_priv ++{ ++ struct pci_dev *pdev; ++ //added for maintain info from eeprom ++ short epromtype; ++ u16 eeprom_vid; ++ u16 eeprom_did; ++ u8 eeprom_CustomerID; ++ u16 eeprom_ChannelPlan; ++ RT_CUSTOMER_ID CustomerID; ++ LED_STRATEGY_8190 LedStrategy; ++ //bool bDcut; ++ u8 IC_Cut; ++ int irq; ++ short irq_enabled; ++ struct ieee80211_device *ieee80211; ++ bool being_init_adapter; ++ u8 Rf_Mode; ++ short card_8192; /* O: rtl8192, 1:rtl8185 V B/C, 2:rtl8185 V D */ ++ u8 card_8192_version; /* if TCR reports card V B/C this discriminates */ ++// short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */ ++ short enable_gpio0; ++ enum card_type {PCI,MINIPCI,CARDBUS,USB/*rtl8187*/}card_type; ++ short hw_plcp_len; ++ short plcp_preamble_mode; ++ u8 ScanDelay; ++ spinlock_t irq_lock; ++ spinlock_t irq_th_lock; ++ spinlock_t tx_lock; ++ spinlock_t rf_ps_lock; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) ++ struct semaphore mutex; ++#else ++ struct mutex mutex; ++#endif ++ spinlock_t rf_lock; //used to lock rf write operation added by wb ++ spinlock_t ps_lock; ++ ++ u32 irq_mask; ++// short irq_enabled; ++// struct net_device *dev; //comment this out. ++ short chan; ++ short sens; ++ short max_sens; ++ u32 rx_prevlen; ++/*RX stuff*/ ++ rx_desc_819x_pci *rx_ring; ++ dma_addr_t rx_ring_dma; ++ unsigned int rx_idx; ++ struct sk_buff *rx_buf[MAX_RX_COUNT]; ++ int rxringcount; ++ u16 rxbuffersize; ++ ++ ++ struct sk_buff *rx_skb; ++ u32 *rxring; ++ u32 *rxringtail; ++ dma_addr_t rxringdma; ++ struct buffer *rxbuffer; ++ struct buffer *rxbufferhead; ++ short rx_skb_complete; ++/*TX stuff*/ ++ struct rtl8192_tx_ring tx_ring[MAX_TX_QUEUE_COUNT]; ++ int txringcount; ++//{ ++ int txbuffsize; ++ int txfwbuffersize; ++ //struct tx_pendingbuf txnp_pending; ++ //struct tasklet_struct irq_tx_tasklet; ++ struct tasklet_struct irq_rx_tasklet; ++ struct tasklet_struct irq_tx_tasklet; ++ struct tasklet_struct irq_prepare_beacon_tasklet; ++ struct buffer *txmapbufs; ++ struct buffer *txbkpbufs; ++ struct buffer *txbepbufs; ++ struct buffer *txvipbufs; ++ struct buffer *txvopbufs; ++ struct buffer *txcmdbufs; ++ struct buffer *txmapbufstail; ++ struct buffer *txbkpbufstail; ++ struct buffer *txbepbufstail; ++ struct buffer *txvipbufstail; ++ struct buffer *txvopbufstail; ++ struct buffer *txcmdbufstail; ++ /* adhoc/master mode stuff */ ++ ptx_ring txbeaconringtail; ++ dma_addr_t txbeaconringdma; ++ ptx_ring txbeaconring; ++ int txbeaconcount; ++ struct buffer *txbeaconbufs; ++ struct buffer *txbeaconbufstail; ++ ptx_ring txmapring; ++ ptx_ring txbkpring; ++ ptx_ring txbepring; ++ ptx_ring txvipring; ++ ptx_ring txvopring; ++ ptx_ring txcmdring; ++ ptx_ring txmapringtail; ++ ptx_ring txbkpringtail; ++ ptx_ring txbepringtail; ++ ptx_ring txvipringtail; ++ ptx_ring txvopringtail; ++ ptx_ring txcmdringtail; ++ ptx_ring txmapringhead; ++ ptx_ring txbkpringhead; ++ ptx_ring txbepringhead; ++ ptx_ring txvipringhead; ++ ptx_ring txvopringhead; ++ ptx_ring txcmdringhead; ++ dma_addr_t txmapringdma; ++ dma_addr_t txbkpringdma; ++ dma_addr_t txbepringdma; ++ dma_addr_t txvipringdma; ++ dma_addr_t txvopringdma; ++ dma_addr_t txcmdringdma; ++ // u8 chtxpwr[15]; //channels from 1 to 14, 0 not used ++// u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used ++// u8 cck_txpwr_base; ++// u8 ofdm_txpwr_base; ++// u8 challow[15]; //channels from 1 to 14, 0 not used ++ short up; ++ short crcmon; //if 1 allow bad crc frame reception in monitor mode ++// short prism_hdr; ++ ++// struct timer_list scan_timer; ++ /*short scanpending; ++ short stopscan;*/ ++// spinlock_t scan_lock; ++// u8 active_probe; ++ //u8 active_scan_num; ++ struct semaphore wx_sem; ++ struct semaphore rf_sem; //used to lock rf write operation added by wb, modified by david ++// short hw_wep; ++ ++// short digphy; ++// short antb; ++// short diversity; ++// u8 cs_treshold; ++// short rcr_csense; ++ u8 rf_type; //0 means 1T2R, 1 means 2T4R ++ RT_RF_TYPE_819xU rf_chip; ++ ++// u32 key0[4]; ++ short (*rf_set_sens)(struct net_device *dev,short sens); ++ u8 (*rf_set_chan)(struct net_device *dev,u8 ch); ++ void (*rf_close)(struct net_device *dev); ++ void (*rf_init)(struct net_device *dev); ++ //short rate; ++ short promisc; ++ /*stats*/ ++ struct Stats stats; ++ struct iw_statistics wstats; ++ struct proc_dir_entry *dir_dev; ++ ++ /*RX stuff*/ ++// u32 *rxring; ++// u32 *rxringtail; ++// dma_addr_t rxringdma; ++ ++#ifdef THOMAS_BEACON ++ u32 *oldaddr; ++#endif ++#ifdef THOMAS_TASKLET ++ atomic_t irt_counter;//count for irq_rx_tasklet ++#endif ++#ifdef JACKSON_NEW_RX ++ struct sk_buff **pp_rxskb; ++ int rx_inx; ++#endif ++ ++/* modified by davad for Rx process */ ++ struct sk_buff_head rx_queue; ++ struct sk_buff_head skb_queue; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ struct tq_struct qos_activate; ++#else ++ struct work_struct qos_activate; ++#endif ++ short tx_urb_index; ++ atomic_t tx_pending[0x10];//UART_PRIORITY+1 ++ ++ struct urb *rxurb_task; ++ ++ //2 Tx Related variables ++ u16 ShortRetryLimit; ++ u16 LongRetryLimit; ++ u32 TransmitConfig; ++ u8 RegCWinMin; // For turbo mode CW adaptive. Added by Annie, 2005-10-27. ++ ++ u32 LastRxDescTSFHigh; ++ u32 LastRxDescTSFLow; ++ ++ ++ //2 Rx Related variables ++ u16 EarlyRxThreshold; ++ u32 ReceiveConfig; ++ u8 AcmControl; ++ ++ u8 RFProgType; ++ ++ u8 retry_data; ++ u8 retry_rts; ++ u16 rts; ++ ++ struct ChnlAccessSetting ChannelAccessSetting; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct work_struct reset_wq; ++#else ++ struct tq_struct reset_wq; ++#endif ++ ++/**********************************************************/ ++//for rtl819xPci ++ // Data Rate Config. Added by Annie, 2006-04-13. ++ u16 basic_rate; ++ u8 short_preamble; ++ u8 slot_time; ++ u16 SifsTime; ++/* WirelessMode*/ ++ u8 RegWirelessMode; ++/*Firmware*/ ++ prt_firmware pFirmware; ++ rtl819x_loopback_e LoopbackMode; ++ firmware_source_e firmware_source; ++ bool AutoloadFailFlag; ++ u16 EEPROMTxPowerDiff; ++ u16 EEPROMAntPwDiff; // Antenna gain offset from B/C/D to A ++ u8 EEPROMThermalMeter; ++ u8 EEPROMPwDiff; ++ u8 EEPROMCrystalCap; ++ u8 EEPROM_Def_Ver; ++ u8 EEPROMTxPowerLevelCCK[14];// CCK channel 1~14 ++ // The following definition is for eeprom 93c56 ++ u8 EEPROMRfACCKChnl1TxPwLevel[3]; //RF-A CCK Tx Power Level at channel 7 ++ u8 EEPROMRfAOfdmChnlTxPwLevel[3];//RF-A CCK Tx Power Level at [0],[1],[2] = channel 1,7,13 ++ u8 EEPROMRfCCCKChnl1TxPwLevel[3]; //RF-C CCK Tx Power Level at channel 7 ++ u8 EEPROMRfCOfdmChnlTxPwLevel[3];//RF-C CCK Tx Power Level at [0],[1],[2] = channel 1,7,13 ++ u8 EEPROMTxPowerLevelCCK_V1[3]; ++ u8 EEPROMTxPowerLevelOFDM24G[14]; // OFDM 2.4G channel 1~14 ++ u8 EEPROMTxPowerLevelOFDM5G[24]; // OFDM 5G ++ u8 EEPROMLegacyHTTxPowerDiff; // Legacy to HT rate power diff ++ bool bTXPowerDataReadFromEEPORM; ++/*channel plan*/ ++ u16 RegChannelPlan; // Channel Plan specifed by user, 15: following setting of EEPROM, 0-14: default channel plan index specified by user. ++ u16 ChannelPlan; ++/*PS related*/ ++ bool RegRfOff; ++ // Rf off action for power save ++ u8 bHwRfOffAction; //0:No action, 1:By GPIO, 2:By Disable ++/*PHY related*/ ++ BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D ++ // Read/write are allow for following hardware information variables ++ u32 MCSTxPowerLevelOriginalOffset[6]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ u8 TxPowerLevelCCK[14]; // CCK channel 1~14 ++ u8 TxPowerLevelCCK_A[14]; // RF-A, CCK channel 1~14 ++ u8 TxPowerLevelCCK_C[14]; ++ u8 TxPowerLevelOFDM24G[14]; // OFDM 2.4G channel 1~14 ++ u8 TxPowerLevelOFDM5G[14]; // OFDM 5G ++ u8 TxPowerLevelOFDM24G_A[14]; // RF-A, OFDM 2.4G channel 1~14 ++ u8 TxPowerLevelOFDM24G_C[14]; // RF-C, OFDM 2.4G channel 1~14 ++ u8 LegacyHTTxPowerDiff; // Legacy to HT rate power diff ++ u8 TxPowerDiff; ++ char RF_C_TxPwDiff; // Antenna gain offset, rf-c to rf-a ++ u8 AntennaTxPwDiff[3]; // Antenna gain offset, index 0 for B, 1 for C, and 2 for D ++ u8 CrystalCap; // CrystalCap. ++ u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 ++ //05/27/2008 cck power enlarge ++ u8 CckPwEnl; ++ u16 TSSI_13dBm; ++ u32 Pwr_Track; ++ u8 CCKPresentAttentuation_20Mdefault; ++ u8 CCKPresentAttentuation_40Mdefault; ++ char CCKPresentAttentuation_difference; ++ char CCKPresentAttentuation; ++ // Use to calculate PWBD. ++ u8 bCckHighPower; ++ long undecorated_smoothed_pwdb; ++ long undecorated_smoothed_cck_adc_pwdb[4]; ++ //for set channel ++ u8 SwChnlInProgress; ++ u8 SwChnlStage; ++ u8 SwChnlStep; ++ u8 SetBWModeInProgress; ++ HT_CHANNEL_WIDTH CurrentChannelBW; ++ ++ // 8190 40MHz mode ++ // ++ u8 nCur40MhzPrimeSC; // Control channel sub-carrier ++ // Joseph test for shorten RF configuration time. ++ // We save RF reg0 in this variable to reduce RF reading. ++ // ++ u32 RfReg0Value[4]; ++ u8 NumTotalRFPath; ++ bool brfpath_rxenable[4]; ++//+by amy 080507 ++ struct timer_list watch_dog_timer; ++ ++//+by amy 080515 for dynamic mechenism ++ //Add by amy Tx Power Control for Near/Far Range 2008/05/15 ++ bool bdynamic_txpower; //bDynamicTxPower ++ bool bDynamicTxHighPower; // Tx high power state ++ bool bDynamicTxLowPower; // Tx low power state ++ bool bLastDTPFlag_High; ++ bool bLastDTPFlag_Low; ++ ++ bool bstore_last_dtpflag; ++ bool bstart_txctrl_bydtp; //Define to discriminate on High power State or on sitesuvey to change Tx gain index ++ //Add by amy for Rate Adaptive ++ rate_adaptive rate_adaptive; ++ //Add by amy for TX power tracking ++ //2008/05/15 Mars OPEN/CLOSE TX POWER TRACKING ++ txbbgain_struct txbbgain_table[TxBBGainTableLength]; ++ u8 txpower_count;//For 6 sec do tracking again ++ bool btxpower_trackingInit; ++ u8 OFDM_index; ++ u8 CCK_index; ++ u8 Record_CCK_20Mindex; ++ u8 Record_CCK_40Mindex; ++ //2007/09/10 Mars Add CCK TX Power Tracking ++ ccktxbbgain_struct cck_txbbgain_table[CCKTxBBGainTableLength]; ++ ccktxbbgain_struct cck_txbbgain_ch14_table[CCKTxBBGainTableLength]; ++ u8 rfa_txpowertrackingindex; ++ u8 rfa_txpowertrackingindex_real; ++ u8 rfa_txpowertracking_default; ++ u8 rfc_txpowertrackingindex; ++ u8 rfc_txpowertrackingindex_real; ++ u8 rfc_txpowertracking_default; ++ bool btxpower_tracking; ++ bool bcck_in_ch14; ++ ++ //For Backup Initial Gain ++ init_gain initgain_backup; ++ u8 DefaultInitialGain[4]; ++ // For EDCA Turbo mode, Added by amy 080515. ++ bool bis_any_nonbepkts; ++ bool bcurrent_turbo_EDCA; ++ ++ bool bis_cur_rdlstate; ++ struct timer_list fsync_timer; ++ bool bfsync_processing; // 500ms Fsync timer is active or not ++ u32 rate_record; ++ u32 rateCountDiffRecord; ++ u32 ContiuneDiffCount; ++ bool bswitch_fsync; ++ ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ //Added by amy 080516 for RX related ++ u16 nrxAMPDU_size; ++ u8 nrxAMPDU_aggr_num; ++ ++ /*Last RxDesc TSF value*/ ++ u32 last_rxdesc_tsf_high; ++ u32 last_rxdesc_tsf_low; ++ ++ //by amy for gpio ++ bool bHwRadioOff; ++ //by amy for ps ++ bool RFChangeInProgress; // RF Chnage in progress, by Bruce, 2007-10-30 ++ bool SetRFPowerStateInProgress; ++ RT_OP_MODE OpMode; ++ //by amy for reset_count ++ u32 reset_count; ++ bool bpbc_pressed; ++ //by amy for debug ++ u32 txpower_checkcnt; ++ u32 txpower_tracking_callback_cnt; ++ u8 thermal_read_val[40]; ++ u8 thermal_readback_index; ++ u32 ccktxpower_adjustcnt_not_ch14; ++ u32 ccktxpower_adjustcnt_ch14; ++ u8 tx_fwinfo_force_subcarriermode; ++ u8 tx_fwinfo_force_subcarrierval; ++ ++ //by amy for silent reset ++ RESET_TYPE ResetProgress; ++ bool bForcedSilentReset; ++ bool bDisableNormalResetCheck; ++ u16 TxCounter; ++ u16 RxCounter; ++ int IrpPendingCount; ++ bool bResetInProgress; ++ bool force_reset; ++ u8 InitialGainOperateType; ++ ++ //define work item by amy 080526 ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct delayed_work update_beacon_wq; ++ struct delayed_work watch_dog_wq; ++ struct delayed_work txpower_tracking_wq; ++ struct delayed_work rfpath_check_wq; ++ struct delayed_work gpio_change_rf_wq; ++ struct delayed_work initialgain_operate_wq; ++#else ++ struct work_struct update_beacon_wq; ++ struct work_struct watch_dog_wq; ++ struct work_struct txpower_tracking_wq; ++ struct work_struct rfpath_check_wq; ++ struct work_struct gpio_change_rf_wq; ++ struct work_struct initialgain_operate_wq; ++#endif ++ struct workqueue_struct *priv_wq; ++#else ++ struct tq_struct update_beacon_wq; ++ /* used for periodly scan */ ++ struct tq_struct txpower_tracking_wq; ++ struct tq_struct rfpath_check_wq; ++ struct tq_struct watch_dog_wq; ++ struct tq_struct gpio_change_rf_wq; ++ struct tq_struct initialgain_operate_wq; ++#endif ++}r8192_priv; ++ ++// for rtl8187 ++// now mirging to rtl8187B ++/* ++typedef enum{ ++ LOW_PRIORITY = 0x02, ++ NORM_PRIORITY ++ } priority_t; ++*/ ++//for rtl8187B ++#if 0 ++typedef enum{ ++ BULK_PRIORITY = 0x01, ++ //RSVD0, ++ //RSVD1, ++ LOW_PRIORITY, ++ NORM_PRIORITY, ++ VO_PRIORITY, ++ VI_PRIORITY, //0x05 ++ BE_PRIORITY, ++ BK_PRIORITY, ++ CMD_PRIORITY,//0x8 ++ RSVD3, ++ BEACON_PRIORITY, //0x0A ++ HIGH_PRIORITY, ++ MANAGE_PRIORITY, ++ RSVD4, ++ RSVD5, ++ UART_PRIORITY //0x0F ++} priority_t; ++#endif ++typedef enum{ ++ NIC_8192E = 1, ++ } nic_t; ++ ++ ++#if 0 //defined in Qos.h ++//typedef u32 AC_CODING; ++#define AC0_BE 0 // ACI: 0x00 // Best Effort ++#define AC1_BK 1 // ACI: 0x01 // Background ++#define AC2_VI 2 // ACI: 0x10 // Video ++#define AC3_VO 3 // ACI: 0x11 // Voice ++#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. ++ ++// ++// ECWmin/ECWmax field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. ++// ++typedef union _ECW{ ++ u8 charData; ++ struct ++ { ++ u8 ECWmin:4; ++ u8 ECWmax:4; ++ }f; // Field ++}ECW, *PECW; ++ ++// ++// ACI/AIFSN Field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _ACI_AIFSN{ ++ u8 charData; ++ ++ struct ++ { ++ u8 AIFSN:4; ++ u8 ACM:1; ++ u8 ACI:2; ++ u8 Reserved:1; ++ }f; // Field ++}ACI_AIFSN, *PACI_AIFSN; ++ ++// ++// AC Parameters Record Format. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _AC_PARAM{ ++ u32 longData; ++ u8 charData[4]; ++ ++ struct ++ { ++ ACI_AIFSN AciAifsn; ++ ECW Ecw; ++ u16 TXOPLimit; ++ }f; // Field ++}AC_PARAM, *PAC_PARAM; ++ ++#endif ++bool init_firmware(struct net_device *dev); ++void rtl819xE_tx_cmd(struct net_device *dev, struct sk_buff *skb); ++short rtl8192_tx(struct net_device *dev, struct sk_buff* skb); ++u32 read_cam(struct net_device *dev, u8 addr); ++void write_cam(struct net_device *dev, u8 addr, u32 data); ++u8 read_nic_byte(struct net_device *dev, int x); ++u8 read_nic_byte_E(struct net_device *dev, int x); ++u32 read_nic_dword(struct net_device *dev, int x); ++u16 read_nic_word(struct net_device *dev, int x) ; ++void write_nic_byte(struct net_device *dev, int x,u8 y); ++void write_nic_byte_E(struct net_device *dev, int x,u8 y); ++void write_nic_word(struct net_device *dev, int x,u16 y); ++void write_nic_dword(struct net_device *dev, int x,u32 y); ++void force_pci_posting(struct net_device *dev); ++ ++void rtl8192_rtx_disable(struct net_device *); ++void rtl8192_rx_enable(struct net_device *); ++void rtl8192_tx_enable(struct net_device *); ++ ++void rtl8192_disassociate(struct net_device *dev); ++//void fix_rx_fifo(struct net_device *dev); ++void rtl8185_set_rf_pins_enable(struct net_device *dev,u32 a); ++ ++void rtl8192_set_anaparam(struct net_device *dev,u32 a); ++void rtl8185_set_anaparam2(struct net_device *dev,u32 a); ++void rtl8192_update_msr(struct net_device *dev); ++int rtl8192_down(struct net_device *dev); ++int rtl8192_up(struct net_device *dev); ++void rtl8192_commit(struct net_device *dev); ++void rtl8192_set_chan(struct net_device *dev,short ch); ++void write_phy(struct net_device *dev, u8 adr, u8 data); ++void write_phy_cck(struct net_device *dev, u8 adr, u32 data); ++void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data); ++void rtl8185_tx_antenna(struct net_device *dev, u8 ant); ++void rtl8187_set_rxconf(struct net_device *dev); ++//short check_nic_enough_desc(struct net_device *dev, priority_t priority); ++void rtl8192_start_beacon(struct net_device *dev); ++void CamResetAllEntry(struct net_device* dev); ++void EnableHWSecurityConfig8192(struct net_device *dev); ++void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, u8 *MacAddr, u8 DefaultKey, u32 *KeyContent ); ++void CamPrintDbgReg(struct net_device* dev); ++extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14); ++extern void firmware_init_param(struct net_device *dev); ++extern RT_STATUS cmpk_message_handle_tx(struct net_device *dev, u8* codevirtualaddress, u32 packettype, u32 buffer_len); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8192_hw_wakeup_wq (struct work_struct *work); ++#else ++void rtl8192_hw_wakeup_wq(struct net_device *dev); ++#endif ++ ++short rtl8192_is_tx_queue_empty(struct net_device *dev); ++#ifdef ENABLE_IPS ++void IPSEnter(struct net_device *dev); ++void IPSLeave(struct net_device *dev); ++#endif ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E_core.c +@@ -0,0 +1,6928 @@ ++/****************************************************************************** ++ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. ++ * Linux device driver for RTL8190P / RTL8192E ++ * ++ * Based on the r8180 driver, which is: ++ * Copyright 2004-2005 Andrea Merello , et al. ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * Jerry chuang ++ */ ++ ++ ++#undef LOOP_TEST ++#undef RX_DONT_PASS_UL ++#undef DEBUG_EPROM ++#undef DEBUG_RX_VERBOSE ++#undef DUMMY_RX ++#undef DEBUG_ZERO_RX ++#undef DEBUG_RX_SKB ++#undef DEBUG_TX_FRAG ++#undef DEBUG_RX_FRAG ++#undef DEBUG_TX_FILLDESC ++#undef DEBUG_TX ++#undef DEBUG_IRQ ++#undef DEBUG_RX ++#undef DEBUG_RXALLOC ++#undef DEBUG_REGISTERS ++#undef DEBUG_RING ++#undef DEBUG_IRQ_TASKLET ++#undef DEBUG_TX_ALLOC ++#undef DEBUG_TX_DESC ++ ++//#define CONFIG_RTL8192_IO_MAP ++#include ++#include "r8192E_hw.h" ++#include "r8192E.h" ++#include "r8190_rtl8256.h" /* RTL8225 Radio frontend */ ++#include "r8180_93cx6.h" /* Card EEPROM */ ++#include "r8192E_wx.h" ++#include "r819xE_phy.h" //added by WB 4.30.2008 ++#include "r819xE_phyreg.h" ++#include "r819xE_cmdpkt.h" ++#include "r8192E_dm.h" ++//#include "r8192xU_phyreg.h" ++//#include ++// FIXME: check if 2.6.7 is ok ++ ++#ifdef CONFIG_PM_RTL ++#include "r8192_pm.h" ++#endif ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++//set here to open your trace code. //WB ++u32 rt_global_debug_component = \ ++ // COMP_INIT | ++ // COMP_EPROM | ++ // COMP_PHY | ++ // COMP_RF | ++ COMP_FIRMWARE | ++ // COMP_TRACE | ++ // COMP_DOWN | ++ // COMP_SWBW | ++ // COMP_SEC | ++// COMP_QOS | ++// COMP_RATE | ++ // COMP_RECV | ++ // COMP_SEND | ++ // COMP_POWER | ++ // COMP_EVENTS | ++ // COMP_RESET | ++ // COMP_CMDPKT | ++ // COMP_POWER_TRACKING | ++ // COMP_INTR | ++ COMP_ERR ; //always open err flags on ++#ifndef PCI_DEVICE ++#define PCI_DEVICE(vend,dev)\ ++ .vendor=(vend),.device=(dev),\ ++ .subvendor=PCI_ANY_ID,.subdevice=PCI_ANY_ID ++#endif ++static struct pci_device_id rtl8192_pci_id_tbl[] __devinitdata = { ++#ifdef RTL8190P ++ /* Realtek */ ++ /* Dlink */ ++ { PCI_DEVICE(0x10ec, 0x8190) }, ++ /* Corega */ ++ { PCI_DEVICE(0x07aa, 0x0045) }, ++ { PCI_DEVICE(0x07aa, 0x0046) }, ++#else ++ /* Realtek */ ++ { PCI_DEVICE(0x10ec, 0x8192) }, ++ ++ /* Corega */ ++ { PCI_DEVICE(0x07aa, 0x0044) }, ++ { PCI_DEVICE(0x07aa, 0x0047) }, ++#endif ++ {} ++}; ++ ++static char* ifname = "wlan%d"; ++#if 0 ++static int hwseqnum = 0; ++static int hwwep = 0; ++#endif ++static int hwwep = 1; //default use hw. set 0 to use software security ++static int channels = 0x3fff; ++ ++MODULE_LICENSE("GPL"); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++MODULE_VERSION("V 1.1"); ++#endif ++MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl); ++//MODULE_AUTHOR("Andrea Merello "); ++MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards"); ++ ++#if 0 ++MODULE_PARM(ifname,"s"); ++MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); ++ ++MODULE_PARM(hwseqnum,"i"); ++MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); ++ ++MODULE_PARM(hwwep,"i"); ++MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); ++ ++MODULE_PARM(channels,"i"); ++MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) ++module_param(ifname, charp, S_IRUGO|S_IWUSR ); ++//module_param(hwseqnum,int, S_IRUGO|S_IWUSR); ++module_param(hwwep,int, S_IRUGO|S_IWUSR); ++module_param(channels,int, S_IRUGO|S_IWUSR); ++#else ++MODULE_PARM(ifname, "s"); ++//MODULE_PARM(hwseqnum,"i"); ++MODULE_PARM(hwwep,"i"); ++MODULE_PARM(channels,"i"); ++#endif ++ ++MODULE_PARM_DESC(ifname," Net interface name, wlan%d=default"); ++//MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); ++MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); ++MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); ++ ++static int __devinit rtl8192_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id); ++static void __devexit rtl8192_pci_disconnect(struct pci_dev *pdev); ++ ++static struct pci_driver rtl8192_pci_driver = { ++ .name = RTL819xE_MODULE_NAME, /* Driver name */ ++ .id_table = rtl8192_pci_id_tbl, /* PCI_ID table */ ++ .probe = rtl8192_pci_probe, /* probe fn */ ++ .remove = __devexit_p(rtl8192_pci_disconnect), /* remove fn */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) ++#ifdef CONFIG_PM_RTL ++ .suspend = rtl8192E_suspend, /* PM suspend fn */ ++ .resume = rtl8192E_resume, /* PM resume fn */ ++#else ++ .suspend = NULL, /* PM suspend fn */ ++ .resume = NULL, /* PM resume fn */ ++#endif ++#endif ++}; ++ ++#ifdef ENABLE_DOT11D ++ ++typedef struct _CHANNEL_LIST ++{ ++ u8 Channel[32]; ++ u8 Len; ++}CHANNEL_LIST, *PCHANNEL_LIST; ++ ++static CHANNEL_LIST ChannelPlan[] = { ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64,149,153,157,161,165},24}, //FCC ++ {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, //Spain. Change to ETSI. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, //France. Change to ETSI. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22}, //MKK //MKK ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22},//MKK1 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13}, //Israel. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64},22}, // For 11a , TELEC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,40,44,48,52,56,60,64}, 22}, //MIC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14} //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 ++}; ++ ++static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv) ++{ ++ int i, max_chan=-1, min_chan=-1; ++ struct ieee80211_device* ieee = priv->ieee80211; ++ switch (channel_plan) ++ { ++ case COUNTRY_CODE_FCC: ++ case COUNTRY_CODE_IC: ++ case COUNTRY_CODE_ETSI: ++ case COUNTRY_CODE_SPAIN: ++ case COUNTRY_CODE_FRANCE: ++ case COUNTRY_CODE_MKK: ++ case COUNTRY_CODE_MKK1: ++ case COUNTRY_CODE_ISRAEL: ++ case COUNTRY_CODE_TELEC: ++ case COUNTRY_CODE_MIC: ++ { ++ Dot11d_Init(ieee); ++ ieee->bGlobalDomain = false; ++ //acturally 8225 & 8256 rf chip only support B,G,24N mode ++ if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256)) ++ { ++ min_chan = 1; ++ max_chan = 14; ++ } ++ else ++ { ++ RT_TRACE(COMP_ERR, "unknown rf chip, can't set channel map in function:%s()\n", __FUNCTION__); ++ } ++ if (ChannelPlan[channel_plan].Len != 0){ ++ // Clear old channel map ++ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); ++ // Set new channel map ++ for (i=0;i max_chan) ++ break; ++ GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1; ++ } ++ } ++ break; ++ } ++ case COUNTRY_CODE_GLOBAL_DOMAIN: ++ { ++ GET_DOT11D_INFO(ieee)->bEnabled = 0; //this flag enabled to follow 11d country IE setting, otherwise, it shall follow global domain setting ++ Dot11d_Reset(ieee); ++ ieee->bGlobalDomain = true; ++ break; ++ } ++ default: ++ break; ++ } ++} ++#endif ++ ++ ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++/* 2007/07/25 MH Defien temp tx fw info. */ ++static TX_FWINFO_T Tmp_TxFwInfo; ++ ++ ++#define rx_hal_is_cck_rate(_pdrvinfo)\ ++ (_pdrvinfo->RxRate == DESC90_RATE1M ||\ ++ _pdrvinfo->RxRate == DESC90_RATE2M ||\ ++ _pdrvinfo->RxRate == DESC90_RATE5_5M ||\ ++ _pdrvinfo->RxRate == DESC90_RATE11M) &&\ ++ !_pdrvinfo->RxHT\ ++ ++ ++void CamResetAllEntry(struct net_device *dev) ++{ ++ //u8 ucIndex; ++ u32 ulcommand = 0; ++ ++#if 1 ++ ulcommand |= BIT31|BIT30; ++ write_nic_dword(dev, RWCAM, ulcommand); ++#else ++ for(ucIndex=0;ucIndexbase_addr +x); ++} ++ ++u32 read_nic_dword(struct net_device *dev, int x) ++{ ++ return inl(dev->base_addr +x); ++} ++ ++u16 read_nic_word(struct net_device *dev, int x) ++{ ++ return inw(dev->base_addr +x); ++} ++ ++void write_nic_byte(struct net_device *dev, int x,u8 y) ++{ ++ outb(y&0xff,dev->base_addr +x); ++} ++ ++void write_nic_word(struct net_device *dev, int x,u16 y) ++{ ++ outw(y,dev->base_addr +x); ++} ++ ++void write_nic_dword(struct net_device *dev, int x,u32 y) ++{ ++ outl(y,dev->base_addr +x); ++} ++ ++#else /* RTL_IO_MAP */ ++ ++u8 read_nic_byte(struct net_device *dev, int x) ++{ ++ return 0xff&readb((u8*)dev->mem_start +x); ++} ++ ++u32 read_nic_dword(struct net_device *dev, int x) ++{ ++ return readl((u8*)dev->mem_start +x); ++} ++ ++u16 read_nic_word(struct net_device *dev, int x) ++{ ++ return readw((u8*)dev->mem_start +x); ++} ++ ++void write_nic_byte(struct net_device *dev, int x,u8 y) ++{ ++ writeb(y,(u8*)dev->mem_start +x); ++ udelay(20); ++} ++ ++void write_nic_dword(struct net_device *dev, int x,u32 y) ++{ ++ writel(y,(u8*)dev->mem_start +x); ++ udelay(20); ++} ++ ++void write_nic_word(struct net_device *dev, int x,u16 y) ++{ ++ writew(y,(u8*)dev->mem_start +x); ++ udelay(20); ++} ++ ++#endif /* RTL_IO_MAP */ ++ ++ ++/////////////////////////////////////////////////////////// ++ ++//u8 read_phy_cck(struct net_device *dev, u8 adr); ++//u8 read_phy_ofdm(struct net_device *dev, u8 adr); ++/* this might still called in what was the PHY rtl8185/rtl8192 common code ++ * plans are to possibilty turn it again in one common code... ++ */ ++inline void force_pci_posting(struct net_device *dev) ++{ ++} ++ ++ ++//warning message WB ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++void rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs); ++#else ++irqreturn_t rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs); ++#endif ++#else ++irqreturn_t rtl8192_interrupt(int irq, void *netdev); ++#endif ++//static struct net_device_stats *rtl8192_stats(struct net_device *dev); ++void rtl8192_commit(struct net_device *dev); ++//void rtl8192_restart(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8192_restart(struct work_struct *work); ++//void rtl8192_rq_tx_ack(struct work_struct *work); ++#else ++ void rtl8192_restart(struct net_device *dev); ++// //void rtl8192_rq_tx_ack(struct net_device *dev); ++ #endif ++ ++void watch_dog_timer_callback(unsigned long data); ++#ifdef ENABLE_IPS ++void IPSEnter(struct net_device *dev); ++void IPSLeave(struct net_device *dev); ++void InactivePsWorkItemCallback(struct net_device *dev); ++#endif ++/**************************************************************************** ++ -----------------------------PROCFS STUFF------------------------- ++*****************************************************************************/ ++ ++static struct proc_dir_entry *rtl8192_proc = NULL; ++ ++ ++ ++static int proc_get_stats_ap(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ struct ieee80211_network *target; ++ ++ int len = 0; ++ ++ list_for_each_entry(target, &ieee->network_list, list) { ++ ++ len += snprintf(page + len, count - len, ++ "%s ", target->ssid); ++ ++ if(target->wpa_ie_len>0 || target->rsn_ie_len>0){ ++ len += snprintf(page + len, count - len, ++ "WPA\n"); ++ } ++ else{ ++ len += snprintf(page + len, count - len, ++ "non_WPA\n"); ++ } ++ ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++static int proc_get_registers(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ int i,n; ++ ++ int max=0xff; ++ ++ /* This dump the current register page */ ++ len += snprintf(page + len, count - len, ++ "\n####################page 0##################\n "); ++ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++ len += snprintf(page + len, count - len, ++ "\n####################page 1##################\n "); ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,0x100|n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ ++ len += snprintf(page + len, count - len, ++ "\n####################page 3##################\n "); ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,0x300|n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++ ++#if 0 ++static int proc_get_cck_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ int i,n; ++ ++ int max = 0x5F; ++ ++ /* This dump the current register page */ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_phy_cck(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++ ++ ++ *eof = 1; ++ return len; ++} ++ ++#endif ++ ++#if 0 ++static int proc_get_ofdm_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ ++ struct net_device *dev = data; ++// struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ int i,n; ++ ++ //int max=0xff; ++ int max = 0x40; ++ ++ /* This dump the current register page */ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_phy_ofdm(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++ ++ ++ ++ *eof = 1; ++ return len; ++} ++ ++#endif ++ ++#if 0 ++static int proc_get_stats_hw(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "NIC int: %lu\n" ++ "Total int: %lu\n", ++ priv->stats.ints, ++ priv->stats.shints); ++ ++ *eof = 1; ++ return len; ++} ++#endif ++ ++static int proc_get_stats_tx(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "TX VI priority ok int: %lu\n" ++// "TX VI priority error int: %lu\n" ++ "TX VO priority ok int: %lu\n" ++// "TX VO priority error int: %lu\n" ++ "TX BE priority ok int: %lu\n" ++// "TX BE priority error int: %lu\n" ++ "TX BK priority ok int: %lu\n" ++// "TX BK priority error int: %lu\n" ++ "TX MANAGE priority ok int: %lu\n" ++// "TX MANAGE priority error int: %lu\n" ++ "TX BEACON priority ok int: %lu\n" ++ "TX BEACON priority error int: %lu\n" ++ "TX CMDPKT priority ok int: %lu\n" ++// "TX high priority ok int: %lu\n" ++// "TX high priority failed error int: %lu\n" ++// "TX queue resume: %lu\n" ++ "TX queue stopped?: %d\n" ++ "TX fifo overflow: %lu\n" ++// "TX beacon: %lu\n" ++// "TX VI queue: %d\n" ++// "TX VO queue: %d\n" ++// "TX BE queue: %d\n" ++// "TX BK queue: %d\n" ++// "TX HW queue: %d\n" ++// "TX VI dropped: %lu\n" ++// "TX VO dropped: %lu\n" ++// "TX BE dropped: %lu\n" ++// "TX BK dropped: %lu\n" ++ "TX total data packets %lu\n" ++ "TX total data bytes :%lu\n", ++// "TX beacon aborted: %lu\n", ++ priv->stats.txviokint, ++// priv->stats.txvierr, ++ priv->stats.txvookint, ++// priv->stats.txvoerr, ++ priv->stats.txbeokint, ++// priv->stats.txbeerr, ++ priv->stats.txbkokint, ++// priv->stats.txbkerr, ++ priv->stats.txmanageokint, ++// priv->stats.txmanageerr, ++ priv->stats.txbeaconokint, ++ priv->stats.txbeaconerr, ++ priv->stats.txcmdpktokint, ++// priv->stats.txhpokint, ++// priv->stats.txhperr, ++// priv->stats.txresumed, ++ netif_queue_stopped(dev), ++ priv->stats.txoverflow, ++// priv->stats.txbeacon, ++// atomic_read(&(priv->tx_pending[VI_QUEUE])), ++// atomic_read(&(priv->tx_pending[VO_QUEUE])), ++// atomic_read(&(priv->tx_pending[BE_QUEUE])), ++// atomic_read(&(priv->tx_pending[BK_QUEUE])), ++// read_nic_byte(dev, TXFIFOCOUNT), ++// priv->stats.txvidrop, ++// priv->stats.txvodrop, ++ priv->ieee80211->stats.tx_packets, ++ priv->ieee80211->stats.tx_bytes ++ ++ ++// priv->stats.txbedrop, ++// priv->stats.txbkdrop ++ // priv->stats.txdatapkt ++// priv->stats.txbeaconerr ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++ ++static int proc_get_stats_rx(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "RX packets: %lu\n" ++ "RX desc err: %lu\n" ++ "RX rx overflow error: %lu\n" ++ "RX invalid urb error: %lu\n", ++ priv->stats.rxint, ++ priv->stats.rxrdu, ++ priv->stats.rxoverflow, ++ priv->stats.rxurberr); ++ ++ *eof = 1; ++ return len; ++} ++ ++static void rtl8192_proc_module_init(void) ++{ ++ RT_TRACE(COMP_INIT, "Initializing proc filesystem"); ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ rtl8192_proc=create_proc_entry(RTL819xE_MODULE_NAME, S_IFDIR, proc_net); ++#else ++ rtl8192_proc=create_proc_entry(RTL819xE_MODULE_NAME, S_IFDIR, init_net.proc_net); ++#endif ++} ++ ++ ++static void rtl8192_proc_module_remove(void) ++{ ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ remove_proc_entry(RTL819xE_MODULE_NAME, proc_net); ++#else ++ remove_proc_entry(RTL819xE_MODULE_NAME, init_net.proc_net); ++#endif ++} ++ ++ ++static void rtl8192_proc_remove_one(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ printk("dev name=======> %s\n",dev->name); ++ ++ if (priv->dir_dev) { ++ // remove_proc_entry("stats-hw", priv->dir_dev); ++ remove_proc_entry("stats-tx", priv->dir_dev); ++ remove_proc_entry("stats-rx", priv->dir_dev); ++ // remove_proc_entry("stats-ieee", priv->dir_dev); ++ remove_proc_entry("stats-ap", priv->dir_dev); ++ remove_proc_entry("registers", priv->dir_dev); ++ // remove_proc_entry("cck-registers",priv->dir_dev); ++ // remove_proc_entry("ofdm-registers",priv->dir_dev); ++ //remove_proc_entry(dev->name, rtl8192_proc); ++ remove_proc_entry("wlan0", rtl8192_proc); ++ priv->dir_dev = NULL; ++ } ++} ++ ++ ++static void rtl8192_proc_init_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *e; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ priv->dir_dev = create_proc_entry(dev->name, ++ S_IFDIR | S_IRUGO | S_IXUGO, ++ rtl8192_proc); ++ if (!priv->dir_dev) { ++ RT_TRACE(COMP_ERR, "Unable to initialize /proc/net/rtl8192/%s\n", ++ dev->name); ++ return; ++ } ++ #if 0 ++ e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_hw, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8192/%s/stats-hw\n", ++ dev->name); ++ } ++ #endif ++ e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_rx, dev); ++ ++ if (!e) { ++ RT_TRACE(COMP_ERR,"Unable to initialize " ++ "/proc/net/rtl8192/%s/stats-rx\n", ++ dev->name); ++ } ++ ++ ++ e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_tx, dev); ++ ++ if (!e) { ++ RT_TRACE(COMP_ERR, "Unable to initialize " ++ "/proc/net/rtl8192/%s/stats-tx\n", ++ dev->name); ++ } ++ #if 0 ++ e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_ieee, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8192/%s/stats-ieee\n", ++ dev->name); ++ } ++ ++ #endif ++ ++ e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_ap, dev); ++ ++ if (!e) { ++ RT_TRACE(COMP_ERR, "Unable to initialize " ++ "/proc/net/rtl8192/%s/stats-ap\n", ++ dev->name); ++ } ++ ++ e = create_proc_read_entry("registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_registers, dev); ++ if (!e) { ++ RT_TRACE(COMP_ERR, "Unable to initialize " ++ "/proc/net/rtl8192/%s/registers\n", ++ dev->name); ++ } ++#if 0 ++ e = create_proc_read_entry("cck-registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_cck_reg, dev); ++ if (!e) { ++ RT_TRACE(COMP_ERR, "Unable to initialize " ++ "/proc/net/rtl8192/%s/cck-registers\n", ++ dev->name); ++ } ++ ++ e = create_proc_read_entry("ofdm-registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_ofdm_reg, dev); ++ if (!e) { ++ RT_TRACE(COMP_ERR, "Unable to initialize " ++ "/proc/net/rtl8192/%s/ofdm-registers\n", ++ dev->name); ++ } ++#endif ++} ++/**************************************************************************** ++ -----------------------------MISC STUFF------------------------- ++*****************************************************************************/ ++ ++short check_nic_enough_desc(struct net_device *dev, int prio) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; ++ ++ /* for now we reserve two free descriptor as a safety boundary ++ * between the tail and the head ++ */ ++ if (ring->entries - skb_queue_len(&ring->queue) >= 2) { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++static void tx_timeout(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //rtl8192_commit(dev); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ schedule_work(&priv->reset_wq); ++#else ++ schedule_task(&priv->reset_wq); ++#endif ++ printk("TXTIMEOUT"); ++} ++ ++ ++/**************************************************************************** ++ ------------------------------HW STUFF--------------------------- ++*****************************************************************************/ ++ ++ ++static void rtl8192_irq_enable(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ priv->irq_enabled = 1; ++ write_nic_dword(dev,INTA_MASK, priv->irq_mask); ++} ++ ++ ++static void rtl8192_irq_disable(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ write_nic_dword(dev,INTA_MASK,0); ++ force_pci_posting(dev); ++ priv->irq_enabled = 0; ++} ++ ++ ++static void rtl8192_set_mode(struct net_device *dev,int mode) ++{ ++ u8 ecmd; ++ ecmd=read_nic_byte(dev, EPROM_CMD); ++ ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK; ++ ecmd=ecmd | (mode<ieee80211->state == IEEE80211_LINKED){ ++ ++ if (priv->ieee80211->iw_mode == IW_MODE_INFRA) ++ msr |= (MSR_LINK_MANAGED<ieee80211->iw_mode == IW_MODE_ADHOC) ++ msr |= (MSR_LINK_ADHOC<ieee80211->iw_mode == IW_MODE_MASTER) ++ msr |= (MSR_LINK_MASTER<%s()====ch:%d\n", __FUNCTION__, ch); ++ priv->chan=ch; ++#if 0 ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC || ++ priv->ieee80211->iw_mode == IW_MODE_MASTER){ ++ ++ priv->ieee80211->link_state = WLAN_LINK_ASSOCIATED; ++ priv->ieee80211->master_chan = ch; ++ rtl8192_update_beacon_ch(dev); ++ } ++#endif ++ ++ /* this hack should avoid frame TX during channel setting*/ ++ ++ ++ // tx = read_nic_dword(dev,TX_CONF); ++ // tx &= ~TX_LOOPBACK_MASK; ++ ++#ifndef LOOP_TEST ++ //TODO ++ // write_nic_dword(dev,TX_CONF, tx |( TX_LOOPBACK_MAC<rf_set_chan) ++ priv->rf_set_chan(dev,priv->chan); ++ // mdelay(10); ++ // write_nic_dword(dev,TX_CONF,tx | (TX_LOOPBACK_NONE<rx_ring_dma); ++} ++ ++/* the TX_DESC_BASE setting is according to the following queue index ++ * BK_QUEUE ===> 0 ++ * BE_QUEUE ===> 1 ++ * VI_QUEUE ===> 2 ++ * VO_QUEUE ===> 3 ++ * HCCA_QUEUE ===> 4 ++ * TXCMD_QUEUE ===> 5 ++ * MGNT_QUEUE ===> 6 ++ * HIGH_QUEUE ===> 7 ++ * BEACON_QUEUE ===> 8 ++ * */ ++static u32 TX_DESC_BASE[] = {BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA}; ++void rtl8192_tx_enable(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ u32 i; ++ for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) ++ write_nic_dword(dev, TX_DESC_BASE[i], priv->tx_ring[i].dma); ++ ++ ieee80211_reset_queue(priv->ieee80211); ++} ++ ++#if 0 ++void rtl8192_beacon_tx_enable(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ u32 reg; ++ ++ reg = read_nic_dword(priv->ieee80211->dev,INTA_MASK); ++ ++ /* enable Beacon realted interrupt signal */ ++ reg |= (IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); ++ write_nic_byte(dev,reg); ++} ++#endif ++ ++static void rtl8192_free_rx_ring(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int i; ++ ++ for (i = 0; i < priv->rxringcount; i++) { ++ struct sk_buff *skb = priv->rx_buf[i]; ++ if (!skb) ++ continue; ++ ++ pci_unmap_single(priv->pdev, ++ *((dma_addr_t *)skb->cb), ++ priv->rxbuffersize, PCI_DMA_FROMDEVICE); ++ kfree_skb(skb); ++ } ++ ++ pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * priv->rxringcount, ++ priv->rx_ring, priv->rx_ring_dma); ++ priv->rx_ring = NULL; ++} ++ ++static void rtl8192_free_tx_ring(struct net_device *dev, unsigned int prio) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; ++ ++ while (skb_queue_len(&ring->queue)) { ++ tx_desc_819x_pci *entry = &ring->desc[ring->idx]; ++ struct sk_buff *skb = __skb_dequeue(&ring->queue); ++ ++ pci_unmap_single(priv->pdev, le32_to_cpu(entry->TxBuffAddr), ++ skb->len, PCI_DMA_TODEVICE); ++ kfree_skb(skb); ++ ring->idx = (ring->idx + 1) % ring->entries; ++ } ++ ++ pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, ++ ring->desc, ring->dma); ++ ring->desc = NULL; ++} ++ ++ ++static void rtl8192_beacon_disable(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ u32 reg; ++ ++ reg = read_nic_dword(priv->ieee80211->dev,INTA_MASK); ++ ++ /* disable Beacon realted interrupt signal */ ++ reg &= ~(IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); ++ write_nic_dword(priv->ieee80211->dev, INTA_MASK, reg); ++} ++ ++void rtl8192_rtx_disable(struct net_device *dev) ++{ ++ u8 cmd; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int i; ++ ++ cmd=read_nic_byte(dev,CMDR); ++// if(!priv->ieee80211->bSupportRemoteWakeUp) { ++ write_nic_byte(dev, CMDR, cmd &~ \ ++ (CR_TE|CR_RE)); ++// } ++ force_pci_posting(dev); ++ mdelay(30); ++ ++ for(i = 0; i < MAX_QUEUE_SIZE; i++) { ++ skb_queue_purge(&priv->ieee80211->skb_waitQ [i]); ++ } ++ for(i = 0; i < MAX_QUEUE_SIZE; i++) { ++ skb_queue_purge(&priv->ieee80211->skb_aggQ [i]); ++ } ++ ++ ++ skb_queue_purge(&priv->skb_queue); ++ return; ++} ++ ++static void rtl8192_reset(struct net_device *dev) ++{ ++ rtl8192_irq_disable(dev); ++ printk("This is RTL819xP Reset procedure\n"); ++} ++ ++static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540}; ++inline u16 rtl8192_rate2rate(short rate) ++{ ++ if (rate >11) return 0; ++ return rtl_rate[rate]; ++} ++ ++ ++ ++#if 0 ++void rtl8192_tx_queues_stop(struct net_device *dev) ++{ ++ //struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ u8 dma_poll_mask = (1<dma_poll_mask |= (1<dma_poll_mask); ++ rtl8192_set_mode(dev,EPROM_CMD_NORMAL); ++ #endif ++} ++ ++ ++static void rtl8192_data_hard_resume(struct net_device *dev) ++{ ++ // FIXME !! ++ #if 0 ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ priv->dma_poll_mask &= ~(1<dma_poll_mask); ++ rtl8192_set_mode(dev,EPROM_CMD_NORMAL); ++ #endif ++} ++ ++/* this function TX data frames when the ieee80211 stack requires this. ++ * It checks also if we need to stop the ieee tx queue, eventually do it ++ */ ++static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ int ret; ++ //unsigned long flags; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ u8 queue_index = tcb_desc->queue_index; ++ /* shall not be referred by command packet */ ++ assert(queue_index != TXCMD_QUEUE); ++ ++ //spin_lock_irqsave(&priv->tx_lock,flags); ++ ++ memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); ++#if 0 ++ tcb_desc->RATRIndex = 7; ++ tcb_desc->bTxDisableRateFallBack = 1; ++ tcb_desc->bTxUseDriverAssingedRate = 1; ++ tcb_desc->bTxEnableFwCalcDur = 1; ++#endif ++ skb_push(skb, priv->ieee80211->tx_headroom); ++ ret = rtl8192_tx(dev, skb); ++ if(ret != 0) { ++ kfree_skb(skb); ++ }; ++ ++// ++ if(queue_index!=MGNT_QUEUE) { ++ priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom); ++ priv->ieee80211->stats.tx_packets++; ++ } ++ ++ //spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++// return ret; ++ return; ++} ++ ++/* This is a rough attempt to TX a frame ++ * This is called by the ieee 80211 stack to TX management frames. ++ * If the ring is full packet are dropped (for data frame the queue ++ * is stopped before this can happen). ++ */ ++static int rtl8192_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ ++ int ret; ++ //unsigned long flags; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ u8 queue_index = tcb_desc->queue_index; ++ ++ ++ //spin_lock_irqsave(&priv->tx_lock,flags); ++ ++ memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); ++ if(queue_index == TXCMD_QUEUE) { ++ // skb_push(skb, USB_HWDESC_HEADER_LEN); ++ rtl819xE_tx_cmd(dev, skb); ++ ret = 0; ++ //spin_unlock_irqrestore(&priv->tx_lock,flags); ++ return ret; ++ } else { ++ // RT_TRACE(COMP_SEND, "To send management packet\n"); ++ tcb_desc->RATRIndex = 7; ++ tcb_desc->bTxDisableRateFallBack = 1; ++ tcb_desc->bTxUseDriverAssingedRate = 1; ++ tcb_desc->bTxEnableFwCalcDur = 1; ++ skb_push(skb, priv->ieee80211->tx_headroom); ++ ret = rtl8192_tx(dev, skb); ++ if(ret != 0) { ++ kfree_skb(skb); ++ }; ++ } ++ ++// priv->ieee80211->stats.tx_bytes+=skb->len; ++// priv->ieee80211->stats.tx_packets++; ++ ++ //spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ return ret; ++ ++} ++ ++ ++void rtl8192_try_wake_queue(struct net_device *dev, int pri); ++ ++static void rtl8192_tx_isr(struct net_device *dev, int prio) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; ++ ++ while (skb_queue_len(&ring->queue)) { ++ tx_desc_819x_pci *entry = &ring->desc[ring->idx]; ++ struct sk_buff *skb; ++ ++ /* beacon packet will only use the first descriptor defautly, ++ * and the OWN may not be cleared by the hardware ++ * */ ++ if(prio != BEACON_QUEUE) { ++ if(entry->OWN) ++ return; ++ ring->idx = (ring->idx + 1) % ring->entries; ++ } ++ ++ skb = __skb_dequeue(&ring->queue); ++ pci_unmap_single(priv->pdev, le32_to_cpu(entry->TxBuffAddr), ++ skb->len, PCI_DMA_TODEVICE); ++ ++ kfree_skb(skb); ++ } ++ if (prio == MGNT_QUEUE){ ++ if (priv->ieee80211->ack_tx_to_ieee){ ++ if (rtl8192_is_tx_queue_empty(dev)){ ++ priv->ieee80211->ack_tx_to_ieee = 0; ++ ieee80211_ps_tx_ack(priv->ieee80211, 1); ++ } ++ } ++ } ++ ++ if(prio != BEACON_QUEUE) { ++ /* try to deal with the pending packets */ ++ tasklet_schedule(&priv->irq_tx_tasklet); ++ } ++ ++} ++ ++static void rtl8192_stop_beacon(struct net_device *dev) ++{ ++ //rtl8192_beacon_disable(dev); ++} ++ ++static void rtl8192_config_rate(struct net_device* dev, u16* rate_config) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_network *net; ++ u8 i=0, basic_rate = 0; ++ net = & priv->ieee80211->current_network; ++ ++ for (i=0; irates_len; i++) ++ { ++ basic_rate = net->rates[i]&0x7f; ++ switch(basic_rate) ++ { ++ case MGN_1M: *rate_config |= RRSR_1M; break; ++ case MGN_2M: *rate_config |= RRSR_2M; break; ++ case MGN_5_5M: *rate_config |= RRSR_5_5M; break; ++ case MGN_11M: *rate_config |= RRSR_11M; break; ++ case MGN_6M: *rate_config |= RRSR_6M; break; ++ case MGN_9M: *rate_config |= RRSR_9M; break; ++ case MGN_12M: *rate_config |= RRSR_12M; break; ++ case MGN_18M: *rate_config |= RRSR_18M; break; ++ case MGN_24M: *rate_config |= RRSR_24M; break; ++ case MGN_36M: *rate_config |= RRSR_36M; break; ++ case MGN_48M: *rate_config |= RRSR_48M; break; ++ case MGN_54M: *rate_config |= RRSR_54M; break; ++ } ++ } ++ for (i=0; irates_ex_len; i++) ++ { ++ basic_rate = net->rates_ex[i]&0x7f; ++ switch(basic_rate) ++ { ++ case MGN_1M: *rate_config |= RRSR_1M; break; ++ case MGN_2M: *rate_config |= RRSR_2M; break; ++ case MGN_5_5M: *rate_config |= RRSR_5_5M; break; ++ case MGN_11M: *rate_config |= RRSR_11M; break; ++ case MGN_6M: *rate_config |= RRSR_6M; break; ++ case MGN_9M: *rate_config |= RRSR_9M; break; ++ case MGN_12M: *rate_config |= RRSR_12M; break; ++ case MGN_18M: *rate_config |= RRSR_18M; break; ++ case MGN_24M: *rate_config |= RRSR_24M; break; ++ case MGN_36M: *rate_config |= RRSR_36M; break; ++ case MGN_48M: *rate_config |= RRSR_48M; break; ++ case MGN_54M: *rate_config |= RRSR_54M; break; ++ } ++ } ++} ++ ++ ++#define SHORT_SLOT_TIME 9 ++#define NON_SHORT_SLOT_TIME 20 ++ ++static void rtl8192_update_cap(struct net_device* dev, u16 cap) ++{ ++ u32 tmp = 0; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_network *net = &priv->ieee80211->current_network; ++ priv->short_preamble = cap & WLAN_CAPABILITY_SHORT_PREAMBLE; ++ tmp = priv->basic_rate; ++ if (priv->short_preamble) ++ tmp |= BRSR_AckShortPmb; ++ write_nic_dword(dev, RRSR, tmp); ++ ++ if (net->mode & (IEEE_G|IEEE_N_24G)) ++ { ++ u8 slot_time = 0; ++ if ((cap & WLAN_CAPABILITY_SHORT_SLOT)&&(!priv->ieee80211->pHTInfo->bCurrentRT2RTLongSlotTime)) ++ {//short slot time ++ slot_time = SHORT_SLOT_TIME; ++ } ++ else //long slot time ++ slot_time = NON_SHORT_SLOT_TIME; ++ priv->slot_time = slot_time; ++ write_nic_byte(dev, SLOT_TIME, slot_time); ++ } ++ ++} ++ ++static void rtl8192_net_update(struct net_device *dev) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_network *net; ++ u16 BcnTimeCfg = 0, BcnCW = 6, BcnIFS = 0xf; ++ u16 rate_config = 0; ++ net = &priv->ieee80211->current_network; ++ //update Basic rate: RR, BRSR ++ rtl8192_config_rate(dev, &rate_config); ++ // 2007.01.16, by Emily ++ // Select RRSR (in Legacy-OFDM and CCK) ++ // For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. ++ // We do not use other rates. ++ priv->basic_rate = rate_config &= 0x15f; ++ //BSSID ++ write_nic_dword(dev,BSSIDR,((u32*)net->bssid)[0]); ++ write_nic_word(dev,BSSIDR+4,((u16*)net->bssid)[2]); ++#if 0 ++ //MSR ++ rtl8192_update_msr(dev); ++#endif ++ ++ ++// rtl8192_update_cap(dev, net->capability); ++ if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ { ++ write_nic_word(dev, ATIMWND, 2); ++ write_nic_word(dev, BCN_DMATIME, 256); ++ write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); ++ // write_nic_word(dev, BcnIntTime, 100); ++ //BIT15 of BCN_DRV_EARLY_INT will indicate whether software beacon or hw beacon is applied. ++ write_nic_word(dev, BCN_DRV_EARLY_INT, 10); ++ write_nic_byte(dev, BCN_ERR_THRESH, 100); ++ ++ BcnTimeCfg |= (BcnCW<tx_ring[TXCMD_QUEUE]; ++ mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); ++ ++ spin_lock_irqsave(&priv->irq_th_lock,flags); ++ idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; ++ entry = &ring->desc[idx]; ++ ++ tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ memset(entry,0,12); ++ entry->LINIP = tcb_desc->bLastIniPkt; ++ entry->FirstSeg = 1;//first segment ++ entry->LastSeg = 1; //last segment ++ if(tcb_desc->bCmdOrInit == DESC_PACKET_TYPE_INIT) { ++ entry->CmdInit = DESC_PACKET_TYPE_INIT; ++ } else { ++ entry->CmdInit = DESC_PACKET_TYPE_NORMAL; ++ entry->Offset = sizeof(TX_FWINFO_8190PCI) + 8; ++ entry->PktSize = (u16)(tcb_desc->pkt_size + entry->Offset); ++ entry->QueueSelect = QSLT_CMD; ++ entry->TxFWInfoSize = 0x08; ++ entry->RATid = (u8)DESC_PACKET_TYPE_INIT; ++ } ++ entry->TxBufferSize = skb->len; ++ entry->TxBuffAddr = cpu_to_le32(mapping); ++ entry->OWN = 1; ++ ++#ifdef JOHN_DUMP_TXDESC ++ { int i; ++ tx_desc_819x_pci *entry1 = &ring->desc[0]; ++ unsigned int *ptr= (unsigned int *)entry1; ++ printk(":\n"); ++ for (i = 0; i < 8; i++) ++ printk("%8x ", ptr[i]); ++ printk("\n"); ++ } ++#endif ++ __skb_queue_tail(&ring->queue, skb); ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ ++ write_nic_byte(dev, TPPoll, TPPoll_CQ); ++ ++ return; ++} ++ ++/* ++ * Mapping Software/Hardware descriptor queue id to "Queue Select Field" ++ * in TxFwInfo data structure ++ * 2006.10.30 by Emily ++ * ++ * \param QUEUEID Software Queue ++*/ ++static u8 MapHwQueueToFirmwareQueue(u8 QueueID) ++{ ++ u8 QueueSelect = 0x0; //defualt set to ++ ++ switch(QueueID) { ++ case BE_QUEUE: ++ QueueSelect = QSLT_BE; //or QSelect = pTcb->priority; ++ break; ++ ++ case BK_QUEUE: ++ QueueSelect = QSLT_BK; //or QSelect = pTcb->priority; ++ break; ++ ++ case VO_QUEUE: ++ QueueSelect = QSLT_VO; //or QSelect = pTcb->priority; ++ break; ++ ++ case VI_QUEUE: ++ QueueSelect = QSLT_VI; //or QSelect = pTcb->priority; ++ break; ++ case MGNT_QUEUE: ++ QueueSelect = QSLT_MGNT; ++ break; ++ ++ case BEACON_QUEUE: ++ QueueSelect = QSLT_BEACON; ++ break; ++ ++ // TODO: 2006.10.30 mark other queue selection until we verify it is OK ++ // TODO: Remove Assertions ++//#if (RTL819X_FPGA_VER & RTL819X_FPGA_GUANGAN_070502) ++ case TXCMD_QUEUE: ++ QueueSelect = QSLT_CMD; ++ break; ++//#endif ++ case HIGH_QUEUE: ++ //QueueSelect = QSLT_HIGH; ++ //break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "TransmitTCB(): Impossible Queue Selection: %d \n", QueueID); ++ break; ++ } ++ return QueueSelect; ++} ++ ++static u8 MRateToHwRate8190Pci(u8 rate) ++{ ++ u8 ret = DESC90_RATE1M; ++ ++ switch(rate) { ++ case MGN_1M: ret = DESC90_RATE1M; break; ++ case MGN_2M: ret = DESC90_RATE2M; break; ++ case MGN_5_5M: ret = DESC90_RATE5_5M; break; ++ case MGN_11M: ret = DESC90_RATE11M; break; ++ case MGN_6M: ret = DESC90_RATE6M; break; ++ case MGN_9M: ret = DESC90_RATE9M; break; ++ case MGN_12M: ret = DESC90_RATE12M; break; ++ case MGN_18M: ret = DESC90_RATE18M; break; ++ case MGN_24M: ret = DESC90_RATE24M; break; ++ case MGN_36M: ret = DESC90_RATE36M; break; ++ case MGN_48M: ret = DESC90_RATE48M; break; ++ case MGN_54M: ret = DESC90_RATE54M; break; ++ ++ // HT rate since here ++ case MGN_MCS0: ret = DESC90_RATEMCS0; break; ++ case MGN_MCS1: ret = DESC90_RATEMCS1; break; ++ case MGN_MCS2: ret = DESC90_RATEMCS2; break; ++ case MGN_MCS3: ret = DESC90_RATEMCS3; break; ++ case MGN_MCS4: ret = DESC90_RATEMCS4; break; ++ case MGN_MCS5: ret = DESC90_RATEMCS5; break; ++ case MGN_MCS6: ret = DESC90_RATEMCS6; break; ++ case MGN_MCS7: ret = DESC90_RATEMCS7; break; ++ case MGN_MCS8: ret = DESC90_RATEMCS8; break; ++ case MGN_MCS9: ret = DESC90_RATEMCS9; break; ++ case MGN_MCS10: ret = DESC90_RATEMCS10; break; ++ case MGN_MCS11: ret = DESC90_RATEMCS11; break; ++ case MGN_MCS12: ret = DESC90_RATEMCS12; break; ++ case MGN_MCS13: ret = DESC90_RATEMCS13; break; ++ case MGN_MCS14: ret = DESC90_RATEMCS14; break; ++ case MGN_MCS15: ret = DESC90_RATEMCS15; break; ++ case (0x80|0x20): ret = DESC90_RATEMCS32; break; ++ ++ default: break; ++ } ++ return ret; ++} ++ ++ ++static u8 QueryIsShort(u8 TxHT, u8 TxRate, cb_desc *tcb_desc) ++{ ++ u8 tmp_Short; ++ ++ tmp_Short = (TxHT==1)?((tcb_desc->bUseShortGI)?1:0):((tcb_desc->bUseShortPreamble)?1:0); ++ ++ if(TxHT==1 && TxRate != DESC90_RATEMCS15) ++ tmp_Short = 0; ++ ++ return tmp_Short; ++} ++ ++/* ++ * The tx procedure is just as following, ++ * skb->cb will contain all the following information, ++ * priority, morefrag, rate, &dev. ++ * */ ++short rtl8192_tx(struct net_device *dev, struct sk_buff* skb) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct rtl8192_tx_ring *ring; ++ unsigned long flags; ++ cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); ++ tx_desc_819x_pci *pdesc = NULL; ++ TX_FWINFO_8190PCI *pTxFwInfo = NULL; ++ dma_addr_t mapping; ++ bool multi_addr=false,broad_addr=false,uni_addr=false; ++ u8* pda_addr = NULL; ++ int idx; ++ ++ mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); ++ /* collect the tx packets statitcs */ ++ pda_addr = ((u8*)skb->data) + sizeof(TX_FWINFO_8190PCI); ++ if(is_multicast_ether_addr(pda_addr)) ++ multi_addr = true; ++ else if(is_broadcast_ether_addr(pda_addr)) ++ broad_addr = true; ++ else ++ uni_addr = true; ++ ++ if(uni_addr) ++ priv->stats.txbytesunicast += (u8)(skb->len) - sizeof(TX_FWINFO_8190PCI); ++ else if(multi_addr) ++ priv->stats.txbytesmulticast +=(u8)(skb->len) - sizeof(TX_FWINFO_8190PCI); ++ else ++ priv->stats.txbytesbroadcast += (u8)(skb->len) - sizeof(TX_FWINFO_8190PCI); ++ ++ /* fill tx firmware */ ++ pTxFwInfo = (PTX_FWINFO_8190PCI)skb->data; ++ memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI)); ++ pTxFwInfo->TxHT = (tcb_desc->data_rate&0x80)?1:0; ++ pTxFwInfo->TxRate = MRateToHwRate8190Pci((u8)tcb_desc->data_rate); ++ pTxFwInfo->EnableCPUDur = tcb_desc->bTxEnableFwCalcDur; ++ pTxFwInfo->Short = QueryIsShort(pTxFwInfo->TxHT, pTxFwInfo->TxRate, tcb_desc); ++ ++ /* Aggregation related */ ++ if(tcb_desc->bAMPDUEnable) { ++ pTxFwInfo->AllowAggregation = 1; ++ pTxFwInfo->RxMF = tcb_desc->ampdu_factor; ++ pTxFwInfo->RxAMD = tcb_desc->ampdu_density; ++ } else { ++ pTxFwInfo->AllowAggregation = 0; ++ pTxFwInfo->RxMF = 0; ++ pTxFwInfo->RxAMD = 0; ++ } ++ ++ // ++ // Protection mode related ++ // ++ pTxFwInfo->RtsEnable = (tcb_desc->bRTSEnable)?1:0; ++ pTxFwInfo->CtsEnable = (tcb_desc->bCTSEnable)?1:0; ++ pTxFwInfo->RtsSTBC = (tcb_desc->bRTSSTBC)?1:0; ++ pTxFwInfo->RtsHT= (tcb_desc->rts_rate&0x80)?1:0; ++ pTxFwInfo->RtsRate = MRateToHwRate8190Pci((u8)tcb_desc->rts_rate); ++ pTxFwInfo->RtsBandwidth = 0; ++ pTxFwInfo->RtsSubcarrier = tcb_desc->RTSSC; ++ pTxFwInfo->RtsShort = (pTxFwInfo->RtsHT==0)?(tcb_desc->bRTSUseShortPreamble?1:0):(tcb_desc->bRTSUseShortGI?1:0); ++ // ++ // Set Bandwidth and sub-channel settings. ++ // ++ if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20_40) ++ { ++ if(tcb_desc->bPacketBW) ++ { ++ pTxFwInfo->TxBandwidth = 1; ++#ifdef RTL8190P ++ pTxFwInfo->TxSubCarrier = 3; ++#else ++ pTxFwInfo->TxSubCarrier = 0; //By SD3's Jerry suggestion, use duplicated mode, cosa 04012008 ++#endif ++ } ++ else ++ { ++ pTxFwInfo->TxBandwidth = 0; ++ pTxFwInfo->TxSubCarrier = priv->nCur40MhzPrimeSC; ++ } ++ } else { ++ pTxFwInfo->TxBandwidth = 0; ++ pTxFwInfo->TxSubCarrier = 0; ++ } ++ ++ if (0) ++ { ++ /* 2007/07/25 MH Copy current TX FW info.*/ ++ memcpy((void*)(&Tmp_TxFwInfo), (void*)(pTxFwInfo), sizeof(TX_FWINFO_8190PCI)); ++ printk("&&&&&&&&&&&&&&&&&&&&&&====>print out fwinf\n"); ++ printk("===>enable fwcacl:%d\n", Tmp_TxFwInfo.EnableCPUDur); ++ printk("===>RTS STBC:%d\n", Tmp_TxFwInfo.RtsSTBC); ++ printk("===>RTS Subcarrier:%d\n", Tmp_TxFwInfo.RtsSubcarrier); ++ printk("===>Allow Aggregation:%d\n", Tmp_TxFwInfo.AllowAggregation); ++ printk("===>TX HT bit:%d\n", Tmp_TxFwInfo.TxHT); ++ printk("===>Tx rate:%d\n", Tmp_TxFwInfo.TxRate); ++ printk("===>Received AMPDU Density:%d\n", Tmp_TxFwInfo.RxAMD); ++ printk("===>Received MPDU Factor:%d\n", Tmp_TxFwInfo.RxMF); ++ printk("===>TxBandwidth:%d\n", Tmp_TxFwInfo.TxBandwidth); ++ printk("===>TxSubCarrier:%d\n", Tmp_TxFwInfo.TxSubCarrier); ++ ++ printk("<=====**********************out of print\n"); ++ ++ } ++ spin_lock_irqsave(&priv->irq_th_lock,flags); ++ ring = &priv->tx_ring[tcb_desc->queue_index]; ++ if (tcb_desc->queue_index != BEACON_QUEUE) { ++ idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; ++ } else { ++ idx = 0; ++ } ++ ++ pdesc = &ring->desc[idx]; ++ if((pdesc->OWN == 1) && (tcb_desc->queue_index != BEACON_QUEUE)) { ++ RT_TRACE(COMP_ERR,"No more TX desc@%d, ring->idx = %d,idx = %d,%x", \ ++ tcb_desc->queue_index,ring->idx, idx,skb->len); ++ return skb->len; ++ } ++ ++ /* fill tx descriptor */ ++ memset((u8*)pdesc,0,12); ++ /*DWORD 0*/ ++ pdesc->LINIP = 0; ++ pdesc->CmdInit = 1; ++ pdesc->Offset = sizeof(TX_FWINFO_8190PCI) + 8; //We must add 8!! Emily ++ pdesc->PktSize = (u16)skb->len-sizeof(TX_FWINFO_8190PCI); ++ ++ /*DWORD 1*/ ++ pdesc->SecCAMID= 0; ++ pdesc->RATid = tcb_desc->RATRIndex; ++ ++ ++ pdesc->NoEnc = 1; ++ pdesc->SecType = 0x0; ++ if (tcb_desc->bHwSec) { ++ static u8 tmp =0; ++ if (!tmp) { ++ printk("==>================hw sec\n"); ++ tmp = 1; ++ } ++ switch (priv->ieee80211->pairwise_key_type) { ++ case KEY_TYPE_WEP40: ++ case KEY_TYPE_WEP104: ++ pdesc->SecType = 0x1; ++ pdesc->NoEnc = 0; ++ break; ++ case KEY_TYPE_TKIP: ++ pdesc->SecType = 0x2; ++ pdesc->NoEnc = 0; ++ break; ++ case KEY_TYPE_CCMP: ++ pdesc->SecType = 0x3; ++ pdesc->NoEnc = 0; ++ break; ++ case KEY_TYPE_NA: ++ pdesc->SecType = 0x0; ++ pdesc->NoEnc = 1; ++ break; ++ } ++ } ++ ++ // ++ // Set Packet ID ++ // ++ pdesc->PktId = 0x0; ++ ++ pdesc->QueueSelect = MapHwQueueToFirmwareQueue(tcb_desc->queue_index); ++ pdesc->TxFWInfoSize = sizeof(TX_FWINFO_8190PCI); ++ ++ pdesc->DISFB = tcb_desc->bTxDisableRateFallBack; ++ pdesc->USERATE = tcb_desc->bTxUseDriverAssingedRate; ++ ++ pdesc->FirstSeg =1; ++ pdesc->LastSeg = 1; ++ pdesc->TxBufferSize = skb->len; ++ ++ pdesc->TxBuffAddr = cpu_to_le32(mapping); ++ __skb_queue_tail(&ring->queue, skb); ++ pdesc->OWN = 1; ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ dev->trans_start = jiffies; ++ write_nic_word(dev,TPPoll,0x01<queue_index); ++ return 0; ++} ++ ++static short rtl8192_alloc_rx_desc_ring(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ rx_desc_819x_pci *entry = NULL; ++ int i; ++ ++ priv->rx_ring = pci_alloc_consistent(priv->pdev, ++ sizeof(*priv->rx_ring) * priv->rxringcount, &priv->rx_ring_dma); ++ ++ if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { ++ RT_TRACE(COMP_ERR,"Cannot allocate RX ring\n"); ++ return -ENOMEM; ++ } ++ ++ memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * priv->rxringcount); ++ priv->rx_idx = 0; ++ ++ for (i = 0; i < priv->rxringcount; i++) { ++ struct sk_buff *skb = dev_alloc_skb(priv->rxbuffersize); ++ dma_addr_t *mapping; ++ entry = &priv->rx_ring[i]; ++ if (!skb) ++ return 0; ++ priv->rx_buf[i] = skb; ++ mapping = (dma_addr_t *)skb->cb; ++ *mapping = pci_map_single(priv->pdev, skb->tail,//skb_tail_pointer(skb), ++ priv->rxbuffersize, PCI_DMA_FROMDEVICE); ++ ++ entry->BufferAddress = cpu_to_le32(*mapping); ++ ++ entry->Length = priv->rxbuffersize; ++ entry->OWN = 1; ++ } ++ ++ entry->EOR = 1; ++ return 0; ++} ++ ++static int rtl8192_alloc_tx_desc_ring(struct net_device *dev, ++ unsigned int prio, unsigned int entries) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ tx_desc_819x_pci *ring; ++ dma_addr_t dma; ++ int i; ++ ++ ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); ++ if (!ring || (unsigned long)ring & 0xFF) { ++ RT_TRACE(COMP_ERR, "Cannot allocate TX ring (prio = %d)\n", prio); ++ return -ENOMEM; ++ } ++ ++ memset(ring, 0, sizeof(*ring)*entries); ++ priv->tx_ring[prio].desc = ring; ++ priv->tx_ring[prio].dma = dma; ++ priv->tx_ring[prio].idx = 0; ++ priv->tx_ring[prio].entries = entries; ++ skb_queue_head_init(&priv->tx_ring[prio].queue); ++ ++ for (i = 0; i < entries; i++) ++ ring[i].NextDescAddress = ++ cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); ++ ++ return 0; ++} ++ ++ ++static short rtl8192_pci_initdescring(struct net_device *dev) ++{ ++ u32 ret; ++ int i; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ ret = rtl8192_alloc_rx_desc_ring(dev); ++ if (ret) { ++ return ret; ++ } ++ ++ ++ /* general process for other queue */ ++ for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { ++ if ((ret = rtl8192_alloc_tx_desc_ring(dev, i, priv->txringcount))) ++ goto err_free_rings; ++ } ++ ++#if 0 ++ /* specific process for hardware beacon process */ ++ if ((ret = rtl8192_alloc_tx_desc_ring(dev, MAX_TX_QUEUE_COUNT - 1, 2))) ++ goto err_free_rings; ++#endif ++ ++ return 0; ++ ++err_free_rings: ++ rtl8192_free_rx_ring(dev); ++ for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) ++ if (priv->tx_ring[i].desc) ++ rtl8192_free_tx_ring(dev, i); ++ return 1; ++} ++ ++static void rtl8192_pci_resetdescring(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int i; ++ ++ /* force the rx_idx to the first one */ ++ if(priv->rx_ring) { ++ rx_desc_819x_pci *entry = NULL; ++ for (i = 0; i < priv->rxringcount; i++) { ++ entry = &priv->rx_ring[i]; ++ entry->OWN = 1; ++ } ++ priv->rx_idx = 0; ++ } ++ ++ /* after reset, release previous pending packet, and force the ++ * tx idx to the first one */ ++ for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { ++ if (priv->tx_ring[i].desc) { ++ struct rtl8192_tx_ring *ring = &priv->tx_ring[i]; ++ ++ while (skb_queue_len(&ring->queue)) { ++ tx_desc_819x_pci *entry = &ring->desc[ring->idx]; ++ struct sk_buff *skb = __skb_dequeue(&ring->queue); ++ ++ pci_unmap_single(priv->pdev, le32_to_cpu(entry->TxBuffAddr), ++ skb->len, PCI_DMA_TODEVICE); ++ kfree_skb(skb); ++ ring->idx = (ring->idx + 1) % ring->entries; ++ } ++ ring->idx = 0; ++ } ++ } ++} ++ ++#if 1 ++extern void rtl8192_update_ratr_table(struct net_device* dev); ++static void rtl8192_link_change(struct net_device *dev) ++{ ++// int i; ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ //write_nic_word(dev, BCN_INTR_ITV, net->beacon_interval); ++ if (ieee->state == IEEE80211_LINKED) ++ { ++ rtl8192_net_update(dev); ++ rtl8192_update_ratr_table(dev); ++#if 1 ++ //add this as in pure N mode, wep encryption will use software way, but there is no chance to set this as wep will not set group key in wext. WB.2008.07.08 ++ if ((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) ++ EnableHWSecurityConfig8192(dev); ++#endif ++ } ++ else ++ { ++ write_nic_byte(dev, 0x173, 0); ++ } ++ /*update timing params*/ ++ //rtl8192_set_chan(dev, priv->chan); ++ //MSR ++ rtl8192_update_msr(dev); ++ ++ // 2007/10/16 MH MAC Will update TSF according to all received beacon, so we have ++ // // To set CBSSID bit when link with any AP or STA. ++ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) ++ { ++ u32 reg = 0; ++ reg = read_nic_dword(dev, RCR); ++ if (priv->ieee80211->state == IEEE80211_LINKED) ++ priv->ReceiveConfig = reg |= RCR_CBSSID; ++ else ++ priv->ReceiveConfig = reg &= ~RCR_CBSSID; ++ write_nic_dword(dev, RCR, reg); ++ } ++} ++#endif ++ ++ ++static struct ieee80211_qos_parameters def_qos_parameters = { ++ {3,3,3,3},/* cw_min */ ++ {7,7,7,7},/* cw_max */ ++ {2,2,2,2},/* aifs */ ++ {0,0,0,0},/* flags */ ++ {0,0,0,0} /* tx_op_limit */ ++}; ++ ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++static void rtl8192_update_beacon(struct work_struct * work) ++{ ++ struct r8192_priv *priv = container_of(work, struct r8192_priv, update_beacon_wq.work); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++void rtl8192_update_beacon(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ struct ieee80211_device* ieee = priv->ieee80211; ++ struct ieee80211_network* net = &ieee->current_network; ++ ++ if (ieee->pHTInfo->bCurrentHTSupport) ++ HTUpdateSelfAndPeerSetting(ieee, net); ++ ieee->pHTInfo->bCurrentRT2RTLongSlotTime = net->bssht.bdRT2RTLongSlotTime; ++ rtl8192_update_cap(dev, net->capability); ++} ++/* ++* background support to run QoS activate functionality ++*/ ++static int WDCAPARA_ADD[] = {EDCAPARA_BE,EDCAPARA_BK,EDCAPARA_VI,EDCAPARA_VO}; ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++static void rtl8192_qos_activate(struct work_struct * work) ++{ ++ struct r8192_priv *priv = container_of(work, struct r8192_priv, qos_activate); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++void rtl8192_qos_activate(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters; ++ u8 mode = priv->ieee80211->current_network.mode; ++// u32 size = sizeof(struct ieee80211_qos_parameters); ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ int i; ++ if (priv == NULL) ++ return; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) ++ down(&priv->mutex); ++#else ++ mutex_lock(&priv->mutex); ++#endif ++ if(priv->ieee80211->state != IEEE80211_LINKED) ++ goto success; ++ RT_TRACE(COMP_QOS,"qos active process with associate response received\n"); ++ /* It better set slot time at first */ ++ /* For we just support b/g mode at present, let the slot time at 9/20 selection */ ++ /* update the ac parameter to related registers */ ++ for(i = 0; i < QOS_QUEUE_NUM; i++) { ++ //Mode G/A: slotTimeTimer = 9; Mode B: 20 ++ u1bAIFS = qos_parameters->aifs[i] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime; ++ u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[i]))<< AC_PARAM_TXOP_LIMIT_OFFSET)| ++ (((u32)(qos_parameters->cw_max[i]))<< AC_PARAM_ECW_MAX_OFFSET)| ++ (((u32)(qos_parameters->cw_min[i]))<< AC_PARAM_ECW_MIN_OFFSET)| ++ ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET)); ++ printk("===>u4bAcParam:%x, ", u4bAcParam); ++ write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam); ++ //write_nic_dword(dev, WDCAPARA_ADD[i], 0x005e4332); ++ } ++ ++success: ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) ++ up(&priv->mutex); ++#else ++ mutex_unlock(&priv->mutex); ++#endif ++} ++ ++static int rtl8192_qos_handle_probe_response(struct r8192_priv *priv, ++ int active_network, ++ struct ieee80211_network *network) ++{ ++ int ret = 0; ++ u32 size = sizeof(struct ieee80211_qos_parameters); ++ ++ if(priv->ieee80211->state !=IEEE80211_LINKED) ++ return ret; ++ ++ if ((priv->ieee80211->iw_mode != IW_MODE_INFRA)) ++ return ret; ++ ++ if (network->flags & NETWORK_HAS_QOS_MASK) { ++ if (active_network && ++ (network->flags & NETWORK_HAS_QOS_PARAMETERS)) ++ network->qos_data.active = network->qos_data.supported; ++ ++ if ((network->qos_data.active == 1) && (active_network == 1) && ++ (network->flags & NETWORK_HAS_QOS_PARAMETERS) && ++ (network->qos_data.old_param_count != ++ network->qos_data.param_count)) { ++ network->qos_data.old_param_count = ++ network->qos_data.param_count; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(priv->priv_wq, &priv->qos_activate); ++#else ++ schedule_task(&priv->qos_activate); ++#endif ++ RT_TRACE (COMP_QOS, "QoS parameters change call " ++ "qos_activate\n"); ++ } ++ } else { ++ memcpy(&priv->ieee80211->current_network.qos_data.parameters,\ ++ &def_qos_parameters, size); ++ ++ if ((network->qos_data.active == 1) && (active_network == 1)) { ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(priv->priv_wq, &priv->qos_activate); ++#else ++ schedule_task(&priv->qos_activate); ++#endif ++ RT_TRACE(COMP_QOS, "QoS was disabled call qos_activate \n"); ++ } ++ network->qos_data.active = 0; ++ network->qos_data.supported = 0; ++ } ++ ++ return 0; ++} ++ ++/* handle manage frame frame beacon and probe response */ ++static int rtl8192_handle_beacon(struct net_device * dev, ++ struct ieee80211_beacon * beacon, ++ struct ieee80211_network * network) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ rtl8192_qos_handle_probe_response(priv,1,network); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->priv_wq, &priv->update_beacon_wq, 0); ++#else ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ schedule_task(&priv->update_beacon_wq); ++#else ++ queue_work(priv->priv_wq, &priv->update_beacon_wq); ++#endif ++#endif ++ return 0; ++ ++} ++ ++/* ++* handling the beaconing responses. if we get different QoS setting ++* off the network from the associated setting, adjust the QoS ++* setting ++*/ ++static int rtl8192_qos_association_resp(struct r8192_priv *priv, ++ struct ieee80211_network *network) ++{ ++ int ret = 0; ++ unsigned long flags; ++ u32 size = sizeof(struct ieee80211_qos_parameters); ++ int set_qos_param = 0; ++ ++ if ((priv == NULL) || (network == NULL)) ++ return ret; ++ ++ if(priv->ieee80211->state !=IEEE80211_LINKED) ++ return ret; ++ ++ if ((priv->ieee80211->iw_mode != IW_MODE_INFRA)) ++ return ret; ++ ++ spin_lock_irqsave(&priv->ieee80211->lock, flags); ++ if(network->flags & NETWORK_HAS_QOS_PARAMETERS) { ++ memcpy(&priv->ieee80211->current_network.qos_data.parameters,\ ++ &network->qos_data.parameters,\ ++ sizeof(struct ieee80211_qos_parameters)); ++ priv->ieee80211->current_network.qos_data.active = 1; ++#if 0 ++ if((priv->ieee80211->current_network.qos_data.param_count != \ ++ network->qos_data.param_count)) ++#endif ++ { ++ set_qos_param = 1; ++ /* update qos parameter for current network */ ++ priv->ieee80211->current_network.qos_data.old_param_count = \ ++ priv->ieee80211->current_network.qos_data.param_count; ++ priv->ieee80211->current_network.qos_data.param_count = \ ++ network->qos_data.param_count; ++ } ++ } else { ++ memcpy(&priv->ieee80211->current_network.qos_data.parameters,\ ++ &def_qos_parameters, size); ++ priv->ieee80211->current_network.qos_data.active = 0; ++ priv->ieee80211->current_network.qos_data.supported = 0; ++ set_qos_param = 1; ++ } ++ ++ spin_unlock_irqrestore(&priv->ieee80211->lock, flags); ++ ++ RT_TRACE(COMP_QOS, "%s: network->flags = %d,%d\n",__FUNCTION__,network->flags ,priv->ieee80211->current_network.qos_data.active); ++ if (set_qos_param == 1) ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(priv->priv_wq, &priv->qos_activate); ++#else ++ schedule_task(&priv->qos_activate); ++#endif ++ ++ ++ return ret; ++} ++ ++ ++static int rtl8192_handle_assoc_response(struct net_device *dev, ++ struct ieee80211_assoc_response_frame *resp, ++ struct ieee80211_network *network) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ rtl8192_qos_association_resp(priv, network); ++ return 0; ++} ++ ++ ++//updateRATRTabel for MCS only. Basic rate is not implement. ++void rtl8192_update_ratr_table(struct net_device* dev) ++ // POCTET_STRING posLegacyRate, ++ // u8* pMcsRate) ++ // PRT_WLAN_STA pEntry) ++{ ++ struct r8192_priv* priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ u8* pMcsRate = ieee->dot11HTOperationalRateSet; ++ //struct ieee80211_network *net = &ieee->current_network; ++ u32 ratr_value = 0; ++ u8 rate_index = 0; ++ ++ rtl8192_config_rate(dev, (u16*)(&ratr_value)); ++ ratr_value |= (*(u16*)(pMcsRate)) << 12; ++// switch (net->mode) ++ switch (ieee->mode) ++ { ++ case IEEE_A: ++ ratr_value &= 0x00000FF0; ++ break; ++ case IEEE_B: ++ ratr_value &= 0x0000000F; ++ break; ++ case IEEE_G: ++ ratr_value &= 0x00000FF7; ++ break; ++ case IEEE_N_24G: ++ case IEEE_N_5G: ++ if (ieee->pHTInfo->PeerMimoPs == 0) //MIMO_PS_STATIC ++ ratr_value &= 0x0007F007; ++ else{ ++ if (priv->rf_type == RF_1T2R) ++ ratr_value &= 0x000FF007; ++ else ++ ratr_value &= 0x0F81F007; ++ } ++ break; ++ default: ++ break; ++ } ++ ratr_value &= 0x0FFFFFFF; ++ if(ieee->pHTInfo->bCurTxBW40MHz && ieee->pHTInfo->bCurShortGI40MHz){ ++ ratr_value |= 0x80000000; ++ }else if(!ieee->pHTInfo->bCurTxBW40MHz && ieee->pHTInfo->bCurShortGI20MHz){ ++ ratr_value |= 0x80000000; ++ } ++ write_nic_dword(dev, RATR0+rate_index*4, ratr_value); ++ write_nic_byte(dev, UFWP, 1); ++} ++ ++static u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04}; ++static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; ++static bool GetNmodeSupportBySecCfg8190Pci(struct net_device*dev) ++{ ++#if 1 ++ struct r8192_priv* priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ int wpa_ie_len= ieee->wpa_ie_len; ++ struct ieee80211_crypt_data* crypt; ++ int encrypt; ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY) || (ieee->host_encrypt && crypt && crypt->ops && (0 == strcmp(crypt->ops->name,"WEP"))); ++ ++ /* simply judge */ ++ if(encrypt && (wpa_ie_len == 0)) { ++ /* wep encryption, no N mode setting */ ++ return false; ++// } else if((wpa_ie_len != 0)&&(memcmp(&(ieee->wpa_ie[14]),ccmp_ie,4))) { ++ } else if((wpa_ie_len != 0)) { ++ /* parse pairwise key type */ ++ //if((pairwisekey = WEP40)||(pairwisekey = WEP104)||(pairwisekey = TKIP)) ++ if (((ieee->wpa_ie[0] == 0xdd) && (!memcmp(&(ieee->wpa_ie[14]),ccmp_ie,4))) || ((ieee->wpa_ie[0] == 0x30) && (!memcmp(&ieee->wpa_ie[10],ccmp_rsn_ie, 4)))) ++ return true; ++ else ++ return false; ++ } else { ++ //RT_TRACE(COMP_ERR,"In %s The GroupEncAlgorithm is [4]\n",__FUNCTION__ ); ++ return true; ++ } ++ ++#if 0 ++ //In here we discuss with SD4 David. He think we still can send TKIP in broadcast group key in MCS rate. ++ //We can't force in G mode if Pairwie key is AES and group key is TKIP ++ if((pSecInfo->GroupEncAlgorithm == WEP104_Encryption) || (pSecInfo->GroupEncAlgorithm == WEP40_Encryption) || ++ (pSecInfo->PairwiseEncAlgorithm == WEP104_Encryption) || ++ (pSecInfo->PairwiseEncAlgorithm == WEP40_Encryption) || (pSecInfo->PairwiseEncAlgorithm == TKIP_Encryption)) ++ { ++ return false; ++ } ++ else ++ return true; ++#endif ++ return true; ++#endif ++} ++ ++static void rtl8192_refresh_supportrate(struct r8192_priv* priv) ++{ ++ struct ieee80211_device* ieee = priv->ieee80211; ++ //we donot consider set support rate for ABG mode, only HT MCS rate is set here. ++ if (ieee->mode == WIRELESS_MODE_N_24G || ieee->mode == WIRELESS_MODE_N_5G) ++ { ++ memcpy(ieee->Regdot11HTOperationalRateSet, ieee->RegHTSuppRateSet, 16); ++ //RT_DEBUG_DATA(COMP_INIT, ieee->RegHTSuppRateSet, 16); ++ //RT_DEBUG_DATA(COMP_INIT, ieee->Regdot11HTOperationalRateSet, 16); ++ } ++ else ++ memset(ieee->Regdot11HTOperationalRateSet, 0, 16); ++ return; ++} ++ ++static u8 rtl8192_getSupportedWireleeMode(struct net_device*dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 ret = 0; ++ switch(priv->rf_chip) ++ { ++ case RF_8225: ++ case RF_8256: ++ case RF_PSEUDO_11N: ++ ret = (WIRELESS_MODE_N_24G|WIRELESS_MODE_G|WIRELESS_MODE_B); ++ break; ++ case RF_8258: ++ ret = (WIRELESS_MODE_A|WIRELESS_MODE_N_5G); ++ break; ++ default: ++ ret = WIRELESS_MODE_B; ++ break; ++ } ++ return ret; ++} ++ ++static void rtl8192_SetWirelessMode(struct net_device* dev, u8 wireless_mode) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 bSupportMode = rtl8192_getSupportedWireleeMode(dev); ++ ++#if 1 ++ if ((wireless_mode == WIRELESS_MODE_AUTO) || ((wireless_mode&bSupportMode)==0)) ++ { ++ if(bSupportMode & WIRELESS_MODE_N_24G) ++ { ++ wireless_mode = WIRELESS_MODE_N_24G; ++ } ++ else if(bSupportMode & WIRELESS_MODE_N_5G) ++ { ++ wireless_mode = WIRELESS_MODE_N_5G; ++ } ++ else if((bSupportMode & WIRELESS_MODE_A)) ++ { ++ wireless_mode = WIRELESS_MODE_A; ++ } ++ else if((bSupportMode & WIRELESS_MODE_G)) ++ { ++ wireless_mode = WIRELESS_MODE_G; ++ } ++ else if((bSupportMode & WIRELESS_MODE_B)) ++ { ++ wireless_mode = WIRELESS_MODE_B; ++ } ++ else{ ++ RT_TRACE(COMP_ERR, "%s(), No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", __FUNCTION__,bSupportMode); ++ wireless_mode = WIRELESS_MODE_B; ++ } ++ } ++#ifdef TO_DO_LIST //// TODO: this function doesn't work well at this time, we shoud wait for FPGA ++ ActUpdateChannelAccessSetting( pAdapter, pHalData->CurrentWirelessMode, &pAdapter->MgntInfo.Info8185.ChannelAccessSetting ); ++#endif ++ priv->ieee80211->mode = wireless_mode; ++ ++ if ((wireless_mode == WIRELESS_MODE_N_24G) || (wireless_mode == WIRELESS_MODE_N_5G)) ++ priv->ieee80211->pHTInfo->bEnableHT = 1; ++ else ++ priv->ieee80211->pHTInfo->bEnableHT = 0; ++ RT_TRACE(COMP_INIT, "Current Wireless Mode is %x\n", wireless_mode); ++ rtl8192_refresh_supportrate(priv); ++#endif ++ ++} ++//init priv variables here ++ ++static bool GetHalfNmodeSupportByAPs819xPci(struct net_device* dev) ++{ ++ bool Reval; ++ struct r8192_priv* priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ ++ if(ieee->bHalfWirelessN24GMode == true) ++ Reval = true; ++ else ++ Reval = false; ++ ++ return Reval; ++} ++ ++short rtl8192_is_tx_queue_empty(struct net_device *dev) ++{ ++ int i=0; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ for (i=0; i<=MGNT_QUEUE; i++) ++ { ++ if ((i== TXCMD_QUEUE) || (i == HCCA_QUEUE) ) ++ continue; ++ if (skb_queue_len(&(&priv->tx_ring[i])->queue) > 0){ ++ printk("===>tx queue is not empty:%d, %d\n", i, skb_queue_len(&(&priv->tx_ring[i])->queue)); ++ return 0; ++ } ++ } ++ return 1; ++} ++#if 0 ++void rtl8192_rq_tx_ack(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ priv->ieee80211->ack_tx_to_ieee = 1; ++} ++#endif ++static void rtl8192_hw_sleep_down(struct net_device *dev) ++{ ++ RT_TRACE(COMP_POWER, "%s()============>come to sleep down\n", __FUNCTION__); ++ MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS); ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++static void rtl8192_hw_sleep_wq (struct work_struct *work) ++{ ++// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); ++// struct ieee80211_device * ieee = (struct ieee80211_device*) ++// container_of(work, struct ieee80211_device, watch_dog_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8192_hw_sleep_wq(struct net_device* dev) ++{ ++#endif ++ //printk("=========>%s()\n", __FUNCTION__); ++ rtl8192_hw_sleep_down(dev); ++} ++// printk("dev is %d\n",dev); ++// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__); ++static void rtl8192_hw_wakeup(struct net_device* dev) ++{ ++// u32 flags = 0; ++ ++// spin_lock_irqsave(&priv->ps_lock,flags); ++ RT_TRACE(COMP_POWER, "%s()============>come to wake up\n", __FUNCTION__); ++ MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS); ++ //FIXME: will we send package stored while nic is sleep? ++// spin_unlock_irqrestore(&priv->ps_lock,flags); ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8192_hw_wakeup_wq (struct work_struct *work) ++{ ++// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); ++// struct ieee80211_device * ieee = (struct ieee80211_device*) ++// container_of(work, struct ieee80211_device, watch_dog_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8192_hw_wakeup_wq(struct net_device* dev) ++{ ++#endif ++ rtl8192_hw_wakeup(dev); ++ ++} ++ ++#define MIN_SLEEP_TIME 50 ++#define MAX_SLEEP_TIME 10000 ++static void rtl8192_hw_to_sleep(struct net_device *dev, u32 th, u32 tl) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ u32 rb = jiffies; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->ps_lock,flags); ++ ++ /* Writing HW register with 0 equals to disable ++ * the timer, that is not really what we want ++ */ ++ tl -= MSECS(4+16+7); ++ ++ //if(tl == 0) tl = 1; ++ ++ /* FIXME HACK FIXME HACK */ ++// force_pci_posting(dev); ++ //mdelay(1); ++ ++// rb = read_nic_dword(dev, TSFTR); ++ ++ /* If the interval in witch we are requested to sleep is too ++ * short then give up and remain awake ++ */ ++ if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME)) ++ ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) { ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++ printk("too short to sleep\n"); ++ return; ++ } ++ ++// write_nic_dword(dev, TimerInt, tl); ++// rb = read_nic_dword(dev, TSFTR); ++ { ++ u32 tmp = (tl>rb)?(tl-rb):(rb-tl); ++ // if (tlieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb ++ } ++ /* if we suspect the TimerInt is gone beyond tl ++ * while setting it, then give up ++ */ ++#if 1 ++ if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))|| ++ ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) { ++ printk("========>too long to sleep:%x, %x, %lx\n", tl, rb, MSECS(MAX_SLEEP_TIME)); ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++ return; ++ } ++#endif ++// if(priv->rf_sleep) ++// priv->rf_sleep(dev); ++ ++ //printk("<=========%s()\n", __FUNCTION__); ++ queue_delayed_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq,0); ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++} ++static void rtl8192_init_priv_variable(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 i; ++ priv->being_init_adapter = false; ++ priv->txbuffsize = 1600;//1024; ++ priv->txfwbuffersize = 4096; ++ priv->txringcount = 64;//32; ++ //priv->txbeaconcount = priv->txringcount; ++ priv->txbeaconcount = 2; ++ priv->rxbuffersize = 9100;//2048;//1024; ++ priv->rxringcount = MAX_RX_COUNT;//64; ++ priv->irq_enabled=0; ++ priv->card_8192 = NIC_8192E; ++ priv->rx_skb_complete = 1; ++ priv->chan = 1; //set to channel 1 ++ priv->RegWirelessMode = WIRELESS_MODE_AUTO; ++ priv->RegChannelPlan = 0xf; ++ priv->nrxAMPDU_size = 0; ++ priv->nrxAMPDU_aggr_num = 0; ++ priv->last_rxdesc_tsf_high = 0; ++ priv->last_rxdesc_tsf_low = 0; ++ priv->ieee80211->mode = WIRELESS_MODE_AUTO; //SET AUTO ++ priv->ieee80211->iw_mode = IW_MODE_INFRA; ++ priv->ieee80211->ieee_up=0; ++ priv->retry_rts = DEFAULT_RETRY_RTS; ++ priv->retry_data = DEFAULT_RETRY_DATA; ++ priv->ieee80211->rts = DEFAULT_RTS_THRESHOLD; ++ priv->ieee80211->rate = 110; //11 mbps ++ priv->ieee80211->short_slot = 1; ++ priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0; ++ priv->bcck_in_ch14 = false; ++ priv->bfsync_processing = false; ++ priv->CCKPresentAttentuation = 0; ++ priv->rfa_txpowertrackingindex = 0; ++ priv->rfc_txpowertrackingindex = 0; ++ priv->CckPwEnl = 6; ++ priv->ScanDelay = 50;//for Scan TODO ++ //added by amy for silent reset ++ priv->ResetProgress = RESET_TYPE_NORESET; ++ priv->bForcedSilentReset = 0; ++ priv->bDisableNormalResetCheck = false; ++ priv->force_reset = false; ++ //added by amy for power save ++ priv->RegRfOff = 0; ++ priv->ieee80211->RfOffReason = 0; ++ priv->RFChangeInProgress = false; ++ priv->bHwRfOffAction = 0; ++ priv->SetRFPowerStateInProgress = false; ++ priv->ieee80211->PowerSaveControl.bInactivePs = true; ++ priv->ieee80211->PowerSaveControl.bIPSModeBackup = false; ++ //just for debug ++ priv->txpower_checkcnt = 0; ++ priv->thermal_readback_index =0; ++ priv->txpower_tracking_callback_cnt = 0; ++ priv->ccktxpower_adjustcnt_ch14 = 0; ++ priv->ccktxpower_adjustcnt_not_ch14 = 0; ++ ++ priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; ++ priv->ieee80211->iw_mode = IW_MODE_INFRA; ++ priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | ++ IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | ++ IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE;/* | ++ IEEE_SOFTMAC_BEACONS;*///added by amy 080604 //| //IEEE_SOFTMAC_SINGLE_QUEUE; ++ ++ priv->ieee80211->active_scan = 1; ++ priv->ieee80211->modulation = IEEE80211_CCK_MODULATION | IEEE80211_OFDM_MODULATION; ++ priv->ieee80211->host_encrypt = 1; ++ priv->ieee80211->host_decrypt = 1; ++ //priv->ieee80211->start_send_beacons = NULL;//rtl819xusb_beacon_tx;//-by amy 080604 ++ //priv->ieee80211->stop_send_beacons = NULL;//rtl8192_beacon_stop;//-by amy 080604 ++ priv->ieee80211->start_send_beacons = rtl8192_start_beacon;//+by david 081107 ++ priv->ieee80211->stop_send_beacons = rtl8192_stop_beacon;//+by david 081107 ++ priv->ieee80211->softmac_hard_start_xmit = rtl8192_hard_start_xmit; ++ priv->ieee80211->set_chan = rtl8192_set_chan; ++ priv->ieee80211->link_change = rtl8192_link_change; ++ priv->ieee80211->softmac_data_hard_start_xmit = rtl8192_hard_data_xmit; ++ priv->ieee80211->data_hard_stop = rtl8192_data_hard_stop; ++ priv->ieee80211->data_hard_resume = rtl8192_data_hard_resume; ++ priv->ieee80211->init_wmmparam_flag = 0; ++ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; ++ priv->ieee80211->check_nic_enough_desc = check_nic_enough_desc; ++ priv->ieee80211->tx_headroom = sizeof(TX_FWINFO_8190PCI); ++ priv->ieee80211->qos_support = 1; ++ priv->ieee80211->dot11PowerSaveMode = 0; ++ //added by WB ++// priv->ieee80211->SwChnlByTimerHandler = rtl8192_phy_SwChnl; ++ priv->ieee80211->SetBWModeHandler = rtl8192_SetBWMode; ++ priv->ieee80211->handle_assoc_response = rtl8192_handle_assoc_response; ++ priv->ieee80211->handle_beacon = rtl8192_handle_beacon; ++ ++ priv->ieee80211->sta_wake_up = rtl8192_hw_wakeup; ++// priv->ieee80211->ps_request_tx_ack = rtl8192_rq_tx_ack; ++ priv->ieee80211->enter_sleep_state = rtl8192_hw_to_sleep; ++ priv->ieee80211->ps_is_queue_empty = rtl8192_is_tx_queue_empty; ++ //added by david ++ priv->ieee80211->GetNmodeSupportBySecCfg = GetNmodeSupportBySecCfg8190Pci; ++ priv->ieee80211->SetWirelessMode = rtl8192_SetWirelessMode; ++ priv->ieee80211->GetHalfNmodeSupportByAPsHandler = GetHalfNmodeSupportByAPs819xPci; ++ ++ //added by amy ++ priv->ieee80211->InitialGainHandler = InitialGain819xPci; ++ ++ priv->card_type = USB; ++ { ++ priv->ShortRetryLimit = 0x30; ++ priv->LongRetryLimit = 0x30; ++ } ++ priv->EarlyRxThreshold = 7; ++ priv->enable_gpio0 = 0; ++ ++ priv->TransmitConfig = 0; ++ ++ priv->ReceiveConfig = RCR_ADD3 | ++ RCR_AMF | RCR_ADF | //accept management/data ++ RCR_AICV | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. ++ RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC ++ RCR_AAP | ((u32)7<irq_mask = (u32)(IMR_ROK | IMR_VODOK | IMR_VIDOK | IMR_BEDOK | IMR_BKDOK |\ ++ IMR_HCCADOK | IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK |\ ++ IMR_BDOK | IMR_RXCMDOK | IMR_TIMEOUT0 | IMR_RDU | IMR_RXFOVW |\ ++ IMR_TXFOVW | IMR_BcnInt | IMR_TBDOK | IMR_TBDER); ++ ++ priv->AcmControl = 0; ++ priv->pFirmware = (rt_firmware*)vmalloc(sizeof(rt_firmware)); ++ if (priv->pFirmware) ++ memset(priv->pFirmware, 0, sizeof(rt_firmware)); ++ ++ /* rx related queue */ ++ skb_queue_head_init(&priv->rx_queue); ++ skb_queue_head_init(&priv->skb_queue); ++ ++ /* Tx related queue */ ++ for(i = 0; i < MAX_QUEUE_SIZE; i++) { ++ skb_queue_head_init(&priv->ieee80211->skb_waitQ [i]); ++ } ++ for(i = 0; i < MAX_QUEUE_SIZE; i++) { ++ skb_queue_head_init(&priv->ieee80211->skb_aggQ [i]); ++ } ++ priv->rf_set_chan = rtl8192_phy_SwChnl; ++} ++ ++//init lock here ++static void rtl8192_init_priv_lock(struct r8192_priv* priv) ++{ ++ spin_lock_init(&priv->tx_lock); ++ spin_lock_init(&priv->irq_lock);//added by thomas ++ spin_lock_init(&priv->irq_th_lock); ++ spin_lock_init(&priv->rf_ps_lock); ++ spin_lock_init(&priv->ps_lock); ++ //spin_lock_init(&priv->rf_lock); ++ sema_init(&priv->wx_sem,1); ++ sema_init(&priv->rf_sem,1); ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) ++ sema_init(&priv->mutex, 1); ++#else ++ mutex_init(&priv->mutex); ++#endif ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void rtl819x_watchdog_wqcallback(struct work_struct *work); ++#else ++extern void rtl819x_watchdog_wqcallback(struct net_device *dev); ++#endif ++ ++void rtl8192_irq_rx_tasklet(struct r8192_priv *priv); ++void rtl8192_irq_tx_tasklet(struct r8192_priv *priv); ++void rtl8192_prepare_beacon(struct r8192_priv *priv); ++//init tasklet and wait_queue here. only 2.6 above kernel is considered ++#define DRV_NAME "wlan0" ++static void rtl8192_init_priv_task(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#ifdef PF_SYNCTHREAD ++ priv->priv_wq = create_workqueue(DRV_NAME,0); ++#else ++ priv->priv_wq = create_workqueue(DRV_NAME); ++#endif ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++// INIT_WORK(&priv->reset_wq, (void(*)(void*)) rtl8192_restart); ++ INIT_WORK(&priv->reset_wq, rtl8192_restart); ++// INIT_DELAYED_WORK(&priv->watch_dog_wq, hal_dm_watchdog); ++ INIT_DELAYED_WORK(&priv->watch_dog_wq, rtl819x_watchdog_wqcallback); ++ INIT_DELAYED_WORK(&priv->txpower_tracking_wq, dm_txpower_trackingcallback); ++ INIT_DELAYED_WORK(&priv->rfpath_check_wq, dm_rf_pathcheck_workitemcallback); ++ INIT_DELAYED_WORK(&priv->update_beacon_wq, rtl8192_update_beacon); ++ //INIT_WORK(&priv->SwChnlWorkItem, rtl8192_SwChnl_WorkItem); ++ //INIT_WORK(&priv->SetBWModeWorkItem, rtl8192_SetBWModeWorkItem); ++ INIT_WORK(&priv->qos_activate, rtl8192_qos_activate); ++ INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8192_hw_wakeup_wq); ++ INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8192_hw_sleep_wq); ++ ++#else ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++ tq_init(&priv->reset_wq, (void*)rtl8192_restart, dev); ++ tq_init(&priv->watch_dog_wq, (void*)rtl819x_watchdog_wqcallback, dev); ++ tq_init(&priv->txpower_tracking_wq, (void*)dm_txpower_trackingcallback, dev); ++ tq_init(&priv->rfpath_check_wq, (void*)dm_rf_pathcheck_workitemcallback, dev); ++ tq_init(&priv->update_beacon_wq, (void*)rtl8192_update_beacon, dev); ++ //tq_init(&priv->SwChnlWorkItem, (void*) rtl8192_SwChnl_WorkItem, dev); ++ //tq_init(&priv->SetBWModeWorkItem, (void*)rtl8192_SetBWModeWorkItem, dev); ++ tq_init(&priv->qos_activate, (void *)rtl8192_qos_activate, dev); ++ tq_init(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8192_hw_wakeup_wq, dev); ++ tq_init(&priv->ieee80211->hw_sleep_wq,(void*) rtl8192_hw_sleep_wq, dev); ++ ++#else ++ INIT_WORK(&priv->reset_wq,(void(*)(void*)) rtl8192_restart,dev); ++// INIT_WORK(&priv->watch_dog_wq, (void(*)(void*)) hal_dm_watchdog,dev); ++ INIT_WORK(&priv->watch_dog_wq, (void(*)(void*)) rtl819x_watchdog_wqcallback,dev); ++ INIT_WORK(&priv->txpower_tracking_wq, (void(*)(void*)) dm_txpower_trackingcallback,dev); ++ INIT_WORK(&priv->rfpath_check_wq, (void(*)(void*)) dm_rf_pathcheck_workitemcallback,dev); ++ INIT_WORK(&priv->update_beacon_wq, (void(*)(void*))rtl8192_update_beacon,dev); ++ //INIT_WORK(&priv->SwChnlWorkItem, (void(*)(void*)) rtl8192_SwChnl_WorkItem, dev); ++ //INIT_WORK(&priv->SetBWModeWorkItem, (void(*)(void*)) rtl8192_SetBWModeWorkItem, dev); ++ INIT_WORK(&priv->qos_activate, (void(*)(void *))rtl8192_qos_activate, dev); ++ INIT_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8192_hw_wakeup_wq, dev); ++ INIT_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8192_hw_sleep_wq, dev); ++#endif ++#endif ++ ++ tasklet_init(&priv->irq_rx_tasklet, ++ (void(*)(unsigned long))rtl8192_irq_rx_tasklet, ++ (unsigned long)priv); ++ tasklet_init(&priv->irq_tx_tasklet, ++ (void(*)(unsigned long))rtl8192_irq_tx_tasklet, ++ (unsigned long)priv); ++ tasklet_init(&priv->irq_prepare_beacon_tasklet, ++ (void(*)(unsigned long))rtl8192_prepare_beacon, ++ (unsigned long)priv); ++} ++ ++static void rtl8192_get_eeprom_size(struct net_device* dev) ++{ ++ u16 curCR = 0; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RT_TRACE(COMP_INIT, "===========>%s()\n", __FUNCTION__); ++ curCR = read_nic_dword(dev, EPROM_CMD); ++ RT_TRACE(COMP_INIT, "read from Reg Cmd9346CR(%x):%x\n", EPROM_CMD, curCR); ++ //whether need I consider BIT5? ++ priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EPROM_93c56 : EPROM_93c46; ++ RT_TRACE(COMP_INIT, "<===========%s(), epromtype:%d\n", __FUNCTION__, priv->epromtype); ++} ++ ++//used to swap endian. as ntohl & htonl are not neccessary to swap endian, so use this instead. ++static inline u16 endian_swap(u16* data) ++{ ++ u16 tmp = *data; ++ *data = (tmp >> 8) | (tmp << 8); ++ return *data; ++} ++ ++/* ++ * Note: Adapter->EEPROMAddressSize should be set before this function call. ++ * EEPROM address size can be got through GetEEPROMSize8185() ++*/ ++static void rtl8192_read_eeprom_info(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ u8 tempval; ++#ifdef RTL8192E ++ u8 ICVer8192, ICVer8256; ++#endif ++ u16 i,usValue, IC_Version; ++ u16 EEPROMId; ++#ifdef RTL8190P ++ u8 offset;//, tmpAFR; ++ u8 EepromTxPower[100]; ++#endif ++ u8 bMac_Tmp_Addr[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x01}; ++ RT_TRACE(COMP_INIT, "====> rtl8192_read_eeprom_info\n"); ++ ++ ++ // TODO: I don't know if we need to apply EF function to EEPROM read function ++ ++ //2 Read EEPROM ID to make sure autoload is success ++ EEPROMId = eprom_read(dev, 0); ++ if( EEPROMId != RTL8190_EEPROM_ID ) ++ { ++ RT_TRACE(COMP_ERR, "EEPROM ID is invalid:%x, %x\n", EEPROMId, RTL8190_EEPROM_ID); ++ priv->AutoloadFailFlag=true; ++ } ++ else ++ { ++ priv->AutoloadFailFlag=false; ++ } ++ ++ // ++ // Assign Chip Version ID ++ // ++ // Read IC Version && Channel Plan ++ if(!priv->AutoloadFailFlag) ++ { ++ // VID, PID ++ priv->eeprom_vid = eprom_read(dev, (EEPROM_VID >> 1)); ++ priv->eeprom_did = eprom_read(dev, (EEPROM_DID >> 1)); ++ ++ usValue = eprom_read(dev, (u16)(EEPROM_Customer_ID>>1)) >> 8 ; ++ priv->eeprom_CustomerID = (u8)( usValue & 0xff); ++ usValue = eprom_read(dev, (EEPROM_ICVersion_ChannelPlan>>1)); ++ priv->eeprom_ChannelPlan = usValue&0xff; ++ IC_Version = ((usValue&0xff00)>>8); ++ ++#ifdef RTL8190P ++ priv->card_8192_version = (VERSION_8190)(IC_Version); ++#else ++ #ifdef RTL8192E ++ ICVer8192 = (IC_Version&0xf); //bit0~3; 1:A cut, 2:B cut, 3:C cut... ++ ICVer8256 = ((IC_Version&0xf0)>>4);//bit4~6, bit7 reserved for other RF chip; 1:A cut, 2:B cut, 3:C cut... ++ RT_TRACE(COMP_INIT, "\nICVer8192 = 0x%x\n", ICVer8192); ++ RT_TRACE(COMP_INIT, "\nICVer8256 = 0x%x\n", ICVer8256); ++ if(ICVer8192 == 0x2) //B-cut ++ { ++ if(ICVer8256 == 0x5) //E-cut ++ priv->card_8192_version= VERSION_8190_BE; ++ } ++ #endif ++#endif ++ switch(priv->card_8192_version) ++ { ++ case VERSION_8190_BD: ++ case VERSION_8190_BE: ++ break; ++ default: ++ priv->card_8192_version = VERSION_8190_BD; ++ break; ++ } ++ RT_TRACE(COMP_INIT, "\nIC Version = 0x%x\n", priv->card_8192_version); ++ } ++ else ++ { ++ priv->card_8192_version = VERSION_8190_BD; ++ priv->eeprom_vid = 0; ++ priv->eeprom_did = 0; ++ priv->eeprom_CustomerID = 0; ++ priv->eeprom_ChannelPlan = 0; ++ RT_TRACE(COMP_INIT, "\nIC Version = 0x%x\n", 0xff); ++ } ++ ++ RT_TRACE(COMP_INIT, "EEPROM VID = 0x%4x\n", priv->eeprom_vid); ++ RT_TRACE(COMP_INIT, "EEPROM DID = 0x%4x\n", priv->eeprom_did); ++ RT_TRACE(COMP_INIT,"EEPROM Customer ID: 0x%2x\n", priv->eeprom_CustomerID); ++ ++ //2 Read Permanent MAC address ++ if(!priv->AutoloadFailFlag) ++ { ++ for(i = 0; i < 6; i += 2) ++ { ++ usValue = eprom_read(dev, (u16) ((EEPROM_NODE_ADDRESS_BYTE_0+i)>>1)); ++ *(u16*)(&dev->dev_addr[i]) = usValue; ++ } ++ } else { ++ // when auto load failed, the last address byte set to be a random one. ++ // added by david woo.2007/11/7 ++ memcpy(dev->dev_addr, bMac_Tmp_Addr, 6); ++ #if 0 ++ for(i = 0; i < 6; i++) ++ { ++ Adapter->PermanentAddress[i] = sMacAddr[i]; ++ PlatformEFIOWrite1Byte(Adapter, IDR0+i, sMacAddr[i]); ++ } ++ #endif ++ } ++ ++ RT_TRACE(COMP_INIT, "Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", ++ dev->dev_addr[0], dev->dev_addr[1], ++ dev->dev_addr[2], dev->dev_addr[3], ++ dev->dev_addr[4], dev->dev_addr[5]); ++ ++ //2 TX Power Check EEPROM Fail or not ++ if(priv->card_8192_version > VERSION_8190_BD) { ++ priv->bTXPowerDataReadFromEEPORM = true; ++ } else { ++ priv->bTXPowerDataReadFromEEPORM = false; ++ } ++ ++ // 2007/11/15 MH 8190PCI Default=2T4R, 8192PCIE dafault=1T2R ++ priv->rf_type = RTL819X_DEFAULT_RF_TYPE; ++ ++ if(priv->card_8192_version > VERSION_8190_BD) ++ { ++ // Read RF-indication and Tx Power gain index diff of legacy to HT OFDM rate. ++ if(!priv->AutoloadFailFlag) ++ { ++ tempval = (eprom_read(dev, (EEPROM_RFInd_PowerDiff>>1))) & 0xff; ++ priv->EEPROMLegacyHTTxPowerDiff = tempval & 0xf; // bit[3:0] ++ ++ if (tempval&0x80) //RF-indication, bit[7] ++ priv->rf_type = RF_1T2R; ++ else ++ priv->rf_type = RF_2T4R; ++ } ++ else ++ { ++ priv->EEPROMLegacyHTTxPowerDiff = EEPROM_Default_LegacyHTTxPowerDiff; ++ } ++ RT_TRACE(COMP_INIT, "EEPROMLegacyHTTxPowerDiff = %d\n", ++ priv->EEPROMLegacyHTTxPowerDiff); ++ ++ // Read ThermalMeter from EEPROM ++ if(!priv->AutoloadFailFlag) ++ { ++ priv->EEPROMThermalMeter = (u8)(((eprom_read(dev, (EEPROM_ThermalMeter>>1))) & 0xff00)>>8); ++ } ++ else ++ { ++ priv->EEPROMThermalMeter = EEPROM_Default_ThermalMeter; ++ } ++ RT_TRACE(COMP_INIT, "ThermalMeter = %d\n", priv->EEPROMThermalMeter); ++ //vivi, for tx power track ++ priv->TSSI_13dBm = priv->EEPROMThermalMeter *100; ++ ++ if(priv->epromtype == EPROM_93c46) ++ { ++ // Read antenna tx power offset of B/C/D to A and CrystalCap from EEPROM ++ if(!priv->AutoloadFailFlag) ++ { ++ usValue = eprom_read(dev, (EEPROM_TxPwDiff_CrystalCap>>1)); ++ priv->EEPROMAntPwDiff = (usValue&0x0fff); ++ priv->EEPROMCrystalCap = (u8)((usValue&0xf000)>>12); ++ } ++ else ++ { ++ priv->EEPROMAntPwDiff = EEPROM_Default_AntTxPowerDiff; ++ priv->EEPROMCrystalCap = EEPROM_Default_TxPwDiff_CrystalCap; ++ } ++ RT_TRACE(COMP_INIT, "EEPROMAntPwDiff = %d\n", priv->EEPROMAntPwDiff); ++ RT_TRACE(COMP_INIT, "EEPROMCrystalCap = %d\n", priv->EEPROMCrystalCap); ++ ++ // ++ // Get per-channel Tx Power Level ++ // ++ for(i=0; i<14; i+=2) ++ { ++ if(!priv->AutoloadFailFlag) ++ { ++ usValue = eprom_read(dev, (u16) ((EEPROM_TxPwIndex_CCK+i)>>1) ); ++ } ++ else ++ { ++ usValue = EEPROM_Default_TxPower; ++ } ++ *((u16*)(&priv->EEPROMTxPowerLevelCCK[i])) = usValue; ++ RT_TRACE(COMP_INIT,"CCK Tx Power Level, Index %d = 0x%02x\n", i, priv->EEPROMTxPowerLevelCCK[i]); ++ RT_TRACE(COMP_INIT, "CCK Tx Power Level, Index %d = 0x%02x\n", i+1, priv->EEPROMTxPowerLevelCCK[i+1]); ++ } ++ for(i=0; i<14; i+=2) ++ { ++ if(!priv->AutoloadFailFlag) ++ { ++ usValue = eprom_read(dev, (u16) ((EEPROM_TxPwIndex_OFDM_24G+i)>>1) ); ++ } ++ else ++ { ++ usValue = EEPROM_Default_TxPower; ++ } ++ *((u16*)(&priv->EEPROMTxPowerLevelOFDM24G[i])) = usValue; ++ RT_TRACE(COMP_INIT, "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", i, priv->EEPROMTxPowerLevelOFDM24G[i]); ++ RT_TRACE(COMP_INIT, "OFDM 2.4G Tx Power Level, Index %d = 0x%02x\n", i+1, priv->EEPROMTxPowerLevelOFDM24G[i+1]); ++ } ++ } ++ else if(priv->epromtype== EPROM_93c56) ++ { ++ #ifdef RTL8190P ++ // Read CrystalCap from EEPROM ++ if(!priv->AutoloadFailFlag) ++ { ++ priv->EEPROMAntPwDiff = EEPROM_Default_AntTxPowerDiff; ++ priv->EEPROMCrystalCap = (u8)(((eprom_read(dev, (EEPROM_C56_CrystalCap>>1))) & 0xf000)>>12); ++ } ++ else ++ { ++ priv->EEPROMAntPwDiff = EEPROM_Default_AntTxPowerDiff; ++ priv->EEPROMCrystalCap = EEPROM_Default_TxPwDiff_CrystalCap; ++ } ++ RT_TRACE(COMP_INIT,"EEPROMAntPwDiff = %d\n", priv->EEPROMAntPwDiff); ++ RT_TRACE(COMP_INIT, "EEPROMCrystalCap = %d\n", priv->EEPROMCrystalCap); ++ ++ // Get Tx Power Level by Channel ++ if(!priv->AutoloadFailFlag) ++ { ++ // Read Tx power of Channel 1 ~ 14 from EEPROM. ++ for(i = 0; i < 12; i+=2) ++ { ++ if (i <6) ++ offset = EEPROM_C56_RfA_CCK_Chnl1_TxPwIndex + i; ++ else ++ offset = EEPROM_C56_RfC_CCK_Chnl1_TxPwIndex + i - 6; ++ usValue = eprom_read(dev, (offset>>1)); ++ *((u16*)(&EepromTxPower[i])) = usValue; ++ } ++ ++ for(i = 0; i < 12; i++) ++ { ++ if (i <= 2) ++ priv->EEPROMRfACCKChnl1TxPwLevel[i] = EepromTxPower[i]; ++ else if ((i >=3 )&&(i <= 5)) ++ priv->EEPROMRfAOfdmChnlTxPwLevel[i-3] = EepromTxPower[i]; ++ else if ((i >=6 )&&(i <= 8)) ++ priv->EEPROMRfCCCKChnl1TxPwLevel[i-6] = EepromTxPower[i]; ++ else ++ priv->EEPROMRfCOfdmChnlTxPwLevel[i-9] = EepromTxPower[i]; ++ } ++ } ++ else ++ { ++ priv->EEPROMRfACCKChnl1TxPwLevel[0] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfACCKChnl1TxPwLevel[1] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfACCKChnl1TxPwLevel[2] = EEPROM_Default_TxPowerLevel; ++ ++ priv->EEPROMRfAOfdmChnlTxPwLevel[0] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfAOfdmChnlTxPwLevel[1] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfAOfdmChnlTxPwLevel[2] = EEPROM_Default_TxPowerLevel; ++ ++ priv->EEPROMRfCCCKChnl1TxPwLevel[0] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfCCCKChnl1TxPwLevel[1] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfCCCKChnl1TxPwLevel[2] = EEPROM_Default_TxPowerLevel; ++ ++ priv->EEPROMRfCOfdmChnlTxPwLevel[0] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfCOfdmChnlTxPwLevel[1] = EEPROM_Default_TxPowerLevel; ++ priv->EEPROMRfCOfdmChnlTxPwLevel[2] = EEPROM_Default_TxPowerLevel; ++ } ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfACCKChnl1TxPwLevel[0] = 0x%x\n", priv->EEPROMRfACCKChnl1TxPwLevel[0]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfACCKChnl1TxPwLevel[1] = 0x%x\n", priv->EEPROMRfACCKChnl1TxPwLevel[1]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfACCKChnl1TxPwLevel[2] = 0x%x\n", priv->EEPROMRfACCKChnl1TxPwLevel[2]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfAOfdmChnlTxPwLevel[0] = 0x%x\n", priv->EEPROMRfAOfdmChnlTxPwLevel[0]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfAOfdmChnlTxPwLevel[1] = 0x%x\n", priv->EEPROMRfAOfdmChnlTxPwLevel[1]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfAOfdmChnlTxPwLevel[2] = 0x%x\n", priv->EEPROMRfAOfdmChnlTxPwLevel[2]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfCCCKChnl1TxPwLevel[0] = 0x%x\n", priv->EEPROMRfCCCKChnl1TxPwLevel[0]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfCCCKChnl1TxPwLevel[1] = 0x%x\n", priv->EEPROMRfCCCKChnl1TxPwLevel[1]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfCCCKChnl1TxPwLevel[2] = 0x%x\n", priv->EEPROMRfCCCKChnl1TxPwLevel[2]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfCOfdmChnlTxPwLevel[0] = 0x%x\n", priv->EEPROMRfCOfdmChnlTxPwLevel[0]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfCOfdmChnlTxPwLevel[1] = 0x%x\n", priv->EEPROMRfCOfdmChnlTxPwLevel[1]); ++ RT_TRACE(COMP_INIT, "priv->EEPROMRfCOfdmChnlTxPwLevel[2] = 0x%x\n", priv->EEPROMRfCOfdmChnlTxPwLevel[2]); ++#endif ++ ++ } ++ // ++ // Update HAL variables. ++ // ++ if(priv->epromtype == EPROM_93c46) ++ { ++ for(i=0; i<14; i++) ++ { ++ priv->TxPowerLevelCCK[i] = priv->EEPROMTxPowerLevelCCK[i]; ++ priv->TxPowerLevelOFDM24G[i] = priv->EEPROMTxPowerLevelOFDM24G[i]; ++ } ++ priv->LegacyHTTxPowerDiff = priv->EEPROMLegacyHTTxPowerDiff; ++ // Antenna B gain offset to antenna A, bit0~3 ++ priv->AntennaTxPwDiff[0] = (priv->EEPROMAntPwDiff & 0xf); ++ // Antenna C gain offset to antenna A, bit4~7 ++ priv->AntennaTxPwDiff[1] = ((priv->EEPROMAntPwDiff & 0xf0)>>4); ++ // Antenna D gain offset to antenna A, bit8~11 ++ priv->AntennaTxPwDiff[2] = ((priv->EEPROMAntPwDiff & 0xf00)>>8); ++ // CrystalCap, bit12~15 ++ priv->CrystalCap = priv->EEPROMCrystalCap; ++ // ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 ++ priv->ThermalMeter[0] = (priv->EEPROMThermalMeter & 0xf); ++ priv->ThermalMeter[1] = ((priv->EEPROMThermalMeter & 0xf0)>>4); ++ } ++ else if(priv->epromtype == EPROM_93c56) ++ { ++ //char cck_pwr_diff_a=0, cck_pwr_diff_c=0; ++ ++ //cck_pwr_diff_a = pHalData->EEPROMRfACCKChnl7TxPwLevel - pHalData->EEPROMRfAOfdmChnlTxPwLevel[1]; ++ //cck_pwr_diff_c = pHalData->EEPROMRfCCCKChnl7TxPwLevel - pHalData->EEPROMRfCOfdmChnlTxPwLevel[1]; ++ for(i=0; i<3; i++) // channel 1~3 use the same Tx Power Level. ++ { ++ priv->TxPowerLevelCCK_A[i] = priv->EEPROMRfACCKChnl1TxPwLevel[0]; ++ priv->TxPowerLevelOFDM24G_A[i] = priv->EEPROMRfAOfdmChnlTxPwLevel[0]; ++ priv->TxPowerLevelCCK_C[i] = priv->EEPROMRfCCCKChnl1TxPwLevel[0]; ++ priv->TxPowerLevelOFDM24G_C[i] = priv->EEPROMRfCOfdmChnlTxPwLevel[0]; ++ } ++ for(i=3; i<9; i++) // channel 4~9 use the same Tx Power Level ++ { ++ priv->TxPowerLevelCCK_A[i] = priv->EEPROMRfACCKChnl1TxPwLevel[1]; ++ priv->TxPowerLevelOFDM24G_A[i] = priv->EEPROMRfAOfdmChnlTxPwLevel[1]; ++ priv->TxPowerLevelCCK_C[i] = priv->EEPROMRfCCCKChnl1TxPwLevel[1]; ++ priv->TxPowerLevelOFDM24G_C[i] = priv->EEPROMRfCOfdmChnlTxPwLevel[1]; ++ } ++ for(i=9; i<14; i++) // channel 10~14 use the same Tx Power Level ++ { ++ priv->TxPowerLevelCCK_A[i] = priv->EEPROMRfACCKChnl1TxPwLevel[2]; ++ priv->TxPowerLevelOFDM24G_A[i] = priv->EEPROMRfAOfdmChnlTxPwLevel[2]; ++ priv->TxPowerLevelCCK_C[i] = priv->EEPROMRfCCCKChnl1TxPwLevel[2]; ++ priv->TxPowerLevelOFDM24G_C[i] = priv->EEPROMRfCOfdmChnlTxPwLevel[2]; ++ } ++ for(i=0; i<14; i++) ++ RT_TRACE(COMP_INIT, "priv->TxPowerLevelCCK_A[%d] = 0x%x\n", i, priv->TxPowerLevelCCK_A[i]); ++ for(i=0; i<14; i++) ++ RT_TRACE(COMP_INIT,"priv->TxPowerLevelOFDM24G_A[%d] = 0x%x\n", i, priv->TxPowerLevelOFDM24G_A[i]); ++ for(i=0; i<14; i++) ++ RT_TRACE(COMP_INIT, "priv->TxPowerLevelCCK_C[%d] = 0x%x\n", i, priv->TxPowerLevelCCK_C[i]); ++ for(i=0; i<14; i++) ++ RT_TRACE(COMP_INIT, "priv->TxPowerLevelOFDM24G_C[%d] = 0x%x\n", i, priv->TxPowerLevelOFDM24G_C[i]); ++ priv->LegacyHTTxPowerDiff = priv->EEPROMLegacyHTTxPowerDiff; ++ priv->AntennaTxPwDiff[0] = 0; ++ priv->AntennaTxPwDiff[1] = 0; ++ priv->AntennaTxPwDiff[2] = 0; ++ priv->CrystalCap = priv->EEPROMCrystalCap; ++ // ThermalMeter, bit0~3 for RFIC1, bit4~7 for RFIC2 ++ priv->ThermalMeter[0] = (priv->EEPROMThermalMeter & 0xf); ++ priv->ThermalMeter[1] = ((priv->EEPROMThermalMeter & 0xf0)>>4); ++ } ++ } ++ ++ if(priv->rf_type == RF_1T2R) ++ { ++ RT_TRACE(COMP_INIT, "\n1T2R config\n"); ++ } ++ else if (priv->rf_type == RF_2T4R) ++ { ++ RT_TRACE(COMP_INIT, "\n2T4R config\n"); ++ } ++ ++ // 2008/01/16 MH We can only know RF type in the function. So we have to init ++ // DIG RATR table again. ++ init_rate_adaptive(dev); ++ ++ //1 Make a copy for following variables and we can change them if we want ++ ++ priv->rf_chip= RF_8256; ++ ++ if(priv->RegChannelPlan == 0xf) ++ { ++ priv->ChannelPlan = priv->eeprom_ChannelPlan; ++ } ++ else ++ { ++ priv->ChannelPlan = priv->RegChannelPlan; ++ } ++ ++ // ++ // Used PID and DID to Set CustomerID ++ // ++ if( priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304 ) ++ { ++ priv->CustomerID = RT_CID_DLINK; ++ } ++ ++ switch(priv->eeprom_CustomerID) ++ { ++ case EEPROM_CID_DEFAULT: ++ priv->CustomerID = RT_CID_DEFAULT; ++ break; ++ case EEPROM_CID_CAMEO: ++ priv->CustomerID = RT_CID_819x_CAMEO; ++ break; ++ case EEPROM_CID_RUNTOP: ++ priv->CustomerID = RT_CID_819x_RUNTOP; ++ break; ++ case EEPROM_CID_NetCore: ++ priv->CustomerID = RT_CID_819x_Netcore; ++ break; ++ case EEPROM_CID_TOSHIBA: // Merge by Jacken, 2008/01/31 ++ priv->CustomerID = RT_CID_TOSHIBA; ++ if(priv->eeprom_ChannelPlan&0x80) ++ priv->ChannelPlan = priv->eeprom_ChannelPlan&0x7f; ++ else ++ priv->ChannelPlan = 0x0; ++ RT_TRACE(COMP_INIT, "Toshiba ChannelPlan = 0x%x\n", ++ priv->ChannelPlan); ++ break; ++ case EEPROM_CID_Nettronix: ++ priv->ScanDelay = 100; //cosa add for scan ++ priv->CustomerID = RT_CID_Nettronix; ++ break; ++ case EEPROM_CID_Pronet: ++ priv->CustomerID = RT_CID_PRONET; ++ break; ++ case EEPROM_CID_DLINK: ++ priv->CustomerID = RT_CID_DLINK; ++ break; ++ ++ case EEPROM_CID_WHQL: ++ //Adapter->bInHctTest = TRUE;//do not supported ++ ++ //priv->bSupportTurboMode = FALSE; ++ //priv->bAutoTurboBy8186 = FALSE; ++ ++ //pMgntInfo->PowerSaveControl.bInactivePs = FALSE; ++ //pMgntInfo->PowerSaveControl.bIPSModeBackup = FALSE; ++ //pMgntInfo->PowerSaveControl.bLeisurePs = FALSE; ++ ++ break; ++ default: ++ // value from RegCustomerID ++ break; ++ } ++ ++ //Avoid the channel plan array overflow, by Bruce, 2007-08-27. ++ if(priv->ChannelPlan > CHANNEL_PLAN_LEN - 1) ++ priv->ChannelPlan = 0; //FCC ++ ++ switch(priv->CustomerID) ++ { ++ case RT_CID_DEFAULT: ++ #ifdef RTL8190P ++ priv->LedStrategy = HW_LED; ++ #else ++ #ifdef RTL8192E ++ priv->LedStrategy = SW_LED_MODE1; ++ #endif ++ #endif ++ break; ++ ++ case RT_CID_819x_CAMEO: ++ priv->LedStrategy = SW_LED_MODE2; ++ break; ++ ++ case RT_CID_819x_RUNTOP: ++ priv->LedStrategy = SW_LED_MODE3; ++ break; ++ ++ case RT_CID_819x_Netcore: ++ priv->LedStrategy = SW_LED_MODE4; ++ break; ++ ++ case RT_CID_Nettronix: ++ priv->LedStrategy = SW_LED_MODE5; ++ break; ++ ++ case RT_CID_PRONET: ++ priv->LedStrategy = SW_LED_MODE6; ++ break; ++ ++ case RT_CID_TOSHIBA: //Modify by Jacken 2008/01/31 ++ // Do nothing. ++ //break; ++ ++ default: ++ #ifdef RTL8190P ++ priv->LedStrategy = HW_LED; ++ #else ++ #ifdef RTL8192E ++ priv->LedStrategy = SW_LED_MODE1; ++ #endif ++ #endif ++ break; ++ } ++/* ++ //2008.06.03, for WOL ++ if( priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304) ++ priv->ieee80211->bSupportRemoteWakeUp = TRUE; ++ else ++ priv->ieee80211->bSupportRemoteWakeUp = FALSE; ++*/ ++ RT_TRACE(COMP_INIT, "RegChannelPlan(%d)\n", priv->RegChannelPlan); ++ RT_TRACE(COMP_INIT, "ChannelPlan = %d \n", priv->ChannelPlan); ++ RT_TRACE(COMP_INIT, "LedStrategy = %d \n", priv->LedStrategy); ++ RT_TRACE(COMP_TRACE, "<==== ReadAdapterInfo\n"); ++ ++ return ; ++} ++ ++ ++static short rtl8192_get_channel_map(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#ifdef ENABLE_DOT11D ++ if(priv->ChannelPlan> COUNTRY_CODE_GLOBAL_DOMAIN){ ++ printk("rtl8180_init:Error channel plan! Set to default.\n"); ++ priv->ChannelPlan= 0; ++ } ++ RT_TRACE(COMP_INIT, "Channel plan is %d\n",priv->ChannelPlan); ++ ++ rtl819x_set_channel_map(priv->ChannelPlan, priv); ++#else ++ int ch,i; ++ //Set Default Channel Plan ++ if(!channels){ ++ DMESG("No channels, aborting"); ++ return -1; ++ } ++ ch=channels; ++ priv->ChannelPlan= 0;//hikaru ++ // set channels 1..14 allowed in given locale ++ for (i=1; i<=14; i++) { ++ (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); ++ ch >>= 1; ++ } ++#endif ++ return 0; ++} ++ ++static short rtl8192_init(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ memset(&(priv->stats),0,sizeof(struct Stats)); ++ rtl8192_init_priv_variable(dev); ++ rtl8192_init_priv_lock(priv); ++ rtl8192_init_priv_task(dev); ++ rtl8192_get_eeprom_size(dev); ++ rtl8192_read_eeprom_info(dev); ++ rtl8192_get_channel_map(dev); ++ init_hal_dm(dev); ++ init_timer(&priv->watch_dog_timer); ++ priv->watch_dog_timer.data = (unsigned long)dev; ++ priv->watch_dog_timer.function = watch_dog_timer_callback; ++#if defined(IRQF_SHARED) ++ if(request_irq(dev->irq, (void*)rtl8192_interrupt, IRQF_SHARED, dev->name, dev)){ ++#else ++ if(request_irq(dev->irq, (void *)rtl8192_interrupt, SA_SHIRQ, dev->name, dev)){ ++#endif ++ printk("Error allocating IRQ %d",dev->irq); ++ return -1; ++ }else{ ++ priv->irq=dev->irq; ++ printk("IRQ %d",dev->irq); ++ } ++ if(rtl8192_pci_initdescring(dev)!=0){ ++ printk("Endopoints initialization failed"); ++ return -1; ++ } ++ ++ //rtl8192_rx_enable(dev); ++ //rtl8192_adapter_start(dev); ++ return 0; ++} ++ ++/****************************************************************************** ++ *function: This function actually only set RRSR, RATR and BW_OPMODE registers ++ * not to do all the hw config as its name says ++ * input: net_device dev ++ * output: none ++ * return: none ++ * notice: This part need to modified according to the rate set we filtered ++ * ****************************************************************************/ ++static void rtl8192_hwconfig(struct net_device* dev) ++{ ++ u32 regRATR = 0, regRRSR = 0; ++ u8 regBwOpMode = 0, regTmp = 0; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++// Set RRSR, RATR, and BW_OPMODE registers ++ // ++ switch(priv->ieee80211->mode) ++ { ++ case WIRELESS_MODE_B: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK; ++ regRRSR = RATE_ALL_CCK; ++ break; ++ case WIRELESS_MODE_A: ++ regBwOpMode = BW_OPMODE_5G |BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_G: ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_AUTO: ++ case WIRELESS_MODE_N_24G: ++ // It support CCK rate by default. ++ // CCK rate will be filtered out only when associated AP does not support it. ++ regBwOpMode = BW_OPMODE_20MHZ; ++ regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; ++ break; ++ case WIRELESS_MODE_N_5G: ++ regBwOpMode = BW_OPMODE_5G; ++ regRATR = RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; ++ regRRSR = RATE_ALL_OFDM_AG; ++ break; ++ } ++ ++ write_nic_byte(dev, BW_OPMODE, regBwOpMode); ++ { ++ u32 ratr_value = 0; ++ ratr_value = regRATR; ++ if (priv->rf_type == RF_1T2R) ++ { ++ ratr_value &= ~(RATE_ALL_OFDM_2SS); ++ } ++ write_nic_dword(dev, RATR0, ratr_value); ++ write_nic_byte(dev, UFWP, 1); ++ } ++ regTmp = read_nic_byte(dev, 0x313); ++ regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); ++ write_nic_dword(dev, RRSR, regRRSR); ++ ++ // ++ // Set Retry Limit here ++ // ++ write_nic_word(dev, RETRY_LIMIT, ++ priv->ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT | \ ++ priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ // Set Contention Window here ++ ++ // Set Tx AGC ++ ++ // Set Tx Antenna including Feedback control ++ ++ // Set Auto Rate fallback control ++ ++ ++} ++ ++ ++static RT_STATUS rtl8192_adapter_start(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++// struct ieee80211_device *ieee = priv->ieee80211; ++ u32 ulRegRead; ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++// static char szMACPHYRegFile[] = RTL819X_PHY_MACPHY_REG; ++// static char szMACPHYRegPGFile[] = RTL819X_PHY_MACPHY_REG_PG; ++ //u8 eRFPath; ++ u8 tmpvalue; ++#ifdef RTL8192E ++ u8 ICVersion,SwitchingRegulatorOutput; ++#endif ++ bool bfirmwareok = true; ++#ifdef RTL8190P ++ u8 ucRegRead; ++#endif ++ u32 tmpRegA, tmpRegC, TempCCk; ++ int i =0; ++// u32 dwRegRead = 0; ++ ++ RT_TRACE(COMP_INIT, "====>%s()\n", __FUNCTION__); ++ priv->being_init_adapter = true; ++ rtl8192_pci_resetdescring(dev); ++ // 2007/11/02 MH Before initalizing RF. We can not use FW to do RF-R/W. ++ priv->Rf_Mode = RF_OP_By_SW_3wire; ++#ifdef RTL8192E ++ //dPLL on ++ if(priv->ResetProgress == RESET_TYPE_NORESET) ++ { ++ write_nic_byte(dev, ANAPAR, 0x37); ++ // Accordign to designer's explain, LBUS active will never > 10ms. We delay 10ms ++ // Joseph increae the time to prevent firmware download fail ++ mdelay(500); ++ } ++#endif ++ //PlatformSleepUs(10000); ++ // For any kind of InitializeAdapter process, we shall use system now!! ++ priv->pFirmware->firmware_status = FW_STATUS_0_INIT; ++ ++ // Set to eRfoff in order not to count receive count. ++ if(priv->RegRfOff == TRUE) ++ priv->ieee80211->eRFPowerState = eRfOff; ++ ++ // ++ //3 //Config CPUReset Register ++ //3// ++ //3 Firmware Reset Or Not ++ ulRegRead = read_nic_dword(dev, CPU_GEN); ++ if(priv->pFirmware->firmware_status == FW_STATUS_0_INIT) ++ { //called from MPInitialized. do nothing ++ ulRegRead |= CPU_GEN_SYSTEM_RESET; ++ }else if(priv->pFirmware->firmware_status == FW_STATUS_5_READY) ++ ulRegRead |= CPU_GEN_FIRMWARE_RESET; // Called from MPReset ++ else ++ RT_TRACE(COMP_ERR, "ERROR in %s(): undefined firmware state(%d)\n", __FUNCTION__, priv->pFirmware->firmware_status); ++ ++#ifdef RTL8190P ++ //2008.06.03, for WOL 90 hw bug ++ ulRegRead &= (~(CPU_GEN_GPIO_UART)); ++#endif ++ ++ write_nic_dword(dev, CPU_GEN, ulRegRead); ++ //mdelay(100); ++ ++#ifdef RTL8192E ++ ++ //3// ++ //3 //Fix the issue of E-cut high temperature issue ++ //3// ++ // TODO: E cut only ++ ICVersion = read_nic_byte(dev, IC_VERRSION); ++ if(ICVersion >= 0x4) //E-cut only ++ { ++ // HW SD suggest that we should not wirte this register too often, so driver ++ // should readback this register. This register will be modified only when ++ // power on reset ++ SwitchingRegulatorOutput = read_nic_byte(dev, SWREGULATOR); ++ if(SwitchingRegulatorOutput != 0xb8) ++ { ++ write_nic_byte(dev, SWREGULATOR, 0xa8); ++ mdelay(1); ++ write_nic_byte(dev, SWREGULATOR, 0xb8); ++ } ++ } ++#endif ++ ++ ++ //3// ++ //3// Initialize BB before MAC ++ //3// ++ RT_TRACE(COMP_INIT, "BB Config Start!\n"); ++ rtStatus = rtl8192_BBConfig(dev); ++ if(rtStatus != RT_STATUS_SUCCESS) ++ { ++ RT_TRACE(COMP_ERR, "BB Config failed\n"); ++ return rtStatus; ++ } ++ RT_TRACE(COMP_INIT,"BB Config Finished!\n"); ++ ++ //3//Set Loopback mode or Normal mode ++ //3// ++ //2006.12.13 by emily. Note!We should not merge these two CPU_GEN register writings ++ // because setting of System_Reset bit reset MAC to default transmission mode. ++ //Loopback mode or not ++ priv->LoopbackMode = RTL819X_NO_LOOPBACK; ++ //priv->LoopbackMode = RTL819X_MAC_LOOPBACK; ++ if(priv->ResetProgress == RESET_TYPE_NORESET) ++ { ++ ulRegRead = read_nic_dword(dev, CPU_GEN); ++ if(priv->LoopbackMode == RTL819X_NO_LOOPBACK) ++ { ++ ulRegRead = ((ulRegRead & CPU_GEN_NO_LOOPBACK_MSK) | CPU_GEN_NO_LOOPBACK_SET); ++ } ++ else if (priv->LoopbackMode == RTL819X_MAC_LOOPBACK ) ++ { ++ ulRegRead |= CPU_CCK_LOOPBACK; ++ } ++ else ++ { ++ RT_TRACE(COMP_ERR,"Serious error: wrong loopback mode setting\n"); ++ } ++ ++ //2008.06.03, for WOL ++ //ulRegRead &= (~(CPU_GEN_GPIO_UART)); ++ write_nic_dword(dev, CPU_GEN, ulRegRead); ++ ++ // 2006.11.29. After reset cpu, we sholud wait for a second, otherwise, it may fail to write registers. Emily ++ udelay(500); ++ } ++ //3Set Hardware(Do nothing now) ++ rtl8192_hwconfig(dev); ++ //2======================================================= ++ // Common Setting for all of the FPGA platform. (part 1) ++ //2======================================================= ++ // If there is changes, please make sure it applies to all of the FPGA version ++ //3 Turn on Tx/Rx ++ write_nic_byte(dev, CMDR, CR_RE|CR_TE); ++ ++ //2Set Tx dma burst ++#ifdef RTL8190P ++ write_nic_byte(dev, PCIF, ((MXDMA2_NoLimit<dev_addr)[0]); ++ write_nic_word(dev, MAC4, ((u16*)(dev->dev_addr + 4))[0]); ++ //set RCR ++ write_nic_dword(dev, RCR, priv->ReceiveConfig); ++ ++ //3 Initialize Number of Reserved Pages in Firmware Queue ++ #ifdef TO_DO_LIST ++ if(priv->bInHctTest) ++ { ++ PlatformEFIOWrite4Byte(Adapter, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM << RSVD_FW_QUEUE_PAGE_BK_SHIFT |\ ++ NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM << RSVD_FW_QUEUE_PAGE_BE_SHIFT | \ ++ NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM << RSVD_FW_QUEUE_PAGE_VI_SHIFT | \ ++ NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM <RegWirelessMode); ++ if(priv->ResetProgress == RESET_TYPE_NORESET) ++ rtl8192_SetWirelessMode(dev, priv->ieee80211->mode); ++ //----------------------------------------------------------------------------- ++ // Set up security related. 070106, by rcnjko: ++ // 1. Clear all H/W keys. ++ // 2. Enable H/W encryption/decryption. ++ //----------------------------------------------------------------------------- ++ CamResetAllEntry(dev); ++ { ++ u8 SECR_value = 0x0; ++ SECR_value |= SCR_TxEncEnable; ++ SECR_value |= SCR_RxDecEnable; ++ SECR_value |= SCR_NoSKMC; ++ write_nic_byte(dev, SECR, SECR_value); ++ } ++ //3Beacon related ++ write_nic_word(dev, ATIMWND, 2); ++ write_nic_word(dev, BCN_INTERVAL, 100); ++ for (i=0; icard_8192_version > (u8) VERSION_8190_BD) { ++ rtl8192_phy_getTxPower(dev); ++ rtl8192_phy_setTxPower(dev, priv->chan); ++ } ++ ++ //if D or C cut ++ tmpvalue = read_nic_byte(dev, IC_VERRSION); ++ priv->IC_Cut = tmpvalue; ++ RT_TRACE(COMP_INIT, "priv->IC_Cut = 0x%x\n", priv->IC_Cut); ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ { ++ //pHalData->bDcut = TRUE; ++ if(priv->IC_Cut == IC_VersionCut_D) ++ RT_TRACE(COMP_INIT, "D-cut\n"); ++ if(priv->IC_Cut == IC_VersionCut_E) ++ { ++ RT_TRACE(COMP_INIT, "E-cut\n"); ++ // HW SD suggest that we should not wirte this register too often, so driver ++ // should readback this register. This register will be modified only when ++ // power on reset ++ } ++ } ++ else ++ { ++ //pHalData->bDcut = FALSE; ++ RT_TRACE(COMP_INIT, "Before C-cut\n"); ++ } ++ ++#if 1 ++ //Firmware download ++ RT_TRACE(COMP_INIT, "Load Firmware!\n"); ++ bfirmwareok = init_firmware(dev); ++ if(bfirmwareok != true) { ++ rtStatus = RT_STATUS_FAILURE; ++ return rtStatus; ++ } ++ RT_TRACE(COMP_INIT, "Load Firmware finished!\n"); ++#endif ++ //RF config ++ if(priv->ResetProgress == RESET_TYPE_NORESET) ++ { ++ RT_TRACE(COMP_INIT, "RF Config Started!\n"); ++ rtStatus = rtl8192_phy_RFConfig(dev); ++ if(rtStatus != RT_STATUS_SUCCESS) ++ { ++ RT_TRACE(COMP_ERR, "RF Config failed\n"); ++ return rtStatus; ++ } ++ RT_TRACE(COMP_INIT, "RF Config Finished!\n"); ++ } ++ rtl8192_phy_updateInitGain(dev); ++ ++ /*---- Set CCK and OFDM Block "ON"----*/ ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); ++ ++#ifdef RTL8192E ++ //Enable Led ++ write_nic_byte(dev, 0x87, 0x0); ++#endif ++#ifdef RTL8190P ++ //2008.06.03, for WOL ++ ucRegRead = read_nic_byte(dev, GPE); ++ ucRegRead |= BIT0; ++ write_nic_byte(dev, GPE, ucRegRead); ++ ++ ucRegRead = read_nic_byte(dev, GPO); ++ ucRegRead &= ~BIT0; ++ write_nic_byte(dev, GPO, ucRegRead); ++#endif ++ ++ //2======================================================= ++ // RF Power Save ++ //2======================================================= ++#ifdef ENABLE_IPS ++ ++{ ++ if(priv->RegRfOff == TRUE) ++ { // User disable RF via registry. ++ RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RegRfOff ----------\n",__FUNCTION__); ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_SW); ++#if 0//cosa, ask SD3 willis and he doesn't know what is this for ++ // Those action will be discard in MgntActSet_RF_State because off the same state ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0); ++#endif ++ } ++ else if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_PS) ++ { // H/W or S/W RF OFF before sleep. ++ RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RfOffReason(%d) ----------\n", __FUNCTION__,priv->ieee80211->RfOffReason); ++ MgntActSet_RF_State(dev, eRfOff, priv->ieee80211->RfOffReason); ++ } ++ else if(priv->ieee80211->RfOffReason >= RF_CHANGE_BY_IPS) ++ { // H/W or S/W RF OFF before sleep. ++ RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RfOffReason(%d) ----------\n", __FUNCTION__,priv->ieee80211->RfOffReason); ++ MgntActSet_RF_State(dev, eRfOff, priv->ieee80211->RfOffReason); ++ } ++ else ++ { ++ RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): RF-ON \n",__FUNCTION__); ++ priv->ieee80211->eRFPowerState = eRfOn; ++ priv->ieee80211->RfOffReason = 0; ++ //DrvIFIndicateCurrentPhyStatus(Adapter); ++ // LED control ++ //Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_ON); ++ ++ // ++ // If inactive power mode is enabled, disable rf while in disconnected state. ++ // But we should still tell upper layer we are in rf on state. ++ // 2007.07.16, by shien chang. ++ // ++ //if(!Adapter->bInHctTest) ++ //IPSEnter(Adapter); ++ ++ } ++} ++#endif ++ if(1){ ++#ifdef RTL8192E ++ // We can force firmware to do RF-R/W ++ if(priv->ieee80211->FwRWRF) ++ priv->Rf_Mode = RF_OP_By_FW; ++ else ++ priv->Rf_Mode = RF_OP_By_SW_3wire; ++#else ++ priv->Rf_Mode = RF_OP_By_SW_3wire; ++#endif ++ } ++#ifdef RTL8190P ++ if(priv->ResetProgress == RESET_TYPE_NORESET) ++ { ++ dm_initialize_txpower_tracking(dev); ++ ++ tmpRegA= rtl8192_QueryBBReg(dev,rOFDM0_XATxIQImbalance,bMaskDWord); ++ tmpRegC= rtl8192_QueryBBReg(dev,rOFDM0_XCTxIQImbalance,bMaskDWord); ++ ++ if(priv->rf_type == RF_2T4R){ ++ for(i = 0; itxbbgain_table[i].txbbgain_value) ++ { ++ priv->rfa_txpowertrackingindex= (u8)i; ++ priv->rfa_txpowertrackingindex_real= (u8)i; ++ priv->rfa_txpowertracking_default = priv->rfa_txpowertrackingindex; ++ break; ++ } ++ } ++ } ++ for(i = 0; itxbbgain_table[i].txbbgain_value) ++ { ++ priv->rfc_txpowertrackingindex= (u8)i; ++ priv->rfc_txpowertrackingindex_real= (u8)i; ++ priv->rfc_txpowertracking_default = priv->rfc_txpowertrackingindex; ++ break; ++ } ++ } ++ TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); ++ ++ for(i=0 ; icck_txbbgain_table[i].ccktxbb_valuearray[0]) ++ { ++ priv->CCKPresentAttentuation_20Mdefault =(u8) i; ++ break; ++ } ++ } ++ priv->CCKPresentAttentuation_40Mdefault = 0; ++ priv->CCKPresentAttentuation_difference = 0; ++ priv->CCKPresentAttentuation = priv->CCKPresentAttentuation_20Mdefault; ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_initial = %d\n", priv->rfa_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real__initial = %d\n", priv->rfa_txpowertrackingindex_real); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_initial = %d\n", priv->rfc_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real_initial = %d\n", priv->rfc_txpowertrackingindex_real); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_difference_initial = %d\n", priv->CCKPresentAttentuation_difference); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_initial = %d\n", priv->CCKPresentAttentuation); ++ } ++#else ++ #ifdef RTL8192E ++ if(priv->ResetProgress == RESET_TYPE_NORESET) ++ { ++ dm_initialize_txpower_tracking(dev); ++ ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ { ++ tmpRegA= rtl8192_QueryBBReg(dev,rOFDM0_XATxIQImbalance,bMaskDWord); ++ tmpRegC= rtl8192_QueryBBReg(dev,rOFDM0_XCTxIQImbalance,bMaskDWord); ++ for(i = 0; itxbbgain_table[i].txbbgain_value) ++ { ++ priv->rfa_txpowertrackingindex= (u8)i; ++ priv->rfa_txpowertrackingindex_real= (u8)i; ++ priv->rfa_txpowertracking_default = priv->rfa_txpowertrackingindex; ++ break; ++ } ++ } ++ ++ TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); ++ ++ for(i=0 ; icck_txbbgain_table[i].ccktxbb_valuearray[0]) ++ { ++ priv->CCKPresentAttentuation_20Mdefault =(u8) i; ++ break; ++ } ++ } ++ priv->CCKPresentAttentuation_40Mdefault = 0; ++ priv->CCKPresentAttentuation_difference = 0; ++ priv->CCKPresentAttentuation = priv->CCKPresentAttentuation_20Mdefault; ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_initial = %d\n", priv->rfa_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real__initial = %d\n", priv->rfa_txpowertrackingindex_real); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_difference_initial = %d\n", priv->CCKPresentAttentuation_difference); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_initial = %d\n", priv->CCKPresentAttentuation); ++ priv->btxpower_tracking = FALSE;//TEMPLY DISABLE ++ } ++ } ++ #endif ++#endif ++ rtl8192_irq_enable(dev); ++ priv->being_init_adapter = false; ++ return rtStatus; ++ ++} ++ ++void rtl8192_prepare_beacon(struct r8192_priv *priv) ++{ ++ struct sk_buff *skb; ++ //unsigned long flags; ++ cb_desc *tcb_desc; ++ ++ skb = ieee80211_get_beacon(priv->ieee80211); ++ tcb_desc = (cb_desc *)(skb->cb + 8); ++ //printk("===========> %s\n", __FUNCTION__); ++ //spin_lock_irqsave(&priv->tx_lock,flags); ++ /* prepare misc info for the beacon xmit */ ++ tcb_desc->queue_index = BEACON_QUEUE; ++ /* IBSS does not support HT yet, use 1M defautly */ ++ tcb_desc->data_rate = 2; ++ tcb_desc->RATRIndex = 7; ++ tcb_desc->bTxDisableRateFallBack = 1; ++ tcb_desc->bTxUseDriverAssingedRate = 1; ++ ++ skb_push(skb, priv->ieee80211->tx_headroom); ++ if(skb){ ++ rtl8192_tx(priv->ieee80211->dev,skb); ++ } ++ //spin_unlock_irqrestore (&priv->tx_lock, flags); ++} ++ ++#if 0 ++void rtl8192_beacon_tx_enable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++#ifdef CONFIG_RTL8185B ++ priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ);MgntQuery_MgntFrameTxRateMgntQuery_MgntFrameTxRate ++ write_nic_byte(dev,TPPollStop, priv->dma_poll_mask); ++#else ++ priv->dma_poll_mask &=~(1<dma_poll_mask); ++#endif ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++#endif ++ ++ ++/* this configures registers for beacon tx and enables it via ++ * rtl8192_beacon_tx_enable(). rtl8192_beacon_tx_disable() might ++ * be used to stop beacon transmission ++ */ ++void rtl8192_start_beacon(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ struct ieee80211_network *net = &priv->ieee80211->current_network; ++ u16 BcnTimeCfg = 0; ++ u16 BcnCW = 6; ++ u16 BcnIFS = 0xf; ++ ++ DMESG("Enabling beacon TX"); ++ //rtl8192_prepare_beacon(dev); ++ rtl8192_irq_disable(dev); ++ //rtl8192_beacon_tx_enable(dev); ++ ++ /* ATIM window */ ++ write_nic_word(dev, ATIMWND, 2); ++ ++ /* Beacon interval (in unit of TU) */ ++ write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); ++ ++ /* ++ * DrvErlyInt (in unit of TU). ++ * (Time to send interrupt to notify driver to c ++ * hange beacon content) ++ * */ ++ write_nic_word(dev, BCN_DRV_EARLY_INT, 10); ++ ++ /* ++ * BcnDMATIM(in unit of us). ++ * Indicates the time before TBTT to perform beacon queue DMA ++ * */ ++ write_nic_word(dev, BCN_DMATIME, 256); ++ ++ /* ++ * Force beacon frame transmission even after receiving ++ * beacon frame from other ad hoc STA ++ * */ ++ write_nic_byte(dev, BCN_ERR_THRESH, 100); ++ ++ /* Set CW and IFS */ ++ BcnTimeCfg |= BcnCW<ieee80211->stats; ++} ++#endif ++ ++ ++ ++static bool HalTxCheckStuck8190Pci(struct net_device *dev) ++{ ++ u16 RegTxCounter = read_nic_word(dev, 0x128); ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ bool bStuck = FALSE; ++ RT_TRACE(COMP_RESET,"%s():RegTxCounter is %d,TxCounter is %d\n",__FUNCTION__,RegTxCounter,priv->TxCounter); ++ if(priv->TxCounter==RegTxCounter) ++ bStuck = TRUE; ++ ++ priv->TxCounter = RegTxCounter; ++ ++ return bStuck; ++} ++ ++/* ++* ++* First added: 2006.11.19 by emily ++*/ ++static RESET_TYPE ++TxCheckStuck(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 QueueID; ++ ptx_ring head=NULL,tail=NULL,txring = NULL; ++ u8 ResetThreshold = NIC_SEND_HANG_THRESHOLD_POWERSAVE; ++ bool bCheckFwTxCnt = false; ++ //unsigned long flags; ++ ++ // ++ // Decide Stuch threshold according to current power save mode ++ // ++ //printk("++++++++++++>%s()\n",__FUNCTION__); ++ switch (priv->ieee80211->dot11PowerSaveMode) ++ { ++ // The threshold value may required to be adjusted . ++ case eActive: // Active/Continuous access. ++ ResetThreshold = NIC_SEND_HANG_THRESHOLD_NORMAL; ++ break; ++ case eMaxPs: // Max power save mode. ++ ResetThreshold = NIC_SEND_HANG_THRESHOLD_POWERSAVE; ++ break; ++ case eFastPs: // Fast power save mode. ++ ResetThreshold = NIC_SEND_HANG_THRESHOLD_POWERSAVE; ++ break; ++ } ++ ++ // ++ // Check whether specific tcb has been queued for a specific time ++ // ++ for(QueueID = 0; QueueID < MAX_TX_QUEUE; QueueID++) ++ { ++ ++ ++ if(QueueID == TXCMD_QUEUE) ++ continue; ++ ++ switch(QueueID) { ++ case MGNT_QUEUE: ++ tail=priv->txmapringtail; ++ head=priv->txmapringhead; ++ break; ++ ++ case BK_QUEUE: ++ tail=priv->txbkpringtail; ++ head=priv->txbkpringhead; ++ break; ++ ++ case BE_QUEUE: ++ tail=priv->txbepringtail; ++ head=priv->txbepringhead; ++ break; ++ ++ case VI_QUEUE: ++ tail=priv->txvipringtail; ++ head=priv->txvipringhead; ++ break; ++ ++ case VO_QUEUE: ++ tail=priv->txvopringtail; ++ head=priv->txvopringhead; ++ break; ++ ++ default: ++ tail=head=NULL; ++ break; ++ } ++ ++ if(tail == head) ++ continue; ++ else ++ { ++ txring = head; ++ if(txring == NULL) ++ { ++ RT_TRACE(COMP_ERR,"%s():txring is NULL , BUG!\n",__FUNCTION__); ++ continue; ++ } ++ txring->nStuckCount++; ++ #if 0 ++ if(txring->nStuckCount > ResetThreshold) ++ { ++ RT_TRACE( COMP_RESET, "<== TxCheckStuck()\n" ); ++ return RESET_TYPE_NORMAL; ++ } ++ #endif ++ bCheckFwTxCnt = TRUE; ++ } ++ } ++#if 1 ++ if(bCheckFwTxCnt) ++ { ++ if(HalTxCheckStuck8190Pci(dev)) ++ { ++ RT_TRACE(COMP_RESET, "TxCheckStuck(): Fw indicates no Tx condition! \n"); ++ return RESET_TYPE_SILENT; ++ } ++ } ++#endif ++ return RESET_TYPE_NORESET; ++} ++ ++ ++static bool HalRxCheckStuck8190Pci(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u16 RegRxCounter = read_nic_word(dev, 0x130); ++ bool bStuck = FALSE; ++ static u8 rx_chk_cnt = 0; ++ RT_TRACE(COMP_RESET,"%s(): RegRxCounter is %d,RxCounter is %d\n",__FUNCTION__,RegRxCounter,priv->RxCounter); ++ // If rssi is small, we should check rx for long time because of bad rx. ++ // or maybe it will continuous silent reset every 2 seconds. ++ rx_chk_cnt++; ++ if(priv->undecorated_smoothed_pwdb >= (RateAdaptiveTH_High+5)) ++ { ++ rx_chk_cnt = 0; //high rssi, check rx stuck right now. ++ } ++ else if(priv->undecorated_smoothed_pwdb < (RateAdaptiveTH_High+5) && ++ ((priv->CurrentChannelBW!=HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdb>=RateAdaptiveTH_Low_40M) || ++ (priv->CurrentChannelBW==HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdb>=RateAdaptiveTH_Low_20M)) ) ++ ++ { ++ if(rx_chk_cnt < 2) ++ { ++ return bStuck; ++ } ++ else ++ { ++ rx_chk_cnt = 0; ++ } ++ } ++ else if(((priv->CurrentChannelBW!=HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdbCurrentChannelBW==HT_CHANNEL_WIDTH_20&&priv->undecorated_smoothed_pwdbundecorated_smoothed_pwdb >= VeryLowRSSI) ++ { ++ if(rx_chk_cnt < 4) ++ { ++ //DbgPrint("RSSI < %d && RSSI >= %d, no check this time \n", RateAdaptiveTH_Low, VeryLowRSSI); ++ return bStuck; ++ } ++ else ++ { ++ rx_chk_cnt = 0; ++ //DbgPrint("RSSI < %d && RSSI >= %d, check this time \n", RateAdaptiveTH_Low, VeryLowRSSI); ++ } ++ } ++ else ++ { ++ if(rx_chk_cnt < 8) ++ { ++ //DbgPrint("RSSI <= %d, no check this time \n", VeryLowRSSI); ++ return bStuck; ++ } ++ else ++ { ++ rx_chk_cnt = 0; ++ //DbgPrint("RSSI <= %d, check this time \n", VeryLowRSSI); ++ } ++ } ++#if 0 ++ if (rx_chk_cnt < 2) ++ return bStuck; ++ else ++ rx_chk_cnt = 0; ++#endif ++ if(priv->RxCounter==RegRxCounter) ++ bStuck = TRUE; ++ ++ priv->RxCounter = RegRxCounter; ++ ++ return bStuck; ++} ++ ++static RESET_TYPE RxCheckStuck(struct net_device *dev) ++{ ++ ++ if(HalRxCheckStuck8190Pci(dev)) ++ { ++ RT_TRACE(COMP_RESET, "RxStuck Condition\n"); ++ return RESET_TYPE_SILENT; ++ } ++ ++ return RESET_TYPE_NORESET; ++} ++ ++static RESET_TYPE ++rtl819x_ifcheck_resetornot(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RESET_TYPE TxResetType = RESET_TYPE_NORESET; ++ RESET_TYPE RxResetType = RESET_TYPE_NORESET; ++ RT_RF_POWER_STATE rfState; ++ ++ rfState = priv->ieee80211->eRFPowerState; ++ ++ TxResetType = TxCheckStuck(dev); ++#if 1 ++ if( rfState != eRfOff && ++ /*ADAPTER_TEST_STATUS_FLAG(Adapter, ADAPTER_STATUS_FW_DOWNLOAD_FAILURE)) &&*/ ++ (priv->ieee80211->iw_mode != IW_MODE_ADHOC)) ++ { ++ // If driver is in the status of firmware download failure , driver skips RF initialization and RF is ++ // in turned off state. Driver should check whether Rx stuck and do silent reset. And ++ // if driver is in firmware download failure status, driver should initialize RF in the following ++ // silent reset procedure Emily, 2008.01.21 ++ ++ // Driver should not check RX stuck in IBSS mode because it is required to ++ // set Check BSSID in order to send beacon, however, if check BSSID is ++ // set, STA cannot hear any packet a all. Emily, 2008.04.12 ++ RxResetType = RxCheckStuck(dev); ++ } ++#endif ++ ++ RT_TRACE(COMP_RESET,"%s(): TxResetType is %d, RxResetType is %d\n",__FUNCTION__,TxResetType,RxResetType); ++ if(TxResetType==RESET_TYPE_NORMAL || RxResetType==RESET_TYPE_NORMAL) ++ return RESET_TYPE_NORMAL; ++ else if(TxResetType==RESET_TYPE_SILENT || RxResetType==RESET_TYPE_SILENT) ++ return RESET_TYPE_SILENT; ++ else ++ return RESET_TYPE_NORESET; ++ ++} ++ ++ ++static void CamRestoreAllEntry(struct net_device *dev) ++{ ++ u8 EntryId = 0; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8* MacAddr = priv->ieee80211->current_network.bssid; ++ ++ static u8 CAM_CONST_ADDR[4][6] = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}; ++ static u8 CAM_CONST_BROAD[] = ++ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ RT_TRACE(COMP_SEC, "CamRestoreAllEntry: \n"); ++ ++ ++ if ((priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP40)|| ++ (priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP104)) ++ { ++ ++ for(EntryId=0; EntryId<4; EntryId++) ++ { ++ { ++ MacAddr = CAM_CONST_ADDR[EntryId]; ++ setKey(dev, ++ EntryId , ++ EntryId, ++ priv->ieee80211->pairwise_key_type, ++ MacAddr, ++ 0, ++ NULL); ++ } ++ } ++ ++ } ++ else if(priv->ieee80211->pairwise_key_type == KEY_TYPE_TKIP) ++ { ++ ++ { ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ setKey(dev, ++ 4, ++ 0, ++ priv->ieee80211->pairwise_key_type, ++ (u8*)dev->dev_addr, ++ 0, ++ NULL); ++ else ++ setKey(dev, ++ 4, ++ 0, ++ priv->ieee80211->pairwise_key_type, ++ MacAddr, ++ 0, ++ NULL); ++ } ++ } ++ else if(priv->ieee80211->pairwise_key_type == KEY_TYPE_CCMP) ++ { ++ ++ { ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ setKey(dev, ++ 4, ++ 0, ++ priv->ieee80211->pairwise_key_type, ++ (u8*)dev->dev_addr, ++ 0, ++ NULL); ++ else ++ setKey(dev, ++ 4, ++ 0, ++ priv->ieee80211->pairwise_key_type, ++ MacAddr, ++ 0, ++ NULL); ++ } ++ } ++ ++ ++ ++ if(priv->ieee80211->group_key_type == KEY_TYPE_TKIP) ++ { ++ MacAddr = CAM_CONST_BROAD; ++ for(EntryId=1 ; EntryId<4 ; EntryId++) ++ { ++ { ++ setKey(dev, ++ EntryId, ++ EntryId, ++ priv->ieee80211->group_key_type, ++ MacAddr, ++ 0, ++ NULL); ++ } ++ } ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ setKey(dev, ++ 0, ++ 0, ++ priv->ieee80211->group_key_type, ++ CAM_CONST_ADDR[0], ++ 0, ++ NULL); ++ } ++ else if(priv->ieee80211->group_key_type == KEY_TYPE_CCMP) ++ { ++ MacAddr = CAM_CONST_BROAD; ++ for(EntryId=1; EntryId<4 ; EntryId++) ++ { ++ { ++ setKey(dev, ++ EntryId , ++ EntryId, ++ priv->ieee80211->group_key_type, ++ MacAddr, ++ 0, ++ NULL); ++ } ++ } ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ setKey(dev, ++ 0 , ++ 0, ++ priv->ieee80211->group_key_type, ++ CAM_CONST_ADDR[0], ++ 0, ++ NULL); ++ } ++} ++ ++void rtl8192_cancel_deferred_work(struct r8192_priv* priv); ++int _rtl8192_up(struct net_device *dev); ++ ++/* ++ * This function is used to fix Tx/Rx stop bug temporarily. ++ * This function will do "system reset" to NIC when Tx or Rx is stuck. ++ * The method checking Tx/Rx stuck of this function is supported by FW, ++ * which reports Tx and Rx counter to register 0x128 and 0x130. ++ * */ ++static void rtl819x_ifsilentreset(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 reset_times = 0; ++ int reset_status = 0; ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ ++ // 2007.07.20. If we need to check CCK stop, please uncomment this line. ++ //bStuck = Adapter->HalFunc.CheckHWStopHandler(Adapter); ++ ++ if(priv->ResetProgress==RESET_TYPE_NORESET) ++ { ++RESET_START: ++ ++ RT_TRACE(COMP_RESET,"=========>Reset progress!! \n"); ++ ++ // Set the variable for reset. ++ priv->ResetProgress = RESET_TYPE_SILENT; ++// rtl8192_close(dev); ++#if 1 ++ down(&priv->wx_sem); ++ if(priv->up == 0) ++ { ++ RT_TRACE(COMP_ERR,"%s():the driver is not up! return\n",__FUNCTION__); ++ up(&priv->wx_sem); ++ return ; ++ } ++ priv->up = 0; ++ RT_TRACE(COMP_RESET,"%s():======>start to down the driver\n",__FUNCTION__); ++ if(!netif_queue_stopped(dev)) ++ netif_stop_queue(dev); ++ ++ dm_backup_dynamic_mechanism_state(dev); ++ ++ rtl8192_irq_disable(dev); ++ rtl8192_cancel_deferred_work(priv); ++ deinit_hal_dm(dev); ++ del_timer_sync(&priv->watch_dog_timer); ++ ieee->sync_scan_hurryup = 1; ++ if(ieee->state == IEEE80211_LINKED) ++ { ++ down(&ieee->wx_sem); ++ printk("ieee->state is IEEE80211_LINKED\n"); ++ ieee80211_stop_send_beacons(priv->ieee80211); ++ del_timer_sync(&ieee->associate_timer); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&ieee->associate_retry_wq); ++#endif ++ ieee80211_stop_scan(ieee); ++ netif_carrier_off(dev); ++ up(&ieee->wx_sem); ++ } ++ else{ ++ printk("ieee->state is NOT LINKED\n"); ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ } ++ rtl8192_rtx_disable(dev); ++ up(&priv->wx_sem); ++ RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__); ++ RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__); ++ reset_status = _rtl8192_up(dev); ++ ++ RT_TRACE(COMP_RESET,"%s():<===========up process is finished\n",__FUNCTION__); ++ if(reset_status == -1) ++ { ++ if(reset_times < 3) ++ { ++ reset_times++; ++ goto RESET_START; ++ } ++ else ++ { ++ RT_TRACE(COMP_ERR," ERR!!! %s(): Reset Failed!!\n",__FUNCTION__); ++ } ++ } ++#endif ++ ieee->is_silent_reset = 1; ++#if 1 ++ EnableHWSecurityConfig8192(dev); ++#if 1 ++ if(ieee->state == IEEE80211_LINKED && ieee->iw_mode == IW_MODE_INFRA) ++ { ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++#if 1 ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_complete_wq); ++#else ++ schedule_task(&ieee->associate_complete_wq); ++#endif ++#endif ++ ++ } ++ else if(ieee->state == IEEE80211_LINKED && ieee->iw_mode == IW_MODE_ADHOC) ++ { ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->link_change(ieee->dev); ++ ++ // notify_wx_assoc_event(ieee); ++ ++ ieee80211_start_send_beacons(ieee); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ netif_carrier_on(ieee->dev); ++ } ++#endif ++ ++ CamRestoreAllEntry(dev); ++ ++ // Restore the previous setting for all dynamic mechanism ++ dm_restore_dynamic_mechanism_state(dev); ++ ++ priv->ResetProgress = RESET_TYPE_NORESET; ++ priv->reset_count++; ++ ++ priv->bForcedSilentReset =false; ++ priv->bResetInProgress = false; ++ ++ // For test --> force write UFWP. ++ write_nic_byte(dev, UFWP, 1); ++ RT_TRACE(COMP_RESET, "Reset finished!! ====>[%d]\n", priv->reset_count); ++#endif ++ } ++} ++ ++#ifdef ENABLE_IPS ++void InactivePsWorkItemCallback(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl)); ++ //u8 index = 0; ++ ++ RT_TRACE(COMP_POWER, "InactivePsWorkItemCallback() ---------> \n"); ++ // ++ // This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem ++ // is really scheduled. ++ // The old code, sets this flag before scheduling the IPS workitem and however, at the same time the ++ // previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing ++ // blocks the IPS procedure of switching RF. ++ // By Bruce, 2007-12-25. ++ // ++ pPSC->bSwRfProcessing = TRUE; ++ ++ RT_TRACE(COMP_RF, "InactivePsWorkItemCallback(): Set RF to %s.\n", \ ++ pPSC->eInactivePowerState == eRfOff?"OFF":"ON"); ++ ++ ++ MgntActSet_RF_State(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS); ++ ++ // ++ // To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20. ++ // ++#if 0 ++ if(pPSC->eInactivePowerState == eRfOn) ++ CamRestoreAllEntry(dev); ++#endif ++ pPSC->bSwRfProcessing = FALSE; ++ RT_TRACE(COMP_POWER, "InactivePsWorkItemCallback() <--------- \n"); ++} ++ ++// ++// Description: ++// Enter the inactive power save mode. RF will be off ++// 2007.08.17, by shien chang. ++// ++void ++IPSEnter(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl)); ++ RT_RF_POWER_STATE rtState; ++ ++ if (pPSC->bInactivePs) ++ { ++ rtState = priv->ieee80211->eRFPowerState; ++ // ++ // Added by Bruce, 2007-12-25. ++ // Do not enter IPS in the following conditions: ++ // (1) RF is already OFF or Sleep ++ // (2) bSwRfProcessing (indicates the IPS is still under going) ++ // (3) Connectted (only disconnected can trigger IPS) ++ // (4) IBSS (send Beacon) ++ // (5) AP mode (send Beacon) ++ // ++ if (rtState == eRfOn && !pPSC->bSwRfProcessing ++ && (priv->ieee80211->state != IEEE80211_LINKED) ) ++ { ++ RT_TRACE(COMP_RF,"IPSEnter(): Turn off RF.\n"); ++ pPSC->eInactivePowerState = eRfOff; ++// queue_work(priv->priv_wq,&(pPSC->InactivePsWorkItem)); ++ InactivePsWorkItemCallback(dev); ++ } ++ } ++} ++ ++// ++// Description: ++// Leave the inactive power save mode, RF will be on. ++// 2007.08.17, by shien chang. ++// ++void ++IPSLeave(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(priv->ieee80211->PowerSaveControl)); ++ RT_RF_POWER_STATE rtState; ++ ++ if (pPSC->bInactivePs) ++ { ++ rtState = priv->ieee80211->eRFPowerState; ++ if (rtState != eRfOn && !pPSC->bSwRfProcessing && priv->ieee80211->RfOffReason <= RF_CHANGE_BY_IPS) ++ { ++ RT_TRACE(COMP_POWER, "IPSLeave(): Turn on RF.\n"); ++ pPSC->eInactivePowerState = eRfOn; ++// queue_work(priv->priv_wq,&(pPSC->InactivePsWorkItem)); ++ InactivePsWorkItemCallback(dev); ++ } ++ } ++} ++#endif ++ ++static void rtl819x_update_rxcounts( ++ struct r8192_priv *priv, ++ u32* TotalRxBcnNum, ++ u32* TotalRxDataNum ++) ++{ ++ u16 SlotIndex; ++ u8 i; ++ ++ *TotalRxBcnNum = 0; ++ *TotalRxDataNum = 0; ++ ++ SlotIndex = (priv->ieee80211->LinkDetectInfo.SlotIndex++)%(priv->ieee80211->LinkDetectInfo.SlotNum); ++ priv->ieee80211->LinkDetectInfo.RxBcnNum[SlotIndex] = priv->ieee80211->LinkDetectInfo.NumRecvBcnInPeriod; ++ priv->ieee80211->LinkDetectInfo.RxDataNum[SlotIndex] = priv->ieee80211->LinkDetectInfo.NumRecvDataInPeriod; ++ for( i=0; iieee80211->LinkDetectInfo.SlotNum; i++ ){ ++ *TotalRxBcnNum += priv->ieee80211->LinkDetectInfo.RxBcnNum[i]; ++ *TotalRxDataNum += priv->ieee80211->LinkDetectInfo.RxDataNum[i]; ++ } ++} ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl819x_watchdog_wqcallback(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct r8192_priv *priv = container_of(dwork,struct r8192_priv,watch_dog_wq); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++extern void rtl819x_watchdog_wqcallback(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ struct ieee80211_device* ieee = priv->ieee80211; ++ RESET_TYPE ResetType = RESET_TYPE_NORESET; ++ static u8 check_reset_cnt=0; ++ unsigned long flags; ++ bool bBusyTraffic = false; ++ static u8 last_time = 0; ++ if(!priv->up) ++ return; ++ hal_dm_watchdog(dev); ++#ifdef ENABLE_IPS ++// printk("watch_dog ENABLE_IPS\n"); ++ if(ieee->actscanning == false){ ++ if((ieee->iw_mode != IW_MODE_ADHOC) && (ieee->state == IEEE80211_NOLINK) && (ieee->beinretry == false) && (ieee->eRFPowerState == eRfOn) && !ieee->is_set_key){ ++ if(ieee->PowerSaveControl.ReturnPoint == IPS_CALLBACK_NONE){ ++ printk("====================>haha:IPSEnter()\n"); ++ IPSEnter(dev); ++ //ieee80211_stop_scan(priv->ieee80211); ++ } ++ } ++ } ++#endif ++ {//to get busy traffic condition ++ if(ieee->state == IEEE80211_LINKED) ++ { ++ if( ieee->LinkDetectInfo.NumRxOkInPeriod> 666 || ++ ieee->LinkDetectInfo.NumTxOkInPeriod> 666 ) { ++ bBusyTraffic = true; ++ } ++ ++ } ++ ieee->LinkDetectInfo.NumRxOkInPeriod = 0; ++ ieee->LinkDetectInfo.NumTxOkInPeriod = 0; ++ ieee->LinkDetectInfo.bBusyTraffic = bBusyTraffic; ++ } ++ ++ ++ //added by amy for AP roaming ++ if (1) ++ { ++ if(ieee->state == IEEE80211_LINKED && ieee->iw_mode == IW_MODE_INFRA) ++ { ++ u32 TotalRxBcnNum = 0; ++ u32 TotalRxDataNum = 0; ++ ++ rtl819x_update_rxcounts(priv, &TotalRxBcnNum, &TotalRxDataNum); ++ if((TotalRxBcnNum+TotalRxDataNum) == 0) ++ { ++ if( ieee->eRFPowerState == eRfOff) ++ RT_TRACE(COMP_ERR,"========>%s()\n",__FUNCTION__); ++ printk("===>%s(): AP is power off,connect another one\n",__FUNCTION__); ++ // Dot11d_Reset(dev); ++ ieee->state = IEEE80211_ASSOCIATING; ++ notify_wx_assoc_event(priv->ieee80211); ++ RemovePeerTS(priv->ieee80211,priv->ieee80211->current_network.bssid); ++ ieee->is_roaming = true; ++ ieee->is_set_key = false; ++ ieee->link_change(dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++#else ++ schedule_task(&ieee->associate_procedure_wq); ++#endif ++ } ++ } ++ ieee->LinkDetectInfo.NumRecvBcnInPeriod=0; ++ ieee->LinkDetectInfo.NumRecvDataInPeriod=0; ++ ++ } ++ //check if reset the driver ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ if(check_reset_cnt++ >= 3 && !ieee->is_roaming && (last_time != 1)) ++ { ++ ResetType = rtl819x_ifcheck_resetornot(dev); ++ check_reset_cnt = 3; ++ //DbgPrint("Start to check silent reset\n"); ++ } ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ if(!priv->bDisableNormalResetCheck && ResetType == RESET_TYPE_NORMAL) ++ { ++ priv->ResetProgress = RESET_TYPE_NORMAL; ++ RT_TRACE(COMP_RESET,"%s(): NOMAL RESET\n",__FUNCTION__); ++ return; ++ } ++ /* disable silent reset temply 2008.9.11*/ ++#if 1 ++ if( ((priv->force_reset) || (!priv->bDisableNormalResetCheck && ResetType==RESET_TYPE_SILENT))) // This is control by OID set in Pomelo ++ { ++ last_time = 1; ++ rtl819x_ifsilentreset(dev); ++ } ++ else ++ last_time = 0; ++#endif ++ priv->force_reset = false; ++ priv->bForcedSilentReset = false; ++ priv->bResetInProgress = false; ++ RT_TRACE(COMP_TRACE, " <==RtUsbCheckForHangWorkItemCallback()\n"); ++ ++} ++ ++void watch_dog_timer_callback(unsigned long data) ++{ ++ struct r8192_priv *priv = ieee80211_priv((struct net_device *) data); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->priv_wq,&priv->watch_dog_wq,0); ++#else ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ schedule_task(&priv->watch_dog_wq); ++#else ++ queue_work(priv->priv_wq,&priv->watch_dog_wq); ++#endif ++#endif ++ mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME)); ++ ++} ++int _rtl8192_up(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //int i; ++ RT_STATUS init_status = RT_STATUS_SUCCESS; ++ priv->up=1; ++ priv->ieee80211->ieee_up=1; ++ RT_TRACE(COMP_INIT, "Bringing up iface"); ++ ++ init_status = rtl8192_adapter_start(dev); ++ if(init_status != RT_STATUS_SUCCESS) ++ { ++ RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n",__FUNCTION__); ++ return -1; ++ } ++ RT_TRACE(COMP_INIT, "start adapter finished\n"); ++#ifdef RTL8192E ++ if(priv->ieee80211->eRFPowerState!=eRfOn) ++ MgntActSet_RF_State(dev, eRfOn, priv->ieee80211->RfOffReason); ++#endif ++ if(priv->ieee80211->state != IEEE80211_LINKED) ++ ieee80211_softmac_start_protocol(priv->ieee80211); ++ ieee80211_reset_queue(priv->ieee80211); ++ watch_dog_timer_callback((unsigned long) dev); ++ if(!netif_queue_stopped(dev)) ++ netif_start_queue(dev); ++ else ++ netif_wake_queue(dev); ++ ++ return 0; ++} ++ ++ ++static int rtl8192_open(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ down(&priv->wx_sem); ++ ret = rtl8192_up(dev); ++ up(&priv->wx_sem); ++ return ret; ++ ++} ++ ++ ++int rtl8192_up(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 1) return -1; ++ ++ return _rtl8192_up(dev); ++} ++ ++ ++static int rtl8192_close(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ down(&priv->wx_sem); ++ ++ ret = rtl8192_down(dev); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++int rtl8192_down(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++// int i; ++#if 0 ++ u8 ucRegRead; ++ u32 ulRegRead; ++#endif ++ if (priv->up == 0) return -1; ++ ++ priv->up=0; ++ priv->ieee80211->ieee_up = 0; ++ RT_TRACE(COMP_DOWN, "==========>%s()\n", __FUNCTION__); ++/* FIXME */ ++ if (!netif_queue_stopped(dev)) ++ netif_stop_queue(dev); ++ ++ rtl8192_irq_disable(dev); ++#if 0 ++ if(!priv->ieee80211->bSupportRemoteWakeUp) { ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT); ++ // 2006.11.30. System reset bit ++ ulRegRead = read_nic_dword(dev, CPU_GEN); ++ ulRegRead|=CPU_GEN_SYSTEM_RESET; ++ write_nic_dword(dev, CPU_GEN, ulRegRead); ++ } else { ++ //2008.06.03 for WOL ++ write_nic_dword(dev, WFCRC0, 0xffffffff); ++ write_nic_dword(dev, WFCRC1, 0xffffffff); ++ write_nic_dword(dev, WFCRC2, 0xffffffff); ++#ifdef RTL8190P ++ //GPIO 0 = TRUE ++ ucRegRead = read_nic_byte(dev, GPO); ++ ucRegRead |= BIT0; ++ write_nic_byte(dev, GPO, ucRegRead); ++#endif ++ //Write PMR register ++ write_nic_byte(dev, PMR, 0x5); ++ //Disable tx, enanble rx ++ write_nic_byte(dev, MacBlkCtrl, 0xa); ++ } ++#endif ++// flush_scheduled_work(); ++ rtl8192_cancel_deferred_work(priv); ++ deinit_hal_dm(dev); ++ del_timer_sync(&priv->watch_dog_timer); ++ ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++#ifdef ENABLE_IPS ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT); ++#endif ++ rtl8192_rtx_disable(dev); ++ memset(&priv->ieee80211->current_network, 0 , offsetof(struct ieee80211_network, list)); ++ ++ RT_TRACE(COMP_DOWN, "<==========%s()\n", __FUNCTION__); ++ ++ return 0; ++} ++ ++ ++void rtl8192_commit(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 0) return ; ++ ++ ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ ++ rtl8192_irq_disable(dev); ++ rtl8192_rtx_disable(dev); ++ _rtl8192_up(dev); ++} ++ ++/* ++void rtl8192_restart(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++*/ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8192_restart(struct work_struct *work) ++{ ++ struct r8192_priv *priv = container_of(work, struct r8192_priv, reset_wq); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++void rtl8192_restart(struct net_device *dev) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ ++ down(&priv->wx_sem); ++ ++ rtl8192_commit(dev); ++ ++ up(&priv->wx_sem); ++} ++ ++static void r8192_set_multicast(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ short promisc; ++ ++ //down(&priv->wx_sem); ++ ++ /* FIXME FIXME */ ++ ++ promisc = (dev->flags & IFF_PROMISC) ? 1:0; ++ ++ if (promisc != priv->promisc) { ++ ; ++ // rtl8192_commit(dev); ++ } ++ ++ priv->promisc = promisc; ++ ++ //schedule_work(&priv->reset_wq); ++ //up(&priv->wx_sem); ++} ++ ++ ++static int r8192_set_mac_adr(struct net_device *dev, void *mac) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct sockaddr *addr = mac; ++ ++ down(&priv->wx_sem); ++ ++ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ schedule_work(&priv->reset_wq); ++#else ++ schedule_task(&priv->reset_wq); ++#endif ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++/* based on ipw2200 driver */ ++static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ struct iwreq *wrq = (struct iwreq *)rq; ++ int ret=-1; ++ struct ieee80211_device *ieee = priv->ieee80211; ++ u32 key[4]; ++ u8 broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ struct iw_point *p = &wrq->u.data; ++ struct ieee_param *ipw = NULL;//(struct ieee_param *)wrq->u.data.pointer; ++ ++ down(&priv->wx_sem); ++ ++ ++ if (p->length < sizeof(struct ieee_param) || !p->pointer){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ipw = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); ++ if (ipw == NULL){ ++ ret = -ENOMEM; ++ goto out; ++ } ++ if (copy_from_user(ipw, p->pointer, p->length)) { ++ kfree(ipw); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ switch (cmd) { ++ case RTL_IOCTL_WPA_SUPPLICANT: ++ //parse here for HW security ++ if (ipw->cmd == IEEE_CMD_SET_ENCRYPTION) ++ { ++ if (ipw->u.crypt.set_tx) ++ { ++ if (strcmp(ipw->u.crypt.alg, "CCMP") == 0) ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ else if (strcmp(ipw->u.crypt.alg, "TKIP") == 0) ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ else if (strcmp(ipw->u.crypt.alg, "WEP") == 0) ++ { ++ if (ipw->u.crypt.key_len == 13) ++ ieee->pairwise_key_type = KEY_TYPE_WEP104; ++ else if (ipw->u.crypt.key_len == 5) ++ ieee->pairwise_key_type = KEY_TYPE_WEP40; ++ } ++ else ++ ieee->pairwise_key_type = KEY_TYPE_NA; ++ ++ if (ieee->pairwise_key_type) ++ { ++ memcpy((u8*)key, ipw->u.crypt.key, 16); ++ EnableHWSecurityConfig8192(dev); ++ //we fill both index entry and 4th entry for pairwise key as in IPW interface, adhoc will only get here, so we need index entry for its default key serching! ++ //added by WB. ++ setKey(dev, 4, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8*)ieee->ap_mac_addr, 0, key); ++ if (ieee->auth_mode != 2) //LEAP WEP will never set this. ++ setKey(dev, ipw->u.crypt.idx, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8*)ieee->ap_mac_addr, 0, key); ++ } ++ if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport){ ++ write_nic_byte(dev, 0x173, 1); //fix aes bug ++ } ++ ++ } ++ else //if (ipw->u.crypt.idx) //group key use idx > 0 ++ { ++ memcpy((u8*)key, ipw->u.crypt.key, 16); ++ if (strcmp(ipw->u.crypt.alg, "CCMP") == 0) ++ ieee->group_key_type= KEY_TYPE_CCMP; ++ else if (strcmp(ipw->u.crypt.alg, "TKIP") == 0) ++ ieee->group_key_type = KEY_TYPE_TKIP; ++ else if (strcmp(ipw->u.crypt.alg, "WEP") == 0) ++ { ++ if (ipw->u.crypt.key_len == 13) ++ ieee->group_key_type = KEY_TYPE_WEP104; ++ else if (ipw->u.crypt.key_len == 5) ++ ieee->group_key_type = KEY_TYPE_WEP40; ++ } ++ else ++ ieee->group_key_type = KEY_TYPE_NA; ++ ++ if (ieee->group_key_type) ++ { ++ setKey( dev, ++ ipw->u.crypt.idx, ++ ipw->u.crypt.idx, //KeyIndex ++ ieee->group_key_type, //KeyType ++ broadcast_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ } ++ } ++#ifdef JOHN_DEBUG ++ //john's test 0711 ++ { ++ int i; ++ printk("@@ wrq->u pointer = "); ++ for(i=0;iu.data.length;i++){ ++ if(i%10==0) printk("\n"); ++ printk( "%8x|", ((u32*)wrq->u.data.pointer)[i] ); ++ } ++ printk("\n"); ++ } ++#endif /*JOHN_DEBUG*/ ++ ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); ++ break; ++ ++ default: ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ kfree(ipw); ++out: ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++static u8 HwRateToMRate90(bool bIsHT, u8 rate) ++{ ++ u8 ret_rate = 0x02; ++ ++ if(!bIsHT) { ++ switch(rate) { ++ case DESC90_RATE1M: ret_rate = MGN_1M; break; ++ case DESC90_RATE2M: ret_rate = MGN_2M; break; ++ case DESC90_RATE5_5M: ret_rate = MGN_5_5M; break; ++ case DESC90_RATE11M: ret_rate = MGN_11M; break; ++ case DESC90_RATE6M: ret_rate = MGN_6M; break; ++ case DESC90_RATE9M: ret_rate = MGN_9M; break; ++ case DESC90_RATE12M: ret_rate = MGN_12M; break; ++ case DESC90_RATE18M: ret_rate = MGN_18M; break; ++ case DESC90_RATE24M: ret_rate = MGN_24M; break; ++ case DESC90_RATE36M: ret_rate = MGN_36M; break; ++ case DESC90_RATE48M: ret_rate = MGN_48M; break; ++ case DESC90_RATE54M: ret_rate = MGN_54M; break; ++ ++ default: ++ RT_TRACE(COMP_RECV, "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n", rate, bIsHT); ++ break; ++ } ++ ++ } else { ++ switch(rate) { ++ case DESC90_RATEMCS0: ret_rate = MGN_MCS0; break; ++ case DESC90_RATEMCS1: ret_rate = MGN_MCS1; break; ++ case DESC90_RATEMCS2: ret_rate = MGN_MCS2; break; ++ case DESC90_RATEMCS3: ret_rate = MGN_MCS3; break; ++ case DESC90_RATEMCS4: ret_rate = MGN_MCS4; break; ++ case DESC90_RATEMCS5: ret_rate = MGN_MCS5; break; ++ case DESC90_RATEMCS6: ret_rate = MGN_MCS6; break; ++ case DESC90_RATEMCS7: ret_rate = MGN_MCS7; break; ++ case DESC90_RATEMCS8: ret_rate = MGN_MCS8; break; ++ case DESC90_RATEMCS9: ret_rate = MGN_MCS9; break; ++ case DESC90_RATEMCS10: ret_rate = MGN_MCS10; break; ++ case DESC90_RATEMCS11: ret_rate = MGN_MCS11; break; ++ case DESC90_RATEMCS12: ret_rate = MGN_MCS12; break; ++ case DESC90_RATEMCS13: ret_rate = MGN_MCS13; break; ++ case DESC90_RATEMCS14: ret_rate = MGN_MCS14; break; ++ case DESC90_RATEMCS15: ret_rate = MGN_MCS15; break; ++ case DESC90_RATEMCS32: ret_rate = (0x80|0x20); break; ++ ++ default: ++ RT_TRACE(COMP_RECV, "HwRateToMRate90(): Non supported Rate [%x], bIsHT = %d!!!\n",rate, bIsHT); ++ break; ++ } ++ } ++ ++ return ret_rate; ++} ++ ++/** ++ * Function: UpdateRxPktTimeStamp ++ * Overview: Recored down the TSF time stamp when receiving a packet ++ * ++ * Input: ++ * PADAPTER Adapter ++ * PRT_RFD pRfd, ++ * ++ * Output: ++ * PRT_RFD pRfd ++ * (pRfd->Status.TimeStampHigh is updated) ++ * (pRfd->Status.TimeStampLow is updated) ++ * Return: ++ * None ++ */ ++static void UpdateRxPktTimeStamp8190 (struct net_device *dev, struct ieee80211_rx_stats *stats) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ if(stats->bIsAMPDU && !stats->bFirstMPDU) { ++ stats->mac_time[0] = priv->LastRxDescTSFLow; ++ stats->mac_time[1] = priv->LastRxDescTSFHigh; ++ } else { ++ priv->LastRxDescTSFLow = stats->mac_time[0]; ++ priv->LastRxDescTSFHigh = stats->mac_time[1]; ++ } ++} ++ ++static long rtl819x_translate_todbm(u8 signal_strength_index)// 0-100 index. ++{ ++ long signal_power; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ signal_power = (long)((signal_strength_index + 1) >> 1); ++ signal_power -= 95; ++ ++ return signal_power; ++} ++ ++// ++// Description: ++// Update Rx signal related information in the packet reeived ++// to RxStats. User application can query RxStats to realize ++// current Rx signal status. ++// ++// Assumption: ++// In normal operation, user only care about the information of the BSS ++// and we shall invoke this function if the packet received is from the BSS. ++// ++static void ++rtl819x_update_rxsignalstatistics8190pci( ++ struct r8192_priv * priv, ++ struct ieee80211_rx_stats * pprevious_stats ++ ) ++{ ++ int weighting = 0; ++ ++ //2 Update Rx Statistics (such as signal strength and signal quality). ++ ++ // Initila state ++ if(priv->stats.recv_signal_power == 0) ++ priv->stats.recv_signal_power = pprevious_stats->RecvSignalPower; ++ ++ // To avoid the past result restricting the statistics sensitivity, weight the current power (5/6) to speed up the ++ // reaction of smoothed Signal Power. ++ if(pprevious_stats->RecvSignalPower > priv->stats.recv_signal_power) ++ weighting = 5; ++ else if(pprevious_stats->RecvSignalPower < priv->stats.recv_signal_power) ++ weighting = (-5); ++ // ++ // We need more correct power of received packets and the "SignalStrength" of RxStats have been beautified or translated, ++ // so we record the correct power in Dbm here. By Bruce, 2008-03-07. ++ // ++ priv->stats.recv_signal_power = (priv->stats.recv_signal_power * 5 + pprevious_stats->RecvSignalPower + weighting) / 6; ++} ++ ++static void ++rtl8190_process_cck_rxpathsel( ++ struct r8192_priv * priv, ++ struct ieee80211_rx_stats * pprevious_stats ++ ) ++{ ++#ifdef RTL8190P //Only 90P 2T4R need to check ++ char last_cck_adc_pwdb[4]={0,0,0,0}; ++ u8 i; ++//cosa add for Rx path selection ++ if(priv->rf_type == RF_2T4R && DM_RxPathSelTable.Enable) ++ { ++ if(pprevious_stats->bIsCCK && ++ (pprevious_stats->bPacketToSelf ||pprevious_stats->bPacketBeacon)) ++ { ++ /* record the cck adc_pwdb to the sliding window. */ ++ if(priv->stats.cck_adc_pwdb.TotalNum++ >= PHY_RSSI_SLID_WIN_MAX) ++ { ++ priv->stats.cck_adc_pwdb.TotalNum = PHY_RSSI_SLID_WIN_MAX; ++ for(i=RF90_PATH_A; istats.cck_adc_pwdb.elements[i][priv->stats.cck_adc_pwdb.index]; ++ priv->stats.cck_adc_pwdb.TotalVal[i] -= last_cck_adc_pwdb[i]; ++ } ++ } ++ for(i=RF90_PATH_A; istats.cck_adc_pwdb.TotalVal[i] += pprevious_stats->cck_adc_pwdb[i]; ++ priv->stats.cck_adc_pwdb.elements[i][priv->stats.cck_adc_pwdb.index] = pprevious_stats->cck_adc_pwdb[i]; ++ } ++ priv->stats.cck_adc_pwdb.index++; ++ if(priv->stats.cck_adc_pwdb.index >= PHY_RSSI_SLID_WIN_MAX) ++ priv->stats.cck_adc_pwdb.index = 0; ++ ++ for(i=RF90_PATH_A; istats.cck_adc_pwdb.TotalVal[i]/priv->stats.cck_adc_pwdb.TotalNum; ++ } ++ ++ for(i=RF90_PATH_A; icck_adc_pwdb[i] > (char)priv->undecorated_smoothed_cck_adc_pwdb[i]) ++ { ++ priv->undecorated_smoothed_cck_adc_pwdb[i] = ++ ( (priv->undecorated_smoothed_cck_adc_pwdb[i]*(Rx_Smooth_Factor-1)) + ++ (pprevious_stats->cck_adc_pwdb[i])) /(Rx_Smooth_Factor); ++ priv->undecorated_smoothed_cck_adc_pwdb[i] = priv->undecorated_smoothed_cck_adc_pwdb[i] + 1; ++ } ++ else ++ { ++ priv->undecorated_smoothed_cck_adc_pwdb[i] = ++ ( (priv->undecorated_smoothed_cck_adc_pwdb[i]*(Rx_Smooth_Factor-1)) + ++ (pprevious_stats->cck_adc_pwdb[i])) /(Rx_Smooth_Factor); ++ } ++ } ++ } ++ } ++#endif ++} ++ ++ ++/* 2008/01/22 MH We can not delcare RSSI/EVM total value of sliding window to ++ be a local static. Otherwise, it may increase when we return from S3/S4. The ++ value will be kept in memory or disk. We must delcare the value in adapter ++ and it will be reinitialized when return from S3/S4. */ ++static void rtl8192_process_phyinfo(struct r8192_priv * priv, u8* buffer,struct ieee80211_rx_stats * pprevious_stats, struct ieee80211_rx_stats * pcurrent_stats) ++{ ++ bool bcheck = false; ++ u8 rfpath; ++ u32 nspatial_stream, tmp_val; ++ //u8 i; ++ static u32 slide_rssi_index=0, slide_rssi_statistics=0; ++ static u32 slide_evm_index=0, slide_evm_statistics=0; ++ static u32 last_rssi=0, last_evm=0; ++ //cosa add for rx path selection ++// static long slide_cck_adc_pwdb_index=0, slide_cck_adc_pwdb_statistics=0; ++// static char last_cck_adc_pwdb[4]={0,0,0,0}; ++ //cosa add for beacon rssi smoothing ++ static u32 slide_beacon_adc_pwdb_index=0, slide_beacon_adc_pwdb_statistics=0; ++ static u32 last_beacon_adc_pwdb=0; ++ ++ struct ieee80211_hdr_3addr *hdr; ++ u16 sc ; ++ unsigned int frag,seq; ++ hdr = (struct ieee80211_hdr_3addr *)buffer; ++ sc = le16_to_cpu(hdr->seq_ctl); ++ frag = WLAN_GET_SEQ_FRAG(sc); ++ seq = WLAN_GET_SEQ_SEQ(sc); ++ //cosa add 04292008 to record the sequence number ++ pcurrent_stats->Seq_Num = seq; ++ // ++ // Check whether we should take the previous packet into accounting ++ // ++ if(!pprevious_stats->bIsAMPDU) ++ { ++ // if previous packet is not aggregated packet ++ bcheck = true; ++ }else ++ { ++//remve for that we don't use AMPDU to calculate PWDB,because the reported PWDB of some AP is fault. ++#if 0 ++ // if previous packet is aggregated packet, and current packet ++ // (1) is not AMPDU ++ // (2) is the first packet of one AMPDU ++ // that means the previous packet is the last one aggregated packet ++ if( !pcurrent_stats->bIsAMPDU || pcurrent_stats->bFirstMPDU) ++ bcheck = true; ++#endif ++ } ++ ++ if(slide_rssi_statistics++ >= PHY_RSSI_SLID_WIN_MAX) ++ { ++ slide_rssi_statistics = PHY_RSSI_SLID_WIN_MAX; ++ last_rssi = priv->stats.slide_signal_strength[slide_rssi_index]; ++ priv->stats.slide_rssi_total -= last_rssi; ++ } ++ priv->stats.slide_rssi_total += pprevious_stats->SignalStrength; ++ ++ priv->stats.slide_signal_strength[slide_rssi_index++] = pprevious_stats->SignalStrength; ++ if(slide_rssi_index >= PHY_RSSI_SLID_WIN_MAX) ++ slide_rssi_index = 0; ++ ++ // <1> Showed on UI for user, in dbm ++ tmp_val = priv->stats.slide_rssi_total/slide_rssi_statistics; ++ priv->stats.signal_strength = rtl819x_translate_todbm((u8)tmp_val); ++ pcurrent_stats->rssi = priv->stats.signal_strength; ++ // ++ // If the previous packet does not match the criteria, neglect it ++ // ++ if(!pprevious_stats->bPacketMatchBSSID) ++ { ++ if(!pprevious_stats->bToSelfBA) ++ return; ++ } ++ ++ if(!bcheck) ++ return; ++ ++ rtl8190_process_cck_rxpathsel(priv,pprevious_stats); ++ ++ // ++ // Check RSSI ++ // ++ priv->stats.num_process_phyinfo++; ++#if 0 ++ /* record the general signal strength to the sliding window. */ ++ if(slide_rssi_statistics++ >= PHY_RSSI_SLID_WIN_MAX) ++ { ++ slide_rssi_statistics = PHY_RSSI_SLID_WIN_MAX; ++ last_rssi = priv->stats.slide_signal_strength[slide_rssi_index]; ++ priv->stats.slide_rssi_total -= last_rssi; ++ } ++ priv->stats.slide_rssi_total += pprevious_stats->SignalStrength; ++ ++ priv->stats.slide_signal_strength[slide_rssi_index++] = pprevious_stats->SignalStrength; ++ if(slide_rssi_index >= PHY_RSSI_SLID_WIN_MAX) ++ slide_rssi_index = 0; ++ ++ // <1> Showed on UI for user, in dbm ++ tmp_val = priv->stats.slide_rssi_total/slide_rssi_statistics; ++ priv->stats.signal_strength = rtl819x_translate_todbm((u8)tmp_val); ++ ++#endif ++ // <2> Showed on UI for engineering ++ // hardware does not provide rssi information for each rf path in CCK ++ if(!pprevious_stats->bIsCCK && pprevious_stats->bPacketToSelf) ++ { ++ for (rfpath = RF90_PATH_A; rfpath < RF90_PATH_C; rfpath++) ++ { ++ if (!rtl8192_phy_CheckIsLegalRFPath(priv->ieee80211->dev, rfpath)) ++ continue; ++ RT_TRACE(COMP_DBG,"Jacken -> pPreviousstats->RxMIMOSignalStrength[rfpath] = %d \n" ,pprevious_stats->RxMIMOSignalStrength[rfpath] ); ++ //Fixed by Jacken 2008-03-20 ++ if(priv->stats.rx_rssi_percentage[rfpath] == 0) ++ { ++ priv->stats.rx_rssi_percentage[rfpath] = pprevious_stats->RxMIMOSignalStrength[rfpath]; ++ //DbgPrint("MIMO RSSI initialize \n"); ++ } ++ if(pprevious_stats->RxMIMOSignalStrength[rfpath] > priv->stats.rx_rssi_percentage[rfpath]) ++ { ++ priv->stats.rx_rssi_percentage[rfpath] = ++ ( (priv->stats.rx_rssi_percentage[rfpath]*(Rx_Smooth_Factor-1)) + ++ (pprevious_stats->RxMIMOSignalStrength[rfpath])) /(Rx_Smooth_Factor); ++ priv->stats.rx_rssi_percentage[rfpath] = priv->stats.rx_rssi_percentage[rfpath] + 1; ++ } ++ else ++ { ++ priv->stats.rx_rssi_percentage[rfpath] = ++ ( (priv->stats.rx_rssi_percentage[rfpath]*(Rx_Smooth_Factor-1)) + ++ (pprevious_stats->RxMIMOSignalStrength[rfpath])) /(Rx_Smooth_Factor); ++ } ++ RT_TRACE(COMP_DBG,"Jacken -> priv->RxStats.RxRSSIPercentage[rfPath] = %d \n" ,priv->stats.rx_rssi_percentage[rfpath] ); ++ } ++ } ++ ++ ++ // ++ // Check PWDB. ++ // ++ //cosa add for beacon rssi smoothing by average. ++ if(pprevious_stats->bPacketBeacon) ++ { ++ /* record the beacon pwdb to the sliding window. */ ++ if(slide_beacon_adc_pwdb_statistics++ >= PHY_Beacon_RSSI_SLID_WIN_MAX) ++ { ++ slide_beacon_adc_pwdb_statistics = PHY_Beacon_RSSI_SLID_WIN_MAX; ++ last_beacon_adc_pwdb = priv->stats.Slide_Beacon_pwdb[slide_beacon_adc_pwdb_index]; ++ priv->stats.Slide_Beacon_Total -= last_beacon_adc_pwdb; ++ //DbgPrint("slide_beacon_adc_pwdb_index = %d, last_beacon_adc_pwdb = %d, Adapter->RxStats.Slide_Beacon_Total = %d\n", ++ // slide_beacon_adc_pwdb_index, last_beacon_adc_pwdb, Adapter->RxStats.Slide_Beacon_Total); ++ } ++ priv->stats.Slide_Beacon_Total += pprevious_stats->RxPWDBAll; ++ priv->stats.Slide_Beacon_pwdb[slide_beacon_adc_pwdb_index] = pprevious_stats->RxPWDBAll; ++ //DbgPrint("slide_beacon_adc_pwdb_index = %d, pPreviousRfd->Status.RxPWDBAll = %d\n", slide_beacon_adc_pwdb_index, pPreviousRfd->Status.RxPWDBAll); ++ slide_beacon_adc_pwdb_index++; ++ if(slide_beacon_adc_pwdb_index >= PHY_Beacon_RSSI_SLID_WIN_MAX) ++ slide_beacon_adc_pwdb_index = 0; ++ pprevious_stats->RxPWDBAll = priv->stats.Slide_Beacon_Total/slide_beacon_adc_pwdb_statistics; ++ if(pprevious_stats->RxPWDBAll >= 3) ++ pprevious_stats->RxPWDBAll -= 3; ++ } ++ ++ RT_TRACE(COMP_RXDESC, "Smooth %s PWDB = %d\n", ++ pprevious_stats->bIsCCK? "CCK": "OFDM", ++ pprevious_stats->RxPWDBAll); ++ ++ if(pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA) ++ { ++ if(priv->undecorated_smoothed_pwdb < 0) // initialize ++ { ++ priv->undecorated_smoothed_pwdb = pprevious_stats->RxPWDBAll; ++ //DbgPrint("First pwdb initialize \n"); ++ } ++#if 1 ++ if(pprevious_stats->RxPWDBAll > (u32)priv->undecorated_smoothed_pwdb) ++ { ++ priv->undecorated_smoothed_pwdb = ++ ( ((priv->undecorated_smoothed_pwdb)*(Rx_Smooth_Factor-1)) + ++ (pprevious_stats->RxPWDBAll)) /(Rx_Smooth_Factor); ++ priv->undecorated_smoothed_pwdb = priv->undecorated_smoothed_pwdb + 1; ++ } ++ else ++ { ++ priv->undecorated_smoothed_pwdb = ++ ( ((priv->undecorated_smoothed_pwdb)*(Rx_Smooth_Factor-1)) + ++ (pprevious_stats->RxPWDBAll)) /(Rx_Smooth_Factor); ++ } ++#else ++ //Fixed by Jacken 2008-03-20 ++ if(pPreviousRfd->Status.RxPWDBAll > (u32)pHalData->UndecoratedSmoothedPWDB) ++ { ++ pHalData->UndecoratedSmoothedPWDB = ++ ( ((pHalData->UndecoratedSmoothedPWDB)* 5) + (pPreviousRfd->Status.RxPWDBAll)) / 6; ++ pHalData->UndecoratedSmoothedPWDB = pHalData->UndecoratedSmoothedPWDB + 1; ++ } ++ else ++ { ++ pHalData->UndecoratedSmoothedPWDB = ++ ( ((pHalData->UndecoratedSmoothedPWDB)* 5) + (pPreviousRfd->Status.RxPWDBAll)) / 6; ++ } ++#endif ++ rtl819x_update_rxsignalstatistics8190pci(priv,pprevious_stats); ++ } ++ ++ // ++ // Check EVM ++ // ++ /* record the general EVM to the sliding window. */ ++ if(pprevious_stats->SignalQuality == 0) ++ { ++ } ++ else ++ { ++ if(pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA){ ++ if(slide_evm_statistics++ >= PHY_RSSI_SLID_WIN_MAX){ ++ slide_evm_statistics = PHY_RSSI_SLID_WIN_MAX; ++ last_evm = priv->stats.slide_evm[slide_evm_index]; ++ priv->stats.slide_evm_total -= last_evm; ++ } ++ ++ priv->stats.slide_evm_total += pprevious_stats->SignalQuality; ++ ++ priv->stats.slide_evm[slide_evm_index++] = pprevious_stats->SignalQuality; ++ if(slide_evm_index >= PHY_RSSI_SLID_WIN_MAX) ++ slide_evm_index = 0; ++ ++ // <1> Showed on UI for user, in percentage. ++ tmp_val = priv->stats.slide_evm_total/slide_evm_statistics; ++ priv->stats.signal_quality = tmp_val; ++ //cosa add 10/11/2007, Showed on UI for user in Windows Vista, for Link quality. ++ priv->stats.last_signal_strength_inpercent = tmp_val; ++ } ++ ++ // <2> Showed on UI for engineering ++ if(pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA) ++ { ++ for(nspatial_stream = 0; nspatial_stream<2 ; nspatial_stream++) // 2 spatial stream ++ { ++ if(pprevious_stats->RxMIMOSignalQuality[nspatial_stream] != -1) ++ { ++ if(priv->stats.rx_evm_percentage[nspatial_stream] == 0) // initialize ++ { ++ priv->stats.rx_evm_percentage[nspatial_stream] = pprevious_stats->RxMIMOSignalQuality[nspatial_stream]; ++ } ++ priv->stats.rx_evm_percentage[nspatial_stream] = ++ ( (priv->stats.rx_evm_percentage[nspatial_stream]* (Rx_Smooth_Factor-1)) + ++ (pprevious_stats->RxMIMOSignalQuality[nspatial_stream]* 1)) / (Rx_Smooth_Factor); ++ } ++ } ++ } ++ } ++ ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: rtl819x_query_rxpwrpercentage() ++ * ++ * Overview: ++ * ++ * Input: char antpower ++ * ++ * Output: NONE ++ * ++ * Return: 0-100 percentage ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/26/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static u8 rtl819x_query_rxpwrpercentage( ++ char antpower ++ ) ++{ ++ if ((antpower <= -100) || (antpower >= 20)) ++ { ++ return 0; ++ } ++ else if (antpower >= 0) ++ { ++ return 100; ++ } ++ else ++ { ++ return (100+antpower); ++ } ++ ++} /* QueryRxPwrPercentage */ ++ ++static u8 ++rtl819x_evm_dbtopercentage( ++ char value ++ ) ++{ ++ char ret_val; ++ ++ ret_val = value; ++ ++ if(ret_val >= 0) ++ ret_val = 0; ++ if(ret_val <= -33) ++ ret_val = -33; ++ ret_val = 0 - ret_val; ++ ret_val*=3; ++ if(ret_val == 99) ++ ret_val = 100; ++ return(ret_val); ++} ++ ++// ++// Description: ++// We want good-looking for signal strength/quality ++// 2007/7/19 01:09, by cosa. ++// ++static long rtl819x_signal_scale_mapping(long currsig) ++{ ++ long retsig; ++ ++ // Step 1. Scale mapping. ++ if(currsig >= 61 && currsig <= 100) ++ { ++ retsig = 90 + ((currsig - 60) / 4); ++ } ++ else if(currsig >= 41 && currsig <= 60) ++ { ++ retsig = 78 + ((currsig - 40) / 2); ++ } ++ else if(currsig >= 31 && currsig <= 40) ++ { ++ retsig = 66 + (currsig - 30); ++ } ++ else if(currsig >= 21 && currsig <= 30) ++ { ++ retsig = 54 + (currsig - 20); ++ } ++ else if(currsig >= 5 && currsig <= 20) ++ { ++ retsig = 42 + (((currsig - 5) * 2) / 3); ++ } ++ else if(currsig == 4) ++ { ++ retsig = 36; ++ } ++ else if(currsig == 3) ++ { ++ retsig = 27; ++ } ++ else if(currsig == 2) ++ { ++ retsig = 18; ++ } ++ else if(currsig == 1) ++ { ++ retsig = 9; ++ } ++ else ++ { ++ retsig = currsig; ++ } ++ ++ return retsig; ++} ++ ++static void rtl8192_query_rxphystatus( ++ struct r8192_priv * priv, ++ struct ieee80211_rx_stats * pstats, ++ prx_desc_819x_pci pdesc, ++ prx_fwinfo_819x_pci pdrvinfo, ++ struct ieee80211_rx_stats * precord_stats, ++ bool bpacket_match_bssid, ++ bool bpacket_toself, ++ bool bPacketBeacon, ++ bool bToSelfBA ++ ) ++{ ++ //PRT_RFD_STATUS pRtRfdStatus = &(pRfd->Status); ++ phy_sts_ofdm_819xpci_t* pofdm_buf; ++ phy_sts_cck_819xpci_t * pcck_buf; ++ phy_ofdm_rx_status_rxsc_sgien_exintfflag* prxsc; ++ u8 *prxpkt; ++ u8 i,max_spatial_stream, tmp_rxsnr, tmp_rxevm, rxsc_sgien_exflg; ++ char rx_pwr[4], rx_pwr_all=0; ++ //long rx_avg_pwr = 0; ++ char rx_snrX, rx_evmX; ++ u8 evm, pwdb_all; ++ u32 RSSI, total_rssi=0;//, total_evm=0; ++// long signal_strength_index = 0; ++ u8 is_cck_rate=0; ++ u8 rf_rx_num = 0; ++ ++ /* 2007/07/04 MH For OFDM RSSI. For high power or not. */ ++ static u8 check_reg824 = 0; ++ static u32 reg824_bit9 = 0; ++ ++ priv->stats.numqry_phystatus++; ++ ++ is_cck_rate = rx_hal_is_cck_rate(pdrvinfo); ++ ++ // Record it for next packet processing ++ memset(precord_stats, 0, sizeof(struct ieee80211_rx_stats)); ++ pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID = bpacket_match_bssid; ++ pstats->bPacketToSelf = precord_stats->bPacketToSelf = bpacket_toself; ++ pstats->bIsCCK = precord_stats->bIsCCK = is_cck_rate;//RX_HAL_IS_CCK_RATE(pDrvInfo); ++ pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon; ++ pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA; ++ /*2007.08.30 requested by SD3 Jerry */ ++ if(check_reg824 == 0) ++ { ++ reg824_bit9 = rtl8192_QueryBBReg(priv->ieee80211->dev, rFPGA0_XA_HSSIParameter2, 0x200); ++ check_reg824 = 1; ++ } ++ ++ ++ prxpkt = (u8*)pdrvinfo; ++ ++ /* Move pointer to the 16th bytes. Phy status start address. */ ++ prxpkt += sizeof(rx_fwinfo_819x_pci); ++ ++ /* Initial the cck and ofdm buffer pointer */ ++ pcck_buf = (phy_sts_cck_819xpci_t *)prxpkt; ++ pofdm_buf = (phy_sts_ofdm_819xpci_t *)prxpkt; ++ ++ pstats->RxMIMOSignalQuality[0] = -1; ++ pstats->RxMIMOSignalQuality[1] = -1; ++ precord_stats->RxMIMOSignalQuality[0] = -1; ++ precord_stats->RxMIMOSignalQuality[1] = -1; ++ ++ if(is_cck_rate) ++ { ++ // ++ // (1)Hardware does not provide RSSI for CCK ++ // ++ ++ // ++ // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) ++ // ++ u8 report;//, cck_agc_rpt; ++#ifdef RTL8190P ++ u8 tmp_pwdb; ++ char cck_adc_pwdb[4]; ++#endif ++ priv->stats.numqry_phystatusCCK++; ++ ++#ifdef RTL8190P //Only 90P 2T4R need to check ++ if(priv->rf_type == RF_2T4R && DM_RxPathSelTable.Enable && bpacket_match_bssid) ++ { ++ for(i=RF90_PATH_A; iadc_pwdb_X[i]; ++ cck_adc_pwdb[i] = (char)tmp_pwdb; ++ cck_adc_pwdb[i] /= 2; ++ pstats->cck_adc_pwdb[i] = precord_stats->cck_adc_pwdb[i] = cck_adc_pwdb[i]; ++ //DbgPrint("RF-%d tmp_pwdb = 0x%x, cck_adc_pwdb = %d", i, tmp_pwdb, cck_adc_pwdb[i]); ++ } ++ } ++#endif ++ ++ if(!reg824_bit9) ++ { ++ report = pcck_buf->cck_agc_rpt & 0xc0; ++ report = report>>6; ++ switch(report) ++ { ++ //Fixed by Jacken from Bryant 2008-03-20 ++ //Original value is -38 , -26 , -14 , -2 ++ //Fixed value is -35 , -23 , -11 , 6 ++ case 0x3: ++ rx_pwr_all = -35 - (pcck_buf->cck_agc_rpt & 0x3e); ++ break; ++ case 0x2: ++ rx_pwr_all = -23 - (pcck_buf->cck_agc_rpt & 0x3e); ++ break; ++ case 0x1: ++ rx_pwr_all = -11 - (pcck_buf->cck_agc_rpt & 0x3e); ++ break; ++ case 0x0: ++ rx_pwr_all = 8 - (pcck_buf->cck_agc_rpt & 0x3e); ++ break; ++ } ++ } ++ else ++ { ++ report = pcck_buf->cck_agc_rpt & 0x60; ++ report = report>>5; ++ switch(report) ++ { ++ case 0x3: ++ rx_pwr_all = -35 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; ++ break; ++ case 0x2: ++ rx_pwr_all = -23 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1); ++ break; ++ case 0x1: ++ rx_pwr_all = -11 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; ++ break; ++ case 0x0: ++ rx_pwr_all = -8 - ((pcck_buf->cck_agc_rpt & 0x1f)<<1) ; ++ break; ++ } ++ } ++ ++ pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); ++ pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; ++ pstats->RecvSignalPower = rx_pwr_all; ++ ++ // ++ // (3) Get Signal Quality (EVM) ++ // ++ if(bpacket_match_bssid) ++ { ++ u8 sq; ++ ++ if(pstats->RxPWDBAll > 40) ++ { ++ sq = 100; ++ }else ++ { ++ sq = pcck_buf->sq_rpt; ++ ++ if(pcck_buf->sq_rpt > 64) ++ sq = 0; ++ else if (pcck_buf->sq_rpt < 20) ++ sq = 100; ++ else ++ sq = ((64-sq) * 100) / 44; ++ } ++ pstats->SignalQuality = precord_stats->SignalQuality = sq; ++ pstats->RxMIMOSignalQuality[0] = precord_stats->RxMIMOSignalQuality[0] = sq; ++ pstats->RxMIMOSignalQuality[1] = precord_stats->RxMIMOSignalQuality[1] = -1; ++ } ++ } ++ else ++ { ++ priv->stats.numqry_phystatusHT++; ++ // ++ // (1)Get RSSI for HT rate ++ // ++ for(i=RF90_PATH_A; ibrfpath_rxenable[i]) ++ rf_rx_num++; ++ //else ++ //continue; ++ ++ //Fixed by Jacken from Bryant 2008-03-20 ++ //Original value is 106 ++#ifdef RTL8190P //Modify by Jacken 2008/03/31 ++ rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i]&0x3F)*2) - 106; ++#else ++ rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i]&0x3F)*2) - 110; ++#endif ++ ++ //Get Rx snr value in DB ++ tmp_rxsnr = pofdm_buf->rxsnr_X[i]; ++ rx_snrX = (char)(tmp_rxsnr); ++ rx_snrX /= 2; ++ priv->stats.rxSNRdB[i] = (long)rx_snrX; ++ ++ /* Translate DBM to percentage. */ ++ RSSI = rtl819x_query_rxpwrpercentage(rx_pwr[i]); ++ if (priv->brfpath_rxenable[i]) ++ total_rssi += RSSI; ++ ++ /* Record Signal Strength for next packet */ ++ if(bpacket_match_bssid) ++ { ++ pstats->RxMIMOSignalStrength[i] =(u8) RSSI; ++ precord_stats->RxMIMOSignalStrength[i] =(u8) RSSI; ++ } ++ } ++ ++ ++ // ++ // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) ++ // ++ //Fixed by Jacken from Bryant 2008-03-20 ++ //Original value is 106 ++ rx_pwr_all = (((pofdm_buf->pwdb_all ) >> 1 )& 0x7f) -106; ++ pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); ++ ++ pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; ++ pstats->RxPower = precord_stats->RxPower = rx_pwr_all; ++ pstats->RecvSignalPower = rx_pwr_all; ++ // ++ // (3)EVM of HT rate ++ // ++ if(pdrvinfo->RxHT && pdrvinfo->RxRate>=DESC90_RATEMCS8 && ++ pdrvinfo->RxRate<=DESC90_RATEMCS15) ++ max_spatial_stream = 2; //both spatial stream make sense ++ else ++ max_spatial_stream = 1; //only spatial stream 1 makes sense ++ ++ for(i=0; irxevm_X[i]; ++ rx_evmX = (char)(tmp_rxevm); ++ ++ // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment ++ // fill most significant bit to "zero" when doing shifting operation which may change a negative ++ // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. ++ rx_evmX /= 2; //dbm ++ ++ evm = rtl819x_evm_dbtopercentage(rx_evmX); ++#if 0 ++ EVM = SignalScaleMapping(EVM);//make it good looking, from 0~100 ++#endif ++ if(bpacket_match_bssid) ++ { ++ if(i==0) // Fill value in RFD, Get the first spatial stream only ++ pstats->SignalQuality = precord_stats->SignalQuality = (u8)(evm & 0xff); ++ pstats->RxMIMOSignalQuality[i] = precord_stats->RxMIMOSignalQuality[i] = (u8)(evm & 0xff); ++ } ++ } ++ ++ ++ /* record rx statistics for debug */ ++ rxsc_sgien_exflg = pofdm_buf->rxsc_sgien_exflg; ++ prxsc = (phy_ofdm_rx_status_rxsc_sgien_exintfflag *)&rxsc_sgien_exflg; ++ if(pdrvinfo->BW) //40M channel ++ priv->stats.received_bwtype[1+prxsc->rxsc]++; ++ else //20M channel ++ priv->stats.received_bwtype[0]++; ++ } ++ ++ //UI BSS List signal strength(in percentage), make it good looking, from 0~100. ++ //It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). ++ if(is_cck_rate) ++ { ++ pstats->SignalStrength = precord_stats->SignalStrength = (u8)(rtl819x_signal_scale_mapping((long)pwdb_all));//PWDB_ALL; ++ ++ } ++ else ++ { ++ //pRfd->Status.SignalStrength = pRecordRfd->Status.SignalStrength = (u1Byte)(SignalScaleMapping(total_rssi/=RF90_PATH_MAX));//(u1Byte)(total_rssi/=RF90_PATH_MAX); ++ // We can judge RX path number now. ++ if (rf_rx_num != 0) ++ pstats->SignalStrength = precord_stats->SignalStrength = (u8)(rtl819x_signal_scale_mapping((long)(total_rssi/=rf_rx_num))); ++ } ++} /* QueryRxPhyStatus8190Pci */ ++ ++static void ++rtl8192_record_rxdesc_forlateruse( ++ struct ieee80211_rx_stats * psrc_stats, ++ struct ieee80211_rx_stats * ptarget_stats ++) ++{ ++ ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; ++ ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; ++ //ptarget_stats->Seq_Num = psrc_stats->Seq_Num; ++} ++ ++ ++ ++static void TranslateRxSignalStuff819xpci(struct net_device *dev, ++ struct sk_buff *skb, ++ struct ieee80211_rx_stats * pstats, ++ prx_desc_819x_pci pdesc, ++ prx_fwinfo_819x_pci pdrvinfo) ++{ ++ // TODO: We must only check packet for current MAC address. Not finish ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ bool bpacket_match_bssid, bpacket_toself; ++ bool bPacketBeacon=false, bToSelfBA=false; ++ static struct ieee80211_rx_stats previous_stats; ++ struct ieee80211_hdr_3addr *hdr; ++ u16 fc,type; ++ ++ // Get Signal Quality for only RX data queue (but not command queue) ++ ++ u8* tmp_buf; ++ u8 *praddr; ++ ++ /* Get MAC frame start address. */ ++ tmp_buf = skb->data; ++ ++ hdr = (struct ieee80211_hdr_3addr *)tmp_buf; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ type = WLAN_FC_GET_TYPE(fc); ++ praddr = hdr->addr1; ++ ++ /* Check if the received packet is acceptabe. */ ++ bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) && ++ (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) ++ && (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV)); ++ bpacket_toself = bpacket_match_bssid & (eqMacAddr(praddr, priv->ieee80211->dev->dev_addr)); ++#if 1//cosa ++ if(WLAN_FC_GET_FRAMETYPE(fc)== IEEE80211_STYPE_BEACON) ++ { ++ bPacketBeacon = true; ++ //DbgPrint("Beacon 2, MatchBSSID = %d, ToSelf = %d \n", bPacketMatchBSSID, bPacketToSelf); ++ } ++ if(WLAN_FC_GET_FRAMETYPE(fc) == IEEE80211_STYPE_BLOCKACK) ++ { ++ if((eqMacAddr(praddr,dev->dev_addr))) ++ bToSelfBA = true; ++ //DbgPrint("BlockAck, MatchBSSID = %d, ToSelf = %d \n", bPacketMatchBSSID, bPacketToSelf); ++ } ++ ++#endif ++ if(bpacket_match_bssid) ++ { ++ priv->stats.numpacket_matchbssid++; ++ } ++ if(bpacket_toself){ ++ priv->stats.numpacket_toself++; ++ } ++ // ++ // Process PHY information for previous packet (RSSI/PWDB/EVM) ++ // ++ // Because phy information is contained in the last packet of AMPDU only, so driver ++ // should process phy information of previous packet ++ rtl8192_process_phyinfo(priv, tmp_buf,&previous_stats, pstats); ++ rtl8192_query_rxphystatus(priv, pstats, pdesc, pdrvinfo, &previous_stats, bpacket_match_bssid, ++ bpacket_toself ,bPacketBeacon, bToSelfBA); ++ rtl8192_record_rxdesc_forlateruse(pstats, &previous_stats); ++ ++} ++ ++ ++static void rtl8192_tx_resume(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ struct sk_buff *skb; ++ int queue_index; ++ ++ for(queue_index = BK_QUEUE; queue_index < TXCMD_QUEUE;queue_index++) { ++ while((!skb_queue_empty(&ieee->skb_waitQ[queue_index]))&& ++ (priv->ieee80211->check_nic_enough_desc(dev,queue_index) > 0)) { ++ /* 1. dequeue the packet from the wait queue */ ++ skb = skb_dequeue(&ieee->skb_waitQ[queue_index]); ++ /* 2. tx the packet directly */ ++ ieee->softmac_data_hard_start_xmit(skb,dev,0/* rate useless now*/); ++ #if 0 ++ if(queue_index!=MGNT_QUEUE) { ++ ieee->stats.tx_packets++; ++ ieee->stats.tx_bytes += skb->len; ++ } ++ #endif ++ } ++ } ++} ++ ++void rtl8192_irq_tx_tasklet(struct r8192_priv *priv) ++{ ++ rtl8192_tx_resume(priv->ieee80211->dev); ++} ++ ++/** ++* Function: UpdateReceivedRateHistogramStatistics ++* Overview: Recored down the received data rate ++* ++* Input: ++* PADAPTER Adapter ++* PRT_RFD pRfd, ++* ++* Output: ++* PRT_TCB Adapter ++* (Adapter->RxStats.ReceivedRateHistogram[] is updated) ++* Return: ++* None ++*/ ++static void UpdateReceivedRateHistogramStatistics8190( ++ struct net_device *dev, ++ struct ieee80211_rx_stats* pstats ++ ) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ u32 rcvType=1; //0: Total, 1:OK, 2:CRC, 3:ICV ++ u32 rateIndex; ++ u32 preamble_guardinterval; //1: short preamble/GI, 0: long preamble/GI ++ ++ /* 2007/03/09 MH We will not update rate of packet from rx cmd queue. */ ++ #if 0 ++ if (pRfd->queue_id == CMPK_RX_QUEUE_ID) ++ return; ++ #endif ++ if(pstats->bCRC) ++ rcvType = 2; ++ else if(pstats->bICV) ++ rcvType = 3; ++ ++ if(pstats->bShortPreamble) ++ preamble_guardinterval = 1;// short ++ else ++ preamble_guardinterval = 0;// long ++ ++ switch(pstats->rate) ++ { ++ // ++ // CCK rate ++ // ++ case MGN_1M: rateIndex = 0; break; ++ case MGN_2M: rateIndex = 1; break; ++ case MGN_5_5M: rateIndex = 2; break; ++ case MGN_11M: rateIndex = 3; break; ++ // ++ // Legacy OFDM rate ++ // ++ case MGN_6M: rateIndex = 4; break; ++ case MGN_9M: rateIndex = 5; break; ++ case MGN_12M: rateIndex = 6; break; ++ case MGN_18M: rateIndex = 7; break; ++ case MGN_24M: rateIndex = 8; break; ++ case MGN_36M: rateIndex = 9; break; ++ case MGN_48M: rateIndex = 10; break; ++ case MGN_54M: rateIndex = 11; break; ++ // ++ // 11n High throughput rate ++ // ++ case MGN_MCS0: rateIndex = 12; break; ++ case MGN_MCS1: rateIndex = 13; break; ++ case MGN_MCS2: rateIndex = 14; break; ++ case MGN_MCS3: rateIndex = 15; break; ++ case MGN_MCS4: rateIndex = 16; break; ++ case MGN_MCS5: rateIndex = 17; break; ++ case MGN_MCS6: rateIndex = 18; break; ++ case MGN_MCS7: rateIndex = 19; break; ++ case MGN_MCS8: rateIndex = 20; break; ++ case MGN_MCS9: rateIndex = 21; break; ++ case MGN_MCS10: rateIndex = 22; break; ++ case MGN_MCS11: rateIndex = 23; break; ++ case MGN_MCS12: rateIndex = 24; break; ++ case MGN_MCS13: rateIndex = 25; break; ++ case MGN_MCS14: rateIndex = 26; break; ++ case MGN_MCS15: rateIndex = 27; break; ++ default: rateIndex = 28; break; ++ } ++ priv->stats.received_preamble_GI[preamble_guardinterval][rateIndex]++; ++ priv->stats.received_rate_histogram[0][rateIndex]++; //total ++ priv->stats.received_rate_histogram[rcvType][rateIndex]++; ++} ++ ++static void rtl8192_rx(struct net_device *dev) ++{ ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ struct ieee80211_hdr_1addr *ieee80211_hdr = NULL; ++ bool unicast_packet = false; ++ struct ieee80211_rx_stats stats = { ++ .signal = 0, ++ .noise = -98, ++ .rate = 0, ++ .freq = IEEE80211_24GHZ_BAND, ++ }; ++ unsigned int count = priv->rxringcount; ++ ++ stats.nic_type = NIC_8192E; ++ ++ while (count--) { ++ rx_desc_819x_pci *pdesc = &priv->rx_ring[priv->rx_idx];//rx descriptor ++ struct sk_buff *skb = priv->rx_buf[priv->rx_idx];//rx pkt ++ ++ if (pdesc->OWN){ ++ /* wait data to be filled by hardware */ ++ return; ++ } else { ++ stats.bICV = pdesc->ICV; ++ stats.bCRC = pdesc->CRC32; ++ stats.bHwError = pdesc->CRC32 | pdesc->ICV; ++ ++ stats.Length = pdesc->Length; ++ if(stats.Length < 24) ++ stats.bHwError |= 1; ++ ++ if(stats.bHwError) { ++ stats.bShift = false; ++ ++ if(pdesc->CRC32) { ++ if (pdesc->Length <500) ++ priv->stats.rxcrcerrmin++; ++ else if (pdesc->Length >1000) ++ priv->stats.rxcrcerrmax++; ++ else ++ priv->stats.rxcrcerrmid++; ++ } ++ goto done; ++ } else { ++ prx_fwinfo_819x_pci pDrvInfo = NULL; ++ struct sk_buff *new_skb = dev_alloc_skb(priv->rxbuffersize); ++ ++ if (unlikely(!new_skb)) { ++ goto done; ++ } ++ ++ stats.RxDrvInfoSize = pdesc->RxDrvInfoSize; ++ stats.RxBufShift = ((pdesc->Shift)&0x03); ++ stats.Decrypted = !pdesc->SWDec; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ pci_dma_sync_single_for_cpu(priv->pdev, ++#else ++ pci_unmap_single(priv->pdev, ++#endif ++ *((dma_addr_t *)skb->cb), ++ priv->rxbuffersize, ++ PCI_DMA_FROMDEVICE); ++ skb_put(skb, pdesc->Length); ++ pDrvInfo = (rx_fwinfo_819x_pci *)(skb->data + stats.RxBufShift); ++ skb_reserve(skb, stats.RxDrvInfoSize + stats.RxBufShift); ++ ++ stats.rate = HwRateToMRate90((bool)pDrvInfo->RxHT, (u8)pDrvInfo->RxRate); ++ stats.bShortPreamble = pDrvInfo->SPLCP; ++ ++ /* it is debug only. It should be disabled in released driver. ++ * 2007.1.11 by Emily ++ * */ ++ UpdateReceivedRateHistogramStatistics8190(dev, &stats); ++ ++ stats.bIsAMPDU = (pDrvInfo->PartAggr==1); ++ stats.bFirstMPDU = (pDrvInfo->PartAggr==1) && (pDrvInfo->FirstAGGR==1); ++ ++ stats.TimeStampLow = pDrvInfo->TSFL; ++ stats.TimeStampHigh = read_nic_dword(dev, TSFR+4); ++ ++ UpdateRxPktTimeStamp8190(dev, &stats); ++ ++ // ++ // Get Total offset of MPDU Frame Body ++ // ++ if((stats.RxBufShift + stats.RxDrvInfoSize) > 0) ++ stats.bShift = 1; ++ ++ stats.RxIs40MHzPacket = pDrvInfo->BW; ++ ++ /* ???? */ ++ TranslateRxSignalStuff819xpci(dev,skb, &stats, pdesc, pDrvInfo); ++ ++ /* Rx A-MPDU */ ++ if(pDrvInfo->FirstAGGR==1 || pDrvInfo->PartAggr == 1) ++ RT_TRACE(COMP_RXDESC, "pDrvInfo->FirstAGGR = %d, pDrvInfo->PartAggr = %d\n", ++ pDrvInfo->FirstAGGR, pDrvInfo->PartAggr); ++ skb_trim(skb, skb->len - 4/*sCrcLng*/); ++ /* rx packets statistics */ ++ ieee80211_hdr = (struct ieee80211_hdr_1addr *)skb->data; ++ unicast_packet = false; ++ ++ if(is_broadcast_ether_addr(ieee80211_hdr->addr1)) { ++ //TODO ++ }else if(is_multicast_ether_addr(ieee80211_hdr->addr1)){ ++ //TODO ++ }else { ++ /* unicast packet */ ++ unicast_packet = true; ++ } ++ ++ stats.packetlength = stats.Length-4; ++ stats.fraglength = stats.packetlength; ++ stats.fragoffset = 0; ++ stats.ntotalfrag = 1; ++ ++ if(!ieee80211_rx(priv->ieee80211, skb, &stats)){ ++ dev_kfree_skb_any(skb); ++ } else { ++ priv->stats.rxok++; ++ if(unicast_packet) { ++ priv->stats.rxbytesunicast += skb->len; ++ } ++ } ++ ++ skb = new_skb; ++ priv->rx_buf[priv->rx_idx] = skb; ++ *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb->tail, priv->rxbuffersize, PCI_DMA_FROMDEVICE); ++// *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, skb_tail_pointer(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE); ++ } ++ ++ } ++done: ++ pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); ++ pdesc->OWN = 1; ++ pdesc->Length = priv->rxbuffersize; ++ if (priv->rx_idx == priv->rxringcount-1) ++ pdesc->EOR = 1; ++ priv->rx_idx = (priv->rx_idx + 1) % priv->rxringcount; ++ } ++ ++} ++ ++void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) ++{ ++ rtl8192_rx(priv->ieee80211->dev); ++ /* unmask RDU */ ++ write_nic_dword(priv->ieee80211->dev, INTA_MASK,read_nic_dword(priv->ieee80211->dev, INTA_MASK) | IMR_RDU); ++} ++ ++static const struct net_device_ops rtl8192_netdev_ops = { ++ .ndo_open = rtl8192_open, ++ .ndo_stop = rtl8192_close, ++/* .ndo_get_stats = rtl8192_stats, */ ++ .ndo_tx_timeout = tx_timeout, ++ .ndo_do_ioctl = rtl8192_ioctl, ++ .ndo_set_multicast_list = r8192_set_multicast, ++ .ndo_set_mac_address = r8192_set_mac_adr, ++ .ndo_start_xmit = ieee80211_xmit, ++}; ++ ++/**************************************************************************** ++ ---------------------------- PCI_STUFF--------------------------- ++*****************************************************************************/ ++ ++static int __devinit rtl8192_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ unsigned long ioaddr = 0; ++ struct net_device *dev = NULL; ++ struct r8192_priv *priv= NULL; ++ u8 unit = 0; ++ ++#ifdef CONFIG_RTL8192_IO_MAP ++ unsigned long pio_start, pio_len, pio_flags; ++#else ++ unsigned long pmem_start, pmem_len, pmem_flags; ++#endif //end #ifdef RTL_IO_MAP ++ ++ RT_TRACE(COMP_INIT,"Configuring chip resources"); ++ ++ if( pci_enable_device (pdev) ){ ++ RT_TRACE(COMP_ERR,"Failed to enable PCI device"); ++ return -EIO; ++ } ++ ++ pci_set_master(pdev); ++ //pci_set_wmi(pdev); ++ pci_set_dma_mask(pdev, 0xffffff00ULL); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ pci_set_consistent_dma_mask(pdev,0xffffff00ULL); ++#endif ++ dev = alloc_ieee80211(sizeof(struct r8192_priv)); ++ if (!dev) ++ return -ENOMEM; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(dev); ++#endif ++ ++ pci_set_drvdata(pdev, dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ SET_NETDEV_DEV(dev, &pdev->dev); ++#endif ++ priv = ieee80211_priv(dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ priv->ieee80211 = netdev_priv(dev); ++#else ++ priv->ieee80211 = (struct ieee80211_device *)dev->priv; ++#endif ++ priv->pdev=pdev; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ if((pdev->subsystem_vendor == PCI_VENDOR_ID_DLINK)&&(pdev->subsystem_device == 0x3304)){ ++ priv->ieee80211->bSupportRemoteWakeUp = 1; ++ } else ++#endif ++ { ++ priv->ieee80211->bSupportRemoteWakeUp = 0; ++ } ++ ++#ifdef CONFIG_RTL8192_IO_MAP ++ ++ pio_start = (unsigned long)pci_resource_start (pdev, 0); ++ pio_len = (unsigned long)pci_resource_len (pdev, 0); ++ pio_flags = (unsigned long)pci_resource_flags (pdev, 0); ++ ++ if (!(pio_flags & IORESOURCE_IO)) { ++ RT_TRACE(COMP_ERR,"region #0 not a PIO resource, aborting"); ++ goto fail; ++ } ++ ++ //DMESG("IO space @ 0x%08lx", pio_start ); ++ if( ! request_region( pio_start, pio_len, RTL819xE_MODULE_NAME ) ){ ++ RT_TRACE(COMP_ERR,"request_region failed!"); ++ goto fail; ++ } ++ ++ ioaddr = pio_start; ++ dev->base_addr = ioaddr; // device I/O address ++ ++#else ++ ++ pmem_start = pci_resource_start(pdev, 1); ++ pmem_len = pci_resource_len(pdev, 1); ++ pmem_flags = pci_resource_flags (pdev, 1); ++ ++ if (!(pmem_flags & IORESOURCE_MEM)) { ++ RT_TRACE(COMP_ERR,"region #1 not a MMIO resource, aborting"); ++ goto fail; ++ } ++ ++ //DMESG("Memory mapped space @ 0x%08lx ", pmem_start); ++ if( ! request_mem_region(pmem_start, pmem_len, RTL819xE_MODULE_NAME)) { ++ RT_TRACE(COMP_ERR,"request_mem_region failed!"); ++ goto fail; ++ } ++ ++ ++ ioaddr = (unsigned long)ioremap_nocache( pmem_start, pmem_len); ++ if( ioaddr == (unsigned long)NULL ){ ++ RT_TRACE(COMP_ERR,"ioremap failed!"); ++ // release_mem_region( pmem_start, pmem_len ); ++ goto fail1; ++ } ++ ++ dev->mem_start = ioaddr; // shared mem start ++ dev->mem_end = ioaddr + pci_resource_len(pdev, 0); // shared mem end ++ ++#endif //end #ifdef RTL_IO_MAP ++ ++ /* We disable the RETRY_TIMEOUT register (0x41) to keep ++ * PCI Tx retries from interfering with C3 CPU state */ ++ pci_write_config_byte(pdev, 0x41, 0x00); ++ ++ ++ pci_read_config_byte(pdev, 0x05, &unit); ++ pci_write_config_byte(pdev, 0x05, unit & (~0x04)); ++ ++ dev->irq = pdev->irq; ++ priv->irq = 0; ++ ++ dev->netdev_ops = &rtl8192_netdev_ops; ++#if 0 ++ dev->open = rtl8192_open; ++ dev->stop = rtl8192_close; ++ //dev->hard_start_xmit = rtl8192_8023_hard_start_xmit; ++ dev->tx_timeout = tx_timeout; ++ //dev->wireless_handlers = &r8192_wx_handlers_def; ++ dev->do_ioctl = rtl8192_ioctl; ++ dev->set_multicast_list = r8192_set_multicast; ++ dev->set_mac_address = r8192_set_mac_adr; ++#endif ++ ++ //DMESG("Oops: i'm coming\n"); ++#if WIRELESS_EXT >= 12 ++#if WIRELESS_EXT < 17 ++ dev->get_wireless_stats = r8192_get_wireless_stats; ++#endif ++ dev->wireless_handlers = (struct iw_handler_def *) &r8192_wx_handlers_def; ++#endif ++ //dev->get_wireless_stats = r8192_get_wireless_stats; ++ dev->type=ARPHRD_ETHER; ++ ++ dev->watchdog_timeo = HZ*3; //modified by john, 0805 ++ ++ if (dev_alloc_name(dev, ifname) < 0){ ++ RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n"); ++ ifname = "wlan%d"; ++ dev_alloc_name(dev, ifname); ++ } ++ ++ RT_TRACE(COMP_INIT, "Driver probe completed1\n"); ++ if(rtl8192_init(dev)!=0){ ++ RT_TRACE(COMP_ERR, "Initialization failed"); ++ goto fail; ++ } ++ ++ netif_carrier_off(dev); ++ netif_stop_queue(dev); ++ ++ register_netdev(dev); ++ RT_TRACE(COMP_INIT, "dev name=======> %s\n",dev->name); ++ rtl8192_proc_init_one(dev); ++ ++ ++ RT_TRACE(COMP_INIT, "Driver probe completed\n"); ++//#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++// return dev; ++//#else ++ return 0; ++//#endif ++ ++fail1: ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ ++ if( dev->base_addr != 0 ){ ++ ++ release_region(dev->base_addr, ++ pci_resource_len(pdev, 0) ); ++ } ++#else ++ if( dev->mem_start != (unsigned long)NULL ){ ++ iounmap( (void *)dev->mem_start ); ++ release_mem_region( pci_resource_start(pdev, 1), ++ pci_resource_len(pdev, 1) ); ++ } ++#endif //end #ifdef RTL_IO_MAP ++ ++fail: ++ if(dev){ ++ ++ if (priv->irq) { ++ free_irq(dev->irq, dev); ++ dev->irq=0; ++ } ++ free_ieee80211(dev); ++ } ++ ++ pci_disable_device(pdev); ++ ++ DMESG("wlan driver load failed\n"); ++ pci_set_drvdata(pdev, NULL); ++ return -ENODEV; ++ ++} ++ ++/* detach all the work and timer structure declared or inititialized ++ * in r8192_init function. ++ * */ ++void rtl8192_cancel_deferred_work(struct r8192_priv* priv) ++{ ++ /* call cancel_work_sync instead of cancel_delayed_work if and only if Linux_version_code ++ * is or is newer than 2.6.20 and work structure is defined to be struct work_struct. ++ * Otherwise call cancel_delayed_work is enough. ++ * FIXME (2.6.20 shoud 2.6.22, work_struct shoud not cancel) ++ * */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&priv->watch_dog_wq); ++ cancel_delayed_work(&priv->update_beacon_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); ++#ifdef RTL8192E ++ cancel_delayed_work(&priv->gpio_change_rf_wq); ++#endif ++#endif ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,22) ++ cancel_work_sync(&priv->reset_wq); ++ cancel_work_sync(&priv->qos_activate); ++ //cancel_work_sync(&priv->SetBWModeWorkItem); ++ //cancel_work_sync(&priv->SwChnlWorkItem); ++#else ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&priv->reset_wq); ++ cancel_delayed_work(&priv->qos_activate); ++ //cancel_delayed_work(&priv->SetBWModeWorkItem); ++ //cancel_delayed_work(&priv->SwChnlWorkItem); ++#endif ++#endif ++ ++} ++ ++ ++static void __devexit rtl8192_pci_disconnect(struct pci_dev *pdev) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++ struct r8192_priv *priv ; ++ ++ if(dev){ ++ ++ unregister_netdev(dev); ++ ++ priv=ieee80211_priv(dev); ++ ++ rtl8192_proc_remove_one(dev); ++ ++ rtl8192_down(dev); ++ if (priv->pFirmware) ++ { ++ vfree(priv->pFirmware); ++ priv->pFirmware = NULL; ++ } ++ // priv->rf_close(dev); ++ // rtl8192_usb_deleteendpoints(dev); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ destroy_workqueue(priv->priv_wq); ++#endif ++ /* redundant with rtl8192_down */ ++ // rtl8192_irq_disable(dev); ++ // rtl8192_reset(dev); ++ // mdelay(10); ++ { ++ u32 i; ++ /* free tx/rx rings */ ++ rtl8192_free_rx_ring(dev); ++ for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { ++ rtl8192_free_tx_ring(dev, i); ++ } ++ } ++ if(priv->irq){ ++ ++ printk("Freeing irq %d\n",dev->irq); ++ free_irq(dev->irq, dev); ++ priv->irq=0; ++ ++ } ++ ++ ++ ++ // free_beacon_desc_ring(dev,priv->txbeaconcount); ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ ++ if( dev->base_addr != 0 ){ ++ ++ release_region(dev->base_addr, ++ pci_resource_len(pdev, 0) ); ++ } ++#else ++ if( dev->mem_start != (unsigned long)NULL ){ ++ iounmap( (void *)dev->mem_start ); ++ release_mem_region( pci_resource_start(pdev, 1), ++ pci_resource_len(pdev, 1) ); ++ } ++#endif /*end #ifdef RTL_IO_MAP*/ ++ free_ieee80211(dev); ++ ++ } ++ ++ pci_disable_device(pdev); ++ RT_TRACE(COMP_DOWN, "wlan driver removed\n"); ++} ++ ++extern int ieee80211_init(void); ++extern void ieee80211_exit(void); ++ ++static int __init rtl8192_pci_module_init(void) ++{ ++ int retval; ++ ++ retval = ieee80211_init(); ++ if (retval) ++ return retval; ++ ++ printk(KERN_INFO "\nLinux kernel driver for RTL8192 based WLAN cards\n"); ++ printk(KERN_INFO "Copyright (c) 2007-2008, Realsil Wlan\n"); ++ RT_TRACE(COMP_INIT, "Initializing module"); ++ RT_TRACE(COMP_INIT, "Wireless extensions version %d", WIRELESS_EXT); ++ rtl8192_proc_module_init(); ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) ++ if(0!=pci_module_init(&rtl8192_pci_driver)) ++#else ++ if(0!=pci_register_driver(&rtl8192_pci_driver)) ++#endif ++ { ++ DMESG("No device found"); ++ /*pci_unregister_driver (&rtl8192_pci_driver);*/ ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++ ++static void __exit rtl8192_pci_module_exit(void) ++{ ++ pci_unregister_driver(&rtl8192_pci_driver); ++ ++ RT_TRACE(COMP_DOWN, "Exiting"); ++ rtl8192_proc_module_remove(); ++ ieee80211_exit(); ++} ++ ++//warning message WB ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++void rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs) ++#else ++irqreturn_t rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs) ++#endif ++#else ++irqreturn_t rtl8192_interrupt(int irq, void *netdev) ++#endif ++{ ++ struct net_device *dev = (struct net_device *) netdev; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ unsigned long flags; ++ u32 inta; ++ /* We should return IRQ_NONE, but for now let me keep this */ ++ if(priv->irq_enabled == 0){ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return; ++#else ++ return IRQ_HANDLED; ++#endif ++ } ++ ++ spin_lock_irqsave(&priv->irq_th_lock,flags); ++ ++ //ISR: 4bytes ++ ++ inta = read_nic_dword(dev, ISR);// & priv->IntrMask; ++ write_nic_dword(dev,ISR,inta); // reset int situation ++ ++ priv->stats.shints++; ++ //DMESG("Enter interrupt, ISR value = 0x%08x", inta); ++ if(!inta){ ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return; ++#else ++ return IRQ_HANDLED; ++#endif ++ /* ++ most probably we can safely return IRQ_NONE, ++ but for now is better to avoid problems ++ */ ++ } ++ ++ if(inta == 0xffff){ ++ /* HW disappared */ ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return; ++#else ++ return IRQ_HANDLED; ++#endif ++ } ++ ++ priv->stats.ints++; ++#ifdef DEBUG_IRQ ++ DMESG("NIC irq %x",inta); ++#endif ++ //priv->irqpending = inta; ++ ++ ++ if(!netif_running(dev)) { ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return; ++#else ++ return IRQ_HANDLED; ++#endif ++ } ++ ++ if(inta & IMR_TIMEOUT0){ ++ // write_nic_dword(dev, TimerInt, 0); ++ //DMESG("=================>waking up"); ++ // rtl8180_hw_wakeup(dev); ++ } ++ ++ if(inta & IMR_TBDOK){ ++ RT_TRACE(COMP_INTR, "beacon ok interrupt!\n"); ++ rtl8192_tx_isr(dev, BEACON_QUEUE); ++ priv->stats.txbeaconokint++; ++ } ++ ++ if(inta & IMR_TBDER){ ++ RT_TRACE(COMP_INTR, "beacon ok interrupt!\n"); ++ rtl8192_tx_isr(dev, BEACON_QUEUE); ++ priv->stats.txbeaconerr++; ++ } ++ ++ if(inta & IMR_MGNTDOK ) { ++ RT_TRACE(COMP_INTR, "Manage ok interrupt!\n"); ++ priv->stats.txmanageokint++; ++ rtl8192_tx_isr(dev,MGNT_QUEUE); ++ ++ } ++ ++ if(inta & IMR_COMDOK) ++ { ++ priv->stats.txcmdpktokint++; ++ rtl8192_tx_isr(dev,TXCMD_QUEUE); ++ } ++ ++ if(inta & IMR_ROK){ ++#ifdef DEBUG_RX ++ DMESG("Frame arrived !"); ++#endif ++ priv->stats.rxint++; ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ } ++ ++ if(inta & IMR_BcnInt) { ++ RT_TRACE(COMP_INTR, "prepare beacon for interrupt!\n"); ++ tasklet_schedule(&priv->irq_prepare_beacon_tasklet); ++ } ++ ++ if(inta & IMR_RDU){ ++ RT_TRACE(COMP_INTR, "rx descriptor unavailable!\n"); ++ priv->stats.rxrdu++; ++ /* reset int situation */ ++ write_nic_dword(dev,INTA_MASK,read_nic_dword(dev, INTA_MASK) & ~IMR_RDU); ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ } ++ ++ if(inta & IMR_RXFOVW){ ++ RT_TRACE(COMP_INTR, "rx overflow !\n"); ++ priv->stats.rxoverflow++; ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ } ++ ++ if(inta & IMR_TXFOVW) priv->stats.txoverflow++; ++ ++ if(inta & IMR_BKDOK){ ++ RT_TRACE(COMP_INTR, "BK Tx OK interrupt!\n"); ++ priv->stats.txbkokint++; ++ priv->ieee80211->LinkDetectInfo.NumTxOkInPeriod++; ++ rtl8192_tx_isr(dev,BK_QUEUE); ++ rtl8192_try_wake_queue(dev, BK_QUEUE); ++ } ++ ++ if(inta & IMR_BEDOK){ ++ RT_TRACE(COMP_INTR, "BE TX OK interrupt!\n"); ++ priv->stats.txbeokint++; ++ priv->ieee80211->LinkDetectInfo.NumTxOkInPeriod++; ++ rtl8192_tx_isr(dev,BE_QUEUE); ++ rtl8192_try_wake_queue(dev, BE_QUEUE); ++ } ++ ++ if(inta & IMR_VIDOK){ ++ RT_TRACE(COMP_INTR, "VI TX OK interrupt!\n"); ++ priv->stats.txviokint++; ++ priv->ieee80211->LinkDetectInfo.NumTxOkInPeriod++; ++ rtl8192_tx_isr(dev,VI_QUEUE); ++ rtl8192_try_wake_queue(dev, VI_QUEUE); ++ } ++ ++ if(inta & IMR_VODOK){ ++ priv->stats.txvookint++; ++ priv->ieee80211->LinkDetectInfo.NumTxOkInPeriod++; ++ rtl8192_tx_isr(dev,VO_QUEUE); ++ rtl8192_try_wake_queue(dev, VO_QUEUE); ++ } ++ ++ force_pci_posting(dev); ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return; ++#else ++ return IRQ_HANDLED; ++#endif ++} ++ ++void rtl8192_try_wake_queue(struct net_device *dev, int pri) ++{ ++#if 0 ++ unsigned long flags; ++ short enough_desc; ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ enough_desc = check_nic_enough_desc(dev,pri); ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ if(enough_desc) ++ ieee80211_wake_queue(priv->ieee80211); ++#endif ++} ++ ++ ++void EnableHWSecurityConfig8192(struct net_device *dev) ++{ ++ u8 SECR_value = 0x0; ++ // struct ieee80211_device* ieee1 = container_of(&dev, struct ieee80211_device, dev); ++ //printk("==>ieee1:%p, dev:%p\n", ieee1, dev); ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ //printk("==>ieee:%p, dev:%p\n", ieee, dev); ++ SECR_value = SCR_TxEncEnable | SCR_RxDecEnable; ++#if 1 ++ if (((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) && (priv->ieee80211->auth_mode != 2)) ++ { ++ SECR_value |= SCR_RxUseDK; ++ SECR_value |= SCR_TxUseDK; ++ } ++ else if ((ieee->iw_mode == IW_MODE_ADHOC) && (ieee->pairwise_key_type & (KEY_TYPE_CCMP | KEY_TYPE_TKIP))) ++ { ++ SECR_value |= SCR_RxUseDK; ++ SECR_value |= SCR_TxUseDK; ++ } ++ ++#endif ++ ++ //add HWSec active enable here. ++//default using hwsec. when peer AP is in N mode only and pairwise_key_type is none_aes(which HT_IOT_ACT_PURE_N_MODE indicates it), use software security. when peer AP is in b,g,n mode mixed and pairwise_key_type is none_aes, use g mode hw security. WB on 2008.7.4 ++ ieee->hwsec_active = 1; ++ ++ if ((ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE) || !hwwep)//!ieee->hwsec_support) //add hwsec_support flag to totol control hw_sec on/off ++ { ++ ieee->hwsec_active = 0; ++ SECR_value &= ~SCR_RxDecEnable; ++ } ++ ++ RT_TRACE(COMP_SEC,"%s:, hwsec:%d, pairwise_key:%d, SECR_value:%x\n", __FUNCTION__, \ ++ ieee->hwsec_active, ieee->pairwise_key_type, SECR_value); ++ { ++ write_nic_byte(dev, SECR, SECR_value);//SECR_value | SCR_UseDK ); ++ } ++ ++} ++#define TOTAL_CAM_ENTRY 32 ++//#define CAM_CONTENT_COUNT 8 ++void setKey( struct net_device *dev, ++ u8 EntryNo, ++ u8 KeyIndex, ++ u16 KeyType, ++ u8 *MacAddr, ++ u8 DefaultKey, ++ u32 *KeyContent ) ++{ ++ u32 TargetCommand = 0; ++ u32 TargetContent = 0; ++ u16 usConfig = 0; ++ u8 i; ++#ifdef ENABLE_IPS ++ struct r8192_priv *priv = (struct r8192_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ rtState = priv->ieee80211->eRFPowerState; ++ if(priv->ieee80211->PowerSaveControl.bInactivePs){ ++ if(rtState == eRfOff){ ++ if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__); ++ up(&priv->wx_sem); ++ return ; ++ } ++ else{ ++ IPSLeave(dev); ++ } ++ } ++ } ++ priv->ieee80211->is_set_key = true; ++#endif ++ if (EntryNo >= TOTAL_CAM_ENTRY) ++ RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n"); ++ ++ RT_TRACE(COMP_SEC, "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr"MAC_FMT"\n", dev,EntryNo, KeyIndex, KeyType, MAC_ARG(MacAddr)); ++ ++ if (DefaultKey) ++ usConfig |= BIT15 | (KeyType<<2); ++ else ++ usConfig |= BIT15 | (KeyType<<2) | KeyIndex; ++// usConfig |= BIT15 | (KeyType<<2) | (DefaultKey<<5) | KeyIndex; ++ ++ ++ for(i=0 ; iafter set key, usconfig:%x\n", usConfig); ++} ++// This function seems not ready! WB ++void CamPrintDbgReg(struct net_device* dev) ++{ ++ unsigned long rvalue; ++ unsigned char ucValue; ++ write_nic_dword(dev, DCAM, 0x80000000); ++ msleep(40); ++ rvalue = read_nic_dword(dev, DCAM); //delay_ms(40); ++ RT_TRACE(COMP_SEC, " TX CAM=%8lX ",rvalue); ++ if((rvalue & 0x40000000) != 0x4000000) ++ RT_TRACE(COMP_SEC, "-->TX Key Not Found "); ++ msleep(20); ++ write_nic_dword(dev, DCAM, 0x00000000); //delay_ms(40); ++ rvalue = read_nic_dword(dev, DCAM); //delay_ms(40); ++ RT_TRACE(COMP_SEC, "RX CAM=%8lX ",rvalue); ++ if((rvalue & 0x40000000) != 0x4000000) ++ RT_TRACE(COMP_SEC, "-->CAM Key Not Found "); ++ ucValue = read_nic_byte(dev, SECR); ++ RT_TRACE(COMP_SEC, "WPA_Config=%x \n",ucValue); ++} ++ ++ ++/*************************************************************************** ++ ------------------- module init / exit stubs ---------------- ++****************************************************************************/ ++module_init(rtl8192_pci_module_init); ++module_exit(rtl8192_pci_module_exit); +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E_dm.c +@@ -0,0 +1,4115 @@ ++/*++ ++Copyright-c Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ r8192U_dm.c ++ ++Abstract: ++ HW dynamic mechanism. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2008-05-14 amy create version 0 porting from windows code. ++ ++--*/ ++#include "r8192E.h" ++#include "r8192E_dm.h" ++#include "r8192E_hw.h" ++#include "r819xE_phy.h" ++#include "r819xE_phyreg.h" ++#include "r8190_rtl8256.h" ++/*---------------------------Define Local Constant---------------------------*/ ++// ++// Indicate different AP vendor for IOT issue. ++// ++#ifdef RTL8190P ++static u32 edca_setting_DL[HT_IOT_PEER_MAX] = ++{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322}; ++static u32 edca_setting_UL[HT_IOT_PEER_MAX] = ++{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322}; ++#else ++#ifdef RTL8192E ++static u32 edca_setting_DL[HT_IOT_PEER_MAX] = ++{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322}; ++static u32 edca_setting_UL[HT_IOT_PEER_MAX] = ++{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322}; ++#else ++static u32 edca_setting_DL[HT_IOT_PEER_MAX] = ++{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5ea44f}; ++static u32 edca_setting_UL[HT_IOT_PEER_MAX] = ++{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f}; ++#endif ++#endif ++ ++#define RTK_UL_EDCA 0xa44f ++#define RTK_DL_EDCA 0x5e4322 ++/*---------------------------Define Local Constant---------------------------*/ ++ ++ ++/*------------------------Define global variable-----------------------------*/ ++// Debug variable ? ++dig_t dm_digtable; ++// Store current shoftware write register content for MAC PHY. ++u8 dm_shadow[16][256] = {{0}}; ++// For Dynamic Rx Path Selection by Signal Strength ++DRxPathSel DM_RxPathSelTable; ++/*------------------------Define global variable-----------------------------*/ ++ ++ ++/*------------------------Define local variable------------------------------*/ ++/*------------------------Define local variable------------------------------*/ ++ ++ ++/*--------------------Define export function prototype-----------------------*/ ++extern void init_hal_dm(struct net_device *dev); ++extern void deinit_hal_dm(struct net_device *dev); ++ ++extern void hal_dm_watchdog(struct net_device *dev); ++ ++ ++extern void init_rate_adaptive(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void dm_txpower_trackingcallback(struct work_struct *work); ++#else ++extern void dm_txpower_trackingcallback(struct net_device *dev); ++#endif ++ ++extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14); ++extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); ++extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); ++extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, ++ u32 dm_type, ++ u32 dm_value); ++extern void DM_ChangeFsyncSetting(struct net_device *dev, ++ s32 DM_Type, ++ s32 DM_Value); ++extern void dm_force_tx_fw_info(struct net_device *dev, ++ u32 force_type, ++ u32 force_value); ++extern void dm_init_edca_turbo(struct net_device *dev); ++extern void dm_rf_operation_test_callback(unsigned long data); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work); ++#else ++extern void dm_rf_pathcheck_workitemcallback(struct net_device *dev); ++#endif ++extern void dm_fsync_timer_callback(unsigned long data); ++#if 0 ++extern bool dm_check_lbus_status(struct net_device *dev); ++#endif ++extern void dm_check_fsync(struct net_device *dev); ++extern void dm_shadow_init(struct net_device *dev); ++extern void dm_initialize_txpower_tracking(struct net_device *dev); ++ ++#ifdef RTL8192E ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void dm_gpio_change_rf_callback(struct work_struct *work); ++#else ++extern void dm_gpio_change_rf_callback(struct net_device *dev); ++#endif ++#endif ++ ++ ++ ++/*--------------------Define export function prototype-----------------------*/ ++ ++ ++/*---------------------Define local function prototype-----------------------*/ ++// DM --> Rate Adaptive ++static void dm_check_rate_adaptive(struct net_device *dev); ++ ++// DM --> Bandwidth switch ++static void dm_init_bandwidth_autoswitch(struct net_device *dev); ++static void dm_bandwidth_autoswitch( struct net_device *dev); ++ ++// DM --> TX power control ++//static void dm_initialize_txpower_tracking(struct net_device *dev); ++ ++static void dm_check_txpower_tracking(struct net_device *dev); ++ ++ ++ ++//static void dm_txpower_reset_recovery(struct net_device *dev); ++ ++ ++// DM --> BB init gain restore ++#ifndef RTL8192U ++static void dm_bb_initialgain_restore(struct net_device *dev); ++ ++ ++// DM --> BB init gain backup ++static void dm_bb_initialgain_backup(struct net_device *dev); ++#endif ++ ++// DM --> Dynamic Init Gain by RSSI ++static void dm_dig_init(struct net_device *dev); ++static void dm_ctrl_initgain_byrssi(struct net_device *dev); ++static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev); ++static void dm_ctrl_initgain_byrssi_by_driverrssi( struct net_device *dev); ++static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(struct net_device *dev); ++static void dm_initial_gain(struct net_device *dev); ++static void dm_pd_th(struct net_device *dev); ++static void dm_cs_ratio(struct net_device *dev); ++ ++static void dm_init_ctstoself(struct net_device *dev); ++// DM --> EDCA turboe mode control ++static void dm_check_edca_turbo(struct net_device *dev); ++ ++// DM --> HW RF control ++static void dm_check_rfctrl_gpio(struct net_device *dev); ++ ++#ifndef RTL8190P ++//static void dm_gpio_change_rf(struct net_device *dev); ++#endif ++// DM --> Check PBC ++static void dm_check_pbc_gpio(struct net_device *dev); ++ ++ ++// DM --> Check current RX RF path state ++static void dm_check_rx_path_selection(struct net_device *dev); ++static void dm_init_rxpath_selection(struct net_device *dev); ++static void dm_rxpath_sel_byrssi(struct net_device *dev); ++ ++ ++// DM --> Fsync for broadcom ap ++static void dm_init_fsync(struct net_device *dev); ++static void dm_deInit_fsync(struct net_device *dev); ++ ++//Added by vivi, 20080522 ++static void dm_check_txrateandretrycount(struct net_device *dev); ++ ++/*---------------------Define local function prototype-----------------------*/ ++ ++/*---------------------Define of Tx Power Control For Near/Far Range --------*/ //Add by Jacken 2008/02/18 ++static void dm_init_dynamic_txpower(struct net_device *dev); ++static void dm_dynamic_txpower(struct net_device *dev); ++ ++ ++// DM --> For rate adaptive and DIG, we must send RSSI to firmware ++static void dm_send_rssi_tofw(struct net_device *dev); ++static void dm_ctstoself(struct net_device *dev); ++/*---------------------------Define function prototype------------------------*/ ++//================================================================================ ++// HW Dynamic mechanism interface. ++//================================================================================ ++ ++// ++// Description: ++// Prepare SW resource for HW dynamic mechanism. ++// ++// Assumption: ++// This function is only invoked at driver intialization once. ++// ++// ++void init_hal_dm(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ // Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism. ++ priv->undecorated_smoothed_pwdb = -1; ++ ++ //Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. ++ dm_init_dynamic_txpower(dev); ++ init_rate_adaptive(dev); ++ //dm_initialize_txpower_tracking(dev); ++ dm_dig_init(dev); ++ dm_init_edca_turbo(dev); ++ dm_init_bandwidth_autoswitch(dev); ++ dm_init_fsync(dev); ++ dm_init_rxpath_selection(dev); ++ dm_init_ctstoself(dev); ++#ifdef RTL8192E ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++ INIT_DELAYED_WORK(&priv->gpio_change_rf_wq, dm_gpio_change_rf_callback); ++#else ++ INIT_WORK(&priv->gpio_change_rf_wq, (void(*)(void*)) dm_gpio_change_rf_callback,dev); ++#endif ++#endif ++ ++} // InitHalDm ++ ++void deinit_hal_dm(struct net_device *dev) ++{ ++ ++ dm_deInit_fsync(dev); ++ ++} ++ ++ ++#ifdef USB_RX_AGGREGATION_SUPPORT ++void dm_CheckRxAggregation(struct net_device *dev) { ++ struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); ++ PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; ++ static unsigned long lastTxOkCnt = 0; ++ static unsigned long lastRxOkCnt = 0; ++ unsigned long curTxOkCnt = 0; ++ unsigned long curRxOkCnt = 0; ++ ++/* ++ if (pHalData->bForcedUsbRxAggr) { ++ if (pHalData->ForcedUsbRxAggrInfo == 0) { ++ if (pHalData->bCurrentRxAggrEnable) { ++ Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, FALSE); ++ } ++ } else { ++ if (!pHalData->bCurrentRxAggrEnable || (pHalData->ForcedUsbRxAggrInfo != pHalData->LastUsbRxAggrInfoSetting)) { ++ Adapter->HalFunc.HalUsbRxAggrHandler(Adapter, TRUE); ++ } ++ } ++ return; ++ } ++ ++*/ ++ curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; ++ curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; ++ ++ if((curTxOkCnt + curRxOkCnt) < 15000000) { ++ return; ++ } ++ ++ if(curTxOkCnt > 4*curRxOkCnt) { ++ if (priv->bCurrentRxAggrEnable) { ++ write_nic_dword(dev, 0x1a8, 0); ++ priv->bCurrentRxAggrEnable = false; ++ } ++ }else{ ++ if (!priv->bCurrentRxAggrEnable && !pHTInfo->bCurrentRT2RTAggregation) { ++ u32 ulValue; ++ ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) | ++ (pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout); ++ /* ++ * If usb rx firmware aggregation is enabled, ++ * when anyone of three threshold conditions above is reached, ++ * firmware will send aggregated packet to driver. ++ */ ++ write_nic_dword(dev, 0x1a8, ulValue); ++ priv->bCurrentRxAggrEnable = true; ++ } ++ } ++ ++ lastTxOkCnt = priv->stats.txbytesunicast; ++ lastRxOkCnt = priv->stats.rxbytesunicast; ++} // dm_CheckEdcaTurbo ++#endif ++ ++ ++ ++void hal_dm_watchdog(struct net_device *dev) ++{ ++ //struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ //static u8 previous_bssid[6] ={0}; ++ ++ /*Add by amy 2008/05/15 ,porting from windows code.*/ ++ dm_check_rate_adaptive(dev); ++ dm_dynamic_txpower(dev); ++ dm_check_txrateandretrycount(dev); ++ ++ dm_check_txpower_tracking(dev); ++ ++ dm_ctrl_initgain_byrssi(dev); ++ dm_check_edca_turbo(dev); ++ dm_bandwidth_autoswitch(dev); ++ ++ dm_check_rfctrl_gpio(dev); ++ dm_check_rx_path_selection(dev); ++ dm_check_fsync(dev); ++ ++ // Add by amy 2008-05-15 porting from windows code. ++ dm_check_pbc_gpio(dev); ++ dm_send_rssi_tofw(dev); ++ dm_ctstoself(dev); ++ ++#ifdef USB_RX_AGGREGATION_SUPPORT ++ dm_CheckRxAggregation(dev); ++#endif ++} //HalDmWatchDog ++ ++ ++/* ++ * Decide Rate Adaptive Set according to distance (signal strength) ++ * 01/11/2008 MHC Modify input arguments and RATR table level. ++ * 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call ++ * the function after making sure RF_Type. ++ */ ++void init_rate_adaptive(struct net_device * dev) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ prate_adaptive pra = (prate_adaptive)&priv->rate_adaptive; ++ ++ pra->ratr_state = DM_RATR_STA_MAX; ++ pra->high2low_rssi_thresh_for_ra = RateAdaptiveTH_High; ++ pra->low2high_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M+5; ++ pra->low2high_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M+5; ++ ++ pra->high_rssi_thresh_for_ra = RateAdaptiveTH_High+5; ++ pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M; ++ pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M; ++ ++ if(priv->CustomerID == RT_CID_819x_Netcore) ++ pra->ping_rssi_enable = 1; ++ else ++ pra->ping_rssi_enable = 0; ++ pra->ping_rssi_thresh_for_ra = 15; ++ ++ ++ if (priv->rf_type == RF_2T4R) ++ { ++ // 07/10/08 MH Modify for RA smooth scheme. ++ /* 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.*/ ++ pra->upper_rssi_threshold_ratr = 0x8f0f0000; ++ pra->middle_rssi_threshold_ratr = 0x8f0ff000; ++ pra->low_rssi_threshold_ratr = 0x8f0ff001; ++ pra->low_rssi_threshold_ratr_40M = 0x8f0ff005; ++ pra->low_rssi_threshold_ratr_20M = 0x8f0ff001; ++ pra->ping_rssi_ratr = 0x0000000d;//cosa add for test ++ } ++ else if (priv->rf_type == RF_1T2R) ++ { ++ pra->upper_rssi_threshold_ratr = 0x000f0000; ++ pra->middle_rssi_threshold_ratr = 0x000ff000; ++ pra->low_rssi_threshold_ratr = 0x000ff001; ++ pra->low_rssi_threshold_ratr_40M = 0x000ff005; ++ pra->low_rssi_threshold_ratr_20M = 0x000ff001; ++ pra->ping_rssi_ratr = 0x0000000d;//cosa add for test ++ } ++ ++} // InitRateAdaptive ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_check_rate_adaptive() ++ * ++ * Overview: ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/26/08 amy Create version 0 proting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void dm_check_rate_adaptive(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; ++ prate_adaptive pra = (prate_adaptive)&priv->rate_adaptive; ++ u32 currentRATR, targetRATR = 0; ++ u32 LowRSSIThreshForRA = 0, HighRSSIThreshForRA = 0; ++ bool bshort_gi_enabled = false; ++ static u8 ping_rssi_state=0; ++ ++ ++ if(!priv->up) ++ { ++ RT_TRACE(COMP_RATE, "<---- dm_check_rate_adaptive(): driver is going to unload\n"); ++ return; ++ } ++ ++ if(pra->rate_adaptive_disabled)//this variable is set by ioctl. ++ return; ++ ++ // TODO: Only 11n mode is implemented currently, ++ if( !(priv->ieee80211->mode == WIRELESS_MODE_N_24G || ++ priv->ieee80211->mode == WIRELESS_MODE_N_5G)) ++ return; ++ ++ if( priv->ieee80211->state == IEEE80211_LINKED ) ++ { ++ // RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t"); ++ ++ // ++ // Check whether Short GI is enabled ++ // ++ bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) || ++ (!pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI20MHz); ++ ++ ++ pra->upper_rssi_threshold_ratr = ++ (pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; ++ ++ pra->middle_rssi_threshold_ratr = ++ (pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; ++ ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ pra->low_rssi_threshold_ratr = ++ (pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; ++ } ++ else ++ { ++ pra->low_rssi_threshold_ratr = ++ (pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; ++ } ++ //cosa add for test ++ pra->ping_rssi_ratr = ++ (pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ; ++ ++ /* 2007/10/08 MH We support RA smooth scheme now. When it is the first ++ time to link with AP. We will not change upper/lower threshold. If ++ STA stay in high or low level, we must change two different threshold ++ to prevent jumping frequently. */ ++ if (pra->ratr_state == DM_RATR_STA_HIGH) ++ { ++ HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra; ++ LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)? ++ (pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M); ++ } ++ else if (pra->ratr_state == DM_RATR_STA_LOW) ++ { ++ HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra; ++ LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)? ++ (pra->low2high_rssi_thresh_for_ra40M):(pra->low2high_rssi_thresh_for_ra20M); ++ } ++ else ++ { ++ HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra; ++ LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)? ++ (pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M); ++ } ++ ++ //DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA); ++ if(priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA) ++ { ++ //DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB); ++ pra->ratr_state = DM_RATR_STA_HIGH; ++ targetRATR = pra->upper_rssi_threshold_ratr; ++ }else if(priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA) ++ { ++ //DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB); ++ pra->ratr_state = DM_RATR_STA_MIDDLE; ++ targetRATR = pra->middle_rssi_threshold_ratr; ++ }else ++ { ++ //DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB); ++ pra->ratr_state = DM_RATR_STA_LOW; ++ targetRATR = pra->low_rssi_threshold_ratr; ++ } ++ ++ //cosa add for test ++ if(pra->ping_rssi_enable) ++ { ++ //pHalData->UndecoratedSmoothedPWDB = 19; ++ if(priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5)) ++ { ++ if( (priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) || ++ ping_rssi_state ) ++ { ++ //DbgPrint("TestRSSI = %d, set RATR to 0x%x \n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR); ++ pra->ratr_state = DM_RATR_STA_LOW; ++ targetRATR = pra->ping_rssi_ratr; ++ ping_rssi_state = 1; ++ } ++ //else ++ // DbgPrint("TestRSSI is between the range. \n"); ++ } ++ else ++ { ++ //DbgPrint("TestRSSI Recover to 0x%x \n", targetRATR); ++ ping_rssi_state = 0; ++ } ++ } ++ ++ // 2008.04.01 ++#if 1 ++ // For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7. ++ if(priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev)) ++ targetRATR &= 0xf00fffff; ++#endif ++ ++ // ++ // Check whether updating of RATR0 is required ++ // ++ currentRATR = read_nic_dword(dev, RATR0); ++ if( targetRATR != currentRATR ) ++ { ++ u32 ratr_value; ++ ratr_value = targetRATR; ++ RT_TRACE(COMP_RATE,"currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR); ++ if(priv->rf_type == RF_1T2R) ++ { ++ ratr_value &= ~(RATE_ALL_OFDM_2SS); ++ } ++ write_nic_dword(dev, RATR0, ratr_value); ++ write_nic_byte(dev, UFWP, 1); ++ ++ pra->last_ratr = targetRATR; ++ } ++ ++ } ++ else ++ { ++ pra->ratr_state = DM_RATR_STA_MAX; ++ } ++ ++} // dm_CheckRateAdaptive ++ ++ ++static void dm_init_bandwidth_autoswitch(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz = BW_AUTO_SWITCH_LOW_HIGH; ++ priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz = BW_AUTO_SWITCH_HIGH_LOW; ++ priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false; ++ priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable = false; ++ ++} // dm_init_bandwidth_autoswitch ++ ++ ++static void dm_bandwidth_autoswitch(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ||!priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable){ ++ return; ++ }else{ ++ if(priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false){//If send packets in 40 Mhz in 20/40 ++ if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz) ++ priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true; ++ }else{//in force send packets in 20 Mhz in 20/40 ++ if(priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz) ++ priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false; ++ ++ } ++ } ++} // dm_BandwidthAutoSwitch ++ ++//OFDM default at 0db, index=6. ++#ifndef RTL8190P ++static u32 OFDMSwingTable[OFDM_Table_Length] = { ++ 0x7f8001fe, // 0, +6db ++ 0x71c001c7, // 1, +5db ++ 0x65400195, // 2, +4db ++ 0x5a400169, // 3, +3db ++ 0x50800142, // 4, +2db ++ 0x47c0011f, // 5, +1db ++ 0x40000100, // 6, +0db ===> default, upper for higher temprature, lower for low temprature ++ 0x390000e4, // 7, -1db ++ 0x32c000cb, // 8, -2db ++ 0x2d4000b5, // 9, -3db ++ 0x288000a2, // 10, -4db ++ 0x24000090, // 11, -5db ++ 0x20000080, // 12, -6db ++ 0x1c800072, // 13, -7db ++ 0x19800066, // 14, -8db ++ 0x26c0005b, // 15, -9db ++ 0x24400051, // 16, -10db ++ 0x12000048, // 17, -11db ++ 0x10000040 // 18, -12db ++}; ++static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = { ++ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0db ===> CCK40M default ++ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 1, -1db ++ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 2, -2db ++ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 3, -3db ++ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 4, -4db ++ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 5, -5db ++ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 6, -6db ===> CCK20M default ++ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 7, -7db ++ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 8, -8db ++ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 9, -9db ++ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 10, -10db ++ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} // 11, -11db ++}; ++ ++static u8 CCKSwingTable_Ch14[CCK_Table_length][8] = { ++ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0db ===> CCK40M default ++ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 1, -1db ++ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 2, -2db ++ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 3, -3db ++ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 4, -4db ++ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 5, -5db ++ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 6, -6db ===> CCK20M default ++ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 7, -7db ++ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 8, -8db ++ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 9, -9db ++ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 10, -10db ++ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} // 11, -11db ++}; ++#endif ++#define Pw_Track_Flag 0x11d ++#define Tssi_Mea_Value 0x13c ++#define Tssi_Report_Value1 0x134 ++#define Tssi_Report_Value2 0x13e ++#define FW_Busy_Flag 0x13f ++static void dm_TXPowerTrackingCallback_TSSI(struct net_device * dev) ++ { ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ bool bHighpowerstate, viviflag = FALSE; ++ DCMD_TXCMD_T tx_cmd; ++ u8 powerlevelOFDM24G; ++ int i =0, j = 0, k = 0; ++ u8 RF_Type, tmp_report[5]={0, 0, 0, 0, 0}; ++ u32 Value; ++ u8 Pwr_Flag; ++ u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver=0; ++#ifdef RTL8192U ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++#endif ++// bool rtStatus = true; ++ u32 delta=0; ++ RT_TRACE(COMP_POWER_TRACKING,"%s()\n",__FUNCTION__); ++// write_nic_byte(dev, 0x1ba, 0); ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++ write_nic_byte(dev, FW_Busy_Flag, 0); ++ priv->ieee80211->bdynamic_txpower_enable = false; ++ bHighpowerstate = priv->bDynamicTxHighPower; ++ ++ powerlevelOFDM24G = (u8)(priv->Pwr_Track>>24); ++ RF_Type = priv->rf_type; ++ Value = (RF_Type<<8) | powerlevelOFDM24G; ++ ++ RT_TRACE(COMP_POWER_TRACKING, "powerlevelOFDM24G = %x\n", powerlevelOFDM24G); ++ ++ for(j = 0; j<=30; j++) ++{ //fill tx_cmd ++ ++ tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING; ++ tx_cmd.Length = 4; ++ tx_cmd.Value = Value; ++#ifdef RTL8192U ++ rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12); ++ if (rtStatus == RT_STATUS_FAILURE) ++ { ++ RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n"); ++ } ++#else ++ cmpk_message_handle_tx(dev, (u8*)&tx_cmd, DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T)); ++#endif ++ mdelay(1); ++ //DbgPrint("hi, vivi, strange\n"); ++ for(i = 0;i <= 30; i++) ++ { ++ Pwr_Flag = read_nic_byte(dev, Pw_Track_Flag); ++ ++ if (Pwr_Flag == 0) ++ { ++ mdelay(1); ++ continue; ++ } ++ ++ Avg_TSSI_Meas = read_nic_word(dev, Tssi_Mea_Value); ++ ++ if(Avg_TSSI_Meas == 0) ++ { ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++ write_nic_byte(dev, FW_Busy_Flag, 0); ++ return; ++ } ++ ++ for(k = 0;k < 5; k++) ++ { ++ if(k !=4) ++ tmp_report[k] = read_nic_byte(dev, Tssi_Report_Value1+k); ++ else ++ tmp_report[k] = read_nic_byte(dev, Tssi_Report_Value2); ++ ++ RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]); ++ } ++ ++ //check if the report value is right ++ for(k = 0;k < 5; k++) ++ { ++ if(tmp_report[k] <= 20) ++ { ++ viviflag =TRUE; ++ break; ++ } ++ } ++ if(viviflag ==TRUE) ++ { ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++ viviflag = FALSE; ++ RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n"); ++ for(k = 0;k < 5; k++) ++ tmp_report[k] = 0; ++ break; ++ } ++ ++ for(k = 0;k < 5; k++) ++ { ++ Avg_TSSI_Meas_from_driver += tmp_report[k]; ++ } ++ ++ Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5; ++ RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver); ++ TSSI_13dBm = priv->TSSI_13dBm; ++ RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm); ++ ++ //if(abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK) ++ // For MacOS-compatible ++ if(Avg_TSSI_Meas_from_driver > TSSI_13dBm) ++ delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm; ++ else ++ delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver; ++ ++ if(delta <= E_FOR_TX_POWER_TRACK) ++ { ++ priv->ieee80211->bdynamic_txpower_enable = TRUE; ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++ write_nic_byte(dev, FW_Busy_Flag, 0); ++ RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n"); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real); ++#ifdef RTL8190P ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex = %d\n", priv->rfc_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real = %d\n", priv->rfc_txpowertrackingindex_real); ++#endif ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_difference = %d\n", priv->CCKPresentAttentuation_difference); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation); ++ return; ++ } ++ else ++ { ++ if(Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK) ++ { ++ if (RF_Type == RF_2T4R) ++ { ++ ++ if((priv->rfa_txpowertrackingindex > 0) &&(priv->rfc_txpowertrackingindex > 0)) ++ { ++ priv->rfa_txpowertrackingindex--; ++ if(priv->rfa_txpowertrackingindex_real > 4) ++ { ++ priv->rfa_txpowertrackingindex_real--; ++ rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); ++ } ++ ++ priv->rfc_txpowertrackingindex--; ++ if(priv->rfc_txpowertrackingindex_real > 4) ++ { ++ priv->rfc_txpowertrackingindex_real--; ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); ++ } ++ } ++ else ++ { ++ rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[4].txbbgain_value); ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[4].txbbgain_value); ++ } ++ } ++ else ++ { ++ if(priv->rfc_txpowertrackingindex > 0) ++ { ++ priv->rfc_txpowertrackingindex--; ++ if(priv->rfc_txpowertrackingindex_real > 4) ++ { ++ priv->rfc_txpowertrackingindex_real--; ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); ++ } ++ } ++ else ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[4].txbbgain_value); ++ } ++ } ++ else ++ { ++ if (RF_Type == RF_2T4R) ++ { ++ if((priv->rfa_txpowertrackingindex < TxBBGainTableLength - 1) &&(priv->rfc_txpowertrackingindex < TxBBGainTableLength - 1)) ++ { ++ priv->rfa_txpowertrackingindex++; ++ priv->rfa_txpowertrackingindex_real++; ++ rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value); ++ priv->rfc_txpowertrackingindex++; ++ priv->rfc_txpowertrackingindex_real++; ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); ++ } ++ else ++ { ++ rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value); ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value); ++ } ++ } ++ else ++ { ++ if(priv->rfc_txpowertrackingindex < (TxBBGainTableLength - 1)) ++ { ++ priv->rfc_txpowertrackingindex++; ++ priv->rfc_txpowertrackingindex_real++; ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value); ++ } ++ else ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value); ++ } ++ } ++ if (RF_Type == RF_2T4R) ++ priv->CCKPresentAttentuation_difference ++ = priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default; ++ else ++ priv->CCKPresentAttentuation_difference ++ = priv->rfc_txpowertrackingindex - priv->rfc_txpowertracking_default; ++ ++ if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ priv->CCKPresentAttentuation ++ = priv->CCKPresentAttentuation_20Mdefault + priv->CCKPresentAttentuation_difference; ++ else ++ priv->CCKPresentAttentuation ++ = priv->CCKPresentAttentuation_40Mdefault + priv->CCKPresentAttentuation_difference; ++ ++ if(priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1)) ++ priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1; ++ if(priv->CCKPresentAttentuation < 0) ++ priv->CCKPresentAttentuation = 0; ++ ++ if(1) ++ { ++ if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = TRUE; ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = FALSE; ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ else ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real); ++#ifdef RTL8190P ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex = %d\n", priv->rfc_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->rfc_txpowertrackingindex_real = %d\n", priv->rfc_txpowertrackingindex_real); ++#endif ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_difference = %d\n", priv->CCKPresentAttentuation_difference); ++ RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation); ++ ++ if (priv->CCKPresentAttentuation_difference <= -12||priv->CCKPresentAttentuation_difference >= 24) ++ { ++ priv->ieee80211->bdynamic_txpower_enable = TRUE; ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++ write_nic_byte(dev, FW_Busy_Flag, 0); ++ RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n"); ++ return; ++ } ++ ++ ++ } ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++ Avg_TSSI_Meas_from_driver = 0; ++ for(k = 0;k < 5; k++) ++ tmp_report[k] = 0; ++ break; ++ } ++ write_nic_byte(dev, FW_Busy_Flag, 0); ++} ++ priv->ieee80211->bdynamic_txpower_enable = TRUE; ++ write_nic_byte(dev, Pw_Track_Flag, 0); ++} ++#ifndef RTL8190P ++static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev) ++{ ++#define ThermalMeterVal 9 ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 tmpRegA, TempCCk; ++ u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval; ++ int i =0, CCKSwingNeedUpdate=0; ++ ++ if(!priv->btxpower_trackingInit) ++ { ++ //Query OFDM default setting ++ tmpRegA= rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord); ++ for(i=0; iOFDM_index= (u8)i; ++ RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, OFDM_index=0x%x\n", ++ rOFDM0_XATxIQImbalance, tmpRegA, priv->OFDM_index); ++ } ++ } ++ ++ //Query CCK default setting From 0xa22 ++ TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); ++ for(i=0 ; iCCK_index =(u8) i; ++ RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, CCK_index=0x%x\n", ++ rCCK0_TxFilter1, TempCCk, priv->CCK_index); ++ break; ++ } ++} ++ priv->btxpower_trackingInit = TRUE; ++ //pHalData->TXPowercount = 0; ++ return; ++ } ++ ++ //========================== ++ // this is only for test, should be masked ++#if 0 ++{ ++ //UINT32 eRFPath; ++ //UINT32 start_rf, end_rf; ++ UINT32 curr_addr; ++ //UINT32 reg_addr; ++ //UINT32 reg_addr_end; ++ UINT32 reg_value; ++ //start_rf = RF90_PATH_A; ++ //end_rf = RF90_PATH_B;//RF90_PATH_MAX; ++ //reg_addr = 0x0; ++ //reg_addr_end = 0x2F; ++ ++ for (curr_addr = 0; curr_addr < 0x2d; curr_addr++) ++ { ++ reg_value = PHY_QueryRFReg( Adapter, (RF90_RADIO_PATH_E)RF90_PATH_A, ++ curr_addr, bMaskDWord); ++ } ++ ++ pHalData->TXPowercount = 0; ++ return; ++} ++#endif ++ //========================== ++ ++ // read and filter out unreasonable value ++ tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078); // 0x12: RF Reg[10:7] ++ RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA); ++ if(tmpRegA < 3 || tmpRegA > 13) ++ return; ++ if(tmpRegA >= 12) // if over 12, TP will be bad when high temprature ++ tmpRegA = 12; ++ RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA); ++ priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion ++ priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion ++ ++ //Get current RF-A temprature index ++ if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temprature ++ { ++ tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA); ++ tmpCCK40Mindex = tmpCCK20Mindex - 6; ++ if(tmpOFDMindex >= OFDM_Table_Length) ++ tmpOFDMindex = OFDM_Table_Length-1; ++ if(tmpCCK20Mindex >= CCK_Table_length) ++ tmpCCK20Mindex = CCK_Table_length-1; ++ if(tmpCCK40Mindex >= CCK_Table_length) ++ tmpCCK40Mindex = CCK_Table_length-1; ++ } ++ else ++ { ++ tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]); ++ if(tmpval >= 6) // higher temprature ++ tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB ++ else ++ tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval; ++ tmpCCK40Mindex = 0; ++ } ++ //DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d", ++ //((u1Byte)tmpRegA - pHalData->ThermalMeter[0]), ++ //tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex); ++ if(priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) //40M ++ tmpCCKindex = tmpCCK40Mindex; ++ else ++ tmpCCKindex = tmpCCK20Mindex; ++ ++ //record for bandwidth swith ++ priv->Record_CCK_20Mindex = tmpCCK20Mindex; ++ priv->Record_CCK_40Mindex = tmpCCK40Mindex; ++ RT_TRACE(COMP_POWER_TRACKING, "Record_CCK_20Mindex / Record_CCK_40Mindex = %d / %d.\n", ++ priv->Record_CCK_20Mindex, priv->Record_CCK_40Mindex); ++ ++ if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = TRUE; ++ CCKSwingNeedUpdate = 1; ++ } ++ else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = FALSE; ++ CCKSwingNeedUpdate = 1; ++ } ++ ++ if(priv->CCK_index != tmpCCKindex) ++{ ++ priv->CCK_index = tmpCCKindex; ++ CCKSwingNeedUpdate = 1; ++ } ++ ++ if(CCKSwingNeedUpdate) ++ { ++ //DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index); ++ dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); ++ } ++ if(priv->OFDM_index != tmpOFDMindex) ++ { ++ priv->OFDM_index = tmpOFDMindex; ++ rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[priv->OFDM_index]); ++ RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n", ++ priv->OFDM_index, OFDMSwingTable[priv->OFDM_index]); ++ } ++ priv->txpower_count = 0; ++} ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void dm_txpower_trackingcallback(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++extern void dm_txpower_trackingcallback(struct net_device *dev) ++{ ++#ifndef RTL8190P ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++#endif ++ ++#ifdef RTL8190P ++ dm_TXPowerTrackingCallback_TSSI(dev); ++#else ++ //if(priv->bDcut == TRUE) ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ dm_TXPowerTrackingCallback_TSSI(dev); ++ else ++ dm_TXPowerTrackingCallback_ThermalMeter(dev); ++#endif ++} ++ ++ ++static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ //Initial the Tx BB index and mapping value ++ priv->txbbgain_table[0].txbb_iq_amplifygain = 12; ++ priv->txbbgain_table[0].txbbgain_value=0x7f8001fe; ++ priv->txbbgain_table[1].txbb_iq_amplifygain = 11; ++ priv->txbbgain_table[1].txbbgain_value=0x788001e2; ++ priv->txbbgain_table[2].txbb_iq_amplifygain = 10; ++ priv->txbbgain_table[2].txbbgain_value=0x71c001c7; ++ priv->txbbgain_table[3].txbb_iq_amplifygain = 9; ++ priv->txbbgain_table[3].txbbgain_value=0x6b8001ae; ++ priv->txbbgain_table[4].txbb_iq_amplifygain = 8; ++ priv->txbbgain_table[4].txbbgain_value=0x65400195; ++ priv->txbbgain_table[5].txbb_iq_amplifygain = 7; ++ priv->txbbgain_table[5].txbbgain_value=0x5fc0017f; ++ priv->txbbgain_table[6].txbb_iq_amplifygain = 6; ++ priv->txbbgain_table[6].txbbgain_value=0x5a400169; ++ priv->txbbgain_table[7].txbb_iq_amplifygain = 5; ++ priv->txbbgain_table[7].txbbgain_value=0x55400155; ++ priv->txbbgain_table[8].txbb_iq_amplifygain = 4; ++ priv->txbbgain_table[8].txbbgain_value=0x50800142; ++ priv->txbbgain_table[9].txbb_iq_amplifygain = 3; ++ priv->txbbgain_table[9].txbbgain_value=0x4c000130; ++ priv->txbbgain_table[10].txbb_iq_amplifygain = 2; ++ priv->txbbgain_table[10].txbbgain_value=0x47c0011f; ++ priv->txbbgain_table[11].txbb_iq_amplifygain = 1; ++ priv->txbbgain_table[11].txbbgain_value=0x43c0010f; ++ priv->txbbgain_table[12].txbb_iq_amplifygain = 0; ++ priv->txbbgain_table[12].txbbgain_value=0x40000100; ++ priv->txbbgain_table[13].txbb_iq_amplifygain = -1; ++ priv->txbbgain_table[13].txbbgain_value=0x3c8000f2; ++ priv->txbbgain_table[14].txbb_iq_amplifygain = -2; ++ priv->txbbgain_table[14].txbbgain_value=0x390000e4; ++ priv->txbbgain_table[15].txbb_iq_amplifygain = -3; ++ priv->txbbgain_table[15].txbbgain_value=0x35c000d7; ++ priv->txbbgain_table[16].txbb_iq_amplifygain = -4; ++ priv->txbbgain_table[16].txbbgain_value=0x32c000cb; ++ priv->txbbgain_table[17].txbb_iq_amplifygain = -5; ++ priv->txbbgain_table[17].txbbgain_value=0x300000c0; ++ priv->txbbgain_table[18].txbb_iq_amplifygain = -6; ++ priv->txbbgain_table[18].txbbgain_value=0x2d4000b5; ++ priv->txbbgain_table[19].txbb_iq_amplifygain = -7; ++ priv->txbbgain_table[19].txbbgain_value=0x2ac000ab; ++ priv->txbbgain_table[20].txbb_iq_amplifygain = -8; ++ priv->txbbgain_table[20].txbbgain_value=0x288000a2; ++ priv->txbbgain_table[21].txbb_iq_amplifygain = -9; ++ priv->txbbgain_table[21].txbbgain_value=0x26000098; ++ priv->txbbgain_table[22].txbb_iq_amplifygain = -10; ++ priv->txbbgain_table[22].txbbgain_value=0x24000090; ++ priv->txbbgain_table[23].txbb_iq_amplifygain = -11; ++ priv->txbbgain_table[23].txbbgain_value=0x22000088; ++ priv->txbbgain_table[24].txbb_iq_amplifygain = -12; ++ priv->txbbgain_table[24].txbbgain_value=0x20000080; ++ priv->txbbgain_table[25].txbb_iq_amplifygain = -13; ++ priv->txbbgain_table[25].txbbgain_value=0x1a00006c; ++ priv->txbbgain_table[26].txbb_iq_amplifygain = -14; ++ priv->txbbgain_table[26].txbbgain_value=0x1c800072; ++ priv->txbbgain_table[27].txbb_iq_amplifygain = -15; ++ priv->txbbgain_table[27].txbbgain_value=0x18000060; ++ priv->txbbgain_table[28].txbb_iq_amplifygain = -16; ++ priv->txbbgain_table[28].txbbgain_value=0x19800066; ++ priv->txbbgain_table[29].txbb_iq_amplifygain = -17; ++ priv->txbbgain_table[29].txbbgain_value=0x15800056; ++ priv->txbbgain_table[30].txbb_iq_amplifygain = -18; ++ priv->txbbgain_table[30].txbbgain_value=0x26c0005b; ++ priv->txbbgain_table[31].txbb_iq_amplifygain = -19; ++ priv->txbbgain_table[31].txbbgain_value=0x14400051; ++ priv->txbbgain_table[32].txbb_iq_amplifygain = -20; ++ priv->txbbgain_table[32].txbbgain_value=0x24400051; ++ priv->txbbgain_table[33].txbb_iq_amplifygain = -21; ++ priv->txbbgain_table[33].txbbgain_value=0x1300004c; ++ priv->txbbgain_table[34].txbb_iq_amplifygain = -22; ++ priv->txbbgain_table[34].txbbgain_value=0x12000048; ++ priv->txbbgain_table[35].txbb_iq_amplifygain = -23; ++ priv->txbbgain_table[35].txbbgain_value=0x11000044; ++ priv->txbbgain_table[36].txbb_iq_amplifygain = -24; ++ priv->txbbgain_table[36].txbbgain_value=0x10000040; ++ ++ //ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29 ++ //This Table is for CH1~CH13 ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[1] = 0x35; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[2] = 0x2e; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[3] = 0x25; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[4] = 0x1c; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[5] = 0x12; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[6] = 0x09; ++ priv->cck_txbbgain_table[0].ccktxbb_valuearray[7] = 0x04; ++ ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[0] = 0x33; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[1] = 0x32; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[2] = 0x2b; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[3] = 0x23; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[4] = 0x1a; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[5] = 0x11; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[6] = 0x08; ++ priv->cck_txbbgain_table[1].ccktxbb_valuearray[7] = 0x04; ++ ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[0] = 0x30; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[1] = 0x2f; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[2] = 0x29; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[3] = 0x21; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[4] = 0x19; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[5] = 0x10; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[6] = 0x08; ++ priv->cck_txbbgain_table[2].ccktxbb_valuearray[7] = 0x03; ++ ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[0] = 0x2d; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[1] = 0x2d; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[2] = 0x27; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[3] = 0x1f; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[4] = 0x18; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[5] = 0x0f; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[6] = 0x08; ++ priv->cck_txbbgain_table[3].ccktxbb_valuearray[7] = 0x03; ++ ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[0] = 0x2b; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[1] = 0x2a; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[2] = 0x25; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[3] = 0x1e; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[4] = 0x16; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[5] = 0x0e; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[6] = 0x07; ++ priv->cck_txbbgain_table[4].ccktxbb_valuearray[7] = 0x03; ++ ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[0] = 0x28; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[1] = 0x28; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[2] = 0x22; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[3] = 0x1c; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[4] = 0x15; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[5] = 0x0d; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[6] = 0x07; ++ priv->cck_txbbgain_table[5].ccktxbb_valuearray[7] = 0x03; ++ ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[0] = 0x26; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[1] = 0x25; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[2] = 0x21; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[3] = 0x1b; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[4] = 0x14; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[5] = 0x0d; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[6] = 0x06; ++ priv->cck_txbbgain_table[6].ccktxbb_valuearray[7] = 0x03; ++ ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[0] = 0x24; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[1] = 0x23; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[2] = 0x1f; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[3] = 0x19; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[4] = 0x13; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[5] = 0x0c; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[6] = 0x06; ++ priv->cck_txbbgain_table[7].ccktxbb_valuearray[7] = 0x03; ++ ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[0] = 0x22; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[1] = 0x21; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[2] = 0x1d; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[3] = 0x18; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[4] = 0x11; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[5] = 0x0b; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[6] = 0x06; ++ priv->cck_txbbgain_table[8].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[0] = 0x20; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[1] = 0x20; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[2] = 0x1b; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[3] = 0x16; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[4] = 0x11; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[5] = 0x08; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[6] = 0x05; ++ priv->cck_txbbgain_table[9].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[0] = 0x1f; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[1] = 0x1e; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[2] = 0x1a; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[3] = 0x15; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[4] = 0x10; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[5] = 0x0a; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[6] = 0x05; ++ priv->cck_txbbgain_table[10].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[0] = 0x1d; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[1] = 0x1c; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[2] = 0x18; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[3] = 0x14; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[4] = 0x0f; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[5] = 0x0a; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[6] = 0x05; ++ priv->cck_txbbgain_table[11].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[0] = 0x1b; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[1] = 0x1a; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[2] = 0x17; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[3] = 0x13; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[4] = 0x0e; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[5] = 0x09; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[6] = 0x04; ++ priv->cck_txbbgain_table[12].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[0] = 0x1a; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[1] = 0x19; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[2] = 0x16; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[3] = 0x12; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[4] = 0x0d; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[5] = 0x09; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[6] = 0x04; ++ priv->cck_txbbgain_table[13].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[0] = 0x18; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[1] = 0x17; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[2] = 0x15; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[3] = 0x11; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[4] = 0x0c; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[5] = 0x08; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[6] = 0x04; ++ priv->cck_txbbgain_table[14].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[0] = 0x17; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[1] = 0x16; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[2] = 0x13; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[3] = 0x10; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[4] = 0x0c; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[5] = 0x08; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[6] = 0x04; ++ priv->cck_txbbgain_table[15].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[0] = 0x16; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[1] = 0x15; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[2] = 0x12; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[3] = 0x0f; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[4] = 0x0b; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[5] = 0x07; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[6] = 0x04; ++ priv->cck_txbbgain_table[16].ccktxbb_valuearray[7] = 0x01; ++ ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[0] = 0x14; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[1] = 0x14; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[2] = 0x11; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[3] = 0x0e; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[4] = 0x0b; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[5] = 0x07; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[6] = 0x03; ++ priv->cck_txbbgain_table[17].ccktxbb_valuearray[7] = 0x02; ++ ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[0] = 0x13; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[1] = 0x13; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[2] = 0x10; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[3] = 0x0d; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[4] = 0x0a; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[5] = 0x06; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[6] = 0x03; ++ priv->cck_txbbgain_table[18].ccktxbb_valuearray[7] = 0x01; ++ ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[0] = 0x12; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[1] = 0x12; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[2] = 0x0f; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[3] = 0x0c; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[4] = 0x09; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[5] = 0x06; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[6] = 0x03; ++ priv->cck_txbbgain_table[19].ccktxbb_valuearray[7] = 0x01; ++ ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[0] = 0x11; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[1] = 0x11; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[2] = 0x0f; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[3] = 0x0c; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[4] = 0x09; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[5] = 0x06; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[6] = 0x03; ++ priv->cck_txbbgain_table[20].ccktxbb_valuearray[7] = 0x01; ++ ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[0] = 0x10; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[1] = 0x10; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[2] = 0x0e; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[3] = 0x0b; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[4] = 0x08; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[5] = 0x05; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[6] = 0x03; ++ priv->cck_txbbgain_table[21].ccktxbb_valuearray[7] = 0x01; ++ ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[0] = 0x0f; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[1] = 0x0f; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[2] = 0x0d; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[3] = 0x0b; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[4] = 0x08; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[5] = 0x05; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03; ++ priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01; ++ ++ //ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29 ++ //This Table is for CH14 ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[1] = 0x35; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[2] = 0x2e; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[3] = 0x1b; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[0] = 0x33; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[1] = 0x32; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[2] = 0x2b; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[3] = 0x19; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[1].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[0] = 0x30; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[1] = 0x2f; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[2] = 0x29; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[3] = 0x18; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[2].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[0] = 0x2d; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[1] = 0x2d; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[2] = 0x27; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[3] = 0x17; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[3].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[0] = 0x2b; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[1] = 0x2a; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[2] = 0x25; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[3] = 0x15; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[4].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[0] = 0x28; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[1] = 0x28; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[2] = 0x22; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[3] = 0x14; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[5].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[0] = 0x26; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[1] = 0x25; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[2] = 0x21; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[3] = 0x13; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[6].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[0] = 0x24; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[1] = 0x23; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[2] = 0x1f; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[3] = 0x12; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[7].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[0] = 0x22; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[1] = 0x21; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[2] = 0x1d; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[3] = 0x11; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[8].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[0] = 0x20; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[1] = 0x20; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[2] = 0x1b; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[3] = 0x10; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[9].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[0] = 0x1f; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[1] = 0x1e; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[2] = 0x1a; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[3] = 0x0f; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[10].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[0] = 0x1d; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[1] = 0x1c; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[2] = 0x18; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[3] = 0x0e; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[11].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[0] = 0x1b; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[1] = 0x1a; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[2] = 0x17; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[3] = 0x0e; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[12].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[0] = 0x1a; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[1] = 0x19; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[2] = 0x16; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[3] = 0x0d; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[13].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[0] = 0x18; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[1] = 0x17; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[2] = 0x15; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[3] = 0x0c; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[14].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[0] = 0x17; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[1] = 0x16; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[2] = 0x13; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[3] = 0x0b; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[15].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[0] = 0x16; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[1] = 0x15; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[2] = 0x12; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[3] = 0x0b; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[16].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[0] = 0x14; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[1] = 0x14; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[2] = 0x11; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[3] = 0x0a; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[17].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[0] = 0x13; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[1] = 0x13; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[2] = 0x10; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[3] = 0x0a; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[18].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[0] = 0x12; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[1] = 0x12; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[2] = 0x0f; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[3] = 0x09; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[19].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[0] = 0x11; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[1] = 0x11; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[2] = 0x0f; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[3] = 0x09; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[20].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[0] = 0x10; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[1] = 0x10; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[2] = 0x0e; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[3] = 0x08; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[21].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[0] = 0x0f; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[1] = 0x0f; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[2] = 0x0d; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[3] = 0x08; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[4] = 0x00; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[5] = 0x00; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[6] = 0x00; ++ priv->cck_txbbgain_ch14_table[22].ccktxbb_valuearray[7] = 0x00; ++ ++ priv->btxpower_tracking = TRUE; ++ priv->txpower_count = 0; ++ priv->btxpower_trackingInit = FALSE; ++ ++} ++#ifndef RTL8190P ++static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ // Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism ++ // can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w ++ // 3-wire by driver cause RF goes into wrong state. ++ if(priv->ieee80211->FwRWRF) ++ priv->btxpower_tracking = TRUE; ++ else ++ priv->btxpower_tracking = FALSE; ++ priv->txpower_count = 0; ++ priv->btxpower_trackingInit = FALSE; ++} ++#endif ++ ++void dm_initialize_txpower_tracking(struct net_device *dev) ++{ ++#ifndef RTL8190P ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++#ifdef RTL8190P ++ dm_InitializeTXPowerTracking_TSSI(dev); ++#else ++ //if(priv->bDcut == TRUE) ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ dm_InitializeTXPowerTracking_TSSI(dev); ++ else ++ dm_InitializeTXPowerTracking_ThermalMeter(dev); ++#endif ++} // dm_InitializeTXPowerTracking ++ ++ ++static void dm_CheckTXPowerTracking_TSSI(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ static u32 tx_power_track_counter = 0; ++ RT_TRACE(COMP_POWER_TRACKING,"%s()\n",__FUNCTION__); ++ if(read_nic_byte(dev, 0x11e) ==1) ++ return; ++ if(!priv->btxpower_tracking) ++ return; ++ tx_power_track_counter++; ++ ++ ++ if(tx_power_track_counter > 90) ++ { ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0); ++ #else ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ schedule_task(&priv->txpower_tracking_wq); ++ #else ++ queue_work(priv->priv_wq,&priv->txpower_tracking_wq); ++ #endif ++ #endif ++ tx_power_track_counter =0; ++ } ++ ++} ++ ++#ifndef RTL8190P ++static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ static u8 TM_Trigger=0; ++#if 0 ++ u1Byte i; ++ u4Byte tmpRegA; ++ for(i=0; i<50; i++) ++ { ++ tmpRegA = PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x12, 0x078); // 0x12: RF Reg[10:7] ++ PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); ++ //delay_us(100); ++ PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); ++ //delay_us(100); ++ } ++ DbgPrint("Trigger and readback ThermalMeter, write RF reg0x2 = 0x4d to 0x4f for 50 times\n"); ++#else ++ //DbgPrint("dm_CheckTXPowerTracking() \n"); ++ if(!priv->btxpower_tracking) ++ return; ++ else ++ { ++ if(priv->txpower_count <= 2) ++ { ++ priv->txpower_count++; ++ return; ++ } ++ } ++ ++ if(!TM_Trigger) ++ { ++ //Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash ++ //actually write reg0x02 bit1=0, then bit1=1. ++ //DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n"); ++ rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); ++ rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); ++ rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); ++ rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); ++ TM_Trigger = 1; ++ return; ++ } ++ else ++ { ++ //DbgPrint("Schedule TxPowerTrackingWorkItem\n"); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0); ++ #else ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ schedule_task(&priv->txpower_tracking_wq); ++ #else ++ queue_work(priv->priv_wq,&priv->txpower_tracking_wq); ++ #endif ++ #endif ++ TM_Trigger = 0; ++ } ++#endif ++ } ++#endif ++ ++static void dm_check_txpower_tracking(struct net_device *dev) ++{ ++#ifndef RTL8190P ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //static u32 tx_power_track_counter = 0; ++#endif ++#ifdef RTL8190P ++ dm_CheckTXPowerTracking_TSSI(dev); ++#else ++ //if(priv->bDcut == TRUE) ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ dm_CheckTXPowerTracking_TSSI(dev); ++ else ++ dm_CheckTXPowerTracking_ThermalMeter(dev); ++#endif ++ ++} // dm_CheckTXPowerTracking ++ ++ ++static void dm_CCKTxPowerAdjust_TSSI(struct net_device *dev, bool bInCH14) ++{ ++ u32 TempVal; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //Write 0xa22 0xa23 ++ TempVal = 0; ++ if(!bInCH14){ ++ //Write 0xa22 0xa23 ++ TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[0] + ++ (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[1]<<8)) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_TxFilter1,bMaskHWord, TempVal); ++ //Write 0xa24 ~ 0xa27 ++ TempVal = 0; ++ TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[2] + ++ (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[3]<<8) + ++ (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[4]<<16 )+ ++ (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[5]<<24)); ++ rtl8192_setBBreg(dev, rCCK0_TxFilter2,bMaskDWord, TempVal); ++ //Write 0xa28 0xa29 ++ TempVal = 0; ++ TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[6] + ++ (priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[7]<<8)) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_DebugPort,bMaskLWord, TempVal); ++ } ++ else ++ { ++ TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[0] + ++ (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[1]<<8)) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_TxFilter1,bMaskHWord, TempVal); ++ //Write 0xa24 ~ 0xa27 ++ TempVal = 0; ++ TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[2] + ++ (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[3]<<8) + ++ (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[4]<<16 )+ ++ (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[5]<<24)); ++ rtl8192_setBBreg(dev, rCCK0_TxFilter2,bMaskDWord, TempVal); ++ //Write 0xa28 0xa29 ++ TempVal = 0; ++ TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[6] + ++ (priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[7]<<8)) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_DebugPort,bMaskLWord, TempVal); ++ } ++ ++ ++} ++#ifndef RTL8190P ++static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH14) ++{ ++ u32 TempVal; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ TempVal = 0; ++ if(!bInCH14) ++ { ++ //Write 0xa22 0xa23 ++ TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] + ++ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8) ; ++ rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); ++ RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", ++ rCCK0_TxFilter1, TempVal); ++ //Write 0xa24 ~ 0xa27 ++ TempVal = 0; ++ TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] + ++ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][3]<<8) + ++ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][4]<<16 )+ ++ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][5]<<24); ++ rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); ++ RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", ++ rCCK0_TxFilter2, TempVal); ++ //Write 0xa28 0xa29 ++ TempVal = 0; ++ TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] + ++ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); ++ RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", ++ rCCK0_DebugPort, TempVal); ++ } ++ else ++ { ++// priv->CCKTxPowerAdjustCntNotCh14++; //cosa add for debug. ++ //Write 0xa22 0xa23 ++ TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] + ++ (CCKSwingTable_Ch14[priv->CCK_index][1]<<8) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); ++ RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", ++ rCCK0_TxFilter1, TempVal); ++ //Write 0xa24 ~ 0xa27 ++ TempVal = 0; ++ TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] + ++ (CCKSwingTable_Ch14[priv->CCK_index][3]<<8) + ++ (CCKSwingTable_Ch14[priv->CCK_index][4]<<16 )+ ++ (CCKSwingTable_Ch14[priv->CCK_index][5]<<24); ++ rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); ++ RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", ++ rCCK0_TxFilter2, TempVal); ++ //Write 0xa28 0xa29 ++ TempVal = 0; ++ TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] + ++ (CCKSwingTable_Ch14[priv->CCK_index][7]<<8) ; ++ ++ rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); ++ RT_TRACE(COMP_POWER_TRACKING,"CCK chnl 14, reg 0x%x = 0x%x\n", ++ rCCK0_DebugPort, TempVal); ++ } ++ } ++#endif ++ ++ ++void dm_cck_txpower_adjust(struct net_device *dev, bool binch14) ++{ // dm_CCKTxPowerAdjust ++#ifndef RTL8190P ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++#ifdef RTL8190P ++ dm_CCKTxPowerAdjust_TSSI(dev, binch14); ++#else ++ //if(priv->bDcut == TRUE) ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ dm_CCKTxPowerAdjust_TSSI(dev, binch14); ++ else ++ dm_CCKTxPowerAdjust_ThermalMeter(dev, binch14); ++#endif ++} ++ ++ ++#ifndef RTL8192U ++static void dm_txpower_reset_recovery( ++ struct net_device *dev ++) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ RT_TRACE(COMP_POWER_TRACKING, "Start Reset Recovery ==>\n"); ++ rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n",priv->rfa_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n",priv->CCKPresentAttentuation); ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ ++ rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n",priv->rfc_txpowertrackingindex); ++ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain); ++ ++} // dm_TXPowerResetRecovery ++ ++void dm_restore_dynamic_mechanism_state(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 reg_ratr = priv->rate_adaptive.last_ratr; ++ ++ if(!priv->up) ++ { ++ RT_TRACE(COMP_RATE, "<---- dm_restore_dynamic_mechanism_state(): driver is going to unload\n"); ++ return; ++ } ++ ++ // ++ // Restore previous state for rate adaptive ++ // ++ if(priv->rate_adaptive.rate_adaptive_disabled) ++ return; ++ // TODO: Only 11n mode is implemented currently, ++ if( !(priv->ieee80211->mode==WIRELESS_MODE_N_24G || ++ priv->ieee80211->mode==WIRELESS_MODE_N_5G)) ++ return; ++ { ++ /* 2007/11/15 MH Copy from 8190PCI. */ ++ u32 ratr_value; ++ ratr_value = reg_ratr; ++ if(priv->rf_type == RF_1T2R) // 1T2R, Spatial Stream 2 should be disabled ++ { ++ ratr_value &=~ (RATE_ALL_OFDM_2SS); ++ //DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value); ++ } ++ //DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value); ++ //cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]); ++ write_nic_dword(dev, RATR0, ratr_value); ++ write_nic_byte(dev, UFWP, 1); ++#if 0 // Disable old code. ++ u1Byte index; ++ u4Byte input_value; ++ index = (u1Byte)((((pu4Byte)(val))[0]) >> 28); ++ input_value = (((pu4Byte)(val))[0]) & 0x0fffffff; ++ // TODO: Correct it. Emily 2007.01.11 ++ PlatformEFIOWrite4Byte(Adapter, RATR0+index*4, input_value); ++#endif ++ } ++ //Resore TX Power Tracking Index ++ if(priv->btxpower_trackingInit && priv->btxpower_tracking){ ++ dm_txpower_reset_recovery(dev); ++ } ++ ++ // ++ //Restore BB Initial Gain ++ // ++ dm_bb_initialgain_restore(dev); ++ ++} // DM_RestoreDynamicMechanismState ++ ++static void dm_bb_initialgain_restore(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 bit_mask = 0x7f; //Bit0~ Bit6 ++ ++ if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) ++ return; ++ ++ //Disable Initial Gain ++ //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800); ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. ++ rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, (u32)priv->initgain_backup.xaagccore1); ++ rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, (u32)priv->initgain_backup.xbagccore1); ++ rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, bit_mask, (u32)priv->initgain_backup.xcagccore1); ++ rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, bit_mask, (u32)priv->initgain_backup.xdagccore1); ++ bit_mask = bMaskByte2; ++ rtl8192_setBBreg(dev, rCCK0_CCA, bit_mask, (u32)priv->initgain_backup.cca); ++ ++ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1); ++ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1); ++ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1); ++ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1); ++ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca); ++ //Enable Initial Gain ++ //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100); ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite. ++ ++} // dm_BBInitialGainRestore ++ ++ ++void dm_backup_dynamic_mechanism_state(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ // Fsync to avoid reset ++ priv->bswitch_fsync = false; ++ priv->bfsync_processing = false; ++ //Backup BB InitialGain ++ dm_bb_initialgain_backup(dev); ++ ++} // DM_BackupDynamicMechanismState ++ ++ ++static void dm_bb_initialgain_backup(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 bit_mask = bMaskByte0; //Bit0~ Bit6 ++ ++ if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) ++ return; ++ ++ //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800); ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. ++ priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask); ++ priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask); ++ priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bit_mask); ++ priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, bit_mask); ++ bit_mask = bMaskByte2; ++ priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, bit_mask); ++ ++ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1); ++ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1); ++ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1); ++ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1); ++ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca); ++ ++} // dm_BBInitialGainBakcup ++ ++#endif ++/*----------------------------------------------------------------------------- ++ * Function: dm_change_dynamic_initgain_thresh() ++ * ++ * Overview: ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/29/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++void dm_change_dynamic_initgain_thresh(struct net_device *dev, u32 dm_type, u32 dm_value) ++{ ++ if (dm_type == DIG_TYPE_THRESH_HIGH) ++ { ++ dm_digtable.rssi_high_thresh = dm_value; ++ } ++ else if (dm_type == DIG_TYPE_THRESH_LOW) ++ { ++ dm_digtable.rssi_low_thresh = dm_value; ++ } ++ else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) ++ { ++ dm_digtable.rssi_high_power_highthresh = dm_value; ++ } ++ else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) ++ { ++ dm_digtable.rssi_high_power_highthresh = dm_value; ++ } ++ else if (dm_type == DIG_TYPE_ENABLE) ++ { ++ dm_digtable.dig_state = DM_STA_DIG_MAX; ++ dm_digtable.dig_enable_flag = true; ++ } ++ else if (dm_type == DIG_TYPE_DISABLE) ++ { ++ dm_digtable.dig_state = DM_STA_DIG_MAX; ++ dm_digtable.dig_enable_flag = false; ++ } ++ else if (dm_type == DIG_TYPE_DBG_MODE) ++ { ++ if(dm_value >= DM_DBG_MAX) ++ dm_value = DM_DBG_OFF; ++ dm_digtable.dbg_mode = (u8)dm_value; ++ } ++ else if (dm_type == DIG_TYPE_RSSI) ++ { ++ if(dm_value > 100) ++ dm_value = 30; ++ dm_digtable.rssi_val = (long)dm_value; ++ } ++ else if (dm_type == DIG_TYPE_ALGORITHM) ++ { ++ if (dm_value >= DIG_ALGO_MAX) ++ dm_value = DIG_ALGO_BY_FALSE_ALARM; ++ if(dm_digtable.dig_algorithm != (u8)dm_value) ++ dm_digtable.dig_algorithm_switch = 1; ++ dm_digtable.dig_algorithm = (u8)dm_value; ++ } ++ else if (dm_type == DIG_TYPE_BACKOFF) ++ { ++ if(dm_value > 30) ++ dm_value = 30; ++ dm_digtable.backoff_val = (u8)dm_value; ++ } ++ else if(dm_type == DIG_TYPE_RX_GAIN_MIN) ++ { ++ if(dm_value == 0) ++ dm_value = 0x1; ++ dm_digtable.rx_gain_range_min = (u8)dm_value; ++ } ++ else if(dm_type == DIG_TYPE_RX_GAIN_MAX) ++ { ++ if(dm_value > 0x50) ++ dm_value = 0x50; ++ dm_digtable.rx_gain_range_max = (u8)dm_value; ++ } ++} /* DM_ChangeDynamicInitGainThresh */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_dig_init() ++ * ++ * Overview: Set DIG scheme init value. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/15/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void dm_dig_init(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ /* 2007/10/05 MH Disable DIG scheme now. Not tested. */ ++ dm_digtable.dig_enable_flag = true; ++ dm_digtable.dig_algorithm = DIG_ALGO_BY_RSSI; ++ dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig ++ dm_digtable.dig_algorithm_switch = 0; ++ ++ /* 2007/10/04 MH Define init gain threshol. */ ++ dm_digtable.dig_state = DM_STA_DIG_MAX; ++ dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; ++ dm_digtable.initialgain_lowerbound_state = false; ++ ++ dm_digtable.rssi_low_thresh = DM_DIG_THRESH_LOW; ++ dm_digtable.rssi_high_thresh = DM_DIG_THRESH_HIGH; ++ ++ dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; ++ dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; ++ ++ dm_digtable.rssi_val = 50; //for new dig debug rssi value ++ dm_digtable.backoff_val = DM_DIG_BACKOFF; ++ dm_digtable.rx_gain_range_max = DM_DIG_MAX; ++ if(priv->CustomerID == RT_CID_819x_Netcore) ++ dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore; ++ else ++ dm_digtable.rx_gain_range_min = DM_DIG_MIN; ++ ++} /* dm_dig_init */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_ctrl_initgain_byrssi() ++ * ++ * Overview: Driver must monitor RSSI and notify firmware to change initial ++ * gain according to different threshold. BB team provide the ++ * suggested solution. ++ * ++ * Input: struct net_device *dev ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/27/2008 amy Create Version 0 porting from windows code. ++ *---------------------------------------------------------------------------*/ ++static void dm_ctrl_initgain_byrssi(struct net_device *dev) ++{ ++ ++ if (dm_digtable.dig_enable_flag == false) ++ return; ++ ++ if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) ++ dm_ctrl_initgain_byrssi_by_fwfalse_alarm(dev); ++ else if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) ++ dm_ctrl_initgain_byrssi_by_driverrssi(dev); ++ else ++ return; ++} ++ ++ ++static void dm_ctrl_initgain_byrssi_by_driverrssi( ++ struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 i; ++ static u8 fw_dig=0; ++ ++ if (dm_digtable.dig_enable_flag == false) ++ return; ++ ++ //DbgPrint("Dig by Sw Rssi \n"); ++ if(dm_digtable.dig_algorithm_switch) // if swithed algorithm, we have to disable FW Dig. ++ fw_dig = 0; ++ if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled ++ {// FW DIG Off ++ for(i=0; i<3; i++) ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. ++ fw_dig++; ++ dm_digtable.dig_state = DM_STA_DIG_OFF; //fw dig off. ++ } ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ dm_digtable.cur_connect_state = DIG_CONNECT; ++ else ++ dm_digtable.cur_connect_state = DIG_DISCONNECT; ++ ++ //DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d \n", ++ //DM_DigTable.PreConnectState, DM_DigTable.CurConnectState); ++ ++ if(dm_digtable.dbg_mode == DM_DBG_OFF) ++ dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb; ++ //DbgPrint("DM_DigTable.Rssi_val = %d \n", DM_DigTable.Rssi_val); ++ dm_initial_gain(dev); ++ dm_pd_th(dev); ++ dm_cs_ratio(dev); ++ if(dm_digtable.dig_algorithm_switch) ++ dm_digtable.dig_algorithm_switch = 0; ++ dm_digtable.pre_connect_state = dm_digtable.cur_connect_state; ++ ++} /* dm_CtrlInitGainByRssi */ ++ ++static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( ++ struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ static u32 reset_cnt = 0; ++ u8 i; ++ ++ if (dm_digtable.dig_enable_flag == false) ++ return; ++ ++ if(dm_digtable.dig_algorithm_switch) ++ { ++ dm_digtable.dig_state = DM_STA_DIG_MAX; ++ // Fw DIG On. ++ for(i=0; i<3; i++) ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite. ++ dm_digtable.dig_algorithm_switch = 0; ++ } ++ ++ if (priv->ieee80211->state != IEEE80211_LINKED) ++ return; ++ ++ // For smooth, we can not change DIG state. ++ if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_low_thresh) && ++ (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh)) ++ { ++ return; ++ } ++ //DbgPrint("Dig by Fw False Alarm\n"); ++ //if (DM_DigTable.Dig_State == DM_STA_DIG_OFF) ++ /*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d", ++ pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh, ++ DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/ ++ /* 1. When RSSI decrease, We have to judge if it is smaller than a treshold ++ and then execute below step. */ ++ if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh)) ++ { ++ /* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters ++ will be reset to init value. We must prevent the condition. */ ++ if (dm_digtable.dig_state == DM_STA_DIG_OFF && ++ (priv->reset_count == reset_cnt)) ++ { ++ return; ++ } ++ else ++ { ++ reset_cnt = priv->reset_count; ++ } ++ ++ // If DIG is off, DIG high power state must reset. ++ dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; ++ dm_digtable.dig_state = DM_STA_DIG_OFF; ++ ++ // 1.1 DIG Off. ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite. ++ ++ // 1.2 Set initial gain. ++ write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17); ++ write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17); ++ write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x17); ++ write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x17); ++ ++ // 1.3 Lower PD_TH for OFDM. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ ++ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); ++ #endif ++ /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(pAdapter, rOFDM0_RxDetector1, 0x40); ++ */ ++ //else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E) ++ ++ ++ //else ++ //PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40); ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ ++ // 1.4 Lower CS ratio for CCK. ++ write_nic_byte(dev, 0xa0a, 0x08); ++ ++ // 1.5 Higher EDCCA. ++ //PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325); ++ return; ++ ++ } ++ ++ /* 2. When RSSI increase, We have to judge if it is larger than a treshold ++ and then execute below step. */ ++ if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) ) ++ { ++ u8 reset_flag = 0; ++ ++ if (dm_digtable.dig_state == DM_STA_DIG_ON && ++ (priv->reset_count == reset_cnt)) ++ { ++ dm_ctrl_initgain_byrssi_highpwr(dev); ++ return; ++ } ++ else ++ { ++ if (priv->reset_count != reset_cnt) ++ reset_flag = 1; ++ ++ reset_cnt = priv->reset_count; ++ } ++ ++ dm_digtable.dig_state = DM_STA_DIG_ON; ++ //DbgPrint("DIG ON\n\r"); ++ ++ // 2.1 Set initial gain. ++ // 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment. ++ if (reset_flag == 1) ++ { ++ write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x2c); ++ write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x2c); ++ write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x2c); ++ write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x2c); ++ } ++ else ++ { ++ write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x20); ++ write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x20); ++ write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x20); ++ write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x20); ++ } ++ ++ // 2.2 Higher PD_TH for OFDM. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ ++ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); ++ #endif ++ /* ++ else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ */ ++ //else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E) ++ ++ //else ++ //PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42); ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); ++ ++ // 2.3 Higher CS ratio for CCK. ++ write_nic_byte(dev, 0xa0a, 0xcd); ++ ++ // 2.4 Lower EDCCA. ++ /* 2008/01/11 MH 90/92 series are the same. */ ++ //PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346); ++ ++ // 2.5 DIG On. ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite. ++ ++ } ++ ++ dm_ctrl_initgain_byrssi_highpwr(dev); ++ ++} /* dm_CtrlInitGainByRssi */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_ctrl_initgain_byrssi_highpwr() ++ * ++ * Overview: ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/28/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void dm_ctrl_initgain_byrssi_highpwr( ++ struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ static u32 reset_cnt_highpwr = 0; ++ ++ // For smooth, we can not change high power DIG state in the range. ++ if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_high_power_lowthresh) && ++ (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh)) ++ { ++ return; ++ } ++ ++ /* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if ++ it is larger than a treshold and then execute below step. */ ++ // 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue. ++ if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh) ++ { ++ if (dm_digtable.dig_highpwr_state == DM_STA_DIG_ON && ++ (priv->reset_count == reset_cnt_highpwr)) ++ return; ++ else ++ dm_digtable.dig_highpwr_state = DM_STA_DIG_ON; ++ ++ // 3.1 Higher PD_TH for OFDM for high power state. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); ++ #endif ++ ++ /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); ++ */ ++ ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); ++ } ++ else ++ { ++ if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF&& ++ (priv->reset_count == reset_cnt_highpwr)) ++ return; ++ else ++ dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF; ++ ++ if (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_lowthresh && ++ priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) ++ { ++ // 3.2 Recover PD_TH for OFDM for normal power region. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); ++ #endif ++ /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ */ ++ ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); ++ } ++ } ++ ++ reset_cnt_highpwr = priv->reset_count; ++ ++} /* dm_CtrlInitGainByRssiHighPwr */ ++ ++ ++static void dm_initial_gain( ++ struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 initial_gain=0; ++ static u8 initialized=0, force_write=0; ++ static u32 reset_cnt=0; ++ ++ if(dm_digtable.dig_algorithm_switch) ++ { ++ initialized = 0; ++ reset_cnt = 0; ++ } ++ ++ if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) ++ { ++ if(dm_digtable.cur_connect_state == DIG_CONNECT) ++ { ++ if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max) ++ dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_max; ++ else if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min) ++ dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_min; ++ else ++ dm_digtable.cur_ig_value = dm_digtable.rssi_val+10-dm_digtable.backoff_val; ++ } ++ else //current state is disconnected ++ { ++ if(dm_digtable.cur_ig_value == 0) ++ dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; ++ else ++ dm_digtable.cur_ig_value = dm_digtable.pre_ig_value; ++ } ++ } ++ else // disconnected -> connected or connected -> disconnected ++ { ++ dm_digtable.cur_ig_value = priv->DefaultInitialGain[0]; ++ dm_digtable.pre_ig_value = 0; ++ } ++ //DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue); ++ ++ // if silent reset happened, we should rewrite the values back ++ if(priv->reset_count != reset_cnt) ++ { ++ force_write = 1; ++ reset_cnt = priv->reset_count; ++ } ++ ++ if(dm_digtable.pre_ig_value != read_nic_byte(dev, rOFDM0_XAAGCCore1)) ++ force_write = 1; ++ ++ { ++ if((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) ++ || !initialized || force_write) ++ { ++ initial_gain = (u8)dm_digtable.cur_ig_value; ++ //DbgPrint("Write initial gain = 0x%x\n", initial_gain); ++ // Set initial gain. ++ write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); ++ write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); ++ write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); ++ write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); ++ dm_digtable.pre_ig_value = dm_digtable.cur_ig_value; ++ initialized = 1; ++ force_write = 0; ++ } ++ } ++} ++ ++static void dm_pd_th( ++ struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ static u8 initialized=0, force_write=0; ++ static u32 reset_cnt = 0; ++ ++ if(dm_digtable.dig_algorithm_switch) ++ { ++ initialized = 0; ++ reset_cnt = 0; ++ } ++ ++ if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) ++ { ++ if(dm_digtable.cur_connect_state == DIG_CONNECT) ++ { ++ if (dm_digtable.rssi_val >= dm_digtable.rssi_high_power_highthresh) ++ dm_digtable.curpd_thstate = DIG_PD_AT_HIGH_POWER; ++ else if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)) ++ dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; ++ else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) && ++ (dm_digtable.rssi_val < dm_digtable.rssi_high_power_lowthresh)) ++ dm_digtable.curpd_thstate = DIG_PD_AT_NORMAL_POWER; ++ else ++ dm_digtable.curpd_thstate = dm_digtable.prepd_thstate; ++ } ++ else ++ { ++ dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; ++ } ++ } ++ else // disconnected -> connected or connected -> disconnected ++ { ++ dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; ++ } ++ ++ // if silent reset happened, we should rewrite the values back ++ if(priv->reset_count != reset_cnt) ++ { ++ force_write = 1; ++ reset_cnt = priv->reset_count; ++ } ++ ++ { ++ if((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) || ++ (initialized<=3) || force_write) ++ { ++ //DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState); ++ if(dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) ++ { ++ // Lower PD_TH for OFDM. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ ++ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); ++ #endif ++ /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x40); ++ */ ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ } ++ else if(dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) ++ { ++ // Higher PD_TH for OFDM. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */ ++ // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same. ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); ++ #endif ++ /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); ++ */ ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); ++ } ++ else if(dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) ++ { ++ // Higher PD_TH for OFDM for high power state. ++ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ++ { ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); ++ #else ++ write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); ++ #endif ++ /*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P) ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x41); ++ */ ++ } ++ else ++ write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); ++ } ++ dm_digtable.prepd_thstate = dm_digtable.curpd_thstate; ++ if(initialized <= 3) ++ initialized++; ++ force_write = 0; ++ } ++ } ++} ++ ++static void dm_cs_ratio( ++ struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ static u8 initialized=0,force_write=0; ++ static u32 reset_cnt = 0; ++ ++ if(dm_digtable.dig_algorithm_switch) ++ { ++ initialized = 0; ++ reset_cnt = 0; ++ } ++ ++ if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) ++ { ++ if(dm_digtable.cur_connect_state == DIG_CONNECT) ++ { ++ if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)) ++ dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; ++ else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) ) ++ dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER; ++ else ++ dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state; ++ } ++ else ++ { ++ dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; ++ } ++ } ++ else // disconnected -> connected or connected -> disconnected ++ { ++ dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; ++ } ++ ++ // if silent reset happened, we should rewrite the values back ++ if(priv->reset_count != reset_cnt) ++ { ++ force_write = 1; ++ reset_cnt = priv->reset_count; ++ } ++ ++ ++ { ++ if((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) || ++ !initialized || force_write) ++ { ++ //DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState); ++ if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) ++ { ++ // Lower CS ratio for CCK. ++ write_nic_byte(dev, 0xa0a, 0x08); ++ } ++ else if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) ++ { ++ // Higher CS ratio for CCK. ++ write_nic_byte(dev, 0xa0a, 0xcd); ++ } ++ dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state; ++ initialized = 1; ++ force_write = 0; ++ } ++ } ++} ++ ++void dm_init_edca_turbo(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ priv->bcurrent_turbo_EDCA = false; ++ priv->ieee80211->bis_any_nonbepkts = false; ++ priv->bis_cur_rdlstate = false; ++} // dm_init_edca_turbo ++ ++#if 1 ++static void dm_check_edca_turbo( ++ struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; ++ //PSTA_QOS pStaQos = pMgntInfo->pStaQos; ++ ++ // Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. ++ static unsigned long lastTxOkCnt = 0; ++ static unsigned long lastRxOkCnt = 0; ++ unsigned long curTxOkCnt = 0; ++ unsigned long curRxOkCnt = 0; ++ ++ // ++ // Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters ++ // should follow the settings from QAP. By Bruce, 2007-12-07. ++ // ++ #if 1 ++ if(priv->ieee80211->state != IEEE80211_LINKED) ++ goto dm_CheckEdcaTurbo_EXIT; ++ #endif ++ // We do not turn on EDCA turbo mode for some AP that has IOT issue ++ if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO) ++ goto dm_CheckEdcaTurbo_EXIT; ++ ++// printk("========>%s():bis_any_nonbepkts is %d\n",__FUNCTION__,priv->bis_any_nonbepkts); ++ // Check the status for current condition. ++ if(!priv->ieee80211->bis_any_nonbepkts) ++ { ++ curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; ++ curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; ++ // For RT-AP, we needs to turn it on when Rx>Tx ++ if(curRxOkCnt > 4*curTxOkCnt) ++ { ++ //printk("%s():curRxOkCnt > 4*curTxOkCnt\n"); ++ if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) ++ { ++ write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]); ++ priv->bis_cur_rdlstate = true; ++ } ++ } ++ else ++ { ++ ++ //printk("%s():curRxOkCnt < 4*curTxOkCnt\n"); ++ if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) ++ { ++ write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]); ++ priv->bis_cur_rdlstate = false; ++ } ++ ++ } ++ ++ priv->bcurrent_turbo_EDCA = true; ++ } ++ else ++ { ++ // ++ // Turn Off EDCA turbo here. ++ // Restore original EDCA according to the declaration of AP. ++ // ++ if(priv->bcurrent_turbo_EDCA) ++ { ++ ++ { ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters; ++ u8 mode = priv->ieee80211->mode; ++ ++ // For Each time updating EDCA parameter, reset EDCA turbo mode status. ++ dm_init_edca_turbo(dev); ++ u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime; ++ u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0]))<< AC_PARAM_TXOP_LIMIT_OFFSET)| ++ (((u32)(qos_parameters->cw_max[0]))<< AC_PARAM_ECW_MAX_OFFSET)| ++ (((u32)(qos_parameters->cw_min[0]))<< AC_PARAM_ECW_MIN_OFFSET)| ++ ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET)); ++ printk("===>u4bAcParam:%x, ", u4bAcParam); ++ //write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam); ++ write_nic_dword(dev, EDCAPARA_BE, u4bAcParam); ++ ++ // Check ACM bit. ++ // If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. ++ { ++ // TODO: Modified this part and try to set acm control in only 1 IO processing!! ++ ++ PACI_AIFSN pAciAifsn = (PACI_AIFSN)&(qos_parameters->aifs[0]); ++ u8 AcmCtrl = read_nic_byte( dev, AcmHwCtrl ); ++ if( pAciAifsn->f.ACM ) ++ { // ACM bit is 1. ++ AcmCtrl |= AcmHw_BeqEn; ++ } ++ else ++ { // ACM bit is 0. ++ AcmCtrl &= (~AcmHw_BeqEn); ++ } ++ ++ RT_TRACE( COMP_QOS,"SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl ) ; ++ write_nic_byte(dev, AcmHwCtrl, AcmCtrl ); ++ } ++ } ++ priv->bcurrent_turbo_EDCA = false; ++ } ++ } ++ ++ ++dm_CheckEdcaTurbo_EXIT: ++ // Set variables for next time. ++ priv->ieee80211->bis_any_nonbepkts = false; ++ lastTxOkCnt = priv->stats.txbytesunicast; ++ lastRxOkCnt = priv->stats.rxbytesunicast; ++} // dm_CheckEdcaTurbo ++#endif ++ ++static void dm_init_ctstoself(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); ++ ++ priv->ieee80211->bCTSToSelfEnable = TRUE; ++ priv->ieee80211->CTSToSelfTH = CTSToSelfTHVal; ++} ++ ++static void dm_ctstoself(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); ++ PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo; ++ static unsigned long lastTxOkCnt = 0; ++ static unsigned long lastRxOkCnt = 0; ++ unsigned long curTxOkCnt = 0; ++ unsigned long curRxOkCnt = 0; ++ ++ if(priv->ieee80211->bCTSToSelfEnable != TRUE) ++ { ++ pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; ++ return; ++ } ++ /* ++ 1. Uplink ++ 2. Linksys350/Linksys300N ++ 3. <50 disable, >55 enable ++ */ ++ ++ if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) ++ { ++ curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; ++ curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; ++ if(curRxOkCnt > 4*curTxOkCnt) //downlink, disable CTS to self ++ { ++ pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; ++ //DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n"); ++ } ++ else //uplink ++ { ++ #if 1 ++ pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; ++ #else ++ if(priv->undecorated_smoothed_pwdb < priv->ieee80211->CTSToSelfTH) // disable CTS to self ++ { ++ pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF; ++ //DbgPrint("dm_CTSToSelf() ==> CTS to self disabled\n"); ++ } ++ else if(priv->undecorated_smoothed_pwdb >= (priv->ieee80211->CTSToSelfTH+5)) // enable CTS to self ++ { ++ pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF; ++ //DbgPrint("dm_CTSToSelf() ==> CTS to self enabled\n"); ++ } ++ #endif ++ } ++ ++ lastTxOkCnt = priv->stats.txbytesunicast; ++ lastRxOkCnt = priv->stats.rxbytesunicast; ++ } ++} ++ ++ ++#if 0 ++/*----------------------------------------------------------------------------- ++ * Function: dm_rf_operation_test_callback() ++ * ++ * Overview: Only for RF operation test now. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/29/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++void dm_rf_operation_test_callback(unsigned long dev) ++{ ++// struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev); ++ u8 erfpath; ++ ++ ++ for(erfpath=0; erfpath<4; erfpath++) ++ { ++ //DbgPrint("Set RF-%d\n\r", eRFPath); ++ //PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3d7); ++ udelay(100); ++ } ++ ++ { ++ //PlatformSetPeriodicTimer(Adapter, &pHalData->RfTest1Timer, 500); ++ } ++ ++ // For test ++ { ++ //u8 i; ++ //PlatformSetPeriodicTimer(Adapter, &pHalData->RfTest1Timer, 500); ++#if 0 ++ for(i=0; i<50; i++) ++ { ++ // Write Test ++ PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); ++ //delay_us(100); ++ PHY_SetRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); ++ //delay_us(100); ++ PHY_SetRFReg(Adapter, RF90_PATH_C, 0x02, bMask12Bits, 0x4d); ++ //delay_us(100); ++ PHY_SetRFReg(Adapter, RF90_PATH_C, 0x02, bMask12Bits, 0x4f); ++ //delay_us(100); ++ ++#if 0 ++ // Read test ++ PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits); ++ //delay_us(100); ++ PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x02, bMask12Bits); ++ //delay_us(100); ++ PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x12, bMask12Bits); ++ //delay_us(100); ++ PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x12, bMask12Bits); ++ //delay_us(100); ++ PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x21, bMask12Bits); ++ //delay_us(100); ++ PHY_QueryRFReg(Adapter, RF90_PATH_A, 0x21, bMask12Bits); ++ //delay_us(100); ++#endif ++ } ++#endif ++ } ++ ++} /* DM_RfOperationTestCallBack */ ++#endif ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_check_rfctrl_gpio() ++ * ++ * Overview: Copy 8187B template for 9xseries. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/28/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++#if 1 ++static void dm_check_rfctrl_gpio(struct net_device * dev) ++{ ++#ifdef RTL8192E ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ ++ // Walk around for DTM test, we will not enable HW - radio on/off because r/w ++ // page 1 register before Lextra bus is enabled cause system fails when resuming ++ // from S4. 20080218, Emily ++ ++ // Stop to execute workitem to prevent S3/S4 bug. ++#ifdef RTL8190P ++ return; ++#endif ++#ifdef RTL8192U ++ return; ++#endif ++#ifdef RTL8192E ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->priv_wq,&priv->gpio_change_rf_wq,0); ++ #else ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ schedule_task(&priv->gpio_change_rf_wq); ++ #else ++ queue_work(priv->priv_wq,&priv->gpio_change_rf_wq); ++ #endif ++ #endif ++#endif ++ ++} /* dm_CheckRfCtrlGPIO */ ++ ++#endif ++/*----------------------------------------------------------------------------- ++ * Function: dm_check_pbc_gpio() ++ * ++ * Overview: Check if PBC button is pressed. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/28/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void dm_check_pbc_gpio(struct net_device *dev) ++{ ++#ifdef RTL8192U ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 tmp1byte; ++ ++ ++ tmp1byte = read_nic_byte(dev,GPI); ++ if(tmp1byte == 0xff) ++ return; ++ ++ if (tmp1byte&BIT6 || tmp1byte&BIT0) ++ { ++ // Here we only set bPbcPressed to TRUE ++ // After trigger PBC, the variable will be set to FALSE ++ RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n"); ++ priv->bpbc_pressed = true; ++ } ++#endif ++ ++} ++ ++#ifdef RTL8192E ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_GPIOChangeRF ++ * Overview: PCI will not support workitem call back HW radio on-off control. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 02/21/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void dm_gpio_change_rf_callback(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct r8192_priv *priv = container_of(dwork,struct r8192_priv,gpio_change_rf_wq); ++ struct net_device *dev = priv->ieee80211->dev; ++#else ++extern void dm_gpio_change_rf_callback(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ u8 tmp1byte; ++ RT_RF_POWER_STATE eRfPowerStateToSet; ++ bool bActuallySet = false; ++ ++ bActuallySet=false; ++ ++ if(!priv->up) ++ { ++ RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),"dm_gpio_change_rf_callback(): Callback function breaks out!!\n"); ++ } ++ else ++ { ++ // 0x108 GPIO input register is read only ++ //set 0x108 B1= 1: RF-ON; 0: RF-OFF. ++ tmp1byte = read_nic_byte(dev,GPI); ++ ++ eRfPowerStateToSet = (tmp1byte&BIT1) ? eRfOn : eRfOff; ++ ++ if( (priv->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn)) ++ { ++ RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio ON\n"); ++ ++ priv->bHwRadioOff = false; ++ bActuallySet = true; ++ } ++ else if ( (priv->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff)) ++ { ++ RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio OFF\n"); ++ priv->bHwRadioOff = true; ++ bActuallySet = true; ++ } ++ ++ if(bActuallySet) ++ { ++ priv->bHwRfOffAction = 1; ++ MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); ++ //DrvIFIndicateCurrentPhyStatus(pAdapter); ++ ++ } ++ else ++ { ++ msleep(2000); ++ } ++ ++ } ++ ++} /* dm_GPIOChangeRF */ ++ ++#endif ++/*----------------------------------------------------------------------------- ++ * Function: DM_RFPathCheckWorkItemCallBack() ++ * ++ * Overview: Check if Current RF RX path is enabled ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 01/30/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void dm_rf_pathcheck_workitemcallback(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct r8192_priv *priv = container_of(dwork,struct r8192_priv,rfpath_check_wq); ++ struct net_device *dev =priv->ieee80211->dev; ++#else ++extern void dm_rf_pathcheck_workitemcallback(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ //bool bactually_set = false; ++ u8 rfpath = 0, i; ++ ++ ++ /* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will ++ always be the same. We only read 0xc04 now. */ ++ rfpath = read_nic_byte(dev, 0xc04); ++ ++ // Check Bit 0-3, it means if RF A-D is enabled. ++ for (i = 0; i < RF90_PATH_MAX; i++) ++ { ++ if (rfpath & (0x01<brfpath_rxenable[i] = 1; ++ else ++ priv->brfpath_rxenable[i] = 0; ++ } ++ if(!DM_RxPathSelTable.Enable) ++ return; ++ ++ dm_rxpath_sel_byrssi(dev); ++} /* DM_RFPathCheckWorkItemCallBack */ ++ ++static void dm_init_rxpath_selection(struct net_device * dev) ++{ ++ u8 i; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ DM_RxPathSelTable.Enable = 1; //default enabled ++ DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low; ++ DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH; ++ if(priv->CustomerID == RT_CID_819x_Netcore) ++ DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; ++ else ++ DM_RxPathSelTable.cck_method = CCK_Rx_Version_1; ++ DM_RxPathSelTable.DbgMode = DM_DBG_OFF; ++ DM_RxPathSelTable.disabledRF = 0; ++ for(i=0; i<4; i++) ++ { ++ DM_RxPathSelTable.rf_rssi[i] = 50; ++ DM_RxPathSelTable.cck_pwdb_sta[i] = -64; ++ DM_RxPathSelTable.rf_enable_rssi_th[i] = 100; ++ } ++} ++ ++static void dm_rxpath_sel_byrssi(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 i, max_rssi_index=0, min_rssi_index=0, sec_rssi_index=0, rf_num=0; ++ u8 tmp_max_rssi=0, tmp_min_rssi=0, tmp_sec_rssi=0; ++ u8 cck_default_Rx=0x2; //RF-C ++ u8 cck_optional_Rx=0x3;//RF-D ++ long tmp_cck_max_pwdb=0, tmp_cck_min_pwdb=0, tmp_cck_sec_pwdb=0; ++ u8 cck_rx_ver2_max_index=0, cck_rx_ver2_min_index=0, cck_rx_ver2_sec_index=0; ++ u8 cur_rf_rssi; ++ long cur_cck_pwdb; ++ static u8 disabled_rf_cnt=0, cck_Rx_Path_initialized=0; ++ u8 update_cck_rx_path; ++ ++ if(priv->rf_type != RF_2T4R) ++ return; ++ ++ if(!cck_Rx_Path_initialized) ++ { ++ DM_RxPathSelTable.cck_Rx_path = (read_nic_byte(dev, 0xa07)&0xf); ++ cck_Rx_Path_initialized = 1; ++ } ++ ++ DM_RxPathSelTable.disabledRF = 0xf; ++ DM_RxPathSelTable.disabledRF &=~ (read_nic_byte(dev, 0xc04)); ++ ++ if(priv->ieee80211->mode == WIRELESS_MODE_B) ++ { ++ DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; //pure B mode, fixed cck version2 ++ //DbgPrint("Pure B mode, use cck rx version2 \n"); ++ } ++ ++ //decide max/sec/min rssi index ++ for (i=0; istats.rx_rssi_percentage[i]; ++ ++ if(priv->brfpath_rxenable[i]) ++ { ++ rf_num++; ++ cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i]; ++ ++ if(rf_num == 1) // find first enabled rf path and the rssi values ++ { //initialize, set all rssi index to the same one ++ max_rssi_index = min_rssi_index = sec_rssi_index = i; ++ tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi; ++ } ++ else if(rf_num == 2) ++ { // we pick up the max index first, and let sec and min to be the same one ++ if(cur_rf_rssi >= tmp_max_rssi) ++ { ++ tmp_max_rssi = cur_rf_rssi; ++ max_rssi_index = i; ++ } ++ else ++ { ++ tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi; ++ sec_rssi_index = min_rssi_index = i; ++ } ++ } ++ else ++ { ++ if(cur_rf_rssi > tmp_max_rssi) ++ { ++ tmp_sec_rssi = tmp_max_rssi; ++ sec_rssi_index = max_rssi_index; ++ tmp_max_rssi = cur_rf_rssi; ++ max_rssi_index = i; ++ } ++ else if(cur_rf_rssi == tmp_max_rssi) ++ { // let sec and min point to the different index ++ tmp_sec_rssi = cur_rf_rssi; ++ sec_rssi_index = i; ++ } ++ else if((cur_rf_rssi < tmp_max_rssi) &&(cur_rf_rssi > tmp_sec_rssi)) ++ { ++ tmp_sec_rssi = cur_rf_rssi; ++ sec_rssi_index = i; ++ } ++ else if(cur_rf_rssi == tmp_sec_rssi) ++ { ++ if(tmp_sec_rssi == tmp_min_rssi) ++ { // let sec and min point to the different index ++ tmp_sec_rssi = cur_rf_rssi; ++ sec_rssi_index = i; ++ } ++ else ++ { ++ // This case we don't need to set any index ++ } ++ } ++ else if((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi)) ++ { ++ // This case we don't need to set any index ++ } ++ else if(cur_rf_rssi == tmp_min_rssi) ++ { ++ if(tmp_sec_rssi == tmp_min_rssi) ++ { // let sec and min point to the different index ++ tmp_min_rssi = cur_rf_rssi; ++ min_rssi_index = i; ++ } ++ else ++ { ++ // This case we don't need to set any index ++ } ++ } ++ else if(cur_rf_rssi < tmp_min_rssi) ++ { ++ tmp_min_rssi = cur_rf_rssi; ++ min_rssi_index = i; ++ } ++ } ++ } ++ } ++ ++ rf_num = 0; ++ // decide max/sec/min cck pwdb index ++ if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) ++ { ++ for (i=0; ibrfpath_rxenable[i]) ++ { ++ rf_num++; ++ cur_cck_pwdb = DM_RxPathSelTable.cck_pwdb_sta[i]; ++ ++ if(rf_num == 1) // find first enabled rf path and the rssi values ++ { //initialize, set all rssi index to the same one ++ cck_rx_ver2_max_index = cck_rx_ver2_min_index = cck_rx_ver2_sec_index = i; ++ tmp_cck_max_pwdb = tmp_cck_min_pwdb = tmp_cck_sec_pwdb = cur_cck_pwdb; ++ } ++ else if(rf_num == 2) ++ { // we pick up the max index first, and let sec and min to be the same one ++ if(cur_cck_pwdb >= tmp_cck_max_pwdb) ++ { ++ tmp_cck_max_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_max_index = i; ++ } ++ else ++ { ++ tmp_cck_sec_pwdb = tmp_cck_min_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_sec_index = cck_rx_ver2_min_index = i; ++ } ++ } ++ else ++ { ++ if(cur_cck_pwdb > tmp_cck_max_pwdb) ++ { ++ tmp_cck_sec_pwdb = tmp_cck_max_pwdb; ++ cck_rx_ver2_sec_index = cck_rx_ver2_max_index; ++ tmp_cck_max_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_max_index = i; ++ } ++ else if(cur_cck_pwdb == tmp_cck_max_pwdb) ++ { // let sec and min point to the different index ++ tmp_cck_sec_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_sec_index = i; ++ } ++ else if((cur_cck_pwdb < tmp_cck_max_pwdb) &&(cur_cck_pwdb > tmp_cck_sec_pwdb)) ++ { ++ tmp_cck_sec_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_sec_index = i; ++ } ++ else if(cur_cck_pwdb == tmp_cck_sec_pwdb) ++ { ++ if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb) ++ { // let sec and min point to the different index ++ tmp_cck_sec_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_sec_index = i; ++ } ++ else ++ { ++ // This case we don't need to set any index ++ } ++ } ++ else if((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb)) ++ { ++ // This case we don't need to set any index ++ } ++ else if(cur_cck_pwdb == tmp_cck_min_pwdb) ++ { ++ if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb) ++ { // let sec and min point to the different index ++ tmp_cck_min_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_min_index = i; ++ } ++ else ++ { ++ // This case we don't need to set any index ++ } ++ } ++ else if(cur_cck_pwdb < tmp_cck_min_pwdb) ++ { ++ tmp_cck_min_pwdb = cur_cck_pwdb; ++ cck_rx_ver2_min_index = i; ++ } ++ } ++ ++ } ++ } ++ } ++ ++ ++ // Set CCK Rx path ++ // reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path. ++ update_cck_rx_path = 0; ++ if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) ++ { ++ cck_default_Rx = cck_rx_ver2_max_index; ++ cck_optional_Rx = cck_rx_ver2_sec_index; ++ if(tmp_cck_max_pwdb != -64) ++ update_cck_rx_path = 1; ++ } ++ ++ if(tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2) ++ { ++ if((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH) ++ { ++ //record the enabled rssi threshold ++ DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = tmp_max_rssi+5; ++ //disable the BB Rx path, OFDM ++ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<>i) & 0x1) //disabled rf ++ { ++ if(tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i]) ++ { ++ //enable the BB Rx path ++ //DbgPrint("RF-%d is enabled. \n", 0x1<= KERNEL_VERSION(2,6,20) ++ queue_delayed_work(priv->priv_wq,&priv->rfpath_check_wq,0); ++#else ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ schedule_task(&priv->rfpath_check_wq); ++#else ++ queue_work(priv->priv_wq,&priv->rfpath_check_wq); ++#endif ++#endif ++} /* dm_CheckRxRFPath */ ++ ++ ++static void dm_init_fsync (struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ priv->ieee80211->fsync_time_interval = 500; ++ priv->ieee80211->fsync_rate_bitmap = 0x0f000800; ++ priv->ieee80211->fsync_rssi_threshold = 30; ++#ifdef RTL8190P ++ priv->ieee80211->bfsync_enable = true; ++#else ++ priv->ieee80211->bfsync_enable = false; ++#endif ++ priv->ieee80211->fsync_multiple_timeinterval = 3; ++ priv->ieee80211->fsync_firstdiff_ratethreshold= 100; ++ priv->ieee80211->fsync_seconddiff_ratethreshold= 200; ++ priv->ieee80211->fsync_state = Default_Fsync; ++ priv->framesyncMonitor = 1; // current default 0xc38 monitor on ++ ++ init_timer(&priv->fsync_timer); ++ priv->fsync_timer.data = (unsigned long)dev; ++ priv->fsync_timer.function = dm_fsync_timer_callback; ++} ++ ++ ++static void dm_deInit_fsync(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ del_timer_sync(&priv->fsync_timer); ++} ++ ++void dm_fsync_timer_callback(unsigned long data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct r8192_priv *priv = ieee80211_priv((struct net_device *)data); ++ u32 rate_index, rate_count = 0, rate_count_diff=0; ++ bool bSwitchFromCountDiff = false; ++ bool bDoubleTimeInterval = false; ++ ++ if( priv->ieee80211->state == IEEE80211_LINKED && ++ priv->ieee80211->bfsync_enable && ++ (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) ++ { ++ // Count rate 54, MCS [7], [12, 13, 14, 15] ++ u32 rate_bitmap; ++ for(rate_index = 0; rate_index <= 27; rate_index++) ++ { ++ rate_bitmap = 1 << rate_index; ++ if(priv->ieee80211->fsync_rate_bitmap & rate_bitmap) ++ rate_count+= priv->stats.received_rate_histogram[1][rate_index]; ++ } ++ ++ if(rate_count < priv->rate_record) ++ rate_count_diff = 0xffffffff - rate_count + priv->rate_record; ++ else ++ rate_count_diff = rate_count - priv->rate_record; ++ if(rate_count_diff < priv->rateCountDiffRecord) ++ { ++ ++ u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff; ++ // Contiune count ++ if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold) ++ priv->ContiuneDiffCount++; ++ else ++ priv->ContiuneDiffCount = 0; ++ ++ // Contiune count over ++ if(priv->ContiuneDiffCount >=2) ++ { ++ bSwitchFromCountDiff = true; ++ priv->ContiuneDiffCount = 0; ++ } ++ } ++ else ++ { ++ // Stop contiune count ++ priv->ContiuneDiffCount = 0; ++ } ++ ++ //If Count diff <= FsyncRateCountThreshold ++ if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold) ++ { ++ bSwitchFromCountDiff = true; ++ priv->ContiuneDiffCount = 0; ++ } ++ priv->rate_record = rate_count; ++ priv->rateCountDiffRecord = rate_count_diff; ++ RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync); ++ // if we never receive those mcs rate and rssi > 30 % then switch fsyn ++ if(priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff) ++ { ++ bDoubleTimeInterval = true; ++ priv->bswitch_fsync = !priv->bswitch_fsync; ++ if(priv->bswitch_fsync) ++ { ++ #ifdef RTL8190P ++ write_nic_byte(dev,0xC36, 0x00); ++ #else ++ write_nic_byte(dev,0xC36, 0x1c); ++ #endif ++ write_nic_byte(dev, 0xC3e, 0x90); ++ } ++ else ++ { ++ #ifdef RTL8190P ++ write_nic_byte(dev, 0xC36, 0x40); ++ #else ++ write_nic_byte(dev, 0xC36, 0x5c); ++ #endif ++ write_nic_byte(dev, 0xC3e, 0x96); ++ } ++ } ++ else if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold) ++ { ++ if(priv->bswitch_fsync) ++ { ++ priv->bswitch_fsync = false; ++ #ifdef RTL8190P ++ write_nic_byte(dev, 0xC36, 0x40); ++ #else ++ write_nic_byte(dev, 0xC36, 0x5c); ++ #endif ++ write_nic_byte(dev, 0xC3e, 0x96); ++ } ++ } ++ if(bDoubleTimeInterval){ ++ if(timer_pending(&priv->fsync_timer)) ++ del_timer_sync(&priv->fsync_timer); ++ priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval); ++ add_timer(&priv->fsync_timer); ++ } ++ else{ ++ if(timer_pending(&priv->fsync_timer)) ++ del_timer_sync(&priv->fsync_timer); ++ priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval); ++ add_timer(&priv->fsync_timer); ++ } ++ } ++ else ++ { ++ // Let Register return to default value; ++ if(priv->bswitch_fsync) ++ { ++ priv->bswitch_fsync = false; ++ #ifdef RTL8190P ++ write_nic_byte(dev, 0xC36, 0x40); ++ #else ++ write_nic_byte(dev, 0xC36, 0x5c); ++ #endif ++ write_nic_byte(dev, 0xC3e, 0x96); ++ } ++ priv->ContiuneDiffCount = 0; ++ #ifdef RTL8190P ++ write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd); ++ #else ++ write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); ++ #endif ++ } ++ RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount); ++ RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync); ++} ++ ++static void dm_StartHWFsync(struct net_device *dev) ++{ ++ RT_TRACE(COMP_HALDM, "%s\n", __FUNCTION__); ++ write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cf); ++ write_nic_byte(dev, 0xc3b, 0x41); ++} ++ ++static void dm_EndSWFsync(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ RT_TRACE(COMP_HALDM, "%s\n", __FUNCTION__); ++ del_timer_sync(&(priv->fsync_timer)); ++ ++ // Let Register return to default value; ++ if(priv->bswitch_fsync) ++ { ++ priv->bswitch_fsync = false; ++ ++ #ifdef RTL8190P ++ write_nic_byte(dev, 0xC36, 0x40); ++ #else ++ write_nic_byte(dev, 0xC36, 0x5c); ++#endif ++ ++ write_nic_byte(dev, 0xC3e, 0x96); ++ } ++ ++ priv->ContiuneDiffCount = 0; ++#ifndef RTL8190P ++ write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); ++#endif ++ ++} ++ ++static void dm_StartSWFsync(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 rateIndex; ++ u32 rateBitmap; ++ ++ RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__); ++ // Initial rate record to zero, start to record. ++ priv->rate_record = 0; ++ // Initial contiune diff count to zero, start to record. ++ priv->ContiuneDiffCount = 0; ++ priv->rateCountDiffRecord = 0; ++ priv->bswitch_fsync = false; ++ ++ if(priv->ieee80211->mode == WIRELESS_MODE_N_24G) ++ { ++ priv->ieee80211->fsync_firstdiff_ratethreshold= 600; ++ priv->ieee80211->fsync_seconddiff_ratethreshold = 0xffff; ++ } ++ else ++ { ++ priv->ieee80211->fsync_firstdiff_ratethreshold= 200; ++ priv->ieee80211->fsync_seconddiff_ratethreshold = 200; ++ } ++ for(rateIndex = 0; rateIndex <= 27; rateIndex++) ++ { ++ rateBitmap = 1 << rateIndex; ++ if(priv->ieee80211->fsync_rate_bitmap & rateBitmap) ++ priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex]; ++ } ++ if(timer_pending(&priv->fsync_timer)) ++ del_timer_sync(&priv->fsync_timer); ++ priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval); ++ add_timer(&priv->fsync_timer); ++ ++#ifndef RTL8190P ++ write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); ++#endif ++ ++} ++ ++static void dm_EndHWFsync(struct net_device *dev) ++{ ++ RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__); ++ write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); ++ write_nic_byte(dev, 0xc3b, 0x49); ++ ++} ++ ++void dm_check_fsync(struct net_device *dev) ++{ ++#define RegC38_Default 0 ++#define RegC38_NonFsync_Other_AP 1 ++#define RegC38_Fsync_AP_BCM 2 ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ //u32 framesyncC34; ++ static u8 reg_c38_State=RegC38_Default; ++ static u32 reset_cnt=0; ++ ++ RT_TRACE(COMP_HALDM, "RSSI %d TimeInterval %d MultipleTimeInterval %d\n", priv->ieee80211->fsync_rssi_threshold, priv->ieee80211->fsync_time_interval, priv->ieee80211->fsync_multiple_timeinterval); ++ RT_TRACE(COMP_HALDM, "RateBitmap 0x%x FirstDiffRateThreshold %d SecondDiffRateThreshold %d\n", priv->ieee80211->fsync_rate_bitmap, priv->ieee80211->fsync_firstdiff_ratethreshold, priv->ieee80211->fsync_seconddiff_ratethreshold); ++ ++ if( priv->ieee80211->state == IEEE80211_LINKED && ++ (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) ++ { ++ if(priv->ieee80211->bfsync_enable == 0) ++ { ++ switch(priv->ieee80211->fsync_state) ++ { ++ case Default_Fsync: ++ dm_StartHWFsync(dev); ++ priv->ieee80211->fsync_state = HW_Fsync; ++ break; ++ case SW_Fsync: ++ dm_EndSWFsync(dev); ++ dm_StartHWFsync(dev); ++ priv->ieee80211->fsync_state = HW_Fsync; ++ break; ++ case HW_Fsync: ++ default: ++ break; ++ } ++ } ++ else ++ { ++ switch(priv->ieee80211->fsync_state) ++ { ++ case Default_Fsync: ++ dm_StartSWFsync(dev); ++ priv->ieee80211->fsync_state = SW_Fsync; ++ break; ++ case HW_Fsync: ++ dm_EndHWFsync(dev); ++ dm_StartSWFsync(dev); ++ priv->ieee80211->fsync_state = SW_Fsync; ++ break; ++ case SW_Fsync: ++ default: ++ break; ++ ++ } ++ } ++ if(priv->framesyncMonitor) ++ { ++ if(reg_c38_State != RegC38_Fsync_AP_BCM) ++ { //For broadcom AP we write different default value ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector3, 0x15); ++ #else ++ write_nic_byte(dev, rOFDM0_RxDetector3, 0x95); ++ #endif ++ ++ reg_c38_State = RegC38_Fsync_AP_BCM; ++ } ++ } ++ } ++ else ++ { ++ switch(priv->ieee80211->fsync_state) ++ { ++ case HW_Fsync: ++ dm_EndHWFsync(dev); ++ priv->ieee80211->fsync_state = Default_Fsync; ++ break; ++ case SW_Fsync: ++ dm_EndSWFsync(dev); ++ priv->ieee80211->fsync_state = Default_Fsync; ++ break; ++ case Default_Fsync: ++ default: ++ break; ++ } ++ ++ if(priv->framesyncMonitor) ++ { ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ { ++ if(priv->undecorated_smoothed_pwdb <= RegC38_TH) ++ { ++ if(reg_c38_State != RegC38_NonFsync_Other_AP) ++ { ++ #ifdef RTL8190P ++ write_nic_byte(dev, rOFDM0_RxDetector3, 0x10); ++ #else ++ write_nic_byte(dev, rOFDM0_RxDetector3, 0x90); ++ #endif ++ ++ reg_c38_State = RegC38_NonFsync_Other_AP; ++ #if 0//cosa ++ if (Adapter->HardwareType == HARDWARE_TYPE_RTL8190P) ++ DbgPrint("Fsync is idle, rssi<=35, write 0xc38 = 0x%x \n", 0x10); ++ else ++ DbgPrint("Fsync is idle, rssi<=35, write 0xc38 = 0x%x \n", 0x90); ++ #endif ++ } ++ } ++ else if(priv->undecorated_smoothed_pwdb >= (RegC38_TH+5)) ++ { ++ if(reg_c38_State) ++ { ++ write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); ++ reg_c38_State = RegC38_Default; ++ //DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x \n", pHalData->framesync); ++ } ++ } ++ } ++ else ++ { ++ if(reg_c38_State) ++ { ++ write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); ++ reg_c38_State = RegC38_Default; ++ //DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x \n", pHalData->framesync); ++ } ++ } ++ } ++ } ++ if(priv->framesyncMonitor) ++ { ++ if(priv->reset_count != reset_cnt) ++ { //After silent reset, the reg_c38_State will be returned to default value ++ write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); ++ reg_c38_State = RegC38_Default; ++ reset_cnt = priv->reset_count; ++ //DbgPrint("reg_c38_State = 0 for silent reset. \n"); ++ } ++ } ++ else ++ { ++ if(reg_c38_State) ++ { ++ write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync); ++ reg_c38_State = RegC38_Default; ++ //DbgPrint("framesync no monitor, write 0xc38 = 0x%x \n", pHalData->framesync); ++ } ++ } ++} ++ ++#if 0 ++/*----------------------------------------------------------------------------- ++ * Function: DM_CheckLBusStatus() ++ * ++ * Overview: For 9x series, we must make sure LBUS is active for IO. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 02/22/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++extern s1Byte DM_CheckLBusStatus(IN PADAPTER Adapter) ++{ ++ PMGNT_INFO pMgntInfo=&Adapter->MgntInfo; ++ ++#if (HAL_CODE_BASE & RTL819X) ++ ++#if (HAL_CODE_BASE == RTL8192) ++ ++#if( DEV_BUS_TYPE==PCI_INTERFACE) ++ //return (pMgntInfo->bLbusEnable); // For debug only ++ return TRUE; ++#endif ++ ++#if( DEV_BUS_TYPE==USB_INTERFACE) ++ return TRUE; ++#endif ++ ++#endif // #if (HAL_CODE_BASE == RTL8192) ++ ++#if (HAL_CODE_BASE == RTL8190) ++ return TRUE; ++#endif // #if (HAL_CODE_BASE == RTL8190) ++ ++#endif // #if (HAL_CODE_BASE & RTL819X) ++} /* DM_CheckLBusStatus */ ++ ++#endif ++ ++/*----------------------------------------------------------------------------- ++ * Function: dm_shadow_init() ++ * ++ * Overview: Store all NIC MAC/BB register content. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/29/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++void dm_shadow_init(struct net_device *dev) ++{ ++ u8 page; ++ u16 offset; ++ ++ for (page = 0; page < 5; page++) ++ for (offset = 0; offset < 256; offset++) ++ { ++ dm_shadow[page][offset] = read_nic_byte(dev, offset+page*256); ++ //DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]); ++ } ++ ++ for (page = 8; page < 11; page++) ++ for (offset = 0; offset < 256; offset++) ++ dm_shadow[page][offset] = read_nic_byte(dev, offset+page*256); ++ ++ for (page = 12; page < 15; page++) ++ for (offset = 0; offset < 256; offset++) ++ dm_shadow[page][offset] = read_nic_byte(dev, offset+page*256); ++ ++} /* dm_shadow_init */ ++ ++/*---------------------------Define function prototype------------------------*/ ++/*----------------------------------------------------------------------------- ++ * Function: DM_DynamicTxPower() ++ * ++ * Overview: Detect Signal strength to control TX Registry ++ Tx Power Control For Near/Far Range ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 03/06/2008 Jacken Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++static void dm_init_dynamic_txpower(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ //Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. ++ priv->ieee80211->bdynamic_txpower_enable = true; //Default to enable Tx Power Control ++ priv->bLastDTPFlag_High = false; ++ priv->bLastDTPFlag_Low = false; ++ priv->bDynamicTxHighPower = false; ++ priv->bDynamicTxLowPower = false; ++} ++ ++static void dm_dynamic_txpower(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ unsigned int txhipower_threshhold=0; ++ unsigned int txlowpower_threshold=0; ++ if(priv->ieee80211->bdynamic_txpower_enable != true) ++ { ++ priv->bDynamicTxHighPower = false; ++ priv->bDynamicTxLowPower = false; ++ return; ++ } ++ //printk("priv->ieee80211->current_network.unknown_cap_exist is %d ,priv->ieee80211->current_network.broadcom_cap_exist is %d\n",priv->ieee80211->current_network.unknown_cap_exist,priv->ieee80211->current_network.broadcom_cap_exist); ++ if((priv->ieee80211->current_network.atheros_cap_exist ) && (priv->ieee80211->mode == IEEE_G)){ ++ txhipower_threshhold = TX_POWER_ATHEROAP_THRESH_HIGH; ++ txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW; ++ } ++ else ++ { ++ txhipower_threshhold = TX_POWER_NEAR_FIELD_THRESH_HIGH; ++ txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW; ++ } ++ ++// printk("=======>%s(): txhipower_threshhold is %d,txlowpower_threshold is %d\n",__FUNCTION__,txhipower_threshhold,txlowpower_threshold); ++ ++ RT_TRACE(COMP_TXAGC,"priv->undecorated_smoothed_pwdb = %ld \n" , priv->undecorated_smoothed_pwdb); ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ { ++ if(priv->undecorated_smoothed_pwdb >= txhipower_threshhold) ++ { ++ priv->bDynamicTxHighPower = true; ++ priv->bDynamicTxLowPower = false; ++ } ++ else ++ { ++ // high power state check ++ if(priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true) ++ { ++ priv->bDynamicTxHighPower = false; ++ } ++ // low power state check ++ if(priv->undecorated_smoothed_pwdb < 35) ++ { ++ priv->bDynamicTxLowPower = true; ++ } ++ else if(priv->undecorated_smoothed_pwdb >= 40) ++ { ++ priv->bDynamicTxLowPower = false; ++ } ++ } ++ } ++ else ++ { ++ //pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange; ++ priv->bDynamicTxHighPower = false; ++ priv->bDynamicTxLowPower = false; ++ } ++ ++ if( (priv->bDynamicTxHighPower != priv->bLastDTPFlag_High ) || ++ (priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low ) ) ++ { ++ RT_TRACE(COMP_TXAGC,"SetTxPowerLevel8190() channel = %d \n" , priv->ieee80211->current_network.channel); ++ ++ ++ rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel); ++ ++ } ++ priv->bLastDTPFlag_High = priv->bDynamicTxHighPower; ++ priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower; ++ ++} /* dm_dynamic_txpower */ ++ ++//added by vivi, for read tx rate and retrycount ++static void dm_check_txrateandretrycount(struct net_device * dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ //for 11n tx rate ++// priv->stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg); ++ ieee->softmac_stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg); ++ //printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate); ++ //for initial tx rate ++// priv->stats.last_packet_rate = read_nic_byte(dev, Initial_Tx_Rate_Reg); ++ ieee->softmac_stats.last_packet_rate = read_nic_byte(dev ,Initial_Tx_Rate_Reg); ++ //for tx tx retry count ++// priv->stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg); ++ ieee->softmac_stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg); ++} ++ ++static void dm_send_rssi_tofw(struct net_device *dev) ++{ ++ DCMD_TXCMD_T tx_cmd; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ // If we test chariot, we should stop the TX command ? ++ // Because 92E will always silent reset when we send tx command. We use register ++ // 0x1e0(byte) to botify driver. ++ write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb); ++ return; ++#if 1 ++ tx_cmd.Op = TXCMD_SET_RX_RSSI; ++ tx_cmd.Length = 4; ++ tx_cmd.Value = priv->undecorated_smoothed_pwdb; ++ ++ cmpk_message_handle_tx(dev, (u8*)&tx_cmd, ++ DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T)); ++#endif ++} ++ ++/*---------------------------Define function prototype------------------------*/ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E_dm.h +@@ -0,0 +1,320 @@ ++/***************************************************************************** ++ * Copyright(c) 2007, RealTEK Technology Inc. All Right Reserved. ++ * ++ * Module: Hal819xUsbDM.h (RTL8192 Header H File) ++ * ++ * ++ * Note: For dynamic control definition constant structure. ++ * ++ * ++ * Export: ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 10/04/2007 MHC Create initial version. ++ * ++ *****************************************************************************/ ++ /* Check to see if the file has been included already. */ ++#ifndef __R8192UDM_H__ ++#define __R8192UDM_H__ ++ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define OFDM_Table_Length 19 ++#define CCK_Table_length 12 ++ ++#define DM_DIG_THRESH_HIGH 40 ++#define DM_DIG_THRESH_LOW 35 ++ ++#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 ++#define DM_DIG_HIGH_PWR_THRESH_LOW 70 ++ ++#define BW_AUTO_SWITCH_HIGH_LOW 25 ++#define BW_AUTO_SWITCH_LOW_HIGH 30 ++ ++#define DM_check_fsync_time_interval 500 ++ ++ ++#define DM_DIG_BACKOFF 12 ++#define DM_DIG_MAX 0x36 ++#define DM_DIG_MIN 0x1c ++#define DM_DIG_MIN_Netcore 0x12 ++ ++#define RxPathSelection_SS_TH_low 30 ++#define RxPathSelection_diff_TH 18 ++ ++#define RateAdaptiveTH_High 50 ++#define RateAdaptiveTH_Low_20M 30 ++#define RateAdaptiveTH_Low_40M 10 ++#define VeryLowRSSI 15 ++#define CTSToSelfTHVal 35 ++ ++//defined by vivi, for tx power track ++#define E_FOR_TX_POWER_TRACK 300 ++//Dynamic Tx Power Control Threshold ++#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68 ++#define TX_POWER_NEAR_FIELD_THRESH_LOW 62 ++//added by amy for atheros AP ++#define TX_POWER_ATHEROAP_THRESH_HIGH 78 ++#define TX_POWER_ATHEROAP_THRESH_LOW 72 ++ ++//defined by vivi, for showing on UI. Newer firmware has changed to 0x1e0 ++#define Current_Tx_Rate_Reg 0x1e0//0x1b8 ++#define Initial_Tx_Rate_Reg 0x1e1 //0x1b9 ++#define Tx_Retry_Count_Reg 0x1ac ++#define RegC38_TH 20 ++#if 0 ++//---------------------------------------------------------------------------- ++// 8190 Rate Adaptive Table Register (offset 0x320, 4 byte) ++//---------------------------------------------------------------------------- ++ ++//CCK ++#define RATR_1M 0x00000001 ++#define RATR_2M 0x00000002 ++#define RATR_55M 0x00000004 ++#define RATR_11M 0x00000008 ++//OFDM ++#define RATR_6M 0x00000010 ++#define RATR_9M 0x00000020 ++#define RATR_12M 0x00000040 ++#define RATR_18M 0x00000080 ++#define RATR_24M 0x00000100 ++#define RATR_36M 0x00000200 ++#define RATR_48M 0x00000400 ++#define RATR_54M 0x00000800 ++//MCS 1 Spatial Stream ++#define RATR_MCS0 0x00001000 ++#define RATR_MCS1 0x00002000 ++#define RATR_MCS2 0x00004000 ++#define RATR_MCS3 0x00008000 ++#define RATR_MCS4 0x00010000 ++#define RATR_MCS5 0x00020000 ++#define RATR_MCS6 0x00040000 ++#define RATR_MCS7 0x00080000 ++//MCS 2 Spatial Stream ++#define RATR_MCS8 0x00100000 ++#define RATR_MCS9 0x00200000 ++#define RATR_MCS10 0x00400000 ++#define RATR_MCS11 0x00800000 ++#define RATR_MCS12 0x01000000 ++#define RATR_MCS13 0x02000000 ++#define RATR_MCS14 0x04000000 ++#define RATR_MCS15 0x08000000 ++// ALL CCK Rate ++#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M ++#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M\ ++ |RATR_36M|RATR_48M|RATR_54M ++#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11| \ ++ RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 ++#endif ++/*--------------------------Define Parameters-------------------------------*/ ++ ++ ++/*------------------------------Define structure----------------------------*/ ++/* 2007/10/04 MH Define upper and lower threshold of DIG enable or disable. */ ++typedef struct _dynamic_initial_gain_threshold_ ++{ ++ u8 dig_enable_flag; ++ u8 dig_algorithm; ++ u8 dbg_mode; ++ u8 dig_algorithm_switch; ++ ++ long rssi_low_thresh; ++ long rssi_high_thresh; ++ ++ long rssi_high_power_lowthresh; ++ long rssi_high_power_highthresh; ++ ++ u8 dig_state; ++ u8 dig_highpwr_state; ++ u8 cur_connect_state; ++ u8 pre_connect_state; ++ ++ u8 curpd_thstate; ++ u8 prepd_thstate; ++ u8 curcs_ratio_state; ++ u8 precs_ratio_state; ++ ++ u32 pre_ig_value; ++ u32 cur_ig_value; ++ ++ u8 backoff_val; ++ u8 rx_gain_range_max; ++ u8 rx_gain_range_min; ++ bool initialgain_lowerbound_state; ++ ++ long rssi_val; ++}dig_t; ++ ++typedef enum tag_dynamic_init_gain_state_definition ++{ ++ DM_STA_DIG_OFF = 0, ++ DM_STA_DIG_ON, ++ DM_STA_DIG_MAX ++}dm_dig_sta_e; ++ ++ ++/* 2007/10/08 MH Define RATR state. */ ++typedef enum tag_dynamic_ratr_state_definition ++{ ++ DM_RATR_STA_HIGH = 0, ++ DM_RATR_STA_MIDDLE = 1, ++ DM_RATR_STA_LOW = 2, ++ DM_RATR_STA_MAX ++}dm_ratr_sta_e; ++ ++/* 2007/10/11 MH Define DIG operation type. */ ++typedef enum tag_dynamic_init_gain_operation_type_definition ++{ ++ DIG_TYPE_THRESH_HIGH = 0, ++ DIG_TYPE_THRESH_LOW = 1, ++ DIG_TYPE_THRESH_HIGHPWR_HIGH = 2, ++ DIG_TYPE_THRESH_HIGHPWR_LOW = 3, ++ DIG_TYPE_DBG_MODE = 4, ++ DIG_TYPE_RSSI = 5, ++ DIG_TYPE_ALGORITHM = 6, ++ DIG_TYPE_BACKOFF = 7, ++ DIG_TYPE_PWDB_FACTOR = 8, ++ DIG_TYPE_RX_GAIN_MIN = 9, ++ DIG_TYPE_RX_GAIN_MAX = 10, ++ DIG_TYPE_ENABLE = 20, ++ DIG_TYPE_DISABLE = 30, ++ DIG_OP_TYPE_MAX ++}dm_dig_op_e; ++ ++typedef enum tag_dig_algorithm_definition ++{ ++ DIG_ALGO_BY_FALSE_ALARM = 0, ++ DIG_ALGO_BY_RSSI = 1, ++ DIG_ALGO_MAX ++}dm_dig_alg_e; ++ ++typedef enum tag_dig_dbgmode_definition ++{ ++ DIG_DBG_OFF = 0, ++ DIG_DBG_ON = 1, ++ DIG_DBG_MAX ++}dm_dig_dbg_e; ++ ++typedef enum tag_dig_connect_definition ++{ ++ DIG_DISCONNECT = 0, ++ DIG_CONNECT = 1, ++ DIG_CONNECT_MAX ++}dm_dig_connect_e; ++ ++typedef enum tag_dig_packetdetection_threshold_definition ++{ ++ DIG_PD_AT_LOW_POWER = 0, ++ DIG_PD_AT_NORMAL_POWER = 1, ++ DIG_PD_AT_HIGH_POWER = 2, ++ DIG_PD_MAX ++}dm_dig_pd_th_e; ++ ++typedef enum tag_dig_cck_cs_ratio_state_definition ++{ ++ DIG_CS_RATIO_LOWER = 0, ++ DIG_CS_RATIO_HIGHER = 1, ++ DIG_CS_MAX ++}dm_dig_cs_ratio_e; ++typedef struct _Dynamic_Rx_Path_Selection_ ++{ ++ u8 Enable; ++ u8 DbgMode; ++ u8 cck_method; ++ u8 cck_Rx_path; ++ ++ u8 SS_TH_low; ++ u8 diff_TH; ++ u8 disabledRF; ++ u8 reserved; ++ ++ u8 rf_rssi[4]; ++ u8 rf_enable_rssi_th[4]; ++ long cck_pwdb_sta[4]; ++}DRxPathSel; ++ ++typedef enum tag_CCK_Rx_Path_Method_Definition ++{ ++ CCK_Rx_Version_1 = 0, ++ CCK_Rx_Version_2= 1, ++ CCK_Rx_Version_MAX ++}DM_CCK_Rx_Path_Method; ++ ++typedef enum tag_DM_DbgMode_Definition ++{ ++ DM_DBG_OFF = 0, ++ DM_DBG_ON = 1, ++ DM_DBG_MAX ++}DM_DBG_E; ++ ++typedef struct tag_Tx_Config_Cmd_Format ++{ ++ u32 Op; /* Command packet type. */ ++ u32 Length; /* Command packet length. */ ++ u32 Value; ++}DCMD_TXCMD_T, *PDCMD_TXCMD_T; ++/*------------------------------Define structure----------------------------*/ ++ ++ ++/*------------------------Export global variable----------------------------*/ ++extern dig_t dm_digtable; ++extern u8 dm_shadow[16][256]; ++extern DRxPathSel DM_RxPathSelTable; ++/*------------------------Export global variable----------------------------*/ ++ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++/*--------------------------Exported Function prototype---------------------*/ ++extern void init_hal_dm(struct net_device *dev); ++extern void deinit_hal_dm(struct net_device *dev); ++ ++extern void hal_dm_watchdog(struct net_device *dev); ++ ++ ++extern void init_rate_adaptive(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void dm_txpower_trackingcallback(struct work_struct *work); ++#else ++extern void dm_txpower_trackingcallback(struct net_device *dev); ++#endif ++ ++extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14); ++extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); ++extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); ++extern void dm_change_dynamic_initgain_thresh(struct net_device *dev, ++ u32 dm_type, ++ u32 dm_value); ++extern void DM_ChangeFsyncSetting(struct net_device *dev, ++ s32 DM_Type, ++ s32 DM_Value); ++extern void dm_force_tx_fw_info(struct net_device *dev, ++ u32 force_type, ++ u32 force_value); ++extern void dm_init_edca_turbo(struct net_device *dev); ++extern void dm_rf_operation_test_callback(unsigned long data); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work); ++#else ++extern void dm_rf_pathcheck_workitemcallback(struct net_device *dev); ++#endif ++extern void dm_fsync_timer_callback(unsigned long data); ++#if 0 ++extern bool dm_check_lbus_status(struct net_device *dev); ++#endif ++extern void dm_check_fsync(struct net_device *dev); ++extern void dm_shadow_init(struct net_device *dev); ++extern void dm_initialize_txpower_tracking(struct net_device *dev); ++ ++ ++#endif /*__R8192UDM_H__ */ ++ ++ ++/* End of r8192U_dm.h */ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E_hw.h +@@ -0,0 +1,811 @@ ++/* ++ This is part of rtl8187 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official Realtek driver. ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ Parts of this driver are based on the Intel Pro Wireless ++ 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects ++ and the Ndiswrapper project Authors. ++*/ ++ ++/* Mariusz Matuszek added full registers definition with Realtek's name */ ++ ++/* this file contains register definitions for the rtl8187 MAC controller */ ++#ifndef R8180_HW ++#define R8180_HW ++ ++typedef enum _VERSION_8190{ ++ // RTL8190 ++ VERSION_8190_BD=0x3, ++ VERSION_8190_BE ++}VERSION_8190,*PVERSION_8190; ++//added for different RF type ++typedef enum _RT_RF_TYPE_DEF ++{ ++ RF_1T2R = 0, ++ RF_2T4R, ++ ++ RF_819X_MAX_TYPE ++}RT_RF_TYPE_DEF; ++ ++typedef enum _BaseBand_Config_Type{ ++ BaseBand_Config_PHY_REG = 0, //Radio Path A ++ BaseBand_Config_AGC_TAB = 1, //Radio Path B ++}BaseBand_Config_Type, *PBaseBand_Config_Type; ++#if 0 ++typedef enum _RT_RF_TYPE_819xU{ ++ RF_TYPE_MIN = 0, ++ RF_8225, ++ RF_8256, ++ RF_8258, ++ RF_PSEUDO_11N = 4, ++}RT_RF_TYPE_819xU, *PRT_RF_TYPE_819xU; ++#endif ++#define RTL8187_REQT_READ 0xc0 ++#define RTL8187_REQT_WRITE 0x40 ++#define RTL8187_REQ_GET_REGS 0x05 ++#define RTL8187_REQ_SET_REGS 0x05 ++ ++#define R8180_MAX_RETRY 255 ++#define MAX_TX_URB 5 ++#define MAX_RX_URB 16 ++//#define MAX_RX_NORMAL_URB 3 ++//#define MAX_RX_COMMAND_URB 2 ++#define RX_URB_SIZE 9100 ++ ++#define BB_ANTATTEN_CHAN14 0x0c ++#define BB_ANTENNA_B 0x40 ++ ++#define BB_HOST_BANG (1<<30) ++#define BB_HOST_BANG_EN (1<<2) ++#define BB_HOST_BANG_CLK (1<<1) ++#define BB_HOST_BANG_RW (1<<3) ++#define BB_HOST_BANG_DATA 1 ++ ++//#if (RTL819X_FPGA_VER & RTL819X_FPGA_VIVI_070920) ++#define RTL8190_EEPROM_ID 0x8129 ++#define EEPROM_VID 0x02 ++#define EEPROM_DID 0x04 ++#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C ++ ++#define EEPROM_TxPowerDiff 0x1F ++ ++ ++#define EEPROM_PwDiff 0x21 //0x21 ++#define EEPROM_CrystalCap 0x22 //0x22 ++ ++ ++ ++#define EEPROM_TxPwIndex_CCK_V1 0x29 //0x29~0x2B ++#define EEPROM_TxPwIndex_OFDM_24G_V1 0x2C //0x2C~0x2E ++#define EEPROM_TxPwIndex_Ver 0x27 //0x27 ++ ++#define EEPROM_Default_TxPowerDiff 0x0 ++#define EEPROM_Default_ThermalMeter 0x77 ++#define EEPROM_Default_AntTxPowerDiff 0x0 ++#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 ++#define EEPROM_Default_PwDiff 0x4 ++#define EEPROM_Default_CrystalCap 0x5 ++#define EEPROM_Default_TxPower 0x1010 ++#define EEPROM_ICVersion_ChannelPlan 0x7C //0x7C:ChannelPlan, 0x7D:IC_Version ++#define EEPROM_Customer_ID 0x7B //0x7B:CustomerID ++#ifdef RTL8190P ++#define EEPROM_RFInd_PowerDiff 0x14 ++#define EEPROM_ThermalMeter 0x15 ++#define EEPROM_TxPwDiff_CrystalCap 0x16 ++#define EEPROM_TxPwIndex_CCK 0x18 //0x18~0x25 ++#define EEPROM_TxPwIndex_OFDM_24G 0x26 //0x26~0x33 ++#define EEPROM_TxPwIndex_OFDM_5G 0x34 //0x34~0x7B ++#define EEPROM_C56_CrystalCap 0x17 //0x17 ++#define EEPROM_C56_RfA_CCK_Chnl1_TxPwIndex 0x80 //0x80 ++#define EEPROM_C56_RfA_HT_OFDM_TxPwIndex 0x81 //0x81~0x83 ++#define EEPROM_C56_RfC_CCK_Chnl1_TxPwIndex 0xbc //0xb8 ++#define EEPROM_C56_RfC_HT_OFDM_TxPwIndex 0xb9 //0xb9~0xbb ++#else ++#ifdef RTL8192E ++#define EEPROM_RFInd_PowerDiff 0x28 ++#define EEPROM_ThermalMeter 0x29 ++#define EEPROM_TxPwDiff_CrystalCap 0x2A //0x2A~0x2B ++#define EEPROM_TxPwIndex_CCK 0x2C //0x23 ++#define EEPROM_TxPwIndex_OFDM_24G 0x3A //0x24~0x26 ++#endif ++#endif ++#define EEPROM_Default_TxPowerLevel 0x10 ++//#define EEPROM_ChannelPlan 0x7c //0x7C ++#define EEPROM_IC_VER 0x7d //0x7D ++#define EEPROM_CRC 0x7e //0x7E~0x7F ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_CAMEO 0x1 ++#define EEPROM_CID_RUNTOP 0x2 ++#define EEPROM_CID_Senao 0x3 ++#define EEPROM_CID_TOSHIBA 0x4 // Toshiba setting, Merge by Jacken, 2008/01/31 ++#define EEPROM_CID_NetCore 0x5 ++#define EEPROM_CID_Nettronix 0x6 ++#define EEPROM_CID_Pronet 0x7 ++#define EEPROM_CID_DLINK 0x8 ++#define EEPROM_CID_WHQL 0xFE //added by sherry for dtm, 20080728 ++//#endif ++enum _RTL8192Pci_HW { ++ MAC0 = 0x000, ++ MAC1 = 0x001, ++ MAC2 = 0x002, ++ MAC3 = 0x003, ++ MAC4 = 0x004, ++ MAC5 = 0x005, ++ PCIF = 0x009, // PCI Function Register 0x0009h~0x000bh ++//---------------------------------------------------------------------------- ++// 8190 PCIF bits (Offset 0x009-000b, 24bit) ++//---------------------------------------------------------------------------- ++#define MXDMA2_16bytes 0x000 ++#define MXDMA2_32bytes 0x001 ++#define MXDMA2_64bytes 0x010 ++#define MXDMA2_128bytes 0x011 ++#define MXDMA2_256bytes 0x100 ++#define MXDMA2_512bytes 0x101 ++#define MXDMA2_1024bytes 0x110 ++#define MXDMA2_NoLimit 0x7 ++ ++#define MULRW_SHIFT 3 ++#define MXDMA2_RX_SHIFT 4 ++#define MXDMA2_TX_SHIFT 0 ++ PMR = 0x00c, // Power management register ++ EPROM_CMD = 0x00e, ++#define EPROM_CMD_RESERVED_MASK BIT5 ++#define EPROM_CMD_9356SEL BIT4 ++#define EPROM_CMD_OPERATING_MODE_SHIFT 6 ++#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) ++#define EPROM_CMD_CONFIG 0x3 ++#define EPROM_CMD_NORMAL 0 ++#define EPROM_CMD_LOAD 1 ++#define EPROM_CMD_PROGRAM 2 ++#define EPROM_CS_SHIFT 3 ++#define EPROM_CK_SHIFT 2 ++#define EPROM_W_SHIFT 1 ++#define EPROM_R_SHIFT 0 ++ ++ AFR = 0x010, ++#define AFR_CardBEn (1<<0) ++#define AFR_CLKRUN_SEL (1<<1) ++#define AFR_FuncRegEn (1<<2) ++ ++ ANAPAR = 0x17, ++#define BB_GLOBAL_RESET_BIT 0x1 ++ BB_GLOBAL_RESET = 0x020, // BasebandGlobal Reset Register ++ BSSIDR = 0x02E, // BSSID Register ++ CMDR = 0x037, // Command register ++#define CR_RST 0x10 ++#define CR_RE 0x08 ++#define CR_TE 0x04 ++#define CR_MulRW 0x01 ++ SIFS = 0x03E, // SIFS register ++ TCR = 0x040, // Transmit Configuration Register ++ RCR = 0x044, // Receive Configuration Register ++//---------------------------------------------------------------------------- ++//// 8190 (RCR) Receive Configuration Register (Offset 0x44~47, 32 bit) ++////---------------------------------------------------------------------------- ++#define RCR_FILTER_MASK (BIT0|BIT1|BIT2|BIT3|BIT5|BIT12|BIT18|BIT19|BIT20|BIT21|BIT22|BIT23) ++#define RCR_ONLYERLPKT BIT31 // Early Receiving based on Packet Size. ++#define RCR_ENCS2 BIT30 // Enable Carrier Sense Detection Method 2 ++#define RCR_ENCS1 BIT29 // Enable Carrier Sense Detection Method 1 ++#define RCR_ENMBID BIT27 // Enable Multiple BssId. ++#define RCR_ACKTXBW (BIT24|BIT25) // TXBW Setting of ACK frames ++#define RCR_CBSSID BIT23 // Accept BSSID match packet ++#define RCR_APWRMGT BIT22 // Accept power management packet ++#define RCR_ADD3 BIT21 // Accept address 3 match packet ++#define RCR_AMF BIT20 // Accept management type frame ++#define RCR_ACF BIT19 // Accept control type frame ++#define RCR_ADF BIT18 // Accept data type frame ++#define RCR_RXFTH BIT13 // Rx FIFO Threshold ++#define RCR_AICV BIT12 // Accept ICV error packet ++#define RCR_ACRC32 BIT5 // Accept CRC32 error packet ++#define RCR_AB BIT3 // Accept broadcast packet ++#define RCR_AM BIT2 // Accept multicast packet ++#define RCR_APM BIT1 // Accept physical match packet ++#define RCR_AAP BIT0 // Accept all unicast packet ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ SLOT_TIME = 0x049, // Slot Time Register ++ ACK_TIMEOUT = 0x04c, // Ack Timeout Register ++ PIFS_TIME = 0x04d, // PIFS time ++ USTIME = 0x04e, // Microsecond Tuning Register, Sets the microsecond time unit used by MAC clock. ++ EDCAPARA_BE = 0x050, // EDCA Parameter of AC BE ++ EDCAPARA_BK = 0x054, // EDCA Parameter of AC BK ++ EDCAPARA_VO = 0x058, // EDCA Parameter of AC VO ++ EDCAPARA_VI = 0x05C, // EDCA Parameter of AC VI ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ RFPC = 0x05F, // Rx FIFO Packet Count ++ CWRR = 0x060, // Contention Window Report Register ++ BCN_TCFG = 0x062, // Beacon Time Configuration ++#define BCN_TCFG_CW_SHIFT 8 ++#define BCN_TCFG_IFS 0 ++ BCN_INTERVAL = 0x070, // Beacon Interval (TU) ++ ATIMWND = 0x072, // ATIM Window Size (TU) ++ BCN_DRV_EARLY_INT = 0x074, // Driver Early Interrupt Time (TU). Time to send interrupt to notify to change beacon content before TBTT ++#define BCN_DRV_EARLY_INT_SWBCN_SHIFT 8 ++#define BCN_DRV_EARLY_INT_TIME_SHIFT 0 ++ BCN_DMATIME = 0x076, // Beacon DMA and ATIM interrupt time (US). Indicates the time before TBTT to perform beacon queue DMA ++ BCN_ERR_THRESH = 0x078, // Beacon Error Threshold ++ RWCAM = 0x0A0, //IN 8190 Data Sheet is called CAMcmd ++ //---------------------------------------------------------------------------- ++ //// 8190 CAM Command Register (offset 0xA0, 4 byte) ++ ////---------------------------------------------------------------------------- ++#define CAM_CM_SecCAMPolling BIT31 //Security CAM Polling ++#define CAM_CM_SecCAMClr BIT30 //Clear all bits in CAM ++#define CAM_CM_SecCAMWE BIT16 //Security CAM enable ++#define CAM_VALID BIT15 ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT5 ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++ ++#define TOTAL_CAM_ENTRY 32 ++ ++#define CAM_CONFIG_USEDK true ++#define CAM_CONFIG_NO_USEDK false ++#define CAM_WRITE BIT16 ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT31 ++#define SCR_UseDK 0x01 ++ WCAMI = 0x0A4, // Software write CAM input content ++ RCAMO = 0x0A8, // Software read/write CAM config ++ SECR = 0x0B0, //Security Configuration Register ++#define SCR_TxUseDK BIT0 //Force Tx Use Default Key ++#define SCR_RxUseDK BIT1 //Force Rx Use Default Key ++#define SCR_TxEncEnable BIT2 //Enable Tx Encryption ++#define SCR_RxDecEnable BIT3 //Enable Rx Decryption ++#define SCR_SKByA2 BIT4 //Search kEY BY A2 ++#define SCR_NoSKMC BIT5 //No Key Search for Multicast ++ SWREGULATOR = 0x0BD, // Switching Regulator ++ INTA_MASK = 0x0f4, ++//---------------------------------------------------------------------------- ++// 8190 IMR/ISR bits (offset 0xfd, 8bits) ++//---------------------------------------------------------------------------- ++#define IMR8190_DISABLED 0x0 ++#define IMR_ATIMEND BIT28 // ATIM Window End Interrupt ++#define IMR_TBDOK BIT27 // Transmit Beacon OK Interrupt ++#define IMR_TBDER BIT26 // Transmit Beacon Error Interrupt ++#define IMR_TXFOVW BIT15 // Transmit FIFO Overflow ++#define IMR_TIMEOUT0 BIT14 // TimeOut0 ++#define IMR_BcnInt BIT13 // Beacon DMA Interrupt 0 ++#define IMR_RXFOVW BIT12 // Receive FIFO Overflow ++#define IMR_RDU BIT11 // Receive Descriptor Unavailable ++#define IMR_RXCMDOK BIT10 // Receive Command Packet OK ++#define IMR_BDOK BIT9 // Beacon Queue DMA OK Interrup ++#define IMR_HIGHDOK BIT8 // High Queue DMA OK Interrupt ++#define IMR_COMDOK BIT7 // Command Queue DMA OK Interrupt ++#define IMR_MGNTDOK BIT6 // Management Queue DMA OK Interrupt ++#define IMR_HCCADOK BIT5 // HCCA Queue DMA OK Interrupt ++#define IMR_BKDOK BIT4 // AC_BK DMA OK Interrupt ++#define IMR_BEDOK BIT3 // AC_BE DMA OK Interrupt ++#define IMR_VIDOK BIT2 // AC_VI DMA OK Interrupt ++#define IMR_VODOK BIT1 // AC_VO DMA Interrupt ++#define IMR_ROK BIT0 // Receive DMA OK Interrupt ++ ISR = 0x0f8, // Interrupt Status Register ++ TPPoll = 0x0fd, // Transmit priority polling register ++#define TPPoll_BKQ BIT0 // BK queue polling ++#define TPPoll_BEQ BIT1 // BE queue polling ++#define TPPoll_VIQ BIT2 // VI queue polling ++#define TPPoll_VOQ BIT3 // VO queue polling ++#define TPPoll_BQ BIT4 // Beacon queue polling ++#define TPPoll_CQ BIT5 // Command queue polling ++#define TPPoll_MQ BIT6 // Management queue polling ++#define TPPoll_HQ BIT7 // High queue polling ++#define TPPoll_HCCAQ BIT8 // HCCA queue polling ++#define TPPoll_StopBK BIT9 // Stop BK queue ++#define TPPoll_StopBE BIT10 // Stop BE queue ++#define TPPoll_StopVI BIT11 // Stop VI queue ++#define TPPoll_StopVO BIT12 // Stop VO queue ++#define TPPoll_StopMgt BIT13 // Stop Mgnt queue ++#define TPPoll_StopHigh BIT14 // Stop High queue ++#define TPPoll_StopHCCA BIT15 // Stop HCCA queue ++#define TPPoll_SHIFT 8 // Queue ID mapping ++ ++ PSR = 0x0ff, // Page Select Register ++#define PSR_GEN 0x0 // Page 0 register general MAC Control ++#define PSR_CPU 0x1 // Page 1 register for CPU ++ CPU_GEN = 0x100, // CPU Reset Register ++ BB_RESET = 0x101, // Baseband Reset ++//---------------------------------------------------------------------------- ++// 8190 CPU General Register (offset 0x100, 4 byte) ++//---------------------------------------------------------------------------- ++#define CPU_CCK_LOOPBACK 0x00030000 ++#define CPU_GEN_SYSTEM_RESET 0x00000001 ++#define CPU_GEN_FIRMWARE_RESET 0x00000008 ++#define CPU_GEN_BOOT_RDY 0x00000010 ++#define CPU_GEN_FIRM_RDY 0x00000020 ++#define CPU_GEN_PUT_CODE_OK 0x00000080 ++#define CPU_GEN_BB_RST 0x00000100 ++#define CPU_GEN_PWR_STB_CPU 0x00000004 ++#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF // Set bit18,17,16 to 0. Set bit19 ++#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 // Set BIT19 to 1 ++#define CPU_GEN_GPIO_UART 0x00007000 ++ ++ LED1Cfg = 0x154,// LED1 Configuration Register ++ LED0Cfg = 0x155,// LED0 Configuration Register ++ ++ AcmAvg = 0x170, // ACM Average Period Register ++ AcmHwCtrl = 0x171, // ACM Hardware Control Register ++//---------------------------------------------------------------------------- ++// ++// 8190 AcmHwCtrl bits (offset 0x171, 1 byte) ++//---------------------------------------------------------------------------- ++#define AcmHw_HwEn BIT0 ++#define AcmHw_BeqEn BIT1 ++#define AcmHw_ViqEn BIT2 ++#define AcmHw_VoqEn BIT3 ++#define AcmHw_BeqStatus BIT4 ++#define AcmHw_ViqStatus BIT5 ++#define AcmHw_VoqStatus BIT6 ++ AcmFwCtrl = 0x172, // ACM Firmware Control Register ++#define AcmFw_BeqStatus BIT0 ++#define AcmFw_ViqStatus BIT1 ++#define AcmFw_VoqStatus BIT2 ++ VOAdmTime = 0x174, // VO Queue Admitted Time Register ++ VIAdmTime = 0x178, // VI Queue Admitted Time Register ++ BEAdmTime = 0x17C, // BE Queue Admitted Time Register ++ RQPN1 = 0x180, // Reserved Queue Page Number , Vo Vi, Be, Bk ++ RQPN2 = 0x184, // Reserved Queue Page Number, HCCA, Cmd, Mgnt, High ++ RQPN3 = 0x188, // Reserved Queue Page Number, Bcn, Public, ++ QPRR = 0x1E0, // Queue Page Report per TID ++ QPNR = 0x1F0, // Queue Packet Number report per TID ++/* there's 9 tx descriptor base address available */ ++ BQDA = 0x200, // Beacon Queue Descriptor Address ++ HQDA = 0x204, // High Priority Queue Descriptor Address ++ CQDA = 0x208, // Command Queue Descriptor Address ++ MQDA = 0x20C, // Management Queue Descriptor Address ++ HCCAQDA = 0x210, // HCCA Queue Descriptor Address ++ VOQDA = 0x214, // VO Queue Descriptor Address ++ VIQDA = 0x218, // VI Queue Descriptor Address ++ BEQDA = 0x21C, // BE Queue Descriptor Address ++ BKQDA = 0x220, // BK Queue Descriptor Address ++/* there's 2 rx descriptor base address availalbe */ ++ RCQDA = 0x224, // Receive command Queue Descriptor Address ++ RDQDA = 0x228, // Receive Queue Descriptor Start Address ++ ++ MAR0 = 0x240, // Multicast filter. ++ MAR4 = 0x244, ++ ++ CCX_PERIOD = 0x250, // CCX Measurement Period Register, in unit of TU. ++ CLM_RESULT = 0x251, // CCA Busy fraction register. ++ NHM_PERIOD = 0x252, // NHM Measurement Period register, in unit of TU. ++ ++ NHM_THRESHOLD0 = 0x253, // Noise Histogram Meashorement0. ++ NHM_THRESHOLD1 = 0x254, // Noise Histogram Meashorement1. ++ NHM_THRESHOLD2 = 0x255, // Noise Histogram Meashorement2. ++ NHM_THRESHOLD3 = 0x256, // Noise Histogram Meashorement3. ++ NHM_THRESHOLD4 = 0x257, // Noise Histogram Meashorement4. ++ NHM_THRESHOLD5 = 0x258, // Noise Histogram Meashorement5. ++ NHM_THRESHOLD6 = 0x259, // Noise Histogram Meashorement6 ++ ++ MCTRL = 0x25A, // Measurement Control ++ ++ NHM_RPI_COUNTER0 = 0x264, // Noise Histogram RPI counter0, the fraction of signal strength < NHM_THRESHOLD0. ++ NHM_RPI_COUNTER1 = 0x265, // Noise Histogram RPI counter1, the fraction of signal strength in (NHM_THRESHOLD0, NHM_THRESHOLD1]. ++ NHM_RPI_COUNTER2 = 0x266, // Noise Histogram RPI counter2, the fraction of signal strength in (NHM_THRESHOLD1, NHM_THRESHOLD2]. ++ NHM_RPI_COUNTER3 = 0x267, // Noise Histogram RPI counter3, the fraction of signal strength in (NHM_THRESHOLD2, NHM_THRESHOLD3]. ++ NHM_RPI_COUNTER4 = 0x268, // Noise Histogram RPI counter4, the fraction of signal strength in (NHM_THRESHOLD3, NHM_THRESHOLD4]. ++ NHM_RPI_COUNTER5 = 0x269, // Noise Histogram RPI counter5, the fraction of signal strength in (NHM_THRESHOLD4, NHM_THRESHOLD5]. ++ NHM_RPI_COUNTER6 = 0x26A, // Noise Histogram RPI counter6, the fraction of signal strength in (NHM_THRESHOLD5, NHM_THRESHOLD6]. ++ NHM_RPI_COUNTER7 = 0x26B, // Noise Histogram RPI counter7, the fraction of signal strength in (NHM_THRESHOLD6, NHM_THRESHOLD7]. ++ WFCRC0 = 0x2f0, ++ WFCRC1 = 0x2f4, ++ WFCRC2 = 0x2f8, ++ ++ BW_OPMODE = 0x300, // Bandwidth operation mode ++#define BW_OPMODE_11J BIT0 ++#define BW_OPMODE_5G BIT1 ++#define BW_OPMODE_20MHZ BIT2 ++ IC_VERRSION = 0x301, //IC_VERSION ++ MSR = 0x303, // Media Status register ++#define MSR_LINK_MASK ((1<<0)|(1<<1)) ++#define MSR_LINK_MANAGED 2 ++#define MSR_LINK_NONE 0 ++#define MSR_LINK_SHIFT 0 ++#define MSR_LINK_ADHOC 1 ++#define MSR_LINK_MASTER 3 ++#define MSR_LINK_ENEDCA (1<<4) ++ RETRY_LIMIT = 0x304, // Retry Limit [15:8]-short, [7:0]-long ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ TSFR = 0x308, ++ RRSR = 0x310, // Response Rate Set ++#define RRSR_RSC_OFFSET 21 ++#define RRSR_SHORT_OFFSET 23 ++#define RRSR_RSC_DUPLICATE 0x600000 ++#define RRSR_RSC_UPSUBCHNL 0x400000 ++#define RRSR_RSC_LOWSUBCHNL 0x200000 ++#define RRSR_SHORT 0x800000 ++#define RRSR_1M BIT0 ++#define RRSR_2M BIT1 ++#define RRSR_5_5M BIT2 ++#define RRSR_11M BIT3 ++#define RRSR_6M BIT4 ++#define RRSR_9M BIT5 ++#define RRSR_12M BIT6 ++#define RRSR_18M BIT7 ++#define RRSR_24M BIT8 ++#define RRSR_36M BIT9 ++#define RRSR_48M BIT10 ++#define RRSR_54M BIT11 ++#define RRSR_MCS0 BIT12 ++#define RRSR_MCS1 BIT13 ++#define RRSR_MCS2 BIT14 ++#define RRSR_MCS3 BIT15 ++#define RRSR_MCS4 BIT16 ++#define RRSR_MCS5 BIT17 ++#define RRSR_MCS6 BIT18 ++#define RRSR_MCS7 BIT19 ++#define BRSR_AckShortPmb BIT23 // CCK ACK: use Short Preamble or not ++ UFWP = 0x318, ++ RATR0 = 0x320, // Rate Adaptive Table register1 ++//---------------------------------------------------------------------------- ++// 8190 Rate Adaptive Table Register (offset 0x320, 4 byte) ++//---------------------------------------------------------------------------- ++//CCK ++#define RATR_1M 0x00000001 ++#define RATR_2M 0x00000002 ++#define RATR_55M 0x00000004 ++#define RATR_11M 0x00000008 ++//OFDM ++#define RATR_6M 0x00000010 ++#define RATR_9M 0x00000020 ++#define RATR_12M 0x00000040 ++#define RATR_18M 0x00000080 ++#define RATR_24M 0x00000100 ++#define RATR_36M 0x00000200 ++#define RATR_48M 0x00000400 ++#define RATR_54M 0x00000800 ++//MCS 1 Spatial Stream ++#define RATR_MCS0 0x00001000 ++#define RATR_MCS1 0x00002000 ++#define RATR_MCS2 0x00004000 ++#define RATR_MCS3 0x00008000 ++#define RATR_MCS4 0x00010000 ++#define RATR_MCS5 0x00020000 ++#define RATR_MCS6 0x00040000 ++#define RATR_MCS7 0x00080000 ++//MCS 2 Spatial Stream ++#define RATR_MCS8 0x00100000 ++#define RATR_MCS9 0x00200000 ++#define RATR_MCS10 0x00400000 ++#define RATR_MCS11 0x00800000 ++#define RATR_MCS12 0x01000000 ++#define RATR_MCS13 0x02000000 ++#define RATR_MCS14 0x04000000 ++#define RATR_MCS15 0x08000000 ++// ALL CCK Rate ++#define RATE_ALL_CCK RATR_1M|RATR_2M|RATR_55M|RATR_11M ++#define RATE_ALL_OFDM_AG RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M|RATR_36M|RATR_48M|RATR_54M ++#define RATE_ALL_OFDM_1SS RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 | \ ++ RATR_MCS4|RATR_MCS5|RATR_MCS6 |RATR_MCS7 ++#define RATE_ALL_OFDM_2SS RATR_MCS8|RATR_MCS9 |RATR_MCS10|RATR_MCS11| \ ++ RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15 ++ ++ ++ DRIVER_RSSI = 0x32c, // Driver tell Firmware current RSSI ++ MCS_TXAGC = 0x340, // MCS AGC ++ CCK_TXAGC = 0x348, // CCK AGC ++// IMR = 0x354, // Interrupt Mask Register ++// IMR_POLL = 0x360, ++ MacBlkCtrl = 0x403, // Mac block on/off control register ++ ++ //Cmd9346CR = 0x00e, ++//#define Cmd9346CR_9356SEL (1<<4) ++#if 0 ++/* 0x0006 - 0x0007 - reserved */ ++ RXFIFOCOUNT = 0x010, ++ TXFIFOCOUNT = 0x012, ++ BQREQ = 0x013, ++/* 0x0010 - 0x0017 - reserved */ ++ TSFTR = 0x018, ++ TLPDA = 0x020, ++ TNPDA = 0x024, ++ THPDA = 0x028, ++ BSSID = 0x02E, ++ RESP_RATE = 0x034, ++ CMD = 0x037, ++#define CMD_RST_SHIFT 4 ++#define CMD_RESERVED_MASK ((1<<1) | (1<<5) | (1<<6) | (1<<7)) ++#define CMD_RX_ENABLE_SHIFT 3 ++#define CMD_TX_ENABLE_SHIFT 2 ++#define CR_RST ((1<< 4)) ++#define CR_RE ((1<< 3)) ++#define CR_TE ((1<< 2)) ++#define CR_MulRW ((1<< 0)) ++ ++ INTA = 0x03e, ++#endif ++ ++/////////////////// ++////////////////// ++#if 0 ++ TX_CONF = 0x040, ++#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30 ++#define TX_LOOPBACK_SHIFT 17 ++#define TX_LOOPBACK_MAC 1 ++#define TX_LOOPBACK_BASEBAND 2 ++#define TX_LOOPBACK_NONE 0 ++#define TX_LOOPBACK_CONTINUE 3 ++#define TX_LOOPBACK_MASK ((1<<17)|(1<<18)) ++#define TX_LRLRETRY_SHIFT 0 ++#define TX_SRLRETRY_SHIFT 8 ++#define TX_NOICV_SHIFT 19 ++#define TX_NOCRC_SHIFT 16 ++#define TCR_DurProcMode ((1<<30)) ++#define TCR_DISReqQsize ((1<<28)) ++#define TCR_HWVERID_MASK ((1<<27)|(1<<26)|(1<<25)) ++#define TCR_HWVERID_SHIFT 25 ++#define TCR_SWPLCPLEN ((1<<24)) ++#define TCR_PLCP_LEN TCR_SAT // rtl8180 ++#define TCR_MXDMA_MASK ((1<<23)|(1<<22)|(1<<21)) ++#define TCR_MXDMA_1024 6 ++#define TCR_MXDMA_2048 7 ++#define TCR_MXDMA_SHIFT 21 ++#define TCR_DISCW ((1<<20)) ++#define TCR_ICV ((1<<19)) ++#define TCR_LBK ((1<<18)|(1<<17)) ++#define TCR_LBK1 ((1<<18)) ++#define TCR_LBK0 ((1<<17)) ++#define TCR_CRC ((1<<16)) ++#define TCR_SRL_MASK ((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) ++#define TCR_LRL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)) ++#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 //rtl8185 ++ ++ RX_CONF = 0x044, ++#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ ++(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) ++#define RX_CHECK_BSSID_SHIFT 23 ++#define ACCEPT_PWR_FRAME_SHIFT 22 ++#define ACCEPT_MNG_FRAME_SHIFT 20 ++#define ACCEPT_CTL_FRAME_SHIFT 19 ++#define ACCEPT_DATA_FRAME_SHIFT 18 ++#define ACCEPT_ICVERR_FRAME_SHIFT 12 ++#define ACCEPT_CRCERR_FRAME_SHIFT 5 ++#define ACCEPT_BCAST_FRAME_SHIFT 3 ++#define ACCEPT_MCAST_FRAME_SHIFT 2 ++#define ACCEPT_ALLMAC_FRAME_SHIFT 0 ++#define ACCEPT_NICMAC_FRAME_SHIFT 1 ++#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) ++#define RX_FIFO_THRESHOLD_SHIFT 13 ++#define RX_FIFO_THRESHOLD_128 3 ++#define RX_FIFO_THRESHOLD_256 4 ++#define RX_FIFO_THRESHOLD_512 5 ++#define RX_FIFO_THRESHOLD_1024 6 ++#define RX_FIFO_THRESHOLD_NONE 7 ++#define RX_AUTORESETPHY_SHIFT 28 ++#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) ++#define MAX_RX_DMA_2048 7 ++#define MAX_RX_DMA_1024 6 ++#define MAX_RX_DMA_SHIFT 10 ++#define RCR_ONLYERLPKT ((1<<31)) ++#define RCR_CS_SHIFT 29 ++#define RCR_CS_MASK ((1<<30) | (1<<29)) ++#define RCR_ENMARP ((1<<28)) ++#define RCR_CBSSID ((1<<23)) ++#define RCR_APWRMGT ((1<<22)) ++#define RCR_ADD3 ((1<<21)) ++#define RCR_AMF ((1<<20)) ++#define RCR_ACF ((1<<19)) ++#define RCR_ADF ((1<<18)) ++#define RCR_RXFTH ((1<<15)|(1<<14)|(1<<13)) ++#define RCR_RXFTH2 ((1<<15)) ++#define RCR_RXFTH1 ((1<<14)) ++#define RCR_RXFTH0 ((1<<13)) ++#define RCR_AICV ((1<<12)) ++#define RCR_MXDMA ((1<<10)|(1<< 9)|(1<< 8)) ++#define RCR_MXDMA2 ((1<<10)) ++#define RCR_MXDMA1 ((1<< 9)) ++#define RCR_MXDMA0 ((1<< 8)) ++#define RCR_9356SEL ((1<< 6)) ++#define RCR_ACRC32 ((1<< 5)) ++#define RCR_AB ((1<< 3)) ++#define RCR_AM ((1<< 2)) ++#define RCR_APM ((1<< 1)) ++#define RCR_AAP ((1<< 0)) ++ ++ INT_TIMEOUT = 0x048, ++ ++ TX_BEACON_RING_ADDR = 0x04c, ++ ++#endif ++#if 0 ++ CONFIG0 = 0x051, ++#define CONFIG0_WEP104 ((1<<6)) ++#define CONFIG0_LEDGPO_En ((1<<4)) ++#define CONFIG0_Aux_Status ((1<<3)) ++#define CONFIG0_GL ((1<<1)|(1<<0)) ++#define CONFIG0_GL1 ((1<<1)) ++#define CONFIG0_GL0 ((1<<0)) ++ CONFIG1 = 0x052, ++#define CONFIG1_LEDS ((1<<7)|(1<<6)) ++#define CONFIG1_LEDS1 ((1<<7)) ++#define CONFIG1_LEDS0 ((1<<6)) ++#define CONFIG1_LWACT ((1<<4)) ++#define CONFIG1_MEMMAP ((1<<3)) ++#define CONFIG1_IOMAP ((1<<2)) ++#define CONFIG1_VPD ((1<<1)) ++#define CONFIG1_PMEn ((1<<0)) ++ CONFIG2 = 0x053, ++#define CONFIG2_LCK ((1<<7)) ++#define CONFIG2_ANT ((1<<6)) ++#define CONFIG2_DPS ((1<<3)) ++#define CONFIG2_PAPE_sign ((1<<2)) ++#define CONFIG2_PAPE_time ((1<<1)|(1<<0)) ++#define CONFIG2_PAPE_time1 ((1<<1)) ++#define CONFIG2_PAPE_time0 ((1<<0)) ++ ANA_PARAM = 0x054, ++ CONFIG3 = 0x059, ++#define CONFIG3_GNTSel ((1<<7)) ++#define CONFIG3_PARM_En ((1<<6)) ++#define CONFIG3_Magic ((1<<5)) ++#define CONFIG3_CardB_En ((1<<3)) ++#define CONFIG3_CLKRUN_En ((1<<2)) ++#define CONFIG3_FuncRegEn ((1<<1)) ++#define CONFIG3_FBtbEn ((1<<0)) ++#define CONFIG3_CLKRUN_SHIFT 2 ++#define CONFIG3_ANAPARAM_W_SHIFT 6 ++ CONFIG4 = 0x05a, ++#define CONFIG4_VCOPDN ((1<<7)) ++#define CONFIG4_PWROFF ((1<<6)) ++#define CONFIG4_PWRMGT ((1<<5)) ++#define CONFIG4_LWPME ((1<<4)) ++#define CONFIG4_LWPTN ((1<<2)) ++#define CONFIG4_RFTYPE ((1<<1)|(1<<0)) ++#define CONFIG4_RFTYPE1 ((1<<1)) ++#define CONFIG4_RFTYPE0 ((1<<0)) ++ TESTR = 0x05b, ++#define TFPC_AC 0x05C ++ ++#define SCR 0x05F ++ PGSELECT = 0x05e, ++#define PGSELECT_PG_SHIFT 0 ++ SECURITY = 0x05f, ++#define SECURITY_WEP_TX_ENABLE_SHIFT 1 ++#define SECURITY_WEP_RX_ENABLE_SHIFT 0 ++#define SECURITY_ENCRYP_104 1 ++#define SECURITY_ENCRYP_SHIFT 4 ++#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5)) ++ ++ ANA_PARAM2 = 0x060, ++ BEACON_INTERVAL = 0x070, ++#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \ ++(1<<6)|(1<<7)|(1<<8)|(1<<9)) ++ ++ ATIM_WND = 0x072, ++#define ATIM_WND_MASK (0x01FF) ++ ++ BCN_INTR_ITV = 0x074, ++#define BCN_INTR_ITV_MASK (0x01FF) ++ ++ ATIM_INTR_ITV = 0x076, ++#define ATIM_INTR_ITV_MASK (0x01FF) ++ ++ AckTimeOutReg = 0x079, //ACK timeout register, in unit of 4 us. ++ PHY_ADR = 0x07c, ++ PHY_READ = 0x07e, ++ RFPinsOutput = 0x080, ++ RFPinsEnable = 0x082, ++//Page 0 ++ RFPinsSelect = 0x084, ++#define SW_CONTROL_GPIO 0x400 ++ RFPinsInput = 0x086, ++ RF_PARA = 0x088, ++ RF_TIMING = 0x08c, ++ GP_ENABLE = 0x090, ++ GPIO = 0x091, ++ TX_AGC_CTL = 0x09c, ++#define TX_AGC_CTL_PER_PACKET_TXAGC 0x01 ++#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0 ++#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1 ++#define TX_AGC_CTL_FEEDBACK_ANT 2 ++#define TXAGC_CTL_PER_PACKET_ANT_SEL 0x02 ++ OFDM_TXAGC = 0x09e, ++ ANTSEL = 0x09f, ++ ++ ++ ++ SIFS = 0x0b4, ++ DIFS = 0x0b5, ++ SLOT = 0x0b6, ++ CW_CONF = 0x0bc, ++#define CW_CONF_PERPACKET_RETRY_LIMIT 0x02 ++#define CW_CONF_PERPACKET_CW 0x01 ++#define CW_CONF_PERPACKET_RETRY_SHIFT 1 ++#define CW_CONF_PERPACKET_CW_SHIFT 0 ++ CW_VAL = 0x0bd, ++ RATE_FALLBACK = 0x0be, ++#define MAX_RESP_RATE_SHIFT 4 ++#define MIN_RESP_RATE_SHIFT 0 ++#define RATE_FALLBACK_CTL_ENABLE 0x80 ++#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00 ++ ACM_CONTROL = 0x0BF, // ACM Control Registe ++//---------------------------------------------------------------------------- ++// 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte) ++//---------------------------------------------------------------------------- ++#define VOQ_ACM_EN (0x01 << 7) //BIT7 ++#define VIQ_ACM_EN (0x01 << 6) //BIT6 ++#define BEQ_ACM_EN (0x01 << 5) //BIT5 ++#define ACM_HW_EN (0x01 << 4) //BIT4 ++#define TXOPSEL (0x01 << 3) //BIT3 ++#define VOQ_ACM_CTL (0x01 << 2) //BIT2 // Set to 1 when AC_VO used time reaches or exceeds the admitted time ++#define VIQ_ACM_CTL (0x01 << 1) //BIT1 // Set to 1 when AC_VI used time reaches or exceeds the admitted time ++#define BEQ_ACM_CTL (0x01 << 0) //BIT0 // Set to 1 when AC_BE used time reaches or exceeds the admitted time ++ CONFIG5 = 0x0D8, ++#define CONFIG5_TX_FIFO_OK ((1<<7)) ++#define CONFIG5_RX_FIFO_OK ((1<<6)) ++#define CONFIG5_CALON ((1<<5)) ++#define CONFIG5_EACPI ((1<<2)) ++#define CONFIG5_LANWake ((1<<1)) ++#define CONFIG5_PME_STS ((1<<0)) ++ TX_DMA_POLLING = 0x0fd, ++#define TX_DMA_POLLING_BEACON_SHIFT 7 ++#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6 ++#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5 ++#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4 ++#define TX_DMA_STOP_BEACON_SHIFT 3 ++#define TX_DMA_STOP_HIPRIORITY_SHIFT 2 ++#define TX_DMA_STOP_NORMPRIORITY_SHIFT 1 ++#define TX_DMA_STOP_LOWPRIORITY_SHIFT 0 ++ CWR = 0x0DC, ++ RetryCTR = 0x0DE, ++ INT_MIG = 0x0E2, // Interrupt Migration (0xE2 ~ 0xE3) ++ TID_AC_MAP = 0x0E8, // TID to AC Mapping Register ++ ANA_PARAM3 = 0x0EE, ++ ++ ++//page 1 ++ Wakeup0 = 0x084, ++ Wakeup1 = 0x08C, ++ Wakeup2LD = 0x094, ++ Wakeup2HD = 0x09C, ++ Wakeup3LD = 0x0A4, ++ Wakeup3HD = 0x0AC, ++ Wakeup4LD = 0x0B4, ++ Wakeup4HD = 0x0BC, ++ CRC0 = 0x0C4, ++ CRC1 = 0x0C6, ++ CRC2 = 0x0C8, ++ CRC3 = 0x0CA, ++ CRC4 = 0x0CC, ++/* 0x00CE - 0x00D3 - reserved */ ++ ++ RFSW_CTRL = 0x272, // 0x272-0x273. ++ ++/**************************************************************************/ ++ FER = 0x0F0, ++ FEMR = 0x0F4, ++ FPSR = 0x0F8, ++ FFER = 0x0FC, ++ ++ AC_VO_PARAM = 0x0F0, // AC_VO Parameters Record ++ AC_VI_PARAM = 0x0F4, // AC_VI Parameters Record ++ AC_BE_PARAM = 0x0F8, // AC_BE Parameters Record ++ AC_BK_PARAM = 0x0FC, // AC_BK Parameters Record ++ TALLY_SEL = 0x0fc, ++#endif ++} ++; ++//---------------------------------------------------------------------------- ++// 818xB AnaParm & AnaParm2 Register ++//---------------------------------------------------------------------------- ++//#define ANAPARM_ASIC_ON 0x45090658 ++//#define ANAPARM2_ASIC_ON 0x727f3f52 ++ ++#define GPI 0x108 ++#define GPO 0x109 ++#define GPE 0x10a ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E_wx.c +@@ -0,0 +1,1409 @@ ++/* ++ This file contains wireless extension handlers. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part ++ of the official realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#include ++#include "r8192E.h" ++#include "r8192E_hw.h" ++#include "r8192E_wx.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++#define RATE_COUNT 12 ++static u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000, ++ 6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000}; ++ ++ ++#ifndef ENETDOWN ++#define ENETDOWN 1 ++#endif ++static int r8192_wx_get_freq(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_freq(priv->ieee80211,a,wrqu,b); ++} ++ ++ ++#if 0 ++ ++static int r8192_wx_set_beaconinterval(struct net_device *dev, struct iw_request_info *aa, ++ union iwreq_data *wrqu, char *b) ++{ ++ int *parms = (int *)b; ++ int bi = parms[0]; ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ DMESG("setting beacon interval to %x",bi); ++ ++ priv->ieee80211->beacon_interval=bi; ++ rtl8180_commit(dev); ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++ ++static int r8192_wx_set_forceassociate(struct net_device *dev, struct iw_request_info *aa, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv=ieee80211_priv(dev); ++ int *parms = (int *)extra; ++ ++ priv->ieee80211->force_associate = (parms[0] > 0); ++ ++ ++ return 0; ++} ++ ++#endif ++static int r8192_wx_get_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8192_priv *priv=ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_mode(priv->ieee80211,a,wrqu,b); ++} ++ ++ ++ ++static int r8192_wx_get_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_rate(priv->ieee80211,info,wrqu,extra); ++} ++ ++ ++ ++static int r8192_wx_set_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++static int r8192_wx_set_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rts(priv->ieee80211,info,wrqu,extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++static int r8192_wx_get_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_rts(priv->ieee80211,info,wrqu,extra); ++} ++ ++static int r8192_wx_set_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_power(priv->ieee80211,info,wrqu,extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++static int r8192_wx_get_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_power(priv->ieee80211,info,wrqu,extra); ++} ++ ++#ifdef JOHN_IOCTL ++u16 read_rtl8225(struct net_device *dev, u8 addr); ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data); ++u32 john_read_rtl8225(struct net_device *dev, u8 adr); ++void _write_rtl8225(struct net_device *dev, u8 adr, u16 data); ++ ++static int r8192_wx_read_regs(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 addr; ++ u16 data1; ++ ++ down(&priv->wx_sem); ++ ++ ++ get_user(addr,(u8*)wrqu->data.pointer); ++ data1 = read_rtl8225(dev, addr); ++ wrqu->data.length = data1; ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++static int r8192_wx_write_regs(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 addr; ++ ++ down(&priv->wx_sem); ++ ++ get_user(addr, (u8*)wrqu->data.pointer); ++ write_rtl8225(dev, addr, wrqu->data.length); ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); ++u8 rtl8187_read_phy(struct net_device *dev,u8 adr, u32 data); ++ ++static int r8192_wx_read_bb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 databb; ++#if 0 ++ int i; ++ for(i=0;i<12;i++) printk("%8x\n", read_cam(dev, i) ); ++#endif ++ ++ down(&priv->wx_sem); ++ ++ databb = rtl8187_read_phy(dev, (u8)wrqu->data.length, 0x00000000); ++ wrqu->data.length = databb; ++ ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++void rtl8187_write_phy(struct net_device *dev, u8 adr, u32 data); ++static int r8192_wx_write_bb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 databb; ++ ++ down(&priv->wx_sem); ++ ++ get_user(databb, (u8*)wrqu->data.pointer); ++ rtl8187_write_phy(dev, wrqu->data.length, databb); ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++ ++static int r8192_wx_write_nicb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 addr; ++ ++ down(&priv->wx_sem); ++ ++ get_user(addr, (u32*)wrqu->data.pointer); ++ write_nic_byte(dev, addr, wrqu->data.length); ++ ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++static int r8192_wx_read_nicb(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 addr; ++ u16 data1; ++ ++ down(&priv->wx_sem); ++ ++ get_user(addr,(u32*)wrqu->data.pointer); ++ data1 = read_nic_byte(dev, addr); ++ wrqu->data.length = data1; ++ ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++static int r8192_wx_get_ap_status(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ struct ieee80211_network *target; ++ int name_len; ++ ++ down(&priv->wx_sem); ++ ++ //count the length of input ssid ++ for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++); ++ ++ //search for the correspoding info which is received ++ list_for_each_entry(target, &ieee->network_list, list) { ++ if ( (target->ssid_len == name_len) && ++ (strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){ ++ if(target->wpa_ie_len>0 || target->rsn_ie_len>0 ) ++ //set flags=1 to indicate this ap is WPA ++ wrqu->data.flags = 1; ++ else wrqu->data.flags = 0; ++ ++ ++ break; ++ } ++ } ++ ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++ ++ ++#endif ++ ++static int r8192_wx_set_rawtx(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++static int r8192_wx_force_reset(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ printk("%s(): force reset ! extra is %d\n",__FUNCTION__, *extra); ++ priv->force_reset = *extra; ++ up(&priv->wx_sem); ++ return 0; ++ ++} ++ ++ ++static int r8192_wx_set_crcmon(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int *parms = (int *)extra; ++ int enable = (parms[0] > 0); ++ short prev = priv->crcmon; ++ ++ down(&priv->wx_sem); ++ ++ if(enable) ++ priv->crcmon=1; ++ else ++ priv->crcmon=0; ++ ++ DMESG("bad CRC in monitor mode are %s", ++ priv->crcmon ? "accepted" : "rejected"); ++ ++ if(prev != priv->crcmon && priv->up){ ++ //rtl8180_down(dev); ++ //rtl8180_up(dev); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ int ret; ++ ++ rtState = priv->ieee80211->eRFPowerState; ++ down(&priv->wx_sem); ++#ifdef ENABLE_IPS ++ if(wrqu->mode == IW_MODE_ADHOC){ ++ ++ if(priv->ieee80211->PowerSaveControl.bInactivePs){ ++ if(rtState == eRfOff){ ++ if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__); ++ up(&priv->wx_sem); ++ return -1; ++ } ++ else{ ++ printk("=========>%s(): IPSLeave\n",__FUNCTION__); ++ IPSLeave(dev); ++ } ++ } ++ } ++ } ++#endif ++ ret = ieee80211_wx_set_mode(priv->ieee80211,a,wrqu,b); ++ ++ //rtl8187_set_rxconf(dev); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++struct iw_range_with_scan_capa ++{ ++ /* Informative stuff (to choose between different interface) */ ++ __u32 throughput; /* To give an idea... */ ++ /* In theory this value should be the maximum benchmarked ++ * TCP/IP throughput, because with most of these devices the ++ * bit rate is meaningless (overhead an co) to estimate how ++ * fast the connection will go and pick the fastest one. ++ * I suggest people to play with Netperf or any benchmark... ++ */ ++ ++ /* NWID (or domain id) */ ++ __u32 min_nwid; /* Minimal NWID we are able to set */ ++ __u32 max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++ __u16 old_num_channels; ++ __u8 old_num_frequency; ++ ++ /* Scan capabilities */ ++ __u8 scan_capa; ++}; ++static int rtl8180_wx_get_range(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *)extra; ++ struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u16 val; ++ int i; ++ ++ wrqu->data.length = sizeof(*range); ++ memset(range, 0, sizeof(*range)); ++ ++ /* Let's try to keep this struct in the same order as in ++ * linux/include/wireless.h ++ */ ++ ++ /* TODO: See what values we can set, and remove the ones we can't ++ * set, or fill them with some default data. ++ */ ++ ++ /* ~5 Mb/s real (802.11b) */ ++ range->throughput = 5 * 1000 * 1000; ++ ++ // TODO: Not used in 802.11b? ++// range->min_nwid; /* Minimal NWID we are able to set */ ++ // TODO: Not used in 802.11b? ++// range->max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++// range->old_num_channels; ++// range->old_num_frequency; ++// range->old_freq[6]; /* Filler to keep "version" at the same offset */ ++ if(priv->rf_set_sens != NULL) ++ range->sensitivity = priv->max_sens; /* signal level threshold range */ ++ ++ range->max_qual.qual = 100; ++ /* TODO: Find real max RSSI and stick here */ ++ range->max_qual.level = 0; ++ range->max_qual.noise = -98; ++ range->max_qual.updated = 7; /* Updated all three */ ++ ++ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ ++ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ ++ range->avg_qual.level = 20 + -98; ++ range->avg_qual.noise = 0; ++ range->avg_qual.updated = 7; /* Updated all three */ ++ ++ range->num_bitrates = RATE_COUNT; ++ ++ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { ++ range->bitrate[i] = rtl8180_rates[i]; ++ } ++ ++ range->min_frag = MIN_FRAG_THRESHOLD; ++ range->max_frag = MAX_FRAG_THRESHOLD; ++ ++ range->min_pmp=0; ++ range->max_pmp = 5000000; ++ range->min_pmt = 0; ++ range->max_pmt = 65535*1000; ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_TIMEOUT; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 16; ++ ++// range->retry_capa; /* What retry options are supported */ ++// range->retry_flags; /* How to decode max/min retry limit */ ++// range->r_time_flags; /* How to decode max/min retry life */ ++// range->min_retry; /* Minimal number of retries */ ++// range->max_retry; /* Maximal number of retries */ ++// range->min_r_time; /* Minimal retry lifetime */ ++// range->max_r_time; /* Maximal retry lifetime */ ++ ++ ++ for (i = 0, val = 0; i < 14; i++) { ++ ++ // Include only legal frequencies for some countries ++#ifdef ENABLE_DOT11D ++ if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { ++#else ++ if ((priv->ieee80211->channel_map)[i+1]) { ++#endif ++ range->freq[val].i = i + 1; ++ range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } else { ++ // FIXME: do we need to set anything for channels ++ // we don't use ? ++ } ++ ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ range->num_frequency = val; ++ range->num_channels = val; ++#if WIRELESS_EXT > 17 ++ range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2| ++ IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ tmp->scan_capa = 0x01; ++ return 0; ++} ++ ++ ++static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ RT_RF_POWER_STATE rtState; ++ int ret; ++ rtState = priv->ieee80211->eRFPowerState; ++ if(!priv->up) return -ENETDOWN; ++ if (priv->ieee80211->LinkDetectInfo.bBusyTraffic == true) ++ return -EAGAIN; ++ ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) ++ { ++ struct iw_scan_req* req = (struct iw_scan_req*)b; ++ if (req->essid_len) ++ { ++ //printk("==**&*&*&**===>scan set ssid:%s\n", req->essid); ++ ieee->current_network.ssid_len = req->essid_len; ++ memcpy(ieee->current_network.ssid, req->essid, req->essid_len); ++ //printk("=====>network ssid:%s\n", ieee->current_network.ssid); ++ } ++ } ++ ++ down(&priv->wx_sem); ++#ifdef ENABLE_IPS ++ priv->ieee80211->actscanning = true; ++ if(priv->ieee80211->state != IEEE80211_LINKED){ ++ if(priv->ieee80211->PowerSaveControl.bInactivePs){ ++ if(rtState == eRfOff){ ++ if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__); ++ up(&priv->wx_sem); ++ return -1; ++ } ++ else{ ++ printk("=========>%s(): IPSLeave\n",__FUNCTION__); ++ IPSLeave(dev); ++ } ++ } ++ } ++ priv->ieee80211->scanning = 0; ++ ieee80211_softmac_scan_syncro(priv->ieee80211); ++ ret = 0; ++ } ++ else ++#else ++ ++ if(priv->ieee80211->state != IEEE80211_LINKED){ ++ priv->ieee80211->scanning = 0; ++ ieee80211_softmac_scan_syncro(priv->ieee80211); ++ ret = 0; ++ } ++ else ++#endif ++ ret = ieee80211_wx_set_scan(priv->ieee80211,a,wrqu,b); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ if(!priv->up) return -ENETDOWN; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_get_scan(priv->ieee80211,a,wrqu,b); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++static int r8192_wx_set_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ int ret; ++ ++ rtState = priv->ieee80211->eRFPowerState; ++ down(&priv->wx_sem); ++#ifdef ENABLE_IPS ++ if(priv->ieee80211->PowerSaveControl.bInactivePs){ ++ if(rtState == eRfOff){ ++ if(priv->ieee80211->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__); ++ up(&priv->wx_sem); ++ return -1; ++ } ++ else{ ++ printk("=========>%s(): IPSLeave\n",__FUNCTION__); ++ IPSLeave(dev); ++ } ++ } ++ } ++#endif ++ ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++ ++ ++static int r8192_wx_get_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++static int r8192_wx_get_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra); ++} ++ ++ ++static int r8192_wx_set_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ if (wrqu->frag.disabled) ++ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; ++ else { ++ if (wrqu->frag.value < MIN_FRAG_THRESHOLD || ++ wrqu->frag.value > MAX_FRAG_THRESHOLD) ++ return -EINVAL; ++ ++ priv->ieee80211->fts = wrqu->frag.value & ~0x1; ++ } ++ ++ return 0; ++} ++ ++ ++static int r8192_wx_get_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ wrqu->frag.value = priv->ieee80211->fts; ++ wrqu->frag.fixed = 0; /* no auto select */ ++ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); ++ ++ return 0; ++} ++ ++ ++static int r8192_wx_set_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ ++ int ret; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++// struct sockaddr *temp = (struct sockaddr *)awrq; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++ ++static int r8192_wx_get_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_wap(priv->ieee80211,info,wrqu,extra); ++} ++ ++ ++static int r8192_wx_get_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key); ++} ++ ++static int r8192_wx_set_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ struct ieee80211_device *ieee = priv->ieee80211; ++ //u32 TargetContent; ++ u32 hwkey[4]={0,0,0,0}; ++ u8 mask=0xff; ++ u32 key_idx=0; ++ u8 zero_addr[4][6] ={ {0x00,0x00,0x00,0x00,0x00,0x00}, ++ {0x00,0x00,0x00,0x00,0x00,0x01}, ++ {0x00,0x00,0x00,0x00,0x00,0x02}, ++ {0x00,0x00,0x00,0x00,0x00,0x03} }; ++ int i; ++ ++ if(!priv->up) return -ENETDOWN; ++ ++ down(&priv->wx_sem); ++ ++ RT_TRACE(COMP_SEC, "Setting SW wep key"); ++ ret = ieee80211_wx_set_encode(priv->ieee80211,info,wrqu,key); ++ ++ up(&priv->wx_sem); ++ ++ ++ //sometimes, the length is zero while we do not type key value ++ if(wrqu->encoding.length!=0){ ++ ++ for(i=0 ; i<4 ; i++){ ++ hwkey[i] |= key[4*i+0]&mask; ++ if(i==1&&(4*i+1)==wrqu->encoding.length) mask=0x00; ++ if(i==3&&(4*i+1)==wrqu->encoding.length) mask=0x00; ++ hwkey[i] |= (key[4*i+1]&mask)<<8; ++ hwkey[i] |= (key[4*i+2]&mask)<<16; ++ hwkey[i] |= (key[4*i+3]&mask)<<24; ++ } ++ ++ #define CONF_WEP40 0x4 ++ #define CONF_WEP104 0x14 ++ ++ switch(wrqu->encoding.flags & IW_ENCODE_INDEX){ ++ case 0: key_idx = ieee->tx_keyidx; break; ++ case 1: key_idx = 0; break; ++ case 2: key_idx = 1; break; ++ case 3: key_idx = 2; break; ++ case 4: key_idx = 3; break; ++ default: break; ++ } ++ ++ //printk("-------====>length:%d, key_idx:%d, flag:%x\n", wrqu->encoding.length, key_idx, wrqu->encoding.flags); ++ if(wrqu->encoding.length==0x5){ ++ ieee->pairwise_key_type = KEY_TYPE_WEP40; ++ EnableHWSecurityConfig8192(dev); ++ setKey( dev, ++ key_idx, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP40, //KeyType ++ zero_addr[key_idx], ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ ++#if 0 ++ if(key_idx == 0){ ++ ++ //write_nic_byte(dev, SECR, 7); ++ setKey( dev, ++ 4, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP40, //KeyType ++ broadcast_addr, //addr ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ } ++#endif ++ } ++ ++ else if(wrqu->encoding.length==0xd){ ++ ieee->pairwise_key_type = KEY_TYPE_WEP104; ++ EnableHWSecurityConfig8192(dev); ++ setKey( dev, ++ key_idx, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP104, //KeyType ++ zero_addr[key_idx], ++ 0, //DefaultKey ++ hwkey); //KeyContent ++#if 0 ++ if(key_idx == 0){ ++ ++ //write_nic_byte(dev, SECR, 7); ++ setKey( dev, ++ 4, //EntryNo ++ key_idx, //KeyIndex ++ KEY_TYPE_WEP104, //KeyType ++ broadcast_addr, //addr ++ 0, //DefaultKey ++ hwkey); //KeyContent ++ } ++#endif ++ } ++ else printk("wrong type in WEP, not WEP40 and WEP104\n"); ++ ++ ++ } ++ ++#if 0 ++ //consider the setting different key index situation ++ //wrqu->encoding.flags = 801 means that we set key with index "1" ++ if(wrqu->encoding.length==0 && (wrqu->encoding.flags >>8) == 0x8 ){ ++ printk("===>1\n"); ++ //write_nic_byte(dev, SECR, 7); ++ EnableHWSecurityConfig8192(dev); ++ //copy wpa config from default key(key0~key3) to broadcast key(key5) ++ // ++ key_idx = (wrqu->encoding.flags & 0xf)-1 ; ++ write_cam(dev, (4*6), 0xffff0000|read_cam(dev, key_idx*6) ); ++ write_cam(dev, (4*6)+1, 0xffffffff); ++ write_cam(dev, (4*6)+2, read_cam(dev, (key_idx*6)+2) ); ++ write_cam(dev, (4*6)+3, read_cam(dev, (key_idx*6)+3) ); ++ write_cam(dev, (4*6)+4, read_cam(dev, (key_idx*6)+4) ); ++ write_cam(dev, (4*6)+5, read_cam(dev, (key_idx*6)+5) ); ++ } ++#endif ++ ++ return ret; ++} ++ ++ ++static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union ++ iwreq_data *wrqu, char *p){ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int *parms=(int*)p; ++ int mode=parms[0]; ++ ++ priv->ieee80211->active_scan = mode; ++ ++ return 1; ++} ++ ++ ++ ++static int r8192_wx_set_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int err = 0; ++ ++ down(&priv->wx_sem); ++ ++ if (wrqu->retry.flags & IW_RETRY_LIFETIME || ++ wrqu->retry.disabled){ ++ err = -EINVAL; ++ goto exit; ++ } ++ if (!(wrqu->retry.flags & IW_RETRY_LIMIT)){ ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if(wrqu->retry.value > R8180_MAX_RETRY){ ++ err= -EINVAL; ++ goto exit; ++ } ++ if (wrqu->retry.flags & IW_RETRY_MAX) { ++ priv->retry_rts = wrqu->retry.value; ++ DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value); ++ ++ }else { ++ priv->retry_data = wrqu->retry.value; ++ DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value); ++ } ++ ++ /* FIXME ! ++ * We might try to write directly the TX config register ++ * or to restart just the (R)TX process. ++ * I'm unsure if whole reset is really needed ++ */ ++ ++ rtl8192_commit(dev); ++ /* ++ if(priv->up){ ++ rtl8180_rtx_disable(dev); ++ rtl8180_rx_enable(dev); ++ rtl8180_tx_enable(dev); ++ ++ } ++ */ ++exit: ++ up(&priv->wx_sem); ++ ++ return err; ++} ++ ++static int r8192_wx_get_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ ++ wrqu->retry.disabled = 0; /* can't be disabled */ ++ ++ if ((wrqu->retry.flags & IW_RETRY_TYPE) == ++ IW_RETRY_LIFETIME) ++ return -EINVAL; ++ ++ if (wrqu->retry.flags & IW_RETRY_MAX) { ++ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX; ++ wrqu->retry.value = priv->retry_rts; ++ } else { ++ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN; ++ wrqu->retry.value = priv->retry_data; ++ } ++ //DMESG("returning %d",wrqu->retry.value); ++ ++ ++ return 0; ++} ++ ++static int r8192_wx_get_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ if(priv->rf_set_sens == NULL) ++ return -1; /* we have not this support for this radio */ ++ wrqu->sens.value = priv->sens; ++ return 0; ++} ++ ++ ++static int r8192_wx_set_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ short err = 0; ++ down(&priv->wx_sem); ++ //DMESG("attempt to set sensivity to %ddb",wrqu->sens.value); ++ if(priv->rf_set_sens == NULL) { ++ err= -1; /* we have not this support for this radio */ ++ goto exit; ++ } ++ if(priv->rf_set_sens(dev, wrqu->sens.value) == 0) ++ priv->sens = wrqu->sens.value; ++ else ++ err= -EINVAL; ++ ++exit: ++ up(&priv->wx_sem); ++ ++ return err; ++} ++ ++#if (WIRELESS_EXT >= 18) ++#if 0 ++static int r8192_wx_get_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int ret = 0; ++ ret = ieee80211_wx_get_encode_ext(priv->ieee80211, info, wrqu, extra); ++ return ret; ++} ++#endif ++static int r8192_wx_set_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret=0; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_encode_ext(ieee, info, wrqu, extra); ++ ++ { ++ u8 broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ u8 zero[6] = {0}; ++ u32 key[4] = {0}; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ struct iw_point *encoding = &wrqu->encoding; ++#if 0 ++ static u8 CAM_CONST_ADDR[4][6] = { ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, ++ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}}; ++#endif ++ u8 idx = 0, alg = 0, group = 0; ++ if ((encoding->flags & IW_ENCODE_DISABLED) || ++ ext->alg == IW_ENCODE_ALG_NONE) //none is not allowed to use hwsec WB 2008.07.01 ++ { ++ ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; ++ CamResetAllEntry(dev); ++ goto end_hw_sec; ++ } ++ alg = (ext->alg == IW_ENCODE_ALG_CCMP)?KEY_TYPE_CCMP:ext->alg; // as IW_ENCODE_ALG_CCMP is defined to be 3 and KEY_TYPE_CCMP is defined to 4; ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) ++ idx --; ++ group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY; ++ ++ if ((!group) || (IW_MODE_ADHOC == ieee->iw_mode) || (alg == KEY_TYPE_WEP40)) ++ { ++ if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40) ) ++ alg = KEY_TYPE_WEP104; ++ ieee->pairwise_key_type = alg; ++ EnableHWSecurityConfig8192(dev); ++ } ++ memcpy((u8*)key, ext->key, 16); //we only get 16 bytes key.why? WB 2008.7.1 ++ ++ if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode !=2) ) ++ { ++ if (ext->key_len == 13) ++ ieee->pairwise_key_type = alg = KEY_TYPE_WEP104; ++ setKey( dev, ++ idx,//EntryNo ++ idx, //KeyIndex ++ alg, //KeyType ++ zero, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ else if (group) ++ { ++ ieee->group_key_type = alg; ++ setKey( dev, ++ idx,//EntryNo ++ idx, //KeyIndex ++ alg, //KeyType ++ broadcast_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ else //pairwise key ++ { ++ if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport){ ++ write_nic_byte(dev, 0x173, 1); //fix aes bug ++ } ++ setKey( dev, ++ 4,//EntryNo ++ idx, //KeyIndex ++ alg, //KeyType ++ (u8*)ieee->ap_mac_addr, //MacAddr ++ 0, //DefaultKey ++ key); //KeyContent ++ } ++ ++ ++ } ++ ++end_hw_sec: ++ up(&priv->wx_sem); ++#endif ++ return ret; ++ ++} ++static int r8192_wx_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *data, char *extra) ++{ ++ int ret=0; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ //printk("====>%s()\n", __FUNCTION__); ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra); ++ up(&priv->wx_sem); ++#endif ++ return ret; ++} ++ ++static int r8192_wx_set_mlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ //printk("====>%s()\n", __FUNCTION__); ++ ++ int ret=0; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); ++ up(&priv->wx_sem); ++#endif ++ return ret; ++} ++#endif ++static int r8192_wx_set_gen_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *data, char *extra) ++{ ++ //printk("====>%s(), len:%d\n", __FUNCTION__, data->length); ++ int ret=0; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ down(&priv->wx_sem); ++#if 1 ++ ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length); ++#endif ++ up(&priv->wx_sem); ++ //printk("<======%s(), ret:%d\n", __FUNCTION__, ret); ++#endif ++ return ret; ++ ++ ++} ++ ++static int dummy(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu,char *b) ++{ ++ return -1; ++} ++ ++ ++static iw_handler r8192_wx_handlers[] = ++{ ++ NULL, /* SIOCSIWCOMMIT */ ++ r8192_wx_get_name, /* SIOCGIWNAME */ ++ dummy, /* SIOCSIWNWID */ ++ dummy, /* SIOCGIWNWID */ ++ r8192_wx_set_freq, /* SIOCSIWFREQ */ ++ r8192_wx_get_freq, /* SIOCGIWFREQ */ ++ r8192_wx_set_mode, /* SIOCSIWMODE */ ++ r8192_wx_get_mode, /* SIOCGIWMODE */ ++ r8192_wx_set_sens, /* SIOCSIWSENS */ ++ r8192_wx_get_sens, /* SIOCGIWSENS */ ++ NULL, /* SIOCSIWRANGE */ ++ rtl8180_wx_get_range, /* SIOCGIWRANGE */ ++ NULL, /* SIOCSIWPRIV */ ++ NULL, /* SIOCGIWPRIV */ ++ NULL, /* SIOCSIWSTATS */ ++ NULL, /* SIOCGIWSTATS */ ++ dummy, /* SIOCSIWSPY */ ++ dummy, /* SIOCGIWSPY */ ++ NULL, /* SIOCGIWTHRSPY */ ++ NULL, /* SIOCWIWTHRSPY */ ++ r8192_wx_set_wap, /* SIOCSIWAP */ ++ r8192_wx_get_wap, /* SIOCGIWAP */ ++#if (WIRELESS_EXT >= 18) ++ r8192_wx_set_mlme, /* MLME-- */ ++#else ++ NULL, ++#endif ++ dummy, /* SIOCGIWAPLIST -- depricated */ ++ r8192_wx_set_scan, /* SIOCSIWSCAN */ ++ r8192_wx_get_scan, /* SIOCGIWSCAN */ ++ r8192_wx_set_essid, /* SIOCSIWESSID */ ++ r8192_wx_get_essid, /* SIOCGIWESSID */ ++ dummy, /* SIOCSIWNICKN */ ++ dummy, /* SIOCGIWNICKN */ ++ NULL, /* -- hole -- */ ++ NULL, /* -- hole -- */ ++ r8192_wx_set_rate, /* SIOCSIWRATE */ ++ r8192_wx_get_rate, /* SIOCGIWRATE */ ++ r8192_wx_set_rts, /* SIOCSIWRTS */ ++ r8192_wx_get_rts, /* SIOCGIWRTS */ ++ r8192_wx_set_frag, /* SIOCSIWFRAG */ ++ r8192_wx_get_frag, /* SIOCGIWFRAG */ ++ dummy, /* SIOCSIWTXPOW */ ++ dummy, /* SIOCGIWTXPOW */ ++ r8192_wx_set_retry, /* SIOCSIWRETRY */ ++ r8192_wx_get_retry, /* SIOCGIWRETRY */ ++ r8192_wx_set_enc, /* SIOCSIWENCODE */ ++ r8192_wx_get_enc, /* SIOCGIWENCODE */ ++ r8192_wx_set_power, /* SIOCSIWPOWER */ ++ r8192_wx_get_power, /* SIOCGIWPOWER */ ++ NULL, /*---hole---*/ ++ NULL, /*---hole---*/ ++ r8192_wx_set_gen_ie,//NULL, /* SIOCSIWGENIE */ ++ NULL, /* SIOCSIWGENIE */ ++#if (WIRELESS_EXT >= 18) ++ r8192_wx_set_auth,//NULL, /* SIOCSIWAUTH */ ++ NULL,//r8192_wx_get_auth,//NULL, /* SIOCSIWAUTH */ ++ r8192_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ ++#else ++ NULL, ++ NULL, ++ NULL, ++#endif ++ NULL,//r8192_wx_get_enc_ext,//NULL, /* SIOCSIWENCODEEXT */ ++ NULL, /* SIOCSIWPMKSA */ ++ NULL, /*---hole---*/ ++ ++}; ++ ++ ++static const struct iw_priv_args r8192_private_args[] = { ++ ++ { ++ SIOCIWFIRSTPRIV + 0x0, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" ++ }, ++ ++ { ++ SIOCIWFIRSTPRIV + 0x1, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" ++ ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x2, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" ++ } ++#ifdef JOHN_IOCTL ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x3, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readRF" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x4, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeRF" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x5, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readBB" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x6, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writeBB" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x7, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "readnicb" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x8, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "writenicb" ++ } ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x9, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" ++ } ++ ++#endif ++ , ++ { ++ SIOCIWFIRSTPRIV + 0x3, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset" ++ ++ } ++ ++}; ++ ++ ++static iw_handler r8192_private_handler[] = { ++// r8192_wx_set_monitor, /* SIOCIWFIRSTPRIV */ ++ r8192_wx_set_crcmon, /*SIOCIWSECONDPRIV*/ ++// r8192_wx_set_forceassociate, ++// r8192_wx_set_beaconinterval, ++// r8192_wx_set_monitor_type, ++ r8192_wx_set_scan_type, ++ r8192_wx_set_rawtx, ++#ifdef JOHN_IOCTL ++ r8192_wx_read_regs, ++ r8192_wx_write_regs, ++ r8192_wx_read_bb, ++ r8192_wx_write_bb, ++ r8192_wx_read_nicb, ++ r8192_wx_write_nicb, ++ r8192_wx_get_ap_status ++#endif ++ r8192_wx_force_reset, ++}; ++ ++//#if WIRELESS_EXT >= 17 ++struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ struct iw_statistics* wstats = &priv->wstats; ++ int tmp_level = 0; ++ int tmp_qual = 0; ++ int tmp_noise = 0; ++ if(ieee->state < IEEE80211_LINKED) ++ { ++ wstats->qual.qual = 0; ++ wstats->qual.level = 0; ++ wstats->qual.noise = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++#else ++ wstats->qual.updated = 0x0f; ++#endif ++ return wstats; ++ } ++ ++ tmp_level = (&ieee->current_network)->stats.rssi; ++ tmp_qual = (&ieee->current_network)->stats.signal; ++ tmp_noise = (&ieee->current_network)->stats.noise; ++ //printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); ++ ++ wstats->qual.level = tmp_level; ++ wstats->qual.qual = tmp_qual; ++ wstats->qual.noise = tmp_noise; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++#else ++ wstats->qual.updated = 0x0f; ++#endif ++ return wstats; ++} ++//#endif ++ ++ ++struct iw_handler_def r8192_wx_handlers_def={ ++ .standard = r8192_wx_handlers, ++ .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler), ++ .private = r8192_private_handler, ++ .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler), ++ .num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args), ++#if WIRELESS_EXT >= 17 ++ .get_wireless_stats = r8192_get_wireless_stats, ++#endif ++ .private_args = (struct iw_priv_args *)r8192_private_args, ++}; +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192E_wx.h +@@ -0,0 +1,22 @@ ++/* ++ This is part of rtl8180 OpenSource driver - v 0.3 ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++/* this file (will) contains wireless extension handlers*/ ++ ++#ifndef R8180_WX_H ++#define R8180_WX_H ++//#include ++//#include "ieee80211.h" ++extern struct iw_handler_def r8192_wx_handlers_def; ++/* Enable the rtl819x_core.c to share this function, david 2008.9.22 */ ++extern struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192_pm.c +@@ -0,0 +1,181 @@ ++/* ++ Power management interface routines. ++ Written by Mariusz Matuszek. ++ This code is currently just a placeholder for later work and ++ does not do anything useful. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++*/ ++ ++#ifdef CONFIG_PM_RTL ++ ++#include "r8192E.h" ++#include "r8192E_hw.h" ++#include "r8192_pm.h" ++#include "r8190_rtl8256.h" ++ ++int rtl8192E_save_state (struct pci_dev *dev, pm_message_t state) ++{ ++ printk(KERN_NOTICE "r8192E save state call (state %u).\n", state.event); ++ return(-EAGAIN); ++} ++ ++ ++int rtl8192E_suspend (struct pci_dev *pdev, pm_message_t state) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 ucRegRead; ++ u32 ulRegRead; ++ ++ RT_TRACE(COMP_POWER, "============> r8192E suspend call.\n"); ++ if (!netif_running(dev)) ++ goto out_pci_suspend; ++ ++ dev->stop(dev); ++#if 0 ++ ++ netif_carrier_off(dev); ++ ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ ++ write_nic_byte(dev,MSR,(read_nic_byte(dev,MSR)&0xfc)|MSR_LINK_NONE); ++ if(!priv->ieee80211->bSupportRemoteWakeUp) { ++ /* disable tx/rx. In 8185 we write 0x10 (Reset bit), ++ * but here we make reference to WMAC and wirte 0x0. ++ * 2006.11.21 Emily ++ */ ++ write_nic_byte(dev, CMDR, 0); ++ } ++ //disable interrupt ++ write_nic_dword(dev,INTA_MASK,0); ++ priv->irq_enabled = 0; ++ write_nic_dword(dev,ISR,read_nic_dword(dev, ISR)); ++ ++ /* need to free DM related functions */ ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++ cancel_work_sync(&priv->reset_wq); ++#else ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&priv->reset_wq); ++#endif ++#endif ++ del_timer_sync(&priv->fsync_timer); ++ del_timer_sync(&priv->watch_dog_timer); ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&priv->watch_dog_wq); ++ cancel_delayed_work(&priv->update_beacon_wq); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ cancel_work_sync(&priv->qos_activate); ++#else ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ cancel_delayed_work(&priv->qos_activate); ++#endif ++#endif ++ ++ /* TODO ++#if ((DEV_BUS_TYPE == PCI_INTERFACE) && (HAL_CODE_BASE == RTL8192)) ++pHalData->bHwRfOffAction = 2; ++#endif ++*/ ++#endif ++ // Call MgntActSet_RF_State instead to prevent RF config race condition. ++ // By Bruce, 2008-01-17. ++ // ++ if(!priv->ieee80211->bSupportRemoteWakeUp) { ++ MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT); ++ // 2006.11.30. System reset bit ++ ulRegRead = read_nic_dword(dev, CPU_GEN); ++ ulRegRead|=CPU_GEN_SYSTEM_RESET; ++ write_nic_dword(dev, CPU_GEN, ulRegRead); ++ } else { ++ //2008.06.03 for WOL ++ write_nic_dword(dev, WFCRC0, 0xffffffff); ++ write_nic_dword(dev, WFCRC1, 0xffffffff); ++ write_nic_dword(dev, WFCRC2, 0xffffffff); ++#ifdef RTL8190P ++ //GPIO 0 = TRUE ++ ucRegRead = read_nic_byte(dev, GPO); ++ ucRegRead |= BIT0; ++ write_nic_byte(dev, GPO, ucRegRead); ++#endif ++ //Write PMR register ++ write_nic_byte(dev, PMR, 0x5); ++ //Disable tx, enanble rx ++ write_nic_byte(dev, MacBlkCtrl, 0xa); ++ } ++ ++out_pci_suspend: ++ RT_TRACE(COMP_POWER, "r8192E support WOL call??????????????????????\n"); ++ if(priv->ieee80211->bSupportRemoteWakeUp) { ++ RT_TRACE(COMP_POWER, "r8192E support WOL call!!!!!!!!!!!!!!!!!!.\n"); ++ } ++ netif_device_detach(dev); ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_enable_wake(pdev, pci_choose_state(pdev,state),\ ++ priv->ieee80211->bSupportRemoteWakeUp?1:0); ++ pci_set_power_state(pdev,pci_choose_state(pdev,state)); ++ ++ return 0; ++} ++ ++int rtl8192E_resume (struct pci_dev *pdev) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++ //struct r8192_priv *priv = ieee80211_priv(dev); ++ //union iwreq_data wrqu; ++ int err; ++ u32 val; ++ ++ RT_TRACE(COMP_POWER, "================>r8192E resume call."); ++ ++ pci_set_power_state(pdev, PCI_D0); ++ ++ err = pci_enable_device(pdev); ++ if(err) { ++ printk(KERN_ERR "%s: pci_enable_device failed on resume\n", ++ dev->name); ++ return err; ++ } ++ ++ pci_restore_state(pdev); ++ ++ /* ++ * Suspend/Resume resets the PCI configuration space, so we have to ++ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries ++ * from interfering with C3 CPU state. pci_restore_state won't help ++ * here since it only restores the first 64 bytes pci config header. ++ */ ++ pci_read_config_dword(pdev, 0x40, &val); ++ if ((val & 0x0000ff00) != 0) { ++ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ++ } ++ ++ ++ ++ pci_enable_wake(pdev, PCI_D0, 0); ++ ++ if(!netif_running(dev)) ++ goto out; ++ ++ netif_device_attach(dev); ++ ++ dev->open(dev); ++out: ++ RT_TRACE(COMP_POWER, "<================r8192E resume call.\n"); ++ return 0; ++} ++ ++ ++int rtl8192E_enable_wake (struct pci_dev *dev, pm_message_t state, int enable) ++{ ++ printk(KERN_NOTICE "r8192E enable wake call (state %u, enable %d).\n", ++ state.event, enable); ++ return(-EAGAIN); ++} ++ ++#endif //CONFIG_PM_RTL +--- /dev/null ++++ b/drivers/staging/rtl8192e/r8192_pm.h +@@ -0,0 +1,28 @@ ++/* ++ Power management interface routines. ++ Written by Mariusz Matuszek. ++ This code is currently just a placeholder for later work and ++ does not do anything useful. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++*/ ++ ++#ifdef CONFIG_PM_RTL ++ ++#ifndef R8192E_PM_H ++#define R8192E_PM_H ++ ++#include ++#include ++ ++int rtl8192E_save_state (struct pci_dev *dev, pm_message_t state); ++int rtl8192E_suspend (struct pci_dev *dev, pm_message_t state); ++int rtl8192E_resume (struct pci_dev *dev); ++int rtl8192E_enable_wake (struct pci_dev *dev, pm_message_t state, int enable); ++ ++#endif //R8192E_PM_H ++ ++#endif // CONFIG_PM_RTL +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_cmdpkt.c +@@ -0,0 +1,820 @@ ++/****************************************************************************** ++ ++ (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved. ++ ++ Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File) ++ ++ Note: The module is responsible for handling TX and RX command packet. ++ 1. TX : Send set and query configuration command packet. ++ 2. RX : Receive tx feedback, beacon state, query configuration ++ command packet. ++ ++ Function: ++ ++ Export: ++ ++ Abbrev: ++ ++ History: ++ Data Who Remark ++ ++ 05/06/2008 amy Create initial version porting from windows driver. ++ ++******************************************************************************/ ++#include "r8192E.h" ++#include "r8192E_hw.h" ++#include "r819xE_cmdpkt.h" ++/*---------------------------Define Local Constant---------------------------*/ ++/* Debug constant*/ ++#define CMPK_DEBOUNCE_CNT 1 ++/* 2007/10/24 MH Add for printing a range of data. */ ++#define CMPK_PRINT(Address)\ ++{\ ++ unsigned char i;\ ++ u32 temp[10];\ ++ \ ++ memcpy(temp, Address, 40);\ ++ for (i = 0; i <40; i+=4)\ ++ printk("\r\n %08x", temp[i]);\ ++}\ ++ ++/*---------------------------Define functions---------------------------------*/ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_message_handle_tx() ++ * ++ * Overview: Driver internal module can call the API to send message to ++ * firmware side. For example, you can send a debug command packet. ++ * Or you can send a request for FW to modify RLX4181 LBUS HW bank. ++ * Otherwise, you can change MAC/PHT/RF register by firmware at ++ * run time. We do not support message more than one segment now. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/06/2008 amy porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++RT_STATUS cmpk_message_handle_tx( ++ struct net_device *dev, ++ u8* code_virtual_address, ++ u32 packettype, ++ u32 buffer_len) ++{ ++ ++ RT_STATUS rt_status = RT_STATUS_SUCCESS; ++#ifdef RTL8192U ++ return rt_status; ++#else ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u16 frag_threshold; ++ u16 frag_length = 0, frag_offset = 0; ++ rt_firmware *pfirmware = priv->pFirmware; ++ struct sk_buff *skb; ++ unsigned char *seg_ptr; ++ cb_desc *tcb_desc; ++ u8 bLastIniPkt; ++ ++ PTX_FWINFO_8190PCI pTxFwInfo = NULL; ++ int i; ++ ++ //spin_lock_irqsave(&priv->tx_lock,flags); ++ RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len); ++ firmware_init_param(dev); ++ //Fragmentation might be required ++ frag_threshold = pfirmware->cmdpacket_frag_thresold; ++ do { ++ if((buffer_len - frag_offset) > frag_threshold) { ++ frag_length = frag_threshold ; ++ bLastIniPkt = 0; ++ ++ } else { ++ frag_length =(u16)(buffer_len - frag_offset); ++ bLastIniPkt = 1; ++ ++ } ++ ++ /* Allocate skb buffer to contain firmware info and tx descriptor info ++ * add 4 to avoid packet appending overflow. ++ * */ ++#ifdef RTL8192U ++ skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); ++#else ++ skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4); ++#endif ++ if(skb == NULL) { ++ rt_status = RT_STATUS_FAILURE; ++ goto Failed; ++ } ++ ++ memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); ++ tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); ++ tcb_desc->queue_index = TXCMD_QUEUE; ++ tcb_desc->bCmdOrInit = packettype; ++ tcb_desc->bLastIniPkt = bLastIniPkt; ++ tcb_desc->pkt_size = frag_length; ++ ++#ifdef RTL8192U ++ skb_reserve(skb, USB_HWDESC_HEADER_LEN); ++#endif ++ ++ //seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom); ++ seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom); ++ ++ pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr; ++ memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI)); ++ memset(pTxFwInfo,0x12,8); ++ ++ seg_ptr +=sizeof(TX_FWINFO_8190PCI); ++ ++ /* ++ * Transform from little endian to big endian ++ * and pending zero ++ */ ++ seg_ptr = skb->tail; ++ for(i=0 ; i < frag_length; i+=4) { ++ *seg_ptr++ = ((i+0)ieee80211->softmac_hard_start_xmit(skb,dev); ++ ++ code_virtual_address += frag_length; ++ frag_offset += frag_length; ++ ++#if 0 ++ { ++ int k; ++ printk("------------tx cmd------------\n"); ++ for(k = 0; ktx_lock,flags); ++ return rt_status; ++ ++ ++#endif ++} /* CMPK_Message_Handle_Tx */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_counttxstatistic() ++ * ++ * Overview: ++ * ++ * Input: PADAPTER pAdapter - . ++ * CMPK_TXFB_T *psTx_FB - . ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/12/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++cmpk_count_txstatistic( ++ struct net_device *dev, ++ cmpk_txfb_t *pstx_fb) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#ifdef ENABLE_PS ++ RT_RF_POWER_STATE rtState; ++ ++ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); ++ ++ // When RF is off, we should not count the packet for hw/sw synchronize ++ // reason, ie. there may be a duration while sw switch is changed and hw ++ // switch is being changed. 2006.12.04, by shien chang. ++ if (rtState == eRfOff) ++ { ++ return; ++ } ++#endif ++ ++#ifdef TODO ++ if(pAdapter->bInHctTest) ++ return; ++#endif ++ /* We can not know the packet length and transmit type: broadcast or uni ++ or multicast. So the relative statistics must be collected in tx ++ feedback info. */ ++ if (pstx_fb->tok) ++ { ++ priv->stats.txfeedbackok++; ++ priv->stats.txoktotal++; ++ priv->stats.txokbytestotal += pstx_fb->pkt_length; ++ priv->stats.txokinperiod++; ++ ++ /* We can not make sure broadcast/multicast or unicast mode. */ ++ if (pstx_fb->pkt_type == PACKET_MULTICAST) ++ { ++ priv->stats.txmulticast++; ++ priv->stats.txbytesmulticast += pstx_fb->pkt_length; ++ } ++ else if (pstx_fb->pkt_type == PACKET_BROADCAST) ++ { ++ priv->stats.txbroadcast++; ++ priv->stats.txbytesbroadcast += pstx_fb->pkt_length; ++ } ++ else ++ { ++ priv->stats.txunicast++; ++ priv->stats.txbytesunicast += pstx_fb->pkt_length; ++ } ++ } ++ else ++ { ++ priv->stats.txfeedbackfail++; ++ priv->stats.txerrtotal++; ++ priv->stats.txerrbytestotal += pstx_fb->pkt_length; ++ ++ /* We can not make sure broadcast/multicast or unicast mode. */ ++ if (pstx_fb->pkt_type == PACKET_MULTICAST) ++ { ++ priv->stats.txerrmulticast++; ++ } ++ else if (pstx_fb->pkt_type == PACKET_BROADCAST) ++ { ++ priv->stats.txerrbroadcast++; ++ } ++ else ++ { ++ priv->stats.txerrunicast++; ++ } ++ } ++ ++ priv->stats.txretrycount += pstx_fb->retry_cnt; ++ priv->stats.txfeedbackretry += pstx_fb->retry_cnt; ++ ++} /* cmpk_CountTxStatistic */ ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_handle_tx_feedback() ++ * ++ * Overview: The function is responsible for extract the message inside TX ++ * feedbck message from firmware. It will contain dedicated info in ++ * ws-06-0063-rtl8190-command-packet-specification. Please ++ * refer to chapter "TX Feedback Element". We have to read 20 bytes ++ * in the command packet. ++ * ++ * Input: struct net_device * dev ++ * u8 * pmsg - Msg Ptr of the command packet. ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/08/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++cmpk_handle_tx_feedback( ++ struct net_device *dev, ++ u8 * pmsg) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ cmpk_txfb_t rx_tx_fb; /* */ ++ ++ priv->stats.txfeedback++; ++ ++ /* 0. Display received message. */ ++ //cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg); ++ ++ /* 1. Extract TX feedback info from RFD to temp structure buffer. */ ++ /* It seems that FW use big endian(MIPS) and DRV use little endian in ++ windows OS. So we have to read the content byte by byte or transfer ++ endian type before copy the message copy. */ ++#if 0 // The TX FEEDBACK packet element address ++ //rx_tx_fb.Element_ID = pMsg[0]; ++ //rx_tx_fb.Length = pMsg[1]; ++ rx_tx_fb.TOK = pMsg[2]>>7; ++ rx_tx_fb.Fail_Reason = (pMsg[2] & 0x70) >> 4; ++ rx_tx_fb.TID = (pMsg[2] & 0x0F); ++ rx_tx_fb.Qos_Pkt = pMsg[3] >> 7; ++ rx_tx_fb.Bandwidth = (pMsg[3] & 0x40) >> 6; ++ rx_tx_fb.Retry_Cnt = pMsg[5]; ++ rx_tx_fb.Pkt_ID = (pMsg[6] << 8) | pMsg[7]; ++ rx_tx_fb.Seq_Num = (pMsg[8] << 8) | pMsg[9]; ++ rx_tx_fb.S_Rate = pMsg[10]; ++ rx_tx_fb.F_Rate = pMsg[11]; ++ rx_tx_fb.S_RTS_Rate = pMsg[12]; ++ rx_tx_fb.F_RTS_Rate = pMsg[13]; ++ rx_tx_fb.pkt_length = (pMsg[14] << 8) | pMsg[15]; ++#endif ++ /* 2007/07/05 MH Use pointer to transfer structure memory. */ ++ //memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T)); ++ memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t)); ++ /* 2. Use tx feedback info to count TX statistics. */ ++ cmpk_count_txstatistic(dev, &rx_tx_fb); ++#if 0 ++ /* 2007/07/11 MH Assign current operate rate. */ ++ if (pAdapter->RegWirelessMode == WIRELESS_MODE_A || ++ pAdapter->RegWirelessMode == WIRELESS_MODE_B || ++ pAdapter->RegWirelessMode == WIRELESS_MODE_G) ++ { ++ pMgntInfo->CurrentOperaRate = (rx_tx_fb.F_Rate & 0x7F); ++ } ++ else if (pAdapter->RegWirelessMode == WIRELESS_MODE_N_24G || ++ pAdapter->RegWirelessMode == WIRELESS_MODE_N_5G) ++ { ++ pMgntInfo->HTCurrentOperaRate = (rx_tx_fb.F_Rate & 0x8F); ++ } ++#endif ++ /* 2007/01/17 MH Comment previous method for TX statistic function. */ ++ /* Collect info TX feedback packet to fill TCB. */ ++ /* We can not know the packet length and transmit type: broadcast or uni ++ or multicast. */ ++ //CountTxStatistics( pAdapter, &tcb ); ++ ++} /* cmpk_Handle_Tx_Feedback */ ++ ++static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u16 tx_rate; ++ { ++ // ++ // 070117, rcnjko: 87B have to S/W beacon for DTM encryption_cmn. ++ // ++ if((priv->ieee80211->current_network.mode == IEEE_A) || ++ (priv->ieee80211->current_network.mode == IEEE_N_5G) || ++ ((priv->ieee80211->current_network.mode == IEEE_N_24G) && (!priv->ieee80211->pHTInfo->bCurSuppCCK))) ++ { ++ tx_rate = 60; ++ DMESG("send beacon frame tx rate is 6Mbpm\n"); ++ } ++ else ++ { ++ tx_rate =10; ++ DMESG("send beacon frame tx rate is 1Mbpm\n"); ++ } ++ ++ //rtl819xusb_beacon_tx(dev,tx_rate); // HW Beacon ++ ++ } ++ ++} ++ ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_handle_interrupt_status() ++ * ++ * Overview: The function is responsible for extract the message from ++ * firmware. It will contain dedicated info in ++ * ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc. ++ * Please refer to chapter "Interrupt Status Element". ++ * ++ * Input: struct net_device *dev, ++ * u8* pmsg - Message Pointer of the command packet. ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/12/2008 amy Add this for rtl8192 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++cmpk_handle_interrupt_status( ++ struct net_device *dev, ++ u8* pmsg) ++{ ++ cmpk_intr_sta_t rx_intr_status; /* */ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ DMESG("---> cmpk_Handle_Interrupt_Status()\n"); ++ ++ /* 0. Display received message. */ ++ //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg); ++ ++ /* 1. Extract TX feedback info from RFD to temp structure buffer. */ ++ /* It seems that FW use big endian(MIPS) and DRV use little endian in ++ windows OS. So we have to read the content byte by byte or transfer ++ endian type before copy the message copy. */ ++ //rx_bcn_state.Element_ID = pMsg[0]; ++ //rx_bcn_state.Length = pMsg[1]; ++ rx_intr_status.length = pmsg[1]; ++ if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) ++ { ++ DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n"); ++ return; ++ } ++ ++ ++ // Statistics of beacon for ad-hoc mode. ++ if( priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ { ++ //2 maybe need endian transform? ++ rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4)); ++ //rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4))); ++ ++ DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status); ++ ++ if (rx_intr_status.interrupt_status & ISR_TxBcnOk) ++ { ++ priv->ieee80211->bibsscoordinator = true; ++ priv->stats.txbeaconokint++; ++ } ++ else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) ++ { ++ priv->ieee80211->bibsscoordinator = false; ++ priv->stats.txbeaconerr++; ++ } ++ ++ if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr) ++ { ++ cmdpkt_beacontimerinterrupt_819xusb(dev); ++ } ++ ++ } ++ ++ // Other informations in interrupt status we need? ++ ++ ++ DMESG("<---- cmpk_handle_interrupt_status()\n"); ++ ++} /* cmpk_handle_interrupt_status */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_handle_query_config_rx() ++ * ++ * Overview: The function is responsible for extract the message from ++ * firmware. It will contain dedicated info in ++ * ws-06-0063-rtl8190-command-packet-specification. Please ++ * refer to chapter "Beacon State Element". ++ * ++ * Input: u8 * pmsg - Message Pointer of the command packet. ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/12/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++cmpk_handle_query_config_rx( ++ struct net_device *dev, ++ u8* pmsg) ++{ ++ cmpk_query_cfg_t rx_query_cfg; /* */ ++ ++ /* 0. Display received message. */ ++ //cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg); ++ ++ /* 1. Extract TX feedback info from RFD to temp structure buffer. */ ++ /* It seems that FW use big endian(MIPS) and DRV use little endian in ++ windows OS. So we have to read the content byte by byte or transfer ++ endian type before copy the message copy. */ ++ //rx_query_cfg.Element_ID = pMsg[0]; ++ //rx_query_cfg.Length = pMsg[1]; ++ rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31; ++ rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5; ++ rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3; ++ rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0; ++ rx_query_cfg.cfg_offset = pmsg[7]; ++ rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) | ++ (pmsg[10] << 8) | (pmsg[11] << 0); ++ rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) | ++ (pmsg[14] << 8) | (pmsg[15] << 0); ++ ++} /* cmpk_Handle_Query_Config_Rx */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_count_tx_status() ++ * ++ * Overview: Count aggregated tx status from firmwar of one type rx command ++ * packet element id = RX_TX_STATUS. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/12/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void cmpk_count_tx_status( struct net_device *dev, ++ cmpk_tx_status_t *pstx_status) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++#ifdef ENABLE_PS ++ ++ RT_RF_POWER_STATE rtstate; ++ ++ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); ++ ++ // When RF is off, we should not count the packet for hw/sw synchronize ++ // reason, ie. there may be a duration while sw switch is changed and hw ++ // switch is being changed. 2006.12.04, by shien chang. ++ if (rtState == eRfOff) ++ { ++ return; ++ } ++#endif ++ ++ priv->stats.txfeedbackok += pstx_status->txok; ++ priv->stats.txoktotal += pstx_status->txok; ++ ++ priv->stats.txfeedbackfail += pstx_status->txfail; ++ priv->stats.txerrtotal += pstx_status->txfail; ++ ++ priv->stats.txretrycount += pstx_status->txretry; ++ priv->stats.txfeedbackretry += pstx_status->txretry; ++ ++ //pAdapter->TxStats.NumTxOkBytesTotal += psTx_FB->pkt_length; ++ //pAdapter->TxStats.NumTxErrBytesTotal += psTx_FB->pkt_length; ++ //pAdapter->MgntInfo.LinkDetectInfo.NumTxOkInPeriod++; ++ ++ priv->stats.txmulticast += pstx_status->txmcok; ++ priv->stats.txbroadcast += pstx_status->txbcok; ++ priv->stats.txunicast += pstx_status->txucok; ++ ++ priv->stats.txerrmulticast += pstx_status->txmcfail; ++ priv->stats.txerrbroadcast += pstx_status->txbcfail; ++ priv->stats.txerrunicast += pstx_status->txucfail; ++ ++ priv->stats.txbytesmulticast += pstx_status->txmclength; ++ priv->stats.txbytesbroadcast += pstx_status->txbclength; ++ priv->stats.txbytesunicast += pstx_status->txuclength; ++ ++ priv->stats.last_packet_rate = pstx_status->rate; ++} /* cmpk_CountTxStatus */ ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_handle_tx_status() ++ * ++ * Overview: Firmware add a new tx feedback status to reduce rx command ++ * packet buffer operation load. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/12/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++cmpk_handle_tx_status( ++ struct net_device *dev, ++ u8* pmsg) ++{ ++ cmpk_tx_status_t rx_tx_sts; /* */ ++ ++ memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t)); ++ /* 2. Use tx feedback info to count TX statistics. */ ++ cmpk_count_tx_status(dev, &rx_tx_sts); ++ ++} /* cmpk_Handle_Tx_Status */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_handle_tx_rate_history() ++ * ++ * Overview: Firmware add a new tx rate history ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/12/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++cmpk_handle_tx_rate_history( ++ struct net_device *dev, ++ u8* pmsg) ++{ ++ cmpk_tx_rahis_t *ptxrate; ++// RT_RF_POWER_STATE rtState; ++ u8 i, j; ++ u16 length = sizeof(cmpk_tx_rahis_t); ++ u32 *ptemp; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ ++#ifdef ENABLE_PS ++ pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); ++ ++ // When RF is off, we should not count the packet for hw/sw synchronize ++ // reason, ie. there may be a duration while sw switch is changed and hw ++ // switch is being changed. 2006.12.04, by shien chang. ++ if (rtState == eRfOff) ++ { ++ return; ++ } ++#endif ++ ++ ptemp = (u32 *)pmsg; ++ ++ // ++ // Do endian transfer to word alignment(16 bits) for windows system. ++ // You must do different endian transfer for linux and MAC OS ++ // ++ for (i = 0; i < (length/4); i++) ++ { ++ u16 temp1, temp2; ++ ++ temp1 = ptemp[i]&0x0000FFFF; ++ temp2 = ptemp[i]>>16; ++ ptemp[i] = (temp1<<16)|temp2; ++ } ++ ++ ptxrate = (cmpk_tx_rahis_t *)pmsg; ++ ++ if (ptxrate == NULL ) ++ { ++ return; ++ } ++ ++ for (i = 0; i < 16; i++) ++ { ++ // Collect CCK rate packet num ++ if (i < 4) ++ priv->stats.txrate.cck[i] += ptxrate->cck[i]; ++ ++ // Collect OFDM rate packet num ++ if (i< 8) ++ priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i]; ++ ++ for (j = 0; j < 4; j++) ++ priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i]; ++ } ++ ++} /* cmpk_Handle_Tx_Rate_History */ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: cmpk_message_handle_rx() ++ * ++ * Overview: In the function, we will capture different RX command packet ++ * info. Every RX command packet element has different message ++ * length and meaning in content. We only support three type of RX ++ * command packet now. Please refer to document ++ * ws-06-0063-rtl8190-command-packet-specification. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/06/2008 amy Create Version 0 porting from windows code. ++ * ++ *---------------------------------------------------------------------------*/ ++u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats *pstats) ++{ ++// u32 debug_level = DBG_LOUD; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ int total_length; ++ u8 cmd_length, exe_cnt = 0; ++ u8 element_id; ++ u8 *pcmd_buff; ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n"); ++ ++ /* 0. Check inpt arguments. If is is a command queue message or pointer is ++ null. */ ++ if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL)) ++ { ++ /* Print error message. */ ++ /*RT_TRACE(COMP_SEND, DebugLevel, ++ ("\n\r[CMPK]-->Err queue id or pointer"));*/ ++ return 0; /* This is not a command packet. */ ++ } ++ ++ /* 1. Read received command packet message length from RFD. */ ++ total_length = pstats->Length; ++ ++ /* 2. Read virtual address from RFD. */ ++ pcmd_buff = pstats->virtual_address; ++ ++ /* 3. Read command pakcet element id and length. */ ++ element_id = pcmd_buff[0]; ++ /*RT_TRACE(COMP_SEND, DebugLevel, ++ ("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/ ++ ++ /* 4. Check every received command packet conent according to different ++ element type. Because FW may aggregate RX command packet to minimize ++ transmit time between DRV and FW.*/ ++ // Add a counter to prevent to locked in the loop too long ++ while (total_length > 0 || exe_cnt++ >100) ++ { ++ /* 2007/01/17 MH We support aggregation of different cmd in the same packet. */ ++ element_id = pcmd_buff[0]; ++ ++ switch(element_id) ++ { ++ case RX_TX_FEEDBACK: ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n"); ++ cmpk_handle_tx_feedback (dev, pcmd_buff); ++ cmd_length = CMPK_RX_TX_FB_SIZE; ++ break; ++ ++ case RX_INTERRUPT_STATUS: ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n"); ++ cmpk_handle_interrupt_status(dev, pcmd_buff); ++ cmd_length = sizeof(cmpk_intr_sta_t); ++ break; ++ ++ case BOTH_QUERY_CONFIG: ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n"); ++ cmpk_handle_query_config_rx(dev, pcmd_buff); ++ cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE; ++ break; ++ ++ case RX_TX_STATUS: ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n"); ++ cmpk_handle_tx_status(dev, pcmd_buff); ++ cmd_length = CMPK_RX_TX_STS_SIZE; ++ break; ++ ++ case RX_TX_PER_PKT_FEEDBACK: ++ // You must at lease add a switch case element here, ++ // Otherwise, we will jump to default case. ++ //DbgPrint("CCX Test\r\n"); ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n"); ++ cmd_length = CMPK_RX_TX_FB_SIZE; ++ break; ++ ++ case RX_TX_RATE_HISTORY: ++ //DbgPrint(" rx tx rate history\r\n"); ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n"); ++ cmpk_handle_tx_rate_history(dev, pcmd_buff); ++ cmd_length = CMPK_TX_RAHIS_SIZE; ++ break; ++ ++ default: ++ ++ RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknow CMD Element\n"); ++ return 1; /* This is a command packet. */ ++ } ++ // 2007/01/22 MH Display received rx command packet info. ++ //cmpk_Display_Message(cmd_length, pcmd_buff); ++ ++ // 2007/01/22 MH Add to display tx statistic. ++ //cmpk_DisplayTxStatistic(pAdapter); ++ ++ /* 2007/03/09 MH Collect sidderent cmd element pkt num. */ ++ priv->stats.rxcmdpkt[element_id]++; ++ ++ total_length -= cmd_length; ++ pcmd_buff += cmd_length; ++ } /* while (total_length > 0) */ ++ return 1; /* This is a command packet. */ ++ ++ RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n"); ++} /* CMPK_Message_Handle_Rx */ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_cmdpkt.h +@@ -0,0 +1,207 @@ ++#ifndef R819XUSB_CMDPKT_H ++#define R819XUSB_CMDPKT_H ++/* Different command packet have dedicated message length and definition. */ ++#define CMPK_RX_TX_FB_SIZE sizeof(cmpk_txfb_t) //20 ++#define CMPK_TX_SET_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16 ++#define CMPK_BOTH_QUERY_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16 ++#define CMPK_RX_TX_STS_SIZE sizeof(cmpk_tx_status_t)// ++#define CMPK_RX_DBG_MSG_SIZE sizeof(cmpk_rx_dbginfo_t)// ++#define CMPK_TX_RAHIS_SIZE sizeof(cmpk_tx_rahis_t) ++ ++/* 2008/05/08 amy For USB constant. */ ++#define ISR_TxBcnOk BIT27 // Transmit Beacon OK ++#define ISR_TxBcnErr BIT26 // Transmit Beacon Error ++#define ISR_BcnTimerIntr BIT13 // Beacon Timer Interrupt ++ ++#if 0 ++/* Define packet type. */ ++typedef enum tag_packet_type ++{ ++ PACKET_BROADCAST, ++ PACKET_MULTICAST, ++ PACKET_UNICAST, ++ PACKET_TYPE_MAX ++}cmpk_pkt_type_e; ++#endif ++ ++/* Define element ID of command packet. */ ++ ++/*------------------------------Define structure----------------------------*/ ++/* Define different command packet structure. */ ++/* 1. RX side: TX feedback packet. */ ++typedef struct tag_cmd_pkt_tx_feedback ++{ ++ // DWORD 0 ++ u8 element_id; /* Command packet type. */ ++ u8 length; /* Command packet length. */ ++ /* 2007/07/05 MH Change tx feedback info field. */ ++ /*------TX Feedback Info Field */ ++ u8 TID:4; /* */ ++ u8 fail_reason:3; /* */ ++ u8 tok:1; /* Transmit ok. */ ++ u8 reserve1:4; /* */ ++ u8 pkt_type:2; /* */ ++ u8 bandwidth:1; /* */ ++ u8 qos_pkt:1; /* */ ++ ++ // DWORD 1 ++ u8 reserve2; /* */ ++ /*------TX Feedback Info Field */ ++ u8 retry_cnt; /* */ ++ u16 pkt_id; /* */ ++ ++ // DWORD 3 ++ u16 seq_num; /* */ ++ u8 s_rate; /* Start rate. */ ++ u8 f_rate; /* Final rate. */ ++ ++ // DWORD 4 ++ u8 s_rts_rate; /* */ ++ u8 f_rts_rate; /* */ ++ u16 pkt_length; /* */ ++ ++ // DWORD 5 ++ u16 reserve3; /* */ ++ u16 duration; /* */ ++}cmpk_txfb_t; ++ ++/* 2. RX side: Interrupt status packet. It includes Beacon State, ++ Beacon Timer Interrupt and other useful informations in MAC ISR Reg. */ ++typedef struct tag_cmd_pkt_interrupt_status ++{ ++ u8 element_id; /* Command packet type. */ ++ u8 length; /* Command packet length. */ ++ u16 reserve; ++ u32 interrupt_status; /* Interrupt Status. */ ++}cmpk_intr_sta_t; ++ ++ ++/* 3. TX side: Set configuration packet. */ ++typedef struct tag_cmd_pkt_set_configuration ++{ ++ u8 element_id; /* Command packet type. */ ++ u8 length; /* Command packet length. */ ++ u16 reserve1; /* */ ++ u8 cfg_reserve1:3; ++ u8 cfg_size:2; /* Configuration info. */ ++ u8 cfg_type:2; /* Configuration info. */ ++ u8 cfg_action:1; /* Configuration info. */ ++ u8 cfg_reserve2; /* Configuration info. */ ++ u8 cfg_page:4; /* Configuration info. */ ++ u8 cfg_reserve3:4; /* Configuration info. */ ++ u8 cfg_offset; /* Configuration info. */ ++ u32 value; /* */ ++ u32 mask; /* */ ++}cmpk_set_cfg_t; ++ ++/* 4. Both side : TX/RX query configuraton packet. The query structure is the ++ same as set configuration. */ ++#define cmpk_query_cfg_t cmpk_set_cfg_t ++ ++/* 5. Multi packet feedback status. */ ++typedef struct tag_tx_stats_feedback // PJ quick rxcmd 09042007 ++{ ++ // For endian transfer --> Driver will not the same as firmware structure. ++ // DW 0 ++ u16 reserve1; ++ u8 length; // Command packet length ++ u8 element_id; // Command packet type ++ ++ // DW 1 ++ u16 txfail; // Tx Fail count ++ u16 txok; // Tx ok count ++ ++ // DW 2 ++ u16 txmcok; // tx multicast ++ u16 txretry; // Tx Retry count ++ ++ // DW 3 ++ u16 txucok; // tx unicast ++ u16 txbcok; // tx broadcast ++ ++ // DW 4 ++ u16 txbcfail; // ++ u16 txmcfail; // ++ ++ // DW 5 ++ u16 reserve2; // ++ u16 txucfail; // ++ ++ // DW 6-8 ++ u32 txmclength; ++ u32 txbclength; ++ u32 txuclength; ++ ++ // DW 9 ++ u16 reserve3_23; ++ u8 reserve3_1; ++ u8 rate; ++}__attribute__((packed)) cmpk_tx_status_t; ++ ++/* 6. Debug feedback message. */ ++/* 2007/10/23 MH Define RX debug message */ ++typedef struct tag_rx_debug_message_feedback ++{ ++ // For endian transfer --> for driver ++ // DW 0 ++ u16 reserve1; ++ u8 length; // Command packet length ++ u8 element_id; // Command packet type ++ ++ // DW 1-?? ++ // Variable debug message. ++ ++}cmpk_rx_dbginfo_t; ++ ++/* 2008/03/20 MH Define transmit rate history. For big endian format. */ ++typedef struct tag_tx_rate_history ++{ ++ // For endian transfer --> for driver ++ // DW 0 ++ u8 element_id; // Command packet type ++ u8 length; // Command packet length ++ u16 reserved1; ++ ++ // DW 1-2 CCK rate counter ++ u16 cck[4]; ++ ++ // DW 3-6 ++ u16 ofdm[8]; ++ ++ // DW 7-14 ++ //UINT16 MCS_BW0_SG0[16]; ++ ++ // DW 15-22 ++ //UINT16 MCS_BW1_SG0[16]; ++ ++ // DW 23-30 ++ //UINT16 MCS_BW0_SG1[16]; ++ ++ // DW 31-38 ++ //UINT16 MCS_BW1_SG1[16]; ++ ++ // DW 7-14 BW=0 SG=0 ++ // DW 15-22 BW=1 SG=0 ++ // DW 23-30 BW=0 SG=1 ++ // DW 31-38 BW=1 SG=1 ++ u16 ht_mcs[4][16]; ++ ++}__attribute__((packed)) cmpk_tx_rahis_t; ++ ++typedef enum tag_command_packet_directories ++{ ++ RX_TX_FEEDBACK = 0, ++ RX_INTERRUPT_STATUS = 1, ++ TX_SET_CONFIG = 2, ++ BOTH_QUERY_CONFIG = 3, ++ RX_TX_STATUS = 4, ++ RX_DBGINFO_FEEDBACK = 5, ++ RX_TX_PER_PKT_FEEDBACK = 6, ++ RX_TX_RATE_HISTORY = 7, ++ RX_CMD_ELE_MAX ++}cmpk_element_e; ++ ++extern u32 cmpk_message_handle_rx(struct net_device *dev, struct ieee80211_rx_stats * pstats); ++ ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_firmware.c +@@ -0,0 +1,620 @@ ++/************************************************************************************************** ++ * Procedure: Init boot code/firmware code/data session ++ * ++ * Description: This routine will intialize firmware. If any error occurs during the initialization ++ * process, the routine shall terminate immediately and return fail. ++ * NIC driver should call NdisOpenFile only from MiniportInitialize. ++ * ++ * Arguments: The pointer of the adapter ++ ++ * Returns: ++ * NDIS_STATUS_FAILURE - the following initialization process should be terminated ++ * NDIS_STATUS_SUCCESS - if firmware initialization process success ++**************************************************************************************************/ ++//#include "ieee80211.h" ++#include "r8192E.h" ++#include "r8192E_hw.h" ++#ifdef RTL8190P ++#include "r819xP_firmware_img.h" ++#else ++#include "r819xE_firmware_img.h" ++#endif ++#include "r819xE_firmware.h" ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++#include ++#endif ++ ++void firmware_init_param(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ rt_firmware *pfirmware = priv->pFirmware; ++ ++ pfirmware->cmdpacket_frag_thresold = GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE); ++} ++ ++/* ++ * segment the img and use the ptr and length to remember info on each segment ++ * ++ */ ++static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, u32 buffer_len) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ bool rt_status = true; ++ u16 frag_threshold; ++ u16 frag_length, frag_offset = 0; ++ //u16 total_size; ++ int i; ++ ++ rt_firmware *pfirmware = priv->pFirmware; ++ struct sk_buff *skb; ++ unsigned char *seg_ptr; ++ cb_desc *tcb_desc; ++ u8 bLastIniPkt; ++ ++ firmware_init_param(dev); ++ //Fragmentation might be required ++ frag_threshold = pfirmware->cmdpacket_frag_thresold; ++ do { ++ if((buffer_len - frag_offset) > frag_threshold) { ++ frag_length = frag_threshold ; ++ bLastIniPkt = 0; ++ ++ } else { ++ frag_length = buffer_len - frag_offset; ++ bLastIniPkt = 1; ++ ++ } ++ ++ /* Allocate skb buffer to contain firmware info and tx descriptor info ++ * add 4 to avoid packet appending overflow. ++ * */ ++ //skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); ++ skb = dev_alloc_skb(frag_length + 4); ++ memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); ++ tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE); ++ tcb_desc->queue_index = TXCMD_QUEUE; ++ tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; ++ tcb_desc->bLastIniPkt = bLastIniPkt; ++ ++ //skb_reserve(skb, USB_HWDESC_HEADER_LEN); ++ seg_ptr = skb->data; ++ /* ++ * Transform from little endian to big endian ++ * and pending zero ++ */ ++ for(i=0 ; i < frag_length; i+=4) { ++ *seg_ptr++ = ((i+0)txbuf_size= (u16)i; ++ skb_put(skb, i); ++ priv->ieee80211->softmac_hard_start_xmit(skb,dev); ++ ++ code_virtual_address += frag_length; ++ frag_offset += frag_length; ++ ++ }while(frag_offset < buffer_len); ++ ++ return rt_status; ++ ++#if 0 ++cmdsend_downloadcode_fail: ++ rt_status = false; ++ RT_TRACE(COMP_ERR, "CmdSendDownloadCode fail !!\n"); ++ return rt_status; ++#endif ++} ++ ++//----------------------------------------------------------------------------- ++// Procedure: Check whether main code is download OK. If OK, turn on CPU ++// ++// Description: CPU register locates in different page against general register. ++// Switch to CPU register in the begin and switch back before return ++// ++// ++// Arguments: The pointer of the adapter ++// ++// Returns: ++// NDIS_STATUS_FAILURE - the following initialization process should be terminated ++// NDIS_STATUS_SUCCESS - if firmware initialization process success ++//----------------------------------------------------------------------------- ++static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) ++{ ++ bool rt_status = true; ++ int check_putcodeOK_time = 200000, check_bootOk_time = 200000; ++ u32 CPU_status = 0; ++ ++ /* Check whether put code OK */ ++ do { ++ CPU_status = read_nic_dword(dev, CPU_GEN); ++ ++ if(CPU_status&CPU_GEN_PUT_CODE_OK) ++ break; ++ ++ }while(check_putcodeOK_time--); ++ ++ if(!(CPU_status&CPU_GEN_PUT_CODE_OK)) { ++ RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n"); ++ goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; ++ } else { ++ RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); ++ } ++ ++ /* Turn On CPU */ ++ CPU_status = read_nic_dword(dev, CPU_GEN); ++ write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); ++ mdelay(1); ++ ++ /* Check whether CPU boot OK */ ++ do { ++ CPU_status = read_nic_dword(dev, CPU_GEN); ++ ++ if(CPU_status&CPU_GEN_BOOT_RDY) ++ break; ++ }while(check_bootOk_time--); ++ ++ if(!(CPU_status&CPU_GEN_BOOT_RDY)) { ++ goto CPUCheckMainCodeOKAndTurnOnCPU_Fail; ++ } else { ++ RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n"); ++ } ++ ++ return rt_status; ++ ++CPUCheckMainCodeOKAndTurnOnCPU_Fail: ++ RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); ++ rt_status = FALSE; ++ return rt_status; ++} ++ ++static bool CPUcheck_firmware_ready(struct net_device *dev) ++{ ++ ++ bool rt_status = true; ++ int check_time = 200000; ++ u32 CPU_status = 0; ++ ++ /* Check Firmware Ready */ ++ do { ++ CPU_status = read_nic_dword(dev, CPU_GEN); ++ ++ if(CPU_status&CPU_GEN_FIRM_RDY) ++ break; ++ ++ }while(check_time--); ++ ++ if(!(CPU_status&CPU_GEN_FIRM_RDY)) ++ goto CPUCheckFirmwareReady_Fail; ++ else ++ RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n"); ++ ++ return rt_status; ++ ++CPUCheckFirmwareReady_Fail: ++ RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); ++ rt_status = false; ++ return rt_status; ++ ++} ++ ++bool init_firmware(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ bool rt_status = TRUE; ++ ++#ifdef RTL8190P ++ u8 *firmware_img_buf[3] = { &rtl8190_fwboot_array[0], ++ &rtl8190_fwmain_array[0], ++ &rtl8190_fwdata_array[0]}; ++ ++ u32 firmware_img_len[3] = { sizeof(rtl8190_fwboot_array), ++ sizeof(rtl8190_fwmain_array), ++ sizeof(rtl8190_fwdata_array)}; ++#else ++ u8 *firmware_img_buf[3] = { &rtl8192e_fwboot_array[0], ++ &rtl8192e_fwmain_array[0], ++ &rtl8192e_fwdata_array[0]}; ++ ++ u32 firmware_img_len[3] = { sizeof(rtl8192e_fwboot_array), ++ sizeof(rtl8192e_fwmain_array), ++ sizeof(rtl8192e_fwdata_array)}; ++#endif ++ u32 file_length = 0; ++ u8 *mapped_file = NULL; ++ u32 init_step = 0; ++ opt_rst_type_e rst_opt = OPT_SYSTEM_RESET; ++ firmware_init_step_e starting_state = FW_INIT_STEP0_BOOT; ++ ++ rt_firmware *pfirmware = priv->pFirmware; ++ const struct firmware *fw_entry; ++#ifdef RTL8190P ++ const char *fw_name[3] = { "RTL8190P/boot.img", ++ "RTL8190P/main.img", ++ "RTL8190P/data.img"}; ++#endif ++#ifdef RTL8192E ++ const char *fw_name[3] = { "RTL8192E/boot.img", ++ "RTL8192E/main.img", ++ "RTL8192E/data.img"}; ++#endif ++ int rc; ++ ++ RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n"); ++ ++ if (pfirmware->firmware_status == FW_STATUS_0_INIT ) { ++ /* it is called by reset */ ++ rst_opt = OPT_SYSTEM_RESET; ++ starting_state = FW_INIT_STEP0_BOOT; ++ // TODO: system reset ++ ++ }else if(pfirmware->firmware_status == FW_STATUS_5_READY) { ++ /* it is called by Initialize */ ++ rst_opt = OPT_FIRMWARE_RESET; ++ starting_state = FW_INIT_STEP2_DATA; ++ }else { ++ RT_TRACE(COMP_FIRMWARE, "PlatformInitFirmware: undefined firmware state\n"); ++ } ++ ++ /* ++ * Download boot, main, and data image for System reset. ++ * Download data image for firmware reseta ++ */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ priv->firmware_source = FW_SOURCE_HEADER_FILE; ++#else ++ priv->firmware_source = FW_SOURCE_IMG_FILE; ++#endif ++ for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) { ++ /* ++ * Open Image file, and map file to contineous memory if open file success. ++ * or read image file from array. Default load from IMG file ++ */ ++ if(rst_opt == OPT_SYSTEM_RESET) { ++ switch(priv->firmware_source) { ++ case FW_SOURCE_IMG_FILE: ++ { ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ if(pfirmware->firmware_buf_size[init_step] == 0) { ++ rc = request_firmware(&fw_entry, fw_name[init_step],&priv->pdev->dev); ++ if(rc < 0 ) { ++ RT_TRACE(COMP_FIRMWARE, "request firmware fail!\n"); ++ goto download_firmware_fail; ++ } ++ ++ if(fw_entry->size > sizeof(pfirmware->firmware_buf[init_step])) { ++ RT_TRACE(COMP_FIRMWARE, "img file size exceed the container buffer fail!\n"); ++ goto download_firmware_fail; ++ } ++ ++ if(init_step != FW_INIT_STEP1_MAIN) { ++ memcpy(pfirmware->firmware_buf[init_step],fw_entry->data,fw_entry->size); ++ pfirmware->firmware_buf_size[init_step] = fw_entry->size; ++ ++ } else { ++#ifdef RTL8190P ++ memcpy(pfirmware->firmware_buf[init_step],fw_entry->data,fw_entry->size); ++ pfirmware->firmware_buf_size[init_step] = fw_entry->size; ++ ++#else ++ memset(pfirmware->firmware_buf[init_step],0,128); ++ memcpy(&pfirmware->firmware_buf[init_step][128],fw_entry->data,fw_entry->size); ++ //mapped_file = pfirmware->firmware_buf[init_step]; ++ pfirmware->firmware_buf_size[init_step] = fw_entry->size+128; ++ //file_length = fw_entry->size + 128; ++#endif ++ } ++ //pfirmware->firmware_buf_size = file_length; ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ if(rst_opt == OPT_SYSTEM_RESET) { ++ release_firmware(fw_entry); ++ } ++#endif ++ } ++ mapped_file = pfirmware->firmware_buf[init_step]; ++ file_length = pfirmware->firmware_buf_size[init_step]; ++#endif ++ break; ++ } ++ case FW_SOURCE_HEADER_FILE: ++ mapped_file = firmware_img_buf[init_step]; ++ file_length = firmware_img_len[init_step]; ++ if(init_step == FW_INIT_STEP2_DATA) { ++ memcpy(pfirmware->firmware_buf[init_step], mapped_file, file_length); ++ pfirmware->firmware_buf_size[init_step] = file_length; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ }else if(rst_opt == OPT_FIRMWARE_RESET ) { ++ /* we only need to download data.img here */ ++ mapped_file = pfirmware->firmware_buf[init_step]; ++ file_length = pfirmware->firmware_buf_size[init_step]; ++ } ++ ++ /* Download image file */ ++ /* The firmware download process is just as following, ++ * 1. that is each packet will be segmented and inserted to the wait queue. ++ * 2. each packet segment will be put in the skb_buff packet. ++ * 3. each skb_buff packet data content will already include the firmware info ++ * and Tx descriptor info ++ * */ ++ rt_status = fw_download_code(dev,mapped_file,file_length); ++ if(rt_status != TRUE) { ++ goto download_firmware_fail; ++ } ++ ++ switch(init_step) { ++ case FW_INIT_STEP0_BOOT: ++ /* Download boot ++ * initialize command descriptor. ++ * will set polling bit when firmware code is also configured ++ */ ++ pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE; ++ //mdelay(1000); ++ /* ++ * To initialize IMEM, CPU move code from 0x80000080, ++ * hence, we send 0x80 byte packet ++ */ ++ break; ++ ++ case FW_INIT_STEP1_MAIN: ++ /* Download firmware code. Wait until Boot Ready and Turn on CPU */ ++ pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE; ++ ++ /* Check Put Code OK and Turn On CPU */ ++ rt_status = CPUcheck_maincodeok_turnonCPU(dev); ++ if(rt_status != TRUE) { ++ RT_TRACE(COMP_FIRMWARE, "CPUcheck_maincodeok_turnonCPU fail!\n"); ++ goto download_firmware_fail; ++ } ++ ++ pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU; ++ break; ++ ++ case FW_INIT_STEP2_DATA: ++ /* download initial data code */ ++ pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE; ++ mdelay(1); ++ ++ rt_status = CPUcheck_firmware_ready(dev); ++ if(rt_status != TRUE) { ++ RT_TRACE(COMP_FIRMWARE, "CPUcheck_firmware_ready fail(%d)!\n",rt_status); ++ goto download_firmware_fail; ++ } ++ ++ /* wait until data code is initialized ready.*/ ++ pfirmware->firmware_status = FW_STATUS_5_READY; ++ break; ++ } ++ } ++ ++ RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n"); ++ //assert(pfirmware->firmware_status == FW_STATUS_5_READY, ("Firmware Download Fail\n")); ++ ++ return rt_status; ++ ++download_firmware_fail: ++ RT_TRACE(COMP_ERR, "ERR in %s()\n", __FUNCTION__); ++ rt_status = FALSE; ++ return rt_status; ++ ++} ++ ++#if 0 ++/* ++ * Procedure: (1) Transform firmware code from little endian to big endian if required. ++ * (2) Number of bytes in Firmware downloading should be multiple ++ * of 4 bytes. If length is not multiple of 4 bytes, appending of zeros is required ++ * ++ */ ++void CmdAppendZeroAndEndianTransform( ++ u1Byte *pDst, ++ u1Byte *pSrc, ++ u2Byte *pLength) ++{ ++ ++ u2Byte ulAppendBytes = 0, i; ++ u2Byte ulLength = *pLength; ++ ++//test only ++ //memset(pDst, 0xcc, 12); ++ ++ ++ /* Transform from little endian to big endian */ ++//#if DEV_BUS_TYPE==PCI_INTERFACE ++#if 0 ++ for( i=0 ; i<(*pLength) ; i+=4) ++ { ++ if((i+3) < (*pLength)) pDst[i+0] = pSrc[i+3]; ++ if((i+2) < (*pLength)) pDst[i+1] = pSrc[i+2]; ++ if((i+1) < (*pLength)) pDst[i+2] = pSrc[i+1]; ++ if((i+0) < (*pLength)) pDst[i+3] = pSrc[i+0]; ++ } ++#else ++ pDst += USB_HWDESC_HEADER_LEN; ++ ulLength -= USB_HWDESC_HEADER_LEN; ++ ++ for( i=0 ; i0) ++ { ++ ulAppendBytes = 4-((*pLength) % 4); ++ ++ for(i=0 ; iFragLength[0] = (u2Byte)pTcb->BufferList[0].Length; ++ ++ QueueID=pTcb->SpecifiedQueueID; ++#if DEV_BUS_TYPE!=USB_INTERFACE ++ firstDesc=curDesc=Adapter->NextTxDescToFill[QueueID]; ++#endif ++ ++#if DEV_BUS_TYPE!=USB_INTERFACE ++ if(VacancyTxDescNum(Adapter, QueueID) > pTcb->BufferCount) ++#else ++ if(PlatformIsTxQueueAvailable(Adapter, QueueID, pTcb->BufferCount) && ++ RTIsListEmpty(&Adapter->TcbWaitQueue[QueueID])) ++#endif ++ { ++ pTcb->nDescUsed=0; ++ ++ for(i=0 ; iBufferCount ; i++) ++ { ++ Adapter->HalFunc.TxFillCmdDescHandler( ++ Adapter, ++ pTcb, ++ QueueID, //QueueIndex ++ curDesc, //index ++ FragBufferIndex==0, //bFirstSeg ++ FragBufferIndex==(pTcb->FragBufCount[FragIndex]-1), //bLastSeg ++ pTcb->BufferList[i].VirtualAddress, //VirtualAddress ++ pTcb->BufferList[i].PhysicalAddressLow, //PhyAddressLow ++ pTcb->BufferList[i].Length, //BufferLen ++ i!=0, //bSetOwnBit ++ (i==(pTcb->BufferCount-1)) && bLastInitPacket, //bLastInitPacket ++ PacketType, //DescPacketType ++ pTcb->FragLength[FragIndex] //PktLen ++ ); ++ ++ if(FragBufferIndex==(pTcb->FragBufCount[FragIndex]-1)) ++ { // Last segment of the fragment. ++ pTcb->nFragSent++; ++ } ++ ++ FragBufferIndex++; ++ if(FragBufferIndex==pTcb->FragBufCount[FragIndex]) ++ { ++ FragIndex++; ++ FragBufferIndex=0; ++ } ++ ++#if DEV_BUS_TYPE!=USB_INTERFACE ++ curDesc=(curDesc+1)%Adapter->NumTxDesc[QueueID]; ++#endif ++ pTcb->nDescUsed++; ++ } ++ ++#if DEV_BUS_TYPE!=USB_INTERFACE ++ RTInsertTailList(&Adapter->TcbBusyQueue[QueueID], &pTcb->List); ++ IncrementTxDescToFill(Adapter, QueueID, pTcb->nDescUsed); ++ Adapter->HalFunc.SetTxDescOWNHandler(Adapter, QueueID, firstDesc); ++ // TODO: should call poll use QueueID ++ Adapter->HalFunc.TxPollingHandler(Adapter, TXCMD_QUEUE); ++#endif ++ } ++ else ++#if DEV_BUS_TYPE!=USB_INTERFACE ++ goto CmdSendPacket_Fail; ++#else ++ { ++ pTcb->bLastInitPacket = bLastInitPacket; ++ RTInsertTailList(&Adapter->TcbWaitQueue[pTcb->SpecifiedQueueID], &pTcb->List); ++ } ++#endif ++ ++ return rtStatus; ++ ++#if DEV_BUS_TYPE!=USB_INTERFACE ++CmdSendPacket_Fail: ++ rtStatus = RT_STATUS_FAILURE; ++ return rtStatus; ++#endif ++ ++} ++#endif ++ ++ ++ ++ ++#if 0 ++RT_STATUS ++FWSendNullPacket( ++ IN PADAPTER Adapter, ++ IN u4Byte Length ++) ++{ ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ ++ ++ PRT_TCB pTcb; ++ PRT_TX_LOCAL_BUFFER pBuf; ++ BOOLEAN bLastInitPacket = FALSE; ++ ++ PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK); ++ ++#if DEV_BUS_TYPE==USB_INTERFACE ++ Length += USB_HWDESC_HEADER_LEN; ++#endif ++ ++ //Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) ++ if(MgntGetBuffer(Adapter, &pTcb, &pBuf)) ++ { ++ PlatformZeroMemory(pBuf->Buffer.VirtualAddress, Length); ++ rtStatus = CmdSendPacket(Adapter, pTcb, pBuf, Length, DESC_PACKET_TYPE_INIT, bLastInitPacket); //0 : always set LastInitPacket to zero ++//#if HAL_CODE_BASE != RTL8190HW ++// // TODO: for test only ++// ReturnTCB(Adapter, pTcb, RT_STATUS_SUCCESS); ++//#endif ++ if(rtStatus == RT_STATUS_FAILURE) ++ goto CmdSendNullPacket_Fail; ++ }else ++ goto CmdSendNullPacket_Fail; ++ ++ PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); ++ return rtStatus; ++ ++ ++CmdSendNullPacket_Fail: ++ PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK); ++ rtStatus = RT_STATUS_FAILURE; ++ RT_ASSERT(rtStatus == RT_STATUS_SUCCESS, ("CmdSendDownloadCode fail !!\n")); ++ return rtStatus; ++} ++#endif ++ ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_firmware.h +@@ -0,0 +1,68 @@ ++#ifndef __INC_FIRMWARE_H ++#define __INC_FIRMWARE_H ++ ++#define RTL8190_CPU_START_OFFSET 0x80 ++/* TODO: this definition is TBD */ ++//#define USB_HWDESC_HEADER_LEN 0 ++ ++/* It should be double word alignment */ ++//#if DEV_BUS_TYPE==PCI_INTERFACE ++//#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) 4*(v/4) - 8 ++//#else ++#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8 ) ++//#endif ++ ++typedef enum _firmware_init_step{ ++ FW_INIT_STEP0_BOOT = 0, ++ FW_INIT_STEP1_MAIN = 1, ++ FW_INIT_STEP2_DATA = 2, ++}firmware_init_step_e; ++ ++typedef enum _opt_rst_type{ ++ OPT_SYSTEM_RESET = 0, ++ OPT_FIRMWARE_RESET = 1, ++}opt_rst_type_e; ++ ++#if 0 ++/* CPU related */ ++RT_STATUS ++CPUCheckMainCodeOKAndTurnOnCPU( ++ IN PADAPTER Adapter ++ ); ++ ++RT_STATUS ++CPUCheckFirmwareReady( ++ IN PADAPTER Adapter ++ ); ++ ++/* Firmware related */ ++VOID ++FWInitializeParameters( ++ IN PADAPTER Adapter ++ ); ++ ++RT_STATUS ++FWSendDownloadCode( ++ IN PADAPTER Adapter, ++ IN pu1Byte CodeVirtualAddrress, ++ IN u4Byte BufferLen ++ ); ++ ++RT_STATUS ++FWSendNullPacket( ++ IN PADAPTER Adapter, ++ IN u4Byte Length ++ ); ++ ++RT_STATUS ++CmdSendPacket( ++ PADAPTER Adapter, ++ PRT_TCB pTcb, ++ PRT_TX_LOCAL_BUFFER pBuf, ++ u4Byte BufferLen, ++ u4Byte PacketType, ++ BOOLEAN bLastInitPacket ++ ); ++#endif ++#endif ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_firmware_img.h +@@ -0,0 +1,2778 @@ ++#ifndef __INC_R819XE_FIRMWARE_IMG_H ++#define __INC_R819XE_FIRMWARE_IMG_H ++ ++/*Created on 2008/ 8/28, 11:46*/ ++#include ++ ++static u8 rtl8192e_fwboot_array[] = { ++0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x08,0xbf,0xc0,0x25,0x08,0x00,0x08, ++0x3c,0x09,0xb0,0x03,0xad,0x28,0x00,0x20,0x40,0x80,0x68,0x00,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0xd0,0x00,0x40,0x8a,0x60,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, ++0x25,0x08,0xa8,0x04,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff, ++0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01,0x01,0x2a,0x10,0x2b, ++0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x00,0x00,0x25,0x4a,0x00,0x00, ++0x4c,0x8a,0x00,0x00,0x4c,0x89,0x08,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, ++0x25,0x08,0xa8,0x04,0x3c,0x01,0x80,0x00,0x01,0x21,0x48,0x25,0x3c,0x0a,0xbf,0xc0, ++0x25,0x4a,0x00,0x7c,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0xad,0x00,0x00,0x00, ++0x21,0x08,0x00,0x04,0x01,0x09,0x10,0x2b,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00, ++0x3c,0x08,0x80,0x01,0x25,0x08,0x7f,0xff,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff, ++0x34,0x21,0xff,0xff,0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01, ++0x01,0x2a,0x10,0x2b,0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x01, ++0x25,0x4a,0x00,0x00,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff,0x01,0x41,0x50,0x24, ++0x3c,0x09,0x00,0x01,0x35,0x29,0x7f,0xff,0x4c,0x8a,0x20,0x00,0x4c,0x89,0x28,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x08,0x04,0x10, ++0x00,0x00,0x00,0x00,0x40,0x88,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x3c,0x08,0xbf,0xc0,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0xbf,0xc0,0x25,0x4a,0x01,0x20,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, ++0x3c,0x08,0xb0,0x03,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x29,0x00,0x10, ++0xad,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x00,0x25,0x08,0x4b,0x94, ++0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,}; ++ ++static u8 rtl8192e_fwmain_array[] = { ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x40,0x04,0x68,0x00,0x40,0x05,0x70,0x00,0x40,0x06,0x40,0x00,0x0c,0x00,0x12,0x98, ++0x00,0x00,0x00,0x00,0x40,0x1a,0x68,0x00,0x33,0x5b,0x00,0x3c,0x17,0x60,0x00,0x09, ++0x00,0x00,0x00,0x00,0x40,0x1b,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0x5b,0xd0,0x24, ++0x40,0x1a,0x70,0x00,0x03,0x40,0x00,0x08,0x42,0x00,0x00,0x10,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0xff,0xff,0x8c,0x43,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x00,0xd0, ++0xac,0x62,0x00,0x00,0x00,0x00,0x20,0x21,0x27,0x85,0x8b,0x70,0x00,0x85,0x18,0x21, ++0x24,0x84,0x00,0x01,0x28,0x82,0x00,0x0a,0x14,0x40,0xff,0xfc,0xa0,0x60,0x00,0x00, ++0x27,0x82,0x8b,0x7a,0x24,0x04,0x00,0x06,0x24,0x84,0xff,0xff,0xa4,0x40,0x00,0x00, ++0x04,0x81,0xff,0xfd,0x24,0x42,0x00,0x02,0x24,0x02,0x00,0x03,0xa3,0x82,0x8b,0x70, ++0x24,0x02,0x00,0x0a,0x24,0x03,0x09,0xc4,0xa3,0x82,0x8b,0x72,0x24,0x02,0x00,0x04, ++0x24,0x04,0x00,0x01,0x24,0x05,0x00,0x02,0xa7,0x83,0x8b,0x86,0xa3,0x82,0x8b,0x78, ++0x24,0x03,0x04,0x00,0x24,0x02,0x02,0x00,0xaf,0x83,0x8b,0x8c,0xa3,0x85,0x8b,0x79, ++0xa7,0x82,0x8b,0x7a,0xa7,0x84,0x8b,0x7c,0xaf,0x84,0x8b,0x88,0xa3,0x84,0x8b,0x71, ++0xa3,0x80,0x8b,0x73,0xa3,0x80,0x8b,0x74,0xa3,0x80,0x8b,0x75,0xa3,0x84,0x8b,0x76, ++0xa3,0x85,0x8b,0x77,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x24,0x42,0x01,0x7c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, ++0x27,0x84,0x8b,0x98,0x00,0x00,0x10,0x21,0x24,0x42,0x00,0x01,0x00,0x02,0x16,0x00, ++0x00,0x02,0x16,0x03,0x28,0x43,0x00,0x03,0xac,0x80,0xff,0xfc,0xa0,0x80,0x00,0x00, ++0x14,0x60,0xff,0xf9,0x24,0x84,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x01,0xc0, ++0x3c,0x08,0xb0,0x03,0xac,0x62,0x00,0x00,0x35,0x08,0x00,0x70,0x8d,0x02,0x00,0x00, ++0x00,0xa0,0x48,0x21,0x00,0x04,0x26,0x00,0x00,0x02,0x2a,0x43,0x00,0x06,0x36,0x00, ++0x00,0x07,0x3e,0x00,0x00,0x02,0x12,0x03,0x29,0x23,0x00,0x03,0x00,0x04,0x56,0x03, ++0x00,0x06,0x36,0x03,0x00,0x07,0x3e,0x03,0x30,0x48,0x00,0x01,0x10,0x60,0x00,0x11, ++0x30,0xa5,0x00,0x07,0x24,0x02,0x00,0x02,0x00,0x49,0x10,0x23,0x00,0x45,0x10,0x07, ++0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x66,0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x10, ++0x00,0x00,0x00,0x00,0x00,0x02,0x21,0x43,0x11,0x00,0x00,0x10,0x00,0x07,0x20,0x0b, ++0x15,0x20,0x00,0x06,0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x05,0x34,0x42,0x01,0x20, ++0xa4,0x44,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x11,0x22,0x00,0x04, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x24, ++0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x22,0x15,0x20,0x00,0x54, ++0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x74,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0x94,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x70, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x6b,0x00,0x08,0x11,0x60,0x00,0x18, ++0x00,0x09,0x28,0x40,0x00,0x00,0x40,0x21,0x27,0x85,0x8b,0x90,0x8c,0xa3,0x00,0x00, ++0x8c,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x62,0x38,0x23,0x00,0x43,0x10,0x2a, ++0x10,0x40,0x00,0x3d,0x00,0x00,0x00,0x00,0xac,0xa7,0x00,0x00,0x25,0x02,0x00,0x01, ++0x00,0x02,0x16,0x00,0x00,0x02,0x46,0x03,0x29,0x03,0x00,0x03,0x14,0x60,0xff,0xf3, ++0x24,0xa5,0x00,0x0c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x70,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x4b,0x10,0x23,0xa0,0x62,0x00,0x00,0x00,0x09,0x28,0x40, ++0x00,0xa9,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x8b,0x98,0x00,0x0a,0x20,0x0b, ++0x00,0x43,0x18,0x21,0x10,0xc0,0x00,0x05,0x00,0x00,0x38,0x21,0x80,0x62,0x00,0x01, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x80,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0xa9,0x10,0x21,0x24,0x07,0x00,0x01, ++0x00,0xa9,0x10,0x21,0x00,0x02,0x30,0x80,0x27,0x82,0x8b,0x98,0xa0,0x67,0x00,0x01, ++0x00,0xc2,0x38,0x21,0x80,0xe3,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x07, ++0x00,0x00,0x00,0x00,0x27,0x83,0x8b,0x90,0x00,0xc3,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x21,0xac,0x62,0x00,0x00,0x27,0x85,0x8b,0x94, ++0x27,0x82,0x8b,0x90,0x00,0xc5,0x28,0x21,0x00,0xc2,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x8c,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x2a,0x14,0x60,0x00,0x03, ++0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xe2,0x00,0x00,0xa0,0xe0,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xb7,0xac,0xa0,0x00,0x00, ++0x11,0x22,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x7c, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0xac,0x08,0x00,0x00,0xa7, ++0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x78,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0xaf,0x83,0x8b,0xa0,0x08,0x00,0x00,0xa7,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x04,0x10, ++0x3c,0x05,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0xa5,0x00,0x70,0x8c,0xa2,0x00,0x00, ++0x90,0x84,0x00,0x08,0x3c,0x06,0xb0,0x03,0x00,0x02,0x16,0x00,0x2c,0x83,0x00,0x03, ++0x34,0xc6,0x00,0x72,0x24,0x07,0x00,0x01,0x10,0x60,0x00,0x11,0x00,0x02,0x2f,0xc2, ++0x90,0xc2,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x02,0x16,0x00,0x10,0xa7,0x00,0x09, ++0x00,0x02,0x16,0x03,0x14,0x80,0x00,0x0c,0x30,0x43,0x00,0x03,0x83,0x82,0x8b,0x98, ++0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x16,0x00, ++0x00,0x02,0x1e,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x72,0xa0,0x43,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x45,0x00,0x05,0x10,0x87,0x00,0x04, ++0x30,0x43,0x00,0x06,0x93,0x82,0x8b,0xb0,0x08,0x00,0x01,0x1f,0x00,0x43,0x10,0x21, ++0x83,0x82,0x8b,0xa4,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x40,0x08,0x00,0x01,0x1f, ++0x00,0x45,0x10,0x21,0x10,0x80,0x00,0x05,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01, ++0x00,0x64,0x10,0x2b,0x14,0x40,0xff,0xfd,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x04,0xe4, ++0x3c,0x04,0xb0,0x02,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x08, ++0x24,0x02,0x00,0x01,0xaf,0x84,0x8b,0xc0,0xa3,0x82,0x8b,0xd0,0xa7,0x80,0x8b,0xc4, ++0xa7,0x80,0x8b,0xc6,0xaf,0x80,0x8b,0xc8,0xaf,0x80,0x8b,0xcc,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, ++0x24,0x42,0x05,0x24,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0xac, ++0x80,0xa2,0x00,0x15,0x8c,0x83,0x00,0x00,0x27,0xbd,0xff,0xf0,0x00,0x43,0x10,0x21, ++0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x10,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20,0x24,0x63,0x05,0x5c,0x27,0xbd,0xff,0xe0, ++0xac,0x43,0x00,0x00,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, ++0x8f,0x90,0x8b,0xc0,0x0c,0x00,0x02,0x98,0x00,0x80,0x88,0x21,0x14,0x40,0x00,0x2a, ++0x3c,0x02,0x00,0x80,0x16,0x20,0x00,0x02,0x34,0x42,0x02,0x01,0x24,0x02,0x02,0x01, ++0xae,0x02,0x00,0x00,0x97,0x84,0x8b,0xc4,0x97,0x82,0x8b,0xc6,0x3c,0x03,0xb0,0x02, ++0x00,0x83,0x20,0x21,0x24,0x42,0x00,0x04,0xa7,0x82,0x8b,0xc6,0xa4,0x82,0x00,0x00, ++0x8f,0x84,0x8b,0xc8,0x8f,0x82,0x8b,0xc0,0x93,0x85,0x8b,0x72,0x24,0x84,0x00,0x01, ++0x24,0x42,0x00,0x04,0x24,0x03,0x8f,0xff,0x3c,0x07,0xb0,0x06,0x3c,0x06,0xb0,0x03, ++0x00,0x43,0x10,0x24,0x00,0x85,0x28,0x2a,0x34,0xe7,0x80,0x18,0xaf,0x82,0x8b,0xc0, ++0xaf,0x84,0x8b,0xc8,0x10,0xa0,0x00,0x08,0x34,0xc6,0x01,0x08,0x8f,0x83,0x8b,0xcc, ++0x8f,0x84,0x8b,0x8c,0x8c,0xc2,0x00,0x00,0x00,0x64,0x18,0x21,0x00,0x43,0x10,0x2b, ++0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x8c,0xe2,0x00,0x00,0x3c,0x03,0x0f,0x00, ++0x3c,0x04,0x04,0x00,0x00,0x43,0x10,0x24,0x10,0x44,0x00,0x03,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x00,0x24,0x63,0x06,0x48,0xaf,0xb0,0x00,0x10,0x34,0x42,0x00,0x20, ++0x8f,0x90,0x8b,0xc0,0xac,0x43,0x00,0x00,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0x00,0x80,0x88,0x21,0x00,0xa0,0x90,0x21, ++0x0c,0x00,0x02,0x98,0x00,0xc0,0x98,0x21,0x24,0x07,0x8f,0xff,0x14,0x40,0x00,0x19, ++0x26,0x03,0x00,0x04,0x24,0x02,0x0e,0x03,0xae,0x02,0x00,0x00,0x00,0x67,0x80,0x24, ++0x26,0x02,0x00,0x04,0xae,0x11,0x00,0x00,0x00,0x47,0x80,0x24,0x97,0x86,0x8b,0xc4, ++0x26,0x03,0x00,0x04,0xae,0x12,0x00,0x00,0x00,0x67,0x80,0x24,0xae,0x13,0x00,0x00, ++0x8f,0x84,0x8b,0xc0,0x3c,0x02,0xb0,0x02,0x97,0x85,0x8b,0xc6,0x00,0xc2,0x30,0x21, ++0x8f,0x82,0x8b,0xc8,0x24,0x84,0x00,0x10,0x24,0xa5,0x00,0x10,0x00,0x87,0x20,0x24, ++0x24,0x42,0x00,0x01,0xa7,0x85,0x8b,0xc6,0xaf,0x84,0x8b,0xc0,0xaf,0x82,0x8b,0xc8, ++0xa4,0xc5,0x00,0x00,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, ++0x94,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0xe0,0x00,0x14,0x40,0x00,0x14, ++0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x02,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfc, ++0x00,0x82,0x28,0x21,0x8c,0xa4,0x00,0x00,0x3c,0x02,0x00,0x70,0x8c,0xa6,0x00,0x08, ++0x00,0x82,0x10,0x21,0x2c,0x43,0x00,0x06,0x10,0x60,0x00,0x09,0x3c,0x03,0x80,0x01, ++0x00,0x02,0x10,0x80,0x24,0x63,0x01,0xe8,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0xaf,0x86,0x80,0x14, ++0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x8c,0xa4,0x00,0x00,0x0c,0x00,0x17,0x84,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0xdc, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x24,0x49,0x00,0xc0,0x20,0x21,0x08,0x00,0x01,0xdc, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00, ++0x8f,0x82,0x80,0x18,0x3c,0x03,0x00,0x0f,0x34,0x63,0x42,0x40,0x00,0x43,0x10,0x21, ++0x00,0x82,0x20,0x2b,0x10,0x80,0x00,0x09,0x24,0x03,0x00,0x05,0x8f,0x82,0x83,0x60, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x83,0x60,0x10,0x43,0x00,0x03, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x8c,0x63,0x01,0x08,0x24,0x02,0x00,0x01,0xa3,0x82,0x80,0x11,0xaf,0x80,0x83,0x60, ++0xaf,0x83,0x80,0x18,0x08,0x00,0x01,0xf9,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xff, ++0x14,0x80,0x00,0x2f,0x00,0x00,0x00,0x00,0x8f,0x82,0x80,0x14,0xa3,0x85,0x83,0x93, ++0x10,0x40,0x00,0x2b,0x2c,0xa2,0x00,0x04,0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40, ++0x24,0xa2,0xff,0xfc,0x2c,0x42,0x00,0x08,0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xf0, ++0x00,0x05,0x10,0x40,0x27,0x84,0x83,0x9c,0x00,0x44,0x10,0x21,0x94,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0xa4,0x43,0x00,0x00, ++0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x0a,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xe0, ++0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xd0, ++0x2c,0x42,0x00,0x10,0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xc0,0x00,0x05,0x10,0x40, ++0x27,0x84,0x83,0x9c,0x00,0x44,0x10,0x21,0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00, ++0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0xa4,0x43,0xff,0xf8,0x2c,0x42,0x00,0x10, ++0x10,0x40,0x00,0x07,0x00,0x05,0x10,0x40,0x27,0x84,0x83,0x9c,0x00,0x44,0x10,0x21, ++0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0xa4,0x43,0xff,0xf8, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0x86,0x8b,0xc0,0x8f,0x82,0x80,0x14, ++0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x10,0x40,0x00,0x2a,0x00,0xc0,0x38,0x21, ++0x24,0x02,0x00,0x07,0x24,0x03,0xff,0x9c,0xa3,0x82,0x83,0x9b,0xa3,0x83,0x83,0x9a, ++0x27,0x8a,0x83,0x98,0x00,0x00,0x20,0x21,0x24,0x09,0x8f,0xff,0x00,0x04,0x10,0x80, ++0x00,0x4a,0x28,0x21,0x8c,0xa2,0x00,0x00,0x24,0xe3,0x00,0x04,0x24,0x88,0x00,0x01, ++0xac,0xe2,0x00,0x00,0x10,0x80,0x00,0x02,0x00,0x69,0x38,0x24,0xac,0xa0,0x00,0x00, ++0x31,0x04,0x00,0xff,0x2c,0x82,0x00,0x27,0x14,0x40,0xff,0xf5,0x00,0x04,0x10,0x80, ++0x97,0x83,0x8b,0xc6,0x97,0x85,0x8b,0xc4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x9c, ++0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18, ++0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x9c, ++0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00, ++0xaf,0x86,0x8b,0xc0,0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96, ++0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x8f,0x86,0x8b,0xc0,0x27,0xbd,0xff,0xc8,0x24,0x02,0x00,0x08, ++0x24,0x03,0x00,0x20,0xaf,0xbf,0x00,0x30,0xa3,0xa2,0x00,0x13,0xa3,0xa3,0x00,0x12, ++0xa7,0xa4,0x00,0x10,0x00,0xc0,0x28,0x21,0x27,0xa9,0x00,0x10,0x00,0x00,0x38,0x21, ++0x24,0x08,0x8f,0xff,0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff,0x24,0xa2,0x00,0x04,0x2c,0xe3,0x00,0x08, ++0xac,0xa4,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x48,0x28,0x24,0x97,0x83,0x8b,0xc6, ++0x97,0x85,0x8b,0xc4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x20,0x00,0xa2,0x28,0x21, ++0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, ++0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x20,0x3c,0x03,0x0f,0x00, ++0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xc0, ++0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x30,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38, ++0x93,0x82,0x8b,0xd0,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11,0x24,0x06,0x00,0x01, ++0x8f,0x82,0x8b,0xc8,0x3c,0x05,0xb0,0x06,0x3c,0x04,0xb0,0x03,0x34,0xa5,0x80,0x18, ++0x34,0x84,0x01,0x08,0x14,0x40,0x00,0x09,0x00,0x00,0x30,0x21,0x97,0x82,0x8b,0xc4, ++0x8c,0x84,0x00,0x00,0x3c,0x03,0xb0,0x02,0x00,0x43,0x10,0x21,0xaf,0x84,0x8b,0xcc, ++0xa7,0x80,0x8b,0xc6,0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0x8c,0xa2,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0xc0,0x10,0x21,0x8f,0x86,0x8b,0xc0,0x8f,0x82,0x8b,0xc8, ++0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x00,0xc0,0x40,0x21,0x14,0x40,0x00,0x0a, ++0x00,0x40,0x50,0x21,0x00,0x00,0x38,0x21,0x27,0x89,0x83,0x68,0x24,0xe2,0x00,0x01, ++0x00,0x07,0x18,0x80,0x30,0x47,0x00,0xff,0x00,0x69,0x18,0x21,0x2c,0xe2,0x00,0x0a, ++0x14,0x40,0xff,0xfa,0xac,0x60,0x00,0x00,0x3c,0x02,0x00,0x80,0x10,0x82,0x00,0x6f, ++0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x6e,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x83,0x6e,0x90,0xa3,0x00,0x15,0x97,0x82,0x83,0x70,0x00,0x03,0x1e,0x00, ++0x00,0x03,0x1e,0x03,0x00,0x43,0x10,0x21,0xa7,0x82,0x83,0x70,0x8c,0xa4,0x00,0x20, ++0x3c,0x02,0x00,0x60,0x3c,0x03,0x00,0x20,0x00,0x82,0x20,0x24,0x10,0x83,0x00,0x54, ++0x00,0x00,0x00,0x00,0x14,0x80,0x00,0x47,0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x74, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x74,0x84,0xa3,0x00,0x06, ++0x8f,0x82,0x83,0x84,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x84, ++0x25,0x42,0x00,0x01,0x28,0x43,0x27,0x10,0xaf,0x82,0x8b,0xc8,0x10,0x60,0x00,0x09, ++0x24,0x02,0x00,0x04,0x93,0x83,0x80,0x11,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x05, ++0x24,0x02,0x00,0x04,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x24,0x03,0x00,0x28,0xa3,0x83,0x83,0x6a,0xa3,0x82,0x83,0x6b, ++0x90,0xa2,0x00,0x18,0x93,0x83,0x83,0x93,0x00,0x00,0x38,0x21,0x00,0x02,0x16,0x00, ++0x00,0x02,0x16,0x03,0xa7,0x82,0x83,0x7e,0xa3,0x83,0x83,0x8c,0x27,0x89,0x83,0x68, ++0x24,0x05,0x8f,0xff,0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff,0x25,0x02,0x00,0x04,0x2c,0xe3,0x00,0x0a, ++0xad,0x04,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x45,0x40,0x24,0x97,0x83,0x8b,0xc6, ++0x97,0x85,0x8b,0xc4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x28,0x00,0xa2,0x28,0x21, ++0x3c,0x04,0xb0,0x06,0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, ++0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x28,0x3c,0x03,0x0f,0x00, ++0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x8b,0xc0, ++0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x02,0x36,0x00,0x00,0x00,0x00,0xa3,0x80,0x80,0x11,0x08,0x00,0x02,0xe5, ++0x00,0x00,0x00,0x00,0x97,0x82,0x83,0x76,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x83,0x76,0x84,0xa3,0x00,0x06,0x8f,0x82,0x83,0x88,0x00,0x00,0x00,0x00, ++0x00,0x43,0x10,0x21,0xaf,0x82,0x83,0x88,0x08,0x00,0x02,0xdd,0x25,0x42,0x00,0x01, ++0x97,0x82,0x83,0x72,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x72, ++0x84,0xa3,0x00,0x06,0x8f,0x82,0x83,0x80,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21, ++0xaf,0x82,0x83,0x80,0x08,0x00,0x02,0xdd,0x25,0x42,0x00,0x01,0x97,0x82,0x83,0x6c, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x83,0x6c,0x08,0x00,0x02,0xc5, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28,0x8c,0xa3,0x00,0x20, ++0x8f,0x8a,0x8b,0xc0,0x3c,0x02,0x00,0x10,0x00,0x62,0x10,0x24,0x00,0xa0,0x38,0x21, ++0x01,0x40,0x48,0x21,0x10,0x40,0x00,0x3d,0x00,0x80,0x28,0x21,0x8c,0xe4,0x00,0x1c, ++0x34,0xa5,0x12,0x06,0xaf,0xa5,0x00,0x10,0x8c,0x82,0x00,0x08,0x00,0x03,0x1c,0x42, ++0x30,0x63,0x00,0x30,0x00,0x02,0x13,0x02,0x30,0x42,0x00,0x40,0x00,0x43,0x10,0x25, ++0x90,0xe6,0x00,0x10,0x90,0xe4,0x00,0x13,0x94,0xe8,0x00,0x0c,0x94,0xe3,0x00,0x1a, ++0x00,0x02,0x16,0x00,0x90,0xe7,0x00,0x12,0x00,0xa2,0x28,0x25,0x24,0x02,0x12,0x34, ++0xa7,0xa2,0x00,0x1c,0x24,0x02,0x56,0x78,0xaf,0xa5,0x00,0x10,0xa3,0xa6,0x00,0x18, ++0xa3,0xa7,0x00,0x1f,0xa7,0xa3,0x00,0x1a,0xa3,0xa4,0x00,0x19,0xa7,0xa8,0x00,0x20, ++0xa7,0xa2,0x00,0x22,0x00,0x00,0x28,0x21,0x27,0xa7,0x00,0x10,0x24,0x06,0x8f,0xff, ++0x00,0x05,0x10,0x80,0x00,0x47,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xa3,0x00,0x01, ++0x30,0x65,0x00,0xff,0x25,0x22,0x00,0x04,0x2c,0xa3,0x00,0x05,0xad,0x24,0x00,0x00, ++0x14,0x60,0xff,0xf7,0x00,0x46,0x48,0x24,0x97,0x83,0x8b,0xc6,0x97,0x85,0x8b,0xc4, ++0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x14,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06, ++0xa7,0x83,0x8b,0xc6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00, ++0x24,0x02,0x8f,0xff,0x25,0x46,0x00,0x14,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x50,0x24, ++0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x8a,0x8b,0xc0,0x10,0xa2,0x00,0x03, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x28, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x3c,0x05,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8,0x00,0x04,0x22,0x00,0x34,0xa5,0x00,0x20, ++0x24,0x42,0x0d,0xfc,0x3c,0x03,0xb0,0x00,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20, ++0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x30,0x00,0x83,0x80,0x21, ++0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14, ++0xac,0xa2,0x00,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x90,0x21,0x26,0x10,0x00,0x08, ++0x00,0x09,0xa6,0x02,0x12,0x80,0x00,0x13,0x00,0x00,0xa8,0x21,0x24,0x13,0x00,0x02, ++0x3c,0x16,0x00,0xff,0x3c,0x17,0xff,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x09,0x12,0x02,0x24,0x42,0x00,0x02,0x31,0x25,0x00,0xff,0x10,0xb3,0x00,0x76, ++0x30,0x51,0x00,0xff,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x18,0x00,0x00,0x00,0x00, ++0x02,0x51,0x10,0x21,0x30,0x52,0xff,0xff,0x02,0x54,0x18,0x2b,0x14,0x60,0xff,0xf2, ++0x02,0x11,0x80,0x21,0x12,0xa0,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, ++0x8c,0x43,0x00,0x00,0x3c,0x04,0x0f,0x00,0x3c,0x02,0x04,0x00,0x00,0x64,0x18,0x24, ++0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x96,0x00,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x8e,0x09,0x00,0x04, ++0x24,0x15,0x00,0x01,0x8e,0x06,0x00,0x0c,0x00,0x09,0x11,0x42,0x00,0x09,0x18,0xc2, ++0x30,0x48,0x00,0x03,0x00,0x09,0x14,0x02,0x30,0x6c,0x00,0x03,0x00,0x09,0x26,0x02, ++0x11,0x15,0x00,0x45,0x30,0x43,0x00,0x0f,0x29,0x02,0x00,0x02,0x14,0x40,0x00,0x26, ++0x00,0x00,0x00,0x00,0x11,0x13,0x00,0x0f,0x00,0x00,0x38,0x21,0x00,0x07,0x22,0x02, ++0x30,0x84,0xff,0x00,0x3c,0x03,0x00,0xff,0x00,0x07,0x2e,0x02,0x00,0x07,0x12,0x00, ++0x00,0x43,0x10,0x24,0x00,0xa4,0x28,0x25,0x00,0xa2,0x28,0x25,0x00,0x07,0x1e,0x00, ++0x00,0xa3,0x28,0x25,0x0c,0x00,0x01,0x92,0x01,0x20,0x20,0x21,0x08,0x00,0x03,0xa5, ++0x02,0x51,0x10,0x21,0x11,0x95,0x00,0x0f,0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x07, ++0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x80,0x27,0x83,0x8b,0x70,0x00,0x43,0x10,0x21, ++0x8c,0x47,0x00,0x18,0x08,0x00,0x03,0xcc,0x00,0x07,0x22,0x02,0x00,0x04,0x10,0x40, ++0x27,0x83,0x8b,0x78,0x00,0x43,0x10,0x21,0x94,0x47,0x00,0x02,0x08,0x00,0x03,0xcc, ++0x00,0x07,0x22,0x02,0x27,0x82,0x8b,0x70,0x00,0x82,0x10,0x21,0x90,0x47,0x00,0x00, ++0x08,0x00,0x03,0xcc,0x00,0x07,0x22,0x02,0x15,0x00,0xff,0xdc,0x00,0x00,0x38,0x21, ++0x10,0x75,0x00,0x05,0x00,0x80,0x38,0x21,0x00,0x65,0x18,0x26,0x24,0x82,0x01,0x00, ++0x00,0x00,0x38,0x21,0x00,0x43,0x38,0x0a,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x0e, ++0x3c,0x02,0xb0,0x03,0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x06,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x8c,0x47,0x00,0x00,0x08,0x00,0x03,0xcc, ++0x00,0x07,0x22,0x02,0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x94,0x43,0x00,0x00, ++0x08,0x00,0x03,0xcb,0x30,0x67,0xff,0xff,0x00,0xe2,0x10,0x21,0x90,0x43,0x00,0x00, ++0x08,0x00,0x03,0xcb,0x30,0x67,0x00,0xff,0x30,0x62,0x00,0x03,0x00,0x02,0x12,0x00, ++0x11,0x95,0x00,0x07,0x00,0x44,0x38,0x21,0x11,0x93,0x00,0x03,0x00,0x00,0x00,0x00, ++0x08,0x00,0x03,0xfd,0x3c,0x02,0xb0,0x0a,0x08,0x00,0x04,0x02,0x3c,0x02,0xb0,0x0a, ++0x08,0x00,0x04,0x06,0x3c,0x02,0xb0,0x0a,0x8e,0x09,0x00,0x04,0x8e,0x02,0x00,0x08, ++0x8e,0x03,0x00,0x0c,0x00,0x09,0x41,0x42,0x00,0x02,0x22,0x02,0x00,0x03,0x3a,0x02, ++0x30,0x84,0xff,0x00,0x30,0xe7,0xff,0x00,0x00,0x02,0x5e,0x02,0x00,0x02,0x32,0x00, ++0x00,0x03,0x56,0x02,0x00,0x03,0x2a,0x00,0x01,0x64,0x58,0x25,0x00,0xd6,0x30,0x24, ++0x01,0x47,0x50,0x25,0x00,0x02,0x16,0x00,0x00,0xb6,0x28,0x24,0x00,0x03,0x1e,0x00, ++0x01,0x66,0x58,0x25,0x01,0x45,0x50,0x25,0x00,0x57,0x10,0x24,0x00,0x77,0x18,0x24, ++0x01,0x62,0x38,0x25,0x01,0x43,0x30,0x25,0x00,0x09,0x10,0xc2,0x00,0x09,0x1c,0x02, ++0x31,0x08,0x00,0x03,0x30,0x4c,0x00,0x03,0x30,0x63,0x00,0x0f,0x00,0x09,0x26,0x02, ++0x00,0xe0,0x58,0x21,0x15,0x00,0x00,0x28,0x00,0xc0,0x50,0x21,0x24,0x02,0x00,0x01, ++0x10,0x62,0x00,0x06,0x00,0x80,0x28,0x21,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0x69, ++0x02,0x51,0x10,0x21,0x24,0x85,0x01,0x00,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x15, ++0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x0a,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21, ++0x8c,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24, ++0x00,0x45,0x10,0x25,0xac,0x62,0x00,0x00,0x08,0x00,0x03,0xa5,0x02,0x51,0x10,0x21, ++0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24, ++0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0xa4,0x62,0x00,0x00,0x08,0x00,0x03,0xa5, ++0x02,0x51,0x10,0x21,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21,0x90,0x62,0x00,0x00, ++0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, ++0x08,0x00,0x03,0xa4,0xa0,0x62,0x00,0x00,0x24,0x02,0x00,0x01,0x11,0x02,0x00,0x21, ++0x00,0x00,0x00,0x00,0x15,0x13,0xff,0x42,0x00,0x00,0x00,0x00,0x11,0x82,0x00,0x17, ++0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x0b,0x00,0x00,0x00,0x00,0x27,0x83,0x8b,0x70, ++0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x18,0x00,0x06,0x18,0x27, ++0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa4, ++0xac,0x82,0x00,0x18,0x27,0x83,0x8b,0x78,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x21, ++0x94,0x82,0x00,0x02,0x00,0x06,0x18,0x27,0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24, ++0x00,0x45,0x10,0x25,0x08,0x00,0x03,0xa4,0xa4,0x82,0x00,0x02,0x27,0x83,0x8b,0x70, ++0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x5a, ++0x00,0xe6,0x28,0x24,0x30,0x62,0x00,0x07,0x00,0x02,0x12,0x00,0x11,0x88,0x00,0x0f, ++0x00,0x44,0x10,0x21,0x11,0x93,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a, ++0x00,0x43,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x47, ++0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x18,0x21,0x94,0x62,0x00,0x00, ++0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x50,0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a, ++0x08,0x00,0x04,0x7d,0x00,0x43,0x18,0x21,0x97,0x85,0x8b,0xc4,0x3c,0x07,0xb0,0x02, ++0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x00,0x00,0xa7,0x28,0x21,0x34,0x84,0x00,0x20, ++0x24,0x42,0x12,0x58,0x24,0x03,0xff,0x80,0xac,0x82,0x00,0x00,0xa0,0xa3,0x00,0x07, ++0x97,0x82,0x8b,0xc6,0x97,0x85,0x8b,0xc4,0x3c,0x06,0xb0,0x06,0x30,0x42,0xff,0xf8, ++0x24,0x42,0x00,0x10,0x00,0xa2,0x10,0x21,0x30,0x42,0x0f,0xff,0x24,0x44,0x00,0x08, ++0x30,0x84,0x0f,0xff,0x00,0x05,0x28,0xc2,0x3c,0x03,0x00,0x40,0x00,0xa3,0x28,0x25, ++0x00,0x87,0x20,0x21,0x34,0xc6,0x80,0x18,0xac,0xc5,0x00,0x00,0xaf,0x84,0x8b,0xc0, ++0xa7,0x82,0x8b,0xc4,0xa7,0x80,0x8b,0xc6,0xaf,0x80,0x8b,0xc8,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x30,0x84,0x00,0xff,0x24,0x02,0x00,0x01, ++0x00,0xe0,0x48,0x21,0x30,0xc6,0x00,0xff,0x8f,0xa7,0x00,0x10,0x10,0x82,0x00,0x07, ++0x00,0xa0,0x40,0x21,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x03,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0xa8,0x01,0x00,0x3c,0x03,0xb0,0x03, ++0x24,0x02,0x00,0x01,0x00,0x07,0x20,0x27,0x01,0x27,0x28,0x24,0x10,0xc2,0x00,0x14, ++0x01,0x03,0x18,0x21,0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0x09,0x00,0x07,0x50,0x27, ++0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x04,0xe1,0xac,0x62,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, ++0xa0,0x62,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0x07, ++0x00,0x04,0x22,0x00,0x30,0xa5,0x00,0xff,0x00,0x85,0x28,0x21,0x3c,0x02,0xb0,0x0a, ++0x00,0xa2,0x40,0x21,0x30,0xc6,0x00,0xff,0x24,0x02,0x00,0x01,0x8f,0xa4,0x00,0x10, ++0x10,0xc2,0x00,0x14,0x24,0x02,0x00,0x02,0x00,0x04,0x50,0x27,0x10,0xc2,0x00,0x09, ++0x00,0xe4,0x48,0x24,0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08, ++0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08, ++0xa4,0x62,0x00,0x00,0x91,0x02,0x00,0x00,0x00,0x04,0x18,0x27,0x00,0xe4,0x20,0x24, ++0x00,0x43,0x10,0x24,0x00,0x44,0x10,0x25,0x03,0xe0,0x00,0x08,0xa1,0x02,0x00,0x00, ++0x30,0xa9,0x00,0xff,0x27,0x83,0x8b,0x70,0x30,0x85,0x00,0xff,0x24,0x02,0x00,0x01, ++0x00,0x07,0x50,0x27,0x00,0xc7,0x40,0x24,0x11,0x22,0x00,0x17,0x00,0xa3,0x18,0x21, ++0x00,0x05,0x20,0x40,0x27,0x82,0x8b,0x70,0x00,0x05,0x28,0x80,0x27,0x83,0x8b,0x78, ++0x00,0x83,0x50,0x21,0x00,0xa2,0x20,0x21,0x24,0x02,0x00,0x02,0x00,0x07,0x40,0x27, ++0x11,0x22,0x00,0x07,0x00,0xc7,0x28,0x24,0x8c,0x82,0x00,0x18,0x00,0x00,0x00,0x00, ++0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x18, ++0x95,0x42,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25, ++0x03,0xe0,0x00,0x08,0xa5,0x42,0x00,0x02,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x4a,0x10,0x24,0x00,0x48,0x10,0x25,0x03,0xe0,0x00,0x08,0xa0,0x62,0x00,0x00, ++0x00,0x04,0x32,0x02,0x30,0xc6,0xff,0x00,0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00, ++0x3c,0x05,0x00,0xff,0x00,0x65,0x18,0x24,0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25, ++0x00,0x04,0x26,0x00,0x03,0xe0,0x00,0x08,0x00,0x44,0x10,0x25,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20,0x24,0x42,0x14,0xdc, ++0x3c,0x04,0xb0,0x03,0xaf,0xbf,0x00,0x14,0xac,0x62,0x00,0x00,0xaf,0xb0,0x00,0x10, ++0x34,0x84,0x00,0x2c,0x8c,0x83,0x00,0x00,0xa7,0x80,0xbc,0x00,0x00,0x03,0x12,0x02, ++0x00,0x03,0x2d,0x02,0x30,0x42,0x0f,0xff,0xa3,0x83,0xbc,0x08,0xa7,0x85,0xbc,0x0c, ++0xa7,0x82,0xbc,0x0a,0xa7,0x80,0xbc,0x02,0xa7,0x80,0xbc,0x04,0xa7,0x80,0xbc,0x06, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x05,0x00,0x3c,0x05,0x08,0x00,0x00,0x45,0x28,0x25, ++0x24,0x04,0x05,0x00,0x0c,0x00,0x06,0xbf,0x00,0x40,0x80,0x21,0x3c,0x02,0xf7,0xff, ++0x34,0x42,0xff,0xff,0x02,0x02,0x80,0x24,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf, ++0x24,0x04,0x05,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03,0x34,0x42,0x01,0x08, ++0x34,0x63,0x01,0x18,0x8c,0x45,0x00,0x00,0x8c,0x64,0x00,0x00,0x3c,0x02,0x00,0x0f, ++0x3c,0x03,0x00,0x4c,0x30,0x84,0x02,0x00,0x34,0x63,0x4b,0x40,0xaf,0x85,0xbc,0x10, ++0x10,0x80,0x00,0x06,0x34,0x42,0x42,0x40,0xaf,0x83,0xbc,0x14,0x8f,0xbf,0x00,0x14, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0xaf,0x82,0xbc,0x14, ++0x08,0x00,0x05,0x67,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x27,0xbd,0xff,0xc8,0x34,0x63,0x00,0x20,0x24,0x42,0x15,0xb8,0x30,0x84,0x00,0xff, ++0xaf,0xbf,0x00,0x30,0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24, ++0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, ++0xaf,0xb0,0x00,0x10,0xac,0x62,0x00,0x00,0x10,0x80,0x00,0x1c,0x24,0x02,0x00,0x02, ++0x10,0x82,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c, ++0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x38,0xa7,0x80,0xbc,0x00,0xa7,0x80,0xbc,0x02,0xa7,0x80,0xbc,0x04, ++0xa7,0x80,0xbc,0x06,0x0c,0x00,0x06,0xd1,0x24,0x04,0x05,0x00,0x3c,0x05,0x08,0x00, ++0x00,0x45,0x28,0x25,0x24,0x04,0x05,0x00,0x0c,0x00,0x06,0xbf,0x00,0x40,0x80,0x21, ++0x3c,0x05,0xf7,0xff,0x34,0xa5,0xff,0xff,0x02,0x05,0x28,0x24,0x0c,0x00,0x06,0xbf, ++0x24,0x04,0x05,0x00,0x08,0x00,0x05,0x82,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1, ++0x24,0x04,0x05,0xa0,0x24,0x04,0x05,0xa4,0x0c,0x00,0x06,0xd1,0x00,0x02,0xbc,0x02, ++0x24,0x04,0x05,0xa8,0x00,0x02,0xb4,0x02,0x0c,0x00,0x06,0xd1,0x30,0x55,0xff,0xff, ++0x00,0x40,0x80,0x21,0x97,0x84,0xbc,0x00,0x97,0x82,0xbc,0x02,0x97,0x83,0xbc,0x06, ++0x02,0xe4,0x20,0x23,0x02,0xa2,0x10,0x23,0x00,0x82,0x20,0x21,0x97,0x82,0xbc,0x04, ++0x32,0x14,0xff,0xff,0x02,0x83,0x18,0x23,0x02,0xc2,0x10,0x23,0x00,0x82,0x20,0x21, ++0x93,0x82,0xbc,0x08,0x00,0x83,0x20,0x21,0x30,0x84,0xff,0xff,0x00,0x82,0x10,0x2b, ++0x14,0x40,0x00,0xaa,0x00,0x00,0x00,0x00,0x97,0x82,0xbc,0x0c,0x00,0x00,0x00,0x00, ++0x00,0x44,0x10,0x2b,0x14,0x40,0x00,0x7f,0x00,0x00,0x00,0x00,0x97,0x82,0xbc,0x0a, ++0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b,0x10,0x40,0x00,0x3a,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f,0x00,0x40,0x80,0x21, ++0x2e,0x22,0x00,0x32,0x10,0x40,0x00,0x13,0x24,0x02,0x00,0x20,0x12,0x22,0x00,0x17, ++0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24,0x26,0x31,0x00,0x01,0x00,0x51,0x80,0x25, ++0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x50,0x02,0x00,0x28,0x21, ++0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x58,0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf, ++0x24,0x04,0x04,0x60,0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x68,0x0c,0x00,0x06,0xbf, ++0x00,0x00,0x00,0x00,0xa7,0x97,0xbc,0x00,0xa7,0x95,0xbc,0x02,0xa7,0x96,0xbc,0x04, ++0xa7,0x94,0xbc,0x06,0x08,0x00,0x05,0x82,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1, ++0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24, ++0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03,0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, ++0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c, ++0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24, ++0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x2c,0x08,0x00,0x05,0xc9, ++0x24,0x02,0xff,0x80,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f, ++0x24,0x02,0x00,0x20,0x16,0x22,0xff,0xdb,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1, ++0x24,0x04,0x02,0x2c,0x34,0x52,0x40,0x00,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf, ++0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x58,0x24,0x04,0x02,0x5c, ++0x0c,0x00,0x06,0xd1,0x00,0x02,0x9e,0x02,0x30,0x43,0x00,0xff,0x00,0x13,0x12,0x00, ++0x00,0x43,0x10,0x25,0x2c,0x43,0x00,0x04,0x14,0x60,0x00,0x1d,0x2c,0x42,0x00,0x11, ++0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff, ++0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xbf, ++0x36,0x52,0x80,0x00,0x02,0x40,0x28,0x21,0x08,0x00,0x05,0xd7,0x24,0x04,0x02,0x2c, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0,0x00,0x40,0x28,0x21, ++0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x02,0x14,0x43,0xff,0xee, ++0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25, ++0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08,0x08,0x00,0x06,0x13,0x3c,0x02,0xff,0xff, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82, ++0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03,0x14,0x43,0xff,0xdf,0x3c,0x02,0xff,0x3f, ++0x34,0x42,0xff,0xff,0x00,0xa2,0x10,0x24,0x3c,0x03,0x00,0x80,0x08,0x00,0x06,0x28, ++0x00,0x43,0x28,0x25,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x50,0x30,0x51,0x00,0x7f, ++0x00,0x40,0x80,0x21,0x2e,0x22,0x00,0x32,0x10,0x40,0xff,0x9a,0x24,0x02,0x00,0x20, ++0x12,0x22,0x00,0x04,0x24,0x02,0xff,0x80,0x02,0x02,0x10,0x24,0x08,0x00,0x05,0xcb, ++0x26,0x31,0x00,0x02,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0, ++0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x03, ++0x10,0x43,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, ++0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c,0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff, ++0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf, ++0x24,0x04,0x02,0x2c,0x08,0x00,0x06,0x42,0x24,0x02,0xff,0x80,0x0c,0x00,0x06,0xd1, ++0x24,0x04,0x04,0x50,0x00,0x40,0x80,0x21,0x30,0x51,0x00,0x7f,0x24,0x02,0x00,0x20, ++0x12,0x22,0x00,0x1d,0x2e,0x22,0x00,0x21,0x14,0x40,0xff,0x72,0x24,0x02,0xff,0x80, ++0x02,0x02,0x10,0x24,0x26,0x31,0xff,0xff,0x00,0x51,0x80,0x25,0x24,0x04,0x04,0x50, ++0x0c,0x00,0x06,0xbf,0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x58,0x0c,0x00,0x06,0xbf, ++0x02,0x00,0x28,0x21,0x24,0x04,0x04,0x60,0x0c,0x00,0x06,0xbf,0x02,0x00,0x28,0x21, ++0x02,0x00,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x68,0x24,0x02,0x00,0x20, ++0x16,0x22,0xff,0x60,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c, ++0x00,0x40,0x90,0x21,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x10,0x24, ++0x08,0x00,0x06,0x19,0x34,0x52,0x80,0x00,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x2c, ++0x34,0x52,0x40,0x00,0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x2c, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x58,0x24,0x04,0x02,0x5c,0x0c,0x00,0x06,0xd1, ++0x00,0x02,0x9e,0x02,0x30,0x43,0x00,0xff,0x00,0x13,0x12,0x00,0x00,0x43,0x10,0x25, ++0x2c,0x43,0x00,0x04,0x14,0x60,0x00,0x20,0x2c,0x42,0x00,0x11,0x10,0x40,0x00,0x0d, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x02,0x42,0x90,0x24, ++0x02,0x40,0x28,0x21,0x24,0x04,0x02,0x2c,0x0c,0x00,0x06,0xbf,0x36,0x52,0x80,0x00, ++0x02,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x2c,0x08,0x00,0x06,0x66, ++0x2e,0x22,0x00,0x21,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08,0x3c,0x04,0x00,0xc0, ++0x00,0x40,0x28,0x21,0x00,0x44,0x10,0x24,0x00,0x02,0x15,0x82,0x24,0x03,0x00,0x02, ++0x14,0x43,0xff,0xec,0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, ++0x00,0xa2,0x10,0x24,0x00,0x44,0x28,0x25,0x0c,0x00,0x06,0xbf,0x24,0x04,0x02,0x08, ++0x08,0x00,0x06,0x96,0x3c,0x02,0xff,0xff,0x0c,0x00,0x06,0xd1,0x24,0x04,0x02,0x08, ++0x00,0x40,0x28,0x21,0x00,0x02,0x15,0x82,0x30,0x42,0x00,0x03,0x24,0x03,0x00,0x03, ++0x14,0x43,0xff,0xdc,0x3c,0x03,0x00,0x80,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, ++0x00,0xa2,0x10,0x24,0x08,0x00,0x06,0xae,0x00,0x43,0x28,0x25,0x30,0x83,0x00,0x03, ++0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x23,0x3c,0x02,0xb0,0x0a,0x00,0x82,0x20,0x21, ++0x3c,0x06,0x00,0x01,0xac,0x85,0x00,0x00,0x24,0x07,0x00,0x01,0x00,0x00,0x28,0x21, ++0x34,0xc6,0x86,0x9f,0x8c,0x82,0x10,0x00,0x24,0xa5,0x00,0x01,0x10,0x47,0x00,0x03, ++0x00,0xc5,0x18,0x2b,0x10,0x60,0xff,0xfb,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0x83,0x00,0x03,0x00,0x04,0x20,0x40,0x3c,0x02,0xb0,0x0a, ++0x00,0x83,0x20,0x23,0x00,0x82,0x20,0x21,0x3c,0x06,0x00,0x01,0x24,0x02,0xff,0xff, ++0xac,0x82,0x10,0x00,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x01,0x34,0xc6,0x86,0x9f, ++0x8c,0x82,0x10,0x00,0x24,0xa5,0x00,0x01,0x10,0x47,0x00,0x03,0x00,0xc5,0x18,0x2b, ++0x10,0x60,0xff,0xfb,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x1b,0x94, ++0x24,0x03,0x00,0x01,0x34,0xa5,0x00,0x20,0x3c,0x06,0xb0,0x03,0xac,0xa2,0x00,0x00, ++0x34,0xc6,0x01,0x04,0xa0,0x83,0x00,0x48,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, ++0xa0,0x80,0x00,0x06,0xa0,0x80,0x00,0x07,0xa0,0x80,0x00,0x08,0xa0,0x80,0x00,0x09, ++0xa0,0x80,0x00,0x0a,0xa0,0x80,0x00,0x11,0xa0,0x80,0x00,0x13,0xa0,0x80,0x00,0x49, ++0x94,0xc2,0x00,0x00,0xac,0x80,0x00,0x00,0xa0,0x80,0x00,0x4e,0x00,0x02,0x14,0x00, ++0x00,0x02,0x14,0x03,0x30,0x43,0x00,0xff,0x30,0x42,0xff,0x00,0xa4,0x82,0x00,0x44, ++0xa4,0x83,0x00,0x46,0xac,0x80,0x00,0x24,0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c, ++0xac,0x80,0x00,0x30,0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xac,0x80,0x00,0x3c, ++0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x40,0x84,0x83,0x00,0x0c,0x3c,0x07,0xb0,0x03, ++0x34,0xe7,0x00,0x20,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x83,0x90,0x04,0x00,0x43,0x10,0x21,0x8c,0x48,0x00,0x18,0x3c,0x02,0x80,0x00, ++0x24,0x42,0x1c,0x28,0xac,0xe2,0x00,0x00,0x8d,0x03,0x00,0x08,0x80,0x82,0x00,0x13, ++0x00,0x05,0x2c,0x00,0x00,0x03,0x1e,0x02,0x00,0x02,0x12,0x00,0x30,0x63,0x00,0x7e, ++0x00,0x62,0x18,0x21,0x00,0x65,0x18,0x21,0x3c,0x02,0xc0,0x00,0x3c,0x05,0xb0,0x05, ++0x34,0x42,0x04,0x00,0x24,0x63,0x00,0x01,0x3c,0x07,0xb0,0x05,0x3c,0x08,0xb0,0x05, ++0x34,0xa5,0x04,0x20,0xac,0xa3,0x00,0x00,0x00,0xc2,0x30,0x21,0x34,0xe7,0x04,0x24, ++0x35,0x08,0x02,0x28,0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x20,0xac,0xe6,0x00,0x00, ++0xac,0x82,0x00,0x3c,0x03,0xe0,0x00,0x08,0xa1,0x03,0x00,0x00,0x27,0xbd,0xff,0xa8, ++0x00,0x07,0x60,0x80,0x27,0x82,0xb4,0x00,0xaf,0xbe,0x00,0x50,0xaf,0xb7,0x00,0x4c, ++0xaf,0xb5,0x00,0x44,0xaf,0xb4,0x00,0x40,0xaf,0xbf,0x00,0x54,0xaf,0xb6,0x00,0x48, ++0xaf,0xb3,0x00,0x3c,0xaf,0xb2,0x00,0x38,0xaf,0xb1,0x00,0x34,0xaf,0xb0,0x00,0x30, ++0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0xe0,0x70,0x21,0x3c,0x02,0x80,0x00, ++0x94,0x73,0x00,0x14,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x20,0x24,0x42,0x1c,0xbc, ++0x3c,0x03,0xb0,0x05,0xac,0xe2,0x00,0x00,0x34,0x63,0x01,0x28,0x90,0x67,0x00,0x00, ++0x00,0x13,0xa8,0xc0,0x02,0xb3,0x18,0x21,0x27,0x82,0x90,0x04,0x00,0x03,0x18,0x80, ++0x00,0x62,0x18,0x21,0x00,0x05,0x2c,0x00,0x00,0x07,0x3e,0x00,0x28,0xc2,0x00,0x03, ++0x00,0xc0,0xa0,0x21,0x00,0x80,0x78,0x21,0x00,0x05,0xbc,0x03,0x8c,0x68,0x00,0x18, ++0x02,0xa0,0x58,0x21,0x10,0x40,0x01,0x81,0x00,0x07,0xf6,0x03,0x00,0xde,0x10,0x07, ++0x30,0x5e,0x00,0x01,0x01,0x73,0x10,0x21,0x27,0x83,0x90,0x08,0x00,0x02,0x10,0x80, ++0x00,0x43,0x10,0x21,0x80,0x4d,0x00,0x06,0x8d,0x03,0x00,0x00,0x8d,0x02,0x00,0x04, ++0x8d,0x0a,0x00,0x08,0x8d,0x03,0x00,0x0c,0xaf,0xa2,0x00,0x20,0x11,0xa0,0x01,0x71, ++0xaf,0xa3,0x00,0x18,0x27,0x82,0xb4,0x00,0x01,0x82,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04, ++0x14,0x60,0x00,0x12,0x00,0x00,0xb0,0x21,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46, ++0x90,0x43,0x00,0x00,0x2a,0x84,0x00,0x04,0x10,0x80,0x01,0x56,0x30,0x65,0x00,0x01, ++0x91,0xe2,0x00,0x09,0x00,0x00,0x00,0x00,0x12,0x82,0x00,0x02,0x00,0x00,0x00,0x00, ++0x00,0x00,0x28,0x21,0x14,0xa0,0x00,0x03,0x00,0x00,0x38,0x21,0x13,0xc0,0x00,0x03, ++0x38,0xf6,0x00,0x01,0x24,0x07,0x00,0x01,0x38,0xf6,0x00,0x01,0x01,0x73,0x10,0x21, ++0x00,0x02,0x30,0x80,0x27,0x83,0x90,0x10,0x00,0xc3,0x48,0x21,0x91,0x25,0x00,0x00, ++0x8f,0xa4,0x00,0x20,0x2c,0xa3,0x00,0x04,0x00,0x04,0x11,0xc3,0x30,0x42,0x00,0x01, ++0x00,0x03,0xb0,0x0b,0x12,0xc0,0x00,0xd8,0xaf,0xa2,0x00,0x24,0x93,0x90,0xbb,0xea, ++0x00,0x0a,0x16,0x42,0x30,0x52,0x00,0x3f,0x2e,0x06,0x00,0x0c,0x10,0xc0,0x00,0xc0, ++0x00,0xa0,0x20,0x21,0x2c,0xa2,0x00,0x10,0x14,0x40,0x00,0x04,0x00,0x90,0x10,0x2b, ++0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x04,0x00,0x90,0x10,0x2b,0x10,0x40,0x00,0x0b, ++0x01,0x73,0x10,0x21,0x27,0x85,0xbb,0x1c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, ++0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, ++0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x01,0x73,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x83,0x90,0x08,0x00,0x43,0x10,0x21,0x31,0xa4,0x00,0x01,0x10,0x80,0x00,0xa5, ++0xa0,0x50,0x00,0x07,0x3c,0x04,0xb0,0x05,0x34,0x84,0x00,0x08,0x24,0x02,0x00,0x01, ++0x3c,0x03,0x80,0x00,0xa1,0xe2,0x00,0x4e,0xac,0x83,0x00,0x00,0x8c,0x85,0x00,0x00, ++0x3c,0x02,0x00,0xf0,0x3c,0x03,0x40,0xf0,0x34,0x42,0xf0,0x00,0x34,0x63,0xf0,0x00, ++0x24,0x17,0x00,0x0e,0x24,0x13,0x01,0x06,0xac,0x82,0x00,0x00,0xac,0x83,0x00,0x00, ++0x27,0x82,0xb4,0x00,0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x24,0x05,0x00,0x01, ++0xaf,0xa5,0x00,0x1c,0x90,0x62,0x00,0x16,0x00,0x13,0xa8,0xc0,0x32,0x51,0x00,0x02, ++0x34,0x42,0x00,0x04,0xa0,0x62,0x00,0x16,0x8f,0xa3,0x00,0x20,0x8f,0xa4,0x00,0x18, ++0x00,0x03,0x13,0x43,0x00,0x04,0x1a,0x02,0x30,0x47,0x00,0x01,0x12,0x20,0x00,0x04, ++0x30,0x64,0x07,0xff,0x2e,0x03,0x00,0x04,0x32,0x42,0x00,0x33,0x00,0x43,0x90,0x0b, ++0x8f,0xa5,0x00,0x24,0x8f,0xa6,0x00,0x1c,0x00,0x12,0x10,0x40,0x00,0x05,0x19,0xc0, ++0x00,0x47,0x10,0x21,0x00,0x06,0x2a,0x80,0x00,0x43,0x10,0x21,0x00,0x10,0x32,0x00, ++0x00,0x04,0x24,0x80,0x02,0x65,0x28,0x21,0x00,0xa4,0x28,0x21,0x00,0x46,0x10,0x21, ++0x00,0x17,0x1c,0x00,0x3c,0x04,0xc0,0x00,0x00,0x43,0x30,0x21,0x16,0x80,0x00,0x29, ++0x00,0xa4,0x28,0x21,0x3c,0x02,0xb0,0x05,0x34,0x42,0x04,0x00,0x3c,0x03,0xb0,0x05, ++0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x04,0x34,0x84,0x02,0x28, ++0x24,0x02,0x00,0x01,0xac,0x65,0x00,0x00,0xa0,0x82,0x00,0x00,0x3c,0x02,0xb0,0x09, ++0x34,0x42,0x01,0x46,0x90,0x44,0x00,0x00,0x91,0xe3,0x00,0x09,0x30,0x86,0x00,0x01, ++0x02,0x83,0x18,0x26,0x00,0x03,0x30,0x0b,0x14,0xc0,0x00,0x03,0x00,0x00,0x28,0x21, ++0x13,0xc0,0x00,0x03,0x02,0xb3,0x10,0x21,0x24,0x05,0x00,0x01,0x02,0xb3,0x10,0x21, ++0x27,0x83,0x90,0x08,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x84,0x48,0x00,0x04, ++0x00,0xa0,0x30,0x21,0x00,0xe0,0x20,0x21,0x02,0x80,0x28,0x21,0x02,0xc0,0x38,0x21, ++0x0c,0x00,0x00,0x70,0xaf,0xa8,0x00,0x10,0x7b,0xbe,0x02,0xbc,0x7b,0xb6,0x02,0x7c, ++0x7b,0xb4,0x02,0x3c,0x7b,0xb2,0x01,0xfc,0x7b,0xb0,0x01,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x58,0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x3d,0x3c,0x02,0xb0,0x05, ++0x24,0x02,0x00,0x02,0x12,0x82,0x00,0x31,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x03, ++0x12,0x82,0x00,0x25,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10,0x12,0x82,0x00,0x19, ++0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x11,0x12,0x82,0x00,0x0d,0x3c,0x02,0xb0,0x05, ++0x24,0x02,0x00,0x12,0x16,0x82,0xff,0xd1,0x3c,0x02,0xb0,0x05,0x3c,0x03,0xb0,0x05, ++0x34,0x42,0x04,0x20,0x3c,0x04,0xb0,0x05,0x34,0x63,0x04,0x24,0xac,0x46,0x00,0x00, ++0x34,0x84,0x02,0x28,0xac,0x65,0x00,0x00,0x08,0x00,0x07,0xe6,0x24,0x02,0x00,0x20, ++0x34,0x42,0x04,0x40,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, ++0x34,0x63,0x04,0x44,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x40,0x08,0x00,0x07,0xe6, ++0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x28,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, ++0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x2c,0x34,0x84,0x02,0x28,0x24,0x02,0xff,0x80, ++0x08,0x00,0x07,0xe6,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x18,0x3c,0x03,0xb0,0x05, ++0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x1c,0x34,0x84,0x02,0x28, ++0x24,0x02,0x00,0x08,0x08,0x00,0x07,0xe6,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x10, ++0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x14, ++0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x04,0x08,0x00,0x07,0xe6,0xac,0x65,0x00,0x00, ++0x34,0x42,0x04,0x08,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, ++0x34,0x63,0x04,0x0c,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x02,0x08,0x00,0x07,0xe6, ++0xac,0x65,0x00,0x00,0x24,0x17,0x00,0x14,0x08,0x00,0x07,0xb8,0x24,0x13,0x01,0x02, ++0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x0c,0x00,0x90,0x18,0x2b,0x10,0x60,0x00,0x0c, ++0x26,0x02,0x00,0x04,0x27,0x85,0xbb,0x1c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, ++0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, ++0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x2e,0x06,0x00,0x0c,0x26,0x02,0x00,0x04, ++0x08,0x00,0x07,0xa2,0x00,0x46,0x80,0x0a,0x27,0x82,0xb4,0x00,0x01,0x82,0x20,0x21, ++0x8c,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0xe2,0x00,0x19,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x27,0x82,0x90,0x20,0x00,0xc2,0x10,0x21, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x14,0x00,0x00,0x00,0x00, ++0x90,0xe3,0x00,0x16,0x27,0x82,0x90,0x08,0x00,0xc2,0x10,0x21,0x34,0x63,0x00,0x20, ++0x90,0x50,0x00,0x07,0xa0,0xe3,0x00,0x16,0x8c,0x84,0x00,0x00,0x00,0x0a,0x1e,0x42, ++0x24,0x06,0x00,0x01,0x90,0x82,0x00,0x16,0x30,0x71,0x00,0x02,0x30,0x72,0x00,0x3f, ++0x30,0x42,0x00,0xfb,0x24,0x17,0x00,0x18,0x24,0x13,0x01,0x03,0x24,0x15,0x08,0x18, ++0xaf,0xa6,0x00,0x1c,0x08,0x00,0x07,0xc2,0xa0,0x82,0x00,0x16,0x8d,0x02,0x00,0x04, ++0x00,0x0a,0x1c,0x42,0x30,0x42,0x00,0x10,0x14,0x40,0x00,0x15,0x30,0x72,0x00,0x3f, ++0x81,0x22,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x11,0x30,0x72,0x00,0x3e, ++0x27,0x83,0x90,0x18,0x00,0xc3,0x18,0x21,0x80,0x64,0x00,0x00,0x27,0x83,0xb5,0x78, ++0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x05,0x90,0x43,0x00,0x04, ++0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x24,0x30,0x63,0x00,0x01,0x02,0x43,0x90,0x25, ++0x27,0x85,0xb4,0x00,0x01,0x85,0x28,0x21,0x8c,0xa6,0x00,0x00,0x01,0x73,0x10,0x21, ++0x27,0x83,0x90,0x10,0x90,0xc4,0x00,0x16,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x30,0x84,0x00,0xdf,0x90,0x50,0x00,0x00,0xa0,0xc4,0x00,0x16,0x80,0xc6,0x00,0x12, ++0x8c,0xa3,0x00,0x00,0x2d,0xc4,0x00,0x02,0xaf,0xa6,0x00,0x1c,0x90,0x62,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfb,0x14,0x80,0x00,0x06,0xa0,0x62,0x00,0x16, ++0x24,0x02,0x00,0x06,0x11,0xc2,0x00,0x03,0x24,0x02,0x00,0x04,0x15,0xc2,0xff,0x0e, ++0x32,0x51,0x00,0x02,0x32,0x51,0x00,0x02,0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x0f, ++0x00,0x11,0x18,0x2b,0x32,0x02,0x00,0x0f,0x34,0x42,0x00,0x10,0x00,0x03,0x19,0x00, ++0x00,0x43,0x18,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xe0,0xa0,0x43,0x00,0x00, ++0x00,0x00,0x20,0x21,0x02,0x00,0x28,0x21,0x0c,0x00,0x02,0x03,0xaf,0xaf,0x00,0x28, ++0x8f,0xaf,0x00,0x28,0x08,0x00,0x07,0xc2,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0xbd, ++0x32,0x03,0x00,0xff,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x42,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0x14,0x40,0xfe,0xaa,0x00,0x00,0x00,0x00, ++0x91,0xe2,0x00,0x09,0x00,0x00,0x00,0x00,0x02,0x82,0x10,0x26,0x08,0x00,0x07,0x79, ++0x00,0x02,0x28,0x0b,0x08,0x00,0x07,0x7f,0x00,0x00,0xb0,0x21,0x24,0x02,0x00,0x10, ++0x10,0xc2,0x00,0x08,0x24,0x02,0x00,0x11,0x10,0xc2,0xfe,0x7d,0x00,0x07,0x17,0x83, ++0x24,0x02,0x00,0x12,0x14,0xc2,0xfe,0x7b,0x00,0x07,0x17,0x43,0x08,0x00,0x07,0x59, ++0x30,0x5e,0x00,0x01,0x08,0x00,0x07,0x59,0x00,0x07,0xf7,0xc2,0x00,0x04,0x10,0x40, ++0x27,0x83,0x80,0x1c,0x00,0x43,0x10,0x21,0x00,0x80,0x40,0x21,0x94,0x44,0x00,0x00, ++0x2d,0x07,0x00,0x04,0x24,0xc2,0x00,0x03,0x00,0x47,0x30,0x0a,0x00,0x86,0x00,0x18, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x23,0x8c, ++0xac,0x62,0x00,0x00,0x2d,0x06,0x00,0x10,0x00,0x00,0x20,0x12,0x00,0x04,0x22,0x42, ++0x24,0x84,0x00,0x01,0x24,0x83,0x00,0xc0,0x10,0xe0,0x00,0x0b,0x24,0x82,0x00,0x60, ++0x00,0x40,0x20,0x21,0x00,0x65,0x20,0x0a,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x00,0x44,0x20,0x04, ++0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x24,0x85,0x00,0x28,0x24,0x83,0x00,0x24, ++0x31,0x02,0x00,0x08,0x14,0xc0,0xff,0xf4,0x24,0x84,0x00,0x14,0x00,0x60,0x20,0x21, ++0x08,0x00,0x08,0xfa,0x00,0xa2,0x20,0x0b,0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0xaf,0xb0,0x00,0x10,0x24,0x42,0x24,0x28,0x00,0x80,0x80,0x21, ++0x34,0x63,0x00,0x20,0x3c,0x04,0xb0,0x03,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, ++0xaf,0xbf,0x00,0x1c,0x83,0xb1,0x00,0x33,0x83,0xa8,0x00,0x37,0x34,0x84,0x01,0x10, ++0xac,0x62,0x00,0x00,0x2e,0x02,0x00,0x10,0x00,0xe0,0x90,0x21,0x8c,0x87,0x00,0x00, ++0x14,0x40,0x00,0x0c,0x2e,0x02,0x00,0x0c,0x3c,0x02,0x00,0x0f,0x34,0x42,0xf0,0x00, ++0x00,0xe2,0x10,0x24,0x14,0x40,0x00,0x37,0x32,0x02,0x00,0x08,0x32,0x02,0x00,0x07, ++0x27,0x83,0x80,0xcc,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00, ++0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x03,0x02,0x00,0x20,0x21,0x32,0x02,0x00,0x0f, ++0x24,0x44,0x00,0x0c,0x00,0x87,0x10,0x06,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x07, ++0x2c,0x82,0x00,0x0c,0x00,0x04,0x10,0x80,0x27,0x83,0xb4,0x50,0x00,0x43,0x10,0x21, ++0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x82,0x00,0x0c,0x14,0x40,0x00,0x05, ++0x00,0x05,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x82,0x10,0x21, ++0x24,0x44,0x00,0x04,0x15,0x00,0x00,0x02,0x24,0x06,0x00,0x20,0x24,0x06,0x00,0x0e, ++0x0c,0x00,0x08,0xe3,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x01,0x00,0x90,0x43,0x00,0x00,0x2e,0x04,0x00,0x04,0x24,0x02,0x00,0x10, ++0x24,0x05,0x00,0x0a,0x00,0x44,0x28,0x0a,0x30,0x63,0x00,0x01,0x14,0x60,0x00,0x02, ++0x00,0x05,0x10,0x40,0x00,0xa0,0x10,0x21,0x30,0x45,0x00,0xff,0x00,0xc5,0x10,0x21, ++0x24,0x46,0x00,0x46,0x02,0x26,0x18,0x04,0xa6,0x43,0x00,0x00,0x8f,0xbf,0x00,0x1c, ++0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x10,0x40,0xff,0xcf,0x2e,0x02,0x00,0x0c,0x32,0x02,0x00,0x07, ++0x27,0x83,0x80,0xc4,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x08,0x00,0x09,0x28, ++0x02,0x04,0x80,0x23,0x27,0xbd,0xff,0xb8,0x00,0x05,0x38,0x80,0x27,0x82,0xb4,0x00, ++0xaf,0xbe,0x00,0x40,0xaf,0xb6,0x00,0x38,0xaf,0xb3,0x00,0x2c,0xaf,0xbf,0x00,0x44, ++0xaf,0xb7,0x00,0x3c,0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xb2,0x00,0x28, ++0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0x00,0xe2,0x38,0x21,0x8c,0xe6,0x00,0x00, ++0xaf,0xa5,0x00,0x4c,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20, ++0x24,0x42,0x25,0x84,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00,0xa0,0xc3,0x00,0x12, ++0x8c,0xe5,0x00,0x00,0x94,0xc3,0x00,0x06,0x90,0xa2,0x00,0x16,0xa4,0xc3,0x00,0x14, ++0x27,0x83,0x90,0x00,0x34,0x42,0x00,0x08,0xa0,0xa2,0x00,0x16,0x8c,0xe8,0x00,0x00, ++0xaf,0xa4,0x00,0x48,0x27,0x82,0x90,0x04,0x95,0x11,0x00,0x14,0x00,0x00,0x00,0x00, ++0x00,0x11,0x98,0xc0,0x02,0x71,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x82,0x10,0x21, ++0x8c,0x52,0x00,0x18,0x00,0x83,0x18,0x21,0x84,0x75,0x00,0x06,0x8e,0x45,0x00,0x08, ++0x8e,0x46,0x00,0x04,0x8e,0x47,0x00,0x04,0x00,0x05,0x1c,0x82,0x00,0x06,0x31,0x42, ++0x27,0x82,0x90,0x10,0x30,0x63,0x00,0x01,0x30,0xc6,0x00,0x01,0x00,0x82,0x20,0x21, ++0xa5,0x15,0x00,0x1a,0x00,0x05,0x14,0x42,0xaf,0xa3,0x00,0x18,0xaf,0xa6,0x00,0x1c, ++0x30,0xe7,0x00,0x10,0x30,0x56,0x00,0x01,0x80,0x97,0x00,0x06,0x14,0xe0,0x00,0x47, ++0x00,0x05,0xf7,0xc2,0x80,0x82,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x44, ++0x02,0x71,0x10,0x21,0x93,0x90,0xbb,0xe9,0x00,0x00,0x00,0x00,0x2e,0x02,0x00,0x0c, ++0x14,0x40,0x00,0x06,0x02,0x00,0x20,0x21,0x00,0x16,0x10,0x40,0x00,0x43,0x10,0x21, ++0x00,0x02,0x11,0x00,0x02,0x02,0x10,0x21,0x24,0x44,0x00,0x04,0x02,0x71,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0x00,0x80,0x80,0x21, ++0xa0,0x44,0x00,0x03,0xa0,0x44,0x00,0x00,0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21, ++0x0c,0x00,0x08,0xe3,0x02,0xa0,0x30,0x21,0x02,0x71,0x18,0x21,0x00,0x03,0x88,0x80, ++0x00,0x40,0xa0,0x21,0x27,0x82,0x90,0x20,0x02,0x22,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x26,0xe3,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21,0x00,0x04,0x25,0xc2, ++0x00,0x03,0x18,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x18,0x40,0x03,0xc4,0x20,0x24, ++0x14,0x80,0x00,0x15,0x02,0x43,0x38,0x21,0x3c,0x08,0xb0,0x03,0x35,0x08,0x00,0x28, ++0x8d,0x03,0x00,0x00,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x48,0x27,0x82,0x90,0x08, ++0x02,0x22,0x10,0x21,0x24,0x63,0x00,0x01,0x02,0xa0,0x28,0x21,0xa4,0x54,0x00,0x04, ++0x00,0xc0,0x38,0x21,0x0c,0x00,0x07,0x2f,0xad,0x03,0x00,0x00,0x7b,0xbe,0x02,0x3c, ++0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48,0x8f,0xa2,0x00,0x1c,0x8f,0xa6,0x00,0x18, ++0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0x0a, ++0xaf,0xa0,0x00,0x14,0x08,0x00,0x09,0xc6,0x02,0x82,0xa0,0x21,0x02,0x71,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00, ++0x08,0x00,0x09,0xb2,0xa0,0x50,0x00,0x03,0x27,0xbd,0xff,0xb8,0xaf,0xb1,0x00,0x24, ++0x8f,0xb1,0x00,0x5c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, ++0x24,0x42,0x27,0xa8,0xaf,0xbe,0x00,0x40,0xaf,0xb7,0x00,0x3c,0xaf,0xb6,0x00,0x38, ++0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xa5,0x00,0x4c,0x8f,0xb5,0x00,0x58, ++0xaf,0xbf,0x00,0x44,0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20, ++0x00,0xe0,0xb0,0x21,0xac,0x62,0x00,0x00,0x00,0x80,0xf0,0x21,0x00,0x00,0xb8,0x21, ++0x16,0x20,0x00,0x2b,0x00,0x00,0xa0,0x21,0x27,0x85,0xb4,0x00,0x00,0x07,0x10,0x80, ++0x00,0x45,0x10,0x21,0x8c,0x53,0x00,0x00,0x00,0x15,0x18,0x80,0x00,0x65,0x18,0x21, ++0x92,0x62,0x00,0x16,0x8c,0x72,0x00,0x00,0x30,0x42,0x00,0x03,0x14,0x40,0x00,0x2d, ++0x00,0x00,0x00,0x00,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x03, ++0x14,0x40,0x00,0x28,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x18,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x38,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x14,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x3c,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x0f,0x3c,0x03,0xb0,0x09,0x3c,0x05,0xb0,0x05,0x34,0x63,0x01,0x44, ++0x34,0xa5,0x02,0x52,0x94,0x66,0x00,0x00,0x90,0xa2,0x00,0x00,0x8f,0xa3,0x00,0x4c, ++0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x04, ++0x30,0xc6,0xff,0xff,0x2c,0xc2,0x00,0x41,0x10,0x40,0x00,0x09,0x24,0x05,0x00,0x14, ++0x02,0x20,0x10,0x21,0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc, ++0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48, ++0x0c,0x00,0x07,0x0a,0x24,0x06,0x01,0x07,0x24,0x02,0x00,0x01,0x08,0x00,0x0a,0x2c, ++0xa3,0xc2,0x00,0x11,0x10,0xc0,0x00,0x1c,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x17, ++0x00,0xc0,0x88,0x21,0x96,0x54,0x00,0x1a,0x02,0xa0,0xb8,0x21,0x12,0x20,0xff,0xed, ++0x02,0x20,0x10,0x21,0x27,0x83,0xb4,0x00,0x00,0x17,0x10,0x80,0x00,0x43,0x10,0x21, ++0x8c,0x44,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x28,0x80,0x86,0x00,0x12, ++0x8c,0x62,0x00,0x00,0x00,0x14,0x2c,0x00,0x00,0x05,0x2c,0x03,0x00,0x46,0x10,0x21, ++0x8f,0xa6,0x00,0x4c,0x02,0xe0,0x38,0x21,0x03,0xc0,0x20,0x21,0x0c,0x00,0x07,0x2f, ++0xac,0x62,0x00,0x00,0x08,0x00,0x0a,0x2c,0xaf,0xd1,0x00,0x40,0x96,0x74,0x00,0x1a, ++0x08,0x00,0x0a,0x3f,0x02,0xc0,0xb8,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08, ++0x8c,0x50,0x00,0x00,0x02,0x60,0x20,0x21,0x0c,0x00,0x1e,0xf3,0x02,0x00,0x28,0x21, ++0x30,0x42,0x00,0xff,0x02,0x00,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x1e,0xf3, ++0xaf,0xa2,0x00,0x18,0x8f,0xa4,0x00,0x18,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0xed, ++0x30,0x50,0x00,0xff,0x12,0x00,0x00,0x18,0x24,0x11,0x00,0x01,0x96,0x63,0x00,0x14, ++0x96,0x44,0x00,0x14,0x27,0x85,0x90,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x00,0x04,0x18,0xc0,0x8c,0x46,0x00,0x08, ++0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x00,0x06,0x17,0x02, ++0x24,0x04,0x00,0xff,0x8c,0x63,0x00,0x08,0x10,0x44,0x00,0xd6,0x00,0x03,0x17,0x02, ++0x10,0x44,0x00,0xd5,0x3c,0x02,0x80,0x00,0x00,0x66,0x18,0x2b,0x24,0x11,0x00,0x02, ++0x24,0x02,0x00,0x01,0x00,0x43,0x88,0x0a,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x5a, ++0x24,0x02,0x00,0x02,0x16,0x22,0xff,0xbd,0x00,0x00,0x00,0x00,0x96,0x49,0x00,0x14, ++0x27,0x82,0x90,0x04,0x02,0xa0,0xb8,0x21,0x00,0x09,0x50,0xc0,0x01,0x49,0x18,0x21, ++0x00,0x03,0x40,0x80,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18,0x00,0x00,0x00,0x00, ++0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04,0x00,0x05,0x24,0x42, ++0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01,0x14,0x40,0x00,0x41, ++0x30,0x87,0x00,0x01,0x27,0x82,0x90,0x18,0x01,0x02,0x10,0x21,0x80,0x44,0x00,0x00, ++0x27,0x82,0xb5,0x78,0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80, ++0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05, ++0x27,0x84,0xb4,0xa0,0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2b, ++0x2c,0x64,0x00,0x0c,0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00, ++0x00,0x62,0x10,0x21,0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xe1, ++0x14,0x80,0x00,0x06,0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21, ++0x00,0x02,0x11,0x00,0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21, ++0x27,0x83,0x90,0x10,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21, ++0xa0,0x45,0x00,0x03,0xa0,0x45,0x00,0x00,0x24,0x02,0x00,0x08,0x12,0x02,0x00,0x0b, ++0x24,0x02,0x00,0x01,0x00,0x60,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x6f, ++0xaf,0xa2,0x00,0x10,0x30,0x54,0xff,0xff,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00, ++0x02,0x02,0x10,0x25,0x08,0x00,0x0a,0x3f,0xa2,0x42,0x00,0x16,0x00,0x60,0x28,0x21, ++0x02,0x40,0x20,0x21,0x0c,0x00,0x1f,0x20,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0a,0xc2, ++0x30,0x54,0xff,0xff,0x08,0x00,0x0a,0xaa,0x00,0x60,0x10,0x21,0x14,0x80,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x08,0x00,0x0a,0xaa, ++0x24,0x42,0x00,0x04,0x27,0x82,0x90,0x10,0x01,0x02,0x10,0x21,0x90,0x43,0x00,0x00, ++0x08,0x00,0x0a,0xba,0xa0,0x43,0x00,0x03,0x96,0x69,0x00,0x14,0x02,0xc0,0xb8,0x21, ++0x24,0x0b,0x00,0x01,0x00,0x09,0x10,0xc0,0x00,0x49,0x18,0x21,0x00,0x03,0x40,0x80, ++0x00,0x40,0x50,0x21,0x27,0x82,0x90,0x04,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04, ++0x00,0x05,0x24,0x42,0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01, ++0x10,0x40,0x00,0x0d,0x30,0x87,0x00,0x01,0x27,0x82,0x90,0x18,0x01,0x02,0x10,0x21, ++0x80,0x43,0x00,0x00,0x00,0x00,0x58,0x21,0x00,0x03,0x11,0x00,0x00,0x43,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80,0x27,0x83,0xb5,0x70, ++0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x04,0x11,0x60,0x00,0x4f,0x00,0x00,0x00,0x00, ++0x01,0x49,0x10,0x21,0x00,0x02,0x20,0x80,0x27,0x85,0x90,0x10,0x00,0x85,0x10,0x21, ++0x80,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x42,0x01,0x49,0x10,0x21, ++0x27,0x82,0x90,0x18,0x00,0x82,0x10,0x21,0x80,0x44,0x00,0x00,0x27,0x82,0xb5,0x78, ++0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x23, ++0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05,0x27,0x84,0xb4,0xa0, ++0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2c,0x2c,0x64,0x00,0x0c, ++0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21, ++0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xe1,0x14,0x80,0x00,0x06, ++0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00, ++0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21,0x27,0x83,0x90,0x10, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21,0xa0,0x45,0x00,0x03, ++0xa0,0x45,0x00,0x00,0x8f,0xa4,0x00,0x18,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x0c, ++0x00,0x60,0x28,0x21,0x24,0x02,0x00,0x01,0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x6f, ++0xaf,0xa2,0x00,0x10,0x8f,0xa3,0x00,0x18,0x30,0x54,0xff,0xff,0x92,0x62,0x00,0x16, ++0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x25,0x08,0x00,0x0a,0x3f,0xa2,0x62,0x00,0x16, ++0x02,0x60,0x20,0x21,0x0c,0x00,0x1f,0x20,0xaf,0xa0,0x00,0x10,0x08,0x00,0x0b,0x31, ++0x00,0x00,0x00,0x00,0x08,0x00,0x0b,0x19,0x00,0x60,0x10,0x21,0x14,0x80,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x08,0x00,0x0b,0x19, ++0x24,0x42,0x00,0x04,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x90,0x43,0x00,0x00, ++0x08,0x00,0x0b,0x29,0xa0,0x43,0x00,0x03,0x27,0x85,0x90,0x10,0x08,0x00,0x0b,0x45, ++0x01,0x49,0x10,0x21,0x3c,0x02,0x80,0x00,0x00,0x62,0x18,0x26,0x08,0x00,0x0a,0x7a, ++0x00,0xc2,0x30,0x26,0x12,0x00,0xff,0x2d,0x24,0x02,0x00,0x01,0x08,0x00,0x0a,0x7f, ++0x24,0x11,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0, ++0x24,0x42,0x2d,0x54,0x34,0x63,0x00,0x20,0x3c,0x05,0xb0,0x05,0xaf,0xb3,0x00,0x24, ++0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x28,0xaf,0xb0,0x00,0x18, ++0xac,0x62,0x00,0x00,0x34,0xa5,0x02,0x42,0x90,0xa2,0x00,0x00,0x00,0x80,0x90,0x21, ++0x24,0x11,0x00,0x10,0x30,0x53,0x00,0xff,0x24,0x02,0x00,0x10,0x12,0x22,0x00,0xcf, ++0x00,0x00,0x18,0x21,0x24,0x02,0x00,0x11,0x12,0x22,0x00,0xc1,0x24,0x02,0x00,0x12, ++0x12,0x22,0x00,0xb4,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0xad,0xae,0x43,0x00,0x40, ++0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x44,0x00,0x00,0x3c,0x03,0x00,0x02, ++0x34,0x63,0x00,0xff,0x00,0x83,0x80,0x24,0x00,0x10,0x14,0x43,0x10,0x40,0x00,0x05, ++0x00,0x00,0x00,0x00,0x8e,0x42,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x92, ++0x00,0x00,0x00,0x00,0x93,0x83,0x8b,0x71,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02, ++0x10,0x40,0x00,0x04,0x32,0x10,0x00,0xff,0x00,0x10,0x11,0xc3,0x14,0x40,0x00,0x86, ++0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x15,0x02,0x00,0x10,0x21,0x26,0x22,0x00,0x01, ++0x30,0x51,0x00,0xff,0x2e,0x23,0x00,0x13,0x14,0x60,0xff,0xdb,0x24,0x03,0x00,0x02, ++0x12,0x63,0x00,0x73,0x24,0x02,0x00,0x05,0x2a,0x62,0x00,0x03,0x10,0x40,0x00,0x58, ++0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x62,0x00,0x4b,0x02,0x40,0x20,0x21, ++0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x70,0x00,0xff,0x12,0x00,0x00,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x28, ++0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, ++0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24,0x24,0x02,0x00,0x07,0x02,0x40,0x20,0x21, ++0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, ++0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x24,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, ++0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xec,0x02,0x00,0x10,0x21, ++0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x24,0x02,0x00,0x05,0x02,0x40,0x20,0x21, ++0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, ++0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x28,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, ++0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xdc,0x02,0x00,0x10,0x21, ++0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c,0x24,0x02,0x00,0x03,0x02,0x40,0x20,0x21, ++0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, ++0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x2c,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, ++0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xcc,0x02,0x00,0x10,0x21, ++0x92,0x46,0x00,0x07,0x8e,0x43,0x00,0x30,0x24,0x02,0x00,0x02,0x02,0x40,0x20,0x21, ++0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea, ++0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x30,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x02,0x2c, ++0x08,0x00,0x0b,0x9b,0x30,0x42,0x00,0xff,0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24, ++0x24,0x02,0x00,0x07,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x09,0xea,0xaf,0xa3,0x00,0x14,0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x24, ++0x12,0x62,0x00,0x0d,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x08,0x16,0x62,0xff,0xa8, ++0x02,0x40,0x20,0x21,0x92,0x46,0x00,0x07,0x8e,0x42,0x00,0x30,0x24,0x05,0x00,0x03, ++0x24,0x07,0x00,0x01,0xaf,0xa3,0x00,0x10,0x0c,0x00,0x09,0xea,0xaf,0xa2,0x00,0x14, ++0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x30,0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c, ++0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x09,0xea,0xaf,0xa3,0x00,0x14,0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x2c, ++0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x01, ++0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x09,0xea,0xaf,0xa3,0x00,0x14, ++0x08,0x00,0x0b,0x94,0xae,0x42,0x00,0x28,0x0c,0x00,0x01,0x57,0x24,0x04,0x00,0x01, ++0x08,0x00,0x0b,0x85,0x00,0x00,0x00,0x00,0x8f,0x84,0xb4,0x40,0xae,0x40,0x00,0x34, ++0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x66,0x00,0x00,0x00,0x00,0x93,0x83,0x8b,0x71, ++0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02,0x10,0x40,0xff,0x69,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x01,0x57,0x00,0x00,0x20,0x21,0x08,0x00,0x0b,0x7d,0x00,0x00,0x00,0x00, ++0x02,0x40,0x20,0x21,0x0c,0x00,0x09,0x61,0x02,0x20,0x28,0x21,0x08,0x00,0x0b,0x71, ++0x3c,0x02,0xb0,0x05,0x8e,0x42,0x00,0x3c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x4a, ++0x00,0x00,0x00,0x00,0x8f,0x82,0xb4,0x48,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x0b,0x6e,0xae,0x43,0x00,0x3c, ++0x8e,0x42,0x00,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x3d,0x24,0x02,0x00,0x12, ++0x8f,0x82,0xb4,0x44,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00, ++0x00,0x02,0x18,0x2b,0x08,0x00,0x0b,0x6e,0xae,0x43,0x00,0x38,0x8e,0x42,0x00,0x34, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x30,0x24,0x02,0x00,0x11,0x8f,0x82,0xb4,0x40, ++0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b, ++0x08,0x00,0x0b,0x6e,0xae,0x43,0x00,0x34,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x27,0xbd,0xff,0xe0,0x34,0x63,0x00,0x20,0x24,0x42,0x31,0x08,0x3c,0x08,0xb0,0x03, ++0xaf,0xb1,0x00,0x14,0xac,0x62,0x00,0x00,0x35,0x08,0x01,0x00,0xaf,0xbf,0x00,0x18, ++0xaf,0xb0,0x00,0x10,0x91,0x03,0x00,0x00,0x00,0xa0,0x48,0x21,0x24,0x11,0x00,0x0a, ++0x2c,0xa5,0x00,0x04,0x24,0x02,0x00,0x10,0x00,0x45,0x88,0x0a,0x30,0x63,0x00,0x01, ++0x00,0xc0,0x28,0x21,0x14,0x60,0x00,0x02,0x00,0x11,0x40,0x40,0x02,0x20,0x40,0x21, ++0x84,0x83,0x00,0x0c,0x31,0x11,0x00,0xff,0x01,0x20,0x20,0x21,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x08,0x00,0x43,0x10,0x21, ++0x84,0x43,0x00,0x04,0x24,0x06,0x00,0x0e,0x10,0xe0,0x00,0x06,0x02,0x23,0x80,0x21, ++0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x0c,0x00,0x08,0xe3,0x00,0x00,0x00,0x00,0x02,0x11,0x18,0x21, ++0x08,0x00,0x0c,0x64,0x00,0x62,0x80,0x21,0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28, ++0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb5,0x00,0x24, ++0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x84,0x82,0x00,0x0c,0x3c,0x06,0xb0,0x03, ++0x34,0xc6,0x00,0x20,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, ++0x27,0x82,0x90,0x04,0x00,0x62,0x10,0x21,0x8c,0x55,0x00,0x18,0x3c,0x02,0x80,0x00, ++0x24,0x42,0x31,0xb8,0xac,0xc2,0x00,0x00,0x8e,0xb0,0x00,0x08,0x27,0x82,0x90,0x08, ++0x00,0x62,0x18,0x21,0x90,0x71,0x00,0x07,0x00,0x10,0x86,0x43,0x32,0x10,0x00,0x01, ++0x00,0xa0,0x38,0x21,0x02,0x00,0x30,0x21,0x00,0xa0,0x98,0x21,0x02,0x20,0x28,0x21, ++0x0c,0x00,0x0c,0x42,0x00,0x80,0x90,0x21,0x02,0x20,0x20,0x21,0x02,0x00,0x28,0x21, ++0x24,0x06,0x00,0x14,0x0c,0x00,0x08,0xe3,0x00,0x40,0xa0,0x21,0x86,0x43,0x00,0x0c, ++0x3c,0x09,0xb0,0x09,0x3c,0x08,0xb0,0x09,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0x80,0x43,0x00,0x06, ++0x3c,0x07,0xb0,0x09,0x3c,0x05,0xb0,0x09,0x28,0x62,0x00,0x00,0x24,0x64,0x00,0x03, ++0x00,0x82,0x18,0x0b,0x00,0x03,0x18,0x83,0x3c,0x02,0xb0,0x09,0x00,0x03,0x18,0x80, ++0x34,0x42,0x01,0x02,0x35,0x29,0x01,0x10,0x35,0x08,0x01,0x14,0x34,0xe7,0x01,0x20, ++0x34,0xa5,0x01,0x24,0xa4,0x54,0x00,0x00,0x12,0x60,0x00,0x11,0x02,0xa3,0xa8,0x21, ++0x8e,0xa2,0x00,0x0c,0x8e,0xa3,0x00,0x08,0x00,0x02,0x14,0x00,0x00,0x03,0x1c,0x02, ++0x00,0x43,0x10,0x21,0xad,0x22,0x00,0x00,0x8e,0xa3,0x00,0x0c,0x00,0x00,0x00,0x00, ++0x00,0x03,0x1c,0x02,0xa5,0x03,0x00,0x00,0x8f,0xbf,0x00,0x28,0x7b,0xb4,0x01,0x3c, ++0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, ++0x8e,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0xad,0x22,0x00,0x00,0x8e,0xa4,0x00,0x08, ++0x00,0x00,0x00,0x00,0xa5,0x04,0x00,0x00,0x7a,0xa2,0x00,0x7c,0x00,0x00,0x00,0x00, ++0x00,0x03,0x1c,0x00,0x00,0x02,0x14,0x02,0x00,0x62,0x18,0x21,0xac,0xe3,0x00,0x00, ++0x8e,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x02,0x08,0x00,0x0c,0xb6, ++0xa4,0xa2,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x1c,0xaf,0xb1,0x00,0x14,0x84,0x82,0x00,0x0c,0x00,0x80,0x90,0x21, ++0x3c,0x05,0xb0,0x03,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80, ++0x27,0x82,0x90,0x04,0x00,0x82,0x10,0x21,0x8c,0x51,0x00,0x18,0x3c,0x02,0x80,0x00, ++0x34,0xa5,0x00,0x20,0x24,0x42,0x33,0x34,0x27,0x83,0x90,0x08,0xac,0xa2,0x00,0x00, ++0x00,0x83,0x20,0x21,0x3c,0x02,0xb0,0x03,0x90,0x86,0x00,0x07,0x34,0x42,0x01,0x00, ++0x8e,0x23,0x00,0x08,0x90,0x44,0x00,0x00,0x2c,0xc5,0x00,0x04,0x24,0x02,0x00,0x10, ++0x24,0x10,0x00,0x0a,0x00,0x45,0x80,0x0a,0x00,0x03,0x1e,0x43,0x30,0x84,0x00,0x01, ++0x30,0x65,0x00,0x01,0x14,0x80,0x00,0x02,0x00,0x10,0x10,0x40,0x02,0x00,0x10,0x21, ++0x00,0xc0,0x20,0x21,0x24,0x06,0x00,0x20,0x0c,0x00,0x08,0xe3,0x30,0x50,0x00,0xff, ++0x86,0x44,0x00,0x0c,0x27,0x85,0x90,0x10,0x3c,0x06,0xb0,0x09,0x00,0x04,0x18,0xc0, ++0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21,0x80,0x64,0x00,0x06, ++0x00,0x50,0x10,0x21,0x34,0xc6,0x01,0x02,0x24,0x85,0x00,0x03,0x28,0x83,0x00,0x00, ++0x00,0xa3,0x20,0x0b,0x00,0x04,0x20,0x83,0x00,0x04,0x20,0x80,0xa4,0xc2,0x00,0x00, ++0x02,0x24,0x20,0x21,0x8c,0x83,0x00,0x04,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x10, ++0xac,0x43,0x00,0x00,0x8c,0x86,0x00,0x08,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x14, ++0xa4,0x46,0x00,0x00,0x8c,0x85,0x00,0x0c,0x8c,0x82,0x00,0x08,0x3c,0x06,0xb0,0x09, ++0x00,0x05,0x2c,0x00,0x00,0x02,0x14,0x02,0x00,0xa2,0x28,0x21,0x34,0xc6,0x01,0x20, ++0xac,0xc5,0x00,0x00,0x8c,0x83,0x00,0x0c,0x3c,0x05,0xb0,0x09,0x34,0xa5,0x01,0x24, ++0x00,0x03,0x1c,0x02,0xa4,0xa3,0x00,0x00,0x92,0x42,0x00,0x0a,0x3c,0x03,0xb0,0x09, ++0x34,0x63,0x01,0x30,0x00,0x02,0x13,0x00,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff, ++0xa4,0x62,0x00,0x00,0x86,0x44,0x00,0x0c,0x27,0x83,0x90,0x18,0x8f,0xbf,0x00,0x1c, ++0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x94,0x44,0x00,0x02,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x3c,0x05,0xb0,0x09, ++0x34,0xa5,0x01,0x32,0xa4,0xa4,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, ++0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0xaf,0xb0,0x00,0x10, ++0x34,0x42,0x00,0x20,0x00,0xa0,0x80,0x21,0x24,0x63,0x34,0xc0,0x00,0x05,0x2c,0x43, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00,0x10,0xa0,0x00,0x05, ++0x00,0x80,0x88,0x21,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0xb6, ++0x00,0x00,0x00,0x00,0x32,0x10,0x00,0xff,0x12,0x00,0x00,0x4c,0x00,0x00,0x10,0x21, ++0x24,0x02,0x00,0x08,0x12,0x02,0x00,0xa3,0x2a,0x02,0x00,0x09,0x10,0x40,0x00,0x89, ++0x24,0x02,0x00,0x40,0x24,0x04,0x00,0x02,0x12,0x04,0x00,0x79,0x2a,0x02,0x00,0x03, ++0x10,0x40,0x00,0x69,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x02,0x00,0x5a, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x00,0x08,0x3c,0x03,0x80,0x00, ++0xa2,0x20,0x00,0x4e,0xac,0x43,0x00,0x00,0x82,0x24,0x00,0x11,0x92,0x27,0x00,0x11, ++0x10,0x80,0x00,0x4e,0x00,0x00,0x00,0x00,0x92,0x26,0x00,0x0a,0x24,0x02,0x00,0x12, ++0x10,0x46,0x00,0x09,0x30,0xc2,0x00,0xff,0x27,0x83,0xb4,0x00,0x00,0x02,0x10,0x80, ++0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x83,0x00,0x14, ++0x00,0x00,0x00,0x00,0xa6,0x23,0x00,0x0c,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x40, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x03,0xa2,0x23,0x00,0x10, ++0x14,0x60,0x00,0x2b,0x30,0x65,0x00,0x01,0x30,0xc2,0x00,0xff,0x27,0x83,0xb4,0x00, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x82,0x23,0x00,0x12, ++0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x30,0x42,0x00,0x01, ++0x00,0x62,0x18,0x21,0x00,0x03,0x26,0x00,0x14,0x80,0x00,0x18,0xa2,0x23,0x00,0x12, ++0x00,0x07,0x16,0x00,0x14,0x40,0x00,0x11,0x24,0x02,0x00,0x01,0x96,0x23,0x00,0x0c, ++0x27,0x84,0x90,0x10,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00,0x3c,0x02,0xb0,0x00, ++0x00,0x65,0x18,0x21,0x00,0x62,0x18,0x21,0x90,0x64,0x00,0x00,0x90,0x62,0x00,0x04, ++0xa2,0x20,0x00,0x15,0xa3,0x80,0x8b,0xd4,0x24,0x02,0x00,0x01,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x0c,0xcd, ++0x02,0x20,0x20,0x21,0x92,0x27,0x00,0x11,0x08,0x00,0x0d,0x7d,0x00,0x07,0x16,0x00, ++0x0c,0x00,0x0c,0x6e,0x02,0x20,0x20,0x21,0x86,0x23,0x00,0x0c,0x27,0x84,0x90,0x08, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x20,0x21, ++0x90,0x85,0x00,0x07,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0xa2,0x25,0x00,0x13, ++0x90,0x83,0x00,0x07,0x08,0x00,0x0d,0x95,0xa0,0x43,0x00,0x02,0x92,0x26,0x00,0x0a, ++0x08,0x00,0x0d,0x5e,0x30,0xc2,0x00,0xff,0x8e,0x22,0x00,0x24,0x00,0x00,0x00,0x00, ++0x10,0x50,0x00,0x07,0xa2,0x20,0x00,0x08,0x24,0x02,0x00,0x07,0xa2,0x22,0x00,0x0a, ++0x92,0x22,0x00,0x27,0xae,0x20,0x00,0x24,0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x04, ++0x08,0x00,0x0d,0xaf,0x24,0x02,0x00,0x06,0x16,0x02,0xff,0x9b,0x3c,0x02,0xb0,0x05, ++0x8e,0x23,0x00,0x2c,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x07,0xa2,0x24,0x00,0x08, ++0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2f,0xae,0x20,0x00,0x2c, ++0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x06,0x08,0x00,0x0d,0xbe,0xa2,0x20,0x00,0x0a, ++0x8e,0x22,0x00,0x28,0x24,0x03,0x00,0x01,0x24,0x04,0x00,0x01,0x10,0x44,0x00,0x07, ++0xa2,0x23,0x00,0x08,0x24,0x02,0x00,0x05,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2b, ++0xae,0x20,0x00,0x28,0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x05,0x08,0x00,0x0d,0xca, ++0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x12,0x2a,0x02,0x00,0x41,0x10,0x40,0x00,0x09, ++0x24,0x02,0x00,0x80,0x24,0x02,0x00,0x20,0x16,0x02,0xff,0x7b,0x3c,0x02,0xb0,0x05, ++0x24,0x02,0x00,0x12,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x51, ++0xae,0x20,0x00,0x3c,0x16,0x02,0xff,0x74,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10, ++0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x51,0xae,0x20,0x00,0x34, ++0x24,0x02,0x00,0x11,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x0d,0x51, ++0xae,0x20,0x00,0x38,0x8e,0x24,0x00,0x30,0x24,0x02,0x00,0x03,0x24,0x03,0x00,0x01, ++0x10,0x83,0x00,0x07,0xa2,0x22,0x00,0x08,0x24,0x02,0x00,0x02,0xa2,0x22,0x00,0x0a, ++0x92,0x22,0x00,0x33,0xae,0x20,0x00,0x30,0x08,0x00,0x0d,0x51,0xa2,0x22,0x00,0x07, ++0x08,0x00,0x0d,0xf0,0xa2,0x24,0x00,0x0a,0x8f,0x84,0xb4,0x40,0xae,0x20,0x00,0x34, ++0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x66,0x32,0x10,0x00,0xff,0x08,0x00,0x0d,0x42, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x37,0xf4, ++0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x80,0xa2,0x00,0x15,0x3c,0x06,0xb0,0x05, ++0x10,0x40,0x00,0x0a,0x34,0xc6,0x02,0x54,0x83,0x83,0x8b,0xd4,0x00,0x00,0x00,0x00, ++0xac,0x83,0x00,0x24,0x8c,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42, ++0x30,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x28,0x8c,0x82,0x00,0x2c, ++0x3c,0x06,0xb0,0x05,0x34,0xc6,0x04,0x50,0x00,0x02,0x18,0x43,0x30,0x63,0x00,0x01, ++0x10,0x40,0x00,0x04,0x30,0x45,0x00,0x01,0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08, ++0xac,0x85,0x00,0x24,0x90,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, ++0x30,0x43,0x00,0x02,0x30,0x42,0x00,0x01,0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08, ++0xac,0x82,0x00,0x24,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd8, ++0x34,0x63,0x00,0x20,0x24,0x42,0x38,0x84,0xac,0x62,0x00,0x00,0xaf,0xb1,0x00,0x1c, ++0xaf,0xbf,0x00,0x20,0xaf,0xb0,0x00,0x18,0x90,0xa6,0x00,0x0a,0x27,0x83,0xb4,0x00, ++0x00,0xa0,0x88,0x21,0x00,0x06,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00, ++0x80,0xa5,0x00,0x11,0x92,0x03,0x00,0x12,0x10,0xa0,0x00,0x04,0xa2,0x20,0x00,0x15, ++0x24,0x02,0x00,0x12,0x10,0xc2,0x00,0xda,0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x12, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x67,0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x12, ++0xa2,0x00,0x00,0x19,0x86,0x23,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x20,0x00,0x43,0x10,0x21, ++0xa0,0x40,0x00,0x00,0x92,0x03,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0xdf, ++0xa2,0x03,0x00,0x16,0x82,0x02,0x00,0x12,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20, ++0x00,0x00,0x00,0x00,0x92,0x23,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x45, ++0x24,0x02,0x00,0x01,0xa2,0x20,0x00,0x04,0x92,0x08,0x00,0x04,0x00,0x00,0x00,0x00, ++0x15,0x00,0x00,0x1e,0x24,0x02,0x00,0x01,0x92,0x07,0x00,0x0a,0xa2,0x02,0x00,0x17, ++0x92,0x02,0x00,0x16,0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xe4,0x10,0x60,0x00,0x03, ++0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16,0x11,0x00,0x00,0x05, ++0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02, ++0xa2,0x02,0x00,0x16,0x92,0x02,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x08, ++0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x02,0x00,0x14, ++0x8f,0xbf,0x00,0x20,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, ++0x96,0x02,0x00,0x00,0x08,0x00,0x0e,0x6c,0xa6,0x02,0x00,0x14,0x92,0x07,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x58, ++0xa2,0x00,0x00,0x17,0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06,0x27,0x86,0x90,0x00, ++0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21, ++0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21, ++0x8c,0x66,0x00,0x08,0x8c,0x45,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xc3,0x20,0x24, ++0x10,0x80,0x00,0x08,0x00,0xa3,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, ++0x10,0x80,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0xa6,0x18,0x2b,0x08,0x00,0x0e,0x58, ++0xa2,0x03,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0xa6,0x18,0x2b,0x08,0x00,0x0e,0x8c, ++0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05, ++0x24,0x02,0x00,0x03,0x14,0x62,0xff,0xb8,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x52, ++0xa2,0x20,0x00,0x07,0x08,0x00,0x0e,0x52,0xa2,0x20,0x00,0x06,0x08,0x00,0x0e,0x52, ++0xa2,0x20,0x00,0x05,0x82,0x22,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x69, ++0x2c,0x62,0x00,0x02,0x10,0x40,0x00,0x49,0x3c,0x02,0xb0,0x09,0x92,0x25,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x3b, ++0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, ++0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24, ++0xa0,0x83,0x00,0x00,0x86,0x23,0x00,0x0c,0x96,0x26,0x00,0x0c,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80,0x27,0x83,0x90,0x04,0x00,0xa3,0x18,0x21, ++0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x18,0x24,0x07,0x00,0x01,0x93,0x82,0x8b,0x71, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x0a,0x24,0x05,0x00,0x24, ++0x00,0x06,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1b,0x66,0x02,0x00,0x20,0x21, ++0x92,0x02,0x00,0x16,0xa2,0x00,0x00,0x12,0x30,0x42,0x00,0xe7,0x08,0x00,0x0e,0x49, ++0xa2,0x02,0x00,0x16,0xf0,0xc5,0x00,0x06,0x00,0x00,0x28,0x12,0x27,0x82,0x90,0x00, ++0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49,0x3c,0x04,0x00,0x80,0x96,0x26,0x00,0x0c, ++0x08,0x00,0x0e,0xc9,0x00,0x06,0x2c,0x00,0x27,0x83,0x90,0x10,0x27,0x82,0x90,0x18, ++0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00,0x90,0x65,0x00,0x05, ++0x93,0x82,0x80,0x10,0x00,0x00,0x30,0x21,0x0c,0x00,0x21,0x9a,0xaf,0xa2,0x00,0x10, ++0x96,0x26,0x00,0x0c,0x08,0x00,0x0e,0xc3,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xcd, ++0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f, ++0x24,0x02,0x00,0x80,0x08,0x00,0x0e,0xb2,0x00,0xa2,0x10,0x07,0x86,0x26,0x00,0x0c, ++0x3c,0x03,0xb0,0x09,0x34,0x42,0x01,0x72,0x34,0x63,0x01,0x78,0x94,0x47,0x00,0x00, ++0x8c,0x65,0x00,0x00,0x00,0x06,0x10,0xc0,0x00,0x46,0x10,0x21,0x3c,0x04,0xb0,0x09, ++0xae,0x25,0x00,0x1c,0x34,0x84,0x01,0x7c,0x27,0x83,0x90,0x04,0x00,0x02,0x10,0x80, ++0x8c,0x85,0x00,0x00,0x00,0x43,0x10,0x21,0x8c,0x43,0x00,0x18,0xae,0x25,0x00,0x20, ++0xa6,0x27,0x00,0x18,0x8c,0x66,0x00,0x08,0x02,0x20,0x20,0x21,0x0c,0x00,0x0f,0x19, ++0x00,0x00,0x28,0x21,0x86,0x25,0x00,0x18,0x8e,0x26,0x00,0x1c,0x8e,0x27,0x00,0x20, ++0x02,0x20,0x20,0x21,0x0c,0x00,0x1c,0x68,0xaf,0xa2,0x00,0x10,0x08,0x00,0x0e,0x49, ++0xa2,0x02,0x00,0x12,0x92,0x22,0x00,0x08,0x08,0x00,0x0e,0x49,0xa2,0x22,0x00,0x09, ++0xa2,0x20,0x00,0x11,0x80,0x82,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xac,0x40,0x00,0x00,0x08,0x00,0x0e,0x49, ++0xa0,0x80,0x00,0x50,0x94,0x8a,0x00,0x0c,0x24,0x03,0x00,0x24,0x00,0x80,0x70,0x21, ++0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03,0x24,0x42,0x3c,0x64,0xf1,0x43,0x00,0x06, ++0x34,0x84,0x00,0x20,0x00,0x00,0x18,0x12,0x00,0xa0,0x68,0x21,0xac,0x82,0x00,0x00, ++0x27,0x85,0x90,0x10,0x27,0x82,0x90,0x0f,0x27,0xbd,0xff,0xf8,0x00,0x62,0x60,0x21, ++0x00,0x65,0x58,0x21,0x00,0x00,0xc0,0x21,0x11,0xa0,0x00,0xcc,0x00,0x00,0x78,0x21, ++0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x91,0x87,0x00,0x00,0x80,0x48,0x00,0x04, ++0x03,0xa0,0x60,0x21,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x48,0x80,0x27,0x83,0x90,0x04,0xa3,0xa7,0x00,0x00, ++0x01,0x23,0x18,0x21,0x8c,0x64,0x00,0x18,0x25,0x02,0xff,0xff,0x00,0x48,0x40,0x0b, ++0x8c,0x83,0x00,0x04,0x2d,0x05,0x00,0x07,0x24,0x02,0x00,0x06,0x30,0x63,0x00,0x08, ++0x14,0x60,0x00,0x35,0x00,0x45,0x40,0x0a,0x93,0xa7,0x00,0x00,0x27,0x82,0x90,0x18, ++0x01,0x22,0x10,0x21,0x30,0xe3,0x00,0xf0,0x38,0x63,0x00,0x50,0x30,0xe5,0x00,0xff, ++0x00,0x05,0x20,0x2b,0x00,0x03,0x18,0x2b,0x00,0x64,0x18,0x24,0x90,0x49,0x00,0x00, ++0x10,0x60,0x00,0x16,0x30,0xe4,0x00,0x0f,0x24,0x02,0x00,0x04,0x10,0xa2,0x00,0x9d, ++0x00,0x00,0x00,0x00,0x11,0xa0,0x00,0x3a,0x2c,0xa2,0x00,0x0c,0x10,0x40,0x00,0x02, ++0x24,0x84,0x00,0x0c,0x00,0xe0,0x20,0x21,0x30,0x84,0x00,0xff,0x00,0x04,0x10,0x40, ++0x27,0x83,0xbb,0x1c,0x00,0x44,0x10,0x21,0x00,0x43,0x10,0x21,0x90,0x47,0x00,0x00, ++0x00,0x00,0x00,0x00,0x2c,0xe3,0x00,0x0c,0xa3,0xa7,0x00,0x00,0x10,0x60,0x00,0x02, ++0x24,0xe2,0x00,0x04,0x00,0xe0,0x10,0x21,0xa3,0xa2,0x00,0x00,0x91,0x65,0x00,0x00, ++0x91,0x82,0x00,0x00,0x30,0xa3,0x00,0xff,0x00,0x62,0x10,0x2b,0x10,0x40,0x00,0x0e, ++0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0x60,0x20,0x21,0x30,0xa2,0x00,0x0f, ++0x24,0x44,0x00,0x0c,0x00,0x04,0x10,0x40,0x00,0x44,0x20,0x21,0x27,0x83,0xbb,0x1c, ++0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x02,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05, ++0x00,0x09,0x11,0x00,0xa1,0x85,0x00,0x00,0x93,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x08,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x27,0x83,0xb4,0xa8,0x00,0x43,0x10,0x21, ++0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x83,0x00,0x0c,0x14,0x60,0x00,0x06, ++0x00,0x80,0x10,0x21,0x00,0x18,0x10,0x40,0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00, ++0x00,0x82,0x10,0x21,0x24,0x42,0x00,0x04,0x08,0x00,0x0f,0x7a,0xa1,0x82,0x00,0x00, ++0x8f,0x8d,0x81,0x5c,0x00,0x00,0x00,0x00,0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xd1,0x00,0x00,0x28,0x21,0x00,0x06,0x74,0x82, ++0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x03,0x00,0xe0,0x10,0x21, ++0x30,0xe2,0x00,0x0f,0x24,0x42,0x00,0x0c,0x30,0x44,0x00,0xff,0xa3,0xa2,0x00,0x00, ++0x24,0x02,0x00,0x0c,0x10,0x82,0x00,0x0d,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x04,0x18,0x40,0x00,0x49,0x10,0x23,0x00,0x64,0x18,0x21, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x27,0x84,0xb4,0xa8,0x00,0x44,0x10,0x21, ++0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0xa7,0x00,0x00,0x00,0x0a,0x1c,0x00, ++0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x83,0x90,0x04,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00, ++0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0x00,0x33, ++0x00,0x06,0x14,0x42,0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80, ++0x00,0x49,0x10,0x23,0x27,0x83,0xb5,0x78,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x90,0x44,0x00,0x04,0x90,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x64,0xc0,0x24, ++0x93,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xe2,0x00,0x0f,0x10,0x40,0x00,0x0f, ++0x31,0xcf,0x00,0x01,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x90,0x00,0x00,0x44,0x10,0x21, ++0x84,0x43,0x00,0x06,0x00,0x00,0x00,0x00,0x28,0x63,0x06,0x41,0x14,0x60,0x00,0x04, ++0x30,0xe2,0x00,0xff,0x24,0x07,0x00,0x0f,0xa3,0xa7,0x00,0x00,0x30,0xe2,0x00,0xff, ++0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x06,0x00,0xe0,0x10,0x21,0x00,0x18,0x10,0x40, ++0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x47,0x10,0x21,0x24,0x42,0x00,0x04, ++0xa3,0xa2,0x00,0x00,0x00,0x40,0x38,0x21,0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00, ++0x24,0xa4,0x00,0x01,0x30,0x85,0xff,0xff,0x00,0xa3,0x18,0x2b,0x14,0x60,0xff,0xad, ++0x30,0xe2,0x00,0xff,0x08,0x00,0x0f,0x67,0x00,0x00,0x00,0x00,0x08,0x00,0x0f,0xc8, ++0x30,0x58,0x00,0x01,0x81,0xc2,0x00,0x48,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x73, ++0x00,0x00,0x00,0x00,0x08,0x00,0x0f,0x55,0x00,0x00,0x00,0x00,0x00,0x0a,0x1c,0x00, ++0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x45,0x10,0x21,0x80,0x48,0x00,0x05,0x91,0x67,0x00,0x00,0x08,0x00,0x0f,0x35, ++0x03,0xa0,0x58,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, ++0x24,0x42,0x40,0x04,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0, ++0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, ++0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38, ++0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0x84,0x82,0x00,0x0c,0x27,0x93,0x90,0x04, ++0x3c,0x05,0xb0,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, ++0x00,0x73,0x10,0x21,0x8c,0x5e,0x00,0x18,0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20, ++0x24,0x42,0x40,0x1c,0xac,0xa2,0x00,0x00,0x8f,0xd0,0x00,0x08,0x27,0x95,0x90,0x10, ++0x00,0x75,0x18,0x21,0x00,0x00,0x28,0x21,0x02,0x00,0x30,0x21,0x90,0x71,0x00,0x00, ++0x0c,0x00,0x0f,0x19,0x00,0x80,0xb0,0x21,0x00,0x40,0x90,0x21,0x00,0x10,0x14,0x42, ++0x30,0x54,0x00,0x01,0x02,0x40,0x20,0x21,0x00,0x10,0x14,0x82,0x02,0x80,0x28,0x21, ++0x12,0x51,0x00,0x23,0x00,0x10,0xbf,0xc2,0x86,0xc3,0x00,0x0c,0x30,0x50,0x00,0x01, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21, ++0xa0,0x52,0x00,0x00,0x86,0xc3,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x53,0x30,0x21,0x8c,0xc7,0x00,0x18, ++0x27,0x83,0x90,0x00,0x00,0x43,0x10,0x21,0x8c,0xe3,0x00,0x04,0x84,0x46,0x00,0x06, ++0x00,0x03,0x19,0x42,0x0c,0x00,0x08,0xe3,0x30,0x73,0x00,0x01,0x00,0x40,0x88,0x21, ++0x02,0x40,0x20,0x21,0x02,0x80,0x28,0x21,0x16,0xe0,0x00,0x10,0x02,0x00,0x30,0x21, ++0x86,0xc2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, ++0x00,0x03,0x18,0x80,0x27,0x82,0x90,0x08,0x00,0x62,0x18,0x21,0xa4,0x71,0x00,0x04, ++0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, ++0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x86,0xc3,0x00,0x0c, ++0xaf,0xb3,0x00,0x10,0xaf,0xa0,0x00,0x14,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21,0x80,0x47,0x00,0x06,0x00,0x00,0x00,0x00, ++0x24,0xe7,0x00,0x02,0x00,0x07,0x17,0xc2,0x00,0xe2,0x38,0x21,0x00,0x07,0x38,0x43, ++0x00,0x07,0x38,0x40,0x0c,0x00,0x09,0x0a,0x03,0xc7,0x38,0x21,0x08,0x00,0x10,0x48, ++0x02,0x22,0x88,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0, ++0x34,0x63,0x00,0x20,0x24,0x42,0x41,0xa4,0xaf,0xb2,0x00,0x20,0xac,0x62,0x00,0x00, ++0xaf,0xbf,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18, ++0x3c,0x02,0xb0,0x03,0x90,0x83,0x00,0x0a,0x34,0x42,0x01,0x04,0x94,0x45,0x00,0x00, ++0x00,0x03,0x18,0x80,0x27,0x82,0xb4,0x00,0x00,0x62,0x18,0x21,0x30,0xa6,0xff,0xff, ++0x8c,0x71,0x00,0x00,0x80,0x85,0x00,0x12,0x30,0xc9,0x00,0xff,0x00,0x06,0x32,0x02, ++0xa4,0x86,0x00,0x44,0xa4,0x89,0x00,0x46,0x82,0x22,0x00,0x12,0x00,0x80,0x90,0x21, ++0x10,0xa0,0x00,0x1b,0xa0,0x80,0x00,0x15,0x00,0xc5,0x10,0x2a,0x10,0x40,0x00,0x14, ++0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x19,0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x20, ++0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00,0xa0,0x80,0x00,0x12,0x92,0x22,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xdf,0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x28, ++0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, ++0x0c,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x97,0x00,0x00,0x00,0x00, ++0x28,0x42,0x00,0x02,0x10,0x40,0x01,0x76,0x00,0x00,0x28,0x21,0x94,0x87,0x00,0x0c, ++0x00,0x00,0x00,0x00,0x00,0xe0,0x10,0x21,0x00,0x02,0x14,0x00,0x00,0x02,0x14,0x03, ++0x00,0x07,0x24,0x00,0x00,0x04,0x24,0x03,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, ++0x00,0x04,0x28,0xc0,0x00,0xa4,0x28,0x21,0x27,0x82,0x90,0x20,0x00,0x03,0x18,0x80, ++0x00,0x62,0x18,0x21,0x00,0x05,0x28,0x80,0x27,0x82,0x90,0x08,0x00,0xa2,0x10,0x21, ++0x8c,0x68,0x00,0x00,0x80,0x44,0x00,0x06,0x27,0x82,0x90,0x10,0x00,0x08,0x1d,0x02, ++0x00,0xa2,0x28,0x21,0x38,0x84,0x00,0x00,0x30,0x63,0x00,0x01,0x01,0x24,0x30,0x0b, ++0x80,0xaa,0x00,0x04,0x80,0xa9,0x00,0x05,0x10,0x60,0x00,0x02,0x00,0x08,0x14,0x02, ++0x30,0x46,0x00,0x0f,0x15,0x20,0x00,0x28,0x01,0x49,0x10,0x21,0x15,0x40,0x00,0x11, ++0x30,0xe3,0xff,0xff,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa8,0x00,0xff, ++0x2d,0x02,0x00,0x04,0x10,0x40,0x01,0x46,0x2d,0x02,0x00,0x10,0x3c,0x04,0xb0,0x05, ++0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x01,0x02,0x10,0x04, ++0x00,0x62,0x18,0x25,0xa0,0x83,0x00,0x00,0x96,0x47,0x00,0x0c,0x00,0x00,0x00,0x00, ++0x30,0xe3,0xff,0xff,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x27,0x84,0x90,0x10, ++0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00, ++0x3c,0x04,0xb0,0x00,0x00,0x65,0x18,0x21,0x00,0x64,0x20,0x21,0x94,0x82,0x00,0x00, ++0x82,0x43,0x00,0x10,0x00,0x02,0x14,0x00,0x14,0x60,0x00,0x06,0x00,0x02,0x3c,0x03, ++0x30,0xe2,0x00,0x04,0x14,0x40,0x00,0x04,0x01,0x49,0x10,0x21,0x34,0xe2,0x08,0x00, ++0xa4,0x82,0x00,0x00,0x01,0x49,0x10,0x21,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, ++0x00,0x46,0x10,0x2a,0x10,0x40,0x00,0x7c,0x00,0x00,0x00,0x00,0x82,0x42,0x00,0x10, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x86,0x43,0x00,0x0c, ++0x25,0x44,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x04,0x92,0x23,0x00,0x16, ++0x02,0x40,0x20,0x21,0x30,0x63,0x00,0xfb,0x08,0x00,0x10,0x9c,0xa2,0x23,0x00,0x16, ++0x86,0x43,0x00,0x0c,0x25,0x24,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x05, ++0x86,0x45,0x00,0x0c,0x0c,0x00,0x1e,0xea,0x02,0x20,0x20,0x21,0x10,0x40,0x00,0x5a, ++0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff, ++0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x4c,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05, ++0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04, ++0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x92,0x45,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x33,0x24,0x02,0x00,0x01, ++0xa2,0x40,0x00,0x04,0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0c, ++0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17,0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x96,0x22,0x00,0x06,0x08,0x00,0x10,0x97, ++0xa6,0x22,0x00,0x14,0x96,0x22,0x00,0x00,0x08,0x00,0x10,0x97,0xa6,0x22,0x00,0x14, ++0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00, ++0x08,0x00,0x11,0x26,0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06, ++0x27,0x86,0x90,0x00,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0, ++0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80, ++0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00, ++0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04, ++0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b, ++0x08,0x00,0x11,0x26,0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b, ++0x08,0x00,0x11,0x49,0x00,0x00,0x00,0x00,0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02, ++0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xca,0x00,0x00,0x00,0x00, ++0x08,0x00,0x11,0x21,0xa2,0x40,0x00,0x07,0x08,0x00,0x11,0x21,0xa2,0x40,0x00,0x06, ++0x08,0x00,0x11,0x21,0xa2,0x40,0x00,0x05,0x14,0x40,0xff,0xbe,0x3c,0x04,0xb0,0x05, ++0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80, ++0x08,0x00,0x11,0x18,0x00,0xa2,0x10,0x07,0x0c,0x00,0x10,0x07,0x02,0x40,0x20,0x21, ++0x08,0x00,0x10,0x97,0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00, ++0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x99,0x2c,0xc2,0x00,0x10, ++0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01, ++0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00, ++0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x80, ++0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x86,0x43,0x00,0x0c,0x27,0x93,0x90,0x04, ++0x96,0x47,0x00,0x0c,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80, ++0x00,0xb3,0x18,0x21,0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x64,0x00,0x00,0x30,0x21, ++0x00,0x07,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x53,0x10,0x21,0x8c,0x43,0x00,0x18,0x93,0x82,0x8b,0x71, ++0x8c,0x64,0x00,0x04,0x30,0x42,0x00,0x01,0x00,0x04,0x21,0x42,0x14,0x40,0x00,0x4d, ++0x30,0x90,0x00,0x01,0x00,0x07,0x2c,0x00,0x00,0x05,0x2c,0x03,0x0c,0x00,0x1b,0x66, ++0x02,0x20,0x20,0x21,0x96,0x26,0x00,0x06,0x12,0x00,0x00,0x14,0x30,0xc5,0xff,0xff, ++0x02,0x60,0x90,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x52,0x18,0x21,0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b, ++0x02,0x20,0x20,0x21,0x8c,0x63,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x62,0x00,0x04, ++0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x0c,0x00,0x1b,0x66,0x30,0x50,0x00,0x01, ++0x96,0x26,0x00,0x06,0x16,0x00,0xff,0xef,0x30,0xc5,0xff,0xff,0x92,0x22,0x00,0x04, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0d,0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17, ++0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00, ++0xa6,0x26,0x00,0x14,0x92,0x22,0x00,0x16,0x08,0x00,0x10,0x96,0x30,0x42,0x00,0xc3, ++0x96,0x22,0x00,0x00,0x08,0x00,0x11,0xbd,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x11,0xb8, ++0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x30,0xc5,0xff,0xff,0x00,0x05,0x18,0xc0, ++0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21,0x27,0x84,0x90,0x00, ++0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21,0x00,0x03,0x18,0x80,0x8c,0x45,0x00,0x08, ++0x00,0x64,0x18,0x21,0x8c,0x64,0x00,0x08,0x3c,0x02,0x80,0x00,0x00,0xa2,0x38,0x24, ++0x10,0xe0,0x00,0x08,0x00,0x82,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21, ++0x10,0xe0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x11,0xb8, ++0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x11,0xdc, ++0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x24,0xf0,0xe5,0x00,0x06,0x00,0x00,0x28,0x12, ++0x27,0x82,0x90,0x00,0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49,0x00,0x00,0x20,0x21, ++0x96,0x47,0x00,0x0c,0x08,0x00,0x11,0x9a,0x00,0x07,0x2c,0x00,0x27,0x83,0x90,0x10, ++0x27,0x82,0x90,0x18,0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00, ++0x90,0x65,0x00,0x05,0x93,0x82,0x80,0x10,0x24,0x07,0x00,0x01,0x0c,0x00,0x21,0x9a, ++0xaf,0xa2,0x00,0x10,0x96,0x47,0x00,0x0c,0x08,0x00,0x11,0x8d,0x00,0x07,0x1c,0x00, ++0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03, ++0x14,0xa2,0xff,0x7d,0x00,0x00,0x00,0x00,0x08,0x00,0x11,0x7e,0xa2,0x40,0x00,0x07, ++0x08,0x00,0x11,0x7e,0xa2,0x40,0x00,0x06,0x08,0x00,0x11,0x7e,0xa2,0x40,0x00,0x05, ++0x14,0x40,0xff,0x71,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, ++0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x11,0x75,0x00,0xa2,0x10,0x07, ++0x14,0x40,0xfe,0xc3,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, ++0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x10,0xd0,0x00,0xa2,0x10,0x07, ++0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x04,0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0xe6,0x00,0x08,0x0c,0x00,0x0f,0x19,0x00,0x00,0x00,0x00, ++0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21,0x00,0x00,0x30,0x21,0x00,0x00,0x38,0x21, ++0x0c,0x00,0x1c,0x68,0xaf,0xa2,0x00,0x10,0x00,0x02,0x1e,0x00,0x14,0x60,0xfe,0x6b, ++0xa2,0x22,0x00,0x12,0x92,0x43,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x40, ++0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x92,0x28,0x00,0x04,0x00,0x00,0x00,0x00, ++0x15,0x00,0x00,0x19,0x24,0x02,0x00,0x01,0x92,0x27,0x00,0x0a,0xa2,0x22,0x00,0x17, ++0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x10,0x00,0x00,0x00,0x00, ++0x96,0x22,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x16, ++0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xc0,0x10,0x60,0x00,0x03,0xa2,0x22,0x00,0x16, ++0x34,0x42,0x00,0x01,0xa2,0x22,0x00,0x16,0x11,0x00,0xfe,0x50,0x00,0x00,0x00,0x00, ++0x92,0x22,0x00,0x16,0x08,0x00,0x10,0x96,0x34,0x42,0x00,0x02,0x96,0x22,0x00,0x00, ++0x08,0x00,0x12,0x3f,0xa6,0x22,0x00,0x14,0x92,0x27,0x00,0x0a,0x00,0x00,0x00,0x00, ++0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0x38,0xa2,0x20,0x00,0x17, ++0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06,0x27,0x86,0x90,0x00,0x00,0x04,0x18,0xc0, ++0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80, ++0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, ++0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08, ++0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02, ++0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x12,0x38,0xa2,0x23,0x00,0x17, ++0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x12,0x67,0x00,0x00,0x00,0x00, ++0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03, ++0x14,0x62,0xff,0xbd,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0x32,0xa2,0x40,0x00,0x07, ++0x08,0x00,0x12,0x32,0xa2,0x40,0x00,0x06,0x08,0x00,0x12,0x32,0xa2,0x40,0x00,0x05, ++0x3c,0x02,0x80,0x00,0x00,0x82,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0xa2,0x18,0x24, ++0x10,0x60,0x00,0x04,0x00,0x00,0x10,0x21,0x10,0xc0,0x00,0x02,0x24,0x02,0x00,0x01, ++0x00,0xa4,0x10,0x2b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xfd, ++0x00,0xa4,0x10,0x2b,0x08,0x00,0x12,0x82,0x00,0x00,0x00,0x00,0x30,0x82,0xff,0xff, ++0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x27,0x84,0x90,0x10,0x00,0x03,0x18,0x80, ++0x00,0x64,0x18,0x21,0x80,0x66,0x00,0x06,0x00,0x02,0x12,0x00,0x3c,0x03,0xb0,0x00, ++0x00,0x46,0x10,0x21,0x00,0x45,0x10,0x21,0x03,0xe0,0x00,0x08,0x00,0x43,0x10,0x21, ++0x27,0xbd,0xff,0xe0,0x30,0x82,0x00,0x7c,0x30,0x84,0xff,0x00,0xaf,0xbf,0x00,0x1c, ++0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x14,0x40,0x00,0x41, ++0x00,0x04,0x22,0x03,0x24,0x02,0x00,0x04,0x3c,0x10,0xb0,0x03,0x8e,0x10,0x00,0x00, ++0x10,0x82,0x00,0x32,0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x03,0x32,0x02,0x00,0x20, ++0x08,0x00,0x12,0xa8,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x06, ++0x34,0x42,0x80,0x24,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x67,0x00,0xff, ++0x10,0xe0,0x00,0x23,0x00,0x00,0x88,0x21,0x8f,0x85,0x8f,0xe0,0x00,0x40,0x30,0x21, ++0x94,0xa2,0x00,0x08,0x8c,0xc3,0x00,0x00,0x26,0x31,0x00,0x01,0x24,0x42,0x00,0x02, ++0x30,0x42,0x01,0xff,0x34,0x63,0x01,0x00,0x02,0x27,0x20,0x2a,0xa4,0xa2,0x00,0x08, ++0x14,0x80,0xff,0xf7,0xac,0xc3,0x00,0x00,0x84,0xa3,0x00,0x08,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x00,0x30,0xac,0x43,0x00,0x00,0x27,0x92,0xb4,0x00,0x24,0x11,0x00,0x12, ++0x8e,0x44,0x00,0x00,0x26,0x31,0xff,0xff,0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x03,0x26,0x52,0x00,0x04,0x0c,0x00,0x18,0xd0,0x00,0x00,0x00,0x00, ++0x06,0x21,0xff,0xf7,0x24,0x02,0xff,0xdf,0x02,0x02,0x80,0x24,0x3c,0x01,0xb0,0x03, ++0x0c,0x00,0x13,0x1c,0xac,0x30,0x00,0x00,0x08,0x00,0x12,0xa8,0x00,0x00,0x00,0x00, ++0x8f,0x85,0x8f,0xe0,0x08,0x00,0x12,0xbe,0x00,0x00,0x00,0x00,0x24,0x02,0xff,0x95, ++0x3c,0x03,0xb0,0x03,0x02,0x02,0x80,0x24,0x34,0x63,0x00,0x30,0x3c,0x01,0xb0,0x03, ++0xac,0x30,0x00,0x00,0x0c,0x00,0x12,0xe5,0xac,0x60,0x00,0x00,0x08,0x00,0x12,0xa8, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x50,0x08,0x00,0x12,0xa8, ++0xac,0x46,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4b,0x94,0x3c,0x0b,0xb0,0x03, ++0xad,0x6a,0x00,0x20,0x3c,0x08,0x80,0x01,0x25,0x08,0x00,0x00,0x3c,0x09,0x80,0x01, ++0x25,0x29,0x03,0x50,0x11,0x09,0x00,0x10,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00, ++0x25,0x4a,0x4b,0xbc,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x08,0xb0,0x06, ++0x35,0x08,0x80,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00, ++0x00,0x00,0x00,0x00,0x31,0x29,0x00,0x01,0x00,0x00,0x00,0x00,0x24,0x01,0x00,0x01, ++0x15,0x21,0xff,0xf2,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4b,0xf8, ++0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x02,0xb0,0x03,0x8c,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x34,0x63,0x00,0x40,0x00,0x00,0x00,0x00,0xac,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0x24,0x3c,0x0b,0xb0,0x03, ++0xad,0x6a,0x00,0x20,0x3c,0x02,0x80,0x01,0x24,0x42,0x00,0x00,0x3c,0x03,0x80,0x01, ++0x24,0x63,0x03,0x50,0x3c,0x04,0xb0,0x00,0x8c,0x85,0x00,0x00,0x00,0x00,0x00,0x00, ++0xac,0x45,0x00,0x00,0x24,0x42,0x00,0x04,0x24,0x84,0x00,0x04,0x00,0x43,0x08,0x2a, ++0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0x1c,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0x70,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, ++0x3c,0x02,0x80,0x01,0x24,0x42,0x03,0x50,0x3c,0x03,0x80,0x01,0x24,0x63,0x3f,0x24, ++0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0xac,0x40,0x00,0x08,0xac,0x40,0x00,0x0c, ++0x24,0x42,0x00,0x10,0x00,0x43,0x08,0x2a,0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0xb0,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, ++0x3c,0x1c,0x80,0x01,0x27,0x9c,0x7f,0xf0,0x27,0x9d,0x8b,0xe0,0x00,0x00,0x00,0x00, ++0x27,0x9d,0x8f,0xc8,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x4c,0xd4,0x3c,0x0b,0xb0,0x03, ++0xad,0x6a,0x00,0x20,0x40,0x80,0x68,0x00,0x40,0x08,0x60,0x00,0x00,0x00,0x00,0x00, ++0x35,0x08,0xff,0x01,0x40,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x15,0x62, ++0x00,0x00,0x00,0x00,0x24,0x84,0xf8,0x00,0x30,0x87,0x00,0x03,0x00,0x04,0x30,0x40, ++0x00,0xc7,0x20,0x23,0x3c,0x02,0xb0,0x0a,0x27,0xbd,0xff,0xe0,0x24,0x03,0xff,0xff, ++0x00,0x82,0x20,0x21,0xaf,0xb1,0x00,0x14,0xac,0x83,0x10,0x00,0xaf,0xbf,0x00,0x18, ++0xaf,0xb0,0x00,0x10,0x00,0xa0,0x88,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x10,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0xc7,0x10,0x23,0x3c,0x03,0xb0,0x0a, ++0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00,0x0c,0x00,0x13,0x99,0x02,0x20,0x20,0x21, ++0x02,0x11,0x80,0x24,0x00,0x50,0x80,0x06,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8, ++0xaf,0xb2,0x00,0x18,0x00,0xa0,0x90,0x21,0x24,0x05,0xff,0xff,0xaf,0xb3,0x00,0x1c, ++0xaf,0xbf,0x00,0x20,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x00,0xc0,0x98,0x21, ++0x12,0x45,0x00,0x23,0x24,0x84,0xf8,0x00,0x30,0x83,0x00,0x03,0x00,0x04,0x10,0x40, ++0x00,0x40,0x88,0x21,0x00,0x60,0x20,0x21,0x00,0x43,0x10,0x23,0x3c,0x03,0xb0,0x0a, ++0x00,0x43,0x10,0x21,0xac,0x45,0x10,0x00,0x00,0x40,0x18,0x21,0x24,0x05,0x00,0x01, ++0x8c,0x62,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x45,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x02,0x24,0x88,0x23,0x02,0x22,0x88,0x21,0x8e,0x30,0x00,0x00,0x0c,0x00,0x13,0x99, ++0x02,0x40,0x20,0x21,0x00,0x12,0x18,0x27,0x02,0x03,0x80,0x24,0x00,0x53,0x10,0x04, ++0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00,0x24,0x03,0x00,0x01,0x8e,0x22,0x10,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x20, ++0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, ++0x30,0x82,0x00,0x03,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x23,0x3c,0x04,0xb0,0x0a, ++0x00,0x64,0x18,0x21,0xac,0x66,0x00,0x00,0x24,0x04,0x00,0x01,0x8c,0x62,0x10,0x00, ++0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x13,0x87, ++0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x64,0x10,0x06,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x20, ++0x14,0x40,0xff,0xf9,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, ++0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x05,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c,0x00,0x80,0x90,0x21,0x00,0xa0,0x80,0x21, ++0x00,0xc0,0x88,0x21,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfc,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0xc0, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x3c,0x02,0xc0,0x00,0x00,0x10,0x1c,0x00, ++0x34,0x42,0x04,0x00,0x3c,0x04,0xb0,0x05,0x3c,0x05,0xb0,0x05,0x24,0x63,0x16,0x09, ++0x02,0x22,0x10,0x21,0x34,0x84,0x04,0x20,0x34,0xa5,0x04,0x24,0x3c,0x06,0xb0,0x05, ++0xac,0x83,0x00,0x00,0x24,0x07,0x00,0x01,0xac,0xa2,0x00,0x00,0x34,0xc6,0x02,0x28, ++0x24,0x02,0x00,0x20,0xae,0x47,0x00,0x3c,0x24,0x04,0x08,0x24,0xa0,0xc2,0x00,0x00, ++0x3c,0x05,0x00,0xc0,0xa2,0x47,0x00,0x11,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01, ++0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01, ++0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x24,0x02,0x00,0x06,0xac,0x82,0x00,0x0c,0xa0,0x80,0x00,0x50, ++0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04,0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x14, ++0xac,0x80,0x00,0x18,0xac,0x80,0x00,0x1c,0xa4,0x80,0x00,0x20,0xac,0x80,0x00,0x24, ++0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c,0xa0,0x80,0x00,0x30,0xa0,0x80,0x00,0x31, ++0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38,0xa0,0x80,0x00,0x3c,0xac,0x82,0x00,0x10, ++0xa0,0x80,0x00,0x44,0xac,0x80,0x00,0x48,0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x4c, ++0x3c,0x04,0xb0,0x06,0x34,0x84,0x80,0x00,0x8c,0x83,0x00,0x00,0x3c,0x02,0x12,0x00, ++0x3c,0x05,0xb0,0x03,0x00,0x62,0x18,0x25,0x34,0xa5,0x00,0x8b,0x24,0x02,0xff,0x80, ++0xac,0x83,0x00,0x00,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x00,0x3c,0x04,0xb0,0x03, ++0x34,0x84,0x00,0x0b,0x24,0x02,0x00,0x22,0x3c,0x05,0xb0,0x01,0x3c,0x06,0x45,0x67, ++0x3c,0x0a,0xb0,0x09,0xa0,0x82,0x00,0x00,0x34,0xa5,0x00,0x04,0x34,0xc6,0x89,0xaa, ++0x35,0x4a,0x00,0x04,0x24,0x02,0x01,0x23,0x3c,0x0b,0xb0,0x09,0x3c,0x07,0x01,0x23, ++0x3c,0x0c,0xb0,0x09,0x3c,0x01,0xb0,0x01,0xac,0x20,0x00,0x00,0x27,0xbd,0xff,0xe0, ++0xac,0xa0,0x00,0x00,0x35,0x6b,0x00,0x08,0x3c,0x01,0xb0,0x09,0xac,0x26,0x00,0x00, ++0x34,0xe7,0x45,0x66,0xa5,0x42,0x00,0x00,0x35,0x8c,0x00,0x0c,0x24,0x02,0xcd,0xef, ++0x3c,0x0d,0xb0,0x09,0x3c,0x08,0xcd,0xef,0x3c,0x0e,0xb0,0x09,0xad,0x67,0x00,0x00, ++0xaf,0xb7,0x00,0x1c,0xa5,0x82,0x00,0x00,0xaf,0xb6,0x00,0x18,0xaf,0xb5,0x00,0x14, ++0xaf,0xb4,0x00,0x10,0xaf,0xb3,0x00,0x0c,0xaf,0xb2,0x00,0x08,0xaf,0xb1,0x00,0x04, ++0xaf,0xb0,0x00,0x00,0x35,0xad,0x00,0x10,0x35,0x08,0x01,0x22,0x35,0xce,0x00,0x14, ++0x24,0x02,0x89,0xab,0x3c,0x0f,0xb0,0x09,0x3c,0x09,0x89,0xab,0x3c,0x10,0xb0,0x09, ++0x3c,0x11,0xb0,0x09,0x3c,0x12,0xb0,0x09,0x3c,0x13,0xb0,0x09,0x3c,0x14,0xb0,0x09, ++0x3c,0x15,0xb0,0x09,0x3c,0x16,0xb0,0x09,0x3c,0x17,0xb0,0x09,0xad,0xa8,0x00,0x00, ++0x24,0x03,0xff,0xff,0xa5,0xc2,0x00,0x00,0x35,0xef,0x00,0x18,0x35,0x29,0xcd,0xee, ++0x36,0x10,0x00,0x1c,0x36,0x31,0x00,0x20,0x36,0x52,0x00,0x24,0x36,0x73,0x00,0x28, ++0x36,0x94,0x00,0x2c,0x36,0xb5,0x00,0x30,0x36,0xd6,0x00,0x34,0x36,0xf7,0x00,0x38, ++0x24,0x02,0x45,0x67,0xad,0xe9,0x00,0x00,0xa6,0x02,0x00,0x00,0xae,0x23,0x00,0x00, ++0x8f,0xb0,0x00,0x00,0xa6,0x43,0x00,0x00,0x8f,0xb1,0x00,0x04,0xae,0x63,0x00,0x00, ++0x8f,0xb2,0x00,0x08,0xa6,0x83,0x00,0x00,0x8f,0xb3,0x00,0x0c,0xae,0xa3,0x00,0x00, ++0x8f,0xb4,0x00,0x10,0xa6,0xc3,0x00,0x00,0x8f,0xb5,0x00,0x14,0xae,0xe3,0x00,0x00, ++0x7b,0xb6,0x00,0xfc,0x3c,0x18,0xb0,0x09,0x37,0x18,0x00,0x3c,0xa7,0x03,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x34,0x63,0x00,0x20,0x24,0x42,0x51,0x48,0xac,0x62,0x00,0x00,0x8c,0x83,0x00,0x34, ++0x34,0x02,0xff,0xff,0x00,0x43,0x10,0x2a,0x14,0x40,0x01,0x04,0x00,0x80,0x28,0x21, ++0x8c,0x86,0x00,0x08,0x24,0x02,0x00,0x03,0x10,0xc2,0x00,0xf7,0x00,0x00,0x00,0x00, ++0x8c,0xa2,0x00,0x2c,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x4f,0x24,0x02,0x00,0x06, ++0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0x14,0x40,0x00,0xdd,0xac,0xa2,0x00,0x2c,0x24,0x02,0x00,0x01, ++0x10,0xc2,0x00,0xdc,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0xca, ++0x00,0x00,0x00,0x00,0x8c,0xa7,0x00,0x04,0x24,0x02,0x00,0x02,0x10,0xe2,0x00,0xc0, ++0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x09, ++0x24,0x02,0x00,0x01,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x05,0xac,0xa2,0x00,0x14, ++0x24,0x02,0x00,0x01,0xac,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x14, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0x04,0x61,0x00,0x19,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2e, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x12, ++0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x42,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x0c,0x3c,0x02,0xb0,0x03,0x80,0xa2,0x00,0x50, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x08,0x3c,0x02,0xb0,0x03,0x14,0xc0,0x00,0x07, ++0x34,0x42,0x00,0x3f,0x24,0x02,0x00,0x0e,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00, ++0x03,0xe0,0x00,0x08,0xa0,0xa3,0x00,0x50,0x34,0x42,0x00,0x3f,0x90,0x44,0x00,0x00, ++0x24,0x03,0x00,0x01,0x10,0x64,0x00,0x7f,0x3c,0x03,0xb0,0x05,0x80,0xa2,0x00,0x31, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, ++0x8c,0x43,0x00,0x00,0x3c,0x04,0xf0,0x00,0x3c,0x02,0x80,0x00,0x00,0x64,0x18,0x24, ++0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x09,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x00, ++0x8c,0xa2,0x00,0x40,0x00,0x00,0x00,0x00,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0x10,0x60,0x00,0x09,0x3c,0x03,0xb0,0x03,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c, ++0x8c,0x43,0x00,0x00,0x3c,0x04,0x00,0x02,0x00,0x64,0x18,0x24,0x14,0x60,0xff,0xf2, ++0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03,0x34,0x63,0x02,0x01,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x80,0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, ++0x8c,0xa3,0x00,0x0c,0x00,0x00,0x00,0x00,0xac,0xa3,0x00,0x10,0x3c,0x02,0xb0,0x03, ++0x90,0x42,0x02,0x01,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x0f,0xac,0xa2,0x00,0x0c, ++0x90,0xa3,0x00,0x0f,0x24,0x02,0x00,0x0d,0x3c,0x01,0xb0,0x03,0x08,0x00,0x14,0xb2, ++0xa0,0x23,0x02,0x01,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x80,0x90,0x44,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x04,0x1e,0x00,0x00,0x03,0x1e,0x03,0x10,0x60,0x00,0x15, ++0xa0,0xa4,0x00,0x44,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x0b,0x24,0x02,0x00,0x02, ++0x10,0x62,0x00,0x03,0x24,0x03,0x00,0x0d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x8c,0xa2,0x00,0x0c,0xac,0xa3,0x00,0x00,0x24,0x03,0x00,0x04,0xac,0xa2,0x00,0x10, ++0x03,0xe0,0x00,0x08,0xac,0xa3,0x00,0x0c,0x24,0x02,0x00,0x0d,0xac,0xa2,0x00,0x00, ++0x24,0x03,0x00,0x04,0x24,0x02,0x00,0x06,0xac,0xa3,0x00,0x10,0x03,0xe0,0x00,0x08, ++0xac,0xa2,0x00,0x0c,0x8c,0xa3,0x00,0x38,0x24,0x04,0x00,0x01,0x10,0x64,0x00,0x2d, ++0x24,0x02,0x00,0x02,0x10,0x60,0x00,0x19,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x10, ++0x24,0x02,0x00,0x04,0x10,0x62,0x00,0x04,0x00,0x00,0x00,0x00,0xac,0xa0,0x00,0x38, ++0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x00,0x10,0xe4,0x00,0x07,0x24,0x02,0x00,0x03, ++0x80,0xa2,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x0b,0xac,0xa3,0x00,0x00, ++0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x38,0x08,0x00,0x15,0x04,0xac,0xa2,0x00,0x00, ++0x10,0xe4,0x00,0x02,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x0c,0xac,0xa2,0x00,0x00, ++0x24,0x02,0x00,0x04,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x38,0x10,0xe4,0x00,0x0e, ++0x3c,0x03,0xb0,0x06,0x34,0x63,0x80,0x24,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x06,0xac,0xa2,0x00,0x18,0x24,0x02,0x00,0x02, ++0xac,0xa2,0x00,0x00,0xac,0xa0,0x00,0x18,0x08,0x00,0x15,0x0d,0x24,0x02,0x00,0x01, ++0x08,0x00,0x15,0x1a,0xac,0xa0,0x00,0x00,0x24,0x02,0x00,0x03,0x08,0x00,0x15,0x1a, ++0xac,0xa2,0x00,0x00,0x24,0x03,0x00,0x0b,0xac,0xa2,0x00,0x38,0x03,0xe0,0x00,0x08, ++0xac,0xa3,0x00,0x00,0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x7d,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x42, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0x78,0x00,0x00,0x00,0x00, ++0x10,0xc0,0xff,0x81,0x24,0x02,0x00,0x0e,0x08,0x00,0x14,0xa7,0x00,0x00,0x00,0x00, ++0x80,0xa2,0x00,0x30,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x3e,0x24,0x02,0x00,0x04, ++0x08,0x00,0x14,0xb2,0x00,0x00,0x00,0x00,0x84,0xa2,0x00,0x20,0x00,0x00,0x00,0x00, ++0x10,0x40,0xff,0x75,0x24,0x02,0x00,0x06,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff, ++0x00,0x60,0x10,0x21,0x14,0x40,0xff,0x2b,0xa4,0xa3,0x00,0x20,0x08,0x00,0x14,0xb2, ++0x24,0x02,0x00,0x06,0x8c,0xa2,0x00,0x1c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x66, ++0x24,0x02,0x00,0x05,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0xff,0x1b,0xac,0xa2,0x00,0x1c, ++0x08,0x00,0x14,0xb2,0x24,0x02,0x00,0x05,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x56, ++0x24,0x02,0x00,0x06,0x08,0x00,0x14,0x60,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x0a, ++0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xb0,0x00,0x10, ++0x27,0x90,0x86,0x58,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18, ++0x0c,0x00,0x29,0xd5,0xaf,0xb1,0x00,0x14,0xaf,0x90,0x8f,0xe0,0x48,0x02,0x00,0x00, ++0x0c,0x00,0x13,0xf0,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x1f,0x02,0x00,0x20,0x21, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3a,0x94,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0xa3,0x83,0x8f,0xe4,0x0c,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x0c,0x00,0x13,0xfb, ++0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x98,0x0c,0x00,0x27,0x59,0x00,0x00,0x00,0x00, ++0x93,0x84,0x80,0x10,0x0c,0x00,0x21,0x3f,0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x18, ++0x0c,0x00,0x06,0xe5,0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x39,0x00,0x00,0x00,0x00, ++0x27,0x84,0x84,0x40,0x0c,0x00,0x13,0xd9,0x00,0x00,0x00,0x00,0x27,0x82,0x89,0x4c, ++0xaf,0x82,0x84,0x80,0x0c,0x00,0x00,0x5f,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x34,0x63,0x01,0x08,0x3c,0x04,0xb0,0x09,0x3c,0x05,0xb0,0x09,0x8c,0x66,0x00,0x00, ++0x34,0x84,0x01,0x68,0x34,0xa5,0x01,0x40,0x24,0x02,0xc8,0x80,0x24,0x03,0x00,0x0a, ++0xa4,0x82,0x00,0x00,0xa4,0xa3,0x00,0x00,0x3c,0x04,0xb0,0x03,0x8c,0x82,0x00,0x00, ++0x8f,0x85,0x84,0x40,0xaf,0x86,0x84,0x38,0x34,0x42,0x00,0x20,0xac,0x82,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x58,0x8c,0x43,0x00,0x00,0x2c,0xa4,0x00,0x11, ++0x34,0x63,0x01,0x00,0xac,0x43,0x00,0x00,0x10,0x80,0xff,0xfa,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x01,0x00,0x05,0x10,0x80,0x24,0x63,0x02,0x00,0x00,0x43,0x10,0x21, ++0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00, ++0x27,0x84,0x84,0x98,0x0c,0x00,0x26,0x8e,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x40, ++0x0c,0x00,0x14,0x52,0x00,0x00,0x00,0x00,0x93,0x83,0x81,0xf1,0x24,0x02,0x00,0x01, ++0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0x40,0x8f,0x82,0x84,0x74, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x84,0x74,0x08,0x00,0x15,0x9d, ++0x3c,0x02,0xb0,0x03,0x27,0x84,0x84,0x98,0x0c,0x00,0x27,0x0d,0x00,0x00,0x00,0x00, ++0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x98,0x0c,0x00,0x28,0xdd, ++0x00,0x00,0x00,0x00,0xa3,0x82,0x84,0x71,0x8f,0x82,0x84,0x74,0xaf,0x80,0x84,0x40, ++0x24,0x42,0x00,0x01,0xaf,0x82,0x84,0x74,0x08,0x00,0x15,0x9c,0x00,0x00,0x28,0x21, ++0x27,0x84,0x86,0x58,0x0c,0x00,0x19,0x5b,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, ++0x14,0x40,0x00,0x05,0x3c,0x03,0xb0,0x05,0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x44, ++0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x6c,0x14,0x40,0x00,0x20, ++0x24,0x02,0x00,0x01,0x8f,0x84,0x84,0x48,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x20, ++0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x54,0x14,0x40,0x00,0x15,0x24,0x02,0x00,0x01, ++0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x07,0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x03, ++0x24,0x02,0x00,0x01,0xaf,0x82,0x84,0x44,0xaf,0x85,0x84,0x40,0x08,0x00,0x15,0xb6, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, ++0xa7,0x83,0x84,0x60,0x14,0x40,0xff,0xf1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0xaf,0x82,0x84,0x44,0xaf,0x80,0x84,0x40,0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x5c,0x14,0x40,0xff,0xf5,0x24,0x02,0x00,0x01, ++0x08,0x00,0x15,0xe1,0x3c,0x03,0xb0,0x09,0x27,0x84,0x86,0x58,0x0c,0x00,0x1a,0xd1, ++0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x70,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xec, ++0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x6c,0x14,0x40,0xff,0xe4, ++0x24,0x02,0x00,0x02,0x8f,0x84,0x84,0x48,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x12, ++0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x04, ++0x08,0x00,0x15,0xed,0x24,0x02,0x00,0x02,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff, ++0x00,0x60,0x10,0x21,0xa7,0x83,0x84,0x60,0x14,0x40,0xff,0xf4,0x00,0x00,0x00,0x00, ++0x08,0x00,0x15,0xfc,0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c, ++0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x84,0x5c, ++0x14,0x40,0xff,0xf7,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0x1d,0x24,0x02,0x00,0x02, ++0x27,0x84,0x89,0x18,0x0c,0x00,0x0b,0x55,0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x44, ++0xaf,0x82,0x84,0x5c,0x38,0x64,0x00,0x02,0x00,0x04,0x18,0x0a,0xaf,0x83,0x84,0x44, ++0x14,0x40,0xff,0xad,0x24,0x05,0x00,0x05,0x8f,0x82,0x89,0x58,0xaf,0x80,0x84,0x40, ++0x10,0x40,0x00,0x02,0x24,0x04,0x00,0x01,0xaf,0x84,0x84,0x48,0x93,0x82,0x89,0x66, ++0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x6c,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05, ++0x34,0x42,0x00,0x08,0x8c,0x43,0x00,0x00,0x3c,0x04,0x20,0x00,0x00,0x64,0x18,0x24, ++0x10,0x60,0xff,0x65,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xa0, ++0x8c,0x43,0x00,0x00,0x3c,0x04,0x80,0x00,0xaf,0x80,0x89,0x40,0x24,0x63,0x00,0x01, ++0xac,0x43,0x00,0x00,0x3c,0x01,0xb0,0x05,0xac,0x24,0x00,0x08,0xaf,0x80,0x89,0x3c, ++0xaf,0x80,0x89,0x44,0xaf,0x80,0x89,0x48,0xaf,0x80,0x89,0x54,0xaf,0x80,0x89,0x4c, ++0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x83,0x82,0x84,0x90,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x20,0xaf,0x82,0x84,0x5c,0x8f,0x85,0x84,0x5c, ++0x27,0x84,0x89,0x18,0x0c,0x00,0x0d,0x30,0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00, ++0xa3,0x82,0x84,0x70,0xaf,0x80,0x84,0x5c,0x10,0x60,0xff,0x8e,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21,0xa7,0x83,0x84,0x60, ++0x10,0x40,0x00,0x04,0x24,0x04,0x00,0x02,0xaf,0x84,0x84,0x48,0x08,0x00,0x15,0xfd, ++0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xee,0x24,0x05,0x00,0x06,0x27,0x84,0x84,0x40, ++0x27,0x85,0x89,0x18,0x0c,0x00,0x0d,0xfd,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x64, ++0xaf,0x80,0x84,0x6c,0x14,0x40,0x00,0x19,0x00,0x40,0x18,0x21,0x8f,0x82,0x84,0x68, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x15,0x24,0x02,0x00,0x02,0x8f,0x83,0x84,0x48, ++0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x0b,0x3c,0x02,0x40,0x00,0x8f,0x83,0x84,0x44, ++0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x02,0x24,0x05,0x00,0x03,0x24,0x05,0x00,0x06, ++0xaf,0x85,0x84,0x40,0x24,0x04,0x00,0x03,0xaf,0x84,0x84,0x48,0x08,0x00,0x15,0xb6, ++0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x14,0x3c,0x01,0xb0,0x05,0xac,0x22,0x00,0x00, ++0xaf,0x80,0x84,0x40,0x08,0x00,0x16,0x96,0x24,0x04,0x00,0x03,0x10,0x60,0x00,0x10, ++0x00,0x00,0x00,0x00,0x27,0x85,0x89,0x18,0x27,0x84,0x84,0x40,0x0c,0x00,0x0e,0x21, ++0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x44,0x24,0x02,0x00,0x01,0xa3,0x80,0x84,0x70, ++0xaf,0x80,0x84,0x48,0x10,0x62,0x00,0x02,0x24,0x05,0x00,0x03,0x24,0x05,0x00,0x04, ++0xaf,0x85,0x84,0x40,0xaf,0x80,0x84,0x64,0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00, ++0x83,0x82,0x84,0x90,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00, ++0x27,0x84,0x89,0x18,0x0c,0x00,0x10,0x69,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x44, ++0xa3,0x80,0x84,0x70,0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x48,0x14,0x40,0x00,0x03, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0xaf,0x82,0x84,0x44,0xaf,0x80,0x84,0x68, ++0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x40,0x27,0x85,0x89,0x18, ++0x0c,0x00,0x0e,0x21,0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x44,0xa3,0x80,0x84,0x70, ++0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x48,0x14,0x40,0xfe,0xeb,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x02,0xaf,0x82,0x84,0x44,0x08,0x00,0x15,0xb6,0x00,0x00,0x00,0x00, ++0x27,0x84,0x89,0x18,0x0c,0x00,0x10,0x69,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0xc6, ++0x00,0x00,0x00,0x00,0x27,0x84,0x84,0x98,0x0c,0x00,0x29,0x73,0x00,0x00,0x00,0x00, ++0x08,0x00,0x15,0xc5,0x00,0x00,0x00,0x00,0x0c,0x00,0x24,0x05,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x26,0xff,0x00,0x00,0x00,0x00,0x0c,0x00,0x18,0x11,0x00,0x00,0x00,0x00, ++0x93,0x83,0xbc,0x18,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x2b,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x83,0xbc,0x10,0x8f,0x82,0xbc,0x14, ++0x00,0x83,0x18,0x23,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x23,0x3c,0x02,0xb0,0x03, ++0x24,0x04,0x05,0xa0,0x34,0x42,0x01,0x18,0x8c,0x42,0x00,0x00,0x0c,0x00,0x06,0xd1, ++0x00,0x00,0x00,0x00,0x24,0x04,0x05,0xa4,0x0c,0x00,0x06,0xd1,0x00,0x02,0x84,0x02, ++0x30,0x51,0xff,0xff,0x24,0x04,0x05,0xa8,0x00,0x02,0x94,0x02,0x0c,0x00,0x06,0xd1, ++0x3a,0x10,0xff,0xff,0x3a,0x31,0xff,0xff,0x30,0x42,0xff,0xff,0x2e,0x10,0x00,0x01, ++0x2e,0x31,0x00,0x01,0x3a,0x52,0xff,0xff,0x02,0x11,0x80,0x25,0x2e,0x52,0x00,0x01, ++0x38,0x42,0xff,0xff,0x02,0x12,0x80,0x25,0x2c,0x42,0x00,0x01,0x02,0x02,0x80,0x25, ++0x16,0x00,0x00,0x02,0x24,0x04,0x00,0x02,0x00,0x00,0x20,0x21,0x0c,0x00,0x05,0x6e, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0xaf,0x83,0xbc,0x10,0x0c,0x00,0x01,0xe9,0x00,0x00,0x00,0x00, ++0xaf,0x80,0x84,0x40,0xaf,0x80,0x84,0x74,0x08,0x00,0x15,0x9c,0x00,0x00,0x28,0x21, ++0x27,0x90,0xb4,0x00,0x24,0x11,0x00,0x12,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00, ++0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x18,0xd0,0x00,0x00,0x00,0x00,0x26,0x31,0xff,0xff,0x06,0x21,0xff,0xf6, ++0x26,0x10,0x00,0x04,0xaf,0x80,0x84,0x40,0x08,0x00,0x15,0xb7,0x00,0x00,0x28,0x21, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x82,0x84,0x38, ++0x00,0x04,0x19,0xc2,0x00,0x02,0x11,0xc2,0x10,0x62,0xff,0xf6,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x02,0x90,0x43,0x00,0x00,0x3c,0x12,0xb0,0x05, ++0xaf,0x84,0x84,0x38,0x30,0x63,0x00,0xff,0x00,0x03,0x11,0x40,0x00,0x43,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x99,0x00,0x00,0x00,0x88,0x21, ++0x36,0x52,0x02,0x2c,0x27,0x90,0xb4,0x00,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00, ++0x90,0x83,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x03,0x10,0x40,0x00,0x06, ++0x30,0x62,0x00,0x1c,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0x38, ++0x0c,0x00,0x1e,0x94,0x02,0x60,0x30,0x21,0x8e,0x42,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0x14,0x40,0xff,0xd7,0x00,0x00,0x00,0x00,0x26,0x31,0x00,0x01, ++0x2a,0x22,0x00,0x13,0x14,0x40,0xff,0xec,0x26,0x10,0x00,0x04,0x08,0x00,0x17,0x21, ++0x00,0x00,0x00,0x00,0x8f,0x84,0x84,0x4c,0x27,0x85,0x89,0x18,0x0c,0x00,0x17,0xa4, ++0x00,0x00,0x00,0x00,0x8f,0x83,0x84,0x4c,0x24,0x02,0x00,0x04,0x14,0x62,0xfe,0xa5, ++0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xee,0x24,0x05,0x00,0x05,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x00,0x3f,0x90,0x44,0x00,0x00,0x24,0x03,0x00,0x01,0x10,0x64,0x00,0x08, ++0x00,0x00,0x00,0x00,0x27,0x84,0x89,0x18,0x0c,0x00,0x24,0x2c,0x00,0x00,0x00,0x00, ++0x24,0x05,0x00,0x05,0xaf,0x85,0x84,0x40,0x08,0x00,0x15,0xb7,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x14,0x8c,0x44,0x00,0x00,0x0c,0x00,0x24,0x49, ++0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x65,0x24,0x05,0x00,0x05,0x8f,0x82,0x89,0x4c, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x8f,0x84,0xb4,0x40, ++0xaf,0x80,0x89,0x4c,0x94,0x85,0x00,0x14,0x0c,0x00,0x1b,0x66,0x00,0x00,0x00,0x00, ++0x93,0x82,0x8b,0x71,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x10,0x40,0x00,0x03, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x57,0x00,0x00,0x20,0x21,0x8f,0x84,0xb4,0x40, ++0x0c,0x00,0x18,0xd0,0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x21,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xff,0x90,0x27,0xbd,0xff,0xe8,0x00,0x80,0x18,0x21,0x34,0x42,0x00,0x01, ++0x27,0x84,0x89,0x18,0x10,0x62,0x00,0x05,0xaf,0xbf,0x00,0x10,0x8f,0xbf,0x00,0x10, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x06,0xe5, ++0x00,0x00,0x00,0x00,0x27,0x84,0x86,0x58,0x0c,0x00,0x18,0x1f,0x00,0x00,0x00,0x00, ++0x27,0x84,0x84,0x40,0x0c,0x00,0x13,0xd9,0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x8b, ++0x00,0x00,0x00,0x00,0x8f,0x82,0x89,0x58,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05, ++0x00,0x00,0x18,0x21,0x8f,0x82,0x84,0x48,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x02, ++0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, ++0x27,0xbd,0xff,0xe0,0x3c,0x06,0xb0,0x03,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0x34,0xc6,0x00,0x5f,0xaf,0xbf,0x00,0x18,0x90,0xc3,0x00,0x00,0x3c,0x07,0xb0,0x03, ++0x34,0xe7,0x00,0x5d,0x34,0x63,0x00,0x01,0x3c,0x09,0xb0,0x03,0x24,0x02,0x00,0x01, ++0xa0,0xc3,0x00,0x00,0x00,0x80,0x80,0x21,0xa0,0xe2,0x00,0x00,0x00,0xa0,0x88,0x21, ++0x35,0x29,0x00,0x5e,0x00,0xe0,0x40,0x21,0x24,0x04,0x00,0x01,0x91,0x22,0x00,0x00, ++0x91,0x03,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x83,0x00,0x03,0x30,0x42,0x00,0x01, ++0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x2c, ++0x24,0x05,0x0f,0x00,0x24,0x02,0x00,0x06,0x12,0x02,0x00,0x08,0x24,0x05,0x00,0x0f, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x02,0x00,0xa0,0x50,0x00,0x00,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x04,0x0c,0x04, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x8c,0x24,0x05,0x0f,0x00, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x3c,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x08,0x00,0x17,0xc5,0x3c,0x02,0xb0,0x03, ++0x24,0x04,0x08,0x8c,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x80, ++0x24,0x05,0x1e,0x00,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x0c,0x04, ++0x24,0x05,0x00,0x0f,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x0d,0x04, ++0x24,0x05,0x00,0x0f,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x24, ++0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x2c, ++0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34, ++0x3c,0x05,0x00,0x30,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x02,0x3c,0x05,0x00,0x30, ++0x24,0x06,0x00,0x03,0x0c,0x00,0x13,0x5f,0x24,0x04,0x08,0x3c,0x02,0x20,0x20,0x21, ++0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa4,0x24,0x06,0x01,0x07,0x08,0x00,0x17,0xc5, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x73,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00, ++0xa3,0x80,0x81,0x58,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0xa3,0x82,0x81,0x58,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x00,0x80,0x70,0x21,0x34,0x63,0x00,0x20,0x24,0x42,0x60,0x7c, ++0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x30,0xad,0xc0,0x02,0xb8, ++0x8c,0x83,0x00,0x00,0x24,0x02,0x00,0xff,0xa5,0xc0,0x00,0x0a,0x00,0x00,0x30,0x21, ++0xa7,0x82,0x8f,0xf0,0x27,0x88,0x90,0x00,0xa5,0xc3,0x00,0x08,0x3c,0x07,0xb0,0x08, ++0x30,0xc2,0xff,0xff,0x00,0x02,0x20,0xc0,0x24,0xc3,0x00,0x01,0x00,0x82,0x10,0x21, ++0x00,0x60,0x30,0x21,0x00,0x02,0x10,0x80,0x30,0x63,0xff,0xff,0x00,0x48,0x10,0x21, ++0x00,0x87,0x20,0x21,0x28,0xc5,0x00,0xff,0xac,0x83,0x00,0x00,0x14,0xa0,0xff,0xf4, ++0xa4,0x43,0x00,0x00,0x3c,0x02,0xb0,0x08,0x34,0x03,0xff,0xff,0x25,0xc4,0x00,0x0c, ++0x24,0x0a,0x00,0x02,0x34,0x42,0x07,0xf8,0x3c,0x06,0xb0,0x03,0xa7,0x83,0xb3,0xdc, ++0xac,0x43,0x00,0x00,0xaf,0x84,0xb4,0x00,0x34,0xc6,0x00,0x64,0xa0,0x8a,0x00,0x18, ++0x94,0xc5,0x00,0x00,0x8f,0x82,0xb4,0x00,0x25,0xc4,0x00,0x30,0x24,0x08,0x00,0x03, ++0x3c,0x03,0xb0,0x03,0xa0,0x45,0x00,0x21,0x34,0x63,0x00,0x66,0xaf,0x84,0xb4,0x04, ++0xa0,0x88,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x04,0x25,0xc4,0x00,0x54, ++0x25,0xc7,0x00,0x78,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x08,0xa0,0x88,0x00,0x18, ++0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x08,0x25,0xc8,0x00,0x9c,0x24,0x09,0x00,0x01, ++0xa0,0x45,0x00,0x21,0xaf,0x87,0xb4,0x0c,0xa0,0xea,0x00,0x18,0x94,0xc4,0x00,0x00, ++0x8f,0x82,0xb4,0x0c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x62,0xa0,0x44,0x00,0x21, ++0xaf,0x88,0xb4,0x10,0xa1,0x09,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x10, ++0x25,0xc4,0x00,0xc0,0x3c,0x06,0xb0,0x03,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x14, ++0xa0,0x89,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xb4,0x14,0x25,0xc4,0x00,0xe4, ++0x34,0xc6,0x00,0x60,0xa0,0x45,0x00,0x21,0xaf,0x84,0xb4,0x18,0xa0,0x80,0x00,0x18, ++0x94,0xc5,0x00,0x00,0x8f,0x82,0xb4,0x18,0x25,0xc3,0x01,0x08,0x25,0xc7,0x01,0x2c, ++0xa0,0x45,0x00,0x21,0xaf,0x83,0xb4,0x1c,0xa0,0x60,0x00,0x18,0x94,0xc8,0x00,0x00, ++0x8f,0x82,0xb4,0x1c,0x25,0xc4,0x01,0x50,0x25,0xc5,0x01,0x74,0xa0,0x48,0x00,0x21, ++0x25,0xc6,0x01,0x98,0x25,0xc9,0x01,0xbc,0x25,0xca,0x01,0xe0,0x25,0xcb,0x02,0x04, ++0x25,0xcc,0x02,0x28,0x25,0xcd,0x02,0x4c,0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03, ++0xaf,0x87,0xb4,0x20,0x34,0x63,0x00,0x38,0xa0,0xe0,0x00,0x18,0xaf,0x84,0xb4,0x24, ++0xa0,0x80,0x00,0x18,0xaf,0x85,0xb4,0x28,0xa0,0xa0,0x00,0x18,0xaf,0x86,0xb4,0x2c, ++0xa0,0xc0,0x00,0x18,0xaf,0x89,0xb4,0x30,0xa1,0x20,0x00,0x18,0xaf,0x8a,0xb4,0x34, ++0xa1,0x40,0x00,0x18,0xaf,0x8b,0xb4,0x38,0xa1,0x60,0x00,0x18,0xaf,0x8c,0xb4,0x3c, ++0xa1,0x80,0x00,0x18,0xaf,0x8d,0xb4,0x40,0xa1,0xa2,0x00,0x18,0x94,0x64,0x00,0x00, ++0x8f,0x82,0xb4,0x40,0x25,0xc5,0x02,0x70,0x3c,0x03,0xb0,0x03,0xa0,0x44,0x00,0x21, ++0x24,0x02,0x00,0x11,0xaf,0x85,0xb4,0x44,0x34,0x63,0x00,0x6e,0xa0,0xa2,0x00,0x18, ++0x94,0x64,0x00,0x00,0x8f,0x82,0xb4,0x44,0x25,0xc5,0x02,0x94,0x3c,0x03,0xb0,0x03, ++0xa0,0x44,0x00,0x21,0x24,0x02,0x00,0x12,0xaf,0x85,0xb4,0x48,0x34,0x63,0x00,0x6c, ++0xa0,0xa2,0x00,0x18,0x94,0x64,0x00,0x00,0x8f,0x82,0xb4,0x48,0x24,0x05,0xff,0xff, ++0x24,0x07,0x00,0x01,0xa0,0x44,0x00,0x21,0x24,0x06,0x00,0x12,0x27,0x84,0xb4,0x00, ++0x8c,0x82,0x00,0x00,0x24,0xc6,0xff,0xff,0xa0,0x40,0x00,0x04,0x8c,0x83,0x00,0x00, ++0xa4,0x45,0x00,0x00,0xa4,0x45,0x00,0x02,0xa0,0x60,0x00,0x0a,0x8c,0x82,0x00,0x00, ++0xa4,0x65,0x00,0x06,0xa4,0x65,0x00,0x08,0xa0,0x40,0x00,0x10,0x8c,0x83,0x00,0x00, ++0xa4,0x45,0x00,0x0c,0xa4,0x45,0x00,0x0e,0xa0,0x60,0x00,0x12,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0xa0,0x40,0x00,0x16,0x8c,0x83,0x00,0x00,0xa4,0x45,0x00,0x14, ++0xa0,0x67,0x00,0x17,0x8c,0x82,0x00,0x00,0x24,0x84,0x00,0x04,0xa0,0x40,0x00,0x20, ++0x04,0xc1,0xff,0xe7,0xac,0x40,0x00,0x1c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20,0x24,0x63,0x63,0x40, ++0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x10,0x00,0x80,0x60,0x21,0x10,0x40,0x00,0x56, ++0x00,0x00,0x70,0x21,0x97,0x82,0x8f,0xf0,0x94,0x8a,0x00,0x0c,0x27,0x87,0x90,0x00, ++0x00,0x02,0x40,0xc0,0x01,0x02,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21, ++0x90,0x8b,0x00,0x18,0xa4,0x4a,0x00,0x00,0x94,0x83,0x00,0x0e,0x39,0x64,0x00,0x10, ++0x2c,0x84,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x34,0x85,0x00,0x02, ++0x39,0x63,0x00,0x11,0x00,0x83,0x28,0x0b,0x34,0xa3,0x00,0x08,0x39,0x64,0x00,0x12, ++0x00,0x02,0x10,0x80,0x00,0xa4,0x18,0x0b,0x00,0x47,0x10,0x21,0x94,0x49,0x00,0x04, ++0x34,0x64,0x00,0x20,0x00,0x6b,0x20,0x0b,0x34,0x83,0x00,0x40,0x39,0x62,0x00,0x01, ++0x00,0x82,0x18,0x0b,0x00,0x09,0x30,0xc0,0x34,0x64,0x00,0x80,0x00,0xc9,0x28,0x21, ++0x39,0x62,0x00,0x02,0x00,0x60,0x68,0x21,0x00,0x82,0x68,0x0a,0x00,0x05,0x28,0x80, ++0x3c,0x02,0xb0,0x08,0x00,0xa7,0x28,0x21,0x00,0xc2,0x30,0x21,0x01,0x02,0x40,0x21, ++0x34,0x03,0xff,0xff,0x35,0xa4,0x01,0x00,0x39,0x62,0x00,0x03,0x2d,0x67,0x00,0x13, ++0xad,0x0a,0x00,0x00,0xa4,0xa3,0x00,0x00,0xac,0xc3,0x00,0x00,0xa7,0x89,0x8f,0xf0, ++0x10,0xe0,0x00,0x0f,0x00,0x82,0x68,0x0a,0x3c,0x03,0x80,0x01,0x00,0x0b,0x10,0x80, ++0x24,0x63,0x02,0x44,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x60, ++0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x00,0x00,0x02,0x74,0x03, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3a,0x94,0x44,0x00,0x00,0x93,0x83,0x8f,0xe4, ++0x91,0x82,0x00,0x21,0x01,0xc4,0x20,0x21,0x91,0x85,0x00,0x10,0x00,0x04,0x24,0x00, ++0x00,0x62,0x18,0x21,0x00,0x04,0x74,0x03,0x00,0x6e,0x18,0x23,0x00,0x65,0x10,0x2a, ++0x00,0xa2,0x18,0x0a,0x00,0x0d,0x24,0x00,0x3c,0x02,0xb0,0x06,0x24,0x05,0xff,0xff, ++0x00,0x64,0x18,0x25,0x34,0x42,0x80,0x20,0xac,0x43,0x00,0x00,0xa5,0x85,0x00,0x0e, ++0xa1,0x80,0x00,0x10,0xa5,0x85,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x62,0x3c,0x03,0xb0,0x03, ++0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x64,0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14, ++0x34,0x63,0x00,0x66,0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x38, ++0x3c,0x03,0xb0,0x03,0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x6e,0x3c,0x03,0xb0,0x03, ++0x08,0x00,0x19,0x14,0x34,0x63,0x00,0x6c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x34,0x63,0x00,0x20,0x24,0x42,0x65,0x08,0x00,0x05,0x28,0x40,0xac,0x62,0x00,0x00, ++0x00,0xa6,0x28,0x21,0x2c,0xe2,0x00,0x10,0x14,0x80,0x00,0x06,0x00,0x00,0x18,0x21, ++0x10,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0xe0,0x18,0x21,0x03,0xe0,0x00,0x08, ++0x00,0x60,0x10,0x21,0x24,0x02,0x00,0x20,0x10,0xe2,0x00,0x06,0x2c,0xe4,0x00,0x10, ++0x24,0xa2,0x00,0x01,0x10,0x80,0xff,0xf9,0x00,0x02,0x11,0x00,0x08,0x00,0x19,0x4f, ++0x00,0x47,0x18,0x21,0x08,0x00,0x19,0x4f,0x24,0xa3,0x00,0x50,0x27,0xbd,0xff,0xc8, ++0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x30, ++0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20, ++0xaf,0xb0,0x00,0x10,0x00,0x80,0x88,0x21,0x84,0x84,0x00,0x08,0x3c,0x05,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x65,0x6c,0x3c,0x03,0xb0,0x06, ++0x00,0x04,0x20,0x80,0xac,0xa2,0x00,0x00,0x00,0x83,0x20,0x21,0x3c,0x06,0xb0,0x06, ++0x8c,0x82,0x00,0x00,0x34,0xc6,0x80,0x24,0x8c,0x88,0x00,0x00,0x8c,0xc4,0x00,0x00, ++0x96,0x25,0x00,0x08,0x30,0x52,0xff,0xff,0x00,0x08,0x44,0x02,0x34,0x84,0x01,0x00, ++0x3c,0x02,0xb0,0x00,0x00,0x08,0x18,0xc0,0x00,0x12,0x3a,0x00,0xac,0xc4,0x00,0x00, ++0x00,0xe2,0x38,0x21,0xae,0x32,0x02,0xb8,0x00,0x68,0x18,0x21,0x24,0xa5,0x00,0x02, ++0x8c,0xf6,0x00,0x00,0x30,0xa5,0x01,0xff,0x8c,0xf4,0x00,0x04,0x27,0x86,0x90,0x00, ++0x00,0x03,0x18,0x80,0x00,0x12,0x98,0xc0,0xa6,0x25,0x00,0x08,0x00,0x66,0x18,0x21, ++0x02,0x72,0x10,0x21,0x94,0x65,0x00,0x00,0x00,0x02,0x48,0x80,0x01,0x26,0x30,0x21, ++0x24,0x02,0xff,0xff,0x00,0x14,0x1a,0x02,0x27,0x84,0x90,0x10,0xa4,0xc2,0x00,0x02, ++0x30,0x63,0x00,0x1f,0x24,0x02,0x00,0x10,0x01,0x24,0x20,0x21,0xa4,0xc8,0x00,0x04, ++0x8c,0xf0,0x00,0x08,0xa6,0x23,0x00,0x06,0xa6,0x25,0x00,0x0a,0xa0,0x82,0x00,0x06, ++0x86,0x25,0x00,0x06,0x27,0x82,0x90,0x04,0x01,0x22,0x10,0x21,0x24,0x03,0x00,0x13, ++0x10,0xa3,0x00,0xee,0xac,0x47,0x00,0x18,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, ++0xa6,0x20,0x00,0x02,0x3c,0x02,0xb0,0x03,0x90,0x64,0x00,0x00,0x34,0x42,0x01,0x08, ++0x8c,0x45,0x00,0x00,0x00,0x10,0x1b,0xc2,0x00,0x04,0x20,0x82,0x30,0x63,0x00,0x01, ++0xac,0xc5,0x00,0x08,0x10,0x60,0x00,0xc7,0x30,0x97,0x00,0x01,0x00,0x10,0x16,0x82, ++0x30,0x46,0x00,0x01,0x00,0x10,0x12,0x02,0x00,0x10,0x19,0xc2,0x00,0x10,0x26,0x02, ++0x00,0x10,0x2e,0x42,0x30,0x48,0x00,0x7f,0x24,0x02,0x00,0x01,0x30,0x75,0x00,0x01, ++0x30,0x84,0x00,0x01,0x10,0xc2,0x00,0xb3,0x30,0xa3,0x00,0x01,0x00,0x60,0x28,0x21, ++0x0c,0x00,0x19,0x42,0x01,0x00,0x38,0x21,0x02,0x72,0x18,0x21,0x00,0x03,0x18,0x80, ++0x2c,0x46,0x00,0x54,0x27,0x85,0x90,0x10,0x27,0x84,0x90,0x08,0x00,0x06,0x10,0x0a, ++0x00,0x65,0x28,0x21,0x26,0xa6,0x00,0x02,0x00,0x64,0x18,0x21,0xa0,0xa2,0x00,0x02, ++0xa0,0x66,0x00,0x06,0xa0,0x62,0x00,0x07,0xa0,0xa2,0x00,0x01,0x02,0x72,0x28,0x21, ++0x00,0x05,0x28,0x80,0x27,0x82,0x90,0x04,0x00,0xa2,0x58,0x21,0x8d,0x64,0x00,0x18, ++0x00,0x10,0x15,0xc2,0x30,0x42,0x00,0x01,0x8c,0x83,0x00,0x0c,0x27,0x84,0x90,0x20, ++0x00,0xa4,0x48,0x21,0xa6,0x22,0x00,0x00,0xa6,0x36,0x00,0x04,0x8d,0x26,0x00,0x00, ++0x00,0x03,0x19,0x42,0x3c,0x02,0xff,0xef,0x34,0x42,0xff,0xff,0x30,0x63,0x00,0x01, ++0x00,0xc2,0x40,0x24,0x00,0x03,0x1d,0x00,0x01,0x03,0x40,0x25,0x00,0x08,0x15,0x02, ++0x00,0x14,0x19,0x82,0x00,0x14,0x25,0x82,0x00,0x10,0x34,0x42,0x00,0x10,0x3c,0x82, ++0x00,0x10,0x2c,0x02,0x30,0x42,0x00,0x01,0x30,0xcd,0x00,0x01,0x30,0x6c,0x00,0x01, ++0x30,0xe6,0x00,0x01,0x30,0x8a,0x00,0x03,0x32,0x94,0x00,0x07,0x30,0xa5,0x00,0x01, ++0xad,0x28,0x00,0x00,0x10,0x40,0x00,0x0b,0x32,0x07,0x00,0x7f,0x8d,0x64,0x00,0x18, ++0x3c,0x03,0xff,0xf0,0x34,0x63,0xff,0xff,0x8c,0x82,0x00,0x0c,0x01,0x03,0x18,0x24, ++0x00,0x02,0x13,0x82,0x30,0x42,0x00,0x0f,0x00,0x02,0x14,0x00,0x00,0x62,0x18,0x25, ++0xad,0x23,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x6a,0x00,0x00,0x00,0x00, ++0x15,0x80,0x00,0x03,0x00,0x00,0x00,0x00,0x15,0x40,0x00,0x5b,0x24,0x02,0x00,0x01, ++0x96,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x04,0xa6,0x22,0x00,0x04, ++0x00,0xa0,0x20,0x21,0x0c,0x00,0x19,0x42,0x01,0xa0,0x28,0x21,0x02,0x72,0x18,0x21, ++0x00,0x03,0x40,0x80,0x2c,0x45,0x00,0x54,0x27,0x84,0x90,0x10,0x01,0x04,0x20,0x21, ++0x00,0x05,0x10,0x0a,0xa0,0x82,0x00,0x00,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, ++0x96,0x23,0x00,0x04,0x27,0x82,0x90,0x00,0x01,0x02,0x10,0x21,0xa4,0x43,0x00,0x06, ++0x27,0x82,0x90,0x04,0x92,0x26,0x00,0x01,0x01,0x02,0x10,0x21,0x8c,0x45,0x00,0x18, ++0x27,0x83,0x90,0x20,0x01,0x03,0x18,0x21,0xa0,0x60,0x00,0x00,0xa0,0x86,0x00,0x07, ++0x94,0xa2,0x00,0x10,0x24,0x03,0x00,0x04,0x30,0x42,0x00,0x0f,0x10,0x43,0x00,0x36, ++0x24,0xa5,0x00,0x10,0x94,0xa3,0x00,0x16,0x27,0x87,0x90,0x18,0x01,0x07,0x10,0x21, ++0xa4,0x43,0x00,0x02,0x94,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x24,0x02,0x72,0x20,0x21,0x94,0xa2,0x00,0x00,0x24,0x03,0x00,0xa4, ++0x30,0x42,0x00,0xff,0x10,0x43,0x00,0x1f,0x00,0x00,0x00,0x00,0x94,0xa2,0x00,0x00, ++0x24,0x03,0x00,0x88,0x30,0x42,0x00,0x88,0x10,0x43,0x00,0x14,0x02,0x72,0x18,0x21, ++0x27,0x84,0x90,0x20,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x3c,0x04,0x00,0x80,0x00,0x44,0x10,0x25,0xac,0x62,0x00,0x00,0x02,0x72,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0xa0,0x54,0x00,0x00,0x8f,0xbf,0x00,0x30, ++0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x94,0xa2,0x00,0x18, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x60,0x10,0x40,0xff,0xe9,0x02,0x72,0x18,0x21, ++0x02,0x72,0x20,0x21,0x27,0x82,0x90,0x20,0x00,0x04,0x20,0x80,0x00,0x82,0x20,0x21, ++0x8c,0x83,0x00,0x00,0x3c,0x02,0xff,0x7f,0x34,0x42,0xff,0xff,0x00,0x62,0x18,0x24, ++0x08,0x00,0x1a,0x37,0xac,0x83,0x00,0x00,0x27,0x87,0x90,0x18,0x01,0x07,0x10,0x21, ++0x08,0x00,0x1a,0x21,0xa4,0x40,0x00,0x02,0x11,0x42,0x00,0x07,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x02,0x14,0x40,0xff,0xa7,0x00,0xa0,0x20,0x21,0x96,0x22,0x00,0x04, ++0x08,0x00,0x19,0xff,0x24,0x42,0x00,0x0c,0x96,0x22,0x00,0x04,0x08,0x00,0x19,0xff, ++0x24,0x42,0x00,0x08,0x16,0xe6,0xff,0x96,0x3c,0x02,0xff,0xfb,0x8d,0x63,0x00,0x18, ++0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24,0xac,0x62,0x00,0x08,0x08,0x00,0x19,0xf8, ++0x00,0x00,0x30,0x21,0x16,0xe6,0xff,0x4e,0x00,0x60,0x28,0x21,0x3c,0x02,0xfb,0xff, ++0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24,0xac,0xe2,0x00,0x08,0x08,0x00,0x19,0xb7, ++0x00,0x00,0x30,0x21,0x93,0x87,0xbb,0x14,0x00,0x10,0x1e,0x42,0x00,0x10,0x26,0x82, ++0x27,0x82,0x90,0x08,0x2c,0xe5,0x00,0x0c,0x01,0x22,0x48,0x21,0x30,0x63,0x00,0x01, ++0x30,0x86,0x00,0x01,0x14,0xa0,0x00,0x06,0x00,0xe0,0x40,0x21,0x00,0x03,0x10,0x40, ++0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0xe2,0x10,0x21,0x24,0x48,0x00,0x04, ++0x02,0x72,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x90,0x10,0x27,0x83,0x90,0x08, ++0x00,0x44,0x20,0x21,0x00,0x43,0x10,0x21,0xa1,0x28,0x00,0x07,0xa0,0x40,0x00,0x06, ++0xa0,0x80,0x00,0x02,0x08,0x00,0x19,0xc7,0xa0,0x80,0x00,0x01,0x24,0x02,0x00,0x01, ++0xa6,0x22,0x00,0x02,0x0c,0x00,0x01,0xc2,0x00,0xe0,0x20,0x21,0x08,0x00,0x1a,0x3b, ++0x00,0x00,0x00,0x00,0x30,0xa7,0xff,0xff,0x00,0x07,0x18,0xc0,0x00,0x67,0x18,0x21, ++0x3c,0x06,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x6a,0x44,0x27,0x85,0x90,0x10, ++0x00,0x03,0x18,0x80,0x34,0xc6,0x00,0x20,0x00,0x65,0x18,0x21,0xac,0xc2,0x00,0x00, ++0x80,0x62,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x29,0x00,0x80,0x28,0x21, ++0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0x30,0x43,0x00,0x01, ++0x14,0x60,0x00,0x02,0xa0,0x82,0x00,0x16,0xa0,0x80,0x00,0x17,0x90,0xa2,0x00,0x04, ++0x3c,0x03,0xb0,0x03,0x27,0x86,0x90,0x00,0x14,0x40,0x00,0x06,0x34,0x63,0x00,0x20, ++0x24,0x02,0x00,0x01,0xa0,0xa2,0x00,0x04,0xa4,0xa7,0x00,0x02,0x03,0xe0,0x00,0x08, ++0xa4,0xa7,0x00,0x00,0x94,0xa4,0x00,0x02,0x3c,0x02,0x80,0x01,0x24,0x42,0x82,0x6c, ++0xac,0x62,0x00,0x00,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80, ++0x00,0x66,0x18,0x21,0x94,0x62,0x00,0x04,0xa4,0x67,0x00,0x02,0x3c,0x03,0xb0,0x08, ++0x00,0x02,0x20,0xc0,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21, ++0x00,0x83,0x20,0x21,0xa4,0x47,0x00,0x00,0xac,0x87,0x00,0x00,0x90,0xa2,0x00,0x04, ++0xa4,0xa7,0x00,0x02,0x24,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x04, ++0x90,0x82,0x00,0x16,0x24,0x85,0x00,0x06,0x34,0x42,0x00,0x01,0x30,0x43,0x00,0x02, ++0x14,0x60,0xff,0xda,0xa0,0x82,0x00,0x16,0x24,0x02,0x00,0x01,0x08,0x00,0x1a,0xa7, ++0xa0,0x82,0x00,0x17,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x00,0x80,0x38,0x21, ++0x84,0x84,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x3c,0x0a,0xb0,0x06, ++0x34,0x63,0x00,0x20,0x24,0x42,0x6b,0x44,0x3c,0x0b,0xb0,0x08,0x27,0x89,0x90,0x00, ++0x34,0x0c,0xff,0xff,0x35,0x4a,0x80,0x20,0x10,0x80,0x00,0x30,0xac,0x62,0x00,0x00, ++0x97,0x82,0x8f,0xf0,0x94,0xe6,0x02,0xba,0x00,0x02,0x18,0xc0,0x00,0x6b,0x28,0x21, ++0xac,0xa6,0x00,0x00,0x8c,0xe4,0x02,0xb8,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80, ++0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21, ++0x94,0x48,0x00,0x04,0x00,0x69,0x18,0x21,0xa4,0x66,0x00,0x00,0x00,0x08,0x28,0xc0, ++0x00,0xab,0x10,0x21,0xac,0x4c,0x00,0x00,0x8c,0xe4,0x02,0xb8,0x27,0x82,0x90,0x04, ++0x00,0xa8,0x28,0x21,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80, ++0x00,0x62,0x10,0x21,0x8c,0x46,0x00,0x18,0x27,0x84,0x90,0x10,0x00,0x64,0x18,0x21, ++0x8c,0xc2,0x00,0x00,0x80,0x67,0x00,0x06,0x00,0x05,0x28,0x80,0x30,0x42,0xff,0xff, ++0x00,0x47,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b,0x00,0x02,0x12,0x02, ++0x00,0x43,0x10,0x21,0x3c,0x04,0x00,0x04,0x00,0xa9,0x28,0x21,0x00,0x44,0x10,0x25, ++0xa4,0xac,0x00,0x00,0xad,0x42,0x00,0x00,0xa7,0x88,0x8f,0xf0,0x8f,0xbf,0x00,0x10, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x84,0xe3,0x00,0x06, ++0x27,0x82,0xb4,0x00,0x94,0xe5,0x02,0xba,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21, ++0x8c,0x64,0x00,0x00,0x0c,0x00,0x1a,0x91,0x00,0x00,0x00,0x00,0x08,0x00,0x1b,0x0b, ++0x00,0x00,0x00,0x00,0x94,0x88,0x00,0x00,0x00,0x80,0x58,0x21,0x27,0x8a,0x90,0x00, ++0x00,0x08,0x18,0xc0,0x00,0x68,0x18,0x21,0x3c,0x04,0xb0,0x03,0x00,0x03,0x18,0x80, ++0x3c,0x02,0x80,0x00,0x00,0x6a,0x18,0x21,0x34,0x84,0x00,0x20,0x24,0x42,0x6c,0x64, ++0x30,0xa5,0xff,0xff,0xac,0x82,0x00,0x00,0x94,0x67,0x00,0x02,0x11,0x05,0x00,0x35, ++0x24,0x04,0x00,0x01,0x91,0x66,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x86,0x10,0x2a, ++0x10,0x40,0x00,0x10,0x00,0xc0,0x48,0x21,0x3c,0x0d,0xb0,0x03,0x01,0x40,0x60,0x21, ++0x35,0xad,0x00,0x20,0x10,0xe5,0x00,0x0d,0x24,0x84,0x00,0x01,0x00,0x07,0x10,0xc0, ++0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x80,0x01,0x20,0x30,0x21,0x00,0x4a,0x10,0x21, ++0x00,0x86,0x18,0x2a,0x00,0xe0,0x40,0x21,0x94,0x47,0x00,0x02,0x14,0x60,0xff,0xf5, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21,0x00,0x08,0x20,0xc0, ++0x00,0x88,0x20,0x21,0x24,0xc2,0xff,0xff,0x00,0x04,0x20,0x80,0xa1,0x62,0x00,0x04, ++0x00,0x8c,0x20,0x21,0x94,0x83,0x00,0x04,0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x4c,0x10,0x21,0x00,0x03,0x28,0xc0,0x94,0x46,0x00,0x02, ++0x00,0xa3,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x6c,0x18,0x21,0xa4,0x66,0x00,0x00, ++0xa4,0x86,0x00,0x02,0x95,0x64,0x00,0x02,0x3c,0x03,0xb0,0x08,0x3c,0x02,0x80,0x01, ++0x00,0xa3,0x28,0x21,0x24,0x42,0x82,0x6c,0xad,0xa2,0x00,0x00,0x10,0x87,0x00,0x03, ++0xac,0xa6,0x00,0x00,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x08,0x00,0x1b,0x59, ++0xa5,0x68,0x00,0x02,0x91,0x62,0x00,0x04,0xa5,0x67,0x00,0x00,0x24,0x42,0xff,0xff, ++0x30,0x43,0x00,0xff,0x14,0x60,0xff,0xf7,0xa1,0x62,0x00,0x04,0x24,0x02,0xff,0xff, ++0x08,0x00,0x1b,0x59,0xa5,0x62,0x00,0x02,0x00,0x05,0x40,0xc0,0x01,0x05,0x30,0x21, ++0x27,0xbd,0xff,0xd8,0x00,0x06,0x30,0x80,0x27,0x82,0x90,0x04,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb0,0x00,0x10, ++0x00,0xc2,0x10,0x21,0x8c,0x47,0x00,0x18,0x00,0xa0,0x90,0x21,0x3c,0x02,0x80,0x00, ++0x3c,0x05,0xb0,0x03,0x34,0xa5,0x00,0x20,0x24,0x42,0x6d,0x98,0xac,0xa2,0x00,0x00, ++0x27,0x83,0x90,0x10,0x00,0xc3,0x30,0x21,0x8c,0xe2,0x00,0x00,0x80,0xc5,0x00,0x06, ++0x00,0x80,0x88,0x21,0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff, ++0x10,0x60,0x00,0x02,0x00,0x02,0x12,0x02,0x24,0x42,0x00,0x01,0x30,0x53,0x00,0xff, ++0x01,0x12,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x10,0x00,0x43,0x10,0x21, ++0x80,0x44,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x4b,0x26,0x24,0x00,0x06, ++0x32,0x50,0xff,0xff,0x02,0x20,0x20,0x21,0x0c,0x00,0x1b,0x19,0x02,0x00,0x28,0x21, ++0x92,0x22,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x2e,0x3c,0x03,0xb0,0x08, ++0x3c,0x09,0x80,0x01,0x27,0x88,0x90,0x00,0xa6,0x32,0x00,0x0c,0x00,0x10,0x20,0xc0, ++0x00,0x90,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04, ++0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x48,0x10,0x21,0x00,0xa3,0x28,0x21,0x25,0x26,0x82,0x6c, ++0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02, ++0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00,0x92,0x22,0x00,0x10,0x92,0x23,0x00,0x0a, ++0xa6,0x32,0x00,0x0e,0x02,0x62,0x10,0x21,0x14,0x60,0x00,0x05,0xa2,0x22,0x00,0x10, ++0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfe,0xa2,0x22,0x00,0x16, ++0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00, ++0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa2,0x22,0x00,0x16, ++0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x28,0x96,0x22,0x00,0x0e,0x27,0x88,0x90,0x00,0x00,0x02,0x20,0xc0, ++0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04, ++0x3c,0x06,0xb0,0x03,0x3c,0x09,0x80,0x01,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21,0x00,0x48,0x10,0x21,0x34,0xc6,0x00,0x20, ++0x25,0x23,0x82,0x6c,0xac,0xc3,0x00,0x00,0xa4,0x50,0x00,0x00,0xac,0xb0,0x00,0x00, ++0x08,0x00,0x1b,0x97,0xa4,0x90,0x00,0x02,0x08,0x00,0x1b,0x8e,0x32,0x50,0xff,0xff, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x6f,0x60,0x34,0x63,0x00,0x20, ++0xac,0x62,0x00,0x00,0x90,0x82,0x00,0x04,0x97,0xaa,0x00,0x12,0x00,0x80,0x60,0x21, ++0x30,0xa8,0xff,0xff,0x00,0x4a,0x20,0x23,0x34,0x09,0xff,0xff,0x30,0xcf,0xff,0xff, ++0x30,0xee,0xff,0xff,0x11,0x09,0x00,0x73,0xa1,0x84,0x00,0x04,0x00,0x0e,0xc0,0xc0, ++0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21,0x03,0x0e,0x20,0x21,0x27,0x8d,0x90,0x00, ++0x00,0x04,0x20,0x80,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0x8d,0x20,0x21, ++0x94,0x86,0x00,0x02,0x94,0x43,0x00,0x04,0x3c,0x19,0x80,0x01,0xa4,0x46,0x00,0x02, ++0x00,0x03,0x28,0xc0,0x00,0xa3,0x18,0x21,0x94,0x87,0x00,0x02,0x3c,0x02,0xb0,0x08, ++0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x21,0x00,0x6d,0x18,0x21,0x27,0x22,0x82,0x6c, ++0x3c,0x01,0xb0,0x03,0xac,0x22,0x00,0x20,0xa4,0x66,0x00,0x00,0x10,0xe9,0x00,0x57, ++0xac,0xa6,0x00,0x00,0x01,0xe0,0x30,0x21,0x11,0x40,0x00,0x1d,0x00,0x00,0x48,0x21, ++0x01,0x40,0x38,0x21,0x27,0x8b,0x90,0x04,0x27,0x8a,0x90,0x10,0x00,0x06,0x40,0xc0, ++0x01,0x06,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x6b,0x10,0x21,0x8c,0x44,0x00,0x18, ++0x00,0x6a,0x18,0x21,0x80,0x65,0x00,0x06,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21,0x30,0x44,0x00,0xff,0x00,0x02,0x12,0x02, ++0x01,0x22,0x18,0x21,0x24,0x62,0x00,0x01,0x14,0x80,0x00,0x02,0x30,0x49,0x00,0xff, ++0x30,0x69,0x00,0xff,0x01,0x06,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21, ++0x24,0xe7,0xff,0xff,0x94,0x46,0x00,0x02,0x14,0xe0,0xff,0xe9,0x00,0x06,0x40,0xc0, ++0x91,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20,0x3c,0x06,0xb0,0x03, ++0xa5,0x8f,0x00,0x0c,0x03,0x0e,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21, ++0x94,0x82,0x00,0x04,0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0, ++0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0xa3,0x28,0x21, ++0x27,0x26,0x82,0x6c,0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00, ++0xa4,0x83,0x00,0x02,0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00,0x91,0x82,0x00,0x10, ++0x91,0x83,0x00,0x04,0xa5,0x8e,0x00,0x0e,0x01,0x22,0x10,0x21,0x14,0x60,0x00,0x05, ++0xa1,0x82,0x00,0x10,0x91,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd, ++0xa1,0x82,0x00,0x16,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x95,0x82,0x00,0x0e, ++0x3c,0x03,0xb0,0x08,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80, ++0x00,0x8d,0x20,0x21,0x94,0x82,0x00,0x04,0x34,0xc6,0x00,0x20,0x27,0x27,0x82,0x6c, ++0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21, ++0x00,0x4d,0x10,0x21,0xac,0xc7,0x00,0x00,0xa4,0x8f,0x00,0x02,0xa4,0x4f,0x00,0x00, ++0xac,0xaf,0x00,0x00,0x08,0x00,0x1c,0x26,0x03,0x0e,0x20,0x21,0x08,0x00,0x1c,0x01, ++0xa5,0x88,0x00,0x02,0x00,0x0e,0xc0,0xc0,0x03,0x0e,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x8d,0x90,0x00,0x00,0x4d,0x10,0x21,0x94,0x43,0x00,0x02,0x30,0x84,0x00,0xff, ++0x14,0x80,0x00,0x05,0xa5,0x83,0x00,0x00,0x24,0x02,0xff,0xff,0x3c,0x19,0x80,0x01, ++0x08,0x00,0x1c,0x01,0xa5,0x82,0x00,0x02,0x08,0x00,0x1c,0x01,0x3c,0x19,0x80,0x01, ++0x3c,0x08,0xb0,0x03,0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0x78,0x35,0x08,0x00,0x20, ++0x24,0x42,0x71,0xa0,0xaf,0xb2,0x00,0x68,0xaf,0xb1,0x00,0x64,0xaf,0xb0,0x00,0x60, ++0xad,0x02,0x00,0x00,0xaf,0xbf,0x00,0x84,0xaf,0xbe,0x00,0x80,0xaf,0xb7,0x00,0x7c, ++0xaf,0xb6,0x00,0x78,0xaf,0xb5,0x00,0x74,0xaf,0xb4,0x00,0x70,0xaf,0xb3,0x00,0x6c, ++0xaf,0xa4,0x00,0x88,0x90,0x83,0x00,0x0a,0x27,0x82,0xb4,0x00,0xaf,0xa6,0x00,0x90, ++0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x63,0x00,0x00,0xaf,0xa7,0x00,0x94, ++0x27,0x86,0x90,0x04,0xaf,0xa3,0x00,0x1c,0x94,0x63,0x00,0x14,0x30,0xb1,0xff,0xff, ++0x24,0x08,0x00,0x01,0x00,0x03,0x20,0xc0,0xaf,0xa3,0x00,0x18,0x00,0x83,0x18,0x21, ++0xaf,0xa4,0x00,0x54,0x00,0x03,0x18,0x80,0x27,0x84,0x90,0x10,0x00,0x64,0x20,0x21, ++0x80,0x82,0x00,0x06,0x00,0x66,0x18,0x21,0x8c,0x66,0x00,0x18,0x24,0x42,0x00,0x02, ++0x00,0x02,0x1f,0xc2,0x8c,0xc4,0x00,0x08,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x00,0x02,0x10,0x40,0x00,0x04,0x2f,0xc2,0x00,0x04,0x1c,0x82,0x00,0xc2,0x38,0x21, ++0x00,0x04,0x24,0x42,0x8f,0xa2,0x00,0x1c,0x30,0x63,0x00,0x01,0x30,0x84,0x00,0x01, ++0xaf,0xa5,0x00,0x3c,0xaf,0xa3,0x00,0x34,0xaf,0xa4,0x00,0x38,0xaf,0xa0,0x00,0x40, ++0xaf,0xa0,0x00,0x44,0xaf,0xa0,0x00,0x50,0xaf,0xa8,0x00,0x20,0x80,0x42,0x00,0x12, ++0x8f,0xb2,0x00,0x18,0xaf,0xa2,0x00,0x28,0x8c,0xd0,0x00,0x0c,0x14,0xa0,0x01,0xe4, ++0x00,0x60,0x30,0x21,0x00,0x10,0x10,0x82,0x30,0x45,0x00,0x07,0x10,0xa0,0x00,0x11, ++0xaf,0xa0,0x00,0x30,0x8f,0xa4,0x00,0x98,0x27,0x82,0x80,0x1c,0x00,0x04,0x18,0x40, ++0x00,0x62,0x18,0x21,0x24,0xa2,0x00,0x06,0x8f,0xa5,0x00,0x20,0x94,0x64,0x00,0x00, ++0x00,0x45,0x10,0x04,0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00, ++0x00,0x07,0x00,0x0d,0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20,0x30,0x42,0xff,0xfc, ++0xaf,0xa2,0x00,0x30,0x8f,0xa3,0x00,0x18,0x8f,0xa4,0x00,0x28,0x34,0x02,0xff,0xff, ++0xaf,0xa0,0x00,0x2c,0xaf,0xa2,0x00,0x48,0xaf,0xa3,0x00,0x4c,0x00,0x60,0xf0,0x21, ++0x00,0x00,0xb8,0x21,0x18,0x80,0x00,0x48,0xaf,0xa0,0x00,0x24,0x00,0x11,0x89,0x02, ++0xaf,0xb1,0x00,0x58,0x00,0x80,0xa8,0x21,0x00,0x12,0x10,0xc0,0x00,0x52,0x18,0x21, ++0x00,0x03,0x80,0x80,0x27,0x85,0x90,0x00,0x02,0x40,0x20,0x21,0x00,0x40,0xa0,0x21, ++0x02,0x05,0x10,0x21,0x94,0x56,0x00,0x02,0x0c,0x00,0x12,0x8b,0x00,0x00,0x28,0x21, ++0x90,0x42,0x00,0x00,0x24,0x03,0x00,0x08,0x30,0x42,0x00,0x0c,0x10,0x43,0x01,0x9e, ++0x24,0x04,0x00,0x01,0x24,0x02,0x00,0x01,0x10,0x82,0x01,0x7c,0x3c,0x02,0xb0,0x03, ++0x8f,0xa6,0x00,0x88,0x34,0x42,0x01,0x04,0x84,0xc5,0x00,0x0c,0x02,0x92,0x18,0x21, ++0x94,0x46,0x00,0x00,0x00,0x05,0x20,0xc0,0x00,0x85,0x20,0x21,0x00,0x03,0x18,0x80, ++0x27,0x82,0x90,0x10,0x27,0x85,0x90,0x08,0x00,0x65,0x28,0x21,0x00,0x62,0x18,0x21, ++0x80,0x71,0x00,0x05,0x80,0x73,0x00,0x04,0x8f,0xa3,0x00,0x88,0x30,0xd0,0xff,0xff, ++0x00,0x10,0x3a,0x03,0x32,0x08,0x00,0xff,0x27,0x82,0x90,0x20,0x00,0x04,0x20,0x80, ++0x80,0xa6,0x00,0x06,0x00,0x82,0x20,0x21,0xa4,0x67,0x00,0x44,0xa4,0x68,0x00,0x46, ++0x8c,0x84,0x00,0x00,0x38,0xc6,0x00,0x00,0x01,0x00,0x80,0x21,0x00,0x04,0x15,0x02, ++0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x03,0x00,0xe6,0x80,0x0a,0x00,0x04,0x14,0x02, ++0x30,0x50,0x00,0x0f,0x12,0x20,0x01,0x50,0x02,0x40,0x20,0x21,0x02,0x71,0x10,0x21, ++0x00,0x50,0x10,0x2a,0x14,0x40,0x00,0xed,0x02,0x92,0x10,0x21,0x93,0x82,0x8b,0x71, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0xe0,0x02,0x92,0x28,0x21, ++0x26,0xe2,0x00,0x01,0x30,0x57,0xff,0xff,0x02,0x40,0xf0,0x21,0x26,0xb5,0xff,0xff, ++0x16,0xa0,0xff,0xbd,0x02,0xc0,0x90,0x21,0x16,0xe0,0x00,0xd0,0x00,0x00,0x00,0x00, ++0x8f,0xa3,0x00,0x98,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x10,0x10,0x40,0x00,0x2e, ++0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x24,0x00,0x00,0x00,0x00,0x18,0x80,0x00,0x2a, ++0x24,0x03,0x00,0x01,0x8f,0xa5,0x00,0x1c,0x27,0x84,0x90,0x04,0x94,0xb2,0x00,0x14, ++0xa0,0xa3,0x00,0x12,0x8f,0xa6,0x00,0x3c,0x00,0x12,0x10,0xc0,0x00,0x52,0x10,0x21, ++0x00,0x02,0x80,0x80,0x27,0x82,0x90,0x10,0x02,0x02,0x10,0x21,0x80,0x43,0x00,0x06, ++0x02,0x04,0x20,0x21,0x8c,0x85,0x00,0x18,0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2, ++0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40,0x14,0xc0,0x00,0x0e, ++0x00,0xa3,0x38,0x21,0x27,0x82,0x90,0x00,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06, ++0x8f,0xa8,0x00,0x1c,0x24,0x02,0x00,0x01,0xa5,0x03,0x00,0x1a,0x7b,0xbe,0x04,0x3c, ++0x7b,0xb6,0x03,0xfc,0x7b,0xb4,0x03,0xbc,0x7b,0xb2,0x03,0x7c,0x7b,0xb0,0x03,0x3c, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x88,0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38, ++0x8f,0xa6,0x00,0x34,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x0a,0xaf,0xa0,0x00,0x14, ++0x08,0x00,0x1d,0x2d,0x00,0x00,0x00,0x00,0x8f,0xa3,0x00,0x44,0x93,0x82,0x81,0x58, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x61,0x30,0x69,0x00,0x03,0x8f,0xa4,0x00,0x24, ++0x8f,0xa5,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x85,0x10,0x2a,0x10,0x40,0x00,0x8f, ++0x00,0x00,0x00,0x00,0x8f,0xa6,0x00,0x1c,0x00,0x00,0x00,0x00,0x90,0xc4,0x00,0x04, ++0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x00,0xa3,0x10,0x2a,0x10,0x40,0x00,0x87, ++0x00,0x00,0x00,0x00,0x8f,0xa8,0x00,0x24,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x83, ++0x00,0x65,0x10,0x23,0x00,0xa8,0x18,0x23,0x00,0x62,0x10,0x2a,0x14,0x40,0x00,0x7d, ++0x30,0x63,0x00,0xff,0x00,0x85,0x10,0x23,0x30,0x42,0x00,0xff,0xaf,0xa2,0x00,0x50, ++0x8f,0xa2,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x73,0x00,0x00,0xa8,0x21, ++0x27,0x8c,0x90,0x00,0x3c,0x0b,0x80,0xff,0x24,0x10,0x00,0x04,0x27,0x91,0x90,0x04, ++0x35,0x6b,0xff,0xff,0x3c,0x0d,0x7f,0x00,0x27,0x8e,0x90,0x10,0x01,0x80,0x78,0x21, ++0x00,0x12,0x30,0xc0,0x00,0xd2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4c,0x10,0x21, ++0x94,0x42,0x00,0x06,0x8f,0xa3,0x00,0x2c,0x8f,0xa4,0x00,0x30,0xaf,0xa2,0x00,0x44, ++0x8f,0xa5,0x00,0x44,0x30,0x49,0x00,0x03,0x02,0x09,0x10,0x23,0x30,0x42,0x00,0x03, ++0x00,0xa2,0x10,0x21,0x8f,0xa8,0x00,0x30,0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff, ++0x00,0x64,0x38,0x21,0x01,0x02,0x28,0x23,0x00,0x62,0x18,0x21,0x00,0x48,0x10,0x2b, ++0x10,0x40,0x00,0x52,0x00,0x00,0x20,0x21,0x30,0xe7,0xff,0xff,0x30,0xa4,0xff,0xff, ++0xaf,0xa7,0x00,0x2c,0x00,0xd2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x51,0x18,0x21, ++0x8c,0x65,0x00,0x18,0x00,0x04,0x25,0x40,0x00,0x8d,0x20,0x24,0x8c,0xa8,0x00,0x04, ++0x00,0x4e,0x18,0x21,0x00,0x4f,0x50,0x21,0x01,0x0b,0x40,0x24,0x01,0x04,0x40,0x25, ++0xac,0xa8,0x00,0x04,0x8f,0xa4,0x00,0x98,0x8f,0xa2,0x00,0x50,0x26,0xb5,0x00,0x01, ++0xa0,0x64,0x00,0x00,0x8c,0xa4,0x00,0x08,0x00,0x00,0x00,0x00,0x04,0x81,0x00,0x0c, ++0x02,0xa2,0x30,0x2a,0x80,0x62,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, ++0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, ++0x00,0xa2,0x38,0x21,0x8f,0xa5,0x00,0x40,0x00,0x00,0x00,0x00,0xa4,0xe5,0x00,0x00, ++0x95,0x52,0x00,0x02,0x14,0xc0,0xff,0xc7,0x00,0x12,0x30,0xc0,0x8f,0xa4,0x00,0x24, ++0x8f,0xa5,0x00,0x50,0x8f,0xa6,0x00,0x1c,0x8f,0xa3,0x00,0x2c,0x00,0x85,0x80,0x21, ++0xa0,0xd0,0x00,0x12,0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03,0x8f,0xa8,0x00,0x88, ++0x00,0x62,0x10,0x23,0xa4,0xc2,0x00,0x1a,0x85,0x03,0x00,0x0c,0x00,0x00,0x00,0x00, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x04, ++0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04, ++0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0xff,0x74,0x02,0x00,0x10,0x21, ++0x8f,0xa3,0x00,0x54,0x8f,0xa4,0x00,0x18,0x8f,0xa5,0x00,0x24,0x00,0x64,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x90,0x18,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00, ++0x10,0xa0,0x00,0x03,0x00,0x00,0x30,0x21,0x08,0x00,0x1d,0x33,0x02,0x00,0x10,0x21, ++0x93,0x82,0x80,0x10,0x00,0x00,0x28,0x21,0x00,0x00,0x38,0x21,0x0c,0x00,0x21,0x9a, ++0xaf,0xa2,0x00,0x10,0x08,0x00,0x1d,0x33,0x02,0x00,0x10,0x21,0x30,0x63,0xff,0xff, ++0x08,0x00,0x1d,0x85,0xaf,0xa3,0x00,0x2c,0x8f,0xa8,0x00,0x44,0x08,0x00,0x1d,0xa7, ++0x31,0x09,0x00,0x03,0x08,0x00,0x1d,0x60,0xaf,0xa3,0x00,0x50,0x8f,0xa6,0x00,0x44, ++0xaf,0xa0,0x00,0x50,0x08,0x00,0x1d,0xa7,0x30,0xc9,0x00,0x03,0x8f,0xa5,0x00,0x48, ++0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c,0x03,0xc0,0x38,0x21,0x0c,0x00,0x1b,0xd8, ++0xaf,0xb7,0x00,0x10,0x08,0x00,0x1d,0x10,0x00,0x00,0x00,0x00,0x00,0x05,0x28,0x80, ++0x27,0x82,0x90,0x00,0x00,0xa2,0x28,0x21,0x00,0x00,0x20,0x21,0x0c,0x00,0x01,0x49, ++0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0x09,0x26,0xe2,0x00,0x01,0x00,0x02,0x80,0x80, ++0x27,0x83,0x90,0x10,0x8f,0xa4,0x00,0x1c,0x02,0x03,0x18,0x21,0x26,0x31,0x00,0x01, ++0x02,0x40,0x28,0x21,0x0c,0x00,0x1e,0xea,0xa0,0x71,0x00,0x05,0x14,0x40,0xff,0x13, ++0x00,0x00,0x00,0x00,0x16,0xe0,0x00,0x4d,0x03,0xc0,0x38,0x21,0x8f,0xa4,0x00,0x24, ++0x8f,0xa5,0x00,0x20,0x24,0x02,0x00,0x01,0x24,0x84,0x00,0x01,0xaf,0xb2,0x00,0x48, ++0xaf,0xb6,0x00,0x4c,0x02,0xc0,0xf0,0x21,0x10,0xa2,0x00,0x41,0xaf,0xa4,0x00,0x24, ++0x27,0x82,0x90,0x00,0x02,0x02,0x10,0x21,0x94,0x42,0x00,0x06,0x8f,0xa4,0x00,0x30, ++0xaf,0xa0,0x00,0x20,0xaf,0xa2,0x00,0x44,0x30,0x49,0x00,0x03,0x8f,0xa8,0x00,0x44, ++0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03,0x01,0x02,0x10,0x21,0x24,0x42,0x00,0x04, ++0x30,0x42,0xff,0xff,0x00,0x44,0x18,0x2b,0x10,0x60,0x00,0x2b,0x00,0x00,0x00,0x00, ++0x8f,0xa5,0x00,0x2c,0x00,0x82,0x10,0x23,0x00,0xa4,0x18,0x21,0x30,0x63,0xff,0xff, ++0x30,0x44,0xff,0xff,0xaf,0xa3,0x00,0x2c,0x02,0x92,0x28,0x21,0x00,0x05,0x28,0x80, ++0x27,0x82,0x90,0x04,0x00,0xa2,0x10,0x21,0x8c,0x46,0x00,0x18,0x3c,0x03,0x80,0xff, ++0x3c,0x02,0x7f,0x00,0x8c,0xc8,0x00,0x04,0x00,0x04,0x25,0x40,0x34,0x63,0xff,0xff, ++0x00,0x82,0x20,0x24,0x01,0x03,0x40,0x24,0x01,0x04,0x40,0x25,0xac,0xc8,0x00,0x04, ++0x8f,0xa8,0x00,0x98,0x27,0x82,0x90,0x10,0x00,0xa2,0x10,0x21,0xa0,0x48,0x00,0x00, ++0x8c,0xc4,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x27,0xc2,0x10,0x80,0xfe,0xdb, ++0xaf,0xa4,0x00,0x3c,0x80,0x42,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, ++0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, ++0x00,0xc2,0x38,0x21,0x8f,0xa2,0x00,0x40,0x00,0x00,0x00,0x00,0xa4,0xe2,0x00,0x00, ++0x08,0x00,0x1d,0x0c,0x26,0xb5,0xff,0xff,0x8f,0xa6,0x00,0x2c,0x00,0x00,0x20,0x21, ++0x00,0xc2,0x10,0x21,0x30,0x42,0xff,0xff,0x08,0x00,0x1e,0x1a,0xaf,0xa2,0x00,0x2c, ++0x8f,0xa6,0x00,0x1c,0x08,0x00,0x1e,0x04,0xa4,0xd2,0x00,0x14,0x8f,0xa5,0x00,0x48, ++0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c,0x0c,0x00,0x1b,0xd8,0xaf,0xb7,0x00,0x10, ++0x08,0x00,0x1d,0xfb,0x00,0x00,0xb8,0x21,0x0c,0x00,0x12,0x8b,0x00,0x00,0x28,0x21, ++0x00,0x40,0x18,0x21,0x94,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x42,0x08,0x00, ++0xa4,0x62,0x00,0x00,0x08,0x00,0x1d,0x00,0x02,0x71,0x10,0x21,0x02,0x92,0x18,0x21, ++0x00,0x03,0x80,0x80,0x27,0x82,0x90,0x04,0x02,0x02,0x10,0x21,0x8c,0x44,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10, ++0x10,0x60,0x00,0x09,0x24,0x06,0x00,0x01,0x93,0x82,0x8b,0x71,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x01,0x10,0x40,0xfe,0xa2,0x3c,0x04,0x00,0x80,0x27,0x85,0x90,0x00, ++0x08,0x00,0x1d,0xeb,0x02,0x05,0x28,0x21,0x27,0x83,0x90,0x18,0x27,0x82,0x90,0x10, ++0x02,0x03,0x18,0x21,0x02,0x02,0x10,0x21,0x90,0x64,0x00,0x00,0x90,0x45,0x00,0x05, ++0x93,0x83,0x80,0x10,0x00,0x00,0x38,0x21,0x0c,0x00,0x21,0x9a,0xaf,0xa3,0x00,0x10, ++0x08,0x00,0x1e,0x62,0x00,0x00,0x00,0x00,0x27,0x82,0x90,0x18,0x02,0x02,0x10,0x21, ++0x94,0x43,0x00,0x02,0x8f,0xa6,0x00,0x58,0x00,0x03,0x19,0x02,0x00,0x66,0x18,0x23, ++0x30,0x63,0x0f,0xff,0x28,0x62,0x00,0x20,0x10,0x40,0x00,0x06,0x28,0x62,0x00,0x40, ++0x8f,0xa8,0x00,0x90,0x00,0x00,0x00,0x00,0x00,0x68,0x10,0x06,0x08,0x00,0x1c,0xd9, ++0x30,0x44,0x00,0x01,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x94, ++0x08,0x00,0x1e,0x83,0x00,0x64,0x10,0x06,0x08,0x00,0x1c,0xd9,0x00,0x00,0x20,0x21, ++0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x0a, ++0xaf,0xa8,0x00,0x14,0x30,0x42,0xff,0xff,0x08,0x00,0x1c,0xa9,0xaf,0xa2,0x00,0x40, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00,0x27,0xbd,0xff,0xe0,0x34,0x42,0x00,0x20, ++0x24,0x63,0x7a,0x50,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, ++0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x0a,0x00,0x80,0x80,0x21,0x14,0x40,0x00,0x45, ++0x00,0x00,0x88,0x21,0x92,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x3c, ++0x00,0x00,0x00,0x00,0x12,0x20,0x00,0x18,0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16, ++0x92,0x05,0x00,0x0a,0x30,0x42,0x00,0xfc,0x10,0xa0,0x00,0x03,0xa2,0x02,0x00,0x16, ++0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16,0x92,0x04,0x00,0x04,0x00,0x00,0x00,0x00, ++0x30,0x83,0x00,0xff,0x10,0x60,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16, ++0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0xa2,0x02,0x00,0x16,0x10,0x60,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x08,0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x00, ++0xa2,0x00,0x00,0x17,0xa6,0x02,0x00,0x14,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x14,0x80,0x00,0x05,0x24,0x02,0x00,0x01, ++0x96,0x03,0x00,0x06,0xa2,0x02,0x00,0x17,0x08,0x00,0x1e,0xbe,0xa6,0x03,0x00,0x14, ++0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06,0x27,0x86,0x90,0x00,0x00,0x04,0x10,0xc0, ++0x00,0x05,0x18,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21,0x00,0x02,0x10,0x80, ++0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, ++0x8c,0x44,0x00,0x08,0x0c,0x00,0x12,0x7c,0x00,0x00,0x00,0x00,0x30,0x43,0x00,0xff, ++0x10,0x60,0x00,0x04,0xa2,0x02,0x00,0x17,0x96,0x02,0x00,0x06,0x08,0x00,0x1e,0xbe, ++0xa6,0x02,0x00,0x14,0x96,0x02,0x00,0x00,0x08,0x00,0x1e,0xbe,0xa6,0x02,0x00,0x14, ++0x96,0x05,0x00,0x00,0x0c,0x00,0x1e,0xea,0x02,0x00,0x20,0x21,0x08,0x00,0x1e,0xa5, ++0x02,0x22,0x88,0x21,0x94,0x85,0x00,0x06,0x0c,0x00,0x1e,0xea,0x00,0x00,0x00,0x00, ++0x08,0x00,0x1e,0xa1,0x00,0x40,0x88,0x21,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x34,0x63,0x00,0x20,0x24,0x42,0x7b,0xa8,0x27,0xbd,0xff,0xf0,0xac,0x62,0x00,0x00, ++0x00,0x00,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x10,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x7b,0xcc,0xac,0x62,0x00,0x00, ++0x90,0x89,0x00,0x0a,0x00,0x80,0x30,0x21,0x11,0x20,0x00,0x05,0x00,0xa0,0x50,0x21, ++0x90,0x82,0x00,0x17,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1b,0x00,0x00,0x00,0x00, ++0x90,0xc7,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0xe0,0x00,0x1b,0x00,0x00,0x00,0x00, ++0x94,0xc8,0x00,0x00,0x27,0x83,0x90,0x00,0x93,0x85,0x8b,0x70,0x00,0x08,0x10,0xc0, ++0x00,0x48,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x08, ++0x00,0xe5,0x28,0x2b,0x10,0xa0,0x00,0x06,0x01,0x44,0x18,0x23,0x8f,0x82,0x8b,0x88, ++0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00, ++0x24,0x03,0x00,0x10,0xa4,0xc8,0x00,0x14,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, ++0x11,0x20,0x00,0x05,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x06,0x24,0x03,0x00,0x08, ++0x08,0x00,0x1f,0x16,0xa4,0xc2,0x00,0x14,0x08,0x00,0x1f,0x16,0x00,0x00,0x18,0x21, ++0x27,0xbd,0xff,0xc8,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24, ++0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x30,0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c, ++0x94,0x91,0x00,0x06,0x00,0x80,0xa0,0x21,0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03, ++0x00,0x11,0xa8,0xc0,0x34,0x84,0x00,0x20,0x24,0x42,0x7c,0x80,0x02,0xb1,0x48,0x21, ++0xac,0x82,0x00,0x00,0x00,0x09,0x48,0x80,0x24,0x03,0x00,0x01,0x27,0x82,0x90,0x10, ++0xa2,0x83,0x00,0x12,0x01,0x22,0x10,0x21,0x27,0x84,0x90,0x04,0x01,0x24,0x20,0x21, ++0x80,0x48,0x00,0x06,0x8c,0x8a,0x00,0x18,0x27,0x83,0x90,0x20,0x01,0x23,0x48,0x21, ++0x8d,0x24,0x00,0x00,0x25,0x08,0x00,0x02,0x8d,0x42,0x00,0x00,0x8d,0x49,0x00,0x04, ++0x00,0x08,0x17,0xc2,0x8d,0x43,0x00,0x08,0x01,0x02,0x40,0x21,0x00,0x04,0x25,0xc2, ++0x00,0x08,0x40,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x1f,0xc2,0x00,0x08,0x40,0x40, ++0x00,0xe0,0x80,0x21,0x00,0x64,0x18,0x24,0x00,0x09,0x49,0x42,0x01,0x48,0x10,0x21, ++0x00,0xa0,0x98,0x21,0x00,0xa0,0x20,0x21,0x00,0x40,0x38,0x21,0x02,0x00,0x28,0x21, ++0x14,0x60,0x00,0x19,0x31,0x29,0x00,0x01,0x94,0x42,0x00,0x00,0x02,0xb1,0x88,0x21, ++0x02,0x00,0x28,0x21,0x00,0x11,0x88,0x80,0x27,0x90,0x90,0x00,0x02,0x30,0x80,0x21, ++0x96,0x03,0x00,0x06,0x30,0x52,0xff,0xff,0x02,0x60,0x20,0x21,0x00,0x60,0x30,0x21, ++0xa6,0x83,0x00,0x1a,0x27,0x82,0x90,0x08,0x0c,0x00,0x08,0xe3,0x02,0x22,0x88,0x21, ++0x00,0x52,0x10,0x21,0x96,0x03,0x00,0x06,0xa6,0x22,0x00,0x04,0x8f,0xbf,0x00,0x30, ++0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x00,0x60,0x10,0x21, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0xaf,0xa9,0x00,0x10,0x0c,0x00,0x09,0x0a, ++0xaf,0xa0,0x00,0x14,0x08,0x00,0x1f,0x54,0x02,0xb1,0x88,0x21,0x27,0xbd,0xff,0xc0, ++0xaf,0xbe,0x00,0x38,0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb5,0x00,0x2c, ++0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x3c,0xaf,0xb4,0x00,0x28, ++0xaf,0xb2,0x00,0x20,0xaf,0xb0,0x00,0x18,0x94,0x90,0x00,0x00,0x3c,0x08,0xb0,0x03, ++0x35,0x08,0x00,0x20,0x00,0x10,0x10,0xc0,0x00,0x50,0x18,0x21,0x00,0x40,0x88,0x21, ++0x3c,0x02,0x80,0x00,0x00,0x03,0x48,0x80,0x24,0x42,0x7d,0xbc,0x00,0x80,0x98,0x21, ++0x27,0x84,0x90,0x10,0x01,0x24,0x20,0x21,0x93,0xb7,0x00,0x53,0xad,0x02,0x00,0x00, ++0x80,0x83,0x00,0x06,0x27,0x82,0x90,0x04,0x01,0x22,0x10,0x21,0x8c,0x44,0x00,0x18, ++0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2,0x8c,0x88,0x00,0x08,0x00,0x62,0x18,0x21, ++0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40,0xaf,0xa7,0x00,0x4c,0x2c,0xa2,0x00,0x10, ++0x00,0xa0,0xa8,0x21,0x00,0x83,0x50,0x21,0x00,0x08,0x47,0xc2,0x00,0xc0,0x58,0x21, ++0x00,0x00,0xb0,0x21,0x8c,0x92,0x00,0x0c,0x14,0x40,0x00,0x13,0x00,0x00,0xf0,0x21, ++0x92,0x67,0x00,0x04,0x24,0x14,0x00,0x01,0x12,0x87,0x00,0x10,0x02,0x30,0x10,0x21, ++0x27,0x83,0x90,0x18,0x01,0x23,0x18,0x21,0x80,0x64,0x00,0x00,0x27,0x83,0xb5,0x70, ++0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x04,0x00,0x00,0x00,0x00, ++0x10,0x80,0x00,0x23,0x00,0x00,0x00,0x00,0x02,0x30,0x10,0x21,0x00,0x02,0x80,0x80, ++0x24,0x04,0x00,0x01,0x27,0x83,0x90,0x20,0xa2,0x64,0x00,0x12,0x02,0x03,0x18,0x21, ++0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01, ++0x01,0x02,0x10,0x24,0x14,0x40,0x00,0x0e,0x02,0xa0,0x20,0x21,0x27,0x82,0x90,0x00, ++0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06,0x00,0x00,0x00,0x00,0xa6,0x63,0x00,0x1a, ++0x94,0x42,0x00,0x06,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c, ++0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, ++0x8f,0xa5,0x00,0x4c,0x01,0x60,0x30,0x21,0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10, ++0x0c,0x00,0x09,0x0a,0xaf,0xa0,0x00,0x14,0x08,0x00,0x1f,0xbb,0x00,0x00,0x00,0x00, ++0x27,0x83,0x90,0x20,0x01,0x23,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x14,0x40,0x00,0xaf, ++0x00,0xa0,0x20,0x21,0x32,0x4f,0x00,0x03,0x00,0x12,0x10,0x82,0x25,0xe3,0x00,0x0d, ++0x30,0x45,0x00,0x07,0x00,0x74,0x78,0x04,0x10,0xa0,0x00,0x0e,0x00,0x00,0x90,0x21, ++0x27,0x82,0x80,0x1c,0x00,0x15,0x18,0x40,0x00,0x62,0x18,0x21,0x94,0x64,0x00,0x00, ++0x24,0xa2,0x00,0x06,0x00,0x54,0x10,0x04,0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02, ++0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d,0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x20, ++0x30,0x52,0xff,0xfc,0x02,0x30,0x10,0x21,0x27,0x83,0x90,0x10,0x00,0x02,0x10,0x80, ++0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x03,0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff, ++0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x04,0x2c,0x62,0x00,0x19,0x30,0x82,0x00,0x0f, ++0x24,0x43,0x00,0x0c,0x2c,0x62,0x00,0x19,0x10,0x40,0x00,0x19,0x24,0x0e,0x00,0x20, ++0x24,0x62,0xff,0xe9,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x15,0x24,0x0e,0x00,0x10, ++0x24,0x62,0xff,0xeb,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x11,0x24,0x0e,0x00,0x08, ++0x24,0x02,0x00,0x14,0x10,0x62,0x00,0x0e,0x24,0x0e,0x00,0x02,0x24,0x62,0xff,0xef, ++0x2c,0x42,0x00,0x03,0x14,0x40,0x00,0x0a,0x24,0x0e,0x00,0x10,0x24,0x62,0xff,0xf1, ++0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x06,0x24,0x0e,0x00,0x08,0x24,0x62,0xff,0xf3, ++0x2c,0x42,0x00,0x02,0x24,0x0e,0x00,0x04,0x24,0x03,0x00,0x02,0x00,0x62,0x70,0x0a, ++0x30,0xe2,0x00,0xff,0x00,0x00,0x48,0x21,0x00,0x00,0x68,0x21,0x10,0x40,0x00,0x6d, ++0x00,0x00,0x58,0x21,0x3c,0x14,0x80,0xff,0x27,0x99,0x90,0x00,0x01,0xf2,0xc0,0x23, ++0x36,0x94,0xff,0xff,0x01,0xc9,0x10,0x2a,0x14,0x40,0x00,0x64,0x24,0x03,0x00,0x04, ++0x00,0x10,0x28,0xc0,0x00,0xb0,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x59,0x10,0x21, ++0x94,0x56,0x00,0x06,0x00,0x00,0x00,0x00,0x32,0xcc,0x00,0x03,0x00,0x6c,0x10,0x23, ++0x30,0x42,0x00,0x03,0x02,0xc2,0x10,0x21,0x24,0x42,0x00,0x04,0x30,0x51,0xff,0xff, ++0x02,0x32,0x18,0x2b,0x10,0x60,0x00,0x4d,0x01,0xf1,0x10,0x23,0x02,0x51,0x10,0x23, ++0x01,0x78,0x18,0x2b,0x10,0x60,0x00,0x34,0x30,0x44,0xff,0xff,0x29,0x22,0x00,0x40, ++0x10,0x40,0x00,0x31,0x01,0x72,0x18,0x21,0x25,0x22,0x00,0x01,0x00,0x02,0x16,0x00, ++0x00,0x02,0x4e,0x03,0x00,0xb0,0x10,0x21,0x00,0x02,0x30,0x80,0x27,0x82,0x90,0x04, ++0x30,0x6b,0xff,0xff,0x00,0xc2,0x18,0x21,0x8c,0x67,0x00,0x18,0x00,0x04,0x25,0x40, ++0x3c,0x03,0x7f,0x00,0x8c,0xe2,0x00,0x04,0x00,0x83,0x20,0x24,0x27,0x83,0x90,0x10, ++0x00,0x54,0x10,0x24,0x00,0xc3,0x28,0x21,0x00,0x44,0x10,0x25,0xac,0xe2,0x00,0x04, ++0x16,0xe0,0x00,0x02,0xa0,0xb5,0x00,0x00,0xa0,0xb5,0x00,0x03,0x27,0x84,0x90,0x20, ++0x00,0xc4,0x18,0x21,0x8c,0x62,0x00,0x00,0x8c,0xe8,0x00,0x08,0x00,0x02,0x15,0xc2, ++0x00,0x08,0x47,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x10,0x40,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x02, ++0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, ++0x00,0xe2,0x50,0x21,0xa5,0x5e,0x00,0x00,0x92,0x62,0x00,0x04,0x25,0xad,0x00,0x01, ++0x27,0x84,0x90,0x00,0x00,0xc4,0x18,0x21,0x01,0xa2,0x10,0x2a,0x94,0x70,0x00,0x02, ++0x14,0x40,0xff,0xb8,0x00,0x00,0x00,0x00,0x96,0x63,0x00,0x14,0x00,0x0c,0x10,0x23, ++0xa2,0x69,0x00,0x12,0x30,0x42,0x00,0x03,0x01,0x62,0x10,0x23,0x00,0x03,0x80,0xc0, ++0x8f,0xa5,0x00,0x4c,0x30,0x4b,0xff,0xff,0x02,0x03,0x80,0x21,0x27,0x82,0x90,0x08, ++0x00,0x10,0x80,0x80,0xa6,0x6b,0x00,0x1a,0x02,0xa0,0x20,0x21,0x01,0x60,0x30,0x21, ++0x01,0x60,0x88,0x21,0x0c,0x00,0x08,0xe3,0x02,0x02,0x80,0x21,0x00,0x5e,0x10,0x21, ++0xa6,0x02,0x00,0x04,0x08,0x00,0x1f,0xc1,0x02,0x20,0x10,0x21,0x01,0x62,0x10,0x2b, ++0x10,0x40,0xff,0xe9,0x00,0x00,0x20,0x21,0x29,0x22,0x00,0x40,0x10,0x40,0xff,0xe6, ++0x01,0x71,0x18,0x21,0x08,0x00,0x20,0x37,0x25,0x22,0x00,0x01,0x08,0x00,0x20,0x66, ++0x32,0xcc,0x00,0x03,0x08,0x00,0x20,0x66,0x00,0x00,0x60,0x21,0x8f,0xa5,0x00,0x4c, ++0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x09,0x0a,0xaf,0xb4,0x00,0x14, ++0x92,0x67,0x00,0x04,0x08,0x00,0x1f,0xd9,0x30,0x5e,0xff,0xff,0x30,0x84,0xff,0xff, ++0x00,0x04,0x30,0xc0,0x00,0xc4,0x20,0x21,0x00,0x04,0x20,0x80,0x27,0x82,0x90,0x00, ++0x3c,0x03,0xb0,0x08,0x30,0xa5,0xff,0xff,0x00,0x82,0x20,0x21,0x00,0xc3,0x30,0x21, ++0xac,0xc5,0x00,0x00,0x03,0xe0,0x00,0x08,0xa4,0x85,0x00,0x00,0x30,0x84,0xff,0xff, ++0x00,0x04,0x30,0xc0,0x00,0xc4,0x30,0x21,0x27,0x88,0x90,0x00,0x00,0x06,0x30,0x80, ++0x00,0xc8,0x30,0x21,0x94,0xc3,0x00,0x04,0x3c,0x02,0xb0,0x08,0x3c,0x07,0xb0,0x03, ++0x00,0x03,0x20,0xc0,0x00,0x83,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x82,0x20,0x21, ++0x3c,0x02,0x80,0x01,0x30,0xa5,0xff,0xff,0x00,0x68,0x18,0x21,0x34,0xe7,0x00,0x20, ++0x24,0x42,0x82,0x6c,0xac,0xe2,0x00,0x00,0xa4,0xc5,0x00,0x02,0xa4,0x65,0x00,0x00, ++0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x00,0x30,0x84,0xff,0xff,0x00,0x04,0x10,0xc0, ++0x00,0x44,0x10,0x21,0x27,0x89,0x90,0x00,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21, ++0x97,0x83,0x8f,0xf0,0x94,0x4a,0x00,0x04,0x3c,0x02,0xb0,0x08,0x00,0x03,0x38,0xc0, ++0x00,0x0a,0x40,0xc0,0x00,0xe3,0x18,0x21,0x01,0x0a,0x28,0x21,0x00,0xe2,0x38,0x21, ++0x01,0x02,0x40,0x21,0x00,0x03,0x18,0x80,0x00,0x05,0x28,0x80,0x3c,0x06,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x00,0xa9,0x28,0x21,0x00,0x69,0x18,0x21,0x34,0xc6,0x00,0x20, ++0x34,0x09,0xff,0xff,0x24,0x42,0x82,0xc8,0xac,0xc2,0x00,0x00,0xa4,0x64,0x00,0x00, ++0xac,0xe4,0x00,0x00,0xa4,0xa9,0x00,0x00,0xad,0x09,0x00,0x00,0xa7,0x8a,0x8f,0xf0, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, ++0x34,0x63,0x00,0x20,0x24,0x42,0x83,0x48,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00, ++0x34,0x84,0x01,0x10,0x8c,0x82,0x00,0x00,0x97,0x83,0x81,0x60,0x30,0x42,0xff,0xff, ++0x10,0x62,0x00,0x16,0x24,0x0a,0x00,0x01,0xa7,0x82,0x81,0x60,0xaf,0x80,0xb4,0x50, ++0x00,0x40,0x28,0x21,0x24,0x06,0x00,0x01,0x27,0x84,0xb4,0x54,0x25,0x43,0xff,0xff, ++0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24,0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00, ++0x8c,0x83,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24, ++0x38,0x42,0x00,0x00,0x01,0x42,0x18,0x0a,0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x14, ++0xac,0x83,0x00,0x00,0x14,0x40,0xff,0xf1,0x24,0x84,0x00,0x04,0x3c,0x0b,0xb0,0x03, ++0x00,0x00,0x50,0x21,0x3c,0x0c,0x80,0x00,0x27,0x89,0xb4,0xa0,0x35,0x6b,0x01,0x20, ++0x8d,0x68,0x00,0x00,0x8d,0x23,0x00,0x04,0x01,0x0c,0x10,0x24,0x00,0x02,0x17,0xc2, ++0x11,0x03,0x00,0x37,0xa1,0x22,0x00,0xdc,0xa1,0x20,0x00,0xd5,0xa1,0x20,0x00,0xd6, ++0x01,0x20,0x30,0x21,0x00,0x00,0x38,0x21,0x00,0x00,0x28,0x21,0x01,0x20,0x20,0x21, ++0x00,0xa8,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0xe0,0x00,0x10,0xa0,0x82,0x00,0x0a, ++0x90,0x82,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x31,0x24,0xa2,0xff,0xff, ++0xa0,0x82,0x00,0x08,0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x09, ++0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x40, ++0x00,0x43,0x10,0x21,0x00,0x46,0x10,0x21,0xa0,0x45,0x00,0x09,0x90,0x82,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x04, ++0x00,0x00,0x00,0x00,0xa0,0xc5,0x00,0xd5,0x24,0x07,0x00,0x01,0xa0,0x85,0x00,0x08, ++0xa0,0xc5,0x00,0xd6,0x24,0xa5,0x00,0x01,0x2c,0xa2,0x00,0x1c,0x14,0x40,0xff,0xe0, ++0x24,0x84,0x00,0x03,0x90,0xc4,0x00,0xd5,0x00,0x00,0x28,0x21,0x00,0xa4,0x10,0x2b, ++0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0xc0,0x18,0x21,0xa0,0x64,0x00,0x08, ++0x90,0xc2,0x00,0xd5,0x24,0xa5,0x00,0x01,0xa0,0x62,0x00,0x09,0x90,0xc4,0x00,0xd5, ++0x00,0x00,0x00,0x00,0x00,0xa4,0x10,0x2b,0x14,0x40,0xff,0xf8,0x24,0x63,0x00,0x03, ++0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x08,0xad,0x28,0x00,0x04,0x25,0x6b,0x00,0x04, ++0x14,0x40,0xff,0xbf,0x25,0x29,0x00,0xec,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x90,0x82,0x00,0x05,0x08,0x00,0x21,0x0d,0xa0,0x82,0x00,0x08,0x97,0x85,0x8b,0x7a, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20, ++0x24,0x42,0x84,0xfc,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x62,0x00,0x00, ++0x30,0x90,0x00,0xff,0x00,0x05,0x28,0x42,0x00,0x00,0x48,0x21,0x27,0x8f,0xb4,0xa4, ++0x00,0x00,0x50,0x21,0x00,0x00,0x58,0x21,0x27,0x98,0xb5,0x84,0x27,0x99,0xb5,0x80, ++0x27,0x8e,0xb5,0x7e,0x27,0x8c,0xb4,0xa8,0x27,0x8d,0xb5,0x00,0x27,0x88,0xb5,0x78, ++0x00,0x0a,0x18,0x80,0x01,0x6f,0x10,0x21,0xac,0x40,0x00,0x00,0xac,0x45,0x00,0x58, ++0x00,0x6e,0x20,0x21,0x00,0x78,0x10,0x21,0xa1,0x00,0xff,0xfc,0xad,0x00,0x00,0x00, ++0xa1,0x00,0x00,0x04,0xa1,0x00,0x00,0x05,0xad,0x00,0xff,0xf8,0x00,0x79,0x18,0x21, ++0x24,0x06,0x00,0x01,0x24,0xc6,0xff,0xff,0xa0,0x80,0x00,0x00,0xa4,0x60,0x00,0x00, ++0xac,0x40,0x00,0x00,0x24,0x63,0x00,0x02,0x24,0x42,0x00,0x04,0x04,0xc1,0xff,0xf9, ++0x24,0x84,0x00,0x01,0x00,0x0a,0x10,0x80,0x00,0x4d,0x20,0x21,0x00,0x00,0x30,0x21, ++0x00,0x4c,0x18,0x21,0x27,0x87,0x81,0x64,0x8c,0xe2,0x00,0x00,0x24,0xe7,0x00,0x04, ++0xac,0x82,0x00,0x00,0xa0,0x66,0x00,0x00,0xa0,0x66,0x00,0x01,0x24,0xc6,0x00,0x01, ++0x28,0xc2,0x00,0x1c,0xa0,0x60,0x00,0x02,0x24,0x84,0x00,0x04,0x14,0x40,0xff,0xf6, ++0x24,0x63,0x00,0x03,0x25,0x29,0x00,0x01,0x29,0x22,0x00,0x08,0x25,0x4a,0x00,0x3b, ++0x25,0x08,0x00,0xec,0x14,0x40,0xff,0xd6,0x25,0x6b,0x00,0xec,0xa7,0x80,0x81,0x60, ++0x00,0x00,0x48,0x21,0x27,0x83,0xb4,0x50,0xac,0x69,0x00,0x00,0x25,0x29,0x00,0x01, ++0x29,0x22,0x00,0x0c,0x14,0x40,0xff,0xfc,0x24,0x63,0x00,0x04,0x0c,0x00,0x20,0xd2, ++0x00,0x00,0x00,0x00,0x2e,0x04,0x00,0x14,0x27,0x83,0xb4,0xa0,0x24,0x09,0x00,0x07, ++0x10,0x80,0x00,0x0a,0x00,0x00,0x00,0x00,0x90,0x62,0x00,0xd5,0x25,0x29,0xff,0xff, ++0xa0,0x62,0x00,0x00,0x05,0x21,0xff,0xfa,0x24,0x63,0x00,0xec,0x8f,0xbf,0x00,0x14, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x90,0x62,0x00,0xd6, ++0x08,0x00,0x21,0x90,0x25,0x29,0xff,0xff,0x30,0x84,0x00,0xff,0x00,0x04,0x11,0x00, ++0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, ++0x27,0x83,0xb4,0xa0,0x00,0x43,0x60,0x21,0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x01, ++0x34,0x84,0x00,0x20,0x24,0x42,0x86,0x68,0x30,0xc6,0x00,0xff,0x93,0xaa,0x00,0x13, ++0x30,0xa5,0x00,0xff,0x30,0xe7,0x00,0xff,0xac,0x82,0x00,0x00,0x10,0xc0,0x00,0xe8, ++0x25,0x8f,0x00,0xd0,0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xfc, ++0x2c,0x43,0x00,0x18,0x10,0x60,0x00,0xc7,0x3c,0x03,0x80,0x01,0x00,0x02,0x10,0x80, ++0x24,0x63,0x02,0x90,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x30,0x14,0x40,0x00,0x1c, ++0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x17,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0x00,0x11,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0c, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x06,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xe0,0x03,0xe0,0x00,0x08, ++0xad,0x82,0x00,0xd0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xe8, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb, ++0x24,0x42,0x00,0x01,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb,0x24,0x42,0x00,0x02, ++0x10,0xa0,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe9,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xe6,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xd0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb, ++0x24,0x42,0xff,0xfc,0x10,0xa0,0xff,0xeb,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0xe5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe0, ++0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xdb,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xf8,0x2d,0x42,0x00,0x19,0x14,0x40,0xff,0xc5, ++0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xdb,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0xd5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd0, ++0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xf0,0x2d,0x42,0x00,0x1b,0x10,0x40,0xff,0xf1, ++0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xcb,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0xc5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x14,0xa2,0xff,0xb5, ++0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb,0x24,0x42,0xff,0xf4, ++0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xe3,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xbd, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xb5,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xc6,0x24,0x02,0x00,0x03, ++0x2d,0x42,0x00,0x23,0x10,0x40,0xff,0xd7,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xae, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xa9,0x24,0x02,0x00,0x02, ++0x14,0xa2,0xff,0xb7,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x03,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x25,0x10,0x40,0xff,0xcb,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xd8, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x16,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xa0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x9a, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x95,0x24,0x02,0x00,0x03, ++0x14,0xa2,0xff,0xb6,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x21,0xcb, ++0x24,0x42,0xff,0xfa,0x10,0xa0,0xff,0x93,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0x8d,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x88, ++0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xf3,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x17, ++0x14,0x40,0xff,0xac,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x34,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x19,0x10,0x40,0xff,0xe2,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x81, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x7b,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x76,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x97, ++0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xc8,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x51, ++0x2d,0x42,0x00,0x1b,0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xde,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0x70,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x6a, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x65,0x24,0x02,0x00,0x03, ++0x10,0xa2,0xff,0x96,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xc8,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x23,0x14,0x40,0xff,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xf9, ++0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xf7,0x2d,0x42,0x00,0x25,0x08,0x00,0x22,0x2d, ++0x2d,0x42,0x00,0x27,0x10,0xa0,0xff,0x5b,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0x55,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x50, ++0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x71,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xe6, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x27,0x14,0x40,0xff,0xad,0x00,0x00,0x00,0x00, ++0x08,0x00,0x22,0x79,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2a,0x14,0x40,0xff,0xd8, ++0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xe9,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2c, ++0x14,0x40,0xff,0x78,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xbd,0x00,0x00,0x00,0x00, ++0x91,0x86,0x00,0x00,0x91,0x83,0x00,0xd4,0x25,0x8d,0x00,0x5c,0x30,0xc4,0x00,0xff, ++0x00,0x04,0x10,0x40,0x00,0x44,0x10,0x21,0x00,0x04,0x48,0x80,0x01,0x82,0x58,0x21, ++0x01,0x89,0x40,0x21,0x25,0x78,0x00,0x08,0x10,0x60,0x00,0x37,0x25,0x0e,0x00,0x60, ++0x2c,0xa2,0x00,0x03,0x14,0x40,0x00,0x25,0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1e,0x00,0x00,0x00,0x00,0x27,0x87,0x81,0x64, ++0x01,0x27,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x03,0x00,0x60, ++0x91,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0xa1,0x82,0x00,0x00, ++0x30,0xc2,0x00,0xff,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x42,0xad,0xa3,0x00,0x00,0x91,0x84,0x00,0x00, ++0x8d,0xc5,0x00,0x00,0x00,0x04,0x20,0x80,0x00,0x87,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x00,0x05,0x28,0x40,0x00,0x8c,0x20,0x21,0x00,0x03,0x18,0x80,0x00,0xa3,0x10,0x2b, ++0x00,0x62,0x28,0x0a,0xac,0x85,0x00,0x60,0x03,0xe0,0x00,0x08,0xa1,0x80,0x00,0xd4, ++0x27,0x87,0x81,0x64,0x08,0x00,0x22,0xb0,0xa1,0x80,0x00,0xdd,0x27,0x82,0x81,0xd4, ++0x8d,0x83,0x00,0xd8,0x00,0x82,0x10,0x21,0x90,0x44,0x00,0x00,0x24,0x63,0x00,0x01, ++0x00,0x64,0x20,0x2b,0x14,0x80,0xff,0x02,0xad,0x83,0x00,0xd8,0x8d,0x02,0x00,0x60, ++0xa1,0x80,0x00,0xd4,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x03,0xe0,0x00,0x08,0xad,0x82,0x00,0x5c,0x10,0xe0,0x00,0x1d,0x24,0x83,0xff,0xfc, ++0x2c,0x62,0x00,0x18,0x10,0x40,0x01,0x10,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01, ++0x24,0x63,0x02,0xf0,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x30,0x14,0x40,0x00,0x65, ++0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x60,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0x00,0x5a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x08, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x51,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xe0,0xad,0x82,0x00,0xd0, ++0x8d,0xe3,0x00,0x00,0x8d,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21, ++0xad,0xa2,0x00,0x00,0xad,0xe0,0x00,0x00,0x8d,0xa3,0x00,0x00,0x8d,0xc4,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x83,0x10,0x2a,0x10,0x40,0x00,0x22,0x00,0x00,0x00,0x00, ++0x93,0x05,0x00,0x01,0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x45,0x00,0x05, ++0x24,0x02,0x00,0x01,0xa1,0x85,0x00,0x00,0xa1,0x82,0x00,0xd4,0x03,0xe0,0x00,0x08, ++0xad,0x80,0x00,0xd8,0x91,0x82,0x00,0xdd,0x24,0x03,0x00,0x01,0x10,0x43,0x00,0x05, ++0x00,0x00,0x00,0x00,0xa1,0x83,0x00,0xd4,0xad,0x80,0x00,0xd8,0x03,0xe0,0x00,0x08, ++0xa1,0x83,0x00,0xdd,0x00,0x04,0x17,0xc2,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x43, ++0xad,0xa2,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x81,0x64,0x8d,0xc5,0x00,0x00, ++0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x00,0x05,0x28,0x40, ++0x00,0x04,0x18,0x80,0x00,0xa3,0x10,0x2b,0x00,0x62,0x28,0x0a,0x08,0x00,0x22,0xc2, ++0xad,0xc5,0x00,0x00,0x97,0x82,0x8b,0x7c,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x2a, ++0x10,0x40,0xfe,0xab,0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x15,0x00,0x00,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x81,0x64, ++0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x6c,0x18,0x21, ++0xac,0x64,0x00,0x60,0x93,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x10,0x80, ++0x01,0x82,0x10,0x21,0x24,0x4e,0x00,0x60,0xa1,0x85,0x00,0x00,0x8d,0xc2,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x03,0xe0,0x00,0x08,0xad,0xa2,0x00,0x00,0x08,0x00,0x23,0x37,0xa1,0x80,0x00,0xdd, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xe8,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x22,0xf3,0x24,0x42,0x00,0x01,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3, ++0x24,0x42,0x00,0x02,0x10,0xa0,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0x00,0x0a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xa0, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x9d,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xd0,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xfc,0x10,0xa0,0xff,0xeb,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xe5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0x93,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xdd,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xf8,0x2d,0x42,0x00,0x19, ++0x14,0x40,0xff,0x7c,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xdb,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xd5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0x83,0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xf0,0x2d,0x42,0x00,0x1b, ++0x10,0x40,0xff,0xf1,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xcb,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xc5,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x14,0xa2,0xff,0x6c,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x22,0xf3, ++0x24,0x42,0xff,0xf4,0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xe3,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xbd,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x68, ++0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd6,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xee, ++0x24,0x02,0x00,0x03,0x2d,0x42,0x00,0x23,0x10,0x40,0xff,0xd7,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xae,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x5c, ++0x24,0x02,0x00,0x02,0x14,0xa2,0xff,0xb7,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x74, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x25,0x10,0x40,0xff,0xcb,0x00,0x00,0x00,0x00, ++0x08,0x00,0x23,0x49,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x16,0x14,0x40,0x00,0x0e, ++0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xa0,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0x9a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x48, ++0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xb6,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x22,0xf3,0x24,0x42,0xff,0xfa,0x10,0xa0,0xff,0x93,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x8d,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0x3b,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x64,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x17,0x14,0x40,0xff,0xac,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xa5, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x19,0x10,0x40,0xff,0xe2,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0x81,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x7b, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x29,0x24,0x02,0x00,0x03, ++0x10,0xa2,0xff,0x97,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xf0,0x00,0x00,0x00,0x00, ++0x08,0x00,0x23,0xc2,0x2d,0x42,0x00,0x1b,0x2d,0x42,0x00,0x1e,0x10,0x40,0xff,0xde, ++0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x70,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0x6a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x18, ++0x24,0x02,0x00,0x03,0x10,0xa2,0xff,0x96,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xf0, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x23,0x14,0x40,0xff,0xf2,0x00,0x00,0x00,0x00, ++0x08,0x00,0x23,0x6a,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x68,0x2d,0x42,0x00,0x25, ++0x08,0x00,0x23,0x9e,0x2d,0x42,0x00,0x27,0x10,0xa0,0xff,0x5b,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x55,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0x03,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x71,0x00,0x00,0x00,0x00, ++0x08,0x00,0x23,0x57,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x27,0x14,0x40,0xff,0xad, ++0x00,0x00,0x00,0x00,0x08,0x00,0x23,0xea,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2a, ++0x14,0x40,0xff,0xd8,0x00,0x00,0x00,0x00,0x08,0x00,0x23,0x5a,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x2c,0x14,0x40,0xff,0x78,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0xe5, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8,0x3c,0x02,0xb0,0x03,0xaf,0xbf,0x00,0x14, ++0xaf,0xb0,0x00,0x10,0x34,0x42,0x01,0x18,0x3c,0x03,0xb0,0x03,0x8c,0x50,0x00,0x00, ++0x34,0x63,0x01,0x2c,0x90,0x62,0x00,0x00,0x32,0x05,0x00,0x01,0xa3,0x82,0x80,0x10, ++0x14,0xa0,0x00,0x14,0x30,0x44,0x00,0xff,0x32,0x02,0x01,0x00,0x14,0x40,0x00,0x09, ++0x00,0x00,0x00,0x00,0x32,0x02,0x08,0x00,0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x01, ++0xa3,0x82,0xbc,0x18,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x0c,0x00,0x05,0x37,0x00,0x00,0x00,0x00,0x26,0x02,0xff,0x00, ++0xa3,0x80,0xbc,0x18,0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x24,0x16, ++0x32,0x02,0x08,0x00,0x0c,0x00,0x21,0x3f,0x00,0x00,0x00,0x00,0x26,0x02,0xff,0xff, ++0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x24,0x13,0x32,0x02,0x01,0x00, ++0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xaf,0xbf,0x00,0x18, ++0x8c,0x43,0x00,0x00,0x3c,0x02,0x00,0x40,0x24,0x07,0x0f,0xff,0x00,0x03,0x33,0x02, ++0x00,0x03,0x2d,0x02,0x00,0x03,0x43,0x02,0x30,0x69,0x0f,0xff,0x00,0x62,0x18,0x24, ++0x30,0xa5,0x00,0x03,0x30,0xc6,0x00,0xff,0x10,0x60,0x00,0x08,0x31,0x08,0x00,0xff, ++0x01,0x00,0x30,0x21,0x0c,0x00,0x24,0xdf,0xaf,0xa9,0x00,0x10,0x8f,0xbf,0x00,0x18, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x25,0x31, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0xd4,0x08,0x00,0x24,0x3f, ++0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0,0x3c,0x02,0xb0,0x03,0xaf,0xbe,0x00,0x38, ++0xaf,0xb5,0x00,0x2c,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x3c, ++0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30,0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24, ++0xaf,0xb2,0x00,0x20,0x34,0x42,0x00,0x3f,0x90,0x43,0x00,0x00,0x00,0x80,0x80,0x21, ++0x00,0x00,0xf0,0x21,0x00,0x00,0x88,0x21,0x10,0x60,0x00,0x76,0x00,0x00,0xa8,0x21, ++0x3c,0x01,0xb0,0x03,0xa0,0x20,0x00,0x3f,0x00,0x10,0x12,0x02,0x24,0x04,0x06,0x14, ++0x0c,0x00,0x06,0xd1,0x30,0x54,0x00,0x0f,0x24,0x04,0x06,0x14,0x0c,0x00,0x06,0xd1, ++0xaf,0xa2,0x00,0x10,0x3c,0x03,0x00,0xff,0x34,0x63,0xff,0xff,0x32,0x10,0x00,0x7f, ++0x00,0x43,0x10,0x24,0x00,0x10,0x86,0x00,0x02,0x02,0x80,0x25,0x02,0x00,0x28,0x21, ++0x24,0x04,0x06,0x14,0x3c,0x13,0xbf,0xff,0x0c,0x00,0x06,0xbf,0x3c,0x16,0xb0,0x03, ++0x00,0x00,0x90,0x21,0x3c,0x17,0x40,0x00,0x36,0x73,0xff,0xff,0x36,0xd6,0x00,0x3e, ++0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x00,0x00,0x57,0x10,0x25,0x00,0x40,0x28,0x21, ++0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x00,0x00,0x00,0x80,0x21,0x0c,0x00,0x25,0xf9, ++0x00,0x00,0x00,0x00,0x26,0x03,0x00,0x01,0x10,0x40,0x00,0x46,0x30,0x70,0x00,0xff, ++0x12,0x00,0xff,0xfa,0x00,0x00,0x00,0x00,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0x00, ++0x00,0x53,0x10,0x24,0x00,0x40,0x28,0x21,0x0c,0x00,0x06,0xbf,0x24,0x04,0x04,0x00, ++0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x37,0x00,0x00,0x00,0x00,0x12,0x80,0x00,0x35, ++0x00,0x00,0x00,0x00,0x32,0x31,0x00,0x7f,0x12,0x20,0x00,0x04,0x24,0x03,0x00,0x04, ++0x27,0xc2,0x00,0x01,0x30,0x5e,0x00,0xff,0x02,0xb1,0xa8,0x21,0x12,0x43,0x00,0x2a, ++0x3c,0x03,0xb0,0x03,0x02,0x43,0x10,0x21,0xa0,0x51,0x00,0x34,0x26,0x42,0x00,0x01, ++0x30,0x52,0x00,0xff,0x2e,0x43,0x00,0x05,0x14,0x60,0xff,0xd9,0x00,0x00,0x00,0x00, ++0x8f,0xa5,0x00,0x10,0x0c,0x00,0x06,0xbf,0x24,0x04,0x06,0x14,0x12,0xa0,0x00,0x0e, ++0x3c,0x02,0xb0,0x03,0x13,0xc0,0x00,0x0d,0x34,0x42,0x00,0x3c,0x00,0x15,0x10,0x40, ++0x00,0x55,0x10,0x21,0x00,0x02,0x10,0xc0,0x00,0x55,0x10,0x21,0x00,0x02,0xa8,0x80, ++0x02,0xbe,0x00,0x1b,0x17,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, ++0x00,0x00,0xa8,0x12,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3c,0x3c,0x03,0xb0,0x03, ++0x3c,0x04,0xb0,0x03,0xa4,0x55,0x00,0x00,0x34,0x63,0x00,0x1c,0x34,0x84,0x00,0x1d, ++0x24,0x02,0x00,0x01,0xa0,0x60,0x00,0x00,0xa0,0x82,0x00,0x00,0x7b,0xbe,0x01,0xfc, ++0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0xa2,0xd1,0x00,0x00,0x08,0x00,0x24,0x98, ++0x26,0x42,0x00,0x01,0x0c,0x00,0x06,0xd1,0x24,0x04,0x04,0xfc,0x08,0x00,0x24,0x8d, ++0x00,0x40,0x88,0x21,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x3c,0x3c,0x04,0xb0,0x03, ++0x3c,0x05,0xb0,0x03,0xa4,0x60,0x00,0x00,0x34,0x84,0x00,0x1c,0x34,0xa5,0x00,0x1d, ++0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x01,0xa0,0x82,0x00,0x00,0x08,0x00,0x24,0xb7, ++0xa0,0xa3,0x00,0x00,0x0c,0x00,0x17,0x99,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x8b, ++0x00,0x10,0x12,0x02,0x3c,0x02,0xb0,0x03,0x3c,0x04,0xb0,0x03,0x34,0x42,0x00,0x3c, ++0x34,0x84,0x00,0x14,0x24,0x03,0x00,0x01,0xa4,0x40,0x00,0x00,0x3c,0x01,0xb0,0x03, ++0xa0,0x23,0x00,0x3f,0x08,0x00,0x24,0xb7,0xac,0x90,0x00,0x00,0x27,0xbd,0xff,0xd8, ++0xaf,0xb0,0x00,0x10,0x30,0xd0,0x00,0xff,0x2e,0x02,0x00,0x2e,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0x30,0xb1,0x00,0xff, ++0x14,0x40,0x00,0x06,0x00,0x80,0x90,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x13,0x00,0x10, ++0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa4,0x24,0x06,0x01,0x07,0x12,0x60,0x00,0x38, ++0x02,0x00,0x30,0x21,0x8f,0xa2,0x00,0x38,0x30,0xc3,0x00,0x3f,0x3c,0x04,0xb0,0x09, ++0x00,0x02,0x14,0x00,0x00,0x43,0x30,0x25,0x34,0x84,0x01,0x60,0x90,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x2a, ++0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x24,0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x20, ++0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x19,0x00,0x00,0x00,0x00,0x16,0x60,0xff,0xe2, ++0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x13,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0d, ++0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x09,0x24,0x02,0x00,0x03,0x16,0x22,0xff,0xda, ++0x00,0x00,0x00,0x00,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5f, ++0x3c,0x06,0x0c,0xb8,0x08,0x00,0x24,0xea,0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x12, ++0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xd0,0x00,0x00,0x00,0x00,0x08,0x00,0x25,0x12, ++0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x12,0x24,0x04,0x08,0x44,0x24,0x04,0x08,0x4c, ++0x0c,0x00,0x13,0x5f,0x24,0x05,0xff,0xff,0x08,0x00,0x25,0x07,0x00,0x00,0x00,0x00, ++0x08,0x00,0x25,0x20,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xe0,0x00,0x00,0x00,0x00, ++0x08,0x00,0x25,0x20,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x20,0x24,0x04,0x08,0x44, ++0x02,0x40,0x20,0x21,0x0c,0x00,0x25,0x71,0x02,0x20,0x28,0x21,0x08,0x00,0x24,0xf5, ++0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xd8,0x2c,0xc2,0x00,0x2e,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c, ++0x00,0xc0,0x80,0x21,0x30,0xb1,0x00,0xff,0x00,0x80,0x90,0x21,0x14,0x40,0x00,0x07, ++0x00,0x00,0x18,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x13,0x00,0x10, ++0x24,0x05,0x00,0x14,0x0c,0x00,0x13,0xa4,0x24,0x06,0x01,0x07,0x12,0x60,0x00,0x24, ++0x02,0x00,0x30,0x21,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x30,0xc5,0x00,0x3f,0x0c,0x00,0x25,0xae, ++0x02,0x20,0x20,0x21,0x16,0x60,0x00,0x0a,0x00,0x40,0x80,0x21,0x24,0x02,0x00,0x01, ++0x12,0x22,0x00,0x15,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0f,0x24,0x02,0x00,0x02, ++0x12,0x22,0x00,0x0b,0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x03,0x00,0x00,0x00,0x00, ++0x08,0x00,0x25,0x3d,0x02,0x00,0x18,0x21,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff, ++0x0c,0x00,0x13,0x5f,0x3c,0x06,0x0c,0xb8,0x08,0x00,0x25,0x3d,0x02,0x00,0x18,0x21, ++0x08,0x00,0x25,0x5f,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xf5,0x00,0x00,0x00,0x00, ++0x08,0x00,0x25,0x5f,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0x5f,0x24,0x04,0x08,0x44, ++0x02,0x40,0x20,0x21,0x0c,0x00,0x25,0x71,0x02,0x20,0x28,0x21,0x08,0x00,0x25,0x49, ++0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xe8,0x2c,0xc2,0x00,0x1f,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x14,0x00,0xc0,0x80,0x21,0x14,0x40,0x00,0x1d,0x30,0xa5,0x00,0xff, ++0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x18,0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x12, ++0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0e,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x07, ++0x24,0x04,0x08,0x4c,0x26,0x10,0xff,0xe2,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x14, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x24,0x05,0xff,0xff, ++0x0c,0x00,0x13,0x5f,0x3c,0x06,0x0d,0xf8,0x08,0x00,0x25,0x82,0x26,0x10,0xff,0xe2, ++0x08,0x00,0x25,0x87,0x24,0x04,0x08,0x48,0x14,0xa0,0xff,0xf2,0x24,0x04,0x08,0x40, ++0x08,0x00,0x25,0x88,0x24,0x05,0xff,0xff,0x08,0x00,0x25,0x87,0x24,0x04,0x08,0x44, ++0x2c,0xc2,0x00,0x10,0x14,0x40,0xff,0xec,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x14, ++0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x0e,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0a, ++0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x03,0x24,0x04,0x08,0x4c,0x08,0x00,0x25,0x82, ++0x26,0x10,0xff,0xf1,0x24,0x05,0xff,0xff,0x0c,0x00,0x13,0x5f,0x3c,0x06,0x0d,0xb8, ++0x08,0x00,0x25,0x82,0x26,0x10,0xff,0xf1,0x08,0x00,0x25,0xa1,0x24,0x04,0x08,0x48, ++0x14,0xa0,0xff,0xf6,0x24,0x04,0x08,0x40,0x08,0x00,0x25,0xa2,0x24,0x05,0xff,0xff, ++0x08,0x00,0x25,0xa1,0x24,0x04,0x08,0x44,0x27,0xbd,0xff,0xe8,0x30,0x84,0x00,0xff, ++0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x39,0xaf,0xbf,0x00,0x10,0x28,0x82,0x00,0x02, ++0x14,0x40,0x00,0x27,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x17, ++0x00,0xa0,0x30,0x21,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x05,0x24,0x04,0x08,0x3c, ++0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x0c,0x00,0x13,0x5f,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x3c,0x3c,0x05,0x80,0x00, ++0x0c,0x00,0x13,0x5f,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x3c,0x3c,0x05,0x80,0x00, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01,0x24,0x04,0x08,0xac,0x0c,0x00,0x13,0x41, ++0x24,0x05,0x0f,0xff,0x08,0x00,0x25,0xbc,0x00,0x00,0x00,0x00,0x24,0x04,0x08,0x34, ++0x0c,0x00,0x13,0x5f,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x34,0x3c,0x05,0x80,0x00, ++0x0c,0x00,0x13,0x5f,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x34,0x3c,0x05,0x80,0x00, ++0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01,0x08,0x00,0x25,0xcb,0x24,0x04,0x08,0xa8, ++0x14,0x80,0xff,0xdf,0x00,0xa0,0x30,0x21,0x24,0x04,0x08,0x24,0x0c,0x00,0x13,0x5f, ++0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x24,0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f, ++0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x24,0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f, ++0x24,0x06,0x00,0x01,0x08,0x00,0x25,0xcb,0x24,0x04,0x08,0xa0,0x00,0xa0,0x30,0x21, ++0x24,0x04,0x08,0x2c,0x0c,0x00,0x13,0x5f,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x2c, ++0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f,0x00,0x00,0x30,0x21,0x24,0x04,0x08,0x2c, ++0x3c,0x05,0x80,0x00,0x0c,0x00,0x13,0x5f,0x24,0x06,0x00,0x01,0x08,0x00,0x25,0xcb, ++0x24,0x04,0x08,0xa4,0x3c,0x05,0x00,0x14,0x3c,0x02,0xb0,0x05,0x34,0x42,0x04,0x20, ++0x3c,0x06,0xc0,0x00,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0x34,0xa5,0x17,0x09, ++0xac,0x45,0x00,0x00,0x34,0xc6,0x05,0x07,0x34,0x63,0x04,0x24,0x34,0x84,0x02,0x28, ++0x3c,0x07,0xb0,0x05,0x24,0x02,0x00,0x20,0xac,0x66,0x00,0x00,0x34,0xe7,0x04,0x50, ++0xa0,0x82,0x00,0x00,0x90,0xe2,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x03, ++0x10,0x40,0xff,0xfc,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x93,0x85,0x81,0xf1,0x24,0x02,0x00,0x01,0x14,0xa2,0x00,0x53,0x00,0x80,0x40,0x21, ++0x8c,0x89,0x00,0x04,0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21,0x8c,0xc3,0x00,0x04, ++0x3c,0x02,0x01,0x00,0x00,0x62,0x10,0x24,0x10,0x40,0x00,0x4b,0x30,0x62,0x00,0x08, ++0x10,0x45,0x00,0x59,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38,0x24,0x03,0x00,0xb4, ++0x30,0x44,0x00,0xff,0x10,0x83,0x00,0x61,0x24,0x02,0x00,0xc4,0x10,0x82,0x00,0x54, ++0x24,0x02,0x00,0x94,0x10,0x82,0x00,0x45,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38, ++0x00,0x00,0x00,0x00,0x30,0x47,0xff,0xff,0x30,0xe3,0x40,0xff,0x24,0x02,0x40,0x88, ++0x14,0x62,0x00,0x39,0x30,0xe3,0x03,0x00,0x24,0x02,0x03,0x00,0x10,0x62,0x00,0x38, ++0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x56,0x00,0x00,0x00,0x00,0x30,0x47,0xff,0xff, ++0x30,0xe2,0x00,0x80,0x14,0x40,0x00,0x30,0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21, ++0x94,0xc3,0x00,0x60,0x24,0x02,0x00,0x08,0x14,0x43,0x00,0x3b,0x00,0x00,0x00,0x00, ++0x90,0xc2,0x00,0x62,0x24,0x03,0x00,0x04,0x00,0x02,0x39,0x02,0x10,0xe3,0x00,0x15, ++0x24,0x02,0x00,0x06,0x14,0xe2,0x00,0x34,0x00,0x00,0x00,0x00,0x8d,0x05,0x01,0xac, ++0x94,0xc4,0x00,0x66,0x27,0x82,0x89,0x68,0x00,0x05,0x28,0x80,0x30,0x87,0xff,0xff, ++0x00,0xa2,0x28,0x21,0x00,0x07,0x1a,0x00,0x8c,0xa4,0x00,0x00,0x00,0x07,0x12,0x02, ++0x00,0x43,0x10,0x25,0x24,0x42,0x00,0x5e,0x24,0x03,0xc0,0x00,0x30,0x47,0xff,0xff, ++0x00,0x83,0x20,0x24,0x00,0x87,0x20,0x25,0xac,0xa4,0x00,0x00,0x08,0x00,0x26,0x76, ++0xad,0x07,0x00,0x10,0x8d,0x05,0x01,0xac,0x94,0xc4,0x00,0x64,0x27,0x82,0x89,0x68, ++0x00,0x05,0x28,0x80,0x30,0x87,0xff,0xff,0x00,0xa2,0x28,0x21,0x00,0x07,0x1a,0x00, ++0x8c,0xa4,0x00,0x00,0x00,0x07,0x12,0x02,0x00,0x43,0x10,0x25,0x24,0x42,0x00,0x36, ++0x3c,0x03,0xff,0xff,0x30,0x47,0xff,0xff,0x00,0x83,0x20,0x24,0x00,0x87,0x20,0x25, ++0xac,0xa4,0x00,0x00,0xad,0x07,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x94,0xc2,0x00,0x50,0x08,0x00,0x26,0x34,0x30,0x47,0xff,0xff,0x8d,0x04,0x01,0xac, ++0x27,0x83,0x89,0x68,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00, ++0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x2e,0xac,0x82,0x00,0x00, ++0x24,0x03,0x00,0x2e,0xad,0x03,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x8d,0x04,0x01,0xac,0x27,0x83,0x89,0x68,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21, ++0x8c,0x82,0x00,0x00,0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x0e, ++0x24,0x03,0x00,0x0e,0x08,0x00,0x26,0x75,0xac,0x82,0x00,0x00,0x8d,0x04,0x01,0xac, ++0x27,0x83,0x89,0x68,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00, ++0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x14,0x24,0x03,0x00,0x14, ++0x08,0x00,0x26,0x75,0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x30,0xc6,0x00,0xff,0x00,0x06,0x48,0x40,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x8b,0xbc,0x30,0x27,0x83,0xbc,0x36,0x00,0x4b,0x40,0x21,0x00,0x43,0x10,0x21, ++0x94,0x47,0x00,0x00,0x30,0xa2,0x3f,0xff,0x10,0xe2,0x00,0x29,0x30,0x8a,0xff,0xff, ++0x95,0x02,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x02,0x11,0x82,0x30,0x42,0x00,0x01, ++0x10,0x43,0x00,0x18,0x00,0x00,0x00,0x00,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x4b,0x30,0x21,0x94,0xc4,0x00,0x02,0x27,0x83,0xbc,0x36,0x27,0x85,0xbc,0x34, ++0x00,0x45,0x28,0x21,0x30,0x84,0xff,0xdf,0x00,0x43,0x10,0x21,0xa4,0xc4,0x00,0x02, ++0xa4,0x40,0x00,0x00,0xa4,0xa0,0x00,0x00,0x94,0xc3,0x00,0x02,0x3c,0x04,0xb0,0x01, ++0x01,0x44,0x20,0x21,0x30,0x63,0xff,0xbf,0xa4,0xc3,0x00,0x02,0xa0,0xc0,0x00,0x00, ++0x8c,0x82,0x00,0x04,0x24,0x03,0xf0,0xff,0x00,0x43,0x10,0x24,0x03,0xe0,0x00,0x08, ++0xac,0x82,0x00,0x04,0x24,0x02,0xc0,0x00,0x91,0x04,0x00,0x01,0x00,0xa2,0x10,0x24, ++0x00,0x47,0x28,0x25,0x3c,0x03,0xb0,0x01,0x24,0x02,0x00,0x02,0x14,0x82,0xff,0xe2, ++0x01,0x43,0x18,0x21,0xac,0x65,0x00,0x00,0x08,0x00,0x26,0xa3,0x01,0x26,0x10,0x21, ++0x08,0x00,0x26,0xa3,0x01,0x26,0x10,0x21,0x93,0x83,0x81,0xf1,0x24,0x02,0x00,0x01, ++0x14,0x62,0x00,0x0d,0x3c,0x02,0xb0,0x01,0x8c,0x84,0x00,0x04,0x3c,0x06,0xb0,0x09, ++0x00,0x82,0x20,0x21,0x8c,0x85,0x00,0x08,0x8c,0x83,0x00,0x04,0x3c,0x02,0x01,0x00, ++0x34,0xc6,0x01,0x00,0x00,0x62,0x18,0x24,0x14,0x60,0x00,0x05,0x30,0xa5,0x20,0x00, ++0x24,0x02,0x00,0x06,0xa0,0xc2,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x09,0x10,0xa0,0xff,0xfc,0x34,0x63,0x01,0x00,0x24,0x02,0x00,0x0e, ++0x08,0x00,0x26,0xd6,0xa0,0x62,0x00,0x00,0x3c,0x02,0xb0,0x01,0x30,0xa5,0xff,0xff, ++0x00,0xa2,0x28,0x21,0x8c,0xa3,0x00,0x00,0x3c,0x02,0x10,0x00,0x00,0x80,0x30,0x21, ++0x00,0x62,0x18,0x24,0x8c,0xa2,0x00,0x04,0x10,0x60,0x00,0x04,0x00,0x00,0x00,0x00, ++0x30,0x42,0x80,0x00,0x10,0x40,0x00,0x13,0x00,0x00,0x00,0x00,0x8c,0xc2,0x01,0xa8, ++0x00,0x00,0x00,0x00,0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40, ++0x00,0x83,0x10,0x0a,0x93,0x83,0x81,0xf0,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, ++0x00,0x82,0x20,0x23,0x24,0x63,0xff,0xff,0xac,0xc4,0x01,0xa8,0xa3,0x83,0x81,0xf0, ++0x8c,0xc4,0x01,0xac,0x8c,0xc2,0x01,0xa8,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x26, ++0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x34,0x63,0x00,0x73,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0xa3,0x80,0x81,0xf1,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0xa3,0x82,0x81,0xf1,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x3c,0x05,0xb0,0x01,0x00,0x80,0x50,0x21, ++0x00,0x45,0x10,0x21,0x8c,0x43,0x00,0x04,0x24,0x02,0x00,0x05,0x00,0x03,0x1a,0x02, ++0x30,0x69,0x00,0x0f,0x11,0x22,0x00,0x0b,0x24,0x02,0x00,0x07,0x11,0x22,0x00,0x09, ++0x24,0x02,0x00,0x0a,0x11,0x22,0x00,0x07,0x24,0x02,0x00,0x0b,0x11,0x22,0x00,0x05, ++0x24,0x02,0x00,0x01,0x93,0x83,0x81,0xf0,0x3c,0x04,0xb0,0x06,0x10,0x62,0x00,0x03, ++0x34,0x84,0x80,0x18,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x02,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00, ++0x8d,0x43,0x01,0xa8,0x27,0x82,0x89,0x68,0x00,0x03,0x18,0x80,0x00,0x6a,0x20,0x21, ++0x8c,0x87,0x00,0xa8,0x00,0x62,0x18,0x21,0x8c,0x68,0x00,0x00,0x00,0xe5,0x28,0x21, ++0x8c,0xa9,0x00,0x00,0x3c,0x02,0xff,0xff,0x27,0x83,0x8a,0x68,0x01,0x22,0x10,0x24, ++0x00,0x48,0x10,0x25,0xac,0xa2,0x00,0x00,0x8d,0x44,0x01,0xa8,0x00,0x07,0x30,0xc2, ++0x3c,0x02,0x00,0x80,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x00,0x06,0x32,0x00, ++0x8c,0xa9,0x00,0x04,0x00,0xc2,0x30,0x25,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00, ++0x01,0x22,0x10,0x25,0x00,0x43,0x10,0x25,0xac,0xa2,0x00,0x04,0xaf,0x87,0xbc,0x20, ++0x8c,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x82,0xbc,0x28,0x8c,0xa3,0x00,0x04, ++0x3c,0x01,0xb0,0x07,0xac,0x26,0x80,0x18,0x8d,0x42,0x01,0xa8,0xaf,0x83,0xbc,0x24, ++0x93,0x85,0x81,0xf0,0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40, ++0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0xa5,0xff,0xff, ++0x00,0x82,0x20,0x23,0xad,0x44,0x01,0xa8,0xa3,0x85,0x81,0xf0,0x08,0x00,0x27,0x21, ++0x00,0x00,0x00,0x00,0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0xa5,0x00,0x20, ++0x24,0x42,0x9d,0x64,0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x20, ++0xac,0x82,0x00,0x64,0x3c,0x02,0x80,0x01,0xac,0x83,0x00,0x60,0xac,0x80,0x00,0x00, ++0xac,0x80,0x00,0x04,0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x4c,0xac,0x80,0x00,0x50, ++0xac,0x80,0x00,0x54,0xac,0x80,0x00,0x0c,0xac,0x80,0x00,0x58,0xa0,0x80,0x00,0x5c, ++0x24,0x42,0x9e,0x28,0x24,0x83,0x00,0x68,0x24,0x05,0x00,0x0f,0x24,0xa5,0xff,0xff, ++0xac,0x62,0x00,0x00,0x04,0xa1,0xff,0xfd,0x24,0x63,0x00,0x04,0x3c,0x02,0x80,0x01, ++0x24,0x42,0x9f,0x10,0xac,0x82,0x00,0x78,0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01, ++0x24,0x63,0xa0,0x9c,0x24,0x42,0xa0,0x08,0xac,0x83,0x00,0x88,0xac,0x82,0x00,0x98, ++0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01,0x24,0x63,0xa1,0x44,0x24,0x42,0xa2,0x5c, ++0xac,0x83,0x00,0xa0,0xac,0x82,0x00,0xa4,0xa0,0x80,0x01,0xba,0xac,0x80,0x01,0xa8, ++0xac,0x80,0x01,0xac,0xac,0x80,0x01,0xb0,0xac,0x80,0x01,0xb4,0xa0,0x80,0x01,0xb8, ++0x03,0xe0,0x00,0x08,0xa0,0x80,0x01,0xb9,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, ++0x34,0x63,0x00,0x20,0x24,0x42,0x9e,0x28,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0x9e,0x40, ++0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11, ++0x00,0x80,0x28,0x21,0x8c,0x82,0x00,0x14,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d, ++0x00,0x00,0x00,0x00,0x8c,0x84,0x00,0x10,0x8c,0xa3,0x00,0x14,0x8c,0xa2,0x00,0x04, ++0x00,0x83,0x20,0x21,0x00,0x44,0x10,0x21,0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b, ++0x00,0x02,0x12,0x02,0x00,0x43,0x10,0x21,0x00,0x02,0x12,0x00,0x30,0x42,0x3f,0xff, ++0xac,0xa2,0x00,0x04,0xac,0xa0,0x00,0x00,0xac,0xa0,0x00,0x4c,0xac,0xa0,0x00,0x50, ++0xac,0xa0,0x00,0x54,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x0c,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0x9e,0xbc,0xac,0x62,0x00,0x00, ++0x8c,0x86,0x00,0x04,0x3c,0x02,0xb0,0x01,0x24,0x03,0x00,0x01,0x00,0xc2,0x10,0x21, ++0x8c,0x45,0x00,0x00,0xac,0x83,0x00,0x4c,0x00,0x05,0x14,0x02,0x30,0xa3,0x3f,0xff, ++0x30,0x42,0x00,0xff,0xac,0x83,0x00,0x10,0xac,0x82,0x00,0x14,0x8c,0x83,0x00,0x14, ++0xac,0x85,0x00,0x40,0x00,0xc3,0x30,0x21,0x03,0xe0,0x00,0x08,0xac,0x86,0x00,0x08, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, ++0x24,0x63,0x9f,0x10,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, ++0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a,0x00,0x80,0x80,0x21, ++0xae,0x00,0x00,0x00,0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54, ++0xae,0x00,0x00,0x0c,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xaf,0x00,0x00,0x00,0x00,0x08,0x00,0x27,0xd1, ++0xae,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, ++0x34,0x42,0x00,0x20,0x24,0x63,0x9f,0x74,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, ++0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x16, ++0x00,0x80,0x80,0x21,0x8e,0x03,0x00,0x08,0x3c,0x02,0xb0,0x01,0x8e,0x04,0x00,0x44, ++0x00,0x62,0x18,0x21,0x90,0x65,0x00,0x00,0x24,0x02,0x00,0x01,0xae,0x02,0x00,0x50, ++0x30,0xa3,0x00,0xff,0x00,0x03,0x10,0x82,0x00,0x04,0x23,0x02,0x30,0x84,0x00,0x0f, ++0x30,0x42,0x00,0x03,0x00,0x03,0x19,0x02,0xae,0x04,0x00,0x34,0xae,0x02,0x00,0x2c, ++0xae,0x03,0x00,0x30,0xa2,0x05,0x00,0x48,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xaf,0x00,0x00,0x00,0x00, ++0x08,0x00,0x27,0xe9,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, ++0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa0,0x08,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x16,0x00,0x80,0x80,0x21,0x92,0x03,0x00,0x44,0x8e,0x02,0x00,0x40, ++0x83,0x85,0x8b,0xd4,0x92,0x04,0x00,0x41,0x30,0x63,0x00,0x01,0x00,0x02,0x16,0x02, ++0xae,0x04,0x00,0x14,0x00,0x00,0x30,0x21,0xae,0x02,0x00,0x18,0x10,0xa0,0x00,0x04, ++0xae,0x03,0x00,0x3c,0x10,0x60,0x00,0x03,0x24,0x02,0x00,0x01,0x24,0x06,0x00,0x01, ++0x24,0x02,0x00,0x01,0xa3,0x86,0x8b,0xd4,0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xdd, ++0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x0e,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa0,0x9c, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x1b,0x00,0x80,0x80,0x21,0x3c,0x02,0xb0,0x03, ++0x8c,0x42,0x00,0x00,0x92,0x04,0x00,0x44,0x8e,0x03,0x00,0x40,0x83,0x86,0x8b,0xd4, ++0x92,0x05,0x00,0x41,0x30,0x42,0x08,0x00,0x30,0x84,0x00,0x01,0x00,0x02,0x12,0xc2, ++0x00,0x03,0x1e,0x02,0x00,0x82,0x20,0x25,0xae,0x05,0x00,0x14,0x00,0x00,0x38,0x21, ++0xae,0x03,0x00,0x18,0x10,0xc0,0x00,0x04,0xae,0x04,0x00,0x3c,0x10,0x80,0x00,0x03, ++0x24,0x02,0x00,0x01,0x24,0x07,0x00,0x01,0x24,0x02,0x00,0x01,0xa3,0x87,0x8b,0xd4, ++0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x0c,0x00,0x27,0xdd,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x33, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, ++0x34,0x42,0x00,0x20,0x24,0x63,0xa1,0x44,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, ++0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x37, ++0x00,0x80,0x80,0x21,0x8e,0x04,0x00,0x04,0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00, ++0x3c,0x05,0xb0,0x01,0x34,0x42,0x00,0x10,0x00,0x85,0x20,0x21,0x00,0x62,0x18,0x25, ++0xac,0x83,0x00,0x04,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x02,0x00,0x20,0x21, ++0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x00,0x00,0x03,0x18,0x80,0x27,0x82,0x89,0x68, ++0x00,0x62,0x18,0x21,0xac,0x66,0x00,0x00,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac, ++0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x04,0x00,0x03,0x18,0x80,0x27,0x82,0x8a,0x68, ++0x00,0x62,0x18,0x21,0x0c,0x00,0x26,0x10,0xac,0x66,0x00,0x00,0x8e,0x03,0x01,0xac, ++0x8e,0x07,0x00,0x04,0x3c,0x06,0xb0,0x03,0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00, ++0x24,0x62,0x00,0x40,0x00,0xa4,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, ++0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x23,0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac, ++0xac,0x67,0x00,0xa8,0x34,0xc6,0x00,0x30,0x8c,0xc3,0x00,0x00,0x93,0x82,0x81,0xf0, ++0x02,0x00,0x20,0x21,0x24,0x63,0x00,0x01,0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00, ++0xa3,0x82,0x81,0xf0,0x0c,0x00,0x27,0x90,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0x27, ++0x00,0x00,0x00,0x00,0x08,0x00,0x28,0x5d,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xa2,0x5c, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x37,0x00,0x80,0x80,0x21,0x8e,0x04,0x00,0x04, ++0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x01,0x34,0x42,0x00,0x10, ++0x00,0x85,0x20,0x21,0x00,0x62,0x18,0x25,0xac,0x83,0x00,0x04,0x8e,0x02,0x00,0x04, ++0x8e,0x03,0x01,0xac,0x02,0x00,0x20,0x21,0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x00, ++0x00,0x03,0x18,0x80,0x27,0x82,0x89,0x68,0x00,0x62,0x18,0x21,0xac,0x66,0x00,0x00, ++0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x04, ++0x00,0x03,0x18,0x80,0x27,0x82,0x8a,0x68,0x00,0x62,0x18,0x21,0x0c,0x00,0x26,0x10, ++0xac,0x66,0x00,0x00,0x8e,0x03,0x01,0xac,0x8e,0x07,0x00,0x04,0x3c,0x06,0xb0,0x03, ++0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00,0x24,0x62,0x00,0x40,0x00,0xa4,0x10,0x0a, ++0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x23, ++0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac,0xac,0x67,0x00,0xa8,0x34,0xc6,0x00,0x30, ++0x8c,0xc3,0x00,0x00,0x93,0x82,0x81,0xf0,0x02,0x00,0x20,0x21,0x24,0x63,0x00,0x01, ++0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00,0xa3,0x82,0x81,0xf0,0x0c,0x00,0x27,0x90, ++0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x0c,0x00,0x28,0x27,0x00,0x00,0x00,0x00,0x08,0x00,0x28,0xa3, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20, ++0x24,0x63,0xa3,0x74,0x27,0xbd,0xff,0xe0,0xac,0x43,0x00,0x00,0x3c,0x02,0x80,0x01, ++0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c, ++0x00,0x80,0x80,0x21,0x24,0x52,0x9e,0x28,0x00,0x00,0x88,0x21,0x3c,0x03,0xb0,0x09, ++0x34,0x63,0x00,0x06,0x8e,0x06,0x00,0x04,0x90,0x62,0x00,0x00,0x00,0x06,0x22,0x02, ++0x00,0x44,0x10,0x23,0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f, ++0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0x84,0xff,0xff, ++0x10,0x44,0x00,0x68,0x00,0x00,0x28,0x21,0x3c,0x02,0xb0,0x01,0x00,0xc2,0x10,0x21, ++0x8c,0x44,0x00,0x04,0x3c,0x03,0x7c,0x00,0x34,0x63,0x00,0xf0,0x00,0x83,0x18,0x24, ++0xae,0x04,0x00,0x44,0x8c,0x44,0x00,0x00,0x10,0x60,0x00,0x69,0x00,0x00,0x38,0x21, ++0x3c,0x09,0xb0,0x03,0x3c,0x06,0x7c,0x00,0x35,0x29,0x00,0x99,0x3c,0x0a,0xb0,0x01, ++0x24,0x08,0x00,0x40,0x34,0xc6,0x00,0xf0,0x3c,0x0b,0xff,0xff,0x3c,0x0c,0x28,0x38, ++0x16,0x20,0x00,0x06,0x24,0xa5,0x00,0x01,0x93,0x82,0x81,0xf6,0x24,0x11,0x00,0x01, ++0x24,0x42,0x00,0x01,0xa1,0x22,0x00,0x00,0xa3,0x82,0x81,0xf6,0x8e,0x02,0x00,0x04, ++0x24,0x07,0x00,0x01,0x24,0x42,0x01,0x00,0x30,0x42,0x3f,0xff,0xae,0x02,0x00,0x04, ++0x00,0x4a,0x10,0x21,0x8c,0x43,0x00,0x04,0x00,0x00,0x00,0x00,0xae,0x03,0x00,0x44, ++0x8c,0x44,0x00,0x00,0x10,0xa8,0x00,0x2d,0x00,0x66,0x18,0x24,0x14,0x60,0xff,0xec, ++0x00,0x8b,0x10,0x24,0x14,0x4c,0xff,0xea,0x24,0x02,0x00,0x01,0x10,0xe2,0x00,0x2f, ++0x3c,0x03,0xb0,0x09,0x8e,0x02,0x00,0x44,0x8e,0x04,0x00,0x60,0x00,0x02,0x1e,0x42, ++0x00,0x02,0x12,0x02,0x30,0x42,0x00,0x0f,0x30,0x63,0x00,0x01,0xae,0x02,0x00,0x00, ++0x10,0x44,0x00,0x1a,0xae,0x03,0x00,0x58,0x8e,0x02,0x00,0x64,0x8e,0x04,0x00,0x58, ++0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x05,0x00,0x00,0x00,0x00,0xae,0x00,0x00,0x4c, ++0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c,0x8e,0x03,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x80,0x00,0x50,0x10,0x21,0x8c,0x42,0x00,0x68, ++0x00,0x00,0x00,0x00,0x10,0x52,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x40,0xf8,0x09, ++0x02,0x00,0x20,0x21,0x8e,0x04,0x00,0x58,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00, ++0xae,0x03,0x00,0x60,0x08,0x00,0x28,0xeb,0xae,0x04,0x00,0x64,0x8e,0x02,0x00,0x64, ++0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xe5,0x00,0x00,0x00,0x00,0x7a,0x02,0x0d,0x7c, ++0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0x43,0x10,0x26, ++0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x34,0x63,0x00,0x06, ++0x8e,0x04,0x00,0x04,0x90,0x62,0x00,0x00,0x00,0x04,0x22,0x02,0x00,0x44,0x10,0x23, ++0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f,0x00,0x83,0x10,0x0a, ++0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0x14,0x87,0xff,0xc5, ++0x00,0x00,0x00,0x00,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x03, ++0x14,0x40,0x00,0x05,0x24,0x02,0x00,0x0d,0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x01, ++0x08,0x00,0x29,0x4b,0xa2,0x02,0x00,0x5c,0x08,0x00,0x29,0x4b,0xa2,0x00,0x00,0x5c, ++0x3c,0x02,0xff,0xff,0x00,0x82,0x10,0x24,0x3c,0x03,0x28,0x38,0x14,0x43,0xff,0x94, ++0x24,0x02,0x00,0x01,0x08,0x00,0x29,0x23,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0xa5,0xcc,0xac,0x43,0x00,0x00, ++0x8c,0x83,0x01,0xa8,0x8c,0x82,0x01,0xac,0x00,0x80,0x40,0x21,0x10,0x62,0x00,0x20, ++0x00,0x00,0x20,0x21,0x93,0x82,0x81,0xf1,0x00,0x03,0x28,0x80,0x3c,0x07,0xb0,0x06, ++0x00,0xa8,0x18,0x21,0x24,0x04,0x00,0x01,0x8c,0x66,0x00,0xa8,0x10,0x44,0x00,0x1c, ++0x34,0xe7,0x80,0x18,0x3c,0x05,0xb0,0x01,0xaf,0x86,0xbc,0x20,0x00,0xc5,0x28,0x21, ++0x8c,0xa3,0x00,0x00,0x00,0x06,0x20,0xc2,0x3c,0x02,0x00,0x80,0x00,0x04,0x22,0x00, ++0x00,0x82,0x20,0x25,0xaf,0x83,0xbc,0x28,0x8c,0xa2,0x00,0x04,0xac,0xe4,0x00,0x00, ++0x8d,0x03,0x01,0xa8,0xaf,0x82,0xbc,0x24,0x24,0x64,0x00,0x01,0x04,0x80,0x00,0x0a, ++0x00,0x80,0x10,0x21,0x00,0x02,0x11,0x83,0x8d,0x03,0x01,0xac,0x00,0x02,0x11,0x80, ++0x00,0x82,0x10,0x23,0x00,0x43,0x18,0x26,0xad,0x02,0x01,0xa8,0x00,0x03,0x20,0x2b, ++0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x08,0x00,0x29,0x95,0x24,0x62,0x00,0x40, ++0x27,0x82,0x89,0x68,0x00,0x06,0x20,0xc2,0x00,0x04,0x22,0x00,0x00,0xa2,0x48,0x21, ++0x3c,0x02,0x00,0x80,0x00,0x82,0x58,0x25,0x93,0x82,0x81,0xf0,0x3c,0x0a,0xb0,0x06, ++0x3c,0x03,0xb0,0x01,0x2c,0x42,0x00,0x02,0x00,0xc3,0x38,0x21,0x35,0x4a,0x80,0x18, ++0x14,0x40,0xff,0xef,0x00,0x00,0x20,0x21,0x8c,0xe5,0x00,0x00,0x8d,0x23,0x00,0x00, ++0x24,0x02,0xc0,0x00,0x00,0xa2,0x10,0x24,0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x00, ++0x8d,0x04,0x01,0xa8,0x27,0x83,0x8a,0x68,0x8c,0xe5,0x00,0x04,0x00,0x04,0x20,0x80, ++0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00,0x00,0xa2,0x10,0x25, ++0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x04,0xaf,0x86,0xbc,0x20,0x8c,0xe2,0x00,0x00, ++0x93,0x85,0x81,0xf0,0xaf,0x82,0xbc,0x28,0x8c,0xe3,0x00,0x04,0xad,0x4b,0x00,0x00, ++0x8d,0x02,0x01,0xa8,0xaf,0x83,0xbc,0x24,0x24,0xa5,0xff,0xff,0x24,0x44,0x00,0x01, ++0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83, ++0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0xad,0x04,0x01,0xa8,0xa3,0x85,0x81,0xf0, ++0x79,0x02,0x0d,0x7c,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x26,0x08,0x00,0x29,0x9c, ++0x00,0x02,0x20,0x2b,0x3c,0x04,0xb0,0x03,0x3c,0x06,0xb0,0x07,0x3c,0x02,0x80,0x01, ++0x34,0xc6,0x00,0x18,0x34,0x84,0x00,0x20,0x24,0x42,0xa7,0x54,0x24,0x03,0xff,0x83, ++0xac,0x82,0x00,0x00,0xa0,0xc3,0x00,0x00,0x90,0xc4,0x00,0x00,0x27,0xbd,0xff,0xf8, ++0x3c,0x03,0xb0,0x07,0x24,0x02,0xff,0x82,0xa3,0xa4,0x00,0x00,0xa0,0x62,0x00,0x00, ++0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x08,0xa3,0xa4,0x00,0x01, ++0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x24,0x02,0x00,0x03,0x3c,0x05,0xb0,0x07, ++0xa3,0xa3,0x00,0x00,0xa0,0xc2,0x00,0x00,0x90,0xc4,0x00,0x00,0x34,0xa5,0x00,0x10, ++0x24,0x02,0x00,0x06,0x3c,0x03,0xb0,0x07,0xa3,0xa4,0x00,0x00,0x34,0x63,0x00,0x38, ++0xa0,0xa2,0x00,0x00,0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x20, ++0xa3,0xa4,0x00,0x00,0xa0,0xa0,0x00,0x00,0x90,0xa3,0x00,0x00,0xaf,0x82,0xbf,0x30, ++0xa3,0xa3,0x00,0x00,0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x08,}; ++ ++static u8 rtl8192e_fwdata_array[] = { ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00, ++0x02,0xe9,0x01,0x74,0x02,0xab,0x01,0xc7,0x01,0x55,0x00,0xe4,0x00,0xab,0x00,0x72, ++0x00,0x55,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x02,0x76,0x01,0x3b, ++0x00,0xd2,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x46,0x00,0x3f,0x01,0x3b,0x00,0x9e, ++0x00,0x69,0x00,0x4f,0x00,0x35,0x00,0x27,0x00,0x23,0x00,0x20,0x01,0x2f,0x00,0x98, ++0x00,0x65,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x22,0x00,0x1e,0x00,0x98,0x00,0x4c, ++0x00,0x33,0x00,0x26,0x00,0x19,0x00,0x13,0x00,0x11,0x00,0x0f,0x02,0x39,0x01,0x1c, ++0x00,0xbd,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x3f,0x00,0x39,0x01,0x1c,0x00,0x8e, ++0x00,0x5f,0x00,0x47,0x00,0x2f,0x00,0x23,0x00,0x20,0x00,0x1c,0x01,0x11,0x00,0x89, ++0x00,0x5b,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x1e,0x00,0x1b,0x00,0x89,0x00,0x44, ++0x00,0x2e,0x00,0x22,0x00,0x17,0x00,0x11,0x00,0x0f,0x00,0x0e,0x02,0xab,0x02,0xab, ++0x02,0x66,0x02,0x66,0x07,0x06,0x06,0x06,0x05,0x06,0x07,0x08,0x04,0x06,0x07,0x08, ++0x09,0x0a,0x0b,0x0b,0x49,0x6e,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x4c, ++0x42,0x4d,0x4f,0x44,0x00,0x00,0x00,0x00,0x54,0x4c,0x42,0x4c,0x5f,0x64,0x61,0x74, ++0x61,0x00,0x54,0x4c,0x42,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x64,0x45,0x4c, ++0x5f,0x64,0x61,0x74,0x61,0x00,0x41,0x64,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00, ++0x45,0x78,0x63,0x43,0x6f,0x64,0x65,0x36,0x00,0x00,0x45,0x78,0x63,0x43,0x6f,0x64, ++0x65,0x37,0x00,0x00,0x53,0x79,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x70, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x49,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x43,0x70,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x76,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x0b,0x63, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x2c, ++0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x60, ++0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x01,0x20,0x00,0x00,0x01,0x80, ++0x00,0x00,0x01,0xb0,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x9c, ++0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0x38,0x00,0x00,0x01,0xa0,0x00,0x00,0x01,0xd4, ++0x00,0x00,0x02,0x08,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0x38, ++0x00,0x00,0x01,0xa0,0x00,0x00,0x02,0x6f,0x00,0x00,0x03,0x40,0x00,0x00,0x03,0xa8, ++0x00,0x00,0x04,0x10,0x01,0x01,0x01,0x02,0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04, ++0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x07,0x6c,0x80,0x00,0x07,0x80, ++0x80,0x00,0x07,0x80,0x80,0x00,0x07,0x70,0x80,0x00,0x07,0x70,0x80,0x00,0x07,0x94, ++0x80,0x00,0x56,0xb0,0x80,0x00,0x57,0x08,0x80,0x00,0x57,0x30,0x80,0x00,0x58,0x28, ++0x80,0x00,0x58,0xe0,0x80,0x00,0x59,0x88,0x80,0x00,0x59,0xfc,0x80,0x00,0x5b,0x08, ++0x80,0x00,0x5b,0x40,0x80,0x00,0x5b,0x54,0x80,0x00,0x5b,0x68,0x80,0x00,0x5c,0x50, ++0x80,0x00,0x5c,0x90,0x80,0x00,0x5d,0x44,0x80,0x00,0x5d,0x6c,0x80,0x00,0x56,0x70, ++0x80,0x00,0x5d,0xbc,0x80,0x00,0x64,0x48,0x80,0x00,0x64,0xc0,0x80,0x00,0x64,0xcc, ++0x80,0x00,0x64,0xd8,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60, ++0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60, ++0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60,0x80,0x00,0x64,0x60, ++0x80,0x00,0x64,0x60,0x80,0x00,0x64,0xe4,0x80,0x00,0x64,0xf0,0x80,0x00,0x64,0xfc, ++0x80,0x00,0x87,0xa4,0x80,0x00,0x87,0xa4,0x80,0x00,0x87,0xa4,0x80,0x00,0x87,0xd8, ++0x80,0x00,0x88,0x18,0x80,0x00,0x88,0x50,0x80,0x00,0x88,0x80,0x80,0x00,0x88,0xb0, ++0x80,0x00,0x88,0xc4,0x80,0x00,0x89,0x2c,0x80,0x00,0x89,0x40,0x80,0x00,0x89,0x7c, ++0x80,0x00,0x89,0x84,0x80,0x00,0x89,0xc0,0x80,0x00,0x89,0xd4,0x80,0x00,0x89,0xdc, ++0x80,0x00,0x89,0xe4,0x80,0x00,0x89,0xe4,0x80,0x00,0x89,0xe4,0x80,0x00,0x89,0xe4, ++0x80,0x00,0x8a,0x14,0x80,0x00,0x8a,0x28,0x80,0x00,0x8a,0x3c,0x80,0x00,0x86,0xe8, ++0x80,0x00,0x8d,0x68,0x80,0x00,0x8d,0x68,0x80,0x00,0x8d,0x68,0x80,0x00,0x8d,0x9c, ++0x80,0x00,0x8d,0xdc,0x80,0x00,0x8e,0x14,0x80,0x00,0x8e,0x44,0x80,0x00,0x8e,0x74, ++0x80,0x00,0x8e,0x88,0x80,0x00,0x8e,0xf0,0x80,0x00,0x8f,0x04,0x80,0x00,0x8f,0x40, ++0x80,0x00,0x8f,0x48,0x80,0x00,0x8f,0x84,0x80,0x00,0x8f,0x98,0x80,0x00,0x8f,0xa0, ++0x80,0x00,0x8f,0xa8,0x80,0x00,0x8f,0xa8,0x80,0x00,0x8f,0xa8,0x80,0x00,0x8f,0xa8, ++0x80,0x00,0x8f,0xd8,0x80,0x00,0x8f,0xec,0x80,0x00,0x90,0x00,0x80,0x00,0x8b,0x88, ++}; ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_phy.c +@@ -0,0 +1,3352 @@ ++#include "r8192E.h" ++#include "r8192E_hw.h" ++#include "r819xE_phyreg.h" ++#include "r8190_rtl8256.h" ++#include "r819xE_phy.h" ++#include "r8192E_dm.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++static u32 RF_CHANNEL_TABLE_ZEBRA[] = { ++ 0, ++ 0x085c, //2412 1 ++ 0x08dc, //2417 2 ++ 0x095c, //2422 3 ++ 0x09dc, //2427 4 ++ 0x0a5c, //2432 5 ++ 0x0adc, //2437 6 ++ 0x0b5c, //2442 7 ++ 0x0bdc, //2447 8 ++ 0x0c5c, //2452 9 ++ 0x0cdc, //2457 10 ++ 0x0d5c, //2462 11 ++ 0x0ddc, //2467 12 ++ 0x0e5c, //2472 13 ++ 0x0f72, //2484 ++}; ++#ifdef RTL8190P ++u32 Rtl8190PciMACPHY_Array[] = { ++0x03c,0xffff0000,0x00000f0f, ++0x340,0xffffffff,0x161a1a1a, ++0x344,0xffffffff,0x12121416, ++0x348,0x0000ffff,0x00001818, ++0x12c,0xffffffff,0x04000802, ++0x318,0x00000fff,0x00000800, ++}; ++u32 Rtl8190PciMACPHY_Array_PG[] = { ++0x03c,0xffff0000,0x00000f0f, ++0x340,0xffffffff,0x0a0c0d0f, ++0x344,0xffffffff,0x06070809, ++0x344,0xffffffff,0x06070809, ++0x348,0x0000ffff,0x00000000, ++0x12c,0xffffffff,0x04000802, ++0x318,0x00000fff,0x00000800, ++}; ++ ++u32 Rtl8190PciAGCTAB_Array[AGCTAB_ArrayLength] = { ++0xc78,0x7d000001, ++0xc78,0x7d010001, ++0xc78,0x7d020001, ++0xc78,0x7d030001, ++0xc78,0x7c040001, ++0xc78,0x7b050001, ++0xc78,0x7a060001, ++0xc78,0x79070001, ++0xc78,0x78080001, ++0xc78,0x77090001, ++0xc78,0x760a0001, ++0xc78,0x750b0001, ++0xc78,0x740c0001, ++0xc78,0x730d0001, ++0xc78,0x720e0001, ++0xc78,0x710f0001, ++0xc78,0x70100001, ++0xc78,0x6f110001, ++0xc78,0x6e120001, ++0xc78,0x6d130001, ++0xc78,0x6c140001, ++0xc78,0x6b150001, ++0xc78,0x6a160001, ++0xc78,0x69170001, ++0xc78,0x68180001, ++0xc78,0x67190001, ++0xc78,0x661a0001, ++0xc78,0x651b0001, ++0xc78,0x641c0001, ++0xc78,0x491d0001, ++0xc78,0x481e0001, ++0xc78,0x471f0001, ++0xc78,0x46200001, ++0xc78,0x45210001, ++0xc78,0x44220001, ++0xc78,0x43230001, ++0xc78,0x28240001, ++0xc78,0x27250001, ++0xc78,0x26260001, ++0xc78,0x25270001, ++0xc78,0x24280001, ++0xc78,0x23290001, ++0xc78,0x222a0001, ++0xc78,0x212b0001, ++0xc78,0x202c0001, ++0xc78,0x0a2d0001, ++0xc78,0x082e0001, ++0xc78,0x062f0001, ++0xc78,0x05300001, ++0xc78,0x04310001, ++0xc78,0x03320001, ++0xc78,0x02330001, ++0xc78,0x01340001, ++0xc78,0x00350001, ++0xc78,0x00360001, ++0xc78,0x00370001, ++0xc78,0x00380001, ++0xc78,0x00390001, ++0xc78,0x003a0001, ++0xc78,0x003b0001, ++0xc78,0x003c0001, ++0xc78,0x003d0001, ++0xc78,0x003e0001, ++0xc78,0x003f0001, ++0xc78,0x7d400001, ++0xc78,0x7d410001, ++0xc78,0x7d420001, ++0xc78,0x7d430001, ++0xc78,0x7c440001, ++0xc78,0x7b450001, ++0xc78,0x7a460001, ++0xc78,0x79470001, ++0xc78,0x78480001, ++0xc78,0x77490001, ++0xc78,0x764a0001, ++0xc78,0x754b0001, ++0xc78,0x744c0001, ++0xc78,0x734d0001, ++0xc78,0x724e0001, ++0xc78,0x714f0001, ++0xc78,0x70500001, ++0xc78,0x6f510001, ++0xc78,0x6e520001, ++0xc78,0x6d530001, ++0xc78,0x6c540001, ++0xc78,0x6b550001, ++0xc78,0x6a560001, ++0xc78,0x69570001, ++0xc78,0x68580001, ++0xc78,0x67590001, ++0xc78,0x665a0001, ++0xc78,0x655b0001, ++0xc78,0x645c0001, ++0xc78,0x495d0001, ++0xc78,0x485e0001, ++0xc78,0x475f0001, ++0xc78,0x46600001, ++0xc78,0x45610001, ++0xc78,0x44620001, ++0xc78,0x43630001, ++0xc78,0x28640001, ++0xc78,0x27650001, ++0xc78,0x26660001, ++0xc78,0x25670001, ++0xc78,0x24680001, ++0xc78,0x23690001, ++0xc78,0x226a0001, ++0xc78,0x216b0001, ++0xc78,0x206c0001, ++0xc78,0x0a6d0001, ++0xc78,0x086e0001, ++0xc78,0x066f0001, ++0xc78,0x05700001, ++0xc78,0x04710001, ++0xc78,0x03720001, ++0xc78,0x02730001, ++0xc78,0x01740001, ++0xc78,0x00750001, ++0xc78,0x00760001, ++0xc78,0x00770001, ++0xc78,0x00780001, ++0xc78,0x00790001, ++0xc78,0x007a0001, ++0xc78,0x007b0001, ++0xc78,0x007c0001, ++0xc78,0x007d0001, ++0xc78,0x007e0001, ++0xc78,0x007f0001, ++0xc78,0x3600001e, ++0xc78,0x3601001e, ++0xc78,0x3602001e, ++0xc78,0x3603001e, ++0xc78,0x3604001e, ++0xc78,0x3605001e, ++0xc78,0x3a06001e, ++0xc78,0x3c07001e, ++0xc78,0x3e08001e, ++0xc78,0x4209001e, ++0xc78,0x430a001e, ++0xc78,0x450b001e, ++0xc78,0x470c001e, ++0xc78,0x480d001e, ++0xc78,0x490e001e, ++0xc78,0x4b0f001e, ++0xc78,0x4c10001e, ++0xc78,0x4d11001e, ++0xc78,0x4d12001e, ++0xc78,0x4e13001e, ++0xc78,0x4f14001e, ++0xc78,0x5015001e, ++0xc78,0x5116001e, ++0xc78,0x5117001e, ++0xc78,0x5218001e, ++0xc78,0x5219001e, ++0xc78,0x531a001e, ++0xc78,0x541b001e, ++0xc78,0x541c001e, ++0xc78,0x551d001e, ++0xc78,0x561e001e, ++0xc78,0x561f001e, ++0xc78,0x5720001e, ++0xc78,0x5821001e, ++0xc78,0x5822001e, ++0xc78,0x5923001e, ++0xc78,0x5924001e, ++0xc78,0x5a25001e, ++0xc78,0x5b26001e, ++0xc78,0x5b27001e, ++0xc78,0x5c28001e, ++0xc78,0x5c29001e, ++0xc78,0x5d2a001e, ++0xc78,0x5d2b001e, ++0xc78,0x5e2c001e, ++0xc78,0x5e2d001e, ++0xc78,0x5f2e001e, ++0xc78,0x602f001e, ++0xc78,0x6030001e, ++0xc78,0x6131001e, ++0xc78,0x6132001e, ++0xc78,0x6233001e, ++0xc78,0x6234001e, ++0xc78,0x6335001e, ++0xc78,0x6336001e, ++0xc78,0x6437001e, ++0xc78,0x6538001e, ++0xc78,0x6639001e, ++0xc78,0x663a001e, ++0xc78,0x673b001e, ++0xc78,0x683c001e, ++0xc78,0x693d001e, ++0xc78,0x6a3e001e, ++0xc78,0x6b3f001e, ++}; ++ ++u32 Rtl8190PciPHY_REGArray[PHY_REGArrayLength] = { ++0x800,0x00050060, ++0x804,0x00000005, ++0x808,0x0000fc00, ++0x80c,0x0000001c, ++0x810,0x801010aa, ++0x814,0x000908c0, ++0x818,0x00000000, ++0x81c,0x00000000, ++0x820,0x00000004, ++0x824,0x00690000, ++0x828,0x00000004, ++0x82c,0x00e90000, ++0x830,0x00000004, ++0x834,0x00690000, ++0x838,0x00000004, ++0x83c,0x00e90000, ++0x840,0x00000000, ++0x844,0x00000000, ++0x848,0x00000000, ++0x84c,0x00000000, ++0x850,0x00000000, ++0x854,0x00000000, ++0x858,0x65a965a9, ++0x85c,0x65a965a9, ++0x860,0x001f0010, ++0x864,0x007f0010, ++0x868,0x001f0010, ++0x86c,0x007f0010, ++0x870,0x0f100f70, ++0x874,0x0f100f70, ++0x878,0x00000000, ++0x87c,0x00000000, ++0x880,0x5c385eb8, ++0x884,0x6357060d, ++0x888,0x0460c341, ++0x88c,0x0000ff00, ++0x890,0x00000000, ++0x894,0xfffffffe, ++0x898,0x4c42382f, ++0x89c,0x00656056, ++0x8b0,0x00000000, ++0x8e0,0x00000000, ++0x8e4,0x00000000, ++0x900,0x00000000, ++0x904,0x00000023, ++0x908,0x00000000, ++0x90c,0x35541545, ++0xa00,0x00d0c7d8, ++0xa04,0xab1f0008, ++0xa08,0x80cd8300, ++0xa0c,0x2e62740f, ++0xa10,0x95009b78, ++0xa14,0x11145008, ++0xa18,0x00881117, ++0xa1c,0x89140fa0, ++0xa20,0x1a1b0000, ++0xa24,0x090e1317, ++0xa28,0x00000204, ++0xa2c,0x00000000, ++0xc00,0x00000040, ++0xc04,0x0000500f, ++0xc08,0x000000e4, ++0xc0c,0x6c6c6c6c, ++0xc10,0x08000000, ++0xc14,0x40000100, ++0xc18,0x08000000, ++0xc1c,0x40000100, ++0xc20,0x08000000, ++0xc24,0x40000100, ++0xc28,0x08000000, ++0xc2c,0x40000100, ++0xc30,0x6de9ac44, ++0xc34,0x164052cd, ++0xc38,0x00070a14, ++0xc3c,0x0a969764, ++0xc40,0x1f7c403f, ++0xc44,0x000100b7, ++0xc48,0xec020000, ++0xc4c,0x00000300, ++0xc50,0x69543420, ++0xc54,0x433c0094, ++0xc58,0x69543420, ++0xc5c,0x433c0094, ++0xc60,0x69543420, ++0xc64,0x433c0094, ++0xc68,0x69543420, ++0xc6c,0x433c0094, ++0xc70,0x2c7f000d, ++0xc74,0x0186175b, ++0xc78,0x0000001f, ++0xc7c,0x00b91612, ++0xc80,0x40000100, ++0xc84,0x00000000, ++0xc88,0x40000100, ++0xc8c,0x08000000, ++0xc90,0x40000100, ++0xc94,0x00000000, ++0xc98,0x40000100, ++0xc9c,0x00000000, ++0xca0,0x00492492, ++0xca4,0x00000000, ++0xca8,0x00000000, ++0xcac,0x00000000, ++0xcb0,0x00000000, ++0xcb4,0x00000000, ++0xcb8,0x00000000, ++0xcbc,0x00492492, ++0xcc0,0x00000000, ++0xcc4,0x00000000, ++0xcc8,0x00000000, ++0xccc,0x00000000, ++0xcd0,0x00000000, ++0xcd4,0x00000000, ++0xcd8,0x64b22427, ++0xcdc,0x00766932, ++0xce0,0x00222222, ++0xd00,0x00000740, ++0xd04,0x0000040f, ++0xd08,0x0000803f, ++0xd0c,0x00000001, ++0xd10,0xa0633333, ++0xd14,0x33333c63, ++0xd18,0x6a8f5b6b, ++0xd1c,0x00000000, ++0xd20,0x00000000, ++0xd24,0x00000000, ++0xd28,0x00000000, ++0xd2c,0xcc979975, ++0xd30,0x00000000, ++0xd34,0x00000000, ++0xd38,0x00000000, ++0xd3c,0x00027293, ++0xd40,0x00000000, ++0xd44,0x00000000, ++0xd48,0x00000000, ++0xd4c,0x00000000, ++0xd50,0x6437140a, ++0xd54,0x024dbd02, ++0xd58,0x00000000, ++0xd5c,0x14032064, ++}; ++u32 Rtl8190PciPHY_REG_1T2RArray[PHY_REG_1T2RArrayLength] = { ++0x800,0x00050060, ++0x804,0x00000004, ++0x808,0x0000fc00, ++0x80c,0x0000001c, ++0x810,0x801010aa, ++0x814,0x000908c0, ++0x818,0x00000000, ++0x81c,0x00000000, ++0x820,0x00000004, ++0x824,0x00690000, ++0x828,0x00000004, ++0x82c,0x00e90000, ++0x830,0x00000004, ++0x834,0x00690000, ++0x838,0x00000004, ++0x83c,0x00e90000, ++0x840,0x00000000, ++0x844,0x00000000, ++0x848,0x00000000, ++0x84c,0x00000000, ++0x850,0x00000000, ++0x854,0x00000000, ++0x858,0x65a965a9, ++0x85c,0x65a965a9, ++0x860,0x001f0000, ++0x864,0x007f0000, ++0x868,0x001f0010, ++0x86c,0x007f0010, ++0x870,0x0f100f70, ++0x874,0x0f100f70, ++0x878,0x00000000, ++0x87c,0x00000000, ++0x880,0x5c385898, ++0x884,0x6357060d, ++0x888,0x0460c341, ++0x88c,0x0000fc00, ++0x890,0x00000000, ++0x894,0xfffffffe, ++0x898,0x4c42382f, ++0x89c,0x00656056, ++0x8b0,0x00000000, ++0x8e0,0x00000000, ++0x8e4,0x00000000, ++0x900,0x00000000, ++0x904,0x00000023, ++0x908,0x00000000, ++0x90c,0x34441444, ++0xa00,0x00d0c7d8, ++0xa04,0x2b1f0008, ++0xa08,0x80cd8300, ++0xa0c,0x2e62740f, ++0xa10,0x95009b78, ++0xa14,0x11145008, ++0xa18,0x00881117, ++0xa1c,0x89140fa0, ++0xa20,0x1a1b0000, ++0xa24,0x090e1317, ++0xa28,0x00000204, ++0xa2c,0x00000000, ++0xc00,0x00000040, ++0xc04,0x0000500c, ++0xc08,0x000000e4, ++0xc0c,0x6c6c6c6c, ++0xc10,0x08000000, ++0xc14,0x40000100, ++0xc18,0x08000000, ++0xc1c,0x40000100, ++0xc20,0x08000000, ++0xc24,0x40000100, ++0xc28,0x08000000, ++0xc2c,0x40000100, ++0xc30,0x6de9ac44, ++0xc34,0x164052cd, ++0xc38,0x00070a14, ++0xc3c,0x0a969764, ++0xc40,0x1f7c403f, ++0xc44,0x000100b7, ++0xc48,0xec020000, ++0xc4c,0x00000300, ++0xc50,0x69543420, ++0xc54,0x433c0094, ++0xc58,0x69543420, ++0xc5c,0x433c0094, ++0xc60,0x69543420, ++0xc64,0x433c0094, ++0xc68,0x69543420, ++0xc6c,0x433c0094, ++0xc70,0x2c7f000d, ++0xc74,0x0186175b, ++0xc78,0x0000001f, ++0xc7c,0x00b91612, ++0xc80,0x40000100, ++0xc84,0x00000000, ++0xc88,0x40000100, ++0xc8c,0x08000000, ++0xc90,0x40000100, ++0xc94,0x00000000, ++0xc98,0x40000100, ++0xc9c,0x00000000, ++0xca0,0x00492492, ++0xca4,0x00000000, ++0xca8,0x00000000, ++0xcac,0x00000000, ++0xcb0,0x00000000, ++0xcb4,0x00000000, ++0xcb8,0x00000000, ++0xcbc,0x00492492, ++0xcc0,0x00000000, ++0xcc4,0x00000000, ++0xcc8,0x00000000, ++0xccc,0x00000000, ++0xcd0,0x00000000, ++0xcd4,0x00000000, ++0xcd8,0x64b22427, ++0xcdc,0x00766932, ++0xce0,0x00222222, ++0xd00,0x00000740, ++0xd04,0x0000040c, ++0xd08,0x0000803f, ++0xd0c,0x00000001, ++0xd10,0xa0633333, ++0xd14,0x33333c63, ++0xd18,0x6a8f5b6b, ++0xd1c,0x00000000, ++0xd20,0x00000000, ++0xd24,0x00000000, ++0xd28,0x00000000, ++0xd2c,0xcc979975, ++0xd30,0x00000000, ++0xd34,0x00000000, ++0xd38,0x00000000, ++0xd3c,0x00027293, ++0xd40,0x00000000, ++0xd44,0x00000000, ++0xd48,0x00000000, ++0xd4c,0x00000000, ++0xd50,0x6437140a, ++0xd54,0x024dbd02, ++0xd58,0x00000000, ++0xd5c,0x14032064, ++}; ++ ++u32 Rtl8190PciRadioA_Array[RadioA_ArrayLength] = { ++0x019,0x00000003, ++0x000,0x000000bf, ++0x001,0x00000ee0, ++0x002,0x0000004c, ++0x003,0x000007f1, ++0x004,0x00000975, ++0x005,0x00000c58, ++0x006,0x00000ae6, ++0x007,0x000000ca, ++0x008,0x00000e1c, ++0x009,0x000007f0, ++0x00a,0x000009d0, ++0x00b,0x000001ba, ++0x00c,0x00000240, ++0x00e,0x00000020, ++0x00f,0x00000990, ++0x012,0x00000806, ++0x014,0x000005ab, ++0x015,0x00000f80, ++0x016,0x00000020, ++0x017,0x00000597, ++0x018,0x0000050a, ++0x01a,0x00000f80, ++0x01b,0x00000f5e, ++0x01c,0x00000008, ++0x01d,0x00000607, ++0x01e,0x000006cc, ++0x01f,0x00000000, ++0x020,0x000001a5, ++0x01f,0x00000001, ++0x020,0x00000165, ++0x01f,0x00000002, ++0x020,0x000000c6, ++0x01f,0x00000003, ++0x020,0x00000086, ++0x01f,0x00000004, ++0x020,0x00000046, ++0x01f,0x00000005, ++0x020,0x000001e6, ++0x01f,0x00000006, ++0x020,0x000001a6, ++0x01f,0x00000007, ++0x020,0x00000166, ++0x01f,0x00000008, ++0x020,0x000000c7, ++0x01f,0x00000009, ++0x020,0x00000087, ++0x01f,0x0000000a, ++0x020,0x000000f7, ++0x01f,0x0000000b, ++0x020,0x000000d7, ++0x01f,0x0000000c, ++0x020,0x000000b7, ++0x01f,0x0000000d, ++0x020,0x00000097, ++0x01f,0x0000000e, ++0x020,0x00000077, ++0x01f,0x0000000f, ++0x020,0x00000057, ++0x01f,0x00000010, ++0x020,0x00000037, ++0x01f,0x00000011, ++0x020,0x000000fb, ++0x01f,0x00000012, ++0x020,0x000000db, ++0x01f,0x00000013, ++0x020,0x000000bb, ++0x01f,0x00000014, ++0x020,0x000000ff, ++0x01f,0x00000015, ++0x020,0x000000e3, ++0x01f,0x00000016, ++0x020,0x000000c3, ++0x01f,0x00000017, ++0x020,0x000000a3, ++0x01f,0x00000018, ++0x020,0x00000083, ++0x01f,0x00000019, ++0x020,0x00000063, ++0x01f,0x0000001a, ++0x020,0x00000043, ++0x01f,0x0000001b, ++0x020,0x00000023, ++0x01f,0x0000001c, ++0x020,0x00000003, ++0x01f,0x0000001d, ++0x020,0x000001e3, ++0x01f,0x0000001e, ++0x020,0x000001c3, ++0x01f,0x0000001f, ++0x020,0x000001a3, ++0x01f,0x00000020, ++0x020,0x00000183, ++0x01f,0x00000021, ++0x020,0x00000163, ++0x01f,0x00000022, ++0x020,0x00000143, ++0x01f,0x00000023, ++0x020,0x00000123, ++0x01f,0x00000024, ++0x020,0x00000103, ++0x023,0x00000203, ++0x024,0x00000200, ++0x00b,0x000001ba, ++0x02c,0x000003d7, ++0x02d,0x00000ff0, ++0x000,0x00000037, ++0x004,0x00000160, ++0x007,0x00000080, ++0x002,0x0000088d, ++0x0fe,0x00000000, ++0x0fe,0x00000000, ++0x016,0x00000200, ++0x016,0x00000380, ++0x016,0x00000020, ++0x016,0x000001a0, ++0x000,0x000000bf, ++0x00d,0x0000001f, ++0x00d,0x00000c9f, ++0x002,0x0000004d, ++0x000,0x00000cbf, ++0x004,0x00000975, ++0x007,0x00000700, ++}; ++u32 Rtl8190PciRadioB_Array[RadioB_ArrayLength] = { ++0x019,0x00000003, ++0x000,0x000000bf, ++0x001,0x000006e0, ++0x002,0x0000004c, ++0x003,0x000007f1, ++0x004,0x00000975, ++0x005,0x00000c58, ++0x006,0x00000ae6, ++0x007,0x000000ca, ++0x008,0x00000e1c, ++0x000,0x000000b7, ++0x00a,0x00000850, ++0x000,0x000000bf, ++0x00b,0x000001ba, ++0x00c,0x00000240, ++0x00e,0x00000020, ++0x015,0x00000f80, ++0x016,0x00000020, ++0x017,0x00000597, ++0x018,0x0000050a, ++0x01a,0x00000e00, ++0x01b,0x00000f5e, ++0x01d,0x00000607, ++0x01e,0x000006cc, ++0x00b,0x000001ba, ++0x023,0x00000203, ++0x024,0x00000200, ++0x000,0x00000037, ++0x004,0x00000160, ++0x016,0x00000200, ++0x016,0x00000380, ++0x016,0x00000020, ++0x016,0x000001a0, ++0x00d,0x00000ccc, ++0x000,0x000000bf, ++0x002,0x0000004d, ++0x000,0x00000cbf, ++0x004,0x00000975, ++0x007,0x00000700, ++}; ++u32 Rtl8190PciRadioC_Array[RadioC_ArrayLength] = { ++0x019,0x00000003, ++0x000,0x000000bf, ++0x001,0x00000ee0, ++0x002,0x0000004c, ++0x003,0x000007f1, ++0x004,0x00000975, ++0x005,0x00000c58, ++0x006,0x00000ae6, ++0x007,0x000000ca, ++0x008,0x00000e1c, ++0x009,0x000007f0, ++0x00a,0x000009d0, ++0x00b,0x000001ba, ++0x00c,0x00000240, ++0x00e,0x00000020, ++0x00f,0x00000990, ++0x012,0x00000806, ++0x014,0x000005ab, ++0x015,0x00000f80, ++0x016,0x00000020, ++0x017,0x00000597, ++0x018,0x0000050a, ++0x01a,0x00000f80, ++0x01b,0x00000f5e, ++0x01c,0x00000008, ++0x01d,0x00000607, ++0x01e,0x000006cc, ++0x01f,0x00000000, ++0x020,0x000001a5, ++0x01f,0x00000001, ++0x020,0x00000165, ++0x01f,0x00000002, ++0x020,0x000000c6, ++0x01f,0x00000003, ++0x020,0x00000086, ++0x01f,0x00000004, ++0x020,0x00000046, ++0x01f,0x00000005, ++0x020,0x000001e6, ++0x01f,0x00000006, ++0x020,0x000001a6, ++0x01f,0x00000007, ++0x020,0x00000166, ++0x01f,0x00000008, ++0x020,0x000000c7, ++0x01f,0x00000009, ++0x020,0x00000087, ++0x01f,0x0000000a, ++0x020,0x000000f7, ++0x01f,0x0000000b, ++0x020,0x000000d7, ++0x01f,0x0000000c, ++0x020,0x000000b7, ++0x01f,0x0000000d, ++0x020,0x00000097, ++0x01f,0x0000000e, ++0x020,0x00000077, ++0x01f,0x0000000f, ++0x020,0x00000057, ++0x01f,0x00000010, ++0x020,0x00000037, ++0x01f,0x00000011, ++0x020,0x000000fb, ++0x01f,0x00000012, ++0x020,0x000000db, ++0x01f,0x00000013, ++0x020,0x000000bb, ++0x01f,0x00000014, ++0x020,0x000000ff, ++0x01f,0x00000015, ++0x020,0x000000e3, ++0x01f,0x00000016, ++0x020,0x000000c3, ++0x01f,0x00000017, ++0x020,0x000000a3, ++0x01f,0x00000018, ++0x020,0x00000083, ++0x01f,0x00000019, ++0x020,0x00000063, ++0x01f,0x0000001a, ++0x020,0x00000043, ++0x01f,0x0000001b, ++0x020,0x00000023, ++0x01f,0x0000001c, ++0x020,0x00000003, ++0x01f,0x0000001d, ++0x020,0x000001e3, ++0x01f,0x0000001e, ++0x020,0x000001c3, ++0x01f,0x0000001f, ++0x020,0x000001a3, ++0x01f,0x00000020, ++0x020,0x00000183, ++0x01f,0x00000021, ++0x020,0x00000163, ++0x01f,0x00000022, ++0x020,0x00000143, ++0x01f,0x00000023, ++0x020,0x00000123, ++0x01f,0x00000024, ++0x020,0x00000103, ++0x023,0x00000203, ++0x024,0x00000200, ++0x00b,0x000001ba, ++0x02c,0x000003d7, ++0x02d,0x00000ff0, ++0x000,0x00000037, ++0x004,0x00000160, ++0x007,0x00000080, ++0x002,0x0000088d, ++0x0fe,0x00000000, ++0x0fe,0x00000000, ++0x016,0x00000200, ++0x016,0x00000380, ++0x016,0x00000020, ++0x016,0x000001a0, ++0x000,0x000000bf, ++0x00d,0x0000001f, ++0x00d,0x00000c9f, ++0x002,0x0000004d, ++0x000,0x00000cbf, ++0x004,0x00000975, ++0x007,0x00000700, ++}; ++u32 Rtl8190PciRadioD_Array[RadioD_ArrayLength] = { ++0x019,0x00000003, ++0x000,0x000000bf, ++0x001,0x000006e0, ++0x002,0x0000004c, ++0x003,0x000007f1, ++0x004,0x00000975, ++0x005,0x00000c58, ++0x006,0x00000ae6, ++0x007,0x000000ca, ++0x008,0x00000e1c, ++0x000,0x000000b7, ++0x00a,0x00000850, ++0x000,0x000000bf, ++0x00b,0x000001ba, ++0x00c,0x00000240, ++0x00e,0x00000020, ++0x015,0x00000f80, ++0x016,0x00000020, ++0x017,0x00000597, ++0x018,0x0000050a, ++0x01a,0x00000e00, ++0x01b,0x00000f5e, ++0x01d,0x00000607, ++0x01e,0x000006cc, ++0x00b,0x000001ba, ++0x023,0x00000203, ++0x024,0x00000200, ++0x000,0x00000037, ++0x004,0x00000160, ++0x016,0x00000200, ++0x016,0x00000380, ++0x016,0x00000020, ++0x016,0x000001a0, ++0x00d,0x00000ccc, ++0x000,0x000000bf, ++0x002,0x0000004d, ++0x000,0x00000cbf, ++0x004,0x00000975, ++0x007,0x00000700, ++}; ++#endif ++#ifdef RTL8192E ++static u32 Rtl8192PciEMACPHY_Array[] = { ++0x03c,0xffff0000,0x00000f0f, ++0x340,0xffffffff,0x161a1a1a, ++0x344,0xffffffff,0x12121416, ++0x348,0x0000ffff,0x00001818, ++0x12c,0xffffffff,0x04000802, ++0x318,0x00000fff,0x00000100, ++}; ++static u32 Rtl8192PciEMACPHY_Array_PG[] = { ++0x03c,0xffff0000,0x00000f0f, ++0xe00,0xffffffff,0x06090909, ++0xe04,0xffffffff,0x00030306, ++0xe08,0x0000ff00,0x00000000, ++0xe10,0xffffffff,0x0a0c0d0f, ++0xe14,0xffffffff,0x06070809, ++0xe18,0xffffffff,0x0a0c0d0f, ++0xe1c,0xffffffff,0x06070809, ++0x12c,0xffffffff,0x04000802, ++0x318,0x00000fff,0x00000800, ++}; ++static u32 Rtl8192PciEAGCTAB_Array[AGCTAB_ArrayLength] = { ++0xc78,0x7d000001, ++0xc78,0x7d010001, ++0xc78,0x7d020001, ++0xc78,0x7d030001, ++0xc78,0x7d040001, ++0xc78,0x7d050001, ++0xc78,0x7c060001, ++0xc78,0x7b070001, ++0xc78,0x7a080001, ++0xc78,0x79090001, ++0xc78,0x780a0001, ++0xc78,0x770b0001, ++0xc78,0x760c0001, ++0xc78,0x750d0001, ++0xc78,0x740e0001, ++0xc78,0x730f0001, ++0xc78,0x72100001, ++0xc78,0x71110001, ++0xc78,0x70120001, ++0xc78,0x6f130001, ++0xc78,0x6e140001, ++0xc78,0x6d150001, ++0xc78,0x6c160001, ++0xc78,0x6b170001, ++0xc78,0x6a180001, ++0xc78,0x69190001, ++0xc78,0x681a0001, ++0xc78,0x671b0001, ++0xc78,0x661c0001, ++0xc78,0x651d0001, ++0xc78,0x641e0001, ++0xc78,0x491f0001, ++0xc78,0x48200001, ++0xc78,0x47210001, ++0xc78,0x46220001, ++0xc78,0x45230001, ++0xc78,0x44240001, ++0xc78,0x43250001, ++0xc78,0x28260001, ++0xc78,0x27270001, ++0xc78,0x26280001, ++0xc78,0x25290001, ++0xc78,0x242a0001, ++0xc78,0x232b0001, ++0xc78,0x222c0001, ++0xc78,0x212d0001, ++0xc78,0x202e0001, ++0xc78,0x0a2f0001, ++0xc78,0x08300001, ++0xc78,0x06310001, ++0xc78,0x05320001, ++0xc78,0x04330001, ++0xc78,0x03340001, ++0xc78,0x02350001, ++0xc78,0x01360001, ++0xc78,0x00370001, ++0xc78,0x00380001, ++0xc78,0x00390001, ++0xc78,0x003a0001, ++0xc78,0x003b0001, ++0xc78,0x003c0001, ++0xc78,0x003d0001, ++0xc78,0x003e0001, ++0xc78,0x003f0001, ++0xc78,0x7d400001, ++0xc78,0x7d410001, ++0xc78,0x7d420001, ++0xc78,0x7d430001, ++0xc78,0x7d440001, ++0xc78,0x7d450001, ++0xc78,0x7c460001, ++0xc78,0x7b470001, ++0xc78,0x7a480001, ++0xc78,0x79490001, ++0xc78,0x784a0001, ++0xc78,0x774b0001, ++0xc78,0x764c0001, ++0xc78,0x754d0001, ++0xc78,0x744e0001, ++0xc78,0x734f0001, ++0xc78,0x72500001, ++0xc78,0x71510001, ++0xc78,0x70520001, ++0xc78,0x6f530001, ++0xc78,0x6e540001, ++0xc78,0x6d550001, ++0xc78,0x6c560001, ++0xc78,0x6b570001, ++0xc78,0x6a580001, ++0xc78,0x69590001, ++0xc78,0x685a0001, ++0xc78,0x675b0001, ++0xc78,0x665c0001, ++0xc78,0x655d0001, ++0xc78,0x645e0001, ++0xc78,0x495f0001, ++0xc78,0x48600001, ++0xc78,0x47610001, ++0xc78,0x46620001, ++0xc78,0x45630001, ++0xc78,0x44640001, ++0xc78,0x43650001, ++0xc78,0x28660001, ++0xc78,0x27670001, ++0xc78,0x26680001, ++0xc78,0x25690001, ++0xc78,0x246a0001, ++0xc78,0x236b0001, ++0xc78,0x226c0001, ++0xc78,0x216d0001, ++0xc78,0x206e0001, ++0xc78,0x0a6f0001, ++0xc78,0x08700001, ++0xc78,0x06710001, ++0xc78,0x05720001, ++0xc78,0x04730001, ++0xc78,0x03740001, ++0xc78,0x02750001, ++0xc78,0x01760001, ++0xc78,0x00770001, ++0xc78,0x00780001, ++0xc78,0x00790001, ++0xc78,0x007a0001, ++0xc78,0x007b0001, ++0xc78,0x007c0001, ++0xc78,0x007d0001, ++0xc78,0x007e0001, ++0xc78,0x007f0001, ++0xc78,0x2e00001e, ++0xc78,0x2e01001e, ++0xc78,0x2e02001e, ++0xc78,0x2e03001e, ++0xc78,0x2e04001e, ++0xc78,0x2e05001e, ++0xc78,0x3006001e, ++0xc78,0x3407001e, ++0xc78,0x3908001e, ++0xc78,0x3c09001e, ++0xc78,0x3f0a001e, ++0xc78,0x420b001e, ++0xc78,0x440c001e, ++0xc78,0x450d001e, ++0xc78,0x460e001e, ++0xc78,0x460f001e, ++0xc78,0x4710001e, ++0xc78,0x4811001e, ++0xc78,0x4912001e, ++0xc78,0x4a13001e, ++0xc78,0x4b14001e, ++0xc78,0x4b15001e, ++0xc78,0x4c16001e, ++0xc78,0x4d17001e, ++0xc78,0x4e18001e, ++0xc78,0x4f19001e, ++0xc78,0x4f1a001e, ++0xc78,0x501b001e, ++0xc78,0x511c001e, ++0xc78,0x521d001e, ++0xc78,0x521e001e, ++0xc78,0x531f001e, ++0xc78,0x5320001e, ++0xc78,0x5421001e, ++0xc78,0x5522001e, ++0xc78,0x5523001e, ++0xc78,0x5624001e, ++0xc78,0x5725001e, ++0xc78,0x5726001e, ++0xc78,0x5827001e, ++0xc78,0x5828001e, ++0xc78,0x5929001e, ++0xc78,0x592a001e, ++0xc78,0x5a2b001e, ++0xc78,0x5b2c001e, ++0xc78,0x5c2d001e, ++0xc78,0x5c2e001e, ++0xc78,0x5d2f001e, ++0xc78,0x5e30001e, ++0xc78,0x5f31001e, ++0xc78,0x6032001e, ++0xc78,0x6033001e, ++0xc78,0x6134001e, ++0xc78,0x6235001e, ++0xc78,0x6336001e, ++0xc78,0x6437001e, ++0xc78,0x6438001e, ++0xc78,0x6539001e, ++0xc78,0x663a001e, ++0xc78,0x673b001e, ++0xc78,0x673c001e, ++0xc78,0x683d001e, ++0xc78,0x693e001e, ++0xc78,0x6a3f001e, ++}; ++static u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLength] = { ++0x0, }; ++static u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLength] = { ++0x800,0x00000000, ++0x804,0x00000001, ++0x808,0x0000fc00, ++0x80c,0x0000001c, ++0x810,0x801010aa, ++0x814,0x008514d0, ++0x818,0x00000040, ++0x81c,0x00000000, ++0x820,0x00000004, ++0x824,0x00690000, ++0x828,0x00000004, ++0x82c,0x00e90000, ++0x830,0x00000004, ++0x834,0x00690000, ++0x838,0x00000004, ++0x83c,0x00e90000, ++0x840,0x00000000, ++0x844,0x00000000, ++0x848,0x00000000, ++0x84c,0x00000000, ++0x850,0x00000000, ++0x854,0x00000000, ++0x858,0x65a965a9, ++0x85c,0x65a965a9, ++0x860,0x001f0010, ++0x864,0x007f0010, ++0x868,0x001f0010, ++0x86c,0x007f0010, ++0x870,0x0f100f70, ++0x874,0x0f100f70, ++0x878,0x00000000, ++0x87c,0x00000000, ++0x880,0x6870e36c, ++0x884,0xe3573600, ++0x888,0x4260c340, ++0x88c,0x0000ff00, ++0x890,0x00000000, ++0x894,0xfffffffe, ++0x898,0x4c42382f, ++0x89c,0x00656056, ++0x8b0,0x00000000, ++0x8e0,0x00000000, ++0x8e4,0x00000000, ++0x900,0x00000000, ++0x904,0x00000023, ++0x908,0x00000000, ++0x90c,0x31121311, ++0xa00,0x00d0c7d8, ++0xa04,0x811f0008, ++0xa08,0x80cd8300, ++0xa0c,0x2e62740f, ++0xa10,0x95009b78, ++0xa14,0x11145008, ++0xa18,0x00881117, ++0xa1c,0x89140fa0, ++0xa20,0x1a1b0000, ++0xa24,0x090e1317, ++0xa28,0x00000204, ++0xa2c,0x00000000, ++0xc00,0x00000040, ++0xc04,0x00005433, ++0xc08,0x000000e4, ++0xc0c,0x6c6c6c6c, ++0xc10,0x08800000, ++0xc14,0x40000100, ++0xc18,0x08000000, ++0xc1c,0x40000100, ++0xc20,0x08000000, ++0xc24,0x40000100, ++0xc28,0x08000000, ++0xc2c,0x40000100, ++0xc30,0x6de9ac44, ++0xc34,0x465c52cd, ++0xc38,0x497f5994, ++0xc3c,0x0a969764, ++0xc40,0x1f7c403f, ++0xc44,0x000100b7, ++0xc48,0xec020000, ++0xc4c,0x00000300, ++0xc50,0x69543420, ++0xc54,0x433c0094, ++0xc58,0x69543420, ++0xc5c,0x433c0094, ++0xc60,0x69543420, ++0xc64,0x433c0094, ++0xc68,0x69543420, ++0xc6c,0x433c0094, ++0xc70,0x2c7f000d, ++0xc74,0x0186175b, ++0xc78,0x0000001f, ++0xc7c,0x00b91612, ++0xc80,0x40000100, ++0xc84,0x20000000, ++0xc88,0x40000100, ++0xc8c,0x20200000, ++0xc90,0x40000100, ++0xc94,0x00000000, ++0xc98,0x40000100, ++0xc9c,0x00000000, ++0xca0,0x00492492, ++0xca4,0x00000000, ++0xca8,0x00000000, ++0xcac,0x00000000, ++0xcb0,0x00000000, ++0xcb4,0x00000000, ++0xcb8,0x00000000, ++0xcbc,0x00492492, ++0xcc0,0x00000000, ++0xcc4,0x00000000, ++0xcc8,0x00000000, ++0xccc,0x00000000, ++0xcd0,0x00000000, ++0xcd4,0x00000000, ++0xcd8,0x64b22427, ++0xcdc,0x00766932, ++0xce0,0x00222222, ++0xd00,0x00000750, ++0xd04,0x00000403, ++0xd08,0x0000907f, ++0xd0c,0x00000001, ++0xd10,0xa0633333, ++0xd14,0x33333c63, ++0xd18,0x6a8f5b6b, ++0xd1c,0x00000000, ++0xd20,0x00000000, ++0xd24,0x00000000, ++0xd28,0x00000000, ++0xd2c,0xcc979975, ++0xd30,0x00000000, ++0xd34,0x00000000, ++0xd38,0x00000000, ++0xd3c,0x00027293, ++0xd40,0x00000000, ++0xd44,0x00000000, ++0xd48,0x00000000, ++0xd4c,0x00000000, ++0xd50,0x6437140a, ++0xd54,0x024dbd02, ++0xd58,0x00000000, ++0xd5c,0x04032064, ++0xe00,0x161a1a1a, ++0xe04,0x12121416, ++0xe08,0x00001800, ++0xe0c,0x00000000, ++0xe10,0x161a1a1a, ++0xe14,0x12121416, ++0xe18,0x161a1a1a, ++0xe1c,0x12121416, ++}; ++static u32 Rtl8192PciERadioA_Array[RadioA_ArrayLength] = { ++0x019,0x00000003, ++0x000,0x000000bf, ++0x001,0x00000ee0, ++0x002,0x0000004c, ++0x003,0x000007f1, ++0x004,0x00000975, ++0x005,0x00000c58, ++0x006,0x00000ae6, ++0x007,0x000000ca, ++0x008,0x00000e1c, ++0x009,0x000007f0, ++0x00a,0x000009d0, ++0x00b,0x000001ba, ++0x00c,0x00000240, ++0x00e,0x00000020, ++0x00f,0x00000990, ++0x012,0x00000806, ++0x014,0x000005ab, ++0x015,0x00000f80, ++0x016,0x00000020, ++0x017,0x00000597, ++0x018,0x0000050a, ++0x01a,0x00000f80, ++0x01b,0x00000f5e, ++0x01c,0x00000008, ++0x01d,0x00000607, ++0x01e,0x000006cc, ++0x01f,0x00000000, ++0x020,0x000001a5, ++0x01f,0x00000001, ++0x020,0x00000165, ++0x01f,0x00000002, ++0x020,0x000000c6, ++0x01f,0x00000003, ++0x020,0x00000086, ++0x01f,0x00000004, ++0x020,0x00000046, ++0x01f,0x00000005, ++0x020,0x000001e6, ++0x01f,0x00000006, ++0x020,0x000001a6, ++0x01f,0x00000007, ++0x020,0x00000166, ++0x01f,0x00000008, ++0x020,0x000000c7, ++0x01f,0x00000009, ++0x020,0x00000087, ++0x01f,0x0000000a, ++0x020,0x000000f7, ++0x01f,0x0000000b, ++0x020,0x000000d7, ++0x01f,0x0000000c, ++0x020,0x000000b7, ++0x01f,0x0000000d, ++0x020,0x00000097, ++0x01f,0x0000000e, ++0x020,0x00000077, ++0x01f,0x0000000f, ++0x020,0x00000057, ++0x01f,0x00000010, ++0x020,0x00000037, ++0x01f,0x00000011, ++0x020,0x000000fb, ++0x01f,0x00000012, ++0x020,0x000000db, ++0x01f,0x00000013, ++0x020,0x000000bb, ++0x01f,0x00000014, ++0x020,0x000000ff, ++0x01f,0x00000015, ++0x020,0x000000e3, ++0x01f,0x00000016, ++0x020,0x000000c3, ++0x01f,0x00000017, ++0x020,0x000000a3, ++0x01f,0x00000018, ++0x020,0x00000083, ++0x01f,0x00000019, ++0x020,0x00000063, ++0x01f,0x0000001a, ++0x020,0x00000043, ++0x01f,0x0000001b, ++0x020,0x00000023, ++0x01f,0x0000001c, ++0x020,0x00000003, ++0x01f,0x0000001d, ++0x020,0x000001e3, ++0x01f,0x0000001e, ++0x020,0x000001c3, ++0x01f,0x0000001f, ++0x020,0x000001a3, ++0x01f,0x00000020, ++0x020,0x00000183, ++0x01f,0x00000021, ++0x020,0x00000163, ++0x01f,0x00000022, ++0x020,0x00000143, ++0x01f,0x00000023, ++0x020,0x00000123, ++0x01f,0x00000024, ++0x020,0x00000103, ++0x023,0x00000203, ++0x024,0x00000100, ++0x00b,0x000001ba, ++0x02c,0x000003d7, ++0x02d,0x00000ff0, ++0x000,0x00000037, ++0x004,0x00000160, ++0x007,0x00000080, ++0x002,0x0000088d, ++0x0fe,0x00000000, ++0x0fe,0x00000000, ++0x016,0x00000200, ++0x016,0x00000380, ++0x016,0x00000020, ++0x016,0x000001a0, ++0x000,0x000000bf, ++0x00d,0x0000001f, ++0x00d,0x00000c9f, ++0x002,0x0000004d, ++0x000,0x00000cbf, ++0x004,0x00000975, ++0x007,0x00000700, ++}; ++static u32 Rtl8192PciERadioB_Array[RadioB_ArrayLength] = { ++0x019,0x00000003, ++0x000,0x000000bf, ++0x001,0x000006e0, ++0x002,0x0000004c, ++0x003,0x000007f1, ++0x004,0x00000975, ++0x005,0x00000c58, ++0x006,0x00000ae6, ++0x007,0x000000ca, ++0x008,0x00000e1c, ++0x000,0x000000b7, ++0x00a,0x00000850, ++0x000,0x000000bf, ++0x00b,0x000001ba, ++0x00c,0x00000240, ++0x00e,0x00000020, ++0x015,0x00000f80, ++0x016,0x00000020, ++0x017,0x00000597, ++0x018,0x0000050a, ++0x01a,0x00000e00, ++0x01b,0x00000f5e, ++0x01d,0x00000607, ++0x01e,0x000006cc, ++0x00b,0x000001ba, ++0x023,0x00000203, ++0x024,0x00000100, ++0x000,0x00000037, ++0x004,0x00000160, ++0x016,0x00000200, ++0x016,0x00000380, ++0x016,0x00000020, ++0x016,0x000001a0, ++0x00d,0x00000ccc, ++0x000,0x000000bf, ++0x002,0x0000004d, ++0x000,0x00000cbf, ++0x004,0x00000975, ++0x007,0x00000700, ++}; ++static u32 Rtl8192PciERadioC_Array[RadioC_ArrayLength] = { ++0x0, }; ++static u32 Rtl8192PciERadioD_Array[RadioD_ArrayLength] = { ++0x0, }; ++#endif ++ ++/*************************Define local function prototype**********************/ ++ ++static u32 phy_FwRFSerialRead(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 Offset); ++static void phy_FwRFSerialWrite(struct net_device* dev,RF90_RADIO_PATH_E eRFPath,u32 Offset,u32 Data); ++/*************************Define local function prototype**********************/ ++/****************************************************************************** ++ *function: This function read BB parameters from Header file we gen, ++ * and do register read/write ++ * input: u32 dwBitMask //taget bit pos in the addr to be modified ++ * output: none ++ * return: u32 return the shift bit bit position of the mask ++ * ****************************************************************************/ ++static u32 rtl8192_CalculateBitShift(u32 dwBitMask) ++{ ++ u32 i; ++ for (i=0; i<=31; i++) ++ { ++ if (((dwBitMask>>i)&0x1) == 1) ++ break; ++ } ++ return i; ++} ++/****************************************************************************** ++ *function: This function check different RF type to execute legal judgement. If RF Path is illegal, we will return false. ++ * input: none ++ * output: none ++ * return: 0(illegal, false), 1(legal,true) ++ * ***************************************************************************/ ++u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath) ++{ ++ u8 ret = 1; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#ifdef RTL8190P ++ if(priv->rf_type == RF_2T4R) ++ { ++ ret= 1; ++ } ++ else if (priv->rf_type == RF_1T2R) ++ { ++ if(eRFPath == RF90_PATH_A || eRFPath == RF90_PATH_B) ++ ret = 0; ++ else if(eRFPath == RF90_PATH_C || eRFPath == RF90_PATH_D) ++ ret = 1; ++ } ++#else ++ #ifdef RTL8192E ++ if (priv->rf_type == RF_2T4R) ++ ret = 0; ++ else if (priv->rf_type == RF_1T2R) ++ { ++ if (eRFPath == RF90_PATH_A || eRFPath == RF90_PATH_B) ++ ret = 1; ++ else if (eRFPath == RF90_PATH_C || eRFPath == RF90_PATH_D) ++ ret = 0; ++ } ++ #endif ++#endif ++ return ret; ++} ++/****************************************************************************** ++ *function: This function set specific bits to BB register ++ * input: net_device dev ++ * u32 dwRegAddr //target addr to be modified ++ * u32 dwBitMask //taget bit pos in the addr to be modified ++ * u32 dwData //value to be write ++ * output: none ++ * return: none ++ * notice: ++ * ****************************************************************************/ ++void rtl8192_setBBreg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData) ++{ ++ ++ u32 OriginalValue, BitShift, NewValue; ++ ++ if(dwBitMask!= bMaskDWord) ++ {//if not "double word" write ++ OriginalValue = read_nic_dword(dev, dwRegAddr); ++ BitShift = rtl8192_CalculateBitShift(dwBitMask); ++ NewValue = (((OriginalValue) & (~dwBitMask)) | (dwData << BitShift)); ++ write_nic_dword(dev, dwRegAddr, NewValue); ++ }else ++ write_nic_dword(dev, dwRegAddr, dwData); ++ return; ++} ++/****************************************************************************** ++ *function: This function reads specific bits from BB register ++ * input: net_device dev ++ * u32 dwRegAddr //target addr to be readback ++ * u32 dwBitMask //taget bit pos in the addr to be readback ++ * output: none ++ * return: u32 Data //the readback register value ++ * notice: ++ * ****************************************************************************/ ++u32 rtl8192_QueryBBReg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask) ++{ ++ u32 Ret = 0, OriginalValue, BitShift; ++ ++ OriginalValue = read_nic_dword(dev, dwRegAddr); ++ BitShift = rtl8192_CalculateBitShift(dwBitMask); ++ Ret = (OriginalValue & dwBitMask) >> BitShift; ++ ++ return (Ret); ++} ++/****************************************************************************** ++ *function: This function read register from RF chip ++ * input: net_device dev ++ * RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D ++ * u32 Offset //target address to be read ++ * output: none ++ * return: u32 readback value ++ * notice: There are three types of serial operations:(1) Software serial write.(2)Hardware LSSI-Low Speed Serial Interface.(3)Hardware HSSI-High speed serial write. Driver here need to implement (1) and (2)---need more spec for this information. ++ * ****************************************************************************/ ++static u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 ret = 0; ++ u32 NewOffset = 0; ++ BB_REGISTER_DEFINITION_T* pPhyReg = &priv->PHYRegDef[eRFPath]; ++ //rtl8192_setBBreg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData, 0); ++ //make sure RF register offset is correct ++ Offset &= 0x3f; ++ ++ //switch page for 8256 RF IC ++ if (priv->rf_chip == RF_8256) ++ { ++#ifdef RTL8190P ++ //analog to digital off, for protection ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] ++#else ++ #ifdef RTL8192E ++ //analog to digital off, for protection ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] ++ #endif ++#endif ++ if (Offset >= 31) ++ { ++ priv->RfReg0Value[eRFPath] |= 0x140; ++ //Switch to Reg_Mode2 for Reg 31-45 ++ rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16) ); ++ //modify offset ++ NewOffset = Offset -30; ++ } ++ else if (Offset >= 16) ++ { ++ priv->RfReg0Value[eRFPath] |= 0x100; ++ priv->RfReg0Value[eRFPath] &= (~0x40); ++ //Switch to Reg_Mode 1 for Reg16-30 ++ rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16) ); ++ ++ NewOffset = Offset - 15; ++ } ++ else ++ NewOffset = Offset; ++ } ++ else ++ { ++ RT_TRACE((COMP_PHY|COMP_ERR), "check RF type here, need to be 8256\n"); ++ NewOffset = Offset; ++ } ++ //put desired read addr to LSSI control Register ++ rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress, NewOffset); ++ //Issue a posedge trigger ++ // ++ rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); ++ rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); ++ ++ ++ // TODO: we should not delay such a long time. Ask help from SD3 ++ msleep(1); ++ ++ ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); ++ ++ ++ // Switch back to Reg_Mode0; ++ if(priv->rf_chip == RF_8256) ++ { ++ priv->RfReg0Value[eRFPath] &= 0xebf; ++ ++ rtl8192_setBBreg( ++ dev, ++ pPhyReg->rf3wireOffset, ++ bMaskDWord, ++ (priv->RfReg0Value[eRFPath] << 16)); ++ ++#ifdef RTL8190P ++ if(priv->rf_type == RF_2T4R) ++ { ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0xf);// 0x88c[11:8] ++ } ++ else if(priv->rf_type == RF_1T2R) ++ { ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xc00, 0x3);// 0x88c[11:10] ++ } ++#else ++ #ifdef RTL8192E ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8] ++ #endif ++#endif ++ } ++ ++ ++ return ret; ++ ++} ++ ++/****************************************************************************** ++ *function: This function write data to RF register ++ * input: net_device dev ++ * RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D ++ * u32 Offset //target address to be written ++ * u32 Data //The new register data to be written ++ * output: none ++ * return: none ++ * notice: For RF8256 only. ++ =========================================================== ++ *Reg Mode RegCTL[1] RegCTL[0] Note ++ * (Reg00[12]) (Reg00[10]) ++ *=========================================================== ++ *Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) ++ *------------------------------------------------------------------ ++ *Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) ++ *------------------------------------------------------------------ ++ * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) ++ *------------------------------------------------------------------ ++ * ****************************************************************************/ ++static void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 DataAndAddr = 0, NewOffset = 0; ++ BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; ++ ++ Offset &= 0x3f; ++ if (priv->rf_chip == RF_8256) ++ { ++ ++#ifdef RTL8190P ++ //analog to digital off, for protection ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] ++#else ++ #ifdef RTL8192E ++ //analog to digital off, for protection ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8] ++ #endif ++#endif ++ ++ if (Offset >= 31) ++ { ++ priv->RfReg0Value[eRFPath] |= 0x140; ++ rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath] << 16)); ++ NewOffset = Offset - 30; ++ } ++ else if (Offset >= 16) ++ { ++ priv->RfReg0Value[eRFPath] |= 0x100; ++ priv->RfReg0Value[eRFPath] &= (~0x40); ++ rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16)); ++ NewOffset = Offset - 15; ++ } ++ else ++ NewOffset = Offset; ++ } ++ else ++ { ++ RT_TRACE((COMP_PHY|COMP_ERR), "check RF type here, need to be 8256\n"); ++ NewOffset = Offset; ++ } ++ ++ // Put write addr in [5:0] and write data in [31:16] ++ DataAndAddr = (Data<<16) | (NewOffset&0x3f); ++ ++ // Write Operation ++ rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); ++ ++ ++ if(Offset==0x0) ++ priv->RfReg0Value[eRFPath] = Data; ++ ++ // Switch back to Reg_Mode0; ++ if(priv->rf_chip == RF_8256) ++ { ++ if(Offset != 0) ++ { ++ priv->RfReg0Value[eRFPath] &= 0xebf; ++ rtl8192_setBBreg( ++ dev, ++ pPhyReg->rf3wireOffset, ++ bMaskDWord, ++ (priv->RfReg0Value[eRFPath] << 16)); ++ } ++#ifdef RTL8190P ++ if(priv->rf_type == RF_2T4R) ++ { ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0xf);// 0x88c[11:8] ++ } ++ else if(priv->rf_type == RF_1T2R) ++ { ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xc00, 0x3);// 0x88c[11:10] ++ } ++#else ++ #ifdef RTL8192E ++ //analog to digital on ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8] ++ #endif ++#endif ++ } ++ ++ return; ++} ++ ++/****************************************************************************** ++ *function: This function set specific bits to RF register ++ * input: net_device dev ++ * RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D ++ * u32 RegAddr //target addr to be modified ++ * u32 BitMask //taget bit pos in the addr to be modified ++ * u32 Data //value to be write ++ * output: none ++ * return: none ++ * notice: ++ * ****************************************************************************/ ++void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 Original_Value, BitShift, New_Value; ++// u8 time = 0; ++ ++ if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) ++ return; ++#ifdef RTL8192E ++ if(priv->ieee80211->eRFPowerState != eRfOn && !priv->being_init_adapter) ++ return; ++#endif ++ //spin_lock_irqsave(&priv->rf_lock, flags); ++ //down(&priv->rf_sem); ++ ++ RT_TRACE(COMP_PHY, "FW RF CTRL is not ready now\n"); ++ if (priv->Rf_Mode == RF_OP_By_FW) ++ { ++ if (BitMask != bMask12Bits) // RF data is 12 bits only ++ { ++ Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); ++ BitShift = rtl8192_CalculateBitShift(BitMask); ++ New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift)); ++ ++ phy_FwRFSerialWrite(dev, eRFPath, RegAddr, New_Value); ++ }else ++ phy_FwRFSerialWrite(dev, eRFPath, RegAddr, Data); ++ udelay(200); ++ ++ } ++ else ++ { ++ if (BitMask != bMask12Bits) // RF data is 12 bits only ++ { ++ Original_Value = rtl8192_phy_RFSerialRead(dev, eRFPath, RegAddr); ++ BitShift = rtl8192_CalculateBitShift(BitMask); ++ New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift)); ++ ++ rtl8192_phy_RFSerialWrite(dev, eRFPath, RegAddr, New_Value); ++ }else ++ rtl8192_phy_RFSerialWrite(dev, eRFPath, RegAddr, Data); ++ } ++ //spin_unlock_irqrestore(&priv->rf_lock, flags); ++ //up(&priv->rf_sem); ++ return; ++} ++ ++/****************************************************************************** ++ *function: This function reads specific bits from RF register ++ * input: net_device dev ++ * u32 RegAddr //target addr to be readback ++ * u32 BitMask //taget bit pos in the addr to be readback ++ * output: none ++ * return: u32 Data //the readback register value ++ * notice: ++ * ****************************************************************************/ ++u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask) ++{ ++ u32 Original_Value, Readback_Value, BitShift; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) ++ return 0; ++#ifdef RTL8192E ++ if(priv->ieee80211->eRFPowerState != eRfOn && !priv->being_init_adapter) ++ return 0; ++#endif ++ down(&priv->rf_sem); ++ if (priv->Rf_Mode == RF_OP_By_FW) ++ { ++ Original_Value = phy_FwRFSerialRead(dev, eRFPath, RegAddr); ++ udelay(200); ++ } ++ else ++ { ++ Original_Value = rtl8192_phy_RFSerialRead(dev, eRFPath, RegAddr); ++ ++ } ++ BitShift = rtl8192_CalculateBitShift(BitMask); ++ Readback_Value = (Original_Value & BitMask) >> BitShift; ++ up(&priv->rf_sem); ++// udelay(200); ++ return (Readback_Value); ++} ++ ++/****************************************************************************** ++ *function: We support firmware to execute RF-R/W. ++ * input: dev ++ * output: none ++ * return: none ++ * notice: ++ * ***************************************************************************/ ++static u32 phy_FwRFSerialRead( ++ struct net_device* dev, ++ RF90_RADIO_PATH_E eRFPath, ++ u32 Offset ) ++{ ++ u32 retValue = 0; ++ u32 Data = 0; ++ u8 time = 0; ++ //DbgPrint("FW RF CTRL\n\r"); ++ /* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can ++ not execute the scheme in the initial step. Otherwise, RF-R/W will waste ++ much time. This is only for site survey. */ ++ // 1. Read operation need not insert data. bit 0-11 ++ //Data &= bMask12Bits; ++ // 2. Write RF register address. Bit 12-19 ++ Data |= ((Offset&0xFF)<<12); ++ // 3. Write RF path. bit 20-21 ++ Data |= ((eRFPath&0x3)<<20); ++ // 4. Set RF read indicator. bit 22=0 ++ //Data |= 0x00000; ++ // 5. Trigger Fw to operate the command. bit 31 ++ Data |= 0x80000000; ++ // 6. We can not execute read operation if bit 31 is 1. ++ while (read_nic_dword(dev, QPNR)&0x80000000) ++ { ++ // If FW can not finish RF-R/W for more than ?? times. We must reset FW. ++ if (time++ < 100) ++ { ++ //DbgPrint("FW not finish RF-R Time=%d\n\r", time); ++ udelay(10); ++ } ++ else ++ break; ++ } ++ // 7. Execute read operation. ++ write_nic_dword(dev, QPNR, Data); ++ // 8. Check if firmawre send back RF content. ++ while (read_nic_dword(dev, QPNR)&0x80000000) ++ { ++ // If FW can not finish RF-R/W for more than ?? times. We must reset FW. ++ if (time++ < 100) ++ { ++ //DbgPrint("FW not finish RF-W Time=%d\n\r", time); ++ udelay(10); ++ } ++ else ++ return (0); ++ } ++ retValue = read_nic_dword(dev, RF_DATA); ++ ++ return (retValue); ++ ++} /* phy_FwRFSerialRead */ ++ ++/****************************************************************************** ++ *function: We support firmware to execute RF-R/W. ++ * input: dev ++ * output: none ++ * return: none ++ * notice: ++ * ***************************************************************************/ ++static void ++phy_FwRFSerialWrite( ++ struct net_device* dev, ++ RF90_RADIO_PATH_E eRFPath, ++ u32 Offset, ++ u32 Data ) ++{ ++ u8 time = 0; ++ ++ //DbgPrint("N FW RF CTRL RF-%d OF%02x DATA=%03x\n\r", eRFPath, Offset, Data); ++ /* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can ++ not execute the scheme in the initial step. Otherwise, RF-R/W will waste ++ much time. This is only for site survey. */ ++ ++ // 1. Set driver write bit and 12 bit data. bit 0-11 ++ //Data &= bMask12Bits; // Done by uper layer. ++ // 2. Write RF register address. bit 12-19 ++ Data |= ((Offset&0xFF)<<12); ++ // 3. Write RF path. bit 20-21 ++ Data |= ((eRFPath&0x3)<<20); ++ // 4. Set RF write indicator. bit 22=1 ++ Data |= 0x400000; ++ // 5. Trigger Fw to operate the command. bit 31=1 ++ Data |= 0x80000000; ++ ++ // 6. Write operation. We can not write if bit 31 is 1. ++ while (read_nic_dword(dev, QPNR)&0x80000000) ++ { ++ // If FW can not finish RF-R/W for more than ?? times. We must reset FW. ++ if (time++ < 100) ++ { ++ //DbgPrint("FW not finish RF-W Time=%d\n\r", time); ++ udelay(10); ++ } ++ else ++ break; ++ } ++ // 7. No matter check bit. We always force the write. Because FW will ++ // not accept the command. ++ write_nic_dword(dev, QPNR, Data); ++ /* 2007/11/02 MH Acoording to test, we must delay 20us to wait firmware ++ to finish RF write operation. */ ++ /* 2008/01/17 MH We support delay in firmware side now. */ ++ //delay_us(20); ++ ++} /* phy_FwRFSerialWrite */ ++ ++ ++/****************************************************************************** ++ *function: This function read BB parameters from Header file we gen, ++ * and do register read/write ++ * input: dev ++ * output: none ++ * return: none ++ * notice: BB parameters may change all the time, so please make ++ * sure it has been synced with the newest. ++ * ***************************************************************************/ ++void rtl8192_phy_configmac(struct net_device* dev) ++{ ++ u32 dwArrayLen = 0, i = 0; ++ u32* pdwArray = NULL; ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#ifdef TO_DO_LIST ++if(Adapter->bInHctTest) ++ { ++ RT_TRACE(COMP_PHY, "Rtl819XMACPHY_ArrayDTM\n"); ++ dwArrayLen = MACPHY_ArrayLengthDTM; ++ pdwArray = Rtl819XMACPHY_ArrayDTM; ++ } ++ else if(priv->bTXPowerDataReadFromEEPORM) ++#endif ++ if(priv->bTXPowerDataReadFromEEPORM) ++ { ++ RT_TRACE(COMP_PHY, "Rtl819XMACPHY_Array_PG\n"); ++ dwArrayLen = MACPHY_Array_PGLength; ++ pdwArray = Rtl819XMACPHY_Array_PG; ++ ++ } ++ else ++ { ++ RT_TRACE(COMP_PHY,"Read rtl819XMACPHY_Array\n"); ++ dwArrayLen = MACPHY_ArrayLength; ++ pdwArray = Rtl819XMACPHY_Array; ++ } ++ for(i = 0; ibInHctTest) ++ { ++ AGCTAB_ArrayLen = AGCTAB_ArrayLengthDTM; ++ Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM; ++ ++ if(priv->RF_Type == RF_2T4R) ++ { ++ PHY_REGArrayLen = PHY_REGArrayLengthDTM; ++ Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArrayDTM; ++ } ++ else if (priv->RF_Type == RF_1T2R) ++ { ++ PHY_REGArrayLen = PHY_REG_1T2RArrayLengthDTM; ++ Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArrayDTM; ++ } ++ } ++ else ++#endif ++ { ++ AGCTAB_ArrayLen = AGCTAB_ArrayLength; ++ Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_Array; ++ if(priv->rf_type == RF_2T4R) ++ { ++ PHY_REGArrayLen = PHY_REGArrayLength; ++ Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArray; ++ } ++ else if (priv->rf_type == RF_1T2R) ++ { ++ PHY_REGArrayLen = PHY_REG_1T2RArrayLength; ++ Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArray; ++ } ++ } ++ ++ if (ConfigType == BaseBand_Config_PHY_REG) ++ { ++ for (i=0; iPHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870 ++ priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) ++ priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874 ++ priv->PHYRegDef[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) ++ ++ // RF Interface Readback Value ++ priv->PHYRegDef[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; // 16 LSBs if read 32-bit from 0x8E0 ++ priv->PHYRegDef[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) ++ priv->PHYRegDef[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 LSBs if read 32-bit from 0x8E4 ++ priv->PHYRegDef[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) ++ ++ // RF Interface Output (and Enable) ++ priv->PHYRegDef[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x860 ++ priv->PHYRegDef[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x864 ++ priv->PHYRegDef[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x868 ++ priv->PHYRegDef[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x86C ++ ++ // RF Interface (Output and) Enable ++ priv->PHYRegDef[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) ++ priv->PHYRegDef[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) ++ priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A) ++ priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E) ++ ++ //Addr of LSSI. Wirte RF register by driver ++ priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter ++ priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; ++ priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter; ++ priv->PHYRegDef[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter; ++ ++ // RF parameter ++ priv->PHYRegDef[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; //BB Band Select ++ priv->PHYRegDef[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; ++ priv->PHYRegDef[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; ++ priv->PHYRegDef[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; ++ ++ // Tx AGC Gain Stage (same for all path. Should we remove this?) ++ priv->PHYRegDef[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ priv->PHYRegDef[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ priv->PHYRegDef[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ priv->PHYRegDef[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage ++ ++ // Tranceiver A~D HSSI Parameter-1 ++ priv->PHYRegDef[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; //wire control parameter1 ++ priv->PHYRegDef[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; //wire control parameter1 ++ priv->PHYRegDef[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1; //wire control parameter1 ++ priv->PHYRegDef[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1; //wire control parameter1 ++ ++ // Tranceiver A~D HSSI Parameter-2 ++ priv->PHYRegDef[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; //wire control parameter2 ++ priv->PHYRegDef[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; //wire control parameter2 ++ priv->PHYRegDef[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2; //wire control parameter2 ++ priv->PHYRegDef[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2; //wire control parameter1 ++ ++ // RF switch Control ++ priv->PHYRegDef[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; //TR/Ant switch control ++ priv->PHYRegDef[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; ++ priv->PHYRegDef[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; ++ priv->PHYRegDef[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; ++ ++ // AGC control 1 ++ priv->PHYRegDef[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; ++ priv->PHYRegDef[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; ++ priv->PHYRegDef[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; ++ priv->PHYRegDef[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; ++ ++ // AGC control 2 ++ priv->PHYRegDef[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; ++ priv->PHYRegDef[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; ++ priv->PHYRegDef[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; ++ priv->PHYRegDef[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; ++ ++ // RX AFE control 1 ++ priv->PHYRegDef[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; ++ priv->PHYRegDef[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; ++ priv->PHYRegDef[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; ++ priv->PHYRegDef[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; ++ ++ // RX AFE control 1 ++ priv->PHYRegDef[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE; ++ priv->PHYRegDef[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; ++ priv->PHYRegDef[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; ++ priv->PHYRegDef[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; ++ ++ // Tx AFE control 1 ++ priv->PHYRegDef[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; ++ priv->PHYRegDef[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; ++ priv->PHYRegDef[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; ++ priv->PHYRegDef[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; ++ ++ // Tx AFE control 2 ++ priv->PHYRegDef[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE; ++ priv->PHYRegDef[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; ++ priv->PHYRegDef[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; ++ priv->PHYRegDef[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; ++ ++ // Tranceiver LSSI Readback ++ priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; ++ priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; ++ priv->PHYRegDef[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; ++ priv->PHYRegDef[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; ++ ++} ++/****************************************************************************** ++ *function: This function is to write register and then readback to make sure whether BB and RF is OK ++ * input: net_device dev ++ * HW90_BLOCK_E CheckBlock ++ * RF90_RADIO_PATH_E eRFPath //only used when checkblock is HW90_BLOCK_RF ++ * output: none ++ * return: return whether BB and RF is ok(0:OK; 1:Fail) ++ * notice: This function may be removed in the ASIC ++ * ***************************************************************************/ ++RT_STATUS rtl8192_phy_checkBBAndRF(struct net_device* dev, HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath) ++{ ++ //struct r8192_priv *priv = ieee80211_priv(dev); ++// BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath]; ++ RT_STATUS ret = RT_STATUS_SUCCESS; ++ u32 i, CheckTimes = 4, dwRegRead = 0; ++ u32 WriteAddr[4]; ++ u32 WriteData[] = {0xfffff027, 0xaa55a02f, 0x00000027, 0x55aa502f}; ++ // Initialize register address offset to be checked ++ WriteAddr[HW90_BLOCK_MAC] = 0x100; ++ WriteAddr[HW90_BLOCK_PHY0] = 0x900; ++ WriteAddr[HW90_BLOCK_PHY1] = 0x800; ++ WriteAddr[HW90_BLOCK_RF] = 0x3; ++ RT_TRACE(COMP_PHY, "=======>%s(), CheckBlock:%d\n", __FUNCTION__, CheckBlock); ++ for(i=0 ; i < CheckTimes ; i++) ++ { ++ ++ // ++ // Write Data to register and readback ++ // ++ switch(CheckBlock) ++ { ++ case HW90_BLOCK_MAC: ++ RT_TRACE(COMP_ERR, "PHY_CheckBBRFOK(): Never Write 0x100 here!"); ++ break; ++ ++ case HW90_BLOCK_PHY0: ++ case HW90_BLOCK_PHY1: ++ write_nic_dword(dev, WriteAddr[CheckBlock], WriteData[i]); ++ dwRegRead = read_nic_dword(dev, WriteAddr[CheckBlock]); ++ break; ++ ++ case HW90_BLOCK_RF: ++ WriteData[i] &= 0xfff; ++ rtl8192_phy_SetRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bMask12Bits, WriteData[i]); ++ // TODO: we should not delay for such a long time. Ask SD3 ++ mdelay(10); ++ dwRegRead = rtl8192_phy_QueryRFReg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], bMaskDWord); ++ mdelay(10); ++ break; ++ ++ default: ++ ret = RT_STATUS_FAILURE; ++ break; ++ } ++ ++ ++ // ++ // Check whether readback data is correct ++ // ++ if(dwRegRead != WriteData[i]) ++ { ++ RT_TRACE(COMP_ERR, "====>error=====dwRegRead: %x, WriteData: %x \n", dwRegRead, WriteData[i]); ++ ret = RT_STATUS_FAILURE; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++ ++/****************************************************************************** ++ *function: This function initialize BB&RF ++ * input: net_device dev ++ * output: none ++ * return: none ++ * notice: Initialization value may change all the time, so please make ++ * sure it has been synced with the newest. ++ * ***************************************************************************/ ++static RT_STATUS rtl8192_BB_Config_ParaFile(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ u8 bRegValue = 0, eCheckItem = 0; ++ u32 dwRegValue = 0; ++ /************************************** ++ //<1>Initialize BaseBand ++ **************************************/ ++ ++ /*--set BB Global Reset--*/ ++ bRegValue = read_nic_byte(dev, BB_GLOBAL_RESET); ++ write_nic_byte(dev, BB_GLOBAL_RESET,(bRegValue|BB_GLOBAL_RESET_BIT)); ++ ++ /*---set BB reset Active---*/ ++ dwRegValue = read_nic_dword(dev, CPU_GEN); ++ write_nic_dword(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); ++ ++ /*----Ckeck FPGAPHY0 and PHY1 board is OK----*/ ++ // TODO: this function should be removed on ASIC , Emily 2007.2.2 ++ for(eCheckItem=(HW90_BLOCK_E)HW90_BLOCK_PHY0; eCheckItem<=HW90_BLOCK_PHY1; eCheckItem++) ++ { ++ rtStatus = rtl8192_phy_checkBBAndRF(dev, (HW90_BLOCK_E)eCheckItem, (RF90_RADIO_PATH_E)0); //don't care RF path ++ if(rtStatus != RT_STATUS_SUCCESS) ++ { ++ RT_TRACE((COMP_ERR | COMP_PHY), "PHY_RF8256_Config():Check PHY%d Fail!!\n", eCheckItem-1); ++ return rtStatus; ++ } ++ } ++ /*---- Set CCK and OFDM Block "OFF"----*/ ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0); ++ /*----BB Register Initilazation----*/ ++ //==m==>Set PHY REG From Header<==m== ++ rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG); ++ ++ /*----Set BB reset de-Active----*/ ++ dwRegValue = read_nic_dword(dev, CPU_GEN); ++ write_nic_dword(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST)); ++ ++ /*----BB AGC table Initialization----*/ ++ //==m==>Set PHY REG From Header<==m== ++ rtl8192_phyConfigBB(dev, BaseBand_Config_AGC_TAB); ++ ++ if (priv->card_8192_version > VERSION_8190_BD) ++ { ++ if(priv->rf_type == RF_2T4R) ++ { ++ // Antenna gain offset from B/C/D to A ++ dwRegValue = ( priv->AntennaTxPwDiff[2]<<8 | ++ priv->AntennaTxPwDiff[1]<<4 | ++ priv->AntennaTxPwDiff[0]); ++ } ++ else ++ dwRegValue = 0x0; //Antenna gain offset doesn't make sense in RF 1T2R. ++ rtl8192_setBBreg(dev, rFPGA0_TxGainStage, ++ (bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue); ++ ++ ++ //XSTALLCap ++#ifdef RTL8190P ++ dwRegValue = priv->CrystalCap & 0x3; // bit0~1 of crystal cap ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bXtalCap01, dwRegValue); ++ dwRegValue = ((priv->CrystalCap & 0xc)>>2); // bit2~3 of crystal cap ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter2, bXtalCap23, dwRegValue); ++#else ++ #ifdef RTL8192E ++ dwRegValue = priv->CrystalCap; ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bXtalCap92x, dwRegValue); ++ #endif ++#endif ++ ++ } ++ ++ // Check if the CCK HighPower is turned ON. ++ // This is used to calculate PWDB. ++// priv->bCckHighPower = (u8)(rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter2, 0x200)); ++ return rtStatus; ++} ++/****************************************************************************** ++ *function: This function initialize BB&RF ++ * input: net_device dev ++ * output: none ++ * return: none ++ * notice: Initialization value may change all the time, so please make ++ * sure it has been synced with the newest. ++ * ***************************************************************************/ ++RT_STATUS rtl8192_BBConfig(struct net_device* dev) ++{ ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ rtl8192_InitBBRFRegDef(dev); ++ //config BB&RF. As hardCode based initialization has not been well ++ //implemented, so use file first.FIXME:should implement it for hardcode? ++ rtStatus = rtl8192_BB_Config_ParaFile(dev); ++ return rtStatus; ++} ++ ++/****************************************************************************** ++ *function: This function obtains the initialization value of Tx power Level offset ++ * input: net_device dev ++ * output: none ++ * return: none ++ * ***************************************************************************/ ++void rtl8192_phy_getTxPower(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#ifdef RTL8190P ++ priv->MCSTxPowerLevelOriginalOffset[0] = ++ read_nic_dword(dev, MCS_TXAGC); ++ priv->MCSTxPowerLevelOriginalOffset[1] = ++ read_nic_dword(dev, (MCS_TXAGC+4)); ++ priv->CCKTxPowerLevelOriginalOffset = ++ read_nic_dword(dev, CCK_TXAGC); ++#else ++ #ifdef RTL8192E ++ priv->MCSTxPowerLevelOriginalOffset[0] = ++ read_nic_dword(dev, rTxAGC_Rate18_06); ++ priv->MCSTxPowerLevelOriginalOffset[1] = ++ read_nic_dword(dev, rTxAGC_Rate54_24); ++ priv->MCSTxPowerLevelOriginalOffset[2] = ++ read_nic_dword(dev, rTxAGC_Mcs03_Mcs00); ++ priv->MCSTxPowerLevelOriginalOffset[3] = ++ read_nic_dword(dev, rTxAGC_Mcs07_Mcs04); ++ priv->MCSTxPowerLevelOriginalOffset[4] = ++ read_nic_dword(dev, rTxAGC_Mcs11_Mcs08); ++ priv->MCSTxPowerLevelOriginalOffset[5] = ++ read_nic_dword(dev, rTxAGC_Mcs15_Mcs12); ++ #endif ++#endif ++ ++ // read rx initial gain ++ priv->DefaultInitialGain[0] = read_nic_byte(dev, rOFDM0_XAAGCCore1); ++ priv->DefaultInitialGain[1] = read_nic_byte(dev, rOFDM0_XBAGCCore1); ++ priv->DefaultInitialGain[2] = read_nic_byte(dev, rOFDM0_XCAGCCore1); ++ priv->DefaultInitialGain[3] = read_nic_byte(dev, rOFDM0_XDAGCCore1); ++ RT_TRACE(COMP_INIT, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x) \n", ++ priv->DefaultInitialGain[0], priv->DefaultInitialGain[1], ++ priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]); ++ ++ // read framesync ++ priv->framesync = read_nic_byte(dev, rOFDM0_RxDetector3); ++ priv->framesyncC34 = read_nic_dword(dev, rOFDM0_RxDetector2); ++ RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x \n", ++ rOFDM0_RxDetector3, priv->framesync); ++ // read SIFS (save the value read fome MACPHY_REG.txt) ++ priv->SifsTime = read_nic_word(dev, SIFS); ++ return; ++} ++ ++/****************************************************************************** ++ *function: This function obtains the initialization value of Tx power Level offset ++ * input: net_device dev ++ * output: none ++ * return: none ++ * ***************************************************************************/ ++void rtl8192_phy_setTxPower(struct net_device* dev, u8 channel) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 powerlevel = 0,powerlevelOFDM24G = 0; ++ char ant_pwr_diff; ++ u32 u4RegValue; ++ ++ if(priv->epromtype == EPROM_93c46) ++ { ++ powerlevel = priv->TxPowerLevelCCK[channel-1]; ++ powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1]; ++ } ++ else if(priv->epromtype == EPROM_93c56) ++ { ++ if(priv->rf_type == RF_1T2R) ++ { ++ powerlevel = priv->TxPowerLevelCCK_C[channel-1]; ++ powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_C[channel-1]; ++ } ++ else if(priv->rf_type == RF_2T4R) ++ { ++ // Mainly we use RF-A Tx Power to write the Tx Power registers, but the RF-C Tx ++ // Power must be calculated by the antenna diff. ++ // So we have to rewrite Antenna gain offset register here. ++ powerlevel = priv->TxPowerLevelCCK_A[channel-1]; ++ powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_A[channel-1]; ++ ++ ant_pwr_diff = priv->TxPowerLevelOFDM24G_C[channel-1] ++ -priv->TxPowerLevelOFDM24G_A[channel-1]; ++ ant_pwr_diff &= 0xf; ++ //DbgPrint(" ant_pwr_diff = 0x%x", (u8)(ant_pwr_diff)); ++ priv->RF_C_TxPwDiff = ant_pwr_diff; ++ ++ priv->AntennaTxPwDiff[2] = 0;// RF-D, don't care ++ priv->AntennaTxPwDiff[1] = (u8)(ant_pwr_diff);// RF-C ++ priv->AntennaTxPwDiff[0] = 0;// RF-B, don't care ++ ++ // Antenna gain offset from B/C/D to A ++ u4RegValue = ( priv->AntennaTxPwDiff[2]<<8 | ++ priv->AntennaTxPwDiff[1]<<4 | ++ priv->AntennaTxPwDiff[0]); ++ ++ rtl8192_setBBreg(dev, rFPGA0_TxGainStage, ++ (bXBTxAGC|bXCTxAGC|bXDTxAGC), u4RegValue); ++ } ++ } ++#ifdef TODO ++ // ++ // CCX 2 S31, AP control of client transmit power: ++ // 1. We shall not exceed Cell Power Limit as possible as we can. ++ // 2. Tolerance is +/- 5dB. ++ // 3. 802.11h Power Contraint takes higher precedence over CCX Cell Power Limit. ++ // ++ // TODO: ++ // 1. 802.11h power contraint ++ // ++ // 071011, by rcnjko. ++ // ++ if( pMgntInfo->OpMode == RT_OP_MODE_INFRASTRUCTURE && ++ pMgntInfo->bWithCcxCellPwr && ++ channel == pMgntInfo->dot11CurrentChannelNumber) ++ { ++ u8 CckCellPwrIdx = DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, pMgntInfo->CcxCellPwr); ++ u8 LegacyOfdmCellPwrIdx = DbmToTxPwrIdx(Adapter, WIRELESS_MODE_G, pMgntInfo->CcxCellPwr); ++ u8 OfdmCellPwrIdx = DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, pMgntInfo->CcxCellPwr); ++ ++ RT_TRACE(COMP_TXAGC, DBG_LOUD, ++ ("CCX Cell Limit: %d dbm => CCK Tx power index : %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n", ++ pMgntInfo->CcxCellPwr, CckCellPwrIdx, LegacyOfdmCellPwrIdx, OfdmCellPwrIdx)); ++ RT_TRACE(COMP_TXAGC, DBG_LOUD, ++ ("EEPROM channel(%d) => CCK Tx power index: %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n", ++ channel, powerlevel, powerlevelOFDM24G + pHalData->LegacyHTTxPowerDiff, powerlevelOFDM24G)); ++ ++ // CCK ++ if(powerlevel > CckCellPwrIdx) ++ powerlevel = CckCellPwrIdx; ++ // Legacy OFDM, HT OFDM ++ if(powerlevelOFDM24G + pHalData->LegacyHTTxPowerDiff > OfdmCellPwrIdx) ++ { ++ if((OfdmCellPwrIdx - pHalData->LegacyHTTxPowerDiff) > 0) ++ { ++ powerlevelOFDM24G = OfdmCellPwrIdx - pHalData->LegacyHTTxPowerDiff; ++ } ++ else ++ { ++ LegacyOfdmCellPwrIdx = 0; ++ } ++ } ++ ++ RT_TRACE(COMP_TXAGC, DBG_LOUD, ++ ("Altered CCK Tx power index : %d, Legacy OFDM Tx power index: %d, OFDM Tx power index: %d\n", ++ powerlevel, powerlevelOFDM24G + pHalData->LegacyHTTxPowerDiff, powerlevelOFDM24G)); ++ } ++ ++ pHalData->CurrentCckTxPwrIdx = powerlevel; ++ pHalData->CurrentOfdm24GTxPwrIdx = powerlevelOFDM24G; ++#endif ++ switch(priv->rf_chip) ++ { ++ case RF_8225: ++ // PHY_SetRF8225CckTxPower(Adapter, powerlevel); ++ // PHY_SetRF8225OfdmTxPower(Adapter, powerlevelOFDM24G); ++ break; ++ case RF_8256: ++ PHY_SetRF8256CCKTxPower(dev, powerlevel); //need further implement ++ PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); ++ break; ++ case RF_8258: ++ break; ++ default: ++ RT_TRACE(COMP_ERR, "unknown rf chip in funtion %s()\n", __FUNCTION__); ++ break; ++ } ++ return; ++} ++ ++/****************************************************************************** ++ *function: This function check Rf chip to do RF config ++ * input: net_device dev ++ * output: none ++ * return: only 8256 is supported ++ * ***************************************************************************/ ++RT_STATUS rtl8192_phy_RFConfig(struct net_device* dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RT_STATUS rtStatus = RT_STATUS_SUCCESS; ++ switch(priv->rf_chip) ++ { ++ case RF_8225: ++// rtStatus = PHY_RF8225_Config(Adapter); ++ break; ++ case RF_8256: ++ rtStatus = PHY_RF8256_Config(dev); ++ break; ++ ++ case RF_8258: ++ break; ++ case RF_PSEUDO_11N: ++ //rtStatus = PHY_RF8225_Config(Adapter); ++ break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "error chip id\n"); ++ break; ++ } ++ return rtStatus; ++} ++ ++/****************************************************************************** ++ *function: This function update Initial gain ++ * input: net_device dev ++ * output: none ++ * return: As Windows has not implemented this, wait for complement ++ * ***************************************************************************/ ++void rtl8192_phy_updateInitGain(struct net_device* dev) ++{ ++ return; ++} ++ ++/****************************************************************************** ++ *function: This function read RF parameters from general head file, and do RF 3-wire ++ * input: net_device dev ++ * output: none ++ * return: return code show if RF configuration is successful(0:pass, 1:fail) ++ * Note: Delay may be required for RF configuration ++ * ***************************************************************************/ ++u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E eRFPath) ++{ ++ ++ int i; ++ //u32* pRFArray; ++ u8 ret = 0; ++ ++ switch(eRFPath){ ++ case RF90_PATH_A: ++ for(i = 0;iTxPowerLevelCCK[channel-1]; ++ u8 powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1]; ++ ++ switch(priv->rf_chip) ++ { ++ case RF_8225: ++#ifdef TO_DO_LIST ++ PHY_SetRF8225CckTxPower(Adapter, powerlevel); ++ PHY_SetRF8225OfdmTxPower(Adapter, powerlevelOFDM24G); ++#endif ++ break; ++ ++ case RF_8256: ++ PHY_SetRF8256CCKTxPower(dev, powerlevel); ++ PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); ++ break; ++ ++ case RF_8258: ++ break; ++ default: ++ RT_TRACE(COMP_ERR, "unknown rf chip ID in rtl8192_SetTxPowerLevel()\n"); ++ break; ++ } ++ return; ++} ++/**************************************************************************************** ++ *function: This function set command table variable(struct SwChnlCmd). ++ * input: SwChnlCmd* CmdTable //table to be set. ++ * u32 CmdTableIdx //variable index in table to be set ++ * u32 CmdTableSz //table size. ++ * SwChnlCmdID CmdID //command ID to set. ++ * u32 Para1 ++ * u32 Para2 ++ * u32 msDelay ++ * output: ++ * return: true if finished, false otherwise ++ * Note: ++ * ************************************************************************************/ ++static u8 rtl8192_phy_SetSwChnlCmdArray( ++ SwChnlCmd* CmdTable, ++ u32 CmdTableIdx, ++ u32 CmdTableSz, ++ SwChnlCmdID CmdID, ++ u32 Para1, ++ u32 Para2, ++ u32 msDelay ++ ) ++{ ++ SwChnlCmd* pCmd; ++ ++ if(CmdTable == NULL) ++ { ++ RT_TRACE(COMP_ERR, "phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n"); ++ return false; ++ } ++ if(CmdTableIdx >= CmdTableSz) ++ { ++ RT_TRACE(COMP_ERR, "phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%d, CmdTableSz:%d\n", ++ CmdTableIdx, CmdTableSz); ++ return false; ++ } ++ ++ pCmd = CmdTable + CmdTableIdx; ++ pCmd->CmdID = CmdID; ++ pCmd->Para1 = Para1; ++ pCmd->Para2 = Para2; ++ pCmd->msDelay = msDelay; ++ ++ return true; ++} ++/****************************************************************************** ++ *function: This function set channel step by step ++ * input: struct net_device *dev ++ * u8 channel ++ * u8* stage //3 stages ++ * u8* step // ++ * u32* delay //whether need to delay ++ * output: store new stage, step and delay for next step(combine with function above) ++ * return: true if finished, false otherwise ++ * Note: Wait for simpler function to replace it //wb ++ * ***************************************************************************/ ++static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u8* step, u32* delay) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++// PCHANNEL_ACCESS_SETTING pChnlAccessSetting; ++ SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT]; ++ u32 PreCommonCmdCnt; ++ SwChnlCmd PostCommonCmd[MAX_POSTCMD_CNT]; ++ u32 PostCommonCmdCnt; ++ SwChnlCmd RfDependCmd[MAX_RFDEPENDCMD_CNT]; ++ u32 RfDependCmdCnt; ++ SwChnlCmd *CurrentCmd = NULL; ++ //RF90_RADIO_PATH_E eRFPath; ++ u8 eRFPath; ++// u32 RfRetVal; ++// u8 RetryCnt; ++ ++ RT_TRACE(COMP_TRACE, "====>%s()====stage:%d, step:%d, channel:%d\n", __FUNCTION__, *stage, *step, channel); ++// RT_ASSERT(IsLegalChannel(Adapter, channel), ("illegal channel: %d\n", channel)); ++ ++#ifdef ENABLE_DOT11D ++ if (!IsLegalChannel(priv->ieee80211, channel)) ++ { ++ RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel); ++ return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop. ++ } ++#endif ++ ++ //for(eRFPath = RF90_PATH_A; eRFPath NumTotalRFPath; eRFPath++) ++ //for(eRFPath = 0; eRFPath Fill up pre common command. ++ PreCommonCmdCnt = 0; ++ rtl8192_phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, ++ CmdID_SetTxPowerLevel, 0, 0, 0); ++ rtl8192_phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT, ++ CmdID_End, 0, 0, 0); ++ ++ // <2> Fill up post common command. ++ PostCommonCmdCnt = 0; ++ ++ rtl8192_phy_SetSwChnlCmdArray(PostCommonCmd, PostCommonCmdCnt++, MAX_POSTCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ ++ // <3> Fill up RF dependent command. ++ RfDependCmdCnt = 0; ++ switch( priv->rf_chip ) ++ { ++ case RF_8225: ++ if (!(channel >= 1 && channel <= 14)) ++ { ++ RT_TRACE(COMP_ERR, "illegal channel for Zebra 8225: %d\n", channel); ++ return false; ++ } ++ rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_RF_WriteReg, rZebra1_Channel, RF_CHANNEL_TABLE_ZEBRA[channel], 10); ++ rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ break; ++ ++ case RF_8256: ++ // TEST!! This is not the table for 8256!! ++ if (!(channel >= 1 && channel <= 14)) ++ { ++ RT_TRACE(COMP_ERR, "illegal channel for Zebra 8256: %d\n", channel); ++ return false; ++ } ++ rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_RF_WriteReg, rZebra1_Channel, channel, 10); ++ rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT, ++ CmdID_End, 0, 0, 0); ++ break; ++ ++ case RF_8258: ++ break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", priv->rf_chip); ++ return false; ++ break; ++ } ++ ++ ++ do{ ++ switch(*stage) ++ { ++ case 0: ++ CurrentCmd=&PreCommonCmd[*step]; ++ break; ++ case 1: ++ CurrentCmd=&RfDependCmd[*step]; ++ break; ++ case 2: ++ CurrentCmd=&PostCommonCmd[*step]; ++ break; ++ } ++ ++ if(CurrentCmd->CmdID==CmdID_End) ++ { ++ if((*stage)==2) ++ { ++ return true; ++ } ++ else ++ { ++ (*stage)++; ++ (*step)=0; ++ continue; ++ } ++ } ++ ++ switch(CurrentCmd->CmdID) ++ { ++ case CmdID_SetTxPowerLevel: ++ if(priv->card_8192_version > (u8)VERSION_8190_BD) //xiong: consider it later! ++ rtl8192_SetTxPowerLevel(dev,channel); ++ break; ++ case CmdID_WritePortUlong: ++ write_nic_dword(dev, CurrentCmd->Para1, CurrentCmd->Para2); ++ break; ++ case CmdID_WritePortUshort: ++ write_nic_word(dev, CurrentCmd->Para1, (u16)CurrentCmd->Para2); ++ break; ++ case CmdID_WritePortUchar: ++ write_nic_byte(dev, CurrentCmd->Para1, (u8)CurrentCmd->Para2); ++ break; ++ case CmdID_RF_WriteReg: ++ for(eRFPath = 0; eRFPath NumTotalRFPath; eRFPath++) ++ rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, bMask12Bits, CurrentCmd->Para2<<7); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ }while(true); ++ }/*for(Number of RF paths)*/ ++ ++ (*delay)=CurrentCmd->msDelay; ++ (*step)++; ++ return false; ++} ++ ++/****************************************************************************** ++ *function: This function does acturally set channel work ++ * input: struct net_device *dev ++ * u8 channel ++ * output: none ++ * return: noin ++ * Note: We should not call this function directly ++ * ***************************************************************************/ ++static void rtl8192_phy_FinishSwChnlNow(struct net_device *dev, u8 channel) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 delay = 0; ++ ++ while(!rtl8192_phy_SwChnlStepByStep(dev,channel,&priv->SwChnlStage,&priv->SwChnlStep,&delay)) ++ { ++ if(delay>0) ++ msleep(delay);//or mdelay? need further consideration ++ if(!priv->up) ++ break; ++ } ++} ++/****************************************************************************** ++ *function: Callback routine of the work item for switch channel. ++ * input: ++ * ++ * output: none ++ * return: noin ++ * ***************************************************************************/ ++void rtl8192_SwChnl_WorkItem(struct net_device *dev) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ RT_TRACE(COMP_TRACE, "==> SwChnlCallback819xUsbWorkItem()\n"); ++ ++ RT_TRACE(COMP_TRACE, "=====>--%s(), set chan:%d, priv:%p\n", __FUNCTION__, priv->chan, priv); ++ ++ rtl8192_phy_FinishSwChnlNow(dev , priv->chan); ++ ++ RT_TRACE(COMP_TRACE, "<== SwChnlCallback819xUsbWorkItem()\n"); ++} ++ ++/****************************************************************************** ++ *function: This function scheduled actural workitem to set channel ++ * input: net_device dev ++ * u8 channel //channel to set ++ * output: none ++ * return: return code show if workitem is scheduled(1:pass, 0:fail) ++ * Note: Delay may be required for RF configuration ++ * ***************************************************************************/ ++u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ RT_TRACE(COMP_PHY, "=====>%s()\n", __FUNCTION__); ++ if(!priv->up) ++ return false; ++ if(priv->SwChnlInProgress) ++ return false; ++ ++// if(pHalData->SetBWModeInProgress) ++// return; ++ ++ //-------------------------------------------- ++ switch(priv->ieee80211->mode) ++ { ++ case WIRELESS_MODE_A: ++ case WIRELESS_MODE_N_5G: ++ if (channel<=14){ ++ RT_TRACE(COMP_ERR, "WIRELESS_MODE_A but channel<=14"); ++ return false; ++ } ++ break; ++ case WIRELESS_MODE_B: ++ if (channel>14){ ++ RT_TRACE(COMP_ERR, "WIRELESS_MODE_B but channel>14"); ++ return false; ++ } ++ break; ++ case WIRELESS_MODE_G: ++ case WIRELESS_MODE_N_24G: ++ if (channel>14){ ++ RT_TRACE(COMP_ERR, "WIRELESS_MODE_G but channel>14"); ++ return false; ++ } ++ break; ++ } ++ //-------------------------------------------- ++ ++ priv->SwChnlInProgress = true; ++ if(channel == 0) ++ channel = 1; ++ ++ priv->chan=channel; ++ ++ priv->SwChnlStage=0; ++ priv->SwChnlStep=0; ++// schedule_work(&(priv->SwChnlWorkItem)); ++// rtl8192_SwChnl_WorkItem(dev); ++ if(priv->up) { ++// queue_work(priv->priv_wq,&(priv->SwChnlWorkItem)); ++ rtl8192_SwChnl_WorkItem(dev); ++ } ++ priv->SwChnlInProgress = false; ++ return true; ++} ++ ++static void CCK_Tx_Power_Track_BW_Switch_TSSI(struct net_device *dev ) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ switch(priv->CurrentChannelBW) ++ { ++ /* 20 MHz channel*/ ++ case HT_CHANNEL_WIDTH_20: ++ //added by vivi, cck,tx power track, 20080703 ++ priv->CCKPresentAttentuation = ++ priv->CCKPresentAttentuation_20Mdefault + priv->CCKPresentAttentuation_difference; ++ ++ if(priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1)) ++ priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1; ++ if(priv->CCKPresentAttentuation < 0) ++ priv->CCKPresentAttentuation = 0; ++ ++ RT_TRACE(COMP_POWER_TRACKING, "20M, priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation); ++ ++ if(priv->ieee80211->current_network.channel== 14 && !priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = TRUE; ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = FALSE; ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ else ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ break; ++ ++ /* 40 MHz channel*/ ++ case HT_CHANNEL_WIDTH_20_40: ++ //added by vivi, cck,tx power track, 20080703 ++ priv->CCKPresentAttentuation = ++ priv->CCKPresentAttentuation_40Mdefault + priv->CCKPresentAttentuation_difference; ++ ++ RT_TRACE(COMP_POWER_TRACKING, "40M, priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation); ++ if(priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1)) ++ priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1; ++ if(priv->CCKPresentAttentuation < 0) ++ priv->CCKPresentAttentuation = 0; ++ ++ if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = TRUE; ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) ++ { ++ priv->bcck_in_ch14 = FALSE; ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ } ++ else ++ dm_cck_txpower_adjust(dev,priv->bcck_in_ch14); ++ break; ++ } ++} ++ ++#ifndef RTL8190P ++static void CCK_Tx_Power_Track_BW_Switch_ThermalMeter(struct net_device *dev) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) ++ priv->bcck_in_ch14 = TRUE; ++ else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) ++ priv->bcck_in_ch14 = FALSE; ++ ++ //write to default index and tx power track will be done in dm. ++ switch(priv->CurrentChannelBW) ++ { ++ /* 20 MHz channel*/ ++ case HT_CHANNEL_WIDTH_20: ++ if(priv->Record_CCK_20Mindex == 0) ++ priv->Record_CCK_20Mindex = 6; //set default value. ++ priv->CCK_index = priv->Record_CCK_20Mindex;//6; ++ RT_TRACE(COMP_POWER_TRACKING, "20MHz, CCK_Tx_Power_Track_BW_Switch_ThermalMeter(),CCK_index = %d\n", priv->CCK_index); ++ break; ++ ++ /* 40 MHz channel*/ ++ case HT_CHANNEL_WIDTH_20_40: ++ priv->CCK_index = priv->Record_CCK_40Mindex;//0; ++ RT_TRACE(COMP_POWER_TRACKING, "40MHz, CCK_Tx_Power_Track_BW_Switch_ThermalMeter(), CCK_index = %d\n", priv->CCK_index); ++ break; ++ } ++ dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); ++} ++#endif ++ ++static void CCK_Tx_Power_Track_BW_Switch(struct net_device *dev) ++{ ++#ifdef RTL8192E ++ struct r8192_priv *priv = ieee80211_priv(dev); ++#endif ++ ++#ifdef RTL8190P ++ CCK_Tx_Power_Track_BW_Switch_TSSI(dev); ++#else ++ //if(pHalData->bDcut == TRUE) ++ if(priv->IC_Cut >= IC_VersionCut_D) ++ CCK_Tx_Power_Track_BW_Switch_TSSI(dev); ++ else ++ CCK_Tx_Power_Track_BW_Switch_ThermalMeter(dev); ++#endif ++} ++ ++ ++// ++/****************************************************************************** ++ *function: Callback routine of the work item for set bandwidth mode. ++ * input: struct net_device *dev ++ * HT_CHANNEL_WIDTH Bandwidth //20M or 40M ++ * HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care ++ * output: none ++ * return: none ++ * Note: I doubt whether SetBWModeInProgress flag is necessary as we can ++ * test whether current work in the queue or not.//do I? ++ * ***************************************************************************/ ++void rtl8192_SetBWModeWorkItem(struct net_device *dev) ++{ ++ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u8 regBwOpMode; ++ ++ RT_TRACE(COMP_SWBW, "==>rtl8192_SetBWModeWorkItem() Switch to %s bandwidth\n", \ ++ priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz") ++ ++ ++ if(priv->rf_chip== RF_PSEUDO_11N) ++ { ++ priv->SetBWModeInProgress= false; ++ return; ++ } ++ if(!priv->up) ++ { ++ priv->SetBWModeInProgress= false; ++ return; ++ } ++ //<1>Set MAC register ++ regBwOpMode = read_nic_byte(dev, BW_OPMODE); ++ ++ switch(priv->CurrentChannelBW) ++ { ++ case HT_CHANNEL_WIDTH_20: ++ regBwOpMode |= BW_OPMODE_20MHZ; ++ // 2007/02/07 Mark by Emily becasue we have not verify whether this register works ++ write_nic_byte(dev, BW_OPMODE, regBwOpMode); ++ break; ++ ++ case HT_CHANNEL_WIDTH_20_40: ++ regBwOpMode &= ~BW_OPMODE_20MHZ; ++ // 2007/02/07 Mark by Emily becasue we have not verify whether this register works ++ write_nic_byte(dev, BW_OPMODE, regBwOpMode); ++ break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n",priv->CurrentChannelBW); ++ break; ++ } ++ ++ //<2>Set PHY related register ++ switch(priv->CurrentChannelBW) ++ { ++ case HT_CHANNEL_WIDTH_20: ++ // Add by Vivi 20071119 ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); ++ rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); ++// rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); ++ ++ // Correct the tx power for CCK rate in 20M. Suggest by YN, 20071207 ++// write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); ++// write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); ++// write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); ++ if(!priv->btxpower_tracking) ++ { ++ write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); ++ write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); ++ write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); ++ } ++ else ++ CCK_Tx_Power_Track_BW_Switch(dev); ++ ++#ifdef RTL8190P ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bADClkPhase, 1); ++ rtl8192_setBBreg(dev, rOFDM0_RxDetector1, bMaskByte0, 0x44); // 0xc30 is for 8190 only, Emily ++#else ++ #ifdef RTL8192E ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); ++ #endif ++#endif ++ ++ break; ++ case HT_CHANNEL_WIDTH_20_40: ++ // Add by Vivi 20071119 ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); ++ rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); ++ //rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); ++ //rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); ++ //rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); ++ ++ // Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207 ++ //write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); ++ //write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e); ++ //write_nic_dword(dev, rCCK0_DebugPort, 0x00000409); ++ if(!priv->btxpower_tracking) ++ { ++ write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); ++ write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e); ++ write_nic_dword(dev, rCCK0_DebugPort, 0x00000409); ++ } ++ else ++ CCK_Tx_Power_Track_BW_Switch(dev); ++ ++ // Set Control channel to upper or lower. These settings are required only for 40MHz ++ rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1)); ++ rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC); ++ ++ ++#ifdef RTL8190P ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bADClkPhase, 0); ++ rtl8192_setBBreg(dev, rOFDM0_RxDetector1, bMaskByte0, 0x42); // 0xc30 is for 8190 only, Emily ++ ++ // Set whether CCK should be sent in upper or lower channel. Suggest by YN. 20071207 ++ // It is set in Tx descriptor for 8192x series ++ if(priv->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_UPPER) ++ { ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, (BIT6|BIT5), 0x01); ++ }else if(priv->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ++ { ++ rtl8192_setBBreg(dev, rFPGA0_RFMOD, (BIT6|BIT5), 0x02); ++ } ++ ++#else ++ #ifdef RTL8192E ++ rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); ++ #endif ++#endif ++ break; ++ default: ++ RT_TRACE(COMP_ERR, "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n" ,priv->CurrentChannelBW); ++ break; ++ ++ } ++ //Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 ++ ++#if 1 ++ //<3>Set RF related register ++ switch( priv->rf_chip ) ++ { ++ case RF_8225: ++#ifdef TO_DO_LIST ++ PHY_SetRF8225Bandwidth(Adapter, pHalData->CurrentChannelBW); ++#endif ++ break; ++ ++ case RF_8256: ++ PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); ++ break; ++ ++ case RF_8258: ++ // PHY_SetRF8258Bandwidth(); ++ break; ++ ++ case RF_PSEUDO_11N: ++ // Do Nothing ++ break; ++ ++ default: ++ RT_TRACE(COMP_ERR, "Unknown RFChipID: %d\n", priv->rf_chip); ++ break; ++ } ++#endif ++ atomic_dec(&(priv->ieee80211->atm_swbw)); ++ priv->SetBWModeInProgress= false; ++ ++ RT_TRACE(COMP_SWBW, "<==SetBWMode819xUsb()"); ++} ++ ++/****************************************************************************** ++ *function: This function schedules bandwith switch work. ++ * input: struct net_device *dev ++ * HT_CHANNEL_WIDTH Bandwidth //20M or 40M ++ * HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care ++ * output: none ++ * return: none ++ * Note: I doubt whether SetBWModeInProgress flag is necessary as we can ++ * test whether current work in the queue or not.//do I? ++ * ***************************************************************************/ ++void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset) ++{ ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->SetBWModeInProgress) ++ return; ++ ++ atomic_inc(&(priv->ieee80211->atm_swbw)); ++ priv->SetBWModeInProgress= true; ++ ++ priv->CurrentChannelBW = Bandwidth; ++ ++ if(Offset==HT_EXTCHNL_OFFSET_LOWER) ++ priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER; ++ else if(Offset==HT_EXTCHNL_OFFSET_UPPER) ++ priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER; ++ else ++ priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ //queue_work(priv->priv_wq, &(priv->SetBWModeWorkItem)); ++ // schedule_work(&(priv->SetBWModeWorkItem)); ++ rtl8192_SetBWModeWorkItem(dev); ++ ++} ++ ++ ++void InitialGain819xPci(struct net_device *dev, u8 Operation) ++{ ++#define SCAN_RX_INITIAL_GAIN 0x17 ++#define POWER_DETECTION_TH 0x08 ++ struct r8192_priv *priv = ieee80211_priv(dev); ++ u32 BitMask; ++ u8 initial_gain; ++ ++ if(priv->up) ++ { ++ switch(Operation) ++ { ++ case IG_Backup: ++ RT_TRACE(COMP_SCAN, "IG_Backup, backup the initial gain.\n"); ++ initial_gain = SCAN_RX_INITIAL_GAIN;//pHalData->DefaultInitialGain[0];// ++ BitMask = bMaskByte0; ++ if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF ++ priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, BitMask); ++ priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, BitMask); ++ priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, BitMask); ++ priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, BitMask); ++ BitMask = bMaskByte2; ++ priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, BitMask); ++ ++ RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1); ++ RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1); ++ RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1); ++ RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1); ++ RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca); ++ ++ RT_TRACE(COMP_SCAN, "Write scan initial gain = 0x%x \n", initial_gain); ++ write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); ++ write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); ++ write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); ++ write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); ++ RT_TRACE(COMP_SCAN, "Write scan 0xa0a = 0x%x \n", POWER_DETECTION_TH); ++ write_nic_byte(dev, 0xa0a, POWER_DETECTION_TH); ++ break; ++ case IG_Restore: ++ RT_TRACE(COMP_SCAN, "IG_Restore, restore the initial gain.\n"); ++ BitMask = 0x7f; //Bit0~ Bit6 ++ if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // FW DIG OFF ++ ++ rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, BitMask, (u32)priv->initgain_backup.xaagccore1); ++ rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, BitMask, (u32)priv->initgain_backup.xbagccore1); ++ rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, BitMask, (u32)priv->initgain_backup.xcagccore1); ++ rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, BitMask, (u32)priv->initgain_backup.xdagccore1); ++ BitMask = bMaskByte2; ++ rtl8192_setBBreg(dev, rCCK0_CCA, BitMask, (u32)priv->initgain_backup.cca); ++ ++ RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1); ++ RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1); ++ RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1); ++ RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1); ++ RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca); ++ ++ rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel); ++ ++ ++ if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) ++ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // FW DIG ON ++ break; ++ default: ++ RT_TRACE(COMP_SCAN, "Unknown IG Operation. \n"); ++ break; ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_phy.h +@@ -0,0 +1,125 @@ ++#ifndef _R819XU_PHY_H ++#define _R819XU_PHY_H ++/* Channel switch:The size of command tables for switch channel*/ ++#define MAX_PRECMD_CNT 16 ++#define MAX_RFDEPENDCMD_CNT 16 ++#define MAX_POSTCMD_CNT 16 ++ ++#ifdef RTL8190P ++#define MACPHY_Array_PGLength 21 ++#define Rtl819XMACPHY_Array_PG Rtl8190PciMACPHY_Array_PG ++#define Rtl819XMACPHY_Array Rtl8190PciMACPHY_Array ++#define RadioC_ArrayLength 246 ++#define RadioD_ArrayLength 78 ++#define Rtl819XRadioA_Array Rtl8190PciRadioA_Array ++#define Rtl819XRadioB_Array Rtl8190PciRadioB_Array ++#define Rtl819XRadioC_Array Rtl8190PciRadioC_Array ++#define Rtl819XRadioD_Array Rtl8190PciRadioD_Array ++#define Rtl819XAGCTAB_Array Rtl8190PciAGCTAB_Array ++#define PHY_REGArrayLength 280 ++#define Rtl819XPHY_REGArray Rtl8190PciPHY_REGArray ++#define PHY_REG_1T2RArrayLength 280 ++#define Rtl819XPHY_REG_1T2RArray Rtl8190PciPHY_REG_1T2RArray ++#endif ++ ++ #ifdef RTL8192E ++ #define MACPHY_Array_PGLength 30 ++ #define Rtl819XMACPHY_Array_PG Rtl8192PciEMACPHY_Array_PG ++ #define Rtl819XMACPHY_Array Rtl8192PciEMACPHY_Array ++ #define RadioC_ArrayLength 1 ++ #define RadioD_ArrayLength 1 ++ #define Rtl819XRadioA_Array Rtl8192PciERadioA_Array ++ #define Rtl819XRadioB_Array Rtl8192PciERadioB_Array ++ #define Rtl819XRadioC_Array Rtl8192PciERadioC_Array ++ #define Rtl819XRadioD_Array Rtl8192PciERadioD_Array ++ #define Rtl819XAGCTAB_Array Rtl8192PciEAGCTAB_Array ++ #define PHY_REGArrayLength 1 ++ #define Rtl819XPHY_REGArray Rtl8192PciEPHY_REGArray ++ #define PHY_REG_1T2RArrayLength 296 ++ #define Rtl819XPHY_REG_1T2RArray Rtl8192PciEPHY_REG_1T2RArray ++ #endif ++#define AGCTAB_ArrayLength 384 ++#define MACPHY_ArrayLength 18 ++ ++#define RadioA_ArrayLength 246 ++#define RadioB_ArrayLength 78 ++ ++ ++typedef enum _SwChnlCmdID{ ++ CmdID_End, ++ CmdID_SetTxPowerLevel, ++ CmdID_BBRegWrite10, ++ CmdID_WritePortUlong, ++ CmdID_WritePortUshort, ++ CmdID_WritePortUchar, ++ CmdID_RF_WriteReg, ++}SwChnlCmdID; ++ ++/*--------------------------------Define structure--------------------------------*/ ++/* 1. Switch channel related */ ++typedef struct _SwChnlCmd{ ++ SwChnlCmdID CmdID; ++ u32 Para1; ++ u32 Para2; ++ u32 msDelay; ++}__attribute__ ((packed)) SwChnlCmd; ++ ++extern u32 rtl819XMACPHY_Array_PG[]; ++extern u32 rtl819XPHY_REG_1T2RArray[]; ++extern u32 rtl819XAGCTAB_Array[]; ++extern u32 rtl819XRadioA_Array[]; ++extern u32 rtl819XRadioB_Array[]; ++extern u32 rtl819XRadioC_Array[]; ++extern u32 rtl819XRadioD_Array[]; ++ ++typedef enum _HW90_BLOCK{ ++ HW90_BLOCK_MAC = 0, ++ HW90_BLOCK_PHY0 = 1, ++ HW90_BLOCK_PHY1 = 2, ++ HW90_BLOCK_RF = 3, ++ HW90_BLOCK_MAXIMUM = 4, // Never use this ++}HW90_BLOCK_E, *PHW90_BLOCK_E; ++ ++typedef enum _RF90_RADIO_PATH{ ++ RF90_PATH_A = 0, //Radio Path A ++ RF90_PATH_B = 1, //Radio Path B ++ RF90_PATH_C = 2, //Radio Path C ++ RF90_PATH_D = 3, //Radio Path D ++ RF90_PATH_MAX //Max RF number 92 support ++}RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E; ++ ++#define bMaskByte0 0xff ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++ ++//extern u32 rtl8192_CalculateBitShift(u32 dwBitMask); ++extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device* dev, u32 eRFPath); ++extern void rtl8192_setBBreg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData); ++extern u32 rtl8192_QueryBBReg(struct net_device* dev, u32 dwRegAddr, u32 dwBitMask); ++//extern u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset); ++//extern void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data); ++extern void rtl8192_phy_SetRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask, u32 Data); ++extern u32 rtl8192_phy_QueryRFReg(struct net_device* dev, RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask); ++extern void rtl8192_phy_configmac(struct net_device* dev); ++extern void rtl8192_phyConfigBB(struct net_device* dev, u8 ConfigType); ++//extern void rtl8192_InitBBRFRegDef(struct net_device* dev); ++extern RT_STATUS rtl8192_phy_checkBBAndRF(struct net_device* dev, HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath); ++//extern RT_STATUS rtl8192_BB_Config_ParaFile(struct net_device* dev); ++extern RT_STATUS rtl8192_BBConfig(struct net_device* dev); ++extern void rtl8192_phy_getTxPower(struct net_device* dev); ++extern void rtl8192_phy_setTxPower(struct net_device* dev, u8 channel); ++extern RT_STATUS rtl8192_phy_RFConfig(struct net_device* dev); ++extern void rtl8192_phy_updateInitGain(struct net_device* dev); ++extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device* dev, RF90_RADIO_PATH_E eRFPath); ++ ++extern u8 rtl8192_phy_SwChnl(struct net_device* dev, u8 channel); ++extern void rtl8192_SetBWMode(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset); ++extern void rtl8192_SwChnl_WorkItem(struct net_device *dev); ++extern void rtl8192_SetBWModeWorkItem(struct net_device *dev); ++extern void InitialGain819xPci(struct net_device *dev, u8 Operation); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xE_phyreg.h +@@ -0,0 +1,878 @@ ++#ifndef _R819XU_PHYREG_H ++#define _R819XU_PHYREG_H ++ ++ ++#define RF_DATA 0x1d4 // FW will write RF data in the register. ++ ++//Register //duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF ++//page 1 ++#define rPMAC_Reset 0x100 ++#define rPMAC_TxStart 0x104 ++#define rPMAC_TxLegacySIG 0x108 ++#define rPMAC_TxHTSIG1 0x10c ++#define rPMAC_TxHTSIG2 0x110 ++#define rPMAC_PHYDebug 0x114 ++#define rPMAC_TxPacketNum 0x118 ++#define rPMAC_TxIdle 0x11c ++#define rPMAC_TxMACHeader0 0x120 ++#define rPMAC_TxMACHeader1 0x124 ++#define rPMAC_TxMACHeader2 0x128 ++#define rPMAC_TxMACHeader3 0x12c ++#define rPMAC_TxMACHeader4 0x130 ++#define rPMAC_TxMACHeader5 0x134 ++#define rPMAC_TxDataType 0x138 ++#define rPMAC_TxRandomSeed 0x13c ++#define rPMAC_CCKPLCPPreamble 0x140 ++#define rPMAC_CCKPLCPHeader 0x144 ++#define rPMAC_CCKCRC16 0x148 ++#define rPMAC_OFDMRxCRC32OK 0x170 ++#define rPMAC_OFDMRxCRC32Er 0x174 ++#define rPMAC_OFDMRxParityEr 0x178 ++#define rPMAC_OFDMRxCRC8Er 0x17c ++#define rPMAC_CCKCRxRC16Er 0x180 ++#define rPMAC_CCKCRxRC32Er 0x184 ++#define rPMAC_CCKCRxRC32OK 0x188 ++#define rPMAC_TxStatus 0x18c ++ ++//90P ++#define MCS_TXAGC 0x340 // MCS AGC ++#define CCK_TXAGC 0x348 // CCK AGC ++ ++//page8 ++#define rFPGA0_RFMOD 0x800 //RF mode & CCK TxSC ++#define rFPGA0_TxInfo 0x804 ++#define rFPGA0_PSDFunction 0x808 ++#define rFPGA0_TxGainStage 0x80c ++#define rFPGA0_RFTiming1 0x810 ++#define rFPGA0_RFTiming2 0x814 ++//#define rFPGA0_XC_RFTiming 0x818 ++//#define rFPGA0_XD_RFTiming 0x81c ++#define rFPGA0_XA_HSSIParameter1 0x820 ++#define rFPGA0_XA_HSSIParameter2 0x824 ++#define rFPGA0_XB_HSSIParameter1 0x828 ++#define rFPGA0_XB_HSSIParameter2 0x82c ++#define rFPGA0_XC_HSSIParameter1 0x830 ++#define rFPGA0_XC_HSSIParameter2 0x834 ++#define rFPGA0_XD_HSSIParameter1 0x838 ++#define rFPGA0_XD_HSSIParameter2 0x83c ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++#define rFPGA0_XC_LSSIParameter 0x848 ++#define rFPGA0_XD_LSSIParameter 0x84c ++#define rFPGA0_RFWakeUpParameter 0x850 ++#define rFPGA0_RFSleepUpParameter 0x854 ++#define rFPGA0_XAB_SwitchControl 0x858 ++#define rFPGA0_XCD_SwitchControl 0x85c ++#define rFPGA0_XA_RFInterfaceOE 0x860 ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++#define rFPGA0_XC_RFInterfaceOE 0x868 ++#define rFPGA0_XD_RFInterfaceOE 0x86c ++#define rFPGA0_XAB_RFInterfaceSW 0x870 ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++#define rFPGA0_XAB_RFParameter 0x878 ++#define rFPGA0_XCD_RFParameter 0x87c ++#define rFPGA0_AnalogParameter1 0x880 ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 ++#define rFPGA0_AnalogParameter4 0x88c ++#define rFPGA0_XA_LSSIReadBack 0x8a0 ++#define rFPGA0_XB_LSSIReadBack 0x8a4 ++#define rFPGA0_XC_LSSIReadBack 0x8a8 ++#define rFPGA0_XD_LSSIReadBack 0x8ac ++#define rFPGA0_PSDReport 0x8b4 ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 ++ ++//page 9 ++#define rFPGA1_RFMOD 0x900 //RF mode & OFDM TxSC ++#define rFPGA1_TxBlock 0x904 ++#define rFPGA1_DebugSelect 0x908 ++#define rFPGA1_TxInfo 0x90c ++ ++//page a ++#define rCCK0_System 0xa00 ++#define rCCK0_AFESetting 0xa04 ++#define rCCK0_CCA 0xa08 ++#define rCCK0_RxAGC1 0xa0c //AGC default value, saturation level ++#define rCCK0_RxAGC2 0xa10 //AGC & DAGC ++#define rCCK0_RxHP 0xa14 ++#define rCCK0_DSPParameter1 0xa18 //Timing recovery & Channel estimation threshold ++#define rCCK0_DSPParameter2 0xa1c //SQ threshold ++#define rCCK0_TxFilter1 0xa20 ++#define rCCK0_TxFilter2 0xa24 ++#define rCCK0_DebugPort 0xa28 //debug port and Tx filter3 ++#define rCCK0_FalseAlarmReport 0xa2c //0xa2d ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 //0xa57 ++#define rCCK0_FACounterLower 0xa5c //0xa5b ++#define rCCK0_FACounterUpper 0xa58 //0xa5c ++ ++//page c ++#define rOFDM0_LSTF 0xc00 ++#define rOFDM0_TRxPathEnable 0xc04 ++#define rOFDM0_TRMuxPar 0xc08 ++#define rOFDM0_TRSWIsolation 0xc0c ++#define rOFDM0_XARxAFE 0xc10 //RxIQ DC offset, Rx digital filter, DC notch filter ++#define rOFDM0_XARxIQImbalance 0xc14 //RxIQ imblance matrix ++#define rOFDM0_XBRxAFE 0xc18 ++#define rOFDM0_XBRxIQImbalance 0xc1c ++#define rOFDM0_XCRxAFE 0xc20 ++#define rOFDM0_XCRxIQImbalance 0xc24 ++#define rOFDM0_XDRxAFE 0xc28 ++#define rOFDM0_XDRxIQImbalance 0xc2c ++#define rOFDM0_RxDetector1 0xc30 //PD,BW & SBD ++#define rOFDM0_RxDetector2 0xc34 //SBD & Fame Sync. ++#define rOFDM0_RxDetector3 0xc38 //Frame Sync. ++#define rOFDM0_RxDetector4 0xc3c //PD, SBD, Frame Sync & Short-GI ++#define rOFDM0_RxDSP 0xc40 //Rx Sync Path ++#define rOFDM0_CFOandDAGC 0xc44 //CFO & DAGC ++#define rOFDM0_CCADropThreshold 0xc48 //CCA Drop threshold ++#define rOFDM0_ECCAThreshold 0xc4c // energy CCA ++#define rOFDM0_XAAGCCore1 0xc50 ++#define rOFDM0_XAAGCCore2 0xc54 ++#define rOFDM0_XBAGCCore1 0xc58 ++#define rOFDM0_XBAGCCore2 0xc5c ++#define rOFDM0_XCAGCCore1 0xc60 ++#define rOFDM0_XCAGCCore2 0xc64 ++#define rOFDM0_XDAGCCore1 0xc68 ++#define rOFDM0_XDAGCCore2 0xc6c ++#define rOFDM0_AGCParameter1 0xc70 ++#define rOFDM0_AGCParameter2 0xc74 ++#define rOFDM0_AGCRSSITable 0xc78 ++#define rOFDM0_HTSTFAGC 0xc7c ++#define rOFDM0_XATxIQImbalance 0xc80 ++#define rOFDM0_XATxAFE 0xc84 ++#define rOFDM0_XBTxIQImbalance 0xc88 ++#define rOFDM0_XBTxAFE 0xc8c ++#define rOFDM0_XCTxIQImbalance 0xc90 ++#define rOFDM0_XCTxAFE 0xc94 ++#define rOFDM0_XDTxIQImbalance 0xc98 ++#define rOFDM0_XDTxAFE 0xc9c ++#define rOFDM0_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++ ++ ++//page d ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++#define rOFDM1_CFO 0xd08 ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++#define rOFDM_PHYCounter1 0xda0 //cca, parity fail ++#define rOFDM_PHYCounter2 0xda4 //rate illegal, crc8 fail ++#define rOFDM_PHYCounter3 0xda8 //MCS not support ++#define rOFDM_ShortCFOAB 0xdac ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++//page e ++#define rTxAGC_Rate18_06 0xe00 ++#define rTxAGC_Rate54_24 0xe04 ++#define rTxAGC_CCK_Mcs32 0xe08 ++#define rTxAGC_Mcs03_Mcs00 0xe10 ++#define rTxAGC_Mcs07_Mcs04 0xe14 ++#define rTxAGC_Mcs11_Mcs08 0xe18 ++#define rTxAGC_Mcs15_Mcs12 0xe1c ++ ++ ++//RF ++//Zebra1 ++#define rZebra1_HSSIEnable 0x0 ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++#define rZebra1_Channel 0x7 ++#define rZebra1_TxGain 0x8 ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++//Zebra4 ++#define rGlobalCtrl 0 ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++//RTL8258 ++#define rRTL8258_TxLPF 0x11 ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++//Bit Mask ++//page-1 ++#define bBBResetB 0x100 ++#define bGlobalResetB 0x200 ++#define bOFDMTxStart 0x4 ++#define bCCKTxStart 0x8 ++#define bCRC32Debug 0x100 ++#define bPMACLoopback 0x10 ++#define bTxLSIG 0xffffff ++#define bOFDMTxRate 0xf ++#define bOFDMTxReserved 0x10 ++#define bOFDMTxLength 0x1ffe0 ++#define bOFDMTxParity 0x20000 ++#define bTxHTSIG1 0xffffff ++#define bTxHTMCSRate 0x7f ++#define bTxHTBW 0x80 ++#define bTxHTLength 0xffff00 ++#define bTxHTSIG2 0xffffff ++#define bTxHTSmoothing 0x1 ++#define bTxHTSounding 0x2 ++#define bTxHTReserved 0x4 ++#define bTxHTAggreation 0x8 ++#define bTxHTSTBC 0x30 ++#define bTxHTAdvanceCoding 0x40 ++#define bTxHTShortGI 0x80 ++#define bTxHTNumberHT_LTF 0x300 ++#define bTxHTCRC8 0x3fc00 ++#define bCounterReset 0x10000 ++#define bNumOfOFDMTx 0xffff ++#define bNumOfCCKTx 0xffff0000 ++#define bTxIdleInterval 0xffff ++#define bOFDMService 0xffff0000 ++#define bTxMACHeader 0xffffffff ++#define bTxDataInit 0xff ++#define bTxHTMode 0x100 ++#define bTxDataType 0x30000 ++#define bTxRandomSeed 0xffffffff ++#define bCCKTxPreamble 0x1 ++#define bCCKTxSFD 0xffff0000 ++#define bCCKTxSIG 0xff ++#define bCCKTxService 0xff00 ++#define bCCKLengthExt 0x8000 ++#define bCCKTxLength 0xffff0000 ++#define bCCKTxCRC16 0xffff ++#define bCCKTxStatus 0x1 ++#define bOFDMTxStatus 0x2 ++ ++//page-8 ++#define bRFMOD 0x1 ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++#define bOFDMRxADCPhase 0x10000 ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++#define bXBTxAGC 0xf00 ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++#define bPAStart 0xf0000000 ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf //Reg0x814 ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 //T2R ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 //chane gain at continue Tx ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++#define b3WireDataLength 0x800 ++#define b3WireAddressLength 0x400 ++#define b3WireRFPowerDown 0x1 ++//#define bHWSISelect 0x8 ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf //3-wire total control ++#define bRFSI_RFENV 0x10 ++#define bRFSI_TRSW 0x20 ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++#define bLSSIReadAddress 0x3f000000 //LSSI "Read" Address ++#define bLSSIReadEdge 0x80000000 //LSSI "Read" edge signal ++#define bLSSIReadBackData 0xfff ++#define bLSSIReadOKFlag 0x1000 ++#define bCCKSampleRate 0x8 //0: 44MHz, 1:88MHz ++ ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++#define bADClkPhase 0x4000000 ++#define b80MClkDelay 0x18000000 ++#define bAFEWatchDogEnable 0x20000000 ++#define bXtalCap 0x0f000000 ++#define bXtalCap01 0xc0000000 ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bIntDifClkEnable 0x400 ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++ ++#define bCCKRxAGCFormat 0x200 ++ ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++//page-9 ++#define bOFDMTxSC 0x30000000 ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff //reset debug page and also HWord, LWord ++#define bDebugItem 0xff //reset debug page and LWord ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++//page-a ++#define bCCKBBMode 0x3 ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++#define bCCKSideBand 0x10 ++#define bCCKScramble 0x8 ++#define bCCKAntDiversity 0x8000 ++#define bCCKCarrierRecovery 0x4000 ++#define bCCKTxRate 0x3000 ++#define bCCKDCCancel 0x0800 ++#define bCCKISICancel 0x0400 ++#define bCCKMatchFilter 0x0200 ++#define bCCKEqualizer 0x0100 ++#define bCCKPreambleDetect 0x800000 ++#define bCCKFastFalseCCA 0x400000 ++#define bCCKChEstStart 0x300000 ++#define bCCKCCACount 0x080000 ++#define bCCKcs_lim 0x070000 ++#define bCCKBistMode 0x80000000 ++#define bCCKCCAMask 0x40000000 ++#define bCCKTxDACPhase 0x4 ++#define bCCKRxADCPhase 0x20000000 //r_rx_clk ++#define bCCKr_cp_mode0 0x0100 ++#define bCCKTxDCOffset 0xf0 ++#define bCCKRxDCOffset 0xf ++#define bCCKCCAMode 0xc000 ++#define bCCKFalseCS_lim 0x3f00 ++#define bCCKCS_ratio 0xc00000 ++#define bCCKCorgBit_sel 0x300000 ++#define bCCKPD_lim 0x0f0000 ++#define bCCKNewCCA 0x80000000 ++#define bCCKRxHPofIG 0x8000 ++#define bCCKRxIG 0x7f00 ++#define bCCKLNAPolarity 0x800000 ++#define bCCKRx1stGain 0x7f0000 ++#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f //AGCsamp_dly ++#define bCCKFixedRxAGC 0x8000 ++//#define bCCKRxAGCFormat 0x4000 //remove to HSSI register 0x824 ++#define bCCKAntennaPolarity 0x2000 ++#define bCCKTxFilterType 0x0c00 ++#define bCCKRxAGCReportType 0x0300 ++#define bCCKRxDAGCEn 0x80000000 ++#define bCCKRxDAGCPeriod 0x20000000 ++#define bCCKRxDAGCSatLevel 0x1f000000 ++#define bCCKTimingRecovery 0x800000 ++#define bCCKTxC0 0x3f0000 ++#define bCCKTxC1 0x3f000000 ++#define bCCKTxC2 0x3f ++#define bCCKTxC3 0x3f00 ++#define bCCKTxC4 0x3f0000 ++#define bCCKTxC5 0x3f000000 ++#define bCCKTxC6 0x3f ++#define bCCKTxC7 0x3f00 ++#define bCCKDebugPort 0xff0000 ++#define bCCKDACDebug 0x0f000000 ++#define bCCKFalseAlarmEnable 0x8000 ++#define bCCKFalseAlarmRead 0x4000 ++#define bCCKTRSSI 0x7f ++#define bCCKRxAGCReport 0xfe ++#define bCCKRxReport_AntSel 0x80000000 ++#define bCCKRxReport_MFOff 0x40000000 ++#define bCCKRxRxReport_SQLoss 0x20000000 ++#define bCCKRxReport_Pktloss 0x10000000 ++#define bCCKRxReport_Lockedbit 0x08000000 ++#define bCCKRxReport_RateError 0x04000000 ++#define bCCKRxReport_RxRate 0x03000000 ++#define bCCKRxFACounterLower 0xff ++#define bCCKRxFACounterUpper 0xff000000 ++#define bCCKRxHPAGCStart 0xe000 ++#define bCCKRxHPAGCFinal 0x1c00 ++ ++#define bCCKRxFalseAlarmEnable 0x8000 ++#define bCCKFACounterFreeze 0x4000 ++ ++#define bCCKTxPathSel 0x10000000 ++#define bCCKDefaultRxPath 0xc000000 ++#define bCCKOptionRxPath 0x3000000 ++ ++//page c ++#define bNumOfSTF 0x3 ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 //the threshold for high power ++#define bRSSI_Gen 0x7f000000 //the threshold for ant diversity ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++//#define bRxMF_Hold 0x3800 ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++ ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++ ++#define bDAFormat 0x40000 ++ ++#define bTxChEmuEnable 0x01000000 ++ ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++ ++#define bExtLNAGain 0x7c00 ++ ++//page d ++#define bSTBCEn 0x4 ++#define bAntennaMapping 0x10 ++#define bNss 0x20 ++#define bCFOAntSumD 0x200 ++#define bPHYCounterReset 0x8000000 ++#define bCFOReportGet 0x4000000 ++#define bOFDMContinueTx 0x10000000 ++#define bOFDMSingleCarrier 0x20000000 ++#define bOFDMSingleTone 0x40000000 ++//#define bRxPath1 0x01 ++//#define bRxPath2 0x02 ++//#define bRxPath3 0x04 ++//#define bRxPath4 0x08 ++//#define bTxPath1 0x10 ++//#define bTxPath2 0x20 ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 //total ++#define bShortCFOFLength 11 //fraction ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++ ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++ ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++ ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++ ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++ ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++ ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++//page e ++#define bTxAGCRate18_06 0x7f7f7f7f ++#define bTxAGCRate54_24 0x7f7f7f7f ++#define bTxAGCRateMCS32 0x7f ++#define bTxAGCRateCCK 0x7f00 ++#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f ++#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f ++#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f ++#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f ++ ++ ++//Rx Pseduo noise ++#define bRxPesudoNoiseOn 0x20000000 ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++//RF ++//Zebra1 ++#define bZebra1_HSSIEnable 0x8 ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++//Zebra4 ++#define bRTL8256RegModeCtrl1 0x100 ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++//RTL8258 ++#define bRTL8258_TxLPFBW 0xc ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++//byte endable for sb_write ++#define bByte0 0x1 ++#define bByte1 0x2 ++#define bByte2 0x4 ++#define bByte3 0x8 ++#define bWord0 0x3 ++#define bWord1 0xc ++#define bDWord 0xf ++ ++//for PutRegsetting & GetRegSetting BitMask ++#define bMaskByte0 0xff ++#define bMaskByte1 0xff00 ++#define bMaskByte2 0xff0000 ++#define bMaskByte3 0xff000000 ++#define bMaskHWord 0xffff0000 ++#define bMaskLWord 0x0000ffff ++#define bMaskDWord 0xffffffff ++ ++//for PutRFRegsetting & GetRFRegSetting BitMask ++#define bMask12Bits 0xfff ++ ++#define bEnable 0x1 ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 //500ms ++#define tUpdateRxCounter 100 //100ms ++ ++#define rateCCK 0 ++#define rateOFDM 1 ++#define rateHT 2 ++ ++//define Register-End ++#define bPMAC_End 0x1ff ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++//define max debug item in each debug page ++//#define bMaxItem_FPGA_PHY0 0x9 ++//#define bMaxItem_FPGA_PHY1 0x3 ++//#define bMaxItem_PHY_11B 0x16 ++//#define bMaxItem_OFDM_PHY0 0x29 ++//#define bMaxItem_OFDM_PHY1 0x0 ++ ++#define bPMACControl 0x0 ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define PathA 0x0 ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++#define rRTL8256RxMixerPole 0xb ++#define bZebraRxMixerPole 0x6 ++#define rRTL8256TxBBOPBias 0x9 ++#define bRTL8256TxBBOPBias 0x400 ++#define rRTL8256TxBBBW 19 ++#define bRTL8256TxBBBW 0x18 ++ ++#endif //__INC_HAL8190PCIPHYREG_H +--- /dev/null ++++ b/drivers/staging/rtl8192e/r819xP_firmware_img.h +@@ -0,0 +1,3637 @@ ++#ifndef __INC_R819XU_FIRMWARE_IMG_H ++#define __INC_R819XU_FIRMWARE_IMG_H ++/*Created on 2008/ 5/19, 6:38*/ ++#include ++ ++u8 rtl8190_fwboot_array[] = { ++0x10,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x3c,0x08,0xbf,0xc0,0x25,0x08,0x00,0x08, ++0x3c,0x09,0xb0,0x03,0xad,0x28,0x00,0x20,0x40,0x80,0x68,0x00,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0xd0,0x00,0x40,0x8a,0x60,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, ++0x25,0x08,0xd6,0x04,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff, ++0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01,0x01,0x2a,0x10,0x2b, ++0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x00,0x00,0x25,0x4a,0x00,0x00, ++0x4c,0x8a,0x00,0x00,0x4c,0x89,0x08,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x01, ++0x25,0x08,0xd6,0x04,0x3c,0x01,0x80,0x00,0x01,0x21,0x48,0x25,0x3c,0x0a,0xbf,0xc0, ++0x25,0x4a,0x00,0x7c,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0xad,0x00,0x00,0x00, ++0x21,0x08,0x00,0x04,0x01,0x09,0x10,0x2b,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00, ++0x3c,0x08,0x80,0x01,0x25,0x08,0x7f,0xff,0x24,0x09,0x00,0x01,0x3c,0x01,0x7f,0xff, ++0x34,0x21,0xff,0xff,0x01,0x01,0x50,0x24,0x00,0x09,0x48,0x40,0x35,0x29,0x00,0x01, ++0x01,0x2a,0x10,0x2b,0x14,0x40,0xff,0xfc,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x01, ++0x25,0x4a,0x00,0x00,0x3c,0x01,0x7f,0xff,0x34,0x21,0xff,0xff,0x01,0x41,0x50,0x24, ++0x3c,0x09,0x00,0x01,0x35,0x29,0x7f,0xff,0x4c,0x8a,0x20,0x00,0x4c,0x89,0x28,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x08,0x04,0x10, ++0x00,0x00,0x00,0x00,0x40,0x88,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x3c,0x08,0xbf,0xc0,0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0xbf,0xc0,0x25,0x4a,0x01,0x20,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, ++0x3c,0x08,0xb0,0x03,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x29,0x00,0x10, ++0xad,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x08,0x80,0x00,0x25,0x08,0x6a,0xbc, ++0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,}; ++ ++u8 rtl8190_fwmain_array[] = { ++0x40,0x04,0x68,0x00,0x40,0x05,0x70,0x00,0x40,0x06,0x40,0x00,0x0c,0x00,0x1a,0x1e, ++0x00,0x00,0x00,0x00,0x40,0x1a,0x68,0x00,0x33,0x5b,0x00,0x3c,0x17,0x60,0x00,0x09, ++0x00,0x00,0x00,0x00,0x40,0x1b,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0x5b,0xd0,0x24, ++0x40,0x1a,0x70,0x00,0x03,0x40,0x00,0x08,0x42,0x00,0x00,0x10,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0xff,0xff,0x8c,0x43,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x00,0xd0, ++0xac,0x62,0x00,0x00,0x00,0x00,0x20,0x21,0x27,0x85,0x94,0x50,0x00,0x85,0x18,0x21, ++0x24,0x84,0x00,0x01,0x28,0x82,0x00,0x0a,0x14,0x40,0xff,0xfc,0xa0,0x60,0x00,0x00, ++0x27,0x82,0x94,0x5a,0x24,0x04,0x00,0x06,0x24,0x84,0xff,0xff,0xa4,0x40,0x00,0x00, ++0x04,0x81,0xff,0xfd,0x24,0x42,0x00,0x02,0x24,0x02,0x00,0x03,0xa3,0x82,0x94,0x50, ++0x24,0x02,0x00,0x0a,0x24,0x03,0x09,0xc4,0xa3,0x82,0x94,0x52,0x24,0x02,0x00,0x04, ++0x24,0x04,0x00,0x01,0x24,0x05,0x00,0x02,0xa7,0x83,0x94,0x66,0xa3,0x82,0x94,0x58, ++0x24,0x03,0x04,0x00,0x24,0x02,0x02,0x00,0xaf,0x83,0x94,0x6c,0xa3,0x85,0x94,0x59, ++0xa7,0x82,0x94,0x5a,0xa7,0x84,0x94,0x5c,0xaf,0x84,0x94,0x68,0xa3,0x84,0x94,0x51, ++0xa3,0x80,0x94,0x53,0xa3,0x80,0x94,0x54,0xa3,0x80,0x94,0x55,0xa3,0x84,0x94,0x56, ++0xa3,0x85,0x94,0x57,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x24,0x42,0x01,0x7c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, ++0x27,0x84,0x94,0x78,0x00,0x00,0x10,0x21,0x24,0x42,0x00,0x01,0x00,0x02,0x16,0x00, ++0x00,0x02,0x16,0x03,0x28,0x43,0x00,0x03,0xac,0x80,0xff,0xfc,0xa0,0x80,0x00,0x00, ++0x14,0x60,0xff,0xf9,0x24,0x84,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x01,0xc0, ++0x3c,0x08,0xb0,0x03,0xac,0x62,0x00,0x00,0x35,0x08,0x00,0x70,0x8d,0x02,0x00,0x00, ++0x00,0xa0,0x48,0x21,0x00,0x04,0x26,0x00,0x00,0x02,0x2a,0x43,0x00,0x06,0x36,0x00, ++0x00,0x07,0x3e,0x00,0x00,0x02,0x12,0x03,0x29,0x23,0x00,0x03,0x00,0x04,0x56,0x03, ++0x00,0x06,0x36,0x03,0x00,0x07,0x3e,0x03,0x30,0x48,0x00,0x01,0x10,0x60,0x00,0x11, ++0x30,0xa5,0x00,0x07,0x24,0x02,0x00,0x02,0x00,0x49,0x10,0x23,0x00,0x45,0x10,0x07, ++0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x66,0x00,0x00,0x00,0x00,0x8f,0xa2,0x00,0x10, ++0x00,0x00,0x00,0x00,0x00,0x02,0x21,0x43,0x11,0x00,0x00,0x10,0x00,0x07,0x20,0x0b, ++0x15,0x20,0x00,0x06,0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x05,0x34,0x42,0x01,0x20, ++0xa4,0x44,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x11,0x22,0x00,0x04, ++0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x24, ++0x3c,0x02,0xb0,0x05,0x08,0x00,0x00,0x94,0x34,0x42,0x01,0x22,0x15,0x20,0x00,0x54, ++0x24,0x02,0x00,0x01,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x74,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0xaf,0x83,0x94,0x74,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x70, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x6b,0x00,0x08,0x11,0x60,0x00,0x18, ++0x00,0x09,0x28,0x40,0x00,0x00,0x40,0x21,0x27,0x85,0x94,0x70,0x8c,0xa3,0x00,0x00, ++0x8c,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x62,0x38,0x23,0x00,0x43,0x10,0x2a, ++0x10,0x40,0x00,0x3d,0x00,0x00,0x00,0x00,0xac,0xa7,0x00,0x00,0x25,0x02,0x00,0x01, ++0x00,0x02,0x16,0x00,0x00,0x02,0x46,0x03,0x29,0x03,0x00,0x03,0x14,0x60,0xff,0xf3, ++0x24,0xa5,0x00,0x0c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x70,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x4b,0x10,0x23,0xa0,0x62,0x00,0x00,0x00,0x09,0x28,0x40, ++0x00,0xa9,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x94,0x78,0x00,0x0a,0x20,0x0b, ++0x00,0x43,0x18,0x21,0x10,0xc0,0x00,0x05,0x00,0x00,0x38,0x21,0x80,0x62,0x00,0x01, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x80,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03,0x00,0xa9,0x10,0x21,0x24,0x07,0x00,0x01, ++0x00,0xa9,0x10,0x21,0x00,0x02,0x30,0x80,0x27,0x82,0x94,0x78,0xa0,0x67,0x00,0x01, ++0x00,0xc2,0x38,0x21,0x80,0xe3,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x07, ++0x00,0x00,0x00,0x00,0x27,0x83,0x94,0x70,0x00,0xc3,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x21,0xac,0x62,0x00,0x00,0x27,0x85,0x94,0x74, ++0x27,0x82,0x94,0x70,0x00,0xc5,0x28,0x21,0x00,0xc2,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x8c,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x2a,0x14,0x60,0x00,0x03, ++0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xe2,0x00,0x00,0xa0,0xe0,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xb7,0xac,0xa0,0x00,0x00, ++0x11,0x22,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x7c, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0x94,0x8c,0x08,0x00,0x00,0xa7, ++0x3c,0x02,0xb0,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x78,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0xaf,0x83,0x94,0x80,0x08,0x00,0x00,0xa7,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x04,0x10, ++0x3c,0x05,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0xa5,0x00,0x70,0x8c,0xa2,0x00,0x00, ++0x90,0x84,0x00,0x08,0x3c,0x06,0xb0,0x03,0x00,0x02,0x16,0x00,0x2c,0x83,0x00,0x03, ++0x34,0xc6,0x00,0x72,0x24,0x07,0x00,0x01,0x10,0x60,0x00,0x11,0x00,0x02,0x2f,0xc2, ++0x90,0xc2,0x00,0x00,0x00,0x00,0x18,0x21,0x00,0x02,0x16,0x00,0x10,0xa7,0x00,0x09, ++0x00,0x02,0x16,0x03,0x14,0x80,0x00,0x0c,0x30,0x43,0x00,0x03,0x83,0x82,0x94,0x78, ++0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0x02,0x16,0x00, ++0x00,0x02,0x1e,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x72,0xa0,0x43,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x45,0x00,0x05,0x10,0x87,0x00,0x04, ++0x30,0x43,0x00,0x06,0x93,0x82,0x94,0x90,0x08,0x00,0x01,0x1f,0x00,0x43,0x10,0x21, ++0x83,0x82,0x94,0x84,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x40,0x08,0x00,0x01,0x1f, ++0x00,0x45,0x10,0x21,0x10,0x80,0x00,0x05,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01, ++0x00,0x64,0x10,0x2b,0x14,0x40,0xff,0xfd,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x04,0xe4, ++0x3c,0x04,0xb0,0x02,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x08, ++0x24,0x02,0x00,0x01,0xaf,0x84,0x94,0xa0,0xa3,0x82,0x94,0xb0,0xa7,0x80,0x94,0xa4, ++0xa7,0x80,0x94,0xa6,0xaf,0x80,0x94,0xa8,0xaf,0x80,0x94,0xac,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, ++0x24,0x42,0x05,0x24,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0xac, ++0x80,0xa2,0x00,0x15,0x8c,0x83,0x00,0x00,0x27,0xbd,0xff,0xf0,0x00,0x43,0x10,0x21, ++0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x10,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x00,0x34,0x42,0x00,0x20,0x24,0x63,0x05,0x5c,0x27,0xbd,0xff,0xe0, ++0xac,0x43,0x00,0x00,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, ++0x8f,0x90,0x94,0xa0,0x0c,0x00,0x02,0x90,0x00,0x80,0x88,0x21,0x14,0x40,0x00,0x2a, ++0x3c,0x02,0x00,0x80,0x16,0x20,0x00,0x02,0x34,0x42,0x02,0x01,0x24,0x02,0x02,0x01, ++0xae,0x02,0x00,0x00,0x97,0x84,0x94,0xa4,0x97,0x82,0x94,0xa6,0x3c,0x03,0xb0,0x02, ++0x00,0x83,0x20,0x21,0x24,0x42,0x00,0x04,0xa7,0x82,0x94,0xa6,0xa4,0x82,0x00,0x00, ++0x8f,0x84,0x94,0xa8,0x8f,0x82,0x94,0xa0,0x93,0x85,0x94,0x52,0x24,0x84,0x00,0x01, ++0x24,0x42,0x00,0x04,0x24,0x03,0x8f,0xff,0x3c,0x07,0xb0,0x06,0x3c,0x06,0xb0,0x03, ++0x00,0x43,0x10,0x24,0x00,0x85,0x28,0x2a,0x34,0xe7,0x80,0x18,0xaf,0x82,0x94,0xa0, ++0xaf,0x84,0x94,0xa8,0x10,0xa0,0x00,0x08,0x34,0xc6,0x01,0x08,0x8f,0x83,0x94,0xac, ++0x8f,0x84,0x94,0x6c,0x8c,0xc2,0x00,0x00,0x00,0x64,0x18,0x21,0x00,0x43,0x10,0x2b, ++0x14,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x8c,0xe2,0x00,0x00,0x3c,0x03,0x0f,0x00, ++0x3c,0x04,0x04,0x00,0x00,0x43,0x10,0x24,0x10,0x44,0x00,0x03,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x04,0x8e,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x00,0x24,0x63,0x06,0x48,0xaf,0xb0,0x00,0x10,0x34,0x42,0x00,0x20, ++0x8f,0x90,0x94,0xa0,0xac,0x43,0x00,0x00,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0x00,0x80,0x88,0x21,0x00,0xa0,0x90,0x21, ++0x0c,0x00,0x02,0x90,0x00,0xc0,0x98,0x21,0x24,0x07,0x8f,0xff,0x14,0x40,0x00,0x19, ++0x26,0x03,0x00,0x04,0x24,0x02,0x0e,0x03,0xae,0x02,0x00,0x00,0x00,0x67,0x80,0x24, ++0x26,0x02,0x00,0x04,0xae,0x11,0x00,0x00,0x00,0x47,0x80,0x24,0x97,0x86,0x94,0xa4, ++0x26,0x03,0x00,0x04,0xae,0x12,0x00,0x00,0x00,0x67,0x80,0x24,0xae,0x13,0x00,0x00, ++0x8f,0x84,0x94,0xa0,0x3c,0x02,0xb0,0x02,0x97,0x85,0x94,0xa6,0x00,0xc2,0x30,0x21, ++0x8f,0x82,0x94,0xa8,0x24,0x84,0x00,0x10,0x24,0xa5,0x00,0x10,0x00,0x87,0x20,0x24, ++0x24,0x42,0x00,0x01,0xa7,0x85,0x94,0xa6,0xaf,0x84,0x94,0xa0,0xaf,0x82,0x94,0xa8, ++0xa4,0xc5,0x00,0x00,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, ++0x94,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0xe0,0x00,0x14,0x40,0x00,0x14, ++0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x02,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfc, ++0x00,0x82,0x28,0x21,0x8c,0xa4,0x00,0x00,0x3c,0x02,0x00,0x70,0x8c,0xa6,0x00,0x08, ++0x00,0x82,0x10,0x21,0x2c,0x43,0x00,0x06,0x10,0x60,0x00,0x09,0x3c,0x03,0x80,0x01, ++0x00,0x02,0x10,0x80,0x24,0x63,0x08,0x94,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0xaf,0x86,0x80,0x14, ++0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x8c,0xa4,0x00,0x00,0x0c,0x00,0x1e,0xfc,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0xdc, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x2b,0x59,0x00,0xc0,0x20,0x21,0x08,0x00,0x01,0xdc, ++0x00,0x00,0x00,0x00,0x87,0x83,0x88,0x06,0x93,0x82,0x80,0x18,0x00,0x00,0x00,0x00, ++0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x93,0x83,0x88,0x07,0x24,0x02,0x00,0x01, ++0xa3,0x82,0x80,0x11,0xa3,0x83,0x80,0x19,0xa3,0x83,0x80,0x18,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x93,0x82,0x80,0x19,0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xf6, ++0x00,0x00,0x00,0x00,0x08,0x00,0x01,0xf3,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xff, ++0x14,0x80,0x00,0x2f,0x00,0x00,0x00,0x00,0x8f,0x82,0x80,0x14,0xa3,0x85,0x8b,0xcb, ++0x10,0x40,0x00,0x2b,0x2c,0xa2,0x00,0x04,0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40, ++0x24,0xa2,0xff,0xfc,0x2c,0x42,0x00,0x08,0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xf0, ++0x00,0x05,0x10,0x40,0x27,0x84,0x8b,0xd4,0x00,0x44,0x10,0x21,0x94,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0xa4,0x43,0x00,0x00, ++0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x0a,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xe0, ++0x2c,0x42,0x00,0x10,0x14,0x40,0x00,0x06,0x00,0x05,0x10,0x40,0x24,0xa2,0xff,0xd0, ++0x2c,0x42,0x00,0x10,0x10,0x40,0x00,0x09,0x24,0xa2,0xff,0xc0,0x00,0x05,0x10,0x40, ++0x27,0x84,0x8b,0xd4,0x00,0x44,0x10,0x21,0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00, ++0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0xa4,0x43,0xff,0xf8,0x2c,0x42,0x00,0x10, ++0x10,0x40,0x00,0x07,0x00,0x05,0x10,0x40,0x27,0x84,0x8b,0xd4,0x00,0x44,0x10,0x21, ++0x94,0x43,0xff,0xf8,0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0xa4,0x43,0xff,0xf8, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8f,0x86,0x94,0xa0,0x8f,0x82,0x80,0x14, ++0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x10,0x40,0x00,0x2a,0x00,0xc0,0x38,0x21, ++0x24,0x02,0x00,0x07,0x24,0x03,0xff,0x9c,0xa3,0x82,0x8b,0xd3,0xa3,0x83,0x8b,0xd2, ++0x27,0x8a,0x8b,0xd0,0x00,0x00,0x20,0x21,0x24,0x09,0x8f,0xff,0x00,0x04,0x10,0x80, ++0x00,0x4a,0x28,0x21,0x8c,0xa2,0x00,0x00,0x24,0xe3,0x00,0x04,0x24,0x88,0x00,0x01, ++0xac,0xe2,0x00,0x00,0x10,0x80,0x00,0x02,0x00,0x69,0x38,0x24,0xac,0xa0,0x00,0x00, ++0x31,0x04,0x00,0xff,0x2c,0x82,0x00,0x27,0x14,0x40,0xff,0xf5,0x00,0x04,0x10,0x80, ++0x97,0x83,0x94,0xa6,0x97,0x85,0x94,0xa4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x9c, ++0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06,0xa7,0x83,0x94,0xa6,0x34,0x84,0x80,0x18, ++0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x9c, ++0x3c,0x03,0x0f,0x00,0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00, ++0xaf,0x86,0x94,0xa0,0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x8e, ++0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x8f,0x86,0x94,0xa0,0x27,0xbd,0xff,0xc8,0x24,0x02,0x00,0x08, ++0x24,0x03,0x00,0x20,0xaf,0xbf,0x00,0x30,0xa3,0xa2,0x00,0x13,0xa3,0xa3,0x00,0x12, ++0xa7,0xa4,0x00,0x10,0x00,0xc0,0x28,0x21,0x27,0xa9,0x00,0x10,0x00,0x00,0x38,0x21, ++0x24,0x08,0x8f,0xff,0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff,0x24,0xa2,0x00,0x04,0x2c,0xe3,0x00,0x08, ++0xac,0xa4,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x48,0x28,0x24,0x97,0x83,0x94,0xa6, ++0x97,0x85,0x94,0xa4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x20,0x00,0xa2,0x28,0x21, ++0x3c,0x04,0xb0,0x06,0xa7,0x83,0x94,0xa6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, ++0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x20,0x3c,0x03,0x0f,0x00, ++0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x94,0xa0, ++0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x8e,0x00,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x30,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38, ++0x93,0x82,0x94,0xb0,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x11,0x24,0x06,0x00,0x01, ++0x8f,0x82,0x94,0xa8,0x3c,0x05,0xb0,0x06,0x3c,0x04,0xb0,0x03,0x34,0xa5,0x80,0x18, ++0x34,0x84,0x01,0x08,0x14,0x40,0x00,0x09,0x00,0x00,0x30,0x21,0x97,0x82,0x94,0xa4, ++0x8c,0x84,0x00,0x00,0x3c,0x03,0xb0,0x02,0x00,0x43,0x10,0x21,0xaf,0x84,0x94,0xac, ++0xa7,0x80,0x94,0xa6,0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04,0x8c,0xa2,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0xc0,0x10,0x21,0x8f,0x86,0x94,0xa0,0x8f,0x82,0x94,0xa8, ++0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x00,0xc0,0x40,0x21,0x14,0x40,0x00,0x0a, ++0x00,0x40,0x50,0x21,0x00,0x00,0x38,0x21,0x27,0x89,0x8b,0xa0,0x24,0xe2,0x00,0x01, ++0x00,0x07,0x18,0x80,0x30,0x47,0x00,0xff,0x00,0x69,0x18,0x21,0x2c,0xe2,0x00,0x0a, ++0x14,0x40,0xff,0xfa,0xac,0x60,0x00,0x00,0x3c,0x02,0x00,0x80,0x10,0x82,0x00,0x6f, ++0x00,0x00,0x00,0x00,0x97,0x82,0x8b,0xa6,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x8b,0xa6,0x90,0xa3,0x00,0x15,0x97,0x82,0x8b,0xa8,0x00,0x03,0x1e,0x00, ++0x00,0x03,0x1e,0x03,0x00,0x43,0x10,0x21,0xa7,0x82,0x8b,0xa8,0x8c,0xa4,0x00,0x20, ++0x3c,0x02,0x00,0x60,0x3c,0x03,0x00,0x20,0x00,0x82,0x20,0x24,0x10,0x83,0x00,0x54, ++0x00,0x00,0x00,0x00,0x14,0x80,0x00,0x47,0x00,0x00,0x00,0x00,0x97,0x82,0x8b,0xac, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0xac,0x84,0xa3,0x00,0x06, ++0x8f,0x82,0x8b,0xbc,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21,0xaf,0x82,0x8b,0xbc, ++0x25,0x42,0x00,0x01,0x28,0x43,0x27,0x10,0xaf,0x82,0x94,0xa8,0x10,0x60,0x00,0x09, ++0x24,0x02,0x00,0x04,0x93,0x83,0x80,0x11,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x05, ++0x24,0x02,0x00,0x04,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x24,0x03,0x00,0x28,0xa3,0x83,0x8b,0xa2,0xa3,0x82,0x8b,0xa3, ++0x90,0xa2,0x00,0x18,0x93,0x83,0x8b,0xcb,0x00,0x00,0x38,0x21,0x00,0x02,0x16,0x00, ++0x00,0x02,0x16,0x03,0xa7,0x82,0x8b,0xb6,0xa3,0x83,0x8b,0xc4,0x27,0x89,0x8b,0xa0, ++0x24,0x05,0x8f,0xff,0x00,0x07,0x10,0x80,0x00,0x49,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x24,0xe3,0x00,0x01,0x30,0x67,0x00,0xff,0x25,0x02,0x00,0x04,0x2c,0xe3,0x00,0x0a, ++0xad,0x04,0x00,0x00,0x14,0x60,0xff,0xf7,0x00,0x45,0x40,0x24,0x97,0x83,0x94,0xa6, ++0x97,0x85,0x94,0xa4,0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x28,0x00,0xa2,0x28,0x21, ++0x3c,0x04,0xb0,0x06,0xa7,0x83,0x94,0xa6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, ++0x8c,0x85,0x00,0x00,0x24,0x02,0x8f,0xff,0x24,0xc6,0x00,0x28,0x3c,0x03,0x0f,0x00, ++0x00,0xc2,0x30,0x24,0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x86,0x94,0xa0, ++0x10,0xa2,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x8e,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x02,0x2e,0x00,0x00,0x00,0x00,0xa3,0x80,0x80,0x11,0x08,0x00,0x02,0xdd, ++0x00,0x00,0x00,0x00,0x97,0x82,0x8b,0xae,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x8b,0xae,0x84,0xa3,0x00,0x06,0x8f,0x82,0x8b,0xc0,0x00,0x00,0x00,0x00, ++0x00,0x43,0x10,0x21,0xaf,0x82,0x8b,0xc0,0x08,0x00,0x02,0xd5,0x25,0x42,0x00,0x01, ++0x97,0x82,0x8b,0xaa,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0xaa, ++0x84,0xa3,0x00,0x06,0x8f,0x82,0x8b,0xb8,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21, ++0xaf,0x82,0x8b,0xb8,0x08,0x00,0x02,0xd5,0x25,0x42,0x00,0x01,0x97,0x82,0x8b,0xa4, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xa7,0x82,0x8b,0xa4,0x08,0x00,0x02,0xbd, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd0,0xaf,0xbf,0x00,0x28,0x8c,0xa3,0x00,0x20, ++0x8f,0x8a,0x94,0xa0,0x3c,0x02,0x00,0x10,0x00,0x62,0x10,0x24,0x00,0xa0,0x38,0x21, ++0x01,0x40,0x48,0x21,0x10,0x40,0x00,0x3d,0x00,0x80,0x28,0x21,0x8c,0xe4,0x00,0x1c, ++0x34,0xa5,0x12,0x06,0xaf,0xa5,0x00,0x10,0x8c,0x82,0x00,0x08,0x00,0x03,0x1c,0x42, ++0x30,0x63,0x00,0x30,0x00,0x02,0x13,0x02,0x30,0x42,0x00,0x40,0x00,0x43,0x10,0x25, ++0x90,0xe6,0x00,0x10,0x90,0xe4,0x00,0x13,0x94,0xe8,0x00,0x0c,0x94,0xe3,0x00,0x1a, ++0x00,0x02,0x16,0x00,0x90,0xe7,0x00,0x12,0x00,0xa2,0x28,0x25,0x24,0x02,0x12,0x34, ++0xa7,0xa2,0x00,0x1c,0x24,0x02,0x56,0x78,0xaf,0xa5,0x00,0x10,0xa3,0xa6,0x00,0x18, ++0xa3,0xa7,0x00,0x1f,0xa7,0xa3,0x00,0x1a,0xa3,0xa4,0x00,0x19,0xa7,0xa8,0x00,0x20, ++0xa7,0xa2,0x00,0x22,0x00,0x00,0x28,0x21,0x27,0xa7,0x00,0x10,0x24,0x06,0x8f,0xff, ++0x00,0x05,0x10,0x80,0x00,0x47,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xa3,0x00,0x01, ++0x30,0x65,0x00,0xff,0x25,0x22,0x00,0x04,0x2c,0xa3,0x00,0x05,0xad,0x24,0x00,0x00, ++0x14,0x60,0xff,0xf7,0x00,0x46,0x48,0x24,0x97,0x83,0x94,0xa6,0x97,0x85,0x94,0xa4, ++0x3c,0x02,0xb0,0x02,0x24,0x63,0x00,0x14,0x00,0xa2,0x28,0x21,0x3c,0x04,0xb0,0x06, ++0xa7,0x83,0x94,0xa6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00,0x8c,0x85,0x00,0x00, ++0x24,0x02,0x8f,0xff,0x25,0x46,0x00,0x14,0x3c,0x03,0x0f,0x00,0x00,0xc2,0x50,0x24, ++0x00,0xa3,0x28,0x24,0x3c,0x02,0x04,0x00,0xaf,0x8a,0x94,0xa0,0x10,0xa2,0x00,0x03, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x8e,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x28, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x3c,0x05,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xc8,0x00,0x04,0x22,0x00,0x34,0xa5,0x00,0x20, ++0x24,0x42,0x0d,0xdc,0x3c,0x03,0xb0,0x00,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20, ++0xaf,0xb2,0x00,0x18,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x30,0x00,0x83,0x80,0x21, ++0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb3,0x00,0x1c,0xaf,0xb1,0x00,0x14, ++0xac,0xa2,0x00,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x90,0x21,0x26,0x10,0x00,0x08, ++0x00,0x09,0xa6,0x02,0x12,0x80,0x00,0x13,0x00,0x00,0xa8,0x21,0x24,0x13,0x00,0x02, ++0x3c,0x16,0x00,0xff,0x3c,0x17,0xff,0x00,0x8e,0x09,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x09,0x12,0x02,0x24,0x42,0x00,0x02,0x31,0x25,0x00,0xff,0x10,0xb3,0x00,0x76, ++0x30,0x51,0x00,0xff,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x18,0x00,0x00,0x00,0x00, ++0x02,0x51,0x10,0x21,0x30,0x52,0xff,0xff,0x02,0x54,0x18,0x2b,0x14,0x60,0xff,0xf2, ++0x02,0x11,0x80,0x21,0x12,0xa0,0x00,0x0a,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18, ++0x8c,0x43,0x00,0x00,0x3c,0x04,0x0f,0x00,0x3c,0x02,0x04,0x00,0x00,0x64,0x18,0x24, ++0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00,0x0c,0x00,0x04,0x8e,0x00,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x30,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x8e,0x09,0x00,0x04, ++0x24,0x15,0x00,0x01,0x8e,0x06,0x00,0x0c,0x00,0x09,0x11,0x42,0x00,0x09,0x18,0xc2, ++0x30,0x48,0x00,0x03,0x00,0x09,0x14,0x02,0x30,0x6c,0x00,0x03,0x00,0x09,0x26,0x02, ++0x11,0x15,0x00,0x45,0x30,0x43,0x00,0x0f,0x29,0x02,0x00,0x02,0x14,0x40,0x00,0x26, ++0x00,0x00,0x00,0x00,0x11,0x13,0x00,0x0f,0x00,0x00,0x38,0x21,0x00,0x07,0x22,0x02, ++0x30,0x84,0xff,0x00,0x3c,0x03,0x00,0xff,0x00,0x07,0x2e,0x02,0x00,0x07,0x12,0x00, ++0x00,0x43,0x10,0x24,0x00,0xa4,0x28,0x25,0x00,0xa2,0x28,0x25,0x00,0x07,0x1e,0x00, ++0x00,0xa3,0x28,0x25,0x0c,0x00,0x01,0x92,0x01,0x20,0x20,0x21,0x08,0x00,0x03,0x9d, ++0x02,0x51,0x10,0x21,0x11,0x95,0x00,0x0f,0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x07, ++0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x80,0x27,0x83,0x94,0x50,0x00,0x43,0x10,0x21, ++0x8c,0x47,0x00,0x18,0x08,0x00,0x03,0xc4,0x00,0x07,0x22,0x02,0x00,0x04,0x10,0x40, ++0x27,0x83,0x94,0x58,0x00,0x43,0x10,0x21,0x94,0x47,0x00,0x02,0x08,0x00,0x03,0xc4, ++0x00,0x07,0x22,0x02,0x27,0x82,0x94,0x50,0x00,0x82,0x10,0x21,0x90,0x47,0x00,0x00, ++0x08,0x00,0x03,0xc4,0x00,0x07,0x22,0x02,0x15,0x00,0xff,0xdc,0x00,0x00,0x38,0x21, ++0x10,0x75,0x00,0x05,0x00,0x80,0x38,0x21,0x00,0x65,0x18,0x26,0x24,0x82,0x01,0x00, ++0x00,0x00,0x38,0x21,0x00,0x43,0x38,0x0a,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x0e, ++0x3c,0x02,0xb0,0x03,0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x06,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x8c,0x47,0x00,0x00,0x08,0x00,0x03,0xc4, ++0x00,0x07,0x22,0x02,0x3c,0x02,0xb0,0x03,0x00,0xe2,0x10,0x21,0x94,0x43,0x00,0x00, ++0x08,0x00,0x03,0xc3,0x30,0x67,0xff,0xff,0x00,0xe2,0x10,0x21,0x90,0x43,0x00,0x00, ++0x08,0x00,0x03,0xc3,0x30,0x67,0x00,0xff,0x30,0x62,0x00,0x03,0x00,0x02,0x12,0x00, ++0x11,0x95,0x00,0x07,0x00,0x44,0x38,0x21,0x11,0x93,0x00,0x03,0x00,0x00,0x00,0x00, ++0x08,0x00,0x03,0xf5,0x3c,0x02,0xb0,0x0a,0x08,0x00,0x03,0xfa,0x3c,0x02,0xb0,0x0a, ++0x08,0x00,0x03,0xfe,0x3c,0x02,0xb0,0x0a,0x8e,0x09,0x00,0x04,0x8e,0x02,0x00,0x08, ++0x8e,0x03,0x00,0x0c,0x00,0x09,0x41,0x42,0x00,0x02,0x22,0x02,0x00,0x03,0x3a,0x02, ++0x30,0x84,0xff,0x00,0x30,0xe7,0xff,0x00,0x00,0x02,0x5e,0x02,0x00,0x02,0x32,0x00, ++0x00,0x03,0x56,0x02,0x00,0x03,0x2a,0x00,0x01,0x64,0x58,0x25,0x00,0xd6,0x30,0x24, ++0x01,0x47,0x50,0x25,0x00,0x02,0x16,0x00,0x00,0xb6,0x28,0x24,0x00,0x03,0x1e,0x00, ++0x01,0x66,0x58,0x25,0x01,0x45,0x50,0x25,0x00,0x57,0x10,0x24,0x00,0x77,0x18,0x24, ++0x01,0x62,0x38,0x25,0x01,0x43,0x30,0x25,0x00,0x09,0x10,0xc2,0x00,0x09,0x1c,0x02, ++0x31,0x08,0x00,0x03,0x30,0x4c,0x00,0x03,0x30,0x63,0x00,0x0f,0x00,0x09,0x26,0x02, ++0x00,0xe0,0x58,0x21,0x15,0x00,0x00,0x28,0x00,0xc0,0x50,0x21,0x24,0x02,0x00,0x01, ++0x10,0x62,0x00,0x06,0x00,0x80,0x28,0x21,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0x69, ++0x02,0x51,0x10,0x21,0x24,0x85,0x01,0x00,0x24,0x02,0x00,0x01,0x11,0x82,0x00,0x15, ++0x24,0x02,0x00,0x02,0x11,0x82,0x00,0x0a,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21, ++0x8c,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24, ++0x00,0x45,0x10,0x25,0xac,0x62,0x00,0x00,0x08,0x00,0x03,0x9d,0x02,0x51,0x10,0x21, ++0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24, ++0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25,0xa4,0x62,0x00,0x00,0x08,0x00,0x03,0x9d, ++0x02,0x51,0x10,0x21,0x3c,0x03,0xb0,0x03,0x00,0xa3,0x18,0x21,0x90,0x62,0x00,0x00, ++0x00,0x0a,0x20,0x27,0x01,0x6a,0x28,0x24,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, ++0x08,0x00,0x03,0x9c,0xa0,0x62,0x00,0x00,0x24,0x02,0x00,0x01,0x11,0x02,0x00,0x21, ++0x00,0x00,0x00,0x00,0x15,0x13,0xff,0x42,0x00,0x00,0x00,0x00,0x11,0x82,0x00,0x17, ++0x00,0x00,0x00,0x00,0x11,0x88,0x00,0x0b,0x00,0x00,0x00,0x00,0x27,0x83,0x94,0x50, ++0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x18,0x00,0x06,0x18,0x27, ++0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x03,0x9c, ++0xac,0x82,0x00,0x18,0x27,0x83,0x94,0x58,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x21, ++0x94,0x82,0x00,0x02,0x00,0x06,0x18,0x27,0x00,0xe6,0x28,0x24,0x00,0x43,0x10,0x24, ++0x00,0x45,0x10,0x25,0x08,0x00,0x03,0x9c,0xa4,0x82,0x00,0x02,0x27,0x83,0x94,0x50, ++0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x52, ++0x00,0xe6,0x28,0x24,0x30,0x62,0x00,0x07,0x00,0x02,0x12,0x00,0x11,0x88,0x00,0x0f, ++0x00,0x44,0x10,0x21,0x11,0x93,0x00,0x07,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a, ++0x00,0x43,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x3f, ++0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x18,0x21,0x94,0x62,0x00,0x00, ++0x00,0x06,0x20,0x27,0x08,0x00,0x04,0x48,0x00,0xe6,0x28,0x24,0x3c,0x03,0xb0,0x0a, ++0x08,0x00,0x04,0x75,0x00,0x43,0x18,0x21,0x97,0x85,0x94,0xa4,0x3c,0x07,0xb0,0x02, ++0x3c,0x04,0xb0,0x03,0x3c,0x02,0x80,0x00,0x00,0xa7,0x28,0x21,0x34,0x84,0x00,0x20, ++0x24,0x42,0x12,0x38,0x24,0x03,0xff,0x80,0xac,0x82,0x00,0x00,0xa0,0xa3,0x00,0x07, ++0x97,0x82,0x94,0xa6,0x97,0x85,0x94,0xa4,0x3c,0x06,0xb0,0x06,0x30,0x42,0xff,0xf8, ++0x24,0x42,0x00,0x10,0x00,0xa2,0x10,0x21,0x30,0x42,0x0f,0xff,0x24,0x44,0x00,0x08, ++0x30,0x84,0x0f,0xff,0x00,0x05,0x28,0xc2,0x3c,0x03,0x00,0x40,0x00,0xa3,0x28,0x25, ++0x00,0x87,0x20,0x21,0x34,0xc6,0x80,0x18,0xac,0xc5,0x00,0x00,0xaf,0x84,0x94,0xa0, ++0xa7,0x82,0x94,0xa4,0xa7,0x80,0x94,0xa6,0xaf,0x80,0x94,0xa8,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff,0x30,0x84,0x00,0xff,0x24,0x02,0x00,0x01, ++0x00,0xe0,0x48,0x21,0x30,0xc6,0x00,0xff,0x8f,0xa7,0x00,0x10,0x10,0x82,0x00,0x07, ++0x00,0xa0,0x40,0x21,0x24,0x02,0x00,0x03,0x10,0x82,0x00,0x03,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0xa8,0x01,0x00,0x3c,0x03,0xb0,0x03, ++0x24,0x02,0x00,0x01,0x00,0x07,0x20,0x27,0x01,0x27,0x28,0x24,0x10,0xc2,0x00,0x14, ++0x01,0x03,0x18,0x21,0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0x09,0x00,0x07,0x50,0x27, ++0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25,0x08,0x00,0x04,0xd9,0xac,0x62,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x01,0x03,0x18,0x21,0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x4a,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xa4,0x62,0x00,0x00, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x24,0x00,0x45,0x10,0x25, ++0xa0,0x62,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0x07, ++0x00,0x04,0x22,0x00,0x30,0xa5,0x00,0xff,0x00,0x85,0x28,0x21,0x3c,0x02,0xb0,0x0a, ++0x00,0xa2,0x40,0x21,0x30,0xc6,0x00,0xff,0x24,0x02,0x00,0x01,0x8f,0xa4,0x00,0x10, ++0x10,0xc2,0x00,0x14,0x24,0x02,0x00,0x02,0x00,0x04,0x50,0x27,0x10,0xc2,0x00,0x09, ++0x00,0xe4,0x48,0x24,0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08, ++0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x00,0xa3,0x18,0x21,0x94,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x4a,0x10,0x24,0x00,0x49,0x10,0x25,0x03,0xe0,0x00,0x08, ++0xa4,0x62,0x00,0x00,0x91,0x02,0x00,0x00,0x00,0x04,0x18,0x27,0x00,0xe4,0x20,0x24, ++0x00,0x43,0x10,0x24,0x00,0x44,0x10,0x25,0x03,0xe0,0x00,0x08,0xa1,0x02,0x00,0x00, ++0x30,0xa9,0x00,0xff,0x27,0x83,0x94,0x50,0x30,0x85,0x00,0xff,0x24,0x02,0x00,0x01, ++0x00,0x07,0x50,0x27,0x00,0xc7,0x40,0x24,0x11,0x22,0x00,0x17,0x00,0xa3,0x18,0x21, ++0x00,0x05,0x20,0x40,0x27,0x82,0x94,0x50,0x00,0x05,0x28,0x80,0x27,0x83,0x94,0x58, ++0x00,0x83,0x50,0x21,0x00,0xa2,0x20,0x21,0x24,0x02,0x00,0x02,0x00,0x07,0x40,0x27, ++0x11,0x22,0x00,0x07,0x00,0xc7,0x28,0x24,0x8c,0x82,0x00,0x18,0x00,0x00,0x00,0x00, ++0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x18, ++0x95,0x42,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x48,0x10,0x24,0x00,0x45,0x10,0x25, ++0x03,0xe0,0x00,0x08,0xa5,0x42,0x00,0x02,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x4a,0x10,0x24,0x00,0x48,0x10,0x25,0x03,0xe0,0x00,0x08,0xa0,0x62,0x00,0x00, ++0x00,0x04,0x32,0x02,0x30,0xc6,0xff,0x00,0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00, ++0x3c,0x05,0x00,0xff,0x00,0x65,0x18,0x24,0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25, ++0x00,0x04,0x26,0x00,0x03,0xe0,0x00,0x08,0x00,0x44,0x10,0x25,0x3c,0x02,0xb0,0x02, ++0x34,0x42,0x00,0x08,0x3c,0x03,0xb0,0x02,0xaf,0x82,0x8c,0x78,0xaf,0x83,0x8c,0x7c, ++0xa7,0x80,0x8c,0x80,0xa7,0x80,0x8c,0x82,0xaf,0x80,0x8c,0x84,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xbf,0x00,0x20,0x94,0x82,0x00,0x04, ++0x3c,0x05,0xff,0x8f,0x00,0x80,0x18,0x21,0x30,0x42,0xe0,0x00,0x14,0x40,0x00,0x0a, ++0x34,0xa5,0xff,0xff,0x90,0x84,0x00,0x02,0x00,0x00,0x00,0x00,0x30,0x84,0x00,0xfc, ++0x00,0x64,0x20,0x21,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa2,0x10,0x2b, ++0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x20,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x0c,0x00,0x07,0xc9,0x00,0x00,0x00,0x00, ++0x08,0x00,0x05,0x4a,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xd8,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c, ++0x8f,0x90,0x94,0xa0,0x0c,0x00,0x30,0x54,0x00,0x80,0x90,0x21,0x00,0x40,0x88,0x21, ++0x93,0x82,0x82,0x28,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1b,0x24,0x02,0x00,0x01, ++0xa3,0x82,0x82,0x28,0x24,0x03,0x00,0x05,0x24,0x02,0x00,0x04,0xa3,0x83,0x8c,0x73, ++0xa3,0x82,0x8c,0x72,0xa7,0x80,0x82,0x2a,0x00,0x00,0x28,0x21,0x27,0x86,0x8c,0x70, ++0x00,0x05,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x44,0x00,0x00,0x24,0xa3,0x00,0x01, ++0x30,0x65,0xff,0xff,0xae,0x04,0x00,0x00,0x10,0xa0,0xff,0xfa,0x00,0x05,0x10,0x80, ++0x8f,0x83,0x94,0xa0,0x97,0x82,0x94,0xa6,0x24,0x05,0x8f,0xff,0x24,0x63,0x00,0x04, ++0x00,0x65,0x18,0x24,0x26,0x04,0x00,0x04,0x24,0x42,0x00,0x04,0xaf,0x83,0x94,0xa0, ++0xa7,0x82,0x94,0xa6,0x00,0x85,0x80,0x24,0x97,0x84,0x82,0x2a,0x27,0x93,0x80,0x34, ++0x02,0x40,0x28,0x21,0x00,0x93,0x20,0x21,0x0c,0x00,0x30,0xd8,0x02,0x20,0x30,0x21, ++0x97,0x87,0x82,0x2a,0x24,0x02,0x00,0x52,0x00,0xf1,0x18,0x21,0xa7,0x83,0x82,0x2a, ++0x82,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x06,0x00,0x60,0x38,0x21, ++0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x28,0x82,0x43,0x00,0x01,0x24,0x02,0x00,0x54,0x14,0x62,0xff,0xf8, ++0x24,0x02,0x00,0x4c,0x82,0x43,0x00,0x02,0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xf4, ++0x00,0x00,0x00,0x00,0x30,0xe6,0xff,0xff,0x10,0xc0,0x00,0x0c,0x00,0x00,0x28,0x21, ++0x02,0x60,0x48,0x21,0x24,0x08,0x8f,0xff,0x00,0xa9,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x24,0xa3,0x00,0x04,0x30,0x65,0xff,0xff,0x26,0x02,0x00,0x04,0x00,0xa6,0x18,0x2b, ++0xae,0x04,0x00,0x00,0x14,0x60,0xff,0xf8,0x00,0x48,0x80,0x24,0x97,0x83,0x94,0xa6, ++0x97,0x85,0x94,0xa4,0x3c,0x02,0xb0,0x02,0x00,0x67,0x18,0x21,0x00,0xa2,0x28,0x21, ++0x3c,0x04,0xb0,0x06,0xa7,0x83,0x94,0xa6,0x34,0x84,0x80,0x18,0xa4,0xa3,0x00,0x00, ++0x8f,0x82,0x94,0xa0,0x8c,0x86,0x00,0x00,0x30,0xe5,0xff,0xff,0x24,0x03,0x8f,0xff, ++0x00,0x45,0x10,0x21,0x3c,0x04,0x0f,0x00,0x00,0x43,0x10,0x24,0x00,0xc4,0x30,0x24, ++0x3c,0x03,0x04,0x00,0xaf,0x82,0x94,0xa0,0x10,0xc3,0xff,0xd1,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x04,0x8e,0x00,0x00,0x00,0x00,0xa3,0x80,0x82,0x28,0x08,0x00,0x05,0x88, ++0x00,0x00,0x00,0x00,0x8f,0x82,0x8c,0x7c,0x97,0x83,0x8c,0x80,0x8f,0x87,0x8c,0x78, ++0x3c,0x06,0xff,0xff,0xac,0x43,0x00,0x00,0x8f,0x82,0x8c,0x7c,0x3c,0x03,0x80,0x00, ++0x24,0xe5,0x00,0x08,0xac,0x43,0x00,0x04,0x8f,0x82,0x8c,0x7c,0x34,0xc6,0x1f,0xff, ++0x3c,0x03,0x00,0x40,0x30,0x42,0x0f,0xff,0x3c,0x04,0xb0,0x06,0x00,0x02,0x10,0xc2, ++0x00,0x43,0x10,0x25,0x00,0xa6,0x28,0x24,0x34,0x84,0x80,0x18,0x27,0xbd,0xff,0xf8, ++0xac,0x82,0x00,0x00,0xaf,0x85,0x8c,0x78,0xaf,0x87,0x8c,0x7c,0xa7,0x80,0x8c,0x80, ++0xa7,0x80,0x8c,0x82,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0, ++0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x8f,0x91,0x8c,0x78, ++0x00,0x80,0x80,0x21,0xaf,0xbf,0x00,0x1c,0x0c,0x00,0x06,0x78,0x00,0xa0,0x90,0x21, ++0x97,0x82,0x8c,0x80,0x36,0x10,0x12,0x00,0x26,0x2a,0x00,0x04,0x24,0x4c,0x00,0x14, ++0x2c,0x42,0x04,0x01,0x14,0x40,0x00,0x0a,0x24,0x09,0x8f,0xff,0x8f,0x82,0x80,0x20, ++0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x80,0x20,0x8f,0xbf,0x00,0x1c, ++0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, ++0x8e,0x44,0x00,0x1c,0x86,0x47,0x00,0x06,0x97,0x86,0x8c,0x82,0x8c,0x82,0x00,0x08, ++0x00,0x07,0x3c,0x00,0x8f,0x85,0x8c,0x78,0x00,0x02,0x11,0x02,0x30,0x42,0x40,0x00, ++0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00,0x8c,0x82,0x00,0x04,0x82,0x43,0x00,0x15, ++0x01,0x49,0x88,0x24,0x00,0x02,0x14,0xc2,0x00,0x03,0x1a,0x00,0x00,0x02,0x14,0x00, ++0x00,0x62,0x80,0x25,0xae,0x30,0x00,0x00,0x92,0x43,0x00,0x13,0x92,0x44,0x00,0x10, ++0x96,0x50,0x00,0x1a,0x00,0x03,0x1c,0x00,0x00,0x04,0x26,0x00,0x02,0x03,0x80,0x25, ++0x26,0x22,0x00,0x04,0x00,0x49,0x88,0x24,0x02,0x04,0x80,0x25,0xae,0x30,0x00,0x00, ++0x92,0x42,0x00,0x0f,0x92,0x43,0x00,0x11,0x26,0x24,0x00,0x04,0x00,0x02,0x12,0x00, ++0x00,0x89,0x88,0x24,0x00,0x62,0x80,0x25,0x02,0x07,0x80,0x25,0x26,0x22,0x00,0x04, ++0xae,0x30,0x00,0x00,0x00,0x49,0x88,0x24,0xae,0x20,0x00,0x00,0x8f,0x82,0x80,0x1c, ++0x24,0xc6,0x00,0x01,0x24,0xa5,0x00,0x14,0x30,0xc8,0xff,0xff,0x3c,0x0b,0xb0,0x03, ++0x00,0xa9,0x28,0x24,0x24,0x42,0x00,0x01,0x2d,0x08,0x00,0x0a,0xaf,0x85,0x8c,0x78, ++0xa7,0x8c,0x8c,0x80,0xaf,0x82,0x80,0x1c,0xa7,0x86,0x8c,0x82,0x11,0x00,0x00,0x07, ++0x35,0x6b,0x01,0x08,0x8f,0x82,0x8c,0x84,0x8d,0x63,0x00,0x00,0x24,0x42,0x04,0x00, ++0x00,0x62,0x18,0x2b,0x14,0x60,0xff,0xc1,0x00,0x00,0x00,0x00,0x0c,0x00,0x05,0xbd, ++0x00,0x00,0x00,0x00,0x08,0x00,0x05,0xf3,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8, ++0xaf,0xbf,0x00,0x10,0x0c,0x00,0x06,0x78,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x27,0xbd,0xff,0xe0, ++0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c, ++0x8f,0x90,0x8c,0x78,0x0c,0x00,0x06,0x78,0x00,0x80,0x90,0x21,0x97,0x82,0x8c,0x80, ++0x24,0x11,0x8f,0xff,0x2c,0x42,0x04,0x01,0x14,0x40,0x00,0x06,0x26,0x03,0x00,0x04, ++0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x24,0x02,0x0e,0x03,0xae,0x02,0x00,0x00,0x00,0x71,0x80,0x24, ++0xae,0x00,0x00,0x00,0x8e,0x44,0x00,0x08,0x26,0x02,0x00,0x04,0x0c,0x00,0x06,0x86, ++0x00,0x51,0x80,0x24,0x97,0x86,0x8c,0x82,0x8f,0x83,0x8c,0x78,0xae,0x02,0x00,0x00, ++0x97,0x82,0x8c,0x80,0x24,0xc6,0x00,0x01,0x8e,0x47,0x00,0x0c,0x24,0x63,0x00,0x10, ++0x30,0xc5,0xff,0xff,0x26,0x04,0x00,0x04,0x3c,0x08,0xb0,0x03,0x00,0x71,0x18,0x24, ++0x00,0x91,0x80,0x24,0x24,0x42,0x00,0x10,0x2c,0xa5,0x00,0x0a,0x35,0x08,0x01,0x08, ++0xae,0x07,0x00,0x00,0xaf,0x83,0x8c,0x78,0xa7,0x82,0x8c,0x80,0xa7,0x86,0x8c,0x82, ++0x10,0xa0,0x00,0x07,0x00,0x00,0x00,0x00,0x8f,0x82,0x8c,0x84,0x8d,0x03,0x00,0x00, ++0x24,0x42,0x04,0x00,0x00,0x62,0x18,0x2b,0x14,0x60,0xff,0xd9,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x05,0xbd,0x00,0x00,0x00,0x00,0x08,0x00,0x06,0x4c,0x00,0x00,0x00,0x00, ++0x97,0x82,0x8c,0x82,0x3c,0x03,0xb0,0x03,0x14,0x40,0x00,0x09,0x34,0x63,0x01,0x08, ++0x8c,0x62,0x00,0x00,0x8f,0x83,0x8c,0x7c,0xa7,0x80,0x8c,0x80,0xaf,0x82,0x8c,0x84, ++0xac,0x60,0x00,0x00,0x8f,0x82,0x8c,0x7c,0x00,0x00,0x00,0x00,0xac,0x40,0x00,0x04, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x32,0x02,0x30,0xc6,0xff,0x00, ++0x00,0x04,0x16,0x02,0x00,0x04,0x1a,0x00,0x3c,0x05,0x00,0xff,0x00,0x65,0x18,0x24, ++0x00,0x46,0x10,0x25,0x00,0x43,0x10,0x25,0x00,0x04,0x26,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x44,0x10,0x25,0x80,0x82,0x00,0x00,0x90,0x83,0x00,0x00,0x10,0x40,0x00,0x0c, ++0x00,0x80,0x28,0x21,0x24,0x62,0xff,0x9f,0x30,0x42,0x00,0xff,0x2c,0x42,0x00,0x1a, ++0x10,0x40,0x00,0x02,0x24,0x63,0xff,0xe0,0xa0,0xa3,0x00,0x00,0x24,0xa5,0x00,0x01, ++0x90,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xf6,0x00,0x40,0x18,0x21, ++0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x80,0x82,0x00,0x00,0x90,0x83,0x00,0x00, ++0x10,0x40,0x00,0x0c,0x00,0x80,0x28,0x21,0x24,0x62,0xff,0xbf,0x30,0x42,0x00,0xff, ++0x2c,0x42,0x00,0x1a,0x10,0x40,0x00,0x02,0x24,0x63,0x00,0x20,0xa0,0xa3,0x00,0x00, ++0x24,0xa5,0x00,0x01,0x90,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xf6, ++0x00,0x40,0x18,0x21,0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x27,0xbd,0xff,0xe8, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0x24,0x10,0xff,0xff,0x0c,0x00,0x2d,0x94, ++0x00,0x00,0x00,0x00,0x10,0x50,0xff,0xfd,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, ++0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x27,0xbd,0xff,0xc8,0xaf,0xb3,0x00,0x1c,0x00,0x00,0x98,0x21,0xaf,0xb1,0x00,0x14, ++0x02,0x65,0x88,0x2b,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x34,0xaf,0xbe,0x00,0x30,0xaf,0xb7,0x00,0x2c,0xaf,0xb4,0x00,0x20, ++0xaf,0xb2,0x00,0x18,0x00,0xa0,0xb0,0x21,0xaf,0xa4,0x00,0x38,0x00,0xc0,0xa8,0x21, ++0x12,0x20,0x00,0x17,0x00,0x80,0x80,0x21,0x24,0x17,0xff,0xff,0x24,0x1e,0x00,0x0a, ++0x0c,0x00,0x2d,0x94,0x00,0x00,0x00,0x00,0x10,0x57,0x00,0x0f,0x00,0x02,0x16,0x00, ++0x00,0x02,0x26,0x03,0x10,0x9e,0x00,0x0e,0x24,0x02,0x00,0x0d,0x10,0x82,0x00,0x34, ++0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x25,0x24,0x02,0x00,0x09,0x10,0x82,0x00,0x13, ++0x00,0x00,0x90,0x21,0xa2,0x04,0x00,0x00,0x26,0x73,0x00,0x01,0x16,0xa0,0x00,0x0b, ++0x26,0x10,0x00,0x01,0x02,0x76,0x88,0x2b,0x16,0x20,0xff,0xed,0x00,0x00,0x00,0x00, ++0x7b,0xbe,0x01,0xbc,0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x0c,0x00,0x2d,0x87, ++0x02,0x76,0x88,0x2b,0x08,0x00,0x06,0xe6,0x00,0x00,0x00,0x00,0x24,0x14,0x00,0x20, ++0xa2,0x14,0x00,0x00,0x26,0x52,0x00,0x01,0x24,0x04,0x00,0x20,0x26,0x73,0x00,0x01, ++0x16,0xa0,0x00,0x06,0x26,0x10,0x00,0x01,0x2a,0x42,0x00,0x08,0x10,0x40,0xff,0xea, ++0x02,0x76,0x88,0x2b,0x08,0x00,0x06,0xf5,0xa2,0x14,0x00,0x00,0x0c,0x00,0x2d,0x87, ++0x00,0x00,0x00,0x00,0x08,0x00,0x06,0xfb,0x2a,0x42,0x00,0x08,0x8f,0xa2,0x00,0x38, ++0x00,0x00,0x00,0x00,0x12,0x02,0xff,0xe0,0x00,0x00,0x00,0x00,0x26,0x10,0xff,0xff, ++0x12,0xa0,0xff,0xdc,0x26,0x73,0xff,0xff,0x0c,0x00,0x2d,0x87,0x24,0x04,0x00,0x08, ++0x0c,0x00,0x2d,0x87,0x24,0x04,0x00,0x20,0x08,0x00,0x06,0xef,0x24,0x04,0x00,0x08, ++0x08,0x00,0x06,0xe8,0xa2,0x00,0x00,0x00,0x90,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x02,0x1e,0x00,0x10,0x60,0x00,0x16,0x00,0x00,0x30,0x21,0x24,0x07,0x00,0x20, ++0x00,0x03,0x1e,0x03,0x10,0x67,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x15, ++0x00,0x00,0x00,0x00,0x10,0x67,0x00,0x0b,0x24,0xc6,0x00,0x01,0x10,0x60,0x00,0x0a, ++0x00,0x02,0x1e,0x00,0x24,0x05,0x00,0x20,0x24,0x84,0x00,0x01,0x80,0x83,0x00,0x00, ++0x90,0x82,0x00,0x00,0x10,0x65,0x00,0x03,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xfa, ++0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00,0x14,0x60,0xff,0xed,0x00,0x00,0x00,0x00, ++0x28,0xc3,0x00,0x08,0x24,0x02,0x00,0x07,0x00,0x43,0x30,0x0a,0x03,0xe0,0x00,0x08, ++0x00,0xc0,0x10,0x21,0x24,0x84,0x00,0x01,0x90,0x82,0x00,0x00,0x08,0x00,0x07,0x2a, ++0x00,0x02,0x1e,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb1,0x00,0x14,0x27,0x91,0x8c,0x88, ++0xaf,0xb0,0x00,0x10,0x24,0x06,0x00,0x20,0x00,0x80,0x80,0x21,0x00,0x00,0x28,0x21, ++0xaf,0xbf,0x00,0x18,0x0c,0x00,0x30,0xce,0x02,0x20,0x20,0x21,0x82,0x02,0x00,0x00, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x1f,0x00,0x00,0x30,0x21,0x02,0x20,0x20,0x21, ++0x24,0x09,0x00,0x20,0x24,0x08,0x00,0x20,0x24,0x07,0x00,0x08,0xac,0x90,0x00,0x00, ++0x82,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x49,0x00,0x0a,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x08,0x24,0x03,0x00,0x20,0x26,0x10,0x00,0x01,0x82,0x02,0x00,0x00, ++0x00,0x00,0x00,0x00,0x10,0x43,0x00,0x03,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfa, ++0x00,0x00,0x00,0x00,0xa2,0x00,0x00,0x00,0x26,0x10,0x00,0x01,0x82,0x02,0x00,0x00, ++0x92,0x03,0x00,0x00,0x10,0x48,0x00,0x0c,0x24,0x05,0x00,0x20,0x24,0xc6,0x00,0x01, ++0x10,0xc7,0x00,0x04,0x24,0x84,0x00,0x04,0x00,0x03,0x16,0x00,0x14,0x40,0xff,0xe7, ++0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x27,0x82,0x8c,0x88, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x26,0x10,0x00,0x01,0x82,0x02,0x00,0x00, ++0x92,0x03,0x00,0x00,0x10,0x45,0xff,0xfc,0x00,0x00,0x00,0x00,0x08,0x00,0x07,0x5c, ++0x24,0xc6,0x00,0x01,0x00,0x80,0x30,0x21,0x90,0x84,0x00,0x00,0x00,0x00,0x38,0x21, ++0x10,0x80,0x00,0x19,0x24,0xc6,0x00,0x01,0x24,0x82,0xff,0xd0,0x30,0x42,0x00,0xff, ++0x2c,0x43,0x00,0x0a,0x14,0x60,0x00,0x0c,0x00,0x07,0x19,0x00,0x24,0x83,0xff,0x9f, ++0x24,0x82,0xff,0xa9,0x24,0x88,0xff,0xc9,0x2c,0x63,0x00,0x06,0x24,0x84,0xff,0xbf, ++0x2c,0x84,0x00,0x06,0x14,0x60,0x00,0x03,0x30,0x42,0x00,0xff,0x10,0x80,0x00,0x0e, ++0x31,0x02,0x00,0xff,0x00,0x07,0x19,0x00,0x00,0x62,0x18,0x21,0x00,0x67,0x10,0x2b, ++0x14,0x40,0x00,0x07,0x00,0x00,0x20,0x21,0x90,0xc4,0x00,0x00,0x00,0x60,0x38,0x21, ++0x14,0x80,0xff,0xe9,0x24,0xc6,0x00,0x01,0xac,0xa7,0x00,0x00,0x24,0x04,0x00,0x01, ++0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x08,0x00,0x07,0x8c,0x00,0x00,0x20,0x21, ++0x00,0x00,0x20,0x21,0x27,0x85,0x94,0xc0,0x24,0x82,0x00,0x01,0x00,0x04,0x18,0x80, ++0x30,0x44,0x00,0xff,0x00,0x65,0x18,0x21,0x2c,0x82,0x00,0x0b,0x14,0x40,0xff,0xfa, ++0xac,0x60,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0xaf,0x84,0x8d,0x08, ++0xaf,0x85,0x8d,0x0c,0xaf,0x86,0x8d,0x10,0xaf,0x87,0x8d,0x14,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x8f,0x82,0x84,0x98,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, ++0x2c,0x43,0x00,0x64,0x24,0x42,0x00,0x01,0x27,0x84,0x8c,0xa8,0xaf,0x82,0x84,0x98, ++0x10,0x60,0x00,0x05,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0xaf,0x80,0x84,0x98,0x0c,0x00,0x07,0xf6, ++0x00,0x00,0x00,0x00,0x00,0x40,0x18,0x21,0x28,0x44,0x00,0x08,0x24,0x02,0x00,0x07, ++0x10,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x14,0x80,0xff,0xf3,0x24,0x02,0x00,0x08, ++0x27,0x84,0x8c,0xa8,0x14,0x62,0xff,0xf0,0x00,0x00,0x00,0x00,0x0c,0x00,0x1a,0x7e, ++0x00,0x00,0x00,0x00,0x27,0x84,0x8c,0xa8,0x0c,0x00,0x08,0x54,0x00,0x00,0x00,0x00, ++0x8f,0x83,0x84,0x9c,0x3c,0x04,0x80,0x01,0x00,0x60,0x28,0x21,0x24,0x63,0x00,0x01, ++0xaf,0x83,0x84,0x9c,0x0c,0x00,0x1a,0x6b,0x24,0x84,0x04,0x90,0x08,0x00,0x07,0xaa, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xc0,0xaf,0xbf,0x00,0x38,0x8c,0x85,0x00,0x0c, ++0x8c,0x88,0x00,0x08,0x18,0xa0,0x00,0x0e,0x00,0x00,0x30,0x21,0x24,0x87,0x00,0x08, ++0x27,0xa9,0x00,0x10,0x00,0x06,0x10,0x80,0x00,0x06,0x19,0x00,0x00,0x49,0x10,0x21, ++0x14,0xc0,0x00,0x1f,0x00,0x83,0x18,0x21,0xaf,0xa7,0x00,0x10,0x24,0xc2,0x00,0x01, ++0x30,0x46,0x00,0xff,0x00,0xc5,0x18,0x2a,0x14,0x60,0xff,0xf7,0x00,0x06,0x10,0x80, ++0x29,0x02,0x00,0x0a,0x14,0x40,0x00,0x05,0x00,0x08,0x18,0x40,0x8f,0xbf,0x00,0x38, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x00,0x68,0x18,0x21, ++0x27,0x82,0x83,0x94,0x00,0x03,0x18,0xc0,0x00,0x62,0x18,0x21,0x8c,0x62,0x00,0x10, ++0x01,0x00,0x20,0x21,0x00,0x40,0xf8,0x09,0x27,0xa6,0x00,0x10,0x8f,0x83,0x84,0xb0, ++0x3c,0x04,0x80,0x01,0x00,0x60,0x28,0x21,0x24,0x63,0x00,0x01,0xaf,0x83,0x84,0xb0, ++0x0c,0x00,0x1a,0x6b,0x24,0x84,0x04,0xa4,0x08,0x00,0x07,0xdf,0x00,0x00,0x00,0x00, ++0x08,0x00,0x07,0xd7,0xac,0x43,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb1,0x00,0x14, ++0xaf,0xbf,0x00,0x18,0x00,0x80,0x88,0x21,0x0c,0x00,0x1a,0xa2,0xaf,0xb0,0x00,0x10, ++0x00,0x40,0x20,0x21,0x24,0x02,0xff,0xff,0x10,0x82,0x00,0x1f,0x24,0x03,0x00,0x06, ++0x8f,0x85,0x84,0xc4,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x0a,0x24,0x02,0x00,0x08, ++0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x3b,0x28,0x82,0x00,0x03,0x10,0x40,0x00,0x32, ++0x24,0x02,0x00,0x1b,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x13,0x24,0x03,0x00,0x08, ++0x24,0x02,0x00,0x08,0x10,0x82,0x00,0x23,0x24,0x02,0x00,0x0d,0x10,0x82,0x00,0x18, ++0x02,0x25,0x10,0x21,0x24,0xa3,0x00,0x01,0xa0,0x44,0x00,0x00,0xaf,0x83,0x84,0xc4, ++0x18,0x60,0x00,0x08,0x24,0x02,0x00,0x43,0x82,0x23,0x00,0x00,0x00,0x00,0x00,0x00, ++0x10,0x62,0x00,0x0a,0x00,0x00,0x00,0x00,0x30,0x84,0xff,0xff,0x0c,0x00,0x1a,0x9e, ++0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x06,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x3c,0x04,0x80,0x01, ++0x0c,0x00,0x1a,0x7e,0x24,0x84,0x04,0xb8,0x08,0x00,0x08,0x1e,0x24,0x03,0x00,0x06, ++0xa0,0x40,0x00,0x00,0x24,0xa5,0x00,0x01,0xaf,0x85,0x84,0xc4,0x0c,0x00,0x1a,0x9e, ++0x24,0x04,0x00,0x0d,0x24,0x03,0x00,0x07,0xaf,0x80,0x84,0xc4,0x08,0x00,0x08,0x1e, ++0x00,0x00,0x00,0x00,0x18,0xa0,0xff,0xeb,0x24,0xa5,0xff,0xff,0xaf,0x85,0x84,0xc4, ++0x0c,0x00,0x1a,0x9e,0x24,0x04,0x00,0x08,0x0c,0x00,0x1a,0x9e,0x24,0x04,0x00,0x20, ++0x08,0x00,0x08,0x1b,0x24,0x04,0x00,0x08,0x14,0x82,0xff,0xd2,0x24,0x02,0x00,0x08, ++0x0c,0x00,0x07,0x90,0x00,0x00,0x00,0x00,0x8f,0x85,0x84,0xc4,0x08,0x00,0x08,0x0c, ++0x24,0x04,0x00,0x0d,0x0c,0x00,0x30,0x54,0x02,0x20,0x20,0x21,0xaf,0x82,0x84,0xc4, ++0x04,0x40,0x00,0x0d,0x00,0x00,0x80,0x21,0x02,0x30,0x10,0x21,0x90,0x44,0x00,0x00, ++0x26,0x10,0x00,0x01,0x00,0x04,0x26,0x00,0x00,0x04,0x26,0x03,0x0c,0x00,0x1a,0x9e, ++0x30,0x84,0xff,0xff,0x8f,0x83,0x84,0xc4,0x00,0x00,0x00,0x00,0x00,0x70,0x18,0x2a, ++0x10,0x60,0xff,0xf6,0x02,0x30,0x10,0x21,0x08,0x00,0x08,0x2e,0x24,0x03,0x00,0x06, ++0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x27,0x83,0x8c,0xe8,0x24,0x02,0x00,0x07, ++0x24,0x42,0xff,0xff,0xac,0x60,0x00,0x00,0x04,0x41,0xff,0xfd,0x24,0x63,0x00,0x04, ++0x0c,0x00,0x08,0x66,0x00,0x00,0x00,0x00,0x8f,0x84,0x8c,0xe8,0x27,0x86,0x8c,0xe8, ++0x0c,0x00,0x08,0x83,0x00,0x40,0x28,0x21,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x27,0xbd,0xff,0xe0,0x00,0x80,0x28,0x21, ++0x27,0x84,0x8c,0xc8,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0x0c,0x00,0x30,0xe5, ++0xaf,0xb0,0x00,0x10,0x8f,0x85,0x83,0x34,0x27,0x84,0x8c,0xc8,0x0c,0x00,0x30,0xa9, ++0x00,0x00,0x88,0x21,0x10,0x40,0x00,0x0c,0x00,0x00,0x00,0x00,0x27,0x90,0x8c,0xe8, ++0x8f,0x85,0x83,0x34,0x00,0x00,0x20,0x21,0xae,0x02,0x00,0x00,0x0c,0x00,0x30,0xa9, ++0x26,0x31,0x00,0x01,0x26,0x10,0x00,0x04,0x10,0x40,0x00,0x03,0x2a,0x23,0x00,0x64, ++0x14,0x60,0xff,0xf7,0x00,0x00,0x00,0x00,0x02,0x20,0x10,0x21,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd0, ++0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xbf,0x00,0x2c, ++0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0x00,0xa0,0xa8,0x21,0x00,0x80,0xa0,0x21,0x00,0xc0,0xb0,0x21,0x10,0xa0,0x00,0x1d, ++0x24,0x02,0x00,0x05,0x3c,0x02,0x80,0x00,0x24,0x43,0x2c,0x80,0x8f,0x82,0x83,0xa4, ++0x00,0x00,0x00,0x00,0x10,0x43,0x00,0x1e,0x00,0x00,0x88,0x21,0x00,0x60,0x98,0x21, ++0x00,0x00,0x90,0x21,0x27,0x90,0x83,0xa4,0x8e,0x05,0xff,0xec,0x02,0x80,0x20,0x21, ++0x0c,0x00,0x30,0xed,0x26,0x10,0x00,0x18,0x10,0x40,0x00,0x06,0x02,0x51,0x18,0x21, ++0x8e,0x02,0x00,0x00,0x26,0x31,0x00,0x01,0x14,0x53,0xff,0xf7,0x00,0x11,0x90,0x40, ++0x02,0x51,0x18,0x21,0x27,0x82,0x83,0x94,0x00,0x03,0x18,0xc0,0x00,0x62,0x18,0x21, ++0x8c,0x62,0x00,0x10,0x02,0x20,0x20,0x21,0x02,0xa0,0x28,0x21,0x00,0x40,0xf8,0x09, ++0x02,0xc0,0x30,0x21,0x8f,0xbf,0x00,0x2c,0x8f,0xb6,0x00,0x28,0x7b,0xb4,0x01,0x3c, ++0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30, ++0x08,0x00,0x08,0xa4,0x00,0x00,0x90,0x21,0x27,0xbd,0xff,0xc0,0xaf,0xb5,0x00,0x34, ++0xaf,0xb3,0x00,0x2c,0xaf,0xb1,0x00,0x24,0xaf,0xbf,0x00,0x38,0xaf,0xb4,0x00,0x30, ++0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20,0x00,0xc0,0x98,0x21,0x30,0xa5,0x00,0xff, ++0xac,0xc0,0x00,0x00,0x24,0x15,0x00,0x0a,0x00,0x00,0x88,0x21,0x27,0xa8,0x00,0x10, ++0x00,0x91,0x18,0x21,0x80,0x62,0x00,0x00,0x26,0x27,0x00,0x01,0x10,0x40,0x00,0x0c, ++0x01,0x11,0x30,0x21,0x90,0x63,0x00,0x00,0x30,0xf1,0x00,0xff,0x2e,0x22,0x00,0x0a, ++0x14,0x40,0xff,0xf7,0xa0,0xc3,0x00,0x00,0x8f,0xbf,0x00,0x38,0x7b,0xb4,0x01,0xbc, ++0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40, ++0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x23,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x1f, ++0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x1a,0x00,0x00,0x00,0x00,0x02,0x20,0x90,0x21, ++0x12,0x40,0xff,0xf1,0x00,0x00,0x88,0x21,0x27,0xb4,0x00,0x10,0x02,0x91,0x10,0x21, ++0x90,0x44,0x00,0x00,0x0c,0x00,0x09,0x0a,0x00,0x00,0x00,0x00,0x02,0x51,0x20,0x23, ++0x24,0x84,0xff,0xff,0x30,0x84,0x00,0xff,0x02,0xa0,0x28,0x21,0x0c,0x00,0x08,0xfb, ++0x00,0x40,0x80,0x21,0x02,0x02,0x00,0x18,0x8e,0x63,0x00,0x00,0x26,0x22,0x00,0x01, ++0x30,0x51,0x00,0xff,0x02,0x32,0x20,0x2b,0x00,0x00,0x80,0x12,0x00,0x70,0x18,0x21, ++0x14,0x80,0xff,0xee,0xae,0x63,0x00,0x00,0x08,0x00,0x08,0xce,0x00,0x00,0x00,0x00, ++0x80,0x82,0x00,0x00,0x08,0x00,0x08,0xce,0xae,0x62,0x00,0x00,0x08,0x00,0x08,0xdb, ++0x24,0x15,0x00,0x10,0x08,0x00,0x08,0xdb,0x24,0x15,0x00,0x0a,0x30,0x84,0x00,0xff, ++0x30,0xa5,0x00,0xff,0x24,0x06,0x00,0x01,0x10,0x80,0x00,0x09,0x00,0x00,0x10,0x21, ++0x00,0xc5,0x00,0x18,0x24,0x42,0x00,0x01,0x30,0x42,0x00,0xff,0x00,0x44,0x18,0x2b, ++0x00,0x00,0x30,0x12,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xfa,0x00,0xc5,0x00,0x18, ++0x03,0xe0,0x00,0x08,0x00,0xc0,0x10,0x21,0x30,0x84,0x00,0xff,0x24,0x83,0xff,0xd0, ++0x30,0x62,0x00,0xff,0x2c,0x42,0x00,0x0a,0x14,0x40,0x00,0x06,0x00,0x00,0x00,0x00, ++0x24,0x82,0xff,0xbf,0x2c,0x42,0x00,0x06,0x14,0x40,0x00,0x02,0x24,0x83,0xff,0xc9, ++0x24,0x83,0xff,0xa9,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x27,0xbd,0xff,0xc8, ++0x24,0x02,0x00,0x01,0xaf,0xbf,0x00,0x30,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, ++0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0x10,0xa2,0x00,0x3e, ++0xaf,0xb0,0x00,0x18,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x08,0x24,0x05,0x00,0x01, ++0x00,0x00,0x10,0x21,0x8f,0xbf,0x00,0x30,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, ++0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x8c,0xc4,0x00,0x04, ++0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x10,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00, ++0x28,0x42,0x00,0x65,0x14,0x40,0x00,0x06,0x00,0x00,0x00,0x00,0x3c,0x04,0x80,0x01, ++0x0c,0x00,0x1a,0x7e,0x24,0x84,0x04,0xbc,0x08,0x00,0x09,0x25,0x24,0x02,0x00,0x01, ++0x3c,0x04,0x80,0x01,0x0c,0x00,0x1a,0x7e,0x24,0x84,0x04,0xc8,0x8f,0x83,0x83,0xa4, ++0x3c,0x02,0x80,0x00,0x24,0x42,0x2c,0x80,0x10,0x62,0xff,0xe5,0x00,0x40,0x90,0x21, ++0x3c,0x13,0x80,0x01,0x27,0x95,0x83,0x90,0x3c,0x14,0x80,0x01,0x27,0x90,0x83,0x94, ++0x00,0x00,0x88,0x21,0x8e,0x03,0x00,0x08,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00, ++0x10,0x62,0x00,0x08,0x26,0x64,0x04,0xd4,0x26,0x10,0x00,0x18,0x8e,0x02,0x00,0x10, ++0x00,0x00,0x00,0x00,0x14,0x52,0xff,0xf7,0x26,0x31,0x00,0x18,0x08,0x00,0x09,0x25, ++0x00,0x00,0x10,0x21,0x0c,0x00,0x1a,0x7e,0x00,0x00,0x00,0x00,0x02,0x35,0x10,0x21, ++0x8c,0x44,0x00,0x00,0x0c,0x00,0x1a,0x7e,0x00,0x00,0x00,0x00,0x0c,0x00,0x1a,0x7e, ++0x26,0x84,0x04,0xd8,0x8e,0x04,0x00,0x00,0x0c,0x00,0x1a,0x7e,0x26,0x10,0x00,0x18, ++0x08,0x00,0x09,0x4b,0x00,0x00,0x00,0x00,0x3c,0x04,0x80,0x01,0x0c,0x00,0x1a,0x7e, ++0x24,0x84,0x04,0xdc,0x3c,0x04,0x80,0x01,0x0c,0x00,0x1a,0x6b,0x24,0x84,0x04,0xec, ++0x24,0x11,0x00,0x05,0x3c,0x12,0x80,0x01,0x27,0x90,0x88,0x0e,0x86,0x05,0x00,0x00, ++0x26,0x44,0x05,0x0c,0x0c,0x00,0x1a,0x6b,0x26,0x31,0xff,0xff,0x06,0x21,0xff,0xfb, ++0x26,0x10,0xff,0xfe,0x08,0x00,0x09,0x25,0x00,0x00,0x10,0x21,0x27,0xbd,0xff,0xd0, ++0x28,0xa2,0x00,0x02,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x2c, ++0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0x00,0xa0,0x80,0x21, ++0x14,0x40,0x00,0x51,0x00,0xc0,0x88,0x21,0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x02, ++0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x10,0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x48, ++0x24,0x05,0x00,0x01,0x8e,0x24,0x00,0x08,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x14, ++0x8f,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x30,0x42,0x0f,0xff,0xaf,0xa2,0x00,0x14, ++0x7b,0xa4,0x00,0xbc,0x0c,0x00,0x0a,0x06,0x24,0x06,0x00,0x04,0x24,0x03,0x00,0x04, ++0x10,0x43,0x00,0x2a,0x24,0x04,0x00,0x04,0x8f,0xa2,0x00,0x10,0x3c,0x04,0x80,0x01, ++0x24,0x84,0x05,0x10,0x00,0x02,0x19,0x02,0x00,0x03,0x81,0x00,0x8f,0xa3,0x00,0x14, ++0x00,0x50,0x10,0x23,0x00,0x02,0x10,0x82,0x00,0x62,0x18,0x21,0x0c,0x00,0x1a,0x7e, ++0xaf,0xa3,0x00,0x14,0x3c,0x04,0x80,0x01,0x0c,0x00,0x1a,0x7e,0x24,0x84,0x05,0x38, ++0x8f,0xa2,0x00,0x14,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x17,0x00,0x00,0x88,0x21, ++0x3c,0x13,0x80,0x01,0x3c,0x12,0x80,0x01,0x3c,0x14,0x80,0x01,0x0c,0x00,0x2e,0x24, ++0x24,0x04,0x27,0x10,0x32,0x23,0x00,0x03,0x02,0x00,0x28,0x21,0x10,0x60,0x00,0x1c, ++0x26,0x64,0x05,0x64,0x8f,0xa2,0x00,0x10,0x00,0x00,0x00,0x00,0x02,0x02,0x10,0x23, ++0x28,0x42,0xff,0xfd,0x10,0x40,0x00,0x10,0x26,0x44,0x05,0x70,0x0c,0x00,0x1a,0x7e, ++0x26,0x10,0x00,0x04,0x8f,0xa2,0x00,0x14,0x26,0x31,0x00,0x01,0x02,0x22,0x10,0x2b, ++0x14,0x40,0xff,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x21,0x8f,0xbf,0x00,0x2c, ++0x8f,0xb4,0x00,0x28,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x00,0x80,0x10,0x21, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x8e,0x05,0x00,0x00,0x26,0x84,0x05,0x74, ++0x0c,0x00,0x1a,0x6b,0x26,0x10,0x00,0x04,0x08,0x00,0x09,0xb1,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x1a,0x6b,0x00,0x00,0x00,0x00,0x08,0x00,0x09,0xa9,0x00,0x00,0x00,0x00, ++0x08,0x00,0x09,0x87,0x24,0x02,0x00,0x01,0x0c,0x00,0x0b,0x2b,0x00,0x00,0x00,0x00, ++0x08,0x00,0x09,0xb7,0x24,0x04,0x00,0x04,0x27,0xbd,0xff,0xd0,0x28,0xa2,0x00,0x03, ++0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0xaf,0xbf,0x00,0x28,0x00,0xa0,0x88,0x21, ++0x10,0x40,0x00,0x09,0x00,0xc0,0x80,0x21,0x0c,0x00,0x0b,0x2b,0x00,0x00,0x00,0x00, ++0x24,0x04,0x00,0x04,0x8f,0xbf,0x00,0x28,0x7b,0xb0,0x01,0x3c,0x00,0x80,0x10,0x21, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x02, ++0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x10,0x8e,0x04,0x00,0x08,0x24,0x05,0x00,0x02, ++0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x14,0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x1b, ++0x24,0x05,0x00,0x01,0x8e,0x04,0x00,0x0c,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x18, ++0x8f,0xa4,0x00,0x10,0x8f,0xa5,0x00,0x18,0x0c,0x00,0x0a,0x06,0x24,0x06,0x00,0x04, ++0x24,0x03,0x00,0x04,0x10,0x43,0xff,0xe7,0x24,0x04,0x00,0x04,0x8f,0xa2,0x00,0x18, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b,0x00,0x00,0x28,0x21,0x8f,0xa2,0x00,0x10, ++0x8f,0xa4,0x00,0x14,0x24,0xa5,0x00,0x01,0xac,0x44,0x00,0x00,0x8f,0xa3,0x00,0x10, ++0x8f,0xa2,0x00,0x18,0x24,0x63,0x00,0x04,0x00,0xa2,0x10,0x2b,0x14,0x40,0xff,0xf7, ++0xaf,0xa3,0x00,0x10,0x08,0x00,0x09,0xd9,0x00,0x00,0x20,0x21,0x24,0x02,0x00,0x01, ++0x08,0x00,0x09,0xec,0xaf,0xa2,0x00,0x18,0x30,0xc6,0x00,0xff,0x00,0xa6,0x00,0x18, ++0x00,0x00,0x28,0x12,0x04,0x81,0x00,0x07,0x00,0x00,0x30,0x21,0x3c,0x02,0x80,0x01, ++0x00,0x85,0x18,0x21,0x34,0x42,0x7f,0xff,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x0b, ++0x3c,0x02,0xb0,0x03,0x3c,0x02,0xaf,0xff,0x34,0x42,0xff,0xff,0x00,0x44,0x10,0x2b, ++0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x0a,0x00,0x85,0x18,0x21,0x34,0x42,0xff,0xff, ++0x00,0x43,0x10,0x2b,0x14,0x40,0x00,0x12,0x3c,0x02,0xb0,0x03,0x34,0x42,0xff,0xff, ++0x00,0x44,0x10,0x2b,0x10,0x40,0x00,0x06,0x3c,0x02,0xb0,0x07,0x3c,0x02,0xb0,0x04, ++0x34,0x42,0xff,0xff,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x09,0x3c,0x02,0xb0,0x07, ++0x34,0x42,0x00,0x3f,0x00,0x44,0x10,0x2b,0x10,0x40,0x00,0x06,0x3c,0x02,0xb0,0x07, ++0x34,0x42,0xff,0xff,0x00,0x43,0x10,0x2b,0x14,0x40,0x00,0x02,0x00,0x00,0x00,0x00, ++0x24,0x06,0x00,0x01,0x14,0xc0,0x00,0x11,0x24,0x02,0x00,0x04,0x3c,0x02,0xb0,0x08, ++0x34,0x42,0x0f,0xff,0x00,0x44,0x10,0x2b,0x14,0x40,0x00,0x08,0x3c,0x02,0x4f,0xf7, ++0x00,0x85,0x20,0x21,0x34,0x42,0xf0,0x00,0x00,0x82,0x20,0x21,0x34,0x03,0xef,0xff, ++0x00,0x64,0x18,0x2b,0x14,0x60,0x00,0x02,0x00,0x00,0x00,0x00,0x24,0x06,0x00,0x02, ++0x10,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0,0x24,0x02,0x00,0x02,0xaf,0xb0,0x00,0x18, ++0xaf,0xbf,0x00,0x1c,0x10,0xa2,0x00,0x23,0x00,0xc0,0x80,0x21,0x28,0xa2,0x00,0x03, ++0x10,0x40,0x00,0x0c,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x04, ++0x00,0x00,0x18,0x21,0x0c,0x00,0x0b,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21, ++0x8f,0xbf,0x00,0x1c,0x8f,0xb0,0x00,0x18,0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x14,0xa2,0xff,0xf7,0x24,0x05,0x00,0x01,0x8c,0xc4,0x00,0x04, ++0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x10,0x8e,0x04,0x00,0x08,0x24,0x05,0x00,0x02, ++0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x14,0x8f,0xa4,0x00,0x10,0x00,0x00,0x00,0x00, ++0x2c,0x82,0x00,0x0b,0x10,0x40,0xff,0xee,0x24,0x03,0x00,0x04,0x00,0x04,0x10,0x80, ++0x8f,0xa4,0x00,0x14,0x27,0x83,0x94,0xc0,0x00,0x43,0x10,0x21,0x08,0x00,0x0a,0x4f, ++0xac,0x44,0x00,0x00,0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x01,0x0c,0x00,0x08,0xb6, ++0x27,0xa6,0x00,0x10,0x8f,0xa5,0x00,0x10,0x27,0x83,0x94,0xc0,0x3c,0x04,0x80,0x01, ++0x00,0x05,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x46,0x00,0x00,0x0c,0x00,0x1a,0x6b, ++0x24,0x84,0x05,0x7c,0x08,0x00,0x0a,0x50,0x00,0x00,0x18,0x21,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xb8,0x28,0xa5,0x00,0x04,0xaf,0xb0,0x00,0x20, ++0xaf,0xbf,0x00,0x40,0xaf,0xb7,0x00,0x3c,0xaf,0xb6,0x00,0x38,0xaf,0xb5,0x00,0x34, ++0xaf,0xb4,0x00,0x30,0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28,0xaf,0xb1,0x00,0x24, ++0x10,0xa0,0x00,0x0b,0x00,0xc0,0x80,0x21,0x0c,0x00,0x0b,0x2b,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x04,0x8f,0xbf,0x00,0x40,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc, ++0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48, ++0x8c,0xc4,0x00,0x04,0x24,0x05,0x00,0x01,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x10, ++0x8e,0x04,0x00,0x08,0x24,0x05,0x00,0x01,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x14, ++0x8e,0x04,0x00,0x0c,0x24,0x05,0x00,0x01,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x18, ++0x8f,0xa3,0x00,0x18,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x3a,0x24,0x02,0x00,0x01, ++0x10,0x62,0x00,0x33,0x3c,0x04,0x80,0x01,0x97,0xb0,0x00,0x12,0x8f,0xa2,0x00,0x14, ++0x00,0x00,0x00,0x00,0x02,0x02,0x10,0x2b,0x10,0x40,0xff,0xe2,0x3c,0x15,0x80,0x01, ++0x3c,0x02,0x80,0x01,0x24,0x52,0x05,0xbc,0x3c,0x14,0xb0,0x06,0x24,0x13,0x00,0x01, ++0x3c,0x17,0xb0,0x08,0x3c,0x16,0x80,0x01,0x32,0x02,0x00,0x01,0x02,0x00,0x28,0x21, ++0x10,0x40,0x00,0x1f,0x26,0xa4,0x05,0xb0,0x8f,0xa3,0x00,0x18,0x00,0x10,0x10,0xc0, ++0x00,0x54,0x10,0x21,0x10,0x60,0x00,0x14,0x02,0x40,0x20,0x21,0x00,0x10,0x10,0xc0, ++0x00,0x57,0x10,0x21,0x10,0x73,0x00,0x09,0x26,0xc4,0x05,0xc4,0x8f,0xa2,0x00,0x14, ++0x26,0x03,0x00,0x01,0x30,0x70,0xff,0xff,0x02,0x02,0x10,0x2b,0x14,0x40,0xff,0xee, ++0x00,0x00,0x00,0x00,0x08,0x00,0x0a,0x8d,0x00,0x00,0x00,0x00,0x8c,0x51,0x00,0x00, ++0x00,0x00,0x00,0x00,0x32,0x25,0x00,0xff,0x0c,0x00,0x1a,0x6b,0x00,0x00,0x00,0x00, ++0x08,0x00,0x0a,0xbf,0x00,0x00,0x00,0x00,0x8c,0x51,0x00,0x00,0x0c,0x00,0x1a,0x6b, ++0x00,0x11,0x2c,0x02,0x32,0x25,0x00,0xff,0x08,0x00,0x0a,0xca,0x02,0x40,0x20,0x21, ++0x0c,0x00,0x1a,0x6b,0x00,0x00,0x00,0x00,0x08,0x00,0x0a,0xb6,0x00,0x00,0x00,0x00, ++0x24,0x84,0x05,0x90,0x0c,0x00,0x1a,0x7e,0x00,0x00,0x00,0x00,0x08,0x00,0x0a,0xa6, ++0x00,0x00,0x00,0x00,0x3c,0x04,0x80,0x01,0x08,0x00,0x0a,0xd9,0x24,0x84,0x05,0xd0, ++0x00,0xa0,0x10,0x21,0x27,0xbd,0xff,0xd8,0x28,0x42,0x00,0x04,0xaf,0xb0,0x00,0x20, ++0xaf,0xbf,0x00,0x24,0x00,0xc0,0x80,0x21,0x24,0x05,0x00,0x01,0x10,0x40,0x00,0x08, ++0x27,0xa6,0x00,0x10,0x0c,0x00,0x0b,0x2b,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04, ++0x8f,0xbf,0x00,0x24,0x8f,0xb0,0x00,0x20,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, ++0x8e,0x04,0x00,0x04,0x0c,0x00,0x08,0xb6,0x00,0x00,0x00,0x00,0x8e,0x04,0x00,0x08, ++0x24,0x05,0x00,0x01,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x14,0x8e,0x04,0x00,0x0c, ++0x24,0x05,0x00,0x01,0x0c,0x00,0x08,0xb6,0x27,0xa6,0x00,0x18,0x08,0x00,0x0a,0xec, ++0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x01,0x00,0x65,0x10,0x2a,0x27,0xbd,0xff,0xd8, ++0x00,0xa0,0x40,0x21,0x10,0x40,0x00,0x0b,0x00,0xc0,0x38,0x21,0x00,0x03,0x20,0x80, ++0x00,0x87,0x10,0x21,0x8c,0x45,0x00,0x00,0x24,0x63,0x00,0x01,0x30,0x63,0x00,0xff, ++0x8c,0xa6,0x00,0x00,0x00,0x9d,0x20,0x21,0x00,0x68,0x10,0x2a,0x14,0x40,0xff,0xf7, ++0xac,0x86,0xff,0xfc,0x8f,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x0b, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x93,0xa2,0x00,0x07,0x00,0x00,0x00,0x00, ++0xa3,0x82,0x87,0x6c,0x08,0x00,0x0b,0x14,0x00,0x00,0x00,0x00,0x93,0xa2,0x00,0x07, ++0x00,0x00,0x00,0x00,0xa3,0x82,0x94,0xb0,0x08,0x00,0x0b,0x14,0x00,0x00,0x00,0x00, ++0x27,0xbd,0xff,0xe8,0x3c,0x04,0x80,0x01,0xaf,0xbf,0x00,0x10,0x18,0xa0,0x00,0x03, ++0x24,0x84,0x05,0xf8,0x0c,0x00,0x1a,0x7e,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10, ++0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x27,0xbd,0xff,0xe8, ++0xaf,0xb0,0x00,0x10,0x00,0x80,0x80,0x21,0x3c,0x04,0x80,0x01,0xaf,0xbf,0x00,0x14, ++0x0c,0x00,0x1a,0x7e,0x24,0x84,0x06,0x0c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, ++0x27,0x83,0x83,0x90,0x00,0x02,0x10,0xc0,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x08, ++0x0c,0x00,0x1a,0x7e,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x34,0x63,0x00,0x20,0x24,0x42,0x2c,0xf8,0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00, ++0x34,0x84,0x00,0x2c,0x8c,0x86,0x00,0x00,0x3c,0x05,0xb0,0x0a,0x34,0xa5,0x1a,0x00, ++0x00,0x06,0x1a,0x02,0x30,0x63,0x0f,0xff,0x00,0x06,0x25,0x02,0x24,0x02,0xff,0xff, ++0xac,0xa2,0x00,0x00,0xa7,0x83,0xc5,0x4a,0xa7,0x84,0xc5,0x4c,0xa3,0x86,0xc5,0x48, ++0xa7,0x80,0xc5,0x40,0xa7,0x80,0xc5,0x42,0xa7,0x80,0xc5,0x44,0xa7,0x80,0xc5,0x46, ++0x00,0xa0,0x38,0x21,0x24,0x03,0x00,0x01,0x8c,0xe2,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x0a,0x00,0x8c,0x45,0x00,0x00, ++0x3c,0x04,0xb0,0x0a,0x34,0x84,0x1a,0x00,0xa0,0x45,0x00,0x00,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x34,0x42,0x0a,0x00,0x3c,0x04,0xb0,0x0a,0xa0,0x45,0x00,0x00,0x34,0x84,0x1a,0x00, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x3c,0x04,0xb0,0x03,0x34,0x63,0x01,0x08, ++0x34,0x84,0x01,0x18,0x8c,0x65,0x00,0x00,0x8c,0x82,0x00,0x00,0xaf,0x85,0xc5,0x50, ++0x30,0x42,0x02,0x00,0x10,0x40,0x00,0x06,0x3c,0x02,0x00,0x0f,0x3c,0x02,0x00,0x4c, ++0x34,0x42,0x4b,0x40,0xaf,0x82,0xc5,0x54,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x08,0x00,0x0b,0x79,0x34,0x42,0x42,0x40,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x34,0x63,0x00,0x20,0x24,0x42,0x2d,0xf8,0x30,0x84,0x00,0xff,0xac,0x62,0x00,0x00, ++0x14,0x80,0x02,0xb3,0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x1b,0x40, ++0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x34,0x42,0x0b,0x40,0x8c,0x46,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x1b,0x48, ++0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x00,0x06,0x54,0x02, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x3c,0x02,0xb0,0x0a,0x34,0x42,0x0b,0x48,0x8c,0x46,0x00,0x00,0x3c,0x03,0xb0,0x0a, ++0x34,0x63,0x1b,0x50,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21, ++0x00,0x06,0x64,0x02,0x30,0xcb,0xff,0xff,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x0b,0x50, ++0x8c,0x46,0x00,0x00,0x97,0x84,0xc5,0x40,0x97,0x82,0xc5,0x42,0x97,0x83,0xc5,0x46, ++0x01,0x44,0x20,0x23,0x01,0x62,0x10,0x23,0x00,0x82,0x20,0x21,0x97,0x82,0xc5,0x44, ++0x30,0xcd,0xff,0xff,0x01,0xa3,0x18,0x23,0x01,0x82,0x10,0x23,0x00,0x82,0x20,0x21, ++0x93,0x82,0xc5,0x48,0x00,0x83,0x20,0x21,0x30,0x84,0xff,0xff,0x00,0x82,0x10,0x2b, ++0x10,0x40,0x00,0xec,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x18,0xa0,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xa0, ++0x8c,0x46,0x00,0x00,0x24,0x02,0x00,0x20,0x30,0xc8,0x00,0x7f,0x11,0x02,0x00,0x4d, ++0x2d,0x02,0x00,0x21,0x14,0x40,0x00,0x2b,0x24,0x02,0xff,0x80,0x00,0xc2,0x10,0x24, ++0x25,0x08,0xff,0xff,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x08,0xa0,0x00,0x48,0x30,0x25, ++0x3c,0x04,0xb0,0x0a,0xac,0x66,0x00,0x00,0x34,0x84,0x18,0xa0,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x34,0x42,0x08,0xb0,0x3c,0x04,0xb0,0x0a,0xac,0x46,0x00,0x00,0x34,0x84,0x18,0xb0, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xc0,0x3c,0x04,0xb0,0x0a,0xac,0x46,0x00,0x00, ++0x34,0x84,0x18,0xc0,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xd0,0x3c,0x04,0xb0,0x0a, ++0xac,0x46,0x00,0x00,0x34,0x84,0x18,0xd0,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x24,0x02,0x00,0x20,0x11,0x02,0x00,0x07, ++0x24,0x02,0xff,0xff,0xa7,0x8a,0xc5,0x40,0xa7,0x8b,0xc5,0x42,0xa7,0x8c,0xc5,0x44, ++0xa7,0x8d,0xc5,0x46,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a, ++0x34,0x63,0x14,0x58,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x0a,0x34,0x63,0x04,0x58,0x8c,0x69,0x00,0x00,0x3c,0x02,0xff,0xff, ++0x34,0x42,0x3f,0xff,0x01,0x22,0x10,0x24,0x34,0x49,0x80,0x00,0x3c,0x04,0xb0,0x0a, ++0xac,0x69,0x00,0x00,0x34,0x84,0x14,0x58,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x0b,0xf9, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x58,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x58, ++0x8c,0x49,0x00,0x00,0x3c,0x04,0xb0,0x0a,0x34,0x84,0x14,0x58,0x35,0x29,0x40,0x00, ++0xac,0x49,0x00,0x00,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x24,0x02,0xff,0xff,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0xb0, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0xb0, ++0x8c,0x47,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0xb8,0x3c,0x05,0xb0,0x0a, ++0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x34,0xa5,0x14,0xb8,0x00,0x07,0x1e,0x02, ++0x24,0x04,0x00,0x01,0x8c,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd, ++0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0xb8,0x8c,0x47,0x00,0x00,0x00,0x03,0x1a,0x00, ++0x30,0xe2,0x00,0xff,0x00,0x62,0x18,0x25,0x2c,0x62,0x00,0x04,0x10,0x40,0x00,0x3a, ++0x2c,0x62,0x00,0x11,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x10,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x10, ++0x8c,0x47,0x00,0x00,0x24,0x02,0x00,0x03,0x00,0x07,0x1d,0x82,0x30,0x64,0x00,0x03, ++0x10,0x82,0x00,0x1a,0x3c,0x02,0xff,0x3f,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff, ++0x3c,0x03,0xb0,0x0a,0x34,0x63,0x04,0x58,0x01,0x22,0x48,0x24,0x3c,0x04,0xb0,0x0a, ++0xac,0x69,0x00,0x00,0x34,0x84,0x14,0x58,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x35,0x29,0x80,0x00, ++0x34,0x42,0x04,0x58,0x3c,0x04,0xb0,0x0a,0xac,0x49,0x00,0x00,0x34,0x84,0x14,0x58, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x2d,0x02,0x00,0x21,0x08,0x00,0x0b,0xcd,0x00,0x00,0x00,0x00,0x34,0x42,0xff,0xff, ++0x3c,0x03,0x00,0x80,0x00,0xe2,0x10,0x24,0x00,0x43,0x38,0x25,0x3c,0x04,0xb0,0x0a, ++0x3c,0x01,0xb0,0x0a,0xac,0x27,0x04,0x10,0x34,0x84,0x14,0x10,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xff,0xff, ++0x08,0x00,0x0c,0x60,0x34,0x42,0x3f,0xff,0x14,0x40,0xff,0xd8,0x3c,0x02,0xff,0xff, ++0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x10,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00, ++0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x10,0x8c,0x47,0x00,0x00, ++0x3c,0x05,0x00,0xc0,0x24,0x03,0x00,0x02,0x00,0xe5,0x10,0x24,0x00,0x02,0x25,0x82, ++0x14,0x83,0xff,0xc6,0x3c,0x02,0xff,0xff,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, ++0x00,0xe2,0x10,0x24,0x00,0x45,0x38,0x25,0x3c,0x04,0xb0,0x0a,0x3c,0x01,0xb0,0x0a, ++0xac,0x27,0x04,0x10,0x34,0x84,0x14,0x10,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xff,0xff,0x08,0x00,0x0c,0x60, ++0x34,0x42,0x3f,0xff,0x97,0x82,0xc5,0x4c,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b, ++0x10,0x40,0x00,0x74,0x34,0x63,0x18,0xa0,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00, ++0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xa0,0x8c,0x46,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0xc8,0x00,0x7f,0x2d,0x02,0x00,0x32,0x10,0x40,0xff,0x3d, ++0x24,0x02,0x00,0x20,0x11,0x02,0x00,0x2b,0x24,0x02,0xff,0x80,0x00,0xc2,0x10,0x24, ++0x25,0x08,0x00,0x02,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x08,0xa0,0x00,0x48,0x30,0x25, ++0x3c,0x04,0xb0,0x0a,0xac,0x66,0x00,0x00,0x34,0x84,0x18,0xa0,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x34,0x42,0x08,0xb0,0x3c,0x04,0xb0,0x0a,0xac,0x46,0x00,0x00,0x34,0x84,0x18,0xb0, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xc0,0x3c,0x04,0xb0,0x0a,0xac,0x46,0x00,0x00, ++0x34,0x84,0x18,0xc0,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xd0,0x3c,0x04,0xb0,0x0a, ++0xac,0x46,0x00,0x00,0x34,0x84,0x18,0xd0,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x0b,0xf9, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x10,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x10, ++0x8c,0x47,0x00,0x00,0x3c,0x05,0x00,0xc0,0x24,0x03,0x00,0x03,0x00,0xe5,0x10,0x24, ++0x00,0x02,0x25,0x82,0x10,0x83,0x00,0x0d,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff, ++0x00,0xe2,0x10,0x24,0x00,0x45,0x38,0x25,0x3c,0x04,0xb0,0x0a,0x3c,0x01,0xb0,0x0a, ++0xac,0x27,0x04,0x10,0x34,0x84,0x14,0x10,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a, ++0x34,0x63,0x14,0x58,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x04,0x58,0x8c,0x69,0x00,0x00, ++0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x01,0x22,0x48,0x24,0x3c,0x04,0xb0,0x0a, ++0xac,0x69,0x00,0x00,0x34,0x84,0x14,0x58,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x24,0x02,0xff,0x80,0x08,0x00,0x0c,0xc0, ++0x00,0xc2,0x10,0x24,0x97,0x82,0xc5,0x4a,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x2b, ++0x10,0x40,0x00,0x75,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x18,0xa0,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xa0, ++0x8c,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xc8,0x00,0x7f,0x2d,0x02,0x00,0x32, ++0x10,0x40,0xfe,0xc4,0x24,0x02,0x00,0x20,0x11,0x02,0x00,0x2b,0x24,0x02,0xff,0x80, ++0x00,0xc2,0x10,0x24,0x25,0x08,0x00,0x01,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x08,0xa0, ++0x00,0x48,0x30,0x25,0x3c,0x04,0xb0,0x0a,0xac,0x66,0x00,0x00,0x34,0x84,0x18,0xa0, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xb0,0x3c,0x04,0xb0,0x0a,0xac,0x46,0x00,0x00, ++0x34,0x84,0x18,0xb0,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xc0,0x3c,0x04,0xb0,0x0a, ++0xac,0x46,0x00,0x00,0x34,0x84,0x18,0xc0,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xd0, ++0x3c,0x04,0xb0,0x0a,0xac,0x46,0x00,0x00,0x34,0x84,0x18,0xd0,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00, ++0x08,0x00,0x0b,0xf9,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x10, ++0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x34,0x42,0x04,0x10,0x8c,0x47,0x00,0x00,0x3c,0x05,0x00,0xc0,0x24,0x03,0x00,0x03, ++0x00,0xe5,0x10,0x24,0x00,0x02,0x25,0x82,0x10,0x83,0x00,0x0d,0x3c,0x02,0xff,0x3f, ++0x34,0x42,0xff,0xff,0x00,0xe2,0x10,0x24,0x00,0x45,0x38,0x25,0x3c,0x04,0xb0,0x0a, ++0x3c,0x01,0xb0,0x0a,0xac,0x27,0x04,0x10,0x34,0x84,0x14,0x10,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x58,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00, ++0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x04,0x58, ++0x8c,0x69,0x00,0x00,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x01,0x22,0x48,0x24, ++0x3c,0x04,0xb0,0x0a,0xac,0x69,0x00,0x00,0x34,0x84,0x14,0x58,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x24,0x02,0xff,0x80, ++0x08,0x00,0x0d,0x39,0x00,0xc2,0x10,0x24,0x34,0x63,0x18,0xa0,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x08,0xa0, ++0x8c,0x46,0x00,0x00,0x24,0x02,0x00,0x20,0x30,0xc8,0x00,0x7f,0x15,0x02,0xfe,0x51, ++0x24,0x02,0xff,0xff,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x58,0xac,0x62,0x00,0x00, ++0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x58,0x8c,0x49,0x00,0x00, ++0x3c,0x04,0xb0,0x0a,0x34,0x84,0x14,0x58,0x35,0x29,0x40,0x00,0xac,0x49,0x00,0x00, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x24,0x02,0xff,0xff,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0xb0,0xac,0x62,0x00,0x00, ++0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0xb0,0x8c,0x47,0x00,0x00, ++0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0xb8,0x3c,0x05,0xb0,0x0a,0x24,0x02,0xff,0xff, ++0xac,0x62,0x00,0x00,0x34,0xa5,0x14,0xb8,0x00,0x07,0x1e,0x02,0x24,0x04,0x00,0x01, ++0x8c,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd,0x3c,0x02,0xb0,0x0a, ++0x34,0x42,0x04,0xb8,0x8c,0x47,0x00,0x00,0x00,0x03,0x1a,0x00,0x30,0xe2,0x00,0xff, ++0x00,0x62,0x18,0x25,0x2c,0x62,0x00,0x04,0x10,0x40,0x00,0x3a,0x2c,0x62,0x00,0x11, ++0x3c,0x03,0xb0,0x0a,0x34,0x63,0x14,0x10,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00, ++0x00,0x60,0x20,0x21,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x10,0x8c,0x47,0x00,0x00, ++0x24,0x02,0x00,0x03,0x00,0x07,0x1d,0x82,0x30,0x64,0x00,0x03,0x10,0x82,0x00,0x1a, ++0x3c,0x02,0xff,0x3f,0x3c,0x02,0xff,0xff,0x34,0x42,0x3f,0xff,0x3c,0x03,0xb0,0x0a, ++0x34,0x63,0x04,0x58,0x01,0x22,0x48,0x24,0x3c,0x04,0xb0,0x0a,0xac,0x69,0x00,0x00, ++0x34,0x84,0x14,0x58,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x35,0x29,0x80,0x00,0x34,0x42,0x04,0x58, ++0x3c,0x04,0xb0,0x0a,0xac,0x49,0x00,0x00,0x34,0x84,0x14,0x58,0x24,0x03,0x00,0x01, ++0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00, ++0x08,0x00,0x0b,0xf9,0x00,0x00,0x00,0x00,0x34,0x42,0xff,0xff,0x3c,0x03,0x00,0x80, ++0x00,0xe2,0x10,0x24,0x00,0x43,0x38,0x25,0x3c,0x03,0xb0,0x0a,0x3c,0x01,0xb0,0x0a, ++0xac,0x27,0x04,0x10,0x34,0x63,0x14,0x10,0x24,0x04,0x00,0x01,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd,0x3c,0x02,0xff,0xff,0x08,0x00,0x0d,0xef, ++0x34,0x42,0x3f,0xff,0x14,0x40,0xff,0xd8,0x3c,0x02,0xff,0xff,0x3c,0x03,0xb0,0x0a, ++0x34,0x63,0x14,0x10,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x3c,0x02,0xb0,0x0a,0x34,0x42,0x04,0x10,0x8c,0x47,0x00,0x00,0x3c,0x05,0x00,0xc0, ++0x24,0x03,0x00,0x02,0x00,0xe5,0x10,0x24,0x00,0x02,0x25,0x82,0x14,0x83,0xff,0xc6, ++0x3c,0x02,0xff,0xff,0x3c,0x02,0xff,0x3f,0x34,0x42,0xff,0xff,0x00,0xe2,0x10,0x24, ++0x00,0x45,0x38,0x25,0x3c,0x03,0xb0,0x0a,0x3c,0x01,0xb0,0x0a,0xac,0x27,0x04,0x10, ++0x34,0x63,0x14,0x10,0x24,0x04,0x00,0x01,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x44,0xff,0xfd,0x3c,0x02,0xff,0xff,0x08,0x00,0x0d,0xef,0x34,0x42,0x3f,0xff, ++0x10,0x82,0x00,0x03,0x3c,0x03,0xb0,0x0a,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x34,0x63,0x1a,0x00,0x24,0x02,0xff,0xff,0xac,0x62,0x00,0x00,0x00,0x60,0x20,0x21, ++0xa7,0x80,0xc5,0x40,0xa7,0x80,0xc5,0x42,0xa7,0x80,0xc5,0x44,0xa7,0x80,0xc5,0x46, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x0a,0x34,0x63,0x0a,0x00,0x8c,0x66,0x00,0x00, ++0x3c,0x02,0x08,0x00,0x3c,0x04,0xb0,0x0a,0x00,0xc2,0x10,0x25,0xac,0x62,0x00,0x00, ++0x34,0x84,0x1a,0x00,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x3c,0x02,0xf7,0xff,0x3c,0x03,0xb0,0x0a,0x34,0x42,0xff,0xff, ++0x34,0x63,0x0a,0x00,0x00,0xc2,0x10,0x24,0x3c,0x04,0xb0,0x0a,0xac,0x62,0x00,0x00, ++0x34,0x84,0x1a,0x00,0x24,0x03,0x00,0x01,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x43,0xff,0xfd,0x00,0x00,0x00,0x00,0x08,0x00,0x0e,0x3a,0x00,0x00,0x00,0x00, ++0x30,0x83,0x00,0x03,0x00,0x04,0x20,0x40,0x00,0x83,0x20,0x23,0x3c,0x02,0xb0,0x0a, ++0x00,0x82,0x20,0x21,0xac,0x85,0x00,0x00,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01, ++0x2c,0x62,0x27,0x10,0x14,0x40,0xff,0xfe,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08, ++0x24,0x63,0xff,0xff,0x30,0x86,0x00,0x03,0x00,0x04,0x28,0x40,0x3c,0x03,0xb0,0x0a, ++0x00,0xa6,0x10,0x23,0x00,0x43,0x10,0x21,0x24,0x04,0xff,0xff,0xac,0x44,0x10,0x00, ++0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01,0x2c,0x62,0x27,0x10,0x14,0x40,0xff,0xfe, ++0x24,0x63,0x00,0x01,0x24,0x63,0xff,0xff,0x00,0xa6,0x18,0x23,0x3c,0x02,0xb0,0x0a, ++0x00,0x62,0x18,0x21,0x8c,0x62,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x00,0x24,0x42,0x3a,0x10,0x24,0x03,0x00,0x01, ++0x34,0xa5,0x00,0x20,0x3c,0x06,0xb0,0x03,0xac,0xa2,0x00,0x00,0x34,0xc6,0x01,0x04, ++0xa0,0x83,0x00,0x48,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05,0xa0,0x80,0x00,0x06, ++0xa0,0x80,0x00,0x07,0xa0,0x80,0x00,0x08,0xa0,0x80,0x00,0x09,0xa0,0x80,0x00,0x0a, ++0xa0,0x80,0x00,0x11,0xa0,0x80,0x00,0x13,0xa0,0x80,0x00,0x49,0x94,0xc2,0x00,0x00, ++0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x24,0x00,0x02,0x14,0x00,0x00,0x02,0x14,0x03, ++0x30,0x43,0x00,0xff,0x30,0x42,0xff,0x00,0xa4,0x83,0x00,0x46,0xa4,0x82,0x00,0x44, ++0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c,0xac,0x80,0x00,0x30,0xac,0x80,0x00,0x34, ++0xac,0x80,0x00,0x38,0xac,0x80,0x00,0x3c,0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x40, ++0x84,0x83,0x00,0x0c,0x3c,0x07,0xb0,0x03,0x34,0xe7,0x00,0x20,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x44,0x00,0x43,0x10,0x21, ++0x8c,0x48,0x00,0x18,0x3c,0x02,0x80,0x00,0x24,0x42,0x3a,0xa0,0xac,0xe2,0x00,0x00, ++0x8d,0x03,0x00,0x08,0x80,0x82,0x00,0x13,0x00,0x05,0x2c,0x00,0x00,0x03,0x1e,0x02, ++0x00,0x02,0x12,0x00,0x30,0x63,0x00,0x7e,0x00,0x62,0x18,0x21,0x00,0x65,0x18,0x21, ++0x3c,0x02,0xc0,0x00,0x3c,0x05,0xb0,0x05,0x34,0x42,0x04,0x00,0x24,0x63,0x00,0x01, ++0x3c,0x07,0xb0,0x05,0x3c,0x08,0xb0,0x05,0x34,0xa5,0x04,0x20,0xac,0xa3,0x00,0x00, ++0x00,0xc2,0x30,0x21,0x34,0xe7,0x04,0x24,0x35,0x08,0x02,0x28,0x24,0x02,0x00,0x01, ++0x24,0x03,0x00,0x20,0xac,0xe6,0x00,0x00,0xac,0x82,0x00,0x3c,0x03,0xe0,0x00,0x08, ++0xa1,0x03,0x00,0x00,0x27,0xbd,0xff,0xb0,0x00,0x07,0x60,0x80,0x27,0x82,0xbd,0x40, ++0xaf,0xb7,0x00,0x44,0xaf,0xb6,0x00,0x40,0xaf,0xb5,0x00,0x3c,0xaf,0xb3,0x00,0x34, ++0xaf,0xbf,0x00,0x4c,0xaf,0xbe,0x00,0x48,0xaf,0xb4,0x00,0x38,0xaf,0xb2,0x00,0x30, ++0xaf,0xb1,0x00,0x2c,0xaf,0xb0,0x00,0x28,0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x00,0xe0,0x70,0x21,0x3c,0x02,0x80,0x00,0x94,0x71,0x00,0x14,0x3c,0x07,0xb0,0x03, ++0x34,0xe7,0x00,0x20,0x24,0x42,0x3b,0x34,0x3c,0x03,0xb0,0x05,0xac,0xe2,0x00,0x00, ++0x34,0x63,0x01,0x28,0x90,0x67,0x00,0x00,0x00,0x11,0xa8,0xc0,0x02,0xb1,0x18,0x21, ++0x27,0x82,0x99,0x44,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x00,0x05,0x2c,0x00, ++0x00,0x07,0x3e,0x00,0x28,0xc2,0x00,0x03,0x00,0xc0,0x98,0x21,0xaf,0xa4,0x00,0x50, ++0x00,0x05,0xb4,0x03,0x8c,0x68,0x00,0x18,0x02,0xa0,0x58,0x21,0x10,0x40,0x01,0x70, ++0x00,0x07,0xbe,0x03,0x00,0xd7,0x10,0x07,0x30,0x57,0x00,0x01,0x01,0x71,0x10,0x21, ++0x27,0x83,0x99,0x48,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x80,0x4d,0x00,0x06, ++0x8d,0x03,0x00,0x00,0x8d,0x02,0x00,0x04,0x8d,0x0a,0x00,0x08,0x8d,0x03,0x00,0x0c, ++0xaf,0xa2,0x00,0x1c,0x11,0xa0,0x01,0x60,0xaf,0xa3,0x00,0x18,0x27,0x82,0xbd,0x40, ++0x01,0x82,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04,0x14,0x60,0x00,0x14,0x00,0x00,0xa0,0x21, ++0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46,0x90,0x43,0x00,0x00,0x2a,0x64,0x00,0x04, ++0x10,0x80,0x01,0x43,0x30,0x65,0x00,0x01,0x8f,0xa3,0x00,0x50,0x00,0x00,0x00,0x00, ++0x90,0x62,0x00,0x09,0x00,0x00,0x00,0x00,0x12,0x62,0x00,0x02,0x00,0x00,0x00,0x00, ++0x00,0x00,0x28,0x21,0x14,0xa0,0x00,0x03,0x00,0x00,0x38,0x21,0x12,0xe0,0x00,0x03, ++0x38,0xf4,0x00,0x01,0x24,0x07,0x00,0x01,0x38,0xf4,0x00,0x01,0x01,0x71,0x10,0x21, ++0x00,0x02,0x30,0x80,0x27,0x83,0x99,0x50,0x00,0xc3,0x48,0x21,0x91,0x25,0x00,0x00, ++0x8f,0xa3,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x03,0x11,0xc3,0x2c,0xa3,0x00,0x04, ++0x30,0x42,0x00,0x01,0x00,0x03,0xa0,0x0b,0x12,0x80,0x00,0xc7,0xaf,0xa2,0x00,0x20, ++0x93,0x90,0xc5,0x2a,0x00,0x0a,0x16,0x42,0x30,0x52,0x00,0x3f,0x2e,0x06,0x00,0x0c, ++0x10,0xc0,0x00,0xaf,0x00,0xa0,0x20,0x21,0x2c,0xa2,0x00,0x10,0x14,0x40,0x00,0x04, ++0x00,0x90,0x10,0x2b,0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x04,0x00,0x90,0x10,0x2b, ++0x10,0x40,0x00,0x0b,0x01,0x71,0x10,0x21,0x27,0x85,0xc4,0x5c,0x00,0x10,0x10,0x40, ++0x00,0x50,0x10,0x21,0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x90,0x18,0x2b,0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x01,0x71,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x48,0x00,0x43,0x10,0x21,0x31,0xa4,0x00,0x01, ++0x10,0x80,0x00,0x94,0xa0,0x50,0x00,0x07,0x24,0x16,0x00,0x0e,0x24,0x11,0x01,0x06, ++0x27,0x82,0xbd,0x40,0x01,0x82,0x10,0x21,0x8c,0x43,0x00,0x00,0x24,0x1e,0x00,0x01, ++0x00,0x11,0xa8,0xc0,0x90,0x62,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x04, ++0xa0,0x62,0x00,0x16,0x8f,0xa5,0x00,0x1c,0x00,0x10,0x32,0x00,0x00,0x05,0x13,0x43, ++0x30,0x47,0x00,0x01,0x8f,0xa2,0x00,0x18,0x8f,0xa5,0x00,0x20,0x00,0x02,0x22,0x02, ++0x00,0x12,0x10,0x40,0x00,0x05,0x19,0xc0,0x30,0x84,0x07,0xff,0x00,0x47,0x10,0x21, ++0x00,0x1e,0x2a,0x80,0x00,0x43,0x10,0x21,0x00,0x04,0x24,0x80,0x02,0x25,0x28,0x21, ++0x00,0xa4,0x28,0x21,0x00,0x46,0x10,0x21,0x00,0x16,0x1c,0x00,0x3c,0x04,0xc0,0x00, ++0x00,0x43,0x30,0x21,0x16,0x60,0x00,0x2b,0x00,0xa4,0x28,0x21,0x3c,0x02,0xb0,0x05, ++0x34,0x42,0x04,0x00,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, ++0x34,0x63,0x04,0x04,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x01,0xac,0x65,0x00,0x00, ++0xa0,0x82,0x00,0x00,0x3c,0x02,0xb0,0x09,0x34,0x42,0x01,0x46,0x90,0x44,0x00,0x00, ++0x8f,0xa2,0x00,0x50,0x30,0x86,0x00,0x01,0x90,0x43,0x00,0x09,0x00,0x00,0x00,0x00, ++0x02,0x63,0x18,0x26,0x00,0x03,0x30,0x0b,0x14,0xc0,0x00,0x03,0x00,0x00,0x28,0x21, ++0x12,0xe0,0x00,0x03,0x02,0xb1,0x10,0x21,0x24,0x05,0x00,0x01,0x02,0xb1,0x10,0x21, ++0x27,0x83,0x99,0x48,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x84,0x48,0x00,0x04, ++0x00,0xa0,0x30,0x21,0x00,0xe0,0x20,0x21,0x02,0x60,0x28,0x21,0x02,0x80,0x38,0x21, ++0x0c,0x00,0x00,0x70,0xaf,0xa8,0x00,0x10,0x7b,0xbe,0x02,0x7c,0x7b,0xb6,0x02,0x3c, ++0x7b,0xb4,0x01,0xfc,0x7b,0xb2,0x01,0xbc,0x7b,0xb0,0x01,0x7c,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x50,0x24,0x02,0x00,0x01,0x12,0x62,0x00,0x3d,0x3c,0x02,0xb0,0x05, ++0x24,0x02,0x00,0x02,0x12,0x62,0x00,0x31,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x03, ++0x12,0x62,0x00,0x25,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x10,0x12,0x62,0x00,0x19, ++0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x11,0x12,0x62,0x00,0x0d,0x3c,0x02,0xb0,0x05, ++0x24,0x02,0x00,0x12,0x16,0x62,0xff,0xcf,0x3c,0x02,0xb0,0x05,0x3c,0x03,0xb0,0x05, ++0x34,0x42,0x04,0x20,0x3c,0x04,0xb0,0x05,0x34,0x63,0x04,0x24,0xac,0x46,0x00,0x00, ++0x34,0x84,0x02,0x28,0xac,0x65,0x00,0x00,0x08,0x00,0x0f,0x74,0x24,0x02,0x00,0x20, ++0x34,0x42,0x04,0x40,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, ++0x34,0x63,0x04,0x44,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x40,0x08,0x00,0x0f,0x74, ++0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x28,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, ++0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x2c,0x34,0x84,0x02,0x28,0x24,0x02,0xff,0x80, ++0x08,0x00,0x0f,0x74,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x18,0x3c,0x03,0xb0,0x05, ++0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x1c,0x34,0x84,0x02,0x28, ++0x24,0x02,0x00,0x08,0x08,0x00,0x0f,0x74,0xac,0x65,0x00,0x00,0x34,0x42,0x04,0x10, ++0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00,0x34,0x63,0x04,0x14, ++0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x04,0x08,0x00,0x0f,0x74,0xac,0x65,0x00,0x00, ++0x34,0x42,0x04,0x08,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05,0xac,0x46,0x00,0x00, ++0x34,0x63,0x04,0x0c,0x34,0x84,0x02,0x28,0x24,0x02,0x00,0x02,0x08,0x00,0x0f,0x74, ++0xac,0x65,0x00,0x00,0x24,0x16,0x00,0x14,0x08,0x00,0x0f,0x4c,0x24,0x11,0x01,0x02, ++0x30,0xa2,0x00,0x07,0x24,0x44,0x00,0x0c,0x00,0x90,0x18,0x2b,0x10,0x60,0x00,0x0c, ++0x26,0x02,0x00,0x04,0x27,0x85,0xc4,0x5c,0x00,0x10,0x10,0x40,0x00,0x50,0x10,0x21, ++0x00,0x45,0x10,0x21,0x90,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x18,0x2b, ++0x14,0x60,0xff,0xfa,0x00,0x10,0x10,0x40,0x2e,0x06,0x00,0x0c,0x26,0x02,0x00,0x04, ++0x08,0x00,0x0f,0x43,0x00,0x46,0x80,0x0a,0x27,0x82,0xbd,0x40,0x01,0x82,0x20,0x21, ++0x8c,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0xe2,0x00,0x19,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x27,0x82,0x99,0x60,0x00,0xc2,0x10,0x21, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x12,0x00,0x00,0x00,0x00, ++0x90,0xe3,0x00,0x16,0x27,0x82,0x99,0x48,0x00,0xc2,0x10,0x21,0x34,0x63,0x00,0x20, ++0x90,0x50,0x00,0x07,0xa0,0xe3,0x00,0x16,0x8c,0x84,0x00,0x00,0x00,0x0a,0x16,0x42, ++0x30,0x52,0x00,0x3f,0x90,0x83,0x00,0x16,0x24,0x16,0x00,0x18,0x24,0x11,0x01,0x03, ++0x30,0x63,0x00,0xfb,0x24,0x1e,0x00,0x01,0x24,0x15,0x08,0x18,0x08,0x00,0x0f,0x55, ++0xa0,0x83,0x00,0x16,0x8d,0x02,0x00,0x04,0x00,0x0a,0x1c,0x42,0x30,0x42,0x00,0x10, ++0x14,0x40,0x00,0x15,0x30,0x72,0x00,0x3f,0x81,0x22,0x00,0x05,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x11,0x30,0x72,0x00,0x3e,0x27,0x83,0x99,0x58,0x00,0xc3,0x18,0x21, ++0x80,0x64,0x00,0x00,0x27,0x83,0xbe,0xb8,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x90,0x44,0x00,0x05,0x90,0x43,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x64,0x18,0x24, ++0x30,0x63,0x00,0x01,0x02,0x43,0x90,0x25,0x27,0x85,0xbd,0x40,0x01,0x85,0x28,0x21, ++0x8c,0xa6,0x00,0x00,0x01,0x71,0x10,0x21,0x27,0x83,0x99,0x50,0x90,0xc4,0x00,0x16, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x30,0x84,0x00,0xdf,0x90,0x50,0x00,0x00, ++0xa0,0xc4,0x00,0x16,0x8c,0xa3,0x00,0x00,0x2d,0xc4,0x00,0x02,0x80,0xde,0x00,0x12, ++0x90,0x62,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfb,0x14,0x80,0x00,0x06, ++0xa0,0x62,0x00,0x16,0x24,0x02,0x00,0x06,0x11,0xc2,0x00,0x03,0x24,0x02,0x00,0x04, ++0x15,0xc2,0xff,0x14,0x00,0x00,0x00,0x00,0x32,0x42,0x00,0x02,0x2e,0x03,0x00,0x0c, ++0x14,0x60,0x00,0x0d,0x00,0x02,0x20,0x2b,0x32,0x02,0x00,0x0f,0x34,0x42,0x00,0x10, ++0x00,0x04,0x19,0x00,0x00,0x43,0x18,0x21,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xb8, ++0x00,0x00,0x20,0x21,0x02,0x00,0x28,0x21,0x0c,0x00,0x01,0xfb,0xa0,0x43,0x00,0x00, ++0x08,0x00,0x0f,0x55,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x4a,0x32,0x03,0x00,0xff, ++0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x42,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x0f,0x14,0x40,0xfe,0xbf,0x00,0x00,0x00,0x00,0x8f,0xa3,0x00,0x50, ++0x00,0x00,0x00,0x00,0x90,0x62,0x00,0x09,0x00,0x00,0x00,0x00,0x02,0x62,0x10,0x26, ++0x08,0x00,0x0f,0x19,0x00,0x02,0x28,0x0b,0x08,0x00,0x0f,0x1f,0x00,0x00,0xa0,0x21, ++0x24,0x02,0x00,0x10,0x10,0xc2,0x00,0x08,0x24,0x02,0x00,0x11,0x10,0xc2,0xfe,0x8e, ++0x00,0x07,0x17,0x83,0x24,0x02,0x00,0x12,0x14,0xc2,0xfe,0x8c,0x00,0x07,0x17,0x43, ++0x08,0x00,0x0e,0xf7,0x30,0x57,0x00,0x01,0x08,0x00,0x0e,0xf7,0x00,0x07,0xbf,0xc2, ++0x00,0x04,0x10,0x40,0x27,0x83,0x86,0x30,0x00,0x43,0x10,0x21,0x00,0x80,0x40,0x21, ++0x94,0x44,0x00,0x00,0x2d,0x07,0x00,0x04,0x24,0xc2,0x00,0x03,0x00,0x47,0x30,0x0a, ++0x00,0x86,0x00,0x18,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20, ++0x24,0x42,0x41,0xc0,0xac,0x62,0x00,0x00,0x2d,0x06,0x00,0x10,0x00,0x00,0x20,0x12, ++0x00,0x04,0x22,0x42,0x24,0x84,0x00,0x01,0x24,0x83,0x00,0xc0,0x10,0xe0,0x00,0x0b, ++0x24,0x82,0x00,0x60,0x00,0x40,0x20,0x21,0x00,0x65,0x20,0x0a,0x3c,0x03,0xb0,0x03, ++0x34,0x63,0x01,0x00,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, ++0x00,0x44,0x20,0x04,0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x24,0x85,0x00,0x28, ++0x24,0x83,0x00,0x24,0x31,0x02,0x00,0x08,0x14,0xc0,0xff,0xf4,0x24,0x84,0x00,0x14, ++0x00,0x60,0x20,0x21,0x08,0x00,0x10,0x87,0x00,0xa2,0x20,0x0b,0x27,0xbd,0xff,0xe0, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0xaf,0xb0,0x00,0x10,0x24,0x42,0x42,0x5c, ++0x00,0x80,0x80,0x21,0x34,0x63,0x00,0x20,0x3c,0x04,0xb0,0x03,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x1c,0x83,0xb1,0x00,0x33,0x83,0xa8,0x00,0x37, ++0x34,0x84,0x01,0x10,0xac,0x62,0x00,0x00,0x2e,0x02,0x00,0x10,0x00,0xe0,0x90,0x21, ++0x8c,0x87,0x00,0x00,0x14,0x40,0x00,0x0c,0x2e,0x02,0x00,0x0c,0x3c,0x02,0x00,0x0f, ++0x34,0x42,0xf0,0x00,0x00,0xe2,0x10,0x24,0x14,0x40,0x00,0x37,0x32,0x02,0x00,0x08, ++0x32,0x02,0x00,0x07,0x27,0x83,0x86,0xe0,0x00,0x43,0x10,0x21,0x90,0x50,0x00,0x00, ++0x00,0x00,0x00,0x00,0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x03,0x02,0x00,0x20,0x21, ++0x32,0x02,0x00,0x0f,0x24,0x44,0x00,0x0c,0x00,0x87,0x10,0x06,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x07,0x2c,0x82,0x00,0x0c,0x00,0x04,0x10,0x80,0x27,0x83,0xbd,0x90, ++0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0x82,0x00,0x0c, ++0x14,0x40,0x00,0x05,0x00,0x05,0x10,0x40,0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00, ++0x00,0x82,0x10,0x21,0x24,0x44,0x00,0x04,0x15,0x00,0x00,0x02,0x24,0x06,0x00,0x20, ++0x24,0x06,0x00,0x0e,0x0c,0x00,0x10,0x70,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x00,0x90,0x43,0x00,0x00,0x2e,0x04,0x00,0x04, ++0x24,0x02,0x00,0x10,0x24,0x05,0x00,0x0a,0x00,0x44,0x28,0x0a,0x30,0x63,0x00,0x01, ++0x14,0x60,0x00,0x02,0x00,0x05,0x10,0x40,0x00,0xa0,0x10,0x21,0x30,0x45,0x00,0xff, ++0x00,0xc5,0x10,0x21,0x24,0x46,0x00,0x46,0x02,0x26,0x18,0x04,0xa6,0x43,0x00,0x00, ++0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x10,0x40,0xff,0xcf,0x2e,0x02,0x00,0x0c, ++0x32,0x02,0x00,0x07,0x27,0x83,0x86,0xd8,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00, ++0x08,0x00,0x10,0xb5,0x02,0x04,0x80,0x23,0x27,0xbd,0xff,0xb8,0x00,0x05,0x38,0x80, ++0x27,0x82,0xbd,0x40,0xaf,0xbe,0x00,0x40,0xaf,0xb6,0x00,0x38,0xaf,0xb3,0x00,0x2c, ++0xaf,0xbf,0x00,0x44,0xaf,0xb7,0x00,0x3c,0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30, ++0xaf,0xb2,0x00,0x28,0xaf,0xb1,0x00,0x24,0xaf,0xb0,0x00,0x20,0x00,0xe2,0x38,0x21, ++0x8c,0xe6,0x00,0x00,0xaf,0xa5,0x00,0x4c,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x03, ++0x34,0xa5,0x00,0x20,0x24,0x42,0x43,0xb8,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00, ++0xa0,0xc3,0x00,0x12,0x8c,0xe5,0x00,0x00,0x94,0xc3,0x00,0x06,0x90,0xa2,0x00,0x16, ++0xa4,0xc3,0x00,0x14,0x27,0x83,0x99,0x40,0x34,0x42,0x00,0x08,0xa0,0xa2,0x00,0x16, ++0x8c,0xe8,0x00,0x00,0xaf,0xa4,0x00,0x48,0x27,0x82,0x99,0x44,0x95,0x11,0x00,0x14, ++0x00,0x00,0x00,0x00,0x00,0x11,0x98,0xc0,0x02,0x71,0x20,0x21,0x00,0x04,0x20,0x80, ++0x00,0x82,0x10,0x21,0x8c,0x52,0x00,0x18,0x00,0x83,0x18,0x21,0x84,0x75,0x00,0x06, ++0x8e,0x45,0x00,0x08,0x8e,0x46,0x00,0x04,0x8e,0x47,0x00,0x04,0x00,0x05,0x1c,0x82, ++0x00,0x06,0x31,0x42,0x27,0x82,0x99,0x50,0x30,0x63,0x00,0x01,0x30,0xc6,0x00,0x01, ++0x00,0x82,0x20,0x21,0xa5,0x15,0x00,0x1a,0x00,0x05,0x14,0x42,0xaf,0xa3,0x00,0x18, ++0xaf,0xa6,0x00,0x1c,0x30,0xe7,0x00,0x10,0x30,0x56,0x00,0x01,0x80,0x97,0x00,0x06, ++0x14,0xe0,0x00,0x47,0x00,0x05,0xf7,0xc2,0x80,0x82,0x00,0x05,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x44,0x02,0x71,0x10,0x21,0x93,0x90,0xc5,0x29,0x00,0x00,0x00,0x00, ++0x2e,0x02,0x00,0x0c,0x14,0x40,0x00,0x06,0x02,0x00,0x20,0x21,0x00,0x16,0x10,0x40, ++0x00,0x43,0x10,0x21,0x00,0x02,0x11,0x00,0x02,0x02,0x10,0x21,0x24,0x44,0x00,0x04, ++0x02,0x71,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x50,0x00,0x43,0x10,0x21, ++0x00,0x80,0x80,0x21,0xa0,0x44,0x00,0x03,0xa0,0x44,0x00,0x00,0x02,0x00,0x20,0x21, ++0x02,0xc0,0x28,0x21,0x0c,0x00,0x10,0x70,0x02,0xa0,0x30,0x21,0x02,0x71,0x18,0x21, ++0x00,0x03,0x88,0x80,0x00,0x40,0xa0,0x21,0x27,0x82,0x99,0x60,0x02,0x22,0x10,0x21, ++0x8c,0x44,0x00,0x00,0x26,0xe3,0x00,0x02,0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21, ++0x00,0x04,0x25,0xc2,0x00,0x03,0x18,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x18,0x40, ++0x03,0xc4,0x20,0x24,0x14,0x80,0x00,0x15,0x02,0x43,0x38,0x21,0x3c,0x08,0xb0,0x03, ++0x35,0x08,0x00,0x28,0x8d,0x03,0x00,0x00,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x48, ++0x27,0x82,0x99,0x48,0x02,0x22,0x10,0x21,0x24,0x63,0x00,0x01,0x02,0xa0,0x28,0x21, ++0xa4,0x54,0x00,0x04,0x00,0xc0,0x38,0x21,0x0c,0x00,0x0e,0xcd,0xad,0x03,0x00,0x00, ++0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc,0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c, ++0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x48,0x8f,0xa2,0x00,0x1c, ++0x8f,0xa6,0x00,0x18,0x02,0x00,0x20,0x21,0x02,0xc0,0x28,0x21,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x10,0x97,0xaf,0xa0,0x00,0x14,0x08,0x00,0x11,0x53,0x02,0x82,0xa0,0x21, ++0x02,0x71,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x50,0x00,0x43,0x10,0x21, ++0x90,0x50,0x00,0x00,0x08,0x00,0x11,0x3f,0xa0,0x50,0x00,0x03,0x27,0xbd,0xff,0xb8, ++0xaf,0xb1,0x00,0x24,0x8f,0xb1,0x00,0x5c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x34,0x63,0x00,0x20,0x24,0x42,0x45,0xdc,0xaf,0xbe,0x00,0x40,0xaf,0xb7,0x00,0x3c, ++0xaf,0xb6,0x00,0x38,0xaf,0xb5,0x00,0x34,0xaf,0xb4,0x00,0x30,0xaf,0xa5,0x00,0x4c, ++0x8f,0xb5,0x00,0x58,0xaf,0xbf,0x00,0x44,0xaf,0xb3,0x00,0x2c,0xaf,0xb2,0x00,0x28, ++0xaf,0xb0,0x00,0x20,0x00,0xe0,0xb0,0x21,0xac,0x62,0x00,0x00,0x00,0x80,0xf0,0x21, ++0x00,0x00,0xb8,0x21,0x16,0x20,0x00,0x2b,0x00,0x00,0xa0,0x21,0x27,0x85,0xbd,0x40, ++0x00,0x07,0x10,0x80,0x00,0x45,0x10,0x21,0x8c,0x53,0x00,0x00,0x00,0x15,0x18,0x80, ++0x00,0x65,0x18,0x21,0x92,0x62,0x00,0x16,0x8c,0x72,0x00,0x00,0x30,0x42,0x00,0x03, ++0x14,0x40,0x00,0x2d,0x00,0x00,0x00,0x00,0x92,0x42,0x00,0x16,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x03,0x14,0x40,0x00,0x28,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x34, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x18,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x38, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x14,0x02,0x20,0x10,0x21,0x8c,0x82,0x00,0x3c, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0f,0x3c,0x03,0xb0,0x09,0x3c,0x05,0xb0,0x05, ++0x34,0x63,0x01,0x44,0x34,0xa5,0x02,0x52,0x94,0x66,0x00,0x00,0x90,0xa2,0x00,0x00, ++0x8f,0xa3,0x00,0x4c,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x06,0x30,0x42,0x00,0x01, ++0x10,0x40,0x00,0x04,0x30,0xc6,0xff,0xff,0x2c,0xc2,0x00,0x41,0x10,0x40,0x00,0x09, ++0x24,0x05,0x00,0x14,0x02,0x20,0x10,0x21,0x7b,0xbe,0x02,0x3c,0x7b,0xb6,0x01,0xfc, ++0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x48,0x0c,0x00,0x0e,0xa8,0x24,0x06,0x01,0x07,0x24,0x02,0x00,0x01, ++0x08,0x00,0x11,0xb9,0xa3,0xc2,0x00,0x11,0x10,0xc0,0x00,0x1c,0x24,0x02,0x00,0x01, ++0x10,0xc2,0x00,0x17,0x00,0xc0,0x88,0x21,0x96,0x54,0x00,0x1a,0x02,0xa0,0xb8,0x21, ++0x12,0x20,0xff,0xed,0x02,0x20,0x10,0x21,0x27,0x83,0xbd,0x40,0x00,0x17,0x10,0x80, ++0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x28, ++0x80,0x86,0x00,0x12,0x8c,0x62,0x00,0x00,0x00,0x14,0x2c,0x00,0x00,0x05,0x2c,0x03, ++0x00,0x46,0x10,0x21,0x8f,0xa6,0x00,0x4c,0x02,0xe0,0x38,0x21,0x03,0xc0,0x20,0x21, ++0x0c,0x00,0x0e,0xcd,0xac,0x62,0x00,0x00,0x08,0x00,0x11,0xb9,0xaf,0xd1,0x00,0x40, ++0x96,0x74,0x00,0x1a,0x08,0x00,0x11,0xcc,0x02,0xc0,0xb8,0x21,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x01,0x08,0x8c,0x50,0x00,0x00,0x02,0x60,0x20,0x21,0x0c,0x00,0x26,0x64, ++0x02,0x00,0x28,0x21,0x30,0x42,0x00,0xff,0x02,0x00,0x28,0x21,0x02,0x40,0x20,0x21, ++0x0c,0x00,0x26,0x64,0xaf,0xa2,0x00,0x18,0x8f,0xa4,0x00,0x18,0x00,0x00,0x00,0x00, ++0x10,0x80,0x00,0xed,0x30,0x50,0x00,0xff,0x12,0x00,0x00,0x18,0x24,0x11,0x00,0x01, ++0x96,0x63,0x00,0x14,0x96,0x44,0x00,0x14,0x27,0x85,0x99,0x40,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x00,0x04,0x18,0xc0, ++0x8c,0x46,0x00,0x08,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21, ++0x00,0x06,0x17,0x02,0x24,0x04,0x00,0xff,0x8c,0x63,0x00,0x08,0x10,0x44,0x00,0xd6, ++0x00,0x03,0x17,0x02,0x10,0x44,0x00,0xd5,0x3c,0x02,0x80,0x00,0x00,0x66,0x18,0x2b, ++0x24,0x11,0x00,0x02,0x24,0x02,0x00,0x01,0x00,0x43,0x88,0x0a,0x24,0x02,0x00,0x01, ++0x12,0x22,0x00,0x5a,0x24,0x02,0x00,0x02,0x16,0x22,0xff,0xbd,0x00,0x00,0x00,0x00, ++0x96,0x49,0x00,0x14,0x27,0x82,0x99,0x44,0x02,0xa0,0xb8,0x21,0x00,0x09,0x50,0xc0, ++0x01,0x49,0x18,0x21,0x00,0x03,0x40,0x80,0x01,0x02,0x10,0x21,0x8c,0x43,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c,0x8c,0x62,0x00,0x04, ++0x00,0x05,0x24,0x42,0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10,0x30,0x66,0x00,0x01, ++0x14,0x40,0x00,0x41,0x30,0x87,0x00,0x01,0x27,0x82,0x99,0x58,0x01,0x02,0x10,0x21, ++0x80,0x44,0x00,0x00,0x27,0x82,0xbe,0xb8,0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23, ++0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21, ++0x90,0x45,0x00,0x05,0x27,0x84,0xbd,0xe0,0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00, ++0x10,0xa0,0x00,0x2b,0x2c,0x64,0x00,0x0c,0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21, ++0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21,0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03, ++0xa0,0x22,0x00,0xb9,0x14,0x80,0x00,0x06,0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40, ++0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04, ++0x01,0x49,0x10,0x21,0x27,0x83,0x99,0x50,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x00,0xa0,0x18,0x21,0xa0,0x45,0x00,0x03,0xa0,0x45,0x00,0x00,0x24,0x02,0x00,0x08, ++0x12,0x02,0x00,0x0b,0x24,0x02,0x00,0x01,0x00,0x60,0x28,0x21,0x02,0x40,0x20,0x21, ++0x0c,0x00,0x26,0xe0,0xaf,0xa2,0x00,0x10,0x30,0x54,0xff,0xff,0x92,0x42,0x00,0x16, ++0x00,0x00,0x00,0x00,0x02,0x02,0x10,0x25,0x08,0x00,0x11,0xcc,0xa2,0x42,0x00,0x16, ++0x00,0x60,0x28,0x21,0x02,0x40,0x20,0x21,0x0c,0x00,0x26,0x91,0xaf,0xa0,0x00,0x10, ++0x08,0x00,0x12,0x4f,0x30,0x54,0xff,0xff,0x08,0x00,0x12,0x37,0x00,0x60,0x10,0x21, ++0x14,0x80,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21, ++0x08,0x00,0x12,0x37,0x24,0x42,0x00,0x04,0x27,0x82,0x99,0x50,0x01,0x02,0x10,0x21, ++0x90,0x43,0x00,0x00,0x08,0x00,0x12,0x47,0xa0,0x43,0x00,0x03,0x96,0x69,0x00,0x14, ++0x02,0xc0,0xb8,0x21,0x24,0x0b,0x00,0x01,0x00,0x09,0x10,0xc0,0x00,0x49,0x18,0x21, ++0x00,0x03,0x40,0x80,0x00,0x40,0x50,0x21,0x27,0x82,0x99,0x44,0x01,0x02,0x10,0x21, ++0x8c,0x43,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x65,0x00,0x08,0x8c,0x62,0x00,0x0c, ++0x8c,0x62,0x00,0x04,0x00,0x05,0x24,0x42,0x00,0x05,0x1c,0x82,0x30,0x42,0x00,0x10, ++0x30,0x66,0x00,0x01,0x10,0x40,0x00,0x0d,0x30,0x87,0x00,0x01,0x27,0x82,0x99,0x58, ++0x01,0x02,0x10,0x21,0x80,0x43,0x00,0x00,0x00,0x00,0x58,0x21,0x00,0x03,0x11,0x00, ++0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80, ++0x27,0x83,0xbe,0xb0,0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x04,0x11,0x60,0x00,0x4f, ++0x00,0x00,0x00,0x00,0x01,0x49,0x10,0x21,0x00,0x02,0x20,0x80,0x27,0x85,0x99,0x50, ++0x00,0x85,0x10,0x21,0x80,0x43,0x00,0x05,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x42, ++0x01,0x49,0x10,0x21,0x27,0x82,0x99,0x58,0x00,0x82,0x10,0x21,0x80,0x44,0x00,0x00, ++0x27,0x82,0xbe,0xb8,0x00,0x04,0x19,0x00,0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80, ++0x00,0x64,0x18,0x23,0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x90,0x45,0x00,0x05, ++0x27,0x84,0xbd,0xe0,0x00,0x64,0x18,0x21,0x90,0x63,0x00,0x00,0x10,0xa0,0x00,0x2c, ++0x2c,0x64,0x00,0x0c,0x14,0x80,0x00,0x04,0x00,0x60,0x10,0x21,0x00,0x06,0x11,0x00, ++0x00,0x62,0x10,0x21,0x24,0x42,0x00,0x24,0x3c,0x01,0xb0,0x03,0xa0,0x22,0x00,0xb9, ++0x14,0x80,0x00,0x06,0x00,0x60,0x28,0x21,0x00,0x07,0x10,0x40,0x00,0x46,0x10,0x21, ++0x00,0x02,0x11,0x00,0x00,0x62,0x10,0x21,0x24,0x45,0x00,0x04,0x01,0x49,0x10,0x21, ++0x27,0x83,0x99,0x50,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x00,0xa0,0x18,0x21, ++0xa0,0x45,0x00,0x03,0xa0,0x45,0x00,0x00,0x8f,0xa4,0x00,0x18,0x24,0x02,0x00,0x08, ++0x10,0x82,0x00,0x0c,0x00,0x60,0x28,0x21,0x24,0x02,0x00,0x01,0x02,0x60,0x20,0x21, ++0x0c,0x00,0x26,0xe0,0xaf,0xa2,0x00,0x10,0x8f,0xa3,0x00,0x18,0x30,0x54,0xff,0xff, ++0x92,0x62,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x25,0x08,0x00,0x11,0xcc, ++0xa2,0x62,0x00,0x16,0x02,0x60,0x20,0x21,0x0c,0x00,0x26,0x91,0xaf,0xa0,0x00,0x10, ++0x08,0x00,0x12,0xbe,0x00,0x00,0x00,0x00,0x08,0x00,0x12,0xa6,0x00,0x60,0x10,0x21, ++0x14,0x80,0xff,0xfd,0x00,0x00,0x00,0x00,0x00,0x06,0x11,0x00,0x00,0x62,0x10,0x21, ++0x08,0x00,0x12,0xa6,0x24,0x42,0x00,0x04,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21, ++0x90,0x43,0x00,0x00,0x08,0x00,0x12,0xb6,0xa0,0x43,0x00,0x03,0x27,0x85,0x99,0x50, ++0x08,0x00,0x12,0xd2,0x01,0x49,0x10,0x21,0x3c,0x02,0x80,0x00,0x00,0x62,0x18,0x26, ++0x08,0x00,0x12,0x07,0x00,0xc2,0x30,0x26,0x12,0x00,0xff,0x2d,0x24,0x02,0x00,0x01, ++0x08,0x00,0x12,0x0c,0x24,0x11,0x00,0x02,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00, ++0x27,0xbd,0xff,0xd0,0x24,0x42,0x4b,0x88,0x34,0x63,0x00,0x20,0x3c,0x05,0xb0,0x05, ++0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x28, ++0xaf,0xb0,0x00,0x18,0xac,0x62,0x00,0x00,0x34,0xa5,0x02,0x42,0x90,0xa2,0x00,0x00, ++0x00,0x80,0x90,0x21,0x24,0x11,0x00,0x10,0x30,0x53,0x00,0xff,0x24,0x02,0x00,0x10, ++0x12,0x22,0x00,0xcf,0x00,0x00,0x18,0x21,0x24,0x02,0x00,0x11,0x12,0x22,0x00,0xc1, ++0x24,0x02,0x00,0x12,0x12,0x22,0x00,0xb4,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0xad, ++0xae,0x43,0x00,0x40,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x44,0x00,0x00, ++0x3c,0x03,0x00,0x02,0x34,0x63,0x00,0xff,0x00,0x83,0x80,0x24,0x00,0x10,0x14,0x43, ++0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x8e,0x42,0x00,0x34,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x92,0x00,0x00,0x00,0x00,0x93,0x83,0x94,0x51,0x00,0x00,0x00,0x00, ++0x30,0x62,0x00,0x02,0x10,0x40,0x00,0x04,0x32,0x10,0x00,0xff,0x00,0x10,0x11,0xc3, ++0x14,0x40,0x00,0x86,0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x15,0x02,0x00,0x10,0x21, ++0x26,0x22,0x00,0x01,0x30,0x51,0x00,0xff,0x2e,0x23,0x00,0x13,0x14,0x60,0xff,0xdb, ++0x24,0x03,0x00,0x02,0x12,0x63,0x00,0x73,0x24,0x02,0x00,0x05,0x2a,0x62,0x00,0x03, ++0x10,0x40,0x00,0x58,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01,0x12,0x62,0x00,0x4b, ++0x02,0x40,0x20,0x21,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x70,0x00,0xff,0x12,0x00,0x00,0x06,0x02,0x00,0x10,0x21, ++0x8f,0xbf,0x00,0x28,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x30,0x92,0x46,0x00,0x04,0x8e,0x43,0x00,0x24,0x24,0x02,0x00,0x07, ++0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x11,0x77,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x24,0x3c,0x02,0xb0,0x05, ++0x8c,0x42,0x02,0x2c,0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xec, ++0x02,0x00,0x10,0x21,0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x24,0x02,0x00,0x05, ++0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x11,0x77,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x28,0x3c,0x02,0xb0,0x05, ++0x8c,0x42,0x02,0x2c,0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xdc, ++0x02,0x00,0x10,0x21,0x92,0x46,0x00,0x06,0x8e,0x43,0x00,0x2c,0x24,0x02,0x00,0x03, ++0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x11,0x77,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x2c,0x3c,0x02,0xb0,0x05, ++0x8c,0x42,0x02,0x2c,0x00,0x00,0x00,0x00,0x30,0x50,0x00,0xff,0x16,0x00,0xff,0xcc, ++0x02,0x00,0x10,0x21,0x92,0x46,0x00,0x07,0x8e,0x43,0x00,0x30,0x24,0x02,0x00,0x02, ++0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01,0xaf,0xa2,0x00,0x10, ++0x0c,0x00,0x11,0x77,0xaf,0xa3,0x00,0x14,0xae,0x42,0x00,0x30,0x3c,0x02,0xb0,0x05, ++0x8c,0x42,0x02,0x2c,0x08,0x00,0x13,0x28,0x30,0x42,0x00,0xff,0x92,0x46,0x00,0x04, ++0x8e,0x43,0x00,0x24,0x24,0x02,0x00,0x07,0x00,0x00,0x28,0x21,0x24,0x07,0x00,0x06, ++0xaf,0xa2,0x00,0x10,0x0c,0x00,0x11,0x77,0xaf,0xa3,0x00,0x14,0x08,0x00,0x13,0x21, ++0xae,0x42,0x00,0x24,0x12,0x62,0x00,0x0d,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x08, ++0x16,0x62,0xff,0xa8,0x02,0x40,0x20,0x21,0x92,0x46,0x00,0x07,0x8e,0x42,0x00,0x30, ++0x24,0x05,0x00,0x03,0x24,0x07,0x00,0x01,0xaf,0xa3,0x00,0x10,0x0c,0x00,0x11,0x77, ++0xaf,0xa2,0x00,0x14,0x08,0x00,0x13,0x21,0xae,0x42,0x00,0x30,0x92,0x46,0x00,0x06, ++0x8e,0x43,0x00,0x2c,0x02,0x40,0x20,0x21,0x24,0x05,0x00,0x02,0x00,0x00,0x38,0x21, ++0xaf,0xa2,0x00,0x10,0x0c,0x00,0x11,0x77,0xaf,0xa3,0x00,0x14,0x08,0x00,0x13,0x21, ++0xae,0x42,0x00,0x2c,0x92,0x46,0x00,0x05,0x8e,0x43,0x00,0x28,0x02,0x40,0x20,0x21, ++0x24,0x05,0x00,0x01,0x24,0x07,0x00,0x04,0xaf,0xa2,0x00,0x10,0x0c,0x00,0x11,0x77, ++0xaf,0xa3,0x00,0x14,0x08,0x00,0x13,0x21,0xae,0x42,0x00,0x28,0x0c,0x00,0x01,0x57, ++0x24,0x04,0x00,0x01,0x08,0x00,0x13,0x12,0x00,0x00,0x00,0x00,0x8f,0x84,0xbd,0x80, ++0xae,0x40,0x00,0x34,0x94,0x85,0x00,0x14,0x0c,0x00,0x22,0xe1,0x00,0x00,0x00,0x00, ++0x93,0x83,0x94,0x51,0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x02,0x10,0x40,0xff,0x69, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x57,0x00,0x00,0x20,0x21,0x08,0x00,0x13,0x0a, ++0x00,0x00,0x00,0x00,0x02,0x40,0x20,0x21,0x0c,0x00,0x10,0xee,0x02,0x20,0x28,0x21, ++0x08,0x00,0x12,0xfe,0x3c,0x02,0xb0,0x05,0x8e,0x42,0x00,0x3c,0x00,0x00,0x00,0x00, ++0x14,0x40,0xff,0x4a,0x00,0x00,0x00,0x00,0x8f,0x82,0xbd,0x88,0x00,0x00,0x00,0x00, ++0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x12,0xfb, ++0xae,0x43,0x00,0x3c,0x8e,0x42,0x00,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x3d, ++0x24,0x02,0x00,0x12,0x8f,0x82,0xbd,0x84,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x2b,0x08,0x00,0x12,0xfb,0xae,0x43,0x00,0x38, ++0x8e,0x42,0x00,0x34,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x30,0x24,0x02,0x00,0x11, ++0x8f,0x82,0xbd,0x80,0x00,0x00,0x00,0x00,0x90,0x42,0x00,0x0a,0x00,0x00,0x00,0x00, ++0x00,0x02,0x18,0x2b,0x08,0x00,0x12,0xfb,0xae,0x43,0x00,0x34,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xe0,0x34,0x63,0x00,0x20,0x24,0x42,0x4f,0x3c, ++0x3c,0x08,0xb0,0x03,0xaf,0xb1,0x00,0x14,0xac,0x62,0x00,0x00,0x35,0x08,0x01,0x00, ++0xaf,0xbf,0x00,0x18,0xaf,0xb0,0x00,0x10,0x91,0x03,0x00,0x00,0x00,0xa0,0x48,0x21, ++0x24,0x11,0x00,0x0a,0x2c,0xa5,0x00,0x04,0x24,0x02,0x00,0x10,0x00,0x45,0x88,0x0a, ++0x30,0x63,0x00,0x01,0x00,0xc0,0x28,0x21,0x14,0x60,0x00,0x02,0x00,0x11,0x40,0x40, ++0x02,0x20,0x40,0x21,0x84,0x83,0x00,0x0c,0x31,0x11,0x00,0xff,0x01,0x20,0x20,0x21, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x48, ++0x00,0x43,0x10,0x21,0x84,0x43,0x00,0x04,0x24,0x06,0x00,0x0e,0x10,0xe0,0x00,0x06, ++0x02,0x23,0x80,0x21,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x10,0x70,0x00,0x00,0x00,0x00, ++0x02,0x11,0x18,0x21,0x08,0x00,0x13,0xf1,0x00,0x62,0x80,0x21,0x27,0xbd,0xff,0xd0, ++0xaf,0xbf,0x00,0x28,0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18, ++0xaf,0xb5,0x00,0x24,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0x84,0x82,0x00,0x0c, ++0x3c,0x06,0xb0,0x03,0x34,0xc6,0x00,0x20,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, ++0x00,0x03,0x18,0x80,0x27,0x82,0x99,0x44,0x00,0x62,0x10,0x21,0x8c,0x55,0x00,0x18, ++0x3c,0x02,0x80,0x00,0x24,0x42,0x4f,0xec,0xac,0xc2,0x00,0x00,0x8e,0xb0,0x00,0x08, ++0x27,0x82,0x99,0x48,0x00,0x62,0x18,0x21,0x90,0x71,0x00,0x07,0x00,0x10,0x86,0x43, ++0x32,0x10,0x00,0x01,0x00,0xa0,0x38,0x21,0x02,0x00,0x30,0x21,0x00,0xa0,0x98,0x21, ++0x02,0x20,0x28,0x21,0x0c,0x00,0x13,0xcf,0x00,0x80,0x90,0x21,0x02,0x20,0x20,0x21, ++0x02,0x00,0x28,0x21,0x24,0x06,0x00,0x14,0x0c,0x00,0x10,0x70,0x00,0x40,0xa0,0x21, ++0x86,0x43,0x00,0x0c,0x3c,0x09,0xb0,0x09,0x3c,0x08,0xb0,0x09,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x50,0x00,0x43,0x10,0x21, ++0x80,0x43,0x00,0x06,0x3c,0x07,0xb0,0x09,0x3c,0x05,0xb0,0x09,0x28,0x62,0x00,0x00, ++0x24,0x64,0x00,0x03,0x00,0x82,0x18,0x0b,0x00,0x03,0x18,0x83,0x3c,0x02,0xb0,0x09, ++0x00,0x03,0x18,0x80,0x34,0x42,0x01,0x02,0x35,0x29,0x01,0x10,0x35,0x08,0x01,0x14, ++0x34,0xe7,0x01,0x20,0x34,0xa5,0x01,0x24,0xa4,0x54,0x00,0x00,0x12,0x60,0x00,0x11, ++0x02,0xa3,0xa8,0x21,0x8e,0xa2,0x00,0x0c,0x8e,0xa3,0x00,0x08,0x00,0x02,0x14,0x00, ++0x00,0x03,0x1c,0x02,0x00,0x43,0x10,0x21,0xad,0x22,0x00,0x00,0x8e,0xa3,0x00,0x0c, ++0x00,0x00,0x00,0x00,0x00,0x03,0x1c,0x02,0xa5,0x03,0x00,0x00,0x8f,0xbf,0x00,0x28, ++0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x30,0x8e,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0xad,0x22,0x00,0x00, ++0x8e,0xa4,0x00,0x08,0x00,0x00,0x00,0x00,0xa5,0x04,0x00,0x00,0x7a,0xa2,0x00,0x7c, ++0x00,0x00,0x00,0x00,0x00,0x03,0x1c,0x00,0x00,0x02,0x14,0x02,0x00,0x62,0x18,0x21, ++0xac,0xe3,0x00,0x00,0x8e,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x02, ++0x08,0x00,0x14,0x43,0xa4,0xa2,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb2,0x00,0x18, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c,0xaf,0xb1,0x00,0x14,0x84,0x82,0x00,0x0c, ++0x00,0x80,0x90,0x21,0x3c,0x05,0xb0,0x03,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21, ++0x00,0x04,0x20,0x80,0x27,0x82,0x99,0x44,0x00,0x82,0x10,0x21,0x8c,0x51,0x00,0x18, ++0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x51,0x68,0x27,0x83,0x99,0x48, ++0xac,0xa2,0x00,0x00,0x00,0x83,0x20,0x21,0x3c,0x02,0xb0,0x03,0x90,0x86,0x00,0x07, ++0x34,0x42,0x01,0x00,0x8e,0x23,0x00,0x08,0x90,0x44,0x00,0x00,0x2c,0xc5,0x00,0x04, ++0x24,0x02,0x00,0x10,0x24,0x10,0x00,0x0a,0x00,0x45,0x80,0x0a,0x00,0x03,0x1e,0x43, ++0x30,0x84,0x00,0x01,0x30,0x65,0x00,0x01,0x14,0x80,0x00,0x02,0x00,0x10,0x10,0x40, ++0x02,0x00,0x10,0x21,0x00,0xc0,0x20,0x21,0x24,0x06,0x00,0x20,0x0c,0x00,0x10,0x70, ++0x30,0x50,0x00,0xff,0x86,0x44,0x00,0x0c,0x27,0x85,0x99,0x50,0x3c,0x06,0xb0,0x09, ++0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x65,0x18,0x21, ++0x80,0x64,0x00,0x06,0x00,0x50,0x10,0x21,0x34,0xc6,0x01,0x02,0x24,0x85,0x00,0x03, ++0x28,0x83,0x00,0x00,0x00,0xa3,0x20,0x0b,0x00,0x04,0x20,0x83,0x00,0x04,0x20,0x80, ++0xa4,0xc2,0x00,0x00,0x02,0x24,0x20,0x21,0x8c,0x83,0x00,0x04,0x3c,0x02,0xb0,0x09, ++0x34,0x42,0x01,0x10,0xac,0x43,0x00,0x00,0x8c,0x86,0x00,0x08,0x3c,0x02,0xb0,0x09, ++0x34,0x42,0x01,0x14,0xa4,0x46,0x00,0x00,0x8c,0x85,0x00,0x0c,0x8c,0x82,0x00,0x08, ++0x3c,0x06,0xb0,0x09,0x00,0x05,0x2c,0x00,0x00,0x02,0x14,0x02,0x00,0xa2,0x28,0x21, ++0x34,0xc6,0x01,0x20,0xac,0xc5,0x00,0x00,0x8c,0x83,0x00,0x0c,0x3c,0x05,0xb0,0x09, ++0x34,0xa5,0x01,0x24,0x00,0x03,0x1c,0x02,0xa4,0xa3,0x00,0x00,0x92,0x42,0x00,0x0a, ++0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x30,0x00,0x02,0x13,0x00,0x24,0x42,0x00,0x04, ++0x30,0x42,0xff,0xff,0xa4,0x62,0x00,0x00,0x86,0x44,0x00,0x0c,0x27,0x83,0x99,0x58, ++0x8f,0xbf,0x00,0x1c,0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x43,0x10,0x21,0x94,0x44,0x00,0x02,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x3c,0x05,0xb0,0x09,0x34,0xa5,0x01,0x32,0xa4,0xa4,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x00, ++0xaf,0xb0,0x00,0x10,0x34,0x42,0x00,0x20,0x00,0xa0,0x80,0x21,0x24,0x63,0x52,0xf4, ++0x00,0x05,0x2c,0x43,0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00, ++0x10,0xa0,0x00,0x05,0x00,0x80,0x88,0x21,0x8c,0x82,0x00,0x34,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0xaf,0x00,0x00,0x00,0x00,0x32,0x10,0x00,0xff,0x12,0x00,0x00,0x47, ++0x00,0x00,0x10,0x21,0x24,0x02,0x00,0x08,0x12,0x02,0x00,0x9c,0x2a,0x02,0x00,0x09, ++0x10,0x40,0x00,0x84,0x24,0x02,0x00,0x40,0x24,0x04,0x00,0x02,0x12,0x04,0x00,0x74, ++0x2a,0x02,0x00,0x03,0x10,0x40,0x00,0x64,0x24,0x02,0x00,0x04,0x24,0x02,0x00,0x01, ++0x12,0x02,0x00,0x55,0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x11,0x92,0x27,0x00,0x11, ++0x10,0x40,0x00,0x4e,0x00,0x00,0x00,0x00,0x92,0x26,0x00,0x0a,0x24,0x02,0x00,0x12, ++0x10,0x46,0x00,0x09,0x30,0xc2,0x00,0xff,0x27,0x83,0xbd,0x40,0x00,0x02,0x10,0x80, ++0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x83,0x00,0x14, ++0x00,0x00,0x00,0x00,0xa6,0x23,0x00,0x0c,0x3c,0x02,0xb0,0x09,0x34,0x42,0x00,0x40, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x03,0xa2,0x23,0x00,0x10, ++0x14,0x60,0x00,0x2b,0x30,0x65,0x00,0x01,0x30,0xc2,0x00,0xff,0x27,0x83,0xbd,0x40, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x82,0x23,0x00,0x12, ++0x90,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42,0x30,0x42,0x00,0x01, ++0x00,0x62,0x18,0x21,0x00,0x03,0x26,0x00,0x14,0x80,0x00,0x18,0xa2,0x23,0x00,0x12, ++0x00,0x07,0x16,0x00,0x14,0x40,0x00,0x11,0x24,0x02,0x00,0x01,0x96,0x23,0x00,0x0c, ++0x27,0x84,0x99,0x50,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x44,0x10,0x21,0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00,0x3c,0x02,0xb0,0x00, ++0x00,0x65,0x18,0x21,0x00,0x62,0x18,0x21,0x90,0x64,0x00,0x00,0x90,0x62,0x00,0x04, ++0xa2,0x20,0x00,0x15,0xa3,0x80,0x95,0x14,0x24,0x02,0x00,0x01,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x14,0x5a, ++0x02,0x20,0x20,0x21,0x92,0x27,0x00,0x11,0x08,0x00,0x15,0x05,0x00,0x07,0x16,0x00, ++0x0c,0x00,0x13,0xfb,0x02,0x20,0x20,0x21,0x86,0x23,0x00,0x0c,0x27,0x84,0x99,0x48, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x44,0x20,0x21, ++0x90,0x85,0x00,0x07,0x27,0x83,0x99,0x50,0x00,0x43,0x10,0x21,0xa2,0x25,0x00,0x13, ++0x90,0x83,0x00,0x07,0x08,0x00,0x15,0x1d,0xa0,0x43,0x00,0x02,0x92,0x26,0x00,0x0a, ++0x08,0x00,0x14,0xe6,0x30,0xc2,0x00,0xff,0x8e,0x22,0x00,0x24,0x00,0x00,0x00,0x00, ++0x10,0x50,0x00,0x07,0xa2,0x20,0x00,0x08,0x24,0x02,0x00,0x07,0xa2,0x22,0x00,0x0a, ++0x92,0x22,0x00,0x27,0xae,0x20,0x00,0x24,0x08,0x00,0x14,0xde,0xa2,0x22,0x00,0x04, ++0x08,0x00,0x15,0x37,0x24,0x02,0x00,0x06,0x16,0x02,0xff,0x9f,0x24,0x02,0x00,0x01, ++0x8e,0x23,0x00,0x2c,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x07,0xa2,0x24,0x00,0x08, ++0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2f,0xae,0x20,0x00,0x2c, ++0x08,0x00,0x14,0xde,0xa2,0x22,0x00,0x06,0x08,0x00,0x15,0x46,0xa2,0x20,0x00,0x0a, ++0x8e,0x22,0x00,0x28,0x24,0x03,0x00,0x01,0x24,0x04,0x00,0x01,0x10,0x44,0x00,0x07, ++0xa2,0x23,0x00,0x08,0x24,0x02,0x00,0x05,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x2b, ++0xae,0x20,0x00,0x28,0x08,0x00,0x14,0xde,0xa2,0x22,0x00,0x05,0x08,0x00,0x15,0x52, ++0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x10,0x2a,0x02,0x00,0x41,0x10,0x40,0x00,0x08, ++0x24,0x02,0x00,0x80,0x24,0x02,0x00,0x20,0x16,0x02,0xff,0x7f,0x24,0x02,0x00,0x12, ++0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08,0x08,0x00,0x14,0xde,0xae,0x20,0x00,0x3c, ++0x16,0x02,0xff,0x79,0x24,0x02,0x00,0x10,0xa2,0x22,0x00,0x0a,0xa2,0x22,0x00,0x08, ++0x08,0x00,0x14,0xde,0xae,0x20,0x00,0x34,0x24,0x02,0x00,0x11,0xa2,0x22,0x00,0x0a, ++0xa2,0x22,0x00,0x08,0x08,0x00,0x14,0xde,0xae,0x20,0x00,0x38,0x8e,0x24,0x00,0x30, ++0x24,0x02,0x00,0x03,0x24,0x03,0x00,0x01,0x10,0x83,0x00,0x07,0xa2,0x22,0x00,0x08, ++0x24,0x02,0x00,0x02,0xa2,0x22,0x00,0x0a,0x92,0x22,0x00,0x33,0xae,0x20,0x00,0x30, ++0x08,0x00,0x14,0xde,0xa2,0x22,0x00,0x07,0x08,0x00,0x15,0x76,0xa2,0x24,0x00,0x0a, ++0x8f,0x84,0xbd,0x80,0xae,0x20,0x00,0x34,0x94,0x85,0x00,0x14,0x0c,0x00,0x22,0xe1, ++0x32,0x10,0x00,0xff,0x08,0x00,0x14,0xcf,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x24,0x42,0x56,0x0c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, ++0x80,0xa2,0x00,0x15,0x3c,0x06,0xb0,0x05,0x10,0x40,0x00,0x0a,0x34,0xc6,0x02,0x54, ++0x83,0x83,0x95,0x14,0x00,0x00,0x00,0x00,0xac,0x83,0x00,0x24,0x8c,0xc2,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x03,0xe0,0x00,0x08, ++0xac,0x82,0x00,0x28,0x8c,0x82,0x00,0x2c,0x3c,0x06,0xb0,0x05,0x34,0xc6,0x04,0x50, ++0x00,0x02,0x18,0x43,0x30,0x63,0x00,0x01,0x10,0x40,0x00,0x04,0x30,0x45,0x00,0x01, ++0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x24,0x90,0xc2,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x30,0x43,0x00,0x02,0x30,0x42,0x00,0x01, ++0xac,0x83,0x00,0x28,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x24,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd8,0x34,0x63,0x00,0x20,0x24,0x42,0x56,0x9c, ++0xac,0x62,0x00,0x00,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x20,0xaf,0xb0,0x00,0x18, ++0x90,0xa6,0x00,0x0a,0x27,0x83,0xbd,0x40,0x00,0xa0,0x88,0x21,0x00,0x06,0x10,0x80, ++0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00,0x80,0xa5,0x00,0x11,0x92,0x03,0x00,0x12, ++0x10,0xa0,0x00,0x04,0xa2,0x20,0x00,0x15,0x24,0x02,0x00,0x12,0x10,0xc2,0x00,0xda, ++0x00,0x00,0x00,0x00,0x82,0x22,0x00,0x12,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x67, ++0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x12,0xa2,0x00,0x00,0x19,0x86,0x23,0x00,0x0c, ++0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x83,0x99,0x60,0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00,0x92,0x03,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x63,0x00,0xdf,0xa2,0x03,0x00,0x16,0x82,0x02,0x00,0x12, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x92,0x23,0x00,0x08, ++0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x45,0x24,0x02,0x00,0x01,0xa2,0x20,0x00,0x04, ++0x92,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x1e,0x24,0x02,0x00,0x01, ++0x92,0x07,0x00,0x0a,0xa2,0x02,0x00,0x17,0x92,0x02,0x00,0x16,0x30,0xe3,0x00,0xff, ++0x30,0x42,0x00,0xe4,0x10,0x60,0x00,0x03,0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01, ++0xa2,0x02,0x00,0x16,0x11,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x02,0x00,0x16, ++0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0xa2,0x02,0x00,0x16,0x92,0x02,0x00,0x17, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x08,0x00,0x00,0x00,0x00,0x96,0x02,0x00,0x06, ++0x00,0x00,0x00,0x00,0xa6,0x02,0x00,0x14,0x8f,0xbf,0x00,0x20,0x7b,0xb0,0x00,0xfc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x96,0x02,0x00,0x00,0x08,0x00,0x15,0xf2, ++0xa6,0x02,0x00,0x14,0x92,0x07,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x03, ++0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xde,0xa2,0x00,0x00,0x17,0x96,0x04,0x00,0x00, ++0x96,0x05,0x00,0x06,0x27,0x86,0x99,0x40,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21, ++0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21, ++0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x66,0x00,0x08,0x8c,0x45,0x00,0x08, ++0x3c,0x03,0x80,0x00,0x00,0xc3,0x20,0x24,0x10,0x80,0x00,0x08,0x00,0xa3,0x10,0x24, ++0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0x80,0x00,0x02,0x24,0x03,0x00,0x01, ++0x00,0xa6,0x18,0x2b,0x08,0x00,0x15,0xde,0xa2,0x03,0x00,0x17,0x10,0x40,0xff,0xfd, ++0x00,0xa6,0x18,0x2b,0x08,0x00,0x16,0x12,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09, ++0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0xb8, ++0x00,0x00,0x00,0x00,0x08,0x00,0x15,0xd8,0xa2,0x20,0x00,0x07,0x08,0x00,0x15,0xd8, ++0xa2,0x20,0x00,0x06,0x08,0x00,0x15,0xd8,0xa2,0x20,0x00,0x05,0x82,0x22,0x00,0x10, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x69,0x2c,0x62,0x00,0x02,0x10,0x40,0x00,0x49, ++0x3c,0x02,0xb0,0x09,0x92,0x25,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff, ++0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x3b,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05, ++0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04, ++0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x86,0x23,0x00,0x0c, ++0x96,0x26,0x00,0x0c,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80, ++0x27,0x83,0x99,0x44,0x00,0xa3,0x18,0x21,0x8c,0x64,0x00,0x18,0x00,0x00,0x00,0x00, ++0x8c,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10,0x10,0x40,0x00,0x18, ++0x24,0x07,0x00,0x01,0x93,0x82,0x94,0x51,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x0a,0x24,0x05,0x00,0x24,0x00,0x06,0x2c,0x00,0x00,0x05,0x2c,0x03, ++0x0c,0x00,0x22,0xe1,0x02,0x00,0x20,0x21,0x92,0x02,0x00,0x16,0xa2,0x00,0x00,0x12, ++0x30,0x42,0x00,0xe7,0x08,0x00,0x15,0xcf,0xa2,0x02,0x00,0x16,0xf0,0xc5,0x00,0x06, ++0x00,0x00,0x28,0x12,0x27,0x82,0x99,0x40,0x00,0xa2,0x28,0x21,0x0c,0x00,0x01,0x49, ++0x3c,0x04,0x00,0x80,0x96,0x26,0x00,0x0c,0x08,0x00,0x16,0x4f,0x00,0x06,0x2c,0x00, ++0x27,0x83,0x99,0x50,0x27,0x82,0x99,0x58,0x00,0xa2,0x10,0x21,0x00,0xa3,0x18,0x21, ++0x90,0x44,0x00,0x00,0x90,0x65,0x00,0x05,0x93,0x82,0x80,0x10,0x00,0x00,0x30,0x21, ++0x0c,0x00,0x29,0x0b,0xaf,0xa2,0x00,0x10,0x96,0x26,0x00,0x0c,0x08,0x00,0x16,0x49, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xcd,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29, ++0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x16,0x38, ++0x00,0xa2,0x10,0x07,0x86,0x26,0x00,0x0c,0x3c,0x03,0xb0,0x09,0x34,0x42,0x01,0x72, ++0x34,0x63,0x01,0x78,0x94,0x47,0x00,0x00,0x8c,0x65,0x00,0x00,0x00,0x06,0x10,0xc0, ++0x00,0x46,0x10,0x21,0x3c,0x04,0xb0,0x09,0xae,0x25,0x00,0x1c,0x34,0x84,0x01,0x7c, ++0x27,0x83,0x99,0x44,0x00,0x02,0x10,0x80,0x8c,0x85,0x00,0x00,0x00,0x43,0x10,0x21, ++0x8c,0x43,0x00,0x18,0xae,0x25,0x00,0x20,0xa6,0x27,0x00,0x18,0x8c,0x66,0x00,0x08, ++0x02,0x20,0x20,0x21,0x0c,0x00,0x16,0x9f,0x00,0x00,0x28,0x21,0x86,0x25,0x00,0x18, ++0x8e,0x26,0x00,0x1c,0x8e,0x27,0x00,0x20,0x02,0x20,0x20,0x21,0x0c,0x00,0x23,0xe3, ++0xaf,0xa2,0x00,0x10,0x08,0x00,0x15,0xcf,0xa2,0x02,0x00,0x12,0x92,0x22,0x00,0x08, ++0x08,0x00,0x15,0xcf,0xa2,0x22,0x00,0x09,0xa2,0x20,0x00,0x11,0x80,0x82,0x00,0x50, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0, ++0xac,0x40,0x00,0x00,0x08,0x00,0x15,0xcf,0xa0,0x80,0x00,0x50,0x94,0x8a,0x00,0x0c, ++0x24,0x03,0x00,0x24,0x00,0x80,0x70,0x21,0x3c,0x02,0x80,0x00,0x3c,0x04,0xb0,0x03, ++0x24,0x42,0x5a,0x7c,0xf1,0x43,0x00,0x06,0x34,0x84,0x00,0x20,0x00,0x00,0x18,0x12, ++0x00,0xa0,0x68,0x21,0xac,0x82,0x00,0x00,0x27,0x85,0x99,0x50,0x27,0x82,0x99,0x4f, ++0x27,0xbd,0xff,0xf8,0x00,0x62,0x60,0x21,0x00,0x65,0x58,0x21,0x00,0x00,0xc0,0x21, ++0x11,0xa0,0x00,0xcc,0x00,0x00,0x78,0x21,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21, ++0x91,0x87,0x00,0x00,0x80,0x48,0x00,0x04,0x03,0xa0,0x60,0x21,0x00,0x0a,0x1c,0x00, ++0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x48,0x80, ++0x27,0x83,0x99,0x44,0xa3,0xa7,0x00,0x00,0x01,0x23,0x18,0x21,0x8c,0x64,0x00,0x18, ++0x25,0x02,0xff,0xff,0x00,0x48,0x40,0x0b,0x8c,0x83,0x00,0x04,0x2d,0x05,0x00,0x07, ++0x24,0x02,0x00,0x06,0x30,0x63,0x00,0x08,0x14,0x60,0x00,0x35,0x00,0x45,0x40,0x0a, ++0x93,0xa7,0x00,0x00,0x27,0x82,0x99,0x58,0x01,0x22,0x10,0x21,0x30,0xe3,0x00,0xf0, ++0x38,0x63,0x00,0x50,0x30,0xe5,0x00,0xff,0x00,0x05,0x20,0x2b,0x00,0x03,0x18,0x2b, ++0x00,0x64,0x18,0x24,0x90,0x49,0x00,0x00,0x10,0x60,0x00,0x16,0x30,0xe4,0x00,0x0f, ++0x24,0x02,0x00,0x04,0x10,0xa2,0x00,0x9d,0x00,0x00,0x00,0x00,0x11,0xa0,0x00,0x3a, ++0x2c,0xa2,0x00,0x0c,0x10,0x40,0x00,0x02,0x24,0x84,0x00,0x0c,0x00,0xe0,0x20,0x21, ++0x30,0x84,0x00,0xff,0x00,0x04,0x10,0x40,0x27,0x83,0xc4,0x5c,0x00,0x44,0x10,0x21, ++0x00,0x43,0x10,0x21,0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xe3,0x00,0x0c, ++0xa3,0xa7,0x00,0x00,0x10,0x60,0x00,0x02,0x24,0xe2,0x00,0x04,0x00,0xe0,0x10,0x21, ++0xa3,0xa2,0x00,0x00,0x91,0x65,0x00,0x00,0x91,0x82,0x00,0x00,0x30,0xa3,0x00,0xff, ++0x00,0x62,0x10,0x2b,0x10,0x40,0x00,0x0e,0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x03, ++0x00,0x60,0x20,0x21,0x30,0xa2,0x00,0x0f,0x24,0x44,0x00,0x0c,0x00,0x04,0x10,0x40, ++0x00,0x44,0x20,0x21,0x27,0x83,0xc4,0x5c,0x00,0x83,0x18,0x21,0x90,0x62,0x00,0x02, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x05,0x00,0x09,0x11,0x00,0xa1,0x85,0x00,0x00, ++0x93,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08,0x00,0x49,0x10,0x23, ++0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21, ++0x27,0x83,0xbd,0xe8,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x2c,0x83,0x00,0x0c,0x14,0x60,0x00,0x06,0x00,0x80,0x10,0x21,0x00,0x18,0x10,0x40, ++0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0x82,0x10,0x21,0x24,0x42,0x00,0x04, ++0x08,0x00,0x17,0x00,0xa1,0x82,0x00,0x00,0x8f,0x8d,0x87,0x70,0x00,0x00,0x00,0x00, ++0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xd1, ++0x00,0x00,0x28,0x21,0x00,0x06,0x74,0x82,0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c, ++0x14,0x40,0x00,0x03,0x00,0xe0,0x10,0x21,0x30,0xe2,0x00,0x0f,0x24,0x42,0x00,0x0c, ++0x30,0x44,0x00,0xff,0xa3,0xa2,0x00,0x00,0x24,0x02,0x00,0x0c,0x10,0x82,0x00,0x0d, ++0x00,0x09,0x11,0x00,0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x04,0x18,0x40, ++0x00,0x49,0x10,0x23,0x00,0x64,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x27,0x84,0xbd,0xe8,0x00,0x44,0x10,0x21,0x90,0x47,0x00,0x00,0x00,0x00,0x00,0x00, ++0xa3,0xa7,0x00,0x00,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x44,0x00,0x43,0x10,0x21, ++0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00, ++0x30,0x63,0x00,0x10,0x14,0x60,0x00,0x33,0x00,0x06,0x14,0x42,0x00,0x09,0x11,0x00, ++0x00,0x49,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x23,0x27,0x83,0xbe,0xb8, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x04,0x90,0x43,0x00,0x05, ++0x00,0x00,0x00,0x00,0x00,0x64,0xc0,0x24,0x93,0xa7,0x00,0x00,0x00,0x00,0x00,0x00, ++0x2c,0xe2,0x00,0x0f,0x10,0x40,0x00,0x0f,0x31,0xcf,0x00,0x01,0x00,0x0a,0x1c,0x00, ++0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x84,0x99,0x40,0x00,0x44,0x10,0x21,0x84,0x43,0x00,0x06,0x00,0x00,0x00,0x00, ++0x28,0x63,0x06,0x41,0x14,0x60,0x00,0x04,0x30,0xe2,0x00,0xff,0x24,0x07,0x00,0x0f, ++0xa3,0xa7,0x00,0x00,0x30,0xe2,0x00,0xff,0x2c,0x42,0x00,0x0c,0x14,0x40,0x00,0x06, ++0x00,0xe0,0x10,0x21,0x00,0x18,0x10,0x40,0x00,0x4f,0x10,0x21,0x00,0x02,0x11,0x00, ++0x00,0x47,0x10,0x21,0x24,0x42,0x00,0x04,0xa3,0xa2,0x00,0x00,0x00,0x40,0x38,0x21, ++0x01,0xa8,0x10,0x21,0x90,0x43,0x00,0x00,0x24,0xa4,0x00,0x01,0x30,0x85,0xff,0xff, ++0x00,0xa3,0x18,0x2b,0x14,0x60,0xff,0xad,0x30,0xe2,0x00,0xff,0x08,0x00,0x16,0xed, ++0x00,0x00,0x00,0x00,0x08,0x00,0x17,0x4e,0x30,0x58,0x00,0x01,0x81,0xc2,0x00,0x48, ++0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x73,0x00,0x00,0x00,0x00,0x08,0x00,0x16,0xdb, ++0x00,0x00,0x00,0x00,0x00,0x0a,0x1c,0x00,0x00,0x03,0x1c,0x03,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x45,0x10,0x21,0x80,0x48,0x00,0x05, ++0x91,0x67,0x00,0x00,0x08,0x00,0x16,0xbb,0x03,0xa0,0x58,0x21,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x5e,0x1c,0x03,0xe0,0x00,0x08, ++0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0,0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30, ++0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28,0xaf,0xb3,0x00,0x24,0xaf,0xb2,0x00,0x20, ++0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38,0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18, ++0x84,0x82,0x00,0x0c,0x27,0x93,0x99,0x44,0x3c,0x05,0xb0,0x03,0x00,0x02,0x18,0xc0, ++0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x73,0x10,0x21,0x8c,0x5e,0x00,0x18, ++0x3c,0x02,0x80,0x00,0x34,0xa5,0x00,0x20,0x24,0x42,0x5e,0x34,0xac,0xa2,0x00,0x00, ++0x8f,0xd0,0x00,0x08,0x27,0x95,0x99,0x50,0x00,0x75,0x18,0x21,0x00,0x00,0x28,0x21, ++0x02,0x00,0x30,0x21,0x90,0x71,0x00,0x00,0x0c,0x00,0x16,0x9f,0x00,0x80,0xb0,0x21, ++0x00,0x40,0x90,0x21,0x00,0x10,0x14,0x42,0x30,0x54,0x00,0x01,0x02,0x40,0x20,0x21, ++0x00,0x10,0x14,0x82,0x02,0x80,0x28,0x21,0x12,0x51,0x00,0x23,0x00,0x10,0xbf,0xc2, ++0x86,0xc3,0x00,0x0c,0x30,0x50,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21,0xa0,0x52,0x00,0x00,0x86,0xc3,0x00,0x0c, ++0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x53,0x30,0x21,0x8c,0xc7,0x00,0x18,0x27,0x83,0x99,0x40,0x00,0x43,0x10,0x21, ++0x8c,0xe3,0x00,0x04,0x84,0x46,0x00,0x06,0x00,0x03,0x19,0x42,0x0c,0x00,0x10,0x70, ++0x30,0x73,0x00,0x01,0x00,0x40,0x88,0x21,0x02,0x40,0x20,0x21,0x02,0x80,0x28,0x21, ++0x16,0xe0,0x00,0x10,0x02,0x00,0x30,0x21,0x86,0xc2,0x00,0x0c,0x00,0x00,0x00,0x00, ++0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80,0x27,0x82,0x99,0x48, ++0x00,0x62,0x18,0x21,0xa4,0x71,0x00,0x04,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc, ++0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x40,0x86,0xc3,0x00,0x0c,0xaf,0xb3,0x00,0x10,0xaf,0xa0,0x00,0x14, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x55,0x10,0x21, ++0x80,0x47,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0xe7,0x00,0x02,0x00,0x07,0x17,0xc2, ++0x00,0xe2,0x38,0x21,0x00,0x07,0x38,0x43,0x00,0x07,0x38,0x40,0x0c,0x00,0x10,0x97, ++0x03,0xc7,0x38,0x21,0x08,0x00,0x17,0xce,0x02,0x22,0x88,0x21,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x27,0xbd,0xff,0xd0,0x34,0x63,0x00,0x20,0x24,0x42,0x5f,0xbc, ++0xaf,0xb2,0x00,0x20,0xac,0x62,0x00,0x00,0xaf,0xbf,0x00,0x28,0xaf,0xb3,0x00,0x24, ++0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0x3c,0x02,0xb0,0x03,0x90,0x83,0x00,0x0a, ++0x34,0x42,0x01,0x04,0x94,0x45,0x00,0x00,0x00,0x03,0x18,0x80,0x27,0x82,0xbd,0x40, ++0x00,0x62,0x18,0x21,0x30,0xa6,0xff,0xff,0x8c,0x71,0x00,0x00,0x80,0x85,0x00,0x12, ++0x30,0xc9,0x00,0xff,0x00,0x06,0x32,0x02,0xa4,0x86,0x00,0x44,0xa4,0x89,0x00,0x46, ++0x82,0x22,0x00,0x12,0x00,0x80,0x90,0x21,0x10,0xa0,0x00,0x1b,0xa0,0x80,0x00,0x15, ++0x00,0xc5,0x10,0x2a,0x10,0x40,0x00,0x14,0x00,0x00,0x00,0x00,0xa2,0x20,0x00,0x19, ++0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x60,0x00,0x43,0x10,0x21,0xa0,0x40,0x00,0x00, ++0xa0,0x80,0x00,0x12,0x92,0x22,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xdf, ++0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x28,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x30,0x0c,0x00,0x17,0x87,0x00,0x00,0x00,0x00, ++0x08,0x00,0x18,0x1d,0x00,0x00,0x00,0x00,0x28,0x42,0x00,0x02,0x10,0x40,0x01,0x76, ++0x00,0x00,0x28,0x21,0x94,0x87,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0xe0,0x10,0x21, ++0x00,0x02,0x14,0x00,0x00,0x02,0x14,0x03,0x00,0x07,0x24,0x00,0x00,0x04,0x24,0x03, ++0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21,0x00,0x04,0x28,0xc0,0x00,0xa4,0x28,0x21, ++0x27,0x82,0x99,0x60,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x00,0x05,0x28,0x80, ++0x27,0x82,0x99,0x48,0x00,0xa2,0x10,0x21,0x8c,0x68,0x00,0x00,0x80,0x44,0x00,0x06, ++0x27,0x82,0x99,0x50,0x00,0x08,0x1d,0x02,0x00,0xa2,0x28,0x21,0x38,0x84,0x00,0x00, ++0x30,0x63,0x00,0x01,0x01,0x24,0x30,0x0b,0x80,0xaa,0x00,0x04,0x80,0xa9,0x00,0x05, ++0x10,0x60,0x00,0x02,0x00,0x08,0x14,0x02,0x30,0x46,0x00,0x0f,0x15,0x20,0x00,0x28, ++0x01,0x49,0x10,0x21,0x15,0x40,0x00,0x11,0x30,0xe3,0xff,0xff,0x92,0x45,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0xa8,0x00,0xff,0x2d,0x02,0x00,0x04,0x10,0x40,0x01,0x46, ++0x2d,0x02,0x00,0x10,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, ++0x24,0x02,0x00,0x01,0x01,0x02,0x10,0x04,0x00,0x62,0x18,0x25,0xa0,0x83,0x00,0x00, ++0x96,0x47,0x00,0x0c,0x00,0x00,0x00,0x00,0x30,0xe3,0xff,0xff,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x27,0x84,0x99,0x50,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21, ++0x80,0x45,0x00,0x06,0x00,0x03,0x1a,0x00,0x3c,0x04,0xb0,0x00,0x00,0x65,0x18,0x21, ++0x00,0x64,0x20,0x21,0x94,0x82,0x00,0x00,0x82,0x43,0x00,0x10,0x00,0x02,0x14,0x00, ++0x14,0x60,0x00,0x06,0x00,0x02,0x3c,0x03,0x30,0xe2,0x00,0x04,0x14,0x40,0x00,0x04, ++0x01,0x49,0x10,0x21,0x34,0xe2,0x08,0x00,0xa4,0x82,0x00,0x00,0x01,0x49,0x10,0x21, ++0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03,0x00,0x46,0x10,0x2a,0x10,0x40,0x00,0x7c, ++0x00,0x00,0x00,0x00,0x82,0x42,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0e, ++0x00,0x00,0x00,0x00,0x86,0x43,0x00,0x0c,0x25,0x44,0x00,0x01,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x50,0x00,0x43,0x10,0x21, ++0xa0,0x44,0x00,0x04,0x92,0x23,0x00,0x16,0x02,0x40,0x20,0x21,0x30,0x63,0x00,0xfb, ++0x08,0x00,0x18,0x22,0xa2,0x23,0x00,0x16,0x86,0x43,0x00,0x0c,0x25,0x24,0x00,0x01, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x50, ++0x00,0x43,0x10,0x21,0xa0,0x44,0x00,0x05,0x86,0x45,0x00,0x0c,0x0c,0x00,0x26,0x5b, ++0x02,0x20,0x20,0x21,0x10,0x40,0x00,0x5a,0x00,0x00,0x00,0x00,0x92,0x45,0x00,0x08, ++0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04,0x10,0x40,0x00,0x4c, ++0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, ++0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27,0x00,0x62,0x18,0x24, ++0xa0,0x83,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa5,0x00,0xff, ++0x14,0xa0,0x00,0x33,0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04,0x92,0x22,0x00,0x04, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0c,0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17, ++0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00, ++0x96,0x22,0x00,0x06,0x08,0x00,0x18,0x1d,0xa6,0x22,0x00,0x14,0x96,0x22,0x00,0x00, ++0x08,0x00,0x18,0x1d,0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x18,0xac,0xa2,0x20,0x00,0x17, ++0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06,0x27,0x86,0x99,0x40,0x00,0x04,0x18,0xc0, ++0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0,0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80, ++0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08, ++0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00,0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08, ++0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02, ++0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b,0x08,0x00,0x18,0xac,0xa2,0x23,0x00,0x17, ++0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b,0x08,0x00,0x18,0xcf,0x00,0x00,0x00,0x00, ++0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03, ++0x14,0xa2,0xff,0xca,0x00,0x00,0x00,0x00,0x08,0x00,0x18,0xa7,0xa2,0x40,0x00,0x07, ++0x08,0x00,0x18,0xa7,0xa2,0x40,0x00,0x06,0x08,0x00,0x18,0xa7,0xa2,0x40,0x00,0x05, ++0x14,0x40,0xff,0xbe,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00, ++0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80,0x08,0x00,0x18,0x9e,0x00,0xa2,0x10,0x07, ++0x0c,0x00,0x17,0x8d,0x02,0x40,0x20,0x21,0x08,0x00,0x18,0x1d,0x00,0x00,0x00,0x00, ++0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xa6,0x00,0xff,0x2c,0xc2,0x00,0x04, ++0x10,0x40,0x00,0x99,0x2c,0xc2,0x00,0x10,0x3c,0x04,0xb0,0x05,0x34,0x84,0x02,0x29, ++0x90,0x83,0x00,0x00,0x24,0x02,0x00,0x01,0x00,0xc2,0x10,0x04,0x00,0x02,0x10,0x27, ++0x00,0x62,0x18,0x24,0xa0,0x83,0x00,0x00,0x92,0x45,0x00,0x08,0x00,0x00,0x00,0x00, ++0x30,0xa5,0x00,0xff,0x14,0xa0,0x00,0x80,0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04, ++0x86,0x43,0x00,0x0c,0x27,0x93,0x99,0x44,0x96,0x47,0x00,0x0c,0x00,0x03,0x10,0xc0, ++0x00,0x43,0x10,0x21,0x00,0x02,0x28,0x80,0x00,0xb3,0x18,0x21,0x8c,0x64,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x10, ++0x10,0x40,0x00,0x64,0x00,0x00,0x30,0x21,0x00,0x07,0x1c,0x00,0x00,0x03,0x1c,0x03, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x53,0x10,0x21, ++0x8c,0x43,0x00,0x18,0x93,0x82,0x94,0x51,0x8c,0x64,0x00,0x04,0x30,0x42,0x00,0x01, ++0x00,0x04,0x21,0x42,0x14,0x40,0x00,0x4d,0x30,0x90,0x00,0x01,0x00,0x07,0x2c,0x00, ++0x00,0x05,0x2c,0x03,0x0c,0x00,0x22,0xe1,0x02,0x20,0x20,0x21,0x96,0x26,0x00,0x06, ++0x12,0x00,0x00,0x14,0x30,0xc5,0xff,0xff,0x02,0x60,0x90,0x21,0x00,0x05,0x10,0xc0, ++0x00,0x45,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x52,0x18,0x21,0x92,0x22,0x00,0x0a, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0b,0x02,0x20,0x20,0x21,0x8c,0x63,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0x62,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x11,0x42, ++0x0c,0x00,0x22,0xe1,0x30,0x50,0x00,0x01,0x96,0x26,0x00,0x06,0x16,0x00,0xff,0xef, ++0x30,0xc5,0xff,0xff,0x92,0x22,0x00,0x04,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x0d, ++0x24,0x02,0x00,0x01,0xa2,0x22,0x00,0x17,0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0xa6,0x26,0x00,0x14,0x92,0x22,0x00,0x16, ++0x08,0x00,0x18,0x1c,0x30,0x42,0x00,0xc3,0x96,0x22,0x00,0x00,0x08,0x00,0x19,0x43, ++0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x03, ++0x00,0x00,0x00,0x00,0x08,0x00,0x19,0x3e,0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00, ++0x30,0xc5,0xff,0xff,0x00,0x05,0x18,0xc0,0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21, ++0x00,0x65,0x18,0x21,0x27,0x84,0x99,0x40,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x21, ++0x00,0x03,0x18,0x80,0x8c,0x45,0x00,0x08,0x00,0x64,0x18,0x21,0x8c,0x64,0x00,0x08, ++0x3c,0x02,0x80,0x00,0x00,0xa2,0x38,0x24,0x10,0xe0,0x00,0x08,0x00,0x82,0x10,0x24, ++0x10,0x40,0x00,0x04,0x00,0x00,0x18,0x21,0x10,0xe0,0x00,0x02,0x24,0x03,0x00,0x01, ++0x00,0x85,0x18,0x2b,0x08,0x00,0x19,0x3e,0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd, ++0x00,0x85,0x18,0x2b,0x08,0x00,0x19,0x62,0x00,0x00,0x00,0x00,0x24,0x05,0x00,0x24, ++0xf0,0xe5,0x00,0x06,0x00,0x00,0x28,0x12,0x27,0x82,0x99,0x40,0x00,0xa2,0x28,0x21, ++0x0c,0x00,0x01,0x49,0x00,0x00,0x20,0x21,0x96,0x47,0x00,0x0c,0x08,0x00,0x19,0x20, ++0x00,0x07,0x2c,0x00,0x27,0x83,0x99,0x50,0x27,0x82,0x99,0x58,0x00,0xa2,0x10,0x21, ++0x00,0xa3,0x18,0x21,0x90,0x44,0x00,0x00,0x90,0x65,0x00,0x05,0x93,0x82,0x80,0x10, ++0x24,0x07,0x00,0x01,0x0c,0x00,0x29,0x0b,0xaf,0xa2,0x00,0x10,0x96,0x47,0x00,0x0c, ++0x08,0x00,0x19,0x13,0x00,0x07,0x1c,0x00,0x10,0xa2,0x00,0x09,0x24,0x02,0x00,0x02, ++0x10,0xa2,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x7d,0x00,0x00,0x00,0x00, ++0x08,0x00,0x19,0x04,0xa2,0x40,0x00,0x07,0x08,0x00,0x19,0x04,0xa2,0x40,0x00,0x06, ++0x08,0x00,0x19,0x04,0xa2,0x40,0x00,0x05,0x14,0x40,0xff,0x71,0x3c,0x04,0xb0,0x05, ++0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80, ++0x08,0x00,0x18,0xfb,0x00,0xa2,0x10,0x07,0x14,0x40,0xfe,0xc3,0x3c,0x04,0xb0,0x05, ++0x34,0x84,0x02,0x29,0x90,0x83,0x00,0x00,0x30,0xa5,0x00,0x0f,0x24,0x02,0x00,0x80, ++0x08,0x00,0x18,0x56,0x00,0xa2,0x10,0x07,0x84,0x83,0x00,0x0c,0x00,0x00,0x00,0x00, ++0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x44, ++0x00,0x43,0x10,0x21,0x8c,0x47,0x00,0x18,0x00,0x00,0x00,0x00,0x8c,0xe6,0x00,0x08, ++0x0c,0x00,0x16,0x9f,0x00,0x00,0x00,0x00,0x02,0x40,0x20,0x21,0x00,0x00,0x28,0x21, ++0x00,0x00,0x30,0x21,0x00,0x00,0x38,0x21,0x0c,0x00,0x23,0xe3,0xaf,0xa2,0x00,0x10, ++0x00,0x02,0x1e,0x00,0x14,0x60,0xfe,0x6b,0xa2,0x22,0x00,0x12,0x92,0x43,0x00,0x08, ++0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x40,0x24,0x02,0x00,0x01,0xa2,0x40,0x00,0x04, ++0x92,0x28,0x00,0x04,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x19,0x24,0x02,0x00,0x01, ++0x92,0x27,0x00,0x0a,0xa2,0x22,0x00,0x17,0x92,0x22,0x00,0x17,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x10,0x00,0x00,0x00,0x00,0x96,0x22,0x00,0x06,0x00,0x00,0x00,0x00, ++0xa6,0x22,0x00,0x14,0x92,0x22,0x00,0x16,0x30,0xe3,0x00,0xff,0x30,0x42,0x00,0xc0, ++0x10,0x60,0x00,0x03,0xa2,0x22,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x22,0x00,0x16, ++0x11,0x00,0xfe,0x50,0x00,0x00,0x00,0x00,0x92,0x22,0x00,0x16,0x08,0x00,0x18,0x1c, ++0x34,0x42,0x00,0x02,0x96,0x22,0x00,0x00,0x08,0x00,0x19,0xc5,0xa6,0x22,0x00,0x14, ++0x92,0x27,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0xe0,0x00,0x03,0x00,0x00,0x00,0x00, ++0x08,0x00,0x19,0xbe,0xa2,0x20,0x00,0x17,0x96,0x24,0x00,0x00,0x96,0x25,0x00,0x06, ++0x27,0x86,0x99,0x40,0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x05,0x10,0xc0, ++0x00,0x45,0x10,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x02,0x10,0x80, ++0x00,0x46,0x10,0x21,0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x3c,0x03,0x80,0x00, ++0x00,0xa3,0x30,0x24,0x10,0xc0,0x00,0x08,0x00,0x83,0x10,0x24,0x10,0x40,0x00,0x04, ++0x00,0x00,0x18,0x21,0x10,0xc0,0x00,0x02,0x24,0x03,0x00,0x01,0x00,0x85,0x18,0x2b, ++0x08,0x00,0x19,0xbe,0xa2,0x23,0x00,0x17,0x10,0x40,0xff,0xfd,0x00,0x85,0x18,0x2b, ++0x08,0x00,0x19,0xed,0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x02, ++0x10,0x62,0x00,0x05,0x24,0x02,0x00,0x03,0x14,0x62,0xff,0xbd,0x00,0x00,0x00,0x00, ++0x08,0x00,0x19,0xb8,0xa2,0x40,0x00,0x07,0x08,0x00,0x19,0xb8,0xa2,0x40,0x00,0x06, ++0x08,0x00,0x19,0xb8,0xa2,0x40,0x00,0x05,0x3c,0x02,0x80,0x00,0x00,0x82,0x30,0x24, ++0x10,0xc0,0x00,0x08,0x00,0xa2,0x18,0x24,0x10,0x60,0x00,0x04,0x00,0x00,0x10,0x21, ++0x10,0xc0,0x00,0x02,0x24,0x02,0x00,0x01,0x00,0xa4,0x10,0x2b,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x10,0x60,0xff,0xfd,0x00,0xa4,0x10,0x2b,0x08,0x00,0x1a,0x08, ++0x00,0x00,0x00,0x00,0x30,0x82,0xff,0xff,0x00,0x02,0x18,0xc0,0x00,0x62,0x18,0x21, ++0x27,0x84,0x99,0x50,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x80,0x66,0x00,0x06, ++0x00,0x02,0x12,0x00,0x3c,0x03,0xb0,0x00,0x00,0x46,0x10,0x21,0x00,0x45,0x10,0x21, ++0x03,0xe0,0x00,0x08,0x00,0x43,0x10,0x21,0x27,0xbd,0xff,0xe0,0x30,0x82,0x00,0x7c, ++0x30,0x84,0xff,0x00,0xaf,0xbf,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, ++0xaf,0xb0,0x00,0x10,0x14,0x40,0x00,0x41,0x00,0x04,0x22,0x03,0x24,0x02,0x00,0x04, ++0x3c,0x10,0xb0,0x03,0x8e,0x10,0x00,0x00,0x10,0x82,0x00,0x32,0x24,0x02,0x00,0x08, ++0x10,0x82,0x00,0x03,0x32,0x02,0x00,0x20,0x08,0x00,0x1a,0x2e,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x17,0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x24,0x8c,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x67,0x00,0xff,0x10,0xe0,0x00,0x23,0x00,0x00,0x88,0x21, ++0x8f,0x85,0x99,0x20,0x00,0x40,0x30,0x21,0x94,0xa2,0x00,0x08,0x8c,0xc3,0x00,0x00, ++0x26,0x31,0x00,0x01,0x24,0x42,0x00,0x02,0x30,0x42,0x01,0xff,0x34,0x63,0x01,0x00, ++0x02,0x27,0x20,0x2a,0xa4,0xa2,0x00,0x08,0x14,0x80,0xff,0xf7,0xac,0xc3,0x00,0x00, ++0x84,0xa3,0x00,0x08,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x30,0xac,0x43,0x00,0x00, ++0x27,0x92,0xbd,0x40,0x24,0x11,0x00,0x12,0x8e,0x44,0x00,0x00,0x26,0x31,0xff,0xff, ++0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03,0x26,0x52,0x00,0x04, ++0x0c,0x00,0x20,0x48,0x00,0x00,0x00,0x00,0x06,0x21,0xff,0xf7,0x24,0x02,0xff,0xdf, ++0x02,0x02,0x80,0x24,0x3c,0x01,0xb0,0x03,0x0c,0x00,0x1a,0xe6,0xac,0x30,0x00,0x00, ++0x08,0x00,0x1a,0x2e,0x00,0x00,0x00,0x00,0x8f,0x85,0x99,0x20,0x08,0x00,0x1a,0x44, ++0x00,0x00,0x00,0x00,0x24,0x02,0xff,0x95,0x3c,0x03,0xb0,0x03,0x02,0x02,0x80,0x24, ++0x34,0x63,0x00,0x30,0x3c,0x01,0xb0,0x03,0xac,0x30,0x00,0x00,0x0c,0x00,0x1a,0xaf, ++0xac,0x60,0x00,0x00,0x08,0x00,0x1a,0x2e,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x00,0x50,0x08,0x00,0x1a,0x2e,0xac,0x46,0x00,0x00,0xaf,0xa7,0x00,0x0c, ++0xaf,0xa4,0x00,0x00,0xaf,0xa5,0x00,0x04,0xaf,0xa6,0x00,0x08,0x27,0xbd,0xfe,0xe8, ++0x00,0x80,0x28,0x21,0x27,0xa6,0x01,0x1c,0x27,0xa4,0x00,0x10,0xaf,0xbf,0x01,0x14, ++0x0c,0x00,0x2e,0x2c,0xaf,0xb0,0x01,0x10,0x00,0x40,0x80,0x21,0x0c,0x00,0x1a,0x7e, ++0x27,0xa4,0x00,0x10,0x02,0x00,0x10,0x21,0x8f,0xbf,0x01,0x14,0x8f,0xb0,0x01,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x01,0x18,0x93,0x83,0x87,0x6c,0x27,0xbd,0xff,0xe8, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0x14,0x60,0x00,0x14,0x00,0x80,0x80,0x21, ++0x80,0x82,0x00,0x00,0x90,0x84,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x00,0x04,0x26,0x00,0x00,0x04,0x26,0x03,0x30,0x84,0xff,0xff,0x0c,0x00,0x1a,0x9e, ++0x26,0x10,0x00,0x01,0x92,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xf8, ++0x00,0x60,0x20,0x21,0x08,0x00,0x1a,0x88,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x14,0x43,0xff,0xef,0x00,0x00,0x00,0x00,0x0c,0x00,0x05,0x52,0x00,0x00,0x00,0x00, ++0x08,0x00,0x1a,0x88,0x00,0x00,0x00,0x00,0x30,0x84,0xff,0xff,0x48,0x84,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10, ++0x0c,0x00,0x2d,0x94,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x10,0x00,0x02,0x14,0x00, ++0x00,0x02,0x14,0x03,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x03,0xe0,0x00,0x08, ++0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x3c,0x0a,0x80,0x00, ++0x25,0x4a,0x6a,0xbc,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x08,0x80,0x01, ++0x25,0x08,0x00,0x00,0x3c,0x09,0x80,0x01,0x25,0x29,0x0b,0x90,0x11,0x09,0x00,0x10, ++0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x6a,0xe4,0x3c,0x0b,0xb0,0x03, ++0xad,0x6a,0x00,0x20,0x3c,0x08,0xb0,0x06,0x35,0x08,0x80,0x10,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x8d,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x29,0x00,0x01, ++0x00,0x00,0x00,0x00,0x24,0x01,0x00,0x01,0x15,0x21,0xff,0xf2,0x00,0x00,0x00,0x00, ++0x3c,0x0a,0x80,0x00,0x25,0x4a,0x6b,0x20,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20, ++0x3c,0x02,0xb0,0x03,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x63,0x00,0x40, ++0x00,0x00,0x00,0x00,0xac,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00, ++0x25,0x4a,0x6b,0x4c,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x02,0x80,0x01, ++0x24,0x42,0x00,0x00,0x3c,0x03,0x80,0x01,0x24,0x63,0x0b,0x90,0x3c,0x04,0xb0,0x00, ++0x8c,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x45,0x00,0x00,0x24,0x42,0x00,0x04, ++0x24,0x84,0x00,0x04,0x00,0x43,0x08,0x2a,0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x1a,0xe6,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x6b,0x98, ++0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x02,0x80,0x01,0x24,0x42,0x0b,0x90, ++0x3c,0x03,0x80,0x01,0x24,0x63,0x48,0x64,0xac,0x40,0x00,0x00,0xac,0x40,0x00,0x04, ++0xac,0x40,0x00,0x08,0xac,0x40,0x00,0x0c,0x24,0x42,0x00,0x10,0x00,0x43,0x08,0x2a, ++0x14,0x20,0xff,0xf9,0x00,0x00,0x00,0x00,0x3c,0x0a,0x80,0x00,0x25,0x4a,0x6b,0xd8, ++0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x3c,0x1c,0x80,0x01,0x27,0x9c,0x7f,0xf0, ++0x27,0x9d,0x95,0x20,0x00,0x00,0x00,0x00,0x27,0x9d,0x99,0x08,0x3c,0x0a,0x80,0x00, ++0x25,0x4a,0x6b,0xfc,0x3c,0x0b,0xb0,0x03,0xad,0x6a,0x00,0x20,0x40,0x80,0x68,0x00, ++0x40,0x08,0x60,0x00,0x00,0x00,0x00,0x00,0x35,0x08,0xff,0x01,0x40,0x88,0x60,0x00, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x1d,0x15,0x00,0x00,0x00,0x00,0x24,0x84,0xf8,0x00, ++0x30,0x87,0x00,0x03,0x00,0x04,0x30,0x40,0x00,0xc7,0x20,0x23,0x3c,0x02,0xb0,0x0a, ++0x27,0xbd,0xff,0xe0,0x24,0x03,0xff,0xff,0x00,0x82,0x20,0x21,0xaf,0xb1,0x00,0x14, ++0xac,0x83,0x10,0x00,0xaf,0xbf,0x00,0x18,0xaf,0xb0,0x00,0x10,0x00,0xa0,0x88,0x21, ++0x24,0x03,0x00,0x01,0x8c,0x82,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x00,0xc7,0x10,0x23,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x10,0x21,0x8c,0x50,0x00,0x00, ++0x0c,0x00,0x1b,0x63,0x02,0x20,0x20,0x21,0x02,0x11,0x80,0x24,0x00,0x50,0x80,0x06, ++0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x20,0x27,0xbd,0xff,0xd8,0xaf,0xb2,0x00,0x18,0x00,0xa0,0x90,0x21, ++0x24,0x05,0xff,0xff,0xaf,0xb3,0x00,0x1c,0xaf,0xbf,0x00,0x20,0xaf,0xb1,0x00,0x14, ++0xaf,0xb0,0x00,0x10,0x00,0xc0,0x98,0x21,0x12,0x45,0x00,0x23,0x24,0x84,0xf8,0x00, ++0x30,0x83,0x00,0x03,0x00,0x04,0x10,0x40,0x00,0x40,0x88,0x21,0x00,0x60,0x20,0x21, ++0x00,0x43,0x10,0x23,0x3c,0x03,0xb0,0x0a,0x00,0x43,0x10,0x21,0xac,0x45,0x10,0x00, ++0x00,0x40,0x18,0x21,0x24,0x05,0x00,0x01,0x8c,0x62,0x10,0x00,0x00,0x00,0x00,0x00, ++0x14,0x45,0xff,0xfd,0x3c,0x02,0xb0,0x0a,0x02,0x24,0x88,0x23,0x02,0x22,0x88,0x21, ++0x8e,0x30,0x00,0x00,0x0c,0x00,0x1b,0x63,0x02,0x40,0x20,0x21,0x00,0x12,0x18,0x27, ++0x02,0x03,0x80,0x24,0x00,0x53,0x10,0x04,0x02,0x02,0x80,0x25,0xae,0x30,0x00,0x00, ++0x24,0x03,0x00,0x01,0x8e,0x22,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x43,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x30,0x82,0x00,0x03,0x00,0x04,0x18,0x40, ++0x00,0x62,0x18,0x23,0x3c,0x04,0xb0,0x0a,0x00,0x64,0x18,0x21,0xac,0x66,0x00,0x00, ++0x24,0x04,0x00,0x01,0x8c,0x62,0x10,0x00,0x00,0x00,0x00,0x00,0x14,0x44,0xff,0xfd, ++0x00,0x00,0x00,0x00,0x08,0x00,0x1b,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x21, ++0x00,0x64,0x10,0x06,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00, ++0x24,0x63,0x00,0x01,0x2c,0x62,0x00,0x20,0x14,0x40,0xff,0xf9,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21,0x27,0xbd,0xff,0xe0,0x3c,0x03,0xb0,0x05, ++0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x1c, ++0x00,0x80,0x90,0x21,0x00,0xa0,0x80,0x21,0x00,0xc0,0x88,0x21,0x34,0x63,0x02,0x2e, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0xfc, ++0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0xc0,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x03, ++0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x03, ++0x3c,0x02,0xc0,0x00,0x00,0x10,0x1c,0x00,0x34,0x42,0x04,0x00,0x3c,0x04,0xb0,0x05, ++0x3c,0x05,0xb0,0x05,0x24,0x63,0x16,0x09,0x02,0x22,0x10,0x21,0x34,0x84,0x04,0x20, ++0x34,0xa5,0x04,0x24,0x3c,0x06,0xb0,0x05,0xac,0x83,0x00,0x00,0x24,0x07,0x00,0x01, ++0xac,0xa2,0x00,0x00,0x34,0xc6,0x02,0x28,0x24,0x02,0x00,0x20,0xae,0x47,0x00,0x3c, ++0x24,0x04,0x08,0x24,0xa0,0xc2,0x00,0x00,0x3c,0x05,0x00,0xc0,0xa2,0x47,0x00,0x11, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x01,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0xc0, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x01,0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x02,0x00,0x06, ++0xac,0x82,0x00,0x0c,0xa0,0x80,0x00,0x50,0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04, ++0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x14,0xac,0x80,0x00,0x18,0xac,0x80,0x00,0x1c, ++0xa4,0x80,0x00,0x20,0xac,0x80,0x00,0x24,0xac,0x80,0x00,0x28,0xac,0x80,0x00,0x2c, ++0xa0,0x80,0x00,0x30,0xa0,0x80,0x00,0x31,0xac,0x80,0x00,0x34,0xac,0x80,0x00,0x38, ++0xa0,0x80,0x00,0x3c,0xac,0x82,0x00,0x10,0xa0,0x80,0x00,0x44,0xac,0x80,0x00,0x48, ++0x03,0xe0,0x00,0x08,0xac,0x80,0x00,0x4c,0x3c,0x04,0xb0,0x06,0x34,0x84,0x80,0x00, ++0x8c,0x83,0x00,0x00,0x3c,0x02,0x12,0x00,0x3c,0x05,0xb0,0x03,0x00,0x62,0x18,0x25, ++0x34,0xa5,0x00,0x8b,0x24,0x02,0xff,0x80,0xac,0x83,0x00,0x00,0x03,0xe0,0x00,0x08, ++0xa0,0xa2,0x00,0x00,0x3c,0x04,0xb0,0x03,0x34,0x84,0x00,0x0b,0x24,0x02,0x00,0x22, ++0x3c,0x05,0xb0,0x01,0x3c,0x06,0x45,0x67,0x3c,0x0a,0xb0,0x09,0xa0,0x82,0x00,0x00, ++0x34,0xa5,0x00,0x04,0x34,0xc6,0x89,0xaa,0x35,0x4a,0x00,0x04,0x24,0x02,0x01,0x23, ++0x3c,0x0b,0xb0,0x09,0x3c,0x07,0x01,0x23,0x3c,0x0c,0xb0,0x09,0x3c,0x01,0xb0,0x01, ++0xac,0x20,0x00,0x00,0x27,0xbd,0xff,0xe0,0xac,0xa0,0x00,0x00,0x35,0x6b,0x00,0x08, ++0x3c,0x01,0xb0,0x09,0xac,0x26,0x00,0x00,0x34,0xe7,0x45,0x66,0xa5,0x42,0x00,0x00, ++0x35,0x8c,0x00,0x0c,0x24,0x02,0xcd,0xef,0x3c,0x0d,0xb0,0x09,0x3c,0x08,0xcd,0xef, ++0x3c,0x0e,0xb0,0x09,0xad,0x67,0x00,0x00,0xaf,0xb7,0x00,0x1c,0xa5,0x82,0x00,0x00, ++0xaf,0xb6,0x00,0x18,0xaf,0xb5,0x00,0x14,0xaf,0xb4,0x00,0x10,0xaf,0xb3,0x00,0x0c, ++0xaf,0xb2,0x00,0x08,0xaf,0xb1,0x00,0x04,0xaf,0xb0,0x00,0x00,0x35,0xad,0x00,0x10, ++0x35,0x08,0x01,0x22,0x35,0xce,0x00,0x14,0x24,0x02,0x89,0xab,0x3c,0x0f,0xb0,0x09, ++0x3c,0x09,0x89,0xab,0x3c,0x10,0xb0,0x09,0x3c,0x11,0xb0,0x09,0x3c,0x12,0xb0,0x09, ++0x3c,0x13,0xb0,0x09,0x3c,0x14,0xb0,0x09,0x3c,0x15,0xb0,0x09,0x3c,0x16,0xb0,0x09, ++0x3c,0x17,0xb0,0x09,0xad,0xa8,0x00,0x00,0x24,0x03,0xff,0xff,0xa5,0xc2,0x00,0x00, ++0x35,0xef,0x00,0x18,0x35,0x29,0xcd,0xee,0x36,0x10,0x00,0x1c,0x36,0x31,0x00,0x20, ++0x36,0x52,0x00,0x24,0x36,0x73,0x00,0x28,0x36,0x94,0x00,0x2c,0x36,0xb5,0x00,0x30, ++0x36,0xd6,0x00,0x34,0x36,0xf7,0x00,0x38,0x24,0x02,0x45,0x67,0xad,0xe9,0x00,0x00, ++0xa6,0x02,0x00,0x00,0xae,0x23,0x00,0x00,0x8f,0xb0,0x00,0x00,0xa6,0x43,0x00,0x00, ++0x8f,0xb1,0x00,0x04,0xae,0x63,0x00,0x00,0x8f,0xb2,0x00,0x08,0xa6,0x83,0x00,0x00, ++0x8f,0xb3,0x00,0x0c,0xae,0xa3,0x00,0x00,0x8f,0xb4,0x00,0x10,0xa6,0xc3,0x00,0x00, ++0x8f,0xb5,0x00,0x14,0xae,0xe3,0x00,0x00,0x7b,0xb6,0x00,0xfc,0x3c,0x18,0xb0,0x09, ++0x37,0x18,0x00,0x3c,0xa7,0x03,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x00,0x34,0x63,0x00,0x20,0x24,0x42,0x70,0x70, ++0xac,0x62,0x00,0x00,0x8c,0x83,0x00,0x34,0x34,0x02,0xff,0xff,0x00,0x43,0x10,0x2a, ++0x14,0x40,0x00,0xed,0x00,0x80,0x28,0x21,0x8c,0x84,0x00,0x08,0x24,0x02,0x00,0x03, ++0x10,0x82,0x00,0xe0,0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x2c,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x47,0x24,0x02,0x00,0x06,0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x14,0x40,0x00,0xc6, ++0xac,0xa2,0x00,0x2c,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0xc5,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x02,0x10,0x82,0x00,0xb3,0x00,0x00,0x00,0x00,0x8c,0xa6,0x00,0x04, ++0x24,0x02,0x00,0x02,0x10,0xc2,0x00,0xa9,0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x14, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x09,0x24,0x02,0x00,0x01,0x3c,0x03,0xb0,0x09, ++0x34,0x63,0x01,0x60,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, ++0x10,0x40,0x00,0x05,0xac,0xa2,0x00,0x14,0x24,0x02,0x00,0x01,0xac,0xa2,0x00,0x00, ++0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x14,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0, ++0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x61,0x00,0x16,0x3c,0x03,0xb0,0x05, ++0x34,0x63,0x02,0x2e,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x10,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x42,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x0b,0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x50, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x07,0x00,0x00,0x00,0x00,0x14,0x80,0x00,0x05, ++0x24,0x02,0x00,0x0e,0x24,0x03,0x00,0x01,0xac,0xa2,0x00,0x00,0x03,0xe0,0x00,0x08, ++0xa0,0xa3,0x00,0x50,0x80,0xa2,0x00,0x31,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a, ++0x3c,0x02,0xb0,0x06,0x34,0x42,0x80,0x18,0x8c,0x43,0x00,0x00,0x3c,0x04,0xf0,0x00, ++0x3c,0x02,0x80,0x00,0x00,0x64,0x18,0x24,0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x09, ++0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x00,0x8c,0xa2,0x00,0x40,0x00,0x00,0x00,0x00, ++0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x09,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2c,0x8c,0x43,0x00,0x00,0x3c,0x04,0x00,0x02, ++0x00,0x64,0x18,0x24,0x14,0x60,0xff,0xf2,0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03, ++0x34,0x63,0x02,0x01,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x80, ++0x10,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x8c,0xa3,0x00,0x0c,0x00,0x00,0x00,0x00, ++0xac,0xa3,0x00,0x10,0x3c,0x02,0xb0,0x03,0x90,0x42,0x02,0x01,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x0f,0xac,0xa2,0x00,0x0c,0x90,0xa3,0x00,0x0f,0x24,0x02,0x00,0x0d, ++0x3c,0x01,0xb0,0x03,0x08,0x00,0x1c,0x74,0xa0,0x23,0x02,0x01,0x3c,0x02,0xb0,0x09, ++0x34,0x42,0x01,0x80,0x90,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x1e,0x00, ++0x00,0x03,0x1e,0x03,0x10,0x60,0x00,0x15,0xa0,0xa4,0x00,0x44,0x24,0x02,0x00,0x01, ++0x10,0x62,0x00,0x0b,0x24,0x02,0x00,0x02,0x10,0x62,0x00,0x03,0x24,0x03,0x00,0x0d, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8c,0xa2,0x00,0x0c,0xac,0xa3,0x00,0x00, ++0x24,0x03,0x00,0x04,0xac,0xa2,0x00,0x10,0x03,0xe0,0x00,0x08,0xac,0xa3,0x00,0x0c, ++0x24,0x02,0x00,0x0d,0xac,0xa2,0x00,0x00,0x24,0x03,0x00,0x04,0x24,0x02,0x00,0x06, ++0xac,0xa3,0x00,0x10,0x03,0xe0,0x00,0x08,0xac,0xa2,0x00,0x0c,0x8c,0xa3,0x00,0x38, ++0x24,0x04,0x00,0x01,0x10,0x64,0x00,0x2d,0x24,0x02,0x00,0x02,0x10,0x60,0x00,0x19, ++0x00,0x00,0x00,0x00,0x10,0x62,0x00,0x10,0x24,0x02,0x00,0x04,0x10,0x62,0x00,0x04, ++0x00,0x00,0x00,0x00,0xac,0xa0,0x00,0x38,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x00, ++0x10,0xc4,0x00,0x07,0x24,0x02,0x00,0x03,0x80,0xa2,0x00,0x30,0x00,0x00,0x00,0x00, ++0x00,0x02,0x18,0x0b,0xac,0xa3,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0xa0,0x00,0x38, ++0x08,0x00,0x1c,0xc6,0xac,0xa2,0x00,0x00,0x10,0xc4,0x00,0x02,0x24,0x02,0x00,0x03, ++0x24,0x02,0x00,0x0c,0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x04,0x03,0xe0,0x00,0x08, ++0xac,0xa2,0x00,0x38,0x10,0xc4,0x00,0x0e,0x3c,0x03,0xb0,0x06,0x34,0x63,0x80,0x24, ++0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x10,0x40,0x00,0x06, ++0xac,0xa2,0x00,0x18,0x24,0x02,0x00,0x02,0xac,0xa2,0x00,0x00,0xac,0xa0,0x00,0x18, ++0x08,0x00,0x1c,0xcf,0x24,0x02,0x00,0x01,0x08,0x00,0x1c,0xdc,0xac,0xa0,0x00,0x00, ++0x24,0x02,0x00,0x03,0x08,0x00,0x1c,0xdc,0xac,0xa2,0x00,0x00,0x24,0x03,0x00,0x0b, ++0xac,0xa2,0x00,0x38,0x03,0xe0,0x00,0x08,0xac,0xa3,0x00,0x00,0x80,0xa2,0x00,0x30, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x55,0x24,0x02,0x00,0x04,0x08,0x00,0x1c,0x74, ++0x00,0x00,0x00,0x00,0x84,0xa2,0x00,0x20,0x00,0x00,0x00,0x00,0x10,0x40,0xff,0x84, ++0x24,0x02,0x00,0x06,0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, ++0x14,0x40,0xff,0x42,0xa4,0xa3,0x00,0x20,0x08,0x00,0x1c,0x74,0x24,0x02,0x00,0x06, ++0x8c,0xa2,0x00,0x1c,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0x75,0x24,0x02,0x00,0x05, ++0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0x10,0x40,0xff,0x32,0xac,0xa2,0x00,0x1c,0x08,0x00,0x1c,0x74, ++0x24,0x02,0x00,0x05,0x3c,0x02,0xb0,0x05,0x8c,0x42,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x02,0x17,0x42,0x30,0x42,0x00,0x01,0x14,0x40,0xff,0x65,0x24,0x02,0x00,0x06, ++0x08,0x00,0x1c,0x2a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x0a,0x03,0xe0,0x00,0x08, ++0xac,0x82,0x00,0x00,0x27,0xbd,0xff,0xc8,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0x27,0x91,0x91,0xf8,0x27,0x90,0x8f,0x38,0xaf,0xbf,0x00,0x30,0xaf,0xb7,0x00,0x2c, ++0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24,0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c, ++0x0c,0x00,0x2d,0x21,0xaf,0xb2,0x00,0x18,0x0c,0x00,0x07,0x90,0x00,0x00,0x00,0x00, ++0xaf,0x91,0x95,0x10,0xaf,0x90,0x99,0x20,0x48,0x02,0x00,0x00,0x0c,0x00,0x1b,0xba, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x1f,0x97,0x02,0x00,0x20,0x21,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x00,0x3a,0x94,0x43,0x00,0x00,0x3a,0x54,0xff,0xff,0xa3,0x83,0x99,0x24, ++0x0c,0x00,0x00,0x34,0x02,0x80,0xa8,0x21,0x0c,0x00,0x1b,0xc5,0x02,0x80,0xb0,0x21, ++0x27,0x84,0x8d,0x78,0x0c,0x00,0x32,0x44,0x02,0x80,0xb8,0x21,0x93,0x84,0x80,0x10, ++0x0c,0x00,0x28,0xb0,0x00,0x00,0x00,0x00,0x0c,0x00,0x0e,0x84,0x02,0x20,0x20,0x21, ++0x0c,0x00,0x01,0x39,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x20,0x0c,0x00,0x1b,0xa3, ++0x00,0x00,0x00,0x00,0x27,0x82,0x92,0x2c,0xaf,0x82,0x8d,0x60,0x0c,0x00,0x00,0x5f, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x08,0x3c,0x04,0xb0,0x09, ++0x3c,0x05,0xb0,0x09,0x8c,0x66,0x00,0x00,0x34,0x84,0x01,0x68,0x24,0x02,0xc8,0x80, ++0x34,0xa5,0x01,0x40,0x24,0x03,0x00,0x0a,0xa4,0x82,0x00,0x00,0xa4,0xa3,0x00,0x00, ++0x3c,0x04,0xb0,0x03,0x8c,0x82,0x00,0x00,0xaf,0x86,0x8d,0x18,0x34,0x42,0x00,0x20, ++0xac,0x82,0x00,0x00,0x0c,0x00,0x07,0xa1,0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x05, ++0x0c,0x00,0x2d,0x39,0x34,0x84,0x00,0x04,0x8f,0x83,0x8d,0x20,0x00,0x00,0x00,0x00, ++0x2c,0x62,0x00,0x11,0x10,0x40,0xff,0xf7,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01, ++0x24,0x63,0x08,0xac,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x78,0x0c,0x00,0x31,0x79, ++0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x20,0x0c,0x00,0x1c,0x1c,0x00,0x00,0x00,0x00, ++0x93,0x83,0x88,0x6d,0x24,0x02,0x00,0x01,0x10,0x62,0x00,0x07,0x00,0x00,0x00,0x00, ++0x8f,0x82,0x8d,0x54,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x01,0xaf,0x82,0x8d,0x54, ++0x08,0x00,0x1d,0x55,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x78,0x0c,0x00,0x31,0xf8, ++0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x78, ++0x0c,0x00,0x33,0xda,0x00,0x00,0x00,0x00,0xa3,0x82,0x8d,0x51,0xaf,0x80,0x8d,0x20, ++0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00,0x27,0x84,0x8f,0x38,0x0c,0x00,0x20,0xd3, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0x14,0x40,0x00,0x05,0x3c,0x03,0xb0,0x05, ++0xaf,0x80,0x8d,0x20,0xaf,0x80,0x8d,0x24,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00, ++0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, ++0xaf,0x82,0x8d,0x4c,0x14,0x40,0x00,0x1e,0x24,0x02,0x00,0x01,0x8f,0x84,0x8d,0x28, ++0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x1d,0x3c,0x03,0xb0,0x09,0x34,0x63,0x01,0x60, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x8d,0x34, ++0x14,0x40,0x00,0x13,0x24,0x02,0x00,0x01,0x24,0x02,0x00,0x02,0x10,0x82,0x00,0x07, ++0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x01,0x24,0x03,0x00,0x03,0xaf,0x82,0x8d,0x24, ++0xaf,0x83,0x8d,0x20,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00,0x34,0x42,0x02,0x2e, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff, ++0x00,0x60,0x10,0x21,0xa7,0x83,0x8d,0x40,0x14,0x40,0xff,0xf3,0x24,0x02,0x00,0x01, ++0xaf,0x82,0x8d,0x24,0x08,0x00,0x1d,0x7f,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x05, ++0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, ++0xaf,0x82,0x8d,0x3c,0x14,0x40,0xff,0xf6,0x24,0x02,0x00,0x01,0x08,0x00,0x1d,0x97, ++0x3c,0x03,0xb0,0x09,0x27,0x84,0x8f,0x38,0x0c,0x00,0x22,0x4c,0x00,0x00,0x00,0x00, ++0x83,0x82,0x8d,0x50,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xed,0x24,0x02,0x00,0x02, ++0x3c,0x03,0xb0,0x05,0x34,0x63,0x04,0x50,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0xff,0xaf,0x82,0x8d,0x4c,0x14,0x40,0xff,0xe5,0x24,0x02,0x00,0x02, ++0x8f,0x84,0x8d,0x28,0x24,0x02,0x00,0x01,0x10,0x82,0x00,0x12,0x24,0x02,0x00,0x02, ++0x10,0x82,0x00,0x05,0x3c,0x02,0xb0,0x05,0x24,0x02,0x00,0x02,0xaf,0x82,0x8d,0x24, ++0x08,0x00,0x1d,0xa4,0x24,0x03,0x00,0x04,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21, ++0xa7,0x83,0x8d,0x40,0x14,0x40,0xff,0xf4,0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0xb0, ++0x24,0x02,0x00,0x02,0x3c,0x03,0xb0,0x05,0x34,0x63,0x02,0x2c,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff,0xaf,0x82,0x8d,0x3c,0x14,0x40,0xff,0xf7, ++0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0xd0,0x24,0x02,0x00,0x02,0x27,0x84,0x91,0xf8, ++0x0c,0x00,0x12,0xe2,0x00,0x00,0x00,0x00,0x8f,0x83,0x8d,0x24,0xaf,0x82,0x8d,0x3c, ++0x38,0x64,0x00,0x02,0x00,0x04,0x18,0x0a,0xaf,0x83,0x8d,0x24,0x14,0x40,0x00,0x08, ++0x24,0x02,0x00,0x05,0x8f,0x82,0x92,0x38,0xaf,0x80,0x8d,0x20,0x10,0x40,0xff,0x78, ++0x24,0x04,0x00,0x01,0xaf,0x84,0x8d,0x28,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00, ++0xaf,0x82,0x8d,0x20,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00,0x83,0x82,0x8d,0x70, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x20,0xaf,0x82,0x8d,0x3c, ++0x8f,0x85,0x8d,0x3c,0x27,0x84,0x91,0xf8,0x0c,0x00,0x14,0xbd,0x00,0x00,0x00,0x00, ++0x00,0x02,0x1e,0x00,0xa3,0x82,0x8d,0x50,0xaf,0x80,0x8d,0x3c,0x10,0x60,0xff,0x73, ++0x3c,0x02,0xb0,0x05,0x34,0x42,0x02,0x2e,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x63,0x00,0x01,0x30,0x63,0x00,0xff,0x00,0x60,0x10,0x21,0xa7,0x83,0x8d,0x40, ++0x10,0x40,0xff,0xe7,0x24,0x02,0x00,0x06,0x24,0x04,0x00,0x02,0xaf,0x84,0x8d,0x28, ++0x08,0x00,0x1d,0x7f,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x20,0x27,0x85,0x91,0xf8, ++0x0c,0x00,0x15,0x83,0x00,0x00,0x00,0x00,0x8f,0x82,0x8d,0x44,0xaf,0x80,0x8d,0x4c, ++0x14,0x40,0x00,0x18,0x00,0x40,0x18,0x21,0x8f,0x82,0x8d,0x48,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x14,0x24,0x02,0x00,0x02,0x8f,0x83,0x8d,0x28,0x00,0x00,0x00,0x00, ++0x10,0x62,0x00,0x09,0x24,0x02,0x00,0x01,0x8f,0x83,0x8d,0x24,0x00,0x00,0x00,0x00, ++0x10,0x62,0x00,0x02,0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x06,0xaf,0x82,0x8d,0x20, ++0x08,0x00,0x1d,0xf9,0x24,0x04,0x00,0x03,0x3c,0x02,0x40,0x00,0x34,0x42,0x00,0x14, ++0x3c,0x01,0xb0,0x05,0xac,0x22,0x00,0x00,0xaf,0x80,0x8d,0x20,0x08,0x00,0x1d,0xf9, ++0x24,0x04,0x00,0x03,0x10,0x60,0x00,0x10,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x20, ++0x27,0x85,0x91,0xf8,0x0c,0x00,0x15,0xa7,0x00,0x00,0x00,0x00,0x8f,0x83,0x8d,0x24, ++0x24,0x02,0x00,0x01,0xa3,0x80,0x8d,0x50,0xaf,0x80,0x8d,0x28,0x10,0x62,0x00,0x02, ++0x24,0x02,0x00,0x03,0x24,0x02,0x00,0x04,0xaf,0x82,0x8d,0x20,0xaf,0x80,0x8d,0x44, ++0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00,0x83,0x82,0x8d,0x70,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x27,0x84,0x91,0xf8,0x0c,0x00,0x17,0xef, ++0x00,0x00,0x00,0x00,0x8f,0x82,0x8d,0x24,0xa3,0x80,0x8d,0x50,0xaf,0x80,0x8d,0x20, ++0xaf,0x80,0x8d,0x28,0x14,0x40,0x00,0x02,0x24,0x02,0x00,0x02,0xaf,0x82,0x8d,0x24, ++0xaf,0x80,0x8d,0x48,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x20, ++0x27,0x85,0x91,0xf8,0x0c,0x00,0x15,0xa7,0x00,0x00,0x00,0x00,0x8f,0x82,0x8d,0x24, ++0xa3,0x80,0x8d,0x50,0xaf,0x80,0x8d,0x20,0xaf,0x80,0x8d,0x28,0x14,0x40,0xff,0x0c, ++0x24,0x02,0x00,0x02,0xaf,0x82,0x8d,0x24,0x08,0x00,0x1d,0x70,0x00,0x00,0x00,0x00, ++0x27,0x84,0x91,0xf8,0x0c,0x00,0x17,0xef,0x00,0x00,0x00,0x00,0x08,0x00,0x1e,0x5f, ++0x00,0x00,0x00,0x00,0x27,0x84,0x8d,0x78,0x0c,0x00,0x34,0x70,0x00,0x00,0x00,0x00, ++0x08,0x00,0x1d,0x7e,0x00,0x00,0x00,0x00,0x0c,0x00,0x2b,0x15,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x31,0xea,0x00,0x00,0x00,0x00,0x0c,0x00,0x1f,0x89,0x00,0x00,0x00,0x00, ++0x93,0x83,0xc5,0x58,0x00,0x00,0x00,0x00,0x14,0x60,0x00,0x1c,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x83,0xc5,0x50,0x8f,0x82,0xc5,0x54, ++0x00,0x83,0x18,0x23,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x14,0x2e,0xa3,0x00,0x01, ++0x2e,0x82,0x00,0x01,0x00,0x43,0x10,0x25,0x2e,0xc4,0x00,0x01,0x00,0x44,0x10,0x25, ++0x2e,0xe3,0x00,0x01,0x3c,0x05,0xb0,0x03,0x00,0x43,0x10,0x25,0x34,0xa5,0x01,0x18, ++0x8c,0xa3,0x00,0x00,0x14,0x40,0x00,0x02,0x24,0x04,0x00,0x02,0x00,0x00,0x20,0x21, ++0x0c,0x00,0x0b,0x7e,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08, ++0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x83,0xc5,0x50,0x0c,0x00,0x01,0xe9, ++0x00,0x00,0x00,0x00,0xaf,0x80,0x8d,0x20,0xaf,0x80,0x8d,0x54,0x08,0x00,0x1d,0x55, ++0x00,0x00,0x00,0x00,0x27,0x90,0xbd,0x40,0x24,0x11,0x00,0x12,0x8e,0x04,0x00,0x00, ++0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x10,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x20,0x48,0x00,0x00,0x00,0x00,0x26,0x31,0xff,0xff, ++0x06,0x21,0xff,0xf6,0x26,0x10,0x00,0x04,0x08,0x00,0x1d,0x7f,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x01,0x08,0x8c,0x44,0x00,0x00,0x8f,0x82,0x8d,0x18, ++0x00,0x04,0x19,0xc2,0x00,0x02,0x11,0xc2,0x10,0x62,0xfe,0xcc,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x01,0x02,0x90,0x43,0x00,0x00,0x3c,0x12,0xb0,0x05,0xaf,0x84,0x8d,0x18, ++0x30,0x63,0x00,0xff,0x00,0x03,0x11,0x40,0x00,0x43,0x10,0x23,0x00,0x02,0x10,0x80, ++0x00,0x43,0x10,0x21,0x00,0x02,0x99,0x00,0x00,0x00,0x88,0x21,0x36,0x52,0x02,0x2c, ++0x27,0x90,0xbd,0x40,0x8e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x62,0x00,0x03,0x10,0x40,0x00,0x06,0x30,0x62,0x00,0x1c, ++0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x8f,0x85,0x8d,0x18,0x0c,0x00,0x26,0x05, ++0x02,0x60,0x30,0x21,0x8e,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xff, ++0x14,0x40,0xfe,0xae,0x00,0x00,0x00,0x00,0x26,0x31,0x00,0x01,0x2a,0x22,0x00,0x13, ++0x14,0x40,0xff,0xec,0x26,0x10,0x00,0x04,0x08,0x00,0x1d,0x7f,0x00,0x00,0x00,0x00, ++0x8f,0x84,0x8d,0x2c,0x27,0x85,0x91,0xf8,0x0c,0x00,0x1f,0x1c,0x00,0x00,0x00,0x00, ++0x8f,0x83,0x8d,0x2c,0x24,0x02,0x00,0x04,0x14,0x62,0xfe,0xa0,0x24,0x02,0x00,0x05, ++0x08,0x00,0x1d,0xfc,0x00,0x00,0x00,0x00,0x27,0x84,0x91,0xf8,0x0c,0x00,0x2b,0x3c, ++0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0xa4,0x24,0x03,0x00,0x05,0x8f,0x82,0x92,0x2c, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x8f,0x84,0xbd,0x80, ++0xaf,0x80,0x92,0x2c,0x94,0x85,0x00,0x14,0x0c,0x00,0x22,0xe1,0x00,0x00,0x00,0x00, ++0x93,0x82,0x94,0x51,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x10,0x40,0x00,0x03, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x01,0x57,0x00,0x00,0x20,0x21,0x8f,0x84,0xbd,0x80, ++0x0c,0x00,0x20,0x48,0x00,0x00,0x00,0x00,0x08,0x00,0x1d,0x7f,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xff,0x90,0x27,0xbd,0xff,0xe8,0x00,0x80,0x18,0x21,0x34,0x42,0x00,0x01, ++0x27,0x84,0x91,0xf8,0x10,0x62,0x00,0x05,0xaf,0xbf,0x00,0x10,0x8f,0xbf,0x00,0x10, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x0e,0x84, ++0x00,0x00,0x00,0x00,0x27,0x84,0x8f,0x38,0x0c,0x00,0x1f,0x97,0x00,0x00,0x00,0x00, ++0x27,0x84,0x8d,0x20,0x0c,0x00,0x1b,0xa3,0x00,0x00,0x00,0x00,0x08,0x00,0x1f,0x03, ++0x00,0x00,0x00,0x00,0x8f,0x82,0x92,0x38,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05, ++0x00,0x00,0x18,0x21,0x8f,0x82,0x8d,0x28,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x02, ++0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x60,0x10,0x21, ++0x27,0xbd,0xff,0xe0,0x3c,0x06,0xb0,0x03,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0x34,0xc6,0x00,0x5f,0xaf,0xbf,0x00,0x18,0x90,0xc3,0x00,0x00,0x3c,0x07,0xb0,0x03, ++0x34,0xe7,0x00,0x5d,0x34,0x63,0x00,0x01,0x3c,0x09,0xb0,0x03,0x24,0x02,0x00,0x01, ++0xa0,0xc3,0x00,0x00,0x00,0x80,0x80,0x21,0xa0,0xe2,0x00,0x00,0x00,0xa0,0x88,0x21, ++0x35,0x29,0x00,0x5e,0x00,0xe0,0x40,0x21,0x24,0x04,0x00,0x01,0x91,0x22,0x00,0x00, ++0x91,0x03,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x83,0x00,0x03,0x30,0x42,0x00,0x01, ++0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x04,0x12,0x02,0x00,0x2c, ++0x24,0x05,0x0f,0x00,0x24,0x02,0x00,0x06,0x12,0x02,0x00,0x08,0x24,0x05,0x00,0x0f, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x02,0x00,0xa0,0x50,0x00,0x00,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x24,0x04,0x0c,0x04, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x0f,0x24,0x04,0x0d,0x04,0x24,0x05,0x00,0x0f, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x80,0x24,0x05,0x1e,0x00, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x8c,0x24,0x05,0x0f,0x00, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x0f,0x24,0x04,0x08,0x24,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x2c,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x34,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x02,0x24,0x04,0x08,0x3c,0x3c,0x05,0x00,0x30, ++0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x02,0x08,0x00,0x1f,0x3d,0x3c,0x02,0xb0,0x03, ++0x24,0x04,0x08,0x8c,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x80, ++0x24,0x05,0x1e,0x00,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x04,0x24,0x04,0x0c,0x04, ++0x24,0x05,0x00,0x0f,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x04,0x24,0x04,0x0d,0x04, ++0x24,0x05,0x00,0x0f,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x04,0x24,0x04,0x08,0x24, ++0x3c,0x05,0x00,0x30,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x2c, ++0x3c,0x05,0x00,0x30,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x03,0x24,0x04,0x08,0x34, ++0x3c,0x05,0x00,0x30,0x0c,0x00,0x1b,0x29,0x24,0x06,0x00,0x02,0x3c,0x05,0x00,0x30, ++0x24,0x06,0x00,0x03,0x0c,0x00,0x1b,0x29,0x24,0x04,0x08,0x3c,0x02,0x20,0x20,0x21, ++0x24,0x05,0x00,0x14,0x0c,0x00,0x1b,0x6e,0x24,0x06,0x01,0x07,0x08,0x00,0x1f,0x3d, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x73,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x02,0x14,0x40,0x00,0x04,0x00,0x00,0x00,0x00, ++0xa3,0x80,0x87,0x6d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0xa3,0x82,0x87,0x6d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x00,0x00,0x80,0x70,0x21,0x34,0x63,0x00,0x20,0x24,0x42,0x7e,0x5c, ++0x3c,0x04,0xb0,0x03,0xac,0x62,0x00,0x00,0x34,0x84,0x00,0x30,0xad,0xc0,0x02,0xb8, ++0x8c,0x83,0x00,0x00,0x24,0x02,0x00,0xff,0xa5,0xc0,0x00,0x0a,0x00,0x00,0x30,0x21, ++0xa7,0x82,0x99,0x30,0x27,0x88,0x99,0x40,0xa5,0xc3,0x00,0x08,0x3c,0x07,0xb0,0x08, ++0x30,0xc2,0xff,0xff,0x00,0x02,0x20,0xc0,0x24,0xc3,0x00,0x01,0x00,0x82,0x10,0x21, ++0x00,0x60,0x30,0x21,0x00,0x02,0x10,0x80,0x30,0x63,0xff,0xff,0x00,0x48,0x10,0x21, ++0x00,0x87,0x20,0x21,0x28,0xc5,0x00,0xff,0xac,0x83,0x00,0x00,0x14,0xa0,0xff,0xf4, ++0xa4,0x43,0x00,0x00,0x3c,0x02,0xb0,0x08,0x34,0x03,0xff,0xff,0x25,0xc4,0x00,0x0c, ++0x24,0x0a,0x00,0x02,0x34,0x42,0x07,0xf8,0x3c,0x06,0xb0,0x03,0xa7,0x83,0xbd,0x1c, ++0xac,0x43,0x00,0x00,0xaf,0x84,0xbd,0x40,0x34,0xc6,0x00,0x64,0xa0,0x8a,0x00,0x18, ++0x94,0xc5,0x00,0x00,0x8f,0x82,0xbd,0x40,0x25,0xc4,0x00,0x30,0x24,0x08,0x00,0x03, ++0x3c,0x03,0xb0,0x03,0xa0,0x45,0x00,0x21,0x34,0x63,0x00,0x66,0xaf,0x84,0xbd,0x44, ++0xa0,0x88,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xbd,0x44,0x25,0xc4,0x00,0x54, ++0x25,0xc7,0x00,0x78,0xa0,0x45,0x00,0x21,0xaf,0x84,0xbd,0x48,0xa0,0x88,0x00,0x18, ++0x94,0x65,0x00,0x00,0x8f,0x82,0xbd,0x48,0x25,0xc8,0x00,0x9c,0x24,0x09,0x00,0x01, ++0xa0,0x45,0x00,0x21,0xaf,0x87,0xbd,0x4c,0xa0,0xea,0x00,0x18,0x94,0xc4,0x00,0x00, ++0x8f,0x82,0xbd,0x4c,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x62,0xa0,0x44,0x00,0x21, ++0xaf,0x88,0xbd,0x50,0xa1,0x09,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xbd,0x50, ++0x25,0xc4,0x00,0xc0,0x3c,0x06,0xb0,0x03,0xa0,0x45,0x00,0x21,0xaf,0x84,0xbd,0x54, ++0xa0,0x89,0x00,0x18,0x94,0x65,0x00,0x00,0x8f,0x82,0xbd,0x54,0x25,0xc4,0x00,0xe4, ++0x34,0xc6,0x00,0x60,0xa0,0x45,0x00,0x21,0xaf,0x84,0xbd,0x58,0xa0,0x80,0x00,0x18, ++0x94,0xc5,0x00,0x00,0x8f,0x82,0xbd,0x58,0x25,0xc3,0x01,0x08,0x25,0xc7,0x01,0x2c, ++0xa0,0x45,0x00,0x21,0xaf,0x83,0xbd,0x5c,0xa0,0x60,0x00,0x18,0x94,0xc8,0x00,0x00, ++0x8f,0x82,0xbd,0x5c,0x25,0xc4,0x01,0x50,0x25,0xc5,0x01,0x74,0xa0,0x48,0x00,0x21, ++0x25,0xc6,0x01,0x98,0x25,0xc9,0x01,0xbc,0x25,0xca,0x01,0xe0,0x25,0xcb,0x02,0x04, ++0x25,0xcc,0x02,0x28,0x25,0xcd,0x02,0x4c,0x24,0x02,0x00,0x10,0x3c,0x03,0xb0,0x03, ++0xaf,0x87,0xbd,0x60,0x34,0x63,0x00,0x38,0xa0,0xe0,0x00,0x18,0xaf,0x84,0xbd,0x64, ++0xa0,0x80,0x00,0x18,0xaf,0x85,0xbd,0x68,0xa0,0xa0,0x00,0x18,0xaf,0x86,0xbd,0x6c, ++0xa0,0xc0,0x00,0x18,0xaf,0x89,0xbd,0x70,0xa1,0x20,0x00,0x18,0xaf,0x8a,0xbd,0x74, ++0xa1,0x40,0x00,0x18,0xaf,0x8b,0xbd,0x78,0xa1,0x60,0x00,0x18,0xaf,0x8c,0xbd,0x7c, ++0xa1,0x80,0x00,0x18,0xaf,0x8d,0xbd,0x80,0xa1,0xa2,0x00,0x18,0x94,0x64,0x00,0x00, ++0x8f,0x82,0xbd,0x80,0x25,0xc5,0x02,0x70,0x3c,0x03,0xb0,0x03,0xa0,0x44,0x00,0x21, ++0x24,0x02,0x00,0x11,0xaf,0x85,0xbd,0x84,0x34,0x63,0x00,0x6e,0xa0,0xa2,0x00,0x18, ++0x94,0x64,0x00,0x00,0x8f,0x82,0xbd,0x84,0x25,0xc5,0x02,0x94,0x3c,0x03,0xb0,0x03, ++0xa0,0x44,0x00,0x21,0x24,0x02,0x00,0x12,0xaf,0x85,0xbd,0x88,0x34,0x63,0x00,0x6c, ++0xa0,0xa2,0x00,0x18,0x94,0x64,0x00,0x00,0x8f,0x82,0xbd,0x88,0x24,0x05,0xff,0xff, ++0x24,0x07,0x00,0x01,0xa0,0x44,0x00,0x21,0x24,0x06,0x00,0x12,0x27,0x84,0xbd,0x40, ++0x8c,0x82,0x00,0x00,0x24,0xc6,0xff,0xff,0xa0,0x40,0x00,0x04,0x8c,0x83,0x00,0x00, ++0xa4,0x45,0x00,0x00,0xa4,0x45,0x00,0x02,0xa0,0x60,0x00,0x0a,0x8c,0x82,0x00,0x00, ++0xa4,0x65,0x00,0x06,0xa4,0x65,0x00,0x08,0xa0,0x40,0x00,0x10,0x8c,0x83,0x00,0x00, ++0xa4,0x45,0x00,0x0c,0xa4,0x45,0x00,0x0e,0xa0,0x60,0x00,0x12,0x8c,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0xa0,0x40,0x00,0x16,0x8c,0x83,0x00,0x00,0xa4,0x45,0x00,0x14, ++0xa0,0x67,0x00,0x17,0x8c,0x82,0x00,0x00,0x24,0x84,0x00,0x04,0xa0,0x40,0x00,0x20, ++0x04,0xc1,0xff,0xe7,0xac,0x40,0x00,0x1c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0x81,0x20, ++0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x10,0x00,0x80,0x60,0x21,0x10,0x40,0x00,0x56, ++0x00,0x00,0x70,0x21,0x97,0x82,0x99,0x30,0x94,0x8a,0x00,0x0c,0x27,0x87,0x99,0x40, ++0x00,0x02,0x40,0xc0,0x01,0x02,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21, ++0x90,0x8b,0x00,0x18,0xa4,0x4a,0x00,0x00,0x94,0x83,0x00,0x0e,0x39,0x64,0x00,0x10, ++0x2c,0x84,0x00,0x01,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x34,0x85,0x00,0x02, ++0x39,0x63,0x00,0x11,0x00,0x83,0x28,0x0b,0x34,0xa3,0x00,0x08,0x39,0x64,0x00,0x12, ++0x00,0x02,0x10,0x80,0x00,0xa4,0x18,0x0b,0x00,0x47,0x10,0x21,0x94,0x49,0x00,0x04, ++0x34,0x64,0x00,0x20,0x00,0x6b,0x20,0x0b,0x34,0x83,0x00,0x40,0x39,0x62,0x00,0x01, ++0x00,0x82,0x18,0x0b,0x00,0x09,0x30,0xc0,0x34,0x64,0x00,0x80,0x00,0xc9,0x28,0x21, ++0x39,0x62,0x00,0x02,0x00,0x60,0x68,0x21,0x00,0x82,0x68,0x0a,0x00,0x05,0x28,0x80, ++0x3c,0x02,0xb0,0x08,0x00,0xa7,0x28,0x21,0x00,0xc2,0x30,0x21,0x01,0x02,0x40,0x21, ++0x34,0x03,0xff,0xff,0x35,0xa4,0x01,0x00,0x39,0x62,0x00,0x03,0x2d,0x67,0x00,0x13, ++0xad,0x0a,0x00,0x00,0xa4,0xa3,0x00,0x00,0xac,0xc3,0x00,0x00,0xa7,0x89,0x99,0x30, ++0x10,0xe0,0x00,0x0f,0x00,0x82,0x68,0x0a,0x3c,0x03,0x80,0x01,0x00,0x0b,0x10,0x80, ++0x24,0x63,0x08,0xf0,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x60, ++0x94,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x00,0x00,0x02,0x74,0x03, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0x3a,0x94,0x44,0x00,0x00,0x93,0x83,0x99,0x24, ++0x91,0x82,0x00,0x21,0x01,0xc4,0x20,0x21,0x91,0x85,0x00,0x10,0x00,0x04,0x24,0x00, ++0x00,0x62,0x18,0x21,0x00,0x04,0x74,0x03,0x00,0x6e,0x18,0x23,0x00,0x65,0x10,0x2a, ++0x00,0xa2,0x18,0x0a,0x00,0x0d,0x24,0x00,0x3c,0x02,0xb0,0x06,0x24,0x05,0xff,0xff, ++0x00,0x64,0x18,0x25,0x34,0x42,0x80,0x20,0xac,0x43,0x00,0x00,0xa5,0x85,0x00,0x0e, ++0xa1,0x80,0x00,0x10,0xa5,0x85,0x00,0x0c,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x08,0x00,0x20,0x8c,0x34,0x63,0x00,0x62,0x3c,0x03,0xb0,0x03, ++0x08,0x00,0x20,0x8c,0x34,0x63,0x00,0x64,0x3c,0x03,0xb0,0x03,0x08,0x00,0x20,0x8c, ++0x34,0x63,0x00,0x66,0x3c,0x03,0xb0,0x03,0x08,0x00,0x20,0x8c,0x34,0x63,0x00,0x38, ++0x3c,0x03,0xb0,0x03,0x08,0x00,0x20,0x8c,0x34,0x63,0x00,0x6e,0x3c,0x03,0xb0,0x03, ++0x08,0x00,0x20,0x8c,0x34,0x63,0x00,0x6c,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01, ++0x34,0x63,0x00,0x20,0x24,0x42,0x82,0xe8,0x00,0x05,0x28,0x40,0xac,0x62,0x00,0x00, ++0x00,0xa6,0x28,0x21,0x2c,0xe2,0x00,0x10,0x14,0x80,0x00,0x06,0x00,0x00,0x18,0x21, ++0x10,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0xe0,0x18,0x21,0x03,0xe0,0x00,0x08, ++0x00,0x60,0x10,0x21,0x24,0x02,0x00,0x20,0x10,0xe2,0x00,0x06,0x2c,0xe4,0x00,0x10, ++0x24,0xa2,0x00,0x01,0x10,0x80,0xff,0xf9,0x00,0x02,0x11,0x00,0x08,0x00,0x20,0xc7, ++0x00,0x47,0x18,0x21,0x08,0x00,0x20,0xc7,0x24,0xa3,0x00,0x50,0x27,0xbd,0xff,0xc8, ++0xaf,0xb4,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, ++0xaf,0xbf,0x00,0x30,0xaf,0xb7,0x00,0x2c,0xaf,0xb6,0x00,0x28,0xaf,0xb5,0x00,0x24, ++0xaf,0xb0,0x00,0x10,0x00,0x80,0x90,0x21,0x84,0x84,0x00,0x08,0x3c,0x05,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x34,0xa5,0x00,0x20,0x24,0x42,0x83,0x4c,0x3c,0x03,0xb0,0x06, ++0x00,0x04,0x20,0x80,0xac,0xa2,0x00,0x00,0x00,0x83,0x20,0x21,0x3c,0x06,0xb0,0x06, ++0x8c,0x82,0x00,0x00,0x34,0xc6,0x80,0x24,0x8c,0x88,0x00,0x00,0x8c,0xc4,0x00,0x00, ++0x96,0x45,0x00,0x08,0x30,0x53,0xff,0xff,0x00,0x08,0x44,0x02,0x34,0x84,0x01,0x00, ++0x3c,0x02,0xb0,0x00,0x00,0x08,0x18,0xc0,0x00,0x13,0x3a,0x00,0xac,0xc4,0x00,0x00, ++0x00,0xe2,0x38,0x21,0xae,0x53,0x02,0xb8,0x00,0x68,0x18,0x21,0x24,0xa5,0x00,0x02, ++0x8c,0xf6,0x00,0x00,0x30,0xa5,0x01,0xff,0x8c,0xf5,0x00,0x04,0x27,0x86,0x99,0x40, ++0x00,0x03,0x18,0x80,0x00,0x13,0xa0,0xc0,0xa6,0x45,0x00,0x08,0x00,0x66,0x18,0x21, ++0x02,0x93,0x10,0x21,0x00,0x02,0x48,0x80,0x94,0x65,0x00,0x00,0x01,0x26,0x30,0x21, ++0x24,0x02,0xff,0xff,0x00,0x15,0x1a,0x02,0x27,0x84,0x99,0x50,0xa4,0xc2,0x00,0x02, ++0x30,0x63,0x00,0x1f,0x24,0x02,0x00,0x10,0x01,0x24,0x20,0x21,0xa4,0xc8,0x00,0x04, ++0x8c,0xf0,0x00,0x08,0xa6,0x43,0x00,0x06,0xa6,0x45,0x00,0x0a,0xa0,0x82,0x00,0x06, ++0x86,0x43,0x00,0x06,0x27,0x82,0x99,0x44,0x01,0x22,0x88,0x21,0x24,0x02,0x00,0x13, ++0x10,0x62,0x00,0xee,0xae,0x27,0x00,0x18,0x3c,0x03,0xb0,0x03,0x34,0x63,0x01,0x00, ++0xa6,0x40,0x00,0x02,0x3c,0x02,0xb0,0x03,0x90,0x64,0x00,0x00,0x34,0x42,0x01,0x08, ++0x8c,0x45,0x00,0x00,0x00,0x10,0x1b,0xc2,0x00,0x04,0x20,0x82,0x30,0x63,0x00,0x01, ++0xac,0xc5,0x00,0x08,0x10,0x60,0x00,0xc7,0x30,0x97,0x00,0x01,0x00,0x10,0x16,0x82, ++0x30,0x46,0x00,0x01,0x00,0x10,0x12,0x02,0x00,0x10,0x19,0xc2,0x00,0x10,0x26,0x02, ++0x00,0x10,0x2e,0x42,0x30,0x48,0x00,0x7f,0x24,0x02,0x00,0x01,0x30,0x71,0x00,0x01, ++0x30,0x84,0x00,0x01,0x10,0xc2,0x00,0xb3,0x30,0xa3,0x00,0x01,0x00,0x60,0x28,0x21, ++0x0c,0x00,0x20,0xba,0x01,0x00,0x38,0x21,0x02,0x93,0x18,0x21,0x00,0x03,0x18,0x80, ++0x2c,0x46,0x00,0x54,0x27,0x85,0x99,0x50,0x27,0x84,0x99,0x48,0x00,0x06,0x10,0x0a, ++0x00,0x65,0x28,0x21,0x26,0x26,0x00,0x02,0x00,0x64,0x18,0x21,0xa0,0xa2,0x00,0x02, ++0xa0,0x66,0x00,0x06,0xa0,0x62,0x00,0x07,0xa0,0xa2,0x00,0x01,0x02,0x93,0x28,0x21, ++0x00,0x05,0x28,0x80,0x27,0x82,0x99,0x44,0x00,0xa2,0x58,0x21,0x8d,0x64,0x00,0x18, ++0x00,0x10,0x15,0xc2,0x30,0x42,0x00,0x01,0x8c,0x83,0x00,0x0c,0x27,0x84,0x99,0x60, ++0x00,0xa4,0x48,0x21,0xa6,0x42,0x00,0x00,0xa6,0x56,0x00,0x04,0x8d,0x26,0x00,0x00, ++0x00,0x03,0x19,0x42,0x3c,0x02,0xff,0xef,0x34,0x42,0xff,0xff,0x30,0x63,0x00,0x01, ++0x00,0xc2,0x40,0x24,0x00,0x03,0x1d,0x00,0x01,0x03,0x40,0x25,0x00,0x08,0x15,0x02, ++0x00,0x10,0x34,0x42,0x00,0x10,0x3c,0x82,0x00,0x15,0x19,0x82,0x00,0x15,0x25,0x82, ++0x00,0x10,0x2c,0x02,0x30,0x42,0x00,0x01,0x30,0xcd,0x00,0x01,0x30,0x6c,0x00,0x01, ++0x30,0xe6,0x00,0x01,0x30,0x8a,0x00,0x03,0x32,0xb1,0x00,0x07,0x30,0xa5,0x00,0x01, ++0xad,0x28,0x00,0x00,0x10,0x40,0x00,0x0b,0x32,0x07,0x00,0x7f,0x8d,0x64,0x00,0x18, ++0x3c,0x03,0xff,0xf0,0x34,0x63,0xff,0xff,0x8c,0x82,0x00,0x0c,0x01,0x03,0x18,0x24, ++0x00,0x02,0x13,0x82,0x30,0x42,0x00,0x0f,0x00,0x02,0x14,0x00,0x00,0x62,0x18,0x25, ++0xad,0x23,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xc2,0x00,0x6a,0x00,0x00,0x00,0x00, ++0x15,0x80,0x00,0x03,0x00,0x00,0x00,0x00,0x15,0x40,0x00,0x5b,0x24,0x02,0x00,0x01, ++0x96,0x42,0x00,0x04,0x00,0x00,0x00,0x00,0x24,0x42,0x00,0x04,0xa6,0x42,0x00,0x04, ++0x00,0xa0,0x20,0x21,0x0c,0x00,0x20,0xba,0x01,0xa0,0x28,0x21,0x02,0x93,0x18,0x21, ++0x00,0x03,0x40,0x80,0x2c,0x45,0x00,0x54,0x27,0x84,0x99,0x50,0x01,0x04,0x20,0x21, ++0x00,0x05,0x10,0x0a,0xa0,0x82,0x00,0x00,0xa0,0x80,0x00,0x04,0xa0,0x80,0x00,0x05, ++0x96,0x43,0x00,0x04,0x27,0x82,0x99,0x40,0x01,0x02,0x10,0x21,0xa4,0x43,0x00,0x06, ++0x27,0x82,0x99,0x44,0x92,0x46,0x00,0x01,0x01,0x02,0x10,0x21,0x8c,0x45,0x00,0x18, ++0x27,0x83,0x99,0x60,0x01,0x03,0x18,0x21,0xa0,0x60,0x00,0x00,0xa0,0x86,0x00,0x07, ++0x94,0xa2,0x00,0x10,0x24,0x03,0x00,0x04,0x30,0x42,0x00,0x0f,0x10,0x43,0x00,0x36, ++0x24,0xa5,0x00,0x10,0x94,0xa3,0x00,0x16,0x27,0x87,0x99,0x58,0x01,0x07,0x10,0x21, ++0xa4,0x43,0x00,0x02,0x94,0xa2,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01, ++0x14,0x40,0x00,0x24,0x02,0x93,0x20,0x21,0x94,0xa2,0x00,0x00,0x24,0x03,0x00,0xa4, ++0x30,0x42,0x00,0xff,0x10,0x43,0x00,0x1f,0x00,0x00,0x00,0x00,0x94,0xa2,0x00,0x00, ++0x24,0x03,0x00,0x88,0x30,0x42,0x00,0x88,0x10,0x43,0x00,0x14,0x02,0x93,0x18,0x21, ++0x27,0x84,0x99,0x60,0x00,0x03,0x18,0x80,0x00,0x64,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x3c,0x04,0x00,0x80,0x00,0x44,0x10,0x25,0xac,0x62,0x00,0x00,0x02,0x93,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0xa0,0x51,0x00,0x00,0x8f,0xbf,0x00,0x30, ++0x7b,0xb6,0x01,0x7c,0x7b,0xb4,0x01,0x3c,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0x94,0xa2,0x00,0x18, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x60,0x10,0x40,0xff,0xe9,0x02,0x93,0x18,0x21, ++0x02,0x93,0x20,0x21,0x27,0x82,0x99,0x60,0x00,0x04,0x20,0x80,0x00,0x82,0x20,0x21, ++0x8c,0x83,0x00,0x00,0x3c,0x02,0xff,0x7f,0x34,0x42,0xff,0xff,0x00,0x62,0x18,0x24, ++0x08,0x00,0x21,0xaf,0xac,0x83,0x00,0x00,0x27,0x87,0x99,0x58,0x01,0x07,0x10,0x21, ++0x08,0x00,0x21,0x99,0xa4,0x40,0x00,0x02,0x11,0x42,0x00,0x07,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x02,0x14,0x40,0xff,0xa7,0x00,0xa0,0x20,0x21,0x96,0x42,0x00,0x04, ++0x08,0x00,0x21,0x77,0x24,0x42,0x00,0x0c,0x96,0x42,0x00,0x04,0x08,0x00,0x21,0x77, ++0x24,0x42,0x00,0x08,0x16,0xe6,0xff,0x96,0x3c,0x02,0xff,0xfb,0x8d,0x63,0x00,0x18, ++0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24,0xac,0x62,0x00,0x08,0x08,0x00,0x21,0x70, ++0x00,0x00,0x30,0x21,0x16,0xe6,0xff,0x4e,0x00,0x60,0x28,0x21,0x3c,0x02,0xfb,0xff, ++0x34,0x42,0xff,0xff,0x02,0x02,0x10,0x24,0xac,0xe2,0x00,0x08,0x08,0x00,0x21,0x2f, ++0x00,0x00,0x30,0x21,0x93,0x87,0xc4,0x54,0x00,0x10,0x1e,0x42,0x00,0x10,0x26,0x82, ++0x27,0x82,0x99,0x48,0x2c,0xe5,0x00,0x0c,0x01,0x22,0x48,0x21,0x30,0x63,0x00,0x01, ++0x30,0x86,0x00,0x01,0x14,0xa0,0x00,0x06,0x00,0xe0,0x40,0x21,0x00,0x03,0x10,0x40, ++0x00,0x46,0x10,0x21,0x00,0x02,0x11,0x00,0x00,0xe2,0x10,0x21,0x24,0x48,0x00,0x04, ++0x02,0x93,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x84,0x99,0x50,0x27,0x83,0x99,0x48, ++0x00,0x44,0x20,0x21,0x00,0x43,0x10,0x21,0xa1,0x28,0x00,0x07,0xa0,0x40,0x00,0x06, ++0xa0,0x80,0x00,0x02,0x08,0x00,0x21,0x3f,0xa0,0x80,0x00,0x01,0x24,0x02,0x00,0x01, ++0x00,0xe0,0x20,0x21,0x0c,0x00,0x01,0xc2,0xa6,0x42,0x00,0x02,0x8e,0x24,0x00,0x18, ++0x0c,0x00,0x05,0x39,0x00,0x00,0x00,0x00,0x08,0x00,0x21,0xb3,0x00,0x00,0x00,0x00, ++0x30,0xa7,0xff,0xff,0x00,0x07,0x18,0xc0,0x00,0x67,0x18,0x21,0x3c,0x06,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x24,0x42,0x88,0x30,0x27,0x85,0x99,0x50,0x00,0x03,0x18,0x80, ++0x34,0xc6,0x00,0x20,0x00,0x65,0x18,0x21,0xac,0xc2,0x00,0x00,0x80,0x62,0x00,0x07, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x29,0x00,0x80,0x28,0x21,0x90,0x82,0x00,0x16, ++0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0x30,0x43,0x00,0x01,0x14,0x60,0x00,0x02, ++0xa0,0x82,0x00,0x16,0xa0,0x80,0x00,0x17,0x90,0xa2,0x00,0x04,0x3c,0x03,0xb0,0x03, ++0x27,0x86,0x99,0x40,0x14,0x40,0x00,0x06,0x34,0x63,0x00,0x20,0x24,0x02,0x00,0x01, ++0xa0,0xa2,0x00,0x04,0xa4,0xa7,0x00,0x02,0x03,0xe0,0x00,0x08,0xa4,0xa7,0x00,0x00, ++0x94,0xa4,0x00,0x02,0x3c,0x02,0x80,0x01,0x24,0x42,0xa0,0x30,0xac,0x62,0x00,0x00, ++0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21, ++0x94,0x62,0x00,0x04,0xa4,0x67,0x00,0x02,0x3c,0x03,0xb0,0x08,0x00,0x02,0x20,0xc0, ++0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x46,0x10,0x21,0x00,0x83,0x20,0x21, ++0xa4,0x47,0x00,0x00,0xac,0x87,0x00,0x00,0x90,0xa2,0x00,0x04,0xa4,0xa7,0x00,0x02, ++0x24,0x42,0x00,0x01,0x03,0xe0,0x00,0x08,0xa0,0xa2,0x00,0x04,0x90,0x82,0x00,0x16, ++0x24,0x85,0x00,0x06,0x34,0x42,0x00,0x01,0x30,0x43,0x00,0x02,0x14,0x60,0xff,0xda, ++0xa0,0x82,0x00,0x16,0x24,0x02,0x00,0x01,0x08,0x00,0x22,0x22,0xa0,0x82,0x00,0x17, ++0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x00,0x80,0x38,0x21,0x84,0x84,0x00,0x02, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x3c,0x0a,0xb0,0x06,0x34,0x63,0x00,0x20, ++0x24,0x42,0x89,0x30,0x3c,0x0b,0xb0,0x08,0x27,0x89,0x99,0x40,0x34,0x0c,0xff,0xff, ++0x35,0x4a,0x80,0x20,0x10,0x80,0x00,0x30,0xac,0x62,0x00,0x00,0x97,0x82,0x99,0x30, ++0x94,0xe6,0x02,0xba,0x00,0x02,0x18,0xc0,0x00,0x6b,0x28,0x21,0xac,0xa6,0x00,0x00, ++0x8c,0xe4,0x02,0xb8,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x04,0x10,0xc0, ++0x00,0x44,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x49,0x10,0x21,0x94,0x48,0x00,0x04, ++0x00,0x69,0x18,0x21,0xa4,0x66,0x00,0x00,0x00,0x08,0x28,0xc0,0x00,0xab,0x10,0x21, ++0xac,0x4c,0x00,0x00,0x8c,0xe4,0x02,0xb8,0x27,0x82,0x99,0x44,0x00,0xa8,0x28,0x21, ++0x00,0x04,0x18,0xc0,0x00,0x64,0x18,0x21,0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21, ++0x8c,0x46,0x00,0x18,0x27,0x84,0x99,0x50,0x00,0x64,0x18,0x21,0x8c,0xc2,0x00,0x00, ++0x80,0x67,0x00,0x06,0x00,0x05,0x28,0x80,0x30,0x42,0xff,0xff,0x00,0x47,0x10,0x21, ++0x30,0x43,0x00,0xff,0x00,0x03,0x18,0x2b,0x00,0x02,0x12,0x02,0x00,0x43,0x10,0x21, ++0x3c,0x04,0x00,0x04,0x00,0xa9,0x28,0x21,0x00,0x44,0x10,0x25,0xa4,0xac,0x00,0x00, ++0xad,0x42,0x00,0x00,0xa7,0x88,0x99,0x30,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x84,0xe3,0x00,0x06,0x27,0x82,0xbd,0x40, ++0x94,0xe5,0x02,0xba,0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00, ++0x0c,0x00,0x22,0x0c,0x00,0x00,0x00,0x00,0x08,0x00,0x22,0x86,0x00,0x00,0x00,0x00, ++0x94,0x88,0x00,0x00,0x00,0x80,0x58,0x21,0x27,0x8a,0x99,0x40,0x00,0x08,0x18,0xc0, ++0x00,0x68,0x18,0x21,0x3c,0x04,0xb0,0x03,0x00,0x03,0x18,0x80,0x3c,0x02,0x80,0x01, ++0x00,0x6a,0x18,0x21,0x34,0x84,0x00,0x20,0x24,0x42,0x8a,0x50,0x30,0xa5,0xff,0xff, ++0xac,0x82,0x00,0x00,0x94,0x67,0x00,0x02,0x11,0x05,0x00,0x35,0x24,0x04,0x00,0x01, ++0x91,0x66,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x86,0x10,0x2a,0x10,0x40,0x00,0x10, ++0x00,0xc0,0x48,0x21,0x3c,0x0d,0xb0,0x03,0x01,0x40,0x60,0x21,0x35,0xad,0x00,0x20, ++0x10,0xe5,0x00,0x0d,0x24,0x84,0x00,0x01,0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21, ++0x00,0x02,0x10,0x80,0x01,0x20,0x30,0x21,0x00,0x4a,0x10,0x21,0x00,0x86,0x18,0x2a, ++0x00,0xe0,0x40,0x21,0x94,0x47,0x00,0x02,0x14,0x60,0xff,0xf5,0x00,0x00,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21,0x00,0x08,0x20,0xc0,0x00,0x88,0x20,0x21, ++0x24,0xc2,0xff,0xff,0x00,0x04,0x20,0x80,0xa1,0x62,0x00,0x04,0x00,0x8c,0x20,0x21, ++0x94,0x83,0x00,0x04,0x00,0x07,0x10,0xc0,0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x4c,0x10,0x21,0x00,0x03,0x28,0xc0,0x94,0x46,0x00,0x02,0x00,0xa3,0x18,0x21, ++0x00,0x03,0x18,0x80,0x00,0x6c,0x18,0x21,0xa4,0x66,0x00,0x00,0xa4,0x86,0x00,0x02, ++0x95,0x64,0x00,0x02,0x3c,0x03,0xb0,0x08,0x3c,0x02,0x80,0x01,0x00,0xa3,0x28,0x21, ++0x24,0x42,0xa0,0x30,0xad,0xa2,0x00,0x00,0x10,0x87,0x00,0x03,0xac,0xa6,0x00,0x00, ++0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x08,0x00,0x22,0xd4,0xa5,0x68,0x00,0x02, ++0x91,0x62,0x00,0x04,0xa5,0x67,0x00,0x00,0x24,0x42,0xff,0xff,0x30,0x43,0x00,0xff, ++0x14,0x60,0xff,0xf7,0xa1,0x62,0x00,0x04,0x24,0x02,0xff,0xff,0x08,0x00,0x22,0xd4, ++0xa5,0x62,0x00,0x02,0x00,0x05,0x40,0xc0,0x01,0x05,0x30,0x21,0x27,0xbd,0xff,0xd8, ++0x00,0x06,0x30,0x80,0x27,0x82,0x99,0x44,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14, ++0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0xaf,0xb0,0x00,0x10,0x00,0xc2,0x10,0x21, ++0x8c,0x47,0x00,0x18,0x00,0xa0,0x90,0x21,0x3c,0x02,0x80,0x01,0x3c,0x05,0xb0,0x03, ++0x34,0xa5,0x00,0x20,0x24,0x42,0x8b,0x84,0xac,0xa2,0x00,0x00,0x27,0x83,0x99,0x50, ++0x00,0xc3,0x30,0x21,0x8c,0xe2,0x00,0x00,0x80,0xc5,0x00,0x06,0x00,0x80,0x88,0x21, ++0x30,0x42,0xff,0xff,0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff,0x10,0x60,0x00,0x02, ++0x00,0x02,0x12,0x02,0x24,0x42,0x00,0x01,0x30,0x53,0x00,0xff,0x01,0x12,0x10,0x21, ++0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x50,0x00,0x43,0x10,0x21,0x80,0x44,0x00,0x07, ++0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x4b,0x26,0x24,0x00,0x06,0x32,0x50,0xff,0xff, ++0x02,0x20,0x20,0x21,0x0c,0x00,0x22,0x94,0x02,0x00,0x28,0x21,0x92,0x22,0x00,0x10, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x2e,0x3c,0x03,0xb0,0x08,0x3c,0x09,0x80,0x01, ++0x27,0x88,0x99,0x40,0xa6,0x32,0x00,0x0c,0x00,0x10,0x20,0xc0,0x00,0x90,0x20,0x21, ++0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x03,0xb0,0x08, ++0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x48,0x10,0x21,0x00,0xa3,0x28,0x21,0x25,0x26,0xa0,0x30,0x34,0x03,0xff,0xff, ++0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02,0xa4,0x43,0x00,0x00, ++0xac,0xa3,0x00,0x00,0x92,0x22,0x00,0x10,0x92,0x23,0x00,0x0a,0xa6,0x32,0x00,0x0e, ++0x02,0x62,0x10,0x21,0x14,0x60,0x00,0x05,0xa2,0x22,0x00,0x10,0x92,0x22,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfe,0xa2,0x22,0x00,0x16,0x92,0x22,0x00,0x04, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x05,0x00,0x00,0x00,0x00,0x92,0x22,0x00,0x16, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa2,0x22,0x00,0x16,0x8f,0xbf,0x00,0x20, ++0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28, ++0x96,0x22,0x00,0x0e,0x27,0x88,0x99,0x40,0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21, ++0x00,0x04,0x20,0x80,0x00,0x88,0x20,0x21,0x94,0x82,0x00,0x04,0x3c,0x06,0xb0,0x03, ++0x3c,0x09,0x80,0x01,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0xa3,0x28,0x21,0x00,0x48,0x10,0x21,0x34,0xc6,0x00,0x20,0x25,0x23,0xa0,0x30, ++0xac,0xc3,0x00,0x00,0xa4,0x50,0x00,0x00,0xac,0xb0,0x00,0x00,0x08,0x00,0x23,0x12, ++0xa4,0x90,0x00,0x02,0x08,0x00,0x23,0x09,0x32,0x50,0xff,0xff,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x24,0x42,0x8d,0x4c,0x34,0x63,0x00,0x20,0xac,0x62,0x00,0x00, ++0x90,0x82,0x00,0x04,0x97,0xaa,0x00,0x12,0x00,0x80,0x60,0x21,0x30,0xa8,0xff,0xff, ++0x00,0x4a,0x20,0x23,0x34,0x09,0xff,0xff,0x30,0xcf,0xff,0xff,0x30,0xee,0xff,0xff, ++0x11,0x09,0x00,0x73,0xa1,0x84,0x00,0x04,0x00,0x0e,0xc0,0xc0,0x00,0x08,0x10,0xc0, ++0x00,0x48,0x10,0x21,0x03,0x0e,0x20,0x21,0x27,0x8d,0x99,0x40,0x00,0x04,0x20,0x80, ++0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0x8d,0x20,0x21,0x94,0x86,0x00,0x02, ++0x94,0x43,0x00,0x04,0x3c,0x19,0x80,0x01,0xa4,0x46,0x00,0x02,0x00,0x03,0x28,0xc0, ++0x00,0xa3,0x18,0x21,0x94,0x87,0x00,0x02,0x3c,0x02,0xb0,0x08,0x00,0x03,0x18,0x80, ++0x00,0xa2,0x28,0x21,0x00,0x6d,0x18,0x21,0x27,0x22,0xa0,0x30,0x3c,0x01,0xb0,0x03, ++0xac,0x22,0x00,0x20,0xa4,0x66,0x00,0x00,0x10,0xe9,0x00,0x57,0xac,0xa6,0x00,0x00, ++0x01,0xe0,0x30,0x21,0x11,0x40,0x00,0x1d,0x00,0x00,0x48,0x21,0x01,0x40,0x38,0x21, ++0x27,0x8b,0x99,0x44,0x27,0x8a,0x99,0x50,0x00,0x06,0x40,0xc0,0x01,0x06,0x18,0x21, ++0x00,0x03,0x18,0x80,0x00,0x6b,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x6a,0x18,0x21, ++0x80,0x65,0x00,0x06,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0xff,0xff, ++0x00,0x45,0x10,0x21,0x30,0x44,0x00,0xff,0x00,0x02,0x12,0x02,0x01,0x22,0x18,0x21, ++0x24,0x62,0x00,0x01,0x14,0x80,0x00,0x02,0x30,0x49,0x00,0xff,0x30,0x69,0x00,0xff, ++0x01,0x06,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x24,0xe7,0xff,0xff, ++0x94,0x46,0x00,0x02,0x14,0xe0,0xff,0xe9,0x00,0x06,0x40,0xc0,0x91,0x82,0x00,0x10, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x20,0x3c,0x06,0xb0,0x03,0xa5,0x8f,0x00,0x0c, ++0x03,0x0e,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21,0x94,0x82,0x00,0x04, ++0x3c,0x03,0xb0,0x08,0x3c,0x07,0xb0,0x03,0x00,0x02,0x28,0xc0,0x00,0xa2,0x10,0x21, ++0x00,0x02,0x10,0x80,0x00,0x4d,0x10,0x21,0x00,0xa3,0x28,0x21,0x27,0x26,0xa0,0x30, ++0x34,0x03,0xff,0xff,0x34,0xe7,0x00,0x20,0xac,0xe6,0x00,0x00,0xa4,0x83,0x00,0x02, ++0xa4,0x43,0x00,0x00,0xac,0xa3,0x00,0x00,0x91,0x82,0x00,0x10,0x91,0x83,0x00,0x04, ++0xa5,0x8e,0x00,0x0e,0x01,0x22,0x10,0x21,0x14,0x60,0x00,0x05,0xa1,0x82,0x00,0x10, ++0x91,0x82,0x00,0x16,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0xfd,0xa1,0x82,0x00,0x16, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x95,0x82,0x00,0x0e,0x3c,0x03,0xb0,0x08, ++0x00,0x02,0x20,0xc0,0x00,0x82,0x20,0x21,0x00,0x04,0x20,0x80,0x00,0x8d,0x20,0x21, ++0x94,0x82,0x00,0x04,0x34,0xc6,0x00,0x20,0x27,0x27,0xa0,0x30,0x00,0x02,0x28,0xc0, ++0x00,0xa2,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0xa3,0x28,0x21,0x00,0x4d,0x10,0x21, ++0xac,0xc7,0x00,0x00,0xa4,0x8f,0x00,0x02,0xa4,0x4f,0x00,0x00,0xac,0xaf,0x00,0x00, ++0x08,0x00,0x23,0xa1,0x03,0x0e,0x20,0x21,0x08,0x00,0x23,0x7c,0xa5,0x88,0x00,0x02, ++0x00,0x0e,0xc0,0xc0,0x03,0x0e,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x8d,0x99,0x40, ++0x00,0x4d,0x10,0x21,0x94,0x43,0x00,0x02,0x30,0x84,0x00,0xff,0x14,0x80,0x00,0x05, ++0xa5,0x83,0x00,0x00,0x24,0x02,0xff,0xff,0x3c,0x19,0x80,0x01,0x08,0x00,0x23,0x7c, ++0xa5,0x82,0x00,0x02,0x08,0x00,0x23,0x7c,0x3c,0x19,0x80,0x01,0x3c,0x08,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0x78,0x35,0x08,0x00,0x20,0x24,0x42,0x8f,0x8c, ++0xaf,0xb2,0x00,0x68,0xaf,0xb1,0x00,0x64,0xaf,0xb0,0x00,0x60,0xad,0x02,0x00,0x00, ++0xaf,0xbf,0x00,0x84,0xaf,0xbe,0x00,0x80,0xaf,0xb7,0x00,0x7c,0xaf,0xb6,0x00,0x78, ++0xaf,0xb5,0x00,0x74,0xaf,0xb4,0x00,0x70,0xaf,0xb3,0x00,0x6c,0xaf,0xa4,0x00,0x88, ++0x90,0x83,0x00,0x0a,0x27,0x82,0xbd,0x40,0xaf,0xa6,0x00,0x90,0x00,0x03,0x18,0x80, ++0x00,0x62,0x18,0x21,0x8c,0x63,0x00,0x00,0xaf,0xa7,0x00,0x94,0x27,0x86,0x99,0x44, ++0xaf,0xa3,0x00,0x1c,0x94,0x63,0x00,0x14,0x30,0xb1,0xff,0xff,0x24,0x08,0x00,0x01, ++0x00,0x03,0x20,0xc0,0xaf,0xa3,0x00,0x18,0x00,0x83,0x18,0x21,0xaf,0xa4,0x00,0x54, ++0x00,0x03,0x18,0x80,0x27,0x84,0x99,0x50,0x00,0x64,0x20,0x21,0x80,0x82,0x00,0x06, ++0x00,0x66,0x18,0x21,0x8c,0x66,0x00,0x18,0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2, ++0x8c,0xc4,0x00,0x08,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43,0x00,0x02,0x10,0x40, ++0x00,0x04,0x2f,0xc2,0x00,0x04,0x1c,0x82,0x00,0xc2,0x38,0x21,0x00,0x04,0x24,0x42, ++0x8f,0xa2,0x00,0x1c,0x30,0x63,0x00,0x01,0x30,0x84,0x00,0x01,0xaf,0xa5,0x00,0x3c, ++0xaf,0xa3,0x00,0x34,0xaf,0xa4,0x00,0x38,0xaf,0xa0,0x00,0x40,0xaf,0xa0,0x00,0x44, ++0xaf,0xa0,0x00,0x50,0xaf,0xa8,0x00,0x20,0x80,0x42,0x00,0x12,0x8f,0xb2,0x00,0x18, ++0xaf,0xa2,0x00,0x28,0x8c,0xd0,0x00,0x0c,0x14,0xa0,0x01,0xda,0x00,0x60,0x30,0x21, ++0x00,0x10,0x10,0x82,0x30,0x45,0x00,0x07,0x10,0xa0,0x00,0x11,0xaf,0xa0,0x00,0x30, ++0x8f,0xa4,0x00,0x98,0x27,0x82,0x86,0x30,0x00,0x04,0x18,0x40,0x00,0x62,0x18,0x21, ++0x24,0xa2,0x00,0x05,0x8f,0xa5,0x00,0x20,0x94,0x64,0x00,0x00,0x00,0x45,0x10,0x04, ++0x00,0x44,0x00,0x1a,0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, ++0x00,0x00,0x10,0x12,0x24,0x42,0x00,0x10,0x30,0x42,0xff,0xfc,0xaf,0xa2,0x00,0x30, ++0x8f,0xa3,0x00,0x18,0x8f,0xa4,0x00,0x28,0x34,0x02,0xff,0xff,0xaf,0xa0,0x00,0x2c, ++0xaf,0xa2,0x00,0x48,0xaf,0xa3,0x00,0x4c,0x00,0x60,0xf0,0x21,0x00,0x00,0xb8,0x21, ++0x18,0x80,0x00,0x4e,0xaf,0xa0,0x00,0x24,0x00,0x11,0x89,0x02,0xaf,0xb1,0x00,0x58, ++0x00,0x80,0xa8,0x21,0x00,0x12,0x10,0xc0,0x00,0x52,0x20,0x21,0x00,0x04,0x20,0x80, ++0x00,0x40,0xa0,0x21,0x27,0x82,0x99,0x58,0x00,0x82,0x10,0x21,0x94,0x43,0x00,0x02, ++0x8f,0xa6,0x00,0x58,0x27,0x85,0x99,0x40,0x00,0x03,0x19,0x02,0x00,0x66,0x18,0x23, ++0x30,0x63,0x0f,0xff,0x00,0x85,0x20,0x21,0x28,0x62,0x00,0x20,0x94,0x96,0x00,0x02, ++0x10,0x40,0x01,0xa1,0x28,0x62,0x00,0x40,0x8f,0xa8,0x00,0x90,0x00,0x00,0x00,0x00, ++0x00,0x68,0x10,0x06,0x30,0x43,0x00,0x01,0x24,0x02,0x00,0x01,0x10,0x62,0x01,0x7b, ++0x3c,0x02,0xb0,0x03,0x8f,0xa6,0x00,0x88,0x34,0x42,0x01,0x04,0x84,0xc5,0x00,0x0c, ++0x02,0x92,0x18,0x21,0x94,0x46,0x00,0x00,0x00,0x05,0x20,0xc0,0x00,0x85,0x20,0x21, ++0x00,0x03,0x18,0x80,0x27,0x82,0x99,0x50,0x27,0x85,0x99,0x48,0x00,0x65,0x28,0x21, ++0x00,0x62,0x18,0x21,0x80,0x71,0x00,0x05,0x80,0x73,0x00,0x04,0x8f,0xa3,0x00,0x88, ++0x30,0xd0,0xff,0xff,0x00,0x10,0x3a,0x03,0x32,0x08,0x00,0xff,0x27,0x82,0x99,0x60, ++0x00,0x04,0x20,0x80,0x80,0xa6,0x00,0x06,0x00,0x82,0x20,0x21,0xa4,0x67,0x00,0x44, ++0xa4,0x68,0x00,0x46,0x8c,0x84,0x00,0x00,0x38,0xc6,0x00,0x00,0x01,0x00,0x80,0x21, ++0x00,0x04,0x15,0x02,0x30,0x42,0x00,0x01,0x10,0x40,0x00,0x03,0x00,0xe6,0x80,0x0a, ++0x00,0x04,0x14,0x02,0x30,0x50,0x00,0x0f,0x12,0x20,0x01,0x50,0x02,0x40,0x20,0x21, ++0x02,0x71,0x10,0x21,0x00,0x50,0x10,0x2a,0x14,0x40,0x00,0xed,0x02,0x92,0x10,0x21, ++0x93,0x82,0x94,0x51,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0xe0, ++0x02,0x92,0x28,0x21,0x26,0xe2,0x00,0x01,0x30,0x57,0xff,0xff,0x02,0x40,0xf0,0x21, ++0x26,0xb5,0xff,0xff,0x16,0xa0,0xff,0xb7,0x02,0xc0,0x90,0x21,0x16,0xe0,0x00,0xd0, ++0x00,0x00,0x00,0x00,0x8f,0xa3,0x00,0x98,0x00,0x00,0x00,0x00,0x2c,0x62,0x00,0x10, ++0x10,0x40,0x00,0x2e,0x00,0x00,0x00,0x00,0x8f,0xa4,0x00,0x24,0x00,0x00,0x00,0x00, ++0x18,0x80,0x00,0x2a,0x24,0x03,0x00,0x01,0x8f,0xa5,0x00,0x1c,0x27,0x84,0x99,0x44, ++0x94,0xb2,0x00,0x14,0xa0,0xa3,0x00,0x12,0x8f,0xa6,0x00,0x3c,0x00,0x12,0x10,0xc0, ++0x00,0x52,0x10,0x21,0x00,0x02,0x80,0x80,0x27,0x82,0x99,0x50,0x02,0x02,0x10,0x21, ++0x80,0x43,0x00,0x06,0x02,0x04,0x20,0x21,0x8c,0x85,0x00,0x18,0x24,0x63,0x00,0x02, ++0x00,0x03,0x17,0xc2,0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40, ++0x14,0xc0,0x00,0x0e,0x00,0xa3,0x38,0x21,0x27,0x82,0x99,0x40,0x02,0x02,0x10,0x21, ++0x94,0x43,0x00,0x06,0x8f,0xa8,0x00,0x1c,0x24,0x02,0x00,0x01,0xa5,0x03,0x00,0x1a, ++0x7b,0xbe,0x04,0x3c,0x7b,0xb6,0x03,0xfc,0x7b,0xb4,0x03,0xbc,0x7b,0xb2,0x03,0x7c, ++0x7b,0xb0,0x03,0x3c,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x88,0x8f,0xa4,0x00,0x98, ++0x8f,0xa5,0x00,0x38,0x8f,0xa6,0x00,0x34,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x10,0x97, ++0xaf,0xa0,0x00,0x14,0x08,0x00,0x24,0xae,0x00,0x00,0x00,0x00,0x8f,0xa3,0x00,0x44, ++0x93,0x82,0x87,0x6d,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x61,0x30,0x69,0x00,0x03, ++0x8f,0xa4,0x00,0x24,0x8f,0xa5,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x85,0x10,0x2a, ++0x10,0x40,0x00,0x8f,0x00,0x00,0x00,0x00,0x8f,0xa6,0x00,0x1c,0x00,0x00,0x00,0x00, ++0x90,0xc4,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x00,0xa3,0x10,0x2a, ++0x10,0x40,0x00,0x87,0x00,0x00,0x00,0x00,0x8f,0xa8,0x00,0x24,0x00,0x00,0x00,0x00, ++0x11,0x00,0x00,0x83,0x00,0x65,0x10,0x23,0x00,0xa8,0x18,0x23,0x00,0x62,0x10,0x2a, ++0x14,0x40,0x00,0x7d,0x30,0x63,0x00,0xff,0x00,0x85,0x10,0x23,0x30,0x42,0x00,0xff, ++0xaf,0xa2,0x00,0x50,0x8f,0xa2,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x73, ++0x00,0x00,0xa8,0x21,0x27,0x8c,0x99,0x40,0x3c,0x0b,0x80,0xff,0x24,0x10,0x00,0x04, ++0x27,0x91,0x99,0x44,0x35,0x6b,0xff,0xff,0x3c,0x0d,0x7f,0x00,0x27,0x8e,0x99,0x50, ++0x01,0x80,0x78,0x21,0x00,0x12,0x30,0xc0,0x00,0xd2,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x4c,0x10,0x21,0x94,0x42,0x00,0x06,0x8f,0xa3,0x00,0x2c,0x8f,0xa4,0x00,0x30, ++0xaf,0xa2,0x00,0x44,0x8f,0xa5,0x00,0x44,0x30,0x49,0x00,0x03,0x02,0x09,0x10,0x23, ++0x30,0x42,0x00,0x03,0x00,0xa2,0x10,0x21,0x8f,0xa8,0x00,0x30,0x24,0x42,0x00,0x04, ++0x30,0x42,0xff,0xff,0x00,0x64,0x38,0x21,0x01,0x02,0x28,0x23,0x00,0x62,0x18,0x21, ++0x00,0x48,0x10,0x2b,0x10,0x40,0x00,0x52,0x00,0x00,0x20,0x21,0x30,0xe7,0xff,0xff, ++0x30,0xa4,0xff,0xff,0xaf,0xa7,0x00,0x2c,0x00,0xd2,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x51,0x18,0x21,0x8c,0x65,0x00,0x18,0x00,0x04,0x25,0x80,0x00,0x8d,0x20,0x24, ++0x8c,0xa8,0x00,0x04,0x00,0x4e,0x18,0x21,0x00,0x4f,0x50,0x21,0x01,0x0b,0x40,0x24, ++0x01,0x04,0x40,0x25,0xac,0xa8,0x00,0x04,0x8f,0xa4,0x00,0x98,0x8f,0xa2,0x00,0x50, ++0x26,0xb5,0x00,0x01,0xa0,0x64,0x00,0x00,0x8c,0xa4,0x00,0x08,0x00,0x00,0x00,0x00, ++0x04,0x81,0x00,0x0c,0x02,0xa2,0x30,0x2a,0x80,0x62,0x00,0x06,0x00,0x00,0x00,0x00, ++0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x00,0x02,0x10,0x40,0x00,0xa2,0x38,0x21,0x8f,0xa5,0x00,0x40,0x00,0x00,0x00,0x00, ++0xa4,0xe5,0x00,0x00,0x95,0x52,0x00,0x02,0x14,0xc0,0xff,0xc7,0x00,0x12,0x30,0xc0, ++0x8f,0xa4,0x00,0x24,0x8f,0xa5,0x00,0x50,0x8f,0xa6,0x00,0x1c,0x8f,0xa3,0x00,0x2c, ++0x00,0x85,0x80,0x21,0xa0,0xd0,0x00,0x12,0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03, ++0x8f,0xa8,0x00,0x88,0x00,0x62,0x10,0x23,0xa4,0xc2,0x00,0x1a,0x85,0x03,0x00,0x0c, ++0x00,0x00,0x00,0x00,0x00,0x03,0x10,0xc0,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x80, ++0x27,0x83,0x99,0x44,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x18,0x00,0x00,0x00,0x00, ++0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10,0x14,0x60,0xff,0x74, ++0x02,0x00,0x10,0x21,0x8f,0xa3,0x00,0x54,0x8f,0xa4,0x00,0x18,0x8f,0xa5,0x00,0x24, ++0x00,0x64,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x83,0x99,0x58,0x00,0x43,0x10,0x21, ++0x90,0x44,0x00,0x00,0x10,0xa0,0x00,0x03,0x00,0x00,0x30,0x21,0x08,0x00,0x24,0xb4, ++0x02,0x00,0x10,0x21,0x93,0x82,0x80,0x10,0x00,0x00,0x28,0x21,0x00,0x00,0x38,0x21, ++0x0c,0x00,0x29,0x0b,0xaf,0xa2,0x00,0x10,0x08,0x00,0x24,0xb4,0x02,0x00,0x10,0x21, ++0x30,0x63,0xff,0xff,0x08,0x00,0x25,0x06,0xaf,0xa3,0x00,0x2c,0x8f,0xa8,0x00,0x44, ++0x08,0x00,0x25,0x28,0x31,0x09,0x00,0x03,0x08,0x00,0x24,0xe1,0xaf,0xa3,0x00,0x50, ++0x8f,0xa6,0x00,0x44,0xaf,0xa0,0x00,0x50,0x08,0x00,0x25,0x28,0x30,0xc9,0x00,0x03, ++0x8f,0xa5,0x00,0x48,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c,0x03,0xc0,0x38,0x21, ++0x0c,0x00,0x23,0x53,0xaf,0xb7,0x00,0x10,0x08,0x00,0x24,0x91,0x00,0x00,0x00,0x00, ++0x00,0x05,0x28,0x80,0x27,0x82,0x99,0x40,0x00,0xa2,0x28,0x21,0x00,0x00,0x20,0x21, ++0x0c,0x00,0x01,0x49,0x00,0x00,0x00,0x00,0x08,0x00,0x24,0x8a,0x26,0xe2,0x00,0x01, ++0x00,0x02,0x80,0x80,0x27,0x83,0x99,0x50,0x8f,0xa4,0x00,0x1c,0x02,0x03,0x18,0x21, ++0x26,0x31,0x00,0x01,0x02,0x40,0x28,0x21,0x0c,0x00,0x26,0x5b,0xa0,0x71,0x00,0x05, ++0x14,0x40,0xff,0x13,0x00,0x00,0x00,0x00,0x16,0xe0,0x00,0x4d,0x03,0xc0,0x38,0x21, ++0x8f,0xa4,0x00,0x24,0x8f,0xa5,0x00,0x20,0x24,0x02,0x00,0x01,0x24,0x84,0x00,0x01, ++0xaf,0xb2,0x00,0x48,0xaf,0xb6,0x00,0x4c,0x02,0xc0,0xf0,0x21,0x10,0xa2,0x00,0x41, ++0xaf,0xa4,0x00,0x24,0x27,0x82,0x99,0x40,0x02,0x02,0x10,0x21,0x94,0x42,0x00,0x06, ++0x8f,0xa4,0x00,0x30,0xaf,0xa0,0x00,0x20,0xaf,0xa2,0x00,0x44,0x30,0x49,0x00,0x03, ++0x8f,0xa8,0x00,0x44,0x00,0x09,0x10,0x23,0x30,0x42,0x00,0x03,0x01,0x02,0x10,0x21, ++0x24,0x42,0x00,0x04,0x30,0x42,0xff,0xff,0x00,0x44,0x18,0x2b,0x10,0x60,0x00,0x2b, ++0x00,0x00,0x00,0x00,0x8f,0xa5,0x00,0x2c,0x00,0x82,0x10,0x23,0x00,0xa4,0x18,0x21, ++0x30,0x63,0xff,0xff,0x30,0x44,0xff,0xff,0xaf,0xa3,0x00,0x2c,0x02,0x92,0x28,0x21, ++0x00,0x05,0x28,0x80,0x27,0x82,0x99,0x44,0x00,0xa2,0x10,0x21,0x8c,0x46,0x00,0x18, ++0x3c,0x03,0x80,0xff,0x3c,0x02,0x7f,0x00,0x8c,0xc8,0x00,0x04,0x00,0x04,0x25,0x80, ++0x34,0x63,0xff,0xff,0x00,0x82,0x20,0x24,0x01,0x03,0x40,0x24,0x01,0x04,0x40,0x25, ++0xac,0xc8,0x00,0x04,0x8f,0xa8,0x00,0x98,0x27,0x82,0x99,0x50,0x00,0xa2,0x10,0x21, ++0xa0,0x48,0x00,0x00,0x8c,0xc4,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x27,0xc2, ++0x10,0x80,0xfe,0xdb,0xaf,0xa4,0x00,0x3c,0x80,0x42,0x00,0x06,0x00,0x00,0x00,0x00, ++0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x00,0x02,0x10,0x40,0x00,0xc2,0x38,0x21,0x8f,0xa2,0x00,0x40,0x00,0x00,0x00,0x00, ++0xa4,0xe2,0x00,0x00,0x08,0x00,0x24,0x8d,0x26,0xb5,0xff,0xff,0x8f,0xa6,0x00,0x2c, ++0x00,0x00,0x20,0x21,0x00,0xc2,0x10,0x21,0x30,0x42,0xff,0xff,0x08,0x00,0x25,0x9b, ++0xaf,0xa2,0x00,0x2c,0x8f,0xa6,0x00,0x1c,0x08,0x00,0x25,0x85,0xa4,0xd2,0x00,0x14, ++0x8f,0xa5,0x00,0x48,0x8f,0xa6,0x00,0x4c,0x8f,0xa4,0x00,0x1c,0x0c,0x00,0x23,0x53, ++0xaf,0xb7,0x00,0x10,0x08,0x00,0x25,0x7c,0x00,0x00,0xb8,0x21,0x0c,0x00,0x1a,0x11, ++0x00,0x00,0x28,0x21,0x94,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x63,0x08,0x00, ++0xa4,0x43,0x00,0x00,0x08,0x00,0x24,0x81,0x02,0x71,0x10,0x21,0x02,0x92,0x18,0x21, ++0x00,0x03,0x80,0x80,0x27,0x82,0x99,0x44,0x02,0x02,0x10,0x21,0x8c,0x44,0x00,0x18, ++0x00,0x00,0x00,0x00,0x8c,0x83,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x10, ++0x10,0x60,0x00,0x09,0x24,0x06,0x00,0x01,0x93,0x82,0x94,0x51,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x01,0x10,0x40,0xfe,0xa3,0x3c,0x04,0x00,0x80,0x27,0x85,0x99,0x40, ++0x08,0x00,0x25,0x6c,0x02,0x05,0x28,0x21,0x27,0x83,0x99,0x58,0x27,0x82,0x99,0x50, ++0x02,0x03,0x18,0x21,0x02,0x02,0x10,0x21,0x90,0x64,0x00,0x00,0x90,0x45,0x00,0x05, ++0x93,0x83,0x80,0x10,0x00,0x00,0x38,0x21,0x0c,0x00,0x29,0x0b,0xaf,0xa3,0x00,0x10, ++0x08,0x00,0x25,0xe2,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x04,0x00,0x00,0x00,0x00, ++0x8f,0xa4,0x00,0x94,0x08,0x00,0x24,0x59,0x00,0x64,0x10,0x06,0x08,0x00,0x24,0x5a, ++0x00,0x00,0x18,0x21,0x8f,0xa4,0x00,0x98,0x8f,0xa5,0x00,0x38,0xaf,0xa0,0x00,0x10, ++0x0c,0x00,0x10,0x97,0xaf,0xa8,0x00,0x14,0x30,0x42,0xff,0xff,0x08,0x00,0x24,0x24, ++0xaf,0xa2,0x00,0x40,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe0, ++0x34,0x42,0x00,0x20,0x24,0x63,0x98,0x14,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x18,0xac,0x43,0x00,0x00,0x90,0x82,0x00,0x0a,0x00,0x80,0x80,0x21, ++0x14,0x40,0x00,0x45,0x00,0x00,0x88,0x21,0x92,0x02,0x00,0x04,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x3c,0x00,0x00,0x00,0x00,0x12,0x20,0x00,0x18,0x00,0x00,0x00,0x00, ++0x92,0x02,0x00,0x16,0x92,0x05,0x00,0x0a,0x30,0x42,0x00,0xfc,0x10,0xa0,0x00,0x03, ++0xa2,0x02,0x00,0x16,0x34,0x42,0x00,0x01,0xa2,0x02,0x00,0x16,0x92,0x04,0x00,0x04, ++0x00,0x00,0x00,0x00,0x30,0x83,0x00,0xff,0x10,0x60,0x00,0x05,0x00,0x00,0x00,0x00, ++0x92,0x02,0x00,0x16,0x00,0x00,0x00,0x00,0x34,0x42,0x00,0x02,0xa2,0x02,0x00,0x16, ++0x10,0x60,0x00,0x0a,0x00,0x00,0x00,0x00,0x14,0xa0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x96,0x02,0x00,0x00,0xa2,0x00,0x00,0x17,0xa6,0x02,0x00,0x14,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x14,0x80,0x00,0x05, ++0x24,0x02,0x00,0x01,0x96,0x03,0x00,0x06,0xa2,0x02,0x00,0x17,0x08,0x00,0x26,0x2f, ++0xa6,0x03,0x00,0x14,0x96,0x04,0x00,0x00,0x96,0x05,0x00,0x06,0x27,0x86,0x99,0x40, ++0x00,0x04,0x10,0xc0,0x00,0x05,0x18,0xc0,0x00,0x44,0x10,0x21,0x00,0x65,0x18,0x21, ++0x00,0x02,0x10,0x80,0x00,0x03,0x18,0x80,0x00,0x66,0x18,0x21,0x00,0x46,0x10,0x21, ++0x8c,0x65,0x00,0x08,0x8c,0x44,0x00,0x08,0x0c,0x00,0x1a,0x02,0x00,0x00,0x00,0x00, ++0x30,0x43,0x00,0xff,0x10,0x60,0x00,0x04,0xa2,0x02,0x00,0x17,0x96,0x02,0x00,0x06, ++0x08,0x00,0x26,0x2f,0xa6,0x02,0x00,0x14,0x96,0x02,0x00,0x00,0x08,0x00,0x26,0x2f, ++0xa6,0x02,0x00,0x14,0x96,0x05,0x00,0x00,0x0c,0x00,0x26,0x5b,0x02,0x00,0x20,0x21, ++0x08,0x00,0x26,0x16,0x02,0x22,0x88,0x21,0x94,0x85,0x00,0x06,0x0c,0x00,0x26,0x5b, ++0x00,0x00,0x00,0x00,0x08,0x00,0x26,0x12,0x00,0x40,0x88,0x21,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0x99,0x6c,0x27,0xbd,0xff,0xf0, ++0xac,0x62,0x00,0x00,0x00,0x00,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x10, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0x99,0x90, ++0xac,0x62,0x00,0x00,0x90,0x89,0x00,0x0a,0x00,0x80,0x30,0x21,0x11,0x20,0x00,0x05, ++0x00,0xa0,0x50,0x21,0x90,0x82,0x00,0x17,0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1b, ++0x00,0x00,0x00,0x00,0x90,0xc7,0x00,0x04,0x00,0x00,0x00,0x00,0x10,0xe0,0x00,0x1b, ++0x00,0x00,0x00,0x00,0x94,0xc8,0x00,0x00,0x27,0x83,0x99,0x40,0x93,0x85,0x94,0x50, ++0x00,0x08,0x10,0xc0,0x00,0x48,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21, ++0x8c,0x44,0x00,0x08,0x00,0xe5,0x28,0x2b,0x10,0xa0,0x00,0x06,0x01,0x44,0x18,0x23, ++0x8f,0x82,0x94,0x68,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x2b,0x10,0x40,0x00,0x05, ++0x00,0x00,0x00,0x00,0x24,0x03,0x00,0x10,0xa4,0xc8,0x00,0x14,0x03,0xe0,0x00,0x08, ++0x00,0x60,0x10,0x21,0x11,0x20,0x00,0x05,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x06, ++0x24,0x03,0x00,0x08,0x08,0x00,0x26,0x87,0xa4,0xc2,0x00,0x14,0x08,0x00,0x26,0x87, ++0x00,0x00,0x18,0x21,0x27,0xbd,0xff,0xc8,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28, ++0xaf,0xb3,0x00,0x24,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x30,0xaf,0xb2,0x00,0x20, ++0xaf,0xb1,0x00,0x1c,0x94,0x91,0x00,0x06,0x00,0x80,0xa0,0x21,0x3c,0x02,0x80,0x01, ++0x3c,0x04,0xb0,0x03,0x00,0x11,0xa8,0xc0,0x34,0x84,0x00,0x20,0x24,0x42,0x9a,0x44, ++0x02,0xb1,0x48,0x21,0xac,0x82,0x00,0x00,0x00,0x09,0x48,0x80,0x24,0x03,0x00,0x01, ++0x27,0x82,0x99,0x50,0xa2,0x83,0x00,0x12,0x01,0x22,0x10,0x21,0x27,0x84,0x99,0x44, ++0x01,0x24,0x20,0x21,0x80,0x48,0x00,0x06,0x8c,0x8a,0x00,0x18,0x27,0x83,0x99,0x60, ++0x01,0x23,0x48,0x21,0x8d,0x24,0x00,0x00,0x25,0x08,0x00,0x02,0x8d,0x42,0x00,0x00, ++0x8d,0x49,0x00,0x04,0x00,0x08,0x17,0xc2,0x8d,0x43,0x00,0x08,0x01,0x02,0x40,0x21, ++0x00,0x04,0x25,0xc2,0x00,0x08,0x40,0x43,0x30,0x84,0x00,0x01,0x00,0x03,0x1f,0xc2, ++0x00,0x08,0x40,0x40,0x00,0xe0,0x80,0x21,0x00,0x64,0x18,0x24,0x00,0x09,0x49,0x42, ++0x01,0x48,0x10,0x21,0x00,0xa0,0x98,0x21,0x00,0xa0,0x20,0x21,0x00,0x40,0x38,0x21, ++0x02,0x00,0x28,0x21,0x14,0x60,0x00,0x19,0x31,0x29,0x00,0x01,0x94,0x42,0x00,0x00, ++0x02,0xb1,0x88,0x21,0x02,0x00,0x28,0x21,0x00,0x11,0x88,0x80,0x27,0x90,0x99,0x40, ++0x02,0x30,0x80,0x21,0x96,0x03,0x00,0x06,0x30,0x52,0xff,0xff,0x02,0x60,0x20,0x21, ++0x00,0x60,0x30,0x21,0xa6,0x83,0x00,0x1a,0x27,0x82,0x99,0x48,0x0c,0x00,0x10,0x70, ++0x02,0x22,0x88,0x21,0x00,0x52,0x10,0x21,0x96,0x03,0x00,0x06,0xa6,0x22,0x00,0x04, ++0x8f,0xbf,0x00,0x30,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc, ++0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x38,0xaf,0xa9,0x00,0x10, ++0x0c,0x00,0x10,0x97,0xaf,0xa0,0x00,0x14,0x08,0x00,0x26,0xc5,0x02,0xb1,0x88,0x21, ++0x27,0xbd,0xff,0xc0,0xaf,0xbe,0x00,0x38,0xaf,0xb7,0x00,0x34,0xaf,0xb6,0x00,0x30, ++0xaf,0xb5,0x00,0x2c,0xaf,0xb3,0x00,0x24,0xaf,0xb1,0x00,0x1c,0xaf,0xbf,0x00,0x3c, ++0xaf,0xb4,0x00,0x28,0xaf,0xb2,0x00,0x20,0xaf,0xb0,0x00,0x18,0x94,0x90,0x00,0x00, ++0x3c,0x08,0xb0,0x03,0x35,0x08,0x00,0x20,0x00,0x10,0x10,0xc0,0x00,0x50,0x18,0x21, ++0x00,0x40,0x88,0x21,0x3c,0x02,0x80,0x01,0x00,0x03,0x48,0x80,0x24,0x42,0x9b,0x80, ++0x00,0x80,0x98,0x21,0x27,0x84,0x99,0x50,0x01,0x24,0x20,0x21,0x93,0xb7,0x00,0x53, ++0xad,0x02,0x00,0x00,0x80,0x83,0x00,0x06,0x27,0x82,0x99,0x44,0x01,0x22,0x10,0x21, ++0x8c,0x44,0x00,0x18,0x24,0x63,0x00,0x02,0x00,0x03,0x17,0xc2,0x8c,0x88,0x00,0x08, ++0x00,0x62,0x18,0x21,0x00,0x03,0x18,0x43,0x00,0x03,0x18,0x40,0xaf,0xa7,0x00,0x4c, ++0x2c,0xa2,0x00,0x10,0x00,0xa0,0xa8,0x21,0x00,0x83,0x50,0x21,0x00,0x08,0x47,0xc2, ++0x00,0xc0,0x58,0x21,0x00,0x00,0xb0,0x21,0x8c,0x92,0x00,0x0c,0x14,0x40,0x00,0x13, ++0x00,0x00,0xf0,0x21,0x92,0x67,0x00,0x04,0x24,0x14,0x00,0x01,0x12,0x87,0x00,0x10, ++0x02,0x30,0x10,0x21,0x27,0x83,0x99,0x58,0x01,0x23,0x18,0x21,0x80,0x64,0x00,0x00, ++0x27,0x83,0xbe,0xb0,0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80, ++0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x04, ++0x00,0x00,0x00,0x00,0x10,0x80,0x00,0x23,0x00,0x00,0x00,0x00,0x02,0x30,0x10,0x21, ++0x00,0x02,0x80,0x80,0x24,0x04,0x00,0x01,0x27,0x83,0x99,0x60,0xa2,0x64,0x00,0x12, ++0x02,0x03,0x18,0x21,0x8c,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x15,0xc2, ++0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24,0x14,0x40,0x00,0x0e,0x02,0xa0,0x20,0x21, ++0x27,0x82,0x99,0x40,0x02,0x02,0x10,0x21,0x94,0x43,0x00,0x06,0x00,0x00,0x00,0x00, ++0xa6,0x63,0x00,0x1a,0x94,0x42,0x00,0x06,0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc, ++0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c,0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x40,0x8f,0xa5,0x00,0x4c,0x01,0x60,0x30,0x21,0x01,0x40,0x38,0x21, ++0xaf,0xa0,0x00,0x10,0x0c,0x00,0x10,0x97,0xaf,0xa0,0x00,0x14,0x08,0x00,0x27,0x2c, ++0x00,0x00,0x00,0x00,0x27,0x83,0x99,0x60,0x01,0x23,0x18,0x21,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x02,0x15,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24, ++0x14,0x40,0x00,0xaf,0x00,0xa0,0x20,0x21,0x32,0x4f,0x00,0x03,0x00,0x12,0x10,0x82, ++0x25,0xe3,0x00,0x0d,0x30,0x45,0x00,0x07,0x00,0x74,0x78,0x04,0x10,0xa0,0x00,0x0e, ++0x00,0x00,0x90,0x21,0x27,0x82,0x86,0x30,0x00,0x15,0x18,0x40,0x00,0x62,0x18,0x21, ++0x94,0x64,0x00,0x00,0x24,0xa2,0x00,0x05,0x00,0x54,0x10,0x04,0x00,0x44,0x00,0x1a, ++0x14,0x80,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d,0x00,0x00,0x10,0x12, ++0x24,0x42,0x00,0x10,0x30,0x52,0xff,0xfc,0x02,0x30,0x10,0x21,0x27,0x83,0x99,0x50, ++0x00,0x02,0x10,0x80,0x00,0x43,0x10,0x21,0x90,0x44,0x00,0x03,0x00,0x00,0x00,0x00, ++0x30,0x83,0x00,0xff,0x2c,0x62,0x00,0x0c,0x14,0x40,0x00,0x04,0x2c,0x62,0x00,0x19, ++0x30,0x82,0x00,0x0f,0x24,0x43,0x00,0x0c,0x2c,0x62,0x00,0x19,0x10,0x40,0x00,0x19, ++0x24,0x0e,0x00,0x20,0x24,0x62,0xff,0xe9,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x15, ++0x24,0x0e,0x00,0x10,0x24,0x62,0xff,0xeb,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x11, ++0x24,0x0e,0x00,0x08,0x24,0x02,0x00,0x14,0x10,0x62,0x00,0x0e,0x24,0x0e,0x00,0x02, ++0x24,0x62,0xff,0xef,0x2c,0x42,0x00,0x03,0x14,0x40,0x00,0x0a,0x24,0x0e,0x00,0x10, ++0x24,0x62,0xff,0xf1,0x2c,0x42,0x00,0x02,0x14,0x40,0x00,0x06,0x24,0x0e,0x00,0x08, ++0x24,0x62,0xff,0xf3,0x2c,0x42,0x00,0x02,0x24,0x0e,0x00,0x04,0x24,0x03,0x00,0x02, ++0x00,0x62,0x70,0x0a,0x30,0xe2,0x00,0xff,0x00,0x00,0x48,0x21,0x00,0x00,0x68,0x21, ++0x10,0x40,0x00,0x6d,0x00,0x00,0x58,0x21,0x3c,0x14,0x80,0xff,0x27,0x99,0x99,0x40, ++0x01,0xf2,0xc0,0x23,0x36,0x94,0xff,0xff,0x01,0xc9,0x10,0x2a,0x14,0x40,0x00,0x64, ++0x24,0x03,0x00,0x04,0x00,0x10,0x28,0xc0,0x00,0xb0,0x10,0x21,0x00,0x02,0x10,0x80, ++0x00,0x59,0x10,0x21,0x94,0x56,0x00,0x06,0x00,0x00,0x00,0x00,0x32,0xcc,0x00,0x03, ++0x00,0x6c,0x10,0x23,0x30,0x42,0x00,0x03,0x02,0xc2,0x10,0x21,0x24,0x42,0x00,0x04, ++0x30,0x51,0xff,0xff,0x02,0x32,0x18,0x2b,0x10,0x60,0x00,0x4d,0x01,0xf1,0x10,0x23, ++0x02,0x51,0x10,0x23,0x01,0x78,0x18,0x2b,0x10,0x60,0x00,0x34,0x30,0x44,0xff,0xff, ++0x29,0x22,0x00,0x40,0x10,0x40,0x00,0x31,0x01,0x72,0x18,0x21,0x25,0x22,0x00,0x01, ++0x00,0x02,0x16,0x00,0x00,0x02,0x4e,0x03,0x00,0xb0,0x10,0x21,0x00,0x02,0x30,0x80, ++0x27,0x82,0x99,0x44,0x30,0x6b,0xff,0xff,0x00,0xc2,0x18,0x21,0x8c,0x67,0x00,0x18, ++0x00,0x04,0x25,0x80,0x3c,0x03,0x7f,0x00,0x8c,0xe2,0x00,0x04,0x00,0x83,0x20,0x24, ++0x27,0x83,0x99,0x50,0x00,0x54,0x10,0x24,0x00,0xc3,0x28,0x21,0x00,0x44,0x10,0x25, ++0xac,0xe2,0x00,0x04,0x16,0xe0,0x00,0x02,0xa0,0xb5,0x00,0x00,0xa0,0xb5,0x00,0x03, ++0x27,0x84,0x99,0x60,0x00,0xc4,0x18,0x21,0x8c,0x62,0x00,0x00,0x8c,0xe8,0x00,0x08, ++0x00,0x02,0x15,0xc2,0x00,0x08,0x47,0xc2,0x30,0x42,0x00,0x01,0x01,0x02,0x10,0x24, ++0x10,0x40,0x00,0x0a,0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x06,0x00,0x00,0x00,0x00, ++0x24,0x42,0x00,0x02,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x00,0x02,0x10,0x40,0x00,0xe2,0x50,0x21,0xa5,0x5e,0x00,0x00,0x92,0x62,0x00,0x04, ++0x25,0xad,0x00,0x01,0x27,0x84,0x99,0x40,0x00,0xc4,0x18,0x21,0x01,0xa2,0x10,0x2a, ++0x94,0x70,0x00,0x02,0x14,0x40,0xff,0xb8,0x00,0x00,0x00,0x00,0x96,0x63,0x00,0x14, ++0x00,0x0c,0x10,0x23,0xa2,0x69,0x00,0x12,0x30,0x42,0x00,0x03,0x01,0x62,0x10,0x23, ++0x00,0x03,0x80,0xc0,0x8f,0xa5,0x00,0x4c,0x30,0x4b,0xff,0xff,0x02,0x03,0x80,0x21, ++0x27,0x82,0x99,0x48,0x00,0x10,0x80,0x80,0xa6,0x6b,0x00,0x1a,0x02,0xa0,0x20,0x21, ++0x01,0x60,0x30,0x21,0x01,0x60,0x88,0x21,0x0c,0x00,0x10,0x70,0x02,0x02,0x80,0x21, ++0x00,0x5e,0x10,0x21,0xa6,0x02,0x00,0x04,0x08,0x00,0x27,0x32,0x02,0x20,0x10,0x21, ++0x01,0x62,0x10,0x2b,0x10,0x40,0xff,0xe9,0x00,0x00,0x20,0x21,0x29,0x22,0x00,0x40, ++0x10,0x40,0xff,0xe6,0x01,0x71,0x18,0x21,0x08,0x00,0x27,0xa8,0x25,0x22,0x00,0x01, ++0x08,0x00,0x27,0xd7,0x32,0xcc,0x00,0x03,0x08,0x00,0x27,0xd7,0x00,0x00,0x60,0x21, ++0x8f,0xa5,0x00,0x4c,0x01,0x40,0x38,0x21,0xaf,0xa0,0x00,0x10,0x0c,0x00,0x10,0x97, ++0xaf,0xb4,0x00,0x14,0x92,0x67,0x00,0x04,0x08,0x00,0x27,0x4a,0x30,0x5e,0xff,0xff, ++0x30,0x84,0xff,0xff,0x00,0x04,0x30,0xc0,0x00,0xc4,0x20,0x21,0x00,0x04,0x20,0x80, ++0x27,0x82,0x99,0x40,0x3c,0x03,0xb0,0x08,0x30,0xa5,0xff,0xff,0x00,0x82,0x20,0x21, ++0x00,0xc3,0x30,0x21,0xac,0xc5,0x00,0x00,0x03,0xe0,0x00,0x08,0xa4,0x85,0x00,0x00, ++0x30,0x84,0xff,0xff,0x00,0x04,0x30,0xc0,0x00,0xc4,0x30,0x21,0x27,0x88,0x99,0x40, ++0x00,0x06,0x30,0x80,0x00,0xc8,0x30,0x21,0x94,0xc3,0x00,0x04,0x3c,0x02,0xb0,0x08, ++0x3c,0x07,0xb0,0x03,0x00,0x03,0x20,0xc0,0x00,0x83,0x18,0x21,0x00,0x03,0x18,0x80, ++0x00,0x82,0x20,0x21,0x3c,0x02,0x80,0x01,0x30,0xa5,0xff,0xff,0x00,0x68,0x18,0x21, ++0x34,0xe7,0x00,0x20,0x24,0x42,0xa0,0x30,0xac,0xe2,0x00,0x00,0xa4,0xc5,0x00,0x02, ++0xa4,0x65,0x00,0x00,0x03,0xe0,0x00,0x08,0xac,0x85,0x00,0x00,0x30,0x84,0xff,0xff, ++0x00,0x04,0x10,0xc0,0x00,0x44,0x10,0x21,0x27,0x89,0x99,0x40,0x00,0x02,0x10,0x80, ++0x00,0x49,0x10,0x21,0x97,0x83,0x99,0x30,0x94,0x4a,0x00,0x04,0x3c,0x02,0xb0,0x08, ++0x00,0x03,0x38,0xc0,0x00,0x0a,0x40,0xc0,0x00,0xe3,0x18,0x21,0x01,0x0a,0x28,0x21, ++0x00,0xe2,0x38,0x21,0x01,0x02,0x40,0x21,0x00,0x03,0x18,0x80,0x00,0x05,0x28,0x80, ++0x3c,0x06,0xb0,0x03,0x3c,0x02,0x80,0x01,0x00,0xa9,0x28,0x21,0x00,0x69,0x18,0x21, ++0x34,0xc6,0x00,0x20,0x34,0x09,0xff,0xff,0x24,0x42,0xa0,0x8c,0xac,0xc2,0x00,0x00, ++0xa4,0x64,0x00,0x00,0xac,0xe4,0x00,0x00,0xa4,0xa9,0x00,0x00,0xad,0x09,0x00,0x00, ++0xa7,0x8a,0x99,0x30,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0xa1,0x0c,0x3c,0x04,0xb0,0x03, ++0xac,0x62,0x00,0x00,0x34,0x84,0x01,0x10,0x8c,0x82,0x00,0x00,0x97,0x83,0x87,0x74, ++0x30,0x42,0xff,0xff,0x10,0x62,0x00,0x16,0x24,0x0a,0x00,0x01,0xa7,0x82,0x87,0x74, ++0xaf,0x80,0xbd,0x90,0x00,0x40,0x28,0x21,0x24,0x06,0x00,0x01,0x27,0x84,0xbd,0x94, ++0x25,0x43,0xff,0xff,0x00,0x66,0x10,0x04,0x00,0xa2,0x10,0x24,0x14,0x40,0x00,0x07, ++0x00,0x00,0x00,0x00,0x8c,0x83,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x66,0x10,0x04, ++0x00,0xa2,0x10,0x24,0x38,0x42,0x00,0x00,0x01,0x42,0x18,0x0a,0x25,0x4a,0x00,0x01, ++0x2d,0x42,0x00,0x14,0xac,0x83,0x00,0x00,0x14,0x40,0xff,0xf1,0x24,0x84,0x00,0x04, ++0x3c,0x0b,0xb0,0x03,0x00,0x00,0x50,0x21,0x3c,0x0c,0x80,0x00,0x27,0x89,0xbd,0xe0, ++0x35,0x6b,0x01,0x20,0x8d,0x68,0x00,0x00,0x8d,0x23,0x00,0x04,0x01,0x0c,0x10,0x24, ++0x00,0x02,0x17,0xc2,0x11,0x03,0x00,0x37,0xa1,0x22,0x00,0xdc,0xa1,0x20,0x00,0xd5, ++0xa1,0x20,0x00,0xd6,0x01,0x20,0x30,0x21,0x00,0x00,0x38,0x21,0x00,0x00,0x28,0x21, ++0x01,0x20,0x20,0x21,0x00,0xa8,0x10,0x06,0x30,0x42,0x00,0x01,0x10,0xe0,0x00,0x10, ++0xa0,0x82,0x00,0x0a,0x90,0x82,0x00,0x07,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x31, ++0x24,0xa2,0xff,0xff,0xa0,0x82,0x00,0x08,0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x90,0x83,0x00,0x08,0x00,0x00,0x00,0x00, ++0x00,0x03,0x10,0x40,0x00,0x43,0x10,0x21,0x00,0x46,0x10,0x21,0xa0,0x45,0x00,0x09, ++0x90,0x82,0x00,0x0a,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x07,0x00,0x00,0x00,0x00, ++0x14,0xe0,0x00,0x04,0x00,0x00,0x00,0x00,0xa0,0xc5,0x00,0xd5,0x24,0x07,0x00,0x01, ++0xa0,0x85,0x00,0x08,0xa0,0xc5,0x00,0xd6,0x24,0xa5,0x00,0x01,0x2c,0xa2,0x00,0x1c, ++0x14,0x40,0xff,0xe0,0x24,0x84,0x00,0x03,0x90,0xc4,0x00,0xd5,0x00,0x00,0x28,0x21, ++0x00,0xa4,0x10,0x2b,0x10,0x40,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0xc0,0x18,0x21, ++0xa0,0x64,0x00,0x08,0x90,0xc2,0x00,0xd5,0x24,0xa5,0x00,0x01,0xa0,0x62,0x00,0x09, ++0x90,0xc4,0x00,0xd5,0x00,0x00,0x00,0x00,0x00,0xa4,0x10,0x2b,0x14,0x40,0xff,0xf8, ++0x24,0x63,0x00,0x03,0x25,0x4a,0x00,0x01,0x2d,0x42,0x00,0x08,0xad,0x28,0x00,0x04, ++0x25,0x6b,0x00,0x04,0x14,0x40,0xff,0xbf,0x25,0x29,0x00,0xec,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x90,0x82,0x00,0x05,0x08,0x00,0x28,0x7e,0xa0,0x82,0x00,0x08, ++0x97,0x85,0x94,0x5a,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0xe8, ++0x34,0x63,0x00,0x20,0x24,0x42,0xa2,0xc0,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, ++0xac,0x62,0x00,0x00,0x30,0x90,0x00,0xff,0x00,0x05,0x28,0x42,0x00,0x00,0x48,0x21, ++0x27,0x8f,0xbd,0xe4,0x00,0x00,0x50,0x21,0x00,0x00,0x58,0x21,0x27,0x98,0xbe,0xc4, ++0x27,0x99,0xbe,0xc0,0x27,0x8e,0xbe,0xbe,0x27,0x8c,0xbd,0xe8,0x27,0x8d,0xbe,0x40, ++0x27,0x88,0xbe,0xb8,0x00,0x0a,0x18,0x80,0x01,0x6f,0x10,0x21,0xac,0x40,0x00,0x00, ++0xac,0x45,0x00,0x58,0x00,0x6e,0x20,0x21,0x00,0x78,0x10,0x21,0xa1,0x00,0xff,0xfc, ++0xad,0x00,0x00,0x00,0xa1,0x00,0x00,0x04,0xa1,0x00,0x00,0x05,0xad,0x00,0xff,0xf8, ++0x00,0x79,0x18,0x21,0x24,0x06,0x00,0x01,0x24,0xc6,0xff,0xff,0xa0,0x80,0x00,0x00, ++0xa4,0x60,0x00,0x00,0xac,0x40,0x00,0x00,0x24,0x63,0x00,0x02,0x24,0x42,0x00,0x04, ++0x04,0xc1,0xff,0xf9,0x24,0x84,0x00,0x01,0x00,0x0a,0x10,0x80,0x00,0x4d,0x20,0x21, ++0x00,0x00,0x30,0x21,0x00,0x4c,0x18,0x21,0x27,0x87,0x87,0x78,0x8c,0xe2,0x00,0x00, ++0x24,0xe7,0x00,0x04,0xac,0x82,0x00,0x00,0xa0,0x66,0x00,0x00,0xa0,0x66,0x00,0x01, ++0x24,0xc6,0x00,0x01,0x28,0xc2,0x00,0x1c,0xa0,0x60,0x00,0x02,0x24,0x84,0x00,0x04, ++0x14,0x40,0xff,0xf6,0x24,0x63,0x00,0x03,0x25,0x29,0x00,0x01,0x29,0x22,0x00,0x08, ++0x25,0x4a,0x00,0x3b,0x25,0x08,0x00,0xec,0x14,0x40,0xff,0xd6,0x25,0x6b,0x00,0xec, ++0xa7,0x80,0x87,0x74,0x00,0x00,0x48,0x21,0x27,0x83,0xbd,0x90,0xac,0x69,0x00,0x00, ++0x25,0x29,0x00,0x01,0x29,0x22,0x00,0x0c,0x14,0x40,0xff,0xfc,0x24,0x63,0x00,0x04, ++0x0c,0x00,0x28,0x43,0x00,0x00,0x00,0x00,0x2e,0x04,0x00,0x14,0x27,0x83,0xbd,0xe0, ++0x24,0x09,0x00,0x07,0x10,0x80,0x00,0x0a,0x00,0x00,0x00,0x00,0x90,0x62,0x00,0xd5, ++0x25,0x29,0xff,0xff,0xa0,0x62,0x00,0x00,0x05,0x21,0xff,0xfa,0x24,0x63,0x00,0xec, ++0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x90,0x62,0x00,0xd6,0x08,0x00,0x29,0x01,0x25,0x29,0xff,0xff,0x30,0x84,0x00,0xff, ++0x00,0x04,0x11,0x00,0x00,0x44,0x10,0x23,0x00,0x02,0x10,0x80,0x00,0x44,0x10,0x23, ++0x00,0x02,0x10,0x80,0x27,0x83,0xbd,0xe0,0x00,0x43,0x60,0x21,0x3c,0x04,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x34,0x84,0x00,0x20,0x24,0x42,0xa4,0x2c,0x30,0xc6,0x00,0xff, ++0x93,0xaa,0x00,0x13,0x30,0xa5,0x00,0xff,0x30,0xe7,0x00,0xff,0xac,0x82,0x00,0x00, ++0x10,0xc0,0x00,0xb8,0x25,0x8f,0x00,0xd0,0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x24,0x42,0xff,0xfc,0x2c,0x43,0x00,0x18,0x10,0x60,0x00,0x9b,0x3c,0x03,0x80,0x01, ++0x00,0x02,0x10,0x80,0x24,0x63,0x09,0x3c,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2c, ++0x14,0x40,0x00,0x1c,0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x17,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x11,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0x00,0x0c,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x06, ++0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xe0, ++0x03,0xe0,0x00,0x08,0xad,0x82,0x00,0xd0,0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c, ++0x24,0x42,0xff,0xe8,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x29,0x3c,0x24,0x42,0x00,0x01,0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c, ++0x24,0x42,0x00,0x02,0x10,0xa0,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0xec,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe9, ++0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c,0x24,0x42,0xff,0xd0, ++0x10,0xa0,0xff,0xf1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xeb, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xe6,0x24,0x02,0x00,0x03, ++0x14,0xa2,0xff,0xe1,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c, ++0x24,0x42,0xff,0xf8,0x2d,0x42,0x00,0x24,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xe1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xdb, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xd6,0x24,0x02,0x00,0x03, ++0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c, ++0x24,0x42,0xff,0xf0,0x10,0xa0,0xff,0xd1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0xcc,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xf7,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xd7,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x39, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x24,0x10,0x40,0xff,0xe5,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xc2,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x14,0xa2,0xff,0xca, ++0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x5e,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x29, ++0x10,0x40,0xff,0xdb,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x49,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x24,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xb6, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xb0,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xab,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xc6, ++0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c,0x24,0x42,0xff,0xfa, ++0x10,0xa0,0xff,0xa9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xa1, ++0x24,0x02,0x00,0x02,0x14,0xa2,0xff,0x94,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x5e, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x24,0x10,0x40,0xff,0xe8,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0x9a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x95, ++0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x90,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x51, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2c,0x14,0x40,0xff,0xcd,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0x91,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x8b, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x86,0x00,0x00,0x00,0x00, ++0x08,0x00,0x29,0x5e,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x87,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x81,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0x7c,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x97,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x29,0x3c,0x24,0x42,0xff,0xfc,0x2d,0x42,0x00,0x24, ++0x14,0x40,0xff,0xa4,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x54,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x24,0x14,0x40,0xff,0x9f,0x00,0x00,0x00,0x00,0x08,0x00,0x29,0x2e, ++0x00,0x00,0x00,0x00,0x91,0x86,0x00,0x00,0x91,0x83,0x00,0xd4,0x25,0x8d,0x00,0x5c, ++0x30,0xc4,0x00,0xff,0x00,0x04,0x10,0x40,0x00,0x44,0x10,0x21,0x00,0x04,0x48,0x80, ++0x01,0x82,0x58,0x21,0x01,0x89,0x40,0x21,0x25,0x78,0x00,0x08,0x10,0x60,0x00,0x36, ++0x25,0x0e,0x00,0x60,0x10,0xa0,0x00,0x25,0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd, ++0x00,0x00,0x00,0x00,0x14,0x40,0x00,0x1e,0x00,0x00,0x00,0x00,0x27,0x87,0x87,0x78, ++0x01,0x27,0x10,0x21,0x8c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x03,0x00,0x60, ++0x91,0x62,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x40,0x30,0x21,0xa1,0x82,0x00,0x00, ++0x30,0xc2,0x00,0xff,0x00,0x02,0x10,0x80,0x00,0x47,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x42,0xad,0xa3,0x00,0x00,0x91,0x84,0x00,0x00, ++0x8d,0xc5,0x00,0x00,0x00,0x04,0x20,0x80,0x00,0x87,0x10,0x21,0x8c,0x43,0x00,0x00, ++0x00,0x05,0x28,0x40,0x00,0x8c,0x20,0x21,0x00,0x03,0x1a,0x80,0x00,0xa3,0x10,0x2b, ++0x00,0x62,0x28,0x0a,0xac,0x85,0x00,0x60,0x03,0xe0,0x00,0x08,0xa1,0x80,0x00,0xd4, ++0x27,0x87,0x87,0x78,0x08,0x00,0x29,0xf0,0xa1,0x80,0x00,0xdd,0x27,0x82,0x87,0xe8, ++0x8d,0x83,0x00,0xd8,0x00,0x82,0x10,0x21,0x90,0x44,0x00,0x00,0x24,0x63,0x00,0x01, ++0x00,0x64,0x20,0x2b,0x14,0x80,0xff,0x33,0xad,0x83,0x00,0xd8,0x8d,0x02,0x00,0x60, ++0xa1,0x80,0x00,0xd4,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x03,0xe0,0x00,0x08,0xad,0x82,0x00,0x5c,0x10,0xe0,0x00,0x1d,0x24,0x83,0xff,0xfc, ++0x2c,0x62,0x00,0x18,0x10,0x40,0x00,0xe4,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01, ++0x24,0x63,0x09,0x9c,0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2c,0x14,0x40,0x00,0x65, ++0x00,0x00,0x00,0x00,0x10,0xa0,0x00,0x60,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0x00,0x5a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x08, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x51,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x00,0x00,0x00,0x00,0x24,0x42,0xff,0xe0,0xad,0x82,0x00,0xd0, ++0x8d,0xe3,0x00,0x00,0x8d,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x21, ++0xad,0xa2,0x00,0x00,0xad,0xe0,0x00,0x00,0x8d,0xa3,0x00,0x00,0x8d,0xc4,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x83,0x10,0x2a,0x10,0x40,0x00,0x22,0x00,0x00,0x00,0x00, ++0x93,0x05,0x00,0x01,0x91,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x45,0x00,0x05, ++0x24,0x02,0x00,0x01,0xa1,0x85,0x00,0x00,0xa1,0x82,0x00,0xd4,0x03,0xe0,0x00,0x08, ++0xad,0x80,0x00,0xd8,0x91,0x82,0x00,0xdd,0x24,0x03,0x00,0x01,0x10,0x43,0x00,0x05, ++0x00,0x00,0x00,0x00,0xa1,0x83,0x00,0xd4,0xad,0x80,0x00,0xd8,0x03,0xe0,0x00,0x08, ++0xa1,0x83,0x00,0xdd,0x00,0x04,0x17,0xc2,0x00,0x82,0x10,0x21,0x00,0x02,0x10,0x43, ++0xad,0xa2,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x87,0x78,0x8d,0xc5,0x00,0x00, ++0x00,0x03,0x18,0x80,0x00,0x62,0x18,0x21,0x8c,0x64,0x00,0x00,0x00,0x05,0x28,0x40, ++0x00,0x04,0x1a,0x80,0x00,0xa3,0x10,0x2b,0x00,0x62,0x28,0x0a,0x08,0x00,0x2a,0x02, ++0xad,0xc5,0x00,0x00,0x97,0x82,0x94,0x5c,0x00,0x00,0x00,0x00,0x00,0x62,0x10,0x2a, ++0x10,0x40,0xfe,0xdc,0x00,0x00,0x00,0x00,0x91,0x82,0x00,0xdd,0x00,0x00,0x00,0x00, ++0x14,0x40,0x00,0x15,0x00,0x00,0x00,0x00,0x91,0x83,0x00,0x00,0x27,0x82,0x87,0x78, ++0x00,0x03,0x18,0x80,0x00,0x62,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x6c,0x18,0x21, ++0xac,0x64,0x00,0x60,0x93,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x10,0x80, ++0x01,0x82,0x10,0x21,0x24,0x4e,0x00,0x60,0xa1,0x85,0x00,0x00,0x8d,0xc2,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x02,0x1f,0xc2,0x00,0x43,0x10,0x21,0x00,0x02,0x10,0x43, ++0x03,0xe0,0x00,0x08,0xad,0xa2,0x00,0x00,0x08,0x00,0x2a,0x77,0xa1,0x80,0x00,0xdd, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33,0x24,0x42,0xff,0xe8,0x8d,0x82,0x00,0xd0, ++0x08,0x00,0x2a,0x33,0x24,0x42,0x00,0x01,0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33, ++0x24,0x42,0x00,0x02,0x10,0xa0,0xff,0xf9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0xa3,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xa0, ++0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33,0x24,0x42,0xff,0xd0, ++0x10,0xa0,0xff,0xf1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xeb, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x99,0x24,0x02,0x00,0x03, ++0x14,0xa2,0xff,0xe3,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33, ++0x24,0x42,0xff,0xf8,0x2d,0x42,0x00,0x24,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xe1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xdb, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x89,0x24,0x02,0x00,0x03, ++0x10,0xa2,0xff,0xf1,0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33, ++0x24,0x42,0xff,0xf0,0x10,0xa0,0xff,0xd1,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01, ++0x10,0xa2,0xff,0x7f,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0xf7,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xd7,0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x30, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x24,0x10,0x40,0xff,0xe5,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0xc2,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x14,0xa2,0xff,0xca, ++0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x9e,0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x29, ++0x10,0x40,0xff,0xdb,0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x89,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x24,0x14,0x40,0x00,0x0e,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0xb6, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0xb0,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x5e,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0xc6, ++0x00,0x00,0x00,0x00,0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33,0x24,0x42,0xff,0xfa, ++0x10,0xa0,0xff,0xa9,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x54, ++0x24,0x02,0x00,0x02,0x14,0xa2,0xff,0x4b,0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x9e, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x24,0x10,0x40,0xff,0xe8,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0x9a,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x48, ++0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x92,0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x91, ++0x00,0x00,0x00,0x00,0x2d,0x42,0x00,0x2c,0x14,0x40,0xff,0xcd,0x00,0x00,0x00,0x00, ++0x10,0xa0,0xff,0x91,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x8b, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x10,0xa2,0xff,0x39,0x00,0x00,0x00,0x00, ++0x08,0x00,0x2a,0x9e,0x00,0x00,0x00,0x00,0x10,0xa0,0xff,0x87,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0x10,0xa2,0xff,0x81,0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02, ++0x10,0xa2,0xff,0x2f,0x24,0x02,0x00,0x03,0x14,0xa2,0xff,0x97,0x00,0x00,0x00,0x00, ++0x8d,0x82,0x00,0xd0,0x08,0x00,0x2a,0x33,0x24,0x42,0xff,0xfc,0x2d,0x42,0x00,0x24, ++0x14,0x40,0xff,0xa4,0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x94,0x00,0x00,0x00,0x00, ++0x2d,0x42,0x00,0x24,0x14,0x40,0xff,0x9f,0x00,0x00,0x00,0x00,0x08,0x00,0x2a,0x25, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8,0x3c,0x02,0xb0,0x03,0xaf,0xbf,0x00,0x14, ++0xaf,0xb0,0x00,0x10,0x34,0x42,0x01,0x18,0x3c,0x03,0xb0,0x03,0x8c,0x50,0x00,0x00, ++0x34,0x63,0x01,0x2c,0x90,0x62,0x00,0x00,0x32,0x05,0x00,0x01,0xa3,0x82,0x80,0x10, ++0x14,0xa0,0x00,0x14,0x30,0x44,0x00,0xff,0x32,0x02,0x01,0x00,0x14,0x40,0x00,0x09, ++0x00,0x00,0x00,0x00,0x32,0x02,0x08,0x00,0x10,0x40,0x00,0x02,0x24,0x02,0x00,0x01, ++0xa3,0x82,0xc5,0x58,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x0c,0x00,0x0b,0x3e,0x00,0x00,0x00,0x00,0x26,0x02,0xff,0x00, ++0xa3,0x80,0xc5,0x58,0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x2b,0x26, ++0x32,0x02,0x08,0x00,0x0c,0x00,0x28,0xb0,0x00,0x00,0x00,0x00,0x26,0x02,0xff,0xff, ++0x3c,0x01,0xb0,0x03,0xac,0x22,0x01,0x18,0x08,0x00,0x2b,0x23,0x32,0x02,0x01,0x00, ++0x27,0xbd,0xff,0xe0,0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xd0,0xaf,0xbf,0x00,0x18, ++0x8c,0x43,0x00,0x00,0x3c,0x02,0x00,0x40,0x24,0x07,0x0f,0xff,0x00,0x03,0x33,0x02, ++0x00,0x03,0x2d,0x02,0x00,0x03,0x43,0x02,0x30,0x69,0x0f,0xff,0x00,0x62,0x18,0x24, ++0x30,0xa5,0x00,0x03,0x30,0xc6,0x00,0xff,0x10,0x60,0x00,0x08,0x31,0x08,0x00,0xff, ++0x01,0x00,0x30,0x21,0x0c,0x00,0x2b,0xe7,0xaf,0xa9,0x00,0x10,0x8f,0xbf,0x00,0x18, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x2c,0x39, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0xd4,0x08,0x00,0x2b,0x4f, ++0xac,0x62,0x00,0x00,0x27,0xbd,0xff,0xc0,0xaf,0xb6,0x00,0x30,0xaf,0xb3,0x00,0x24, ++0xaf,0xb1,0x00,0x1c,0xaf,0xb0,0x00,0x18,0xaf,0xbf,0x00,0x3c,0xaf,0xbe,0x00,0x38, ++0xaf,0xb7,0x00,0x34,0xaf,0xb5,0x00,0x2c,0xaf,0xb4,0x00,0x28,0xaf,0xb2,0x00,0x20, ++0x0c,0x00,0x1f,0x11,0x00,0x80,0x80,0x21,0x00,0x00,0xb0,0x21,0x00,0x00,0x88,0x21, ++0x10,0x40,0x00,0x12,0x00,0x00,0x98,0x21,0x3c,0x02,0xb0,0x03,0x3c,0x03,0xb0,0x03, ++0x3c,0x04,0xb0,0x03,0x24,0x05,0x00,0x01,0x34,0x42,0x00,0xbc,0x34,0x63,0x00,0xbb, ++0x34,0x84,0x00,0xba,0xa4,0x40,0x00,0x00,0xa0,0x65,0x00,0x00,0xa0,0x85,0x00,0x00, ++0x7b,0xbe,0x01,0xfc,0x7b,0xb6,0x01,0xbc,0x7b,0xb4,0x01,0x7c,0x7b,0xb2,0x01,0x3c, ++0x7b,0xb0,0x00,0xfc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x40,0x3c,0x02,0xb0,0x03, ++0x34,0x42,0x01,0x47,0x90,0x44,0x00,0x00,0x00,0x10,0x1a,0x02,0x3c,0x15,0xfd,0xff, ++0x30,0x84,0x00,0xff,0xa0,0x50,0x00,0x00,0x30,0x74,0x00,0x0f,0xaf,0xa4,0x00,0x10, ++0x00,0x00,0x90,0x21,0x3c,0x17,0x02,0x00,0x36,0xb5,0xff,0xff,0x3c,0x1e,0xb0,0x03, ++0x0c,0x00,0x0e,0x71,0x24,0x04,0x00,0x78,0x00,0x57,0x10,0x25,0x00,0x40,0x28,0x21, ++0x0c,0x00,0x0e,0x64,0x24,0x04,0x00,0x78,0x00,0x00,0x80,0x21,0x0c,0x00,0x2d,0x0a, ++0x00,0x00,0x00,0x00,0x26,0x03,0x00,0x01,0x30,0x70,0x00,0xff,0x10,0x40,0x00,0x47, ++0x2e,0x03,0x00,0x02,0x14,0x60,0xff,0xf9,0x00,0x00,0x00,0x00,0x0c,0x00,0x0e,0x71, ++0x24,0x04,0x00,0x78,0x00,0x55,0x10,0x24,0x00,0x40,0x28,0x21,0x0c,0x00,0x0e,0x64, ++0x24,0x04,0x00,0x78,0x24,0x02,0x00,0x01,0x12,0x82,0x00,0x38,0x24,0x04,0x00,0xe0, ++0x12,0x80,0x00,0x36,0x24,0x04,0x00,0xe4,0x32,0x22,0x00,0x60,0x32,0x23,0x0c,0x00, ++0x00,0x03,0x1a,0x02,0x3c,0x05,0x00,0x60,0x00,0x02,0x11,0x42,0x02,0x25,0x20,0x24, ++0x00,0x43,0x10,0x25,0x3c,0x03,0x04,0x00,0x02,0x23,0x28,0x24,0x00,0x04,0x24,0x42, ++0x00,0x44,0x10,0x25,0x00,0x05,0x2d,0x02,0x00,0x45,0x88,0x25,0x12,0x20,0x00,0x05, ++0x26,0x42,0x00,0x01,0x26,0xc2,0x00,0x01,0x30,0x56,0x00,0xff,0x02,0x71,0x98,0x21, ++0x26,0x42,0x00,0x01,0x02,0x5e,0x20,0x21,0x30,0x52,0x00,0xff,0x2e,0x43,0x00,0x05, ++0xa0,0x91,0x00,0xd8,0x14,0x60,0xff,0xce,0x3c,0x02,0xb0,0x03,0x8f,0xa5,0x00,0x10, ++0x34,0x42,0x01,0x47,0xa0,0x45,0x00,0x00,0x12,0x60,0x00,0x0e,0x3c,0x02,0xb0,0x03, ++0x12,0xc0,0x00,0x0d,0x34,0x42,0x00,0xbc,0x00,0x13,0x10,0x40,0x00,0x53,0x10,0x21, ++0x00,0x02,0x10,0xc0,0x00,0x53,0x10,0x21,0x00,0x02,0x98,0x80,0x02,0x76,0x00,0x1b, ++0x16,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d,0x00,0x00,0x98,0x12, ++0x3c,0x02,0xb0,0x03,0x34,0x42,0x00,0xbc,0x3c,0x03,0xb0,0x03,0x3c,0x04,0xb0,0x03, ++0xa4,0x53,0x00,0x00,0x34,0x63,0x00,0xbb,0x34,0x84,0x00,0xba,0x24,0x02,0x00,0x01, ++0xa0,0x60,0x00,0x00,0x08,0x00,0x2b,0x74,0xa0,0x82,0x00,0x00,0x0c,0x00,0x0e,0x71, ++0x00,0x00,0x00,0x00,0x08,0x00,0x2b,0xa2,0x00,0x40,0x88,0x21,0x3c,0x03,0xb0,0x03, ++0x34,0x63,0x00,0xbc,0x3c,0x04,0xb0,0x03,0x3c,0x05,0xb0,0x03,0xa4,0x60,0x00,0x00, ++0x34,0x84,0x00,0xbb,0x34,0xa5,0x00,0xba,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x01, ++0xa0,0x82,0x00,0x00,0x08,0x00,0x2b,0x74,0xa0,0xa3,0x00,0x00,0x27,0xbd,0xff,0xd8, ++0xaf,0xb0,0x00,0x10,0x30,0xd0,0x00,0xff,0x2e,0x02,0x00,0x2e,0xaf,0xb2,0x00,0x18, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x20,0xaf,0xb3,0x00,0x1c,0x30,0xb1,0x00,0xff, ++0x14,0x40,0x00,0x06,0x00,0x80,0x90,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x13,0x00,0x10, ++0x24,0x05,0x00,0x14,0x0c,0x00,0x1b,0x6e,0x24,0x06,0x01,0x07,0x12,0x60,0x00,0x38, ++0x02,0x00,0x30,0x21,0x8f,0xa2,0x00,0x38,0x30,0xc3,0x00,0x3f,0x3c,0x04,0xb0,0x09, ++0x00,0x02,0x14,0x00,0x00,0x43,0x30,0x25,0x34,0x84,0x01,0x60,0x90,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfd,0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x2a, ++0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x24,0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x20, ++0x24,0x02,0x00,0x03,0x12,0x22,0x00,0x19,0x00,0x00,0x00,0x00,0x16,0x60,0xff,0xe2, ++0x24,0x02,0x00,0x01,0x12,0x22,0x00,0x13,0x2a,0x22,0x00,0x02,0x14,0x40,0x00,0x0d, ++0x24,0x02,0x00,0x02,0x12,0x22,0x00,0x09,0x24,0x02,0x00,0x03,0x16,0x22,0xff,0xda, ++0x00,0x00,0x00,0x00,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff,0x0c,0x00,0x1b,0x29, ++0x3c,0x06,0x0c,0xb8,0x08,0x00,0x2b,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x2c,0x1a, ++0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xd0,0x00,0x00,0x00,0x00,0x08,0x00,0x2c,0x1a, ++0x24,0x04,0x08,0x40,0x08,0x00,0x2c,0x1a,0x24,0x04,0x08,0x44,0x24,0x04,0x08,0x4c, ++0x0c,0x00,0x1b,0x29,0x24,0x05,0xff,0xff,0x08,0x00,0x2c,0x0f,0x00,0x00,0x00,0x00, ++0x08,0x00,0x2c,0x28,0x24,0x04,0x08,0x48,0x16,0x20,0xff,0xe0,0x00,0x00,0x00,0x00, ++0x08,0x00,0x2c,0x28,0x24,0x04,0x08,0x40,0x08,0x00,0x2c,0x28,0x24,0x04,0x08,0x44, ++0x02,0x40,0x20,0x21,0x0c,0x00,0x2c,0x75,0x02,0x20,0x28,0x21,0x08,0x00,0x2b,0xfd, ++0x00,0x40,0x30,0x21,0x27,0xbd,0xff,0xd8,0x2c,0xc2,0x00,0x2e,0xaf,0xb3,0x00,0x1c, ++0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x20,0xaf,0xb2,0x00,0x18, ++0x00,0xc0,0x88,0x21,0x30,0xb0,0x00,0xff,0x00,0x80,0x98,0x21,0x14,0x40,0x00,0x07, ++0x00,0x00,0x18,0x21,0x8f,0xbf,0x00,0x20,0x7b,0xb2,0x00,0xfc,0x7b,0xb0,0x00,0xbc, ++0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x28,0x2e,0x32,0x00,0x10, ++0x24,0x05,0x00,0x14,0x0c,0x00,0x1b,0x6e,0x24,0x06,0x01,0x07,0x12,0x40,0x00,0x1f, ++0x02,0x20,0x10,0x21,0x30,0x45,0x00,0x3f,0x0c,0x00,0x2c,0xb2,0x02,0x00,0x20,0x21, ++0x16,0x40,0x00,0x0a,0x00,0x40,0x88,0x21,0x24,0x02,0x00,0x01,0x12,0x02,0x00,0x15, ++0x2a,0x02,0x00,0x02,0x14,0x40,0x00,0x0f,0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x0b, ++0x24,0x02,0x00,0x03,0x12,0x02,0x00,0x03,0x00,0x00,0x00,0x00,0x08,0x00,0x2c,0x45, ++0x02,0x20,0x18,0x21,0x24,0x04,0x08,0x4c,0x24,0x05,0xff,0xff,0x0c,0x00,0x1b,0x29, ++0x3c,0x06,0x0c,0xb8,0x08,0x00,0x2c,0x45,0x02,0x20,0x18,0x21,0x08,0x00,0x2c,0x62, ++0x24,0x04,0x08,0x48,0x16,0x00,0xff,0xf5,0x00,0x00,0x00,0x00,0x08,0x00,0x2c,0x62, ++0x24,0x04,0x08,0x40,0x08,0x00,0x2c,0x62,0x24,0x04,0x08,0x44,0x02,0x60,0x20,0x21, ++0x02,0x20,0x30,0x21,0x0c,0x00,0x2c,0x75,0x02,0x00,0x28,0x21,0x08,0x00,0x2c,0x52, ++0x30,0x45,0x00,0x3f,0x27,0xbd,0xff,0xe8,0x2c,0xc2,0x00,0x1f,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x14,0x00,0xc0,0x80,0x21,0x14,0x40,0x00,0x1d,0x30,0xa5,0x00,0xff, ++0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x18,0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x12, ++0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0e,0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x07, ++0x24,0x04,0x08,0x4c,0x26,0x10,0xff,0xe2,0x02,0x00,0x10,0x21,0x8f,0xbf,0x00,0x14, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x24,0x05,0xff,0xff, ++0x0c,0x00,0x1b,0x29,0x3c,0x06,0x0d,0xf8,0x08,0x00,0x2c,0x86,0x26,0x10,0xff,0xe2, ++0x08,0x00,0x2c,0x8b,0x24,0x04,0x08,0x48,0x14,0xa0,0xff,0xf2,0x24,0x04,0x08,0x40, ++0x08,0x00,0x2c,0x8c,0x24,0x05,0xff,0xff,0x08,0x00,0x2c,0x8b,0x24,0x04,0x08,0x44, ++0x2c,0xc2,0x00,0x10,0x14,0x40,0xff,0xec,0x24,0x02,0x00,0x01,0x10,0xa2,0x00,0x14, ++0x28,0xa2,0x00,0x02,0x14,0x40,0x00,0x0e,0x24,0x02,0x00,0x02,0x10,0xa2,0x00,0x0a, ++0x24,0x02,0x00,0x03,0x10,0xa2,0x00,0x03,0x24,0x04,0x08,0x4c,0x08,0x00,0x2c,0x86, ++0x26,0x10,0xff,0xf1,0x24,0x05,0xff,0xff,0x0c,0x00,0x1b,0x29,0x3c,0x06,0x0d,0xb8, ++0x08,0x00,0x2c,0x86,0x26,0x10,0xff,0xf1,0x08,0x00,0x2c,0xa5,0x24,0x04,0x08,0x48, ++0x14,0xa0,0xff,0xf6,0x24,0x04,0x08,0x40,0x08,0x00,0x2c,0xa6,0x24,0x05,0xff,0xff, ++0x08,0x00,0x2c,0xa5,0x24,0x04,0x08,0x44,0x27,0xbd,0xff,0xe0,0x00,0x80,0x10,0x21, ++0x24,0x04,0x00,0x50,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x18, ++0x00,0xa0,0x88,0x21,0x0c,0x00,0x01,0x31,0x30,0x50,0x00,0xff,0x24,0x03,0x00,0x01, ++0x12,0x03,0x00,0x3e,0x02,0x20,0x30,0x21,0x2a,0x02,0x00,0x02,0x14,0x40,0x00,0x2a, ++0x00,0x00,0x00,0x00,0x24,0x02,0x00,0x02,0x12,0x02,0x00,0x19,0x24,0x04,0x08,0x34, ++0x24,0x02,0x00,0x03,0x12,0x02,0x00,0x05,0x24,0x04,0x08,0x3c,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x0c,0x00,0x1b,0x29, ++0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x3c,0x3c,0x05,0x80,0x00,0x0c,0x00,0x1b,0x29, ++0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00,0x24,0x06,0x00,0x01,0x0c,0x00,0x1b,0x29, ++0x24,0x04,0x08,0x3c,0x0c,0x00,0x01,0x31,0x24,0x04,0x00,0x28,0x24,0x04,0x08,0xac, ++0x0c,0x00,0x1b,0x0b,0x24,0x05,0x0f,0xff,0x08,0x00,0x2c,0xc7,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x1b,0x29,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x34,0x3c,0x05,0x80,0x00, ++0x0c,0x00,0x1b,0x29,0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00,0x24,0x06,0x00,0x01, ++0x0c,0x00,0x1b,0x29,0x24,0x04,0x08,0x34,0x0c,0x00,0x01,0x31,0x24,0x04,0x00,0x28, ++0x08,0x00,0x2c,0xd8,0x24,0x04,0x08,0xa8,0x16,0x00,0xff,0xdc,0x02,0x20,0x30,0x21, ++0x24,0x04,0x08,0x24,0x0c,0x00,0x1b,0x29,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x24, ++0x3c,0x05,0x80,0x00,0x0c,0x00,0x1b,0x29,0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00, ++0x24,0x06,0x00,0x01,0x0c,0x00,0x1b,0x29,0x24,0x04,0x08,0x24,0x0c,0x00,0x01,0x31, ++0x24,0x04,0x00,0x28,0x08,0x00,0x2c,0xd8,0x24,0x04,0x08,0xa0,0x24,0x04,0x08,0x2c, ++0x0c,0x00,0x1b,0x29,0x3c,0x05,0x3f,0x00,0x24,0x04,0x08,0x2c,0x3c,0x05,0x80,0x00, ++0x0c,0x00,0x1b,0x29,0x00,0x00,0x30,0x21,0x3c,0x05,0x80,0x00,0x24,0x06,0x00,0x01, ++0x0c,0x00,0x1b,0x29,0x24,0x04,0x08,0x2c,0x0c,0x00,0x01,0x31,0x24,0x04,0x00,0x28, ++0x08,0x00,0x2c,0xd8,0x24,0x04,0x08,0xa4,0x3c,0x05,0x00,0x14,0x3c,0x02,0xb0,0x05, ++0x34,0x42,0x04,0x20,0x3c,0x06,0xc0,0x00,0x3c,0x03,0xb0,0x05,0x3c,0x04,0xb0,0x05, ++0x34,0xa5,0x17,0x09,0xac,0x45,0x00,0x00,0x34,0xc6,0x05,0x07,0x34,0x63,0x04,0x24, ++0x34,0x84,0x02,0x28,0x3c,0x07,0xb0,0x05,0x24,0x02,0x00,0x20,0xac,0x66,0x00,0x00, ++0x34,0xe7,0x04,0x50,0xa0,0x82,0x00,0x00,0x90,0xe2,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x03,0x10,0x40,0xff,0xfc,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe8,0xaf,0xbf,0x00,0x10,0x0c,0x00,0x2d,0xcf, ++0x00,0x00,0x00,0x00,0x0c,0x00,0x2d,0xd1,0x00,0x00,0x00,0x00,0x0c,0x00,0x2d,0xf8, ++0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x05,0x34,0x84,0x00,0x04,0x0c,0x00,0x2d,0xd8, ++0x34,0x05,0x9c,0x40,0x8f,0xbf,0x00,0x10,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x24,0x02,0x00,0x01,0x03,0xe0,0x00,0x08, ++0x24,0x02,0x00,0x01,0x97,0x82,0x88,0x10,0x00,0x00,0x00,0x00,0x2c,0x43,0x00,0x64, ++0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x10,0x14,0x60,0x00,0x28,0x00,0x80,0x30,0x21, ++0x8c,0x82,0x00,0x00,0x3c,0x03,0x20,0x00,0xa7,0x80,0x88,0x10,0x00,0x43,0x10,0x24, ++0x10,0x40,0x00,0x22,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00, ++0x00,0x43,0x10,0x25,0x97,0x83,0x88,0x04,0xac,0x82,0x00,0x00,0x8c,0x85,0x00,0x00, ++0x24,0x63,0x00,0x01,0x3c,0x02,0x40,0x64,0x34,0x42,0x64,0x00,0x00,0x03,0x24,0x00, ++0x00,0xa2,0x28,0x25,0x00,0x04,0x24,0x03,0x24,0x02,0x00,0x64,0xac,0xc5,0x00,0x00, ++0xa7,0x83,0x88,0x04,0x10,0x82,0x00,0x2b,0x00,0x00,0x00,0x00,0x87,0x82,0x88,0x06, ++0x24,0x03,0x00,0x3c,0x10,0x43,0x00,0x21,0x00,0x00,0x00,0x00,0x87,0x82,0x88,0x08, ++0x00,0x00,0x00,0x00,0x10,0x43,0x00,0x17,0x00,0x00,0x00,0x00,0x87,0x83,0x88,0x0a, ++0x24,0x02,0x00,0x18,0x10,0x62,0x00,0x0d,0x00,0x00,0x00,0x00,0x87,0x83,0x88,0x0c, ++0x24,0x02,0x01,0x6d,0x10,0x62,0x00,0x03,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x0e,0xa7,0x80,0x88,0x0c,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x88,0x0e,0x08,0x00,0x2d,0x67,0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x0c, ++0xa7,0x80,0x88,0x0a,0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x0c,0x08,0x00,0x2d,0x63, ++0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x0a,0xa7,0x80,0x88,0x08,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x88,0x0a,0x08,0x00,0x2d,0x5f,0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x08, ++0xa7,0x80,0x88,0x06,0x24,0x42,0x00,0x01,0xa7,0x82,0x88,0x08,0x08,0x00,0x2d,0x5b, ++0x00,0x00,0x00,0x00,0x97,0x82,0x88,0x06,0xa7,0x80,0x88,0x04,0x24,0x42,0x00,0x01, ++0xa7,0x82,0x88,0x06,0x08,0x00,0x2d,0x57,0x00,0x00,0x00,0x00,0x00,0x04,0x24,0x00, ++0x3c,0x03,0xb0,0x07,0x00,0x04,0x24,0x03,0x34,0x63,0x00,0x28,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x40,0x10,0x40,0xff,0xfc,0x00,0x00,0x00,0x00, ++0x3c,0x01,0xb0,0x07,0xa0,0x24,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21, ++0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x28,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x63,0x00,0x01,0x10,0x60,0x00,0x06,0x24,0x02,0xff,0xff,0x3c,0x02,0xb0,0x07, ++0x90,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x27,0xbd,0xff,0xe0,0xaf,0xb0,0x00,0x10, ++0x3c,0x10,0x04,0xc4,0x00,0x04,0x11,0x00,0x36,0x10,0xb4,0x00,0x02,0x02,0x00,0x1b, ++0xaf,0xb1,0x00,0x14,0x3c,0x11,0xb0,0x07,0x36,0x31,0x00,0x18,0x24,0x04,0x00,0x0a, ++0xaf,0xbf,0x00,0x18,0x14,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x0d, ++0x00,0x00,0x80,0x12,0x0c,0x00,0x2e,0x24,0x00,0x00,0x00,0x00,0x92,0x22,0x00,0x00, ++0x24,0x03,0xff,0x80,0x24,0x04,0x00,0x0a,0x00,0x43,0x10,0x25,0x0c,0x00,0x2e,0x24, ++0xa2,0x22,0x00,0x00,0x24,0x04,0x00,0x0a,0x3c,0x01,0xb0,0x07,0xa0,0x30,0x00,0x00, ++0x0c,0x00,0x2e,0x24,0x00,0x10,0x82,0x03,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x08, ++0xa0,0x50,0x00,0x00,0x0c,0x00,0x2e,0x24,0x24,0x04,0x00,0x0a,0x92,0x22,0x00,0x00, ++0x8f,0xbf,0x00,0x18,0x8f,0xb0,0x00,0x10,0x30,0x42,0x00,0x7f,0xa2,0x22,0x00,0x00, ++0x8f,0xb1,0x00,0x14,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x58,0x8c,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x34,0x42,0x07,0xa4,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00, ++0x27,0xbd,0xff,0xf8,0x00,0x80,0x38,0x21,0x00,0xa0,0x30,0x21,0x00,0x00,0x18,0x21, ++0x00,0x63,0x00,0x18,0x00,0x00,0x10,0x12,0x00,0xc2,0x10,0x2b,0x14,0x40,0x00,0x05, ++0x00,0x00,0x00,0x00,0x24,0x63,0x00,0x01,0x2c,0x62,0x01,0x00,0x14,0x40,0xff,0xf9, ++0x00,0x63,0x00,0x18,0x24,0x63,0xff,0xff,0x00,0x63,0x00,0x18,0x30,0x63,0x00,0xff, ++0x8c,0xe4,0x00,0x00,0x00,0x03,0x2a,0x00,0x00,0x03,0x1c,0x00,0x00,0x00,0x10,0x12, ++0x00,0xc2,0x10,0x23,0x30,0x42,0x00,0xff,0x00,0x45,0x10,0x21,0x00,0x43,0x10,0x21, ++0x00,0x82,0x20,0x25,0xac,0xe4,0x00,0x00,0x8c,0xe2,0x00,0x00,0x3c,0x03,0x40,0x00, ++0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x00,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x08, ++0x27,0xbd,0xff,0xe0,0xaf,0xbf,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0x3c,0x04,0xb0,0x03,0x8c,0x82,0x00,0x00,0x3c,0x06,0xb0,0x03,0x34,0xc6,0x00,0x08, ++0x34,0x42,0x40,0x00,0xac,0x82,0x00,0x00,0x8c,0x83,0x00,0x00,0x24,0x02,0xcf,0xff, ++0x3c,0x11,0xb0,0x07,0x00,0x62,0x18,0x24,0xac,0x83,0x00,0x00,0x8c,0xc5,0x00,0x00, ++0x3c,0x02,0x00,0xff,0x24,0x04,0x00,0x0a,0x00,0xa2,0x28,0x25,0xac,0xc5,0x00,0x00, ++0x0c,0x00,0x2e,0x24,0x36,0x31,0x00,0x18,0x24,0x02,0xff,0x83,0x3c,0x04,0x00,0x01, ++0xa2,0x22,0x00,0x00,0x0c,0x00,0x2d,0xa2,0x34,0x84,0xc2,0x00,0x0c,0x00,0x2e,0x24, ++0x24,0x04,0x00,0x0a,0x24,0x02,0x00,0x03,0xa2,0x22,0x00,0x00,0x24,0x04,0x00,0x0a, ++0x0c,0x00,0x2e,0x24,0x3c,0x10,0xb0,0x07,0x36,0x10,0x00,0x10,0x24,0x02,0x00,0x06, ++0xa2,0x02,0x00,0x00,0x0c,0x00,0x2e,0x24,0x24,0x04,0x00,0x0a,0xa2,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x18,0x7b,0xb0,0x00,0xbc,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, ++0x10,0x80,0x00,0x05,0x00,0x00,0x18,0x21,0x24,0x63,0x00,0x01,0x00,0x64,0x10,0x2b, ++0x14,0x40,0xff,0xfd,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x27,0xbd,0xff,0xc0,0xaf,0xb5,0x00,0x34,0xaf,0xb2,0x00,0x28,0xaf,0xb0,0x00,0x20, ++0xaf,0xbf,0x00,0x38,0xaf,0xb4,0x00,0x30,0xaf,0xb3,0x00,0x2c,0xaf,0xb1,0x00,0x24, ++0xaf,0xa5,0x00,0x44,0x90,0xa7,0x00,0x00,0x00,0x80,0xa8,0x21,0x00,0xc0,0x90,0x21, ++0x00,0x07,0x1e,0x00,0x10,0x60,0x00,0x0f,0x00,0x80,0x80,0x21,0x00,0x03,0x1e,0x03, ++0x24,0x02,0x00,0x25,0x10,0x62,0x00,0x13,0x00,0x00,0x88,0x21,0xa2,0x07,0x00,0x00, ++0x8f,0xa5,0x00,0x44,0x26,0x10,0x00,0x01,0x24,0xa5,0x00,0x01,0xaf,0xa5,0x00,0x44, ++0x90,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1e,0x00,0x14,0x60,0xff,0xf3, ++0x00,0x00,0x00,0x00,0x02,0x15,0x10,0x23,0xa2,0x00,0x00,0x00,0x8f,0xbf,0x00,0x38, ++0x7b,0xb4,0x01,0xbc,0x7b,0xb2,0x01,0x7c,0x7b,0xb0,0x01,0x3c,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x40,0x24,0xa5,0x00,0x01,0xaf,0xa5,0x00,0x44,0x80,0xa3,0x00,0x00, ++0x00,0x00,0x00,0x00,0x24,0x63,0xff,0xe0,0x2c,0x62,0x00,0x11,0x10,0x40,0x00,0x11, ++0x00,0xa0,0x38,0x21,0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01,0x24,0x63,0x09,0xfc, ++0x00,0x43,0x10,0x21,0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08, ++0x00,0x00,0x00,0x00,0x08,0x00,0x2e,0x51,0x36,0x31,0x00,0x10,0x08,0x00,0x2e,0x51, ++0x36,0x31,0x00,0x08,0x08,0x00,0x2e,0x51,0x36,0x31,0x00,0x20,0x08,0x00,0x2e,0x51, ++0x36,0x31,0x00,0x04,0x90,0xe4,0x00,0x00,0x3c,0x02,0x80,0x01,0x24,0x42,0x02,0x1c, ++0x00,0x44,0x10,0x21,0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04, ++0x14,0x60,0x00,0xfd,0x24,0x14,0xff,0xff,0x00,0x04,0x16,0x00,0x00,0x02,0x16,0x03, ++0x24,0x03,0x00,0x2a,0x10,0x43,0x00,0xee,0x26,0x42,0x00,0x03,0x80,0xa3,0x00,0x00, ++0x24,0x02,0x00,0x2e,0x10,0x62,0x00,0xcc,0x24,0x08,0xff,0xff,0x80,0xa3,0x00,0x00, ++0x24,0x02,0x00,0x68,0x10,0x62,0x00,0xc4,0x24,0x06,0xff,0xff,0x24,0x02,0x00,0x6c, ++0x10,0x62,0x00,0xc1,0x24,0x02,0x00,0x4c,0x10,0x62,0x00,0xbf,0x24,0x02,0x00,0x5a, ++0x10,0x62,0x00,0xbd,0x00,0x00,0x00,0x00,0x80,0xa3,0x00,0x00,0x00,0x00,0x00,0x00, ++0x24,0x63,0xff,0xdb,0x2c,0x62,0x00,0x54,0x10,0x40,0x00,0xaa,0x24,0x09,0x00,0x0a, ++0x00,0x03,0x10,0x80,0x3c,0x03,0x80,0x01,0x24,0x63,0x0a,0x40,0x00,0x43,0x10,0x21, ++0x8c,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x08,0x00,0x00,0x00,0x00, ++0x32,0x22,0x00,0x10,0x14,0x40,0x00,0x09,0x24,0x02,0xff,0xfc,0x26,0x94,0xff,0xff, ++0x1a,0x80,0x00,0x05,0x24,0x02,0x00,0x20,0x26,0x94,0xff,0xff,0xa2,0x02,0x00,0x00, ++0x1e,0x80,0xff,0xfd,0x26,0x10,0x00,0x01,0x24,0x02,0xff,0xfc,0x26,0x44,0x00,0x03, ++0x00,0x82,0x90,0x24,0x92,0x42,0x00,0x03,0x26,0x94,0xff,0xff,0x26,0x52,0x00,0x04, ++0xa2,0x02,0x00,0x00,0x1a,0x80,0x00,0x06,0x26,0x10,0x00,0x01,0x24,0x02,0x00,0x20, ++0x26,0x94,0xff,0xff,0xa2,0x02,0x00,0x00,0x1e,0x80,0xff,0xfd,0x26,0x10,0x00,0x01, ++0x8f,0xa5,0x00,0x44,0x08,0x00,0x2e,0x43,0x24,0xa5,0x00,0x01,0x24,0x02,0x00,0x25, ++0x08,0x00,0x2e,0x40,0xa2,0x02,0x00,0x00,0x36,0x31,0x00,0x40,0x24,0x09,0x00,0x10, ++0x24,0x02,0x00,0x4c,0x10,0xc2,0x00,0x2a,0x24,0x02,0x00,0x6c,0x10,0xc2,0x00,0x05, ++0x24,0x02,0x00,0x5a,0x10,0xc2,0x00,0x1f,0x24,0x02,0x00,0x68,0x10,0xc2,0x00,0x13, ++0x24,0x02,0xff,0xfc,0x24,0x02,0xff,0xfc,0x26,0x43,0x00,0x03,0x00,0x62,0x90,0x24, ++0x32,0x22,0x00,0x02,0x8e,0x47,0x00,0x00,0x00,0x00,0x30,0x21,0x10,0x40,0x00,0x03, ++0x26,0x52,0x00,0x04,0x00,0xe0,0x10,0x21,0x00,0x02,0x37,0xc3,0x02,0x00,0x20,0x21, ++0xaf,0xa9,0x00,0x10,0xaf,0xb4,0x00,0x14,0xaf,0xa8,0x00,0x18,0x0c,0x00,0x2f,0x91, ++0xaf,0xb1,0x00,0x1c,0x08,0x00,0x2e,0xac,0x00,0x40,0x80,0x21,0x26,0x43,0x00,0x03, ++0x00,0x62,0x90,0x24,0x32,0x22,0x00,0x02,0x96,0x47,0x00,0x02,0x00,0x00,0x30,0x21, ++0x10,0x40,0xff,0xf2,0x26,0x52,0x00,0x04,0x00,0x07,0x14,0x00,0x08,0x00,0x2e,0xc6, ++0x00,0x02,0x3c,0x03,0x26,0x42,0x00,0x03,0x24,0x03,0xff,0xfc,0x00,0x43,0x90,0x24, ++0x8e,0x47,0x00,0x00,0x00,0x00,0x30,0x21,0x08,0x00,0x2e,0xc7,0x26,0x52,0x00,0x04, ++0x26,0x42,0x00,0x07,0x24,0x03,0xff,0xf8,0x00,0x43,0x90,0x24,0x8e,0x46,0x00,0x00, ++0x8e,0x47,0x00,0x04,0x08,0x00,0x2e,0xc7,0x26,0x52,0x00,0x08,0x08,0x00,0x2e,0xb4, ++0x36,0x31,0x00,0x02,0x26,0x44,0x00,0x03,0x24,0x02,0xff,0xfc,0x00,0x82,0x90,0x24, ++0x8e,0x44,0x00,0x00,0x02,0x15,0x10,0x23,0x26,0x52,0x00,0x04,0x08,0x00,0x2e,0x42, ++0xac,0x82,0x00,0x00,0x08,0x00,0x2e,0xb4,0x24,0x09,0x00,0x08,0x24,0x02,0xff,0xff, ++0x12,0x82,0x00,0x11,0x00,0x00,0x00,0x00,0x26,0x43,0x00,0x03,0x24,0x02,0xff,0xfc, ++0x00,0x62,0x90,0x24,0x8e,0x47,0x00,0x00,0x02,0x00,0x20,0x21,0x24,0x02,0x00,0x10, ++0x00,0x00,0x30,0x21,0xaf,0xa2,0x00,0x10,0xaf,0xb4,0x00,0x14,0xaf,0xa8,0x00,0x18, ++0x0c,0x00,0x2f,0x91,0xaf,0xb1,0x00,0x1c,0x8f,0xa5,0x00,0x44,0x00,0x40,0x80,0x21, ++0x08,0x00,0x2e,0x42,0x26,0x52,0x00,0x04,0x24,0x14,0x00,0x08,0x08,0x00,0x2e,0xf6, ++0x36,0x31,0x00,0x01,0x26,0x42,0x00,0x03,0x24,0x03,0xff,0xfc,0x00,0x43,0x90,0x24, ++0x8e,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x60,0x00,0x23,0x26,0x52,0x00,0x04, ++0x02,0x60,0x20,0x21,0x0c,0x00,0x30,0x5f,0x01,0x00,0x28,0x21,0x00,0x40,0x20,0x21, ++0x32,0x22,0x00,0x10,0x14,0x40,0x00,0x09,0x00,0x94,0x10,0x2a,0x10,0x40,0x00,0x07, ++0x26,0x94,0xff,0xff,0x24,0x03,0x00,0x20,0x00,0x94,0x10,0x2a,0xa2,0x03,0x00,0x00, ++0x26,0x94,0xff,0xff,0x14,0x40,0xff,0xfc,0x26,0x10,0x00,0x01,0x18,0x80,0x00,0x07, ++0x00,0x80,0x18,0x21,0x92,0x62,0x00,0x00,0x24,0x63,0xff,0xff,0x26,0x73,0x00,0x01, ++0xa2,0x02,0x00,0x00,0x14,0x60,0xff,0xfb,0x26,0x10,0x00,0x01,0x00,0x94,0x10,0x2a, ++0x10,0x40,0xff,0x83,0x26,0x94,0xff,0xff,0x24,0x03,0x00,0x20,0x00,0x94,0x10,0x2a, ++0xa2,0x03,0x00,0x00,0x26,0x94,0xff,0xff,0x14,0x40,0xff,0xfc,0x26,0x10,0x00,0x01, ++0x08,0x00,0x2e,0xac,0x00,0x00,0x00,0x00,0x3c,0x02,0x80,0x01,0x08,0x00,0x2f,0x10, ++0x24,0x53,0x08,0x04,0x24,0x02,0x00,0x25,0xa2,0x02,0x00,0x00,0x8f,0xa5,0x00,0x44, ++0x00,0x00,0x00,0x00,0x80,0xa2,0x00,0x00,0x90,0xa3,0x00,0x00,0x10,0x40,0x00,0x03, ++0x26,0x10,0x00,0x01,0x08,0x00,0x2e,0x40,0xa2,0x03,0x00,0x00,0x24,0xa5,0xff,0xff, ++0x08,0x00,0x2e,0x42,0xaf,0xa5,0x00,0x44,0x80,0xa6,0x00,0x00,0x24,0xa5,0x00,0x01, ++0x08,0x00,0x2e,0x86,0xaf,0xa5,0x00,0x44,0x24,0xa5,0x00,0x01,0xaf,0xa5,0x00,0x44, ++0x90,0xa4,0x00,0x00,0x3c,0x02,0x80,0x01,0x24,0x42,0x02,0x1c,0x00,0x44,0x10,0x21, ++0x90,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x63,0x00,0x04,0x14,0x60,0x00,0x0f, ++0x00,0x04,0x16,0x00,0x00,0x02,0x16,0x03,0x24,0x03,0x00,0x2a,0x10,0x43,0x00,0x04, ++0x26,0x42,0x00,0x03,0x29,0x02,0x00,0x00,0x08,0x00,0x2e,0x7b,0x00,0x02,0x40,0x0b, ++0x24,0x03,0xff,0xfc,0x00,0x43,0x90,0x24,0x24,0xa5,0x00,0x01,0x8e,0x48,0x00,0x00, ++0xaf,0xa5,0x00,0x44,0x08,0x00,0x2f,0x55,0x26,0x52,0x00,0x04,0x0c,0x00,0x2f,0x75, ++0x27,0xa4,0x00,0x44,0x8f,0xa5,0x00,0x44,0x08,0x00,0x2f,0x55,0x00,0x40,0x40,0x21, ++0x24,0x03,0xff,0xfc,0x00,0x43,0x90,0x24,0x8e,0x54,0x00,0x00,0x24,0xe5,0x00,0x01, ++0xaf,0xa5,0x00,0x44,0x06,0x81,0xff,0x0d,0x26,0x52,0x00,0x04,0x00,0x14,0xa0,0x23, ++0x08,0x00,0x2e,0x77,0x36,0x31,0x00,0x10,0x0c,0x00,0x2f,0x75,0x27,0xa4,0x00,0x44, ++0x8f,0xa5,0x00,0x44,0x08,0x00,0x2e,0x77,0x00,0x40,0xa0,0x21,0x08,0x00,0x2e,0x51, ++0x36,0x31,0x00,0x01,0x8c,0x86,0x00,0x00,0x3c,0x02,0x80,0x01,0x00,0x80,0x48,0x21, ++0x90,0xc3,0x00,0x00,0x24,0x44,0x02,0x1c,0x00,0x64,0x18,0x21,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x04,0x10,0x40,0x00,0x10,0x00,0x00,0x38,0x21, ++0x00,0x80,0x40,0x21,0x24,0xc2,0x00,0x01,0x80,0xc5,0x00,0x00,0xad,0x22,0x00,0x00, ++0x90,0x43,0x00,0x00,0x00,0x40,0x30,0x21,0x00,0x07,0x10,0x80,0x00,0x68,0x18,0x21, ++0x90,0x64,0x00,0x00,0x00,0x47,0x10,0x21,0x00,0x02,0x10,0x40,0x00,0x45,0x10,0x21, ++0x30,0x84,0x00,0x04,0x14,0x80,0xff,0xf3,0x24,0x47,0xff,0xd0,0x03,0xe0,0x00,0x08, ++0x00,0xe0,0x10,0x21,0x27,0xbd,0xff,0x98,0xaf,0xb2,0x00,0x50,0x8f,0xb2,0x00,0x84, ++0x3c,0x02,0x80,0x01,0xaf,0xb4,0x00,0x58,0x32,0x43,0x00,0x40,0xaf,0xb1,0x00,0x4c, ++0xaf,0xb0,0x00,0x48,0xaf,0xb7,0x00,0x64,0xaf,0xb6,0x00,0x60,0xaf,0xb5,0x00,0x5c, ++0xaf,0xb3,0x00,0x54,0x00,0x80,0x68,0x21,0x00,0xc0,0x70,0x21,0x00,0xe0,0x78,0x21, ++0x8f,0xb0,0x00,0x78,0x8f,0xb8,0x00,0x7c,0x8f,0xb1,0x00,0x80,0x10,0x60,0x00,0x03, ++0x24,0x54,0x08,0x0c,0x3c,0x02,0x80,0x01,0x24,0x54,0x08,0x34,0x32,0x42,0x00,0x10, ++0x10,0x40,0x00,0x04,0x26,0x02,0xff,0xfe,0x24,0x02,0xff,0xfe,0x02,0x42,0x90,0x24, ++0x26,0x02,0xff,0xfe,0x2c,0x42,0x00,0x23,0x10,0x40,0x00,0x5d,0x00,0x00,0x18,0x21, ++0x32,0x42,0x00,0x01,0x24,0x15,0x00,0x30,0x24,0x03,0x00,0x20,0x32,0x44,0x00,0x02, ++0x00,0x62,0xa8,0x0a,0x10,0x80,0x00,0x07,0x00,0x00,0xb8,0x21,0x05,0xc0,0x00,0x96, ++0x32,0x42,0x00,0x04,0x10,0x40,0x00,0x90,0x32,0x42,0x00,0x08,0x24,0x17,0x00,0x2b, ++0x27,0x18,0xff,0xff,0x32,0x56,0x00,0x20,0x12,0xc0,0x00,0x07,0x01,0xcf,0x10,0x25, ++0x24,0x02,0x00,0x10,0x12,0x02,0x00,0x86,0x27,0x03,0xff,0xff,0x3a,0x02,0x00,0x08, ++0x00,0x62,0xc0,0x0a,0x01,0xcf,0x10,0x25,0x14,0x40,0x00,0x55,0x00,0x00,0xc8,0x21, ++0x24,0x02,0x00,0x30,0x24,0x19,0x00,0x01,0xa3,0xa2,0x00,0x00,0x02,0x39,0x10,0x2a, ++0x03,0x22,0x88,0x0b,0x32,0x43,0x00,0x11,0x14,0x60,0x00,0x0a,0x03,0x11,0xc0,0x23, ++0x03,0x00,0x10,0x21,0x18,0x40,0x00,0x07,0x27,0x18,0xff,0xff,0x24,0x03,0x00,0x20, ++0x03,0x00,0x10,0x21,0xa1,0xa3,0x00,0x00,0x27,0x18,0xff,0xff,0x1c,0x40,0xff,0xfc, ++0x25,0xad,0x00,0x01,0x12,0xe0,0x00,0x03,0x00,0x00,0x00,0x00,0xa1,0xb7,0x00,0x00, ++0x25,0xad,0x00,0x01,0x12,0xc0,0x00,0x07,0x32,0x42,0x00,0x10,0x24,0x02,0x00,0x08, ++0x12,0x02,0x00,0x38,0x24,0x02,0x00,0x10,0x12,0x02,0x00,0x30,0x24,0x02,0x00,0x30, ++0x32,0x42,0x00,0x10,0x14,0x40,0x00,0x0a,0x03,0x31,0x10,0x2a,0x03,0x00,0x10,0x21, ++0x18,0x40,0x00,0x06,0x27,0x18,0xff,0xff,0x03,0x00,0x10,0x21,0xa1,0xb5,0x00,0x00, ++0x27,0x18,0xff,0xff,0x1c,0x40,0xff,0xfc,0x25,0xad,0x00,0x01,0x03,0x31,0x10,0x2a, ++0x10,0x40,0x00,0x07,0x26,0x31,0xff,0xff,0x24,0x03,0x00,0x30,0x03,0x31,0x10,0x2a, ++0xa1,0xa3,0x00,0x00,0x26,0x31,0xff,0xff,0x14,0x40,0xff,0xfc,0x25,0xad,0x00,0x01, ++0x03,0x20,0x10,0x21,0x18,0x40,0x00,0x08,0x27,0x39,0xff,0xff,0x03,0xb9,0x10,0x21, ++0x90,0x43,0x00,0x00,0x03,0x20,0x20,0x21,0x27,0x39,0xff,0xff,0xa1,0xa3,0x00,0x00, ++0x1c,0x80,0xff,0xfa,0x25,0xad,0x00,0x01,0x03,0x00,0x10,0x21,0x18,0x40,0x00,0x07, ++0x27,0x18,0xff,0xff,0x24,0x03,0x00,0x20,0x03,0x00,0x10,0x21,0xa1,0xa3,0x00,0x00, ++0x27,0x18,0xff,0xff,0x1c,0x40,0xff,0xfc,0x25,0xad,0x00,0x01,0x01,0xa0,0x18,0x21, ++0x7b,0xb6,0x03,0x3c,0x7b,0xb4,0x02,0xfc,0x7b,0xb2,0x02,0xbc,0x7b,0xb0,0x02,0x7c, ++0x00,0x60,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x68,0xa1,0xa2,0x00,0x00, ++0x92,0x83,0x00,0x21,0x25,0xad,0x00,0x01,0xa1,0xa3,0x00,0x00,0x08,0x00,0x2f,0xe4, ++0x25,0xad,0x00,0x01,0x24,0x02,0x00,0x30,0x08,0x00,0x30,0x17,0xa1,0xa2,0x00,0x00, ++0x01,0xcf,0x10,0x25,0x10,0x40,0xff,0xad,0x00,0x00,0x60,0x21,0x00,0x0e,0x18,0x02, ++0x03,0x3d,0x98,0x21,0x00,0x60,0x20,0x21,0x01,0xe0,0x38,0x21,0x10,0x60,0x00,0x04, ++0x27,0x39,0x00,0x01,0x00,0x70,0x00,0x1b,0x00,0x00,0x20,0x12,0x00,0x00,0x18,0x10, ++0x00,0x80,0x48,0x21,0x00,0xe0,0x30,0x21,0x01,0x80,0x70,0x21,0x01,0x80,0x28,0x21, ++0x10,0x00,0x00,0x06,0x24,0x04,0x00,0x21,0x00,0x03,0x08,0x40,0x00,0x03,0x2f,0xc2, ++0x00,0x22,0x18,0x25,0x00,0x06,0x30,0x40,0x00,0x0e,0x70,0x40,0x14,0xa0,0x00,0x02, ++0x00,0x70,0x10,0x2b,0x14,0x40,0x00,0x03,0x24,0x84,0xff,0xff,0x00,0x70,0x18,0x23, ++0x25,0xce,0x00,0x01,0x14,0x80,0xff,0xf4,0x00,0x06,0x17,0xc2,0x02,0x83,0x18,0x21, ++0x01,0xc0,0x38,0x21,0x00,0x00,0x50,0x21,0x00,0x09,0x20,0x00,0x00,0x00,0x28,0x21, ++0x90,0x66,0x00,0x00,0x00,0x8a,0x70,0x25,0x00,0xa7,0x78,0x25,0x01,0xcf,0x10,0x25, ++0x14,0x40,0xff,0xda,0xa2,0x66,0x00,0x00,0x08,0x00,0x2f,0xcc,0x02,0x39,0x10,0x2a, ++0x08,0x00,0x2f,0xc5,0x27,0x18,0xff,0xfe,0x10,0x40,0xff,0x73,0x32,0x56,0x00,0x20, ++0x08,0x00,0x2f,0xbc,0x24,0x17,0x00,0x20,0x00,0x0f,0x78,0x23,0x00,0x0e,0x70,0x23, ++0x00,0x0f,0x10,0x2b,0x01,0xc2,0x70,0x23,0x08,0x00,0x2f,0xbc,0x24,0x17,0x00,0x2d, ++0x80,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x06,0x00,0x80,0x18,0x21, ++0x24,0x63,0x00,0x01,0x80,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfc, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x64,0x10,0x23,0x24,0xa5,0xff,0xff, ++0x24,0x02,0xff,0xff,0x10,0xa2,0x00,0x0d,0x00,0x80,0x18,0x21,0x80,0x82,0x00,0x00, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x09,0x00,0x00,0x00,0x00,0x24,0x06,0xff,0xff, ++0x24,0xa5,0xff,0xff,0x10,0xa6,0x00,0x05,0x24,0x63,0x00,0x01,0x80,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x64,0x10,0x23,0x80,0x82,0x00,0x00,0x90,0x88,0x00,0x00,0x10,0x40,0x00,0x17, ++0x00,0x00,0x48,0x21,0x90,0xa3,0x00,0x00,0x00,0xa0,0x30,0x21,0x10,0x60,0x00,0x0b, ++0x00,0x60,0x38,0x21,0x00,0x08,0x16,0x00,0x00,0x02,0x46,0x03,0x00,0x07,0x16,0x00, ++0x00,0x02,0x16,0x03,0x11,0x02,0x00,0x05,0x24,0xc6,0x00,0x01,0x90,0xc3,0x00,0x00, ++0x00,0x00,0x00,0x00,0x14,0x60,0xff,0xf9,0x00,0x60,0x38,0x21,0x00,0x03,0x16,0x00, ++0x10,0x40,0x00,0x06,0x00,0x00,0x00,0x00,0x24,0x84,0x00,0x01,0x90,0x82,0x00,0x00, ++0x25,0x29,0x00,0x01,0x14,0x40,0xff,0xeb,0x00,0x40,0x40,0x21,0x03,0xe0,0x00,0x08, ++0x01,0x20,0x10,0x21,0x80,0x82,0x00,0x00,0x90,0x87,0x00,0x00,0x10,0x40,0x00,0x17, ++0x00,0x00,0x18,0x21,0x90,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00, ++0x10,0x60,0x00,0x0c,0x00,0xa0,0x30,0x21,0x00,0x07,0x16,0x00,0x00,0x02,0x3e,0x03, ++0x00,0x03,0x16,0x03,0x10,0xe2,0x00,0x0d,0x00,0x80,0x18,0x21,0x24,0xc6,0x00,0x01, ++0x90,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x1e,0x00,0x14,0x60,0xff,0xf9, ++0x00,0x03,0x16,0x03,0x24,0x84,0x00,0x01,0x90,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x14,0x40,0xff,0xec,0x00,0x40,0x38,0x21,0x00,0x00,0x18,0x21,0x03,0xe0,0x00,0x08, ++0x00,0x60,0x10,0x21,0x27,0xbd,0xff,0xe0,0xaf,0xb0,0x00,0x10,0x8f,0x90,0xc5,0x5c, ++0xaf,0xb1,0x00,0x14,0xaf,0xbf,0x00,0x18,0x00,0x84,0x80,0x0b,0x00,0x00,0x30,0x21, ++0x12,0x00,0x00,0x0a,0x00,0xa0,0x88,0x21,0x0c,0x00,0x30,0x71,0x02,0x00,0x20,0x21, ++0x02,0x02,0x80,0x21,0x82,0x02,0x00,0x00,0x02,0x20,0x28,0x21,0x02,0x00,0x20,0x21, ++0x14,0x40,0x00,0x07,0x00,0x00,0x30,0x21,0xaf,0x80,0xc5,0x5c,0x8f,0xbf,0x00,0x18, ++0x7b,0xb0,0x00,0xbc,0x00,0xc0,0x10,0x21,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, ++0x0c,0x00,0x30,0x8d,0x00,0x00,0x00,0x00,0x00,0x40,0x18,0x21,0x10,0x40,0x00,0x07, ++0x02,0x00,0x30,0x21,0x80,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x03, ++0x00,0x00,0x00,0x00,0xa0,0x60,0x00,0x00,0x24,0x63,0x00,0x01,0xaf,0x83,0xc5,0x5c, ++0x08,0x00,0x30,0xbb,0x00,0x00,0x00,0x00,0x24,0xc6,0xff,0xff,0x24,0x02,0xff,0xff, ++0x10,0xc2,0x00,0x05,0x00,0x80,0x18,0x21,0x24,0xc6,0xff,0xff,0xa0,0x65,0x00,0x00, ++0x14,0xc2,0xff,0xfd,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21, ++0x24,0xc6,0xff,0xff,0x24,0x02,0xff,0xff,0x10,0xc2,0x00,0x08,0x00,0x80,0x18,0x21, ++0x24,0x07,0xff,0xff,0x90,0xa2,0x00,0x00,0x24,0xc6,0xff,0xff,0x24,0xa5,0x00,0x01, ++0xa0,0x62,0x00,0x00,0x14,0xc7,0xff,0xfb,0x24,0x63,0x00,0x01,0x03,0xe0,0x00,0x08, ++0x00,0x80,0x10,0x21,0x00,0x80,0x18,0x21,0x90,0xa2,0x00,0x00,0x24,0xa5,0x00,0x01, ++0xa0,0x82,0x00,0x00,0x14,0x40,0xff,0xfc,0x24,0x84,0x00,0x01,0x03,0xe0,0x00,0x08, ++0x00,0x60,0x10,0x21,0x90,0x83,0x00,0x00,0x90,0xa2,0x00,0x00,0x24,0x84,0x00,0x01, ++0x00,0x62,0x10,0x23,0x00,0x02,0x16,0x00,0x00,0x02,0x16,0x03,0x14,0x40,0x00,0x03, ++0x24,0xa5,0x00,0x01,0x14,0x60,0xff,0xf7,0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x00,0x00,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x10,0x21,0x93,0x85,0x88,0x6d, ++0x24,0x02,0x00,0x01,0x14,0xa2,0x00,0x53,0x00,0x80,0x40,0x21,0x8c,0x89,0x00,0x04, ++0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21,0x8c,0xc3,0x00,0x04,0x3c,0x02,0x01,0x00, ++0x00,0x62,0x10,0x24,0x10,0x40,0x00,0x4b,0x30,0x62,0x00,0x08,0x10,0x45,0x00,0x59, ++0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38,0x24,0x03,0x00,0xb4,0x30,0x44,0x00,0xff, ++0x10,0x83,0x00,0x61,0x24,0x02,0x00,0xc4,0x10,0x82,0x00,0x54,0x24,0x02,0x00,0x94, ++0x10,0x82,0x00,0x45,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x38,0x00,0x00,0x00,0x00, ++0x30,0x47,0xff,0xff,0x30,0xe3,0x40,0xff,0x24,0x02,0x40,0x88,0x14,0x62,0x00,0x39, ++0x30,0xe3,0x03,0x00,0x24,0x02,0x03,0x00,0x10,0x62,0x00,0x38,0x00,0x00,0x00,0x00, ++0x94,0xc2,0x00,0x56,0x00,0x00,0x00,0x00,0x30,0x47,0xff,0xff,0x30,0xe2,0x00,0x80, ++0x14,0x40,0x00,0x30,0x3c,0x02,0xb0,0x01,0x01,0x22,0x30,0x21,0x94,0xc3,0x00,0x60, ++0x24,0x02,0x00,0x08,0x14,0x43,0x00,0x3b,0x00,0x00,0x00,0x00,0x90,0xc2,0x00,0x62, ++0x24,0x03,0x00,0x04,0x00,0x02,0x39,0x02,0x10,0xe3,0x00,0x15,0x24,0x02,0x00,0x06, ++0x14,0xe2,0x00,0x34,0x00,0x00,0x00,0x00,0x8d,0x05,0x01,0xac,0x94,0xc4,0x00,0x66, ++0x27,0x82,0x92,0x48,0x00,0x05,0x28,0x80,0x30,0x87,0xff,0xff,0x00,0xa2,0x28,0x21, ++0x00,0x07,0x1a,0x00,0x8c,0xa4,0x00,0x00,0x00,0x07,0x12,0x02,0x00,0x43,0x10,0x25, ++0x24,0x42,0x00,0x5e,0x24,0x03,0xc0,0x00,0x30,0x47,0xff,0xff,0x00,0x83,0x20,0x24, ++0x00,0x87,0x20,0x25,0xac,0xa4,0x00,0x00,0x08,0x00,0x31,0x61,0xad,0x07,0x00,0x10, ++0x8d,0x05,0x01,0xac,0x94,0xc4,0x00,0x64,0x27,0x82,0x92,0x48,0x00,0x05,0x28,0x80, ++0x30,0x87,0xff,0xff,0x00,0xa2,0x28,0x21,0x00,0x07,0x1a,0x00,0x8c,0xa4,0x00,0x00, ++0x00,0x07,0x12,0x02,0x00,0x43,0x10,0x25,0x24,0x42,0x00,0x36,0x3c,0x03,0xff,0xff, ++0x30,0x47,0xff,0xff,0x00,0x83,0x20,0x24,0x00,0x87,0x20,0x25,0xac,0xa4,0x00,0x00, ++0xad,0x07,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x94,0xc2,0x00,0x50, ++0x08,0x00,0x31,0x1f,0x30,0x47,0xff,0xff,0x8d,0x04,0x01,0xac,0x27,0x83,0x92,0x48, ++0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0xff,0xff, ++0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x2e,0xac,0x82,0x00,0x00,0x24,0x03,0x00,0x2e, ++0xad,0x03,0x00,0x10,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8d,0x04,0x01,0xac, ++0x27,0x83,0x92,0x48,0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00, ++0x3c,0x03,0xff,0xff,0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x0e,0x24,0x03,0x00,0x0e, ++0x08,0x00,0x31,0x60,0xac,0x82,0x00,0x00,0x8d,0x04,0x01,0xac,0x27,0x83,0x92,0x48, ++0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0xff,0xff, ++0x00,0x43,0x10,0x24,0x34,0x42,0x00,0x14,0x24,0x03,0x00,0x14,0x08,0x00,0x31,0x60, ++0xac,0x82,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x30,0xc6,0x00,0xff, ++0x00,0x06,0x48,0x40,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80,0x27,0x8b,0xc5,0x70, ++0x27,0x83,0xc5,0x76,0x00,0x4b,0x40,0x21,0x00,0x43,0x10,0x21,0x94,0x47,0x00,0x00, ++0x30,0xa2,0x3f,0xff,0x10,0xe2,0x00,0x29,0x30,0x8a,0xff,0xff,0x95,0x02,0x00,0x02, ++0x24,0x03,0x00,0x01,0x00,0x02,0x11,0x82,0x30,0x42,0x00,0x01,0x10,0x43,0x00,0x18, ++0x00,0x00,0x00,0x00,0x01,0x26,0x10,0x21,0x00,0x02,0x10,0x80,0x00,0x4b,0x30,0x21, ++0x94,0xc4,0x00,0x02,0x27,0x83,0xc5,0x76,0x27,0x85,0xc5,0x74,0x00,0x45,0x28,0x21, ++0x30,0x84,0xff,0xdf,0x00,0x43,0x10,0x21,0xa4,0xc4,0x00,0x02,0xa4,0x40,0x00,0x00, ++0xa4,0xa0,0x00,0x00,0x94,0xc3,0x00,0x02,0x3c,0x04,0xb0,0x01,0x01,0x44,0x20,0x21, ++0x30,0x63,0xff,0xbf,0xa4,0xc3,0x00,0x02,0xa0,0xc0,0x00,0x00,0x8c,0x82,0x00,0x04, ++0x24,0x03,0xf0,0xff,0x00,0x43,0x10,0x24,0x03,0xe0,0x00,0x08,0xac,0x82,0x00,0x04, ++0x24,0x02,0xc0,0x00,0x91,0x04,0x00,0x01,0x00,0xa2,0x10,0x24,0x00,0x47,0x28,0x25, ++0x3c,0x03,0xb0,0x01,0x24,0x02,0x00,0x02,0x14,0x82,0xff,0xe2,0x01,0x43,0x18,0x21, ++0xac,0x65,0x00,0x00,0x08,0x00,0x31,0x8e,0x01,0x26,0x10,0x21,0x08,0x00,0x31,0x8e, ++0x01,0x26,0x10,0x21,0x93,0x83,0x88,0x6d,0x24,0x02,0x00,0x01,0x14,0x62,0x00,0x0d, ++0x3c,0x02,0xb0,0x01,0x8c,0x84,0x00,0x04,0x3c,0x06,0xb0,0x09,0x00,0x82,0x20,0x21, ++0x8c,0x85,0x00,0x08,0x8c,0x83,0x00,0x04,0x3c,0x02,0x01,0x00,0x34,0xc6,0x01,0x00, ++0x00,0x62,0x18,0x24,0x14,0x60,0x00,0x05,0x30,0xa5,0x20,0x00,0x24,0x02,0x00,0x06, ++0xa0,0xc2,0x00,0x00,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x09, ++0x10,0xa0,0xff,0xfc,0x34,0x63,0x01,0x00,0x24,0x02,0x00,0x0e,0x08,0x00,0x31,0xc1, ++0xa0,0x62,0x00,0x00,0x3c,0x02,0xb0,0x01,0x30,0xa5,0xff,0xff,0x00,0xa2,0x28,0x21, ++0x8c,0xa3,0x00,0x00,0x3c,0x02,0x10,0x00,0x00,0x80,0x30,0x21,0x00,0x62,0x18,0x24, ++0x8c,0xa2,0x00,0x04,0x10,0x60,0x00,0x04,0x00,0x00,0x00,0x00,0x30,0x42,0x80,0x00, ++0x10,0x40,0x00,0x13,0x00,0x00,0x00,0x00,0x8c,0xc2,0x01,0xa8,0x00,0x00,0x00,0x00, ++0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a, ++0x93,0x83,0x88,0x6c,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23, ++0x24,0x63,0xff,0xff,0xac,0xc4,0x01,0xa8,0xa3,0x83,0x88,0x6c,0x8c,0xc4,0x01,0xac, ++0x8c,0xc2,0x01,0xa8,0x00,0x00,0x00,0x00,0x00,0x44,0x10,0x26,0x00,0x02,0x10,0x2b, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x3c,0x03,0xb0,0x03,0x34,0x63,0x00,0x73, ++0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x01,0x14,0x40,0x00,0x04, ++0x00,0x00,0x00,0x00,0xa3,0x80,0x88,0x6d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x24,0x02,0x00,0x01,0xa3,0x82,0x88,0x6d,0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00, ++0x8c,0x82,0x00,0x04,0x3c,0x05,0xb0,0x01,0x00,0x80,0x50,0x21,0x00,0x45,0x10,0x21, ++0x8c,0x43,0x00,0x04,0x24,0x02,0x00,0x05,0x00,0x03,0x1a,0x02,0x30,0x69,0x00,0x0f, ++0x11,0x22,0x00,0x0b,0x24,0x02,0x00,0x07,0x11,0x22,0x00,0x09,0x24,0x02,0x00,0x0a, ++0x11,0x22,0x00,0x07,0x24,0x02,0x00,0x0b,0x11,0x22,0x00,0x05,0x24,0x02,0x00,0x01, ++0x93,0x83,0x88,0x6c,0x3c,0x04,0xb0,0x06,0x10,0x62,0x00,0x03,0x34,0x84,0x80,0x18, ++0x03,0xe0,0x00,0x08,0x00,0x00,0x00,0x00,0x8c,0x82,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x02,0x17,0x02,0x14,0x40,0xff,0xfa,0x00,0x00,0x00,0x00,0x8d,0x43,0x01,0xa8, ++0x27,0x82,0x92,0x48,0x00,0x03,0x18,0x80,0x00,0x6a,0x20,0x21,0x8c,0x87,0x00,0xa8, ++0x00,0x62,0x18,0x21,0x8c,0x68,0x00,0x00,0x00,0xe5,0x28,0x21,0x8c,0xa9,0x00,0x00, ++0x3c,0x02,0xff,0xff,0x27,0x83,0x93,0x48,0x01,0x22,0x10,0x24,0x00,0x48,0x10,0x25, ++0xac,0xa2,0x00,0x00,0x8d,0x44,0x01,0xa8,0x00,0x07,0x30,0xc2,0x3c,0x02,0x00,0x80, ++0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x00,0x06,0x32,0x00,0x8c,0xa9,0x00,0x04, ++0x00,0xc2,0x30,0x25,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00,0x01,0x22,0x10,0x25, ++0x00,0x43,0x10,0x25,0xac,0xa2,0x00,0x04,0xaf,0x87,0xc5,0x60,0x8c,0xa2,0x00,0x00, ++0x00,0x00,0x00,0x00,0xaf,0x82,0xc5,0x68,0x8c,0xa3,0x00,0x04,0x3c,0x01,0xb0,0x07, ++0xac,0x26,0x80,0x18,0x8d,0x42,0x01,0xa8,0xaf,0x83,0xc5,0x64,0x93,0x85,0x88,0x6c, ++0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a, ++0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x24,0xa5,0xff,0xff,0x00,0x82,0x20,0x23, ++0xad,0x44,0x01,0xa8,0xa3,0x85,0x88,0x6c,0x08,0x00,0x32,0x0c,0x00,0x00,0x00,0x00, ++0x3c,0x05,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0xa5,0x00,0x20,0x24,0x42,0xc9,0x10, ++0xac,0xa2,0x00,0x00,0x24,0x02,0x00,0x02,0x24,0x03,0x00,0x20,0xac,0x82,0x00,0x64, ++0x3c,0x02,0x80,0x01,0xac,0x83,0x00,0x60,0xac,0x80,0x00,0x00,0xac,0x80,0x00,0x04, ++0xac,0x80,0x00,0x08,0xac,0x80,0x00,0x4c,0xac,0x80,0x00,0x50,0xac,0x80,0x00,0x54, ++0xac,0x80,0x00,0x0c,0xac,0x80,0x00,0x58,0xa0,0x80,0x00,0x5c,0x24,0x42,0xc9,0xd4, ++0x24,0x83,0x00,0x68,0x24,0x05,0x00,0x0f,0x24,0xa5,0xff,0xff,0xac,0x62,0x00,0x00, ++0x04,0xa1,0xff,0xfd,0x24,0x63,0x00,0x04,0x3c,0x02,0x80,0x01,0x24,0x42,0xcb,0x04, ++0xac,0x82,0x00,0x78,0x3c,0x03,0x80,0x01,0x3c,0x02,0x80,0x01,0x24,0x63,0xcc,0x90, ++0x24,0x42,0xcb,0xfc,0xac,0x83,0x00,0x88,0xac,0x82,0x00,0x98,0x3c,0x03,0x80,0x01, ++0x3c,0x02,0x80,0x01,0x24,0x63,0xcd,0x38,0x24,0x42,0xce,0x50,0xac,0x83,0x00,0xa0, ++0xac,0x82,0x00,0xa4,0xa0,0x80,0x01,0xba,0xac,0x80,0x01,0xa8,0xac,0x80,0x01,0xac, ++0xac,0x80,0x01,0xb0,0xac,0x80,0x01,0xb4,0xa0,0x80,0x01,0xb8,0x03,0xe0,0x00,0x08, ++0xa0,0x80,0x01,0xb9,0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20, ++0x24,0x42,0xc9,0xd4,0x03,0xe0,0x00,0x08,0xac,0x62,0x00,0x00,0x3c,0x03,0xb0,0x03, ++0x3c,0x02,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x63,0x00,0x20,0x24,0x42,0xc9,0xec, ++0xaf,0xb0,0x00,0x10,0xac,0x62,0x00,0x00,0xaf,0xbf,0x00,0x14,0x8c,0x83,0x00,0x10, ++0x8f,0x82,0x94,0xe8,0x00,0x80,0x80,0x21,0x3c,0x04,0x80,0x01,0x30,0x46,0x00,0x01, ++0x10,0x60,0x00,0x11,0x24,0x84,0x08,0x64,0x8e,0x02,0x00,0x14,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x0d,0x00,0x00,0x00,0x00,0x8e,0x05,0x00,0x10,0x8e,0x03,0x00,0x14, ++0x8e,0x02,0x00,0x04,0x00,0xa3,0x28,0x21,0x00,0x45,0x10,0x21,0x30,0x43,0x00,0xff, ++0x00,0x03,0x18,0x2b,0x00,0x02,0x12,0x02,0x00,0x43,0x10,0x21,0x00,0x02,0x12,0x00, ++0x30,0x42,0x3f,0xff,0xae,0x02,0x00,0x04,0x14,0xc0,0x00,0x0a,0x00,0x00,0x00,0x00, ++0xae,0x00,0x00,0x00,0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54, ++0xae,0x00,0x00,0x0c,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x18,0x8e,0x05,0x00,0x10,0x8e,0x07,0x00,0x04,0x8e,0x06,0x00,0x14, ++0x0c,0x00,0x1a,0x6b,0x00,0x00,0x00,0x00,0x08,0x00,0x32,0x9d,0xae,0x00,0x00,0x00, ++0x3c,0x03,0xb0,0x03,0x3c,0x02,0x80,0x01,0x34,0x63,0x00,0x20,0x24,0x42,0xca,0xb0, ++0xac,0x62,0x00,0x00,0x8c,0x86,0x00,0x04,0x3c,0x02,0xb0,0x01,0x24,0x03,0x00,0x01, ++0x00,0xc2,0x10,0x21,0x8c,0x45,0x00,0x00,0xac,0x83,0x00,0x4c,0x00,0x05,0x14,0x02, ++0x30,0xa3,0x3f,0xff,0x30,0x42,0x00,0xff,0xac,0x83,0x00,0x10,0xac,0x82,0x00,0x14, ++0x8c,0x83,0x00,0x14,0xac,0x85,0x00,0x40,0x00,0xc3,0x30,0x21,0x03,0xe0,0x00,0x08, ++0xac,0x86,0x00,0x08,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8, ++0x34,0x42,0x00,0x20,0x24,0x63,0xcb,0x04,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, ++0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x0a, ++0x00,0x80,0x80,0x21,0xae,0x00,0x00,0x00,0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50, ++0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x32,0xac,0x00,0x00,0x00,0x00, ++0x08,0x00,0x32,0xce,0xae,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, ++0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xcb,0x68,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x4c,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x16,0x00,0x80,0x80,0x21,0x8e,0x03,0x00,0x08,0x3c,0x02,0xb0,0x01, ++0x8e,0x04,0x00,0x44,0x00,0x62,0x18,0x21,0x90,0x65,0x00,0x00,0x24,0x02,0x00,0x01, ++0xae,0x02,0x00,0x50,0x30,0xa3,0x00,0xff,0x00,0x03,0x10,0x82,0x00,0x04,0x23,0x02, ++0x30,0x84,0x00,0x0f,0x30,0x42,0x00,0x03,0x00,0x03,0x19,0x02,0xae,0x04,0x00,0x34, ++0xae,0x02,0x00,0x2c,0xae,0x03,0x00,0x30,0xa2,0x05,0x00,0x48,0x8f,0xbf,0x00,0x14, ++0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x32,0xac, ++0x00,0x00,0x00,0x00,0x08,0x00,0x32,0xe6,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03, ++0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xcb,0xfc, ++0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x50, ++0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x16,0x00,0x80,0x80,0x21,0x92,0x03,0x00,0x44, ++0x8e,0x02,0x00,0x40,0x83,0x85,0x95,0x14,0x92,0x04,0x00,0x41,0x30,0x63,0x00,0x01, ++0x00,0x02,0x16,0x02,0xae,0x04,0x00,0x14,0x00,0x00,0x30,0x21,0xae,0x02,0x00,0x18, ++0x10,0xa0,0x00,0x04,0xae,0x03,0x00,0x3c,0x10,0x60,0x00,0x03,0x24,0x02,0x00,0x01, ++0x24,0x06,0x00,0x01,0x24,0x02,0x00,0x01,0xa3,0x86,0x95,0x14,0x8f,0xbf,0x00,0x14, ++0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x0c,0x00,0x32,0xda,0x00,0x00,0x00,0x00,0x08,0x00,0x33,0x0b,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, ++0x24,0x63,0xcc,0x90,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, ++0x8c,0x82,0x00,0x50,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x1b,0x00,0x80,0x80,0x21, ++0x3c,0x02,0xb0,0x03,0x8c,0x42,0x00,0x00,0x92,0x04,0x00,0x44,0x8e,0x03,0x00,0x40, ++0x83,0x86,0x95,0x14,0x92,0x05,0x00,0x41,0x30,0x42,0x08,0x00,0x30,0x84,0x00,0x01, ++0x00,0x02,0x12,0xc2,0x00,0x03,0x1e,0x02,0x00,0x82,0x20,0x25,0xae,0x05,0x00,0x14, ++0x00,0x00,0x38,0x21,0xae,0x03,0x00,0x18,0x10,0xc0,0x00,0x04,0xae,0x04,0x00,0x3c, ++0x10,0x80,0x00,0x03,0x24,0x02,0x00,0x01,0x24,0x07,0x00,0x01,0x24,0x02,0x00,0x01, ++0xa3,0x87,0x95,0x14,0x8f,0xbf,0x00,0x14,0xae,0x02,0x00,0x54,0x8f,0xb0,0x00,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x32,0xda,0x00,0x00,0x00,0x00, ++0x08,0x00,0x33,0x30,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, ++0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20,0x24,0x63,0xcd,0x38,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00,0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00, ++0x10,0x40,0x00,0x37,0x00,0x80,0x80,0x21,0x8e,0x04,0x00,0x04,0x8e,0x03,0x00,0x44, ++0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x01,0x34,0x42,0x00,0x10,0x00,0x85,0x20,0x21, ++0x00,0x62,0x18,0x25,0xac,0x83,0x00,0x04,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac, ++0x02,0x00,0x20,0x21,0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x00,0x00,0x03,0x18,0x80, ++0x27,0x82,0x92,0x48,0x00,0x62,0x18,0x21,0xac,0x66,0x00,0x00,0x8e,0x02,0x00,0x04, ++0x8e,0x03,0x01,0xac,0x00,0x45,0x10,0x21,0x8c,0x46,0x00,0x04,0x00,0x03,0x18,0x80, ++0x27,0x82,0x93,0x48,0x00,0x62,0x18,0x21,0x0c,0x00,0x30,0xfb,0xac,0x66,0x00,0x00, ++0x8e,0x03,0x01,0xac,0x8e,0x07,0x00,0x04,0x3c,0x06,0xb0,0x03,0x24,0x65,0x00,0x01, ++0x28,0xa4,0x00,0x00,0x24,0x62,0x00,0x40,0x00,0xa4,0x10,0x0a,0x00,0x02,0x11,0x83, ++0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80,0x00,0xa2,0x28,0x23,0x00,0x70,0x18,0x21, ++0xae,0x05,0x01,0xac,0xac,0x67,0x00,0xa8,0x34,0xc6,0x00,0x30,0x8c,0xc3,0x00,0x00, ++0x93,0x82,0x88,0x6c,0x02,0x00,0x20,0x21,0x24,0x63,0x00,0x01,0x24,0x42,0x00,0x01, ++0xac,0xc3,0x00,0x00,0xa3,0x82,0x88,0x6c,0x0c,0x00,0x32,0x7b,0x00,0x00,0x00,0x00, ++0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18, ++0x0c,0x00,0x33,0x24,0x00,0x00,0x00,0x00,0x08,0x00,0x33,0x5a,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x27,0xbd,0xff,0xe8,0x34,0x42,0x00,0x20, ++0x24,0x63,0xce,0x50,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14,0xac,0x43,0x00,0x00, ++0x8c,0x82,0x00,0x54,0x00,0x00,0x00,0x00,0x10,0x40,0x00,0x37,0x00,0x80,0x80,0x21, ++0x8e,0x04,0x00,0x04,0x8e,0x03,0x00,0x44,0x3c,0x02,0x80,0x00,0x3c,0x05,0xb0,0x01, ++0x34,0x42,0x00,0x10,0x00,0x85,0x20,0x21,0x00,0x62,0x18,0x25,0xac,0x83,0x00,0x04, ++0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x02,0x00,0x20,0x21,0x00,0x45,0x10,0x21, ++0x8c,0x46,0x00,0x00,0x00,0x03,0x18,0x80,0x27,0x82,0x92,0x48,0x00,0x62,0x18,0x21, ++0xac,0x66,0x00,0x00,0x8e,0x02,0x00,0x04,0x8e,0x03,0x01,0xac,0x00,0x45,0x10,0x21, ++0x8c,0x46,0x00,0x04,0x00,0x03,0x18,0x80,0x27,0x82,0x93,0x48,0x00,0x62,0x18,0x21, ++0x0c,0x00,0x30,0xfb,0xac,0x66,0x00,0x00,0x8e,0x03,0x01,0xac,0x8e,0x07,0x00,0x04, ++0x3c,0x06,0xb0,0x03,0x24,0x65,0x00,0x01,0x28,0xa4,0x00,0x00,0x24,0x62,0x00,0x40, ++0x00,0xa4,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x03,0x18,0x80, ++0x00,0xa2,0x28,0x23,0x00,0x70,0x18,0x21,0xae,0x05,0x01,0xac,0xac,0x67,0x00,0xa8, ++0x34,0xc6,0x00,0x30,0x8c,0xc3,0x00,0x00,0x93,0x82,0x88,0x6c,0x02,0x00,0x20,0x21, ++0x24,0x63,0x00,0x01,0x24,0x42,0x00,0x01,0xac,0xc3,0x00,0x00,0xa3,0x82,0x88,0x6c, ++0x0c,0x00,0x32,0x7b,0x00,0x00,0x00,0x00,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x0c,0x00,0x33,0x24,0x00,0x00,0x00,0x00, ++0x08,0x00,0x33,0xa0,0x00,0x00,0x00,0x00,0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01, ++0x34,0x42,0x00,0x20,0x24,0x63,0xcf,0x68,0x27,0xbd,0xff,0xe0,0xac,0x43,0x00,0x00, ++0x3c,0x02,0x80,0x01,0xaf,0xb2,0x00,0x18,0xaf,0xb1,0x00,0x14,0xaf,0xb0,0x00,0x10, ++0xaf,0xbf,0x00,0x1c,0x00,0x80,0x80,0x21,0x24,0x52,0xc9,0xd4,0x00,0x00,0x88,0x21, ++0x3c,0x03,0xb0,0x09,0x34,0x63,0x00,0x06,0x8e,0x06,0x00,0x04,0x90,0x62,0x00,0x00, ++0x00,0x06,0x22,0x02,0x00,0x44,0x10,0x23,0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00, ++0x24,0x42,0x00,0x7f,0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80, ++0x24,0x84,0xff,0xff,0x10,0x44,0x00,0x68,0x00,0x00,0x28,0x21,0x3c,0x02,0xb0,0x01, ++0x00,0xc2,0x10,0x21,0x8c,0x44,0x00,0x04,0x3c,0x03,0x7c,0x00,0x34,0x63,0x00,0xf0, ++0x00,0x83,0x18,0x24,0xae,0x04,0x00,0x44,0x8c,0x44,0x00,0x00,0x10,0x60,0x00,0x69, ++0x00,0x00,0x38,0x21,0x3c,0x09,0xb0,0x03,0x3c,0x06,0x7c,0x00,0x35,0x29,0x00,0x99, ++0x3c,0x0a,0xb0,0x01,0x24,0x08,0x00,0x40,0x34,0xc6,0x00,0xf0,0x3c,0x0b,0xff,0xff, ++0x3c,0x0c,0x28,0x38,0x16,0x20,0x00,0x06,0x24,0xa5,0x00,0x01,0x93,0x82,0x88,0xa0, ++0x24,0x11,0x00,0x01,0x24,0x42,0x00,0x01,0xa1,0x22,0x00,0x00,0xa3,0x82,0x88,0xa0, ++0x8e,0x02,0x00,0x04,0x24,0x07,0x00,0x01,0x24,0x42,0x01,0x00,0x30,0x42,0x3f,0xff, ++0xae,0x02,0x00,0x04,0x00,0x4a,0x10,0x21,0x8c,0x43,0x00,0x04,0x00,0x00,0x00,0x00, ++0xae,0x03,0x00,0x44,0x8c,0x44,0x00,0x00,0x10,0xa8,0x00,0x2d,0x00,0x66,0x18,0x24, ++0x14,0x60,0xff,0xec,0x00,0x8b,0x10,0x24,0x14,0x4c,0xff,0xea,0x24,0x02,0x00,0x01, ++0x10,0xe2,0x00,0x2f,0x3c,0x03,0xb0,0x09,0x8e,0x02,0x00,0x44,0x8e,0x04,0x00,0x60, ++0x00,0x02,0x1e,0x42,0x00,0x02,0x12,0x02,0x30,0x42,0x00,0x0f,0x30,0x63,0x00,0x01, ++0xae,0x02,0x00,0x00,0x10,0x44,0x00,0x1a,0xae,0x03,0x00,0x58,0x8e,0x02,0x00,0x64, ++0x8e,0x04,0x00,0x58,0x00,0x00,0x00,0x00,0x10,0x82,0x00,0x05,0x00,0x00,0x00,0x00, ++0xae,0x00,0x00,0x4c,0xae,0x00,0x00,0x50,0xae,0x00,0x00,0x54,0xae,0x00,0x00,0x0c, ++0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x80,0x00,0x50,0x10,0x21, ++0x8c,0x42,0x00,0x68,0x00,0x00,0x00,0x00,0x10,0x52,0x00,0x06,0x00,0x00,0x00,0x00, ++0x00,0x40,0xf8,0x09,0x02,0x00,0x20,0x21,0x8e,0x04,0x00,0x58,0x8e,0x03,0x00,0x00, ++0x00,0x00,0x00,0x00,0xae,0x03,0x00,0x60,0x08,0x00,0x33,0xe8,0xae,0x04,0x00,0x64, ++0x8e,0x02,0x00,0x64,0x00,0x00,0x00,0x00,0x14,0x62,0xff,0xe5,0x00,0x00,0x00,0x00, ++0x7a,0x02,0x0d,0x7c,0x8f,0xbf,0x00,0x1c,0x8f,0xb2,0x00,0x18,0x7b,0xb0,0x00,0xbc, ++0x00,0x43,0x10,0x26,0x00,0x02,0x10,0x2b,0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x20, ++0x34,0x63,0x00,0x06,0x8e,0x04,0x00,0x04,0x90,0x62,0x00,0x00,0x00,0x04,0x22,0x02, ++0x00,0x44,0x10,0x23,0x24,0x44,0x00,0x40,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x7f, ++0x00,0x83,0x10,0x0a,0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23, ++0x14,0x87,0xff,0xc5,0x00,0x00,0x00,0x00,0x8e,0x03,0x00,0x00,0x00,0x00,0x00,0x00, ++0x2c,0x62,0x00,0x03,0x14,0x40,0x00,0x05,0x24,0x02,0x00,0x0d,0x10,0x62,0x00,0x03, ++0x24,0x02,0x00,0x01,0x08,0x00,0x34,0x48,0xa2,0x02,0x00,0x5c,0x08,0x00,0x34,0x48, ++0xa2,0x00,0x00,0x5c,0x3c,0x02,0xff,0xff,0x00,0x82,0x10,0x24,0x3c,0x03,0x28,0x38, ++0x14,0x43,0xff,0x94,0x24,0x02,0x00,0x01,0x08,0x00,0x34,0x20,0x00,0x00,0x00,0x00, ++0x3c,0x02,0xb0,0x03,0x3c,0x03,0x80,0x01,0x34,0x42,0x00,0x20,0x24,0x63,0xd1,0xc0, ++0xac,0x43,0x00,0x00,0x8c,0x83,0x01,0xa8,0x8c,0x82,0x01,0xac,0x00,0x80,0x40,0x21, ++0x10,0x62,0x00,0x20,0x00,0x00,0x20,0x21,0x93,0x82,0x88,0x6d,0x00,0x03,0x28,0x80, ++0x3c,0x07,0xb0,0x06,0x00,0xa8,0x18,0x21,0x24,0x04,0x00,0x01,0x8c,0x66,0x00,0xa8, ++0x10,0x44,0x00,0x1c,0x34,0xe7,0x80,0x18,0x3c,0x05,0xb0,0x01,0xaf,0x86,0xc5,0x60, ++0x00,0xc5,0x28,0x21,0x8c,0xa3,0x00,0x00,0x00,0x06,0x20,0xc2,0x3c,0x02,0x00,0x80, ++0x00,0x04,0x22,0x00,0x00,0x82,0x20,0x25,0xaf,0x83,0xc5,0x68,0x8c,0xa2,0x00,0x04, ++0xac,0xe4,0x00,0x00,0x8d,0x03,0x01,0xa8,0xaf,0x82,0xc5,0x64,0x24,0x64,0x00,0x01, ++0x04,0x80,0x00,0x0a,0x00,0x80,0x10,0x21,0x00,0x02,0x11,0x83,0x8d,0x03,0x01,0xac, ++0x00,0x02,0x11,0x80,0x00,0x82,0x10,0x23,0x00,0x43,0x18,0x26,0xad,0x02,0x01,0xa8, ++0x00,0x03,0x20,0x2b,0x03,0xe0,0x00,0x08,0x00,0x80,0x10,0x21,0x08,0x00,0x34,0x92, ++0x24,0x62,0x00,0x40,0x27,0x82,0x92,0x48,0x00,0x06,0x20,0xc2,0x00,0x04,0x22,0x00, ++0x00,0xa2,0x48,0x21,0x3c,0x02,0x00,0x80,0x00,0x82,0x58,0x25,0x93,0x82,0x88,0x6c, ++0x3c,0x0a,0xb0,0x06,0x3c,0x03,0xb0,0x01,0x2c,0x42,0x00,0x02,0x00,0xc3,0x38,0x21, ++0x35,0x4a,0x80,0x18,0x14,0x40,0xff,0xef,0x00,0x00,0x20,0x21,0x8c,0xe5,0x00,0x00, ++0x8d,0x23,0x00,0x00,0x24,0x02,0xc0,0x00,0x00,0xa2,0x10,0x24,0x00,0x43,0x10,0x25, ++0xac,0xe2,0x00,0x00,0x8d,0x04,0x01,0xa8,0x27,0x83,0x93,0x48,0x8c,0xe5,0x00,0x04, ++0x00,0x04,0x20,0x80,0x00,0x83,0x20,0x21,0x8c,0x82,0x00,0x00,0x3c,0x03,0x80,0x00, ++0x00,0xa2,0x10,0x25,0x00,0x43,0x10,0x25,0xac,0xe2,0x00,0x04,0xaf,0x86,0xc5,0x60, ++0x8c,0xe2,0x00,0x00,0x93,0x85,0x88,0x6c,0xaf,0x82,0xc5,0x68,0x8c,0xe3,0x00,0x04, ++0xad,0x4b,0x00,0x00,0x8d,0x02,0x01,0xa8,0xaf,0x83,0xc5,0x64,0x24,0xa5,0xff,0xff, ++0x24,0x44,0x00,0x01,0x28,0x83,0x00,0x00,0x24,0x42,0x00,0x40,0x00,0x83,0x10,0x0a, ++0x00,0x02,0x11,0x83,0x00,0x02,0x11,0x80,0x00,0x82,0x20,0x23,0xad,0x04,0x01,0xa8, ++0xa3,0x85,0x88,0x6c,0x79,0x02,0x0d,0x7c,0x00,0x00,0x00,0x00,0x00,0x43,0x10,0x26, ++0x08,0x00,0x34,0x99,0x00,0x02,0x20,0x2b,0x90,0x87,0x00,0x00,0x3c,0x02,0x80,0x01, ++0x27,0xbd,0xff,0xe8,0x24,0x48,0x02,0x1c,0xaf,0xb0,0x00,0x10,0xaf,0xbf,0x00,0x14, ++0x01,0x07,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x20, ++0x10,0x40,0x00,0x0a,0x00,0x00,0x80,0x21,0x24,0x84,0x00,0x01,0x90,0x87,0x00,0x00, ++0x00,0x00,0x00,0x00,0x01,0x07,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x20,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00,0x00,0x07,0x16,0x00, ++0x00,0x02,0x16,0x03,0x24,0x03,0x00,0x2d,0x10,0x43,0x00,0x0f,0x00,0x00,0x00,0x00, ++0x0c,0x00,0x34,0xfd,0x00,0x00,0x00,0x00,0x00,0x40,0x18,0x21,0x00,0x02,0x10,0x23, ++0x04,0x61,0x00,0x05,0x00,0x70,0x10,0x0a,0x16,0x00,0x00,0x03,0x3c,0x02,0x80,0x00, ++0x3c,0x02,0x7f,0xff,0x34,0x42,0xff,0xff,0x8f,0xbf,0x00,0x14,0x8f,0xb0,0x00,0x10, ++0x03,0xe0,0x00,0x08,0x27,0xbd,0x00,0x18,0x24,0x10,0xff,0xff,0x08,0x00,0x34,0xec, ++0x24,0x84,0x00,0x01,0x00,0x80,0x38,0x21,0x90,0x84,0x00,0x00,0x3c,0x02,0x80,0x01, ++0x24,0x48,0x02,0x1c,0x01,0x04,0x18,0x21,0x90,0x62,0x00,0x00,0x00,0x00,0x00,0x00, ++0x30,0x42,0x00,0x20,0x10,0x40,0x00,0x0a,0x00,0x00,0x50,0x21,0x24,0xe7,0x00,0x01, ++0x90,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x18,0x21,0x90,0x62,0x00,0x00, ++0x00,0x00,0x00,0x00,0x30,0x42,0x00,0x20,0x14,0x40,0xff,0xf8,0x00,0x00,0x00,0x00, ++0x00,0x04,0x16,0x00,0x00,0x02,0x16,0x03,0x38,0x42,0x00,0x2b,0x24,0xe3,0x00,0x01, ++0x24,0x04,0x00,0x10,0x10,0xc4,0x00,0x38,0x00,0x62,0x38,0x0a,0x90,0xe4,0x00,0x00, ++0x14,0xc0,0x00,0x07,0x00,0x80,0x18,0x21,0x00,0x04,0x16,0x00,0x00,0x02,0x16,0x03, ++0x24,0x03,0x00,0x30,0x10,0x43,0x00,0x25,0x24,0x06,0x00,0x0a,0x00,0x80,0x18,0x21, ++0x00,0x03,0x16,0x00,0x10,0x40,0x00,0x1a,0x30,0x64,0x00,0xff,0x24,0x82,0xff,0xa9, ++0x2c,0x83,0x00,0x61,0x30,0x48,0x00,0xff,0x10,0x60,0x00,0x09,0x2c,0x89,0x00,0x41, ++0x24,0x82,0xff,0xc9,0x30,0x48,0x00,0xff,0x11,0x20,0x00,0x05,0x2c,0x83,0x00,0x3a, ++0x24,0x82,0xff,0xd0,0x14,0x60,0x00,0x02,0x30,0x48,0x00,0xff,0x24,0x08,0x00,0xff, ++0x01,0x06,0x10,0x2a,0x10,0x40,0x00,0x0a,0x01,0x46,0x00,0x18,0x24,0xe7,0x00,0x01, ++0x00,0x00,0x18,0x12,0x00,0x6a,0x10,0x2b,0x14,0x40,0x00,0x0a,0x00,0x68,0x50,0x21, ++0x80,0xe2,0x00,0x00,0x90,0xe3,0x00,0x00,0x14,0x40,0xff,0xe8,0x30,0x64,0x00,0xff, ++0x10,0xa0,0x00,0x02,0x00,0x00,0x00,0x00,0xac,0xa7,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x01,0x40,0x10,0x21,0x03,0xe0,0x00,0x08,0x24,0x02,0xff,0xff,0x24,0x06,0x00,0x08, ++0x80,0xe3,0x00,0x01,0x24,0x02,0x00,0x78,0x10,0x62,0x00,0x03,0x24,0x02,0x00,0x58, ++0x14,0x62,0xff,0xd7,0x00,0x80,0x18,0x21,0x24,0xe7,0x00,0x02,0x90,0xe4,0x00,0x00, ++0x08,0x00,0x35,0x1f,0x24,0x06,0x00,0x10,0x80,0xe3,0x00,0x00,0x24,0x02,0x00,0x30, ++0x90,0xe4,0x00,0x00,0x10,0x62,0xff,0xf2,0x00,0x00,0x00,0x00,0x08,0x00,0x35,0x18, ++0x00,0x00,0x00,0x00,0x3c,0x04,0xb0,0x03,0x3c,0x06,0xb0,0x07,0x3c,0x02,0x80,0x01, ++0x34,0xc6,0x00,0x18,0x34,0x84,0x00,0x20,0x24,0x42,0xd5,0x54,0x24,0x03,0xff,0x83, ++0xac,0x82,0x00,0x00,0xa0,0xc3,0x00,0x00,0x90,0xc4,0x00,0x00,0x27,0xbd,0xff,0xf8, ++0x3c,0x03,0xb0,0x07,0x24,0x02,0xff,0x82,0xa3,0xa4,0x00,0x00,0xa0,0x62,0x00,0x00, ++0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x08,0xa3,0xa4,0x00,0x01, ++0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x24,0x02,0x00,0x03,0x3c,0x05,0xb0,0x07, ++0xa3,0xa3,0x00,0x00,0xa0,0xc2,0x00,0x00,0x90,0xc4,0x00,0x00,0x34,0xa5,0x00,0x10, ++0x24,0x02,0x00,0x06,0x3c,0x03,0xb0,0x07,0xa3,0xa4,0x00,0x00,0x34,0x63,0x00,0x38, ++0xa0,0xa2,0x00,0x00,0x90,0x64,0x00,0x00,0x3c,0x02,0xb0,0x07,0x34,0x42,0x00,0x20, ++0xa3,0xa4,0x00,0x00,0xa0,0xa0,0x00,0x00,0x90,0xa3,0x00,0x00,0xaf,0x82,0xc8,0x70, ++0xa3,0xa3,0x00,0x00,0xa0,0x40,0x00,0x00,0x90,0x43,0x00,0x00,0x03,0xe0,0x00,0x08, ++0x27,0xbd,0x00,0x08,}; ++ ++u8 rtl8190_fwdata_array[] = { ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x0a,0x0d,0x5b,0x43,0x4d,0x50,0x4b,0x5d,0x00,0x00,0x00,0x00, ++0x80,0x01,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08, ++0x08,0x08,0x08,0x08,0x08,0x28,0x28,0x28,0x28,0x28,0x08,0x08,0x08,0x08,0x08,0x08, ++0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0xa0,0x10,0x10,0x10, ++0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x04,0x04,0x04,0x04, ++0x04,0x04,0x04,0x04,0x04,0x04,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x41,0x41,0x41, ++0x41,0x41,0x41,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x10,0x10,0x10,0x10,0x10,0x10,0x42,0x42,0x42, ++0x42,0x42,0x42,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, ++0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x10,0x10,0x10,0x10,0x08,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x10,0x10,0x10, ++0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, ++0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x01,0x01,0x01,0x01, ++0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++0x01,0x01,0x01,0x10,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02, ++0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, ++0x02,0x02,0x02,0x10,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x20,0x09,0x0d,0x0a, ++0x00,0x00,0x00,0x00,0x80,0x01,0x03,0x1c,0x00,0x00,0x00,0x00,0x43,0x6e,0x73,0x64, ++0x31,0x00,0x00,0x00,0x68,0x65,0x6c,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x72,0x34,0x00,0x00,0x77,0x34,0x00,0x00,0x64,0x62,0x67,0x00,0x72,0x61,0x63,0x74, ++0x72,0x6c,0x00,0x00,0x73,0x79,0x73,0x64,0x00,0x00,0x00,0x00,0x73,0x79,0x73,0x63, ++0x74,0x72,0x6c,0x00,0x74,0x78,0x74,0x62,0x6c,0x00,0x00,0x00,0x70,0x72,0x61,0x6e, ++0x67,0x65,0x00,0x00,0x64,0x6d,0x00,0x00,0x75,0x6e,0x6b,0x6e,0x6f,0x77,0x00,0x00, ++0x80,0x01,0x03,0x34,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01, ++0x00,0x00,0x00,0x00,0x80,0x00,0x24,0x5c,0x80,0x01,0x03,0x40,0x80,0x01,0x03,0x3c, ++0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x25,0xbc, ++0x80,0x01,0x03,0x44,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01, ++0x00,0x00,0x00,0x00,0x80,0x00,0x27,0x38,0x80,0x01,0x03,0x48,0x80,0x01,0x03,0x3c, ++0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x29,0x04, ++0x80,0x01,0x03,0x4c,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01, ++0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xdc,0x80,0x01,0x03,0x54,0x80,0x01,0x03,0x3c, ++0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xe4, ++0x80,0x01,0x03,0x5c,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01, ++0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xec,0x80,0x01,0x03,0x64,0x80,0x01,0x03,0x3c, ++0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xf4, ++0x80,0x01,0x03,0x6c,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01, ++0x00,0x00,0x00,0x00,0x80,0x00,0x2b,0x80,0x80,0x01,0x03,0x74,0x80,0x01,0x03,0x3c, ++0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x80,0x00,0x2b,0xf4, ++0x80,0x01,0x03,0x78,0x80,0x01,0x03,0x3c,0x80,0x01,0x03,0x3c,0x00,0x00,0x00,0x0f, ++0x00,0x00,0x00,0x01,0x80,0x00,0x2c,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x0a,0x0d,0x52,0x54,0x4c,0x38,0x31,0x39,0x58,0x2d,0x25,0x64,0x3e,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x52,0x54,0x4c,0x38,0x31,0x39,0x58,0x2d,0x25,0x64,0x3e,0x0a, ++0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x0a,0x0d,0x45,0x72, ++0x72,0x20,0x44,0x49,0x52,0x00,0x00,0x00,0x0a,0x0d,0x44,0x42,0x47,0x20,0x43,0x4d, ++0x44,0x73,0x3a,0x00,0x0a,0x0d,0x5b,0x00,0x5d,0x2d,0x00,0x00,0x0a,0x0d,0x3c,0x31, ++0x2e,0x43,0x4d,0x4e,0x3e,0x20,0x3c,0x32,0x2e,0x3f,0x3e,0x00,0x0a,0x0d,0x20,0x79, ++0x65,0x61,0x72,0x2d,0x64,0x61,0x79,0x2d,0x68,0x6f,0x75,0x72,0x2d,0x6d,0x69,0x6e, ++0x2d,0x73,0x65,0x63,0x2d,0x31,0x30,0x6d,0x73,0x3d,0x00,0x00,0x25,0x64,0x2d,0x00, ++0x0a,0x0d,0x09,0x20,0x20,0x20,0x20,0x20,0x30,0x30,0x20,0x20,0x20,0x20,0x20,0x20, ++0x20,0x30,0x34,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x38,0x20,0x20,0x20,0x20, ++0x20,0x20,0x20,0x30,0x43,0x00,0x00,0x00,0x0a,0x0d,0x09,0x20,0x20,0x20,0x20,0x20, ++0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, ++0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d,0x3d, ++0x3d,0x3d,0x3d,0x00,0x0d,0x0a,0x20,0x30,0x78,0x25,0x30,0x38,0x58,0x20,0x20,0x00, ++0x09,0x00,0x00,0x00,0x25,0x30,0x38,0x58,0x20,0x00,0x00,0x00,0x0a,0x0d,0x44,0x62, ++0x67,0x5f,0x46,0x6c,0x61,0x67,0x25,0x64,0x3d,0x30,0x78,0x25,0x30,0x38,0x78,0x00, ++0x0a,0x0d,0x54,0x58,0x4c,0x4c,0x54,0x09,0x09,0x4e,0x45,0x58,0x54,0x20,0x20,0x20, ++0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x4e,0x45,0x58,0x54,0x0a,0x0d,0x00, ++0x0a,0x0d,0x20,0x50,0x61,0x67,0x65,0x25,0x33,0x64,0x09,0x00,0x25,0x34,0x64,0x20, ++0x20,0x20,0x20,0x00,0x25,0x34,0x64,0x20,0x20,0x20,0x20,0x09,0x00,0x00,0x00,0x00, ++0x0a,0x0d,0x54,0x58,0x4f,0x51,0x54,0x09,0x09,0x48,0x65,0x61,0x64,0x20,0x20,0x20, ++0x20,0x54,0x61,0x69,0x6c,0x20,0x20,0x20,0x20,0x48,0x65,0x61,0x64,0x20,0x20,0x20, ++0x20,0x54,0x61,0x69,0x6c,0x0a,0x0d,0x00,0x0a,0x0d,0x55,0x6e,0x6b,0x6e,0x6f,0x77, ++0x20,0x63,0x6f,0x6d,0x6d,0x61,0x6e,0x64,0x00,0x00,0x00,0x00,0x0a,0x0d,0x45,0x72, ++0x72,0x20,0x41,0x72,0x67,0x0a,0x0d,0x55,0x53,0x41,0x47,0x45,0x3a,0x00,0x00,0x00, ++0x10,0x00,0x08,0x00,0x02,0xe9,0x01,0x74,0x02,0xab,0x01,0xc7,0x01,0x55,0x00,0xe4, ++0x00,0xab,0x00,0x72,0x00,0x55,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c,0x00,0x4c, ++0x02,0x76,0x01,0x3b,0x00,0xd2,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x46,0x00,0x3f, ++0x01,0x3b,0x00,0x9e,0x00,0x69,0x00,0x4f,0x00,0x35,0x00,0x27,0x00,0x23,0x00,0x20, ++0x01,0x2f,0x00,0x98,0x00,0x65,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x22,0x00,0x1e, ++0x00,0x98,0x00,0x4c,0x00,0x33,0x00,0x26,0x00,0x19,0x00,0x13,0x00,0x11,0x00,0x0f, ++0x02,0x39,0x01,0x1c,0x00,0xbd,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x3f,0x00,0x39, ++0x01,0x1c,0x00,0x8e,0x00,0x5f,0x00,0x47,0x00,0x2f,0x00,0x23,0x00,0x20,0x00,0x1c, ++0x01,0x11,0x00,0x89,0x00,0x5b,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x1e,0x00,0x1b, ++0x00,0x89,0x00,0x44,0x00,0x2e,0x00,0x22,0x00,0x17,0x00,0x11,0x00,0x0f,0x00,0x0e, ++0x02,0xab,0x02,0xab,0x02,0x66,0x02,0x66,0x07,0x06,0x06,0x06,0x05,0x06,0x07,0x08, ++0x04,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0b,0x49,0x6e,0x74,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x54,0x4c,0x42,0x4d,0x4f,0x44,0x00,0x00,0x00,0x00,0x54,0x4c,0x42,0x4c, ++0x5f,0x64,0x61,0x74,0x61,0x00,0x54,0x4c,0x42,0x53,0x00,0x00,0x00,0x00,0x00,0x00, ++0x41,0x64,0x45,0x4c,0x5f,0x64,0x61,0x74,0x61,0x00,0x41,0x64,0x45,0x53,0x00,0x00, ++0x00,0x00,0x00,0x00,0x45,0x78,0x63,0x43,0x6f,0x64,0x65,0x36,0x00,0x00,0x45,0x78, ++0x63,0x43,0x6f,0x64,0x65,0x37,0x00,0x00,0x53,0x79,0x73,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x42,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x49,0x00,0x00, ++0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x70,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x4f,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x80,0x01,0x14,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x10, ++0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x48, ++0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0xc0,0x00,0x00,0x01,0x20, ++0x00,0x00,0x01,0x20,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0xd0, ++0x00,0x00,0x01,0x38,0x00,0x00,0x01,0xa0,0x00,0x00,0x02,0x70,0x00,0x00,0x03,0x40, ++0x00,0x00,0x03,0xa8,0x00,0x00,0x04,0x10,0x00,0x00,0x00,0xd0,0x00,0x00,0x01,0xa0, ++0x00,0x00,0x02,0x70,0x00,0x00,0x03,0x40,0x00,0x00,0x04,0xe0,0x00,0x00,0x06,0x80, ++0x00,0x00,0x07,0x50,0x00,0x00,0x08,0x20,0x01,0x01,0x01,0x02,0x01,0x01,0x02,0x02, ++0x03,0x03,0x04,0x04,0x01,0x02,0x02,0x04,0x04,0x06,0x07,0x08,0x02,0x04,0x04,0x07, ++0x07,0x0b,0x0d,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x3c,0x4e,0x55,0x4c,0x4c,0x3e,0x00,0x00,0x30,0x31,0x32,0x33, ++0x34,0x35,0x36,0x37,0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a, ++0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a, ++0x00,0x00,0x00,0x00,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42, ++0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52, ++0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++0x00,0x00,0x00,0x00,0x5b,0x52,0x58,0x5d,0x20,0x70,0x6b,0x74,0x5f,0x6c,0x65,0x6e, ++0x3d,0x25,0x64,0x20,0x6f,0x66,0x66,0x73,0x65,0x74,0x3d,0x25,0x64,0x20,0x73,0x74, ++0x61,0x72,0x74,0x5f,0x61,0x64,0x64,0x72,0x3d,0x25,0x30,0x38,0x78,0x0a,0x0d,0x00, ++0x00,0x00,0x00,0x00,0x80,0x00,0x07,0x6c,0x80,0x00,0x07,0x80,0x80,0x00,0x07,0x80, ++0x80,0x00,0x07,0x70,0x80,0x00,0x07,0x70,0x80,0x00,0x07,0x94,0x80,0x00,0x75,0x98, ++0x80,0x00,0x75,0xec,0x80,0x00,0x76,0x08,0x80,0x00,0x76,0xf4,0x80,0x00,0x77,0xac, ++0x80,0x00,0x77,0xfc,0x80,0x00,0x78,0x68,0x80,0x00,0x79,0x6c,0x80,0x00,0x79,0xa0, ++0x80,0x00,0x79,0xb4,0x80,0x00,0x79,0xc8,0x80,0x00,0x7a,0x74,0x80,0x00,0x7a,0xb0, ++0x80,0x00,0x7b,0x60,0x80,0x00,0x7b,0x88,0x80,0x00,0x75,0x54,0x80,0x00,0x7b,0x9c, ++0x80,0x00,0x82,0x28,0x80,0x00,0x82,0xa0,0x80,0x00,0x82,0xac,0x80,0x00,0x82,0xb8, ++0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40, ++0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40, ++0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40,0x80,0x00,0x82,0x40, ++0x80,0x00,0x82,0xc4,0x80,0x00,0x82,0xd0,0x80,0x00,0x82,0xdc,0x80,0x00,0xa5,0x50, ++0x80,0x00,0xa5,0x50,0x80,0x00,0xa5,0x50,0x80,0x00,0xa5,0x50,0x80,0x00,0xa5,0x50, ++0x80,0x00,0xa5,0x84,0x80,0x00,0xa5,0xf4,0x80,0x00,0xa6,0x1c,0x80,0x00,0xa6,0xf8, ++0x80,0x00,0xa6,0xf8,0x80,0x00,0xa6,0xf8,0x80,0x00,0xa6,0xf8,0x80,0x00,0xa6,0xf8, ++0x80,0x00,0xa6,0x30,0x80,0x00,0xa6,0x94,0x80,0x00,0xa6,0xc4,0x80,0x00,0xa6,0xf8, ++0x80,0x00,0xa6,0xf8,0x80,0x00,0xa6,0xf8,0x80,0x00,0xa6,0xf8,0x80,0x00,0xa6,0xd0, ++0x80,0x00,0xa7,0x2c,0x80,0x00,0xa7,0x40,0x80,0x00,0xa4,0xac,0x80,0x00,0xaa,0x50, ++0x80,0x00,0xaa,0x50,0x80,0x00,0xaa,0x50,0x80,0x00,0xaa,0x50,0x80,0x00,0xaa,0x50, ++0x80,0x00,0xaa,0x84,0x80,0x00,0xaa,0xf4,0x80,0x00,0xab,0x1c,0x80,0x00,0xab,0xf8, ++0x80,0x00,0xab,0xf8,0x80,0x00,0xab,0xf8,0x80,0x00,0xab,0xf8,0x80,0x00,0xab,0xf8, ++0x80,0x00,0xab,0x30,0x80,0x00,0xab,0x94,0x80,0x00,0xab,0xc4,0x80,0x00,0xab,0xf8, ++0x80,0x00,0xab,0xf8,0x80,0x00,0xab,0xf8,0x80,0x00,0xab,0xf8,0x80,0x00,0xab,0xd0, ++0x80,0x00,0xac,0x2c,0x80,0x00,0xac,0x40,0x80,0x00,0xa8,0x88,0x80,0x00,0xb9,0x8c, ++0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0x94,0x80,0x00,0xb9,0xa4, ++0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0xa4, ++0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0x9c,0x80,0x00,0xb9,0xa4, ++0x80,0x00,0xb9,0x84,0x80,0x00,0xb9,0xa4,0x80,0x00,0xb9,0xa4,0x80,0x00,0xbd,0xcc, ++0x80,0x00,0xba,0xbc,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xba,0xc8, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xba,0x50,0x80,0x00,0xbb,0x9c, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbb,0x9c,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbb,0xa4,0x80,0x00,0xbb,0xc4,0x80,0x00,0xbb,0xcc, ++0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0x24,0x80,0x00,0xbc,0xd4, ++0x80,0x00,0xba,0xd0,0x80,0x00,0xbc,0xd4,0x80,0x00,0xbc,0xd4,0x80,0x00,0xba,0xcc, ++}; ++ ++#endif //__INC_R819XU_FIRMWARE_IMG_H diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt2860-wireless-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt2860-wireless-driver.patch new file mode 100644 index 000000000..f3afd40cf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt2860-wireless-driver.patch @@ -0,0 +1,89950 @@ +From 52076881ca20d02dd8b4b14348a08a3479715252 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Tue, 28 Oct 2008 14:48:09 -0700 +Subject: Staging: add rt2860 wireless driver + +From: Greg Kroah-Hartman + +This is the Ralink RT2860 driver from the company that does horrible +things like reading a config file from /etc. However, the driver that +is currently under development from the wireless development community +is not working at all yet, so distros and users are using this version +instead (quite common hardware on a lot of netbook machines). + +So here is this driver, for now, until the wireless developers get a +"clean" version into the main tree, or until this version is cleaned up +sufficiently to move out of the staging tree. + +Ported to the Linux build system and cleaned up a bit already by me. + +Cc: Linux wireless +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/rt2860/2860_main_dev.c | 1377 +++ + drivers/staging/rt2860/Kconfig | 5 + drivers/staging/rt2860/Makefile | 41 + drivers/staging/rt2860/TODO | 17 + drivers/staging/rt2860/aironet.h | 210 + drivers/staging/rt2860/ap.h | 557 + + drivers/staging/rt2860/chlist.h | 1296 +++ + drivers/staging/rt2860/common/2860_rtmp_init.c | 922 ++ + drivers/staging/rt2860/common/action.c | 1031 ++ + drivers/staging/rt2860/common/action.h | 68 + drivers/staging/rt2860/common/ba_action.c | 1802 +++++ + drivers/staging/rt2860/common/cmm_data.c | 3469 ++++++++++ + drivers/staging/rt2860/common/cmm_data_2860.c | 1240 +++ + drivers/staging/rt2860/common/cmm_info.c | 3417 +++++++++ + drivers/staging/rt2860/common/cmm_sanity.c | 1633 ++++ + drivers/staging/rt2860/common/cmm_sync.c | 702 ++ + drivers/staging/rt2860/common/cmm_wpa.c | 1606 ++++ + drivers/staging/rt2860/common/dfs.c | 453 + + drivers/staging/rt2860/common/eeprom.c | 244 + drivers/staging/rt2860/common/firmware.h | 558 + + drivers/staging/rt2860/common/md5.c | 1427 ++++ + drivers/staging/rt2860/common/mlme.c | 8667 +++++++++++++++++++++++++ + drivers/staging/rt2860/common/netif_block.c | 144 + drivers/staging/rt2860/common/netif_block.h | 58 + drivers/staging/rt2860/common/rtmp_init.c | 3757 ++++++++++ + drivers/staging/rt2860/common/rtmp_tkip.c | 1607 ++++ + drivers/staging/rt2860/common/rtmp_wep.c | 499 + + drivers/staging/rt2860/common/spectrum.c | 1877 +++++ + drivers/staging/rt2860/config.mk | 245 + drivers/staging/rt2860/dfs.h | 100 + drivers/staging/rt2860/leap.h | 215 + drivers/staging/rt2860/link_list.h | 134 + drivers/staging/rt2860/md4.h | 42 + drivers/staging/rt2860/md5.h | 107 + drivers/staging/rt2860/mlme.h | 1447 ++++ + drivers/staging/rt2860/oid.h | 995 ++ + drivers/staging/rt2860/rt2860.h | 349 + + drivers/staging/rt2860/rt28xx.h | 2714 +++++++ + drivers/staging/rt2860/rt_ate.c | 6025 +++++++++++++++++ + drivers/staging/rt2860/rt_ate.h | 353 + + drivers/staging/rt2860/rt_config.h | 101 + drivers/staging/rt2860/rt_linux.c | 1054 +++ + drivers/staging/rt2860/rt_linux.h | 926 ++ + drivers/staging/rt2860/rt_main_dev.c | 1686 ++++ + drivers/staging/rt2860/rt_profile.c | 1976 +++++ + drivers/staging/rt2860/rtmp.h | 7177 ++++++++++++++++++++ + drivers/staging/rt2860/rtmp_ckipmic.h | 113 + drivers/staging/rt2860/rtmp_def.h | 1588 ++++ + drivers/staging/rt2860/rtmp_type.h | 94 + drivers/staging/rt2860/spectrum.h | 322 + drivers/staging/rt2860/spectrum_def.h | 95 + drivers/staging/rt2860/sta/aironet.c | 1312 +++ + drivers/staging/rt2860/sta/assoc.c | 1826 +++++ + drivers/staging/rt2860/sta/auth.c | 474 + + drivers/staging/rt2860/sta/auth_rsp.c | 167 + drivers/staging/rt2860/sta/connect.c | 2751 +++++++ + drivers/staging/rt2860/sta/dls.c | 2201 ++++++ + drivers/staging/rt2860/sta/rtmp_data.c | 2614 +++++++ + drivers/staging/rt2860/sta/sanity.c | 420 + + drivers/staging/rt2860/sta/sync.c | 1961 +++++ + drivers/staging/rt2860/sta/wpa.c | 2086 ++++++ + drivers/staging/rt2860/sta_ioctl.c | 6944 ++++++++++++++++++++ + drivers/staging/rt2860/wpa.h | 356 + + 65 files changed, 89657 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -47,4 +47,6 @@ source "drivers/staging/agnx/Kconfig" + + source "drivers/staging/otus/Kconfig" + ++source "drivers/staging/rt2860/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -15,3 +15,4 @@ obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_USB_ATMEL) += at76_usb/ + obj-$(CONFIG_AGNX) += agnx/ + obj-$(CONFIG_OTUS) += otus/ ++obj-$(CONFIG_RT2860) += rt2860/ +--- /dev/null ++++ b/drivers/staging/rt2860/2860_main_dev.c +@@ -0,0 +1,1377 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ 2870_main_dev.c ++ ++ Abstract: ++ Create and register network interface. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++*/ ++ ++#include "rt_config.h" ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// record whether the card in the card list is used in the card file ++extern UINT8 MC_CardUsed[]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ++extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, ++ IN UINT argc, OUT PRTMP_ADAPTER *ppAd); ++ ++static void rx_done_tasklet(unsigned long data); ++static void mgmt_dma_done_tasklet(unsigned long data); ++static void ac0_dma_done_tasklet(unsigned long data); ++static void ac1_dma_done_tasklet(unsigned long data); ++static void ac2_dma_done_tasklet(unsigned long data); ++static void ac3_dma_done_tasklet(unsigned long data); ++static void hcca_dma_done_tasklet(unsigned long data); ++static void fifo_statistic_full_tasklet(unsigned long data); ++ ++ ++/*---------------------------------------------------------------------*/ ++/* Symbol & Macro Definitions */ ++/*---------------------------------------------------------------------*/ ++#define RT2860_INT_RX_DLY (1<<0) // bit 0 ++#define RT2860_INT_TX_DLY (1<<1) // bit 1 ++#define RT2860_INT_RX_DONE (1<<2) // bit 2 ++#define RT2860_INT_AC0_DMA_DONE (1<<3) // bit 3 ++#define RT2860_INT_AC1_DMA_DONE (1<<4) // bit 4 ++#define RT2860_INT_AC2_DMA_DONE (1<<5) // bit 5 ++#define RT2860_INT_AC3_DMA_DONE (1<<6) // bit 6 ++#define RT2860_INT_HCCA_DMA_DONE (1<<7) // bit 7 ++#define RT2860_INT_MGMT_DONE (1<<8) // bit 8 ++ ++#define INT_RX RT2860_INT_RX_DONE ++ ++#define INT_AC0_DLY (RT2860_INT_AC0_DMA_DONE) //| RT2860_INT_TX_DLY) ++#define INT_AC1_DLY (RT2860_INT_AC1_DMA_DONE) //| RT2860_INT_TX_DLY) ++#define INT_AC2_DLY (RT2860_INT_AC2_DMA_DONE) //| RT2860_INT_TX_DLY) ++#define INT_AC3_DLY (RT2860_INT_AC3_DMA_DONE) //| RT2860_INT_TX_DLY) ++#define INT_HCCA_DLY (RT2860_INT_HCCA_DMA_DONE) //| RT2860_INT_TX_DLY) ++#define INT_MGMT_DLY RT2860_INT_MGMT_DONE ++ ++/*---------------------------------------------------------------------*/ ++/* Prototypes of Functions Used */ ++/*---------------------------------------------------------------------*/ ++/* function declarations */ ++static INT __devinit rt2860_init_one (struct pci_dev *pci_dev, const struct pci_device_id *ent); ++static VOID __devexit rt2860_remove_one(struct pci_dev *pci_dev); ++static INT __devinit rt2860_probe(struct pci_dev *pci_dev, const struct pci_device_id *ent); ++void init_thread_task(PRTMP_ADAPTER pAd); ++static void __exit rt2860_cleanup_module(void); ++static int __init rt2860_init_module(void); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#ifdef CONFIG_PM ++static int rt2860_suspend(struct pci_dev *pci_dev, pm_message_t state); ++static int rt2860_resume(struct pci_dev *pci_dev); ++#endif // CONFIG_PM // ++#endif ++ ++ ++// ++// Ralink PCI device table, include all supported chipsets ++// ++static struct pci_device_id rt2860_pci_tbl[] __devinitdata = ++{ ++ {PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCI_DEVICE_ID)}, //RT28602.4G ++ {PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCIe_DEVICE_ID)}, ++ {PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2760_PCI_DEVICE_ID)}, ++ {PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2790_PCIe_DEVICE_ID)}, ++ {PCI_DEVICE(VEN_AWT_PCI_VENDOR_ID, VEN_AWT_PCIe_DEVICE_ID)}, ++ {0,} // terminate list ++}; ++ ++MODULE_DEVICE_TABLE(pci, rt2860_pci_tbl); ++#ifdef CONFIG_STA_SUPPORT ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_VERSION ++MODULE_VERSION(STA_DRIVER_VERSION); ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// ++// Our PCI driver structure ++// ++static struct pci_driver rt2860_driver = ++{ ++ name: "rt2860", ++ id_table: rt2860_pci_tbl, ++ probe: rt2860_init_one, ++#if LINUX_VERSION_CODE >= 0x20412 ++ remove: __devexit_p(rt2860_remove_one), ++#else ++ remove: __devexit(rt2860_remove_one), ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#ifdef CONFIG_PM ++ suspend: rt2860_suspend, ++ resume: rt2860_resume, ++#endif ++#endif ++}; ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#ifdef CONFIG_PM ++ ++VOID RT2860RejectPendingPackets( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // clear PS packets ++ // clear TxSw packets ++} ++ ++static int rt2860_suspend( ++ struct pci_dev *pci_dev, ++ pm_message_t state) ++{ ++ struct net_device *net_dev = pci_get_drvdata(pci_dev); ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL; ++ INT32 retval; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_suspend()\n")); ++ ++ if (net_dev == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); ++ } ++ else ++ { ++ pAd = (PRTMP_ADAPTER)net_dev->priv; ++ ++ /* we can not use IFF_UP because ra0 down but ra1 up */ ++ /* and 1 suspend/resume function for 1 module, not for each interface */ ++ /* so Linux will call suspend/resume function once */ ++ if (VIRTUAL_IF_NUM(pAd) > 0) ++ { ++ // avoid users do suspend after interface is down ++ ++ // stop interface ++ netif_carrier_off(net_dev); ++ netif_stop_queue(net_dev); ++ ++ // mark device as removed from system and therefore no longer available ++ netif_device_detach(net_dev); ++ ++ // mark halt flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++ // take down the device ++ rt28xx_close((PNET_DEV)net_dev); ++ ++ RT_MOD_DEC_USE_COUNT(); ++ } ++ } ++ ++ // reference to http://vovo2000.com/type-lab/linux/kernel-api/linux-kernel-api.html ++ // enable device to generate PME# when suspended ++ // pci_choose_state(): Choose the power state of a PCI device to be suspended ++ retval = pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1); ++ // save the PCI configuration space of a device before suspending ++ pci_save_state(pci_dev); ++ // disable PCI device after use ++ pci_disable_device(pci_dev); ++ ++ retval = pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_suspend()\n")); ++ return retval; ++} ++ ++static int rt2860_resume( ++ struct pci_dev *pci_dev) ++{ ++ struct net_device *net_dev = pci_get_drvdata(pci_dev); ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL; ++ INT32 retval; ++ ++ ++ // set the power state of a PCI device ++ // PCI has 4 power states, DO (normal) ~ D3(less power) ++ // in include/linux/pci.h, you can find that ++ // #define PCI_D0 ((pci_power_t __force) 0) ++ // #define PCI_D1 ((pci_power_t __force) 1) ++ // #define PCI_D2 ((pci_power_t __force) 2) ++ // #define PCI_D3hot ((pci_power_t __force) 3) ++ // #define PCI_D3cold ((pci_power_t __force) 4) ++ // #define PCI_UNKNOWN ((pci_power_t __force) 5) ++ // #define PCI_POWER_ERROR ((pci_power_t __force) -1) ++ retval = pci_set_power_state(pci_dev, PCI_D0); ++ ++ // restore the saved state of a PCI device ++ pci_restore_state(pci_dev); ++ ++ // initialize device before it's used by a driver ++ if (pci_enable_device(pci_dev)) ++ { ++ printk("pci enable fail!\n"); ++ return 0; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_resume()\n")); ++ ++ if (net_dev == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); ++ } ++ else ++ pAd = (PRTMP_ADAPTER)net_dev->priv; ++ ++ if (pAd != NULL) ++ { ++ /* we can not use IFF_UP because ra0 down but ra1 up */ ++ /* and 1 suspend/resume function for 1 module, not for each interface */ ++ /* so Linux will call suspend/resume function once */ ++ if (VIRTUAL_IF_NUM(pAd) > 0) ++ { ++ // mark device as attached from system and restart if needed ++ netif_device_attach(net_dev); ++ ++ if (rt28xx_open((PNET_DEV)net_dev) != 0) ++ { ++ // open fail ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_resume()\n")); ++ return 0; ++ } ++ ++ // increase MODULE use count ++ RT_MOD_INC_USE_COUNT(); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++ netif_start_queue(net_dev); ++ netif_carrier_on(net_dev); ++ netif_wake_queue(net_dev); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_resume()\n")); ++ return 0; ++} ++#endif // CONFIG_PM // ++#endif ++ ++ ++static INT __init rt2860_init_module(VOID) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ return pci_register_driver(&rt2860_driver); ++#else ++ return pci_module_init(&rt2860_driver); ++#endif ++} ++ ++ ++// ++// Driver module unload function ++// ++static VOID __exit rt2860_cleanup_module(VOID) ++{ ++ pci_unregister_driver(&rt2860_driver); ++} ++ ++module_init(rt2860_init_module); ++module_exit(rt2860_cleanup_module); ++ ++ ++static INT __devinit rt2860_init_one ( ++ IN struct pci_dev *pci_dev, ++ IN const struct pci_device_id *ent) ++{ ++ INT rc; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_init_one\n")); ++ ++ // wake up and enable device ++ if (pci_enable_device (pci_dev)) ++ { ++ rc = -EIO; ++ } ++ else ++ { ++ rc = rt2860_probe(pci_dev, ent); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_init_one\n")); ++ return rc; ++} ++ ++ ++static VOID __devexit rt2860_remove_one( ++ IN struct pci_dev *pci_dev) ++{ ++ struct net_device *net_dev = pci_get_drvdata(pci_dev); ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_remove_one\n")); ++ ++ if (pAd != NULL) ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) ++ MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ++ ++ ++ // Unregister network device ++ unregister_netdev(net_dev); ++ ++ // Unmap CSR base address ++ iounmap((char *)(net_dev->base_addr)); ++ ++ RTMPFreeAdapter(pAd); ++ ++ // release memory region ++ release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); ++ } ++ else ++ { ++ // Unregister network device ++ unregister_netdev(net_dev); ++ ++ // Unmap CSR base address ++ iounmap((char *)(net_dev->base_addr)); ++ ++ // release memory region ++ release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); ++ } ++ ++ // Free pre-allocated net_device memory ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ free_netdev(net_dev); ++#else ++ kfree(net_dev); ++#endif ++} ++ ++// ++// PCI device probe & initialization function ++// ++static INT __devinit rt2860_probe( ++ IN struct pci_dev *pci_dev, ++ IN const struct pci_device_id *ent) ++{ ++ PRTMP_ADAPTER pAd; ++ INT rv = 0; ++ ++ rv = (INT)rt28xx_probe((void *)pci_dev, (void *)ent, 0, &pAd); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE); ++ return rv; ++} ++ ++ ++void init_thread_task(IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE pObj; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->mgmt_dma_done_task, mgmt_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac0_dma_done_task, ac0_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac1_dma_done_task, ac1_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac2_dma_done_task, ac2_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac3_dma_done_task, ac3_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->hcca_dma_done_task, hcca_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->fifo_statistic_full_task, fifo_statistic_full_tasklet, (unsigned long)pAd); ++} ++ ++void kill_thread_task(IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE pObj; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ tasklet_kill(&pObj->rx_done_task); ++ tasklet_kill(&pObj->mgmt_dma_done_task); ++ tasklet_kill(&pObj->ac0_dma_done_task); ++ tasklet_kill(&pObj->ac1_dma_done_task); ++ tasklet_kill(&pObj->ac2_dma_done_task); ++ tasklet_kill(&pObj->ac3_dma_done_task); ++ tasklet_kill(&pObj->hcca_dma_done_task); ++ tasklet_kill(&pObj->tbtt_task); ++ tasklet_kill(&pObj->fifo_statistic_full_task); ++} ++ ++ ++static void rt2860_int_enable(PRTMP_ADAPTER pAd, unsigned int mode) ++{ ++ u32 regValue; ++ ++ pAd->int_disable_mask &= ~(mode); ++ regValue = pAd->int_enable_reg & ~(pAd->int_disable_mask); ++ RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); // 1:enable ++ ++ if (regValue != 0) ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); ++} ++ ++ ++static void rt2860_int_disable(PRTMP_ADAPTER pAd, unsigned int mode) ++{ ++ u32 regValue; ++ ++ pAd->int_disable_mask |= mode; ++ regValue = pAd->int_enable_reg & ~(pAd->int_disable_mask); ++ RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); // 0: disable ++ ++ if (regValue == 0) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); ++ } ++} ++ ++static void mgmt_dma_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ IntSource.word = 0; ++ IntSource.field.MgmtDmaDone = 1; ++ pAd->int_pending &= ~INT_MGMT_DLY; ++ ++ RTMPHandleMgmtRingDmaDoneInterrupt(pAd); ++ ++ // if you use RTMP_SEM_LOCK, sometimes kernel will hang up, no any ++ // bug report output ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid lose of interrupts ++ */ ++ if (pAd->int_pending & INT_MGMT_DLY) ++ { ++ tasklet_hi_schedule(&pObj->mgmt_dma_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable TxDataInt again */ ++ rt2860_int_enable(pAd, INT_MGMT_DLY); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++static void rx_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ BOOLEAN bReschedule = 0; ++ POS_COOKIE pObj; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pAd->int_pending &= ~(INT_RX); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ bReschedule = STARxDoneInterruptHandle(pAd, 0); ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid rotting packet ++ */ ++ if (pAd->int_pending & INT_RX || bReschedule) ++ { ++ tasklet_hi_schedule(&pObj->rx_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable RxINT again */ ++ rt2860_int_enable(pAd, INT_RX); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ ++} ++ ++void fifo_statistic_full_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ POS_COOKIE pObj; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pAd->int_pending &= ~(FifoStaFullInt); ++ NICUpdateFifoStaCounters(pAd); ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid rotting packet ++ */ ++ if (pAd->int_pending & FifoStaFullInt) ++ { ++ tasklet_hi_schedule(&pObj->fifo_statistic_full_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable RxINT again */ ++ ++ rt2860_int_enable(pAd, FifoStaFullInt); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ ++} ++ ++static void hcca_dma_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ IntSource.word = 0; ++ IntSource.field.HccaDmaDone = 1; ++ pAd->int_pending &= ~INT_HCCA_DLY; ++ ++ RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid lose of interrupts ++ */ ++ if (pAd->int_pending & INT_HCCA_DLY) ++ { ++ tasklet_hi_schedule(&pObj->hcca_dma_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable TxDataInt again */ ++ rt2860_int_enable(pAd, INT_HCCA_DLY); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++static void ac3_dma_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ BOOLEAN bReschedule = 0; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ IntSource.word = 0; ++ IntSource.field.Ac3DmaDone = 1; ++ pAd->int_pending &= ~INT_AC3_DLY; ++ ++ bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid lose of interrupts ++ */ ++ if ((pAd->int_pending & INT_AC3_DLY) || bReschedule) ++ { ++ tasklet_hi_schedule(&pObj->ac3_dma_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable TxDataInt again */ ++ rt2860_int_enable(pAd, INT_AC3_DLY); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++static void ac2_dma_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ BOOLEAN bReschedule = 0; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ IntSource.word = 0; ++ IntSource.field.Ac2DmaDone = 1; ++ pAd->int_pending &= ~INT_AC2_DLY; ++ ++ bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ ++ /* ++ * double check to avoid lose of interrupts ++ */ ++ if ((pAd->int_pending & INT_AC2_DLY) || bReschedule) ++ { ++ tasklet_hi_schedule(&pObj->ac2_dma_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable TxDataInt again */ ++ rt2860_int_enable(pAd, INT_AC2_DLY); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++static void ac1_dma_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ BOOLEAN bReschedule = 0; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ IntSource.word = 0; ++ IntSource.field.Ac1DmaDone = 1; ++ pAd->int_pending &= ~INT_AC1_DLY; ++ ++ bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid lose of interrupts ++ */ ++ if ((pAd->int_pending & INT_AC1_DLY) || bReschedule) ++ { ++ tasklet_hi_schedule(&pObj->ac1_dma_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable TxDataInt again */ ++ rt2860_int_enable(pAd, INT_AC1_DLY); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++static void ac0_dma_done_tasklet(unsigned long data) ++{ ++ unsigned long flags; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ BOOLEAN bReschedule = 0; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ IntSource.word = 0; ++ IntSource.field.Ac0DmaDone = 1; ++ pAd->int_pending &= ~INT_AC0_DLY; ++ ++ bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); ++ ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ /* ++ * double check to avoid lose of interrupts ++ */ ++ if ((pAd->int_pending & INT_AC0_DLY) || bReschedule) ++ { ++ tasklet_hi_schedule(&pObj->ac0_dma_done_task); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++ return; ++ } ++ ++ /* enable TxDataInt again */ ++ rt2860_int_enable(pAd, INT_AC0_DLY); ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++ ++int print_int_count; ++ ++IRQ_HANDLE_TYPE ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) ++rt2860_interrupt(int irq, void *dev_instance) ++#else ++rt2860_interrupt(int irq, void *dev_instance, struct pt_regs *regs) ++#endif ++{ ++ struct net_device *net_dev = (struct net_device *) dev_instance; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ INT_SOURCE_CSR_STRUC IntSource; ++ POS_COOKIE pObj; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ /* Note 03312008: we can not return here before ++ RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); ++ RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); ++ Or kernel will panic after ifconfig ra0 down sometimes */ ++ ++ ++ // ++ // Inital the Interrupt source. ++ // ++ IntSource.word = 0x00000000L; ++// McuIntSource.word = 0x00000000L; ++ ++ // ++ // Get the interrupt sources & saved to local variable ++ // ++ //RTMP_IO_READ32(pAd, where, &McuIntSource.word); ++ //RTMP_IO_WRITE32(pAd, , McuIntSource.word); ++ ++ // ++ // Flag fOP_STATUS_DOZE On, means ASIC put to sleep, elase means ASICK WakeUp ++ // And at the same time, clock maybe turned off that say there is no DMA service. ++ // when ASIC get to sleep. ++ // To prevent system hang on power saving. ++ // We need to check it before handle the INT_SOURCE_CSR, ASIC must be wake up. ++ // ++ // RT2661 => when ASIC is sleeping, MAC register cannot be read and written. ++ // RT2860 => when ASIC is sleeping, MAC register can be read and written. ++ ++ { ++ RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); ++ RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); // write 1 to clear ++ } ++ ++ // Do nothing if Reset in progress ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ return IRQ_HANDLED; ++#else ++ return; ++#endif ++ } ++ ++ // ++ // Handle interrupt, walk through all bits ++ // Should start from highest priority interrupt ++ // The priority can be adjust by altering processing if statement ++ // ++ ++ pAd->bPCIclkOff = FALSE; ++ ++ // If required spinlock, each interrupt service routine has to acquire ++ // and release itself. ++ // ++ ++ // Do nothing if NIC doesn't exist ++ if (IntSource.word == 0xffffffff) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ return IRQ_HANDLED; ++#else ++ return; ++#endif ++ } ++ ++ if (IntSource.word & TxCoherent) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (">>>TxCoherent<<<\n")); ++ RTMPHandleRxCoherentInterrupt(pAd); ++ } ++ ++ if (IntSource.word & RxCoherent) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (">>>RxCoherent<<<\n")); ++ RTMPHandleRxCoherentInterrupt(pAd); ++ } ++ ++ if (IntSource.word & FifoStaFullInt) ++ { ++#if 1 ++ if ((pAd->int_disable_mask & FifoStaFullInt) == 0) ++ { ++ /* mask FifoStaFullInt */ ++ rt2860_int_disable(pAd, FifoStaFullInt); ++ tasklet_hi_schedule(&pObj->fifo_statistic_full_task); ++ } ++ pAd->int_pending |= FifoStaFullInt; ++#else ++ NICUpdateFifoStaCounters(pAd); ++#endif ++ } ++ ++ if (IntSource.word & INT_MGMT_DLY) ++ { ++ if ((pAd->int_disable_mask & INT_MGMT_DLY) ==0 ) ++ { ++ rt2860_int_disable(pAd, INT_MGMT_DLY); ++ tasklet_hi_schedule(&pObj->mgmt_dma_done_task); ++ } ++ pAd->int_pending |= INT_MGMT_DLY ; ++ } ++ ++ if (IntSource.word & INT_RX) ++ { ++ if ((pAd->int_disable_mask & INT_RX) == 0) ++ { ++ /* mask RxINT */ ++ rt2860_int_disable(pAd, INT_RX); ++ tasklet_hi_schedule(&pObj->rx_done_task); ++ } ++ pAd->int_pending |= INT_RX; ++ } ++ ++ if (IntSource.word & INT_HCCA_DLY) ++ { ++ ++ if ((pAd->int_disable_mask & INT_HCCA_DLY) == 0) ++ { ++ /* mask TxDataInt */ ++ rt2860_int_disable(pAd, INT_HCCA_DLY); ++ tasklet_hi_schedule(&pObj->hcca_dma_done_task); ++ } ++ pAd->int_pending |= INT_HCCA_DLY; ++ } ++ ++ if (IntSource.word & INT_AC3_DLY) ++ { ++ ++ if ((pAd->int_disable_mask & INT_AC3_DLY) == 0) ++ { ++ /* mask TxDataInt */ ++ rt2860_int_disable(pAd, INT_AC3_DLY); ++ tasklet_hi_schedule(&pObj->ac3_dma_done_task); ++ } ++ pAd->int_pending |= INT_AC3_DLY; ++ } ++ ++ if (IntSource.word & INT_AC2_DLY) ++ { ++ ++ if ((pAd->int_disable_mask & INT_AC2_DLY) == 0) ++ { ++ /* mask TxDataInt */ ++ rt2860_int_disable(pAd, INT_AC2_DLY); ++ tasklet_hi_schedule(&pObj->ac2_dma_done_task); ++ } ++ pAd->int_pending |= INT_AC2_DLY; ++ } ++ ++ if (IntSource.word & INT_AC1_DLY) ++ { ++ ++ pAd->int_pending |= INT_AC1_DLY; ++ ++ if ((pAd->int_disable_mask & INT_AC1_DLY) == 0) ++ { ++ /* mask TxDataInt */ ++ rt2860_int_disable(pAd, INT_AC1_DLY); ++ tasklet_hi_schedule(&pObj->ac1_dma_done_task); ++ } ++ ++ } ++ ++ if (IntSource.word & INT_AC0_DLY) ++ { ++ pAd->int_pending |= INT_AC0_DLY; ++ ++ if ((pAd->int_disable_mask & INT_AC0_DLY) == 0) ++ { ++ /* mask TxDataInt */ ++ rt2860_int_disable(pAd, INT_AC0_DLY); ++ tasklet_hi_schedule(&pObj->ac0_dma_done_task); ++ } ++ ++ } ++ ++ if (IntSource.word & PreTBTTInt) ++ { ++ RTMPHandlePreTBTTInterrupt(pAd); ++ } ++ ++ if (IntSource.word & TBTTInt) ++ { ++ RTMPHandleTBTTInterrupt(pAd); ++ } ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (IntSource.word & AutoWakeupInt) ++ RTMPHandleTwakeupInterrupt(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ return IRQ_HANDLED; ++#endif ++ ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Check the chipset vendor/product ID. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ ++Return Value: ++ TRUE Check ok ++ FALSE Check fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXChipsetCheck( ++ IN void *_dev_p) ++{ ++ /* always TRUE */ ++ return TRUE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Init net device structure. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ *net_dev Point to the net device ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ TRUE Init ok ++ FALSE Init fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXNetDevInit( ++ IN void *_dev_p, ++ IN struct net_device *net_dev, ++ IN RTMP_ADAPTER *pAd) ++{ ++ struct pci_dev *pci_dev = (struct pci_dev *)_dev_p; ++ CHAR *print_name; ++ ULONG csr_addr; ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ print_name = pci_dev ? pci_name(pci_dev) : "rt2860"; ++#else ++ print_name = pci_dev ? pci_dev->slot_name : "rt2860"; ++#endif // LINUX_VERSION_CODE // ++ ++ net_dev->base_addr = 0; ++ net_dev->irq = 0; ++ ++ if (pci_request_regions(pci_dev, print_name)) ++ goto err_out_free_netdev; ++ ++ // interrupt IRQ number ++ net_dev->irq = pci_dev->irq; ++ ++ // map physical address to virtual address for accessing register ++ csr_addr = (unsigned long) ioremap(pci_resource_start(pci_dev, 0), ++ pci_resource_len(pci_dev, 0)); ++ ++ if (!csr_addr) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("ioremap failed for device %s, region 0x%lX @ 0x%lX\n", ++ print_name, (ULONG)pci_resource_len(pci_dev, 0), ++ (ULONG)pci_resource_start(pci_dev, 0))); ++ goto err_out_free_res; ++ } ++ ++ // Save CSR virtual address and irq to device structure ++ net_dev->base_addr = csr_addr; ++ pAd->CSRBaseAddress = (PUCHAR)net_dev->base_addr; ++ ++ // Set DMA master ++ pci_set_master(pci_dev); ++ ++ net_dev->priv_flags = INT_MAIN; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: at 0x%lx, VA 0x%lx, IRQ %d. \n", ++ net_dev->name, (ULONG)pci_resource_start(pci_dev, 0), ++ (ULONG)csr_addr, pci_dev->irq)); ++ return TRUE; ++ ++ ++ /* --------------------------- ERROR HANDLE --------------------------- */ ++err_out_free_res: ++ pci_release_regions(pci_dev); ++err_out_free_netdev: ++ /* free netdev in caller, not here */ ++ return FALSE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Init net device structure. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ TRUE Config ok ++ FALSE Config fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 argc) ++{ ++ /* no use */ ++ return TRUE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Disable DMA. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28XXDMADisable( ++ IN RTMP_ADAPTER *pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ ++ ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ GloCfg.word &= 0xff0; ++ GloCfg.field.EnTXWriteBackDDONE =1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Enable DMA. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28XXDMAEnable( ++ IN RTMP_ADAPTER *pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ int i = 0; ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i <200); ++ ++ RTMPusecDelay(50); ++ ++ GloCfg.field.EnTXWriteBackDDONE = 1; ++ GloCfg.field.WPDMABurstSIZE = 2; ++ GloCfg.field.EnableRxDMA = 1; ++ GloCfg.field.EnableTxDMA = 1; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Write Beacon buffer to Asic. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28xx_UpdateBeaconToAsic( ++ IN RTMP_ADAPTER *pAd, ++ IN INT apidx, ++ IN ULONG FrameLen, ++ IN ULONG UpdatePos) ++{ ++ ULONG CapInfoPos = 0; ++ UCHAR *ptr, *ptr_update, *ptr_capinfo; ++ UINT i; ++ BOOLEAN bBcnReq = FALSE; ++ UCHAR bcn_idx = 0; ++ ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __FUNCTION__)); ++ return; ++ } ++ ++ if (bBcnReq == FALSE) ++ { ++ /* when the ra interface is down, do not send its beacon frame */ ++ /* clear all zero */ ++ for(i=0; iBeaconOffset[bcn_idx] + i, 0x00); ++ } ++ else ++ { ++ ptr = (PUCHAR)&pAd->BeaconTxWI; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(ptr, TYPE_TXWI); ++#endif ++ for (i=0; iBeaconOffset[bcn_idx] + i, longptr); ++ ptr += 4; ++ } ++ ++ // Update CapabilityInfo in Beacon ++ for (i = CapInfoPos; i < (CapInfoPos+2); i++) ++ { ++ RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_capinfo); ++ ptr_capinfo ++; ++ } ++ ++ if (FrameLen > UpdatePos) ++ { ++ for (i= UpdatePos; i< (FrameLen); i++) ++ { ++ RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_update); ++ ptr_update ++; ++ } ++ } ++ ++ } ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPInitPCIeLinkCtrlValue( ++ IN PRTMP_ADAPTER pAd) ++{ ++} ++ ++VOID RTMPFindHostPCIDev( ++ IN PRTMP_ADAPTER pAd) ++{ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Level = RESTORE_HALT : Restore PCI host and Ralink PCIe Link Control field to its default value. ++ Level = Other Value : Restore from dot11 power save or radio off status. And force PCI host Link Control fields to 0x1 ++ ++ ======================================================================== ++*/ ++VOID RTMPPCIeLinkCtrlValueRestore( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Level) ++{ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Max : limit Host PCI and Ralink PCIe device's LINK CONTROL field's value. ++ Because now frequently set our device to mode 1 or mode 3 will cause problem. ++ ++ ======================================================================== ++*/ ++VOID RTMPPCIeLinkCtrlSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Max) ++{ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID rt2860_stop(struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL; ++ if (net_dev == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); ++ } ++ else ++ pAd = (PRTMP_ADAPTER)net_dev->priv; ++ ++ if (pAd != NULL) ++ { ++ // stop interface ++ netif_carrier_off(net_dev); ++ netif_stop_queue(net_dev); ++ ++ // mark device as removed from system and therefore no longer available ++ netif_device_detach(net_dev); ++ ++ // mark halt flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++ // take down the device ++ rt28xx_close((PNET_DEV)net_dev); ++ RT_MOD_DEC_USE_COUNT(); ++ } ++ return; ++} ++ ++/* ++ * invaild or writeback cache ++ * and convert virtual address to physical address ++ */ ++dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, int sd_idx, int direction) ++{ ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ /* ++ ------ Porting Information ------ ++ > For Tx Alloc: ++ mgmt packets => sd_idx = 0 ++ SwIdx: pAd->MgmtRing.TxCpuIdx ++ pTxD : pAd->MgmtRing.Cell[SwIdx].AllocVa; ++ ++ data packets => sd_idx = 1 ++ TxIdx : pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx ++ QueIdx: pTxBlk->QueIdx ++ pTxD : pAd->TxRing[pTxBlk->QueIdx].Cell[TxIdx].AllocVa; ++ ++ > For Rx Alloc: ++ sd_idx = -1 ++ */ ++ ++ pAd = (PRTMP_ADAPTER)handle; ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ if (sd_idx == 1) ++ { ++ PTX_BLK pTxBlk; ++ pTxBlk = (PTX_BLK)ptr; ++ return pci_map_single(pObj->pci_dev, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, direction); ++ } ++ else ++ { ++ return pci_map_single(pObj->pci_dev, ptr, size, direction); ++ } ++ ++} ++ ++void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int direction) ++{ ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ pAd=(PRTMP_ADAPTER)handle; ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ pci_unmap_single(pObj->pci_dev, dma_addr, size, direction); ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/aironet.h +@@ -0,0 +1,210 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 04-06-15 Initial ++*/ ++ ++#ifndef __AIRONET_H__ ++#define __AIRONET_H__ ++ ++// Measurement Type definition ++#define MSRN_TYPE_UNUSED 0 ++#define MSRN_TYPE_CHANNEL_LOAD_REQ 1 ++#define MSRN_TYPE_NOISE_HIST_REQ 2 ++#define MSRN_TYPE_BEACON_REQ 3 ++#define MSRN_TYPE_FRAME_REQ 4 ++ ++// Scan Mode in Beacon Request ++#define MSRN_SCAN_MODE_PASSIVE 0 ++#define MSRN_SCAN_MODE_ACTIVE 1 ++#define MSRN_SCAN_MODE_BEACON_TABLE 2 ++ ++// PHY type definition for Aironet beacon report, CCX 2 table 36-9 ++#define PHY_FH 1 ++#define PHY_DSS 2 ++#define PHY_UNUSED 3 ++#define PHY_OFDM 4 ++#define PHY_HR_DSS 5 ++#define PHY_ERP 6 ++ ++// RPI table in dBm ++#define RPI_0 0 // Power <= -87 ++#define RPI_1 1 // -87 < Power <= -82 ++#define RPI_2 2 // -82 < Power <= -77 ++#define RPI_3 3 // -77 < Power <= -72 ++#define RPI_4 4 // -72 < Power <= -67 ++#define RPI_5 5 // -67 < Power <= -62 ++#define RPI_6 6 // -62 < Power <= -57 ++#define RPI_7 7 // -57 < Power ++ ++// Cisco Aironet IAPP definetions ++#define AIRONET_IAPP_TYPE 0x32 ++#define AIRONET_IAPP_SUBTYPE_REQUEST 0x01 ++#define AIRONET_IAPP_SUBTYPE_REPORT 0x81 ++ ++// Measurement Request detail format ++typedef struct _MEASUREMENT_REQUEST { ++ UCHAR Channel; ++ UCHAR ScanMode; // Use only in beacon request, other requests did not use this field ++ USHORT Duration; ++} MEASUREMENT_REQUEST, *PMEASUREMENT_REQUEST; ++ ++// Beacon Measurement Report ++// All these field might change to UCHAR, because we didn't do anything to these report. ++// We copy all these beacons and report to CCX 2 AP. ++typedef struct _BEACON_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR PhyType; // Definiation is listed above table 36-9 ++ UCHAR RxPower; ++ UCHAR BSSID[6]; ++ UCHAR ParentTSF[4]; ++ UCHAR TargetTSF[8]; ++ USHORT BeaconInterval; ++ USHORT CapabilityInfo; ++} BEACON_REPORT, *PBEACON_REPORT; ++ ++// Frame Measurement Report (Optional) ++typedef struct _FRAME_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR TA; ++ UCHAR BSSID[6]; ++ UCHAR RSSI; ++ UCHAR Count; ++} FRAME_REPORT, *PFRAME_REPORT; ++ ++#pragma pack(1) ++// Channel Load Report ++typedef struct _CHANNEL_LOAD_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR CCABusy; ++} CHANNEL_LOAD_REPORT, *PCHANNEL_LOAD_REPORT; ++#pragma pack() ++ ++// Nosie Histogram Report ++typedef struct _NOISE_HIST_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR Density[8]; ++} NOISE_HIST_REPORT, *PNOISE_HIST_REPORT; ++ ++// Radio Management Capability element ++typedef struct _RADIO_MANAGEMENT_CAPABILITY { ++ UCHAR Eid; // TODO: Why the Eid is 1 byte, not normal 2 bytes??? ++ UCHAR Length; ++ UCHAR AironetOui[3]; // AIronet OUI (00 40 96) ++ UCHAR Type; // Type / Version ++ USHORT Status; // swap16 required ++} RADIO_MANAGEMENT_CAPABILITY, *PRADIO_MANAGEMENT_CAPABILITY; ++ ++// Measurement Mode Bit definition ++typedef struct _MEASUREMENT_MODE { ++ UCHAR Rsvd:4; ++ UCHAR Report:1; ++ UCHAR NotUsed:1; ++ UCHAR Enable:1; ++ UCHAR Parallel:1; ++} MEASUREMENT_MODE, *PMEASUREMENT_MODE; ++ ++// Measurement Request element, This is little endian mode ++typedef struct _MEASUREMENT_REQUEST_ELEMENT { ++ USHORT Eid; ++ USHORT Length; // swap16 required ++ USHORT Token; // non-zero unique token ++ UCHAR Mode; // Measurement Mode ++ UCHAR Type; // Measurement type ++} MEASUREMENT_REQUEST_ELEMENT, *PMEASUREMENT_REQUEST_ELEMENT; ++ ++// Measurement Report element, This is little endian mode ++typedef struct _MEASUREMENT_REPORT_ELEMENT { ++ USHORT Eid; ++ USHORT Length; // swap16 required ++ USHORT Token; // non-zero unique token ++ UCHAR Mode; // Measurement Mode ++ UCHAR Type; // Measurement type ++} MEASUREMENT_REPORT_ELEMENT, *PMEASUREMENT_REPORT_ELEMENT; ++ ++// Cisco Aironet IAPP Frame Header, Network byte order used ++typedef struct _AIRONET_IAPP_HEADER { ++ UCHAR CiscoSnapHeader[8]; // 8 bytes Cisco snap header ++ USHORT Length; // IAPP ID & length, remember to swap16 in LE system ++ UCHAR Type; // IAPP type ++ UCHAR SubType; // IAPP subtype ++ UCHAR DA[6]; // Destination MAC address ++ UCHAR SA[6]; // Source MAC address ++ USHORT Token; // Dialog token, no need to swap16 since it is for yoken usage only ++} AIRONET_IAPP_HEADER, *PAIRONET_IAPP_HEADER; ++ ++// Radio Measurement Request frame ++typedef struct _AIRONET_RM_REQUEST_FRAME { ++ AIRONET_IAPP_HEADER IAPP; // Common header ++ UCHAR Delay; // Activation Delay ++ UCHAR Offset; // Measurement offset ++} AIRONET_RM_REQUEST_FRAME, *PAIRONET_RM_REQUEST_FRAME; ++ ++// Radio Measurement Report frame ++typedef struct _AIRONET_RM_REPORT_FRAME { ++ AIRONET_IAPP_HEADER IAPP; // Common header ++} AIRONET_RM_REPORT_FRAME, *PAIRONET_RM_REPORT_FRAME; ++ ++// Saved element request actions which will saved in StaCfg. ++typedef struct _RM_REQUEST_ACTION { ++ MEASUREMENT_REQUEST_ELEMENT ReqElem; // Saved request element ++ MEASUREMENT_REQUEST Measurement; // Saved measurement within the request element ++} RM_REQUEST_ACTION, *PRM_REQUEST_ACTION; ++ ++// CCX administration control ++typedef union _CCX_CONTROL { ++ struct { ++ UINT32 Enable:1; // Enable CCX2 ++ UINT32 LeapEnable:1; // Enable LEAP at CCX2 ++ UINT32 RMEnable:1; // Radio Measurement Enable ++ UINT32 DCRMEnable:1; // Non serving channel Radio Measurement enable ++ UINT32 QOSEnable:1; // Enable QOS for CCX 2.0 support ++ UINT32 FastRoamEnable:1; // Enable fast roaming ++ UINT32 Rsvd:2; // Not used ++ UINT32 dBmToRoam:8; // the condition to roam when receiving Rssi less than this value. It's negative value. ++ UINT32 TuLimit:16; // Limit for different channel scan ++ } field; ++ UINT32 word; ++} CCX_CONTROL, *PCCX_CONTROL; ++ ++#endif // __AIRONET_H__ +--- /dev/null ++++ b/drivers/staging/rt2860/ap.h +@@ -0,0 +1,557 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ ap.h ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ James Tan 09-06-2002 modified (Revise NTCRegTable) ++ John Chang 12-22-2004 modified for RT2561/2661. merge with STA driver ++*/ ++#ifndef __AP_H__ ++#define __AP_H__ ++ ++ ++ ++// ========================= AP RTMP.h ================================ ++ ++ ++ ++// ============================================================= ++// Function Prototypes ++// ============================================================= ++ ++// ap_data.c ++ ++BOOLEAN APBridgeToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN ULONG fromwdsidx); ++ ++BOOLEAN APHandleRxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APSendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets); ++ ++NDIS_STATUS APSendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++NDIS_STATUS APHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++VOID APRxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++NDIS_STATUS APCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN UCHAR Wcid); ++ ++BOOLEAN APCheckClass2Class3Error( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++VOID APHandleRxPsPoll( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN USHORT Aid, ++ IN BOOLEAN isActive); ++ ++VOID RTMPDescriptorEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType); ++ ++VOID RTMPFrameEndianChange( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG Dir, ++ IN BOOLEAN FromRxDoneInt); ++ ++// ap_assoc.c ++ ++VOID APAssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APPeerAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MbssKickOutStas( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN USHORT Reason); ++ ++VOID APMlmeKickOutSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pStaAddr, ++ IN UCHAR Wcid, ++ IN USHORT Reason); ++ ++VOID APMlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APCls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++ ++USHORT APBuildAssociation( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN USHORT CapabilityInfo, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN UCHAR *RSN, ++ IN UCHAR *pRSNLen, ++ IN BOOLEAN bWmmCapable, ++ IN ULONG RalinkIe, ++#ifdef DOT11N_DRAFT3 ++ IN EXT_CAP_INFO_ELEMENT ExtCapInfo, ++#endif // DOT11N_DRAFT3 // ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ OUT USHORT *pAid); ++ ++// ap_auth.c ++ ++void APAuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APMlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APCls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++// ap_authrsp.c ++ ++VOID APAuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]); ++ ++VOID APPeerAuthAtAuthRspIdleAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT StatusCode); ++ ++// ap_connect.c ++ ++BOOLEAN BeaconTransmitRequired( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APMakeBssBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APUpdateBeaconFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APMakeAllBssBeacon( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APUpdateAllBeaconFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++// ap_sync.c ++ ++VOID APSyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID APInvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerBeaconAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APMlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APScanCnclAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ApSiteSurvey( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID SupportRate( ++ IN PUCHAR SupRate, ++ IN UCHAR SupRateLen, ++ IN PUCHAR ExtRate, ++ IN UCHAR ExtRateLen, ++ OUT PUCHAR *Rates, ++ OUT PUCHAR RatesLen, ++ OUT PUCHAR pMaxSupportRate); ++ ++ ++BOOLEAN ApScanRunning( ++ IN PRTMP_ADAPTER pAd); ++ ++#ifdef DOT11N_DRAFT3 ++VOID APOverlappingBSSScan( ++ IN RTMP_ADAPTER *pAd); ++#endif // DOT11N_DRAFT3 // ++ ++// ap_wpa.c ++ ++VOID APWpaStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++// ap_mlme.c ++ ++VOID APMlmePeriodicExec( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APMlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx); ++ ++VOID APMlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate); ++ ++VOID APMlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN APMsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType); ++ ++VOID APQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++VOID RTMPSetPiggyBack( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bPiggyBack); ++ ++VOID APAsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APAsicRxAntEvalTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++// ap.c ++ ++VOID APSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Channel); ++ ++NDIS_STATUS APInitialize( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APShutdown( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APStartUp( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APCleanupPsQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_HEADER pQueue); ++ ++VOID MacTableReset( ++ IN PRTMP_ADAPTER pAd); ++ ++MAC_TABLE_ENTRY *MacTableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR apidx, ++ IN BOOLEAN CleanAll); ++ ++BOOLEAN MacTableDeleteEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr); ++ ++MAC_TABLE_ENTRY *MacTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID MacTableMaintenance( ++ IN PRTMP_ADAPTER pAd); ++ ++UINT32 MacTableAssocStaNumGet( ++ IN PRTMP_ADAPTER pAd); ++ ++MAC_TABLE_ENTRY *APSsPsInquiry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ OUT SST *Sst, ++ OUT USHORT *Aid, ++ OUT UCHAR *PsMode, ++ OUT UCHAR *Rate); ++ ++BOOLEAN APPsIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN ULONG Wcid, ++ IN UCHAR Psm); ++ ++VOID ApLogEvent( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN USHORT Event); ++ ++#ifdef DOT11_N_SUPPORT ++VOID APUpdateOperationMode( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++ ++VOID APUpdateCapabilityAndErpIe( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN ApCheckAccessControlList( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR Apidx); ++ ++VOID ApUpdateAccessControlList( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Apidx); ++ ++VOID ApEnqueueNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR TxRate, ++ IN UCHAR PID, ++ IN UCHAR apidx, ++ IN BOOLEAN bQosNull, ++ IN BOOLEAN bEOSP, ++ IN UCHAR OldUP); ++ ++VOID ApSendFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuffer, ++ IN ULONG Length, ++ IN UCHAR TxRate, ++ IN UCHAR PID); ++ ++VOID ApEnqueueAckFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR TxRate, ++ IN UCHAR apidx); ++ ++UCHAR APAutoSelectChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN Optimal); ++ ++// ap_sanity.c ++ ++ ++BOOLEAN PeerAssocReqCmmSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN isRessoc, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pListenInterval, ++ OUT PUCHAR pApAddr, ++ OUT UCHAR *pSsidLen, ++ OUT char *Ssid, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *RSN, ++ OUT UCHAR *pRSNLen, ++ OUT BOOLEAN *pbWmmCapable, ++ OUT ULONG *pRalinkIe, ++#ifdef DOT11N_DRAFT3 ++ OUT EXT_CAP_INFO_ELEMENT *pExtCapInfo, ++#endif // DOT11N_DRAFT3 // ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDisassocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerDeauthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN APPeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr1, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Alg, ++ OUT USHORT *Seq, ++ OUT USHORT *Status, ++ CHAR *ChlgText); ++ ++BOOLEAN APPeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *SsidLen); ++ ++BOOLEAN APPeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *SsidLen, ++ OUT UCHAR *BssType, ++ OUT USHORT *BeaconPeriod, ++ OUT UCHAR *Channel, ++ OUT LARGE_INTEGER *Timestamp, ++ OUT USHORT *CapabilityInfo, ++ OUT UCHAR Rate[], ++ OUT UCHAR *RateLen, ++ OUT BOOLEAN *ExtendedRateIeExist, ++ OUT UCHAR *Erp); ++ ++// ap_info.c ++ ++#ifdef WIN_NDIS ++NDIS_STATUS APQueryInformation( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN NDIS_OID Oid, ++ IN PVOID pInformationBuffer, ++ IN ULONG InformationBufferLength, ++ OUT PULONG pBytesWritten, ++ OUT PULONG pBytesNeeded); ++ ++NDIS_STATUS APSetInformation( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN NDIS_OID Oid, ++ IN PVOID pInformationBuffer, ++ IN ULONG InformationBufferLength, ++ OUT PULONG pBytesRead, ++ OUT PULONG pBytesNeeded); ++#endif ++ ++ ++// ================== end of AP RTMP.h ======================== ++ ++ ++#endif // __AP_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/chlist.h +@@ -0,0 +1,1296 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ chlist.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi Wu 2007-12-19 created ++*/ ++ ++#ifndef __CHLIST_H__ ++#define __CHLIST_H__ ++ ++#include "rtmp_type.h" ++#include "rtmp_def.h" ++ ++ ++#define ODOR 0 ++#define IDOR 1 ++#define BOTH 2 ++ ++#define BAND_5G 0 ++#define BAND_24G 1 ++#define BAND_BOTH 2 ++ ++typedef struct _CH_DESP { ++ UCHAR FirstChannel; ++ UCHAR NumOfCh; ++ CHAR MaxTxPwr; // dBm ++ UCHAR Geography; // 0:out door, 1:in door, 2:both ++ BOOLEAN DfsReq; // Dfs require, 0: No, 1: yes. ++} CH_DESP, *PCH_DESP; ++ ++typedef struct _CH_REGION { ++ UCHAR CountReg[3]; ++ UCHAR DfsType; // 0: CE, 1: FCC, 2: JAP, 3:JAP_W53, JAP_W56 ++ CH_DESP ChDesp[10]; ++} CH_REGION, *PCH_REGION; ++ ++static CH_REGION ChRegion[] = ++{ ++ { // Antigua and Berbuda ++ "AG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Argentina ++ "AR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Aruba ++ "AW", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Australia ++ "AU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Austria ++ "AT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bahamas ++ "BS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Barbados ++ "BB", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bermuda ++ "BM", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Brazil ++ "BR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 24, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Belgium ++ "BE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 18, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 18, IDOR, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bulgaria ++ "BG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Canada ++ "CA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Cayman IsLands ++ "KY", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Chile ++ "CL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // China ++ "CN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Colombia ++ "CO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Costa Rica ++ "CR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Cyprus ++ "CY", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Czech_Republic ++ "CZ", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Denmark ++ "DK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Dominican Republic ++ "DO", ++ CE, ++ { ++ { 1, 0, 20, BOTH, FALSE}, // 2.4 G, ch 0 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Equador ++ "EC", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 100, 11, 27, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // El Salvador ++ "SV", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 30, BOTH, TRUE}, // 5G, ch 52~64 ++ { 149, 4, 36, BOTH, TRUE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Finland ++ "FI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // France ++ "FR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Germany ++ "DE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Greece ++ "GR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Guam ++ "GU", ++ CE, ++ { ++ { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Guatemala ++ "GT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Haiti ++ "HT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Honduras ++ "HN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Hong Kong ++ "HK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Hungary ++ "HU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Iceland ++ "IS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // India ++ "IN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 24, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Indonesia ++ "ID", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Ireland ++ "IE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Israel ++ "IL", ++ CE, ++ { ++ { 1, 3, 20, IDOR, FALSE}, // 2.4 G, ch 1~3 ++ { 4, 6, 20, BOTH, FALSE}, // 2.4 G, ch 4~9 ++ { 10, 4, 20, IDOR, FALSE}, // 2.4 G, ch 10~13 ++ { 0}, // end ++ } ++ }, ++ ++ { // Italy ++ "IT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Japan ++ "JP", ++ JAP, ++ { ++ { 1, 14, 20, BOTH, FALSE}, // 2.4 G, ch 1~14 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 0}, // end ++ } ++ }, ++ ++ { // Jordan ++ "JO", ++ CE, ++ { ++ { 1, 13, 20, IDOR, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 149, 4, 23, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Latvia ++ "LV", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Liechtenstein ++ "LI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Lithuania ++ "LT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Luxemburg ++ "LU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Malaysia ++ "MY", ++ CE, ++ { ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Malta ++ "MT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Marocco ++ "MA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 ++ { 0}, // end ++ } ++ }, ++ ++ { // Mexico ++ "MX", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, IDOR, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Netherlands ++ "NL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // New Zealand ++ "NZ", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Norway ++ "NO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Peru ++ "PE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Portugal ++ "PT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Poland ++ "PL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Romania ++ "RO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Russia ++ "RU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 20, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Saudi Arabia ++ "SA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 23, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Serbia_and_Montenegro ++ "CS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 0}, // end ++ } ++ }, ++ ++ { // Singapore ++ "SG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Slovakia ++ "SK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Slovenia ++ "SI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // South Africa ++ "ZA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // South Korea ++ "KR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 8, 20, BOTH, FALSE}, // 5G, ch 100~128 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Spain ++ "ES", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Sweden ++ "SE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Switzerland ++ "CH", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Taiwan ++ "TW", ++ CE, ++ { ++ { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Turkey ++ "TR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // UK ++ "GB", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Ukraine ++ "UA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 0}, // end ++ } ++ }, ++ ++ { // United_Arab_Emirates ++ "AE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 0}, // end ++ } ++ }, ++ ++ { // United_States ++ "US", ++ CE, ++ { ++ { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 17, IDOR, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 24, BOTH, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Venezuela ++ "VE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Default ++ "", ++ CE, ++ { ++ { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 20, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++}; ++ ++static inline PCH_REGION GetChRegion( ++ IN PUCHAR CntryCode) ++{ ++ INT loop = 0; ++ PCH_REGION pChRegion = NULL; ++ ++ while (strcmp(ChRegion[loop].CountReg, "") != 0) ++ { ++ if (strncmp(ChRegion[loop].CountReg, CntryCode, 2) == 0) ++ { ++ pChRegion = &ChRegion[loop]; ++ break; ++ } ++ loop++; ++ } ++ ++ if (pChRegion == NULL) ++ pChRegion = &ChRegion[loop]; ++ return pChRegion; ++} ++ ++static inline VOID ChBandCheck( ++ IN UCHAR PhyMode, ++ OUT PUCHAR pChType) ++{ ++ switch(PhyMode) ++ { ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ *pChType = BAND_5G; ++ break; ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AGN_MIXED: ++ case PHY_11ABGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ *pChType = BAND_BOTH; ++ break; ++ ++ default: ++ *pChType = BAND_24G; ++ break; ++ } ++} ++ ++static inline UCHAR FillChList( ++ IN PRTMP_ADAPTER pAd, ++ IN PCH_DESP pChDesp, ++ IN UCHAR Offset, ++ IN UCHAR increment) ++{ ++ INT i, j, l; ++ UCHAR channel; ++ ++ j = Offset; ++ for (i = 0; i < pChDesp->NumOfCh; i++) ++ { ++ channel = pChDesp->FirstChannel + i * increment; ++ for (l=0; lTxPower[l].Channel) ++ { ++ pAd->ChannelList[j].Power = pAd->TxPower[l].Power; ++ pAd->ChannelList[j].Power2 = pAd->TxPower[l].Power2; ++ break; ++ } ++ } ++ if (l == MAX_NUM_OF_CHANNELS) ++ continue; ++ ++ pAd->ChannelList[j].Channel = pChDesp->FirstChannel + i * increment; ++ pAd->ChannelList[j].MaxTxPwr = pChDesp->MaxTxPwr; ++ pAd->ChannelList[j].DfsReq = pChDesp->DfsReq; ++ j++; ++ } ++ pAd->ChannelListNum = j; ++ ++ return j; ++} ++ ++static inline VOID CreateChList( ++ IN PRTMP_ADAPTER pAd, ++ IN PCH_REGION pChRegion, ++ IN UCHAR Geography) ++{ ++ INT i; ++ UCHAR offset = 0; ++ PCH_DESP pChDesp; ++ UCHAR ChType; ++ UCHAR increment; ++ ++ if (pChRegion == NULL) ++ return; ++ ++ ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); ++ ++ for (i=0; i<10; i++) ++ { ++ pChDesp = &pChRegion->ChDesp[i]; ++ if (pChDesp->FirstChannel == 0) ++ break; ++ ++ if (ChType == BAND_5G) ++ { ++ if (pChDesp->FirstChannel <= 14) ++ continue; ++ } ++ else if (ChType == BAND_24G) ++ { ++ if (pChDesp->FirstChannel > 14) ++ continue; ++ } ++ ++ if ((pChDesp->Geography == BOTH) ++ || (pChDesp->Geography == Geography)) ++ { ++ if (pChDesp->FirstChannel > 14) ++ increment = 4; ++ else ++ increment = 1; ++ offset = FillChList(pAd, pChDesp, offset, increment); ++ } ++ } ++} ++ ++static inline VOID BuildChannelListEx( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PCH_REGION pChReg; ++ ++ pChReg = GetChRegion(pAd->CommonCfg.CountryCode); ++ CreateChList(pAd, pChReg, pAd->CommonCfg.Geography); ++} ++ ++static inline VOID BuildBeaconChList( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf, ++ OUT PULONG pBufLen) ++{ ++ INT i; ++ ULONG TmpLen; ++ PCH_REGION pChRegion; ++ PCH_DESP pChDesp; ++ UCHAR ChType; ++ ++ pChRegion = GetChRegion(pAd->CommonCfg.CountryCode); ++ ++ if (pChRegion == NULL) ++ return; ++ ++ ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); ++ *pBufLen = 0; ++ ++ for (i=0; i<10; i++) ++ { ++ pChDesp = &pChRegion->ChDesp[i]; ++ if (pChDesp->FirstChannel == 0) ++ break; ++ ++ if (ChType == BAND_5G) ++ { ++ if (pChDesp->FirstChannel <= 14) ++ continue; ++ } ++ else if (ChType == BAND_24G) ++ { ++ if (pChDesp->FirstChannel > 14) ++ continue; ++ } ++ ++ if ((pChDesp->Geography == BOTH) ++ || (pChDesp->Geography == pAd->CommonCfg.Geography)) ++ { ++ MakeOutgoingFrame(pBuf + *pBufLen, &TmpLen, ++ 1, &pChDesp->FirstChannel, ++ 1, &pChDesp->NumOfCh, ++ 1, &pChDesp->MaxTxPwr, ++ END_OF_ARGS); ++ *pBufLen += TmpLen; ++ } ++ } ++} ++ ++ ++#ifdef DOT11_N_SUPPORT ++static inline BOOLEAN IsValidChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++ ++{ ++ INT i; ++ ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].Channel == channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++ ++static inline UCHAR GetExtCh( ++ IN UCHAR Channel, ++ IN UCHAR Direction) ++{ ++ CHAR ExtCh; ++ ++ if (Direction == EXTCHA_ABOVE) ++ ExtCh = Channel + 4; ++ else ++ ExtCh = (Channel - 4) > 0 ? (Channel - 4) : 0; ++ ++ return ExtCh; ++} ++ ++ ++static inline VOID N_ChannelCheck( ++ IN PRTMP_ADAPTER pAd) ++{ ++ //UCHAR ChannelNum = pAd->ChannelListNum; ++ UCHAR Channel = pAd->CommonCfg.Channel; ++ ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (Channel > 14) ++ { ++ if ((Channel == 36) || (Channel == 44) || (Channel == 52) || (Channel == 60) || (Channel == 100) || (Channel == 108) || ++ (Channel == 116) || (Channel == 124) || (Channel == 132) || (Channel == 149) || (Channel == 157)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ else if ((Channel == 40) || (Channel == 48) || (Channel == 56) || (Channel == 64) || (Channel == 104) || (Channel == 112) || ++ (Channel == 120) || (Channel == 128) || (Channel == 136) || (Channel == 153) || (Channel == 161)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } ++ } ++ else ++ { ++ do ++ { ++ UCHAR ExtCh; ++ UCHAR Dir = pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; ++ ExtCh = GetExtCh(Channel, Dir); ++ if (IsValidChannel(pAd, ExtCh)) ++ break; ++ ++ Dir = (Dir == EXTCHA_ABOVE) ? EXTCHA_BELOW : EXTCHA_ABOVE; ++ ExtCh = GetExtCh(Channel, Dir); ++ if (IsValidChannel(pAd, ExtCh)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = Dir; ++ break; ++ } ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } while(FALSE); ++ ++ if (Channel == 14) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ //pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_NONE; // We didn't set the ExtCh as NONE due to it'll set in RTMPSetHT() ++ } ++#if 0 ++ switch (pAd->CommonCfg.CountryRegion & 0x7f) ++ { ++ case REGION_0_BG_BAND: // 1 -11 ++ case REGION_1_BG_BAND: // 1 - 13 ++ case REGION_5_BG_BAND: // 1 - 14 ++ if (Channel <= 4) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ else if (Channel >= 8) ++ { ++ if ((ChannelNum - Channel) < 4) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ break; ++ ++ case REGION_2_BG_BAND: // 10 - 11 ++ case REGION_3_BG_BAND: // 10 - 13 ++ case REGION_4_BG_BAND: // 14 ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ break; ++ ++ case REGION_6_BG_BAND: // 3 - 9 ++ if (Channel <= 5) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else if (Channel == 6) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ else if (Channel >= 7) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ break; ++ ++ case REGION_7_BG_BAND: // 5 - 13 ++ if (Channel <= 8) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else if (Channel >= 10) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ break; ++ ++ default: // Error. should never happen ++ break; ++ } ++#endif ++ } ++ } ++ ++ ++} ++ ++ ++static inline VOID N_SetCenCh( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ if (pAd->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel == 14) ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 1; ++ else ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++ ++static inline UINT8 GetCuntryMaxTxPwr( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 channel) ++{ ++ int i; ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].Channel == channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return 0xff; ++ else ++ return pAd->ChannelList[i].MaxTxPwr; ++} ++#endif // __CHLIST_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/2860_rtmp_init.c +@@ -0,0 +1,922 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ 2860_rtmp_init.c ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme ++ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. ++*/ ++#include "../rt_config.h" ++ ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Allocate DMA memory blocks for send, receive ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPAllocTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ULONG RingBasePaHigh; ++ ULONG RingBasePaLow; ++ PVOID RingBaseVa; ++ INT index, num; ++ PTXD_STRUC pTxD; ++ PRXD_STRUC pRxD; ++ ULONG ErrorValue = 0; ++ PRTMP_TX_RING pTxRing; ++ PRTMP_DMABUF pDmaBuf; ++ PNDIS_PACKET pPacket; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n")); ++ do ++ { ++ // ++ // Allocate all ring descriptors, include TxD, RxD, MgmtD. ++ // Although each size is different, to prevent cacheline and alignment ++ // issue, I intentional set them all to 64 bytes. ++ // ++ for (num=0; numTxDescRing[num].AllocSize = TX_RING_SIZE * TXD_SIZE; ++ RTMP_AllocateTxDescMemory( ++ pAd, ++ num, ++ pAd->TxDescRing[num].AllocSize, ++ FALSE, ++ &pAd->TxDescRing[num].AllocVa, ++ &pAd->TxDescRing[num].AllocPa); ++ ++ if (pAd->TxDescRing[num].AllocVa == NULL) ++ { ++ ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; ++ DBGPRINT_ERR(("Failed to allocate a big buffer\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++ ++ // Zero init this memory block ++ NdisZeroMemory(pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocSize); ++ ++ // Save PA & VA for further operation ++ RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxDescRing[num].AllocPa); ++ RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxDescRing[num].AllocPa); ++ RingBaseVa = pAd->TxDescRing[num].AllocVa; ++ ++ // ++ // Allocate all 1st TXBuf's memory for this TxRing ++ // ++ pAd->TxBufSpace[num].AllocSize = TX_RING_SIZE * TX_DMA_1ST_BUFFER_SIZE; ++ RTMP_AllocateFirstTxBuffer( ++ pAd, ++ num, ++ pAd->TxBufSpace[num].AllocSize, ++ FALSE, ++ &pAd->TxBufSpace[num].AllocVa, ++ &pAd->TxBufSpace[num].AllocPa); ++ ++ if (pAd->TxBufSpace[num].AllocVa == NULL) ++ { ++ ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; ++ DBGPRINT_ERR(("Failed to allocate a big buffer\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++ ++ // Zero init this memory block ++ NdisZeroMemory(pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocSize); ++ ++ // Save PA & VA for further operation ++ BufBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxBufSpace[num].AllocPa); ++ BufBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxBufSpace[num].AllocPa); ++ BufBaseVa = pAd->TxBufSpace[num].AllocVa; ++ ++ // ++ // Initialize Tx Ring Descriptor and associated buffer memory ++ // ++ pTxRing = &pAd->TxRing[num]; ++ for (index = 0; index < TX_RING_SIZE; index++) ++ { ++ pTxRing->Cell[index].pNdisPacket = NULL; ++ pTxRing->Cell[index].pNextNdisPacket = NULL; ++ // Init Tx Ring Size, Va, Pa variables ++ pTxRing->Cell[index].AllocSize = TXD_SIZE; ++ pTxRing->Cell[index].AllocVa = RingBaseVa; ++ RTMP_SetPhysicalAddressHigh(pTxRing->Cell[index].AllocPa, RingBasePaHigh); ++ RTMP_SetPhysicalAddressLow (pTxRing->Cell[index].AllocPa, RingBasePaLow); ++ ++ // Setup Tx Buffer size & address. only 802.11 header will store in this space ++ pDmaBuf = &pTxRing->Cell[index].DmaBuf; ++ pDmaBuf->AllocSize = TX_DMA_1ST_BUFFER_SIZE; ++ pDmaBuf->AllocVa = BufBaseVa; ++ RTMP_SetPhysicalAddressHigh(pDmaBuf->AllocPa, BufBasePaHigh); ++ RTMP_SetPhysicalAddressLow(pDmaBuf->AllocPa, BufBasePaLow); ++ ++ // link the pre-allocated TxBuf to TXD ++ pTxD = (PTXD_STRUC) pTxRing->Cell[index].AllocVa; ++ pTxD->SDPtr0 = BufBasePaLow; ++ // advance to next ring descriptor address ++ pTxD->DMADONE = 1; ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ RingBasePaLow += TXD_SIZE; ++ RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE; ++ ++ // advance to next TxBuf address ++ BufBasePaLow += TX_DMA_1ST_BUFFER_SIZE; ++ BufBaseVa = (PUCHAR) BufBaseVa + TX_DMA_1ST_BUFFER_SIZE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("TxRing[%d]: total %d entry allocated\n", num, index)); ++ } ++ if (Status == NDIS_STATUS_RESOURCES) ++ break; ++ ++ // ++ // Allocate MGMT ring descriptor's memory except Tx ring which allocated eariler ++ // ++ pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * TXD_SIZE; ++ RTMP_AllocateMgmtDescMemory( ++ pAd, ++ pAd->MgmtDescRing.AllocSize, ++ FALSE, ++ &pAd->MgmtDescRing.AllocVa, ++ &pAd->MgmtDescRing.AllocPa); ++ ++ if (pAd->MgmtDescRing.AllocVa == NULL) ++ { ++ ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; ++ DBGPRINT_ERR(("Failed to allocate a big buffer\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++ ++ // Zero init this memory block ++ NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); ++ ++ // Save PA & VA for further operation ++ RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->MgmtDescRing.AllocPa); ++ RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->MgmtDescRing.AllocPa); ++ RingBaseVa = pAd->MgmtDescRing.AllocVa; ++ ++ // ++ // Initialize MGMT Ring and associated buffer memory ++ // ++ for (index = 0; index < MGMT_RING_SIZE; index++) ++ { ++ pAd->MgmtRing.Cell[index].pNdisPacket = NULL; ++ pAd->MgmtRing.Cell[index].pNextNdisPacket = NULL; ++ // Init MGMT Ring Size, Va, Pa variables ++ pAd->MgmtRing.Cell[index].AllocSize = TXD_SIZE; ++ pAd->MgmtRing.Cell[index].AllocVa = RingBaseVa; ++ RTMP_SetPhysicalAddressHigh(pAd->MgmtRing.Cell[index].AllocPa, RingBasePaHigh); ++ RTMP_SetPhysicalAddressLow (pAd->MgmtRing.Cell[index].AllocPa, RingBasePaLow); ++ ++ // Offset to next ring descriptor address ++ RingBasePaLow += TXD_SIZE; ++ RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE; ++ ++ // link the pre-allocated TxBuf to TXD ++ pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[index].AllocVa; ++ pTxD->DMADONE = 1; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ // no pre-allocated buffer required in MgmtRing for scatter-gather case ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", index)); ++ ++ // ++ // Allocate RX ring descriptor's memory except Tx ring which allocated eariler ++ // ++ pAd->RxDescRing.AllocSize = RX_RING_SIZE * RXD_SIZE; ++ RTMP_AllocateRxDescMemory( ++ pAd, ++ pAd->RxDescRing.AllocSize, ++ FALSE, ++ &pAd->RxDescRing.AllocVa, ++ &pAd->RxDescRing.AllocPa); ++ ++ if (pAd->RxDescRing.AllocVa == NULL) ++ { ++ ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; ++ DBGPRINT_ERR(("Failed to allocate a big buffer\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++ ++ // Zero init this memory block ++ NdisZeroMemory(pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocSize); ++ ++ ++ printk("RX DESC %p size = %ld\n", pAd->RxDescRing.AllocVa, ++ pAd->RxDescRing.AllocSize); ++ ++ // Save PA & VA for further operation ++ RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->RxDescRing.AllocPa); ++ RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->RxDescRing.AllocPa); ++ RingBaseVa = pAd->RxDescRing.AllocVa; ++ ++ // ++ // Initialize Rx Ring and associated buffer memory ++ // ++ for (index = 0; index < RX_RING_SIZE; index++) ++ { ++ // Init RX Ring Size, Va, Pa variables ++ pAd->RxRing.Cell[index].AllocSize = RXD_SIZE; ++ pAd->RxRing.Cell[index].AllocVa = RingBaseVa; ++ RTMP_SetPhysicalAddressHigh(pAd->RxRing.Cell[index].AllocPa, RingBasePaHigh); ++ RTMP_SetPhysicalAddressLow (pAd->RxRing.Cell[index].AllocPa, RingBasePaLow); ++ ++ // Offset to next ring descriptor address ++ RingBasePaLow += RXD_SIZE; ++ RingBaseVa = (PUCHAR) RingBaseVa + RXD_SIZE; ++ ++ // Setup Rx associated Buffer size & allocate share memory ++ pDmaBuf = &pAd->RxRing.Cell[index].DmaBuf; ++ pDmaBuf->AllocSize = RX_BUFFER_AGGRESIZE; ++ pPacket = RTMP_AllocateRxPacketBuffer( ++ pAd, ++ pDmaBuf->AllocSize, ++ FALSE, ++ &pDmaBuf->AllocVa, ++ &pDmaBuf->AllocPa); ++ ++ /* keep allocated rx packet */ ++ pAd->RxRing.Cell[index].pNdisPacket = pPacket; ++ ++ // Error handling ++ if (pDmaBuf->AllocVa == NULL) ++ { ++ ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY; ++ DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++ ++ // Zero init this memory block ++ NdisZeroMemory(pDmaBuf->AllocVa, pDmaBuf->AllocSize); ++ ++ // Write RxD buffer address & allocated buffer length ++ pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa; ++ pRxD->SDP0 = RTMP_GetPhysicalAddressLow(pDmaBuf->AllocPa); ++ pRxD->DDONE = 0; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); ++#endif ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Rx Ring: total %d entry allocated\n", index)); ++ ++ } while (FALSE); ++ ++ ++ NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME)); ++ pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); ++ ++ if (pAd->FragFrame.pFragPacket == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ } ++ ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ // Log error inforamtion ++ NdisWriteErrorLogEntry( ++ pAd->AdapterHandle, ++ NDIS_ERROR_CODE_OUT_OF_RESOURCES, ++ 1, ++ ErrorValue); ++ } ++ ++ DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status)); ++ return Status; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize transmit data structures ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Initialize all transmit releated private buffer, include those define ++ in RTMP_ADAPTER structure and all private data structures. ++ ++ ======================================================================== ++*/ ++VOID NICInitTxRxRingAndBacklogQueue( ++ IN PRTMP_ADAPTER pAd) ++{ ++ //WPDMA_GLO_CFG_STRUC GloCfg; ++ int i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--> NICInitTxRxRingAndBacklogQueue\n")); ++ ++ // Initialize all transmit related software queues ++ InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_BE]); ++ InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_BK]); ++ InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_VI]); ++ InitializeQueueHeader(&pAd->TxSwQueue[QID_AC_VO]); ++ InitializeQueueHeader(&pAd->TxSwQueue[QID_HCCA]); ++ ++ // Init RX Ring index pointer ++ pAd->RxRing.RxSwReadIdx = 0; ++ pAd->RxRing.RxCpuIdx = RX_RING_SIZE - 1; ++ ++ // Init TX rings index pointer ++ for (i=0; iTxRing[i].TxSwFreeIdx = 0; ++ pAd->TxRing[i].TxCpuIdx = 0; ++ } ++ ++ // init MGMT ring index pointer ++ pAd->MgmtRing.TxSwFreeIdx = 0; ++ pAd->MgmtRing.TxCpuIdx = 0; ++ ++ pAd->PrivateInfo.TxRingFullCnt = 0; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC Asics. Call after rest DMA. So reset TX_CTX_IDX to zero. ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID RTMPRingCleanUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType) ++{ ++ PTXD_STRUC pTxD; ++ PRXD_STRUC pRxD; ++ PQUEUE_ENTRY pEntry; ++ PNDIS_PACKET pPacket; ++ int i; ++ PRTMP_TX_RING pTxRing; ++ unsigned long IrqFlags; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPRingCleanUp(RingIdx=%d, Pending-NDIS=%ld)\n", RingType, pAd->RalinkCounters.PendingNdisPacketCount)); ++ switch (RingType) ++ { ++ case QID_AC_BK: ++ case QID_AC_BE: ++ case QID_AC_VI: ++ case QID_AC_VO: ++ case QID_HCCA: ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++ pTxRing = &pAd->TxRing[RingType]; ++ ++ // We have to clean all descriptors in case some error happened with reset ++ for (i=0; iCell[i].AllocVa; ++ ++ pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNdisPacket; ++ // release scatter-and-gather NDIS_PACKET ++ if (pPacket) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ pTxRing->Cell[i].pNdisPacket = NULL; ++ } ++ ++ pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNextNdisPacket; ++ // release scatter-and-gather NDIS_PACKET ++ if (pPacket) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ pTxRing->Cell[i].pNextNdisPacket = NULL; ++ } ++ } ++ ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + RingType * 0x10, &pTxRing->TxDmaIdx); ++ pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; ++ pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + RingType * 0x10, pTxRing->TxCpuIdx); ++ ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++ while (pAd->TxSwQueue[RingType].Head != NULL) ++ { ++ pEntry = RemoveHeadQueue(&pAd->TxSwQueue[RingType]); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ DBGPRINT(RT_DEBUG_TRACE,("Release 1 NDIS packet from s/w backlog queue\n")); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ break; ++ ++ case QID_MGMT: ++ // We have to clean all descriptors in case some error happened with reset ++ NdisAcquireSpinLock(&pAd->MgmtRingLock); ++ ++ for (i=0; iMgmtRing.Cell[i].AllocVa; ++ ++ pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNdisPacket; ++ // rlease scatter-and-gather NDIS_PACKET ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ pAd->MgmtRing.Cell[i].pNdisPacket = NULL; ++ ++ pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNextNdisPacket; ++ // release scatter-and-gather NDIS_PACKET ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL; ++ ++ } ++ ++ RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pAd->MgmtRing.TxDmaIdx); ++ pAd->MgmtRing.TxSwFreeIdx = pAd->MgmtRing.TxDmaIdx; ++ pAd->MgmtRing.TxCpuIdx = pAd->MgmtRing.TxDmaIdx; ++ RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); ++ ++ NdisReleaseSpinLock(&pAd->MgmtRingLock); ++ pAd->RalinkCounters.MgmtRingFullCount = 0; ++ break; ++ ++ case QID_RX: ++ // We have to clean all descriptors in case some error happened with reset ++ NdisAcquireSpinLock(&pAd->RxRingLock); ++ ++ for (i=0; iRxRing.Cell[i].AllocVa; ++ pRxD->DDONE = 0 ; ++ } ++ ++ RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx); ++ pAd->RxRing.RxSwReadIdx = pAd->RxRing.RxDmaIdx; ++ pAd->RxRing.RxCpuIdx = ((pAd->RxRing.RxDmaIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxDmaIdx-1)); ++ RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); ++ ++ NdisReleaseSpinLock(&pAd->RxRingLock); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++NDIS_STATUS AdapterBlockAllocateMemory( ++ IN PVOID handle, ++ OUT PVOID *ppAd) ++{ ++ PPCI_DEV pci_dev; ++ dma_addr_t *phy_addr; ++ POS_COOKIE pObj = (POS_COOKIE) handle; ++ ++ pci_dev = pObj->pci_dev; ++ phy_addr = &pObj->pAd_pa; ++ ++ *ppAd = (PVOID)vmalloc(sizeof(RTMP_ADAPTER)); //pci_alloc_consistent(pci_dev, sizeof(RTMP_ADAPTER), phy_addr); ++ ++ if (*ppAd) ++ { ++ NdisZeroMemory(*ppAd, sizeof(RTMP_ADAPTER)); ++ ((PRTMP_ADAPTER)*ppAd)->OS_Cookie = handle; ++ return (NDIS_STATUS_SUCCESS); ++ } else { ++ return (NDIS_STATUS_FAILURE); ++ } ++} ++ ++ ++void RTMP_AllocateTxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ *VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); ++ ++} ++ ++void RTMP_AllocateMgmtDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ *VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); ++ ++} ++ ++void RTMP_AllocateRxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ *VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); ++ ++} ++ ++void RTMP_FreeRxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN PVOID VirtualAddress, ++ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ PCI_FREE_CONSISTENT(pObj->pci_dev, Length, VirtualAddress, PhysicalAddress); ++} ++ ++ ++void RTMP_AllocateFirstTxBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ *VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); ++} ++ ++/* ++ * FUNCTION: Allocate a common buffer for DMA ++ * ARGUMENTS: ++ * AdapterHandle: AdapterHandle ++ * Length: Number of bytes to allocate ++ * Cached: Whether or not the memory can be cached ++ * VirtualAddress: Pointer to memory is returned here ++ * PhysicalAddress: Physical address corresponding to virtual address ++ */ ++ ++void RTMP_AllocateSharedMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ *VirtualAddress = (PVOID)PCI_ALLOC_CONSISTENT(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); ++} ++ ++VOID RTMPFreeTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int index, num , j; ++ PRTMP_TX_RING pTxRing; ++ PTXD_STRUC pTxD; ++ PNDIS_PACKET pPacket; ++ unsigned int IrqFlags; ++ ++ POS_COOKIE pObj =(POS_COOKIE) pAd->OS_Cookie; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n")); ++ ++ // Free TxSwQueue Packet ++ for (index=0; index irq_lock, IrqFlags); ++ pQueue = &pAd->TxSwQueue[index]; ++ while (pQueue->Head) ++ { ++ pEntry = RemoveHeadQueue(pQueue); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ } ++ ++ // Free Tx Ring Packet ++ for (index=0;index< NUM_OF_TX_RING;index++) ++ { ++ pTxRing = &pAd->TxRing[index]; ++ ++ for (j=0; j< TX_RING_SIZE; j++) ++ { ++ pTxD = (PTXD_STRUC) (pTxRing->Cell[j].AllocVa); ++ pPacket = pTxRing->Cell[j].pNdisPacket; ++ ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[j].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[j].pNextNdisPacket; ++ ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = NULL; ++ ++ } ++ } ++ ++ for (index = RX_RING_SIZE - 1 ; index >= 0; index--) ++ { ++ if ((pAd->RxRing.Cell[index].DmaBuf.AllocVa) && (pAd->RxRing.Cell[index].pNdisPacket)) ++ { ++ PCI_UNMAP_SINGLE(pObj->pci_dev, pAd->RxRing.Cell[index].DmaBuf.AllocPa, pAd->RxRing.Cell[index].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE); ++ RELEASE_NDIS_PACKET(pAd, pAd->RxRing.Cell[index].pNdisPacket, NDIS_STATUS_SUCCESS); ++ } ++ } ++ NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(RTMP_DMACB)); ++ ++ if (pAd->RxDescRing.AllocVa) ++ { ++ PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->RxDescRing.AllocSize, pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocPa); ++ } ++ NdisZeroMemory(&pAd->RxDescRing, sizeof(RTMP_DMABUF)); ++ ++ if (pAd->MgmtDescRing.AllocVa) ++ { ++ PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->MgmtDescRing.AllocSize, pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocPa); ++ } ++ NdisZeroMemory(&pAd->MgmtDescRing, sizeof(RTMP_DMABUF)); ++ ++ for (num = 0; num < NUM_OF_TX_RING; num++) ++ { ++ if (pAd->TxBufSpace[num].AllocVa) ++ { ++ PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->TxBufSpace[num].AllocSize, pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocPa); ++ } ++ NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(RTMP_DMABUF)); ++ ++ if (pAd->TxDescRing[num].AllocVa) ++ { ++ PCI_FREE_CONSISTENT(pObj->pci_dev, pAd->TxDescRing[num].AllocSize, pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocPa); ++ } ++ NdisZeroMemory(&pAd->TxDescRing[num], sizeof(RTMP_DMABUF)); ++ } ++ ++ if (pAd->FragFrame.pFragPacket) ++ RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n")); ++} ++ ++ ++/* ++ * FUNCTION: Allocate a packet buffer for DMA ++ * ARGUMENTS: ++ * AdapterHandle: AdapterHandle ++ * Length: Number of bytes to allocate ++ * Cached: Whether or not the memory can be cached ++ * VirtualAddress: Pointer to memory is returned here ++ * PhysicalAddress: Physical address corresponding to virtual address ++ * Notes: ++ * Cached is ignored: always cached memory ++ */ ++PNDIS_PACKET RTMP_AllocateRxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) ++{ ++ PNDIS_PACKET pkt; ++ ++ pkt = RTPKT_TO_OSPKT(DEV_ALLOC_SKB(Length)); ++ ++ if (pkt == NULL) { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate rx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) { ++ RTMP_SET_PACKET_SOURCE(pkt, PKTSRC_NDIS); ++ *VirtualAddress = (PVOID) RTPKT_TO_OSPKT(pkt)->data; ++ *PhysicalAddress = PCI_MAP_SINGLE(pAd, *VirtualAddress, Length, -1, PCI_DMA_FROMDEVICE); ++ } else { ++ *VirtualAddress = (PVOID) NULL; ++ *PhysicalAddress = (NDIS_PHYSICAL_ADDRESS) NULL; ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++VOID Invalid_Remaining_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG VirtualAddress) ++{ ++ NDIS_PHYSICAL_ADDRESS PhysicalAddress; ++ ++ PhysicalAddress = PCI_MAP_SINGLE(pAd, (void *)(VirtualAddress+1600), RX_BUFFER_NORMSIZE-1600, -1, PCI_DMA_FROMDEVICE); ++} ++ ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending) ++{ ++ PRXD_STRUC pRxD; ++#ifdef RT_BIG_ENDIAN ++ PRXD_STRUC pDestRxD; ++ RXD_STRUC RxD; ++#endif ++ PNDIS_PACKET pRxPacket = NULL; ++ PNDIS_PACKET pNewPacket; ++ PVOID AllocVa; ++ NDIS_PHYSICAL_ADDRESS AllocPa; ++ BOOLEAN bReschedule = FALSE; ++ ++ RTMP_SEM_LOCK(&pAd->RxRingLock); ++ ++ if (*pRxPending == 0) ++ { ++ // Get how may packets had been received ++ RTMP_IO_READ32(pAd, RX_DRX_IDX , &pAd->RxRing.RxDmaIdx); ++ ++ if (pAd->RxRing.RxSwReadIdx == pAd->RxRing.RxDmaIdx) ++ { ++ // no more rx packets ++ bReschedule = FALSE; ++ goto done; ++ } ++ ++ // get rx pending count ++ if (pAd->RxRing.RxDmaIdx > pAd->RxRing.RxSwReadIdx) ++ *pRxPending = pAd->RxRing.RxDmaIdx - pAd->RxRing.RxSwReadIdx; ++ else ++ *pRxPending = pAd->RxRing.RxDmaIdx + RX_RING_SIZE - pAd->RxRing.RxSwReadIdx; ++ ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ pDestRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa; ++ RxD = *pDestRxD; ++ pRxD = &RxD; ++ RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); ++#else ++ // Point to Rx indexed rx ring descriptor ++ pRxD = (PRXD_STRUC) pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].AllocVa; ++#endif ++ ++ if (pRxD->DDONE == 0) ++ { ++ *pRxPending = 0; ++ // DMAIndx had done but DDONE bit not ready ++ bReschedule = TRUE; ++ goto done; ++ } ++ ++ ++ // return rx descriptor ++ NdisMoveMemory(pSaveRxD, pRxD, RXD_SIZE); ++ ++ pNewPacket = RTMP_AllocateRxPacketBuffer(pAd, RX_BUFFER_AGGRESIZE, FALSE, &AllocVa, &AllocPa); ++ ++ if (pNewPacket) ++ { ++ // unmap the rx buffer ++ PCI_UNMAP_SINGLE(pAd, pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocPa, ++ pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE); ++ pRxPacket = pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].pNdisPacket; ++ ++ pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocSize = RX_BUFFER_AGGRESIZE; ++ pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].pNdisPacket = (PNDIS_PACKET) pNewPacket; ++ pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocVa = AllocVa; ++ pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx].DmaBuf.AllocPa = AllocPa; ++ /* update SDP0 to new buffer of rx packet */ ++ pRxD->SDP0 = AllocPa; ++ } ++ else ++ { ++ //printk("No Rx Buffer\n"); ++ pRxPacket = NULL; ++ bReschedule = TRUE; ++ } ++ ++ pRxD->DDONE = 0; ++ ++ // had handled one rx packet ++ *pRxPending = *pRxPending - 1; ++ ++ // update rx descriptor and kick rx ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pRxD, TYPE_RXD); ++ WriteBackToDescriptor((PUCHAR)pDestRxD, (PUCHAR)pRxD, FALSE, TYPE_RXD); ++#endif ++ INC_RING_INDEX(pAd->RxRing.RxSwReadIdx, RX_RING_SIZE); ++ ++ pAd->RxRing.RxCpuIdx = (pAd->RxRing.RxSwReadIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxSwReadIdx-1); ++ RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); ++ ++done: ++ RTMP_SEM_UNLOCK(&pAd->RxRingLock); ++ *pbReschedule = bReschedule; ++ return pRxPacket; ++} ++/* End of 2860_rtmp_init.c */ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/action.c +@@ -0,0 +1,1031 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ action.c ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 2006 created for rt2860 ++ */ ++ ++#include "../rt_config.h" ++#include "action.h" ++ ++ ++static VOID ReservedAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ Note: ++ The state machine looks like the following ++ ++ ASSOC_IDLE ++ MT2_MLME_DISASSOC_REQ mlme_disassoc_req_action ++ MT2_PEER_DISASSOC_REQ peer_disassoc_action ++ MT2_PEER_ASSOC_REQ drop ++ MT2_PEER_REASSOC_REQ drop ++ MT2_CLS3ERR cls3err_action ++ ========================================================================== ++ */ ++VOID ActionStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, (STATE_MACHINE_FUNC *)Trans, MAX_ACT_STATE, MAX_ACT_MSG, (STATE_MACHINE_FUNC)Drop, ACT_IDLE, ACT_MACHINE_BASE); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_SPECTRUM_CATE, (STATE_MACHINE_FUNC)PeerSpectrumAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_QOS_CATE, (STATE_MACHINE_FUNC)PeerQOSAction); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)ReservedAction); ++#ifdef QOS_DLS_SUPPORT ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)PeerDLSAction); ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_BA_CATE, (STATE_MACHINE_FUNC)PeerBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_HT_CATE, (STATE_MACHINE_FUNC)PeerHTAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ADD_BA_CATE, (STATE_MACHINE_FUNC)MlmeADDBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ORI_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_REC_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); ++#endif // DOT11_N_SUPPORT // ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_PUBLIC_CATE, (STATE_MACHINE_FUNC)PeerPublicAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_RM_CATE, (STATE_MACHINE_FUNC)PeerRMAction); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_QOS_CATE, (STATE_MACHINE_FUNC)MlmeQOSAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_DLS_CATE, (STATE_MACHINE_FUNC)MlmeDLSAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_ACT_INVALID, (STATE_MACHINE_FUNC)MlmeInvalidAction); ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID MlmeADDBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ MLME_ADDBA_REQ_STRUCT *pInfo; ++ UCHAR Addr[6]; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG Idx; ++ FRAME_ADDBA_REQ Frame; ++ ULONG FrameLen; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ ++ pInfo = (MLME_ADDBA_REQ_STRUCT *)Elem->Msg; ++ NdisZeroMemory(&Frame, sizeof(FRAME_ADDBA_REQ)); ++ ++ if(MlmeAddBAReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++ // 1. find entry ++ Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; ++ if (Idx == 0) ++ { ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() can't find BAOriEntry \n")); ++ return; ++ } ++ else ++ { ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) ++ ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pInfo->pAddr); ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ Frame.Category = CATEGORY_BA; ++ Frame.Action = ADDBA_REQ; ++ Frame.BaParm.AMSDUSupported = 0; ++ Frame.BaParm.BAPolicy = IMMED_BA; ++ Frame.BaParm.TID = pInfo->TID; ++ Frame.BaParm.BufSize = pInfo->BaBufSize; ++ Frame.Token = pInfo->Token; ++ Frame.TimeOutValue = pInfo->TimeOutValue; ++ Frame.BaStartSeq.field.FragNum = 0; ++ Frame.BaStartSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; ++ ++ *(USHORT *)(&Frame.BaParm) = cpu2le16(*(USHORT *)(&Frame.BaParm)); ++ Frame.TimeOutValue = cpu2le16(Frame.TimeOutValue); ++ Frame.BaStartSeq.word = cpu2le16(Frame.BaStartSeq.word); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ADDBA_REQ), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BA - Send ADDBA request. StartSeq = %x, FrameLen = %ld. BufSize = %d\n", Frame.BaStartSeq.field.StartSeq, FrameLen, Frame.BaParm.BufSize)); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ send DELBA and delete BaEntry if any ++ Parametrs: ++ Elem - MLME message MLME_DELBA_REQ_STRUCT ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDELBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DELBA_REQ_STRUCT *pInfo; ++ PUCHAR pOutBuffer = NULL; ++ PUCHAR pOutBuffer2 = NULL; ++ NDIS_STATUS NStatus; ++ ULONG Idx; ++ FRAME_DELBA_REQ Frame; ++ ULONG FrameLen; ++ FRAME_BAR FrameBar; ++ ++ pInfo = (MLME_DELBA_REQ_STRUCT *)Elem->Msg; ++ // must send back DELBA ++ NdisZeroMemory(&Frame, sizeof(FRAME_DELBA_REQ)); ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeDELBAAction(), Initiator(%d) \n", pInfo->Initiator)); ++ ++ if(MlmeDelBAReqSanity(pAd, Elem->Msg, Elem->MsgLen)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeDELBAAction() allocate memory failed 1. \n")); ++ return; ++ } ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR, ("BA - MlmeDELBAAction() allocate memory failed 2. \n")); ++ return; ++ } ++ ++ // SEND BAR (Send BAR to refresh peer reordering buffer.) ++ Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL funciton. ++ FrameBar.StartingSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = pInfo->TID; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.ACKPolicy = IMMED_BA; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.Compressed = 1; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.MTID = 0; // make sure sequence not clear in DEL funciton. ++ ++ MakeOutgoingFrame(pOutBuffer2, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer2); ++ DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeDELBAAction() . Send BAR to refresh peer reordering buffer \n")); ++ ++ // SEND DELBA FRAME ++ FrameLen = 0; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[pInfo->Wcid].Addr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ Frame.Category = CATEGORY_BA; ++ Frame.Action = DELBA; ++ Frame.DelbaParm.Initiator = pInfo->Initiator; ++ Frame.DelbaParm.TID = pInfo->TID; ++ Frame.ReasonCode = 39; // Time Out ++ *(USHORT *)(&Frame.DelbaParm) = cpu2le16(*(USHORT *)(&Frame.DelbaParm)); ++ Frame.ReasonCode = cpu2le16(Frame.ReasonCode); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_DELBA_REQ), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("BA - MlmeDELBAAction() . 3 DELBA sent. Initiator(%d)\n", pInfo->Initiator)); ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID MlmeQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++VOID MlmeDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++VOID MlmeInvalidAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ //PUCHAR pOutBuffer = NULL; ++ //Return the receiving frame except the MSB of category filed set to 1. 7.3.1.11 ++} ++ ++VOID PeerQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++#ifdef QOS_DLS_SUPPORT ++VOID PeerDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ switch(Action) ++ { ++ case ACTION_DLS_REQUEST: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsReqAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ ++ case ACTION_DLS_RESPONSE: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsRspAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ ++ case ACTION_DLS_TEARDOWN: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsTearDownAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ } ++} ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ switch(Action) ++ { ++ case ADDBA_REQ: ++ PeerAddBAReqAction(pAd,Elem); ++ break; ++ case ADDBA_RESP: ++ PeerAddBARspAction(pAd,Elem); ++ break; ++ case DELBA: ++ PeerDelBAAction(pAd,Elem); ++ break; ++ } ++} ++ ++ ++#ifdef DOT11N_DRAFT3 ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID StaPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Bss2040Coexist) ++{ ++ BSS_2040_COEXIST_IE BssCoexist; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ BssCoexist.word = Bss2040Coexist; ++ // AP asks Station to return a 20/40 BSS Coexistence mgmt frame. So we first starts a scan, then send back 20/40 BSS Coexistence mgmt frame ++ if ((BssCoexist.field.InfoReq == 1) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))) ++ { ++ // Clear record first. After scan , will update those bit and send back to transmiter. ++ pAd->CommonCfg.BSSCoexist2040.field.InfoReq = 1; ++ pAd->CommonCfg.BSSCoexist2040.field.Intolerant40 = 0; ++ pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 0; ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_2040_BSS_COEXIST); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ } ++} ++ ++ ++/* ++Description : Build Intolerant Channel Rerpot from Trigger event table. ++return : how many bytes copied. ++*/ ++ULONG BuildIntolerantChannelRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest) ++{ ++ ULONG FrameLen = 0; ++ ULONG ReadOffset = 0; ++ UCHAR i; ++ UCHAR LastRegClass = 0xff; ++ PUCHAR pLen; ++ ++ for ( i = 0;i < MAX_TRIGGER_EVENT;i++) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid == TRUE) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass == LastRegClass) ++ { ++ *(pDest + ReadOffset) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; ++ *pLen++; ++ ReadOffset++; ++ FrameLen++; ++ } ++ else ++ { ++ *(pDest + ReadOffset) = IE_2040_BSS_INTOLERANT_REPORT; // IE ++ *(pDest + ReadOffset + 1) = 2; // Len = RegClass byte + channel byte. ++ pLen = pDest + ReadOffset + 1; ++ LastRegClass = pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass; ++ *(pDest + ReadOffset + 2) = LastRegClass; // Len = RegClass byte + channel byte. ++ *(pDest + ReadOffset + 3) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; ++ FrameLen += 4; ++ ReadOffset += 4; ++ } ++ ++ } ++ } ++ return FrameLen; ++} ++ ++ ++/* ++Description : Send 20/40 BSS Coexistence Action frame If one trigger event is triggered. ++*/ ++VOID Send2040CoexistAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ FRAME_ACTION_HDR Frame; ++ ULONG FrameLen; ++ ULONG IntolerantChaRepLen; ++ ++ IntolerantChaRepLen = 0; ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction() allocate memory failed \n")); ++ return; ++ } ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[Wcid].Addr, pAd->CommonCfg.Bssid); ++ Frame.Category = CATEGORY_PUBLIC; ++ Frame.Action = ACTION_BSS_2040_COEXIST; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ACTION_HDR), &Frame, ++ END_OF_ARGS); ++ ++ *(pOutBuffer + FrameLen) = pAd->CommonCfg.BSSCoexist2040.word; ++ FrameLen++; ++ ++ if (bAddIntolerantCha == TRUE) ++ IntolerantChaRepLen = BuildIntolerantChannelRep(pAd, pOutBuffer + FrameLen); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen + IntolerantChaRepLen); ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction( BSSCoexist2040 = 0x%x ) \n", pAd->CommonCfg.BSSCoexist2040.word)); ++ ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ After scan, Update 20/40 BSS Coexistence IE and send out. ++ According to 802.11n D3.03 11.14.10 ++ ++ Parameters: ++ ========================================================================== ++ */ ++VOID Update2040CoexistFrameAndNotify( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha) ++{ ++ BSS_2040_COEXIST_IE OldValue; ++ ++ OldValue.word = pAd->CommonCfg.BSSCoexist2040.word; ++ if ((pAd->CommonCfg.TriggerEventTab.EventANo > 0) || (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)) ++ pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 1; ++ ++ // Need to check !!!! ++ // How STA will set Intolerant40 if implementation dependent. Now we don't set this bit first.!!!!! ++ // So Only check BSS20WidthReq change. ++ if (OldValue.field.BSS20WidthReq != pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq) ++ { ++ Send2040CoexistAction(pAd, Wcid, bAddIntolerantCha); ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++BOOLEAN ChannelSwitchSanityCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary) ++{ ++ UCHAR i; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ if ((NewChannel > 7) && (Secondary == 1)) ++ return FALSE; ++ ++ if ((NewChannel < 5) && (Secondary == 3)) ++ return FALSE; ++ ++ // 0. Check if new channel is in the channellist. ++ for (i = 0;i < pAd->ChannelListNum;i++) ++ { ++ if (pAd->ChannelList[i].Channel == NewChannel) ++ { ++ break; ++ } ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++VOID ChannelSwitchAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary) ++{ ++ UCHAR BBPValue = 0; ++ ULONG MACValue; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SPECTRUM - ChannelSwitchAction(NewChannel = %d , Secondary = %d) \n", NewChannel, Secondary)); ++ ++ if (ChannelSwitchSanityCheck(pAd, Wcid, NewChannel, Secondary) == FALSE) ++ return; ++ ++ // 1. Switches to BW = 20. ++ if (Secondary == 0) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ pAd->CommonCfg.Channel = NewChannel; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel,FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz !!! \n" )); ++ } ++ // 1. Switches to BW = 40 And Station supports BW = 40. ++ else if (((Secondary == 1) || (Secondary == 3)) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == 1)) ++ { ++ pAd->CommonCfg.Channel = NewChannel; ++ ++ if (Secondary == 1) ++ { ++ // Secondary above. ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); ++ MACValue &= 0xfe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); ++ BBPValue&= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++ { ++ // Secondary below. ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); ++ MACValue &= 0xfe; ++ MACValue |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); ++ BBPValue&= (~0x20); ++ BBPValue|= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 1; ++ } ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++VOID PeerPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++#ifdef DOT11N_DRAFT3 ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++#endif // DOT11N_DRAFT3 // ++ ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++#ifdef DOT11N_DRAFT3 ++ switch(Action) ++ { ++ case ACTION_BSS_2040_COEXIST: // Format defined in IEEE 7.4.7a.1 in 11n Draf3.03 ++ { ++ //UCHAR BssCoexist; ++ BSS_2040_COEXIST_ELEMENT *pCoexistInfo; ++ BSS_2040_COEXIST_IE *pBssCoexistIe; ++ BSS_2040_INTOLERANT_CH_REPORT *pIntolerantReport = NULL; ++ ++ if (Elem->MsgLen <= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT)) ) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ACTION - 20/40 BSS Coexistence Management Frame length too short! len = %ld!\n", Elem->MsgLen)); ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("ACTION - 20/40 BSS Coexistence Management action----> \n")); ++ hex_dump("CoexistenceMgmtFrame", Elem->Msg, Elem->MsgLen); ++ ++ ++ pCoexistInfo = (BSS_2040_COEXIST_ELEMENT *) &Elem->Msg[LENGTH_802_11+2]; ++ //hex_dump("CoexistInfo", (PUCHAR)pCoexistInfo, sizeof(BSS_2040_COEXIST_ELEMENT)); ++ if (Elem->MsgLen >= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT) + sizeof(BSS_2040_INTOLERANT_CH_REPORT))) ++ { ++ pIntolerantReport = (BSS_2040_INTOLERANT_CH_REPORT *)((PUCHAR)pCoexistInfo + sizeof(BSS_2040_COEXIST_ELEMENT)); ++ } ++ //hex_dump("IntolerantReport ", (PUCHAR)pIntolerantReport, sizeof(BSS_2040_INTOLERANT_CH_REPORT)); ++ ++ pBssCoexistIe = (BSS_2040_COEXIST_IE *)(&pCoexistInfo->BssCoexistIe); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ StaPublicAction(pAd, pCoexistInfo); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++ break; ++ } ++ ++#endif // DOT11N_DRAFT3 // ++ ++} ++ ++ ++static VOID ReservedAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Category; ++ ++ if (Elem->MsgLen <= LENGTH_802_11) ++ { ++ return; ++ } ++ ++ Category = Elem->Msg[LENGTH_802_11]; ++ DBGPRINT(RT_DEBUG_TRACE,("Rcv reserved category(%d) Action Frame\n", Category)); ++ hex_dump("Reserved Action Frame", &Elem->Msg[0], Elem->MsgLen); ++} ++ ++VOID PeerRMAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ return; ++} ++ ++#ifdef DOT11_N_SUPPORT ++static VOID respond_ht_information_exchange_action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ FRAME_HT_INFO HTINFOframe, *pFrame; ++ UCHAR *pAddr; ++ ++ ++ // 2. Always send back ADDBA Response ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - respond_ht_information_exchange_action() allocate memory failed \n")); ++ return; ++ } ++ ++ // get RA ++ pFrame = (FRAME_HT_INFO *) &Elem->Msg[0]; ++ pAddr = pFrame->Hdr.Addr2; ++ ++ NdisZeroMemory(&HTINFOframe, sizeof(FRAME_HT_INFO)); ++ // 2-1. Prepare ADDBA Response frame. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &HTINFOframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++ ActHeaderInit(pAd, &HTINFOframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ HTINFOframe.Category = CATEGORY_HT; ++ HTINFOframe.Action = HT_INFO_EXCHANGE; ++ HTINFOframe.HT_Info.Request = 0; ++ HTINFOframe.HT_Info.Forty_MHz_Intolerant = pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant; ++ HTINFOframe.HT_Info.STA_Channel_Width = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_HT_INFO), &HTINFOframe, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID SendNotifyBWActionFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ FRAME_ACTION_HDR Frame; ++ ULONG FrameLen; ++ PUCHAR pAddr1; ++ ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - SendNotifyBWAction() allocate memory failed \n")); ++ return; ++ } ++ ++ if (Wcid == MCAST_WCID) ++ pAddr1 = &BROADCAST_ADDR[0]; ++ else ++ pAddr1 = pAd->MacTab.Content[Wcid].Addr; ++ ActHeaderInit(pAd, &Frame.Hdr, pAddr1, pAd->ApCfg.MBSSID[apidx].Bssid, pAd->ApCfg.MBSSID[apidx].Bssid); ++ ++ Frame.Category = CATEGORY_HT; ++ Frame.Action = NOTIFY_BW_ACTION; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ACTION_HDR), &Frame, ++ END_OF_ARGS); ++ ++ *(pOutBuffer + FrameLen) = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; ++ FrameLen++; ++ ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ DBGPRINT(RT_DEBUG_TRACE,("ACT - SendNotifyBWAction(NotifyBW= %d)!\n", pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)); ++ ++} ++#endif // DOT11N_DRAFT3 // ++ ++ ++VOID PeerHTAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ switch(Action) ++ { ++ case NOTIFY_BW_ACTION: ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Notify Channel bandwidth action----> \n")); ++#ifdef CONFIG_STA_SUPPORT ++ if(pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ { ++ // Note, this is to patch DIR-1353 AP. When the AP set to Wep, it will use legacy mode. But AP still keeps ++ // sending BW_Notify Action frame, and cause us to linkup and linkdown. ++ // In legacy mode, don't need to parse HT action frame. ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION -Ignore HT Notify Channel BW when link as legacy mode. BW = %d---> \n", ++ Elem->Msg[LENGTH_802_11+2] )); ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (Elem->Msg[LENGTH_802_11+2] == 0) // 7.4.8.2. if value is 1, keep the same as supported channel bandwidth. ++ pAd->MacTab.Content[Elem->Wcid].HTPhyMode.field.BW = 0; ++ ++ break; ++ case SMPS_ACTION: ++ // 7.3.1.25 ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - SMPS action----> \n")); ++ if (((Elem->Msg[LENGTH_802_11+2]&0x1) == 0)) ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_ENABLE; ++ } ++ else if (((Elem->Msg[LENGTH_802_11+2]&0x2) == 0)) ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_STATIC; ++ } ++ else ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_DYNAMIC; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Aid(%d) MIMO PS = %d\n", Elem->Wcid, pAd->MacTab.Content[Elem->Wcid].MmpsMode)); ++ // rt2860c : add something for smps change. ++ break; ++ ++ case SETPCO_ACTION: ++ break; ++ case MIMO_CHA_MEASURE_ACTION: ++ break; ++ case HT_INFO_EXCHANGE: ++ { ++ HT_INFORMATION_OCTET *pHT_info; ++ ++ pHT_info = (HT_INFORMATION_OCTET *) &Elem->Msg[LENGTH_802_11+2]; ++ // 7.4.8.10 ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Information Exchange action----> \n")); ++ if (pHT_info->Request) ++ { ++ respond_ht_information_exchange_action(pAd, Elem); ++ } ++ } ++ break; ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Retry sending ADDBA Reqest. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Parametrs: ++ p8023Header: if this is already 802.3 format, p8023Header is NULL ++ ++ Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. ++ FALSE , then continue indicaterx at this moment. ++ ========================================================================== ++ */ ++VOID ORIBATimerTimeout( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MAC_TABLE_ENTRY *pEntry; ++ INT i, total; ++ UCHAR TID; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ total = pAd->MacTab.Size * NUM_OF_TID; ++ ++ for (i = 1; ((i 0)) ; i++) ++ { ++ if (pAd->BATable.BAOriEntry[i].ORI_BA_Status == Originator_Done) ++ { ++ pEntry = &pAd->MacTab.Content[pAd->BATable.BAOriEntry[i].Wcid]; ++ TID = pAd->BATable.BAOriEntry[i].TID; ++ ++ ASSERT(pAd->BATable.BAOriEntry[i].Wcid < MAX_LEN_OF_MAC_TABLE); ++ } ++ total --; ++ } ++} ++ ++ ++VOID SendRefreshBAR( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ FRAME_BAR FrameBar; ++ ULONG FrameLen; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ USHORT Sequence; ++ UCHAR i, TID; ++ USHORT idx; ++ BA_ORI_ENTRY *pBAEntry; ++ ++ for (i = 0; i BAOriWcidArray[i]; ++ if (idx == 0) ++ { ++ continue; ++ } ++ pBAEntry = &pAd->BATable.BAOriEntry[idx]; ++ ++ if (pBAEntry->ORI_BA_Status == Originator_Done) ++ { ++ TID = pBAEntry->TID; ++ ++ ASSERT(pBAEntry->Wcid < MAX_LEN_OF_MAC_TABLE); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++ ++ Sequence = pEntry->TxSeq[TID]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. ++ FrameBar.StartingSeq.field.StartSeq = Sequence; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = TID; // make sure sequence not clear in DEL funciton. ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ if (1) // Now we always send BAR. ++ { ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ } ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID ActHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN PUCHAR Addr1, ++ IN PUCHAR Addr2, ++ IN PUCHAR Addr3) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SUBTYPE_ACTION; ++ ++ COPY_MAC_ADDR(pHdr80211->Addr1, Addr1); ++ COPY_MAC_ADDR(pHdr80211->Addr2, Addr2); ++ COPY_MAC_ADDR(pHdr80211->Addr3, Addr3); ++} ++ ++VOID BarHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PFRAME_BAR pCntlBar, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA) ++{ ++ NdisZeroMemory(pCntlBar, sizeof(FRAME_BAR)); ++ pCntlBar->FC.Type = BTYPE_CNTL; ++ pCntlBar->FC.SubType = SUBTYPE_BLOCK_ACK_REQ; ++ pCntlBar->BarControl.MTID = 0; ++ pCntlBar->BarControl.Compressed = 1; ++ pCntlBar->BarControl.ACKPolicy = 0; ++ ++ ++ pCntlBar->Duration = 16 + RTMPCalcDuration(pAd, RATE_1, sizeof(FRAME_BA)); ++ ++ COPY_MAC_ADDR(pCntlBar->Addr1, pDA); ++ COPY_MAC_ADDR(pCntlBar->Addr2, pSA); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Category and action code into the action frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. category code of the frame. ++ 4. action code of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID InsertActField( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 Category, ++ IN UINT8 ActCode) ++{ ++ ULONG TempLen; ++ ++ MakeOutgoingFrame( pFrameBuf, &TempLen, ++ 1, &Category, ++ 1, &ActCode, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/rt2860/common/action.h +@@ -0,0 +1,68 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 04-06-15 Initial ++*/ ++ ++#ifndef __ACTION_H__ ++#define __ACTION_H__ ++ ++typedef struct PACKED __HT_INFO_OCTET ++{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR Reserved:5; ++ UCHAR STA_Channel_Width:1; ++ UCHAR Forty_MHz_Intolerant:1; ++ UCHAR Request:1; ++#else ++ UCHAR Request:1; ++ UCHAR Forty_MHz_Intolerant:1; ++ UCHAR STA_Channel_Width:1; ++ UCHAR Reserved:5; ++#endif ++} HT_INFORMATION_OCTET; ++ ++ ++typedef struct PACKED __FRAME_HT_INFO ++{ ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ HT_INFORMATION_OCTET HT_Info; ++} FRAME_HT_INFO, *PFRAME_HT_INFO; ++ ++#endif /* __ACTION_H__ */ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/ba_action.c +@@ -0,0 +1,1802 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifdef DOT11_N_SUPPORT ++ ++#include "../rt_config.h" ++ ++ ++ ++#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) //1 // inital sequence number of BA session ++ ++#define ORI_SESSION_MAX_RETRY 8 ++#define ORI_BA_SESSION_TIMEOUT (2000) // ms ++#define REC_BA_SESSION_IDLE_TIMEOUT (1000) // ms ++ ++#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms ++#define MAX_REORDERING_PACKET_TIMEOUT ((3000 * HZ)/1000) // system ticks -- 100 ms ++ ++#define RESET_RCV_SEQ (0xFFFF) ++ ++static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk); ++ ++ ++BA_ORI_ENTRY *BATableAllocOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx); ++ ++BA_REC_ENTRY *BATableAllocRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx); ++ ++VOID BAOriSessionSetupTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID BARecSessionIdleTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout); ++BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout); ++ ++#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk) \ ++ Announce_Reordering_Packet(_pAd, _mpdu_blk); ++ ++VOID BA_MaxWinSizeReasign( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntryPeer, ++ OUT UCHAR *pWinSize) ++{ ++ UCHAR MaxSize; ++ ++ ++ if (pAd->MACVersion >= RALINK_2883_VERSION) // 3*3 ++ { ++ if (pAd->MACVersion >= RALINK_3070_VERSION) ++ { ++ if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) ++ MaxSize = 7; // for non-open mode ++ else ++ MaxSize = 13; ++ } ++ else ++ MaxSize = 31; ++ } ++ else if (pAd->MACVersion >= RALINK_2880E_VERSION) // 2880 e ++ { ++ if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) ++ MaxSize = 7; // for non-open mode ++ else ++ MaxSize = 13; ++ } ++ else ++ MaxSize = 7; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n", ++ *pWinSize, MaxSize)); ++ ++ if ((*pWinSize) > MaxSize) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ba> reassign max win size from %d to %d\n", ++ *pWinSize, MaxSize)); ++ ++ *pWinSize = MaxSize; ++ } ++} ++ ++void Announce_Reordering_Packet(IN PRTMP_ADAPTER pAd, ++ IN struct reordering_mpdu *mpdu) ++{ ++ PNDIS_PACKET pPacket; ++ ++ pPacket = mpdu->pPacket; ++ ++ if (mpdu->bAMSDU) ++ { ++ ASSERT(0); ++ BA_Reorder_AMSDU_Annnounce(pAd, pPacket); ++ } ++ else ++ { ++ // ++ // pass this 802.3 packet to upper layer or forward this packet to WM directly ++ // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++/* ++ * Insert a reordering mpdu into sorted linked list by sequence no. ++ */ ++BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list, struct reordering_mpdu *mpdu) ++{ ++ ++ struct reordering_mpdu **ppScan = &list->next; ++ ++ while (*ppScan != NULL) ++ { ++ if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ)) ++ { ++ ppScan = &(*ppScan)->next; ++ } ++ else if ((*ppScan)->Sequence == mpdu->Sequence) ++ { ++ /* give up this duplicated frame */ ++ return(FALSE); ++ } ++ else ++ { ++ /* find position */ ++ break; ++ } ++ } ++ ++ mpdu->next = *ppScan; ++ *ppScan = mpdu; ++ list->qlen++; ++ return TRUE; ++} ++ ++ ++/* ++ * caller lock critical section if necessary ++ */ ++static inline void ba_enqueue(struct reordering_list *list, struct reordering_mpdu *mpdu_blk) ++{ ++ list->qlen++; ++ mpdu_blk->next = list->next; ++ list->next = mpdu_blk; ++} ++ ++/* ++ * caller lock critical section if necessary ++ */ ++static inline struct reordering_mpdu * ba_dequeue(struct reordering_list *list) ++{ ++ struct reordering_mpdu *mpdu_blk = NULL; ++ ++ ASSERT(list); ++ ++ if (list->qlen) ++ { ++ list->qlen--; ++ mpdu_blk = list->next; ++ if (mpdu_blk) ++ { ++ list->next = mpdu_blk->next; ++ mpdu_blk->next = NULL; ++ } ++ } ++ return mpdu_blk; ++} ++ ++ ++static inline struct reordering_mpdu *ba_reordering_mpdu_dequeue(struct reordering_list *list) ++{ ++ return(ba_dequeue(list)); ++} ++ ++ ++static inline struct reordering_mpdu *ba_reordering_mpdu_probe(struct reordering_list *list) ++ { ++ ASSERT(list); ++ ++ return(list->next); ++ } ++ ++ ++/* ++ * free all resource for reordering mechanism ++ */ ++void ba_reordering_resource_release(PRTMP_ADAPTER pAd) ++{ ++ BA_TABLE *Tab; ++ PBA_REC_ENTRY pBAEntry; ++ struct reordering_mpdu *mpdu_blk; ++ int i; ++ ++ Tab = &pAd->BATable; ++ ++ /* I. release all pending reordering packet */ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ pBAEntry = &Tab->BARecEntry[i]; ++ if (pBAEntry->REC_BA_Status != Recipient_NONE) ++ { ++ while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) ++ { ++ ASSERT(mpdu_blk->pPacket); ++ RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket, NDIS_STATUS_FAILURE); ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ } ++ } ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ ++ ASSERT(pBAEntry->list.qlen == 0); ++ /* II. free memory of reordering mpdu table */ ++ NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); ++ os_free_mem(pAd, pAd->mpdu_blk_pool.mem); ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++} ++ ++ ++ ++/* ++ * Allocate all resource for reordering mechanism ++ */ ++BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num) ++{ ++ int i; ++ PUCHAR mem; ++ struct reordering_mpdu *mpdu_blk; ++ struct reordering_list *freelist; ++ ++ /* allocate spinlock */ ++ NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock); ++ ++ /* initialize freelist */ ++ freelist = &pAd->mpdu_blk_pool.freelist; ++ freelist->next = NULL; ++ freelist->qlen = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Allocate %d memory for BA reordering\n", (UINT32)(num*sizeof(struct reordering_mpdu)))); ++ ++ /* allocate number of mpdu_blk memory */ ++ os_alloc_mem(pAd, (PUCHAR *)&mem, (num*sizeof(struct reordering_mpdu))); ++ ++ pAd->mpdu_blk_pool.mem = mem; ++ ++ if (mem == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Can't Allocate Memory for BA Reordering\n")); ++ return(FALSE); ++ } ++ ++ /* build mpdu_blk free list */ ++ for (i=0; impdu_blk_pool.lock); ++ mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist); ++ if (mpdu_blk) ++ { ++// blk_count++; ++ /* reset mpdu_blk */ ++ NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu)); ++ } ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++ return mpdu_blk; ++} ++ ++static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk) ++{ ++ ASSERT(mpdu_blk); ++ ++ NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); ++// blk_count--; ++ ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk); ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++} ++ ++ ++static USHORT ba_indicate_reordering_mpdus_in_order( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN USHORT StartSeq) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ USHORT LastIndSeq = RESET_RCV_SEQ; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) ++ { ++ /* find in-order frame */ ++ if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ)) ++ { ++ break; ++ } ++ /* dequeue in-order frame from reodering list */ ++ mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ /* move to next sequence */ ++ StartSeq = mpdu_blk->Sequence; ++ LastIndSeq = StartSeq; ++ /* free mpdu_blk */ ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ ++ /* update last indicated sequence */ ++ return LastIndSeq; ++} ++ ++static void ba_indicate_reordering_mpdus_le_seq( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN USHORT Sequence) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) ++ { ++ /* find in-order frame */ ++ if ((mpdu_blk->Sequence == Sequence) || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ)) ++ { ++ /* dequeue in-order frame from reodering list */ ++ mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ /* free mpdu_blk */ ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ else ++ { ++ break; ++ } ++ } ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++} ++ ++ ++static void ba_refresh_reordering_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ PBA_REC_ENTRY pBAEntry) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ /* dequeue in-order frame from reodering list */ ++ while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) ++ { ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ ++ pBAEntry->LastIndSeq = mpdu_blk->Sequence; ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ ++ /* update last indicated sequence */ ++ } ++ ASSERT(pBAEntry->list.qlen == 0); ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++} ++ ++ ++//static ++void ba_flush_reordering_timeout_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN ULONG Now32) ++ ++{ ++ USHORT Sequence; ++ ++// if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) && ++// (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //|| ++// (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) && ++// (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8))) ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT/6))) ++ &&(pBAEntry->list.qlen > 1) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++ (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, ++ pBAEntry->LastIndSeq)); ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++ else ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) ++ && (pBAEntry->list.qlen > 0) ++ ) ++ { ++// printk("timeout[%d] (%lx-%lx = %d > %d): %x, ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++// (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), REORDERING_PACKET_TIMEOUT, ++// pBAEntry->LastIndSeq); ++ // ++ // force LastIndSeq to shift to LastIndSeq+1 ++ // ++ Sequence = (pBAEntry->LastIndSeq+1) & MAXSEQ; ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ pBAEntry->LastIndSeq = Sequence; ++ // ++ // indicate in-order mpdus ++ // ++ Sequence = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, Sequence); ++ if (Sequence != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = Sequence; ++ } ++ ++ //printk("%x, flush one!\n", pBAEntry->LastIndSeq); ++ ++ } ++#if 0 ++ else if ( ++ (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT))) && ++ (pBAEntry->list.qlen > 1)) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%lx-%lx = %d > %d): %x\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++ (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, ++ pBAEntry->LastIndSeq)); ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++#endif ++} ++ ++ ++/* ++ * generate ADDBA request to ++ * set up BA agreement ++ */ ++VOID BAOriSessionSetUp( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN UCHAR TID, ++ IN USHORT TimeOut, ++ IN ULONG DelayTime, ++ IN BOOLEAN isForced) ++ ++{ ++ //MLME_ADDBA_REQ_STRUCT AddbaReq; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ USHORT Idx; ++ BOOLEAN Cancelled; ++ ++ if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE) && (isForced == FALSE)) ++ return; ++ ++ // if this entry is limited to use legacy tx mode, it doesn't generate BA. ++ if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT) ++ return; ++ ++ if ((pEntry->BADeclineBitmap & (1<BAOriWcidArray[TID]; ++ if (Idx == 0) ++ { ++ // allocate a BA session ++ pBAEntry = BATableAllocOriEntry(pAd, &Idx); ++ if (pBAEntry == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ADDBA - MlmeADDBAAction() allocate BA session failed \n")); ++ return; ++ } ++ } ++ else ++ { ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ } ++ ++ if (pBAEntry->ORI_BA_Status >= Originator_WaitRes) ++ { ++ return; ++ } ++ ++ pEntry->BAOriWcidArray[TID] = Idx; ++ ++ // Initialize BA session ++ pBAEntry->ORI_BA_Status = Originator_WaitRes; ++ pBAEntry->Wcid = pEntry->Aid; ++ pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; ++ pBAEntry->Sequence = BA_ORI_INIT_SEQ; ++ pBAEntry->Token = 1; // (2008-01-21) Jan Lee recommends it - this token can't be 0 ++ pBAEntry->TID = TID; ++ pBAEntry->TimeOutValue = TimeOut; ++ pBAEntry->pAdapter = pAd; ++ ++ if (!(pEntry->TXBAbitmap & (1<ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE); ++ } ++ else ++ RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); ++ ++ // set timer to send ADDBA request ++ RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime); ++} ++ ++VOID BAOriSessionAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PFRAME_ADDBA_RSP pFrame) ++{ ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ BOOLEAN Cancelled; ++ UCHAR TID; ++ USHORT Idx; ++ PUCHAR pOutBuffer2 = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ FRAME_BAR FrameBar; ++ ++ TID = pFrame->BaParm.TID; ++ Idx = pEntry->BAOriWcidArray[TID]; ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ ++ // Start fill in parameters. ++ if ((Idx !=0) && (pBAEntry->TID == TID) && (pBAEntry->ORI_BA_Status == Originator_WaitRes)) ++ { ++ pBAEntry->BAWinSize = min(pBAEntry->BAWinSize, ((UCHAR)pFrame->BaParm.BufSize)); ++ BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize); ++ ++ pBAEntry->TimeOutValue = pFrame->TimeOutValue; ++ pBAEntry->ORI_BA_Status = Originator_Done; ++ // reset sequence number ++ pBAEntry->Sequence = BA_ORI_INIT_SEQ; ++ // Set Bitmap flag. ++ pEntry->TXBAbitmap |= (1<ORIBATimer, &Cancelled); ++ ++ pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap, ++ pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue)); ++ ++ // SEND BAR ; ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - BAOriSessionAdd() allocate memory failed \n")); ++ return; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. ++ FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = pBAEntry->TID; // make sure sequence not clear in DEL funciton. ++ MakeOutgoingFrame(pOutBuffer2, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer2); ++ ++ ++ if (pBAEntry->ORIBATimer.TimerValue) ++ RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue); // in mSec ++ } ++} ++ ++BOOLEAN BARecSessionAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PFRAME_ADDBA_REQ pFrame) ++{ ++ BA_REC_ENTRY *pBAEntry = NULL; ++ BOOLEAN Status = TRUE; ++ BOOLEAN Cancelled; ++ USHORT Idx; ++ UCHAR TID; ++ UCHAR BAWinSize; ++ //UINT32 Value; ++ //UINT offset; ++ ++ ++ ASSERT(pEntry); ++ ++ // find TID ++ TID = pFrame->BaParm.TID; ++ ++ BAWinSize = min(((UCHAR)pFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ ++ // Intel patch ++ if (BAWinSize == 0) ++ { ++ BAWinSize = 64; ++ } ++ ++ Idx = pEntry->BARecWcidArray[TID]; ++ ++ ++ if (Idx == 0) ++ { ++ pBAEntry = BATableAllocRecEntry(pAd, &Idx); ++ } ++ else ++ { ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx, ++ pFrame->BaParm.BufSize, BAWinSize)); ++ ++ // Start fill in parameters. ++ if (pBAEntry != NULL) ++ { ++ ASSERT(pBAEntry->list.qlen == 0); ++ ++ pBAEntry->REC_BA_Status = Recipient_HandleRes; ++ pBAEntry->BAWinSize = BAWinSize; ++ pBAEntry->Wcid = pEntry->Aid; ++ pBAEntry->TID = TID; ++ pBAEntry->TimeOutValue = pFrame->TimeOutValue; ++ pBAEntry->REC_BA_Status = Recipient_Accept; ++ // initial sequence number ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; //pFrame->BaStartSeq.field.StartSeq; ++ ++ printk("Start Seq = %08x\n", pFrame->BaStartSeq.field.StartSeq); ++ ++ if (pEntry->RXBAbitmap & (1<RECBATimer, &Cancelled); ++ } ++ else ++ { ++ RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE); ++ } ++ ++#if 0 // for debugging ++ RTMPSetTimer(&pBAEntry->RECBATimer, REC_BA_SESSION_IDLE_TIMEOUT); ++#endif ++ ++ // Set Bitmap flag. ++ pEntry->RXBAbitmap |= (1<BARecWcidArray[TID] = Idx; ++ ++ pEntry->BADeclineBitmap &= ~(1<Aid, TID); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n", ++ pEntry->Aid, pEntry->RXBAbitmap, pEntry->BARecWcidArray[TID])); ++ } ++ else ++ { ++ Status = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE,("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n", ++ PRINT_MAC(pEntry->Addr), TID)); ++ } ++ return(Status); ++} ++ ++ ++BA_REC_ENTRY *BATableAllocRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx) ++{ ++ int i; ++ BA_REC_ENTRY *pBAEntry = NULL; ++ ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION) ++ { ++ printk("BA Recipeint Session (%ld) > %d\n", pAd->BATable.numAsRecipient, ++ MAX_BARECI_SESSION); ++ goto done; ++ } ++ ++ // reserve idx 0 to identify BAWcidArray[TID] as empty ++ for (i=1; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ pBAEntry =&pAd->BATable.BARecEntry[i]; ++ if ((pBAEntry->REC_BA_Status == Recipient_NONE)) ++ { ++ // get one ++ pAd->BATable.numAsRecipient++; ++ pBAEntry->REC_BA_Status = Recipient_USED; ++ *Idx = i; ++ break; ++ } ++ } ++ ++done: ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ return pBAEntry; ++} ++ ++BA_ORI_ENTRY *BATableAllocOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx) ++{ ++ int i; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE)) ++ { ++ goto done; ++ } ++ ++ // reserve idx 0 to identify BAWcidArray[TID] as empty ++ for (i=1; iBATable.BAOriEntry[i]; ++ if ((pBAEntry->ORI_BA_Status == Originator_NONE)) ++ { ++ // get one ++ pAd->BATable.numAsOriginator++; ++ pBAEntry->ORI_BA_Status = Originator_USED; ++ pBAEntry->pAdapter = pAd; ++ *Idx = i; ++ break; ++ } ++ } ++ ++done: ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ return pBAEntry; ++} ++ ++ ++VOID BATableFreeOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Idx) ++{ ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) ++ return; ++ ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ ++ if (pBAEntry->ORI_BA_Status != Originator_NONE) ++ { ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ pEntry->BAOriWcidArray[pBAEntry->TID] = 0; ++ ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ if (pBAEntry->ORI_BA_Status == Originator_Done) ++ { ++ pEntry->TXBAbitmap &= (~(1<<(pBAEntry->TID) )); ++ DBGPRINT(RT_DEBUG_TRACE, ("BATableFreeOriEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); ++ // Erase Bitmap flag. ++ } ++ ++ ASSERT(pAd->BATable.numAsOriginator != 0); ++ ++ pAd->BATable.numAsOriginator -= 1; ++ ++ pBAEntry->ORI_BA_Status = Originator_NONE; ++ pBAEntry->Token = 0; ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++ ++ ++VOID BATableFreeRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Idx) ++{ ++ BA_REC_ENTRY *pBAEntry = NULL; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE)) ++ return; ++ ++ pBAEntry =&pAd->BATable.BARecEntry[Idx]; ++ ++ if (pBAEntry->REC_BA_Status != Recipient_NONE) ++ { ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ pEntry->BARecWcidArray[pBAEntry->TID] = 0; ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ ASSERT(pAd->BATable.numAsRecipient != 0); ++ ++ pAd->BATable.numAsRecipient -= 1; ++ ++ pBAEntry->REC_BA_Status = Recipient_NONE; ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++ ++ ++VOID BAOriSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive, ++ IN BOOLEAN bForceSend) ++{ ++ ULONG Idx = 0; ++ BA_ORI_ENTRY *pBAEntry; ++ BOOLEAN Cancelled; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ { ++ return; ++ } ++ ++ // ++ // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). ++ // ++ Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID]; ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) ++ { ++ if (bForceSend == TRUE) ++ { ++ // force send specified TID DelBA ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = TID; ++ DelbaReq.Initiator = ORIGINATOR; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ ++ pBAEntry = &pAd->BATable.BAOriEntry[Idx]; ++ DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status)); ++ // ++ // Prepare DelBA action frame and send to the peer. ++ // ++ if ((bPassive == FALSE) && (TID == pBAEntry->TID) && (pBAEntry->ORI_BA_Status == Originator_Done)) ++ { ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = pBAEntry->TID; ++ DelbaReq.Initiator = ORIGINATOR; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); ++ BATableFreeOriEntry(pAd, Idx); ++ ++ if (bPassive) ++ { ++ //BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE); ++ } ++} ++ ++VOID BARecSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive) ++{ ++ ULONG Idx = 0; ++ BA_REC_ENTRY *pBAEntry; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ { ++ return; ++ } ++ ++ // ++ // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). ++ // ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx == 0) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ ++ ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->REC_BA_Status)); ++ // ++ // Prepare DelBA action frame and send to the peer. ++ // ++ if ((TID == pBAEntry->TID) && (pBAEntry->REC_BA_Status == Recipient_Accept)) ++ { ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ BOOLEAN Cancelled; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ //ULONG offset; ++ //UINT32 VALUE; ++ ++ RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled); ++ ++ // ++ // 1. Send DELBA Action Frame ++ // ++ if (bPassive == FALSE) ++ { ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = TID; ++ DelbaReq.Initiator = RECIPIENT; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ ++ ++ // ++ // 2. Free resource of BA session ++ // ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ // Erase Bitmap flag. ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; ++ pBAEntry->BAWinSize = 0; ++ // Erase Bitmap flag at software mactable ++ pAd->MacTab.Content[Wcid].RXBAbitmap &= (~(1<<(pBAEntry->TID))); ++ pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0; ++ ++ RT28XX_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID); ++ ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ ++ } ++ ++ BATableFreeRecEntry(pAd, Idx); ++} ++ ++VOID BASessionTearDownALL( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid) ++{ ++ int i; ++ ++ for (i=0; ipAdapter; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ ++ if ((pBAEntry->ORI_BA_Status == Originator_WaitRes) && (pBAEntry->Token < ORI_SESSION_MAX_RETRY)) ++ { ++ MLME_ADDBA_REQ_STRUCT AddbaReq; ++ ++ NdisZeroMemory(&AddbaReq, sizeof(AddbaReq)); ++ COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr); ++ AddbaReq.Wcid = (UCHAR)(pEntry->Aid); ++ AddbaReq.TID = pBAEntry->TID; ++ AddbaReq.BaBufSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; ++ AddbaReq.TimeOutValue = 0; ++ AddbaReq.Token = pBAEntry->Token; ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++ DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token)); ++ ++ pBAEntry->Token++; ++ RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT); ++ } ++ else ++ { ++ BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Retry sending ADDBA Reqest. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Parametrs: ++ p8023Header: if this is already 802.3 format, p8023Header is NULL ++ ++ Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. ++ FALSE , then continue indicaterx at this moment. ++ ========================================================================== ++ */ ++VOID BARecSessionIdleTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ++ BA_REC_ENTRY *pBAEntry = (BA_REC_ENTRY *)FunctionContext; ++ PRTMP_ADAPTER pAd; ++ ULONG Now32; ++ ++ if (pBAEntry == NULL) ++ return; ++ ++ if ((pBAEntry->REC_BA_Status == Recipient_Accept)) ++ { ++ NdisGetSystemUpTime(&Now32); ++ ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer + REC_BA_SESSION_IDLE_TIMEOUT))) ++ { ++ pAd = pBAEntry->pAdapter; ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ printk("%ld: REC BA session Timeout\n", Now32); ++ } ++ } ++} ++ ++ ++VOID PeerAddBAReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ // 7.4.4.1 ++ //ULONG Idx; ++ UCHAR Status = 1; ++ UCHAR pAddr[6]; ++ FRAME_ADDBA_RSP ADDframe; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ PFRAME_ADDBA_REQ pAddreqFrame = NULL; ++ //UCHAR BufSize; ++ ULONG FrameLen; ++ PULONG ptemp; ++ PMAC_TABLE_ENTRY pMacEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid)); ++ ++ //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); ++ ++ //ADDBA Request from unknown peer, ignore this. ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ pMacEntry = &pAd->MacTab.Content[Elem->Wcid]; ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerAddBAReqAction----> \n")); ++ ptemp = (PULONG)Elem->Msg; ++ //DBGPRINT_RAW(RT_DEBUG_EMU, ("%08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x\n", *(ptemp), *(ptemp+1), *(ptemp+2), *(ptemp+3), *(ptemp+4), *(ptemp+5), *(ptemp+6), *(ptemp+7), *(ptemp+8))); ++ ++ if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr)) ++ { ++ ++ if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry)) ++ { ++ pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); ++ printk("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid); ++ if (BARecSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pAddreqFrame)) ++ Status = 0; ++ else ++ Status = 38; // more parameters have invalid values ++ } ++ else ++ { ++ Status = 37; // the request has been declined. ++ } ++ } ++ ++ if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI) ++ ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC); ++ ++ pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); ++ // 2. Always send back ADDBA Response ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - PeerBAAction() allocate memory failed \n")); ++ return; ++ } ++ ++ NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP)); ++ // 2-1. Prepare ADDBA Response frame. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->MacTab.Content[Elem->Wcid].ValidAsDls) ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ADDframe.Category = CATEGORY_BA; ++ ADDframe.Action = ADDBA_RESP; ++ ADDframe.Token = pAddreqFrame->Token; ++ // What is the Status code?? need to check. ++ ADDframe.StatusCode = Status; ++ ADDframe.BaParm.BAPolicy = IMMED_BA; ++ ADDframe.BaParm.AMSDUSupported = 0; ++ ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID; ++ ADDframe.BaParm.BufSize = min(((UCHAR)pAddreqFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ if (ADDframe.BaParm.BufSize == 0) ++ { ++ ADDframe.BaParm.BufSize = 64; ++ } ++ ADDframe.TimeOutValue = 0; //pAddreqFrame->TimeOutValue; ++ ++ *(USHORT *)(&ADDframe.BaParm) = cpu2le16(*(USHORT *)(&ADDframe.BaParm)); ++ ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode); ++ ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ADDBA_RSP), &ADDframe, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID, ++ ADDframe.BaParm.BufSize)); ++} ++ ++ ++VOID PeerAddBARspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ //UCHAR Idx, i; ++ //PUCHAR pOutBuffer = NULL; ++ PFRAME_ADDBA_RSP pFrame = NULL; ++ //PBA_ORI_ENTRY pBAEntry; ++ ++ //ADDBA Response from unknown peer, ignore this. ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid)); ++ ++ //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); ++ ++ if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen)) ++ { ++ pFrame = (PFRAME_ADDBA_RSP)(&Elem->Msg[0]); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\t\t StatusCode = %d\n", pFrame->StatusCode)); ++ switch (pFrame->StatusCode) ++ { ++ case 0: ++ // I want a BAsession with this peer as an originator. ++ BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pFrame); ++ break; ++ default: ++ // check status == USED ??? ++ BAOriSessionTearDown(pAd, Elem->Wcid, pFrame->BaParm.TID, TRUE, FALSE); ++ break; ++ } ++ // Rcv Decline StatusCode ++ if ((pFrame->StatusCode == 37) ++#ifdef CONFIG_STA_SUPPORT ++ || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0)) ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<BaParm.TID; ++ } ++ } ++} ++ ++VOID PeerDelBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ //UCHAR Idx; ++ //PUCHAR pOutBuffer = NULL; ++ PFRAME_DELBA_REQ pDelFrame = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__)); ++ //DELBA Request from unknown peer, ignore this. ++ if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) ++ { ++ pDelFrame = (PFRAME_DELBA_REQ)(&Elem->Msg[0]); ++ if (pDelFrame->DelbaParm.Initiator == ORIGINATOR) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> ORIGINATOR\n")); ++ BARecSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n", pDelFrame->ReasonCode)); ++ //hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen); ++ BAOriSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE, FALSE); ++ } ++ } ++} ++ ++ ++BOOLEAN CntlEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG MsgLen, ++ IN PFRAME_BA_REQ pMsg) ++{ ++ PFRAME_BA_REQ pFrame = pMsg; ++ //PRTMP_REORDERBUF pBuffer; ++ //PRTMP_REORDERBUF pDmaBuf; ++ PBA_REC_ENTRY pBAEntry; ++ //BOOLEAN Result; ++ ULONG Idx; ++ //UCHAR NumRxPkt; ++ UCHAR TID;//, i; ++ ++ TID = (UCHAR)pFrame->BARControl.TID; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID)); ++ //hex_dump("BAR", (PCHAR) pFrame, MsgLen); ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return FALSE; ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ else if (MsgLen != sizeof(FRAME_BA_REQ)) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ else if (MsgLen != sizeof(FRAME_BA_REQ)) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ ++ if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8)) ++ { ++ // if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search. ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ } ++ else ++ { ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID, pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq )); ++ ++ if (SEQ_SMALLER(pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq, MAXSEQ)) ++ { ++ //printk("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq); ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, pFrame->BAStartingSeq.field.StartSeq); ++ pBAEntry->LastIndSeq = (pFrame->BAStartingSeq.field.StartSeq == 0) ? MAXSEQ :(pFrame->BAStartingSeq.field.StartSeq -1); ++ } ++ //ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ return TRUE; ++} ++ ++/* ++Description : Send PSMP Action frame If PSMP mode switches. ++*/ ++VOID SendPSMPAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Psmp) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ //ULONG Idx; ++ FRAME_PSMP_ACTION Frame; ++ ULONG FrameLen; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); ++#endif // CONFIG_STA_SUPPORT // ++ ++ Frame.Category = CATEGORY_HT; ++ Frame.Action = SMPS_ACTION; ++ switch (Psmp) ++ { ++ case MMPS_ENABLE: ++ Frame.Psmp = 0; ++ break; ++ case MMPS_DYNAMIC: ++ Frame.Psmp = 3; ++ break; ++ case MMPS_STATIC: ++ Frame.Psmp = 1; ++ break; ++ } ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_PSMP_ACTION), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR,("HT - SendPSMPAction( %d ) \n", Frame.Psmp)); ++} ++ ++ ++#define RADIO_MEASUREMENT_REQUEST_ACTION 0 ++ ++typedef struct PACKED ++{ ++ UCHAR RegulatoryClass; ++ UCHAR ChannelNumber; ++ USHORT RandomInterval; ++ USHORT MeasurementDuration; ++ UCHAR MeasurementMode; ++ UCHAR BSSID[MAC_ADDR_LEN]; ++ UCHAR ReportingCondition; ++ UCHAR Threshold; ++ UCHAR SSIDIE[2]; // 2 byte ++} BEACON_REQUEST; ++ ++typedef struct PACKED ++{ ++ UCHAR ID; ++ UCHAR Length; ++ UCHAR Token; ++ UCHAR RequestMode; ++ UCHAR Type; ++} MEASUREMENT_REQ; ++ ++ ++ ++ ++void convert_reordering_packet_to_preAMSDU_or_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNDIS_PACKET pRxPkt; ++ UCHAR Header802_3[LENGTH_802_3]; ++ ++ // 1. get 802.3 Header ++ // 2. remove LLC ++ // a. pointer pRxBlk->pData to payload ++ // b. modify pRxBlk->DataSize ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ASSERT(pRxBlk->pRxPacket); ++ pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ RTPKT_TO_OSPKT(pRxPkt)->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ RTPKT_TO_OSPKT(pRxPkt)->data = pRxBlk->pData; ++ RTPKT_TO_OSPKT(pRxPkt)->len = pRxBlk->DataSize; ++ RTPKT_TO_OSPKT(pRxPkt)->tail = RTPKT_TO_OSPKT(pRxPkt)->data + RTPKT_TO_OSPKT(pRxPkt)->len; ++ ++ // ++ // copy 802.3 header, if necessary ++ // ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef LINUX ++ NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); ++#endif ++#ifdef UCOS ++ NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); ++#endif ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++ ++#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID) \ ++ do \ ++ { \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU)) \ ++ { \ ++ Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP)) \ ++ { \ ++ Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ else \ ++ { \ ++ Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ } while (0); ++ ++ ++ ++static VOID ba_enqueue_reordering_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ UINT16 Sequence = (UINT16) pRxBlk->pHeader->Sequence; ++ ++ mpdu_blk = ba_mpdu_blk_alloc(pAd); ++ if (mpdu_blk != NULL) ++ { ++ // Write RxD buffer address & allocated buffer length ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ mpdu_blk->Sequence = Sequence; ++ ++ mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU); ++ ++ convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd, pRxBlk, FromWhichBSSID); ++ ++ STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); ++ ++ // ++ // it is necessary for reordering packet to record ++ // which BSS it come from ++ // ++ RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); ++ ++ mpdu_blk->pPacket = pRxBlk->pRxPacket; ++ ++ if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk) == FALSE) ++ { ++ // had been already within reordering list ++ // don't indicate ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_SUCCESS); ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ ++ ASSERT((0<= pBAEntry->list.qlen) && (pBAEntry->list.qlen <= pBAEntry->BAWinSize)); ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ } ++ else ++ { ++#if 0 ++ DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d:%d) Can't allocate reordering mpdu blk\n", ++ blk_count, pBAEntry->list.qlen)); ++#else ++ DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d) Can't allocate reordering mpdu blk\n", ++ pBAEntry->list.qlen)); ++#endif ++ /* ++ * flush all pending reordering mpdus ++ * and receving mpdu to upper layer ++ * make tcp/ip to take care reordering mechanism ++ */ ++ //ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); ++ ++ pBAEntry->LastIndSeq = Sequence; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Indicate this packet to upper layer or put it into reordering buffer ++ ++ Parametrs: ++ pRxBlk : carry necessary packet info 802.11 format ++ FromWhichBSSID : the packet received from which BSS ++ ++ Return : ++ none ++ ++ Note : ++ the packet queued into reordering buffer need to cover to 802.3 format ++ or pre_AMSDU format ++ ========================================================================== ++ */ ++ ++VOID Indicate_AMPDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ USHORT Idx; ++ PBA_REC_ENTRY pBAEntry = NULL; ++ UINT16 Sequence = pRxBlk->pHeader->Sequence; ++ ULONG Now32; ++ UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; ++ UCHAR TID = pRxBlk->pRxWI->TID; ++ ++ ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) ++ { ++#if 0 // sample take off, no use ++ static int err_size; ++ ++ err_size++; ++ if (err_size > 20) { ++ printk("AMPDU DataSize = %d\n", pRxBlk->DataSize); ++ hex_dump("802.11 Header", (UCHAR *)pRxBlk->pHeader, 24); ++ hex_dump("Payload", pRxBlk->pData, 64); ++ err_size = 0; ++ } ++#endif ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ++#if 0 // test ++ /* Rec BA Session had been torn down */ ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++#endif ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx == 0) ++ { ++ /* Rec BA Session had been torn down */ ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ } ++ else ++ { ++ // impossible !!! ++ ASSERT(0); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ASSERT(pBAEntry); ++ ++ // update last rx time ++ NdisGetSystemUpTime(&Now32); ++ ++ pBAEntry->rcvSeq = Sequence; ++ ++ ++ ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ ++ // ++ // Reset Last Indicate Sequence ++ // ++ if (pBAEntry->LastIndSeq == RESET_RCV_SEQ) ++ { ++ ASSERT((pBAEntry->list.qlen == 0) && (pBAEntry->list.next == NULL)); ++ ++ // reset rcv sequence of BA session ++ pBAEntry->LastIndSeq = Sequence; ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ ++ ++ // ++ // I. Check if in order. ++ // ++ if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) ++ { ++ USHORT LastIndSeq; ++ ++ pBAEntry->LastIndSeq = Sequence; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ LastIndSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); ++ if (LastIndSeq != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = LastIndSeq; ++ } ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++ // ++ // II. Drop Duplicated Packet ++ // ++ else if (Sequence == pBAEntry->LastIndSeq) ++ { ++ ++ // drop and release packet ++ pBAEntry->nDropPacket++; ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ // ++ // III. Drop Old Received Packet ++ // ++ else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) ++ { ++ ++ // drop and release packet ++ pBAEntry->nDropPacket++; ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ // ++ // IV. Receive Sequence within Window Size ++ // ++ else if (SEQ_SMALLER(Sequence, (((pBAEntry->LastIndSeq+pBAEntry->BAWinSize+1)) & MAXSEQ), MAXSEQ)) ++ { ++ ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); ++ } ++ // ++ // V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer ++ // ++ else ++ { ++#if 0 ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++#else ++ LONG WinStartSeq, TmpSeq; ++ ++ ++ TmpSeq = Sequence - (pBAEntry->BAWinSize) -1; ++ if (TmpSeq < 0) ++ { ++ TmpSeq = (MAXSEQ+1) + TmpSeq; ++ } ++ WinStartSeq = (TmpSeq+1) & MAXSEQ; ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq); ++ pBAEntry->LastIndSeq = WinStartSeq; //TmpSeq; ++ ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ ++ ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); ++ ++ TmpSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); ++ if (TmpSeq != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = TmpSeq; ++ } ++#endif ++ } ++} ++ ++#endif // DOT11_N_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/cmm_data_2860.c +@@ -0,0 +1,1240 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++/* ++ All functions in this file must be PCI-depended, or you should out your function ++ in other files. ++ ++*/ ++#include "../rt_config.h" ++ ++extern RTMP_RF_REGS RF2850RegTable[]; ++extern UCHAR NUM_OF_2850_CHNL; ++ ++USHORT RtmpPCI_WriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber) ++{ ++ ++ UCHAR *pDMAHeaderBufVA; ++ USHORT TxIdx, RetTxIdx; ++ PTXD_STRUC pTxD; ++ UINT32 BufBasePaLow; ++ PRTMP_TX_RING pTxRing; ++ USHORT hwHeaderLen; ++ ++ // ++ // get Tx Ring Resource ++ // ++ pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; ++ TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; ++ pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; ++ BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); ++ ++ // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer ++ if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ { ++ hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; ++ } ++ else ++ { ++ hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ } ++ NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); ++ ++ pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ ++ // ++ // build Tx Descriptor ++ // ++ ++ pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++ NdisZeroMemory(pTxD, TXD_SIZE); ++ ++ pTxD->SDPtr0 = BufBasePaLow; ++ pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding ++ pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; ++ pTxD->SDLen1 = pTxBlk->SrcBufLen; ++ pTxD->LastSec0 = 0; ++ pTxD->LastSec1 = (bIsLast) ? 1 : 0; ++ ++ RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); ++ ++ RetTxIdx = TxIdx; ++ // ++ // Update Tx index ++ // ++ INC_RING_INDEX(TxIdx, TX_RING_SIZE); ++ pTxRing->TxCpuIdx = TxIdx; ++ ++ *FreeNumber -= 1; ++ ++ return RetTxIdx; ++} ++ ++ ++USHORT RtmpPCI_WriteSingleTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber) ++{ ++ ++ UCHAR *pDMAHeaderBufVA; ++ USHORT TxIdx, RetTxIdx; ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ UINT32 BufBasePaLow; ++ PRTMP_TX_RING pTxRing; ++ USHORT hwHeaderLen; ++ ++ // ++ // get Tx Ring Resource ++ // ++ pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; ++ TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; ++ pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; ++ BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); ++ ++ // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer ++ hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen); ++ ++ pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ ++ // ++ // build Tx Descriptor ++ // ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++#endif ++ NdisZeroMemory(pTxD, TXD_SIZE); ++ ++ pTxD->SDPtr0 = BufBasePaLow; ++ pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding ++ pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; ++ pTxD->SDLen1 = pTxBlk->SrcBufLen; ++ pTxD->LastSec0 = 0; ++ pTxD->LastSec1 = (bIsLast) ? 1 : 0; ++ ++ RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif // RT_BIG_ENDIAN // ++ ++ RetTxIdx = TxIdx; ++ // ++ // Update Tx index ++ // ++ INC_RING_INDEX(TxIdx, TX_RING_SIZE); ++ pTxRing->TxCpuIdx = TxIdx; ++ ++ *FreeNumber -= 1; ++ ++ return RetTxIdx; ++} ++ ++ ++USHORT RtmpPCI_WriteMultiTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR frameNum, ++ OUT USHORT *FreeNumber) ++{ ++ BOOLEAN bIsLast; ++ UCHAR *pDMAHeaderBufVA; ++ USHORT TxIdx, RetTxIdx; ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ UINT32 BufBasePaLow; ++ PRTMP_TX_RING pTxRing; ++ USHORT hwHdrLen; ++ UINT32 firstDMALen; ++ ++ bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0); ++ ++ // ++ // get Tx Ring Resource ++ // ++ pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; ++ TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; ++ pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; ++ BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); ++ ++ if (frameNum == 0) ++ { ++ // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer ++ if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; ++ hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; ++ else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; ++ hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD; ++ else ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; ++ } ++ else ++ { ++ firstDMALen = pTxBlk->MpduHeaderLen; ++ } ++ ++ NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); ++ ++ pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ ++ // ++ // build Tx Descriptor ++ // ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++#endif ++ NdisZeroMemory(pTxD, TXD_SIZE); ++ ++ pTxD->SDPtr0 = BufBasePaLow; ++ pTxD->SDLen0 = firstDMALen; // include padding ++ pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);; ++ pTxD->SDLen1 = pTxBlk->SrcBufLen; ++ pTxD->LastSec0 = 0; ++ pTxD->LastSec1 = (bIsLast) ? 1 : 0; ++ ++ RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); ++ ++#ifdef RT_BIG_ENDIAN ++ if (frameNum == 0) ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++ ++ if (frameNum != 0) ++ RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); ++ ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif // RT_BIG_ENDIAN // ++ ++ RetTxIdx = TxIdx; ++ // ++ // Update Tx index ++ // ++ INC_RING_INDEX(TxIdx, TX_RING_SIZE); ++ pTxRing->TxCpuIdx = TxIdx; ++ ++ *FreeNumber -= 1; ++ ++ return RetTxIdx; ++ ++} ++ ++ ++VOID RtmpPCI_FinalWriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN USHORT totalMPDUSize, ++ IN USHORT FirstTxIdx) ++{ ++ ++ PTXWI_STRUC pTxWI; ++ PRTMP_TX_RING pTxRing; ++ ++ // ++ // get Tx Ring Resource ++ // ++ pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; ++ pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa; ++ pTxWI->MPDUtotalByteCount = totalMPDUSize; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++} ++ ++ ++VOID RtmpPCIDataLastTxIdx( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN USHORT LastTxIdx) ++{ ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ PRTMP_TX_RING pTxRing; ++ ++ // ++ // get Tx Ring Resource ++ // ++ pTxRing = &pAd->TxRing[QueIdx]; ++ ++ // ++ // build Tx Descriptor ++ // ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++#endif ++ ++ pTxD->LastSec1 = 1; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif // RT_BIG_ENDIAN // ++ ++} ++ ++ ++USHORT RtmpPCI_WriteFragTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR fragNum, ++ OUT USHORT *FreeNumber) ++{ ++ UCHAR *pDMAHeaderBufVA; ++ USHORT TxIdx, RetTxIdx; ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ UINT32 BufBasePaLow; ++ PRTMP_TX_RING pTxRing; ++ USHORT hwHeaderLen; ++ UINT32 firstDMALen; ++ ++ // ++ // Get Tx Ring Resource ++ // ++ pTxRing = &pAd->TxRing[pTxBlk->QueIdx]; ++ TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx; ++ pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; ++ BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); ++ ++ // ++ // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer ++ // ++ hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; ++ NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen); ++ ++ ++ // ++ // Build Tx Descriptor ++ // ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++#endif ++ NdisZeroMemory(pTxD, TXD_SIZE); ++ ++ if (fragNum == pTxBlk->TotalFragNum) ++ { ++ pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket; ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ } ++ ++ pTxD->SDPtr0 = BufBasePaLow; ++ pTxD->SDLen0 = firstDMALen; // include padding ++ pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE); ++ pTxD->SDLen1 = pTxBlk->SrcBufLen; ++ pTxD->LastSec0 = 0; ++ pTxD->LastSec1 = 1; ++ ++ RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI); ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif // RT_BIG_ENDIAN // ++ ++ RetTxIdx = TxIdx; ++ pTxBlk->Priv += pTxBlk->SrcBufLen; ++ ++ // ++ // Update Tx index ++ // ++ INC_RING_INDEX(TxIdx, TX_RING_SIZE); ++ pTxRing->TxCpuIdx = TxIdx; ++ ++ *FreeNumber -= 1; ++ ++ return RetTxIdx; ++ ++} ++ ++/* ++ Must be run in Interrupt context ++ This function handle PCI specific TxDesc and cpu index update and kick the packet out. ++ */ ++int RtmpPCIMgmtKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pSrcBufVA, ++ IN UINT SrcBufLen) ++{ ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; ++ ++#ifdef RT_BIG_ENDIAN ++ pDestTxD = (PTXD_STRUC)pAd->MgmtRing.Cell[SwIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#else ++ pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa; ++#endif ++ ++ pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket; ++ pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL; ++ ++ RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT); ++ pTxD->LastSec0 = 1; ++ pTxD->LastSec1 = 1; ++ pTxD->DMADONE = 0; ++ pTxD->SDLen1 = 0; ++ pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);; ++ pTxD->SDLen0 = SrcBufLen; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // Increase TX_CTX_IDX, but write to register later. ++ INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); ++ ++ RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound ++ ++ Arguments: ++ pRxD Pointer to the Rx descriptor ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS No err ++ NDIS_STATUS_FAILURE Error ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxD) ++{ ++ PCIPHER_KEY pWpaKey; ++ INT dBm; ++ ++ // Phy errors & CRC errors ++ if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc)) ++ { ++ // Check RSSI for Noise Hist statistic collection. ++ dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; ++ if (dBm <= -87) ++ pAd->StaCfg.RPIDensity[0] += 1; ++ else if (dBm <= -82) ++ pAd->StaCfg.RPIDensity[1] += 1; ++ else if (dBm <= -77) ++ pAd->StaCfg.RPIDensity[2] += 1; ++ else if (dBm <= -72) ++ pAd->StaCfg.RPIDensity[3] += 1; ++ else if (dBm <= -67) ++ pAd->StaCfg.RPIDensity[4] += 1; ++ else if (dBm <= -62) ++ pAd->StaCfg.RPIDensity[5] += 1; ++ else if (dBm <= -57) ++ pAd->StaCfg.RPIDensity[6] += 1; ++ else if (dBm > -57) ++ pAd->StaCfg.RPIDensity[7] += 1; ++ ++ return(NDIS_STATUS_FAILURE); ++ } ++ ++ // Add Rx size to channel load counter, we should ignore error counts ++ pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14); ++ ++ // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics ++ if (pHeader != NULL) ++ { ++ if (pHeader->FC.ToDs) ++ { ++ return(NDIS_STATUS_FAILURE); ++ } ++ } ++ ++ // Drop not U2M frames, cant's drop here because we will drop beacon in this case ++ // I am kind of doubting the U2M bit operation ++ // if (pRxD->U2M == 0) ++ // return(NDIS_STATUS_FAILURE); ++ ++ // drop decyption fail frame ++ if (pRxD->CipherErr) ++ { ++ if (pRxD->CipherErr == 2) ++ {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV ok but MICErr "));} ++ else if (pRxD->CipherErr == 1) ++ {DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV Err "));} ++ else if (pRxD->CipherErr == 3) ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: Key not valid ")); ++ ++ if (((pRxD->CipherErr & 1) == 1) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) ++ RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n", ++ pRxD->CipherErr, ++ pRxD->SDL0, ++ pRxD->Mcast | pRxD->Bcast, ++ pRxD->MyBss, ++ pRxWI->WirelessCliID, ++ pRxWI->KeyIndex)); ++ ++ // ++ // MIC Error ++ // ++ if (pRxD->CipherErr == 2) ++ { ++ pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ WpaSendMicFailureToWpaSupplicant(pAd, ++ (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE); ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ RTMPReportMicError(pAd, pWpaKey); ++ ++ if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd)) ++ RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n")); ++ } ++ ++ if (pHeader == NULL) ++ return(NDIS_STATUS_SUCCESS); ++ ++ return(NDIS_STATUS_FAILURE); ++ } ++ ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine sends command to firmware and turn our chip to power save mode. ++ Both RadioOff and .11 power save function needs to call this routine. ++ Input: ++ Level = GUIRADIO_OFF : GUI Radio Off mode ++ Level = DOT11POWERSAVE : 802.11 power save mode ++ Level = RTMP_HALT : When Disable device. ++ ++ ========================================================================== ++ */ ++VOID RT28xxPciAsicRadioOff( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Level, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ WPDMA_GLO_CFG_STRUC DmaCfg; ++ UCHAR i, tempBBP_R3 = 0; ++ BOOLEAN brc = FALSE, Cancelled; ++ UINT32 TbTTTime = 0; ++ UINT32 PsPollTime = 0, MACValue; ++ ULONG BeaconPeriodTime; ++ UINT32 RxDmaIdx, RxCpuIdx; ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx)); ++ ++ // Check Rx DMA busy status, if more than half is occupied, give up this radio off. ++ RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx); ++ RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx); ++ if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx)); ++ return; ++ } ++ else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx)); ++ return; ++ } ++ ++ // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops. ++ pAd->bPCIclkOffDisableTx = TRUE; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ ++ if (Level == DOT11POWERSAVE) ++ { ++ RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime); ++ TbTTTime &= 0x1ffff; ++ // 00. check if need to do sleep in this DTIM period. If next beacon will arrive within 30ms , ...doesn't necessarily sleep. ++ // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms ++ if (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime)); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ pAd->bPCIclkOffDisableTx = FALSE; ++ return; ++ } ++ else ++ { ++ PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000; ++ PsPollTime -= 3; ++ ++ BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100; ++ if (TbttNumToNextWakeUp > 0) ++ PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime); ++ ++ pAd->Mlme.bPsPollTimerRunning = TRUE; ++ RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime); ++ } ++ } ++ } ++ ++ // 0. Disable Tx DMA. ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ DmaCfg.field.EnableTxDMA = 0; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ ++ // 1. Wait DMA not busy ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0)) ++ break; ++ RTMPusecDelay(20); ++ i++; ++ }while(i < 50); ++ ++ if (i >= 50) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy. return on RT28xxPciAsicRadioOff ()\n")); ++ pAd->bPCIclkOffDisableTx = FALSE; ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ DmaCfg.field.EnableTxDMA = 1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ return; ++ } ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF); ++ ++ // Set to 1R. ++ tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3); ++ ++ // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. ++ if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) ++ && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); ++ } ++ ++ // When PCI clock is off, don't want to service interrupt. ++ RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt); ++ ++ RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); ++ // Disable MAC Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue); ++ MACValue &= 0xf7; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue); ++ ++ // 2. Send Sleep command ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff); ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff); ++ AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout unit:40us. ++ // 2-1. Wait command success ++ // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task. ++ brc = AsicCheckCommanOk(pAd, PowerSafeCID); ++ ++ if (brc == FALSE) ++ { ++ // try again ++ AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout unit:40us. ++ //RTMPusecDelay(200); ++ brc = AsicCheckCommanOk(pAd, PowerSafeCID); ++ } ++ ++ // 3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe. ++ // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem. ++ if ((Level == DOT11POWERSAVE) && (brc == TRUE)) ++ { ++ AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio. ++ // 3-1. Wait command success ++ AsicCheckCommanOk(pAd, PowerRadioOffCID); ++ } ++ else if (brc == TRUE) ++ { ++ AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio. ++ // 3-1. Wait command success ++ AsicCheckCommanOk(pAd, PowerRadioOffCID); ++ } ++ ++ // Wait DMA not busy ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ if (DmaCfg.field.RxDMABusy == 0) ++ break; ++ RTMPusecDelay(20); ++ i++; ++ }while(i < 50); ++ ++ if (i >= 50) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. on RT28xxPciAsicRadioOff ()\n")); ++ } ++ // disable DMA Rx. ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ DmaCfg.field.EnableRxDMA = 0; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ } ++ ++ if (Level == DOT11POWERSAVE) ++ { ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90); ++ ++ // we have decided to SLEEP, so at least do it for a BEACON period. ++ if (TbttNumToNextWakeUp == 0) ++ TbttNumToNextWakeUp = 1; ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ // 1. Set auto wake up timer. ++ AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1; ++ AutoWakeupCfg.field.EnableAutoWakeup = 1; ++ AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ } ++ ++ // 4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value. ++ if (Level == RTMP_HALT) ++ { ++ if ((brc == TRUE) && (i < 50)) ++ RTMPPCIeLinkCtrlSetting(pAd, 1); ++ } ++ // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function ++ else ++ { ++ if ((brc == TRUE) && (i < 50)) ++ RTMPPCIeLinkCtrlSetting(pAd, 3); ++ } ++ ++ pAd->bPCIclkOffDisableTx = FALSE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ This routine sends command to firmware and turn our chip to wake up mode from power save mode. ++ Both RadioOn and .11 power save function needs to call this routine. ++ Input: ++ Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On. Need to restore PCI host value. ++ Level = other value : normal wake up function. ++ ++ ========================================================================== ++ */ ++BOOLEAN RT28xxPciAsicRadioOn( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Level) ++{ ++ WPDMA_GLO_CFG_STRUC DmaCfg; ++ BOOLEAN Cancelled, brv = TRUE; ++ UINT32 MACValue; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n")); ++ // 1. Set PCI Link Control in Configuration Space. ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP); ++ RTMPusecDelay(6000); ++ } ++ } ++ ++ pAd->bPCIclkOff = FALSE; ++ ++ // 2. Send wake up command. ++ AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00); ++ ++ // 2-1. wait command ok. ++ brv = AsicCheckCommanOk(pAd, PowerWakeCID); ++ if (brv) ++ { ++ //RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT)); ++ NICEnableInterrupt(pAd); ++ ++ // 3. Enable Tx DMA. ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ DmaCfg.field.EnableTxDMA = 1; ++ DmaCfg.field.EnableRxDMA = 1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ ++ // Eable MAC Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue); ++ MACValue |= 0x8; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF); ++ if (Level == GUI_IDLE_POWER_SAVE) ++ { ++ // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. ++ if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) ++ && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ } ++ } ++ return TRUE; ++ } ++ else ++ return FALSE; ++} ++ ++VOID RT28xxPciStaAsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx) ++{ ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ return; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n")); ++ return; ++ } ++ ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ // Support PCIe Advance Power Save ++ if (bFromTx == TRUE) ++ { ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP); ++ RTMPusecDelay(3000); ++ DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n")); ++ } ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE)) ++ { ++ // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. ++ if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) ++ && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ } ++ } ++ } ++ else ++ { ++ // PCI, 2860-PCIe ++ AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00); ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ } ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); ++ DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n")); ++} ++ ++VOID RT28xxPciStaAsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ return; ++ } ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ ULONG Now = 0; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ return; ++ } ++ ++ NdisGetSystemUpTime(&Now); ++ // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM. ++ // Because Some AP can't queuing outgoing frames immediately. ++ if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL)); ++ return; ++ } ++ else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL)); ++ return; ++ } ++ ++ RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp); ++ } ++ else ++ { ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ // we have decided to SLEEP, so at least do it for a BEACON period. ++ if (TbttNumToNextWakeUp == 0) ++ TbttNumToNextWakeUp = 1; ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1; ++ AutoWakeupCfg.field.EnableAutoWakeup = 1; ++ AutoWakeupCfg.field.AutoLeadTime = 5; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us. ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __FUNCTION__, TbttNumToNextWakeUp)); ++ } ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); ++} ++ ++VOID PsPollWakeExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ unsigned long flags; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n")); ++ RTMP_INT_LOCK(&pAd->irq_lock, flags); ++ if (pAd->Mlme.bPsPollTimerRunning) ++ { ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP); ++ } ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMP_INT_UNLOCK(&pAd->irq_lock, flags); ++} ++ ++VOID RadioOnExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ WPDMA_GLO_CFG_STRUC DmaCfg; ++ BOOLEAN Cancelled; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n")); ++ RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10); ++ return; ++ } ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n")); ++ RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10); ++ return; ++ } ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ pAd->bPCIclkOff = FALSE; ++ RTMPRingCleanUp(pAd, QID_AC_BK); ++ RTMPRingCleanUp(pAd, QID_AC_BE); ++ RTMPRingCleanUp(pAd, QID_AC_VI); ++ RTMPRingCleanUp(pAd, QID_AC_VO); ++ RTMPRingCleanUp(pAd, QID_HCCA); ++ RTMPRingCleanUp(pAd, QID_MGMT); ++ RTMPRingCleanUp(pAd, QID_RX); ++ ++ // 2. Send wake up command. ++ AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02); ++ // 2-1. wait command ok. ++ AsicCheckCommanOk(pAd, PowerWakeCID); ++ ++ // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt. ++ NICEnableInterrupt(pAd); ++ ++ // 3. Enable Tx DMA. ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); ++ DmaCfg.field.EnableTxDMA = 1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ ++ // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. ++ if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) ++ && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ } ++ ++ // Clear Radio off flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_ON); ++ ++ if (pAd->StaCfg.Psm == PWR_ACTIVE) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); ++ } ++ } ++ else ++ { ++ RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0); ++ } ++} ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RT28xxPciMlmeRadioOn( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__)); ++ ++ if ((pAd->OpMode == OPMODE_AP) || ++ ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))) ++ { ++ NICResetFromError(pAd); ++ ++ RTMPRingCleanUp(pAd, QID_AC_BK); ++ RTMPRingCleanUp(pAd, QID_AC_BE); ++ RTMPRingCleanUp(pAd, QID_AC_VI); ++ RTMPRingCleanUp(pAd, QID_AC_VO); ++ RTMPRingCleanUp(pAd, QID_HCCA); ++ RTMPRingCleanUp(pAd, QID_MGMT); ++ RTMPRingCleanUp(pAd, QID_RX); ++ ++ // Enable Tx/Rx ++ RTMPEnableRxTx(pAd); ++ ++ // Clear Radio off flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_ON); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ++ (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))) ++ { ++ BOOLEAN Cancelled; ++ ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP); ++ ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); ++ RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10); ++ } ++#endif // CONFIG_STA_SUPPORT // ++} ++ ++VOID RT28xxPciMlmeRadioOFF( ++ IN PRTMP_ADAPTER pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ UINT32 i; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__)); ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_OFF); ++ // Set Radio off flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ BOOLEAN Cancelled; ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ BOOLEAN Cancelled; ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); ++ } ++ ++ // Link down first if any association exists ++ if (INFRA_ON(pAd) || ADHOC_ON(pAd)) ++ LinkDown(pAd, FALSE); ++ RTMPusecDelay(10000); ++ //========================================== ++ // Clean up old bss table ++ BssTableInit(&pAd->ScanTab); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Disable Tx/Rx DMA ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA ++ GloCfg.field.EnableTxDMA = 0; ++ GloCfg.field.EnableRxDMA = 0; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings ++ ++ ++ // MAC_SYS_CTRL => value = 0x0 => 40mA ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0); ++ ++ // PWR_PIN_CFG => value = 0x0 => 40mA ++ RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0); ++ ++ // TX_PIN_CFG => value = 0x0 => 20mA ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0); ++ ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ // Must using 40MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); ++ } ++ ++ // Waiting for DMA idle ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ }while (i++ < 100); ++} +--- /dev/null ++++ b/drivers/staging/rt2860/common/cmm_data.c +@@ -0,0 +1,3469 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#include "../rt_config.h" ++ ++#define MAX_TX_IN_TBTT (16) ++ ++ ++UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; ++// Add Cisco Aironet SNAP heade for CCX2 support ++UCHAR SNAP_AIRONET[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00}; ++UCHAR CKIP_LLC_SNAP[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; ++UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e}; ++UCHAR EAPOL[] = {0x88, 0x8e}; ++UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */ ++ ++UCHAR IPX[] = {0x81, 0x37}; ++UCHAR APPLE_TALK[] = {0x80, 0xf3}; ++UCHAR RateIdToPlcpSignal[12] = { ++ 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec ++ 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14 ++ 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14 ++ ++UCHAR OfdmSignalToRateId[16] = { ++ RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively ++ RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively ++ RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively ++ RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively ++}; ++ ++UCHAR OfdmRateToRxwiMCS[12] = { ++ 0, 0, 0, 0, ++ 0, 1, 2, 3, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 ++ 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 ++}; ++UCHAR RxwiMCSToOfdmRate[12] = { ++ RATE_6, RATE_9, RATE_12, RATE_18, ++ RATE_24, RATE_36, RATE_48, RATE_54, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 ++ 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 ++}; ++ ++char* MCSToMbps[] = {"1Mbps","2Mbps","5.5Mbps","11Mbps","06Mbps","09Mbps","12Mbps","18Mbps","24Mbps","36Mbps","48Mbps","54Mbps","MM-0","MM-1","MM-2","MM-3","MM-4","MM-5","MM-6","MM-7","MM-8","MM-9","MM-10","MM-11","MM-12","MM-13","MM-14","MM-15","MM-32","ee1","ee2","ee3"}; ++ ++UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2}; ++UCHAR default_sta_aifsn[]={3,7,2,2}; ++ ++UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO}; ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ API for MLME to transmit management frame to AP (BSS Mode) ++ or station (IBSS Mode) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the outgoing 802.11 frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MiniportMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length) ++{ ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ULONG FreeNum; ++#ifdef RT2860 ++ unsigned long IrqFlags = 0; ++#endif // RT2860 // ++ UCHAR IrqState; ++ UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; ++ ++ ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); ++ ++ QueIdx=3; ++ ++ // 2860C use Tx Ring ++ ++ IrqState = pAd->irq_disabled; ++#ifdef RT2860 ++ if ((pAd->MACVersion == 0x28600100) && (!IrqState)) ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++#endif // RT2860 // ++ ++ do ++ { ++ // Reset is in progress, stop immediately ++ if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| ++ !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ break; ++ } ++ ++ // Check Free priority queue ++ // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. ++ ++ // 2860C use Tx Ring ++ if (pAd->MACVersion == 0x28600100) ++ { ++ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); ++ } ++ else ++ { ++ FreeNum = GET_MGMTRING_FREENO(pAd); ++ } ++ ++ if ((FreeNum > 0)) ++ { ++ // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 ++ NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); ++ break; ++ } ++ ++ //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ //pAd->CommonCfg.MlmeRate = RATE_2; ++ ++ ++ Status = MlmeHardTransmit(pAd, QueIdx, pPacket); ++ if (Status != NDIS_STATUS_SUCCESS) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ } ++ else ++ { ++ pAd->RalinkCounters.MgmtRingFullCount++; ++ DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", ++ QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); ++ } ++ ++ } while (FALSE); ++ ++#ifdef RT2860 ++ // 2860C use Tx Ring ++ if ((pAd->MACVersion == 0x28600100) && (!IrqState)) ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++#endif // RT2860 // ++ ++ return Status; ++} ++ ++ ++#ifdef RT2860 ++NDIS_STATUS MiniportMMRequestUnlock( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length) ++{ ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ULONG FreeNum; ++ TXWI_STRUC TXWI; ++ ULONG SW_TX_IDX; ++ PTXD_STRUC pTxD; ++ ++ QueIdx = 3; ++ ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); ++ ++ do ++ { ++ // Reset is in progress, stop immediately ++ if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| ++ !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ break; ++ } ++ ++ // Check Free priority queue ++ // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. ++ // 2860C use Tx Ring ++ if (pAd->MACVersion == 0x28600100) ++ { ++ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); ++ SW_TX_IDX = pAd->TxRing[QueIdx].TxCpuIdx; ++ pTxD = (PTXD_STRUC) pAd->TxRing[QueIdx].Cell[SW_TX_IDX].AllocVa; ++ } ++ else ++ { ++ FreeNum = GET_MGMTRING_FREENO(pAd); ++ SW_TX_IDX = pAd->MgmtRing.TxCpuIdx; ++ pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SW_TX_IDX].AllocVa; ++ } ++ if ((FreeNum > 0)) ++ { ++ NdisZeroMemory(&TXWI, TXWI_SIZE); ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&TXWI, TXWI_SIZE, pData, Length); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); ++ break; ++ } ++ ++ Status = MlmeHardTransmit(pAd, QueIdx, pPacket); ++ if (Status != NDIS_STATUS_SUCCESS) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ } ++ else ++ { ++ pAd->RalinkCounters.MgmtRingFullCount++; ++ DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing\n", QueIdx)); ++ } ++ ++ } while (FALSE); ++ ++ ++ return Status; ++} ++#endif // RT2860 // ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware transmit function ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuffer Pointer to memory of outgoing frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef RT2860 ++ if ( pAd->MACVersion == 0x28600100 ) ++ return MlmeHardTransmitTxRing(pAd,QueIdx,pPacket); ++ else ++#endif // RT2860 // ++ return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); ++ ++} ++ ++ ++#ifdef RT2860 ++NDIS_STATUS MlmeHardTransmitTxRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ PHEADER_802_11 pHeader_802_11; ++ BOOLEAN bAckRequired, bInsertTimestamp; ++ ULONG SrcBufPA; ++ UCHAR MlmeRate; ++ ULONG SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; ++ PTXWI_STRUC pFirstTxWI; ++ ULONG FreeNum; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++ ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ if (pSrcBufVA == NULL) ++ { ++ // The buffer shouldn't be NULL ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // Make sure MGMT ring resource won't be used by other threads ++ //NdisAcquireSpinLock(&pAd->TxRingLock); ++ ++ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ if (FreeNum == 0) ++ { ++ //NdisReleaseSpinLock(&pAd->TxRingLock); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ SwIdx = pAd->TxRing[QueIdx].TxCpuIdx; ++ ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ ++ if (pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket) ++ { ++ printk("MlmeHardTransmit Error\n"); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // outgoing frame always wakeup PHY to prevent frame lost ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ pFirstTxWI =(PTXWI_STRUC)pSrcBufVA; ++ ++ pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXWI_SIZE); ++ if (pHeader_802_11->Addr1[0] & 0x01) ++ { ++ MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ } ++ else ++ { ++ MlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ if ((pHeader_802_11->FC.Type == BTYPE_DATA) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) ++ { ++ pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); ++ } ++ ++ // Verify Mlme rate for a / g bands. ++ if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band ++ MlmeRate = RATE_6; ++ ++ // ++ // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) ++ // Snice it's been set to 0 while on MgtMacHeaderInit ++ // By the way this will cause frame to be send on PWR_SAVE failed. ++ // ++ // ++ // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame ++#ifdef CONFIG_STA_SUPPORT ++ // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD ++ if (pHeader_802_11->FC.Type != BTYPE_DATA) ++ { ++ if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ) || !(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; ++ } ++ else ++ { ++ pHeader_802_11->FC.PwrMgmt = pAd->CommonCfg.bAPSDForcePowerSave; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ bInsertTimestamp = FALSE; ++ if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL ++ { ++ bAckRequired = FALSE; ++ } ++ else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) ++ { ++ if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST ++ { ++ bAckRequired = FALSE; ++ pHeader_802_11->Duration = 0; ++ } ++ else ++ { ++ bAckRequired = TRUE; ++ pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); ++ if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) ++ { ++ bInsertTimestamp = TRUE; ++ } ++ } ++ } ++ pHeader_802_11->Sequence = pAd->Sequence++; ++ if (pAd->Sequence > 0xfff) ++ pAd->Sequence = 0; ++ // Before radar detection done, mgmt frame can not be sent but probe req ++ // Because we need to use probe req to trigger driver to send probe req in passive scan ++ if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); ++#endif ++ // ++ // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET ++ // should always has only one ohysical buffer, and the whole frame size equals ++ // to the first scatter buffer size ++ // ++ ++ // Initialize TX Descriptor ++ // For inter-frame gap, the number is for this frame and next frame ++ // For MLME rate, we will fix as 2Mb to match other vendor's implement ++ ++// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. ++ // Only beacon use Nseq=TRUE. So here we use Nseq=FALSE. ++ if (pMacEntry == NULL) ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, RESERVED_WCID, (SrcBufLen - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, ++ bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, pMacEntry->Aid, (SrcBufLen - TXWI_SIZE), ++ pMacEntry->MaxHTPhyMode.field.MCS, 0, ++ (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, ++ IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); ++ } ++ ++ pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket = pPacket; ++ pAd->TxRing[QueIdx].Cell[SwIdx].pNextNdisPacket = NULL; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); ++#endif ++ SrcBufPA = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE); ++ ++ ++ RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_EDCA); ++ pTxD->LastSec0 = 1; ++ pTxD->LastSec1 = 1; ++ pTxD->SDLen0 = SrcBufLen; ++ pTxD->SDLen1 = 0; ++ pTxD->SDPtr0 = SrcBufPA; ++ pTxD->DMADONE = 0; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // Increase TX_CTX_IDX, but write to register later. ++ INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); ++ ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx*0x10, pAd->TxRing[QueIdx].TxCpuIdx); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++#endif // RT2860 // ++ ++ ++NDIS_STATUS MlmeHardTransmitMgmtRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PHEADER_802_11 pHeader_802_11; ++ BOOLEAN bAckRequired, bInsertTimestamp; ++ UCHAR MlmeRate; ++ PTXWI_STRUC pFirstTxWI; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ RTMP_SEM_LOCK(&pAd->MgmtRingLock); ++ ++ ++ if (pSrcBufVA == NULL) ++ { ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // outgoing frame always wakeup PHY to prevent frame lost ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE); ++ pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE); ++ ++ if (pHeader_802_11->Addr1[0] & 0x01) ++ { ++ MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ } ++ else ++ { ++ MlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ // Verify Mlme rate for a / g bands. ++ if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band ++ MlmeRate = RATE_6; ++ ++ if ((pHeader_802_11->FC.Type == BTYPE_DATA) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) ++ { ++ pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. ++ if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED ++#ifdef DOT11_N_SUPPORT ++ || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ if (pAd->LatchRfRegs.Channel > 14) ++ pAd->CommonCfg.MlmeTransmit.field.MODE = 1; ++ else ++ pAd->CommonCfg.MlmeTransmit.field.MODE = 0; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) ++ // Snice it's been set to 0 while on MgtMacHeaderInit ++ // By the way this will cause frame to be send on PWR_SAVE failed. ++ // ++ // pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE); ++ // ++ // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame ++#ifdef CONFIG_STA_SUPPORT ++ // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD ++ if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) ++ { ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ bInsertTimestamp = FALSE; ++ if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL ++ { ++#ifdef CONFIG_STA_SUPPORT ++ //Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue. ++ if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ bAckRequired = FALSE; ++ } ++ else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) ++ { ++ if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST ++ { ++ bAckRequired = FALSE; ++ pHeader_802_11->Duration = 0; ++ } ++ else ++ { ++ bAckRequired = TRUE; ++ pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); ++ if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) ++ { ++ bInsertTimestamp = TRUE; ++ } ++ } ++ } ++ ++ pHeader_802_11->Sequence = pAd->Sequence++; ++ if (pAd->Sequence >0xfff) ++ pAd->Sequence = 0; ++ ++ // Before radar detection done, mgmt frame can not be sent but probe req ++ // Because we need to use probe req to trigger driver to send probe req in passive scan ++ if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); ++#endif ++ ++ // ++ // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET ++ // should always has only one ohysical buffer, and the whole frame size equals ++ // to the first scatter buffer size ++ // ++ ++ // Initialize TX Descriptor ++ // For inter-frame gap, the number is for this frame and next frame ++ // For MLME rate, we will fix as 2Mb to match other vendor's implement ++ ++// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. ++ if (pMacEntry == NULL) ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, RESERVED_WCID, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, ++ bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, pMacEntry->Aid, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), ++ pMacEntry->MaxHTPhyMode.field.MCS, 0, ++ (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, ++ IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); ++#endif ++ ++ // Now do hardware-depened kick out. ++ HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); ++ ++ // Make sure to release MGMT ring resource ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++/******************************************************************************** ++ ++ New DeQueue Procedures. ++ ++ ********************************************************************************/ ++ ++#define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \ ++ do{ \ ++ if (bIntContext == FALSE) \ ++ RTMP_IRQ_LOCK((lock), IrqFlags); \ ++ }while(0) ++ ++#define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \ ++ do{ \ ++ if (bIntContext == FALSE) \ ++ RTMP_IRQ_UNLOCK((lock), IrqFlags); \ ++ }while(0) ++ ++/* ++ ======================================================================== ++ Tx Path design algorithm: ++ Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal), ++ Specific Packet Type. Following show the classification rule and policy for each kinds of packets. ++ Classification Rule=> ++ Multicast: (*addr1 & 0x01) == 0x01 ++ Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc. ++ 11N Rate : If peer support HT ++ (1).AMPDU -- If TXBA is negotiated. ++ (2).AMSDU -- If AMSDU is capable for both peer and ourself. ++ *). AMSDU can embedded in a AMPDU, but now we didn't support it. ++ (3).Normal -- Other packets which send as 11n rate. ++ ++ B/G Rate : If peer is b/g only. ++ (1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6 ++ (2).Normal -- Other packets which send as b/g rate. ++ Fragment: ++ The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment. ++ ++ Classified Packet Handle Rule=> ++ Multicast: ++ No ACK, //pTxBlk->bAckRequired = FALSE; ++ No WMM, //pTxBlk->bWMM = FALSE; ++ No piggyback, //pTxBlk->bPiggyBack = FALSE; ++ Force LowRate, //pTxBlk->bForceLowRate = TRUE; ++ Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use ++ the same policy to handle it. ++ Force LowRate, //pTxBlk->bForceLowRate = TRUE; ++ ++ 11N Rate : ++ No piggyback, //pTxBlk->bPiggyBack = FALSE; ++ ++ (1).AMSDU ++ pTxBlk->bWMM = TRUE; ++ (2).AMPDU ++ pTxBlk->bWMM = TRUE; ++ (3).Normal ++ ++ B/G Rate : ++ (1).ARALINK ++ ++ (2).Normal ++ ======================================================================== ++*/ ++static UCHAR TxPktClassification( ++ IN RTMP_ADAPTER *pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ UCHAR TxFrameType = TX_UNKOWN_FRAME; ++ UCHAR Wcid; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bHTRate = FALSE; ++#endif // DOT11_N_SUPPORT // ++ ++ Wcid = RTMP_GET_PACKET_WCID(pPacket); ++ if (Wcid == MCAST_WCID) ++ { // Handle for RA is Broadcast/Multicast Address. ++ return TX_MCAST_FRAME; ++ } ++ ++ // Handle for unicast packets ++ pMacEntry = &pAd->MacTab.Content[Wcid]; ++ if (RTMP_GET_PACKET_LOWRATE(pPacket)) ++ { // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++#ifdef DOT11_N_SUPPORT ++ else if (IS_HT_RATE(pMacEntry)) ++ { // it's a 11n capable packet ++ ++ // Depends on HTPhyMode to check if the peer support the HTRate transmission. ++ // Currently didn't support A-MSDU embedded in A-MPDU ++ bHTRate = TRUE; ++ if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE)) ++ TxFrameType = TX_LEGACY_FRAME; ++#ifdef UAPSD_AP_SUPPORT ++ else if (RTMP_GET_PACKET_EOSP(pPacket)) ++ TxFrameType = TX_LEGACY_FRAME; ++#endif // UAPSD_AP_SUPPORT // ++ else if((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0) ++ return TX_AMPDU_FRAME; ++ else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED)) ++ return TX_AMSDU_FRAME; ++ else ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++#endif // DOT11_N_SUPPORT // ++ else ++ { // it's a legacy b/g packet. ++ if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && ++ (RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) && ++ (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) ++ { // if peer support Ralink Aggregation, we use it. ++ TxFrameType = TX_RALINK_FRAME; ++ } ++ else ++ { ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++ } ++ ++ // Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU. ++ if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME)) ++ TxFrameType = TX_FRAG_FRAME; ++ ++ return TxFrameType; ++} ++ ++ ++BOOLEAN RTMP_FillTxBlkInfo( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PACKET_INFO PacketInfo; ++ PNDIS_PACKET pPacket; ++ PMAC_TABLE_ENTRY pMacEntry = NULL; ++ ++ pPacket = pTxBlk->pPacket; ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); ++ ++ pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); ++ pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket); ++ pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); ++ pTxBlk->FrameGap = IFS_HTTXOP; // ASIC determine Frame Gap ++ ++ if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); ++ else ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); ++ ++ // Default to clear this flag ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS); ++ ++ ++ if (pTxBlk->Wcid == MCAST_WCID) ++ { ++ pTxBlk->pMacEntry = NULL; ++ { ++#ifdef MCAST_RATE_SPECIFIC ++ PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); ++ if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff)) ++ pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode; ++ else ++#endif // MCAST_RATE_SPECIFIC // ++ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; ++ } ++ ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); // AckRequired = FALSE, when broadcast packet in Adhoc mode. ++ //TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate); ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag); ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); ++ if (RTMP_GET_PACKET_MOREDATA(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); ++ } ++ ++ } ++ else ++ { ++ pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; ++ pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; ++ ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ ++ // For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK. ++ if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); ++ else ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); ++ ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ // If support WMM, enable it. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) ++ { ++ if ( (RTMP_GET_PACKET_LOWRATE(pPacket)) || ++ ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1))) ++ { // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. ++ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; ++#ifdef DOT11_N_SUPPORT ++ // Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it??? ++ if (IS_HT_STA(pTxBlk->pMacEntry) && ++ (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && ++ ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))) ++ { ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ( (IS_HT_RATE(pMacEntry) == FALSE) && ++ (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) ++ { // Currently piggy-back only support when peer is operate in b/g mode. ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (RTMP_GET_PACKET_MOREDATA(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); ++ } ++#ifdef UAPSD_AP_SUPPORT ++ if (RTMP_GET_PACKET_EOSP(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP); ++ } ++#endif // UAPSD_AP_SUPPORT // ++ } ++ else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); ++ } ++ ++ pMacEntry->DebugTxCount++; ++ } ++ ++ return TRUE; ++ ++FillTxBlkErr: ++ return FALSE; ++} ++ ++ ++BOOLEAN CanDoAggregateTransmit( ++ IN RTMP_ADAPTER *pAd, ++ IN NDIS_PACKET *pPacket, ++ IN TX_BLK *pTxBlk) ++{ ++ ++ //printk("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType); ++ ++ if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID) ++ return FALSE; ++ ++ if (RTMP_GET_PACKET_DHCP(pPacket) || ++ RTMP_GET_PACKET_EAPOL(pPacket) || ++ RTMP_GET_PACKET_WAI(pPacket)) ++ return FALSE; ++ ++ if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) && ++ ((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100))) ++ { // For AMSDU, allow the packets with total length < max-amsdu size ++ return FALSE; ++ } ++ ++ if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) && ++ (pTxBlk->TxPacketList.Number == 2)) ++ { // For RALINK-Aggregation, allow two frames in one batch. ++ return FALSE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP ++ return TRUE; ++ else ++#endif // CONFIG_STA_SUPPORT // ++ return FALSE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ To do the enqueue operation and extract the first item of waiting ++ list. If a number of available shared memory segments could meet ++ the request of extracted item, the extracted item will be fragmented ++ into shared memory segments. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pQueue Pointer to Waiting Queue ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPDeQueuePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bIntContext, ++ IN UCHAR QIdx, /* BulkOutPipeId */ ++ IN UCHAR Max_Tx_Packets) ++{ ++ PQUEUE_ENTRY pEntry = NULL; ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ UCHAR Count=0; ++ PQUEUE_HEADER pQueue; ++ ULONG FreeNumber[NUM_OF_TX_RING]; ++ UCHAR QueIdx, sQIdx, eQIdx; ++ unsigned long IrqFlags = 0; ++ BOOLEAN hasTxDesc = FALSE; ++ TX_BLK TxBlk; ++ TX_BLK *pTxBlk; ++ ++#ifdef DBG_DIAGNOSE ++ BOOLEAN firstRound; ++ RtmpDiagStruct *pDiagStruct = &pAd->DiagStruct; ++#endif ++ ++ ++ if (QIdx == NUM_OF_TX_RING) ++ { ++ sQIdx = 0; ++ eQIdx = 3; // 4 ACs, start from 0. ++ } ++ else ++ { ++ sQIdx = eQIdx = QIdx; ++ } ++ ++ for (QueIdx=sQIdx; QueIdx <= eQIdx; QueIdx++) ++ { ++ Count=0; ++ ++ RT28XX_START_DEQUEUE(pAd, QueIdx, IrqFlags); ++ ++#ifdef DBG_DIAGNOSE ++ firstRound = ((QueIdx == 0) ? TRUE : FALSE); ++#endif // DBG_DIAGNOSE // ++ ++ while (1) ++ { ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); ++ return; ++ } ++ ++ if (Count >= Max_Tx_Packets) ++ break; ++ ++ DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ if (&pAd->TxSwQueue[QueIdx] == NULL) ++ { ++#ifdef DBG_DIAGNOSE ++ if (firstRound == TRUE) ++ pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][0]++; ++#endif // DBG_DIAGNOSE // ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++#ifdef RT2860 ++ FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); ++ ++#ifdef DBG_DIAGNOSE ++ if (firstRound == TRUE) ++ { ++ UCHAR txDescNumLevel, txSwQNumLevel; ++ ++ txDescNumLevel = (TX_RING_SIZE - FreeNumber[QueIdx]); // Number of occupied hw desc. ++ txDescNumLevel = ((txDescNumLevel <=15) ? txDescNumLevel : 15); ++ pDiagStruct->TxDescCnt[pDiagStruct->ArrayCurIdx][txDescNumLevel]++; ++ ++ txSwQNumLevel = ((pAd->TxSwQueue[QueIdx].Number <=7) ? pAd->TxSwQueue[QueIdx].Number : 8); ++ pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][txSwQNumLevel]++; ++ ++ firstRound = FALSE; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ if (FreeNumber[QueIdx] <= 5) ++ { ++ // free Tx(QueIdx) resources ++ RTMPFreeTXDUponTxDmaDone(pAd, QueIdx); ++ FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); ++ } ++#endif // RT2860 // ++ ++ // probe the Queue Head ++ pQueue = &pAd->TxSwQueue[QueIdx]; ++ if ((pEntry = pQueue->Head) == NULL) ++ { ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ pTxBlk = &TxBlk; ++ NdisZeroMemory((PUCHAR)pTxBlk, sizeof(TX_BLK)); ++ pTxBlk->QueIdx = QueIdx; ++ ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ ++ // Early check to make sure we have enoguh Tx Resource. ++ hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); ++ if (!hasTxDesc) ++ { ++ pAd->PrivateInfo.TxRingFullCnt++; ++ ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ ++ break; ++ } ++ ++ pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket); ++ pEntry = RemoveHeadQueue(pQueue); ++ pTxBlk->TotalFrameNum++; ++ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary ++ pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); ++ pTxBlk->pPacket = pPacket; ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ ++ if (pTxBlk->TxFrameType == TX_RALINK_FRAME || pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ { ++ // Enhance SW Aggregation Mechanism ++ if (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, FreeNumber[QueIdx], pTxBlk->TxFrameType)) ++ { ++ InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ do{ ++ if((pEntry = pQueue->Head) == NULL) ++ break; ++ ++ // For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); ++ hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); ++ if ((hasTxDesc == FALSE) || (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE)) ++ break; ++ ++ //Remove the packet from the TxSwQueue and insert into pTxBlk ++ pEntry = RemoveHeadQueue(pQueue); ++ ASSERT(pEntry); ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ pTxBlk->TotalFrameNum++; ++ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary ++ pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ }while(1); ++ ++ if (pTxBlk->TxPacketList.Number == 1) ++ pTxBlk->TxFrameType = TX_LEGACY_FRAME; ++ } ++ ++ ++ Count += pTxBlk->TxPacketList.Number; ++ ++ // Do HardTransmit now. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ Status = STAHardTransmit(pAd, pTxBlk, QueIdx); ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RT2860 ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ // static rate also need NICUpdateFifoStaCounters() function. ++ //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) ++ NICUpdateFifoStaCounters(pAd); ++#endif // RT2860 // ++ } ++ ++ RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); ++ ++ ++#ifdef BLOCK_NET_IF ++ if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) ++ && (pAd->TxSwQueue[QueIdx].Number < 1)) ++ { ++ releaseNetIf(&pAd->blockQueueTab[QueIdx]); ++ } ++#endif // BLOCK_NET_IF // ++ ++ } ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Rate Transmit rate ++ Size Frame size in units of byte ++ ++ Return Value: ++ Duration number in units of usec ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++USHORT RTMPCalcDuration( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Rate, ++ IN ULONG Size) ++{ ++ ULONG Duration = 0; ++ ++ if (Rate < RATE_FIRST_OFDM_RATE) // CCK ++ { ++ if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED)) ++ Duration = 96; // 72+24 preamble+plcp ++ else ++ Duration = 192; // 144+48 preamble+plcp ++ ++ Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); ++ if ((Size << 4) % RateIdTo500Kbps[Rate]) ++ Duration ++; ++ } ++ else if (Rate <= RATE_LAST_OFDM_RATE)// OFDM rates ++ { ++ Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension ++ Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); ++ if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) ++ Duration += 4; ++ } ++ else //mimo rate ++ { ++ Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension ++ } ++ ++ return (USHORT)Duration; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pTxWI Pointer to head of each MPDU to HW. ++ Ack Setting for Ack requirement bit ++ Fragment Setting for Fragment bit ++ RetryMode Setting for retry mode ++ Ifs Setting for IFS gap ++ Rate Setting for transmit rate ++ Service Setting for service ++ Length Frame length ++ TxPreamble Short or Long preamble when using CCK rates ++ QueIdx - 0-3, according to 802.11e/d4.4 June/2003 ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ See also : BASmartHardTransmit() !!! ++ ++ ======================================================================== ++*/ ++VOID RTMPWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pOutTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit) ++{ ++ PMAC_TABLE_ENTRY pMac = NULL; ++ TXWI_STRUC TxWI; ++ PTXWI_STRUC pTxWI; ++ ++ if (WCID < MAX_LEN_OF_MAC_TABLE) ++ pMac = &pAd->MacTab.Content[WCID]; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(&TxWI, TXWI_SIZE); ++ pTxWI = &TxWI; ++ ++ pTxWI->FRAG= FRAG; ++ ++ pTxWI->CFACK = CFACK; ++ pTxWI->TS= InsTimestamp; ++ pTxWI->AMPDU = AMPDU; ++ pTxWI->ACK = Ack; ++ pTxWI->txop= Txopmode; ++ ++ pTxWI->NSEQ = NSeq; ++ // John tune the performace with Intel Client in 20 MHz performance ++#ifdef DOT11_N_SUPPORT ++ BASize = pAd->CommonCfg.TxBASize; ++ ++ if( BASize >7 ) ++ BASize =7; ++ pTxWI->BAWinSize = BASize; ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->WirelessCliID = WCID; ++ pTxWI->MPDUtotalByteCount = Length; ++ pTxWI->PacketId = PID; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ pTxWI->CFACK = CfAck; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pMac) ++ { ++ if (pAd->CommonCfg.bMIMOPSEnable) ++ { ++ if ((pMac->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMac->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ } ++ //pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0; ++ if (pMac->bIAmBadAtheros && (pMac->WepStatus != Ndis802_11WEPDisabled)) ++ { ++ pTxWI->MpduDensity = 7; ++ } ++ else ++ { ++ pTxWI->MpduDensity = pMac->MpduDensity; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->PacketId = pTxWI->MCS; ++ NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); ++} ++ ++ ++VOID RTMPWriteTxWI_Data( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk) ++{ ++ HTTRANSMIT_SETTING *pTransmit; ++ PMAC_TABLE_ENTRY pMacEntry; ++#ifdef DOT11_N_SUPPORT ++ UCHAR BASize; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ ASSERT(pTxWI); ++ ++ pTransmit = pTxBlk->pTransmit; ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(pTxWI, TXWI_SIZE); ++ ++ pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag); ++ pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); ++ pTxWI->txop = pTxBlk->FrameGap; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (pMacEntry && ++ (pAd->StaCfg.BssType == BSS_INFRA) && ++ (pMacEntry->ValidAsDls == TRUE)) ++ pTxWI->WirelessCliID = BSSID_WCID; ++ else ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ pTxWI->WirelessCliID = pTxBlk->Wcid; ++ ++ pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack); ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); ++ ++ // John tune the performace with Intel Client in 20 MHz performance ++ BASize = pAd->CommonCfg.TxBASize; ++ if((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry)) ++ { ++ UCHAR RABAOriIdx = 0; //The RA's BA Originator table index. ++ ++ RABAOriIdx = pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority]; ++ BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize; ++ } ++ ++ pTxWI->TxBF = pTransmit->field.TxBF; ++ pTxWI->BAWinSize = BASize; ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pMacEntry) ++ { ++ if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMacEntry->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ ++ if (pMacEntry->bIAmBadAtheros && (pMacEntry->WepStatus != Ndis802_11WEPDisabled)) ++ { ++ pTxWI->MpduDensity = 7; ++ } ++ else ++ { ++ pTxWI->MpduDensity = pMacEntry->MpduDensity; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DBG_DIAGNOSE ++ if (pTxBlk->QueIdx== 0) ++ { ++ pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; ++ pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ // for rate adapation ++ pTxWI->PacketId = pTxWI->MCS; ++} ++ ++ ++VOID RTMPWriteTxWI_Cache( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk) ++{ ++ PHTTRANSMIT_SETTING pTransmit; ++ PMAC_TABLE_ENTRY pMacEntry; ++ ++ // ++ // update TXWI ++ // ++ pMacEntry = pTxBlk->pMacEntry; ++ pTransmit = pTxBlk->pTransmit; ++ ++ if (pMacEntry->bAutoTxRateSwitch) ++ { ++ pTxWI->txop = IFS_HTTXOP; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ ++ // set PID for TxRateSwitching ++ pTxWI->PacketId = pTransmit->field.MCS; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE); ++ pTxWI->MIMOps = 0; ++ ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ ++ if (pAd->CommonCfg.bMIMOPSEnable) ++ { ++ // MIMO Power Save Mode ++ if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMacEntry->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if ((pTransmit->field.MODE >= MODE_HTMIX) && (pTransmit->field.MCS > 7)) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DBG_DIAGNOSE ++ if (pTxBlk->QueIdx== 0) ++ { ++ pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; ++ pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pTxD Pointer to transmit descriptor ++ Ack Setting for Ack requirement bit ++ Fragment Setting for Fragment bit ++ RetryMode Setting for retry mode ++ Ifs Setting for IFS gap ++ Rate Setting for transmit rate ++ Service Setting for service ++ Length Frame length ++ TxPreamble Short or Long preamble when using CCK rates ++ QueIdx - 0-3, according to 802.11e/d4.4 June/2003 ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPWriteTxDescriptor( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXD_STRUC pTxD, ++ IN BOOLEAN bWIV, ++ IN UCHAR QueueSEL) ++{ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ ++ pTxD->WIV = (bWIV) ? 1: 0; ++ pTxD->QSEL= (QueueSEL); ++ if (pAd->bGenOneHCCA == TRUE) ++ pTxD->QSEL= FIFO_HCCA; ++ pTxD->DMADONE = 0; ++} ++ ++ ++// should be called only when - ++// 1. MEADIA_CONNECTED ++// 2. AGGREGATION_IN_USED ++// 3. Fragmentation not in used ++// 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible ++BOOLEAN TxFrameIsAggregatible( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pPrevAddr1, ++ IN PUCHAR p8023hdr) ++{ ++ ++ // can't aggregate EAPOL (802.1x) frame ++ if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e)) ++ return FALSE; ++ ++ // can't aggregate multicast/broadcast frame ++ if (p8023hdr[0] & 0x01) ++ return FALSE; ++ ++ if (INFRA_ON(pAd)) // must be unicast to AP ++ return TRUE; ++ else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) // unicast to same STA ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check the MSDU Aggregation policy ++ 1.HT aggregation is A-MSDU ++ 2.legaacy rate aggregation is software aggregation by Ralink. ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN PeerIsAggreOn( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG TxRate, ++ IN PMAC_TABLE_ENTRY pMacEntry) ++{ ++ ULONG AFlags = (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE); ++ ++ if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++ { ++ return TRUE; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) ++ { // legacy Ralink Aggregation support ++ return TRUE; ++ } ++#endif // AGGREGATION_SUPPORT // ++ } ++ ++ return FALSE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check and fine the packet waiting in SW queue with highest priority ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ pQueue Pointer to Waiting Queue ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++PQUEUE_HEADER RTMPCheckTxSwQueue( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pQueIdx) ++{ ++ ++ ULONG Number; ++ ++ Number = pAd->TxSwQueue[QID_AC_BK].Number ++ + pAd->TxSwQueue[QID_AC_BE].Number ++ + pAd->TxSwQueue[QID_AC_VI].Number ++ + pAd->TxSwQueue[QID_AC_VO].Number ++ + pAd->TxSwQueue[QID_HCCA].Number; ++ ++ if (pAd->TxSwQueue[QID_AC_VO].Head != NULL) ++ { ++ *pQueIdx = QID_AC_VO; ++ return (&pAd->TxSwQueue[QID_AC_VO]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL) ++ { ++ *pQueIdx = QID_AC_VI; ++ return (&pAd->TxSwQueue[QID_AC_VI]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL) ++ { ++ *pQueIdx = QID_AC_BE; ++ return (&pAd->TxSwQueue[QID_AC_BE]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL) ++ { ++ *pQueIdx = QID_AC_BK; ++ return (&pAd->TxSwQueue[QID_AC_BK]); ++ } ++ else if (pAd->TxSwQueue[QID_HCCA].Head != NULL) ++ { ++ *pQueIdx = QID_HCCA; ++ return (&pAd->TxSwQueue[QID_HCCA]); ++ } ++ ++ // No packet pending in Tx Sw queue ++ *pQueIdx = QID_AC_BK; ++ ++ return (NULL); ++} ++ ++ ++#ifdef RT2860 ++BOOLEAN RTMPFreeTXDUponTxDmaDone( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx) ++{ ++ PRTMP_TX_RING pTxRing; ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++#endif ++ PNDIS_PACKET pPacket; ++ UCHAR FREE = 0; ++ TXD_STRUC TxD, *pOriTxD; ++ //ULONG IrqFlags; ++ BOOLEAN bReschedule = FALSE; ++ ++ ++ ASSERT(QueIdx < NUM_OF_TX_RING); ++ pTxRing = &pAd->TxRing[QueIdx]; ++ ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF, &pTxRing->TxDmaIdx); ++ while (pTxRing->TxSwFreeIdx != pTxRing->TxDmaIdx) ++ { ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++ PHEADER_802_11 pHeader80211; ++ ++ if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) ++ { ++ if (pAd->ate.QID == QueIdx) ++ { ++ pAd->ate.TxDoneCount++; ++ //pAd->ate.Repeat++; ++ pAd->RalinkCounters.KickTxCount++; ++ ++ /* always use QID_AC_BE and FIFO_EDCA */ ++ ASSERT(pAd->ate.QID == 0); ++ pAd->ate.TxAc0++; ++ ++ FREE++; ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); ++ pOriTxD = pTxD; ++ NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); ++ pTxD = &TxD; ++#else ++ pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); ++ pOriTxD = pDestTxD ; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ pTxD->DMADONE = 0; ++ ++ pHeader80211 = pTxRing->Cell[pTxRing->TxSwFreeIdx].DmaBuf.AllocVa + sizeof(TXWI_STRUC); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader80211, DIR_READ, FALSE); ++#endif ++ pHeader80211->Sequence = ++pAd->ate.seq; ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader80211, DIR_WRITE, FALSE); ++#endif ++ ++ if ((pAd->ate.bQATxStart == TRUE) && (pAd->ate.Mode & ATE_TXFRAME) && (pAd->ate.TxDoneCount < pAd->ate.TxCount)) ++ { ++ pAd->RalinkCounters.TransmittedByteCount += (pTxD->SDLen1 + pTxD->SDLen0); ++ pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx] ++; ++ INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); ++ /* get tx_tdx_idx again */ ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF , &pTxRing->TxDmaIdx); ++ goto kick_out; ++ } ++ else if ((pAd->ate.TxStatus == 1)/* or (pAd->ate.bQATxStart == TRUE) ??? */ && (pAd->ate.TxDoneCount == pAd->ate.TxCount))//<========================PETER ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("all Tx is done\n")); ++ // Tx status enters idle mode. ++ pAd->ate.TxStatus = 0; ++ } ++ else if (!(pAd->ate.Mode & ATE_TXFRAME)) ++ { ++ /* not complete sending yet, but someone press the Stop TX botton. */ ++ DBGPRINT(RT_DEBUG_ERROR,("not complete sending yet, but someone pressed the Stop TX bottom\n")); ++ DBGPRINT(RT_DEBUG_ERROR,("pAd->ate.Mode = 0x%02x\n", pAd->ate.Mode)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_OFF,("pTxRing->TxSwFreeIdx = %d\n", pTxRing->TxSwFreeIdx)); ++ } ++#ifndef RT_BIG_ENDIAN ++ NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); ++#else ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ *pDestTxD = TxD; ++#endif // RT_BIG_ENDIAN // ++ ++ INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); ++ continue; ++ } ++ } ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++ // static rate also need NICUpdateFifoStaCounters() function. ++ //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) ++ NICUpdateFifoStaCounters(pAd); ++ ++ /* Note : If (pAd->ate.bQATxStart == TRUE), we will never reach here. */ ++ FREE++; ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); ++ pOriTxD = pTxD; ++ NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); ++ pTxD = &TxD; ++#else ++ pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa); ++ pOriTxD = pDestTxD ; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ ++ pTxD->DMADONE = 0; ++ ++ ++#ifdef RALINK_ATE ++ /* Execution of this block is not allowed when ATE is running. */ ++ if (!(ATE_ON(pAd))) ++#endif // RALINK_ATE // ++/*====================================================================*/ ++ { ++ pPacket = pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket; ++ if (pPacket) ++ { ++#ifdef CONFIG_5VT_ENHANCE ++ if (RTMP_GET_PACKET_5VT(pPacket)) ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, 16, PCI_DMA_TODEVICE); ++ else ++#endif // CONFIG_5VT_ENHANCE // ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket; ++ ++ ASSERT(pPacket == NULL); ++ if (pPacket) ++ { ++#ifdef CONFIG_5VT_ENHANCE ++ if (RTMP_GET_PACKET_5VT(pPacket)) ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, 16, PCI_DMA_TODEVICE); ++ else ++#endif // CONFIG_5VT_ENHANCE // ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = NULL; ++ } ++/*====================================================================*/ ++ ++ pAd->RalinkCounters.TransmittedByteCount += (pTxD->SDLen1 + pTxD->SDLen0); ++ pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx] ++; ++ INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE); ++ /* get tx_tdx_idx again */ ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF , &pTxRing->TxDmaIdx); ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ *pDestTxD = TxD; ++#else ++ NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); ++#endif ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++kick_out: ++#endif // RALINK_28xx_QA // ++ ++ // ++ // ATE_TXCONT mode also need to send some normal frames, so let it in. ++ // ATE_STOP must be changed not to be 0xff ++ // to prevent it from running into this block. ++ // ++ if ((pAd->ate.Mode & ATE_TXFRAME) && (pAd->ate.QID == QueIdx)) ++ { ++ // TxDoneCount++ has been done if QA is used. ++ if (pAd->ate.bQATxStart == FALSE) ++ { ++ pAd->ate.TxDoneCount++; ++ } ++ if (((pAd->ate.TxCount - pAd->ate.TxDoneCount + 1) >= TX_RING_SIZE)) ++ { ++ /* Note : We increase TxCpuIdx here, not TxSwFreeIdx ! */ ++ INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE); ++#ifndef RT_BIG_ENDIAN//<==========================PETER ++ pTxD = (PTXD_STRUC) (pTxRing->Cell[pAd->TxRing[QueIdx].TxCpuIdx].AllocVa); ++ pOriTxD = pTxD; ++ NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC)); ++ pTxD = &TxD; ++#else ++ pDestTxD = (PTXD_STRUC) (pTxRing->Cell[pAd->TxRing[QueIdx].TxCpuIdx].AllocVa); ++ pOriTxD = pDestTxD ; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ pTxD->DMADONE = 0; ++#ifndef RT_BIG_ENDIAN//<==========================PETER ++ NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC)); ++#else ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ *pDestTxD = TxD; ++#endif ++ // kick Tx-Ring. ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx * RINGREG_DIFF, pAd->TxRing[QueIdx].TxCpuIdx); ++ pAd->RalinkCounters.KickTxCount++; ++ } ++ } ++#endif // RALINK_ATE // ++ } ++ ++ ++ return bReschedule; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process TX Rings DMA Done interrupt, running in DPC level ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd, ++ IN INT_SOURCE_CSR_STRUC TxRingBitmap) ++{ ++ unsigned long IrqFlags; ++ BOOLEAN bReschedule = FALSE; ++ ++ // Make sure Tx ring resource won't be used by other threads ++ ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++ ++ if (TxRingBitmap.field.Ac0DmaDone) ++ bReschedule = RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BE); ++ ++ if (TxRingBitmap.field.HccaDmaDone) ++ bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_HCCA); ++ ++ if (TxRingBitmap.field.Ac3DmaDone) ++ bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VO); ++ ++ if (TxRingBitmap.field.Ac2DmaDone) ++ bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VI); ++ ++ if (TxRingBitmap.field.Ac1DmaDone) ++ bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BK); ++ ++ // Make sure to release Tx ring resource ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ ++ // Dequeue outgoing frames from TxSwQueue[] and process it ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ ++ return bReschedule; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process MGMT ring DMA done interrupt, running in DPC level ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPHandleMgmtRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ PNDIS_PACKET pPacket; ++ UCHAR FREE = 0; ++ PRTMP_MGMT_RING pMgmtRing = &pAd->MgmtRing; ++ ++ NdisAcquireSpinLock(&pAd->MgmtRingLock); ++ ++ RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pMgmtRing->TxDmaIdx); ++ while (pMgmtRing->TxSwFreeIdx!= pMgmtRing->TxDmaIdx) ++ { ++ FREE++; ++#ifdef RT_BIG_ENDIAN ++ pDestTxD = (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].AllocVa); ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#else ++ pTxD = (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].AllocVa); ++#endif ++ pTxD->DMADONE = 0; ++ pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket; ++ ++ ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket = NULL; ++ ++ pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket = NULL; ++ INC_RING_INDEX(pMgmtRing->TxSwFreeIdx, MGMT_RING_SIZE); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, TRUE, TYPE_TXD); ++#endif ++ } ++ NdisReleaseSpinLock(&pAd->MgmtRingLock); ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Arguments: ++ Adapter Pointer to our adapter. Dequeue all power safe delayed braodcast frames after beacon. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPHandleTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ { ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ } ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Arguments: ++ Adapter Pointer to our adapter. Rewrite beacon content before next send-out. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPHandlePreTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ { ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPHandlePreTBTTInterrupt...\n")); ++ } ++ } ++ ++ ++} ++ ++VOID RTMPHandleRxCoherentInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ ++ if (pAd == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("====> pAd is NULL, return.\n")); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPHandleRxCoherentInterrupt \n")); ++ ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG , &GloCfg.word); ++ ++ GloCfg.field.EnTXWriteBackDDONE = 0; ++ GloCfg.field.EnableRxDMA = 0; ++ GloCfg.field.EnableTxDMA = 0; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ RTMPRingCleanUp(pAd, QID_AC_BE); ++ RTMPRingCleanUp(pAd, QID_AC_BK); ++ RTMPRingCleanUp(pAd, QID_AC_VI); ++ RTMPRingCleanUp(pAd, QID_AC_VO); ++ RTMPRingCleanUp(pAd, QID_HCCA); ++ RTMPRingCleanUp(pAd, QID_MGMT); ++ RTMPRingCleanUp(pAd, QID_RX); ++ ++ RTMPEnableRxTx(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPHandleRxCoherentInterrupt \n")); ++} ++ ++ ++VOID DBGPRINT_TX_RING( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx) ++{ ++ UINT32 Ac0Base; ++ UINT32 Ac0HwIdx = 0, Ac0SwIdx = 0, AC0freeIdx; ++ int i; ++ PULONG ptemp; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("=====================================================\n " )); ++ switch (QueIdx) ++ { ++ case QID_AC_BE: ++ RTMP_IO_READ32(pAd, TX_BASE_PTR0, &Ac0Base); ++ RTMP_IO_READ32(pAd, TX_CTX_IDX0, &Ac0SwIdx); ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0, &Ac0HwIdx); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_BE DESCRIPTOR \n " )); ++ for (i=0;iTxRing[QID_AC_BE].Cell[i].AllocVa; ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); ++ break; ++ case QID_AC_BK: ++ RTMP_IO_READ32(pAd, TX_BASE_PTR1, &Ac0Base); ++ RTMP_IO_READ32(pAd, TX_CTX_IDX1, &Ac0SwIdx); ++ RTMP_IO_READ32(pAd, TX_DTX_IDX1, &Ac0HwIdx); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_BK DESCRIPTOR \n " )); ++ for (i=0;iTxRing[QID_AC_BK].Cell[i].AllocVa; ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); ++ break; ++ case QID_AC_VI: ++ RTMP_IO_READ32(pAd, TX_BASE_PTR2, &Ac0Base); ++ RTMP_IO_READ32(pAd, TX_CTX_IDX2, &Ac0SwIdx); ++ RTMP_IO_READ32(pAd, TX_DTX_IDX2, &Ac0HwIdx); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_VI DESCRIPTOR \n " )); ++ for (i=0;iTxRing[QID_AC_VI].Cell[i].AllocVa; ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); ++ break; ++ case QID_AC_VO: ++ RTMP_IO_READ32(pAd, TX_BASE_PTR3, &Ac0Base); ++ RTMP_IO_READ32(pAd, TX_CTX_IDX3, &Ac0SwIdx); ++ RTMP_IO_READ32(pAd, TX_DTX_IDX3, &Ac0HwIdx); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("All QID_AC_VO DESCRIPTOR \n " )); ++ for (i=0;iTxRing[QID_AC_VO].Cell[i].AllocVa; ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); ++ break; ++ case QID_MGMT: ++ RTMP_IO_READ32(pAd, TX_BASE_PTR5, &Ac0Base); ++ RTMP_IO_READ32(pAd, TX_CTX_IDX5, &Ac0SwIdx); ++ RTMP_IO_READ32(pAd, TX_DTX_IDX5, &Ac0HwIdx); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" All QID_MGMT DESCRIPTOR \n " )); ++ for (i=0;iMgmtRing.Cell[i].AllocVa; ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08lx: %08lx: %08lx: %08lx\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" \n " )); ++ break; ++ ++ default: ++ DBGPRINT_ERR(("DBGPRINT_TX_RING(Ring %d) not supported\n", QueIdx)); ++ break; ++ } ++ AC0freeIdx = pAd->TxRing[QueIdx].TxSwFreeIdx; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("TxRing%d, TX_DTX_IDX=%d, TX_CTX_IDX=%d\n", QueIdx, Ac0HwIdx, Ac0SwIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" TxSwFreeIdx[%d]", AC0freeIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" pending-NDIS=%ld\n", pAd->RalinkCounters.PendingNdisPacketCount)); ++ ++ ++} ++ ++ ++VOID DBGPRINT_RX_RING( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 Ac0Base; ++ UINT32 Ac0HwIdx = 0, Ac0SwIdx = 0, AC0freeIdx; ++ int i; ++ UINT32 *ptemp; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("=====================================================\n " )); ++ RTMP_IO_READ32(pAd, RX_BASE_PTR, &Ac0Base); ++ RTMP_IO_READ32(pAd, RX_CRX_IDX, &Ac0SwIdx); ++ RTMP_IO_READ32(pAd, RX_DRX_IDX, &Ac0HwIdx); ++ AC0freeIdx = pAd->RxRing.RxSwReadIdx; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("All RX DSP \n " )); ++ for (i=0;iRxRing.Cell[i].AllocVa; ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("[%02d] %08x: %08x: %08x: %08x\n " , i, *ptemp,*(ptemp+1),*(ptemp+2),*(ptemp+3))); ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("RxRing, RX_DRX_IDX=%d, RX_CRX_IDX=%d \n", Ac0HwIdx, Ac0SwIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" RxSwReadIdx [%d]=", AC0freeIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" pending-NDIS=%ld\n", pAd->RalinkCounters.PendingNdisPacketCount)); ++} ++#endif // RT2860 // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Suspend MSDU transmission ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("SCANNING, suspend MSDU transmission ...\n")); ++ ++ ++ // ++ // Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and ++ // use Lowbound as R66 value on ScanNextChannel(...) ++ // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); ++ ++ // set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning) ++ RTMPSetAGCInitValue(pAd, BW_20); ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Resume MSDU transmission ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n")); ++ ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++} ++ ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ USHORT PayloadSize; ++ USHORT SubFrameSize; ++ PHEADER_802_3 pAMSDUsubheader; ++ UINT nMSDU; ++ UCHAR Header802_3[14]; ++ ++ PUCHAR pPayload, pDA, pSA, pRemovedLLCSNAP; ++ PNDIS_PACKET pClonePacket; ++ ++ ++ ++ nMSDU = 0; ++ ++ while (DataSize > LENGTH_802_3) ++ { ++ ++ nMSDU++; ++ ++ pAMSDUsubheader = (PHEADER_802_3)pData; ++ PayloadSize = pAMSDUsubheader->Octet[1] + (pAMSDUsubheader->Octet[0]<<8); ++ SubFrameSize = PayloadSize + LENGTH_802_3; ++ ++ ++ if ((DataSize < SubFrameSize) || (PayloadSize > 1518 )) ++ { ++ break; ++ } ++ ++ pPayload = pData + LENGTH_802_3; ++ pDA = pData; ++ pSA = pData + MAC_ADDR_LEN; ++ ++ // convert to 802.3 header ++ CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP); ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) ) ++ { ++ // avoid local heap overflow, use dyanamic allocation ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ memmove(Elem->Msg+(LENGTH_802_11 + LENGTH_802_1_H), pPayload, PayloadSize); ++ Elem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + PayloadSize; ++ WpaEAPOLKeyAction(pAd, Elem); ++ kfree(Elem); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pRemovedLLCSNAP) ++ { ++ pPayload -= LENGTH_802_3; ++ PayloadSize += LENGTH_802_3; ++ NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); ++ if (pClonePacket) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ // A-MSDU has padding to multiple of 4 including subframe header. ++ // align SubFrameSize up to multiple of 4 ++ SubFrameSize = (SubFrameSize+3)&(~0x3); ++ ++ ++ if (SubFrameSize > 1528 || SubFrameSize < 32) ++ { ++ break; ++ } ++ ++ if (DataSize > SubFrameSize) ++ { ++ pData += SubFrameSize; ++ DataSize -= SubFrameSize; ++ } ++ else ++ { ++ // end of A-MSDU ++ DataSize = 0; ++ } ++ } ++ ++ // finally release original rx packet ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ ++ return nMSDU; ++} ++ ++ ++UINT BA_Reorder_AMSDU_Annnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PUCHAR pData; ++ USHORT DataSize; ++ UINT nMSDU = 0; ++ ++ pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); ++ DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); ++ ++ nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); ++ ++ return nMSDU; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Look up the MAC address in the MAC table. Return NULL if not found. ++ Return: ++ pEntry - pointer to the MAC entry; NULL is not found ++ ========================================================================== ++*/ ++MAC_TABLE_ENTRY *MacTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ PUCHAR pAddr) ++{ ++ ULONG HashIdx; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = pAd->MacTab.Hash[HashIdx]; ++ ++ while (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsWDS || pEntry->ValidAsApCli || pEntry->ValidAsMesh)) ++ { ++ if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ break; ++ } ++ else ++ pEntry = pEntry->pNext; ++ } ++ ++ return pEntry; ++} ++ ++MAC_TABLE_ENTRY *MacTableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR apidx, ++ IN BOOLEAN CleanAll) ++{ ++ UCHAR HashIdx; ++ int i, FirstWcid; ++ MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; ++ ++ // if FULL, return ++ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) ++ return NULL; ++ ++ FirstWcid = 1; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ FirstWcid = 2; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // allocate one MAC entry ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ for (i = FirstWcid; i< MAX_LEN_OF_MAC_TABLE; i++) // skip entry#0 so that "entry index == AID" for fast lookup ++ { ++ // pick up the first available vacancy ++ if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) && ++ (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && ++ (pAd->MacTab.Content[i].ValidAsApCli== FALSE) && ++ (pAd->MacTab.Content[i].ValidAsMesh == FALSE) ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ && (pAd->MacTab.Content[i].ValidAsDls == FALSE) ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ if (CleanAll == TRUE) ++ { ++ pEntry->MaxSupportedRate = RATE_11; ++ pEntry->CurrTxRate = RATE_11; ++ NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); ++ pEntry->PairwiseKey.KeyLen = 0; ++ pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; ++ } ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (apidx >= MIN_NET_DEVICE_FOR_DLS) ++ { ++ pEntry->ValidAsCLI = FALSE; ++ pEntry->ValidAsWDS = FALSE; ++ pEntry->ValidAsApCli = FALSE; ++ pEntry->ValidAsMesh = FALSE; ++ pEntry->ValidAsDls = TRUE; ++ pEntry->isCached = FALSE; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry->ValidAsCLI = TRUE; ++ pEntry->ValidAsWDS = FALSE; ++ pEntry->ValidAsApCli = FALSE; ++ pEntry->ValidAsMesh = FALSE; ++ pEntry->ValidAsDls = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ pEntry->bIAmBadAtheros = FALSE; ++ pEntry->pAd = pAd; ++ pEntry->CMTimerRunning = FALSE; ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ pEntry->RSNIE_Len = 0; ++ NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter)); ++ pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR; ++ ++ if (pEntry->ValidAsMesh) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_MESH); ++ else if (pEntry->ValidAsApCli) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI); ++ else if (pEntry->ValidAsWDS) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ else if (pEntry->ValidAsDls) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_DLS); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ else ++ pEntry->apidx = apidx; ++ ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; ++#ifdef RT2860 ++ AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)i); ++#endif // RT2860 // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ pEntry->GTKState = REKEY_NEGOTIATING; ++ pEntry->PairwiseKey.KeyLen = 0; ++ pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ++ (pAd->StaCfg.BssType == BSS_ADHOC)) ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry->ValidAsDls == TRUE) ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ else ++#endif //QOS_DLS_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; ++ COPY_MAC_ADDR(pEntry->Addr, pAddr); ++ pEntry->Sst = SST_NOT_AUTH; ++ pEntry->AuthState = AS_NOT_AUTH; ++ pEntry->Aid = (USHORT)i; //0; ++ pEntry->CapabilityInfo = 0; ++ pEntry->PsMode = PWR_ACTIVE; ++ pEntry->PsQIdleCount = 0; ++ pEntry->NoDataIdleCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ InitializeQueueHeader(&pEntry->PsQueue); ++ ++ ++ pAd->MacTab.Size ++; ++ // Add this entry into ASIC RX WCID search table ++ RT28XX_STA_ENTRY_ADD(pAd, pEntry); ++ ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertEntry - allocate entry #%d, Total= %d\n",i, pAd->MacTab.Size)); ++ break; ++ } ++ } ++ ++ // add this MAC entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ if (pAd->MacTab.Hash[HashIdx] == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pAd->MacTab.Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ return pEntry; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Delete a specified client from MAC table ++ ========================================================================== ++ */ ++BOOLEAN MacTableDeleteEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr) ++{ ++ USHORT HashIdx; ++ MAC_TABLE_ENTRY *pEntry, *pPrevEntry, *pProbeEntry; ++ BOOLEAN Cancelled; ++ ++ if (wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = &pAd->MacTab.Content[wcid]; ++ ++ if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ || pEntry->ValidAsDls ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ )) ++ { ++ if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ ++ // Delete this entry from ASIC on-chip WCID Table ++ RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid); ++ ++#ifdef DOT11_N_SUPPORT ++ // free resources of BA ++ BASessionTearDownALL(pAd, pEntry->Aid); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ pPrevEntry = NULL; ++ pProbeEntry = pAd->MacTab.Hash[HashIdx]; ++ ASSERT(pProbeEntry); ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ // not found !!! ++ ASSERT(pProbeEntry != NULL); ++ ++ RT28XX_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid); ++ ++ ++ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) ++ { ++ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ } ++ ++ ++ NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); ++ pAd->MacTab.Size --; ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableDeleteEntry1 - Total= %d\n", pAd->MacTab.Size)); ++ } ++ else ++ { ++ printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid); ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ //Reset operating mode when no Sta. ++ if (pAd->MacTab.Size == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; ++#endif // DOT11_N_SUPPORT // ++ AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ This routine reset the entire MAC table. All packets pending in ++ the power-saving queues are freed here. ++ ========================================================================== ++ */ ++VOID MacTableReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n")); ++ //NdisAcquireSpinLock(&pAd->MacTabLock); ++ ++ for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) ++ { ++ ++#ifdef DOT11_N_SUPPORT ++ // free resources of BA ++ BASessionTearDownALL(pAd, i); ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->MacTab.Content[i].ValidAsCLI = FALSE; ++ ++ ++ ++ ++ //AsicDelWcidTab(pAd, i); ++ } ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID AssocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, ++ IN PUCHAR pAddr, ++ IN USHORT CapabilityInfo, ++ IN ULONG Timeout, ++ IN USHORT ListenIntv) ++{ ++ COPY_MAC_ADDR(AssocReq->Addr, pAddr); ++ // Add mask to support 802.11b mode only ++ AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; // not cf-pollable, not cf-poll-request ++ AssocReq->Timeout = Timeout; ++ AssocReq->ListenIntv = ListenIntv; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID DisassocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, ++ IN PUCHAR pAddr, ++ IN USHORT Reason) ++{ ++ COPY_MAC_ADDR(DisassocReq->Addr, pAddr); ++ DisassocReq->Reason = Reason; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check the out going frame, if this is an DHCP or ARP datagram ++ will be duplicate another frame at low data rate transmit. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pPacket Pointer to outgoing Ndis frame ++ ++ Return Value: ++ TRUE To be duplicate at Low data rate transmit. (1mb) ++ FALSE Do nothing. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ MAC header + IP Header + UDP Header ++ 14 Bytes 20 Bytes ++ ++ UDP Header ++ 00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| ++ Source Port ++ 16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31| ++ Destination Port ++ ++ port 0x43 means Bootstrap Protocol, server. ++ Port 0x44 means Bootstrap Protocol, client. ++ ++ ======================================================================== ++*/ ++ ++BOOLEAN RTMPCheckDHCPFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ ULONG NumberOfBytesRead = 0; ++ ULONG CurrentOffset = 0; ++ PVOID pVirtualAddress = NULL; ++ UINT NdisBufferLength; ++ PUCHAR pSrc; ++ USHORT Protocol; ++ UCHAR ByteOffset36 = 0; ++ UCHAR ByteOffset38 = 0; ++ BOOLEAN ReadFirstParm = TRUE; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, (PUCHAR *)&pVirtualAddress, &NdisBufferLength); ++ ++ NumberOfBytesRead += NdisBufferLength; ++ pSrc = (PUCHAR) pVirtualAddress; ++ Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); ++ ++ // ++ // Check DHCP & BOOTP protocol ++ // ++ while (NumberOfBytesRead <= PacketInfo.TotalPacketLength) ++ { ++ if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE)) ++ { ++ CurrentOffset = 35 - (NumberOfBytesRead - NdisBufferLength); ++ ByteOffset36 = *(pSrc + CurrentOffset); ++ ReadFirstParm = FALSE; ++ } ++ ++ if (NumberOfBytesRead >= 37) ++ { ++ CurrentOffset = 37 - (NumberOfBytesRead - NdisBufferLength); ++ ByteOffset38 = *(pSrc + CurrentOffset); ++ //End of Read ++ break; ++ } ++ return FALSE; ++ } ++ ++ // Check for DHCP & BOOTP protocol ++ if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43)) ++ { ++ // ++ // 2054 (hex 0806) for ARP datagrams ++ // if this packet is not ARP datagrams, then do nothing ++ // ARP datagrams will also be duplicate at 1mb broadcast frames ++ // ++ if (Protocol != 0x0806 ) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++BOOLEAN RTMPCheckEtherType( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ USHORT TypeLen; ++ UCHAR Byte0, Byte1; ++ PUCHAR pSrcBuf; ++ UINT32 pktLen; ++ UINT16 srcPort, dstPort; ++ BOOLEAN status = TRUE; ++ ++ ++ pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); ++ pktLen = GET_OS_PKT_LEN(pPacket); ++ ++ ASSERT(pSrcBuf); ++ ++ RTMP_SET_PACKET_SPECIFIC(pPacket, 0); ++ ++ // get Ethernet protocol field ++ TypeLen = (pSrcBuf[12] << 8) + pSrcBuf[13]; ++ ++ pSrcBuf += LENGTH_802_3; // Skip the Ethernet Header. ++ ++ if (TypeLen <= 1500) ++ { // 802.3, 802.3 LLC ++ /* ++ DestMAC(6) + SrcMAC(6) + Lenght(2) + ++ DSAP(1) + SSAP(1) + Control(1) + ++ if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. ++ => + SNAP (5, OriginationID(3) + etherType(2)) ++ */ ++ if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) ++ { ++ Sniff2BytesFromNdisBuffer(pSrcBuf, 6, &Byte0, &Byte1); ++ RTMP_SET_PACKET_LLCSNAP(pPacket, 1); ++ TypeLen = (USHORT)((Byte0 << 8) + Byte1); ++ pSrcBuf += 8; // Skip this LLC/SNAP header ++ } ++ else ++ { ++ //It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it. ++ } ++ } ++ ++ // If it's a VLAN packet, get the real Type/Length field. ++ if (TypeLen == 0x8100) ++ { ++ /* 0x8100 means VLAN packets */ ++ ++ /* Dest. MAC Address (6-bytes) + ++ Source MAC Address (6-bytes) + ++ Length/Type = 802.1Q Tag Type (2-byte) + ++ Tag Control Information (2-bytes) + ++ Length / Type (2-bytes) + ++ data payload (0-n bytes) + ++ Pad (0-p bytes) + ++ Frame Check Sequence (4-bytes) */ ++ ++ RTMP_SET_PACKET_VLAN(pPacket, 1); ++ Sniff2BytesFromNdisBuffer(pSrcBuf, 2, &Byte0, &Byte1); ++ TypeLen = (USHORT)((Byte0 << 8) + Byte1); ++ ++ pSrcBuf += 4; // Skip the VLAN Header. ++ } ++ ++ switch (TypeLen) ++ { ++ case 0x0800: ++ { ++ ASSERT((pktLen > 34)); ++ if (*(pSrcBuf + 9) == 0x11) ++ { // udp packet ++ ASSERT((pktLen > 34)); // 14 for ethernet header, 20 for IP header ++ ++ pSrcBuf += 20; // Skip the IP header ++ srcPort = OS_NTOHS(*((UINT16 *)pSrcBuf)); ++ dstPort = OS_NTOHS(*((UINT16 *)(pSrcBuf +2))); ++ ++ if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44)) ++ { //It's a BOOTP/DHCP packet ++ RTMP_SET_PACKET_DHCP(pPacket, 1); ++ } ++ } ++ } ++ break; ++ case 0x0806: ++ { ++ //ARP Packet. ++ RTMP_SET_PACKET_DHCP(pPacket, 1); ++ } ++ break; ++ case 0x888e: ++ { ++ // EAPOL Packet. ++ RTMP_SET_PACKET_EAPOL(pPacket, 1); ++ } ++ break; ++ default: ++ status = FALSE; ++ break; ++ } ++ ++ return status; ++ ++} ++ ++ ++ ++VOID Update_Rssi_Sample( ++ IN PRTMP_ADAPTER pAd, ++ IN RSSI_SAMPLE *pRssi, ++ IN PRXWI_STRUC pRxWI) ++ { ++ CHAR rssi0 = pRxWI->RSSI0; ++ CHAR rssi1 = pRxWI->RSSI1; ++ CHAR rssi2 = pRxWI->RSSI2; ++ ++ if (rssi0 != 0) ++ { ++ pRssi->LastRssi0 = ConvertToRssi(pAd, (CHAR)rssi0, RSSI_0); ++ pRssi->AvgRssi0X8 = (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0; ++ pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3; ++ } ++ ++ if (rssi1 != 0) ++ { ++ pRssi->LastRssi1 = ConvertToRssi(pAd, (CHAR)rssi1, RSSI_1); ++ pRssi->AvgRssi1X8 = (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1; ++ pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3; ++ } ++ ++ if (rssi2 != 0) ++ { ++ pRssi->LastRssi2 = ConvertToRssi(pAd, (CHAR)rssi2, RSSI_2); ++ pRssi->AvgRssi2X8 = (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2; ++ pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3; ++ } ++} ++ ++ ++ ++// Normal legacy Rx packet indication ++VOID Indicate_Legacy_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ UCHAR Header802_3[LENGTH_802_3]; ++ ++ // 1. get 802.3 Header ++ // 2. remove LLC ++ // a. pointer pRxBlk->pData to payload ++ // b. modify pRxBlk->DataSize ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pRxBlk->DataSize > MAX_RX_PKT_LEN) ++ { ++ ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ++ STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); ++ ++ ++ wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); ++ ++ // ++ // pass this 802.3 packet to upper layer or forward this packet to WM directly ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++ ++// Normal, AMPDU or AMSDU ++VOID CmmRxnonRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) ++ { ++ // handle A-MSDU ++ Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ } ++} ++ ++ ++VOID CmmRxRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ UCHAR Header802_3[LENGTH_802_3]; ++ UINT16 Msdu2Size; ++ UINT16 Payload1Size, Payload2Size; ++ PUCHAR pData2; ++ PNDIS_PACKET pPacket2 = NULL; ++ ++ ++ ++ Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData+1) << 8); ++ ++ if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize)) ++ { ++ /* skip two byte MSDU2 len */ ++ pRxBlk->pData += 2; ++ pRxBlk->DataSize -= 2; ++ } ++ else ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // get 802.3 Header and remove LLC ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ASSERT(pRxBlk->pRxPacket); ++ ++ // Ralink Aggregation frame ++ pAd->RalinkCounters.OneSecRxAggregationCount ++; ++ Payload1Size = pRxBlk->DataSize - Msdu2Size; ++ Payload2Size = Msdu2Size - LENGTH_802_3; ++ ++ pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (!pPacket2) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // update payload size of 1st packet ++ pRxBlk->DataSize = Payload1Size; ++ wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pPacket2) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++ ++#define RESET_FRAGFRAME(_fragFrame) \ ++ { \ ++ _fragFrame.RxSize = 0; \ ++ _fragFrame.Sequence = 0; \ ++ _fragFrame.LastFrag = 0; \ ++ _fragFrame.Flags = 0; \ ++ } ++ ++ ++PNDIS_PACKET RTMPDeFragmentDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ UCHAR *pData = pRxBlk->pData; ++ USHORT DataSize = pRxBlk->DataSize; ++ PNDIS_PACKET pRetPacket = NULL; ++ UCHAR *pFragBuffer = NULL; ++ BOOLEAN bReassDone = FALSE; ++ UCHAR HeaderRoom = 0; ++ ++ ++ ASSERT(pHeader); ++ ++ HeaderRoom = pData - (UCHAR *)pHeader; ++ ++ // Re-assemble the fragmented packets ++ if (pHeader->Frag == 0) // Frag. Number is 0 : First frag or only one pkt ++ { ++ // the first pkt of fragment, record it. ++ if (pHeader->FC.MoreFrag) ++ { ++ ASSERT(pAd->FragFrame.pFragPacket); ++ pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); ++ pAd->FragFrame.RxSize = DataSize + HeaderRoom; ++ NdisMoveMemory(pFragBuffer, pHeader, pAd->FragFrame.RxSize); ++ pAd->FragFrame.Sequence = pHeader->Sequence; ++ pAd->FragFrame.LastFrag = pHeader->Frag; // Should be 0 ++ ASSERT(pAd->FragFrame.LastFrag == 0); ++ goto done; // end of processing this frame ++ } ++ } ++ else //Middle & End of fragment ++ { ++ if ((pHeader->Sequence != pAd->FragFrame.Sequence) || ++ (pHeader->Frag != (pAd->FragFrame.LastFrag + 1))) ++ { ++ // Fragment is not the same sequence or out of fragment number order ++ // Reset Fragment control blk ++ RESET_FRAGFRAME(pAd->FragFrame); ++ DBGPRINT(RT_DEBUG_ERROR, ("Fragment is not the same sequence or out of fragment number order.\n")); ++ goto done; // give up this frame ++ } ++ else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE) ++ { ++ // Fragment frame is too large, it exeeds the maximum frame size. ++ // Reset Fragment control blk ++ RESET_FRAGFRAME(pAd->FragFrame); ++ DBGPRINT(RT_DEBUG_ERROR, ("Fragment frame is too large, it exeeds the maximum frame size.\n")); ++ goto done; // give up this frame ++ } ++ ++ // ++ // Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment. ++ // In this case, we will dropt it. ++ // ++ if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", pHeader->Sequence, pHeader->Frag)); ++ goto done; // give up this frame ++ } ++ ++ pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); ++ ++ // concatenate this fragment into the re-assembly buffer ++ NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, DataSize); ++ pAd->FragFrame.RxSize += DataSize; ++ pAd->FragFrame.LastFrag = pHeader->Frag; // Update fragment number ++ ++ // Last fragment ++ if (pHeader->FC.MoreFrag == FALSE) ++ { ++ bReassDone = TRUE; ++ } ++ } ++ ++done: ++ // always release rx fragmented packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ ++ // return defragmented packet if packet is reassembled completely ++ // otherwise return NULL ++ if (bReassDone) ++ { ++ PNDIS_PACKET pNewFragPacket; ++ ++ // allocate a new packet buffer for fragment ++ pNewFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); ++ if (pNewFragPacket) ++ { ++ // update RxBlk ++ pRetPacket = pAd->FragFrame.pFragPacket; ++ pAd->FragFrame.pFragPacket = pNewFragPacket; ++ pRxBlk->pHeader = (PHEADER_802_11) GET_OS_PKT_DATAPTR(pRetPacket); ++ pRxBlk->pData = (UCHAR *)pRxBlk->pHeader + HeaderRoom; ++ pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom; ++ pRxBlk->pRxPacket = pRetPacket; ++ } ++ else ++ { ++ RESET_FRAGFRAME(pAd->FragFrame); ++ } ++ } ++ ++ return pRetPacket; ++} ++ ++ ++VOID Indicate_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ UINT nMSDU; ++ ++ update_os_packet_info(pAd, pRxBlk, FromWhichBSSID); ++ RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); ++ nMSDU = deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, pRxBlk->DataSize); ++} ++ ++VOID Indicate_EAPOL_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pEntry == NULL) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n")); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++} ++ ++#define BCN_TBTT_OFFSET 64 //defer 64 us ++VOID ReSyncBeaconTime( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ UINT32 Offset; ++ ++ ++ Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET); ++ ++ pAd->TbttTickCount++; ++ ++ // ++ // The updated BeaconInterval Value will affect Beacon Interval after two TBTT ++ // beacasue the original BeaconInterval had been loaded into next TBTT_TIMER ++ // ++ if (Offset == (BCN_TBTT_OFFSET-2)) ++ { ++ BCN_TIME_CFG_STRUC csr; ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1 ; // ASIC register in units of 1/16 TU = 64us ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ } ++ else ++ { ++ if (Offset == (BCN_TBTT_OFFSET-1)) ++ { ++ BCN_TIME_CFG_STRUC csr; ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; // ASIC register in units of 1/16 TU ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/cmm_info.c +@@ -0,0 +1,3417 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#include "../rt_config.h" ++ ++INT Show_SSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef DOT11_N_SUPPORT ++INT Show_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // DOT11_N_SUPPORT // ++ ++INT Show_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_CountryCode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef AGGREGATION_SUPPORT ++INT Show_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // AGGREGATION_SUPPORT // ++ ++#ifdef WMM_SUPPORT ++INT Show_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // WMM_SUPPORT // ++ ++INT Show_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef CONFIG_STA_SUPPORT ++INT Show_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Show_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++static struct { ++ CHAR *name; ++ INT (*show_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC, RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC[] = { ++ {"SSID", Show_SSID_Proc}, ++ {"WirelessMode", Show_WirelessMode_Proc}, ++ {"TxBurst", Show_TxBurst_Proc}, ++ {"TxPreamble", Show_TxPreamble_Proc}, ++ {"TxPower", Show_TxPower_Proc}, ++ {"Channel", Show_Channel_Proc}, ++ {"BGProtection", Show_BGProtection_Proc}, ++ {"RTSThreshold", Show_RTSThreshold_Proc}, ++ {"FragThreshold", Show_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Show_HtBw_Proc}, ++ {"HtMcs", Show_HtMcs_Proc}, ++ {"HtGi", Show_HtGi_Proc}, ++ {"HtOpMode", Show_HtOpMode_Proc}, ++ {"HtExtcha", Show_HtExtcha_Proc}, ++ {"HtMpduDensity", Show_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Show_HtBaWinSize_Proc}, ++ {"HtRdg", Show_HtRdg_Proc}, ++ {"HtAmsdu", Show_HtAmsdu_Proc}, ++ {"HtAutoBa", Show_HtAutoBa_Proc}, ++#endif // DOT11_N_SUPPORT // ++ {"CountryRegion", Show_CountryRegion_Proc}, ++ {"CountryRegionABand", Show_CountryRegionABand_Proc}, ++ {"CountryCode", Show_CountryCode_Proc}, ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Show_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Show_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Show_IEEE80211H_Proc}, ++#ifdef CONFIG_STA_SUPPORT ++ {"NetworkType", Show_NetworkType_Proc}, ++#endif // CONFIG_STA_SUPPORT // ++ {"AuthMode", Show_AuthMode_Proc}, ++ {"EncrypType", Show_EncrypType_Proc}, ++ {"DefaultKeyID", Show_DefaultKeyID_Proc}, ++ {"Key1", Show_Key1_Proc}, ++ {"Key2", Show_Key2_Proc}, ++ {"Key3", Show_Key3_Proc}, ++ {"Key4", Show_Key4_Proc}, ++ {"WPAPSK", Show_WPAPSK_Proc}, ++ {NULL, NULL} ++}; ++ ++/* ++ ========================================================================== ++ Description: ++ Get Driver version. ++ ++ Return: ++ ========================================================================== ++*/ ++INT Set_DriverVersion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); ++#endif // CONFIG_STA_SUPPORT // ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Country Region. ++ This command will not work, if the field of CountryRegion in eeprom is programmed. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG region; ++ ++ region = simple_strtol(arg, 0, 10); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ return -EOPNOTSUPP; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Country can be set only when EEPROM not programmed ++ if (pAd->CommonCfg.CountryRegion & 0x80) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameter of CountryRegion in eeprom is programmed \n")); ++ return FALSE; ++ } ++ ++ if((region >= 0) && (region <= REGION_MAXIMUM_BG_BAND)) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) region; ++ } ++ else if (region == REGION_31_BG_BAND) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) region; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameters out of range\n")); ++ return FALSE; ++ } ++ ++ // if set country region, driver needs to be reset ++ BuildChannelList(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegion_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegion)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Country Region for A band. ++ This command will not work, if the field of CountryRegion in eeprom is programmed. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG region; ++ ++ region = simple_strtol(arg, 0, 10); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ return -EOPNOTSUPP; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Country can be set only when EEPROM not programmed ++ if (pAd->CommonCfg.CountryRegionForABand & 0x80) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameter of CountryRegion in eeprom is programmed \n")); ++ return FALSE; ++ } ++ ++ if((region >= 0) && (region <= REGION_MAXIMUM_A_BAND)) ++ { ++ pAd->CommonCfg.CountryRegionForABand = (UCHAR) region; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameters out of range\n")); ++ return FALSE; ++ } ++ ++ // if set country region, driver needs to be reset ++ BuildChannelList(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegionABand_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegionForABand)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Wireless Mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG WirelessMode; ++ INT success = TRUE; ++ ++ WirelessMode = simple_strtol(arg, 0, 10); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ INT MaxPhyMode = PHY_11G; ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ if (WirelessMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAd, WirelessMode); ++#ifdef DOT11_N_SUPPORT ++ if (WirelessMode >= PHY_11ABGN_MIXED) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ pAd->CommonCfg.REGBACapability.field.AutoBA = TRUE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ pAd->CommonCfg.REGBACapability.field.AutoBA = FALSE; ++ } ++#endif // DOT11_N_SUPPORT // ++ // Set AdhocMode rates ++ if (pAd->StaCfg.BssType == BSS_ADHOC) ++ { ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy to on-chip memory ++ } ++ } ++ else ++ { ++ success = FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // it is needed to set SSID to take effect ++ if (success == TRUE) ++ { ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WirelessMode_Proc::(=%ld)\n", WirelessMode)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_WirelessMode_Proc::parameters out of range\n")); ++ } ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Channel ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ INT success = TRUE; ++ UCHAR Channel; ++ ++ Channel = (UCHAR) simple_strtol(arg, 0, 10); ++ ++ // check if this channel is valid ++ if (ChannelSanity(pAd, Channel) == TRUE) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->CommonCfg.Channel = Channel; ++ ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ N_ChannelCheck(pAd); ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ N_SetCenCh(pAd); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40, control_channel(%d), CentralChannel(%d) \n", ++ pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAd->CommonCfg.Channel)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ success = TRUE; ++ } ++ else ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ success = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ if (success == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Channel_Proc::(Channel=%d)\n", pAd->CommonCfg.Channel)); ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Short Slot Time Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ShortSlot_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG ShortSlot; ++ ++ ShortSlot = simple_strtol(arg, 0, 10); ++ ++ if (ShortSlot == 1) ++ pAd->CommonCfg.bUseShortSlotTime = TRUE; ++ else if (ShortSlot == 0) ++ pAd->CommonCfg.bUseShortSlotTime = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ShortSlot_Proc::(ShortSlot=%d)\n", pAd->CommonCfg.bUseShortSlotTime)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Tx power ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG TxPower; ++ INT success = FALSE; ++ ++ TxPower = (ULONG) simple_strtol(arg, 0, 10); ++ if (TxPower <= 100) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->CommonCfg.TxPowerDefault = TxPower; ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ success = TRUE; ++ } ++ else ++ success = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPower_Proc::(TxPowerPercentage=%ld)\n", pAd->CommonCfg.TxPowerPercentage)); ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set 11B/11G Protection ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ switch (simple_strtol(arg, 0, 10)) ++ { ++ case 0: //AUTO ++ pAd->CommonCfg.UseBGProtection = 0; ++ break; ++ case 1: //Always On ++ pAd->CommonCfg.UseBGProtection = 1; ++ break; ++ case 2: //Always OFF ++ pAd->CommonCfg.UseBGProtection = 2; ++ break; ++ default: //Invalid argument ++ return FALSE; ++ } ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_BGProtection_Proc::(BGProtection=%ld)\n", pAd->CommonCfg.UseBGProtection)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set TxPreamble ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ RT_802_11_PREAMBLE Preamble; ++ ++ Preamble = simple_strtol(arg, 0, 10); ++ ++ ++ switch (Preamble) ++ { ++ case Rt802_11PreambleShort: ++ pAd->CommonCfg.TxPreamble = Preamble; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ case Rt802_11PreambleLong: ++#ifdef CONFIG_STA_SUPPORT ++ case Rt802_11PreambleAuto: ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++#endif // CONFIG_STA_SUPPORT // ++ pAd->CommonCfg.TxPreamble = Preamble; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ default: //Invalid argument ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPreamble_Proc::(TxPreamble=%ld)\n", pAd->CommonCfg.TxPreamble)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set RTS Threshold ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ ++ RtsThresh = simple_strtol(arg, 0, 10); ++ ++ if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) ++ pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++#ifdef CONFIG_STA_SUPPORT ++ else if (RtsThresh == 0) ++ pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; ++#endif // CONFIG_STA_SUPPORT // ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_RTSThreshold_Proc::(RTSThreshold=%d)\n", pAd->CommonCfg.RtsThreshold)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Fragment Threshold ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ ++ FragThresh = simple_strtol(arg, 0, 10); ++ ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ //Illegal FragThresh so we set it to default ++ pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ } ++ else if (FragThresh % 2 == 1) ++ { ++ // The length of each fragment shall always be an even number of octets, except for the last fragment ++ // of an MSDU or MMPDU, which may be either an even or an odd number of octets. ++ pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); ++ } ++ else ++ { ++ pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->CommonCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) ++ pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ else ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_FragThreshold_Proc::(FragThreshold=%d)\n", pAd->CommonCfg.FragmentThreshold)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set TxBurst ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG TxBurst; ++ ++ TxBurst = simple_strtol(arg, 0, 10); ++ if (TxBurst == 1) ++ pAd->CommonCfg.bEnableTxBurst = TRUE; ++ else if (TxBurst == 0) ++ pAd->CommonCfg.bEnableTxBurst = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxBurst_Proc::(TxBurst=%d)\n", pAd->CommonCfg.bEnableTxBurst)); ++ ++ return TRUE; ++} ++ ++#ifdef AGGREGATION_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set TxBurst ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG aggre; ++ ++ aggre = simple_strtol(arg, 0, 10); ++ ++ if (aggre == 1) ++ pAd->CommonCfg.bAggregationCapable = TRUE; ++ else if (aggre == 0) ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PktAggregate_Proc::(AGGRE=%d)\n", pAd->CommonCfg.bAggregationCapable)); ++ ++ return TRUE; ++} ++#endif ++ ++/* ++ ========================================================================== ++ Description: ++ Set IEEE80211H. ++ This parameter is 1 when needs radar detection, otherwise 0 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG ieee80211h; ++ ++ ieee80211h = simple_strtol(arg, 0, 10); ++ ++ if (ieee80211h == 1) ++ pAd->CommonCfg.bIEEE80211H = TRUE; ++ else if (ieee80211h == 0) ++ pAd->CommonCfg.bIEEE80211H = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_IEEE80211H_Proc::(IEEE80211H=%d)\n", pAd->CommonCfg.bIEEE80211H)); ++ ++ return TRUE; ++} ++ ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ For Debug information ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Debug_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> Set_Debug_Proc *******************\n")); ++ ++ if(simple_strtol(arg, 0, 10) <= RT_DEBUG_LOUD) ++ RTDebugLevel = simple_strtol(arg, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== Set_Debug_Proc(RTDebugLevel = %ld)\n", RTDebugLevel)); ++ ++ return TRUE; ++} ++#endif ++ ++INT Show_DescInfo_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++#ifdef RT2860 ++ INT i, QueIdx=0; ++ PRT28XX_RXD_STRUC pRxD; ++ PTXD_STRUC pTxD; ++ PRTMP_TX_RING pTxRing = &pAd->TxRing[QueIdx]; ++ PRTMP_MGMT_RING pMgmtRing = &pAd->MgmtRing; ++ PRTMP_RX_RING pRxRing = &pAd->RxRing; ++ ++ for(i=0;iCell[i].AllocVa; ++ printk("Desc #%d\n",i); ++ hex_dump("Tx Descriptor", (char *)pTxD, 16); ++ printk("pTxD->DMADONE = %x\n", pTxD->DMADONE); ++ } ++ printk("---------------------------------------------------\n"); ++ for(i=0;iCell[i].AllocVa; ++ printk("Desc #%d\n",i); ++ hex_dump("Mgmt Descriptor", (char *)pTxD, 16); ++ printk("pMgmt->DMADONE = %x\n", pTxD->DMADONE); ++ } ++ printk("---------------------------------------------------\n"); ++ for(i=0;iCell[i].AllocVa; ++ printk("Desc #%d\n",i); ++ hex_dump("Rx Descriptor", (char *)pRxD, 16); ++ printk("pRxD->DDONE = %x\n", pRxD->DDONE); ++ } ++#endif // RT2860 // ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Reset statistics counter ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ arg ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ResetStatCounter_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>Set_ResetStatCounter_Proc\n")); ++ ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAd); ++ ++ NdisZeroMemory(&pAd->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAd->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAd->RalinkCounters, sizeof(COUNTER_RALINK)); ++ ++ return TRUE; ++} ++ ++BOOLEAN RTMPCheckStrPrintAble( ++ IN CHAR *pInPutStr, ++ IN UCHAR strLen) ++{ ++ UCHAR i=0; ++ ++ for (i=0; i 0x7E)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Remove WPA Key process ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuf Pointer to the where the key stored ++ ++ Return Value: ++ NDIS_SUCCESS Add key successfully ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPSetDesiredRates( ++ IN PRTMP_ADAPTER pAdapter, ++ IN LONG Rates) ++{ ++ NDIS_802_11_RATES aryRates; ++ ++ memset(&aryRates, 0x00, sizeof(NDIS_802_11_RATES)); ++ switch (pAdapter->CommonCfg.PhyMode) ++ { ++ case PHY_11A: // A only ++ switch (Rates) ++ { ++ case 6000000: //6M ++ aryRates[0] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 9000000: //9M ++ aryRates[0] = 0x12; // 9M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 12000000: //12M ++ aryRates[0] = 0x18; // 12M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 18000000: //18M ++ aryRates[0] = 0x24; // 18M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 24000000: //24M ++ aryRates[0] = 0x30; // 24M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; ++ break; ++ case 36000000: //36M ++ aryRates[0] = 0x48; // 36M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; ++ break; ++ case 48000000: //48M ++ aryRates[0] = 0x60; // 48M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; ++ break; ++ case 54000000: //54M ++ aryRates[0] = 0x6c; // 54M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; ++ break; ++ case -1: //Auto ++ default: ++ aryRates[0] = 0x6c; // 54Mbps ++ aryRates[1] = 0x60; // 48Mbps ++ aryRates[2] = 0x48; // 36Mbps ++ aryRates[3] = 0x30; // 24Mbps ++ aryRates[4] = 0x24; // 18M ++ aryRates[5] = 0x18; // 12M ++ aryRates[6] = 0x12; // 9M ++ aryRates[7] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ break; ++ } ++ break; ++ case PHY_11BG_MIXED: // B/G Mixed ++ case PHY_11B: // B only ++ case PHY_11ABG_MIXED: // A/B/G Mixed ++ default: ++ switch (Rates) ++ { ++ case 1000000: //1M ++ aryRates[0] = 0x02; ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 2000000: //2M ++ aryRates[0] = 0x04; ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 5000000: //5.5M ++ aryRates[0] = 0x0b; // 5.5M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 11000000: //11M ++ aryRates[0] = 0x16; // 11M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 6000000: //6M ++ aryRates[0] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 9000000: //9M ++ aryRates[0] = 0x12; // 9M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 12000000: //12M ++ aryRates[0] = 0x18; // 12M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 18000000: //18M ++ aryRates[0] = 0x24; // 18M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 24000000: //24M ++ aryRates[0] = 0x30; // 24M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; ++ break; ++ case 36000000: //36M ++ aryRates[0] = 0x48; // 36M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; ++ break; ++ case 48000000: //48M ++ aryRates[0] = 0x60; // 48M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; ++ break; ++ case 54000000: //54M ++ aryRates[0] = 0x6c; // 54M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; ++ break; ++ case -1: //Auto ++ default: ++ if (pAdapter->CommonCfg.PhyMode == PHY_11B) ++ { //B Only ++ aryRates[0] = 0x16; // 11Mbps ++ aryRates[1] = 0x0b; // 5.5Mbps ++ aryRates[2] = 0x04; // 2Mbps ++ aryRates[3] = 0x02; // 1Mbps ++ } ++ else ++ { //(B/G) Mixed or (A/B/G) Mixed ++ aryRates[0] = 0x6c; // 54Mbps ++ aryRates[1] = 0x60; // 48Mbps ++ aryRates[2] = 0x48; // 36Mbps ++ aryRates[3] = 0x30; // 24Mbps ++ aryRates[4] = 0x16; // 11Mbps ++ aryRates[5] = 0x0b; // 5.5Mbps ++ aryRates[6] = 0x04; // 2Mbps ++ aryRates[7] = 0x02; // 1Mbps ++ } ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ break; ++ } ++ break; ++ } ++ ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, (" RTMPSetDesiredRates (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++} ++ ++NDIS_STATUS RTMPWPARemoveKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf) ++{ ++ PNDIS_802_11_REMOVE_KEY pKey; ++ ULONG KeyIdx; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ BOOLEAN bTxKey; // Set the key as transmit key ++ BOOLEAN bPairwise; // Indicate the key is pairwise key ++ BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. ++ // Otherwise, it will set by the NIC. ++ BOOLEAN bAuthenticator; // indicate key is set by authenticator. ++ INT i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("---> RTMPWPARemoveKeyProc\n")); ++ ++ pKey = (PNDIS_802_11_REMOVE_KEY) pBuf; ++ KeyIdx = pKey->KeyIndex & 0xff; ++ // Bit 31 of Add-key, Tx Key ++ bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; ++ // Bit 30 of Add-key PairwiseKey ++ bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; ++ // Bit 29 of Add-key KeyRSC ++ bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; ++ // Bit 28 of Add-key Authenticator ++ bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; ++ ++ // 1. If bTx is TRUE, return failure information ++ if (bTxKey == TRUE) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 2. Check Pairwise Key ++ if (bPairwise) ++ { ++ // a. If BSSID is broadcast, remove all pairwise keys. ++ // b. If not broadcast, remove the pairwise specified by BSSID ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ if (MAC_ADDR_EQUAL(pAd->SharedKey[BSS0][i].BssId, pKey->BSSID)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%d)\n", i)); ++ pAd->SharedKey[BSS0][i].KeyLen = 0; ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)i); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ } ++ } ++ // 3. Group Key ++ else ++ { ++ // a. If BSSID is broadcast, remove all group keys indexed ++ // b. If BSSID matched, delete the group key indexed. ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%ld)\n", KeyIdx)); ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx); ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ ++ return (Status); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Remove All WPA Keys ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPWPARemoveAllKeys( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ UCHAR i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveAllKeys(AuthMode=%d, WepStatus=%d)\n", pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus)); ++ ++ // For WEP/CKIP, there is no need to remove it, since WinXP won't set it again after ++ // Link up. And it will be replaced if user changed it. ++ if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return; ++ ++ // For WPA-None, there is no need to remove it, since WinXP won't set it again after ++ // Link up. And it will be replaced if user changed it. ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ return; ++ ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAd, BSS0, BSSID_WCID); ++ ++ // set all shared key mode as no-security. ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("remove %s key #%d\n", CipherName[pAd->SharedKey[BSS0][i].CipherAlg], i)); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][i], sizeof(CIPHER_KEY)); ++ ++ AsicRemoveSharedKeyEntry(pAd, BSS0, i); ++ } ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Change NIC PHY mode. Re-association may be necessary. possible settings ++ include - PHY_11B, PHY_11BG_MIXED, PHY_11A, and PHY_11ABG_MIXED ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPSetPhyMode( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG phymode) ++{ ++ INT i; ++ // the selected phymode must be supported by the RF IC encoded in E2PROM ++ ++ // if no change, do nothing ++ /* bug fix ++ if (pAd->CommonCfg.PhyMode == phymode) ++ return; ++ */ ++ pAd->CommonCfg.PhyMode = (UCHAR)phymode; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPSetPhyMode : PhyMode=%d, channel=%d \n", pAd->CommonCfg.PhyMode, pAd->CommonCfg.Channel)); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ BuildChannelListEx(pAd); ++#else ++ BuildChannelList(pAd); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // sanity check user setting ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->CommonCfg.Channel == pAd->ChannelList[i].Channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->CommonCfg.Channel = FirstChannel(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetPhyMode: channel is out of range, use first channel=%d \n", pAd->CommonCfg.Channel)); ++ } ++ ++ NdisZeroMemory(pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisZeroMemory(pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisZeroMemory(pAd->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ switch (phymode) { ++ case PHY_11B: ++ pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRateLen = 4; ++ pAd->CommonCfg.ExtRateLen = 0; ++ pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps ++ //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_CCK; // This MODE is only FYI. not use ++ break; ++ ++ case PHY_11G: ++ case PHY_11BG_MIXED: ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11N_2_4G: ++ case PHY_11ABGN_MIXED: ++ case PHY_11BGN_MIXED: ++ case PHY_11GN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[4] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[5] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[6] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRateLen = 8; ++ pAd->CommonCfg.ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[1] = 0x18; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[2] = 0x30; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[3] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRateLen = 4; ++ pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[4] = 12; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[5] = 18; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[6] = 24; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[7] = 36; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[8] = 48; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[9] = 72; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[10] = 96; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[11] = 108; // 54 mbps, in units of 0.5 Mbps ++ break; ++ ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AN_MIXED: ++ case PHY_11AGN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRateLen = 8; ++ pAd->CommonCfg.ExtRateLen = 0; ++ pAd->CommonCfg.DesireRate[0] = 12; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 18; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 24; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 36; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[4] = 48; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[5] = 72; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[6] = 96; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[7] = 108; // 54 mbps, in units of 0.5 Mbps ++ //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_OFDM; // This MODE is only FYI. not use ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++} ++ ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ======================================================================== ++ Routine Description: ++ Caller ensures we has 802.11n support. ++ Calls at setting HT from AP/STASetinformation ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ ======================================================================== ++*/ ++VOID RTMPSetHT( ++ IN PRTMP_ADAPTER pAd, ++ IN OID_SET_HT_PHYMODE *pHTPhyMode) ++{ ++ //ULONG *pmcs; ++ UINT32 Value = 0; ++ UCHAR BBPValue = 0; ++ UCHAR BBP3Value = 0; ++ UCHAR RxStream = pAd->CommonCfg.RxStream; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : HT_mode(%d), ExtOffset(%d), MCS(%d), BW(%d), STBC(%d), SHORTGI(%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, ++ pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ ++ // Don't zero supportedHyPhy structure. ++ RTMPZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); ++ RTMPZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); ++ RTMPZeroMemory(&pAd->CommonCfg.NewExtChanOffset, sizeof(pAd->CommonCfg.NewExtChanOffset)); ++ RTMPZeroMemory(&pAd->CommonCfg.DesiredHtPhy, sizeof(pAd->CommonCfg.DesiredHtPhy)); ++ ++ if (pAd->CommonCfg.bRdg) ++ { ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 1; ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 0; ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 0; ++ } ++ ++ pAd->CommonCfg.HtCapability.HtCapParm.MaxRAmpduFactor = 3; ++ pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor = 3; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : RxBAWinLimit = %d\n", pAd->CommonCfg.BACapability.field.RxBAWinLimit)); ++ ++ // Mimo power save, A-MSDU size, ++ pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize = (UCHAR)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.DesiredHtPhy.MimoPs = (UCHAR)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ ++ pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : AMsduSize = %d, MimoPs = %d, MpduDensity = %d, MaxRAmpduFactor = %d\n", ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize, ++ pAd->CommonCfg.DesiredHtPhy.MimoPs, ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity, ++ pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor)); ++ ++ if(pHTPhyMode->HtMode == HTMODE_GF) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.GF = 1; ++ pAd->CommonCfg.DesiredHtPhy.GF = 1; ++ } ++ else ++ pAd->CommonCfg.DesiredHtPhy.GF = 0; ++ ++ // Decide Rx MCSSet ++ switch (RxStream) ++ { ++ case 1: ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0x00; ++ break; ++ ++ case 2: ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; ++ break; ++ ++ case 3: // 3*3 ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[2] = 0xff; ++ break; ++ } ++ ++ if (pAd->CommonCfg.bForty_Mhz_Intolerant && (pAd->CommonCfg.Channel <= 14) && (pHTPhyMode->BW == BW_40) ) ++ { ++ pHTPhyMode->BW = BW_20; ++ pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant = 1; ++ } ++ ++ if(pHTPhyMode->BW == BW_40) ++ { ++ pAd->CommonCfg.HtCapability.MCSSet[4] = 0x1; // MCS 32 ++ pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 1; ++ if (pAd->CommonCfg.Channel <= 14) ++ pAd->CommonCfg.HtCapability.HtCapInfo.CCKmodein40 = 1; ++ ++ pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 1; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 1; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = (pHTPhyMode->ExtOffset == EXTCHA_BELOW)? (EXTCHA_BELOW): EXTCHA_ABOVE; ++ // Set Regsiter for extension channel position. ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBP3Value); ++ if ((pHTPhyMode->ExtOffset == EXTCHA_BELOW)) ++ { ++ Value |= 0x1; ++ BBP3Value |= (0x20); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ } ++ else if ((pHTPhyMode->ExtOffset == EXTCHA_ABOVE)) ++ { ++ Value &= 0xfe; ++ BBP3Value &= (~0x20); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ } ++ ++ // Turn on BBP 40MHz mode now only as AP . ++ // Sta can turn on BBP 40MHz after connection with 40MHz AP. Sta only broadcast 40MHz capability before connection. ++ if ((pAd->OpMode == OPMODE_AP) || INFRA_ON(pAd) || ADHOC_ON(pAd) ++ ) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBP3Value); ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 0; ++ pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 0; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 0; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = EXTCHA_NONE; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ // Turn on BBP 20MHz mode by request here. ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ } ++ } ++ ++ if(pHTPhyMode->STBC == STBC_USE) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 1; ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 1; ++ pAd->CommonCfg.HtCapability.HtCapInfo.RxSTBC = 1; ++ pAd->CommonCfg.DesiredHtPhy.RxSTBC = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; ++ pAd->CommonCfg.DesiredHtPhy.RxSTBC = 0; ++ } ++ ++ ++ if(pHTPhyMode->SHORTGI == GI_400) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 1; ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 1; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 1; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 0; ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 0; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 0; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 0; ++ } ++ ++ // We support link adaptation for unsolicit MCS feedback, set to 2. ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback = MCSFBK_NONE; //MCSFBK_UNSOLICIT; ++ pAd->CommonCfg.AddHTInfo.ControlChan = pAd->CommonCfg.Channel; ++ // 1, the extension channel above the control channel. ++ ++ // EDCA parameters used for AP's own transmission ++ if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) ++ { ++ pAd->CommonCfg.APEdcaParm.bValid = TRUE; ++ pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; ++ pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; ++ pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; ++ pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; ++ pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmax[0] = 6; ++ pAd->CommonCfg.APEdcaParm.Cwmax[1] = 10; ++ pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; ++ ++ pAd->CommonCfg.APEdcaParm.Txop[0] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[1] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[2] = 94; ++ pAd->CommonCfg.APEdcaParm.Txop[3] = 47; ++ } ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ RTMPSetIndividualHT(pAd, 0); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Caller ensures we has 802.11n support. ++ Calls at setting HT from AP/STASetinformation ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ ======================================================================== ++*/ ++VOID RTMPSetIndividualHT( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx) ++{ ++ PRT_HT_PHY_INFO pDesired_ht_phy = NULL; ++ UCHAR TxStream = pAd->CommonCfg.TxStream; ++ UCHAR DesiredMcs = MCS_AUTO; ++ ++ do ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pDesired_ht_phy = &pAd->StaCfg.DesiredHtPhyInfo; ++ DesiredMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; ++ //pAd->StaCfg.bAutoTxRateSwitch = (DesiredMcs == MCS_AUTO) ? TRUE : FALSE; ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } while (FALSE); ++ ++ if (pDesired_ht_phy == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetIndividualHT: invalid apidx(%d)\n", apidx)); ++ return; ++ } ++ RTMPZeroMemory(pDesired_ht_phy, sizeof(RT_HT_PHY_INFO)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetIndividualHT : Desired MCS = %d\n", DesiredMcs)); ++ // Check the validity of MCS ++ if ((TxStream == 1) && ((DesiredMcs >= MCS_8) && (DesiredMcs <= MCS_15))) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS(%d) is invalid in 1S, reset it as MCS_7\n", DesiredMcs)); ++ DesiredMcs = MCS_7; ++ } ++ ++ if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_20) && (DesiredMcs == MCS_32)) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS_32 is only supported in 40-MHz, reset it as MCS_0\n")); ++ DesiredMcs = MCS_0; ++ } ++ ++ pDesired_ht_phy->bHtEnable = TRUE; ++ ++ // Decide desired Tx MCS ++ switch (TxStream) ++ { ++ case 1: ++ if (DesiredMcs == MCS_AUTO) ++ { ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0x00; ++ } ++ else if (DesiredMcs <= MCS_7) ++ { ++ pDesired_ht_phy->MCSSet[0]= 1<MCSSet[1]= 0x00; ++ } ++ break; ++ ++ case 2: ++ if (DesiredMcs == MCS_AUTO) ++ { ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0xff; ++ } ++ else if (DesiredMcs <= MCS_15) ++ { ++ ULONG mode; ++ ++ mode = DesiredMcs / 8; ++ if (mode < 2) ++ pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); ++ } ++ break; ++ ++ case 3: // 3*3 ++ if (DesiredMcs == MCS_AUTO) ++ { ++ /* MCS0 ~ MCS23, 3 bytes */ ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0xff; ++ pDesired_ht_phy->MCSSet[2]= 0xff; ++ } ++ else if (DesiredMcs <= MCS_23) ++ { ++ ULONG mode; ++ ++ mode = DesiredMcs / 8; ++ if (mode < 3) ++ pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); ++ } ++ break; ++ } ++ ++ if(pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_40) ++ { ++ if (DesiredMcs == MCS_AUTO || DesiredMcs == MCS_32) ++ pDesired_ht_phy->MCSSet[4] = 0x1; ++ } ++ ++ // update HT Rate setting ++ if (pAd->OpMode == OPMODE_STA) ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ else ++ MlmeUpdateHtTxRates(pAd, apidx); ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Update HT IE from our capability. ++ ++ Arguments: ++ Send all HT IE in beacon/probe rsp/assoc rsp/action frame. ++ ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateHTIE( ++ IN RT_HT_CAPABILITY *pRtHt, ++ IN UCHAR *pMcsSet, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo) ++{ ++ RTMPZeroMemory(pHtCapability, sizeof(HT_CAPABILITY_IE)); ++ RTMPZeroMemory(pAddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ pHtCapability->HtCapInfo.ChannelWidth = pRtHt->ChannelWidth; ++ pHtCapability->HtCapInfo.MimoPs = pRtHt->MimoPs; ++ pHtCapability->HtCapInfo.GF = pRtHt->GF; ++ pHtCapability->HtCapInfo.ShortGIfor20 = pRtHt->ShortGIfor20; ++ pHtCapability->HtCapInfo.ShortGIfor40 = pRtHt->ShortGIfor40; ++ pHtCapability->HtCapInfo.TxSTBC = pRtHt->TxSTBC; ++ pHtCapability->HtCapInfo.RxSTBC = pRtHt->RxSTBC; ++ pHtCapability->HtCapInfo.AMsduSize = pRtHt->AmsduSize; ++ pHtCapability->HtCapParm.MaxRAmpduFactor = pRtHt->MaxRAmpduFactor; ++ pHtCapability->HtCapParm.MpduDensity = pRtHt->MpduDensity; ++ ++ pAddHtInfo->AddHtInfo.ExtChanOffset = pRtHt->ExtChanOffset ; ++ pAddHtInfo->AddHtInfo.RecomWidth = pRtHt->RecomWidth; ++ pAddHtInfo->AddHtInfo2.OperaionMode = pRtHt->OperaionMode; ++ pAddHtInfo->AddHtInfo2.NonGfPresent = pRtHt->NonGfPresent; ++ RTMPMoveMemory(pAddHtInfo->MCSSet, /*pRtHt->MCSSet*/pMcsSet, 4); // rt2860 only support MCS max=32, no need to copy all 16 uchar. ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPUpdateHTIE <== \n")); ++} ++#endif // DOT11_N_SUPPORT // ++ ++/* ++ ======================================================================== ++ Description: ++ Add Client security information into ASIC WCID table and IVEIV table. ++ Return: ++ ======================================================================== ++*/ ++VOID RTMPAddWcidAttributeEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ UINT32 WCIDAttri = 0; ++ USHORT offset; ++ UCHAR IVEIV = 0; ++ USHORT Wcid = 0; ++ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (BssIdx > BSS0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPAddWcidAttributeEntry: The BSS-index(%d) is out of range for Infra link. \n", BssIdx)); ++ return; ++ } ++ ++ // 1. In ADHOC mode, the AID is wcid number. And NO mesh link exists. ++ // 2. In Infra mode, the AID:1 MUST be wcid of infra STA. ++ // the AID:2~ assign to mesh link entry. ++ if (pEntry && ADHOC_ON(pAd)) ++ Wcid = pEntry->Aid; ++ else if (pEntry && INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry->ValidAsDls == TRUE) ++ Wcid = pEntry->Aid; ++ else ++#endif // QOS_DLS_SUPPORT // ++ Wcid = BSSID_WCID; ++ } ++ else ++ Wcid = MCAST_WCID; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // Update WCID attribute table ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pEntry && pEntry->ValidAsMesh) ++ WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; ++#ifdef QOS_DLS_SUPPORT ++ else if ((pEntry) && (pEntry->ValidAsDls) && ++ ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES) || ++ (CipherAlg == CIPHER_NONE))) ++ WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; ++#endif // QOS_DLS_SUPPORT // ++ else ++ WCIDAttri = (CipherAlg<<1) | SHAREDKEYTABLE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++ ++ ++ // Update IV/EIV table ++ offset = MAC_IVEIV_TABLE_BASE + (Wcid * HW_IVEIV_ENTRY_SIZE); ++ ++ // WPA mode ++ if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) || (CipherAlg == CIPHER_AES)) ++ { ++ // Eiv bit on. keyid always is 0 for pairwise key ++ IVEIV = (KeyIdx <<6) | 0x20; ++ } ++ else ++ { ++ // WEP KeyIdx is default tx key. ++ IVEIV = (KeyIdx << 6); ++ } ++ ++ // For key index and ext IV bit, so only need to update the position(offset+3). ++#ifdef RT2860 ++ RTMP_IO_WRITE8(pAd, offset+3, IVEIV); ++#endif // RT2860 // ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); ++ DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Parse encryption type ++Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ ========================================================================== ++*/ ++CHAR *GetEncryptType(CHAR enc) ++{ ++ if(enc == Ndis802_11WEPDisabled) ++ return "NONE"; ++ if(enc == Ndis802_11WEPEnabled) ++ return "WEP"; ++ if(enc == Ndis802_11Encryption2Enabled) ++ return "TKIP"; ++ if(enc == Ndis802_11Encryption3Enabled) ++ return "AES"; ++ if(enc == Ndis802_11Encryption4Enabled) ++ return "TKIPAES"; ++ else ++ return "UNKNOW"; ++} ++ ++CHAR *GetAuthMode(CHAR auth) ++{ ++ if(auth == Ndis802_11AuthModeOpen) ++ return "OPEN"; ++ if(auth == Ndis802_11AuthModeShared) ++ return "SHARED"; ++ if(auth == Ndis802_11AuthModeAutoSwitch) ++ return "AUTOWEP"; ++ if(auth == Ndis802_11AuthModeWPA) ++ return "WPA"; ++ if(auth == Ndis802_11AuthModeWPAPSK) ++ return "WPAPSK"; ++ if(auth == Ndis802_11AuthModeWPANone) ++ return "WPANONE"; ++ if(auth == Ndis802_11AuthModeWPA2) ++ return "WPA2"; ++ if(auth == Ndis802_11AuthModeWPA2PSK) ++ return "WPA2PSK"; ++ if(auth == Ndis802_11AuthModeWPA1WPA2) ++ return "WPA1WPA2"; ++ if(auth == Ndis802_11AuthModeWPA1PSKWPA2PSK) ++ return "WPA1PSKWPA2PSK"; ++ ++ return "UNKNOW"; ++} ++ ++#if 1 //#ifndef UCOS ++/* ++ ========================================================================== ++ Description: ++ Get site survey results ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) UI needs to wait 4 seconds after issue a site survey command ++ 2.) iwpriv ra0 get_site_survey ++ 3.) UI needs to prepare at least 4096bytes to get the results ++ ========================================================================== ++*/ ++#define LINE_LEN (4+33+20+8+10+9+7+3) // Channel+SSID+Bssid+WepStatus+AuthMode+Signal+WiressMode+NetworkType ++VOID RTMPIoctlGetSiteSurvey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *msg; ++ INT i=0; ++ INT WaitCnt; ++ INT Status=0; ++ CHAR Ssid[MAX_LEN_OF_SSID +1]; ++ INT Rssi = 0, max_len = LINE_LEN; ++ UINT Rssi_Quality = 0; ++ NDIS_802_11_NETWORK_TYPE wireless_mode; ++ ++ os_alloc_mem(NULL, (PUCHAR *)&msg, sizeof(CHAR)*((MAX_LEN_OF_BSS_TABLE)*max_len)); ++ ++ if (msg == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - msg memory alloc fail.\n")); ++ return; ++ } ++ ++ memset(msg, 0 ,(MAX_LEN_OF_BSS_TABLE)*max_len ); ++ memset(Ssid, 0 ,(MAX_LEN_OF_SSID +1)); ++ sprintf(msg,"%s","\n"); ++ sprintf(msg+strlen(msg),"%-4s%-33s%-20s%-8s%-10s%-9s%-7s%-3s\n", ++ "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", " NT"); ++ ++ WaitCnt = 0; ++#ifdef CONFIG_STA_SUPPORT ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ while ((ScanRunning(pAdapter) == TRUE) && (WaitCnt++ < 200)) ++ OS_WAIT(500); ++#endif // CONFIG_STA_SUPPORT // ++ ++ for(i=0; iScanTab.BssNr ;i++) ++ { ++ if( pAdapter->ScanTab.BssEntry[i].Channel==0) ++ break; ++ ++ if((strlen(msg)+max_len ) >= IW_SCAN_MAX_DATA) ++ break; ++ ++ //Channel ++ sprintf(msg+strlen(msg),"%-4d", pAdapter->ScanTab.BssEntry[i].Channel); ++ //SSID ++ memcpy(Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ Ssid[pAdapter->ScanTab.BssEntry[i].SsidLen] = '\0'; ++ sprintf(msg+strlen(msg),"%-33s", Ssid); ++ //BSSID ++ sprintf(msg+strlen(msg),"%02x:%02x:%02x:%02x:%02x:%02x ", ++ pAdapter->ScanTab.BssEntry[i].Bssid[0], ++ pAdapter->ScanTab.BssEntry[i].Bssid[1], ++ pAdapter->ScanTab.BssEntry[i].Bssid[2], ++ pAdapter->ScanTab.BssEntry[i].Bssid[3], ++ pAdapter->ScanTab.BssEntry[i].Bssid[4], ++ pAdapter->ScanTab.BssEntry[i].Bssid[5]); ++ //Encryption Type ++ sprintf(msg+strlen(msg),"%-8s",GetEncryptType(pAdapter->ScanTab.BssEntry[i].WepStatus)); ++ //Authentication Mode ++ if (pAdapter->ScanTab.BssEntry[i].WepStatus == Ndis802_11WEPEnabled) ++ sprintf(msg+strlen(msg),"%-10s", "UNKNOW"); ++ else ++ sprintf(msg+strlen(msg),"%-10s",GetAuthMode(pAdapter->ScanTab.BssEntry[i].AuthMode)); ++ // Rssi ++ Rssi = (INT)pAdapter->ScanTab.BssEntry[i].Rssi; ++ if (Rssi >= -50) ++ Rssi_Quality = 100; ++ else if (Rssi >= -80) // between -50 ~ -80dbm ++ Rssi_Quality = (UINT)(24 + ((Rssi + 80) * 26)/10); ++ else if (Rssi >= -90) // between -80 ~ -90dbm ++ Rssi_Quality = (UINT)(((Rssi + 90) * 26)/10); ++ else // < -84 dbm ++ Rssi_Quality = 0; ++ sprintf(msg+strlen(msg),"%-9d", Rssi_Quality); ++ // Wireless Mode ++ wireless_mode = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ if (wireless_mode == Ndis802_11FH || ++ wireless_mode == Ndis802_11DS) ++ sprintf(msg+strlen(msg),"%-7s", "11b"); ++ else if (wireless_mode == Ndis802_11OFDM5) ++ sprintf(msg+strlen(msg),"%-7s", "11a"); ++ else if (wireless_mode == Ndis802_11OFDM5_N) ++ sprintf(msg+strlen(msg),"%-7s", "11a/n"); ++ else if (wireless_mode == Ndis802_11OFDM24) ++ sprintf(msg+strlen(msg),"%-7s", "11b/g"); ++ else if (wireless_mode == Ndis802_11OFDM24_N) ++ sprintf(msg+strlen(msg),"%-7s", "11b/g/n"); ++ else ++ sprintf(msg+strlen(msg),"%-7s", "unknow"); ++ //Network Type ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_ADHOC) ++ sprintf(msg+strlen(msg),"%-3s", " Ad"); ++ else ++ sprintf(msg+strlen(msg),"%-3s", " In"); ++ ++ sprintf(msg+strlen(msg),"\n"); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - wrq->u.data.length = %d\n", wrq->u.data.length)); ++ os_free_mem(NULL, (PUCHAR)msg); ++} ++ ++ ++#define MAC_LINE_LEN (14+4+4+10+10+10+6+6) // Addr+aid+psm+datatime+rxbyte+txbyte+current tx rate+last tx rate ++VOID RTMPIoctlGetMacTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq) ++{ ++ INT i; ++ RT_802_11_MAC_TABLE MacTab; ++ char *msg; ++ ++ MacTab.Num = 0; ++ for (i=0; iMacTab.Content[i].ValidAsCLI && (pAd->MacTab.Content[i].Sst == SST_ASSOC)) ++ { ++ COPY_MAC_ADDR(MacTab.Entry[MacTab.Num].Addr, &pAd->MacTab.Content[i].Addr); ++ MacTab.Entry[MacTab.Num].Aid = (UCHAR)pAd->MacTab.Content[i].Aid; ++ MacTab.Entry[MacTab.Num].Psm = pAd->MacTab.Content[i].PsMode; ++#ifdef DOT11_N_SUPPORT ++ MacTab.Entry[MacTab.Num].MimoPs = pAd->MacTab.Content[i].MmpsMode; ++#endif // DOT11_N_SUPPORT // ++ ++ // Fill in RSSI per entry ++ MacTab.Entry[MacTab.Num].AvgRssi0 = pAd->MacTab.Content[i].RssiSample.AvgRssi0; ++ MacTab.Entry[MacTab.Num].AvgRssi1 = pAd->MacTab.Content[i].RssiSample.AvgRssi1; ++ MacTab.Entry[MacTab.Num].AvgRssi2 = pAd->MacTab.Content[i].RssiSample.AvgRssi2; ++ ++ // the connected time per entry ++ MacTab.Entry[MacTab.Num].ConnectedTime = pAd->MacTab.Content[i].StaConnectTime; ++ MacTab.Entry[MacTab.Num].TxRate.field.MCS = pAd->MacTab.Content[i].HTPhyMode.field.MCS; ++ MacTab.Entry[MacTab.Num].TxRate.field.BW = pAd->MacTab.Content[i].HTPhyMode.field.BW; ++ MacTab.Entry[MacTab.Num].TxRate.field.ShortGI = pAd->MacTab.Content[i].HTPhyMode.field.ShortGI; ++ MacTab.Entry[MacTab.Num].TxRate.field.STBC = pAd->MacTab.Content[i].HTPhyMode.field.STBC; ++ MacTab.Entry[MacTab.Num].TxRate.field.rsv = pAd->MacTab.Content[i].HTPhyMode.field.rsv; ++ MacTab.Entry[MacTab.Num].TxRate.field.MODE = pAd->MacTab.Content[i].HTPhyMode.field.MODE; ++ MacTab.Entry[MacTab.Num].TxRate.word = pAd->MacTab.Content[i].HTPhyMode.word; ++ ++ MacTab.Num += 1; ++ } ++ } ++ wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE); ++ if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); ++ } ++ ++ msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG); ++ memset(msg, 0 ,MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN ); ++ sprintf(msg,"%s","\n"); ++ sprintf(msg+strlen(msg),"%-14s%-4s%-4s%-10s%-10s%-10s%-6s%-6s\n", ++ "MAC", "AID", "PSM", "LDT", "RxB", "TxB","CTxR", "LTxR"); ++ ++ for (i=0; iMacTab.Content[i]; ++ if (pEntry->ValidAsCLI && (pEntry->Sst == SST_ASSOC)) ++ { ++ if((strlen(msg)+MAC_LINE_LEN ) >= (MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN) ) ++ break; ++ sprintf(msg+strlen(msg),"%02x%02x%02x%02x%02x%02x ", ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ sprintf(msg+strlen(msg),"%-4d", (int)pEntry->Aid); ++ sprintf(msg+strlen(msg),"%-4d", (int)pEntry->PsMode); ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.LastDataPacketTime*/); // ToDo ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalRxByteCount*/); // ToDo ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalTxByteCount*/); // ToDo ++ sprintf(msg+strlen(msg),"%-6d",RateIdToMbps[pAd->MacTab.Content[i].CurrTxRate]); ++ sprintf(msg+strlen(msg),"%-6d\n",0/*RateIdToMbps[pAd->MacTab.Content[i].LastTxRate]*/); // ToDo ++ } ++ } ++ // for compatible with old API just do the printk to console ++ //wrq->u.data.length = strlen(msg); ++ //if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s", msg)); ++ } ++ ++ kfree(msg); ++} ++#endif // UCOS // ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_BASetup_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++/* ++ The BASetup inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ //printk("\n%s\n", arg); ++ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > 15) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x\n", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nSetup BA Session: Tid = %d\n", tid); ++ BAOriSessionSetUp(pAd, pEntry, tid, 0, 100, TRUE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_BADecline_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG bBADecline; ++ ++ bBADecline = simple_strtol(arg, 0, 10); ++ ++ if (bBADecline == 0) ++ { ++ pAd->CommonCfg.bBADecline = FALSE; ++ } ++ else if (bBADecline == 1) ++ { ++ pAd->CommonCfg.bBADecline = TRUE; ++ } ++ else ++ { ++ return FALSE; //Invalid argument ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_BADecline_Proc::(BADecline=%d)\n", pAd->CommonCfg.bBADecline)); ++ ++ return TRUE; ++} ++ ++INT Set_BAOriTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++/* ++ The BAOriTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > NUM_OF_TID) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nTear down Ori BA Session: Tid = %d\n", tid); ++ BAOriSessionTearDown(pAd, pEntry->Aid, tid, FALSE, TRUE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_BARecTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > NUM_OF_TID) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nTear down Rec BA Session: Tid = %d\n", tid); ++ BARecSessionTearDown(pAd, pEntry->Aid, tid, FALSE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtBw; ++ ++ HtBw = simple_strtol(arg, 0, 10); ++ if (HtBw == BW_40) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ else if (HtBw == BW_20) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBw_Proc::(HtBw=%d)\n", pAd->CommonCfg.RegTransmitSetting.field.BW)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtMcs, Mcs_tmp; ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN bAutoRate = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ Mcs_tmp = simple_strtol(arg, 0, 10); ++ ++ if (Mcs_tmp <= 15 || Mcs_tmp == 32) ++ HtMcs = Mcs_tmp; ++ else ++ HtMcs = MCS_AUTO; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = HtMcs; ++ pAd->StaCfg.bAutoTxRateSwitch = (HtMcs == MCS_AUTO) ? TRUE:FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(HtMcs=%d, bAutoTxRateSwitch = %d)\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS, pAd->StaCfg.bAutoTxRateSwitch)); ++ ++ if ((pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE < MODE_HTMIX)) ++ { ++ if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && ++ (HtMcs >= 0 && HtMcs <= 3) && ++ (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_CCK)) ++ { ++ RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs] * 1000000)); ++ } ++ else if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && ++ (HtMcs >= 0 && HtMcs <= 7) && ++ (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_OFDM)) ++ { ++ RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs+4] * 1000000)); ++ } ++ else ++ bAutoRate = TRUE; ++ ++ if (bAutoRate) ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ RTMPSetDesiredRates(pAd, -1); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(FixedTxMode=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode)); ++ } ++ if (ADHOC_ON(pAd)) ++ return TRUE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ SetCommonHT(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtGi; ++ ++ HtGi = simple_strtol(arg, 0, 10); ++ ++ if ( HtGi == GI_400) ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; ++ else if ( HtGi == GI_800 ) ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtGi_Proc::(ShortGI=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.ShortGI)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_HtTxBASize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR Size; ++ ++ Size = simple_strtol(arg, 0, 10); ++ ++ if (Size <=0 || Size >=64) ++ { ++ Size = 8; ++ } ++ pAd->CommonCfg.TxBASize = Size-1; ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_HtTxBASize ::(TxBASize= %d)\n", Size)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == HTMODE_GF) ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; ++ else if ( Value == HTMODE_MM ) ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtOpMode_Proc::(HtOpMode=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.HTMODE)); ++ ++ return TRUE; ++ ++} ++ ++INT Set_HtStbc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == STBC_USE) ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; ++ else if ( Value == STBC_NONE ) ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Stbc_Proc::(HtStbc=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.STBC)); ++ ++ return TRUE; ++} ++ ++INT Set_HtHtc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->HTCEnable = FALSE; ++ else if ( Value ==1 ) ++ pAd->HTCEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtHtc_Proc::(HtHtc=%d)\n",pAd->HTCEnable)); ++ ++ return TRUE; ++} ++ ++INT Set_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == 0) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ else if ( Value ==1 ) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtExtcha_Proc::(HtExtcha=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.EXTCHA)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value <=7 && Value >= 0) ++ pAd->CommonCfg.BACapability.field.MpduDensity = Value; ++ else ++ pAd->CommonCfg.BACapability.field.MpduDensity = 4; ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMpduDensity_Proc::(HtMpduDensity=%d)\n",pAd->CommonCfg.BACapability.field.MpduDensity)); ++ ++ return TRUE; ++} ++ ++INT Set_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ ++ if (Value >=1 && Value <= 64) ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; ++ } ++ else ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; ++ } ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBaWinSize_Proc::(HtBaWinSize=%d)\n",pAd->CommonCfg.BACapability.field.RxBAWinLimit)); ++ ++ return TRUE; ++} ++ ++INT Set_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == 0) ++ pAd->CommonCfg.bRdg = FALSE; ++ else if ( Value ==1 ) ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->CommonCfg.bRdg = TRUE; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtRdg_Proc::(HtRdg=%d)\n",pAd->CommonCfg.bRdg)); ++ ++ return TRUE; ++} ++ ++INT Set_HtLinkAdapt_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->bLinkAdapt = FALSE; ++ else if ( Value ==1 ) ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->bLinkAdapt = TRUE; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtLinkAdapt_Proc::(HtLinkAdapt=%d)\n",pAd->bLinkAdapt)); ++ ++ return TRUE; ++} ++ ++INT Set_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; ++ else if ( Value == 1 ) ++ pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAmsdu_Proc::(HtAmsdu=%d)\n",pAd->CommonCfg.BACapability.field.AmsduEnable)); ++ ++ return TRUE; ++} ++ ++INT Set_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAutoBa_Proc::(HtAutoBa=%d)\n",pAd->CommonCfg.BACapability.field.AutoBA)); ++ ++ return TRUE; ++ ++} ++ ++INT Set_HtProtect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.bHTProtect = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.bHTProtect = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtProtect_Proc::(HtProtect=%d)\n",pAd->CommonCfg.bHTProtect)); ++ ++ return TRUE; ++} ++ ++INT Set_SendPSMPAction_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], mode; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the mode value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and mode value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ mode = simple_strtol((token+1), 0, 10); ++ if (mode > MMPS_ENABLE) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], mode); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nSendPSMPAction MIPS mode = %d\n", mode); ++ SendPSMPAction(pAd, pEntry->Aid, mode); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++ ++} ++ ++INT Set_HtMIMOPSmode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value <=3 && Value >= 0) ++ pAd->CommonCfg.BACapability.field.MMPSmode = Value; ++ else ++ pAd->CommonCfg.BACapability.field.MMPSmode = 3; ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMIMOPSmode_Proc::(MIMOPS mode=%d)\n",pAd->CommonCfg.BACapability.field.MMPSmode)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_ForceShortGI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->WIFItestbed.bShortGI = FALSE; ++ else if (Value == 1) ++ pAd->WIFItestbed.bShortGI = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceShortGI_Proc::(ForceShortGI=%d)\n", pAd->WIFItestbed.bShortGI)); ++ ++ return TRUE; ++} ++ ++ ++ ++INT Set_ForceGF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->WIFItestbed.bGreenField = FALSE; ++ else if (Value == 1) ++ pAd->WIFItestbed.bGreenField = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceGF_Proc::(ForceGF=%d)\n", pAd->WIFItestbed.bGreenField)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMimoPs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.bMIMOPSEnable = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMimoPs_Proc::(HtMimoPs=%d)\n",pAd->CommonCfg.bMIMOPSEnable)); ++ ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++INT SetCommonHT( ++ IN PRTMP_ADAPTER pAd) ++{ ++ OID_SET_HT_PHYMODE SetHT; ++ ++ if (pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) ++ return FALSE; ++ ++ SetHT.PhyMode = pAd->CommonCfg.PhyMode; ++ SetHT.TransmitNo = ((UCHAR)pAd->Antenna.field.TxPath); ++ SetHT.HtMode = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.HTMODE; ++ SetHT.ExtOffset = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; ++ SetHT.MCS = MCS_AUTO; ++ SetHT.BW = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.BW; ++ SetHT.STBC = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.STBC; ++ SetHT.SHORTGI = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.ShortGI; ++ ++ RTMPSetHT(pAd, &SetHT); ++ ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_FixedTxMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR fix_tx_mode = FIXED_TXMODE_HT; ++ ++ if (strcmp(arg, "OFDM") == 0 || strcmp(arg, "ofdm") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_OFDM; ++ } ++ else if (strcmp(arg, "CCK") == 0 || strcmp(arg, "cck") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_CCK; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_FixedTxMode_Proc::(FixedTxMode=%d)\n", fix_tx_mode)); ++ ++ return TRUE; ++} ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++INT Set_OpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++#ifdef RT2860 ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++#endif // RT2860 // ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); ++ return FALSE; ++ } ++ ++ if (Value == 0) ++ pAd->OpMode = OPMODE_STA; ++ else if (Value == 1) ++ pAd->OpMode = OPMODE_AP; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_OpMode_Proc::(OpMode=%s)\n", pAd->OpMode == 1 ? "AP Mode" : "STA Mode")); ++ ++ return TRUE; ++} ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++ ++///////////////////////////////////////////////////////////////////////// ++PCHAR RTMPGetRalinkAuthModeStr( ++ IN NDIS_802_11_AUTHENTICATION_MODE authMode) ++{ ++ switch(authMode) ++ { ++ case Ndis802_11AuthModeOpen: ++ return "OPEN"; ++ default: ++ case Ndis802_11AuthModeWPAPSK: ++ return "WPAPSK"; ++ case Ndis802_11AuthModeShared: ++ return "SHARED"; ++ case Ndis802_11AuthModeWPA: ++ return "WPA"; ++ case Ndis802_11AuthModeWPA2: ++ return "WPA2"; ++ case Ndis802_11AuthModeWPA2PSK: ++ return "WPA2PSK"; ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ return "WPAPSKWPA2PSK"; ++ case Ndis802_11AuthModeWPA1WPA2: ++ return "WPA1WPA2"; ++ case Ndis802_11AuthModeWPANone: ++ return "WPANONE"; ++ } ++} ++ ++PCHAR RTMPGetRalinkEncryModeStr( ++ IN USHORT encryMode) ++{ ++ switch(encryMode) ++ { ++ default: ++ case Ndis802_11WEPDisabled: ++ return "NONE"; ++ case Ndis802_11WEPEnabled: ++ return "WEP"; ++ case Ndis802_11Encryption2Enabled: ++ return "TKIP"; ++ case Ndis802_11Encryption3Enabled: ++ return "AES"; ++ case Ndis802_11Encryption4Enabled: ++ return "TKIPAES"; ++ } ++} ++ ++INT RTMPShowCfgValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pName, ++ IN PUCHAR pBuf) ++{ ++ INT Status = 0; ++ ++ for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) ++ { ++ if (!strcmp(pName, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name)) ++ { ++ if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->show_proc(pAd, pBuf)) ++ Status = -EINVAL; ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name == NULL) ++ { ++ sprintf(pBuf, "\n"); ++ for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) ++ sprintf(pBuf, "%s%s\n", pBuf, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); ++ } ++ ++ return Status; ++} ++ ++INT Show_SSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); ++#endif // CONFIG_STA_SUPPORT // ++ return 0; ++} ++ ++INT Show_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11BG_MIXED: ++ sprintf(pBuf, "\t11B/G"); ++ break; ++ case PHY_11B: ++ sprintf(pBuf, "\t11B"); ++ break; ++ case PHY_11A: ++ sprintf(pBuf, "\t11A"); ++ break; ++ case PHY_11ABG_MIXED: ++ sprintf(pBuf, "\t11A/B/G"); ++ break; ++ case PHY_11G: ++ sprintf(pBuf, "\t11G"); ++ break; ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++ sprintf(pBuf, "\t11A/B/G/N"); ++ break; ++ case PHY_11N_2_4G: ++ sprintf(pBuf, "\t11N only with 2.4G"); ++ break; ++ case PHY_11GN_MIXED: ++ sprintf(pBuf, "\t11G/N"); ++ break; ++ case PHY_11AN_MIXED: ++ sprintf(pBuf, "\t11A/N"); ++ break; ++ case PHY_11BGN_MIXED: ++ sprintf(pBuf, "\t11B/G/N"); ++ break; ++ case PHY_11AGN_MIXED: ++ sprintf(pBuf, "\t11A/G/N"); ++ break; ++ case PHY_11N_5G: ++ sprintf(pBuf, "\t11N only with 5G"); ++ break; ++#endif // DOT11_N_SUPPORT // ++ default: ++ sprintf(pBuf, "\tUnknow Value(%d)", pAd->CommonCfg.PhyMode); ++ break; ++ } ++ return 0; ++} ++ ++ ++INT Show_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bEnableTxBurst ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.TxPreamble) ++ { ++ case Rt802_11PreambleShort: ++ sprintf(pBuf, "\tShort"); ++ break; ++ case Rt802_11PreambleLong: ++ sprintf(pBuf, "\tLong"); ++ break; ++ case Rt802_11PreambleAuto: ++ sprintf(pBuf, "\tAuto"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.TxPreamble); ++ break; ++ } ++ ++ return 0; ++} ++ ++INT Show_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%lu", pAd->CommonCfg.TxPowerPercentage); ++ return 0; ++} ++ ++INT Show_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.Channel); ++ return 0; ++} ++ ++INT Show_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.UseBGProtection) ++ { ++ case 1: //Always On ++ sprintf(pBuf, "\tON"); ++ break; ++ case 2: //Always OFF ++ sprintf(pBuf, "\tOFF"); ++ break; ++ case 0: //AUTO ++ sprintf(pBuf, "\tAuto"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.UseBGProtection); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.RtsThreshold); ++ return 0; ++} ++ ++INT Show_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.FragmentThreshold); ++ return 0; ++} ++ ++#ifdef DOT11_N_SUPPORT ++INT Show_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ sprintf(pBuf, "\t40 MHz"); ++ } ++ else ++ { ++ sprintf(pBuf, "\t20 MHz"); ++ } ++ return 0; ++} ++ ++INT Show_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++#endif // CONFIG_STA_SUPPORT // ++ return 0; ++} ++ ++INT Show_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.ShortGI) ++ { ++ case GI_400: ++ sprintf(pBuf, "\tGI_400"); ++ break; ++ case GI_800: ++ sprintf(pBuf, "\tGI_800"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.ShortGI); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.HTMODE) ++ { ++ case HTMODE_GF: ++ sprintf(pBuf, "\tGF"); ++ break; ++ case HTMODE_MM: ++ sprintf(pBuf, "\tMM"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.HTMODE); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.EXTCHA) ++ { ++ case EXTCHA_BELOW: ++ sprintf(pBuf, "\tBelow"); ++ break; ++ case EXTCHA_ABOVE: ++ sprintf(pBuf, "\tAbove"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.EXTCHA); ++ break; ++ } ++ return 0; ++} ++ ++ ++INT Show_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.MpduDensity); ++ return 0; ++} ++ ++INT Show_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ return 0; ++} ++ ++INT Show_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bRdg ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AmsduEnable ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AutoBA ? "TRUE":"FALSE"); ++ return 0; ++} ++#endif // DOT11_N_SUPPORT // ++ ++INT Show_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegion); ++ return 0; ++} ++ ++INT Show_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegionForABand); ++ return 0; ++} ++ ++INT Show_CountryCode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.CountryCode); ++ return 0; ++} ++ ++#ifdef AGGREGATION_SUPPORT ++INT Show_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bAggregationCapable ? "TRUE":"FALSE"); ++ return 0; ++} ++#endif // AGGREGATION_SUPPORT // ++ ++#ifdef WMM_SUPPORT ++INT Show_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); ++#endif // CONFIG_STA_SUPPORT // ++ ++ return 0; ++} ++#endif // WMM_SUPPORT // ++ ++INT Show_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bIEEE80211H ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++INT Show_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->StaCfg.BssType) ++ { ++ case BSS_ADHOC: ++ sprintf(pBuf, "\tAdhoc"); ++ break; ++ case BSS_INFRA: ++ sprintf(pBuf, "\tInfra"); ++ break; ++ case BSS_ANY: ++ sprintf(pBuf, "\tAny"); ++ break; ++ case BSS_MONITOR: ++ sprintf(pBuf, "\tMonitor"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%d)", pAd->StaCfg.BssType); ++ break; ++ } ++ return 0; ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Show_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeOpen; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AuthMode = pAd->StaCfg.AuthMode; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((AuthMode >= Ndis802_11AuthModeOpen) && ++ (AuthMode <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ sprintf(pBuf, "\t%s", RTMPGetRalinkAuthModeStr(AuthMode)); ++ else ++ sprintf(pBuf, "\tUnknow Value(%d)", AuthMode); ++ ++ return 0; ++} ++ ++INT Show_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ NDIS_802_11_WEP_STATUS WepStatus = Ndis802_11WEPDisabled; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ WepStatus = pAd->StaCfg.WepStatus; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((WepStatus >= Ndis802_11WEPEnabled) && ++ (WepStatus <= Ndis802_11Encryption4KeyAbsent)) ++ sprintf(pBuf, "\t%s", RTMPGetRalinkEncryModeStr(WepStatus)); ++ else ++ sprintf(pBuf, "\tUnknow Value(%d)", WepStatus); ++ ++ return 0; ++} ++ ++INT Show_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ UCHAR DefaultKeyId = 0; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ DefaultKeyId = pAd->StaCfg.DefaultKeyId; ++#endif // CONFIG_STA_SUPPORT // ++ ++ sprintf(pBuf, "\t%d", DefaultKeyId); ++ ++ return 0; ++} ++ ++INT Show_WepKey_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN INT KeyIdx, ++ OUT PUCHAR pBuf) ++{ ++ UCHAR Key[16] = {0}, KeyLength = 0; ++ INT index = BSS0; ++ ++ KeyLength = pAd->SharedKey[index][KeyIdx].KeyLen; ++ NdisMoveMemory(Key, pAd->SharedKey[index][KeyIdx].Key, KeyLength); ++ ++ //check key string is ASCII or not ++ if (RTMPCheckStrPrintAble(Key, KeyLength)) ++ sprintf(pBuf, "\t%s", Key); ++ else ++ { ++ int idx; ++ sprintf(pBuf, "\t"); ++ for (idx = 0; idx < KeyLength; idx++) ++ sprintf(pBuf+strlen(pBuf), "%02X", Key[idx]); ++ } ++ return 0; ++} ++ ++INT Show_Key1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 0, pBuf); ++ return 0; ++} ++ ++INT Show_Key2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 1, pBuf); ++ return 0; ++} ++ ++INT Show_Key3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 2, pBuf); ++ return 0; ++} ++ ++INT Show_Key4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 3, pBuf); ++ return 0; ++} ++ ++INT Show_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ INT idx; ++ UCHAR PMK[32] = {0}; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); ++#endif // CONFIG_STA_SUPPORT // ++ ++ sprintf(pBuf, "\tPMK = "); ++ for (idx = 0; idx < 32; idx++) ++ sprintf(pBuf+strlen(pBuf), "%02X", PMK[idx]); ++ ++ return 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/cmm_sanity.c +@@ -0,0 +1,1633 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sanity.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 add WMM support ++*/ ++#include "../rt_config.h" ++ ++ ++extern UCHAR CISCO_OUI[]; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR BROADCOM_OUI[]; ++extern UCHAR WPS_OUI[]; ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeAddBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2) ++{ ++ PMLME_ADDBA_REQ_STRUCT pInfo; ++ ++ pInfo = (MLME_ADDBA_REQ_STRUCT *)Msg; ++ ++ if ((MsgLen != sizeof(MLME_ADDBA_REQ_STRUCT))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - The peer Mac is not associated yet.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->pAddr[0]&0x01) == 0x01) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - broadcast address not support BA\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeDelBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen) ++{ ++ MLME_DELBA_REQ_STRUCT *pInfo; ++ pInfo = (MLME_DELBA_REQ_STRUCT *)Msg; ++ ++ if ((MsgLen != sizeof(MLME_DELBA_REQ_STRUCT))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer Mac is not associated yet.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->TID & 0xf0)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer TID is incorrect.\n")); ++ return FALSE; ++ } ++ ++ if (NdisEqualMemory(pAd->MacTab.Content[pInfo->Wcid].Addr, pInfo->Addr, MAC_ADDR_LEN) == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - the peer addr dosen't exist.\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerAddBAReqActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_ADDBA_REQ pAddFrame; ++ pAddFrame = (PFRAME_ADDBA_REQ)(pMsg); ++ if (MsgLen < (sizeof(FRAME_ADDBA_REQ))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ // we support immediate BA. ++ *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); ++ pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); ++ pAddFrame->BaStartSeq.word = cpu2le16(pAddFrame->BaStartSeq.word); ++ ++ if (pAddFrame->BaParm.BAPolicy != IMMED_BA) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); ++ DBGPRINT(RT_DEBUG_ERROR,("ADDBA Request. tid=%x, Bufsize=%x, AMSDUSupported=%x \n", pAddFrame->BaParm.TID, pAddFrame->BaParm.BufSize, pAddFrame->BaParm.AMSDUSupported)); ++ return FALSE; ++ } ++ ++ // we support immediate BA. ++ if (pAddFrame->BaParm.TID &0xfff0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request incorrect TID = %d\n", pAddFrame->BaParm.TID)); ++ return FALSE; ++ } ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ return TRUE; ++} ++ ++BOOLEAN PeerAddBARspActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen) ++{ ++ PFRAME_ADDBA_RSP pAddFrame; ++ ++ pAddFrame = (PFRAME_ADDBA_RSP)(pMsg); ++ if (MsgLen < (sizeof(FRAME_ADDBA_RSP))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ // we support immediate BA. ++ *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); ++ pAddFrame->StatusCode = cpu2le16(pAddFrame->StatusCode); ++ pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); ++ ++ if (pAddFrame->BaParm.BAPolicy != IMMED_BA) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Response Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); ++ return FALSE; ++ } ++ ++ // we support immediate BA. ++ if (pAddFrame->BaParm.TID &0xfff0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response incorrect TID = %d\n", pAddFrame->BaParm.TID)); ++ return FALSE; ++ } ++ return TRUE; ++ ++} ++ ++BOOLEAN PeerDelBAActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN VOID *pMsg, ++ IN ULONG MsgLen ) ++{ ++ //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_DELBA_REQ pDelFrame; ++ if (MsgLen != (sizeof(FRAME_DELBA_REQ))) ++ return FALSE; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ pDelFrame = (PFRAME_DELBA_REQ)(pMsg); ++ ++ *(USHORT *)(&pDelFrame->DelbaParm) = cpu2le16(*(USHORT *)(&pDelFrame->DelbaParm)); ++ pDelFrame->ReasonCode = cpu2le16(pDelFrame->ReasonCode); ++ ++ if (pDelFrame->DelbaParm.TID &0xfff0) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgChannel, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pBssType, ++ OUT USHORT *pBeaconPeriod, ++ OUT UCHAR *pChannel, ++ OUT UCHAR *pNewChannel, ++ OUT LARGE_INTEGER *pTimestamp, ++ OUT CF_PARM *pCfParm, ++ OUT USHORT *pAtimWin, ++ OUT USHORT *pCapabilityInfo, ++ OUT UCHAR *pErp, ++ OUT UCHAR *pDtimCount, ++ OUT UCHAR *pDtimPeriod, ++ OUT UCHAR *pBcastFlag, ++ OUT UCHAR *pMessageToMe, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT UCHAR *pCkipFlag, ++ OUT UCHAR *pAironetCellPowerLimit, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT PQBSS_LOAD_PARM pQbssLoad, ++ OUT PQOS_CAPABILITY_PARM pQosCapability, ++ OUT ULONG *pRalinkIe, ++ OUT UCHAR *pHtCapabilityLen, ++#ifdef CONFIG_STA_SUPPORT ++ OUT UCHAR *pPreNHtCapabilityLen, ++#endif // CONFIG_STA_SUPPORT // ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT UCHAR *AddHtInfoLen, ++ OUT ADD_HT_INFO_IE *AddHtInfo, ++ OUT UCHAR *NewExtChannelOffset, // Ht extension channel offset(above or below) ++ OUT USHORT *LengthVIE, ++ OUT PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ CHAR *Ptr; ++#ifdef CONFIG_STA_SUPPORT ++ CHAR TimLen; ++#endif // CONFIG_STA_SUPPORT // ++ PFRAME_802_11 pFrame; ++ PEID_STRUCT pEid; ++ UCHAR SubType; ++ UCHAR Sanity; ++ //UCHAR ECWMin, ECWMax; ++ //MAC_CSR9_STRUC Csr9; ++ ULONG Length = 0; ++ ++ // For some 11a AP which didn't have DS_IE, we use two conditions to decide the channel ++ // 1. If the AP is 11n enabled, then check the control channel. ++ // 2. If the AP didn't have any info about channel, use the channel we received this frame as the channel. (May inaccuracy!!) ++ UCHAR CtrlChannel = 0; ++ ++ // Add for 3 necessary EID field check ++ Sanity = 0; ++ ++ *pAtimWin = 0; ++ *pErp = 0; ++ *pDtimCount = 0; ++ *pDtimPeriod = 0; ++ *pBcastFlag = 0; ++ *pMessageToMe = 0; ++ *pExtRateLen = 0; ++ *pCkipFlag = 0; // Default of CkipFlag is 0 ++ *pAironetCellPowerLimit = 0xFF; // Default of AironetCellPowerLimit is 0xFF ++ *LengthVIE = 0; // Set the length of VIE to init value 0 ++ *pHtCapabilityLen = 0; // Set the length of VIE to init value 0 ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ *pPreNHtCapabilityLen = 0; // Set the length of VIE to init value 0 ++#endif // CONFIG_STA_SUPPORT // ++ *AddHtInfoLen = 0; // Set the length of VIE to init value 0 ++ *pRalinkIe = 0; ++ *pNewChannel = 0; ++ *NewExtChannelOffset = 0xff; //Default 0xff means no such IE ++ pCfParm->bValid = FALSE; // default: no IE_CF found ++ pQbssLoad->bValid = FALSE; // default: no IE_QBSS_LOAD found ++ pEdcaParm->bValid = FALSE; // default: no IE_EDCA_PARAMETER found ++ pQosCapability->bValid = FALSE; // default: no IE_QOS_CAPABILITY found ++ ++ pFrame = (PFRAME_802_11)Msg; ++ ++ // get subtype from header ++ SubType = (UCHAR)pFrame->Hdr.FC.SubType; ++ ++ // get Addr2 and BSSID from header ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ COPY_MAC_ADDR(pBssid, pFrame->Hdr.Addr3); ++ ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ // get timestamp from payload and advance the pointer ++ NdisMoveMemory(pTimestamp, Ptr, TIMESTAMP_LEN); ++ ++ pTimestamp->u.LowPart = cpu2le32(pTimestamp->u.LowPart); ++ pTimestamp->u.HighPart = cpu2le32(pTimestamp->u.HighPart); ++ ++ Ptr += TIMESTAMP_LEN; ++ Length += TIMESTAMP_LEN; ++ ++ // get beacon interval from payload and advance the pointer ++ NdisMoveMemory(pBeaconPeriod, Ptr, 2); ++ Ptr += 2; ++ Length += 2; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ Length += 2; ++ ++ if (CAP_IS_ESS_ON(*pCapabilityInfo)) ++ *pBssType = BSS_INFRA; ++ else ++ *pBssType = BSS_ADHOC; ++ ++ pEid = (PEID_STRUCT) Ptr; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ // ++ // Secure copy VIE to VarIE[MAX_VIE_LEN] didn't overflow. ++ // ++ if ((*LengthVIE + pEid->Len + 2) >= MAX_VIE_LEN) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - Variable IEs out of resource [len(=%d) > MAX_VIE_LEN(=%d)]\n", ++ (*LengthVIE + pEid->Len + 2), MAX_VIE_LEN)); ++ break; ++ } ++ ++ switch(pEid->Eid) ++ { ++ case IE_SSID: ++ // Already has one SSID EID in this beacon, ignore the second one ++ if (Sanity & 0x1) ++ break; ++ if(pEid->Len <= MAX_LEN_OF_SSID) ++ { ++ NdisMoveMemory(Ssid, pEid->Octet, pEid->Len); ++ *pSsidLen = pEid->Len; ++ Sanity |= 0x1; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_SUPP_RATES: ++ if(pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ Sanity |= 0x2; ++ NdisMoveMemory(SupRate, pEid->Octet, pEid->Len); ++ *pSupRateLen = pEid->Len; ++ ++ // TODO: 2004-09-14 not a good design here, cause it exclude extra rates ++ // from ScanTab. We should report as is. And filter out unsupported ++ // rates in MlmeAux. ++ // Check against the supported rates ++ // RTMPCheckRates(pAd, SupRate, pSupRateLen); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! ++ { ++ NdisMoveMemory(pHtCapability, pEid->Octet, sizeof(HT_CAPABILITY_IE)); ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ *pPreNHtCapabilityLen = 0; // Nnow we only support 26 bytes. ++ ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_HT_CAP. pEid->Len = %d\n", pEid->Len)); ++ } ++ ++ break; ++ case IE_ADD_HT: ++ if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) ++ { ++ // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only ++ // copy first sizeof(ADD_HT_INFO_IE) ++ NdisMoveMemory(AddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ ++ CtrlChannel = AddHtInfo->ControlChan; ++ ++ *(USHORT *)(&AddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo2)); ++ *(USHORT *)(&AddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo3)); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_ADD_HT. \n")); ++ } ++ ++ break; ++ case IE_SECONDARY_CH_OFFSET: ++ if (pEid->Len == 1) ++ { ++ *NewExtChannelOffset = pEid->Octet[0]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); ++ } ++ ++ break; ++ case IE_FH_PARM: ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n")); ++ break; ++ ++ case IE_DS_PARM: ++ if(pEid->Len == 1) ++ { ++ *pChannel = *pEid->Octet; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ChannelSanity(pAd, *pChannel) == 0) ++ { ++ ++ return FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ Sanity |= 0x4; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_CF_PARM: ++ if(pEid->Len == 6) ++ { ++ pCfParm->bValid = TRUE; ++ pCfParm->CfpCount = pEid->Octet[0]; ++ pCfParm->CfpPeriod = pEid->Octet[1]; ++ pCfParm->CfpMaxDuration = pEid->Octet[2] + 256 * pEid->Octet[3]; ++ pCfParm->CfpDurRemaining = pEid->Octet[4] + 256 * pEid->Octet[5]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n")); ++ return FALSE; ++ } ++ break; ++ ++ case IE_IBSS_PARM: ++ if(pEid->Len == 2) ++ { ++ NdisMoveMemory(pAtimWin, pEid->Octet, pEid->Len); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_IBSS_PARM\n")); ++ return FALSE; ++ } ++ break; ++ ++#ifdef CONFIG_STA_SUPPORT ++ case IE_TIM: ++ if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) ++ { ++ GetTimBit((PUCHAR)pEid, pAd->StaActive.Aid, &TimLen, pBcastFlag, pDtimCount, pDtimPeriod, pMessageToMe); ++ } ++ break; ++#endif // CONFIG_STA_SUPPORT // ++ case IE_CHANNEL_SWITCH_ANNOUNCEMENT: ++ if(pEid->Len == 3) ++ { ++ *pNewChannel = pEid->Octet[1]; //extract new channel number ++ } ++ break; ++ ++ // New for WPA ++ // CCX v2 has the same IE, we need to parse that too ++ // Wifi WMM use the same IE vale, need to parse that too ++ // case IE_WPA: ++ case IE_VENDOR_SPECIFIC: ++ // Check the OUI version, filter out non-standard usage ++ if (NdisEqualMemory(pEid->Octet, RALINK_OUI, 3) && (pEid->Len == 7)) ++ { ++ //*pRalinkIe = pEid->Octet[3]; ++ if (pEid->Octet[3] != 0) ++ *pRalinkIe = pEid->Octet[3]; ++ else ++ *pRalinkIe = 0xf0000000; // Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. ++ } ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++ // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. ++ ++ // Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, ++ // Check broadcom-defiend pre-802.11nD1.0 OUI for HT related IE, including HT Capatilities IE and HT Information IE ++ else if ((*pHtCapabilityLen == 0) && NdisEqualMemory(pEid->Octet, PRE_N_HT_OUI, 3) && (pEid->Len >= 4) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if ((pEid->Octet[3] == OUI_PREN_HT_CAP) && (pEid->Len >= 30) && (*pHtCapabilityLen == 0)) ++ { ++ NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); ++ *pPreNHtCapabilityLen = SIZE_HT_CAP_IE; ++ } ++ ++ if ((pEid->Octet[3] == OUI_PREN_ADD_HT) && (pEid->Len >= 26)) ++ { ++ NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ { ++ // Copy to pVIE which will report to microsoft bssid list. ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++ else if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) ++ { ++ PUCHAR ptr; ++ int i; ++ ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ptr = &pEid->Octet[8]; ++ for (i=0; i<4; i++) ++ { ++ UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX ++ pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM ++ pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN ++ pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin ++ pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax ++ pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us ++ ptr += 4; // point to next AC ++ } ++ } ++ else if (NdisEqualMemory(pEid->Octet, WME_INFO_ELEM, 6) && (pEid->Len == 7)) ++ { ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ++ // use default EDCA parameter ++ pEdcaParm->bACM[QID_AC_BE] = 0; ++ pEdcaParm->Aifsn[QID_AC_BE] = 3; ++ pEdcaParm->Cwmin[QID_AC_BE] = CW_MIN_IN_BITS; ++ pEdcaParm->Cwmax[QID_AC_BE] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_BE] = 0; ++ ++ pEdcaParm->bACM[QID_AC_BK] = 0; ++ pEdcaParm->Aifsn[QID_AC_BK] = 7; ++ pEdcaParm->Cwmin[QID_AC_BK] = CW_MIN_IN_BITS; ++ pEdcaParm->Cwmax[QID_AC_BK] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_BK] = 0; ++ ++ pEdcaParm->bACM[QID_AC_VI] = 0; ++ pEdcaParm->Aifsn[QID_AC_VI] = 2; ++ pEdcaParm->Cwmin[QID_AC_VI] = CW_MIN_IN_BITS-1; ++ pEdcaParm->Cwmax[QID_AC_VI] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_VI] = 96; // AC_VI: 96*32us ~= 3ms ++ ++ pEdcaParm->bACM[QID_AC_VO] = 0; ++ pEdcaParm->Aifsn[QID_AC_VO] = 2; ++ pEdcaParm->Cwmin[QID_AC_VO] = CW_MIN_IN_BITS-2; ++ pEdcaParm->Cwmax[QID_AC_VO] = CW_MAX_IN_BITS-1; ++ pEdcaParm->Txop[QID_AC_VO] = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); ++ *pExtRateLen = pEid->Len; ++ ++ // TODO: 2004-09-14 not a good design here, cause it exclude extra rates ++ // from ScanTab. We should report as is. And filter out unsupported ++ // rates in MlmeAux. ++ // Check against the supported rates ++ // RTMPCheckRates(pAd, ExtRate, pExtRateLen); ++ } ++ break; ++ ++ case IE_ERP: ++ if (pEid->Len == 1) ++ { ++ *pErp = (UCHAR)pEid->Octet[0]; ++ } ++ break; ++ ++ case IE_AIRONET_CKIP: ++ // 0. Check Aironet IE length, it must be larger or equal to 28 ++ // Cisco AP350 used length as 28 ++ // Cisco AP12XX used length as 30 ++ if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) ++ break; ++ ++ // 1. Copy CKIP flag byte to buffer for process ++ *pCkipFlag = *(pEid->Octet + 8); ++ break; ++ ++ case IE_AP_TX_POWER: ++ // AP Control of Client Transmit Power ++ //0. Check Aironet IE length, it must be 6 ++ if (pEid->Len != 0x06) ++ break; ++ ++ // Get cell power limit in dBm ++ if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) ++ *pAironetCellPowerLimit = *(pEid->Octet + 4); ++ break; ++ ++ // WPA2 & 802.11i RSN ++ case IE_RSN: ++ // There is no OUI for version anymore, check the group cipher OUI before copying ++ if (RTMPEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ { ++ // Copy to pVIE which will report to microsoft bssid list. ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++ break; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ case IE_COUNTRY: ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ break; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ ++ default: ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ // For some 11a AP. it did not have the channel EID, patch here ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ UCHAR LatchRfChannel = MsgChannel; ++ if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) ++ { ++ if (CtrlChannel != 0) ++ *pChannel = CtrlChannel; ++ else ++ *pChannel = LatchRfChannel; ++ Sanity |= 0x4; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (Sanity != 0x7) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", Sanity)); ++ return FALSE; ++ } ++ else ++ { ++ return TRUE; ++ } ++ ++} ++ ++#ifdef DOT11N_DRAFT3 ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check for some IE addressed in 802.11n d3.03. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerBeaconAndProbeRspSanity2( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *RegClass) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 pFrame; ++ PEID_STRUCT pEid; ++ ULONG Length = 0; ++ ++ pFrame = (PFRAME_802_11)Msg; ++ ++ *RegClass = 0; ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ // get timestamp from payload and advance the pointer ++ Ptr += TIMESTAMP_LEN; ++ Length += TIMESTAMP_LEN; ++ ++ // get beacon interval from payload and advance the pointer ++ Ptr += 2; ++ Length += 2; ++ ++ // get capability info from payload and advance the pointer ++ Ptr += 2; ++ Length += 2; ++ ++ pEid = (PEID_STRUCT) Ptr; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ switch(pEid->Eid) ++ { ++ case IE_SUPP_REG_CLASS: ++ if(pEid->Len > 0) ++ { ++ *RegClass = *pEid->Octet; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ return TRUE; ++ ++} ++#endif // DOT11N_DRAFT3 // ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeScanReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *pBssType, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pScanType) ++{ ++ MLME_SCAN_REQ_STRUCT *Info; ++ ++ Info = (MLME_SCAN_REQ_STRUCT *)(Msg); ++ *pBssType = Info->BssType; ++ *pSsidLen = Info->SsidLen; ++ NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); ++ *pScanType = Info->ScanType; ++ ++ if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC || *pBssType == BSS_ANY) ++ && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE ++#ifdef CONFIG_STA_SUPPORT ++ || *pScanType == SCAN_CISCO_PASSIVE || *pScanType == SCAN_CISCO_ACTIVE ++ || *pScanType == SCAN_CISCO_CHANNEL_LOAD || *pScanType == SCAN_CISCO_NOISE ++#endif // CONFIG_STA_SUPPORT // ++ )) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqSanity fail - wrong BssType or ScanType\n")); ++ return FALSE; ++ } ++} ++ ++// IRQL = DISPATCH_LEVEL ++UCHAR ChannelSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++{ ++ int i; ++ ++ for (i = 0; i < pAd->ChannelListNum; i ++) ++ { ++ if (channel == pAd->ChannelList[i].Channel) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerDeauthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pReason) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pReason, &pFrame->Octet[0], 2); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT USHORT *pAlg, ++ OUT USHORT *pSeq, ++ OUT USHORT *pStatus, ++ CHAR *pChlgText) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pAlg, &pFrame->Octet[0], 2); ++ NdisMoveMemory(pSeq, &pFrame->Octet[2], 2); ++ NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); ++ ++ if ((*pAlg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (*pAlg == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ { ++ if (*pSeq == 1 || *pSeq == 2) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); ++ return FALSE; ++ } ++ } ++ else if (*pAlg == Ndis802_11AuthModeShared) ++ { ++ if (*pSeq == 1 || *pSeq == 4) ++ { ++ return TRUE; ++ } ++ else if (*pSeq == 2 || *pSeq == 3) ++ { ++ NdisMoveMemory(pChlgText, &pFrame->Octet[8], CIPHER_TEXT_LEN); ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); ++ return FALSE; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong algorithm\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeAuthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT ULONG *pTimeout, ++ OUT USHORT *pAlg) ++{ ++ MLME_AUTH_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_AUTH_REQ_STRUCT *)Msg; ++ COPY_MAC_ADDR(pAddr, pInfo->Addr); ++ *pTimeout = pInfo->Timeout; ++ *pAlg = pInfo->Alg; ++ ++ if (((*pAlg == Ndis802_11AuthModeShared) ||(*pAlg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (*pAlg == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) && ++ ((*pAddr & 0x01) == 0)) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAuthReqSanity fail - wrong algorithm\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeAssocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pApAddr, ++ OUT USHORT *pCapabilityInfo, ++ OUT ULONG *pTimeout, ++ OUT USHORT *pListenIntv) ++{ ++ MLME_ASSOC_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_ASSOC_REQ_STRUCT *)Msg; ++ *pTimeout = pInfo->Timeout; // timeout ++ COPY_MAC_ADDR(pApAddr, pInfo->Addr); // AP address ++ *pCapabilityInfo = pInfo->CapabilityInfo; // capability info ++ *pListenIntv = pInfo->ListenIntv; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerDisassocSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pReason) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pReason, &pFrame->Octet[0], 2); ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Sanity check NetworkType (11b, 11g or 11a) ++ ++ Arguments: ++ pBss - Pointer to BSS table. ++ ++ Return Value: ++ Ndis802_11DS .......(11b) ++ Ndis802_11OFDM24....(11g) ++ Ndis802_11OFDM5.....(11a) ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( ++ IN PBSS_ENTRY pBss) ++{ ++ NDIS_802_11_NETWORK_TYPE NetWorkType; ++ UCHAR rate, i; ++ ++ NetWorkType = Ndis802_11DS; ++ ++ if (pBss->Channel <= 14) ++ { ++ // ++ // First check support Rate. ++ // ++ for (i = 0; i < pBss->SupRateLen; i++) ++ { ++ rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit ++ if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) ++ { ++ continue; ++ } ++ else ++ { ++ // ++ // Otherwise (even rate > 108) means Ndis802_11OFDM24 ++ // ++ NetWorkType = Ndis802_11OFDM24; ++ break; ++ } ++ } ++ ++ // ++ // Second check Extend Rate. ++ // ++ if (NetWorkType != Ndis802_11OFDM24) ++ { ++ for (i = 0; i < pBss->ExtRateLen; i++) ++ { ++ rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit ++ if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) ++ { ++ continue; ++ } ++ else ++ { ++ // ++ // Otherwise (even rate > 108) means Ndis802_11OFDM24 ++ // ++ NetWorkType = Ndis802_11OFDM24; ++ break; ++ } ++ } ++ } ++ } ++ else ++ { ++ NetWorkType = Ndis802_11OFDM5; ++ } ++ ++ if (pBss->HtCapabilityLen != 0) ++ { ++ if (NetWorkType == Ndis802_11OFDM5) ++ NetWorkType = Ndis802_11OFDM5_N; ++ else ++ NetWorkType = Ndis802_11OFDM24_N; ++ } ++ ++ return NetWorkType; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ WPA message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN PeerWpaMessageSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN PEAPOL_PACKET pMsg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgType, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ UCHAR mic[LEN_KEY_DESC_MIC], digest[80], KEYDATA[MAX_LEN_OF_RSNIE]; ++ BOOLEAN bReplayDiff = FALSE; ++ BOOLEAN bWPA2 = FALSE; ++ KEY_INFO EapolKeyInfo; ++ UCHAR GroupKeyIndex = 0; ++ ++ ++ NdisZeroMemory(mic, sizeof(mic)); ++ NdisZeroMemory(digest, sizeof(digest)); ++ NdisZeroMemory(KEYDATA, sizeof(KEYDATA)); ++ NdisZeroMemory((PUCHAR)&EapolKeyInfo, sizeof(EapolKeyInfo)); ++ ++ NdisMoveMemory((PUCHAR)&EapolKeyInfo, (PUCHAR)&pMsg->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT *)&EapolKeyInfo) = cpu2le16(*((USHORT *)&EapolKeyInfo)); ++ ++ // Choose WPA2 or not ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ bWPA2 = TRUE; ++ ++ // 0. Check MsgType ++ if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("The message type is invalid(%d)! \n", MsgType)); ++ return FALSE; ++ } ++ ++ // 1. Replay counter check ++ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) // For supplicant ++ { ++ // First validate replay counter, only accept message with larger replay counter. ++ // Let equal pass, some AP start with all zero replay counter ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ if ((RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ { ++ bReplayDiff = TRUE; ++ } ++ } ++ else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) // For authenticator ++ { ++ // check Replay Counter coresponds to MSG from authenticator, otherwise discard ++ if (!NdisEqualMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY)) ++ { ++ bReplayDiff = TRUE; ++ } ++ } ++ ++ // Replay Counter different condition ++ if (bReplayDiff) ++ { ++ // send wireless event - for replay counter different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ if (MsgType < EAPOL_GROUP_MSG_1) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", MsgType)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); ++ } ++ ++ hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ hex_dump("Current replay counter ", pEntry->R_Counter, LEN_KEY_DESC_REPLAY); ++ return FALSE; ++ } ++ ++ // 2. Verify MIC except Pairwise Msg1 ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ { ++ UCHAR rcvd_mic[LEN_KEY_DESC_MIC]; ++ ++ // Record the received MIC for check later ++ NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ if (pEntry->WepStatus == Ndis802_11Encryption2Enabled) // TKIP ++ { ++ hmac_md5(pEntry->PTK, LEN_EAP_MICK, (PUCHAR)pMsg, MsgLen, mic); ++ } ++ else if (pEntry->WepStatus == Ndis802_11Encryption3Enabled) // AES ++ { ++ HMAC_SHA1((PUCHAR)pMsg, MsgLen, pEntry->PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); ++ } ++ ++ if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC)) ++ { ++ // send wireless event - for MIC different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_MIC_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ if (MsgType < EAPOL_GROUP_MSG_1) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in pairwise msg %d of 4-way handshake!\n", MsgType)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); ++ } ++ ++ hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC); ++ hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC); ++ ++ return FALSE; ++ } ++ } ++ ++ // Extract the context of the Key Data field if it exist ++ // The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is un-encrypted. ++ // The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted. ++ if (pMsg->KeyDesc.KeyDataLen[1] > 0) ++ { ++ // Decrypt this field ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ if(pEntry->WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ AES_GTK_KEY_UNWRAP(&pEntry->PTK[16], KEYDATA, pMsg->KeyDesc.KeyDataLen[1],pMsg->KeyDesc.KeyData); ++ } ++ else ++ { ++ INT i; ++ UCHAR Key[32]; ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pMsg->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pEntry->PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); ++ } ++ ++ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) ++ GroupKeyIndex = EapolKeyInfo.KeyIndex; ++ ++ } ++ else if ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2)) ++ { ++ NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); ++ } ++ else ++ { ++ ++ return TRUE; ++ } ++ ++ // Parse Key Data field to ++ // 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2) ++ // 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2 ++ // 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2) ++ if (!RTMPParseEapolKeyData(pAd, KEYDATA, pMsg->KeyDesc.KeyDataLen[1], GroupKeyIndex, MsgType, bWPA2, pEntry)) ++ { ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN MlmeDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PRT_802_11_DLS *pDLS, ++ OUT PUSHORT pReason) ++{ ++ MLME_DLS_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_DLS_REQ_STRUCT *)Msg; ++ ++ *pDLS = pInfo->pDLS; ++ *pReason = pInfo->Reason; ++ ++ return TRUE; ++} ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN PeerDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pDlsTimeout, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ PEID_STRUCT eid_ptr; ++ ++ // to prevent caller from using garbage output value ++ *pCapabilityInfo = 0; ++ *pDlsTimeout = 0; ++ *pHtCapabilityLen = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pDlsTimeout, Ptr, 2); ++ Ptr += 2; ++ ++ // Category and Action field + DA + SA + capability + Timeout ++ eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; ++ ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_SUPP_RATES: ++ if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) ++ { ++ NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); ++ DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); ++ *pRatesLen = eid_ptr->Len; ++ } ++ else ++ { ++ *pRatesLen = 8; ++ Rates[0] = 0x82; ++ Rates[1] = 0x84; ++ Rates[2] = 0x8b; ++ Rates[3] = 0x96; ++ Rates[4] = 0x12; ++ Rates[5] = 0x24; ++ Rates[6] = 0x48; ++ Rates[7] = 0x6c; ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); ++ *pRatesLen = (*pRatesLen) + eid_ptr->Len; ++ } ++ else ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); ++ *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) ++ { ++ NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_HT_CAP\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerDlsRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ PEID_STRUCT eid_ptr; ++ ++ // to prevent caller from using garbage output value ++ *pStatus = 0; ++ *pCapabilityInfo = 0; ++ *pHtCapabilityLen = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get status code from payload and advance the pointer ++ NdisMoveMemory(pStatus, Ptr, 2); ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ if (pStatus == 0) ++ { ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ } ++ ++ // Category and Action field + status code + DA + SA + capability ++ eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; ++ ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_SUPP_RATES: ++ if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) ++ { ++ NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); ++ DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); ++ *pRatesLen = eid_ptr->Len; ++ } ++ else ++ { ++ *pRatesLen = 8; ++ Rates[0] = 0x82; ++ Rates[1] = 0x84; ++ Rates[2] = 0x8b; ++ Rates[3] = 0x96; ++ Rates[4] = 0x12; ++ Rates[5] = 0x24; ++ Rates[6] = 0x48; ++ Rates[7] = 0x6c; ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); ++ *pRatesLen = (*pRatesLen) + eid_ptr->Len; ++ } ++ else ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); ++ *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) ++ { ++ NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_HT_CAP\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerDlsTearDownSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pReason) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ ++ // to prevent caller from using garbage output value ++ *pReason = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get reason code from payload and advance the pointer ++ NdisMoveMemory(pReason, Ptr, 2); ++ Ptr += 2; ++ ++ return TRUE; ++} ++#endif // QOS_DLS_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/cmm_sync.c +@@ -0,0 +1,702 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sync.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 modified for rt2561/2661 ++*/ ++#include "../rt_config.h" ++ ++// 2.4 Ghz channel plan index in the TxPower arrays. ++#define BG_BAND_REGION_0_START 0 // 1,2,3,4,5,6,7,8,9,10,11 ++#define BG_BAND_REGION_0_SIZE 11 ++#define BG_BAND_REGION_1_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13 ++#define BG_BAND_REGION_1_SIZE 13 ++#define BG_BAND_REGION_2_START 9 // 10,11 ++#define BG_BAND_REGION_2_SIZE 2 ++#define BG_BAND_REGION_3_START 9 // 10,11,12,13 ++#define BG_BAND_REGION_3_SIZE 4 ++#define BG_BAND_REGION_4_START 13 // 14 ++#define BG_BAND_REGION_4_SIZE 1 ++#define BG_BAND_REGION_5_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 ++#define BG_BAND_REGION_5_SIZE 14 ++#define BG_BAND_REGION_6_START 2 // 3,4,5,6,7,8,9 ++#define BG_BAND_REGION_6_SIZE 7 ++#define BG_BAND_REGION_7_START 4 // 5,6,7,8,9,10,11,12,13 ++#define BG_BAND_REGION_7_SIZE 9 ++#define BG_BAND_REGION_31_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 ++#define BG_BAND_REGION_31_SIZE 14 ++ ++// 5 Ghz channel plan index in the TxPower arrays. ++UCHAR A_BAND_REGION_0_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_1_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++UCHAR A_BAND_REGION_2_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64}; ++UCHAR A_BAND_REGION_3_CHANNEL_LIST[]={52, 56, 60, 64, 149, 153, 157, 161}; ++UCHAR A_BAND_REGION_4_CHANNEL_LIST[]={149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_5_CHANNEL_LIST[]={149, 153, 157, 161}; ++UCHAR A_BAND_REGION_6_CHANNEL_LIST[]={36, 40, 44, 48}; ++UCHAR A_BAND_REGION_7_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_8_CHANNEL_LIST[]={52, 56, 60, 64}; ++UCHAR A_BAND_REGION_9_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_10_CHANNEL_LIST[]={36, 40, 44, 48, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_11_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161}; ++ ++//BaSizeArray follows the 802.11n definition as MaxRxFactor. 2^(13+factor) bytes. When factor =0, it's about Ba buffer size =8. ++UCHAR BaSizeArray[4] = {8,16,32,64}; ++ ++/* ++ ========================================================================== ++ Description: ++ Update StaCfg->ChannelList[] according to 1) Country Region 2) RF IC type, ++ and 3) PHY-mode user selected. ++ The outcome is used by driver when doing site survey. ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID BuildChannelList( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i, j, index=0, num=0; ++ PUCHAR pChannelList = NULL; ++ ++ NdisZeroMemory(pAd->ChannelList, MAX_NUM_OF_CHANNELS * sizeof(CHANNEL_TX_POWER)); ++ ++ // if not 11a-only mode, channel list starts from 2.4Ghz band ++ if ((pAd->CommonCfg.PhyMode != PHY_11A) ++#ifdef DOT11_N_SUPPORT ++ && (pAd->CommonCfg.PhyMode != PHY_11AN_MIXED) && (pAd->CommonCfg.PhyMode != PHY_11N_5G) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ switch (pAd->CommonCfg.CountryRegion & 0x7f) ++ { ++ case REGION_0_BG_BAND: // 1 -11 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_0_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_0_SIZE); ++ index += BG_BAND_REGION_0_SIZE; ++ break; ++ case REGION_1_BG_BAND: // 1 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_1_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_1_SIZE); ++ index += BG_BAND_REGION_1_SIZE; ++ break; ++ case REGION_2_BG_BAND: // 10 - 11 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_2_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_2_SIZE); ++ index += BG_BAND_REGION_2_SIZE; ++ break; ++ case REGION_3_BG_BAND: // 10 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_3_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_3_SIZE); ++ index += BG_BAND_REGION_3_SIZE; ++ break; ++ case REGION_4_BG_BAND: // 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_4_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_4_SIZE); ++ index += BG_BAND_REGION_4_SIZE; ++ break; ++ case REGION_5_BG_BAND: // 1 - 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_5_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_5_SIZE); ++ index += BG_BAND_REGION_5_SIZE; ++ break; ++ case REGION_6_BG_BAND: // 3 - 9 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_6_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_6_SIZE); ++ index += BG_BAND_REGION_6_SIZE; ++ break; ++ case REGION_7_BG_BAND: // 5 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_7_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_7_SIZE); ++ index += BG_BAND_REGION_7_SIZE; ++ break; ++ case REGION_31_BG_BAND: // 1 - 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_31_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_31_SIZE); ++ index += BG_BAND_REGION_31_SIZE; ++ break; ++ default: // Error. should never happen ++ break; ++ } ++ for (i=0; iChannelList[i].MaxTxPwr = 20; ++ } ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11A) || (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ switch (pAd->CommonCfg.CountryRegionForABand & 0x7f) ++ { ++ case REGION_0_A_BAND: ++ num = sizeof(A_BAND_REGION_0_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_0_CHANNEL_LIST; ++ break; ++ case REGION_1_A_BAND: ++ num = sizeof(A_BAND_REGION_1_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_1_CHANNEL_LIST; ++ break; ++ case REGION_2_A_BAND: ++ num = sizeof(A_BAND_REGION_2_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_2_CHANNEL_LIST; ++ break; ++ case REGION_3_A_BAND: ++ num = sizeof(A_BAND_REGION_3_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_3_CHANNEL_LIST; ++ break; ++ case REGION_4_A_BAND: ++ num = sizeof(A_BAND_REGION_4_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_4_CHANNEL_LIST; ++ break; ++ case REGION_5_A_BAND: ++ num = sizeof(A_BAND_REGION_5_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_5_CHANNEL_LIST; ++ break; ++ case REGION_6_A_BAND: ++ num = sizeof(A_BAND_REGION_6_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_6_CHANNEL_LIST; ++ break; ++ case REGION_7_A_BAND: ++ num = sizeof(A_BAND_REGION_7_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_7_CHANNEL_LIST; ++ break; ++ case REGION_8_A_BAND: ++ num = sizeof(A_BAND_REGION_8_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_8_CHANNEL_LIST; ++ break; ++ case REGION_9_A_BAND: ++ num = sizeof(A_BAND_REGION_9_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_9_CHANNEL_LIST; ++ break; ++ ++ case REGION_10_A_BAND: ++ num = sizeof(A_BAND_REGION_10_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_10_CHANNEL_LIST; ++ break; ++ ++ case REGION_11_A_BAND: ++ num = sizeof(A_BAND_REGION_11_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_11_CHANNEL_LIST; ++ break; ++ ++ default: // Error. should never happen ++ DBGPRINT(RT_DEBUG_WARN,("countryregion=%d not support", pAd->CommonCfg.CountryRegionForABand)); ++ break; ++ } ++ ++ if (num != 0) ++ { ++ UCHAR RadarCh[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ for (i=0; iTxPower[j].Channel) ++ NdisMoveMemory(&pAd->ChannelList[index+i], &pAd->TxPower[j], sizeof(CHANNEL_TX_POWER)); ++ } ++ for (j=0; j<15; j++) ++ { ++ if (pChannelList[i] == RadarCh[j]) ++ pAd->ChannelList[index+i].DfsReq = TRUE; ++ } ++ pAd->ChannelList[index+i].MaxTxPwr = 20; ++ } ++ index += num; ++ } ++ } ++ ++ pAd->ChannelListNum = index; ++ DBGPRINT(RT_DEBUG_TRACE,("country code=%d/%d, RFIC=%d, PHY mode=%d, support %d channels\n", ++ pAd->CommonCfg.CountryRegion, pAd->CommonCfg.CountryRegionForABand, pAd->RfIcType, pAd->CommonCfg.PhyMode, pAd->ChannelListNum)); ++#ifdef DBG ++ for (i=0;iChannelListNum;i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("BuildChannel # %d :: Pwr0 = %d, Pwr1 =%d, \n ", pAd->ChannelList[i].Channel, pAd->ChannelList[i].Power, pAd->ChannelList[i].Power2)); ++ } ++#endif ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine return the first channel number according to the country ++ code selection and RF IC selection (signal band or dual band). It is called ++ whenever driver need to start a site survey of all supported channels. ++ Return: ++ ch - the first channel number of current country code setting ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++UCHAR FirstChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return pAd->ChannelList[0].Channel; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine returns the next channel number. This routine is called ++ during driver need to start a site survey of all supported channels. ++ Return: ++ next_channel - the next channel number valid in current country code setting. ++ Note: ++ return 0 if no more next channel ++ ========================================================================== ++ */ ++UCHAR NextChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++{ ++ int i; ++ UCHAR next_channel = 0; ++ ++ for (i = 0; i < (pAd->ChannelListNum - 1); i++) ++ if (channel == pAd->ChannelList[i].Channel) ++ { ++ next_channel = pAd->ChannelList[i+1].Channel; ++ break; ++ } ++ return next_channel; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is for Cisco Compatible Extensions 2.X ++ Spec31. AP Control of Client Transmit Power ++ Return: ++ None ++ Note: ++ Required by Aironet dBm(mW) ++ 0dBm(1mW), 1dBm(5mW), 13dBm(20mW), 15dBm(30mW), ++ 17dBm(50mw), 20dBm(100mW) ++ ++ We supported ++ 3dBm(Lowest), 6dBm(10%), 9dBm(25%), 12dBm(50%), ++ 14dBm(75%), 15dBm(100%) ++ ++ The client station's actual transmit power shall be within +/- 5dB of ++ the minimum value or next lower value. ++ ========================================================================== ++ */ ++VOID ChangeToCellPowerLimit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AironetCellPowerLimit) ++{ ++ //valud 0xFF means that hasn't found power limit information ++ //from the AP's Beacon/Probe response. ++ if (AironetCellPowerLimit == 0xFF) ++ return; ++ ++ if (AironetCellPowerLimit < 6) //Used Lowest Power Percentage. ++ pAd->CommonCfg.TxPowerPercentage = 6; ++ else if (AironetCellPowerLimit < 9) ++ pAd->CommonCfg.TxPowerPercentage = 10; ++ else if (AironetCellPowerLimit < 12) ++ pAd->CommonCfg.TxPowerPercentage = 25; ++ else if (AironetCellPowerLimit < 14) ++ pAd->CommonCfg.TxPowerPercentage = 50; ++ else if (AironetCellPowerLimit < 15) ++ pAd->CommonCfg.TxPowerPercentage = 75; ++ else ++ pAd->CommonCfg.TxPowerPercentage = 100; //else used maximum ++ ++ if (pAd->CommonCfg.TxPowerPercentage > pAd->CommonCfg.TxPowerDefault) ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ ++} ++ ++CHAR ConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ LNAGain = GET_LNA_GAIN(pAd); ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-12 - RssiOffset - LNAGain - Rssi); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan next channel ++ ========================================================================== ++ */ ++VOID ScanNextChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ HEADER_802_11 Hdr80211; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ UCHAR SsidLen = 0, ScanType = pAd->MlmeAux.ScanType, BBPValue = 0; ++#ifdef CONFIG_STA_SUPPORT ++ USHORT Status; ++ PHEADER_802_11 pHdr80211; ++#endif // CONFIG_STA_SUPPORT // ++ UINT ScanTimeIn5gChannel = SHORT_CHANNEL_TIME; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (MONITOR_ON(pAd)) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (pAd->MlmeAux.Channel == 0) ++ { ++ if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ++#ifdef CONFIG_STA_SUPPORT ++ && (INFRA_ON(pAd) ++ || (pAd->OpMode == OPMODE_AP)) ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); ++ } ++ else ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to channel %d, Total BSS[%02d]\n",pAd->CommonCfg.Channel, pAd->ScanTab.BssNr)); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // ++ // To prevent data lost. ++ // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. ++ // Now, we need to send an NULL data with turned PSM bit off to AP, when scan progress done ++ // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) ++ { ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ pHdr80211 = (PHEADER_802_11) pOutBuffer; ++ MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pHdr80211->Duration = 0; ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame\n")); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPusecDelay(5000); ++ } ++ } ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ } ++ else ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // BBP and RF are not accessible in PS mode, we has to wake them up first ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ ++ // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, TRUE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->MlmeAux.Channel > 14) ++ { ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) ++ { ++ ScanType = SCAN_PASSIVE; ++ ScanTimeIn5gChannel = MIN_CHANNEL_TIME; ++ } ++ } ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // carrier detection ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ ScanType = SCAN_PASSIVE; ++ ScanTimeIn5gChannel = MIN_CHANNEL_TIME; ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ //Global country domain(ch1-11:active scan, ch12-14 passive scan) ++ if ((pAd->MlmeAux.Channel <= 14) && (pAd->MlmeAux.Channel >= 12) && ((pAd->CommonCfg.CountryRegion & 0x7f) == REGION_31_BG_BAND)) ++ { ++ ScanType = SCAN_PASSIVE; ++ } ++ ++ // We need to shorten active scan time in order for WZC connect issue ++ // Chnage the channel scan time for CISCO stuff based on its IAPP announcement ++ if (ScanType == FAST_SCAN_ACTIVE) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, FAST_ACTIVE_SCAN_TIME); ++#ifdef CONFIG_STA_SUPPORT ++ else if (((ScanType == SCAN_CISCO_ACTIVE) || ++ (ScanType == SCAN_CISCO_PASSIVE) || ++ (ScanType == SCAN_CISCO_CHANNEL_LOAD) || ++ (ScanType == SCAN_CISCO_NOISE)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if (pAd->StaCfg.CCXScanTime < 25) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime * 2); ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ else // must be SCAN_PASSIVE or SCAN_ACTIVE ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ if (pAd->MlmeAux.Channel > 14) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, ScanTimeIn5gChannel); ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MIN_CHANNEL_TIME); ++ } ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MAX_CHANNEL_TIME); ++ } ++ ++ if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) || ++ (ScanType == SCAN_CISCO_ACTIVE)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - ScanNextChannel() allocate memory fail\n")); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return; ++ } ++ ++ // There is no need to send broadcast probe request if active scan is in effect. ++ if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) ++ ) ++ SsidLen = pAd->MlmeAux.SsidLen; ++ else ++ SsidLen = 0; ++ ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &SsidLen, ++ SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->CommonCfg.SupRateLen, ++ pAd->CommonCfg.SupRateLen, pAd->CommonCfg.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->CommonCfg.ExtRateLen) ++ { ++ ULONG Tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->CommonCfg.ExtRateLen, ++ pAd->CommonCfg.ExtRateLen, pAd->CommonCfg.ExtRate, ++ END_OF_ARGS); ++ FrameLen += Tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ ULONG Tmp; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ if (pAd->bBroadComHT == TRUE) ++ { ++ HtLen = pAd->MlmeAux.HtCapabilityLen + 4; ++#ifdef RT_BIG_ENDIAN ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#else ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++#endif // RT_BIG_ENDIAN // ++ } ++ else ++ { ++ HtLen = pAd->MlmeAux.HtCapabilityLen; ++#ifdef RT_BIG_ENDIAN ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, SIZE_HT_CAP_IE); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#else ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#endif // RT_BIG_ENDIAN // ++ } ++ FrameLen += Tmp; ++ ++#ifdef DOT11N_DRAFT3 ++ if (pAd->CommonCfg.BACapability.field.b2040CoexistScanSup == 1) ++ { ++ ULONG Tmp; ++ HtLen = 1; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtHtCapIe, ++ 1, &HtLen, ++ 1, &pAd->CommonCfg.BSSCoexist2040.word, ++ END_OF_ARGS); ++ ++ FrameLen += Tmp; ++ } ++#endif // DOT11N_DRAFT3 // ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ ++ // For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++} ++ ++VOID MgtProbReqMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SubType; ++ if (SubType == SUBTYPE_ACK) ++ pHdr80211->FC.Type = BTYPE_CNTL; ++ pHdr80211->FC.ToDs = ToDs; ++ COPY_MAC_ADDR(pHdr80211->Addr1, pDA); ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/cmm_wpa.c +@@ -0,0 +1,1606 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 03-07-22 Initial ++ Paul Lin 03-11-28 Modify for supplicant ++*/ ++#include "../rt_config.h" ++// WPA OUI ++UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; ++UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; ++UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; ++UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; ++// WPA2 OUI ++UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; ++UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; ++UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; ++UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; ++UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; ++// MSA OUI ++UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 ++UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The pseudo-random function(PRF) that hashes various inputs to ++ derive a pseudo-random value. To add liveness to the pseudo-random ++ value, a nonce should be one of the inputs. ++ ++ It is used to generate PTK, GTK or some specific random value. ++ ++ Arguments: ++ UCHAR *key, - the key material for HMAC_SHA1 use ++ INT key_len - the length of key ++ UCHAR *prefix - a prefix label ++ INT prefix_len - the length of the label ++ UCHAR *data - a specific data with variable length ++ INT data_len - the length of a specific data ++ INT len - the output lenght ++ ++ Return Value: ++ UCHAR *output - the calculated result ++ ++ Note: ++ 802.11i-2004 Annex H.3 ++ ++ ======================================================================== ++*/ ++VOID PRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *prefix, ++ IN INT prefix_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len) ++{ ++ INT i; ++ UCHAR *input; ++ INT currentindex = 0; ++ INT total_len; ++ ++ // Allocate memory for input ++ os_alloc_mem(NULL, (PUCHAR *)&input, 1024); ++ ++ if (input == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); ++ return; ++ } ++ ++ // Generate concatenation input ++ NdisMoveMemory(input, prefix, prefix_len); ++ ++ // Concatenate a single octet containing 0 ++ input[prefix_len] = 0; ++ ++ // Concatenate specific data ++ NdisMoveMemory(&input[prefix_len + 1], data, data_len); ++ total_len = prefix_len + 1 + data_len; ++ ++ // Concatenate a single octet containing 0 ++ // This octet shall be update later ++ input[total_len] = 0; ++ total_len++; ++ ++ // Iterate to calculate the result by hmac-sha-1 ++ // Then concatenate to last result ++ for (i = 0; i < (len + 19) / 20; i++) ++ { ++ HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); ++ currentindex += 20; ++ ++ // update the last octet ++ input[total_len - 1]++; ++ } ++ os_free_mem(NULL, input); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK. ++ It shall be called by 4-way handshake processing. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PMK - pointer to PMK ++ ANonce - pointer to ANonce ++ AA - pointer to Authenticator Address ++ SNonce - pointer to SNonce ++ SA - pointer to Supplicant Address ++ len - indicate the length of PTK (octet) ++ ++ Return Value: ++ Output pointer to the PTK ++ ++ Note: ++ Refer to IEEE 802.11i-2004 8.5.1.2 ++ ++ ======================================================================== ++*/ ++VOID WpaCountPTK( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *PMK, ++ IN UCHAR *ANonce, ++ IN UCHAR *AA, ++ IN UCHAR *SNonce, ++ IN UCHAR *SA, ++ OUT UCHAR *output, ++ IN UINT len) ++{ ++ UCHAR concatenation[76]; ++ UINT CurrPos = 0; ++ UCHAR temp[32]; ++ UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', ++ 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; ++ ++ // initiate the concatenation input ++ NdisZeroMemory(temp, sizeof(temp)); ++ NdisZeroMemory(concatenation, 76); ++ ++ // Get smaller address ++ if (RTMPCompareMemory(SA, AA, 6) == 1) ++ NdisMoveMemory(concatenation, AA, 6); ++ else ++ NdisMoveMemory(concatenation, SA, 6); ++ CurrPos += 6; ++ ++ // Get larger address ++ if (RTMPCompareMemory(SA, AA, 6) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], SA, 6); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], AA, 6); ++ ++ // store the larger mac address for backward compatible of ++ // ralink proprietary STA-key issue ++ NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN); ++ CurrPos += 6; ++ ++ // Get smaller Nonce ++ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) ++ NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue ++ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); ++ CurrPos += 32; ++ ++ // Get larger Nonce ++ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) ++ NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue ++ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); ++ CurrPos += 32; ++ ++ hex_dump("concatenation=", concatenation, 76); ++ ++ // Use PRF to generate PTK ++ PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Generate random number by software. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ macAddr - pointer to local MAC address ++ ++ Return Value: ++ ++ Note: ++ 802.1ii-2004 Annex H.5 ++ ++ ======================================================================== ++*/ ++VOID GenRandom( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *macAddr, ++ OUT UCHAR *random) ++{ ++ INT i, curr; ++ UCHAR local[80], KeyCounter[32]; ++ UCHAR result[80]; ++ ULONG CurrentTime; ++ UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; ++ ++ // Zero the related information ++ NdisZeroMemory(result, 80); ++ NdisZeroMemory(local, 80); ++ NdisZeroMemory(KeyCounter, 32); ++ ++ for (i = 0; i < 32; i++) ++ { ++ // copy the local MAC address ++ COPY_MAC_ADDR(local, macAddr); ++ curr = MAC_ADDR_LEN; ++ ++ // concatenate the current time ++ NdisGetSystemUpTime(&CurrentTime); ++ NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); ++ curr += sizeof(CurrentTime); ++ ++ // concatenate the last result ++ NdisMoveMemory(&local[curr], result, 32); ++ curr += 32; ++ ++ // concatenate a variable ++ NdisMoveMemory(&local[curr], &i, 2); ++ curr += 2; ++ ++ // calculate the result ++ PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); ++ } ++ ++ NdisMoveMemory(random, result, 32); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build cipher suite in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ WepStatus - indicate the encryption type ++ bMixCipher - a boolean to indicate the pairwise cipher and group ++ cipher are the same or not ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UINT WepStatus, ++ IN BOOLEAN bMixCipher, ++ IN UCHAR FlexibleCipher, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ UCHAR PairwiseCnt; ++ ++ *rsn_len = 0; ++ ++ // decide WPA2 or WPA1 ++ if (ElementID == Wpa2Ie) ++ { ++ RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; ++ ++ // Assign the verson as 1 ++ pRsnie_cipher->version = 1; ++ ++ switch (WepStatus) ++ { ++ // TKIP mode ++ case Ndis802_11Encryption2Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); ++ *rsn_len = sizeof(RSNIE2); ++ break; ++ ++ // AES mode ++ case Ndis802_11Encryption3Enabled: ++ if (bMixCipher) ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ else ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); ++ *rsn_len = sizeof(RSNIE2); ++ break; ++ ++ // TKIP-AES mix mode ++ case Ndis802_11Encryption4Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ ++ PairwiseCnt = 1; ++ // Insert WPA2 TKIP as the first pairwise cipher ++ if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); ++ // Insert WPA2 AES as the secondary pairwise cipher ++ if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); ++ PairwiseCnt = 2; ++ } ++ } ++ else ++ { ++ // Insert WPA2 AES as the first pairwise cipher ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); ++ } ++ ++ pRsnie_cipher->ucount = PairwiseCnt; ++ *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); ++ break; ++ } ++ ++ // swap for big-endian platform ++ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); ++ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); ++ } ++ else ++ { ++ RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; ++ ++ // Assign OUI and version ++ NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); ++ pRsnie_cipher->version = 1; ++ ++ switch (WepStatus) ++ { ++ // TKIP mode ++ case Ndis802_11Encryption2Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); ++ *rsn_len = sizeof(RSNIE); ++ break; ++ ++ // AES mode ++ case Ndis802_11Encryption3Enabled: ++ if (bMixCipher) ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ else ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); ++ *rsn_len = sizeof(RSNIE); ++ break; ++ ++ // TKIP-AES mix mode ++ case Ndis802_11Encryption4Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ ++ PairwiseCnt = 1; ++ // Insert WPA TKIP as the first pairwise cipher ++ if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); ++ // Insert WPA AES as the secondary pairwise cipher ++ if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); ++ PairwiseCnt = 2; ++ } ++ } ++ else ++ { ++ // Insert WPA AES as the first pairwise cipher ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); ++ } ++ ++ pRsnie_cipher->ucount = PairwiseCnt; ++ *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); ++ break; ++ } ++ ++ // swap for big-endian platform ++ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); ++ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build AKM suite in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ AuthMode - indicate the authentication mode ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeAKM( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UINT AuthMode, ++ IN UCHAR apidx, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ RSNIE_AUTH *pRsnie_auth; ++ ++ pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); ++ ++ // decide WPA2 or WPA1 ++ if (ElementID == Wpa2Ie) ++ { ++ switch (AuthMode) ++ { ++ case Ndis802_11AuthModeWPA2: ++ case Ndis802_11AuthModeWPA1WPA2: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPA2PSK: ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); ++ break; ++ } ++ } ++ else ++ { ++ switch (AuthMode) ++ { ++ case Ndis802_11AuthModeWPA: ++ case Ndis802_11AuthModeWPA1WPA2: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPAPSK: ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPANone: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); ++ break; ++ } ++ } ++ ++ pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount); ++ ++ (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build capability in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeCap( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UCHAR apidx, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ RSN_CAPABILITIES *pRSN_Cap; ++ ++ // it could be ignored in WPA1 mode ++ if (ElementID == WpaIe) ++ return; ++ ++ pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); ++ ++ ++ pRSN_Cap->word = cpu2le16(pRSN_Cap->word); ++ ++ (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build RSN IE context. It is not included element-ID and length. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ AuthMode - indicate the authentication mode ++ WepStatus - indicate the encryption type ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPMakeRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT AuthMode, ++ IN UINT WepStatus, ++ IN UCHAR apidx) ++{ ++ PUCHAR pRsnIe = NULL; // primary RSNIE ++ UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE ++ UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE ++ UCHAR PrimaryRsnie; ++ BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different ++ UCHAR p_offset; ++ WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode ++ ++ rsnielen_cur_p = NULL; ++ rsnielen_ex_cur_p = NULL; ++ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ if (AuthMode < Ndis802_11AuthModeWPA) ++ return; ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Support WPAPSK or WPA2PSK in STA-Infra mode ++ // Support WPANone in STA-Adhoc mode ++ if ((AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); ++ ++ // Zero RSNIE context ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); ++ ++ // Pointer to RSNIE ++ rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; ++ pRsnIe = pAd->StaCfg.RSN_IE; ++ ++ bMixCipher = pAd->StaCfg.bMixCipher; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // indicate primary RSNIE as WPA or WPA2 ++ if ((AuthMode == Ndis802_11AuthModeWPA) || ++ (AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (AuthMode == Ndis802_11AuthModeWPANone) || ++ (AuthMode == Ndis802_11AuthModeWPA1WPA2) || ++ (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ PrimaryRsnie = WpaIe; ++ else ++ PrimaryRsnie = Wpa2Ie; ++ ++ { ++ // Build the primary RSNIE ++ // 1. insert cipher suite ++ RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); ++ ++ // 2. insert AKM ++ RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); ++ ++ // 3. insert capability ++ RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); ++ } ++ ++ // 4. update the RSNIE length ++ *rsnielen_cur_p = p_offset; ++ ++ hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); ++ ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Check whether the received frame is EAP frame. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ pEntry - pointer to active entry ++ pData - the received frame ++ DataByteCount - the received frame's length ++ FromWhichBSSID - indicate the interface index ++ ++ Return: ++ TRUE - This frame is EAP frame ++ FALSE - otherwise ++ ========================================================================== ++*/ ++BOOLEAN RTMPCheckWPAframe( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR pData, ++ IN ULONG DataByteCount, ++ IN UCHAR FromWhichBSSID) ++{ ++ ULONG Body_len; ++ BOOLEAN Cancelled; ++ ++ ++ if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H)) ++ return FALSE; ++ ++ ++ // Skip LLC header ++ if (NdisEqualMemory(SNAP_802_1H, pData, 6) || ++ // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL ++ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) ++ { ++ pData += 6; ++ } ++ // Skip 2-bytes EAPoL type ++ if (NdisEqualMemory(EAPOL, pData, 2)) ++ { ++ pData += 2; ++ } ++ else ++ return FALSE; ++ ++ switch (*(pData+1)) ++ { ++ case EAPPacket: ++ Body_len = (*(pData+2)<<8) | (*(pData+3)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len)); ++ break; ++ case EAPOLStart: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n")); ++ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n")); ++ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ } ++ break; ++ case EAPOLLogoff: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n")); ++ break; ++ case EAPOLKey: ++ Body_len = (*(pData+2)<<8) | (*(pData+3)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len)); ++ break; ++ case EAPOLASFAlert: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n")); ++ break; ++ default: ++ return FALSE; ++ ++ } ++ return TRUE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ENCRYPT AES GTK before sending in EAPOL frame. ++ AES GTK length = 128 bit, so fix blocks for aes-key-wrap as 2 in this function. ++ This function references to RFC 3394 for aes key wrap algorithm. ++ Return: ++ ========================================================================== ++*/ ++VOID AES_GTK_KEY_WRAP( ++ IN UCHAR *key, ++ IN UCHAR *plaintext, ++ IN UCHAR p_len, ++ OUT UCHAR *ciphertext) ++{ ++ UCHAR A[8], BIN[16], BOUT[16]; ++ UCHAR R[512]; ++ INT num_blocks = p_len/8; // unit:64bits ++ INT i, j; ++ aes_context aesctx; ++ UCHAR xor; ++ ++ rtmp_aes_set_key(&aesctx, key, 128); ++ ++ // Init IA ++ for (i = 0; i < 8; i++) ++ A[i] = 0xa6; ++ ++ //Input plaintext ++ for (i = 0; i < num_blocks; i++) ++ { ++ for (j = 0 ; j < 8; j++) ++ R[8 * (i + 1) + j] = plaintext[8 * i + j]; ++ } ++ ++ // Key Mix ++ for (j = 0; j < 6; j++) ++ { ++ for(i = 1; i <= num_blocks; i++) ++ { ++ //phase 1 ++ NdisMoveMemory(BIN, A, 8); ++ NdisMoveMemory(&BIN[8], &R[8 * i], 8); ++ rtmp_aes_encrypt(&aesctx, BIN, BOUT); ++ ++ NdisMoveMemory(A, &BOUT[0], 8); ++ xor = num_blocks * j + i; ++ A[7] = BOUT[7] ^ xor; ++ NdisMoveMemory(&R[8 * i], &BOUT[8], 8); ++ } ++ } ++ ++ // Output ciphertext ++ NdisMoveMemory(ciphertext, A, 8); ++ ++ for (i = 1; i <= num_blocks; i++) ++ { ++ for (j = 0 ; j < 8; j++) ++ ciphertext[8 * i + j] = R[8 * i + j]; ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Misc function to decrypt AES body ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ This function references to RFC 3394 for aes key unwrap algorithm. ++ ++ ======================================================================== ++*/ ++VOID AES_GTK_KEY_UNWRAP( ++ IN UCHAR *key, ++ OUT UCHAR *plaintext, ++ IN UCHAR c_len, ++ IN UCHAR *ciphertext) ++ ++{ ++ UCHAR A[8], BIN[16], BOUT[16]; ++ UCHAR xor; ++ INT i, j; ++ aes_context aesctx; ++ UCHAR *R; ++ INT num_blocks = c_len/8; // unit:64bits ++ ++ ++ os_alloc_mem(NULL, (PUCHAR *)&R, 512); ++ ++ if (R == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); ++ return; ++ } /* End of if */ ++ ++ // Initialize ++ NdisMoveMemory(A, ciphertext, 8); ++ //Input plaintext ++ for(i = 0; i < (c_len-8); i++) ++ { ++ R[ i] = ciphertext[i + 8]; ++ } ++ ++ rtmp_aes_set_key(&aesctx, key, 128); ++ ++ for(j = 5; j >= 0; j--) ++ { ++ for(i = (num_blocks-1); i > 0; i--) ++ { ++ xor = (num_blocks -1 )* j + i; ++ NdisMoveMemory(BIN, A, 8); ++ BIN[7] = A[7] ^ xor; ++ NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); ++ rtmp_aes_decrypt(&aesctx, BIN, BOUT); ++ NdisMoveMemory(A, &BOUT[0], 8); ++ NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); ++ } ++ } ++ ++ // OUTPUT ++ for(i = 0; i < c_len; i++) ++ { ++ plaintext[i] = R[i]; ++ } ++ ++ ++ os_free_mem(NULL, R); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Report the EAP message type ++ ++ Arguments: ++ msg - EAPOL_PAIR_MSG_1 ++ EAPOL_PAIR_MSG_2 ++ EAPOL_PAIR_MSG_3 ++ EAPOL_PAIR_MSG_4 ++ EAPOL_GROUP_MSG_1 ++ EAPOL_GROUP_MSG_2 ++ ++ Return: ++ message type string ++ ++ ========================================================================== ++*/ ++CHAR *GetEapolMsgType(CHAR msg) ++{ ++ if(msg == EAPOL_PAIR_MSG_1) ++ return "Pairwise Message 1"; ++ else if(msg == EAPOL_PAIR_MSG_2) ++ return "Pairwise Message 2"; ++ else if(msg == EAPOL_PAIR_MSG_3) ++ return "Pairwise Message 3"; ++ else if(msg == EAPOL_PAIR_MSG_4) ++ return "Pairwise Message 4"; ++ else if(msg == EAPOL_GROUP_MSG_1) ++ return "Group Message 1"; ++ else if(msg == EAPOL_GROUP_MSG_2) ++ return "Group Message 2"; ++ else ++ return "Invalid Message"; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Sanity RSN IE of EAPoL message ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ IN MAC_TABLE_ENTRY *pEntry, ++ OUT UCHAR *Offset) ++{ ++ PUCHAR pVIE; ++ UCHAR len; ++ PEID_STRUCT pEid; ++ BOOLEAN result = FALSE; ++ ++ pVIE = pData; ++ len = DataLen; ++ *Offset = 0; ++ ++ while (len > sizeof(RSNIE2)) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // WPA RSN IE ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) ++ { ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) && ++ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && ++ (pEntry->RSNIE_Len == (pEid->Len + 2))) ++ { ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ // WPA2 RSN IE ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) ++ { ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) && ++ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && ++ (pEntry->RSNIE_Len == (pEid->Len + 2))/* ToDo-AlbertY for mesh*/) ++ { ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ else ++ { ++ break; ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ ++ ++ return result; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. ++ GTK is encaptulated in KDE format at p.83 802.11i D10 ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ 802.11i D10 ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPParseEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR GroupKeyIndex, ++ IN UCHAR MsgType, ++ IN BOOLEAN bWPA2, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ PKDE_ENCAP pKDE = NULL; ++ PUCHAR pMyKeyData = pKeyData; ++ UCHAR KeyDataLength = KeyDataLen; ++ UCHAR GTKLEN = 0; ++ UCHAR DefaultIdx = 0; ++ UCHAR skip_offset; ++ ++ // Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it ++ if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // Check RSN IE whether it is WPA2/WPA2PSK ++ if (!RTMPCheckRSNIE(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) ++ { ++ // send wireless event - for RSN IE different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_RSNIE_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in msg %d of 4-way handshake!\n", MsgType)); ++ hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen); ++ hex_dump("Desired RSN_IE ", pEntry->RSN_IE, pEntry->RSNIE_Len); ++ ++ return FALSE; ++ } ++ else ++ { ++ if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // skip RSN IE ++ pMyKeyData += skip_offset; ++ KeyDataLength -= skip_offset; ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); ++ } ++ else ++ return TRUE; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); ++ ++ // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 ++ if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ if (KeyDataLength >= 8) // KDE format exclude GTK length ++ { ++ pKDE = (PKDE_ENCAP) pMyKeyData; ++ ++ ++ DefaultIdx = pKDE->GTKEncap.Kid; ++ ++ // Sanity check - KED length ++ if (KeyDataLength < (pKDE->Len + 2)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); ++ return FALSE; ++ } ++ ++ // Get GTK length - refer to IEEE 802.11i-2004 p.82 ++ GTKLEN = pKDE->Len -6; ++ if (GTKLEN < LEN_AES_KEY) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); ++ return FALSE; ++ } ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KDE format length is too short \n")); ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN)); ++ // skip it ++ pMyKeyData += 8; ++ KeyDataLength -= 8; ++ ++ } ++ else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) ++ { ++ DefaultIdx = GroupKeyIndex; ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK DefaultKeyID=%d \n", DefaultIdx)); ++ } ++ ++ // Sanity check - shared key index must be 1 ~ 3 ++ if (DefaultIdx < 1 || DefaultIdx > 3) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index(%d) is invalid in %s %s \n", DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); ++ return FALSE; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ // Todo ++#endif // CONFIG_STA_SUPPORT // ++ ++ return TRUE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Construct EAPoL message for WPA handshaking ++ Its format is below, ++ ++ +--------------------+ ++ | Protocol Version | 1 octet ++ +--------------------+ ++ | Protocol Type | 1 octet ++ +--------------------+ ++ | Body Length | 2 octets ++ +--------------------+ ++ | Descriptor Type | 1 octet ++ +--------------------+ ++ | Key Information | 2 octets ++ +--------------------+ ++ | Key Length | 1 octet ++ +--------------------+ ++ | Key Repaly Counter | 8 octets ++ +--------------------+ ++ | Key Nonce | 32 octets ++ +--------------------+ ++ | Key IV | 16 octets ++ +--------------------+ ++ | Key RSC | 8 octets ++ +--------------------+ ++ | Key ID or Reserved | 8 octets ++ +--------------------+ ++ | Key MIC | 16 octets ++ +--------------------+ ++ | Key Data Length | 2 octets ++ +--------------------+ ++ | Key Data | n octets ++ +--------------------+ ++ ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ConstructEapolMsg( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AuthMode, ++ IN UCHAR WepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN UCHAR *ReplayCounter, ++ IN UCHAR *KeyNonce, ++ IN UCHAR *TxRSC, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_Len, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ BOOLEAN bWPA2 = FALSE; ++ ++ // Choose WPA2 or not ++ if ((AuthMode == Ndis802_11AuthModeWPA2) || (AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ bWPA2 = TRUE; ++ ++ // Init Packet and Fill header ++ pMsg->ProVer = EAPOL_VER; ++ pMsg->ProType = EAPOLKey; ++ ++ // Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field ++ pMsg->Body_Len[1] = LEN_EAPOL_KEY_MSG; ++ ++ // Fill in EAPoL descriptor ++ if (bWPA2) ++ pMsg->KeyDesc.Type = WPA2_KEY_DESC; ++ else ++ pMsg->KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 ++ // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used. ++ pMsg->KeyDesc.KeyInfo.KeyDescVer = ++ (((WepStatus == Ndis802_11Encryption3Enabled) || (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ // Specify Key Type as Group(0) or Pairwise(1) ++ if (MsgType >= EAPOL_GROUP_MSG_1) ++ pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY; ++ else ++ pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // Specify Key Index, only group_msg1_WPA1 ++ if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1)) ++ pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx; ++ ++ if (MsgType == EAPOL_PAIR_MSG_3) ++ pMsg->KeyDesc.KeyInfo.Install = 1; ++ ++ if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1)) ++ pMsg->KeyDesc.KeyInfo.KeyAck = 1; ++ ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ pMsg->KeyDesc.KeyInfo.KeyMic = 1; ++ ++ if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) || (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) ++ { ++ pMsg->KeyDesc.KeyInfo.Secure = 1; ++ } ++ ++ if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) ++ { ++ pMsg->KeyDesc.KeyInfo.EKD_DL = 1; ++ } ++ ++ // key Information element has done. ++ *(USHORT *)(&pMsg->KeyDesc.KeyInfo) = cpu2le16(*(USHORT *)(&pMsg->KeyDesc.KeyInfo)); ++ ++ // Fill in Key Length ++ { ++ if (MsgType >= EAPOL_GROUP_MSG_1) ++ { ++ // the length of group key cipher ++ pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH : LEN_AES_KEY); ++ } ++ else ++ { ++ // the length of pairwise key cipher ++ pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); ++ } ++ } ++ ++ // Fill in replay counter ++ NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Fill Key Nonce field ++ // ANonce : pairwise_msg1 & pairwise_msg3 ++ // SNonce : pairwise_msg2 ++ // GNonce : group_msg1_wpa1 ++ if ((MsgType <= EAPOL_PAIR_MSG_3) || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)))) ++ NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Fill key IV - WPA2 as 0, WPA1 as random ++ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ // Suggest IV be random number plus some number, ++ NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16], LEN_KEY_DESC_IV); ++ pMsg->KeyDesc.KeyIv[15] += 2; ++ } ++ ++ // Fill Key RSC field ++ // It contains the RSC for the GTK being installed. ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6); ++ } ++ ++ // Clear Key MIC field for MIC calculation later ++ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ ConstructEapolKeyData(pAd, ++ AuthMode, ++ WepStatus, ++ GroupKeyWepStatus, ++ MsgType, ++ DefaultKeyIdx, ++ bWPA2, ++ PTK, ++ GTK, ++ RSNIE, ++ RSNIE_Len, ++ pMsg); ++ ++ // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1. ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ { ++ CalculateMIC(pAd, WepStatus, PTK, pMsg); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); ++ DBGPRINT(RT_DEBUG_TRACE, (" Body length = %d \n", pMsg->Body_Len[1])); ++ DBGPRINT(RT_DEBUG_TRACE, (" Key length = %d \n", pMsg->KeyDesc.KeyLength[1])); ++ ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Construct the Key Data field of EAPoL message ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ConstructEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AuthMode, ++ IN UCHAR WepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN BOOLEAN bWPA2Capable, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_LEN, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ UCHAR *mpool, *Key_Data, *Rc4GTK; ++ UCHAR ekey[(LEN_KEY_DESC_IV+LEN_EAP_EK)]; ++ UCHAR data_offset; ++ ++ ++ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) ++ return; ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1500); ++ ++ if (mpool == NULL) ++ return; ++ ++ /* Rc4GTK Len = 512 */ ++ Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4); ++ /* Key_Data Len = 512 */ ++ Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4); ++ ++ NdisZeroMemory(Key_Data, 512); ++ pMsg->KeyDesc.KeyDataLen[1] = 0; ++ data_offset = 0; ++ ++ // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 ++ if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3))) ++ { ++ if (bWPA2Capable) ++ Key_Data[data_offset + 0] = IE_WPA2; ++ else ++ Key_Data[data_offset + 0] = IE_WPA; ++ ++ Key_Data[data_offset + 1] = RSNIE_LEN; ++ NdisMoveMemory(&Key_Data[data_offset + 2], RSNIE, RSNIE_LEN); ++ data_offset += (2 + RSNIE_LEN); ++ } ++ ++ // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 ++ if (bWPA2Capable && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) ++ { ++ // Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h ++ Key_Data[data_offset + 0] = 0xDD; ++ ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Key_Data[data_offset + 1] = 0x16;// 4+2+16(OUI+DataType+DataField) ++ } ++ else ++ { ++ Key_Data[data_offset + 1] = 0x26;// 4+2+32(OUI+DataType+DataField) ++ } ++ ++ Key_Data[data_offset + 2] = 0x00; ++ Key_Data[data_offset + 3] = 0x0F; ++ Key_Data[data_offset + 4] = 0xAC; ++ Key_Data[data_offset + 5] = 0x01; ++ ++ // GTK KDE format - 802.11i-2004 Figure-43x ++ Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03); ++ Key_Data[data_offset + 7] = 0x00; // Reserved Byte ++ ++ data_offset += 8; ++ } ++ ++ ++ // Encapsulate GTK and encrypt the key-data field with KEK. ++ // Only for pairwise_msg3_WPA2 and group_msg1 ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ // Fill in GTK ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ NdisMoveMemory(&Key_Data[data_offset], GTK, LEN_AES_KEY); ++ data_offset += LEN_AES_KEY; ++ } ++ else ++ { ++ NdisMoveMemory(&Key_Data[data_offset], GTK, TKIP_GTK_LENGTH); ++ data_offset += TKIP_GTK_LENGTH; ++ } ++ ++ // Still dont know why, but if not append will occur "GTK not include in MSG3" ++ // Patch for compatibility between zero config and funk ++ if (MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) ++ { ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Key_Data[data_offset + 0] = 0xDD; ++ Key_Data[data_offset + 1] = 0; ++ data_offset += 2; ++ } ++ else ++ { ++ Key_Data[data_offset + 0] = 0xDD; ++ Key_Data[data_offset + 1] = 0; ++ Key_Data[data_offset + 2] = 0; ++ Key_Data[data_offset + 3] = 0; ++ Key_Data[data_offset + 4] = 0; ++ Key_Data[data_offset + 5] = 0; ++ data_offset += 6; ++ } ++ } ++ ++ // Encrypt the data material in key data field ++ if (WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ AES_GTK_KEY_WRAP(&PTK[16], Key_Data, data_offset, Rc4GTK); ++ // AES wrap function will grow 8 bytes in length ++ data_offset += 8; ++ } ++ else ++ { ++ // PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV) ++ // put TxTsc in Key RSC field ++ pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. ++ ++ // ekey is the contanetion of IV-field, and PTK[16]->PTK[31] ++ NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv, LEN_KEY_DESC_IV); ++ NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &PTK[16], LEN_EAP_EK); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); //INIT SBOX, KEYLEN+3(IV) ++ pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data, data_offset); ++ WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK, Key_Data, data_offset); ++ } ++ ++ NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset); ++ } ++ else ++ { ++ NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset); ++ } ++ ++ // set key data length field and total length ++ pMsg->KeyDesc.KeyDataLen[1] = data_offset; ++ pMsg->Body_Len[1] += data_offset; ++ ++ os_free_mem(pAd, mpool); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calcaulate MIC. It is used during 4-ways handsharking. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PeerWepStatus - indicate the encryption type ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID CalculateMIC( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR *PTK, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ UCHAR *OutBuffer; ++ ULONG FrameLen = 0; ++ UCHAR mic[LEN_KEY_DESC_MIC]; ++ UCHAR digest[80]; ++ ++ // allocate memory for MIC calculation ++ os_alloc_mem(pAd, (PUCHAR *)&OutBuffer, 512); ++ ++ if (OutBuffer == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n")); ++ return; ++ } ++ ++ // make a frame for calculating MIC. ++ MakeOutgoingFrame(OutBuffer, &FrameLen, ++ pMsg->Body_Len[1] + 4, pMsg, ++ END_OF_ARGS); ++ ++ NdisZeroMemory(mic, sizeof(mic)); ++ ++ // Calculate MIC ++ if (PeerWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ HMAC_SHA1(OutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic); ++ } ++ ++ // store the calculated MIC ++ NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC); ++ ++ os_free_mem(pAd, OutBuffer); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Some received frames can't decrypt by Asic, so decrypt them by software. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PeerWepStatus - indicate the encryption type ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS - decryption successful ++ NDIS_STATUS_FAILURE - decryption failure ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPSoftDecryptBroadCastData( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, ++ IN PCIPHER_KEY pShard_key) ++{ ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ ++ ++ ++ // handle WEP decryption ++ if (GroupCipher == Ndis802_11Encryption1Enabled) ++ { ++ if (RTMPSoftDecryptWEP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, pShard_key)) ++ { ++ ++ //Minus IV[4] & ICV[4] ++ pRxWI->MPDUtotalByteCount -= 8; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : Software decrypt WEP data fails.\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ // handle TKIP decryption ++ else if (GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ if (RTMPSoftDecryptTKIP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, pShard_key)) ++ { ++ ++ //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV ++ pRxWI->MPDUtotalByteCount -= 20; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptTKIP Failed\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ // handle AES decryption ++ else if (GroupCipher == Ndis802_11Encryption3Enabled) ++ { ++ if (RTMPSoftDecryptAES(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount , pShard_key)) ++ { ++ ++ //8 bytes MIC, 8 bytes IV/EIV (CCMP Header) ++ pRxWI->MPDUtotalByteCount -= 16; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptAES Failed\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ else ++ { ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/dfs.c +@@ -0,0 +1,453 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ ap_dfs.c ++ ++ Abstract: ++ Support DFS function. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi 03-12-2007 created ++*/ ++ ++#include "../rt_config.h" ++ ++typedef struct _RADAR_DURATION_TABLE ++{ ++ ULONG RDDurRegion; ++ ULONG RadarSignalDuration; ++ ULONG Tolerance; ++} RADAR_DURATION_TABLE, *PRADAR_DURATION_TABLE; ++ ++ ++static UCHAR RdIdleTimeTable[MAX_RD_REGION][4] = ++{ ++ {9, 250, 250, 250}, // CE ++ {4, 250, 250, 250}, // FCC ++ {4, 250, 250, 250}, // JAP ++ {15, 250, 250, 250}, // JAP_W53 ++ {4, 250, 250, 250} // JAP_W56 ++}; ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Bbp Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID BbpRadarDetectionStart( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT8 RadarPeriod; ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 114, 0x02); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 121, 0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 122, 0x00); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 123, 0x08/*0x80*/); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 124, 0x28); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 125, 0xff); ++ ++#if 0 ++ // toggle Rx enable bit for radar detection. ++ // it's Andy's recommand. ++ { ++ UINT32 Value; ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (0x1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ Value &= ~(0x1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++#endif ++ RadarPeriod = ((UINT)RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + (UINT)pAd->CommonCfg.RadarDetect.DfsSessionTime) < 250 ? ++ (RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + pAd->CommonCfg.RadarDetect.DfsSessionTime) : 250; ++ ++ RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); ++ RTMP_IO_WRITE8(pAd, 0x7021, 0x40); ++ ++ RadarDetectionStart(pAd, 0, RadarPeriod); ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Bbp Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID BbpRadarDetectionStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); ++ RTMP_IO_WRITE8(pAd, 0x7021, 0x60); ++ ++ RadarDetectionStop(pAd); ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID RadarDetectionStart( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN CTSProtect, ++ IN UINT8 CTSPeriod) ++{ ++ UINT8 DfsActiveTime = (pAd->CommonCfg.RadarDetect.DfsSessionTime & 0x1f); ++ UINT8 CtsProtect = (CTSProtect == 1) ? 0x02 : 0x01; // CTS protect. ++ ++ if (CTSProtect != 0) ++ { ++ switch(pAd->CommonCfg.RadarDetect.RDDurRegion) ++ { ++ case FCC: ++ case JAP_W56: ++ CtsProtect = 0x03; ++ break; ++ ++ case CE: ++ case JAP_W53: ++ default: ++ CtsProtect = 0x02; ++ break; ++ } ++ } ++ else ++ CtsProtect = 0x01; ++ ++ ++ // send start-RD with CTS protection command to MCU ++ // highbyte [7] reserve ++ // highbyte [6:5] 0x: stop Carrier/Radar detection ++ // highbyte [10]: Start Carrier/Radar detection without CTS protection, 11: Start Carrier/Radar detection with CTS protection ++ // highbyte [4:0] Radar/carrier detection duration. In 1ms. ++ ++ // lowbyte [7:0] Radar/carrier detection period, in 1ms. ++ AsicSendCommandToMcu(pAd, 0x60, 0xff, CTSPeriod, DfsActiveTime | (CtsProtect << 5)); ++ //AsicSendCommandToMcu(pAd, 0x63, 0xff, 10, 0); ++ ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ TRUE Found radar signal ++ FALSE Not found radar signal ++ ++ ======================================================================== ++*/ ++VOID RadarDetectionStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("RadarDetectionStop.\n")); ++ AsicSendCommandToMcu(pAd, 0x60, 0xff, 0x00, 0x00); // send start-RD with CTS protection command to MCU ++ ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar channel check routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ TRUE need to do radar detect ++ FALSE need not to do radar detect ++ ++ ======================================================================== ++*/ ++BOOLEAN RadarChannelCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ch) ++{ ++#if 1 ++ INT i; ++ BOOLEAN result = FALSE; ++ ++ for (i=0; iChannelListNum; i++) ++ { ++ if (Ch == pAd->ChannelList[i].Channel) ++ { ++ result = pAd->ChannelList[i].DfsReq; ++ break; ++ } ++ } ++ ++ return result; ++#else ++ INT i; ++ UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ ++ for (i=0; i<15; i++) ++ { ++ if (Ch == Channel[i]) ++ { ++ break; ++ } ++ } ++ ++ if (i != 15) ++ return TRUE; ++ else ++ return FALSE; ++#endif ++} ++ ++ULONG JapRadarType( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ const UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ ++ if (pAd->CommonCfg.RadarDetect.RDDurRegion != JAP) ++ { ++ return pAd->CommonCfg.RadarDetect.RDDurRegion; ++ } ++ ++ for (i=0; i<15; i++) ++ { ++ if (pAd->CommonCfg.Channel == Channel[i]) ++ { ++ break; ++ } ++ } ++ ++ if (i < 4) ++ return JAP_W53; ++ else if (i < 15) ++ return JAP_W56; ++ else ++ return JAP; // W52 ++ ++} ++ ++ULONG RTMPBbpReadRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT8 byteValue = 0; ++ ULONG result; ++ ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R115, &byteValue); ++ ++ result = 0; ++ switch (byteValue) ++ { ++ case 1: // radar signal detected by pulse mode. ++ case 2: // radar signal detected by width mode. ++ result = RTMPReadRadarDuration(pAd); ++ break; ++ ++ case 0: // No radar signal. ++ default: ++ ++ result = 0; ++ break; ++ } ++ ++ return result; ++} ++ ++ULONG RTMPReadRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG result = 0; ++ ++#ifdef DFS_SUPPORT ++ UINT8 duration1 = 0, duration2 = 0, duration3 = 0; ++ ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R116, &duration1); ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R117, &duration2); ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R118, &duration3); ++ result = (duration1 << 16) + (duration2 << 8) + duration3; ++#endif // DFS_SUPPORT // ++ ++ return result; ++ ++} ++ ++VOID RTMPCleanRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Radar wave detection. The API should be invoke each second. ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID ApRadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i; ++ ++ pAd->CommonCfg.RadarDetect.InServiceMonitorCount++; ++ ++ for (i=0; iChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].RemainingTimeForUse > 0) ++ { ++ pAd->ChannelList[i].RemainingTimeForUse --; ++ if ((pAd->Mlme.PeriodicRound%5) == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RadarDetectPeriodic - ch=%d, RemainingTimeForUse=%d\n", pAd->ChannelList[i].Channel, pAd->ChannelList[i].RemainingTimeForUse)); ++ } ++ } ++ } ++ ++ //radar detect ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ RadarDetectPeriodic(pAd); ++ } ++ ++ return; ++} ++ ++// Periodic Radar detection, switch channel will occur in RTMPHandleTBTTInterrupt() ++// Before switch channel, driver needs doing channel switch announcement. ++VOID RadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // need to check channel availability, after switch channel ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_SILENCE_MODE) ++ return; ++ ++ // channel availability check time is 60sec, use 65 for assurance ++ if (pAd->CommonCfg.RadarDetect.RDCount++ > pAd->CommonCfg.RadarDetect.ChMovingTime) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Not found radar signal, start send beacon and radar detection in service monitor\n\n")); ++ BbpRadarDetectionStop(pAd); ++ AsicEnableBssSync(pAd); ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ ++ ++ return; ++ } ++ ++ return; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ change channel moving time for DFS testing. ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 set ChMovTime=[value] ++ ========================================================================== ++*/ ++INT Set_ChMovingTime_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT8 Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ pAd->CommonCfg.RadarDetect.ChMovingTime = Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ pAd->CommonCfg.RadarDetect.ChMovingTime)); ++ ++ return TRUE; ++} ++ ++INT Set_LongPulseRadarTh_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT8 Value; ++ ++ Value = simple_strtol(arg, 0, 10) > 10 ? 10 : simple_strtol(arg, 0, 10); ++ ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh)); ++ ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/eeprom.c +@@ -0,0 +1,244 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ eeprom.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#include "../rt_config.h" ++ ++// IRQL = PASSIVE_LEVEL ++VOID RaiseClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x) ++{ ++ *x = *x | EESK; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); ++ RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID LowerClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x) ++{ ++ *x = *x & ~EESK; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); ++ RTMPusecDelay(1); ++} ++ ++// IRQL = PASSIVE_LEVEL ++USHORT ShiftInBits( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x,i; ++ USHORT data=0; ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~( EEDO | EEDI); ++ ++ for(i=0; i<16; i++) ++ { ++ data = data << 1; ++ RaiseClock(pAd, &x); ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EEDI); ++ if(x & EEDO) ++ data |= 1; ++ ++ LowerClock(pAd, &x); ++ } ++ ++ return data; ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID ShiftOutBits( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT data, ++ IN USHORT count) ++{ ++ UINT32 x,mask; ++ ++ mask = 0x01 << (count - 1); ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EEDO | EEDI); ++ ++ do ++ { ++ x &= ~EEDI; ++ if(data & mask) x |= EEDI; ++ ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ mask = mask >> 1; ++ } while(mask); ++ ++ x &= ~EEDI; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID EEpromCleanup( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EECS | EEDI); ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++} ++ ++VOID EWEN( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and six pulse in that order ++ ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); ++ ShiftOutBits(pAd, 0, 6); ++ ++ EEpromCleanup(pAd); ++} ++ ++VOID EWDS( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and six pulse in that order ++ ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); ++ ShiftOutBits(pAd, 0, 6); ++ ++ EEpromCleanup(pAd); ++} ++ ++// IRQL = PASSIVE_LEVEL ++USHORT RTMP_EEPROM_READ16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset) ++{ ++ UINT32 x; ++ USHORT data; ++ ++ Offset /= 2; ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and register number in that order ++ ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); ++ ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ++ ++ // Now read the data (16 bits) in from the selected EEPROM word ++ data = ShiftInBits(pAd); ++ ++ EEpromCleanup(pAd); ++ ++ return data; ++} //ReadEEprom ++ ++VOID RTMP_EEPROM_WRITE16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Data) ++{ ++ UINT32 x; ++ ++ Offset /= 2; ++ ++ EWEN(pAd); ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode ,register number and data in that order ++ ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); ++ ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ++ ShiftOutBits(pAd, Data, 16); // 16-bit access ++ ++ // read DO status ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ EEpromCleanup(pAd); ++ ++ RTMPusecDelay(10000); //delay for twp(MAX)=10ms ++ ++ EWDS(pAd); ++ ++ EEpromCleanup(pAd); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/firmware.h +@@ -0,0 +1,558 @@ ++/* ++ Copyright (c) 2007, Ralink Technology Corporation ++ All rights reserved. ++ ++ Redistribution. Redistribution and use in binary form, without ++ modification, are permitted provided that the following conditions are ++ met: ++ ++ * Redistributions must reproduce the above copyright notice and the ++ following disclaimer in the documentation and/or other materials ++ provided with the distribution. ++ * Neither the name of Ralink Technology Corporation nor the names of its ++ suppliers may be used to endorse or promote products derived from this ++ software without specific prior written permission. ++ * No reverse engineering, decompilation, or disassembly of this software ++ is permitted. ++ ++ Limited patent license. Ralink Technology Corporation grants a world-wide, ++ royalty-free, non-exclusive license under patents it now or hereafter ++ owns or controls to make, have made, use, import, offer to sell and ++ sell ("Utilize") this software, but solely to the extent that any ++ such patent is necessary to Utilize the software alone, or in ++ combination with an operating system licensed under an approved Open ++ Source license as listed by the Open Source Initiative at ++ http://opensource.org/licenses. The patent license shall not apply to ++ any other combinations which include this software. No hardware per ++ se is licensed hereunder. ++ ++ DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ++ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ++ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ++ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ++ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ++ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS ++ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ DAMAGE. ++*/ ++/* AUTO GEN PLEASE DO NOT MODIFY IT */ ++/* AUTO GEN PLEASE DO NOT MODIFY IT */ ++ ++ ++UCHAR FirmwareImage [] = { ++0x02, 0x03, 0x5e, 0x02, 0x02, 0xb1, 0x22, 0x22, 0xff, 0xff, 0xff, 0x02, 0x01, 0x82, 0xff, 0xff, ++0xff, 0xff, 0xff, 0x02, 0x00, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x01, 0x33, 0xc0, 0xe0, ++0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18, 0xc2, 0xaf, 0x30, 0x45, 0x03, ++0x12, 0x10, 0x09, 0x90, 0x04, 0x16, 0xe0, 0x30, 0xe3, 0x03, 0x74, 0x08, 0xf0, 0x90, 0x04, 0x14, ++0xe0, 0x20, 0xe7, 0x03, 0x02, 0x00, 0xcb, 0x74, 0x80, 0xf0, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x2f, ++0x90, 0x04, 0x04, 0xe0, 0x24, 0xcf, 0x60, 0x30, 0x14, 0x60, 0x42, 0x24, 0xe2, 0x60, 0x47, 0x14, ++0x60, 0x55, 0x24, 0x21, 0x70, 0x60, 0xe5, 0x55, 0x24, 0xfe, 0x60, 0x07, 0x14, 0x60, 0x08, 0x24, ++0x02, 0x70, 0x08, 0x7d, 0x01, 0x80, 0x28, 0x7d, 0x02, 0x80, 0x24, 0x90, 0x70, 0x10, 0xe0, 0xf5, ++0x50, 0x85, 0x2f, 0x40, 0xd2, 0x01, 0x80, 0x3e, 0xe5, 0x55, 0x64, 0x03, 0x60, 0x04, 0xe5, 0x55, ++0x70, 0x04, 0x7d, 0x02, 0x80, 0x09, 0x85, 0x2f, 0x41, 0xd2, 0x02, 0x80, 0x29, 0xad, 0x55, 0xaf, ++0x2f, 0x12, 0x02, 0x8d, 0x80, 0x20, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x47, 0x90, 0x70, 0x11, 0xe0, ++0xf5, 0x44, 0x12, 0x10, 0x25, 0x80, 0x06, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x45, 0xe4, 0xfd, 0xaf, ++0x2f, 0x12, 0x02, 0x8d, 0xd2, 0x04, 0x90, 0x70, 0x13, 0xe4, 0xf0, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, ++0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x53, 0xc2, ++0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, ++0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x30, 0x90, ++0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, ++0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, ++0x0d, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x02, 0x2c, 0x74, 0xff, 0xf0, 0xc2, 0x05, ++0xd2, 0xaf, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0xe8, 0xc0, 0xe0, ++0xe9, 0xc0, 0xe0, 0xea, 0xc0, 0xe0, 0xeb, 0xc0, 0xe0, 0xec, 0xc0, 0xe0, 0xed, 0xc0, 0xe0, 0xee, ++0xc0, 0xe0, 0xef, 0xc0, 0xe0, 0xc2, 0xaf, 0x30, 0x45, 0x03, 0x12, 0x10, 0x12, 0xd2, 0xaf, 0xd0, ++0xe0, 0xff, 0xd0, 0xe0, 0xfe, 0xd0, 0xe0, 0xfd, 0xd0, 0xe0, 0xfc, 0xd0, 0xe0, 0xfb, 0xd0, 0xe0, ++0xfa, 0xd0, 0xe0, 0xf9, 0xd0, 0xe0, 0xf8, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, ++0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0xc2, ++0xaf, 0x30, 0x45, 0x03, 0x12, 0x10, 0x0c, 0x30, 0x58, 0x0a, 0xe5, 0x54, 0x60, 0x04, 0x15, 0x54, ++0x80, 0x02, 0xc2, 0x58, 0x30, 0x59, 0x0a, 0xe5, 0x50, 0x60, 0x04, 0x15, 0x50, 0x80, 0x02, 0xc2, ++0x59, 0xd5, 0x53, 0x07, 0x30, 0x60, 0x04, 0x15, 0x46, 0xd2, 0x04, 0x30, 0x45, 0x03, 0x12, 0x10, ++0x0f, 0xc2, 0x8d, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, ++0x12, 0x02, 0xd3, 0x30, 0x45, 0x03, 0x12, 0x10, 0x03, 0x30, 0x01, 0x06, 0x20, 0x09, 0x03, 0x12, ++0x10, 0x1c, 0x30, 0x02, 0x06, 0x20, 0x0a, 0x03, 0x12, 0x10, 0x1f, 0x30, 0x03, 0x06, 0x20, 0x0b, ++0x03, 0x12, 0x10, 0x1f, 0x30, 0x04, 0x06, 0x20, 0x0c, 0x03, 0x12, 0x10, 0x22, 0x20, 0x13, 0x09, ++0x20, 0x11, 0x06, 0xe5, 0x2b, 0x45, 0x2c, 0x60, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0xa9, 0x12, ++0x02, 0xec, 0x80, 0xbf, 0xc2, 0x43, 0xd2, 0x45, 0xe4, 0xf5, 0x20, 0xf5, 0x21, 0xf5, 0x53, 0xf5, ++0x46, 0xf5, 0x2b, 0xf5, 0x2c, 0xc2, 0x42, 0xf5, 0x51, 0xf5, 0x52, 0xf5, 0x55, 0x90, 0x04, 0x18, ++0x74, 0x80, 0xf0, 0x90, 0x04, 0x1a, 0x74, 0x08, 0xf0, 0xc2, 0x19, 0xc2, 0x18, 0xc2, 0x1a, 0x22, ++0xc8, 0xef, 0xc8, 0xe6, 0xfa, 0x08, 0xe6, 0x4a, 0x60, 0x0c, 0xc8, 0xef, 0xc8, 0x08, 0xe6, 0x16, ++0x18, 0x70, 0x01, 0x16, 0xc3, 0x22, 0xed, 0x24, 0xff, 0xfd, 0xec, 0x34, 0xff, 0xc8, 0xef, 0xc8, ++0xf6, 0x08, 0xc6, 0xed, 0xc6, 0xd3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, ++0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, ++0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0xef, 0xf4, 0x60, ++0x1f, 0xe4, 0xfe, 0x12, 0x03, 0x6a, 0xe0, 0xb4, 0xff, 0x12, 0x12, 0x03, 0x6a, 0xef, 0xf0, 0x74, ++0x1c, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xe3, ++0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x08, 0xc2, 0xaf, ++0x30, 0x45, 0x03, 0x12, 0x10, 0x06, 0xd2, 0xaf, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, ++0xd0, 0xe0, 0x32, 0xc2, 0xaf, 0x12, 0x00, 0x06, 0x12, 0x02, 0x14, 0x12, 0x03, 0x1c, 0xe4, 0xf5, ++0x22, 0xf5, 0x47, 0x90, 0x04, 0x00, 0x74, 0x80, 0xf0, 0xd2, 0xaf, 0x22, 0x30, 0x45, 0x03, 0x12, ++0x10, 0x15, 0xe5, 0x20, 0x70, 0x03, 0x20, 0x10, 0x03, 0x30, 0x11, 0x03, 0x43, 0x87, 0x01, 0x22, ++0xc0, 0x2a, 0x74, 0x03, 0xc0, 0xe0, 0xc0, 0x82, 0xc0, 0x83, 0x75, 0x2a, 0x0a, 0x22, 0xc0, 0x2a, ++0x74, 0x03, 0xc0, 0xe0, 0xc0, 0x82, 0xc0, 0x83, 0x75, 0x2a, 0x18, 0x22, 0x75, 0x89, 0x02, 0xe4, ++0xf5, 0x8c, 0xf5, 0x8a, 0xf5, 0x88, 0xf5, 0xb8, 0xf5, 0xe8, 0x75, 0x90, 0x18, 0xd2, 0x8c, 0x75, ++0xa8, 0x05, 0x22, 0xce, 0xef, 0xce, 0xee, 0x60, 0x08, 0x7f, 0xff, 0x12, 0x03, 0x80, 0x1e, 0x80, ++0xf5, 0x22, 0xc8, 0xef, 0xc8, 0xe6, 0x60, 0x03, 0x16, 0xc3, 0x22, 0xed, 0x14, 0xf6, 0xd3, 0x22, ++0xc8, 0xef, 0xc8, 0xe6, 0x60, 0x06, 0x16, 0xe6, 0x24, 0xff, 0xb3, 0x22, 0xc3, 0x22, 0x78, 0x7f, ++0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x5f, 0x02, 0x01, 0xd0, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, ++0x34, 0x70, 0xf5, 0x83, 0x22, 0xef, 0x90, 0x03, 0x7e, 0x93, 0x90, 0x03, 0x00, 0x73, 0x0a, 0x18, ++0xef, 0x60, 0x03, 0x1f, 0x80, 0xfa, 0x22, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x3b, 0x02, 0x10, 0x3c, 0x02, 0x12, 0xb8, 0x02, ++0x12, 0xb9, 0x02, 0x13, 0x3e, 0x02, 0x13, 0x3f, 0xc3, 0x22, 0xff, 0xff, 0x02, 0x16, 0x56, 0x02, ++0x17, 0x6b, 0x02, 0x14, 0x2a, 0x02, 0x13, 0x40, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x00, ++0xd8, 0x30, 0x06, 0x06, 0x20, 0x0e, 0x03, 0x12, 0x18, 0x5e, 0x22, 0x22, 0x90, 0x04, 0x14, 0xe0, ++0x20, 0xe7, 0x03, 0x02, 0x12, 0xb7, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, ++0x12, 0x02, 0x67, 0x11, 0x4e, 0x30, 0x11, 0x25, 0x31, 0x10, 0x87, 0x33, 0x10, 0xaa, 0x34, 0x10, ++0xc3, 0x35, 0x11, 0x57, 0x50, 0x11, 0x7b, 0x51, 0x11, 0x84, 0x52, 0x11, 0x84, 0x53, 0x11, 0x84, ++0x54, 0x11, 0xc5, 0x55, 0x11, 0xdc, 0x70, 0x12, 0x07, 0x71, 0x12, 0x34, 0x72, 0x12, 0x5e, 0x80, ++0x12, 0x81, 0x83, 0x00, 0x00, 0x12, 0xb7, 0x75, 0x24, 0x05, 0x75, 0x25, 0xdc, 0x90, 0x70, 0x9f, ++0x74, 0x12, 0xf0, 0xd2, 0x18, 0xd2, 0x61, 0x75, 0x35, 0x0d, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, ++0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0xb7, 0x02, 0x12, 0xaa, 0xc2, 0x18, 0x90, 0x01, 0x14, 0xe0, ++0x54, 0xfd, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0xb7, ++0x02, 0x12, 0xaa, 0xe5, 0x55, 0x64, 0x02, 0x70, 0x37, 0x90, 0x70, 0x10, 0xe0, 0x60, 0x08, 0x90, ++0x01, 0x0d, 0x74, 0x09, 0xf0, 0x80, 0x25, 0xe5, 0x34, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, ++0x60, 0x14, 0x24, 0x03, 0x70, 0x16, 0x90, 0x01, 0x0d, 0x74, 0x08, 0xf0, 0x80, 0x0e, 0x90, 0x01, ++0x0d, 0x74, 0x0b, 0xf0, 0x80, 0x06, 0x90, 0x01, 0x0d, 0x74, 0x1b, 0xf0, 0x7d, 0x01, 0x80, 0x02, ++0x7d, 0x02, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x1b, 0x90, ++0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, ++0x12, 0xb7, 0x02, 0x12, 0xaa, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf, 0x56, 0x12, ++0x02, 0x8d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, ++0x70, 0x03, 0x02, 0x12, 0xb7, 0x02, 0x12, 0xaa, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x22, 0x90, 0x70, ++0x11, 0xe0, 0x24, 0xff, 0x92, 0x1b, 0x22, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, ++0x03, 0x02, 0x12, 0xb7, 0x90, 0x70, 0x11, 0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, ++0x03, 0x02, 0x12, 0xb7, 0x75, 0x4e, 0x03, 0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, ++0xff, 0x92, 0x47, 0x22, 0x90, 0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, ++0x10, 0xe0, 0xff, 0x74, 0x47, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, ++0x74, 0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, ++0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, ++0x12, 0xb7, 0x02, 0x12, 0xaa, 0xe5, 0x47, 0xb4, 0x07, 0x08, 0x90, 0x70, 0x11, 0xe0, 0x54, 0x07, ++0xf5, 0x26, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0xd2, 0x04, 0x22, 0x90, 0x70, 0x10, 0xe0, ++0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x02, ++0x8d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, ++0x03, 0x02, 0x12, 0xb7, 0x02, 0x12, 0xaa, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, ++0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, ++0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, ++0x12, 0xb7, 0x80, 0x76, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x26, 0xff, 0xc2, 0x19, 0xc2, 0x18, ++0xc2, 0x1a, 0x75, 0x34, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, 0x04, 0x14, 0x74, ++0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x5b, 0x80, 0x4c, 0x90, 0x70, ++0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, ++0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x38, 0x80, ++0x29, 0x90, 0x70, 0x10, 0xe0, 0xf5, 0x34, 0xd3, 0x94, 0x00, 0x40, 0x07, 0x90, 0x01, 0x0d, 0xe0, ++0x54, 0xfb, 0xf0, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x02, 0x8d, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, ++0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x0d, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, ++0xf0, 0x90, 0x02, 0x2c, 0x74, 0xff, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x60, 0x03, 0x02, 0x13, 0x3d, ++0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0xa2, 0x19, ++0xe4, 0x33, 0x90, 0x70, 0x90, 0xf0, 0xa2, 0x18, 0xe4, 0x33, 0xa3, 0xf0, 0x30, 0x19, 0x4d, 0x90, ++0x70, 0x98, 0x74, 0x23, 0xf0, 0xa3, 0xe5, 0x25, 0xf0, 0xe5, 0x24, 0xa3, 0xf0, 0x7f, 0x35, 0x7d, ++0x32, 0x12, 0x03, 0x42, 0x50, 0x09, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf7, 0xf0, 0xd2, 0x06, 0xe5, ++0x35, 0xd3, 0x94, 0x10, 0x40, 0x1e, 0x30, 0x1a, 0x1b, 0xc2, 0x1a, 0xa2, 0x18, 0x92, 0x19, 0x20, ++0x19, 0x12, 0x90, 0x04, 0x09, 0xe0, 0x54, 0xdd, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x08, 0xf0, ++0xc2, 0x61, 0xd2, 0x03, 0xe5, 0x35, 0xb4, 0x0b, 0x14, 0xd2, 0x03, 0x22, 0xe4, 0xf5, 0x35, 0xa2, ++0x18, 0x92, 0x19, 0x30, 0x19, 0x07, 0x90, 0x04, 0x09, 0xe0, 0x44, 0x22, 0xf0, 0x22, 0x22, 0x22, ++0xc2, 0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x02, 0x67, 0x13, 0x62, 0x00, 0x13, 0xf5, 0x04, 0x13, ++0xf1, 0x08, 0x13, 0xcc, 0x10, 0x13, 0x76, 0x20, 0x13, 0x96, 0x60, 0x13, 0xa7, 0xa0, 0x00, 0x00, ++0x13, 0xf7, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, ++0x03, 0x02, 0x13, 0xf7, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, ++0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, ++0x66, 0x53, 0x43, 0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, ++0x47, 0x64, 0x06, 0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, ++0xc4, 0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, ++0x70, 0x35, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, ++0x06, 0x53, 0x5e, 0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, ++0x42, 0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, ++0x06, 0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x38, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, ++0xe5, 0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, ++0xe5, 0x4a, 0xf0, 0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, ++0xe5, 0x42, 0xf0, 0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, ++0x70, 0x03, 0x12, 0x16, 0x36, 0x12, 0x14, 0x3f, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, ++0xaf, 0x90, 0x04, 0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x1c, 0x80, 0x08, 0xe5, 0x4e, 0x45, ++0x4f, 0x24, 0xff, 0x92, 0x1c, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x1d, 0x74, ++0x1e, 0xf0, 0xe5, 0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x38, 0x70, 0x13, 0x30, 0x1c, 0x05, 0xe5, ++0x5f, 0x20, 0xe5, 0x0b, 0x30, 0x1d, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, ++0x38, 0x70, 0x05, 0x75, 0x38, 0x0c, 0x80, 0x02, 0x15, 0x38, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, ++0xe5, 0x5f, 0x30, 0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, ++0x47, 0x64, 0x03, 0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x38, ++0x70, 0x03, 0x30, 0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x38, 0x70, 0x05, 0x75, 0x38, 0x07, 0x80, 0x02, ++0x15, 0x38, 0xd2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5, 0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, ++0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5, 0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, ++0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c, 0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, ++0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x15, 0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, ++0xe3, 0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, ++0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, 0x15, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, ++0xe3, 0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, ++0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, 0x80, 0x15, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, ++0xe3, 0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, ++0x71, 0x92, 0x70, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x46, 0x90, ++0x02, 0x29, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, ++0x60, 0x1f, 0x24, 0x03, 0x60, 0x03, 0x02, 0x16, 0x35, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0d, ++0x80, 0x07, 0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x04, 0x54, 0xfe, 0xf0, 0x22, 0x44, 0x01, 0xf0, ++0x22, 0xe5, 0x46, 0x30, 0xe3, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02, 0x28, 0xe0, ++0x54, 0xfe, 0x4f, 0xf0, 0x22, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x03, 0x02, 0x16, 0x35, 0xf5, 0x27, ++0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x26, 0x14, 0x60, 0x26, 0x14, 0x60, 0x2e, 0x14, ++0x60, 0x36, 0x24, 0x03, 0x70, 0x5f, 0xe5, 0x46, 0x13, 0x13, 0x13, 0x54, 0x1f, 0x75, 0xf0, 0x03, ++0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, ++0x80, 0x02, 0xa2, 0x47, 0x92, 0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x3f, 0xe5, 0x46, 0x30, ++0xe3, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe3, 0x0d, 0x54, 0x70, 0xc3, ++0x94, 0x60, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, 0x47, ++0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, 0x47, ++0xb3, 0x92, 0x39, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, 0x02, 0x28, 0xe0, ++0x54, 0xfc, 0x45, 0x27, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45, ++0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59, ++0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x30, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x4a, ++0x14, 0x60, 0x6a, 0x24, 0x02, 0x60, 0x03, 0x02, 0x17, 0x4c, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x20, ++0x19, 0x1c, 0x90, 0x02, 0x08, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x04, 0x34, ++0xe0, 0xb4, 0x02, 0x1c, 0xa3, 0xe0, 0xb4, 0x02, 0x17, 0xa3, 0xe0, 0xb4, 0x02, 0x12, 0x7f, 0x20, ++0x12, 0x16, 0x4c, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x02, 0x17, 0x4c, ++0xe5, 0x50, 0x70, 0x06, 0x75, 0x30, 0x03, 0x02, 0x17, 0x4c, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, ++0x70, 0x15, 0x7f, 0x20, 0x12, 0x16, 0x4c, 0x20, 0x19, 0x07, 0x90, 0x02, 0x08, 0xe0, 0x54, 0xfb, ++0xf0, 0x75, 0x51, 0x02, 0x02, 0x17, 0x4c, 0xe5, 0x50, 0x70, 0x02, 0x80, 0x7a, 0x20, 0x19, 0x0f, ++0x90, 0x02, 0x08, 0xe0, 0x20, 0xe3, 0x6c, 0x90, 0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x64, 0x90, ++0x12, 0x04, 0x74, 0x0a, 0xf0, 0x30, 0x1b, 0x11, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, ++0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x20, 0x19, 0x07, 0x90, 0x04, 0x01, 0xe0, ++0x44, 0x10, 0xf0, 0xe5, 0x34, 0xf4, 0x90, 0x04, 0x01, 0x60, 0x06, 0xe0, 0x54, 0xfb, 0xf0, 0x80, ++0x04, 0xe0, 0x54, 0xf9, 0xf0, 0x20, 0x19, 0x07, 0x90, 0x12, 0x04, 0xe0, 0x44, 0x04, 0xf0, 0xe5, ++0x34, 0xf4, 0x60, 0x14, 0x90, 0x01, 0x0d, 0xe0, 0xf5, 0x33, 0xe5, 0x34, 0xd3, 0x94, 0x02, 0x40, ++0x07, 0x90, 0x12, 0x04, 0xe0, 0x54, 0xfd, 0xf0, 0x75, 0x30, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, ++0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x30, 0x03, 0xf5, 0x51, 0xe5, 0x30, 0x60, 0x18, ++0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0x20, 0x19, 0x0e, 0xad, 0x30, 0xaf, 0x40, 0x12, 0x18, ++0x2a, 0xe5, 0x30, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x30, 0x01, 0x0e, ++0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, 0x02, 0xaf, 0x40, 0x12, 0x18, 0x2a, 0xe5, 0x52, ++0x14, 0x60, 0x55, 0x14, 0x60, 0x2f, 0x24, 0x02, 0x60, 0x03, 0x02, 0x18, 0x27, 0xe5, 0x34, 0xf4, ++0x60, 0x23, 0xe5, 0x34, 0xd3, 0x94, 0x02, 0x40, 0x16, 0x90, 0x12, 0x04, 0xe0, 0x44, 0x02, 0xf0, ++0x90, 0x01, 0x0d, 0xe0, 0x20, 0xe3, 0x03, 0x02, 0x18, 0x27, 0x7f, 0x50, 0x12, 0x16, 0x51, 0x75, ++0x52, 0x02, 0x75, 0x55, 0x03, 0xe5, 0x34, 0xf4, 0x60, 0x0a, 0xe5, 0x54, 0x70, 0x69, 0x90, 0x01, ++0x0d, 0xe5, 0x33, 0xf0, 0x90, 0x12, 0x04, 0xe0, 0x54, 0xfb, 0xf0, 0x7f, 0x20, 0x12, 0x16, 0x51, ++0x75, 0x52, 0x01, 0x75, 0x55, 0x03, 0x80, 0x4f, 0xe5, 0x54, 0x70, 0x4b, 0x90, 0x04, 0x01, 0xe0, ++0x44, 0x0e, 0xf0, 0x20, 0x19, 0x04, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44, 0x0f, ++0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, 0x03, ++0xf0, 0x20, 0x19, 0x07, 0x90, 0x02, 0x08, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, ++0x0c, 0xf0, 0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, ++0x12, 0x18, 0x2a, 0x80, 0x02, 0xc2, 0x03, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4, 0xfe, ++0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74, 0x14, ++0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82, 0xe4, ++0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, 0x22, 0x20, 0x19, ++0x03, 0x02, 0x19, 0x0f, 0x90, 0x70, 0x80, 0xe0, 0x04, 0xf0, 0x90, 0x04, 0x37, 0xe0, 0x30, 0xe5, ++0x03, 0x02, 0x19, 0x0b, 0x90, 0x04, 0x28, 0xe0, 0xf5, 0x31, 0xa3, 0xe0, 0xf5, 0x30, 0xf5, 0x32, ++0xe4, 0xf5, 0x37, 0x90, 0x70, 0x81, 0xe0, 0x04, 0xf0, 0x90, 0x70, 0x82, 0xe0, 0x04, 0xf0, 0xe5, ++0x32, 0x75, 0xf0, 0x80, 0xa4, 0x24, 0x00, 0xff, 0xe5, 0xf0, 0x34, 0x80, 0xfe, 0xe5, 0x30, 0x65, ++0x32, 0x70, 0x05, 0xfc, 0x7d, 0x18, 0x80, 0x04, 0x7c, 0x00, 0x7d, 0x00, 0xef, 0x2d, 0xff, 0xee, ++0x3c, 0xfe, 0x12, 0x19, 0x10, 0x50, 0x25, 0x90, 0x70, 0x83, 0xe0, 0x04, 0xf0, 0x90, 0x01, 0x14, ++0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x30, 0xe1, 0x06, 0x90, 0x70, 0x92, 0x74, 0x45, 0xf0, 0x90, 0x70, ++0x93, 0xe0, 0x04, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x90, 0x70, 0x94, 0xf0, 0xe5, 0x32, 0x65, 0x31, ++0x60, 0x10, 0xe4, 0x25, 0x32, 0xff, 0xe4, 0x34, 0x80, 0x8f, 0x82, 0xf5, 0x83, 0xe0, 0xf5, 0x32, ++0x80, 0x97, 0x90, 0x04, 0x10, 0x74, 0x01, 0xf0, 0x90, 0x04, 0x28, 0xe5, 0x31, 0xf0, 0xa3, 0xe5, ++0x30, 0xf0, 0x90, 0x04, 0x11, 0x74, 0x01, 0xf0, 0x02, 0x18, 0x6a, 0xc2, 0x06, 0xd2, 0x1a, 0x22, ++0x90, 0x70, 0x84, 0xe5, 0x37, 0xf0, 0xc3, 0x94, 0x06, 0x50, 0x19, 0x8f, 0x82, 0x8e, 0x83, 0xe0, ++0xb4, 0xff, 0x07, 0x05, 0x37, 0xe4, 0xf5, 0x36, 0x80, 0x59, 0xe4, 0xf5, 0x37, 0x8f, 0x82, 0x8e, ++0x83, 0xf0, 0x80, 0x4f, 0xe5, 0x36, 0x75, 0xf0, 0x06, 0x84, 0x74, 0x08, 0x25, 0xf0, 0xf5, 0x82, ++0xe4, 0x34, 0x10, 0xf5, 0x83, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0x6d, 0x70, 0x30, ++0x90, 0x70, 0x88, 0xe0, 0x04, 0xf0, 0xa3, 0xe0, 0xfd, 0xd3, 0x95, 0x37, 0x40, 0x02, 0x80, 0x02, ++0xad, 0x37, 0x90, 0x70, 0x89, 0xed, 0xf0, 0x05, 0x37, 0x05, 0x36, 0xe5, 0x36, 0x75, 0xf0, 0x06, ++0x84, 0x74, 0x8a, 0x25, 0xf0, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x03, ++0xe4, 0xf5, 0x37, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0xef, 0x54, 0x7f, 0x60, 0x0a, 0xe5, 0x37, 0xc3, ++0x94, 0x4e, 0x50, 0x03, 0x02, 0x19, 0x10, 0xe5, 0x37, 0xb4, 0x4e, 0x03, 0xd3, 0x80, 0x01, 0xc3, ++0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x94, 0xeb, } ; +--- /dev/null ++++ b/drivers/staging/rt2860/common/md5.c +@@ -0,0 +1,1427 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ md5.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ jan 10-28-03 Initial ++ Rita 11-23-04 Modify MD5 and SHA-1 ++ Rita 10-14-05 Modify SHA-1 in big-endian platform ++ */ ++#include "../rt_config.h" ++ ++/** ++ * md5_mac: ++ * @key: pointer to the key used for MAC generation ++ * @key_len: length of the key in bytes ++ * @data: pointer to the data area for which the MAC is generated ++ * @data_len: length of the data in bytes ++ * @mac: pointer to the buffer holding space for the MAC; the buffer should ++ * have space for 128-bit (16 bytes) MD5 hash value ++ * ++ * md5_mac() determines the message authentication code by using secure hash ++ * MD5(key | data | key). ++ */ ++void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) ++{ ++ MD5_CTX context; ++ ++ MD5Init(&context); ++ MD5Update(&context, key, key_len); ++ MD5Update(&context, data, data_len); ++ MD5Update(&context, key, key_len); ++ MD5Final(mac, &context); ++} ++ ++/** ++ * hmac_md5: ++ * @key: pointer to the key used for MAC generation ++ * @key_len: length of the key in bytes ++ * @data: pointer to the data area for which the MAC is generated ++ * @data_len: length of the data in bytes ++ * @mac: pointer to the buffer holding space for the MAC; the buffer should ++ * have space for 128-bit (16 bytes) MD5 hash value ++ * ++ * hmac_md5() determines the message authentication code using HMAC-MD5. ++ * This implementation is based on the sample code presented in RFC 2104. ++ */ ++void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) ++{ ++ MD5_CTX context; ++ u8 k_ipad[65]; /* inner padding - key XORd with ipad */ ++ u8 k_opad[65]; /* outer padding - key XORd with opad */ ++ u8 tk[16]; ++ int i; ++ ++ //assert(key != NULL && data != NULL && mac != NULL); ++ ++ /* if key is longer than 64 bytes reset it to key = MD5(key) */ ++ if (key_len > 64) { ++ MD5_CTX ttcontext; ++ ++ MD5Init(&ttcontext); ++ MD5Update(&ttcontext, key, key_len); ++ MD5Final(tk, &ttcontext); ++ //key=(PUCHAR)ttcontext.buf; ++ key = tk; ++ key_len = 16; ++ } ++ ++ /* the HMAC_MD5 transform looks like: ++ * ++ * MD5(K XOR opad, MD5(K XOR ipad, text)) ++ * ++ * where K is an n byte key ++ * ipad is the byte 0x36 repeated 64 times ++ * opad is the byte 0x5c repeated 64 times ++ * and text is the data being protected */ ++ ++ /* start out by storing key in pads */ ++ NdisZeroMemory(k_ipad, sizeof(k_ipad)); ++ NdisZeroMemory(k_opad, sizeof(k_opad)); ++ //assert(key_len < sizeof(k_ipad)); ++ NdisMoveMemory(k_ipad, key, key_len); ++ NdisMoveMemory(k_opad, key, key_len); ++ ++ /* XOR key with ipad and opad values */ ++ for (i = 0; i < 64; i++) { ++ k_ipad[i] ^= 0x36; ++ k_opad[i] ^= 0x5c; ++ } ++ ++ /* perform inner MD5 */ ++ MD5Init(&context); /* init context for 1st pass */ ++ MD5Update(&context, k_ipad, 64); /* start with inner pad */ ++ MD5Update(&context, data, data_len); /* then text of datagram */ ++ MD5Final(mac, &context); /* finish up 1st pass */ ++ ++ /* perform outer MD5 */ ++ MD5Init(&context); /* init context for 2nd pass */ ++ MD5Update(&context, k_opad, 64); /* start with outer pad */ ++ MD5Update(&context, mac, 16); /* then results of 1st hash */ ++ MD5Final(mac, &context); /* finish up 2nd pass */ ++} ++ ++#ifndef RT_BIG_ENDIAN ++#define byteReverse(buf, len) /* Nothing */ ++#else ++void byteReverse(unsigned char *buf, unsigned longs); ++void byteReverse(unsigned char *buf, unsigned longs) ++{ ++ do { ++ *(UINT32 *)buf = SWAP32(*(UINT32 *)buf); ++ buf += 4; ++ } while (--longs); ++} ++#endif ++ ++ ++/* ========================== MD5 implementation =========================== */ ++// four base functions for MD5 ++#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z))) ++#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z))) ++#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z)) ++#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z))) ++#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s)))) ++ ++#define MD5Step(f, w, x, y, z, data, t, s) \ ++ ( w += f(x, y, z) + data + t, w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w += x ) ++ ++ ++/* ++ * Function Description: ++ * Initiate MD5 Context satisfied in RFC 1321 ++ * ++ * Arguments: ++ * pCtx Pointer to MD5 context ++ * ++ * Return Value: ++ * None ++ */ ++VOID MD5Init(MD5_CTX *pCtx) ++{ ++ pCtx->Buf[0]=0x67452301; ++ pCtx->Buf[1]=0xefcdab89; ++ pCtx->Buf[2]=0x98badcfe; ++ pCtx->Buf[3]=0x10325476; ++ ++ pCtx->LenInBitCount[0]=0; ++ pCtx->LenInBitCount[1]=0; ++} ++ ++ ++/* ++ * Function Description: ++ * Update MD5 Context, allow of an arrary of octets as the next portion ++ * of the message ++ * ++ * Arguments: ++ * pCtx Pointer to MD5 context ++ * pData Pointer to input data ++ * LenInBytes The length of input data (unit: byte) ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called after MD5Init or MD5Update(itself) ++ */ ++VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) ++{ ++ ++ UINT32 TfTimes; ++ UINT32 temp; ++ unsigned int i; ++ ++ temp = pCtx->LenInBitCount[0]; ++ ++ pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); ++ ++ if (pCtx->LenInBitCount[0] < temp) ++ pCtx->LenInBitCount[1]++; //carry in ++ ++ pCtx->LenInBitCount[1] += LenInBytes >> 29; ++ ++ // mod 64 bytes ++ temp = (temp >> 3) & 0x3f; ++ ++ // process lacks of 64-byte data ++ if (temp) ++ { ++ UCHAR *pAds = (UCHAR *) pCtx->Input + temp; ++ ++ if ((temp+LenInBytes) < 64) ++ { ++ NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); ++ return; ++ } ++ ++ NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp); ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ pData += 64-temp; ++ LenInBytes -= 64-temp; ++ } // end of if (temp) ++ ++ ++ TfTimes = (LenInBytes >> 6); ++ ++ for (i=TfTimes; i>0; i--) ++ { ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ pData += 64; ++ LenInBytes -= 64; ++ } // end of for ++ ++ // buffering lacks of 64-byte data ++ if(LenInBytes) ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); ++ ++} ++ ++ ++/* ++ * Function Description: ++ * Append padding bits and length of original message in the tail ++ * The message digest has to be completed in the end ++ * ++ * Arguments: ++ * Digest Output of Digest-Message for MD5 ++ * pCtx Pointer to MD5 context ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called after MD5Update ++ */ ++VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx) ++{ ++ UCHAR Remainder; ++ UCHAR PadLenInBytes; ++ UCHAR *pAppend=0; ++ unsigned int i; ++ ++ Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); ++ ++ PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); ++ ++ pAppend = (UCHAR *)pCtx->Input + Remainder; ++ ++ // padding bits without crossing block(64-byte based) boundary ++ if (Remainder < 56) ++ { ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); ++ ++ // add data-length field, from low to high ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); ++ } ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of if ++ ++ // padding bits with crossing block(64-byte based) boundary ++ else ++ { ++ // the first block === ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); ++ PadLenInBytes -= (64 - Remainder - 1); ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ ++ // the second block === ++ NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); ++ ++ // add data-length field ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); ++ } ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of else ++ ++ ++ NdisMoveMemory((UCHAR *)Digest, (UINT32 *)pCtx->Buf, 16); // output ++ byteReverse((UCHAR *)Digest, 4); ++ NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free ++} ++ ++ ++/* ++ * Function Description: ++ * The central algorithm of MD5, consists of four rounds and sixteen ++ * steps per round ++ * ++ * Arguments: ++ * Buf Buffers of four states (output: 16 bytes) ++ * Mes Input data (input: 64 bytes) ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called by MD5Update or MD5Final ++ */ ++VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]) ++{ ++ UINT32 Reg[4], Temp; ++ unsigned int i; ++ ++ static UCHAR LShiftVal[16] = ++ { ++ 7, 12, 17, 22, ++ 5, 9 , 14, 20, ++ 4, 11, 16, 23, ++ 6, 10, 15, 21, ++ }; ++ ++ ++ // [equal to 4294967296*abs(sin(index))] ++ static UINT32 MD5Table[64] = ++ { ++ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, ++ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, ++ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, ++ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, ++ ++ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, ++ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, ++ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, ++ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, ++ ++ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, ++ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, ++ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, ++ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, ++ ++ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, ++ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, ++ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, ++ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ++ }; ++ ++ ++ for (i=0; i<4; i++) ++ Reg[i]=Buf[i]; ++ ++ ++ // 64 steps in MD5 algorithm ++ for (i=0; i<16; i++) ++ { ++ MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i], ++ MD5Table[i], LShiftVal[i & 0x3]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=16; i<32; i++) ++ { ++ MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], ++ MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=32; i<48; i++) ++ { ++ MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], ++ MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=48; i<64; i++) ++ { ++ MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], ++ MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ ++ ++ // (temporary)output ++ for (i=0; i<4; i++) ++ Buf[i] += Reg[i]; ++ ++} ++ ++ ++ ++/* ========================= SHA-1 implementation ========================== */ ++// four base functions for SHA-1 ++#define SHA1_F1(b, c, d) (((b) & (c)) | ((~b) & (d))) ++#define SHA1_F2(b, c, d) ((b) ^ (c) ^ (d)) ++#define SHA1_F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) ++ ++ ++#define SHA1Step(f, a, b, c, d, e, w, k) \ ++ ( e += ( f(b, c, d) + w + k + CYCLIC_LEFT_SHIFT(a, 5)) & 0xffffffff, \ ++ b = CYCLIC_LEFT_SHIFT(b, 30) ) ++ ++//Initiate SHA-1 Context satisfied in RFC 3174 ++VOID SHAInit(SHA_CTX *pCtx) ++{ ++ pCtx->Buf[0]=0x67452301; ++ pCtx->Buf[1]=0xefcdab89; ++ pCtx->Buf[2]=0x98badcfe; ++ pCtx->Buf[3]=0x10325476; ++ pCtx->Buf[4]=0xc3d2e1f0; ++ ++ pCtx->LenInBitCount[0]=0; ++ pCtx->LenInBitCount[1]=0; ++} ++ ++/* ++ * Function Description: ++ * Update SHA-1 Context, allow of an arrary of octets as the next ++ * portion of the message ++ * ++ * Arguments: ++ * pCtx Pointer to SHA-1 context ++ * pData Pointer to input data ++ * LenInBytes The length of input data (unit: byte) ++ * ++ * Return Value: ++ * error indicate more than pow(2,64) bits of data ++ * ++ * Note: ++ * Called after SHAInit or SHAUpdate(itself) ++ */ ++UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) ++{ ++ UINT32 TfTimes; ++ UINT32 temp1,temp2; ++ unsigned int i; ++ UCHAR err=1; ++ ++ temp1 = pCtx->LenInBitCount[0]; ++ temp2 = pCtx->LenInBitCount[1]; ++ ++ pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); ++ if (pCtx->LenInBitCount[0] < temp1) ++ pCtx->LenInBitCount[1]++; //carry in ++ ++ ++ pCtx->LenInBitCount[1] = (UINT32) (pCtx->LenInBitCount[1] +(LenInBytes >> 29)); ++ if (pCtx->LenInBitCount[1] < temp2) ++ return (err); //check total length of original data ++ ++ ++ // mod 64 bytes ++ temp1 = (temp1 >> 3) & 0x3f; ++ ++ // process lacks of 64-byte data ++ if (temp1) ++ { ++ UCHAR *pAds = (UCHAR *) pCtx->Input + temp1; ++ ++ if ((temp1+LenInBytes) < 64) ++ { ++ NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); ++ return (0); ++ } ++ ++ NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp1); ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ pData += 64-temp1; ++ LenInBytes -= 64-temp1; ++ } // end of if (temp1) ++ ++ ++ TfTimes = (LenInBytes >> 6); ++ ++ for (i=TfTimes; i>0; i--) ++ { ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ pData += 64; ++ LenInBytes -= 64; ++ } // end of for ++ ++ // buffering lacks of 64-byte data ++ if(LenInBytes) ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); ++ ++ return (0); ++ ++} ++ ++// Append padding bits and length of original message in the tail ++// The message digest has to be completed in the end ++VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]) ++{ ++ UCHAR Remainder; ++ UCHAR PadLenInBytes; ++ UCHAR *pAppend=0; ++ unsigned int i; ++ ++ Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); ++ ++ pAppend = (UCHAR *)pCtx->Input + Remainder; ++ ++ PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); ++ ++ // padding bits without crossing block(64-byte based) boundary ++ if (Remainder < 56) ++ { ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); ++ ++ // add data-length field, from high to low ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); ++ } ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 14); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of if ++ ++ // padding bits with crossing block(64-byte based) boundary ++ else ++ { ++ // the first block === ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); ++ PadLenInBytes -= (64 - Remainder - 1); ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ ++ // the second block === ++ NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); ++ ++ // add data-length field ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); ++ } ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of else ++ ++ ++ //Output, bytereverse ++ for (i=0; i<20; i++) ++ { ++ Digest [i] = (UCHAR)(pCtx->Buf[i>>2] >> 8*(3-(i & 0x3))); ++ } ++ ++ NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free ++} ++ ++ ++// The central algorithm of SHA-1, consists of four rounds and ++// twenty steps per round ++VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]) ++{ ++ UINT32 Reg[5],Temp; ++ unsigned int i; ++ UINT32 W[80]; ++ ++ static UINT32 SHA1Table[4] = { 0x5a827999, 0x6ed9eba1, ++ 0x8f1bbcdc, 0xca62c1d6 }; ++ ++ Reg[0]=Buf[0]; ++ Reg[1]=Buf[1]; ++ Reg[2]=Buf[2]; ++ Reg[3]=Buf[3]; ++ Reg[4]=Buf[4]; ++ ++ //the first octet of a word is stored in the 0th element, bytereverse ++ for(i = 0; i < 16; i++) ++ { ++ W[i] = (Mes[i] >> 24) & 0xff; ++ W[i] |= (Mes[i] >> 8 ) & 0xff00; ++ W[i] |= (Mes[i] << 8 ) & 0xff0000; ++ W[i] |= (Mes[i] << 24) & 0xff000000; ++ } ++ ++ ++ for (i = 0; i < 64; i++) ++ W[16+i] = CYCLIC_LEFT_SHIFT(W[i] ^ W[2+i] ^ W[8+i] ^ W[13+i], 1); ++ ++ ++ // 80 steps in SHA-1 algorithm ++ for (i=0; i<80; i++) ++ { ++ if (i<20) ++ SHA1Step(SHA1_F1, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[0]); ++ ++ else if (i>=20 && i<40) ++ SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[1]); ++ ++ else if (i>=40 && i<60) ++ SHA1Step(SHA1_F3, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[2]); ++ ++ else ++ SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[3]); ++ ++ ++ // one-word right shift ++ Temp = Reg[4]; ++ Reg[4] = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ ++ } // end of for-loop ++ ++ ++ // (temporary)output ++ for (i=0; i<5; i++) ++ Buf[i] += Reg[i]; ++ ++} ++ ++ ++/* ========================= AES En/Decryption ========================== */ ++ ++/* forward S-box */ ++static uint32 FSb[256] = ++{ ++ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, ++ 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, ++ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, ++ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, ++ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, ++ 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, ++ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, ++ 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, ++ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, ++ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, ++ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, ++ 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, ++ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, ++ 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, ++ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, ++ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, ++ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, ++ 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, ++ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, ++ 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, ++ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, ++ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, ++ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, ++ 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, ++ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, ++ 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, ++ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, ++ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, ++ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, ++ 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, ++ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, ++ 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 ++}; ++ ++/* forward table */ ++#define FT \ ++\ ++ V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ ++ V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ ++ V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ ++ V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ ++ V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ ++ V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ ++ V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ ++ V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ ++ V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ ++ V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ ++ V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ ++ V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ ++ V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ ++ V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ ++ V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ ++ V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ ++ V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ ++ V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ ++ V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ ++ V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ ++ V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ ++ V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ ++ V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ ++ V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ ++ V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ ++ V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ ++ V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ ++ V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ ++ V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ ++ V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ ++ V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ ++ V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ ++ V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ ++ V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ ++ V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ ++ V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ ++ V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ ++ V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ ++ V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ ++ V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ ++ V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ ++ V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ ++ V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ ++ V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ ++ V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ ++ V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ ++ V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ ++ V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ ++ V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ ++ V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ ++ V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ ++ V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ ++ V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ ++ V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ ++ V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ ++ V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ ++ V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ ++ V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ ++ V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ ++ V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ ++ V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ ++ V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ ++ V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ ++ V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) ++ ++#define V(a,b,c,d) 0x##a##b##c##d ++static uint32 FT0[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##d##a##b##c ++static uint32 FT1[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##c##d##a##b ++static uint32 FT2[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##b##c##d##a ++static uint32 FT3[256] = { FT }; ++#undef V ++ ++#undef FT ++ ++/* reverse S-box */ ++ ++static uint32 RSb[256] = ++{ ++ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, ++ 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, ++ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, ++ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, ++ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, ++ 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, ++ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, ++ 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, ++ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, ++ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, ++ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, ++ 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, ++ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, ++ 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, ++ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, ++ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, ++ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, ++ 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, ++ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, ++ 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, ++ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, ++ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, ++ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, ++ 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, ++ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, ++ 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, ++ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, ++ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, ++ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, ++ 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, ++ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, ++ 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ++}; ++ ++/* reverse table */ ++ ++#define RT \ ++\ ++ V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ ++ V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ ++ V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ ++ V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ ++ V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ ++ V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ ++ V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ ++ V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ ++ V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ ++ V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ ++ V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ ++ V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ ++ V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ ++ V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ ++ V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ ++ V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ ++ V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ ++ V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ ++ V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ ++ V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ ++ V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ ++ V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ ++ V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ ++ V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ ++ V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ ++ V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ ++ V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ ++ V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ ++ V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ ++ V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ ++ V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ ++ V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ ++ V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ ++ V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ ++ V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ ++ V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ ++ V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ ++ V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ ++ V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ ++ V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ ++ V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ ++ V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ ++ V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ ++ V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ ++ V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ ++ V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ ++ V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ ++ V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ ++ V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ ++ V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ ++ V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ ++ V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ ++ V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ ++ V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ ++ V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ ++ V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ ++ V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ ++ V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ ++ V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ ++ V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ ++ V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ ++ V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ ++ V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ ++ V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) ++ ++#define V(a,b,c,d) 0x##a##b##c##d ++static uint32 RT0[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##d##a##b##c ++static uint32 RT1[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##c##d##a##b ++static uint32 RT2[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##b##c##d##a ++static uint32 RT3[256] = { RT }; ++#undef V ++ ++#undef RT ++ ++/* round constants */ ++ ++static uint32 RCON[10] = ++{ ++ 0x01000000, 0x02000000, 0x04000000, 0x08000000, ++ 0x10000000, 0x20000000, 0x40000000, 0x80000000, ++ 0x1B000000, 0x36000000 ++}; ++ ++/* key schedule tables */ ++ ++static int KT_init = 1; ++ ++static uint32 KT0[256]; ++static uint32 KT1[256]; ++static uint32 KT2[256]; ++static uint32 KT3[256]; ++ ++/* platform-independant 32-bit integer manipulation macros */ ++ ++#define GET_UINT32(n,b,i) \ ++{ \ ++ (n) = ( (uint32) (b)[(i) ] << 24 ) \ ++ | ( (uint32) (b)[(i) + 1] << 16 ) \ ++ | ( (uint32) (b)[(i) + 2] << 8 ) \ ++ | ( (uint32) (b)[(i) + 3] ); \ ++} ++ ++#define PUT_UINT32(n,b,i) \ ++{ \ ++ (b)[(i) ] = (uint8) ( (n) >> 24 ); \ ++ (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ ++ (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ ++ (b)[(i) + 3] = (uint8) ( (n) ); \ ++} ++ ++/* AES key scheduling routine */ ++ ++int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ) ++{ ++ int i; ++ uint32 *RK, *SK; ++ ++ switch( nbits ) ++ { ++ case 128: ctx->nr = 10; break; ++ case 192: ctx->nr = 12; break; ++ case 256: ctx->nr = 14; break; ++ default : return( 1 ); ++ } ++ ++ RK = ctx->erk; ++ ++ for( i = 0; i < (nbits >> 5); i++ ) ++ { ++ GET_UINT32( RK[i], key, i * 4 ); ++ } ++ ++ /* setup encryption round keys */ ++ ++ switch( nbits ) ++ { ++ case 128: ++ ++ for( i = 0; i < 10; i++, RK += 4 ) ++ { ++ RK[4] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); ++ ++ RK[5] = RK[1] ^ RK[4]; ++ RK[6] = RK[2] ^ RK[5]; ++ RK[7] = RK[3] ^ RK[6]; ++ } ++ break; ++ ++ case 192: ++ ++ for( i = 0; i < 8; i++, RK += 6 ) ++ { ++ RK[6] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); ++ ++ RK[7] = RK[1] ^ RK[6]; ++ RK[8] = RK[2] ^ RK[7]; ++ RK[9] = RK[3] ^ RK[8]; ++ RK[10] = RK[4] ^ RK[9]; ++ RK[11] = RK[5] ^ RK[10]; ++ } ++ break; ++ ++ case 256: ++ ++ for( i = 0; i < 7; i++, RK += 8 ) ++ { ++ RK[8] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); ++ ++ RK[9] = RK[1] ^ RK[8]; ++ RK[10] = RK[2] ^ RK[9]; ++ RK[11] = RK[3] ^ RK[10]; ++ ++ RK[12] = RK[4] ^ ++ ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[11] ) ] ); ++ ++ RK[13] = RK[5] ^ RK[12]; ++ RK[14] = RK[6] ^ RK[13]; ++ RK[15] = RK[7] ^ RK[14]; ++ } ++ break; ++ } ++ ++ /* setup decryption round keys */ ++ ++ if( KT_init ) ++ { ++ for( i = 0; i < 256; i++ ) ++ { ++ KT0[i] = RT0[ FSb[i] ]; ++ KT1[i] = RT1[ FSb[i] ]; ++ KT2[i] = RT2[ FSb[i] ]; ++ KT3[i] = RT3[ FSb[i] ]; ++ } ++ ++ KT_init = 0; ++ } ++ ++ SK = ctx->drk; ++ ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ ++ for( i = 1; i < ctx->nr; i++ ) ++ { ++ RK -= 8; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ } ++ ++ RK -= 8; ++ ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ ++ return( 0 ); ++} ++ ++/* AES 128-bit block encryption routine */ ++ ++void rtmp_aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16] ) ++{ ++ uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; ++ ++ RK = ctx->erk; ++ GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; ++ GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; ++ GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; ++ GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; ++ ++#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ ++{ \ ++ RK += 4; \ ++ \ ++ X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y3 ) ]; \ ++ \ ++ X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y0 ) ]; \ ++ \ ++ X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y1 ) ]; \ ++ \ ++ X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y2 ) ]; \ ++} ++ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ ++ ++ if( ctx->nr > 10 ) ++ { ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ ++ } ++ ++ if( ctx->nr > 12 ) ++ { ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ ++ } ++ ++ /* last round */ ++ ++ RK += 4; ++ ++ X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y3 ) ] ); ++ ++ X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y0 ) ] ); ++ ++ X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y1 ) ] ); ++ ++ X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y2 ) ] ); ++ ++ PUT_UINT32( X0, output, 0 ); ++ PUT_UINT32( X1, output, 4 ); ++ PUT_UINT32( X2, output, 8 ); ++ PUT_UINT32( X3, output, 12 ); ++} ++ ++/* AES 128-bit block decryption routine */ ++ ++void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) ++{ ++ uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; ++ ++ RK = ctx->drk; ++ ++ GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; ++ GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; ++ GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; ++ GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; ++ ++#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ ++{ \ ++ RK += 4; \ ++ \ ++ X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y1 ) ]; \ ++ \ ++ X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y2 ) ]; \ ++ \ ++ X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y3 ) ]; \ ++ \ ++ X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y0 ) ]; \ ++} ++ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ ++ ++ if( ctx->nr > 10 ) ++ { ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ ++ } ++ ++ if( ctx->nr > 12 ) ++ { ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ ++ } ++ ++ /* last round */ ++ ++ RK += 4; ++ ++ X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y1 ) ] ); ++ ++ X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y2 ) ] ); ++ ++ X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y3 ) ] ); ++ ++ X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y0 ) ] ); ++ ++ PUT_UINT32( X0, output, 0 ); ++ PUT_UINT32( X1, output, 4 ); ++ PUT_UINT32( X2, output, 8 ); ++ PUT_UINT32( X3, output, 12 ); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ SHA1 function ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID HMAC_SHA1( ++ IN UCHAR *text, ++ IN UINT text_len, ++ IN UCHAR *key, ++ IN UINT key_len, ++ IN UCHAR *digest) ++{ ++ SHA_CTX context; ++ UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */ ++ UCHAR k_opad[65]; /* outer padding - key XORd with opad */ ++ INT i; ++ ++ // if key is longer than 64 bytes reset it to key=SHA1(key) ++ if (key_len > 64) ++ { ++ SHA_CTX tctx; ++ SHAInit(&tctx); ++ SHAUpdate(&tctx, key, key_len); ++ SHAFinal(&tctx, key); ++ key_len = 20; ++ } ++ NdisZeroMemory(k_ipad, sizeof(k_ipad)); ++ NdisZeroMemory(k_opad, sizeof(k_opad)); ++ NdisMoveMemory(k_ipad, key, key_len); ++ NdisMoveMemory(k_opad, key, key_len); ++ ++ // XOR key with ipad and opad values ++ for (i = 0; i < 64; i++) ++ { ++ k_ipad[i] ^= 0x36; ++ k_opad[i] ^= 0x5c; ++ } ++ ++ // perform inner SHA1 ++ SHAInit(&context); /* init context for 1st pass */ ++ SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ ++ SHAUpdate(&context, text, text_len); /* then text of datagram */ ++ SHAFinal(&context, digest); /* finish up 1st pass */ ++ ++ //perform outer SHA1 ++ SHAInit(&context); /* init context for 2nd pass */ ++ SHAUpdate(&context, k_opad, 64); /* start with outer pad */ ++ SHAUpdate(&context, digest, 20); /* then results of 1st hash */ ++ SHAFinal(&context, digest); /* finish up 2nd pass */ ++ ++} ++ ++/* ++* F(P, S, c, i) = U1 xor U2 xor ... Uc ++* U1 = PRF(P, S || Int(i)) ++* U2 = PRF(P, U1) ++* Uc = PRF(P, Uc-1) ++*/ ++ ++void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) ++{ ++ unsigned char digest[36], digest1[SHA_DIGEST_LEN]; ++ int i, j; ++ ++ /* U1 = PRF(P, S || int(i)) */ ++ memcpy(digest, ssid, ssidlength); ++ digest[ssidlength] = (unsigned char)((count>>24) & 0xff); ++ digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); ++ digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); ++ digest[ssidlength+3] = (unsigned char)(count & 0xff); ++ HMAC_SHA1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update ++ ++ /* output = U1 */ ++ memcpy(output, digest1, SHA_DIGEST_LEN); ++ ++ for (i = 1; i < iterations; i++) ++ { ++ /* Un = PRF(P, Un-1) */ ++ HMAC_SHA1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update ++ memcpy(digest1, digest, SHA_DIGEST_LEN); ++ ++ /* output = output xor Un */ ++ for (j = 0; j < SHA_DIGEST_LEN; j++) ++ { ++ output[j] ^= digest[j]; ++ } ++ } ++} ++/* ++* password - ascii string up to 63 characters in length ++* ssid - octet string up to 32 octets ++* ssidlength - length of ssid in octets ++* output must be 40 octets in length and outputs 256 bits of key ++*/ ++int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) ++{ ++ if ((strlen(password) > 63) || (ssidlength > 32)) ++ return 0; ++ ++ F(password, ssid, ssidlength, 4096, 1, output); ++ F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); ++ return 1; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/mlme.c +@@ -0,0 +1,8667 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ mlme.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-08-25 Modify from RT2500 code base ++ John Chang 2004-09-06 modified for RT2600 ++*/ ++ ++#include "../rt_config.h" ++#include ++ ++UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96}; ++ ++UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; ++UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac}; ++UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72}; ++UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; ++UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; ++UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; ++UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++UCHAR RateSwitchTable[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x11, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x21, 0, 30, 50, ++ 0x05, 0x21, 1, 20, 50, ++ 0x06, 0x21, 2, 20, 50, ++ 0x07, 0x21, 3, 15, 50, ++ 0x08, 0x21, 4, 15, 30, ++ 0x09, 0x21, 5, 10, 25, ++ 0x0a, 0x21, 6, 8, 25, ++ 0x0b, 0x21, 7, 8, 25, ++ 0x0c, 0x20, 12, 15, 30, ++ 0x0d, 0x20, 13, 8, 20, ++ 0x0e, 0x20, 14, 8, 20, ++ 0x0f, 0x20, 15, 8, 25, ++ 0x10, 0x22, 15, 8, 25, ++ 0x11, 0x00, 0, 0, 0, ++ 0x12, 0x00, 0, 0, 0, ++ 0x13, 0x00, 0, 0, 0, ++ 0x14, 0x00, 0, 0, 0, ++ 0x15, 0x00, 0, 0, 0, ++ 0x16, 0x00, 0, 0, 0, ++ 0x17, 0x00, 0, 0, 0, ++ 0x18, 0x00, 0, 0, 0, ++ 0x19, 0x00, 0, 0, 0, ++ 0x1a, 0x00, 0, 0, 0, ++ 0x1b, 0x00, 0, 0, 0, ++ 0x1c, 0x00, 0, 0, 0, ++ 0x1d, 0x00, 0, 0, 0, ++ 0x1e, 0x00, 0, 0, 0, ++ 0x1f, 0x00, 0, 0, 0, ++}; ++ ++UCHAR RateSwitchTable11B[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x04, 0x03, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++}; ++ ++UCHAR RateSwitchTable11BG[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x10, 2, 20, 35, ++ 0x05, 0x10, 3, 16, 35, ++ 0x06, 0x10, 4, 10, 25, ++ 0x07, 0x10, 5, 16, 25, ++ 0x08, 0x10, 6, 10, 25, ++ 0x09, 0x10, 7, 10, 13, ++}; ++ ++UCHAR RateSwitchTable11G[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x08, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x10, 0, 20, 101, ++ 0x01, 0x10, 1, 20, 35, ++ 0x02, 0x10, 2, 20, 35, ++ 0x03, 0x10, 3, 16, 35, ++ 0x04, 0x10, 4, 10, 25, ++ 0x05, 0x10, 5, 16, 25, ++ 0x06, 0x10, 6, 10, 25, ++ 0x07, 0x10, 7, 10, 13, ++}; ++ ++#ifdef DOT11_N_SUPPORT ++UCHAR RateSwitchTable11N1S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x09, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 10, 25, ++ 0x06, 0x21, 6, 8, 14, ++ 0x07, 0x21, 7, 8, 14, ++ 0x08, 0x23, 7, 8, 14, ++}; ++ ++UCHAR RateSwitchTable11N2S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N3S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N2SForABand[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N3SForABand[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN1S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0d, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x21, 0, 30,101, //50 ++ 0x05, 0x21, 1, 20, 50, ++ 0x06, 0x21, 2, 20, 50, ++ 0x07, 0x21, 3, 15, 50, ++ 0x08, 0x21, 4, 15, 30, ++ 0x09, 0x21, 5, 10, 25, ++ 0x0a, 0x21, 6, 8, 14, ++ 0x0b, 0x21, 7, 8, 14, ++ 0x0c, 0x23, 7, 8, 14, ++}; ++ ++UCHAR RateSwitchTable11BGN2S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN3S[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 20, 50, ++ 0x04, 0x21, 4, 15, 50, ++ 0x05, 0x20, 20, 15, 30, ++ 0x06, 0x20, 21, 8, 20, ++ 0x07, 0x20, 22, 8, 20, ++ 0x08, 0x20, 23, 8, 25, ++ 0x09, 0x22, 23, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN2SForABand[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0c, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x21, 12, 15, 30, ++ 0x07, 0x20, 20, 15, 30, ++ 0x08, 0x20, 21, 8, 20, ++ 0x09, 0x20, 22, 8, 20, ++ 0x0a, 0x20, 23, 8, 25, ++ 0x0b, 0x22, 23, 8, 25, ++}; ++#endif // DOT11_N_SUPPORT // ++ ++PUCHAR ReasonString[] = { ++ /* 0 */ "Reserved", ++ /* 1 */ "Unspecified Reason", ++ /* 2 */ "Previous Auth no longer valid", ++ /* 3 */ "STA is leaving / has left", ++ /* 4 */ "DIS-ASSOC due to inactivity", ++ /* 5 */ "AP unable to hanle all associations", ++ /* 6 */ "class 2 error", ++ /* 7 */ "class 3 error", ++ /* 8 */ "STA is leaving / has left", ++ /* 9 */ "require auth before assoc/re-assoc", ++ /* 10 */ "Reserved", ++ /* 11 */ "Reserved", ++ /* 12 */ "Reserved", ++ /* 13 */ "invalid IE", ++ /* 14 */ "MIC error", ++ /* 15 */ "4-way handshake timeout", ++ /* 16 */ "2-way (group key) handshake timeout", ++ /* 17 */ "4-way handshake IE diff among AssosReq/Rsp/Beacon", ++ /* 18 */ ++}; ++ ++extern UCHAR OfdmRateToRxwiMCS[]; ++// since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. ++// otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate ++ULONG BasicRateMask[12] = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */, ++ 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */, ++ 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */}; ++ ++UCHAR MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00}; ++UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than ++// this value, then it's quaranteed capable of operating in 36 mbps TX rate in ++// clean environment. ++// TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 ++CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; ++ ++UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; ++USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; ++ ++UCHAR SsidIe = IE_SSID; ++UCHAR SupRateIe = IE_SUPP_RATES; ++UCHAR ExtRateIe = IE_EXT_SUPP_RATES; ++#ifdef DOT11_N_SUPPORT ++UCHAR HtCapIe = IE_HT_CAP; ++UCHAR AddHtInfoIe = IE_ADD_HT; ++UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; ++#ifdef DOT11N_DRAFT3 ++UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++UCHAR ErpIe = IE_ERP; ++UCHAR DsIe = IE_DS_PARM; ++UCHAR TimIe = IE_TIM; ++UCHAR WpaIe = IE_WPA; ++UCHAR Wpa2Ie = IE_WPA2; ++UCHAR IbssIe = IE_IBSS_PARM; ++UCHAR Ccx2Ie = IE_CCX_V2; ++ ++extern UCHAR WPA_OUI[]; ++ ++UCHAR SES_OUI[] = {0x00, 0x90, 0x4c}; ++ ++UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; ++ ++// Reset the RFIC setting to new series ++RTMP_RF_REGS RF2850RegTable[] = { ++// ch R1 R2 R3(TX0~4=0) R4 ++ {1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b}, ++ {2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f}, ++ {3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b}, ++ {4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f}, ++ {5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b}, ++ {6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f}, ++ {7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b}, ++ {8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f}, ++ {9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b}, ++ {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f}, ++ {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b}, ++ {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f}, ++ {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b}, ++ {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193}, ++ ++ // 802.11 UNI / HyperLan 2 ++ {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3}, ++ {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193}, ++ {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183}, ++ {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3}, ++ {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b}, ++ {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b}, ++ {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193}, ++ {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3}, ++ {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b}, ++ {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183}, ++ {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193}, ++ {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5. ++ ++ // 802.11 HyperLan 2 ++ {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783}, ++ ++ // 2008.04.30 modified ++ // The system team has AN to improve the EVM value ++ // for channel 102 to 108 for the RT2850/RT2750 dual band solution. ++ {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793}, ++ {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3}, ++ {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193}, ++ ++ {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183}, ++ {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b}, ++ {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3}, ++ {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193}, ++ {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183}, ++ {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193}, ++ {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927 ++ {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3}, ++ {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b}, ++ {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193}, ++ {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b}, ++ {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183}, ++ ++ // 802.11 UNII ++ {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7}, ++ {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187}, ++ {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f}, ++ {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f}, ++ {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7}, ++ {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187}, ++ {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197}, ++ ++ // Japan ++ {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b}, ++ {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13}, ++ {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b}, ++ {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23}, ++ {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13}, ++ {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b}, ++ {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23}, ++ ++ // still lack of MMAC(Japan) ch 34,38,42,46 ++}; ++UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS)); ++ ++FREQUENCY_ITEM FreqItems3020[] = ++{ ++ /**************************************************/ ++ // ISM : 2.4 to 2.483 GHz // ++ /**************************************************/ ++ // 11g ++ /**************************************************/ ++ //-CH---N-------R---K----------- ++ {1, 241, 2, 2}, ++ {2, 241, 2, 7}, ++ {3, 242, 2, 2}, ++ {4, 242, 2, 7}, ++ {5, 243, 2, 2}, ++ {6, 243, 2, 7}, ++ {7, 244, 2, 2}, ++ {8, 244, 2, 7}, ++ {9, 245, 2, 2}, ++ {10, 245, 2, 7}, ++ {11, 246, 2, 2}, ++ {12, 246, 2, 7}, ++ {13, 247, 2, 2}, ++ {14, 248, 2, 4}, ++}; ++#define NUM_OF_3020_CHNL (sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)) ++ ++/* ++ ========================================================================== ++ Description: ++ initialize the MLME task and its data structure (queue, spinlock, ++ timer, state machines). ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Return: ++ always return NDIS_STATUS_SUCCESS ++ ++ ========================================================================== ++*/ ++NDIS_STATUS MlmeInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n")); ++ ++ do ++ { ++ Status = MlmeQueueInit(&pAd->Mlme.Queue); ++ if(Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ pAd->Mlme.bRunning = FALSE; ++ NdisAllocateSpinLock(&pAd->Mlme.TaskLock); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ BssTableInit(&pAd->ScanTab); ++ ++ // init STA state machines ++ AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); ++ AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); ++ AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); ++ SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); ++ WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); ++ AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); ++ ++#ifdef QOS_DLS_SUPPORT ++ DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); ++#endif // QOS_DLS_SUPPORT // ++ ++ ++ // Since we are using switch/case to implement it, the init is different from the above ++ // state machine init ++ MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); ++ ++ // Init mlme periodic timer ++ RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE); ++ ++ // Set mlme periodic timer ++ RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); ++ ++ // software-based RX Antenna diversity ++ RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef RT2860 ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ // only PCIe cards need these two timers ++ RTMPInitTimer(pAd, &pAd->Mlme.PsPollTimer, GET_TIMER_FUNCTION(PsPollWakeExec), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer, GET_TIMER_FUNCTION(RadioOnExec), pAd, FALSE); ++ } ++ } ++#endif // RT2860 // ++#endif // CONFIG_STA_SUPPORT // ++ ++ } while (FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ main loop of the MLME ++ Pre: ++ Mlme has to be initialized, and there are something inside the queue ++ Note: ++ This function is invoked from MPSetInformation and MPReceive; ++ This task guarantee only one MlmeHandler will run. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeHandler( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_QUEUE_ELEM *Elem = NULL; ++#ifdef APCLI_SUPPORT ++ SHORT apcliIfIndex; ++#endif ++ ++ // Only accept MLME and Frame from peer side, no other (control/data) frame should ++ // get into this state machine ++ ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ if(pAd->Mlme.bRunning) ++ { ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ return; ++ } ++ else ++ { ++ pAd->Mlme.bRunning = TRUE; ++ } ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ ++ while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num)); ++ break; ++ } ++ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ ++ //From message type, determine which state machine I should drive ++ if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) ++ { ++ ++ // if dequeue success ++ switch (Elem->Machine) ++ { ++ // STA state machines ++#ifdef CONFIG_STA_SUPPORT ++ case ASSOC_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); ++ break; ++ case AUTH_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); ++ break; ++ case AUTH_RSP_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); ++ break; ++ case SYNC_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); ++ break; ++ case MLME_CNTL_STATE_MACHINE: ++ MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); ++ break; ++ case WPA_PSK_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); ++ break; ++#ifdef LEAP_SUPPORT ++ case LEAP_STATE_MACHINE: ++ LeapMachinePerformAction(pAd, &pAd->Mlme.LeapMachine, Elem); ++ break; ++#endif ++ case AIRONET_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); ++ break; ++ ++#ifdef QOS_DLS_SUPPORT ++ case DLS_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); ++ break; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ case ACTION_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); ++ break; ++ ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine)); ++ break; ++ } // end of switch ++ ++ // free MLME element ++ Elem->Occupied = FALSE; ++ Elem->MsgLen = 0; ++ ++ } ++ else { ++ DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); ++ } ++ } ++ ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ pAd->Mlme.bRunning = FALSE; ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Destructor of MLME (Destroy queue, state machine, spin lock and timer) ++ Parameters: ++ Adapter - NIC Adapter pointer ++ Post: ++ The MLME task will no longer work properly ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeHalt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BOOLEAN Cancelled; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ // disable BEACON generation and other BEACON related hardware timers ++ AsicDisableSync(pAd); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef QOS_DLS_SUPPORT ++ UCHAR i; ++#endif // QOS_DLS_SUPPORT // ++ // Cancel pending timers ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++#ifdef RT2860 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); ++ } ++#endif // RT2860 // ++ ++#ifdef QOS_DLS_SUPPORT ++ for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); ++ } ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); ++ ++ ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ // Set LED ++ RTMPSetLED(pAd, LED_HALT); ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. ++ } ++ ++ RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled ++ ++ MlmeQueueDestroy(&pAd->Mlme.Queue); ++ NdisFreeSpinLock(&pAd->Mlme.TaskLock); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n")); ++} ++ ++VOID MlmeResetRalinkCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt; ++ // clear all OneSecxxx counters. ++ pAd->RalinkCounters.OneSecBeaconSentCnt = 0; ++ pAd->RalinkCounters.OneSecFalseCCACnt = 0; ++ pAd->RalinkCounters.OneSecRxFcsErrCnt = 0; ++ pAd->RalinkCounters.OneSecRxOkCnt = 0; ++ pAd->RalinkCounters.OneSecTxFailCount = 0; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0; ++ pAd->RalinkCounters.OneSecTxRetryOkCount = 0; ++ pAd->RalinkCounters.OneSecRxOkDataCnt = 0; ++ ++ // TODO: for debug only. to be removed ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0; ++ pAd->RalinkCounters.OneSecTxDoneCount = 0; ++ pAd->RalinkCounters.OneSecRxCount = 0; ++ pAd->RalinkCounters.OneSecTxAggregationCount = 0; ++ pAd->RalinkCounters.OneSecRxAggregationCount = 0; ++ ++ return; ++} ++ ++unsigned long rx_AMSDU; ++unsigned long rx_Total; ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is executed periodically to - ++ 1. Decide if it's a right time to turn on PwrMgmt bit of all ++ outgoiing frames ++ 2. Calculate ChannelQuality based on statistics of the last ++ period, so that TX rate won't toggling very frequently between a ++ successful TX and a failed TX. ++ 3. If the calculated ChannelQuality indicated current connection not ++ healthy, then a ROAMing attempt is tried here. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++#define ADHOC_BEACON_LOST_TIME (8*OS_HZ) // 8 sec ++VOID MlmePeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ULONG TxTotalCnt; ++ PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef RT2860 ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second. ++ // Move code to here, because following code will return when radio is off ++ if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) == 0) && (pAd->StaCfg.bHardwareRadio == TRUE) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (pAd->bPCIclkOff == FALSE)) ++ { ++ UINT32 data = 0; ++ ++ // Read GPIO pin2 as Hardware controlled radio state ++ RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); ++ if (data & 0x04) ++ { ++ pAd->StaCfg.bHwRadio = TRUE; ++ } ++ else ++ { ++ pAd->StaCfg.bHwRadio = FALSE; ++ } ++ if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = HW_RADIO_OFF; ++ } ++ } ++ } ++ } ++#endif // RT2860 // ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RADIO_MEASUREMENT | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS)))) ++ return; ++ ++ RT28XX_MLME_PRE_SANITY_CHECK(pAd); ++ ++#ifdef RALINK_ATE ++ /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) ++ { ++ pAd->Mlme.PeriodicRound ++; ++ return; ++ } ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ ++ if (pAd->Mlme.PeriodicRound & 0x1) ++ { ++ // This is the fix for wifi 11n extension channel overlapping test case. for 2860D ++ if (((pAd->MACVersion & 0xffff) == 0x0101) && ++ (STA_TGN_WIFI_ON(pAd)) && ++ (pAd->CommonCfg.IOTestParm.bToggle == FALSE)) ++ ++ { ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf); ++ pAd->CommonCfg.IOTestParm.bToggle = TRUE; ++ } ++ else if ((STA_TGN_WIFI_ON(pAd)) && ++ ((pAd->MACVersion & 0xffff) == 0x0101)) ++ { ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f); ++ pAd->CommonCfg.IOTestParm.bToggle = FALSE; ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->bUpdateBcnCntDone = FALSE; ++ ++// RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); ++ pAd->Mlme.PeriodicRound ++; ++ ++ // execute every 500ms ++ if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ // perform dynamic tx rate switching based on past TX history ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) ++ MlmeDynamicTxRateSwitching(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // Normal 1 second Mlme PeriodicExec. ++ if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) ++ { ++ pAd->Mlme.OneSecPeriodicRound ++; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ /* request from Baron : move this routine from later to here */ ++ /* for showing Rx error count in ATE RXFRAME */ ++ NICUpdateRawCounters(pAd); ++ if (pAd->ate.bRxFer == 1) ++ { ++ pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); ++ pAd->ate.RxCntPerSec = 0; ++ ++ if (pAd->ate.RxAntennaSel == 0) ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", ++ pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); ++ else ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); ++ } ++ MlmeResetRalinkCounters(pAd); ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ ++ if (rx_Total) ++ { ++ ++ // reset counters ++ rx_AMSDU = 0; ++ rx_Total = 0; ++ } ++ ++ // Media status changed, report to NDIS ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ ++ } ++ else ++ { ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ } ++ } ++ ++ NdisGetSystemUpTime(&pAd->Mlme.Now32); ++ ++ // add the most up-to-date h/w raw counters into software variable, so that ++ // the dynamic tuning mechanism below are based on most up-to-date information ++ NICUpdateRawCounters(pAd); ++ ++ ++#ifdef DOT11_N_SUPPORT ++ // Need statistics after read counter. So put after NICUpdateRawCounters ++ ORIBATimerTimeout(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ // The time period for checking antenna is according to traffic ++ if (pAd->Mlme.bEnableAutoAntennaCheck) ++ { ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt > 50) ++ { ++ if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) ++ { ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ else ++ { ++ if (pAd->Mlme.OneSecPeriodicRound % 3 == 0) ++ { ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ STAMlmePeriodicExec(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ MlmeResetRalinkCounters(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef RT2860 ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->bPCIclkOff == FALSE)) ++#endif // RT2860 // ++ { ++ // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock ++ // and sending CTS-to-self over and over. ++ // Software Patch Solution: ++ // 1. Polling debug state register 0x10F4 every one second. ++ // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. ++ // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. ++ ++ UINT32 MacReg = 0; ++ ++ RTMP_IO_READ32(pAd, 0x10F4, &MacReg); ++ if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20))) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ RTMPusecDelay(1); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC); ++ ++ DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n")); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ ++ pAd->bUpdateBcnCntDone = FALSE; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID STAMlmePeriodicExec( ++ PRTMP_ADAPTER pAd) ++{ ++ ULONG TxTotalCnt; ++ ++// ++// We return here in ATE mode, because the statistics ++// that ATE needs are not collected via this routine. ++// ++#ifdef RALINK_ATE ++ // It is supposed that we will never reach here in ATE mode. ++ ASSERT(!(ATE_ON(pAd))); ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // WPA MIC error should block association attempt for 60 seconds ++ if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) ++ pAd->StaCfg.bBlockAssoc = FALSE; ++ } ++ ++ if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ pAd->PreMediaState = pAd->IndicateMediaState; ++ } ++ ++ ++ ++ ++ AsicStaBbpTuning(pAd); ++ ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ // update channel quality for Roaming and UI LinkQuality display ++ MlmeCalculateChannelQuality(pAd, pAd->Mlme.Now32); ++ } ++ ++ // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if ++ // Radio is currently in noisy environment ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ AsicAdjustTxPower(pAd); ++ ++ if (INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ // Check DLS time out, then tear down those session ++ RTMPCheckDLSTimeOut(pAd); ++#endif // QOS_DLS_SUPPORT // ++ ++ // Is PSM bit consistent with user power management policy? ++ // This is the only place that will set PSM bit ON. ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ MlmeCheckPsmChange(pAd, pAd->Mlme.Now32); ++ ++ pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt; ++ ++ if ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && ++ ((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt < 600))) ++ { ++ RTMPSetAGCInitValue(pAd, BW_20); ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd)))); ++ } ++ ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) ++ { ++ // When APSD is enabled, the period changes as 20 sec ++ if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8) ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ } ++ else ++ { ++ // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) ++ if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) ++ { ++ if (pAd->CommonCfg.bWmmCapable) ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ else ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); ++ } ++ } ++ } ++ ++ if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); ++ pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; ++ pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime; ++ ++ // Lost AP, send disconnect & link down event ++ LinkDown(pAd, FALSE); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) ++ { ++ pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ ++ // Add auto seamless roaming ++ if (pAd->StaCfg.bFastRoaming) ++ { ++ SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam)); ++ ++ if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam) ++ { ++ MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32); ++ } ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ // 2003-04-17 john. this is a patch that driver forces a BEACON out if ASIC fails ++ // the "TX BEACON competition" for the entire past 1 sec. ++ // So that even when ASIC's BEACONgen engine been blocked ++ // by peer's BEACON due to slower system clock, this STA still can send out ++ // minimum BEACON to tell the peer I'm alive. ++ // drawback is that this BEACON won't be well aligned at TBTT boundary. ++ // EnqueueBeaconFrame(pAd); // software send BEACON ++ ++ // if all 11b peers leave this BSS more than 5 seconds, update Tx rate, ++ // restore outgoing BEACON to support B/G-mixed mode ++ if ((pAd->CommonCfg.Channel <= 14) && ++ (pAd->CommonCfg.MaxTxRate <= RATE_11) && ++ (pAd->CommonCfg.MaxDesiredRate > RATE_11) && ++ ((pAd->StaCfg.Last11bBeaconRxTime + 5*OS_HZ) < pAd->Mlme.Now32)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 11B peer left, update Tx rates\n")); ++ NdisMoveMemory(pAd->StaActive.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pAd->StaActive.SupRateLen = pAd->CommonCfg.SupRateLen; ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy to on-chip memory ++ pAd->StaCfg.AdhocBOnlyJoined = FALSE; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ if ((pAd->StaCfg.AdhocBGJoined) && ++ ((pAd->StaCfg.Last11gBeaconRxTime + 5 * OS_HZ) < pAd->Mlme.Now32)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 11G peer left\n")); ++ pAd->StaCfg.AdhocBGJoined = FALSE; ++ } ++ ++ if ((pAd->StaCfg.Adhoc20NJoined) && ++ ((pAd->StaCfg.Last20NBeaconRxTime + 5 * OS_HZ) < pAd->Mlme.Now32)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 20MHz N peer left\n")); ++ pAd->StaCfg.Adhoc20NJoined = FALSE; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ //radar detect ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ RadarDetectPeriodic(pAd); ++ } ++ ++ // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState ++ // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can ++ // join later. ++ if ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) && ++ OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ MLME_START_REQ_STRUCT StartReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n")); ++ LinkDown(pAd, FALSE); ++ ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ } ++ else // no INFRA nor ADHOC connection ++ { ++ ++ if (pAd->StaCfg.bScanReqIsFromWebUI && ++ ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32)) ++ goto SKIP_AUTO_SCAN_CONN; ++ else ++ pAd->StaCfg.bScanReqIsFromWebUI = FALSE; ++ ++ if ((pAd->StaCfg.bAutoReconnect == TRUE) ++ && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) ++ && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) ++ { ++ if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) ++ { ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); ++ ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ // Reset Missed scan number ++ pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; ++ } ++ else if (pAd->StaCfg.BssType == BSS_ADHOC) // Quit the forever scan when in a very clean room ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) ++ { ++ MlmeAutoScan(pAd); ++ pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; ++ } ++ else ++ { ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else ++#endif // CARRIER_DETECTION_SUPPORT // ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ } ++ } ++ } ++ ++SKIP_AUTO_SCAN_CONN: ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) ++ { ++ pAd->MacTab.fAnyBASession = TRUE; ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++ else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE)) ++ { ++ pAd->MacTab.fAnyBASession = FALSE; ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) ++ TriEventCounterMaintenance(pAd); ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ return; ++} ++ ++// Link down report ++VOID LinkDownExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeAutoScan( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n")); ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeAutoReconnectLastSSID( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && ++ (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) ++ { ++ NDIS_802_11_SSID OidSsid; ++ OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen; ++ NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen)); ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ &OidSsid); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ========================================================================== ++ Validate SSID for connection try and rescan purpose ++ Valid SSID will have visible chars only. ++ The valid length is from 0 to 32. ++ IRQL = DISPATCH_LEVEL ++ ========================================================================== ++ */ ++BOOLEAN MlmeValidateSSID( ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen) ++{ ++ int index; ++ ++ if (SsidLen > MAX_LEN_OF_SSID) ++ return (FALSE); ++ ++ // Check each character value ++ for (index = 0; index < SsidLen; index++) ++ { ++ if (pSsid[index] < 0x20) ++ return (FALSE); ++ } ++ ++ // All checked ++ return (TRUE); ++} ++ ++VOID MlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx) ++{ ++ do ++ { ++ // decide the rate table for tuning ++ if (pAd->CommonCfg.TxRateTableSize > 0) ++ { ++ *ppTable = RateSwitchTable; ++ *pTableSize = RateSwitchTable[0]; ++ *pInitTxRateIdx = RateSwitchTable[1]; ++ ++ break; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && ++ !pAd->StaCfg.AdhocBOnlyJoined && ++ !pAd->StaCfg.AdhocBGJoined && ++ (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ++ ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ {// 11N 1S Adhoc ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ ++ } ++ else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && ++ !pAd->StaCfg.AdhocBOnlyJoined && ++ !pAd->StaCfg.AdhocBGJoined && ++ (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ++ (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && ++ (pAd->Antenna.field.TxPath == 2)) ++ {// 11N 2S Adhoc ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ } ++ else if((pAd->LatchRfRegs.Channel <= 14) && (pAd->StaCfg.AdhocBOnlyJoined == TRUE)) ++ { ++ // USe B Table when Only b-only Station in my IBSS . ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ } ++ else if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ } ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) ++ {// 11BGN 1S AP ++ *ppTable = RateSwitchTable11BGN1S; ++ *pTableSize = RateSwitchTable11BGN1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN1S[1]; ++ ++ break; ++ } ++ ++ if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) ++ {// 11BGN 2S AP ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11BGN2S; ++ *pTableSize = RateSwitchTable11BGN2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN2S[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11BGN2SForABand; ++ *pTableSize = RateSwitchTable11BGN2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1]; ++ ++ } ++ break; ++ } ++ ++ if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) ++ {// 11N 1S AP ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ ++ break; ++ } ++ ++ if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) ++ {// 11N 2S AP ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ } ++ ++ break; ++ } ++#endif // DOT11_N_SUPPORT // ++ //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen == 4) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// B only AP ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen > 8) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// B/G mixed AP ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen == 8) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// G only AP ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef DOT11_N_SUPPORT ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) ++#endif // DOT11_N_SUPPORT // ++ { // Legacy mode ++ if (pAd->CommonCfg.MaxTxRate <= RATE_11) ++ { ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ } ++ else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11)) ++ { ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ } ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ if (pAd->CommonCfg.TxStream == 1) ++ { ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.TxStream == 1) ++ { ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", ++ pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } while(FALSE); ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ This routine checks if there're other APs out there capable for ++ roaming. Caller should call this routine only when Link up in INFRA mode ++ and channel quality is below CQI_GOOD_THRESHOLD. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Output: ++ ========================================================================== ++ */ ++VOID MlmeCheckForRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ USHORT i; ++ BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; ++ BSS_ENTRY *pBss; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n")); ++ // put all roaming candidates into RoamTab, and sort in RSSI order ++ BssTableInit(pRoamTab); ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ pBss = &pAd->ScanTab.BssEntry[i]; ++ ++ if ((pBss->LastBeaconRxTime + BEACON_LOST_TIME) < Now32) ++ continue; // AP disappear ++ if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) ++ continue; // RSSI too weak. forget it. ++ if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) ++ continue; // skip current AP ++ if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA)) ++ continue; // only AP with stronger RSSI is eligible for roaming ++ ++ // AP passing all above rules is put into roaming candidate table ++ NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); ++ pRoamTab->BssNr += 1; ++ } ++ ++ if (pRoamTab->BssNr > 0) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ pAd->RalinkCounters.PoorCQIRoamingCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine checks if there're other APs out there capable for ++ roaming. Caller should call this routine only when link up in INFRA mode ++ and channel quality is below CQI_GOOD_THRESHOLD. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Output: ++ ========================================================================== ++ */ ++VOID MlmeCheckForFastRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now) ++{ ++ USHORT i; ++ BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; ++ BSS_ENTRY *pBss; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n")); ++ // put all roaming candidates into RoamTab, and sort in RSSI order ++ BssTableInit(pRoamTab); ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ pBss = &pAd->ScanTab.BssEntry[i]; ++ ++ if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel)) ++ continue; // RSSI too weak. forget it. ++ if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) ++ continue; // skip current AP ++ if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) ++ continue; // skip different SSID ++ if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA)) ++ continue; // skip AP without better RSSI ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi)); ++ // AP passing all above rules is put into roaming candidate table ++ NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); ++ pRoamTab->BssNr += 1; ++ } ++ ++ if (pRoamTab->BssNr > 0) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ pAd->RalinkCounters.PoorCQIRoamingCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ } ++ // Maybe site survey required ++ else ++ { ++ if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); ++ pAd->StaCfg.ScanCnt = 2; ++ pAd->StaCfg.LastScanTime = Now; ++ MlmeAutoScan(pAd); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine calculates TxPER, RxPER of the past N-sec period. And ++ according to the calculation result, ChannelQuality is calculated here ++ to decide if current AP is still doing the job. ++ ++ If ChannelQuality is not good, a ROAMing attempt may be tried later. ++ Output: ++ StaCfg.ChannelQuality - 0..100 ++ ++ IRQL = DISPATCH_LEVEL ++ ++ NOTE: This routine decide channle quality based on RX CRC error ratio. ++ Caller should make sure a function call to NICUpdateRawCounters(pAd) ++ is performed right before this routine, so that this routine can decide ++ channel quality based on the most up-to-date information ++ ========================================================================== ++ */ ++VOID MlmeCalculateChannelQuality( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ ULONG TxOkCnt, TxCnt, TxPER, TxPRR; ++ ULONG RxCnt, RxPER; ++ UCHAR NorRssi; ++ CHAR MaxRssi; ++ ULONG BeaconLostTime = BEACON_LOST_TIME; ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // longer beacon lost time when carrier detection enabled ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ BeaconLostTime = BEACON_LOST_TIME + BEACON_LOST_TIME/2; ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); ++ ++ // ++ // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics ++ // ++ TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount; ++ TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount; ++ if (TxCnt < 5) ++ { ++ TxPER = 0; ++ TxPRR = 0; ++ } ++ else ++ { ++ TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt; ++ TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt; ++ } ++ ++ // ++ // calculate RX PER - don't take RxPER into consideration if too few sample ++ // ++ RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt; ++ if (RxCnt < 5) ++ RxPER = 0; ++ else ++ RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt; ++ ++ // ++ // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER ++ // ++ if (INFRA_ON(pAd) && ++ (pAd->RalinkCounters.OneSecTxNoRetryOkCount < 2) && // no heavy traffic ++ (pAd->StaCfg.LastBeaconRxTime + BeaconLostTime < Now32)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt)); ++ pAd->Mlme.ChannelQuality = 0; ++ } ++ else ++ { ++ // Normalize Rssi ++ if (MaxRssi > -40) ++ NorRssi = 100; ++ else if (MaxRssi < -90) ++ NorRssi = 0; ++ else ++ NorRssi = (MaxRssi + 90) * 2; ++ ++ // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) ++ pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi + ++ TX_WEIGHTING * (100 - TxPRR) + ++ RX_WEIGHTING* (100 - RxPER)) / 100; ++ if (pAd->Mlme.ChannelQuality >= 100) ++ pAd->Mlme.ChannelQuality = 100; ++ } ++ ++} ++ ++VOID MlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate) ++{ ++ UCHAR MaxMode = MODE_OFDM; ++ ++#ifdef DOT11_N_SUPPORT ++ MaxMode = MODE_HTGREENFIELD; ++ ++ if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; ++ ++ if (pTxRate->CurrMCS < MCS_AUTO) ++ pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS; ++ ++ if (pAd->StaCfg.HTPhyMode.field.MCS > 7) ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; ++ ++ if (ADHOC_ON(pAd)) ++ { ++ // If peer adhoc is b-only mode, we can't send 11g rate. ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ pEntry->HTPhyMode.field.STBC = STBC_NONE; ++ ++ // ++ // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary ++ // ++ pEntry->HTPhyMode.field.MODE = pTxRate->Mode; ++ pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ ++ // Patch speed error in status page ++ pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE; ++ } ++ else ++ { ++ if (pTxRate->Mode <= MaxMode) ++ pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ ++#ifdef DOT11_N_SUPPORT ++ // Reexam each bandwidth's SGI support. ++ if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) ++ { ++ if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE))) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE))) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ } ++ ++ // Turn RTS/CTS rate to 6Mbps. ++ if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) ++ { ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ if (pAd->MacTab.fAnyBASession) ++ { ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ else ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ } ++ else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) ++ { ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ if (pAd->MacTab.fAnyBASession) ++ { ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ else ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ } ++ else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) ++ { ++ AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ ++ } ++ else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) ++ { ++ AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; ++ pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && ++ pAd->WIFItestbed.bGreenField) ++ pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine calculates the acumulated TxPER of eaxh TxRate. And ++ according to the calculation result, change CommonCfg.TxRate which ++ is the stable TX Rate we expect the Radio situation could sustained. ++ ++ CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} ++ Output: ++ CommonCfg.TxRate - ++ ++ IRQL = DISPATCH_LEVEL ++ ++ NOTE: ++ call this routine every second ++ ========================================================================== ++ */ ++VOID MlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx; ++ ULONG i, AccuTxTotalCnt = 0, TxTotalCnt; ++ ULONG TxErrorRatio = 0; ++ BOOLEAN bTxRateChanged, bUpgradeQuality = FALSE; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; ++ CHAR Rssi, RssiOffset = 0; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; ++ MAC_TABLE_ENTRY *pEntry; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ /*if (pAd->Antenna.field.RxPath > 1) ++ Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; ++ else ++ Rssi = pAd->StaCfg.RssiSample.AvgRssi0;*/ ++ ++ // ++ // walk through MAC table, see if need to change AP's TX rate toward each entry ++ // ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ // check if this entry need to switch rate automatically ++ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) ++ continue; ++ ++ if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) ++ { ++ Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.RssiSample.AvgRssi0, (CHAR)pAd->StaCfg.RssiSample.AvgRssi1, (CHAR)pAd->StaCfg.RssiSample.AvgRssi2); ++ ++ // Update statistic counter ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ pAd->bUpdateBcnCntDone = TRUE; ++ TxRetransmit = StaTx1.field.TxRetransmit; ++ TxSuccess = StaTx1.field.TxSuccess; ++ TxFailCount = TxStaCnt0.field.TxFailCount; ++ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; ++ ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ ++ // if no traffic in the past 1-sec period, don't change TX rate, ++ // but clear all bad history. because the bad history may affect the next ++ // Chariot throughput test ++ AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; ++ } ++ else ++ { ++ Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); ++ ++ TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + ++ pEntry->OneSecTxRetryOkCount + ++ pEntry->OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; ++ } ++ ++ CurrRateIdx = pEntry->CurrTxRateIndex; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); ++ ++ if (CurrRateIdx >= TableSize) ++ { ++ CurrRateIdx = TableSize - 1; ++ } ++ ++ // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. ++ // So need to sync here. ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS) ++ //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ ) ++ { ++ ++ // Need to sync Real Tx rate and our record. ++ // Then return for next DRS. ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5]; ++ pEntry->CurrTxRateIndex = InitTxRateIdx; ++ MlmeSetTxRate(pAd, pEntry, pCurrTxRate); ++ ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ continue; ++ } ++ ++ // decide the next upgrade rate and downgrade rate, if any ++ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx -1; ++ } ++ else if (CurrRateIdx == 0) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx; ++ } ++ else if (CurrRateIdx == (TableSize - 1)) ++ { ++ UpRateIdx = CurrRateIdx; ++ DownRateIdx = CurrRateIdx - 1; ++ } ++ ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) ++ { ++ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); ++ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ TrainUp = pCurrTxRate->TrainUp; ++ TrainDown = pCurrTxRate->TrainDown; ++ } ++ ++ //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; ++ ++ // ++ // Keep the last time TxRateChangeAction status. ++ // ++ pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction; ++ ++ ++ ++ // ++ // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI ++ // (criteria copied from RT2500 for Netopia case) ++ // ++ if (TxTotalCnt <= 15) ++ { ++ CHAR idx = 0; ++ UCHAR TxRateIdx; ++ //UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; ++ UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0; ++ UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; ++ UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3 ++ ++ // check the existence and index of each needed MCS ++ while (idx < pTable[0]) ++ { ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5]; ++ ++ if (pCurrTxRate->CurrMCS == MCS_0) ++ { ++ MCS0 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_1) ++ { ++ MCS1 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_2) ++ { ++ MCS2 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_3) ++ { ++ MCS3 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_4) ++ { ++ MCS4 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_5) ++ { ++ MCS5 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_6) ++ { ++ MCS6 = idx; ++ } ++ //else if (pCurrTxRate->CurrMCS == MCS_7) ++ else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput ++ { ++ MCS7 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_12) ++ { ++ MCS12 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_13) ++ { ++ MCS13 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_14) ++ { ++ MCS14 = idx; ++ } ++ //else if ((pCurrTxRate->CurrMCS == MCS_15)/* && (pCurrTxRate->ShortGI == GI_800)*/) //we hope to use ShortGI as initial rate ++ else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) //we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI ++ { ++ MCS15 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3 ++ { ++ MCS20 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_21) ++ { ++ MCS21 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_22) ++ { ++ MCS22 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_23) ++ { ++ MCS23 = idx; ++ } ++ idx ++; ++ } ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ RssiOffset = 2; ++ } ++ else ++ { ++ RssiOffset = 5; ++ } ++ } ++ else ++ { ++ if (pAd->NicConfig2.field.ExternalLNAForA) ++ { ++ RssiOffset = 5; ++ } ++ else ++ { ++ RssiOffset = 8; ++ } ++ } ++#ifdef DOT11_N_SUPPORT ++ /*if (MCS15)*/ ++ if ((pTable == RateSwitchTable11BGN3S) || ++ (pTable == RateSwitchTable11N3S) || ++ (pTable == RateSwitchTable)) ++ {// N mode with 3 stream // 3*3 ++ if (MCS23 && (Rssi >= -70)) ++ TxRateIdx = MCS15; ++ else if (MCS22 && (Rssi >= -72)) ++ TxRateIdx = MCS14; ++ else if (MCS21 && (Rssi >= -76)) ++ TxRateIdx = MCS13; ++ else if (MCS20 && (Rssi >= -78)) ++ TxRateIdx = MCS12; ++ else if (MCS4 && (Rssi >= -82)) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi >= -84)) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi >= -86)) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi >= -88)) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3 ++ {// N mode with 2 stream ++ if (MCS15 && (Rssi >= (-70+RssiOffset))) ++ TxRateIdx = MCS15; ++ else if (MCS14 && (Rssi >= (-72+RssiOffset))) ++ TxRateIdx = MCS14; ++ else if (MCS13 && (Rssi >= (-76+RssiOffset))) ++ TxRateIdx = MCS13; ++ else if (MCS12 && (Rssi >= (-78+RssiOffset))) ++ TxRateIdx = MCS12; ++ else if (MCS4 && (Rssi >= (-82+RssiOffset))) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi >= (-84+RssiOffset))) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi >= (-86+RssiOffset))) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi >= (-88+RssiOffset))) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) ++ {// N mode with 1 stream ++ if (MCS7 && (Rssi > (-72+RssiOffset))) ++ TxRateIdx = MCS7; ++ else if (MCS6 && (Rssi > (-74+RssiOffset))) ++ TxRateIdx = MCS6; ++ else if (MCS5 && (Rssi > (-77+RssiOffset))) ++ TxRateIdx = MCS5; ++ else if (MCS4 && (Rssi > (-79+RssiOffset))) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi > (-81+RssiOffset))) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi > (-83+RssiOffset))) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi > (-86+RssiOffset))) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ {// Legacy mode ++ if (MCS7 && (Rssi > -70)) ++ TxRateIdx = MCS7; ++ else if (MCS6 && (Rssi > -74)) ++ TxRateIdx = MCS6; ++ else if (MCS5 && (Rssi > -78)) ++ TxRateIdx = MCS5; ++ else if (MCS4 && (Rssi > -82)) ++ TxRateIdx = MCS4; ++ else if (MCS4 == 0) // for B-only mode ++ TxRateIdx = MCS3; ++ else if (MCS3 && (Rssi > -85)) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi > -87)) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi > -90)) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ ++ { ++ pEntry->CurrTxRateIndex = TxRateIdx; ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ ++ NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ pEntry->fLastSecAccordingRSSI = TRUE; ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ continue; ++ } ++ ++ if (pEntry->fLastSecAccordingRSSI == TRUE) ++ { ++ pEntry->fLastSecAccordingRSSI = FALSE; ++ pEntry->LastSecTxRateChangeAction = 0; ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ continue; ++ } ++ ++ do ++ { ++ BOOLEAN bTrainUpDown = FALSE; ++ ++ pEntry->CurrTxRateStableTime ++; ++ ++ // downgrade TX quality if PER >= Rate-Down threshold ++ if (TxErrorRatio >= TrainDown) ++ { ++ bTrainUpDown = TRUE; ++ pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ // upgrade TX quality if PER <= Rate-Up threshold ++ else if (TxErrorRatio <= TrainUp) ++ { ++ bTrainUpDown = TRUE; ++ bUpgradeQuality = TRUE; ++ if (pEntry->TxQuality[CurrRateIdx]) ++ pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate ++ ++ if (pEntry->TxRateUpPenalty) ++ pEntry->TxRateUpPenalty --; ++ else if (pEntry->TxQuality[UpRateIdx]) ++ pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality ++ } ++ ++ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio; ++ ++ if (bTrainUpDown) ++ { ++ // perform DRS - consider TxRate Down first, then rate up. ++ if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND)) ++ { ++ pEntry->CurrTxRateIndex = DownRateIdx; ++ } ++ else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0)) ++ { ++ pEntry->CurrTxRateIndex = UpRateIdx; ++ } ++ } ++ } while (FALSE); ++ ++ // if rate-up happen, clear all bad history of all TX rates ++ if (pEntry->CurrTxRateIndex > CurrRateIdx) ++ { ++ pEntry->CurrTxRateStableTime = 0; ++ pEntry->TxRateUpPenalty = 0; ++ pEntry->LastSecTxRateChangeAction = 1; // rate UP ++ NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ ++ // ++ // For TxRate fast train up ++ // ++ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) ++ { ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; ++ } ++ bTxRateChanged = TRUE; ++ } ++ // if rate-down happen, only clear DownRate's bad history ++ else if (pEntry->CurrTxRateIndex < CurrRateIdx) ++ { ++ pEntry->CurrTxRateStableTime = 0; ++ pEntry->TxRateUpPenalty = 0; // no penalty ++ pEntry->LastSecTxRateChangeAction = 2; // rate DOWN ++ pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; ++ pEntry->PER[pEntry->CurrTxRateIndex] = 0; ++ ++ // ++ // For TxRate fast train down ++ // ++ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) ++ { ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; ++ } ++ bTxRateChanged = TRUE; ++ } ++ else ++ { ++ pEntry->LastSecTxRateChangeAction = 0; // rate no change ++ bTxRateChanged = FALSE; ++ } ++ ++ pEntry->LastTxOkCount = TxSuccess; ++ ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; ++ if (bTxRateChanged && pNextTxRate) ++ { ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Station side, Auto TxRate faster train up timer call back function. ++ ++ Arguments: ++ SystemSpecific1 - Not used. ++ FunctionContext - Pointer to our Adapter context. ++ SystemSpecific2 - Not used. ++ SystemSpecific3 - Not used. ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID StaQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; ++ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; ++ ULONG TxTotalCnt; ++ ULONG TxErrorRatio = 0; ++ BOOLEAN bTxRateChanged = TRUE; //, bUpgradeQuality = FALSE; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ CHAR Rssi, ratio; ++ ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; ++ MAC_TABLE_ENTRY *pEntry; ++ ULONG i; ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; ++ ++ // ++ // walk through MAC table, see if need to change AP's TX rate toward each entry ++ // ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ // check if this entry need to switch rate automatically ++ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) ++ continue; ++ ++ //Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.AvgRssi0, (CHAR)pAd->StaCfg.AvgRssi1, (CHAR)pAd->StaCfg.AvgRssi2); ++ if (pAd->Antenna.field.TxPath > 1) ++ Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; ++ else ++ Rssi = pAd->StaCfg.RssiSample.AvgRssi0; ++ ++ CurrRateIdx = pAd->CommonCfg.TxRateIndex; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); ++ ++ // decide the next upgrade rate and downgrade rate, if any ++ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx -1; ++ } ++ else if (CurrRateIdx == 0) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx; ++ } ++ else if (CurrRateIdx == (TableSize - 1)) ++ { ++ UpRateIdx = CurrRateIdx; ++ DownRateIdx = CurrRateIdx - 1; ++ } ++ ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) ++ { ++ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); ++ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ TrainUp = pCurrTxRate->TrainUp; ++ TrainDown = pCurrTxRate->TrainDown; ++ } ++ ++ if (pAd->MacTab.Size == 1) ++ { ++ // Update statistic counter ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ ++ TxRetransmit = StaTx1.field.TxRetransmit; ++ TxSuccess = StaTx1.field.TxSuccess; ++ TxFailCount = TxStaCnt0.field.TxFailCount; ++ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; ++ ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; ++ } ++ else ++ { ++ TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + ++ pEntry->OneSecTxRetryOkCount + ++ pEntry->OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; ++ } ++ ++ ++ // ++ // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI ++ // (criteria copied from RT2500 for Netopia case) ++ // ++ if (TxTotalCnt <= 12) ++ { ++ NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ ++ if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) ++ { ++ pAd->CommonCfg.TxRateIndex = DownRateIdx; ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) ++ { ++ pAd->CommonCfg.TxRateIndex = UpRateIdx; ++ } ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n")); ++ return; ++ } ++ ++ do ++ { ++ ULONG OneSecTxNoRetryOKRationCount; ++ ++ if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0) ++ ratio = 5; ++ else ++ ratio = 4; ++ ++ // downgrade TX quality if PER >= Rate-Down threshold ++ if (TxErrorRatio >= TrainDown) ++ { ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ ++ pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio; ++ ++ OneSecTxNoRetryOKRationCount = (TxSuccess * ratio); ++ ++ // perform DRS - consider TxRate Down first, then rate up. ++ if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) ++ { ++ if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) ++ { ++ pAd->CommonCfg.TxRateIndex = DownRateIdx; ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ ++ } ++ ++ } ++ else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) ++ { ++ if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) ++ { ++ ++ } ++ else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) ++ { ++ pAd->CommonCfg.TxRateIndex = UpRateIdx; ++ } ++ } ++ }while (FALSE); ++ ++ // if rate-up happen, clear all bad history of all TX rates ++ if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) ++ { ++ pAd->DrsCounters.TxRateUpPenalty = 0; ++ NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ } ++ // if rate-down happen, only clear DownRate's bad history ++ else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex)); ++ ++ pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty ++ pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; ++ pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; ++ } ++ else ++ { ++ bTxRateChanged = FALSE; ++ } ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5]; ++ if (bTxRateChanged && pNextTxRate) ++ { ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is executed periodically inside MlmePeriodicExec() after ++ association with an AP. ++ It checks if StaCfg.Psm is consistent with user policy (recorded in ++ StaCfg.WindowsPowerMode). If not, enforce user policy. However, ++ there're some conditions to consider: ++ 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all ++ the time when Mibss==TRUE ++ 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE ++ if outgoing traffic available in TxRing or MgmtRing. ++ Output: ++ 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeCheckPsmChange( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ ULONG PowerMode; ++ ++ // condition - ++ // 1. Psm maybe ON only happen in INFRASTRUCTURE mode ++ // 2. user wants either MAX_PSP or FAST_PSP ++ // 3. but current psm is not in PWR_SAVE ++ // 4. CNTL state machine is not doing SCANning ++ // 5. no TX SUCCESS event for the past 1-sec period ++#ifdef NDIS51_MINIPORT ++ if (pAd->StaCfg.WindowsPowerProfile == NdisPowerProfileBattery) ++ PowerMode = pAd->StaCfg.WindowsBatteryPowerMode; ++ else ++#endif ++ PowerMode = pAd->StaCfg.WindowsPowerMode; ++ ++ if (INFRA_ON(pAd) && ++ (PowerMode != Ndis802_11PowerModeCAM) && ++ (pAd->StaCfg.Psm == PWR_ACTIVE) && ++ (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) ++ { ++ NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); ++ pAd->RalinkCounters.RxCountSinceLastNULL = 0; ++ MlmeSetPsmBit(pAd, PWR_SAVE); ++ if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) ++ { ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); ++ } ++ else ++ { ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ } ++ } ++} ++ ++// IRQL = PASSIVE_LEVEL ++// IRQL = DISPATCH_LEVEL ++VOID MlmeSetPsmBit( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm) ++{ ++ AUTO_RSP_CFG_STRUC csr4; ++ ++ pAd->StaCfg.Psm = psm; ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); ++ csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm)); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeSetTxPreamble( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TxPreamble) ++{ ++ AUTO_RSP_CFG_STRUC csr4; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ //TxPreamble = Rt802_11PreambleLong; ++ ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); ++ if (TxPreamble == Rt802_11PreambleLong) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ csr4.field.AutoResponderPreamble = 0; ++ } ++ else ++ { ++ // NOTE: 1Mbps should always use long preamble ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n")); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ csr4.field.AutoResponderPreamble = 1; ++ } ++ ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Update basic rate bitmap ++ ========================================================================== ++ */ ++ ++VOID UpdateBasicRateBitmap( ++ IN PRTMP_ADAPTER pAdapter) ++{ ++ INT i, j; ++ /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */ ++ UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; ++ UCHAR *sup_p = pAdapter->CommonCfg.SupRate; ++ UCHAR *ext_p = pAdapter->CommonCfg.ExtRate; ++ ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap; ++ ++ ++ /* if A mode, always use fix BasicRateBitMap */ ++ //if (pAdapter->CommonCfg.Channel == PHY_11A) ++ if (pAdapter->CommonCfg.Channel > 14) ++ pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */ ++ /* End of if */ ++ ++ if (pAdapter->CommonCfg.BasicRateBitmap > 4095) ++ { ++ /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */ ++ return; ++ } /* End of if */ ++ ++ for(i=0; iCommonCfg.DesireRate[i] & 0x7f) ++ { ++ case 2: Rate = RATE_1; num++; break; ++ case 4: Rate = RATE_2; num++; break; ++ case 11: Rate = RATE_5_5; num++; break; ++ case 22: Rate = RATE_11; num++; break; ++ case 12: Rate = RATE_6; num++; break; ++ case 18: Rate = RATE_9; num++; break; ++ case 24: Rate = RATE_12; num++; break; ++ case 36: Rate = RATE_18; num++; break; ++ case 48: Rate = RATE_24; num++; break; ++ case 72: Rate = RATE_36; num++; break; ++ case 96: Rate = RATE_48; num++; break; ++ case 108: Rate = RATE_54; num++; break; ++ //default: Rate = RATE_1; break; ++ } ++ if (MaxDesire < Rate) MaxDesire = Rate; ++ } ++ ++//=========================================================================== ++//=========================================================================== ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pHtPhy = &pAd->StaCfg.HTPhyMode; ++ pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; ++ pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; ++ ++ auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; ++ HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; ++ ++ if ((pAd->StaCfg.BssType == BSS_ADHOC) && ++ (pAd->CommonCfg.PhyMode == PHY_11B) && ++ (MaxDesire > RATE_11)) ++ { ++ MaxDesire = RATE_11; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->CommonCfg.MaxDesiredRate = MaxDesire; ++ pMinHtPhy->word = 0; ++ pMaxHtPhy->word = 0; ++ pHtPhy->word = 0; ++ ++ // Auto rate switching is enabled only if more than one DESIRED RATES are ++ // specified; otherwise disabled ++ if (num <= 1) ++ { ++ *auto_rate_cur_p = FALSE; ++ } ++ else ++ { ++ *auto_rate_cur_p = TRUE; ++ } ++ ++#if 1 ++ if (HtMcs != MCS_AUTO) ++ { ++ *auto_rate_cur_p = FALSE; ++ } ++ else ++ { ++ *auto_rate_cur_p = TRUE; ++ } ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ pSupRate = &pAd->StaActive.SupRate[0]; ++ pExtRate = &pAd->StaActive.ExtRate[0]; ++ SupRateLen = pAd->StaActive.SupRateLen; ++ ExtRateLen = pAd->StaActive.ExtRateLen; ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ pSupRate = &pAd->CommonCfg.SupRate[0]; ++ pExtRate = &pAd->CommonCfg.ExtRate[0]; ++ SupRateLen = pAd->CommonCfg.SupRateLen; ++ ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ } ++ ++ // find max supported rate ++ for (i=0; i Rate) MinSupport = Rate; ++ } ++ ++ for (i=0; i Rate) MinSupport = Rate; ++ } ++ ++ RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap); ++ ++ // calculate the exptected ACK rate for each TX rate. This info is used to caculate ++ // the DURATION field of outgoing uniicast DATA/MGMT frame ++ for (i=0; iCommonCfg.ExpectedACKRate[i] = CurrBasicRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire])); ++ // max tx rate = min {max desire rate, max supported rate} ++ if (MaxSupport < MaxDesire) ++ pAd->CommonCfg.MaxTxRate = MaxSupport; ++ else ++ pAd->CommonCfg.MaxTxRate = MaxDesire; ++ ++ pAd->CommonCfg.MinTxRate = MinSupport; ++ if (*auto_rate_cur_p) ++ { ++ short dbm = 0; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; ++#endif // CONFIG_STA_SUPPORT // ++ if (bLinkUp == TRUE) ++ pAd->CommonCfg.TxRate = RATE_24; ++ else ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ ++ if (dbm < -75) ++ pAd->CommonCfg.TxRate = RATE_11; ++ else if (dbm < -70) ++ pAd->CommonCfg.TxRate = RATE_24; ++ ++ // should never exceed MaxTxRate (consider 11B-only mode) ++ if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate) ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ ++ pAd->CommonCfg.TxRateIndex = 0; ++ } ++ else ++ { ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate; ++ pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK; ++ ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE; ++ } ++ ++ if (pAd->CommonCfg.TxRate <= RATE_11) ++ { ++ pMaxHtPhy->field.MODE = MODE_CCK; ++ pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate; ++ pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate; ++ } ++ else ++ { ++ pMaxHtPhy->field.MODE = MODE_OFDM; ++ pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate]; ++ if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54)) ++ {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];} ++ else ++ {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;} ++ } ++ ++ pHtPhy->word = (pMaxHtPhy->word); ++ if (bLinkUp && (pAd->OpMode == OPMODE_STA)) ++ { ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word; ++ pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word; ++ pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word; ++ } ++ else ++ { ++ switch (pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11BG_MIXED: ++ case PHY_11B: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11BGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.MlmeRate = RATE_1; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; ++ pAd->CommonCfg.RtsRate = RATE_11; ++ break; ++ case PHY_11G: ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AGN_MIXED: ++ case PHY_11GN_MIXED: ++ case PHY_11N_2_4G: ++ case PHY_11AN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ break; ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ pAd->CommonCfg.MlmeRate = RATE_1; ++ pAd->CommonCfg.RtsRate = RATE_1; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; ++ } ++ else ++ { ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ break; ++ default: // error ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->CommonCfg.RtsRate = RATE_1; ++ break; ++ } ++ // ++ // Keep Basic Mlme Rate. ++ // ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word; ++ if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM) ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24]; ++ else ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1; ++ pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n", ++ RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate], ++ /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n", ++ RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n", ++ pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); ++} ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ This function update HT Rate setting. ++ Input Wcid value is valid for 2 case : ++ 1. it's used for Station in infra mode that copy AP rate to Mactable. ++ 2. OR Station in adhoc mode to copy peer's HT rate to Mactable. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeUpdateHtTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx) ++{ ++ UCHAR StbcMcs; //j, StbcMcs, bitmask; ++ CHAR i; // 3*3 ++ RT_HT_CAPABILITY *pRtHtCap = NULL; ++ RT_HT_PHY_INFO *pActiveHtPhy = NULL; ++ ULONG BasicMCS; ++ UCHAR j, bitmask; ++ PRT_HT_PHY_INFO pDesireHtPhy = NULL; ++ PHTTRANSMIT_SETTING pHtPhy = NULL; ++ PHTTRANSMIT_SETTING pMaxHtPhy = NULL; ++ PHTTRANSMIT_SETTING pMinHtPhy = NULL; ++ BOOLEAN *auto_rate_cur_p; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n")); ++ ++ auto_rate_cur_p = NULL; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; ++ pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; ++ pHtPhy = &pAd->StaCfg.HTPhyMode; ++ pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; ++ pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; ++ ++ auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ return; ++ ++ pRtHtCap = &pAd->StaActive.SupportedHtPhy; ++ pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo; ++ StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs; ++ BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16); ++ if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) ++ pMaxHtPhy->field.STBC = STBC_USE; ++ else ++ pMaxHtPhy->field.STBC = STBC_NONE; ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ if (pDesireHtPhy->bHtEnable == FALSE) ++ return; ++ ++ pRtHtCap = &pAd->CommonCfg.DesiredHtPhy; ++ StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs; ++ BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16); ++ if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) ++ pMaxHtPhy->field.STBC = STBC_USE; ++ else ++ pMaxHtPhy->field.STBC = STBC_NONE; ++ } ++ ++ // Decide MAX ht rate. ++ if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ pMaxHtPhy->field.MODE = MODE_HTGREENFIELD; ++ else ++ pMaxHtPhy->field.MODE = MODE_HTMIX; ++ ++ if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth)) ++ pMaxHtPhy->field.BW = BW_40; ++ else ++ pMaxHtPhy->field.BW = BW_20; ++ ++ if (pMaxHtPhy->field.BW == BW_20) ++ pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20); ++ else ++ pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40); ++ ++ for (i=23; i>=0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ ++ if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask)) ++ { ++ pMaxHtPhy->field.MCS = i; ++ break; ++ } ++ ++ if (i==0) ++ break; ++ } ++ ++ // Copy MIN ht rate. rt2860??? ++ pMinHtPhy->field.BW = BW_20; ++ pMinHtPhy->field.MCS = 0; ++ pMinHtPhy->field.STBC = 0; ++ pMinHtPhy->field.ShortGI = 0; ++ //If STA assigns fixed rate. update to fixed here. ++#ifdef CONFIG_STA_SUPPORT ++ if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) ++ { ++ if (pDesireHtPhy->MCSSet[4] != 0) ++ { ++ pMaxHtPhy->field.MCS = 32; ++ pMinHtPhy->field.MCS = 32; ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS)); ++ } ++ ++ for (i=23; (CHAR)i >= 0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask)) ++ { ++ pMaxHtPhy->field.MCS = i; ++ pMinHtPhy->field.MCS = i; ++ break; ++ } ++ if (i==0) ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ // Decide ht rate ++ pHtPhy->field.STBC = pMaxHtPhy->field.STBC; ++ pHtPhy->field.BW = pMaxHtPhy->field.BW; ++ pHtPhy->field.MODE = pMaxHtPhy->field.MODE; ++ pHtPhy->field.MCS = pMaxHtPhy->field.MCS; ++ pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI; ++ ++ // use default now. rt2860 ++ if (pDesireHtPhy->MCSSet[0] != 0xff) ++ *auto_rate_cur_p = FALSE; ++ else ++ *auto_rate_cur_p = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize )); ++ DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS, ++ pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); ++} ++#endif // DOT11_N_SUPPORT // ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRadioOff( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RT28XX_MLME_RADIO_OFF(pAd); ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRadioOn( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RT28XX_MLME_RADIO_ON(pAd); ++} ++ ++// =========================================================================================== ++// bss_table.c ++// =========================================================================================== ++ ++ ++/*! \brief initialize BSS table ++ * \param p_tab pointer to the table ++ * \return none ++ * \pre ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID BssTableInit( ++ IN BSS_TABLE *Tab) ++{ ++ int i; ++ ++ Tab->BssNr = 0; ++ Tab->BssOverlapNr = 0; ++ for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) ++ { ++ NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY)); ++ Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value ++ } ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInit( ++ IN PRTMP_ADAPTER pAd, ++ IN BA_TABLE *Tab) ++{ ++ int i; ++ ++ Tab->numAsOriginator = 0; ++ Tab->numAsRecipient = 0; ++ NdisAllocateSpinLock(&pAd->BATabLock); ++ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE; ++ NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock)); ++ } ++ for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) ++ { ++ Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++/*! \brief search the BSS table by SSID ++ * \param p_tab pointer to the bss table ++ * \param ssid SSID string ++ * \return index of the table, BSS_NOT_FOUND if not in the table ++ * \pre ++ * \post ++ * \note search by sequential search ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++ULONG BssTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ // ++ // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. ++ // We should distinguish this case. ++ // ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++ULONG BssSsidTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ // ++ // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. ++ // We should distinguish this case. ++ // ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) && ++ SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++ULONG BssTableSearchWithSSID( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR Bssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) && ++ (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) || ++ (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) || ++ (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen)))) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableDeleteEntry( ++ IN OUT BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel) ++{ ++ UCHAR i, j; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ if ((Tab->BssEntry[i].Channel == Channel) && ++ (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) ++ { ++ for (j = i; j < Tab->BssNr - 1; j++) ++ { ++ NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); ++ } ++ NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY)); ++ Tab->BssNr -= 1; ++ return; ++ } ++ } ++} ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ======================================================================== ++ Routine Description: ++ Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed. ++ ++ Arguments: ++ // IRQL = DISPATCH_LEVEL ++ ======================================================================== ++*/ ++VOID BATableDeleteORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_ORI_ENTRY *pBAORIEntry) ++{ ++ ++ if (pBAORIEntry->ORI_BA_Status != Originator_NONE) ++ { ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ if (pBAORIEntry->ORI_BA_Status == Originator_Done) ++ { ++ pAd->BATable.numAsOriginator -= 1; ++ DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); ++ // Erase Bitmap flag. ++ } ++ pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here ++ pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here ++ pBAORIEntry->ORI_BA_Status = Originator_NONE; ++ pBAORIEntry->Token = 1; ++ // Not clear Sequence here. ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++/*! \brief ++ * \param ++ * \return ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID BssEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_ENTRY *pBss, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN PCF_PARM pCfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ COPY_MAC_ADDR(pBss->Bssid, pBssid); ++ // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID ++ pBss->Hidden = 1; ++ if (SsidLen > 0) ++ { ++ // For hidden SSID AP, it might send beacon with SSID len equal to 0 ++ // Or send beacon /probe response with SSID len matching real SSID length, ++ // but SSID is all zero. such as "00-00-00-00" with length 4. ++ // We have to prevent this case overwrite correct table ++ if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) ++ { ++ NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pBss->Ssid, Ssid, SsidLen); ++ pBss->SsidLen = SsidLen; ++ pBss->Hidden = 0; ++ } ++ } ++ else ++ pBss->SsidLen = 0; ++ pBss->BssType = BssType; ++ pBss->BeaconPeriod = BeaconPeriod; ++ if (BssType == BSS_INFRA) ++ { ++ if (pCfParm->bValid) ++ { ++ pBss->CfpCount = pCfParm->CfpCount; ++ pBss->CfpPeriod = pCfParm->CfpPeriod; ++ pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; ++ pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; ++ } ++ } ++ else ++ { ++ pBss->AtimWin = AtimWin; ++ } ++ ++ pBss->CapabilityInfo = CapabilityInfo; ++ // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES ++ // Combine with AuthMode, they will decide the connection methods. ++ pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); ++ ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES); ++ if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen); ++ else ++ NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pBss->SupRateLen = SupRateLen; ++ ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen); ++ NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); ++ NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); ++ pBss->NewExtChanOffset = NewExtChanOffset; ++ pBss->ExtRateLen = ExtRateLen; ++ pBss->Channel = Channel; ++ pBss->CentralChannel = Channel; ++ pBss->Rssi = Rssi; ++ // Update CkipFlag. if not exists, the value is 0x0 ++ pBss->CkipFlag = CkipFlag; ++ ++ // New for microsoft Fixed IEs ++ NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8); ++ pBss->FixIEs.BeaconInterval = BeaconPeriod; ++ pBss->FixIEs.Capabilities = CapabilityInfo; ++ ++ // New for microsoft Variable IEs ++ if (LengthVIE != 0) ++ { ++ pBss->VarIELen = LengthVIE; ++ NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen); ++ } ++ else ++ { ++ pBss->VarIELen = 0; ++ } ++ ++ pBss->AddHtInfoLen = 0; ++ pBss->HtCapabilityLen = 0; ++#ifdef DOT11_N_SUPPORT ++ if (HtCapabilityLen> 0) ++ { ++ pBss->HtCapabilityLen = HtCapabilityLen; ++ NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); ++ if (AddHtInfoLen > 0) ++ { ++ pBss->AddHtInfoLen = AddHtInfoLen; ++ NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); ++ ++ if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) ++ { ++ pBss->CentralChannel = pAddHtInfo->ControlChan - 2; ++ } ++ else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) ++ { ++ pBss->CentralChannel = pAddHtInfo->ControlChan + 2; ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ BssCipherParse(pBss); ++ ++ // new for QOS ++ if (pEdcaParm) ++ NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ else ++ pBss->EdcaParm.bValid = FALSE; ++ if (pQosCapability) ++ NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ else ++ pBss->QosCapability.bValid = FALSE; ++ if (pQbssLoad) ++ NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ else ++ pBss->QbssLoad.bValid = FALSE; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ PEID_STRUCT pEid; ++ USHORT Length = 0; ++ ++ ++ NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); ++ NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ NdisZeroMemory(&pBss->CountryString[0], 3); ++ pBss->bHasCountryIE = FALSE; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ pEid = (PEID_STRUCT) pVIE; ++ while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) ++ { ++ switch(pEid->Eid) ++ { ++ case IE_WPA: ++ if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ { ++ if ((pEid->Len + 2) > MAX_CUSTOM_LEN) ++ { ++ pBss->WpaIE.IELen = 0; ++ break; ++ } ++ pBss->WpaIE.IELen = pEid->Len + 2; ++ NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen); ++ } ++ break; ++ case IE_RSN: ++ if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ { ++ if ((pEid->Len + 2) > MAX_CUSTOM_LEN) ++ { ++ pBss->RsnIE.IELen = 0; ++ break; ++ } ++ pBss->RsnIE.IELen = pEid->Len + 2; ++ NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); ++ } ++ break; ++#ifdef EXT_BUILD_CHANNEL_LIST ++ case IE_COUNTRY: ++ NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); ++ pBss->bHasCountryIE = TRUE; ++ break; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ } ++ Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++} ++ ++/*! ++ * \brief insert an entry into the bss table ++ * \param p_tab The BSS table ++ * \param Bssid BSSID ++ * \param ssid SSID ++ * \param ssid_len Length of SSID ++ * \param bss_type ++ * \param beacon_period ++ * \param timestamp ++ * \param p_cf ++ * \param atim_win ++ * \param cap ++ * \param rates ++ * \param rates_len ++ * \param channel_idx ++ * \return none ++ * \pre ++ * \post ++ * \note If SSID is identical, the old entry will be replaced by the new one ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++ULONG BssTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN CF_PARM *CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR ChannelNo, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ ULONG Idx; ++ ++ Idx = BssTableSearchWithSSID(Tab, pBssid, Ssid, SsidLen, ChannelNo); ++ if (Idx == BSS_NOT_FOUND) ++ { ++ if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) ++ { ++ // ++ // It may happen when BSS Table was full. ++ // The desired AP will not be added into BSS Table ++ // In this case, if we found the desired AP then overwrite BSS Table. ++ // ++ if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) || ++ SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)) ++ { ++ Idx = Tab->BssOverlapNr; ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE; ++ } ++ return Idx; ++ } ++ else ++ { ++ return BSS_NOT_FOUND; ++ } ++ } ++ Idx = Tab->BssNr; ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ Tab->BssNr++; ++ } ++ else ++ { ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ } ++ ++ return Idx; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++VOID TriEventInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ ++ for (i = 0;i < MAX_TRIGGER_EVENT;i++) ++ pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; ++ ++ pAd->CommonCfg.TriggerEventTab.EventANo = 0; ++ pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; ++} ++ ++ULONG TriEventTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT TRIGGER_EVENT_TAB *Tab, ++ IN PUCHAR pBssid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR RegClass, ++ IN UCHAR ChannelNo) ++{ ++ // Event A ++ if (HtCapabilityLen == 0) ++ { ++ if (Tab->EventANo < MAX_TRIGGER_EVENT) ++ { ++ RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); ++ Tab->EventA[Tab->EventANo].bValid = TRUE; ++ Tab->EventA[Tab->EventANo].Channel = ChannelNo; ++ Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; ++ if (RegClass != 0) ++ { ++ // Beacon has Regulatory class IE. So use beacon's ++ Tab->EventA[Tab->EventANo].RegClass = RegClass; ++ } ++ else ++ { ++ // Use Station's Regulatory class instead. ++ if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) ++ { ++ if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) ++ { ++ Tab->EventA[Tab->EventANo].RegClass = 32; ++ } ++ else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) ++ Tab->EventA[Tab->EventANo].RegClass = 33; ++ } ++ else ++ Tab->EventA[Tab->EventANo].RegClass = ??; ++ ++ } ++ ++ Tab->EventANo ++; ++ } ++ } ++ else if (pHtCapability->HtCapInfo.Intolerant40) ++ { ++ Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Trigger Event table Maintainence called once every second. ++ ++ Arguments: ++ // IRQL = DISPATCH_LEVEL ++ ======================================================================== ++*/ ++VOID TriEventCounterMaintenance( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ BOOLEAN bNotify = FALSE; ++ for (i = 0;i < MAX_TRIGGER_EVENT;i++) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; ++ pAd->CommonCfg.TriggerEventTab.EventANo --; ++ // Need to send 20/40 Coexistence Notify frame if has status change. ++ bNotify = TRUE; ++ } ++ } ++ } ++ if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventBCountDown--; ++ if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) ++ bNotify = TRUE; ++ } ++ ++ if (bNotify == TRUE) ++ Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableSsidSort( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *OutTab, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen) ++{ ++ INT i; ++ BssTableInit(OutTab); ++ ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i]; ++ BOOLEAN bIsHiddenApIncluded = FALSE; ++ ++ if (((pAd->CommonCfg.bIEEE80211H == 1) && ++ (pAd->MlmeAux.Channel > 14) && ++ RadarChannelCheck(pAd, pInBss->Channel)) ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ if (pInBss->Hidden) ++ bIsHiddenApIncluded = TRUE; ++ } ++ ++ if ((pInBss->BssType == pAd->StaCfg.BssType) && ++ (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded)) ++ { ++ BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; ++ ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. ++ if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && ++ (pInBss->bHasCountryIE == FALSE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); ++ continue; ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef DOT11_N_SUPPORT ++ // 2.4G/5G N only mode ++ if ((pInBss->HtCapabilityLen == 0) && ++ ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); ++ continue; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // New for WPA2 ++ // Check the Authmode first ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode ++ if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) ++ // None matched ++ continue; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) ++ continue; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA2.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) ++ continue; ++ } ++ } ++ // Bss Type matched, SSID matched. ++ // We will check wepstatus for qualification Bss ++ else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus)); ++ // ++ // For the SESv2 case, we will not qualify WepStatus. ++ // ++ if (!pInBss->bSES) ++ continue; ++ } ++ ++ // Since the AP is using hidden SSID, and we are trying to connect to ANY ++ // It definitely will fail. So, skip it. ++ // CCX also require not even try to connect it!! ++ if (SsidLen == 0) ++ continue; ++ ++#ifdef DOT11_N_SUPPORT ++ // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region ++ // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, ++ if ((pInBss->CentralChannel != pInBss->Channel) && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ SetCommonHT(pAd); ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ else ++ { ++ if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20) ++ { ++ SetCommonHT(pAd); ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // copy matching BSS from InTab to OutTab ++ NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); ++ ++ OutTab->BssNr++; ++ } ++ else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0)) ++ { ++ BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; ++ ++ ++#ifdef DOT11_N_SUPPORT ++ // 2.4G/5G N only mode ++ if ((pInBss->HtCapabilityLen == 0) && ++ ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); ++ continue; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // New for WPA2 ++ // Check the Authmode first ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode ++ if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) ++ // None matched ++ continue; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) ++ continue; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA2.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) ++ continue; ++ } ++ } ++ // Bss Type matched, SSID matched. ++ // We will check wepstatus for qualification Bss ++ else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) ++ continue; ++ ++#ifdef DOT11_N_SUPPORT ++ // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region ++ // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, ++ if ((pInBss->CentralChannel != pInBss->Channel) && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ SetCommonHT(pAd); ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // copy matching BSS from InTab to OutTab ++ NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); ++ ++ OutTab->BssNr++; ++ } ++ ++ if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) ++ break; ++ } ++ ++ BssTableSortByRssi(OutTab); ++} ++ ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableSortByRssi( ++ IN OUT BSS_TABLE *OutTab) ++{ ++ INT i, j; ++ BSS_ENTRY TmpBss; ++ ++ for (i = 0; i < OutTab->BssNr - 1; i++) ++ { ++ for (j = i+1; j < OutTab->BssNr; j++) ++ { ++ if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) ++ { ++ NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); ++ NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); ++ NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); ++ } ++ } ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++VOID BssCipherParse( ++ IN OUT PBSS_ENTRY pBss) ++{ ++ PEID_STRUCT pEid; ++ PUCHAR pTmp; ++ PRSN_IE_HEADER_STRUCT pRsnHeader; ++ PCIPHER_SUITE_STRUCT pCipher; ++ PAKM_SUITE_STRUCT pAKM; ++ USHORT Count; ++ INT Length; ++ NDIS_802_11_ENCRYPTION_STATUS TmpCipher; ++ ++ // ++ // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. ++ // ++ if (pBss->Privacy) ++ { ++ pBss->WepStatus = Ndis802_11WEPEnabled; ++ } ++ else ++ { ++ pBss->WepStatus = Ndis802_11WEPDisabled; ++ } ++ // Set default to disable & open authentication before parsing variable IE ++ pBss->AuthMode = Ndis802_11AuthModeOpen; ++ pBss->AuthModeAux = Ndis802_11AuthModeOpen; ++ ++ // Init WPA setting ++ pBss->WPA.PairCipher = Ndis802_11WEPDisabled; ++ pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled; ++ pBss->WPA.GroupCipher = Ndis802_11WEPDisabled; ++ pBss->WPA.RsnCapability = 0; ++ pBss->WPA.bMixMode = FALSE; ++ ++ // Init WPA2 setting ++ pBss->WPA2.PairCipher = Ndis802_11WEPDisabled; ++ pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled; ++ pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled; ++ pBss->WPA2.RsnCapability = 0; ++ pBss->WPA2.bMixMode = FALSE; ++ ++ ++ Length = (INT) pBss->VarIELen; ++ ++ while (Length > 0) ++ { ++ // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently ++ pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length; ++ pEid = (PEID_STRUCT) pTmp; ++ switch (pEid->Eid) ++ { ++ case IE_WPA: ++ //Parse Cisco IE_WPA (LEAP, CCKM, etc.) ++ if ( NdisEqualMemory((pTmp+8), CISCO_OUI, 3)) ++ { ++ pTmp += 11; ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WepStatus = Ndis802_11Encryption1Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WepStatus = Ndis802_11Encryption2Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 4: ++ pBss->WepStatus = Ndis802_11Encryption3Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ default: ++ break; ++ } ++ ++ // if Cisco IE_WPA, break ++ break; ++ } ++ else if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7)) ++ { ++ pBss->bSES = TRUE; ++ break; ++ } ++ else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1) ++ { ++ // if unsupported vendor specific IE ++ break; ++ } ++ // Skip OUI, version, and multicast suite ++ // This part should be improved in the future when AP supported multiple cipher suite. ++ // For now, it's OK since almost all APs have fixed cipher suite supported. ++ // pTmp = (PUCHAR) pEid->Octet; ++ pTmp += 11; ++ ++ // Cipher Suite Selectors from Spec P802.11i/D3.2 P26. ++ // Value Meaning ++ // 0 None ++ // 1 WEP-40 ++ // 2 Tkip ++ // 3 WRAP ++ // 4 AES ++ // 5 WEP-104 ++ // Parse group cipher ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ // number of unicast suite ++ pTmp += 1; ++ ++ // skip all unicast cipher suites ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // Parsing all unicast cipher suite ++ while (Count > 0) ++ { ++ // Skip OUI ++ pTmp += 3; ++ TmpCipher = Ndis802_11WEPDisabled; ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ TmpCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ TmpCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ TmpCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ if (TmpCipher > pBss->WPA.PairCipher) ++ { ++ // Move the lower cipher suite to PairCipherAux ++ pBss->WPA.PairCipherAux = pBss->WPA.PairCipher; ++ pBss->WPA.PairCipher = TmpCipher; ++ } ++ else ++ { ++ pBss->WPA.PairCipherAux = TmpCipher; ++ } ++ pTmp++; ++ Count--; ++ } ++ ++ // 4. get AKM suite counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ pTmp += 3; ++ ++ switch (*pTmp) ++ { ++ case 1: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA; ++ break; ++ case 2: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPAPSK; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK; ++ break; ++ default: ++ break; ++ } ++ pTmp += 1; ++ ++ // Fixed for WPA-None ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ pBss->AuthMode = Ndis802_11AuthModeWPANone; ++ pBss->AuthModeAux = Ndis802_11AuthModeWPANone; ++ pBss->WepStatus = pBss->WPA.GroupCipher; ++ // Patched bugs for old driver ++ if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) ++ pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; ++ } ++ else ++ pBss->WepStatus = pBss->WPA.PairCipher; ++ ++ // Check the Pair & Group, if different, turn on mixed mode flag ++ if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher) ++ pBss->WPA.bMixMode = TRUE; ++ ++ break; ++ ++ case IE_RSN: ++ pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp; ++ ++ // 0. Version must be 1 ++ if (le2cpu16(pRsnHeader->Version) != 1) ++ break; ++ pTmp += sizeof(RSN_IE_HEADER_STRUCT); ++ ++ // 1. Check group cipher ++ pCipher = (PCIPHER_SUITE_STRUCT) pTmp; ++ if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) ++ break; ++ ++ // Parse group cipher ++ switch (pCipher->Type) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ // set to correct offset for next parsing ++ pTmp += sizeof(CIPHER_SUITE_STRUCT); ++ ++ // 2. Get pairwise cipher counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // 3. Get pairwise cipher ++ // Parsing all unicast cipher suite ++ while (Count > 0) ++ { ++ // Skip OUI ++ pCipher = (PCIPHER_SUITE_STRUCT) pTmp; ++ TmpCipher = Ndis802_11WEPDisabled; ++ switch (pCipher->Type) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ TmpCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ TmpCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ TmpCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ if (TmpCipher > pBss->WPA2.PairCipher) ++ { ++ // Move the lower cipher suite to PairCipherAux ++ pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher; ++ pBss->WPA2.PairCipher = TmpCipher; ++ } ++ else ++ { ++ pBss->WPA2.PairCipherAux = TmpCipher; ++ } ++ pTmp += sizeof(CIPHER_SUITE_STRUCT); ++ Count--; ++ } ++ ++ // 4. get AKM suite counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // 5. Get AKM ciphers ++ pAKM = (PAKM_SUITE_STRUCT) pTmp; ++ if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) ++ break; ++ ++ switch (pAKM->Type) ++ { ++ case 1: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA2; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA2; ++ break; ++ case 2: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA2PSK; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK; ++ break; ++ default: ++ break; ++ } ++ pTmp += (Count * sizeof(AKM_SUITE_STRUCT)); ++ ++ // Fixed for WPA-None ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ pBss->AuthMode = Ndis802_11AuthModeWPANone; ++ pBss->AuthModeAux = Ndis802_11AuthModeWPANone; ++ pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; ++ pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; ++ pBss->WepStatus = pBss->WPA.GroupCipher; ++ // Patched bugs for old driver ++ if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) ++ pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; ++ } ++ pBss->WepStatus = pBss->WPA2.PairCipher; ++ ++ // 6. Get RSN capability ++ //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp; ++ pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // Check the Pair & Group, if different, turn on mixed mode flag ++ if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher) ++ pBss->WPA2.bMixMode = TRUE; ++ ++ break; ++ default: ++ break; ++ } ++ Length -= (pEid->Len + 2); ++ } ++} ++ ++// =========================================================================================== ++// mac_table.c ++// =========================================================================================== ++ ++/*! \brief generates a random mac address value for IBSS BSSID ++ * \param Addr the bssid location ++ * \return none ++ * \pre ++ * \post ++ */ ++VOID MacAddrRandomBssid( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pAddr) ++{ ++ INT i; ++ ++ for (i = 0; i < MAC_ADDR_LEN; i++) ++ { ++ pAddr[i] = RandomByte(pAd); ++ } ++ ++ pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx ++} ++ ++/*! \brief init the management mac frame header ++ * \param p_hdr mac header ++ * \param subtype subtype of the frame ++ * \param p_ds destination address, don't care if it is a broadcast address ++ * \return none ++ * \pre the station has the following information in the pAd->StaCfg ++ * - bssid ++ * - station address ++ * \post ++ * \note this function initializes the following field ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID MgtMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SubType; ++ pHdr80211->FC.ToDs = ToDs; ++ COPY_MAC_ADDR(pHdr80211->Addr1, pDA); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); ++} ++ ++// =========================================================================================== ++// mem_mgmt.c ++// =========================================================================================== ++ ++/*!*************************************************************************** ++ * This routine build an outgoing frame, and fill all information specified ++ * in argument list to the frame body. The actual frame size is the summation ++ * of all arguments. ++ * input params: ++ * Buffer - pointer to a pre-allocated memory segment ++ * args - a list of pairs. ++ * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this ++ * function will FAIL!!! ++ * return: ++ * Size of the buffer ++ * usage: ++ * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ****************************************************************************/ ++ULONG MakeOutgoingFrame( ++ OUT CHAR *Buffer, ++ OUT ULONG *FrameLen, ...) ++{ ++ CHAR *p; ++ int leng; ++ ULONG TotLeng; ++ va_list Args; ++ ++ // calculates the total length ++ TotLeng = 0; ++ va_start(Args, FrameLen); ++ do ++ { ++ leng = va_arg(Args, int); ++ if (leng == END_OF_ARGS) ++ { ++ break; ++ } ++ p = va_arg(Args, PVOID); ++ NdisMoveMemory(&Buffer[TotLeng], p, leng); ++ TotLeng = TotLeng + leng; ++ } while(TRUE); ++ ++ va_end(Args); /* clean up */ ++ *FrameLen = TotLeng; ++ return TotLeng; ++} ++ ++// =========================================================================================== ++// mlme_queue.c ++// =========================================================================================== ++ ++/*! \brief Initialize The MLME Queue, used by MLME Functions ++ * \param *Queue The MLME Queue ++ * \return Always Return NDIS_STATE_SUCCESS in this implementation ++ * \pre ++ * \post ++ * \note Because this is done only once (at the init stage), no need to be locked ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++NDIS_STATUS MlmeQueueInit( ++ IN MLME_QUEUE *Queue) ++{ ++ INT i; ++ ++ NdisAllocateSpinLock(&Queue->Lock); ++ ++ Queue->Num = 0; ++ Queue->Head = 0; ++ Queue->Tail = 0; ++ ++ for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) ++ { ++ Queue->Entry[i].Occupied = FALSE; ++ Queue->Entry[i].MsgLen = 0; ++ NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE); ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread ++ * \param *Queue The MLME Queue ++ * \param Machine The State Machine Id ++ * \param MsgType The Message Type ++ * \param MsgLen The Message length ++ * \param *Msg The message pointer ++ * \return TRUE if enqueue is successful, FALSE if the queue is full ++ * \pre ++ * \post ++ * \note The message has to be initialized ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeEnqueue( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Machine, ++ IN ULONG MsgType, ++ IN ULONG MsgLen, ++ IN VOID *Msg) ++{ ++ INT Tail; ++ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return FALSE; ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ ++ if (MlmeQueueFull(Queue)) ++ { ++ return FALSE; ++ } ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Tail = Queue->Tail; ++ Queue->Tail++; ++ Queue->Num++; ++ if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Tail = 0; ++ } ++ ++ Queue->Entry[Tail].Wcid = RESERVED_WCID; ++ Queue->Entry[Tail].Occupied = TRUE; ++ Queue->Entry[Tail].Machine = Machine; ++ Queue->Entry[Tail].MsgType = MsgType; ++ Queue->Entry[Tail].MsgLen = MsgLen; ++ ++ if (Msg != NULL) ++ { ++ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); ++ } ++ ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ return TRUE; ++} ++ ++/*! \brief This function is used when Recv gets a MLME message ++ * \param *Queue The MLME Queue ++ * \param TimeStampHigh The upper 32 bit of timestamp ++ * \param TimeStampLow The lower 32 bit of timestamp ++ * \param Rssi The receiving RSSI strength ++ * \param MsgLen The length of the message ++ * \param *Msg The message pointer ++ * \return TRUE if everything ok, FALSE otherwise (like Queue Full) ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG TimeStampHigh, ++ IN ULONG TimeStampLow, ++ IN UCHAR Rssi0, ++ IN UCHAR Rssi1, ++ IN UCHAR Rssi2, ++ IN ULONG MsgLen, ++ IN VOID *Msg, ++ IN UCHAR Signal) ++{ ++ INT Tail, Machine; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ INT MsgType; ++ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; ++ ++#ifdef RALINK_ATE ++ /* Nothing to do in ATE mode */ ++ if(ATE_ON(pAd)) ++ return FALSE; ++#endif // RALINK_ATE // ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); ++ return FALSE; ++ } ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ ++ if (MlmeQueueFull(Queue)) ++ { ++ return FALSE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType)); ++ return FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // OK, we got all the informations, it is time to put things into queue ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Tail = Queue->Tail; ++ Queue->Tail++; ++ Queue->Num++; ++ if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Tail = 0; ++ } ++ Queue->Entry[Tail].Occupied = TRUE; ++ Queue->Entry[Tail].Machine = Machine; ++ Queue->Entry[Tail].MsgType = MsgType; ++ Queue->Entry[Tail].MsgLen = MsgLen; ++ Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow; ++ Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh; ++ Queue->Entry[Tail].Rssi0 = Rssi0; ++ Queue->Entry[Tail].Rssi1 = Rssi1; ++ Queue->Entry[Tail].Rssi2 = Rssi2; ++ Queue->Entry[Tail].Signal = Signal; ++ Queue->Entry[Tail].Wcid = (UCHAR)Wcid; ++ ++ Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel; ++ ++ if (Msg != NULL) ++ { ++ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); ++ } ++ ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return TRUE; ++} ++ ++ ++/*! \brief Dequeue a message from the MLME Queue ++ * \param *Queue The MLME Queue ++ * \param *Elem The message dequeued from MLME Queue ++ * \return TRUE if the Elem contains something, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeDequeue( ++ IN MLME_QUEUE *Queue, ++ OUT MLME_QUEUE_ELEM **Elem) ++{ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ *Elem = &(Queue->Entry[Queue->Head]); ++ Queue->Num--; ++ Queue->Head++; ++ if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Head = 0; ++ } ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ return TRUE; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRestartStateMachine( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef RT2860 ++ MLME_QUEUE_ELEM *Elem = NULL; ++#endif // RT2860 // ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN Cancelled; ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); ++ ++#ifdef RT2860 ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ if(pAd->Mlme.bRunning) ++ { ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ return; ++ } ++ else ++ { ++ pAd->Mlme.bRunning = TRUE; ++ } ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ ++ // Remove all Mlme queues elements ++ while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) ++ { ++ //From message type, determine which state machine I should drive ++ if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) ++ { ++ // free MLME element ++ Elem->Occupied = FALSE; ++ Elem->MsgLen = 0; ++ ++ } ++ else { ++ DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n")); ++ } ++ } ++#endif // RT2860 // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef QOS_DLS_SUPPORT ++ UCHAR i; ++#endif // QOS_DLS_SUPPORT // ++ // Cancel all timer events ++ // Be careful to cancel new added timer ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++ ++#ifdef QOS_DLS_SUPPORT ++ for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); ++ } ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Change back to original channel in case of doing scan ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // Resume MSDU which is turned off durning scan ++ RTMPResumeMsduTransmission(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Set all state machines back IDLE ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ pAd->Mlme.ActMachine.CurrState = ACT_IDLE; ++#ifdef QOS_DLS_SUPPORT ++ pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RT2860 ++ // Remove running state ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ pAd->Mlme.bRunning = FALSE; ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++#endif // RT2860 // ++} ++ ++/*! \brief test if the MLME Queue is empty ++ * \param *Queue The MLME Queue ++ * \return TRUE if the Queue is empty, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeQueueEmpty( ++ IN MLME_QUEUE *Queue) ++{ ++ BOOLEAN Ans; ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Ans = (Queue->Num == 0); ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ return Ans; ++} ++ ++/*! \brief test if the MLME Queue is full ++ * \param *Queue The MLME Queue ++ * \return TRUE if the Queue is empty, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeQueueFull( ++ IN MLME_QUEUE *Queue) ++{ ++ BOOLEAN Ans; ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied); ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ return Ans; ++} ++ ++/*! \brief The destructor of MLME Queue ++ * \param ++ * \return ++ * \pre ++ * \post ++ * \note Clear Mlme Queue, Set Queue->Num to Zero. ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID MlmeQueueDestroy( ++ IN MLME_QUEUE *pQueue) ++{ ++ NdisAcquireSpinLock(&(pQueue->Lock)); ++ pQueue->Num = 0; ++ pQueue->Head = 0; ++ pQueue->Tail = 0; ++ NdisReleaseSpinLock(&(pQueue->Lock)); ++ NdisFreeSpinLock(&(pQueue->Lock)); ++} ++ ++/*! \brief To substitute the message type if the message is coming from external ++ * \param pFrame The frame received ++ * \param *Machine The state machine ++ * \param *MsgType the message type for the state machine ++ * \return TRUE if the substitution is successful, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++#ifdef CONFIG_STA_SUPPORT ++BOOLEAN MsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType) ++{ ++ USHORT Seq; ++ UCHAR EAPType; ++ PUCHAR pData; ++ ++ // Pointer to start of data frames including SNAP header ++ pData = (PUCHAR) pFrame + LENGTH_802_11; ++ ++ // The only data type will pass to this function is EAPOL frame ++ if (pFrame->Hdr.FC.Type == BTYPE_DATA) ++ { ++ if (NdisEqualMemory(SNAP_AIRONET, pData, LENGTH_802_1_H)) ++ { ++ // Cisco Aironet SNAP header ++ *Machine = AIRONET_STATE_MACHINE; ++ *MsgType = MT2_AIRONET_MSG; ++ return (TRUE); ++ } ++#ifdef LEAP_SUPPORT ++ if ( pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP ) //LEAP ++ { ++ // LEAP frames ++ *Machine = LEAP_STATE_MACHINE; ++ EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); ++ return (LeapMsgTypeSubst(EAPType, MsgType)); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ *Machine = WPA_PSK_STATE_MACHINE; ++ EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); ++ return(WpaMsgTypeSubst(EAPType, MsgType)); ++ } ++ } ++ ++ switch (pFrame->Hdr.FC.SubType) ++ { ++ case SUBTYPE_ASSOC_REQ: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ASSOC_REQ; ++ break; ++ case SUBTYPE_ASSOC_RSP: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ASSOC_RSP; ++ break; ++ case SUBTYPE_REASSOC_REQ: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_REASSOC_REQ; ++ break; ++ case SUBTYPE_REASSOC_RSP: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_REASSOC_RSP; ++ break; ++ case SUBTYPE_PROBE_REQ: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_PROBE_REQ; ++ break; ++ case SUBTYPE_PROBE_RSP: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_PROBE_RSP; ++ break; ++ case SUBTYPE_BEACON: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_BEACON; ++ break; ++ case SUBTYPE_ATIM: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ATIM; ++ break; ++ case SUBTYPE_DISASSOC: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_DISASSOC_REQ; ++ break; ++ case SUBTYPE_AUTH: ++ // get the sequence number from payload 24 Mac Header + 2 bytes algorithm ++ NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); ++ if (Seq == 1 || Seq == 3) ++ { ++ *Machine = AUTH_RSP_STATE_MACHINE; ++ *MsgType = MT2_PEER_AUTH_ODD; ++ } ++ else if (Seq == 2 || Seq == 4) ++ { ++ *Machine = AUTH_STATE_MACHINE; ++ *MsgType = MT2_PEER_AUTH_EVEN; ++ } ++ else ++ { ++ return FALSE; ++ } ++ break; ++ case SUBTYPE_DEAUTH: ++ *Machine = AUTH_RSP_STATE_MACHINE; ++ *MsgType = MT2_PEER_DEAUTH; ++ break; ++ case SUBTYPE_ACTION: ++ *Machine = ACTION_STATE_MACHINE; ++ // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support ++ if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) ++ { ++ *MsgType = MT2_ACT_INVALID; ++ } ++ else ++ { ++ *MsgType = (pFrame->Octet[0]&0x7F); ++ } ++ break; ++ default: ++ return FALSE; ++ break; ++ } ++ ++ return TRUE; ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++// =========================================================================================== ++// state_machine.c ++// =========================================================================================== ++ ++/*! \brief Initialize the state machine. ++ * \param *S pointer to the state machine ++ * \param Trans State machine transition function ++ * \param StNr number of states ++ * \param MsgNr number of messages ++ * \param DefFunc default function, when there is invalid state/message combination ++ * \param InitState initial state of the state machine ++ * \param Base StateMachine base, internal use only ++ * \pre p_sm should be a legal pointer ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID StateMachineInit( ++ IN STATE_MACHINE *S, ++ IN STATE_MACHINE_FUNC Trans[], ++ IN ULONG StNr, ++ IN ULONG MsgNr, ++ IN STATE_MACHINE_FUNC DefFunc, ++ IN ULONG InitState, ++ IN ULONG Base) ++{ ++ ULONG i, j; ++ ++ // set number of states and messages ++ S->NrState = StNr; ++ S->NrMsg = MsgNr; ++ S->Base = Base; ++ ++ S->TransFunc = Trans; ++ ++ // init all state transition to default function ++ for (i = 0; i < StNr; i++) ++ { ++ for (j = 0; j < MsgNr; j++) ++ { ++ S->TransFunc[i * MsgNr + j] = DefFunc; ++ } ++ } ++ ++ // set the starting state ++ S->CurrState = InitState; ++} ++ ++/*! \brief This function fills in the function pointer into the cell in the state machine ++ * \param *S pointer to the state machine ++ * \param St state ++ * \param Msg incoming message ++ * \param f the function to be executed when (state, message) combination occurs at the state machine ++ * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID StateMachineSetAction( ++ IN STATE_MACHINE *S, ++ IN ULONG St, ++ IN ULONG Msg, ++ IN STATE_MACHINE_FUNC Func) ++{ ++ ULONG MsgIdx; ++ ++ MsgIdx = Msg - S->Base; ++ ++ if (St < S->NrState && MsgIdx < S->NrMsg) ++ { ++ // boundary checking before setting the action ++ S->TransFunc[St * S->NrMsg + MsgIdx] = Func; ++ } ++} ++ ++/*! \brief This function does the state transition ++ * \param *Adapter the NIC adapter pointer ++ * \param *S the state machine ++ * \param *Elem the message to be executed ++ * \return None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID StateMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ The drop function, when machine executes this, the message is simply ++ ignored. This function does nothing, the message is freed in ++ StateMachinePerformAction() ++ ========================================================================== ++ */ ++VOID Drop( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++// =========================================================================================== ++// lfsr.c ++// =========================================================================================== ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID LfsrInit( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Seed) ++{ ++ if (Seed == 0) ++ pAd->Mlme.ShiftReg = 1; ++ else ++ pAd->Mlme.ShiftReg = Seed; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++UCHAR RandomByte( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ UCHAR R, Result; ++ ++ R = 0; ++ ++ if (pAd->Mlme.ShiftReg == 0) ++ NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg); ++ ++ for (i = 0; i < 8; i++) ++ { ++ if (pAd->Mlme.ShiftReg & 0x00000001) ++ { ++ pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; ++ Result = 1; ++ } ++ else ++ { ++ pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; ++ Result = 0; ++ } ++ R = (R << 1) | Result; ++ } ++ ++ return R; ++} ++ ++VOID AsicUpdateAutoFallBackTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRateTable) ++{ ++ UCHAR i; ++ HT_FBK_CFG0_STRUC HtCfg0; ++ HT_FBK_CFG1_STRUC HtCfg1; ++ LG_FBK_CFG0_STRUC LgCfg0; ++ LG_FBK_CFG1_STRUC LgCfg1; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate; ++ ++ // set to initial value ++ HtCfg0.word = 0x65432100; ++ HtCfg1.word = 0xedcba988; ++ LgCfg0.word = 0xedcba988; ++ LgCfg1.word = 0x00002100; ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1; ++ for (i = 1; i < *((PUCHAR) pRateTable); i++) ++ { ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1+i; ++ switch (pCurrTxRate->Mode) ++ { ++ case 0: //CCK ++ break; ++ case 1: //OFDM ++ { ++ switch(pCurrTxRate->CurrMCS) ++ { ++ case 0: ++ LgCfg0.field.OFDMMCS0FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 1: ++ LgCfg0.field.OFDMMCS1FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 2: ++ LgCfg0.field.OFDMMCS2FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 3: ++ LgCfg0.field.OFDMMCS3FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 4: ++ LgCfg0.field.OFDMMCS4FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 5: ++ LgCfg0.field.OFDMMCS5FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 6: ++ LgCfg0.field.OFDMMCS6FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 7: ++ LgCfg0.field.OFDMMCS7FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ } ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case 2: //HT-MIX ++ case 3: //HT-GF ++ { ++ if ((pNextTxRate->Mode >= MODE_HTMIX) && (pCurrTxRate->CurrMCS != pNextTxRate->CurrMCS)) ++ { ++ switch(pCurrTxRate->CurrMCS) ++ { ++ case 0: ++ HtCfg0.field.HTMCS0FBK = pNextTxRate->CurrMCS; ++ break; ++ case 1: ++ HtCfg0.field.HTMCS1FBK = pNextTxRate->CurrMCS; ++ break; ++ case 2: ++ HtCfg0.field.HTMCS2FBK = pNextTxRate->CurrMCS; ++ break; ++ case 3: ++ HtCfg0.field.HTMCS3FBK = pNextTxRate->CurrMCS; ++ break; ++ case 4: ++ HtCfg0.field.HTMCS4FBK = pNextTxRate->CurrMCS; ++ break; ++ case 5: ++ HtCfg0.field.HTMCS5FBK = pNextTxRate->CurrMCS; ++ break; ++ case 6: ++ HtCfg0.field.HTMCS6FBK = pNextTxRate->CurrMCS; ++ break; ++ case 7: ++ HtCfg0.field.HTMCS7FBK = pNextTxRate->CurrMCS; ++ break; ++ case 8: ++ HtCfg1.field.HTMCS8FBK = pNextTxRate->CurrMCS; ++ break; ++ case 9: ++ HtCfg1.field.HTMCS9FBK = pNextTxRate->CurrMCS; ++ break; ++ case 10: ++ HtCfg1.field.HTMCS10FBK = pNextTxRate->CurrMCS; ++ break; ++ case 11: ++ HtCfg1.field.HTMCS11FBK = pNextTxRate->CurrMCS; ++ break; ++ case 12: ++ HtCfg1.field.HTMCS12FBK = pNextTxRate->CurrMCS; ++ break; ++ case 13: ++ HtCfg1.field.HTMCS13FBK = pNextTxRate->CurrMCS; ++ break; ++ case 14: ++ HtCfg1.field.HTMCS14FBK = pNextTxRate->CurrMCS; ++ break; ++ case 15: ++ HtCfg1.field.HTMCS15FBK = pNextTxRate->CurrMCS; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicUpdateAutoFallBackTable: not support CurrMCS=%d\n", pCurrTxRate->CurrMCS)); ++ } ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ pNextTxRate = pCurrTxRate; ++ } ++ ++ RTMP_IO_WRITE32(pAd, HT_FBK_CFG0, HtCfg0.word); ++ RTMP_IO_WRITE32(pAd, HT_FBK_CFG1, HtCfg1.word); ++ RTMP_IO_WRITE32(pAd, LG_FBK_CFG0, LgCfg0.word); ++ RTMP_IO_WRITE32(pAd, LG_FBK_CFG1, LgCfg1.word); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set MAC register value according operation mode. ++ OperationMode AND bNonGFExist are for MM and GF Proteciton. ++ If MM or GF mask is not set, those passing argument doesn't not take effect. ++ ++ Operation mode meaning: ++ = 0 : Pure HT, no preotection. ++ = 0x01; there may be non-HT devices in both the control and extension channel, protection is optional in BSS. ++ = 0x10: No Transmission in 40M is protected. ++ = 0x11: Transmission in both 40M and 20M shall be protected ++ if (bNonGFExist) ++ we should choose not to use GF. But still set correct ASIC registers. ++ ======================================================================== ++*/ ++VOID AsicUpdateProtect( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT OperationMode, ++ IN UCHAR SetMask, ++ IN BOOLEAN bDisableBGProtect, ++ IN BOOLEAN bNonGFExist) ++{ ++ PROT_CFG_STRUC ProtCfg, ProtCfg4; ++ UINT32 Protect[6]; ++ USHORT offset; ++ UCHAR i; ++ UINT32 MacReg = 0; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++ if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8)) ++ { ++ return; ++ } ++ ++ if (pAd->BATable.numAsOriginator) ++ { ++ // ++ // enable the RTS/CTS to avoid channel collision ++ // ++ SetMask = ALLN_SETPROTECT; ++ OperationMode = 8; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Config ASIC RTS threshold register ++ RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); ++ MacReg &= 0xFF0000FF; ++#if 0 ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++#else ++ // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 ++ if (( ++#ifdef DOT11_N_SUPPORT ++ (pAd->CommonCfg.BACapability.field.AmsduEnable) || ++#endif // DOT11_N_SUPPORT // ++ (pAd->CommonCfg.bAggregationCapable == TRUE)) ++ && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD) ++ { ++ MacReg |= (0x1000 << 8); ++ } ++ else ++ { ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++ } ++#endif ++ ++ RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); ++ ++ // Initial common protection settings ++ RTMPZeroMemory(Protect, sizeof(Protect)); ++ ProtCfg4.word = 0; ++ ProtCfg.word = 0; ++ ProtCfg.field.TxopAllowGF40 = 1; ++ ProtCfg.field.TxopAllowGF20 = 1; ++ ProtCfg.field.TxopAllowMM40 = 1; ++ ProtCfg.field.TxopAllowMM20 = 1; ++ ProtCfg.field.TxopAllowOfdm = 1; ++ ProtCfg.field.TxopAllowCck = 1; ++ ProtCfg.field.RTSThEn = 1; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ++ // update PHY mode and rate ++ if (pAd->CommonCfg.Channel > 14) ++ ProtCfg.field.ProtectRate = 0x4000; ++ ProtCfg.field.ProtectRate |= pAd->CommonCfg.RtsRate; ++ ++ // Handle legacy(B/G) protection ++ if (bDisableBGProtect) ++ { ++ //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; ++ Protect[0] = ProtCfg.word; ++ Protect[1] = ProtCfg.word; ++ } ++ else ++ { ++ //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; // CCK do not need to be protected ++ Protect[0] = ProtCfg.word; ++ ProtCfg.field.ProtectCtrl = ASIC_CTS; // OFDM needs using CCK to protect ++ Protect[1] = ProtCfg.word; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // Decide HT frame protection. ++ if ((SetMask & ALLN_SETPROTECT) != 0) ++ { ++ switch(OperationMode) ++ { ++ case 0x0: ++ // NO PROTECT ++ // 1.All STAs in the BSS are 20/40 MHz HT ++ // 2. in ai 20/40MHz BSS ++ // 3. all STAs are 20MHz in a 20MHz BSS ++ // Pure HT. no protection. ++ ++ // MM20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[2] = 0x01744004; ++ ++ // MM40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[3] = 0x03f44084; ++ ++ // CF20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[4] = 0x01744004; ++ ++ // CF40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[5] = 0x03f44084; ++ ++ if (bNonGFExist) ++ { ++ // PROT_NAV(19:18) -- 01 (Short NAV protectiion) ++ // PROT_CTRL(17:16) -- 01 (RTS/CTS) ++ Protect[4] = 0x01754004; ++ Protect[5] = 0x03f54084; ++ } ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ break; ++ ++ case 1: ++ // This is "HT non-member protection mode." ++ // If there may be non-HT STAs my BSS ++ ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) ++ ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. ++ ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083; ++ } ++ //Assign Protection method for 20&40 MHz packets ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ ++ case 2: ++ // If only HT STAs are in BSS. at least one is 20MHz. Only protect 40MHz packets ++ ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) ++ ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. ++ ++ //Assign Protection method for 40MHz packets ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ if (bNonGFExist) ++ { ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ } ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ break; ++ ++ case 3: ++ // HT mixed mode. PROTECT ALL! ++ // Assign Rate ++ ProtCfg.word = 0x01744004; //duplicaet legacy 24M. BW set 1. ++ ProtCfg4.word = 0x03f44084; ++ // both 20MHz and 40MHz are protected. Whether use RTS or CTS-to-self depends on the ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. ++ ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083 ++ } ++ //Assign Protection method for 20&40 MHz packets ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ ++ case 8: ++ // Special on for Atheros problem n chip. ++ Protect[2] = 0x01754004; ++ Protect[3] = 0x03f54084; ++ Protect[4] = 0x01754004; ++ Protect[5] = 0x03f54084; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ offset = CCK_PROT_CFG; ++ for (i = 0;i < 6;i++) ++ { ++ if ((SetMask & (1<< i))) ++ { ++ RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN BOOLEAN bScan) ++{ ++ ULONG R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0; ++ CHAR TxPwer = 0, TxPwer2 = DEFAULT_RF_TX_POWER; //Bbp94 = BBPR94_DEFAULT, TxPwer2 = DEFAULT_RF_TX_POWER; ++ UCHAR index; ++ UINT32 Value = 0; //BbpReg, Value; ++ RTMP_RF_REGS *RFRegTable; ++ ++ // Search Tx power value ++ for (index = 0; index < pAd->ChannelListNum; index++) ++ { ++ if (Channel == pAd->ChannelList[index].Channel) ++ { ++ TxPwer = pAd->ChannelList[index].Power; ++ TxPwer2 = pAd->ChannelList[index].Power2; ++ break; ++ } ++ } ++ ++ if (index == MAX_NUM_OF_CHANNELS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Cant find the Channel#%d \n", Channel)); ++ } ++ ++ { ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ R2 |= 0x40; // write 1 to off Rxpath. ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ ++ if (Channel > 14) ++ { ++ // initialize R3, R4 ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff); ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15); ++ ++ // 5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB ++ // R3 ++ if ((TxPwer >= -7) && (TxPwer < 0)) ++ { ++ TxPwer = (7+TxPwer); ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10); ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer=%d \n", TxPwer)); ++ } ++ else ++ { ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10) | (1 << 9); ++ } ++ ++ // R4 ++ if ((TxPwer2 >= -7) && (TxPwer2 < 0)) ++ { ++ TxPwer2 = (7+TxPwer2); ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7); ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); ++ } ++ else ++ { ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7) | (1 << 6); ++ } ++ } ++ else ++ { ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15) | (TxPwer2 <<6);// Set freq Offset & TxPwr1 ++ } ++ ++ // Based on BBP current mode before changing RF channel. ++ if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) ++ { ++ R4 |=0x200000; ++ } ++ ++ // Update variables ++ pAd->LatchRfRegs.Channel = Channel; ++ pAd->LatchRfRegs.R1 = RFRegTable[index].R1; ++ pAd->LatchRfRegs.R2 = R2; ++ pAd->LatchRfRegs.R3 = R3; ++ pAd->LatchRfRegs.R4 = R4; ++ ++ // Set RF value 1's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 2's set R3[bit2] = [1] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 3's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ // Change BBP setting during siwtch from a->g, g->a ++ if (Channel <= 14) ++ { ++ ULONG TxPinCfg = 0x00050F0A;//Gary 2007/08/09 0x050A0A ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ ++ // Rx High power VGA offset for LNA select ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); ++ } ++ ++ // 5G band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x04); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ else ++ { ++ ULONG TxPinCfg = 0x00050F05;//Gary 2007/8/9 0x050505 ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); ++ ++ // Rx High power VGA offset for LNA select ++ if (pAd->NicConfig2.field.ExternalLNAForA) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); ++ } ++ ++ // 5G band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x02); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ ++ // R66 should be set according to Channel and use 20MHz when scanning ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x2E + GET_LNA_GAIN(pAd))); ++ if (bScan) ++ RTMPSetAGCInitValue(pAd, BW_20); ++ else ++ RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); ++ ++ // ++ // On 11A, We should delay and wait RF/BBP to be stable ++ // and the appropriate time should be 1000 micro seconds ++ // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. ++ // ++ RTMPusecDelay(1000); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%lu, Pwr1=%lu, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ (R3 & 0x00003e00) >> 9, ++ (R4 & 0x000007c0) >> 6, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This function is required for 2421 only, and should not be used during ++ site survey. It's only required after NIC decided to stay at a channel ++ for a longer period. ++ When this function is called, it's always after AsicSwitchChannel(). ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicLockChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicAntennaSelect( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Antenna miscellaneous setting. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ BandState Indicate current Band State. ++ ++ Return Value: ++ None ++ ++ IRQL <= DISPATCH_LEVEL ++ ++ Note: ++ 1.) Frame End type control ++ only valid for G only (RF_2527 & RF_2529) ++ 0: means DPDT, set BBP R4 bit 5 to 1 ++ 1: means SPDT, set BBP R4 bit 5 to 0 ++ ++ ++ ======================================================================== ++*/ ++VOID AsicAntennaSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN ABGBAND_STATE BandState) ++{ ++} ++ ++VOID AsicRfTuningExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Gives CCK TX rate 2 more dB TX power. ++ This routine works only in LINK UP in INFRASTRUCTURE mode. ++ ++ calculate desired Tx power in RF R3.Tx0~5, should consider - ++ 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) ++ 1. TxPowerPercentage ++ 2. auto calibration based on TSSI feedback ++ 3. extra 2 db for CCK ++ 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP ++ ++ NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), ++ it should be called AFTER MlmeDynamicTxRatSwitching() ++ ========================================================================== ++ */ ++VOID AsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i, j; ++ CHAR DeltaPwr = 0; ++ BOOLEAN bAutoTxAgc = FALSE; ++ UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; ++ UCHAR BbpR1 = 0, BbpR49 = 0, idx; ++ PCHAR pTxAgcCompensate; ++ ULONG TxPwr[5]; ++ CHAR Value; ++ ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ if (pAd->CommonCfg.CentralChannel > 14) ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; ++ } ++ } ++ ++ // TX power compensation for temperature variation based on TSSI. try every 4 second ++ if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) ++ { ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ /* bg channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ TssiRef = pAd->TssiRefG; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; ++ TxAgcStep = pAd->TxAgcStepG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ /* a channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ TssiRef = pAd->TssiRefA; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; ++ TxAgcStep = pAd->TxAgcStepA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ { ++ /* BbpR1 is unsigned char */ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); ++ ++ /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ ++ /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ ++ /* step value is defined in pAd->TxAgcStepG for tx power value */ ++ ++ /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ ++ /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ above value are examined in mass factory production */ ++ /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ ++ ++ /* plus (+) is 0x00 ~ 0x45, minus (-) is 0xa0 ~ 0xf0 */ ++ /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ ++ /* if value is 0xa5, tx power will be -= TxAgcStep*(2-1) */ ++ ++ if (BbpR49 > pTssiMinusBoundary[1]) ++ { ++ // Reading is larger than the reference value ++ // check for how large we need to decrease the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should decrease, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = -(TxAgcStep * (idx-1)); ++ ++ DeltaPwr += (*pTxAgcCompensate); ++ DBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else if (BbpR49 < pTssiPlusBoundary[1]) ++ { ++ // Reading is smaller than the reference value ++ // check for how large we need to increase the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should increase, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = TxAgcStep * (idx-1); ++ DeltaPwr += (*pTxAgcCompensate); ++ DBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else ++ { ++ *pTxAgcCompensate = 0; ++ DBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R49=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, 0)); ++ } ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ DeltaPwr += (*pTxAgcCompensate); ++ } ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1); ++ BbpR1 &= 0xFC; ++ ++#ifdef SINGLE_SKU ++ // Handle regulatory max tx power constrain ++ do ++ { ++ UCHAR TxPwrInEEPROM = 0xFF, CountryTxPwr = 0xFF, criterion; ++ UCHAR AdjustMaxTxPwr[40]; ++ ++ if (pAd->CommonCfg.Channel > 14) // 5G band ++ TxPwrInEEPROM = ((pAd->CommonCfg.DefineMaxTxPwr & 0xFF00) >> 8); ++ else // 2.4G band ++ TxPwrInEEPROM = (pAd->CommonCfg.DefineMaxTxPwr & 0x00FF); ++ CountryTxPwr = GetCuntryMaxTxPwr(pAd, pAd->CommonCfg.Channel); ++ ++ // error handling, range check ++ if ((TxPwrInEEPROM > 0x50) || (CountryTxPwr > 0x50)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("AsicAdjustTxPower - Invalid max tx power (=0x%02x), CountryTxPwr=%d\n", TxPwrInEEPROM, CountryTxPwr)); ++ break; ++ } ++ ++ criterion = *((PUCHAR)TxPwr + 2) & 0xF; // FAE use OFDM 6M as criterion ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (criterion=%d, TxPwrInEEPROM=%d, CountryTxPwr=%d)\n", criterion, TxPwrInEEPROM, CountryTxPwr)); ++ ++ // Adjust max tx power according to the relationship of tx power in E2PROM ++ for (i=0; i<5; i++) ++ { ++ // CCK will have 4dBm larger than OFDM ++ // Therefore, we should separate to parse the tx power field ++ if (i == 0) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ if (j < 4) ++ { ++ // CCK will have 4dBm larger than OFDM ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion) + 4; ++ } ++ else ++ { ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ } ++ else ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ } ++ } ++ ++ // Adjust tx power according to the relationship ++ for (i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ // The system tx power is larger than the regulatory, the power should be restrain ++ if (AdjustMaxTxPwr[i*8+j] > CountryTxPwr) ++ { ++ // decrease to zero and don't need to take care BBPR1 ++ if ((Value - (AdjustMaxTxPwr[i*8+j] - CountryTxPwr)) > 0) ++ Value -= (AdjustMaxTxPwr[i*8+j] - CountryTxPwr); ++ else ++ Value = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ else ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d, no change)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ } ++ } ++ } while (FALSE); ++#endif // SINGLE_SKU // ++ ++ /* calculate delta power based on the percentage specified from UI */ ++ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) ++ // We lower TX power here according to the percentage specified from UI ++ if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW // DeltaPwr -= 1; ++ { ++ DeltaPwr -= 1; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW // DeltaPwr -= 3; ++ { ++ DeltaPwr -= 3; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW // DeltaPwr -= 6; ++ { ++ BbpR1 |= 0x01; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW // DeltaPwr -= 9; ++ { ++ BbpR1 |= 0x01; ++ DeltaPwr -= 3; ++ } ++ else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW // DeltaPwr -= 12; ++ { ++ BbpR1 |= 0x02; ++ } ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpR1); ++ ++ /* reset different new tx power for different TX rate */ ++ for(i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ ++ ++ if ((Value + DeltaPwr) < 0) ++ { ++ Value = 0; /* min */ ++ } ++ else if ((Value + DeltaPwr) > 0xF) ++ { ++ Value = 0xF; /* max */ ++ } ++ else ++ { ++ Value += DeltaPwr; /* temperature compensation */ ++ } ++ ++ /* fill new value to CSR offset */ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ ++ /* write tx power value to CSR */ ++ /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M ++ TX power for OFDM 6M/9M ++ TX power for CCK5.5M/11M ++ TX power for CCK1M/2M */ ++ /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); ++ } ++ } ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ put PHY to sleep here, and set next wakeup timer. PHY doesn't not wakeup ++ automatically. Instead, MCU will issue a TwakeUpInterrupt to host after ++ the wakeup timer timeout. Driver has to issue a separate command to wake ++ PHY up. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ AsicForceWakeup() is used whenever manual wakeup is required ++ AsicForceSleep() should only be used when not in INFRA BSS. When ++ in INFRA BSS, we should use AsicSleepThenAutoWakeup() instead. ++ ========================================================================== ++ */ ++VOID AsicForceSleep( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ AsicForceWakeup() is used whenever Twakeup timer (set via AsicSleepThenAutoWakeup) ++ expired. ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ========================================================================== ++ */ ++VOID AsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); ++ RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); ++} ++#endif // CONFIG_STA_SUPPORT // ++/* ++ ========================================================================== ++ Description: ++ Set My BSSID ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetBssid( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid) ++{ ++ ULONG Addr4; ++ DBGPRINT(RT_DEBUG_TRACE, ("==============> AsicSetBssid %x:%x:%x:%x:%x:%x\n", ++ pBssid[0],pBssid[1],pBssid[2],pBssid[3], pBssid[4],pBssid[5])); ++ ++ Addr4 = (ULONG)(pBssid[0]) | ++ (ULONG)(pBssid[1] << 8) | ++ (ULONG)(pBssid[2] << 16) | ++ (ULONG)(pBssid[3] << 24); ++ RTMP_IO_WRITE32(pAd, MAC_BSSID_DW0, Addr4); ++ ++ Addr4 = 0; ++ // always one BSSID in STA mode ++ Addr4 = (ULONG)(pBssid[4]) | (ULONG)(pBssid[5] << 8); ++ ++ RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, Addr4); ++} ++ ++VOID AsicSetMcastWC( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[MCAST_WCID]; ++ USHORT offset; ++ ++ pEntry->Sst = SST_ASSOC; ++ pEntry->Aid = MCAST_WCID; // Softap supports 1 BSSID and use WCID=0 as multicast Wcid index ++ pEntry->PsMode = PWR_ACTIVE; ++ pEntry->CurrTxRate = pAd->CommonCfg.MlmeRate; ++ offset = MAC_WCID_BASE + BSS0Mcast_WCID * HW_WCID_ENTRY_SIZE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDelWcidTab( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid) ++{ ++ ULONG Addr0 = 0x0, Addr1 = 0x0; ++ ULONG offset; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicDelWcidTab==>Wcid = 0x%x\n",Wcid)); ++ offset = MAC_WCID_BASE + Wcid * HW_WCID_ENTRY_SIZE; ++ RTMP_IO_WRITE32(pAd, offset, Addr0); ++ offset += 4; ++ RTMP_IO_WRITE32(pAd, offset, Addr1); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableRDG( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ UINT32 Data = 0; ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ TxLinkCfg.field.TxRDGEn = 1; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++ ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ Data |= 0x80; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDisableRDG( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ UINT32 Data = 0; ++ ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ TxLinkCfg.field.TxRDGEn = 0; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++ ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ ++ Data &= 0xFFFFFF00; ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE) ++#ifdef DOT11_N_SUPPORT ++ && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode ++ if (pAd->CommonCfg.bEnableTxBurst) ++ Data |= 0x20; ++ } ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDisableSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->Disable TSF synchronization\n")); ++ ++ // 2003-12-20 disable TSF and TBTT while NIC in power-saving have side effect ++ // that NIC will never wakes up because TSF stops and no more ++ // TBTT interrupts ++ pAd->TbttTickCount = 0; ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ csr.field.bTsfTicking = 0; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableBssSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n")); ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU ++ csr.field.bTsfTicking = 1; ++ csr.field.TsfSyncMode = 1; // sync TSF in INFRASTRUCTURE mode ++ csr.field.bBeaconGen = 0; // do NOT generate BEACON ++ csr.field.bTBTTEnable = 1; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Note: ++ BEACON frame in shared memory should be built ok before this routine ++ can be called. Otherwise, a garbage frame maybe transmitted out every ++ Beacon period. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableIbssSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr9; ++ PUCHAR ptr; ++ UINT i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableIbssSync(ADHOC mode. MPDUtotalByteCount = %d)\n", pAd->BeaconTxWI.MPDUtotalByteCount)); ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr9.word); ++ csr9.field.bBeaconGen = 0; ++ csr9.field.bTBTTEnable = 0; ++ csr9.field.bTsfTicking = 0; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); ++ ++#ifdef RT2860 ++ // move BEACON TXD and frame content to on-chip memory ++ ptr = (PUCHAR)&pAd->BeaconTxWI; ++ for (i=0; iBeaconBuf; ++ for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=4) ++ { ++ UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24); ++ RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, longptr); ++ ptr +=4; ++ } ++#endif // RT2860 // ++ ++ // start sending BEACON ++ csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU ++ csr9.field.bTsfTicking = 1; ++ csr9.field.TsfSyncMode = 2; // sync TSF in IBSS mode ++ csr9.field.bTBTTEnable = 1; ++ csr9.field.bBeaconGen = 1; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetEdcaParm( ++ IN PRTMP_ADAPTER pAd, ++ IN PEDCA_PARM pEdcaParm) ++{ ++ EDCA_AC_CFG_STRUC Ac0Cfg, Ac1Cfg, Ac2Cfg, Ac3Cfg; ++ AC_TXOP_CSR0_STRUC csr0; ++ AC_TXOP_CSR1_STRUC csr1; ++ AIFSN_CSR_STRUC AifsnCsr; ++ CWMIN_CSR_STRUC CwminCsr; ++ CWMAX_CSR_STRUC CwmaxCsr; ++ int i; ++ ++ Ac0Cfg.word = 0; ++ Ac1Cfg.word = 0; ++ Ac2Cfg.word = 0; ++ Ac3Cfg.word = 0; ++ if ((pEdcaParm == NULL) || (pEdcaParm->bValid == FALSE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AsicSetEdcaParm\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WMM_INUSED); ++ for (i=0; iMacTab.Content[i].ValidAsCLI || pAd->MacTab.Content[i].ValidAsApCli) ++ CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[i], fCLIENT_STATUS_WMM_CAPABLE); ++ } ++ ++ //======================================================== ++ // MAC Register has a copy . ++ //======================================================== ++ if( pAd->CommonCfg.bEnableTxBurst ) ++ { ++ // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode ++ Ac0Cfg.field.AcTxop = 0x20; // Suggest by John for TxBurst in HT Mode ++ } ++ else ++ Ac0Cfg.field.AcTxop = 0; // QID_AC_BE ++ Ac0Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac0Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac0Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); ++ ++ Ac1Cfg.field.AcTxop = 0; // QID_AC_BK ++ Ac1Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac1Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac1Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); ++ ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ Ac2Cfg.field.AcTxop = 192; // AC_VI: 192*32us ~= 6ms ++ Ac3Cfg.field.AcTxop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ Ac2Cfg.field.AcTxop = 96; // AC_VI: 96*32us ~= 3ms ++ Ac3Cfg.field.AcTxop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ Ac2Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac2Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac2Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); ++ Ac3Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac3Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac3Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); ++ ++ //======================================================== ++ // DMA Register has a copy too. ++ //======================================================== ++ csr0.field.Ac0Txop = 0; // QID_AC_BE ++ csr0.field.Ac1Txop = 0; // QID_AC_BK ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ csr1.field.Ac2Txop = 192; // AC_VI: 192*32us ~= 6ms ++ csr1.field.Ac3Txop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ csr1.field.Ac2Txop = 96; // AC_VI: 96*32us ~= 3ms ++ csr1.field.Ac3Txop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); ++ ++ CwminCsr.word = 0; ++ CwminCsr.field.Cwmin0 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin1 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin2 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin3 = CW_MIN_IN_BITS; ++ RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); ++ ++ CwmaxCsr.word = 0; ++ CwmaxCsr.field.Cwmax0 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax1 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax2 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax3 = CW_MAX_IN_BITS; ++ RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); ++ ++ RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, 0x00002222); ++ ++ NdisZeroMemory(&pAd->CommonCfg.APEdcaParm, sizeof(EDCA_PARM)); ++ } ++ else ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WMM_INUSED); ++ //======================================================== ++ // MAC Register has a copy. ++ //======================================================== ++ // ++ // Modify Cwmin/Cwmax/Txop on queue[QID_AC_VI], Recommend by Jerry 2005/07/27 ++ // To degrade our VIDO Queue's throughput for WiFi WMM S3T07 Issue. ++ // ++ //pEdcaParm->Txop[QID_AC_VI] = pEdcaParm->Txop[QID_AC_VI] * 7 / 10; // rt2860c need this ++ ++ Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE]; ++ Ac0Cfg.field.Cwmin= pEdcaParm->Cwmin[QID_AC_BE]; ++ Ac0Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BE]; ++ Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]; //+1; ++ ++ Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; ++ Ac1Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_BK]; //+2; ++ Ac1Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BK]; ++ Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; //+1; ++ ++ Ac2Cfg.field.AcTxop = (pEdcaParm->Txop[QID_AC_VI] * 6) / 10; ++ Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI]; ++ Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI]; ++ Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Tuning for Wi-Fi WMM S06 ++ if (pAd->CommonCfg.bWiFiTest && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ Ac2Cfg.field.Aifsn -= 1; ++ ++ // Tuning for TGn Wi-Fi 5.2.32 ++ // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta ++ if (STA_TGN_WIFI_ON(pAd) && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ { ++ Ac0Cfg.field.Aifsn = 3; ++ Ac2Cfg.field.AcTxop = 5; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO]; ++ Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO]; ++ Ac3Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VO]; ++ Ac3Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VO]; ++ ++//#ifdef WIFI_TEST ++ if (pAd->CommonCfg.bWiFiTest) ++ { ++ if (Ac3Cfg.field.AcTxop == 102) ++ { ++ Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE] ? pEdcaParm->Txop[QID_AC_BE] : 10; ++ Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]-1; /* AIFSN must >= 1 */ ++ Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; ++ Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; ++ Ac2Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VI]; ++ } /* End of if */ ++ } ++//#endif // WIFI_TEST // ++ ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); ++ ++ ++ //======================================================== ++ // DMA Register has a copy too. ++ //======================================================== ++ csr0.field.Ac0Txop = Ac0Cfg.field.AcTxop; ++ csr0.field.Ac1Txop = Ac1Cfg.field.AcTxop; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ ++ csr1.field.Ac2Txop = Ac2Cfg.field.AcTxop; ++ csr1.field.Ac3Txop = Ac3Cfg.field.AcTxop; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); ++ ++ CwminCsr.word = 0; ++ CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE]; ++ CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK]; ++ CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); ++ ++ CwmaxCsr.word = 0; ++ CwmaxCsr.field.Cwmax0 = pEdcaParm->Cwmax[QID_AC_BE]; ++ CwmaxCsr.field.Cwmax1 = pEdcaParm->Cwmax[QID_AC_BK]; ++ CwmaxCsr.field.Cwmax2 = pEdcaParm->Cwmax[QID_AC_VI]; ++ CwmaxCsr.field.Cwmax3 = pEdcaParm->Cwmax[QID_AC_VO]; ++ RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); ++ ++ AifsnCsr.word = 0; ++ AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE]; ++ AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK]; ++ AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Tuning for Wi-Fi WMM S06 ++ if (pAd->CommonCfg.bWiFiTest && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4; ++ ++ // Tuning for TGn Wi-Fi 5.2.32 ++ // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta ++ if (STA_TGN_WIFI_ON(pAd) && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ { ++ AifsnCsr.field.Aifsn0 = 3; ++ AifsnCsr.field.Aifsn2 = 7; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word); ++ ++ NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ if (!ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("EDCA [#%d]: AIFSN CWmin CWmax TXOP(us) ACM\n", pEdcaParm->EdcaUpdateCount)); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_BE %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[0], ++ pEdcaParm->Cwmin[0], ++ pEdcaParm->Cwmax[0], ++ pEdcaParm->Txop[0]<<5, ++ pEdcaParm->bACM[0])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_BK %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[1], ++ pEdcaParm->Cwmin[1], ++ pEdcaParm->Cwmax[1], ++ pEdcaParm->Txop[1]<<5, ++ pEdcaParm->bACM[1])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_VI %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[2], ++ pEdcaParm->Cwmin[2], ++ pEdcaParm->Cwmax[2], ++ pEdcaParm->Txop[2]<<5, ++ pEdcaParm->bACM[2])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_VO %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[3], ++ pEdcaParm->Cwmin[3], ++ pEdcaParm->Cwmax[3], ++ pEdcaParm->Txop[3]<<5, ++ pEdcaParm->bACM[3])); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetSlotTime( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUseShortSlotTime) ++{ ++ ULONG SlotTime; ++ UINT32 RegValue = 0; ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->CommonCfg.Channel > 14) ++ bUseShortSlotTime = TRUE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (bUseShortSlotTime) ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); ++ else ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); ++ ++ SlotTime = (bUseShortSlotTime)? 9 : 20; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // force using short SLOT time for FAE to demo performance when TxBurst is ON ++ if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) ++#ifdef DOT11_N_SUPPORT ++ || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ // In this case, we will think it is doing Wi-Fi test ++ // And we will not set to short slot when bEnableTxBurst is TRUE. ++ } ++ else if (pAd->CommonCfg.bEnableTxBurst) ++ SlotTime = 9; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // For some reasons, always set it to short slot time. ++ // ++ // ToDo: Should consider capability with 11B ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.BssType == BSS_ADHOC) ++ SlotTime = 20; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue); ++ RegValue = RegValue & 0xFFFFFF00; ++ ++ RegValue |= SlotTime; ++ ++ RTMP_IO_WRITE32(pAd, BKOFF_SLOT_CFG, RegValue); ++} ++ ++/* ++ ======================================================================== ++ Description: ++ Add Shared key information into ASIC. ++ Update shared key, TxMic and RxMic to Asic Shared key table ++ Update its cipherAlg to Asic Shared key Mode. ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicAddSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic) ++{ ++ ULONG offset; //, csr0; ++ SHAREDKEY_MODE_STRUC csr1; ++#ifdef RT2860 ++ INT i; ++#endif // RT2860 // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); ++//============================================================================================ ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicAddSharedKeyEntry: %s key #%d\n", CipherName[CipherAlg], BssIndex*4 + KeyIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); ++ if (pRxMic) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ if (pTxMic) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ } ++//============================================================================================ ++ // ++ // fill key material - key + TX MIC + RX MIC ++ // ++#ifdef RT2860 ++ offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; ++ for (i=0; iKey; ++ PUCHAR pTxMic = pCipherKey->TxMic; ++ PUCHAR pRxMic = pCipherKey->RxMic; ++ PUCHAR pTxtsc = pCipherKey->TxTsc; ++ UCHAR CipherAlg = pCipherKey->CipherAlg; ++ SHAREDKEY_MODE_STRUC csr1; ++#ifdef RT2860 ++ UCHAR i; ++#endif // RT2860 // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); ++ // ++ // 1.) decide key table offset ++ // ++ if (bUsePairewiseKeyTable) ++ offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); ++ else ++ offset = SHARED_KEY_TABLE_BASE + (4 * BssIndex + KeyIdx) * HW_KEY_ENTRY_SIZE; ++ ++ // ++ // 2.) Set Key to Asic ++ // ++ //for (i = 0; i < KeyLen; i++) ++#ifdef RT2860 ++ for (i = 0; i < MAX_LEN_OF_PEER_KEY; i++) ++ { ++ RTMP_IO_WRITE8(pAd, offset + i, pKey[i]); ++ } ++ offset += MAX_LEN_OF_PEER_KEY; ++ ++ // ++ // 3.) Set MIC key if available ++ // ++ if (pTxMic) ++ { ++ for (i = 0; i < 8; i++) ++ { ++ RTMP_IO_WRITE8(pAd, offset + i, pTxMic[i]); ++ } ++ } ++ offset += LEN_TKIP_TXMICK; ++ ++ if (pRxMic) ++ { ++ for (i = 0; i < 8; i++) ++ { ++ RTMP_IO_WRITE8(pAd, offset + i, pRxMic[i]); ++ } ++ } ++#endif // RT2860 // ++ ++ ++ // ++ // 4.) Modify IV/EIV if needs ++ // This will force Asic to use this key ID by setting IV. ++ // ++ if (bTxKey) ++ { ++#ifdef RT2860 ++ offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); ++ // ++ // Write IV ++ // ++ RTMP_IO_WRITE8(pAd, offset, pTxtsc[1]); ++ RTMP_IO_WRITE8(pAd, offset + 1, ((pTxtsc[1] | 0x20) & 0x7f)); ++ RTMP_IO_WRITE8(pAd, offset + 2, pTxtsc[0]); ++ ++ IV4 = (KeyIdx << 6); ++ if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES)) ++ IV4 |= 0x20; // turn on extension bit means EIV existence ++ ++ RTMP_IO_WRITE8(pAd, offset + 3, IV4); ++ ++ // ++ // Write EIV ++ // ++ offset += 4; ++ for (i = 0; i < 4; i++) ++ { ++ RTMP_IO_WRITE8(pAd, offset + i, pTxtsc[i + 2]); ++ } ++#endif // RT2860 // ++ ++ AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); ++ } ++ ++ if (!bUsePairewiseKeyTable) ++ { ++ // ++ // Only update the shared key security mode ++ // ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), &csr1.word); ++ if ((BssIndex % 2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss0Key3CipherAlg = CipherAlg; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss1Key3CipherAlg = CipherAlg; ++ } ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), csr1.word); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== AsicAddKeyEntry\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ Description: ++ Add Pair-wise key material into ASIC. ++ Update pairwise key, TxMic and RxMic to Asic Pair-wise key table ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicAddPairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR WCID, ++ IN CIPHER_KEY *pCipherKey) ++{ ++ INT i; ++ ULONG offset; ++ PUCHAR pKey = pCipherKey->Key; ++ PUCHAR pTxMic = pCipherKey->TxMic; ++ PUCHAR pRxMic = pCipherKey->RxMic; ++#ifdef DBG ++ UCHAR CipherAlg = pCipherKey->CipherAlg; ++#endif // DBG // ++ ++ // EKEY ++ offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); ++#ifdef RT2860 ++ for (i=0; i= 100) ++ { ++#ifdef RT2860 ++#ifdef RALINK_ATE ++ if (pAd->ate.bFWLoading == TRUE) ++ { ++ /* reloading firmware when received iwpriv cmd "ATE=ATESTOP" */ ++ if (j > 0) ++ { ++ if (j % 64 != 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("#")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("\n")); ++ } ++ ++j; ++ } ++ else if (j == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Loading firmware. Please wait for a moment...\n")); ++ ++j; ++ } ++ } ++ else ++#endif // RALINK_ATE // ++#endif // RT2860 // ++ { ++ DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); ++ } ++ return FALSE; ++ } ++ ++#ifdef RT2860 ++#ifdef RALINK_ATE ++ else if (pAd->ate.bFWLoading == TRUE) ++ { ++ /* reloading of firmware is completed */ ++ pAd->ate.bFWLoading = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR, ("\n")); ++ j = 0; ++ } ++#endif // RALINK_ATE // ++#endif // RT2860 // ++ ++ H2MMailbox.field.Owner = 1; // pass ownership to MCU ++ H2MMailbox.field.CmdToken = Token; ++ H2MMailbox.field.HighByte = Arg1; ++ H2MMailbox.field.LowByte = Arg0; ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); ++ ++ H2MCmd.word = 0; ++ H2MCmd.field.HostCommand = Command; ++ RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); ++ ++ if (Command != 0x80) ++ { ++ } ++ ++ return TRUE; ++} ++ ++#ifdef RT2860 ++BOOLEAN AsicCheckCommanOk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command) ++{ ++ UINT32 CmdStatus = 0, CID = 0, i; ++ UINT32 ThisCIDMask = 0; ++ ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, H2M_MAILBOX_CID, &CID); ++ // Find where the command is. Because this is randomly specified by firmware. ++ if ((CID & CID0MASK) == Command) ++ { ++ ThisCIDMask = CID0MASK; ++ break; ++ } ++ else if ((((CID & CID1MASK)>>8) & 0xff) == Command) ++ { ++ ThisCIDMask = CID1MASK; ++ break; ++ } ++ else if ((((CID & CID2MASK)>>16) & 0xff) == Command) ++ { ++ ThisCIDMask = CID2MASK; ++ break; ++ } ++ else if ((((CID & CID3MASK)>>24) & 0xff) == Command) ++ { ++ ThisCIDMask = CID3MASK; ++ break; ++ } ++ ++ RTMPusecDelay(100); ++ i++; ++ }while (i < 200); ++ ++ // Get CommandStatus Value ++ RTMP_IO_READ32(pAd, H2M_MAILBOX_STATUS, &CmdStatus); ++ ++ // This command's status is at the same position as command. So AND command position's bitmask to read status. ++ if (i < 200) ++ { ++ // If Status is 1, the comamnd is success. ++ if (((CmdStatus & ThisCIDMask) == 0x1) || ((CmdStatus & ThisCIDMask) == 0x100) ++ || ((CmdStatus & ThisCIDMask) == 0x10000) || ((CmdStatus & ThisCIDMask) == 0x1000000)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanOk CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus)); ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff); ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff); ++ return TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail1 CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail2 Timeout Command = %d, CmdStatus= 0x%x \n", Command, CmdStatus)); ++ } ++ // Clear Command and Status. ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff); ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff); ++ ++ return FALSE; ++} ++#endif // RT2860 // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for different PHY type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPCheckRates( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT UCHAR SupRate[], ++ IN OUT UCHAR *SupRateLen) ++{ ++ UCHAR RateIdx, i, j; ++ UCHAR NewRate[12], NewRateLen; ++ ++ NewRateLen = 0; ++ ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ RateIdx = 4; ++ else ++ RateIdx = 12; ++ ++ // Check for support rates exclude basic rate bit ++ for (i = 0; i < *SupRateLen; i++) ++ for (j = 0; j < RateIdx; j++) ++ if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ NewRate[NewRateLen++] = SupRate[i]; ++ ++ *SupRateLen = NewRateLen; ++ NdisMoveMemory(SupRate, NewRate, NewRateLen); ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++BOOLEAN RTMPCheckChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR CentralChannel, ++ IN UCHAR Channel) ++{ ++ UCHAR k; ++ UCHAR UpperChannel = 0, LowerChannel = 0; ++ UCHAR NoEffectChannelinList = 0; ++ ++ // Find upper and lower channel according to 40MHz current operation. ++ if (CentralChannel < Channel) ++ { ++ UpperChannel = Channel; ++ if (CentralChannel > 2) ++ LowerChannel = CentralChannel - 2; ++ else ++ return FALSE; ++ } ++ else if (CentralChannel > Channel) ++ { ++ UpperChannel = CentralChannel + 2; ++ LowerChannel = Channel; ++ } ++ ++ for (k = 0;k < pAd->ChannelListNum;k++) ++ { ++ if (pAd->ChannelList[k].Channel == UpperChannel) ++ { ++ NoEffectChannelinList ++; ++ } ++ if (pAd->ChannelList[k].Channel == LowerChannel) ++ { ++ NoEffectChannelinList ++; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList)); ++ if (NoEffectChannelinList == 2) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for HT phy type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode) ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckHt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo) ++{ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ // If use AMSDU, set flag. ++ if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED); ++ // Save Peer Capability ++ if (pHtCapability->HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE); ++ if (pHtCapability->HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE); ++ if (pHtCapability->HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (pHtCapability->HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) ++ { ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE); ++ } ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity; ++ } ++ ++ // Will check ChannelWidth for MCSSet[4] below ++ pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1; ++ switch (pAd->CommonCfg.RxStream) ++ { ++ case 1: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ case 2: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ case 3: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ } ++ ++ pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n", ++ pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth, ++ pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode)); ++ ++ pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF; ++ ++ // Send Assoc Req with my HT capability. ++ pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize; ++ pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs; ++ pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20); ++ pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40); ++ pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC); ++ pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC); ++ pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor; ++ pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity; ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; ++ pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; ++ if (pAd->CommonCfg.bRdg) ++ { ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport; ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1; ++ } ++ ++ if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20) ++ pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32 ++ ++ COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for different PHY type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateMlmeRate( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR MinimumRate; ++ UCHAR ProperMlmeRate; //= RATE_54; ++ UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++ BOOLEAN bMatch = FALSE; ++ ++ switch (pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11B: ++ ProperMlmeRate = RATE_11; ++ MinimumRate = RATE_1; ++ break; ++ case PHY_11BG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++ case PHY_11BGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ if ((pAd->MlmeAux.SupRateLen == 4) && ++ (pAd->MlmeAux.ExtRateLen == 0)) ++ // B only AP ++ ProperMlmeRate = RATE_11; ++ else ++ ProperMlmeRate = RATE_24; ++ ++ if (pAd->MlmeAux.Channel <= 14) ++ MinimumRate = RATE_1; ++ else ++ MinimumRate = RATE_6; ++ break; ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n ++ case PHY_11GN_MIXED: ++ case PHY_11AGN_MIXED: ++ case PHY_11AN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ ProperMlmeRate = RATE_24; ++ MinimumRate = RATE_6; ++ break; ++ case PHY_11ABG_MIXED: ++ ProperMlmeRate = RATE_24; ++ if (pAd->MlmeAux.Channel <= 14) ++ MinimumRate = RATE_1; ++ else ++ MinimumRate = RATE_6; ++ break; ++ default: // error ++ ProperMlmeRate = RATE_1; ++ MinimumRate = RATE_1; ++ break; ++ } ++ ++ for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) ++ { ++ for (j = 0; j < RateIdx; j++) ++ { ++ if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ { ++ if (j == ProperMlmeRate) ++ { ++ bMatch = TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (bMatch) ++ break; ++ } ++ ++ if (bMatch == FALSE) ++ { ++ for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) ++ { ++ for (j = 0; j < RateIdx; j++) ++ { ++ if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ { ++ if (j == ProperMlmeRate) ++ { ++ bMatch = TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (bMatch) ++ break; ++ } ++ } ++ ++ if (bMatch == FALSE) ++ { ++ ProperMlmeRate = MinimumRate; ++ } ++ ++ pAd->CommonCfg.MlmeRate = MinimumRate; ++ pAd->CommonCfg.RtsRate = ProperMlmeRate; ++ if (pAd->CommonCfg.MlmeRate >= RATE_6) ++ { ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ else ++ { ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word)); ++} ++ ++CHAR RTMPMaxRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi0, ++ IN CHAR Rssi1, ++ IN CHAR Rssi2) ++{ ++ CHAR larger = -127; ++ ++ if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) ++ { ++ larger = Rssi0; ++ } ++ ++ if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) ++ { ++ larger = max(Rssi0, Rssi1); ++ } ++ ++ if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) ++ { ++ larger = max(larger, Rssi2); ++ } ++ ++ if (larger == -127) ++ larger = 0; ++ ++ return larger; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Periodic evaluate antenna link status ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID AsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BBPR3 = 0; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_NIC_NOT_EXIST | ++ fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return; ++ ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef RT2860 ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.BBPR3 = BBPR3; ++#endif // RT2860 // ++#endif // CONFIG_STA_SUPPORT // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ { ++ ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt > 50) ++ { ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); ++ pAd->Mlme.bLowThroughput = FALSE; ++ } ++ else ++ { ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); ++ pAd->Mlme.bLowThroughput = TRUE; ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ After evaluation, check antenna link status ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID AsicRxAntEvalTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR BBPR3 = 0; ++ CHAR larger = -127, rssi0, rssi1, rssi2; ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ return; ++ ++ ++ // if the traffic is low, use average rssi as the criteria ++ if (pAd->Mlme.bLowThroughput == TRUE) ++ { ++ rssi0 = pAd->StaCfg.RssiSample.LastRssi0; ++ rssi1 = pAd->StaCfg.RssiSample.LastRssi1; ++ rssi2 = pAd->StaCfg.RssiSample.LastRssi2; ++ } ++ else ++ { ++ rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; ++ rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; ++ rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; ++ } ++ ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ larger = max(rssi0, rssi1); ++ ++ if (larger > (rssi2 + 20)) ++ pAd->Mlme.RealRxPath = 2; ++ else ++ pAd->Mlme.RealRxPath = 3; ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ if (rssi0 > (rssi1 + 20)) ++ pAd->Mlme.RealRxPath = 1; ++ else ++ pAd->Mlme.RealRxPath = 2; ++ } ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Mlme.RealRxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Mlme.RealRxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Mlme.RealRxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++#ifdef RT2860 ++ pAd->StaCfg.BBPR3 = BBPR3; ++#endif // RT2860 // ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++ ++ ++VOID APSDPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ return; ++ ++ pAd->CommonCfg.TriggerTimerCount++; ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Set/reset MAC registers according to bPiggyBack parameter ++ ++ Arguments: ++ pAd - Adapter pointer ++ bPiggyBack - Enable / Disable Piggy-Back ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID RTMPSetPiggyBack( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bPiggyBack) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ ++ TxLinkCfg.field.TxCFAckEn = bPiggyBack; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ check if this entry need to switch rate automatically ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry) ++{ ++ BOOLEAN result = TRUE; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // only associated STA counts ++ if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) ++ { ++ result = pAd->StaCfg.bAutoTxRateSwitch; ++ } ++ else ++ result = FALSE; ++ ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry && (pEntry->ValidAsDls)) ++ result = pAd->StaCfg.bAutoTxRateSwitch; ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ return result; ++} ++ ++ ++BOOLEAN RTMPAutoRateSwitchCheck( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.bAutoTxRateSwitch) ++ return TRUE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ return FALSE; ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ check if this entry need to fix tx legacy rate ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++UCHAR RTMPStaFixedTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry) ++{ ++ UCHAR tx_mode = FIXED_TXMODE_HT; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return tx_mode; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified. ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateLegacyTxSetting( ++ UCHAR fixed_tx_mode, ++ PMAC_TABLE_ENTRY pEntry) ++{ ++ HTTRANSMIT_SETTING TransmitSetting; ++ ++ if (fixed_tx_mode == FIXED_TXMODE_HT) ++ return; ++ ++ TransmitSetting.word = 0; ++ ++ TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE; ++ TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS; ++ ++ if (fixed_tx_mode == FIXED_TXMODE_CCK) ++ { ++ TransmitSetting.field.MODE = MODE_CCK; ++ // CCK mode allow MCS 0~3 ++ if (TransmitSetting.field.MCS > MCS_3) ++ TransmitSetting.field.MCS = MCS_3; ++ } ++ else ++ { ++ TransmitSetting.field.MODE = MODE_OFDM; ++ // OFDM mode allow MCS 0~7 ++ if (TransmitSetting.field.MCS > MCS_7) ++ TransmitSetting.field.MCS = MCS_7; ++ } ++ ++ if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) ++ { ++ pEntry->HTPhyMode.word = TransmitSetting.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n", ++ pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS)); ++ } ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ dynamic tune BBP R66 to find a balance between sensibility and ++ noise isolation ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicStaBbpTuning( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30; ++ CHAR Rssi; ++ ++ // 2860C did not support Fase CCA, therefore can't tune ++ if (pAd->MACVersion == 0x28600100) ++ return; ++ ++ // ++ // work as a STA ++ // ++ if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING ++ return; ++ ++ if ((pAd->OpMode == OPMODE_STA) ++ && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++#ifdef RT2860 ++ && (pAd->bPCIclkOff == FALSE) ++#endif // RT2860 // ++ ) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); ++ R66 = OrigR66Value; ++ ++ if (pAd->Antenna.field.RxPath > 1) ++ Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; ++ else ++ Rssi = pAd->StaCfg.RssiSample.AvgRssi0; ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { //BG band ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ } ++ else ++ { //A band ++ if (pAd->CommonCfg.BBPCurrentBW == BW_20) ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ else ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ } ++ ++ ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RTMPSetAGCInitValue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BandWidth) ++{ ++ UCHAR R66 = 0x30; ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { // BG band ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { //A band ++ if (BandWidth == BW_20) ++ { ++ R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ { ++ R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++} ++ ++VOID AsicTurnOffRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ ++ // RF R2 bit 18 = 0 ++ UINT32 R1 = 0, R2 = 0, R3 = 0; ++ UCHAR index; ++ RTMP_RF_REGS *RFRegTable; ++ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R1 = RFRegTable[index].R1 & 0xffffdfff; ++ R2 = RFRegTable[index].R2 & 0xfffbffff; ++ R3 = RFRegTable[index].R3 & 0xfff3ffff; ++ ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ ++ // Program R1b13 to 1, R3/b18,19 to 0, R2b18 to 0. ++ // Set RF R2 bit18=0, R3 bit[18:19]=0 ++ //if (pAd->StaCfg.bRadio == FALSE) ++ if (1) ++ { ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x, R3 = 0x%08x \n", ++ Channel, pAd->RfIcType, R2, R3)); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x \n", ++ Channel, pAd->RfIcType, R2)); ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++VOID AsicTurnOnRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ ++ // RF R2 bit 18 = 0 ++ UINT32 R1 = 0, R2 = 0, R3 = 0; ++ UCHAR index; ++ RTMP_RF_REGS *RFRegTable; ++ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R3 = pAd->LatchRfRegs.R3; ++ R3 &= 0xfff3ffff; ++ R3 |= 0x00080000; ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ ++ R1 = RFRegTable[index].R1; ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ R2 |= 0x40; // write 1 to off Rxpath. ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOnRFClk#%d(RF=%d, ) , R2=0x%08x\n", ++ Channel, ++ pAd->RfIcType, ++ R2)); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/netif_block.c +@@ -0,0 +1,144 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "../rt_config.h" ++#include "netif_block.h" ++ ++static NETIF_ENTRY freeNetIfEntryPool[FREE_NETIF_POOL_SIZE]; ++static LIST_HEADER freeNetIfEntryList; ++ ++void initblockQueueTab( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ ++ initList(&freeNetIfEntryList); ++ for (i = 0; i < FREE_NETIF_POOL_SIZE; i++) ++ insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)&freeNetIfEntryPool[i]); ++ ++ for (i=0; i < NUM_OF_TX_RING; i++) ++ initList(&pAd->blockQueueTab[i].NetIfList); ++ ++ return; ++} ++ ++BOOLEAN blockNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, ++ IN PNET_DEV pNetDev) ++{ ++ PNETIF_ENTRY pNetIfEntry = NULL; ++ ++ if ((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(&freeNetIfEntryList)) != NULL) ++ { ++ netif_stop_queue(pNetDev); ++ pNetIfEntry->pNetDev = pNetDev; ++ insertTailList(&pBlockQueueEntry->NetIfList, (PLIST_ENTRY)pNetIfEntry); ++ ++ pBlockQueueEntry->SwTxQueueBlockFlag = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("netif_stop_queue(%s)\n", pNetDev->name)); ++ } ++ else ++ return FALSE; ++ ++ return TRUE; ++} ++ ++VOID releaseNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry) ++{ ++ PNETIF_ENTRY pNetIfEntry = NULL; ++ PLIST_HEADER pNetIfList = &pBlockQueueEntry->NetIfList; ++ ++ while((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(pNetIfList)) != NULL) ++ { ++ PNET_DEV pNetDev = pNetIfEntry->pNetDev; ++ netif_wake_queue(pNetDev); ++ insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)pNetIfEntry); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("netif_wake_queue(%s)\n", pNetDev->name)); ++ } ++ pBlockQueueEntry->SwTxQueueBlockFlag = FALSE; ++ return; ++} ++ ++ ++VOID StopNetIfQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PNET_DEV NetDev = NULL; ++ UCHAR IfIdx = 0; ++ BOOLEAN valid = FALSE; ++ ++#ifdef APCLI_SUPPORT ++ if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_APCLI) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_APCLI) % MAX_APCLI_NUM; ++ NetDev = pAd->ApCfg.ApCliTab[IfIdx].dev; ++ } ++ else ++#endif // APCLI_SUPPORT // ++#ifdef WDS_SUPPORT ++ if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_WDS) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_WDS) % MAX_WDS_ENTRY; ++ NetDev = pAd->WdsTab.WdsEntry[IfIdx].dev; ++ } ++ else ++#endif // WDS_SUPPORT // ++ { ++#ifdef MBSS_SUPPORT ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_MBSSID) % MAX_MBSSID_NUM; ++ NetDev = pAd->ApCfg.MBSSID[IfIdx].MSSIDDev; ++ } ++ else ++ { ++ IfIdx = MAIN_MBSSID; ++ NetDev = pAd->net_dev; ++ } ++#else ++ IfIdx = MAIN_MBSSID; ++ NetDev = pAd->net_dev; ++#endif ++ } ++ ++ // WMM support 4 software queues. ++ // One software queue full doesn't mean device have no capbility to transmit packet. ++ // So disable block Net-If queue function while WMM enable. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ valid = (pAd->CommonCfg.bWmmCapable == TRUE) ? FALSE : TRUE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (valid) ++ blockNetIf(&pAd->blockQueueTab[QueIdx], NetDev); ++ return; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/netif_block.h +@@ -0,0 +1,58 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __NET_IF_BLOCK_H__ ++#define __NET_IF_BLOCK_H__ ++ ++//#include ++#include "link_list.h" ++#include "rtmp.h" ++ ++#define FREE_NETIF_POOL_SIZE 32 ++ ++typedef struct _NETIF_ENTRY ++{ ++ struct _NETIF_ENTRY *pNext; ++ PNET_DEV pNetDev; ++} NETIF_ENTRY, *PNETIF_ENTRY; ++ ++void initblockQueueTab( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN blockNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, ++ IN PNET_DEV pNetDev); ++ ++VOID releaseNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry); ++ ++VOID StopNetIfQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++#endif // __NET_IF_BLOCK_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/rtmp_init.c +@@ -0,0 +1,3757 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_init.c ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme ++ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. ++*/ ++#include "../rt_config.h" ++#include "firmware.h" ++ ++UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; ++ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, ++ 0x00000010, 0x00000020, 0x00000040, 0x00000080, ++ 0x00000100, 0x00000200, 0x00000400, 0x00000800, ++ 0x00001000, 0x00002000, 0x00004000, 0x00008000, ++ 0x00010000, 0x00020000, 0x00040000, 0x00080000, ++ 0x00100000, 0x00200000, 0x00400000, 0x00800000, ++ 0x01000000, 0x02000000, 0x04000000, 0x08000000, ++ 0x10000000, 0x20000000, 0x40000000, 0x80000000}; ++ ++char* CipherName[] = {"none","wep64","wep128","TKIP","AES","CKIP64","CKIP128"}; ++ ++const unsigned short ccitt_16Table[] = { ++ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, ++ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, ++ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, ++ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, ++ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, ++ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, ++ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, ++ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, ++ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, ++ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, ++ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, ++ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, ++ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, ++ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, ++ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, ++ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, ++ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, ++ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, ++ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, ++ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, ++ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, ++ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, ++ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, ++ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, ++ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, ++ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, ++ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, ++ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, ++ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, ++ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, ++ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, ++ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 ++}; ++#define ByteCRC16(v, crc) \ ++ (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) ++ ++unsigned char BitReverse(unsigned char x) ++{ ++ int i; ++ unsigned char Temp=0; ++ for(i=0; ; i++) ++ { ++ if(x & 0x80) Temp |= 0x80; ++ if(i==7) break; ++ x <<= 1; ++ Temp >>= 1; ++ } ++ return Temp; ++} ++ ++// ++// BBP register initialization set ++// ++REG_PAIR BBPRegTable[] = { ++ {BBP_R65, 0x2C}, // fix rssi issue ++ {BBP_R66, 0x38}, // Also set this default value to pAd->BbpTuning.R66CurrentValue at initial ++ {BBP_R69, 0x12}, ++ {BBP_R70, 0xa}, // BBP_R70 will change to 0x8 in ApStartUp and LinkUp for rt2860C, otherwise value is 0xa ++ {BBP_R73, 0x10}, ++ {BBP_R81, 0x37}, ++ {BBP_R82, 0x62}, ++ {BBP_R83, 0x6A}, ++ {BBP_R84, 0x99}, // 0x19 is for rt2860E and after. This is for extension channel overlapping IOT. 0x99 is for rt2860D and before ++ {BBP_R86, 0x00}, // middle range issue, Rory @2008-01-28 ++ {BBP_R91, 0x04}, // middle range issue, Rory @2008-01-28 ++ {BBP_R92, 0x00}, // middle range issue, Rory @2008-01-28 ++ {BBP_R103, 0x00}, // near range high-power issue, requested from Gary @2008-0528 ++ {BBP_R105, 0x05}, // 0x05 is for rt2860E to turn on FEQ control. It is safe for rt2860D and before, because Bit 7:2 are reserved in rt2860D and before. ++}; ++#define NUM_BBP_REG_PARMS (sizeof(BBPRegTable) / sizeof(REG_PAIR)) ++ ++// ++// RF register initialization set ++// ++ ++// ++// ASIC register initialization sets ++// ++ ++RTMP_REG_PAIR MACRegTable[] = { ++#if defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x200) ++ {BCN_OFFSET0, 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ ++ {BCN_OFFSET1, 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ ++#elif defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x100) ++ {BCN_OFFSET0, 0xece8e4e0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ ++ {BCN_OFFSET1, 0xfcf8f4f0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ ++#else ++ #error You must re-calculate new value for BCN_OFFSET0 & BCN_OFFSET1 in MACRegTable[]!!! ++#endif // HW_BEACON_OFFSET // ++ ++ {LEGACY_BASIC_RATE, 0x0000013f}, // Basic rate set bitmap ++ {HT_BASIC_RATE, 0x00008003}, // Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI. ++ {MAC_SYS_CTRL, 0x00}, // 0x1004, , default Disable RX ++ {RX_FILTR_CFG, 0x17f97}, //0x1400 , RX filter control, ++ {BKOFF_SLOT_CFG, 0x209}, // default set short slot time, CC_DELAY_TIME should be 2 ++ {TX_SW_CFG0, 0x0}, // Gary,2008-05-21 for CWC test ++ {TX_SW_CFG1, 0x80606}, // Gary,2006-08-23 ++ {TX_LINK_CFG, 0x1020}, // Gary,2006-08-23 ++ {TX_TIMEOUT_CFG, 0x000a2090}, // CCK has some problem. So increase timieout value. 2006-10-09// MArvek RT , Modify for 2860E ,2007-08-01 ++ {MAX_LEN_CFG, MAX_AGGREGATION_SIZE | 0x00001000}, // 0x3018, MAX frame length. Max PSDU = 16kbytes. ++ {LED_CFG, 0x7f031e46}, // Gary, 2006-08-23 ++ {PBF_MAX_PCNT, 0x1F3FBF9F}, //0x1F3f7f9f}, //Jan, 2006/04/20 ++ {TX_RTY_CFG, 0x47d01f0f}, // Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03 ++ {AUTO_RSP_CFG, 0x00000013}, // Initial Auto_Responder, because QA will turn off Auto-Responder ++ {CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. ++ {OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. ++ {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS ++ {GF40_PROT_CFG, 0x03F44084}, ++ {MM20_PROT_CFG, 0x01744004}, ++#ifdef RT2860 ++ {MM40_PROT_CFG, 0x03F54084}, ++#endif // RT2860 // ++ {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. ++ {TX_RTS_CFG, 0x00092b20}, ++ {EXP_ACK_TIME, 0x002400ca}, // default value ++ {TXOP_HLDR_ET, 0x00000002}, ++ ++ /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us ++ is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0 ++ and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping ++ will always lost. So we change the SIFS of CCK from 10us to 16us. */ ++ {XIFS_TIME_CFG, 0x33a41010}, ++ {PWR_PIN_CFG, 0x00000003}, // patch for 2880-E ++}; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++RTMP_REG_PAIR STAMACRegTable[] = { ++ {WMM_AIFSN_CFG, 0x00002273}, ++ {WMM_CWMIN_CFG, 0x00002344}, ++ {WMM_CWMAX_CFG, 0x000034aa}, ++}; ++#endif // CONFIG_STA_SUPPORT // ++ ++#define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) ++#ifdef CONFIG_STA_SUPPORT ++#define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// New 8k byte firmware size for RT3071/RT3072 ++#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 ++#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) ++#define FIRMWARE_MAJOR_VERSION 0 ++ ++#define FIRMWAREIMAGEV1_LENGTH 0x1000 ++#define FIRMWAREIMAGEV2_LENGTH 0x1000 ++ ++#ifdef RT2860 ++#define FIRMWARE_MINOR_VERSION 2 ++#endif // RT2860 // ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Allocate RTMP_ADAPTER data block and do some initialization ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPAllocAdapterBlock( ++ IN PVOID handle, ++ OUT PRTMP_ADAPTER *ppAdapter) ++{ ++ PRTMP_ADAPTER pAd; ++ NDIS_STATUS Status; ++ INT index; ++ UCHAR *pBeaconBuf = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocAdapterBlock\n")); ++ ++ *ppAdapter = NULL; ++ ++ do ++ { ++ // Allocate RTMP_ADAPTER memory block ++ pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG); ++ if (pBeaconBuf == NULL) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n")); ++ break; ++ } ++ ++ Status = AdapterBlockAllocateMemory(handle, (PVOID *)&pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n")); ++ break; ++ } ++ pAd->BeaconBuf = pBeaconBuf; ++ printk("\n\n=== pAd = %p, size = %d ===\n\n", pAd, (UINT32)sizeof(RTMP_ADAPTER)); ++ ++ ++ // Init spin locks ++ NdisAllocateSpinLock(&pAd->MgmtRingLock); ++#ifdef RT2860 ++ NdisAllocateSpinLock(&pAd->RxRingLock); ++#endif // RT2860 // ++ ++ for (index =0 ; index < NUM_OF_TX_RING; index++) ++ { ++ NdisAllocateSpinLock(&pAd->TxSwQueueLock[index]); ++ NdisAllocateSpinLock(&pAd->DeQueueLock[index]); ++ pAd->DeQueueRunning[index] = FALSE; ++ } ++ ++ NdisAllocateSpinLock(&pAd->irq_lock); ++ ++ } while (FALSE); ++ ++ if ((Status != NDIS_STATUS_SUCCESS) && (pBeaconBuf)) ++ kfree(pBeaconBuf); ++ ++ *ppAdapter = pAd; ++ ++ DBGPRINT_S(Status, ("<-- RTMPAllocAdapterBlock, Status=%x\n", Status)); ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial Tx power per MCS and BW from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReadTxPwrPerRate( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG data, Adata, Gdata; ++ USHORT i, value, value2; ++ INT Apwrdelta, Gpwrdelta; ++ UCHAR t1,t2,t3,t4; ++ BOOLEAN bValid, bApwrdeltaMinus = TRUE, bGpwrdeltaMinus = TRUE; ++ ++ // ++ // Get power delta for 20MHz and 40MHz. ++ // ++ DBGPRINT(RT_DEBUG_TRACE, ("Txpower per Rate\n")); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_DELTA, value2); ++ Apwrdelta = 0; ++ Gpwrdelta = 0; ++ ++ if ((value2 & 0xff) != 0xff) ++ { ++ if ((value2 & 0x80)) ++ Gpwrdelta = (value2&0xf); ++ ++ if ((value2 & 0x40)) ++ bGpwrdeltaMinus = FALSE; ++ else ++ bGpwrdeltaMinus = TRUE; ++ } ++ if ((value2 & 0xff00) != 0xff00) ++ { ++ if ((value2 & 0x8000)) ++ Apwrdelta = ((value2&0xf00)>>8); ++ ++ if ((value2 & 0x4000)) ++ bApwrdeltaMinus = FALSE; ++ else ++ bApwrdeltaMinus = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Gpwrdelta = %x, Apwrdelta = %x .\n", Gpwrdelta, Apwrdelta)); ++ ++ // ++ // Get Txpower per MCS for 20MHz in 2.4G. ++ // ++ for (i=0; i<5; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4, value); ++ data = value; ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ data |= (value<<16); ++ ++ pAd->Tx20MPwrCfgABand[i] = pAd->Tx40MPwrCfgABand[i] = Adata; ++ pAd->Tx20MPwrCfgGBand[i] = pAd->Tx40MPwrCfgGBand[i] = Gdata; ++ ++ if (data != 0xffffffff) ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, data); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 2.4G band-%lx, Adata = %lx, Gdata = %lx \n", data, Adata, Gdata)); ++ } ++ ++ // ++ // Check this block is valid for 40MHz in 2.4G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 40MHz in 2.4G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4, value); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4 + 2, value); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx40MPwrCfgGBand[i+1] = (pAd->Tx40MPwrCfgGBand[i+1] & 0x0000FFFF) | (Gdata & 0xFFFF0000); ++ else ++ pAd->Tx40MPwrCfgGBand[i+1] = Gdata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 2.4G band, Gdata = %lx \n", Gdata)); ++ } ++ } ++ ++ // ++ // Check this block is valid for 20MHz in 5G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 20MHz in 5G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<5; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx20MPwrCfgABand[i] = (pAd->Tx20MPwrCfgABand[i] & 0x0000FFFF) | (Adata & 0xFFFF0000); ++ else ++ pAd->Tx20MPwrCfgABand[i] = Adata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 5GHz band, Adata = %lx \n", Adata)); ++ } ++ } ++ ++ // ++ // Check this block is valid for 40MHz in 5G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 40MHz in 5G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx40MPwrCfgABand[i+1] = (pAd->Tx40MPwrCfgABand[i+1] & 0x0000FFFF) | (Adata & 0xFFFF0000); ++ else ++ pAd->Tx40MPwrCfgABand[i+1] = Adata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 5GHz band, Adata = %lx \n", Adata)); ++ } ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial channel power parameters from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReadChannelPwr( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i, choffset; ++ EEPROM_TX_PWR_STRUC Power; ++ EEPROM_TX_PWR_STRUC Power2; ++ ++ // Read Tx power value for all channels ++ // Value from 1 - 0x7f. Default value is 24. ++ // Power value : 2.4G 0x00 (0) ~ 0x1F (31) ++ // : 5.5G 0xF9 (-7) ~ 0x0F (15) ++ ++ // 0. 11b/g, ch1 - ch 14 ++ for (i = 0; i < 7; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2, Power2.word); ++ pAd->TxPower[i * 2].Channel = i * 2 + 1; ++ pAd->TxPower[i * 2 + 1].Channel = i * 2 + 2; ++ ++ if ((Power.field.Byte0 > 31) || (Power.field.Byte0 < 0)) ++ pAd->TxPower[i * 2].Power = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 > 31) || (Power.field.Byte1 < 0)) ++ pAd->TxPower[i * 2 + 1].Power = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2 + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 > 31) || (Power2.field.Byte0 < 0)) ++ pAd->TxPower[i * 2].Power2 = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 > 31) || (Power2.field.Byte1 < 0)) ++ pAd->TxPower[i * 2 + 1].Power2 = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2 + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 1. U-NII lower/middle band: 36, 38, 40; 44, 46, 48; 52, 54, 56; 60, 62, 64 (including central frequency in BW 40MHz) ++ // 1.1 Fill up channel ++ choffset = 14; ++ for (i = 0; i < 4; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 36 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 36 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 36 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ ++ // 1.2 Fill up power ++ for (i = 0; i < 6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 2. HipperLAN 2 100, 102 ,104; 108, 110, 112; 116, 118, 120; 124, 126, 128; 132, 134, 136; 140 (including central frequency in BW 40MHz) ++ // 2.1 Fill up channel ++ choffset = 14 + 12; ++ for (i = 0; i < 5; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 100 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 100 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 100 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ pAd->TxPower[3 * 5 + choffset + 0].Channel = 140; ++ pAd->TxPower[3 * 5 + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * 5 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ // 2.2 Fill up power ++ for (i = 0; i < 8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 3. U-NII upper band: 149, 151, 153; 157, 159, 161; 165 (including central frequency in BW 40MHz) ++ // 3.1 Fill up channel ++ choffset = 14 + 12 + 16; ++ for (i = 0; i < 2; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 149 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 149 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 149 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ pAd->TxPower[3 * 2 + choffset + 0].Channel = 165; ++ pAd->TxPower[3 * 2 + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * 2 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ // 3.2 Fill up power ++ for (i = 0; i < 4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 4. Print and Debug ++ choffset = 14 + 12 + 16 + 7; ++ ++ ++#if 0 ++ // Init the 802.11j channel number for TX channel power ++ // 0. 20MHz ++ for (i = 0; i < 3; i++) ++ { ++ pAd->TxPower11J[i].Channel = 8 + i * 4; ++ pAd->TxPower11J[i].BW = BW_20; ++ } ++ ++ for (i = 0; i < 4; i++) ++ { ++ pAd->TxPower11J[i + 3].Channel = 34 + i * 4; ++ pAd->TxPower11J[i + 3].BW = BW_20; ++ } ++ ++ for (i = 0; i < 4; i++) ++ { ++ pAd->TxPower11J[i + 7].Channel = 184 + i * 4; ++ pAd->TxPower11J[i + 7].BW = BW_20; ++ } ++ ++ // 0. 10MHz ++ for (i = 0; i < 2; i++) ++ { ++ pAd->TxPower11J[i + 11].Channel = 7 + i; ++ pAd->TxPower11J[i + 11].BW = BW_10; ++ } ++ pAd->TxPower11J[13].Channel = 11; ++ pAd->TxPower11J[13].BW = BW_10; ++ ++ for (i = 0; i < 3; i++) ++ { ++ pAd->TxPower11J[i + 14].Channel = 183 + i; ++ pAd->TxPower11J[i + 14].BW= BW_10; ++ } ++ ++ for (i = 0; i < 3; i++) ++ { ++ pAd->TxPower11J[i + 17].Channel = 187 + i; ++ pAd->TxPower11J[i + 17].BW = BW_10; ++ } ++ for (i = 0; i < 10; i++) ++ { ++ Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_Japan_TX_PWR_OFFSET + i * 2); ++ Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_Japan_TX2_PWR_OFFSET + i * 2); ++ ++ if ((Power.field.Byte0 < 36) && (Power.field.Byte0 > -6)) ++ pAd->TxPower11J[i * 2].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 36) && (Power.field.Byte1 > -6)) ++ pAd->TxPower11J[i * 2 + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 36) && (Power2.field.Byte0 > -6)) ++ pAd->TxPower11J[i * 2].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 36) && (Power2.field.Byte1 > -6)) ++ pAd->TxPower11J[i * 2 + 1].Power2 = Power2.field.Byte1; ++ } ++#endif ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read the following from the registry ++ 1. All the parameters ++ 2. NetworkAddres ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ WrapperConfigurationContext For use by NdisOpenConfiguration ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICReadRegParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status)); ++ return Status; ++} ++ ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial parameters from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NICReadEEPROMParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mac_addr) ++{ ++ UINT32 data = 0; ++ USHORT i, value, value2; ++ UCHAR TmpPhy; ++ EEPROM_TX_PWR_STRUC Power; ++ EEPROM_VERSION_STRUC Version; ++ EEPROM_ANTENNA_STRUC Antenna; ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICReadEEPROMParameters\n")); ++ ++ // Init EEPROM Address Number, before access EEPROM; if 93c46, EEPROMAddressNum=6, else if 93c66, EEPROMAddressNum=8 ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &data); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> E2PROM_CSR = 0x%x\n", data)); ++ ++ if((data & 0x30) == 0) ++ pAd->EEPROMAddressNum = 6; // 93C46 ++ else if((data & 0x30) == 0x10) ++ pAd->EEPROMAddressNum = 8; // 93C66 ++ else ++ pAd->EEPROMAddressNum = 8; // 93C86 ++ DBGPRINT(RT_DEBUG_TRACE, ("--> EEPROMAddressNum = %d\n", pAd->EEPROMAddressNum )); ++ ++ // RT2860 MAC no longer auto load MAC address from E2PROM. Driver has to intialize ++ // MAC address registers according to E2PROM setting ++ if (mac_addr == NULL || ++ strlen(mac_addr) != 17 || ++ mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' || ++ mac_addr[11] != ':' || mac_addr[14] != ':') ++ { ++ USHORT Addr01,Addr23,Addr45 ; ++ ++ RT28xx_EEPROM_READ16(pAd, 0x04, Addr01); ++ RT28xx_EEPROM_READ16(pAd, 0x06, Addr23); ++ RT28xx_EEPROM_READ16(pAd, 0x08, Addr45); ++ ++ pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); ++ pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); ++ pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); ++ pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); ++ pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); ++ pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from E2PROM \n")); ++ } ++ else ++ { ++ INT j; ++ PUCHAR macptr; ++ ++ macptr = mac_addr; ++ ++ for (j=0; jPermanentAddress[j], 1); ++ macptr=macptr+3; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from module parameter \n")); ++ } ++ ++ ++ { ++ //more conveninet to test mbssid, so ap's bssid &0xf1 ++ if (pAd->PermanentAddress[0] == 0xff) ++ pAd->PermanentAddress[0] = RandomByte(pAd)&0xf8; ++ ++ //if (pAd->PermanentAddress[5] == 0xff) ++ // pAd->PermanentAddress[5] = RandomByte(pAd)&0xf8; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->PermanentAddress[0], pAd->PermanentAddress[1], ++ pAd->PermanentAddress[2], pAd->PermanentAddress[3], ++ pAd->PermanentAddress[4], pAd->PermanentAddress[5])); ++ if (pAd->bLocalAdminMAC == FALSE) ++ { ++ MAC_DW0_STRUC csr2; ++ MAC_DW1_STRUC csr3; ++ COPY_MAC_ADDR(pAd->CurrentAddress, pAd->PermanentAddress); ++ csr2.field.Byte0 = pAd->CurrentAddress[0]; ++ csr2.field.Byte1 = pAd->CurrentAddress[1]; ++ csr2.field.Byte2 = pAd->CurrentAddress[2]; ++ csr2.field.Byte3 = pAd->CurrentAddress[3]; ++ RTMP_IO_WRITE32(pAd, MAC_ADDR_DW0, csr2.word); ++ csr3.word = 0; ++ csr3.field.Byte4 = pAd->CurrentAddress[4]; ++ csr3.field.Byte5 = pAd->CurrentAddress[5]; ++ csr3.field.U2MeMask = 0xff; ++ RTMP_IO_WRITE32(pAd, MAC_ADDR_DW1, csr3.word); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->PermanentAddress[0], pAd->PermanentAddress[1], ++ pAd->PermanentAddress[2], pAd->PermanentAddress[3], ++ pAd->PermanentAddress[4], pAd->PermanentAddress[5])); ++ } ++ } ++ ++ // if not return early. cause fail at emulation. ++ // Init the channel number for TX channel power ++ RTMPReadChannelPwr(pAd); ++ ++ // if E2PROM version mismatch with driver's expectation, then skip ++ // all subsequent E2RPOM retieval and set a system error bit to notify GUI ++ RT28xx_EEPROM_READ16(pAd, EEPROM_VERSION_OFFSET, Version.word); ++ pAd->EepromVersion = Version.field.Version + Version.field.FaeReleaseNumber * 256; ++ DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: Version = %d, FAE release #%d\n", Version.field.Version, Version.field.FaeReleaseNumber)); ++ ++ if (Version.field.Version > VALID_EEPROM_VERSION) ++ { ++ DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n",Version.field.Version, VALID_EEPROM_VERSION)); ++ /*pAd->SystemErrorBitmap |= 0x00000001; ++ ++ // hard-code default value when no proper E2PROM installed ++ pAd->bAutoTxAgcA = FALSE; ++ pAd->bAutoTxAgcG = FALSE; ++ ++ // Default the channel power ++ for (i = 0; i < MAX_NUM_OF_CHANNELS; i++) ++ pAd->TxPower[i].Power = DEFAULT_RF_TX_POWER; ++ ++ // Default the channel power ++ for (i = 0; i < MAX_NUM_OF_11JCHANNELS; i++) ++ pAd->TxPower11J[i].Power = DEFAULT_RF_TX_POWER; ++ ++ for(i = 0; i < NUM_EEPROM_BBP_PARMS; i++) ++ pAd->EEPROMDefaultValue[i] = 0xffff; ++ return; */ ++ } ++ ++ // Read BBP default value from EEPROM and store to array(EEPROMDefaultValue) in pAd ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, value); ++ pAd->EEPROMDefaultValue[0] = value; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC2_OFFSET, value); ++ pAd->EEPROMDefaultValue[1] = value; ++ ++ RT28xx_EEPROM_READ16(pAd, 0x38, value); // Country Region ++ pAd->EEPROMDefaultValue[2] = value; ++ ++ for(i = 0; i < 8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_BBP_BASE_OFFSET + i*2, value); ++ pAd->EEPROMDefaultValue[i+3] = value; ++ } ++ ++ // We have to parse NIC configuration 0 at here. ++ // If TSSI did not have preloaded value, it should reset the TxAutoAgc to false ++ // Therefore, we have to read TxAutoAgc control beforehand. ++ // Read Tx AGC control bit ++ Antenna.word = pAd->EEPROMDefaultValue[0]; ++ if (Antenna.word == 0xFFFF) ++ { ++ Antenna.word = 0; ++ Antenna.field.RfIcType = RFIC_2820; ++ Antenna.field.TxPath = 1; ++ Antenna.field.RxPath = 2; ++ DBGPRINT(RT_DEBUG_WARN, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); ++ } ++ ++ // Choose the desired Tx&Rx stream. ++ if ((pAd->CommonCfg.TxStream == 0) || (pAd->CommonCfg.TxStream > Antenna.field.TxPath)) ++ pAd->CommonCfg.TxStream = Antenna.field.TxPath; ++ ++ if ((pAd->CommonCfg.RxStream == 0) || (pAd->CommonCfg.RxStream > Antenna.field.RxPath)) ++ { ++ pAd->CommonCfg.RxStream = Antenna.field.RxPath; ++ ++ if ((pAd->MACVersion < RALINK_2883_VERSION) && ++ (pAd->CommonCfg.RxStream > 2)) ++ { ++ // only 2 Rx streams for RT2860 series ++ pAd->CommonCfg.RxStream = 2; ++ } ++ } ++ ++ // 3*3 ++ // read value from EEPROM and set them to CSR174 ~ 177 in chain0 ~ chain2 ++ // yet implement ++ for(i=0; i<3; i++) ++ { ++ } ++ ++ NicConfig2.word = pAd->EEPROMDefaultValue[1]; ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NicConfig2.word = 0; ++ if ((NicConfig2.word & 0x00ff) == 0xff) ++ { ++ NicConfig2.word &= 0xff00; ++ } ++ ++ if ((NicConfig2.word >> 8) == 0xff) ++ { ++ NicConfig2.word &= 0x00ff; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (NicConfig2.field.DynamicTxAgcControl == 1) ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; ++ else ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("NICReadEEPROMParameters: RxPath = %d, TxPath = %d\n", Antenna.field.RxPath, Antenna.field.TxPath)); ++ ++ // Save the antenna for future use ++ pAd->Antenna.word = Antenna.word; ++ ++ // ++ // Reset PhyMode if we don't support 802.11a ++ // Only RFIC_2850 & RFIC_2750 support 802.11a ++ // ++ if ((Antenna.field.RfIcType != RFIC_2850) && (Antenna.field.RfIcType != RFIC_2750)) ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11A)) ++ pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; ++#ifdef DOT11_N_SUPPORT ++ else if ((pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11N_5G)) ++ pAd->CommonCfg.PhyMode = PHY_11BGN_MIXED; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ // Read TSSI reference and TSSI boundary for temperature compensation. This is ugly ++ // 0. 11b/g ++ { ++ /* these are tempature reference value (0x00 ~ 0xFE) ++ ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ TssiPlusBoundaryG [4] [3] [2] [1] [0] (smaller) + ++ TssiMinusBoundaryG[0] [1] [2] [3] [4] (larger) */ ++ RT28xx_EEPROM_READ16(pAd, 0x6E, Power.word); ++ pAd->TssiMinusBoundaryG[4] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryG[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x70, Power.word); ++ pAd->TssiMinusBoundaryG[2] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryG[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x72, Power.word); ++ pAd->TssiRefG = Power.field.Byte0; /* reference value [0] */ ++ pAd->TssiPlusBoundaryG[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x74, Power.word); ++ pAd->TssiPlusBoundaryG[2] = Power.field.Byte0; ++ pAd->TssiPlusBoundaryG[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x76, Power.word); ++ pAd->TssiPlusBoundaryG[4] = Power.field.Byte0; ++ pAd->TxAgcStepG = Power.field.Byte1; ++ pAd->TxAgcCompensateG = 0; ++ pAd->TssiMinusBoundaryG[0] = pAd->TssiRefG; ++ pAd->TssiPlusBoundaryG[0] = pAd->TssiRefG; ++ ++ // Disable TxAgc if the based value is not right ++ if (pAd->TssiRefG == 0xff) ++ pAd->bAutoTxAgcG = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("E2PROM: G Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", ++ pAd->TssiMinusBoundaryG[4], pAd->TssiMinusBoundaryG[3], pAd->TssiMinusBoundaryG[2], pAd->TssiMinusBoundaryG[1], ++ pAd->TssiRefG, ++ pAd->TssiPlusBoundaryG[1], pAd->TssiPlusBoundaryG[2], pAd->TssiPlusBoundaryG[3], pAd->TssiPlusBoundaryG[4], ++ pAd->TxAgcStepG, pAd->bAutoTxAgcG)); ++ } ++ // 1. 11a ++ { ++ RT28xx_EEPROM_READ16(pAd, 0xD4, Power.word); ++ pAd->TssiMinusBoundaryA[4] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryA[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xD6, Power.word); ++ pAd->TssiMinusBoundaryA[2] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryA[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xD8, Power.word); ++ pAd->TssiRefA = Power.field.Byte0; ++ pAd->TssiPlusBoundaryA[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xDA, Power.word); ++ pAd->TssiPlusBoundaryA[2] = Power.field.Byte0; ++ pAd->TssiPlusBoundaryA[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xDC, Power.word); ++ pAd->TssiPlusBoundaryA[4] = Power.field.Byte0; ++ pAd->TxAgcStepA = Power.field.Byte1; ++ pAd->TxAgcCompensateA = 0; ++ pAd->TssiMinusBoundaryA[0] = pAd->TssiRefA; ++ pAd->TssiPlusBoundaryA[0] = pAd->TssiRefA; ++ ++ // Disable TxAgc if the based value is not right ++ if (pAd->TssiRefA == 0xff) ++ pAd->bAutoTxAgcA = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("E2PROM: A Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", ++ pAd->TssiMinusBoundaryA[4], pAd->TssiMinusBoundaryA[3], pAd->TssiMinusBoundaryA[2], pAd->TssiMinusBoundaryA[1], ++ pAd->TssiRefA, ++ pAd->TssiPlusBoundaryA[1], pAd->TssiPlusBoundaryA[2], pAd->TssiPlusBoundaryA[3], pAd->TssiPlusBoundaryA[4], ++ pAd->TxAgcStepA, pAd->bAutoTxAgcA)); ++ } ++ pAd->BbpRssiToDbmDelta = 0x0; ++ ++ // Read frequency offset setting for RF ++ RT28xx_EEPROM_READ16(pAd, EEPROM_FREQ_OFFSET, value); ++ if ((value & 0x00FF) != 0x00FF) ++ pAd->RfFreqOffset = (ULONG) (value & 0x00FF); ++ else ++ pAd->RfFreqOffset = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: RF FreqOffset=0x%lx \n", pAd->RfFreqOffset)); ++ ++ //CountryRegion byte offset (38h) ++ value = pAd->EEPROMDefaultValue[2] >> 8; // 2.4G band ++ value2 = pAd->EEPROMDefaultValue[2] & 0x00FF; // 5G band ++ ++ if ((value <= REGION_MAXIMUM_BG_BAND) && (value2 <= REGION_MAXIMUM_A_BAND)) ++ { ++ pAd->CommonCfg.CountryRegion = ((UCHAR) value) | 0x80; ++ pAd->CommonCfg.CountryRegionForABand = ((UCHAR) value2) | 0x80; ++ TmpPhy = pAd->CommonCfg.PhyMode; ++ pAd->CommonCfg.PhyMode = 0xff; ++ RTMPSetPhyMode(pAd, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ // ++ // Get RSSI Offset on EEPROM 0x9Ah & 0x9Ch. ++ // The valid value are (-10 ~ 10) ++ // ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, value); ++ pAd->BGRssiOffset0 = value & 0x00ff; ++ pAd->BGRssiOffset1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET+2, value); ++ pAd->BGRssiOffset2 = value & 0x00ff; ++ pAd->ALNAGain1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, value); ++ pAd->BLNAGain = value & 0x00ff; ++ pAd->ALNAGain0 = (value >> 8); ++ ++ // Validate 11b/g RSSI_0 offset. ++ if ((pAd->BGRssiOffset0 < -10) || (pAd->BGRssiOffset0 > 10)) ++ pAd->BGRssiOffset0 = 0; ++ ++ // Validate 11b/g RSSI_1 offset. ++ if ((pAd->BGRssiOffset1 < -10) || (pAd->BGRssiOffset1 > 10)) ++ pAd->BGRssiOffset1 = 0; ++ ++ // Validate 11b/g RSSI_2 offset. ++ if ((pAd->BGRssiOffset2 < -10) || (pAd->BGRssiOffset2 > 10)) ++ pAd->BGRssiOffset2 = 0; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, value); ++ pAd->ARssiOffset0 = value & 0x00ff; ++ pAd->ARssiOffset1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET+2), value); ++ pAd->ARssiOffset2 = value & 0x00ff; ++ pAd->ALNAGain2 = (value >> 8); ++ ++ if (((UCHAR)pAd->ALNAGain1 == 0xFF) || (pAd->ALNAGain1 == 0x00)) ++ pAd->ALNAGain1 = pAd->ALNAGain0; ++ if (((UCHAR)pAd->ALNAGain2 == 0xFF) || (pAd->ALNAGain2 == 0x00)) ++ pAd->ALNAGain2 = pAd->ALNAGain0; ++ ++ // Validate 11a RSSI_0 offset. ++ if ((pAd->ARssiOffset0 < -10) || (pAd->ARssiOffset0 > 10)) ++ pAd->ARssiOffset0 = 0; ++ ++ // Validate 11a RSSI_1 offset. ++ if ((pAd->ARssiOffset1 < -10) || (pAd->ARssiOffset1 > 10)) ++ pAd->ARssiOffset1 = 0; ++ ++ //Validate 11a RSSI_2 offset. ++ if ((pAd->ARssiOffset2 < -10) || (pAd->ARssiOffset2 > 10)) ++ pAd->ARssiOffset2 = 0; ++ ++ // ++ // Get LED Setting. ++ // ++ RT28xx_EEPROM_READ16(pAd, 0x3a, value); ++ pAd->LedCntl.word = (value&0xff00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED1_OFFSET, value); ++ pAd->Led1 = value; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED2_OFFSET, value); ++ pAd->Led2 = value; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED3_OFFSET, value); ++ pAd->Led3 = value; ++ ++ RTMPReadTxPwrPerRate(pAd); ++ ++#ifdef SINGLE_SKU ++ //pAd->CommonCfg.DefineMaxTxPwr = RTMP_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR, pAd->CommonCfg.DefineMaxTxPwr); ++#endif // SINGLE_SKU // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICReadEEPROMParameters\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set default value from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NICInitAsicFromEEPROM( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef CONFIG_STA_SUPPORT ++ UINT32 data = 0; ++ UCHAR BBPR1 = 0; ++#endif // CONFIG_STA_SUPPORT // ++ USHORT i; ++ EEPROM_ANTENNA_STRUC Antenna; ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ UCHAR BBPR3 = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitAsicFromEEPROM\n")); ++ for(i = 3; i < NUM_EEPROM_BBP_PARMS; i++) ++ { ++ UCHAR BbpRegIdx, BbpValue; ++ ++ if ((pAd->EEPROMDefaultValue[i] != 0xFFFF) && (pAd->EEPROMDefaultValue[i] != 0)) ++ { ++ BbpRegIdx = (UCHAR)(pAd->EEPROMDefaultValue[i] >> 8); ++ BbpValue = (UCHAR)(pAd->EEPROMDefaultValue[i] & 0xff); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BbpRegIdx, BbpValue); ++ } ++ } ++ ++ Antenna.word = pAd->Antenna.word; ++ pAd->Mlme.RealRxPath = (UCHAR) Antenna.field.RxPath; ++ pAd->RfIcType = (UCHAR) Antenna.field.RfIcType; ++ ++ NicConfig2.word = pAd->EEPROMDefaultValue[1]; ++ ++ ++ // Save the antenna for future use ++ pAd->NicConfig2.word = NicConfig2.word; ++ ++ // ++ // Send LED Setting to MCU. ++ // ++ if (pAd->LedCntl.word == 0xFF) ++ { ++ pAd->LedCntl.word = 0x01; ++ pAd->Led1 = 0x5555; ++ pAd->Led2 = 0x2221; ++ ++#ifdef RT2860 ++ pAd->Led3 = 0xA9F8; ++#endif // RT2860 // ++ } ++ ++ AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); ++ AsicSendCommandToMcu(pAd, 0x53, 0xff, (UCHAR)pAd->Led2, (UCHAR)(pAd->Led2 >> 8)); ++ AsicSendCommandToMcu(pAd, 0x54, 0xff, (UCHAR)pAd->Led3, (UCHAR)(pAd->Led3 >> 8)); ++ pAd->LedIndicatorStregth = 0xFF; ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, before link up ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Read Hardware controlled Radio state enable bit ++ if (NicConfig2.field.HardwareRadioControl == 1) ++ { ++ pAd->StaCfg.bHardwareRadio = TRUE; ++ ++ // Read GPIO pin2 as Hardware controlled radio state ++ RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); ++ if ((data & 0x04) == 0) ++ { ++ pAd->StaCfg.bHwRadio = FALSE; ++ pAd->StaCfg.bRadio = FALSE; ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ } ++ } ++ else ++ pAd->StaCfg.bHardwareRadio = FALSE; ++ ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ RTMPSetLED(pAd, LED_RADIO_OFF); ++ } ++ else ++ { ++ RTMPSetLED(pAd, LED_RADIO_ON); ++#ifdef RT2860 ++ AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); ++ AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00); ++ // 2-1. wait command ok. ++ AsicCheckCommanOk(pAd, PowerWakeCID); ++#endif // RT2860 // ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Turn off patching for cardbus controller ++ if (NicConfig2.field.CardbusAcceleration == 1) ++ { ++ } ++ ++ if (NicConfig2.field.DynamicTxAgcControl == 1) ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; ++ else ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; ++ // ++ // Since BBP has been progamed, to make sure BBP setting will be ++ // upate inside of AsicAntennaSelect, so reset to UNKNOWN_BAND!! ++ // ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Handle the difference when 1T ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BBPR1); ++ if(pAd->Antenna.field.TxPath == 1) ++ { ++ BBPR1 &= (~0x18); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BBPR1); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Use Hw Radio Control Pin=%d; if used Pin=%d;\n", pAd->CommonCfg.bHardwareRadio, pAd->CommonCfg.bHardwareRadio)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPath = %d, RxPath = %d, RFIC=%d, Polar+LED mode=%x\n", pAd->Antenna.field.TxPath, pAd->Antenna.field.RxPath, pAd->RfIcType, pAd->LedCntl.word)); ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitAsicFromEEPROM\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize NIC hardware ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICInitializeAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ WPDMA_GLO_CFG_STRUC GloCfg; ++#ifdef RT2860 ++ UINT32 Value; ++ DELAY_INT_CFG_STRUC IntCfg; ++#endif // RT2860 // ++ ULONG i =0, j=0; ++ AC_TXOP_CSR0_STRUC csr0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAdapter\n")); ++ ++ // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: ++retry: ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i<100); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ GloCfg.word &= 0xff0; ++ GloCfg.field.EnTXWriteBackDDONE =1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ // Record HW Beacon offset ++ pAd->BeaconOffset[0] = HW_BEACON_BASE0; ++ pAd->BeaconOffset[1] = HW_BEACON_BASE1; ++ pAd->BeaconOffset[2] = HW_BEACON_BASE2; ++ pAd->BeaconOffset[3] = HW_BEACON_BASE3; ++ pAd->BeaconOffset[4] = HW_BEACON_BASE4; ++ pAd->BeaconOffset[5] = HW_BEACON_BASE5; ++ pAd->BeaconOffset[6] = HW_BEACON_BASE6; ++ pAd->BeaconOffset[7] = HW_BEACON_BASE7; ++ ++ // ++ // write all shared Ring's base address into ASIC ++ // ++ ++ // asic simulation sequence put this ahead before loading firmware. ++ // pbf hardware reset ++#ifdef RT2860 ++ RTMP_IO_WRITE32(pAd, WPDMA_RST_IDX, 0x1003f); // 0x10000 for reset rx, 0x3f resets all 6 tx rings. ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0xe1f); ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0xe00); ++#endif // RT2860 // ++ ++ // Initialze ASIC for TX & Rx operation ++ if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) ++ { ++ if (j++ == 0) ++ { ++ NICLoadFirmware(pAd); ++ goto retry; ++ } ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++#ifdef RT2860 ++ // Write AC_BK base address register ++ Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_AC_BK].Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, TX_BASE_PTR1, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> TX_BASE_PTR1 : 0x%x\n", Value)); ++ ++ // Write AC_BE base address register ++ Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_AC_BE].Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, TX_BASE_PTR0, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> TX_BASE_PTR0 : 0x%x\n", Value)); ++ ++ // Write AC_VI base address register ++ Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_AC_VI].Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, TX_BASE_PTR2, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> TX_BASE_PTR2 : 0x%x\n", Value)); ++ ++ // Write AC_VO base address register ++ Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_AC_VO].Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, TX_BASE_PTR3, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> TX_BASE_PTR3 : 0x%x\n", Value)); ++ ++ // Write HCCA base address register ++ Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_HCCA].Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, TX_BASE_PTR4, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> TX_BASE_PTR4 : 0x%x\n", Value)); ++ ++ // Write MGMT_BASE_CSR register ++ Value = RTMP_GetPhysicalAddressLow(pAd->MgmtRing.Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, TX_BASE_PTR5, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> TX_BASE_PTR5 : 0x%x\n", Value)); ++ ++ // Write RX_BASE_CSR register ++ Value = RTMP_GetPhysicalAddressLow(pAd->RxRing.Cell[0].AllocPa); ++ RTMP_IO_WRITE32(pAd, RX_BASE_PTR, Value); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RX_BASE_PTR : 0x%x\n", Value)); ++ ++ // Init RX Ring index pointer ++ pAd->RxRing.RxSwReadIdx = 0; ++ pAd->RxRing.RxCpuIdx = RX_RING_SIZE-1; ++ RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); ++ ++ // Init TX rings index pointer ++ { ++ for (i=0; iTxRing[i].TxSwFreeIdx = 0; ++ pAd->TxRing[i].TxCpuIdx = 0; ++ RTMP_IO_WRITE32(pAd, (TX_CTX_IDX0 + i * 0x10) , pAd->TxRing[i].TxCpuIdx); ++ } ++ } ++ ++ // init MGMT ring index pointer ++ pAd->MgmtRing.TxSwFreeIdx = 0; ++ pAd->MgmtRing.TxCpuIdx = 0; ++ RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx); ++ ++ // ++ // set each Ring's SIZE into ASIC. Descriptor Size is fixed by design. ++ // ++ ++ // Write TX_RING_CSR0 register ++ Value = TX_RING_SIZE; ++ RTMP_IO_WRITE32(pAd, TX_MAX_CNT0, Value); ++ RTMP_IO_WRITE32(pAd, TX_MAX_CNT1, Value); ++ RTMP_IO_WRITE32(pAd, TX_MAX_CNT2, Value); ++ RTMP_IO_WRITE32(pAd, TX_MAX_CNT3, Value); ++ RTMP_IO_WRITE32(pAd, TX_MAX_CNT4, Value); ++ Value = MGMT_RING_SIZE; ++ RTMP_IO_WRITE32(pAd, TX_MGMTMAX_CNT, Value); ++ ++ // Write RX_RING_CSR register ++ Value = RX_RING_SIZE; ++ RTMP_IO_WRITE32(pAd, RX_MAX_CNT, Value); ++#endif // RT2860 // ++ ++ ++ // WMM parameter ++ csr0.word = 0; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ csr0.field.Ac0Txop = 192; // AC_VI: 192*32us ~= 6ms ++ csr0.field.Ac1Txop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ csr0.field.Ac0Txop = 96; // AC_VI: 96*32us ~= 3ms ++ csr0.field.Ac1Txop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); ++ ++ ++#ifdef RT2860 ++ // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i < 100); ++ ++ GloCfg.word &= 0xff0; ++ GloCfg.field.EnTXWriteBackDDONE =1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ IntCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, DELAY_INT_CFG, IntCfg.word); ++#endif // RT2860 // ++ ++ ++ // reset action ++ // Load firmware ++ // Status = NICLoadFirmware(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAdapter\n")); ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize ASIC ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICInitializeAsic( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset) ++{ ++ ULONG Index = 0; ++ UCHAR R0 = 0xff; ++ UINT32 MacCsr12 = 0, Counter = 0; ++ USHORT KeyIdx; ++ INT i,apidx; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); ++ ++#ifdef RT2860 ++ if (bHardReset == TRUE) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); ++ } ++ else ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ // Initialize MAC register to default value ++ for (Index = 0; Index < NUM_MAC_REG_PARMS; Index++) ++ { ++ RTMP_IO_WRITE32(pAd, MACRegTable[Index].Register, MACRegTable[Index].Value); ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ for (Index = 0; Index < NUM_STA_MAC_REG_PARMS; Index++) ++ { ++ RTMP_IO_WRITE32(pAd, STAMACRegTable[Index].Register, STAMACRegTable[Index].Value); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2860 // ++ ++ ++ // ++ // Before program BBP, we need to wait BBP/RF get wake up. ++ // ++ Index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_STATUS_CFG, &MacCsr12); ++ ++ if ((MacCsr12 & 0x03) == 0) // if BB.RF is stable ++ break; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Check MAC_STATUS_CFG = Busy = %x\n", MacCsr12)); ++ RTMPusecDelay(1000); ++ } while (Index++ < 100); ++ ++ // The commands to firmware should be after these commands, these commands will init firmware ++ // PCI and USB are not the same because PCI driver needs to wait for PCI bus ready ++ RTMP_IO_WRITE32(pAd, H2M_BBP_AGENT, 0); // initialize BBP R/W access agent ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, 0); ++ RTMPusecDelay(1000); ++ ++ // Read BBP register, make sure BBP is up and running before write new data ++ Index = 0; ++ do ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R0, &R0); ++ DBGPRINT(RT_DEBUG_TRACE, ("BBP version = %x\n", R0)); ++ } while ((++Index < 20) && ((R0 == 0xff) || (R0 == 0x00))); ++ //ASSERT(Index < 20); //this will cause BSOD on Check-build driver ++ ++ if ((R0 == 0xff) || (R0 == 0x00)) ++ return NDIS_STATUS_FAILURE; ++ ++ // Initialize BBP register to default value ++ for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, BBPRegTable[Index].Value); ++ } ++ ++ // for rt2860E and after, init BBP_R84 with 0x19. This is for extension channel overlapping IOT. ++ if ((pAd->MACVersion&0xffff) != 0x0101) ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); ++ ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x12); ++ } ++ ++ if (pAd->MACVersion >= RALINK_2880E_VERSION && pAd->MACVersion < RALINK_3070_VERSION) // 3*3 ++ { ++ // enlarge MAX_LEN_CFG ++ UINT32 csr; ++ RTMP_IO_READ32(pAd, MAX_LEN_CFG, &csr); ++ csr &= 0xFFF; ++ csr |= 0x2000; ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, csr); ++ } ++ ++ ++ // Add radio off control ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set Radio Off\n")); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Clear raw counters ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); ++ ++ // ASIC will keep garbage value after boot ++ // Clear all seared key table when initial ++ // This routine can be ignored in radio-ON/OFF operation. ++ if (bHardReset) ++ { ++ for (KeyIdx = 0; KeyIdx < 4; KeyIdx++) ++ { ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4*KeyIdx, 0); ++ } ++ ++ // Clear all pairwise key table when initial ++ for (KeyIdx = 0; KeyIdx < 256; KeyIdx++) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_WCID_ATTRIBUTE_BASE + (KeyIdx * HW_WCID_ATTRI_SIZE), 1); ++ } ++ } ++ ++ ++ // It isn't necessary to clear this space when not hard reset. ++ if (bHardReset == TRUE) ++ { ++ // clear all on-chip BEACON frame space ++ for (apidx = 0; apidx < HW_BEACON_MAX_COUNT; apidx++) ++ { ++ for (i = 0; i < HW_BEACON_OFFSET>>2; i+=4) ++ RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[apidx] + i, 0x00); ++ } ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // for rt2860E and after, init TXOP_CTRL_CFG with 0x583f. This is for extension channel overlapping IOT. ++ if ((pAd->MACVersion&0xffff) != 0x0101) ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x583f); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAsic\n")); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC Asics ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID NICIssueReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 Value = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICIssueReset\n")); ++ ++ // Disable Rx, register value supposed will remain after reset ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= (0xfffffff3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Issue reset and clear from reset state ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x03); // 2004-09-17 change from 0x01 ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x00); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICIssueReset\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check ASIC registers and find any reason the system might hang ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN NICCheckForHang( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return (FALSE); ++} ++ ++VOID NICUpdateFifoStaCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_STA_FIFO_STRUC StaFifo; ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR i = 0; ++ UCHAR pid = 0, wcid = 0; ++ CHAR reTry; ++ UCHAR succMCS; ++ ++#ifdef RALINK_ATE ++ /* Nothing to do in ATE mode */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ do ++ { ++ RTMP_IO_READ32(pAd, TX_STA_FIFO, &StaFifo.word); ++ ++ if (StaFifo.field.bValid == 0) ++ break; ++ ++ wcid = (UCHAR)StaFifo.field.wcid; ++ ++ ++ /* ignore NoACK and MGMT frame use 0xFF as WCID */ ++ if ((StaFifo.field.TxAckRequired == 0) || (wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ i++; ++ continue; ++ } ++ ++ /* PID store Tx MCS Rate */ ++ pid = (UCHAR)StaFifo.field.PidType; ++ ++ pEntry = &pAd->MacTab.Content[wcid]; ++ ++ pEntry->DebugFIFOCount++; ++ ++#ifdef DOT11_N_SUPPORT ++ if (StaFifo.field.TxBF) // 3*3 ++ pEntry->TxBFCount++; ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef UAPSD_AP_SUPPORT ++ UAPSD_SP_AUE_Handle(pAd, pEntry, StaFifo.field.TxSuccess); ++#endif // UAPSD_AP_SUPPORT // ++ ++ if (!StaFifo.field.TxSuccess) ++ { ++ pEntry->FIFOCount++; ++ pEntry->OneSecTxFailCount++; ++ ++ if (pEntry->FIFOCount >= 1) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("#")); ++#if 0 ++ SendRefreshBAR(pAd, pEntry); ++ pEntry->NoBADataCountDown = 64; ++#else ++#ifdef DOT11_N_SUPPORT ++ pEntry->NoBADataCountDown = 64; ++#endif // DOT11_N_SUPPORT // ++ ++ if(pEntry->PsMode == PWR_ACTIVE) ++ { ++#ifdef DOT11_N_SUPPORT ++ int tid; ++ for (tid=0; tidAid, tid, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Update the continuous transmission counter except PS mode ++ pEntry->ContinueTxFailCnt++; ++ } ++ else ++ { ++ // Clear the FIFOCount when sta in Power Save mode. Basically we assume ++ // this tx error happened due to sta just go to sleep. ++ pEntry->FIFOCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ } ++#endif ++ //pEntry->FIFOCount = 0; ++ } ++ //pEntry->bSendBAR = TRUE; ++ } ++ else ++ { ++#ifdef DOT11_N_SUPPORT ++ if ((pEntry->PsMode != PWR_SAVE) && (pEntry->NoBADataCountDown > 0)) ++ { ++ pEntry->NoBADataCountDown--; ++ if (pEntry->NoBADataCountDown==0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("@\n")); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ pEntry->FIFOCount = 0; ++ pEntry->OneSecTxNoRetryOkCount++; ++ // update NoDataIdleCount when sucessful send packet to STA. ++ pEntry->NoDataIdleCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ } ++ ++ succMCS = StaFifo.field.SuccessRate & 0x7F; ++ ++ reTry = pid - succMCS; ++ ++ if (StaFifo.field.TxSuccess) ++ { ++ pEntry->TXMCSExpected[pid]++; ++ if (pid == succMCS) ++ { ++ pEntry->TXMCSSuccessful[pid]++; ++ } ++ else ++ { ++ pEntry->TXMCSAutoFallBack[pid][succMCS]++; ++ } ++ } ++ else ++ { ++ pEntry->TXMCSFailed[pid]++; ++ } ++ ++ if (reTry > 0) ++ { ++ if ((pid >= 12) && succMCS <=7) ++ { ++ reTry -= 4; ++ } ++ pEntry->OneSecTxRetryOkCount += reTry; ++ } ++ ++ i++; ++ // ASIC store 16 stack ++ } while ( i < (2*TX_RING_SIZE) ); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read statistical counters from hardware registers and record them ++ in software variables for later on query ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID NICUpdateRawCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 OldValue; ++ RX_STA_CNT0_STRUC RxStaCnt0; ++ RX_STA_CNT1_STRUC RxStaCnt1; ++ RX_STA_CNT2_STRUC RxStaCnt2; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT2_STRUC StaTx2; ++ TX_AGG_CNT_STRUC TxAggCnt; ++ TX_AGG_CNT0_STRUC TxAggCnt0; ++ TX_AGG_CNT1_STRUC TxAggCnt1; ++ TX_AGG_CNT2_STRUC TxAggCnt2; ++ TX_AGG_CNT3_STRUC TxAggCnt3; ++ TX_AGG_CNT4_STRUC TxAggCnt4; ++ TX_AGG_CNT5_STRUC TxAggCnt5; ++ TX_AGG_CNT6_STRUC TxAggCnt6; ++ TX_AGG_CNT7_STRUC TxAggCnt7; ++ ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &RxStaCnt0.word); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &RxStaCnt2.word); ++ ++ { ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &RxStaCnt1.word); ++ // Update RX PLCP error counter ++ pAd->PrivateInfo.PhyRxErrCnt += RxStaCnt1.field.PlcpErr; ++ // Update False CCA counter ++ pAd->RalinkCounters.OneSecFalseCCACnt += RxStaCnt1.field.FalseCca; ++ } ++ ++ // Update FCS counters ++ OldValue= pAd->WlanCounters.FCSErrorCount.u.LowPart; ++ pAd->WlanCounters.FCSErrorCount.u.LowPart += (RxStaCnt0.field.CrcErr); // >> 7); ++ if (pAd->WlanCounters.FCSErrorCount.u.LowPart < OldValue) ++ pAd->WlanCounters.FCSErrorCount.u.HighPart++; ++ ++ // Add FCS error count to private counters ++ pAd->RalinkCounters.OneSecRxFcsErrCnt += RxStaCnt0.field.CrcErr; ++ OldValue = pAd->RalinkCounters.RealFcsErrCount.u.LowPart; ++ pAd->RalinkCounters.RealFcsErrCount.u.LowPart += RxStaCnt0.field.CrcErr; ++ if (pAd->RalinkCounters.RealFcsErrCount.u.LowPart < OldValue) ++ pAd->RalinkCounters.RealFcsErrCount.u.HighPart++; ++ ++ // Update Duplicate Rcv check ++ pAd->RalinkCounters.DuplicateRcv += RxStaCnt2.field.RxDupliCount; ++ pAd->WlanCounters.FrameDuplicateCount.u.LowPart += RxStaCnt2.field.RxDupliCount; ++ // Update RX Overflow counter ++ pAd->Counters8023.RxNoBuffer += (RxStaCnt2.field.RxFifoOverflowCount); ++ ++ if (!pAd->bUpdateBcnCntDone) ++ { ++ // Update BEACON sent count ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &StaTx2.word); ++ pAd->RalinkCounters.OneSecBeaconSentCnt += TxStaCnt0.field.TxBeaconCount; ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ } ++ ++ { ++ RTMP_IO_READ32(pAd, TX_AGG_CNT, &TxAggCnt.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT0, &TxAggCnt0.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT1, &TxAggCnt1.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT2, &TxAggCnt2.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT3, &TxAggCnt3.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT4, &TxAggCnt4.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT5, &TxAggCnt5.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT6, &TxAggCnt6.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT7, &TxAggCnt7.word); ++ pAd->RalinkCounters.TxAggCount += TxAggCnt.field.AggTxCount; ++ pAd->RalinkCounters.TxNonAggCount += TxAggCnt.field.NonAggTxCount; ++ pAd->RalinkCounters.TxAgg1MPDUCount += TxAggCnt0.field.AggSize1Count; ++ pAd->RalinkCounters.TxAgg2MPDUCount += TxAggCnt0.field.AggSize2Count; ++ ++ pAd->RalinkCounters.TxAgg3MPDUCount += TxAggCnt1.field.AggSize3Count; ++ pAd->RalinkCounters.TxAgg4MPDUCount += TxAggCnt1.field.AggSize4Count; ++ pAd->RalinkCounters.TxAgg5MPDUCount += TxAggCnt2.field.AggSize5Count; ++ pAd->RalinkCounters.TxAgg6MPDUCount += TxAggCnt2.field.AggSize6Count; ++ ++ pAd->RalinkCounters.TxAgg7MPDUCount += TxAggCnt3.field.AggSize7Count; ++ pAd->RalinkCounters.TxAgg8MPDUCount += TxAggCnt3.field.AggSize8Count; ++ pAd->RalinkCounters.TxAgg9MPDUCount += TxAggCnt4.field.AggSize9Count; ++ pAd->RalinkCounters.TxAgg10MPDUCount += TxAggCnt4.field.AggSize10Count; ++ ++ pAd->RalinkCounters.TxAgg11MPDUCount += TxAggCnt5.field.AggSize11Count; ++ pAd->RalinkCounters.TxAgg12MPDUCount += TxAggCnt5.field.AggSize12Count; ++ pAd->RalinkCounters.TxAgg13MPDUCount += TxAggCnt6.field.AggSize13Count; ++ pAd->RalinkCounters.TxAgg14MPDUCount += TxAggCnt6.field.AggSize14Count; ++ ++ pAd->RalinkCounters.TxAgg15MPDUCount += TxAggCnt7.field.AggSize15Count; ++ pAd->RalinkCounters.TxAgg16MPDUCount += TxAggCnt7.field.AggSize16Count; ++ ++ // Calculate the transmitted A-MPDU count ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += TxAggCnt0.field.AggSize1Count; ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt0.field.AggSize2Count / 2); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize3Count / 3); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize4Count / 4); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize5Count / 5); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize6Count / 6); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize7Count / 7); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize8Count / 8); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize9Count / 9); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize10Count / 10); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize11Count / 11); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize12Count / 12); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize13Count / 13); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize14Count / 14); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize15Count / 15); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize16Count / 16); ++ } ++ ++#ifdef DBG_DIAGNOSE ++ { ++ RtmpDiagStruct *pDiag; ++ COUNTER_RALINK *pRalinkCounters; ++ UCHAR ArrayCurIdx, i; ++ ++ pDiag = &pAd->DiagStruct; ++ pRalinkCounters = &pAd->RalinkCounters; ++ ArrayCurIdx = pDiag->ArrayCurIdx; ++ ++ if (pDiag->inited == 0) ++ { ++ NdisZeroMemory(pDiag, sizeof(struct _RtmpDiagStrcut_)); ++ pDiag->ArrayStartIdx = pDiag->ArrayCurIdx = 0; ++ pDiag->inited = 1; ++ } ++ else ++ { ++ // Tx ++ pDiag->TxFailCnt[ArrayCurIdx] = TxStaCnt0.field.TxFailCount; ++ pDiag->TxAggCnt[ArrayCurIdx] = TxAggCnt.field.AggTxCount; ++ pDiag->TxNonAggCnt[ArrayCurIdx] = TxAggCnt.field.NonAggTxCount; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][0] = TxAggCnt0.field.AggSize1Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][1] = TxAggCnt0.field.AggSize2Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][2] = TxAggCnt1.field.AggSize3Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][3] = TxAggCnt1.field.AggSize4Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][4] = TxAggCnt2.field.AggSize5Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][5] = TxAggCnt2.field.AggSize6Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][6] = TxAggCnt3.field.AggSize7Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][7] = TxAggCnt3.field.AggSize8Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][8] = TxAggCnt4.field.AggSize9Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][9] = TxAggCnt4.field.AggSize10Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][10] = TxAggCnt5.field.AggSize11Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][11] = TxAggCnt5.field.AggSize12Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][12] = TxAggCnt6.field.AggSize13Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][13] = TxAggCnt6.field.AggSize14Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][14] = TxAggCnt7.field.AggSize15Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][15] = TxAggCnt7.field.AggSize16Count; ++ ++ pDiag->RxCrcErrCnt[ArrayCurIdx] = RxStaCnt0.field.CrcErr; ++ ++ INC_RING_INDEX(pDiag->ArrayCurIdx, DIAGNOSE_TIME); ++ ArrayCurIdx = pDiag->ArrayCurIdx; ++ for (i =0; i < 9; i++) ++ { ++ pDiag->TxDescCnt[ArrayCurIdx][i]= 0; ++ pDiag->TxSWQueCnt[ArrayCurIdx][i] =0; ++ pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; ++ pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; ++ } ++ pDiag->TxDataCnt[ArrayCurIdx] = 0; ++ pDiag->TxFailCnt[ArrayCurIdx] = 0; ++ pDiag->RxDataCnt[ArrayCurIdx] = 0; ++ pDiag->RxCrcErrCnt[ArrayCurIdx] = 0; ++ for (i = 9; i < 24; i++) // 3*3 ++ { ++ pDiag->TxDescCnt[ArrayCurIdx][i] = 0; ++ pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; ++ pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; ++} ++ ++ if (pDiag->ArrayCurIdx == pDiag->ArrayStartIdx) ++ INC_RING_INDEX(pDiag->ArrayStartIdx, DIAGNOSE_TIME); ++ } ++ ++ } ++#endif // DBG_DIAGNOSE // ++ ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC from error ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Reset NIC from error state ++ ++ ======================================================================== ++*/ ++VOID NICResetFromError( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Reset BBP (according to alex, reset ASIC will force reset BBP ++ // Therefore, skip the reset BBP ++ // RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x2); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ // Remove ASIC from reset state ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ ++ NICInitializeAdapter(pAd, FALSE); ++ NICInitAsicFromEEPROM(pAd); ++ ++ // Switch to current channel, since during reset process, the connection should remains on. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ erase 8051 firmware image in MAC ASIC ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID NICEraseFirmware( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ ++ for(i=0; i %s\n", __FUNCTION__)); ++ ++ /* init */ ++ pFirmwareImage = NULL; ++ src = RTMP_FIRMWARE_FILE_NAME; ++ ++ /* save uid and gid used for filesystem access. ++ set user and group to 0 (root) */ ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ ++ FIRMWARE_MINOR_VERSION; ++ ++ ++ /* allocate firmware buffer */ ++ pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); ++ if (pFirmwareImage == NULL) ++ { ++ /* allocate fail, use default firmware array in firmware.h */ ++ printk("%s - Allocate memory fail!\n", __FUNCTION__); ++ NICLF_DEFAULT_USE(); ++ } ++ else ++ { ++ /* allocate ok! zero the firmware buffer */ ++ memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); ++ } /* End of if */ ++ ++ ++ /* if ok, read firmware file from *.bin file */ ++ if (flg_default_firm_use == FALSE) ++ { ++ do ++ { ++ /* open the bin file */ ++ srcf = filp_open(src, O_RDONLY, 0); ++ ++ if (IS_ERR(srcf)) ++ { ++ printk("%s - Error %ld opening %s\n", ++ __FUNCTION__, -PTR_ERR(srcf), src); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ ++ /* the object must have a read method */ ++ if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) ++ { ++ printk("%s - %s does not have a write method\n", __FUNCTION__, src); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ ++ /* read the firmware from the file *.bin */ ++ FileLength = srcf->f_op->read(srcf, ++ pFirmwareImage, ++ MAX_FIRMWARE_IMAGE_SIZE, ++ &srcf->f_pos); ++ ++ if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) ++ { ++ printk("%s: error file length (=%d) in RT2860AP.BIN\n", ++ __FUNCTION__, FileLength); ++ NICLF_DEFAULT_USE(); ++ break; ++ } ++ else ++ { ++ PUCHAR ptr = pFirmwareImage; ++ USHORT crc = 0xffff; ++ ++ ++ /* calculate firmware CRC */ ++ for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) ++ crc = ByteCRC16(BitReverse(*ptr), crc); ++ /* End of for */ ++ ++ if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ ++ (UCHAR)BitReverse((UCHAR)(crc>>8))) || ++ (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ ++ (UCHAR)BitReverse((UCHAR)crc))) ++ { ++ /* CRC fail */ ++ printk("%s: CRC = 0x%02x 0x%02x " ++ "error, should be 0x%02x 0x%02x\n", ++ __FUNCTION__, ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], ++ (UCHAR)(crc>>8), (UCHAR)(crc)); ++ NICLF_DEFAULT_USE(); ++ break; ++ } ++ else ++ { ++ /* firmware is ok */ ++ pAd->FirmwareVersion = \ ++ (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; ++ ++ /* check if firmware version of the file is too old */ ++ if ((pAd->FirmwareVersion) < \ ++ ((FIRMWARE_MAJOR_VERSION << 8) + ++ FIRMWARE_MINOR_VERSION)) ++ { ++ printk("%s: firmware version too old!\n", __FUNCTION__); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ } /* End of if */ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("NICLoadFirmware: CRC ok, ver=%d.%d\n", ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); ++ } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ ++ break; ++ } while(TRUE); ++ ++ /* close firmware file */ ++ if (IS_ERR(srcf)) ++ ; ++ else ++ { ++ retval = filp_close(srcf, NULL); ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("--> Error %d closing %s\n", -retval, src)); ++ } /* End of if */ ++ } /* End of if */ ++ } /* End of if */ ++ ++ ++ /* write firmware to ASIC */ ++ if (flg_default_firm_use == TRUE) ++ { ++ /* use default fimeware, free allocated buffer */ ++ if (pFirmwareImage != NULL) ++ kfree(pFirmwareImage); ++ /* End of if */ ++ ++ /* use default *.bin array */ ++ pFirmwareImage = FirmwareImage; ++ FileLength = sizeof(FirmwareImage); ++ } /* End of if */ ++ ++ /* enable Host program ram write selection */ ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); ++ ++ for(i=0; ifsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++#else ++ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ PUCHAR pFirmwareImage; ++ ULONG FileLength, Index; ++ //ULONG firm; ++ UINT32 MacReg = 0; ++ ++ pFirmwareImage = FirmwareImage; ++ FileLength = sizeof(FirmwareImage); ++ RT28XX_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); ++#endif ++ ++ /* check if MCU is ready */ ++ Index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacReg); ++ ++ if (MacReg & 0x80) ++ break; ++ ++ RTMPusecDelay(1000); ++ } while (Index++ < 1000); ++ ++ if (Index >= 1000) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); ++ } /* End of if */ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("<=== %s (status=%d)\n", __FUNCTION__, Status)); ++ return Status; ++} /* End of NICLoadFirmware */ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Load Tx rate switching parameters ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS firmware image load ok ++ NDIS_STATUS_FAILURE image not found ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Rate Table Format: ++ 1. (B0: Valid Item number) (B1:Initial item from zero) ++ 2. Item Number(Dec) Mode(Hex) Current MCS(Dec) TrainUp(Dec) TrainDown(Dec) ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICLoadRateSwitchingParams( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ if pSrc1 all zero with length Length, return 0. ++ If not all zero, return 1 ++ ++ Arguments: ++ pSrc1 ++ ++ Return Value: ++ 1: not all zero ++ 0: all zero ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPNotAllZero( ++ IN PVOID pSrc1, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ ULONG Index = 0; ++ ++ pMem1 = (PUCHAR) pSrc1; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ if (pMem1[Index] != 0x0) ++ { ++ break; ++ } ++ } ++ ++ if (Index == Length) ++ { ++ return (0); ++ } ++ else ++ { ++ return (1); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare two memory block ++ ++ Arguments: ++ pSrc1 Pointer to first memory address ++ pSrc2 Pointer to second memory address ++ ++ Return Value: ++ 0: memory is equal ++ 1: pSrc1 memory is larger ++ 2: pSrc2 memory is larger ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPCompareMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ PUCHAR pMem2; ++ ULONG Index = 0; ++ ++ pMem1 = (PUCHAR) pSrc1; ++ pMem2 = (PUCHAR) pSrc2; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ if (pMem1[Index] > pMem2[Index]) ++ return (1); ++ else if (pMem1[Index] < pMem2[Index]) ++ return (2); ++ } ++ ++ // Equal ++ return (0); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Zero out memory block ++ ++ Arguments: ++ pSrc1 Pointer to memory address ++ Length Size ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPZeroMemory( ++ IN PVOID pSrc, ++ IN ULONG Length) ++{ ++ PUCHAR pMem; ++ ULONG Index = 0; ++ ++ pMem = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem[Index] = 0x00; ++ } ++} ++ ++VOID RTMPFillMemory( ++ IN PVOID pSrc, ++ IN ULONG Length, ++ IN UCHAR Fill) ++{ ++ PUCHAR pMem; ++ ULONG Index = 0; ++ ++ pMem = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem[Index] = Fill; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy data from memory block 1 to memory block 2 ++ ++ Arguments: ++ pDest Pointer to destination memory address ++ pSrc Pointer to source memory address ++ Length Copy size ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPMoveMemory( ++ OUT PVOID pDest, ++ IN PVOID pSrc, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ PUCHAR pMem2; ++ UINT Index; ++ ++ ASSERT((Length==0) || (pDest && pSrc)); ++ ++ pMem1 = (PUCHAR) pDest; ++ pMem2 = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem1[Index] = pMem2[Index]; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize port configuration structure ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID UserCfgInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT key_index, bss_index; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit\n")); ++ ++ // ++ // part I. intialize common configuration ++ // ++ ++ for(key_index=0; key_indexSharedKey[bss_index][key_index].KeyLen = 0; ++ pAd->SharedKey[bss_index][key_index].CipherAlg = CIPHER_NONE; ++ } ++ } ++ ++ pAd->Antenna.word = 0; ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ ++ pAd->LedCntl.word = 0; ++#ifdef RT2860 ++ pAd->LedIndicatorStregth = 0; ++ pAd->RLnkCtrlOffset = 0; ++ pAd->HostLnkCtrlOffset = 0; ++#endif // RT2860 // ++ ++ pAd->bAutoTxAgcA = FALSE; // Default is OFF ++ pAd->bAutoTxAgcG = FALSE; // Default is OFF ++ pAd->RfIcType = RFIC_2820; ++ ++ // Init timer for reset complete event ++ pAd->CommonCfg.CentralChannel = 1; ++ pAd->bForcePrintTX = FALSE; ++ pAd->bForcePrintRX = FALSE; ++ pAd->bStaFifoTest = FALSE; ++ pAd->bProtectionTest = FALSE; ++ pAd->bHCCATest = FALSE; ++ pAd->bGenOneHCCA = FALSE; ++ pAd->CommonCfg.Dsifs = 10; // in units of usec ++ pAd->CommonCfg.TxPower = 100; //mW ++ pAd->CommonCfg.TxPowerPercentage = 0xffffffff; // AUTO ++ pAd->CommonCfg.TxPowerDefault = 0xffffffff; // AUTO ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleAuto; // use Long preamble on TX by defaut ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ pAd->CommonCfg.RtsThreshold = 2347; ++ pAd->CommonCfg.FragmentThreshold = 2346; ++ pAd->CommonCfg.UseBGProtection = 0; // 0: AUTO ++ pAd->CommonCfg.bEnableTxBurst = TRUE; //0; ++ pAd->CommonCfg.PhyMode = 0xff; // unknown ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++ pAd->CommonCfg.RadarDetect.CSPeriod = 10; ++ pAd->CommonCfg.RadarDetect.CSCount = 0; ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ pAd->CommonCfg.RadarDetect.ChMovingTime = 65; ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh = 3; ++ pAd->CommonCfg.bAPSDCapable = FALSE; ++ pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; ++ pAd->CommonCfg.TriggerTimerCount = 0; ++ pAd->CommonCfg.bAPSDForcePowerSave = FALSE; ++ pAd->CommonCfg.bCountryFlag = FALSE; ++ pAd->CommonCfg.TxStream = 0; ++ pAd->CommonCfg.RxStream = 0; ++ ++ NdisZeroMemory(&pAd->BeaconTxWI, sizeof(pAd->BeaconTxWI)); ++ ++#ifdef DOT11_N_SUPPORT ++ NdisZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); ++ pAd->HTCEnable = FALSE; ++ pAd->bBroadComHT = FALSE; ++ pAd->CommonCfg.bRdg = FALSE; ++ ++#ifdef DOT11N_DRAFT3 ++ pAd->CommonCfg.Dot11OBssScanPassiveDwell = dot11OBSSScanPassiveDwell; // Unit : TU. 5~1000 ++ pAd->CommonCfg.Dot11OBssScanActiveDwell = dot11OBSSScanActiveDwell; // Unit : TU. 10~1000 ++ pAd->CommonCfg.Dot11BssWidthTriggerScanInt = dot11BSSWidthTriggerScanInterval; // Unit : Second ++ pAd->CommonCfg.Dot11OBssScanPassiveTotalPerChannel = dot11OBSSScanPassiveTotalPerChannel; // Unit : TU. 200~10000 ++ pAd->CommonCfg.Dot11OBssScanActiveTotalPerChannel = dot11OBSSScanActiveTotalPerChannel; // Unit : TU. 20~10000 ++ pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor = dot11BSSWidthChannelTransactionDelayFactor; ++ pAd->CommonCfg.Dot11OBssScanActivityThre = dot11BSSScanActivityThreshold; // Unit : percentage ++ pAd->CommonCfg.Dot11BssWidthChanTranDelay = (pAd->CommonCfg.Dot11BssWidthTriggerScanInt * pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor); ++#endif // DOT11N_DRAFT3 // ++ ++ NdisZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ pAd->CommonCfg.BACapability.field.MpduDensity = 0; ++ pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; //32; ++ pAd->CommonCfg.BACapability.field.TxBAWinLimit = 64; //32; ++ DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit. BACapability = 0x%x\n", pAd->CommonCfg.BACapability.word)); ++ ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ BATableInit(pAd, &pAd->BATable); ++ ++ pAd->CommonCfg.bExtChannelSwitchAnnouncement = 1; ++ pAd->CommonCfg.bHTProtect = 1; ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ pAd->CommonCfg.bBADecline = FALSE; ++ pAd->CommonCfg.bDisableReordering = FALSE; ++ ++ pAd->CommonCfg.TxBASize = 7; ++ ++ pAd->CommonCfg.REGBACapability.word = pAd->CommonCfg.BACapability.word; ++#endif // DOT11_N_SUPPORT // ++ ++ //pAd->CommonCfg.HTPhyMode.field.BW = BW_20; ++ //pAd->CommonCfg.HTPhyMode.field.MCS = MCS_AUTO; ++ //pAd->CommonCfg.HTPhyMode.field.ShortGI = GI_800; ++ //pAd->CommonCfg.HTPhyMode.field.STBC = STBC_NONE; ++ pAd->CommonCfg.TxRate = RATE_6; ++ ++ pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.BW = BW_20; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ ++ pAd->CommonCfg.BeaconPeriod = 100; // in mSec ++ ++ // ++ // part II. intialize STA specific configuration ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_DIRECT); ++ RX_FILTER_CLEAR_FLAG(pAd, fRX_FILTER_ACCEPT_MULTICAST); ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_BROADCAST); ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_ALL_MULTICAST); ++ ++ pAd->StaCfg.Psm = PWR_ACTIVE; ++ ++ pAd->StaCfg.OrigWepStatus = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.PairCipher = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.GroupCipher = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.bMixCipher = FALSE; ++ pAd->StaCfg.DefaultKeyId = 0; ++ ++ // 802.1x port control ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.LastMicErrorTime = 0; ++ pAd->StaCfg.MicErrCnt = 0; ++ pAd->StaCfg.bBlockAssoc = FALSE; ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ ++ pAd->CommonCfg.NdisRadioStateOff = FALSE; // New to support microsoft disable radio with OID command ++ ++ pAd->StaCfg.RssiTrigger = 0; ++ NdisZeroMemory(&pAd->StaCfg.RssiSample, sizeof(RSSI_SAMPLE)); ++ pAd->StaCfg.RssiTriggerMode = RSSI_TRIGGERED_UPON_BELOW_THRESHOLD; ++ pAd->StaCfg.AtimWin = 0; ++ pAd->StaCfg.DefaultListenCount = 3;//default listen count; ++ pAd->StaCfg.BssType = BSS_INFRA; // BSS_INFRA or BSS_ADHOC or BSS_MONITOR ++ pAd->StaCfg.bScanReqIsFromWebUI = FALSE; ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); ++ ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ } ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ pAd->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ ++ // global variables mXXXX used in MAC protocol state machines ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ ++ // PHY specification ++ pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; // default PHY mode ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); // CCK use LONG preamble ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // user desired power mode ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.bWindowsACCAMEnable = FALSE; ++ ++#ifdef LEAP_SUPPORT ++ // CCX v1.0 releated init value ++ RTMPInitTimer(pAd, &pAd->StaCfg.LeapAuthTimer, GET_TIMER_FUNCTION(LeapAuthTimeout), pAd, FALSE); ++ pAd->StaCfg.LeapAuthMode = CISCO_AuthModeLEAPNone; ++ pAd->StaCfg.bCkipOn = FALSE; ++#endif // LEAP_SUPPORT // ++ ++ RTMPInitTimer(pAd, &pAd->StaCfg.StaQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(StaQuickResponeForRateUpExec), pAd, FALSE); ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; ++ ++ // Patch for Ndtest ++ pAd->StaCfg.ScanCnt = 0; ++ ++ // CCX 2.0 control flag init ++ pAd->StaCfg.CCXEnable = FALSE; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; ++ pAd->StaCfg.CCXQosECWMin = 4; ++ pAd->StaCfg.CCXQosECWMax = 10; ++ ++ pAd->StaCfg.bHwRadio = TRUE; // Default Hardware Radio status is On ++ pAd->StaCfg.bSwRadio = TRUE; // Default Software Radio status is On ++ pAd->StaCfg.bRadio = TRUE; // bHwRadio && bSwRadio ++ pAd->StaCfg.bHardwareRadio = FALSE; // Default is OFF ++ pAd->StaCfg.bShowHiddenSSID = FALSE; // Default no show ++ ++ // Nitro mode control ++ pAd->StaCfg.bAutoReconnect = TRUE; ++ ++ // Save the init time as last scan time, the system should do scan after 2 seconds. ++ // This patch is for driver wake up from standby mode, system will do scan right away. ++ pAd->StaCfg.LastScanTime = 0; ++ NdisZeroMemory(pAd->nickname, IW_ESSID_MAX_SIZE+1); ++ sprintf(pAd->nickname, "%s", STA_NIC_DEVICE_NAME); ++ RTMPInitTimer(pAd, &pAd->StaCfg.WpaDisassocAndBlockAssocTimer, GET_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc), pAd, FALSE); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAd->StaCfg.IEEE8021X = FALSE; ++ pAd->StaCfg.IEEE8021x_required_keys = FALSE; ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Default for extra information is not valid ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ ++ // Default Config change flag ++ pAd->bConfigChanged = FALSE; ++ ++ // ++ // part III. AP configurations ++ // ++ ++ ++ // ++ // part IV. others ++ // ++ // dynamic BBP R66:sensibity tuning to overcome background noise ++ pAd->BbpTuning.bEnable = TRUE; ++ pAd->BbpTuning.FalseCcaLowerThreshold = 100; ++ pAd->BbpTuning.FalseCcaUpperThreshold = 512; ++ pAd->BbpTuning.R66Delta = 4; ++ pAd->Mlme.bEnableAutoAntennaCheck = TRUE; ++ ++ // ++ // Also initial R66CurrentValue, RTUSBResumeMsduTransmission might use this value. ++ // if not initial this value, the default value will be 0. ++ // ++ pAd->BbpTuning.R66CurrentValue = 0x38; ++ ++ pAd->Bbp94 = BBPR94_DEFAULT; ++ pAd->BbpForCCK = FALSE; ++ ++ // initialize MAC table and allocate spin lock ++ NdisZeroMemory(&pAd->MacTab, sizeof(MAC_TABLE)); ++ InitializeQueueHeader(&pAd->MacTab.McastPsQueue); ++ NdisAllocateSpinLock(&pAd->MacTabLock); ++ ++#ifdef RALINK_ATE ++ NdisZeroMemory(&pAd->ate, sizeof(ATE_INFO)); ++ pAd->ate.Mode = ATE_STOP; ++ pAd->ate.TxCount = 200;/* to exceed TX_RING_SIZE ... */ ++ pAd->ate.TxLength = 1024; ++ pAd->ate.TxWI.ShortGI = 0;// LONG GI : 800 ns ++ pAd->ate.TxWI.PHYMODE = MODE_CCK; ++ pAd->ate.TxWI.MCS = 3; ++ pAd->ate.TxWI.BW = BW_20; ++ pAd->ate.Channel = 1; ++ pAd->ate.QID = QID_AC_BE; ++ pAd->ate.Addr1[0] = 0x00; ++ pAd->ate.Addr1[1] = 0x11; ++ pAd->ate.Addr1[2] = 0x22; ++ pAd->ate.Addr1[3] = 0xAA; ++ pAd->ate.Addr1[4] = 0xBB; ++ pAd->ate.Addr1[5] = 0xCC; ++ NdisMoveMemory(pAd->ate.Addr2, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ NdisMoveMemory(pAd->ate.Addr3, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ pAd->ate.bRxFer = 0; ++ pAd->ate.bQATxStart = FALSE; ++ pAd->ate.bQARxStart = FALSE; ++#ifdef RT2860 ++ pAd->ate.bFWLoading = FALSE; ++#endif // RT2860 // ++#ifdef RALINK_28xx_QA ++ //pAd->ate.Repeat = 0; ++ pAd->ate.TxStatus = 0; ++ pAd->ate.AtePid = THREAD_PID_INIT_VALUE; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++ ++ pAd->CommonCfg.bWiFiTest = FALSE; ++#ifdef RT2860 ++ pAd->bPCIclkOff = FALSE; ++#endif // RT2860 // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); ++} ++ ++// IRQL = PASSIVE_LEVEL ++UCHAR BtoH(char ch) ++{ ++ if (ch >= '0' && ch <= '9') return (ch - '0'); // Handle numerals ++ if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA); // Handle capitol hex digits ++ if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA); // Handle small hex digits ++ return(255); ++} ++ ++// ++// FUNCTION: AtoH(char *, UCHAR *, int) ++// ++// PURPOSE: Converts ascii string to network order hex ++// ++// PARAMETERS: ++// src - pointer to input ascii string ++// dest - pointer to output hex ++// destlen - size of dest ++// ++// COMMENTS: ++// ++// 2 ascii bytes make a hex byte so must put 1st ascii byte of pair ++// into upper nibble and 2nd ascii byte of pair into lower nibble. ++// ++// IRQL = PASSIVE_LEVEL ++ ++void AtoH(char * src, UCHAR * dest, int destlen) ++{ ++ char * srcptr; ++ PUCHAR destTemp; ++ ++ srcptr = src; ++ destTemp = (PUCHAR) dest; ++ ++ while(destlen--) ++ { ++ *destTemp = BtoH(*srcptr++) << 4; // Put 1st ascii byte in upper nibble. ++ *destTemp += BtoH(*srcptr++); // Add 2nd ascii byte to above. ++ destTemp++; ++ } ++} ++ ++VOID RTMPPatchMacBbpBug( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG Index; ++ ++ // Initialize BBP register to default value ++ for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, (UCHAR)BBPRegTable[Index].Value); ++ } ++ ++ // Initialize RF register to default value ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // Re-init BBP register from EEPROM value ++ NICInitAsicFromEEPROM(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTimer Timer structure ++ pTimerFunc Function to execute when timer expired ++ Repeat Ture for period timer ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitTimer( ++ IN PRTMP_ADAPTER pAd, ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN PVOID pTimerFunc, ++ IN PVOID pData, ++ IN BOOLEAN Repeat) ++{ ++ // ++ // Set Valid to TRUE for later used. ++ // It will crash if we cancel a timer or set a timer ++ // that we haven't initialize before. ++ // ++ pTimer->Valid = TRUE; ++ ++ pTimer->PeriodicType = Repeat; ++ pTimer->State = FALSE; ++ pTimer->cookie = (ULONG) pData; ++ ++ ++ RTMP_OS_Init_Timer(pAd, &pTimer->TimerObj, pTimerFunc, (PVOID) pTimer); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pTimer Timer structure ++ Value Timer value in milliseconds ++ ++ Return Value: ++ None ++ ++ Note: ++ To use this routine, must call RTMPInitTimer before. ++ ++ ======================================================================== ++*/ ++VOID RTMPSetTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value) ++{ ++ if (pTimer->Valid) ++ { ++ pTimer->TimerValue = Value; ++ pTimer->State = FALSE; ++ if (pTimer->PeriodicType == TRUE) ++ { ++ pTimer->Repeat = TRUE; ++ RTMP_SetPeriodicTimer(&pTimer->TimerObj, Value); ++ } ++ else ++ { ++ pTimer->Repeat = FALSE; ++ RTMP_OS_Add_Timer(&pTimer->TimerObj, Value); ++ } ++ } ++ else ++ { ++ DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pTimer Timer structure ++ Value Timer value in milliseconds ++ ++ Return Value: ++ None ++ ++ Note: ++ To use this routine, must call RTMPInitTimer before. ++ ++ ======================================================================== ++*/ ++VOID RTMPModTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value) ++{ ++ BOOLEAN Cancel; ++ ++ if (pTimer->Valid) ++ { ++ pTimer->TimerValue = Value; ++ pTimer->State = FALSE; ++ if (pTimer->PeriodicType == TRUE) ++ { ++ RTMPCancelTimer(pTimer, &Cancel); ++ RTMPSetTimer(pTimer, Value); ++ } ++ else ++ { ++ RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value); ++ } ++ } ++ else ++ { ++ DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Cancel timer objects ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ 1.) To use this routine, must call RTMPInitTimer before. ++ 2.) Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID RTMPCancelTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ OUT BOOLEAN *pCancelled) ++{ ++ if (pTimer->Valid) ++ { ++ if (pTimer->State == FALSE) ++ pTimer->Repeat = FALSE; ++ RTMP_OS_Del_Timer(&pTimer->TimerObj, pCancelled); ++ ++ if (*pCancelled == TRUE) ++ pTimer->State = TRUE; ++ ++ } ++ else ++ { ++ // ++ // NdisMCancelTimer just canced the timer and not mean release the timer. ++ // And don't set the "Valid" to False. So that we can use this timer again. ++ // ++ DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set LED Status ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Status LED Status ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSetLED( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Status) ++{ ++ //ULONG data; ++ UCHAR HighByte = 0; ++ UCHAR LowByte; ++ ++// In ATE mode of RT2860 AP/STA, we have erased 8051 firmware. ++// So LED mode is not supported when ATE is running. ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ LowByte = pAd->LedCntl.field.LedMode&0x7f; ++ switch (Status) ++ { ++ case LED_LINK_DOWN: ++ HighByte = 0x20; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ pAd->LedIndicatorStregth = 0; ++ break; ++ case LED_LINK_UP: ++ if (pAd->CommonCfg.Channel > 14) ++ HighByte = 0xa0; ++ else ++ HighByte = 0x60; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_RADIO_ON: ++ HighByte = 0x20; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_HALT: ++ LowByte = 0; // Driver sets MAC register and MAC controls LED ++ case LED_RADIO_OFF: ++ HighByte = 0; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_WPS: ++ HighByte = 0x10; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_ON_SITE_SURVEY: ++ HighByte = 0x08; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_POWER_UP: ++ HighByte = 0x04; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetLED::Unknown Status %d\n", Status)); ++ break; ++ } ++ ++ // ++ // Keep LED status for LED SiteSurvey mode. ++ // After SiteSurvey, we will set the LED mode to previous status. ++ // ++ if ((Status != LED_ON_SITE_SURVEY) && (Status != LED_POWER_UP)) ++ pAd->LedStatus = Status; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetLED::Mode=%d,HighByte=0x%02x,LowByte=0x%02x\n", pAd->LedCntl.field.LedMode, HighByte, LowByte)); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set LED Signal Stregth ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Dbm Signal Stregth ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Can be run on any IRQL level. ++ ++ According to Microsoft Zero Config Wireless Signal Stregth definition as belows. ++ <= -90 No Signal ++ <= -81 Very Low ++ <= -71 Low ++ <= -67 Good ++ <= -57 Very Good ++ > -57 Excellent ++ ======================================================================== ++*/ ++VOID RTMPSetSignalLED( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_802_11_RSSI Dbm) ++{ ++ UCHAR nLed = 0; ++ ++ // ++ // if not Signal Stregth, then do nothing. ++ // ++ if (pAd->LedCntl.field.LedMode != LED_MODE_SIGNAL_STREGTH) ++ { ++ return; ++ } ++ ++ if (Dbm <= -90) ++ nLed = 0; ++ else if (Dbm <= -81) ++ nLed = 1; ++ else if (Dbm <= -71) ++ nLed = 3; ++ else if (Dbm <= -67) ++ nLed = 7; ++ else if (Dbm <= -57) ++ nLed = 15; ++ else ++ nLed = 31; ++ ++ // ++ // Update Signal Stregth to firmware if changed. ++ // ++ if (pAd->LedIndicatorStregth != nLed) ++ { ++ AsicSendCommandToMcu(pAd, 0x51, 0xff, nLed, pAd->LedCntl.field.Polarity); ++ pAd->LedIndicatorStregth = nLed; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Enable RX ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL <= DISPATCH_LEVEL ++ ++ Note: ++ Before Enable RX, make sure you have enabled Interrupt. ++ ======================================================================== ++*/ ++VOID RTMPEnableRxTx( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPEnableRxTx\n")); ++ ++ // Enable Rx DMA. ++ RT28XXDMAEnable(pAd); ++ ++ // enable RX of MAC block ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ UINT32 rx_filter_flag = APNORMAL; ++ ++ ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, rx_filter_flag); // enable RX of DMA block ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ } ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPEnableRxTx\n")); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/rtmp_tkip.c +@@ -0,0 +1,1607 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_tkip.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Wu 02-25-02 Initial ++*/ ++ ++#include "../rt_config.h" ++ ++// Rotation functions on 32 bit values ++#define ROL32( A, n ) \ ++ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) ++#define ROR32( A, n ) ROL32( (A), 32-(n) ) ++ ++UINT Tkip_Sbox_Lower[256] = ++{ ++ 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, ++ 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, ++ 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, ++ 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, ++ 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, ++ 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, ++ 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, ++ 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, ++ 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, ++ 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, ++ 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, ++ 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, ++ 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, ++ 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, ++ 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, ++ 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, ++ 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, ++ 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, ++ 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, ++ 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, ++ 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, ++ 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, ++ 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, ++ 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, ++ 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, ++ 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, ++ 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, ++ 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, ++ 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, ++ 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, ++ 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, ++ 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A ++}; ++ ++UINT Tkip_Sbox_Upper[256] = ++{ ++ 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, ++ 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, ++ 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, ++ 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, ++ 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, ++ 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, ++ 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, ++ 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, ++ 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, ++ 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, ++ 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, ++ 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, ++ 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, ++ 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, ++ 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, ++ 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, ++ 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, ++ 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, ++ 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, ++ 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, ++ 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, ++ 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, ++ 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, ++ 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, ++ 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, ++ 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, ++ 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, ++ 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, ++ 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, ++ 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, ++ 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, ++ 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C ++}; ++ ++/*****************************/ ++/******** SBOX Table *********/ ++/*****************************/ ++ ++UCHAR SboxTable[256] = ++{ ++ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, ++ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, ++ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, ++ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, ++ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, ++ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, ++ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, ++ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, ++ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, ++ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, ++ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, ++ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, ++ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, ++ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, ++ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, ++ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, ++ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, ++ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, ++ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, ++ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, ++ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, ++ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, ++ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, ++ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, ++ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, ++ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, ++ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, ++ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, ++ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, ++ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, ++ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, ++ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++}; ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round); ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a); ++// ++// Expanded IV for TKIP function. ++// ++typedef struct PACKED _IV_CONTROL_ ++{ ++ union PACKED ++ { ++ struct PACKED ++ { ++ UCHAR rc0; ++ UCHAR rc1; ++ UCHAR rc2; ++ ++ union PACKED ++ { ++ struct PACKED ++ { ++#ifdef RT_BIG_ENDIAN ++ UCHAR KeyID:2; ++ UCHAR ExtIV:1; ++ UCHAR Rsvd:5; ++#else ++ UCHAR Rsvd:5; ++ UCHAR ExtIV:1; ++ UCHAR KeyID:2; ++#endif ++ } field; ++ UCHAR Byte; ++ } CONTROL; ++ } field; ++ ++ ULONG word; ++ } IV16; ++ ++ ULONG IV32; ++} TKIP_IV, *PTKIP_IV; ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Convert from UCHAR[] to ULONG in a portable way ++ ++ Arguments: ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPTkipGetUInt32( ++ IN PUCHAR pMICKey) ++{ ++ ULONG res = 0; ++ INT i; ++ ++ for (i = 0; i < 4; i++) ++ { ++ res |= (*pMICKey++) << (8 * i); ++ } ++ ++ return res; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Convert from ULONG to UCHAR[] in a portable way ++ ++ Arguments: ++ pDst pointer to destination for convert ULONG to UCHAR[] ++ val the value for convert ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipPutUInt32( ++ IN OUT PUCHAR pDst, ++ IN ULONG val) ++{ ++ INT i; ++ ++ for(i = 0; i < 4; i++) ++ { ++ *pDst++ = (UCHAR) (val & 0xff); ++ val >>= 8; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set the MIC Key. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipSetMICKey( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pMICKey) ++{ ++ // Set the key ++ pTkip->K0 = RTMPTkipGetUInt32(pMICKey); ++ pTkip->K1 = RTMPTkipGetUInt32(pMICKey + 4); ++ // and reset the message ++ pTkip->L = pTkip->K0; ++ pTkip->R = pTkip->K1; ++ pTkip->nBytesInM = 0; ++ pTkip->M = 0; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ uChar Append this uChar ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipAppendByte( ++ IN PTKIP_KEY_INFO pTkip, ++ IN UCHAR uChar) ++{ ++ // Append the byte to our word-sized buffer ++ pTkip->M |= (uChar << (8* pTkip->nBytesInM)); ++ pTkip->nBytesInM++; ++ // Process the word if it is full. ++ if( pTkip->nBytesInM >= 4 ) ++ { ++ pTkip->L ^= pTkip->M; ++ pTkip->R ^= ROL32( pTkip->L, 17 ); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ((pTkip->L & 0xff00ff00) >> 8) | ((pTkip->L & 0x00ff00ff) << 8); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ROL32( pTkip->L, 3 ); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ROR32( pTkip->L, 2 ); ++ pTkip->L += pTkip->R; ++ // Clear the buffer ++ pTkip->M = 0; ++ pTkip->nBytesInM = 0; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to source data for Calculate MIC Value ++ Len Indicate the length of the source data ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipAppend( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pSrc, ++ IN UINT nBytes) ++{ ++ // This is simple ++ while(nBytes > 0) ++ { ++ RTMPTkipAppendByte(pTkip, *pSrc++); ++ nBytes--; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ the MIC Value is store in pAd->PrivateInfo.MIC ++ ======================================================================== ++*/ ++VOID RTMPTkipGetMIC( ++ IN PTKIP_KEY_INFO pTkip) ++{ ++ // Append the minimum padding ++ RTMPTkipAppendByte(pTkip, 0x5a ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ // and then zeroes until the length is a multiple of 4 ++ while( pTkip->nBytesInM != 0 ) ++ { ++ RTMPTkipAppendByte(pTkip, 0 ); ++ } ++ // The appendByte function has already computed the result. ++ RTMPTkipPutUInt32(pTkip->MIC, pTkip->L); ++ RTMPTkipPutUInt32(pTkip->MIC + 4, pTkip->R); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init Tkip function. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. ++ KeyId TK Key ID ++ pTA Pointer to transmitter address ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitTkipEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN PUCHAR pTA, ++ IN PUCHAR pMICKey, ++ IN PUCHAR pTSC, ++ OUT PULONG pIV16, ++ OUT PULONG pIV32) ++{ ++ TKIP_IV tkipIv; ++ ++ // Prepare 8 bytes TKIP encapsulation for MPDU ++ NdisZeroMemory(&tkipIv, sizeof(TKIP_IV)); ++ tkipIv.IV16.field.rc0 = *(pTSC + 1); ++ tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; ++ tkipIv.IV16.field.rc2 = *pTSC; ++ tkipIv.IV16.field.CONTROL.field.ExtIV = 1; // 0: non-extended IV, 1: an extended IV ++ tkipIv.IV16.field.CONTROL.field.KeyID = KeyId; ++ NdisMoveMemory(&tkipIv.IV32, (pTSC + 2), 4); // Copy IV ++ ++ *pIV16 = tkipIv.IV16.word; ++ *pIV32 = tkipIv.IV32; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init MIC Value calculation function which include set MIC key & ++ calculate first 16 bytes (DA + SA + priority + 0) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitMICEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN UCHAR UserPriority, ++ IN PUCHAR pMICKey) ++{ ++ ULONG Priority = UserPriority; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Tx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, (PUCHAR)&Priority, 4); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare MIC value of received MSDU ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to the received Plain text data ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ Len the length of the received plain text data exclude MIC value ++ ++ Return Value: ++ TRUE MIC value matched ++ FALSE MIC value mismatched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPTkipCompareMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UCHAR UserPriority, ++ IN UINT Len) ++{ ++ UCHAR OldMic[8]; ++ ULONG Priority = UserPriority; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); ++ ++ // Calculate MIC value from plain text data ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); ++ ++ // Get MIC valude from received frame ++ NdisMoveMemory(OldMic, pSrc + Len, 8); ++ ++ // Get MIC value from decrypted plain data ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); ++ ++ // Move MIC value from MSDU, this steps should move to data path. ++ // Since the MIC value might cross MPDUs. ++ if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValue(): TKIP MIC Error !\n")); //MIC error. ++ ++ ++ return (FALSE); ++ } ++ return (TRUE); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare MIC value of received MSDU ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pLLC LLC header ++ pSrc Pointer to the received Plain text data ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ Len the length of the received plain text data exclude MIC value ++ ++ Return Value: ++ TRUE MIC value matched ++ FALSE MIC value mismatched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPTkipCompareMICValueWithLLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pLLC, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UINT Len) ++{ ++ UCHAR OldMic[8]; ++ ULONG Priority = 0; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); ++ ++ // Start with LLC header ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pLLC, 8); ++ ++ // Calculate MIC value from plain text data ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); ++ ++ // Get MIC valude from received frame ++ NdisMoveMemory(OldMic, pSrc + Len, 8); ++ ++ // Get MIC value from decrypted plain data ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); ++ ++ // Move MIC value from MSDU, this steps should move to data path. ++ // Since the MIC value might cross MPDUs. ++ if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValueWithLLC(): TKIP MIC Error !\n")); //MIC error. ++ ++ ++ return (FALSE); ++ } ++ return (TRUE); ++} ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware transmit function ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to Ndis Packet for MIC calculation ++ pEncap Pointer to LLC encap data ++ LenEncap Total encap length, might be 0 which indicates no encap ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPCalculateMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pEncap, ++ IN PCIPHER_KEY pKey, ++ IN UCHAR apidx) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PUCHAR pSrc; ++ UCHAR UserPriority; ++ UCHAR vlan_offset = 0; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ UserPriority = RTMP_GET_PACKET_UP(pPacket); ++ pSrc = pSrcBufVA; ++ ++ // determine if this is a vlan packet ++ if (((*(pSrc + 12) << 8) + *(pSrc + 13)) == 0x8100) ++ vlan_offset = 4; ++ ++ { ++ RTMPInitMICEngine( ++ pAd, ++ pKey->Key, ++ pSrc, ++ pSrc + 6, ++ UserPriority, ++ pKey->TxMic); ++ } ++ ++ ++ if (pEncap != NULL) ++ { ++ // LLC encapsulation ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pEncap, 6); ++ // Protocol Type ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc + 12 + vlan_offset, 2); ++ } ++ SrcBufLen -= (14 + vlan_offset); ++ pSrc += (14 + vlan_offset); ++ do ++ { ++ if (SrcBufLen > 0) ++ { ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc, SrcBufLen); ++ } ++ ++ break; // No need handle next packet ++ ++ } while (TRUE); // End of copying payload ++ ++ // Compute the final MIC Value ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); ++} ++ ++ ++/************************************************************/ ++/* tkip_sbox() */ ++/* Returns a 16 bit value from a 64K entry table. The Table */ ++/* is synthesized from two 256 entry byte wide tables. */ ++/************************************************************/ ++ ++UINT tkip_sbox(UINT index) ++{ ++ UINT index_low; ++ UINT index_high; ++ UINT left, right; ++ ++ index_low = (index % 256); ++ index_high = ((index >> 8) % 256); ++ ++ left = Tkip_Sbox_Lower[index_low] + (Tkip_Sbox_Upper[index_low] * 256); ++ right = Tkip_Sbox_Upper[index_high] + (Tkip_Sbox_Lower[index_high] * 256); ++ ++ return (left ^ right); ++} ++ ++UINT rotr1(UINT a) ++{ ++ unsigned int b; ++ ++ if ((a & 0x01) == 0x01) ++ { ++ b = (a >> 1) | 0x8000; ++ } ++ else ++ { ++ b = (a >> 1) & 0x7fff; ++ } ++ b = b % 65536; ++ return b; ++} ++ ++VOID RTMPTkipMixKey( ++ UCHAR *key, ++ UCHAR *ta, ++ ULONG pnl, /* Least significant 16 bits of PN */ ++ ULONG pnh, /* Most significant 32 bits of PN */ ++ UCHAR *rc4key, ++ UINT *p1k) ++{ ++ ++ UINT tsc0; ++ UINT tsc1; ++ UINT tsc2; ++ ++ UINT ppk0; ++ UINT ppk1; ++ UINT ppk2; ++ UINT ppk3; ++ UINT ppk4; ++ UINT ppk5; ++ ++ INT i; ++ INT j; ++ ++ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ ++ tsc1 = (unsigned int)(pnh % 65536); ++ tsc2 = (unsigned int)(pnl % 65536); /* lsb */ ++ ++ /* Phase 1, step 1 */ ++ p1k[0] = tsc1; ++ p1k[1] = tsc0; ++ p1k[2] = (UINT)(ta[0] + (ta[1]*256)); ++ p1k[3] = (UINT)(ta[2] + (ta[3]*256)); ++ p1k[4] = (UINT)(ta[4] + (ta[5]*256)); ++ ++ /* Phase 1, step 2 */ ++ for (i=0; i<8; i++) ++ { ++ j = 2*(i & 1); ++ p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*key[1+j]) + key[j])) % 65536 )) % 65536; ++ p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*key[5+j]) + key[4+j])) % 65536 )) % 65536; ++ p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*key[9+j]) + key[8+j])) % 65536 )) % 65536; ++ p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*key[13+j]) + key[12+j])) % 65536 )) % 65536; ++ p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*key[1+j]) + key[j]))) % 65536 )) % 65536; ++ p1k[4] = (p1k[4] + i) % 65536; ++ } ++ ++ /* Phase 2, Step 1 */ ++ ppk0 = p1k[0]; ++ ppk1 = p1k[1]; ++ ppk2 = p1k[2]; ++ ppk3 = p1k[3]; ++ ppk4 = p1k[4]; ++ ppk5 = (p1k[4] + tsc2) % 65536; ++ ++ /* Phase2, Step 2 */ ++ ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*key[1]) + key[0])) % 65536); ++ ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*key[3]) + key[2])) % 65536); ++ ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*key[5]) + key[4])) % 65536); ++ ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*key[7]) + key[6])) % 65536); ++ ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*key[9]) + key[8])) % 65536); ++ ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*key[11]) + key[10])) % 65536); ++ ++ ppk0 = ppk0 + rotr1(ppk5 ^ ((256*key[13]) + key[12])); ++ ppk1 = ppk1 + rotr1(ppk0 ^ ((256*key[15]) + key[14])); ++ ppk2 = ppk2 + rotr1(ppk1); ++ ppk3 = ppk3 + rotr1(ppk2); ++ ppk4 = ppk4 + rotr1(ppk3); ++ ppk5 = ppk5 + rotr1(ppk4); ++ ++ /* Phase 2, Step 3 */ ++ /* Phase 2, Step 3 */ ++ ++ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ ++ tsc1 = (unsigned int)(pnh % 65536); ++ tsc2 = (unsigned int)(pnl % 65536); /* lsb */ ++ ++ rc4key[0] = (tsc2 >> 8) % 256; ++ rc4key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f; ++ rc4key[2] = tsc2 % 256; ++ rc4key[3] = ((ppk5 ^ ((256*key[1]) + key[0])) >> 1) % 256; ++ ++ rc4key[4] = ppk0 % 256; ++ rc4key[5] = (ppk0 >> 8) % 256; ++ ++ rc4key[6] = ppk1 % 256; ++ rc4key[7] = (ppk1 >> 8) % 256; ++ ++ rc4key[8] = ppk2 % 256; ++ rc4key[9] = (ppk2 >> 8) % 256; ++ ++ rc4key[10] = ppk3 % 256; ++ rc4key[11] = (ppk3 >> 8) % 256; ++ ++ rc4key[12] = ppk4 % 256; ++ rc4key[13] = (ppk4 >> 8) % 256; ++ ++ rc4key[14] = ppk5 % 256; ++ rc4key[15] = (ppk5 >> 8) % 256; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header1() */ ++/* Builds the first MIC header block from */ ++/* header fields. */ ++/************************************************/ ++ ++void construct_mic_header1( ++ unsigned char *mic_header1, ++ int header_length, ++ unsigned char *mpdu) ++{ ++ mic_header1[0] = (unsigned char)((header_length - 2) / 256); ++ mic_header1[1] = (unsigned char)((header_length - 2) % 256); ++ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ ++ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ ++ mic_header1[4] = mpdu[4]; /* A1 */ ++ mic_header1[5] = mpdu[5]; ++ mic_header1[6] = mpdu[6]; ++ mic_header1[7] = mpdu[7]; ++ mic_header1[8] = mpdu[8]; ++ mic_header1[9] = mpdu[9]; ++ mic_header1[10] = mpdu[10]; /* A2 */ ++ mic_header1[11] = mpdu[11]; ++ mic_header1[12] = mpdu[12]; ++ mic_header1[13] = mpdu[13]; ++ mic_header1[14] = mpdu[14]; ++ mic_header1[15] = mpdu[15]; ++} ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++ ++void construct_mic_header2( ++ unsigned char *mic_header2, ++ unsigned char *mpdu, ++ int a4_exists, ++ int qc_exists) ++{ ++ int i; ++ ++ for (i = 0; i<16; i++) mic_header2[i]=0x00; ++ ++ mic_header2[0] = mpdu[16]; /* A3 */ ++ mic_header2[1] = mpdu[17]; ++ mic_header2[2] = mpdu[18]; ++ mic_header2[3] = mpdu[19]; ++ mic_header2[4] = mpdu[20]; ++ mic_header2[5] = mpdu[21]; ++ ++ // In Sequence Control field, mute sequence numer bits (12-bit) ++ mic_header2[6] = mpdu[22] & 0x0f; /* SC */ ++ mic_header2[7] = 0x00; /* mpdu[23]; */ ++ ++ if ((!qc_exists) & a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ } ++ ++ if (qc_exists && (!a4_exists)) ++ { ++ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ ++ mic_header2[9] = mpdu[25] & 0x00; ++ } ++ ++ if (qc_exists && a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ mic_header2[14] = mpdu[30] & 0x0f; ++ mic_header2[15] = mpdu[31] & 0x00; ++ } ++} ++ ++ ++/************************************************/ ++/* construct_mic_iv() */ ++/* Builds the MIC IV from header fields and PN */ ++/************************************************/ ++ ++void construct_mic_iv( ++ unsigned char *mic_iv, ++ int qc_exists, ++ int a4_exists, ++ unsigned char *mpdu, ++ unsigned int payload_length, ++ unsigned char *pn_vector) ++{ ++ int i; ++ ++ mic_iv[0] = 0x59; ++ if (qc_exists && a4_exists) ++ mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ ++ if (qc_exists && !a4_exists) ++ mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ ++ if (!qc_exists) ++ mic_iv[1] = 0x00; ++ for (i = 2; i < 8; i++) ++ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ ++#ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ ++#else ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ ++#endif ++ i = (payload_length / 256); ++ i = (payload_length % 256); ++ mic_iv[14] = (unsigned char) (payload_length / 256); ++ mic_iv[15] = (unsigned char) (payload_length % 256); ++ ++} ++ ++ ++ ++/************************************/ ++/* bitwise_xor() */ ++/* A 128 bit, bitwise exclusive or */ ++/************************************/ ++ ++void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out) ++{ ++ int i; ++ for (i=0; i<16; i++) ++ { ++ out[i] = ina[i] ^ inb[i]; ++ } ++} ++ ++ ++void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext) ++{ ++ int round; ++ int i; ++ unsigned char intermediatea[16]; ++ unsigned char intermediateb[16]; ++ unsigned char round_key[16]; ++ ++ for(i=0; i<16; i++) round_key[i] = key[i]; ++ ++ for (round = 0; round < 11; round++) ++ { ++ if (round == 0) ++ { ++ xor_128(round_key, data, ciphertext); ++ next_key(round_key, round); ++ } ++ else if (round == 10) ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ xor_128(intermediateb, round_key, ciphertext); ++ } ++ else /* 1 - 9 */ ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ mix_column(&intermediateb[0], &intermediatea[0]); ++ mix_column(&intermediateb[4], &intermediatea[4]); ++ mix_column(&intermediateb[8], &intermediatea[8]); ++ mix_column(&intermediateb[12], &intermediatea[12]); ++ xor_128(intermediatea, round_key, ciphertext); ++ next_key(round_key, round); ++ } ++ } ++ ++} ++ ++void construct_ctr_preload( ++ unsigned char *ctr_preload, ++ int a4_exists, ++ int qc_exists, ++ unsigned char *mpdu, ++ unsigned char *pn_vector, ++ int c) ++{ ++ ++ int i = 0; ++ for (i=0; i<16; i++) ctr_preload[i] = 0x00; ++ i = 0; ++ ++ ctr_preload[0] = 0x01; /* flag */ ++ if (qc_exists && a4_exists) ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ ++ if (qc_exists && !a4_exists) ctr_preload[1] = mpdu[24] & 0x0f; ++ ++ for (i = 2; i < 8; i++) ++ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ ++#ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ ++#else ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ ++#endif ++ ctr_preload[14] = (unsigned char) (c / 256); // Ctr ++ ctr_preload[15] = (unsigned char) (c % 256); ++ ++} ++ ++ ++// ++// TRUE: Success! ++// FALSE: Decrypt Error! ++// ++BOOLEAN RTMPSoftDecryptTKIP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN UCHAR UserPriority, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ UCHAR KeyID; ++ UINT HeaderLen; ++ UCHAR fc0; ++ UCHAR fc1; ++ USHORT fc; ++ UINT frame_type; ++ UINT frame_subtype; ++ UINT from_ds; ++ UINT to_ds; ++ INT a4_exists; ++ INT qc_exists; ++ USHORT duration; ++ USHORT seq_control; ++ USHORT qos_control; ++ UCHAR TA[MAC_ADDR_LEN]; ++ UCHAR DA[MAC_ADDR_LEN]; ++ UCHAR SA[MAC_ADDR_LEN]; ++ UCHAR RC4Key[16]; ++ UINT p1k[5]; //for mix_key; ++ ULONG pnl;/* Least significant 16 bits of PN */ ++ ULONG pnh;/* Most significant 32 bits of PN */ ++ UINT num_blocks; ++ UINT payload_remainder; ++ ARCFOURCONTEXT ArcFourContext; ++ UINT crc32 = 0; ++ UINT trailfcs = 0; ++ UCHAR MIC[8]; ++ UCHAR TrailMIC[8]; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ fc0 = *pData; ++ fc1 = *(pData + 1); ++ ++ fc = *((PUSHORT)pData); ++ ++ frame_type = ((fc0 >> 2) & 0x03); ++ frame_subtype = ((fc0 >> 4) & 0x0f); ++ ++ from_ds = (fc1 & 0x2) >> 1; ++ to_ds = (fc1 & 0x1); ++ ++ a4_exists = (from_ds & to_ds); ++ qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ ++ (frame_subtype == 0x09) || /* Likely to change. */ ++ (frame_subtype == 0x0a) || ++ (frame_subtype == 0x0b) ++ ); ++ ++ HeaderLen = 24; ++ if (a4_exists) ++ HeaderLen += 6; ++ ++ KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); ++ KeyID = KeyID >> 6; ++ ++ if (pWpaKey[KeyID].KeyLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP failed!(KeyID[%d] Length can not be 0)\n", KeyID)); ++ return FALSE; ++ } ++ ++ duration = *((PUSHORT)(pData+2)); ++ ++ seq_control = *((PUSHORT)(pData+22)); ++ ++ if (qc_exists) ++ { ++ if (a4_exists) ++ { ++ qos_control = *((PUSHORT)(pData+30)); ++ } ++ else ++ { ++ qos_control = *((PUSHORT)(pData+24)); ++ } ++ } ++ ++ if (to_ds == 0 && from_ds == 1) ++ { ++ NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+16, MAC_ADDR_LEN); ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); //BSSID ++ } ++ else if (to_ds == 0 && from_ds == 0 ) ++ { ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); ++ } ++ else if (to_ds == 1 && from_ds == 0) ++ { ++ NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); ++ } ++ else if (to_ds == 1 && from_ds == 1) ++ { ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+22, MAC_ADDR_LEN); ++ } ++ ++ num_blocks = (DataByteCnt - 16) / 16; ++ payload_remainder = (DataByteCnt - 16) % 16; ++ ++ pnl = (*(pData + HeaderLen)) * 256 + *(pData + HeaderLen + 2); ++ pnh = *((PULONG)(pData + HeaderLen + 4)); ++ pnh = cpu2le32(pnh); ++ RTMPTkipMixKey(pWpaKey[KeyID].Key, TA, pnl, pnh, RC4Key, p1k); ++ ++ ARCFOUR_INIT(&ArcFourContext, RC4Key, 16); ++ ++ ARCFOUR_DECRYPT(&ArcFourContext, pData + HeaderLen, pData + HeaderLen + 8, DataByteCnt - HeaderLen - 8); ++ NdisMoveMemory(&trailfcs, pData + DataByteCnt - 8 - 4, 4); ++ crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 4); //Skip IV+EIV 8 bytes & Skip last 4 bytes(FCS). ++ crc32 ^= 0xffffffff; /* complement */ ++ ++ if(crc32 != cpu2le32(trailfcs)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP, WEP Data ICV Error !\n")); //ICV error. ++ ++ return (FALSE); ++ } ++ ++ NdisMoveMemory(TrailMIC, pData + DataByteCnt - 8 - 8 - 4, 8); ++ RTMPInitMICEngine(pAd, pWpaKey[KeyID].Key, DA, SA, UserPriority, pWpaKey[KeyID].RxMic); ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 12); ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); ++ NdisMoveMemory(MIC, pAd->PrivateInfo.Tx.MIC, 8); ++ ++ if (!NdisEqualMemory(MIC, TrailMIC, 8)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptTKIP, WEP Data MIC Error !\n")); //MIC error. ++ return (FALSE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ return TRUE; ++} ++ ++ ++ ++ ++BOOLEAN RTMPSoftDecryptAES( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ UCHAR KeyID; ++ UINT HeaderLen; ++ UCHAR PN[6]; ++ UINT payload_len; ++ UINT num_blocks; ++ UINT payload_remainder; ++ USHORT fc; ++ UCHAR fc0; ++ UCHAR fc1; ++ UINT frame_type; ++ UINT frame_subtype; ++ UINT from_ds; ++ UINT to_ds; ++ INT a4_exists; ++ INT qc_exists; ++ UCHAR aes_out[16]; ++ int payload_index; ++ UINT i; ++ UCHAR ctr_preload[16]; ++ UCHAR chain_buffer[16]; ++ UCHAR padded_buffer[16]; ++ UCHAR mic_iv[16]; ++ UCHAR mic_header1[16]; ++ UCHAR mic_header2[16]; ++ UCHAR MIC[8]; ++ UCHAR TrailMIC[8]; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ fc0 = *pData; ++ fc1 = *(pData + 1); ++ ++ fc = *((PUSHORT)pData); ++ ++ frame_type = ((fc0 >> 2) & 0x03); ++ frame_subtype = ((fc0 >> 4) & 0x0f); ++ ++ from_ds = (fc1 & 0x2) >> 1; ++ to_ds = (fc1 & 0x1); ++ ++ a4_exists = (from_ds & to_ds); ++ qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ ++ (frame_subtype == 0x09) || /* Likely to change. */ ++ (frame_subtype == 0x0a) || ++ (frame_subtype == 0x0b) ++ ); ++ ++ HeaderLen = 24; ++ if (a4_exists) ++ HeaderLen += 6; ++ ++ KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); ++ KeyID = KeyID >> 6; ++ ++ if (pWpaKey[KeyID].KeyLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptAES failed!(KeyID[%d] Length can not be 0)\n", KeyID)); ++ return FALSE; ++ } ++ ++ PN[0] = *(pData+ HeaderLen); ++ PN[1] = *(pData+ HeaderLen + 1); ++ PN[2] = *(pData+ HeaderLen + 4); ++ PN[3] = *(pData+ HeaderLen + 5); ++ PN[4] = *(pData+ HeaderLen + 6); ++ PN[5] = *(pData+ HeaderLen + 7); ++ ++ payload_len = DataByteCnt - HeaderLen - 8 - 8; // 8 bytes for CCMP header , 8 bytes for MIC ++ payload_remainder = (payload_len) % 16; ++ num_blocks = (payload_len) / 16; ++ ++ ++ ++ // Find start of payload ++ payload_index = HeaderLen + 8; //IV+EIV ++ ++ for (i=0; i< num_blocks; i++) ++ { ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ i+1 ); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, pData + payload_index, chain_buffer); ++ NdisMoveMemory(pData + payload_index - 8, chain_buffer, 16); ++ payload_index += 16; ++ } ++ ++ // ++ // If there is a short final block, then pad it ++ // encrypt it and copy the unpadded part back ++ // ++ if (payload_remainder > 0) ++ { ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ num_blocks + 1); ++ ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ NdisMoveMemory(pData + payload_index - 8, chain_buffer, payload_remainder); ++ payload_index += payload_remainder; ++ } ++ ++ // ++ // Descrypt the MIC ++ // ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ 0); ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, 8); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ ++ NdisMoveMemory(TrailMIC, chain_buffer, 8); ++ ++ // ++ // Calculate MIC ++ // ++ ++ //Force the protected frame bit on ++ *(pData + 1) = *(pData + 1) | 0x40; ++ ++ // Find start of payload ++ // Because the CCMP header has been removed ++ payload_index = HeaderLen; ++ ++ construct_mic_iv( ++ mic_iv, ++ qc_exists, ++ a4_exists, ++ pData, ++ payload_len, ++ PN); ++ ++ construct_mic_header1( ++ mic_header1, ++ HeaderLen, ++ pData); ++ ++ construct_mic_header2( ++ mic_header2, ++ pData, ++ a4_exists, ++ qc_exists); ++ ++ aes128k128d(pWpaKey[KeyID].Key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ ++ // iterate through each 16 byte payload block ++ for (i = 0; i < num_blocks; i++) ++ { ++ bitwise_xor(aes_out, pData + payload_index, chain_buffer); ++ payload_index += 16; ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ } ++ ++ // Add on the final payload block if it needs padding ++ if (payload_remainder > 0) ++ { ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ } ++ // aes_out contains padded mic, discard most significant ++ // 8 bytes to generate 64 bit MIC ++ for (i = 0 ; i < 8; i++) MIC[i] = aes_out[i]; ++ ++ if (!NdisEqualMemory(MIC, TrailMIC, 8)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptAES, MIC Error !\n")); //MIC error. ++ return FALSE; ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ return TRUE; ++} ++ ++/****************************************/ ++/* aes128k128d() */ ++/* Performs a 128 bit AES encrypt with */ ++/* 128 bit data. */ ++/****************************************/ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0;i<16; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round) ++{ ++ UCHAR rcon; ++ UCHAR sbox_key[4]; ++ UCHAR rcon_table[12] = ++ { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++ 0x1b, 0x36, 0x36, 0x36 ++ }; ++ ++ sbox_key[0] = RTMPCkipSbox(key[13]); ++ sbox_key[1] = RTMPCkipSbox(key[14]); ++ sbox_key[2] = RTMPCkipSbox(key[15]); ++ sbox_key[3] = RTMPCkipSbox(key[12]); ++ ++ rcon = rcon_table[round]; ++ ++ xor_32(&key[0], sbox_key, &key[0]); ++ key[0] = key[0] ^ rcon; ++ ++ xor_32(&key[4], &key[0], &key[4]); ++ xor_32(&key[8], &key[4], &key[8]); ++ xor_32(&key[12], &key[8], &key[12]); ++} ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0;i<4; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0; i< 16; i++) ++ { ++ out[i] = RTMPCkipSbox(in[i]); ++ } ++} ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a) ++{ ++ return SboxTable[(int)a]; ++} ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ out[0] = in[0]; ++ out[1] = in[5]; ++ out[2] = in[10]; ++ out[3] = in[15]; ++ out[4] = in[4]; ++ out[5] = in[9]; ++ out[6] = in[14]; ++ out[7] = in[3]; ++ out[8] = in[8]; ++ out[9] = in[13]; ++ out[10] = in[2]; ++ out[11] = in[7]; ++ out[12] = in[12]; ++ out[13] = in[1]; ++ out[14] = in[6]; ++ out[15] = in[11]; ++} ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ INT i; ++ UCHAR add1b[4]; ++ UCHAR add1bf7[4]; ++ UCHAR rotl[4]; ++ UCHAR swap_halfs[4]; ++ UCHAR andf7[4]; ++ UCHAR rotr[4]; ++ UCHAR temp[4]; ++ UCHAR tempb[4]; ++ ++ for (i=0 ; i<4; i++) ++ { ++ if ((in[i] & 0x80)== 0x80) ++ add1b[i] = 0x1b; ++ else ++ add1b[i] = 0x00; ++ } ++ ++ swap_halfs[0] = in[2]; /* Swap halfs */ ++ swap_halfs[1] = in[3]; ++ swap_halfs[2] = in[0]; ++ swap_halfs[3] = in[1]; ++ ++ rotl[0] = in[3]; /* Rotate left 8 bits */ ++ rotl[1] = in[0]; ++ rotl[2] = in[1]; ++ rotl[3] = in[2]; ++ ++ andf7[0] = in[0] & 0x7f; ++ andf7[1] = in[1] & 0x7f; ++ andf7[2] = in[2] & 0x7f; ++ andf7[3] = in[3] & 0x7f; ++ ++ for (i = 3; i>0; i--) /* logical shift left 1 bit */ ++ { ++ andf7[i] = andf7[i] << 1; ++ if ((andf7[i-1] & 0x80) == 0x80) ++ { ++ andf7[i] = (andf7[i] | 0x01); ++ } ++ } ++ andf7[0] = andf7[0] << 1; ++ andf7[0] = andf7[0] & 0xfe; ++ ++ xor_32(add1b, andf7, add1bf7); ++ ++ xor_32(in, add1bf7, rotr); ++ ++ temp[0] = rotr[0]; /* Rotate right 8 bits */ ++ rotr[0] = rotr[1]; ++ rotr[1] = rotr[2]; ++ rotr[2] = rotr[3]; ++ rotr[3] = temp[0]; ++ ++ xor_32(add1bf7, rotr, temp); ++ xor_32(swap_halfs, rotl,tempb); ++ xor_32(temp, tempb, out); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/rtmp_wep.c +@@ -0,0 +1,499 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_wep.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Wu 10-28-02 Initial ++*/ ++ ++#include "../rt_config.h" ++ ++UINT FCSTAB_32[256] = ++{ ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, ++ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, ++ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ++ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, ++ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, ++ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, ++ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ++ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, ++ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, ++ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, ++ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, ++ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, ++ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, ++ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ++ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, ++ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, ++ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, ++ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ++ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, ++ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, ++ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, ++ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, ++ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ++ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, ++ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, ++ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, ++ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ++ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, ++ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, ++ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, ++ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, ++ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, ++ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, ++ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ++ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, ++ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, ++ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, ++ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ++ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, ++ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, ++ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, ++ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, ++ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ++ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ++}; ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init WEP function. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pKey Pointer to the WEP KEY ++ KeyId WEP Key ID ++ KeyLen the length of WEP KEY ++ pDest Pointer to the destination which Encryption data will store in. ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitWepEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN UCHAR KeyLen, ++ IN OUT PUCHAR pDest) ++{ ++ UINT i; ++ UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ ++ pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10) && (pAd->OpMode == OPMODE_STA)) ++ { ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, pKey, KeyLen); //INIT SBOX, KEYLEN+3(IV) ++ NdisMoveMemory(pDest, pKey, 3); //Append Init Vector ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ NdisMoveMemory(WEPKEY + 3, pKey, KeyLen); ++ ++ for(i = 0; i < 3; i++) ++ WEPKEY[i] = RandomByte(pAd); //Call mlme RandomByte() function. ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, KeyLen + 3); //INIT SBOX, KEYLEN+3(IV) ++ ++ NdisMoveMemory(pDest, WEPKEY, 3); //Append Init Vector ++ } ++ *(pDest+3) = (KeyId << 6); //Append KEYID ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Encrypt transimitted data ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to the transimitted source data that will be encrypt ++ pDest Pointer to the destination where entryption data will be store in. ++ Len Indicate the length of the source data ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPEncryptData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDest, ++ IN UINT Len) ++{ ++ pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, pSrc, Len); ++ ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, pSrc, Len); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Decrypt received WEP data ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ pSrc Pointer to the received data ++ Len the length of the received data ++ ++ Return Value: ++ TRUE Decrypt WEP data success ++ FALSE Decrypt WEP data failed ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPSoftDecryptWEP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pGroupKey) ++{ ++ UINT trailfcs; ++ UINT crc32; ++ UCHAR KeyIdx; ++ UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ UCHAR *pPayload = (UCHAR *)pData + LENGTH_802_11; ++ ULONG payload_len = DataByteCnt - LENGTH_802_11; ++ ++ NdisMoveMemory(WEPKEY, pPayload, 3); //Get WEP IV ++ ++ KeyIdx = (*(pPayload + 3) & 0xc0) >> 6; ++ if (pGroupKey[KeyIdx].KeyLen == 0) ++ return (FALSE); ++ ++ NdisMoveMemory(WEPKEY + 3, pGroupKey[KeyIdx].Key, pGroupKey[KeyIdx].KeyLen); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, pGroupKey[KeyIdx].KeyLen + 3); ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, pPayload, pPayload + 4, payload_len - 4); ++ NdisMoveMemory(&trailfcs, pPayload + payload_len - 8, 4); ++ crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pPayload, payload_len - 8); //Skip last 4 bytes(FCS). ++ crc32 ^= 0xffffffff; /* complement */ ++ ++ if(crc32 != cpu2le32(trailfcs)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("! WEP Data CRC Error !\n")); //CRC error. ++ return (FALSE); ++ } ++ return (TRUE); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm "ARCFOUR" initialize ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pKey Pointer to the WEP KEY ++ KeyLen Indicate the length fo the WEP KEY ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_INIT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pKey, ++ IN UINT KeyLen) ++{ ++ UCHAR t, u; ++ UINT keyindex; ++ UINT stateindex; ++ PUCHAR state; ++ UINT counter; ++ ++ state = Ctx->STATE; ++ Ctx->X = 0; ++ Ctx->Y = 0; ++ for (counter = 0; counter < 256; counter++) ++ state[counter] = (UCHAR)counter; ++ keyindex = 0; ++ stateindex = 0; ++ for (counter = 0; counter < 256; counter++) ++ { ++ t = state[counter]; ++ stateindex = (stateindex + pKey[keyindex] + t) & 0xff; ++ u = state[stateindex]; ++ state[stateindex] = t; ++ state[counter] = u; ++ if (++keyindex >= KeyLen) ++ keyindex = 0; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get bytes from ARCFOUR CONTEXT (S-BOX) ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ ++ Return Value: ++ UCHAR - the value of the ARCFOUR CONTEXT (S-BOX) ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UCHAR ARCFOUR_BYTE( ++ IN PARCFOURCONTEXT Ctx) ++{ ++ UINT x; ++ UINT y; ++ UCHAR sx, sy; ++ PUCHAR state; ++ ++ state = Ctx->STATE; ++ x = (Ctx->X + 1) & 0xff; ++ sx = state[x]; ++ y = (sx + Ctx->Y) & 0xff; ++ sy = state[y]; ++ Ctx->X = x; ++ Ctx->Y = y; ++ state[y] = sx; ++ state[x] = sy; ++ ++ return(state[(sx + sy) & 0xff]); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Decryption Algorithm ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source data ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_DECRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source dta ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm which conform to the special requirement to encrypt GTK. ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source dta ++ ++ ++ ======================================================================== ++*/ ++ ++VOID WPAARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ //discard first 256 bytes ++ for (i = 0; i < 256; i++) ++ ARCFOUR_BYTE(Ctx); ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate a new FCS given the current FCS and the new data. ++ ++ Arguments: ++ Fcs the original FCS value ++ Cp pointer to the data which will be calculate the FCS ++ Len the length of the data ++ ++ Return Value: ++ UINT - FCS 32 bits ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UINT RTMP_CALC_FCS32( ++ IN UINT Fcs, ++ IN PUCHAR Cp, ++ IN INT Len) ++{ ++ while (Len--) ++ Fcs = (((Fcs) >> 8) ^ FCSTAB_32[((Fcs) ^ (*Cp++)) & 0xff]); ++ ++ return (Fcs); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get last FCS and encrypt it to the destination ++ ++ Arguments: ++ pDest Pointer to the Destination ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSetICV( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest) ++{ ++ pAd->PrivateInfo.FCSCRC32 ^= 0xffffffff; /* complement */ ++ pAd->PrivateInfo.FCSCRC32 = cpu2le32(pAd->PrivateInfo.FCSCRC32); ++ ++ ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, (PUCHAR) &pAd->PrivateInfo.FCSCRC32, 4); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/common/spectrum.c +@@ -0,0 +1,1877 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ ++ Module Name: ++ action.c ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ --------- ---------- ---------------------------------------------- ++ Fonchi Wu 2008 created for 802.11h ++ */ ++ ++#include "../rt_config.h" ++#include "action.h" ++ ++VOID MeasureReqTabInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC); ++ if (pAd->CommonCfg.pMeasureReqTab) ++ NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB)); ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__)); ++ ++ return; ++} ++ ++VOID MeasureReqTabExit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock); ++ ++ if (pAd->CommonCfg.pMeasureReqTab) ++ kfree(pAd->CommonCfg.pMeasureReqTab); ++ pAd->CommonCfg.pMeasureReqTab = NULL; ++ ++ return; ++} ++ ++static PMEASURE_REQ_ENTRY MeasureReqLookUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ UINT HashIdx; ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ++ if (pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ pEntry = pTab->Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if (pEntry->DialogToken == DialogToken) ++ break; ++ else ++ { ++ pPrevEntry = pEntry; ++ pEntry = pEntry->pNext; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ return pEntry; ++} ++ ++static PMEASURE_REQ_ENTRY MeasureReqInsert( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ INT i; ++ ULONG HashIdx; ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry; ++ ULONG Now; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ pEntry = MeasureReqLookUp(pAd, DialogToken); ++ if (pEntry == NULL) ++ { ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry = &pTab->Content[i]; ++ ++ if ((pEntry->Valid == TRUE) ++ && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT))) ++ { ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); ++ pTab->Size--; ++ ++ break; ++ } ++ ++ if (pEntry->Valid == FALSE) ++ break; ++ } ++ ++ if (i < MAX_MEASURE_REQ_TAB_SIZE) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry->lastTime = Now; ++ pEntry->Valid = TRUE; ++ pEntry->DialogToken = DialogToken; ++ pTab->Size++; ++ } ++ else ++ { ++ pEntry = NULL; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__)); ++ } ++ ++ // add this Neighbor entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ if (pTab->Hash[HashIdx] == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pTab->Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ } ++ ++ return pEntry; ++} ++ ++static VOID MeasureReqDelete( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return; ++ } ++ ++ // if empty, return ++ if (pTab->Size == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n")); ++ return; ++ } ++ ++ pEntry = MeasureReqLookUp(pAd, DialogToken); ++ if (pEntry != NULL) ++ { ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); ++ pTab->Size--; ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ } ++ ++ return; ++} ++ ++VOID TpcReqTabInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock); ++ ++ pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC); ++ if (pAd->CommonCfg.pTpcReqTab) ++ NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB)); ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__)); ++ ++ return; ++} ++ ++VOID TpcReqTabExit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock); ++ ++ if (pAd->CommonCfg.pTpcReqTab) ++ kfree(pAd->CommonCfg.pTpcReqTab); ++ pAd->CommonCfg.pTpcReqTab = NULL; ++ ++ return; ++} ++ ++static PTPC_REQ_ENTRY TpcReqLookUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ UINT HashIdx; ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ++ if (pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ ++ HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ pEntry = pTab->Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if (pEntry->DialogToken == DialogToken) ++ break; ++ else ++ { ++ pPrevEntry = pEntry; ++ pEntry = pEntry->pNext; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ ++ return pEntry; ++} ++ ++ ++static PTPC_REQ_ENTRY TpcReqInsert( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ INT i; ++ ULONG HashIdx; ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry; ++ ULONG Now; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ pEntry = TpcReqLookUp(pAd, DialogToken); ++ if (pEntry == NULL) ++ { ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry = &pTab->Content[i]; ++ ++ if ((pEntry->Valid == TRUE) ++ && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT))) ++ { ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); ++ pTab->Size--; ++ ++ break; ++ } ++ ++ if (pEntry->Valid == FALSE) ++ break; ++ } ++ ++ if (i < MAX_TPC_REQ_TAB_SIZE) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry->lastTime = Now; ++ pEntry->Valid = TRUE; ++ pEntry->DialogToken = DialogToken; ++ pTab->Size++; ++ } ++ else ++ { ++ pEntry = NULL; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__)); ++ } ++ ++ // add this Neighbor entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ if (pTab->Hash[HashIdx] == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pTab->Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ } ++ ++ return pEntry; ++} ++ ++static VOID TpcReqDelete( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return; ++ } ++ ++ // if empty, return ++ if (pTab->Size == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n")); ++ return; ++ } ++ ++ pEntry = TpcReqLookUp(pAd, DialogToken); ++ if (pEntry != NULL) ++ { ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); ++ pTab->Size--; ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Get Current TimeS tamp. ++ ++ Parametrs: ++ ++ Return : Current Time Stamp. ++ ========================================================================== ++ */ ++static UINT64 GetCurrentTimeStamp( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // get current time stamp. ++ return 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Get Current Transmit Power. ++ ++ Parametrs: ++ ++ Return : Current Time Stamp. ++ ========================================================================== ++ */ ++static UINT8 GetCurTxPwr( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 Wcid) ++{ ++ return 16; /* 16 dBm */ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Dialog Token into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Dialog token. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertDialogToken( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 DialogToken) ++{ ++ ULONG TempLen; ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &DialogToken, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert TPC Request IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ static VOID InsertTpcReqIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen) ++{ ++ ULONG TempLen; ++ ULONG Len = 0; ++ UINT8 ElementID = IE_TPC_REQUEST; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert TPC Report IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Transmit Power. ++ 4. Link Margin. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ static VOID InsertTpcReportIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin) ++{ ++ ULONG TempLen; ++ ULONG Len = sizeof(TPC_REPORT_INFO); ++ UINT8 ElementID = IE_TPC_REPORT; ++ TPC_REPORT_INFO TpcReportIE; ++ ++ TpcReportIE.TxPwr = TxPwr; ++ TpcReportIE.LinkMargin = LinkMargin; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, &TpcReportIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Channel Switch Announcement IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. channel switch announcement mode. ++ 4. new selected channel. ++ 5. channel switch announcement count. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertChSwAnnIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewChannel, ++ IN UINT8 ChSwCnt) ++{ ++ ULONG TempLen; ++ ULONG Len = sizeof(CH_SW_ANN_INFO); ++ UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT; ++ CH_SW_ANN_INFO ChSwAnnIE; ++ ++ ChSwAnnIE.ChSwMode = ChSwMode; ++ ChSwAnnIE.Channel = NewChannel; ++ ChSwAnnIE.ChSwCnt = ChSwCnt; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, &ChSwAnnIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Measure Request IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Measure Token. ++ 4. Measure Request Mode. ++ 5. Measure Request Type. ++ 6. Measure Channel. ++ 7. Measure Start time. ++ 8. Measure Duration. ++ ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertMeasureReqIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN PMEASURE_REQ_INFO pMeasureReqIE) ++{ ++ ULONG TempLen; ++ UINT8 Len = sizeof(MEASURE_REQ_INFO); ++ UINT8 ElementID = IE_MEASUREMENT_REQUEST; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, pMeasureReqIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Measure Report IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Measure Token. ++ 4. Measure Request Mode. ++ 5. Measure Request Type. ++ 6. Length of Report Infomation ++ 7. Pointer of Report Infomation Buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertMeasureReportIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN PMEASURE_REPORT_INFO pMeasureReportIE, ++ IN UINT8 ReportLnfoLen, ++ IN PUINT8 pReportInfo) ++{ ++ ULONG TempLen; ++ ULONG Len; ++ UINT8 ElementID = IE_MEASUREMENT_REPORT; ++ ++ Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, pMeasureReportIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ if ((ReportLnfoLen > 0) && (pReportInfo != NULL)) ++ { ++ MakeOutgoingFrame(pFrameBuf + *pFrameLen, &TempLen, ++ ReportLnfoLen, pReportInfo, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ } ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 MeasureCh, ++ IN UINT16 MeasureDuration) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ HEADER_802_11 ActHdr; ++ MEASURE_REQ_INFO MeasureReqIE; ++ UINT8 RmReqDailogToken = RandomByte(pAd); ++ UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd); ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken); ++ ++ // prepare Measurement IE. ++ NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO)); ++ MeasureReqIE.Token = RmReqDailogToken; ++ MeasureReqIE.ReqMode.word = MeasureReqMode; ++ MeasureReqIE.ReqType = MeasureReqType; ++ MeasureReqIE.MeasureReq.ChNum = MeasureCh; ++ MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime); ++ MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration); ++ InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 ReportInfoLen, ++ IN PUINT8 pReportInfo) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ HEADER_802_11 ActHdr; ++ MEASURE_REPORT_INFO MeasureRepIE; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // prepare Measurement IE. ++ NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO)); ++ MeasureRepIE.Token = MeasureToken; ++ MeasureRepIE.ReportMode.word = MeasureReqMode; ++ MeasureRepIE.ReportType = MeasureReqType; ++ InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UCHAR DialogToken) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // Insert TPC Request IE. ++ InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // Insert TPC Request IE. ++ InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Channel Switch Announcement action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ 2. Channel switch announcement mode. ++ 2. a New selected channel. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueChSwAnn( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewCh) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH); ++ ++ InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++static BOOLEAN DfsRequirementCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 Channel) ++{ ++ BOOLEAN Result = FALSE; ++ INT i; ++ ++ do ++ { ++ // check DFS procedure is running. ++ // make sure DFS procedure won't start twice. ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++ { ++ Result = FALSE; ++ break; ++ } ++ ++ // check the new channel carried from Channel Switch Announcemnet is valid. ++ for (i=0; iChannelListNum; i++) ++ { ++ if ((Channel == pAd->ChannelList[i].Channel) ++ &&(pAd->ChannelList[i].RemainingTimeForUse == 0)) ++ { ++ // found radar signal in the channel. the channel can't use at least for 30 minutes. ++ pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec ++ Result = TRUE; ++ break; ++ } ++ } ++ } while(FALSE); ++ ++ return Result; ++} ++ ++VOID NotifyChSwAnnToPeerAPs( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRA, ++ IN PUCHAR pTA, ++ IN UINT8 ChSwMode, ++ IN UINT8 Channel) ++{ ++#ifdef WDS_SUPPORT ++ if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address. ++ { ++ INT i; ++ // info neighbor APs that Radar signal found throgh WDS link. ++ for (i = 0; i < MAX_WDS_ENTRY; i++) ++ { ++ if (ValidWdsEntry(pAd, i)) ++ { ++ PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr; ++ ++ // DA equal to SA. have no necessary orignal AP which found Radar signal. ++ if (MAC_ADDR_EQUAL(pTA, pDA)) ++ continue; ++ ++ // send Channel Switch Action frame to info Neighbro APs. ++ EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel); ++ } ++ } ++ } ++#endif // WDS_SUPPORT // ++} ++ ++static VOID StartDFSProcedure( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN UINT8 ChSwMode) ++{ ++ // start DFS procedure ++ pAd->CommonCfg.Channel = Channel; ++#ifdef DOT11_N_SUPPORT ++ N_ChannelCheck(pAd); ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE; ++ pAd->CommonCfg.RadarDetect.CSCount = 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Channel Switch Announcement action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Channel switch announcement infomation buffer. ++ ++ ++ Return : None. ++ ========================================================================== ++ */ ++ ++/* ++ Channel Switch Announcement IE. ++ +----+-----+-----------+------------+-----------+ ++ | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt | ++ +----+-----+-----------+------------+-----------+ ++ 1 1 1 1 1 ++*/ ++static BOOLEAN PeerChSwAnnSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PCH_SW_ANN_INFO pChSwAnnInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pChSwAnnInfo == NULL) ++ return result; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_CHANNEL_SWITCH_ANNOUNCEMENT: ++ NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1); ++ ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement request action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Measurement request infomation buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerMeasureReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PMEASURE_REQ_INFO pMeasureReqInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ PUCHAR ptr; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pMeasureReqInfo == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_MEASUREMENT_REQUEST: ++ NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1); ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1); ++ NdisMoveMemory(&MeasureStartTime, ptr + 1, 8); ++ pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime); ++ NdisMoveMemory(&MeasureDuration, ptr + 9, 2); ++ pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration); ++ ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement report action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Measurement report infomation buffer. ++ 4. basic report infomation buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ ++/* ++ Measurement Report IE. ++ +----+-----+-------+-------------+--------------+----------------+ ++ | ID | Len | Token | Report Mode | Measure Type | Measure Report | ++ +----+-----+-------+-------------+--------------+----------------+ ++ 1 1 1 1 1 variable ++ ++ Basic Report. ++ +--------+------------+----------+-----+ ++ | Ch Num | Start Time | Duration | Map | ++ +--------+------------+----------+-----+ ++ 1 8 2 1 ++ ++ Map Field Bit Format. ++ +-----+---------------+---------------------+-------+------------+----------+ ++ | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved | ++ +-----+---------------+---------------------+-------+------------+----------+ ++ 0 1 2 3 4 5-7 ++*/ ++static BOOLEAN PeerMeasureReportSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PMEASURE_REPORT_INFO pMeasureReportInfo, ++ OUT PUINT8 pReportBuf) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ PUCHAR ptr; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pMeasureReportInfo == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_MEASUREMENT_REPORT: ++ NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1); ++ if (pMeasureReportInfo->ReportType == RM_BASIC) ++ { ++ PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->Map, ptr + 11, 1); ++ ++ } ++ else if (pMeasureReportInfo->ReportType == RM_CCA) ++ { ++ PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1); ++ ++ } ++ else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM) ++ { ++ PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8); ++ } ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Request action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Dialog Token. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerTpcReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pDialogToken == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_TPC_REQUEST: ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Report action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Dialog Token. ++ 4. TPC Report IE. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerTpcRepSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PTPC_REPORT_INFO pTpcRepInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pDialogToken == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_TPC_REPORT: ++ NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1); ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Channel Switch Announcement action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerChSwAnnAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ CH_SW_ANN_INFO ChSwAnnInfo; ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR index = 0, Channel = 0, NewChannel = 0; ++ ULONG Bssidx = 0; ++#endif // CONFIG_STA_SUPPORT // ++ ++ NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO)); ++ if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n")); ++ return; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n")); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel)); ++ hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6); ++ ++ Channel = pAd->CommonCfg.Channel; ++ NewChannel = ChSwAnnInfo.Channel; ++ ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) ++ { ++ // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). ++ // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. ++ AsicSwitchChannel(pAd, 1, FALSE); ++ AsicLockChannel(pAd, 1); ++ LinkDown(pAd, FALSE); ++ MlmeQueueInit(&pAd->Mlme.Queue); ++ BssTableInit(&pAd->ScanTab); ++ RTMPusecDelay(1000000); // use delay to prevent STA do reassoc ++ ++ // channel sanity check ++ for (index = 0 ; index < pAd->ChannelListNum; index++) ++ { ++ if (pAd->ChannelList[index].Channel == NewChannel) ++ { ++ pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; ++ pAd->CommonCfg.Channel = NewChannel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); ++ break; ++ } ++ } ++ ++ if (index >= pAd->ChannelListNum) ++ { ++ DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement Request action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerMeasureReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ UINT8 DialogToken; ++ MEASURE_REQ_INFO MeasureReqInfo; ++ MEASURE_REPORT_MODE ReportMode; ++ ++ if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo)) ++ { ++ ReportMode.word = 0; ++ ReportMode.field.Incapable = 1; ++ EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL); ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement Report action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerMeasureReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MEASURE_REPORT_INFO MeasureReportInfo; ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ UINT8 DialogToken; ++ PUINT8 pMeasureReportInfo; ++ ++// if (pAd->CommonCfg.bIEEE80211H != TRUE) ++// return; ++ ++ if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT))); ++ return; ++ } ++ ++ NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO)); ++ NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT)); ++ if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo)) ++ { ++ do { ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ ++ // Not a autonomous measure report. ++ // check the dialog token field. drop it if the dialog token doesn't match. ++ if ((DialogToken != 0) ++ && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL)) ++ break; ++ ++ if (pEntry != NULL) ++ MeasureReqDelete(pAd, pEntry->DialogToken); ++ ++ if (MeasureReportInfo.ReportType == RM_BASIC) ++ { ++ PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo; ++ if ((pBasicReport->Map.field.Radar) ++ && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE)) ++ { ++ NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum); ++ StartDFSProcedure(pAd, pBasicReport->ChNum, 1); ++ } ++ } ++ } while (FALSE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n")); ++ ++ kfree(pMeasureReportInfo); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Request action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerTpcReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ PUCHAR pFramePtr = pFr->Octet; ++ UINT8 DialogToken; ++ UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid); ++ UINT8 LinkMargin = 0; ++ CHAR RealRssi; ++ ++ // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The ++ // STA may incorporate rate information and channel conditions, including interference, into its computation ++ // of link margin. ++ ++ RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ++ ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ++ ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ // skip Category and action code. ++ pFramePtr += 2; ++ ++ // Dialog token. ++ NdisMoveMemory(&DialogToken, pFramePtr, 1); ++ ++ LinkMargin = (RealRssi / MIN_RCV_PWR); ++ if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken)) ++ EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Report action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerTpcRepAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UINT8 DialogToken; ++ TPC_REPORT_INFO TpcRepInfo; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ ++ NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO)); ++ if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo)) ++ { ++ if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL) ++ { ++ TpcReqDelete(pAd, pEntry->DialogToken); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n", ++ __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); ++ } ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Spectrun action frames Handler such as channel switch annoucement, ++ measurement report, measurement request actions frames. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID PeerSpectrumAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ if (pAd->CommonCfg.bIEEE80211H != TRUE) ++ return; ++ ++ switch(Action) ++ { ++ case SPEC_MRQ: ++ // current rt2860 unable do such measure specified in Measurement Request. ++ // reject all measurement request. ++ PeerMeasureReqAction(pAd, Elem); ++ break; ++ ++ case SPEC_MRP: ++ PeerMeasureReportAction(pAd, Elem); ++ break; ++ ++ case SPEC_TPCRQ: ++ PeerTpcReqAction(pAd, Elem); ++ break; ++ ++ case SPEC_TPCRP: ++ PeerTpcRepAction(pAd, Elem); ++ break; ++ ++ case SPEC_CHANNEL_SWITCH: ++{ ++#ifdef DOT11N_DRAFT3 ++ SEC_CHA_OFFSET_IE Secondary; ++ CHA_SWITCH_ANNOUNCE_IE ChannelSwitch; ++ ++ // 802.11h only has Channel Switch Announcement IE. ++ RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE)); ++ ++ // 802.11n D3.03 adds secondary channel offset element in the end. ++ if (Elem->MsgLen == (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE))) ++ { ++ RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE)); ++ } ++ else ++ { ++ Secondary.SecondaryChannelOffset = 0; ++ } ++ ++ if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3)) ++ { ++ ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset); ++ } ++#endif // DOT11N_DRAFT3 // ++} ++ PeerChSwAnnAction(pAd, Elem); ++ break; ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Parametrs: ++ ++ Return : None. ++ ========================================================================== ++ */ ++INT Set_MeasureReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT Aid = 1; ++ UINT ArgIdx; ++ PUCHAR thisChar; ++ ++ MEASURE_REQ_MODE MeasureReqMode; ++ UINT8 MeasureReqToken = RandomByte(pAd); ++ UINT8 MeasureReqType = RM_BASIC; ++ UINT8 MeasureCh = 1; ++ ++ ArgIdx = 1; ++ while ((thisChar = strsep((char **)&arg, "-")) != NULL) ++ { ++ switch(ArgIdx) ++ { ++ case 1: // Aid. ++ Aid = simple_strtol(thisChar, 0, 16); ++ break; ++ ++ case 2: // Measurement Request Type. ++ MeasureReqType = simple_strtol(thisChar, 0, 16); ++ if (MeasureReqType > 3) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType)); ++ return TRUE; ++ } ++ break; ++ ++ case 3: // Measurement channel. ++ MeasureCh = simple_strtol(thisChar, 0, 16); ++ break; ++ } ++ ArgIdx++; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh)); ++ if (!VALID_WCID(Aid)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ return TRUE; ++ } ++ ++ MeasureReqMode.word = 0; ++ MeasureReqMode.field.Enable = 1; ++ ++ MeasureReqInsert(pAd, MeasureReqToken); ++ ++ EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr, ++ MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000); ++ ++ return TRUE; ++} ++ ++INT Set_TpcReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT Aid; ++ ++ UINT8 TpcReqToken = RandomByte(pAd); ++ ++ Aid = simple_strtol(arg, 0, 16); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid)); ++ if (!VALID_WCID(Aid)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ return TRUE; ++ } ++ ++ TpcReqInsert(pAd, TpcReqToken); ++ ++ EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken); ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/config.mk +@@ -0,0 +1,245 @@ ++# Support ATE function ++HAS_ATE=n ++ ++# Support 28xx QA ATE function ++HAS_28xx_QA=n ++ ++# Support Wpa_Supplicant ++HAS_WPA_SUPPLICANT=n ++ ++# Support Native WpaSupplicant for Network Maganger ++HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=n ++ ++#Support Net interface block while Tx-Sw queue full ++HAS_BLOCK_NET_IF=n ++ ++#Support DFS function ++HAS_DFS_SUPPORT=n ++ ++#Support Carrier-Sense function ++HAS_CS_SUPPORT=n ++ ++#ifdef MULTI_CARD ++# Support for Multiple Cards ++HAS_MC_SUPPORT=n ++#endif // MULTI_CARD // ++ ++#Support for IEEE802.11e DLS ++HAS_QOS_DLS_SUPPORT=n ++ ++#Support for EXT_CHANNEL ++HAS_EXT_BUILD_CHANNEL_LIST=n ++ ++#Support for Net-SNMP ++HAS_SNMP_SUPPORT=n ++ ++#Support features of Single SKU. ++HAS_SINGLE_SKU_SUPPORT=n ++ ++#Support features of 802.11n ++HAS_DOT11_N_SUPPORT=y ++ ++ ++################################################# ++ ++CC := $(CROSS_COMPILE)gcc ++LD := $(CROSS_COMPILE)ld ++ ++WFLAGS := -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT -DLINUX -Wall -Wstrict-prototypes -Wno-trigraphs ++ ++ ++################################################# ++ ++#ifdef CONFIG_STA_SUPPORT ++# config for STA mode ++ ++ifeq ($(RT28xx_MODE),STA) ++WFLAGS += -DCONFIG_STA_SUPPORT -DDBG ++ ++ifeq ($(HAS_WPA_SUPPLICANT),y) ++WFLAGS += -DWPA_SUPPLICANT_SUPPORT ++endif ++ ++ifeq ($(HAS_NATIVE_WPA_SUPPLICANT_SUPPORT),y) ++WFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT ++endif ++ ++ifeq ($(HAS_ATE),y) ++WFLAGS += -DRALINK_ATE ++ifeq ($(HAS_28xx_QA),y) ++WFLAGS += -DRALINK_28xx_QA ++endif ++endif ++ ++ifeq ($(HAS_SNMP_SUPPORT),y) ++WFLAGS += -DSNMP_SUPPORT ++endif ++ ++ifeq ($(HAS_QOS_DLS_SUPPORT),y) ++WFLAGS += -DQOS_DLS_SUPPORT ++endif ++ ++ifeq ($(HAS_DOT11_N_SUPPORT),y) ++WFLAGS += -DDOT11_N_SUPPORT ++endif ++ ++ifeq ($(HAS_CS_SUPPORT),y) ++WFLAGS += -DCARRIER_DETECTION_SUPPORT ++endif ++ ++ifeq ($(HAS_SINGLE_SKU_SUPPORT),y) ++WFLAGS += -DSINGLE_SKU ++endif ++ ++endif ++# endif of ifeq ($(RT28xx_MODE),STA) ++#endif // CONFIG_STA_SUPPORT // ++ ++################################################# ++ ++################################################# ++ ++# ++# Common compiler flag ++# ++ ++ ++ifeq ($(HAS_EXT_BUILD_CHANNEL_LIST),y) ++WFLAGS += -DEXT_BUILD_CHANNEL_LIST ++endif ++ ++ifeq ($(CHIPSET),2860) ++WFLAGS +=-DRT2860 ++endif ++ ++ifeq ($(CHIPSET),2870) ++WFLAGS +=-DRT2870 ++endif ++ ++ifeq ($(PLATFORM),5VT) ++#WFLAGS += -DCONFIG_5VT_ENHANCE ++endif ++ ++ifeq ($(HAS_BLOCK_NET_IF),y) ++WFLAGS += -DBLOCK_NET_IF ++endif ++ ++ifeq ($(HAS_DFS_SUPPORT),y) ++WFLAGS += -DDFS_SUPPORT ++endif ++ ++#ifdef MULTI_CARD ++ifeq ($(HAS_MC_SUPPORT),y) ++WFLAGS += -DMULTIPLE_CARD_SUPPORT ++endif ++#endif // MULTI_CARD // ++ ++ifeq ($(HAS_LLTD),y) ++WFLAGS += -DLLTD_SUPPORT ++endif ++ ++ifeq ($(PLATFORM),IXP) ++WFLAGS += -DRT_BIG_ENDIAN ++endif ++ ++ifeq ($(PLATFORM),IKANOS_V160) ++WFLAGS += -DRT_BIG_ENDIAN -DIKANOS_VX_1X0 ++endif ++ ++ifeq ($(PLATFORM),IKANOS_V180) ++WFLAGS += -DRT_BIG_ENDIAN -DIKANOS_VX_1X0 ++endif ++ ++ifeq ($(PLATFORM),INF_TWINPASS) ++WFLAGS += -DRT_BIG_ENDIAN -DINF_TWINPASS ++endif ++ ++ifeq ($(PLATFORM),INF_DANUBE) ++WFLAGS += -DINF_DANUBE -DRT_BIG_ENDIAN ++endif ++ ++ifeq ($(PLATFORM),CAVM_OCTEON) ++WFLAGS += -DRT_BIG_ENDIAN ++endif ++ ++ifeq ($(PLATFORM),BRCM_6358) ++WFLAGS += -DRT_BIG_ENDIAN ++endif ++ ++ifeq ($(PLATFORM),INF_AMAZON_SE) ++#WFLAGS += -DRT_BIG_ENDIAN -DINF_AMAZON_SE -DBG_FT_SUPPORT ++WFLAGS += -DRT_BIG_ENDIAN -DINF_AMAZON_SE ++endif ++ ++#kernel build options for 2.4 ++# move to Makefile outside LINUX_SRC := /opt/star/kernel/linux-2.4.27-star ++ ++ifeq ($(PLATFORM),STAR) ++CFLAGS := -D__KERNEL__ -I$(LINUX_SRC)/include -I$(RT28xx_DIR)/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -Uarm -fno-common -pipe -mapcs-32 -D__LINUX_ARM_ARCH__=4 -march=armv4 -mshort-load-bytes -msoft-float -Uarm -DMODULE -DMODVERSIONS -include $(LINUX_SRC)/include/linux/modversions.h $(WFLAGS) ++ ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),SIGMA) ++CFLAGS := -D__KERNEL__ -I$(RT28xx_DIR)/include -I$(LINUX_SRC)/include -I$(LINUX_SRC)/include/asm/gcc -I$(LINUX_SRC)/include/asm-mips/mach-tango2 -I$(LINUX_SRC)/include/asm-mips/mach-tango2 -DEM86XX_CHIP=EM86XX_CHIPID_TANGO2 -DEM86XX_REVISION=6 -I$(LINUX_SRC)/include/asm-mips/mach-generic -I$(RT2860_DIR)/include -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -ffreestanding -O2 -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic -pipe -mabi=32 -march=mips32r2 -Wa,-32 -Wa,-march=mips32r2 -Wa,-mips32r2 -Wa,--trap -DMODULE $(WFLAGS) ++ ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),SIGMA_8622) ++CFLAGS := -D__KERNEL__ -I$(CROSS_COMPILE_INCLUDE)/include -I$(LINUX_SRC)/include -I$(RT28xx_DIR)/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-common -pipe -fno-builtin -D__linux__ -DNO_MM -mapcs-32 -march=armv4 -mtune=arm7tdmi -msoft-float -DMODULE -mshort-load-bytes -nostdinc -iwithprefix -DMODULE $(WFLAGS) ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),5VT) ++CFLAGS := -D__KERNEL__ -I$(LINUX_SRC)/include -I$(RT28xx_DIR)/include -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-omit-frame-pointer -mapcs -mno-sched-prolog -mabi=apcs-gnu -mno-thumb-interwork -D__LINUX_ARM_ARCH__=5 -march=armv5te -mtune=arm926ej-s --param max-inline-insns-single=40000 -Uarm -Wdeclaration-after-statement -Wno-pointer-sign -DMODULE $(WFLAGS) ++ ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),IKANOS_V160) ++CFLAGS := -D__KERNEL__ -I$(LINUX_SRC)/include -I$(LINUX_SRC)/include/asm/gcc -I$(LINUX_SRC)/include/asm-mips/mach-tango2 -I$(LINUX_SRC)/include/asm-mips/mach-tango2 -I$(LINUX_SRC)/include/asm-mips/mach-generic -I$(RT28xx_DIR)/include -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -ffreestanding -O2 -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic -pipe -march=lx4189 -Wa, -DMODULE $(WFLAGS) ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),IKANOS_V180) ++CFLAGS := -D__KERNEL__ -I$(LINUX_SRC)/include -I$(LINUX_SRC)/include/asm/gcc -I$(LINUX_SRC)/include/asm-mips/mach-tango2 -I$(LINUX_SRC)/include/asm-mips/mach-tango2 -I$(LINUX_SRC)/include/asm-mips/mach-generic -I$(RT28xx_DIR)/include -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -ffreestanding -O2 -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic -pipe -mips32r2 -Wa, -DMODULE $(WFLAGS) ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),INF_TWINPASS) ++CFLAGS := -D__KERNEL__ -DMODULE -I$(LINUX_SRC)/include -I$(RT28xx_DIR)/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -G 0 -mno-abicalls -fno-pic -march=4kc -mips32 -Wa,--trap -pipe -mlong-calls $(WFLAGS) ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),INF_DANUBE) ++CFLAGS := -I$(RT28xx_DIR)/include $(WFLAGS) -Wundef -fno-strict-aliasing -fno-common -ffreestanding -Os -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic -pipe -msoft-float -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -I$(LINUX_SRC)/include/asm-mips/mach-generic ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),BRCM_6358) ++CFLAGS := $(WFLAGS) -I$(RT28xx_DIR)/include -nostdinc -iwithprefix include -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -I $(LINUX_SRC)/include/asm/gcc -G 0 -mno-abicalls -fno-pic -pipe -finline-limit=100000 -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -I$(LINUX_SRC)/include/asm-mips/mach-bcm963xx -I$(LINUX_SRC)/include/asm-mips/mach-generic -Os -fomit-frame-pointer -Wdeclaration-after-statement -DMODULE -mlong-calls ++export CFLAGS ++endif ++ ++ifeq ($(PLATFORM),PC) ++ ifneq (,$(findstring 2.4,$(LINUX_SRC))) ++ # Linux 2.4 ++ CFLAGS := -D__KERNEL__ -I$(LINUX_SRC)/include -I$(RT28xx_DIR)/include -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe -mpreferred-stack-boundary=2 -march=i686 -DMODULE -DMODVERSIONS -include $(LINUX_SRC)/include/linux/modversions.h $(WFLAGS) ++ export CFLAGS ++ else ++ # Linux 2.6 ++ EXTRA_CFLAGS := $(WFLAGS) -I$(RT28xx_DIR)/include ++ endif ++endif ++ ++ifeq ($(PLATFORM),IXP) ++ EXTRA_CFLAGS := -v $(WFLAGS) -I$(RT28xx_DIR)/include -mbig-endian ++endif ++ ++ifeq ($(PLATFORM),CAVM_OCTEON) ++ EXTRA_CFLAGS := $(WFLAGS) -I$(RT28xx_DIR)/include \ ++ -mabi=64 $(WFLAGS) ++export CFLAGS ++endif ++ +--- /dev/null ++++ b/drivers/staging/rt2860/dfs.h +@@ -0,0 +1,100 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ dfs.h ++ ++ Abstract: ++ Support DFS function. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi 03-12-2007 created ++*/ ++ ++#define RADAR_PULSE 1 ++#define RADAR_WIDTH 2 ++ ++#define WIDTH_RD_IDLE 0 ++#define WIDTH_RD_CHECK 1 ++ ++ ++VOID BbpRadarDetectionStart( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BbpRadarDetectionStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RadarDetectionStart( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN CTS_Protect, ++ IN UINT8 CTSPeriod); ++ ++VOID RadarDetectionStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++BOOLEAN RadarChannelCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ch); ++ ++ULONG JapRadarType( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPBbpReadRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPReadRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPCleanRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPrepareRDCTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN ULONG Duration, ++ IN UCHAR RTSRate, ++ IN ULONG CTSBaseAddr, ++ IN UCHAR FrameGap); ++ ++VOID RTMPPrepareRadarDetectParams( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++INT Set_ChMovingTime_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_LongPulseRadarTh_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/Kconfig +@@ -0,0 +1,5 @@ ++config RT2860 ++ tristate "Ralink 2860 wireless support" ++ depends on PCI && X86 && WLAN_80211 ++ ---help--- ++ This is an experimental driver for the Ralink 2860 wireless chip. +--- /dev/null ++++ b/drivers/staging/rt2860/leap.h +@@ -0,0 +1,215 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ leap.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef __LEAP_H__ ++#define __LEAP_H__ ++ ++// Messages for Associate state machine ++#define LEAP_MACHINE_BASE 30 ++ ++#define LEAP_MSG_REQUEST_IDENTITY 31 ++#define LEAP_MSG_REQUEST_LEAP 32 ++#define LEAP_MSG_SUCCESS 33 ++#define LEAP_MSG_FAILED 34 ++#define LEAP_MSG_RESPONSE_LEAP 35 ++#define LEAP_MSG_EAPOLKEY 36 ++#define LEAP_MSG_UNKNOWN 37 ++#define LEAP_MSG 38 ++//! assoc state-machine states ++#define LEAP_IDLE 0 ++#define LEAP_WAIT_IDENTITY_REQUEST 1 ++#define LEAP_WAIT_CHANLLENGE_REQUEST 2 ++#define LEAP_WAIT_SUCCESS 3 ++#define LEAP_WAIT_CHANLLENGE_RESPONSE 4 ++#define LEAP_WAIT_EAPOLKEY 5 ++ ++#define LEAP_REASON_INVALID_AUTH 0x01 ++#define LEAP_REASON_AUTH_TIMEOUT 0x02 ++#define LEAP_REASON_CHALLENGE_FROM_AP_FAILED 0x03 ++#define LEAP_REASON_CHALLENGE_TO_AP_FAILED 0x04 ++ ++#define CISCO_AuthModeLEAP 0x80 ++#define CISCO_AuthModeLEAPNone 0x00 ++#define LEAP_AUTH_TIMEOUT 30000 ++#define LEAP_CHALLENGE_RESPONSE_LENGTH 24 ++#define LEAP_CHALLENGE_REQUEST_LENGTH 8 ++ ++typedef struct _LEAP_EAPOL_HEADER_ { ++ UCHAR Version; ++ UCHAR Type; ++ UCHAR Length[2]; ++} LEAP_EAPOL_HEADER, *PLEAP_EAPOL_HEADER; ++ ++typedef struct _LEAP_EAPOL_PACKET_ { ++ UCHAR Code; ++ UCHAR Identifier; ++ UCHAR Length[2]; ++ UCHAR Type; ++} LEAP_EAPOL_PACKET, *PLEAP_EAPOL_PACKET; ++ ++typedef struct _LEAP_EAP_CONTENTS_ { ++ UCHAR Version; ++ UCHAR Reserved; ++ UCHAR Length; ++} LEAP_EAP_CONTENTS, *PLEAP_EAP_CONTENTS; ++ ++/*** EAPOL key ***/ ++typedef struct _EAPOL_KEY_HEADER_ { ++ UCHAR Type; ++ UCHAR Length[2]; ++ UCHAR Counter[8]; ++ UCHAR IV[16]; ++ UCHAR Index; ++ UCHAR Signature[16]; ++} EAPOL_KEY_HEADER, *PEAPOL_KEY_HEADER; ++ ++BOOLEAN LeapMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT ULONG *MsgType); ++ ++VOID LeapMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr3); ++ ++VOID LeapStartAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapIdentityAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapPeerChallengeAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HashPwd( ++ IN PUCHAR pwd, ++ IN INT pwdlen, ++ OUT PUCHAR hash); ++ ++VOID PeerChallengeResponse( ++ IN PUCHAR szChallenge, ++ IN PUCHAR smbPasswd, ++ OUT PUCHAR szResponse); ++ ++VOID ParityKey( ++ OUT PUCHAR szOut, ++ IN PUCHAR szIn); ++ ++VOID DesKey( ++ OUT ULONG k[16][2], ++ IN PUCHAR key, ++ IN INT decrypt); ++ ++VOID Des( ++ IN ULONG ks[16][2], ++ OUT UCHAR block[8]); ++ ++VOID DesEncrypt( ++ IN PUCHAR szClear, ++ IN PUCHAR szKey, ++ OUT PUCHAR szOut); ++ ++VOID LeapNetworkChallengeAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapNetworkChallengeResponse( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HashpwdHash( ++ IN PUCHAR hash, ++ IN PUCHAR hashhash); ++ ++VOID ProcessSessionKey( ++ OUT PUCHAR SessionKey, ++ IN PUCHAR hash2, ++ IN PUCHAR ChallengeToRadius, ++ IN PUCHAR ChallengeResponseFromRadius, ++ IN PUCHAR ChallengeFromRadius, ++ IN PUCHAR ChallengeResponseToRadius); ++ ++VOID LeapEapolKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID RogueApTableInit( ++ IN ROGUEAP_TABLE *Tab); ++ ++ULONG RogueApTableSearch( ++ IN ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr); ++ ++VOID RogueApEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT ROGUEAP_ENTRY *pRogueAp, ++ IN PUCHAR pAddr, ++ IN UCHAR FaileCode); ++ ++ULONG RogueApTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr, ++ IN UCHAR FaileCode); ++ ++VOID RogueApTableDeleteEntry( ++ IN OUT ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr); ++ ++VOID LeapAuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LeapSendRogueAPReport( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN CCKMAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen); ++ ++#endif // __LEAP_H__ +--- /dev/null ++++ b/drivers/staging/rt2860/link_list.h +@@ -0,0 +1,134 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __LINK_LIST_H__ ++#define __LINK_LIST_H__ ++ ++typedef struct _LIST_ENTRY ++{ ++ struct _LIST_ENTRY *pNext; ++} LIST_ENTRY, *PLIST_ENTRY; ++ ++typedef struct _LIST_HEADR ++{ ++ PLIST_ENTRY pHead; ++ PLIST_ENTRY pTail; ++ UCHAR size; ++} LIST_HEADER, *PLIST_HEADER; ++ ++static inline VOID initList( ++ IN PLIST_HEADER pList) ++{ ++ pList->pHead = pList->pTail = NULL; ++ pList->size = 0; ++ return; ++} ++ ++static inline VOID insertTailList( ++ IN PLIST_HEADER pList, ++ IN PLIST_ENTRY pEntry) ++{ ++ pEntry->pNext = NULL; ++ if (pList->pTail) ++ pList->pTail->pNext = pEntry; ++ else ++ pList->pHead = pEntry; ++ pList->pTail = pEntry; ++ pList->size++; ++ ++ return; ++} ++ ++static inline PLIST_ENTRY removeHeadList( ++ IN PLIST_HEADER pList) ++{ ++ PLIST_ENTRY pNext; ++ PLIST_ENTRY pEntry; ++ ++ pEntry = pList->pHead; ++ if (pList->pHead != NULL) ++ { ++ pNext = pList->pHead->pNext; ++ pList->pHead = pNext; ++ if (pNext == NULL) ++ pList->pTail = NULL; ++ pList->size--; ++ } ++ return pEntry; ++} ++ ++static inline int getListSize( ++ IN PLIST_HEADER pList) ++{ ++ return pList->size; ++} ++ ++static inline PLIST_ENTRY delEntryList( ++ IN PLIST_HEADER pList, ++ IN PLIST_ENTRY pEntry) ++{ ++ PLIST_ENTRY pCurEntry; ++ PLIST_ENTRY pPrvEntry; ++ ++ if(pList->pHead == NULL) ++ return NULL; ++ ++ if(pEntry == pList->pHead) ++ { ++ pCurEntry = pList->pHead; ++ pList->pHead = pCurEntry->pNext; ++ ++ if(pList->pHead == NULL) ++ pList->pTail = NULL; ++ ++ pList->size--; ++ return pCurEntry; ++ } ++ ++ pPrvEntry = pList->pHead; ++ pCurEntry = pPrvEntry->pNext; ++ while(pCurEntry != NULL) ++ { ++ if (pEntry == pCurEntry) ++ { ++ pPrvEntry->pNext = pCurEntry->pNext; ++ ++ if(pEntry == pList->pTail) ++ pList->pTail = pPrvEntry; ++ ++ pList->size--; ++ break; ++ } ++ pPrvEntry = pCurEntry; ++ pCurEntry = pPrvEntry->pNext; ++ } ++ ++ return pCurEntry; ++} ++ ++#endif // ___LINK_LIST_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/Makefile +@@ -0,0 +1,41 @@ ++obj-$(CONFIG_RT2860) += rt2860sta.o ++ ++# TODO: all of these should be removed ++EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT ++EXTRA_CFLAGS += -DRT2860 ++EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT ++EXTRA_CFLAGS += -DDBG ++EXTRA_CFLAGS += -DDOT11_N_SUPPORT ++ ++rt2860sta-objs := \ ++ common/md5.o \ ++ common/mlme.o \ ++ common/rtmp_wep.o \ ++ common/action.o \ ++ common/cmm_data.o \ ++ common/rtmp_init.o \ ++ common/rtmp_tkip.o \ ++ common/cmm_sync.o \ ++ common/eeprom.o \ ++ common/cmm_sanity.o \ ++ common/cmm_info.o \ ++ common/cmm_wpa.o \ ++ common/dfs.o \ ++ common/spectrum.o \ ++ sta/assoc.o \ ++ sta/aironet.o \ ++ sta/auth.o \ ++ sta/auth_rsp.o \ ++ sta/sync.o \ ++ sta/sanity.o \ ++ sta/rtmp_data.o \ ++ sta/connect.o \ ++ sta/wpa.o \ ++ rt_linux.o \ ++ rt_profile.o \ ++ rt_main_dev.o \ ++ sta_ioctl.o \ ++ common/ba_action.o \ ++ common/2860_rtmp_init.o \ ++ 2860_main_dev.o \ ++ common/cmm_data_2860.o +--- /dev/null ++++ b/drivers/staging/rt2860/md4.h +@@ -0,0 +1,42 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __MD4_H__ ++#define __MD4_H__ ++ ++/* MD4 context. */ ++typedef struct _MD4_CTX_ { ++ ULONG state[4]; /* state (ABCD) */ ++ ULONG count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ UCHAR buffer[64]; /* input buffer */ ++} MD4_CTX; ++ ++VOID MD4Init (MD4_CTX *); ++VOID MD4Update (MD4_CTX *, PUCHAR, UINT); ++VOID MD4Final (UCHAR [16], MD4_CTX *); ++ ++#endif //__MD4_H__ +\ No newline at end of file +--- /dev/null ++++ b/drivers/staging/rt2860/md5.h +@@ -0,0 +1,107 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ md5.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ jan 10-28-03 Initial ++ Rita 11-23-04 Modify MD5 and SHA-1 ++*/ ++ ++#ifndef uint8 ++#define uint8 unsigned char ++#endif ++ ++#ifndef uint32 ++#define uint32 unsigned long int ++#endif ++ ++ ++#ifndef __MD5_H__ ++#define __MD5_H__ ++ ++#define MD5_MAC_LEN 16 ++ ++typedef struct _MD5_CTX { ++ UINT32 Buf[4]; // buffers of four states ++ UCHAR Input[64]; // input message ++ UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits ++} MD5_CTX; ++ ++VOID MD5Init(MD5_CTX *pCtx); ++VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); ++VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx); ++VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]); ++ ++void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); ++void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); ++ ++// ++// SHA context ++// ++typedef struct _SHA_CTX ++{ ++ UINT32 Buf[5]; // buffers of five states ++ UCHAR Input[80]; // input message ++ UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits ++ ++} SHA_CTX; ++ ++VOID SHAInit(SHA_CTX *pCtx); ++UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); ++VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]); ++VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]); ++ ++#define SHA_DIGEST_LEN 20 ++#endif // __MD5_H__ ++ ++/******************************************************************************/ ++#ifndef _AES_H ++#define _AES_H ++ ++typedef struct ++{ ++ uint32 erk[64]; /* encryption round keys */ ++ uint32 drk[64]; /* decryption round keys */ ++ int nr; /* number of rounds */ ++} ++aes_context; ++ ++int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ); ++void rtmp_aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); ++void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); ++ ++void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output); ++int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output); ++ ++#endif /* aes.h */ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/mlme.h +@@ -0,0 +1,1447 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ mlme.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2003-08-28 Created ++ John Chang 2004-09-06 modified for RT2600 ++ ++*/ ++#ifndef __MLME_H__ ++#define __MLME_H__ ++ ++// maximum supported capability information - ++// ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot ++#define SUPPORTED_CAPABILITY_INFO 0x0533 ++ ++#define END_OF_ARGS -1 ++#define LFSR_MASK 0x80000057 ++#define MLME_TASK_EXEC_INTV 100/*200*/ // ++#define LEAD_TIME 5 ++#define MLME_TASK_EXEC_MULTIPLE 10 /*5*/ // MLME_TASK_EXEC_MULTIPLE * MLME_TASK_EXEC_INTV = 1 sec ++#define REORDER_EXEC_INTV 100 // 0.1 sec ++ ++// The definition of Radar detection duration region ++#define CE 0 ++#define FCC 1 ++#define JAP 2 ++#define JAP_W53 3 ++#define JAP_W56 4 ++#define MAX_RD_REGION 5 ++ ++#ifdef NDIS51_MINIPORT ++#define BEACON_LOST_TIME 4000 // 2048 msec = 2 sec ++#else ++#define BEACON_LOST_TIME 4 * OS_HZ // 2048 msec = 2 sec ++#endif ++ ++#define DLS_TIMEOUT 1200 // unit: msec ++#define AUTH_TIMEOUT 300 // unit: msec ++#define ASSOC_TIMEOUT 300 // unit: msec ++#define JOIN_TIMEOUT 2 * OS_HZ // unit: msec ++#define SHORT_CHANNEL_TIME 90 // unit: msec ++#define MIN_CHANNEL_TIME 110 // unit: msec, for dual band scan ++#define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan ++#define FAST_ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time ++#define CW_MIN_IN_BITS 4 // actual CwMin = 2^CW_MIN_IN_BITS - 1 ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifndef CONFIG_AP_SUPPORT ++#define CW_MAX_IN_BITS 10 // actual CwMax = 2^CW_MAX_IN_BITS - 1 ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++extern UINT32 CW_MAX_IN_BITS; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++// Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). ++// SHould not refer to this constant anymore ++//#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm ++#define RSSI_FOR_MID_TX_POWER -55 // -55 db is considered mid-distance ++#define RSSI_FOR_LOW_TX_POWER -45 // -45 db is considered very short distance and ++ // eligible to use a lower TX power ++#define RSSI_FOR_LOWEST_TX_POWER -30 ++//#define MID_TX_POWER_DELTA 0 // 0 db from full TX power upon mid-distance to AP ++#define LOW_TX_POWER_DELTA 6 // -3 db from full TX power upon very short distance. 1 grade is 0.5 db ++#define LOWEST_TX_POWER_DELTA 16 // -8 db from full TX power upon shortest distance. 1 grade is 0.5 db ++ ++#define RSSI_TRIGGERED_UPON_BELOW_THRESHOLD 0 ++#define RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD 1 ++#define RSSI_THRESHOLD_FOR_ROAMING 25 ++#define RSSI_DELTA 5 ++ ++// Channel Quality Indication ++#define CQI_IS_GOOD(cqi) ((cqi) >= 50) ++//#define CQI_IS_FAIR(cqi) (((cqi) >= 20) && ((cqi) < 50)) ++#define CQI_IS_POOR(cqi) (cqi < 50) //(((cqi) >= 5) && ((cqi) < 20)) ++#define CQI_IS_BAD(cqi) (cqi < 5) ++#define CQI_IS_DEAD(cqi) (cqi == 0) ++ ++// weighting factor to calculate Channel quality, total should be 100% ++#define RSSI_WEIGHTING 50 ++#define TX_WEIGHTING 30 ++#define RX_WEIGHTING 20 ++ ++#define BSS_NOT_FOUND 0xFFFFFFFF ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define MAX_LEN_OF_MLME_QUEUE 40 //10 ++#endif // CONFIG_STA_SUPPORT // ++ ++#define SCAN_PASSIVE 18 // scan with no probe request, only wait beacon and probe response ++#define SCAN_ACTIVE 19 // scan with probe request, and wait beacon and probe response ++#define SCAN_CISCO_PASSIVE 20 // Single channel passive scan ++#define SCAN_CISCO_ACTIVE 21 // Single channel active scan ++#define SCAN_CISCO_NOISE 22 // Single channel passive scan for noise histogram collection ++#define SCAN_CISCO_CHANNEL_LOAD 23 // Single channel passive scan for channel load collection ++#define FAST_SCAN_ACTIVE 24 // scan with probe request, and wait beacon and probe response ++ ++#ifdef DOT11N_DRAFT3 ++#define SCAN_2040_BSS_COEXIST 26 ++#endif // DOT11N_DRAFT3 // ++ ++#define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01)) ++#define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) ++#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) ++#define TID_MAC_HASH(Addr,TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) ++#define TID_MAC_HASH_INDEX(Addr,TID) (TID_MAC_HASH(Addr,TID) % HASH_TABLE_SIZE) ++ ++// LED Control ++// assoiation ON. one LED ON. another blinking when TX, OFF when idle ++// no association, both LED off ++#define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46) ++#define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46) ++ ++// bit definition of the 2-byte pBEACON->Capability field ++#define CAP_IS_ESS_ON(x) (((x) & 0x0001) != 0) ++#define CAP_IS_IBSS_ON(x) (((x) & 0x0002) != 0) ++#define CAP_IS_CF_POLLABLE_ON(x) (((x) & 0x0004) != 0) ++#define CAP_IS_CF_POLL_REQ_ON(x) (((x) & 0x0008) != 0) ++#define CAP_IS_PRIVACY_ON(x) (((x) & 0x0010) != 0) ++#define CAP_IS_SHORT_PREAMBLE_ON(x) (((x) & 0x0020) != 0) ++#define CAP_IS_PBCC_ON(x) (((x) & 0x0040) != 0) ++#define CAP_IS_AGILITY_ON(x) (((x) & 0x0080) != 0) ++#define CAP_IS_SPECTRUM_MGMT(x) (((x) & 0x0100) != 0) // 802.11e d9 ++#define CAP_IS_QOS(x) (((x) & 0x0200) != 0) // 802.11e d9 ++#define CAP_IS_SHORT_SLOT(x) (((x) & 0x0400) != 0) ++#define CAP_IS_APSD(x) (((x) & 0x0800) != 0) // 802.11e d9 ++#define CAP_IS_IMMED_BA(x) (((x) & 0x1000) != 0) // 802.11e d9 ++#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0) ++#define CAP_IS_DELAY_BA(x) (((x) & 0x4000) != 0) // 802.11e d9 ++ ++#define CAP_GENERATE(ess,ibss,priv,s_pre,s_slot,spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000)) ++ ++#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) // 802.11g ++#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) // 802.11g ++#define ERP_IS_USE_BARKER_PREAMBLE(x) (((x) & 0x04) != 0) // 802.11g ++ ++#define DRS_TX_QUALITY_WORST_BOUND 8// 3 // just test by gary ++#define DRS_PENALTY 8 ++ ++#define BA_NOTUSE 2 ++//BA Policy subfiled value in ADDBA frame ++#define IMMED_BA 1 ++#define DELAY_BA 0 ++ ++// BA Initiator subfield in DELBA frame ++#define ORIGINATOR 1 ++#define RECIPIENT 0 ++ ++// ADDBA Status Code ++#define ADDBA_RESULTCODE_SUCCESS 0 ++#define ADDBA_RESULTCODE_REFUSED 37 ++#define ADDBA_RESULTCODE_INVALID_PARAMETERS 38 ++ ++// DELBA Reason Code ++#define DELBA_REASONCODE_QSTA_LEAVING 36 ++#define DELBA_REASONCODE_END_BA 37 ++#define DELBA_REASONCODE_UNKNOWN_BA 38 ++#define DELBA_REASONCODE_TIMEOUT 39 ++ ++// reset all OneSecTx counters ++#define RESET_ONE_SEC_TX_CNT(__pEntry) \ ++if (((__pEntry)) != NULL) \ ++{ \ ++ (__pEntry)->OneSecTxRetryOkCount = 0; \ ++ (__pEntry)->OneSecTxFailCount = 0; \ ++ (__pEntry)->OneSecTxNoRetryOkCount = 0; \ ++} ++ ++// ++// 802.11 frame formats ++// ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT LSIGTxopProSup:1; ++ USHORT Forty_Mhz_Intolerant:1; ++ USHORT PSMP:1; ++ USHORT CCKmodein40:1; ++ USHORT AMsduSize:1; ++ USHORT DelayedBA:1; //rt2860c not support ++ USHORT RxSTBC:2; ++ USHORT TxSTBC:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT ShortGIfor20:1; ++ USHORT GF:1; //green field ++ USHORT MimoPs:2;//momi power safe ++ USHORT ChannelWidth:1; ++ USHORT AdvCoding:1; ++#else ++ USHORT AdvCoding:1; ++ USHORT ChannelWidth:1; ++ USHORT MimoPs:2;//momi power safe ++ USHORT GF:1; //green field ++ USHORT ShortGIfor20:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT TxSTBC:1; ++ USHORT RxSTBC:2; ++ USHORT DelayedBA:1; //rt2860c not support ++ USHORT AMsduSize:1; // only support as zero ++ USHORT CCKmodein40:1; ++ USHORT PSMP:1; ++ USHORT Forty_Mhz_Intolerant:1; ++ USHORT LSIGTxopProSup:1; ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CAP_INFO, *PHT_CAP_INFO; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:3;//momi power safe ++ UCHAR MpduDensity:3; ++ UCHAR MaxRAmpduFactor:2; ++#else ++ UCHAR MaxRAmpduFactor:2; ++ UCHAR MpduDensity:3; ++ UCHAR rsv:3;//momi power safe ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CAP_PARM, *PHT_CAP_PARM; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++ UCHAR MCSSet[10]; ++ UCHAR SupRate[2]; // unit : 1Mbps ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:3; ++ UCHAR MpduDensity:1; ++ UCHAR TxStream:2; ++ UCHAR TxRxNotEqual:1; ++ UCHAR TxMCSSetDefined:1; ++#else ++ UCHAR TxMCSSetDefined:1; ++ UCHAR TxRxNotEqual:1; ++ UCHAR TxStream:2; ++ UCHAR MpduDensity:1; ++ UCHAR rsv:3; ++#endif // RT_BIG_ENDIAN // ++ UCHAR rsv3[3]; ++} HT_MCS_SET, *PHT_MCS_SET; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:4; ++ USHORT RDGSupport:1; //reverse Direction Grant support ++ USHORT PlusHTC:1; //+HTC control field support ++ USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. ++ USHORT rsv:5;//momi power safe ++ USHORT TranTime:2; ++ USHORT Pco:1; ++#else ++ USHORT Pco:1; ++ USHORT TranTime:2; ++ USHORT rsv:5;//momi power safe ++ USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. ++ USHORT PlusHTC:1; //+HTC control field support ++ USHORT RDGSupport:1; //reverse Direction Grant support ++ USHORT rsv2:4; ++#endif /* RT_BIG_ENDIAN */ ++} EXT_HT_CAP_INFO, *PEXT_HT_CAP_INFO; ++ ++// HT Beamforming field in HT Cap IE . ++typedef struct PACKED _HT_BF_CAP{ ++#ifdef RT_BIG_ENDIAN ++ ULONG rsv:3; ++ ULONG ChanEstimation:2; ++ ULONG CSIRowBFSup:2; ++ ULONG ComSteerBFAntSup:2; ++ ULONG NoComSteerBFAntSup:2; ++ ULONG CSIBFAntSup:2; ++ ULONG MinGrouping:2; ++ ULONG ExpComBF:2; ++ ULONG ExpNoComBF:2; ++ ULONG ExpCSIFbk:2; ++ ULONG ExpComSteerCapable:1; ++ ULONG ExpNoComSteerCapable:1; ++ ULONG ExpCSICapable:1; ++ ULONG Calibration:2; ++ ULONG ImpTxBFCapable:1; ++ ULONG TxNDPCapable:1; ++ ULONG RxNDPCapable:1; ++ ULONG TxSoundCapable:1; ++ ULONG RxSoundCapable:1; ++ ULONG TxBFRecCapable:1; ++#else ++ ULONG TxBFRecCapable:1; ++ ULONG RxSoundCapable:1; ++ ULONG TxSoundCapable:1; ++ ULONG RxNDPCapable:1; ++ ULONG TxNDPCapable:1; ++ ULONG ImpTxBFCapable:1; ++ ULONG Calibration:2; ++ ULONG ExpCSICapable:1; ++ ULONG ExpNoComSteerCapable:1; ++ ULONG ExpComSteerCapable:1; ++ ULONG ExpCSIFbk:2; ++ ULONG ExpNoComBF:2; ++ ULONG ExpComBF:2; ++ ULONG MinGrouping:2; ++ ULONG CSIBFAntSup:2; ++ ULONG NoComSteerBFAntSup:2; ++ ULONG ComSteerBFAntSup:2; ++ ULONG CSIRowBFSup:2; ++ ULONG ChanEstimation:2; ++ ULONG rsv:3; ++#endif // RT_BIG_ENDIAN // ++} HT_BF_CAP, *PHT_BF_CAP; ++ ++// HT antenna selection field in HT Cap IE . ++typedef struct PACKED _HT_AS_CAP{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:1; ++ UCHAR TxSoundPPDU:1; ++ UCHAR RxASel:1; ++ UCHAR AntIndFbk:1; ++ UCHAR ExpCSIFbk:1; ++ UCHAR AntIndFbkTxASEL:1; ++ UCHAR ExpCSIFbkTxASEL:1; ++ UCHAR AntSelect:1; ++#else ++ UCHAR AntSelect:1; ++ UCHAR ExpCSIFbkTxASEL:1; ++ UCHAR AntIndFbkTxASEL:1; ++ UCHAR ExpCSIFbk:1; ++ UCHAR AntIndFbk:1; ++ UCHAR RxASel:1; ++ UCHAR TxSoundPPDU:1; ++ UCHAR rsv:1; ++#endif // RT_BIG_ENDIAN // ++} HT_AS_CAP, *PHT_AS_CAP; ++ ++// Draft 1.0 set IE length 26, but is extensible.. ++#define SIZE_HT_CAP_IE 26 ++// The structure for HT Capability IE. ++typedef struct PACKED _HT_CAPABILITY_IE{ ++ HT_CAP_INFO HtCapInfo; ++ HT_CAP_PARM HtCapParm; ++// HT_MCS_SET HtMCSSet; ++ UCHAR MCSSet[16]; ++ EXT_HT_CAP_INFO ExtHtCapInfo; ++ HT_BF_CAP TxBFCap; // beamforming cap. rt2860c not support beamforming. ++ HT_AS_CAP ASCap; //antenna selection. ++} HT_CAPABILITY_IE, *PHT_CAPABILITY_IE; ++ ++ ++// 802.11n draft3 related structure definitions. ++// 7.3.2.60 ++#define dot11OBSSScanPassiveDwell 20 // in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. ++#define dot11OBSSScanActiveDwell 10 // in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. ++#define dot11BSSWidthTriggerScanInterval 300 // in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. ++#define dot11OBSSScanPassiveTotalPerChannel 200 // in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. ++#define dot11OBSSScanActiveTotalPerChannel 20 //in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan ++#define dot11BSSWidthChannelTransactionDelayFactor 5 // min ratio between the delay time in performing a switch from 20MHz BSS to 20/40 BSS operation and the maxima ++ // interval between overlapping BSS scan operations. ++#define dot11BSSScanActivityThreshold 25 // in %%, max total time that a STA may be active on the medium during a period of ++ // (dot11BSSWidthChannelTransactionDelayFactor * dot11BSSWidthTriggerScanInterval) seconds without ++ // being obligated to perform OBSS Scan operations. default is 25(== 0.25%) ++ ++typedef struct PACKED _OVERLAP_BSS_SCAN_IE{ ++ USHORT ScanPassiveDwell; ++ USHORT ScanActiveDwell; ++ USHORT TriggerScanInt; // Trigger scan interval ++ USHORT PassiveTalPerChannel; // passive total per channel ++ USHORT ActiveTalPerChannel; // active total per channel ++ USHORT DelayFactor; // BSS width channel transition delay factor ++ USHORT ScanActThre; // Scan Activity threshold ++}OVERLAP_BSS_SCAN_IE, *POVERLAP_BSS_SCAN_IE; ++ ++ ++// 7.3.2.56. 20/40 Coexistence element used in Element ID = 72 = IE_2040_BSS_COEXIST ++typedef union PACKED _BSS_2040_COEXIST_IE{ ++ struct PACKED { ++ #ifdef RT_BIG_ENDIAN ++ UCHAR rsv:5; ++ UCHAR BSS20WidthReq:1; ++ UCHAR Intolerant40:1; ++ UCHAR InfoReq:1; ++ #else ++ UCHAR InfoReq:1; ++ UCHAR Intolerant40:1; // Inter-BSS. set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS. ++ UCHAR BSS20WidthReq:1; // Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS. ++ UCHAR rsv:5; ++#endif // RT_BIG_ENDIAN // ++ } field; ++ UCHAR word; ++} BSS_2040_COEXIST_IE, *PBSS_2040_COEXIST_IE; ++ ++ ++typedef struct _TRIGGER_EVENTA{ ++ BOOLEAN bValid; ++ UCHAR BSSID[6]; ++ UCHAR RegClass; // Regulatory Class ++ USHORT Channel; ++ ULONG CDCounter; // Maintain a seperate count down counter for each Event A. ++} TRIGGER_EVENTA, *PTRIGGER_EVENTA; ++ ++// 20/40 trigger event table ++// If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. ++#define MAX_TRIGGER_EVENT 64 ++typedef struct _TRIGGER_EVENT_TAB{ ++ UCHAR EventANo; ++ TRIGGER_EVENTA EventA[MAX_TRIGGER_EVENT]; ++ ULONG EventBCountDown; // Count down counter for Event B. ++} TRIGGER_EVENT_TAB, *PTRIGGER_EVENT_TAB; ++ ++// 7.3.27 20/40 Bss Coexistence Mgmt capability used in extended capabilities information IE( ID = 127 = IE_EXT_CAPABILITY). ++// This is the first octet and was defined in 802.11n D3.03 and 802.11yD9.0 ++typedef struct PACKED _EXT_CAP_INFO_ELEMENT{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv2:5; ++ UCHAR ExtendChannelSwitch:1; ++ UCHAR rsv:1; ++ UCHAR BssCoexistMgmtSupport:1; ++#else ++ UCHAR BssCoexistMgmtSupport:1; ++ UCHAR rsv:1; ++ UCHAR ExtendChannelSwitch:1; ++ UCHAR rsv2:5; ++#endif // RT_BIG_ENDIAN // ++}EXT_CAP_INFO_ELEMENT, *PEXT_CAP_INFO_ELEMENT; ++ ++ ++// 802.11n 7.3.2.61 ++typedef struct PACKED _BSS_2040_COEXIST_ELEMENT{ ++ UCHAR ElementID; // ID = IE_2040_BSS_COEXIST = 72 ++ UCHAR Len; ++ BSS_2040_COEXIST_IE BssCoexistIe; ++}BSS_2040_COEXIST_ELEMENT, *PBSS_2040_COEXIST_ELEMENT; ++ ++ ++//802.11n 7.3.2.59 ++typedef struct PACKED _BSS_2040_INTOLERANT_CH_REPORT{ ++ UCHAR ElementID; // ID = IE_2040_BSS_INTOLERANT_REPORT = 73 ++ UCHAR Len; ++ UCHAR RegulatoryClass; ++ UCHAR ChList[0]; ++}BSS_2040_INTOLERANT_CH_REPORT, *PBSS_2040_INTOLERANT_CH_REPORT; ++ ++ ++// The structure for channel switch annoucement IE. This is in 802.11n D3.03 ++typedef struct PACKED _CHA_SWITCH_ANNOUNCE_IE{ ++ UCHAR SwitchMode; //channel switch mode ++ UCHAR NewChannel; // ++ UCHAR SwitchCount; // ++} CHA_SWITCH_ANNOUNCE_IE, *PCHA_SWITCH_ANNOUNCE_IE; ++ ++ ++// The structure for channel switch annoucement IE. This is in 802.11n D3.03 ++typedef struct PACKED _SEC_CHA_OFFSET_IE{ ++ UCHAR SecondaryChannelOffset; // 1: Secondary above, 3: Secondary below, 0: no Secondary ++} SEC_CHA_OFFSET_IE, *PSEC_CHA_OFFSET_IE; ++ ++ ++// This structure is extracted from struct RT_HT_CAPABILITY ++typedef struct { ++ BOOLEAN bHtEnable; // If we should use ht rate. ++ BOOLEAN bPreNHt; // If we should use ht rate. ++ //Substract from HT Capability IE ++ UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , ++} RT_HT_PHY_INFO, *PRT_HT_PHY_INFO; ++ ++//This structure substracts ralink supports from all 802.11n-related features. ++//Features not listed here but contained in 802.11n spec are not supported in rt2860. ++typedef struct { ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv:5; ++ USHORT AmsduSize:1; // Max receiving A-MSDU size ++ USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n ++ USHORT RxSTBC:2; // 2 bits ++ USHORT TxSTBC:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT ShortGIfor20:1; ++ USHORT GF:1; //green field ++ USHORT MimoPs:2;//mimo power safe MMPS_ ++ USHORT ChannelWidth:1; ++#else ++ USHORT ChannelWidth:1; ++ USHORT MimoPs:2;//mimo power safe MMPS_ ++ USHORT GF:1; //green field ++ USHORT ShortGIfor20:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT TxSTBC:1; ++ USHORT RxSTBC:2; // 2 bits ++ USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n ++ USHORT AmsduSize:1; // Max receiving A-MSDU size ++ USHORT rsv:5; ++#endif ++ ++ //Substract from Addiont HT INFO IE ++#ifdef RT_BIG_ENDIAN ++ UCHAR RecomWidth:1; ++ UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n ++ UCHAR MpduDensity:3; ++ UCHAR MaxRAmpduFactor:2; ++#else ++ UCHAR MaxRAmpduFactor:2; ++ UCHAR MpduDensity:3; ++ UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n ++ UCHAR RecomWidth:1; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:11; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv3:1; ++ USHORT NonGfPresent:1; ++ USHORT OperaionMode:2; ++#else ++ USHORT OperaionMode:2; ++ USHORT NonGfPresent:1; ++ USHORT rsv3:1; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv2:11; ++#endif ++ ++ // New Extension Channel Offset IE ++ UCHAR NewExtChannelOffset; ++ // Extension Capability IE = 127 ++ UCHAR BSSCoexist2040; ++} RT_HT_CAPABILITY, *PRT_HT_CAPABILITY; ++ ++// field in Addtional HT Information IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR SerInterGranu:3; ++ UCHAR S_PSMPSup:1; ++ UCHAR RifsMode:1; ++ UCHAR RecomWidth:1; ++ UCHAR ExtChanOffset:2; ++#else ++ UCHAR ExtChanOffset:2; ++ UCHAR RecomWidth:1; ++ UCHAR RifsMode:1; ++ UCHAR S_PSMPSup:1; //Indicate support for scheduled PSMP ++ UCHAR SerInterGranu:3; //service interval granularity ++#endif ++} ADD_HTINFO, *PADD_HTINFO; ++ ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:11; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv:1; ++ USHORT NonGfPresent:1; ++ USHORT OperaionMode:2; ++#else ++ USHORT OperaionMode:2; ++ USHORT NonGfPresent:1; ++ USHORT rsv:1; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv2:11; ++#endif ++} ADD_HTINFO2, *PADD_HTINFO2; ++ ++ ++// TODO: Need sync with spec about the definition of StbcMcs. In Draft 3.03, it's reserved. ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv:4; ++ USHORT PcoPhase:1; ++ USHORT PcoActive:1; ++ USHORT LsigTxopProt:1; ++ USHORT STBCBeacon:1; ++ USHORT DualCTSProtect:1; ++ USHORT DualBeacon:1; ++ USHORT StbcMcs:6; ++#else ++ USHORT StbcMcs:6; ++ USHORT DualBeacon:1; ++ USHORT DualCTSProtect:1; ++ USHORT STBCBeacon:1; ++ USHORT LsigTxopProt:1; // L-SIG TXOP protection full support ++ USHORT PcoActive:1; ++ USHORT PcoPhase:1; ++ USHORT rsv:4; ++#endif // RT_BIG_ENDIAN // ++} ADD_HTINFO3, *PADD_HTINFO3; ++ ++#define SIZE_ADD_HT_INFO_IE 22 ++typedef struct PACKED{ ++ UCHAR ControlChan; ++ ADD_HTINFO AddHtInfo; ++ ADD_HTINFO2 AddHtInfo2; ++ ADD_HTINFO3 AddHtInfo3; ++ UCHAR MCSSet[16]; // Basic MCS set ++} ADD_HT_INFO_IE, *PADD_HT_INFO_IE; ++ ++typedef struct PACKED{ ++ UCHAR NewExtChanOffset; ++} NEW_EXT_CHAN_IE, *PNEW_EXT_CHAN_IE; ++ ++ ++// 4-byte HTC field. maybe included in any frame except non-QOS data frame. The Order bit must set 1. ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UINT32 RDG:1; //RDG / More PPDU ++ UINT32 ACConstraint:1; //feedback request ++ UINT32 rsv:5; //calibration sequence ++ UINT32 ZLFAnnouce:1; // ZLF announcement ++ UINT32 CSISTEERING:2; //CSI/ STEERING ++ UINT32 FBKReq:2; //feedback request ++ UINT32 CalSeq:2; //calibration sequence ++ UINT32 CalPos:2; // calibration position ++ UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available ++ UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. ++ UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. ++ UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback ++ UINT32 TRQ:1; //sounding request ++ UINT32 MA:1; //management action payload exist in (QoS Null+HTC) ++#else ++ UINT32 MA:1; //management action payload exist in (QoS Null+HTC) ++ UINT32 TRQ:1; //sounding request ++ UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback ++ UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. ++ UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. ++ UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available ++ UINT32 CalPos:2; // calibration position ++ UINT32 CalSeq:2; //calibration sequence ++ UINT32 FBKReq:2; //feedback request ++ UINT32 CSISTEERING:2; //CSI/ STEERING ++ UINT32 ZLFAnnouce:1; // ZLF announcement ++ UINT32 rsv:5; //calibration sequence ++ UINT32 ACConstraint:1; //feedback request ++ UINT32 RDG:1; //RDG / More PPDU ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CONTROL, *PHT_CONTROL; ++ ++// 2-byte QOS CONTROL field ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Txop_QueueSize:8; ++ USHORT AMsduPresent:1; ++ USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA ++ USHORT EOSP:1; ++ USHORT TID:4; ++#else ++ USHORT TID:4; ++ USHORT EOSP:1; ++ USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA ++ USHORT AMsduPresent:1; ++ USHORT Txop_QueueSize:8; ++#endif /* !RT_BIG_ENDIAN */ ++} QOS_CONTROL, *PQOS_CONTROL; ++ ++// 2-byte Frame control field ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Order:1; // Strict order expected ++ USHORT Wep:1; // Wep data ++ USHORT MoreData:1; // More data bit ++ USHORT PwrMgmt:1; // Power management bit ++ USHORT Retry:1; // Retry status bit ++ USHORT MoreFrag:1; // More fragment bit ++ USHORT FrDs:1; // From DS indication ++ USHORT ToDs:1; // To DS indication ++ USHORT SubType:4; // MSDU subtype ++ USHORT Type:2; // MSDU type ++ USHORT Ver:2; // Protocol version ++#else ++ USHORT Ver:2; // Protocol version ++ USHORT Type:2; // MSDU type ++ USHORT SubType:4; // MSDU subtype ++ USHORT ToDs:1; // To DS indication ++ USHORT FrDs:1; // From DS indication ++ USHORT MoreFrag:1; // More fragment bit ++ USHORT Retry:1; // Retry status bit ++ USHORT PwrMgmt:1; // Power management bit ++ USHORT MoreData:1; // More data bit ++ USHORT Wep:1; // Wep data ++ USHORT Order:1; // Strict order expected ++#endif /* !RT_BIG_ENDIAN */ ++} FRAME_CONTROL, *PFRAME_CONTROL; ++ ++typedef struct PACKED _HEADER_802_11 { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR Addr3[MAC_ADDR_LEN]; ++#ifdef RT_BIG_ENDIAN ++ USHORT Sequence:12; ++ USHORT Frag:4; ++#else ++ USHORT Frag:4; ++ USHORT Sequence:12; ++#endif /* !RT_BIG_ENDIAN */ ++ UCHAR Octet[0]; ++} HEADER_802_11, *PHEADER_802_11; ++ ++typedef struct PACKED _FRAME_802_11 { ++ HEADER_802_11 Hdr; ++ UCHAR Octet[1]; ++} FRAME_802_11, *PFRAME_802_11; ++ ++// QoSNull embedding of management action. When HT Control MA field set to 1. ++typedef struct PACKED _MA_BODY { ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Octet[1]; ++} MA_BODY, *PMA_BODY; ++ ++typedef struct PACKED _HEADER_802_3 { ++ UCHAR DAAddr1[MAC_ADDR_LEN]; ++ UCHAR SAAddr2[MAC_ADDR_LEN]; ++ UCHAR Octet[2]; ++} HEADER_802_3, *PHEADER_802_3; ++////Block ACK related format ++// 2-byte BA Parameter field in DELBA frames to terminate an already set up bA ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; // value of TC os TS ++ USHORT Initiator:1; // 1: originator 0:recipient ++ USHORT Rsv:11; // always set to 0 ++#else ++ USHORT Rsv:11; // always set to 0 ++ USHORT Initiator:1; // 1: originator 0:recipient ++ USHORT TID:4; // value of TC os TS ++#endif /* !RT_BIG_ENDIAN */ ++} DELBA_PARM, *PDELBA_PARM; ++ ++// 2-byte BA Parameter Set field in ADDBA frames to signal parm for setting up a BA ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT BufSize:10; // number of buffe of size 2304 octetsr ++ USHORT TID:4; // value of TC os TS ++ USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA ++ USHORT AMSDUSupported:1; // 0: not permitted 1: permitted ++#else ++ USHORT AMSDUSupported:1; // 0: not permitted 1: permitted ++ USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA ++ USHORT TID:4; // value of TC os TS ++ USHORT BufSize:10; // number of buffe of size 2304 octetsr ++#endif /* !RT_BIG_ENDIAN */ ++} BA_PARM, *PBA_PARM; ++ ++// 2-byte BA Starting Seq CONTROL field ++typedef union PACKED { ++ struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent ++ USHORT FragNum:4; // always set to 0 ++#else ++ USHORT FragNum:4; // always set to 0 ++ USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent ++#endif /* RT_BIG_ENDIAN */ ++ } field; ++ USHORT word; ++} BASEQ_CONTROL, *PBASEQ_CONTROL; ++ ++//BAControl and BARControl are the same ++// 2-byte BA CONTROL field in BA frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; //EWC V1.24 ++ USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK ++#else ++ USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK ++ USHORT MTID:1; //EWC V1.24 ++ USHORT Compressed:1; ++ USHORT Rsv:9; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} BA_CONTROL, *PBA_CONTROL; ++ ++// 2-byte BAR CONTROL field in BAR frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv1:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ ++ USHORT ACKPolicy:1; ++#else ++ USHORT ACKPolicy:1; // 0:normal ack, 1:no ack. ++ USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ ++ USHORT Compressed:1; ++ USHORT Rsv1:9; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} BAR_CONTROL, *PBAR_CONTROL; ++ ++// BARControl in MTBAR frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT NumTID:4; ++ USHORT Rsv1:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; ++ USHORT ACKPolicy:1; ++#else ++ USHORT ACKPolicy:1; ++ USHORT MTID:1; ++ USHORT Compressed:1; ++ USHORT Rsv1:9; ++ USHORT NumTID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} MTBAR_CONTROL, *PMTBAR_CONTROL; ++ ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv1:12; ++#else ++ USHORT Rsv1:12; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} PER_TID_INFO, *PPER_TID_INFO; ++ ++typedef struct { ++ PER_TID_INFO PerTID; ++ BASEQ_CONTROL BAStartingSeq; ++} EACH_TID, *PEACH_TID; ++ ++ ++typedef struct PACKED _PSPOLL_FRAME { ++ FRAME_CONTROL FC; ++ USHORT Aid; ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR Ta[MAC_ADDR_LEN]; ++} PSPOLL_FRAME, *PPSPOLL_FRAME; ++ ++typedef struct PACKED _RTS_FRAME { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++}RTS_FRAME, *PRTS_FRAME; ++ ++// BAREQ AND MTBAREQ have the same subtype BAR, 802.11n BAR use compressed bitmap. ++typedef struct PACKED _FRAME_BA_REQ { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BARControl; ++ BASEQ_CONTROL BAStartingSeq; ++} FRAME_BA_REQ, *PFRAME_BA_REQ; ++ ++typedef struct PACKED _FRAME_MTBA_REQ { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ MTBAR_CONTROL MTBARControl; ++ PER_TID_INFO PerTIDInfo; ++ BASEQ_CONTROL BAStartingSeq; ++} FRAME_MTBA_REQ, *PFRAME_MTBA_REQ; ++ ++// Compressed format is mandantory in HT STA ++typedef struct PACKED _FRAME_MTBA { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BA_CONTROL BAControl; ++ BASEQ_CONTROL BAStartingSeq; ++ UCHAR BitMap[8]; ++} FRAME_MTBA, *PFRAME_MTBA; ++ ++typedef struct PACKED _FRAME_PSMP_ACTION { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Psmp; // 7.3.1.25 ++} FRAME_PSMP_ACTION, *PFRAME_PSMP_ACTION; ++ ++typedef struct PACKED _FRAME_ACTION_HDR { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++} FRAME_ACTION_HDR, *PFRAME_ACTION_HDR; ++ ++//Action Frame ++//Action Frame Category:Spectrum, Action:Channel Switch. 7.3.2.20 ++typedef struct PACKED _CHAN_SWITCH_ANNOUNCE { ++ UCHAR ElementID; // ID = IE_CHANNEL_SWITCH_ANNOUNCEMENT = 37 ++ UCHAR Len; ++ CHA_SWITCH_ANNOUNCE_IE CSAnnounceIe; ++} CHAN_SWITCH_ANNOUNCE, *PCHAN_SWITCH_ANNOUNCE; ++ ++ ++//802.11n : 7.3.2.20a ++typedef struct PACKED _SECOND_CHAN_OFFSET { ++ UCHAR ElementID; // ID = IE_SECONDARY_CH_OFFSET = 62 ++ UCHAR Len; ++ SEC_CHA_OFFSET_IE SecChOffsetIe; ++} SECOND_CHAN_OFFSET, *PSECOND_CHAN_OFFSET; ++ ++ ++typedef struct PACKED _FRAME_SPETRUM_CS { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ CHAN_SWITCH_ANNOUNCE CSAnnounce; ++ SECOND_CHAN_OFFSET SecondChannel; ++} FRAME_SPETRUM_CS, *PFRAME_SPETRUM_CS; ++ ++ ++typedef struct PACKED _FRAME_ADDBA_REQ { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; // 1 ++ BA_PARM BaParm; // 2 - 10 ++ USHORT TimeOutValue; // 0 - 0 ++ BASEQ_CONTROL BaStartSeq; // 0-0 ++} FRAME_ADDBA_REQ, *PFRAME_ADDBA_REQ; ++ ++typedef struct PACKED _FRAME_ADDBA_RSP { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; ++ USHORT StatusCode; ++ BA_PARM BaParm; //0 - 2 ++ USHORT TimeOutValue; ++} FRAME_ADDBA_RSP, *PFRAME_ADDBA_RSP; ++ ++typedef struct PACKED _FRAME_DELBA_REQ { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ DELBA_PARM DelbaParm; ++ USHORT ReasonCode; ++} FRAME_DELBA_REQ, *PFRAME_DELBA_REQ; ++ ++ ++//7.2.1.7 ++typedef struct PACKED _FRAME_BAR { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BarControl; ++ BASEQ_CONTROL StartingSeq; ++} FRAME_BAR, *PFRAME_BAR; ++ ++//7.2.1.7 ++typedef struct PACKED _FRAME_BA { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BarControl; ++ BASEQ_CONTROL StartingSeq; ++ UCHAR bitmask[8]; ++} FRAME_BA, *PFRAME_BA; ++ ++ ++// Radio Measuement Request Frame Format ++typedef struct PACKED _FRAME_RM_REQ_ACTION { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; ++ USHORT Repetition; ++ UCHAR data[0]; ++} FRAME_RM_REQ_ACTION, *PFRAME_RM_REQ_ACTION; ++ ++typedef struct PACKED { ++ UCHAR ID; ++ UCHAR Length; ++ UCHAR ChannelSwitchMode; ++ UCHAR NewRegClass; ++ UCHAR NewChannelNum; ++ UCHAR ChannelSwitchCount; ++} HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE, *PHT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE; ++ ++ ++// ++// _Limit must be the 2**n - 1 ++// _SEQ1 , _SEQ2 must be within 0 ~ _Limit ++// ++#define SEQ_STEPONE(_SEQ1, _SEQ2, _Limit) ((_SEQ1 == ((_SEQ2+1) & _Limit))) ++#define SEQ_SMALLER(_SEQ1, _SEQ2, _Limit) (((_SEQ1-_SEQ2) & ((_Limit+1)>>1))) ++#define SEQ_LARGER(_SEQ1, _SEQ2, _Limit) ((_SEQ1 != _SEQ2) && !(((_SEQ1-_SEQ2) & ((_Limit+1)>>1)))) ++#define SEQ_WITHIN_WIN(_SEQ1, _SEQ2, _WIN, _Limit) (SEQ_LARGER(_SEQ1, _SEQ2, _Limit) && \ ++ SEQ_SMALLER(_SEQ1, ((_SEQ2+_WIN+1)&_Limit), _Limit)) ++ ++// ++// Contention-free parameter (without ID and Length) ++// ++typedef struct PACKED { ++ BOOLEAN bValid; // 1: variable contains valid value ++ UCHAR CfpCount; ++ UCHAR CfpPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpDurRemaining; ++} CF_PARM, *PCF_PARM; ++ ++typedef struct _CIPHER_SUITE { ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher 1, this one has more secured cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipherAux; // Unicast cipher 2 if AP announce two unicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Group cipher ++ USHORT RsnCapability; // RSN capability from beacon ++ BOOLEAN bMixMode; // Indicate Pair & Group cipher might be different ++} CIPHER_SUITE, *PCIPHER_SUITE; ++ ++// EDCA configuration from AP's BEACON/ProbeRsp ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ BOOLEAN bAdd; // 1: variable contains valid value ++ BOOLEAN bQAck; ++ BOOLEAN bQueueRequest; ++ BOOLEAN bTxopRequest; ++ BOOLEAN bAPSDCapable; ++// BOOLEAN bMoreDataAck; ++ UCHAR EdcaUpdateCount; ++ UCHAR Aifsn[4]; // 0:AC_BK, 1:AC_BE, 2:AC_VI, 3:AC_VO ++ UCHAR Cwmin[4]; ++ UCHAR Cwmax[4]; ++ USHORT Txop[4]; // in unit of 32-us ++ BOOLEAN bACM[4]; // 1: Admission Control of AC_BK is mandattory ++} EDCA_PARM, *PEDCA_PARM; ++ ++// QBSS LOAD information from QAP's BEACON/ProbeRsp ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ USHORT StaNum; ++ UCHAR ChannelUtilization; ++ USHORT RemainingAdmissionControl; // in unit of 32-us ++} QBSS_LOAD_PARM, *PQBSS_LOAD_PARM; ++ ++// QBSS Info field in QSTA's assoc req ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR Rsv2:1; ++ UCHAR MaxSPLength:2; ++ UCHAR Rsv1:1; ++ UCHAR UAPSD_AC_BE:1; ++ UCHAR UAPSD_AC_BK:1; ++ UCHAR UAPSD_AC_VI:1; ++ UCHAR UAPSD_AC_VO:1; ++#else ++ UCHAR UAPSD_AC_VO:1; ++ UCHAR UAPSD_AC_VI:1; ++ UCHAR UAPSD_AC_BK:1; ++ UCHAR UAPSD_AC_BE:1; ++ UCHAR Rsv1:1; ++ UCHAR MaxSPLength:2; ++ UCHAR Rsv2:1; ++#endif /* !RT_BIG_ENDIAN */ ++} QBSS_STA_INFO_PARM, *PQBSS_STA_INFO_PARM; ++ ++// QBSS Info field in QAP's Beacon/ProbeRsp ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR UAPSD:1; ++ UCHAR Rsv:3; ++ UCHAR ParamSetCount:4; ++#else ++ UCHAR ParamSetCount:4; ++ UCHAR Rsv:3; ++ UCHAR UAPSD:1; ++#endif /* !RT_BIG_ENDIAN */ ++} QBSS_AP_INFO_PARM, *PQBSS_AP_INFO_PARM; ++ ++// QOS Capability reported in QAP's BEACON/ProbeRsp ++// QOS Capability sent out in QSTA's AssociateReq/ReAssociateReq ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ BOOLEAN bQAck; ++ BOOLEAN bQueueRequest; ++ BOOLEAN bTxopRequest; ++// BOOLEAN bMoreDataAck; ++ UCHAR EdcaUpdateCount; ++} QOS_CAPABILITY_PARM, *PQOS_CAPABILITY_PARM; ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef struct { ++ UCHAR IELen; ++ UCHAR IE[MAX_CUSTOM_LEN]; ++} WPA_IE_; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++typedef struct { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR Channel; ++ UCHAR CentralChannel; //Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. ++ UCHAR BssType; ++ USHORT AtimWin; ++ USHORT BeaconPeriod; ++ ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen; ++ HT_CAPABILITY_IE HtCapability; ++ UCHAR HtCapabilityLen; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChanOffset; ++ CHAR Rssi; ++ UCHAR Privacy; // Indicate security function ON/OFF. Don't mess up with auth mode. ++ UCHAR Hidden; ++ ++ USHORT DtimPeriod; ++ USHORT CapabilityInfo; ++ ++ USHORT CfpCount; ++ USHORT CfpPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpDurRemaining; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ ++ ULONG LastBeaconRxTime; // OS's timestamp ++ ++ BOOLEAN bSES; ++ ++ // New for WPA2 ++ CIPHER_SUITE WPA; // AP announced WPA cipher suite ++ CIPHER_SUITE WPA2; // AP announced WPA2 cipher suite ++ ++ // New for microsoft WPA support ++ NDIS_802_11_FIXED_IEs FixIEs; ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeAux; // Addition mode for WPA2 / WPA capable AP ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; // Unicast Encryption Algorithm extract from VAR_IE ++ USHORT VarIELen; // Length of next VIE include EID & Length ++ UCHAR VarIEs[MAX_VIE_LEN]; ++ ++ // CCX Ckip information ++ UCHAR CkipFlag; ++ ++ // CCX 2 TSF ++ UCHAR PTSF[4]; // Parent TSF ++ UCHAR TTSF[8]; // Target TSF ++ ++ // 802.11e d9, and WMM ++ EDCA_PARM EdcaParm; ++ QOS_CAPABILITY_PARM QosCapability; ++ QBSS_LOAD_PARM QbssLoad; ++#ifdef CONFIG_STA_SUPPORT ++ WPA_IE_ WpaIE; ++ WPA_IE_ RsnIE; ++#ifdef EXT_BUILD_CHANNEL_LIST ++ UCHAR CountryString[3]; ++ BOOLEAN bHasCountryIE; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++} BSS_ENTRY, *PBSS_ENTRY; ++ ++typedef struct { ++ UCHAR BssNr; ++ UCHAR BssOverlapNr; ++ BSS_ENTRY BssEntry[MAX_LEN_OF_BSS_TABLE]; ++} BSS_TABLE, *PBSS_TABLE; ++ ++ ++typedef struct _MLME_QUEUE_ELEM { ++ ULONG Machine; ++ ULONG MsgType; ++ ULONG MsgLen; ++ UCHAR Msg[MGMT_DMA_BUFFER_SIZE]; ++ LARGE_INTEGER TimeStamp; ++ UCHAR Rssi0; ++ UCHAR Rssi1; ++ UCHAR Rssi2; ++ UCHAR Signal; ++ UCHAR Channel; ++ UCHAR Wcid; ++ BOOLEAN Occupied; ++} MLME_QUEUE_ELEM, *PMLME_QUEUE_ELEM; ++ ++typedef struct _MLME_QUEUE { ++ ULONG Num; ++ ULONG Head; ++ ULONG Tail; ++ NDIS_SPIN_LOCK Lock; ++ MLME_QUEUE_ELEM Entry[MAX_LEN_OF_MLME_QUEUE]; ++} MLME_QUEUE, *PMLME_QUEUE; ++ ++typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem); ++ ++typedef struct _STATE_MACHINE { ++ ULONG Base; ++ ULONG NrState; ++ ULONG NrMsg; ++ ULONG CurrState; ++ STATE_MACHINE_FUNC *TransFunc; ++} STATE_MACHINE, *PSTATE_MACHINE; ++ ++ ++// MLME AUX data structure that hold temporarliy settings during a connection attempt. ++// Once this attemp succeeds, all settings will be copy to pAd->StaActive. ++// A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of ++// several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely ++// separate this under-trial settings away from pAd->StaActive so that once ++// this new attempt failed, driver can auto-recover back to the active settings. ++typedef struct _MLME_AUX { ++ UCHAR BssType; ++ UCHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR AutoReconnectSsid[MAX_LEN_OF_SSID]; ++ UCHAR AutoReconnectSsidLen; ++ USHORT Alg; ++ UCHAR ScanType; ++ UCHAR Channel; ++ UCHAR CentralChannel; ++ USHORT Aid; ++ USHORT CapabilityInfo; ++ USHORT BeaconPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpPeriod; ++ USHORT AtimWin; ++ ++ // Copy supported rate from desired AP's beacon. We are trying to match ++ // AP's supported and extended rate settings. ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRateLen; ++ HT_CAPABILITY_IE HtCapability; ++ UCHAR HtCapabilityLen; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR NewExtChannelOffset; ++ //RT_HT_CAPABILITY SupportedHtPhy; ++ ++ // new for QOS ++ QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP ++ EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP ++ QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP ++ ++ // new to keep Ralink specific feature ++ ULONG APRalinkIe; ++ ++ BSS_TABLE SsidBssTab; // AP list for the same SSID ++ BSS_TABLE RoamTab; // AP list eligible for roaming ++ ULONG BssIdx; ++ ULONG RoamIdx; ++ ++ BOOLEAN CurrReqIsFromNdis; ++ ++ RALINK_TIMER_STRUCT BeaconTimer, ScanTimer; ++ RALINK_TIMER_STRUCT AuthTimer; ++ RALINK_TIMER_STRUCT AssocTimer, ReassocTimer, DisassocTimer; ++} MLME_AUX, *PMLME_AUX; ++ ++typedef struct _MLME_ADDBA_REQ_STRUCT{ ++ UCHAR Wcid; // ++ UCHAR pAddr[MAC_ADDR_LEN]; ++ UCHAR BaBufSize; ++ USHORT TimeOutValue; ++ UCHAR TID; ++ UCHAR Token; ++ USHORT BaStartSeq; ++} MLME_ADDBA_REQ_STRUCT, *PMLME_ADDBA_REQ_STRUCT; ++ ++ ++typedef struct _MLME_DELBA_REQ_STRUCT{ ++ UCHAR Wcid; // ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR TID; ++ UCHAR Initiator; ++} MLME_DELBA_REQ_STRUCT, *PMLME_DELBA_REQ_STRUCT; ++ ++// assoc struct is equal to reassoc ++typedef struct _MLME_ASSOC_REQ_STRUCT{ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT CapabilityInfo; ++ USHORT ListenIntv; ++ ULONG Timeout; ++} MLME_ASSOC_REQ_STRUCT, *PMLME_ASSOC_REQ_STRUCT, MLME_REASSOC_REQ_STRUCT, *PMLME_REASSOC_REQ_STRUCT; ++ ++typedef struct _MLME_DISASSOC_REQ_STRUCT{ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Reason; ++} MLME_DISASSOC_REQ_STRUCT, *PMLME_DISASSOC_REQ_STRUCT; ++ ++typedef struct _MLME_AUTH_REQ_STRUCT { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Alg; ++ ULONG Timeout; ++} MLME_AUTH_REQ_STRUCT, *PMLME_AUTH_REQ_STRUCT; ++ ++typedef struct _MLME_DEAUTH_REQ_STRUCT { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Reason; ++} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; ++ ++typedef struct { ++ ULONG BssIdx; ++} MLME_JOIN_REQ_STRUCT; ++ ++typedef struct _MLME_SCAN_REQ_STRUCT { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR BssType; ++ UCHAR ScanType; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++} MLME_SCAN_REQ_STRUCT, *PMLME_SCAN_REQ_STRUCT; ++ ++typedef struct _MLME_START_REQ_STRUCT { ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++} MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++// structure for DLS ++typedef struct _RT_802_11_DLS { ++ USHORT TimeOut; // Use to time out while slience, unit: second , set by UI ++ USHORT CountDownTimer; // Use to time out while slience,unit: second , used by driver only ++ NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI ++ UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only ++ BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link ++ RALINK_TIMER_STRUCT Timer; // Use to time out while handshake ++ USHORT Sequence; ++ USHORT MacTabMatchWCID; // ASIC ++ BOOLEAN bHTCap; ++ PVOID pAd; ++} RT_802_11_DLS, *PRT_802_11_DLS; ++ ++typedef struct _MLME_DLS_REQ_STRUCT { ++ PRT_802_11_DLS pDLS; ++ USHORT Reason; ++} MLME_DLS_REQ_STRUCT, *PMLME_DLS_REQ_STRUCT; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct PACKED { ++ UCHAR Eid; ++ UCHAR Len; ++ CHAR Octet[1]; ++} EID_STRUCT,*PEID_STRUCT, BEACON_EID_STRUCT, *PBEACON_EID_STRUCT; ++ ++typedef struct PACKED _RTMP_TX_RATE_SWITCH ++{ ++ UCHAR ItemNo; ++#ifdef RT_BIG_ENDIAN ++ UCHAR Rsv2:2; ++ UCHAR Mode:2; ++ UCHAR Rsv1:1; ++ UCHAR BW:1; ++ UCHAR ShortGI:1; ++ UCHAR STBC:1; ++#else ++ UCHAR STBC:1; ++ UCHAR ShortGI:1; ++ UCHAR BW:1; ++ UCHAR Rsv1:1; ++ UCHAR Mode:2; ++ UCHAR Rsv2:2; ++#endif ++ UCHAR CurrMCS; ++ UCHAR TrainUp; ++ UCHAR TrainDown; ++} RRTMP_TX_RATE_SWITCH, *PRTMP_TX_RATE_SWITCH; ++ ++// ========================== AP mlme.h =============================== ++#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps ++#define DEFAULT_DTIM_PERIOD 1 ++ ++#define MAC_TABLE_AGEOUT_TIME 300 // unit: sec ++#define MAC_TABLE_ASSOC_TIMEOUT 5 // unit: sec ++#define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE) ++ ++// AP shall drop the sta if contine Tx fail count reach it. ++#define MAC_ENTRY_LIFE_CHECK_CNT 20 // packet cnt. ++ ++// Value domain of pMacEntry->Sst ++typedef enum _Sst { ++ SST_NOT_AUTH, // 0: equivalent to IEEE 802.11/1999 state 1 ++ SST_AUTH, // 1: equivalent to IEEE 802.11/1999 state 2 ++ SST_ASSOC // 2: equivalent to IEEE 802.11/1999 state 3 ++} SST; ++ ++// value domain of pMacEntry->AuthState ++typedef enum _AuthState { ++ AS_NOT_AUTH, ++ AS_AUTH_OPEN, // STA has been authenticated using OPEN SYSTEM ++ AS_AUTH_KEY, // STA has been authenticated using SHARED KEY ++ AS_AUTHENTICATING // STA is waiting for AUTH seq#3 using SHARED KEY ++} AUTH_STATE; ++ ++//for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _ApWpaState { ++ AS_NOTUSE, // 0 ++ AS_DISCONNECT, // 1 ++ AS_DISCONNECTED, // 2 ++ AS_INITIALIZE, // 3 ++ AS_AUTHENTICATION, // 4 ++ AS_AUTHENTICATION2, // 5 ++ AS_INITPMK, // 6 ++ AS_INITPSK, // 7 ++ AS_PTKSTART, // 8 ++ AS_PTKINIT_NEGOTIATING, // 9 ++ AS_PTKINITDONE, // 10 ++ AS_UPDATEKEYS, // 11 ++ AS_INTEGRITY_FAILURE, // 12 ++ AS_KEYUPDATE, // 13 ++} AP_WPA_STATE; ++ ++// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _GTKState { ++ REKEY_NEGOTIATING, ++ REKEY_ESTABLISHED, ++ KEYERROR, ++} GTK_STATE; ++ ++// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _WpaGTKState { ++ SETKEYS, ++ SETKEYS_DONE, ++} WPA_GTK_STATE; ++// ====================== end of AP mlme.h ============================ ++ ++ ++#endif // MLME_H__ +--- /dev/null ++++ b/drivers/staging/rt2860/oid.h +@@ -0,0 +1,995 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ oid.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef _OID_H_ ++#define _OID_H_ ++ ++ ++#define TRUE 1 ++#define FALSE 0 ++// ++// IEEE 802.11 Structures and definitions ++// ++#define MAX_TX_POWER_LEVEL 100 /* mW */ ++#define MAX_RSSI_TRIGGER -10 /* dBm */ ++#define MIN_RSSI_TRIGGER -200 /* dBm */ ++#define MAX_FRAG_THRESHOLD 2346 /* byte count */ ++#define MIN_FRAG_THRESHOLD 256 /* byte count */ ++#define MAX_RTS_THRESHOLD 2347 /* byte count */ ++ ++// new types for Media Specific Indications ++// Extension channel offset ++#define EXTCHA_NONE 0 ++#define EXTCHA_ABOVE 0x1 ++#define EXTCHA_BELOW 0x3 ++ ++// BW ++#define BAND_WIDTH_20 0 ++#define BAND_WIDTH_40 1 ++#define BAND_WIDTH_BOTH 2 ++#define BAND_WIDTH_10 3 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. ++// SHORTGI ++#define GAP_INTERVAL_400 1 // only support in HT mode ++#define GAP_INTERVAL_800 0 ++#define GAP_INTERVAL_BOTH 2 ++ ++#define NdisMediaStateConnected 1 ++#define NdisMediaStateDisconnected 0 ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++#define MAC_ADDR_LENGTH 6 ++#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc ++#define MAX_NUMBER_OF_EVENT 10 // entry # in EVENT table ++#define MAX_NUMBER_OF_MAC 32 // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 ++#define MAX_NUMBER_OF_ACL 64 ++#define MAX_LENGTH_OF_SUPPORT_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define MAX_NUMBER_OF_DLS_ENTRY 4 ++ ++#ifndef UNDER_CE ++ ++#define OID_GEN_MACHINE_NAME 0x0001021A ++ ++#ifdef RALINK_ATE ++#define RT_QUERY_ATE_TXDONE_COUNT 0x0401 ++#endif // RALINK_ATE // ++#define RT_QUERY_SIGNAL_CONTEXT 0x0402 ++#define RT_SET_IAPP_PID 0x0404 ++#define RT_SET_APD_PID 0x0405 ++#define RT_SET_DEL_MAC_ENTRY 0x0406 ++ ++// ++// IEEE 802.11 OIDs ++// ++#define OID_GET_SET_TOGGLE 0x8000 ++ ++#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0103 ++#define OID_802_11_NETWORK_TYPE_IN_USE 0x0104 ++#define OID_802_11_RSSI_TRIGGER 0x0107 ++#define RT_OID_802_11_RSSI 0x0108 //rt2860 only , kathy ++#define RT_OID_802_11_RSSI_1 0x0109 //rt2860 only , kathy ++#define RT_OID_802_11_RSSI_2 0x010A //rt2860 only , kathy ++#define OID_802_11_NUMBER_OF_ANTENNAS 0x010B ++#define OID_802_11_RX_ANTENNA_SELECTED 0x010C ++#define OID_802_11_TX_ANTENNA_SELECTED 0x010D ++#define OID_802_11_SUPPORTED_RATES 0x010E ++#define OID_802_11_ADD_WEP 0x0112 ++#define OID_802_11_REMOVE_WEP 0x0113 ++#define OID_802_11_DISASSOCIATE 0x0114 ++#define OID_802_11_PRIVACY_FILTER 0x0118 ++#define OID_802_11_ASSOCIATION_INFORMATION 0x011E ++#define OID_802_11_TEST 0x011F ++#define RT_OID_802_11_COUNTRY_REGION 0x0507 ++#define OID_802_11_BSSID_LIST_SCAN 0x0508 ++#define OID_802_11_SSID 0x0509 ++#define OID_802_11_BSSID 0x050A ++#define RT_OID_802_11_RADIO 0x050B ++#define RT_OID_802_11_PHY_MODE 0x050C ++#define RT_OID_802_11_STA_CONFIG 0x050D ++#define OID_802_11_DESIRED_RATES 0x050E ++#define RT_OID_802_11_PREAMBLE 0x050F ++#define OID_802_11_WEP_STATUS 0x0510 ++#define OID_802_11_AUTHENTICATION_MODE 0x0511 ++#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 ++#define RT_OID_802_11_RESET_COUNTERS 0x0513 ++#define OID_802_11_RTS_THRESHOLD 0x0514 ++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0515 ++#define OID_802_11_POWER_MODE 0x0516 ++#define OID_802_11_TX_POWER_LEVEL 0x0517 ++#define RT_OID_802_11_ADD_WPA 0x0518 ++#define OID_802_11_REMOVE_KEY 0x0519 ++#define OID_802_11_ADD_KEY 0x0520 ++#define OID_802_11_CONFIGURATION 0x0521 ++#define OID_802_11_TX_PACKET_BURST 0x0522 ++#define RT_OID_802_11_QUERY_NOISE_LEVEL 0x0523 ++#define RT_OID_802_11_EXTRA_INFO 0x0524 ++#ifdef DBG ++#define RT_OID_802_11_HARDWARE_REGISTER 0x0525 ++#endif ++#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS ++#define OID_802_11_DEAUTHENTICATION 0x0526 ++#define OID_802_11_DROP_UNENCRYPTED 0x0527 ++#define OID_802_11_MIC_FAILURE_REPORT_FRAME 0x0528 ++ ++// For 802.1x daemin using to require current driver configuration ++#define OID_802_11_RADIUS_QUERY_SETTING 0x0540 ++ ++#define RT_OID_DEVICE_NAME 0x0607 ++#define RT_OID_VERSION_INFO 0x0608 ++#define OID_802_11_BSSID_LIST 0x0609 ++#define OID_802_3_CURRENT_ADDRESS 0x060A ++#define OID_GEN_MEDIA_CONNECT_STATUS 0x060B ++#define RT_OID_802_11_QUERY_LINK_STATUS 0x060C ++#define OID_802_11_RSSI 0x060D ++#define OID_802_11_STATISTICS 0x060E ++#define OID_GEN_RCV_OK 0x060F ++#define OID_GEN_RCV_NO_BUFFER 0x0610 ++#define RT_OID_802_11_QUERY_EEPROM_VERSION 0x0611 ++#define RT_OID_802_11_QUERY_FIRMWARE_VERSION 0x0612 ++#define RT_OID_802_11_QUERY_LAST_RX_RATE 0x0613 ++#define RT_OID_802_11_TX_POWER_LEVEL_1 0x0614 ++#define RT_OID_802_11_QUERY_PIDVID 0x0615 ++//for WPA_SUPPLICANT_SUPPORT ++#define OID_SET_COUNTERMEASURES 0x0616 ++#define OID_802_11_SET_IEEE8021X 0x0617 ++#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 ++#define OID_802_11_PMKID 0x0620 ++#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 ++#define RT_OID_WE_VERSION_COMPILED 0x0622 ++#define RT_OID_NEW_DRIVER 0x0623 ++ ++ ++//rt2860 , kathy ++#define RT_OID_802_11_SNR_0 0x0630 ++#define RT_OID_802_11_SNR_1 0x0631 ++#define RT_OID_802_11_QUERY_LAST_TX_RATE 0x0632 ++#define RT_OID_802_11_QUERY_HT_PHYMODE 0x0633 ++#define RT_OID_802_11_SET_HT_PHYMODE 0x0634 ++#define OID_802_11_RELOAD_DEFAULTS 0x0635 ++#define RT_OID_802_11_QUERY_APSD_SETTING 0x0636 ++#define RT_OID_802_11_SET_APSD_SETTING 0x0637 ++#define RT_OID_802_11_QUERY_APSD_PSM 0x0638 ++#define RT_OID_802_11_SET_APSD_PSM 0x0639 ++#define RT_OID_802_11_QUERY_DLS 0x063A ++#define RT_OID_802_11_SET_DLS 0x063B ++#define RT_OID_802_11_QUERY_DLS_PARAM 0x063C ++#define RT_OID_802_11_SET_DLS_PARAM 0x063D ++#define RT_OID_802_11_QUERY_WMM 0x063E ++#define RT_OID_802_11_SET_WMM 0x063F ++#define RT_OID_802_11_QUERY_IMME_BA_CAP 0x0640 ++#define RT_OID_802_11_SET_IMME_BA_CAP 0x0641 ++#define RT_OID_802_11_QUERY_BATABLE 0x0642 ++#define RT_OID_802_11_ADD_IMME_BA 0x0643 ++#define RT_OID_802_11_TEAR_IMME_BA 0x0644 ++#define RT_OID_DRIVER_DEVICE_NAME 0x0645 ++#define RT_OID_802_11_QUERY_DAT_HT_PHYMODE 0x0646 ++#define RT_OID_QUERY_MULTIPLE_CARD_SUPPORT 0x0647 ++ ++// Ralink defined OIDs ++// Dennis Lee move to platform specific ++ ++#define RT_OID_802_11_BSSID (OID_GET_SET_TOGGLE | OID_802_11_BSSID) ++#define RT_OID_802_11_SSID (OID_GET_SET_TOGGLE | OID_802_11_SSID) ++#define RT_OID_802_11_INFRASTRUCTURE_MODE (OID_GET_SET_TOGGLE | OID_802_11_INFRASTRUCTURE_MODE) ++#define RT_OID_802_11_ADD_WEP (OID_GET_SET_TOGGLE | OID_802_11_ADD_WEP) ++#define RT_OID_802_11_ADD_KEY (OID_GET_SET_TOGGLE | OID_802_11_ADD_KEY) ++#define RT_OID_802_11_REMOVE_WEP (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_WEP) ++#define RT_OID_802_11_REMOVE_KEY (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_KEY) ++#define RT_OID_802_11_DISASSOCIATE (OID_GET_SET_TOGGLE | OID_802_11_DISASSOCIATE) ++#define RT_OID_802_11_AUTHENTICATION_MODE (OID_GET_SET_TOGGLE | OID_802_11_AUTHENTICATION_MODE) ++#define RT_OID_802_11_PRIVACY_FILTER (OID_GET_SET_TOGGLE | OID_802_11_PRIVACY_FILTER) ++#define RT_OID_802_11_BSSID_LIST_SCAN (OID_GET_SET_TOGGLE | OID_802_11_BSSID_LIST_SCAN) ++#define RT_OID_802_11_WEP_STATUS (OID_GET_SET_TOGGLE | OID_802_11_WEP_STATUS) ++#define RT_OID_802_11_RELOAD_DEFAULTS (OID_GET_SET_TOGGLE | OID_802_11_RELOAD_DEFAULTS) ++#define RT_OID_802_11_NETWORK_TYPE_IN_USE (OID_GET_SET_TOGGLE | OID_802_11_NETWORK_TYPE_IN_USE) ++#define RT_OID_802_11_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | OID_802_11_TX_POWER_LEVEL) ++#define RT_OID_802_11_RSSI_TRIGGER (OID_GET_SET_TOGGLE | OID_802_11_RSSI_TRIGGER) ++#define RT_OID_802_11_FRAGMENTATION_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_FRAGMENTATION_THRESHOLD) ++#define RT_OID_802_11_RTS_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_RTS_THRESHOLD) ++#define RT_OID_802_11_RX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_RX_ANTENNA_SELECTED) ++#define RT_OID_802_11_TX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_TX_ANTENNA_SELECTED) ++#define RT_OID_802_11_SUPPORTED_RATES (OID_GET_SET_TOGGLE | OID_802_11_SUPPORTED_RATES) ++#define RT_OID_802_11_DESIRED_RATES (OID_GET_SET_TOGGLE | OID_802_11_DESIRED_RATES) ++#define RT_OID_802_11_CONFIGURATION (OID_GET_SET_TOGGLE | OID_802_11_CONFIGURATION) ++#define RT_OID_802_11_POWER_MODE (OID_GET_SET_TOGGLE | OID_802_11_POWER_MODE) ++ ++typedef enum _NDIS_802_11_STATUS_TYPE ++{ ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; ++ ++typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; ++ ++typedef struct _NDIS_802_11_STATUS_INDICATION ++{ ++ NDIS_802_11_STATUS_TYPE StatusType; ++} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; ++ ++// mask for authentication/integrity fields ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++ ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST ++{ ++ ULONG Length; // Length of structure ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ULONG Flags; ++} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; ++ ++//Added new types for PMKID Candidate lists. ++typedef struct _PMKID_CANDIDATE { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ ULONG Flags; ++} PMKID_CANDIDATE, *PPMKID_CANDIDATE; ++ ++typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST ++{ ++ ULONG Version; // Version of the structure ++ ULONG NumCandidates; // No. of pmkid candidates ++ PMKID_CANDIDATE CandidateList[1]; ++} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; ++ ++//Flags for PMKID Candidate list structure ++#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++ ++// Added new types for OFDM 5G and 2.4G ++typedef enum _NDIS_802_11_NETWORK_TYPE ++{ ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM5_N, ++ Ndis802_11OFDM24, ++ Ndis802_11OFDM24_N, ++ Ndis802_11Automode, ++ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; ++ ++typedef struct _NDIS_802_11_NETWORK_TYPE_LIST ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_802_11_NETWORK_TYPE NetworkType [1]; ++} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST; ++ ++typedef enum _NDIS_802_11_POWER_MODE ++{ ++ Ndis802_11PowerModeCAM, ++ Ndis802_11PowerModeMAX_PSP, ++ Ndis802_11PowerModeFast_PSP, ++ Ndis802_11PowerModeLegacy_PSP, ++ Ndis802_11PowerModeMax // not a real mode, defined as an upper bound ++} NDIS_802_11_POWER_MODE, *PNDIS_802_11_POWER_MODE; ++ ++typedef ULONG NDIS_802_11_TX_POWER_LEVEL; // in milliwatts ++ ++// ++// Received Signal Strength Indication ++// ++typedef LONG NDIS_802_11_RSSI; // in dBm ++ ++typedef struct _NDIS_802_11_CONFIGURATION_FH ++{ ++ ULONG Length; // Length of structure ++ ULONG HopPattern; // As defined by 802.11, MSB set ++ ULONG HopSet; // to one if non-802.11 ++ ULONG DwellTime; // units are Kusec ++} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; ++ ++typedef struct _NDIS_802_11_CONFIGURATION ++{ ++ ULONG Length; // Length of structure ++ ULONG BeaconPeriod; // units are Kusec ++ ULONG ATIMWindow; // units are Kusec ++ ULONG DSConfig; // Frequency, units are kHz ++ NDIS_802_11_CONFIGURATION_FH FHConfig; ++} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; ++ ++typedef struct _NDIS_802_11_STATISTICS ++{ ++ ULONG Length; // Length of structure ++ LARGE_INTEGER TransmittedFragmentCount; ++ LARGE_INTEGER MulticastTransmittedFrameCount; ++ LARGE_INTEGER FailedCount; ++ LARGE_INTEGER RetryCount; ++ LARGE_INTEGER MultipleRetryCount; ++ LARGE_INTEGER RTSSuccessCount; ++ LARGE_INTEGER RTSFailureCount; ++ LARGE_INTEGER ACKFailureCount; ++ LARGE_INTEGER FrameDuplicateCount; ++ LARGE_INTEGER ReceivedFragmentCount; ++ LARGE_INTEGER MulticastReceivedFrameCount; ++ LARGE_INTEGER FCSErrorCount; ++ LARGE_INTEGER TKIPLocalMICFailures; ++ LARGE_INTEGER TKIPRemoteMICErrors; ++ LARGE_INTEGER TKIPICVErrors; ++ LARGE_INTEGER TKIPCounterMeasuresInvoked; ++ LARGE_INTEGER TKIPReplays; ++ LARGE_INTEGER CCMPFormatErrors; ++ LARGE_INTEGER CCMPReplays; ++ LARGE_INTEGER CCMPDecryptErrors; ++ LARGE_INTEGER FourWayHandshakeFailures; ++} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS; ++ ++typedef ULONG NDIS_802_11_KEY_INDEX; ++typedef ULONGLONG NDIS_802_11_KEY_RSC; ++ ++#define MAX_RADIUS_SRV_NUM 2 // 802.1x failover number ++ ++typedef struct PACKED _RADIUS_SRV_INFO { ++ UINT32 radius_ip; ++ UINT32 radius_port; ++ UCHAR radius_key[64]; ++ UCHAR radius_key_len; ++} RADIUS_SRV_INFO, *PRADIUS_SRV_INFO; ++ ++typedef struct PACKED _RADIUS_KEY_INFO ++{ ++ UCHAR radius_srv_num; ++ RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; ++ UCHAR ieee8021xWEP; // dynamic WEP ++ UCHAR key_index; ++ UCHAR key_length; // length of key in bytes ++ UCHAR key_material[13]; ++} RADIUS_KEY_INFO, *PRADIUS_KEY_INFO; ++ ++// It's used by 802.1x daemon to require relative configuration ++typedef struct PACKED _RADIUS_CONF ++{ ++ UINT32 Length; // Length of this structure ++ UCHAR mbss_num; // indicate multiple BSS number ++ UINT32 own_ip_addr; ++ UINT32 retry_interval; ++ UINT32 session_timeout_interval; ++ UCHAR EAPifname[IFNAMSIZ]; ++ UCHAR EAPifname_len; ++ UCHAR PreAuthifname[IFNAMSIZ]; ++ UCHAR PreAuthifname_len; ++ RADIUS_KEY_INFO RadiusInfo[8/*MAX_MBSSID_NUM*/]; ++} RADIUS_CONF, *PRADIUS_CONF; ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++// Key mapping keys require a BSSID ++typedef struct _NDIS_802_11_KEY ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; ++ UINT KeyLength; // length of key in bytes ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_KEY_RSC KeyRSC; ++ UCHAR KeyMaterial[1]; // variable length depending on above field ++} NDIS_802_11_KEY, *PNDIS_802_11_KEY; ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct _NDIS_802_11_REMOVE_KEY ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; ++ NDIS_802_11_MAC_ADDRESS BSSID; ++} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; ++ ++typedef struct _NDIS_802_11_WEP ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; // 0 is the per-client key, 1-N are the ++ // global keys ++ UINT KeyLength; // length of key in bytes ++ UCHAR KeyMaterial[1];// variable length depending on above field ++} NDIS_802_11_WEP, *PNDIS_802_11_WEP; ++ ++ ++typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE ++{ ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11Monitor, ++ Ndis802_11InfrastructureMax // Not a real value, defined as upper bound ++} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; ++ ++// Add new authentication modes ++typedef enum _NDIS_802_11_AUTHENTICATION_MODE ++{ ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWPA2, ++ Ndis802_11AuthModeWPA2PSK, ++ Ndis802_11AuthModeWPA1WPA2, ++ Ndis802_11AuthModeWPA1PSKWPA2PSK, ++ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound ++} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; ++ ++typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates ++typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates ++ ++typedef struct PACKED _NDIS_802_11_SSID ++{ ++ UINT SsidLength; // length of SSID field below, in bytes; ++ // this can be zero. ++ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field ++} NDIS_802_11_SSID, *PNDIS_802_11_SSID; ++ ++ ++typedef struct PACKED _NDIS_WLAN_BSSID ++{ ++ ULONG Length; // Length of this structure ++ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID ++ UCHAR Reserved[2]; ++ NDIS_802_11_SSID Ssid; // SSID ++ ULONG Privacy; // WEP encryption requirement ++ NDIS_802_11_RSSI Rssi; // receive signal strength in dBm ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES SupportedRates; ++} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; ++ ++typedef struct PACKED _NDIS_802_11_BSSID_LIST ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_WLAN_BSSID Bssid[1]; ++} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; ++ ++// Added Capabilities, IELength and IEs for each BSSID ++typedef struct PACKED _NDIS_WLAN_BSSID_EX ++{ ++ ULONG Length; // Length of this structure ++ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID ++ UCHAR Reserved[2]; ++ NDIS_802_11_SSID Ssid; // SSID ++ UINT Privacy; // WEP encryption requirement ++ NDIS_802_11_RSSI Rssi; // receive signal ++ // strength in dBm ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ ULONG IELength; ++ UCHAR IEs[1]; ++} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; ++ ++typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_WLAN_BSSID_EX Bssid[1]; ++} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; ++ ++typedef struct PACKED _NDIS_802_11_FIXED_IEs ++{ ++ UCHAR Timestamp[8]; ++ USHORT BeaconInterval; ++ USHORT Capabilities; ++} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; ++ ++typedef struct _NDIS_802_11_VARIABLE_IEs ++{ ++ UCHAR ElementID; ++ UCHAR Length; // Number of bytes in data field ++ UCHAR data[1]; ++} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; ++ ++typedef ULONG NDIS_802_11_FRAGMENTATION_THRESHOLD; ++ ++typedef ULONG NDIS_802_11_RTS_THRESHOLD; ++ ++typedef ULONG NDIS_802_11_ANTENNA; ++ ++typedef enum _NDIS_802_11_PRIVACY_FILTER ++{ ++ Ndis802_11PrivFilterAcceptAll, ++ Ndis802_11PrivFilter8021xWEP ++} NDIS_802_11_PRIVACY_FILTER, *PNDIS_802_11_PRIVACY_FILTER; ++ ++// Added new encryption types ++// Also aliased typedef to new name ++typedef enum _NDIS_802_11_WEP_STATUS ++{ ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent, ++ Ndis802_11Encryption4Enabled, // TKIP or AES mix ++ Ndis802_11Encryption4KeyAbsent, ++} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, ++ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; ++ ++typedef enum _NDIS_802_11_RELOAD_DEFAULTS ++{ ++ Ndis802_11ReloadWEPKeys ++} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++typedef struct _NDIS_802_11_AI_REQFI ++{ ++ USHORT Capabilities; ++ USHORT ListenInterval; ++ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; ++} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; ++ ++typedef struct _NDIS_802_11_AI_RESFI ++{ ++ USHORT Capabilities; ++ USHORT StatusCode; ++ USHORT AssociationId; ++} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; ++ ++typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION ++{ ++ ULONG Length; ++ USHORT AvailableRequestFixedIEs; ++ NDIS_802_11_AI_REQFI RequestFixedIEs; ++ ULONG RequestIELength; ++ ULONG OffsetRequestIEs; ++ USHORT AvailableResponseFixedIEs; ++ NDIS_802_11_AI_RESFI ResponseFixedIEs; ++ ULONG ResponseIELength; ++ ULONG OffsetResponseIEs; ++} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_EVENT ++{ ++ NDIS_802_11_STATUS_INDICATION Status; ++ NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; ++} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; ++ ++// 802.11 Media stream constraints, associated with OID_802_11_MEDIA_STREAM_MODE ++typedef enum _NDIS_802_11_MEDIA_STREAM_MODE ++{ ++ Ndis802_11MediaStreamOff, ++ Ndis802_11MediaStreamOn, ++} NDIS_802_11_MEDIA_STREAM_MODE, *PNDIS_802_11_MEDIA_STREAM_MODE; ++ ++// PMKID Structures ++typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef struct _BSSID_INFO ++{ ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_PMKID_VALUE PMKID; ++} BSSID_INFO, *PBSSID_INFO; ++ ++typedef struct _NDIS_802_11_PMKID ++{ ++ UINT Length; ++ UINT BSSIDInfoCount; ++ BSSID_INFO BSSIDInfo[1]; ++} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; ++ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; ++} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; ++ ++typedef struct _NDIS_802_11_CAPABILITY ++{ ++ ULONG Length; ++ ULONG Version; ++ ULONG NoOfPMKIDs; ++ ULONG NoOfAuthEncryptPairsSupported; ++ NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; ++} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; ++ ++//#endif //of WIN 2k ++#endif //UNDER_CE ++ ++#if WIRELESS_EXT <= 11 ++#ifndef SIOCDEVPRIVATE ++#define SIOCDEVPRIVATE 0x8BE0 ++#endif ++#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) ++ ++#ifdef DBG ++#define RTPRIV_IOCTL_BBP (SIOCIWFIRSTPRIV + 0x03) ++#define RTPRIV_IOCTL_MAC (SIOCIWFIRSTPRIV + 0x05) ++#define RTPRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x07) ++#endif ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++#define RTPRIV_IOCTL_ATE (SIOCIWFIRSTPRIV + 0x08) ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#define RTPRIV_IOCTL_STATISTICS (SIOCIWFIRSTPRIV + 0x09) ++#define RTPRIV_IOCTL_ADD_PMKID_CACHE (SIOCIWFIRSTPRIV + 0x0A) ++#define RTPRIV_IOCTL_RADIUS_DATA (SIOCIWFIRSTPRIV + 0x0C) ++#define RTPRIV_IOCTL_GSITESURVEY (SIOCIWFIRSTPRIV + 0x0D) ++#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) // Sync. with RT61 (for wpa_supplicant) ++#define RTPRIV_IOCTL_GET_MAC_TABLE (SIOCIWFIRSTPRIV + 0x0F) ++ ++#define RTPRIV_IOCTL_SHOW (SIOCIWFIRSTPRIV + 0x11) ++enum { ++ SHOW_CONN_STATUS = 4, ++ SHOW_DRVIER_VERION = 5, ++ SHOW_BA_INFO = 6, ++ SHOW_DESC_INFO = 7, ++ RAIO_OFF = 10, ++ RAIO_ON = 11, ++#ifdef QOS_DLS_SUPPORT ++ SHOW_DLS_ENTRY_INFO = 19, ++#endif // QOS_DLS_SUPPORT // ++ SHOW_CFG_VALUE = 20, ++}; ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++//SNMP ieee 802dot11, kathy , 2008_0220 ++// dot11res(3) ++#define RT_OID_802_11_MANUFACTUREROUI 0x0700 ++#define RT_OID_802_11_MANUFACTURERNAME 0x0701 ++#define RT_OID_802_11_RESOURCETYPEIDNAME 0x0702 ++ ++// dot11smt(1) ++#define RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED 0x0703 ++#define RT_OID_802_11_POWERMANAGEMENTMODE 0x0704 ++#define OID_802_11_WEPDEFAULTKEYVALUE 0x0705 // read , write ++#define OID_802_11_WEPDEFAULTKEYID 0x0706 ++#define RT_OID_802_11_WEPKEYMAPPINGLENGTH 0x0707 ++#define OID_802_11_SHORTRETRYLIMIT 0x0708 ++#define OID_802_11_LONGRETRYLIMIT 0x0709 ++#define RT_OID_802_11_PRODUCTID 0x0710 ++#define RT_OID_802_11_MANUFACTUREID 0x0711 ++ ++// //dot11Phy(4) ++#define OID_802_11_CURRENTCHANNEL 0x0712 ++ ++//dot11mac ++#define RT_OID_802_11_MAC_ADDRESS 0x0713 ++#endif // SNMP_SUPPORT // ++ ++#define OID_802_11_BUILD_CHANNEL_EX 0x0714 ++#define OID_802_11_GET_CH_LIST 0x0715 ++#define OID_802_11_GET_COUNTRY_CODE 0x0716 ++#define OID_802_11_GET_CHANNEL_GEOGRAPHY 0x0717 ++ ++#ifdef LLTD_SUPPORT ++// for consistency with RT61 ++#define RT_OID_GET_PHY_MODE 0x761 ++#endif // LLTD_SUPPORT // ++ ++// New for MeetingHouse Api support ++#define OID_MH_802_1X_SUPPORTED 0xFFEDC100 ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! ++typedef union _HTTRANSMIT_SETTING { ++#ifdef RT_BIG_ENDIAN ++ struct { ++ USHORT MODE:2; // Use definition MODE_xxx. ++ USHORT TxBF:1; ++ USHORT rsv:2; ++ USHORT STBC:2; //SPACE ++ USHORT ShortGI:1; ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT MCS:7; // MCS ++ } field; ++#else ++ struct { ++ USHORT MCS:7; // MCS ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:2; ++ USHORT TxBF:1; ++ USHORT MODE:2; // Use definition MODE_xxx. ++ } field; ++#endif ++ USHORT word; ++ } HTTRANSMIT_SETTING, *PHTTRANSMIT_SETTING; ++ ++typedef enum _RT_802_11_PREAMBLE { ++ Rt802_11PreambleLong, ++ Rt802_11PreambleShort, ++ Rt802_11PreambleAuto ++} RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; ++ ++// Only for STA, need to sync with AP ++// 2005-03-08 match current RaConfig. ++typedef enum _RT_802_11_PHY_MODE { ++ PHY_11BG_MIXED = 0, ++ PHY_11B, ++ PHY_11A, ++ PHY_11ABG_MIXED, ++ PHY_11G, ++#ifdef DOT11_N_SUPPORT ++ PHY_11ABGN_MIXED, // both band 5 ++ PHY_11N_2_4G, // 11n-only with 2.4G band 6 ++ PHY_11GN_MIXED, // 2.4G band 7 ++ PHY_11AN_MIXED, // 5G band 8 ++ PHY_11BGN_MIXED, // if check 802.11b. 9 ++ PHY_11AGN_MIXED, // if check 802.11b. 10 ++ PHY_11N_5G, // 11n-only with 5G band 11 ++#endif // DOT11_N_SUPPORT // ++} RT_802_11_PHY_MODE; ++ ++// put all proprietery for-query objects here to reduce # of Query_OID ++typedef struct _RT_802_11_LINK_STATUS { ++ ULONG CurrTxRate; // in units of 0.5Mbps ++ ULONG ChannelQuality; // 0..100 % ++ ULONG TxByteCount; // both ok and fail ++ ULONG RxByteCount; // both ok and fail ++ ULONG CentralChannel; // 40MHz central channel number ++} RT_802_11_LINK_STATUS, *PRT_802_11_LINK_STATUS; ++ ++typedef struct _RT_802_11_EVENT_LOG { ++ LARGE_INTEGER SystemTime; // timestammp via NdisGetCurrentSystemTime() ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ USHORT Event; // EVENT_xxx ++} RT_802_11_EVENT_LOG, *PRT_802_11_EVENT_LOG; ++ ++typedef struct _RT_802_11_EVENT_TABLE { ++ ULONG Num; ++ ULONG Rsv; // to align Log[] at LARGE_INEGER boundary ++ RT_802_11_EVENT_LOG Log[MAX_NUMBER_OF_EVENT]; ++} RT_802_11_EVENT_TABLE, PRT_802_11_EVENT_TABLE; ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! ++typedef union _MACHTTRANSMIT_SETTING { ++ struct { ++ USHORT MCS:7; // MCS ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:3; ++ USHORT MODE:2; // Use definition MODE_xxx. ++ } field; ++ USHORT word; ++ } MACHTTRANSMIT_SETTING, *PMACHTTRANSMIT_SETTING; ++ ++typedef struct _RT_802_11_MAC_ENTRY { ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ UCHAR Aid; ++ UCHAR Psm; // 0:PWR_ACTIVE, 1:PWR_SAVE ++ UCHAR MimoPs; // 0:MMPS_STATIC, 1:MMPS_DYNAMIC, 3:MMPS_Enabled ++ CHAR AvgRssi0; ++ CHAR AvgRssi1; ++ CHAR AvgRssi2; ++ UINT32 ConnectedTime; ++ MACHTTRANSMIT_SETTING TxRate; ++} RT_802_11_MAC_ENTRY, *PRT_802_11_MAC_ENTRY; ++ ++typedef struct _RT_802_11_MAC_TABLE { ++ ULONG Num; ++ RT_802_11_MAC_ENTRY Entry[MAX_NUMBER_OF_MAC]; ++} RT_802_11_MAC_TABLE, *PRT_802_11_MAC_TABLE; ++ ++// structure for query/set hardware register - MAC, BBP, RF register ++typedef struct _RT_802_11_HARDWARE_REGISTER { ++ ULONG HardwareType; // 0:MAC, 1:BBP, 2:RF register, 3:EEPROM ++ ULONG Offset; // Q/S register offset addr ++ ULONG Data; // R/W data buffer ++} RT_802_11_HARDWARE_REGISTER, *PRT_802_11_HARDWARE_REGISTER; ++ ++typedef struct _RT_802_11_AP_CONFIG { ++ ULONG EnableTxBurst; // 0-disable, 1-enable ++ ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate ++ ULONG IsolateInterStaTraffic; // 0-disable, 1-enable isolation ++ ULONG HideSsid; // 0-disable, 1-enable hiding ++ ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF ++ ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time ++ ULONG Rsv1; // must be 0 ++ ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY ++} RT_802_11_AP_CONFIG, *PRT_802_11_AP_CONFIG; ++ ++// structure to query/set STA_CONFIG ++typedef struct _RT_802_11_STA_CONFIG { ++ ULONG EnableTxBurst; // 0-disable, 1-enable ++ ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate ++ ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF ++ ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time when applicable ++ ULONG AdhocMode; // 0-11b rates only (WIFI spec), 1 - b/g mixed, 2 - g only ++ ULONG HwRadioStatus; // 0-OFF, 1-ON, default is 1, Read-Only ++ ULONG Rsv1; // must be 0 ++ ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY ++} RT_802_11_STA_CONFIG, *PRT_802_11_STA_CONFIG; ++ ++// ++// For OID Query or Set about BA structure ++// ++typedef struct _OID_BACAP_STRUC { ++ UCHAR RxBAWinLimit; ++ UCHAR TxBAWinLimit; ++ UCHAR Policy; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid ++ UCHAR MpduDensity; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid ++ UCHAR AmsduEnable; //Enable AMSDU transmisstion ++ UCHAR AmsduSize; // 0:3839, 1:7935 bytes. UINT MSDUSizeToBytes[] = { 3839, 7935}; ++ UCHAR MMPSmode; // MIMO power save more, 0:static, 1:dynamic, 2:rsv, 3:mimo enable ++ BOOLEAN AutoBA; // Auto BA will automatically ++} OID_BACAP_STRUC, *POID_BACAP_STRUC; ++ ++typedef struct _RT_802_11_ACL_ENTRY { ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ USHORT Rsv; ++} RT_802_11_ACL_ENTRY, *PRT_802_11_ACL_ENTRY; ++ ++typedef struct PACKED _RT_802_11_ACL { ++ ULONG Policy; // 0-disable, 1-positive list, 2-negative list ++ ULONG Num; ++ RT_802_11_ACL_ENTRY Entry[MAX_NUMBER_OF_ACL]; ++} RT_802_11_ACL, *PRT_802_11_ACL; ++ ++typedef struct _RT_802_11_WDS { ++ ULONG Num; ++ NDIS_802_11_MAC_ADDRESS Entry[24/*MAX_NUM_OF_WDS_LINK*/]; ++ ULONG KeyLength; ++ UCHAR KeyMaterial[32]; ++} RT_802_11_WDS, *PRT_802_11_WDS; ++ ++typedef struct _RT_802_11_TX_RATES_ { ++ UCHAR SupRateLen; ++ UCHAR SupRate[MAX_LENGTH_OF_SUPPORT_RATES]; ++ UCHAR ExtRateLen; ++ UCHAR ExtRate[MAX_LENGTH_OF_SUPPORT_RATES]; ++} RT_802_11_TX_RATES, *PRT_802_11_TX_RATES; ++ ++ ++// Definition of extra information code ++#define GENERAL_LINK_UP 0x0 // Link is Up ++#define GENERAL_LINK_DOWN 0x1 // Link is Down ++#define HW_RADIO_OFF 0x2 // Hardware radio off ++#define SW_RADIO_OFF 0x3 // Software radio off ++#define AUTH_FAIL 0x4 // Open authentication fail ++#define AUTH_FAIL_KEYS 0x5 // Shared authentication fail ++#define ASSOC_FAIL 0x6 // Association failed ++#define EAP_MIC_FAILURE 0x7 // Deauthencation because MIC failure ++#define EAP_4WAY_TIMEOUT 0x8 // Deauthencation on 4-way handshake timeout ++#define EAP_GROUP_KEY_TIMEOUT 0x9 // Deauthencation on group key handshake timeout ++#define EAP_SUCCESS 0xa // EAP succeed ++#define DETECT_RADAR_SIGNAL 0xb // Radar signal occur in current channel ++#define EXTRA_INFO_MAX 0xb // Indicate Last OID ++ ++#define EXTRA_INFO_CLEAR 0xffffffff ++ ++// This is OID setting structure. So only GF or MM as Mode. This is valid when our wirelss mode has 802.11n in use. ++typedef struct { ++ RT_802_11_PHY_MODE PhyMode; // ++ UCHAR TransmitNo; ++ UCHAR HtMode; //HTMODE_GF or HTMODE_MM ++ UCHAR ExtOffset; //extension channel above or below ++ UCHAR MCS; ++ UCHAR BW; ++ UCHAR STBC; ++ UCHAR SHORTGI; ++ UCHAR rsv; ++} OID_SET_HT_PHYMODE, *POID_SET_HT_PHYMODE; ++ ++#ifdef LLTD_SUPPORT ++typedef struct _RT_LLTD_ASSOICATION_ENTRY { ++ UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; ++ unsigned short MOR; // maximum operational rate ++ UCHAR phyMode; ++} RT_LLTD_ASSOICATION_ENTRY, *PRT_LLTD_ASSOICATION_ENTRY; ++ ++typedef struct _RT_LLTD_ASSOICATION_TABLE { ++ unsigned int Num; ++ RT_LLTD_ASSOICATION_ENTRY Entry[MAX_NUMBER_OF_MAC]; ++} RT_LLTD_ASSOICATION_TABLE, *PRT_LLTD_ASSOICATION_TABLE; ++#endif // LLTD_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++//rt2860, kathy 2007-0118 ++// structure for DLS ++typedef struct _RT_802_11_DLS_UI { ++ USHORT TimeOut; // unit: second , set by UI ++ USHORT CountDownTimer; // unit: second , used by driver only ++ NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI ++ UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only ++ BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link ++} RT_802_11_DLS_UI, *PRT_802_11_DLS_UI; ++ ++typedef struct _RT_802_11_DLS_INFO { ++ RT_802_11_DLS_UI Entry[MAX_NUMBER_OF_DLS_ENTRY]; ++ UCHAR num; ++} RT_802_11_DLS_INFO, *PRT_802_11_DLS_INFO; ++ ++typedef enum _RT_802_11_DLS_MODE { ++ DLS_NONE, ++ DLS_WAIT_KEY, ++ DLS_FINISH ++} RT_802_11_DLS_MODE; ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++#define RT_ASSOC_EVENT_FLAG 0x0101 ++#define RT_DISASSOC_EVENT_FLAG 0x0102 ++#define RT_REQIE_EVENT_FLAG 0x0103 ++#define RT_RESPIE_EVENT_FLAG 0x0104 ++#define RT_ASSOCINFO_EVENT_FLAG 0x0105 ++#define RT_PMKIDCAND_FLAG 0x0106 ++#define RT_INTERFACE_DOWN 0x0107 ++#define RT_INTERFACE_UP 0x0108 ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#define MAX_CUSTOM_LEN 128 ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef enum _RT_802_11_D_CLIENT_MODE ++{ ++ Rt802_11_D_None, ++ Rt802_11_D_Flexible, ++ Rt802_11_D_Strict, ++} RT_802_11_D_CLIENT_MODE, *PRT_802_11_D_CLIENT_MODE; ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct _RT_CHANNEL_LIST_INFO ++{ ++ UCHAR ChannelList[MAX_NUM_OF_CHS]; // list all supported channels for site survey ++ UCHAR ChannelListNum; // number of channel in ChannelList[] ++} RT_CHANNEL_LIST_INFO, *PRT_CHANNEL_LIST_INFO; ++ ++ ++#endif // _OID_H_ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt2860.h +@@ -0,0 +1,349 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __RT2860_H__ ++#define __RT2860_H__ ++ ++#define RT28xx_CHIP_NAME "RT2860" ++ ++#define TXINFO_SIZE 0 ++#define TXPADDING_SIZE 0 ++ ++/* ----------------- EEPROM Related MACRO ----------------- */ ++#define RT28xx_EEPROM_READ16(pAd, offset, var) \ ++ var = RTMP_EEPROM_READ16(pAd, offset) ++ ++#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ ++ RTMP_EEPROM_WRITE16(pAd, offset, var) ++ ++/* ----------------- TASK/THREAD Related MACRO ----------------- */ ++#define RT28XX_TASK_THREAD_INIT(pAd, Status) \ ++ init_thread_task(pAd); NICInitTxRxRingAndBacklogQueue(pAd); \ ++ Status = NDIS_STATUS_SUCCESS; ++ ++/* function declarations */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define IRQ_HANDLE_TYPE irqreturn_t ++#else ++#define IRQ_HANDLE_TYPE void ++#endif ++ ++IRQ_HANDLE_TYPE ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) ++rt2860_interrupt(int irq, void *dev_instance); ++#else ++rt2860_interrupt(int irq, void *dev_instance, struct pt_regs *regs); ++#endif ++ ++/* ----------------- Frimware Related MACRO ----------------- */ ++#define RT28XX_WRITE_FIRMWARE(_pAd, _pFwImage, _FwLen) \ ++ do{ \ ++ ULONG _i, _firm; \ ++ RTMP_IO_WRITE32(_pAd, PBF_SYS_CTRL, 0x10000); \ ++ \ ++ for(_i=0; _i<_FwLen; _i+=4) \ ++ { \ ++ _firm = _pFwImage[_i] + \ ++ (_pFwImage[_i+3] << 24) + \ ++ (_pFwImage[_i+2] << 16) + \ ++ (_pFwImage[_i+1] << 8); \ ++ RTMP_IO_WRITE32(_pAd, FIRMWARE_IMAGE_BASE + _i, _firm); \ ++ } \ ++ RTMP_IO_WRITE32(_pAd, PBF_SYS_CTRL, 0x00000); \ ++ RTMP_IO_WRITE32(_pAd, PBF_SYS_CTRL, 0x00001); \ ++ \ ++ /* initialize BBP R/W access agent */ \ ++ RTMP_IO_WRITE32(_pAd, H2M_BBP_AGENT, 0); \ ++ RTMP_IO_WRITE32(_pAd, H2M_MAILBOX_CSR, 0); \ ++ }while(0) ++ ++/* ----------------- TX Related MACRO ----------------- */ ++#define RT28XX_START_DEQUEUE(pAd, QueIdx, irqFlags) do{}while(0) ++#define RT28XX_STOP_DEQUEUE(pAd, QueIdx, irqFlags) do{}while(0) ++ ++ ++#define RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, freeNum, pPacket) \ ++ ((freeNum) >= (ULONG)(pTxBlk->TotalFragNum + RTMP_GET_PACKET_FRAGMENTS(pPacket) + 3)) /* rough estimate we will use 3 more descriptor. */ ++#define RT28XX_RELEASE_DESC_RESOURCE(pAd, QueIdx) \ ++ do{}while(0) ++ ++#define NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, freeNum, _TxFrameType) \ ++ (((freeNum != (TX_RING_SIZE-1)) && (pAd->TxSwQueue[QueIdx].Number == 0)) || (freeNum<3)) ++ //(((freeNum) != (TX_RING_SIZE-1)) && (pAd->TxSwQueue[QueIdx].Number == 1 /*0*/)) ++ ++ ++#define HAL_KickOutMgmtTx(_pAd, _QueIdx, _pPacket, _pSrcBufVA, _SrcBufLen) \ ++ RtmpPCIMgmtKickOut(_pAd, _QueIdx, _pPacket, _pSrcBufVA, _SrcBufLen) ++ ++#define RTMP_PKT_TAIL_PADDING 0 ++ ++#define fRTMP_ADAPTER_NEED_STOP_TX 0 ++ ++#define HAL_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) \ ++ /* RtmpPCI_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber)*/ ++ ++#define HAL_WriteTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) \ ++ RtmpPCI_WriteSingleTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) ++ ++#define HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) \ ++ RtmpPCI_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) ++ ++#define HAL_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) \ ++ RtmpPCI_WriteMultiTxResource(pAd, pTxBlk, frameNum, pFreeNumber) ++ ++#define HAL_FinalWriteTxResource(_pAd, _pTxBlk, _TotalMPDUSize, _FirstTxIdx) \ ++ RtmpPCI_FinalWriteTxResource(_pAd, _pTxBlk, _TotalMPDUSize, _FirstTxIdx) ++ ++#define HAL_LastTxIdx(_pAd, _QueIdx,_LastTxIdx) \ ++ /*RtmpPCIDataLastTxIdx(_pAd, _QueIdx,_LastTxIdx)*/ ++ ++#define HAL_KickOutTx(_pAd, _pTxBlk, _QueIdx) \ ++ RTMP_IO_WRITE32((_pAd), TX_CTX_IDX0+((_QueIdx)*0x10), (_pAd)->TxRing[(_QueIdx)].TxCpuIdx) ++/* RtmpPCIDataKickOut(_pAd, _pTxBlk, _QueIdx)*/ ++ ++#define HAL_KickOutNullFrameTx(_pAd, _QueIdx, _pNullFrame, _frameLen) \ ++ MiniportMMRequest(_pAd, _QueIdx, _pNullFrame, _frameLen) ++ ++#define GET_TXRING_FREENO(_pAd, _QueIdx) \ ++ (_pAd->TxRing[_QueIdx].TxSwFreeIdx > _pAd->TxRing[_QueIdx].TxCpuIdx) ? \ ++ (_pAd->TxRing[_QueIdx].TxSwFreeIdx - _pAd->TxRing[_QueIdx].TxCpuIdx - 1) \ ++ : \ ++ (_pAd->TxRing[_QueIdx].TxSwFreeIdx + TX_RING_SIZE - _pAd->TxRing[_QueIdx].TxCpuIdx - 1); ++ ++ ++#define GET_MGMTRING_FREENO(_pAd) \ ++ (_pAd->MgmtRing.TxSwFreeIdx > _pAd->MgmtRing.TxCpuIdx) ? \ ++ (_pAd->MgmtRing.TxSwFreeIdx - _pAd->MgmtRing.TxCpuIdx - 1) \ ++ : \ ++ (_pAd->MgmtRing.TxSwFreeIdx + MGMT_RING_SIZE - _pAd->MgmtRing.TxCpuIdx - 1); ++ ++ ++/* ----------------- RX Related MACRO ----------------- */ ++ ++// no use ++#define RT28XX_RCV_PKT_GET_INIT(pAd) ++#define RT28XX_RV_A_BUF_END ++//#define RT28XX_RV_ALL_BUF_END ++ ++ ++/* ----------------- ASIC Related MACRO ----------------- */ ++// no use ++#define RT28XX_DMA_POST_WRITE(pAd) ++ ++// reset MAC of a station entry to 0x000000000000 ++#define RT28XX_STA_ENTRY_MAC_RESET(pAd, Wcid) \ ++ AsicDelWcidTab(pAd, Wcid); ++ ++// add this entry into ASIC RX WCID search table ++#define RT28XX_STA_ENTRY_ADD(pAd, pEntry) \ ++ AsicUpdateRxWCIDTable(pAd, pEntry->Aid, pEntry->Addr); ++ ++// remove Pair-wise key material from ASIC ++#define RT28XX_STA_ENTRY_KEY_DEL(pAd, BssIdx, Wcid) \ ++ AsicRemovePairwiseKeyEntry(pAd, BssIdx, (UCHAR)Wcid); ++ ++// add Client security information into ASIC WCID table and IVEIV table ++#define RT28XX_STA_SECURITY_INFO_ADD(pAd, apidx, KeyID, pEntry) \ ++ RTMPAddWcidAttributeEntry(pAd, apidx, KeyID, \ ++ pAd->SharedKey[apidx][KeyID].CipherAlg, pEntry); ++ ++#define RT28XX_SECURITY_KEY_ADD(pAd, apidx, KeyID, pEntry) \ ++ { /* update pairwise key information to ASIC Shared Key Table */ \ ++ AsicAddSharedKeyEntry(pAd, apidx, KeyID, \ ++ pAd->SharedKey[apidx][KeyID].CipherAlg, \ ++ pAd->SharedKey[apidx][KeyID].Key, \ ++ pAd->SharedKey[apidx][KeyID].TxMic, \ ++ pAd->SharedKey[apidx][KeyID].RxMic); \ ++ /* update ASIC WCID attribute table and IVEIV table */ \ ++ RTMPAddWcidAttributeEntry(pAd, apidx, KeyID, \ ++ pAd->SharedKey[apidx][KeyID].CipherAlg, \ ++ pEntry); } ++ ++ ++// Insert the BA bitmap to ASIC for the Wcid entry ++#define RT28XX_ADD_BA_SESSION_TO_ASIC(_pAd, _Aid, _TID) \ ++ do{ \ ++ UINT32 _Value = 0, _Offset; \ ++ _Offset = MAC_WCID_BASE + (_Aid) * HW_WCID_ENTRY_SIZE + 4; \ ++ RTMP_IO_READ32((_pAd), _Offset, &_Value); \ ++ _Value |= (0x10000<<(_TID)); \ ++ RTMP_IO_WRITE32((_pAd), _Offset, _Value); \ ++ }while(0) ++ ++ ++// Remove the BA bitmap from ASIC for the Wcid entry ++// bitmap field starts at 0x10000 in ASIC WCID table ++#define RT28XX_DEL_BA_SESSION_FROM_ASIC(_pAd, _Wcid, _TID) \ ++ do{ \ ++ UINT32 _Value = 0, _Offset; \ ++ _Offset = MAC_WCID_BASE + (_Wcid) * HW_WCID_ENTRY_SIZE + 4; \ ++ RTMP_IO_READ32((_pAd), _Offset, &_Value); \ ++ _Value &= (~(0x10000 << (_TID))); \ ++ RTMP_IO_WRITE32((_pAd), _Offset, _Value); \ ++ }while(0) ++ ++ ++/* ----------------- PCI/USB Related MACRO ----------------- */ ++ ++#define RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p) \ ++ ((POS_COOKIE)handle)->pci_dev = dev_p; ++ ++// set driver data ++#define RT28XX_DRVDATA_SET(_a) pci_set_drvdata(_a, net_dev); ++ ++#define RT28XX_UNMAP() \ ++{ if (net_dev->base_addr) { \ ++ iounmap((void *)(net_dev->base_addr)); \ ++ release_mem_region(pci_resource_start(dev_p, 0), \ ++ pci_resource_len(dev_p, 0)); } \ ++ if (net_dev->irq) pci_release_regions(dev_p); } ++ ++#ifdef PCI_MSI_SUPPORT ++#define RTMP_MSI_ENABLE(_pAd) \ ++{ POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ ++ (_pAd)->HaveMsi = pci_enable_msi(_pObj->pci_dev) == 0 ? TRUE : FALSE; } ++ ++#define RTMP_MSI_DISABLE(_pAd) \ ++{ POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ ++ if (_pAd->HaveMsi == TRUE) \ ++ pci_disable_msi(_pObj->pci_dev); \ ++ _pAd->HaveMsi = FALSE; } ++#else ++#define RTMP_MSI_ENABLE(_pAd) ++#define RTMP_MSI_DISABLE(_pAd) ++#endif // PCI_MSI_SUPPORT // ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++#define SA_SHIRQ IRQF_SHARED ++#endif ++ ++#define RT28XX_IRQ_REQUEST(net_dev) \ ++{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->priv); \ ++ POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ ++ RTMP_MSI_ENABLE(_pAd); \ ++ if ((retval = request_irq(_pObj->pci_dev->irq, \ ++ rt2860_interrupt, SA_SHIRQ, \ ++ (net_dev)->name, (net_dev)))) { \ ++ printk("RT2860: request_irq ERROR(%d)\n", retval); \ ++ return retval; } } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define RT28XX_IRQ_RELEASE(net_dev) \ ++{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->priv); \ ++ POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ ++ synchronize_irq(_pObj->pci_dev->irq); \ ++ free_irq(_pObj->pci_dev->irq, (net_dev)); \ ++ RTMP_MSI_DISABLE(_pAd); } ++#else ++#define RT28XX_IRQ_RELEASE(net_dev) \ ++{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->priv); \ ++ POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ ++ free_irq(_pObj->pci_dev->irq, (net_dev)); \ ++ RTMP_MSI_DISABLE(_pAd); } ++#endif ++ ++#define RT28XX_IRQ_INIT(pAd) \ ++ { pAd->int_enable_reg = ((DELAYINTMASK) | \ ++ (RxINT|TxDataInt|TxMgmtInt)) & ~(0x03); \ ++ pAd->int_disable_mask = 0; \ ++ pAd->int_pending = 0; } ++ ++#define RT28XX_IRQ_ENABLE(pAd) \ ++ { /* clear garbage ints */ \ ++ RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, 0xffffffff); \ ++ NICEnableInterrupt(pAd); } ++ ++#define RT28XX_PUT_DEVICE(dev_p) ++ ++ ++/* ----------------- MLME Related MACRO ----------------- */ ++#define RT28XX_MLME_HANDLER(pAd) MlmeHandler(pAd) ++ ++#define RT28XX_MLME_PRE_SANITY_CHECK(pAd) ++ ++#define RT28XX_MLME_STA_QUICK_RSP_WAKE_UP(pAd) \ ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++#define RT28XX_MLME_RESET_STATE_MACHINE(pAd) \ ++ MlmeRestartStateMachine(pAd) ++ ++#define RT28XX_HANDLE_COUNTER_MEASURE(_pAd, _pEntry) \ ++ HandleCounterMeasure(_pAd, _pEntry) ++ ++/* ----------------- Power Save Related MACRO ----------------- */ ++#define RT28XX_PS_POLL_ENQUEUE(pAd) EnqueuePsPoll(pAd) ++ ++// ++// Device ID & Vendor ID, these values should match EEPROM value ++// ++#define NIC2860_PCI_DEVICE_ID 0x0601 ++#define NIC2860_PCIe_DEVICE_ID 0x0681 ++#define NIC2760_PCI_DEVICE_ID 0x0701 // 1T/2R Cardbus ??? ++#define NIC2790_PCIe_DEVICE_ID 0x0781 // 1T/2R miniCard ++ ++#define NIC_PCI_VENDOR_ID 0x1814 ++ ++#define VEN_AWT_PCIe_DEVICE_ID 0x1059 ++#define VEN_AWT_PCI_VENDOR_ID 0x1A3B ++ ++// For RTMPPCIePowerLinkCtrlRestore () function ++#define RESTORE_HALT 1 ++#define RESTORE_WAKEUP 2 ++#define RESTORE_CLOSE 3 ++ ++#define PowerSafeCID 1 ++#define PowerRadioOffCID 2 ++#define PowerWakeCID 3 ++#define CID0MASK 0x000000ff ++#define CID1MASK 0x0000ff00 ++#define CID2MASK 0x00ff0000 ++#define CID3MASK 0xff000000 ++ ++#define PCI_REG_READ_WORD(pci_dev, offset, Configuration) \ ++ if (pci_read_config_word(pci_dev, offset, ®16) == 0) \ ++ Configuration = le2cpu16(reg16); \ ++ else \ ++ Configuration = 0; ++ ++#define PCI_REG_WIRTE_WORD(pci_dev, offset, Configuration) \ ++ reg16 = cpu2le16(Configuration); \ ++ pci_write_config_word(pci_dev, offset, reg16); \ ++ ++#define RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx) \ ++ RT28xxPciStaAsicForceWakeup(pAd, bFromTx); ++ ++#define RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp) \ ++ RT28xxPciStaAsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ ++#define RT28XX_MLME_RADIO_ON(pAd) \ ++ RT28xxPciMlmeRadioOn(pAd); ++ ++#define RT28XX_MLME_RADIO_OFF(pAd) \ ++ RT28xxPciMlmeRadioOFF(pAd); ++ ++#endif //__RT2860_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt28xx.h +@@ -0,0 +1,2714 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt28xx.h ++ ++ Abstract: ++ RT28xx ASIC related definition & structures ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee Jan-3-2006 created for RT2860c ++*/ ++ ++#ifndef __RT28XX_H__ ++#define __RT28XX_H__ ++ ++ ++// ++// PCI registers - base address 0x0000 ++// ++#define PCI_CFG 0x0000 ++#define PCI_EECTRL 0x0004 ++#define PCI_MCUCTRL 0x0008 ++ ++// ++// SCH/DMA registers - base address 0x0200 ++// ++// INT_SOURCE_CSR: Interrupt source register. Write one to clear corresponding bit ++// ++#define DMA_CSR0 0x200 ++#define INT_SOURCE_CSR 0x200 ++#ifdef RT_BIG_ENDIAN ++typedef union _INT_SOURCE_CSR_STRUC { ++ struct { ++ UINT32 :14; ++ UINT32 TxCoherent:1; ++ UINT32 RxCoherent:1; ++ UINT32 GPTimer:1; ++ UINT32 AutoWakeup:1;//bit14 ++ UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c ++ UINT32 PreTBTT:1; ++ UINT32 TBTTInt:1; ++ UINT32 RxTxCoherent:1; ++ UINT32 MCUCommandINT:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 RxDone:1; ++ UINT32 TxDelayINT:1; //delayed interrupt, not interrupt until several int or time limit hit ++ UINT32 RxDelayINT:1; //dealyed interrupt ++ } field; ++ UINT32 word; ++} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; ++#else ++typedef union _INT_SOURCE_CSR_STRUC { ++ struct { ++ UINT32 RxDelayINT:1; ++ UINT32 TxDelayINT:1; ++ UINT32 RxDone:1; ++ UINT32 Ac0DmaDone:1;//4 ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 HccaDmaDone:1; // bit7 ++ UINT32 MgmtDmaDone:1; ++ UINT32 MCUCommandINT:1;//bit 9 ++ UINT32 RxTxCoherent:1; ++ UINT32 TBTTInt:1; ++ UINT32 PreTBTT:1; ++ UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c ++ UINT32 AutoWakeup:1;//bit14 ++ UINT32 GPTimer:1; ++ UINT32 RxCoherent:1;//bit16 ++ UINT32 TxCoherent:1; ++ UINT32 :14; ++ } field; ++ UINT32 word; ++} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; ++#endif ++ ++// ++// INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF ++// ++#define INT_MASK_CSR 0x204 ++#ifdef RT_BIG_ENDIAN ++typedef union _INT_MASK_CSR_STRUC { ++ struct { ++ UINT32 TxCoherent:1; ++ UINT32 RxCoherent:1; ++ UINT32 :20; ++ UINT32 MCUCommandINT:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 RxDone:1; ++ UINT32 TxDelay:1; ++ UINT32 RXDelay_INT_MSK:1; ++ } field; ++ UINT32 word; ++}INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; ++#else ++typedef union _INT_MASK_CSR_STRUC { ++ struct { ++ UINT32 RXDelay_INT_MSK:1; ++ UINT32 TxDelay:1; ++ UINT32 RxDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 MCUCommandINT:1; ++ UINT32 :20; ++ UINT32 RxCoherent:1; ++ UINT32 TxCoherent:1; ++ } field; ++ UINT32 word; ++} INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; ++#endif ++#define WPDMA_GLO_CFG 0x208 ++#ifdef RT_BIG_ENDIAN ++typedef union _WPDMA_GLO_CFG_STRUC { ++ struct { ++ UINT32 HDR_SEG_LEN:16; ++ UINT32 RXHdrScater:8; ++ UINT32 BigEndian:1; ++ UINT32 EnTXWriteBackDDONE:1; ++ UINT32 WPDMABurstSIZE:2; ++ UINT32 RxDMABusy:1; ++ UINT32 EnableRxDMA:1; ++ UINT32 TxDMABusy:1; ++ UINT32 EnableTxDMA:1; ++ } field; ++ UINT32 word; ++}WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; ++#else ++typedef union _WPDMA_GLO_CFG_STRUC { ++ struct { ++ UINT32 EnableTxDMA:1; ++ UINT32 TxDMABusy:1; ++ UINT32 EnableRxDMA:1; ++ UINT32 RxDMABusy:1; ++ UINT32 WPDMABurstSIZE:2; ++ UINT32 EnTXWriteBackDDONE:1; ++ UINT32 BigEndian:1; ++ UINT32 RXHdrScater:8; ++ UINT32 HDR_SEG_LEN:16; ++ } field; ++ UINT32 word; ++} WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; ++#endif ++#define WPDMA_RST_IDX 0x20c ++#ifdef RT_BIG_ENDIAN ++typedef union _WPDMA_RST_IDX_STRUC { ++ struct { ++ UINT32 :15; ++ UINT32 RST_DRX_IDX0:1; ++ UINT32 rsv:10; ++ UINT32 RST_DTX_IDX5:1; ++ UINT32 RST_DTX_IDX4:1; ++ UINT32 RST_DTX_IDX3:1; ++ UINT32 RST_DTX_IDX2:1; ++ UINT32 RST_DTX_IDX1:1; ++ UINT32 RST_DTX_IDX0:1; ++ } field; ++ UINT32 word; ++}WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; ++#else ++typedef union _WPDMA_RST_IDX_STRUC { ++ struct { ++ UINT32 RST_DTX_IDX0:1; ++ UINT32 RST_DTX_IDX1:1; ++ UINT32 RST_DTX_IDX2:1; ++ UINT32 RST_DTX_IDX3:1; ++ UINT32 RST_DTX_IDX4:1; ++ UINT32 RST_DTX_IDX5:1; ++ UINT32 rsv:10; ++ UINT32 RST_DRX_IDX0:1; ++ UINT32 :15; ++ } field; ++ UINT32 word; ++} WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; ++#endif ++#define DELAY_INT_CFG 0x0210 ++#ifdef RT_BIG_ENDIAN ++typedef union _DELAY_INT_CFG_STRUC { ++ struct { ++ UINT32 TXDLY_INT_EN:1; ++ UINT32 TXMAX_PINT:7; ++ UINT32 TXMAX_PTIME:8; ++ UINT32 RXDLY_INT_EN:1; ++ UINT32 RXMAX_PINT:7; ++ UINT32 RXMAX_PTIME:8; ++ } field; ++ UINT32 word; ++}DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; ++#else ++typedef union _DELAY_INT_CFG_STRUC { ++ struct { ++ UINT32 RXMAX_PTIME:8; ++ UINT32 RXMAX_PINT:7; ++ UINT32 RXDLY_INT_EN:1; ++ UINT32 TXMAX_PTIME:8; ++ UINT32 TXMAX_PINT:7; ++ UINT32 TXDLY_INT_EN:1; ++ } field; ++ UINT32 word; ++} DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; ++#endif ++#define WMM_AIFSN_CFG 0x0214 ++#ifdef RT_BIG_ENDIAN ++typedef union _AIFSN_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Aifsn3:4; // for AC_VO ++ UINT32 Aifsn2:4; // for AC_VI ++ UINT32 Aifsn1:4; // for AC_BK ++ UINT32 Aifsn0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; ++#else ++typedef union _AIFSN_CSR_STRUC { ++ struct { ++ UINT32 Aifsn0:4; // for AC_BE ++ UINT32 Aifsn1:4; // for AC_BK ++ UINT32 Aifsn2:4; // for AC_VI ++ UINT32 Aifsn3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; ++#endif ++// ++// CWMIN_CSR: CWmin for each EDCA AC ++// ++#define WMM_CWMIN_CFG 0x0218 ++#ifdef RT_BIG_ENDIAN ++typedef union _CWMIN_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Cwmin3:4; // for AC_VO ++ UINT32 Cwmin2:4; // for AC_VI ++ UINT32 Cwmin1:4; // for AC_BK ++ UINT32 Cwmin0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; ++#else ++typedef union _CWMIN_CSR_STRUC { ++ struct { ++ UINT32 Cwmin0:4; // for AC_BE ++ UINT32 Cwmin1:4; // for AC_BK ++ UINT32 Cwmin2:4; // for AC_VI ++ UINT32 Cwmin3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; ++#endif ++ ++// ++// CWMAX_CSR: CWmin for each EDCA AC ++// ++#define WMM_CWMAX_CFG 0x021c ++#ifdef RT_BIG_ENDIAN ++typedef union _CWMAX_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Cwmax3:4; // for AC_VO ++ UINT32 Cwmax2:4; // for AC_VI ++ UINT32 Cwmax1:4; // for AC_BK ++ UINT32 Cwmax0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; ++#else ++typedef union _CWMAX_CSR_STRUC { ++ struct { ++ UINT32 Cwmax0:4; // for AC_BE ++ UINT32 Cwmax1:4; // for AC_BK ++ UINT32 Cwmax2:4; // for AC_VI ++ UINT32 Cwmax3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; ++#endif ++ ++ ++// ++// AC_TXOP_CSR0: AC_BK/AC_BE TXOP register ++// ++#define WMM_TXOP0_CFG 0x0220 ++#ifdef RT_BIG_ENDIAN ++typedef union _AC_TXOP_CSR0_STRUC { ++ struct { ++ USHORT Ac1Txop; // for AC_BE, in unit of 32us ++ USHORT Ac0Txop; // for AC_BK, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; ++#else ++typedef union _AC_TXOP_CSR0_STRUC { ++ struct { ++ USHORT Ac0Txop; // for AC_BK, in unit of 32us ++ USHORT Ac1Txop; // for AC_BE, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; ++#endif ++ ++// ++// AC_TXOP_CSR1: AC_VO/AC_VI TXOP register ++// ++#define WMM_TXOP1_CFG 0x0224 ++#ifdef RT_BIG_ENDIAN ++typedef union _AC_TXOP_CSR1_STRUC { ++ struct { ++ USHORT Ac3Txop; // for AC_VO, in unit of 32us ++ USHORT Ac2Txop; // for AC_VI, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; ++#else ++typedef union _AC_TXOP_CSR1_STRUC { ++ struct { ++ USHORT Ac2Txop; // for AC_VI, in unit of 32us ++ USHORT Ac3Txop; // for AC_VO, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; ++#endif ++#define RINGREG_DIFF 0x10 ++#define GPIO_CTRL_CFG 0x0228 //MAC_CSR13 ++#define MCU_CMD_CFG 0x022c ++#define TX_BASE_PTR0 0x0230 //AC_BK base address ++#define TX_MAX_CNT0 0x0234 ++#define TX_CTX_IDX0 0x0238 ++#define TX_DTX_IDX0 0x023c ++#define TX_BASE_PTR1 0x0240 //AC_BE base address ++#define TX_MAX_CNT1 0x0244 ++#define TX_CTX_IDX1 0x0248 ++#define TX_DTX_IDX1 0x024c ++#define TX_BASE_PTR2 0x0250 //AC_VI base address ++#define TX_MAX_CNT2 0x0254 ++#define TX_CTX_IDX2 0x0258 ++#define TX_DTX_IDX2 0x025c ++#define TX_BASE_PTR3 0x0260 //AC_VO base address ++#define TX_MAX_CNT3 0x0264 ++#define TX_CTX_IDX3 0x0268 ++#define TX_DTX_IDX3 0x026c ++#define TX_BASE_PTR4 0x0270 //HCCA base address ++#define TX_MAX_CNT4 0x0274 ++#define TX_CTX_IDX4 0x0278 ++#define TX_DTX_IDX4 0x027c ++#define TX_BASE_PTR5 0x0280 //MGMT base address ++#define TX_MAX_CNT5 0x0284 ++#define TX_CTX_IDX5 0x0288 ++#define TX_DTX_IDX5 0x028c ++#define TX_MGMTMAX_CNT TX_MAX_CNT5 ++#define TX_MGMTCTX_IDX TX_CTX_IDX5 ++#define TX_MGMTDTX_IDX TX_DTX_IDX5 ++#define RX_BASE_PTR 0x0290 //RX base address ++#define RX_MAX_CNT 0x0294 ++#define RX_CRX_IDX 0x0298 ++#define RX_DRX_IDX 0x029c ++#define USB_DMA_CFG 0x02a0 ++#ifdef RT_BIG_ENDIAN ++typedef union _USB_DMA_CFG_STRUC { ++ struct { ++ UINT32 TxBusy:1; //USB DMA TX FSM busy . debug only ++ UINT32 RxBusy:1; //USB DMA RX FSM busy . debug only ++ UINT32 EpoutValid:6; //OUT endpoint data valid. debug only ++ UINT32 TxBulkEn:1; //Enable USB DMA Tx ++ UINT32 RxBulkEn:1; //Enable USB DMA Rx ++ UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation ++ UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. ++ UINT32 TxClear:1; //Clear USB DMA TX path ++ UINT32 rsv:2; ++ UINT32 phyclear:1; //phy watch dog enable. write 1 ++ UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 1024 bytes ++ UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns ++ } field; ++ UINT32 word; ++} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; ++#else ++typedef union _USB_DMA_CFG_STRUC { ++ struct { ++ UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns ++ UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 256 bytes ++ UINT32 phyclear:1; //phy watch dog enable. write 1 ++ UINT32 rsv:2; ++ UINT32 TxClear:1; //Clear USB DMA TX path ++ UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. ++ UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation ++ UINT32 RxBulkEn:1; //Enable USB DMA Rx ++ UINT32 TxBulkEn:1; //Enable USB DMA Tx ++ UINT32 EpoutValid:6; //OUT endpoint data valid ++ UINT32 RxBusy:1; //USB DMA RX FSM busy ++ UINT32 TxBusy:1; //USB DMA TX FSM busy ++ } field; ++ UINT32 word; ++} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; ++#endif ++ ++// ++// 3 PBF registers ++// ++// ++// Most are for debug. Driver doesn't touch PBF register. ++#define PBF_SYS_CTRL 0x0400 ++#define PBF_CFG 0x0408 ++#define PBF_MAX_PCNT 0x040C ++#define PBF_CTRL 0x0410 ++#define PBF_INT_STA 0x0414 ++#define PBF_INT_ENA 0x0418 ++#define TXRXQ_PCNT 0x0438 ++#define PBF_DBG 0x043c ++#define PBF_CAP_CTRL 0x0440 ++ ++// ++// 4 MAC registers ++// ++// ++// 4.1 MAC SYSTEM configuration registers (offset:0x1000) ++// ++#define MAC_CSR0 0x1000 ++#ifdef RT_BIG_ENDIAN ++typedef union _ASIC_VER_ID_STRUC { ++ struct { ++ USHORT ASICVer; // version : 2860 ++ USHORT ASICRev; // reversion : 0 ++ } field; ++ UINT32 word; ++} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; ++#else ++typedef union _ASIC_VER_ID_STRUC { ++ struct { ++ USHORT ASICRev; // reversion : 0 ++ USHORT ASICVer; // version : 2860 ++ } field; ++ UINT32 word; ++} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; ++#endif ++#define MAC_SYS_CTRL 0x1004 //MAC_CSR1 ++#define MAC_ADDR_DW0 0x1008 // MAC ADDR DW0 ++#define MAC_ADDR_DW1 0x100c // MAC ADDR DW1 ++// ++// MAC_CSR2: STA MAC register 0 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_DW0_STRUC { ++ struct { ++ UCHAR Byte3; // MAC address byte 3 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte0; // MAC address byte 0 ++ } field; ++ UINT32 word; ++} MAC_DW0_STRUC, *PMAC_DW0_STRUC; ++#else ++typedef union _MAC_DW0_STRUC { ++ struct { ++ UCHAR Byte0; // MAC address byte 0 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte3; // MAC address byte 3 ++ } field; ++ UINT32 word; ++} MAC_DW0_STRUC, *PMAC_DW0_STRUC; ++#endif ++ ++// ++// MAC_CSR3: STA MAC register 1 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_DW1_STRUC { ++ struct { ++ UCHAR Rsvd1; ++ UCHAR U2MeMask; ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Byte4; // MAC address byte 4 ++ } field; ++ UINT32 word; ++} MAC_DW1_STRUC, *PMAC_DW1_STRUC; ++#else ++typedef union _MAC_DW1_STRUC { ++ struct { ++ UCHAR Byte4; // MAC address byte 4 ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR U2MeMask; ++ UCHAR Rsvd1; ++ } field; ++ UINT32 word; ++} MAC_DW1_STRUC, *PMAC_DW1_STRUC; ++#endif ++ ++#define MAC_BSSID_DW0 0x1010 // MAC BSSID DW0 ++#define MAC_BSSID_DW1 0x1014 // MAC BSSID DW1 ++ ++// ++// MAC_CSR5: BSSID register 1 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_CSR5_STRUC { ++ struct { ++ USHORT Rsvd:11; ++ USHORT MBssBcnNum:3; ++ USHORT BssIdMode:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID ++ UCHAR Byte5; // BSSID byte 5 ++ UCHAR Byte4; // BSSID byte 4 ++ } field; ++ UINT32 word; ++} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; ++#else ++typedef union _MAC_CSR5_STRUC { ++ struct { ++ UCHAR Byte4; // BSSID byte 4 ++ UCHAR Byte5; // BSSID byte 5 ++ USHORT BssIdMask:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID ++ USHORT MBssBcnNum:3; ++ USHORT Rsvd:11; ++ } field; ++ UINT32 word; ++} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; ++#endif ++ ++#define MAX_LEN_CFG 0x1018 // rt2860b max 16k bytes. bit12:13 Maximum PSDU length (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 ++#define BBP_CSR_CFG 0x101c // ++// ++// BBP_CSR_CFG: BBP serial control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _BBP_CSR_CFG_STRUC { ++ struct { ++ UINT32 :12; ++ UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel ++ UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles ++ UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. ++ UINT32 fRead:1; // 0: Write BBP, 1: Read BBP ++ UINT32 RegNum:8; // Selected BBP register ++ UINT32 Value:8; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; ++#else ++typedef union _BBP_CSR_CFG_STRUC { ++ struct { ++ UINT32 Value:8; // Register value to program into BBP ++ UINT32 RegNum:8; // Selected BBP register ++ UINT32 fRead:1; // 0: Write BBP, 1: Read BBP ++ UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. ++ UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles ++ UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel ++ UINT32 :12; ++ } field; ++ UINT32 word; ++} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; ++#endif ++#define RF_CSR_CFG0 0x1020 ++// ++// RF_CSR_CFG: RF control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG0_STRUC { ++ struct { ++ UINT32 Busy:1; // 0: idle 1: 8busy ++ UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate ++ UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby ++ UINT32 bitwidth:5; // Selected BBP register ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; ++#else ++typedef union _RF_CSR_CFG0_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 bitwidth:5; // Selected BBP register ++ UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby ++ UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate ++ UINT32 Busy:1; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; ++#endif ++#define RF_CSR_CFG1 0x1024 ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG1_STRUC { ++ struct { ++ UINT32 rsv:7; // 0: idle 1: 8busy ++ UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; ++#else ++typedef union _RF_CSR_CFG1_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) ++ UINT32 rsv:7; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; ++#endif ++#define RF_CSR_CFG2 0x1028 // ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG2_STRUC { ++ struct { ++ UINT32 rsv:8; // 0: idle 1: 8busy ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; ++#else ++typedef union _RF_CSR_CFG2_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 rsv:8; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; ++#endif ++#define LED_CFG 0x102c // MAC_CSR14 ++#ifdef RT_BIG_ENDIAN ++typedef union _LED_CFG_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high ++ UINT32 YLedMode:2; // yellow Led Mode ++ UINT32 GLedMode:2; // green Led Mode ++ UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on ++ UINT32 rsv:2; ++ UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms ++ UINT32 OffPeriod:8; // blinking off period unit 1ms ++ UINT32 OnPeriod:8; // blinking on period unit 1ms ++ } field; ++ UINT32 word; ++} LED_CFG_STRUC, *PLED_CFG_STRUC; ++#else ++typedef union _LED_CFG_STRUC { ++ struct { ++ UINT32 OnPeriod:8; // blinking on period unit 1ms ++ UINT32 OffPeriod:8; // blinking off period unit 1ms ++ UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms ++ UINT32 rsv:2; ++ UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on ++ UINT32 GLedMode:2; // green Led Mode ++ UINT32 YLedMode:2; // yellow Led Mode ++ UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} LED_CFG_STRUC, *PLED_CFG_STRUC; ++#endif ++// ++// 4.2 MAC TIMING configuration registers (offset:0x1100) ++// ++#define XIFS_TIME_CFG 0x1100 // MAC_CSR8 MAC_CSR9 ++#ifdef RT_BIG_ENDIAN ++typedef union _IFS_SLOT_CFG_STRUC { ++ struct { ++ UINT32 rsv:2; ++ UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer ++ UINT32 EIFS:9; // unit 1us ++ UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND ++ UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX ++ UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX ++ } field; ++ UINT32 word; ++} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; ++#else ++typedef union _IFS_SLOT_CFG_STRUC { ++ struct { ++ UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX ++ UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX ++ UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND ++ UINT32 EIFS:9; // unit 1us ++ UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer ++ UINT32 rsv:2; ++ } field; ++ UINT32 word; ++} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; ++#endif ++ ++#define BKOFF_SLOT_CFG 0x1104 // mac_csr9 last 8 bits ++#define NAV_TIME_CFG 0x1108 // NAV (MAC_CSR15) ++#define CH_TIME_CFG 0x110C // Count as channel busy ++#define PBF_LIFE_TIMER 0x1110 //TX/RX MPDU timestamp timer (free run)Unit: 1us ++#define BCN_TIME_CFG 0x1114 // TXRX_CSR9 ++ ++#define BCN_OFFSET0 0x042C ++#define BCN_OFFSET1 0x0430 ++ ++// ++// BCN_TIME_CFG : Synchronization control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _BCN_TIME_CFG_STRUC { ++ struct { ++ UINT32 TxTimestampCompensate:8; ++ UINT32 :3; ++ UINT32 bBeaconGen:1; // Enable beacon generator ++ UINT32 bTBTTEnable:1; ++ UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode ++ UINT32 bTsfTicking:1; // Enable TSF auto counting ++ UINT32 BeaconInterval:16; // in unit of 1/16 TU ++ } field; ++ UINT32 word; ++} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; ++#else ++typedef union _BCN_TIME_CFG_STRUC { ++ struct { ++ UINT32 BeaconInterval:16; // in unit of 1/16 TU ++ UINT32 bTsfTicking:1; // Enable TSF auto counting ++ UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode ++ UINT32 bTBTTEnable:1; ++ UINT32 bBeaconGen:1; // Enable beacon generator ++ UINT32 :3; ++ UINT32 TxTimestampCompensate:8; ++ } field; ++ UINT32 word; ++} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; ++#endif ++#define TBTT_SYNC_CFG 0x1118 // txrx_csr10 ++#define TSF_TIMER_DW0 0x111C // Local TSF timer lsb 32 bits. Read-only ++#define TSF_TIMER_DW1 0x1120 // msb 32 bits. Read-only. ++#define TBTT_TIMER 0x1124 // TImer remains till next TBTT. Read-only. TXRX_CSR14 ++#define INT_TIMER_CFG 0x1128 // ++#define INT_TIMER_EN 0x112c // GP-timer and pre-tbtt Int enable ++#define CH_IDLE_STA 0x1130 // channel idle time ++#define CH_BUSY_STA 0x1134 // channle busy time ++// ++// 4.2 MAC POWER configuration registers (offset:0x1200) ++// ++#define MAC_STATUS_CFG 0x1200 // old MAC_CSR12 ++#define PWR_PIN_CFG 0x1204 // old MAC_CSR12 ++#define AUTO_WAKEUP_CFG 0x1208 // old MAC_CSR10 ++// ++// AUTO_WAKEUP_CFG: Manual power control / status register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _AUTO_WAKEUP_STRUC { ++ struct { ++ UINT32 :16; ++ UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake ++ UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set ++ UINT32 AutoLeadTime:8; ++ } field; ++ UINT32 word; ++} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; ++#else ++typedef union _AUTO_WAKEUP_STRUC { ++ struct { ++ UINT32 AutoLeadTime:8; ++ UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set ++ UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake ++ UINT32 :16; ++ } field; ++ UINT32 word; ++} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; ++#endif ++// ++// 4.3 MAC TX configuration registers (offset:0x1300) ++// ++ ++#define EDCA_AC0_CFG 0x1300 //AC_TXOP_CSR0 0x3474 ++#define EDCA_AC1_CFG 0x1304 ++#define EDCA_AC2_CFG 0x1308 ++#define EDCA_AC3_CFG 0x130c ++#ifdef RT_BIG_ENDIAN ++typedef union _EDCA_AC_CFG_STRUC { ++ struct { ++ UINT32 :12; // ++ UINT32 Cwmax:4; //unit power of 2 ++ UINT32 Cwmin:4; // ++ UINT32 Aifsn:4; // # of slot time ++ UINT32 AcTxop:8; // in unit of 32us ++ } field; ++ UINT32 word; ++} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; ++#else ++typedef union _EDCA_AC_CFG_STRUC { ++ struct { ++ UINT32 AcTxop:8; // in unit of 32us ++ UINT32 Aifsn:4; // # of slot time ++ UINT32 Cwmin:4; // ++ UINT32 Cwmax:4; //unit power of 2 ++ UINT32 :12; // ++ } field; ++ UINT32 word; ++} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; ++#endif ++ ++#define EDCA_TID_AC_MAP 0x1310 ++#define TX_PWR_CFG_0 0x1314 ++#define TX_PWR_CFG_1 0x1318 ++#define TX_PWR_CFG_2 0x131C ++#define TX_PWR_CFG_3 0x1320 ++#define TX_PWR_CFG_4 0x1324 ++#define TX_PIN_CFG 0x1328 ++#define TX_BAND_CFG 0x132c // 0x1 use upper 20MHz. 0 juse lower 20MHz ++#define TX_SW_CFG0 0x1330 ++#define TX_SW_CFG1 0x1334 ++#define TX_SW_CFG2 0x1338 ++#define TXOP_THRES_CFG 0x133c ++#define TXOP_CTRL_CFG 0x1340 ++#define TX_RTS_CFG 0x1344 ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_RTS_CFG_STRUC { ++ struct { ++ UINT32 rsv:7; ++ UINT32 RtsFbkEn:1; // enable rts rate fallback ++ UINT32 RtsThres:16; // unit:byte ++ UINT32 AutoRtsRetryLimit:8; ++ } field; ++ UINT32 word; ++} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; ++#else ++typedef union _TX_RTS_CFG_STRUC { ++ struct { ++ UINT32 AutoRtsRetryLimit:8; ++ UINT32 RtsThres:16; // unit:byte ++ UINT32 RtsFbkEn:1; // enable rts rate fallback ++ UINT32 rsv:7; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; ++#endif ++#define TX_TIMEOUT_CFG 0x1348 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_TIMEOUT_CFG_STRUC { ++ struct { ++ UINT32 rsv2:8; ++ UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) ++ UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure ++ UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us ++ UINT32 rsv:4; ++ } field; ++ UINT32 word; ++} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; ++#else ++typedef union _TX_TIMEOUT_CFG_STRUC { ++ struct { ++ UINT32 rsv:4; ++ UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us ++ UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure ++ UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) ++ UINT32 rsv2:8; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; ++#endif ++#define TX_RTY_CFG 0x134c ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_RTY_CFG_STRUC { ++ struct { ++ UINT32 rsv:1; ++ UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable ++ UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 LongRtyThre:12; // Long retry threshoold ++ UINT32 LongRtyLimit:8; //long retry limit ++ UINT32 ShortRtyLimit:8; // short retry limit ++ ++ } field; ++ UINT32 word; ++} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; ++#else ++typedef union PACKED _TX_RTY_CFG_STRUC { ++ struct { ++ UINT32 ShortRtyLimit:8; // short retry limit ++ UINT32 LongRtyLimit:8; //long retry limit ++ UINT32 LongRtyThre:12; // Long retry threshoold ++ UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable ++ UINT32 rsv:1; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; ++#endif ++#define TX_LINK_CFG 0x1350 ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_LINK_CFG_STRUC { ++ struct PACKED { ++ UINT32 RemotMFS:8; //remote MCS feedback sequence number ++ UINT32 RemotMFB:8; // remote MCS feedback ++ UINT32 rsv:3; // ++ UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable ++ UINT32 TxRDGEn:1; // RDG TX enable ++ UINT32 TxMRQEn:1; // MCS request TX enable ++ UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) ++ UINT32 MFBEnable:1; // TX apply remote MFB 1:enable ++ UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us ++ } field; ++ UINT32 word; ++} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; ++#else ++typedef union PACKED _TX_LINK_CFG_STRUC { ++ struct PACKED { ++ UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us ++ UINT32 MFBEnable:1; // TX apply remote MFB 1:enable ++ UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) ++ UINT32 TxMRQEn:1; // MCS request TX enable ++ UINT32 TxRDGEn:1; // RDG TX enable ++ UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable ++ UINT32 rsv:3; // ++ UINT32 RemotMFB:8; // remote MCS feedback ++ UINT32 RemotMFS:8; //remote MCS feedback sequence number ++ } field; ++ UINT32 word; ++} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; ++#endif ++#define HT_FBK_CFG0 0x1354 ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _HT_FBK_CFG0_STRUC { ++ struct { ++ UINT32 HTMCS7FBK:4; ++ UINT32 HTMCS6FBK:4; ++ UINT32 HTMCS5FBK:4; ++ UINT32 HTMCS4FBK:4; ++ UINT32 HTMCS3FBK:4; ++ UINT32 HTMCS2FBK:4; ++ UINT32 HTMCS1FBK:4; ++ UINT32 HTMCS0FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; ++#else ++typedef union PACKED _HT_FBK_CFG0_STRUC { ++ struct { ++ UINT32 HTMCS0FBK:4; ++ UINT32 HTMCS1FBK:4; ++ UINT32 HTMCS2FBK:4; ++ UINT32 HTMCS3FBK:4; ++ UINT32 HTMCS4FBK:4; ++ UINT32 HTMCS5FBK:4; ++ UINT32 HTMCS6FBK:4; ++ UINT32 HTMCS7FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; ++#endif ++#define HT_FBK_CFG1 0x1358 ++#ifdef RT_BIG_ENDIAN ++typedef union _HT_FBK_CFG1_STRUC { ++ struct { ++ UINT32 HTMCS15FBK:4; ++ UINT32 HTMCS14FBK:4; ++ UINT32 HTMCS13FBK:4; ++ UINT32 HTMCS12FBK:4; ++ UINT32 HTMCS11FBK:4; ++ UINT32 HTMCS10FBK:4; ++ UINT32 HTMCS9FBK:4; ++ UINT32 HTMCS8FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; ++#else ++typedef union _HT_FBK_CFG1_STRUC { ++ struct { ++ UINT32 HTMCS8FBK:4; ++ UINT32 HTMCS9FBK:4; ++ UINT32 HTMCS10FBK:4; ++ UINT32 HTMCS11FBK:4; ++ UINT32 HTMCS12FBK:4; ++ UINT32 HTMCS13FBK:4; ++ UINT32 HTMCS14FBK:4; ++ UINT32 HTMCS15FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; ++#endif ++#define LG_FBK_CFG0 0x135c ++#ifdef RT_BIG_ENDIAN ++typedef union _LG_FBK_CFG0_STRUC { ++ struct { ++ UINT32 OFDMMCS7FBK:4; //initial value is 6 ++ UINT32 OFDMMCS6FBK:4; //initial value is 5 ++ UINT32 OFDMMCS5FBK:4; //initial value is 4 ++ UINT32 OFDMMCS4FBK:4; //initial value is 3 ++ UINT32 OFDMMCS3FBK:4; //initial value is 2 ++ UINT32 OFDMMCS2FBK:4; //initial value is 1 ++ UINT32 OFDMMCS1FBK:4; //initial value is 0 ++ UINT32 OFDMMCS0FBK:4; //initial value is 0 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; ++#else ++typedef union _LG_FBK_CFG0_STRUC { ++ struct { ++ UINT32 OFDMMCS0FBK:4; //initial value is 0 ++ UINT32 OFDMMCS1FBK:4; //initial value is 0 ++ UINT32 OFDMMCS2FBK:4; //initial value is 1 ++ UINT32 OFDMMCS3FBK:4; //initial value is 2 ++ UINT32 OFDMMCS4FBK:4; //initial value is 3 ++ UINT32 OFDMMCS5FBK:4; //initial value is 4 ++ UINT32 OFDMMCS6FBK:4; //initial value is 5 ++ UINT32 OFDMMCS7FBK:4; //initial value is 6 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; ++#endif ++#define LG_FBK_CFG1 0x1360 ++#ifdef RT_BIG_ENDIAN ++typedef union _LG_FBK_CFG1_STRUC { ++ struct { ++ UINT32 rsv:16; ++ UINT32 CCKMCS3FBK:4; //initial value is 2 ++ UINT32 CCKMCS2FBK:4; //initial value is 1 ++ UINT32 CCKMCS1FBK:4; //initial value is 0 ++ UINT32 CCKMCS0FBK:4; //initial value is 0 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; ++#else ++typedef union _LG_FBK_CFG1_STRUC { ++ struct { ++ UINT32 CCKMCS0FBK:4; //initial value is 0 ++ UINT32 CCKMCS1FBK:4; //initial value is 0 ++ UINT32 CCKMCS2FBK:4; //initial value is 1 ++ UINT32 CCKMCS3FBK:4; //initial value is 2 ++ UINT32 rsv:16; ++ } field; ++ UINT32 word; ++} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; ++#endif ++ ++//======================================================= ++//================ Protection Paramater================================ ++//======================================================= ++#define CCK_PROT_CFG 0x1364 //CCK Protection ++#define ASIC_SHORTNAV 1 ++#define ASIC_LONGNAV 2 ++#define ASIC_RTS 1 ++#define ASIC_CTS 2 ++#ifdef RT_BIG_ENDIAN ++typedef union _PROT_CFG_STRUC { ++ struct { ++ UINT32 rsv:5; ++ UINT32 RTSThEn:1; //RTS threshold enable on CCK TX ++ UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. ++ UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. ++ UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv ++ UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv ++ UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). ++ } field; ++ UINT32 word; ++} PROT_CFG_STRUC, *PPROT_CFG_STRUC; ++#else ++typedef union _PROT_CFG_STRUC { ++ struct { ++ UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). ++ UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv ++ UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv ++ UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. ++ UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 RTSThEn:1; //RTS threshold enable on CCK TX ++ UINT32 rsv:5; ++ } field; ++ UINT32 word; ++} PROT_CFG_STRUC, *PPROT_CFG_STRUC; ++#endif ++ ++#define OFDM_PROT_CFG 0x1368 //OFDM Protection ++#define MM20_PROT_CFG 0x136C //MM20 Protection ++#define MM40_PROT_CFG 0x1370 //MM40 Protection ++#define GF20_PROT_CFG 0x1374 //GF20 Protection ++#define GF40_PROT_CFG 0x1378 //GR40 Protection ++#define EXP_CTS_TIME 0x137C // ++#define EXP_ACK_TIME 0x1380 // ++ ++// ++// 4.4 MAC RX configuration registers (offset:0x1400) ++// ++#define RX_FILTR_CFG 0x1400 //TXRX_CSR0 ++#define AUTO_RSP_CFG 0x1404 //TXRX_CSR4 ++// ++// TXRX_CSR4: Auto-Responder/ ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _AUTO_RSP_CFG_STRUC { ++ struct { ++ UINT32 :24; ++ UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame ++ UINT32 DualCTSEn:1; // Power bit value in conrtrol frame ++ UINT32 rsv:1; // Power bit value in conrtrol frame ++ UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble ++ UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode ++ UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode ++ UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble ++ UINT32 AutoResponderEnable:1; ++ } field; ++ UINT32 word; ++} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; ++#else ++typedef union _AUTO_RSP_CFG_STRUC { ++ struct { ++ UINT32 AutoResponderEnable:1; ++ UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble ++ UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode ++ UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode ++ UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble ++ UINT32 rsv:1; // Power bit value in conrtrol frame ++ UINT32 DualCTSEn:1; // Power bit value in conrtrol frame ++ UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame ++ UINT32 :24; ++ } field; ++ UINT32 word; ++} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; ++#endif ++ ++#define LEGACY_BASIC_RATE 0x1408 // TXRX_CSR5 0x3054 ++#define HT_BASIC_RATE 0x140c ++#define HT_CTRL_CFG 0x1410 ++#define SIFS_COST_CFG 0x1414 ++#define RX_PARSER_CFG 0x1418 //Set NAV for all received frames ++ ++// ++// 4.5 MAC Security configuration (offset:0x1500) ++// ++#define TX_SEC_CNT0 0x1500 // ++#define RX_SEC_CNT0 0x1504 // ++#define CCMP_FC_MUTE 0x1508 // ++// ++// 4.6 HCCA/PSMP (offset:0x1600) ++// ++#define TXOP_HLDR_ADDR0 0x1600 ++#define TXOP_HLDR_ADDR1 0x1604 ++#define TXOP_HLDR_ET 0x1608 ++#define QOS_CFPOLL_RA_DW0 0x160c ++#define QOS_CFPOLL_A1_DW1 0x1610 ++#define QOS_CFPOLL_QC 0x1614 ++// ++// 4.7 MAC Statistis registers (offset:0x1700) ++// ++#define RX_STA_CNT0 0x1700 // ++#define RX_STA_CNT1 0x1704 // ++#define RX_STA_CNT2 0x1708 // ++ ++// ++// RX_STA_CNT0_STRUC: RX PLCP error count & RX CRC error count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT0_STRUC { ++ struct { ++ USHORT PhyErr; ++ USHORT CrcErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; ++#else ++typedef union _RX_STA_CNT0_STRUC { ++ struct { ++ USHORT CrcErr; ++ USHORT PhyErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; ++#endif ++ ++// ++// RX_STA_CNT1_STRUC: RX False CCA count & RX LONG frame count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT1_STRUC { ++ struct { ++ USHORT PlcpErr; ++ USHORT FalseCca; ++ } field; ++ UINT32 word; ++} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; ++#else ++typedef union _RX_STA_CNT1_STRUC { ++ struct { ++ USHORT FalseCca; ++ USHORT PlcpErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; ++#endif ++ ++// ++// RX_STA_CNT2_STRUC: ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT2_STRUC { ++ struct { ++ USHORT RxFifoOverflowCount; ++ USHORT RxDupliCount; ++ } field; ++ UINT32 word; ++} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; ++#else ++typedef union _RX_STA_CNT2_STRUC { ++ struct { ++ USHORT RxDupliCount; ++ USHORT RxFifoOverflowCount; ++ } field; ++ UINT32 word; ++} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; ++#endif ++#define TX_STA_CNT0 0x170C // ++// ++// STA_CSR3: TX Beacon count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT0_STRUC { ++ struct { ++ USHORT TxBeaconCount; ++ USHORT TxFailCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; ++#else ++typedef union _TX_STA_CNT0_STRUC { ++ struct { ++ USHORT TxFailCount; ++ USHORT TxBeaconCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; ++#endif ++#define TX_STA_CNT1 0x1710 // ++// ++// TX_STA_CNT1: TX tx count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT1_STRUC { ++ struct { ++ USHORT TxRetransmit; ++ USHORT TxSuccess; ++ } field; ++ UINT32 word; ++} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; ++#else ++typedef union _TX_STA_CNT1_STRUC { ++ struct { ++ USHORT TxSuccess; ++ USHORT TxRetransmit; ++ } field; ++ UINT32 word; ++} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; ++#endif ++#define TX_STA_CNT2 0x1714 // ++// ++// TX_STA_CNT2: TX tx count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT2_STRUC { ++ struct { ++ USHORT TxUnderFlowCount; ++ USHORT TxZeroLenCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; ++#else ++typedef union _TX_STA_CNT2_STRUC { ++ struct { ++ USHORT TxZeroLenCount; ++ USHORT TxUnderFlowCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; ++#endif ++#define TX_STA_FIFO 0x1718 // ++// ++// TX_STA_FIFO_STRUC: TX Result for specific PID status fifo register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_STA_FIFO_STRUC { ++ struct { ++ UINT32 Reserve:2; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 wcid:8; //wireless client index ++ UINT32 TxAckRequired:1; // ack required ++ UINT32 TxAggre:1; // Tx is aggregated ++ UINT32 TxSuccess:1; // Tx success. whether success or not ++ UINT32 PidType:4; ++ UINT32 bValid:1; // 1:This register contains a valid TX result ++ } field; ++ UINT32 word; ++} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; ++#else ++typedef union PACKED _TX_STA_FIFO_STRUC { ++ struct { ++ UINT32 bValid:1; // 1:This register contains a valid TX result ++ UINT32 PidType:4; ++ UINT32 TxSuccess:1; // Tx No retry success ++ UINT32 TxAggre:1; // Tx Retry Success ++ UINT32 TxAckRequired:1; // Tx fail ++ UINT32 wcid:8; //wireless client index ++// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 TxBF:1; ++ UINT32 Reserve:2; ++ } field; ++ UINT32 word; ++} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT 0x171c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT_STRUC { ++ struct { ++ USHORT AggTxCount; ++ USHORT NonAggTxCount; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; ++#else ++typedef union _TX_AGG_CNT_STRUC { ++ struct { ++ USHORT NonAggTxCount; ++ USHORT AggTxCount; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT0 0x1720 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT0_STRUC { ++ struct { ++ USHORT AggSize2Count; ++ USHORT AggSize1Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; ++#else ++typedef union _TX_AGG_CNT0_STRUC { ++ struct { ++ USHORT AggSize1Count; ++ USHORT AggSize2Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT1 0x1724 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT1_STRUC { ++ struct { ++ USHORT AggSize4Count; ++ USHORT AggSize3Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; ++#else ++typedef union _TX_AGG_CNT1_STRUC { ++ struct { ++ USHORT AggSize3Count; ++ USHORT AggSize4Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; ++#endif ++#define TX_AGG_CNT2 0x1728 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT2_STRUC { ++ struct { ++ USHORT AggSize6Count; ++ USHORT AggSize5Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; ++#else ++typedef union _TX_AGG_CNT2_STRUC { ++ struct { ++ USHORT AggSize5Count; ++ USHORT AggSize6Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT3 0x172c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT3_STRUC { ++ struct { ++ USHORT AggSize8Count; ++ USHORT AggSize7Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; ++#else ++typedef union _TX_AGG_CNT3_STRUC { ++ struct { ++ USHORT AggSize7Count; ++ USHORT AggSize8Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT4 0x1730 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT4_STRUC { ++ struct { ++ USHORT AggSize10Count; ++ USHORT AggSize9Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; ++#else ++typedef union _TX_AGG_CNT4_STRUC { ++ struct { ++ USHORT AggSize9Count; ++ USHORT AggSize10Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; ++#endif ++#define TX_AGG_CNT5 0x1734 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT5_STRUC { ++ struct { ++ USHORT AggSize12Count; ++ USHORT AggSize11Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; ++#else ++typedef union _TX_AGG_CNT5_STRUC { ++ struct { ++ USHORT AggSize11Count; ++ USHORT AggSize12Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; ++#endif ++#define TX_AGG_CNT6 0x1738 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT6_STRUC { ++ struct { ++ USHORT AggSize14Count; ++ USHORT AggSize13Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; ++#else ++typedef union _TX_AGG_CNT6_STRUC { ++ struct { ++ USHORT AggSize13Count; ++ USHORT AggSize14Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; ++#endif ++#define TX_AGG_CNT7 0x173c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT7_STRUC { ++ struct { ++ USHORT AggSize16Count; ++ USHORT AggSize15Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; ++#else ++typedef union _TX_AGG_CNT7_STRUC { ++ struct { ++ USHORT AggSize15Count; ++ USHORT AggSize16Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; ++#endif ++#define MPDU_DENSITY_CNT 0x1740 ++#ifdef RT_BIG_ENDIAN ++typedef union _MPDU_DEN_CNT_STRUC { ++ struct { ++ USHORT RXZeroDelCount; //RX zero length delimiter count ++ USHORT TXZeroDelCount; //TX zero length delimiter count ++ } field; ++ UINT32 word; ++} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; ++#else ++typedef union _MPDU_DEN_CNT_STRUC { ++ struct { ++ USHORT TXZeroDelCount; //TX zero length delimiter count ++ USHORT RXZeroDelCount; //RX zero length delimiter count ++ } field; ++ UINT32 word; ++} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; ++#endif ++// ++// TXRX control registers - base address 0x3000 ++// ++// rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. ++#define TXRX_CSR1 0x77d0 ++ ++// ++// Security key table memory, base address = 0x1000 ++// ++#define MAC_WCID_BASE 0x1800 //8-bytes(use only 6-bytes) * 256 entry = ++#define HW_WCID_ENTRY_SIZE 8 ++#define PAIRWISE_KEY_TABLE_BASE 0x4000 // 32-byte * 256-entry = -byte ++#define HW_KEY_ENTRY_SIZE 0x20 ++#define PAIRWISE_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte ++#define MAC_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte ++#define HW_IVEIV_ENTRY_SIZE 8 ++#define MAC_WCID_ATTRIBUTE_BASE 0x6800 // 4-byte * 256-entry = -byte ++#define HW_WCID_ATTRI_SIZE 4 ++#define WCID_RESERVED 0x6bfc ++#define SHARED_KEY_TABLE_BASE 0x6c00 // 32-byte * 16-entry = 512-byte ++#define SHARED_KEY_MODE_BASE 0x7000 // 32-byte * 16-entry = 512-byte ++#define HW_SHARED_KEY_MODE_SIZE 4 ++#define SHAREDKEYTABLE 0 ++#define PAIRWISEKEYTABLE 1 ++ ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _SHAREDKEY_MODE_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 Bss1Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key0CipherAlg:3; ++ } field; ++ UINT32 word; ++} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; ++#else ++typedef union _SHAREDKEY_MODE_STRUC { ++ struct { ++ UINT32 Bss0Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key3CipherAlg:3; ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; ++#endif ++// 64-entry for pairwise key table ++typedef struct _HW_WCID_ENTRY { // 8-byte per entry ++ UCHAR Address[6]; ++ UCHAR Rsv[2]; ++} HW_WCID_ENTRY, PHW_WCID_ENTRY; ++ ++ ++ ++// ++// Other on-chip shared memory space, base = 0x2000 ++// ++ ++// CIS space - base address = 0x2000 ++#define HW_CIS_BASE 0x2000 ++ ++// Carrier-sense CTS frame base address. It's where mac stores carrier-sense frame for carrier-sense function. ++#define HW_CS_CTS_BASE 0x7700 ++// DFS CTS frame base address. It's where mac stores CTS frame for DFS. ++#define HW_DFS_CTS_BASE 0x7780 ++#define HW_CTS_FRAME_SIZE 0x80 ++ ++// 2004-11-08 john - since NULL frame won't be that long (256 byte). We steal 16 tail bytes ++// to save debugging settings ++#define HW_DEBUG_SETTING_BASE 0x77f0 // 0x77f0~0x77ff total 16 bytes ++#define HW_DEBUG_SETTING_BASE2 0x7770 // 0x77f0~0x77ff total 16 bytes ++ ++// In order to support maximum 8 MBSS and its maximum length is 512 for each beacon ++// Three section discontinue memory segments will be used. ++// 1. The original region for BCN 0~3 ++// 2. Extract memory from FCE table for BCN 4~5 ++// 3. Extract memory from Pair-wise key table for BCN 6~7 ++// It occupied those memory of wcid 238~253 for BCN 6 ++// and wcid 222~237 for BCN 7 ++#define HW_BEACON_MAX_SIZE 0x1000 /* unit: byte */ ++#define HW_BEACON_BASE0 0x7800 ++#define HW_BEACON_BASE1 0x7A00 ++#define HW_BEACON_BASE2 0x7C00 ++#define HW_BEACON_BASE3 0x7E00 ++#define HW_BEACON_BASE4 0x7200 ++#define HW_BEACON_BASE5 0x7400 ++#define HW_BEACON_BASE6 0x5DC0 ++#define HW_BEACON_BASE7 0x5BC0 ++ ++#define HW_BEACON_MAX_COUNT 8 ++#define HW_BEACON_OFFSET 0x0200 ++#define HW_BEACON_CONTENT_LEN (HW_BEACON_OFFSET - TXWI_SIZE) ++ ++// HOST-MCU shared memory - base address = 0x2100 ++#define HOST_CMD_CSR 0x404 ++#define H2M_MAILBOX_CSR 0x7010 ++#define H2M_MAILBOX_CID 0x7014 ++#define H2M_MAILBOX_STATUS 0x701c ++#define H2M_INT_SRC 0x7024 ++#define H2M_BBP_AGENT 0x7028 ++#define M2H_CMD_DONE_CSR 0x000c ++#define MCU_TXOP_ARRAY_BASE 0x000c // TODO: to be provided by Albert ++#define MCU_TXOP_ENTRY_SIZE 32 // TODO: to be provided by Albert ++#define MAX_NUM_OF_TXOP_ENTRY 16 // TODO: must be same with 8051 firmware ++#define MCU_MBOX_VERSION 0x01 // TODO: to be confirmed by Albert ++#define MCU_MBOX_VERSION_OFFSET 5 // TODO: to be provided by Albert ++ ++// ++// Host DMA registers - base address 0x200 . TX0-3=EDCAQid0-3, TX4=HCCA, TX5=MGMT, ++// ++// ++// DMA RING DESCRIPTOR ++// ++#define E2PROM_CSR 0x0004 ++#define IO_CNTL_CSR 0x77d0 ++ ++#ifdef RT2860 ++// 8051 firmware image for RT2860 - base address = 0x4000 ++#define FIRMWARE_IMAGE_BASE 0x2000 ++#define MAX_FIRMWARE_IMAGE_SIZE 0x2000 // 8kbyte ++#endif // RT2860 // ++ ++ ++// ================================================================ ++// Tx / Rx / Mgmt ring descriptor definition ++// ================================================================ ++ ++// the following PID values are used to mark outgoing frame type in TXD->PID so that ++// proper TX statistics can be collected based on these categories ++// b3-2 of PID field - ++#define PID_MGMT 0x05 ++#define PID_BEACON 0x0c ++#define PID_DATA_NORMALUCAST 0x02 ++#define PID_DATA_AMPDU 0x04 ++#define PID_DATA_NO_ACK 0x08 ++#define PID_DATA_NOT_NORM_ACK 0x03 ++// value domain of pTxD->HostQId (4-bit: 0~15) ++#define QID_AC_BK 1 // meet ACI definition in 802.11e ++#define QID_AC_BE 0 // meet ACI definition in 802.11e ++#define QID_AC_VI 2 ++#define QID_AC_VO 3 ++#define QID_HCCA 4 ++#define NUM_OF_TX_RING 5 ++#define QID_MGMT 13 ++#define QID_RX 14 ++#define QID_OTHER 15 ++ ++ ++// ------------------------------------------------------ ++// BBP & RF definition ++// ------------------------------------------------------ ++#define BUSY 1 ++#define IDLE 0 ++ ++#define RF_R00 0 ++#define RF_R01 1 ++#define RF_R02 2 ++#define RF_R03 3 ++#define RF_R04 4 ++#define RF_R05 5 ++#define RF_R06 6 ++#define RF_R07 7 ++#define RF_R08 8 ++#define RF_R09 9 ++#define RF_R10 10 ++#define RF_R11 11 ++#define RF_R12 12 ++#define RF_R13 13 ++#define RF_R14 14 ++#define RF_R15 15 ++#define RF_R16 16 ++#define RF_R17 17 ++#define RF_R18 18 ++#define RF_R19 19 ++#define RF_R20 20 ++#define RF_R21 21 ++#define RF_R22 22 ++#define RF_R23 23 ++#define RF_R24 24 ++#define RF_R25 25 ++#define RF_R26 26 ++#define RF_R27 27 ++#define RF_R28 28 ++#define RF_R29 29 ++#define RF_R30 30 ++#define RF_R31 31 ++ ++#define BBP_R0 0 // version ++#define BBP_R1 1 // TSSI ++#define BBP_R2 2 // TX configure ++#define BBP_R3 3 ++#define BBP_R4 4 ++#define BBP_R5 5 ++#define BBP_R6 6 ++#define BBP_R14 14 // RX configure ++#define BBP_R16 16 ++#define BBP_R17 17 // RX sensibility ++#define BBP_R18 18 ++#define BBP_R21 21 ++#define BBP_R22 22 ++#define BBP_R24 24 ++#define BBP_R25 25 ++#define BBP_R49 49 //TSSI ++#define BBP_R50 50 ++#define BBP_R51 51 ++#define BBP_R52 52 ++#define BBP_R55 55 ++#define BBP_R62 62 // Rx SQ0 Threshold HIGH ++#define BBP_R63 63 ++#define BBP_R64 64 ++#define BBP_R65 65 ++#define BBP_R66 66 ++#define BBP_R67 67 ++#define BBP_R68 68 ++#define BBP_R69 69 ++#define BBP_R70 70 // Rx AGC SQ CCK Xcorr threshold ++#define BBP_R73 73 ++#define BBP_R75 75 ++#define BBP_R77 77 ++#define BBP_R81 81 ++#define BBP_R82 82 ++#define BBP_R83 83 ++#define BBP_R84 84 ++#define BBP_R86 86 ++#define BBP_R91 91 ++#define BBP_R92 92 ++#define BBP_R94 94 // Tx Gain Control ++#define BBP_R103 103 ++#define BBP_R105 105 ++#define BBP_R113 113 ++#define BBP_R114 114 ++#define BBP_R115 115 ++#define BBP_R116 116 ++#define BBP_R117 117 ++#define BBP_R118 118 ++#define BBP_R119 119 ++#define BBP_R120 120 ++#define BBP_R121 121 ++#define BBP_R122 122 ++#define BBP_R123 123 ++ ++ ++#define BBPR94_DEFAULT 0x06 // Add 1 value will gain 1db ++ ++#define RSSI_FOR_VERY_LOW_SENSIBILITY -35 ++#define RSSI_FOR_LOW_SENSIBILITY -58 ++#define RSSI_FOR_MID_LOW_SENSIBILITY -80 ++#define RSSI_FOR_MID_SENSIBILITY -90 ++ ++//------------------------------------------------------------------------- ++// EEPROM definition ++//------------------------------------------------------------------------- ++#define EEDO 0x08 ++#define EEDI 0x04 ++#define EECS 0x02 ++#define EESK 0x01 ++#define EERL 0x80 ++ ++#define EEPROM_WRITE_OPCODE 0x05 ++#define EEPROM_READ_OPCODE 0x06 ++#define EEPROM_EWDS_OPCODE 0x10 ++#define EEPROM_EWEN_OPCODE 0x13 ++ ++#define NUM_EEPROM_BBP_PARMS 19 // Include NIC Config 0, 1, CR, TX ALC step, BBPs ++#define NUM_EEPROM_TX_G_PARMS 7 ++#define EEPROM_NIC1_OFFSET 0x34 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_NIC2_OFFSET 0x36 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_BBP_BASE_OFFSET 0xf0 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_G_TX_PWR_OFFSET 0x52 ++#define EEPROM_G_TX2_PWR_OFFSET 0x60 ++#define EEPROM_LED1_OFFSET 0x3c ++#define EEPROM_LED2_OFFSET 0x3e ++#define EEPROM_LED3_OFFSET 0x40 ++#define EEPROM_LNA_OFFSET 0x44 ++#define EEPROM_RSSI_BG_OFFSET 0x46 ++#define EEPROM_RSSI_A_OFFSET 0x4a ++#define EEPROM_DEFINE_MAX_TXPWR 0x4e ++#define EEPROM_TXPOWER_BYRATE_20MHZ_2_4G 0xde // 20MHZ 2.4G tx power. ++#define EEPROM_TXPOWER_BYRATE_40MHZ_2_4G 0xee // 40MHZ 2.4G tx power. ++#define EEPROM_TXPOWER_BYRATE_20MHZ_5G 0xfa // 20MHZ 5G tx power. ++#define EEPROM_TXPOWER_BYRATE_40MHZ_5G 0x10a // 40MHZ 5G tx power. ++#define EEPROM_A_TX_PWR_OFFSET 0x78 ++#define EEPROM_A_TX2_PWR_OFFSET 0xa6 ++#define EEPROM_VERSION_OFFSET 0x02 ++#define EEPROM_FREQ_OFFSET 0x3a ++#define EEPROM_TXPOWER_BYRATE 0xde // 20MHZ power. ++#define EEPROM_TXPOWER_DELTA 0x50 // 20MHZ AND 40 MHZ use different power. This is delta in 40MHZ. ++#define VALID_EEPROM_VERSION 1 ++ ++// PairKeyMode definition ++#define PKMODE_NONE 0 ++#define PKMODE_WEP64 1 ++#define PKMODE_WEP128 2 ++#define PKMODE_TKIP 3 ++#define PKMODE_AES 4 ++#define PKMODE_CKIP64 5 ++#define PKMODE_CKIP128 6 ++#define PKMODE_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table ++ ++// ================================================================================= ++// WCID format ++// ================================================================================= ++//7.1 WCID ENTRY format : 8bytes ++typedef struct _WCID_ENTRY_STRUC { ++ UCHAR RXBABitmap7; // bit0 for TID8, bit7 for TID 15 ++ UCHAR RXBABitmap0; // bit0 for TID0, bit7 for TID 7 ++ UCHAR MAC[6]; // 0 for shared key table. 1 for pairwise key table ++} WCID_ENTRY_STRUC, *PWCID_ENTRY_STRUC; ++ ++//8.1.1 SECURITY KEY format : 8DW ++// 32-byte per entry, total 16-entry for shared key table, 64-entry for pairwise key table ++typedef struct _HW_KEY_ENTRY { // 32-byte per entry ++ UCHAR Key[16]; ++ UCHAR TxMic[8]; ++ UCHAR RxMic[8]; ++} HW_KEY_ENTRY, *PHW_KEY_ENTRY; ++ ++//8.1.2 IV/EIV format : 2DW ++ ++//8.1.3 RX attribute entry format : 1DW ++#ifdef RT_BIG_ENDIAN ++typedef struct _MAC_ATTRIBUTE_STRUC { ++ UINT32 rsv:22; ++ UINT32 RXWIUDF:3; ++ UINT32 BSSIDIdx:3; //multipleBSS index for the WCID ++ UINT32 PairKeyMode:3; ++ UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table ++} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; ++#else ++typedef struct _MAC_ATTRIBUTE_STRUC { ++ UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table ++ UINT32 PairKeyMode:3; ++ UINT32 BSSIDIdx:3; //multipleBSS index for the WCID ++ UINT32 RXWIUDF:3; ++ UINT32 rsv:22; ++} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; ++#endif ++ ++ ++// ================================================================================= ++// TX / RX ring descriptor format ++// ================================================================================= ++ ++// the first 24-byte in TXD is called TXINFO and will be DMAed to MAC block through TXFIFO. ++// MAC block use this TXINFO to control the transmission behavior of this frame. ++#define FIFO_MGMT 0 ++#define FIFO_HCCA 1 ++#define FIFO_EDCA 2 ++ ++// ++// TX descriptor format, Tx ring, Mgmt Ring ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _TXD_STRUC { ++ // Word 0 ++ UINT32 SDPtr0; ++ // Word 1 ++ UINT32 DMADONE:1; ++ UINT32 LastSec0:1; ++ UINT32 SDLen0:14; ++ UINT32 Burst:1; ++ UINT32 LastSec1:1; ++ UINT32 SDLen1:14; ++ // Word 2 ++ UINT32 SDPtr1; ++ // Word 3 ++ UINT32 ICO:1; ++ UINT32 UCO:1; ++ UINT32 TCO:1; ++ UINT32 rsv:2; ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 rsv2:24; ++} TXD_STRUC, *PTXD_STRUC; ++#else ++typedef struct PACKED _TXD_STRUC { ++ // Word 0 ++ UINT32 SDPtr0; ++ // Word 1 ++ UINT32 SDLen1:14; ++ UINT32 LastSec1:1; ++ UINT32 Burst:1; ++ UINT32 SDLen0:14; ++ UINT32 LastSec0:1; ++ UINT32 DMADONE:1; ++ //Word2 ++ UINT32 SDPtr1; ++ //Word3 ++ UINT32 rsv2:24; ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 rsv:2; ++ UINT32 TCO:1; // ++ UINT32 UCO:1; // ++ UINT32 ICO:1; // ++} TXD_STRUC, *PTXD_STRUC; ++#endif ++ ++ ++// ++// TXD Wireless Information format for Tx ring and Mgmt Ring ++// ++//txop : for txop mode ++// 0:txop for the MPDU frame will be handles by ASIC by register ++// 1/2/3:the MPDU frame is send after PIFS/backoff/SIFS ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _TXWI_STRUC { ++ // Word 0 ++ UINT32 PHYMODE:2; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 rsv2:1; ++ UINT32 Ifs:1; // ++ UINT32 STBC:2; //channel bandwidth 20MHz or 40 MHz ++ UINT32 ShortGI:1; ++ UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz ++ UINT32 MCS:7; ++ ++ UINT32 rsv:6; ++ UINT32 txop:2; //tx back off mode 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. ++ UINT32 MpduDensity:3; ++ UINT32 AMPDU:1; ++ ++ UINT32 TS:1; ++ UINT32 CFACK:1; ++ UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode ++ UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. ++ // Word 1 ++ UINT32 PacketId:4; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 WirelessCliID:8; ++ UINT32 BAWinSize:6; ++ UINT32 NSEQ:1; ++ UINT32 ACK:1; ++ // Word 2 ++ UINT32 IV; ++ // Word 3 ++ UINT32 EIV; ++} TXWI_STRUC, *PTXWI_STRUC; ++#else ++typedef struct PACKED _TXWI_STRUC { ++ // Word 0 ++ UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. ++ UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode ++ UINT32 CFACK:1; ++ UINT32 TS:1; ++ ++ UINT32 AMPDU:1; ++ UINT32 MpduDensity:3; ++ UINT32 txop:2; //FOR "THIS" frame. 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. ++ UINT32 rsv:6; ++ ++ UINT32 MCS:7; ++ UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz ++ UINT32 ShortGI:1; ++ UINT32 STBC:2; // 1: STBC support MCS =0-7, 2,3 : RESERVE ++ UINT32 Ifs:1; // ++ UINT32 rsv2:1; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 PHYMODE:2; ++ // Word 1 ++ UINT32 ACK:1; ++ UINT32 NSEQ:1; ++ UINT32 BAWinSize:6; ++ UINT32 WirelessCliID:8; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 PacketId:4; ++ //Word2 ++ UINT32 IV; ++ //Word3 ++ UINT32 EIV; ++} TXWI_STRUC, *PTXWI_STRUC; ++#endif ++// ++// Rx descriptor format, Rx Ring ++// ++#ifdef RT2860 ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _RXD_STRUC { ++ // Word 0 ++ UINT32 SDP0; ++ // Word 1 ++ UINT32 DDONE:1; ++ UINT32 LS0:1; ++ UINT32 SDL0:14; ++ UINT32 Rsv:2; ++ UINT32 SDL1:14; ++ // Word 2 ++ UINT32 SDP1; ++ // Word 3 ++ UINT32 Rsv1:13; ++ UINT32 PlcpRssil:1;// To be moved ++ UINT32 PlcpSignal:1; // To be moved ++ UINT32 Decrypted:1; // this frame is being decrypted. ++ UINT32 AMPDU:1; ++ UINT32 L2PAD:1; ++ UINT32 RSSI:1; ++ UINT32 HTC:1; ++ UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. obsolete. ++ UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid ++ UINT32 Crc:1; // 1: CRC error ++ UINT32 MyBss:1; // 1: this frame belongs to the same BSSID ++ UINT32 Bcast:1; // 1: this is a broadcast frame ++ UINT32 Mcast:1; // 1: this is a multicast frame ++ UINT32 U2M:1; // 1: this RX frame is unicast to me ++ UINT32 FRAG:1; ++ UINT32 NULLDATA:1; ++ UINT32 DATA:1; ++ UINT32 BA:1; ++ ++} RXD_STRUC, *PRXD_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; ++#else ++typedef struct PACKED _RXD_STRUC { ++ // Word 0 ++ UINT32 SDP0; ++ // Word 1 ++ UINT32 SDL1:14; ++ UINT32 Rsv:2; ++ UINT32 SDL0:14; ++ UINT32 LS0:1; ++ UINT32 DDONE:1; ++ // Word 2 ++ UINT32 SDP1; ++ // Word 3 ++ UINT32 BA:1; ++ UINT32 DATA:1; ++ UINT32 NULLDATA:1; ++ UINT32 FRAG:1; ++ UINT32 U2M:1; // 1: this RX frame is unicast to me ++ UINT32 Mcast:1; // 1: this is a multicast frame ++ UINT32 Bcast:1; // 1: this is a broadcast frame ++ UINT32 MyBss:1; // 1: this frame belongs to the same BSSID ++ UINT32 Crc:1; // 1: CRC error ++ UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid ++ UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. ++ UINT32 HTC:1; ++ UINT32 RSSI:1; ++ UINT32 L2PAD:1; ++ UINT32 AMPDU:1; ++ UINT32 Decrypted:1; // this frame is being decrypted. ++ UINT32 PlcpSignal:1; // To be moved ++ UINT32 PlcpRssil:1;// To be moved ++ UINT32 Rsv1:13; ++} RXD_STRUC, *PRXD_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; ++#endif ++#endif // RT2860 // ++// ++// RXWI wireless information format, in PBF. invisible in driver. ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _RXWI_STRUC { ++ // Word 0 ++ UINT32 TID:4; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 UDF:3; ++ UINT32 BSSID:3; ++ UINT32 KeyIndex:2; ++ UINT32 WirelessCliID:8; ++ // Word 1 ++ UINT32 PHYMODE:2; // 1: this RX frame is unicast to me ++ UINT32 rsv:3; ++ UINT32 STBC:2; ++ UINT32 ShortGI:1; ++ UINT32 BW:1; ++ UINT32 MCS:7; ++ UINT32 SEQUENCE:12; ++ UINT32 FRAG:4; ++ // Word 2 ++ UINT32 rsv1:8; ++ UINT32 RSSI2:8; ++ UINT32 RSSI1:8; ++ UINT32 RSSI0:8; ++ // Word 3 ++ UINT32 rsv2:16; ++ UINT32 SNR1:8; ++ UINT32 SNR0:8; ++} RXWI_STRUC, *PRXWI_STRUC; ++#else ++typedef struct PACKED _RXWI_STRUC { ++ // Word 0 ++ UINT32 WirelessCliID:8; ++ UINT32 KeyIndex:2; ++ UINT32 BSSID:3; ++ UINT32 UDF:3; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 TID:4; ++ // Word 1 ++ UINT32 FRAG:4; ++ UINT32 SEQUENCE:12; ++ UINT32 MCS:7; ++ UINT32 BW:1; ++ UINT32 ShortGI:1; ++ UINT32 STBC:2; ++ UINT32 rsv:3; ++ UINT32 PHYMODE:2; // 1: this RX frame is unicast to me ++ //Word2 ++ UINT32 RSSI0:8; ++ UINT32 RSSI1:8; ++ UINT32 RSSI2:8; ++ UINT32 rsv1:8; ++ //Word3 ++ UINT32 SNR0:8; ++ UINT32 SNR1:8; ++ UINT32 rsv2:16; ++} RXWI_STRUC, *PRXWI_STRUC; ++#endif ++ ++ ++// ================================================================================= ++// HOST-MCU communication data structure ++// ================================================================================= ++ ++// ++// H2M_MAILBOX_CSR: Host-to-MCU Mailbox ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _H2M_MAILBOX_STRUC { ++ struct { ++ UINT32 Owner:8; ++ UINT32 CmdToken:8; // 0xff tells MCU not to report CmdDoneInt after excuting the command ++ UINT32 HighByte:8; ++ UINT32 LowByte:8; ++ } field; ++ UINT32 word; ++} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; ++#else ++typedef union _H2M_MAILBOX_STRUC { ++ struct { ++ UINT32 LowByte:8; ++ UINT32 HighByte:8; ++ UINT32 CmdToken:8; ++ UINT32 Owner:8; ++ } field; ++ UINT32 word; ++} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; ++#endif ++ ++// ++// M2H_CMD_DONE_CSR: MCU-to-Host command complete indication ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _M2H_CMD_DONE_STRUC { ++ struct { ++ UINT32 CmdToken3; ++ UINT32 CmdToken2; ++ UINT32 CmdToken1; ++ UINT32 CmdToken0; ++ } field; ++ UINT32 word; ++} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; ++#else ++typedef union _M2H_CMD_DONE_STRUC { ++ struct { ++ UINT32 CmdToken0; ++ UINT32 CmdToken1; ++ UINT32 CmdToken2; ++ UINT32 CmdToken3; ++ } field; ++ UINT32 word; ++} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; ++#endif ++ ++ ++ ++// ++// MCU_LEDCS: MCU LED Control Setting. ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MCU_LEDCS_STRUC { ++ struct { ++ UCHAR Polarity:1; ++ UCHAR LedMode:7; ++ } field; ++ UCHAR word; ++} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; ++#else ++typedef union _MCU_LEDCS_STRUC { ++ struct { ++ UCHAR LedMode:7; ++ UCHAR Polarity:1; ++ } field; ++ UCHAR word; ++} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; ++#endif ++// ================================================================================= ++// Register format ++// ================================================================================= ++ ++ ++ ++//NAV_TIME_CFG :NAV ++#ifdef RT_BIG_ENDIAN ++typedef union _NAV_TIME_CFG_STRUC { ++ struct { ++ USHORT rsv:6; ++ USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable ++ USHORT Eifs:9; // in unit of 1-us ++ UCHAR SlotTime; // in unit of 1-us ++ UCHAR Sifs; // in unit of 1-us ++ } field; ++ UINT32 word; ++} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; ++#else ++typedef union _NAV_TIME_CFG_STRUC { ++ struct { ++ UCHAR Sifs; // in unit of 1-us ++ UCHAR SlotTime; // in unit of 1-us ++ USHORT Eifs:9; // in unit of 1-us ++ USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable ++ USHORT rsv:6; ++ } field; ++ UINT32 word; ++} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; ++#endif ++ ++ ++ ++ ++ ++// ++// RX_FILTR_CFG: /RX configuration register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union RX_FILTR_CFG_STRUC { ++ struct { ++ UINT32 :15; ++ UINT32 DropRsvCntlType:1; ++ ++ UINT32 DropBAR:1; // ++ UINT32 DropBA:1; // ++ UINT32 DropPsPoll:1; // Drop Ps-Poll ++ UINT32 DropRts:1; // Drop Ps-Poll ++ ++ UINT32 DropCts:1; // Drop Ps-Poll ++ UINT32 DropAck:1; // Drop Ps-Poll ++ UINT32 DropCFEnd:1; // Drop Ps-Poll ++ UINT32 DropCFEndAck:1; // Drop Ps-Poll ++ ++ UINT32 DropDuplicate:1; // Drop duplicate frame ++ UINT32 DropBcast:1; // Drop broadcast frames ++ UINT32 DropMcast:1; // Drop multicast frames ++ UINT32 DropVerErr:1; // Drop version error frame ++ ++ UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true ++ UINT32 DropNotToMe:1; // Drop not to me unicast frame ++ UINT32 DropPhyErr:1; // Drop physical error ++ UINT32 DropCRCErr:1; // Drop CRC error ++ } field; ++ UINT32 word; ++} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; ++#else ++typedef union _RX_FILTR_CFG_STRUC { ++ struct { ++ UINT32 DropCRCErr:1; // Drop CRC error ++ UINT32 DropPhyErr:1; // Drop physical error ++ UINT32 DropNotToMe:1; // Drop not to me unicast frame ++ UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true ++ ++ UINT32 DropVerErr:1; // Drop version error frame ++ UINT32 DropMcast:1; // Drop multicast frames ++ UINT32 DropBcast:1; // Drop broadcast frames ++ UINT32 DropDuplicate:1; // Drop duplicate frame ++ ++ UINT32 DropCFEndAck:1; // Drop Ps-Poll ++ UINT32 DropCFEnd:1; // Drop Ps-Poll ++ UINT32 DropAck:1; // Drop Ps-Poll ++ UINT32 DropCts:1; // Drop Ps-Poll ++ ++ UINT32 DropRts:1; // Drop Ps-Poll ++ UINT32 DropPsPoll:1; // Drop Ps-Poll ++ UINT32 DropBA:1; // ++ UINT32 DropBAR:1; // ++ ++ UINT32 DropRsvCntlType:1; ++ UINT32 :15; ++ } field; ++ UINT32 word; ++} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; ++#endif ++ ++ ++ ++ ++// ++// PHY_CSR4: RF serial control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _PHY_CSR4_STRUC { ++ struct { ++ UINT32 Busy:1; // 1: ASIC is busy execute RF programming. ++ UINT32 PLL_LD:1; // RF PLL_LD status ++ UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program ++ UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) ++ UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. ++ } field; ++ UINT32 word; ++} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; ++#else ++typedef union _PHY_CSR4_STRUC { ++ struct { ++ UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. ++ UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) ++ UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program ++ UINT32 PLL_LD:1; // RF PLL_LD status ++ UINT32 Busy:1; // 1: ASIC is busy execute RF programming. ++ } field; ++ UINT32 word; ++} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; ++#endif ++ ++ ++// ++// SEC_CSR5: shared key table security mode register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _SEC_CSR5_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 Bss3Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key0CipherAlg:3; ++ } field; ++ UINT32 word; ++} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; ++#else ++typedef union _SEC_CSR5_STRUC { ++ struct { ++ UINT32 Bss2Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key3CipherAlg:3; ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; ++#endif ++ ++ ++// ++// HOST_CMD_CSR: For HOST to interrupt embedded processor ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _HOST_CMD_CSR_STRUC { ++ struct { ++ UINT32 Rsv:24; ++ UINT32 HostCommand:8; ++ } field; ++ UINT32 word; ++} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; ++#else ++typedef union _HOST_CMD_CSR_STRUC { ++ struct { ++ UINT32 HostCommand:8; ++ UINT32 Rsv:24; ++ } field; ++ UINT32 word; ++} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; ++#endif ++ ++ ++// ++// AIFSN_CSR: AIFSN for each EDCA AC ++// ++ ++ ++ ++// ++// E2PROM_CSR: EEPROM control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _E2PROM_CSR_STRUC { ++ struct { ++ UINT32 Rsvd:25; ++ UINT32 LoadStatus:1; // 1:loading, 0:done ++ UINT32 Type:1; // 1: 93C46, 0:93C66 ++ UINT32 EepromDO:1; ++ UINT32 EepromDI:1; ++ UINT32 EepromCS:1; ++ UINT32 EepromSK:1; ++ UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. ++ } field; ++ UINT32 word; ++} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; ++#else ++typedef union _E2PROM_CSR_STRUC { ++ struct { ++ UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. ++ UINT32 EepromSK:1; ++ UINT32 EepromCS:1; ++ UINT32 EepromDI:1; ++ UINT32 EepromDO:1; ++ UINT32 Type:1; // 1: 93C46, 0:93C66 ++ UINT32 LoadStatus:1; // 1:loading, 0:done ++ UINT32 Rsvd:25; ++ } field; ++ UINT32 word; ++} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; ++#endif ++ ++ ++// ------------------------------------------------------------------- ++// E2PROM data layout ++// ------------------------------------------------------------------- ++ ++// ++// EEPROM antenna select format ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_ANTENNA_STRUC { ++ struct { ++ USHORT Rsv:4; ++ USHORT RfIcType:4; // see E2PROM document ++ USHORT TxPath:4; // 1: 1T, 2: 2T ++ USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R ++ } field; ++ USHORT word; ++} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; ++#else ++typedef union _EEPROM_ANTENNA_STRUC { ++ struct { ++ USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R ++ USHORT TxPath:4; // 1: 1T, 2: 2T ++ USHORT RfIcType:4; // see E2PROM document ++ USHORT Rsv:4; ++ } field; ++ USHORT word; ++} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_NIC_CINFIG2_STRUC { ++ struct { ++ USHORT Rsv2:6; // must be 0 ++ USHORT BW40MAvailForA:1; // 0:enable, 1:disable ++ USHORT BW40MAvailForG:1; // 0:enable, 1:disable ++ USHORT EnableWPSPBC:1; // WPS PBC Control bit ++ USHORT BW40MSidebandForA:1; ++ USHORT BW40MSidebandForG:1; ++ USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable ++ USHORT ExternalLNAForA:1; // external LNA enable for 5G ++ USHORT ExternalLNAForG:1; // external LNA enable for 2.4G ++ USHORT DynamicTxAgcControl:1; // ++ USHORT HardwareRadioControl:1; // Whether RF is controlled by driver or HW. 1:enable hw control, 0:disable ++ } field; ++ USHORT word; ++} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; ++#else ++typedef union _EEPROM_NIC_CINFIG2_STRUC { ++ struct { ++ USHORT HardwareRadioControl:1; // 1:enable, 0:disable ++ USHORT DynamicTxAgcControl:1; // ++ USHORT ExternalLNAForG:1; // ++ USHORT ExternalLNAForA:1; // external LNA enable for 2.4G ++ USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable ++ USHORT BW40MSidebandForG:1; ++ USHORT BW40MSidebandForA:1; ++ USHORT EnableWPSPBC:1; // WPS PBC Control bit ++ USHORT BW40MAvailForG:1; // 0:enable, 1:disable ++ USHORT BW40MAvailForA:1; // 0:enable, 1:disable ++ USHORT Rsv2:6; // must be 0 ++ } field; ++ USHORT word; ++} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; ++#endif ++ ++// ++// TX_PWR Value valid range 0xFA(-6) ~ 0x24(36) ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_TX_PWR_STRUC { ++ struct { ++ CHAR Byte1; // High Byte ++ CHAR Byte0; // Low Byte ++ } field; ++ USHORT word; ++} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; ++#else ++typedef union _EEPROM_TX_PWR_STRUC { ++ struct { ++ CHAR Byte0; // Low Byte ++ CHAR Byte1; // High Byte ++ } field; ++ USHORT word; ++} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_VERSION_STRUC { ++ struct { ++ UCHAR Version; // High Byte ++ UCHAR FaeReleaseNumber; // Low Byte ++ } field; ++ USHORT word; ++} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; ++#else ++typedef union _EEPROM_VERSION_STRUC { ++ struct { ++ UCHAR FaeReleaseNumber; // Low Byte ++ UCHAR Version; // High Byte ++ } field; ++ USHORT word; ++} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_LED_STRUC { ++ struct { ++ USHORT Rsvd:3; // Reserved ++ USHORT LedMode:5; // Led mode. ++ USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. ++ USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. ++ USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. ++ USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. ++ USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. ++ USHORT PolarityACT:1; // Polarity ACT setting. ++ USHORT PolarityRDY_A:1; // Polarity RDY_A setting. ++ USHORT PolarityRDY_G:1; // Polarity RDY_G setting. ++ } field; ++ USHORT word; ++} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; ++#else ++typedef union _EEPROM_LED_STRUC { ++ struct { ++ USHORT PolarityRDY_G:1; // Polarity RDY_G setting. ++ USHORT PolarityRDY_A:1; // Polarity RDY_A setting. ++ USHORT PolarityACT:1; // Polarity ACT setting. ++ USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. ++ USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. ++ USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. ++ USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. ++ USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. ++ USHORT LedMode:5; // Led mode. ++ USHORT Rsvd:3; // Reserved ++ } field; ++ USHORT word; ++} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_TXPOWER_DELTA_STRUC { ++ struct { ++ UCHAR TxPowerEnable:1;// Enable ++ UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value ++ UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) ++ } field; ++ UCHAR value; ++} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; ++#else ++typedef union _EEPROM_TXPOWER_DELTA_STRUC { ++ struct { ++ UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) ++ UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value ++ UCHAR TxPowerEnable:1;// Enable ++ } field; ++ UCHAR value; ++} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; ++#endif ++ ++// ++// QOS_CSR0: TXOP holder address0 register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _QOS_CSR0_STRUC { ++ struct { ++ UCHAR Byte3; // MAC address byte 3 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte0; // MAC address byte 0 ++ } field; ++ UINT32 word; ++} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; ++#else ++typedef union _QOS_CSR0_STRUC { ++ struct { ++ UCHAR Byte0; // MAC address byte 0 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte3; // MAC address byte 3 ++ } field; ++ UINT32 word; ++} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; ++#endif ++ ++// ++// QOS_CSR1: TXOP holder address1 register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _QOS_CSR1_STRUC { ++ struct { ++ UCHAR Rsvd1; ++ UCHAR Rsvd0; ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Byte4; // MAC address byte 4 ++ } field; ++ UINT32 word; ++} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; ++#else ++typedef union _QOS_CSR1_STRUC { ++ struct { ++ UCHAR Byte4; // MAC address byte 4 ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Rsvd0; ++ UCHAR Rsvd1; ++ } field; ++ UINT32 word; ++} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; ++#endif ++ ++#define RF_CSR_CFG 0x500 ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG_STRUC { ++ struct { ++ UINT Rsvd1:14; // Reserved ++ UINT RF_CSR_KICK:1; // kick RF register read/write ++ UINT RF_CSR_WR:1; // 0: read 1: write ++ UINT Rsvd2:3; // Reserved ++ UINT TESTCSR_RFACC_REGNUM:5; // RF register ID ++ UINT RF_CSR_DATA:8; // DATA ++ } field; ++ UINT word; ++} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; ++#else ++typedef union _RF_CSR_CFG_STRUC { ++ struct { ++ UINT RF_CSR_DATA:8; // DATA ++ UINT TESTCSR_RFACC_REGNUM:5; // RF register ID ++ UINT Rsvd2:3; // Reserved ++ UINT RF_CSR_WR:1; // 0: read 1: write ++ UINT RF_CSR_KICK:1; // kick RF register read/write ++ UINT Rsvd1:14; // Reserved ++ } field; ++ UINT word; ++} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; ++#endif ++ ++#endif // __RT28XX_H__ +--- /dev/null ++++ b/drivers/staging/rt2860/rt_ate.c +@@ -0,0 +1,6025 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++#ifdef RALINK_ATE ++UCHAR TemplateFrame[24] = {0x08/* Data type */,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes ++extern RTMP_RF_REGS RF2850RegTable[]; ++extern UCHAR NUM_OF_2850_CHNL; ++ ++static CHAR CCKRateTable[] = {0, 1, 2, 3, 8, 9, 10, 11, -1}; /* CCK Mode. */ ++static CHAR OFDMRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; /* OFDM Mode. */ ++static CHAR HTMIXRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}; /* HT Mix Mode. */ ++ ++static INT TxDmaBusy( ++ IN PRTMP_ADAPTER pAd); ++ ++static INT RxDmaBusy( ++ IN PRTMP_ADAPTER pAd); ++ ++static VOID RtmpDmaEnable( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Enable); ++ ++static VOID BbpSoftReset( ++ IN PRTMP_ADAPTER pAd); ++ ++static VOID RtmpRfIoWrite( ++ IN PRTMP_ADAPTER pAd); ++ ++static INT ATESetUpFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TxIdx); ++ ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index); ++ ++static INT ATECmdHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++static int CheckMCSValid( ++ IN UCHAR Mode, ++ IN UCHAR Mcs); ++ ++#ifdef RT2860 ++static VOID ATEWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pOutTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit); ++#endif // RT2860 // ++ ++ ++static VOID SetJapanFilter( ++ IN PRTMP_ADAPTER pAd); ++ ++/*=========================end of prototype=========================*/ ++ ++#ifdef RT2860 ++static INT TxDmaBusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT result; ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA ++ if (GloCfg.field.TxDMABusy) ++ result = 1; ++ else ++ result = 0; ++ ++ return result; ++} ++ ++static INT RxDmaBusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT result; ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA ++ if (GloCfg.field.RxDMABusy) ++ result = 1; ++ else ++ result = 0; ++ ++ return result; ++} ++ ++static VOID RtmpDmaEnable( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Enable) ++{ ++ BOOLEAN value; ++ ULONG WaitCnt; ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ ++ value = Enable > 0 ? 1 : 0; ++ ++ // check DMA is in busy mode. ++ WaitCnt = 0; ++ while (TxDmaBusy(pAd) || RxDmaBusy(pAd)) ++ { ++ RTMPusecDelay(10); ++ if (WaitCnt++ > 100) ++ break; ++ } ++ ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA ++ GloCfg.field.EnableTxDMA = value; ++ GloCfg.field.EnableRxDMA = value; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings ++ RTMPusecDelay(5000); ++ ++ return; ++} ++#endif // RT2860 // ++ ++ ++static VOID BbpSoftReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BbpData = 0; ++ ++ // Soft reset, set BBP R21 bit0=1->0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); ++ BbpData |= 0x00000001; //set bit0=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); ++ BbpData &= ~(0x00000001); //set bit0=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); ++ ++ return; ++} ++ ++static VOID RtmpRfIoWrite( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Set RF value 1's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 2's set R3[bit2] = [1] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 3's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ return; ++} ++ ++static int CheckMCSValid( ++ UCHAR Mode, ++ UCHAR Mcs) ++{ ++ int i; ++ PCHAR pRateTab; ++ ++ switch(Mode) ++ { ++ case 0: ++ pRateTab = CCKRateTable; ++ break; ++ case 1: ++ pRateTab = OFDMRateTable; ++ break; ++ case 2: ++ case 3: ++ pRateTab = HTMIXRateTable; ++ break; ++ default: ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("unrecognizable Tx Mode %d\n", Mode)); ++ return -1; ++ break; ++ } ++ ++ i = 0; ++ while(pRateTab[i] != -1) ++ { ++ if (pRateTab[i] == Mcs) ++ return 0; ++ i++; ++ } ++ ++ return -1; ++} ++ ++#if 1 ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index) ++{ ++ ULONG R; ++ CHAR TxPower; ++ UCHAR Bbp94 = 0; ++ BOOLEAN bPowerReduce = FALSE; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power ++ ** are not synchronized. ++ */ ++/* ++ pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; ++ pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; ++*/ ++ return 0; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (TxPower > 31) ++ { ++ // ++ // R3, R4 can't large than 31 (0x24), 31 ~ 36 used by BBP 94 ++ // ++ R = 31; ++ if (TxPower <= 36) ++ Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 ++ // ++ R = 0; ++ if (TxPower >= -6) ++ Bbp94 = BBPR94_DEFAULT + TxPower; ++ } ++ else ++ { ++ // 0 ~ 31 ++ R = (ULONG) TxPower; ++ Bbp94 = BBPR94_DEFAULT; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ } ++ else// 5.5 GHz ++ { ++ if (TxPower > 15) ++ { ++ // ++ // R3, R4 can't large than 15 (0x0F) ++ // ++ R = 15; ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0 ++ // ++ // -1 ~ -7 ++ ASSERT((TxPower >= -7)); ++ R = (ULONG)(TxPower + 7); ++ bPowerReduce = TRUE; ++ } ++ else ++ { ++ // 0 ~ 15 ++ R = (ULONG) TxPower; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R)); ++ } ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (index == 0) ++ { ++ R = R << 9; // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = R << 6; // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else// 5.5GHz ++ { ++ if (bPowerReduce == FALSE) ++ { ++ if (index == 0) ++ { ++ R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else ++ { ++ if (index == 0) ++ { ++ R = (R << 10); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ ++ /* Clear bit 9 of R3 to reduce 7dB. */ ++ pAd->LatchRfRegs.R3 = (R & (~(1 << 9))); ++ } ++ else ++ { ++ R = (R << 7); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ ++ /* Clear bit 6 of R4 to reduce 7dB. */ ++ pAd->LatchRfRegs.R4 = (R & (~(1 << 6))); ++ } ++ } ++ } ++ ++ RtmpRfIoWrite(pAd); ++ ++ return 0; ++ } ++} ++#else// 1 // ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index) ++{ ++ ULONG R; ++ CHAR TxPower; ++ UCHAR Bbp94 = 0; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ // TODO: how to get current TxPower0/1 from pAd->LatchRfRegs ? ++ /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power ++ ** are not synchronized. ++ */ ++/* ++ pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; ++ pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; ++*/ ++ return 0; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; ++ ++ if (TxPower > 31) ++ { ++ // ++ // R3, R4 can't large than 36 (0x24), 31 ~ 36 used by BBP 94 ++ // ++ R = 31; ++ if (TxPower <= 36) ++ Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 ++ // ++ R = 0; ++ if (TxPower >= -6) ++ Bbp94 = BBPR94_DEFAULT + TxPower; ++ } ++ else ++ { ++ // 0 ~ 31 ++ R = (ULONG) TxPower; ++ Bbp94 = BBPR94_DEFAULT; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (index == 0) ++ { ++ R = R << 9; // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = R << 6; // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else ++ { ++ if (index == 0) ++ { ++ R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ ++ RtmpRfIoWrite(pAd); ++ ++ return 0; ++ } ++} ++#endif // 1 // ++/* ++ ========================================================================== ++ Description: ++ Set ATE operation mode to ++ 0. ATESTART = Start ATE Mode ++ 1. ATESTOP = Stop ATE Mode ++ 2. TXCONT = Continuous Transmit ++ 3. TXCARR = Transmit Carrier ++ 4. TXFRAME = Transmit Frames ++ 5. RXFRAME = Receive Frames ++#ifdef RALINK_28xx_QA ++ 6. TXSTOP = Stop Any Type of Transmition ++ 7. RXSTOP = Stop Receiving Frames ++#endif // RALINK_28xx_QA // ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++#ifdef RT2860 ++static INT ATECmdHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 Value = 0; ++ UCHAR BbpData; ++ UINT32 MacData = 0; ++ PTXD_STRUC pTxD; ++ INT index; ++ UINT i=0, atemode; ++ PRXD_STRUC pRxD; ++ PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; ++#ifndef UCOS ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++#endif // UCOS // ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> ATECmdHandler()\n")); ++ ++ ATEAsicSwitchChannel(pAd); ++ AsicLockChannel(pAd, pAd->ate.Channel); ++ ++ RTMPusecDelay(5000); ++ ++ // read MAC_SYS_CTRL and backup MAC_SYS_CTRL value. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ // clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ++ if (!strcmp(arg, "ATESTART")) //Enter ATE mode and set Tx/Rx Idle ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTART\n")); ++ ++#ifndef UCOS ++ // check if we have removed the firmware ++ if (!(ATE_ON(pAd))) ++ { ++ NICEraseFirmware(pAd); ++ } ++#endif // !UCOS // ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode = ATE_START; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ if (atemode & ATE_TXCARR) ++ { ++ // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ else if (atemode & ATE_TXCARRSUPP) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // No Carrier Suppression set BBP R24 bit0=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); ++ BbpData &= 0xFFFFFFFE; //clear bit0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); ++ } ++ // We should free some resource which was allocated when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. ++ else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) ++ { ++ PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; ++ ++ if (atemode & ATE_TXCONT) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ // Abort Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 0); ++ for (i=0; iTxRing[QID_AC_BE].Cell[i].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pAd->TxRing[QID_AC_BE].Cell[i].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ pTxD->DMADONE = 0; ++ pPacket = pTxRing->Cell[i].pNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[i].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[i].pNextNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[i].pNextNdisPacket = NULL; ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ } ++ // Start Tx, RX DMA ++ RtmpDmaEnable(pAd, 1); ++ } ++ // reset Rx statistics. ++ pAd->ate.LastSNR0 = 0; ++ pAd->ate.LastSNR1 = 0; ++ pAd->ate.LastRssi0 = 0; ++ pAd->ate.LastRssi1 = 0; ++ pAd->ate.LastRssi2 = 0; ++ pAd->ate.AvgRssi0 = 0; ++ pAd->ate.AvgRssi1 = 0; ++ pAd->ate.AvgRssi2 = 0; ++ pAd->ate.AvgRssi0X8 = 0; ++ pAd->ate.AvgRssi1X8 = 0; ++ pAd->ate.AvgRssi2X8 = 0; ++ pAd->ate.NumOfAvgRssiSample = 0; ++ ++#ifdef RALINK_28xx_QA ++ // Tx frame ++ pAd->ate.bQATxStart = FALSE; ++ pAd->ate.bQARxStart = FALSE; ++ pAd->ate.seq = 0; ++ ++ // counters ++ pAd->ate.U2M = 0; ++ pAd->ate.OtherData = 0; ++ pAd->ate.Beacon = 0; ++ pAd->ate.OtherCount = 0; ++ pAd->ate.TxAc0 = 0; ++ pAd->ate.TxAc1 = 0; ++ pAd->ate.TxAc2 = 0; ++ pAd->ate.TxAc3 = 0; ++ pAd->ate.TxHCCA = 0; ++ pAd->ate.TxMgmt = 0; ++ pAd->ate.RSSI0 = 0; ++ pAd->ate.RSSI1 = 0; ++ pAd->ate.RSSI2 = 0; ++ pAd->ate.SNR0 = 0; ++ pAd->ate.SNR1 = 0; ++ ++ // control ++ pAd->ate.TxDoneCount = 0; ++ pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running ++#endif // RALINK_28xx_QA // ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ // ++ // LinkDown() has "AsicDisableSync();" and "RTMP_BBP_IO_R/W8_BY_REG_ID();" inside. ++ // ++// LinkDown(pAd, FALSE); ++// AsicEnableBssSync(pAd); ++#ifndef UCOS ++ netif_stop_queue(pAd->net_dev); ++#endif // !UCOS // ++ // ++ // If we skip "LinkDown()", we should disable protection ++ // to prevent from sending out RTS or CTS-to-self. ++ // ++ ATEDisableAsicProtect(pAd); ++ RTMPStationStop(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ /* Disable Tx */ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ /* Disable Rx */ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ else if (!strcmp(arg, "ATESTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTOP\n")); ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); // recover the MAC_SYS_CTRL register back. ++ ++ // Disable Tx, Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= (0xfffffff3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++#ifndef UCOS ++ pAd->ate.bFWLoading = TRUE; ++ Status = NICLoadFirmware(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); ++ return FALSE; ++ } ++#endif // !UCOS // ++ pAd->ate.Mode = ATE_STOP; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ // ++ // Even the firmware has been loaded, ++ // we still could use ATE_BBP_IO_READ8_BY_REG_ID(). ++ // But this is not suggested. ++ // ++ BbpSoftReset(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ NICDisableInterrupt(pAd); ++ ++ NICInitializeAdapter(pAd, TRUE); ++ ++ ++ // Reinitialize Rx Ring before Rx DMA is enabled. ++ // The nightmare of >>>RxCoherent<<< was gone ! ++ for (index = 0; index < RX_RING_SIZE; index++) ++ { ++ pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa; ++ pRxD->DDONE = 0; ++ } ++ ++ // We should read EEPROM for all cases. ++ NICReadEEPROMParameters(pAd, NULL); ++ NICInitAsicFromEEPROM(pAd); ++ ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // ++ // Enable Interrupt ++ // ++ ++ // ++ // These steps are only for APAutoSelectChannel(). ++ // ++#if 0 ++ //pAd->bStaFifoTest = TRUE; ++ pAd->int_enable_reg = ((DELAYINTMASK) | (RxINT|TxDataInt|TxMgmtInt)) & ~(0x03); ++ pAd->int_disable_mask = 0; ++ pAd->int_pending = 0; ++#endif ++ RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, 0xffffffff); // clear garbage interrupts ++ NICEnableInterrupt(pAd); ++ ++ ++/*=========================================================================*/ ++ /* restore RX_FILTR_CFG */ ++#ifdef CONFIG_STA_SUPPORT ++ /* restore RX_FILTR_CFG due to that QA maybe set it to 0x3 */ ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); ++#endif // CONFIG_STA_SUPPORT // ++/*=========================================================================*/ ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Enable Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ RTMPStationStart(pAd); ++#endif // CONFIG_STA_SUPPORT // ++#ifndef UCOS ++ netif_start_queue(pAd->net_dev); ++#endif // !UCOS // ++ } ++ else if (!strcmp(arg, "TXCARR")) // Tx Carrier ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCARR\n")); ++ pAd->ate.Mode |= ATE_TXCARR; ++ ++ // QA has done the following steps if it is used. ++ if (pAd->ate.bQATxStart == FALSE) ++ { ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Carrier Test set BBP R22 bit7=1, bit6=1, bit[5~0]=0x01 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ BbpData |= 0x000000C1; //set bit7=1, bit6=1, bit[5~0]=0x01 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1 ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value = Value | 0x00000010; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ } ++ else if (!strcmp(arg, "TXCONT")) // Tx Continue ++ { ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ /* set MAC_SYS_CTRL(0x1004) bit4(Continuous Tx Production Test) ++ and bit2(MAC TX enable) back to zero. */ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData &= 0xFFFFFFEB; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ // set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF7F; //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ ++ /* for TxCont mode. ++ ** Step 1: Send 50 packets first then wait for a moment. ++ ** Step 2: Send more 50 packet then start continue mode. ++ */ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCONT\n")); ++ // Step 1: send 50 packets first. ++ pAd->ate.Mode |= ATE_TXCONT; ++ pAd->ate.TxCount = 50; ++ /* Do it after Tx/Rx DMA is aborted. */ ++// pAd->ate.TxDoneCount = 0; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Fix can't smooth kick ++ { ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * 0x10, &pTxRing->TxDmaIdx); ++ pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; ++ pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * 0x10, pTxRing->TxCpuIdx); ++ } ++ ++ pAd->ate.TxDoneCount = 0; ++ ++ /* Only needed if we have to send some normal frames. */ ++ SetJapanFilter(pAd); ++ ++ for (i = 0; (i < TX_RING_SIZE-1) && (i < pAd->ate.TxCount); i++) ++ { ++ PNDIS_PACKET pPacket; ++ UINT32 TxIdx = pTxRing->TxCpuIdx; ++ ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ // Clean current cell. ++ pPacket = pTxRing->Cell[TxIdx].pNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[TxIdx].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[TxIdx].pNextNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ ++ if (ATESetUpFrame(pAd, TxIdx) != 0) ++ break; ++ ++ INC_RING_INDEX(pTxRing->TxCpuIdx, TX_RING_SIZE); ++ } ++ ++ // Setup frame format. ++ ATESetUpFrame(pAd, pTxRing->TxCpuIdx); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#endif // RALINK_28xx_QA // ++ ++ // kick Tx-Ring. ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * RINGREG_DIFF, pAd->TxRing[QID_AC_BE].TxCpuIdx); ++ ++ RTMPusecDelay(5000); ++ ++ ++ // Step 2: send more 50 packets then start continue mode. ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Cont. TX set BBP R22 bit7=1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData |= 0x00000080; //set bit7=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ pAd->ate.TxCount = 50; ++ ++ // Fix can't smooth kick ++ { ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * 0x10, &pTxRing->TxDmaIdx); ++ pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; ++ pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * 0x10, pTxRing->TxCpuIdx); ++ } ++ ++ pAd->ate.TxDoneCount = 0; ++ ++ SetJapanFilter(pAd); ++ ++ for (i = 0; (i < TX_RING_SIZE-1) && (i < pAd->ate.TxCount); i++) ++ { ++ PNDIS_PACKET pPacket; ++ UINT32 TxIdx = pTxRing->TxCpuIdx; ++ ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ // clean current cell. ++ pPacket = pTxRing->Cell[TxIdx].pNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[TxIdx].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[TxIdx].pNextNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ ++ if (ATESetUpFrame(pAd, TxIdx) != 0) ++ break; ++ ++ INC_RING_INDEX(pTxRing->TxCpuIdx, TX_RING_SIZE); ++ } ++ ++ ATESetUpFrame(pAd, pTxRing->TxCpuIdx); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#endif // RALINK_28xx_QA // ++ ++ // kick Tx-Ring. ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * RINGREG_DIFF, pAd->TxRing[QID_AC_BE].TxCpuIdx); ++ ++ RTMPusecDelay(500); ++ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData |= 0x00000010; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ } ++ else if (!strcmp(arg, "TXFRAME")) // Tx Frames ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXFRAME(Count=%d)\n", pAd->ate.TxCount)); ++ pAd->ate.Mode |= ATE_TXFRAME; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Fix can't smooth kick ++ { ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * 0x10, &pTxRing->TxDmaIdx); ++ pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx; ++ pTxRing->TxCpuIdx = pTxRing->TxDmaIdx; ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * 0x10, pTxRing->TxCpuIdx); ++ } ++ ++ pAd->ate.TxDoneCount = 0; ++ ++ SetJapanFilter(pAd); ++ ++ for (i = 0; (i < TX_RING_SIZE-1) && (i < pAd->ate.TxCount); i++) ++ { ++ PNDIS_PACKET pPacket; ++ UINT32 TxIdx = pTxRing->TxCpuIdx; ++ ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ // Clean current cell. ++ pPacket = pTxRing->Cell[TxIdx].pNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[TxIdx].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[TxIdx].pNextNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[TxIdx].pNextNdisPacket = NULL; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ ++ if (ATESetUpFrame(pAd, TxIdx) != 0) ++ break; ++ ++ INC_RING_INDEX(pTxRing->TxCpuIdx, TX_RING_SIZE); ++ ++ } ++ ++ ATESetUpFrame(pAd, pTxRing->TxCpuIdx); ++ ++ // Start Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++#ifdef RALINK_28xx_QA ++ // add this for LoopBack mode ++ if (pAd->ate.bQARxStart == FALSE) ++ { ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#else ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++#endif // RALINK_28xx_QA // ++ ++ RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QID_AC_BE * RINGREG_DIFF, &pAd->TxRing[QID_AC_BE].TxDmaIdx); ++ // kick Tx-Ring. ++ RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QID_AC_BE * RINGREG_DIFF, pAd->TxRing[QID_AC_BE].TxCpuIdx); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ } ++#ifdef RALINK_28xx_QA ++ else if (!strcmp(arg, "TXSTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXSTOP\n")); ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode &= ATE_TXSTOP; ++ pAd->ate.bQATxStart = FALSE; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ ++ if (atemode & ATE_TXCARR) ++ { ++ // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ else if (atemode & ATE_TXCARRSUPP) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // No Carrier Suppression set BBP R24 bit0=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); ++ BbpData &= 0xFFFFFFFE; //clear bit0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); ++ } ++ // We should free some resource which allocate when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. ++ else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) ++ { ++ ++ PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; ++ ++ if (atemode & ATE_TXCONT) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ ++ // Abort Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 0); ++ for (i=0; iTxRing[QID_AC_BE].Cell[i].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pAd->TxRing[QID_AC_BE].Cell[i].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++#endif ++ pTxD->DMADONE = 0; ++ pPacket = pTxRing->Cell[i].pNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNdisPacket as NULL after clear ++ pTxRing->Cell[i].pNdisPacket = NULL; ++ ++ pPacket = pTxRing->Cell[i].pNextNdisPacket; ++ if (pPacket) ++ { ++ PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ } ++ //Always assign pNextNdisPacket as NULL after clear ++ pTxRing->Cell[i].pNextNdisPacket = NULL; ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif ++ } ++ // Enable Tx, Rx DMA ++ RtmpDmaEnable(pAd, 1); ++ ++ } ++ ++ // control ++// pAd->ate.TxDoneCount = 0; ++ pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ else if (!strcmp(arg, "RXSTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXSTOP\n")); ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode &= ATE_RXSTOP; ++ pAd->ate.bQARxStart = FALSE; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ ++ if (atemode & ATE_TXCARR) ++ { ++ ; ++ } ++ else if (atemode & ATE_TXCARRSUPP) ++ { ++ ; ++ } ++ ++ // We should free some resource which was allocated when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. ++ else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) ++ { ++ if (atemode & ATE_TXCONT) ++ { ++ ; ++ } ++ } ++ ++ // control ++// pAd->ate.TxDoneCount = 0; ++// pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++#endif // RALINK_28xx_QA // ++ else if (!strcmp(arg, "RXFRAME")) // Rx Frames ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXFRAME\n")); ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ pAd->ate.Mode |= ATE_RXFRAME; ++ ++ // Disable Tx of MAC block. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Enable Rx of MAC block. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: Invalid arg!\n")); ++ return FALSE; ++ } ++ RTMPusecDelay(5000); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATECmdHandler()\n")); ++ ++ return TRUE; ++} ++#endif // RT2860 // ++/* */ ++/* */ ++/*=======================End of RT2860=======================*/ ++ ++ ++/*======================Start of RT2870======================*/ ++/* */ ++/* */ ++ ++ ++INT Set_ATE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (ATECmdHandler(pAd, arg)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Success\n")); ++ ++ ++ return TRUE; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Failed\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR1=DA for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR3=DA for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_DA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr3[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_DA_Proc (DA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr3[0], ++ pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_DA_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR3=SA for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR2=SA for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_SA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr2[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_SA_Proc (SA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr2[0], ++ pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_SA_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR2=BSSID for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR1=BSSID for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_BSSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr1[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_BSSID_Proc (BSSID = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr1[0], ++ pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_BSSID_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Channel ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_CHANNEL_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR channel; ++ ++ channel = simple_strtol(arg, 0, 10); ++ ++ if ((channel < 1) || (channel > 216))// to allow A band channel : ((channel < 1) || (channel > 14)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_CHANNEL_Proc::Out of range, it should be in range of 1~14.\n")); ++ return FALSE; ++ } ++ pAd->ate.Channel = channel; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAd->ate.Channel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_CHANNEL_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Power0 ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_POWER0_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR TxPower; ++ ++ TxPower = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if ((TxPower > 31) || (TxPower < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ else// 5.5GHz ++ { ++ if ((TxPower > 15) || (TxPower < -7)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ ++ pAd->ate.TxPower0 = TxPower; ++ ATETxPwrHandler(pAd, 0); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER0_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Power1 ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_POWER1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR TxPower; ++ ++ TxPower = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if ((TxPower > 31) || (TxPower < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ else ++ { ++ if ((TxPower > 15) || (TxPower < -7)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ ++ pAd->ate.TxPower1 = TxPower; ++ ATETxPwrHandler(pAd, 1); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER1_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Antenna ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR value; ++ ++ value = simple_strtol(arg, 0, 10); ++ ++ if ((value > 2) || (value < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_Antenna_Proc::Out of range (Value=%d)\n", value)); ++ return FALSE; ++ } ++ ++ pAd->ate.TxAntennaSel = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_Antenna_Proc (Antenna = %d)\n", pAd->ate.TxAntennaSel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Ralink: Set_ATE_TX_Antenna_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Rx Antenna ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_RX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR value; ++ ++ value = simple_strtol(arg, 0, 10); ++ ++ if ((value > 3) || (value < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_RX_Antenna_Proc::Out of range (Value=%d)\n", value)); ++ return FALSE; ++ } ++ ++ pAd->ate.RxAntennaSel = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_Antenna_Proc (Antenna = %d)\n", pAd->ate.RxAntennaSel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_Antenna_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE RF frequence offset ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_FREQOFFSET_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR RFFreqOffset; ++ ULONG R4; ++ ++ RFFreqOffset = simple_strtol(arg, 0, 10); ++ ++ if(RFFreqOffset >= 64) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_FREQOFFSET_Proc::Out of range, it should be in range of 0~63.\n")); ++ return FALSE; ++ } ++ ++ pAd->ate.RFFreqOffset = RFFreqOffset; ++ R4 = pAd->ate.RFFreqOffset << 15; // shift TX power control to correct RF register bit position ++ R4 |= (pAd->LatchRfRegs.R4 & ((~0x001f8000))); ++ pAd->LatchRfRegs.R4 = R4; ++ ++ RtmpRfIoWrite(pAd); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_FREQOFFSET_Proc (RFFreqOffset = %d)\n", pAd->ate.RFFreqOffset)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_FREQOFFSET_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE RF BW ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_BW_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ int i; ++ UCHAR value = 0; ++ UCHAR BBPCurrentBW; ++ ++ BBPCurrentBW = simple_strtol(arg, 0, 10); ++ ++ if(BBPCurrentBW == 0) ++ pAd->ate.TxWI.BW = BW_20; ++ else ++ pAd->ate.TxWI.BW = BW_40; ++ ++ if(pAd->ate.TxWI.BW == BW_20) ++ { ++ if(pAd->ate.Channel <= 14) ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx20MPwrCfgGBand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgGBand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ else ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx20MPwrCfgABand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgABand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ ++ //Set BBP R4 bit[4:3]=0:0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value &= (~0x18); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ ++ //Set BBP R66=0x3C ++ value = 0x3C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); ++ //Set BBP R68=0x0B ++ //to improve Rx sensitivity. ++ value = 0x0B; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); ++ //Set BBP R69=0x16 ++ value = 0x16; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); ++ //Set BBP R70=0x08 ++ value = 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); ++ //Set BBP R73=0x11 ++ value = 0x11; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); ++ ++ // If Channel=14, Bandwidth=20M and Mode=CCK, Set BBP R4 bit5=1 ++ // (Japan filter coefficients) ++ // This segment of code will only works when ATETXMODE and ATECHANNEL ++ // were set to MODE_CCK and 14 respectively before ATETXBW is set to 0. ++ //===================================================================== ++ if (pAd->ate.Channel == 14) ++ { ++ int TxMode = pAd->ate.TxWI.PHYMODE; ++ if (TxMode == MODE_CCK) ++ { ++ // when Channel==14 && Mode==CCK && BandWidth==20M, BBP R4 bit5=1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value |= 0x20; //set bit5=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ } ++ } ++ ++ //===================================================================== ++ // If bandwidth != 40M, RF Reg4 bit 21 = 0. ++ pAd->LatchRfRegs.R4 &= ~0x00200000; ++ RtmpRfIoWrite(pAd); ++ } ++ else if(pAd->ate.TxWI.BW == BW_40) ++ { ++ if(pAd->ate.Channel <= 14) ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx40MPwrCfgGBand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgGBand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ else ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx40MPwrCfgABand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgABand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->ate.TxWI.PHYMODE >= MODE_HTMIX) && (pAd->ate.TxWI.MCS == 7)) ++ { ++ value = 0x28; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R67, value); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ //Set BBP R4 bit[4:3]=1:0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value &= (~0x18); ++ value |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ ++ //Set BBP R66=0x3C ++ value = 0x3C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); ++ //Set BBP R68=0x0C ++ //to improve Rx sensitivity. ++ value = 0x0C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); ++ //Set BBP R69=0x1A ++ value = 0x1A; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); ++ //Set BBP R70=0x0A ++ value = 0x0A; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); ++ //Set BBP R73=0x16 ++ value = 0x16; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); ++ ++ // If bandwidth = 40M, set RF Reg4 bit 21 = 1. ++ pAd->LatchRfRegs.R4 |= 0x00200000; ++ RtmpRfIoWrite(pAd); ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_BW_Proc (BBPCurrentBW = %d)\n", pAd->ate.TxWI.BW)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_BW_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame length ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_LENGTH_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxLength = simple_strtol(arg, 0, 10); ++ ++ if((pAd->ate.TxLength < 24) || (pAd->ate.TxLength > (MAX_FRAME_SIZE - 34/* == 2312 */))) ++ { ++ pAd->ate.TxLength = (MAX_FRAME_SIZE - 34/* == 2312 */); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_LENGTH_Proc::Out of range, it should be in range of 24~%d.\n", (MAX_FRAME_SIZE - 34/* == 2312 */))); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_LENGTH_Proc (TxLength = %d)\n", pAd->ate.TxLength)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_LENGTH_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame count ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_COUNT_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxCount = simple_strtol(arg, 0, 10); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAd->ate.TxCount)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame MCS ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_MCS_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR MCS; ++ int result; ++ ++ MCS = simple_strtol(arg, 0, 10); ++ result = CheckMCSValid(pAd->ate.TxWI.PHYMODE, MCS); ++ ++ if (result != -1) ++ { ++ pAd->ate.TxWI.MCS = (UCHAR)MCS; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MCS_Proc::Out of range, refer to rate table.\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MCS_Proc (MCS = %d)\n", pAd->ate.TxWI.MCS)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MCS_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame Mode ++ 0: MODE_CCK ++ 1: MODE_OFDM ++ 2: MODE_HTMIX ++ 3: MODE_HTGREENFIELD ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_MODE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxWI.PHYMODE = simple_strtol(arg, 0, 10); ++ ++ if(pAd->ate.TxWI.PHYMODE > 3) ++ { ++ pAd->ate.TxWI.PHYMODE = 0; ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MODE_Proc::Out of range. it should be in range of 0~3\n")); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("0: CCK, 1: OFDM, 2: HT_MIX, 3: HT_GREEN_FIELD.\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MODE_Proc (TxMode = %d)\n", pAd->ate.TxWI.PHYMODE)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MODE_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame GI ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_GI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxWI.ShortGI = simple_strtol(arg, 0, 10); ++ ++ if(pAd->ate.TxWI.ShortGI > 1) ++ { ++ pAd->ate.TxWI.ShortGI = 0; ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_GI_Proc::Out of range\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_GI_Proc (GI = %d)\n", pAd->ate.TxWI.ShortGI)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_GI_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++INT Set_ATE_RX_FER_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.bRxFer = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.bRxFer == 1) ++ { ++ pAd->ate.RxCntPerSec = 0; ++ pAd->ate.RxTotalCnt = 0; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_FER_Proc (bRxFer = %d)\n", pAd->ate.bRxFer)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_FER_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Read_RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print(KERN_EMERG "R1 = %lx\n", pAd->LatchRfRegs.R1); ++ ate_print(KERN_EMERG "R2 = %lx\n", pAd->LatchRfRegs.R2); ++ ate_print(KERN_EMERG "R3 = %lx\n", pAd->LatchRfRegs.R3); ++ ate_print(KERN_EMERG "R4 = %lx\n", pAd->LatchRfRegs.R4); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R1 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R2 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R3 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R4 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Load and Write EEPROM from a binary file prepared in advance. ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++#ifndef UCOS ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN ret = FALSE; ++ PUCHAR src = EEPROM_BIN_FILE_NAME; ++ struct file *srcf; ++ INT32 retval, orgfsuid, orgfsgid; ++ mm_segment_t orgfs; ++ USHORT WriteEEPROM[(EEPROM_SIZE/2)]; ++ UINT32 FileLength = 0; ++ UINT32 value = simple_strtol(arg, 0, 10); ++ ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value)); ++ ++ if (value > 0) ++ { ++ /* zero the e2p buffer */ ++ NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); ++ ++ /* save uid and gid used for filesystem access. ++ ** set user and group to 0 (root) ++ */ ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ /* as root */ ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ do ++ { ++ /* open the bin file */ ++ srcf = filp_open(src, O_RDONLY, 0); ++ ++ if (IS_ERR(srcf)) ++ { ++ ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src); ++ break; ++ } ++ ++ /* the object must have a read method */ ++ if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) ++ { ++ ate_print("%s - %s does not have a read method\n", __FUNCTION__, src); ++ break; ++ } ++ ++ /* read the firmware from the file *.bin */ ++ FileLength = srcf->f_op->read(srcf, ++ (PUCHAR)WriteEEPROM, ++ EEPROM_SIZE, ++ &srcf->f_pos); ++ ++ if (FileLength != EEPROM_SIZE) ++ { ++ ate_print("%s: error file length (=%d) in e2p.bin\n", ++ __FUNCTION__, FileLength); ++ break; ++ } ++ else ++ { ++ /* write the content of .bin file to EEPROM */ ++ rt_ee_write_all(pAd, WriteEEPROM); ++ ret = TRUE; ++ } ++ break; ++ } while(TRUE); ++ ++ /* close firmware file */ ++ if (IS_ERR(srcf)) ++ { ++ ; ++ } ++ else ++ { ++ retval = filp_close(srcf, NULL); ++ if (retval) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); ++ ++ } ++ } ++ ++ /* restore */ ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ } ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret)); ++ ++ return ret; ++ ++} ++#else ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT WriteEEPROM[(EEPROM_SIZE/2)]; ++ struct iwreq *wrq = (struct iwreq *)arg; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length)); ++ ++ if (wrq->u.data.length != EEPROM_SIZE) ++ { ++ ate_print("%s: error length (=%d) from host\n", ++ __FUNCTION__, wrq->u.data.length); ++ return FALSE; ++ } ++ else/* (wrq->u.data.length == EEPROM_SIZE) */ ++ { ++ /* zero the e2p buffer */ ++ NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); ++ ++ /* fill the local buffer */ ++ NdisMoveMemory((PUCHAR)WriteEEPROM, wrq->u.data.pointer, wrq->u.data.length); ++ ++ do ++ { ++ /* write the content of .bin file to EEPROM */ ++ rt_ee_write_all(pAd, WriteEEPROM); ++ ++ } while(FALSE); ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__)); ++ ++ return TRUE; ++ ++} ++#endif // !UCOS // ++ ++INT Set_ATE_Read_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT buffer[EEPROM_SIZE/2]; ++ USHORT *p; ++ int i; ++ ++ rt_ee_read_all(pAd, (USHORT *)buffer); ++ p = buffer; ++ for (i = 0; i < (EEPROM_SIZE/2); i++) ++ { ++ ate_print("%4.4x ", *p); ++ if (((i+1) % 16) == 0) ++ ate_print("\n"); ++ p++; ++ } ++ return TRUE; ++} ++ ++INT Set_ATE_Show_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print("Mode=%d\n", pAd->ate.Mode); ++ ate_print("TxPower0=%d\n", pAd->ate.TxPower0); ++ ate_print("TxPower1=%d\n", pAd->ate.TxPower1); ++ ate_print("TxAntennaSel=%d\n", pAd->ate.TxAntennaSel); ++ ate_print("RxAntennaSel=%d\n", pAd->ate.RxAntennaSel); ++ ate_print("BBPCurrentBW=%d\n", pAd->ate.TxWI.BW); ++ ate_print("GI=%d\n", pAd->ate.TxWI.ShortGI); ++ ate_print("MCS=%d\n", pAd->ate.TxWI.MCS); ++ ate_print("TxMode=%d\n", pAd->ate.TxWI.PHYMODE); ++ ate_print("Addr1=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr1[0], pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5]); ++ ate_print("Addr2=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr2[0], pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5]); ++ ate_print("Addr3=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr3[0], pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5]); ++ ate_print("Channel=%d\n", pAd->ate.Channel); ++ ate_print("TxLength=%d\n", pAd->ate.TxLength); ++ ate_print("TxCount=%u\n", pAd->ate.TxCount); ++ ate_print("RFFreqOffset=%d\n", pAd->ate.RFFreqOffset); ++ ate_print(KERN_EMERG "Set_ATE_Show_Proc Success\n"); ++ return TRUE; ++} ++ ++INT Set_ATE_Help_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print("ATE=ATESTART, ATESTOP, TXCONT, TXCARR, TXFRAME, RXFRAME\n"); ++ ate_print("ATEDA\n"); ++ ate_print("ATESA\n"); ++ ate_print("ATEBSSID\n"); ++ ate_print("ATECHANNEL, range:0~14(unless A band !)\n"); ++ ate_print("ATETXPOW0, set power level of antenna 1.\n"); ++ ate_print("ATETXPOW1, set power level of antenna 2.\n"); ++ ate_print("ATETXANT, set TX antenna. 0:all, 1:antenna one, 2:antenna two.\n"); ++ ate_print("ATERXANT, set RX antenna.0:all, 1:antenna one, 2:antenna two, 3:antenna three.\n"); ++ ate_print("ATETXFREQOFFSET, set frequency offset, range 0~63\n"); ++ ate_print("ATETXBW, set BandWidth, 0:20MHz, 1:40MHz.\n"); ++ ate_print("ATETXLEN, set Frame length, range 24~%d\n", (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ ate_print("ATETXCNT, set how many frame going to transmit.\n"); ++ ate_print("ATETXMCS, set MCS, reference to rate table.\n"); ++ ate_print("ATETXMODE, set Mode 0:CCK, 1:OFDM, 2:HT-Mix, 3:GreenField, reference to rate table.\n"); ++ ate_print("ATETXGI, set GI interval, 0:Long, 1:Short\n"); ++ ate_print("ATERXFER, 0:disable Rx Frame error rate. 1:enable Rx Frame error rate.\n"); ++ ate_print("ATERRF, show all RF registers.\n"); ++ ate_print("ATEWRF1, set RF1 register.\n"); ++ ate_print("ATEWRF2, set RF2 register.\n"); ++ ate_print("ATEWRF3, set RF3 register.\n"); ++ ate_print("ATEWRF4, set RF4 register.\n"); ++ ate_print("ATELDE2P, load EEPROM from .bin file.\n"); ++ ate_print("ATERE2P, display all EEPROM content.\n"); ++ ate_print("ATESHOW, display all parameters of ATE.\n"); ++ ate_print("ATEHELP, online help.\n"); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ AsicSwitchChannel() dedicated for ATE. ++ ++ ========================================================================== ++*/ ++VOID ATEAsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0, Value = 0; ++ CHAR TxPwer = 0, TxPwer2 = 0; ++ UCHAR index, BbpValue = 0, R66 = 0x30; ++ RTMP_RF_REGS *RFRegTable; ++ UCHAR Channel; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ if (pAd->ate.Channel != pAd->LatchRfRegs.Channel) ++ { ++ pAd->ate.Channel = pAd->LatchRfRegs.Channel; ++ } ++ return; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ Channel = pAd->ate.Channel; ++ ++ // Select antenna ++ AsicAntennaSelect(pAd, Channel); ++ ++ // fill Tx power value ++ TxPwer = pAd->ate.TxPower0; ++ TxPwer2 = pAd->ate.TxPower1; ++ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ /* But only 2850 and 2750 support 5.5GHz band... */ ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ switch (pAd->ate.RxAntennaSel) ++ { ++ case 1: ++ R2 |= 0x20040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x00; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 2: ++ R2 |= 0x10040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x01; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ default: ++ R2 |= 0x40; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ /* Only enable two Antenna to receive. */ ++ BbpValue |= 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ } ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ if (pAd->ate.TxAntennaSel == 1) ++ { ++ R2 |= 0x4000; // If TX Antenna select is 1 , bit 14 = 1; Disable Ant 2 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; //11100111B ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ else if (pAd->ate.TxAntennaSel == 2) ++ { ++ R2 |= 0x8000; // If TX Antenna select is 2 , bit 15 = 1; Disable Ant 1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; ++ BbpValue |= 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ else ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; ++ BbpValue |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ } ++ if (pAd->Antenna.field.RxPath == 3) ++ { ++ switch (pAd->ate.RxAntennaSel) ++ { ++ case 1: ++ R2 |= 0x20040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x00; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 2: ++ R2 |= 0x10040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x01; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 3: ++ R2 |= 0x30000; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x02; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ default: ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ } ++ } ++ ++ if (Channel > 14) ++ { ++ // initialize R3, R4 ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff); ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15); ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ // 5.5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB ++ // R3 ++ if ((TxPwer >= -7) && (TxPwer < 0)) ++ { ++ TxPwer = (7+TxPwer); ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer=%d \n", TxPwer)); ++ } ++ else ++ { ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10) | (1 << 9); ++ } ++ ++ // R4 ++ if ((TxPwer2 >= -7) && (TxPwer2 < 0)) ++ { ++ TxPwer2 = (7+TxPwer2); ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); ++ } ++ else ++ { ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7) | (1 << 6); ++ } ++ } ++ else ++ { ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15) | (TxPwer2 <<6);// Set freq offset & TxPwr1 ++ } ++ ++ // Based on BBP current mode before changing RF channel. ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ R4 |=0x200000; ++ } ++ ++ // Update variables ++ pAd->LatchRfRegs.Channel = Channel; ++ pAd->LatchRfRegs.R1 = RFRegTable[index].R1; ++ pAd->LatchRfRegs.R2 = R2; ++ pAd->LatchRfRegs.R3 = R3; ++ pAd->LatchRfRegs.R4 = R4; ++ ++ RtmpRfIoWrite(pAd); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ // Change BBP setting during switch from a->g, g->a ++ if (Channel <= 14) ++ { ++ ULONG TxPinCfg = 0x00050F0A;// 2007.10.09 by Brian : 0x0005050A ==> 0x00050F0A ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ ++ /* For 1T/2R chip only... */ ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ } ++ else ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); ++ } ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ if ((BbpValue != 0x00)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); ++ } ++ ++ // 5.5GHz band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x04); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R. ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ else ++ { ++ ULONG TxPinCfg = 0x00050F05;//2007.10.09 by Brian : 0x00050505 ==> 0x00050F05 ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ if ((BbpValue != 0x00)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); ++ } ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R91, &BbpValue); ++ ASSERT((BbpValue == 0x04)); ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R92, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ ++ // 5.5GHz band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x02); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R. ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ ++ // R66 should be set according to Channel and use 20MHz when scanning ++ if (Channel <= 14) ++ { ++ // BG band ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { ++ // 5.5 GHz band ++ if (pAd->ate.TxWI.BW == BW_20) ++ { ++ R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { ++ R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ ++ // ++ // On 11A, We should delay and wait RF/BBP to be stable ++ // and the appropriate time should be 1000 micro seconds ++ // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. ++ // ++ RTMPusecDelay(1000); ++ ++ if (Channel > 14) ++ { ++ // When 5.5GHz band the LSB of TxPwr will be used to reduced 7dB or not. ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%u, Pwr1=%u, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ (R3 & 0x00003e00) >> 9, ++ (R4 & 0x000007c0) >> 6, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++ } ++} ++ ++// ++// In fact, no one will call this routine so far ! ++// ++/* ++ ========================================================================== ++ Description: ++ Gives CCK TX rate 2 more dB TX power. ++ This routine works only in ATE mode. ++ ++ calculate desired Tx power in RF R3.Tx0~5, should consider - ++ 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) ++ 1. TxPowerPercentage ++ 2. auto calibration based on TSSI feedback ++ 3. extra 2 db for CCK ++ 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP ++ ++ NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), ++ it should be called AFTER MlmeDynamicTxRateSwitching() ++ ========================================================================== ++ */ ++VOID ATEAsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i, j; ++ CHAR DeltaPwr = 0; ++ BOOLEAN bAutoTxAgc = FALSE; ++ UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; ++ UCHAR BbpR49 = 0, idx; ++ PCHAR pTxAgcCompensate; ++ ULONG TxPwr[5]; ++ CHAR Value; ++ ++ /* no one calls this procedure so far */ ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ if (pAd->ate.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; ++ } ++ } ++ else ++ { ++ if (pAd->ate.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; ++ } ++ } ++ ++ // TX power compensation for temperature variation based on TSSI. ++ // Do it per 4 seconds. ++ if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ /* bg channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ TssiRef = pAd->TssiRefG; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; ++ TxAgcStep = pAd->TxAgcStepG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ /* a channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ TssiRef = pAd->TssiRefA; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; ++ TxAgcStep = pAd->TxAgcStepA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ { ++ /* BbpR49 is unsigned char */ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); ++ ++ /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ ++ /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ ++ /* step value is defined in pAd->TxAgcStepG for tx power value */ ++ ++ /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ ++ /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ above value are examined in mass factory production */ ++ /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ ++ ++ /* plus is 0x10 ~ 0x40, minus is 0x60 ~ 0x90 */ ++ /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ ++ /* if value is 0x65, tx power will be -= TxAgcStep*(2-1) */ ++ ++ if (BbpR49 > pTssiMinusBoundary[1]) ++ { ++ // Reading is larger than the reference value. ++ // Check for how large we need to decrease the Tx power. ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should decrease, idx = 0 means there is nothing to compensate ++// if (R3 > (ULONG) (TxAgcStep * (idx-1))) ++ *pTxAgcCompensate = -(TxAgcStep * (idx-1)); ++// else ++// *pTxAgcCompensate = -((UCHAR)R3); ++ ++ DeltaPwr += (*pTxAgcCompensate); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else if (BbpR49 < pTssiPlusBoundary[1]) ++ { ++ // Reading is smaller than the reference value ++ // check for how large we need to increase the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should increase, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = TxAgcStep * (idx-1); ++ DeltaPwr += (*pTxAgcCompensate); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else ++ { ++ *pTxAgcCompensate = 0; ++ ATEDBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, 0)); ++ } ++ } ++ } ++ else ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ DeltaPwr += (*pTxAgcCompensate); ++ } ++ ++ /* calculate delta power based on the percentage specified from UI */ ++ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) ++ // We lower TX power here according to the percentage specified from UI ++ if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW ++ { ++ DeltaPwr -= 1; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW ++ { ++ DeltaPwr -= 3; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW ++ { ++ DeltaPwr -= 6; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW ++ { ++ DeltaPwr -= 9; ++ } ++ else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW ++ { ++ DeltaPwr -= 12; ++ } ++ ++ /* reset different new tx power for different TX rate */ ++ for(i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ ++ ++ if ((Value + DeltaPwr) < 0) ++ { ++ Value = 0; /* min */ ++ } ++ else if ((Value + DeltaPwr) > 0xF) ++ { ++ Value = 0xF; /* max */ ++ } ++ else ++ { ++ Value += DeltaPwr; /* temperature compensation */ ++ } ++ ++ /* fill new value to CSR offset */ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ ++ /* write tx power value to CSR */ ++ /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M ++ TX power for OFDM 6M/9M ++ TX power for CCK5.5M/11M ++ TX power for CCK1M/2M */ ++ /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); ++ ++ ++ } ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Write TxWI for ATE mode. ++ ++ Return Value: ++ None ++ ======================================================================== ++*/ ++#ifdef RT2860 ++static VOID ATEWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pOutTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit) ++{ ++ TXWI_STRUC TxWI; ++ PTXWI_STRUC pTxWI; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(&TxWI, TXWI_SIZE); ++ pTxWI = &TxWI; ++ ++ pTxWI->FRAG= FRAG; ++ ++ pTxWI->CFACK = CFACK; ++ pTxWI->TS= InsTimestamp; ++ pTxWI->AMPDU = AMPDU; ++ pTxWI->ACK = Ack; ++ pTxWI->txop= Txopmode; ++ ++ pTxWI->NSEQ = NSeq; ++ // John tune the performace with Intel Client in 20 MHz performance ++ if( BASize >7 ) ++ BASize =7; ++ ++ pTxWI->BAWinSize = BASize; ++ pTxWI->WirelessCliID = WCID; ++ pTxWI->MPDUtotalByteCount = Length; ++ pTxWI->PacketId = PID; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ pTxWI->CFACK = CfAck; ++ pTxWI->MIMOps = 0; ++ pTxWI->MpduDensity = 0; ++ ++ pTxWI->PacketId = pTxWI->MCS; ++ NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); ++ ++ return; ++} ++#endif // RT2860 // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Disable protection for ATE. ++ ======================================================================== ++*/ ++VOID ATEDisableAsicProtect( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PROT_CFG_STRUC ProtCfg, ProtCfg4; ++ UINT32 Protect[6]; ++ USHORT offset; ++ UCHAR i; ++ UINT32 MacReg = 0; ++ ++ // Config ASIC RTS threshold register ++ RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); ++ MacReg &= 0xFF0000FF; ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++ RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); ++ ++ // Initial common protection settings ++ RTMPZeroMemory(Protect, sizeof(Protect)); ++ ProtCfg4.word = 0; ++ ProtCfg.word = 0; ++ ProtCfg.field.TxopAllowGF40 = 1; ++ ProtCfg.field.TxopAllowGF20 = 1; ++ ProtCfg.field.TxopAllowMM40 = 1; ++ ProtCfg.field.TxopAllowMM20 = 1; ++ ProtCfg.field.TxopAllowOfdm = 1; ++ ProtCfg.field.TxopAllowCck = 1; ++ ProtCfg.field.RTSThEn = 1; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ++ // Handle legacy(B/G) protection ++ ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; ++ Protect[0] = ProtCfg.word; ++ Protect[1] = ProtCfg.word; ++ ++ // NO PROTECT ++ // 1.All STAs in the BSS are 20/40 MHz HT ++ // 2. in ai 20/40MHz BSS ++ // 3. all STAs are 20MHz in a 20MHz BSS ++ // Pure HT. no protection. ++ ++ // MM20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[2] = 0x01744004; ++ ++ // MM40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[3] = 0x03f44084; ++ ++ // CF20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[4] = 0x01744004; ++ ++ // CF40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[5] = 0x03f44084; ++ ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ ++ offset = CCK_PROT_CFG; ++ for (i = 0;i < 6;i++) ++ RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); ++ ++} ++ ++ ++/* There are two ways to convert Rssi */ ++#if 1 ++// ++// The way used with GET_LNA_GAIN(). ++// ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ LNAGain = GET_LNA_GAIN(pAd); ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-12 - RssiOffset - LNAGain - Rssi); ++} ++#else ++// ++// The way originally used in ATE of rt2860ap. ++// ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ LNAGain = pAd->ALNAGain; ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ LNAGain = pAd->BLNAGain; ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-32 - RssiOffset + LNAGain - Rssi); ++} ++#endif /* end of #if 1 */ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set Japan filter coefficients if needed. ++ Note: ++ This routine should only be called when ++ entering TXFRAME mode or TXCONT mode. ++ ++ ======================================================================== ++*/ ++static VOID SetJapanFilter( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BbpData = 0; ++ ++ // ++ // If Channel=14 and Bandwidth=20M and Mode=CCK, set BBP R4 bit5=1 ++ // (Japan Tx filter coefficients)when (TXFRAME or TXCONT). ++ // ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BbpData); ++ ++ if ((pAd->ate.TxWI.PHYMODE == MODE_CCK) && (pAd->ate.Channel == 14) && (pAd->ate.TxWI.BW == BW_20)) ++ { ++ BbpData |= 0x20; // turn on ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SetJapanFilter!!!\n")); ++ } ++ else ++ { ++ BbpData &= 0xdf; // turn off ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ClearJapanFilter!!!\n")); ++ } ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BbpData); ++} ++ ++VOID ATESampleRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI) ++{ ++ /* There are two ways to collect RSSI. */ ++#if 1 ++ //pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; ++ if (pRxWI->RSSI0 != 0) ++ { ++ pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); ++ pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; ++ pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; ++ } ++ if (pRxWI->RSSI1 != 0) ++ { ++ pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); ++ pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; ++ pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; ++ } ++ if (pRxWI->RSSI2 != 0) ++ { ++ pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); ++ pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; ++ pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; ++ } ++ ++ pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0);// CHAR ==> UCHAR ? ++ pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1);// CHAR ==> UCHAR ? ++ ++ pAd->ate.NumOfAvgRssiSample ++; ++#else ++ pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0); ++ pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1); ++ pAd->ate.RxCntPerSec++; ++ pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); ++ pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); ++ pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); ++ pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; ++ pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; ++ pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; ++ pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; ++ pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; ++ pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; ++ pAd->ate.NumOfAvgRssiSample ++; ++#endif ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPStationStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++// BOOLEAN Cancelled; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStop\n")); ++ ++#if 0 ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++#endif ++ // For rx statistics, we need to keep this timer running. ++// RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStop\n")); ++} ++ ++VOID RTMPStationStart( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); ++#ifdef RT2860 ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ // ++ // We did not cancel this timer when entering ATE mode. ++ // ++// RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); ++#endif // RT2860 // ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Setup Frame format. ++ NOTE: ++ This routine should only be used in ATE mode. ++ ========================================================================== ++ */ ++#ifdef RT2860 ++static INT ATESetUpFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TxIdx) ++{ ++ UINT j; ++ PTXD_STRUC pTxD; ++#ifdef RT_BIG_ENDIAN ++ PTXD_STRUC pDestTxD; ++ TXD_STRUC TxD; ++#endif ++ PNDIS_PACKET pPacket; ++ PUCHAR pDest; ++ PVOID AllocVa; ++ NDIS_PHYSICAL_ADDRESS AllocPa; ++ HTTRANSMIT_SETTING TxHTPhyMode; ++ ++ PRTMP_TX_RING pTxRing = &pAd->TxRing[QID_AC_BE]; ++ PTXWI_STRUC pTxWI = (PTXWI_STRUC) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; ++ PUCHAR pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa; ++ ++#ifdef RALINK_28xx_QA ++ PHEADER_802_11 pHeader80211; ++#endif // RALINK_28xx_QA // ++ ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // always use QID_AC_BE and FIFO_EDCA ++ ++ // fill TxWI ++ TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; ++ TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; ++ TxHTPhyMode.field.STBC = 0; ++ TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; ++ TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; ++ ATEWriteTxWI(pAd, pTxWI, pAd->ate.TxWI.FRAG, pAd->ate.TxWI.CFACK, pAd->ate.TxWI.TS, pAd->ate.TxWI.AMPDU, pAd->ate.TxWI.ACK, pAd->ate.TxWI.NSEQ, ++ pAd->ate.TxWI.BAWinSize, 0, pAd->ate.TxWI.MPDUtotalByteCount, pAd->ate.TxWI.PacketId, 0, 0, pAd->ate.TxWI.txop/*IFS_HTTXOP*/, pAd->ate.TxWI.CFACK/*FALSE*/, &TxHTPhyMode); ++ } ++ else ++ { ++ TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; ++ TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; ++ TxHTPhyMode.field.STBC = 0; ++ TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; ++ TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; ++ ATEWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ++ 4, 0, pAd->ate.TxLength, 0, 0, 0, IFS_HTTXOP, FALSE, &TxHTPhyMode); ++ } ++ ++ // fill 802.11 header. ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE, pAd->ate.Header, pAd->ate.HLen); ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE, TemplateFrame, LENGTH_802_11); ++ NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE+4, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE+10, pAd->ate.Addr2, ETH_LENGTH_OF_ADDRESS); ++ NdisMoveMemory(pDMAHeaderBufVA+TXWI_SIZE+16, pAd->ate.Addr3, ETH_LENGTH_OF_ADDRESS); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (((PUCHAR)pDMAHeaderBufVA)+TXWI_SIZE), DIR_READ, FALSE); ++#endif // RT_BIG_ENDIAN // ++ ++ /* alloc buffer for payload */ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ /* Why not use RTMP_AllocateTxPacketBuffer() instead of RTMP_AllocateRxPacketBuffer()? */ ++ pPacket = RTMP_AllocateRxPacketBuffer(pAd, pAd->ate.DLen + 0x100, FALSE, &AllocVa, &AllocPa); ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ /* Why not use RTMP_AllocateTxPacketBuffer() instead of RTMP_AllocateRxPacketBuffer()? */ ++ pPacket = RTMP_AllocateRxPacketBuffer(pAd, pAd->ate.TxLength, FALSE, &AllocVa, &AllocPa); ++ } ++ ++ if (pPacket == NULL) ++ { ++ pAd->ate.TxCount = 0; ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s fail to alloc packet space.\n", __FUNCTION__)); ++ return -1; ++ } ++ pTxRing->Cell[TxIdx].pNextNdisPacket = pPacket; ++ ++ pDest = (PUCHAR) AllocVa; ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ RTPKT_TO_OSPKT(pPacket)->len = pAd->ate.DLen; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ RTPKT_TO_OSPKT(pPacket)->len = pAd->ate.TxLength - LENGTH_802_11; ++ } ++ ++ // Prepare frame payload ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // copy pattern ++ if ((pAd->ate.PLen != 0)) ++ { ++ int j; ++ ++ for (j = 0; j < pAd->ate.DLen; j+=pAd->ate.PLen) ++ { ++ memcpy(RTPKT_TO_OSPKT(pPacket)->data + j, pAd->ate.Pattern, pAd->ate.PLen); ++ } ++ } ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ for(j = 0; j < RTPKT_TO_OSPKT(pPacket)->len; j++) ++ pDest[j] = 0xA5; ++ } ++ ++ // ++ // build Tx Descriptor ++ // ++#ifndef RT_BIG_ENDIAN ++ pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa; ++#else ++ pDestTxD = (PTXD_STRUC)pTxRing->Cell[TxIdx].AllocVa; ++ TxD = *pDestTxD; ++ pTxD = &TxD; ++#endif // !RT_BIG_ENDIAN // ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // prepare TxD ++ NdisZeroMemory(pTxD, TXD_SIZE); ++ RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); ++ // build TX DESC ++ pTxD->SDPtr0 = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa); ++ pTxD->SDLen0 = TXWI_SIZE + pAd->ate.HLen; ++ pTxD->LastSec0 = 0; ++ pTxD->SDPtr1 = AllocPa; ++ pTxD->SDLen1 = RTPKT_TO_OSPKT(pPacket)->len; ++ pTxD->LastSec1 = 1; ++ ++ pDest = (PUCHAR)pTxWI; ++ pDest += TXWI_SIZE; ++ pHeader80211 = (PHEADER_802_11)pDest; ++ ++ // modify sequence number.... ++ if (pAd->ate.TxDoneCount == 0) ++ { ++ pAd->ate.seq = pHeader80211->Sequence; ++ } ++ else ++ pHeader80211->Sequence = ++pAd->ate.seq; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ NdisZeroMemory(pTxD, TXD_SIZE); ++ RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA); ++ // build TX DESC ++ pTxD->SDPtr0 = RTMP_GetPhysicalAddressLow (pTxRing->Cell[TxIdx].DmaBuf.AllocPa); ++ pTxD->SDLen0 = TXWI_SIZE + LENGTH_802_11; ++ pTxD->LastSec0 = 0; ++ pTxD->SDPtr1 = AllocPa; ++ pTxD->SDLen1 = RTPKT_TO_OSPKT(pPacket)->len; ++ pTxD->LastSec1 = 1; ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++ RTMPFrameEndianChange(pAd, (((PUCHAR)pDMAHeaderBufVA)+TXWI_SIZE), DIR_WRITE, FALSE); ++ RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD); ++ WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD); ++#endif // RT_BIG_ENDIAN // ++ return 0; ++} ++/* */ ++/* */ ++/*=======================End of RT2860=======================*/ ++#endif // RT2860 // ++ ++ ++VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) ++{ ++ USHORT i; ++ USHORT value; ++ ++ for (i = 0 ; i < EEPROM_SIZE/2 ; ) ++ { ++ /* "value" is expecially for some compilers... */ ++ RT28xx_EEPROM_READ16(pAd, i*2, value); ++ Data[i] = value; ++ i++; ++ } ++} ++ ++VOID rt_ee_write_all(PRTMP_ADAPTER pAd, USHORT *Data) ++{ ++ USHORT i; ++ USHORT value; ++ ++ for (i = 0 ; i < EEPROM_SIZE/2 ; ) ++ { ++ /* "value" is expecially for some compilers... */ ++ value = Data[i]; ++ RT28xx_EEPROM_WRITE16(pAd, i*2, value); ++ i ++; ++ } ++} ++#ifdef RALINK_28xx_QA ++VOID ATE_QA_Statistics( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN PHEADER_802_11 pHeader) ++{ ++ // update counter first ++ if (pHeader != NULL) ++ { ++ if (pHeader->FC.Type == BTYPE_DATA) ++ { ++ if (pRxD->U2M) ++ pAd->ate.U2M++; ++ else ++ pAd->ate.OtherData++; ++ } ++ else if (pHeader->FC.Type == BTYPE_MGMT) ++ { ++ if (pHeader->FC.SubType == SUBTYPE_BEACON) ++ pAd->ate.Beacon++; ++ else ++ pAd->ate.OtherCount++; ++ } ++ else if (pHeader->FC.Type == BTYPE_CNTL) ++ { ++ pAd->ate.OtherCount++; ++ } ++ } ++ pAd->ate.RSSI0 = pRxWI->RSSI0; ++ pAd->ate.RSSI1 = pRxWI->RSSI1; ++ pAd->ate.RSSI2 = pRxWI->RSSI2; ++ pAd->ate.SNR0 = pRxWI->SNR0; ++ pAd->ate.SNR1 = pRxWI->SNR1; ++} ++ ++/* command id with Cmd Type == 0x0008(for 28xx)/0x0005(for iNIC) */ ++#define RACFG_CMD_RF_WRITE_ALL 0x0000 ++#define RACFG_CMD_E2PROM_READ16 0x0001 ++#define RACFG_CMD_E2PROM_WRITE16 0x0002 ++#define RACFG_CMD_E2PROM_READ_ALL 0x0003 ++#define RACFG_CMD_E2PROM_WRITE_ALL 0x0004 ++#define RACFG_CMD_IO_READ 0x0005 ++#define RACFG_CMD_IO_WRITE 0x0006 ++#define RACFG_CMD_IO_READ_BULK 0x0007 ++#define RACFG_CMD_BBP_READ8 0x0008 ++#define RACFG_CMD_BBP_WRITE8 0x0009 ++#define RACFG_CMD_BBP_READ_ALL 0x000a ++#define RACFG_CMD_GET_COUNTER 0x000b ++#define RACFG_CMD_CLEAR_COUNTER 0x000c ++ ++#define RACFG_CMD_RSV1 0x000d ++#define RACFG_CMD_RSV2 0x000e ++#define RACFG_CMD_RSV3 0x000f ++ ++#define RACFG_CMD_TX_START 0x0010 ++#define RACFG_CMD_GET_TX_STATUS 0x0011 ++#define RACFG_CMD_TX_STOP 0x0012 ++#define RACFG_CMD_RX_START 0x0013 ++#define RACFG_CMD_RX_STOP 0x0014 ++#define RACFG_CMD_GET_NOISE_LEVEL 0x0015 ++ ++#define RACFG_CMD_ATE_START 0x0080 ++#define RACFG_CMD_ATE_STOP 0x0081 ++ ++#define RACFG_CMD_ATE_START_TX_CARRIER 0x0100 ++#define RACFG_CMD_ATE_START_TX_CONT 0x0101 ++#define RACFG_CMD_ATE_START_TX_FRAME 0x0102 ++#define RACFG_CMD_ATE_SET_BW 0x0103 ++#define RACFG_CMD_ATE_SET_TX_POWER0 0x0104 ++#define RACFG_CMD_ATE_SET_TX_POWER1 0x0105 ++#define RACFG_CMD_ATE_SET_FREQ_OFFSET 0x0106 ++#define RACFG_CMD_ATE_GET_STATISTICS 0x0107 ++#define RACFG_CMD_ATE_RESET_COUNTER 0x0108 ++#define RACFG_CMD_ATE_SEL_TX_ANTENNA 0x0109 ++#define RACFG_CMD_ATE_SEL_RX_ANTENNA 0x010a ++#define RACFG_CMD_ATE_SET_PREAMBLE 0x010b ++#define RACFG_CMD_ATE_SET_CHANNEL 0x010c ++#define RACFG_CMD_ATE_SET_ADDR1 0x010d ++#define RACFG_CMD_ATE_SET_ADDR2 0x010e ++#define RACFG_CMD_ATE_SET_ADDR3 0x010f ++#define RACFG_CMD_ATE_SET_RATE 0x0110 ++#define RACFG_CMD_ATE_SET_TX_FRAME_LEN 0x0111 ++#define RACFG_CMD_ATE_SET_TX_FRAME_COUNT 0x0112 ++#define RACFG_CMD_ATE_START_RX_FRAME 0x0113 ++#define RACFG_CMD_ATE_E2PROM_READ_BULK 0x0114 ++#define RACFG_CMD_ATE_E2PROM_WRITE_BULK 0x0115 ++#define RACFG_CMD_ATE_IO_WRITE_BULK 0x0116 ++#define RACFG_CMD_ATE_BBP_READ_BULK 0x0117 ++#define RACFG_CMD_ATE_BBP_WRITE_BULK 0x0118 ++#define RACFG_CMD_ATE_RF_READ_BULK 0x0119 ++#define RACFG_CMD_ATE_RF_WRITE_BULK 0x011a ++ ++ ++ ++#define A2Hex(_X, _p) \ ++{ \ ++ UCHAR *p; \ ++ _X = 0; \ ++ p = _p; \ ++ while (((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= '0') && (*p <= '9'))) \ ++ { \ ++ if ((*p >= 'a') && (*p <= 'f')) \ ++ _X = _X * 16 + *p - 87; \ ++ else if ((*p >= 'A') && (*p <= 'F')) \ ++ _X = _X * 16 + *p - 55; \ ++ else if ((*p >= '0') && (*p <= '9')) \ ++ _X = _X * 16 + *p - 48; \ ++ p++; \ ++ } \ ++} ++ ++ ++static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); ++static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); ++static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len); ++ ++#ifdef UCOS ++int ate_copy_to_user( ++ IN PUCHAR payload, ++ IN PUCHAR msg, ++ IN INT len) ++{ ++ memmove(payload, msg, len); ++ return 0; ++} ++ ++#undef copy_to_user ++#define copy_to_user(x,y,z) ate_copy_to_user((PUCHAR)x, (PUCHAR)y, z) ++#endif // UCOS // ++ ++#define LEN_OF_ARG 16 ++ ++VOID RtmpDoAte( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ unsigned short Command_Id; ++ struct ate_racfghdr *pRaCfg; ++ INT Status = NDIS_STATUS_SUCCESS; ++ ++ ++ ++ if((pRaCfg = kmalloc(sizeof(struct ate_racfghdr), GFP_KERNEL)) == NULL) ++ { ++ Status = -EINVAL; ++ return; ++ } ++ ++ NdisZeroMemory(pRaCfg, sizeof(struct ate_racfghdr)); ++ ++ if (copy_from_user((PUCHAR)pRaCfg, wrq->u.data.pointer, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ kfree(pRaCfg); ++ return; ++ } ++ ++ ++ Command_Id = ntohs(pRaCfg->command_id); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id)); ++ ++ switch (Command_Id) ++ { ++ // We will get this command when QA starts. ++ case RACFG_CMD_ATE_START: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START\n")); ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_ATE_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START is done !\n")); ++ } ++ Set_ATE_Proc(pAdapter, "ATESTART"); ++ } ++ break; ++ ++ // We will get this command either QA is closed or ated is killed by user. ++ case RACFG_CMD_ATE_STOP: ++ { ++#ifndef UCOS ++ INT32 ret; ++#endif // !UCOS // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_STOP\n")); ++ ++ // Distinguish this command came from QA(via ated) ++ // or ate daemon according to the existence of pid in payload. ++ // No need to prepare feedback if this cmd came directly from ate daemon. ++ pRaCfg->length = ntohs(pRaCfg->length); ++ ++ if (pRaCfg->length == sizeof(pAdapter->ate.AtePid)) ++ { ++ // This command came from QA. ++ // Get the pid of ATE daemon. ++ memcpy((UCHAR *)&pAdapter->ate.AtePid, ++ (&pRaCfg->data[0]) - 2/* == &(pRaCfg->status) */, ++ sizeof(pAdapter->ate.AtePid)); ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_STOP\n")); ++ Status = -EFAULT; ++ } ++ ++ // ++ // kill ATE daemon when leaving ATE mode. ++ // We must kill ATE daemon first before setting ATESTOP, ++ // or Microsoft will report sth. wrong. ++#ifndef UCOS ++ ret = KILL_THREAD_PID(pAdapter->ate.AtePid, SIGTERM, 1); ++ if (ret) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("%s: unable to signal thread\n", pAdapter->net_dev->name)); ++ } ++#endif // !UCOS // ++ } ++ ++ // AP might have in ATE_STOP mode due to cmd from QA. ++ if (ATE_ON(pAdapter)) ++ { ++ // Someone has killed ate daemon while QA GUI is still open. ++ Set_ATE_Proc(pAdapter, "ATESTOP"); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_AP_START is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RF_WRITE_ALL: ++ { ++ UINT32 R1, R2, R3, R4; ++ USHORT channel; ++ ++ memcpy(&R1, pRaCfg->data-2, 4); ++ memcpy(&R2, pRaCfg->data+2, 4); ++ memcpy(&R3, pRaCfg->data+6, 4); ++ memcpy(&R4, pRaCfg->data+10, 4); ++ memcpy(&channel, pRaCfg->data+14, 2); ++ ++ pAdapter->LatchRfRegs.R1 = ntohl(R1); ++ pAdapter->LatchRfRegs.R2 = ntohl(R2); ++ pAdapter->LatchRfRegs.R3 = ntohl(R3); ++ pAdapter->LatchRfRegs.R4 = ntohl(R4); ++ pAdapter->LatchRfRegs.Channel = ntohs(channel); ++ ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R3); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R4); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RF_WRITE_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RF_WRITE_ALL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_READ16: ++ { ++ USHORT offset, value, tmp; ++ ++ offset = ntohs(pRaCfg->status); ++ /* "tmp" is expecially for some compilers... */ ++ RT28xx_EEPROM_READ16(pAdapter, offset, tmp); ++ value = tmp; ++ value = htons(value); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("EEPROM Read offset = 0x%04x, value = 0x%04x\n", offset, value)); ++ ++ // prepare feedback ++ pRaCfg->length = htons(4); ++ pRaCfg->status = htons(0); ++ memcpy(pRaCfg->data, &value, 2); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("sizeof(struct ate_racfghdr) = %d\n", sizeof(struct ate_racfghdr))); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ16\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ16 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_WRITE16: ++ { ++ USHORT offset, value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&value, pRaCfg->data, 2); ++ value = ntohs(value); ++ RT28xx_EEPROM_WRITE16(pAdapter, offset, value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE16\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_WRITE16 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_READ_ALL: ++ { ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer, EEPROM_SIZE); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+EEPROM_SIZE); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ_ALL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_WRITE_ALL: ++ { ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ NdisZeroMemory((UCHAR *)buffer, EEPROM_SIZE); ++ memcpy_exs(pAdapter, (UCHAR *)buffer, (UCHAR *)&pRaCfg->status, EEPROM_SIZE); ++ rt_ee_write_all(pAdapter,(USHORT *)buffer); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_E2PROM_WRITE_ALL is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_IO_READ: ++ { ++ UINT32 offset; ++ UINT32 value; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract the offset out. ++ offset &= 0x0000FFFF; ++ RTMP_IO_READ32(pAdapter, offset, &value); ++ value = htonl(value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(6); ++ pRaCfg->status = htons(0); ++ memcpy(pRaCfg->data, &value, 4); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_IO_WRITE: ++ { ++ UINT32 offset, value; ++ ++ memcpy(&offset, pRaCfg->data-2, 4); ++ memcpy(&value, pRaCfg->data+2, 4); ++ ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract out the offset. ++ offset &= 0x0000FFFF; ++ value = ntohl(value); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_IO_WRITE: offset = %x, value = %x\n", offset, value)); ++ RTMP_IO_WRITE32(pAdapter, offset, value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_WRITE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_WRITE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_IO_READ_BULK: ++ { ++ UINT32 offset; ++ USHORT len; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract the offset. ++ offset &= 0x0000FFFF; ++ memcpy(&len, pRaCfg->data+2, 2); ++ len = ntohs(len); ++ ++ if (len > 371) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("len is too large, make it smaller\n")); ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(1); ++ break; ++ } ++ ++ RTMP_IO_READ_BULK(pAdapter, pRaCfg->data, (UCHAR *)offset, len*4);// unit in four bytes ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len*4);// unit in four bytes ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ_BULK is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_BBP_READ8: ++ { ++ USHORT offset; ++ UCHAR value; ++ ++ value = 0; ++ offset = ntohs(pRaCfg->status); ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); ++ } ++ // prepare feedback ++ pRaCfg->length = htons(3); ++ pRaCfg->status = htons(0); ++ pRaCfg->data[0] = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("BBP value = %x\n", value)); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ8\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ8 is done !\n")); ++ } ++ } ++ break; ++ case RACFG_CMD_BBP_WRITE8: ++ { ++ USHORT offset; ++ UCHAR value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&value, pRaCfg->data, 1); ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); ++ } ++ ++ if ((offset == BBP_R1) || (offset == BBP_R3)) ++ { ++ SyncTxRxConfig(pAdapter, offset, value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_WRITE8\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_WRITE8 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_BBP_READ_ALL: ++ { ++ USHORT j; ++ ++ for (j = 0; j < 137; j++) ++ { ++ pRaCfg->data[j] = 0; ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+137); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ_ALL is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_ATE_E2PROM_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ if (offset + len <= EEPROM_SIZE) ++ memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer+offset, len); ++ else ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("exceed EEPROM size\n")); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_E2PROM_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_E2PROM_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ memcpy_exs(pAdapter, (UCHAR *)buffer + offset, (UCHAR *)pRaCfg->data + 2, len); ++ rt_ee_write_all(pAdapter,(USHORT *)buffer); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_E2PROM_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_IO_WRITE_BULK: ++ { ++ UINT32 offset, i, value; ++ USHORT len; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ memcpy(&len, pRaCfg->data+2, 2); ++ len = ntohs(len); ++ ++ for (i = 0; i < len; i += 4) ++ { ++ memcpy_exl(pAdapter, (UCHAR *)&value, pRaCfg->data+4+i, 4); ++ printk("Write %x %x\n", offset + i, value); ++ RTMP_IO_WRITE32(pAdapter, (offset +i) & 0xffff, value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_IO_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_IO_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_BBP_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ pRaCfg->data[j - offset] = 0; ++ ++ if (pAdapter->ate.Mode == ATE_STOP) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ else ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_BBP_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ UCHAR *value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ value = pRaCfg->data + 2 + (j - offset); ++ if (pAdapter->ate.Mode == ATE_STOP) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); ++ } ++ else ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_WRITE_BULK is done !\n")); ++ } ++ } ++ break; ++ ++#ifdef CONFIG_RALINK_RT3052 ++ case RACFG_CMD_ATE_RF_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ pRaCfg->data[j - offset] = 0; ++ RT30xxReadRFRegister(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_RF_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ UCHAR *value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ value = pRaCfg->data + 2 + (j - offset); ++ RT30xxWriteRFRegister(pAdapter, j, *value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++#endif ++ ++ ++ case RACFG_CMD_GET_NOISE_LEVEL: ++ { ++ UCHAR channel; ++ INT32 buffer[3][10];/* 3 : RxPath ; 10 : no. of per rssi samples */ ++ ++ channel = (ntohs(pRaCfg->status) & 0x00FF); ++ CalNoiseLevel(pAdapter, channel, buffer); ++ memcpy_exl(pAdapter, (UCHAR *)pRaCfg->data, (UCHAR *)&(buffer[0][0]), (sizeof(INT32)*3*10)); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2 + (sizeof(INT32)*3*10)); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_NOISE_LEVEL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_NOISE_LEVEL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_GET_COUNTER: ++ { ++ memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.U2M, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->ate.OtherData, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->ate.Beacon, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->ate.OtherCount, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->ate.TxAc0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->ate.TxAc1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->ate.TxAc2, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->ate.TxAc3, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->ate.TxHCCA, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->ate.TxMgmt, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&pAdapter->ate.RSSI0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&pAdapter->ate.RSSI1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&pAdapter->ate.RSSI2, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[52], (UCHAR *)&pAdapter->ate.SNR0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[56], (UCHAR *)&pAdapter->ate.SNR1, 4); ++ ++ pRaCfg->length = htons(2+60); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_COUNTER is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_CLEAR_COUNTER: ++ { ++ pAdapter->ate.U2M = 0; ++ pAdapter->ate.OtherData = 0; ++ pAdapter->ate.Beacon = 0; ++ pAdapter->ate.OtherCount = 0; ++ pAdapter->ate.TxAc0 = 0; ++ pAdapter->ate.TxAc1 = 0; ++ pAdapter->ate.TxAc2 = 0; ++ pAdapter->ate.TxAc3 = 0; ++ pAdapter->ate.TxHCCA = 0; ++ pAdapter->ate.TxMgmt = 0; ++ pAdapter->ate.TxDoneCount = 0; ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_CLEAR_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_CLEAR_COUNTER is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_TX_START: ++ { ++ USHORT *p; ++ USHORT err = 1; ++ UCHAR Bbp22Value = 0, Bbp24Value = 0; ++ ++ if ((pAdapter->ate.TxStatus != 0) && (pAdapter->ate.Mode & ATE_TXFRAME)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Ate Tx is already running, to run next Tx, you must stop it first\n")); ++ err = 2; ++ goto TX_START_ERROR; ++ } ++ else if ((pAdapter->ate.TxStatus != 0) && !(pAdapter->ate.Mode & ATE_TXFRAME)) ++ { ++ int i = 0; ++ ++ while ((i++ < 10) && (pAdapter->ate.TxStatus != 0)) ++ { ++ RTMPusecDelay(5000); ++ } ++ ++ // force it to stop ++ pAdapter->ate.TxStatus = 0; ++ pAdapter->ate.TxDoneCount = 0; ++ //pAdapter->ate.Repeat = 0; ++ pAdapter->ate.bQATxStart = FALSE; ++ } ++ ++ // If pRaCfg->length == 0, this "RACFG_CMD_TX_START" is for Carrier test or Carrier Suppression. ++ if (ntohs(pRaCfg->length) != 0) ++ { ++ // Get frame info ++ ++ NdisMoveMemory(&pAdapter->ate.TxWI, pRaCfg->data + 2, 16); ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)&pAdapter->ate.TxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ NdisMoveMemory(&pAdapter->ate.TxCount, pRaCfg->data + 18, 4); ++ pAdapter->ate.TxCount = ntohl(pAdapter->ate.TxCount); ++ ++ p = (USHORT *)(&pRaCfg->data[22]); ++ //p = pRaCfg->data + 22; ++ // always use QID_AC_BE ++ pAdapter->ate.QID = 0; ++ p = (USHORT *)(&pRaCfg->data[24]); ++ //p = pRaCfg->data + 24; ++ pAdapter->ate.HLen = ntohs(*p); ++ ++ if (pAdapter->ate.HLen > 32) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.HLen > 32\n")); ++ err = 3; ++ goto TX_START_ERROR; ++ } ++ ++ NdisMoveMemory(&pAdapter->ate.Header, pRaCfg->data + 26, pAdapter->ate.HLen); ++ ++ ++ pAdapter->ate.PLen = ntohs(pRaCfg->length) - (pAdapter->ate.HLen + 28); ++ ++ if (pAdapter->ate.PLen > 32) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.PLen > 32\n")); ++ err = 4; ++ goto TX_START_ERROR; ++ } ++ ++ NdisMoveMemory(&pAdapter->ate.Pattern, pRaCfg->data + 26 + pAdapter->ate.HLen, pAdapter->ate.PLen); ++ pAdapter->ate.DLen = pAdapter->ate.TxWI.MPDUtotalByteCount - pAdapter->ate.HLen; ++ } ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R22, &Bbp22Value); ++ ++ switch (Bbp22Value) ++ { ++ case BBP22_TXFRAME: ++ { ++ if (pAdapter->ate.TxCount == 0) ++ { ++#ifdef RT2860 ++ pAdapter->ate.TxCount = 0xFFFFFFFF; ++#endif // RT2860 // ++ } ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXFRAME"); ++ } ++ break; ++ ++ case BBP22_TXCONT_OR_CARRSUPP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("BBP22_TXCONT_OR_CARRSUPP\n")); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, 24, &Bbp24Value); ++ ++ switch (Bbp24Value) ++ { ++ case BBP24_TXCONT: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCONT\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXCONT"); ++ } ++ break; ++ ++ case BBP24_CARRSUPP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARRSUPP\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ pAdapter->ate.Mode |= ATE_TXCARRSUPP; ++ } ++ break; ++ ++ default: ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); ++ } ++ break; ++ } ++ } ++ break; ++ ++ case BBP22_TXCARR: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARR\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXCARR"); ++ } ++ break; ++ ++ default: ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); ++ } ++ break; ++ } ++ ++ if (pAdapter->ate.bQATxStart == TRUE) ++ { ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() was failed in case RACFG_CMD_TX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_START is done !\n")); ++ } ++ break; ++ } ++ ++TX_START_ERROR: ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(err); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_TX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("feedback of TX_START_ERROR is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_GET_TX_STATUS: ++ { ++ UINT32 count; ++ ++ // prepare feedback ++ pRaCfg->length = htons(6); ++ pRaCfg->status = htons(0); ++ count = htonl(pAdapter->ate.TxDoneCount); ++ NdisMoveMemory(pRaCfg->data, &count, 4); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_TX_STATUS\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_TX_STATUS is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_TX_STOP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_TX_STOP\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXSTOP"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_TX_STOP\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_STOP is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RX_START: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); ++ ++ pAdapter->ate.bQARxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "RXFRAME"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RX_STOP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_STOP\n")); ++ ++ Set_ATE_Proc(pAdapter, "RXSTOP"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_STOP\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_STOP is done !\n")); ++ } ++ } ++ break; ++ ++ /* The following cases are for new ATE GUI(not QA). */ ++ /*==================================================*/ ++ case RACFG_CMD_ATE_START_TX_CARRIER: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CARRIER\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXCARR"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CARRIER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CARRIER is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_TX_CONT: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CONT\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXCONT"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CONT\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CONT is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_TX_FRAME: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_FRAME\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXFRAME"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_FRAME\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_FRAME is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_BW: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_BW\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ ++ Set_ATE_TX_BW_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_BW\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_BW is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_POWER0: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER0\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_POWER0_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER0\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER0 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_POWER1: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER1\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_POWER1_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER1\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER1 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_FREQ_OFFSET: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_FREQOFFSET_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_FREQ_OFFSET is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_GET_STATISTICS: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_GET_STATISTICS\n")); ++ ++ memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.TxDoneCount, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->WlanCounters.RetryCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->WlanCounters.FailedCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->WlanCounters.RTSSuccessCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->WlanCounters.RTSFailureCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->WlanCounters.FCSErrorCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->Counters8023.RxNoBuffer, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->RalinkCounters.OneSecFalseCCACnt, 4); ++ ++ if (pAdapter->ate.RxAntennaSel == 0) ++ { ++ INT32 RSSI0 = 0; ++ INT32 RSSI1 = 0; ++ INT32 RSSI2 = 0; ++ ++ RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); ++ RSSI1 = (INT32)(pAdapter->ate.LastRssi1 - pAdapter->BbpRssiToDbmDelta); ++ RSSI2 = (INT32)(pAdapter->ate.LastRssi2 - pAdapter->BbpRssiToDbmDelta); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&RSSI1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&RSSI2, 4); ++ pRaCfg->length = htons(2+52); ++ } ++ else ++ { ++ INT32 RSSI0 = 0; ++ ++ RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); ++ pRaCfg->length = htons(2+44); ++ } ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_GET_STATISTICS\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_GET_STATISTICS is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_RESET_COUNTER: ++ { ++ SHORT value = 1; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_RESET_COUNTER\n")); ++ ++ sprintf((PCHAR)str, "%d", value); ++ Set_ResetStatCounter_Proc(pAdapter, str); ++ ++ pAdapter->ate.TxDoneCount = 0; ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RESET_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RESET_COUNTER is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_ATE_SEL_TX_ANTENNA: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_Antenna_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_TX_ANTENNA is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SEL_RX_ANTENNA: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_RX_Antenna_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_RX_ANTENNA is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_PREAMBLE: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_PREAMBLE\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_MODE_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_PREAMBLE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_PREAMBLE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_CHANNEL: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_CHANNEL\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_CHANNEL_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_CHANNEL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_CHANNEL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR1: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR1\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr1, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR1\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR1 is done !\n (ADDR1 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr1[0], ++ pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR2: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR2\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr2, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR2\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR2 is done !\n (ADDR2 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr2[0], ++ pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR3: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR3\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr3, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR3\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR3 is done !\n (ADDR3 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr3[0], ++ pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_RATE: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_RATE\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_MCS_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_RATE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_RATE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_FRAME_LEN: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_LENGTH_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_LEN is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_FRAME_COUNT: ++ { ++ USHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++#ifdef RT2860 ++ /* TX_FRAME_COUNT == 0 means tx infinitely */ ++ if (value == 0) ++ { ++ /* Use TxCount = 0xFFFFFFFF to approximate the infinity. */ ++ pAdapter->ate.TxCount = 0xFFFFFFFF; ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAdapter->ate.TxCount)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); ++ ++ ++ } ++ else ++#endif // RT2860 // ++ { ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_COUNT_Proc(pAdapter, str); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_COUNT is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_RX_FRAME: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); ++ ++ Set_ATE_Proc(pAdapter, "RXFRAME"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ ASSERT(pRaCfg != NULL); ++ if (pRaCfg != NULL) ++ { ++ kfree(pRaCfg); ++ } ++ return; ++} ++ ++VOID BubbleSort(INT32 n, INT32 a[]) ++{ ++ INT32 k, j, temp; ++ ++ for (k = n-1; k>0; k--) ++ { ++ for (j = 0; j a[j+1]) ++ { ++ temp = a[j]; ++ a[j]=a[j+1]; ++ a[j+1]=temp; ++ } ++ } ++ } ++} ++ ++VOID CalNoiseLevel(PRTMP_ADAPTER pAd, UCHAR channel, INT32 RSSI[3][10]) ++{ ++ INT32 RSSI0, RSSI1, RSSI2; ++ CHAR Rssi0Offset, Rssi1Offset, Rssi2Offset; ++ UCHAR BbpR50Rssi0 = 0, BbpR51Rssi1 = 0, BbpR52Rssi2 = 0; ++ UCHAR Org_BBP66value = 0, Org_BBP69value = 0, Org_BBP70value = 0, data = 0; ++ USHORT LNA_Gain = 0; ++ INT32 j = 0; ++ UCHAR Org_Channel = pAd->ate.Channel; ++ USHORT GainValue = 0, OffsetValue = 0; ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &Org_BBP66value); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R69, &Org_BBP69value); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R70, &Org_BBP70value); ++ ++ //********************************************************************** ++ // Read the value of LNA gain and Rssi offset ++ //********************************************************************** ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, GainValue); ++ ++ // for Noise Level ++ if (channel <= 14) ++ { ++ LNA_Gain = GainValue & 0x00FF; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, OffsetValue); ++ Rssi0Offset = OffsetValue & 0x00FF; ++ Rssi1Offset = (OffsetValue & 0xFF00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_BG_OFFSET + 2)/* 0x48 */, OffsetValue); ++ Rssi2Offset = OffsetValue & 0x00FF; ++ } ++ else ++ { ++ LNA_Gain = (GainValue & 0xFF00) >> 8; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, OffsetValue); ++ Rssi0Offset = OffsetValue & 0x00FF; ++ Rssi1Offset = (OffsetValue & 0xFF00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET + 2)/* 0x4C */, OffsetValue); ++ Rssi2Offset = OffsetValue & 0x00FF; ++ } ++ //********************************************************************** ++ { ++ pAd->ate.Channel = channel; ++ ATEAsicSwitchChannel(pAd); ++ mdelay(5); ++ ++ data = 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, data); ++ data = 0x40; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, data); ++ data = 0x40; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, data); ++ mdelay(5); ++ ++ // Start Rx ++ pAd->ate.bQARxStart = TRUE; ++ Set_ATE_Proc(pAd, "RXFRAME"); ++ ++ mdelay(5); ++ ++ for (j = 0; j < 10; j++) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &BbpR50Rssi0); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &BbpR51Rssi1); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &BbpR52Rssi2); ++ ++ mdelay(10); ++ ++ // Calculate RSSI 0 ++ if (BbpR50Rssi0 == 0) ++ { ++ RSSI0 = -100; ++ } ++ else ++ { ++ RSSI0 = (INT32)(-12 - BbpR50Rssi0 - LNA_Gain - Rssi0Offset); ++ } ++ RSSI[0][j] = RSSI0; ++ ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ // Calculate RSSI 1 ++ if (BbpR51Rssi1 == 0) ++ { ++ RSSI1 = -100; ++ } ++ else ++ { ++ RSSI1 = (INT32)(-12 - BbpR51Rssi1 - LNA_Gain - Rssi1Offset); ++ } ++ RSSI[1][j] = RSSI1; ++ } ++ ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ // Calculate RSSI 2 ++ if (BbpR52Rssi2 == 0) ++ RSSI2 = -100; ++ else ++ RSSI2 = (INT32)(-12 - BbpR52Rssi2 - LNA_Gain - Rssi2Offset); ++ ++ RSSI[2][j] = RSSI2; ++ } ++ } ++ ++ // Stop Rx ++ Set_ATE_Proc(pAd, "RXSTOP"); ++ ++ mdelay(5); ++ ++#if 0// Debug Message................ ++ ate_print("\n**********************************************************\n"); ++ ate_print("Noise Level: Channel %d\n", channel); ++ ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[0][0], RSSI[0][1], RSSI[0][2], ++ RSSI[0][3], RSSI[0][4], RSSI[0][5], ++ RSSI[0][6], RSSI[0][7], RSSI[0][8], ++ RSSI[0][9]); ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[1][0], RSSI[1][1], RSSI[1][2], ++ RSSI[1][3], RSSI[1][4], RSSI[1][5], ++ RSSI[1][6], RSSI[1][7], RSSI[1][8], ++ RSSI[1][9]); ++ } ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[2][0], RSSI[2][1], RSSI[2][2], ++ RSSI[2][3], RSSI[2][4], RSSI[2][5], ++ RSSI[2][6], RSSI[2][7], RSSI[2][8], ++ RSSI[2][9]); ++ } ++#endif // 0 // ++ BubbleSort(10, RSSI[0]); // 1R ++ ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ BubbleSort(10, RSSI[1]); ++ } ++ ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ BubbleSort(10, RSSI[2]); ++ } ++ ++#if 0// Debug Message................ ++ ate_print("\nAfter Sorting....Channel %d\n", channel); ++ ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[0][0], RSSI[0][1], RSSI[0][2], ++ RSSI[0][3], RSSI[0][4], RSSI[0][5], ++ RSSI[0][6], RSSI[0][7], RSSI[0][8], ++ RSSI[0][9]); ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[1][0], RSSI[1][1], RSSI[1][2], ++ RSSI[1][3], RSSI[1][4], RSSI[1][5], ++ RSSI[1][6], RSSI[1][7], RSSI[1][8], ++ RSSI[1][9]); ++ } ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[2][0], RSSI[2][1], RSSI[2][2], ++ RSSI[2][3], RSSI[2][4], RSSI[2][5], ++ RSSI[2][6], RSSI[2][7], RSSI[2][8], ++ RSSI[2][9]); ++ } ++ ate_print("**********************************************************\n"); ++#endif // 0 // ++ } ++ ++ pAd->ate.Channel = Org_Channel; ++ ATEAsicSwitchChannel(pAd); ++ ++ // Restore original value ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, Org_BBP66value); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, Org_BBP69value); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, Org_BBP70value); ++ ++ return; ++} ++ ++BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value) ++{ ++ UCHAR tmp = 0, bbp_data = 0; ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); ++ } ++ ++ /* confirm again */ ++ ASSERT(bbp_data == value); ++ ++ switch(offset) ++ { ++ case BBP_R1: ++ /* Need to sync. tx configuration with legacy ATE. */ ++ tmp = (bbp_data & ((1 << 4) | (1 << 3))/* 0x18 */) >> 3; ++ switch(tmp) ++ { ++ /* The BBP R1 bit[4:3] = 2 :: Both DACs will be used by QA. */ ++ case 2: ++ /* All */ ++ pAd->ate.TxAntennaSel = 0; ++ break; ++ /* The BBP R1 bit[4:3] = 0 :: DAC 0 will be used by QA. */ ++ case 0: ++ /* Antenna one */ ++ pAd->ate.TxAntennaSel = 1; ++ break; ++ /* The BBP R1 bit[4:3] = 1 :: DAC 1 will be used by QA. */ ++ case 1: ++ /* Antenna two */ ++ pAd->ate.TxAntennaSel = 2; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ } ++ break;/* case BBP_R1 */ ++ ++ case BBP_R3: ++ /* Need to sync. rx configuration with legacy ATE. */ ++ tmp = (bbp_data & ((1 << 1) | (1 << 0))/* 0x03 */); ++ switch(tmp) ++ { ++ /* The BBP R3 bit[1:0] = 3 :: All ADCs will be used by QA. */ ++ case 3: ++ /* All */ ++ pAd->ate.RxAntennaSel = 0; ++ break; ++ /* The BBP R3 bit[1:0] = 0 :: ADC 0 will be used by QA, */ ++ /* unless the BBP R3 bit[4:3] = 2 */ ++ case 0: ++ /* Antenna one */ ++ pAd->ate.RxAntennaSel = 1; ++ tmp = ((bbp_data & ((1 << 4) | (1 << 3))/* 0x03 */) >> 3); ++ if (tmp == 2)// 3R ++ { ++ /* Default : All ADCs will be used by QA */ ++ pAd->ate.RxAntennaSel = 0; ++ } ++ break; ++ /* The BBP R3 bit[1:0] = 1 :: ADC 1 will be used by QA. */ ++ case 1: ++ /* Antenna two */ ++ pAd->ate.RxAntennaSel = 2; ++ break; ++ /* The BBP R3 bit[1:0] = 2 :: ADC 2 will be used by QA. */ ++ case 2: ++ /* Antenna three */ ++ pAd->ate.RxAntennaSel = 3; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ } ++ break;/* case BBP_R3 */ ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ ++ } ++ return TRUE; ++} ++ ++static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) ++{ ++ ULONG i, Value = 0; ++ ULONG *pDst, *pSrc; ++ UCHAR *p8; ++ ++ p8 = src; ++ pDst = (ULONG *) dst; ++ pSrc = (ULONG *) src; ++ ++ for (i = 0 ; i < (len/4); i++) ++ { ++ /* For alignment issue, we need a variable "Value". */ ++ memmove(&Value, pSrc, 4); ++ Value = htonl(Value); ++ memmove(pDst, &Value, 4); ++ pDst++; ++ pSrc++; ++ } ++ if ((len % 4) != 0) ++ { ++ /* wish that it will never reach here */ ++ memmove(&Value, pSrc, (len % 4)); ++ Value = htonl(Value); ++ memmove(pDst, &Value, (len % 4)); ++ } ++} ++ ++static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) ++{ ++ ULONG i; ++ UCHAR *pDst, *pSrc; ++ ++ pDst = dst; ++ pSrc = src; ++ ++ for (i = 0; i < (len/2); i++) ++ { ++ memmove(pDst, pSrc, 2); ++ *((USHORT *)pDst) = htons(*((USHORT *)pDst)); ++ pDst+=2; ++ pSrc+=2; ++ } ++ ++ if ((len % 2) != 0) ++ { ++ memmove(pDst, pSrc, 1); ++ } ++} ++ ++static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len) ++{ ++ UINT32 i, Value; ++ UINT32 *pDst, *pSrc; ++ ++ pDst = (UINT32 *) dst; ++ pSrc = (UINT32 *) src; ++ ++ for (i = 0 ; i < (len/4); i++) ++ { ++ RTMP_IO_READ32(pAd, (ULONG)pSrc, &Value); ++ Value = htonl(Value); ++ memmove(pDst, &Value, 4); ++ pDst++; ++ pSrc++; ++ } ++ return; ++} ++ ++// TODO: ++#if 0 ++/* These work only when RALINK_ATE is defined */ ++INT Set_TxStart_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG value = simple_strtol(arg, 0, 10); ++ UCHAR buffer[26] = {0x88, 0x02, 0x2c, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00, 0x55, 0x44, 0x33, 0x22, 0x11, 0xc0, 0x22, 0x00, 0x00}; ++ POS_COOKIE pObj; ++ ++ if (pAd->ate.TxStatus != 0) ++ return FALSE; ++ ++ pAd->ate.TxInfo = 0x04000000; ++ bzero(&pAd->ate.TxWI, sizeof(TXWI_STRUC)); ++ pAd->ate.TxWI.PHYMODE = 0;// MODE_CCK ++ pAd->ate.TxWI.MPDUtotalByteCount = 1226; ++ pAd->ate.TxWI.MCS = 3; ++ //pAd->ate.Mode = ATE_START; ++ pAd->ate.Mode |= ATE_TXFRAME; ++ pAd->ate.TxCount = value; ++ pAd->ate.QID = 0; ++ pAd->ate.HLen = 26; ++ pAd->ate.PLen = 0; ++ pAd->ate.DLen = 1200; ++ memcpy(pAd->ate.Header, buffer, 26); ++ pAd->ate.bQATxStart = TRUE; ++ //pObj = (POS_COOKIE) pAd->OS_Cookie; ++ //tasklet_hi_schedule(&pObj->AteTxTask); ++ return TRUE; ++} ++#endif /* end of #if 0 */ ++ ++INT Set_TxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Set_TxStop_Proc\n")); ++ ++ if (Set_ATE_Proc(pAd, "TXSTOP")) ++ { ++ return TRUE; ++} ++ else ++ { ++ return FALSE; ++ } ++} ++ ++INT Set_RxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Set_RxStop_Proc\n")); ++ ++ if (Set_ATE_Proc(pAd, "RXSTOP")) ++ { ++ return TRUE; ++} ++ else ++ { ++ return FALSE; ++ } ++} ++ ++#if 0 ++INT Set_EEWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT offset = 0, value; ++ PUCHAR p2 = arg; ++ ++ while((*p2 != ':') && (*p2 != '\0')) ++ { ++ p2++; ++ } ++ ++ if (*p2 == ':') ++ { ++ A2Hex(offset, arg); ++ A2Hex(value, p2+ 1); ++ } ++ else ++ { ++ A2Hex(value, arg); ++ } ++ ++ if (offset >= EEPROM_SIZE) ++ { ++ ate_print("Offset can not exceed EEPROM_SIZE( == 0x%04x)\n", EEPROM_SIZE); ++ return FALSE; ++ } ++ ++ RTMP_EEPROM_WRITE16(pAd, offset, value); ++ ++ return TRUE; ++} ++ ++INT Set_BBPRead_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR value = 0, offset; ++ ++ A2Hex(offset, arg); ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); ++ } ++ ++ ate_print("%x\n", value); ++ ++ return TRUE; ++} ++ ++ ++INT Set_BBPWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT offset = 0; ++ PUCHAR p2 = arg; ++ UCHAR value; ++ ++ while((*p2 != ':') && (*p2 != '\0')) ++ { ++ p2++; ++ } ++ ++ if (*p2 == ':') ++ { ++ A2Hex(offset, arg); ++ A2Hex(value, p2+ 1); ++ } ++ else ++ { ++ A2Hex(value, arg); ++ } ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); ++ } ++ else ++ { ++ RTNP_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); ++ } ++ ++ return TRUE; ++} ++ ++INT Set_RFWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ PUCHAR p2, p3, p4; ++ ULONG R1, R2, R3, R4; ++ ++ p2 = arg; ++ ++ while((*p2 != ':') && (*p2 != '\0')) ++ { ++ p2++; ++ } ++ ++ if (*p2 != ':') ++ return FALSE; ++ ++ p3 = p2 + 1; ++ ++ while((*p3 != ':') && (*p3 != '\0')) ++ { ++ p3++; ++ } ++ ++ if (*p3 != ':') ++ return FALSE; ++ ++ p4 = p3 + 1; ++ ++ while((*p4 != ':') && (*p4 != '\0')) ++ { ++ p4++; ++ } ++ ++ if (*p4 != ':') ++ return FALSE; ++ ++ ++ A2Hex(R1, arg); ++ A2Hex(R2, p2 + 1); ++ A2Hex(R3, p3 + 1); ++ A2Hex(R4, p4 + 1); ++ ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ RTMP_RF_IO_WRITE32(pAd, R4); ++ ++ return TRUE; ++} ++#endif // end of #if 0 // ++#endif // RALINK_28xx_QA // ++ ++#endif // RALINK_ATE // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt_ate.h +@@ -0,0 +1,353 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __ATE_H__ ++#define __ATE_H__ ++ ++#ifndef UCOS ++#define ate_print printk ++#define ATEDBGPRINT DBGPRINT ++#ifdef RT2860 ++#define EEPROM_SIZE 0x200 ++#ifdef CONFIG_STA_SUPPORT ++#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2860STA/e2p.bin" ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2860 // ++ ++#else // !UCOS // ++#define fATE_LOAD_EEPROM 0x0C43 ++#ifdef CONFIG_PRINTK ++extern INT ConsoleResponse(IN PUCHAR buff); ++extern int (*remote_display)(char *); ++extern void puts (const char *s); ++ ++/* specificly defined to redirect and show ate-related messages to host. */ ++/* Try to define ate_print as a macro. */ ++#define ate_print(fmt, args...) \ ++do{ int (*org_remote_display)(char *) = NULL; \ ++ org_remote_display = remote_display;\ ++ /* Save original "remote_display" */\ ++ remote_display = (int (*)(char *))ConsoleResponse; \ ++ printk(fmt, ## args); \ ++ /* Restore the remote_display function pointer */ \ ++ remote_display = org_remote_display; }while(0) ++ ++#define ATEDBGPRINT(Level, Fmt) \ ++{ \ ++ if ((Level) <= RTDebugLevel) \ ++ { \ ++ ate_print Fmt; \ ++ } \ ++} ++#endif // CONFIG_PRINTK // ++#endif // !UCOS // ++ ++#define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) ++ ++/* RT2880_iNIC will define "RT2860". */ ++#ifdef RT2860 ++#define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) \ ++{ \ ++ BBP_CSR_CFG_STRUC BbpCsr; \ ++ int i, k; \ ++ for (i=0; iBbpWriteLatch[_I]; \ ++ } \ ++} ++ ++#define ATE_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) \ ++{ \ ++ BBP_CSR_CFG_STRUC BbpCsr; \ ++ int BusyCnt; \ ++ for (BusyCnt=0; BusyCntBbpWriteLatch[_I] = _V; \ ++ break; \ ++ } \ ++ if (BusyCnt == MAX_BUSY_COUNT) \ ++ { \ ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("BBP write R%d fail\n", _I)); \ ++ } \ ++} ++#endif // RT2860 // ++ ++/* RT2880_iNIC will define RT2860. */ ++#ifdef RT2860 ++#define EEPROM_SIZE 0x200 ++/* iNIC has its own EEPROM_BIN_FILE_NAME */ ++#ifndef UCOS ++#ifdef CONFIG_STA_SUPPORT ++#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2860STA/e2p.bin" ++#endif // CONFIG_STA_SUPPORT // ++#endif // !UCOS // ++#endif // RT2860 // ++ ++ ++ ++VOID rt_ee_read_all( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Data); ++ ++ ++VOID rt_ee_write_all( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT *Data); ++ ++INT Set_ATE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_DA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_SA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_BSSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_CHANNEL_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_POWER0_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_POWER1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_RX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_FREQOFFSET_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_BW_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_LENGTH_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_COUNT_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_MCS_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_MODE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_GI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_ATE_RX_FER_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Read_RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Read_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Show_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Help_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++VOID ATE_QA_Statistics( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC p28xxRxD, ++ IN PHEADER_802_11 pHeader); ++ ++VOID RtmpDoAte( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID BubbleSort( ++ IN INT32 n, ++ IN INT32 a[]); ++ ++VOID CalNoiseLevel( ++ IN PRTMP_ADAPTER pAdapter, ++ IN UCHAR channel, ++ OUT INT32 buffer[3][10]); ++ ++BOOLEAN SyncTxRxConfig( ++ IN PRTMP_ADAPTER pAdapter, ++ IN USHORT offset, ++ IN UCHAR value); ++ ++#if 0 ++INT Set_TxStart_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // 0 // ++ ++INT Set_TxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#if 0 ++INT Set_EERead_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_EEWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BBPRead_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BBPWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RFWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // end of #if 0 // ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++VOID ATEAsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ATEAsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ATEDisableAsicProtect( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber); ++ ++VOID ATESampleRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPStationStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPStationStart( ++ IN PRTMP_ADAPTER pAd); ++#endif // CONFIG_STA_SUPPORT // ++#endif // __ATE_H__ // +--- /dev/null ++++ b/drivers/staging/rt2860/rt_config.h +@@ -0,0 +1,101 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt_config.h ++ ++ Abstract: ++ Central header file to maintain all include files for all NDIS ++ miniport driver routines. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ ++*/ ++#ifndef __RT_CONFIG_H__ ++#define __RT_CONFIG_H__ ++ ++#include "rtmp_type.h" ++#ifdef UCOS ++#include "includes.h" ++#include ++#include "rt_ucos.h" ++#endif ++ ++#ifdef LINUX ++#include "rt_linux.h" ++#endif ++#include "rtmp_def.h" ++#include "rt28xx.h" ++ ++#ifdef RT2860 ++#include "rt2860.h" ++#endif // RT2860 // ++ ++ ++#include "oid.h" ++#include "mlme.h" ++#include "wpa.h" ++#include "md5.h" ++#include "rtmp.h" ++#include "ap.h" ++#include "dfs.h" ++#include "chlist.h" ++#include "spectrum.h" ++ ++#ifdef LEAP_SUPPORT ++#include "leap.h" ++#endif // LEAP_SUPPORT // ++ ++#ifdef BLOCK_NET_IF ++#include "netif_block.h" ++#endif // BLOCK_NET_IF // ++ ++#ifdef IGMP_SNOOP_SUPPORT ++#include "igmp_snoop.h" ++#endif // IGMP_SNOOP_SUPPORT // ++ ++#ifdef RALINK_ATE ++#include "rt_ate.h" ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifndef WPA_SUPPLICANT_SUPPORT ++#error "Build for being controlled by NetworkManager or wext, please set HAS_WPA_SUPPLICANT=y and HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y" ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef IKANOS_VX_1X0 ++#include "vr_ikans.h" ++#endif // IKANOS_VX_1X0 // ++ ++#endif // __RT_CONFIG_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt_linux.c +@@ -0,0 +1,1054 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++ULONG RTDebugLevel = RT_DEBUG_ERROR; ++ ++BUILD_TIMER_FUNCTION(MlmePeriodicExec); ++BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); ++BUILD_TIMER_FUNCTION(APSDPeriodicExec); ++BUILD_TIMER_FUNCTION(AsicRfTuningExec); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++BUILD_TIMER_FUNCTION(BeaconTimeout); ++BUILD_TIMER_FUNCTION(ScanTimeout); ++BUILD_TIMER_FUNCTION(AuthTimeout); ++BUILD_TIMER_FUNCTION(AssocTimeout); ++BUILD_TIMER_FUNCTION(ReassocTimeout); ++BUILD_TIMER_FUNCTION(DisassocTimeout); ++BUILD_TIMER_FUNCTION(LinkDownExec); ++#ifdef LEAP_SUPPORT ++BUILD_TIMER_FUNCTION(LeapAuthTimeout); ++#endif ++BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); ++BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); ++#ifdef RT2860 ++BUILD_TIMER_FUNCTION(PsPollWakeExec); ++BUILD_TIMER_FUNCTION(RadioOnExec); ++#endif // RT2860 // ++#ifdef QOS_DLS_SUPPORT ++BUILD_TIMER_FUNCTION(DlsTimeoutAction); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++// for wireless system event message ++char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = { ++ // system status event ++ "had associated successfully", /* IW_ASSOC_EVENT_FLAG */ ++ "had disassociated", /* IW_DISASSOC_EVENT_FLAG */ ++ "had deauthenticated", /* IW_DEAUTH_EVENT_FLAG */ ++ "had been aged-out and disassociated", /* IW_AGEOUT_EVENT_FLAG */ ++ "occurred CounterMeasures attack", /* IW_COUNTER_MEASURES_EVENT_FLAG */ ++ "occurred replay counter different in Key Handshaking", /* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */ ++ "occurred RSNIE different in Key Handshaking", /* IW_RSNIE_DIFF_EVENT_FLAG */ ++ "occurred MIC different in Key Handshaking", /* IW_MIC_DIFF_EVENT_FLAG */ ++ "occurred ICV error in RX", /* IW_ICV_ERROR_EVENT_FLAG */ ++ "occurred MIC error in RX", /* IW_MIC_ERROR_EVENT_FLAG */ ++ "Group Key Handshaking timeout", /* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */ ++ "Pairwise Key Handshaking timeout", /* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */ ++ "RSN IE sanity check failure", /* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */ ++ "set key done in WPA/WPAPSK", /* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */ ++ "set key done in WPA2/WPA2PSK", /* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */ ++ "connects with our wireless client", /* IW_STA_LINKUP_EVENT_FLAG */ ++ "disconnects with our wireless client", /* IW_STA_LINKDOWN_EVENT_FLAG */ ++ "scan completed" /* IW_SCAN_COMPLETED_EVENT_FLAG */ ++ "scan terminate!! Busy!! Enqueue fail!!" /* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */ ++ }; ++ ++// for wireless IDS_spoof_attack event message ++char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = { ++ "detected conflict SSID", /* IW_CONFLICT_SSID_EVENT_FLAG */ ++ "detected spoofed association response", /* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */ ++ "detected spoofed reassociation responses", /* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */ ++ "detected spoofed probe response", /* IW_SPOOF_PROBE_RESP_EVENT_FLAG */ ++ "detected spoofed beacon", /* IW_SPOOF_BEACON_EVENT_FLAG */ ++ "detected spoofed disassociation", /* IW_SPOOF_DISASSOC_EVENT_FLAG */ ++ "detected spoofed authentication", /* IW_SPOOF_AUTH_EVENT_FLAG */ ++ "detected spoofed deauthentication", /* IW_SPOOF_DEAUTH_EVENT_FLAG */ ++ "detected spoofed unknown management frame", /* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */ ++ "detected replay attack" /* IW_REPLAY_ATTACK_EVENT_FLAG */ ++ }; ++ ++// for wireless IDS_flooding_attack event message ++char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = { ++ "detected authentication flooding", /* IW_FLOOD_AUTH_EVENT_FLAG */ ++ "detected association request flooding", /* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */ ++ "detected reassociation request flooding", /* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */ ++ "detected probe request flooding", /* IW_FLOOD_PROBE_REQ_EVENT_FLAG */ ++ "detected disassociation flooding", /* IW_FLOOD_DISASSOC_EVENT_FLAG */ ++ "detected deauthentication flooding", /* IW_FLOOD_DEAUTH_EVENT_FLAG */ ++ "detected 802.1x eap-request flooding" /* IW_FLOOD_EAP_REQ_EVENT_FLAG */ ++ }; ++ ++/* timeout -- ms */ ++VOID RTMP_SetPeriodicTimer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ timeout = ((timeout*HZ) / 1000); ++ pTimer->expires = jiffies + timeout; ++ add_timer(pTimer); ++} ++ ++/* convert NdisMInitializeTimer --> RTMP_OS_Init_Timer */ ++VOID RTMP_OS_Init_Timer( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN TIMER_FUNCTION function, ++ IN PVOID data) ++{ ++ init_timer(pTimer); ++ pTimer->data = (unsigned long)data; ++ pTimer->function = function; ++} ++ ++ ++VOID RTMP_OS_Add_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ if (timer_pending(pTimer)) ++ return; ++ ++ timeout = ((timeout*HZ) / 1000); ++ pTimer->expires = jiffies + timeout; ++ add_timer(pTimer); ++} ++ ++VOID RTMP_OS_Mod_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ timeout = ((timeout*HZ) / 1000); ++ mod_timer(pTimer, jiffies + timeout); ++} ++ ++VOID RTMP_OS_Del_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ OUT BOOLEAN *pCancelled) ++{ ++ if (timer_pending(pTimer)) ++ { ++ *pCancelled = del_timer_sync(pTimer); ++ } ++ else ++ { ++ *pCancelled = TRUE; ++ } ++ ++} ++ ++VOID RTMP_OS_Release_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_ENTRY pEntry) ++{ ++ //RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); ++} ++ ++// Unify all delay routine by using udelay ++VOID RTMPusecDelay( ++ IN ULONG usec) ++{ ++ ULONG i; ++ ++ for (i = 0; i < (usec / 50); i++) ++ udelay(50); ++ ++ if (usec % 50) ++ udelay(usec % 50); ++} ++ ++void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time) ++{ ++ time->u.LowPart = jiffies; ++} ++ ++// pAd MUST allow to be NULL ++NDIS_STATUS os_alloc_mem( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR *mem, ++ IN ULONG size) ++{ ++ *mem = (PUCHAR) kmalloc(size, GFP_ATOMIC); ++ if (*mem) ++ return (NDIS_STATUS_SUCCESS); ++ else ++ return (NDIS_STATUS_FAILURE); ++} ++ ++// pAd MUST allow to be NULL ++NDIS_STATUS os_free_mem( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mem) ++{ ++ ++ ASSERT(mem); ++ kfree(mem); ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++ ++PNDIS_PACKET RTMP_AllocateFragPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length) ++{ ++ struct sk_buff *pkt; ++ ++ pkt = dev_alloc_skb(Length); ++ ++ if (pkt == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate frag rx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) ++ { ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++PNDIS_PACKET RTMP_AllocateTxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress) ++{ ++ struct sk_buff *pkt; ++ ++ pkt = dev_alloc_skb(Length); ++ ++ if (pkt == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate tx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) ++ { ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ *VirtualAddress = (PVOID) pkt->data; ++ } ++ else ++ { ++ *VirtualAddress = (PVOID) NULL; ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++VOID build_tx_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pFrame, ++ IN ULONG FrameLen) ++{ ++ ++ struct sk_buff *pTxPkt; ++ ++ ASSERT(pPacket); ++ pTxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen); ++} ++ ++VOID RTMPFreeAdapter( ++ IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE os_cookie; ++ int index; ++ ++ os_cookie=(POS_COOKIE)pAd->OS_Cookie; ++ ++ kfree(pAd->BeaconBuf); ++ ++ ++ NdisFreeSpinLock(&pAd->MgmtRingLock); ++ ++#ifdef RT2860 ++ NdisFreeSpinLock(&pAd->RxRingLock); ++#endif // RT2860 // ++ ++ for (index =0 ; index < NUM_OF_TX_RING; index++) ++ { ++ NdisFreeSpinLock(&pAd->TxSwQueueLock[index]); ++ NdisFreeSpinLock(&pAd->DeQueueLock[index]); ++ pAd->DeQueueRunning[index] = FALSE; ++ } ++ ++ NdisFreeSpinLock(&pAd->irq_lock); ++ ++ vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); ++ kfree(os_cookie); ++} ++ ++BOOLEAN OS_Need_Clone_Packet(void) ++{ ++ return (FALSE); ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ clone an input NDIS PACKET to another one. The new internally created NDIS PACKET ++ must have only one NDIS BUFFER ++ return - byte copied. 0 means can't create NDIS PACKET ++ NOTE: internally created NDIS_PACKET should be destroyed by RTMPFreeNdisPacket ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU. ++ *pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet. ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPCloneNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN pInsAMSDUHdr, ++ IN PNDIS_PACKET pInPacket, ++ OUT PNDIS_PACKET *ppOutPacket) ++{ ++ ++ struct sk_buff *pkt; ++ ++ ASSERT(pInPacket); ++ ASSERT(ppOutPacket); ++ ++ // 1. Allocate a packet ++ pkt = dev_alloc_skb(2048); ++ ++ if (pkt == NULL) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ skb_put(pkt, GET_OS_PKT_LEN(pInPacket)); ++ NdisMoveMemory(pkt->data, GET_OS_PKT_DATAPTR(pInPacket), GET_OS_PKT_LEN(pInPacket)); ++ *ppOutPacket = OSPKT_TO_RTPKT(pkt); ++ ++ ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ ++ printk("###Clone###\n"); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++// the allocated NDIS PACKET must be freed via RTMPFreeNdisPacket() ++NDIS_STATUS RTMPAllocateNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ OUT PNDIS_PACKET *ppPacket, ++ IN PUCHAR pHeader, ++ IN UINT HeaderLen, ++ IN PUCHAR pData, ++ IN UINT DataLen) ++{ ++ PNDIS_PACKET pPacket; ++ ASSERT(pData); ++ ASSERT(DataLen); ++ ++ // 1. Allocate a packet ++ pPacket = (PNDIS_PACKET *) dev_alloc_skb(HeaderLen + DataLen + TXPADDING_SIZE); ++ if (pPacket == NULL) ++ { ++ *ppPacket = NULL; ++#ifdef DEBUG ++ printk("RTMPAllocateNdisPacket Fail\n\n"); ++#endif ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // 2. clone the frame content ++ if (HeaderLen > 0) ++ NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket), pHeader, HeaderLen); ++ if (DataLen > 0) ++ NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket) + HeaderLen, pData, DataLen); ++ ++ // 3. update length of packet ++ skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen); ++ ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket)); ++ *ppPacket = pPacket; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ Description: ++ This routine frees a miniport internally allocated NDIS_PACKET and its ++ corresponding NDIS_BUFFER and allocated memory. ++ ======================================================================== ++*/ ++VOID RTMPFreeNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ dev_kfree_skb_any(RTPKT_TO_OSPKT(pPacket)); ++} ++ ++ ++// IRQL = DISPATCH_LEVEL ++// NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same ++// scatter gather buffer ++NDIS_STATUS Sniff2BytesFromNdisBuffer( ++ IN PNDIS_BUFFER pFirstBuffer, ++ IN UCHAR DesiredOffset, ++ OUT PUCHAR pByte0, ++ OUT PUCHAR pByte1) ++{ ++ *pByte0 = *(PUCHAR)(pFirstBuffer + DesiredOffset); ++ *pByte1 = *(PUCHAR)(pFirstBuffer + DesiredOffset + 1); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++void RTMP_QueryPacketInfo( ++ IN PNDIS_PACKET pPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen) ++{ ++ pPacketInfo->BufferCount = 1; ++ pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); ++ pPacketInfo->PhysicalBufferCount = 1; ++ pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); ++ ++ *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ *pSrcBufLen = GET_OS_PKT_LEN(pPacket); ++} ++ ++void RTMP_QueryNextPacketInfo( ++ IN PNDIS_PACKET *ppPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen) ++{ ++ PNDIS_PACKET pPacket = NULL; ++ ++ if (*ppPacket) ++ pPacket = GET_OS_PKT_NEXT(*ppPacket); ++ ++ if (pPacket) ++ { ++ pPacketInfo->BufferCount = 1; ++ pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); ++ pPacketInfo->PhysicalBufferCount = 1; ++ pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); ++ ++ *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ *pSrcBufLen = GET_OS_PKT_LEN(pPacket); ++ *ppPacket = GET_OS_PKT_NEXT(pPacket); ++ } ++ else ++ { ++ pPacketInfo->BufferCount = 0; ++ pPacketInfo->pFirstBuffer = NULL; ++ pPacketInfo->PhysicalBufferCount = 0; ++ pPacketInfo->TotalPacketLength = 0; ++ ++ *pSrcBufVA = NULL; ++ *pSrcBufLen = 0; ++ *ppPacket = NULL; ++ } ++} ++ ++// not yet support MBSS ++PNET_DEV get_netdev_from_bssid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNET_DEV dev_p = NULL; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ dev_p = pAd->net_dev; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ASSERT(dev_p); ++ return dev_p; /* return one of MBSS */ ++} ++ ++PNDIS_PACKET DuplicatePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *skb; ++ PNDIS_PACKET pRetPacket = NULL; ++ USHORT DataSize; ++ UCHAR *pData; ++ ++ DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); ++ pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); ++ ++ ++ skb = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG); ++ if (skb) ++ { ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pRetPacket = OSPKT_TO_RTPKT(skb); ++ } ++ ++ return pRetPacket; ++ ++} ++ ++PNDIS_PACKET duplicate_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *skb; ++ PNDIS_PACKET pPacket = NULL; ++ ++ ++ if ((skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != NULL) ++ { ++ skb_reserve(skb, 2); ++ NdisMoveMemory(skb->tail, pHeader802_3, HdrLen); ++ skb_put(skb, HdrLen); ++ NdisMoveMemory(skb->tail, pData, DataSize); ++ skb_put(skb, DataSize); ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pPacket = OSPKT_TO_RTPKT(skb); ++ } ++ ++ return pPacket; ++} ++ ++ ++#define TKIP_TX_MIC_SIZE 8 ++PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ struct sk_buff *skb, *newskb; ++ ++ ++ skb = RTPKT_TO_OSPKT(pPacket); ++ if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE) ++ { ++ // alloc a new skb and copy the packet ++ newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); ++ dev_kfree_skb_any(skb); ++ if (newskb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC for packet failed!, dropping packet!\n")); ++ return NULL; ++ } ++ skb = newskb; ++ } ++ ++ return OSPKT_TO_RTPKT(skb); ++} ++ ++ ++ ++ ++PNDIS_PACKET ClonePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ struct sk_buff *pRxPkt; ++ struct sk_buff *pClonedPkt; ++ ++ ASSERT(pPacket); ++ pRxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ // clone the packet ++ pClonedPkt = skb_clone(pRxPkt, MEM_ALLOC_FLAG); ++ ++ if (pClonedPkt) ++ { ++ // set the correct dataptr and data len ++ pClonedPkt->dev = pRxPkt->dev; ++ pClonedPkt->data = pData; ++ pClonedPkt->len = DataSize; ++ pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len; ++ ASSERT(DataSize < 1530); ++ } ++ return pClonedPkt; ++} ++ ++// ++// change OS packet DataPtr and DataLen ++// ++void update_os_packet_info( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *pOSPkt; ++ ++ ASSERT(pRxBlk->pRxPacket); ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pOSPkt->data = pRxBlk->pData; ++ pOSPkt->len = pRxBlk->DataSize; ++ pOSPkt->tail = pOSPkt->data + pOSPkt->len; ++} ++ ++ ++void wlan_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN PUCHAR pHeader802_3, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *pOSPkt; ++ ++ ASSERT(pRxBlk->pRxPacket); ++ ASSERT(pHeader802_3); ++ ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pOSPkt->data = pRxBlk->pData; ++ pOSPkt->len = pRxBlk->DataSize; ++ pOSPkt->tail = pOSPkt->data + pOSPkt->len; ++ ++ // ++ // copy 802.3 header ++ // ++ // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ ++void announce_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ ++ struct sk_buff *pRxPkt; ++ ++ ASSERT(pPacket); ++ ++ pRxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ /* Push up the protocol stack */ ++#ifdef IKANOS_VX_1X0 ++ IKANOS_DataFrameRx(pAd, pRxPkt->dev, pRxPkt, pRxPkt->len); ++#else ++ pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev); ++ ++ netif_rx(pRxPkt); ++#endif // IKANOS_VX_1X0 // ++} ++ ++ ++PRTMP_SCATTER_GATHER_LIST ++rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg) ++{ ++ sg->NumberOfElements = 1; ++ sg->Elements[0].Address = GET_OS_PKT_DATAPTR(pPacket); ++ sg->Elements[0].Length = GET_OS_PKT_LEN(pPacket); ++ return (sg); ++} ++ ++void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) ++{ ++ unsigned char *pt; ++ int x; ++ ++ if (RTDebugLevel < RT_DEBUG_TRACE) ++ return; ++ ++ pt = pSrcBufVA; ++ printk("%s: %p, len = %d\n",str, pSrcBufVA, SrcBufLen); ++ for (x=0; x= 15 ++ ++ union iwreq_data wrqu; ++ PUCHAR pBuf = NULL, pBufPtr = NULL; ++ USHORT event, type, BufLen; ++ UCHAR event_table_len = 0; ++ ++ type = Event_flag & 0xFF00; ++ event = Event_flag & 0x00FF; ++ ++ switch (type) ++ { ++ case IW_SYS_EVENT_FLAG_START: ++ event_table_len = IW_SYS_EVENT_TYPE_NUM; ++ break; ++ ++ case IW_SPOOF_EVENT_FLAG_START: ++ event_table_len = IW_SPOOF_EVENT_TYPE_NUM; ++ break; ++ ++ case IW_FLOOD_EVENT_FLAG_START: ++ event_table_len = IW_FLOOD_EVENT_TYPE_NUM; ++ break; ++ } ++ ++ if (event_table_len == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type)); ++ return; ++ } ++ ++ if (event >= event_table_len) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event)); ++ return; ++ } ++ ++ //Allocate memory and copy the msg. ++ if((pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC)) != NULL) ++ { ++ //Prepare the payload ++ memset(pBuf, 0, IW_CUSTOM_MAX_LEN); ++ ++ pBufPtr = pBuf; ++ ++ if (pAddr) ++ pBufPtr += sprintf(pBufPtr, "(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ", PRINT_MAC(pAddr)); ++ else if (BssIdx < MAX_MBSSID_NUM) ++ pBufPtr += sprintf(pBufPtr, "(RT2860) BSS(ra%d) ", BssIdx); ++ else ++ pBufPtr += sprintf(pBufPtr, "(RT2860) "); ++ ++ if (type == IW_SYS_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s", pWirelessSysEventText[event]); ++ else if (type == IW_SPOOF_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s (RSSI=%d)", pWirelessSpoofEventText[event], Rssi); ++ else if (type == IW_FLOOD_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s", pWirelessFloodEventText[event]); ++ else ++ pBufPtr += sprintf(pBufPtr, "%s", "unknown event"); ++ ++ pBufPtr[pBufPtr - pBuf] = '\0'; ++ BufLen = pBufPtr - pBuf; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = Event_flag; ++ wrqu.data.length = BufLen; ++ ++ //send wireless event ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf); ++ ++ //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf)); ++ ++ kfree(pBuf); ++ } ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__)); ++#else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__)); ++#endif /* WIRELESS_EXT >= 15 */ ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++void send_monitor_packets( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ struct sk_buff *pOSPkt; ++ wlan_ng_prism2_header *ph; ++ int rate_index = 0; ++ USHORT header_len = 0; ++ UCHAR temp_header[40] = {0}; ++ ++ u_int32_t ralinkrate[256] = {2,4,11,22, 12,18,24,36,48,72,96, 108, 109, 110, 111, 112, 13, 26, 39, 52,78,104, 117, 130, 26, 52, 78,104, 156, 208, 234, 260, 27, 54,81,108,162, 216, 243, 270, // Last 38 ++ 54, 108, 162, 216, 324, 432, 486, 540, 14, 29, 43, 57, 87, 115, 130, 144, 29, 59,87,115, 173, 230,260, 288, 30, 60,90,120,180,240,270,300,60,120,180,240,360,480,540,600, 0,1,2,3,4,5,6,7,8,9,10, ++ 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80}; ++ ++ ++ ASSERT(pRxBlk->pRxPacket); ++ if (pRxBlk->DataSize < 10) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize)); ++ goto err_free_sk_buff; ++ } ++ ++ if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); ++ goto err_free_sk_buff; ++ } ++ ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ pOSPkt->dev = get_netdev_from_bssid(pAd, BSS0); ++ if (pRxBlk->pHeader->FC.Type == BTYPE_DATA) ++ { ++ pRxBlk->DataSize -= LENGTH_802_11; ++ if ((pRxBlk->pHeader->FC.ToDs == 1) && ++ (pRxBlk->pHeader->FC.FrDs == 1)) ++ header_len = LENGTH_802_11_WITH_ADDR4; ++ else ++ header_len = LENGTH_802_11; ++ ++ // QOS ++ if (pRxBlk->pHeader->FC.SubType & 0x08) ++ { ++ header_len += 2; ++ // Data skip QOS contorl field ++ pRxBlk->DataSize -=2; ++ } ++ ++ // Order bit: A-Ralink or HTC+ ++ if (pRxBlk->pHeader->FC.Order) ++ { ++ header_len += 4; ++ // Data skip HTC contorl field ++ pRxBlk->DataSize -= 4; ++ } ++ ++ // Copy Header ++ if (header_len <= 40) ++ NdisMoveMemory(temp_header, pRxBlk->pData, header_len); ++ ++ // skip HW padding ++ if (pRxBlk->RxD.L2PAD) ++ pRxBlk->pData += (header_len + 2); ++ else ++ pRxBlk->pData += header_len; ++ } //end if ++ ++ ++ if (pRxBlk->DataSize < pOSPkt->len) { ++ skb_trim(pOSPkt,pRxBlk->DataSize); ++ } else { ++ skb_put(pOSPkt,(pRxBlk->DataSize - pOSPkt->len)); ++ } //end if ++ ++ if ((pRxBlk->pData - pOSPkt->data) > 0) { ++ skb_put(pOSPkt,(pRxBlk->pData - pOSPkt->data)); ++ skb_pull(pOSPkt,(pRxBlk->pData - pOSPkt->data)); ++ } //end if ++ ++ if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) { ++ if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__)); ++ goto err_free_sk_buff; ++ } //end if ++ } //end if ++ ++ if (header_len > 0) ++ NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header, header_len); ++ ++ ph = (wlan_ng_prism2_header *) skb_push(pOSPkt, sizeof(wlan_ng_prism2_header)); ++ NdisZeroMemory(ph, sizeof(wlan_ng_prism2_header)); ++ ++ ph->msgcode = DIDmsg_lnxind_wlansniffrm; ++ ph->msglen = sizeof(wlan_ng_prism2_header); ++ strcpy(ph->devname, pAd->net_dev->name); ++ ++ ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; ++ ph->hosttime.status = 0; ++ ph->hosttime.len = 4; ++ ph->hosttime.data = jiffies; ++ ++ ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; ++ ph->mactime.status = 0; ++ ph->mactime.len = 0; ++ ph->mactime.data = 0; ++ ++ ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; ++ ph->istx.status = 0; ++ ph->istx.len = 0; ++ ph->istx.data = 0; ++ ++ ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; ++ ph->channel.status = 0; ++ ph->channel.len = 4; ++ ++ ph->channel.data = (u_int32_t)pAd->CommonCfg.Channel; ++ ++ ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; ++ ph->rssi.status = 0; ++ ph->rssi.len = 4; ++ ph->rssi.data = (u_int32_t)RTMPMaxRssi(pAd, ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI0, RSSI_0), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI1, RSSI_1), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2, RSSI_2));; ++ ++ ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; ++ ph->signal.status = 0; ++ ph->signal.len = 4; ++ ph->signal.data = 0; //rssi + noise; ++ ++ ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; ++ ph->noise.status = 0; ++ ph->noise.len = 4; ++ ph->noise.data = 0; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) ++ { ++ rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) ++ rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; ++ else ++ rate_index = (UCHAR)(pRxBlk->pRxWI->MCS); ++ if (rate_index < 0) ++ rate_index = 0; ++ if (rate_index > 255) ++ rate_index = 255; ++ ++ ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; ++ ph->rate.status = 0; ++ ph->rate.len = 4; ++ ph->rate.data = ralinkrate[rate_index]; ++ ++ ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; ++ ph->frmlen.status = 0; ++ ph->frmlen.len = 4; ++ ph->frmlen.data = (u_int32_t)pRxBlk->DataSize; ++ ++ ++ pOSPkt->pkt_type = PACKET_OTHERHOST; ++ pOSPkt->protocol = eth_type_trans(pOSPkt, pOSPkt->dev); ++ pOSPkt->ip_summed = CHECKSUM_NONE; ++ netif_rx(pOSPkt); ++ ++ return; ++ ++err_free_sk_buff: ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) ++{ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ daemonize(pThreadName /*"%s",pAd->net_dev->name*/); ++ ++ allow_signal(SIGTERM); ++ allow_signal(SIGKILL); ++ current->flags |= PF_NOFREEZE; ++#else ++ unsigned long flags; ++ ++ daemonize(); ++ reparent_to_init(); ++ strcpy(current->comm, pThreadName); ++ ++ siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); ++ ++ /* Allow interception of SIGKILL only ++ * Don't allow other signals to interrupt the transmission */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) ++ spin_lock_irqsave(¤t->sigmask_lock, flags); ++ flush_signals(current); ++ recalc_sigpending(current); ++ spin_unlock_irqrestore(¤t->sigmask_lock, flags); ++#endif ++#endif ++ ++ /* signal that we've started the thread */ ++ complete(pNotify); ++ ++} ++ ++void RTMP_IndicateMediaState( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ else ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt_linux.h +@@ -0,0 +1,926 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++/***********************************************************************/ ++/* */ ++/* Program: rt_linux.c */ ++/* Created: 4/21/2006 1:17:38 PM */ ++/* Author: Wu Xi-Kun */ ++/* Comments: `description` */ ++/* */ ++/*---------------------------------------------------------------------*/ ++/* */ ++/* History: */ ++/* Revision 1.1 4/21/2006 1:17:38 PM xsikun */ ++/* Initial revision */ ++/* */ ++/***********************************************************************/ ++ ++#include "rtmp_type.h" ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++ ++// load firmware ++#define __KERNEL_SYSCALLS__ ++#include ++#include ++ ++ ++#define MEM_ALLOC_FLAG (GFP_ATOMIC) //(GFP_DMA | GFP_ATOMIC) ++ ++#ifndef IFNAMSIZ ++#define IFNAMSIZ 16 ++#endif ++ ++//#define CONFIG_CKIP_SUPPORT ++ ++#undef __inline ++#define __inline static inline ++ ++typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_dev); ++ ++// add by kathy ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef RT2860 ++#define STA_PROFILE_PATH "/etc/Wireless/RT2860STA/RT2860STA.dat" ++#define STA_RTMP_FIRMWARE_FILE_NAME "/etc/Wireless/RT2860STA/RT2860STA.bin" ++#define STA_NIC_DEVICE_NAME "RT2860STA" ++#define STA_DRIVER_VERSION "1.8.0.0" ++#ifdef MULTIPLE_CARD_SUPPORT ++#define CARD_INFO_PATH "/etc/Wireless/RT2860STA/RT2860STACard.dat" ++#endif // MULTIPLE_CARD_SUPPORT // ++#endif // RT2860 // ++ ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RT2860 ++#ifndef PCI_DEVICE ++#define PCI_DEVICE(vend,dev) \ ++ .vendor = (vend), .device = (dev), \ ++ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID ++#endif // PCI_DEVICE // ++#endif // RT2860 // ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ ++#define RTMP_TIME_AFTER(a,b) \ ++ (typecheck(unsigned long, (unsigned long)a) && \ ++ typecheck(unsigned long, (unsigned long)b) && \ ++ ((long)(b) - (long)(a) < 0)) ++ ++#define RTMP_TIME_AFTER_EQ(a,b) \ ++ (typecheck(unsigned long, (unsigned long)a) && \ ++ typecheck(unsigned long, (unsigned long)b) && \ ++ ((long)(a) - (long)(b) >= 0)) ++#define RTMP_TIME_BEFORE(a,b) RTMP_TIME_AFTER_EQ(b,a) ++#else ++#define RTMP_TIME_AFTER(a,b) time_after(a, b) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define RT_MOD_INC_USE_COUNT() \ ++ if (!try_module_get(THIS_MODULE)) \ ++ { \ ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \ ++ return -1; \ ++ } ++ ++#define RT_MOD_DEC_USE_COUNT() module_put(THIS_MODULE); ++#else ++#define RT_MOD_INC_USE_COUNT() MOD_INC_USE_COUNT; ++#define RT_MOD_DEC_USE_COUNT() MOD_DEC_USE_COUNT; ++#endif ++ ++#define OS_HZ HZ ++ ++#define ETH_LENGTH_OF_ADDRESS 6 ++ ++#define IN ++#define OUT ++ ++#define NDIS_STATUS INT ++#define NDIS_STATUS_SUCCESS 0x00 ++#define NDIS_STATUS_FAILURE 0x01 ++#define NDIS_STATUS_INVALID_DATA 0x02 ++#define NDIS_STATUS_RESOURCES 0x03 ++ ++#define MIN_NET_DEVICE_FOR_AID 0x00 //0x00~0x3f ++#define MIN_NET_DEVICE_FOR_MBSSID 0x00 //0x00,0x10,0x20,0x30 ++#define MIN_NET_DEVICE_FOR_WDS 0x10 //0x40,0x50,0x60,0x70 ++#define MIN_NET_DEVICE_FOR_APCLI 0x20 ++#define MIN_NET_DEVICE_FOR_MESH 0x30 ++#ifdef CONFIG_STA_SUPPORT ++#define MIN_NET_DEVICE_FOR_DLS 0x40 ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define NDIS_PACKET_TYPE_DIRECTED 0 ++#define NDIS_PACKET_TYPE_MULTICAST 1 ++#define NDIS_PACKET_TYPE_BROADCAST 2 ++#define NDIS_PACKET_TYPE_ALL_MULTICAST 3 ++#endif // CONFIG_STA_SUPPORT // ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++typedef struct pid * THREAD_PID; ++#define THREAD_PID_INIT_VALUE NULL ++#define GET_PID(_v) find_get_pid(_v) ++#define GET_PID_NUMBER(_v) pid_nr(_v) ++#define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0) ++#define KILL_THREAD_PID(_A, _B, _C) kill_pid(_A, _B, _C) ++#else ++typedef pid_t THREAD_PID; ++#define THREAD_PID_INIT_VALUE -1 ++#define GET_PID(_v) _v ++#define GET_PID_NUMBER(_v) _v ++#define CHECK_PID_LEGALITY(_pid) if (_pid >= 0) ++#define KILL_THREAD_PID(_A, _B, _C) kill_proc(_A, _B, _C) ++#endif ++ ++struct os_lock { ++ spinlock_t lock; ++ unsigned long flags; ++}; ++ ++ ++struct os_cookie { ++#ifdef RT2860 ++ struct pci_dev *pci_dev; ++ struct pci_dev *parent_pci_dev; ++ dma_addr_t pAd_pa; ++#endif // RT2860 // ++ ++ ++ struct tasklet_struct rx_done_task; ++ struct tasklet_struct mgmt_dma_done_task; ++ struct tasklet_struct ac0_dma_done_task; ++ struct tasklet_struct ac1_dma_done_task; ++ struct tasklet_struct ac2_dma_done_task; ++ struct tasklet_struct ac3_dma_done_task; ++ struct tasklet_struct hcca_dma_done_task; ++ struct tasklet_struct tbtt_task; ++#ifdef RT2860 ++ struct tasklet_struct fifo_statistic_full_task; ++#endif // RT2860 // ++ ++ ++ unsigned long apd_pid; //802.1x daemon pid ++ INT ioctl_if_type; ++ INT ioctl_if; ++}; ++ ++typedef struct _VIRTUAL_ADAPTER ++{ ++ struct net_device *RtmpDev; ++ struct net_device *VirtualDev; ++} VIRTUAL_ADAPTER, PVIRTUAL_ADAPTER; ++ ++#undef ASSERT ++#define ASSERT(x) \ ++{ \ ++ if (!(x)) \ ++ { \ ++ printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ ++ } \ ++} ++ ++typedef struct os_cookie * POS_COOKIE; ++typedef struct pci_dev * PPCI_DEV; ++typedef struct net_device * PNET_DEV; ++typedef void * PNDIS_PACKET; ++typedef char NDIS_PACKET; ++typedef PNDIS_PACKET * PPNDIS_PACKET; ++typedef dma_addr_t NDIS_PHYSICAL_ADDRESS; ++typedef dma_addr_t * PNDIS_PHYSICAL_ADDRESS; ++typedef spinlock_t NDIS_SPIN_LOCK; ++typedef struct timer_list NDIS_MINIPORT_TIMER; ++typedef void * NDIS_HANDLE; ++typedef char * PNDIS_BUFFER; ++ ++ ++ ++void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen); ++ ++dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, int sd_idx, int direction); ++void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int direction); ++ ++ ++//////////////////////////////////////// ++// MOVE TO rtmp.h ? ++///////////////////////////////////////// ++#define PKTSRC_NDIS 0x7f ++#define PKTSRC_DRIVER 0x0f ++#define PRINT_MAC(addr) \ ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ++ ++ ++#define RT2860_PCI_DEVICE_ID 0x0601 ++ ++#ifdef RT2860 ++#define PCI_MAP_SINGLE(_handle, _ptr, _size, _sd_idx, _dir) \ ++ linux_pci_map_single(_handle, _ptr, _size, _sd_idx, _dir) ++ ++#define PCI_UNMAP_SINGLE(_handle, _ptr, _size, _dir) \ ++ linux_pci_unmap_single(_handle, _ptr, _size, _dir) ++ ++#define PCI_ALLOC_CONSISTENT(_pci_dev, _size, _ptr) \ ++ pci_alloc_consistent(_pci_dev, _size, _ptr) ++ ++#define PCI_FREE_CONSISTENT(_pci_dev, _size, _virtual_addr, _physical_addr) \ ++ pci_free_consistent(_pci_dev, _size, _virtual_addr, _physical_addr) ++ ++#define DEV_ALLOC_SKB(_length) \ ++ dev_alloc_skb(_length) ++#endif // RT2860 // ++ ++ ++ ++#define BEACON_FRAME_DMA_CACHE_WBACK(_ptr, _size) \ ++ dma_cache_wback(_ptr, _size) ++ ++ ++////////////////////////////////////////// ++// ++////////////////////////////////////////// ++ ++ ++#define NdisMIndicateStatus(_w, _x, _y, _z) ++ ++ ++typedef struct timer_list RTMP_OS_TIMER; ++ ++ ++ ++typedef struct _RALINK_TIMER_STRUCT { ++ RTMP_OS_TIMER TimerObj; // Ndis Timer object ++ BOOLEAN Valid; // Set to True when call RTMPInitTimer ++ BOOLEAN State; // True if timer cancelled ++ BOOLEAN PeriodicType; // True if timer is periodic timer ++ BOOLEAN Repeat; // True if periodic timer ++ ULONG TimerValue; // Timer value in milliseconds ++ ULONG cookie; // os specific object ++} RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; ++ ++ ++ ++ ++//#define DBG 1 ++ ++// ++// MACRO for debugging information ++// ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++ ++#define DBGPRINT_RAW(Level, Fmt) \ ++{ \ ++ if (Level <= RTDebugLevel) \ ++ { \ ++ printk Fmt; \ ++ } \ ++} ++ ++#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt) ++ ++ ++#define DBGPRINT_ERR(Fmt) \ ++{ \ ++ printk("ERROR!!! "); \ ++ printk Fmt; \ ++} ++ ++#define DBGPRINT_S(Status, Fmt) \ ++{ \ ++ printk Fmt; \ ++} ++ ++ ++#else ++#define DBGPRINT(Level, Fmt) ++#define DBGPRINT_RAW(Level, Fmt) ++#define DBGPRINT_S(Status, Fmt) ++#define DBGPRINT_ERR(Fmt) ++#endif ++ ++ ++// ++// spin_lock enhanced for Nested spin lock ++// ++#define NdisAllocateSpinLock(__lock) \ ++{ \ ++ spin_lock_init((spinlock_t *)(__lock)); \ ++} ++ ++#define NdisFreeSpinLock(lock) \ ++{ \ ++} ++ ++ ++#define RTMP_SEM_LOCK(__lock) \ ++{ \ ++ spin_lock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#define RTMP_SEM_UNLOCK(__lock) \ ++{ \ ++ spin_unlock_bh((spinlock_t *)(__lock)); \ ++} ++ ++// sample, use semaphore lock to replace IRQ lock, 2007/11/15 ++#define RTMP_IRQ_LOCK(__lock, __irqflags) \ ++{ \ ++ __irqflags = 0; \ ++ spin_lock_bh((spinlock_t *)(__lock)); \ ++ pAd->irq_disabled |= 1; \ ++} ++ ++#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ ++{ \ ++ pAd->irq_disabled &= 0; \ ++ spin_unlock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#define RTMP_INT_LOCK(__lock, __irqflags) \ ++{ \ ++ spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ ++} ++ ++#define RTMP_INT_UNLOCK(__lock, __irqflag) \ ++{ \ ++ spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ ++} ++ ++#ifdef RT2860 ++#if defined(INF_TWINPASS) || defined(INF_DANUBE) || defined(IKANOS_VX_1X0) ++//Patch for ASIC turst read/write bug, needs to remove after metel fix ++#define RTMP_IO_READ32(_A, _R, _pV) \ ++{ \ ++ if ((_A)->bPCIclkOff == FALSE) \ ++ { \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + (_R)))); \ ++ (*_pV = SWAP32(*((UINT32 *)(_pV)))); \ ++ } \ ++} ++#define RTMP_IO_READ8(_A, _R, _pV) \ ++{ \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ ++ (*_pV = readb((void *)((_A)->CSRBaseAddress + (_R)))); \ ++} ++#define RTMP_IO_WRITE32(_A, _R, _V) \ ++{ \ ++ if ((_A)->bPCIclkOff == FALSE) \ ++ { \ ++ UINT32 _Val; \ ++ _Val = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0)); \ ++ _Val = SWAP32(_V); \ ++ writel(_Val, (void *)((_A)->CSRBaseAddress + (_R))); \ ++ } \ ++} ++#define RTMP_IO_WRITE8(_A, _R, _V) \ ++{ \ ++ UINT Val; \ ++ Val = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0)); \ ++ writeb((_V), (PUCHAR)((_A)->CSRBaseAddress + (_R))); \ ++} ++#define RTMP_IO_WRITE16(_A, _R, _V) \ ++{ \ ++ UINT Val; \ ++ Val = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0)); \ ++ writew(SWAP16((_V)), (PUSHORT)((_A)->CSRBaseAddress + (_R))); \ ++} ++#else ++//Patch for ASIC turst read/write bug, needs to remove after metel fix ++#define RTMP_IO_READ32(_A, _R, _pV) \ ++{ \ ++ if ((_A)->bPCIclkOff == FALSE) \ ++ { \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + (_R)))); \ ++ } \ ++ else \ ++ *_pV = 0; \ ++} ++#define RTMP_IO_READ8(_A, _R, _pV) \ ++{ \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ ++ (*_pV = readb((void *)((_A)->CSRBaseAddress + (_R)))); \ ++} ++#define RTMP_IO_WRITE32(_A, _R, _V) \ ++{ \ ++ if ((_A)->bPCIclkOff == FALSE) \ ++ { \ ++ UINT Val; \ ++ Val = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0)); \ ++ writel(_V, (void *)((_A)->CSRBaseAddress + (_R))); \ ++ } \ ++} ++#if defined(BRCM_6358) ++#define RTMP_IO_WRITE8(_A, _R, _V) \ ++{ \ ++ ULONG Val; \ ++ UCHAR _i; \ ++ _i = (_R & 0x3); \ ++ Val = readl((void *)((_A)->CSRBaseAddress + (_R - _i))); \ ++ Val = Val & (~(0x000000ff << ((_i)*8))); \ ++ Val = Val | ((ULONG)_V << ((_i)*8)); \ ++ writel((Val), (void *)((_A)->CSRBaseAddress + (_R - _i))); \ ++} ++#else ++#define RTMP_IO_WRITE8(_A, _R, _V) \ ++{ \ ++ UINT Val; \ ++ Val = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0)); \ ++ writeb((_V), (PUCHAR)((_A)->CSRBaseAddress + (_R))); \ ++} ++#endif ++#define RTMP_IO_WRITE16(_A, _R, _V) \ ++{ \ ++ UINT Val; \ ++ Val = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0)); \ ++ writew((_V), (PUSHORT)((_A)->CSRBaseAddress + (_R))); \ ++} ++#endif ++#endif // RT2860 // ++ ++ ++#ifndef wait_event_interruptible_timeout ++#define __wait_event_interruptible_timeout(wq, condition, ret) \ ++do { \ ++ wait_queue_t __wait; \ ++ init_waitqueue_entry(&__wait, current); \ ++ add_wait_queue(&wq, &__wait); \ ++ for (;;) { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (!signal_pending(current)) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ continue; \ ++ } \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&wq, &__wait); \ ++} while (0) ++ ++#define wait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!(condition)) \ ++ __wait_event_interruptible_timeout(wq, condition, __ret); \ ++ __ret; \ ++}) ++#endif ++#define ONE_TICK 1 ++#define OS_WAIT(_time) \ ++{ int _i; \ ++ long _loop = ((_time)/(1000/OS_HZ)) > 0 ? ((_time)/(1000/OS_HZ)) : 1;\ ++ wait_queue_head_t _wait; \ ++ init_waitqueue_head(&_wait); \ ++ for (_i=0; _i<(_loop); _i++) \ ++ wait_event_interruptible_timeout(_wait, 0, ONE_TICK); } ++ ++ ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++typedef void (*TIMER_FUNCTION)(unsigned long); ++ ++#define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), MAC_ADDR_LEN) ++ ++#define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) ++#define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) ++ ++#ifdef RT2860 ++#define BUILD_TIMER_FUNCTION(_func) \ ++void linux_##_func(unsigned long data) \ ++{ \ ++ PRALINK_TIMER_STRUCT pTimer = (PRALINK_TIMER_STRUCT) data; \ ++ \ ++ _func(NULL, (PVOID) pTimer->cookie, NULL, pTimer); \ ++ if (pTimer->Repeat) \ ++ RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); \ ++} ++#endif // RT2860 // ++ ++ ++ ++#define DECLARE_TIMER_FUNCTION(_func) \ ++void linux_##_func(unsigned long data) ++ ++#define GET_TIMER_FUNCTION(_func) \ ++ linux_##_func ++ ++DECLARE_TIMER_FUNCTION(MlmePeriodicExec); ++DECLARE_TIMER_FUNCTION(MlmeRssiReportExec); ++DECLARE_TIMER_FUNCTION(AsicRxAntEvalTimeout); ++DECLARE_TIMER_FUNCTION(APSDPeriodicExec); ++DECLARE_TIMER_FUNCTION(AsicRfTuningExec); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++DECLARE_TIMER_FUNCTION(BeaconTimeout); ++DECLARE_TIMER_FUNCTION(ScanTimeout); ++DECLARE_TIMER_FUNCTION(AuthTimeout); ++DECLARE_TIMER_FUNCTION(AssocTimeout); ++DECLARE_TIMER_FUNCTION(ReassocTimeout); ++DECLARE_TIMER_FUNCTION(DisassocTimeout); ++DECLARE_TIMER_FUNCTION(LinkDownExec); ++#ifdef LEAP_SUPPORT ++DECLARE_TIMER_FUNCTION(LeapAuthTimeout); ++#endif ++DECLARE_TIMER_FUNCTION(StaQuickResponeForRateUpExec); ++DECLARE_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); ++DECLARE_TIMER_FUNCTION(PsPollWakeExec); ++DECLARE_TIMER_FUNCTION(RadioOnExec); ++ ++#ifdef QOS_DLS_SUPPORT ++DECLARE_TIMER_FUNCTION(DlsTimeoutAction); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); ++ ++ ++/* ++ * packet helper ++ * - convert internal rt packet to os packet or ++ * os packet to rt packet ++ */ ++#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) ++#define OSPKT_TO_RTPKT(_p) ((PNDIS_PACKET)(_p)) ++ ++#define GET_OS_PKT_DATAPTR(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->data) ++ ++#define GET_OS_PKT_LEN(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->len) ++ ++#define GET_OS_PKT_DATATAIL(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->tail) ++ ++#define GET_OS_PKT_HEAD(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->head) ++ ++#define GET_OS_PKT_END(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->end) ++ ++#define GET_OS_PKT_NETDEV(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->dev) ++ ++#define GET_OS_PKT_TYPE(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)) ++ ++#define GET_OS_PKT_NEXT(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->next) ++ ++ ++#define OS_NTOHS(_Val) \ ++ (ntohs(_Val)) ++#define OS_HTONS(_Val) \ ++ (htons(_Val)) ++#define OS_NTOHL(_Val) \ ++ (ntohl(_Val)) ++#define OS_HTONL(_Val) \ ++ (htonl(_Val)) ++ ++/* statistics counter */ ++#define STATS_INC_RX_PACKETS(_pAd, _dev) ++#define STATS_INC_TX_PACKETS(_pAd, _dev) ++ ++#define STATS_INC_RX_BYTESS(_pAd, _dev, len) ++#define STATS_INC_TX_BYTESS(_pAd, _dev, len) ++ ++#define STATS_INC_RX_ERRORS(_pAd, _dev) ++#define STATS_INC_TX_ERRORS(_pAd, _dev) ++ ++#define STATS_INC_RX_DROPPED(_pAd, _dev) ++#define STATS_INC_TX_DROPPED(_pAd, _dev) ++ ++ ++#define CB_OFF 10 ++ ++ ++// check DDK NDIS_PACKET data structure and find out only MiniportReservedEx[0..7] can be used by our driver without ++// ambiguity. Fields after pPacket->MiniportReservedEx[8] may be used by other wrapper layer thus crashes the driver ++// ++ ++// User Priority ++#define RTMP_SET_PACKET_UP(_p, _prio) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0] = _prio) ++#define RTMP_GET_PACKET_UP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0]) ++ ++// Fragment # ++#define RTMP_SET_PACKET_FRAGMENTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1] = _num) ++#define RTMP_GET_PACKET_FRAGMENTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1]) ++ ++// 0x0 ~0x7f: TX to AP's own BSS which has the specified AID. if AID>127, set bit 7 in RTMP_SET_PACKET_EMACTAB too. ++//(this value also as MAC(on-chip WCID) table index) ++// 0x80~0xff: TX to a WDS link. b0~6: WDS index ++#define RTMP_SET_PACKET_WCID(_p, _wdsidx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2] = _wdsidx) ++#define RTMP_GET_PACKET_WCID(_p) ((UCHAR)(RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2])) ++ ++// 0xff: PKTSRC_NDIS, others: local TX buffer index. This value affects how to a packet ++#define RTMP_SET_PACKET_SOURCE(_p, _pktsrc) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3] = _pktsrc) ++#define RTMP_GET_PACKET_SOURCE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3]) ++ ++// RTS/CTS-to-self protection method ++#define RTMP_SET_PACKET_RTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4] = _num) ++#define RTMP_GET_PACKET_RTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4]) ++// see RTMP_S(G)ET_PACKET_EMACTAB ++ ++// TX rate index ++#define RTMP_SET_PACKET_TXRATE(_p, _rate) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5] = _rate) ++#define RTMP_GET_PACKET_TXRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5]) ++ ++// From which Interface ++#define RTMP_SET_PACKET_IF(_p, _ifdx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6] = _ifdx) ++#define RTMP_GET_PACKET_IF(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6]) ++#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) RTMP_SET_PACKET_IF((_p), (_bss)) ++#define RTMP_SET_PACKET_NET_DEVICE_WDS(_p, _bss) RTMP_SET_PACKET_IF((_p), ((_bss) + MIN_NET_DEVICE_FOR_WDS)) ++#define RTMP_SET_PACKET_NET_DEVICE_APCLI(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_APCLI)) ++#define RTMP_SET_PACKET_NET_DEVICE_MESH(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_MESH)) ++#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) RTMP_GET_PACKET_IF((_p)) ++#define RTMP_GET_PACKET_NET_DEVICE(_p) RTMP_GET_PACKET_IF((_p)) ++ ++#define RTMP_SET_PACKET_MOREDATA(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7] = _morebit) ++#define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) ++ ++ ++#if 0 ++//#define RTMP_SET_PACKET_DHCP(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) ++//#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) ++#else ++// ++// Sepcific Pakcet Type definition ++// ++#define RTMP_PACKET_SPECIFIC_CB_OFFSET 11 ++ ++#define RTMP_PACKET_SPECIFIC_DHCP 0x01 ++#define RTMP_PACKET_SPECIFIC_EAPOL 0x02 ++#define RTMP_PACKET_SPECIFIC_IPV4 0x04 ++#define RTMP_PACKET_SPECIFIC_WAI 0x08 ++#define RTMP_PACKET_SPECIFIC_VLAN 0x10 ++#define RTMP_PACKET_SPECIFIC_LLCSNAP 0x20 ++ ++//Specific ++#define RTMP_SET_PACKET_SPECIFIC(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) ++ ++//DHCP ++#define RTMP_SET_PACKET_DHCP(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_DHCP); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_DHCP); \ ++ }while(0) ++#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_DHCP) ++ ++//EAPOL ++#define RTMP_SET_PACKET_EAPOL(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_EAPOL); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_EAPOL); \ ++ }while(0) ++#define RTMP_GET_PACKET_EAPOL(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_EAPOL) ++ ++//WAI ++#define RTMP_SET_PACKET_WAI(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_WAI); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_WAI); \ ++ }while(0) ++#define RTMP_GET_PACKET_WAI(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_WAI) ++ ++#define RTMP_GET_PACKET_LOWRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & (RTMP_PACKET_SPECIFIC_EAPOL | RTMP_PACKET_SPECIFIC_DHCP | RTMP_PACKET_SPECIFIC_WAI)) ++ ++//VLAN ++#define RTMP_SET_PACKET_VLAN(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_VLAN); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_VLAN); \ ++ }while(0) ++#define RTMP_GET_PACKET_VLAN(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_VLAN) ++ ++//LLC/SNAP ++#define RTMP_SET_PACKET_LLCSNAP(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_LLCSNAP); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_LLCSNAP); \ ++ }while(0) ++ ++#define RTMP_GET_PACKET_LLCSNAP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_LLCSNAP) ++ ++// IP ++#define RTMP_SET_PACKET_IPV4(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_IPV4); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_IPV4); \ ++ }while(0) ++ ++#define RTMP_GET_PACKET_IPV4(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_IPV4) ++ ++#endif ++ ++ ++// If this flag is set, it indicates that this EAPoL frame MUST be clear. ++#define RTMP_SET_PACKET_CLEAR_EAP_FRAME(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12] = _flg) ++#define RTMP_GET_PACKET_CLEAR_EAP_FRAME(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12]) ++ ++#define RTMP_SET_PACKET_5VT(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22] = _flg) ++#define RTMP_GET_PACKET_5VT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22]) ++ ++#ifdef CONFIG_5VT_ENHANCE ++#define BRIDGE_TAG 0x35564252 // depends on 5VT define in br_input.c ++#endif ++ ++ ++#define NDIS_SET_PACKET_STATUS(_p, _status) ++ ++ ++#define GET_SG_LIST_FROM_PACKET(_p, _sc) \ ++ rt_get_sg_list_from_packet(_p, _sc) ++ ++#define NdisMoveMemory(Destination, Source, Length) memmove(Destination, Source, Length) ++#define NdisZeroMemory(Destination, Length) memset(Destination, 0, Length) ++#define NdisFillMemory(Destination, Length, Fill) memset(Destination, Fill, Length) ++#define NdisEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) ++#define RTMPEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) ++ ++ ++#define RTMP_INC_REF(_A) 0 ++#define RTMP_DEC_REF(_A) 0 ++#define RTMP_GET_REF(_A) 0 ++ ++ ++ ++/* ++ * ULONG ++ * RTMP_GetPhysicalAddressLow( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ */ ++#define RTMP_GetPhysicalAddressLow(PhysicalAddress) (PhysicalAddress) ++ ++/* ++ * ULONG ++ * RTMP_GetPhysicalAddressHigh( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ */ ++#define RTMP_GetPhysicalAddressHigh(PhysicalAddress) (0) ++ ++/* ++ * VOID ++ * RTMP_SetPhysicalAddressLow( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, ++ * IN ULONG Value); ++ */ ++#define RTMP_SetPhysicalAddressLow(PhysicalAddress, Value) \ ++ PhysicalAddress = Value; ++ ++/* ++ * VOID ++ * RTMP_SetPhysicalAddressHigh( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, ++ * IN ULONG Value); ++ */ ++#define RTMP_SetPhysicalAddressHigh(PhysicalAddress, Value) ++ ++ ++//CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); ++#define QUEUE_ENTRY_TO_PACKET(pEntry) \ ++ (PNDIS_PACKET)(pEntry) ++ ++#define PACKET_TO_QUEUE_ENTRY(pPacket) \ ++ (PQUEUE_ENTRY)(pPacket) ++ ++ ++#ifndef CONTAINING_RECORD ++#define CONTAINING_RECORD(address, type, field) \ ++((type *)((PCHAR)(address) - offsetof(type, field))) ++#endif ++ ++ ++#define RELEASE_NDIS_PACKET(_pAd, _pPacket, _Status) \ ++{ \ ++ RTMPFreeNdisPacket(_pAd, _pPacket); \ ++} ++ ++ ++#define SWITCH_PhyAB(_pAA, _pBB) \ ++{ \ ++ ULONG AABasePaHigh; \ ++ ULONG AABasePaLow; \ ++ ULONG BBBasePaHigh; \ ++ ULONG BBBasePaLow; \ ++ BBBasePaHigh = RTMP_GetPhysicalAddressHigh(_pBB); \ ++ BBBasePaLow = RTMP_GetPhysicalAddressLow(_pBB); \ ++ AABasePaHigh = RTMP_GetPhysicalAddressHigh(_pAA); \ ++ AABasePaLow = RTMP_GetPhysicalAddressLow(_pAA); \ ++ RTMP_SetPhysicalAddressHigh(_pAA, BBBasePaHigh); \ ++ RTMP_SetPhysicalAddressLow(_pAA, BBBasePaLow); \ ++ RTMP_SetPhysicalAddressHigh(_pBB, AABasePaHigh); \ ++ RTMP_SetPhysicalAddressLow(_pBB, AABasePaLow); \ ++} ++ ++ ++#define NdisWriteErrorLogEntry(_a, _b, _c, _d) ++#define NdisMAllocateMapRegisters(_a, _b, _c, _d, _e) NDIS_STATUS_SUCCESS ++ ++ ++#define NdisAcquireSpinLock RTMP_SEM_LOCK ++#define NdisReleaseSpinLock RTMP_SEM_UNLOCK ++ ++static inline void NdisGetSystemUpTime(ULONG *time) ++{ ++ *time = jiffies; ++} ++ ++//pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); ++#define QUEUE_ENTRY_TO_PKT(pEntry) \ ++ ((PNDIS_PACKET) (pEntry)) ++ ++int rt28xx_packet_xmit(struct sk_buff *skb); ++ ++ ++ ++void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); ++ ++#ifdef RT2860 ++#if !defined(PCI_CAP_ID_EXP) ++#define PCI_CAP_ID_EXP 0x10 ++#endif ++ ++#if !defined(PCI_EXP_LNKCTL) ++#define PCI_EXP_LNKCTL 0x10 ++#endif ++ ++#if !defined(PCI_CLASS_BRIDGE_PCI) ++#define PCI_CLASS_BRIDGE_PCI 0x0604 ++#endif ++ ++#define PCIBUS_INTEL_VENDOR 0x8086 ++#endif // RT2860 // ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt_main_dev.c +@@ -0,0 +1,1686 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt_main_dev.c ++ ++ Abstract: ++ Create and register network interface. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Sample Mar/21/07 Merge RT2870 and RT2860 drivers. ++*/ ++ ++#include "rt_config.h" ++ ++#define FORTY_MHZ_INTOLERANT_INTERVAL (60*1000) // 1 min ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// record whether the card in the card list is used in the card file ++UINT8 MC_CardUsed[MAX_NUM_OF_MULTIPLE_CARD]; ++// record used card mac address in the card list ++static UINT8 MC_CardMac[MAX_NUM_OF_MULTIPLE_CARD][6]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++UINT32 CW_MAX_IN_BITS; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++/*---------------------------------------------------------------------*/ ++/* Private Variables Used */ ++/*---------------------------------------------------------------------*/ ++//static RALINK_TIMER_STRUCT PeriodicTimer; ++ ++char *mac = ""; // default 00:00:00:00:00:00 ++char *hostname = ""; // default CMPC ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) ++MODULE_PARM (mac, "s"); ++#else ++module_param (mac, charp, 0); ++#endif ++MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); ++ ++ ++/*---------------------------------------------------------------------*/ ++/* Prototypes of Functions Used */ ++/*---------------------------------------------------------------------*/ ++#ifdef DOT11_N_SUPPORT ++extern BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); ++extern void ba_reordering_resource_release(PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); ++ ++#ifdef RT2860 ++extern void init_thread_task(PRTMP_ADAPTER pAd); ++#endif // RT2860 // ++ ++// public function prototype ++INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, ++ IN UINT argc, OUT PRTMP_ADAPTER *ppAd); ++ ++// private function prototype ++static int rt28xx_init(IN struct net_device *net_dev); ++INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev); ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++struct net_device *alloc_netdev( ++ int sizeof_priv, ++ const char *mask, ++ void (*setup)(struct net_device *)); ++#endif // LINUX_VERSION_CODE // ++ ++static void CfgInitHook(PRTMP_ADAPTER pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++extern const struct iw_handler_def rt28xx_iw_handler_def; ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++extern const struct iw_handler_def rt28xx_ap_iw_handler_def; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev); ++#endif ++ ++struct net_device_stats *RT28xx_get_ether_stats( ++ IN struct net_device *net_dev); ++ ++/* ++======================================================================== ++Routine Description: ++ Close raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int MainVirtualIF_close(IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ netif_carrier_off(pAd->net_dev); ++ netif_stop_queue(pAd->net_dev); ++ ++ ++ VIRTUAL_IF_DOWN(pAd); ++ ++ RT_MOD_DEC_USE_COUNT(); ++ ++ return 0; // close ok ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Open raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int MainVirtualIF_open(IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ if (VIRTUAL_IF_UP(pAd) != 0) ++ return -1; ++ ++ // increase MODULE use count ++ RT_MOD_INC_USE_COUNT(); ++ ++ netif_start_queue(net_dev); ++ netif_carrier_on(net_dev); ++ netif_wake_queue(net_dev); ++ ++ return 0; ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Close raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int rt28xx_close(IN PNET_DEV dev) ++{ ++ struct net_device * net_dev = (struct net_device *)dev; ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ BOOLEAN Cancelled = FALSE; ++ UINT32 i = 0; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt28xx_close\n")); ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ ++#ifdef WDS_SUPPORT ++ WdsDown(pAd); ++#endif // WDS_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef RT2860 ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_CLOSE); ++#endif // RT2860 // ++ ++ // If dirver doesn't wake up firmware here, ++ // NICLoadFirmware will hang forever when interface is up again. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AsicForceWakeup(pAd, TRUE); ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ // send DLS-TEAR_DOWN message, ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ UCHAR i; ++ ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ RT28XX_MLME_HANDLER(pAd); ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ if (INFRA_ON(pAd) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ MLME_DISASSOC_REQ_STRUCT DisReq; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ COPY_MAC_ADDR(DisReq.Addr, pAd->CommonCfg.Bssid); ++ DisReq.Reason = REASON_DEAUTH_STA_LEAVING; ++ ++ MsgElem->Machine = ASSOC_STATE_MACHINE; ++ MsgElem->MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAd->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, MsgElem); ++ kfree(MsgElem); ++ ++ RTMPusecDelay(1000); ++ } ++ ++ ++#ifdef CCX_SUPPORT ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &Cancelled); ++#endif ++ ++ RTMPCancelTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, &Cancelled); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ // send wireless event to wpa_supplicant for infroming interface down. ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_INTERFACE_DOWN; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ MlmeRadioOff(pAd); ++#ifdef RT2860 ++ pAd->bPCIclkOff = FALSE; ++#endif // RT2860 // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ ++ for (i = 0 ; i < NUM_OF_TX_RING; i++) ++ { ++ while (pAd->DeQueueRunning[i] == TRUE) ++ { ++ printk("Waiting for TxQueue[%d] done..........\n", i); ++ RTMPusecDelay(1000); ++ } ++ } ++ ++ // Stop Mlme state machine ++ MlmeHalt(pAd); ++ ++ // Close kernel threads or tasklets ++ kill_thread_task(pAd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ MacTableReset(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ MeasureReqTabExit(pAd); ++ TpcReqTabExit(pAd); ++ ++ ++#ifdef RT2860 ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) ++ { ++ NICDisableInterrupt(pAd); ++ } ++ ++ // Disable Rx, register value supposed will remain after reset ++ NICIssueReset(pAd); ++ ++ // Free IRQ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ // Deregister interrupt function ++ RT28XX_IRQ_RELEASE(net_dev) ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ } ++#endif // RT2860 // ++ ++ ++ // Free Ring or USB buffers ++ RTMPFreeTxRxRingMemory(pAd); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ ++#ifdef DOT11_N_SUPPORT ++ // Free BA reorder resource ++ ba_reordering_resource_release(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_START_UP); ++ ++ return 0; // close ok ++} /* End of rt28xx_close */ ++ ++static int rt28xx_init(IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->priv; ++ UINT index; ++ UCHAR TmpPhy; ++ NDIS_STATUS Status; ++ UINT32 MacCsr0 = 0; ++ ++ ++#ifdef DOT11_N_SUPPORT ++ // Allocate BA Reordering memory ++ ba_reordering_resource_init(pAd, MAX_REORDERING_MPDU_NUM); ++#endif // DOT11_N_SUPPORT // ++ ++ // Make sure MAC gets ready. ++ index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); ++ pAd->MACVersion = MacCsr0; ++ ++ if ((pAd->MACVersion != 0x00) && (pAd->MACVersion != 0xFFFFFFFF)) ++ break; ++ ++ RTMPusecDelay(10); ++ } while (index++ < 100); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); ++ ++ // Disable DMA ++ RT28XXDMADisable(pAd); ++ ++ ++ // Load 8051 firmware ++ Status = NICLoadFirmware(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); ++ goto err1; ++ } ++ ++ NICLoadRateSwitchingParams(pAd); ++ ++ // Disable interrupts here which is as soon as possible ++ // This statement should never be true. We might consider to remove it later ++#ifdef RT2860 ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) ++ { ++ NICDisableInterrupt(pAd); ++ } ++#endif // RT2860 // ++ ++ Status = RTMPAllocTxRxRingMemory(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status)); ++ goto err1; ++ } ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ ++ // initialize MLME ++ // ++ ++ Status = MlmeInit(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status)); ++ goto err2; ++ } ++ ++ // Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default ++ // ++ UserCfgInit(pAd); ++ ++ ++ RT28XX_TASK_THREAD_INIT(pAd, Status); ++ if (Status != NDIS_STATUS_SUCCESS) ++ goto err1; ++ ++ CfgInitHook(pAd); ++ ++ ++#ifdef BLOCK_NET_IF ++ initblockQueueTab(pAd); ++#endif // BLOCK_NET_IF // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisAllocateSpinLock(&pAd->MacTabLock); ++#endif // CONFIG_STA_SUPPORT // ++ ++ MeasureReqTabInit(pAd); ++ TpcReqTabInit(pAd); ++ ++ // ++ // Init the hardware, we need to init asic before read registry, otherwise mac register will be reset ++ // ++ Status = NICInitializeAdapter(pAd, TRUE); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n", Status)); ++ if (Status != NDIS_STATUS_SUCCESS) ++ goto err3; ++ } ++ ++ // Read parameters from Config File ++ Status = RTMPReadParametersHook(pAd); ++ ++ printk("1. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICReadRegParameters failed, Status[=0x%08x]\n",Status)); ++ goto err4; ++ } ++ ++ ++ ++ //Init Ba Capability parameters. ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.DesiredHtPhy.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ // UPdata to HT IE ++ pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++#endif // DOT11_N_SUPPORT // ++ ++ printk("2. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ ++ // We should read EEPROM for all cases. rt2860b ++ NICReadEEPROMParameters(pAd, mac); ++ ++ printk("3. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ ++ NICInitAsicFromEEPROM(pAd); //rt2860b ++ ++ // Set PHY to appropriate mode ++ TmpPhy = pAd->CommonCfg.PhyMode; ++ pAd->CommonCfg.PhyMode = 0xff; ++ RTMPSetPhyMode(pAd, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ // No valid channels. ++ if (pAd->ChannelListNum == 0) ++ { ++ printk("Wrong configuration. No valid channel found. Check \"ContryCode\" and \"ChannelGeography\" setting.\n"); ++ goto err4; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ printk("MCS Set = %02x %02x %02x %02x %02x\n", pAd->CommonCfg.HtCapability.MCSSet[0], ++ pAd->CommonCfg.HtCapability.MCSSet[1], pAd->CommonCfg.HtCapability.MCSSet[2], ++ pAd->CommonCfg.HtCapability.MCSSet[3], pAd->CommonCfg.HtCapability.MCSSet[4]); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef IKANOS_VX_1X0 ++ VR_IKANOS_FP_Init(pAd->ApCfg.BssidNum, pAd->PermanentAddress); ++#endif // IKANOS_VX_1X0 // ++ ++ // ++ // Initialize RF register to default value ++ // ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // 8051 firmware require the signal during booting time. ++ AsicSendCommandToMcu(pAd, 0x72, 0xFF, 0x00, 0x00); ++ ++ if (pAd && (Status != NDIS_STATUS_SUCCESS)) ++ { ++ // ++ // Undo everything if it failed ++ // ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ } ++ } ++ else if (pAd) ++ { ++ // Microsoft HCT require driver send a disconnect event after driver initialization. ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event B!\n")); ++ ++ ++ }// end of else ++ ++ ++ DBGPRINT_S(Status, ("<==== RTMPInitialize, Status=%x\n", Status)); ++ ++ return TRUE; ++ ++ ++err4: ++err3: ++ MlmeHalt(pAd); ++err2: ++ RTMPFreeTxRxRingMemory(pAd); ++err1: ++ ++#ifdef DOT11_N_SUPPORT ++ os_free_mem(pAd, pAd->mpdu_blk_pool.mem); // free BA pool ++#endif // DOT11_N_SUPPORT // ++ RT28XX_IRQ_RELEASE(net_dev); ++ ++ // shall not set priv to NULL here because the priv didn't been free yet. ++ //net_dev->priv = 0; ++#ifdef INF_AMAZON_SE ++err0: ++#endif // INF_AMAZON_SE // ++ printk("!!! %s Initialized fail !!!\n", RT28xx_CHIP_NAME); ++ return FALSE; ++} /* End of rt28xx_init */ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Open raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++======================================================================== ++*/ ++int rt28xx_open(IN PNET_DEV dev) ++{ ++ struct net_device * net_dev = (struct net_device *)dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->priv; ++ int retval = 0; ++ POS_COOKIE pObj; ++ ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -1; ++ } ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ CW_MAX_IN_BITS = 6; ++ } ++ else if (pAd->OpMode == OPMODE_STA) ++ { ++ CW_MAX_IN_BITS = 10; ++ } ++ ++#if WIRELESS_EXT >= 12 ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ if (pAd->OpMode == OPMODE_AP) ++ net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_ap_iw_handler_def; ++ else if (pAd->OpMode == OPMODE_STA) ++ net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_iw_handler_def; ++ } ++#endif // WIRELESS_EXT >= 12 // ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef RT2860 ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // If dirver doesn't wake up firmware here, ++ // NICLoadFirmware will hang forever when interface is up again. ++ // RT2860 PCI ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) && ++ OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ AsicForceWakeup(pAd, TRUE); ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ } ++ } ++#endif // RT2860 // ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Init ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ // reset Adapter flags ++ RTMP_CLEAR_FLAGS(pAd); ++ ++ // Request interrupt service routine for PCI device ++ // register the interrupt routine with the os ++ RT28XX_IRQ_REQUEST(net_dev); ++ ++ ++ // Init BssTab & ChannelInfo tabbles for auto channel select. ++ ++ ++ // Chip & other init ++ if (rt28xx_init(net_dev) == FALSE) ++ goto err; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NdisZeroMemory(pAd->StaCfg.dev_name, 16); ++ NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Set up the Mac address ++ NdisMoveMemory(net_dev->dev_addr, (void *) pAd->CurrentAddress, 6); ++ ++ // Init IRQ parameters ++ RT28XX_IRQ_INIT(pAd); ++ ++ // Various AP function init ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ // send wireless event to wpa_supplicant for infroming interface down. ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_INTERFACE_UP; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Enable Interrupt ++ RT28XX_IRQ_ENABLE(pAd); ++ ++ // Now Enable RxTx ++ RTMPEnableRxTx(pAd); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP); ++ ++ { ++ UINT32 reg = 0; ++ RTMP_IO_READ32(pAd, 0x1300, ®); // clear garbage interrupts ++ printk("0x1300 = %08x\n", reg); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef RT2860 ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMPInitPCIeLinkCtrlValue(pAd); ++#endif // RT2860 // ++#endif // CONFIG_STA_SUPPORT // ++ ++ return (retval); ++ ++err: ++ return (-1); ++} /* End of rt28xx_open */ ++ ++ ++/* Must not be called for mdev and apdev */ ++static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status; ++ INT i=0; ++ CHAR slot_name[IFNAMSIZ]; ++ struct net_device *device; ++ ++ ++ //ether_setup(dev); ++ dev->hard_start_xmit = rt28xx_send_packets; ++ ++#ifdef IKANOS_VX_1X0 ++ dev->hard_start_xmit = IKANOS_DataFramesTx; ++#endif // IKANOS_VX_1X0 // ++ ++#ifdef CONFIG_STA_SUPPORT ++#if WIRELESS_EXT >= 12 ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ dev->wireless_handlers = &rt28xx_iw_handler_def; ++ } ++#endif //WIRELESS_EXT >= 12 ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++#if WIRELESS_EXT >= 12 ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ dev->wireless_handlers = &rt28xx_ap_iw_handler_def; ++ } ++#endif //WIRELESS_EXT >= 12 ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#if WIRELESS_EXT < 21 ++ dev->get_wireless_stats = rt28xx_get_wireless_stats; ++#endif ++ dev->get_stats = RT28xx_get_ether_stats; ++ dev->open = MainVirtualIF_open; //rt28xx_open; ++ dev->stop = MainVirtualIF_close; //rt28xx_close; ++ dev->priv_flags = INT_MAIN; ++ dev->do_ioctl = rt28xx_ioctl; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++ dev->validate_addr = NULL; ++#endif ++ // find available device name ++ for (i = 0; i < 8; i++) ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if (pAd->MC_RowID >= 0) ++ sprintf(slot_name, "ra%02d_%d", pAd->MC_RowID, i); ++ else ++#endif // MULTIPLE_CARD_SUPPORT // ++ sprintf(slot_name, "ra%d", i); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ device = dev_get_by_name(dev_net(dev), slot_name); ++#else ++ device = dev_get_by_name(dev->nd_net, slot_name); ++#endif ++#else ++ device = dev_get_by_name(slot_name); ++#endif ++ if (device != NULL) dev_put(device); ++#else ++ for (device = dev_base; device != NULL; device = device->next) ++ { ++ if (strncmp(device->name, slot_name, 4) == 0) ++ break; ++ } ++#endif ++ if(device == NULL) ++ break; ++ } ++ ++ if(i == 8) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if (pAd->MC_RowID >= 0) ++ sprintf(dev->name, "ra%02d_%d", pAd->MC_RowID, i); ++ else ++#endif // MULTIPLE_CARD_SUPPORT // ++ sprintf(dev->name, "ra%d", i); ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ ++ return Status; ++ ++} ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++/* ++======================================================================== ++Routine Description: ++ Get card profile path. ++ ++Arguments: ++ pAd ++ ++Return Value: ++ TRUE - Find a card profile ++ FALSE - use default profile ++ ++Note: ++======================================================================== ++*/ ++extern INT RTMPGetKeyParameter( ++ IN PCHAR key, ++ OUT PCHAR dest, ++ IN INT destsize, ++ IN PCHAR buffer); ++ ++BOOLEAN RTMP_CardInfoRead( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define MC_SELECT_CARDID 0 /* use CARD ID (0 ~ 31) to identify different cards */ ++#define MC_SELECT_MAC 1 /* use CARD MAC to identify different cards */ ++#define MC_SELECT_CARDTYPE 2 /* use CARD type (abgn or bgn) to identify different cards */ ++ ++#define LETTER_CASE_TRANSLATE(txt_p, card_id) \ ++ { UINT32 _len; char _char; \ ++ for(_len=0; _lenfsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ // get RF IC type ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &data); ++ ++ if ((data & 0x30) == 0) ++ pAd->EEPROMAddressNum = 6; // 93C46 ++ else if ((data & 0x30) == 0x10) ++ pAd->EEPROMAddressNum = 8; // 93C66 ++ else ++ pAd->EEPROMAddressNum = 8; // 93C86 ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, antenna.word); ++ ++ if ((antenna.field.RfIcType == RFIC_2850) || ++ (antenna.field.RfIcType == RFIC_2750)) ++ { ++ /* ABGN card */ ++ strcpy(RFIC_word, "abgn"); ++ } ++ else ++ { ++ /* BGN card */ ++ strcpy(RFIC_word, "bgn"); ++ } ++ ++ // get MAC address ++ RT28xx_EEPROM_READ16(pAd, 0x04, addr01); ++ RT28xx_EEPROM_READ16(pAd, 0x06, addr23); ++ RT28xx_EEPROM_READ16(pAd, 0x08, addr45); ++ ++ mac[0] = (UCHAR)(addr01 & 0xff); ++ mac[1] = (UCHAR)(addr01 >> 8); ++ mac[2] = (UCHAR)(addr23 & 0xff); ++ mac[3] = (UCHAR)(addr23 >> 8); ++ mac[4] = (UCHAR)(addr45 & 0xff); ++ mac[5] = (UCHAR)(addr45 >> 8); ++ ++ // open card information file ++ srcf = filp_open(CARD_INFO_PATH, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ /* card information file does not exist */ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("--> Error %ld opening %s\n", -PTR_ERR(srcf), CARD_INFO_PATH)); ++ return FALSE; ++ } ++ ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ /* card information file exists so reading the card information */ ++ memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); ++ retval = srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); ++ if (retval < 0) ++ { ++ /* read fail */ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("--> Read %s error %d\n", CARD_INFO_PATH, -retval)); ++ } ++ else ++ { ++ /* get card selection method */ ++ memset(tmpbuf, 0x00, MAX_PARAM_BUFFER_SIZE); ++ card_select_method = MC_SELECT_CARDTYPE; // default ++ ++ if (RTMPGetKeyParameter("SELECT", tmpbuf, 256, buffer)) ++ { ++ if (strcmp(tmpbuf, "CARDID") == 0) ++ card_select_method = MC_SELECT_CARDID; ++ else if (strcmp(tmpbuf, "MAC") == 0) ++ card_select_method = MC_SELECT_MAC; ++ else if (strcmp(tmpbuf, "CARDTYPE") == 0) ++ card_select_method = MC_SELECT_CARDTYPE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("MC> Card Selection = %d\n", card_select_method)); ++ ++ // init ++ card_free_id = -1; ++ card_nouse_id = -1; ++ card_same_mac_id = -1; ++ card_match_id = -1; ++ ++ // search current card information records ++ for(card_index=0; ++ card_index Free = %d, Same = %d, NOUSE = %d\n", ++ card_free_id, card_same_mac_id, card_nouse_id)); ++ ++ if ((card_same_mac_id >= 0) && ++ ((card_select_method == MC_SELECT_CARDID) || ++ (card_select_method == MC_SELECT_CARDTYPE))) ++ { ++ // same MAC entry is found ++ card_match_id = card_same_mac_id; ++ ++ if (card_select_method == MC_SELECT_CARDTYPE) ++ { ++ // for CARDTYPE ++ sprintf(card_id_buf, "%02dCARDTYPE%s", ++ card_match_id, RFIC_word); ++ ++ if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) ++ { ++ // we found the card ID ++ LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); ++ } ++ } ++ } ++ else ++ { ++ // the card is 1st plug-in, try to find the match card profile ++ switch(card_select_method) ++ { ++ case MC_SELECT_CARDID: // CARDID ++ default: ++ if (card_free_id >= 0) ++ card_match_id = card_free_id; ++ else ++ card_match_id = card_nouse_id; ++ break; ++ ++ case MC_SELECT_MAC: // MAC ++ sprintf(card_id_buf, "MAC%02x:%02x:%02x:%02x:%02x:%02x", ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ ++ /* try to find the key word in the card file */ ++ if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) ++ { ++ LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); ++ ++ /* get the row ID (2 ASCII characters) */ ++ start_ptr -= 2; ++ card_id_buf[0] = *(start_ptr); ++ card_id_buf[1] = *(start_ptr+1); ++ card_id_buf[2] = 0x00; ++ ++ card_match_id = simple_strtol(card_id_buf, 0, 10); ++ } ++ break; ++ ++ case MC_SELECT_CARDTYPE: // CARDTYPE ++ card_nouse_id = -1; ++ ++ for(card_index=0; ++ card_index= 0) ++ { ++ // make up search keyword ++ switch(card_select_method) ++ { ++ case MC_SELECT_CARDID: // CARDID ++ sprintf(card_id_buf, "%02dCARDID", card_match_id); ++ break; ++ ++ case MC_SELECT_MAC: // MAC ++ sprintf(card_id_buf, ++ "%02dmac%02x:%02x:%02x:%02x:%02x:%02x", ++ card_match_id, ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ break; ++ ++ case MC_SELECT_CARDTYPE: // CARDTYPE ++ default: ++ sprintf(card_id_buf, "%02dcardtype%s", ++ card_match_id, RFIC_word); ++ break; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Search Keyword = %s\n", card_id_buf)); ++ ++ // read card file path ++ if (RTMPGetKeyParameter(card_id_buf, tmpbuf, 256, buffer)) ++ { ++ if (strlen(tmpbuf) < sizeof(pAd->MC_FileName)) ++ { ++ // backup card information ++ pAd->MC_RowID = card_match_id; /* base 0 */ ++ MC_CardUsed[card_match_id] = 1; ++ memcpy(MC_CardMac[card_match_id], mac, sizeof(mac)); ++ ++ // backup card file path ++ NdisMoveMemory(pAd->MC_FileName, tmpbuf , strlen(tmpbuf)); ++ pAd->MC_FileName[strlen(tmpbuf)] = '\0'; ++ flg_match_ok = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("Card Profile Name = %s\n", pAd->MC_FileName)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("Card Profile Name length too large!\n")); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("Can not find search key word in card.dat!\n")); ++ } ++ ++ if ((flg_match_ok != TRUE) && ++ (card_match_id < MAX_NUM_OF_MULTIPLE_CARD)) ++ { ++ MC_CardUsed[card_match_id] = 0; ++ memset(MC_CardMac[card_match_id], 0, sizeof(mac)); ++ } ++ } // if (card_match_id >= 0) ++ } ++ } ++ ++ // close file ++ retval = filp_close(srcf, NULL); ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ kfree(buffer); ++ kfree(tmpbuf); ++ return flg_match_ok; ++} ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Probe RT28XX chipset. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ _dev_id_p Point to the PCI or USB device ID ++ ++Return Value: ++ 0 Probe OK ++ -ENODEV Probe Fail ++ ++Note: ++======================================================================== ++*/ ++INT __devinit rt28xx_probe( ++ IN void *_dev_p, ++ IN void *_dev_id_p, ++ IN UINT argc, ++ OUT PRTMP_ADAPTER *ppAd) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; ++ INT status; ++ PVOID handle; ++#ifdef RT2860 ++ struct pci_dev *dev_p = (struct pci_dev *)_dev_p; ++#endif // RT2860 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); ++#endif // CONFIG_STA_SUPPORT // ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++ net_dev = alloc_netdev(sizeof(PRTMP_ADAPTER), "eth%d", ether_setup); ++#else ++ net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); ++#endif ++ if (net_dev == NULL) ++ { ++ printk("alloc_netdev failed\n"); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ module_put(THIS_MODULE); ++#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++#else ++ MOD_DEC_USE_COUNT; ++#endif ++ goto err_out; ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(net_dev); ++#endif ++ ++ netif_stop_queue(net_dev); ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++/* for supporting Network Manager */ ++/* Set the sysfs physical device reference for the network logical device ++ * if set prior to registration will cause a symlink during initialization. ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ SET_NETDEV_DEV(net_dev, &(dev_p->dev)); ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ // Allocate RTMP_ADAPTER miniport adapter structure ++ handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); ++ RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p); ++ ++ status = RTMPAllocAdapterBlock(handle, &pAd); ++ if (status != NDIS_STATUS_SUCCESS) ++ goto err_out_free_netdev; ++ ++ net_dev->priv = (PVOID)pAd; ++ pAd->net_dev = net_dev; // must be before RT28XXNetDevInit() ++ ++ RT28XXNetDevInit(_dev_p, net_dev, pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAd->StaCfg.OriDevType = net_dev->type; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Post config ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ if (RT28XXProbePostConfig(_dev_p, pAd, argc) == FALSE) ++ goto err_out_unmap; ++#else ++ if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) ++ goto err_out_unmap; ++#endif // LINUX_VERSION_CODE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAd->OpMode = OPMODE_STA; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++ // find its profile path ++ pAd->MC_RowID = -1; // use default profile path ++ RTMP_CardInfoRead(pAd); ++ ++ if (pAd->MC_RowID == -1) ++#ifdef CONFIG_STA_SUPPORT ++ strcpy(pAd->MC_FileName, STA_PROFILE_PATH); ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("MC> ROW = %d, PATH = %s\n", pAd->MC_RowID, pAd->MC_FileName)); ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ // sample move ++ if (rt_ieee80211_if_setup(net_dev, pAd) != NDIS_STATUS_SUCCESS) ++ goto err_out_unmap; ++ ++ // Register this device ++ status = register_netdev(net_dev); ++ if (status) ++ goto err_out_unmap; ++ ++ // Set driver data ++ RT28XX_DRVDATA_SET(_dev_p); ++ ++ *ppAd = pAd; ++ return 0; // probe ok ++ ++ ++ /* --------------------------- ERROR HANDLE --------------------------- */ ++err_out_unmap: ++ RTMPFreeAdapter(pAd); ++ RT28XX_UNMAP(); ++ ++err_out_free_netdev: ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ free_netdev(net_dev); ++#else ++ kfree(net_dev); ++#endif ++ ++err_out: ++ RT28XX_PUT_DEVICE(dev_p); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return (LONG)NULL; ++#else ++ return -ENODEV; /* probe fail */ ++#endif // LINUX_VERSION_CODE // ++} /* End of rt28xx_probe */ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ The entry point for Linux kernel sent packet to our driver. ++ ++Arguments: ++ sk_buff *skb the pointer refer to a sk_buffer. ++ ++Return Value: ++ 0 ++ ++Note: ++ This function is the entry point of Tx Path for Os delivery packet to ++ our driver. You only can put OS-depened & STA/AP common handle procedures ++ in here. ++======================================================================== ++*/ ++int rt28xx_packet_xmit(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = skb->dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ int status = 0; ++ PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; ++ ++ /* RT2870STA does this in RTMPSendPackets() */ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); ++ return 0; ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Drop send request since we are in monitor mode ++ if (MONITOR_ON(pAd)) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ goto done; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // EapolStart size is 18 ++ if (skb->len < 14) ++ { ++ //printk("bad packet size: %d\n", pkt->len); ++ hex_dump("bad packet", skb->data, skb->len); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ goto done; ++ } ++ ++ RTMP_SET_PACKET_5VT(pPacket, 0); ++#ifdef CONFIG_5VT_ENHANCE ++ if (*(int*)(skb->cb) == BRIDGE_TAG) { ++ RTMP_SET_PACKET_5VT(pPacket, 1); ++ } ++#endif ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ status = 0; ++done: ++ ++ return status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Send a packet to WLAN. ++ ++Arguments: ++ skb_p points to our adapter ++ dev_p which WLAN network interface ++ ++Return Value: ++ 0: transmit successfully ++ otherwise: transmit fail ++ ++Note: ++======================================================================== ++*/ ++INT rt28xx_send_packets( ++ IN struct sk_buff *skb_p, ++ IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ if (!(net_dev->flags & IFF_UP)) ++ { ++ RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); ++ return 0; ++ } ++ ++ NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); ++ RTMP_SET_PACKET_NET_DEVICE_MBSSID(skb_p, MAIN_MBSSID); ++ ++ return rt28xx_packet_xmit(skb_p); ++ ++} /* End of MBSS_VirtualIF_PacketSend */ ++ ++ ++ ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++struct net_device *alloc_netdev( ++ int sizeof_priv, ++ const char *mask, ++ void (*setup)(struct net_device *)) ++{ ++ struct net_device *dev; ++ INT alloc_size; ++ ++ ++ /* ensure 32-byte alignment of the private area */ ++ alloc_size = sizeof (*dev) + sizeof_priv + 31; ++ ++ dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); ++ if (dev == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("alloc_netdev: Unable to allocate device memory.\n")); ++ return NULL; ++ } ++ ++ memset(dev, 0, alloc_size); ++ ++ if (sizeof_priv) ++ dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); ++ ++ setup(dev); ++ strcpy(dev->name, mask); ++ ++ return dev; ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++void CfgInitHook(PRTMP_ADAPTER pAd) ++{ ++ pAd->bBroadComHT = TRUE; ++} /* End of CfgInitHook */ ++ ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt28xx_get_wireless_stats --->\n")); ++ ++ pAd->iw_stats.status = 0; // Status - device dependent for now ++ ++ // link quality ++ pAd->iw_stats.qual.qual = ((pAd->Mlme.ChannelQuality * 12)/10 + 10); ++ if(pAd->iw_stats.qual.qual > 100) ++ pAd->iw_stats.qual.qual = 100; ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ pAd->iw_stats.qual.level = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->iw_stats.qual.noise = pAd->BbpWriteLatch[66]; // noise level (dBm) ++ ++ pAd->iw_stats.qual.noise += 256 - 143; ++ pAd->iw_stats.qual.updated = 1; // Flags to know if updated ++#ifdef IW_QUAL_DBM ++ pAd->iw_stats.qual.updated |= IW_QUAL_DBM; // Level + Noise are dBm ++#endif // IW_QUAL_DBM // ++ ++ pAd->iw_stats.discard.nwid = 0; // Rx : Wrong nwid/essid ++ pAd->iw_stats.miss.beacon = 0; // Missed beacons/superframe ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- rt28xx_get_wireless_stats\n")); ++ return &pAd->iw_stats; ++} /* End of rt28xx_get_wireless_stats */ ++#endif // WIRELESS_EXT // ++ ++ ++ ++void tbtt_tasklet(unsigned long data) ++{ ++#define MAX_TX_IN_TBTT (16) ++ ++} ++ ++INT rt28xx_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ INT ret = 0; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ret = rt28xx_sta_ioctl(net_dev, rq, cmd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return ret; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ return ethernet statistics counter ++ ++ Arguments: ++ net_dev Pointer to net_device ++ ++ Return Value: ++ net_device_stats* ++ ++ Note: ++ ++ ======================================================================== ++*/ ++struct net_device_stats *RT28xx_get_ether_stats( ++ IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = NULL; ++ ++ if (net_dev) ++ pAd = net_dev->priv; ++ ++ if (pAd) ++ { ++ ++ pAd->stats.rx_packets = pAd->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pAd->stats.tx_packets = pAd->WlanCounters.TransmittedFragmentCount.QuadPart; ++ ++ pAd->stats.rx_bytes = pAd->RalinkCounters.ReceivedByteCount; ++ pAd->stats.tx_bytes = pAd->RalinkCounters.TransmittedByteCount; ++ ++ pAd->stats.rx_errors = pAd->Counters8023.RxErrors; ++ pAd->stats.tx_errors = pAd->Counters8023.TxErrors; ++ ++ pAd->stats.rx_dropped = 0; ++ pAd->stats.tx_dropped = 0; ++ ++ pAd->stats.multicast = pAd->WlanCounters.MulticastReceivedFrameCount.QuadPart; // multicast packets received ++ pAd->stats.collisions = pAd->Counters8023.OneCollision + pAd->Counters8023.MoreCollisions; // Collision packets ++ ++ pAd->stats.rx_length_errors = 0; ++ pAd->stats.rx_over_errors = pAd->Counters8023.RxNoBuffer; // receiver ring buff overflow ++ pAd->stats.rx_crc_errors = 0;//pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error ++ pAd->stats.rx_frame_errors = pAd->Counters8023.RcvAlignmentErrors; // recv'd frame alignment error ++ pAd->stats.rx_fifo_errors = pAd->Counters8023.RxNoBuffer; // recv'r fifo overrun ++ pAd->stats.rx_missed_errors = 0; // receiver missed packet ++ ++ // detailed tx_errors ++ pAd->stats.tx_aborted_errors = 0; ++ pAd->stats.tx_carrier_errors = 0; ++ pAd->stats.tx_fifo_errors = 0; ++ pAd->stats.tx_heartbeat_errors = 0; ++ pAd->stats.tx_window_errors = 0; ++ ++ // for cslip etc ++ pAd->stats.rx_compressed = 0; ++ pAd->stats.tx_compressed = 0; ++ ++ return &pAd->stats; ++ } ++ else ++ return NULL; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rtmp_ckipmic.h +@@ -0,0 +1,113 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_ckipmic.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef __RTMP_CKIPMIC_H__ ++#define __RTMP_CKIPMIC_H__ ++ ++typedef struct _MIC_CONTEXT { ++ /* --- MMH context */ ++ UCHAR CK[16]; /* the key */ ++ UCHAR coefficient[16]; /* current aes counter mode coefficients */ ++ ULONGLONG accum; /* accumulated mic, reduced to u32 in final() */ ++ UINT position; /* current position (byte offset) in message */ ++ UCHAR part[4]; /* for conversion of message to u32 for mmh */ ++} MIC_CONTEXT, *PMIC_CONTEXT; ++ ++VOID CKIP_key_permute( ++ OUT UCHAR *PK, /* output permuted key */ ++ IN UCHAR *CK, /* input CKIP key */ ++ IN UCHAR toDsFromDs, /* input toDs/FromDs bits */ ++ IN UCHAR *piv); /* input pointer to IV */ ++ ++VOID RTMPCkipMicInit( ++ IN PMIC_CONTEXT pContext, ++ IN PUCHAR CK); ++ ++VOID RTMPMicUpdate( ++ IN PMIC_CONTEXT pContext, ++ IN PUCHAR pOctets, ++ IN INT len); ++ ++ULONG RTMPMicGetCoefficient( ++ IN PMIC_CONTEXT pContext); ++ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a); ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round); ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID RTMPAesEncrypt( ++ IN PUCHAR key, ++ IN PUCHAR data, ++ IN PUCHAR ciphertext); ++ ++VOID RTMPMicFinal( ++ IN PMIC_CONTEXT pContext, ++ OUT UCHAR digest[4]); ++ ++VOID RTMPCkipInsertCMIC( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pMIC, ++ IN PUCHAR p80211hdr, ++ IN PNDIS_PACKET pPacket, ++ IN PCIPHER_KEY pKey, ++ IN PUCHAR mic_snap); ++ ++#endif //__RTMP_CKIPMIC_H__ +--- /dev/null ++++ b/drivers/staging/rt2860/rtmp_def.h +@@ -0,0 +1,1588 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_def.h ++ ++ Abstract: ++ Miniport related definition header ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ John Chang 08-05-2003 add definition for 11g & other drafts ++*/ ++#ifndef __RTMP_DEF_H__ ++#define __RTMP_DEF_H__ ++ ++#include "oid.h" ++ ++// ++// Debug information verbosity: lower values indicate higher urgency ++// ++#define RT_DEBUG_OFF 0 ++#define RT_DEBUG_ERROR 1 ++#define RT_DEBUG_WARN 2 ++#define RT_DEBUG_TRACE 3 ++#define RT_DEBUG_INFO 4 ++#define RT_DEBUG_LOUD 5 ++ ++#define NIC_TAG ((ULONG)'0682') ++#define NIC_DBG_STRING ("**RT28xx**") ++ ++#ifdef SNMP_SUPPORT ++// for snmp ++// to get manufacturer OUI, kathy, 2008_0220 ++#define ManufacturerOUI_LEN 3 ++#define ManufacturerNAME ("Ralink Technology Company.") ++#define ResourceTypeIdName ("Ralink_ID") ++#endif ++ ++ ++#define RALINK_2883_VERSION ((UINT32)0x28830300) ++#define RALINK_2880E_VERSION ((UINT32)0x28720200) ++#define RALINK_3070_VERSION ((UINT32)0x30700200) ++ ++// ++// NDIS version in use by the NIC driver. ++// The high byte is the major version. The low byte is the minor version. ++// ++#ifdef NDIS51_MINIPORT ++#define NIC_DRIVER_VERSION 0x0501 ++#else ++#define NIC_DRIVER_VERSION 0x0500 ++#endif ++ ++// ++// NDIS media type, current is ethernet, change if native wireless supported ++// ++#define NIC_MEDIA_TYPE NdisMedium802_3 ++#define NIC_PCI_HDR_LENGTH 0xe2 ++#define NIC_MAX_PACKET_SIZE 2304 ++#define NIC_HEADER_SIZE 14 ++#define MAX_MAP_REGISTERS_NEEDED 32 ++#define MIN_MAP_REGISTERS_NEEDED 2 //Todo: should consider fragment issue. ++ ++// ++// interface type, we use PCI ++// ++#define NIC_INTERFACE_TYPE NdisInterfacePci ++#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive ++ ++// ++// buffer size passed in NdisMQueryAdapterResources ++// We should only need three adapter resources (IO, interrupt and memory), ++// Some devices get extra resources, so have room for 10 resources ++// UF_SIZE (sizeof(NDIS_RESOURCE_LIST) + (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))) ++ ++ ++#define NIC_RESOURCE_B// ++// IO space length ++// ++#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC) ++ ++#define MAX_RX_PKT_LEN 1520 ++ ++// ++// Entry number for each DMA descriptor ring ++// ++ ++#ifdef RT2860 ++#define TX_RING_SIZE 64 //64 ++#define MGMT_RING_SIZE 128 ++#define RX_RING_SIZE 128 //64 ++#define MAX_TX_PROCESS TX_RING_SIZE //8 ++#define MAX_DMA_DONE_PROCESS TX_RING_SIZE ++#define MAX_TX_DONE_PROCESS TX_RING_SIZE //8 ++#define LOCAL_TXBUF_SIZE 2 ++#endif // RT2860 // ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// MC: Multple Cards ++#define MAX_NUM_OF_MULTIPLE_CARD 32 ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#define MAX_RX_PROCESS 128 //64 //32 ++#define NUM_OF_LOCAL_TXBUF 2 ++#define TXD_SIZE 16 ++#define TXWI_SIZE 16 ++#define RXD_SIZE 16 ++#define RXWI_SIZE 16 ++// TXINFO_SIZE + TXWI_SIZE + 802.11 Header Size + AMSDU sub frame header ++#define TX_DMA_1ST_BUFFER_SIZE 96 // only the 1st physical buffer is pre-allocated ++#define MGMT_DMA_BUFFER_SIZE 1536 //2048 ++#define RX_BUFFER_AGGRESIZE 3840 //3904 //3968 //4096 //2048 //4096 ++#define RX_BUFFER_NORMSIZE 3840 //3904 //3968 //4096 //2048 //4096 ++#define TX_BUFFER_NORMSIZE RX_BUFFER_NORMSIZE ++#define MAX_FRAME_SIZE 2346 // Maximum 802.11 frame size ++#define MAX_AGGREGATION_SIZE 3840 //3904 //3968 //4096 ++#define MAX_NUM_OF_TUPLE_CACHE 2 ++#define MAX_MCAST_LIST_SIZE 32 ++#define MAX_LEN_OF_VENDOR_DESC 64 ++//#define MAX_SIZE_OF_MCAST_PSQ (NUM_OF_LOCAL_TXBUF >> 2) // AP won't spend more than 1/4 of total buffers on M/BCAST PSQ ++#define MAX_SIZE_OF_MCAST_PSQ 32 ++ ++#define MAX_RX_PROCESS_CNT (RX_RING_SIZE) ++ ++ ++#define MAX_PACKETS_IN_QUEUE (512) //(512) // to pass WMM A5-WPAPSK ++#define MAX_PACKETS_IN_MCAST_PS_QUEUE 32 ++#define MAX_PACKETS_IN_PS_QUEUE 128 //32 ++#define WMM_NUM_OF_AC 4 /* AC0, AC1, AC2, and AC3 */ ++ ++ ++ ++// RxFilter ++#define STANORMAL 0x17f97 ++#define APNORMAL 0x15f97 ++// ++// RTMP_ADAPTER flags ++// ++#define fRTMP_ADAPTER_MAP_REGISTER 0x00000001 ++#define fRTMP_ADAPTER_INTERRUPT_IN_USE 0x00000002 ++#define fRTMP_ADAPTER_HARDWARE_ERROR 0x00000004 ++#define fRTMP_ADAPTER_SCATTER_GATHER 0x00000008 ++#define fRTMP_ADAPTER_SEND_PACKET_ERROR 0x00000010 ++#define fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS 0x00000020 ++#define fRTMP_ADAPTER_HALT_IN_PROGRESS 0x00000040 ++#define fRTMP_ADAPTER_RESET_IN_PROGRESS 0x00000080 ++#define fRTMP_ADAPTER_NIC_NOT_EXIST 0x00000100 ++#define fRTMP_ADAPTER_TX_RING_ALLOCATED 0x00000200 ++#define fRTMP_ADAPTER_REMOVE_IN_PROGRESS 0x00000400 ++#define fRTMP_ADAPTER_MIMORATE_INUSED 0x00000800 ++#define fRTMP_ADAPTER_RX_RING_ALLOCATED 0x00001000 ++#define fRTMP_ADAPTER_INTERRUPT_ACTIVE 0x00002000 ++#define fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS 0x00004000 ++#define fRTMP_ADAPTER_REASSOC_IN_PROGRESS 0x00008000 ++#define fRTMP_ADAPTER_MEDIA_STATE_PENDING 0x00010000 ++#define fRTMP_ADAPTER_RADIO_OFF 0x00020000 ++#define fRTMP_ADAPTER_BULKOUT_RESET 0x00040000 ++#define fRTMP_ADAPTER_BULKIN_RESET 0x00080000 ++#define fRTMP_ADAPTER_RDG_ACTIVE 0x00100000 ++#define fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE 0x00200000 ++#define fRTMP_ADAPTER_SCAN_2040 0x04000000 ++#define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000 ++ ++#define fRTMP_ADAPTER_START_UP 0x10000000 //Devive already initialized and enabled Tx/Rx. ++#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000 ++#define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000 ++ ++// ++// STA operation status flags ++// ++#define fOP_STATUS_INFRA_ON 0x00000001 ++#define fOP_STATUS_ADHOC_ON 0x00000002 ++#define fOP_STATUS_BG_PROTECTION_INUSED 0x00000004 ++#define fOP_STATUS_SHORT_SLOT_INUSED 0x00000008 ++#define fOP_STATUS_SHORT_PREAMBLE_INUSED 0x00000010 ++#define fOP_STATUS_RECEIVE_DTIM 0x00000020 ++#define fOP_STATUS_MEDIA_STATE_CONNECTED 0x00000080 ++#define fOP_STATUS_WMM_INUSED 0x00000100 ++#define fOP_STATUS_AGGREGATION_INUSED 0x00000200 ++#define fOP_STATUS_DOZE 0x00000400 // debug purpose ++#define fOP_STATUS_PIGGYBACK_INUSED 0x00000800 // piggy-back, and aggregation ++#define fOP_STATUS_APSD_INUSED 0x00001000 ++#define fOP_STATUS_TX_AMSDU_INUSED 0x00002000 ++#define fOP_STATUS_MAX_RETRY_ENABLED 0x00004000 ++#define fOP_STATUS_WAKEUP_NOW 0x00008000 ++#define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 ++ ++#ifdef DOT11N_DRAFT3 ++#define fOP_STATUS_SCAN_2040 0x00040000 ++#endif // DOT11N_DRAFT3 // ++ ++#define CCKSETPROTECT 0x1 ++#define OFDMSETPROTECT 0x2 ++#define MM20SETPROTECT 0x4 ++#define MM40SETPROTECT 0x8 ++#define GF20SETPROTECT 0x10 ++#define GR40SETPROTECT 0x20 ++#define ALLN_SETPROTECT (GR40SETPROTECT | GF20SETPROTECT | MM40SETPROTECT | MM20SETPROTECT) ++ ++// ++// AP's client table operation status flags ++// ++#define fCLIENT_STATUS_WMM_CAPABLE 0x00000001 // CLIENT can parse QOS DATA frame ++#define fCLIENT_STATUS_AGGREGATION_CAPABLE 0x00000002 // CLIENT can receive Ralink's proprietary TX aggregation frame ++#define fCLIENT_STATUS_PIGGYBACK_CAPABLE 0x00000004 // CLIENT support piggy-back ++#define fCLIENT_STATUS_AMSDU_INUSED 0x00000008 ++#define fCLIENT_STATUS_SGI20_CAPABLE 0x00000010 ++#define fCLIENT_STATUS_SGI40_CAPABLE 0x00000020 ++#define fCLIENT_STATUS_TxSTBC_CAPABLE 0x00000040 ++#define fCLIENT_STATUS_RxSTBC_CAPABLE 0x00000080 ++#define fCLIENT_STATUS_HTC_CAPABLE 0x00000100 ++#define fCLIENT_STATUS_RDG_CAPABLE 0x00000200 ++#define fCLIENT_STATUS_MCSFEEDBACK_CAPABLE 0x00000400 ++#define fCLIENT_STATUS_APSD_CAPABLE 0x00000800 /* UAPSD STATION */ ++ ++#ifdef DOT11N_DRAFT3 ++#define fCLIENT_STATUS_BSSCOEXIST_CAPABLE 0x00001000 ++#endif // DOT11N_DRAFT3 // ++ ++#define fCLIENT_STATUS_RALINK_CHIPSET 0x00100000 ++// ++// STA configuration flags ++// ++ ++// 802.11n Operating Mode Definition. 0-3 also used in ASICUPdateProtect switch case ++#define HT_NO_PROTECT 0 ++#define HT_LEGACY_PROTECT 1 ++#define HT_40_PROTECT 2 ++#define HT_2040_PROTECT 3 ++#define HT_RTSCTS_6M 7 ++//following is our own definition in order to turn on our ASIC protection register in INFRASTRUCTURE. ++#define HT_ATHEROS 8 // rt2860c has problem with atheros chip. we need to turn on RTS/CTS . ++#define HT_FORCERTSCTS 9 // Force turn on RTS/CTS first. then go to evaluate if this force RTS is necessary. ++ ++// ++// RX Packet Filter control flags. Apply on pAd->PacketFilter ++// ++#define fRX_FILTER_ACCEPT_DIRECT NDIS_PACKET_TYPE_DIRECTED ++#define fRX_FILTER_ACCEPT_MULTICAST NDIS_PACKET_TYPE_MULTICAST ++#define fRX_FILTER_ACCEPT_BROADCAST NDIS_PACKET_TYPE_BROADCAST ++#define fRX_FILTER_ACCEPT_ALL_MULTICAST NDIS_PACKET_TYPE_ALL_MULTICAST ++ ++// ++// Error code section ++// ++// NDIS_ERROR_CODE_ADAPTER_NOT_FOUND ++#define ERRLOG_READ_PCI_SLOT_FAILED 0x00000101L ++#define ERRLOG_WRITE_PCI_SLOT_FAILED 0x00000102L ++#define ERRLOG_VENDOR_DEVICE_NOMATCH 0x00000103L ++ ++// NDIS_ERROR_CODE_ADAPTER_DISABLED ++#define ERRLOG_BUS_MASTER_DISABLED 0x00000201L ++ ++// NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION ++#define ERRLOG_INVALID_SPEED_DUPLEX 0x00000301L ++#define ERRLOG_SET_SECONDARY_FAILED 0x00000302L ++ ++// NDIS_ERROR_CODE_OUT_OF_RESOURCES ++#define ERRLOG_OUT_OF_MEMORY 0x00000401L ++#define ERRLOG_OUT_OF_SHARED_MEMORY 0x00000402L ++#define ERRLOG_OUT_OF_MAP_REGISTERS 0x00000403L ++#define ERRLOG_OUT_OF_BUFFER_POOL 0x00000404L ++#define ERRLOG_OUT_OF_NDIS_BUFFER 0x00000405L ++#define ERRLOG_OUT_OF_PACKET_POOL 0x00000406L ++#define ERRLOG_OUT_OF_NDIS_PACKET 0x00000407L ++#define ERRLOG_OUT_OF_LOOKASIDE_MEMORY 0x00000408L ++ ++// NDIS_ERROR_CODE_HARDWARE_FAILURE ++#define ERRLOG_SELFTEST_FAILED 0x00000501L ++#define ERRLOG_INITIALIZE_ADAPTER 0x00000502L ++#define ERRLOG_REMOVE_MINIPORT 0x00000503L ++ ++// NDIS_ERROR_CODE_RESOURCE_CONFLICT ++#define ERRLOG_MAP_IO_SPACE 0x00000601L ++#define ERRLOG_QUERY_ADAPTER_RESOURCES 0x00000602L ++#define ERRLOG_NO_IO_RESOURCE 0x00000603L ++#define ERRLOG_NO_INTERRUPT_RESOURCE 0x00000604L ++#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L ++ ++ ++// WDS definition ++#define MAX_WDS_ENTRY 4 ++#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table ++ ++#define WDS_DISABLE_MODE 0 ++#define WDS_RESTRICT_MODE 1 ++#define WDS_BRIDGE_MODE 2 ++#define WDS_REPEATER_MODE 3 ++#define WDS_LAZY_MODE 4 ++ ++ ++#define MAX_MESH_NUM 0 ++ ++#define MAX_APCLI_NUM 0 ++#ifdef APCLI_SUPPORT ++#undef MAX_APCLI_NUM ++#define MAX_APCLI_NUM 1 ++#endif // APCLI_SUPPORT // ++ ++#define MAX_MBSSID_NUM 1 ++#ifdef MBSS_SUPPORT ++#undef MAX_MBSSID_NUM ++#define MAX_MBSSID_NUM (8 - MAX_MESH_NUM - MAX_APCLI_NUM) ++#endif // MBSS_SUPPORT // ++ ++/* sanity check for apidx */ ++#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ ++ { if (apidx > MAX_MBSSID_NUM) { \ ++ printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \ ++ apidx = MAIN_MBSSID; } } ++ ++#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE ) ++ ++#define MAIN_MBSSID 0 ++#define FIRST_MBSSID 1 ++ ++ ++#define MAX_BEACON_SIZE 512 ++// If the MAX_MBSSID_NUM is larger than 6, ++// it shall reserve some WCID space(wcid 222~253) for beacon frames. ++// - these wcid 238~253 are reserved for beacon#6(ra6). ++// - these wcid 222~237 are reserved for beacon#7(ra7). ++#if defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 8) ++#define HW_RESERVED_WCID 222 ++#elif defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 7) ++#define HW_RESERVED_WCID 238 ++#else ++#define HW_RESERVED_WCID 255 ++#endif ++ ++// Then dedicate wcid of DFS and Carrier-Sense. ++#define DFS_CTS_WCID (HW_RESERVED_WCID - 1) ++#define CS_CTS_WCID (HW_RESERVED_WCID - 2) ++#define LAST_SPECIFIC_WCID (HW_RESERVED_WCID - 2) ++ ++// If MAX_MBSSID_NUM is 8, the maximum available wcid for the associated STA is 211. ++// If MAX_MBSSID_NUM is 7, the maximum available wcid for the associated STA is 228. ++#define MAX_AVAILABLE_CLIENT_WCID (LAST_SPECIFIC_WCID - MAX_MBSSID_NUM - 1) ++ ++// TX need WCID to find Cipher Key ++// these wcid 212 ~ 219 are reserved for bc/mc packets if MAX_MBSSID_NUM is 8. ++#define GET_GroupKey_WCID(__wcid, __bssidx) \ ++ { \ ++ __wcid = LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM) + __bssidx; \ ++ } ++ ++#define IsGroupKeyWCID(__wcid) (((__wcid) < LAST_SPECIFIC_WCID) && ((__wcid) >= (LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM)))) ++ ++ ++// definition to support multiple BSSID ++#define BSS0 0 ++#define BSS1 1 ++#define BSS2 2 ++#define BSS3 3 ++#define BSS4 4 ++#define BSS5 5 ++#define BSS6 6 ++#define BSS7 7 ++ ++ ++//============================================================ ++// Length definitions ++#define PEER_KEY_NO 2 ++#define MAC_ADDR_LEN 6 ++#define TIMESTAMP_LEN 8 ++#define MAX_LEN_OF_SUPPORTED_RATES MAX_LENGTH_OF_SUPPORT_RATES // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define MAX_LEN_OF_KEY 32 // 32 octets == 256 bits, Redefine for WPA ++#define MAX_NUM_OF_CHANNELS MAX_NUM_OF_CHS // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination ++#define MAX_NUM_OF_11JCHANNELS 20 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination ++#define MAX_LEN_OF_SSID 32 ++#define CIPHER_TEXT_LEN 128 ++#define HASH_TABLE_SIZE 256 ++#define MAX_VIE_LEN 1024 // New for WPA cipher suite variable IE sizes. ++#define MAX_SUPPORT_MCS 32 ++ ++//============================================================ ++// ASIC WCID Table definition. ++//============================================================ ++#define BSSID_WCID 1 // in infra mode, always put bssid with this WCID ++#define MCAST_WCID 0x0 ++#define BSS0Mcast_WCID 0x0 ++#define BSS1Mcast_WCID 0xf8 ++#define BSS2Mcast_WCID 0xf9 ++#define BSS3Mcast_WCID 0xfa ++#define BSS4Mcast_WCID 0xfb ++#define BSS5Mcast_WCID 0xfc ++#define BSS6Mcast_WCID 0xfd ++#define BSS7Mcast_WCID 0xfe ++#define RESERVED_WCID 0xff ++ ++#define MAX_NUM_OF_ACL_LIST MAX_NUMBER_OF_ACL ++ ++#define MAX_LEN_OF_MAC_TABLE MAX_NUMBER_OF_MAC // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 ++ ++#if MAX_LEN_OF_MAC_TABLE>MAX_AVAILABLE_CLIENT_WCID ++#error MAX_LEN_OF_MAC_TABLE can not be larger than MAX_AVAILABLE_CLIENT_WCID!!!! ++#endif ++ ++#define MAX_NUM_OF_WDS_LINK_PERBSSID 3 ++#define MAX_NUM_OF_WDS_LINK (MAX_NUM_OF_WDS_LINK_PERBSSID*MAX_MBSSID_NUM) ++#define MAX_NUM_OF_EVENT MAX_NUMBER_OF_EVENT ++#define WDS_LINK_START_WCID (MAX_LEN_OF_MAC_TABLE-1) ++ ++#define NUM_OF_TID 8 ++#define MAX_AID_BA 4 ++#define MAX_LEN_OF_BA_REC_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) //Block ACK recipient ++#define MAX_LEN_OF_BA_ORI_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) // Block ACK originator ++#define MAX_LEN_OF_BSS_TABLE 64 ++#define MAX_REORDERING_MPDU_NUM 512 ++ ++// key related definitions ++#define SHARE_KEY_NUM 4 ++#define MAX_LEN_OF_SHARE_KEY 16 // byte count ++#define MAX_LEN_OF_PEER_KEY 16 // byte count ++#define PAIRWISE_KEY_NUM 64 // in MAC ASIC pairwise key table ++#define GROUP_KEY_NUM 4 ++#define PMK_LEN 32 ++#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table ++#define PMKID_NO 4 // Number of PMKID saved supported ++#define MAX_LEN_OF_MLME_BUFFER 2048 ++ ++// power status related definitions ++#define PWR_ACTIVE 0 ++#define PWR_SAVE 1 ++#define PWR_MMPS 2 //MIMO power save ++ ++// Auth and Assoc mode related definitions ++#define AUTH_MODE_OPEN 0x00 ++#define AUTH_MODE_KEY 0x01 ++ ++// BSS Type definitions ++#define BSS_ADHOC 0 // = Ndis802_11IBSS ++#define BSS_INFRA 1 // = Ndis802_11Infrastructure ++#define BSS_ANY 2 // = Ndis802_11AutoUnknown ++#define BSS_MONITOR 3 // = Ndis802_11Monitor ++ ++ ++// Reason code definitions ++#define REASON_RESERVED 0 ++#define REASON_UNSPECIFY 1 ++#define REASON_NO_LONGER_VALID 2 ++#define REASON_DEAUTH_STA_LEAVING 3 ++#define REASON_DISASSOC_INACTIVE 4 ++#define REASON_DISASSPC_AP_UNABLE 5 ++#define REASON_CLS2ERR 6 ++#define REASON_CLS3ERR 7 ++#define REASON_DISASSOC_STA_LEAVING 8 ++#define REASON_STA_REQ_ASSOC_NOT_AUTH 9 ++#define REASON_INVALID_IE 13 ++#define REASON_MIC_FAILURE 14 ++#define REASON_4_WAY_TIMEOUT 15 ++#define REASON_GROUP_KEY_HS_TIMEOUT 16 ++#define REASON_IE_DIFFERENT 17 ++#define REASON_MCIPHER_NOT_VALID 18 ++#define REASON_UCIPHER_NOT_VALID 19 ++#define REASON_AKMP_NOT_VALID 20 ++#define REASON_UNSUPPORT_RSNE_VER 21 ++#define REASON_INVALID_RSNE_CAP 22 ++#define REASON_8021X_AUTH_FAIL 23 ++#define REASON_CIPHER_SUITE_REJECTED 24 ++#define REASON_DECLINED 37 ++ ++#define REASON_QOS_UNSPECIFY 32 ++#define REASON_QOS_LACK_BANDWIDTH 33 ++#define REASON_POOR_CHANNEL_CONDITION 34 ++#define REASON_QOS_OUTSIDE_TXOP_LIMITION 35 ++#define REASON_QOS_QSTA_LEAVING_QBSS 36 ++#define REASON_QOS_UNWANTED_MECHANISM 37 ++#define REASON_QOS_MECH_SETUP_REQUIRED 38 ++#define REASON_QOS_REQUEST_TIMEOUT 39 ++#define REASON_QOS_CIPHER_NOT_SUPPORT 45 ++ ++// Status code definitions ++#define MLME_SUCCESS 0 ++#define MLME_UNSPECIFY_FAIL 1 ++#define MLME_CANNOT_SUPPORT_CAP 10 ++#define MLME_REASSOC_DENY_ASSOC_EXIST 11 ++#define MLME_ASSOC_DENY_OUT_SCOPE 12 ++#define MLME_ALG_NOT_SUPPORT 13 ++#define MLME_SEQ_NR_OUT_OF_SEQUENCE 14 ++#define MLME_REJ_CHALLENGE_FAILURE 15 ++#define MLME_REJ_TIMEOUT 16 ++#define MLME_ASSOC_REJ_UNABLE_HANDLE_STA 17 ++#define MLME_ASSOC_REJ_DATA_RATE 18 ++ ++#define MLME_ASSOC_REJ_NO_EXT_RATE 22 ++#define MLME_ASSOC_REJ_NO_EXT_RATE_PBCC 23 ++#define MLME_ASSOC_REJ_NO_CCK_OFDM 24 ++ ++#define MLME_QOS_UNSPECIFY 32 ++#define MLME_REQUEST_DECLINED 37 ++#define MLME_REQUEST_WITH_INVALID_PARAM 38 ++#define MLME_DLS_NOT_ALLOW_IN_QBSS 48 ++#define MLME_DEST_STA_NOT_IN_QBSS 49 ++#define MLME_DEST_STA_IS_NOT_A_QSTA 50 ++ ++#define MLME_INVALID_FORMAT 0x51 ++#define MLME_FAIL_NO_RESOURCE 0x52 ++#define MLME_STATE_MACHINE_REJECT 0x53 ++#define MLME_MAC_TABLE_FAIL 0x54 ++ ++// IE code ++#define IE_SSID 0 ++#define IE_SUPP_RATES 1 ++#define IE_FH_PARM 2 ++#define IE_DS_PARM 3 ++#define IE_CF_PARM 4 ++#define IE_TIM 5 ++#define IE_IBSS_PARM 6 ++#define IE_COUNTRY 7 // 802.11d ++#define IE_802_11D_REQUEST 10 // 802.11d ++#define IE_QBSS_LOAD 11 // 802.11e d9 ++#define IE_EDCA_PARAMETER 12 // 802.11e d9 ++#define IE_TSPEC 13 // 802.11e d9 ++#define IE_TCLAS 14 // 802.11e d9 ++#define IE_SCHEDULE 15 // 802.11e d9 ++#define IE_CHALLENGE_TEXT 16 ++#define IE_POWER_CONSTRAINT 32 // 802.11h d3.3 ++#define IE_POWER_CAPABILITY 33 // 802.11h d3.3 ++#define IE_TPC_REQUEST 34 // 802.11h d3.3 ++#define IE_TPC_REPORT 35 // 802.11h d3.3 ++#define IE_SUPP_CHANNELS 36 // 802.11h d3.3 ++#define IE_CHANNEL_SWITCH_ANNOUNCEMENT 37 // 802.11h d3.3 ++#define IE_MEASUREMENT_REQUEST 38 // 802.11h d3.3 ++#define IE_MEASUREMENT_REPORT 39 // 802.11h d3.3 ++#define IE_QUIET 40 // 802.11h d3.3 ++#define IE_IBSS_DFS 41 // 802.11h d3.3 ++#define IE_ERP 42 // 802.11g ++#define IE_TS_DELAY 43 // 802.11e d9 ++#define IE_TCLAS_PROCESSING 44 // 802.11e d9 ++#define IE_QOS_CAPABILITY 46 // 802.11e d6 ++#define IE_HT_CAP 45 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD ++#define IE_AP_CHANNEL_REPORT 51 // 802.11k d6 ++#define IE_HT_CAP2 52 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD ++#define IE_RSN 48 // 802.11i d3.0 ++#define IE_WPA2 48 // WPA2 ++#define IE_EXT_SUPP_RATES 50 // 802.11g ++#define IE_SUPP_REG_CLASS 59 // 802.11y. Supported regulatory classes. ++#define IE_EXT_CHANNEL_SWITCH_ANNOUNCEMENT 60 // 802.11n ++#define IE_ADD_HT 61 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD ++#define IE_ADD_HT2 53 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD ++ ++ ++// For 802.11n D3.03 ++//#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet ++#define IE_SECONDARY_CH_OFFSET 62 // 802.11n D3.03 Secondary Channel Offset element ++#define IE_2040_BSS_COEXIST 72 // 802.11n D3.0.3 ++#define IE_2040_BSS_INTOLERANT_REPORT 73 // 802.11n D3.03 ++#define IE_OVERLAPBSS_SCAN_PARM 74 // 802.11n D3.03 ++#define IE_EXT_CAPABILITY 127 // 802.11n D3.03 ++ ++ ++#define IE_WPA 221 // WPA ++#define IE_VENDOR_SPECIFIC 221 // Wifi WMM (WME) ++ ++#define OUI_BROADCOM_HT 51 // ++#define OUI_BROADCOM_HTADD 52 // ++#define OUI_PREN_HT_CAP 51 // ++#define OUI_PREN_ADD_HT 52 // ++ ++// CCX information ++#define IE_AIRONET_CKIP 133 // CCX1.0 ID 85H for CKIP ++#define IE_AP_TX_POWER 150 // CCX 2.0 for AP transmit power ++#define IE_MEASUREMENT_CAPABILITY 221 // CCX 2.0 ++#define IE_CCX_V2 221 ++#define IE_AIRONET_IPADDRESS 149 // CCX ID 95H for IP Address ++#define IE_AIRONET_CCKMREASSOC 156 // CCX ID 9CH for CCKM Reassociation Request element ++#define CKIP_NEGOTIATION_LENGTH 30 ++#define AIRONET_IPADDRESS_LENGTH 10 ++#define AIRONET_CCKMREASSOC_LENGTH 24 ++ ++// ======================================================== ++// MLME state machine definition ++// ======================================================== ++ ++// STA MLME state mahcines ++#define ASSOC_STATE_MACHINE 1 ++#define AUTH_STATE_MACHINE 2 ++#define AUTH_RSP_STATE_MACHINE 3 ++#define SYNC_STATE_MACHINE 4 ++#define MLME_CNTL_STATE_MACHINE 5 ++#define WPA_PSK_STATE_MACHINE 6 ++#define LEAP_STATE_MACHINE 7 ++#define AIRONET_STATE_MACHINE 8 ++#define ACTION_STATE_MACHINE 9 ++ ++// AP MLME state machines ++#define AP_ASSOC_STATE_MACHINE 11 ++#define AP_AUTH_STATE_MACHINE 12 ++#define AP_AUTH_RSP_STATE_MACHINE 13 ++#define AP_SYNC_STATE_MACHINE 14 ++#define AP_CNTL_STATE_MACHINE 15 ++#define AP_WPA_STATE_MACHINE 16 ++ ++#ifdef QOS_DLS_SUPPORT ++#define DLS_STATE_MACHINE 26 ++#endif // QOS_DLS_SUPPORT // ++ ++// ++// STA's CONTROL/CONNECT state machine: states, events, total function # ++// ++#define CNTL_IDLE 0 ++#define CNTL_WAIT_DISASSOC 1 ++#define CNTL_WAIT_JOIN 2 ++#define CNTL_WAIT_REASSOC 3 ++#define CNTL_WAIT_START 4 ++#define CNTL_WAIT_AUTH 5 ++#define CNTL_WAIT_ASSOC 6 ++#define CNTL_WAIT_AUTH2 7 ++#define CNTL_WAIT_OID_LIST_SCAN 8 ++#define CNTL_WAIT_OID_DISASSOC 9 ++ ++#define MT2_ASSOC_CONF 34 ++#define MT2_AUTH_CONF 35 ++#define MT2_DEAUTH_CONF 36 ++#define MT2_DISASSOC_CONF 37 ++#define MT2_REASSOC_CONF 38 ++#define MT2_PWR_MGMT_CONF 39 ++#define MT2_JOIN_CONF 40 ++#define MT2_SCAN_CONF 41 ++#define MT2_START_CONF 42 ++#define MT2_GET_CONF 43 ++#define MT2_SET_CONF 44 ++#define MT2_RESET_CONF 45 ++#define MT2_MLME_ROAMING_REQ 52 ++ ++#define CNTL_FUNC_SIZE 1 ++ ++// ++// STA's ASSOC state machine: states, events, total function # ++// ++#define ASSOC_IDLE 0 ++#define ASSOC_WAIT_RSP 1 ++#define REASSOC_WAIT_RSP 2 ++#define DISASSOC_WAIT_RSP 3 ++#define MAX_ASSOC_STATE 4 ++ ++#define ASSOC_MACHINE_BASE 0 ++#define MT2_MLME_ASSOC_REQ 0 ++#define MT2_MLME_REASSOC_REQ 1 ++#define MT2_MLME_DISASSOC_REQ 2 ++#define MT2_PEER_DISASSOC_REQ 3 ++#define MT2_PEER_ASSOC_REQ 4 ++#define MT2_PEER_ASSOC_RSP 5 ++#define MT2_PEER_REASSOC_REQ 6 ++#define MT2_PEER_REASSOC_RSP 7 ++#define MT2_DISASSOC_TIMEOUT 8 ++#define MT2_ASSOC_TIMEOUT 9 ++#define MT2_REASSOC_TIMEOUT 10 ++#define MAX_ASSOC_MSG 11 ++ ++#define ASSOC_FUNC_SIZE (MAX_ASSOC_STATE * MAX_ASSOC_MSG) ++ ++// ++// ACT state machine: states, events, total function # ++// ++#define ACT_IDLE 0 ++#define MAX_ACT_STATE 1 ++ ++#define ACT_MACHINE_BASE 0 ++ ++//Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. ++//Category ++#define MT2_PEER_SPECTRUM_CATE 0 ++#define MT2_PEER_QOS_CATE 1 ++#define MT2_PEER_DLS_CATE 2 ++#define MT2_PEER_BA_CATE 3 ++#define MT2_PEER_PUBLIC_CATE 4 ++#define MT2_PEER_RM_CATE 5 ++#define MT2_PEER_HT_CATE 7 // 7.4.7 ++#define MAX_PEER_CATE_MSG 7 ++#define MT2_MLME_ADD_BA_CATE 8 ++#define MT2_MLME_ORI_DELBA_CATE 9 ++#define MT2_MLME_REC_DELBA_CATE 10 ++#define MT2_MLME_QOS_CATE 11 ++#define MT2_MLME_DLS_CATE 12 ++#define MT2_ACT_INVALID 13 ++#define MAX_ACT_MSG 14 ++ ++//Category field ++#define CATEGORY_SPECTRUM 0 ++#define CATEGORY_QOS 1 ++#define CATEGORY_DLS 2 ++#define CATEGORY_BA 3 ++#define CATEGORY_PUBLIC 4 ++#define CATEGORY_RM 5 ++#define CATEGORY_HT 7 ++ ++ ++// DLS Action frame definition ++#define ACTION_DLS_REQUEST 0 ++#define ACTION_DLS_RESPONSE 1 ++#define ACTION_DLS_TEARDOWN 2 ++ ++//Spectrum Action field value 802.11h 7.4.1 ++#define SPEC_MRQ 0 // Request ++#define SPEC_MRP 1 //Report ++#define SPEC_TPCRQ 2 ++#define SPEC_TPCRP 3 ++#define SPEC_CHANNEL_SWITCH 4 ++ ++ ++//BA Action field value ++#define ADDBA_REQ 0 ++#define ADDBA_RESP 1 ++#define DELBA 2 ++ ++//Public's Action field value in Public Category. Some in 802.11y and some in 11n ++#define ACTION_BSS_2040_COEXIST 0 // 11n ++#define ACTION_DSE_ENABLEMENT 1 // 11y D9.0 ++#define ACTION_DSE_DEENABLEMENT 2 // 11y D9.0 ++#define ACTION_DSE_REG_LOCATION_ANNOUNCE 3 // 11y D9.0 ++#define ACTION_EXT_CH_SWITCH_ANNOUNCE 4 // 11y D9.0 ++#define ACTION_DSE_MEASUREMENT_REQ 5 // 11y D9.0 ++#define ACTION_DSE_MEASUREMENT_REPORT 6 // 11y D9.0 ++#define ACTION_MEASUREMENT_PILOT_ACTION 7 // 11y D9.0 ++#define ACTION_DSE_POWER_CONSTRAINT 8 // 11y D9.0 ++ ++ ++//HT Action field value ++#define NOTIFY_BW_ACTION 0 ++#define SMPS_ACTION 1 ++#define PSMP_ACTION 2 ++#define SETPCO_ACTION 3 ++#define MIMO_CHA_MEASURE_ACTION 4 ++#define MIMO_N_BEACONFORM 5 ++#define MIMO_BEACONFORM 6 ++#define ANTENNA_SELECT 7 ++#define HT_INFO_EXCHANGE 8 ++ ++#define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG) ++// ++// STA's AUTHENTICATION state machine: states, evvents, total function # ++// ++#define AUTH_REQ_IDLE 0 ++#define AUTH_WAIT_SEQ2 1 ++#define AUTH_WAIT_SEQ4 2 ++#define MAX_AUTH_STATE 3 ++ ++#define AUTH_MACHINE_BASE 0 ++#define MT2_MLME_AUTH_REQ 0 ++#define MT2_PEER_AUTH_EVEN 1 ++#define MT2_AUTH_TIMEOUT 2 ++#define MAX_AUTH_MSG 3 ++ ++#define AUTH_FUNC_SIZE (MAX_AUTH_STATE * MAX_AUTH_MSG) ++ ++// ++// STA's AUTH_RSP state machine: states, events, total function # ++// ++#define AUTH_RSP_IDLE 0 ++#define AUTH_RSP_WAIT_CHAL 1 ++#define MAX_AUTH_RSP_STATE 2 ++ ++#define AUTH_RSP_MACHINE_BASE 0 ++#define MT2_AUTH_CHALLENGE_TIMEOUT 0 ++#define MT2_PEER_AUTH_ODD 1 ++#define MT2_PEER_DEAUTH 2 ++#define MAX_AUTH_RSP_MSG 3 ++ ++#define AUTH_RSP_FUNC_SIZE (MAX_AUTH_RSP_STATE * MAX_AUTH_RSP_MSG) ++ ++// ++// STA's SYNC state machine: states, events, total function # ++// ++#define SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define JOIN_WAIT_BEACON 1 ++#define SCAN_LISTEN 2 ++#define MAX_SYNC_STATE 3 ++ ++#define SYNC_MACHINE_BASE 0 ++#define MT2_MLME_SCAN_REQ 0 ++#define MT2_MLME_JOIN_REQ 1 ++#define MT2_MLME_START_REQ 2 ++#define MT2_PEER_BEACON 3 ++#define MT2_PEER_PROBE_RSP 4 ++#define MT2_PEER_ATIM 5 ++#define MT2_SCAN_TIMEOUT 6 ++#define MT2_BEACON_TIMEOUT 7 ++#define MT2_ATIM_TIMEOUT 8 ++#define MT2_PEER_PROBE_REQ 9 ++#define MAX_SYNC_MSG 10 ++ ++#define SYNC_FUNC_SIZE (MAX_SYNC_STATE * MAX_SYNC_MSG) ++ ++//Messages for the DLS state machine ++#define DLS_IDLE 0 ++#define MAX_DLS_STATE 1 ++ ++#define DLS_MACHINE_BASE 0 ++#define MT2_MLME_DLS_REQ 0 ++#define MT2_PEER_DLS_REQ 1 ++#define MT2_PEER_DLS_RSP 2 ++#define MT2_MLME_DLS_TEAR_DOWN 3 ++#define MT2_PEER_DLS_TEAR_DOWN 4 ++#define MAX_DLS_MSG 5 ++ ++#define DLS_FUNC_SIZE (MAX_DLS_STATE * MAX_DLS_MSG) ++ ++// ++// STA's WPA-PSK State machine: states, events, total function # ++// ++#define WPA_PSK_IDLE 0 ++#define MAX_WPA_PSK_STATE 1 ++ ++#define WPA_MACHINE_BASE 0 ++#define MT2_EAPPacket 0 ++#define MT2_EAPOLStart 1 ++#define MT2_EAPOLLogoff 2 ++#define MT2_EAPOLKey 3 ++#define MT2_EAPOLASFAlert 4 ++#define MAX_WPA_PSK_MSG 5 ++ ++#define WPA_PSK_FUNC_SIZE (MAX_WPA_PSK_STATE * MAX_WPA_PSK_MSG) ++ ++// ++// STA's CISCO-AIRONET State machine: states, events, total function # ++// ++#define AIRONET_IDLE 0 ++#define AIRONET_SCANNING 1 ++#define MAX_AIRONET_STATE 2 ++ ++#define AIRONET_MACHINE_BASE 0 ++#define MT2_AIRONET_MSG 0 ++#define MT2_AIRONET_SCAN_REQ 1 ++#define MT2_AIRONET_SCAN_DONE 2 ++#define MAX_AIRONET_MSG 3 ++ ++#define AIRONET_FUNC_SIZE (MAX_AIRONET_STATE * MAX_AIRONET_MSG) ++ ++// ++// AP's CONTROL/CONNECT state machine: states, events, total function # ++// ++#define AP_CNTL_FUNC_SIZE 1 ++ ++// ++// AP's ASSOC state machine: states, events, total function # ++// ++#define AP_ASSOC_IDLE 0 ++#define AP_MAX_ASSOC_STATE 1 ++ ++#define AP_ASSOC_MACHINE_BASE 0 ++#define APMT2_MLME_DISASSOC_REQ 0 ++#define APMT2_PEER_DISASSOC_REQ 1 ++#define APMT2_PEER_ASSOC_REQ 2 ++#define APMT2_PEER_REASSOC_REQ 3 ++#define APMT2_CLS3ERR 4 ++#define AP_MAX_ASSOC_MSG 5 ++ ++#define AP_ASSOC_FUNC_SIZE (AP_MAX_ASSOC_STATE * AP_MAX_ASSOC_MSG) ++ ++// ++// AP's AUTHENTICATION state machine: states, events, total function # ++// ++#define AP_AUTH_REQ_IDLE 0 ++#define AP_MAX_AUTH_STATE 1 ++ ++#define AP_AUTH_MACHINE_BASE 0 ++#define APMT2_MLME_DEAUTH_REQ 0 ++#define APMT2_CLS2ERR 1 ++#define AP_MAX_AUTH_MSG 2 ++ ++#define AP_AUTH_FUNC_SIZE (AP_MAX_AUTH_STATE * AP_MAX_AUTH_MSG) ++ ++// ++// AP's AUTH-RSP state machine: states, events, total function # ++// ++#define AP_AUTH_RSP_IDLE 0 ++#define AP_MAX_AUTH_RSP_STATE 1 ++ ++#define AP_AUTH_RSP_MACHINE_BASE 0 ++#define APMT2_AUTH_CHALLENGE_TIMEOUT 0 ++#define APMT2_PEER_AUTH_ODD 1 ++#define APMT2_PEER_DEAUTH 2 ++#define AP_MAX_AUTH_RSP_MSG 3 ++ ++#define AP_AUTH_RSP_FUNC_SIZE (AP_MAX_AUTH_RSP_STATE * AP_MAX_AUTH_RSP_MSG) ++ ++// ++// AP's SYNC state machine: states, events, total function # ++// ++#define AP_SYNC_IDLE 0 ++#define AP_SCAN_LISTEN 1 ++#define AP_MAX_SYNC_STATE 2 ++ ++#define AP_SYNC_MACHINE_BASE 0 ++#define APMT2_PEER_PROBE_REQ 0 ++#define APMT2_PEER_BEACON 1 ++#define APMT2_MLME_SCAN_REQ 2 ++#define APMT2_PEER_PROBE_RSP 3 ++#define APMT2_SCAN_TIMEOUT 4 ++#define APMT2_MLME_SCAN_CNCL 5 ++#define AP_MAX_SYNC_MSG 6 ++ ++#define AP_SYNC_FUNC_SIZE (AP_MAX_SYNC_STATE * AP_MAX_SYNC_MSG) ++ ++// ++// AP's WPA state machine: states, events, total function # ++// ++#define AP_WPA_PTK 0 ++#define AP_MAX_WPA_PTK_STATE 1 ++ ++#define AP_WPA_MACHINE_BASE 0 ++#define APMT2_EAPPacket 0 ++#define APMT2_EAPOLStart 1 ++#define APMT2_EAPOLLogoff 2 ++#define APMT2_EAPOLKey 3 ++#define APMT2_EAPOLASFAlert 4 ++#define AP_MAX_WPA_MSG 5 ++ ++#define AP_WPA_FUNC_SIZE (AP_MAX_WPA_PTK_STATE * AP_MAX_WPA_MSG) ++ ++#ifdef APCLI_SUPPORT ++//ApCli authentication state machine ++#define APCLI_AUTH_REQ_IDLE 0 ++#define APCLI_AUTH_WAIT_SEQ2 1 ++#define APCLI_AUTH_WAIT_SEQ4 2 ++#define APCLI_MAX_AUTH_STATE 3 ++ ++#define APCLI_AUTH_MACHINE_BASE 0 ++#define APCLI_MT2_MLME_AUTH_REQ 0 ++#define APCLI_MT2_MLME_DEAUTH_REQ 1 ++#define APCLI_MT2_PEER_AUTH_EVEN 2 ++#define APCLI_MT2_PEER_DEAUTH 3 ++#define APCLI_MT2_AUTH_TIMEOUT 4 ++#define APCLI_MAX_AUTH_MSG 5 ++ ++#define APCLI_AUTH_FUNC_SIZE (APCLI_MAX_AUTH_STATE * APCLI_MAX_AUTH_MSG) ++ ++//ApCli association state machine ++#define APCLI_ASSOC_IDLE 0 ++#define APCLI_ASSOC_WAIT_RSP 1 ++#define APCLI_MAX_ASSOC_STATE 2 ++ ++#define APCLI_ASSOC_MACHINE_BASE 0 ++#define APCLI_MT2_MLME_ASSOC_REQ 0 ++#define APCLI_MT2_MLME_DISASSOC_REQ 1 ++#define APCLI_MT2_PEER_DISASSOC_REQ 2 ++#define APCLI_MT2_PEER_ASSOC_RSP 3 ++#define APCLI_MT2_ASSOC_TIMEOUT 4 ++#define APCLI_MAX_ASSOC_MSG 5 ++ ++#define APCLI_ASSOC_FUNC_SIZE (APCLI_MAX_ASSOC_STATE * APCLI_MAX_ASSOC_MSG) ++ ++//ApCli sync state machine ++#define APCLI_SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define APCLI_JOIN_WAIT_PROBE_RSP 1 ++#define APCLI_MAX_SYNC_STATE 2 ++ ++#define APCLI_SYNC_MACHINE_BASE 0 ++#define APCLI_MT2_MLME_PROBE_REQ 0 ++#define APCLI_MT2_PEER_PROBE_RSP 1 ++#define APCLI_MT2_PROBE_TIMEOUT 2 ++#define APCLI_MAX_SYNC_MSG 3 ++ ++#define APCLI_SYNC_FUNC_SIZE (APCLI_MAX_SYNC_STATE * APCLI_MAX_SYNC_MSG) ++ ++//ApCli ctrl state machine ++#define APCLI_CTRL_DISCONNECTED 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define APCLI_CTRL_PROBE 1 ++#define APCLI_CTRL_AUTH 2 ++#define APCLI_CTRL_AUTH_2 3 ++#define APCLI_CTRL_ASSOC 4 ++#define APCLI_CTRL_DEASSOC 5 ++#define APCLI_CTRL_CONNECTED 6 ++#define APCLI_MAX_CTRL_STATE 7 ++ ++#define APCLI_CTRL_MACHINE_BASE 0 ++#define APCLI_CTRL_JOIN_REQ 0 ++#define APCLI_CTRL_PROBE_RSP 1 ++#define APCLI_CTRL_AUTH_RSP 2 ++#define APCLI_CTRL_DISCONNECT_REQ 3 ++#define APCLI_CTRL_PEER_DISCONNECT_REQ 4 ++#define APCLI_CTRL_ASSOC_RSP 5 ++#define APCLI_CTRL_DEASSOC_RSP 6 ++#define APCLI_CTRL_JOIN_REQ_TIMEOUT 7 ++#define APCLI_CTRL_AUTH_REQ_TIMEOUT 8 ++#define APCLI_CTRL_ASSOC_REQ_TIMEOUT 9 ++#define APCLI_MAX_CTRL_MSG 10 ++ ++#define APCLI_CTRL_FUNC_SIZE (APCLI_MAX_CTRL_STATE * APCLI_MAX_CTRL_MSG) ++ ++#endif // APCLI_SUPPORT // ++ ++ ++// ============================================================================= ++ ++// value domain of 802.11 header FC.Tyte, which is b3..b2 of the 1st-byte of MAC header ++#define BTYPE_MGMT 0 ++#define BTYPE_CNTL 1 ++#define BTYPE_DATA 2 ++ ++// value domain of 802.11 MGMT frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_ASSOC_REQ 0 ++#define SUBTYPE_ASSOC_RSP 1 ++#define SUBTYPE_REASSOC_REQ 2 ++#define SUBTYPE_REASSOC_RSP 3 ++#define SUBTYPE_PROBE_REQ 4 ++#define SUBTYPE_PROBE_RSP 5 ++#define SUBTYPE_BEACON 8 ++#define SUBTYPE_ATIM 9 ++#define SUBTYPE_DISASSOC 10 ++#define SUBTYPE_AUTH 11 ++#define SUBTYPE_DEAUTH 12 ++#define SUBTYPE_ACTION 13 ++#define SUBTYPE_ACTION_NO_ACK 14 ++ ++// value domain of 802.11 CNTL frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_WRAPPER 7 ++#define SUBTYPE_BLOCK_ACK_REQ 8 ++#define SUBTYPE_BLOCK_ACK 9 ++#define SUBTYPE_PS_POLL 10 ++#define SUBTYPE_RTS 11 ++#define SUBTYPE_CTS 12 ++#define SUBTYPE_ACK 13 ++#define SUBTYPE_CFEND 14 ++#define SUBTYPE_CFEND_CFACK 15 ++ ++// value domain of 802.11 DATA frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_DATA 0 ++#define SUBTYPE_DATA_CFACK 1 ++#define SUBTYPE_DATA_CFPOLL 2 ++#define SUBTYPE_DATA_CFACK_CFPOLL 3 ++#define SUBTYPE_NULL_FUNC 4 ++#define SUBTYPE_CFACK 5 ++#define SUBTYPE_CFPOLL 6 ++#define SUBTYPE_CFACK_CFPOLL 7 ++#define SUBTYPE_QDATA 8 ++#define SUBTYPE_QDATA_CFACK 9 ++#define SUBTYPE_QDATA_CFPOLL 10 ++#define SUBTYPE_QDATA_CFACK_CFPOLL 11 ++#define SUBTYPE_QOS_NULL 12 ++#define SUBTYPE_QOS_CFACK 13 ++#define SUBTYPE_QOS_CFPOLL 14 ++#define SUBTYPE_QOS_CFACK_CFPOLL 15 ++ ++// ACK policy of QOS Control field bit 6:5 ++#define NORMAL_ACK 0x00 // b6:5 = 00 ++#define NO_ACK 0x20 // b6:5 = 01 ++#define NO_EXPLICIT_ACK 0x40 // b6:5 = 10 ++#define BLOCK_ACK 0x60 // b6:5 = 11 ++ ++// ++// rtmp_data.c use these definition ++// ++#define LENGTH_802_11 24 ++#define LENGTH_802_11_AND_H 30 ++#define LENGTH_802_11_CRC_H 34 ++#define LENGTH_802_11_CRC 28 ++#define LENGTH_802_11_WITH_ADDR4 30 ++#define LENGTH_802_3 14 ++#define LENGTH_802_3_TYPE 2 ++#define LENGTH_802_1_H 8 ++#define LENGTH_EAPOL_H 4 ++#define LENGTH_WMMQOS_H 2 ++#define LENGTH_CRC 4 ++#define MAX_SEQ_NUMBER 0x0fff ++#define LENGTH_802_3_NO_TYPE 12 ++#define LENGTH_802_1Q 4 /* VLAN related */ ++ ++// STA_CSR4.field.TxResult ++#define TX_RESULT_SUCCESS 0 ++#define TX_RESULT_ZERO_LENGTH 1 ++#define TX_RESULT_UNDER_RUN 2 ++#define TX_RESULT_OHY_ERROR 4 ++#define TX_RESULT_RETRY_FAIL 6 ++ ++// All PHY rate summary in TXD ++// Preamble MODE in TxD ++#define MODE_CCK 0 ++#define MODE_OFDM 1 ++#ifdef DOT11_N_SUPPORT ++#define MODE_HTMIX 2 ++#define MODE_HTGREENFIELD 3 ++#endif // DOT11_N_SUPPORT // ++// MCS for CCK. BW.SGI.STBC are reserved ++#define MCS_LONGP_RATE_1 0 // long preamble CCK 1Mbps ++#define MCS_LONGP_RATE_2 1 // long preamble CCK 1Mbps ++#define MCS_LONGP_RATE_5_5 2 ++#define MCS_LONGP_RATE_11 3 ++#define MCS_SHORTP_RATE_1 4 // long preamble CCK 1Mbps. short is forbidden in 1Mbps ++#define MCS_SHORTP_RATE_2 5 // short preamble CCK 2Mbps ++#define MCS_SHORTP_RATE_5_5 6 ++#define MCS_SHORTP_RATE_11 7 ++// To send duplicate legacy OFDM. set BW=BW_40. SGI.STBC are reserved ++#define MCS_RATE_6 0 // legacy OFDM ++#define MCS_RATE_9 1 // OFDM ++#define MCS_RATE_12 2 // OFDM ++#define MCS_RATE_18 3 // OFDM ++#define MCS_RATE_24 4 // OFDM ++#define MCS_RATE_36 5 // OFDM ++#define MCS_RATE_48 6 // OFDM ++#define MCS_RATE_54 7 // OFDM ++// HT ++#define MCS_0 0 // 1S ++#define MCS_1 1 ++#define MCS_2 2 ++#define MCS_3 3 ++#define MCS_4 4 ++#define MCS_5 5 ++#define MCS_6 6 ++#define MCS_7 7 ++#define MCS_8 8 // 2S ++#define MCS_9 9 ++#define MCS_10 10 ++#define MCS_11 11 ++#define MCS_12 12 ++#define MCS_13 13 ++#define MCS_14 14 ++#define MCS_15 15 ++#define MCS_16 16 // 3*3 ++#define MCS_17 17 ++#define MCS_18 18 ++#define MCS_19 19 ++#define MCS_20 20 ++#define MCS_21 21 ++#define MCS_22 22 ++#define MCS_23 23 ++#define MCS_32 32 ++#define MCS_AUTO 33 ++ ++#ifdef DOT11_N_SUPPORT ++// OID_HTPHYMODE ++// MODE ++#define HTMODE_MM 0 ++#define HTMODE_GF 1 ++#endif // DOT11_N_SUPPORT // ++ ++// Fixed Tx MODE - HT, CCK or OFDM ++#define FIXED_TXMODE_HT 0 ++#define FIXED_TXMODE_CCK 1 ++#define FIXED_TXMODE_OFDM 2 ++// BW ++#define BW_20 BAND_WIDTH_20 ++#define BW_40 BAND_WIDTH_40 ++#define BW_BOTH BAND_WIDTH_BOTH ++#define BW_10 BAND_WIDTH_10 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. ++ ++#ifdef DOT11_N_SUPPORT ++// SHORTGI ++#define GI_400 GAP_INTERVAL_400 // only support in HT mode ++#define GI_BOTH GAP_INTERVAL_BOTH ++#endif // DOT11_N_SUPPORT // ++#define GI_800 GAP_INTERVAL_800 ++// STBC ++#define STBC_NONE 0 ++#ifdef DOT11_N_SUPPORT ++#define STBC_USE 1 // limited use in rt2860b phy ++#define RXSTBC_ONE 1 // rx support of one spatial stream ++#define RXSTBC_TWO 2 // rx support of 1 and 2 spatial stream ++#define RXSTBC_THR 3 // rx support of 1~3 spatial stream ++// MCS FEEDBACK ++#define MCSFBK_NONE 0 // not support mcs feedback / ++#define MCSFBK_RSV 1 // reserved ++#define MCSFBK_UNSOLICIT 2 // only support unsolict mcs feedback ++#define MCSFBK_MRQ 3 // response to both MRQ and unsolict mcs feedback ++ ++// MIMO power safe ++#define MMPS_STATIC 0 ++#define MMPS_DYNAMIC 1 ++#define MMPS_RSV 2 ++#define MMPS_ENABLE 3 ++ ++ ++// A-MSDU size ++#define AMSDU_0 0 ++#define AMSDU_1 1 ++ ++#endif // DOT11_N_SUPPORT // ++ ++// MCS use 7 bits ++#define TXRATEMIMO 0x80 ++#define TXRATEMCS 0x7F ++#define TXRATEOFDM 0x7F ++#define RATE_1 0 ++#define RATE_2 1 ++#define RATE_5_5 2 ++#define RATE_11 3 ++#define RATE_6 4 // OFDM ++#define RATE_9 5 // OFDM ++#define RATE_12 6 // OFDM ++#define RATE_18 7 // OFDM ++#define RATE_24 8 // OFDM ++#define RATE_36 9 // OFDM ++#define RATE_48 10 // OFDM ++#define RATE_54 11 // OFDM ++#define RATE_FIRST_OFDM_RATE RATE_6 ++#define RATE_LAST_OFDM_RATE RATE_54 ++#define RATE_6_5 12 // HT mix ++#define RATE_13 13 // HT mix ++#define RATE_19_5 14 // HT mix ++#define RATE_26 15 // HT mix ++#define RATE_39 16 // HT mix ++#define RATE_52 17 // HT mix ++#define RATE_58_5 18 // HT mix ++#define RATE_65 19 // HT mix ++#define RATE_78 20 // HT mix ++#define RATE_104 21 // HT mix ++#define RATE_117 22 // HT mix ++#define RATE_130 23 // HT mix ++//#define RATE_AUTO_SWITCH 255 // for StaCfg.FixedTxRate only ++#define HTRATE_0 12 ++#define RATE_FIRST_MM_RATE HTRATE_0 ++#define RATE_FIRST_HT_RATE HTRATE_0 ++#define RATE_LAST_HT_RATE HTRATE_0 ++ ++// pTxWI->txop ++#define IFS_HTTXOP 0 // The txop will be handles by ASIC. ++#define IFS_PIFS 1 ++#define IFS_SIFS 2 ++#define IFS_BACKOFF 3 ++ ++// pTxD->RetryMode ++#define LONG_RETRY 1 ++#define SHORT_RETRY 0 ++ ++// Country Region definition ++#define REGION_MINIMUM_BG_BAND 0 ++#define REGION_0_BG_BAND 0 // 1-11 ++#define REGION_1_BG_BAND 1 // 1-13 ++#define REGION_2_BG_BAND 2 // 10-11 ++#define REGION_3_BG_BAND 3 // 10-13 ++#define REGION_4_BG_BAND 4 // 14 ++#define REGION_5_BG_BAND 5 // 1-14 ++#define REGION_6_BG_BAND 6 // 3-9 ++#define REGION_7_BG_BAND 7 // 5-13 ++#define REGION_31_BG_BAND 31 // 5-13 ++#define REGION_MAXIMUM_BG_BAND 7 ++ ++#define REGION_MINIMUM_A_BAND 0 ++#define REGION_0_A_BAND 0 // 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165 ++#define REGION_1_A_BAND 1 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 ++#define REGION_2_A_BAND 2 // 36, 40, 44, 48, 52, 56, 60, 64 ++#define REGION_3_A_BAND 3 // 52, 56, 60, 64, 149, 153, 157, 161 ++#define REGION_4_A_BAND 4 // 149, 153, 157, 161, 165 ++#define REGION_5_A_BAND 5 // 149, 153, 157, 161 ++#define REGION_6_A_BAND 6 // 36, 40, 44, 48 ++#define REGION_7_A_BAND 7 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 ++#define REGION_8_A_BAND 8 // 52, 56, 60, 64 ++#define REGION_9_A_BAND 9 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165 ++#define REGION_10_A_BAND 10 // 36, 40, 44, 48, 149, 153, 157, 161, 165 ++#define REGION_11_A_BAND 11 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161 ++#define REGION_MAXIMUM_A_BAND 11 ++ ++// pTxD->CipherAlg ++#define CIPHER_NONE 0 ++#define CIPHER_WEP64 1 ++#define CIPHER_WEP128 2 ++#define CIPHER_TKIP 3 ++#define CIPHER_AES 4 ++#define CIPHER_CKIP64 5 ++#define CIPHER_CKIP128 6 ++#define CIPHER_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table ++#define CIPHER_SMS4 8 ++ ++// value domain of pAd->RfIcType ++#define RFIC_2820 1 // 2.4G 2T3R ++#define RFIC_2850 2 // 2.4G/5G 2T3R ++#define RFIC_2720 3 // 2.4G 1T2R ++#define RFIC_2750 4 // 2.4G/5G 1T2R ++#define RFIC_3020 5 // 2.4G 1T1R ++#define RFIC_2020 6 // 2.4G B/G ++ ++// LED Status. ++#define LED_LINK_DOWN 0 ++#define LED_LINK_UP 1 ++#define LED_RADIO_OFF 2 ++#define LED_RADIO_ON 3 ++#define LED_HALT 4 ++#define LED_WPS 5 ++#define LED_ON_SITE_SURVEY 6 ++#define LED_POWER_UP 7 ++ ++// value domain of pAd->LedCntl.LedMode and E2PROM ++#define LED_MODE_DEFAULT 0 ++#define LED_MODE_TWO_LED 1 ++#define LED_MODE_SIGNAL_STREGTH 8 // EEPROM define =8 ++ ++// RC4 init value, used fro WEP & TKIP ++#define PPPINITFCS32 0xffffffff /* Initial FCS value */ ++ ++// value domain of pAd->StaCfg.PortSecured. 802.1X controlled port definition ++#define WPA_802_1X_PORT_SECURED 1 ++#define WPA_802_1X_PORT_NOT_SECURED 2 ++ ++#define PAIRWISE_KEY 1 ++#define GROUP_KEY 2 ++ ++//definition of DRS ++#define MAX_STEP_OF_TX_RATE_SWITCH 32 ++ ++ ++// pre-allocated free NDIS PACKET/BUFFER poll for internal usage ++#define MAX_NUM_OF_FREE_NDIS_PACKET 128 ++ ++//Block ACK ++#define MAX_TX_REORDERBUF 64 ++#define MAX_RX_REORDERBUF 64 ++#define DEFAULT_TX_TIMEOUT 30 ++#define DEFAULT_RX_TIMEOUT 30 ++ ++// definition of Recipient or Originator ++#define I_RECIPIENT TRUE ++#define I_ORIGINATOR FALSE ++ ++#define DEFAULT_BBP_TX_POWER 0 ++#define DEFAULT_RF_TX_POWER 5 ++ ++#define MAX_INI_BUFFER_SIZE 4096 ++#define MAX_PARAM_BUFFER_SIZE (2048) // enough for ACL (18*64) ++ //18 : the length of Mac address acceptable format "01:02:03:04:05:06;") ++ //64 : MAX_NUM_OF_ACL_LIST ++// definition of pAd->OpMode ++#define OPMODE_STA 0 ++#define OPMODE_AP 1 ++//#define OPMODE_L3_BRG 2 // as AP and STA at the same time ++ ++#ifdef RT_BIG_ENDIAN ++#define DIR_READ 0 ++#define DIR_WRITE 1 ++#define TYPE_TXD 0 ++#define TYPE_RXD 1 ++#define TYPE_TXINFO 0 ++#define TYPE_RXINFO 1 ++#define TYPE_TXWI 0 ++#define TYPE_RXWI 1 ++#endif ++ ++// ========================= AP rtmp_def.h =========================== ++// value domain for pAd->EventTab.Log[].Event ++#define EVENT_RESET_ACCESS_POINT 0 // Log = "hh:mm:ss Restart Access Point" ++#define EVENT_ASSOCIATED 1 // Log = "hh:mm:ss STA 00:01:02:03:04:05 associated" ++#define EVENT_DISASSOCIATED 2 // Log = "hh:mm:ss STA 00:01:02:03:04:05 left this BSS" ++#define EVENT_AGED_OUT 3 // Log = "hh:mm:ss STA 00:01:02:03:04:05 was aged-out and removed from this BSS" ++#define EVENT_COUNTER_M 4 ++#define EVENT_INVALID_PSK 5 ++#define EVENT_MAX_EVENT_TYPE 6 ++// ==== end of AP rtmp_def.h ============ ++ ++// definition RSSI Number ++#define RSSI_0 0 ++#define RSSI_1 1 ++#define RSSI_2 2 ++ ++// definition of radar detection ++#define RD_NORMAL_MODE 0 // Not found radar signal ++#define RD_SWITCHING_MODE 1 // Found radar signal, and doing channel switch ++#define RD_SILENCE_MODE 2 // After channel switch, need to be silence a while to ensure radar not found ++ ++//Driver defined cid for mapping status and command. ++#define SLEEPCID 0x11 ++#define WAKECID 0x22 ++#define QUERYPOWERCID 0x33 ++#define OWNERMCU 0x1 ++#define OWNERCPU 0x0 ++ ++// MBSSID definition ++#define ENTRY_NOT_FOUND 0xFF ++ ++ ++/* After Linux 2.6.9, ++ * VLAN module use Private (from user) interface flags (netdevice->priv_flags). ++ * #define IFF_802_1Q_VLAN 0x1 -- 802.1Q VLAN device. in if.h ++ * ref to ip_sabotage_out() [ out->priv_flags & IFF_802_1Q_VLAN ] in br_netfilter.c ++ * ++ * For this reason, we MUST use EVEN value in priv_flags ++ */ ++#define INT_MAIN 0x0100 ++#define INT_MBSSID 0x0200 ++#define INT_WDS 0x0300 ++#define INT_APCLI 0x0400 ++#define INT_MESH 0x0500 ++ ++// Use bitmap to allow coexist of ATE_TXFRAME and ATE_RXFRAME(i.e.,to support LoopBack mode) ++#ifdef RALINK_ATE ++#define ATE_START 0x00 // Start ATE ++#define ATE_STOP 0x80 // Stop ATE ++#define ATE_TXCONT 0x05 // Continuous Transmit ++#define ATE_TXCARR 0x09 // Transmit Carrier ++#define ATE_TXCARRSUPP 0x11 // Transmit Carrier Suppression ++#define ATE_TXFRAME 0x01 // Transmit Frames ++#define ATE_RXFRAME 0x02 // Receive Frames ++#ifdef RALINK_28xx_QA ++#define ATE_TXSTOP 0xe2 // Stop Transmition(i.e., TXCONT, TXCARR, TXCARRSUPP, and TXFRAME) ++#define ATE_RXSTOP 0xfd // Stop receiving Frames ++#define BBP22_TXFRAME 0x00 // Transmit Frames ++#define BBP22_TXCONT_OR_CARRSUPP 0x80 // Continuous Transmit or Carrier Suppression ++#define BBP22_TXCARR 0xc1 // Transmit Carrier ++#define BBP24_TXCONT 0x00 // Continuous Transmit ++#define BBP24_CARRSUPP 0x01 // Carrier Suppression ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++// WEP Key TYPE ++#define WEP_HEXADECIMAL_TYPE 0 ++#define WEP_ASCII_TYPE 1 ++ ++ ++ ++// WIRELESS EVENTS definition ++/* Max number of char in custom event, refer to wireless_tools.28/wireless.20.h */ ++#define IW_CUSTOM_MAX_LEN 255 /* In bytes */ ++ ++// For system event - start ++#define IW_SYS_EVENT_FLAG_START 0x0200 ++#define IW_ASSOC_EVENT_FLAG 0x0200 ++#define IW_DISASSOC_EVENT_FLAG 0x0201 ++#define IW_DEAUTH_EVENT_FLAG 0x0202 ++#define IW_AGEOUT_EVENT_FLAG 0x0203 ++#define IW_COUNTER_MEASURES_EVENT_FLAG 0x0204 ++#define IW_REPLAY_COUNTER_DIFF_EVENT_FLAG 0x0205 ++#define IW_RSNIE_DIFF_EVENT_FLAG 0x0206 ++#define IW_MIC_DIFF_EVENT_FLAG 0x0207 ++#define IW_ICV_ERROR_EVENT_FLAG 0x0208 ++#define IW_MIC_ERROR_EVENT_FLAG 0x0209 ++#define IW_GROUP_HS_TIMEOUT_EVENT_FLAG 0x020A ++#define IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG 0x020B ++#define IW_RSNIE_SANITY_FAIL_EVENT_FLAG 0x020C ++#define IW_SET_KEY_DONE_WPA1_EVENT_FLAG 0x020D ++#define IW_SET_KEY_DONE_WPA2_EVENT_FLAG 0x020E ++#define IW_STA_LINKUP_EVENT_FLAG 0x020F ++#define IW_STA_LINKDOWN_EVENT_FLAG 0x0210 ++#define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211 ++#define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212 ++// if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END ++#define IW_SYS_EVENT_FLAG_END 0x0212 ++#define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1) ++// For system event - end ++ ++// For spoof attack event - start ++#define IW_SPOOF_EVENT_FLAG_START 0x0300 ++#define IW_CONFLICT_SSID_EVENT_FLAG 0x0300 ++#define IW_SPOOF_ASSOC_RESP_EVENT_FLAG 0x0301 ++#define IW_SPOOF_REASSOC_RESP_EVENT_FLAG 0x0302 ++#define IW_SPOOF_PROBE_RESP_EVENT_FLAG 0x0303 ++#define IW_SPOOF_BEACON_EVENT_FLAG 0x0304 ++#define IW_SPOOF_DISASSOC_EVENT_FLAG 0x0305 ++#define IW_SPOOF_AUTH_EVENT_FLAG 0x0306 ++#define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307 ++#define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308 ++#define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309 ++// if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END ++#define IW_SPOOF_EVENT_FLAG_END 0x0309 ++#define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1) ++// For spoof attack event - end ++ ++// For flooding attack event - start ++#define IW_FLOOD_EVENT_FLAG_START 0x0400 ++#define IW_FLOOD_AUTH_EVENT_FLAG 0x0400 ++#define IW_FLOOD_ASSOC_REQ_EVENT_FLAG 0x0401 ++#define IW_FLOOD_REASSOC_REQ_EVENT_FLAG 0x0402 ++#define IW_FLOOD_PROBE_REQ_EVENT_FLAG 0x0403 ++#define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404 ++#define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405 ++#define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406 ++// if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END ++#define IW_FLOOD_EVENT_FLAG_END 0x0406 ++#define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1) ++// For flooding attack - end ++ ++// End - WIRELESS EVENTS definition ++ ++#ifdef CONFIG_STA_SUPPORT ++// definition for DLS, kathy ++#define MAX_NUM_OF_INIT_DLS_ENTRY 1 ++#define MAX_NUM_OF_DLS_ENTRY MAX_NUMBER_OF_DLS_ENTRY ++ ++//Block ACK , rt2860, kathy ++#define MAX_TX_REORDERBUF 64 ++#define MAX_RX_REORDERBUF 64 ++#define DEFAULT_TX_TIMEOUT 30 ++#define DEFAULT_RX_TIMEOUT 30 ++#ifndef CONFIG_AP_SUPPORT ++#define MAX_BARECI_SESSION 8 ++#endif ++ ++#ifndef IW_ESSID_MAX_SIZE ++/* Maximum size of the ESSID and pAd->nickname strings */ ++#define IW_ESSID_MAX_SIZE 32 ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef MCAST_RATE_SPECIFIC ++#define MCAST_DISABLE 0 ++#define MCAST_CCK 1 ++#define MCAST_OFDM 2 ++#define MCAST_HTMIX 3 ++#endif // MCAST_RATE_SPECIFIC // ++ ++// For AsicRadioOff/AsicRadioOn function ++#define DOT11POWERSAVE 0 ++#define GUIRADIO_OFF 1 ++#define RTMP_HALT 2 ++#define GUI_IDLE_POWER_SAVE 3 ++// -- ++ ++ ++// definition for WpaSupport flag ++#define WPA_SUPPLICANT_DISABLE 0 ++#define WPA_SUPPLICANT_ENABLE 1 ++#define WPA_SUPPLICANT_ENABLE_WITH_WEB_UI 2 ++ ++// Endian byte swapping codes ++#define SWAP16(x) \ ++ ((UINT16)( \ ++ (((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \ ++ (((UINT16)(x) & (UINT16) 0xff00U) >> 8) )) ++ ++#define SWAP32(x) \ ++ ((UINT32)( \ ++ (((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \ ++ (((UINT32)(x) & (UINT32) 0x0000ff00UL) << 8) | \ ++ (((UINT32)(x) & (UINT32) 0x00ff0000UL) >> 8) | \ ++ (((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) )) ++ ++#define SWAP64(x) \ ++ ((UINT64)( \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) << 8) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >> 8) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) ++ ++#ifdef RT_BIG_ENDIAN ++ ++#define cpu2le64(x) SWAP64((x)) ++#define le2cpu64(x) SWAP64((x)) ++#define cpu2le32(x) SWAP32((x)) ++#define le2cpu32(x) SWAP32((x)) ++#define cpu2le16(x) SWAP16((x)) ++#define le2cpu16(x) SWAP16((x)) ++#define cpu2be64(x) ((UINT64)(x)) ++#define be2cpu64(x) ((UINT64)(x)) ++#define cpu2be32(x) ((UINT32)(x)) ++#define be2cpu32(x) ((UINT32)(x)) ++#define cpu2be16(x) ((UINT16)(x)) ++#define be2cpu16(x) ((UINT16)(x)) ++ ++#else // Little_Endian ++ ++#define cpu2le64(x) ((UINT64)(x)) ++#define le2cpu64(x) ((UINT64)(x)) ++#define cpu2le32(x) ((UINT32)(x)) ++#define le2cpu32(x) ((UINT32)(x)) ++#define cpu2le16(x) ((UINT16)(x)) ++#define le2cpu16(x) ((UINT16)(x)) ++#define cpu2be64(x) SWAP64((x)) ++#define be2cpu64(x) SWAP64((x)) ++#define cpu2be32(x) SWAP32((x)) ++#define be2cpu32(x) SWAP32((x)) ++#define cpu2be16(x) SWAP16((x)) ++#define be2cpu16(x) SWAP16((x)) ++ ++#endif // RT_BIG_ENDIAN ++ ++#endif // __RTMP_DEF_H__ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rtmp.h +@@ -0,0 +1,7177 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp.h ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ James Tan 2002-09-06 modified (Revise NTCRegTable) ++ John Chang 2004-09-06 modified for RT2600 ++*/ ++#ifndef __RTMP_H__ ++#define __RTMP_H__ ++ ++#include "link_list.h" ++#include "spectrum_def.h" ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#include "aironet.h" ++#endif // CONFIG_STA_SUPPORT // ++ ++//#define DBG_DIAGNOSE 1 ++ ++#if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_STA_SUPPORT) ++#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) if(_pAd->OpMode == OPMODE_AP) ++#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) if(_pAd->OpMode == OPMODE_STA) ++#else ++#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) ++#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) ++#endif ++ ++#define VIRTUAL_IF_INC(__pAd) ((__pAd)->VirtualIfCnt++) ++#define VIRTUAL_IF_DEC(__pAd) ((__pAd)->VirtualIfCnt--) ++#define VIRTUAL_IF_NUM(__pAd) ((__pAd)->VirtualIfCnt) ++ ++ ++ ++// ++// NDIS Version definitions ++// ++#ifdef NDIS50_MINIPORT ++#define RTMP_NDIS_MAJOR_VERSION 5 ++#define RTMP_NDIS_MINOR_VERSION 0 ++#endif ++ ++#ifdef NDIS51_MINIPORT ++#define RTMP_NDIS_MAJOR_VERSION 5 ++#define RTMP_NDIS_MINOR_VERSION 1 ++#endif ++ ++extern char NIC_VENDOR_DESC[]; ++extern int NIC_VENDOR_DESC_LEN; ++ ++extern unsigned char SNAP_AIRONET[]; ++extern unsigned char CipherSuiteCiscoCCKM[]; ++extern unsigned char CipherSuiteCiscoCCKMLen; ++extern unsigned char CipherSuiteCiscoCCKM24[]; ++extern unsigned char CipherSuiteCiscoCCKM24Len; ++extern unsigned char CipherSuiteCCXTkip[]; ++extern unsigned char CipherSuiteCCXTkipLen; ++extern unsigned char CISCO_OUI[]; ++extern UCHAR BaSizeArray[4]; ++ ++extern UCHAR BROADCAST_ADDR[MAC_ADDR_LEN]; ++extern UCHAR MULTICAST_ADDR[MAC_ADDR_LEN]; ++extern UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN]; ++extern ULONG BIT32[32]; ++extern UCHAR BIT8[8]; ++extern char* CipherName[]; ++extern char* MCSToMbps[]; ++extern UCHAR RxwiMCSToOfdmRate[12]; ++extern UCHAR SNAP_802_1H[6]; ++extern UCHAR SNAP_BRIDGE_TUNNEL[6]; ++extern UCHAR SNAP_AIRONET[8]; ++extern UCHAR CKIP_LLC_SNAP[8]; ++extern UCHAR EAPOL_LLC_SNAP[8]; ++extern UCHAR EAPOL[2]; ++extern UCHAR IPX[2]; ++extern UCHAR APPLE_TALK[2]; ++extern UCHAR RateIdToPlcpSignal[12]; // see IEEE802.11a-1999 p.14 ++extern UCHAR OfdmRateToRxwiMCS[]; ++extern UCHAR OfdmSignalToRateId[16] ; ++extern UCHAR default_cwmin[4]; ++extern UCHAR default_cwmax[4]; ++extern UCHAR default_sta_aifsn[4]; ++extern UCHAR MapUserPriorityToAccessCategory[8]; ++ ++extern USHORT RateUpPER[]; ++extern USHORT RateDownPER[]; ++extern UCHAR Phy11BNextRateDownward[]; ++extern UCHAR Phy11BNextRateUpward[]; ++extern UCHAR Phy11BGNextRateDownward[]; ++extern UCHAR Phy11BGNextRateUpward[]; ++extern UCHAR Phy11ANextRateDownward[]; ++extern UCHAR Phy11ANextRateUpward[]; ++extern CHAR RssiSafeLevelForTxRate[]; ++extern UCHAR RateIdToMbps[]; ++extern USHORT RateIdTo500Kbps[]; ++ ++extern UCHAR CipherSuiteWpaNoneTkip[]; ++extern UCHAR CipherSuiteWpaNoneTkipLen; ++ ++extern UCHAR CipherSuiteWpaNoneAes[]; ++extern UCHAR CipherSuiteWpaNoneAesLen; ++ ++extern UCHAR SsidIe; ++extern UCHAR SupRateIe; ++extern UCHAR ExtRateIe; ++ ++#ifdef DOT11_N_SUPPORT ++extern UCHAR HtCapIe; ++extern UCHAR AddHtInfoIe; ++extern UCHAR NewExtChanIe; ++#ifdef DOT11N_DRAFT3 ++extern UCHAR ExtHtCapIe; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++extern UCHAR ErpIe; ++extern UCHAR DsIe; ++extern UCHAR TimIe; ++extern UCHAR WpaIe; ++extern UCHAR Wpa2Ie; ++extern UCHAR IbssIe; ++extern UCHAR Ccx2Ie; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR Ccx2IeInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR PowerConstraintIE[]; ++ ++ ++extern UCHAR RateSwitchTable[]; ++extern UCHAR RateSwitchTable11B[]; ++extern UCHAR RateSwitchTable11G[]; ++extern UCHAR RateSwitchTable11BG[]; ++ ++#ifdef DOT11_N_SUPPORT ++extern UCHAR RateSwitchTable11BGN1S[]; ++extern UCHAR RateSwitchTable11BGN2S[]; ++extern UCHAR RateSwitchTable11BGN2SForABand[]; ++extern UCHAR RateSwitchTable11N1S[]; ++extern UCHAR RateSwitchTable11N2S[]; ++extern UCHAR RateSwitchTable11N2SForABand[]; ++ ++#ifdef CONFIG_STA_SUPPORT ++extern UCHAR PRE_N_HT_OUI[]; ++#endif // CONFIG_STA_SUPPORT // ++#endif // DOT11_N_SUPPORT // ++ ++#define MAXSEQ (0xFFF) ++ ++#ifdef RALINK_ATE ++typedef struct _ATE_INFO { ++ UCHAR Mode; ++ CHAR TxPower0; ++ CHAR TxPower1; ++ CHAR TxAntennaSel; ++ CHAR RxAntennaSel; ++ TXWI_STRUC TxWI; // TXWI ++ USHORT QID; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR Addr3[MAC_ADDR_LEN]; ++ UCHAR Channel; ++ UINT32 TxLength; ++ UINT32 TxCount; ++ UINT32 TxDoneCount; // Tx DMA Done ++ UINT32 RFFreqOffset; ++ BOOLEAN bRxFer; ++ BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. ++ BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. ++#ifdef RT2860 ++ BOOLEAN bFWLoading; // Reload firmware when ATE is done. ++#endif // RT2860 // ++ UINT32 RxTotalCnt; ++ UINT32 RxCntPerSec; ++ ++ CHAR LastSNR0; // last received SNR ++ CHAR LastSNR1; // last received SNR for 2nd antenna ++ CHAR LastRssi0; // last received RSSI ++ CHAR LastRssi1; // last received RSSI for 2nd antenna ++ CHAR LastRssi2; // last received RSSI for 3rd antenna ++ CHAR AvgRssi0; // last 8 frames' average RSSI ++ CHAR AvgRssi1; // last 8 frames' average RSSI ++ CHAR AvgRssi2; // last 8 frames' average RSSI ++ SHORT AvgRssi0X8; // sum of last 8 frames' RSSI ++ SHORT AvgRssi1X8; // sum of last 8 frames' RSSI ++ SHORT AvgRssi2X8; // sum of last 8 frames' RSSI ++ ++ UINT32 NumOfAvgRssiSample; ++ ++#ifdef RALINK_28xx_QA ++ // Tx frame ++ USHORT HLen; // Header Length ++ USHORT PLen; // Pattern Length ++ UCHAR Header[32]; // Header buffer ++ UCHAR Pattern[32]; // Pattern buffer ++ USHORT DLen; // Data Length ++ USHORT seq; ++ UINT32 CID; ++ THREAD_PID AtePid; ++ // counters ++ UINT32 U2M; ++ UINT32 OtherData; ++ UINT32 Beacon; ++ UINT32 OtherCount; ++ UINT32 TxAc0; ++ UINT32 TxAc1; ++ UINT32 TxAc2; ++ UINT32 TxAc3; ++ UINT32 TxHCCA; ++ UINT32 TxMgmt; ++ UINT32 RSSI0; ++ UINT32 RSSI1; ++ UINT32 RSSI2; ++ UINT32 SNR0; ++ UINT32 SNR1; ++ // control ++ //UINT32 Repeat; // Tx Cpu count ++ UCHAR TxStatus; // task Tx status // 0 --> task is idle, 1 --> task is running ++#endif // RALINK_28xx_QA // ++} ATE_INFO, *PATE_INFO; ++ ++#ifdef RALINK_28xx_QA ++struct ate_racfghdr { ++ UINT32 magic_no; ++ USHORT command_type; ++ USHORT command_id; ++ USHORT length; ++ USHORT sequence; ++ USHORT status; ++ UCHAR data[2046]; ++} __attribute__((packed)); ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++struct reordering_mpdu ++{ ++ struct reordering_mpdu *next; ++ PNDIS_PACKET pPacket; /* coverted to 802.3 frame */ ++ int Sequence; /* sequence number of MPDU */ ++ BOOLEAN bAMSDU; ++}; ++ ++struct reordering_list ++{ ++ struct reordering_mpdu *next; ++ int qlen; ++}; ++ ++struct reordering_mpdu_pool ++{ ++ PVOID mem; ++ NDIS_SPIN_LOCK lock; ++ struct reordering_list freelist; ++}; ++#endif // DOT11_N_SUPPORT // ++ ++typedef struct _RSSI_SAMPLE { ++ CHAR LastRssi0; // last received RSSI ++ CHAR LastRssi1; // last received RSSI ++ CHAR LastRssi2; // last received RSSI ++ CHAR AvgRssi0; ++ CHAR AvgRssi1; ++ CHAR AvgRssi2; ++ SHORT AvgRssi0X8; ++ SHORT AvgRssi1X8; ++ SHORT AvgRssi2X8; ++} RSSI_SAMPLE; ++ ++// ++// Queue structure and macros ++// ++typedef struct _QUEUE_ENTRY { ++ struct _QUEUE_ENTRY *Next; ++} QUEUE_ENTRY, *PQUEUE_ENTRY; ++ ++// Queue structure ++typedef struct _QUEUE_HEADER { ++ PQUEUE_ENTRY Head; ++ PQUEUE_ENTRY Tail; ++ ULONG Number; ++} QUEUE_HEADER, *PQUEUE_HEADER; ++ ++#define InitializeQueueHeader(QueueHeader) \ ++{ \ ++ (QueueHeader)->Head = (QueueHeader)->Tail = NULL; \ ++ (QueueHeader)->Number = 0; \ ++} ++ ++#define RemoveHeadQueue(QueueHeader) \ ++(QueueHeader)->Head; \ ++{ \ ++ PQUEUE_ENTRY pNext; \ ++ if ((QueueHeader)->Head != NULL) \ ++ { \ ++ pNext = (QueueHeader)->Head->Next; \ ++ (QueueHeader)->Head = pNext; \ ++ if (pNext == NULL) \ ++ (QueueHeader)->Tail = NULL; \ ++ (QueueHeader)->Number--; \ ++ } \ ++} ++ ++#define InsertHeadQueue(QueueHeader, QueueEntry) \ ++{ \ ++ ((PQUEUE_ENTRY)QueueEntry)->Next = (QueueHeader)->Head; \ ++ (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ ++ if ((QueueHeader)->Tail == NULL) \ ++ (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Number++; \ ++} ++ ++#define InsertTailQueue(QueueHeader, QueueEntry) \ ++{ \ ++ ((PQUEUE_ENTRY)QueueEntry)->Next = NULL; \ ++ if ((QueueHeader)->Tail) \ ++ (QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(QueueEntry); \ ++ else \ ++ (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Number++; \ ++} ++ ++// ++// Macros for flag and ref count operations ++// ++#define RTMP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) ++#define RTMP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) ++#define RTMP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) ++#define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) ++#define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) ++ ++#define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) ++#define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) ++#define OPSTATUS_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.OpStatusFlags & (_F)) != 0) ++ ++#define CLIENT_STATUS_SET_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags |= (_F)) ++#define CLIENT_STATUS_CLEAR_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags &= ~(_F)) ++#define CLIENT_STATUS_TEST_FLAG(_pEntry,_F) (((_pEntry)->ClientStatusFlags & (_F)) != 0) ++ ++#define RX_FILTER_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter |= (_F)) ++#define RX_FILTER_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter &= ~(_F)) ++#define RX_FILTER_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.PacketFilter & (_F)) != 0) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define STA_NO_SECURITY_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) ++#define STA_WEP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) ++#define STA_TKIP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++#define STA_AES_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ ++#define STA_TGN_WIFI_ON(_p) (_p->StaCfg.bTGnWifiTest == TRUE) ++#endif // CONFIG_STA_SUPPORT // ++ ++#define CKIP_KP_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x10) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) ++#define CKIP_CMIC_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x08) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) ++ ++ ++#define INC_RING_INDEX(_idx, _RingSize) \ ++{ \ ++ (_idx) = (_idx+1) % (_RingSize); \ ++} ++ ++#define IS_RT3070(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30700000) ++ ++#define RING_PACKET_INIT(_TxRing, _idx) \ ++{ \ ++ _TxRing->Cell[_idx].pNdisPacket = NULL; \ ++ _TxRing->Cell[_idx].pNextNdisPacket = NULL; \ ++} ++ ++#define TXDT_INIT(_TxD) \ ++{ \ ++ NdisZeroMemory(_TxD, TXD_SIZE); \ ++ _TxD->DMADONE = 1; \ ++} ++ ++//Set last data segment ++#define RING_SET_LASTDS(_TxD, _IsSD0) \ ++{ \ ++ if (_IsSD0) {_TxD->LastSec0 = 1;} \ ++ else {_TxD->LastSec1 = 1;} \ ++} ++ ++// Increase TxTsc value for next transmission ++// TODO: ++// When i==6, means TSC has done one full cycle, do re-keying stuff follow specs ++// Should send a special event microsoft defined to request re-key ++#define INC_TX_TSC(_tsc) \ ++{ \ ++ int i=0; \ ++ while (++_tsc[i] == 0x0) \ ++ { \ ++ i++; \ ++ if (i == 6) \ ++ break; \ ++ } \ ++} ++ ++#ifdef DOT11_N_SUPPORT ++// StaActive.SupportedHtPhy.MCSSet is copied from AP beacon. Don't need to update here. ++#define COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ ++{ \ ++ _pAd->StaActive.SupportedHtPhy.ChannelWidth = _pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth; \ ++ _pAd->StaActive.SupportedHtPhy.MimoPs = _pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs; \ ++ _pAd->StaActive.SupportedHtPhy.GF = _pAd->MlmeAux.HtCapability.HtCapInfo.GF; \ ++ _pAd->StaActive.SupportedHtPhy.ShortGIfor20 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20; \ ++ _pAd->StaActive.SupportedHtPhy.ShortGIfor40 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40; \ ++ _pAd->StaActive.SupportedHtPhy.TxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC; \ ++ _pAd->StaActive.SupportedHtPhy.RxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC; \ ++ _pAd->StaActive.SupportedHtPhy.ExtChanOffset = _pAd->MlmeAux.AddHtInfo.AddHtInfo.ExtChanOffset; \ ++ _pAd->StaActive.SupportedHtPhy.RecomWidth = _pAd->MlmeAux.AddHtInfo.AddHtInfo.RecomWidth; \ ++ _pAd->StaActive.SupportedHtPhy.OperaionMode = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode; \ ++ _pAd->StaActive.SupportedHtPhy.NonGfPresent = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent; \ ++ NdisMoveMemory((_pAd)->MacTab.Content[BSSID_WCID].HTCapability.MCSSet, (_pAd)->StaActive.SupportedPhyInfo.MCSSet, sizeof(UCHAR) * 16);\ ++} ++ ++#define COPY_AP_HTSETTINGS_FROM_BEACON(_pAd, _pHtCapability) \ ++{ \ ++ _pAd->MacTab.Content[BSSID_WCID].AMsduSize = (UCHAR)(_pHtCapability->HtCapInfo.AMsduSize); \ ++ _pAd->MacTab.Content[BSSID_WCID].MmpsMode= (UCHAR)(_pHtCapability->HtCapInfo.MimoPs); \ ++ _pAd->MacTab.Content[BSSID_WCID].MaxRAmpduFactor = (UCHAR)(_pHtCapability->HtCapParm.MaxRAmpduFactor); \ ++} ++#endif // DOT11_N_SUPPORT // ++ ++// ++// MACRO for 32-bit PCI register read / write ++// ++// Usage : RTMP_IO_READ32( ++// PRTMP_ADAPTER pAd, ++// ULONG Register_Offset, ++// PULONG pValue) ++// ++// RTMP_IO_WRITE32( ++// PRTMP_ADAPTER pAd, ++// ULONG Register_Offset, ++// ULONG Value) ++// ++ ++// ++// BBP & RF are using indirect access. Before write any value into it. ++// We have to make sure there is no outstanding command pending via checking busy bit. ++// ++#define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register ++// ++#ifdef RT2860 ++#define RTMP_RF_IO_WRITE32(_A, _V) \ ++{ \ ++ PHY_CSR4_STRUC Value; \ ++ ULONG BusyCnt = 0; \ ++ if ((_A)->bPCIclkOff) \ ++ { \ ++ return; \ ++ } \ ++ do { \ ++ RTMP_IO_READ32(_A, RF_CSR_CFG0, &Value.word); \ ++ if (Value.field.Busy == IDLE) \ ++ break; \ ++ BusyCnt++; \ ++ } while (BusyCnt < MAX_BUSY_COUNT); \ ++ if (BusyCnt < MAX_BUSY_COUNT) \ ++ { \ ++ RTMP_IO_WRITE32(_A, RF_CSR_CFG0, _V); \ ++ } \ ++} ++ ++#define BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) \ ++{ \ ++ BBP_CSR_CFG_STRUC BbpCsr; \ ++ int i, k; \ ++ for (i=0; iBbpWriteLatch[_I]; \ ++ } \ ++} ++ ++//#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) {} ++// Read BBP register by register's ID. Generate PER to test BA ++#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) \ ++{ \ ++ BBP_CSR_CFG_STRUC BbpCsr; \ ++ int i, k; \ ++ if ((_A)->bPCIclkOff == FALSE) \ ++ { \ ++ for (i=0; iBbpWriteLatch[_I]; \ ++ RTMP_IO_READ32(_A, H2M_BBP_AGENT, &BbpCsr.word); \ ++ BbpCsr.field.Busy = 0; \ ++ RTMP_IO_WRITE32(_A, H2M_BBP_AGENT, BbpCsr.word); \ ++ } \ ++ } \ ++} ++ ++#define BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) \ ++{ \ ++ BBP_CSR_CFG_STRUC BbpCsr; \ ++ int BusyCnt; \ ++ for (BusyCnt=0; BusyCntBbpWriteLatch[_I] = _V; \ ++ break; \ ++ } \ ++ if (BusyCnt == MAX_BUSY_COUNT) \ ++ { \ ++ DBGPRINT_ERR(("BBP write R%d fail\n", _I)); \ ++ } \ ++} ++ ++// Write BBP register by register's ID & value ++#define RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) \ ++{ \ ++ BBP_CSR_CFG_STRUC BbpCsr; \ ++ int BusyCnt; \ ++ if ((_A)->bPCIclkOff == FALSE) \ ++ { \ ++ for (BusyCnt=0; BusyCntOpMode == OPMODE_AP) \ ++ RTMPusecDelay(1000); \ ++ (_A)->BbpWriteLatch[_I] = _V; \ ++ break; \ ++ } \ ++ if (BusyCnt == MAX_BUSY_COUNT) \ ++ { \ ++ DBGPRINT_ERR(("BBP write R%d=0x%x fail\n", _I, BbpCsr.word)); \ ++ RTMP_IO_READ32(_A, H2M_BBP_AGENT, &BbpCsr.word); \ ++ BbpCsr.field.Busy = 0; \ ++ RTMP_IO_WRITE32(_A, H2M_BBP_AGENT, BbpCsr.word); \ ++ } \ ++ } \ ++} ++#endif // RT2860 // ++ ++ ++#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ ++ switch (ch) \ ++ { \ ++ case 1: khz = 2412000; break; \ ++ case 2: khz = 2417000; break; \ ++ case 3: khz = 2422000; break; \ ++ case 4: khz = 2427000; break; \ ++ case 5: khz = 2432000; break; \ ++ case 6: khz = 2437000; break; \ ++ case 7: khz = 2442000; break; \ ++ case 8: khz = 2447000; break; \ ++ case 9: khz = 2452000; break; \ ++ case 10: khz = 2457000; break; \ ++ case 11: khz = 2462000; break; \ ++ case 12: khz = 2467000; break; \ ++ case 13: khz = 2472000; break; \ ++ case 14: khz = 2484000; break; \ ++ case 36: /* UNII */ khz = 5180000; break; \ ++ case 40: /* UNII */ khz = 5200000; break; \ ++ case 44: /* UNII */ khz = 5220000; break; \ ++ case 48: /* UNII */ khz = 5240000; break; \ ++ case 52: /* UNII */ khz = 5260000; break; \ ++ case 56: /* UNII */ khz = 5280000; break; \ ++ case 60: /* UNII */ khz = 5300000; break; \ ++ case 64: /* UNII */ khz = 5320000; break; \ ++ case 149: /* UNII */ khz = 5745000; break; \ ++ case 153: /* UNII */ khz = 5765000; break; \ ++ case 157: /* UNII */ khz = 5785000; break; \ ++ case 161: /* UNII */ khz = 5805000; break; \ ++ case 165: /* UNII */ khz = 5825000; break; \ ++ case 100: /* HiperLAN2 */ khz = 5500000; break; \ ++ case 104: /* HiperLAN2 */ khz = 5520000; break; \ ++ case 108: /* HiperLAN2 */ khz = 5540000; break; \ ++ case 112: /* HiperLAN2 */ khz = 5560000; break; \ ++ case 116: /* HiperLAN2 */ khz = 5580000; break; \ ++ case 120: /* HiperLAN2 */ khz = 5600000; break; \ ++ case 124: /* HiperLAN2 */ khz = 5620000; break; \ ++ case 128: /* HiperLAN2 */ khz = 5640000; break; \ ++ case 132: /* HiperLAN2 */ khz = 5660000; break; \ ++ case 136: /* HiperLAN2 */ khz = 5680000; break; \ ++ case 140: /* HiperLAN2 */ khz = 5700000; break; \ ++ case 34: /* Japan MMAC */ khz = 5170000; break; \ ++ case 38: /* Japan MMAC */ khz = 5190000; break; \ ++ case 42: /* Japan MMAC */ khz = 5210000; break; \ ++ case 46: /* Japan MMAC */ khz = 5230000; break; \ ++ case 184: /* Japan */ khz = 4920000; break; \ ++ case 188: /* Japan */ khz = 4940000; break; \ ++ case 192: /* Japan */ khz = 4960000; break; \ ++ case 196: /* Japan */ khz = 4980000; break; \ ++ case 208: /* Japan, means J08 */ khz = 5040000; break; \ ++ case 212: /* Japan, means J12 */ khz = 5060000; break; \ ++ case 216: /* Japan, means J16 */ khz = 5080000; break; \ ++ default: khz = 2412000; break; \ ++ } \ ++ } ++ ++#define MAP_KHZ_TO_CHANNEL_ID(khz, ch) { \ ++ switch (khz) \ ++ { \ ++ case 2412000: ch = 1; break; \ ++ case 2417000: ch = 2; break; \ ++ case 2422000: ch = 3; break; \ ++ case 2427000: ch = 4; break; \ ++ case 2432000: ch = 5; break; \ ++ case 2437000: ch = 6; break; \ ++ case 2442000: ch = 7; break; \ ++ case 2447000: ch = 8; break; \ ++ case 2452000: ch = 9; break; \ ++ case 2457000: ch = 10; break; \ ++ case 2462000: ch = 11; break; \ ++ case 2467000: ch = 12; break; \ ++ case 2472000: ch = 13; break; \ ++ case 2484000: ch = 14; break; \ ++ case 5180000: ch = 36; /* UNII */ break; \ ++ case 5200000: ch = 40; /* UNII */ break; \ ++ case 5220000: ch = 44; /* UNII */ break; \ ++ case 5240000: ch = 48; /* UNII */ break; \ ++ case 5260000: ch = 52; /* UNII */ break; \ ++ case 5280000: ch = 56; /* UNII */ break; \ ++ case 5300000: ch = 60; /* UNII */ break; \ ++ case 5320000: ch = 64; /* UNII */ break; \ ++ case 5745000: ch = 149; /* UNII */ break; \ ++ case 5765000: ch = 153; /* UNII */ break; \ ++ case 5785000: ch = 157; /* UNII */ break; \ ++ case 5805000: ch = 161; /* UNII */ break; \ ++ case 5825000: ch = 165; /* UNII */ break; \ ++ case 5500000: ch = 100; /* HiperLAN2 */ break; \ ++ case 5520000: ch = 104; /* HiperLAN2 */ break; \ ++ case 5540000: ch = 108; /* HiperLAN2 */ break; \ ++ case 5560000: ch = 112; /* HiperLAN2 */ break; \ ++ case 5580000: ch = 116; /* HiperLAN2 */ break; \ ++ case 5600000: ch = 120; /* HiperLAN2 */ break; \ ++ case 5620000: ch = 124; /* HiperLAN2 */ break; \ ++ case 5640000: ch = 128; /* HiperLAN2 */ break; \ ++ case 5660000: ch = 132; /* HiperLAN2 */ break; \ ++ case 5680000: ch = 136; /* HiperLAN2 */ break; \ ++ case 5700000: ch = 140; /* HiperLAN2 */ break; \ ++ case 5170000: ch = 34; /* Japan MMAC */ break; \ ++ case 5190000: ch = 38; /* Japan MMAC */ break; \ ++ case 5210000: ch = 42; /* Japan MMAC */ break; \ ++ case 5230000: ch = 46; /* Japan MMAC */ break; \ ++ case 4920000: ch = 184; /* Japan */ break; \ ++ case 4940000: ch = 188; /* Japan */ break; \ ++ case 4960000: ch = 192; /* Japan */ break; \ ++ case 4980000: ch = 196; /* Japan */ break; \ ++ case 5040000: ch = 208; /* Japan, means J08 */ break; \ ++ case 5060000: ch = 212; /* Japan, means J12 */ break; \ ++ case 5080000: ch = 216; /* Japan, means J16 */ break; \ ++ default: ch = 1; break; \ ++ } \ ++ } ++ ++// ++// Common fragment list structure - Identical to the scatter gather frag list structure ++// ++#define NIC_MAX_PHYS_BUF_COUNT 8 ++ ++typedef struct _RTMP_SCATTER_GATHER_ELEMENT { ++ PVOID Address; ++ ULONG Length; ++ PULONG Reserved; ++} RTMP_SCATTER_GATHER_ELEMENT, *PRTMP_SCATTER_GATHER_ELEMENT; ++ ++ ++typedef struct _RTMP_SCATTER_GATHER_LIST { ++ ULONG NumberOfElements; ++ PULONG Reserved; ++ RTMP_SCATTER_GATHER_ELEMENT Elements[NIC_MAX_PHYS_BUF_COUNT]; ++} RTMP_SCATTER_GATHER_LIST, *PRTMP_SCATTER_GATHER_LIST; ++ ++// ++// Some utility macros ++// ++#ifndef min ++#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) ++#endif ++ ++#ifndef max ++#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) ++#endif ++ ++#define GET_LNA_GAIN(_pAd) ((_pAd->LatchRfRegs.Channel <= 14) ? (_pAd->BLNAGain) : ((_pAd->LatchRfRegs.Channel <= 64) ? (_pAd->ALNAGain0) : ((_pAd->LatchRfRegs.Channel <= 128) ? (_pAd->ALNAGain1) : (_pAd->ALNAGain2)))) ++ ++#define INC_COUNTER64(Val) (Val.QuadPart++) ++ ++#define INFRA_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_INFRA_ON)) ++#define ADHOC_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_ADHOC_ON)) ++#define MONITOR_ON(_p) (((_p)->StaCfg.BssType) == BSS_MONITOR) ++#define IDLE_ON(_p) (!INFRA_ON(_p) && !ADHOC_ON(_p)) ++ ++// Check LEAP & CCKM flags ++#define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) ++#define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE)) ++ ++// if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required ++#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \ ++{ \ ++ if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_802_1H; \ ++ if (NdisEqualMemory(IPX, _pBufVA + 12, 2) || \ ++ NdisEqualMemory(APPLE_TALK, _pBufVA + 12, 2)) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ _pExtraLlcSnapEncap = NULL; \ ++ } \ ++} ++ ++// New Define for new Tx Path. ++#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(_pBufVA, _pExtraLlcSnapEncap) \ ++{ \ ++ if (((*(_pBufVA) << 8) + *(_pBufVA + 1)) > 1500) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_802_1H; \ ++ if (NdisEqualMemory(IPX, _pBufVA, 2) || \ ++ NdisEqualMemory(APPLE_TALK, _pBufVA, 2)) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ _pExtraLlcSnapEncap = NULL; \ ++ } \ ++} ++ ++ ++#define MAKE_802_3_HEADER(_p, _pMac1, _pMac2, _pType) \ ++{ \ ++ NdisMoveMemory(_p, _pMac1, MAC_ADDR_LEN); \ ++ NdisMoveMemory((_p + MAC_ADDR_LEN), _pMac2, MAC_ADDR_LEN); \ ++ NdisMoveMemory((_p + MAC_ADDR_LEN * 2), _pType, LENGTH_802_3_TYPE); \ ++} ++ ++// if pData has no LLC/SNAP (neither RFC1042 nor Bridge tunnel), keep it that way. ++// else if the received frame is LLC/SNAP-encaped IPX or APPLETALK, preserve the LLC/SNAP field ++// else remove the LLC/SNAP field from the result Ethernet frame ++// Patch for WHQL only, which did not turn on Netbios but use IPX within its payload ++// Note: ++// _pData & _DataSize may be altered (remove 8-byte LLC/SNAP) by this MACRO ++// _pRemovedLLCSNAP: pointer to removed LLC/SNAP; NULL is not removed ++#define CONVERT_TO_802_3(_p8023hdr, _pDA, _pSA, _pData, _DataSize, _pRemovedLLCSNAP) \ ++{ \ ++ char LLC_Len[2]; \ ++ \ ++ _pRemovedLLCSNAP = NULL; \ ++ if (NdisEqualMemory(SNAP_802_1H, _pData, 6) || \ ++ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, _pData, 6)) \ ++ { \ ++ PUCHAR pProto = _pData + 6; \ ++ \ ++ if ((NdisEqualMemory(IPX, pProto, 2) || NdisEqualMemory(APPLE_TALK, pProto, 2)) && \ ++ NdisEqualMemory(SNAP_802_1H, _pData, 6)) \ ++ { \ ++ LLC_Len[0] = (UCHAR)(_DataSize / 256); \ ++ LLC_Len[1] = (UCHAR)(_DataSize % 256); \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ ++ } \ ++ else \ ++ { \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, pProto); \ ++ _pRemovedLLCSNAP = _pData; \ ++ _DataSize -= LENGTH_802_1_H; \ ++ _pData += LENGTH_802_1_H; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ LLC_Len[0] = (UCHAR)(_DataSize / 256); \ ++ LLC_Len[1] = (UCHAR)(_DataSize % 256); \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ ++ } \ ++} ++ ++#define SWITCH_AB( _pAA, _pBB) \ ++{ \ ++ PVOID pCC; \ ++ pCC = _pBB; \ ++ _pBB = _pAA; \ ++ _pAA = pCC; \ ++} ++ ++// Enqueue this frame to MLME engine ++// We need to enqueue the whole frame because MLME need to pass data type ++// information from 802.11 header ++#ifdef RT2860 ++#define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ ++{ \ ++ UINT32 High32TSF, Low32TSF; \ ++ RTMP_IO_READ32(_pAd, TSF_TIMER_DW1, &High32TSF); \ ++ RTMP_IO_READ32(_pAd, TSF_TIMER_DW0, &Low32TSF); \ ++ MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ ++} ++#endif // RT2860 // ++ ++#define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ ++ NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) ++ ++#define MAC_ADDR_EQUAL(pAddr1,pAddr2) RTMPEqualMemory((PVOID)(pAddr1), (PVOID)(pAddr2), MAC_ADDR_LEN) ++#define SSID_EQUAL(ssid1, len1, ssid2, len2) ((len1==len2) && (RTMPEqualMemory(ssid1, ssid2, len1))) ++ ++// ++// Check if it is Japan W53(ch52,56,60,64) channel. ++// ++#define JapanChannelCheck(channel) ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define STA_PORT_SECURED(_pAd) \ ++{ \ ++ _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ ++ NdisAcquireSpinLock(&_pAd->MacTabLock); \ ++ _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ ++ NdisReleaseSpinLock(&_pAd->MacTabLock); \ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// ++// Register set pair for initialzation register set definition ++// ++typedef struct _RTMP_REG_PAIR ++{ ++ ULONG Register; ++ ULONG Value; ++} RTMP_REG_PAIR, *PRTMP_REG_PAIR; ++ ++typedef struct _REG_PAIR ++{ ++ UCHAR Register; ++ UCHAR Value; ++} REG_PAIR, *PREG_PAIR; ++ ++// ++// Register set pair for initialzation register set definition ++// ++typedef struct _RTMP_RF_REGS ++{ ++ UCHAR Channel; ++ ULONG R1; ++ ULONG R2; ++ ULONG R3; ++ ULONG R4; ++} RTMP_RF_REGS, *PRTMP_RF_REGS; ++ ++typedef struct _FREQUENCY_ITEM { ++ UCHAR Channel; ++ UCHAR N; ++ UCHAR R; ++ UCHAR K; ++} FREQUENCY_ITEM, *PFREQUENCY_ITEM; ++ ++// ++// Data buffer for DMA operation, the buffer must be contiguous physical memory ++// Both DMA to / from CPU use the same structure. ++// ++typedef struct _RTMP_DMABUF ++{ ++ ULONG AllocSize; ++ PVOID AllocVa; // TxBuf virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address ++} RTMP_DMABUF, *PRTMP_DMABUF; ++ ++ ++typedef union _HEADER_802_11_SEQ{ ++#ifdef RT_BIG_ENDIAN ++ struct { ++ USHORT Sequence:12; ++ USHORT Frag:4; ++ } field; ++#else ++ struct { ++ USHORT Frag:4; ++ USHORT Sequence:12; ++ } field; ++#endif ++ USHORT value; ++} HEADER_802_11_SEQ, *PHEADER_802_11_SEQ; ++ ++// ++// Data buffer for DMA operation, the buffer must be contiguous physical memory ++// Both DMA to / from CPU use the same structure. ++// ++typedef struct _RTMP_REORDERBUF ++{ ++ BOOLEAN IsFull; ++ PVOID AllocVa; // TxBuf virtual address ++ UCHAR Header802_3[14]; ++ HEADER_802_11_SEQ Sequence; //support compressed bitmap BA, so no consider fragment in BA ++ UCHAR DataOffset; ++ USHORT Datasize; ++ ULONG AllocSize; ++#ifdef RT2860 ++ NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address ++#endif // RT2860 // ++} RTMP_REORDERBUF, *PRTMP_REORDERBUF; ++ ++// ++// Control block (Descriptor) for all ring descriptor DMA operation, buffer must be ++// contiguous physical memory. NDIS_PACKET stored the binding Rx packet descriptor ++// which won't be released, driver has to wait until upper layer return the packet ++// before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair ++// to describe the packet buffer. For Tx, NDIS_PACKET stored the tx packet descriptor ++// which driver should ACK upper layer when the tx is physically done or failed. ++// ++typedef struct _RTMP_DMACB ++{ ++ ULONG AllocSize; // Control block size ++ PVOID AllocVa; // Control block virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address ++ PNDIS_PACKET pNdisPacket; ++ PNDIS_PACKET pNextNdisPacket; ++ ++ RTMP_DMABUF DmaBuf; // Associated DMA buffer structure ++} RTMP_DMACB, *PRTMP_DMACB; ++ ++typedef struct _RTMP_TX_BUF ++{ ++ PQUEUE_ENTRY Next; ++ UCHAR Index; ++ ULONG AllocSize; // Control block size ++ PVOID AllocVa; // Control block virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address ++} RTMP_TXBUF, *PRTMP_TXBUF; ++ ++typedef struct _RTMP_RX_BUF ++{ ++ BOOLEAN InUse; ++ ULONG ByBaRecIndex; ++ RTMP_REORDERBUF MAP_RXBuf[MAX_RX_REORDERBUF]; ++} RTMP_RXBUF, *PRTMP_RXBUF; ++typedef struct _RTMP_TX_RING ++{ ++ RTMP_DMACB Cell[TX_RING_SIZE]; ++ UINT32 TxCpuIdx; ++ UINT32 TxDmaIdx; ++ UINT32 TxSwFreeIdx; // software next free tx index ++} RTMP_TX_RING, *PRTMP_TX_RING; ++ ++typedef struct _RTMP_RX_RING ++{ ++ RTMP_DMACB Cell[RX_RING_SIZE]; ++ UINT32 RxCpuIdx; ++ UINT32 RxDmaIdx; ++ INT32 RxSwReadIdx; // software next read index ++} RTMP_RX_RING, *PRTMP_RX_RING; ++ ++typedef struct _RTMP_MGMT_RING ++{ ++ RTMP_DMACB Cell[MGMT_RING_SIZE]; ++ UINT32 TxCpuIdx; ++ UINT32 TxDmaIdx; ++ UINT32 TxSwFreeIdx; // software next free tx index ++} RTMP_MGMT_RING, *PRTMP_MGMT_RING; ++ ++// ++// Statistic counter structure ++// ++typedef struct _COUNTER_802_3 ++{ ++ // General Stats ++ ULONG GoodTransmits; ++ ULONG GoodReceives; ++ ULONG TxErrors; ++ ULONG RxErrors; ++ ULONG RxNoBuffer; ++ ++ // Ethernet Stats ++ ULONG RcvAlignmentErrors; ++ ULONG OneCollision; ++ ULONG MoreCollisions; ++ ++} COUNTER_802_3, *PCOUNTER_802_3; ++ ++typedef struct _COUNTER_802_11 { ++ ULONG Length; ++ LARGE_INTEGER LastTransmittedFragmentCount; ++ LARGE_INTEGER TransmittedFragmentCount; ++ LARGE_INTEGER MulticastTransmittedFrameCount; ++ LARGE_INTEGER FailedCount; ++ LARGE_INTEGER RetryCount; ++ LARGE_INTEGER MultipleRetryCount; ++ LARGE_INTEGER RTSSuccessCount; ++ LARGE_INTEGER RTSFailureCount; ++ LARGE_INTEGER ACKFailureCount; ++ LARGE_INTEGER FrameDuplicateCount; ++ LARGE_INTEGER ReceivedFragmentCount; ++ LARGE_INTEGER MulticastReceivedFrameCount; ++ LARGE_INTEGER FCSErrorCount; ++} COUNTER_802_11, *PCOUNTER_802_11; ++ ++typedef struct _COUNTER_RALINK { ++ ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput ++ ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput ++ ULONG BeenDisassociatedCount; ++ ULONG BadCQIAutoRecoveryCount; ++ ULONG PoorCQIRoamingCount; ++ ULONG MgmtRingFullCount; ++ ULONG RxCountSinceLastNULL; ++ ULONG RxCount; ++ ULONG RxRingErrCount; ++ ULONG KickTxCount; ++ ULONG TxRingErrCount; ++ LARGE_INTEGER RealFcsErrCount; ++ ULONG PendingNdisPacketCount; ++ ++ ULONG OneSecOsTxCount[NUM_OF_TX_RING]; ++ ULONG OneSecDmaDoneCount[NUM_OF_TX_RING]; ++ UINT32 OneSecTxDoneCount; ++ ULONG OneSecRxCount; ++ UINT32 OneSecTxAggregationCount; ++ UINT32 OneSecRxAggregationCount; ++ ++ UINT32 OneSecFrameDuplicateCount; ++ ++ ++ UINT32 OneSecTxNoRetryOkCount; ++ UINT32 OneSecTxRetryOkCount; ++ UINT32 OneSecTxFailCount; ++ UINT32 OneSecFalseCCACnt; // CCA error count, for debug purpose, might move to global counter ++ UINT32 OneSecRxOkCnt; // RX without error ++ UINT32 OneSecRxOkDataCnt; // unicast-to-me DATA frame count ++ UINT32 OneSecRxFcsErrCnt; // CRC error ++ UINT32 OneSecBeaconSentCnt; ++ UINT32 LastOneSecTotalTxCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount ++ UINT32 LastOneSecRxOkDataCnt; // OneSecRxOkDataCnt ++ ULONG DuplicateRcv; ++ ULONG TxAggCount; ++ ULONG TxNonAggCount; ++ ULONG TxAgg1MPDUCount; ++ ULONG TxAgg2MPDUCount; ++ ULONG TxAgg3MPDUCount; ++ ULONG TxAgg4MPDUCount; ++ ULONG TxAgg5MPDUCount; ++ ULONG TxAgg6MPDUCount; ++ ULONG TxAgg7MPDUCount; ++ ULONG TxAgg8MPDUCount; ++ ULONG TxAgg9MPDUCount; ++ ULONG TxAgg10MPDUCount; ++ ULONG TxAgg11MPDUCount; ++ ULONG TxAgg12MPDUCount; ++ ULONG TxAgg13MPDUCount; ++ ULONG TxAgg14MPDUCount; ++ ULONG TxAgg15MPDUCount; ++ ULONG TxAgg16MPDUCount; ++ ++ LARGE_INTEGER TransmittedOctetsInAMSDU; ++ LARGE_INTEGER TransmittedAMSDUCount; ++ LARGE_INTEGER ReceivedOctesInAMSDUCount; ++ LARGE_INTEGER ReceivedAMSDUCount; ++ LARGE_INTEGER TransmittedAMPDUCount; ++ LARGE_INTEGER TransmittedMPDUsInAMPDUCount; ++ LARGE_INTEGER TransmittedOctetsInAMPDUCount; ++ LARGE_INTEGER MPDUInReceivedAMPDUCount; ++} COUNTER_RALINK, *PCOUNTER_RALINK; ++ ++typedef struct _PID_COUNTER { ++ ULONG TxAckRequiredCount; // CRC error ++ ULONG TxAggreCount; ++ ULONG TxSuccessCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount ++ ULONG LastSuccessRate; ++} PID_COUNTER, *PPID_COUNTER; ++ ++typedef struct _COUNTER_DRS { ++ // to record the each TX rate's quality. 0 is best, the bigger the worse. ++ USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++ ULONG CurrTxRateStableTime; // # of second in current TX rate ++ BOOLEAN fNoisyEnvironment; ++ BOOLEAN fLastSecAccordingRSSI; ++ UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down ++ UCHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction ++ ULONG LastTxOkCount; ++} COUNTER_DRS, *PCOUNTER_DRS; ++ ++// ++// Arcfour Structure Added by PaulWu ++// ++typedef struct _ARCFOUR ++{ ++ UINT X; ++ UINT Y; ++ UCHAR STATE[256]; ++} ARCFOURCONTEXT, *PARCFOURCONTEXT; ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI too. just copy to TXWI. ++typedef struct _RECEIVE_SETTING { ++#ifdef RT_BIG_ENDIAN ++ USHORT MIMO:1; ++ USHORT OFDM:1; ++ USHORT rsv:3; ++ USHORT STBC:2; //SPACE ++ USHORT ShortGI:1; ++ USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz ++ USHORT NumOfRX:2; // MIMO. WE HAVE 3R ++#else ++ USHORT NumOfRX:2; // MIMO. WE HAVE 3R ++ USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:3; ++ USHORT OFDM:1; ++ USHORT MIMO:1; ++#endif ++ } RECEIVE_SETTING, *PRECEIVE_SETTING; ++ ++// Shared key data structure ++typedef struct _WEP_KEY { ++ UCHAR KeyLen; // Key length for each key, 0: entry is invalid ++ UCHAR Key[MAX_LEN_OF_KEY]; // right now we implement 4 keys, 128 bits max ++} WEP_KEY, *PWEP_KEY; ++ ++typedef struct _CIPHER_KEY { ++ UCHAR Key[16]; // right now we implement 4 keys, 128 bits max ++ UCHAR RxMic[8]; // make alignment ++ UCHAR TxMic[8]; ++ UCHAR TxTsc[6]; // 48bit TSC value ++ UCHAR RxTsc[6]; // 48bit TSC value ++ UCHAR CipherAlg; // 0-none, 1:WEP64, 2:WEP128, 3:TKIP, 4:AES, 5:CKIP64, 6:CKIP128 ++ UCHAR KeyLen; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR BssId[6]; ++#endif // CONFIG_STA_SUPPORT // ++ // Key length for each key, 0: entry is invalid ++ UCHAR Type; // Indicate Pairwise/Group when reporting MIC error ++} CIPHER_KEY, *PCIPHER_KEY; ++ ++typedef struct _BBP_TUNING_STRUCT { ++ BOOLEAN Enable; ++ UCHAR FalseCcaCountUpperBound; // 100 per sec ++ UCHAR FalseCcaCountLowerBound; // 10 per sec ++ UCHAR R17LowerBound; // specified in E2PROM ++ UCHAR R17UpperBound; // 0x68 according to David Tung ++ UCHAR CurrentR17Value; ++} BBP_TUNING, *PBBP_TUNING; ++ ++typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { ++ UCHAR EvaluatePeriod; // 0:not evalute status, 1: evaluate status, 2: switching status ++ UCHAR Pair1PrimaryRxAnt; // 0:Ant-E1, 1:Ant-E2 ++ UCHAR Pair1SecondaryRxAnt; // 0:Ant-E1, 1:Ant-E2 ++ UCHAR Pair2PrimaryRxAnt; // 0:Ant-E3, 1:Ant-E4 ++ UCHAR Pair2SecondaryRxAnt; // 0:Ant-E3, 1:Ant-E4 ++ SHORT Pair1AvgRssi[2]; // AvgRssi[0]:E1, AvgRssi[1]:E2 ++ SHORT Pair2AvgRssi[2]; // AvgRssi[0]:E3, AvgRssi[1]:E4 ++ SHORT Pair1LastAvgRssi; // ++ SHORT Pair2LastAvgRssi; // ++ ULONG RcvPktNumWhenEvaluate; ++ BOOLEAN FirstPktArrivedWhenEvaluate; ++ RALINK_TIMER_STRUCT RxAntDiversityTimer; ++} SOFT_RX_ANT_DIVERSITY, *PSOFT_RX_ANT_DIVERSITY; ++ ++typedef struct _LEAP_AUTH_INFO { ++ BOOLEAN Enabled; //Ture: Enable LEAP Authentication ++ BOOLEAN CCKM; //Ture: Use Fast Reauthentication with CCKM ++ UCHAR Reserve[2]; ++ UCHAR UserName[256]; //LEAP, User name ++ ULONG UserNameLen; ++ UCHAR Password[256]; //LEAP, User Password ++ ULONG PasswordLen; ++} LEAP_AUTH_INFO, *PLEAP_AUTH_INFO; ++ ++typedef struct { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR ErrorCode[2]; //00 01-Invalid authentication type ++ //00 02-Authentication timeout ++ //00 03-Challenge from AP failed ++ //00 04-Challenge to AP failed ++ BOOLEAN Reported; ++} ROGUEAP_ENTRY, *PROGUEAP_ENTRY; ++ ++typedef struct { ++ UCHAR RogueApNr; ++ ROGUEAP_ENTRY RogueApEntry[MAX_LEN_OF_BSS_TABLE]; ++} ROGUEAP_TABLE, *PROGUEAP_TABLE; ++ ++typedef struct { ++ BOOLEAN Enable; ++ UCHAR Delta; ++ BOOLEAN PlusSign; ++} CCK_TX_POWER_CALIBRATE, *PCCK_TX_POWER_CALIBRATE; ++ ++// ++// Receive Tuple Cache Format ++// ++typedef struct _TUPLE_CACHE { ++ BOOLEAN Valid; ++ UCHAR MacAddress[MAC_ADDR_LEN]; ++ USHORT Sequence; ++ USHORT Frag; ++} TUPLE_CACHE, *PTUPLE_CACHE; ++ ++// ++// Fragment Frame structure ++// ++typedef struct _FRAGMENT_FRAME { ++ PNDIS_PACKET pFragPacket; ++ ULONG RxSize; ++ USHORT Sequence; ++ USHORT LastFrag; ++ ULONG Flags; // Some extra frame information. bit 0: LLC presented ++} FRAGMENT_FRAME, *PFRAGMENT_FRAME; ++ ++ ++// ++// Packet information for NdisQueryPacket ++// ++typedef struct _PACKET_INFO { ++ UINT PhysicalBufferCount; // Physical breaks of buffer descripor chained ++ UINT BufferCount ; // Number of Buffer descriptor chained ++ UINT TotalPacketLength ; // Self explained ++ PNDIS_BUFFER pFirstBuffer; // Pointer to first buffer descriptor ++} PACKET_INFO, *PPACKET_INFO; ++ ++// ++// Tkip Key structure which RC4 key & MIC calculation ++// ++typedef struct _TKIP_KEY_INFO { ++ UINT nBytesInM; // # bytes in M for MICKEY ++ ULONG IV16; ++ ULONG IV32; ++ ULONG K0; // for MICKEY Low ++ ULONG K1; // for MICKEY Hig ++ ULONG L; // Current state for MICKEY ++ ULONG R; // Current state for MICKEY ++ ULONG M; // Message accumulator for MICKEY ++ UCHAR RC4KEY[16]; ++ UCHAR MIC[8]; ++} TKIP_KEY_INFO, *PTKIP_KEY_INFO; ++ ++// ++// Private / Misc data, counters for driver internal use ++// ++typedef struct __PRIVATE_STRUC { ++ UINT SystemResetCnt; // System reset counter ++ UINT TxRingFullCnt; // Tx ring full occurrance number ++ UINT PhyRxErrCnt; // PHY Rx error count, for debug purpose, might move to global counter ++ // Variables for WEP encryption / decryption in rtmp_wep.c ++ UINT FCSCRC32; ++ ARCFOURCONTEXT WEPCONTEXT; ++ // Tkip stuff ++ TKIP_KEY_INFO Tx; ++ TKIP_KEY_INFO Rx; ++} PRIVATE_STRUC, *PPRIVATE_STRUC; ++ ++// structure to tune BBP R66 (BBP TUNING) ++typedef struct _BBP_R66_TUNING { ++ BOOLEAN bEnable; ++ USHORT FalseCcaLowerThreshold; // default 100 ++ USHORT FalseCcaUpperThreshold; // default 512 ++ UCHAR R66Delta; ++ UCHAR R66CurrentValue; ++ BOOLEAN R66LowerUpperSelect; //Before LinkUp, Used LowerBound or UpperBound as R66 value. ++} BBP_R66_TUNING, *PBBP_R66_TUNING; ++ ++// structure to store channel TX power ++typedef struct _CHANNEL_TX_POWER { ++ USHORT RemainingTimeForUse; //unit: sec ++ UCHAR Channel; ++#ifdef DOT11N_DRAFT3 ++ BOOLEAN bEffectedChannel; // For BW 40 operating in 2.4GHz , the "effected channel" is the channel that is covered in 40Mhz. ++#endif // DOT11N_DRAFT3 // ++ CHAR Power; ++ CHAR Power2; ++ UCHAR MaxTxPwr; ++ UCHAR DfsReq; ++} CHANNEL_TX_POWER, *PCHANNEL_TX_POWER; ++ ++// structure to store 802.11j channel TX power ++typedef struct _CHANNEL_11J_TX_POWER { ++ UCHAR Channel; ++ UCHAR BW; // BW_10 or BW_20 ++ CHAR Power; ++ CHAR Power2; ++ USHORT RemainingTimeForUse; //unit: sec ++} CHANNEL_11J_TX_POWER, *PCHANNEL_11J_TX_POWER; ++ ++typedef enum _ABGBAND_STATE_ { ++ UNKNOWN_BAND, ++ BG_BAND, ++ A_BAND, ++} ABGBAND_STATE; ++ ++typedef struct _MLME_STRUCT { ++#ifdef CONFIG_STA_SUPPORT ++ // STA state machines ++ STATE_MACHINE CntlMachine; ++ STATE_MACHINE AssocMachine; ++ STATE_MACHINE AuthMachine; ++ STATE_MACHINE AuthRspMachine; ++ STATE_MACHINE SyncMachine; ++ STATE_MACHINE WpaPskMachine; ++ STATE_MACHINE LeapMachine; ++ STATE_MACHINE AironetMachine; ++ STATE_MACHINE_FUNC AssocFunc[ASSOC_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AuthFunc[AUTH_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AuthRspFunc[AUTH_RSP_FUNC_SIZE]; ++ STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE]; ++ STATE_MACHINE_FUNC WpaPskFunc[WPA_PSK_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AironetFunc[AIRONET_FUNC_SIZE]; ++#endif // CONFIG_STA_SUPPORT // ++ STATE_MACHINE_FUNC ActFunc[ACT_FUNC_SIZE]; ++ // Action ++ STATE_MACHINE ActMachine; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ STATE_MACHINE DlsMachine; ++ STATE_MACHINE_FUNC DlsFunc[DLS_FUNC_SIZE]; ++#endif // QOS_DLS_SUPPORT // ++ ++ ++ ++ ++ ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming ++ ULONG Now32; // latch the value of NdisGetSystemUpTime() ++ ULONG LastSendNULLpsmTime; ++ ++ BOOLEAN bRunning; ++ NDIS_SPIN_LOCK TaskLock; ++ MLME_QUEUE Queue; ++ ++ UINT ShiftReg; ++ ++ RALINK_TIMER_STRUCT PeriodicTimer; ++ RALINK_TIMER_STRUCT APSDPeriodicTimer; ++ RALINK_TIMER_STRUCT LinkDownTimer; ++ RALINK_TIMER_STRUCT LinkUpTimer; ++#ifdef RT2860 ++ UCHAR bPsPollTimerRunning; ++ RALINK_TIMER_STRUCT PsPollTimer; ++ RALINK_TIMER_STRUCT RadioOnOffTimer; ++#endif // RT2860 // ++ ULONG PeriodicRound; ++ ULONG OneSecPeriodicRound; ++ ++ UCHAR RealRxPath; ++ BOOLEAN bLowThroughput; ++ BOOLEAN bEnableAutoAntennaCheck; ++ RALINK_TIMER_STRUCT RxAntEvalTimer; ++ ++ ++} MLME_STRUCT, *PMLME_STRUCT; ++ ++// structure for radar detection and channel switch ++typedef struct _RADAR_DETECT_STRUCT { ++ UCHAR CSCount; //Channel switch counter ++ UCHAR CSPeriod; //Channel switch period (beacon count) ++ UCHAR RDCount; //Radar detection counter ++ UCHAR RDMode; //Radar Detection mode ++ UCHAR RDDurRegion; //Radar detection duration region ++ UCHAR BBPR16; ++ UCHAR BBPR17; ++ UCHAR BBPR18; ++ UCHAR BBPR21; ++ UCHAR BBPR22; ++ UCHAR BBPR64; ++ ULONG InServiceMonitorCount; // unit: sec ++ UINT8 DfsSessionTime; ++ BOOLEAN bFastDfs; ++ UINT8 ChMovingTime; ++ UINT8 LongPulseRadarTh; ++} RADAR_DETECT_STRUCT, *PRADAR_DETECT_STRUCT; ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++typedef enum CD_STATE_n ++{ ++ CD_NORMAL, ++ CD_SILENCE, ++ CD_MAX_STATE ++} CD_STATE; ++ ++typedef struct CARRIER_DETECTION_s ++{ ++ BOOLEAN Enable; ++ UINT8 CDSessionTime; ++ UINT8 CDPeriod; ++ CD_STATE CD_State; ++} CARRIER_DETECTION, *PCARRIER_DETECTION; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++typedef enum _REC_BLOCKACK_STATUS ++{ ++ Recipient_NONE=0, ++ Recipient_USED, ++ Recipient_HandleRes, ++ Recipient_Accept ++} REC_BLOCKACK_STATUS, *PREC_BLOCKACK_STATUS; ++ ++typedef enum _ORI_BLOCKACK_STATUS ++{ ++ Originator_NONE=0, ++ Originator_USED, ++ Originator_WaitRes, ++ Originator_Done ++} ORI_BLOCKACK_STATUS, *PORI_BLOCKACK_STATUS; ++ ++#ifdef DOT11_N_SUPPORT ++typedef struct _BA_ORI_ENTRY{ ++ UCHAR Wcid; ++ UCHAR TID; ++ UCHAR BAWinSize; ++ UCHAR Token; ++// Sequence is to fill every outgoing QoS DATA frame's sequence field in 802.11 header. ++ USHORT Sequence; ++ USHORT TimeOutValue; ++ ORI_BLOCKACK_STATUS ORI_BA_Status; ++ RALINK_TIMER_STRUCT ORIBATimer; ++ PVOID pAdapter; ++} BA_ORI_ENTRY, *PBA_ORI_ENTRY; ++ ++typedef struct _BA_REC_ENTRY { ++ UCHAR Wcid; ++ UCHAR TID; ++ UCHAR BAWinSize; // 7.3.1.14. each buffer is capable of holding a max AMSDU or MSDU. ++ USHORT LastIndSeq; ++ USHORT TimeOutValue; ++ RALINK_TIMER_STRUCT RECBATimer; ++ ULONG LastIndSeqAtTimer; ++ ULONG nDropPacket; ++ ULONG rcvSeq; ++ REC_BLOCKACK_STATUS REC_BA_Status; ++ NDIS_SPIN_LOCK RxReRingLock; // Rx Ring spinlock ++ PVOID pAdapter; ++ struct reordering_list list; ++} BA_REC_ENTRY, *PBA_REC_ENTRY; ++ ++ ++typedef struct { ++ ULONG numAsRecipient; // I am recipient of numAsRecipient clients. These client are in the BARecEntry[] ++ ULONG numAsOriginator; // I am originator of numAsOriginator clients. These clients are in the BAOriEntry[] ++ BA_ORI_ENTRY BAOriEntry[MAX_LEN_OF_BA_ORI_TABLE]; ++ BA_REC_ENTRY BARecEntry[MAX_LEN_OF_BA_REC_TABLE]; ++} BA_TABLE, *PBA_TABLE; ++ ++//For QureyBATableOID use; ++typedef struct PACKED _OID_BA_REC_ENTRY{ ++ UCHAR MACAddr[MAC_ADDR_LEN]; ++ UCHAR BaBitmap; // if (BaBitmap&(1<> 3) + 1) /* /8 + 1 */ ++#define WLAN_CT_TIM_BCMC_OFFSET 0 /* unit: 32B */ ++ ++/* clear bcmc TIM bit */ ++#define WLAN_MR_TIM_BCMC_CLEAR(apidx) \ ++ pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] &= ~BIT8[0]; ++ ++/* set bcmc TIM bit */ ++#define WLAN_MR_TIM_BCMC_SET(apidx) \ ++ pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] |= BIT8[0]; ++ ++/* clear a station PS TIM bit */ ++#define WLAN_MR_TIM_BIT_CLEAR(ad_p, apidx, wcid) \ ++ { UCHAR tim_offset = wcid >> 3; \ ++ UCHAR bit_offset = wcid & 0x7; \ ++ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] &= (~BIT8[bit_offset]); } ++ ++/* set a station PS TIM bit */ ++#define WLAN_MR_TIM_BIT_SET(ad_p, apidx, wcid) \ ++ { UCHAR tim_offset = wcid >> 3; \ ++ UCHAR bit_offset = wcid & 0x7; \ ++ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] |= BIT8[bit_offset]; } ++ ++ ++typedef struct _MULTISSID_STRUCT { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ USHORT CapabilityInfo; ++ ++ PNET_DEV MSSIDDev; ++ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++ WPA_MIX_PAIR_CIPHER WpaMixPairCipher; ++ ++ ULONG TxCount; ++ ULONG RxCount; ++ ULONG ReceivedByteCount; ++ ULONG TransmittedByteCount; ++ ULONG RxErrorCount; ++ ULONG RxDropCount; ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. this is for reading registry setting only. not useful. ++ BOOLEAN bAutoTxRateSwitch; ++ ++ UCHAR DefaultKeyId; ++ ++ UCHAR TxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11, ... ++ UCHAR DesiredRates[MAX_LEN_OF_SUPPORTED_RATES];// OID_802_11_DESIRED_RATES ++ UCHAR DesiredRatesIndex; ++ UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ ++ UCHAR TimBitmaps[WLAN_MAX_NUM_OF_TIM]; ++ ++ // WPA ++ UCHAR GMK[32]; ++ UCHAR PMK[32]; ++ UCHAR GTK[32]; ++ BOOLEAN IEEE8021X; ++ BOOLEAN PreAuth; ++ UCHAR GNonce[32]; ++ UCHAR PortSecured; ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; ++ UCHAR BANClass3Data; ++ ULONG IsolateInterStaTraffic; ++ ++ UCHAR RSNIE_Len[2]; ++ UCHAR RSN_IE[2][MAX_LEN_OF_RSNIE]; ++ ++ ++ UCHAR TimIELocationInBeacon; ++ UCHAR CapabilityInfoLocationInBeacon; ++ // outgoing BEACON frame buffer and corresponding TXWI ++ // PTXWI_STRUC BeaconTxWI; // ++ CHAR BeaconBuf[MAX_BEACON_SIZE]; // NOTE: BeaconBuf should be 4-byte aligned ++ ++ BOOLEAN bHideSsid; ++ UINT16 StationKeepAliveTime; // unit: second ++ ++ USHORT VLAN_VID; ++ USHORT VLAN_Priority; ++ ++ RT_802_11_ACL AccessControlList; ++ ++ // EDCA Qos ++ BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM ++ BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS ++ ++ UCHAR DlsPTK[64]; // Due to windows dirver count on meetinghouse to handle 4-way shake ++ ++ // For 802.1x daemon setting per BSS ++ UCHAR radius_srv_num; ++ RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; ++ ++#ifdef RTL865X_SOC ++ unsigned int mylinkid; ++#endif ++ ++ ++ UINT32 RcvdConflictSsidCount; ++ UINT32 RcvdSpoofedAssocRespCount; ++ UINT32 RcvdSpoofedReassocRespCount; ++ UINT32 RcvdSpoofedProbeRespCount; ++ UINT32 RcvdSpoofedBeaconCount; ++ UINT32 RcvdSpoofedDisassocCount; ++ UINT32 RcvdSpoofedAuthCount; ++ UINT32 RcvdSpoofedDeauthCount; ++ UINT32 RcvdSpoofedUnknownMgmtCount; ++ UINT32 RcvdReplayAttackCount; ++ ++ CHAR RssiOfRcvdConflictSsid; ++ CHAR RssiOfRcvdSpoofedAssocResp; ++ CHAR RssiOfRcvdSpoofedReassocResp; ++ CHAR RssiOfRcvdSpoofedProbeResp; ++ CHAR RssiOfRcvdSpoofedBeacon; ++ CHAR RssiOfRcvdSpoofedDisassoc; ++ CHAR RssiOfRcvdSpoofedAuth; ++ CHAR RssiOfRcvdSpoofedDeauth; ++ CHAR RssiOfRcvdSpoofedUnknownMgmt; ++ CHAR RssiOfRcvdReplayAttack; ++ ++ BOOLEAN bBcnSntReq; ++ UCHAR BcnBufIdx; ++} MULTISSID_STRUCT, *PMULTISSID_STRUCT; ++ ++ ++ ++#ifdef DOT11N_DRAFT3 ++typedef enum _BSS2040COEXIST_FLAG{ ++ BSS_2040_COEXIST_DISABLE = 0, ++ BSS_2040_COEXIST_TIMER_FIRED = 1, ++ BSS_2040_COEXIST_INFO_SYNC = 2, ++ BSS_2040_COEXIST_INFO_NOTIFY = 4, ++}BSS2040COEXIST_FLAG; ++#endif // DOT11N_DRAFT3 // ++ ++// configuration common to OPMODE_AP as well as OPMODE_STA ++typedef struct _COMMON_CONFIG { ++ ++ BOOLEAN bCountryFlag; ++ UCHAR CountryCode[3]; ++ UCHAR Geography; ++ UCHAR CountryRegion; // Enum of country region, 0:FCC, 1:IC, 2:ETSI, 3:SPAIN, 4:France, 5:MKK, 6:MKK1, 7:Israel ++ UCHAR CountryRegionForABand; // Enum of country region for A band ++ UCHAR PhyMode; // PHY_11A, PHY_11B, PHY_11BG_MIXED, PHY_ABG_MIXED ++ USHORT Dsifs; // in units of usec ++ ULONG PacketFilter; // Packet filter for receiving ++ ++ CHAR Ssid[MAX_LEN_OF_SSID]; // NOT NULL-terminated ++ UCHAR SsidLen; // the actual ssid length in used ++ UCHAR LastSsidLen; // the actual ssid length in used ++ CHAR LastSsid[MAX_LEN_OF_SSID]; // NOT NULL-terminated ++ UCHAR LastBssid[MAC_ADDR_LEN]; ++ ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ USHORT BeaconPeriod; ++ UCHAR Channel; ++ UCHAR CentralChannel; // Central Channel when using 40MHz is indicating. not real channel. ++ ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen; ++ UCHAR DesireRate[MAX_LEN_OF_SUPPORTED_RATES]; // OID_802_11_DESIRED_RATES ++ UCHAR MaxDesiredRate; ++ UCHAR ExpectedACKRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ ++ ULONG BasicRateBitmap; // backup basic ratebitmap ++ ++ BOOLEAN bAPSDCapable; ++ BOOLEAN bInServicePeriod; ++ BOOLEAN bAPSDAC_BE; ++ BOOLEAN bAPSDAC_BK; ++ BOOLEAN bAPSDAC_VI; ++ BOOLEAN bAPSDAC_VO; ++ BOOLEAN bNeedSendTriggerFrame; ++ BOOLEAN bAPSDForcePowerSave; // Force power save mode, should only use in APSD-STAUT ++ ULONG TriggerTimerCount; ++ UCHAR MaxSPLength; ++ UCHAR BBPCurrentBW; // BW_10, BW_20, BW_40 ++ REG_TRANSMIT_SETTING RegTransmitSetting; //registry transmit setting. this is for reading registry setting only. not useful. ++ UCHAR TxRate; // Same value to fill in TXD. TxRate is 6-bit ++ UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ UCHAR TxRateIndex; // Tx rate index in RateSwitchTable ++ UCHAR TxRateTableSize; // Valid Tx rate table size in RateSwitchTable ++ UCHAR MinTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ UCHAR RtsRate; // RATE_xxx ++ HTTRANSMIT_SETTING MlmeTransmit; // MGMT frame PHY rate setting when operatin at Ht rate. ++ UCHAR MlmeRate; // RATE_xxx, used to send MLME frames ++ UCHAR BasicMlmeRate; // Default Rate for sending MLME frames ++ ++ USHORT RtsThreshold; // in unit of BYTE ++ USHORT FragmentThreshold; // in unit of BYTE ++ ++ UCHAR TxPower; // in unit of mW ++ ULONG TxPowerPercentage; // 0~100 % ++ ULONG TxPowerDefault; // keep for TxPowerPercentage ++ ++#ifdef DOT11_N_SUPPORT ++ BACAP_STRUC BACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 ++ BACAP_STRUC REGBACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 ++#endif // DOT11_N_SUPPORT // ++ IOT_STRUC IOTestParm; // 802.11n InterOpbility Test Parameter; ++ ULONG TxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto ++ BOOLEAN bUseZeroToDisableFragment; // Microsoft use 0 as disable ++ ULONG UseBGProtection; // 0: auto, 1: always use, 2: always not use ++ BOOLEAN bUseShortSlotTime; // 0: disable, 1 - use short slot (9us) ++ BOOLEAN bEnableTxBurst; // 1: enble TX PACKET BURST, 0: disable TX PACKET BURST ++ BOOLEAN bAggregationCapable; // 1: enable TX aggregation when the peer supports it ++ BOOLEAN bPiggyBackCapable; // 1: enable TX piggy-back according MAC's version ++ BOOLEAN bIEEE80211H; // 1: enable IEEE802.11h spec. ++ ULONG DisableOLBCDetect; // 0: enable OLBC detect; 1 disable OLBC detect ++ ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bRdg; ++#endif // DOT11_N_SUPPORT // ++ BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM ++ QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP ++ EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP ++ QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP ++ UCHAR AckPolicy[4]; // ACK policy of the specified AC. see ACK_xxx ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS ++#endif // CONFIG_STA_SUPPORT // ++ // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular ++ // BOOLEAN control, either ON or OFF. These flags should always be accessed via ++ // OPSTATUS_TEST_FLAG(), OPSTATUS_SET_FLAG(), OP_STATUS_CLEAR_FLAG() macros. ++ // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition ++ ULONG OpStatusFlags; ++ ++ BOOLEAN NdisRadioStateOff; //For HCT 12.0, set this flag to TRUE instead of called MlmeRadioOff. ++ ABGBAND_STATE BandState; // For setting BBP used on B/G or A mode. ++ ++ // IEEE802.11H--DFS. ++ RADAR_DETECT_STRUCT RadarDetect; ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++ CARRIER_DETECTION CarrierDetect; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ UCHAR BASize; // USer desired BAWindowSize. Should not exceed our max capability ++ //RT_HT_CAPABILITY SupportedHtPhy; ++ RT_HT_CAPABILITY DesiredHtPhy; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHTInfo; // Useful as AP. ++ //This IE is used with channel switch announcement element when changing to a new 40MHz. ++ //This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. ++ NEW_EXT_CHAN_IE NewExtChanOffset; //7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present ++ ++#ifdef DOT11N_DRAFT3 ++ UCHAR Bss2040CoexistFlag; // bit 0: bBssCoexistTimerRunning, bit 1: NeedSyncAddHtInfo. ++ RALINK_TIMER_STRUCT Bss2040CoexistTimer; ++ ++ //This IE is used for 20/40 BSS Coexistence. ++ BSS_2040_COEXIST_IE BSS2040CoexistInfo; ++ // ====== 11n D3.0 =======================> ++ USHORT Dot11OBssScanPassiveDwell; // Unit : TU. 5~1000 ++ USHORT Dot11OBssScanActiveDwell; // Unit : TU. 10~1000 ++ USHORT Dot11BssWidthTriggerScanInt; // Unit : Second ++ USHORT Dot11OBssScanPassiveTotalPerChannel; // Unit : TU. 200~10000 ++ USHORT Dot11OBssScanActiveTotalPerChannel; // Unit : TU. 20~10000 ++ USHORT Dot11BssWidthChanTranDelayFactor; ++ USHORT Dot11OBssScanActivityThre; // Unit : percentage ++ ++ ULONG Dot11BssWidthChanTranDelay; // multiple of (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) ++ ULONG CountDownCtr; // CountDown Counter from (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) ++ ++ NDIS_SPIN_LOCK TriggerEventTabLock; ++ BSS_2040_COEXIST_IE LastBSSCoexist2040; ++ BSS_2040_COEXIST_IE BSSCoexist2040; ++ TRIGGER_EVENT_TAB TriggerEventTab; ++ UCHAR ChannelListIdx; ++ // <====== 11n D3.0 ======================= ++ BOOLEAN bOverlapScanning; ++#endif // DOT11N_DRAFT3 // ++ ++ BOOLEAN bHTProtect; ++ BOOLEAN bMIMOPSEnable; ++ BOOLEAN bBADecline; ++ BOOLEAN bDisableReordering; ++ BOOLEAN bForty_Mhz_Intolerant; ++ BOOLEAN bExtChannelSwitchAnnouncement; ++ BOOLEAN bRcvBSSWidthTriggerEvents; ++ ULONG LastRcvBSSWidthTriggerEventsTime; ++ ++ UCHAR TxBASize; ++#endif // DOT11_N_SUPPORT // ++ ++ // Enable wireless event ++ BOOLEAN bWirelessEvent; ++ BOOLEAN bWiFiTest; // Enable this parameter for WiFi test ++ ++ // Tx & Rx Stream number selection ++ UCHAR TxStream; ++ UCHAR RxStream; ++ ++ // transmit phy mode, trasmit rate for Multicast. ++#ifdef MCAST_RATE_SPECIFIC ++ UCHAR McastTransmitMcs; ++ UCHAR McastTransmitPhyMode; ++#endif // MCAST_RATE_SPECIFIC // ++ ++ BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled ++ ++ ++ ++ NDIS_SPIN_LOCK MeasureReqTabLock; ++ PMEASURE_REQ_TAB pMeasureReqTab; ++ ++ NDIS_SPIN_LOCK TpcReqTabLock; ++ PTPC_REQ_TAB pTpcReqTab; ++ ++ // transmit phy mode, trasmit rate for Multicast. ++#ifdef MCAST_RATE_SPECIFIC ++ HTTRANSMIT_SETTING MCastPhyMode; ++#endif // MCAST_RATE_SPECIFIC // ++ ++#ifdef SINGLE_SKU ++ UINT16 DefineMaxTxPwr; ++#endif // SINGLE_SKU // ++ ++ ++} COMMON_CONFIG, *PCOMMON_CONFIG; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++// STA configuration and status ++typedef struct _STA_ADMIN_CONFIG { ++ // GROUP 1 - ++ // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe ++ // the user intended configuration, but not necessary fully equal to the final ++ // settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either ++ // AP or IBSS holder). ++ // Once initialized, user configuration can only be changed via OID_xxx ++ UCHAR BssType; // BSS_INFRA or BSS_ADHOC ++ USHORT AtimWin; // used when starting a new IBSS ++ ++ // GROUP 2 - ++ // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe ++ // the user intended configuration, and should be always applied to the final ++ // settings in ACTIVE BSS without compromising with the BSS holder. ++ // Once initialized, user configuration can only be changed via OID_xxx ++ UCHAR RssiTrigger; ++ UCHAR RssiTriggerMode; // RSSI_TRIGGERED_UPON_BELOW_THRESHOLD or RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD ++ USHORT DefaultListenCount; // default listen count; ++ ULONG WindowsPowerMode; // Power mode for AC power ++ ULONG WindowsBatteryPowerMode; // Power mode for battery if exists ++ BOOLEAN bWindowsACCAMEnable; // Enable CAM power mode when AC on ++ BOOLEAN bAutoReconnect; // Set to TRUE when setting OID_802_11_SSID with no matching BSSID ++ ULONG WindowsPowerProfile; // Windows power profile, for NDIS5.1 PnP ++ ++ // MIB:ieee802dot11.dot11smt(1).dot11StationConfigTable(1) ++ USHORT Psm; // power management mode (PWR_ACTIVE|PWR_SAVE) ++ USHORT DisassocReason; ++ UCHAR DisassocSta[MAC_ADDR_LEN]; ++ USHORT DeauthReason; ++ UCHAR DeauthSta[MAC_ADDR_LEN]; ++ USHORT AuthFailReason; ++ UCHAR AuthFailSta[MAC_ADDR_LEN]; ++ ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++ ++ UCHAR PMK[32]; // WPA PSK mode PMK ++ UCHAR PTK[64]; // WPA PSK mode PTK ++ UCHAR GTK[32]; // GTK from authenticator ++ BSSID_INFO SavedPMK[PMKID_NO]; ++ UINT SavedPMKNum; // Saved PMKID number ++ ++ UCHAR DefaultKeyId; ++ ++ ++ // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED ++ UCHAR PortSecured; ++ ++ // For WPA countermeasures ++ ULONG LastMicErrorTime; // record last MIC error time ++ ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). ++ BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. ++ // For WPA-PSK supplicant state ++ WPA_STATE WpaState; // Default is SS_NOTUSE and handled by microsoft 802.1x ++ UCHAR ReplayCounter[8]; ++ UCHAR ANonce[32]; // ANonce for WPA-PSK from aurhenticator ++ UCHAR SNonce[32]; // SNonce for WPA-PSK ++ ++ UCHAR LastSNR0; // last received BEACON's SNR ++ UCHAR LastSNR1; // last received BEACON's SNR for 2nd antenna ++ RSSI_SAMPLE RssiSample; ++ ULONG NumOfAvgRssiSample; ++ ++ ULONG LastBeaconRxTime; // OS's timestamp of the last BEACON RX time ++ ULONG Last11bBeaconRxTime; // OS's timestamp of the last 11B BEACON RX time ++ ULONG Last11gBeaconRxTime; // OS's timestamp of the last 11G BEACON RX time ++ ULONG Last20NBeaconRxTime; // OS's timestamp of the last 20MHz N BEACON RX time ++ ++ ULONG LastScanTime; // Record last scan time for issue BSSID_SCAN_LIST ++ ULONG ScanCnt; // Scan counts since most recent SSID, BSSID, SCAN OID request ++ BOOLEAN bSwRadio; // Software controlled Radio On/Off, TRUE: On ++ BOOLEAN bHwRadio; // Hardware controlled Radio On/Off, TRUE: On ++ BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state ++ BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled ++ BOOLEAN bShowHiddenSSID; // Show all known SSID in SSID list get operation ++ ++ BOOLEAN AdhocBOnlyJoined; // Indicate Adhoc B Join. ++ BOOLEAN AdhocBGJoined; // Indicate Adhoc B/G Join. ++ BOOLEAN Adhoc20NJoined; // Indicate Adhoc 20MHz N Join. ++ ++ // New for WPA, windows want us to to keep association information and ++ // Fixed IEs from last association response ++ NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; ++ USHORT ReqVarIELen; // Length of next VIE include EID & Length ++ UCHAR ReqVarIEs[MAX_VIE_LEN]; // The content saved here should be little-endian format. ++ USHORT ResVarIELen; // Length of next VIE include EID & Length ++ UCHAR ResVarIEs[MAX_VIE_LEN]; ++ ++ UCHAR RSNIE_Len; ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be little-endian format. ++ ++ // New variables used for CCX 1.0 ++ BOOLEAN bCkipOn; ++ BOOLEAN bCkipCmicOn; ++ UCHAR CkipFlag; ++ UCHAR GIV[3]; //for CCX iv ++ UCHAR RxSEQ[4]; ++ UCHAR TxSEQ[4]; ++ UCHAR CKIPMIC[4]; ++ UCHAR LeapAuthMode; ++ LEAP_AUTH_INFO LeapAuthInfo; ++ UCHAR HashPwd[16]; ++ UCHAR NetworkChallenge[8]; ++ UCHAR NetworkChallengeResponse[24]; ++ UCHAR PeerChallenge[8]; ++ ++ UCHAR PeerChallengeResponse[24]; ++ UCHAR SessionKey[16]; //Network session keys (NSK) ++ RALINK_TIMER_STRUCT LeapAuthTimer; ++ ROGUEAP_TABLE RogueApTab; //Cisco CCX1 Rogue AP Detection ++ ++ // New control flags for CCX ++ CCX_CONTROL CCXControl; // Master administration state ++ BOOLEAN CCXEnable; // Actual CCX state ++ UCHAR CCXScanChannel; // Selected channel for CCX beacon request ++ USHORT CCXScanTime; // Time out to wait for beacon and probe response ++ UCHAR CCXReqType; // Current processing CCX request type ++ BSS_TABLE CCXBssTab; // BSS Table ++ UCHAR FrameReportBuf[2048]; // Buffer for creating frame report ++ USHORT FrameReportLen; // Current Frame report length ++ ULONG CLBusyBytes; // Save the total bytes received durning channel load scan time ++ USHORT RPIDensity[8]; // Array for RPI density collection ++ // Start address of each BSS table within FrameReportBuf ++ // It's important to update the RxPower of the corresponding Bss ++ USHORT BssReportOffset[MAX_LEN_OF_BSS_TABLE]; ++ USHORT BeaconToken; // Token for beacon report ++ ULONG LastBssIndex; // Most current reported Bss index ++ RM_REQUEST_ACTION MeasurementRequest[16]; // Saved measurement request ++ UCHAR RMReqCnt; // Number of measurement request saved. ++ UCHAR CurrentRMReqIdx; // Number of measurement request saved. ++ BOOLEAN ParallelReq; // Parallel measurement, only one request performed, ++ // It must be the same channel with maximum duration ++ USHORT ParallelDuration; // Maximum duration for parallel measurement ++ UCHAR ParallelChannel; // Only one channel with parallel measurement ++ USHORT IAPPToken; // IAPP dialog token ++ UCHAR CCXQosECWMin; // Cisco QOS ECWMin for AC 0 ++ UCHAR CCXQosECWMax; // Cisco QOS ECWMax for AC 0 ++ // Hack for channel load and noise histogram parameters ++ UCHAR NHFactor; // Parameter for Noise histogram ++ UCHAR CLFactor; // Parameter for channel load ++ ++ UCHAR KRK[16]; //Key Refresh Key. ++ UCHAR BTK[32]; //Base Transient Key ++ BOOLEAN CCKMLinkUpFlag; ++ ULONG CCKMRN; //(Re)Association request number. ++ LARGE_INTEGER CCKMBeaconAtJoinTimeStamp; //TSF timer for Re-assocaite to the new AP ++ UCHAR AironetCellPowerLimit; //in dBm ++ UCHAR AironetIPAddress[4]; //eg. 192.168.1.1 ++ BOOLEAN CCXAdjacentAPReportFlag; //flag for determining report Assoc Lost time ++ CHAR CCXAdjacentAPSsid[MAX_LEN_OF_SSID]; //Adjacent AP's SSID report ++ UCHAR CCXAdjacentAPSsidLen; // the actual ssid length in used ++ UCHAR CCXAdjacentAPBssid[MAC_ADDR_LEN]; //Adjacent AP's BSSID report ++ USHORT CCXAdjacentAPChannel; ++ ULONG CCXAdjacentAPLinkDownTime; //for Spec S32. ++ ++ RALINK_TIMER_STRUCT StaQuickResponeForRateUpTimer; ++ BOOLEAN StaQuickResponeForRateUpTimerRunning; ++ ++ UCHAR DtimCount; // 0.. DtimPeriod-1 ++ UCHAR DtimPeriod; // default = 3 ++ ++#ifdef QOS_DLS_SUPPORT ++ RT_802_11_DLS DLSEntry[MAX_NUM_OF_DLS_ENTRY]; ++ UCHAR DlsReplayCounter[8]; ++#endif // QOS_DLS_SUPPORT // ++ //////////////////////////////////////////////////////////////////////////////////////// ++ // This is only for WHQL test. ++ BOOLEAN WhqlTest; ++ //////////////////////////////////////////////////////////////////////////////////////// ++ ++ RALINK_TIMER_STRUCT WpaDisassocAndBlockAssocTimer; ++ // Fast Roaming ++ BOOLEAN bFastRoaming; // 0:disable fast roaming, 1:enable fast roaming ++ CHAR dBmToRoam; // the condition to roam when receiving Rssi less than this value. It's negative value. ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ BOOLEAN IEEE8021X; ++ BOOLEAN IEEE8021x_required_keys; ++ CIPHER_KEY DesireSharedKey[4]; // Record user desired WEP keys ++ UCHAR DesireSharedKeyId; ++ ++ // 0: driver ignores wpa_supplicant ++ // 1: wpa_supplicant initiates scanning and AP selection ++ // 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters ++ UCHAR WpaSupplicantUP; ++ UCHAR WpaSupplicantScanCount; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ CHAR dev_name[16]; ++ USHORT OriDevType; ++ ++ BOOLEAN bTGnWifiTest; ++ BOOLEAN bScanReqIsFromWebUI; ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ ++#ifdef RT2860 ++ UCHAR BBPR3; ++#endif // RT2860 // ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ UCHAR IEEE80211dClientMode; ++ UCHAR StaOriCountryCode[3]; ++ UCHAR StaOriGeography; ++#endif // EXT_BUILD_CHANNEL_LIST // ++} STA_ADMIN_CONFIG, *PSTA_ADMIN_CONFIG; ++ ++// This data structure keep the current active BSS/IBSS's configuration that this STA ++// had agreed upon joining the network. Which means these parameters are usually decided ++// by the BSS/IBSS creator instead of user configuration. Data in this data structurre ++// is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. ++// Normally, after SCAN or failed roaming attempts, we need to recover back to ++// the current active settings. ++typedef struct _STA_ACTIVE_CONFIG { ++ USHORT Aid; ++ USHORT AtimWin; // in kusec; IBSS parameter set element ++ USHORT CapabilityInfo; ++ USHORT CfpMaxDuration; ++ USHORT CfpPeriod; ++ ++ // Copy supported rate from desired AP's beacon. We are trying to match ++ // AP's supported and extended rate settings. ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRateLen; ++ // Copy supported ht from desired AP's beacon. We are trying to match ++ RT_HT_PHY_INFO SupportedPhyInfo; ++ RT_HT_CAPABILITY SupportedHtPhy; ++} STA_ACTIVE_CONFIG, *PSTA_ACTIVE_CONFIG; ++#endif // CONFIG_STA_SUPPORT // ++ ++// ----------- start of AP -------------------------- ++// AUTH-RSP State Machine Aux data structure ++typedef struct _AP_MLME_AUX { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Alg; ++ CHAR Challenge[CIPHER_TEXT_LEN]; ++} AP_MLME_AUX, *PAP_MLME_AUX; ++ ++// structure to define WPA Group Key Rekey Interval ++typedef struct PACKED _RT_802_11_WPA_REKEY { ++ ULONG ReKeyMethod; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG ReKeyInterval; // time-based: seconds, packet-based: kilo-packets ++} RT_WPA_REKEY,*PRT_WPA_REKEY, RT_802_11_WPA_REKEY, *PRT_802_11_WPA_REKEY; ++ ++typedef struct _MAC_TABLE_ENTRY { ++ //Choose 1 from ValidAsWDS and ValidAsCLI to validize. ++ BOOLEAN ValidAsCLI; // Sta mode, set this TRUE after Linkup,too. ++ BOOLEAN ValidAsWDS; // This is WDS Entry. only for AP mode. ++ BOOLEAN ValidAsApCli; //This is a AP-Client entry, only for AP mode which enable AP-Client functions. ++ BOOLEAN ValidAsMesh; ++ BOOLEAN ValidAsDls; // This is DLS Entry. only for STA mode. ++ BOOLEAN isCached; ++ BOOLEAN bIAmBadAtheros; // Flag if this is Atheros chip that has IOT problem. We need to turn on RTS/CTS protection. ++ ++ UCHAR EnqueueEapolStartTimerRunning; // Enqueue EAPoL-Start for triggering EAP SM ++ //jan for wpa ++ // record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB ++ UCHAR CMTimerRunning; ++ UCHAR apidx; // MBSS number ++ UCHAR RSNIE_Len; ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; ++ UCHAR ANonce[LEN_KEY_DESC_NONCE]; ++ UCHAR R_Counter[LEN_KEY_DESC_REPLAY]; ++ UCHAR PTK[64]; ++ UCHAR ReTryCounter; ++ RALINK_TIMER_STRUCT RetryTimer; ++ RALINK_TIMER_STRUCT EnqueueStartForPSKTimer; // A timer which enqueue EAPoL-Start for triggering PSK SM ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ AP_WPA_STATE WpaState; ++ GTK_STATE GTKState; ++ USHORT PortSecured; ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ CIPHER_KEY PairwiseKey; ++ PVOID pAd; ++ INT PMKID_CacheIdx; ++ UCHAR PMKID[LEN_PMKID]; ++ ++ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR PsMode; ++ SST Sst; ++ AUTH_STATE AuthState; // for SHARED KEY authentication state machine used only ++ BOOLEAN IsReassocSta; // Indicate whether this is a reassociation procedure ++ USHORT Aid; ++ USHORT CapabilityInfo; ++ UCHAR LastRssi; ++ ULONG NoDataIdleCount; ++ UINT16 StationKeepAliveCount; // unit: second ++ ULONG PsQIdleCount; ++ QUEUE_HEADER PsQueue; ++ ++ UINT32 StaConnectTime; // the live time of this station since associated with AP ++ ++ ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bSendBAR; ++ USHORT NoBADataCountDown; ++ ++ UINT32 CachedBuf[16]; // UINT (4 bytes) for alignment ++ UINT TxBFCount; // 3*3 ++#endif // DOT11_N_SUPPORT // ++ UINT FIFOCount; ++ UINT DebugFIFOCount; ++ UINT DebugTxCount; ++ BOOLEAN bDlsInit; ++ ++ ++//==================================================== ++//WDS entry needs these ++// rt2860 add this. if ValidAsWDS==TRUE, MatchWDSTabIdx is the index in WdsTab.MacTab ++ UINT MatchWDSTabIdx; ++ UCHAR MaxSupportedRate; ++ UCHAR CurrTxRate; ++ UCHAR CurrTxRateIndex; ++ // to record the each TX rate's quality. 0 is best, the bigger the worse. ++ USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UINT32 OneSecTxNoRetryOkCount; ++ UINT32 OneSecTxRetryOkCount; ++ UINT32 OneSecTxFailCount; ++ UINT32 ContinueTxFailCnt; ++ UINT32 CurrTxRateStableTime; // # of second in current TX rate ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++//==================================================== ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ UINT MatchDlsEntryIdx; // indicate the index in pAd->StaCfg.DLSEntry ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ BOOLEAN fNoisyEnvironment; ++ BOOLEAN fLastSecAccordingRSSI; ++ UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down ++ CHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction ++ ULONG LastTxOkCount; ++ UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; ++ ++ // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular ++ // BOOLEAN control, either ON or OFF. These flags should always be accessed via ++ // CLIENT_STATUS_TEST_FLAG(), CLIENT_STATUS_SET_FLAG(), CLIENT_STATUS_CLEAR_FLAG() macros. ++ // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition. fCLIENT_STATUS_AMSDU_INUSED ++ ULONG ClientStatusFlags; ++ ++ // TODO: Shall we move that to DOT11_N_SUPPORT??? ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ ++#ifdef DOT11_N_SUPPORT ++ // HT EWC MIMO-N used parameters ++ USHORT RXBAbitmap; // fill to on-chip RXWI_BA_BITMASK in 8.1.3RX attribute entry format ++ USHORT TXBAbitmap; // This bitmap as originator, only keep in software used to mark AMPDU bit in TXWI ++ USHORT TXAutoBAbitmap; ++ USHORT BADeclineBitmap; ++ USHORT BARecWcidArray[NUM_OF_TID]; // The mapping wcid of recipient session. if RXBAbitmap bit is masked ++ USHORT BAOriWcidArray[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked ++ USHORT BAOriSequence[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked ++ ++ // 802.11n features. ++ UCHAR MpduDensity; ++ UCHAR MaxRAmpduFactor; ++ UCHAR AMsduSize; ++ UCHAR MmpsMode; // MIMO power save more. ++ ++ HT_CAPABILITY_IE HTCapability; ++ ++#ifdef DOT11N_DRAFT3 ++ UCHAR BSS2040CoexistenceMgmtSupport; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ BOOLEAN bAutoTxRateSwitch; ++ ++ UCHAR RateLen; ++ struct _MAC_TABLE_ENTRY *pNext; ++ USHORT TxSeq[NUM_OF_TID]; ++ USHORT NonQosDataSeq; ++ ++ RSSI_SAMPLE RssiSample; ++ ++ UINT32 TXMCSExpected[16]; ++ UINT32 TXMCSSuccessful[16]; ++ UINT32 TXMCSFailed[16]; ++ UINT32 TXMCSAutoFallBack[16][16]; ++} MAC_TABLE_ENTRY, *PMAC_TABLE_ENTRY; ++ ++typedef struct _MAC_TABLE { ++ USHORT Size; ++ MAC_TABLE_ENTRY *Hash[HASH_TABLE_SIZE]; ++ MAC_TABLE_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; ++ QUEUE_HEADER McastPsQueue; ++ ULONG PsQIdleCount; ++ BOOLEAN fAnyStationInPsm; ++ BOOLEAN fAnyStationBadAtheros; // Check if any Station is atheros 802.11n Chip. We need to use RTS/CTS with Atheros 802,.11n chip. ++ BOOLEAN fAnyTxOPForceDisable; // Check if it is necessary to disable BE TxOP ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN fAnyStationIsLegacy; // Check if I use legacy rate to transmit to my BSS Station/ ++ BOOLEAN fAnyStationNonGF; // Check if any Station can't support GF. ++ BOOLEAN fAnyStation20Only; // Check if any Station can't support GF. ++ BOOLEAN fAnyStationMIMOPSDynamic; // Check if any Station is MIMO Dynamic ++ BOOLEAN fAnyBASession; // Check if there is BA session. Force turn on RTS/CTS ++#endif // DOT11_N_SUPPORT // ++} MAC_TABLE, *PMAC_TABLE; ++ ++#ifdef DOT11_N_SUPPORT ++#define IS_HT_STA(_pMacEntry) \ ++ (_pMacEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) ++ ++#define IS_HT_RATE(_pMacEntry) \ ++ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++ ++#define PEER_IS_HT_RATE(_pMacEntry) \ ++ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++#endif // DOT11_N_SUPPORT // ++ ++typedef struct _WDS_ENTRY { ++ BOOLEAN Valid; ++ UCHAR Addr[MAC_ADDR_LEN]; ++ ULONG NoDataIdleCount; ++ struct _WDS_ENTRY *pNext; ++} WDS_ENTRY, *PWDS_ENTRY; ++ ++typedef struct _WDS_TABLE_ENTRY { ++ USHORT Size; ++ UCHAR WdsAddr[MAC_ADDR_LEN]; ++ WDS_ENTRY *Hash[HASH_TABLE_SIZE]; ++ WDS_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; ++ UCHAR MaxSupportedRate; ++ UCHAR CurrTxRate; ++ USHORT TxQuality[MAX_LEN_OF_SUPPORTED_RATES]; ++ USHORT OneSecTxOkCount; ++ USHORT OneSecTxRetryOkCount; ++ USHORT OneSecTxFailCount; ++ ULONG CurrTxRateStableTime; // # of second in current TX rate ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++} WDS_TABLE_ENTRY, *PWDS_TABLE_ENTRY; ++ ++typedef struct _RT_802_11_WDS_ENTRY { ++ PNET_DEV dev; ++ UCHAR Valid; ++ UCHAR PhyMode; ++ UCHAR PeerWdsAddr[MAC_ADDR_LEN]; ++ UCHAR MacTabMatchWCID; // ASIC ++ NDIS_802_11_WEP_STATUS WepStatus; ++ UCHAR KeyIdx; ++ CIPHER_KEY WdsKey; ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. ++} RT_802_11_WDS_ENTRY, *PRT_802_11_WDS_ENTRY; ++ ++typedef struct _WDS_TABLE { ++ UCHAR Mode; ++ ULONG Size; ++ RT_802_11_WDS_ENTRY WdsEntry[MAX_WDS_ENTRY]; ++} WDS_TABLE, *PWDS_TABLE; ++ ++typedef struct _APCLI_STRUCT { ++ PNET_DEV dev; ++#ifdef RTL865X_SOC ++ unsigned int mylinkid; ++#endif ++ BOOLEAN Enable; // Set it as 1 if the apcli interface was configured to "1" or by iwpriv cmd "ApCliEnable" ++ BOOLEAN Valid; // Set it as 1 if the apcli interface associated success to remote AP. ++ UCHAR MacTabWCID; //WCID value, which point to the entry of ASIC Mac table. ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ ++ UCHAR CfgSsidLen; ++ CHAR CfgSsid[MAX_LEN_OF_SSID]; ++ UCHAR CfgApCliBssid[ETH_LENGTH_OF_ADDRESS]; ++ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS]; ++ ++ ULONG ApCliRcvBeaconTime; ++ ++ ULONG CtrlCurrState; ++ ULONG SyncCurrState; ++ ULONG AuthCurrState; ++ ULONG AssocCurrState; ++ ULONG WpaPskCurrState; ++ ++ USHORT AuthReqCnt; ++ USHORT AssocReqCnt; ++ ++ ULONG ClientStatusFlags; ++ UCHAR MpduDensity; ++ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ UCHAR PSK[100]; // reserve PSK key material ++ UCHAR PSKLen; ++ UCHAR PMK[32]; // WPA PSK mode PMK ++ UCHAR GTK[32]; // GTK from authenticator ++ ++ CIPHER_KEY SharedKey[SHARE_KEY_NUM]; ++ UCHAR DefaultKeyId; ++ ++ // store RSN_IE built by driver ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be convert to little-endian format. ++ UCHAR RSNIE_Len; ++ ++ // For WPA countermeasures ++ ULONG LastMicErrorTime; // record last MIC error time ++ BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. ++ ++ // For WPA-PSK supplicant state ++ UCHAR SNonce[32]; // SNonce for WPA-PSK ++ UCHAR GNonce[32]; // GNonce for WPA-PSK from authenticator ++ ++#ifdef WSC_AP_SUPPORT ++ WSC_CTRL WscControl; ++#endif // WSC_AP_SUPPORT // ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. ++} APCLI_STRUCT, *PAPCLI_STRUCT; ++ ++// ----------- end of AP ---------------------------- ++ ++#ifdef BLOCK_NET_IF ++typedef struct _BLOCK_QUEUE_ENTRY ++{ ++ BOOLEAN SwTxQueueBlockFlag; ++ LIST_HEADER NetIfList; ++} BLOCK_QUEUE_ENTRY, *PBLOCK_QUEUE_ENTRY; ++#endif // BLOCK_NET_IF // ++ ++struct wificonf ++{ ++ BOOLEAN bShortGI; ++ BOOLEAN bGreenField; ++}; ++ ++ ++ ++ ++typedef struct _INF_PCI_CONFIG ++{ ++ PUCHAR CSRBaseAddress; // PCI MMIO Base Address, all access will use ++}INF_PCI_CONFIG; ++ ++typedef struct _INF_USB_CONFIG ++{ ++ UINT BulkInEpAddr; // bulk-in endpoint address ++ UINT BulkOutEpAddr[6]; // bulk-out endpoint address ++ ++}INF_USB_CONFIG; ++ ++#ifdef IKANOS_VX_1X0 ++ typedef void (*IkanosWlanTxCbFuncP)(void *, void *); ++ ++ struct IKANOS_TX_INFO ++ { ++ struct net_device *netdev; ++ IkanosWlanTxCbFuncP *fp; ++ }; ++#endif // IKANOS_VX_1X0 // ++ ++#ifdef NINTENDO_AP ++typedef struct _NINDO_CTRL_BLOCK { ++ ++ RT_NINTENDO_TABLE DS_TABLE; ++ ++#ifdef CHIP25XX ++ spinlock_t NINTENDO_TABLE_Lock; ++#else ++ NDIS_SPIN_LOCK NINTENDO_TABLE_Lock; ++#endif // CHIP25XX // ++ ++ UCHAR NINTENDO_UP_BUFFER[512]; ++ UCHAR Local_KeyIdx; ++ CIPHER_KEY Local_SharedKey; ++ UCHAR Local_bHideSsid; ++ UCHAR Local_AuthMode; ++ UCHAR Local_WepStatus; ++ USHORT Local_CapabilityInfo; ++} NINDO_CTRL_BLOCK; ++#endif // NINTENDO_AP // ++ ++ ++#ifdef DBG_DIAGNOSE ++#define DIAGNOSE_TIME 10 // 10 sec ++typedef struct _RtmpDiagStrcut_ ++{ // Diagnosis Related element ++ unsigned char inited; ++ unsigned char qIdx; ++ unsigned char ArrayStartIdx; ++ unsigned char ArrayCurIdx; ++ // Tx Related Count ++ USHORT TxDataCnt[DIAGNOSE_TIME]; ++ USHORT TxFailCnt[DIAGNOSE_TIME]; ++ USHORT TxDescCnt[DIAGNOSE_TIME][24]; // 3*3 // TxDesc queue length in scale of 0~14, >=15 ++ USHORT TxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 ++ USHORT TxSWQueCnt[DIAGNOSE_TIME][9]; // TxSwQueue length in scale of 0, 1, 2, 3, 4, 5, 6, 7, >=8 ++ ++ USHORT TxAggCnt[DIAGNOSE_TIME]; ++ USHORT TxNonAggCnt[DIAGNOSE_TIME]; ++ USHORT TxAMPDUCnt[DIAGNOSE_TIME][24]; // 3*3 // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. ++ USHORT TxRalinkCnt[DIAGNOSE_TIME]; // TxRalink Aggregation Count in 1 sec scale. ++ USHORT TxAMSDUCnt[DIAGNOSE_TIME]; // TxAMSUD Aggregation Count in 1 sec scale. ++ ++ // Rx Related Count ++ USHORT RxDataCnt[DIAGNOSE_TIME]; // Rx Total Data count. ++ USHORT RxCrcErrCnt[DIAGNOSE_TIME]; ++ USHORT RxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 ++}RtmpDiagStruct; ++#endif // DBG_DIAGNOSE // ++ ++ ++// ++// The miniport adapter structure ++// ++typedef struct _RTMP_ADAPTER ++{ ++ PVOID OS_Cookie; // save specific structure relative to OS ++ PNET_DEV net_dev; ++ ULONG VirtualIfCnt; ++ ++#ifdef RT2860 ++ USHORT LnkCtrlBitMask; ++ USHORT RLnkCtrlConfiguration; ++ USHORT RLnkCtrlOffset; ++ USHORT HostLnkCtrlConfiguration; ++ USHORT HostLnkCtrlOffset; ++ USHORT PCIePowerSaveLevel; ++ BOOLEAN bPCIclkOff; // flag that indicate if the PICE power status in Configuration SPace.. ++ BOOLEAN bPCIclkOffDisableTx; // ++ ++ ++/*****************************************************************************************/ ++/* PCI related parameters */ ++/*****************************************************************************************/ ++ PUCHAR CSRBaseAddress; // PCI MMIO Base Address, all access will use ++ ++ UINT int_enable_reg; ++ UINT int_disable_mask; ++ UINT int_pending; ++ ++ ++ RTMP_DMABUF TxBufSpace[NUM_OF_TX_RING]; // Shared memory of all 1st pre-allocated TxBuf associated with each TXD ++ RTMP_DMABUF RxDescRing; // Shared memory for RX descriptors ++ RTMP_DMABUF TxDescRing[NUM_OF_TX_RING]; // Shared memory for Tx descriptors ++ RTMP_TX_RING TxRing[NUM_OF_TX_RING]; // AC0~4 + HCCA ++#endif // RT2860 // ++ ++ ++ NDIS_SPIN_LOCK irq_lock; ++ UCHAR irq_disabled; ++ ++ ++ ++/*****************************************************************************************/ ++ /* Both PCI/USB related parameters */ ++/*****************************************************************************************/ ++ ++ ++/*****************************************************************************************/ ++/* Tx related parameters */ ++/*****************************************************************************************/ ++ BOOLEAN DeQueueRunning[NUM_OF_TX_RING]; // for ensuring RTUSBDeQueuePacket get call once ++ NDIS_SPIN_LOCK DeQueueLock[NUM_OF_TX_RING]; ++ ++ ++ // resource for software backlog queues ++ QUEUE_HEADER TxSwQueue[NUM_OF_TX_RING]; // 4 AC + 1 HCCA ++ NDIS_SPIN_LOCK TxSwQueueLock[NUM_OF_TX_RING]; // TxSwQueue spinlock ++ ++ RTMP_DMABUF MgmtDescRing; // Shared memory for MGMT descriptors ++ RTMP_MGMT_RING MgmtRing; ++ NDIS_SPIN_LOCK MgmtRingLock; // Prio Ring spinlock ++ ++ ++/*****************************************************************************************/ ++/* Rx related parameters */ ++/*****************************************************************************************/ ++ ++#ifdef RT2860 ++ RTMP_RX_RING RxRing; ++ NDIS_SPIN_LOCK RxRingLock; // Rx Ring spinlock ++#endif // RT2860 // ++ ++ ++ ++/*****************************************************************************************/ ++/* ASIC related parameters */ ++/*****************************************************************************************/ ++ UINT32 MACVersion; // MAC version. Record rt2860C(0x28600100) or rt2860D (0x28600101).. ++ ++ // --------------------------- ++ // E2PROM ++ // --------------------------- ++ ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused ++ UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 ++ USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; ++ ULONG FirmwareVersion; // byte 0: Minor version, byte 1: Major version, otherwise unused. ++ ++ // --------------------------- ++ // BBP Control ++ // --------------------------- ++ UCHAR BbpWriteLatch[140]; // record last BBP register value written via BBP_IO_WRITE/BBP_IO_WRITE_VY_REG_ID ++ UCHAR BbpRssiToDbmDelta; ++ BBP_R66_TUNING BbpTuning; ++ ++ // ---------------------------- ++ // RFIC control ++ // ---------------------------- ++ UCHAR RfIcType; // RFIC_xxx ++ ULONG RfFreqOffset; // Frequency offset for channel switching ++ RTMP_RF_REGS LatchRfRegs; // latch th latest RF programming value since RF IC doesn't support READ ++ ++ EEPROM_ANTENNA_STRUC Antenna; // Since ANtenna definition is different for a & g. We need to save it for future reference. ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ ++ // This soft Rx Antenna Diversity mechanism is used only when user set ++ // RX Antenna = DIVERSITY ON ++ SOFT_RX_ANT_DIVERSITY RxAnt; ++ ++ UCHAR RFProgSeq; ++ CHANNEL_TX_POWER TxPower[MAX_NUM_OF_CHANNELS]; // Store Tx power value for all channels. ++ CHANNEL_TX_POWER ChannelList[MAX_NUM_OF_CHANNELS]; // list all supported channels for site survey ++ CHANNEL_11J_TX_POWER TxPower11J[MAX_NUM_OF_11JCHANNELS]; // 802.11j channel and bw ++ CHANNEL_11J_TX_POWER ChannelList11J[MAX_NUM_OF_11JCHANNELS]; // list all supported channels for site survey ++ ++ UCHAR ChannelListNum; // number of channel in ChannelList[] ++ UCHAR Bbp94; ++ BOOLEAN BbpForCCK; ++ ULONG Tx20MPwrCfgABand[5]; ++ ULONG Tx20MPwrCfgGBand[5]; ++ ULONG Tx40MPwrCfgABand[5]; ++ ULONG Tx40MPwrCfgGBand[5]; ++ ++ BOOLEAN bAutoTxAgcA; // Enable driver auto Tx Agc control ++ UCHAR TssiRefA; // Store Tssi reference value as 25 temperature. ++ UCHAR TssiPlusBoundaryA[5]; // Tssi boundary for increase Tx power to compensate. ++ UCHAR TssiMinusBoundaryA[5]; // Tssi boundary for decrease Tx power to compensate. ++ UCHAR TxAgcStepA; // Store Tx TSSI delta increment / decrement value ++ CHAR TxAgcCompensateA; // Store the compensation (TxAgcStep * (idx-1)) ++ ++ BOOLEAN bAutoTxAgcG; // Enable driver auto Tx Agc control ++ UCHAR TssiRefG; // Store Tssi reference value as 25 temperature. ++ UCHAR TssiPlusBoundaryG[5]; // Tssi boundary for increase Tx power to compensate. ++ UCHAR TssiMinusBoundaryG[5]; // Tssi boundary for decrease Tx power to compensate. ++ UCHAR TxAgcStepG; // Store Tx TSSI delta increment / decrement value ++ CHAR TxAgcCompensateG; // Store the compensation (TxAgcStep * (idx-1)) ++ ++ //+++For RT2870, the parameteres is start from BGRssiOffset1 ~ BGRssiOffset3 ++ CHAR BGRssiOffset0; // Store B/G RSSI#0 Offset value on EEPROM 0x46h ++ CHAR BGRssiOffset1; // Store B/G RSSI#1 Offset value ++ CHAR BGRssiOffset2; // Store B/G RSSI#2 Offset value ++ //--- ++ ++ //+++For RT2870, the parameteres is start from ARssiOffset1 ~ ARssiOffset3 ++ CHAR ARssiOffset0; // Store A RSSI#0 Offset value on EEPROM 0x4Ah ++ CHAR ARssiOffset1; // Store A RSSI#1 Offset value ++ CHAR ARssiOffset2; // Store A RSSI#2 Offset value ++ //--- ++ ++ CHAR BLNAGain; // Store B/G external LNA#0 value on EEPROM 0x44h ++ CHAR ALNAGain0; // Store A external LNA#0 value for ch36~64 ++ CHAR ALNAGain1; // Store A external LNA#1 value for ch100~128 ++ CHAR ALNAGain2; // Store A external LNA#2 value for ch132~165 ++ ++ // ---------------------------- ++ // LED control ++ // ---------------------------- ++ MCU_LEDCS_STRUC LedCntl; ++ USHORT Led1; // read from EEPROM 0x3c ++ USHORT Led2; // EEPROM 0x3e ++ USHORT Led3; // EEPROM 0x40 ++ UCHAR LedIndicatorStregth; ++ UCHAR RssiSingalstrengthOffet; ++ BOOLEAN bLedOnScanning; ++ UCHAR LedStatus; ++ ++/*****************************************************************************************/ ++/* 802.11 related parameters */ ++/*****************************************************************************************/ ++ // outgoing BEACON frame buffer and corresponding TXD ++ TXWI_STRUC BeaconTxWI; ++ PUCHAR BeaconBuf; ++ USHORT BeaconOffset[HW_BEACON_MAX_COUNT]; ++ ++ // pre-build PS-POLL and NULL frame upon link up. for efficiency purpose. ++ PSPOLL_FRAME PsPollFrame; ++ HEADER_802_11 NullFrame; ++ ++//=========AP=========== ++ ++ ++//=======STA=========== ++#ifdef CONFIG_STA_SUPPORT ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++ // ----------------------------------------------- ++ // STA specific configuration & operation status ++ // used only when pAd->OpMode == OPMODE_STA ++ // ----------------------------------------------- ++ STA_ADMIN_CONFIG StaCfg; // user desired settings ++ STA_ACTIVE_CONFIG StaActive; // valid only when ADHOC_ON(pAd) || INFRA_ON(pAd) ++ CHAR nickname[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f ++ NDIS_MEDIA_STATE PreMediaState; ++#endif // CONFIG_STA_SUPPORT // ++ ++//=======Common=========== ++ // OP mode: either AP or STA ++ UCHAR OpMode; // OPMODE_STA, OPMODE_AP ++ ++ NDIS_MEDIA_STATE IndicateMediaState; // Base on Indication state, default is NdisMediaStateDisConnected ++ ++ // MAT related parameters ++ ++ // configuration: read from Registry & E2PROM ++ BOOLEAN bLocalAdminMAC; // Use user changed MAC ++ UCHAR PermanentAddress[MAC_ADDR_LEN]; // Factory default MAC address ++ UCHAR CurrentAddress[MAC_ADDR_LEN]; // User changed MAC address ++ ++ // ------------------------------------------------------ ++ // common configuration to both OPMODE_STA and OPMODE_AP ++ // ------------------------------------------------------ ++ COMMON_CONFIG CommonCfg; ++ MLME_STRUCT Mlme; ++ ++ // AP needs those vaiables for site survey feature. ++ MLME_AUX MlmeAux; // temporary settings used during MLME state machine ++ BSS_TABLE ScanTab; // store the latest SCAN result ++ ++ //About MacTab, the sta driver will use #0 and #1 for multicast and AP. ++ MAC_TABLE MacTab; // ASIC on-chip WCID entry table. At TX, ASIC always use key according to this on-chip table. ++ NDIS_SPIN_LOCK MacTabLock; ++ ++#ifdef DOT11_N_SUPPORT ++ BA_TABLE BATable; ++#endif // DOT11_N_SUPPORT // ++ NDIS_SPIN_LOCK BATabLock; ++ RALINK_TIMER_STRUCT RECBATimer; ++ ++ // encryption/decryption KEY tables ++ CIPHER_KEY SharedKey[MAX_MBSSID_NUM][4]; // STA always use SharedKey[BSS0][0..3] ++ ++ // RX re-assembly buffer for fragmentation ++ FRAGMENT_FRAME FragFrame; // Frame storage for fragment frame ++ ++ // various Counters ++ COUNTER_802_3 Counters8023; // 802.3 counters ++ COUNTER_802_11 WlanCounters; // 802.11 MIB counters ++ COUNTER_RALINK RalinkCounters; // Ralink propriety counters ++ COUNTER_DRS DrsCounters; // counters for Dynamic TX Rate Switching ++ PRIVATE_STRUC PrivateInfo; // Private information & counters ++ ++ // flags, see fRTMP_ADAPTER_xxx flags ++ ULONG Flags; // Represent current device status ++ ++ // current TX sequence # ++ USHORT Sequence; ++ ++#ifdef UNDER_CE ++ NDIS_HANDLE hGiISR; ++#endif ++ ++ ++ // Control disconnect / connect event generation ++ //+++Didn't used anymore ++ ULONG LinkDownTime; ++ //--- ++ ULONG LastRxRate; ++ ULONG LastTxRate; ++ //+++Used only for Station ++ BOOLEAN bConfigChanged; // Config Change flag for the same SSID setting ++ //--- ++ ++ ULONG ExtraInfo; // Extra information for displaying status ++ ULONG SystemErrorBitmap; // b0: E2PROM version error ++ ++ //+++Didn't used anymore ++ ULONG MacIcVersion; // MAC/BBP serial interface issue solved after ver.D ++ //--- ++ ++ // --------------------------- ++ // System event log ++ // --------------------------- ++ RT_802_11_EVENT_TABLE EventTab; ++ ++ ++ BOOLEAN HTCEnable; ++ ++ /*****************************************************************************************/ ++ /* Statistic related parameters */ ++ /*****************************************************************************************/ ++ ++ BOOLEAN bUpdateBcnCntDone; ++ ULONG watchDogMacDeadlock; // prevent MAC/BBP into deadlock condition ++ // ---------------------------- ++ // DEBUG paramerts ++ // ---------------------------- ++ BOOLEAN bBanAllBaSetup; ++ BOOLEAN bPromiscuous; ++ ++ // ---------------------------- ++ // rt2860c emulation-use Parameters ++ // ---------------------------- ++ ULONG rtsaccu[30]; ++ ULONG ctsaccu[30]; ++ ULONG cfendaccu[30]; ++ ULONG bacontent[16]; ++ ULONG rxint[RX_RING_SIZE+1]; ++ UCHAR rcvba[60]; ++ BOOLEAN bLinkAdapt; ++ BOOLEAN bForcePrintTX; ++ BOOLEAN bForcePrintRX; ++ BOOLEAN bDisablescanning; //defined in RT2870 USB ++ BOOLEAN bStaFifoTest; ++ BOOLEAN bProtectionTest; ++ BOOLEAN bHCCATest; ++ BOOLEAN bGenOneHCCA; ++ BOOLEAN bBroadComHT; ++ //+++Following add from RT2870 USB. ++ ULONG BulkOutReq; ++ ULONG BulkOutComplete; ++ ULONG BulkOutCompleteOther; ++ ULONG BulkOutCompleteCancel; // seems not use now? ++ ULONG BulkInReq; ++ ULONG BulkInComplete; ++ ULONG BulkInCompleteFail; ++ //--- ++ ++ struct wificonf WIFItestbed; ++ ++#ifdef RALINK_ATE ++ ATE_INFO ate; ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++ struct reordering_mpdu_pool mpdu_blk_pool; ++#endif // DOT11_N_SUPPORT // ++ ++ ULONG OneSecondnonBEpackets; // record non BE packets per second ++ ++#if WIRELESS_EXT >= 12 ++ struct iw_statistics iw_stats; ++#endif ++ ++ struct net_device_stats stats; ++ ++#ifdef BLOCK_NET_IF ++ BLOCK_QUEUE_ENTRY blockQueueTab[NUM_OF_TX_RING]; ++#endif // BLOCK_NET_IF // ++ ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++ INT32 MC_RowID; ++ UCHAR MC_FileName[256]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ULONG TbttTickCount; ++#ifdef PCI_MSI_SUPPORT ++ BOOLEAN HaveMsi; ++#endif // PCI_MSI_SUPPORT // ++ ++ ++ UCHAR is_on; ++ ++#define TIME_BASE (1000000/OS_HZ) ++#define TIME_ONE_SECOND (1000000/TIME_BASE) ++ UCHAR flg_be_adjust; ++ ULONG be_adjust_last_time; ++ ++#ifdef NINTENDO_AP ++ NINDO_CTRL_BLOCK nindo_ctrl_block; ++#endif // NINTENDO_AP // ++ ++ ++#ifdef IKANOS_VX_1X0 ++ struct IKANOS_TX_INFO IkanosTxInfo; ++ struct IKANOS_TX_INFO IkanosRxInfo[MAX_MBSSID_NUM + MAX_WDS_ENTRY + MAX_APCLI_NUM + MAX_MESH_NUM]; ++#endif // IKANOS_VX_1X0 // ++ ++ ++#ifdef DBG_DIAGNOSE ++ RtmpDiagStruct DiagStruct; ++#endif // DBG_DIAGNOSE // ++ ++ ++ UINT8 PM_FlgSuspend; ++} RTMP_ADAPTER, *PRTMP_ADAPTER; ++ ++// ++// Cisco IAPP format ++// ++typedef struct _CISCO_IAPP_CONTENT_ ++{ ++ USHORT Length; //IAPP Length ++ UCHAR MessageType; //IAPP type ++ UCHAR FunctionCode; //IAPP function type ++ UCHAR DestinaionMAC[MAC_ADDR_LEN]; ++ UCHAR SourceMAC[MAC_ADDR_LEN]; ++ USHORT Tag; //Tag(element IE) - Adjacent AP report ++ USHORT TagLength; //Length of element not including 4 byte header ++ UCHAR OUI[4]; //0x00, 0x40, 0x96, 0x00 ++ UCHAR PreviousAP[MAC_ADDR_LEN]; //MAC Address of access point ++ USHORT Channel; ++ USHORT SsidLen; ++ UCHAR Ssid[MAX_LEN_OF_SSID]; ++ USHORT Seconds; //Seconds that the client has been disassociated. ++} CISCO_IAPP_CONTENT, *PCISCO_IAPP_CONTENT; ++ ++#define DELAYINTMASK 0x0003fffb ++#define INTMASK 0x0003fffb ++#define IndMask 0x0003fffc ++#define RxINT 0x00000005 // Delayed Rx or indivi rx ++#define TxDataInt 0x000000fa // Delayed Tx or indivi tx ++#define TxMgmtInt 0x00000102 // Delayed Tx or indivi tx ++#define TxCoherent 0x00020000 // tx coherent ++#define RxCoherent 0x00010000 // rx coherent ++#define McuCommand 0x00000200 // mcu ++#define PreTBTTInt 0x00001000 // Pre-TBTT interrupt ++#define TBTTInt 0x00000800 // TBTT interrupt ++#define GPTimeOutInt 0x00008000 // GPtimeout interrupt ++#define AutoWakeupInt 0x00004000 // AutoWakeupInt interrupt ++#define FifoStaFullInt 0x00002000 // fifo statistics full interrupt ++ ++ ++typedef struct _RX_BLK_ ++{ ++ RT28XX_RXD_STRUC RxD; ++ PRXWI_STRUC pRxWI; ++ PHEADER_802_11 pHeader; ++ PNDIS_PACKET pRxPacket; ++ UCHAR *pData; ++ USHORT DataSize; ++ USHORT Flags; ++ UCHAR UserPriority; // for calculate TKIP MIC using ++} RX_BLK; ++ ++ ++#define RX_BLK_SET_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags |= _flag) ++#define RX_BLK_TEST_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags & _flag) ++#define RX_BLK_CLEAR_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags &= ~(_flag)) ++ ++ ++#define fRX_WDS 0x0001 ++#define fRX_AMSDU 0x0002 ++#define fRX_ARALINK 0x0004 ++#define fRX_HTC 0x0008 ++#define fRX_PAD 0x0010 ++#define fRX_AMPDU 0x0020 ++#define fRX_QOS 0x0040 ++#define fRX_INFRA 0x0080 ++#define fRX_EAP 0x0100 ++#define fRX_MESH 0x0200 ++#define fRX_APCLI 0x0400 ++#define fRX_DLS 0x0800 ++#define fRX_WPI 0x1000 ++ ++#define LENGTH_AMSDU_SUBFRAMEHEAD 14 ++#define LENGTH_ARALINK_SUBFRAMEHEAD 14 ++#define LENGTH_ARALINK_HEADER_FIELD 2 ++ ++#define TX_UNKOWN_FRAME 0x00 ++#define TX_MCAST_FRAME 0x01 ++#define TX_LEGACY_FRAME 0x02 ++#define TX_AMPDU_FRAME 0x04 ++#define TX_AMSDU_FRAME 0x08 ++#define TX_RALINK_FRAME 0x10 ++#define TX_FRAG_FRAME 0x20 ++ ++ ++// Currently the sizeof(TX_BLK) is 148 bytes. ++typedef struct _TX_BLK_ ++{ ++ UCHAR QueIdx; ++ UCHAR TxFrameType; // Indicate the Transmission type of the all frames in one batch ++ UCHAR TotalFrameNum; // Total frame number want to send-out in one batch ++ USHORT TotalFragNum; // Total frame fragments required in one batch ++ USHORT TotalFrameLen; // Total length of all frames want to send-out in one batch ++ ++ QUEUE_HEADER TxPacketList; ++ MAC_TABLE_ENTRY *pMacEntry; // NULL: packet with 802.11 RA field is multicast/broadcast address ++ HTTRANSMIT_SETTING *pTransmit; ++ ++ // Following structure used for the characteristics of a specific packet. ++ PNDIS_PACKET pPacket; ++ PUCHAR pSrcBufHeader; // Reference to the head of sk_buff->data ++ PUCHAR pSrcBufData; // Reference to the sk_buff->data, will changed depends on hanlding progresss ++ UINT SrcBufLen; // Length of packet payload which not including Layer 2 header ++ PUCHAR pExtraLlcSnapEncap; // NULL means no extra LLC/SNAP is required ++ UCHAR HeaderBuf[80]; // TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP ++ UCHAR MpduHeaderLen; // 802.11 header length NOT including the padding ++ UCHAR HdrPadLen; // recording Header Padding Length; ++ UCHAR apidx; // The interface associated to this packet ++ UCHAR Wcid; // The MAC entry associated to this packet ++ UCHAR UserPriority; // priority class of packet ++ UCHAR FrameGap; // what kind of IFS this packet use ++ UCHAR MpduReqNum; // number of fragments of this frame ++ UCHAR TxRate; // TODO: Obsoleted? Should change to MCS? ++ UCHAR CipherAlg; // cipher alogrithm ++ PCIPHER_KEY pKey; ++ ++ ++ ++ USHORT Flags; //See following definitions for detail. ++ ++ //YOU SHOULD NOT TOUCH IT! Following parameters are used for hardware-depended layer. ++ ULONG Priv; // Hardware specific value saved in here. ++} TX_BLK, *PTX_BLK; ++ ++ ++#define fTX_bRtsRequired 0x0001 // Indicate if need send RTS frame for protection. Not used in RT2860/RT2870. ++#define fTX_bAckRequired 0x0002 // the packet need ack response ++#define fTX_bPiggyBack 0x0004 // Legacy device use Piggback or not ++#define fTX_bHTRate 0x0008 // allow to use HT rate ++#define fTX_bForceNonQoS 0x0010 // force to transmit frame without WMM-QoS in HT mode ++#define fTX_bAllowFrag 0x0020 // allow to fragment the packet, A-MPDU, A-MSDU, A-Ralink is not allowed to fragment ++#define fTX_bMoreData 0x0040 // there are more data packets in PowerSave Queue ++#define fTX_bWMM 0x0080 // QOS Data ++ ++#define fTX_bClearEAPFrame 0x0100 ++ ++#define TX_BLK_ASSIGN_FLAG(_pTxBlk, _flag, value) \ ++ do { \ ++ if (value) \ ++ (_pTxBlk->Flags |= _flag) \ ++ else \ ++ (_pTxBlk->Flags &= ~(_flag)) \ ++ }while(0) ++ ++#define TX_BLK_SET_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags |= _flag) ++#define TX_BLK_TEST_FLAG(_pTxBlk, _flag) (((_pTxBlk->Flags & _flag) == _flag) ? 1 : 0) ++#define TX_BLK_CLEAR_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags &= ~(_flag)) ++ ++ ++ ++ ++ ++//------------------------------------------------------------------------------------------ ++ ++ ++#ifdef RT2860 ++// ++// Enable & Disable NIC interrupt via writing interrupt mask register ++// Since it use ADAPTER structure, it have to be put after structure definition. ++// ++__inline VOID NICDisableInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RTMP_IO_WRITE32(pAd, INT_MASK_CSR, 0x0); // 0: disable ++ //RTMP_IO_WRITE32(pAd, PBF_INT_ENA, 0x0); // 0x418 is for firmware . SW doesn't handle here. ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); ++} ++ ++__inline VOID NICEnableInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // ++ // Flag "fOP_STATUS_DOZE" On, means ASIC put to sleep, else means ASIC WakeUp ++ // To prevent System hang, we should enalbe the interrupt when ++ // ASIC is already Wake Up. ++ // ++ // RT2661 => when ASIC is sleeping, MAC register cannot be read and written. ++ // RT2860 => when ASIC is sleeping, MAC register can be read and written. ++ //if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ RTMP_IO_WRITE32(pAd, INT_MASK_CSR, pAd->int_enable_reg /*DELAYINTMASK*/); // 1:enable ++ } ++ //else ++ // DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_DOZE !\n")); ++ ++ //RTMP_IO_WRITE32(pAd, PBF_INT_ENA, 0x00000030); // 1 : enable ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); ++} ++#endif // RT2860 // ++ ++#ifdef RT_BIG_ENDIAN ++static inline VOID WriteBackToDescriptor( ++ IN PUCHAR Dest, ++ IN PUCHAR Src, ++ IN BOOLEAN DoEncrypt, ++ IN ULONG DescriptorType) ++{ ++ UINT32 *p1, *p2; ++ ++ p1 = ((UINT32 *)Dest); ++ p2 = ((UINT32 *)Src); ++ ++ *p1 = *p2; ++ *(p1+2) = *(p2+2); ++ *(p1+3) = *(p2+3); ++ *(p1+1) = *(p2+1); // Word 1; this must be written back last ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of Tx/Rx descriptor . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to Tx/Rx descriptor ++ DescriptorType Direction of the frame ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update descriptor ++ ======================================================================== ++*/ ++static inline VOID RTMPWIEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType) ++{ ++ int size; ++ int i; ++ ++ size = ((DescriptorType == TYPE_TXWI) ? TXWI_SIZE : RXWI_SIZE); ++ ++ if(DescriptorType == TYPE_TXWI) ++ { ++ *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 ++ *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData+4))); // Byte 4~7 ++ } ++ else ++ { ++ for(i=0; i < size/4 ; i++) ++ *(((UINT32 *)pData) +i) = SWAP32(*(((UINT32 *)pData)+i)); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of Tx/Rx descriptor . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to Tx/Rx descriptor ++ DescriptorType Direction of the frame ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update descriptor ++ ======================================================================== ++*/ ++#ifdef RT2860 ++static inline VOID RTMPDescriptorEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType) ++{ ++ *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 ++ *((UINT32 *)(pData + 8)) = SWAP32(*((UINT32 *)(pData+8))); // Byte 8~11 ++ *((UINT32 *)(pData +12)) = SWAP32(*((UINT32 *)(pData + 12))); // Byte 12~15 ++ *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData + 4))); // Byte 4~7, this must be swapped last ++} ++#endif // RT2860 // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of all kinds of 802.11 frames . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the 802.11 frame structure ++ Dir Direction of the frame ++ FromRxDoneInt Caller is from RxDone interrupt ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update buffer data ++ ======================================================================== ++*/ ++static inline VOID RTMPFrameEndianChange( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG Dir, ++ IN BOOLEAN FromRxDoneInt) ++{ ++ PHEADER_802_11 pFrame; ++ PUCHAR pMacHdr; ++ ++ // swab 16 bit fields - Frame Control field ++ if(Dir == DIR_READ) ++ { ++ *(USHORT *)pData = SWAP16(*(USHORT *)pData); ++ } ++ ++ pFrame = (PHEADER_802_11) pData; ++ pMacHdr = (PUCHAR) pFrame; ++ ++ // swab 16 bit fields - Duration/ID field ++ *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); ++ ++ // swab 16 bit fields - Sequence Control field ++ *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); ++ ++ if(pFrame->FC.Type == BTYPE_MGMT) ++ { ++ switch(pFrame->FC.SubType) ++ { ++ case SUBTYPE_ASSOC_REQ: ++ case SUBTYPE_REASSOC_REQ: ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Listen Interval field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_ASSOC_RSP: ++ case SUBTYPE_REASSOC_RSP: ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Status Code field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - AID field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_AUTH: ++ // If from APHandleRxDoneInterrupt routine, it is still a encrypt format. ++ // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. ++ if(!FromRxDoneInt && pFrame->FC.Wep == 1) ++ break; ++ else ++ { ++ // swab 16 bit fields - Auth Alg No. field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Auth Seq No. field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Status Code field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ } ++ break; ++ ++ case SUBTYPE_BEACON: ++ case SUBTYPE_PROBE_RSP: ++ // swab 16 bit fields - BeaconInterval field ++ pMacHdr += (sizeof(HEADER_802_11) + TIMESTAMP_LEN); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(USHORT); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_DEAUTH: ++ case SUBTYPE_DISASSOC: ++ // swab 16 bit fields - Reason code field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ } ++ } ++ else if( pFrame->FC.Type == BTYPE_DATA ) ++ { ++ } ++ else if(pFrame->FC.Type == BTYPE_CNTL) ++ { ++ switch(pFrame->FC.SubType) ++ { ++ case SUBTYPE_BLOCK_ACK_REQ: ++ { ++ PFRAME_BA_REQ pBAReq = (PFRAME_BA_REQ)pFrame; ++ *(USHORT *)(&pBAReq->BARControl) = SWAP16(*(USHORT *)(&pBAReq->BARControl)); ++ pBAReq->BAStartingSeq.word = SWAP16(pBAReq->BAStartingSeq.word); ++ } ++ break; ++ case SUBTYPE_BLOCK_ACK: ++ // For Block Ack packet, the HT_CONTROL field is in the same offset with Addr3 ++ *(UINT32 *)(&pFrame->Addr3[0]) = SWAP32(*(UINT32 *)(&pFrame->Addr3[0])); ++ break; ++ ++ case SUBTYPE_ACK: ++ //For ACK packet, the HT_CONTROL field is in the same offset with Addr2 ++ *(UINT32 *)(&pFrame->Addr2[0])= SWAP32(*(UINT32 *)(&pFrame->Addr2[0])); ++ break; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("Invalid Frame Type!!!\n")); ++ } ++ ++ // swab 16 bit fields - Frame Control ++ if(Dir == DIR_WRITE) ++ { ++ *(USHORT *)pData = SWAP16(*(USHORT *)pData); ++ } ++} ++#endif // RT_BIG_ENDIAN // ++ ++ ++static inline VOID ConvertMulticastIP2MAC( ++ IN PUCHAR pIpAddr, ++ IN PUCHAR *ppMacAddr, ++ IN UINT16 ProtoType) ++{ ++ if (pIpAddr == NULL) ++ return; ++ ++ if (ppMacAddr == NULL || *ppMacAddr == NULL) ++ return; ++ ++ switch (ProtoType) ++ { ++ case ETH_P_IPV6: ++// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); ++ *(*ppMacAddr) = 0x33; ++ *(*ppMacAddr + 1) = 0x33; ++ *(*ppMacAddr + 2) = pIpAddr[12]; ++ *(*ppMacAddr + 3) = pIpAddr[13]; ++ *(*ppMacAddr + 4) = pIpAddr[14]; ++ *(*ppMacAddr + 5) = pIpAddr[15]; ++ break; ++ ++ case ETH_P_IP: ++ default: ++// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); ++ *(*ppMacAddr) = 0x01; ++ *(*ppMacAddr + 1) = 0x00; ++ *(*ppMacAddr + 2) = 0x5e; ++ *(*ppMacAddr + 3) = pIpAddr[1] & 0x7f; ++ *(*ppMacAddr + 4) = pIpAddr[2]; ++ *(*ppMacAddr + 5) = pIpAddr[3]; ++ break; ++ } ++ ++ return; ++} ++ ++BOOLEAN RTMPCheckForHang( ++ IN NDIS_HANDLE MiniportAdapterContext ++ ); ++ ++VOID RTMPHalt( ++ IN NDIS_HANDLE MiniportAdapterContext ++ ); ++ ++// ++// Private routines in rtmp_init.c ++// ++NDIS_STATUS RTMPAllocAdapterBlock( ++ IN PVOID handle, ++ OUT PRTMP_ADAPTER *ppAdapter ++ ); ++ ++NDIS_STATUS RTMPAllocTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++NDIS_STATUS RTMPFindAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ); ++ ++NDIS_STATUS RTMPReadParametersHook( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++VOID RTMPFreeAdapter( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++NDIS_STATUS NICReadRegParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ); ++ ++ ++VOID NICReadEEPROMParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mac_addr); ++ ++VOID NICInitAsicFromEEPROM( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICInitTxRxRingAndBacklogQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICInitializeAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset); ++ ++NDIS_STATUS NICInitializeAsic( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset); ++ ++VOID NICIssueReset( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPRingCleanUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType); ++ ++VOID RxTest( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS DbgSendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++VOID UserCfgInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICResetFromError( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICEraseFirmware( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICLoadFirmware( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICLoadRateSwitchingParams( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN NICCheckForHang( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICUpdateFifoStaCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICUpdateRawCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPNotAllZero( ++ IN PVOID pSrc1, ++ IN ULONG Length); ++ ++VOID RTMPZeroMemory( ++ IN PVOID pSrc, ++ IN ULONG Length); ++ ++ULONG RTMPCompareMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length); ++ ++VOID RTMPMoveMemory( ++ OUT PVOID pDest, ++ IN PVOID pSrc, ++ IN ULONG Length); ++ ++VOID AtoH( ++ char *src, ++ UCHAR *dest, ++ int destlen); ++ ++UCHAR BtoH( ++ char ch); ++ ++VOID RTMPPatchMacBbpBug( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPatchCardBus( ++ IN PRTMP_ADAPTER pAdapter); ++ ++VOID RTMPPatchRalinkCardBus( ++ IN PRTMP_ADAPTER pAdapter, ++ IN ULONG Bus); ++ ++ULONG RTMPReadCBConfig( ++ IN ULONG Bus, ++ IN ULONG Slot, ++ IN ULONG Func, ++ IN ULONG Offset); ++ ++VOID RTMPWriteCBConfig( ++ IN ULONG Bus, ++ IN ULONG Slot, ++ IN ULONG Func, ++ IN ULONG Offset, ++ IN ULONG Value); ++ ++VOID RTMPInitTimer( ++ IN PRTMP_ADAPTER pAd, ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN PVOID pTimerFunc, ++ IN PVOID pData, ++ IN BOOLEAN Repeat); ++ ++VOID RTMPSetTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value); ++ ++ ++VOID RTMPModTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value); ++ ++VOID RTMPCancelTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ OUT BOOLEAN *pCancelled); ++ ++VOID RTMPSetLED( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Status); ++ ++VOID RTMPSetSignalLED( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_802_11_RSSI Dbm); ++ ++VOID RTMPEnableRxTx( ++ IN PRTMP_ADAPTER pAd); ++ ++// ++// prototype in action.c ++// ++VOID ActionStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeADDBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDELBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeInvalidAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerAddBAReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAddBARspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDelBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // DOT11_N_SUPPORT // ++ ++VOID SendPSMPAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Psmp); ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID SendBSS2040CoexistMgmtAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx, ++ IN UCHAR InfoReq); ++ ++VOID SendNotifyBWActionFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx); ++ ++BOOLEAN ChannelSwitchSanityCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary); ++ ++VOID ChannelSwitchAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Channel, ++ IN UCHAR Secondary); ++ ++ULONG BuildIntolerantChannelRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest); ++ ++VOID Update2040CoexistFrameAndNotify( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha); ++ ++VOID Send2040CoexistAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha); ++#endif // DOT11N_DRAFT3 // ++ ++VOID PeerRMAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID StaPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Bss2040Coexist); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++VOID PeerBSSTranAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerHTAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // DOT11_N_SUPPORT // ++ ++VOID PeerQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef QOS_DLS_SUPPORT ++VOID PeerDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++VOID DlsParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, ++ IN PRT_802_11_DLS pDls, ++ IN USHORT reason); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID RECBATimerTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID ORIBATimerTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID SendRefreshBAR( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++#endif // DOT11_N_SUPPORT // ++ ++VOID ActHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN PUCHAR Addr1, ++ IN PUCHAR Addr2, ++ IN PUCHAR Addr3); ++ ++VOID BarHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PFRAME_BAR pCntlBar, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA); ++ ++VOID InsertActField( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 Category, ++ IN UINT8 ActCode); ++ ++BOOLEAN QosBADataParse( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bAMSDU, ++ IN PUCHAR p8023Header, ++ IN UCHAR WCID, ++ IN UCHAR TID, ++ IN USHORT Sequence, ++ IN UCHAR DataOffset, ++ IN USHORT Datasize, ++ IN UINT CurRxIndex); ++ ++#ifdef DOT11_N_SUPPORT ++BOOLEAN CntlEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG MsgLen, ++ IN PFRAME_BA_REQ pMsg); ++ ++VOID BaAutoManSwitch( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++ ++VOID HTIOTCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BatRecIdx); ++ ++// ++// Private routines in rtmp_data.c ++// ++BOOLEAN RTMPHandleRxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleTxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd, ++ IN INT_SOURCE_CSR_STRUC TxRingBitmap); ++ ++VOID RTMPHandleMgmtRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandlePreTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++void RTMPHandleTwakeupInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleRxCoherentInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN TxFrameIsAggregatible( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pPrevAddr1, ++ IN PUCHAR p8023hdr); ++ ++BOOLEAN PeerIsAggreOn( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG TxRate, ++ IN PMAC_TABLE_ENTRY pMacEntry); ++ ++NDIS_STATUS Sniff2BytesFromNdisBuffer( ++ IN PNDIS_BUFFER pFirstBuffer, ++ IN UCHAR DesiredOffset, ++ OUT PUCHAR pByte0, ++ OUT PUCHAR pByte1); ++ ++NDIS_STATUS STASendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++VOID STASendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets); ++ ++VOID RTMPDeQueuePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bIntContext, ++ IN UCHAR QueIdx, ++ IN UCHAR Max_Tx_Packets); ++ ++NDIS_STATUS RTMPHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR QueIdx, ++ OUT PULONG pFreeTXDLeft); ++ ++NDIS_STATUS STAHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++VOID STARxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++NDIS_STATUS RTMPFreeTXDRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType, ++ IN UCHAR NumberRequired, ++ IN PUCHAR FreeNumberIs); ++ ++NDIS_STATUS MlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++NDIS_STATUS MlmeHardTransmitMgmtRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++NDIS_STATUS MlmeHardTransmitTxRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++USHORT RTMPCalcDuration( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Rate, ++ IN ULONG Size); ++ ++VOID RTMPWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit); ++ ++ ++VOID RTMPWriteTxWI_Data( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk); ++ ++ ++VOID RTMPWriteTxWI_Cache( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk); ++ ++VOID RTMPWriteTxDescriptor( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXD_STRUC pTxD, ++ IN BOOLEAN bWIV, ++ IN UCHAR QSEL); ++ ++VOID RTMPSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS MiniportMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length); ++ ++VOID RTMPSendNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull); ++ ++VOID RTMPSendDisassociationFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSendRTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN unsigned int NextMpduSize, ++ IN UCHAR TxRate, ++ IN UCHAR RTSRate, ++ IN USHORT AckDuration, ++ IN UCHAR QueIdx, ++ IN UCHAR FrameGap); ++ ++ ++NDIS_STATUS RTMPApplyPacketFilter( ++ IN PRTMP_ADAPTER pAd, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN PHEADER_802_11 pHeader); ++ ++PQUEUE_HEADER RTMPCheckTxSwQueue( ++ IN PRTMP_ADAPTER pAd, ++ OUT UCHAR *QueIdx); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPReportMicError( ++ IN PRTMP_ADAPTER pAd, ++ IN PCIPHER_KEY pWpaKey); ++ ++VOID WpaMicFailureReportFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaDisassocApAndBlockAssoc( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // CONFIG_STA_SUPPORT // ++ ++NDIS_STATUS RTMPCloneNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN pInsAMSDUHdr, ++ IN PNDIS_PACKET pInPacket, ++ OUT PNDIS_PACKET *ppOutPacket); ++ ++NDIS_STATUS RTMPAllocateNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET *pPacket, ++ IN PUCHAR pHeader, ++ IN UINT HeaderLen, ++ IN PUCHAR pData, ++ IN UINT DataLen); ++ ++VOID RTMPFreeNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++BOOLEAN RTMPFreeTXDUponTxDmaDone( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx); ++ ++BOOLEAN RTMPCheckDHCPFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++BOOLEAN RTMPCheckEtherType( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++VOID RTMPCckBbpTuning( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT TxRate); ++ ++// ++// Private routines in rtmp_wep.c ++// ++VOID RTMPInitWepEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN UCHAR KeyLen, ++ IN PUCHAR pDest); ++ ++VOID RTMPEncryptData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDest, ++ IN UINT Len); ++ ++BOOLEAN RTMPDecryptData( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR pSrc, ++ IN UINT Len, ++ IN UINT idx); ++ ++BOOLEAN RTMPSoftDecryptWEP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pGroupKey); ++ ++VOID RTMPSetICV( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest); ++ ++VOID ARCFOUR_INIT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pKey, ++ IN UINT KeyLen); ++ ++UCHAR ARCFOUR_BYTE( ++ IN PARCFOURCONTEXT Ctx); ++ ++VOID ARCFOUR_DECRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++VOID ARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++VOID WPAARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++UINT RTMP_CALC_FCS32( ++ IN UINT Fcs, ++ IN PUCHAR Cp, ++ IN INT Len); ++ ++// ++// MLME routines ++// ++ ++// Asic/RF/BBP related functions ++ ++VOID AsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicUpdateProtect( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT OperaionMode, ++ IN UCHAR SetMask, ++ IN BOOLEAN bDisableBGProtect, ++ IN BOOLEAN bNonGFExist); ++ ++VOID AsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN BOOLEAN bScan); ++ ++VOID AsicLockChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ; ++ ++VOID AsicAntennaSelect( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++VOID AsicAntennaSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN ABGBAND_STATE BandState); ++ ++VOID AsicRfTuningExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID AsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp); ++ ++VOID AsicForceSleep( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx); ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID AsicSetBssid( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid); ++ ++VOID AsicSetMcastWC( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDelWcidTab( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid); ++ ++VOID AsicEnableRDG( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDisableRDG( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDisableSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicEnableBssSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicEnableIbssSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicSetEdcaParm( ++ IN PRTMP_ADAPTER pAd, ++ IN PEDCA_PARM pEdcaParm); ++ ++VOID AsicSetSlotTime( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUseShortSlotTime); ++ ++VOID AsicAddSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic); ++ ++VOID AsicRemoveSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx); ++ ++VOID AsicUpdateWCIDAttribute( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bUsePairewiseKeyTable); ++ ++VOID AsicUpdateWCIDIVEIV( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN ULONG uIV, ++ IN ULONG uEIV); ++ ++VOID AsicUpdateRxWCIDTable( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN PUCHAR pAddr); ++ ++VOID AsicAddKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN PCIPHER_KEY pCipherKey, ++ IN BOOLEAN bUsePairewiseKeyTable, ++ IN BOOLEAN bTxKey); ++ ++VOID AsicAddPairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR WCID, ++ IN CIPHER_KEY *pCipherKey); ++ ++VOID AsicRemovePairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR Wcid); ++ ++BOOLEAN AsicSendCommandToMcu( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command, ++ IN UCHAR Token, ++ IN UCHAR Arg0, ++ IN UCHAR Arg1); ++ ++#ifdef RT2860 ++BOOLEAN AsicCheckCommanOk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command); ++#endif // RT2860 // ++ ++VOID MacAddrRandomBssid( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pAddr); ++ ++VOID MgtMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid); ++ ++VOID MlmeRadioOff( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeRadioOn( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++VOID BssTableInit( ++ IN BSS_TABLE *Tab); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInit( ++ IN PRTMP_ADAPTER pAd, ++ IN BA_TABLE *Tab); ++#endif // DOT11_N_SUPPORT // ++ ++ULONG BssTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel); ++ ++ULONG BssSsidTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel); ++ ++ULONG BssTableSearchWithSSID( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR Bssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel); ++ ++VOID BssTableDeleteEntry( ++ IN OUT PBSS_TABLE pTab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableDeleteORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_ORI_ENTRY *pBAORIEntry); ++ ++VOID BATableDeleteRECEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_REC_ENTRY *pBARECEntry); ++ ++VOID BATableTearORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR TID, ++ IN UCHAR Wcid, ++ IN BOOLEAN bForceDelete, ++ IN BOOLEAN ALL); ++ ++VOID BATableTearRECEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR TID, ++ IN UCHAR WCID, ++ IN BOOLEAN ALL); ++#endif // DOT11_N_SUPPORT // ++ ++VOID BssEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT PBSS_ENTRY pBss, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN PCF_PARM CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++ULONG BssTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT PBSS_TABLE pTab, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN CF_PARM *CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Aid, ++ IN USHORT TimeOutValue, ++ IN USHORT StartingSeq, ++ IN UCHAR TID, ++ IN UCHAR BAWinSize, ++ IN UCHAR OriginatorStatus, ++ IN BOOLEAN IsRecipient); ++ ++#ifdef DOT11N_DRAFT3 ++VOID Bss2040CoexistTimeOut( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++VOID TriEventInit( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG TriEventTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT TRIGGER_EVENT_TAB *Tab, ++ IN PUCHAR pBssid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR RegClass, ++ IN UCHAR ChannelNo); ++ ++VOID TriEventCounterMaintenance( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++VOID BssTableSsidSort( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *OutTab, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen); ++ ++VOID BssTableSortByRssi( ++ IN OUT BSS_TABLE *OutTab); ++ ++VOID BssCipherParse( ++ IN OUT PBSS_ENTRY pBss); ++ ++NDIS_STATUS MlmeQueueInit( ++ IN MLME_QUEUE *Queue); ++ ++VOID MlmeQueueDestroy( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MlmeEnqueue( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Machine, ++ IN ULONG MsgType, ++ IN ULONG MsgLen, ++ IN VOID *Msg); ++ ++BOOLEAN MlmeEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG TimeStampHigh, ++ IN ULONG TimeStampLow, ++ IN UCHAR Rssi0, ++ IN UCHAR Rssi1, ++ IN UCHAR Rssi2, ++ IN ULONG MsgLen, ++ IN PVOID Msg, ++ IN UCHAR Signal); ++ ++ ++BOOLEAN MlmeDequeue( ++ IN MLME_QUEUE *Queue, ++ OUT MLME_QUEUE_ELEM **Elem); ++ ++VOID MlmeRestartStateMachine( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeQueueEmpty( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MlmeQueueFull( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType); ++ ++VOID StateMachineInit( ++ IN STATE_MACHINE *Sm, ++ IN STATE_MACHINE_FUNC Trans[], ++ IN ULONG StNr, ++ IN ULONG MsgNr, ++ IN STATE_MACHINE_FUNC DefFunc, ++ IN ULONG InitState, ++ IN ULONG Base); ++ ++VOID StateMachineSetAction( ++ IN STATE_MACHINE *S, ++ IN ULONG St, ++ ULONG Msg, ++ IN STATE_MACHINE_FUNC F); ++ ++VOID StateMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Drop( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID ReassocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID AssocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID DisassocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++//---------------------------------------------- ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAssocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerReassocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDisassocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID DisassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AssocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ReassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Cls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID SwitchBetweenWepAndCkip( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID InvalidStateWhenAssoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenReassoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenDisassociate( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++ ++VOID ComposePsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ComposeNullFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AssocPostProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr2, ++ IN USHORT CapabilityInfo, ++ IN USHORT Aid, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN PEDCA_PARM pEdcaParm, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID AuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID AuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID MlmeAuthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthRspAtSeq2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthRspAtSeq4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AuthTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Cls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID MlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenAuth( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++//============================================= ++ ++VOID AuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]); ++ ++VOID PeerDeauthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT Reason, ++ IN USHORT Status); ++ ++// ++// Private routines in dls.c ++// ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++void DlsStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID RTMPCheckDLSTimeOut( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPRcvFrameDLSCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN ULONG Len, ++ IN PRT28XX_RXD_STRUC pRxD); ++ ++INT RTMPCheckDLSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++NDIS_STATUS RTMPSendSTAKeyRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++NDIS_STATUS RTMPSendSTAKeyHandShake( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++VOID DlsTimeoutAction( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN MlmeDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PRT_802_11_DLS *pDLS, ++ OUT PUSHORT pReason); ++ ++INT Set_DlsEntryInfo_Display_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++MAC_TABLE_ENTRY *MacTableInsertDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UINT DlsEntryIdx); ++ ++BOOLEAN MacTableDeleteDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr); ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount); ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR wcid, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount); ++ ++INT Set_DlsAddEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_DlsTearDownEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN PeerDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pDlsTimeout, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDlsRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDlsTearDownSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pReason); ++#endif // QOS_DLS_SUPPORT // ++ ++//======================================== ++ ++VOID SyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID BeaconTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID ScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenJoin( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenStart( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID EnqueueProbeRequest( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN ScanRunning( ++ IN PRTMP_ADAPTER pAd); ++//========================================= ++ ++VOID MlmeCntlInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeCntlMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlIdleProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlOidScanProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlOidSsidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlOidRTBssidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlMlmeRoamingProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlWaitDisassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitJoinProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitReassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitStartProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAuthProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAuthProc2( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAssocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef QOS_DLS_SUPPORT ++VOID CntlOidDLSSetupProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // QOS_DLS_SUPPORT // ++ ++VOID LinkUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssType); ++ ++VOID LinkDown( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN IsReqFromAP); ++ ++VOID IterateOnBssTab( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID IterateOnBssTab2( ++ IN PRTMP_ADAPTER pAd);; ++ ++VOID JoinParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, ++ IN ULONG BssIdx); ++ ++VOID AssocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, ++ IN PUCHAR pAddr, ++ IN USHORT CapabilityInfo, ++ IN ULONG Timeout, ++ IN USHORT ListenIntv); ++ ++VOID ScanParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN UCHAR ScanType); ++ ++VOID DisassocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, ++ IN PUCHAR pAddr, ++ IN USHORT Reason); ++ ++VOID StartParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_START_REQ_STRUCT *StartReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen); ++ ++VOID AuthParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, ++ IN PUCHAR pAddr, ++ IN USHORT Alg); ++ ++VOID EnqueuePsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EnqueueBeaconFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeJoinReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeStartReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID BeaconTimeoutAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeaconAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ScanNextChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG MakeIbssBeacon( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID CCXAdjacentAPReport( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeScanReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *BssType, ++ OUT CHAR ssid[], ++ OUT UCHAR *SsidLen, ++ OUT UCHAR *ScanType); ++ ++BOOLEAN PeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgChannel, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pBssType, ++ OUT USHORT *pBeaconPeriod, ++ OUT UCHAR *pChannel, ++ OUT UCHAR *pNewChannel, ++ OUT LARGE_INTEGER *pTimestamp, ++ OUT CF_PARM *pCfParm, ++ OUT USHORT *pAtimWin, ++ OUT USHORT *pCapabilityInfo, ++ OUT UCHAR *pErp, ++ OUT UCHAR *pDtimCount, ++ OUT UCHAR *pDtimPeriod, ++ OUT UCHAR *pBcastFlag, ++ OUT UCHAR *pMessageToMe, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT UCHAR *pCkipFlag, ++ OUT UCHAR *pAironetCellPowerLimit, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT PQBSS_LOAD_PARM pQbssLoad, ++ OUT PQOS_CAPABILITY_PARM pQosCapability, ++ OUT ULONG *pRalinkIe, ++ OUT UCHAR *pHtCapabilityLen, ++#ifdef CONFIG_STA_SUPPORT ++ OUT UCHAR *pPreNHtCapabilityLen, ++#endif // CONFIG_STA_SUPPORT // ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT UCHAR *AddHtInfoLen, ++ OUT ADD_HT_INFO_IE *AddHtInfo, ++ OUT UCHAR *NewExtChannel, ++ OUT USHORT *LengthVIE, ++ OUT PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++BOOLEAN PeerAddBAReqActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2); ++ ++BOOLEAN PeerAddBARspActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen); ++ ++BOOLEAN PeerDelBAActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN VOID *pMsg, ++ IN ULONG MsgLen); ++ ++BOOLEAN MlmeAssocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pApAddr, ++ OUT USHORT *CapabilityInfo, ++ OUT ULONG *Timeout, ++ OUT USHORT *ListenIntv); ++ ++BOOLEAN MlmeAuthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT ULONG *Timeout, ++ OUT USHORT *Alg); ++ ++BOOLEAN MlmeStartReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT CHAR Ssid[], ++ OUT UCHAR *Ssidlen); ++ ++BOOLEAN PeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT USHORT *Alg, ++ OUT USHORT *Seq, ++ OUT USHORT *Status, ++ OUT CHAR ChlgText[]); ++ ++BOOLEAN PeerAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT USHORT *pAid, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ OUT UCHAR *pHtCapabilityLen, ++ OUT UCHAR *pAddHtInfoLen, ++ OUT UCHAR *pNewExtChannelOffset, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT UCHAR *pCkipFlag); ++ ++BOOLEAN PeerDisassocSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerWpaMessageSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN PEAPOL_PACKET pMsg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgType, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN PeerDeauthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen); ++ ++BOOLEAN GetTimBit( ++ IN CHAR *Ptr, ++ IN USHORT Aid, ++ OUT UCHAR *TimLen, ++ OUT UCHAR *BcastFlag, ++ OUT UCHAR *DtimCount, ++ OUT UCHAR *DtimPeriod, ++ OUT UCHAR *MessageToMe); ++ ++UCHAR ChannelSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel); ++ ++NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( ++ IN PBSS_ENTRY pBss); ++ ++BOOLEAN MlmeDelBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen); ++ ++BOOLEAN MlmeAddBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2); ++ ++ULONG MakeOutgoingFrame( ++ OUT CHAR *Buffer, ++ OUT ULONG *Length, ...); ++ ++VOID LfsrInit( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Seed); ++ ++UCHAR RandomByte( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicUpdateAutoFallBackTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pTxRate); ++ ++VOID MlmePeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LinkDownExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LinkUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID STAMlmePeriodicExec( ++ PRTMP_ADAPTER pAd); ++ ++VOID MlmeAutoScan( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeAutoReconnectLastSSID( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeValidateSSID( ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen); ++ ++VOID MlmeCheckForRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32); ++ ++VOID MlmeCheckForFastRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now); ++ ++VOID MlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate); ++ ++VOID MlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx); ++ ++VOID MlmeCalculateChannelQuality( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now); ++ ++VOID MlmeCheckPsmChange( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32); ++ ++VOID MlmeSetPsmBit( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm); ++ ++VOID MlmeSetTxPreamble( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TxPreamble); ++ ++VOID UpdateBasicRateBitmap( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeUpdateTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bLinkUp, ++ IN UCHAR apidx); ++ ++#ifdef DOT11_N_SUPPORT ++VOID MlmeUpdateHtTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx); ++#endif // DOT11_N_SUPPORT // ++ ++VOID RTMPCheckRates( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT UCHAR SupRate[], ++ IN OUT UCHAR *SupRateLen); ++ ++#ifdef CONFIG_STA_SUPPORT ++BOOLEAN RTMPCheckChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR CentralChannel, ++ IN UCHAR Channel); ++#endif // CONFIG_STA_SUPPORT // ++ ++BOOLEAN RTMPCheckHt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN OUT HT_CAPABILITY_IE *pHtCapability, ++ IN OUT ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID StaQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID AsicBbpTuning1( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicBbpTuning2( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPUpdateMlmeRate( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR RTMPMaxRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi0, ++ IN CHAR Rssi1, ++ IN CHAR Rssi2); ++ ++VOID AsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicRxAntEvalTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID APSDPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++ ++UCHAR RTMPStaFixedTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++ ++VOID RTMPUpdateLegacyTxSetting( ++ UCHAR fixed_tx_mode, ++ PMAC_TABLE_ENTRY pEntry); ++ ++BOOLEAN RTMPAutoRateSwitchCheck( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS MlmeInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeHandler( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeHalt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeResetRalinkCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BuildChannelList( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR FirstChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR NextChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel); ++ ++VOID ChangeToCellPowerLimit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AironetCellPowerLimit); ++ ++VOID RaiseClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x); ++ ++VOID LowerClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x); ++ ++USHORT ShiftInBits( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ShiftOutBits( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT data, ++ IN USHORT count); ++ ++VOID EEpromCleanup( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EWDS( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EWEN( ++ IN PRTMP_ADAPTER pAd); ++ ++USHORT RTMP_EEPROM_READ16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset); ++ ++VOID RTMP_EEPROM_WRITE16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Data); ++ ++// ++// Prototypes of function definition in rtmp_tkip.c ++// ++VOID RTMPInitTkipEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pTKey, ++ IN UCHAR KeyId, ++ IN PUCHAR pTA, ++ IN PUCHAR pMICKey, ++ IN PUCHAR pTSC, ++ OUT PULONG pIV16, ++ OUT PULONG pIV32); ++ ++VOID RTMPInitMICEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN UCHAR UserPriority, ++ IN PUCHAR pMICKey); ++ ++BOOLEAN RTMPTkipCompareMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UCHAR UserPriority, ++ IN UINT Len); ++ ++VOID RTMPCalculateMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pEncap, ++ IN PCIPHER_KEY pKey, ++ IN UCHAR apidx); ++ ++BOOLEAN RTMPTkipCompareMICValueWithLLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pLLC, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UINT Len); ++ ++VOID RTMPTkipAppendByte( ++ IN PTKIP_KEY_INFO pTkip, ++ IN UCHAR uChar); ++ ++VOID RTMPTkipAppend( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pSrc, ++ IN UINT nBytes); ++ ++VOID RTMPTkipGetMIC( ++ IN PTKIP_KEY_INFO pTkip); ++ ++BOOLEAN RTMPSoftDecryptTKIP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN UCHAR UserPriority, ++ IN PCIPHER_KEY pWpaKey); ++ ++BOOLEAN RTMPSoftDecryptAES( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pWpaKey); ++ ++// ++// Prototypes of function definition in cmm_info.c ++// ++NDIS_STATUS RTMPWPARemoveKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++VOID RTMPWPARemoveAllKeys( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPCheckStrPrintAble( ++ IN CHAR *pInPutStr, ++ IN UCHAR strLen); ++ ++VOID RTMPSetPhyMode( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG phymode); ++ ++VOID RTMPUpdateHTIE( ++ IN RT_HT_CAPABILITY *pRtHt, ++ IN UCHAR *pMcsSet, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID RTMPAddWcidAttributeEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++CHAR *GetEncryptType( ++ CHAR enc); ++ ++CHAR *GetAuthMode( ++ CHAR auth); ++ ++VOID RTMPIoctlGetSiteSurvey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlGetMacTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIndicateWPA2Status( ++ IN PRTMP_ADAPTER pAdapter); ++ ++VOID RTMPOPModeSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPAddBSSIDCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Aid, ++ IN PNDIS_802_11_KEY pKey, ++ IN UCHAR CipherAlg); ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID RTMPSetHT( ++ IN PRTMP_ADAPTER pAd, ++ IN OID_SET_HT_PHYMODE *pHTPhyMode); ++ ++VOID RTMPSetIndividualHT( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx); ++#endif // DOT11_N_SUPPORT // ++ ++VOID RTMPSendWirelessEvent( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Event_flag, ++ IN PUCHAR pAddr, ++ IN UCHAR BssIdx, ++ IN CHAR Rssi); ++ ++VOID NICUpdateCntlCounters( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN UCHAR SubType, ++ IN PRXWI_STRUC pRxWI); ++// ++// prototype in wpa.c ++// ++BOOLEAN WpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType); ++ ++VOID WpaPskStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID WpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaPairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaPairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaGroupMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr1); ++ ++VOID Wpa2PairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Wpa2PairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++BOOLEAN ParseKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR bPairewise); ++ ++VOID RTMPToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN is4wayFrame); ++ ++VOID HMAC_SHA1( ++ IN UCHAR *text, ++ IN UINT text_len, ++ IN UCHAR *key, ++ IN UINT key_len, ++ IN UCHAR *digest); ++ ++VOID PRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *prefix, ++ IN INT prefix_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len); ++ ++VOID CCKMPRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len); ++ ++VOID WpaCountPTK( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *PMK, ++ IN UCHAR *ANonce, ++ IN UCHAR *AA, ++ IN UCHAR *SNonce, ++ IN UCHAR *SA, ++ OUT UCHAR *output, ++ IN UINT len); ++ ++VOID GenRandom( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *macAddr, ++ OUT UCHAR *random); ++ ++// ++// prototype in aironet.c ++// ++VOID AironetStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID AironetMsgAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AironetRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ChannelLoadRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID NoiseHistRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID BeaconRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ChannelLoadReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID NoiseHistReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetFinalReportAction( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BeaconReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetAddBeaconReport( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Index, ++ IN PMLME_QUEUE_ELEM pElem); ++ ++VOID AironetCreateBeaconReportFromBssTable( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID DBGPRINT_TX_RING( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx); ++ ++VOID DBGPRINT_RX_RING( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR ConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber); ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID BuildEffectedChannelList( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11N_DRAFT3 // ++ ++ ++VOID APAsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++VOID APAsicRxAntEvalTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++// ++// function prototype in cmm_wpa.c ++// ++BOOLEAN RTMPCheckWPAframe( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR pData, ++ IN ULONG DataByteCount, ++ IN UCHAR FromWhichBSSID); ++ ++VOID AES_GTK_KEY_UNWRAP( ++ IN UCHAR *key, ++ OUT UCHAR *plaintext, ++ IN UCHAR c_len, ++ IN UCHAR *ciphertext); ++ ++BOOLEAN RTMPCheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ IN MAC_TABLE_ENTRY *pEntry, ++ OUT UCHAR *Offset); ++ ++BOOLEAN RTMPParseEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR GroupKeyIndex, ++ IN UCHAR MsgType, ++ IN BOOLEAN bWPA2, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID ConstructEapolMsg( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerAuthMode, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR MyGroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN UCHAR *ReplayCounter, ++ IN UCHAR *KeyNonce, ++ IN UCHAR *TxRSC, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_Len, ++ OUT PEAPOL_PACKET pMsg); ++ ++VOID CalculateMIC( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR *PTK, ++ OUT PEAPOL_PACKET pMsg); ++ ++NDIS_STATUS RTMPSoftDecryptBroadCastData( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, ++ IN PCIPHER_KEY pShard_key); ++ ++VOID ConstructEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerAuthMode, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN BOOLEAN bWPA2Capable, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_LEN, ++ OUT PEAPOL_PACKET pMsg); ++ ++VOID RTMPMakeRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT AuthMode, ++ IN UINT WepStatus, ++ IN UCHAR apidx); ++ ++// ++// function prototype in ap_wpa.c ++// ++ ++BOOLEAN APWpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType) ; ++ ++MAC_TABLE_ENTRY *PACInquiry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid); ++ ++BOOLEAN RTMPCheckMcast( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN RTMPCheckUcast( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN RTMPCheckAUTH( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID WPAStart4WayHS( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN ULONG TimeInterval); ++ ++VOID WPAStart2WayGroupHS( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID APWpaEAPPacketAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLStartAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLLogoffAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLASFAlertAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HandleCounterMeasure( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID PeerPairMsg2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerPairMsg4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CMTimerExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID WPARetryExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID EnqueueStartForPSKExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID RTMPHandleSTAKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerGroupMsg2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN VOID *Msg, ++ IN UINT MsgLen); ++ ++VOID PairDisAssocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN USHORT Reason); ++ ++VOID MlmeDeAuthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN USHORT Reason); ++ ++VOID GREKEYPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID CountGTK( ++ IN UCHAR *PMK, ++ IN UCHAR *GNonce, ++ IN UCHAR *AA, ++ OUT UCHAR *output, ++ IN UINT len); ++ ++VOID GetSmall( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ OUT PUCHAR out, ++ IN ULONG Length); ++ ++VOID GetLarge( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ OUT PUCHAR out, ++ IN ULONG Length); ++ ++VOID APGenRandom( ++ IN PRTMP_ADAPTER pAd, ++ OUT UCHAR *random); ++ ++VOID AES_GTK_KEY_WRAP( ++ IN UCHAR *key, ++ IN UCHAR *plaintext, ++ IN UCHAR p_len, ++ OUT UCHAR *ciphertext); ++ ++VOID WpaSend( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR pPacket, ++ IN ULONG Len); ++ ++VOID APToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN bClearFrame); ++ ++VOID RTMPAddPMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN PUCHAR pAddr, ++ IN UCHAR *PMKID, ++ IN UCHAR *PMK); ++ ++INT RTMPSearchPMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN PUCHAR pAddr); ++ ++VOID RTMPDeletePMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN INT idx); ++ ++VOID RTMPMaintainPMKIDCache( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSendTriggerFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuffer, ++ IN ULONG Length, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull); ++ ++ ++/* timeout -- ms */ ++VOID RTMP_SetPeriodicTimer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++VOID RTMP_OS_Init_Timer( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN TIMER_FUNCTION function, ++ IN PVOID data); ++ ++VOID RTMP_OS_Add_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++VOID RTMP_OS_Mod_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++ ++VOID RTMP_OS_Del_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ OUT BOOLEAN *pCancelled); ++ ++ ++VOID RTMP_OS_Release_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_ENTRY pEntry); ++ ++VOID RTMPusecDelay( ++ IN ULONG usec); ++ ++NDIS_STATUS os_alloc_mem( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR *mem, ++ IN ULONG size); ++ ++NDIS_STATUS os_free_mem( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mem); ++ ++ ++void RTMP_AllocateSharedMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++VOID RTMPFreeTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS AdapterBlockAllocateMemory( ++ IN PVOID handle, ++ OUT PVOID *ppAd); ++ ++void RTMP_AllocateTxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateFirstTxBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateMgmtDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateRxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++PNDIS_PACKET RTMP_AllocateRxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++PNDIS_PACKET RTMP_AllocateTxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress); ++ ++PNDIS_PACKET RTMP_AllocateFragPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length); ++ ++void RTMP_QueryPacketInfo( ++ IN PNDIS_PACKET pPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen); ++ ++void RTMP_QueryNextPacketInfo( ++ IN PNDIS_PACKET *ppPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen); ++ ++ ++BOOLEAN RTMP_FillTxBlkInfo( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk); ++ ++ ++PRTMP_SCATTER_GATHER_LIST ++rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg); ++ ++ ++ void announce_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++UINT BA_Reorder_AMSDU_Annnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++UINT Handle_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++void convert_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR p8023hdr, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNET_DEV get_netdev_from_bssid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET duplicate_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pOldPkt); ++ ++PNDIS_PACKET duplicate_pkt_with_VLAN( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++PNDIS_PACKET duplicate_pkt_with_WPI( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UINT32 ext_head_len, ++ IN UINT32 ext_tail_len); ++ ++UCHAR VLAN_8023_Header_Copy( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ OUT PUCHAR pData, ++ IN UCHAR FromWhichBSSID); ++ ++#ifdef DOT11_N_SUPPORT ++void ba_flush_reordering_timeout_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN ULONG Now32); ++ ++ ++VOID BAOriSessionSetUp( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN UCHAR TID, ++ IN USHORT TimeOut, ++ IN ULONG DelayTime, ++ IN BOOLEAN isForced); ++ ++VOID BASessionTearDownALL( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid); ++#endif // DOT11_N_SUPPORT // ++ ++BOOLEAN OS_Need_Clone_Packet(void); ++ ++ ++VOID build_tx_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pFrame, ++ IN ULONG FrameLen); ++ ++ ++VOID BAOriSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive, ++ IN BOOLEAN bForceSend); ++ ++VOID BARecSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive); ++ ++BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); ++void ba_reordering_resource_release(PRTMP_ADAPTER pAd); ++ ++ULONG AutoChBssInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR ChannelNo, ++ IN CHAR Rssi); ++ ++void AutoChBssTableInit( ++ IN PRTMP_ADAPTER pAd); ++ ++void ChannelInfoInit( ++ IN PRTMP_ADAPTER pAd); ++ ++void AutoChBssTableDestroy( ++ IN PRTMP_ADAPTER pAd); ++ ++void ChannelInfoDestroy( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR New_ApAutoSelectChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN rtstrmactohex( ++ IN char *s1, ++ IN char *s2); ++ ++BOOLEAN rtstrcasecmp( ++ IN char *s1, ++ IN char *s2); ++ ++char *rtstrstruncasecmp( ++ IN char *s1, ++ IN char *s2); ++ ++char *rtstrstr( ++ IN const char * s1, ++ IN const char * s2); ++ ++char *rstrtok( ++ IN char * s, ++ IN const char * ct); ++ ++int rtinet_aton( ++ const char *cp, ++ unsigned int *addr); ++ ++////////// common ioctl functions ////////// ++INT Set_DriverVersion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ShortSlot_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef AGGREGATION_SUPPORT ++INT Set_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef DBG ++INT Set_Debug_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Show_DescInfo_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ResetStatCounter_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_BASetup_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BADecline_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BAOriTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BARecTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtStbc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtHtc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtLinkAdapt_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtProtect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMimoPs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_ForceShortGI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ForceGF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT SetCommonHT( ++ IN PRTMP_ADAPTER pAd); ++ ++INT Set_SendPSMPAction_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMIMOPSmode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_HtTxBASize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++//Dls , kathy ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++#ifdef DOT11_N_SUPPORT ++//Block ACK ++VOID QueryBATABLE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PQUERYBA_TABLE pBAT); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT WpaCheckEapCode( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFrame, ++ IN USHORT FrameLen, ++ IN USHORT OffSet); ++ ++VOID WpaSendMicFailureToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUnicast); ++ ++VOID SendAssocIEsToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++int wext_notify_event_assoc( ++ IN RTMP_ADAPTER *pAd); ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++#ifdef DOT11_N_SUPPORT ++VOID Handle_BSS_Width_Trigger_Events( ++ IN PRTMP_ADAPTER pAd); ++ ++void build_ext_channel_switch_ie( ++ IN PRTMP_ADAPTER pAd, ++ IN HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE *pIE); ++#endif // DOT11_N_SUPPORT // ++ ++ ++BOOLEAN APRxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN STARxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN argc); ++ ++#ifdef DOT11_N_SUPPORT ++// AMPDU packet indication ++VOID Indicate_AMPDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++// AMSDU packet indication ++VOID Indicate_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++#endif // DOT11_N_SUPPORT // ++ ++// Normal legacy Rx packet indication ++VOID Indicate_Legacy_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Indicate_EAPOL_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++void update_os_packet_info( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++void wlan_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN PUCHAR pHeader802_3, ++ IN UCHAR FromWhichBSSID); ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++// remove LLC and get 802_3 Header ++#define RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(_pRxBlk, _pHeader802_3) \ ++{ \ ++ PUCHAR _pRemovedLLCSNAP = NULL, _pDA, _pSA; \ ++ \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_MESH)) \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr3; \ ++ _pSA = (PUCHAR)_pRxBlk->pHeader + sizeof(HEADER_802_11); \ ++ } \ ++ else \ ++ { \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_INFRA)) \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr1; \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_DLS)) \ ++ _pSA = _pRxBlk->pHeader->Addr2; \ ++ else \ ++ _pSA = _pRxBlk->pHeader->Addr3; \ ++ } \ ++ else \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr1; \ ++ _pSA = _pRxBlk->pHeader->Addr2; \ ++ } \ ++ } \ ++ \ ++ CONVERT_TO_802_3(_pHeader802_3, _pDA, _pSA, _pRxBlk->pData, \ ++ _pRxBlk->DataSize, _pRemovedLLCSNAP); \ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++BOOLEAN APFowardWirelessStaToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN ULONG FromWhichBSSID); ++ ++VOID Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Sta_Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define ANNOUNCE_OR_FORWARD_802_3_PACKET(_pAd, _pPacket, _FromWhichBSS)\ ++ Sta_Announce_or_Forward_802_3_Packet(_pAd, _pPacket, _FromWhichBSS); ++ //announce_802_3_packet(_pAd, _pPacket); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++PNDIS_PACKET DuplicatePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET ClonePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++ ++// Normal, AMPDU or AMSDU ++VOID CmmRxnonRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID CmmRxRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Update_Rssi_Sample( ++ IN PRTMP_ADAPTER pAd, ++ IN RSSI_SAMPLE *pRssi, ++ IN PRXWI_STRUC pRxWI); ++ ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending); ++ ++PNDIS_PACKET RTMPDeFragmentDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk); ++ ++//////////////////////////////////////// ++ ++ ++ ++ ++ ++#ifdef SNMP_SUPPORT ++//for snmp , kathy ++typedef struct _DefaultKeyIdxValue ++{ ++ UCHAR KeyIdx; ++ UCHAR Value[16]; ++} DefaultKeyIdxValue, *PDefaultKeyIdxValue; ++#endif ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++enum { ++ DIDmsg_lnxind_wlansniffrm = 0x00000044, ++ DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, ++ DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, ++ DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, ++ DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, ++ DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, ++ DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, ++ DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, ++ DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, ++ DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, ++ DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 ++}; ++enum { ++ P80211ENUM_msgitem_status_no_value = 0x00 ++}; ++enum { ++ P80211ENUM_truth_false = 0x00, ++ P80211ENUM_truth_true = 0x01 ++}; ++ ++/* Definition from madwifi */ ++typedef struct { ++ UINT32 did; ++ UINT16 status; ++ UINT16 len; ++ UINT32 data; ++} p80211item_uint32_t; ++ ++typedef struct { ++ UINT32 msgcode; ++ UINT32 msglen; ++#define WLAN_DEVNAMELEN_MAX 16 ++ UINT8 devname[WLAN_DEVNAMELEN_MAX]; ++ p80211item_uint32_t hosttime; ++ p80211item_uint32_t mactime; ++ p80211item_uint32_t channel; ++ p80211item_uint32_t rssi; ++ p80211item_uint32_t sq; ++ p80211item_uint32_t signal; ++ p80211item_uint32_t noise; ++ p80211item_uint32_t rate; ++ p80211item_uint32_t istx; ++ p80211item_uint32_t frmlen; ++} wlan_ng_prism2_header; ++ ++/* The radio capture header precedes the 802.11 header. */ ++typedef struct PACKED _ieee80211_radiotap_header { ++ UINT8 it_version; /* Version 0. Only increases ++ * for drastic changes, ++ * introduction of compatible ++ * new fields does not count. ++ */ ++ UINT8 it_pad; ++ UINT16 it_len; /* length of the whole ++ * header in bytes, including ++ * it_version, it_pad, ++ * it_len, and data fields. ++ */ ++ UINT32 it_present; /* A bitmap telling which ++ * fields are present. Set bit 31 ++ * (0x80000000) to extend the ++ * bitmap by another 32 bits. ++ * Additional extensions are made ++ * by setting bit 31. ++ */ ++}ieee80211_radiotap_header ; ++ ++enum ieee80211_radiotap_type { ++ IEEE80211_RADIOTAP_TSFT = 0, ++ IEEE80211_RADIOTAP_FLAGS = 1, ++ IEEE80211_RADIOTAP_RATE = 2, ++ IEEE80211_RADIOTAP_CHANNEL = 3, ++ IEEE80211_RADIOTAP_FHSS = 4, ++ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, ++ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, ++ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, ++ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, ++ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, ++ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, ++ IEEE80211_RADIOTAP_ANTENNA = 11, ++ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, ++ IEEE80211_RADIOTAP_DB_ANTNOISE = 13 ++}; ++ ++#define WLAN_RADIOTAP_PRESENT ( \ ++ (1 << IEEE80211_RADIOTAP_TSFT) | \ ++ (1 << IEEE80211_RADIOTAP_FLAGS) | \ ++ (1 << IEEE80211_RADIOTAP_RATE) | \ ++ 0) ++ ++typedef struct _wlan_radiotap_header { ++ ieee80211_radiotap_header wt_ihdr; ++ INT64 wt_tsft; ++ UINT8 wt_flags; ++ UINT8 wt_rate; ++} wlan_radiotap_header; ++/* Definition from madwifi */ ++ ++void send_monitor_packets( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk); ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev); ++#endif ++ ++VOID RTMPSetDesiredRates( ++ IN PRTMP_ADAPTER pAdapter, ++ IN LONG Rates); ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Set_FixedTxMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++INT Set_OpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++static inline char* GetPhyMode( ++ int Mode) ++{ ++ switch(Mode) ++ { ++ case MODE_CCK: ++ return "CCK"; ++ ++ case MODE_OFDM: ++ return "OFDM"; ++#ifdef DOT11_N_SUPPORT ++ case MODE_HTMIX: ++ return "HTMIX"; ++ ++ case MODE_HTGREENFIELD: ++ return "GREEN"; ++#endif // DOT11_N_SUPPORT // ++ default: ++ return "N/A"; ++ } ++} ++ ++ ++static inline char* GetBW( ++ int BW) ++{ ++ switch(BW) ++ { ++ case BW_10: ++ return "10M"; ++ ++ case BW_20: ++ return "20M"; ++#ifdef DOT11_N_SUPPORT ++ case BW_40: ++ return "40M"; ++#endif // DOT11_N_SUPPORT // ++ default: ++ return "N/A"; ++ } ++} ++ ++ ++VOID RT28xxThreadTerminate( ++ IN RTMP_ADAPTER *pAd); ++ ++BOOLEAN RT28XXChipsetCheck( ++ IN void *_dev_p); ++ ++BOOLEAN RT28XXNetDevInit( ++ IN void *_dev_p, ++ IN struct net_device *net_dev, ++ IN RTMP_ADAPTER *pAd); ++ ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 argc); ++ ++VOID RT28XXDMADisable( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT28XXDMAEnable( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT28xx_UpdateBeaconToAsic( ++ IN RTMP_ADAPTER * pAd, ++ IN INT apidx, ++ IN ULONG BeaconLen, ++ IN ULONG UpdatePos); ++ ++INT rt28xx_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd); ++#endif // CONFIG_STA_SUPPORT // ++ ++BOOLEAN RT28XXSecurityKeyAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG apidx, ++ IN ULONG KeyIdx, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++//////////////////////////////////////// ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending); ++ ++ ++void kill_thread_task(PRTMP_ADAPTER pAd); ++ ++void tbtt_tasklet(unsigned long data); ++ ++#ifdef RT2860 ++// ++// Function Prototype in cmm_data_2860.c ++// ++USHORT RtmpPCI_WriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpPCI_WriteSingleTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpPCI_WriteMultiTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR frameNum, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpPCI_WriteFragTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR fragNum, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpPCI_WriteSubTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++VOID RtmpPCI_FinalWriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN USHORT totalMPDUSize, ++ IN USHORT FirstTxIdx); ++ ++VOID RtmpPCIDataLastTxIdx( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN USHORT LastTxIdx); ++ ++VOID RtmpPCIDataKickOut( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++ ++int RtmpPCIMgmtKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pSrcBufVA, ++ IN UINT SrcBufLen); ++ ++ ++NDIS_STATUS RTMPCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxD); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPInitPCIeLinkCtrlValue( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPFindHostPCIDev( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPCIeLinkCtrlValueRestore( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Level); ++ ++VOID RTMPPCIeLinkCtrlSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Max); ++ ++VOID RT28xxPciAsicRadioOff( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Level, ++ IN USHORT TbttNumToNextWakeUp); ++ ++BOOLEAN RT28xxPciAsicRadioOn( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Level); ++ ++VOID RT28xxPciStaAsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx); ++ ++VOID RT28xxPciStaAsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp); ++ ++VOID PsPollWakeExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID RadioOnExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RT28xxPciMlmeRadioOn( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RT28xxPciMlmeRadioOFF( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT2860 // ++ ++VOID AsicTurnOffRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++VOID AsicTurnOnRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++ ++//////////////////////////////////////// ++ ++VOID QBSS_LoadInit( ++ IN RTMP_ADAPTER *pAd); ++ ++UINT32 QBSS_LoadElementAppend( ++ IN RTMP_ADAPTER *pAd, ++ OUT UINT8 *buf_p); ++ ++VOID QBSS_LoadUpdate( ++ IN RTMP_ADAPTER *pAd); ++ ++/////////////////////////////////////// ++INT RTMPShowCfgValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pName, ++ IN PUCHAR pBuf); ++ ++PCHAR RTMPGetRalinkAuthModeStr( ++ IN NDIS_802_11_AUTHENTICATION_MODE authMode); ++ ++PCHAR RTMPGetRalinkEncryModeStr( ++ IN USHORT encryMode); ++////////////////////////////////////// ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID AsicStaBbpTuning( ++ IN PRTMP_ADAPTER pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++void RTMP_IndicateMediaState( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ReSyncBeaconTime( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSetAGCInitValue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BandWidth); ++ ++int rt28xx_close(IN PNET_DEV dev); ++int rt28xx_open(IN PNET_DEV dev); ++ ++__inline INT VIRTUAL_IF_UP(PRTMP_ADAPTER pAd) ++{ ++extern VOID MeshMakeBeacon(IN PRTMP_ADAPTER pAd, IN UCHAR idx); ++extern VOID MeshUpdateBeaconFrame(IN PRTMP_ADAPTER pAd, IN UCHAR idx); ++ ++ if (VIRTUAL_IF_NUM(pAd) == 0) ++ { ++ if (rt28xx_open(pAd->net_dev) != 0) ++ return -1; ++ } ++ else ++ { ++ } ++ VIRTUAL_IF_INC(pAd); ++ return 0; ++} ++ ++__inline VOID VIRTUAL_IF_DOWN(PRTMP_ADAPTER pAd) ++{ ++ VIRTUAL_IF_DEC(pAd); ++ if (VIRTUAL_IF_NUM(pAd) == 0) ++ rt28xx_close(pAd->net_dev); ++ return; ++} ++ ++ ++#endif // __RTMP_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rtmp_type.h +@@ -0,0 +1,94 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_type.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 1-2-2004 ++*/ ++#ifndef __RTMP_TYPE_H__ ++#define __RTMP_TYPE_H__ ++ ++#define PACKED __attribute__ ((packed)) ++ ++// Put platform dependent declaration here ++// For example, linux type definition ++typedef unsigned char UINT8; ++typedef unsigned short UINT16; ++typedef unsigned int UINT32; ++typedef unsigned long long UINT64; ++typedef int INT32; ++typedef long long INT64; ++ ++typedef unsigned char * PUINT8; ++typedef unsigned short * PUINT16; ++typedef unsigned int * PUINT32; ++typedef unsigned long long * PUINT64; ++typedef int * PINT32; ++typedef long long * PINT64; ++ ++typedef signed char CHAR; ++typedef signed short SHORT; ++typedef signed int INT; ++typedef signed long LONG; ++typedef signed long long LONGLONG; ++ ++ ++typedef unsigned char UCHAR; ++typedef unsigned short USHORT; ++typedef unsigned int UINT; ++typedef unsigned long ULONG; ++typedef unsigned long long ULONGLONG; ++ ++typedef unsigned char BOOLEAN; ++typedef void VOID; ++ ++typedef VOID * PVOID; ++typedef CHAR * PCHAR; ++typedef UCHAR * PUCHAR; ++typedef USHORT * PUSHORT; ++typedef LONG * PLONG; ++typedef ULONG * PULONG; ++typedef UINT * PUINT; ++ ++typedef unsigned int NDIS_MEDIA_STATE; ++ ++typedef union _LARGE_INTEGER { ++ struct { ++ UINT LowPart; ++ INT32 HighPart; ++ } u; ++ INT64 QuadPart; ++} LARGE_INTEGER; ++ ++#endif // __RTMP_TYPE_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/rt_profile.c +@@ -0,0 +1,1976 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++#ifdef DOT11_N_SUPPORT ++static void HTParametersHook( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR *pValueStr, ++ IN CHAR *pInput); ++#endif // DOT11_N_SUPPORT // ++ ++#define ETH_MAC_ADDR_STR_LEN 17 // in format of xx:xx:xx:xx:xx:xx ++ ++// We assume the s1 is a sting, s2 is a memory space with 6 bytes. and content of s1 will be changed. ++BOOLEAN rtstrmactohex(char *s1, char *s2) ++{ ++ int i = 0; ++ char *ptokS = s1, *ptokE = s1; ++ ++ if (strlen(s1) != ETH_MAC_ADDR_STR_LEN) ++ return FALSE; ++ ++ while((*ptokS) != '\0') ++ { ++ if((ptokE = strchr(ptokS, ':')) != NULL) ++ *ptokE++ = '\0'; ++ if ((strlen(ptokS) != 2) || (!isxdigit(*ptokS)) || (!isxdigit(*(ptokS+1)))) ++ break; // fail ++ AtoH(ptokS, &s2[i++], 1); ++ ptokS = ptokE; ++ if (i == 6) ++ break; // parsing finished ++ } ++ ++ return ( i == 6 ? TRUE : FALSE); ++ ++} ++ ++ ++// we assume the s1 and s2 both are strings. ++BOOLEAN rtstrcasecmp(char *s1, char *s2) ++{ ++ char *p1 = s1, *p2 = s2; ++ ++ if (strlen(s1) != strlen(s2)) ++ return FALSE; ++ ++ while(*p1 != '\0') ++ { ++ if((*p1 != *p2) && ((*p1 ^ *p2) != 0x20)) ++ return FALSE; ++ p1++; ++ p2++; ++ } ++ ++ return TRUE; ++} ++ ++// we assume the s1 (buffer) and s2 (key) both are strings. ++char * rtstrstruncasecmp(char * s1, char * s2) ++{ ++ INT l1, l2, i; ++ char temp1, temp2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *) s1; ++ ++ l1 = strlen(s1); ++ ++ while (l1 >= l2) ++ { ++ l1--; ++ ++ for(i=0; i= l2) ++ { ++ l1--; ++ if (!memcmp(s1,s2,l2)) ++ return (char *) s1; ++ s1++; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * rstrtok - Split a string into tokens ++ * @s: The string to be searched ++ * @ct: The characters to search for ++ * * WARNING: strtok is deprecated, use strsep instead. However strsep is not compatible with old architecture. ++ */ ++char * __rstrtok; ++char * rstrtok(char * s,const char * ct) ++{ ++ char *sbegin, *send; ++ ++ sbegin = s ? s : __rstrtok; ++ if (!sbegin) ++ { ++ return NULL; ++ } ++ ++ sbegin += strspn(sbegin,ct); ++ if (*sbegin == '\0') ++ { ++ __rstrtok = NULL; ++ return( NULL ); ++ } ++ ++ send = strpbrk( sbegin, ct); ++ if (send && *send != '\0') ++ *send++ = '\0'; ++ ++ __rstrtok = send; ++ ++ return (sbegin); ++} ++ ++/** ++ * delimitcnt - return the count of a given delimiter in a given string. ++ * @s: The string to be searched. ++ * @ct: The delimiter to search for. ++ * Notice : We suppose the delimiter is a single-char string(for example : ";"). ++ */ ++INT delimitcnt(char * s,const char * ct) ++{ ++ INT count = 0; ++ /* point to the beginning of the line */ ++ const char *token = s; ++ ++ for ( ;; ) ++ { ++ token = strpbrk(token, ct); /* search for delimiters */ ++ ++ if ( token == NULL ) ++ { ++ /* advanced to the terminating null character */ ++ break; ++ } ++ /* skip the delimiter */ ++ ++token; ++ ++ /* ++ * Print the found text: use len with %.*s to specify field width. ++ */ ++ ++ /* accumulate delimiter count */ ++ ++count; ++ } ++ return count; ++} ++ ++/* ++ * converts the Internet host address from the standard numbers-and-dots notation ++ * into binary data. ++ * returns nonzero if the address is valid, zero if not. ++ */ ++int rtinet_aton(const char *cp, unsigned int *addr) ++{ ++ unsigned int val; ++ int base, n; ++ char c; ++ unsigned int parts[4]; ++ unsigned int *pp = parts; ++ ++ for (;;) ++ { ++ /* ++ * Collect number up to ``.''. ++ * Values are specified as for C: ++ * 0x=hex, 0=octal, other=decimal. ++ */ ++ val = 0; ++ base = 10; ++ if (*cp == '0') ++ { ++ if (*++cp == 'x' || *cp == 'X') ++ base = 16, cp++; ++ else ++ base = 8; ++ } ++ while ((c = *cp) != '\0') ++ { ++ if (isdigit((unsigned char) c)) ++ { ++ val = (val * base) + (c - '0'); ++ cp++; ++ continue; ++ } ++ if (base == 16 && isxdigit((unsigned char) c)) ++ { ++ val = (val << 4) + ++ (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); ++ cp++; ++ continue; ++ } ++ break; ++ } ++ if (*cp == '.') ++ { ++ /* ++ * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) ++ * a.b (with b treated as 24 bits) ++ */ ++ if (pp >= parts + 3 || val > 0xff) ++ return 0; ++ *pp++ = val, cp++; ++ } ++ else ++ break; ++ } ++ ++ /* ++ * Check for trailing junk. ++ */ ++ while (*cp) ++ if (!isspace((unsigned char) *cp++)) ++ return 0; ++ ++ /* ++ * Concoct the address according to the number of parts specified. ++ */ ++ n = pp - parts + 1; ++ switch (n) ++ { ++ ++ case 1: /* a -- 32 bits */ ++ break; ++ ++ case 2: /* a.b -- 8.24 bits */ ++ if (val > 0xffffff) ++ return 0; ++ val |= parts[0] << 24; ++ break; ++ ++ case 3: /* a.b.c -- 8.8.16 bits */ ++ if (val > 0xffff) ++ return 0; ++ val |= (parts[0] << 24) | (parts[1] << 16); ++ break; ++ ++ case 4: /* a.b.c.d -- 8.8.8.8 bits */ ++ if (val > 0xff) ++ return 0; ++ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); ++ break; ++ } ++ ++ *addr = htonl(val); ++ return 1; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Find key section for Get key parameter. ++ ++ Arguments: ++ buffer Pointer to the buffer to start find the key section ++ section the key of the secion to be find ++ ++ Return Value: ++ NULL Fail ++ Others Success ++ ======================================================================== ++*/ ++PUCHAR RTMPFindSection( ++ IN PCHAR buffer) ++{ ++ CHAR temp_buf[32]; ++ PUCHAR ptr; ++ ++ strcpy(temp_buf, "Default"); ++ ++ if((ptr = rtstrstr(buffer, temp_buf)) != NULL) ++ return (ptr+strlen("\n")); ++ else ++ return NULL; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get key parameter. ++ ++ Arguments: ++ key Pointer to key string ++ dest Pointer to destination ++ destsize The datasize of the destination ++ buffer Pointer to the buffer to start find the key ++ ++ Return Value: ++ TRUE Success ++ FALSE Fail ++ ++ Note: ++ This routine get the value with the matched key (case case-sensitive) ++ ======================================================================== ++*/ ++INT RTMPGetKeyParameter( ++ IN PCHAR key, ++ OUT PCHAR dest, ++ IN INT destsize, ++ IN PCHAR buffer) ++{ ++ UCHAR *temp_buf1 = NULL; ++ UCHAR *temp_buf2 = NULL; ++ CHAR *start_ptr; ++ CHAR *end_ptr; ++ CHAR *ptr; ++ CHAR *offset = 0; ++ INT len; ++ ++ //temp_buf1 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ os_alloc_mem(NULL, &temp_buf1, MAX_PARAM_BUFFER_SIZE); ++ ++ if(temp_buf1 == NULL) ++ return (FALSE); ++ ++ //temp_buf2 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ os_alloc_mem(NULL, &temp_buf2, MAX_PARAM_BUFFER_SIZE); ++ if(temp_buf2 == NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ return (FALSE); ++ } ++ ++ //find section ++ if((offset = RTMPFindSection(buffer)) == NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ os_free_mem(NULL, temp_buf2); ++ return (FALSE); ++ } ++ ++ strcpy(temp_buf1, "\n"); ++ strcat(temp_buf1, key); ++ strcat(temp_buf1, "="); ++ ++ //search key ++ if((start_ptr=rtstrstr(offset, temp_buf1))==NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ os_free_mem(NULL, temp_buf2); ++ return (FALSE); ++ } ++ ++ start_ptr+=strlen("\n"); ++ if((end_ptr=rtstrstr(start_ptr, "\n"))==NULL) ++ end_ptr=start_ptr+strlen(start_ptr); ++ ++ if (end_ptrSharedKey[i][idx].KeyLen = KeyLen / 2; ++ AtoH(keybuff, pAd->SharedKey[i][idx].Key, KeyLen / 2); ++ if (KeyLen == 10) ++ CipherAlg = CIPHER_WEP64; ++ else ++ CipherAlg = CIPHER_WEP128; ++ pAd->SharedKey[i][idx].CipherAlg = CipherAlg; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("I/F(ra%d) Key%dStr=%s and type=%s\n", i, idx+1, keybuff, (KeyType == 0) ? "Hex":"Ascii")); ++ return 1; ++ } ++ else ++ {//Invalid key length ++ DBGPRINT(RT_DEBUG_ERROR, ("I/F(ra%d) Key%dStr is Invalid key length! KeyLen = %ld!\n", i, idx+1, KeyLen)); ++ return 0; ++ } ++ } ++} ++static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) ++{ ++ char tok_str[16]; ++ PUCHAR macptr; ++ INT i = 0, idx; ++ ULONG KeyType[MAX_MBSSID_NUM]; ++ ULONG KeyIdx; ++ ++ NdisZeroMemory(KeyType, MAX_MBSSID_NUM); ++ ++ //DefaultKeyID ++ if(RTMPGetKeyParameter("DefaultKeyID", tmpbuf, 25, buffer)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ KeyIdx = simple_strtol(tmpbuf, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1); ++ else ++ pAd->StaCfg.DefaultKeyId = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyID(0~3)=%d\n", pAd->StaCfg.DefaultKeyId)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ for (idx = 0; idx < 4; idx++) ++ { ++ sprintf(tok_str, "Key%dType", idx + 1); ++ //Key1Type ++ if (RTMPGetKeyParameter(tok_str, tmpbuf, 128, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ KeyType[i] = simple_strtol(macptr, 0, 10); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ sprintf(tok_str, "Key%dStr", idx + 1); ++ if (RTMPGetCriticalParameter(tok_str, tmpbuf, 128, buffer)) ++ { ++ rtmp_parse_key_buffer_from_file(pAd, tmpbuf, KeyType[BSS0], BSS0, idx); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ } ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) ++{ ++ PUCHAR macptr; ++ INT i=0; ++ BOOLEAN bWmmEnable = FALSE; ++ ++ //WmmCapable ++ if(RTMPGetKeyParameter("WmmCapable", tmpbuf, 32, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ { ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ bWmmEnable = TRUE; ++ } ++ else //Disable ++ { ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WmmCapable=%d\n", pAd->CommonCfg.bWmmCapable)); ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ //DLSCapable ++ if(RTMPGetKeyParameter("DLSCapable", tmpbuf, 32, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ { ++ pAd->CommonCfg.bDLSCapable = TRUE; ++ } ++ else //Disable ++ { ++ pAd->CommonCfg.bDLSCapable = FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("bDLSCapable=%d\n", pAd->CommonCfg.bDLSCapable)); ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ //AckPolicy for AC_BK, AC_BE, AC_VI, AC_VO ++ if(RTMPGetKeyParameter("AckPolicy", tmpbuf, 32, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ pAd->CommonCfg.AckPolicy[i] = (UCHAR)simple_strtol(macptr, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AckPolicy[%d]=%d\n", i, pAd->CommonCfg.AckPolicy[i])); ++ } ++ } ++ ++ if (bWmmEnable) ++ { ++ //APSDCapable ++ if(RTMPGetKeyParameter("APSDCapable", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bAPSDCapable = TRUE; ++ else ++ pAd->CommonCfg.bAPSDCapable = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("APSDCapable=%d\n", pAd->CommonCfg.bAPSDCapable)); ++ } ++ ++ //APSDAC for AC_BE, AC_BK, AC_VI, AC_VO ++ if(RTMPGetKeyParameter("APSDAC", tmpbuf, 32, buffer)) ++ { ++ BOOLEAN apsd_ac[4]; ++ ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ apsd_ac[i] = (BOOLEAN)simple_strtol(macptr, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("APSDAC%d %d\n", i, apsd_ac[i])); ++ } ++ ++ pAd->CommonCfg.bAPSDAC_BE = apsd_ac[0]; ++ pAd->CommonCfg.bAPSDAC_BK = apsd_ac[1]; ++ pAd->CommonCfg.bAPSDAC_VI = apsd_ac[2]; ++ pAd->CommonCfg.bAPSDAC_VO = apsd_ac[3]; ++ } ++ } ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++NDIS_STATUS RTMPReadParametersHook( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PUCHAR src = NULL; ++ struct file *srcf; ++ INT retval, orgfsuid, orgfsgid; ++ mm_segment_t orgfs; ++ CHAR *buffer; ++ CHAR *tmpbuf; ++ ULONG RtsThresh; ++ ULONG FragThresh; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR keyMaterial[40]; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ PUCHAR macptr; ++ INT i = 0; ++ ++ buffer = kmalloc(MAX_INI_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ if(buffer == NULL) ++ return NDIS_STATUS_FAILURE; ++ ++ tmpbuf = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ if(tmpbuf == NULL) ++ { ++ kfree(buffer); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ src = STA_PROFILE_PATH; ++#endif // CONFIG_STA_SUPPORT // ++#ifdef MULTIPLE_CARD_SUPPORT ++ src = pAd->MC_FileName; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ // Save uid and gid used for filesystem access. ++ // Set user and group to 0 (root) ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid=current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ if (src && *src) ++ { ++ srcf = filp_open(src, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); ++ } ++ else ++ { ++ // The object must have a read method ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); ++ retval=srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); ++ if (retval < 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Read %s error %d\n", src, -retval)); ++ } ++ else ++ { ++ // set file parameter to portcfg ++ //CountryRegion ++ if(RTMPGetKeyParameter("CountryRegion", tmpbuf, 25, buffer)) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryRegion=%d\n", pAd->CommonCfg.CountryRegion)); ++ } ++ //CountryRegionABand ++ if(RTMPGetKeyParameter("CountryRegionABand", tmpbuf, 25, buffer)) ++ { ++ pAd->CommonCfg.CountryRegionForABand= (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryRegionABand=%d\n", pAd->CommonCfg.CountryRegionForABand)); ++ } ++ //CountryCode ++ if(RTMPGetKeyParameter("CountryCode", tmpbuf, 25, buffer)) ++ { ++ NdisMoveMemory(pAd->CommonCfg.CountryCode, tmpbuf , 2); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(pAd->StaCfg.StaOriCountryCode, tmpbuf , 2); ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ if (strlen(pAd->CommonCfg.CountryCode) != 0) ++ { ++ pAd->CommonCfg.bCountryFlag = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryCode=%s\n", pAd->CommonCfg.CountryCode)); ++ } ++ //ChannelGeography ++ if(RTMPGetKeyParameter("ChannelGeography", tmpbuf, 25, buffer)) ++ { ++ UCHAR Geography = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ if (Geography <= BOTH) ++ { ++ pAd->CommonCfg.Geography = Geography; ++ pAd->CommonCfg.CountryCode[2] = ++ (pAd->CommonCfg.Geography == BOTH) ? ' ' : ((pAd->CommonCfg.Geography == IDOR) ? 'I' : 'O'); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.StaOriGeography = pAd->CommonCfg.Geography; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelGeography=%d\n", pAd->CommonCfg.Geography)); ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.Geography = BOTH; ++ pAd->CommonCfg.CountryCode[2] = ' '; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //SSID ++ if (RTMPGetCriticalParameter("SSID", tmpbuf, 256, buffer)) ++ { ++ if (strlen(tmpbuf) <= 32) ++ { ++ pAd->CommonCfg.SsidLen = (UCHAR) strlen(tmpbuf); ++ NdisZeroMemory(pAd->CommonCfg.Ssid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->CommonCfg.Ssid, tmpbuf, pAd->CommonCfg.SsidLen); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->CommonCfg.SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, tmpbuf, pAd->MlmeAux.AutoReconnectSsidLen); ++ pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //NetworkType ++ if (RTMPGetKeyParameter("NetworkType", tmpbuf, 25, buffer)) ++ { ++ pAd->bConfigChanged = TRUE; ++ if (strcmp(tmpbuf, "Adhoc") == 0) ++ pAd->StaCfg.BssType = BSS_ADHOC; ++ else //Default Infrastructure mode ++ pAd->StaCfg.BssType = BSS_INFRA; ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ //Channel ++ if(RTMPGetKeyParameter("Channel", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.Channel = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("Channel=%d\n", pAd->CommonCfg.Channel)); ++ } ++ //WirelessMode ++ if(RTMPGetKeyParameter("WirelessMode", tmpbuf, 10, buffer)) ++ { ++ int value = 0, maxPhyMode = PHY_11G; ++ ++#ifdef DOT11_N_SUPPORT ++ maxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ value = simple_strtol(tmpbuf, 0, 10); ++ ++ if (value <= maxPhyMode) ++ { ++ pAd->CommonCfg.PhyMode = value; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("PhyMode=%d\n", pAd->CommonCfg.PhyMode)); ++ } ++ //BasicRate ++ if(RTMPGetKeyParameter("BasicRate", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.BasicRateBitmap = (ULONG) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("BasicRate=%ld\n", pAd->CommonCfg.BasicRateBitmap)); ++ } ++ //BeaconPeriod ++ if(RTMPGetKeyParameter("BeaconPeriod", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.BeaconPeriod = (USHORT) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconPeriod=%d\n", pAd->CommonCfg.BeaconPeriod)); ++ } ++ //TxPower ++ if(RTMPGetKeyParameter("TxPower", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.TxPowerPercentage = (ULONG) simple_strtol(tmpbuf, 0, 10); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPower=%ld\n", pAd->CommonCfg.TxPowerPercentage)); ++ } ++ //BGProtection ++ if(RTMPGetKeyParameter("BGProtection", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //Always On ++ pAd->CommonCfg.UseBGProtection = 1; ++ break; ++ case 2: //Always OFF ++ pAd->CommonCfg.UseBGProtection = 2; ++ break; ++ case 0: //AUTO ++ default: ++ pAd->CommonCfg.UseBGProtection = 0; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("BGProtection=%ld\n", pAd->CommonCfg.UseBGProtection)); ++ } ++ //OLBCDetection ++ if(RTMPGetKeyParameter("DisableOLBC", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //disable OLBC Detection ++ pAd->CommonCfg.DisableOLBCDetect = 1; ++ break; ++ case 0: //enable OLBC Detection ++ pAd->CommonCfg.DisableOLBCDetect = 0; ++ break; ++ default: ++ pAd->CommonCfg.DisableOLBCDetect= 0; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("OLBCDetection=%ld\n", pAd->CommonCfg.DisableOLBCDetect)); ++ } ++ //TxPreamble ++ if(RTMPGetKeyParameter("TxPreamble", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case Rt802_11PreambleShort: ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleShort; ++ break; ++ case Rt802_11PreambleLong: ++ default: ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleLong; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPreamble=%ld\n", pAd->CommonCfg.TxPreamble)); ++ } ++ //RTSThreshold ++ if(RTMPGetKeyParameter("RTSThreshold", tmpbuf, 10, buffer)) ++ { ++ RtsThresh = simple_strtol(tmpbuf, 0, 10); ++ if( (RtsThresh >= 1) && (RtsThresh <= MAX_RTS_THRESHOLD) ) ++ pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ else ++ pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTSThreshold=%d\n", pAd->CommonCfg.RtsThreshold)); ++ } ++ //FragThreshold ++ if(RTMPGetKeyParameter("FragThreshold", tmpbuf, 10, buffer)) ++ { ++ FragThresh = simple_strtol(tmpbuf, 0, 10); ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { //illegal FragThresh so we set it to default ++ pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else if (FragThresh % 2 == 1) ++ { ++ // The length of each fragment shall always be an even number of octets, except for the last fragment ++ // of an MSDU or MMPDU, which may be either an even or an odd number of octets. ++ pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); ++ } ++ else ++ { ++ pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ //pAd->CommonCfg.AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; ++ DBGPRINT(RT_DEBUG_TRACE, ("FragThreshold=%d\n", pAd->CommonCfg.FragmentThreshold)); ++ } ++ //TxBurst ++ if(RTMPGetKeyParameter("TxBurst", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bEnableTxBurst = TRUE; ++ else //Disable ++ pAd->CommonCfg.bEnableTxBurst = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("TxBurst=%d\n", pAd->CommonCfg.bEnableTxBurst)); ++ } ++ ++#ifdef AGGREGATION_SUPPORT ++ //PktAggregate ++ if(RTMPGetKeyParameter("PktAggregate", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bAggregationCapable = TRUE; ++ else //Disable ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++#ifdef PIGGYBACK_SUPPORT ++ pAd->CommonCfg.bPiggyBackCapable = pAd->CommonCfg.bAggregationCapable; ++#endif // PIGGYBACK_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("PktAggregate=%d\n", pAd->CommonCfg.bAggregationCapable)); ++ } ++#else ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++ pAd->CommonCfg.bPiggyBackCapable = FALSE; ++#endif // AGGREGATION_SUPPORT // ++ ++ // WmmCapable ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); ++#endif // CONFIG_STA_SUPPORT // ++ ++ //ShortSlot ++ if(RTMPGetKeyParameter("ShortSlot", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bUseShortSlotTime = TRUE; ++ else //Disable ++ pAd->CommonCfg.bUseShortSlotTime = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortSlot=%d\n", pAd->CommonCfg.bUseShortSlotTime)); ++ } ++ //IEEE80211H ++ if(RTMPGetKeyParameter("IEEE80211H", tmpbuf, 10, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ if(simple_strtol(macptr, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bIEEE80211H = TRUE; ++ else //Disable ++ pAd->CommonCfg.bIEEE80211H = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IEEE80211H=%d\n", pAd->CommonCfg.bIEEE80211H)); ++ } ++ } ++ //CSPeriod ++ if(RTMPGetKeyParameter("CSPeriod", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.RadarDetect.CSPeriod = simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.RadarDetect.CSPeriod = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CSPeriod=%d\n", pAd->CommonCfg.RadarDetect.CSPeriod)); ++ } ++ ++ //RDRegion ++ if(RTMPGetKeyParameter("RDRegion", tmpbuf, 128, buffer)) ++ { ++ if ((strncmp(tmpbuf, "JAP_W53", 7) == 0) || (strncmp(tmpbuf, "jap_w53", 7) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W53; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 15; ++ } ++ else if ((strncmp(tmpbuf, "JAP_W56", 7) == 0) || (strncmp(tmpbuf, "jap_w56", 7) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W56; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ else if ((strncmp(tmpbuf, "JAP", 3) == 0) || (strncmp(tmpbuf, "jap", 3) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; ++ } ++ else if ((strncmp(tmpbuf, "FCC", 3) == 0) || (strncmp(tmpbuf, "fcc", 3) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = FCC; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; ++ } ++ else if ((strncmp(tmpbuf, "CE", 2) == 0) || (strncmp(tmpbuf, "ce", 2) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ else ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RDRegion=%d\n", pAd->CommonCfg.RadarDetect.RDDurRegion)); ++ } ++ else ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ ++ //WirelessEvent ++ if(RTMPGetKeyParameter("WirelessEvent", tmpbuf, 10, buffer)) ++ { ++#if WIRELESS_EXT >= 15 ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.bWirelessEvent = simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.bWirelessEvent = 0; // disable ++#else ++ pAd->CommonCfg.bWirelessEvent = 0; // disable ++#endif ++ DBGPRINT(RT_DEBUG_TRACE, ("WirelessEvent=%d\n", pAd->CommonCfg.bWirelessEvent)); ++ } ++ if(RTMPGetKeyParameter("WiFiTest", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.bWiFiTest= simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.bWiFiTest = 0; // disable ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WiFiTest=%d\n", pAd->CommonCfg.bWiFiTest)); ++ } ++ //AuthMode ++ if(RTMPGetKeyParameter("AuthMode", tmpbuf, 128, buffer)) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((strcmp(tmpbuf, "WEPAUTO") == 0) || (strcmp(tmpbuf, "wepauto") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(tmpbuf, "SHARED") == 0) || (strcmp(tmpbuf, "shared") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(tmpbuf, "WPAPSK") == 0) || (strcmp(tmpbuf, "wpapsk") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(tmpbuf, "WPANONE") == 0) || (strcmp(tmpbuf, "wpanone") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(tmpbuf, "WPA2PSK") == 0) || (strcmp(tmpbuf, "wpa2psk") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(tmpbuf, "WPA") == 0) || (strcmp(tmpbuf, "wpa") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(tmpbuf, "WPA2") == 0) || (strcmp(tmpbuf, "wpa2") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ //EncrypType ++ if(RTMPGetKeyParameter("EncrypType", tmpbuf, 128, buffer)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ else if ((strcmp(tmpbuf, "TKIP") == 0) || (strcmp(tmpbuf, "tkip") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ else if ((strcmp(tmpbuf, "AES") == 0) || (strcmp(tmpbuf, "aes") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ else ++ pAd->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ ++ // Update all wepstatus related ++ pAd->StaCfg.PairCipher = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.bMixCipher = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if(RTMPGetCriticalParameter("WPAPSK", tmpbuf, 512, buffer)) ++ { ++ int err=0; ++ ++ tmpbuf[strlen(tmpbuf)] = '\0'; // make STA can process .$^& for WPAPSK input ++ ++ if ((pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ { ++ err = 1; ++ } ++ else if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) < 64)) ++ { ++ PasswordHash((char *)tmpbuf, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, keyMaterial); ++ NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else if (strlen(tmpbuf) == 64) ++ { ++ AtoH(tmpbuf, keyMaterial, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); ++ } ++ else ++ { ++ err = 1; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__)); ++ } ++ ++ if (err == 0) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // Start STA supplicant state machine ++ pAd->StaCfg.WpaState = SS_START; ++ } ++ else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ //DefaultKeyID, KeyType, KeyStr ++ rtmp_read_key_parms_from_file(pAd, tmpbuf, buffer); ++ ++#ifdef DOT11_N_SUPPORT ++ HTParametersHook(pAd, tmpbuf, buffer); ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++ //CarrierDetect ++ if(RTMPGetKeyParameter("CarrierDetect", tmpbuf, 128, buffer)) ++ { ++ if ((strncmp(tmpbuf, "0", 1) == 0)) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else if ((strncmp(tmpbuf, "1", 1) == 0)) ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CarrierDetect.Enable=%d\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ } ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //PSMode ++ if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) ++ { ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(tmpbuf, "MAX_PSP") == 0) || (strcmp(tmpbuf, "max_psp") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsm(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAd->StaCfg.DefaultListenCount = 5; ++ } ++ else if ((strcmp(tmpbuf, "Fast_PSP") == 0) || (strcmp(tmpbuf, "fast_psp") == 0) ++ || (strcmp(tmpbuf, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsmBit(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAd->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(tmpbuf, "Legacy_PSP") == 0) || (strcmp(tmpbuf, "legacy_psp") == 0) ++ || (strcmp(tmpbuf, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsmBit(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAd->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("PSMode=%ld\n", pAd->StaCfg.WindowsPowerMode)); ++ } ++ } ++ // FastRoaming ++ if (RTMPGetKeyParameter("FastRoaming", tmpbuf, 32, buffer)) ++ { ++ if (simple_strtol(tmpbuf, 0, 10) == 0) ++ pAd->StaCfg.bFastRoaming = FALSE; ++ else ++ pAd->StaCfg.bFastRoaming = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FastRoaming=%d\n", pAd->StaCfg.bFastRoaming)); ++ } ++ // RoamThreshold ++ if (RTMPGetKeyParameter("RoamThreshold", tmpbuf, 32, buffer)) ++ { ++ long lInfo = simple_strtol(tmpbuf, 0, 10); ++ ++ if (lInfo > 90 || lInfo < 60) ++ pAd->StaCfg.dBmToRoam = -70; ++ else ++ pAd->StaCfg.dBmToRoam = (CHAR)(-1)*lInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RoamThreshold=%d dBm\n", pAd->StaCfg.dBmToRoam)); ++ } ++ ++ if(RTMPGetKeyParameter("TGnWifiTest", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("TGnWifiTest=%d\n", pAd->StaCfg.bTGnWifiTest)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> %s does not have a write method\n", src)); ++ } ++ ++ retval=filp_close(srcf,NULL); ++ ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); ++ } ++ } ++ } ++ ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ ++ kfree(buffer); ++ kfree(tmpbuf); ++ ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++#ifdef DOT11_N_SUPPORT ++static void HTParametersHook( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR *pValueStr, ++ IN CHAR *pInput) ++{ ++ ++ INT Value; ++ ++ if (RTMPGetKeyParameter("HT_PROTECT", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bHTProtect = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bHTProtect = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Protection = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ if (RTMPGetKeyParameter("HT_MIMOPSEnable", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bMIMOPSEnable = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPSEnable = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ ++ if (RTMPGetKeyParameter("HT_MIMOPSMode", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value > MMPS_ENABLE) ++ { ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ } ++ else ++ { ++ //TODO: add mimo power saving mechanism ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ //pAd->CommonCfg.BACapability.field.MMPSmode = Value; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPS Mode = %d\n", Value)); ++ } ++ ++ if (RTMPGetKeyParameter("HT_BADecline", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bBADecline = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bBADecline = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Decline = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ ++ if (RTMPGetKeyParameter("HT_DisableReordering", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bDisableReordering = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bDisableReordering = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: DisableReordering = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ if (RTMPGetKeyParameter("HT_AutoBA", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ } ++ pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Auto BA = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // Tx_+HTC frame ++ if (RTMPGetKeyParameter("HT_HTC", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->HTCEnable = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx +HTC frame = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // Enable HT Link Adaptation Control ++ if (RTMPGetKeyParameter("HT_LinkAdapt", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->bLinkAdapt = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->bLinkAdapt = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Link Adaptation Control = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); ++ } ++ ++ // Reverse Direction Mechanism ++ if (RTMPGetKeyParameter("HT_RDG", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bRdg = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->CommonCfg.bRdg = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: RDG = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); ++ } ++ ++ ++ ++ ++ // Tx A-MSUD ? ++ if (RTMPGetKeyParameter("HT_AMSDU", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx A-MSDU = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // MPDU Density ++ if (RTMPGetKeyParameter("HT_MpduDensity", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value <=7 && Value >= 0) ++ { ++ pAd->CommonCfg.BACapability.field.MpduDensity = Value; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d\n", Value)); ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.MpduDensity = 4; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d (Default)\n", 4)); ++ } ++ } ++ ++ // Max Rx BA Window Size ++ if (RTMPGetKeyParameter("HT_BAWinSize", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value >=1 && Value <= 64) ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = %d\n", Value)); ++ } ++ else ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = 64 (Defualt)\n")); ++ } ++ ++ } ++ ++ // Guard Interval ++ if (RTMPGetKeyParameter("HT_GI", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == GI_400) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Guard Interval = %s\n", (Value==GI_400) ? "400" : "800" )); ++ } ++ ++ // HT Operation Mode : Mixed Mode , Green Field ++ if (RTMPGetKeyParameter("HT_OpMode", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == HTMODE_GF) ++ { ++ ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Operate Mode = %s\n", (Value==HTMODE_GF) ? "Green Field" : "Mixed Mode" )); ++ } ++ ++ // Fixed Tx mode : CCK, OFDM ++ if (RTMPGetKeyParameter("FixedTxMode", pValueStr, 25, pInput)) ++ { ++ UCHAR fix_tx_mode; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ fix_tx_mode = FIXED_TXMODE_HT; ++ ++ if (strcmp(pValueStr, "OFDM") == 0 || strcmp(pValueStr, "ofdm") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_OFDM; ++ } ++ else if (strcmp(pValueStr, "CCK") == 0 || strcmp(pValueStr, "cck") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_CCK; ++ } ++ else if (strcmp(pValueStr, "HT") == 0 || strcmp(pValueStr, "ht") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_HT; ++ } ++ else ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ // 1 : CCK ++ // 2 : OFDM ++ // otherwise : HT ++ if (Value == FIXED_TXMODE_CCK || Value == FIXED_TXMODE_OFDM) ++ fix_tx_mode = Value; ++ else ++ fix_tx_mode = FIXED_TXMODE_HT; ++ } ++ ++ pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; ++ DBGPRINT(RT_DEBUG_TRACE, ("Fixed Tx Mode = %d\n", fix_tx_mode)); ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ // Channel Width ++ if (RTMPGetKeyParameter("HT_BW", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == BW_40) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } ++ ++#ifdef MCAST_RATE_SPECIFIC ++ pAd->CommonCfg.MCastPhyMode.field.BW = pAd->CommonCfg.RegTransmitSetting.field.BW; ++#endif // MCAST_RATE_SPECIFIC // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Channel Width = %s\n", (Value==BW_40) ? "40 MHz" : "20 MHz" )); ++ } ++ ++ if (RTMPGetKeyParameter("HT_EXTCHA", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == 0) ++ { ++ ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Ext Channel = %s\n", (Value==0) ? "BELOW" : "ABOVE" )); ++ } ++ ++ // MSC ++ if (RTMPGetKeyParameter("HT_MCS", pValueStr, 50, pInput)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if ((Value >= 0 && Value <= 23) || (Value == 32)) // 3*3 ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = Value; ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = %d\n", pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = AUTO\n")); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // STBC ++ if (RTMPGetKeyParameter("HT_STBC", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == STBC_USE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: STBC = %d\n", pAd->CommonCfg.RegTransmitSetting.field.STBC)); ++ } ++ ++ // 40_Mhz_Intolerant ++ if (RTMPGetKeyParameter("HT_40MHZ_INTOLERANT", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bForty_Mhz_Intolerant = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bForty_Mhz_Intolerant = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: 40MHZ INTOLERANT = %d\n", pAd->CommonCfg.bForty_Mhz_Intolerant)); ++ } ++ //HT_TxStream ++ if(RTMPGetKeyParameter("HT_TxStream", pValueStr, 10, pInput)) ++ { ++ switch (simple_strtol(pValueStr, 0, 10)) ++ { ++ case 1: ++ pAd->CommonCfg.TxStream = 1; ++ break; ++ case 2: ++ pAd->CommonCfg.TxStream = 2; ++ break; ++ case 3: // 3*3 ++ default: ++ pAd->CommonCfg.TxStream = 3; ++ ++ if (pAd->MACVersion < RALINK_2883_VERSION) ++ pAd->CommonCfg.TxStream = 2; // only 2 tx streams for RT2860 series ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx Stream = %d\n", pAd->CommonCfg.TxStream)); ++ } ++ //HT_RxStream ++ if(RTMPGetKeyParameter("HT_RxStream", pValueStr, 10, pInput)) ++ { ++ switch (simple_strtol(pValueStr, 0, 10)) ++ { ++ case 1: ++ pAd->CommonCfg.RxStream = 1; ++ break; ++ case 2: ++ pAd->CommonCfg.RxStream = 2; ++ break; ++ case 3: ++ default: ++ pAd->CommonCfg.RxStream = 3; ++ ++ if (pAd->MACVersion < RALINK_2883_VERSION) ++ pAd->CommonCfg.RxStream = 2; // only 2 rx streams for RT2860 series ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Rx Stream = %d\n", pAd->CommonCfg.RxStream)); ++ } ++ ++} ++#endif // DOT11_N_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/spectrum_def.h +@@ -0,0 +1,95 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ spectrum_def.h ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ --------- ---------- ---------------------------------------------- ++ Fonchi Wu 2008 created for 802.11h ++ */ ++ ++#ifndef __SPECTRUM_DEF_H__ ++#define __SPECTRUM_DEF_H__ ++ ++#define MAX_MEASURE_REQ_TAB_SIZE 3 ++#define MAX_HASH_MEASURE_REQ_TAB_SIZE MAX_MEASURE_REQ_TAB_SIZE ++ ++#define MAX_TPC_REQ_TAB_SIZE 3 ++#define MAX_HASH_TPC_REQ_TAB_SIZE MAX_TPC_REQ_TAB_SIZE ++ ++#define MIN_RCV_PWR 100 /* Negative value ((dBm) */ ++ ++#define RM_TPC_REQ 0 ++#define RM_MEASURE_REQ 1 ++ ++#define RM_BASIC 0 ++#define RM_CCA 1 ++#define RM_RPI_HISTOGRAM 2 ++ ++#define TPC_REQ_AGE_OUT 500 /* ms */ ++#define MQ_REQ_AGE_OUT 500 /* ms */ ++ ++#define TPC_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_HASH_TPC_REQ_TAB_SIZE) ++#define MQ_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_MEASURE_REQ_TAB_SIZE) ++ ++typedef struct _MEASURE_REQ_ENTRY ++{ ++ struct _MEASURE_REQ_ENTRY *pNext; ++ ULONG lastTime; ++ BOOLEAN Valid; ++ UINT8 DialogToken; ++ UINT8 MeasureDialogToken[3]; // 0:basic measure, 1: CCA measure, 2: RPI_Histogram measure. ++} MEASURE_REQ_ENTRY, *PMEASURE_REQ_ENTRY; ++ ++typedef struct _MEASURE_REQ_TAB ++{ ++ UCHAR Size; ++ PMEASURE_REQ_ENTRY Hash[MAX_HASH_MEASURE_REQ_TAB_SIZE]; ++ MEASURE_REQ_ENTRY Content[MAX_MEASURE_REQ_TAB_SIZE]; ++} MEASURE_REQ_TAB, *PMEASURE_REQ_TAB; ++ ++typedef struct _TPC_REQ_ENTRY ++{ ++ struct _TPC_REQ_ENTRY *pNext; ++ ULONG lastTime; ++ BOOLEAN Valid; ++ UINT8 DialogToken; ++} TPC_REQ_ENTRY, *PTPC_REQ_ENTRY; ++ ++typedef struct _TPC_REQ_TAB ++{ ++ UCHAR Size; ++ PTPC_REQ_ENTRY Hash[MAX_HASH_TPC_REQ_TAB_SIZE]; ++ TPC_REQ_ENTRY Content[MAX_TPC_REQ_TAB_SIZE]; ++} TPC_REQ_TAB, *PTPC_REQ_TAB; ++ ++#endif // __SPECTRUM_DEF_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/spectrum.h +@@ -0,0 +1,322 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#ifndef __SPECTRUM_H__ ++#define __SPECTRUM_H__ ++ ++#include "rtmp_type.h" ++#include "spectrum_def.h" ++ ++typedef struct PACKED _TPC_REPORT_INFO ++{ ++ UINT8 TxPwr; ++ UINT8 LinkMargin; ++} TPC_REPORT_INFO, *PTPC_REPORT_INFO; ++ ++typedef struct PACKED _CH_SW_ANN_INFO ++{ ++ UINT8 ChSwMode; ++ UINT8 Channel; ++ UINT8 ChSwCnt; ++} CH_SW_ANN_INFO, *PCH_SW_ANN_INFO; ++ ++typedef union PACKED _MEASURE_REQ_MODE ++{ ++#ifdef RT_BIG_ENDIAN ++ struct PACKED ++ { ++ UINT8 Rev1:4; ++ UINT8 Report:1; ++ UINT8 Request:1; ++ UINT8 Enable:1; ++ UINT8 Rev0:1; ++ } field; ++#else ++ struct PACKED ++ { ++ UINT8 Rev0:1; ++ UINT8 Enable:1; ++ UINT8 Request:1; ++ UINT8 Report:1; ++ UINT8 Rev1:4; ++ } field; ++#endif // RT_BIG_ENDIAN // ++ UINT8 word; ++} MEASURE_REQ_MODE, *PMEASURE_REQ_MODE; ++ ++typedef struct PACKED _MEASURE_REQ ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++} MEASURE_REQ, *PMEASURE_REQ; ++ ++typedef struct PACKED _MEASURE_REQ_INFO ++{ ++ UINT8 Token; ++ MEASURE_REQ_MODE ReqMode; ++ UINT8 ReqType; ++ MEASURE_REQ MeasureReq; ++} MEASURE_REQ_INFO, *PMEASURE_REQ_INFO; ++ ++typedef union PACKED _MEASURE_BASIC_REPORT_MAP ++{ ++#ifdef RT_BIG_ENDIAN ++ struct PACKED ++ { ++ UINT8 Rev:3; ++ UINT8 Unmeasure:1; ++ UINT8 Radar:1; ++ UINT8 UnidentifiedSignal:1; ++ UINT8 OfdmPreamble:1; ++ UINT8 BSS:1; ++ } field; ++#else ++ struct PACKED ++ { ++ UINT8 BSS:1; ++ UINT8 OfdmPreamble:1; ++ UINT8 UnidentifiedSignal:1; ++ UINT8 Radar:1; ++ UINT8 Unmeasure:1; ++ UINT8 Rev:3; ++ } field; ++#endif // RT_BIG_ENDIAN // ++ UINT8 word; ++} MEASURE_BASIC_REPORT_MAP, *PMEASURE_BASIC_REPORT_MAP; ++ ++typedef struct PACKED _MEASURE_BASIC_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ MEASURE_BASIC_REPORT_MAP Map; ++} MEASURE_BASIC_REPORT, *PMEASURE_BASIC_REPORT; ++ ++typedef struct PACKED _MEASURE_CCA_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ UINT8 CCA_Busy_Fraction; ++} MEASURE_CCA_REPORT, *PMEASURE_CCA_REPORT; ++ ++typedef struct PACKED _MEASURE_RPI_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ UINT8 RPI_Density[8]; ++} MEASURE_RPI_REPORT, *PMEASURE_RPI_REPORT; ++ ++typedef union PACKED _MEASURE_REPORT_MODE ++{ ++ struct PACKED ++ { ++#ifdef RT_BIG_ENDIAN ++ UINT8 Rev:5; ++ UINT8 Refused:1; ++ UINT8 Incapable:1; ++ UINT8 Late:1; ++#else ++ UINT8 Late:1; ++ UINT8 Incapable:1; ++ UINT8 Refused:1; ++ UINT8 Rev:5; ++#endif // RT_BIG_ENDIAN // ++ } field; ++ UINT8 word; ++} MEASURE_REPORT_MODE, *PMEASURE_REPORT_MODE; ++ ++typedef struct PACKED _MEASURE_REPORT_INFO ++{ ++ UINT8 Token; ++ MEASURE_REPORT_MODE ReportMode; ++ UINT8 ReportType; ++ UINT8 Octect[0]; ++} MEASURE_REPORT_INFO, *PMEASURE_REPORT_INFO; ++ ++typedef struct PACKED _QUIET_INFO ++{ ++ UINT8 QuietCnt; ++ UINT8 QuietPeriod; ++ UINT8 QuietDuration; ++ UINT8 QuietOffset; ++} QUIET_INFO, *PQUIET_INFO; ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 MeasureCh, ++ IN UINT16 MeasureDuration); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 ReportInfoLen, ++ IN PUINT8 pReportInfo); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UCHAR DialogToken); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Channel Switch Announcement action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ 2. Channel switch announcement mode. ++ 2. a New selected channel. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueChSwAnn( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewCh); ++ ++/* ++ ========================================================================== ++ Description: ++ Spectrun action frames Handler such as channel switch annoucement, ++ measurement report, measurement request actions frames. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID PeerSpectrumAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Parametrs: ++ ++ Return : None. ++ ========================================================================== ++ */ ++INT Set_MeasureReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TpcReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++VOID MeasureReqTabInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MeasureReqTabExit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID TpcReqTabInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID TpcReqTabExit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NotifyChSwAnnToPeerAPs( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRA, ++ IN PUCHAR pTA, ++ IN UINT8 ChSwMode, ++ IN UINT8 Channel); ++#endif // __SPECTRUM_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/aironet.c +@@ -0,0 +1,1312 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 04-06-15 Initial ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ========================================================================== ++ */ ++VOID AironetStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE); ++ StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction); ++ StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction); ++ StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This is state machine function. ++ When receiving EAPOL packets which is for 802.1x key management. ++ Use both in WPA, and WPAPSK case. ++ In this function, further dispatch to different functions according to the received packet. 3 categories are : ++ 1. normal 4-way pairwisekey and 2-way groupkey handshake ++ 2. MIC error (Countermeasures attack) report packet from STA. ++ 3. Request for pairwise/group key update from STA ++ Return: ++ ========================================================================== ++*/ ++VOID AironetMsgAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Length; ++ UCHAR Index, i; ++ PUCHAR pData; ++ PAIRONET_RM_REQUEST_FRAME pRMReq; ++ PRM_REQUEST_ACTION pReqElem; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n")); ++ ++ // 0. Get Aironet IAPP header first ++ pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11]; ++ pData = (PUCHAR) &Elem->Msg[LENGTH_802_11]; ++ ++ // 1. Change endian format form network to little endian ++ Length = be2cpu16(pRMReq->IAPP.Length); ++ ++ // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled ++ if (pAd->StaCfg.CCXEnable != TRUE) ++ return; ++ ++ // 2.1 Radio measurement must be on ++ if (pAd->StaCfg.CCXControl.field.RMEnable != 1) ++ return; ++ ++ // 2.2. Debug print all bit information ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset)); ++ ++ // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension ++ if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n")); ++ return; ++ } ++ ++ // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request. ++ // Since we are acting as client only, we will disregards reply subtype. ++ if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n")); ++ return; ++ } ++ ++ // 5. Verify Destination MAC and Source MAC, both should be all zeros. ++ if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n")); ++ return; ++ } ++ ++ if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n")); ++ return; ++ } ++ ++ // 6. Reinit all report related fields ++ NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048); ++ NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE); ++ NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4); ++ ++ // 7. Point to the start of first element report element ++ pAd->StaCfg.FrameReportLen = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER); ++ DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); ++ pAd->StaCfg.LastBssIndex = 0xff; ++ pAd->StaCfg.RMReqCnt = 0; ++ pAd->StaCfg.ParallelReq = FALSE; ++ pAd->StaCfg.ParallelDuration = 0; ++ pAd->StaCfg.ParallelChannel = 0; ++ pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; ++ pAd->StaCfg.CurrentRMReqIdx = 0; ++ pAd->StaCfg.CLBusyBytes = 0; ++ // Reset the statistics ++ for (i = 0; i < 8; i++) ++ pAd->StaCfg.RPIDensity[i] = 0; ++ ++ Index = 0; ++ ++ // 8. Save dialog token for report ++ pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; ++ ++ // Save Activation delay & measurement offset, Not really needed ++ ++ // 9. Point to the first request element ++ pData += sizeof(AIRONET_RM_REQUEST_FRAME); ++ // Length should exclude the CISCO Aironet SNAP header ++ Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H); ++ ++ // 10. Start Parsing the Measurement elements. ++ // Be careful about multiple MR elements within one frames. ++ while (Length > 0) ++ { ++ pReqElem = (PRM_REQUEST_ACTION) pData; ++ switch (pReqElem->ReqElem.Eid) ++ { ++ case IE_MEASUREMENT_REQUEST: ++ // From the example, it seems we only need to support one request in one frame ++ // There is no multiple request in one frame. ++ // Besides, looks like we need to take care the measurement request only. ++ // The measurement request is always 4 bytes. ++ ++ // Start parsing this type of request. ++ // 0. Eid is IE_MEASUREMENT_REQUEST ++ // 1. Length didn't include Eid and Length field, it always be 8. ++ // 2. Measurement Token, we nned to save it for the corresponding report. ++ // 3. Measurement Mode, Although there are definitions, but we din't see value other than ++ // 0 from test specs examples. ++ // 4. Measurement Type, this is what we need to do. ++ switch (pReqElem->ReqElem.Type) ++ { ++ case MSRN_TYPE_CHANNEL_LOAD_REQ: ++ case MSRN_TYPE_NOISE_HIST_REQ: ++ case MSRN_TYPE_BEACON_REQ: ++ // Check the Enable non-serving channel measurement control ++ if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0) ++ { ++ // Check channel before enqueue the action ++ if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) ++ break; ++ } ++ else ++ { ++ // If off channel measurement, check the TU duration limit ++ if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) ++ if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit) ++ break; ++ } ++ ++ // Save requests and execute actions later ++ NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION)); ++ Index += 1; ++ break; ++ ++ case MSRN_TYPE_FRAME_REQ: ++ // Since it's option, we will support later ++ // FrameRequestAction(pAd, pData); ++ break; ++ ++ default: ++ break; ++ } ++ ++ // Point to next Measurement request ++ pData += sizeof(RM_REQUEST_ACTION); ++ Length -= sizeof(RM_REQUEST_ACTION); ++ break; ++ ++ // We accept request only, all others are dropped ++ case IE_MEASUREMENT_REPORT: ++ case IE_AP_TX_POWER: ++ case IE_MEASUREMENT_CAPABILITY: ++ default: ++ return; ++ } ++ } ++ ++ // 11. Update some flags and index ++ pAd->StaCfg.RMReqCnt = Index; ++ ++ if (Index) ++ { ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRM_REQUEST_ACTION pReq; ++ ++ // 1. Point to next request element ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ // 2. Parse measurement type and call appropriate functions ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) ++ // Beacon measurement request ++ BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else ++ // Unknown. Do nothing and return, this should never happen ++ return; ++ ++ // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one ++ if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt) ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1]; ++ // Check for parallel bit ++ if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel)) ++ { ++ // Update parallel mode request information ++ pAd->StaCfg.ParallelReq = TRUE; ++ pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ? ++ (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime)); ++ } ++ } ++ ++ // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used ++ RT28XX_MLME_HANDLER(pAd); ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare channel load report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ChannelLoadRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32]; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ // Passive scan Mode ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer;; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_CHANNEL_LOAD_REQ; ++ pAd->StaCfg.CLBusyBytes = 0; ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); ++ ++ // Set channel load measurement flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare noise histogram report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NoiseHistRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32], i; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ // Passive scan Mode ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_NOISE_HIST_REQ; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ // Reset the statistics ++ for (i = 0; i < 8; i++) ++ pAd->StaCfg.RPIDensity[i] = 0; ++ ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); ++ ++ // Set channel load measurement flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare Beacon report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID BeaconRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE) ++ { ++ // Passive scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n")); ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ } ++ else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE) ++ { ++ // Active scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n")); ++ ++ // Control state machine is not idle, reject the request ++ if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ } ++ else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE) ++ { ++ // Beacon report Mode, report all the APS in current bss table ++ DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n")); ++ ++ // Copy current BSS table to CCX table, we can omit this step later on. ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE)); ++ ++ // Create beacon report from Bss table ++ AironetCreateBeaconReportFromBssTable(pAd); ++ ++ // Set state to scanning ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ // Enqueue report request ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++ else ++ { ++ // Wrong scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n")); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRM_REQUEST_ACTION pReq; ++ ULONG Now32; ++ ++ NdisGetSystemUpTime(&Now32); ++ pAd->StaCfg.LastBeaconRxTime = Now32; ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n")); ++ ++ // 1. Parse measurement type and call appropriate functions ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) ++ // Beacon measurement request ++ BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else ++ // Unknown. Do nothing and return ++ ; ++ ++ // 2. Point to the correct index of action element, start from 0 ++ pAd->StaCfg.CurrentRMReqIdx++; ++ ++ // 3. Check for parallel actions ++ if (pAd->StaCfg.ParallelReq == TRUE) ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ // Process next action right away ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ ++ pAd->StaCfg.ParallelReq = FALSE; ++ pAd->StaCfg.CurrentRMReqIdx++; ++ } ++ ++ if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt) ++ { ++ // 4. There is no more unprocessed measurement request, go for transmit this report ++ AironetFinalReportAction(pAd); ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ } ++ else ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ if (pReq->Measurement.Channel != pAd->CommonCfg.Channel) ++ { ++ RTMPusecDelay(100000); ++ } ++ ++ // 5. There are more requests to be measure ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetFinalReportAction( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PUCHAR pDest; ++ PAIRONET_IAPP_HEADER pIAPP; ++ PHEADER_802_11 pHeader; ++ UCHAR AckRate = RATE_2; ++ USHORT AckDuration = 0; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n")); ++ ++ // 0. Set up the frame pointer, Frame was inited at the end of message action ++ pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11]; ++ ++ // 1. Update report IAPP fields ++ pIAPP = (PAIRONET_IAPP_HEADER) pDest; ++ ++ // 2. Copy Cisco SNAP header ++ NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H); ++ ++ // 3. network order for this 16bit length ++ pIAPP->Length = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H); ++ ++ // 3.1 sanity check the report length, ignore it if there is nothing to report ++ if (be2cpu16(pIAPP->Length) <= 18) ++ return; ++ ++ // 4. Type must be 0x32 ++ pIAPP->Type = AIRONET_IAPP_TYPE; ++ ++ // 5. SubType for report must be 0x81 ++ pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT; ++ ++ // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function ++ // We will do it again here. We can use BSSID instead ++ COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid); ++ ++ // 7. SA is the client reporting which must be our MAC ++ COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress); ++ ++ // 8. Copy the saved dialog token ++ pIAPP->Token = pAd->StaCfg.IAPPToken; ++ ++ // 9. Make the Report frame 802.11 header ++ // Reuse function in wpa.c ++ pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf; ++ pAd->Sequence ++; ++ WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid); ++ ++ // ACK size is 14 include CRC, and its rate is based on real time information ++ AckRate = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate]; ++ AckDuration = RTMPCalcDuration(pAd, AckRate, 14); ++ pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration; ++ ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything. ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf, ++ END_OF_ARGS); ++ ++ // 11. Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ChannelLoadReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PCHANNEL_LOAD_REPORT pLoad; ++ PUCHAR pDest; ++ UCHAR CCABusyFraction; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n")); ++ ++ // Disable Rx with promiscuous reception, make it back to normal ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ ++ // 0. Setup pointer for processing beacon & probe response ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ ++ // 1. Fill Measurement report element field. ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ // Fixed Length at 9, not include Eid and length fields ++ pReport->Length = 9; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_CHANNEL_LOAD_REQ; ++ ++ // 2. Fill channel report measurement data ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pLoad = (PCHANNEL_LOAD_REPORT) pDest; ++ pLoad->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; ++ pLoad->Spare = 0; ++ pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; ++ ++ // 3. Calculate the CCA Busy Fraction ++ // (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed ++ // = (Bytes + ACK) / 12 / duration ++ // 9 is the good value for pAd->StaCfg.CLFactor ++ // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration); ++ CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration); ++ if (CCABusyFraction < 10) ++ CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1; ++ ++ pLoad->CCABusy = CCABusyFraction; ++ DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); ++ pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); ++ ++ // 4. Clear channel load measurement flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ // 5. reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NoiseHistReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PNOISE_HIST_REPORT pNoise; ++ PUCHAR pDest; ++ UCHAR i,NoiseCnt; ++ USHORT TotalRPICnt, TotalRPISum; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n")); ++ ++ // 0. Disable Rx with promiscuous reception, make it back to normal ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ // 1. Setup pointer for processing beacon & probe response ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ ++ // 2. Fill Measurement report element field. ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ // Fixed Length at 16, not include Eid and length fields ++ pReport->Length = 16; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_NOISE_HIST_REQ; ++ ++ // 3. Fill noise histogram report measurement data ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pNoise = (PNOISE_HIST_REPORT) pDest; ++ pNoise->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; ++ pNoise->Spare = 0; ++ pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; ++ // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU ++ // We estimate 4000 normal packets received durning 10 seconds test. ++ // Adjust it if required. ++ // 3 is a good value for pAd->StaCfg.NHFactor ++ // TotalRPICnt = pNoise->Duration * 3 / 10; ++ TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10; ++ TotalRPISum = 0; ++ ++ for (i = 0; i < 8; i++) ++ { ++ TotalRPISum += pAd->StaCfg.RPIDensity[i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i])); ++ } ++ ++ // Double check if the counter is larger than our expectation. ++ // We will replace it with the total number plus a fraction. ++ if (TotalRPISum > TotalRPICnt) ++ TotalRPICnt = TotalRPISum + pNoise->Duration / 20; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt)); ++ ++ // 5. Initialize noise count for the total summation of 0xff ++ NoiseCnt = 0; ++ for (i = 1; i < 8; i++) ++ { ++ pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt); ++ if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0)) ++ pNoise->Density[i]++; ++ NoiseCnt += pNoise->Density[i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d] = 0x%02x\n", i, pNoise->Density[i])); ++ } ++ ++ // 6. RPI[0] represents the rest of counts ++ pNoise->Density[0] = 0xff - NoiseCnt; ++ DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0] = 0x%02x\n", pNoise->Density[0])); ++ ++ pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT)); ++ ++ // 7. Clear channel load measurement flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ // 8. reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare Beacon report action, ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID BeaconReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n")); ++ ++ // Looks like we don't have anything thing need to do here. ++ // All measurement report already finished in AddBeaconReport ++ // The length is in the FrameReportLen ++ ++ // reset Beacon index for next beacon request ++ pAd->StaCfg.LastBssIndex = 0xff; ++ ++ // reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Index Current BSSID in CCXBsstab entry index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetAddBeaconReport( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Index, ++ IN PMLME_QUEUE_ELEM pElem) ++{ ++ PVOID pMsg; ++ PUCHAR pSrc, pDest; ++ UCHAR ReqIdx; ++ ULONG MsgLen; ++ USHORT Length; ++ PFRAME_802_11 pFrame; ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PEID_STRUCT pEid; ++ PBEACON_REPORT pBeaconReport; ++ PBSS_ENTRY pBss; ++ ++ // 0. Setup pointer for processing beacon & probe response ++ pMsg = pElem->Msg; ++ MsgLen = pElem->MsgLen; ++ pFrame = (PFRAME_802_11) pMsg; ++ pSrc = pFrame->Octet; // Start from AP TSF ++ pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; ++ ReqIdx = pAd->StaCfg.CurrentRMReqIdx; ++ ++ // 1 Check the Index, if we already create this entry, only update the average RSSI ++ if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff)) ++ { ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]]; ++ // Point to bss report information ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ ++ // Update Rx power, in dBm ++ // Get the original RSSI readback from BBP ++ pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta; ++ // Average the Rssi reading ++ pBeaconReport->RxPower = (pBeaconReport->RxPower + pBss->Rssi) / 2; ++ // Get to dBm format ++ pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", ++ pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], ++ pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index])); ++ ++ // Update other information here ++ ++ // Done ++ return; ++ } ++ ++ // 2. Update reported Index ++ pAd->StaCfg.LastBssIndex = Index; ++ ++ // 3. Setup the buffer address for copying this BSSID into reporting frame ++ // The offset should start after 802.11 header and report frame header. ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ ++ // 4. Save the start offset of each Bss in report frame ++ pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen; ++ ++ // 5. Fill Measurement report fields ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ pReport->Length = 0; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_BEACON_REQ; ++ Length = sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ ++ // 6. Start thebeacon report format ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ pDest += sizeof(BEACON_REPORT); ++ Length += sizeof(BEACON_REPORT); ++ ++ // 7. Copy Channel number ++ pBeaconReport->Channel = pBss->Channel; ++ pBeaconReport->Spare = 0; ++ pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; ++ pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); ++ // 8. Rx power, in dBm ++ pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", ++ pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], ++ pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen)); ++ ++ pBeaconReport->BeaconInterval = pBss->BeaconPeriod; ++ COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3); ++ NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4); ++ NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4); ++ ++ // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo ++ pSrc += (TIMESTAMP_LEN + 2); ++ pBeaconReport->CapabilityInfo = *(USHORT *)pSrc; ++ ++ // 10. Point to start of element ID ++ pSrc += 2; ++ pEid = (PEID_STRUCT) pSrc; ++ ++ // 11. Start process all variable Eid oayload and add the appropriate to the frame report ++ while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen)) ++ { ++ // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate, ++ // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set, ++ // TIM (report first 4 bytes only, radio measurement capability ++ switch (pEid->Eid) ++ { ++ case IE_SSID: ++ case IE_SUPP_RATES: ++ case IE_FH_PARM: ++ case IE_DS_PARM: ++ case IE_CF_PARM: ++ case IE_IBSS_PARM: ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ break; ++ ++ case IE_MEASUREMENT_CAPABILITY: ++ // Since this IE is duplicated with WPA security IE, we has to do sanity check before ++ // recognize it. ++ // 1. It also has fixed 6 bytes IE length. ++ if (pEid->Len != 6) ++ break; ++ // 2. Check the Cisco Aironet OUI ++ if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3)) ++ { ++ // Matched, this is what we want ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ } ++ break; ++ ++ case IE_TIM: ++ if (pEid->Len > 4) ++ { ++ // May truncate and report the first 4 bytes only, with the eid & len, total should be 6 ++ NdisMoveMemory(pDest, pEid, 6); ++ pDest += 6; ++ Length += 6; ++ } ++ else ++ { ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ // 12. Move to next element ID ++ pSrc += (2 + pEid->Len); ++ pEid = (PEID_STRUCT) pSrc; ++ } ++ ++ // 13. Update the length in the header, not include EID and length ++ pReport->Length = Length - 4; ++ ++ // 14. Update the frame report buffer data length ++ pAd->StaCfg.FrameReportLen += Length; ++ DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Index Current BSSID in CCXBsstab entry index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetCreateBeaconReportFromBssTable( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PBEACON_REPORT pBeaconReport; ++ UCHAR Index, ReqIdx; ++ USHORT Length; ++ PUCHAR pDest; ++ PBSS_ENTRY pBss; ++ ++ // 0. setup base pointer ++ ReqIdx = pAd->StaCfg.CurrentRMReqIdx; ++ ++ for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++) ++ { ++ // 1. Setup the buffer address for copying this BSSID into reporting frame ++ // The offset should start after 802.11 header and report frame header. ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; ++ Length = 0; ++ ++ // 2. Fill Measurement report fields ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ pReport->Length = 0; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_BEACON_REQ; ++ Length = sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ ++ // 3. Start the beacon report format ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ pDest += sizeof(BEACON_REPORT); ++ Length += sizeof(BEACON_REPORT); ++ ++ // 4. Copy Channel number ++ pBeaconReport->Channel = pBss->Channel; ++ pBeaconReport->Spare = 0; ++ pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; ++ pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); ++ pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; ++ pBeaconReport->BeaconInterval = pBss->BeaconPeriod; ++ pBeaconReport->CapabilityInfo = pBss->CapabilityInfo; ++ COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid); ++ NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4); ++ NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8); ++ ++ // 5. Create SSID ++ *pDest++ = 0x00; ++ *pDest++ = pBss->SsidLen; ++ NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen); ++ pDest += pBss->SsidLen; ++ Length += (2 + pBss->SsidLen); ++ ++ // 6. Create SupportRates ++ *pDest++ = 0x01; ++ *pDest++ = pBss->SupRateLen; ++ NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen); ++ pDest += pBss->SupRateLen; ++ Length += (2 + pBss->SupRateLen); ++ ++ // 7. DS Parameter ++ *pDest++ = 0x03; ++ *pDest++ = 1; ++ *pDest++ = pBss->Channel; ++ Length += 3; ++ ++ // 8. IBSS parameter if presents ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ *pDest++ = 0x06; ++ *pDest++ = 2; ++ *(PUSHORT) pDest = pBss->AtimWin; ++ pDest += 2; ++ Length += 4; ++ } ++ ++ // 9. Update length field, not include EID and length ++ pReport->Length = Length - 4; ++ ++ // 10. Update total frame size ++ pAd->StaCfg.FrameReportLen += Length; ++ } ++} +--- /dev/null ++++ b/drivers/staging/rt2860/sta/assoc.c +@@ -0,0 +1,1826 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ assoc.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-9-3 porting from RT2500 ++*/ ++#include "../rt_config.h" ++ ++UCHAR CipherWpaTemplate[] = { ++ 0xdd, // WPA IE ++ 0x16, // Length ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x01 // authentication ++ }; ++ ++UCHAR CipherWpa2Template[] = { ++ 0x30, // RSN IE ++ 0x14, // Length ++ 0x01, 0x00, // Version ++ 0x00, 0x0f, 0xac, 0x02, // group cipher, TKIP ++ 0x01, 0x00, // number of pairwise ++ 0x00, 0x0f, 0xac, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x0f, 0xac, 0x02, // authentication ++ 0x00, 0x00, // RSN capability ++ }; ++ ++UCHAR Ccx2IeInfo[] = { 0x00, 0x40, 0x96, 0x03, 0x02}; ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE); ++ ++ // first column ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ ++ // second column ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); ++ // ++ // Patch 3Com AP MOde:3CRWE454G72 ++ // We send Assoc request frame to this AP, it always send Reassoc Rsp not Associate Rsp. ++ // ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction); ++ ++ // third column ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); ++ // ++ // Patch, AP doesn't send Reassociate Rsp frame to Station. ++ // ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction); ++ ++ // fourth column ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction); ++ ++ // initialize the timer ++ RTMPInitTimer(pAd, &pAd->MlmeAux.AssocTimer, GET_TIMER_FUNCTION(AssocTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.ReassocTimer, GET_TIMER_FUNCTION(ReassocTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.DisassocTimer, GET_TIMER_FUNCTION(DisassocTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Association timeout procedure. After association timeout, this function ++ will be called and it will put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Reassociation timeout procedure. After reassociation timeout, this ++ function will be called and put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ReassocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Disassociation timeout procedure. After disassociation timeout, this ++ function will be called and put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID DisassocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ mlme assoc req handling procedure ++ Parameters: ++ Adapter - Adapter pointer ++ Elem - MLME Queue Element ++ Pre: ++ the station has been authenticated and the following information is stored in the config ++ -# SSID ++ -# supported rates and their length ++ -# listen interval (Adapter->StaCfg.default_listen_count) ++ -# Transmit power (Adapter->StaCfg.tx_power) ++ Post : ++ -# An association request frame is generated and sent to the air ++ -# Association timer starts ++ -# Association state -> ASSOC_WAIT_RSP ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR ApAddr[6]; ++ HEADER_802_11 AssocHdr; ++ UCHAR Ccx2Len = 5; ++ UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ USHORT ListenIntv; ++ ULONG Timeout; ++ USHORT CapabilityInfo; ++ BOOLEAN TimerCancelled; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ ULONG tmp; ++ USHORT VarIesOffset; ++ UCHAR CkipFlag; ++ UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; ++ UCHAR AironetCkipIe = IE_AIRONET_CKIP; ++ UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; ++ UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; ++ UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; ++ UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; ++ USHORT Status; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block Assoc request durning WPA block period!\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ // check sanity first ++ else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); ++ ++ // Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() allocate memory failed \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ // Add by James 03/06/27 ++ pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ // Association don't need to report MAC address ++ pAd->StaCfg.AssocInfo.AvailableRequestFixedIEs = ++ NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL; ++ pAd->StaCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo; ++ pAd->StaCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv; ++ // Only reassociate need this ++ //COPY_MAC_ADDR(pAd->StaCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, ApAddr); ++ pAd->StaCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ ++ NdisZeroMemory(pAd->StaCfg.ReqVarIEs, MAX_VIE_LEN); ++ // First add SSID ++ VarIesOffset = 0; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SsidLen, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ VarIesOffset += pAd->MlmeAux.SsidLen; ++ ++ // Second add Supported rates ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SupRateIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SupRateLen, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.SupRate, pAd->MlmeAux.SupRateLen); ++ VarIesOffset += pAd->MlmeAux.SupRateLen; ++ // End Add by James ++ ++ if ((pAd->CommonCfg.Channel > 14) && ++ (pAd->CommonCfg.bIEEE80211H == TRUE)) ++ CapabilityInfo |= 0x0100; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send ASSOC request...\n")); ++ MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, ApAddr, ApAddr); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AssocHdr, ++ 2, &CapabilityInfo, ++ 2, &ListenIntv, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) ++ { ++ HtLen = SIZE_HT_CAP_IE + 4; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisZeroMemory(&HtCapabilityTmp, sizeof(HT_CAPABILITY_IE)); ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, pAd->MlmeAux.HtCapabilityLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen,&HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION ++ // Case I: (Aggregation + Piggy-Back) ++ // 1. user enable aggregation, AND ++ // 2. Mac support piggy-back ++ // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON ++ // Case II: (Aggregation) ++ // 1. user enable aggregation, AND ++ // 2. AP annouces it's AGGREGATION-capable in BEACON ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ } ++ else ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x06, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ ++ if (pAd->MlmeAux.APEdcaParm.bValid) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) ++ { ++ QBSS_STA_INFO_PARM QosInfo; ++ ++ NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); ++ QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; ++ QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; ++ QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; ++ QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; ++ QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; ++ WmeIe[8] |= *(PUCHAR)&QosInfo; ++ } ++ else ++ { ++ // The Parameter Set Count is set to ¡§0¡¨ in the association request frames ++ // WmeIe[8] |= (pAd->MlmeAux.APEdcaParm.EdcaUpdateCount & 0x0f); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 9, &WmeIe[0], ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // ++ // Let WPA(#221) Element ID on the end of this association frame. ++ // Otherwise some AP will fail on parsing Element ID and set status fail on Assoc Rsp. ++ // For example: Put Vendor Specific IE on the front of WPA IE. ++ // This happens on AP (Model No:Linksys WRK54G) ++ // ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ++ ) ++ ) ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ { ++ RSNIe = IE_WPA2; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP != 1) ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ ++ // Check for WPA PMK cache list ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ++ { ++ INT idx; ++ BOOLEAN FoundPMK = FALSE; ++ // Search chched PMKID, append it if existed ++ for (idx = 0; idx < PMKID_NO; idx++) ++ { ++ if (NdisEqualMemory(ApAddr, &pAd->StaCfg.SavedPMK[idx].BSSID, 6)) ++ { ++ FoundPMK = TRUE; ++ break; ++ } ++ } ++ ++ if (FoundPMK) ++ { ++ // Set PMK number ++ *(PUSHORT) &pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len] = 1; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len + 2], &pAd->StaCfg.SavedPMK[idx].PMKID, 16); ++ pAd->StaCfg.RSNIE_Len += 18; ++ } ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == 1) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ } ++ else ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ } ++ ++ FrameLen += tmp; ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP != 1) ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ // Append Variable IE ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->StaCfg.RSNIE_Len, 1); ++ VarIesOffset += 1; ++ } ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ VarIesOffset += pAd->StaCfg.RSNIE_Len; ++ ++ // Set Variable IEs Length ++ pAd->StaCfg.ReqVarIELen = VarIesOffset; ++ } ++ ++ // We have update that at PeerBeaconAtJoinRequest() ++ CkipFlag = pAd->StaCfg.CkipFlag; ++ if (CkipFlag != 0) ++ { ++ NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); ++ CkipNegotiationBuffer[2] = 0x66; ++ // Make it try KP & MIC, since we have to follow the result from AssocRsp ++ CkipNegotiationBuffer[8] = 0x18; ++ CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; ++ CkipFlag = 0x18; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCkipIe, ++ 1, &AironetCkipLen, ++ AironetCkipLen, CkipNegotiationBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // Add CCX v2 request if CCX2 admin state is on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ { ++ ++ // ++ // Add AironetIPAddressIE for Cisco CCX 2.X ++ // Add CCX Version ++ // ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetIPAddressIE, ++ 1, &AironetIPAddressLen, ++ AironetIPAddressLen, AironetIPAddressBuffer, ++ 1, &Ccx2Ie, ++ 1, &Ccx2Len, ++ Ccx2Len, Ccx2IeInfo, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // ++ // Add CipherSuite CCKM or LeapTkip if setting. ++ // ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCiscoCCKMLen, CipherSuiteCiscoCCKM, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // Third add RSN ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); //Save CipherSuite ++ VarIesOffset += CipherSuiteCiscoCCKMLen; ++ } ++ else if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCCXTkipLen, CipherSuiteCCXTkip, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // Third add RSN ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCCXTkip, CipherSuiteCCXTkipLen); ++ VarIesOffset += CipherSuiteCCXTkipLen; ++ } ++#endif // LEAP_SUPPORT // ++ ++ // Add by James 03/06/27 ++ // Set Variable IEs Length ++ pAd->StaCfg.ReqVarIELen = VarIesOffset; ++ pAd->StaCfg.AssocInfo.RequestIELength = VarIesOffset; ++ ++ // OffsetResponseIEs follow ReqVarIE ++ pAd->StaCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->StaCfg.ReqVarIELen; ++ // End Add by James ++ } ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AssocTimer, Timeout); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ mlme reassoc req handling procedure ++ Parameters: ++ Elem - ++ Pre: ++ -# SSID (Adapter->StaCfg.ssid[]) ++ -# BSSID (AP address, Adapter->StaCfg.bssid) ++ -# Supported rates (Adapter->StaCfg.supported_rates[]) ++ -# Supported rates length (Adapter->StaCfg.supported_rates_len) ++ -# Tx power (Adapter->StaCfg.tx_power) ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR ApAddr[6]; ++ HEADER_802_11 ReassocHdr; ++ UCHAR Ccx2Len = 5; ++ UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ USHORT CapabilityInfo, ListenIntv; ++ ULONG Timeout; ++ ULONG FrameLen = 0; ++ BOOLEAN TimerCancelled; ++ NDIS_STATUS NStatus; ++ ULONG tmp; ++ PUCHAR pOutBuffer = NULL; ++//CCX 2.X ++#ifdef LEAP_SUPPORT ++ UCHAR CkipFlag; ++ UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; ++ UCHAR AironetCkipIe = IE_AIRONET_CKIP; ++ UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; ++ UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; ++ UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; ++ UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; ++ UCHAR AironetCCKMReassocIE = IE_AIRONET_CCKMREASSOC; ++ UCHAR AironetCCKMReassocLen = AIRONET_CCKMREASSOC_LENGTH; ++ UCHAR AironetCCKMReassocBuffer[AIRONET_CCKMREASSOC_LENGTH]; ++ UCHAR AironetOUI[] = {0x00, 0x40, 0x96, 0x00}; ++ UCHAR MICMN[16]; ++ UCHAR CalcMicBuffer[80]; ++ ULONG CalcMicBufferLen = 0; ++#endif // LEAP_SUPPORT // ++ USHORT Status; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block ReAssoc request durning WPA block period!\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ // the parameters are the same as the association ++ else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() allocate memory failed \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); ++ ++ // make frame, use bssid as the AP address?? ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send RE-ASSOC request...\n")); ++ MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, ApAddr, ApAddr); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &ReassocHdr, ++ 2, &CapabilityInfo, ++ 2, &ListenIntv, ++ MAC_ADDR_LEN, ApAddr, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ if (pAd->MlmeAux.APEdcaParm.bValid) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) ++ { ++ QBSS_STA_INFO_PARM QosInfo; ++ ++ NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); ++ QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; ++ QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; ++ QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; ++ QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; ++ QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; ++ WmeIe[8] |= *(PUCHAR)&QosInfo; ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 9, &WmeIe[0], ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) ++ { ++ HtLen = SIZE_HT_CAP_IE + 4; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION ++ // Case I: (Aggregation + Piggy-Back) ++ // 1. user enable aggregation, AND ++ // 2. Mac support piggy-back ++ // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON ++ // Case II: (Aggregation) ++ // 1. user enable aggregation, AND ++ // 2. AP annouces it's AGGREGATION-capable in BEACON ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ } ++ else ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x04, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ CkipFlag = pAd->StaCfg.CkipFlag; // We have update that at PeerBeaconAtJoinRequest() ++ if (CkipFlag != 0) ++ { ++ NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); ++ CkipNegotiationBuffer[2] = 0x66; ++ // Make it try KP & MIC, since we have to follow the result from AssocRsp ++ CkipNegotiationBuffer[8] = 0x18; ++ CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCkipIe, ++ 1, &AironetCkipLen, ++ AironetCkipLen, CkipNegotiationBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetIPAddressIE, ++ 1, &AironetIPAddressLen, ++ AironetIPAddressLen, AironetIPAddressBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // ++ // The RN is incremented before each reassociation request. ++ // ++ pAd->StaCfg.CCKMRN++; ++ // ++ // Calculate MIC = hmac-md5(krk, STA-ID|BSSID|RSNIE|TSF|RN); ++ // ++ COPY_MAC_ADDR(CalcMicBuffer, pAd->CurrentAddress); ++ CalcMicBufferLen = MAC_ADDR_LEN; ++ COPY_MAC_ADDR(CalcMicBuffer + CalcMicBufferLen, pAd->MlmeAux.Bssid); ++ CalcMicBufferLen += MAC_ADDR_LEN; ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); ++ CalcMicBufferLen += CipherSuiteCiscoCCKMLen; ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR) &pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp)); ++ CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp); ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR)&pAd->StaCfg.CCKMRN, sizeof(pAd->StaCfg.CCKMRN)); ++ CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMRN); ++ hmac_md5(pAd->StaCfg.KRK, LEN_EAP_MICK, CalcMicBuffer, CalcMicBufferLen, MICMN); ++ ++ // ++ // fill up CCKM reassociation request element ++ // ++ NdisMoveMemory(AironetCCKMReassocBuffer, AironetOUI, 4); ++ NdisMoveMemory(AironetCCKMReassocBuffer + 4, (PUCHAR)&pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, 8); ++ NdisMoveMemory(AironetCCKMReassocBuffer + 12, (PUCHAR) &pAd->StaCfg.CCKMRN, 4); ++ NdisMoveMemory(AironetCCKMReassocBuffer +16, MICMN, 8); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCCKMReassocIE, ++ 1, &AironetCCKMReassocLen, ++ AironetCCKMReassocLen, AironetCCKMReassocBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCiscoCCKMLen,CipherSuiteCiscoCCKM, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++#endif // LEAP_SUPPORT // ++ ++ // Add CCX v2 request if CCX2 admin state is on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ { ++ // ++ // Add CCX Version ++ // ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &Ccx2Ie, ++ 1, &Ccx2Len, ++ Ccx2Len, Ccx2IeInfo, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.ReassocTimer, Timeout); /* in mSec */ ++ pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Upper layer issues disassoc request ++ Parameters: ++ Elem - ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PMLME_DISASSOC_REQ_STRUCT pDisassocReq; ++ HEADER_802_11 DisassocHdr; ++ PHEADER_802_11 pDisassocHdr; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ NDIS_STATUS NStatus; ++ BOOLEAN TimerCancelled; ++ ULONG Timeout = 0; ++ USHORT Status; ++ ++#ifdef QOS_DLS_SUPPORT ++ // send DLS-TEAR_DOWN message, ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ UCHAR i; ++ ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // skip sanity check ++ pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - MlmeDisassocReqAction() allocate memory failed\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ ++ ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &TimerCancelled); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send DISASSOC request[BSSID::%02x:%02x:%02x:%02x:%02x:%02x (Reason=%d)\n", ++ pDisassocReq->Addr[0], pDisassocReq->Addr[1], pDisassocReq->Addr[2], ++ pDisassocReq->Addr[3], pDisassocReq->Addr[4], pDisassocReq->Addr[5], pDisassocReq->Reason)); ++ MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pDisassocReq->Addr, pDisassocReq->Addr); // patch peap ttls switching issue ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DisassocHdr, ++ 2, &pDisassocReq->Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ // To patch Instance and Buffalo(N) AP ++ // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine ++ // Therefore, we send both of them. ++ pDisassocHdr = (PHEADER_802_11)pOutBuffer; ++ pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING; ++ COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr); ++ ++ RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */ ++ pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends assoc rsp back ++ Parameters: ++ Elme - MLME message containing the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAssocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo, Status, Aid; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BOOLEAN TimerCancelled; ++ UCHAR CkipFlag; ++ EDCA_PARM EdcaParm; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, ++ &HtCapability,&AddHtInfo, &HtCapabilityLen,&AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) ++ { ++ // The frame is for me ? ++ if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status)); ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++#endif // DOT11_N_SUPPORT // ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); ++ if(Status == MLME_SUCCESS) ++ { ++ // go to procedure listed on page 376 ++ AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ if (CkipFlag & 0x18) ++ { ++ NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); ++ pAd->StaCfg.GIV[0] = RandomByte(pAd); ++ pAd->StaCfg.GIV[1] = RandomByte(pAd); ++ pAd->StaCfg.GIV[2] = RandomByte(pAd); ++ pAd->StaCfg.bCkipOn = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); ++ } ++ } ++ else ++ { ++ // Faile on Association, we need to check the status code ++ // Is that a Rogue AP? ++#ifdef LEAP_SUPPORT ++ if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (Status == MLME_ALG_NOT_SUPPORT)) ++ { //Possibly Rogue AP ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, pAd->MlmeAux.Bssid, LEAP_REASON_INVALID_AUTH); ++ } ++#endif // LEAP_SUPPORT // ++ } ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerAssocRspAction() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends reassoc rsp ++ Parametrs: ++ Elem - MLME message cntaining the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerReassocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo; ++ USHORT Status; ++ USHORT Aid; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR CkipFlag; ++ BOOLEAN TimerCancelled; ++ EDCA_PARM EdcaParm; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, ++ &HtCapability, &AddHtInfo, &HtCapabilityLen, &AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) ++ { ++ if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) // The frame is for me ? ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status)); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); ++ ++ if(Status == MLME_SUCCESS) ++ { ++ // go to procedure listed on page 376 ++ AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ } ++ ++ // ++ // Cisco Leap CCKM supported Re-association. ++ // ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ if (CCKMAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen) == TRUE) ++ { ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ if (CkipFlag & 0x18) ++ { ++ NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); ++ pAd->StaCfg.GIV[0] = RandomByte(pAd); ++ pAd->StaCfg.GIV[1] = RandomByte(pAd); ++ pAd->StaCfg.GIV[2] = RandomByte(pAd); ++ pAd->StaCfg.bCkipOn = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); ++ } ++ ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - CCKMAssocRspSanity() sanity check fail\n")); ++ } ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ // CkipFlag is no use for reassociate ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerReassocRspAction() sanity check fail\n")); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ procedures on IEEE 802.11/1999 p.376 ++ Parametrs: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocPostProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr2, ++ IN USHORT CapabilityInfo, ++ IN USHORT Aid, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN PEDCA_PARM pEdcaParm, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN ADD_HT_INFO_IE *pAddHtInfo) // AP might use this additional ht info IE ++{ ++ ULONG Idx; ++ ++ pAd->MlmeAux.BssType = BSS_INFRA; ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2); ++ pAd->MlmeAux.Aid = Aid; ++ pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; ++#ifdef DOT11_N_SUPPORT ++ // Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. ++ if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) ++ { ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->Aifsn[0] = 3; ++ pEdcaParm->Aifsn[1] = 7; ++ pEdcaParm->Aifsn[2] = 2; ++ pEdcaParm->Aifsn[3] = 2; ++ ++ pEdcaParm->Cwmin[0] = 4; ++ pEdcaParm->Cwmin[1] = 4; ++ pEdcaParm->Cwmin[2] = 3; ++ pEdcaParm->Cwmin[3] = 2; ++ ++ pEdcaParm->Cwmax[0] = 10; ++ pEdcaParm->Cwmax[1] = 10; ++ pEdcaParm->Cwmax[2] = 4; ++ pEdcaParm->Cwmax[3] = 3; ++ ++ pEdcaParm->Txop[0] = 0; ++ pEdcaParm->Txop[1] = 0; ++ pEdcaParm->Txop[2] = 96; ++ pEdcaParm->Txop[3] = 48; ++ ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ ++ // filter out un-supported rates ++ pAd->MlmeAux.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ ++ // filter out un-supported rates ++ pAd->MlmeAux.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++ ++#ifdef DOT11_N_SUPPORT ++ if (HtCapabilityLen > 0) ++ { ++ RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> AP.AMsduSize = %d. ClientStatusFlags = 0x%lx \n", pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n", ++ pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize)); ++#endif // DOT11_N_SUPPORT // ++ ++ // Set New WPA information ++ Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); ++ if (Idx == BSS_NOT_FOUND) ++ { ++ DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n")); ++ } ++ else ++ { ++ // Init variable ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0; ++ NdisZeroMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, MAX_LEN_OF_RSNIE); ++ ++ // Store appropriate RSN_IE for WPA SM negotiation later ++ if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAd->ScanTab.BssEntry[Idx].VarIELen != 0)) ++ { ++ PUCHAR pVIE; ++ USHORT len; ++ PEID_STRUCT pEid; ++ ++ pVIE = pAd->ScanTab.BssEntry[Idx].VarIEs; ++ len = pAd->ScanTab.BssEntry[Idx].VarIELen; ++ ++ while (len > 0) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // For WPA/WPAPSK ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA SM negotiation \n")); ++ } ++ // For WPA2/WPA2PSK ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA2 SM negotiation \n")); ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ } ++ ++ if (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> no RSN_IE \n")); ++ } ++ else ++ { ++ hex_dump("RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ left part of IEEE 802.11/1999 p.374 ++ Parameters: ++ Elem - MLME message containing the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDisassocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Reason; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction()\n")); ++ if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() Reason = %d\n", Reason)); ++ if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, Addr2)) ++ { ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ // Cisco_LEAP has start a timer ++ // We should cancel it if using LEAP ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); ++ //Check is it mach the LEAP Authentication failed as possible a Rogue AP ++ //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Association. ++ if ((pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE) && (pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); ++ } ++ } ++#endif // LEAP_SUPPORT // ++ // ++ // Get Current System time and Turn on AdjacentAPReport ++ // ++ NdisGetSystemUpTime(&pAd->StaCfg.CCXAdjacentAPLinkDownTime); ++ pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; ++ LinkDown(pAd, TRUE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() sanity check fail\n")); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after assoc timeout ++ Parameters: ++ Elme - ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - AssocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after reassoc timeout ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ReassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - ReassocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after disassoc timeout ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID DisassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - DisassocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenAssoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenAssoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenReassoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenReassoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenDisassociate( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenDisassoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ right part of IEEE 802.11/1999 page 374 ++ Note: ++ This event should never cause ASSOC state machine perform state ++ transition, and has no relationship with CNTL machine. So we separate ++ this routine as a service outside of ASSOC state transition table. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID Cls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr) ++{ ++ HEADER_802_11 DisassocHdr; ++ PHEADER_802_11 pDisassocHdr; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ NDIS_STATUS NStatus; ++ USHORT Reason = REASON_CLS3ERR; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Class 3 Error, Send DISASSOC frame\n")); ++ MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, pAd->CommonCfg.Bssid); // patch peap ttls switching issue ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DisassocHdr, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ // To patch Instance and Buffalo(N) AP ++ // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine ++ // Therefore, we send both of them. ++ pDisassocHdr = (PHEADER_802_11)pOutBuffer; ++ pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DisassocReason = REASON_CLS3ERR; ++ COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pAddr); ++} ++ ++ /* ++ ========================================================================== ++ Description: ++ Switch between WEP and CKIP upon new association up. ++ Parameters: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID SwitchBetweenWepAndCkip( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ // if KP is required. change the CipherAlg in hardware shard key table from WEP ++ // to CKIP. else remain as WEP ++ if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10)) ++ { ++ // modify hardware key table so that MAC use correct algorithm to decrypt RX ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); ++ if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP128; ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); ++ ++ // modify software key table so that driver can specify correct algorithm in TXD upon TX ++ for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_WEP64) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP64; ++ else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP128) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP128; ++ } ++ } ++ ++ // else if KP NOT inused. change the CipherAlg in hardware shard key table from CKIP ++ // to WEP. ++ else ++ { ++ // modify hardware key table so that MAC use correct algorithm to decrypt RX ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); ++ if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_WEP128; ++ ++ // modify software key table so that driver can specify correct algorithm in TXD upon TX ++ for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_CKIP64) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP64; ++ else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP128) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP128; ++ } ++ ++ // ++ // On WPA-NONE, must update CipherAlg. ++ // Because the OID_802_11_WEP_STATUS was been set after OID_802_11_ADD_KEY ++ // and CipherAlg will be CIPHER_NONE by Windows ZeroConfig. ++ // So we need to update CipherAlg after connect. ++ // ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ if (pAd->SharedKey[BSS0][i].KeyLen != 0) ++ { ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_TKIP; ++ } ++ else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_AES; ++ } ++ } ++ else ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; ++ } ++ } ++ ++ csr1.field.Bss0Key0CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ csr1.field.Bss0Key1CipherAlg = pAd->SharedKey[BSS0][1].CipherAlg; ++ csr1.field.Bss0Key2CipherAlg = pAd->SharedKey[BSS0][2].CipherAlg; ++ csr1.field.Bss0Key3CipherAlg = pAd->SharedKey[BSS0][3].CipherAlg; ++ } ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); ++ } ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++VOID SendAssocIEsToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd) ++{ ++ union iwreq_data wrqu; ++ unsigned char custom[IW_CUSTOM_MAX] = {0}; ++ ++ if ((pAd->StaCfg.ReqVarIELen + 17) <= IW_CUSTOM_MAX) ++ { ++ sprintf(custom, "ASSOCINFO_ReqIEs="); ++ NdisMoveMemory(custom+17, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = pAd->StaCfg.ReqVarIELen + 17; ++ wrqu.data.flags = RT_REQIE_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOCINFO_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen + 17 > MAX_CUSTOM_LEN\n")); ++ ++ return; ++} ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++int wext_notify_event_assoc( ++ IN RTMP_ADAPTER *pAd) ++{ ++ union iwreq_data wrqu; ++ char custom[IW_CUSTOM_MAX] = {0}; ++ ++#if WIRELESS_EXT > 17 ++ if (pAd->StaCfg.ReqVarIELen <= IW_CUSTOM_MAX) ++ { ++ wrqu.data.length = pAd->StaCfg.ReqVarIELen; ++ memcpy(custom, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); ++ wireless_send_event(pAd->net_dev, IWEVASSOCREQIE, &wrqu, custom); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen > MAX_CUSTOM_LEN\n")); ++#else ++ if (((pAd->StaCfg.ReqVarIELen*2) + 17) <= IW_CUSTOM_MAX) ++ { ++ UCHAR idx; ++ wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17; ++ sprintf(custom, "ASSOCINFO(ReqIEs="); ++ for (idx=0; idxStaCfg.ReqVarIELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAd->StaCfg.ReqVarIEs[idx]); ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("(pAd->StaCfg.ReqVarIELen*2) + 17 > MAX_CUSTOM_LEN\n")); ++#endif ++ ++ return 0; ++ ++} ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/auth.c +@@ -0,0 +1,474 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ auth.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-9-3 porting from RT2500 ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ authenticate state machine init, including state transition and timer init ++ Parameters: ++ Sm - pointer to the auth state machine ++ Note: ++ The state machine looks like this ++ ++ AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4 ++ MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth ++ MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action ++ MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++ ++void AuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE); ++ ++ // the first column ++ StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction); ++ ++ // the second column ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); ++ ++ // the third column ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); ++ ++ RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ function to be executed at timer thread when auth timer expires ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n")); ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ // send a de-auth to reset AP's state machine (Patch AP-Dir635) ++ if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2) ++ Cls2errAction(pAd, pAd->MlmeAux.Bssid); ++ ++ ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeAuthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr[6]; ++ USHORT Alg, Seq, Status; ++ ULONG Timeout; ++ HEADER_802_11 AuthHdr; ++ BOOLEAN TimerCancelled; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg)) ++ { ++ // reset timer ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr); ++ pAd->MlmeAux.Alg = Alg; ++ Seq = 1; ++ Status = MLME_SUCCESS; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg)); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg)); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&AuthHdr, ++ 2, &Alg, ++ 2, &Seq, ++ 2, &Status, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; ++ } ++ else ++ { ++ DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAuthRspAtSeq2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Seq, Status, RemoteStatus, Alg; ++ UCHAR ChlgText[CIPHER_TEXT_LEN]; ++ UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; ++ UCHAR Element[2]; ++ HEADER_802_11 AuthHdr; ++ BOOLEAN TimerCancelled; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Status2; ++ ++ if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) ++ { ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status)); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ ++ if (Status == MLME_SUCCESS) ++ { ++ // Authentication Mode "LEAP" has allow for CCX 1.X ++ if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ { ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++#ifdef LEAP_SUPPORT ++ pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE; ++#endif // LEAP_SUPPORT // ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ else ++ { ++ // 2. shared key, need to be challenged ++ Seq++; ++ RemoteStatus = MLME_SUCCESS; ++ ++ // Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status2 = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n")); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid); ++ AuthHdr.FC.Wep = 1; ++ // Encrypt challenge text & auth information ++ RTMPInitWepEngine( ++ pAd, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen, ++ CyperChlgText); ++ ++ Alg = cpu2le16(*(USHORT *)&Alg); ++ Seq = cpu2le16(*(USHORT *)&Seq); ++ RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus); ++ ++ RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2); ++ RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2); ++ RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2); ++ Element[0] = 16; ++ Element[1] = 128; ++ RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2); ++ RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128); ++ RTMPSetICV(pAd, CyperChlgText + 140); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AuthHdr, ++ CIPHER_TEXT_LEN + 16, CyperChlgText, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; ++ } ++ } ++ else ++ { ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ //Invalid Authentication possible rogue AP ++ //Add this Ap to Rogue AP. ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH); ++ } ++#endif // LEAP_SUPPORT // ++ pAd->StaCfg.AuthFailReason = Status; ++ COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAuthRspAtSeq4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Alg, Seq, Status; ++ CHAR ChlgText[CIPHER_TEXT_LEN]; ++ BOOLEAN TimerCancelled; ++ ++ if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) ++ { ++ if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n")); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ ++ if (Status != MLME_SUCCESS) ++ { ++ pAd->StaCfg.AuthFailReason = Status; ++ COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); ++ } ++ ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ HEADER_802_11 DeauthHdr; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Status; ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason)); ++ MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DeauthHdr, ++ 2, &pInfo->Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DeauthReason = pInfo->Reason; ++ COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); ++ ++ // send wireless event - for deauthentication ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID InvalidStateWhenAuth( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState)); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Some STA/AP ++ Note: ++ This action should never trigger AUTH state transition, therefore we ++ separate it from AUTH state machine, and make it as a standalone service ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID Cls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr) ++{ ++ HEADER_802_11 DeauthHdr; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Reason = REASON_CLS2ERR; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n")); ++ MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DeauthHdr, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DeauthReason = Reason; ++ COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/auth_rsp.c +@@ -0,0 +1,167 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ auth_rsp.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-10-1 copy from RT2560 ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ authentication state machine init procedure ++ Parameters: ++ Sm - the state machine ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE); ++ ++ // column 1 ++ StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); ++ ++ // column 2 ++ StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID PeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT Reason, ++ IN USHORT Status) ++{ ++ HEADER_802_11 AuthHdr; ++ ULONG FrameLen = 0; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ++ if (Reason != MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Peer AUTH fail...\n")); ++ return; ++ } ++ ++ //Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send AUTH response (seq#2)...\n")); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, pHdr80211->Addr2, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AuthHdr, ++ 2, &Alg, ++ 2, &Seq, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID PeerDeauthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMLME_QUEUE_ELEM Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Reason; ++ ++ if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) ++ { ++ if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(Addr2, pAd->CommonCfg.Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason)); ++ ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ ++ // send wireless event - for deauthentication ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ LinkDown(pAd, TRUE); ++ ++ // Authentication Mode Cisco_LEAP has start a timer ++ // We should cancel it if using LEAP ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); ++ //Check is it mach the LEAP Authentication failed as possible a Rogue AP ++ //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Authenticaton. ++ if ((pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED) && (pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE)) ++ { ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); ++ } ++ } ++#endif // LEAP_SUPPORT // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - PeerDeauthAction() sanity check fail\n")); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/connect.c +@@ -0,0 +1,2751 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ connect.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-08-08 Major modification from RT2560 ++*/ ++#include "../rt_config.h" ++ ++UCHAR CipherSuiteWpaNoneTkip[] = { ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x00 // authentication ++ }; ++UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteWpaNoneAes[] = { ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x04, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x04, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x00 // authentication ++ }; ++UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR)); ++ ++// The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS, ++// or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS ++// All settings successfuly negotiated furing MLME state machines become final settings ++// and are copied to pAd->StaActive ++#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ ++{ \ ++ (_pAd)->CommonCfg.SsidLen = (_pAd)->MlmeAux.SsidLen; \ ++ NdisMoveMemory((_pAd)->CommonCfg.Ssid, (_pAd)->MlmeAux.Ssid, (_pAd)->MlmeAux.SsidLen); \ ++ COPY_MAC_ADDR((_pAd)->CommonCfg.Bssid, (_pAd)->MlmeAux.Bssid); \ ++ (_pAd)->CommonCfg.Channel = (_pAd)->MlmeAux.Channel; \ ++ (_pAd)->CommonCfg.CentralChannel = (_pAd)->MlmeAux.CentralChannel; \ ++ (_pAd)->StaActive.Aid = (_pAd)->MlmeAux.Aid; \ ++ (_pAd)->StaActive.AtimWin = (_pAd)->MlmeAux.AtimWin; \ ++ (_pAd)->StaActive.CapabilityInfo = (_pAd)->MlmeAux.CapabilityInfo; \ ++ (_pAd)->CommonCfg.BeaconPeriod = (_pAd)->MlmeAux.BeaconPeriod; \ ++ (_pAd)->StaActive.CfpMaxDuration = (_pAd)->MlmeAux.CfpMaxDuration; \ ++ (_pAd)->StaActive.CfpPeriod = (_pAd)->MlmeAux.CfpPeriod; \ ++ (_pAd)->StaActive.SupRateLen = (_pAd)->MlmeAux.SupRateLen; \ ++ NdisMoveMemory((_pAd)->StaActive.SupRate, (_pAd)->MlmeAux.SupRate, (_pAd)->MlmeAux.SupRateLen);\ ++ (_pAd)->StaActive.ExtRateLen = (_pAd)->MlmeAux.ExtRateLen; \ ++ NdisMoveMemory((_pAd)->StaActive.ExtRate, (_pAd)->MlmeAux.ExtRate, (_pAd)->MlmeAux.ExtRateLen);\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APEdcaParm, &(_pAd)->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APQosCapability, &(_pAd)->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APQbssLoad, &(_pAd)->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));\ ++ COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].Addr, (_pAd)->MlmeAux.Bssid); \ ++ (_pAd)->MacTab.Content[BSSID_WCID].Aid = (_pAd)->MlmeAux.Aid; \ ++ (_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = (_pAd)->StaCfg.PairCipher;\ ++ COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.BssId, (_pAd)->MlmeAux.Bssid);\ ++ (_pAd)->MacTab.Content[BSSID_WCID].RateLen = (_pAd)->StaActive.SupRateLen + (_pAd)->StaActive.ExtRateLen;\ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++*/ ++VOID MlmeCntlInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ // Control state machine differs from other state machines, the interface ++ // follows the standard interface ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID MlmeCntlMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ switch(pAd->Mlme.CntlMachine.CurrState) ++ { ++ case CNTL_IDLE: ++ { ++ CntlIdleProc(pAd, Elem); ++ } ++ break; ++ case CNTL_WAIT_DISASSOC: ++ CntlWaitDisassocProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_JOIN: ++ CntlWaitJoinProc(pAd, Elem); ++ break; ++ ++ // CNTL_WAIT_REASSOC is the only state in CNTL machine that does ++ // not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". ++ // Therefore not protected by NDIS's "only one outstanding OID request" ++ // rule. Which means NDIS may SET OID in the middle of ROAMing attempts. ++ // Current approach is to block new SET request at RTMPSetInformation() ++ // when CntlMachine.CurrState is not CNTL_IDLE ++ case CNTL_WAIT_REASSOC: ++ CntlWaitReassocProc(pAd, Elem); ++ break; ++ ++ case CNTL_WAIT_START: ++ CntlWaitStartProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_AUTH: ++ CntlWaitAuthProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_AUTH2: ++ CntlWaitAuthProc2(pAd, Elem); ++ break; ++ case CNTL_WAIT_ASSOC: ++ CntlWaitAssocProc(pAd, Elem); ++ break; ++ ++ case CNTL_WAIT_OID_LIST_SCAN: ++ if(Elem->MsgType == MT2_SCAN_CONF) ++ { ++ // Resume TxRing after SCANING complete. We hope the out-of-service time ++ // won't be too long to let upper layer time-out the waiting frames ++ RTMPResumeMsduTransmission(pAd); ++ if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) ++ { ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ ++ // ++ // Set LED status to previous status. ++ // ++ if (pAd->bLedOnScanning) ++ { ++ pAd->bLedOnScanning = FALSE; ++ RTMPSetLED(pAd, pAd->LedStatus); ++ } ++#ifdef DOT11N_DRAFT3 ++ // AP sent a 2040Coexistence mgmt frame, then station perform a scan, and then send back the respone. ++ if (pAd->CommonCfg.BSSCoexist2040.field.InfoReq == 1) ++ { ++ Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); ++ } ++#endif // DOT11N_DRAFT3 // ++ } ++ break; ++ ++ case CNTL_WAIT_OID_DISASSOC: ++ if (Elem->MsgType == MT2_DISASSOC_CONF) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++ break; ++ default: ++ DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType)); ++ break; ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlIdleProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ switch(Elem->MsgType) ++ { ++ case OID_802_11_SSID: ++ CntlOidSsidProc(pAd, Elem); ++ break; ++ ++ case OID_802_11_BSSID: ++ CntlOidRTBssidProc(pAd,Elem); ++ break; ++ ++ case OID_802_11_BSSID_LIST_SCAN: ++ CntlOidScanProc(pAd,Elem); ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAd->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ } ++ break; ++ ++ case MT2_MLME_ROAMING_REQ: ++ CntlMlmeRoamingProc(pAd, Elem); ++ break; ++ ++ case OID_802_11_MIC_FAILURE_REPORT_FRAME: ++ WpaMicFailureReportFrame(pAd, Elem); ++ break; ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS_PARAM: ++ CntlOidDLSSetupProc(pAd, Elem); ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType)); ++ break; ++ } ++} ++ ++VOID CntlOidScanProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ULONG BssIdx = BSS_NOT_FOUND; ++ BSS_ENTRY CurrBss; ++ ++#ifdef RALINK_ATE ++/* Disable scanning when ATE is running. */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++ // record current BSS if network is connected. ++ // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ BssIdx = BssSsidTableSearch(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->CommonCfg.Channel); ++ if (BssIdx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(&CurrBss, &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); ++ } ++ } ++ ++ // clean up previous SCAN result, add current BSS back to table if any ++ BssTableInit(&pAd->ScanTab); ++ if (BssIdx != BSS_NOT_FOUND) ++ { ++ // DDK Note: If the NIC is associated with a particular BSSID and SSID ++ // that are not contained in the list of BSSIDs generated by this scan, the ++ // BSSID description of the currently associated BSSID and SSID should be ++ // appended to the list of BSSIDs in the NIC's database. ++ // To ensure this, we append this BSS as the first entry in SCAN result ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY)); ++ pAd->ScanTab.BssNr = 1; ++ } ++ ++ ScanParmFill(pAd, &ScanReq, "", 0, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, ++ sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Before calling this routine, user desired SSID should already been ++ recorded in CommonCfg.Ssid[] ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidSsidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem) ++{ ++ PNDIS_802_11_SSID pOidSsid = (NDIS_802_11_SSID *)Elem->Msg; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ULONG Now; ++ ++ // Step 1. record the desired user settings to MlmeAux ++ NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength); ++ pAd->MlmeAux.SsidLen = (UCHAR)pOidSsid->SsidLength; ++ NdisZeroMemory(pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ pAd->MlmeAux.BssType = pAd->StaCfg.BssType; ++ ++ ++ // ++ // Update Reconnect Ssid, that user desired to connect. ++ // ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; ++ ++ // step 2. find all matching BSS in the lastest SCAN result (inBssTab) ++ // & log them into MlmeAux.SsidBssTab for later-on iteration. Sort by RSSI order ++ BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - %d BSS of %d BSS match the desire (%d)SSID - %s\n", ++ pAd->MlmeAux.SsidBssTab.BssNr, pAd->ScanTab.BssNr, pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid)); ++ NdisGetSystemUpTime(&Now); ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ (pAd->CommonCfg.SsidLen == pAd->MlmeAux.SsidBssTab.BssEntry[0].SsidLen) && ++ NdisEqualMemory(pAd->CommonCfg.Ssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Ssid, pAd->CommonCfg.SsidLen) && ++ MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Bssid)) ++ { ++ // Case 1. already connected with an AP who has the desired SSID ++ // with highest RSSI ++ ++ // Add checking Mode "LEAP" for CCX 1.0 ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ // case 1.1 For WPA, WPA-PSK, if the 1x port is not secured, we have to redo ++ // connection process ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else if (pAd->bConfigChanged == TRUE) ++ { ++ // case 1.2 Important Config has changed, we have to reconnect to the same AP ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP Because config changed...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ // case 1.3. already connected to the SSID with highest RSSI. ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - already with this BSSID. ignore this SET_SSID request\n")); ++ // ++ // (HCT 12.1) 1c_wlan_mediaevents required ++ // media connect events are indicated when associating with the same AP ++ // ++ if (INFRA_ON(pAd)) ++ { ++ // ++ // Since MediaState already is NdisMediaStateConnected ++ // We just indicate the connect event again to meet the WHQL required. ++ // ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up ++ } ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ else if (INFRA_ON(pAd)) ++ { ++ // ++ // For RT61 ++ // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) ++ // RT61 may lost SSID, and not connect to NDTEST_WEP_AP2 and will connect to NDTEST_WEP_AP2 by Autoreconnect ++ // But media status is connected, so the SSID not report correctly. ++ // ++ if (!SSID_EQUAL(pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen)) ++ { ++ // ++ // Different SSID means not Roaming case, so we let LinkDown() to Indicate a disconnect event. ++ // ++ pAd->MlmeAux.CurrReqIsFromNdis = TRUE; ++ } ++ // case 2. active INFRA association existent ++ // roaming is done within miniport driver, nothing to do with configuration ++ // utility. so upon a new SET(OID_802_11_SSID) is received, we just ++ // disassociate with the current associated AP, ++ // then perform a new association with this new SSID, no matter the ++ // new/old SSID are the same or not. ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ if (ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - drop current ADHOC\n")); ++ LinkDown(pAd, FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); ++ } ++ ++ if ((pAd->MlmeAux.SsidBssTab.BssNr == 0) && ++ (pAd->StaCfg.bAutoReconnect == TRUE) && ++ (pAd->MlmeAux.BssType == BSS_INFRA) && ++ (MlmeValidateSSID(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen) == TRUE) ++ ) ++ { ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - No matching BSS, start a new scan\n")); ++ ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ // Reset Missed scan number ++ pAd->StaCfg.LastScanTime = Now; ++ } ++ else ++ { ++ pAd->MlmeAux.BssIdx = 0; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidRTBssidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem) ++{ ++ ULONG BssIdx; ++ PUCHAR pOidBssid = (PUCHAR)Elem->Msg; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ MLME_JOIN_REQ_STRUCT JoinReq; ++ ++#ifdef RALINK_ATE ++/* No need to perform this routine when ATE is running. */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ // record user desired settings ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid); ++ pAd->MlmeAux.BssType = pAd->StaCfg.BssType; ++ ++ // ++ // Update Reconnect Ssid, that user desired to connect. ++ // ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ ++ // find the desired BSS in the latest SCAN result table ++ BssIdx = BssTableSearch(&pAd->ScanTab, pOidBssid, pAd->MlmeAux.Channel); ++ if (BssIdx == BSS_NOT_FOUND) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ return; ++ } ++ ++ // copy the matched BSS entry from ScanTab to MlmeAux.SsidBssTab. Why? ++ // Because we need this entry to become the JOIN target in later on SYNC state machine ++ pAd->MlmeAux.BssIdx = 0; ++ pAd->MlmeAux.SsidBssTab.BssNr = 1; ++ NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); ++ ++ // 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP ++ // we just follow normal procedure. The reason of user doing this may because he/she changed ++ // AP to another channel, but we still received BEACON from it thus don't claim Link Down. ++ // Since user knows he's changed AP channel, he'll re-connect again. By skipping the following ++ // checking, we'll disassociate then re-do normal association with this AP at the new channel. ++ // 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do ++ // connection when setting the same BSSID. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pOidBssid)) ++ { ++ // already connected to the same BSSID, go back to idle state directly ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ else ++ { ++ if (INFRA_ON(pAd)) ++ { ++ // disassoc from current AP first ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - disassociate with current AP ...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ if (ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n")); ++ LinkDown(pAd, FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); ++ } ++ ++ // Change the wepstatus to original wepstatus ++ pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ // Set the Pairwise and Group cipher to match the intended AP setting ++ // We can only connect to AP with less secured cipher setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher; ++ else if (pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher; ++ else if (pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ ++ // RSN capability ++ pAd->StaCfg.RsnCapability = pAd->ScanTab.BssEntry[BssIdx].WPA2.RsnCapability; ++ } ++ ++ // Set Mix cipher flag ++ pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; ++ if (pAd->StaCfg.bMixCipher == TRUE) ++ { ++ // If mix cipher, re-build RSNIE ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ } ++ // No active association, join the BSS immediately ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pOidBssid[0],pOidBssid[1],pOidBssid[2],pOidBssid[3],pOidBssid[4],pOidBssid[5])); ++ ++ JoinParmFill(pAd, &JoinReq, pAd->MlmeAux.BssIdx); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; ++ } ++ } ++} ++ ++// Roaming is the only external request triggering CNTL state machine ++// despite of other "SET OID" operation. All "SET OID" related oerations ++// happen in sequence, because no other SET OID will be sent to this device ++// until the the previous SET operation is complete (successful o failed). ++// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? ++// or been corrupted by other "SET OID"? ++// ++// IRQL = DISPATCH_LEVEL ++VOID CntlMlmeRoamingProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ // TODO: ++ // AP in different channel may show lower RSSI than actual value?? ++ // should we add a weighting factor to compensate it? ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - Roaming in MlmeAux.RoamTab...\n")); ++ ++ NdisMoveMemory(&pAd->MlmeAux.SsidBssTab, &pAd->MlmeAux.RoamTab, sizeof(pAd->MlmeAux.RoamTab)); ++ pAd->MlmeAux.SsidBssTab.BssNr = pAd->MlmeAux.RoamTab.BssNr; ++ ++ BssTableSortByRssi(&pAd->MlmeAux.SsidBssTab); ++ pAd->MlmeAux.BssIdx = 0; ++ IterateOnBssTab(pAd); ++} ++ ++#ifdef QOS_DLS_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidDLSSetupProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRT_802_11_DLS pDLS = (PRT_802_11_DLS)Elem->Msg; ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ INT i; ++ USHORT reason = REASON_UNSPECIFY; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - (OID set %02x:%02x:%02x:%02x:%02x:%02x with Valid=%d, Status=%d, TimeOut=%d, CountDownTimer=%d)\n", ++ pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5], ++ pDLS->Valid, pDLS->Status, pDLS->TimeOut, pDLS->CountDownTimer)); ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ // DLS will not be supported when Adhoc mode ++ if (INFRA_ON(pAd)) ++ { ++ for (i = 0; i < MAX_NUM_OF_DLS_ENTRY; i++) ++ { ++ if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ (pDLS->TimeOut == pAd->StaCfg.DLSEntry[i].TimeOut) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 1. Same setting, just drop it ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - setting unchanged\n")); ++ break; ++ } ++ else if (!pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 2. Disable DLS link case, just tear down DLS link ++ reason = REASON_QOS_UNWANTED_MECHANISM; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - start tear down procedure\n")); ++ break; ++ } ++ else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && !pAd->StaCfg.DLSEntry[i].Valid) ++ { ++ // 3. Enable case, start DLS setup procedure ++ NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); ++ ++ //Update countdown timer ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS setup case\n")); ++ break; ++ } ++ else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && !MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 4. update mac case, tear down old DLS and setup new DLS ++ reason = REASON_QOS_UNWANTED_MECHANISM; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS tear down and restart case\n")); ++ break; ++ } ++ else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr) && (pAd->StaCfg.DLSEntry[i].TimeOut != pDLS->TimeOut)) ++ { ++ // 5. update timeout case, start DLS setup procedure (no tear down) ++ pAd->StaCfg.DLSEntry[i].TimeOut = pDLS->TimeOut; ++ //Update countdown timer ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS update timeout case\n")); ++ break; ++ } ++ else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ (pAd->StaCfg.DLSEntry[i].Status != DLS_FINISH) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 6. re-setup case, start DLS setup procedure (no tear down) ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS retry setup procedure\n")); ++ break; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN,("CNTL - DLS not changed in entry - %d - Valid=%d, Status=%d, TimeOut=%d\n", ++ i, pAd->StaCfg.DLSEntry[i].Valid, pAd->StaCfg.DLSEntry[i].Status, pAd->StaCfg.DLSEntry[i].TimeOut)); ++ } ++ } ++ } ++} ++#endif // QOS_DLS_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitDisassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_START_REQ_STRUCT StartReq; ++ ++ if (Elem->MsgType == MT2_DISASSOC_CONF) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Dis-associate successful\n")); ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ LinkDown(pAd, FALSE); ++ ++ // case 1. no matching BSS, and user wants ADHOC, so we just start a new one ++ if ((pAd->MlmeAux.SsidBssTab.BssNr==0) && (pAd->StaCfg.BssType == BSS_ADHOC)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ // case 2. try each matched BSS ++ else ++ { ++ pAd->MlmeAux.BssIdx = 0; ++ ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitJoinProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_JOIN_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ // 1. joined an IBSS, we are pretty much done here ++ if (pAd->MlmeAux.BssType == BSS_ADHOC) ++ { ++ // ++ // 5G bands rules of Japan: ++ // Ad hoc must be disabled in W53(ch52,56,60,64) channels. ++ // ++ if ( (pAd->CommonCfg.bIEEE80211H == 1) && ++ RadarChannelCheck(pAd, pAd->CommonCfg.Channel) ++ ) ++ { ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Join adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); ++ return; ++ } ++ ++ LinkUp(pAd, BSS_ADHOC); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - join the IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ } ++ // 2. joined a new INFRA network, start from authentication ++ else ++ { ++#ifdef LEAP_SUPPORT ++ // Add AuthMode "LEAP" for CCX 1.X ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); ++ } ++ else ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ } ++ } ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH; ++ } ++ } ++ else ++ { ++ // 3. failed, try next BSS ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitStartProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Result; ++ ++ if (Elem->MsgType == MT2_START_CONF) ++ { ++ NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); ++ if (Result == MLME_SUCCESS) ++ { ++ // ++ // 5G bands rules of Japan: ++ // Ad hoc must be disabled in W53(ch52,56,60,64) channels. ++ // ++ if ( (pAd->CommonCfg.bIEEE80211H == 1) && ++ RadarChannelCheck(pAd, pAd->CommonCfg.Channel) ++ ) ++ { ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); ++ return; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ N_ChannelCheck(pAd); ++ SetCommonHT(pAd); ++ NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &pAd->CommonCfg.AddHTInfo, sizeof(ADD_HT_INFO_IE)); ++ RTMPCheckHt(pAd, BSSID_WCID, &pAd->CommonCfg.HtCapability, &pAd->CommonCfg.AddHTInfo); ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ NdisZeroMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], 16); ++ NdisMoveMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], &pAd->CommonCfg.HtCapability.MCSSet[0], 16); ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ ++ if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) ++ { ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) ++ { ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ } ++ LinkUp(pAd, BSS_ADHOC); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ // Before send beacon, driver need do radar detection ++ if ((pAd->CommonCfg.Channel > 14 ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE; ++ pAd->CommonCfg.RadarDetect.RDCount = 0; ++#ifdef DFS_SUPPORT ++ BbpRadarDetectionStart(pAd); ++#endif // DFS_SUPPORT // ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Start IBSS fail. BUG!!!!!\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAuthProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_ASSOC_REQ_STRUCT AssocReq; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_AUTH_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); ++ AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ ++#ifdef LEAP_SUPPORT ++ // ++ // Cisco Leap CCKM supported Re-association. ++ // ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ //if CCKM is turn on , that's mean Fast Reauthentication ++ //Use CCKM Reassociation instead of normal association for Fast Roaming. ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; ++ } ++ } ++ else ++ { ++ // This fail may because of the AP already keep us in its MAC table without ++ // ageing-out. The previous authentication attempt must have let it remove us. ++ // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n")); ++#ifdef LEAP_SUPPORT ++ //Add AuthMode "LEAP" for CCX 1.X ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) ++ { ++ // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); ++ } ++ else ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ } ++ } ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAuthProc2( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_ASSOC_REQ_STRUCT AssocReq; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_AUTH_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); ++ AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; ++ } ++ else ++ { ++#ifdef LEAP_SUPPORT ++ // Process LEAP first, since it use different control variable ++ // We don't want to affect other poven operation ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ // LEAP Auth not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - *LEAP* AUTH FAIL, give up; try next BSS\n")); ++ DBGPRINT(RT_DEBUG_TRACE, ("Total match BSSID [=%d]\n", pAd->MlmeAux.SsidBssTab.BssNr)); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && ++ (pAd->MlmeAux.Alg == Ndis802_11AuthModeShared)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try OPEN system...\n")); ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; ++ } ++ else ++ { ++ // not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, give up; try next BSS\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //??????? ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAssocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ ++ if (Elem->MsgType == MT2_ASSOC_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ LinkUp(pAd, BSS_INFRA); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association successful on BSS #%ld\n",pAd->MlmeAux.BssIdx)); ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++ else ++ { ++ // not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association fails on BSS #%ld\n",pAd->MlmeAux.BssIdx)); ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitReassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Result; ++ ++ if (Elem->MsgType == MT2_REASSOC_CONF) ++ { ++ NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); ++ if (Result == MLME_SUCCESS) ++ { ++ // ++ // NDIS requires a new Link UP indication but no Link Down for RE-ASSOC ++ // ++ LinkUp(pAd, BSS_INFRA); ++ ++ // send wireless event - for association ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ STA_PORT_SECURED(pAd); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++#endif // LEAP_SUPPORT // ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); ++ } ++ else ++ { ++ // reassoc failed, try to pick next BSS in the BSS Table ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition fails on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); ++ pAd->MlmeAux.RoamIdx++; ++ IterateOnBssTab2(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID LinkUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssType) ++{ ++ ULONG Now; ++ UINT32 Data; ++ BOOLEAN Cancelled; ++ UCHAR Value = 0, idx; ++ MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; ++ ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ ++ // ++ // ASSOC - DisassocTimeoutAction ++ // CNTL - Dis-associate successful ++ // !!! LINK DOWN !!! ++ // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) ++ // ++ // To prevent DisassocTimeoutAction to call Link down after we link up, ++ // cancel the DisassocTimer no matter what it start or not. ++ // ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ ++ COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ ++#ifdef DOT11_N_SUPPORT ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++#endif // DOT11_N_SUPPORT // ++ // It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS ++ // is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place ++ // to examine if cipher algorithm switching is required. ++ //rt2860b. Don't know why need this ++ SwitchBetweenWepAndCkip(pAd); ++ ++#ifdef RT2860 ++ // Before power save before link up function, We will force use 1R. ++ // So after link up, check Rx antenna # again. ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ Value |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ Value |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ Value |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ pAd->StaCfg.BBPR3 = Value; ++#endif // RT2860 // ++ ++ if (BssType == BSS_ADHOC) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // No carrier detection when adhoc ++ // CarrierDetectionStop(pAd); ++ pAd->CommonCfg.CarrierDetect.CD_State = CD_NORMAL; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" )); ++ } ++ else ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!Infra LINK UP !!! \n" )); ++ } ++ ++ // 3*3 ++ // reset Tx beamforming bit ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x01); ++ Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++#ifdef DOT11_N_SUPPORT ++ // Change to AP channel ++ if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++#ifdef RT2860 ++ pAd->StaCfg.BBPR3 = Value; ++#endif // RT2860 // ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++#ifdef RT2860 ++ pAd->StaCfg.BBPR3 = Value; ++#endif // RT2860 // ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++#ifdef RT2860 ++ pAd->StaCfg.BBPR3 = Value; ++#endif // RT2860 // ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! 20MHz LINK UP !!! \n" )); ++ } ++ ++ RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); ++ // ++ // Save BBP_R66 value, it will be used in RTUSBResumeMsduTransmission ++ // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n", ++ BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); ++ ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity)); ++#endif // DOT11_N_SUPPORT // ++ ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ ++ AsicSetSlotTime(pAd, TRUE); ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++ ++ // Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit ++ AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) ++ { ++ // Update HT protectionfor based on AP's operating mode. ++ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); ++ } ++ else ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS)); ++ ++ NdisGetSystemUpTime(&Now); ++ pAd->StaCfg.LastBeaconRxTime = Now; // last RX timestamp ++ ++ if ((pAd->CommonCfg.TxPreamble != Rt802_11PreambleLong) && ++ CAP_IS_SHORT_PREAMBLE_ON(pAd->StaActive.CapabilityInfo)) ++ { ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); ++ } ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ ++ if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE) ++ { ++#ifdef DFS_SUPPORT ++ RadarDetectionStop(pAd); ++#endif // DFS_SUPPORT // ++ } ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ ++ if (BssType == BSS_ADHOC) ++ { ++ MakeIbssBeacon(pAd); ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ ; //Do nothing ++ } ++ else ++ { ++ AsicEnableIbssSync(pAd); ++ } ++ ++ // In ad hoc mode, use MAC table from index 1. ++ // p.s ASIC use all 0xff as termination of WCID table search.To prevent it's 0xff-ff-ff-ff-ff-ff, Write 0 here. ++ RTMP_IO_WRITE32(pAd, MAC_WCID_BASE, 0x00); ++ RTMP_IO_WRITE32(pAd, 0x1808, 0x00); ++ ++ // If WEP is enabled, add key material and cipherAlg into Asic ++ // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) ++ ++ if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ ++ for (idx=0; idx < SHARE_KEY_NUM; idx++) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][idx].Key; ++ ++ if (pAd->SharedKey[BSS0][idx].KeyLen > 0) ++ { ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ if (idx == pAd->StaCfg.DefaultKeyId) ++ { ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ } ++ } ++ ++ ++ } ++ } ++ // If WPANone is enabled, add key material and cipherAlg into Asic ++ // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) ++ else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAd->StaCfg.DefaultKeyId = 0; // always be zero ++ ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); ++ ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Unknow Cipher (=%d), set Cipher to AES\n", pAd->StaCfg.PairCipher)); ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ } ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, NULL); ++ ++ } ++ ++ } ++ else // BSS_INFRA ++ { ++ // Check the new SSID with last SSID ++ while (Cancelled == TRUE) ++ { ++ if (pAd->CommonCfg.LastSsidLen == pAd->CommonCfg.SsidLen) ++ { ++ if (RTMPCompareMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen) == 0) ++ { ++ // Link to the old one no linkdown is required. ++ break; ++ } ++ } ++ // Send link down event before set to link up ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event AA!\n")); ++ break; ++ } ++ ++ // ++ // On WPA mode, Remove All Keys if not connect to the last BSSID ++ // Key will be set after 4-way handshake. ++ // ++ if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ ULONG IV; ++ ++ // Remove all WPA keys ++ RTMPWPARemoveAllKeys(pAd); ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ ++ // Fixed connection failed with Range Maximizer - 515 AP (Marvell Chip) when security is WPAPSK/TKIP ++ // If IV related values are too large in GroupMsg2, AP would ignore this message. ++ IV = 0; ++ IV |= (pAd->StaCfg.DefaultKeyId << 30); ++ AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); ++ } ++ // NOTE: ++ // the decision of using "short slot time" or not may change dynamically due to ++ // new STA association to the AP. so we have to decide that upon parsing BEACON, not here ++ ++ // NOTE: ++ // the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically ++ // due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here ++ ++ ComposePsPoll(pAd); ++ ComposeNullFrame(pAd); ++ ++ AsicEnableBssSync(pAd); ++ ++ // Add BSSID to WCID search table ++ AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid); ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ // add this BSSID entry into HASH table ++ { ++ UCHAR HashIdx; ++ ++ //pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ HashIdx = MAC_ADDR_HASH_INDEX(pAd->CommonCfg.Bssid); ++ if (pAd->MacTab.Hash[HashIdx] == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pAd->MacTab.Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ ++ // If WEP is enabled, add paiewise and shared key ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (((pAd->StaCfg.WpaSupplicantUP)&& ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&& ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || ++ ((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&& ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled))) ++#else ++ if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ ++ for (idx=0; idx < SHARE_KEY_NUM; idx++) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][idx].Key; ++ ++ if (pAd->SharedKey[BSS0][idx].KeyLen > 0) ++ { ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ if (idx == pAd->StaCfg.DefaultKeyId) ++ { ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry); ++ } ++ } ++ } ++ } ++ ++ // only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode ++ // should wait until at least 2 active nodes in this BSSID. ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ // For GUI ++ ++ if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ { ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ } ++ // -- ++ RTMP_IndicateMediaState(pAd); ++ ++ // Add BSSID in my MAC Table. ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ RTMPMoveMemory(pAd->MacTab.Content[BSSID_WCID].Addr, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); ++ pAd->MacTab.Content[BSSID_WCID].Aid = BSSID_WCID; ++ pAd->MacTab.Content[BSSID_WCID].pAd = pAd; ++ pAd->MacTab.Content[BSSID_WCID].ValidAsCLI = TRUE; //Although this is bssid..still set ValidAsCl ++ pAd->MacTab.Size = 1; // infra mode always set MACtab size =1. ++ pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC; ++ pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC; ++ pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! ClientStatusFlags=%lx)\n", ++ pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++ ++ MlmeUpdateTxRates(pAd, TRUE, BSS0); ++#ifdef DOT11_N_SUPPORT ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable)); ++#endif // DOT11_N_SUPPORT // ++ ++ // ++ // Report Adjacent AP report. ++ // ++#ifdef LEAP_SUPPORT ++ CCXAdjacentAPReport(pAd); ++#endif // LEAP_SUPPORT // ++ ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && (pAd->MlmeAux.APRalinkIe & 0x00000003) == 3) ++ { ++ ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ RTMPSetPiggyBack(pAd, TRUE); ++ DBGPRINT(RT_DEBUG_TRACE, ("Turn on Piggy-Back\n")); ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ } ++ } ++ ++ if (pAd->MlmeAux.APRalinkIe != 0x0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE)) ++ { ++ AsicEnableRDG(pAd); ++ } ++#endif // DOT11_N_SUPPORT // ++ OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); ++ } ++ else ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); ++ CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); ++ } ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++#endif // DOT11_N_SUPPORT // ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_LINK_UP); ++ ++ pAd->Mlme.PeriodicRound = 0; ++ pAd->Mlme.OneSecPeriodicRound = 0; ++ pAd->bConfigChanged = FALSE; // Reset config flag ++ pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up ++ ++ // Set asic auto fall back ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, &pAd->MacTab.Content[BSSID_WCID], &pTable, &TableSize, &pAd->CommonCfg.TxRateIndex); ++ AsicUpdateAutoFallBackTable(pAd, pTable); ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ pEntry->MaxHTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ if (pAd->StaCfg.bAutoTxRateSwitch == FALSE) ++ { ++ pEntry->bAutoTxRateSwitch = FALSE; ++#ifdef DOT11_N_SUPPORT ++ if (pEntry->HTPhyMode.field.MCS == 32) ++ pEntry->HTPhyMode.field.ShortGI = GI_800; ++ ++ if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32)) ++ pEntry->HTPhyMode.field.STBC = STBC_NONE; ++#endif // DOT11_N_SUPPORT // ++ // If the legacy mode is set, overwrite the transmit setting of this entry. ++ if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM) ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ else ++ pEntry->bAutoTxRateSwitch = TRUE; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ // Let Link Status Page display first initial rate. ++ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); ++ // Select DAC according to HT or Legacy ++ if (pAd->StaActive.SupportedPhyInfo.MCSSet[0] != 0x00) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); ++ Value &= (~0x18); ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ Value |= 0x10; ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ { ++ } ++ else if (pEntry->MaxRAmpduFactor == 0) ++ { ++ // If HT AP doesn't support MaxRAmpduFactor = 1, we need to set max PSDU to 0. ++ // Because our Init value is 1 at MACRegTable. ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Patch for Marvel AP to gain high throughput ++ // Need to set as following, ++ // 1. Set txop in register-EDCA_AC0_CFG as 0x60 ++ // 2. Set EnTXWriteBackDDONE in register-WPDMA_GLO_CFG as zero ++ // 3. PBF_MAX_PCNT as 0x1F3FBF9F ++ // 4. kick per two packets when dequeue ++ // ++ // Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable ++ // ++ // if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is. ++#ifdef DOT11_N_SUPPORT ++ if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) ++ || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE))) ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n")); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.bEnableTxBurst) ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ Data |= 0x60; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = TRUE; ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3FBF9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 2\n")); ++ } ++ else ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n")); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // Re-check to turn on TX burst or not. ++ if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd)))) ++ { ++ pAd->CommonCfg.IOTestParm.bNextDisableRxBA = TRUE; ++ if (pAd->CommonCfg.bEnableTxBurst) ++ { ++ UINT32 MACValue = 0; ++ // Force disable TXOP value in this case. The same action in MLMEUpdateProtect too. ++ // I didn't change PBF_MAX_PCNT setting. ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &MACValue); ++ MACValue &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, MACValue); ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE; ++ COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!pAd->bNextDisableRxBA= %d \n", pAd->CommonCfg.IOTestParm.bNextDisableRxBA)); ++ // BSSID add in one MAC entry too. Because in Tx, ASIC need to check Cipher and IV/EIV, BAbitmap ++ // Pther information in MACTab.Content[BSSID_WCID] is not necessary for driver. ++ // Note: As STA, The MACTab.Content[BSSID_WCID]. PairwiseKey and Shared Key for BSS0 are the same. ++ ++ if (pAd->StaCfg.WepStatus <= Ndis802_11WEPDisabled) ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll; ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pEntry->PortSecured = pAd->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ // ++ // Patch Atheros AP TX will breakdown issue. ++ // AP Model: DLink DWL-8200AP ++ // ++ if (INFRA_ON(pAd) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && STA_TKIP_ON(pAd)) ++ { ++ RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x01); ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x00); ++ } ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if ((pAd->CommonCfg.BACapability.field.b2040CoexistScanSup) && (pAd->CommonCfg.Channel <= 11)) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SCAN_2040); ++ BuildEffectedChannelList(pAd); ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++} ++ ++/* ++ ========================================================================== ++ ++ Routine Description: ++ Disconnect current BSSID ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ IsReqFromAP - Request from AP ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ We need more information to know it's this requst from AP. ++ If yes! we need to do extra handling, for example, remove the WPA key. ++ Otherwise on 4-way handshaking will faied, since the WPA key didn't be ++ remove while auto reconnect. ++ Disconnect request from AP, it means we will start afresh 4-way handshaking ++ on WPA mode. ++ ++ ========================================================================== ++*/ ++VOID LinkDown( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN IsReqFromAP) ++{ ++ UCHAR i, ByteValue = 0; ++ ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ ++#ifdef RT2860 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ BOOLEAN Cancelled; ++ pAd->Mlme.bPsPollTimerRunning = FALSE; ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ AsicForceWakeup(pAd, TRUE); ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ } ++ ++ pAd->bPCIclkOff = FALSE; ++#endif // RT2860 // ++ if (ADHOC_ON(pAd)) // Adhoc mode link down ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MacTab.Size=%d !!!\n", pAd->MacTab.Size)); ++ } ++ else // Infra structure mode ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n")); ++ ++#ifdef QOS_DLS_SUPPORT ++ // DLS tear down frame must be sent before link down ++ // send DLS-TEAR_DOWN message ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ // Saved last SSID for linkup comparison ++ pAd->CommonCfg.LastSsidLen = pAd->CommonCfg.SsidLen; ++ NdisMoveMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen); ++ COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); ++ if (pAd->MlmeAux.CurrReqIsFromNdis == TRUE) ++ { ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event A!\n")); ++ pAd->MlmeAux.CurrReqIsFromNdis = FALSE; ++ } ++ else ++ { ++ // ++ // If disassociation request is from NDIS, then we don't need to delete BSSID from entry. ++ // Otherwise lost beacon or receive De-Authentication from AP, ++ // then we should delete BSSID from BssTable. ++ // If we don't delete from entry, roaming will fail. ++ // ++ BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); ++ } ++ ++ // restore back to - ++ // 1. long slot (20 us) or short slot (9 us) time ++ // 2. turn on/off RTS/CTS and/or CTS-to-self protection ++ // 3. short preamble ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ ++ if (pAd->StaCfg.CCXAdjacentAPReportFlag == TRUE) ++ { ++ // ++ // Record current AP's information. ++ // for later used reporting Adjacent AP report. ++ // ++ pAd->StaCfg.CCXAdjacentAPChannel = pAd->CommonCfg.Channel; ++ pAd->StaCfg.CCXAdjacentAPSsidLen = pAd->CommonCfg.SsidLen; ++ NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen); ++ COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid); ++ } ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // Country IE of the AP will be evaluated and will be used. ++ if (pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) ++ { ++ NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pAd->StaCfg.StaOriCountryCode[0], 2); ++ pAd->CommonCfg.Geography = pAd->StaCfg.StaOriGeography; ++ BuildChannelListEx(pAd); ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ } ++ ++ for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) ++ MacTableDeleteEntry(pAd, pAd->MacTab.Content[i].Aid, pAd->MacTab.Content[i].Addr); ++ } ++ ++ pAd->StaCfg.CCXQosECWMin = 4; ++ pAd->StaCfg.CCXQosECWMax = 10; ++ ++ AsicSetSlotTime(pAd, TRUE); //FALSE); ++ AsicSetEdcaParm(pAd, NULL); ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_LINK_DOWN); ++ pAd->LedIndicatorStregth = 0xF0; ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. ++ ++ AsicDisableSync(pAd); ++ ++ pAd->Mlme.PeriodicRound = 0; ++ pAd->Mlme.OneSecPeriodicRound = 0; ++ ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ { ++ // Remove StaCfg Information after link down ++ NdisZeroMemory(pAd->CommonCfg.Bssid, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->CommonCfg.Ssid, MAX_LEN_OF_SSID); ++ pAd->CommonCfg.SsidLen = 0; ++ } ++#ifdef DOT11_N_SUPPORT ++ NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE)); ++ NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ pAd->MlmeAux.HtCapabilityLen = 0; ++ pAd->MlmeAux.NewExtChannelOffset = 0xff; ++#endif // DOT11_N_SUPPORT // ++ ++ // Reset WPA-PSK state. Only reset when supplicant enabled ++ if (pAd->StaCfg.WpaState != SS_NOTUSE) ++ { ++ pAd->StaCfg.WpaState = SS_START; ++ // Clear Replay counter ++ NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); ++ ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->CommonCfg.bDLSCapable) ++ NdisZeroMemory(pAd->StaCfg.DlsReplayCounter, 8); ++#endif // QOS_DLS_SUPPORT // ++ } ++ ++ ++ // ++ // if link down come from AP, we need to remove all WPA keys on WPA mode. ++ // otherwise will cause 4-way handshaking failed, since the WPA key not empty. ++ // ++ if ((IsReqFromAP) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ // Remove all WPA keys ++ RTMPWPARemoveAllKeys(pAd); ++ } ++ ++ // 802.1x port control ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Prevent clear PortSecured here with static WEP ++ // NetworkManger set security policy first then set SSID to connect AP. ++ if (pAd->StaCfg.WpaSupplicantUP && ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) && ++ (pAd->StaCfg.IEEE8021X == FALSE)) ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pAd->MacTab.Content[BSSID_WCID].PortSecured = pAd->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ pAd->StaCfg.MicErrCnt = 0; ++ ++ // Turn off Ckip control flag ++ pAd->StaCfg.bCkipOn = FALSE; ++ pAd->StaCfg.CCXEnable = FALSE; ++ ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ // Update extra information to link is up ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ ++ pAd->StaCfg.AdhocBOnlyJoined = FALSE; ++ pAd->StaCfg.AdhocBGJoined = FALSE; ++ pAd->StaCfg.Adhoc20NJoined = FALSE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ ++ // Reset the Current AP's IP address ++ NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4); ++ ++ // Clean association information ++ NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); ++ pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ pAd->StaCfg.ReqVarIELen = 0; ++ pAd->StaCfg.ResVarIELen = 0; ++ ++ // ++ // Reset RSSI value after link down ++ // ++ pAd->StaCfg.RssiSample.AvgRssi0 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi0X8 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi1 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi1X8 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi2 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi2X8 = 0; ++ ++ // Restore MlmeRate ++ pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate; ++ ++#ifdef DOT11_N_SUPPORT ++ // ++ // After Link down, reset piggy-back setting in ASIC. Disable RDG. ++ // ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &ByteValue); ++ ByteValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue); ++ } ++#endif // DOT11_N_SUPPORT // ++ // Reset DAC ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue); ++ ByteValue &= (~0x18); ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ ByteValue |= 0x10; ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, ByteValue); ++ ++ RTMPSetPiggyBack(pAd,FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); ++ ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word; ++#endif // DOT11_N_SUPPORT // ++ ++ // Restore all settings in the following. ++ AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE); ++ AsicDisableRDG(pAd); ++ pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE; ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SCAN_2040); ++ pAd->CommonCfg.BSSCoexist2040.word = 0; ++ TriEventInit(pAd); ++ for (i = 0; i < (pAd->ChannelListNum - 1); i++) ++ { ++ pAd->ChannelList[i].bEffectedChannel = FALSE; ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID IterateOnBssTab( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_START_REQ_STRUCT StartReq; ++ MLME_JOIN_REQ_STRUCT JoinReq; ++ ULONG BssIdx; ++ ++ // Change the wepstatus to original wepstatus ++ pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; ++ ++ BssIdx = pAd->MlmeAux.BssIdx; ++ if (BssIdx < pAd->MlmeAux.SsidBssTab.BssNr) ++ { ++ // Check cipher suite, AP must have more secured cipher than station setting ++ // Set the Pairwise and Group cipher to match the intended AP setting ++ // We can only connect to AP with less secured cipher setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher; ++ else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher; ++ else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ ++ // RSN capability ++ pAd->StaCfg.RsnCapability = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.RsnCapability; ++ } ++ ++ // Set Mix cipher flag ++ pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; ++ if (pAd->StaCfg.bMixCipher == TRUE) ++ { ++ // If mix cipher, re-build RSNIE ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.SsidBssTab.BssNr)); ++ JoinParmFill(pAd, &JoinReq, BssIdx); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), ++ &JoinReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; ++ } ++ else if (pAd->StaCfg.BssType == BSS_ADHOC) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ else // no more BSS ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All roaming failed, stay @ ch #%d\n", pAd->CommonCfg.Channel)); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++} ++ ++// for re-association only ++// IRQL = DISPATCH_LEVEL ++VOID IterateOnBssTab2( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_REASSOC_REQ_STRUCT ReassocReq; ++ ULONG BssIdx; ++ BSS_ENTRY *pBss; ++ ++ BssIdx = pAd->MlmeAux.RoamIdx; ++ pBss = &pAd->MlmeAux.RoamTab.BssEntry[BssIdx]; ++ ++ if (BssIdx < pAd->MlmeAux.RoamTab.BssNr) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.RoamTab.BssNr)); ++ ++ AsicSwitchChannel(pAd, pBss->Channel, FALSE); ++ AsicLockChannel(pAd, pBss->Channel); ++ ++ // reassociate message has the same structure as associate message ++ AssocParmFill(pAd, &ReassocReq, pBss->Bssid, pBss->CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, ++ sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; ++ } ++ else // no more BSS ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All fast roaming failed, back to ch #%d\n",pAd->CommonCfg.Channel)); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID JoinParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, ++ IN ULONG BssIdx) ++{ ++ JoinReq->BssIdx = BssIdx; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID ScanParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN UCHAR ScanType) ++{ ++ NdisZeroMemory(ScanReq->Ssid, MAX_LEN_OF_SSID); ++ ScanReq->SsidLen = SsidLen; ++ NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen); ++ ScanReq->BssType = BssType; ++ ScanReq->ScanType = ScanType; ++} ++ ++#ifdef QOS_DLS_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID DlsParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, ++ IN PRT_802_11_DLS pDls, ++ IN USHORT reason) ++{ ++ pDlsReq->pDLS = pDls; ++ pDlsReq->Reason = reason; ++} ++#endif // QOS_DLS_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID StartParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_START_REQ_STRUCT *StartReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen) ++{ ++ ASSERT(SsidLen <= MAX_LEN_OF_SSID); ++ NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen); ++ StartReq->SsidLen = SsidLen; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID AuthParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, ++ IN PUCHAR pAddr, ++ IN USHORT Alg) ++{ ++ COPY_MAC_ADDR(AuthReq->Addr, pAddr); ++ AuthReq->Alg = Alg; ++ AuthReq->Timeout = AUTH_TIMEOUT; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++#ifdef RT2860 ++VOID ComposePsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++ pAd->PsPollFrame.FC.Type = BTYPE_CNTL; ++ pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL; ++ pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000; ++ COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress); ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID ComposeNullFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11)); ++ pAd->NullFrame.FC.Type = BTYPE_DATA; ++ pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC; ++ pAd->NullFrame.FC.ToDs = 1; ++ COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); ++} ++#endif // RT2860 // ++ ++ ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Pre-build a BEACON frame in the shared memory ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++ULONG MakeIbssBeacon( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR DsLen = 1, IbssLen = 2; ++ UCHAR LocalErpIe[3] = {IE_ERP, 1, 0x04}; ++ HEADER_802_11 BcnHdr; ++ USHORT CapabilityInfo; ++ LARGE_INTEGER FakeTimestamp; ++ ULONG FrameLen = 0; ++ PTXWI_STRUC pTxWI = &pAd->BeaconTxWI; ++ CHAR *pBeaconFrame = pAd->BeaconBuf; ++ BOOLEAN Privacy; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen = 0; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen = 0; ++ UCHAR RSNIe = IE_WPA; ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11B) && (pAd->CommonCfg.Channel <= 14)) ++ { ++ SupRate[0] = 0x82; // 1 mbps ++ SupRate[1] = 0x84; // 2 mbps ++ SupRate[2] = 0x8b; // 5.5 mbps ++ SupRate[3] = 0x96; // 11 mbps ++ SupRateLen = 4; ++ ExtRateLen = 0; ++ } ++ else if (pAd->CommonCfg.Channel > 14) ++ { ++ SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ SupRateLen = 8; ++ ExtRateLen = 0; ++ ++ // ++ // Also Update MlmeRate & RtsRate for G only & A only ++ // ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ else ++ { ++ SupRate[0] = 0x82; // 1 mbps ++ SupRate[1] = 0x84; // 2 mbps ++ SupRate[2] = 0x8b; // 5.5 mbps ++ SupRate[3] = 0x96; // 11 mbps ++ SupRateLen = 4; ++ ++ ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps, ++ ExtRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ ExtRate[2] = 0x18; // 12 mbps, in units of 0.5 Mbps, ++ ExtRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ ExtRate[4] = 0x30; // 24 mbps, in units of 0.5 Mbps, ++ ExtRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ ExtRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ ExtRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ ExtRateLen = 8; ++ } ++ ++ pAd->StaActive.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->StaActive.SupRate, SupRate, SupRateLen); ++ pAd->StaActive.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, ExtRateLen); ++ ++ // compose IBSS beacon frame ++ MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR, pAd->CommonCfg.Bssid); ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); ++ ++ MakeOutgoingFrame(pBeaconFrame, &FrameLen, ++ sizeof(HEADER_802_11), &BcnHdr, ++ TIMESTAMP_LEN, &FakeTimestamp, ++ 2, &pAd->CommonCfg.BeaconPeriod, ++ 2, &CapabilityInfo, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &SupRateLen, ++ SupRateLen, SupRate, ++ 1, &DsIe, ++ 1, &DsLen, ++ 1, &pAd->CommonCfg.Channel, ++ 1, &IbssIe, ++ 1, &IbssLen, ++ 2, &pAd->StaActive.AtimWin, ++ END_OF_ARGS); ++ ++ // add ERP_IE and EXT_RAE IE of in 802.11g ++ if (ExtRateLen) ++ { ++ ULONG tmp; ++ ++ MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, ++ 3, LocalErpIe, ++ 1, &ExtRateIe, ++ 1, &ExtRateLen, ++ ExtRateLen, ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // If adhoc secruity is set for WPA-None, append the cipher suite IE ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ ULONG tmp; ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ ++ MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen, HtLen1; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++ ADD_HT_INFO_IE addHTInfoTmp; ++ USHORT b2lTmp, b2lTmp2; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(pAd->CommonCfg.HtCapability); ++ HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ 1, &AddHtInfoIe, ++ 1, &HtLen1, ++ HtLen1, &pAd->CommonCfg.AddHTInfo, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1); ++ *(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2)); ++ *(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3)); ++ ++ MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ 1, &AddHtInfoIe, ++ 1, &HtLen1, ++ HtLen1, &addHTInfoTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ //beacon use reserved WCID 0xff ++ if (pAd->CommonCfg.Channel > 14) ++ { ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, ++ PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ // Set to use 1Mbps for Adhoc beacon. ++ HTTRANSMIT_SETTING Transmit; ++ Transmit.word = 0; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, ++ PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n", ++ FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode)); ++ return FrameLen; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/dls.c +@@ -0,0 +1,2201 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ dls.c ++ ++ Abstract: ++ Handle WMM-DLS state machine ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 02-14-2006 ++ Arvin Tai 06-03-2008 Modified for RT28xx ++ */ ++ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ dls state machine init, including state transition and timer init ++ Parameters: ++ Sm - pointer to the dls state machine ++ Note: ++ The state machine looks like this ++ ++ DLS_IDLE ++ MT2_MLME_DLS_REQUEST MlmeDlsReqAction ++ MT2_PEER_DLS_REQUEST PeerDlsReqAction ++ MT2_PEER_DLS_RESPONSE PeerDlsRspAction ++ MT2_MLME_DLS_TEARDOWN MlmeTearDownAction ++ MT2_PEER_DLS_TEARDOWN PeerTearDownAction ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++void DlsStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ UCHAR i; ++ ++ StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_DLS_STATE, MAX_DLS_MSG, (STATE_MACHINE_FUNC)Drop, DLS_IDLE, DLS_MACHINE_BASE); ++ ++ // the first column ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_REQ, (STATE_MACHINE_FUNC)MlmeDlsReqAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_REQ, (STATE_MACHINE_FUNC)PeerDlsReqAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_RSP, (STATE_MACHINE_FUNC)PeerDlsRspAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)MlmeDlsTearDownAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)PeerDlsTearDownAction); ++ ++ for (i=0; iStaCfg.DLSEntry[i].pAd = pAd; ++ RTMPInitTimer(pAd, &pAd->StaCfg.DLSEntry[i].Timer, GET_TIMER_FUNCTION(DlsTimeoutAction), pAd, FALSE); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ HEADER_802_11 DlsReqHdr; ++ PRT_802_11_DLS pDLS = NULL; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_REQUEST; ++ ULONG tmp; ++ USHORT reason; ++ ULONG Timeout; ++ BOOLEAN TimerCancelled; ++ ++ if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &reason)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsReqAction() \n")); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsReqAction() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsReqHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsReqHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, &pDLS->MacAddr, ++ 6, pAd->CurrentAddress, ++ 2, &pAd->StaActive.CapabilityInfo, ++ 2, &pDLS->TimeOut, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR HtLen; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(HT_CAPABILITY_IE); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen = FrameLen + tmp; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ Timeout = DLS_TIMEOUT; ++ RTMPSetTimer(&pDLS->Timer, Timeout); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT StatusCode = MLME_SUCCESS; ++ HEADER_802_11 DlsRspHdr; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_RESPONSE; ++ ULONG tmp; ++ USHORT CapabilityInfo; ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT DLSTimeOut; ++ SHORT i; ++ ULONG Timeout; ++ BOOLEAN TimerCancelled; ++ PRT_802_11_DLS pDLS = NULL; ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR SupportedRatesLen; ++ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR HtCapabilityLen; ++ HT_CAPABILITY_IE HtCapability; ++ ++ if (!PeerDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &DLSTimeOut, ++ &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) ++ return; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (i = 0; i < SupportedRatesLen; i++) ++ { ++ if (MaxSupportedRateIn500Kbps < (SupportedRates[i] & 0x7f)) ++ MaxSupportedRateIn500Kbps = SupportedRates[i] & 0x7f; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() from %02x:%02x:%02x:%02x:%02x:%02x\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() allocate memory failed \n")); ++ return; ++ } ++ ++ if (!INFRA_ON(pAd)) ++ { ++ StatusCode = MLME_REQUEST_DECLINED; ++ } ++ else if (!pAd->CommonCfg.bWmmCapable) ++ { ++ StatusCode = MLME_DEST_STA_IS_NOT_A_QSTA; ++ } ++ else if (!pAd->CommonCfg.bDLSCapable) ++ { ++ StatusCode = MLME_REQUEST_DECLINED; ++ } ++ else ++ { ++ // find table to update parameters ++ for (i = (MAX_NUM_OF_DLS_ENTRY-1); i >= 0; i--) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ } ++ ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ pDLS = &pAd->StaCfg.DLSEntry[i]; ++ break; ++ } ++ } ++ ++ // can not find in table, create a new one ++ if (i < 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() can not find same entry \n")); ++ for (i=(MAX_NUM_OF_DLS_ENTRY - 1); i >= MAX_NUM_OF_INIT_DLS_ENTRY; i--) ++ { ++ if (!pAd->StaCfg.DLSEntry[i].Valid) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ } ++ ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ pAd->StaCfg.DLSEntry[i].Valid = TRUE; ++ pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; ++ NdisMoveMemory(pAd->StaCfg.DLSEntry[i].MacAddr, SA, MAC_ADDR_LEN); ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ pDLS = &pAd->StaCfg.DLSEntry[i]; ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsReqAction() Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ ++ printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ break; ++ } ++ } ++ } ++ StatusCode = MLME_SUCCESS; ++ ++ // can not find in table, create a new one ++ if (i < 0) ++ { ++ StatusCode = MLME_QOS_UNSPECIFY; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() DLSEntry table full(only can support %d DLS session) \n", MAX_NUM_OF_DLS_ENTRY - MAX_NUM_OF_INIT_DLS_ENTRY)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() use entry(%d) %02x:%02x:%02x:%02x:%02x:%02x\n", ++ i, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ } ++ ++ ActHeaderInit(pAd, &DlsRspHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsRspHdr, ++ 1, &Category, ++ 1, &Action, ++ 2, &StatusCode, ++ 6, SA, ++ 6, pAd->CurrentAddress, ++ 2, &pAd->StaActive.CapabilityInfo, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR HtLen; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(HT_CAPABILITY_IE); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen = FrameLen + tmp; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (pDLS && (pDLS->Status != DLS_FINISH)) ++ { ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ Timeout = DLS_TIMEOUT; ++ RTMPSetTimer(&pDLS->Timer, Timeout); ++ } ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsRspHdr, ++ 1, &Category, ++ 1, &Action, ++ 2, &StatusCode, ++ 6, SA, ++ 6, pAd->CurrentAddress, ++ END_OF_ARGS); ++ } ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo; ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT StatusCode; ++ SHORT i; ++ BOOLEAN TimerCancelled; ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR SupportedRatesLen; ++ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR HtCapabilityLen; ++ HT_CAPABILITY_IE HtCapability; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (!INFRA_ON(pAd)) ++ return; ++ ++ if (!PeerDlsRspSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &StatusCode, ++ &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) ++ return; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); ++ } ++ else ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); ++ } ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ ++ //initialize seq no for DLS frames. ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ } ++ else ++ { ++ // DLS setup procedure failed. ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); ++ } ++ } ++ } ++ ++ if (i >= MAX_NUM_OF_INIT_DLS_ENTRY) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() update timeout value \n")); ++ for (i=(MAX_NUM_OF_DLS_ENTRY-1); i>=MAX_NUM_OF_INIT_DLS_ENTRY; i--) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); ++ } ++ else ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); ++ } ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ } ++ else ++ { ++ // DLS setup procedure failed. ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); ++ } ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_TEARDOWN; ++ USHORT ReasonCode = REASON_QOS_UNSPECIFY; ++ HEADER_802_11 DlsTearDownHdr; ++ PRT_802_11_DLS pDLS; ++ BOOLEAN TimerCancelled; ++ UCHAR i; ++ ++ if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &ReasonCode)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsTearDownAction() with ReasonCode=%d \n", ReasonCode)); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsTearDownAction() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsTearDownHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, &pDLS->MacAddr, ++ 6, pAd->CurrentAddress, ++ 2, &ReasonCode, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ ++ // Remove key in local dls table entry ++ for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // clear peer dls table entry ++ for (i = MAX_NUM_OF_INIT_DLS_ENTRY; i < MAX_NUM_OF_DLS_ENTRY; i++) ++ { ++ if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT ReasonCode; ++ UINT i; ++ BOOLEAN TimerCancelled; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (!INFRA_ON(pAd)) ++ return; ++ ++ if (!PeerDlsTearDownSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &ReasonCode)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsTearDownAction() from %02x:%02x:%02x:%02x:%02x:%02x with ReasonCode=%d\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5], ReasonCode)); ++ ++ // clear local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // clear peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID RTMPCheckDLSTimeOut( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_UNSPECIFY; ++ ++ if (! pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (! INFRA_ON(pAd)) ++ return; ++ ++ // If timeout value is equaled to zero, it means always not be timeout. ++ ++ // update local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer --; ++ ++ if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ } ++ } ++ ++ // update peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer --; ++ ++ if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN RTMPRcvFrameDLSCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN ULONG Len, ++ IN PRT28XX_RXD_STRUC pRxD) ++{ ++ ULONG i; ++ BOOLEAN bFindEntry = FALSE; ++ BOOLEAN bSTAKeyFrame = FALSE; ++ PEAPOL_PACKET pEap; ++ PUCHAR pProto, pAddr = NULL; ++ PUCHAR pSTAKey = NULL; ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR digest[80]; ++ UCHAR DlsPTK[80]; ++ UCHAR temp[64]; ++ BOOLEAN TimerCancelled; ++ CIPHER_KEY PairwiseKey; ++ ++ ++ if (! pAd->CommonCfg.bDLSCapable) ++ return bSTAKeyFrame; ++ ++ if (! INFRA_ON(pAd)) ++ return bSTAKeyFrame; ++ ++ if (! (pHeader->FC.SubType & 0x08)) ++ return bSTAKeyFrame; ++ ++ if (Len < LENGTH_802_11 + 6 + 2 + 2) ++ return bSTAKeyFrame; ++ ++ pProto = (PUCHAR)pHeader + LENGTH_802_11 + 2 + 6; // QOS Control field , 0xAA 0xAA 0xAA 0x00 0x00 0x00 ++ pAddr = pHeader->Addr2; ++ ++ // L2PAD bit on will pad 2 bytes at LLC ++ if (pRxD->L2PAD) ++ { ++ pProto += 2; ++ } ++ ++ if (RTMPEqualMemory(EAPOL, pProto, 2) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ pEap = (PEAPOL_PACKET) (pProto + 2); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff Len=%ld, DataLen=%d, KeyMic=%d, Install=%d, KeyAck=%d, Secure=%d, EKD_DL=%d, Error=%d, Request=%d\n", Len, ++ (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16), ++ pEap->KeyDesc.KeyInfo.KeyMic, ++ pEap->KeyDesc.KeyInfo.Install, ++ pEap->KeyDesc.KeyInfo.KeyAck, ++ pEap->KeyDesc.KeyInfo.Secure, ++ pEap->KeyDesc.KeyInfo.EKD_DL, ++ pEap->KeyDesc.KeyInfo.Error, ++ pEap->KeyDesc.KeyInfo.Request)); ++ ++ if ((Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16)) && pEap->KeyDesc.KeyInfo.KeyMic ++ && pEap->KeyDesc.KeyInfo.Install && pEap->KeyDesc.KeyInfo.KeyAck && pEap->KeyDesc.KeyInfo.Secure ++ && pEap->KeyDesc.KeyInfo.EKD_DL && !pEap->KeyDesc.KeyInfo.Error && !pEap->KeyDesc.KeyInfo.Request) ++ { ++ // First validate replay counter, only accept message with larger replay counter ++ // Let equal pass, some AP start with all zero replay counter ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ if ((RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ return bSTAKeyFrame; ++ ++ //RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter (%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", ++ pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], ++ pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], ++ pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); ++ ++ // put these code segment to get the replay counter ++ if (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) ++ return bSTAKeyFrame; ++ ++ // Check MIC value ++ // Save the MIC and replace with zero ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ NdisMoveMemory(OldMic, pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1((PUCHAR) pEap, pEap->Body_Len[1] + 4, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(DlsPTK, LEN_EAP_MICK, (PUCHAR) pEap, pEap->Body_Len[1] + 4, Mic); ++ } ++ ++ if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in Msg1 of STAKey handshake! \n")); ++ return bSTAKeyFrame; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("MIC VALID in Msg1 of STAKey handshake! \n")); ++#if 1 ++ if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0C) ++ && (pEap->KeyDesc.KeyData[4] == 0x43) && (pEap->KeyDesc.KeyData[5] == 0x02)) ++ { ++ pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) ++ pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%ld, KeyDataLen=%d\n", ++ pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); ++ ++ bSTAKeyFrame = TRUE; ++ } ++#else ++ if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0F) ++ && (pEap->KeyDesc.KeyData[4] == 0xAC) && (pEap->KeyDesc.KeyData[5] == 0x02)) ++ { ++ pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) ++ pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%d, KeyDataLen=%d\n", ++ pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); ++ ++ bSTAKeyFrame = TRUE; ++ } ++#endif ++ ++ } ++ else if (Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE)) ++ { ++#if 0 ++ RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++#endif ++ RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter 2(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", ++ pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], ++ pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], ++ pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); ++ ++ } ++ } ++ ++ // If timeout value is equaled to zero, it means always not be timeout. ++ // update local dls table entry ++ for (i= 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (bSTAKeyFrame) ++ { ++ PMAC_TABLE_ENTRY pEntry; ++ ++ // STAKey frame, add pairwise key table ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ ++ PairwiseKey.KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); ++ NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); ++ ++ PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; ++ ++ pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ // Add Pair-wise key to Asic ++#ifdef RT2860 ++ AsicAddPairwiseKeyEntry(pAd, ++ pAd->StaCfg.DLSEntry[i].MacAddr, ++ (UCHAR)pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, ++ &PairwiseKey); ++ ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ PairwiseKey.CipherAlg, ++ pEntry); ++ ++#endif // RT2860 // ++ NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); ++ ++ RTMPSendSTAKeyHandShake(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Initiator side)\n")); ++ } ++ else ++ { ++ // Data frame, update timeout value ++ if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ } ++ } ++ ++ bFindEntry = TRUE; ++ } ++ } ++ ++ // update peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (bSTAKeyFrame) ++ { ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ // STAKey frame, add pairwise key table, and send STAkey Msg-2 ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ ++ PairwiseKey.KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); ++ NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); ++ ++ PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; ++ ++ pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ // Add Pair-wise key to Asic ++#ifdef RT2860 ++ AsicAddPairwiseKeyEntry(pAd, ++ pAd->StaCfg.DLSEntry[i].MacAddr, ++ (UCHAR)pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, ++ &PairwiseKey); ++ ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ PairwiseKey.CipherAlg, ++ pEntry); ++#endif // RT2860 // ++ NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); ++ ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyHandShake(pAd, pAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Peer side)\n")); ++ } ++ } ++ else ++ { ++ // Data frame, update timeout value ++ if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ } ++ } ++ ++ bFindEntry = TRUE; ++ } ++ } ++ ++ ++ return bSTAKeyFrame; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check if the frame can be sent through DLS direct link interface ++ ++ Arguments: ++ pAd Pointer to adapter ++ ++ Return Value: ++ DLS entry index ++ ++ Note: ++ ++ ======================================================================== ++*/ ++INT RTMPCheckDLSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ INT rval = -1; ++ INT i; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return rval; ++ ++ if (!INFRA_ON(pAd)) ++ return rval; ++ ++ do{ ++ // check local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ rval = i; ++ break; ++ } ++ } ++ ++ // check peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ rval = i; ++ break; ++ } ++ } ++ } while (FALSE); ++ ++ return rval; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ HEADER_802_11 DlsTearDownHdr; ++ ULONG FrameLen = 0; ++ USHORT Reason = REASON_QOS_QSTA_LEAVING_QBSS; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_TEARDOWN; ++ UCHAR i = 0; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame \n")); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ASSOC - RTMPSendDLSTearDownFrame() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsTearDownHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, pDA, ++ 6, pAd->CurrentAddress, ++ 2, &Reason, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ // Remove key in local dls table entry ++ for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // Remove key in peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame and remove key in (i=%d) \n", i)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++NDIS_STATUS RTMPSendSTAKeyRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ UCHAR Header802_3[14]; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ UCHAR digest[80]; ++ PUCHAR pOutBuffer = NULL; ++ PNDIS_PACKET pNdisPacket; ++ UCHAR temp[64]; ++ UCHAR DlsPTK[80]; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyRequest() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); ++ ++ pAd->Sequence ++; ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE andPeer MAC address ++ ++ // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ ++ // Key descriptor version ++ Packet.KeyDesc.KeyInfo.KeyDescVer = ++ (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ Packet.KeyDesc.KeyInfo.Request = 1; ++ ++ Packet.KeyDesc.KeyDataLen[1] = 12; ++ ++ // use our own OUI to distinguish proprietary with standard. ++ Packet.KeyDesc.KeyData[0] = 0xDD; ++ Packet.KeyDesc.KeyData[1] = 0x0A; ++ Packet.KeyDesc.KeyData[2] = 0x00; ++ Packet.KeyDesc.KeyData[3] = 0x0C; ++ Packet.KeyDesc.KeyData[4] = 0x43; ++ Packet.KeyDesc.KeyData[5] = 0x03; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); ++ ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Allocate buffer for transmitting message ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return NStatus; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ // calculate MIC ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ NdisZeroMemory(digest, sizeof(digest)); ++ HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(Header802_3), Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); ++ STASendPacket(pAd, pNdisPacket); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyRequest- Send STAKey request (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); ++ ++ return NStatus; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++NDIS_STATUS RTMPSendSTAKeyHandShake( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ UCHAR Header802_3[14]; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ UCHAR digest[80]; ++ PUCHAR pOutBuffer = NULL; ++ PNDIS_PACKET pNdisPacket; ++ UCHAR temp[64]; ++ UCHAR DlsPTK[80]; // Due to dirver can not get PTK, use proprietary PTK ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyHandShake() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); ++ ++ pAd->Sequence ++; ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE and Peer MAC address ++ ++ // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ ++ // Key descriptor version ++ Packet.KeyDesc.KeyInfo.KeyDescVer = ++ (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ Packet.KeyDesc.KeyDataLen[1] = 12; ++ ++ // use our own OUI to distinguish proprietary with standard. ++ Packet.KeyDesc.KeyData[0] = 0xDD; ++ Packet.KeyDesc.KeyData[1] = 0x0A; ++ Packet.KeyDesc.KeyData[2] = 0x00; ++ Packet.KeyDesc.KeyData[3] = 0x0C; ++ Packet.KeyDesc.KeyData[4] = 0x43; ++ Packet.KeyDesc.KeyData[5] = 0x03; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); ++ ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Allocate buffer for transmitting message ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return NStatus; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ // calculate MIC ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ NdisZeroMemory(digest, sizeof(digest)); ++ HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(Header802_3), Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); ++ STASendPacket(pAd, pNdisPacket); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyHandShake- Send STAKey Message-2 (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); ++ ++ return NStatus; ++} ++ ++VOID DlsTimeoutAction( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason; ++ PRT_802_11_DLS pDLS = (PRT_802_11_DLS)FunctionContext; ++ PRTMP_ADAPTER pAd = pDLS->pAd; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("DlsTimeout - Tear down DLS links (%02x:%02x:%02x:%02x:%02x:%02x)\n", ++ pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5])); ++ ++ if ((pDLS) && (pDLS->Valid)) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pDLS->Valid = FALSE; ++ pDLS->Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, pDLS, reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++ ++/* ++================================================================ ++Description : because DLS and CLI share the same WCID table in ASIC. ++Mesh entry also insert to pAd->MacTab.content[]. Such is marked as ValidAsDls = TRUE. ++Also fills the pairwise key. ++Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Dls ++from index MAX_AID_BA. ++================================================================ ++*/ ++MAC_TABLE_ENTRY *MacTableInsertDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UINT DlsEntryIdx) ++{ ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableInsertDlsEntry\n")); ++ // if FULL, return ++ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) ++ return NULL; ++ ++ do ++ { ++ if((pEntry = DlsEntryTableLookup(pAd, pAddr, TRUE)) != NULL) ++ break; ++ ++ // allocate one MAC entry ++ pEntry = MacTableInsertEntry(pAd, pAddr, DlsEntryIdx + MIN_NET_DEVICE_FOR_DLS, TRUE); ++ if (pEntry) ++ { ++ pAd->StaCfg.DLSEntry[DlsEntryIdx].MacTabMatchWCID = pEntry->Aid; ++ pEntry->MatchDlsEntryIdx = DlsEntryIdx; ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertDlsEntry - allocate entry #%d, Total= %d\n",pEntry->Aid, pAd->MacTab.Size)); ++ ++ // If legacy WEP is used, set pair-wise cipherAlg into WCID attribute table for this entry ++ if ((pEntry->ValidAsDls) && (pEntry->WepStatus == Ndis802_11WEPEnabled)) ++ { ++ UCHAR KeyIdx = 0; ++ UCHAR CipherAlg = 0; ++ ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pEntry); ++ } ++ ++ break; ++ } ++ } while(FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableInsertDlsEntry\n")); ++ ++ return pEntry; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Delete all Mesh Entry in pAd->MacTab ++ ========================================================================== ++ */ ++BOOLEAN MacTableDeleteDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableDeleteDlsEntry\n")); ++ ++ if (!VALID_WCID(wcid)) ++ return FALSE; ++ ++ MacTableDeleteEntry(pAd, wcid, pAddr); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableDeleteDlsEntry\n")); ++ ++ return TRUE; ++} ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount) ++{ ++ ULONG HashIdx; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ RTMP_SEM_LOCK(&pAd->MacTabLock); ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = pAd->MacTab.Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if ((pEntry->ValidAsDls == TRUE) ++ && MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ if(bResetIdelCount) ++ pEntry->NoDataIdleCount = 0; ++ break; ++ } ++ else ++ pEntry = pEntry->pNext; ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->MacTabLock); ++ return pEntry; ++} ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR wcid, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount) ++{ ++ ULONG DLsIndex; ++ PMAC_TABLE_ENTRY pCurEntry = NULL; ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ if (!VALID_WCID(wcid)) ++ return NULL; ++ ++ RTMP_SEM_LOCK(&pAd->MacTabLock); ++ ++ do ++ { ++ pCurEntry = &pAd->MacTab.Content[wcid]; ++ ++ DLsIndex = 0xff; ++ if ((pCurEntry) && (pCurEntry->ValidAsDls== TRUE)) ++ { ++ DLsIndex = pCurEntry->MatchDlsEntryIdx; ++ } ++ ++ if (DLsIndex == 0xff) ++ break; ++ ++ if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) ++ { ++ if(bResetIdelCount) ++ pCurEntry->NoDataIdleCount = 0; ++ pEntry = pCurEntry; ++ break; ++ } ++ } while(FALSE); ++ ++ RTMP_SEM_UNLOCK(&pAd->MacTabLock); ++ ++ return pEntry; ++} ++ ++INT Set_DlsEntryInfo_Display_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ INT i; ++ ++ printk("\n%-19s%-8s\n", "MAC", "TIMEOUT\n"); ++ for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[pAd->StaCfg.DLSEntry[i].MacTabMatchWCID]; ++ ++ printk("%02x:%02x:%02x:%02x:%02x:%02x ", ++ pAd->StaCfg.DLSEntry[i].MacAddr[0], pAd->StaCfg.DLSEntry[i].MacAddr[1], pAd->StaCfg.DLSEntry[i].MacAddr[2], ++ pAd->StaCfg.DLSEntry[i].MacAddr[3], pAd->StaCfg.DLSEntry[i].MacAddr[4], pAd->StaCfg.DLSEntry[i].MacAddr[5]); ++ printk("%-8d\n", pAd->StaCfg.DLSEntry[i].TimeOut); ++ ++ printk("\n"); ++ printk("\n%-19s%-4s%-4s%-4s%-4s%-8s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", ++ "MAC", "AID", "BSS", "PSM", "WMM", "MIMOPS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); ++ printk("%02X:%02X:%02X:%02X:%02X:%02X ", ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ printk("%-4d", (int)pEntry->Aid); ++ printk("%-4d", (int)pEntry->apidx); ++ printk("%-4d", (int)pEntry->PsMode); ++ printk("%-4d", (int)CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)); ++ printk("%-8d", (int)pEntry->MmpsMode); ++ printk("%-7d", pEntry->RssiSample.AvgRssi0); ++ printk("%-7d", pEntry->RssiSample.AvgRssi1); ++ printk("%-7d", pEntry->RssiSample.AvgRssi2); ++ printk("%-10s", GetPhyMode(pEntry->HTPhyMode.field.MODE)); ++ printk("%-6s", GetBW(pEntry->HTPhyMode.field.BW)); ++ printk("%-6d", pEntry->HTPhyMode.field.MCS); ++ printk("%-6d", pEntry->HTPhyMode.field.ShortGI); ++ printk("%-6d", pEntry->HTPhyMode.field.STBC); ++ printk("%-10d, %d, %d%%\n", pEntry->DebugFIFOCount, pEntry->DebugTxCount, ++ (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); ++ printk("\n"); ++ ++ } ++ } ++ ++ return TRUE; ++} ++ ++INT Set_DlsAddEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[MAC_ADDR_LEN]; ++ USHORT Timeout; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ RT_802_11_DLS Dls; ++ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and timeout value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ Timeout = simple_strtol((token+1), 0, 10); ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%d", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], (int)Timeout); ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ Dls.TimeOut = Timeout; ++ COPY_MAC_ADDR(Dls.MacAddr, mac); ++ Dls.Valid = 1; ++ ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_DlsTearDownEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR macAddr[MAC_ADDR_LEN]; ++ CHAR *value; ++ INT i; ++ RT_802_11_DLS Dls; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ AtoH(value, &macAddr[i++], 2); ++ } ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], ++ macAddr[2], macAddr[3], macAddr[4], macAddr[5]); ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ COPY_MAC_ADDR(Dls.MacAddr, macAddr); ++ Dls.Valid = 0; ++ ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta_ioctl.c +@@ -0,0 +1,6944 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sta_ioctl.c ++ ++ Abstract: ++ IOCTL related subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 01-03-2003 created ++ Rory Chen 02-14-2005 modify to support RT61 ++*/ ++ ++#include "rt_config.h" ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++#endif ++ ++#define NR_WEP_KEYS 4 ++#define WEP_SMALL_KEY_LEN (40/8) ++#define WEP_LARGE_KEY_LEN (104/8) ++ ++#define GROUP_KEY_NO 4 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) ++#else ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) ++#endif ++ ++extern UCHAR CipherWpa2Template[]; ++extern UCHAR CipherWpaPskTkip[]; ++extern UCHAR CipherWpaPskTkipLen; ++ ++typedef struct PACKED _RT_VERSION_INFO{ ++ UCHAR DriverVersionW; ++ UCHAR DriverVersionX; ++ UCHAR DriverVersionY; ++ UCHAR DriverVersionZ; ++ UINT DriverBuildYear; ++ UINT DriverBuildMonth; ++ UINT DriverBuildDay; ++} RT_VERSION_INFO, *PRT_VERSION_INFO; ++ ++struct iw_priv_args privtab[] = { ++{ RTPRIV_IOCTL_SET, ++ IW_PRIV_TYPE_CHAR | 1024, 0, ++ "set"}, ++ ++{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++/* --- sub-ioctls definitions --- */ ++ { SHOW_CONN_STATUS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, ++ { SHOW_DRVIER_VERION, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, ++ { SHOW_BA_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, ++ { SHOW_DESC_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, ++ { RAIO_OFF, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, ++ { RAIO_ON, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, ++#ifdef QOS_DLS_SUPPORT ++ { SHOW_DLS_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, ++#endif // QOS_DLS_SUPPORT // ++ { SHOW_CFG_VALUE, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, ++/* --- sub-ioctls relations --- */ ++ ++#ifdef DBG ++{ RTPRIV_IOCTL_BBP, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "bbp"}, ++{ RTPRIV_IOCTL_MAC, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "mac"}, ++{ RTPRIV_IOCTL_E2P, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "e2p"}, ++#endif /* DBG */ ++ ++{ RTPRIV_IOCTL_STATISTICS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "stat"}, ++{ RTPRIV_IOCTL_GSITESURVEY, ++ 0, IW_PRIV_TYPE_CHAR | 1024, ++ "get_site_survey"}, ++}; ++ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WMM_SUPPORT ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++VOID RTMPIoctlBBP( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++#endif // DBG // ++ ++ ++NDIS_STATUS RTMPWPANoneAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++INT Set_FragTest_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++static struct { ++ CHAR *name; ++ INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { ++ {"DriverVersion", Set_DriverVersion_Proc}, ++ {"CountryRegion", Set_CountryRegion_Proc}, ++ {"CountryRegionABand", Set_CountryRegionABand_Proc}, ++ {"SSID", Set_SSID_Proc}, ++ {"WirelessMode", Set_WirelessMode_Proc}, ++ {"TxBurst", Set_TxBurst_Proc}, ++ {"TxPreamble", Set_TxPreamble_Proc}, ++ {"TxPower", Set_TxPower_Proc}, ++ {"Channel", Set_Channel_Proc}, ++ {"BGProtection", Set_BGProtection_Proc}, ++ {"RTSThreshold", Set_RTSThreshold_Proc}, ++ {"FragThreshold", Set_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Set_HtBw_Proc}, ++ {"HtMcs", Set_HtMcs_Proc}, ++ {"HtGi", Set_HtGi_Proc}, ++ {"HtOpMode", Set_HtOpMode_Proc}, ++ {"HtExtcha", Set_HtExtcha_Proc}, ++ {"HtMpduDensity", Set_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Set_HtBaWinSize_Proc}, ++ {"HtRdg", Set_HtRdg_Proc}, ++ {"HtAmsdu", Set_HtAmsdu_Proc}, ++ {"HtAutoBa", Set_HtAutoBa_Proc}, ++ {"HtBaDecline", Set_BADecline_Proc}, ++ {"HtProtect", Set_HtProtect_Proc}, ++ {"HtMimoPs", Set_HtMimoPs_Proc}, ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Set_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Set_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Set_IEEE80211H_Proc}, ++ {"NetworkType", Set_NetworkType_Proc}, ++ {"AuthMode", Set_AuthMode_Proc}, ++ {"EncrypType", Set_EncrypType_Proc}, ++ {"DefaultKeyID", Set_DefaultKeyID_Proc}, ++ {"Key1", Set_Key1_Proc}, ++ {"Key2", Set_Key2_Proc}, ++ {"Key3", Set_Key3_Proc}, ++ {"Key4", Set_Key4_Proc}, ++ {"WPAPSK", Set_WPAPSK_Proc}, ++ {"ResetCounter", Set_ResetStatCounter_Proc}, ++ {"PSMode", Set_PSMode_Proc}, ++#ifdef DBG ++ {"Debug", Set_Debug_Proc}, ++#endif ++ ++#ifdef RALINK_ATE ++ {"ATE", Set_ATE_Proc}, ++ {"ATEDA", Set_ATE_DA_Proc}, ++ {"ATESA", Set_ATE_SA_Proc}, ++ {"ATEBSSID", Set_ATE_BSSID_Proc}, ++ {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, ++ {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, ++ {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, ++ {"ATETXANT", Set_ATE_TX_Antenna_Proc}, ++ {"ATERXANT", Set_ATE_RX_Antenna_Proc}, ++ {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, ++ {"ATETXBW", Set_ATE_TX_BW_Proc}, ++ {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, ++ {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, ++ {"ATETXMCS", Set_ATE_TX_MCS_Proc}, ++ {"ATETXMODE", Set_ATE_TX_MODE_Proc}, ++ {"ATETXGI", Set_ATE_TX_GI_Proc}, ++ {"ATERXFER", Set_ATE_RX_FER_Proc}, ++ {"ATERRF", Set_ATE_Read_RF_Proc}, ++ {"ATEWRF1", Set_ATE_Write_RF1_Proc}, ++ {"ATEWRF2", Set_ATE_Write_RF2_Proc}, ++ {"ATEWRF3", Set_ATE_Write_RF3_Proc}, ++ {"ATEWRF4", Set_ATE_Write_RF4_Proc}, ++ {"ATELDE2P", Set_ATE_Load_E2P_Proc}, ++ {"ATERE2P", Set_ATE_Read_E2P_Proc}, ++ {"ATESHOW", Set_ATE_Show_Proc}, ++ {"ATEHELP", Set_ATE_Help_Proc}, ++ ++#ifdef RALINK_28xx_QA ++ {"TxStop", Set_TxStop_Proc}, ++ {"RxStop", Set_RxStop_Proc}, ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ {"WpaSupport", Set_Wpa_Support}, ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++ {"FixedTxMode", Set_FixedTxMode_Proc}, ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ {"OpMode", Set_OpMode_Proc}, ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++#ifdef DOT11_N_SUPPORT ++ {"TGnWifiTest", Set_TGnWifiTest_Proc}, ++ {"ForceGF", Set_ForceGF_Proc}, ++#endif // DOT11_N_SUPPORT // ++#ifdef QOS_DLS_SUPPORT ++ {"DlsAddEntry", Set_DlsAddEntry_Proc}, ++ {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, ++#endif // QOS_DLS_SUPPORT // ++ {"LongRetry", Set_LongRetryLimit_Proc}, ++ {"ShortRetry", Set_ShortRetryLimit_Proc}, ++#ifdef EXT_BUILD_CHANNEL_LIST ++ {"11dClientMode", Set_Ieee80211dClientMode_Proc}, ++#endif // EXT_BUILD_CHANNEL_LIST // ++#ifdef CARRIER_DETECTION_SUPPORT ++ {"CarrierDetect", Set_CarrierDetect_Proc}, ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ {NULL,} ++}; ++ ++ ++VOID RTMPAddKey( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_802_11_KEY pKey) ++{ ++ ULONG KeyIdx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ NdisZeroMemory(pAd->StaCfg.PMK, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); ++ goto end; ++ } ++ // Update PTK ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ // set 802.1x port control ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else ++ { ++ // Update GTK ++ pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else // dynamic WEP from wpa_supplicant ++ { ++ UCHAR CipherAlg; ++ PUCHAR Key; ++ ++ if(pKey->KeyLength == 32) ++ goto end; ++ ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ ++ if (KeyIdx < 4) ++ { ++ // it is a default shared key, for Pairwise key setting ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ pEntry = MacTableLookup(pAd, pKey->BSSID); ++ ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); ++ ++ // set key material and key length ++ pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // set Cipher type ++ if (pKey->KeyLength == 5) ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; ++ else ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; ++ ++ // Add Pair-wise key to Asic ++ AsicAddPairwiseKeyEntry( ++ pAd, ++ pEntry->Addr, ++ (UCHAR)pEntry->Aid, ++ &pEntry->PairwiseKey); ++ ++ // update WCID attribute table and IVEIV table for this entry ++ RTMPAddWcidAttributeEntry( ++ pAd, ++ BSS0, ++ KeyIdx, // The value may be not zero ++ pEntry->PairwiseKey.CipherAlg, ++ pEntry); ++ ++ } ++ } ++ else ++ { ++ // Default key for tx (shared key) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ ++ // set key material and key length ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // Set Ciper type ++ if (pKey->KeyLength == 5) ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; ++ else ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ } ++ } ++ } ++end: ++ return; ++} ++ ++char * rtstrchr(const char * s, int c) ++{ ++ for(; *s != (char) c; ++s) ++ if (*s == '\0') ++ return NULL; ++ return (char *) s; ++} ++ ++/* ++This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function ++*/ ++ ++int ++rt_ioctl_giwname(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++#ifdef RT2860 ++ strncpy(name, "RT2860 Wireless", IFNAMSIZ); ++#endif // RT2860 // ++ return 0; ++} ++ ++int rt_ioctl_siwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int chan = -1; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ ++ if (freq->e > 1) ++ return -EINVAL; ++ ++ if((freq->e == 0) && (freq->m <= 1000)) ++ chan = freq->m; // Setting by channel number ++ else ++ MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, ++ ++ if (ChannelSanity(pAdapter, chan) == TRUE) ++ { ++ pAdapter->CommonCfg.Channel = chan; ++ DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); ++ } ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++int rt_ioctl_giwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter = NULL; ++ UCHAR ch; ++ ULONG m; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ch = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); ++ ++ MAP_CHANNEL_ID_TO_KHZ(ch, m); ++ freq->m = m * 100; ++ freq->e = 1; ++ return 0; ++} ++ ++int rt_ioctl_siwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (*mode) ++ { ++ case IW_MODE_ADHOC: ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ break; ++ case IW_MODE_INFRA: ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ break; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ case IW_MODE_MONITOR: ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ break; ++#endif ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); ++ return -EINVAL; ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (ADHOC_ON(pAdapter)) ++ *mode = IW_MODE_ADHOC; ++ else if (INFRA_ON(pAdapter)) ++ *mode = IW_MODE_INFRA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ else if (MONITOR_ON(pAdapter)) ++ { ++ *mode = IW_MODE_MONITOR; ++ } ++#endif ++ else ++ *mode = IW_MODE_AUTO; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); ++ return 0; ++} ++ ++int rt_ioctl_siwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ return 0; ++} ++ ++int rt_ioctl_giwrange(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ struct iw_range *range = (struct iw_range *) extra; ++ u16 val; ++ int i; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_DBM; ++ ++ if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) ++ { ++ range->min_pmp = 1 * 1024; ++ range->max_pmp = 65535 * 1024; ++ range->min_pmt = 1 * 1024; ++ range->max_pmt = 1000 * 1024; ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_TIMEOUT; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | ++ IW_POWER_UNICAST_R | IW_POWER_ALL_R; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 14; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = pAdapter->ChannelListNum; ++ ++ val = 0; ++ for (i = 1; i <= range->num_channels; i++) ++ { ++ u32 m; ++ range->freq[val].i = pAdapter->ChannelList[i-1].Channel; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); ++ range->freq[val].m = m * 100; /* HZ */ ++ ++ range->freq[val].e = 1; ++ val++; ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ range->num_frequency = val; ++ ++ range->max_qual.qual = 100; /* what is correct max? This was not ++ * documented exactly. At least ++ * 69 has been observed. */ ++ range->max_qual.level = 0; /* dB */ ++ range->max_qual.noise = 0; /* dB */ ++ ++ /* What would be suitable values for "average/typical" qual? */ ++ range->avg_qual.qual = 20; ++ range->avg_qual.level = -60; ++ range->avg_qual.noise = -95; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = NR_WEP_KEYS; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++#if WIRELESS_EXT > 17 ++ /* IW_ENC_CAPA_* bit field */ ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ return 0; ++} ++ ++int rt_ioctl_siwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ memset(Bssid, 0, MAC_ADDR_LEN); ++ memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ ++ return 0; ++} ++ ++int rt_ioctl_giwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); ++ return -ENOTCONN; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Units are in db above the noise floor. That means the ++ * rssi values reported in the tx/rx descriptors in the ++ * driver are the SNR expressed in db. ++ * ++ * If you assume that the noise floor is -95, which is an ++ * excellent assumption 99.5 % of the time, then you can ++ * derive the absolute signal level (i.e. -95 + rssi). ++ * There are some other slight factors to take into account ++ * depending on whether the rssi measurement is from 11b, ++ * 11g, or 11a. These differences are at most 2db and ++ * can be documented. ++ * ++ * NB: various calculations are based on the orinoco/wavelan ++ * drivers for compatibility ++ */ ++static void set_quality(PRTMP_ADAPTER pAdapter, ++ struct iw_quality *iq, ++ signed char rssi) ++{ ++ __u8 ChannelQuality; ++ ++ // Normalize Rssi ++ if (rssi >= -50) ++ ChannelQuality = 100; ++ else if (rssi >= -80) // between -50 ~ -80dbm ++ ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); ++ else if (rssi >= -90) // between -80 ~ -90dbm ++ ChannelQuality = (__u8)((rssi + 90) * 26)/10; ++ else ++ ChannelQuality = 0; ++ ++ iq->qual = (__u8)ChannelQuality; ++ ++ iq->level = (__u8)(rssi); ++ iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) ++ iq->noise += 256 - 143; ++ iq->updated = pAdapter->iw_stats.qual.updated; ++} ++ ++int rt_ioctl_iwaplist(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ struct sockaddr addr[IW_MAX_AP]; ++ struct iw_quality qual[IW_MAX_AP]; ++ int i; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ data->length = 0; ++ return 0; ++ //return -ENETDOWN; ++ } ++ ++ for (i = 0; i = pAdapter->ScanTab.BssNr) ++ break; ++ addr[i].sa_family = ARPHRD_ETHER; ++ memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); ++ } ++ data->length = i; ++ memcpy(extra, &addr, i*sizeof(addr[0])); ++ data->flags = 1; /* signal quality present (sort of) */ ++ memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); ++ ++ return 0; ++} ++ ++#ifdef SIOCGIWSCAN ++int rt_ioctl_siwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ULONG Now; ++ int Status = NDIS_STATUS_SUCCESS; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ return -EINVAL; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount++; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return 0; ++ do{ ++ Now = jiffies; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && ++ (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ RT28XX_MLME_HANDLER(pAdapter); ++ }while(0); ++ return 0; ++} ++ ++int rt_ioctl_giwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int i=0; ++ char *current_ev = extra, *previous_ev = extra; ++ char *end_buf; ++ char *current_val, custom[MAX_CUSTOM_LEN] = {0}; ++#ifndef IWEVGENIE ++ char idx; ++#endif // IWEVGENIE // ++ struct iw_event iwe; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ return -EAGAIN; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount = 0; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if (pAdapter->ScanTab.BssNr == 0) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++#if WIRELESS_EXT >= 17 ++ if (data->length > 0) ++ end_buf = extra + data->length; ++ else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#endif ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ if (current_ev >= end_buf) ++ { ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //MAC address ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //ESSID ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ iwe.u.data.flags = 1; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Network Type ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) ++ { ++ iwe.u.mode = IW_MODE_ADHOC; ++ } ++ else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) ++ { ++ iwe.u.mode = IW_MODE_INFRA; ++ } ++ else ++ { ++ iwe.u.mode = IW_MODE_AUTO; ++ } ++ iwe.len = IW_EV_UINT_LEN; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Channel and Frequency ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ else ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Add quality statistics ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.level = 0; ++ iwe.u.qual.noise = 0; ++ set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Encyption key ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) ++ iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Bit Rate ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].SupRateLen) ++ { ++ UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWRATE; ++ current_val = current_ev + IW_EV_LCP_LEN; ++ if (tmpRate == 0x82) ++ iwe.u.bitrate.value = 1 * 1000000; ++ else if (tmpRate == 0x84) ++ iwe.u.bitrate.value = 2 * 1000000; ++ else if (tmpRate == 0x8B) ++ iwe.u.bitrate.value = 5.5 * 1000000; ++ else if (tmpRate == 0x96) ++ iwe.u.bitrate.value = 11 * 1000000; ++ else ++ iwe.u.bitrate.value = (tmpRate/2) * 1000000; ++ ++ iwe.u.bitrate.disabled = 0; ++ current_val = IWE_STREAM_ADD_VALUE(info, current_ev, ++ current_val, end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ ++ if((current_val-current_ev)>IW_EV_LCP_LEN) ++ current_ev = current_val; ++ else ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++#ifdef IWEVGENIE ++ //WPA IE ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#else ++ //WPA IE ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "wpa_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "rsn_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#endif // IWEVGENIE // ++ } ++ ++ data->length = current_ev - extra; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); ++ return 0; ++} ++#endif ++ ++int rt_ioctl_siwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->flags) ++ { ++ PCHAR pSsidString = NULL; ++ ++ // Includes null character. ++ if (data->length > (IW_ESSID_MAX_SIZE + 1)) ++ return -E2BIG; ++ ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, essid, data->length); ++ if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) ++ return -EINVAL; ++ } ++ else ++ return -ENOMEM; ++ } ++ else ++ { ++ // ANY ssid ++ if (Set_SSID_Proc(pAdapter, "") == FALSE) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int rt_ioctl_giwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ data->flags = 1; ++ if (MONITOR_ON(pAdapter)) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++ else ++ {//the ANY ssid was specified ++ data->length = 0; ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); ++ } ++ ++ return 0; ++ ++} ++ ++int rt_ioctl_siwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->length > IW_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); ++ memcpy(pAdapter->nickname, nickname, data->length); ++ ++ ++ return 0; ++} ++ ++int rt_ioctl_giwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (data->length > strlen(pAdapter->nickname) + 1) ++ data->length = strlen(pAdapter->nickname) + 1; ++ if (data->length > 0) { ++ memcpy(nickname, pAdapter->nickname, data->length-1); ++ nickname[data->length-1] = '\0'; ++ } ++ return 0; ++} ++ ++int rt_ioctl_siwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (rts->disabled) ++ val = MAX_RTS_THRESHOLD; ++ else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ else if (rts->value == 0) ++ val = MAX_RTS_THRESHOLD; ++ else ++ val = rts->value; ++ ++ if (val != pAdapter->CommonCfg.RtsThreshold) ++ pAdapter->CommonCfg.RtsThreshold = val; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ rts->value = pAdapter->CommonCfg.RtsThreshold; ++ rts->disabled = (rts->value == MAX_RTS_THRESHOLD); ++ rts->fixed = 1; ++ ++ return 0; ++} ++ ++int rt_ioctl_siwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (frag->disabled) ++ val = MAX_FRAG_THRESHOLD; ++ else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) ++ val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ ++ else if (frag->value == 0) ++ val = MAX_FRAG_THRESHOLD; ++ else ++ return -EINVAL; ++ ++ pAdapter->CommonCfg.FragmentThreshold = val; ++ return 0; ++} ++ ++int rt_ioctl_giwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ frag->value = pAdapter->CommonCfg.FragmentThreshold; ++ frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); ++ frag->fixed = 1; ++ ++ return 0; ++} ++ ++#define MAX_WEP_KEY_SIZE 13 ++#define MIN_WEP_KEY_SIZE 5 ++int rt_ioctl_siwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_DISABLED)) ++ { ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ else if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) ++ { ++ STA_PORT_SECURED(pAdapter); ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ if (erq->flags & IW_ENCODE_RESTRICTED) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ ++ if (erq->length > 0) ++ { ++ int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; ++ /* Check the size of the key */ ++ if (erq->length > MAX_WEP_KEY_SIZE) { ++ return -EINVAL; ++ } ++ /* Check key index */ ++ if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", ++ keyIdx, pAdapter->StaCfg.DefaultKeyId)); ++ ++ //Using default key ++ keyIdx = pAdapter->StaCfg.DefaultKeyId; ++ } ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ ++ if (erq->length == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (erq->length == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ /* Disable the key */ ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ ++ /* Check if the key is not marked as invalid */ ++ if(!(erq->flags & IW_ENCODE_NOKEY)) { ++ /* Copy the key in the driver */ ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); ++ } ++ } ++ else ++ { ++ /* Do we want to just set the transmit key index ? */ ++ int index = (erq->flags & IW_ENCODE_INDEX) - 1; ++ if ((index >= 0) && (index < 4)) ++ { ++ pAdapter->StaCfg.DefaultKeyId = index; ++ } ++ else ++ /* Don't complain if only change the mode */ ++ if(!erq->flags & IW_ENCODE_MODE) { ++ return -EINVAL; ++ } ++ } ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); ++ return 0; ++} ++ ++int ++rt_ioctl_giwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ int kid; ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ kid = erq->flags & IW_ENCODE_INDEX; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); ++ ++ if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ++ { ++ erq->length = 0; ++ erq->flags = IW_ENCODE_DISABLED; ++ } ++ else if ((kid > 0) && (kid <=4)) ++ { ++ // copy wep key ++ erq->flags = kid ; /* NB: base 1 */ ++ if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) ++ erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); ++ //if ((kid == pAdapter->PortCfg.DefaultKeyId)) ++ //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ ++ } ++ else if (kid == 0) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); ++ // copy default key ID ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ ++ erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ } ++ ++ return 0; ++ ++} ++ ++static int ++rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter; ++ POS_COOKIE pObj; ++ char *this_char = extra; ++ char *value; ++ int Status=0; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAdapter->OS_Cookie; ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (!*this_char) ++ return -EINVAL; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value) ++ return -EINVAL; ++ ++ // reject setting nothing besides ANY ssid(ssidLen=0) ++ if (!*value && (strcmp(this_char, "SSID") != 0)) ++ return -EINVAL; ++ ++ for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) ++ { ++ if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) ++ { ++ if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) ++ { //FALSE:Set private failed then return Invalid argument ++ Status = -EINVAL; ++ } ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_SET_PROC->name == NULL) ++ { //Not found argument ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); ++ } ++ ++ return Status; ++} ++ ++ ++static int ++rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n\n"); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ } ++ sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); ++ sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->ate.RxAntennaSel == 0) ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++ else ++ { ++ sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); ++ ++ return Status; ++} ++ ++#ifdef DOT11_N_SUPPORT ++void getBaInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pOutBuf) ++{ ++ INT i, j; ++ BA_ORI_ENTRY *pOriBAEntry; ++ BA_REC_ENTRY *pRecBAEntry; ++ ++ for (i=0; iMacTab.Content[i]; ++ if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) ++ { ++ sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", ++ pOutBuf, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); ++ ++ sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BARecWcidArray[j] != 0) ++ { ++ pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); ++ } ++ } ++ sprintf(pOutBuf, "%s\n", pOutBuf); ++ ++ sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BAOriWcidArray[j] != 0) ++ { ++ pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); ++ } ++ } ++ sprintf(pOutBuf, "%s\n\n", pOutBuf); ++ } ++ if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ } ++ ++ return; ++} ++#endif // DOT11_N_SUPPORT // ++ ++static int ++rt_private_show(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ u32 subcmd = wrq->flags; ++ ++ if (dev->priv_flags == INT_MAIN) ++ pAd = dev->priv; ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(subcmd) ++ { ++ ++ case SHOW_CONN_STATUS: ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW) ++ sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); ++ else ++#endif // DOT11_N_SUPPORT // ++ sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); ++ } ++ else ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", ++ pAd->CommonCfg.Ssid, ++ pAd->CommonCfg.Bssid[0], ++ pAd->CommonCfg.Bssid[1], ++ pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3], ++ pAd->CommonCfg.Bssid[4], ++ pAd->CommonCfg.Bssid[5]); ++ DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); ++ } ++ else if (ADHOC_ON(pAd)) ++ sprintf(extra, "Connected\n"); ++ } ++ else ++ { ++ sprintf(extra, "Disconnected\n"); ++ DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); ++ } ++ } ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case SHOW_DRVIER_VERION: ++ sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#ifdef DOT11_N_SUPPORT ++ case SHOW_BA_INFO: ++ getBaInfo(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SHOW_DESC_INFO: ++ { ++ Show_DescInfo_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++ case RAIO_OFF: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = FALSE; ++ if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ sprintf(extra, "Radio Off\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case RAIO_ON: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = TRUE; ++ //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ } ++ sprintf(extra, "Radio On\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case SHOW_DLS_ENTRY_INFO: ++ { ++ Set_DlsEntryInfo_Display_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ case SHOW_CFG_VALUE: ++ { ++ Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); ++ if (Status == 0) ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ } ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); ++ break; ++ } ++ ++ return Status; ++} ++ ++#ifdef SIOCSIWMLME ++int rt_ioctl_siwmlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; ++ MLME_QUEUE_ELEM MsgElem; ++ MLME_DISASSOC_REQ_STRUCT DisAssocReq; ++ MLME_DEAUTH_REQ_STRUCT DeAuthReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); ++ ++ if (pMlme == NULL) ++ return -EINVAL; ++ ++ switch(pMlme->cmd) ++ { ++#ifdef IW_MLME_DEAUTH ++ case IW_MLME_DEAUTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); ++ DeAuthReq.Reason = pMlme->reason_code; ++ MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); ++ MlmeDeauthReqAction(pAd, &MsgElem); ++ if (INFRA_ON(pAd)) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ break; ++#endif // IW_MLME_DEAUTH // ++#ifdef IW_MLME_DISASSOC ++ case IW_MLME_DISASSOC: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); ++ DisAssocReq.Reason = pMlme->reason_code; ++ ++ MsgElem.Machine = ASSOC_STATE_MACHINE; ++ MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, &MsgElem); ++ break; ++#endif // IW_MLME_DISASSOC // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); ++ break; ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWMLME // ++ ++#if WIRELESS_EXT > 17 ++int rt_ioctl_siwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ if (param->value == IW_AUTH_WPA_VERSION_WPA) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ } ++ else if (param->value == IW_AUTH_WPA_VERSION_WPA2) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_KEY_MGMT: ++ if (param->value == IW_AUTH_KEY_MGMT_802_1X) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else ++ // WEP 1x ++ pAdapter->StaCfg.IEEE8021X = TRUE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == 0) ++ { ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ if (param->value != 0) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ { ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ } ++ else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ } ++ else ++ return -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); ++ break; ++ default: ++ return -EOPNOTSUPP; ++} ++ ++ return 0; ++} ++ ++int rt_ioctl_giwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); ++ return 0; ++} ++ ++void fnSetCipherKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN INT keyIdx, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bGTK, ++ IN struct iw_encode_ext *ext) ++{ ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ pAdapter->SharedKey[BSS0][keyIdx].Key, ++ pAdapter->SharedKey[BSS0][keyIdx].TxMic, ++ pAdapter->SharedKey[BSS0][keyIdx].RxMic); ++ ++ if (bGTK) ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ NULL); ++ else ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ &pAdapter->MacTab.Content[BSSID_WCID]); ++} ++ ++int rt_ioctl_siwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++ { ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int keyIdx, alg = ext->alg; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ { ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); ++ } ++ else ++ { ++ // Get Key Index and convet to our own defined key index ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ return -EINVAL; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ pAdapter->StaCfg.DefaultKeyId = keyIdx; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); ++ } ++ ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); ++ break; ++ case IW_ENCODE_ALG_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); ++ if (ext->key_len == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (ext->key_len == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ return -EINVAL; ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); ++ if (ext->key_len == 32) ++ { ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); ++ ++ // set 802.1x port control ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else ++ return -EINVAL; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ STA_PORT_SECURED(pAdapter); ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); ++ ++ // set 802.1x port control ++ STA_PORT_SECURED(pAdapter); ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++rt_ioctl_giwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PCHAR pKey = NULL; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) ++ { ++ if (idx < 1 || idx > 4) ++ return -EINVAL; ++ idx--; ++ ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) ++ { ++ if (idx != pAd->StaCfg.DefaultKeyId) ++ { ++ ext->key_len = 0; ++ return 0; ++ } ++ } ++ } ++ else ++ idx = pAd->StaCfg.DefaultKeyId; ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ ext->key_len = 0; ++ switch(pAd->StaCfg.WepStatus) { ++ case Ndis802_11WEPDisabled: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ encoding->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11WEPEnabled: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; ++ pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ else ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ ++ if (max_key_len < 32) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = 32; ++ pKey = &pAd->StaCfg.PMK[0]; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ext->key_len && pKey) ++ { ++ encoding->flags |= IW_ENCODE_ENABLED; ++ memcpy(ext->key, pKey, ext->key_len); ++ } ++ ++ return 0; ++} ++ ++#ifdef SIOCSIWGENIE ++int rt_ioctl_siwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (wrqu->data.length > MAX_LEN_OF_RSNIE || ++ (wrqu->data.length && extra == NULL)) ++ return -EINVAL; ++ ++ if (wrqu->data.length) ++ { ++ pAd->StaCfg.RSNIE_Len = wrqu->data.length; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); ++ } ++ else ++ { ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWGENIE // ++ ++int rt_ioctl_giwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if ((pAd->StaCfg.RSNIE_Len == 0) || ++ (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) ++ { ++ wrqu->data.length = 0; ++ return 0; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) ++ return -E2BIG; ++ ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ else ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len ++ return -E2BIG; ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ RSNIe = IE_RSN; ++ ++ extra[0] = (char)RSNIe; ++ extra[1] = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_siwpmksa(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; ++ INT CachedIdx = 0, idx = 0; ++ ++ if (pPmksa == NULL) ++ return -EINVAL; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); ++ switch(pPmksa->cmd) ++ { ++ case IW_PMKSA_FLUSH: ++ NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); ++ break; ++ case IW_PMKSA_REMOVE: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ { ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); ++ for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) ++ { ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); ++ } ++ pAd->StaCfg.SavedPMKNum--; ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); ++ break; ++ case IW_PMKSA_ADD: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ pAd->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); ++ break; ++ } ++ ++ return 0; ++} ++#endif // #if WIRELESS_EXT > 17 ++ ++#ifdef DBG ++static int ++rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++ { ++ CHAR *this_char; ++ CHAR *value = NULL; ++ UCHAR regBBP = 0; ++ UINT32 bbpId; ++ UINT32 bbpValue; ++ BOOLEAN bIsPrintAllBBP = FALSE; ++ INT Status = 0; ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ if (wrq->length > 1) //No parameters. ++ { ++ sprintf(extra, "\n"); ++ ++ //Parsing Read or Write ++ this_char = wrq->pointer; ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); ++ if (sscanf(this_char, "%d", &(bbpId)) == 1) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Write ++ if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ bIsPrintAllBBP = TRUE; ++ ++next: ++ if (bIsPrintAllBBP) ++ { ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n"); ++ for (bbpId = 0; bbpId <= 136; bbpId++) ++ { ++ if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) ++ break; ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); ++ if (bbpId%5 == 4) ++ sprintf(extra+strlen(extra), "\n"); ++ } ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); ++ ++ return Status; ++} ++#endif // DBG // ++ ++int rt_ioctl_siwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); ++ /* rate = -1 => auto rate ++ rate = X, fixed = 1 => (fixed rate X) ++ */ ++ if (rate == -1) ++ { ++ //Auto Rate ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, -1); ++ ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ else ++ { ++ if (fixed) ++ { ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, rate); ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ // TODO: rate = X, fixed = 0 => (rates <= X) ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ int rate_index = 0, rate_count = 0; ++ HTTRANSMIT_SETTING ht_setting; ++ __s32 ralinkrate[] = ++ {2, 4, 11, 22, // CCK ++ 12, 18, 24, 36, 48, 72, 96, 108, // OFDM ++ 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 ++ 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 ++ 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 ++ 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 ++ 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 ++ 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 ++ 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 ++ 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 ++ ++ rate_count = sizeof(ralinkrate)/sizeof(__s32); ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && ++ (INFRA_ON(pAd)) && ++ ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) ++ ht_setting.word = pAd->StaCfg.HTPhyMode.word; ++ else ++ ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ ++#ifdef DOT11_N_SUPPORT ++ if (ht_setting.field.MODE >= MODE_HTMIX) ++ { ++ rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (ht_setting.field.MODE == MODE_OFDM) ++ rate_index = (UCHAR)(ht_setting.field.MCS) + 4; ++ else if (ht_setting.field.MODE == MODE_CCK) ++ rate_index = (UCHAR)(ht_setting.field.MCS); ++ ++ if (rate_index < 0) ++ rate_index = 0; ++ ++ if (rate_index > rate_count) ++ rate_index = rate_count; ++ ++ wrqu->bitrate.value = ralinkrate[rate_index] * 500000; ++ wrqu->bitrate.disabled = 0; ++ ++ return 0; ++} ++ ++static const iw_handler rt_handler[] = ++{ ++ (iw_handler) NULL, /* SIOCSIWCOMMIT */ ++ (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ ++ (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ ++ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ ++ (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ ++ (iw_handler) NULL, /* SIOCSIWSPY */ ++ (iw_handler) NULL, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* SIOCSIWTHRSPY */ ++ (iw_handler) NULL, /* SIOCGIWTHRSPY */ ++ (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ ++ (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ ++#ifdef SIOCSIWMLME ++ (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* SIOCSIWMLME */ ++#endif // SIOCSIWMLME // ++ (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ ++#ifdef SIOCGIWSCAN ++ (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ ++#else ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* SIOCGIWSCAN */ ++ (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ ++ (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ ++ (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ ++ (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) NULL, /* SIOCSIWTXPOW */ ++ (iw_handler) NULL, /* SIOCGIWTXPOW */ ++ (iw_handler) NULL, /* SIOCSIWRETRY */ ++ (iw_handler) NULL, /* SIOCGIWRETRY */ ++ (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) NULL, /* SIOCSIWPOWER */ ++ (iw_handler) NULL, /* SIOCGIWPOWER */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ ++ (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ ++ (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ ++ (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ ++ (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ ++#endif ++}; ++ ++static const iw_handler rt_priv_handlers[] = { ++ (iw_handler) NULL, /* + 0x00 */ ++ (iw_handler) NULL, /* + 0x01 */ ++#ifndef CONFIG_AP_SUPPORT ++ (iw_handler) rt_ioctl_setparam, /* + 0x02 */ ++#else ++ (iw_handler) NULL, /* + 0x02 */ ++#endif // CONFIG_AP_SUPPORT // ++#ifdef DBG ++ (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ ++#else ++ (iw_handler) NULL, /* + 0x03 */ ++#endif ++ (iw_handler) NULL, /* + 0x04 */ ++ (iw_handler) NULL, /* + 0x05 */ ++ (iw_handler) NULL, /* + 0x06 */ ++ (iw_handler) NULL, /* + 0x07 */ ++ (iw_handler) NULL, /* + 0x08 */ ++ (iw_handler) rt_private_get_statistics, /* + 0x09 */ ++ (iw_handler) NULL, /* + 0x0A */ ++ (iw_handler) NULL, /* + 0x0B */ ++ (iw_handler) NULL, /* + 0x0C */ ++ (iw_handler) NULL, /* + 0x0D */ ++ (iw_handler) NULL, /* + 0x0E */ ++ (iw_handler) NULL, /* + 0x0F */ ++ (iw_handler) NULL, /* + 0x10 */ ++ (iw_handler) rt_private_show, /* + 0x11 */ ++ (iw_handler) NULL, /* + 0x12 */ ++ (iw_handler) NULL, /* + 0x13 */ ++ (iw_handler) NULL, /* + 0x15 */ ++ (iw_handler) NULL, /* + 0x17 */ ++ (iw_handler) NULL, /* + 0x18 */ ++}; ++ ++const struct iw_handler_def rt28xx_iw_handler_def = ++{ ++#define N(a) (sizeof (a) / sizeof (a[0])) ++ .standard = (iw_handler *) rt_handler, ++ .num_standard = sizeof(rt_handler) / sizeof(iw_handler), ++ .private = (iw_handler *) rt_priv_handlers, ++ .num_private = N(rt_priv_handlers), ++ .private_args = (struct iw_priv_args *) privtab, ++ .num_private_args = N(privtab), ++#if IW_HANDLER_VERSION >= 7 ++ .get_wireless_stats = rt28xx_get_wireless_stats, ++#endif ++}; ++ ++INT RTMPSetInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ RT_802_11_PHY_MODE PhyMode; ++ RT_802_11_STA_CONFIG StaConfig; ++ NDIS_802_11_RATES aryRates; ++ RT_802_11_PREAMBLE Preamble; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ PNDIS_802_11_KEY pKey = NULL; ++ PNDIS_802_11_WEP pWepKey =NULL; ++ PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; ++ NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; ++ NDIS_802_11_NETWORK_TYPE NetType; ++ ULONG Now; ++ UINT KeyIdx = 0; ++ INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; ++ ULONG PowerTemp; ++ BOOLEAN RadioState; ++ BOOLEAN StateMachineTouched = FALSE; ++#ifdef DOT11_N_SUPPORT ++ OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy ++#endif // DOT11_N_SUPPORT // ++#ifdef WPA_SUPPLICANT_SUPPORT ++ PNDIS_802_11_PMKID pPmkId = NULL; ++ BOOLEAN IEEE8021xState = FALSE; ++ BOOLEAN IEEE8021x_required_keys = FALSE; ++ UCHAR wpa_supplicant_enable = 0; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR ctmp; ++#endif // SNMP_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); ++ switch(cmd & 0x7FFF) { ++ case RT_OID_802_11_COUNTRY_REGION: ++ if (wrq->u.data.length < sizeof(UCHAR)) ++ Status = -EINVAL; ++ // Only avaliable when EEPROM not programming ++ else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) ++ { ++ ULONG Country; ++ UCHAR TmpPhy; ++ ++ Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); ++ pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); ++ TmpPhy = pAdapter->CommonCfg.PhyMode; ++ pAdapter->CommonCfg.PhyMode = 0xff; ++ // Build all corresponding channel information ++ RTMPSetPhyMode(pAdapter, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, ++ pAdapter->CommonCfg.CountryRegion)); ++ } ++ break; ++ case OID_802_11_BSSID_LIST_SCAN: ++ #ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ Now = jiffies; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ break; ++ } ++ ++ //Benson add 20080527, when radio off, sta don't need to scan ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) ++ break; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ break; ++ case OID_802_11_SSID: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) ++ Status = -EINVAL; ++ else ++ { ++ PCHAR pSsidString = NULL; ++ Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ if (Ssid.SsidLength > MAX_LEN_OF_SSID) ++ Status = -EINVAL; ++ else ++ { ++ if (Ssid.SsidLength == 0) ++ { ++ Set_SSID_Proc(pAdapter, ""); ++ } ++ else ++ { ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); ++ Set_SSID_Proc(pAdapter, pSsidString); ++ kfree(pSsidString); ++ } ++ else ++ Status = -ENOMEM; ++ } ++ } ++ } ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ } ++ break; ++ case RT_OID_802_11_RADIO: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); ++ if (pAdapter->StaCfg.bSwRadio != RadioState) ++ { ++ pAdapter->StaCfg.bSwRadio = RadioState; ++ if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) ++ { ++ pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); ++ if (pAdapter->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ MlmeRadioOff(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PhyMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAdapter, PhyMode); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); ++ } ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; ++ pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; ++ pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable ++ if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && ++ (StaConfig.AdhocMode <= MaxPhyMode)) ++ { ++ // allow dynamic change of "USE OFDM rate or not" in ADHOC mode ++ // if setting changed, need to reset current TX rate as well as BEACON frame format ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ { ++ pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; ++ RTMPSetPhyMode(pAdapter, PhyMode); ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ MakeIbssBeacon(pAdapter); // re-build BEACON frame ++ AsicEnableIbssSync(pAdapter); // copy to on-chip memory ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", ++ pAdapter->CommonCfg.bEnableTxBurst, ++ pAdapter->CommonCfg.UseBGProtection, ++ pAdapter->CommonCfg.bUseShortSlotTime)); ++ } ++ break; ++ case OID_802_11_DESIRED_RATES: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ } ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); ++ if (Preamble == Rt802_11PreambleShort) ++ { ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); ++ } ++ else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) ++ { ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); ++ } ++ break; ++ case OID_802_11_WEP_STATUS: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); ++ // Since TKIP, AES, WEP are all supported. It should not have any invalid setting ++ if (WepStatus <= Ndis802_11Encryption3KeyAbsent) ++ { ++ if (pAdapter->StaCfg.WepStatus != WepStatus) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.WepStatus = WepStatus; ++ pAdapter->StaCfg.OrigWepStatus = WepStatus; ++ pAdapter->StaCfg.PairCipher = WepStatus; ++ pAdapter->StaCfg.GroupCipher = WepStatus; ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); ++ } ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (AuthMode > Ndis802_11AuthModeMax) ++ { ++ Status = -EINVAL; ++ break; ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode != AuthMode) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.AuthMode = AuthMode; ++ } ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); ++ } ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (BssType == Ndis802_11IBSS) ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ else if (BssType == Ndis802_11Infrastructure) ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ else if (BssType == Ndis802_11Monitor) ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ else ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); ++ } ++ } ++ break; ++ case OID_802_11_REMOVE_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); ++ if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) ++ { ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx >= 4){ ++ Status = -EINVAL; ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_RESET_COUNTERS: ++ NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); ++ pAdapter->Counters8023.RxNoBuffer = 0; ++ pAdapter->Counters8023.GoodReceives = 0; ++ pAdapter->Counters8023.RxNoBuffer = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); ++ if (RtsThresh > MAX_RTS_THRESHOLD) ++ Status = -EINVAL; ++ else ++ pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ if (FragThresh == 0) ++ { ++ pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else ++ Status = -EINVAL; ++ } ++ else ++ pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerMode == Ndis802_11PowerModeCAM) ++ Set_PSMode_Proc(pAdapter, "CAM"); ++ else if (PowerMode == Ndis802_11PowerModeMAX_PSP) ++ Set_PSMode_Proc(pAdapter, "Max_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeFast_PSP) ++ Set_PSMode_Proc(pAdapter, "Fast_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) ++ Set_PSMode_Proc(pAdapter, "Legacy_PSP"); ++ else ++ Status = -EINVAL; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ if (wrq->u.data.length < sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerTemp > 100) ++ PowerTemp = 0xffffffff; // AUTO ++ pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. ++ pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ } ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (NetType == Ndis802_11DS) ++ RTMPSetPhyMode(pAdapter, PHY_11B); ++ else if (NetType == Ndis802_11OFDM24) ++ RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); ++ else if (NetType == Ndis802_11OFDM5) ++ RTMPSetPhyMode(pAdapter, PHY_11A); ++ else ++ Status = -EINVAL; ++#ifdef DOT11_N_SUPPORT ++ if (Status == NDIS_STATUS_SUCCESS) ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); ++ } ++ break; ++ // For WPA PSK PMK key ++ case RT_OID_802_11_ADD_WPA: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); ++ } ++ else ++ { ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) ++ { ++ Status = -EOPNOTSUPP; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); ++ } ++ else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode ++ { ++ NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); ++ // Use RaConfig as PSK agent. ++ // Start STA supplicant state machine ++ if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ pAdapter->StaCfg.WpaState = SS_START; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ else ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_REMOVE_KEY: ++ pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pRemoveKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pRemoveKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); ++ } ++ else ++ { ++ KeyIdx = pRemoveKey->KeyIndex; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx > 3) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); ++ } ++ } ++ } ++ } ++ kfree(pRemoveKey); ++ break; ++ // New for WPA ++ case OID_802_11_ADD_KEY: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); ++ } ++ else ++ { ++ RTMPAddKey(pAdapter, pKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_CONFIGURATION: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); ++ pConfig = &Config; ++ ++ if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) ++ pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; ++ ++ pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; ++ MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); ++ // ++ // Save the channel on MlmeAux for CntlOidRTBssidProc used. ++ // ++ pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", ++ pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_HT_PHYMODE: ++ if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) ++ Status = -EINVAL; ++ else ++ { ++ POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; ++ ++ Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", ++ pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ RTMPSetHT(pAdapter, pHTPhyMode); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", ++ pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, ++ pAdapter->StaCfg.HTPhyMode.field.STBC)); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case RT_OID_802_11_SET_APSD_SETTING: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ ULONG apsd ; ++ Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); ++ ++ /*------------------------------------------------------------------- ++ |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | ++ --------------------------------------------------------------------- ++ | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | ++ ---------------------------------------------------------------------*/ ++ pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; ++ pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, ++ pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_APSD_PSM: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ // Driver needs to notify AP when PSM changes ++ Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); ++ if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) ++ { ++ MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); ++ RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ } ++ break; ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; ++ Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); ++ if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) ++ { ++ int i; ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_DLS_PARAM: ++ if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) ++ Status = -EINVAL; ++ else ++ { ++ RT_802_11_DLS Dls; ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ case RT_OID_802_11_SET_WMM: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); ++ } ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ // ++ // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. ++ // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 ++ // when query OID_802_11_BSSID_LIST. ++ // ++ // TRUE: NumberOfItems will set to 0. ++ // FALSE: NumberOfItems no change. ++ // ++ pAdapter->CommonCfg.NdisRadioStateOff = TRUE; ++ // Set to immediately send the media disconnect event ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_DISASSOCIATE, ++ 0, ++ NULL); ++ ++ StateMachineTouched = TRUE; ++ } ++ break; ++ ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_IMME_BA_CAP: ++ if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) ++ Status = -EINVAL; ++ else ++ { ++ OID_BACAP_STRUC Orde ; ++ Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); ++ if (Orde.Policy > BA_NOTUSE) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ } ++ else if (Orde.Policy == BA_NOTUSE) ++ { ++ pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ } ++ else ++ { ++ pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; ++ pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ ++ if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; ++ ++ } ++ ++ pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); ++ } ++ ++ break; ++ case RT_OID_802_11_ADD_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ UCHAR index; ++ OID_ADD_BA_ENTRY BA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); ++ if (BA.TID > 15) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ else ++ { ++ //BATableInsertEntry ++ //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. ++ index = BA.TID; ++ // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too ++ pEntry = MacTableLookup(pAdapter, BA.MACAddr); ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); ++ break; ++ } ++ if (BA.IsRecipient == FALSE) ++ { ++ if (pEntry->bIAmBadAtheros == TRUE) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; ++ ++ BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); ++ } ++ else ++ { ++ //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", ++ BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] ++ , BA.MACAddr[4], BA.MACAddr[5])); ++ } ++ } ++ break; ++ ++ case RT_OID_802_11_TEAR_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ POID_ADD_BA_ENTRY pBA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if (pBA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); ++ ++ if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (pBA->IsRecipient == FALSE) ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); ++ BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ if (pEntry) ++ { ++ BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ kfree(pBA); ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ ++ // For WPA_SUPPLICANT to set static wep key ++ case OID_802_11_ADD_WEP: ++ pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pWepKey == NULL) ++ { ++ Status = -ENOMEM; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); ++ break; ++ } ++ Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (Status) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); ++ } ++ else ++ { ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ // KeyIdx must be 0 ~ 3 ++ if (KeyIdx > 4) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg = 0; ++ PUCHAR Key; ++ ++ // set key material and key length ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ ++ switch(pWepKey->KeyLength) ++ { ++ case 5: ++ CipherAlg = CIPHER_WEP64; ++ break; ++ case 13: ++ CipherAlg = CIPHER_WEP128; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); ++ Status = -EINVAL; ++ break; ++ } ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ ++ // Default key for tx (shared key) ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // set key material and key length ++ NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ++#endif // WPA_SUPPLICANT_SUPPORT ++ { ++ Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); ++ } ++ } ++ kfree(pWepKey); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case OID_SET_COUNTERMEASURES: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.bBlockAssoc = TRUE; ++ else ++ // WPA MIC error should block association attempt for 60 seconds ++ pAdapter->StaCfg.bBlockAssoc = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ } ++ break; ++ case OID_802_11_DEAUTHENTICATION: ++ if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) ++ Status = -EINVAL; ++ else ++ { ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; ++ Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); ++ MlmeDeauthReqAction(pAdapter, MsgElem); ++ kfree(MsgElem); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ LinkDown(pAdapter, FALSE); ++ pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); ++ } ++ break; ++ case OID_802_11_DROP_UNENCRYPTED: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ NdisAcquireSpinLock(&pAdapter->MacTabLock); ++ pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAdapter->MacTabLock); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021X = IEEE8021xState; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); ++ } ++ break; ++ case OID_802_11_PMKID: ++ pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pPmkId == NULL) { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // check the PMKID information ++ if (pPmkId->BSSIDInfoCount == 0) ++ NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ else ++ { ++ PBSSID_INFO pBssIdInfo; ++ UINT BssIdx; ++ UINT CachedIdx; ++ ++ for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) ++ { ++ // point to the indexed BSSID_INFO structure ++ pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); ++ // Find the entry in the saved data base. ++ for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ pAdapter->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ } ++ } ++ } ++ if(pPmkId) ++ kfree(pPmkId); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++#ifdef SNMP_SUPPORT ++ case OID_802_11_SHORTRETRYLIMIT: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); ++ pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ //pKey = &WepKey; ++ ++ if ( pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); ++ } ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); ++ ++ // it is a shared key ++ if (KeyIdx > 4) ++ Status = -EINVAL; ++ else ++ { ++ pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ //RestartAPIsRequired = TRUE; ++ } ++ break; ++ ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); ++ ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ break; ++ ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); ++ sprintf(&ctmp,"%d", ctmp); ++ Set_Channel_Proc(pAdapter, &ctmp); ++ } ++ break; ++#endif ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ ++ return Status; ++} ++ ++INT RTMPQueryInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; ++ PNDIS_WLAN_BSSID_EX pBss; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_CONFIGURATION *pConfiguration = NULL; ++ RT_802_11_LINK_STATUS *pLinkStatus = NULL; ++ RT_802_11_STA_CONFIG *pStaConfig = NULL; ++ NDIS_802_11_STATISTICS *pStatistics = NULL; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ RT_802_11_PREAMBLE PreamType; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_MEDIA_STATE MediaState; ++ ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; ++ USHORT BssLen = 0; ++ PUCHAR pBuf = NULL, pPtr; ++ INT Status = NDIS_STATUS_SUCCESS; ++ UINT we_version_compiled; ++ UCHAR i, Padding = 0; ++ BOOLEAN RadioState; ++ UCHAR driverVersion[8]; ++ OID_SET_HT_PHYMODE *pHTPhyMode = NULL; ++ ++ ++#ifdef SNMP_SUPPORT ++ //for snmp, kathy ++ DefaultKeyIdxValue *pKeyIdxValue; ++ INT valueLen; ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR tmp[64]; ++#endif //SNMP ++ ++ switch(cmd) ++ { ++ case RT_OID_DEVICE_NAME: ++ wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); ++ Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); ++ break; ++ case RT_OID_VERSION_INFO: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); ++ wrq->u.data.length = 8*sizeof(UCHAR); ++ sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); ++ driverVersion[7] = '\0'; ++ if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#ifdef RALINK_ATE ++ case RT_QUERY_ATE_TXDONE_COUNT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); ++ wrq->u.data.length = sizeof(UINT32); ++ if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#endif // RALINK_ATE // ++ case OID_802_11_BSSID_LIST: ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); ++ return -EAGAIN; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ // Claculate total buffer size required ++ BssBufSize = sizeof(ULONG); ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ // Align pointer to 4 bytes boundary. ++ //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); ++ //if (Padding == 4) ++ // Padding = 0; ++ BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ } ++ ++ // For safety issue, we add 256 bytes just in case ++ BssBufSize += 256; ++ // Allocate the same size as passed from higher layer ++ pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); ++ if(pBuf == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ // Init 802_11_BSSID_LIST_EX structure ++ NdisZeroMemory(pBuf, BssBufSize); ++ pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; ++ pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; ++ ++ // Calculate total buffer length ++ BssLen = 4; // Consist of NumberOfItems ++ // Point to start of NDIS_WLAN_BSSID_EX ++ // pPtr = pBuf + sizeof(ULONG); ++ pPtr = (PUCHAR) &pBssidList->Bssid[0]; ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ pBss = (PNDIS_WLAN_BSSID_EX) pPtr; ++ NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) ++ { ++ // ++ // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation ++ // and then failed to send EAPOl farame. ++ // ++ if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ else ++ pBss->Ssid.SsidLength = 0; ++ } ++ else ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; ++ pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; ++ pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; ++ pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; ++ ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); ++ ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) ++ pBss->InfrastructureMode = Ndis802_11Infrastructure; ++ else ++ pBss->InfrastructureMode = Ndis802_11IBSS; ++ ++ NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); ++ NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, ++ pAdapter->ScanTab.BssEntry[i].ExtRate, ++ pAdapter->ScanTab.BssEntry[i].ExtRateLen); ++ ++ if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) ++ { ++ pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ } ++ else ++ { ++ pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; ++ } ++ pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ ++#if WIRELESS_EXT < 17 ++ if ((BssLen + pBss->Length) < wrq->u.data.length) ++ BssLen += pBss->Length; ++ else ++ { ++ pBssidList->NumberOfItems = i; ++ break; ++ } ++#else ++ BssLen += pBss->Length; ++#endif ++ } ++ ++#if WIRELESS_EXT < 17 ++ wrq->u.data.length = BssLen; ++#else ++ if (BssLen > wrq->u.data.length) ++ { ++ kfree(pBssidList); ++ return -E2BIG; ++ } ++ else ++ wrq->u.data.length = BssLen; ++#endif ++ Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); ++ kfree(pBssidList); ++ break; ++ case OID_802_3_CURRENT_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ case OID_GEN_MEDIA_CONNECT_STATUS: ++ if (pAdapter->IndicateMediaState == NdisMediaStateConnected) ++ MediaState = NdisMediaStateConnected; ++ else ++ MediaState = NdisMediaStateDisconnected; ++ ++ wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); ++ Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++#endif // RALINK_ATE // ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); ++ Status = -ENOTCONN; ++ } ++ break; ++ case OID_802_11_SSID: ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); ++ Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; ++ memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); ++ wrq->u.data.length = sizeof(NDIS_802_11_SSID); ++ Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); ++ break; ++ case RT_OID_802_11_QUERY_LINK_STATUS: ++ pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); ++ if (pLinkStatus) ++ { ++ pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps ++ pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; ++ pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; ++ pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; ++ pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; ++ wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); ++ Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); ++ kfree(pLinkStatus); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_CONFIGURATION: ++ pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); ++ if (pConfiguration) ++ { ++ pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; ++ pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); ++ wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); ++ Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", ++ pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ kfree(pConfiguration); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_SNR_0: ++ if ((pAdapter->StaCfg.LastSNR0 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ break; ++ case RT_OID_802_11_SNR_1: ++ if ((pAdapter->Antenna.field.RxPath > 1) && ++ (pAdapter->StaCfg.LastSNR1 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); ++ break; ++ case OID_802_11_RSSI_TRIGGER: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); ++ break; ++ case OID_802_11_RSSI: ++ case RT_OID_802_11_RSSI: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_1: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_2: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_802_11_STATISTICS: ++ pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); ++ if (pStatistics) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAdapter); ++ ++ // Sanity check for calculation of sucessful count ++ if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) ++ pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ ++ pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; ++ pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; ++ pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; ++ pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; ++ pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; ++ pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; ++ pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; ++ pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; ++ pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; ++#ifdef DBG ++ pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; ++#else ++ pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; ++ pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; ++#endif ++ wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); ++ Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); ++ kfree(pStatistics); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_GEN_RCV_OK: ++ ulInfo = pAdapter->Counters8023.GoodReceives; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_GEN_RCV_NO_BUFFER: ++ ulInfo = pAdapter->Counters8023.RxNoBuffer; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); ++ if (pStaConfig) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); ++ pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; ++ pStaConfig->EnableTurboRate = 0; ++ pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; ++ pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; ++ //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; ++ pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; ++ pStaConfig->Rsv1 = 0; ++ pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; ++ wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); ++ Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); ++ kfree(pStaConfig); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ RtsThresh = pAdapter->CommonCfg.RtsThreshold; ++ wrq->u.data.length = sizeof(RtsThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ FragThresh = pAdapter->CommonCfg.FragmentThreshold; ++ if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) ++ FragThresh = 0; ++ wrq->u.data.length = sizeof(FragThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ PowerMode = pAdapter->StaCfg.WindowsPowerMode; ++ wrq->u.data.length = sizeof(PowerMode); ++ Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); ++ break; ++ case RT_OID_802_11_RADIO: ++ RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; ++ wrq->u.data.length = sizeof(RadioState); ++ Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ BssType = Ndis802_11IBSS; ++ else if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ BssType = Ndis802_11Infrastructure; ++ else if (pAdapter->StaCfg.BssType == BSS_MONITOR) ++ BssType = Ndis802_11Monitor; ++ else ++ BssType = Ndis802_11AutoUnknown; ++ ++ wrq->u.data.length = sizeof(BssType); ++ Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ PreamType = pAdapter->CommonCfg.TxPreamble; ++ wrq->u.data.length = sizeof(PreamType); ++ Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ AuthMode = pAdapter->StaCfg.AuthMode; ++ wrq->u.data.length = sizeof(AuthMode); ++ Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); ++ break; ++ case OID_802_11_WEP_STATUS: ++ WepStatus = pAdapter->StaCfg.WepStatus; ++ wrq->u.data.length = sizeof(WepStatus); ++ Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); ++ break; ++ case OID_802_11_TX_POWER_LEVEL: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ break; ++ case OID_802_11_NETWORK_TYPES_SUPPORTED: ++ if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) ++ { ++ NetworkTypeList[0] = 3; // NumberOfItems = 3 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a ++ wrq->u.data.length = 16; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ else ++ { ++ NetworkTypeList[0] = 2; // NumberOfItems = 2 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ wrq->u.data.length = 12; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ wrq->u.data.length = sizeof(ULONG); ++ if (pAdapter->CommonCfg.PhyMode == PHY_11A) ++ ulInfo = Ndis802_11OFDM5; ++ else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) ++ ulInfo = Ndis802_11OFDM24; ++ else ++ ulInfo = Ndis802_11DS; ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_LAST_RX_RATE: ++ ulInfo = (ULONG)pAdapter->LastRxRate; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_LAST_TX_RATE: ++ //ulInfo = (ULONG)pAdapter->LastTxRate; ++ ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_EEPROM_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_FIRMWARE_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_NOISE_LEVEL: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); ++ break; ++ case RT_OID_802_11_EXTRA_INFO: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); ++ break; ++ case RT_OID_WE_VERSION_COMPILED: ++ wrq->u.data.length = sizeof(UINT); ++ we_version_compiled = WIRELESS_EXT; ++ Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_APSD_SETTING: ++ apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) ++ | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); ++ ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", ++ apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); ++ break; ++ case RT_OID_802_11_QUERY_APSD_PSM: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ break; ++ case RT_OID_802_11_QUERY_WMM: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case RT_OID_NEW_DRIVER: ++ { ++ UCHAR enabled = 1; ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ case RT_OID_DRIVER_DEVICE_NAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); ++ wrq->u.data.length = 16; ++ if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; ++ ++ pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_COUNTRY_REGION: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); ++ wrq->u.data.length = sizeof(ulInfo); ++ ulInfo = pAdapter->CommonCfg.CountryRegionForABand; ++ ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); ++ if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; ++ ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ i = 0; ++#ifdef MULTIPLE_CARD_SUPPORT ++ i = 1; ++#endif // MULTIPLE_CARD_SUPPORT // ++ if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); ++ break; ++#ifdef SNMP_SUPPORT ++ case RT_OID_802_11_MAC_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREROUI: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); ++ wrq->u.data.length = ManufacturerOUI_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTURERNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_RESOURCETYPEIDNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); ++ wrq->u.data.length = strlen(ResourceTypeIdName); ++ Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); ++ ulInfo = 1; // 1 is support wep else 2 is not support. ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_POWERMANAGEMENTMODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); ++ if (pAdapter->StaCfg.Psm == PSMP_ACTION) ++ ulInfo = 1; // 1 is power active else 2 is power save. ++ else ++ ulInfo = 2; ++ ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); ++ //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; ++ pKeyIdxValue = wrq->u.data.pointer; ++ DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); ++ valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ NdisMoveMemory(pKeyIdxValue->Value, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, ++ valueLen); ++ pKeyIdxValue->Value[valueLen]='\0'; ++ ++ wrq->u.data.length = sizeof(DefaultKeyIdxValue); ++ ++ Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ pAdapter->SharedKey[BSS0][0].Key[0], ++ pAdapter->SharedKey[BSS0][1].Key[0], ++ pAdapter->SharedKey[BSS0][2].Key[0], ++ pAdapter->SharedKey[BSS0][3].Key[0])); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); ++ break; ++ ++ case RT_OID_802_11_WEPKEYMAPPINGLENGTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ wrq->u.data.length); ++ break; ++ ++ case OID_802_11_SHORTRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRODUCTID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); ++ ++#ifdef RT2860 ++ { ++ ++ USHORT device_id; ++ if (((POS_COOKIE)pAdapter->OS_Cookie)->pci_dev != NULL) ++ pci_read_config_word(((POS_COOKIE)pAdapter->OS_Cookie)->pci_dev, PCI_DEVICE_ID, &device_id); ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" pci_dev = NULL\n")); ++ sprintf(tmp, "%04x %04x\n", NIC_PCI_VENDOR_ID, device_id); ++ } ++#endif // RT2860 // ++ wrq->u.data.length = strlen(tmp); ++ Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++#endif //SNMP_SUPPORT ++ ++ case OID_802_11_BUILD_CHANNEL_EX: ++ { ++ UCHAR value; ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 1; ++#else ++ DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 0; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ Status = copy_to_user(wrq->u.data.pointer, &value, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ } ++ break; ++ ++ case OID_802_11_GET_CH_LIST: ++ { ++ PRT_CHANNEL_LIST_INFO pChListBuf; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); ++ if (pAdapter->ChannelListNum == 0) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); ++ if (pChListBuf == NULL) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf->ChannelListNum = pAdapter->ChannelListNum; ++ for (i = 0; i < pChListBuf->ChannelListNum; i++) ++ pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; ++ ++ wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ ++ if (pChListBuf) ++ kfree(pChListBuf); ++ } ++ break; ++ ++ case OID_802_11_GET_COUNTRY_CODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); ++ wrq->u.data.length = 2; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ case OID_802_11_GET_CHANNEL_GEOGRAPHY: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); ++ wrq->u.data.length = 1; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_QUERY_DLS: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ break; ++ ++ case RT_OID_802_11_QUERY_DLS_PARAM: ++ { ++ PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); ++ if (pDlsInfo == NULL) ++ break; ++ ++ for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); ++ } ++ ++ pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; ++ wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); ++ ++ if (pDlsInfo) ++ kfree(pDlsInfo); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ return Status; ++} ++ ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ POS_COOKIE pObj; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ struct iwreq *wrq = (struct iwreq *) rq; ++ BOOLEAN StateMachineTouched = FALSE; ++ INT Status = NDIS_STATUS_SUCCESS; ++ USHORT subcmd; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (wrq->u.data.pointer == NULL) ++ { ++ return Status; ++ } ++ ++ if (strstr(wrq->u.data.pointer, "OpMode") == NULL) ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ } ++ ++ { // determine this ioctl command is comming from which interface. ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(cmd) ++ { ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++ case RTPRIV_IOCTL_ATE: ++ { ++ RtmpDoAte(pAd, wrq); ++ } ++ break; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ case SIOCGIFHWADDR: ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); ++ memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); ++ break; ++ case SIOCGIWNAME: ++ { ++ char *name=&wrq->u.name[0]; ++ rt_ioctl_giwname(net_dev, NULL, name, NULL); ++ break; ++ } ++ case SIOCGIWESSID: //Get ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWESSID: //Set ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWNWID: // set network id (the cell) ++ case SIOCGIWNWID: // get network id ++ Status = -EOPNOTSUPP; ++ break; ++ case SIOCSIWFREQ: //set channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCGIWFREQ: // get channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCSIWNICKN: //set node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_siwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWNICKN: //get node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_giwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWRATE: //get default bit rate (bps) ++ rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCSIWRATE: //set default bit rate (bps) ++ rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCGIWRTS: // get RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_giwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCSIWRTS: //set RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_siwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCGIWFRAG: //get fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCSIWFRAG: //set fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCGIWENCODE: //get encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCSIWENCODE: //set encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCGIWAP: //get access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCSIWAP: //set access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCGIWMODE: //get operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_giwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCSIWMODE: //set operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_siwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCGIWSENS: //get sensitivity (dBm) ++ case SIOCSIWSENS: //set sensitivity (dBm) ++ case SIOCGIWPOWER: //get Power Management settings ++ case SIOCSIWPOWER: //set Power Management settings ++ case SIOCGIWTXPOW: //get transmit power (dBm) ++ case SIOCSIWTXPOW: //set transmit power (dBm) ++ case SIOCGIWRANGE: //Get range of parameters ++ case SIOCGIWRETRY: //get retry limits and lifetime ++ case SIOCSIWRETRY: //set retry limits and lifetime ++ Status = -EOPNOTSUPP; ++ break; ++ case RT_PRIV_IOCTL: ++ subcmd = wrq->u.data.flags; ++ if( subcmd & OID_GET_SET_TOGGLE) ++ Status = RTMPSetInformation(pAd, rq, subcmd); ++ else ++ Status = RTMPQueryInformation(pAd, rq, subcmd); ++ break; ++ case SIOCGIWPRIV: ++ if (wrq->u.data.pointer) ++ { ++ if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) ++ break; ++ wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); ++ if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) ++ Status = -EFAULT; ++ } ++ break; ++ case RTPRIV_IOCTL_SET: ++ if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) ++ break; ++ rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); ++ break; ++ case RTPRIV_IOCTL_GSITESURVEY: ++ RTMPIoctlGetSiteSurvey(pAd, wrq); ++ break; ++#ifdef DBG ++ case RTPRIV_IOCTL_MAC: ++ RTMPIoctlMAC(pAd, wrq); ++ break; ++ case RTPRIV_IOCTL_E2P: ++ RTMPIoctlE2PROM(pAd, wrq); ++ break; ++#endif // DBG // ++ case SIOCETHTOOL: ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ if(StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set SSID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_SSID Ssid, *pSsid=NULL; ++ BOOLEAN StateMachineTouched = FALSE; ++ int success = TRUE; ++ ++ if( strlen(arg) <= MAX_LEN_OF_SSID) ++ { ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ if (strlen(arg) != 0) ++ { ++ NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); ++ Ssid.SsidLength = strlen(arg); ++ } ++ else //ANY ssid ++ { ++ Ssid.SsidLength = 0; ++ memcpy(Ssid.Ssid, "", 0); ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; ++ } ++ pSsid = &Ssid; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ pAdapter->bConfigChanged = TRUE; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ (VOID *)pSsid); ++ ++ StateMachineTouched = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ } ++ else ++ success = FALSE; ++ ++ if (StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAdapter); ++ ++ return success; ++} ++ ++#ifdef WMM_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WmmCapable Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN bWmmCapable; ++ ++ bWmmCapable = simple_strtol(arg, 0, 10); ++ ++ if ((bWmmCapable == 1) ++ ) ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ else if (bWmmCapable == 0) ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", ++ pAd->CommonCfg.bWmmCapable)); ++ ++ return TRUE; ++} ++#endif // WMM_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Set Network Type(Infrastructure/Adhoc mode) ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UINT32 Value = 0; ++ ++ if (strcmp(arg, "Adhoc") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_ADHOC) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (INFRA_ON(pAdapter)) ++ { ++ //BOOLEAN Cancelled; ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_ADHOC; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); ++ } ++ else if (strcmp(arg, "Infra") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_INFRA) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (ADHOC_ON(pAdapter)) ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); ++ ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ } ++ else if (strcmp(arg, "Monitor") == 0) ++ { ++ UCHAR bbpValue = 0; ++ BCN_TIME_CFG_STRUC csr; ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ // disable all periodic state machine ++ pAdapter->StaCfg.bAutoReconnect = FALSE; ++ // reset all mlme state machine ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); ++ if (pAdapter->CommonCfg.CentralChannel == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ pAdapter->CommonCfg.CentralChannel = 36; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAdapter->CommonCfg.CentralChannel = 6; ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ N_ChannelCheck(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ // 40MHz ,control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) ++ { ++ // 40MHz ,control channel at upper ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value |= 0x1; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // 20MHz ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_20; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); ++ } ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); ++ // ASIC supporsts sniffer function with replacing RSSI with timestamp. ++ //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ //Value |= (0x80); ++ //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ // disable sync ++ RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); ++ ++ pAdapter->StaCfg.BssType = BSS_MONITOR; ++ pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Authentication mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Encryption Type ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Default Key ID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ ULONG KeyIdx; ++ ++ KeyIdx = simple_strtol(arg, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY1 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ ++ pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 0, ++ pAdapter->SharedKey[BSS0][0].CipherAlg, ++ pAdapter->SharedKey[BSS0][0].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ ++ Description: ++ Set WEP KEY2 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 1, ++ pAdapter->SharedKey[BSS0][1].CipherAlg, ++ pAdapter->SharedKey[BSS0][1].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY3 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 2, ++ pAdapter->SharedKey[BSS0][2].CipherAlg, ++ pAdapter->SharedKey[BSS0][2].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY4 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 3, ++ pAdapter->SharedKey[BSS0][3].CipherAlg, ++ pAdapter->SharedKey[BSS0][3].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WPA PSK key ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UCHAR keyMaterial[40]; ++ ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return TRUE; // do nothing ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); ++ ++ NdisZeroMemory(keyMaterial, 40); ++ ++ if ((strlen(arg) < 8) || (strlen(arg) > 64)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); ++ return FALSE; ++ } ++ ++ if (strlen(arg) == 64) ++ { ++ AtoH(arg, keyMaterial, 32); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else ++ { ++ PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ } ++ ++ ++ ++ if(pAdapter->StaCfg.BssType == BSS_ADHOC && ++ pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ } ++ else ++ { ++ // Start STA supplicant state machine ++ pAdapter->StaCfg.WpaState = SS_START; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Power Saving mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(arg, "Max_PSP") == 0) || ++ (strcmp(arg, "max_psp") == 0) || ++ (strcmp(arg, "MAX_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ pAdapter->StaCfg.DefaultListenCount = 5; ++ ++ } ++ else if ((strcmp(arg, "Fast_PSP") == 0) || ++ (strcmp(arg, "fast_psp") == 0) || ++ (strcmp(arg, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(arg, "Legacy_PSP") == 0) || ++ (strcmp(arg, "legacy_psp") == 0) || ++ (strcmp(arg, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { ++ //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAdapter, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); ++ } ++ else ++ return FALSE; ++ ++ ++ return TRUE; ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WpaSupport flag. ++ Value: ++ 0: Driver ignore wpa_supplicant. ++ 1: wpa_supplicant initiates scanning and AP selection. ++ 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ if ( simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ else if ( simple_strtol(arg, 0, 10) == 1) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++ else if ( simple_strtol(arg, 0, 10) == 2) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; ++ else ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); ++ ++ return TRUE; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ Read / Write MAC ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 ++ 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 ++ ========================================================================== ++*/ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ ULONG macAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ UINT32 macValue = 0; ++ INT Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // Mac Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ if (macAddr < 0xFFFF) ++ { ++ RTMP_IO_READ32(pAdapter, macAddr, &macValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[8-k+j] = temp2[j]; ++ } ++ ++ while(k < 8) ++ temp2[7-k++]='0'; ++ temp2[8]='\0'; ++ ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 4); ++ macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; ++ ++ // debug mode ++ if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) ++ { ++ // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning ++ if (macValue & 0x000000ff) ++ { ++ pAdapter->BbpTuning.bEnable = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); ++ } ++ else ++ { ++ UCHAR R66; ++ pAdapter->BbpTuning.bEnable = FALSE; ++ R66 = 0x26 + GET_LNA_GAIN(pAdapter); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); ++ } ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); ++ ++ RTMP_IO_WRITE32(pAdapter, macAddr, macValue); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); ++ } ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Read / Write E2PROM ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 ++ 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 ++ ========================================================================== ++*/ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ USHORT eepAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ USHORT eepValue; ++ int Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ ++ ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // E2PROM addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ if (eepAddr < 0xFFFF) ++ { ++ RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[4-k+j] = temp2[j]; ++ } ++ ++ while(k < 4) ++ temp2[3-k++]='0'; ++ temp2[4]='\0'; ++ ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 2); ++ eepValue = *temp*256 + temp[1]; ++ ++ RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); ++} ++#endif // DBG // ++ ++ ++ ++ ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); ++ return TRUE; ++} ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++ else if (simple_strtol(arg, 0, 10) == 1) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; ++ else if (simple_strtol(arg, 0, 10) == 2) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; ++ else ++ return FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); ++ return TRUE; ++} ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ return TRUE; ++} ++#endif // CARRIER_DETECTION_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/rtmp_data.c +@@ -0,0 +1,2614 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_data.c ++ ++ Abstract: ++ Data path subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Aug/17/04 major modification for RT2561/2661 ++ Jan Lee Mar/17/06 major modification for RT2860 New Ring Design ++*/ ++#include "../rt_config.h" ++ ++ ++ ++VOID STARxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ UCHAR *pTmpBuf; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) ++ // TBD : process fragmented EAPol frames ++ { ++ // In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable ++ if ( pAd->StaCfg.IEEE8021X == TRUE && ++ (EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H))) ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ int idx = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n")); ++ STA_PORT_SECURED(pAd); ++ ++ if (pAd->StaCfg.IEEE8021x_required_keys == FALSE) ++ { ++ idx = pAd->StaCfg.DesireSharedKeyId; ++ CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg; ++ Key = pAd->StaCfg.DesireSharedKey[idx].Key; ++ ++ if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) ++ { ++#ifdef RT2860 ++ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++#endif // RT2860 // ++ // For Preventing ShardKey Table is cleared by remove key procedure. ++ pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; ++ pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; ++ NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].KeyLen); ++ } ++ } ++ } ++ ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Special DATA frame that has to pass to MLME ++ // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process ++ // 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process ++ { ++ pTmpBuf = pRxBlk->pData - LENGTH_802_11; ++ NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); ++ REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize)); ++ } ++ } ++ ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ ++} ++ ++VOID STARxDataFrameAnnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ ++ // non-EAP frame ++ if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) ++ { ++ { ++ // drop all non-EAP DATA frame before ++ // this client's Port-Access-Control is secured ++ if (pRxBlk->pHeader->FC.Wep) ++ { ++ // unsupported cipher suite ++ if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ else ++ { ++ // encryption in-use but receive a non-EAPOL clear text frame, drop it ++ if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ } ++ RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) ++ { ++ // Normal legacy, AMPDU or AMSDU ++ CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID); ++ ++ } ++ else ++ { ++ // ARALINK ++ CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ } ++#ifdef QOS_DLS_SUPPORT ++ RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); ++#endif // QOS_DLS_SUPPORT // ++ } ++ else ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // Determin the destination of the EAP frame ++ // to WPA state machine or upper layer ++ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ } ++ } ++} ++ ++ ++// For TKIP frame, calculate the MIC value ++BOOLEAN STACheckTkipMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk) ++{ ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ UCHAR *pData = pRxBlk->pData; ++ USHORT DataSize = pRxBlk->DataSize; ++ UCHAR UserPriority = pRxBlk->UserPriority; ++ PCIPHER_KEY pWpaKey; ++ UCHAR *pDA, *pSA; ++ ++ pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; ++ ++ pDA = pHeader->Addr1; ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) ++ { ++ pSA = pHeader->Addr3; ++ } ++ else ++ { ++ pSA = pHeader->Addr2; ++ } ++ ++ if (RTMPTkipCompareMICValue(pAd, ++ pData, ++ pDA, ++ pSA, ++ pWpaKey->RxMic, ++ UserPriority, ++ DataSize) == FALSE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ RTMPReportMicError(pAd, pWpaKey); ++ } ++ ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++// ++// All Rx routines use RX_BLK structure to hande rx events ++// It is very important to build pRxBlk attributes ++// 1. pHeader pointer to 802.11 Header ++// 2. pData pointer to payload including LLC (just skip Header) ++// 3. set payload size including LLC to DataSize ++// 4. set some flags with RX_BLK_SET_FLAG() ++// ++VOID STAHandleRxDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ BOOLEAN bFragment = FALSE; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ UCHAR FromWhichBSSID = BSS0; ++ UCHAR UserPriority = 0; ++ ++ { ++ // before LINK UP, all DATA frames are rejected ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) ++ if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) ++ { ++ return; ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // Drop not my BSS frames ++ if (pRxD->MyBss == 0) ++ { ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ ++ pAd->RalinkCounters.RxCountSinceLastNULL++; ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08)) ++ { ++ UCHAR *pData; ++ DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n")); ++ ++ // Qos bit 4 ++ pData = (PUCHAR)pHeader + LENGTH_802_11; ++ if ((*pData >> 4) & 0x01) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); ++ pAd->CommonCfg.bInServicePeriod = FALSE; ++ ++ // Force driver to fall into sleep mode when rcv EOSP frame ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ USHORT TbttNumToNextWakeUp; ++ USHORT NextDtim = pAd->StaCfg.DtimPeriod; ++ ULONG Now; ++ ++ NdisGetSystemUpTime(&Now); ++ NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod; ++ ++ TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) ++ TbttNumToNextWakeUp = NextDtim; ++ ++ MlmeSetPsmBit(pAd, PWR_SAVE); ++ // if WMM-APSD is failed, try to disable following line ++ AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ } ++ } ++ ++ if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n")); ++ } ++ } ++ ++ // Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame ++ if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // Drop not my BSS frame (we can not only check the MyBss bit in RxD) ++#ifdef QOS_DLS_SUPPORT ++ if (!pAd->CommonCfg.bDLSCapable) ++ { ++#endif // QOS_DLS_SUPPORT // ++ if (INFRA_ON(pAd)) ++ { ++ // Infrastructure mode, check address 2 for BSSID ++ if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) ++ { ++ // Receive frame not my BSSID ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ else // Ad-Hoc mode or Not associated ++ { ++ // Ad-Hoc mode, check address 3 for BSSID ++ if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) ++ { ++ // Receive frame not my BSSID ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++#ifdef QOS_DLS_SUPPORT ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // ++ // find pEntry ++ // ++ if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) ++ { ++ pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; ++ } ++ else ++ { ++ // 1. release packet if infra mode ++ // 2. new a pEntry if ad-hoc mode ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // infra or ad-hoc ++ if (INFRA_ON(pAd)) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); ++#ifdef QOS_DLS_SUPPORT ++ if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) ++ RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ASSERT(pRxWI->WirelessCliID == BSSID_WCID); ++ } ++ ++ // check Atheros Client ++ if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry )) ++ { ++ pEntry->bIAmBadAtheros = TRUE; ++ pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; ++ pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; ++ if (!STA_AES_ON(pAd)) ++ { ++ AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE); ++ } ++ } ++ } ++ ++ pRxBlk->pData = (UCHAR *)pHeader; ++ ++ // ++ // update RxBlk->pData, DataSize ++ // 802.11 Header, QOS, HTC, Hw Padding ++ // ++ ++ // 1. skip 802.11 HEADER ++ { ++ pRxBlk->pData += LENGTH_802_11; ++ pRxBlk->DataSize -= LENGTH_802_11; ++ } ++ ++ // 2. QOS ++ if (pHeader->FC.SubType & 0x08) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); ++ UserPriority = *(pRxBlk->pData) & 0x0f; ++ // bit 7 in QoS Control field signals the HT A-MSDU format ++ if ((*pRxBlk->pData) & 0x80) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); ++ } ++ ++ // skip QOS contorl field ++ pRxBlk->pData += 2; ++ pRxBlk->DataSize -=2; ++ } ++ pRxBlk->UserPriority = UserPriority; ++ ++ // 3. Order bit: A-Ralink or HTC+ ++ if (pHeader->FC.Order) ++ { ++#ifdef AGGREGATION_SUPPORT ++ if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); ++ } ++ else ++#endif ++ { ++#ifdef DOT11_N_SUPPORT ++ RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); ++ // skip HTC contorl field ++ pRxBlk->pData += 4; ++ pRxBlk->DataSize -= 4; ++#endif // DOT11_N_SUPPORT // ++ } ++ } ++ ++ // 4. skip HW padding ++ if (pRxD->L2PAD) ++ { ++ // just move pData pointer ++ // because DataSize excluding HW padding ++ RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); ++ pRxBlk->pData += 2; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pRxD->BA) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++ // ++ // Case I Process Broadcast & Multicast data frame ++ // ++ if (pRxD->Bcast || pRxD->Mcast) ++ { ++ INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); ++ ++ // Drop Mcast/Bcast frame with fragment bit on ++ if (pHeader->FC.MoreFrag) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // Filter out Bcast frame which AP relayed for us ++ if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ else if (pRxD->U2M) ++ { ++ pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) ++ { ++ MAC_TABLE_ENTRY *pDlsEntry = NULL; ++ ++ pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); ++ if(pDlsEntry) ++ Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ if (ADHOC_ON(pAd)) ++ { ++ pEntry = MacTableLookup(pAd, pHeader->Addr2); ++ if (pEntry) ++ Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI); ++ } ++ ++ ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); ++ ++ pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); ++ pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); ++ ++ pAd->RalinkCounters.OneSecRxOkDataCnt++; ++ ++ ++ if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) ++ { ++ // re-assemble the fragmented packets ++ // return complete frame (pRxPacket) or NULL ++ bFragment = TRUE; ++ pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); ++ } ++ ++ if (pRxPacket) ++ { ++ pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; ++ ++ // process complete frame ++ if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled)) ++ { ++ // Minus MIC length ++ pRxBlk->DataSize -= 8; ++ ++ // For TKIP frame, calculate the MIC value ++ if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE) ++ { ++ return; ++ } ++ } ++ ++ STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ else ++ { ++ // just return ++ // because RTMPDeFragmentDataFrame() will release rx packet, ++ // if packet is fragmented ++ return; ++ } ++ } ++ ++ ASSERT(0); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++} ++ ++VOID STAHandleRxMgmtFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ ++ do ++ { ++ ++ // We should collect RSSI not only U2M data but also my beacon ++ if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))) ++ { ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); ++ ++ pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); ++ pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); ++ } ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); ++ break; ++ } ++ ++ REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount, ++ pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); ++ } while (FALSE); ++ ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); ++} ++ ++VOID STAHandleRxControlFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++#ifdef DOT11_N_SUPPORT ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++#endif // DOT11_N_SUPPORT // ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ ++ switch (pHeader->FC.SubType) ++ { ++ case SUBTYPE_BLOCK_ACK_REQ: ++#ifdef DOT11_N_SUPPORT ++ { ++ CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SUBTYPE_BLOCK_ACK: ++ case SUBTYPE_ACK: ++ default: ++ break; ++ } ++ ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process RxDone interrupt, running in DPC level ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ This routine has to maintain Rx ring read pointer. ++ Need to consider QOS DATA format when converting to 802.3 ++ ======================================================================== ++*/ ++BOOLEAN STARxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN argc) ++{ ++ NDIS_STATUS Status; ++ UINT32 RxProcessed, RxPending; ++ BOOLEAN bReschedule = FALSE; ++ RT28XX_RXD_STRUC *pRxD; ++ UCHAR *pData; ++ PRXWI_STRUC pRxWI; ++ PNDIS_PACKET pRxPacket; ++ PHEADER_802_11 pHeader; ++ RX_BLK RxCell; ++ ++ RxProcessed = RxPending = 0; ++ ++ // process whole rx ring ++ while (1) ++ { ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST) || ++ !RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP)) ++ { ++ break; ++ } ++ ++#ifdef RT2860 ++ if (RxProcessed++ > MAX_RX_PROCESS_CNT) ++ { ++ // need to reschedule rx handle ++ bReschedule = TRUE; ++ break; ++ } ++#endif // RT2860 // ++ ++ RxProcessed ++; // test ++ ++ // 1. allocate a new data packet into rx ring to replace received packet ++ // then processing the received packet ++ // 2. the callee must take charge of release of packet ++ // 3. As far as driver is concerned , ++ // the rx packet must ++ // a. be indicated to upper layer or ++ // b. be released if it is discarded ++ pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending); ++ if (pRxPacket == NULL) ++ { ++ // no more packet to process ++ break; ++ } ++ ++ // get rx ring descriptor ++ pRxD = &(RxCell.RxD); ++ // get rx data buffer ++ pData = GET_OS_PKT_DATAPTR(pRxPacket); ++ pRxWI = (PRXWI_STRUC) pData; ++ pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); ++ RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); ++#endif ++ ++ // build RxCell ++ RxCell.pRxWI = pRxWI; ++ RxCell.pHeader = pHeader; ++ RxCell.pRxPacket = pRxPacket; ++ RxCell.pData = (UCHAR *) pHeader; ++ RxCell.DataSize = pRxWI->MPDUtotalByteCount; ++ RxCell.Flags = 0; ++ ++ // Increase Total receive byte counter after real data received no mater any error or not ++ pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount; ++ pAd->RalinkCounters.RxCount ++; ++ ++ INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); ++ ++ if (pRxWI->MPDUtotalByteCount < 14) ++ Status = NDIS_STATUS_FAILURE; ++ ++ if (MONITOR_ON(pAd)) ++ { ++ send_monitor_packets(pAd, &RxCell); ++ break; ++ } ++ /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ pAd->ate.RxCntPerSec++; ++ ATESampleRssi(pAd, pRxWI); ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQARxStart == TRUE) ++ { ++ /* (*pRxD) has been swapped in GetPacketFromRxRing() */ ++ ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); ++ } ++#endif // RALINK_28xx_QA // ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); ++ continue; ++ } ++#endif // RALINK_ATE // ++ ++ // Check for all RxD errors ++ Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); ++ ++ // Handle the received frame ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ switch (pHeader->FC.Type) ++ { ++ // CASE I, receive a DATA frame ++ case BTYPE_DATA: ++ { ++ // process DATA frame ++ STAHandleRxDataFrame(pAd, &RxCell); ++ } ++ break; ++ // CASE II, receive a MGMT frame ++ case BTYPE_MGMT: ++ { ++ STAHandleRxMgmtFrame(pAd, &RxCell); ++ } ++ break; ++ // CASE III. receive a CNTL frame ++ case BTYPE_CNTL: ++ { ++ STAHandleRxControlFrame(pAd, &RxCell); ++ } ++ break; ++ // discard other type ++ default: ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ break; ++ } ++ } ++ else ++ { ++ pAd->Counters8023.RxErrors++; ++ // discard this frame ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ } ++ ++ return bReschedule; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Arguments: ++ pAd Pointer to our adapter ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPHandleTwakeupInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ AsicForceWakeup(pAd, FALSE); ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Early checking and OS-depened parsing for Tx packet send to our STA driver. ++ ++Arguments: ++ NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. ++ PPNDIS_PACKET ppPacketArray The packet array need to do transmission. ++ UINT NumberOfPackets Number of packet in packet array. ++ ++Return Value: ++ NONE ++ ++Note: ++ This function do early checking and classification for send-out packet. ++ You only can put OS-depened & STA related code in here. ++======================================================================== ++*/ ++VOID STASendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets) ++{ ++ UINT Index; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext; ++ PNDIS_PACKET pPacket; ++ BOOLEAN allowToSend = FALSE; ++ ++ ++ for (Index = 0; Index < NumberOfPackets; Index++) ++ { ++ pPacket = ppPacketArray[Index]; ++ ++ do ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ { ++ // Drop send request since hardware is in reset state ++ break; ++ } ++ else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) ++ { ++ // Drop send request since there are no physical connection yet ++ break; ++ } ++ else ++ { ++ // Record that orignal packet source is from NDIS layer,so that ++ // later on driver knows how to release this NDIS PACKET ++#ifdef QOS_DLS_SUPPORT ++ MAC_TABLE_ENTRY *pEntry; ++ PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ ++ pEntry = MacTableLookup(pAd, pSrcBufVA); ++ if (pEntry && (pEntry->ValidAsDls == TRUE)) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++ NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); ++ pAd->RalinkCounters.PendingNdisPacketCount++; ++ ++ allowToSend = TRUE; ++ } ++ } while(FALSE); ++ ++ if (allowToSend == TRUE) ++ STASendPacket(pAd, pPacket); ++ else ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ ++ // Dequeue outgoing frames from TxSwQueue[] and process it ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ This routine is used to do packet parsing and classification for Tx packet ++ to STA device, and it will en-queue packets to our TxSwQueue depends on AC ++ class. ++ ++Arguments: ++ pAd Pointer to our adapter ++ pPacket Pointer to send packet ++ ++Return Value: ++ NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue. ++ NDIS_STATUS_FAILURE If failed to do en-queue. ++ ++Note: ++ You only can put OS-indepened & STA related code in here. ++======================================================================== ++*/ ++NDIS_STATUS STASendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ UINT AllowFragSize; ++ UCHAR NumberOfFrag; ++ UCHAR QueIdx, UserPriority; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ unsigned int IrqFlags; ++ UCHAR FlgIsIP = 0; ++ UCHAR Rate; ++ ++ // Prepare packet information structure for buffer descriptor ++ // chained within a single NDIS packet. ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ if (pSrcBufVA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen)); ++ // Resourece is low, system did not allocate virtual address ++ // return NDIS_STATUS_FAILURE directly to upper layer ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++ if (SrcBufLen < 14) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++ // In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. ++ // Note multicast packets in adhoc also use BSSID_WCID index. ++ { ++ if(INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ USHORT tmpWcid; ++ ++ tmpWcid = RTMP_GET_PACKET_WCID(pPacket); ++ if (VALID_WCID(tmpWcid) && ++ (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) ++ { ++ pEntry = &pAd->MacTab.Content[tmpWcid]; ++ Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); ++ Rate = pAd->CommonCfg.TxRate; ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ if (*pSrcBufVA & 0x01) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); ++ pEntry = &pAd->MacTab.Content[MCAST_WCID]; ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAd, pSrcBufVA); ++ } ++ Rate = pAd->CommonCfg.TxRate; ++ } ++ } ++ ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA))); ++ // Resourece is low, system did not allocate virtual address ++ // return NDIS_STATUS_FAILURE directly to upper layer ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ if (ADHOC_ON(pAd) ++ ) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid); ++ } ++ ++ // ++ // Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. ++ // Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). ++ RTMPCheckEtherType(pAd, pPacket); ++ ++ ++ ++ // ++ // WPA 802.1x secured port control - drop all non-802.1x frame before port secured ++ // ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef WPA_SUPPLICANT_SUPPORT ++ || (pAd->StaCfg.IEEE8021X == TRUE) ++#endif // WPA_SUPPLICANT_SUPPORT // ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) ++ && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++ ++ // STEP 1. Decide number of fragments required to deliver this MSDU. ++ // The estimation here is not very accurate because difficult to ++ // take encryption overhead into consideration here. The result ++ // "NumberOfFrag" is then just used to pre-check if enough free ++ // TXD are available to hold this MSDU. ++ ++ ++ if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast ++ NumberOfFrag = 1; ++ else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) ++ NumberOfFrag = 1; // Aggregation overwhelms fragmentation ++ else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) ++ NumberOfFrag = 1; // Aggregation overwhelms fragmentation ++#ifdef DOT11_N_SUPPORT ++ else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) ++ NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation ++#endif // DOT11_N_SUPPORT // ++ else ++ { ++ // The calculated "NumberOfFrag" is a rough estimation because of various ++ // encryption/encapsulation overhead not taken into consideration. This number is just ++ // used to make sure enough free TXD are available before fragmentation takes place. ++ // In case the actual required number of fragments of an NDIS packet ++ // excceeds "NumberOfFrag"caculated here and not enough free TXD available, the ++ // last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of ++ // resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should ++ // rarely happen and the penalty is just like a TX RETRY fail. Affordable. ++ ++ AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; ++ NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; ++ // To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size ++ if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) ++ { ++ NumberOfFrag--; ++ } ++ } ++ ++ // Save fragment number to Ndis packet reserved field ++ RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); ++ ++ ++ // STEP 2. Check the requirement of RTS: ++ // If multiple fragment required, RTS is required only for the first fragment ++ // if the fragment size large than RTS threshold ++ // For RT28xx, Let ASIC send RTS/CTS ++ RTMP_SET_PACKET_RTS(pPacket, 0); ++ RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); ++ ++ // ++ // STEP 3. Traffic classification. outcome = ++ // ++ UserPriority = 0; ++ QueIdx = QID_AC_BE; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) ++ { ++ USHORT Protocol; ++ UCHAR LlcSnapLen = 0, Byte0, Byte1; ++ do ++ { ++ // get Ethernet protocol field ++ Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); ++ if (Protocol <= 1500) ++ { ++ // get Ethernet protocol field from LLC/SNAP ++ if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) ++ break; ++ ++ Protocol = (USHORT)((Byte0 << 8) + Byte1); ++ LlcSnapLen = 8; ++ } ++ ++ // always AC_BE for non-IP packet ++ if (Protocol != 0x0800) ++ break; ++ ++ // get IP header ++ if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) ++ break; ++ ++ // return AC_BE if packet is not IPv4 ++ if ((Byte0 & 0xf0) != 0x40) ++ break; ++ ++ FlgIsIP = 1; ++ UserPriority = (Byte1 & 0xe0) >> 5; ++ QueIdx = MapUserPriorityToAccessCategory[UserPriority]; ++ ++ // TODO: have to check ACM bit. apply TSPEC if ACM is ON ++ // TODO: downgrade UP & QueIdx before passing ACM ++ if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) ++ { ++ UserPriority = 0; ++ QueIdx = QID_AC_BE; ++ } ++ } while (FALSE); ++ } ++ ++ RTMP_SET_PACKET_UP(pPacket, UserPriority); ++ ++ ++ ++ // Make sure SendTxWait queue resource won't be used by other threads ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++ if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++#ifdef BLOCK_NET_IF ++ StopNetIfQueue(pAd, QueIdx, pPacket); ++#endif // BLOCK_NET_IF // ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ ++ return NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket)); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& ++ (pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) ++ { ++ if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1<PortSecured == WPA_802_1X_PORT_SECURED) ++ // For IOT compatibility, if ++ // 1. It is Ralink chip or ++ // 2. It is OPEN or AES mode, ++ // then BA session can be bulit. ++ && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) || ++ (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled)) ++ ) ++ { ++ BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ This subroutine will scan through releative ring descriptor to find ++ out avaliable free ring descriptor and compare with request size. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ QueIdx Selected TX Ring ++ ++ Return Value: ++ NDIS_STATUS_FAILURE Not enough free descriptor ++ NDIS_STATUS_SUCCESS Enough free descriptor ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#ifdef RT2860 ++NDIS_STATUS RTMPFreeTXDRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR NumberRequired, ++ IN PUCHAR FreeNumberIs) ++{ ++ ULONG FreeNumber = 0; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ ++ switch (QueIdx) ++ { ++ case QID_AC_BK: ++ case QID_AC_BE: ++ case QID_AC_VI: ++ case QID_AC_VO: ++ case QID_HCCA: ++ if (pAd->TxRing[QueIdx].TxSwFreeIdx > pAd->TxRing[QueIdx].TxCpuIdx) ++ FreeNumber = pAd->TxRing[QueIdx].TxSwFreeIdx - pAd->TxRing[QueIdx].TxCpuIdx - 1; ++ else ++ FreeNumber = pAd->TxRing[QueIdx].TxSwFreeIdx + TX_RING_SIZE - pAd->TxRing[QueIdx].TxCpuIdx - 1; ++ ++ if (FreeNumber >= NumberRequired) ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ ++ case QID_MGMT: ++ if (pAd->MgmtRing.TxSwFreeIdx > pAd->MgmtRing.TxCpuIdx) ++ FreeNumber = pAd->MgmtRing.TxSwFreeIdx - pAd->MgmtRing.TxCpuIdx - 1; ++ else ++ FreeNumber = pAd->MgmtRing.TxSwFreeIdx + MGMT_RING_SIZE - pAd->MgmtRing.TxCpuIdx - 1; ++ ++ if (FreeNumber >= NumberRequired) ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); ++ break; ++ } ++ *FreeNumberIs = (UCHAR)FreeNumber; ++ ++ return (Status); ++} ++#endif // RT2860 // ++ ++ ++ ++VOID RTMPSendDisassociationFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++} ++ ++VOID RTMPSendNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull) ++{ ++ UCHAR NullFrame[48]; ++ ULONG Length; ++ PHEADER_802_11 pHeader_802_11; ++ ++ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ // WPA 802.1x secured port control ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef WPA_SUPPLICANT_SUPPORT ++ || (pAd->StaCfg.IEEE8021X == TRUE) ++#endif ++ ) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ return; ++ } ++ ++ NdisZeroMemory(NullFrame, 48); ++ Length = sizeof(HEADER_802_11); ++ ++ pHeader_802_11 = (PHEADER_802_11) NullFrame; ++ ++ pHeader_802_11->FC.Type = BTYPE_DATA; ++ pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; ++ pHeader_802_11->FC.ToDs = 1; ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ } ++ else ++ { ++ pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0; ++ } ++ pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); ++ ++ pAd->Sequence++; ++ pHeader_802_11->Sequence = pAd->Sequence; ++ ++ // Prepare QosNull function frame ++ if (bQosNull) ++ { ++ pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; ++ ++ // copy QOS control bytes ++ NullFrame[Length] = 0; ++ NullFrame[Length+1] = 0; ++ Length += 2;// if pad with 2 bytes for alignment, APSD will fail ++ } ++ ++ HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); ++ ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID RTMPSendRTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN unsigned int NextMpduSize, ++ IN UCHAR TxRate, ++ IN UCHAR RTSRate, ++ IN USHORT AckDuration, ++ IN UCHAR QueIdx, ++ IN UCHAR FrameGap) ++{ ++} ++ ++ ++ ++// -------------------------------------------------------- ++// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM ++// Find the WPA key, either Group or Pairwise Key ++// LEAP + TKIP also use WPA key. ++// -------------------------------------------------------- ++// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst ++// In Cisco CCX 2.0 Leap Authentication ++// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey ++// Instead of the SharedKey, SharedKey Length may be Zero. ++VOID STAFindCipherAlgorithm( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet ++ UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm ++ UCHAR KeyIdx = 0xff; ++ PUCHAR pSrcBufVA; ++ PCIPHER_KEY pKey = NULL; ++ ++ pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); ++ ++ { ++ // Select Cipher ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) ++ Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast ++ else ++ Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast ++ ++ if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) ++ { ++ ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128); ++ ++ // 4-way handshaking frame must be clear ++ if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) && ++ (pAd->SharedKey[BSS0][0].KeyLen)) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ KeyIdx = 0; ++ } ++ } ++ else if (Cipher == Ndis802_11Encryption1Enabled) ++ { ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on ++ { ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) ++ KeyIdx = 1; ++ else ++ KeyIdx = 0; ++ } ++ else ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ else if (LEAP_CCKM_ON(pAd)) ++ { ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) ++ KeyIdx = 1; ++ else ++ KeyIdx = 0; ++ } ++ else // standard WEP64 or WEP128 ++#endif // LEAP_SUPPORT // ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ else if ((Cipher == Ndis802_11Encryption2Enabled) || ++ (Cipher == Ndis802_11Encryption3Enabled)) ++ { ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ else if (pAd->SharedKey[BSS0][0].KeyLen) ++ KeyIdx = 0; ++ else ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ ++ if (KeyIdx == 0xff) ++ CipherAlg = CIPHER_NONE; ++ else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) ++ CipherAlg = CIPHER_NONE; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ( pAd->StaCfg.WpaSupplicantUP && ++ (Cipher == Ndis802_11Encryption1Enabled) && ++ (pAd->StaCfg.IEEE8021X == TRUE) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ CipherAlg = CIPHER_NONE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ //Header_802_11.FC.Wep = 1; ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ pKey = &pAd->SharedKey[BSS0][KeyIdx]; ++ } ++ } ++ ++ pTxBlk->CipherAlg = CipherAlg; ++ pTxBlk->pKey = pKey; ++} ++ ++ ++VOID STABuildCommon802_11Header( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ ++ HEADER_802_11 *pHeader_802_11; ++#ifdef QOS_DLS_SUPPORT ++ BOOLEAN bDLSFrame = FALSE; ++ INT DlsEntryIndex = 0; ++#endif // QOS_DLS_SUPPORT // ++ ++ // ++ // MAKE A COMMON 802.11 HEADER ++ // ++ ++ // normal wlan header size : 24 octets ++ pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); ++ ++ pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ ++ NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11)); ++ ++ pHeader_802_11->FC.FrDs = 0; ++ pHeader_802_11->FC.Type = BTYPE_DATA; ++ pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); ++ ++#ifdef QOS_DLS_SUPPORT ++ if (INFRA_ON(pAd)) ++ { ++ // Check if the frame can be sent through DLS direct link interface ++ // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) ++ DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); ++ if (DlsEntryIndex >= 0) ++ bDLSFrame = TRUE; ++ else ++ bDLSFrame = FALSE; ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ if (pTxBlk->pMacEntry) ++ { ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) ++ { ++ pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq; ++ pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ; ++ } ++ else ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ pHeader_802_11->Sequence = pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence; ++ pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence = (pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence+1) & MAXSEQ; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; ++ pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; ++ } ++ } ++ } ++ else ++ { ++ pHeader_802_11->Sequence = pAd->Sequence; ++ pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence ++ } ++ ++ pHeader_802_11->Frag = 0; ++ ++ pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); ++ ++ { ++ if (INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ pHeader_802_11->FC.ToDs = 0; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader); ++ pHeader_802_11->FC.ToDs = 1; ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ pHeader_802_11->FC.ToDs = 0; ++ } ++ } ++ ++ if (pTxBlk->CipherAlg != CIPHER_NONE) ++ pHeader_802_11->FC.Wep = 1; ++ ++ // ----------------------------------------------------------------- ++ // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. ++ // ----------------------------------------------------------------- ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID STABuildCache802_11Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR *pHeader) ++{ ++ MAC_TABLE_ENTRY *pMacEntry; ++ PHEADER_802_11 pHeader80211; ++ ++ pHeader80211 = (PHEADER_802_11)pHeader; ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ // ++ // Update the cached 802.11 HEADER ++ // ++ ++ // normal wlan header size : 24 octets ++ pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); ++ ++ // More Bit ++ pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); ++ ++ // Sequence ++ pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; ++ pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; ++ ++ { ++ // Check if the frame can be sent through DLS direct link interface ++ // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) ++#ifdef QOS_DLS_SUPPORT ++ BOOLEAN bDLSFrame = FALSE; ++ INT DlsEntryIndex = 0; ++ ++ DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); ++ if (DlsEntryIndex >= 0) ++ bDLSFrame = TRUE; ++ else ++ bDLSFrame = FALSE; ++#endif // QOS_DLS_SUPPORT // ++ ++ // The addr3 of normal packet send from DS is Dest Mac address. ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); ++ pHeader80211->FC.ToDs = 0; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ if (ADHOC_ON(pAd)) ++ COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); ++ else ++ COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader); ++ } ++ ++ // ----------------------------------------------------------------- ++ // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. ++ // ----------------------------------------------------------------- ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ pHeader80211->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++} ++#endif // DOT11_N_SUPPORT // ++ ++static inline PUCHAR STA_Build_ARalink_Frame_Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ HEADER_802_11 *pHeader_802_11; ++ PNDIS_PACKET pNextPacket; ++ UINT32 nextBufLen; ++ PQUEUE_ENTRY pQEntry; ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // steal "order" bit to mark "aggregation" ++ pHeader_802_11->FC.Order = 1; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // padding at front of LLC header. LLC header should at 4-bytes aligment. ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ // For RA Aggregation, ++ // put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format ++ pQEntry = pTxBlk->TxPacketList.Head; ++ pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry); ++ nextBufLen = GET_OS_PKT_LEN(pNextPacket); ++ if (RTMP_GET_PACKET_VLAN(pNextPacket)) ++ nextBufLen -= LENGTH_802_1Q; ++ ++ *pHeaderBufPtr = (UCHAR)nextBufLen & 0xff; ++ *(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8); ++ ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ return pHeaderBufPtr; ++ ++} ++ ++#ifdef DOT11_N_SUPPORT ++static inline PUCHAR STA_Build_AMSDU_Frame_Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr;//, pSaveBufPtr; ++ HEADER_802_11 *pHeader_802_11; ++ ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ // ++ // A-MSDU packet ++ // ++ *pHeaderBufPtr |= 0x80; ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ //pSaveBufPtr = pHeaderBufPtr; ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ // @@@ MpduHeaderLen excluding padding @@@ ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ return pHeaderBufPtr; ++ ++} ++ ++ ++VOID STA_AMPDU_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ MAC_TABLE_ENTRY *pMacEntry; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ASSERT(pTxBlk); ++ ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ pMacEntry = pTxBlk->pMacEntry; ++ if (pMacEntry->isCached) ++ { ++ // NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! ++ NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11)); ++ pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); ++ STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); ++ } ++ else ++ { ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ } ++ ++ ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ // ++ // build HTC+ ++ // HTC control filed following QoS field ++ // ++ if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)) ++ { ++ if (pMacEntry->isCached == FALSE) ++ { ++ // mark HTC bit ++ pHeader_802_11->FC.Order = 1; ++ ++ NdisZeroMemory(pHeaderBufPtr, 4); ++ *(pHeaderBufPtr+3) |= 0x80; ++ } ++ pHeaderBufPtr += 4; ++ pTxBlk->MpduHeaderLen += 4; ++ } ++ ++ //pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; ++ ASSERT(pTxBlk->MpduHeaderLen >= 24); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ // @@@ MpduHeaderLen excluding padding @@@ ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ { ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ } ++ ++ if (pMacEntry->isCached) ++ { ++ RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ } ++ else ++ { ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf)); ++ NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]))); ++ pMacEntry->isCached = TRUE; ++ } ++ ++ // calculate Transmitted AMPDU count and ByteCount ++ { ++ pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++; ++ pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen; ++ } ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ } ++ ++} ++ ++ ++VOID STA_AMSDU_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding. ++ USHORT totalMPDUSize=0; ++ UCHAR *subFrameHeader; ++ UCHAR padding = 0; ++ USHORT FirstTx = 0, LastTxIdx = 0; ++ BOOLEAN bVLANPkt; ++ int frameNum = 0; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ ASSERT((pTxBlk->TxPacketList.Number > 1)); ++ ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ if (frameNum == 0) ++ { ++ pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); ++ ++ // NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ } ++ else ++ { ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; ++ padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen); ++ NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD); ++ pHeaderBufPtr += padding; ++ pTxBlk->MpduHeaderLen = padding; ++ } ++ ++ // ++ // A-MSDU subframe ++ // DA(6)+SA(6)+Length(2) + LLC/SNAP Encap ++ // ++ subFrameHeader = pHeaderBufPtr; ++ subFramePayloadLen = pTxBlk->SrcBufLen; ++ ++ NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); ++ ++ ++ pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; ++ pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ ++ subFramePayloadLen = pTxBlk->SrcBufLen; ++ ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ subFramePayloadLen += LENGTH_802_1_H; ++ } ++ ++ // update subFrame Length field ++ subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; ++ subFrameHeader[13] = subFramePayloadLen & 0xFF; ++ ++ totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++ if (frameNum ==0) ++ FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ else ++ LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ ++ frameNum++; ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // calculate Transmitted AMSDU Count and ByteCount ++ { ++ pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++; ++ pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize; ++ } ++ ++ } ++ ++ HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); ++ HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID STA_Legacy_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ASSERT(pTxBlk); ++ ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ if (pTxBlk->TxFrameType == TX_MCAST_FRAME) ++ { ++ INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); ++ } ++ ++ if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); ++ else ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) ++ pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // The remaining content of MPDU header should locate at 4-octets aligment ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ { ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ // ++ // if original Ethernet frame contains no LLC/SNAP, ++ // then an extra LLC/SNAP encap is required ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ UCHAR vlan_size; ++ ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // skip vlan tag ++ vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ } ++ ++ // ++ // prepare for TXWI ++ // use Wcid as Key Index ++ // ++ ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++ ++ ++VOID STA_ARalink_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ USHORT totalMPDUSize=0; ++ USHORT FirstTx, LastTxIdx; ++ int frameNum = 0; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ ASSERT((pTxBlk->TxPacketList.Number== 2)); ++ ++ ++ FirstTx = LastTxIdx = 0; // Is it ok init they as 0? ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ if (frameNum == 0) ++ { // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header ++ ++ pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk); ++ ++ // It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount ++ // will be updated after final frame was handled. ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ } ++ else ++ { // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; ++ pTxBlk->MpduHeaderLen = 0; ++ ++ // A-Ralink sub-sequent frame header is the same as 802.3 header. ++ // DA(6)+SA(6)+FrameType(2) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12); ++ pHeaderBufPtr += 12; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; ++ } ++ ++ totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ if (frameNum ==0) ++ FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ else ++ LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ ++ frameNum++; ++ ++ pAd->RalinkCounters.OneSecTxAggregationCount++; ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ } ++ ++ HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); ++ HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ ++} ++ ++ ++VOID STA_Fragment_Frame_Tx( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ UCHAR fragNum = 0; ++ PACKET_INFO PacketInfo; ++ USHORT EncryptionOverhead = 0; ++ UINT32 FreeMpduSize, SrcRemainingBytes; ++ USHORT AckDuration; ++ UINT NextMpduSize; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ { ++ pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); ++ if (pTxBlk->pPacket == NULL) ++ return; ++ RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); ++ } ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr; ++ ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ // ++ // if original Ethernet frame contains no LLC/SNAP, ++ // then an extra LLC/SNAP encap is required ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ UCHAR vlan_size; ++ ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // skip vlan tag ++ vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ ++ // If TKIP is used and fragmentation is required. Driver has to ++ // append TKIP MIC at tail of the scatter buffer ++ // MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC ++ if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ { ++ ++ // NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust ++ // to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. ++ NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); ++ //skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); ++ pTxBlk->SrcBufLen += 8; ++ pTxBlk->TotalFrameLen += 8; ++ pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; ++ } ++ ++ // ++ // calcuate the overhead bytes that encryption algorithm may add. This ++ // affects the calculate of "duration" field ++ // ++ if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128)) ++ EncryptionOverhead = 8; //WEP: IV[4] + ICV[4]; ++ else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) ++ EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength ++ else if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] ++ else if (pTxBlk->CipherAlg == CIPHER_AES) ++ EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8] ++ else ++ EncryptionOverhead = 0; ++ ++ // decide how much time an ACK/CTS frame will consume in the air ++ AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14); ++ ++ // Init the total payload length of this frame. ++ SrcRemainingBytes = pTxBlk->SrcBufLen; ++ ++ pTxBlk->TotalFragNum = 0xff; ++ ++ do { ++ ++ FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; ++ ++ FreeMpduSize -= pTxBlk->MpduHeaderLen; ++ ++ if (SrcRemainingBytes <= FreeMpduSize) ++ { // this is the last or only fragment ++ ++ pTxBlk->SrcBufLen = SrcRemainingBytes; ++ ++ pHeader_802_11->FC.MoreFrag = 0; ++ pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration; ++ ++ // Indicate the lower layer that this's the last fragment. ++ pTxBlk->TotalFragNum = fragNum; ++ } ++ else ++ { // more fragment is required ++ ++ pTxBlk->SrcBufLen = FreeMpduSize; ++ ++ NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold)); ++ pHeader_802_11->FC.MoreFrag = 1; ++ pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead); ++ } ++ ++ if (fragNum == 0) ++ pTxBlk->FrameGap = IFS_HTTXOP; ++ else ++ pTxBlk->FrameGap = IFS_SIFS; ++ ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // Update the frame number, remaining size of the NDIS packet payload. ++ ++ // space for 802.11 header. ++ if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) ++ pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; ++ ++ fragNum++; ++ SrcRemainingBytes -= pTxBlk->SrcBufLen; ++ pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; ++ ++ pHeader_802_11->Frag++; // increase Frag # ++ ++ }while(SrcRemainingBytes > 0); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++ ++ ++#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ ++ while(_pTxBlk->TxPacketList.Head) \ ++ { \ ++ _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ ++ RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ ++ } ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware encryption before really ++ sent out to air. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to outgoing Ndis frame ++ NumberOfFrag Number of fragment required ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS STAHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx) ++{ ++ NDIS_PACKET *pPacket; ++ PQUEUE_ENTRY pQEntry; ++ ++ // --------------------------------------------- ++ // STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. ++ // --------------------------------------------- ++ // ++ ASSERT(pTxBlk->TxPacketList.Number); ++ if (pTxBlk->TxPacketList.Head == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number)); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); ++ ++#if 0 //def CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ if ((pAd->CommonCfg.CarrierDetect.Enable == TRUE) && (isCarrierDetectExist(pAd) == TRUE)) ++ { ++ DBGPRINT(RT_DEBUG_INFO,("STAHardTransmit --> radar detect not in normal mode !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return (NDIS_STATUS_FAILURE); ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ // ------------------------------------------------------------------ ++ // STEP 1. WAKE UP PHY ++ // outgoing frame always wakeup PHY to prevent frame lost and ++ // turn off PSM bit to improve performance ++ // ------------------------------------------------------------------ ++ // not to change PSM bit, just send this frame out? ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); ++ AsicForceWakeup(pAd, TRUE); ++ } ++ ++ // It should not change PSM bit, when APSD turn on. ++ if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) ++ || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) ++ || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) ++ { ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && ++ (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP)) ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ } ++ ++ switch (pTxBlk->TxFrameType) ++ { ++#ifdef DOT11_N_SUPPORT ++ case TX_AMPDU_FRAME: ++ STA_AMPDU_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_AMSDU_FRAME: ++ STA_AMSDU_Frame_Tx(pAd, pTxBlk); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case TX_LEGACY_FRAME: ++ STA_Legacy_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_MCAST_FRAME: ++ STA_Legacy_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_RALINK_FRAME: ++ STA_ARalink_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_FRAG_FRAME: ++ STA_Fragment_Frame_Tx(pAd, pTxBlk); ++ break; ++ default: ++ { ++ // It should not happened! ++ DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n")); ++ while(pTxBlk->TxPacketList.Number) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (pPacket) ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ } ++ break; ++ } ++ ++ return (NDIS_STATUS_SUCCESS); ++ ++} ++ ++ULONG HashBytesPolynomial(UCHAR *value, unsigned int len) ++{ ++ unsigned char *word = value; ++ unsigned int ret = 0; ++ unsigned int i; ++ ++ for(i=0; i < len; i++) ++ { ++ int mod = i % 32; ++ ret ^=(unsigned int) (word[i]) << mod; ++ ret ^=(unsigned int) (word[i]) >> (32 - mod); ++ } ++ return ret; ++} ++ ++VOID Sta_Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID) ++{ ++ if (TRUE ++ ) ++ { ++ announce_802_3_packet(pAd, pPacket); ++ } ++ else ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/sanity.c +@@ -0,0 +1,420 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sanity.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 add WMM support ++*/ ++#include "../rt_config.h" ++ ++extern UCHAR CISCO_OUI[]; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR BROADCOM_OUI[]; ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeStartReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen) ++{ ++ MLME_START_REQ_STRUCT *Info; ++ ++ Info = (MLME_START_REQ_STRUCT *)(Msg); ++ ++ if (Info->SsidLen > MAX_LEN_OF_SSID) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqSanity fail - wrong SSID length\n")); ++ return FALSE; ++ } ++ ++ *pSsidLen = Info->SsidLen; ++ NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT USHORT *pAid, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ OUT UCHAR *pHtCapabilityLen, ++ OUT UCHAR *pAddHtInfoLen, ++ OUT UCHAR *pNewExtChannelOffset, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT UCHAR *pCkipFlag) ++{ ++ CHAR IeType, *Ptr; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PEID_STRUCT pEid; ++ ULONG Length = 0; ++ ++ *pNewExtChannelOffset = 0xff; ++ *pHtCapabilityLen = 0; ++ *pAddHtInfoLen = 0; ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2); ++ Length += 2; ++ NdisMoveMemory(pStatus, &pFrame->Octet[2], 2); ++ Length += 2; ++ *pCkipFlag = 0; ++ *pExtRateLen = 0; ++ pEdcaParm->bValid = FALSE; ++ ++ if (*pStatus != MLME_SUCCESS) ++ return TRUE; ++ ++ NdisMoveMemory(pAid, &pFrame->Octet[4], 2); ++ Length += 2; ++ ++ // Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform ++ *pAid = (*pAid) & 0x3fff; // AID is low 14-bit ++ ++ // -- get supported rates from payload and advance the pointer ++ IeType = pFrame->Octet[6]; ++ *pSupRateLen = pFrame->Octet[7]; ++ if ((IeType != IE_SUPP_RATES) || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity fail - wrong SupportedRates IE\n")); ++ return FALSE; ++ } ++ else ++ NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen); ++ ++ Length = Length + 2 + *pSupRateLen; ++ ++ // many AP implement proprietary IEs in non-standard order, we'd better ++ // tolerate mis-ordered IEs to get best compatibility ++ pEid = (PEID_STRUCT) &pFrame->Octet[8 + (*pSupRateLen)]; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ switch (pEid->Eid) ++ { ++ case IE_EXT_SUPP_RATES: ++ if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); ++ *pExtRateLen = pEid->Len; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ case IE_HT_CAP2: ++ if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! ++ { ++ NdisMoveMemory(pHtCapability, pEid->Octet, SIZE_HT_CAP_IE); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_HT_CAP. \n")); ++ } ++ ++ break; ++#ifdef DOT11_N_SUPPORT ++ case IE_ADD_HT: ++ case IE_ADD_HT2: ++ if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) ++ { ++ // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only ++ // copy first sizeof(ADD_HT_INFO_IE) ++ NdisMoveMemory(pAddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); ++ ++ *(USHORT *)(&pAddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo2)); ++ *(USHORT *)(&pAddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo3)); ++ ++ *pAddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_ADD_HT. \n")); ++ } ++ ++ break; ++ case IE_SECONDARY_CH_OFFSET: ++ if (pEid->Len == 1) ++ { ++ *pNewExtChannelOffset = pEid->Octet[0]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); ++ } ++#endif // DOT11_N_SUPPORT // ++ break; ++ case IE_AIRONET_CKIP: ++ // 0. Check Aironet IE length, it must be larger or equal to 28 ++ // Cisco's AP VxWork version(will not be supported) used this IE length as 28 ++ // Cisco's AP IOS version used this IE length as 30 ++ if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) ++ break; ++ ++ // 1. Copy CKIP flag byte to buffer for process ++ *pCkipFlag = *(pEid->Octet + 8); ++ break; ++ ++ case IE_AIRONET_IPADDRESS: ++ if (pEid->Len != 0x0A) ++ break; ++ ++ // Get Cisco Aironet IP information ++ if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) ++ NdisMoveMemory(pAd->StaCfg.AironetIPAddress, pEid->Octet + 4, 4); ++ break; ++ ++ // CCX2, WMM use the same IE value ++ // case IE_CCX_V2: ++ case IE_VENDOR_SPECIFIC: ++ // handle WME PARAMTER ELEMENT ++ if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) ++ { ++ PUCHAR ptr; ++ int i; ++ ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ //pEdcaParm->bMoreDataAck = FALSE; // pEid->Octet[0] & 0x80; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ptr = &pEid->Octet[8]; ++ for (i=0; i<4; i++) ++ { ++ UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX ++ pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM ++ pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN ++ pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin ++ pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax ++ pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us ++ ptr += 4; // point to next AC ++ } ++ } ++ ++ // handle CCX IE ++ else ++ { ++ // 0. Check the size and CCX admin control ++ if (pAd->StaCfg.CCXControl.field.Enable == 0) ++ break; ++ if (pEid->Len != 5) ++ break; ++ ++ // Turn CCX2 if matched ++ if (NdisEqualMemory(pEid->Octet, Ccx2IeInfo, 5) == 1) ++ pAd->StaCfg.CCXEnable = TRUE; ++ break; ++ } ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity - ignore unrecognized EID = %d\n", pEid->Eid)); ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ // Force CCX2 enable to TRUE for those AP didn't replay CCX v2 IE, we still force it to be on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ pAd->StaCfg.CCXEnable = TRUE; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen) ++{ ++ UCHAR Idx; ++ UCHAR RateLen; ++ CHAR IeType; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ ++ if ((pFrame->Octet[0] != IE_SSID) || (pFrame->Octet[1] > MAX_LEN_OF_SSID)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",pFrame->Octet[0],pFrame->Octet[1])); ++ return FALSE; ++ } ++ ++ *pSsidLen = pFrame->Octet[1]; ++ NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen); ++ ++ Idx = *pSsidLen + 2; ++ ++ // -- get supported rates from payload and advance the pointer ++ IeType = pFrame->Octet[Idx]; ++ RateLen = pFrame->Octet[Idx + 1]; ++ if (IeType != IE_SUPP_RATES) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",pFrame->Octet[Idx],pFrame->Octet[Idx+1])); ++ return FALSE; ++ } ++ else ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8)) ++ return (FALSE); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN GetTimBit( ++ IN CHAR *Ptr, ++ IN USHORT Aid, ++ OUT UCHAR *TimLen, ++ OUT UCHAR *BcastFlag, ++ OUT UCHAR *DtimCount, ++ OUT UCHAR *DtimPeriod, ++ OUT UCHAR *MessageToMe) ++{ ++ UCHAR BitCntl, N1, N2, MyByte, MyBit; ++ CHAR *IdxPtr; ++ ++ IdxPtr = Ptr; ++ ++ IdxPtr ++; ++ *TimLen = *IdxPtr; ++ ++ // get DTIM Count from TIM element ++ IdxPtr ++; ++ *DtimCount = *IdxPtr; ++ ++ // get DTIM Period from TIM element ++ IdxPtr++; ++ *DtimPeriod = *IdxPtr; ++ ++ // get Bitmap Control from TIM element ++ IdxPtr++; ++ BitCntl = *IdxPtr; ++ ++ if ((*DtimCount == 0) && (BitCntl & 0x01)) ++ *BcastFlag = TRUE; ++ else ++ *BcastFlag = FALSE; ++ ++ // Parse Partial Virtual Bitmap from TIM element ++ N1 = BitCntl & 0xfe; // N1 is the first bitmap byte# ++ N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte# ++ ++ if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3))) ++ *MessageToMe = FALSE; ++ else ++ { ++ MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream ++ MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0); ++ ++ IdxPtr += (MyByte + 1); ++ ++ //if (*IdxPtr) ++ // DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); ++ ++ if (*IdxPtr & (0x01 << MyBit)) ++ *MessageToMe = TRUE; ++ else ++ *MessageToMe = FALSE; ++ } ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/sync.c +@@ -0,0 +1,1961 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sync.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 modified for rt2561/2661 ++ Jan Lee 2006-08-01 modified for rt2860 for 802.11n ++*/ ++#include "../rt_config.h" ++ ++#define AC0_DEF_TXOP 0 ++#define AC1_DEF_TXOP 0 ++#define AC2_DEF_TXOP 94 ++#define AC3_DEF_TXOP 47 ++ ++VOID AdhocTurnOnQos( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Turn on QOs if use HT rate. ++ if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) ++ { ++ pAd->CommonCfg.APEdcaParm.bValid = TRUE; ++ pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; ++ pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; ++ pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; ++ pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; ++ pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10; ++ pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6; ++ pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; ++ ++ pAd->CommonCfg.APEdcaParm.Txop[0] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[1] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP; ++ pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP; ++ } ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ The sync state machine, ++ Parameters: ++ Sm - pointer to the state machine ++ Note: ++ the state machine looks like the following ++ ++ ========================================================================== ++ */ ++VOID SyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE); ++ ++ // column 1 ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction); ++ ++ //column 2 ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction); ++ ++ // column 3 ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction); ++ ++ // timer init ++ RTMPInitTimer(pAd, &pAd->MlmeAux.BeaconTimer, GET_TIMER_FUNCTION(BeaconTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.ScanTimer, GET_TIMER_FUNCTION(ScanTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Beacon timeout handler, executed in timer thread ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID BeaconTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SYNC - BeaconTimeout\n")); ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ++ ) ++ { ++ UCHAR BBPValue = 0; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan timeout handler, executed in timer thread ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++ if (MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL)) ++ { ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ else ++ { ++ // To prevent SyncMachine.CurrState is SCAN_LISTEN forever. ++ pAd->MlmeAux.Channel = 0; ++ ScanNextChannel(pAd); ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME SCAN req state machine procedure ++ ========================================================================== ++ */ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType, BBPValue = 0; ++ BOOLEAN TimerCancelled; ++ ULONG Now; ++ USHORT Status; ++ PHEADER_802_11 pHdr80211; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ++ // Check the total scan tries for one single OID command ++ // If this is the CCX 2.0 Case, skip that! ++ if ( !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeScanReqAction before Startup\n")); ++ return; ++ } ++ ++ // Increase the scan retry counters. ++ pAd->StaCfg.ScanCnt++; ++ ++#ifdef RT2860 ++ if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && ++ (IDLE_ON(pAd)) && ++ (pAd->StaCfg.bRadio == TRUE) && ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) ++ { ++ RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); ++ } ++#endif // RT2860 // ++ ++ // first check the parameter sanity ++ if (MlmeScanReqSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ &BssType, ++ Ssid, ++ &SsidLen, ++ &ScanType)) ++ { ++ ++ // Check for channel load and noise hist request ++ // Suspend MSDU only at scan request, not the last two mentioned ++ if ((ScanType == SCAN_CISCO_NOISE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD)) ++ { ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ RTMPSuspendMsduTransmission(pAd); // Suspend MSDU transmission here ++ } ++ else ++ { ++ // Suspend MSDU transmission here ++ RTMPSuspendMsduTransmission(pAd); ++ } ++ ++ // ++ // To prevent data lost. ++ // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. ++ // And should send an NULL data with turned PSM bit off to AP, when scan progress done ++ // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) ++ { ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ pHdr80211 = (PHEADER_802_11) pOutBuffer; ++ MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pHdr80211->Duration = 0; ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame for off channel RM\n")); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPusecDelay(5000); ++ } ++ } ++ ++ NdisGetSystemUpTime(&Now); ++ pAd->StaCfg.LastScanTime = Now; ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ ++ // record desired BSS parameters ++ pAd->MlmeAux.BssType = BssType; ++ pAd->MlmeAux.ScanType = ScanType; ++ pAd->MlmeAux.SsidLen = SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ ++ // start from the first channel ++ pAd->MlmeAux.Channel = FirstChannel(pAd); ++ ++ // Change the scan channel when dealing with CCX beacon report ++ if ((ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_ACTIVE) || ++ (ScanType == SCAN_CISCO_CHANNEL_LOAD) || (ScanType == SCAN_CISCO_NOISE)) ++ pAd->MlmeAux.Channel = pAd->StaCfg.CCXScanChannel; ++ ++ // Let BBP register at 20MHz to do scan ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ++ ScanNextChannel(pAd); ++ } ++ else ++ { ++ DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME JOIN req state machine procedure ++ ========================================================================== ++ */ ++VOID MlmeJoinReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR BBPValue = 0; ++ BSS_ENTRY *pBss; ++ BOOLEAN TimerCancelled; ++ HEADER_802_11 Hdr80211; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ PUCHAR pOutBuffer = NULL; ++ PUCHAR pSupRate = NULL; ++ UCHAR SupRateLen; ++ PUCHAR pExtRate = NULL; ++ UCHAR ExtRateLen; ++ UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C}; ++ UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR); ++ MLME_JOIN_REQ_STRUCT *pInfo = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); ++ ++#ifdef RT2860 ++ if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && ++ (IDLE_ON(pAd)) && ++ (pAd->StaCfg.bRadio == TRUE) && ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) ++ { ++ RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); ++ } ++#endif // RT2860 // ++ ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ pBss = &pAd->MlmeAux.SsidBssTab.BssEntry[pInfo->BssIdx]; ++ ++ // record the desired SSID & BSSID we're waiting for ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pBss->Bssid); ++ ++ // If AP's SSID is not hidden, it is OK for updating ssid to MlmeAux again. ++ if (pBss->Hidden == 0) ++ { ++ NdisMoveMemory(pAd->MlmeAux.Ssid, pBss->Ssid, pBss->SsidLen); ++ pAd->MlmeAux.SsidLen = pBss->SsidLen; ++ } ++ ++ pAd->MlmeAux.BssType = pBss->BssType; ++ pAd->MlmeAux.Channel = pBss->Channel; ++ pAd->MlmeAux.CentralChannel = pBss->CentralChannel; ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // Country IE of the AP will be evaluated and will be used. ++ if ((pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) && ++ (pBss->bHasCountryIE == TRUE)) ++ { ++ NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pBss->CountryString[0], 2); ++ if (pBss->CountryString[2] == 'I') ++ pAd->CommonCfg.Geography = IDOR; ++ else if (pBss->CountryString[2] == 'O') ++ pAd->CommonCfg.Geography = ODOR; ++ else ++ pAd->CommonCfg.Geography = BOTH; ++ BuildChannelListEx(pAd); ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Let BBP register at 20MHz to do scan ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ++ ++ // switch channel and waiting for beacon timer ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ RTMPSetTimer(&pAd->MlmeAux.BeaconTimer, JOIN_TIMEOUT); ++ ++ do ++ { ++ if (((pAd->CommonCfg.bIEEE80211H == 1) && ++ (pAd->MlmeAux.Channel > 14) && ++ RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ // ++ // We can't send any Probe request frame to meet 802.11h. ++ // ++ if (pBss->Hidden == 0) ++ break; ++ } ++ ++ // ++ // send probe request ++ // ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ if (pAd->MlmeAux.Channel <= 14) ++ { ++ pSupRate = pAd->CommonCfg.SupRate; ++ SupRateLen = pAd->CommonCfg.SupRateLen; ++ pExtRate = pAd->CommonCfg.ExtRate; ++ ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ } ++ else ++ { ++ // ++ // Overwrite Support Rate, CCK rate are not allowed ++ // ++ pSupRate = ASupRate; ++ SupRateLen = ASupRateLen; ++ ExtRateLen = 0; ++ } ++ ++ if (pAd->MlmeAux.BssType == BSS_INFRA) ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, pAd->MlmeAux.Bssid, pAd->MlmeAux.Bssid); ++ else ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &SupRateLen, ++ SupRateLen, pSupRate, ++ END_OF_ARGS); ++ ++ if (ExtRateLen) ++ { ++ ULONG Tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtRateIe, ++ 1, &ExtRateLen, ++ ExtRateLen, pExtRate, ++ END_OF_ARGS); ++ FrameLen += Tmp; ++ } ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } while (FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Switch to ch %d, Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ ++ pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME START Request state machine procedure, starting an IBSS ++ ========================================================================== ++ */ ++VOID MlmeStartReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen; ++ BOOLEAN TimerCancelled; ++ ++ // New for WPA security suites ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ LARGE_INTEGER TimeStamp; ++ BOOLEAN Privacy; ++ USHORT Status; ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ TimeStamp.u.LowPart = 0; ++ TimeStamp.u.HighPart = 0; ++ ++ if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen)) ++ { ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ // ++ // Start a new IBSS. All IBSS parameters are decided now.... ++ // ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - Start a new IBSS. All IBSS parameters are decided now.... \n")); ++ pAd->MlmeAux.BssType = BSS_ADHOC; ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ pAd->MlmeAux.SsidLen = SsidLen; ++ ++ // generate a radom number as BSSID ++ MacAddrRandomBssid(pAd, pAd->MlmeAux.Bssid); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - generate a radom number as BSSID \n")); ++ ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ pAd->MlmeAux.CapabilityInfo = CAP_GENERATE(0,1,Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 1, 0); ++ pAd->MlmeAux.BeaconPeriod = pAd->CommonCfg.BeaconPeriod; ++ pAd->MlmeAux.AtimWin = pAd->StaCfg.AtimWin; ++ pAd->MlmeAux.Channel = pAd->CommonCfg.Channel; ++ ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.CentralChannel; ++ ++ pAd->MlmeAux.SupRateLen= pAd->CommonCfg.SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); ++ pAd->MlmeAux.HtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ // Not turn pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE here. ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n")); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->MlmeAux.HtCapabilityLen = 0; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ } ++ // temporarily not support QOS in IBSS ++ NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeStartReqAction(ch= %d,sup rates= %d, ext rates=%d)\n", ++ pAd->MlmeAux.Channel, pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++ } ++ else ++ { ++ DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends beacon back when scanning ++ ========================================================================== ++ */ ++VOID PeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, NewChannel, ++ SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe; ++ CF_PARM CfParm; ++ USHORT BeaconPeriod, AtimWin, CapabilityInfo; ++ PFRAME_802_11 pFrame; ++ LARGE_INTEGER TimeStamp; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ USHORT LenVIE; ++ UCHAR CkipFlag; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ ULONG RalinkIe; ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ pFrame = (PFRAME_802_11) Elem->Msg; ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++#ifdef DOT11_N_SUPPORT ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++#endif // DOT11_N_SUPPORT // ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &CfParm, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ ULONG Idx; ++ CHAR Rssi = 0; ++ ++ Idx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Idx != BSS_NOT_FOUND) ++ Rssi = pAd->ScanTab.BssEntry[Idx].Rssi; ++ ++ Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ ++#ifdef DOT11_N_SUPPORT ++ if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) ++ HtCapabilityLen = SIZE_HT_CAP_IE; ++#endif // DOT11_N_SUPPORT // ++ if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel)) ++ { ++ Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen,ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++ if (Idx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(pAd->StaCfg.CCXBssTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ if (pAd->StaCfg.CCXReqType == MSRN_TYPE_BEACON_REQ) ++ AironetAddBeaconReport(pAd, Idx, Elem); ++ } ++ } ++ else ++ { ++ Idx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (pAd->ChannelList[pAd->CommonCfg.ChannelListIdx].bEffectedChannel == TRUE) ++ { ++ UCHAR RegClass; ++ PeerBeaconAndProbeRspSanity2(pAd, Elem->Msg, Elem->MsgLen, &RegClass); ++ TriEventTableSetEntry(pAd, &pAd->CommonCfg.TriggerEventTab, Bssid, &HtCapability, HtCapabilityLen, RegClass, Channel); ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ if (Idx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ } ++ } ++ } ++ // sanity check fail, ignored ++} ++ ++/* ++ ========================================================================== ++ Description: ++ When waiting joining the (I)BSS, beacon received from external ++ ========================================================================== ++ */ ++VOID PeerBeaconAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, MessageToMe, ++ DtimCount, DtimPeriod, BcastFlag, NewChannel; ++ LARGE_INTEGER TimeStamp; ++ USHORT BeaconPeriod, AtimWin, CapabilityInfo; ++ CF_PARM Cf; ++ BOOLEAN TimerCancelled; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ UCHAR CkipFlag; ++ USHORT LenVIE; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ USHORT Status; ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ ULONG RalinkIe; ++ ULONG Idx; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++#ifdef DOT11_N_SUPPORT ++ UCHAR CentralChannel; ++#endif // DOT11_N_SUPPORT // ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &Cf, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ // Disqualify 11b only adhoc when we are in 11g only adhoc mode ++ if ((BssType == BSS_ADHOC) && (pAd->CommonCfg.PhyMode == PHY_11G) && ((SupRateLen+ExtRateLen)< 12)) ++ return; ++ ++ // BEACON from desired BSS/IBSS found. We should be able to decide most ++ // BSS parameters here. ++ // Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? ++ // Do we need to receover back all parameters belonging to previous BSS? ++ // A. Should be not. There's no back-door recover to previous AP. It still need ++ // a new JOIN-AUTH-ASSOC sequence. ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - receive desired BEACON at JoinWaitBeacon... Channel = %d\n", Channel)); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ // Update RSSI to prevent No signal display when cards first initialized ++ pAd->StaCfg.RssiSample.LastRssi0 = ConvertToRssi(pAd, Elem->Rssi0, RSSI_0); ++ pAd->StaCfg.RssiSample.LastRssi1 = ConvertToRssi(pAd, Elem->Rssi1, RSSI_1); ++ pAd->StaCfg.RssiSample.LastRssi2 = ConvertToRssi(pAd, Elem->Rssi2, RSSI_2); ++ pAd->StaCfg.RssiSample.AvgRssi0 = pAd->StaCfg.RssiSample.LastRssi0; ++ pAd->StaCfg.RssiSample.AvgRssi0X8 = pAd->StaCfg.RssiSample.AvgRssi0 << 3; ++ pAd->StaCfg.RssiSample.AvgRssi1 = pAd->StaCfg.RssiSample.LastRssi1; ++ pAd->StaCfg.RssiSample.AvgRssi1X8 = pAd->StaCfg.RssiSample.AvgRssi1 << 3; ++ pAd->StaCfg.RssiSample.AvgRssi2 = pAd->StaCfg.RssiSample.LastRssi2; ++ pAd->StaCfg.RssiSample.AvgRssi2X8 = pAd->StaCfg.RssiSample.AvgRssi2 << 3; ++ ++ // ++ // We need to check if SSID only set to any, then we can record the current SSID. ++ // Otherwise will cause hidden SSID association failed. ++ // ++ if (pAd->MlmeAux.SsidLen == 0) ++ { ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ pAd->MlmeAux.SsidLen = SsidLen; ++ } ++ else ++ { ++ Idx = BssSsidTableSearch(&pAd->ScanTab, Bssid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Channel); ++ ++ if (Idx != BSS_NOT_FOUND) ++ { ++ // ++ // Multiple SSID case, used correct CapabilityInfo ++ // ++ CapabilityInfo = pAd->ScanTab.BssEntry[Idx].CapabilityInfo; ++ } ++ } ++ NdisMoveMemory(pAd->MlmeAux.Bssid, Bssid, MAC_ADDR_LEN); ++ pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; ++ pAd->MlmeAux.BssType = BssType; ++ pAd->MlmeAux.BeaconPeriod = BeaconPeriod; ++ pAd->MlmeAux.Channel = Channel; ++ pAd->MlmeAux.AtimWin = AtimWin; ++ pAd->MlmeAux.CfpPeriod = Cf.CfpPeriod; ++ pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration; ++ pAd->MlmeAux.APRalinkIe = RalinkIe; ++ ++ // Copy AP's supported rate to MlmeAux for creating assoication request ++ // Also filter out not supported rate ++ pAd->MlmeAux.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ pAd->MlmeAux.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++ ++ NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16); ++#ifdef DOT11_N_SUPPORT ++ pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; ++ pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen; ++ ++ // filter out un-supported ht rates ++ if (((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ ++ // StaActive.SupportedHtPhy.MCSSet stores Peer AP's 11n Rx capability ++ NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16); ++ pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; ++ pAd->MlmeAux.HtCapabilityLen = SIZE_HT_CAP_IE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ if (PreNHtCapabilityLen > 0) ++ pAd->StaActive.SupportedPhyInfo.bPreNHt = TRUE; ++ RTMPCheckHt(pAd, BSSID_WCID, &HtCapability, &AddHtInfo); ++ // Copy AP Parameter to StaActive. This is also in LinkUp. ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction! (MpduDensity=%d, MaxRAmpduFactor=%d, BW=%d)\n", ++ pAd->StaActive.SupportedHtPhy.MpduDensity, pAd->StaActive.SupportedHtPhy.MaxRAmpduFactor, HtCapability.HtCapInfo.ChannelWidth)); ++ ++ if (AddHtInfoLen > 0) ++ { ++ CentralChannel = AddHtInfo.ControlChan; ++ // Check again the Bandwidth capability of this AP. ++ if ((AddHtInfo.ControlChan > 2)&& (AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ CentralChannel = AddHtInfo.ControlChan - 2; ++ } ++ else if ((AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ CentralChannel = AddHtInfo.ControlChan + 2; ++ } ++ ++ // Check Error . ++ if (pAd->MlmeAux.CentralChannel != CentralChannel) ++ DBGPRINT(RT_DEBUG_ERROR, ("PeerBeaconAtJoinAction HT===>Beacon Central Channel = %d, Control Channel = %d. Mlmeaux CentralChannel = %d\n", CentralChannel, AddHtInfo.ControlChan, pAd->MlmeAux.CentralChannel)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction HT===>Central Channel = %d, Control Channel = %d, .\n", CentralChannel, AddHtInfo.ControlChan)); ++ ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // To prevent error, let legacy AP must have same CentralChannel and Channel. ++ if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0)) ++ pAd->MlmeAux.CentralChannel = pAd->MlmeAux.Channel; ++ ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ } ++ ++ RTMPUpdateMlmeRate(pAd); ++ ++ // copy QOS related information ++ if ((pAd->CommonCfg.bWmmCapable) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM)); ++ NdisMoveMemory(&pAd->MlmeAux.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisMoveMemory(&pAd->MlmeAux.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ else ++ { ++ NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n", ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); ++ ++#ifdef LEAP_SUPPORT ++ // Update CkipFlag ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ ++ // Keep TimeStamp for Re-Association used. ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ pAd->StaCfg.CCKMBeaconAtJoinTimeStamp = TimeStamp; ++#endif // LEAP_SUPPORT // ++ ++ if (AironetCellPowerLimit != 0xFF) ++ { ++ //We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power ++ ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); ++ } ++ else //Used the default TX Power Percentage. ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++ } ++ // not to me BEACON, ignored ++ } ++ // sanity check fail, ignore this frame ++} ++ ++/* ++ ========================================================================== ++ Description: ++ receive BEACON from peer ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ CF_PARM CfParm; ++ UCHAR SsidLen, MessageToMe=0, BssType, Channel, NewChannel, index=0; ++ UCHAR DtimCount=0, DtimPeriod=0, BcastFlag=0; ++ USHORT CapabilityInfo, AtimWin, BeaconPeriod; ++ LARGE_INTEGER TimeStamp; ++ USHORT TbttNumToNextWakeUp; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ UCHAR CkipFlag; ++ USHORT LenVIE; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ ULONG RalinkIe; ++ // New for WPA security suites ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen, PreNHtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ if (!(INFRA_ON(pAd) || ADHOC_ON(pAd) ++ )) ++ return; ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &CfParm, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ BOOLEAN is_my_bssid, is_my_ssid; ++ ULONG Bssidx, Now; ++ BSS_ENTRY *pBss; ++ CHAR RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ is_my_bssid = MAC_ADDR_EQUAL(Bssid, pAd->CommonCfg.Bssid)? TRUE : FALSE; ++ is_my_ssid = SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)? TRUE:FALSE; ++ ++ ++ // ignore BEACON not for my SSID ++ if ((! is_my_ssid) && (! is_my_bssid)) ++ return; ++ ++ // It means STA waits disassoc completely from this AP, ignores this beacon. ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC) ++ return; ++ ++#ifdef DOT11_N_SUPPORT ++ // Copy Control channel for this BSSID. ++ if (AddHtInfoLen != 0) ++ Channel = AddHtInfo.ControlChan; ++ ++ if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) ++ HtCapabilityLen = SIZE_HT_CAP_IE; ++#endif // DOT11_N_SUPPORT // ++ ++ // ++ // Housekeeping "SsidBssTab" table for later-on ROAMing usage. ++ // ++ Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ // discover new AP of this network, create BSS entry ++ Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &HtCapability, &AddHtInfo,HtCapabilityLen,AddHtInfoLen,NewExtChannelOffset, Channel, ++ RealRssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability, ++ &QbssLoad, LenVIE, pVIE); ++ if (Bssidx == BSS_NOT_FOUND) // return if BSS table full ++ return; ++ ++ NdisMoveMemory(pAd->ScanTab.BssEntry[Bssidx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ ++ ++ ++ } ++ ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) ++ { ++ // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). ++ // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. ++ AsicSwitchChannel(pAd, 1, FALSE); ++ AsicLockChannel(pAd, 1); ++ LinkDown(pAd, FALSE); ++ MlmeQueueInit(&pAd->Mlme.Queue); ++ BssTableInit(&pAd->ScanTab); ++ RTMPusecDelay(1000000); // use delay to prevent STA do reassoc ++ ++ // channel sanity check ++ for (index = 0 ; index < pAd->ChannelListNum; index++) ++ { ++ if (pAd->ChannelList[index].Channel == NewChannel) ++ { ++ pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; ++ pAd->CommonCfg.Channel = NewChannel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeacon - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); ++ break; ++ } ++ } ++ ++ if (index >= pAd->ChannelListNum) ++ { ++ DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); ++ } ++ } ++ ++ // if the ssid matched & bssid unmatched, we should select the bssid with large value. ++ // This might happened when two STA start at the same time ++ if ((! is_my_bssid) && ADHOC_ON(pAd)) ++ { ++ INT i; ++ ++ // Add the safeguard against the mismatch of adhoc wep status ++ if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus) ++ { ++ return; ++ } ++ ++ // collapse into the ADHOC network which has bigger BSSID value. ++ for (i = 0; i < 6; i++) ++ { ++ if (Bssid[i] > pAd->CommonCfg.Bssid[i]) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - merge to the IBSS with bigger BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ AsicDisableSync(pAd); ++ COPY_MAC_ADDR(pAd->CommonCfg.Bssid, Bssid); ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy BEACON frame to on-chip memory ++ is_my_bssid = TRUE; ++ break; ++ } ++ else if (Bssid[i] < pAd->CommonCfg.Bssid[i]) ++ break; ++ } ++ } ++ ++ ++ NdisGetSystemUpTime(&Now); ++ pBss = &pAd->ScanTab.BssEntry[Bssidx]; ++ pBss->Rssi = RealRssi; // lastest RSSI ++ pBss->LastBeaconRxTime = Now; // last RX timestamp ++ ++ // ++ // BEACON from my BSSID - either IBSS or INFRA network ++ // ++ if (is_my_bssid) ++ { ++ RXWI_STRUC RxWI; ++ ++ pAd->StaCfg.DtimCount = DtimCount; ++ pAd->StaCfg.DtimPeriod = DtimPeriod; ++ pAd->StaCfg.LastBeaconRxTime = Now; ++ ++ ++ RxWI.RSSI0 = Elem->Rssi0; ++ RxWI.RSSI1 = Elem->Rssi1; ++ RxWI.RSSI2 = Elem->Rssi2; ++ ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, &RxWI); ++ if (AironetCellPowerLimit != 0xFF) ++ { ++ // ++ // We get the Cisco (ccx) "TxPower Limit" required ++ // Changed to appropriate TxPower Limit for Ciso Compatible Extensions ++ // ++ ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); ++ } ++ else ++ { ++ // ++ // AironetCellPowerLimit equal to 0xFF means the Cisco (ccx) "TxPower Limit" not exist. ++ // Used the default TX Power Percentage, that set from UI. ++ // ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ } ++ ++ // at least one 11b peer joined. downgrade the MaxTxRate to 11Mbps ++ // after last 11b peer left for several seconds, we'll auto switch back to 11G rate ++ // in MlmePeriodicExec() ++ if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo))) ++ { ++ BOOLEAN bRestart; ++ BOOLEAN bnRestart; ++ ++ bRestart = FALSE; ++ bnRestart = FALSE; ++ ++ do ++ { ++ if ((SupRateLen+ExtRateLen <= 4) && (pAd->CommonCfg.MaxTxRate > RATE_11)) ++ { ++ if (pAd->StaCfg.AdhocBOnlyJoined == FALSE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - 11b peer joined. down-grade to 11b TX rates \n")); ++ bRestart = TRUE; ++ NdisMoveMemory(pAd->StaActive.SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pAd->StaActive.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pAd->StaActive.ExtRateLen = ExtRateLen; ++ pAd->StaCfg.AdhocBOnlyJoined = TRUE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ AsicSetEdcaParm(pAd, NULL); ++ } ++ ++ // this timestamp is for MlmePeriodicExec() to check if all 11B peers have left ++ pAd->StaCfg.Last11bBeaconRxTime = Now; ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++ // Update Ht Phy. ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ !pAd->StaCfg.AdhocBGJoined && ++ !pAd->StaCfg.AdhocBOnlyJoined) ++ AdhocTurnOnQos(pAd); ++ ++ // Handle rate switch issue when Adhoc mode ++ if ((SupRateLen+ExtRateLen >= 8) && (HtCapability.MCSSet[0] == 0) && (HtCapability.MCSSet[1] == 0)) ++ { ++ if (pAd->StaCfg.AdhocBGJoined == FALSE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - 11g peer joined. down-grade to 11g TX rates \n")); ++ bRestart = TRUE; ++ NdisMoveMemory(pAd->StaActive.SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pAd->StaActive.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pAd->StaActive.ExtRateLen = ExtRateLen; ++ pAd->StaCfg.AdhocBGJoined = TRUE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ AsicSetEdcaParm(pAd, NULL); ++ } ++ ++ // this timestamp is for MlmePeriodicExec() to check if all 11g peers have left ++ pAd->StaCfg.Last11gBeaconRxTime = Now; ++ break; ++ } ++ else if (!pAd->StaCfg.AdhocBGJoined && ++ !pAd->StaCfg.AdhocBOnlyJoined && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) && ++ (HtCapability.HtCapInfo.ChannelWidth == BW_20)) ++ { ++ if (pAd->StaCfg.Adhoc20NJoined == FALSE) ++ { ++ UCHAR ByteValue = 0; ++ ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ ++ pAd->StaCfg.Adhoc20NJoined = TRUE; ++ NdisMoveMemory(&pAd->MlmeAux.HtCapability, &HtCapability, SIZE_HT_CAP_IE); ++ if (AddHtInfoLen != 0) ++ NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, AddHtInfoLen); ++ NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16); ++ ++ RTMPCheckHt(pAd, Elem->Wcid, &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ bRestart = TRUE; ++ bnRestart = TRUE; ++ } ++ // this timestamp is for MlmePeriodicExec() to check if all 20MHz N peers have left ++ pAd->StaCfg.Last20NBeaconRxTime = Now; ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ } ++ }while (FALSE); ++ ++ // If peer Adhoc is legacy mode, I don't need to call MlmeUpdateHtTxRates no matter I support HT or not ++ if ((bRestart == TRUE) && (bnRestart == FALSE)) ++ { ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy to on-chip memory ++ } ++#ifdef DOT11_N_SUPPORT ++ else if ((bRestart == TRUE) && (bnRestart == TRUE)) ++ { ++ MlmeUpdateTxRates(pAd, FALSE, BSS0); ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy to on-chip memory ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // At least another peer in this IBSS, declare MediaState as CONNECTED ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ ++ // 2003/03/12 - john ++ // Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that ++ // "site survey" result should always include the current connected network. ++ // ++ Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n")); ++ } ++ ++ // Ad-hoc mode is using MAC address as BA session. So we need to continuously find newly joined adhoc station by receiving beacon. ++ // To prevent always check this, we use wcid == RESERVED_WCID to recognize it as newly joined adhoc station. ++ if (ADHOC_ON(pAd) && (Elem->Wcid == RESERVED_WCID)) ++ { ++ UCHAR idx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ // look up the existing table ++ pEntry = MacTableLookup(pAd, Addr2); ++ if (pEntry == NULL) ++ { ++ // Another adhoc joining, add to our MAC table. ++ pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE); ++ if (pEntry) ++ { ++ pEntry->Sst = SST_ASSOC; ++ idx = pAd->StaCfg.DefaultKeyId; ++ // After InsertEntry, Write to ASIC on-chip table. ++ RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry); ++ DBGPRINT(RT_DEBUG_TRACE, ("ADHOC %x:%x:%x:%x:%x:%x join in.Entry=%d\n", Addr2[0],Addr2[1],Addr2[2],Addr2[3],Addr2[4],Addr2[5], pEntry->Aid)); ++ ++ pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ if (HtCapabilityLen <= 0) ++ { ++ pEntry->HTPhyMode.field.STBC = 0; ++ pEntry->HTPhyMode.field.BW = 0; ++ pEntry->HTPhyMode.field.ShortGI = 0; ++ if ((SupRateLen+ExtRateLen <= 4) && (pAd->CommonCfg.Channel <= 14)) ++ { ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ } ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ { ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ } ++ } ++ ++ if (INFRA_ON(pAd)) ++ { ++ BOOLEAN bUseShortSlot, bUseBGProtection; ++ ++ // decide to use/change to - ++ // 1. long slot (20 us) or short slot (9 us) time ++ // 2. turn on/off RTS/CTS and/or CTS-to-self protection ++ // 3. short preamble ++ ++ //bUseShortSlot = pAd->CommonCfg.bUseShortSlotTime && CAP_IS_SHORT_SLOT(CapabilityInfo); ++ bUseShortSlot = CAP_IS_SHORT_SLOT(CapabilityInfo); ++ if (bUseShortSlot != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED)) ++ AsicSetSlotTime(pAd, bUseShortSlot); ++ ++ bUseBGProtection = (pAd->CommonCfg.UseBGProtection == 1) || // always use ++ ((pAd->CommonCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp)); ++ ++ if (pAd->CommonCfg.Channel > 14) // always no BG protection in A-band. falsely happened when switching A/G band to a dual-band AP ++ bUseBGProtection = FALSE; ++ ++ if (bUseBGProtection != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ if (bUseBGProtection) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),FALSE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); ++ } ++ else ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),TRUE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); ++ } ++ ++ DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection)); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // check Ht protection mode. and adhere to the Non-GF device indication by AP. ++ if ((AddHtInfoLen != 0) && ++ ((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) || ++ (AddHtInfo.AddHtInfo2.NonGfPresent != pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent))) ++ { ++ pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent = AddHtInfo.AddHtInfo2.NonGfPresent; ++ pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode = AddHtInfo.AddHtInfo2.OperaionMode; ++ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); ++ } ++ else ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) && ++ ERP_IS_USE_BARKER_PREAMBLE(Erp)) ++ { ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP forced to use LONG preamble\n")); ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ (EdcaParm.bValid == TRUE) && ++ (EdcaParm.EdcaUpdateCount != pAd->CommonCfg.APEdcaParm.EdcaUpdateCount)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP change EDCA parameters(from %d to %d)\n", ++ pAd->CommonCfg.APEdcaParm.EdcaUpdateCount, ++ EdcaParm.EdcaUpdateCount)); ++ AsicSetEdcaParm(pAd, &EdcaParm); ++ } ++ ++ // copy QOS related information ++ NdisMoveMemory(&pAd->CommonCfg.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisMoveMemory(&pAd->CommonCfg.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ ++ // only INFRASTRUCTURE mode support power-saving feature ++ if ((INFRA_ON(pAd) && (pAd->StaCfg.Psm == PWR_SAVE)) || (pAd->CommonCfg.bAPSDForcePowerSave)) ++ { ++ UCHAR FreeNumber; ++ // 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL ++ // 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE ++ // 3. we have outgoing frames in TxRing or MgmtRing, better stay AWAKE ++ // 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE ++ // 5. otherwise, put PHY back to sleep to save battery. ++ if (MessageToMe) ++ { ++#ifdef RT2860 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); ++ // Turn clk to 80Mhz. ++ } ++#endif // RT2860 // ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && ++ pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) ++ { ++ pAd->CommonCfg.bNeedSendTriggerFrame = TRUE; ++ } ++ else ++ RT28XX_PS_POLL_ENQUEUE(pAd); ++ } ++ else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) ++ { ++#ifdef RT2860 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); ++ } ++#endif // RT2860 // ++ } ++ else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_BE].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_VI].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_VO].Number != 0) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_BK, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_BE, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_VI, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_VO, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_MGMT, MGMT_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS)) ++ { ++ // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme ++ // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? ++#ifdef RT2860 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); ++ } ++#endif // RT2860 // ++ } ++ else ++ { ++ USHORT NextDtim = DtimCount; ++ ++ if (NextDtim == 0) ++ NextDtim = DtimPeriod; ++ ++ TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) ++ TbttNumToNextWakeUp = NextDtim; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ } ++ } ++ } ++ } ++ // not my BSSID, ignore it ++ } ++ // sanity check fail, ignore this frame ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Receive PROBE REQ from remote peer when operating in IBSS mode ++ ========================================================================== ++ */ ++VOID PeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++#ifdef DOT11_N_SUPPORT ++ UCHAR HtLen, AddHtLen, NewExtLen; ++#endif // DOT11_N_SUPPORT // ++ HEADER_802_11 ProbeRspHdr; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ LARGE_INTEGER FakeTimestamp; ++ UCHAR DsLen = 1, IbssLen = 2; ++ UCHAR LocalErpIe[3] = {IE_ERP, 1, 0}; ++ BOOLEAN Privacy; ++ USHORT CapabilityInfo; ++ UCHAR RSNIe = IE_WPA; ++ ++ if (! ADHOC_ON(pAd)) ++ return; ++ ++ if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, Ssid, &SsidLen)) ++ { ++ if ((SsidLen == 0) || SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) ++ { ++ // allocate and send out ProbeRsp frame ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ //pAd->StaCfg.AtimWin = 0; // ?????? ++ ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &ProbeRspHdr, ++ TIMESTAMP_LEN, &FakeTimestamp, ++ 2, &pAd->CommonCfg.BeaconPeriod, ++ 2, &CapabilityInfo, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->StaActive.SupRateLen, ++ pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, ++ 1, &DsIe, ++ 1, &DsLen, ++ 1, &pAd->CommonCfg.Channel, ++ 1, &IbssIe, ++ 1, &IbssLen, ++ 2, &pAd->StaActive.AtimWin, ++ END_OF_ARGS); ++ ++ if (pAd->StaActive.ExtRateLen) ++ { ++ ULONG tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 3, LocalErpIe, ++ 1, &ExtRateIe, ++ 1, &pAd->StaActive.ExtRateLen, ++ pAd->StaActive.ExtRateLen, &pAd->StaActive.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // If adhoc secruity is set for WPA-None, append the cipher suite IE ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ ULONG tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ ULONG TmpLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ HtLen = sizeof(pAd->CommonCfg.HtCapability); ++ AddHtLen = sizeof(pAd->CommonCfg.AddHTInfo); ++ NewExtLen = 1; ++ //New extension channel offset IE is included in Beacon, Probe Rsp or channel Switch Announcement Frame ++ if (pAd->bBroadComHT == TRUE) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ sizeof(HT_CAPABILITY_IE), &pAd->CommonCfg.HtCapability, ++ 1, &AddHtInfoIe, ++ 1, &AddHtLen, ++ sizeof(ADD_HT_INFO_IE), &pAd->CommonCfg.AddHTInfo, ++ 1, &NewExtChanIe, ++ 1, &NewExtLen, ++ sizeof(NEW_EXT_CHAN_IE), &pAd->CommonCfg.NewExtChanOffset, ++ END_OF_ARGS); ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } ++} ++ ++VOID BeaconTimeoutAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BeaconTimeoutAtJoinAction\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan timeout procedure. basically add channel index by 1 and rescan ++ ========================================================================== ++ */ ++VOID ScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ pAd->MlmeAux.Channel = NextChannel(pAd, pAd->MlmeAux.Channel); ++ ++ // Only one channel scanned for CISCO beacon request ++ if ((pAd->MlmeAux.ScanType == SCAN_CISCO_ACTIVE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_PASSIVE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_NOISE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_CHANNEL_LOAD)) ++ pAd->MlmeAux.Channel = 0; ++ ++ // this routine will stop if pAd->MlmeAux.Channel == 0 ++ ScanNextChannel(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AYNC - InvalidStateWhenScan(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenJoin( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenJoin(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenStart( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenStart(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID EnqueuePsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ ++ if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP) ++ pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE; ++ MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID EnqueueProbeRequest( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS NState; ++ PUCHAR pOutBuffer; ++ ULONG FrameLen = 0; ++ HEADER_802_11 Hdr80211; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("force out a ProbeRequest ...\n")); ++ ++ NState = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NState == NDIS_STATUS_SUCCESS) ++ { ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ ++ // this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->StaActive.SupRateLen, ++ pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ ++} ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++VOID BuildEffectedChannelList( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR EChannel[11]; ++ UCHAR i, j, k; ++ UCHAR UpperChannel = 0, LowerChannel = 0; ++ ++ RTMPZeroMemory(EChannel, 11); ++ i = 0; ++ // Find upper channel and lower channel. ++ if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) ++ { ++ UpperChannel = pAd->CommonCfg.Channel; ++ LowerChannel = pAd->CommonCfg.CentralChannel; ++ } ++ else if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) ++ { ++ UpperChannel = pAd->CommonCfg.CentralChannel; ++ LowerChannel = pAd->CommonCfg.Channel; ++ } ++ else ++ { ++ return; ++ } ++ ++ // Record channels that is below lower channel.. ++ if (LowerChannel > 1) ++ { ++ EChannel[0] = LowerChannel - 1; ++ i = 1; ++ if (LowerChannel > 2) ++ { ++ EChannel[1] = LowerChannel - 2; ++ i = 2; ++ if (LowerChannel > 3) ++ { ++ EChannel[2] = LowerChannel - 3; ++ i = 3; ++ } ++ } ++ } ++ // Record channels that is between lower channel and upper channel. ++ for (k = LowerChannel;k < UpperChannel;k++) ++ { ++ EChannel[i] = k; ++ i++; ++ } ++ // Record channels that is above upper channel.. ++ if (LowerChannel < 11) ++ { ++ EChannel[i] = UpperChannel + 1; ++ i++; ++ if (LowerChannel < 10) ++ { ++ EChannel[i] = LowerChannel + 2; ++ i++; ++ if (LowerChannel < 9) ++ { ++ EChannel[i] = LowerChannel + 3; ++ i++; ++ } ++ } ++ } ++ // ++ for (j = 0;j < i;j++) ++ { ++ for (k = 0;k < pAd->ChannelListNum;k++) ++ { ++ if (pAd->ChannelList[k].Channel == EChannel[j]) ++ { ++ pAd->ChannelList[k].bEffectedChannel = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,(" EffectedChannel( =%d)\n", EChannel[j])); ++ break; ++ } ++ } ++ } ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++BOOLEAN ScanRunning( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return (pAd->Mlme.SyncMachine.CurrState == SCAN_LISTEN) ? TRUE : FALSE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/sta/wpa.c +@@ -0,0 +1,2086 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 03-07-22 Initial ++ Paul Lin 03-11-28 Modify for supplicant ++*/ ++#include "../rt_config.h" ++ ++#define WPARSNIE 0xdd ++#define WPA2RSNIE 0x30 ++ ++//extern UCHAR BIT8[]; ++UCHAR CipherWpaPskTkip[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x02 // authentication ++ }; ++UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); ++ ++UCHAR CipherWpaPskAes[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x04, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x04, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x02 // authentication ++ }; ++UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCiscoCCKM[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x40, 0x96, 0x01, // Multicast ++ 0x01, 0x00, // Number of uicast ++ 0x00, 0x40, 0x96, 0x01, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x40, 0x96, 0x00 // Authentication ++ }; ++UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCiscoCCKM24[] = { ++ 0xDD, 0x18, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x40, 0x96, 0x01, // Multicast ++ 0x01, 0x00, // Number of uicast ++ 0x00, 0x40, 0x96, 0x01, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x40, 0x96, 0x00, ++ 0x28, 0x00// Authentication ++ }; ++ ++UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCCXTkip[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x01 // authentication ++ }; ++UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR)); ++ ++UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; ++UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; ++ ++UCHAR EAPOL_FRAME[] = {0x88, 0x8E}; ++ ++BOOLEAN CheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ OUT UCHAR *Offset); ++ ++void inc_byte_array(UCHAR *counter, int len); ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Classify WPA EAP message type ++ ++ Arguments: ++ EAPType Value of EAP message type ++ MsgType Internal Message definition for MLME state machine ++ ++ Return Value: ++ TRUE Found appropriate message type ++ FALSE No appropriate message type ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ All these constants are defined in wpa.h ++ For supplicant, there is only EAPOL Key message avaliable ++ ++ ======================================================================== ++*/ ++BOOLEAN WpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType) ++{ ++ switch (EAPType) ++ { ++ case EAPPacket: ++ *MsgType = MT2_EAPPacket; ++ break; ++ case EAPOLStart: ++ *MsgType = MT2_EAPOLStart; ++ break; ++ case EAPOLLogoff: ++ *MsgType = MT2_EAPOLLogoff; ++ break; ++ case EAPOLKey: ++ *MsgType = MT2_EAPOLKey; ++ break; ++ case EAPOLASFAlert: ++ *MsgType = MT2_EAPOLASFAlert; ++ break; ++ default: ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ========================================================================== ++ */ ++VOID WpaPskStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); ++ StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This is state machine function. ++ When receiving EAPOL packets which is for 802.1x key management. ++ Use both in WPA, and WPAPSK case. ++ In this function, further dispatch to different functions according to the received packet. 3 categories are : ++ 1. normal 4-way pairwisekey and 2-way groupkey handshake ++ 2. MIC error (Countermeasures attack) report packet from STA. ++ 3. Request for pairwise/group key update from STA ++ Return: ++ ========================================================================== ++*/ ++VOID WpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ INT MsgType = EAPOL_MSG_INVALID; ++ PKEY_DESCRIPTER pKeyDesc; ++ PHEADER_802_11 pHeader; //red ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ UCHAR EapolVr; ++ KEY_INFO peerKeyInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n")); ++ ++ // Get 802.11 header first ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Get EAPoL-Key Descriptor ++ pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo)); ++ ++ ++ // 1. Check EAPOL frame version and type ++ EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H]; ++ ++ if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n")); ++ return; ++ } ++ ++ // First validate replay counter, only accept message with larger replay counter ++ // Let equal pass, some AP start with all zero replay counter ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ ++ if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n")); ++ return; ++ } ++ ++ // Process WPA2PSK frame ++ if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.EKD_DL == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 0) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); ++ } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.EKD_DL == 1) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_3; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); ++ } else if((peerKeyInfo.KeyType == GROUPKEY) && ++ (peerKeyInfo.EKD_DL == 1) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_GROUP_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); ++ } ++ ++ // We will assume link is up (assoc suceess and port not secured). ++ // All state has to be able to process message from previous state ++ switch(pAd->StaCfg.WpaState) ++ { ++ case SS_START: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ break; ++ ++ case SS_WAIT_MSG_3: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ Wpa2PairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ break; ++ ++ case SS_WAIT_GROUP: // When doing group key exchange ++ case SS_FINISH: // This happened when update group key ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ Wpa2PairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ else if(MsgType == EAPOL_GROUP_MSG_1) ++ { ++ WpaGroupMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ // Process WPAPSK Frame ++ // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant ++ else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.KeyIndex == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 0) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); ++ } ++ else if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.KeyIndex == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_3; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); ++ } ++ else if((peerKeyInfo.KeyType == GROUPKEY) && ++ (peerKeyInfo.KeyIndex != 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_GROUP_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); ++ } ++ ++ // We will assume link is up (assoc suceess and port not secured). ++ // All state has to be able to process message from previous state ++ switch(pAd->StaCfg.WpaState) ++ { ++ case SS_START: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ break; ++ ++ case SS_WAIT_MSG_3: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ WpaPairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ break; ++ ++ case SS_WAIT_GROUP: // When doing group key exchange ++ case SS_FINISH: // This happened when update group key ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ WpaPairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ } ++ else if(MsgType == EAPOL_GROUP_MSG_1) ++ { ++ WpaGroupMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Pairwise key 4-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaPairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PHEADER_802_11 pHeader; ++ UCHAR *mpool, *PTK, *digest; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ PEAPOL_PACKET pMsg1; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n")); ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); ++ ++ if (mpool == NULL) ++ return; ++ ++ // PTK Len = 80. ++ PTK = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(PTK + 80, 4); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 1 from authenticator ++ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ // 1. Save Replay counter, it will use to verify message 3 and construct message 2 ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Save ANonce ++ NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Generate random SNonce ++ GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); ++ ++ // Calc PTK(ANonce, SNonce) ++ WpaCountPTK(pAd, ++ pAd->StaCfg.PMK, ++ pAd->StaCfg.ANonce, ++ pAd->CommonCfg.Bssid, ++ pAd->StaCfg.SNonce, ++ pAd->CurrentAddress, ++ PTK, ++ LEN_PTK); ++ ++ // Save key to PTK entry ++ NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Message 2 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ // ++ // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ // 1. Key descriptor version and appropriate RSN IE ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ // fill in Data Material and its length ++ Packet.KeyDesc.KeyData[0] = IE_WPA; ++ Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; ++ Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; ++ ++ // Update Key length ++ Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; ++ // 2. Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // 3. KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ //Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ ++ // 4. Fill SNonce ++ NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); ++ ++ // 5. Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE) ++ // Out buffer for transmitting message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, mpool); ++ return; ++ } ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // 6. Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ ++ HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring and send Msg 2 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n")); ++} ++ ++VOID Wpa2PairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PHEADER_802_11 pHeader; ++ UCHAR *mpool, *PTK, *digest; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ PEAPOL_PACKET pMsg1; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n")); ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); ++ ++ if (mpool == NULL) ++ return; ++ ++ // PTK Len = 80. ++ PTK = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(PTK + 80, 4); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 1 from authenticator ++ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ // 1. Save Replay counter, it will use to verify message 3 and construct message 2 ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Save ANonce ++ NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Generate random SNonce ++ GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); ++ ++ if(pMsg1->KeyDesc.KeyDataLen[1] > 0 ) ++ { ++ // cached PMKID ++ } ++ ++ // Calc PTK(ANonce, SNonce) ++ WpaCountPTK(pAd, ++ pAd->StaCfg.PMK, ++ pAd->StaCfg.ANonce, ++ pAd->CommonCfg.Bssid, ++ pAd->StaCfg.SNonce, ++ pAd->CurrentAddress, ++ PTK, ++ LEN_PTK); ++ ++ // Save key to PTK entry ++ NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message 2 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ // ++ // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ ++ // 1. Key descriptor version and appropriate RSN IE ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ // fill in Data Material and its length ++ Packet.KeyDesc.KeyData[0] = IE_WPA2; ++ Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; ++ Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; ++ ++ // 2. Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // 3. KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = 0; ++ Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; ++ ++ // 4. Fill SNonce ++ NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); ++ ++ // 5. Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // Out buffer for transmitting message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // 6. Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ ++ // Make Transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ os_free_mem(pAd, mpool); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n")); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Pairwise key 4-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaPairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PHEADER_802_11 pHeader; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pMsg3; ++ UCHAR Mic[16], OldMic[16]; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ UCHAR skip_offset; ++ KEY_INFO peerKeyInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n")); ++ ++ // Record 802.11 header & the received EAPOL packet Msg3 ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ ++ // 1. Verify cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) ++ { ++ return; ++ } ++ else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ return; ++ } ++ ++ // Verify RSN IE ++ //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) ++ if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n")); ++ hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); ++ hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n")); ++ ++ ++ // 2. Check MIC value ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ UCHAR digest[80]; ++ ++ HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else // TKIP ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ ++ // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ return; ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 4. Double check ANonce ++ if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) ++ return; ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Message 4 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) ++ // ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; ++ ++ // Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS ++ // Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3 ++ Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting message 4 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ return; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ UCHAR digest[80]; ++ ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ // Update PTK ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ // Make transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // Copy frame to Tx ring and Send Message 4 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n")); ++} ++ ++VOID Wpa2PairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PHEADER_802_11 pHeader; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pMsg3; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR *mpool, *KEYDATA, *digest; ++ UCHAR Key[32]; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ KEY_INFO peerKeyInfo; ++ ++ // allocate memory ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); ++ ++ if(mpool == NULL) ++ return; ++ ++ // KEYDATA Len = 512. ++ KEYDATA = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n")); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 3 frame. ++ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ // 1. Verify cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // 2. Check MIC value ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ ++ // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 4. Double check ANonce ++ if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Obtain GTK ++ // 5. Decrypt GTK from Key Data ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // Decrypt AES GTK ++ AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData); ++ } ++ else // TKIP ++ { ++ INT i; ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); ++ } ++ ++ if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update GTK to ASIC ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message 4 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) ++ // ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; ++ ++ // Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting message 4 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ // Update PTK ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ // Make Transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // Copy frame to Tx ring and Send Message 4 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ // set 802.1x port control ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ ++ // send wireless event - for set key done WPA2 ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n")); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Group key 2-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaGroupMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pGroup; ++ UCHAR *mpool, *digest, *KEYDATA; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR GTK[32], Key[32]; ++ KEY_INFO peerKeyInfo; ++ ++ // allocate memory ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); ++ ++ if(mpool == NULL) ++ return; ++ ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(mpool, 4); ++ // KEYDATA Len = 512. ++ KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n")); ++ ++ // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) ++ pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ // 0. Check cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // 1. Verify Replay counter ++ // Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Verify MIC is valid ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n")); ++ MlmeFreeMemory(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n")); ++ ++ ++ // 3. Decrypt GTK from Key Data ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // Decrypt AES GTK ++ AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData); ++ } ++ else // TKIP ++ { ++ INT i; ++ ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]); ++ } ++ ++ // Process decrypted key data material ++ // Parse keyData to handle KDE format for WPA2PSK ++ if (peerKeyInfo.EKD_DL) ++ { ++ if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ } ++ else // WPAPSK ++ { ++ // set key material, TxMic and RxMic for WPAPSK ++ NdisMoveMemory(GTK, KEYDATA, 32); ++ NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32); ++ pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex; ++ ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, >K[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, >K[24], LEN_TKIP_TXMICK); ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); ++ } ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ ++ // init header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Group message 1 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) ++ // ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ else ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1]; ++ ++ // Key Index as G-Msg 1 ++ if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex; ++ ++ // Key Type Group key ++ Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Secure bit ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting group message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ MlmeFreeMemory(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring and prepare for encryption ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); ++ ++ // 6 Free allocated memory ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ // send wireless event - for set key done WPA2 ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init WPA MAC header ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr1) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.ToDs = 1; ++ if (wep == 1) ++ pHdr80211->FC.Wep = 1; ++ ++ // Addr1: BSSID, Addr2: SA, Addr3: DA ++ COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1); ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid); ++ pHdr80211->Sequence = pAd->Sequence; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware encryption before really ++ sent out to air. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to outgoing Ndis frame ++ NumberOfFrag Number of fragment required ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN is4wayFrame) ++ ++{ ++ NDIS_STATUS Status; ++ PNDIS_PACKET pPacket; ++ UCHAR Index; ++ ++ do ++ { ++ // 1. build a NDIS packet and call RTMPSendPacket(); ++ // be careful about how/when to release this internal allocated NDIS PACKET buffer ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ if (is4wayFrame) ++ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1); ++ else ++ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0); ++ ++ // 2. send out the packet ++ Status = STASendPacket(pAd, pPacket); ++ if(Status == NDIS_STATUS_SUCCESS) ++ { ++ // Dequeue one frame from TxSwQueue0..3 queue and process it ++ // There are three place calling dequeue for TX ring. ++ // 1. Here, right after queueing the frame. ++ // 2. At the end of TxRingTxDone service routine. ++ // 3. Upon NDIS call RTMPSendPackets ++ if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) ++ { ++ for(Index = 0; Index < 5; Index ++) ++ if(pAd->TxSwQueue[Index].Number > 0) ++ RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS); ++ } ++ } ++ } while(FALSE); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Sanity RSN IE form AP ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ ======================================================================== ++*/ ++BOOLEAN CheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ OUT UCHAR *Offset) ++{ ++ PUCHAR pVIE; ++ UCHAR len; ++ PEID_STRUCT pEid; ++ BOOLEAN result = FALSE; ++ ++ pVIE = pData; ++ len = DataLen; ++ *Offset = 0; ++ ++ while (len > sizeof(RSNIE2)) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // WPA RSN IE ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && ++ (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && ++ (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ // WPA2 RSN IE ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) && ++ (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && ++ (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ else ++ { ++ break; ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset)); ++ ++ return result; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. ++ GTK is encaptulated in KDE format at p.83 802.11i D10 ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ 802.11i D10 ++ ++ ======================================================================== ++*/ ++BOOLEAN ParseKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR bPairewise) ++{ ++ PKDE_ENCAP pKDE = NULL; ++ PUCHAR pMyKeyData = pKeyData; ++ UCHAR KeyDataLength = KeyDataLen; ++ UCHAR GTKLEN; ++ UCHAR skip_offset; ++ ++ // Verify The RSN IE contained in Pairewise-Msg 3 and skip it ++ if (bPairewise) ++ { ++ // Check RSN IE whether it is WPA2/WPA2PSK ++ if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n")); ++ hex_dump("Get KEYDATA :", pKeyData, KeyDataLen); ++ return FALSE; ++ } ++ else ++ { ++ // skip RSN IE ++ pMyKeyData += skip_offset; ++ KeyDataLength -= skip_offset; ++ ++ //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); ++ ++ // Parse EKD format ++ if (KeyDataLength >= 8) ++ { ++ pKDE = (PKDE_ENCAP) pMyKeyData; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n")); ++ return FALSE; ++ } ++ ++ ++ // Sanity check - shared key index should not be 0 ++ if (pKDE->GTKEncap.Kid == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n")); ++ return FALSE; ++ } ++ ++ // Sanity check - KED length ++ if (KeyDataLength < (pKDE->Len + 2)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); ++ return FALSE; ++ } ++ ++ // Get GTK length - refer to IEEE 802.11i-2004 p.82 ++ GTKLEN = pKDE->Len -6; ++ ++ if (GTKLEN < LEN_AES_KEY) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); ++ return FALSE; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN)); ++ ++ // Update GTK ++ // set key material, TxMic and RxMic for WPAPSK ++ NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32); ++ pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid; ++ ++ // Update shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK); ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ return TRUE; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Cisco CCKM PRF function ++ ++ Arguments: ++ key Cisco Base Transient Key (BTK) ++ key_len The key length of the BTK ++ data Ruquest Number(RN) + BSSID ++ data_len The length of the data ++ output Store for PTK(Pairwise transient keys) ++ len The length of the output ++ Return Value: ++ None ++ ++ Note: ++ 802.1i Annex F.9 ++ ++ ======================================================================== ++*/ ++VOID CCKMPRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len) ++{ ++ INT i; ++ UCHAR input[1024]; ++ INT currentindex = 0; ++ INT total_len; ++ ++ NdisMoveMemory(input, data, data_len); ++ total_len = data_len; ++ input[total_len] = 0; ++ total_len++; ++ for (i = 0; i < (len + 19) / 20; i++) ++ { ++ HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); ++ currentindex += 20; ++ input[total_len - 1]++; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process MIC error indication and record MIC error timer. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pWpaKey Pointer to the WPA key structure ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReportMicError( ++ IN PRTMP_ADAPTER pAd, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ ULONG Now; ++ UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0); ++ ++ // Record Last MIC error time and count ++ Now = jiffies; ++ if (pAd->StaCfg.MicErrCnt == 0) ++ { ++ pAd->StaCfg.MicErrCnt++; ++ pAd->StaCfg.LastMicErrorTime = Now; ++ NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); ++ } ++ else if (pAd->StaCfg.MicErrCnt == 1) ++ { ++ if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) ++ { ++ // Update Last MIC error time, this did not violate two MIC errors within 60 seconds ++ pAd->StaCfg.LastMicErrorTime = Now; ++ } ++ else ++ { ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ pAd->StaCfg.LastMicErrorTime = Now; ++ // Violate MIC error counts, MIC countermeasures kicks in ++ pAd->StaCfg.MicErrCnt++; ++ } ++ } ++ else ++ { ++ // MIC error count >= 2 ++ // This should not happen ++ ; ++ } ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_MIC_FAILURE_REPORT_FRAME, ++ 1, ++ &unicastKey); ++ ++ if (pAd->StaCfg.MicErrCnt == 2) ++ { ++ RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); ++ } ++} ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#define LENGTH_EAP_H 4 ++// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). ++INT WpaCheckEapCode( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFrame, ++ IN USHORT FrameLen, ++ IN USHORT OffSet) ++{ ++ ++ PUCHAR pData; ++ INT result = 0; ++ ++ if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H ) ++ return result; ++ ++ pData = pFrame + OffSet; // skip offset bytes ++ ++ if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type ++ { ++ result = *(pData+4); // EAP header - Code ++ } ++ ++ return result; ++} ++ ++VOID WpaSendMicFailureToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUnicast) ++{ ++ union iwreq_data wrqu; ++ char custom[IW_CUSTOM_MAX] = {0}; ++ ++ sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); ++ if (bUnicast) ++ sprintf(custom, "%s unicast", custom); ++ wrqu.data.length = strlen(custom); ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ ++ return; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++VOID WpaMicFailureReportFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ BOOLEAN bUnicast; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); ++ ++ bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE); ++ pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Request field presented ++ Packet.KeyDesc.KeyInfo.Request = 1; ++ ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Error field presented ++ Packet.KeyDesc.KeyInfo.Error = 1; ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; ++ ++ // Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ inc_byte_array(pAd->StaCfg.ReplayCounter, 8); ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ UCHAR digest[20] = {0}; ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // opy frame to Tx ring and send MIC failure report frame to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); ++} ++ ++/** from wpa_supplicant ++ * inc_byte_array - Increment arbitrary length byte array by one ++ * @counter: Pointer to byte array ++ * @len: Length of the counter in bytes ++ * ++ * This function increments the last byte of the counter by one and continues ++ * rolling over to more significant bytes if the byte was incremented from ++ * 0xff to 0x00. ++ */ ++void inc_byte_array(UCHAR *counter, int len) ++{ ++ int pos = len - 1; ++ while (pos >= 0) { ++ counter[pos]++; ++ if (counter[pos] != 0) ++ break; ++ pos--; ++ } ++} ++ ++VOID WpaDisassocApAndBlockAssoc( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ++ // disassoc from current AP first ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ pAd->StaCfg.bBlockAssoc = TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2860/TODO +@@ -0,0 +1,17 @@ ++I'm hesitant to add a TODO file here, as the wireless developers would ++really have people help them out on the "clean" rt2860 driver that can ++be found at the rt2860.sf.net site. ++ ++But, if you wish to clean up this driver instead, here's a short list of ++things that need to be done to get it into a more mergable shape: ++ ++TODO: ++ - checkpatch.pl clean ++ - sparse clean ++ - port to in-kernel 80211 stack ++ - remove reading from /etc/ config files ++ - review by the wireless developer community ++ ++Please send any patches or complaints about this driver to Greg ++Kroah-Hartman and don't bother the upstream wireless ++kernel developers about it, they want nothing to do with it. +--- /dev/null ++++ b/drivers/staging/rt2860/wpa.h +@@ -0,0 +1,356 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++ ++#ifndef __WPA_H__ ++#define __WPA_H__ ++ ++// EAPOL Key descripter frame format related length ++#define LEN_KEY_DESC_NONCE 32 ++#define LEN_KEY_DESC_IV 16 ++#define LEN_KEY_DESC_RSC 8 ++#define LEN_KEY_DESC_ID 8 ++#define LEN_KEY_DESC_REPLAY 8 ++#define LEN_KEY_DESC_MIC 16 ++ ++// The length is the EAPoL-Key frame except key data field. ++// Please refer to 802.11i-2004 ,Figure 43u in p.78 ++#define LEN_EAPOL_KEY_MSG (sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE) ++ ++// EAP Code Type. ++#define EAP_CODE_REQUEST 1 ++#define EAP_CODE_RESPONSE 2 ++#define EAP_CODE_SUCCESS 3 ++#define EAP_CODE_FAILURE 4 ++ ++// EAPOL frame Protocol Version ++#define EAPOL_VER 1 ++#define EAPOL_VER2 2 ++ ++// EAPOL-KEY Descriptor Type ++#define WPA1_KEY_DESC 0xfe ++#define WPA2_KEY_DESC 0x02 ++ ++// Key Descriptor Version of Key Information ++#define DESC_TYPE_TKIP 1 ++#define DESC_TYPE_AES 2 ++#define DESC_TYPE_MESH 3 ++ ++#define LEN_MSG1_2WAY 0x7f ++#define MAX_LEN_OF_EAP_HS 256 ++ ++#define LEN_MASTER_KEY 32 ++ ++// EAPOL EK, MK ++#define LEN_EAP_EK 16 ++#define LEN_EAP_MICK 16 ++#define LEN_EAP_KEY ((LEN_EAP_EK)+(LEN_EAP_MICK)) ++// TKIP key related ++#define LEN_PMKID 16 ++#define LEN_TKIP_EK 16 ++#define LEN_TKIP_RXMICK 8 ++#define LEN_TKIP_TXMICK 8 ++#define LEN_AES_EK 16 ++#define LEN_AES_KEY LEN_AES_EK ++#define LEN_TKIP_KEY ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) ++#define TKIP_AP_TXMICK_OFFSET ((LEN_EAP_KEY)+(LEN_TKIP_EK)) ++#define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) ++#define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) ++#define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) ++ ++// RSN IE Length definition ++#define MAX_LEN_OF_RSNIE 90 ++#define MIN_LEN_OF_RSNIE 8 ++ ++//EAP Packet Type ++#define EAPPacket 0 ++#define EAPOLStart 1 ++#define EAPOLLogoff 2 ++#define EAPOLKey 3 ++#define EAPOLASFAlert 4 ++#define EAPTtypeMax 5 ++ ++#define EAPOL_MSG_INVALID 0 ++#define EAPOL_PAIR_MSG_1 1 ++#define EAPOL_PAIR_MSG_2 2 ++#define EAPOL_PAIR_MSG_3 3 ++#define EAPOL_PAIR_MSG_4 4 ++#define EAPOL_GROUP_MSG_1 5 ++#define EAPOL_GROUP_MSG_2 6 ++ ++#define PAIRWISEKEY 1 ++#define GROUPKEY 0 ++ ++// Retry timer counter initial value ++#define PEER_MSG1_RETRY_TIMER_CTR 0 ++#define PEER_MSG3_RETRY_TIMER_CTR 10 ++#define GROUP_MSG1_RETRY_TIMER_CTR 20 ++ ++ ++#define EAPOL_START_DISABLE 0 ++#define EAPOL_START_PSK 1 ++#define EAPOL_START_1X 2 ++ ++#define MIX_CIPHER_WPA_TKIP_ON(x) (((x) & 0x08) != 0) ++#define MIX_CIPHER_WPA_AES_ON(x) (((x) & 0x04) != 0) ++#define MIX_CIPHER_WPA2_TKIP_ON(x) (((x) & 0x02) != 0) ++#define MIX_CIPHER_WPA2_AES_ON(x) (((x) & 0x01) != 0) ++ ++#define ROUND_UP(__x, __y) \ ++ (((ULONG)((__x)+((__y)-1))) & ((ULONG)~((__y)-1))) ++ ++#define ADD_ONE_To_64BIT_VAR(_V) \ ++{ \ ++ UCHAR cnt = LEN_KEY_DESC_REPLAY; \ ++ do \ ++ { \ ++ cnt--; \ ++ _V[cnt]++; \ ++ if (cnt == 0) \ ++ break; \ ++ }while (_V[cnt] == 0); \ ++} ++ ++#define IS_WPA_CAPABILITY(a) (((a) >= Ndis802_11AuthModeWPA) && ((a) <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ ++// EAPOL Key Information definition within Key descriptor format ++typedef struct PACKED _KEY_INFO ++{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR KeyAck:1; ++ UCHAR Install:1; ++ UCHAR KeyIndex:2; ++ UCHAR KeyType:1; ++ UCHAR KeyDescVer:3; ++ UCHAR Rsvd:3; ++ UCHAR EKD_DL:1; // EKD for AP; DL for STA ++ UCHAR Request:1; ++ UCHAR Error:1; ++ UCHAR Secure:1; ++ UCHAR KeyMic:1; ++#else ++ UCHAR KeyMic:1; ++ UCHAR Secure:1; ++ UCHAR Error:1; ++ UCHAR Request:1; ++ UCHAR EKD_DL:1; // EKD for AP; DL for STA ++ UCHAR Rsvd:3; ++ UCHAR KeyDescVer:3; ++ UCHAR KeyType:1; ++ UCHAR KeyIndex:2; ++ UCHAR Install:1; ++ UCHAR KeyAck:1; ++#endif ++} KEY_INFO, *PKEY_INFO; ++ ++// EAPOL Key descriptor format ++typedef struct PACKED _KEY_DESCRIPTER ++{ ++ UCHAR Type; ++ KEY_INFO KeyInfo; ++ UCHAR KeyLength[2]; ++ UCHAR ReplayCounter[LEN_KEY_DESC_REPLAY]; ++ UCHAR KeyNonce[LEN_KEY_DESC_NONCE]; ++ UCHAR KeyIv[LEN_KEY_DESC_IV]; ++ UCHAR KeyRsc[LEN_KEY_DESC_RSC]; ++ UCHAR KeyId[LEN_KEY_DESC_ID]; ++ UCHAR KeyMic[LEN_KEY_DESC_MIC]; ++ UCHAR KeyDataLen[2]; ++ UCHAR KeyData[MAX_LEN_OF_RSNIE]; ++} KEY_DESCRIPTER, *PKEY_DESCRIPTER; ++ ++typedef struct PACKED _EAPOL_PACKET ++{ ++ UCHAR ProVer; ++ UCHAR ProType; ++ UCHAR Body_Len[2]; ++ KEY_DESCRIPTER KeyDesc; ++} EAPOL_PACKET, *PEAPOL_PACKET; ++ ++//802.11i D10 page 83 ++typedef struct PACKED _GTK_ENCAP ++{ ++#ifndef RT_BIG_ENDIAN ++ UCHAR Kid:2; ++ UCHAR tx:1; ++ UCHAR rsv:5; ++ UCHAR rsv1; ++#else ++ UCHAR rsv:5; ++ UCHAR tx:1; ++ UCHAR Kid:2; ++ UCHAR rsv1; ++#endif ++ UCHAR GTK[TKIP_GTK_LENGTH]; ++} GTK_ENCAP, *PGTK_ENCAP; ++ ++typedef struct PACKED _KDE_ENCAP ++{ ++ UCHAR Type; ++ UCHAR Len; ++ UCHAR OUI[3]; ++ UCHAR DataType; ++ GTK_ENCAP GTKEncap; ++} KDE_ENCAP, *PKDE_ENCAP; ++ ++// For WPA1 ++typedef struct PACKED _RSNIE { ++ UCHAR oui[4]; ++ USHORT version; ++ UCHAR mcast[4]; ++ USHORT ucount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }ucast[1]; ++} RSNIE, *PRSNIE; ++ ++// For WPA2 ++typedef struct PACKED _RSNIE2 { ++ USHORT version; ++ UCHAR mcast[4]; ++ USHORT ucount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }ucast[1]; ++} RSNIE2, *PRSNIE2; ++ ++// AKM Suite ++typedef struct PACKED _RSNIE_AUTH { ++ USHORT acount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }auth[1]; ++} RSNIE_AUTH,*PRSNIE_AUTH; ++ ++typedef union PACKED _RSN_CAPABILITIES { ++ struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Rsvd:10; ++ USHORT GTKSA_R_Counter:2; ++ USHORT PTKSA_R_Counter:2; ++ USHORT No_Pairwise:1; ++ USHORT PreAuth:1; ++#else ++ USHORT PreAuth:1; ++ USHORT No_Pairwise:1; ++ USHORT PTKSA_R_Counter:2; ++ USHORT GTKSA_R_Counter:2; ++ USHORT Rsvd:10; ++#endif ++ } field; ++ USHORT word; ++} RSN_CAPABILITIES, *PRSN_CAPABILITIES; ++ ++typedef struct PACKED _EAP_HDR { ++ UCHAR ProVer; ++ UCHAR ProType; ++ UCHAR Body_Len[2]; ++ UCHAR code; ++ UCHAR identifier; ++ UCHAR length[2]; // including code and identifier, followed by length-2 octets of data ++} EAP_HDR, *PEAP_HDR; ++ ++// For supplicant state machine states. 802.11i Draft 4.1, p. 97 ++// We simplified it ++typedef enum _WpaState ++{ ++ SS_NOTUSE, // 0 ++ SS_START, // 1 ++ SS_WAIT_MSG_3, // 2 ++ SS_WAIT_GROUP, // 3 ++ SS_FINISH, // 4 ++ SS_KEYUPDATE, // 5 ++} WPA_STATE; ++ ++// ++// The definition of the cipher combination ++// ++// bit3 bit2 bit1 bit0 ++// +------------+------------+ ++// | WPA | WPA2 | ++// +------+-----+------+-----+ ++// | TKIP | AES | TKIP | AES | ++// | 0 | 1 | 1 | 0 | -> 0x06 ++// | 0 | 1 | 1 | 1 | -> 0x07 ++// | 1 | 0 | 0 | 1 | -> 0x09 ++// | 1 | 0 | 1 | 1 | -> 0x0B ++// | 1 | 1 | 0 | 1 | -> 0x0D ++// | 1 | 1 | 1 | 0 | -> 0x0E ++// | 1 | 1 | 1 | 1 | -> 0x0F ++// +------+-----+------+-----+ ++// ++typedef enum _WpaMixPairCipher ++{ ++ MIX_CIPHER_NOTUSE = 0x00, ++ WPA_NONE_WPA2_TKIPAES = 0x03, // WPA2-TKIPAES ++ WPA_AES_WPA2_TKIP = 0x06, ++ WPA_AES_WPA2_TKIPAES = 0x07, ++ WPA_TKIP_WPA2_AES = 0x09, ++ WPA_TKIP_WPA2_TKIPAES = 0x0B, ++ WPA_TKIPAES_WPA2_NONE = 0x0C, // WPA-TKIPAES ++ WPA_TKIPAES_WPA2_AES = 0x0D, ++ WPA_TKIPAES_WPA2_TKIP = 0x0E, ++ WPA_TKIPAES_WPA2_TKIPAES = 0x0F, ++} WPA_MIX_PAIR_CIPHER; ++ ++typedef struct PACKED _RSN_IE_HEADER_STRUCT { ++ UCHAR Eid; ++ UCHAR Length; ++ USHORT Version; // Little endian format ++} RSN_IE_HEADER_STRUCT, *PRSN_IE_HEADER_STRUCT; ++ ++// Cipher suite selector types ++typedef struct PACKED _CIPHER_SUITE_STRUCT { ++ UCHAR Oui[3]; ++ UCHAR Type; ++} CIPHER_SUITE_STRUCT, *PCIPHER_SUITE_STRUCT; ++ ++// Authentication and Key Management suite selector ++typedef struct PACKED _AKM_SUITE_STRUCT { ++ UCHAR Oui[3]; ++ UCHAR Type; ++} AKM_SUITE_STRUCT, *PAKM_SUITE_STRUCT; ++ ++// RSN capability ++typedef struct PACKED _RSN_CAPABILITY { ++ USHORT Rsv:10; ++ USHORT GTKSAReplayCnt:2; ++ USHORT PTKSAReplayCnt:2; ++ USHORT NoPairwise:1; ++ USHORT PreAuth:1; ++} RSN_CAPABILITY, *PRSN_CAPABILITY; ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt2870-wireless-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt2870-wireless-driver.patch new file mode 100644 index 000000000..347361d09 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt2870-wireless-driver.patch @@ -0,0 +1,110739 @@ +From 0d43598686dd4b9c4ef8fe9027ac60b5335feaa8 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 17 Dec 2008 17:04:23 -0800 +Subject: [PATCH 1/4] Staging: add rt2870 wireless driver + +From: Greg Kroah-Hartman + +This is the Ralink RT2870 driver from the company that does horrible +things like reading a config file from /etc. However, the driver that +is currently under development from the wireless development community +is not working at all yet, so distros and users are using this version +instead (quite common hardware on a lot of netbook machines). + +So here is this driver, for now, until the wireless developers get a +"clean" version into the main tree, or until this version is cleaned up +sufficiently to move out of the staging tree. + +Ported to the Linux build system and cleaned up a bit already by me. + +Cc: Linux wireless +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/rt2870/2870_main_dev.c | 1612 ++++ + drivers/staging/rt2870/Kconfig | 6 + drivers/staging/rt2870/Makefile | 47 + drivers/staging/rt2870/TODO | 10 + drivers/staging/rt2870/aironet.h | 210 + drivers/staging/rt2870/ap.h | 562 + + drivers/staging/rt2870/chlist.h | 1296 +++ + drivers/staging/rt2870/common/2870_rtmp_init.c | 1778 +++++ + drivers/staging/rt2870/common/action.c | 1046 +++ + drivers/staging/rt2870/common/action.h | 68 + drivers/staging/rt2870/common/ba_action.c | 1798 +++++ + drivers/staging/rt2870/common/cmm_data.c | 2734 +++++++ + drivers/staging/rt2870/common/cmm_data_2870.c | 963 ++ + drivers/staging/rt2870/common/cmm_info.c | 3712 ++++++++++ + drivers/staging/rt2870/common/cmm_sanity.c | 1663 ++++ + drivers/staging/rt2870/common/cmm_sync.c | 711 ++ + drivers/staging/rt2870/common/cmm_wpa.c | 1654 ++++ + drivers/staging/rt2870/common/dfs.c | 453 + + drivers/staging/rt2870/common/eeprom.c | 254 + drivers/staging/rt2870/common/firmware.h | 558 + + drivers/staging/rt2870/common/md5.c | 1427 ++++ + drivers/staging/rt2870/common/mlme.c | 8609 +++++++++++++++++++++++++ + drivers/staging/rt2870/common/netif_block.c | 144 + drivers/staging/rt2870/common/rtmp_init.c | 4132 +++++++++++ + drivers/staging/rt2870/common/rtmp_tkip.c | 1613 ++++ + drivers/staging/rt2870/common/rtmp_wep.c | 508 + + drivers/staging/rt2870/common/rtusb_bulk.c | 1981 +++++ + drivers/staging/rt2870/common/rtusb_data.c | 229 + drivers/staging/rt2870/common/rtusb_io.c | 2006 +++++ + drivers/staging/rt2870/common/spectrum.c | 1876 +++++ + drivers/staging/rt2870/dfs.h | 100 + drivers/staging/rt2870/leap.h | 215 + drivers/staging/rt2870/link_list.h | 134 + drivers/staging/rt2870/md4.h | 42 + drivers/staging/rt2870/md5.h | 107 + drivers/staging/rt2870/mlme.h | 1471 ++++ + drivers/staging/rt2870/netif_block.h | 58 + drivers/staging/rt2870/oid.h | 1091 +++ + drivers/staging/rt2870/rt2870.h | 761 ++ + drivers/staging/rt2870/rt28xx.h | 2689 +++++++ + drivers/staging/rt2870/rt_ate.c | 6452 ++++++++++++++++++ + drivers/staging/rt2870/rt_ate.h | 315 + drivers/staging/rt2870/rt_config.h | 104 + drivers/staging/rt2870/rt_linux.c | 1095 +++ + drivers/staging/rt2870/rt_linux.h | 908 ++ + drivers/staging/rt2870/rt_main_dev.c | 1863 +++++ + drivers/staging/rt2870/rt_profile.c | 2016 +++++ + drivers/staging/rt2870/rtmp.h | 7586 ++++++++++++++++++++++ + drivers/staging/rt2870/rtmp_ckipmic.h | 113 + drivers/staging/rt2870/rtmp_def.h | 1622 ++++ + drivers/staging/rt2870/rtmp_type.h | 94 + drivers/staging/rt2870/spectrum.h | 322 + drivers/staging/rt2870/spectrum_def.h | 95 + drivers/staging/rt2870/sta/aironet.c | 1312 +++ + drivers/staging/rt2870/sta/assoc.c | 2039 +++++ + drivers/staging/rt2870/sta/auth.c | 474 + + drivers/staging/rt2870/sta/auth_rsp.c | 166 + drivers/staging/rt2870/sta/connect.c | 2822 ++++++++ + drivers/staging/rt2870/sta/dls.c | 2210 ++++++ + drivers/staging/rt2870/sta/rtmp_data.c | 2619 +++++++ + drivers/staging/rt2870/sta/sanity.c | 420 + + drivers/staging/rt2870/sta/sync.c | 1753 +++++ + drivers/staging/rt2870/sta/wpa.c | 2107 ++++++ + drivers/staging/rt2870/sta_ioctl.c | 7068 ++++++++++++++++++++ + drivers/staging/rt2870/sta_ioctl.c.patch | 18 + drivers/staging/rt2870/tmp60 | 7037 ++++++++++++++++++++ + drivers/staging/rt2870/tmp61 | 7037 ++++++++++++++++++++ + drivers/staging/rt2870/wpa.h | 357 + + 70 files changed, 110355 insertions(+) + create mode 100644 drivers/staging/rt2870/2870_main_dev.c + create mode 100644 drivers/staging/rt2870/Kconfig + create mode 100644 drivers/staging/rt2870/Makefile + create mode 100644 drivers/staging/rt2870/TODO + create mode 100644 drivers/staging/rt2870/aironet.h + create mode 100644 drivers/staging/rt2870/ap.h + create mode 100644 drivers/staging/rt2870/chlist.h + create mode 100644 drivers/staging/rt2870/common/2870_rtmp_init.c + create mode 100644 drivers/staging/rt2870/common/action.c + create mode 100644 drivers/staging/rt2870/common/action.h + create mode 100644 drivers/staging/rt2870/common/ba_action.c + create mode 100644 drivers/staging/rt2870/common/cmm_data.c + create mode 100644 drivers/staging/rt2870/common/cmm_data_2870.c + create mode 100644 drivers/staging/rt2870/common/cmm_info.c + create mode 100644 drivers/staging/rt2870/common/cmm_sanity.c + create mode 100644 drivers/staging/rt2870/common/cmm_sync.c + create mode 100644 drivers/staging/rt2870/common/cmm_wpa.c + create mode 100644 drivers/staging/rt2870/common/dfs.c + create mode 100644 drivers/staging/rt2870/common/eeprom.c + create mode 100644 drivers/staging/rt2870/common/firmware.h + create mode 100644 drivers/staging/rt2870/common/md5.c + create mode 100644 drivers/staging/rt2870/common/mlme.c + create mode 100644 drivers/staging/rt2870/common/netif_block.c + create mode 100644 drivers/staging/rt2870/common/rtmp_init.c + create mode 100644 drivers/staging/rt2870/common/rtmp_tkip.c + create mode 100644 drivers/staging/rt2870/common/rtmp_wep.c + create mode 100644 drivers/staging/rt2870/common/rtusb_bulk.c + create mode 100644 drivers/staging/rt2870/common/rtusb_data.c + create mode 100644 drivers/staging/rt2870/common/rtusb_io.c + create mode 100644 drivers/staging/rt2870/common/spectrum.c + create mode 100644 drivers/staging/rt2870/dfs.h + create mode 100644 drivers/staging/rt2870/leap.h + create mode 100644 drivers/staging/rt2870/link_list.h + create mode 100644 drivers/staging/rt2870/md4.h + create mode 100644 drivers/staging/rt2870/md5.h + create mode 100644 drivers/staging/rt2870/mlme.h + create mode 100644 drivers/staging/rt2870/netif_block.h + create mode 100644 drivers/staging/rt2870/oid.h + create mode 100644 drivers/staging/rt2870/rt2870.h + create mode 100644 drivers/staging/rt2870/rt28xx.h + create mode 100644 drivers/staging/rt2870/rt_ate.c + create mode 100644 drivers/staging/rt2870/rt_ate.h + create mode 100644 drivers/staging/rt2870/rt_config.h + create mode 100644 drivers/staging/rt2870/rt_linux.c + create mode 100644 drivers/staging/rt2870/rt_linux.h + create mode 100644 drivers/staging/rt2870/rt_main_dev.c + create mode 100644 drivers/staging/rt2870/rt_profile.c + create mode 100644 drivers/staging/rt2870/rtmp.h + create mode 100644 drivers/staging/rt2870/rtmp_ckipmic.h + create mode 100644 drivers/staging/rt2870/rtmp_def.h + create mode 100644 drivers/staging/rt2870/rtmp_type.h + create mode 100644 drivers/staging/rt2870/spectrum.h + create mode 100644 drivers/staging/rt2870/spectrum_def.h + create mode 100644 drivers/staging/rt2870/sta/aironet.c + create mode 100644 drivers/staging/rt2870/sta/assoc.c + create mode 100644 drivers/staging/rt2870/sta/auth.c + create mode 100644 drivers/staging/rt2870/sta/auth_rsp.c + create mode 100644 drivers/staging/rt2870/sta/connect.c + create mode 100644 drivers/staging/rt2870/sta/dls.c + create mode 100644 drivers/staging/rt2870/sta/rtmp_data.c + create mode 100644 drivers/staging/rt2870/sta/sanity.c + create mode 100644 drivers/staging/rt2870/sta/sync.c + create mode 100644 drivers/staging/rt2870/sta/wpa.c + create mode 100644 drivers/staging/rt2870/sta_ioctl.c + create mode 100644 drivers/staging/rt2870/sta_ioctl.c.patch + create mode 100644 drivers/staging/rt2870/tmp60 + create mode 100644 drivers/staging/rt2870/tmp61 + create mode 100644 drivers/staging/rt2870/wpa.h + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -49,6 +49,8 @@ source "drivers/staging/otus/Kconfig" + + source "drivers/staging/rt2860/Kconfig" + ++source "drivers/staging/rt2870/Kconfig" ++ + source "drivers/staging/benet/Kconfig" + + source "drivers/staging/rtl8187se/Kconfig" +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -16,5 +16,6 @@ obj-$(CONFIG_USB_ATMEL) += at76_usb/ + obj-$(CONFIG_AGNX) += agnx/ + obj-$(CONFIG_OTUS) += otus/ + obj-$(CONFIG_RT2860) += rt2860/ ++obj-$(CONFIG_RT2870) += rt2870/ + obj-$(CONFIG_BENET) += benet/ + obj-$(CONFIG_RTL8187SE) += rtl8187se/ +--- /dev/null ++++ b/drivers/staging/rt2870/2870_main_dev.c +@@ -0,0 +1,1612 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_main.c ++ ++ Abstract: ++ main initialization routines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Jan Lee 01-10-2005 modified ++ Sample Jun/01/07 Merge RT2870 and RT2860 drivers. ++*/ ++ ++#include "rt_config.h" ++ ++ ++// Following information will be show when you run 'modinfo' ++// *** If you have a solution for the bug in current version of driver, please mail to me. ++// Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** ++MODULE_AUTHOR("Paul Lin "); ++MODULE_DESCRIPTION("RT2870 Wireless Lan Linux Driver"); ++#ifdef CONFIG_STA_SUPPORT ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_VERSION ++MODULE_VERSION(STA_DRIVER_VERSION); ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// record whether the card in the card list is used in the card file ++extern UINT8 MC_CardUsed[]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++/* Kernel thread and vars, which handles packets that are completed. Only ++ * packets that have a "complete" function are sent here. This way, the ++ * completion is run out of kernel context, and doesn't block the rest of ++ * the stack. */ ++ ++extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, ++ IN UINT argc, OUT PRTMP_ADAPTER *ppAd); ++ ++ ++/* module table */ ++struct usb_device_id rtusb_usb_id[] = RT2870_USB_DEVICES; ++INT const rtusb_usb_id_len = sizeof(rtusb_usb_id) / sizeof(struct usb_device_id); ++MODULE_DEVICE_TABLE(usb, rtusb_usb_id); ++ ++#ifndef PF_NOFREEZE ++#define PF_NOFREEZE 0 ++#endif ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ ++/**************************************************************************/ ++/**************************************************************************/ ++//tested for kernel 2.4 series ++/**************************************************************************/ ++/**************************************************************************/ ++static void *rtusb_probe(struct usb_device *dev, UINT interface, ++ const struct usb_device_id *id_table); ++static void rtusb_disconnect(struct usb_device *dev, void *ptr); ++ ++struct usb_driver rtusb_driver = { ++ name:"rt2870", ++ probe:rtusb_probe, ++ disconnect:rtusb_disconnect, ++ id_table:rtusb_usb_id, ++ }; ++ ++#else ++ ++#ifdef CONFIG_PM ++static int rt2870_suspend(struct usb_interface *intf, pm_message_t state); ++static int rt2870_resume(struct usb_interface *intf); ++#endif // CONFIG_PM // ++ ++/**************************************************************************/ ++/**************************************************************************/ ++//tested for kernel 2.6series ++/**************************************************************************/ ++/**************************************************************************/ ++static int rtusb_probe (struct usb_interface *intf, ++ const struct usb_device_id *id); ++static void rtusb_disconnect(struct usb_interface *intf); ++ ++struct usb_driver rtusb_driver = { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ .owner = THIS_MODULE, ++#endif ++ .name="rt2870", ++ .probe=rtusb_probe, ++ .disconnect=rtusb_disconnect, ++ .id_table=rtusb_usb_id, ++ ++#ifdef CONFIG_PM ++ suspend: rt2870_suspend, ++ resume: rt2870_resume, ++#endif ++ }; ++ ++#ifdef CONFIG_PM ++ ++VOID RT2860RejectPendingPackets( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // clear PS packets ++ // clear TxSw packets ++} ++ ++static int rt2870_suspend( ++ struct usb_interface *intf, ++ pm_message_t state) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = usb_get_intfdata(intf); ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_suspend()\n")); ++ net_dev = pAd->net_dev; ++ netif_device_detach (net_dev); ++ ++ pAd->PM_FlgSuspend = 1; ++ if (netif_running(net_dev)) { ++ RTUSBCancelPendingBulkInIRP(pAd); ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_suspend()\n")); ++ return 0; ++} ++ ++static int rt2870_resume( ++ struct usb_interface *intf) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = usb_get_intfdata(intf); ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_resume()\n")); ++ ++ pAd->PM_FlgSuspend = 0; ++ net_dev = pAd->net_dev; ++ netif_device_attach (net_dev); ++ netif_start_queue(net_dev); ++ netif_carrier_on(net_dev); ++ netif_wake_queue(net_dev); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_resume()\n")); ++ return 0; ++} ++#endif // CONFIG_PM // ++#endif // LINUX_VERSION_CODE // ++ ++ ++// Init driver module ++INT __init rtusb_init(void) ++{ ++ printk("rtusb init --->\n"); ++ return usb_register(&rtusb_driver); ++} ++ ++// Deinit driver module ++VOID __exit rtusb_exit(void) ++{ ++ usb_deregister(&rtusb_driver); ++ printk("<--- rtusb exit\n"); ++} ++ ++module_init(rtusb_init); ++module_exit(rtusb_exit); ++ ++ ++ ++ ++/*--------------------------------------------------------------------- */ ++/* function declarations */ ++/*--------------------------------------------------------------------- */ ++ ++/* ++======================================================================== ++Routine Description: ++ MLME kernel thread. ++ ++Arguments: ++ *Context the pAd, driver control block pointer ++ ++Return Value: ++ 0 close the thread ++ ++Note: ++======================================================================== ++*/ ++INT MlmeThread( ++ IN void *Context) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; ++ POS_COOKIE pObj; ++ int status; ++ ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ rtmp_os_thread_init("rt2870MlmeThread", (PVOID)&(pAd->mlmeComplete)); ++ ++ while (pAd->mlme_kill == 0) ++ { ++ /* lock the device pointers */ ++ //down(&(pAd->mlme_semaphore)); ++ status = down_interruptible(&(pAd->mlme_semaphore)); ++ ++ /* lock the device pointers , need to check if required*/ ++ //down(&(pAd->usbdev_semaphore)); ++ ++ if (!pAd->PM_FlgSuspend) ++ MlmeHandler(pAd); ++ ++ /* unlock the device pointers */ ++ //up(&(pAd->usbdev_semaphore)); ++ if (status != 0) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ break; ++ } ++ } ++ ++ /* notify the exit routine that we're actually exiting now ++ * ++ * complete()/wait_for_completion() is similar to up()/down(), ++ * except that complete() is safe in the case where the structure ++ * is getting deleted in a parallel mode of execution (i.e. just ++ * after the down() -- that's necessary for the thread-shutdown ++ * case. ++ * ++ * complete_and_exit() goes even further than this -- it is safe in ++ * the case that the thread of the caller is going away (not just ++ * the structure) -- this is necessary for the module-remove case. ++ * This is important in preemption kernels, which transfer the flow ++ * of execution immediately upon a complete(). ++ */ ++ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); ++ ++ pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE; ++ ++ complete_and_exit (&pAd->mlmeComplete, 0); ++ return 0; ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ USB command kernel thread. ++ ++Arguments: ++ *Context the pAd, driver control block pointer ++ ++Return Value: ++ 0 close the thread ++ ++Note: ++======================================================================== ++*/ ++INT RTUSBCmdThread( ++ IN void * Context) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; ++ POS_COOKIE pObj; ++ int status; ++ ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ rtmp_os_thread_init("rt2870CmdThread", (PVOID)&(pAd->CmdQComplete)); ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ pAd->CmdQ.CmdQState = RT2870_THREAD_RUNNING; ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ while (pAd->CmdQ.CmdQState == RT2870_THREAD_RUNNING) ++ { ++ /* lock the device pointers */ ++ //down(&(pAd->RTUSBCmd_semaphore)); ++ status = down_interruptible(&(pAd->RTUSBCmd_semaphore)); ++ ++ if (pAd->CmdQ.CmdQState == RT2870_THREAD_STOPED) ++ break; ++ ++ if (status != 0) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ break; ++ } ++ /* lock the device pointers , need to check if required*/ ++ //down(&(pAd->usbdev_semaphore)); ++ ++ if (!pAd->PM_FlgSuspend) ++ CMDHandler(pAd); ++ ++ /* unlock the device pointers */ ++ //up(&(pAd->usbdev_semaphore)); ++ } ++ ++ if (!pAd->PM_FlgSuspend) ++ { // Clear the CmdQElements. ++ CmdQElmt *pCmdQElmt = NULL; ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; ++ while(pAd->CmdQ.size) ++ { ++ RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt); ++ if (pCmdQElmt) ++ { ++ if (pCmdQElmt->CmdFromNdis == TRUE) ++ { ++ if (pCmdQElmt->buffer != NULL) ++ NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); ++ ++ NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ { ++ if ((pCmdQElmt->buffer != NULL) && (pCmdQElmt->bufferlength != 0)) ++ NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); ++ { ++ NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); ++ } ++ } ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ } ++ /* notify the exit routine that we're actually exiting now ++ * ++ * complete()/wait_for_completion() is similar to up()/down(), ++ * except that complete() is safe in the case where the structure ++ * is getting deleted in a parallel mode of execution (i.e. just ++ * after the down() -- that's necessary for the thread-shutdown ++ * case. ++ * ++ * complete_and_exit() goes even further than this -- it is safe in ++ * the case that the thread of the caller is going away (not just ++ * the structure) -- this is necessary for the module-remove case. ++ * This is important in preemption kernels, which transfer the flow ++ * of execution immediately upon a complete(). ++ */ ++ DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n")); ++ ++ pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE; ++ ++ complete_and_exit (&pAd->CmdQComplete, 0); ++ return 0; ++ ++} ++ ++ ++static void RT2870_TimerQ_Handle(RTMP_ADAPTER *pAd) ++{ ++ int status; ++ RALINK_TIMER_STRUCT *pTimer; ++ RT2870_TIMER_ENTRY *pEntry; ++ unsigned long irqFlag; ++ ++ while(!pAd->TimerFunc_kill) ++ { ++// printk("waiting for event!\n"); ++ pTimer = NULL; ++ ++ status = down_interruptible(&(pAd->RTUSBTimer_semaphore)); ++ ++ if (pAd->TimerQ.status == RT2870_THREAD_STOPED) ++ break; ++ ++ // event happened. ++ while(pAd->TimerQ.pQHead) ++ { ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlag); ++ pEntry = pAd->TimerQ.pQHead; ++ if (pEntry) ++ { ++ pTimer = pEntry->pRaTimer; ++ ++ // update pQHead ++ pAd->TimerQ.pQHead = pEntry->pNext; ++ if (pEntry == pAd->TimerQ.pQTail) ++ pAd->TimerQ.pQTail = NULL; ++ ++ // return this queue entry to timerQFreeList. ++ pEntry->pNext = pAd->TimerQ.pQPollFreeList; ++ pAd->TimerQ.pQPollFreeList = pEntry; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlag); ++ ++ if (pTimer) ++ { ++ if (pTimer->handle != NULL) ++ if (!pAd->PM_FlgSuspend) ++ pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer); ++ if ((pTimer->Repeat) && (pTimer->State == FALSE)) ++ RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); ++ } ++ } ++ ++ if (status != 0) ++ { ++ pAd->TimerQ.status = RT2870_THREAD_STOPED; ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ break; ++ } ++ } ++} ++ ++ ++INT TimerQThread( ++ IN OUT PVOID Context) ++{ ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ pAd = (PRTMP_ADAPTER)Context; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ rtmp_os_thread_init("rt2870TimerQHandle", (PVOID)&(pAd->TimerQComplete)); ++ ++ RT2870_TimerQ_Handle(pAd); ++ ++ /* notify the exit routine that we're actually exiting now ++ * ++ * complete()/wait_for_completion() is similar to up()/down(), ++ * except that complete() is safe in the case where the structure ++ * is getting deleted in a parallel mode of execution (i.e. just ++ * after the down() -- that's necessary for the thread-shutdown ++ * case. ++ * ++ * complete_and_exit() goes even further than this -- it is safe in ++ * the case that the thread of the caller is going away (not just ++ * the structure) -- this is necessary for the module-remove case. ++ * This is important in preemption kernels, which transfer the flow ++ * of execution immediately upon a complete(). ++ */ ++ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); ++ ++ pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE; ++ ++ complete_and_exit(&pAd->TimerQComplete, 0); ++ return 0; ++ ++} ++ ++ ++RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer) ++{ ++ RT2870_TIMER_ENTRY *pQNode = NULL, *pQTail; ++ unsigned long irqFlags; ++ ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ if (pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT) ++ { ++ if(pAd->TimerQ.pQPollFreeList) ++ { ++ pQNode = pAd->TimerQ.pQPollFreeList; ++ pAd->TimerQ.pQPollFreeList = pQNode->pNext; ++ ++ pQNode->pRaTimer = pTimer; ++ pQNode->pNext = NULL; ++ ++ pQTail = pAd->TimerQ.pQTail; ++ if (pAd->TimerQ.pQTail != NULL) ++ pQTail->pNext = pQNode; ++ pAd->TimerQ.pQTail = pQNode; ++ if (pAd->TimerQ.pQHead == NULL) ++ pAd->TimerQ.pQHead = pQNode; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ ++ if (pQNode) ++ up(&pAd->RTUSBTimer_semaphore); ++ //wake_up(&timerWaitQ); ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ } ++ return pQNode; ++} ++ ++ ++BOOLEAN RT2870_TimerQ_Remove( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer) ++{ ++ RT2870_TIMER_ENTRY *pNode, *pPrev = NULL; ++ unsigned long irqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ if (pAd->TimerQ.status >= RT2870_THREAD_INITED) ++ { ++ pNode = pAd->TimerQ.pQHead; ++ while (pNode) ++ { ++ if (pNode->pRaTimer == pTimer) ++ break; ++ pPrev = pNode; ++ pNode = pNode->pNext; ++ } ++ ++ // Now move it to freeList queue. ++ if (pNode) ++ { ++ if (pNode == pAd->TimerQ.pQHead) ++ pAd->TimerQ.pQHead = pNode->pNext; ++ if (pNode == pAd->TimerQ.pQTail) ++ pAd->TimerQ.pQTail = pPrev; ++ if (pPrev != NULL) ++ pPrev->pNext = pNode->pNext; ++ ++ // return this queue entry to timerQFreeList. ++ pNode->pNext = pAd->TimerQ.pQPollFreeList; ++ pAd->TimerQ.pQPollFreeList = pNode; ++ } ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ ++ return TRUE; ++} ++ ++ ++void RT2870_TimerQ_Exit(RTMP_ADAPTER *pAd) ++{ ++ RT2870_TIMER_ENTRY *pTimerQ; ++ unsigned long irqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ while (pAd->TimerQ.pQHead) ++ { ++ pTimerQ = pAd->TimerQ.pQHead; ++ pAd->TimerQ.pQHead = pTimerQ->pNext; ++ // remove the timeQ ++ } ++ pAd->TimerQ.pQPollFreeList = NULL; ++ os_free_mem(pAd, pAd->TimerQ.pTimerQPoll); ++ pAd->TimerQ.pQTail = NULL; ++ pAd->TimerQ.pQHead = NULL; ++ pAd->TimerQ.status = RT2870_THREAD_STOPED; ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ ++} ++ ++ ++void RT2870_TimerQ_Init(RTMP_ADAPTER *pAd) ++{ ++ int i; ++ RT2870_TIMER_ENTRY *pQNode, *pEntry; ++ unsigned long irqFlags; ++ ++ NdisAllocateSpinLock(&pAd->TimerQLock); ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ)); ++ //InterlockedExchange(&pAd->TimerQ.count, 0); ++ ++ /* Initialise the wait q head */ ++ //init_waitqueue_head(&timerWaitQ); ++ ++ os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RT2870_TIMER_ENTRY) * TIMER_QUEUE_SIZE_MAX); ++ if (pAd->TimerQ.pTimerQPoll) ++ { ++ pEntry = NULL; ++ pQNode = (RT2870_TIMER_ENTRY *)pAd->TimerQ.pTimerQPoll; ++ for (i = 0 ;i pNext = pEntry; ++ pEntry = pQNode; ++ pQNode++; ++ } ++ pAd->TimerQ.pQPollFreeList = pEntry; ++ pAd->TimerQ.pQHead = NULL; ++ pAd->TimerQ.pQTail = NULL; ++ pAd->TimerQ.status = RT2870_THREAD_INITED; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++} ++ ++ ++VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) ++{ ++ PHT_TX_CONTEXT pHTTXContext; ++ int idx; ++ ULONG irqFlags; ++ PURB pUrb; ++ BOOLEAN needDumpSeq = FALSE; ++ UINT32 MACValue; ++ ++ ++ idx = 0; ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); ++ if ((MACValue & 0xff) !=0 ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 0 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40012); ++ while((MACValue &0xff) != 0 && (idx++ < 10)) ++ { ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); ++ NdisMSleep(1); ++ } ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); ++ } ++ ++ idx = 0; ++ if ((MACValue & 0xff00) !=0 ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 1 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf4000a); ++ while((MACValue &0xff00) != 0 && (idx++ < 10)) ++ { ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); ++ NdisMSleep(1); ++ } ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); ++ } ++ ++ ++ if (pAd->watchDogRxOverFlowCnt >= 2) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Rx Bulk-In hanged! Cancel the pending Rx bulks request!\n")); ++ if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_BULKIN_RESET | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Call CMDTHREAD_RESET_BULK_IN to cancel the pending Rx Bulk!\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); ++ needDumpSeq = TRUE; ++ } ++ pAd->watchDogRxOverFlowCnt = 0; ++ } ++ ++ ++ for (idx = 0; idx < NUM_OF_TX_RING; idx++) ++ { ++ pUrb = NULL; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[idx], irqFlags); ++ if ((pAd->BulkOutPending[idx] == TRUE) && pAd->watchDogTxPendingCnt) ++ { ++ pAd->watchDogTxPendingCnt[idx]++; ++ ++ if ((pAd->watchDogTxPendingCnt[idx] > 2) && ++ (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_BULKOUT_RESET))) ++ ) ++ { ++ // FIXME: Following code just support single bulk out. If you wanna support multiple bulk out. Modify it! ++ pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[idx]); ++ if (pHTTXContext->IRPPending) ++ { // Check TxContext. ++ pUrb = pHTTXContext->pUrb; ++ } ++ else if (idx == MGMTPIPEIDX) ++ { ++ PTX_CONTEXT pMLMEContext, pNULLContext, pPsPollContext; ++ ++ //Check MgmtContext. ++ pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); ++ pPsPollContext = (PTX_CONTEXT)(&pAd->PsPollContext); ++ pNULLContext = (PTX_CONTEXT)(&pAd->NullContext); ++ ++ if (pMLMEContext->IRPPending) ++ { ++ ASSERT(pMLMEContext->IRPPending); ++ pUrb = pMLMEContext->pUrb; ++ } ++ else if (pNULLContext->IRPPending) ++ { ++ ASSERT(pNULLContext->IRPPending); ++ pUrb = pNULLContext->pUrb; ++ } ++ else if (pPsPollContext->IRPPending) ++ { ++ ASSERT(pPsPollContext->IRPPending); ++ pUrb = pPsPollContext->pUrb; ++ } ++ } ++ ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Tx Bulk-Out hanged! Cancel the pending Tx bulks request of idx(%d)!\n", idx)); ++ if (pUrb) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Unlink the pending URB!\n")); ++ // unlink it now ++ RTUSB_UNLINK_URB(pUrb); ++ // Sleep 200 microseconds to give cancellation time to work ++ RTMPusecDelay(200); ++ needDumpSeq = TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Unkonw bulkOut URB maybe hanged!!!!!!!!!!!!\n")); ++ } ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); ++ } ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); ++ } ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // For Sigma debug, dump the ba_reordering sequence. ++ if((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ USHORT Idx; ++ PBA_REC_ENTRY pBAEntry = NULL; ++ UCHAR count = 0; ++ struct reordering_mpdu *mpdu_blk; ++ ++ Idx = pAd->MacTab.Content[BSSID_WCID].BARecWcidArray[0]; ++ ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ if((pBAEntry->list.qlen > 0) && (pBAEntry->list.next != NULL)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("NICUpdateRawCounters():The Queueing pkt in reordering buffer:\n")); ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ mpdu_blk = pBAEntry->list.next; ++ while (mpdu_blk) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("\t%d:Seq-%d, bAMSDU-%d!\n", count, mpdu_blk->Sequence, mpdu_blk->bAMSDU)); ++ mpdu_blk = mpdu_blk->next; ++ count++; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\npBAEntry->LastIndSeq=%d!\n", pBAEntry->LastIndSeq)); ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Release allocated resources. ++ ++Arguments: ++ *dev Point to the PCI or USB device ++ pAd driver control block pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd) ++{ ++ struct net_device *net_dev = NULL; ++ ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("rtusb_disconnect: unregister usbnet usb-%s-%s\n", ++ dev->bus->bus_name, dev->devpath)); ++ if (!pAd) ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) ++ MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ while(MOD_IN_USE > 0) ++ { ++ MOD_DEC_USE_COUNT; ++ } ++#else ++ usb_put_dev(dev); ++#endif // LINUX_VERSION_CODE // ++ ++ printk("rtusb_disconnect: pAd == NULL!\n"); ++ return; ++ } ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); ++ ++ ++ ++ // for debug, wait to show some messages to /proc system ++ udelay(1); ++ ++ ++ ++ ++ net_dev = pAd->net_dev; ++ if (pAd->net_dev != NULL) ++ { ++ printk("rtusb_disconnect: unregister_netdev(), dev->name=%s!\n", net_dev->name); ++ unregister_netdev (pAd->net_dev); ++ } ++ udelay(1); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++#else ++ flush_scheduled_work(); ++#endif // LINUX_VERSION_CODE // ++ udelay(1); ++ ++ // free net_device memory ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ kfree(net_dev); ++#else ++ free_netdev(net_dev); ++#endif // LINUX_VERSION_CODE // ++ ++ // free adapter memory ++ RTMPFreeAdapter(pAd); ++ ++ // release a use of the usb device structure ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ while(MOD_IN_USE > 0) ++ { ++ MOD_DEC_USE_COUNT; ++ } ++#else ++ usb_put_dev(dev); ++#endif // LINUX_VERSION_CODE // ++ udelay(1); ++ ++ DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n")); ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Probe RT28XX chipset. ++ ++Arguments: ++ *dev Point to the PCI or USB device ++ interface ++ *id_table Point to the PCI or USB device ID ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++static void *rtusb_probe(struct usb_device *dev, UINT interface, ++ const struct usb_device_id *id) ++{ ++ PRTMP_ADAPTER pAd; ++ rt28xx_probe((void *)dev, (void *)id, interface, &pAd); ++ return (void *)pAd; ++} ++ ++//Disconnect function is called within exit routine ++static void rtusb_disconnect(struct usb_device *dev, void *ptr) ++{ ++ _rtusb_disconnect(dev, ((PRTMP_ADAPTER)ptr)); ++} ++ ++#else /* kernel 2.6 series */ ++static int rtusb_probe (struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ PRTMP_ADAPTER pAd; ++ return (int)rt28xx_probe((void *)intf, (void *)id, 0, &pAd); ++} ++ ++ ++static void rtusb_disconnect(struct usb_interface *intf) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ PRTMP_ADAPTER pAd; ++ ++ ++ pAd = usb_get_intfdata(intf); ++ usb_set_intfdata(intf, NULL); ++ ++ _rtusb_disconnect(dev, pAd); ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Close kernel threads. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ NONE ++ ++Note: ++======================================================================== ++*/ ++VOID RT28xxThreadTerminate( ++ IN RTMP_ADAPTER *pAd) ++{ ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ INT ret; ++ ++ ++ // Sleep 50 milliseconds so pending io might finish normally ++ RTMPusecDelay(50000); ++ ++ // We want to wait until all pending receives and sends to the ++ // device object. We cancel any ++ // irps. Wait until sends and receives have stopped. ++ RTUSBCancelPendingIRPs(pAd); ++ ++ // Terminate Threads ++ CHECK_PID_LEGALITY(pObj->TimerQThr_pid) ++ { ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ printk("Terminate the TimerQThr_pid=%d!\n", GET_PID_NUMBER(pObj->TimerQThr_pid)); ++ mb(); ++ pAd->TimerFunc_kill = 1; ++ mb(); ++ ret = KILL_THREAD_PID(pObj->TimerQThr_pid, SIGTERM, 1); ++ if (ret) ++ { ++ printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n", ++ pAd->net_dev->name, GET_PID_NUMBER(pObj->TimerQThr_pid), ret); ++ } ++ else ++ { ++ wait_for_completion(&pAd->TimerQComplete); ++ pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE; ++ } ++ } ++ ++ CHECK_PID_LEGALITY(pObj->MLMEThr_pid) ++ { ++ printk("Terminate the MLMEThr_pid=%d!\n", GET_PID_NUMBER(pObj->MLMEThr_pid)); ++ mb(); ++ pAd->mlme_kill = 1; ++ //RT28XX_MLME_HANDLER(pAd); ++ mb(); ++ ret = KILL_THREAD_PID(pObj->MLMEThr_pid, SIGTERM, 1); ++ if (ret) ++ { ++ printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n", ++ pAd->net_dev->name, GET_PID_NUMBER(pObj->MLMEThr_pid), ret); ++ } ++ else ++ { ++ //wait_for_completion (&pAd->notify); ++ wait_for_completion (&pAd->mlmeComplete); ++ pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE; ++ } ++ } ++ ++ CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) ++ { ++ printk("Terminate the RTUSBCmdThr_pid=%d!\n", GET_PID_NUMBER(pObj->RTUSBCmdThr_pid)); ++ mb(); ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ mb(); ++ //RTUSBCMDUp(pAd); ++ ret = KILL_THREAD_PID(pObj->RTUSBCmdThr_pid, SIGTERM, 1); ++ if (ret) ++ { ++ printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n", ++ pAd->net_dev->name, GET_PID_NUMBER(pObj->RTUSBCmdThr_pid), ret); ++ } ++ else ++ { ++ //wait_for_completion (&pAd->notify); ++ wait_for_completion (&pAd->CmdQComplete); ++ pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE; ++ } ++ } ++ ++ ++ // Kill tasklets ++ pAd->mlme_kill = 0; ++ pAd->CmdQ.CmdQState = RT2870_THREAD_UNKNOWN; ++ pAd->TimerFunc_kill = 0; ++} ++ ++ ++void kill_thread_task(IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE pObj; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ tasklet_kill(&pObj->rx_done_task); ++ tasklet_kill(&pObj->mgmt_dma_done_task); ++ tasklet_kill(&pObj->ac0_dma_done_task); ++ tasklet_kill(&pObj->ac1_dma_done_task); ++ tasklet_kill(&pObj->ac2_dma_done_task); ++ tasklet_kill(&pObj->ac3_dma_done_task); ++ tasklet_kill(&pObj->hcca_dma_done_task); ++ tasklet_kill(&pObj->tbtt_task); ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Check the chipset vendor/product ID. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ ++Return Value: ++ TRUE Check ok ++ FALSE Check fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXChipsetCheck( ++ IN void *_dev_p) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++#else ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_device *dev_p = interface_to_usbdev(intf); ++#endif // LINUX_VERSION_CODE // ++ UINT32 i; ++ ++ ++ for(i=0; idescriptor.idVendor == rtusb_usb_id[i].idVendor && ++ dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) ++ { ++ printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", ++ dev_p->descriptor.idVendor, dev_p->descriptor.idProduct); ++ break; ++ } ++ } ++ ++ if (i == rtusb_usb_id_len) ++ { ++ printk("rt2870: Error! Device Descriptor not matching!\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Init net device structure. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ *net_dev Point to the net device ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ TRUE Init ok ++ FALSE Init fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXNetDevInit( ++ IN void *_dev_p, ++ IN struct net_device *net_dev, ++ IN RTMP_ADAPTER *pAd) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++#else ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_device *dev_p = interface_to_usbdev(intf); ++#endif // LINUX_VERSION_CODE // ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ pAd->config = dev_p->config; ++#else ++ pAd->config = &dev_p->config->desc; ++#endif // LINUX_VERSION_CODE // ++ return TRUE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Init net device structure. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ TRUE Config ok ++ FALSE Config fail ++ ++Note: ++======================================================================== ++*/ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 interface) ++{ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++ struct usb_interface *intf; ++ struct usb_interface_descriptor *iface_desc; ++ struct usb_endpoint_descriptor *endpoint; ++ ULONG BulkOutIdx; ++ UINT32 i; ++ ++ ++ /* get the active interface descriptor */ ++ intf = &dev_p->actconfig->interface[interface]; ++ iface_desc = &intf->altsetting[0]; ++ ++ /* get # of enpoints */ ++ pAd->NumberOfPipes = iface_desc->bNumEndpoints; ++ DBGPRINT(RT_DEBUG_TRACE, ("NumEndpoints=%d\n", iface_desc->bNumEndpoints)); ++ ++ /* Configure Pipes */ ++ endpoint = &iface_desc->endpoint[0]; ++ BulkOutIdx = 0; ++ ++ for(i=0; iNumberOfPipes; i++) ++ { ++ if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && ++ ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) ++ { ++ pAd->BulkInEpAddr = endpoint[i].bEndpointAddress; ++ pAd->BulkInMaxPacketSize = endpoint[i].wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); ++ } ++ else if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && ++ ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) ++ { ++ // There are 6 bulk out EP. EP6 highest priority. ++ // EP1-4 is EDCA. EP5 is HCCA. ++ pAd->BulkOutEpAddr[BulkOutIdx++] = endpoint[i].bEndpointAddress; ++ pAd->BulkOutMaxPacketSize = endpoint[i].wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); ++ } ++ } ++ ++ if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) ++ { ++ printk("Could not find both bulk-in and bulk-out endpoints\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++#else ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 interface) ++{ ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_host_interface *iface_desc; ++ ULONG BulkOutIdx; ++ UINT32 i; ++ ++ ++ /* get the active interface descriptor */ ++ iface_desc = intf->cur_altsetting; ++ ++ /* get # of enpoints */ ++ pAd->NumberOfPipes = iface_desc->desc.bNumEndpoints; ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("NumEndpoints=%d\n", iface_desc->desc.bNumEndpoints)); ++ ++ /* Configure Pipes */ ++ BulkOutIdx = 0; ++ ++ for(i=0; iNumberOfPipes; i++) ++ { ++ if ((iface_desc->endpoint[i].desc.bmAttributes == ++ USB_ENDPOINT_XFER_BULK) && ++ ((iface_desc->endpoint[i].desc.bEndpointAddress & ++ USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) ++ { ++ pAd->BulkInEpAddr = iface_desc->endpoint[i].desc.bEndpointAddress; ++ pAd->BulkInMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x\n", iface_desc->endpoint[i].desc.bEndpointAddress)); ++ } ++ else if ((iface_desc->endpoint[i].desc.bmAttributes == ++ USB_ENDPOINT_XFER_BULK) && ++ ((iface_desc->endpoint[i].desc.bEndpointAddress & ++ USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) ++ { ++ // there are 6 bulk out EP. EP6 highest priority. ++ // EP1-4 is EDCA. EP5 is HCCA. ++ pAd->BulkOutEpAddr[BulkOutIdx++] = iface_desc->endpoint[i].desc.bEndpointAddress; ++ pAd->BulkOutMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x \n", iface_desc->endpoint[i].desc.bEndpointAddress)); ++ } ++ } ++ ++ if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) ++ { ++ printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Disable DMA. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28XXDMADisable( ++ IN RTMP_ADAPTER *pAd) ++{ ++ // no use ++} ++ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Enable DMA. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28XXDMAEnable( ++ IN RTMP_ADAPTER *pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ USB_DMA_CFG_STRUC UsbCfg; ++ int i = 0; ++ ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i <200); ++ ++ ++ RTMPusecDelay(50); ++ GloCfg.field.EnTXWriteBackDDONE = 1; ++ GloCfg.field.EnableRxDMA = 1; ++ GloCfg.field.EnableTxDMA = 1; ++ DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ UsbCfg.word = 0; ++ UsbCfg.field.phyclear = 0; ++ /* usb version is 1.1,do not use bulk in aggregation */ ++ if (pAd->BulkInMaxPacketSize == 512) ++ UsbCfg.field.RxBulkAggEn = 1; ++ /* for last packet, PBF might use more than limited, so minus 2 to prevent from error */ ++ UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3; ++ UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */ ++ UsbCfg.field.RxBulkEn = 1; ++ UsbCfg.field.TxBulkEn = 1; ++ ++ RTUSBWriteMACRegister(pAd, USB_DMA_CFG, UsbCfg.word); ++ ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Write Beacon buffer to Asic. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28xx_UpdateBeaconToAsic( ++ IN RTMP_ADAPTER *pAd, ++ IN INT apidx, ++ IN ULONG FrameLen, ++ IN ULONG UpdatePos) ++{ ++ PUCHAR pBeaconFrame = NULL; ++ UCHAR *ptr; ++ UINT i, padding; ++ BEACON_SYNC_STRUCT *pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ UINT32 longValue; ++ BOOLEAN bBcnReq = FALSE; ++ UCHAR bcn_idx = 0; ++ ++ ++ if (pBeaconFrame == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("pBeaconFrame is NULL!\n")); ++ return; ++ } ++ ++ if (pBeaconSync == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("pBeaconSync is NULL!\n")); ++ return; ++ } ++ ++ //if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE) || ++ // ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL) || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP)) ++ // ) ++ if (bBcnReq == FALSE) ++ { ++ /* when the ra interface is down, do not send its beacon frame */ ++ /* clear all zero */ ++ for(i=0; iBeaconOffset[bcn_idx] + i, 0x00); ++ } ++ pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[bcn_idx], TXWI_SIZE); ++ } ++ else ++ { ++ ptr = (PUCHAR)&pAd->BeaconTxWI; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(ptr, TYPE_TXWI); ++#endif ++ if (NdisEqualMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE) == FALSE) ++ { // If BeaconTxWI changed, we need to rewrite the TxWI for the Beacon frames. ++ pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); ++ NdisMoveMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE); ++ } ++ ++ if ((pBeaconSync->BeaconBitMap & (1 << bcn_idx)) != (1 << bcn_idx)) ++ { ++ for (i=0; iBeaconOffset[bcn_idx] + i, longValue); ++ ptr += 4; ++ } ++ } ++ ++ ptr = pBeaconSync->BeaconBuf[bcn_idx]; ++ padding = (FrameLen & 0x01); ++ NdisZeroMemory((PUCHAR)(pBeaconFrame + FrameLen), padding); ++ FrameLen += padding; ++ for (i = 0 ; i < FrameLen /*HW_BEACON_OFFSET*/; i += 2) ++ { ++ if (NdisEqualMemory(ptr, pBeaconFrame, 2) == FALSE) ++ { ++ NdisMoveMemory(ptr, pBeaconFrame, 2); ++ //shortValue = *ptr + (*(ptr+1)<<8); ++ //RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, shortValue); ++ RTUSBMultiWrite(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, ptr, 2); ++ } ++ ptr +=2; ++ pBeaconFrame += 2; ++ } ++ ++ pBeaconSync->BeaconBitMap |= (1 << bcn_idx); ++ } ++ ++} ++ ++ ++VOID RT2870_BssBeaconStop( ++ IN RTMP_ADAPTER *pAd) ++{ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ int i, offset; ++ BOOLEAN Cancelled = TRUE; ++ ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ if (pBeaconSync && pBeaconSync->EnableBeacon) ++ { ++ INT NumOfBcn; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NumOfBcn = MAX_MESH_NUM; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); ++ ++ for(i=0; iBeaconBuf[i], HW_BEACON_OFFSET); ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); ++ ++ for (offset=0; offsetBeaconOffset[i] + offset, 0x00); ++ ++ pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; ++ pBeaconSync->TimIELocationInBeacon[i] = 0; ++ } ++ pBeaconSync->BeaconBitMap = 0; ++ pBeaconSync->DtimBitOn = 0; ++ } ++} ++ ++ ++VOID RT2870_BssBeaconStart( ++ IN RTMP_ADAPTER *pAd) ++{ ++ int apidx; ++ BEACON_SYNC_STRUCT *pBeaconSync; ++// LARGE_INTEGER tsfTime, deltaTime; ++ ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ if (pBeaconSync && pBeaconSync->EnableBeacon) ++ { ++ INT NumOfBcn; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NumOfBcn = MAX_MESH_NUM; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ for(apidx=0; apidxBeaconBuf[apidx], HW_BEACON_OFFSET); ++ pBeaconSync->CapabilityInfoLocationInBeacon[apidx] = CapabilityInfoLocationInBeacon; ++ pBeaconSync->TimIELocationInBeacon[apidx] = TimIELocationInBeacon; ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[apidx], TXWI_SIZE); ++ } ++ pBeaconSync->BeaconBitMap = 0; ++ pBeaconSync->DtimBitOn = 0; ++ pAd->CommonCfg.BeaconUpdateTimer.Repeat = TRUE; ++ ++ pAd->CommonCfg.BeaconAdjust = 0; ++ pAd->CommonCfg.BeaconFactor = 0xffffffff / (pAd->CommonCfg.BeaconPeriod << 10); ++ pAd->CommonCfg.BeaconRemain = (0xffffffff % (pAd->CommonCfg.BeaconPeriod << 10)) + 1; ++ printk("RT2870_BssBeaconStart:BeaconFactor=%d, BeaconRemain=%d!\n", pAd->CommonCfg.BeaconFactor, pAd->CommonCfg.BeaconRemain); ++ RTMPSetTimer(&pAd->CommonCfg.BeaconUpdateTimer, pAd->CommonCfg.BeaconPeriod); ++ ++ } ++} ++ ++ ++VOID RT2870_BssBeaconInit( ++ IN RTMP_ADAPTER *pAd) ++{ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ int i; ++ ++ NdisAllocMemory(pAd->CommonCfg.pBeaconSync, sizeof(BEACON_SYNC_STRUCT), MEM_ALLOC_FLAG); ++ if (pAd->CommonCfg.pBeaconSync) ++ { ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ NdisZeroMemory(pBeaconSync, sizeof(BEACON_SYNC_STRUCT)); ++ for(i=0; i < HW_BEACON_MAX_COUNT; i++) ++ { ++ NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET); ++ pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; ++ pBeaconSync->TimIELocationInBeacon[i] = 0; ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); ++ } ++ pBeaconSync->BeaconBitMap = 0; ++ ++ //RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE); ++ pBeaconSync->EnableBeacon = TRUE; ++ } ++} ++ ++ ++VOID RT2870_BssBeaconExit( ++ IN RTMP_ADAPTER *pAd) ++{ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ BOOLEAN Cancelled = TRUE; ++ int i; ++ ++ if (pAd->CommonCfg.pBeaconSync) ++ { ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ pBeaconSync->EnableBeacon = FALSE; ++ RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); ++ pBeaconSync->BeaconBitMap = 0; ++ ++ for(i=0; iBeaconBuf[i], HW_BEACON_OFFSET); ++ pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; ++ pBeaconSync->TimIELocationInBeacon[i] = 0; ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); ++ } ++ ++ NdisFreeMemory(pAd->CommonCfg.pBeaconSync, HW_BEACON_OFFSET * HW_BEACON_MAX_COUNT, 0); ++ pAd->CommonCfg.pBeaconSync = NULL; ++ } ++} ++ ++VOID BeaconUpdateExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; ++ LARGE_INTEGER tsfTime_a;//, tsfTime_b, deltaTime_exp, deltaTime_ab; ++ UINT32 delta, remain, remain_low, remain_high; ++// BOOLEAN positive; ++ ++ ReSyncBeaconTime(pAd); ++ ++ ++ ++ RTMP_IO_READ32(pAd, TSF_TIMER_DW0, &tsfTime_a.u.LowPart); ++ RTMP_IO_READ32(pAd, TSF_TIMER_DW1, &tsfTime_a.u.HighPart); ++ ++ ++ //positive=getDeltaTime(tsfTime_a, expectedTime, &deltaTime_exp); ++ remain_high = pAd->CommonCfg.BeaconRemain * tsfTime_a.u.HighPart; ++ remain_low = tsfTime_a.u.LowPart % (pAd->CommonCfg.BeaconPeriod << 10); ++ remain = (remain_high + remain_low)%(pAd->CommonCfg.BeaconPeriod << 10); ++ delta = (pAd->CommonCfg.BeaconPeriod << 10) - remain; ++ ++ pAd->CommonCfg.BeaconUpdateTimer.TimerValue = (delta >> 10) + 10; ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/aironet.h +@@ -0,0 +1,210 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 04-06-15 Initial ++*/ ++ ++#ifndef __AIRONET_H__ ++#define __AIRONET_H__ ++ ++// Measurement Type definition ++#define MSRN_TYPE_UNUSED 0 ++#define MSRN_TYPE_CHANNEL_LOAD_REQ 1 ++#define MSRN_TYPE_NOISE_HIST_REQ 2 ++#define MSRN_TYPE_BEACON_REQ 3 ++#define MSRN_TYPE_FRAME_REQ 4 ++ ++// Scan Mode in Beacon Request ++#define MSRN_SCAN_MODE_PASSIVE 0 ++#define MSRN_SCAN_MODE_ACTIVE 1 ++#define MSRN_SCAN_MODE_BEACON_TABLE 2 ++ ++// PHY type definition for Aironet beacon report, CCX 2 table 36-9 ++#define PHY_FH 1 ++#define PHY_DSS 2 ++#define PHY_UNUSED 3 ++#define PHY_OFDM 4 ++#define PHY_HR_DSS 5 ++#define PHY_ERP 6 ++ ++// RPI table in dBm ++#define RPI_0 0 // Power <= -87 ++#define RPI_1 1 // -87 < Power <= -82 ++#define RPI_2 2 // -82 < Power <= -77 ++#define RPI_3 3 // -77 < Power <= -72 ++#define RPI_4 4 // -72 < Power <= -67 ++#define RPI_5 5 // -67 < Power <= -62 ++#define RPI_6 6 // -62 < Power <= -57 ++#define RPI_7 7 // -57 < Power ++ ++// Cisco Aironet IAPP definetions ++#define AIRONET_IAPP_TYPE 0x32 ++#define AIRONET_IAPP_SUBTYPE_REQUEST 0x01 ++#define AIRONET_IAPP_SUBTYPE_REPORT 0x81 ++ ++// Measurement Request detail format ++typedef struct _MEASUREMENT_REQUEST { ++ UCHAR Channel; ++ UCHAR ScanMode; // Use only in beacon request, other requests did not use this field ++ USHORT Duration; ++} MEASUREMENT_REQUEST, *PMEASUREMENT_REQUEST; ++ ++// Beacon Measurement Report ++// All these field might change to UCHAR, because we didn't do anything to these report. ++// We copy all these beacons and report to CCX 2 AP. ++typedef struct _BEACON_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR PhyType; // Definiation is listed above table 36-9 ++ UCHAR RxPower; ++ UCHAR BSSID[6]; ++ UCHAR ParentTSF[4]; ++ UCHAR TargetTSF[8]; ++ USHORT BeaconInterval; ++ USHORT CapabilityInfo; ++} BEACON_REPORT, *PBEACON_REPORT; ++ ++// Frame Measurement Report (Optional) ++typedef struct _FRAME_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR TA; ++ UCHAR BSSID[6]; ++ UCHAR RSSI; ++ UCHAR Count; ++} FRAME_REPORT, *PFRAME_REPORT; ++ ++#pragma pack(1) ++// Channel Load Report ++typedef struct _CHANNEL_LOAD_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR CCABusy; ++} CHANNEL_LOAD_REPORT, *PCHANNEL_LOAD_REPORT; ++#pragma pack() ++ ++// Nosie Histogram Report ++typedef struct _NOISE_HIST_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR Density[8]; ++} NOISE_HIST_REPORT, *PNOISE_HIST_REPORT; ++ ++// Radio Management Capability element ++typedef struct _RADIO_MANAGEMENT_CAPABILITY { ++ UCHAR Eid; // TODO: Why the Eid is 1 byte, not normal 2 bytes??? ++ UCHAR Length; ++ UCHAR AironetOui[3]; // AIronet OUI (00 40 96) ++ UCHAR Type; // Type / Version ++ USHORT Status; // swap16 required ++} RADIO_MANAGEMENT_CAPABILITY, *PRADIO_MANAGEMENT_CAPABILITY; ++ ++// Measurement Mode Bit definition ++typedef struct _MEASUREMENT_MODE { ++ UCHAR Rsvd:4; ++ UCHAR Report:1; ++ UCHAR NotUsed:1; ++ UCHAR Enable:1; ++ UCHAR Parallel:1; ++} MEASUREMENT_MODE, *PMEASUREMENT_MODE; ++ ++// Measurement Request element, This is little endian mode ++typedef struct _MEASUREMENT_REQUEST_ELEMENT { ++ USHORT Eid; ++ USHORT Length; // swap16 required ++ USHORT Token; // non-zero unique token ++ UCHAR Mode; // Measurement Mode ++ UCHAR Type; // Measurement type ++} MEASUREMENT_REQUEST_ELEMENT, *PMEASUREMENT_REQUEST_ELEMENT; ++ ++// Measurement Report element, This is little endian mode ++typedef struct _MEASUREMENT_REPORT_ELEMENT { ++ USHORT Eid; ++ USHORT Length; // swap16 required ++ USHORT Token; // non-zero unique token ++ UCHAR Mode; // Measurement Mode ++ UCHAR Type; // Measurement type ++} MEASUREMENT_REPORT_ELEMENT, *PMEASUREMENT_REPORT_ELEMENT; ++ ++// Cisco Aironet IAPP Frame Header, Network byte order used ++typedef struct _AIRONET_IAPP_HEADER { ++ UCHAR CiscoSnapHeader[8]; // 8 bytes Cisco snap header ++ USHORT Length; // IAPP ID & length, remember to swap16 in LE system ++ UCHAR Type; // IAPP type ++ UCHAR SubType; // IAPP subtype ++ UCHAR DA[6]; // Destination MAC address ++ UCHAR SA[6]; // Source MAC address ++ USHORT Token; // Dialog token, no need to swap16 since it is for yoken usage only ++} AIRONET_IAPP_HEADER, *PAIRONET_IAPP_HEADER; ++ ++// Radio Measurement Request frame ++typedef struct _AIRONET_RM_REQUEST_FRAME { ++ AIRONET_IAPP_HEADER IAPP; // Common header ++ UCHAR Delay; // Activation Delay ++ UCHAR Offset; // Measurement offset ++} AIRONET_RM_REQUEST_FRAME, *PAIRONET_RM_REQUEST_FRAME; ++ ++// Radio Measurement Report frame ++typedef struct _AIRONET_RM_REPORT_FRAME { ++ AIRONET_IAPP_HEADER IAPP; // Common header ++} AIRONET_RM_REPORT_FRAME, *PAIRONET_RM_REPORT_FRAME; ++ ++// Saved element request actions which will saved in StaCfg. ++typedef struct _RM_REQUEST_ACTION { ++ MEASUREMENT_REQUEST_ELEMENT ReqElem; // Saved request element ++ MEASUREMENT_REQUEST Measurement; // Saved measurement within the request element ++} RM_REQUEST_ACTION, *PRM_REQUEST_ACTION; ++ ++// CCX administration control ++typedef union _CCX_CONTROL { ++ struct { ++ UINT32 Enable:1; // Enable CCX2 ++ UINT32 LeapEnable:1; // Enable LEAP at CCX2 ++ UINT32 RMEnable:1; // Radio Measurement Enable ++ UINT32 DCRMEnable:1; // Non serving channel Radio Measurement enable ++ UINT32 QOSEnable:1; // Enable QOS for CCX 2.0 support ++ UINT32 FastRoamEnable:1; // Enable fast roaming ++ UINT32 Rsvd:2; // Not used ++ UINT32 dBmToRoam:8; // the condition to roam when receiving Rssi less than this value. It's negative value. ++ UINT32 TuLimit:16; // Limit for different channel scan ++ } field; ++ UINT32 word; ++} CCX_CONTROL, *PCCX_CONTROL; ++ ++#endif // __AIRONET_H__ +--- /dev/null ++++ b/drivers/staging/rt2870/ap.h +@@ -0,0 +1,562 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ ap.h ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ James Tan 09-06-2002 modified (Revise NTCRegTable) ++ John Chang 12-22-2004 modified for RT2561/2661. merge with STA driver ++*/ ++#ifndef __AP_H__ ++#define __AP_H__ ++ ++ ++ ++// ========================= AP RTMP.h ================================ ++ ++ ++ ++// ============================================================= ++// Function Prototypes ++// ============================================================= ++ ++// ap_data.c ++ ++BOOLEAN APBridgeToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN ULONG fromwdsidx); ++ ++BOOLEAN APHandleRxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APSendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets); ++ ++NDIS_STATUS APSendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++NDIS_STATUS APHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++VOID APRxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++NDIS_STATUS APCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN UCHAR Wcid); ++ ++BOOLEAN APCheckClass2Class3Error( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++VOID APHandleRxPsPoll( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN USHORT Aid, ++ IN BOOLEAN isActive); ++ ++VOID RTMPDescriptorEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType); ++ ++VOID RTMPFrameEndianChange( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG Dir, ++ IN BOOLEAN FromRxDoneInt); ++ ++// ap_assoc.c ++ ++VOID APAssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APPeerAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MbssKickOutStas( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN USHORT Reason); ++ ++VOID APMlmeKickOutSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pStaAddr, ++ IN UCHAR Wcid, ++ IN USHORT Reason); ++ ++VOID APMlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APCls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++ ++USHORT APBuildAssociation( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN USHORT CapabilityInfo, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN UCHAR *RSN, ++ IN UCHAR *pRSNLen, ++ IN BOOLEAN bWmmCapable, ++ IN ULONG RalinkIe, ++#ifdef DOT11N_DRAFT3 ++ IN EXT_CAP_INFO_ELEMENT ExtCapInfo, ++#endif // DOT11N_DRAFT3 // ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ OUT USHORT *pAid); ++ ++/* ++VOID RTMPAddClientSec( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic, ++ IN MAC_TABLE_ENTRY *pEntry); ++*/ ++ ++// ap_auth.c ++ ++void APAuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APMlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APCls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++// ap_authrsp.c ++ ++VOID APAuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]); ++ ++VOID APPeerAuthAtAuthRspIdleAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT StatusCode); ++ ++// ap_connect.c ++ ++BOOLEAN BeaconTransmitRequired( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APMakeBssBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APUpdateBeaconFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APMakeAllBssBeacon( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APUpdateAllBeaconFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++// ap_sync.c ++ ++VOID APSyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID APInvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerBeaconAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APMlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APScanCnclAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ApSiteSurvey( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID SupportRate( ++ IN PUCHAR SupRate, ++ IN UCHAR SupRateLen, ++ IN PUCHAR ExtRate, ++ IN UCHAR ExtRateLen, ++ OUT PUCHAR *Rates, ++ OUT PUCHAR RatesLen, ++ OUT PUCHAR pMaxSupportRate); ++ ++ ++BOOLEAN ApScanRunning( ++ IN PRTMP_ADAPTER pAd); ++ ++#ifdef DOT11N_DRAFT3 ++VOID APOverlappingBSSScan( ++ IN RTMP_ADAPTER *pAd); ++#endif // DOT11N_DRAFT3 // ++ ++// ap_wpa.c ++ ++VOID APWpaStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++// ap_mlme.c ++ ++VOID APMlmePeriodicExec( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APMlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx); ++ ++VOID APMlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate); ++ ++VOID APMlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN APMsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType); ++ ++VOID APQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++#ifdef RT2870 ++VOID BeaconUpdateExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // RT2870 // ++ ++VOID RTMPSetPiggyBack( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bPiggyBack); ++ ++VOID APAsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APAsicRxAntEvalTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++// ap.c ++ ++VOID APSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Channel); ++ ++NDIS_STATUS APInitialize( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APShutdown( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APStartUp( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APCleanupPsQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_HEADER pQueue); ++ ++VOID MacTableReset( ++ IN PRTMP_ADAPTER pAd); ++ ++MAC_TABLE_ENTRY *MacTableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR apidx, ++ IN BOOLEAN CleanAll); ++ ++BOOLEAN MacTableDeleteEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr); ++ ++MAC_TABLE_ENTRY *MacTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID MacTableMaintenance( ++ IN PRTMP_ADAPTER pAd); ++ ++UINT32 MacTableAssocStaNumGet( ++ IN PRTMP_ADAPTER pAd); ++ ++MAC_TABLE_ENTRY *APSsPsInquiry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ OUT SST *Sst, ++ OUT USHORT *Aid, ++ OUT UCHAR *PsMode, ++ OUT UCHAR *Rate); ++ ++BOOLEAN APPsIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN ULONG Wcid, ++ IN UCHAR Psm); ++ ++VOID ApLogEvent( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN USHORT Event); ++ ++#ifdef DOT11_N_SUPPORT ++VOID APUpdateOperationMode( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++ ++VOID APUpdateCapabilityAndErpIe( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN ApCheckAccessControlList( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR Apidx); ++ ++VOID ApUpdateAccessControlList( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Apidx); ++ ++VOID ApEnqueueNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR TxRate, ++ IN UCHAR PID, ++ IN UCHAR apidx, ++ IN BOOLEAN bQosNull, ++ IN BOOLEAN bEOSP, ++ IN UCHAR OldUP); ++ ++VOID ApSendFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuffer, ++ IN ULONG Length, ++ IN UCHAR TxRate, ++ IN UCHAR PID); ++ ++VOID ApEnqueueAckFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR TxRate, ++ IN UCHAR apidx); ++ ++UCHAR APAutoSelectChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN Optimal); ++ ++// ap_sanity.c ++ ++ ++BOOLEAN PeerAssocReqCmmSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN isRessoc, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pListenInterval, ++ OUT PUCHAR pApAddr, ++ OUT UCHAR *pSsidLen, ++ OUT char *Ssid, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *RSN, ++ OUT UCHAR *pRSNLen, ++ OUT BOOLEAN *pbWmmCapable, ++#ifdef WSC_AP_SUPPORT ++ OUT BOOLEAN *pWscCapable, ++#endif // WSC_AP_SUPPORT // ++ OUT ULONG *pRalinkIe, ++#ifdef DOT11N_DRAFT3 ++ OUT EXT_CAP_INFO_ELEMENT *pExtCapInfo, ++#endif // DOT11N_DRAFT3 // ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDisassocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerDeauthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN APPeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr1, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Alg, ++ OUT USHORT *Seq, ++ OUT USHORT *Status, ++ CHAR *ChlgText); ++ ++BOOLEAN APPeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *SsidLen); ++ ++BOOLEAN APPeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *SsidLen, ++ OUT UCHAR *BssType, ++ OUT USHORT *BeaconPeriod, ++ OUT UCHAR *Channel, ++ OUT LARGE_INTEGER *Timestamp, ++ OUT USHORT *CapabilityInfo, ++ OUT UCHAR Rate[], ++ OUT UCHAR *RateLen, ++ OUT BOOLEAN *ExtendedRateIeExist, ++ OUT UCHAR *Erp); ++ ++// ap_info.c ++ ++ ++ ++// ================== end of AP RTMP.h ======================== ++ ++ ++#endif // __AP_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/chlist.h +@@ -0,0 +1,1296 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ chlist.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi Wu 2007-12-19 created ++*/ ++ ++#ifndef __CHLIST_H__ ++#define __CHLIST_H__ ++ ++#include "rtmp_type.h" ++#include "rtmp_def.h" ++ ++ ++#define ODOR 0 ++#define IDOR 1 ++#define BOTH 2 ++ ++#define BAND_5G 0 ++#define BAND_24G 1 ++#define BAND_BOTH 2 ++ ++typedef struct _CH_DESP { ++ UCHAR FirstChannel; ++ UCHAR NumOfCh; ++ CHAR MaxTxPwr; // dBm ++ UCHAR Geography; // 0:out door, 1:in door, 2:both ++ BOOLEAN DfsReq; // Dfs require, 0: No, 1: yes. ++} CH_DESP, *PCH_DESP; ++ ++typedef struct _CH_REGION { ++ UCHAR CountReg[3]; ++ UCHAR DfsType; // 0: CE, 1: FCC, 2: JAP, 3:JAP_W53, JAP_W56 ++ CH_DESP ChDesp[10]; ++} CH_REGION, *PCH_REGION; ++ ++static CH_REGION ChRegion[] = ++{ ++ { // Antigua and Berbuda ++ "AG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Argentina ++ "AR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Aruba ++ "AW", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Australia ++ "AU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Austria ++ "AT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bahamas ++ "BS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Barbados ++ "BB", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bermuda ++ "BM", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Brazil ++ "BR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 24, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Belgium ++ "BE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 18, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 18, IDOR, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bulgaria ++ "BG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Canada ++ "CA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Cayman IsLands ++ "KY", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Chile ++ "CL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // China ++ "CN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Colombia ++ "CO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Costa Rica ++ "CR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Cyprus ++ "CY", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Czech_Republic ++ "CZ", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Denmark ++ "DK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Dominican Republic ++ "DO", ++ CE, ++ { ++ { 1, 0, 20, BOTH, FALSE}, // 2.4 G, ch 0 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Equador ++ "EC", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 100, 11, 27, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // El Salvador ++ "SV", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 30, BOTH, TRUE}, // 5G, ch 52~64 ++ { 149, 4, 36, BOTH, TRUE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Finland ++ "FI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // France ++ "FR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Germany ++ "DE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Greece ++ "GR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Guam ++ "GU", ++ CE, ++ { ++ { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Guatemala ++ "GT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Haiti ++ "HT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Honduras ++ "HN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Hong Kong ++ "HK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Hungary ++ "HU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Iceland ++ "IS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // India ++ "IN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 24, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Indonesia ++ "ID", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Ireland ++ "IE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Israel ++ "IL", ++ CE, ++ { ++ { 1, 3, 20, IDOR, FALSE}, // 2.4 G, ch 1~3 ++ { 4, 6, 20, BOTH, FALSE}, // 2.4 G, ch 4~9 ++ { 10, 4, 20, IDOR, FALSE}, // 2.4 G, ch 10~13 ++ { 0}, // end ++ } ++ }, ++ ++ { // Italy ++ "IT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Japan ++ "JP", ++ JAP, ++ { ++ { 1, 14, 20, BOTH, FALSE}, // 2.4 G, ch 1~14 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 0}, // end ++ } ++ }, ++ ++ { // Jordan ++ "JO", ++ CE, ++ { ++ { 1, 13, 20, IDOR, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 149, 4, 23, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Latvia ++ "LV", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Liechtenstein ++ "LI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Lithuania ++ "LT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Luxemburg ++ "LU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Malaysia ++ "MY", ++ CE, ++ { ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Malta ++ "MT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Marocco ++ "MA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 ++ { 0}, // end ++ } ++ }, ++ ++ { // Mexico ++ "MX", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, IDOR, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Netherlands ++ "NL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // New Zealand ++ "NZ", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Norway ++ "NO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Peru ++ "PE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Portugal ++ "PT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Poland ++ "PL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Romania ++ "RO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Russia ++ "RU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 20, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Saudi Arabia ++ "SA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 23, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Serbia_and_Montenegro ++ "CS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 0}, // end ++ } ++ }, ++ ++ { // Singapore ++ "SG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Slovakia ++ "SK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Slovenia ++ "SI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // South Africa ++ "ZA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // South Korea ++ "KR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 8, 20, BOTH, FALSE}, // 5G, ch 100~128 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Spain ++ "ES", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Sweden ++ "SE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Switzerland ++ "CH", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Taiwan ++ "TW", ++ CE, ++ { ++ { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Turkey ++ "TR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // UK ++ "GB", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Ukraine ++ "UA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 0}, // end ++ } ++ }, ++ ++ { // United_Arab_Emirates ++ "AE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 0}, // end ++ } ++ }, ++ ++ { // United_States ++ "US", ++ CE, ++ { ++ { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 17, IDOR, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 24, BOTH, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Venezuela ++ "VE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Default ++ "", ++ CE, ++ { ++ { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 20, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++}; ++ ++static inline PCH_REGION GetChRegion( ++ IN PUCHAR CntryCode) ++{ ++ INT loop = 0; ++ PCH_REGION pChRegion = NULL; ++ ++ while (strcmp(ChRegion[loop].CountReg, "") != 0) ++ { ++ if (strncmp(ChRegion[loop].CountReg, CntryCode, 2) == 0) ++ { ++ pChRegion = &ChRegion[loop]; ++ break; ++ } ++ loop++; ++ } ++ ++ if (pChRegion == NULL) ++ pChRegion = &ChRegion[loop]; ++ return pChRegion; ++} ++ ++static inline VOID ChBandCheck( ++ IN UCHAR PhyMode, ++ OUT PUCHAR pChType) ++{ ++ switch(PhyMode) ++ { ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ *pChType = BAND_5G; ++ break; ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AGN_MIXED: ++ case PHY_11ABGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ *pChType = BAND_BOTH; ++ break; ++ ++ default: ++ *pChType = BAND_24G; ++ break; ++ } ++} ++ ++static inline UCHAR FillChList( ++ IN PRTMP_ADAPTER pAd, ++ IN PCH_DESP pChDesp, ++ IN UCHAR Offset, ++ IN UCHAR increment) ++{ ++ INT i, j, l; ++ UCHAR channel; ++ ++ j = Offset; ++ for (i = 0; i < pChDesp->NumOfCh; i++) ++ { ++ channel = pChDesp->FirstChannel + i * increment; ++ for (l=0; lTxPower[l].Channel) ++ { ++ pAd->ChannelList[j].Power = pAd->TxPower[l].Power; ++ pAd->ChannelList[j].Power2 = pAd->TxPower[l].Power2; ++ break; ++ } ++ } ++ if (l == MAX_NUM_OF_CHANNELS) ++ continue; ++ ++ pAd->ChannelList[j].Channel = pChDesp->FirstChannel + i * increment; ++ pAd->ChannelList[j].MaxTxPwr = pChDesp->MaxTxPwr; ++ pAd->ChannelList[j].DfsReq = pChDesp->DfsReq; ++ j++; ++ } ++ pAd->ChannelListNum = j; ++ ++ return j; ++} ++ ++static inline VOID CreateChList( ++ IN PRTMP_ADAPTER pAd, ++ IN PCH_REGION pChRegion, ++ IN UCHAR Geography) ++{ ++ INT i; ++ UCHAR offset = 0; ++ PCH_DESP pChDesp; ++ UCHAR ChType; ++ UCHAR increment; ++ ++ if (pChRegion == NULL) ++ return; ++ ++ ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); ++ ++ for (i=0; i<10; i++) ++ { ++ pChDesp = &pChRegion->ChDesp[i]; ++ if (pChDesp->FirstChannel == 0) ++ break; ++ ++ if (ChType == BAND_5G) ++ { ++ if (pChDesp->FirstChannel <= 14) ++ continue; ++ } ++ else if (ChType == BAND_24G) ++ { ++ if (pChDesp->FirstChannel > 14) ++ continue; ++ } ++ ++ if ((pChDesp->Geography == BOTH) ++ || (pChDesp->Geography == Geography)) ++ { ++ if (pChDesp->FirstChannel > 14) ++ increment = 4; ++ else ++ increment = 1; ++ offset = FillChList(pAd, pChDesp, offset, increment); ++ } ++ } ++} ++ ++static inline VOID BuildChannelListEx( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PCH_REGION pChReg; ++ ++ pChReg = GetChRegion(pAd->CommonCfg.CountryCode); ++ CreateChList(pAd, pChReg, pAd->CommonCfg.Geography); ++} ++ ++static inline VOID BuildBeaconChList( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf, ++ OUT PULONG pBufLen) ++{ ++ INT i; ++ ULONG TmpLen; ++ PCH_REGION pChRegion; ++ PCH_DESP pChDesp; ++ UCHAR ChType; ++ ++ pChRegion = GetChRegion(pAd->CommonCfg.CountryCode); ++ ++ if (pChRegion == NULL) ++ return; ++ ++ ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); ++ *pBufLen = 0; ++ ++ for (i=0; i<10; i++) ++ { ++ pChDesp = &pChRegion->ChDesp[i]; ++ if (pChDesp->FirstChannel == 0) ++ break; ++ ++ if (ChType == BAND_5G) ++ { ++ if (pChDesp->FirstChannel <= 14) ++ continue; ++ } ++ else if (ChType == BAND_24G) ++ { ++ if (pChDesp->FirstChannel > 14) ++ continue; ++ } ++ ++ if ((pChDesp->Geography == BOTH) ++ || (pChDesp->Geography == pAd->CommonCfg.Geography)) ++ { ++ MakeOutgoingFrame(pBuf + *pBufLen, &TmpLen, ++ 1, &pChDesp->FirstChannel, ++ 1, &pChDesp->NumOfCh, ++ 1, &pChDesp->MaxTxPwr, ++ END_OF_ARGS); ++ *pBufLen += TmpLen; ++ } ++ } ++} ++ ++ ++#ifdef DOT11_N_SUPPORT ++static inline BOOLEAN IsValidChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++ ++{ ++ INT i; ++ ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].Channel == channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++ ++static inline UCHAR GetExtCh( ++ IN UCHAR Channel, ++ IN UCHAR Direction) ++{ ++ CHAR ExtCh; ++ ++ if (Direction == EXTCHA_ABOVE) ++ ExtCh = Channel + 4; ++ else ++ ExtCh = (Channel - 4) > 0 ? (Channel - 4) : 0; ++ ++ return ExtCh; ++} ++ ++ ++static inline VOID N_ChannelCheck( ++ IN PRTMP_ADAPTER pAd) ++{ ++ //UCHAR ChannelNum = pAd->ChannelListNum; ++ UCHAR Channel = pAd->CommonCfg.Channel; ++ ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (Channel > 14) ++ { ++ if ((Channel == 36) || (Channel == 44) || (Channel == 52) || (Channel == 60) || (Channel == 100) || (Channel == 108) || ++ (Channel == 116) || (Channel == 124) || (Channel == 132) || (Channel == 149) || (Channel == 157)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ else if ((Channel == 40) || (Channel == 48) || (Channel == 56) || (Channel == 64) || (Channel == 104) || (Channel == 112) || ++ (Channel == 120) || (Channel == 128) || (Channel == 136) || (Channel == 153) || (Channel == 161)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } ++ } ++ else ++ { ++ do ++ { ++ UCHAR ExtCh; ++ UCHAR Dir = pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; ++ ExtCh = GetExtCh(Channel, Dir); ++ if (IsValidChannel(pAd, ExtCh)) ++ break; ++ ++ Dir = (Dir == EXTCHA_ABOVE) ? EXTCHA_BELOW : EXTCHA_ABOVE; ++ ExtCh = GetExtCh(Channel, Dir); ++ if (IsValidChannel(pAd, ExtCh)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = Dir; ++ break; ++ } ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } while(FALSE); ++ ++ if (Channel == 14) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ //pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_NONE; // We didn't set the ExtCh as NONE due to it'll set in RTMPSetHT() ++ } ++#if 0 ++ switch (pAd->CommonCfg.CountryRegion & 0x7f) ++ { ++ case REGION_0_BG_BAND: // 1 -11 ++ case REGION_1_BG_BAND: // 1 - 13 ++ case REGION_5_BG_BAND: // 1 - 14 ++ if (Channel <= 4) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ else if (Channel >= 8) ++ { ++ if ((ChannelNum - Channel) < 4) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ break; ++ ++ case REGION_2_BG_BAND: // 10 - 11 ++ case REGION_3_BG_BAND: // 10 - 13 ++ case REGION_4_BG_BAND: // 14 ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ break; ++ ++ case REGION_6_BG_BAND: // 3 - 9 ++ if (Channel <= 5) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else if (Channel == 6) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ else if (Channel >= 7) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ break; ++ ++ case REGION_7_BG_BAND: // 5 - 13 ++ if (Channel <= 8) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else if (Channel >= 10) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ break; ++ ++ default: // Error. should never happen ++ break; ++ } ++#endif ++ } ++ } ++ ++ ++} ++ ++ ++static inline VOID N_SetCenCh( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ if (pAd->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel == 14) ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 1; ++ else ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++ ++static inline UINT8 GetCuntryMaxTxPwr( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 channel) ++{ ++ int i; ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].Channel == channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return 0xff; ++ else ++ return pAd->ChannelList[i].MaxTxPwr; ++} ++#endif // __CHLIST_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/2870_rtmp_init.c +@@ -0,0 +1,1778 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ 2870_rtmp_init.c ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme ++ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. ++ Sample Lin 2007-05-31 Merge RT2860 and RT2870 drivers. ++*/ ++ ++#include "../rt_config.h" ++ ++ ++static void rx_done_tasklet(unsigned long data); ++static void rt2870_hcca_dma_done_tasklet(unsigned long data); ++static void rt2870_ac3_dma_done_tasklet(unsigned long data); ++static void rt2870_ac2_dma_done_tasklet(unsigned long data); ++static void rt2870_ac1_dma_done_tasklet(unsigned long data); ++static void rt2870_ac0_dma_done_tasklet(unsigned long data); ++static void rt2870_mgmt_dma_done_tasklet(unsigned long data); ++static void rt2870_null_frame_complete_tasklet(unsigned long data); ++static void rt2870_rts_frame_complete_tasklet(unsigned long data); ++static void rt2870_pspoll_frame_complete_tasklet(unsigned long data); ++static void rt2870_dataout_complete_tasklet(unsigned long data); ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Initialize receive data structures. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_RESOURCES ++ ++Note: ++ Initialize all receive releated private buffer, include those define ++ in RTMP_ADAPTER structure and all private data structures. The mahor ++ work is to allocate buffer for each packet and chain buffer to ++ NDIS packet descriptor. ++======================================================================== ++*/ ++NDIS_STATUS NICInitRecv( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitRecv\n")); ++ pObj = pObj; ++ ++ //InterlockedExchange(&pAd->PendingRx, 0); ++ pAd->PendingRx = 0; ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = 0 ; //RX_RING_SIZE -1; // Rx Bulk pointer ++ pAd->NextRxBulkInPosition = 0; ++ ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ //Allocate URB ++ pRxContext->pUrb = RTUSB_ALLOC_URB(0); ++ if (pRxContext->pUrb == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ goto out1; ++ } ++ ++ // Allocate transfer buffer ++ pRxContext->TransferBuffer = RTUSB_URB_ALLOC_BUFFER(pObj->pUsb_Dev, MAX_RXBULK_SIZE, &pRxContext->data_dma); ++ if (pRxContext->TransferBuffer == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ goto out1; ++ } ++ ++ NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); ++ ++ pRxContext->pAd = pAd; ++ pRxContext->pIrp = NULL; ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ //pRxContext->ReorderInUse = FALSE; ++ pRxContext->bRxHandling = FALSE; ++ pRxContext->BulkInOffset = 0; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitRecv\n")); ++ return Status; ++ ++out1: ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ if (NULL != pRxContext->TransferBuffer) ++ { ++ RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, MAX_RXBULK_SIZE, ++ pRxContext->TransferBuffer, pRxContext->data_dma); ++ pRxContext->TransferBuffer = NULL; ++ } ++ ++ if (NULL != pRxContext->pUrb) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ RTUSB_FREE_URB(pRxContext->pUrb); ++ pRxContext->pUrb = NULL; ++ } ++ } ++ ++ return Status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Initialize transmit data structures. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_RESOURCES ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS NICInitTransmit( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define LM_USB_ALLOC(pObj, Context, TB_Type, BufferSize, Status, msg1, err1, msg2, err2) \ ++ Context->pUrb = RTUSB_ALLOC_URB(0); \ ++ if (Context->pUrb == NULL) { \ ++ DBGPRINT(RT_DEBUG_ERROR, msg1); \ ++ Status = NDIS_STATUS_RESOURCES; \ ++ goto err1; } \ ++ \ ++ Context->TransferBuffer = \ ++ (TB_Type)RTUSB_URB_ALLOC_BUFFER(pObj->pUsb_Dev, BufferSize, &Context->data_dma); \ ++ if (Context->TransferBuffer == NULL) { \ ++ DBGPRINT(RT_DEBUG_ERROR, msg2); \ ++ Status = NDIS_STATUS_RESOURCES; \ ++ goto err2; } ++ ++#define LM_URB_FREE(pObj, Context, BufferSize) \ ++ if (NULL != Context->pUrb) { \ ++ RTUSB_UNLINK_URB(Context->pUrb); \ ++ RTUSB_FREE_URB(Context->pUrb); \ ++ Context->pUrb = NULL; } \ ++ if (NULL != Context->TransferBuffer) { \ ++ RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, BufferSize, \ ++ Context->TransferBuffer, \ ++ Context->data_dma); \ ++ Context->TransferBuffer = NULL; } ++ ++ UCHAR i, acidx; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++ PTX_CONTEXT pPsPollContext = &(pAd->PsPollContext); ++ PTX_CONTEXT pRTSContext = &(pAd->RTSContext); ++ PTX_CONTEXT pMLMEContext = NULL; ++// PHT_TX_CONTEXT pHTTXContext = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ PVOID RingBaseVa; ++// RTMP_TX_RING *pTxRing; ++ RTMP_MGMT_RING *pMgmtRing; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitTransmit\n")); ++ pObj = pObj; ++ ++ // Init 4 set of Tx parameters ++ for(acidx = 0; acidx < NUM_OF_TX_RING; acidx++) ++ { ++ // Initialize all Transmit releated queues ++ InitializeQueueHeader(&pAd->TxSwQueue[acidx]); ++ ++ // Next Local tx ring pointer waiting for buck out ++ pAd->NextBulkOutIndex[acidx] = acidx; ++ pAd->BulkOutPending[acidx] = FALSE; // Buck Out control flag ++ //pAd->DataBulkDoneIdx[acidx] = 0; ++ } ++ ++ //pAd->NextMLMEIndex = 0; ++ //pAd->PushMgmtIndex = 0; ++ //pAd->PopMgmtIndex = 0; ++ //InterlockedExchange(&pAd->MgmtQueueSize, 0); ++ //InterlockedExchange(&pAd->TxCount, 0); ++ ++ //pAd->PrioRingFirstIndex = 0; ++ //pAd->PrioRingTxCnt = 0; ++ ++ do ++ { ++ // ++ // TX_RING_SIZE, 4 ACs ++ // ++ for(acidx=0; acidx<4; acidx++) ++ { ++ PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); ++ ++ NdisZeroMemory(pHTTXContext, sizeof(HT_TX_CONTEXT)); ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pHTTXContext, PHTTX_BUFFER, sizeof(HTTX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX TxContext[%d] urb!! \n", acidx), ++ done, ++ ("<-- ERROR in Alloc TX TxContext[%d] HTTX_BUFFER !! \n", acidx), ++ out1); ++ ++ NdisZeroMemory(pHTTXContext->TransferBuffer->Aggregation, 4); ++ pHTTXContext->pAd = pAd; ++ pHTTXContext->pIrp = NULL; ++ pHTTXContext->IRPPending = FALSE; ++ pHTTXContext->NextBulkOutPosition = 0; ++ pHTTXContext->ENextBulkOutPosition = 0; ++ pHTTXContext->CurWritePosition = 0; ++ pHTTXContext->CurWriteRealPos = 0; ++ pHTTXContext->BulkOutSize = 0; ++ pHTTXContext->BulkOutPipeId = acidx; ++ pHTTXContext->bRingEmpty = TRUE; ++ pHTTXContext->bCopySavePad = FALSE; ++ ++ pAd->BulkOutPending[acidx] = FALSE; ++ } ++ ++ ++ // ++ // MGMT_RING_SIZE ++ // ++#if 0 ++ for(i=0; iMLMEContext[i]); ++ ++ ++ NdisZeroMemory(pMLMEContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pMLMEContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX MLMEContext[%d] urb!! \n", i), ++ out2, ++ ("<-- ERROR in Alloc TX MLMEContext[%d] TX_BUFFER !! \n", i), ++ out2); ++ ++ pMLMEContext->pAd = pAd; ++ pMLMEContext->pIrp = NULL; ++ pMLMEContext->InUse = FALSE; ++ pMLMEContext->IRPPending = FALSE; ++ } ++#else ++ // Allocate MGMT ring descriptor's memory ++ pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * sizeof(TX_CONTEXT); ++ RTMPAllocateMemory(&pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); ++ if (pAd->MgmtDescRing.AllocVa == NULL) ++ { ++ DBGPRINT_ERR(("Failed to allocate a big buffer for MgmtDescRing!\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ goto out1; ++ } ++ NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); ++ RingBaseVa = pAd->MgmtDescRing.AllocVa; ++ ++ // Initialize MGMT Ring and associated buffer memory ++ pMgmtRing = &pAd->MgmtRing; ++ for (i = 0; i < MGMT_RING_SIZE; i++) ++ { ++ // link the pre-allocated Mgmt buffer to MgmtRing.Cell ++ pMgmtRing->Cell[i].AllocSize = sizeof(TX_CONTEXT); ++ pMgmtRing->Cell[i].AllocVa = RingBaseVa; ++ pMgmtRing->Cell[i].pNdisPacket = NULL; ++ pMgmtRing->Cell[i].pNextNdisPacket = NULL; ++ ++ //Allocate URB for MLMEContext ++ pMLMEContext = (PTX_CONTEXT) pAd->MgmtRing.Cell[i].AllocVa; ++ pMLMEContext->pUrb = RTUSB_ALLOC_URB(0); ++ if (pMLMEContext->pUrb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("<-- ERROR in Alloc TX MLMEContext[%d] urb!! \n", i)); ++ Status = NDIS_STATUS_RESOURCES; ++ goto out2; ++ } ++ pMLMEContext->pAd = pAd; ++ pMLMEContext->pIrp = NULL; ++ pMLMEContext->TransferBuffer = NULL; ++ pMLMEContext->InUse = FALSE; ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ pMLMEContext->BulkOutSize = 0; ++ pMLMEContext->SelfIdx = i; ++ ++ // Offset to next ring descriptor address ++ RingBaseVa = (PUCHAR) RingBaseVa + sizeof(TX_CONTEXT); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", i)); ++ ++ //pAd->MgmtRing.TxSwFreeIdx = (MGMT_RING_SIZE - 1); ++ pAd->MgmtRing.TxSwFreeIdx = MGMT_RING_SIZE; ++ pAd->MgmtRing.TxCpuIdx = 0; ++ pAd->MgmtRing.TxDmaIdx = 0; ++#endif ++ ++ // ++ // BEACON_RING_SIZE ++ // ++ for(i=0; iBeaconContext[i]); ++ ++ ++ NdisZeroMemory(pBeaconContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pBeaconContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX BeaconContext[%d] urb!! \n", i), ++ out2, ++ ("<-- ERROR in Alloc TX BeaconContext[%d] TX_BUFFER !! \n", i), ++ out3); ++ ++ pBeaconContext->pAd = pAd; ++ pBeaconContext->pIrp = NULL; ++ pBeaconContext->InUse = FALSE; ++ pBeaconContext->IRPPending = FALSE; ++ } ++ ++ // ++ // NullContext ++ // ++ NdisZeroMemory(pNullContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pNullContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX NullContext urb!! \n"), ++ out3, ++ ("<-- ERROR in Alloc TX NullContext TX_BUFFER !! \n"), ++ out4); ++ ++ pNullContext->pAd = pAd; ++ pNullContext->pIrp = NULL; ++ pNullContext->InUse = FALSE; ++ pNullContext->IRPPending = FALSE; ++ ++ // ++ // RTSContext ++ // ++ NdisZeroMemory(pRTSContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pRTSContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX RTSContext urb!! \n"), ++ out4, ++ ("<-- ERROR in Alloc TX RTSContext TX_BUFFER !! \n"), ++ out5); ++ ++ pRTSContext->pAd = pAd; ++ pRTSContext->pIrp = NULL; ++ pRTSContext->InUse = FALSE; ++ pRTSContext->IRPPending = FALSE; ++ ++ // ++ // PsPollContext ++ // ++ //NdisZeroMemory(pPsPollContext, sizeof(TX_CONTEXT)); ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pPsPollContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX PsPollContext urb!! \n"), ++ out5, ++ ("<-- ERROR in Alloc TX PsPollContext TX_BUFFER !! \n"), ++ out6); ++ ++ pPsPollContext->pAd = pAd; ++ pPsPollContext->pIrp = NULL; ++ pPsPollContext->InUse = FALSE; ++ pPsPollContext->IRPPending = FALSE; ++ pPsPollContext->bAggregatible = FALSE; ++ pPsPollContext->LastOne = TRUE; ++ ++ } while (FALSE); ++ ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitTransmit\n")); ++ ++ return Status; ++ ++ /* --------------------------- ERROR HANDLE --------------------------- */ ++out6: ++ LM_URB_FREE(pObj, pPsPollContext, sizeof(TX_BUFFER)); ++ ++out5: ++ LM_URB_FREE(pObj, pRTSContext, sizeof(TX_BUFFER)); ++ ++out4: ++ LM_URB_FREE(pObj, pNullContext, sizeof(TX_BUFFER)); ++ ++out3: ++ for(i=0; iBeaconContext[i]); ++ if (pBeaconContext) ++ LM_URB_FREE(pObj, pBeaconContext, sizeof(TX_BUFFER)); ++ } ++ ++out2: ++ if (pAd->MgmtDescRing.AllocVa) ++ { ++ pMgmtRing = &pAd->MgmtRing; ++ for(i=0; iMgmtRing.Cell[i].AllocVa; ++ if (pMLMEContext) ++ LM_URB_FREE(pObj, pMLMEContext, sizeof(TX_BUFFER)); ++ } ++ NdisFreeMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize, 0); ++ pAd->MgmtDescRing.AllocVa = NULL; ++ } ++ ++out1: ++ for (acidx = 0; acidx < 4; acidx++) ++ { ++ PHT_TX_CONTEXT pTxContext = &(pAd->TxContext[acidx]); ++ if (pTxContext) ++ LM_URB_FREE(pObj, pTxContext, sizeof(HTTX_BUFFER)); ++ } ++ ++ // Here we didn't have any pre-allocated memory need to free. ++ ++ return Status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Allocate DMA memory blocks for send, receive. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS RTMPAllocTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd) ++{ ++// COUNTER_802_11 pCounter = &pAd->WlanCounters; ++ NDIS_STATUS Status; ++ INT num; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n")); ++ ++ ++ do ++ { ++ // Init the CmdQ and CmdQLock ++ NdisAllocateSpinLock(&pAd->CmdQLock); ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ RTUSBInitializeCmdQ(&pAd->CmdQ); ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ ++ NdisAllocateSpinLock(&pAd->MLMEBulkOutLock); ++ //NdisAllocateSpinLock(&pAd->MLMEWaitQueueLock); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[0]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[1]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[2]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[3]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[4]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[5]); ++ NdisAllocateSpinLock(&pAd->BulkInLock); ++ ++ for (num = 0; num < NUM_OF_TX_RING; num++) ++ { ++ NdisAllocateSpinLock(&pAd->TxContextQueueLock[num]); ++ } ++ ++#ifdef RALINK_ATE ++ NdisAllocateSpinLock(&pAd->GenericLock); ++#endif // RALINK_ATE // ++ ++// NdisAllocateSpinLock(&pAd->MemLock); // Not used in RT28XX ++ ++// NdisAllocateSpinLock(&pAd->MacTabLock); // init it in UserCfgInit() ++// NdisAllocateSpinLock(&pAd->BATabLock); // init it in BATableInit() ++ ++// for(num=0; numBATable.BARecEntry[num].RxReRingLock); ++// } ++ ++ // ++ // Init Mac Table ++ // ++// MacTableInitialize(pAd); ++ ++ // ++ // Init send data structures and related parameters ++ // ++ Status = NICInitTransmit(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ // ++ // Init receive data structures and related parameters ++ // ++ Status = NICInitRecv(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ pAd->PendingIoCount = 1; ++ ++ } while (FALSE); ++ ++ NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME)); ++ pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); ++ ++ if (pAd->FragFrame.pFragPacket == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ } ++ ++ DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status)); ++ return Status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Calls USB_InterfaceStop and frees memory allocated for the URBs ++ calls NdisMDeregisterDevice and frees the memory ++ allocated in VNetInitialize for the Adapter Object ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RTMPFreeTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define LM_URB_FREE(pObj, Context, BufferSize) \ ++ if (NULL != Context->pUrb) { \ ++ RTUSB_UNLINK_URB(Context->pUrb); \ ++ RTUSB_FREE_URB(Context->pUrb); \ ++ Context->pUrb = NULL; } \ ++ if (NULL != Context->TransferBuffer) { \ ++ RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, BufferSize, \ ++ Context->TransferBuffer, \ ++ Context->data_dma); \ ++ Context->TransferBuffer = NULL; } ++ ++ ++ UINT i, acidx; ++ PTX_CONTEXT pNullContext = &pAd->NullContext; ++ PTX_CONTEXT pPsPollContext = &pAd->PsPollContext; ++ PTX_CONTEXT pRTSContext = &pAd->RTSContext; ++// PHT_TX_CONTEXT pHTTXContext; ++ //PRTMP_REORDERBUF pReorderBuf; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++// RTMP_TX_RING *pTxRing; ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("---> RTMPFreeTxRxRingMemory\n")); ++ pObj = pObj; ++ ++ // Free all resources for the RECEIVE buffer queue. ++ for(i=0; i<(RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ if (pRxContext) ++ LM_URB_FREE(pObj, pRxContext, MAX_RXBULK_SIZE); ++ } ++ ++ // Free PsPoll frame resource ++ LM_URB_FREE(pObj, pPsPollContext, sizeof(TX_BUFFER)); ++ ++ // Free NULL frame resource ++ LM_URB_FREE(pObj, pNullContext, sizeof(TX_BUFFER)); ++ ++ // Free RTS frame resource ++ LM_URB_FREE(pObj, pRTSContext, sizeof(TX_BUFFER)); ++ ++ ++ // Free beacon frame resource ++ for(i=0; iBeaconContext[i]); ++ if (pBeaconContext) ++ LM_URB_FREE(pObj, pBeaconContext, sizeof(TX_BUFFER)); ++ } ++ ++ ++ // Free mgmt frame resource ++ for(i = 0; i < MGMT_RING_SIZE; i++) ++ { ++ PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[i].AllocVa; ++ //LM_URB_FREE(pObj, pMLMEContext, sizeof(TX_BUFFER)); ++ if (NULL != pAd->MgmtRing.Cell[i].pNdisPacket) ++ { ++ RTMPFreeNdisPacket(pAd, pAd->MgmtRing.Cell[i].pNdisPacket); ++ pAd->MgmtRing.Cell[i].pNdisPacket = NULL; ++ pMLMEContext->TransferBuffer = NULL; ++ } ++ ++ if (pMLMEContext) ++ { ++ if (NULL != pMLMEContext->pUrb) ++ { ++ RTUSB_UNLINK_URB(pMLMEContext->pUrb); ++ RTUSB_FREE_URB(pMLMEContext->pUrb); ++ pMLMEContext->pUrb = NULL; ++ } ++ } ++ } ++ if (pAd->MgmtDescRing.AllocVa) ++ NdisFreeMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize, 0); ++ ++ ++ // Free Tx frame resource ++ for (acidx = 0; acidx < 4; acidx++) ++ { ++ PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); ++ if (pHTTXContext) ++ LM_URB_FREE(pObj, pHTTXContext, sizeof(HTTX_BUFFER)); ++ } ++ ++ if (pAd->FragFrame.pFragPacket) ++ RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS); ++ ++ for(i=0; i<6; i++) ++ { ++ NdisFreeSpinLock(&pAd->BulkOutLock[i]); ++ } ++ ++ NdisFreeSpinLock(&pAd->BulkInLock); ++ NdisFreeSpinLock(&pAd->MLMEBulkOutLock); ++ ++ NdisFreeSpinLock(&pAd->CmdQLock); ++#ifdef RALINK_ATE ++ NdisFreeSpinLock(&pAd->GenericLock); ++#endif // RALINK_ATE // ++ // Clear all pending bulk-out request flags. ++ RTUSB_CLEAR_BULK_FLAG(pAd, 0xffffffff); ++ ++// NdisFreeSpinLock(&pAd->MacTabLock); ++ ++// for(i=0; iBATable.BARecEntry[i].RxReRingLock); ++// } ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("<--- ReleaseAdapter\n")); ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Allocate memory for adapter control block. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS AdapterBlockAllocateMemory( ++ IN PVOID handle, ++ OUT PVOID *ppAd) ++{ ++ PUSB_DEV usb_dev; ++ POS_COOKIE pObj = (POS_COOKIE) handle; ++ ++ ++ usb_dev = pObj->pUsb_Dev; ++ ++ pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE; ++ pObj->RTUSBCmdThr_pid = THREAD_PID_INIT_VALUE; ++ ++ *ppAd = (PVOID)vmalloc(sizeof(RTMP_ADAPTER)); ++ ++ if (*ppAd) ++ { ++ NdisZeroMemory(*ppAd, sizeof(RTMP_ADAPTER)); ++ ((PRTMP_ADAPTER)*ppAd)->OS_Cookie = handle; ++ return (NDIS_STATUS_SUCCESS); ++ } ++ else ++ { ++ return (NDIS_STATUS_FAILURE); ++ } ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Create kernel threads & tasklets. ++ ++Arguments: ++ *net_dev Pointer to wireless net device interface ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS CreateThreads( ++ IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pid_t pid_number = -1; ++ ++ //init_MUTEX(&(pAd->usbdev_semaphore)); ++ ++ init_MUTEX_LOCKED(&(pAd->mlme_semaphore)); ++ init_completion (&pAd->mlmeComplete); ++ ++ init_MUTEX_LOCKED(&(pAd->RTUSBCmd_semaphore)); ++ init_completion (&pAd->CmdQComplete); ++ ++ init_MUTEX_LOCKED(&(pAd->RTUSBTimer_semaphore)); ++ init_completion (&pAd->TimerQComplete); ++ ++ // Creat MLME Thread ++ pObj->MLMEThr_pid= THREAD_PID_INIT_VALUE; ++ pid_number = kernel_thread(MlmeThread, pAd, CLONE_VM); ++ if (pid_number < 0) ++ { ++ printk (KERN_WARNING "%s: unable to start Mlme thread\n",pAd->net_dev->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ pObj->MLMEThr_pid = GET_PID(pid_number); ++ // Wait for the thread to start ++ wait_for_completion(&(pAd->mlmeComplete)); ++ ++ // Creat Command Thread ++ pObj->RTUSBCmdThr_pid= THREAD_PID_INIT_VALUE; ++ pid_number = kernel_thread(RTUSBCmdThread, pAd, CLONE_VM); ++ if (pid_number < 0) ++ { ++ printk (KERN_WARNING "%s: unable to start RTUSBCmd thread\n",pAd->net_dev->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ pObj->RTUSBCmdThr_pid = GET_PID(pid_number); ++ wait_for_completion(&(pAd->CmdQComplete)); ++ ++ pObj->TimerQThr_pid= THREAD_PID_INIT_VALUE; ++ pid_number = kernel_thread(TimerQThread, pAd, CLONE_VM); ++ if (pid_number < 0) ++ { ++ printk (KERN_WARNING "%s: unable to start TimerQThread\n",pAd->net_dev->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ pObj->TimerQThr_pid = GET_PID(pid_number); ++ // Wait for the thread to start ++ wait_for_completion(&(pAd->TimerQComplete)); ++ ++ // Create receive tasklet ++ tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (ULONG)pAd); ++ tasklet_init(&pObj->mgmt_dma_done_task, rt2870_mgmt_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac0_dma_done_task, rt2870_ac0_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac1_dma_done_task, rt2870_ac1_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac2_dma_done_task, rt2870_ac2_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac3_dma_done_task, rt2870_ac3_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->hcca_dma_done_task, rt2870_hcca_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->null_frame_complete_task, rt2870_null_frame_complete_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->rts_frame_complete_task, rt2870_rts_frame_complete_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->pspoll_frame_complete_task, rt2870_pspoll_frame_complete_tasklet, (unsigned long)pAd); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++======================================================================== ++Routine Description: ++ As STA's BSSID is a WC too, it uses shared key table. ++ This function write correct unicast TX key to ASIC WCID. ++ And we still make a copy in our MacTab.Content[BSSID_WCID].PairwiseKey. ++ Caller guarantee TKIP/AES always has keyidx = 0. (pairwise key) ++ Caller guarantee WEP calls this function when set Txkey, default key index=0~3. ++ ++Arguments: ++ pAd Pointer to our adapter ++ pKey Pointer to the where the key stored ++ ++Return Value: ++ NDIS_SUCCESS Add key successfully ++ ++Note: ++======================================================================== ++*/ ++VOID RTMPAddBSSIDCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Aid, ++ IN PNDIS_802_11_KEY pKey, ++ IN UCHAR CipherAlg) ++{ ++ PUCHAR pTxMic, pRxMic; ++ BOOLEAN bKeyRSC, bAuthenticator; // indicate the receive SC set by KeyRSC value ++// UCHAR CipherAlg; ++ UCHAR i; ++ ULONG WCIDAttri; ++ USHORT offset; ++ UCHAR KeyIdx, IVEIV[8]; ++ UINT32 Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddBSSIDCipher==> Aid = %d\n",Aid)); ++ ++ // Bit 29 of Add-key KeyRSC ++ bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; ++ ++ // Bit 28 of Add-key Authenticator ++ bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; ++ KeyIdx = (UCHAR)pKey->KeyIndex&0xff; ++ ++ if (KeyIdx > 4) ++ return; ++ ++ ++ if (pAd->MacTab.Content[Aid].PairwiseKey.CipherAlg == CIPHER_TKIP) ++ { if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ // for WPA-None Tx, Rx MIC is the same ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pRxMic = pTxMic; ++ } ++ else if (bAuthenticator == TRUE) ++ { ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; ++ } ++ else ++ { ++ pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; ++ } ++ ++ offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE) + 0x10; ++ for (i=0; i<8; ) ++ { ++ Value = *(pTxMic+i); ++ Value += (*(pTxMic+i+1)<<8); ++ Value += (*(pTxMic+i+2)<<16); ++ Value += (*(pTxMic+i+3)<<24); ++ RTUSBWriteMACRegister(pAd, offset+i, Value); ++ i+=4; ++ } ++ ++ offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE) + 0x18; ++ for (i=0; i<8; ) ++ { ++ Value = *(pRxMic+i); ++ Value += (*(pRxMic+i+1)<<8); ++ Value += (*(pRxMic+i+2)<<16); ++ Value += (*(pRxMic+i+3)<<24); ++ RTUSBWriteMACRegister(pAd, offset+i, Value); ++ i+=4; ++ } ++ ++ // Only Key lenth equal to TKIP key have these ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxMic, pRxMic, 8); ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.TxMic, pTxMic, 8); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ (" TxMIC = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3], ++ pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ DBGPRINT(RT_DEBUG_TRACE, ++ (" RxMIC = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3], ++ pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ ++ // 2. Record Security Key. ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen= (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // 3. Check RxTsc. And used to init to ASIC IV. ++ if (bKeyRSC == TRUE) ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxTsc, &pKey->KeyRSC, 6); ++ else ++ NdisZeroMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxTsc, 6); ++ ++ // 4. Init TxTsc to one based on WiFi WPA specs ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[0] = 1; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[1] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[2] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[3] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[4] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[5] = 0; ++ ++ CipherAlg = pAd->MacTab.Content[Aid].PairwiseKey.CipherAlg; ++ ++ offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE); ++ RTUSBMultiWrite(pAd, (USHORT) offset, pKey->KeyMaterial, ++ ((pKey->KeyLength == LEN_TKIP_KEY) ? 16 : (USHORT)pKey->KeyLength)); ++ ++ offset = SHARED_KEY_TABLE_BASE + (KeyIdx * HW_KEY_ENTRY_SIZE); ++ RTUSBMultiWrite(pAd, (USHORT) offset, pKey->KeyMaterial, (USHORT)pKey->KeyLength); ++ ++ offset = PAIRWISE_IVEIV_TABLE_BASE + (Aid * HW_IVEIV_ENTRY_SIZE); ++ NdisZeroMemory(IVEIV, 8); ++ ++ // IV/EIV ++ if ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES)) ++ { ++ IVEIV[3] = 0x20; // Eiv bit on. keyid always 0 for pairwise key ++ } ++ // default key idx needs to set. ++ // in TKIP/AES KeyIdx = 0 , WEP KeyIdx is default tx key. ++ else ++ { ++ IVEIV[3] |= (KeyIdx<< 6); ++ } ++ RTUSBMultiWrite(pAd, (USHORT) offset, IVEIV, 8); ++ ++ // WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:1=PAIRWISE KEY, BSSIdx is 0 ++ if ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES)) ++ { ++ WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; ++ } ++ else ++ WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; ++ ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Aid* HW_WCID_ATTRI_SIZE); ++ RTUSBWriteMACRegister(pAd, offset, WCIDAttri); ++ RTUSBReadMACRegister(pAd, offset, &Value); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BSSID_WCID : offset = %x, WCIDAttri = %lx\n", ++ offset, WCIDAttri)); ++ ++ // pAddr ++ // Add Bssid mac address at linkup. not here. check! ++ /*offset = MAC_WCID_BASE + (BSSID_WCID * HW_WCID_ENTRY_SIZE); ++ *for (i=0; iBSSID[i]); ++ } ++ */ ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("AddBSSIDasWCIDEntry: Alg=%s, KeyLength = %d\n", ++ CipherName[CipherAlg], pKey->KeyLength)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Key [idx=%x] [KeyLen = %d]\n", ++ pKey->KeyIndex, pKey->KeyLength)); ++ for(i=0; iKeyLength; i++) ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" %x:", pKey->KeyMaterial[i])); ++ DBGPRINT(RT_DEBUG_TRACE,(" \n")); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++======================================================================== ++Routine Description: ++ Get a received packet. ++ ++Arguments: ++ pAd device control block ++ pSaveRxD receive descriptor information ++ *pbReschedule need reschedule flag ++ *pRxPending pending received packet flag ++ ++Return Value: ++ the recieved packet ++ ++Note: ++======================================================================== ++*/ ++#define RT2870_RXDMALEN_FIELD_SIZE 4 ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending) ++{ ++ PRX_CONTEXT pRxContext; ++ PNDIS_PACKET pSkb; ++ PUCHAR pData; ++ ULONG ThisFrameLen; ++ ULONG RxBufferLength; ++ PRXWI_STRUC pRxWI; ++ ++ pRxContext = &pAd->RxContext[pAd->NextRxBulkInReadIndex]; ++ if ((pRxContext->Readable == FALSE) || (pRxContext->InUse == TRUE)) ++ return NULL; ++ ++ RxBufferLength = pRxContext->BulkInOffset - pAd->ReadPosition; ++ if (RxBufferLength < (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXWI_STRUC) + sizeof(RXINFO_STRUC))) ++ { ++ goto label_null; ++ } ++ ++ pData = &pRxContext->TransferBuffer[pAd->ReadPosition]; /* 4KB */ ++ // The RXDMA field is 4 bytes, now just use the first 2 bytes. The Length including the (RXWI + MSDU + Padding) ++ ThisFrameLen = *pData + (*(pData+1)<<8); ++ if (ThisFrameLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("BIRIdx(%d): RXDMALen is zero.[%ld], BulkInBufLen = %ld)\n", ++ pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset)); ++ goto label_null; ++ } ++ if ((ThisFrameLen&0x3) != 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("BIRIdx(%d): RXDMALen not multiple of 4.[%ld], BulkInBufLen = %ld)\n", ++ pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset)); ++ goto label_null; ++ } ++ ++ if ((ThisFrameLen + 8)> RxBufferLength) // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BIRIdx(%d):FrameLen(0x%lx) outranges. BulkInLen=0x%lx, remaining RxBufLen=0x%lx, ReadPos=0x%lx\n", ++ pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset, RxBufferLength, pAd->ReadPosition)); ++ ++ // error frame. finish this loop ++ goto label_null; ++ } ++ ++ // skip USB frame length field ++ pData += RT2870_RXDMALEN_FIELD_SIZE; ++ pRxWI = (PRXWI_STRUC)pData; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(pData, TYPE_RXWI); ++#endif // RT_BIG_ENDIAN // ++ if (pRxWI->MPDUtotalByteCount > ThisFrameLen) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n", ++ __FUNCTION__, pRxWI->MPDUtotalByteCount, ThisFrameLen)); ++ goto label_null; ++ } ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(pData, TYPE_RXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ // allocate a rx packet ++ pSkb = dev_alloc_skb(ThisFrameLen); ++ if (pSkb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", __FUNCTION__)); ++ goto label_null; ++ } ++ ++ // copy the rx packet ++ memcpy(skb_put(pSkb, ThisFrameLen), pData, ThisFrameLen); ++ RTPKT_TO_OSPKT(pSkb)->dev = get_netdev_from_bssid(pAd, BSS0); ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pSkb), PKTSRC_NDIS); ++ ++ // copy RxD ++ *pSaveRxD = *(PRXINFO_STRUC)(pData + ThisFrameLen); ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pSaveRxD, TYPE_RXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // update next packet read position. ++ pAd->ReadPosition += (ThisFrameLen + RT2870_RXDMALEN_FIELD_SIZE + RXINFO_SIZE); // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) ++ ++ return pSkb; ++ ++label_null: ++ ++ return NULL; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Handle received packets. ++ ++Arguments: ++ data - URB information pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++static void rx_done_tasklet(unsigned long data) ++{ ++ purbb_t pUrb; ++ PRX_CONTEXT pRxContext; ++ PRTMP_ADAPTER pAd; ++ NTSTATUS Status; ++ unsigned int IrqFlags; ++ ++ pUrb = (purbb_t)data; ++ pRxContext = (PRX_CONTEXT)pUrb->context; ++ pAd = pRxContext->pAd; ++ Status = pUrb->status; ++ ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->BulkInOffset += pUrb->actual_length; ++ //NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ pAd->BulkInComplete++; ++ pAd->NextRxBulkInPosition = 0; ++ if (pRxContext->BulkInOffset) // As jan's comment, it may bulk-in success but size is zero. ++ { ++ pRxContext->Readable = TRUE; ++ INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ } ++ else // STATUS_OTHER ++ { ++ pAd->BulkInCompleteFail++; ++ // Still read this packet although it may comtain wrong bytes. ++ pRxContext->Readable = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Parsing all packets. because after reset, the index will reset to all zero. ++ if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_BULKIN_RESET | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk In Failed. Status=%d, BIIdx=0x%x, BIRIdx=0x%x, actual_length= 0x%x\n", ++ Status, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pRxContext->pUrb->actual_length)); ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); ++ } ++ } ++ ++ ASSERT((pRxContext->InUse == pRxContext->IRPPending)); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ // If the driver is in ATE mode and Rx frame is set into here. ++ if (pAd->ContinBulkIn == TRUE) ++ { ++ RTUSBBulkReceive(pAd); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ RTUSBBulkReceive(pAd); ++ ++ return; ++ ++} ++ ++ ++static void rt2870_mgmt_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pMLMEContext; ++ int index; ++ PNDIS_PACKET pPacket; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ++ ++ pUrb = (purbb_t)data; ++ pMLMEContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pMLMEContext->pAd; ++ Status = pUrb->status; ++ index = pMLMEContext->SelfIdx; ++ ++ ASSERT((pAd->MgmtRing.TxDmaIdx == index)); ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ ++ if (Status != USB_ST_NOERROR) ++ { ++ //Bulk-Out fail status handle ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); ++ // TODO: How to handle about the MLMEBulkOut failed issue. Need to resend the mgmt pkt? ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ } ++ } ++ ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ // Reset MLME context flags ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->InUse = FALSE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ pMLMEContext->BulkOutSize = 0; ++ ++ pPacket = pAd->MgmtRing.Cell[index].pNdisPacket; ++ pAd->MgmtRing.Cell[index].pNdisPacket = NULL; ++ ++ // Increase MgmtRing Index ++ INC_RING_INDEX(pAd->MgmtRing.TxDmaIdx, MGMT_RING_SIZE); ++ pAd->MgmtRing.TxSwFreeIdx++; ++ RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ // No-matter success or fail, we free the mgmt packet. ++ if (pPacket) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET) && ++ ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG)) ++ { // For Mgmt Bulk-Out failed, ignore it now. ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ } ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++} ++ ++ ++static void rt2870_hcca_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 4; ++ purbb_t pUrb; ++ ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("--->hcca_dma_done_tasklet\n")); ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("<---hcca_dma_done_tasklet\n")); ++ ++ return; ++} ++ ++ ++static void rt2870_ac3_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 3; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<3); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++} ++ ++ ++static void rt2870_ac2_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 2; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<2); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ return; ++} ++ ++ ++static void rt2870_ac1_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 1; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<1); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++} ++ ++ ++static void rt2870_ac0_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 0; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /* ((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++ ++} ++ ++ ++static void rt2870_null_frame_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pNullContext; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ unsigned long irqFlag; ++ ++ ++ pUrb = (purbb_t)data; ++ pNullContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pNullContext->pAd; ++ Status = pUrb->status; ++ ++ // Reset Null frame context flags ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); ++ pNullContext->IRPPending = FALSE; ++ pNullContext->InUse = FALSE; ++ pAd->BulkOutPending[0] = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out Null Frame Failed, ReasonCode=%d!\n", Status)); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ } ++ } ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++static void rt2870_rts_frame_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pRTSContext; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ unsigned long irqFlag; ++ ++ ++ pUrb = (purbb_t)data; ++ pRTSContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pRTSContext->pAd; ++ Status = pUrb->status; ++ ++ // Reset RTS frame context flags ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); ++ pRTSContext->IRPPending = FALSE; ++ pRTSContext->InUse = FALSE; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out RTS Frame Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ } ++ } ++ ++ RTMP_SEM_LOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); ++ pAd->BulkOutPending[pRTSContext->BulkOutPipeId] = FALSE; ++ RTMP_SEM_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++static void rt2870_pspoll_frame_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pPsPollContext; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ ++ ++ pUrb = (purbb_t)data; ++ pPsPollContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pPsPollContext->pAd; ++ Status = pUrb->status; ++ ++ // Reset PsPoll context flags ++ pPsPollContext->IRPPending = FALSE; ++ pPsPollContext->InUse = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out PSPoll Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ } ++ ++ RTMP_SEM_LOCK(&pAd->BulkOutLock[0]); ++ pAd->BulkOutPending[0] = FALSE; ++ RTMP_SEM_UNLOCK(&pAd->BulkOutLock[0]); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++static void rt2870_dataout_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ purbb_t pUrb; ++ POS_COOKIE pObj; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ Status = pUrb->status; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pHTTXContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ //DBGPRINT(RT_DEBUG_LOUD, ("Done-B(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", BulkOutPipeId, in_interrupt(), pHTTXContext->CurWritePosition, ++ // pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pHTTXContext->IRPPending = FALSE; ++ pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ pAd->BulkOutComplete++; ++ ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ pAd->Counters8023.GoodTransmits++; ++ //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ FREE_HTTX_RING(pAd, BulkOutPipeId, pHTTXContext); ++ //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ ++ } ++ else // STATUS_OTHER ++ { ++ PUCHAR pBuf; ++ ++ pAd->BulkOutCompleteOther++; ++ ++ pBuf = &pHTTXContext->TransferBuffer->field.WirelessPacket[pHTTXContext->NextBulkOutPosition]; ++ ++ if (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST | ++ fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = BulkOutPipeId; ++ pAd->bulkResetReq[BulkOutPipeId] = pAd->BulkOutReq; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkOutDataPacket failed: ReasonCode=%d!\n", Status)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("\t>>BulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("\t>>BulkOut Header:%x %x %x %x %x %x %x %x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7])); ++ //DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOutCompleteCancel=0x%x, BulkOutCompleteOther=0x%x\n", pAd->BulkOutCompleteCancel, pAd->BulkOutCompleteOther)); ++ ++ } ++ ++ // ++ // bInUse = TRUE, means some process are filling TX data, after that must turn on bWaitingBulkOut ++ // bWaitingBulkOut = TRUE, means the TX data are waiting for bulk out. ++ // ++ //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition) && ++ (pHTTXContext->ENextBulkOutPosition != (pHTTXContext->CurWritePosition+8)) && ++ !RTUSB_TEST_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId))) ++ { ++ // Indicate There is data avaliable ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protection of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++} ++ ++/* End of 2870_rtmp_init.c */ +--- /dev/null ++++ b/drivers/staging/rt2870/common/action.c +@@ -0,0 +1,1046 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ action.c ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 2006 created for rt2860 ++ */ ++ ++#include "../rt_config.h" ++#include "action.h" ++ ++ ++static VOID ReservedAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ Note: ++ The state machine looks like the following ++ ++ ASSOC_IDLE ++ MT2_MLME_DISASSOC_REQ mlme_disassoc_req_action ++ MT2_PEER_DISASSOC_REQ peer_disassoc_action ++ MT2_PEER_ASSOC_REQ drop ++ MT2_PEER_REASSOC_REQ drop ++ MT2_CLS3ERR cls3err_action ++ ========================================================================== ++ */ ++VOID ActionStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, (STATE_MACHINE_FUNC *)Trans, MAX_ACT_STATE, MAX_ACT_MSG, (STATE_MACHINE_FUNC)Drop, ACT_IDLE, ACT_MACHINE_BASE); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_SPECTRUM_CATE, (STATE_MACHINE_FUNC)PeerSpectrumAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_QOS_CATE, (STATE_MACHINE_FUNC)PeerQOSAction); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)ReservedAction); ++#ifdef QOS_DLS_SUPPORT ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)PeerDLSAction); ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_BA_CATE, (STATE_MACHINE_FUNC)PeerBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_HT_CATE, (STATE_MACHINE_FUNC)PeerHTAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ADD_BA_CATE, (STATE_MACHINE_FUNC)MlmeADDBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ORI_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_REC_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); ++#endif // DOT11_N_SUPPORT // ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_PUBLIC_CATE, (STATE_MACHINE_FUNC)PeerPublicAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_RM_CATE, (STATE_MACHINE_FUNC)PeerRMAction); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_QOS_CATE, (STATE_MACHINE_FUNC)MlmeQOSAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_DLS_CATE, (STATE_MACHINE_FUNC)MlmeDLSAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_ACT_INVALID, (STATE_MACHINE_FUNC)MlmeInvalidAction); ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID MlmeADDBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ MLME_ADDBA_REQ_STRUCT *pInfo; ++ UCHAR Addr[6]; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG Idx; ++ FRAME_ADDBA_REQ Frame; ++ ULONG FrameLen; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ ++ pInfo = (MLME_ADDBA_REQ_STRUCT *)Elem->Msg; ++ NdisZeroMemory(&Frame, sizeof(FRAME_ADDBA_REQ)); ++ ++ if(MlmeAddBAReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++ // 1. find entry ++ Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; ++ if (Idx == 0) ++ { ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() can't find BAOriEntry \n")); ++ return; ++ } ++ else ++ { ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) ++ ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pInfo->pAddr); ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ Frame.Category = CATEGORY_BA; ++ Frame.Action = ADDBA_REQ; ++ Frame.BaParm.AMSDUSupported = 0; ++ Frame.BaParm.BAPolicy = IMMED_BA; ++ Frame.BaParm.TID = pInfo->TID; ++ Frame.BaParm.BufSize = pInfo->BaBufSize; ++ Frame.Token = pInfo->Token; ++ Frame.TimeOutValue = pInfo->TimeOutValue; ++ Frame.BaStartSeq.field.FragNum = 0; ++ Frame.BaStartSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; ++ ++ *(USHORT *)(&Frame.BaParm) = cpu2le16(*(USHORT *)(&Frame.BaParm)); ++ Frame.TimeOutValue = cpu2le16(Frame.TimeOutValue); ++ Frame.BaStartSeq.word = cpu2le16(Frame.BaStartSeq.word); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ADDBA_REQ), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BA - Send ADDBA request. StartSeq = %x, FrameLen = %ld. BufSize = %d\n", Frame.BaStartSeq.field.StartSeq, FrameLen, Frame.BaParm.BufSize)); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ send DELBA and delete BaEntry if any ++ Parametrs: ++ Elem - MLME message MLME_DELBA_REQ_STRUCT ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDELBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DELBA_REQ_STRUCT *pInfo; ++ PUCHAR pOutBuffer = NULL; ++ PUCHAR pOutBuffer2 = NULL; ++ NDIS_STATUS NStatus; ++ ULONG Idx; ++ FRAME_DELBA_REQ Frame; ++ ULONG FrameLen; ++ FRAME_BAR FrameBar; ++ ++ pInfo = (MLME_DELBA_REQ_STRUCT *)Elem->Msg; ++ // must send back DELBA ++ NdisZeroMemory(&Frame, sizeof(FRAME_DELBA_REQ)); ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeDELBAAction(), Initiator(%d) \n", pInfo->Initiator)); ++ ++ if(MlmeDelBAReqSanity(pAd, Elem->Msg, Elem->MsgLen)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeDELBAAction() allocate memory failed 1. \n")); ++ return; ++ } ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR, ("BA - MlmeDELBAAction() allocate memory failed 2. \n")); ++ return; ++ } ++ ++ // SEND BAR (Send BAR to refresh peer reordering buffer.) ++ Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL funciton. ++ FrameBar.StartingSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = pInfo->TID; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.ACKPolicy = IMMED_BA; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.Compressed = 1; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.MTID = 0; // make sure sequence not clear in DEL funciton. ++ ++ MakeOutgoingFrame(pOutBuffer2, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer2); ++ DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeDELBAAction() . Send BAR to refresh peer reordering buffer \n")); ++ ++ // SEND DELBA FRAME ++ FrameLen = 0; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->MacTab.Content[pInfo->Wcid].ValidAsDls) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[pInfo->Wcid].Addr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ Frame.Category = CATEGORY_BA; ++ Frame.Action = DELBA; ++ Frame.DelbaParm.Initiator = pInfo->Initiator; ++ Frame.DelbaParm.TID = pInfo->TID; ++ Frame.ReasonCode = 39; // Time Out ++ *(USHORT *)(&Frame.DelbaParm) = cpu2le16(*(USHORT *)(&Frame.DelbaParm)); ++ Frame.ReasonCode = cpu2le16(Frame.ReasonCode); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_DELBA_REQ), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("BA - MlmeDELBAAction() . 3 DELBA sent. Initiator(%d)\n", pInfo->Initiator)); ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID MlmeQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++VOID MlmeDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++VOID MlmeInvalidAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ //PUCHAR pOutBuffer = NULL; ++ //Return the receiving frame except the MSB of category filed set to 1. 7.3.1.11 ++} ++ ++VOID PeerQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++#ifdef QOS_DLS_SUPPORT ++VOID PeerDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ switch(Action) ++ { ++ case ACTION_DLS_REQUEST: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsReqAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ ++ case ACTION_DLS_RESPONSE: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsRspAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ ++ case ACTION_DLS_TEARDOWN: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsTearDownAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ } ++} ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ switch(Action) ++ { ++ case ADDBA_REQ: ++ PeerAddBAReqAction(pAd,Elem); ++ break; ++ case ADDBA_RESP: ++ PeerAddBARspAction(pAd,Elem); ++ break; ++ case DELBA: ++ PeerDelBAAction(pAd,Elem); ++ break; ++ } ++} ++ ++ ++#ifdef DOT11N_DRAFT3 ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID StaPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Bss2040Coexist) ++{ ++ BSS_2040_COEXIST_IE BssCoexist; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ BssCoexist.word = Bss2040Coexist; ++ // AP asks Station to return a 20/40 BSS Coexistence mgmt frame. So we first starts a scan, then send back 20/40 BSS Coexistence mgmt frame ++ if ((BssCoexist.field.InfoReq == 1) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))) ++ { ++ // Clear record first. After scan , will update those bit and send back to transmiter. ++ pAd->CommonCfg.BSSCoexist2040.field.InfoReq = 1; ++ pAd->CommonCfg.BSSCoexist2040.field.Intolerant40 = 0; ++ pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 0; ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_2040_BSS_COEXIST); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ } ++} ++ ++ ++/* ++Description : Build Intolerant Channel Rerpot from Trigger event table. ++return : how many bytes copied. ++*/ ++ULONG BuildIntolerantChannelRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest) ++{ ++ ULONG FrameLen = 0; ++ ULONG ReadOffset = 0; ++ UCHAR i; ++ UCHAR LastRegClass = 0xff; ++ PUCHAR pLen; ++ ++ for ( i = 0;i < MAX_TRIGGER_EVENT;i++) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid == TRUE) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass == LastRegClass) ++ { ++ *(pDest + ReadOffset) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; ++ *pLen++; ++ ReadOffset++; ++ FrameLen++; ++ } ++ else ++ { ++ *(pDest + ReadOffset) = IE_2040_BSS_INTOLERANT_REPORT; // IE ++ *(pDest + ReadOffset + 1) = 2; // Len = RegClass byte + channel byte. ++ pLen = pDest + ReadOffset + 1; ++ LastRegClass = pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass; ++ *(pDest + ReadOffset + 2) = LastRegClass; // Len = RegClass byte + channel byte. ++ *(pDest + ReadOffset + 3) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; ++ FrameLen += 4; ++ ReadOffset += 4; ++ } ++ ++ } ++ } ++ return FrameLen; ++} ++ ++ ++/* ++Description : Send 20/40 BSS Coexistence Action frame If one trigger event is triggered. ++*/ ++VOID Send2040CoexistAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ FRAME_ACTION_HDR Frame; ++ ULONG FrameLen; ++ ULONG IntolerantChaRepLen; ++ ++ IntolerantChaRepLen = 0; ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction() allocate memory failed \n")); ++ return; ++ } ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[Wcid].Addr, pAd->CommonCfg.Bssid); ++ Frame.Category = CATEGORY_PUBLIC; ++ Frame.Action = ACTION_BSS_2040_COEXIST; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ACTION_HDR), &Frame, ++ END_OF_ARGS); ++ ++ *(pOutBuffer + FrameLen) = pAd->CommonCfg.BSSCoexist2040.word; ++ FrameLen++; ++ ++ if (bAddIntolerantCha == TRUE) ++ IntolerantChaRepLen = BuildIntolerantChannelRep(pAd, pOutBuffer + FrameLen); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen + IntolerantChaRepLen); ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction( BSSCoexist2040 = 0x%x ) \n", pAd->CommonCfg.BSSCoexist2040.word)); ++ ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ After scan, Update 20/40 BSS Coexistence IE and send out. ++ According to 802.11n D3.03 11.14.10 ++ ++ Parameters: ++ ========================================================================== ++ */ ++VOID Update2040CoexistFrameAndNotify( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha) ++{ ++ BSS_2040_COEXIST_IE OldValue; ++ ++ OldValue.word = pAd->CommonCfg.BSSCoexist2040.word; ++ if ((pAd->CommonCfg.TriggerEventTab.EventANo > 0) || (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)) ++ pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 1; ++ ++ // Need to check !!!! ++ // How STA will set Intolerant40 if implementation dependent. Now we don't set this bit first.!!!!! ++ // So Only check BSS20WidthReq change. ++ if (OldValue.field.BSS20WidthReq != pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq) ++ { ++ Send2040CoexistAction(pAd, Wcid, bAddIntolerantCha); ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++BOOLEAN ChannelSwitchSanityCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary) ++{ ++ UCHAR i; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ if ((NewChannel > 7) && (Secondary == 1)) ++ return FALSE; ++ ++ if ((NewChannel < 5) && (Secondary == 3)) ++ return FALSE; ++ ++ // 0. Check if new channel is in the channellist. ++ for (i = 0;i < pAd->ChannelListNum;i++) ++ { ++ if (pAd->ChannelList[i].Channel == NewChannel) ++ { ++ break; ++ } ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++VOID ChannelSwitchAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary) ++{ ++ UCHAR BBPValue = 0; ++ ULONG MACValue; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SPECTRUM - ChannelSwitchAction(NewChannel = %d , Secondary = %d) \n", NewChannel, Secondary)); ++ ++ if (ChannelSwitchSanityCheck(pAd, Wcid, NewChannel, Secondary) == FALSE) ++ return; ++ ++ // 1. Switches to BW = 20. ++ if (Secondary == 0) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ pAd->CommonCfg.Channel = NewChannel; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel,FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz !!! \n" )); ++ } ++ // 1. Switches to BW = 40 And Station supports BW = 40. ++ else if (((Secondary == 1) || (Secondary == 3)) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == 1)) ++ { ++ pAd->CommonCfg.Channel = NewChannel; ++ ++ if (Secondary == 1) ++ { ++ // Secondary above. ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); ++ MACValue &= 0xfe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); ++ BBPValue&= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++ { ++ // Secondary below. ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); ++ MACValue &= 0xfe; ++ MACValue |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); ++ BBPValue&= (~0x20); ++ BBPValue|= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 1; ++ } ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++VOID PeerPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++#ifdef DOT11N_DRAFT3 ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++#endif // DOT11N_DRAFT3 // ++ ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++#ifdef DOT11N_DRAFT3 ++ switch(Action) ++ { ++ case ACTION_BSS_2040_COEXIST: // Format defined in IEEE 7.4.7a.1 in 11n Draf3.03 ++ { ++ //UCHAR BssCoexist; ++ BSS_2040_COEXIST_ELEMENT *pCoexistInfo; ++ BSS_2040_COEXIST_IE *pBssCoexistIe; ++ BSS_2040_INTOLERANT_CH_REPORT *pIntolerantReport = NULL; ++ ++ if (Elem->MsgLen <= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT)) ) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ACTION - 20/40 BSS Coexistence Management Frame length too short! len = %ld!\n", Elem->MsgLen)); ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("ACTION - 20/40 BSS Coexistence Management action----> \n")); ++ hex_dump("CoexistenceMgmtFrame", Elem->Msg, Elem->MsgLen); ++ ++ ++ pCoexistInfo = (BSS_2040_COEXIST_ELEMENT *) &Elem->Msg[LENGTH_802_11+2]; ++ //hex_dump("CoexistInfo", (PUCHAR)pCoexistInfo, sizeof(BSS_2040_COEXIST_ELEMENT)); ++ if (Elem->MsgLen >= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT) + sizeof(BSS_2040_INTOLERANT_CH_REPORT))) ++ { ++ pIntolerantReport = (BSS_2040_INTOLERANT_CH_REPORT *)((PUCHAR)pCoexistInfo + sizeof(BSS_2040_COEXIST_ELEMENT)); ++ } ++ //hex_dump("IntolerantReport ", (PUCHAR)pIntolerantReport, sizeof(BSS_2040_INTOLERANT_CH_REPORT)); ++ ++ pBssCoexistIe = (BSS_2040_COEXIST_IE *)(&pCoexistInfo->BssCoexistIe); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ StaPublicAction(pAd, pCoexistInfo); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++ break; ++ } ++ ++#endif // DOT11N_DRAFT3 // ++ ++} ++ ++ ++static VOID ReservedAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Category; ++ ++ if (Elem->MsgLen <= LENGTH_802_11) ++ { ++ return; ++ } ++ ++ Category = Elem->Msg[LENGTH_802_11]; ++ DBGPRINT(RT_DEBUG_TRACE,("Rcv reserved category(%d) Action Frame\n", Category)); ++ hex_dump("Reserved Action Frame", &Elem->Msg[0], Elem->MsgLen); ++} ++ ++VOID PeerRMAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ return; ++} ++ ++#ifdef DOT11_N_SUPPORT ++static VOID respond_ht_information_exchange_action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ FRAME_HT_INFO HTINFOframe, *pFrame; ++ UCHAR *pAddr; ++ ++ ++ // 2. Always send back ADDBA Response ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - respond_ht_information_exchange_action() allocate memory failed \n")); ++ return; ++ } ++ ++ // get RA ++ pFrame = (FRAME_HT_INFO *) &Elem->Msg[0]; ++ pAddr = pFrame->Hdr.Addr2; ++ ++ NdisZeroMemory(&HTINFOframe, sizeof(FRAME_HT_INFO)); ++ // 2-1. Prepare ADDBA Response frame. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &HTINFOframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++ ActHeaderInit(pAd, &HTINFOframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ HTINFOframe.Category = CATEGORY_HT; ++ HTINFOframe.Action = HT_INFO_EXCHANGE; ++ HTINFOframe.HT_Info.Request = 0; ++ HTINFOframe.HT_Info.Forty_MHz_Intolerant = pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant; ++ HTINFOframe.HT_Info.STA_Channel_Width = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_HT_INFO), &HTINFOframe, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID SendNotifyBWActionFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ FRAME_ACTION_HDR Frame; ++ ULONG FrameLen; ++ PUCHAR pAddr1; ++ ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - SendNotifyBWAction() allocate memory failed \n")); ++ return; ++ } ++ ++ if (Wcid == MCAST_WCID) ++ pAddr1 = &BROADCAST_ADDR[0]; ++ else ++ pAddr1 = pAd->MacTab.Content[Wcid].Addr; ++ ActHeaderInit(pAd, &Frame.Hdr, pAddr1, pAd->ApCfg.MBSSID[apidx].Bssid, pAd->ApCfg.MBSSID[apidx].Bssid); ++ ++ Frame.Category = CATEGORY_HT; ++ Frame.Action = NOTIFY_BW_ACTION; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ACTION_HDR), &Frame, ++ END_OF_ARGS); ++ ++ *(pOutBuffer + FrameLen) = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; ++ FrameLen++; ++ ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ DBGPRINT(RT_DEBUG_TRACE,("ACT - SendNotifyBWAction(NotifyBW= %d)!\n", pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)); ++ ++} ++#endif // DOT11N_DRAFT3 // ++ ++ ++VOID PeerHTAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ switch(Action) ++ { ++ case NOTIFY_BW_ACTION: ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Notify Channel bandwidth action----> \n")); ++#ifdef CONFIG_STA_SUPPORT ++ if(pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ { ++ // Note, this is to patch DIR-1353 AP. When the AP set to Wep, it will use legacy mode. But AP still keeps ++ // sending BW_Notify Action frame, and cause us to linkup and linkdown. ++ // In legacy mode, don't need to parse HT action frame. ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION -Ignore HT Notify Channel BW when link as legacy mode. BW = %d---> \n", ++ Elem->Msg[LENGTH_802_11+2] )); ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (Elem->Msg[LENGTH_802_11+2] == 0) // 7.4.8.2. if value is 1, keep the same as supported channel bandwidth. ++ pAd->MacTab.Content[Elem->Wcid].HTPhyMode.field.BW = 0; ++ ++ break; ++ ++ case SMPS_ACTION: ++ // 7.3.1.25 ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - SMPS action----> \n")); ++ if (((Elem->Msg[LENGTH_802_11+2]&0x1) == 0)) ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_ENABLE; ++ } ++ else if (((Elem->Msg[LENGTH_802_11+2]&0x2) == 0)) ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_STATIC; ++ } ++ else ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_DYNAMIC; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Aid(%d) MIMO PS = %d\n", Elem->Wcid, pAd->MacTab.Content[Elem->Wcid].MmpsMode)); ++ // rt2860c : add something for smps change. ++ break; ++ ++ case SETPCO_ACTION: ++ break; ++ ++ case MIMO_CHA_MEASURE_ACTION: ++ break; ++ ++ case HT_INFO_EXCHANGE: ++ { ++ HT_INFORMATION_OCTET *pHT_info; ++ ++ pHT_info = (HT_INFORMATION_OCTET *) &Elem->Msg[LENGTH_802_11+2]; ++ // 7.4.8.10 ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Information Exchange action----> \n")); ++ if (pHT_info->Request) ++ { ++ respond_ht_information_exchange_action(pAd, Elem); ++ } ++ } ++ break; ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Retry sending ADDBA Reqest. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Parametrs: ++ p8023Header: if this is already 802.3 format, p8023Header is NULL ++ ++ Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. ++ FALSE , then continue indicaterx at this moment. ++ ========================================================================== ++ */ ++VOID ORIBATimerTimeout( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MAC_TABLE_ENTRY *pEntry; ++ INT i, total; ++// FRAME_BAR FrameBar; ++// ULONG FrameLen; ++// NDIS_STATUS NStatus; ++// PUCHAR pOutBuffer = NULL; ++// USHORT Sequence; ++ UCHAR TID; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ total = pAd->MacTab.Size * NUM_OF_TID; ++ ++ for (i = 1; ((i 0)) ; i++) ++ { ++ if (pAd->BATable.BAOriEntry[i].ORI_BA_Status == Originator_Done) ++ { ++ pEntry = &pAd->MacTab.Content[pAd->BATable.BAOriEntry[i].Wcid]; ++ TID = pAd->BATable.BAOriEntry[i].TID; ++ ++ ASSERT(pAd->BATable.BAOriEntry[i].Wcid < MAX_LEN_OF_MAC_TABLE); ++ } ++ total --; ++ } ++} ++ ++ ++VOID SendRefreshBAR( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ FRAME_BAR FrameBar; ++ ULONG FrameLen; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ USHORT Sequence; ++ UCHAR i, TID; ++ USHORT idx; ++ BA_ORI_ENTRY *pBAEntry; ++ ++ for (i = 0; i BAOriWcidArray[i]; ++ if (idx == 0) ++ { ++ continue; ++ } ++ pBAEntry = &pAd->BATable.BAOriEntry[idx]; ++ ++ if (pBAEntry->ORI_BA_Status == Originator_Done) ++ { ++ TID = pBAEntry->TID; ++ ++ ASSERT(pBAEntry->Wcid < MAX_LEN_OF_MAC_TABLE); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++ ++ Sequence = pEntry->TxSeq[TID]; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. ++ FrameBar.StartingSeq.field.StartSeq = Sequence; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = TID; // make sure sequence not clear in DEL funciton. ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ //if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_RALINK_CHIPSET))) ++ if (1) // Now we always send BAR. ++ { ++ //MiniportMMRequestUnlock(pAd, 0, pOutBuffer, FrameLen); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ } ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID ActHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN PUCHAR Addr1, ++ IN PUCHAR Addr2, ++ IN PUCHAR Addr3) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SUBTYPE_ACTION; ++ ++ COPY_MAC_ADDR(pHdr80211->Addr1, Addr1); ++ COPY_MAC_ADDR(pHdr80211->Addr2, Addr2); ++ COPY_MAC_ADDR(pHdr80211->Addr3, Addr3); ++} ++ ++VOID BarHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PFRAME_BAR pCntlBar, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA) ++{ ++// USHORT Duration; ++ ++ NdisZeroMemory(pCntlBar, sizeof(FRAME_BAR)); ++ pCntlBar->FC.Type = BTYPE_CNTL; ++ pCntlBar->FC.SubType = SUBTYPE_BLOCK_ACK_REQ; ++ pCntlBar->BarControl.MTID = 0; ++ pCntlBar->BarControl.Compressed = 1; ++ pCntlBar->BarControl.ACKPolicy = 0; ++ ++ ++ pCntlBar->Duration = 16 + RTMPCalcDuration(pAd, RATE_1, sizeof(FRAME_BA)); ++ ++ COPY_MAC_ADDR(pCntlBar->Addr1, pDA); ++ COPY_MAC_ADDR(pCntlBar->Addr2, pSA); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Category and action code into the action frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. category code of the frame. ++ 4. action code of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID InsertActField( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 Category, ++ IN UINT8 ActCode) ++{ ++ ULONG TempLen; ++ ++ MakeOutgoingFrame( pFrameBuf, &TempLen, ++ 1, &Category, ++ 1, &ActCode, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/rt2870/common/action.h +@@ -0,0 +1,68 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 04-06-15 Initial ++*/ ++ ++#ifndef __ACTION_H__ ++#define __ACTION_H__ ++ ++typedef struct PACKED __HT_INFO_OCTET ++{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR Reserved:5; ++ UCHAR STA_Channel_Width:1; ++ UCHAR Forty_MHz_Intolerant:1; ++ UCHAR Request:1; ++#else ++ UCHAR Request:1; ++ UCHAR Forty_MHz_Intolerant:1; ++ UCHAR STA_Channel_Width:1; ++ UCHAR Reserved:5; ++#endif ++} HT_INFORMATION_OCTET; ++ ++ ++typedef struct PACKED __FRAME_HT_INFO ++{ ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ HT_INFORMATION_OCTET HT_Info; ++} FRAME_HT_INFO, *PFRAME_HT_INFO; ++ ++#endif /* __ACTION_H__ */ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/ba_action.c +@@ -0,0 +1,1798 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++ ++#ifdef DOT11_N_SUPPORT ++ ++#include "../rt_config.h" ++ ++ ++ ++#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) //1 // inital sequence number of BA session ++ ++#define ORI_SESSION_MAX_RETRY 8 ++#define ORI_BA_SESSION_TIMEOUT (2000) // ms ++#define REC_BA_SESSION_IDLE_TIMEOUT (1000) // ms ++ ++#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms ++#define MAX_REORDERING_PACKET_TIMEOUT ((3000 * HZ)/1000) // system ticks -- 100 ms ++ ++#define RESET_RCV_SEQ (0xFFFF) ++ ++static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk); ++ ++ ++BA_ORI_ENTRY *BATableAllocOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx); ++ ++BA_REC_ENTRY *BATableAllocRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx); ++ ++VOID BAOriSessionSetupTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID BARecSessionIdleTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout); ++BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout); ++ ++#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk) \ ++ Announce_Reordering_Packet(_pAd, _mpdu_blk); ++ ++VOID BA_MaxWinSizeReasign( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntryPeer, ++ OUT UCHAR *pWinSize) ++{ ++ UCHAR MaxSize; ++ ++ ++ if (pAd->MACVersion >= RALINK_2883_VERSION) // 3*3 ++ { ++ if (pAd->MACVersion >= RALINK_3070_VERSION) ++ { ++ if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) ++ MaxSize = 7; // for non-open mode ++ else ++ MaxSize = 13; ++ } ++ else ++ MaxSize = 31; ++ } ++ else if (pAd->MACVersion >= RALINK_2880E_VERSION) // 2880 e ++ { ++ if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) ++ MaxSize = 7; // for non-open mode ++ else ++ MaxSize = 13; ++ } ++ else ++ MaxSize = 7; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n", ++ *pWinSize, MaxSize)); ++ ++ if ((*pWinSize) > MaxSize) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ba> reassign max win size from %d to %d\n", ++ *pWinSize, MaxSize)); ++ ++ *pWinSize = MaxSize; ++ } ++} ++ ++void Announce_Reordering_Packet(IN PRTMP_ADAPTER pAd, ++ IN struct reordering_mpdu *mpdu) ++{ ++ PNDIS_PACKET pPacket; ++ ++ pPacket = mpdu->pPacket; ++ ++ if (mpdu->bAMSDU) ++ { ++ ASSERT(0); ++ BA_Reorder_AMSDU_Annnounce(pAd, pPacket); ++ } ++ else ++ { ++ // ++ // pass this 802.3 packet to upper layer or forward this packet to WM directly ++ // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++/* ++ * Insert a reordering mpdu into sorted linked list by sequence no. ++ */ ++BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list, struct reordering_mpdu *mpdu) ++{ ++ ++ struct reordering_mpdu **ppScan = &list->next; ++ ++ while (*ppScan != NULL) ++ { ++ if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ)) ++ { ++ ppScan = &(*ppScan)->next; ++ } ++ else if ((*ppScan)->Sequence == mpdu->Sequence) ++ { ++ /* give up this duplicated frame */ ++ return(FALSE); ++ } ++ else ++ { ++ /* find position */ ++ break; ++ } ++ } ++ ++ mpdu->next = *ppScan; ++ *ppScan = mpdu; ++ list->qlen++; ++ return TRUE; ++} ++ ++ ++/* ++ * caller lock critical section if necessary ++ */ ++static inline void ba_enqueue(struct reordering_list *list, struct reordering_mpdu *mpdu_blk) ++{ ++ list->qlen++; ++ mpdu_blk->next = list->next; ++ list->next = mpdu_blk; ++} ++ ++/* ++ * caller lock critical section if necessary ++ */ ++static inline struct reordering_mpdu * ba_dequeue(struct reordering_list *list) ++{ ++ struct reordering_mpdu *mpdu_blk = NULL; ++ ++ ASSERT(list); ++ ++ if (list->qlen) ++ { ++ list->qlen--; ++ mpdu_blk = list->next; ++ if (mpdu_blk) ++ { ++ list->next = mpdu_blk->next; ++ mpdu_blk->next = NULL; ++ } ++ } ++ return mpdu_blk; ++} ++ ++ ++static inline struct reordering_mpdu *ba_reordering_mpdu_dequeue(struct reordering_list *list) ++{ ++ return(ba_dequeue(list)); ++} ++ ++ ++static inline struct reordering_mpdu *ba_reordering_mpdu_probe(struct reordering_list *list) ++ { ++ ASSERT(list); ++ ++ return(list->next); ++ } ++ ++ ++/* ++ * free all resource for reordering mechanism ++ */ ++void ba_reordering_resource_release(PRTMP_ADAPTER pAd) ++{ ++ BA_TABLE *Tab; ++ PBA_REC_ENTRY pBAEntry; ++ struct reordering_mpdu *mpdu_blk; ++ int i; ++ ++ Tab = &pAd->BATable; ++ ++ /* I. release all pending reordering packet */ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ pBAEntry = &Tab->BARecEntry[i]; ++ if (pBAEntry->REC_BA_Status != Recipient_NONE) ++ { ++ while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) ++ { ++ ASSERT(mpdu_blk->pPacket); ++ RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket, NDIS_STATUS_FAILURE); ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ } ++ } ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ ++ ASSERT(pBAEntry->list.qlen == 0); ++ /* II. free memory of reordering mpdu table */ ++ NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); ++ os_free_mem(pAd, pAd->mpdu_blk_pool.mem); ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++} ++ ++ ++ ++/* ++ * Allocate all resource for reordering mechanism ++ */ ++BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num) ++{ ++ int i; ++ PUCHAR mem; ++ struct reordering_mpdu *mpdu_blk; ++ struct reordering_list *freelist; ++ ++ /* allocate spinlock */ ++ NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock); ++ ++ /* initialize freelist */ ++ freelist = &pAd->mpdu_blk_pool.freelist; ++ freelist->next = NULL; ++ freelist->qlen = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Allocate %d memory for BA reordering\n", (UINT32)(num*sizeof(struct reordering_mpdu)))); ++ ++ /* allocate number of mpdu_blk memory */ ++ os_alloc_mem(pAd, (PUCHAR *)&mem, (num*sizeof(struct reordering_mpdu))); ++ ++ pAd->mpdu_blk_pool.mem = mem; ++ ++ if (mem == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Can't Allocate Memory for BA Reordering\n")); ++ return(FALSE); ++ } ++ ++ /* build mpdu_blk free list */ ++ for (i=0; impdu_blk_pool.lock); ++ mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist); ++ if (mpdu_blk) ++ { ++// blk_count++; ++ /* reset mpdu_blk */ ++ NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu)); ++ } ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++ return mpdu_blk; ++} ++ ++static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk) ++{ ++ ASSERT(mpdu_blk); ++ ++ NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); ++// blk_count--; ++ ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk); ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++} ++ ++ ++static USHORT ba_indicate_reordering_mpdus_in_order( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN USHORT StartSeq) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ USHORT LastIndSeq = RESET_RCV_SEQ; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) ++ { ++ /* find in-order frame */ ++ if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ)) ++ { ++ break; ++ } ++ /* dequeue in-order frame from reodering list */ ++ mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ /* move to next sequence */ ++ StartSeq = mpdu_blk->Sequence; ++ LastIndSeq = StartSeq; ++ /* free mpdu_blk */ ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ ++ /* update last indicated sequence */ ++ return LastIndSeq; ++} ++ ++static void ba_indicate_reordering_mpdus_le_seq( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN USHORT Sequence) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) ++ { ++ /* find in-order frame */ ++ if ((mpdu_blk->Sequence == Sequence) || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ)) ++ { ++ /* dequeue in-order frame from reodering list */ ++ mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ /* free mpdu_blk */ ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ else ++ { ++ break; ++ } ++ } ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++} ++ ++ ++static void ba_refresh_reordering_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ PBA_REC_ENTRY pBAEntry) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ /* dequeue in-order frame from reodering list */ ++ while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) ++ { ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ ++ pBAEntry->LastIndSeq = mpdu_blk->Sequence; ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ ++ /* update last indicated sequence */ ++ } ++ ASSERT(pBAEntry->list.qlen == 0); ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++} ++ ++ ++//static ++void ba_flush_reordering_timeout_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN ULONG Now32) ++ ++{ ++ USHORT Sequence; ++ ++// if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) && ++// (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //|| ++// (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) && ++// (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8))) ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT/6))) ++ &&(pBAEntry->list.qlen > 1) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++ (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, ++ pBAEntry->LastIndSeq)); ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++ else ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) ++ && (pBAEntry->list.qlen > 0) ++ ) ++ { ++ // ++ // force LastIndSeq to shift to LastIndSeq+1 ++ // ++ Sequence = (pBAEntry->LastIndSeq+1) & MAXSEQ; ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ pBAEntry->LastIndSeq = Sequence; ++ // ++ // indicate in-order mpdus ++ // ++ Sequence = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, Sequence); ++ if (Sequence != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = Sequence; ++ } ++ ++ } ++#if 0 ++ else if ( ++ (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT))) && ++ (pBAEntry->list.qlen > 1)) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%lx-%lx = %d > %d): %x\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++ (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, ++ pBAEntry->LastIndSeq)); ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++#endif ++} ++ ++ ++/* ++ * generate ADDBA request to ++ * set up BA agreement ++ */ ++VOID BAOriSessionSetUp( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN UCHAR TID, ++ IN USHORT TimeOut, ++ IN ULONG DelayTime, ++ IN BOOLEAN isForced) ++ ++{ ++ //MLME_ADDBA_REQ_STRUCT AddbaReq; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ USHORT Idx; ++ BOOLEAN Cancelled; ++ ++ if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE) && (isForced == FALSE)) ++ return; ++ ++ // if this entry is limited to use legacy tx mode, it doesn't generate BA. ++ if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT) ++ return; ++ ++ if ((pEntry->BADeclineBitmap & (1<BAOriWcidArray[TID]; ++ if (Idx == 0) ++ { ++ // allocate a BA session ++ pBAEntry = BATableAllocOriEntry(pAd, &Idx); ++ if (pBAEntry == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ADDBA - MlmeADDBAAction() allocate BA session failed \n")); ++ return; ++ } ++ } ++ else ++ { ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ } ++ ++ if (pBAEntry->ORI_BA_Status >= Originator_WaitRes) ++ { ++ return; ++ } ++ ++ pEntry->BAOriWcidArray[TID] = Idx; ++ ++ // Initialize BA session ++ pBAEntry->ORI_BA_Status = Originator_WaitRes; ++ pBAEntry->Wcid = pEntry->Aid; ++ pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; ++ pBAEntry->Sequence = BA_ORI_INIT_SEQ; ++ pBAEntry->Token = 1; // (2008-01-21) Jan Lee recommends it - this token can't be 0 ++ pBAEntry->TID = TID; ++ pBAEntry->TimeOutValue = TimeOut; ++ pBAEntry->pAdapter = pAd; ++ ++ if (!(pEntry->TXBAbitmap & (1<ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE); ++ } ++ else ++ RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); ++ ++ // set timer to send ADDBA request ++ RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime); ++} ++ ++VOID BAOriSessionAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PFRAME_ADDBA_RSP pFrame) ++{ ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ BOOLEAN Cancelled; ++ UCHAR TID; ++ USHORT Idx; ++ PUCHAR pOutBuffer2 = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ FRAME_BAR FrameBar; ++ ++ TID = pFrame->BaParm.TID; ++ Idx = pEntry->BAOriWcidArray[TID]; ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ ++ // Start fill in parameters. ++ if ((Idx !=0) && (pBAEntry->TID == TID) && (pBAEntry->ORI_BA_Status == Originator_WaitRes)) ++ { ++ pBAEntry->BAWinSize = min(pBAEntry->BAWinSize, ((UCHAR)pFrame->BaParm.BufSize)); ++ BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize); ++ ++ pBAEntry->TimeOutValue = pFrame->TimeOutValue; ++ pBAEntry->ORI_BA_Status = Originator_Done; ++ // reset sequence number ++ pBAEntry->Sequence = BA_ORI_INIT_SEQ; ++ // Set Bitmap flag. ++ pEntry->TXBAbitmap |= (1<ORIBATimer, &Cancelled); ++ ++ pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap, ++ pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue)); ++ ++ // SEND BAR ; ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - BAOriSessionAdd() allocate memory failed \n")); ++ return; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. ++ FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = pBAEntry->TID; // make sure sequence not clear in DEL funciton. ++ MakeOutgoingFrame(pOutBuffer2, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer2); ++ ++ ++ if (pBAEntry->ORIBATimer.TimerValue) ++ RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue); // in mSec ++ } ++} ++ ++BOOLEAN BARecSessionAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PFRAME_ADDBA_REQ pFrame) ++{ ++ BA_REC_ENTRY *pBAEntry = NULL; ++ BOOLEAN Status = TRUE; ++ BOOLEAN Cancelled; ++ USHORT Idx; ++ UCHAR TID; ++ UCHAR BAWinSize; ++ //UINT32 Value; ++ //UINT offset; ++ ++ ++ ASSERT(pEntry); ++ ++ // find TID ++ TID = pFrame->BaParm.TID; ++ ++ BAWinSize = min(((UCHAR)pFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ ++ // Intel patch ++ if (BAWinSize == 0) ++ { ++ BAWinSize = 64; ++ } ++ ++ Idx = pEntry->BARecWcidArray[TID]; ++ ++ ++ if (Idx == 0) ++ { ++ pBAEntry = BATableAllocRecEntry(pAd, &Idx); ++ } ++ else ++ { ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx, ++ pFrame->BaParm.BufSize, BAWinSize)); ++ ++ // Start fill in parameters. ++ if (pBAEntry != NULL) ++ { ++ ASSERT(pBAEntry->list.qlen == 0); ++ ++ pBAEntry->REC_BA_Status = Recipient_HandleRes; ++ pBAEntry->BAWinSize = BAWinSize; ++ pBAEntry->Wcid = pEntry->Aid; ++ pBAEntry->TID = TID; ++ pBAEntry->TimeOutValue = pFrame->TimeOutValue; ++ pBAEntry->REC_BA_Status = Recipient_Accept; ++ // initial sequence number ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; //pFrame->BaStartSeq.field.StartSeq; ++ ++ printk("Start Seq = %08x\n", pFrame->BaStartSeq.field.StartSeq); ++ ++ if (pEntry->RXBAbitmap & (1<RECBATimer, &Cancelled); ++ } ++ else ++ { ++ RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE); ++ } ++ ++#if 0 // for debugging ++ RTMPSetTimer(&pBAEntry->RECBATimer, REC_BA_SESSION_IDLE_TIMEOUT); ++#endif ++ ++ // Set Bitmap flag. ++ pEntry->RXBAbitmap |= (1<BARecWcidArray[TID] = Idx; ++ ++ pEntry->BADeclineBitmap &= ~(1<Aid, TID); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n", ++ pEntry->Aid, pEntry->RXBAbitmap, pEntry->BARecWcidArray[TID])); ++ } ++ else ++ { ++ Status = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE,("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n", ++ PRINT_MAC(pEntry->Addr), TID)); ++ } ++ return(Status); ++} ++ ++ ++BA_REC_ENTRY *BATableAllocRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx) ++{ ++ int i; ++ BA_REC_ENTRY *pBAEntry = NULL; ++ ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION) ++ { ++ printk("BA Recipeint Session (%ld) > %d\n", pAd->BATable.numAsRecipient, ++ MAX_BARECI_SESSION); ++ goto done; ++ } ++ ++ // reserve idx 0 to identify BAWcidArray[TID] as empty ++ for (i=1; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ pBAEntry =&pAd->BATable.BARecEntry[i]; ++ if ((pBAEntry->REC_BA_Status == Recipient_NONE)) ++ { ++ // get one ++ pAd->BATable.numAsRecipient++; ++ pBAEntry->REC_BA_Status = Recipient_USED; ++ *Idx = i; ++ break; ++ } ++ } ++ ++done: ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ return pBAEntry; ++} ++ ++BA_ORI_ENTRY *BATableAllocOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx) ++{ ++ int i; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE)) ++ { ++ goto done; ++ } ++ ++ // reserve idx 0 to identify BAWcidArray[TID] as empty ++ for (i=1; iBATable.BAOriEntry[i]; ++ if ((pBAEntry->ORI_BA_Status == Originator_NONE)) ++ { ++ // get one ++ pAd->BATable.numAsOriginator++; ++ pBAEntry->ORI_BA_Status = Originator_USED; ++ pBAEntry->pAdapter = pAd; ++ *Idx = i; ++ break; ++ } ++ } ++ ++done: ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ return pBAEntry; ++} ++ ++ ++VOID BATableFreeOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Idx) ++{ ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) ++ return; ++ ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ ++ if (pBAEntry->ORI_BA_Status != Originator_NONE) ++ { ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ pEntry->BAOriWcidArray[pBAEntry->TID] = 0; ++ ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ if (pBAEntry->ORI_BA_Status == Originator_Done) ++ { ++ pEntry->TXBAbitmap &= (~(1<<(pBAEntry->TID) )); ++ DBGPRINT(RT_DEBUG_TRACE, ("BATableFreeOriEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); ++ // Erase Bitmap flag. ++ } ++ ++ ASSERT(pAd->BATable.numAsOriginator != 0); ++ ++ pAd->BATable.numAsOriginator -= 1; ++ ++ pBAEntry->ORI_BA_Status = Originator_NONE; ++ pBAEntry->Token = 0; ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++ ++ ++VOID BATableFreeRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Idx) ++{ ++ BA_REC_ENTRY *pBAEntry = NULL; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE)) ++ return; ++ ++ pBAEntry =&pAd->BATable.BARecEntry[Idx]; ++ ++ if (pBAEntry->REC_BA_Status != Recipient_NONE) ++ { ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ pEntry->BARecWcidArray[pBAEntry->TID] = 0; ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ ASSERT(pAd->BATable.numAsRecipient != 0); ++ ++ pAd->BATable.numAsRecipient -= 1; ++ ++ pBAEntry->REC_BA_Status = Recipient_NONE; ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++ ++ ++VOID BAOriSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive, ++ IN BOOLEAN bForceSend) ++{ ++ ULONG Idx = 0; ++ BA_ORI_ENTRY *pBAEntry; ++ BOOLEAN Cancelled; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ { ++ return; ++ } ++ ++ // ++ // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). ++ // ++ Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID]; ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) ++ { ++ if (bForceSend == TRUE) ++ { ++ // force send specified TID DelBA ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = TID; ++ DelbaReq.Initiator = ORIGINATOR; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ ++ pBAEntry = &pAd->BATable.BAOriEntry[Idx]; ++ DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status)); ++ // ++ // Prepare DelBA action frame and send to the peer. ++ // ++ if ((bPassive == FALSE) && (TID == pBAEntry->TID) && (pBAEntry->ORI_BA_Status == Originator_Done)) ++ { ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = pBAEntry->TID; ++ DelbaReq.Initiator = ORIGINATOR; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); ++ BATableFreeOriEntry(pAd, Idx); ++ ++ if (bPassive) ++ { ++ //BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE); ++ } ++} ++ ++VOID BARecSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive) ++{ ++ ULONG Idx = 0; ++ BA_REC_ENTRY *pBAEntry; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ { ++ return; ++ } ++ ++ // ++ // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). ++ // ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx == 0) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ ++ ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->REC_BA_Status)); ++ // ++ // Prepare DelBA action frame and send to the peer. ++ // ++ if ((TID == pBAEntry->TID) && (pBAEntry->REC_BA_Status == Recipient_Accept)) ++ { ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ BOOLEAN Cancelled; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ //ULONG offset; ++ //UINT32 VALUE; ++ ++ RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled); ++ ++ // ++ // 1. Send DELBA Action Frame ++ // ++ if (bPassive == FALSE) ++ { ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = TID; ++ DelbaReq.Initiator = RECIPIENT; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ ++ ++ // ++ // 2. Free resource of BA session ++ // ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ // Erase Bitmap flag. ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; ++ pBAEntry->BAWinSize = 0; ++ // Erase Bitmap flag at software mactable ++ pAd->MacTab.Content[Wcid].RXBAbitmap &= (~(1<<(pBAEntry->TID))); ++ pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0; ++ ++ RT28XX_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID); ++ ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ ++ } ++ ++ BATableFreeRecEntry(pAd, Idx); ++} ++ ++VOID BASessionTearDownALL( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid) ++{ ++ int i; ++ ++ for (i=0; ipAdapter; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ ++ if ((pBAEntry->ORI_BA_Status == Originator_WaitRes) && (pBAEntry->Token < ORI_SESSION_MAX_RETRY)) ++ { ++ MLME_ADDBA_REQ_STRUCT AddbaReq; ++ ++ NdisZeroMemory(&AddbaReq, sizeof(AddbaReq)); ++ COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr); ++ AddbaReq.Wcid = (UCHAR)(pEntry->Aid); ++ AddbaReq.TID = pBAEntry->TID; ++ AddbaReq.BaBufSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; ++ AddbaReq.TimeOutValue = 0; ++ AddbaReq.Token = pBAEntry->Token; ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++ DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token)); ++ ++ pBAEntry->Token++; ++ RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT); ++ } ++ else ++ { ++ BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Retry sending ADDBA Reqest. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Parametrs: ++ p8023Header: if this is already 802.3 format, p8023Header is NULL ++ ++ Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. ++ FALSE , then continue indicaterx at this moment. ++ ========================================================================== ++ */ ++VOID BARecSessionIdleTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ++ BA_REC_ENTRY *pBAEntry = (BA_REC_ENTRY *)FunctionContext; ++ PRTMP_ADAPTER pAd; ++ ULONG Now32; ++ ++ if (pBAEntry == NULL) ++ return; ++ ++ if ((pBAEntry->REC_BA_Status == Recipient_Accept)) ++ { ++ NdisGetSystemUpTime(&Now32); ++ ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer + REC_BA_SESSION_IDLE_TIMEOUT))) ++ { ++ pAd = pBAEntry->pAdapter; ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ printk("%ld: REC BA session Timeout\n", Now32); ++ } ++ } ++} ++ ++ ++VOID PeerAddBAReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ // 7.4.4.1 ++ //ULONG Idx; ++ UCHAR Status = 1; ++ UCHAR pAddr[6]; ++ FRAME_ADDBA_RSP ADDframe; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ PFRAME_ADDBA_REQ pAddreqFrame = NULL; ++ //UCHAR BufSize; ++ ULONG FrameLen; ++ PULONG ptemp; ++ PMAC_TABLE_ENTRY pMacEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid)); ++ ++ //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); ++ ++ //ADDBA Request from unknown peer, ignore this. ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ pMacEntry = &pAd->MacTab.Content[Elem->Wcid]; ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerAddBAReqAction----> \n")); ++ ptemp = (PULONG)Elem->Msg; ++ //DBGPRINT_RAW(RT_DEBUG_EMU, ("%08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x\n", *(ptemp), *(ptemp+1), *(ptemp+2), *(ptemp+3), *(ptemp+4), *(ptemp+5), *(ptemp+6), *(ptemp+7), *(ptemp+8))); ++ ++ if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr)) ++ { ++ ++ if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry)) ++ { ++ pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); ++ printk("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid); ++ if (BARecSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pAddreqFrame)) ++ Status = 0; ++ else ++ Status = 38; // more parameters have invalid values ++ } ++ else ++ { ++ Status = 37; // the request has been declined. ++ } ++ } ++ ++ if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI) ++ ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC); ++ ++ pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); ++ // 2. Always send back ADDBA Response ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - PeerBAAction() allocate memory failed \n")); ++ return; ++ } ++ ++ NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP)); ++ // 2-1. Prepare ADDBA Response frame. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->MacTab.Content[Elem->Wcid].ValidAsDls) ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ADDframe.Category = CATEGORY_BA; ++ ADDframe.Action = ADDBA_RESP; ++ ADDframe.Token = pAddreqFrame->Token; ++ // What is the Status code?? need to check. ++ ADDframe.StatusCode = Status; ++ ADDframe.BaParm.BAPolicy = IMMED_BA; ++ ADDframe.BaParm.AMSDUSupported = 0; ++ ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID; ++ ADDframe.BaParm.BufSize = min(((UCHAR)pAddreqFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ if (ADDframe.BaParm.BufSize == 0) ++ { ++ ADDframe.BaParm.BufSize = 64; ++ } ++ ADDframe.TimeOutValue = 0; //pAddreqFrame->TimeOutValue; ++ ++ *(USHORT *)(&ADDframe.BaParm) = cpu2le16(*(USHORT *)(&ADDframe.BaParm)); ++ ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode); ++ ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ADDBA_RSP), &ADDframe, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID, ++ ADDframe.BaParm.BufSize)); ++} ++ ++ ++VOID PeerAddBARspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ //UCHAR Idx, i; ++ //PUCHAR pOutBuffer = NULL; ++ PFRAME_ADDBA_RSP pFrame = NULL; ++ //PBA_ORI_ENTRY pBAEntry; ++ ++ //ADDBA Response from unknown peer, ignore this. ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid)); ++ ++ //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); ++ ++ if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen)) ++ { ++ pFrame = (PFRAME_ADDBA_RSP)(&Elem->Msg[0]); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\t\t StatusCode = %d\n", pFrame->StatusCode)); ++ switch (pFrame->StatusCode) ++ { ++ case 0: ++ // I want a BAsession with this peer as an originator. ++ BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pFrame); ++ break; ++ default: ++ // check status == USED ??? ++ BAOriSessionTearDown(pAd, Elem->Wcid, pFrame->BaParm.TID, TRUE, FALSE); ++ break; ++ } ++ // Rcv Decline StatusCode ++ if ((pFrame->StatusCode == 37) ++#ifdef CONFIG_STA_SUPPORT ++ || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0)) ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<BaParm.TID; ++ } ++ } ++} ++ ++VOID PeerDelBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ //UCHAR Idx; ++ //PUCHAR pOutBuffer = NULL; ++ PFRAME_DELBA_REQ pDelFrame = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__)); ++ //DELBA Request from unknown peer, ignore this. ++ if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) ++ { ++ pDelFrame = (PFRAME_DELBA_REQ)(&Elem->Msg[0]); ++ if (pDelFrame->DelbaParm.Initiator == ORIGINATOR) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> ORIGINATOR\n")); ++ BARecSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n", pDelFrame->ReasonCode)); ++ //hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen); ++ BAOriSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE, FALSE); ++ } ++ } ++} ++ ++ ++BOOLEAN CntlEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG MsgLen, ++ IN PFRAME_BA_REQ pMsg) ++{ ++ PFRAME_BA_REQ pFrame = pMsg; ++ //PRTMP_REORDERBUF pBuffer; ++ //PRTMP_REORDERBUF pDmaBuf; ++ PBA_REC_ENTRY pBAEntry; ++ //BOOLEAN Result; ++ ULONG Idx; ++ //UCHAR NumRxPkt; ++ UCHAR TID;//, i; ++ ++ TID = (UCHAR)pFrame->BARControl.TID; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID)); ++ //hex_dump("BAR", (PCHAR) pFrame, MsgLen); ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return FALSE; ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ else if (MsgLen != sizeof(FRAME_BA_REQ)) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ else if (MsgLen != sizeof(FRAME_BA_REQ)) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ ++ if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8)) ++ { ++ // if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search. ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ } ++ else ++ { ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID, pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq )); ++ ++ if (SEQ_SMALLER(pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq, MAXSEQ)) ++ { ++ //printk("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq); ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, pFrame->BAStartingSeq.field.StartSeq); ++ pBAEntry->LastIndSeq = (pFrame->BAStartingSeq.field.StartSeq == 0) ? MAXSEQ :(pFrame->BAStartingSeq.field.StartSeq -1); ++ } ++ //ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ return TRUE; ++} ++ ++/* ++Description : Send PSMP Action frame If PSMP mode switches. ++*/ ++VOID SendPSMPAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Psmp) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ //ULONG Idx; ++ FRAME_PSMP_ACTION Frame; ++ ULONG FrameLen; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); ++#endif // CONFIG_STA_SUPPORT // ++ ++ Frame.Category = CATEGORY_HT; ++ Frame.Action = SMPS_ACTION; ++ switch (Psmp) ++ { ++ case MMPS_ENABLE: ++ Frame.Psmp = 0; ++ break; ++ case MMPS_DYNAMIC: ++ Frame.Psmp = 3; ++ break; ++ case MMPS_STATIC: ++ Frame.Psmp = 1; ++ break; ++ } ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_PSMP_ACTION), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR,("HT - SendPSMPAction( %d ) \n", Frame.Psmp)); ++} ++ ++ ++#define RADIO_MEASUREMENT_REQUEST_ACTION 0 ++ ++typedef struct PACKED ++{ ++ UCHAR RegulatoryClass; ++ UCHAR ChannelNumber; ++ USHORT RandomInterval; ++ USHORT MeasurementDuration; ++ UCHAR MeasurementMode; ++ UCHAR BSSID[MAC_ADDR_LEN]; ++ UCHAR ReportingCondition; ++ UCHAR Threshold; ++ UCHAR SSIDIE[2]; // 2 byte ++} BEACON_REQUEST; ++ ++typedef struct PACKED ++{ ++ UCHAR ID; ++ UCHAR Length; ++ UCHAR Token; ++ UCHAR RequestMode; ++ UCHAR Type; ++} MEASUREMENT_REQ; ++ ++ ++ ++ ++void convert_reordering_packet_to_preAMSDU_or_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNDIS_PACKET pRxPkt; ++ UCHAR Header802_3[LENGTH_802_3]; ++ ++ // 1. get 802.3 Header ++ // 2. remove LLC ++ // a. pointer pRxBlk->pData to payload ++ // b. modify pRxBlk->DataSize ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ASSERT(pRxBlk->pRxPacket); ++ pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ RTPKT_TO_OSPKT(pRxPkt)->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ RTPKT_TO_OSPKT(pRxPkt)->data = pRxBlk->pData; ++ RTPKT_TO_OSPKT(pRxPkt)->len = pRxBlk->DataSize; ++ RTPKT_TO_OSPKT(pRxPkt)->tail = RTPKT_TO_OSPKT(pRxPkt)->data + RTPKT_TO_OSPKT(pRxPkt)->len; ++ ++ // ++ // copy 802.3 header, if necessary ++ // ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef LINUX ++ NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); ++#endif ++#ifdef UCOS ++ NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); ++#endif ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++ ++#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID) \ ++ do \ ++ { \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU)) \ ++ { \ ++ Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP)) \ ++ { \ ++ Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ else \ ++ { \ ++ Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ } while (0); ++ ++ ++ ++static VOID ba_enqueue_reordering_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ UINT16 Sequence = (UINT16) pRxBlk->pHeader->Sequence; ++ ++ mpdu_blk = ba_mpdu_blk_alloc(pAd); ++ if (mpdu_blk != NULL) ++ { ++ // Write RxD buffer address & allocated buffer length ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ mpdu_blk->Sequence = Sequence; ++ ++ mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU); ++ ++ convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd, pRxBlk, FromWhichBSSID); ++ ++ STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); ++ ++ // ++ // it is necessary for reordering packet to record ++ // which BSS it come from ++ // ++ RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); ++ ++ mpdu_blk->pPacket = pRxBlk->pRxPacket; ++ ++ if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk) == FALSE) ++ { ++ // had been already within reordering list ++ // don't indicate ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_SUCCESS); ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ ++ ASSERT((0<= pBAEntry->list.qlen) && (pBAEntry->list.qlen <= pBAEntry->BAWinSize)); ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ } ++ else ++ { ++#if 0 ++ DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d:%d) Can't allocate reordering mpdu blk\n", ++ blk_count, pBAEntry->list.qlen)); ++#else ++ DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d) Can't allocate reordering mpdu blk\n", ++ pBAEntry->list.qlen)); ++#endif ++ /* ++ * flush all pending reordering mpdus ++ * and receving mpdu to upper layer ++ * make tcp/ip to take care reordering mechanism ++ */ ++ //ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); ++ ++ pBAEntry->LastIndSeq = Sequence; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Indicate this packet to upper layer or put it into reordering buffer ++ ++ Parametrs: ++ pRxBlk : carry necessary packet info 802.11 format ++ FromWhichBSSID : the packet received from which BSS ++ ++ Return : ++ none ++ ++ Note : ++ the packet queued into reordering buffer need to cover to 802.3 format ++ or pre_AMSDU format ++ ========================================================================== ++ */ ++ ++VOID Indicate_AMPDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ USHORT Idx; ++ PBA_REC_ENTRY pBAEntry = NULL; ++ UINT16 Sequence = pRxBlk->pHeader->Sequence; ++ ULONG Now32; ++ UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; ++ UCHAR TID = pRxBlk->pRxWI->TID; ++ ++ ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) ++ { ++#if 0 // sample take off, no use ++ static int err_size; ++ ++ err_size++; ++ if (err_size > 20) { ++ printk("AMPDU DataSize = %d\n", pRxBlk->DataSize); ++ hex_dump("802.11 Header", (UCHAR *)pRxBlk->pHeader, 24); ++ hex_dump("Payload", pRxBlk->pData, 64); ++ err_size = 0; ++ } ++#endif ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ++#if 0 // test ++ /* Rec BA Session had been torn down */ ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++#endif ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx == 0) ++ { ++ /* Rec BA Session had been torn down */ ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ } ++ else ++ { ++ // impossible !!! ++ ASSERT(0); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ASSERT(pBAEntry); ++ ++ // update last rx time ++ NdisGetSystemUpTime(&Now32); ++ ++ pBAEntry->rcvSeq = Sequence; ++ ++ ++ ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ ++ // ++ // Reset Last Indicate Sequence ++ // ++ if (pBAEntry->LastIndSeq == RESET_RCV_SEQ) ++ { ++ ASSERT((pBAEntry->list.qlen == 0) && (pBAEntry->list.next == NULL)); ++ ++ // reset rcv sequence of BA session ++ pBAEntry->LastIndSeq = Sequence; ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ ++ ++ // ++ // I. Check if in order. ++ // ++ if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) ++ { ++ USHORT LastIndSeq; ++ ++ pBAEntry->LastIndSeq = Sequence; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ LastIndSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); ++ if (LastIndSeq != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = LastIndSeq; ++ } ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++ // ++ // II. Drop Duplicated Packet ++ // ++ else if (Sequence == pBAEntry->LastIndSeq) ++ { ++ ++ // drop and release packet ++ pBAEntry->nDropPacket++; ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ // ++ // III. Drop Old Received Packet ++ // ++ else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) ++ { ++ ++ // drop and release packet ++ pBAEntry->nDropPacket++; ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ // ++ // IV. Receive Sequence within Window Size ++ // ++ else if (SEQ_SMALLER(Sequence, (((pBAEntry->LastIndSeq+pBAEntry->BAWinSize+1)) & MAXSEQ), MAXSEQ)) ++ { ++ ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); ++ } ++ // ++ // V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer ++ // ++ else ++ { ++#if 0 ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++#else ++ LONG WinStartSeq, TmpSeq; ++ ++ ++ TmpSeq = Sequence - (pBAEntry->BAWinSize) -1; ++ if (TmpSeq < 0) ++ { ++ TmpSeq = (MAXSEQ+1) + TmpSeq; ++ } ++ WinStartSeq = (TmpSeq+1) & MAXSEQ; ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq); ++ pBAEntry->LastIndSeq = WinStartSeq; //TmpSeq; ++ ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ ++ ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); ++ ++ TmpSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); ++ if (TmpSeq != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = TmpSeq; ++ } ++#endif ++ } ++} ++ ++#endif // DOT11_N_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/cmm_data_2870.c +@@ -0,0 +1,963 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++/* ++ All functions in this file must be USB-depended, or you should out your function ++ in other files. ++ ++*/ ++#include "../rt_config.h" ++ ++ ++/* ++ We can do copy the frame into pTxContext when match following conditions. ++ => ++ => ++ => ++*/ ++static inline NDIS_STATUS RtmpUSBCanDoWrite( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN HT_TX_CONTEXT *pHTTXContext) ++{ ++ NDIS_STATUS canWrite = NDIS_STATUS_RESOURCES; ++ ++ if (((pHTTXContext->CurWritePosition) < pHTTXContext->NextBulkOutPosition) && (pHTTXContext->CurWritePosition + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c1!\n")); ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); ++ } ++ else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < LOCAL_TXBUF_SIZE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c2!\n")); ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); ++ } ++ else if (pHTTXContext->bCurWriting == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c3!\n")); ++ } ++ else ++ { ++ canWrite = NDIS_STATUS_SUCCESS; ++ } ++ ++ ++ return canWrite; ++} ++ ++ ++USHORT RtmpUSB_WriteSubTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber) ++{ ++ ++ // Dummy function. Should be removed in the future. ++ return 0; ++ ++} ++ ++USHORT RtmpUSB_WriteFragTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR fragNum, ++ OUT USHORT *FreeNumber) ++{ ++ HT_TX_CONTEXT *pHTTXContext; ++ USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ PUCHAR pWirelessPacket = NULL; ++ UCHAR QueIdx; ++ NDIS_STATUS Status; ++ unsigned long IrqFlags; ++ UINT32 USBDMApktLen = 0, DMAHdrLen, padding; ++ BOOLEAN TxQLastRound = FALSE; ++ ++ // ++ // get Tx Ring Resource & Dma Buffer address ++ // ++ QueIdx = pTxBlk->QueIdx; ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ fillOffset = pHTTXContext->CurWritePosition; ++ ++ if(fragNum == 0) ++ { ++ // Check if we have enough space for this bulk-out batch. ++ Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ pHTTXContext->bCurWriting = TRUE; ++ ++ // Reserve space for 8 bytes padding. ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) ++ { ++ pHTTXContext->ENextBulkOutPosition += 8; ++ pHTTXContext->CurWritePosition += 8; ++ fillOffset += 8; ++ } ++ pTxBlk->Priv = 0; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return(Status); ++ } ++ } ++ else ++ { ++ // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. ++ Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ fillOffset += pTxBlk->Priv; ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return(Status); ++ } ++ } ++ ++ NdisZeroMemory((PUCHAR)(&pTxBlk->HeaderBuf[0]), TXINFO_SIZE); ++ pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); ++ pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); ++ ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ // copy TXWI + WLAN Header + LLC into DMA Header Buffer ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ // Build our URB for USBD ++ DMAHdrLen = TXWI_SIZE + hwHdrLen; ++ USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; ++ padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment ++ USBDMApktLen += padding; ++ ++ pTxBlk->Priv += (TXINFO_SIZE + USBDMApktLen); ++ ++ // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); ++ ++ if (fragNum == pTxBlk->TotalFragNum) ++ { ++ pTxInfo->USBDMATxburst = 0; ++ if ((pHTTXContext->CurWritePosition + pTxBlk->Priv + 3906)> MAX_TXBULK_LIMIT) ++ { ++ pTxInfo->SwUseLastRound = 1; ++ TxQLastRound = TRUE; ++ } ++ } ++ else ++ { ++ pTxInfo->USBDMATxburst = 1; ++ } ++ ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); ++ ++ // Zero the last padding. ++ pWirelessPacket += pTxBlk->SrcBufLen; ++ NdisZeroMemory(pWirelessPacket, padding + 8); ++ ++ if (fragNum == pTxBlk->TotalFragNum) ++ { ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ // Update the pHTTXContext->CurWritePosition. 3906 used to prevent the NextBulkOut is a A-RALINK/A-MSDU Frame. ++ pHTTXContext->CurWritePosition += pTxBlk->Priv; ++ if (TxQLastRound == TRUE) ++ pHTTXContext->CurWritePosition = 8; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ ++ // Finally, set bCurWriting as FALSE ++ pHTTXContext->bCurWriting = FALSE; ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ // succeed and release the skb buffer ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); ++ } ++ ++ ++ return(Status); ++ ++} ++ ++ ++USHORT RtmpUSB_WriteSingleTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber) ++{ ++ HT_TX_CONTEXT *pHTTXContext; ++ USHORT hwHdrLen; ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ PUCHAR pWirelessPacket; ++ UCHAR QueIdx; ++ unsigned long IrqFlags; ++ NDIS_STATUS Status; ++ UINT32 USBDMApktLen = 0, DMAHdrLen, padding; ++ BOOLEAN bTxQLastRound = FALSE; ++ ++ // For USB, didn't need PCI_MAP_SINGLE() ++ //SrcBufPA = PCI_MAP_SINGLE(pAd, (char *) pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, PCI_DMA_TODEVICE); ++ ++ ++ // ++ // get Tx Ring Resource & Dma Buffer address ++ // ++ QueIdx = pTxBlk->QueIdx; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ fillOffset = pHTTXContext->CurWritePosition; ++ ++ ++ ++ // Check ring full. ++ Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); ++ if(Status == NDIS_STATUS_SUCCESS) ++ { ++ pHTTXContext->bCurWriting = TRUE; ++ ++ pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); ++ pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); ++ ++ // Reserve space for 8 bytes padding. ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) ++ { ++ pHTTXContext->ENextBulkOutPosition += 8; ++ pHTTXContext->CurWritePosition += 8; ++ fillOffset += 8; ++ } ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ // copy TXWI + WLAN Header + LLC into DMA Header Buffer ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ // Build our URB for USBD ++ DMAHdrLen = TXWI_SIZE + hwHdrLen; ++ USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; ++ padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment ++ USBDMApktLen += padding; ++ ++ pTxBlk->Priv = (TXINFO_SIZE + USBDMApktLen); ++ ++ // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); ++ ++ if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > MAX_TXBULK_LIMIT) ++ { ++ pTxInfo->SwUseLastRound = 1; ++ bTxQLastRound = TRUE; ++ } ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ ++ // We unlock it here to prevent the first 8 bytes maybe over-writed issue. ++ // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxcontext. ++ // 2. An interrupt break our routine and handle bulk-out complete. ++ // 3. In the bulk-out compllete, it need to do another bulk-out, ++ // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, ++ // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. ++ // 4. Interrupt complete. ++ // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. ++ // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. ++ // and the packet will wrong. ++ pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); ++ pWirelessPacket += pTxBlk->SrcBufLen; ++ NdisZeroMemory(pWirelessPacket, padding + 8); ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ pHTTXContext->CurWritePosition += pTxBlk->Priv; ++ if (bTxQLastRound) ++ pHTTXContext->CurWritePosition = 8; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ pHTTXContext->bCurWriting = FALSE; ++ } ++ ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ ++ // succeed and release the skb buffer ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); ++ ++ return(Status); ++ ++} ++ ++ ++USHORT RtmpUSB_WriteMultiTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR frameNum, ++ OUT USHORT *FreeNumber) ++{ ++ HT_TX_CONTEXT *pHTTXContext; ++ USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ PUCHAR pWirelessPacket = NULL; ++ UCHAR QueIdx; ++ NDIS_STATUS Status; ++ unsigned long IrqFlags; ++ //UINT32 USBDMApktLen = 0, DMAHdrLen, padding; ++ ++ // ++ // get Tx Ring Resource & Dma Buffer address ++ // ++ QueIdx = pTxBlk->QueIdx; ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ if(frameNum == 0) ++ { ++ // Check if we have enough space for this bulk-out batch. ++ Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ pHTTXContext->bCurWriting = TRUE; ++ ++ pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); ++ pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); ++ ++ ++ // Reserve space for 8 bytes padding. ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) ++ { ++ ++ pHTTXContext->CurWritePosition += 8; ++ pHTTXContext->ENextBulkOutPosition += 8; ++ } ++ fillOffset = pHTTXContext->CurWritePosition; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ // ++ // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer ++ // ++ if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; ++ hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; ++ else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; ++ hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD; ++ else ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ // Update the pTxBlk->Priv. ++ pTxBlk->Priv = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; ++ ++ // pTxInfo->USBDMApktLen now just a temp value and will to correct latter. ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(pTxBlk->Priv), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); ++ ++ // Copy it. ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->Priv); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pHTTXContext->CurWriteRealPos += pTxBlk->Priv; ++ pWirelessPacket += pTxBlk->Priv; ++ } ++ } ++ else ++ { // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. ++ ++ Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ fillOffset = (pHTTXContext->CurWritePosition + pTxBlk->Priv); ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ //hwHdrLen = pTxBlk->MpduHeaderLen; ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->MpduHeaderLen); ++ pWirelessPacket += (pTxBlk->MpduHeaderLen); ++ pTxBlk->Priv += pTxBlk->MpduHeaderLen; ++ } ++ else ++ { // It should not happened now unless we are going to shutdown. ++ DBGPRINT(RT_DEBUG_ERROR, ("WriteMultiTxResource():bCurWriting is FALSE when handle sub-sequent frames.\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ } ++ ++ ++ // We unlock it here to prevent the first 8 bytes maybe over-write issue. ++ // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxContext. ++ // 2. An interrupt break our routine and handle bulk-out complete. ++ // 3. In the bulk-out compllete, it need to do another bulk-out, ++ // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, ++ // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. ++ // 4. Interrupt complete. ++ // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. ++ // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. ++ // and the packet will wrong. ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("WriteMultiTxResource: CWPos = %ld, NBOutPos = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); ++ goto done; ++ } ++ ++ // Copy the frame content into DMA buffer and update the pTxBlk->Priv ++ NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); ++ pWirelessPacket += pTxBlk->SrcBufLen; ++ pTxBlk->Priv += pTxBlk->SrcBufLen; ++ ++done: ++ // Release the skb buffer here ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); ++ ++ return(Status); ++ ++} ++ ++ ++VOID RtmpUSB_FinalWriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN USHORT totalMPDUSize, ++ IN USHORT TxIdx) ++{ ++ UCHAR QueIdx; ++ HT_TX_CONTEXT *pHTTXContext; ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ UINT32 USBDMApktLen, padding; ++ unsigned long IrqFlags; ++ PUCHAR pWirelessPacket; ++ ++ QueIdx = pTxBlk->QueIdx; ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ if (pHTTXContext->bCurWriting == TRUE) ++ { ++ fillOffset = pHTTXContext->CurWritePosition; ++ if (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) ++ && (pHTTXContext->bCopySavePad == TRUE)) ++ pWirelessPacket = (PUCHAR)(&pHTTXContext->SavedPad[0]); ++ else ++ pWirelessPacket = (PUCHAR)(&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]); ++ ++ // ++ // Update TxInfo->USBDMApktLen , ++ // the length = TXWI_SIZE + 802.11_hdr + 802.11_hdr_pad + payload_of_all_batch_frames + Bulk-Out-padding ++ // ++ pTxInfo = (PTXINFO_STRUC)(pWirelessPacket); ++ ++ // Calculate the bulk-out padding ++ USBDMApktLen = pTxBlk->Priv - TXINFO_SIZE; ++ padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment ++ USBDMApktLen += padding; ++ ++ pTxInfo->USBDMATxPktLen = USBDMApktLen; ++ ++ // ++ // Update TXWI->MPDUtotalByteCount , ++ // the length = 802.11 header + payload_of_all_batch_frames ++ pTxWI= (PTXWI_STRUC)(pWirelessPacket + TXINFO_SIZE); ++ pTxWI->MPDUtotalByteCount = totalMPDUSize; ++ ++ // ++ // Update the pHTTXContext->CurWritePosition ++ // ++ pHTTXContext->CurWritePosition += (TXINFO_SIZE + USBDMApktLen); ++ if ((pHTTXContext->CurWritePosition + 3906)> MAX_TXBULK_LIMIT) ++ { // Add 3906 for prevent the NextBulkOut packet size is a A-RALINK/A-MSDU Frame. ++ pHTTXContext->CurWritePosition = 8; ++ pTxInfo->SwUseLastRound = 1; ++ } ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ ++ // ++ // Zero the last padding. ++ // ++ pWirelessPacket = (&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset + pTxBlk->Priv]); ++ NdisZeroMemory(pWirelessPacket, padding + 8); ++ ++ // Finally, set bCurWriting as FALSE ++ pHTTXContext->bCurWriting = FALSE; ++ ++ } ++ else ++ { // It should not happened now unless we are going to shutdown. ++ DBGPRINT(RT_DEBUG_ERROR, ("FinalWriteTxResource():bCurWriting is FALSE when handle last frames.\n")); ++ } ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++} ++ ++ ++VOID RtmpUSBDataLastTxIdx( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN USHORT TxIdx) ++{ ++ // DO nothing for USB. ++} ++ ++ ++/* ++ When can do bulk-out: ++ 1. TxSwFreeIdx < TX_RING_SIZE; ++ It means has at least one Ring entity is ready for bulk-out, kick it out. ++ 2. If TxSwFreeIdx == TX_RING_SIZE ++ Check if the CurWriting flag is FALSE, if it's FALSE, we can do kick out. ++ ++*/ ++VOID RtmpUSBDataKickOut( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx) ++{ ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++/* ++ Must be run in Interrupt context ++ This function handle RT2870 specific TxDesc and cpu index update and kick the packet out. ++ */ ++int RtmpUSBMgmtKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pSrcBufVA, ++ IN UINT SrcBufLen) ++{ ++ PTXINFO_STRUC pTxInfo; ++ ULONG BulkOutSize; ++ UCHAR padLen; ++ PUCHAR pDest; ++ ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; ++ PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[SwIdx].AllocVa; ++ unsigned long IrqFlags; ++ ++ ++ pTxInfo = (PTXINFO_STRUC)(pSrcBufVA); ++ ++ // Build our URB for USBD ++ BulkOutSize = SrcBufLen; ++ BulkOutSize = (BulkOutSize + 3) & (~3); ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(BulkOutSize - TXINFO_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ ++ BulkOutSize += 4; // Always add 4 extra bytes at every packet. ++ ++ // If BulkOutSize is multiple of BulkOutMaxPacketSize, add extra 4 bytes again. ++ if ((BulkOutSize % pAd->BulkOutMaxPacketSize) == 0) ++ BulkOutSize += 4; ++ ++ padLen = BulkOutSize - SrcBufLen; ++ ASSERT((padLen <= RTMP_PKT_TAIL_PADDING)); ++ ++ // Now memzero all extra padding bytes. ++ pDest = (PUCHAR)(pSrcBufVA + SrcBufLen); ++ skb_put(GET_OS_PKT_TYPE(pPacket), padLen); ++ NdisZeroMemory(pDest, padLen); ++ ++ RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ pAd->MgmtRing.Cell[pAd->MgmtRing.TxCpuIdx].pNdisPacket = pPacket; ++ pMLMEContext->TransferBuffer = (PTX_BUFFER)(GET_OS_PKT_DATAPTR(pPacket)); ++ ++ // Length in TxInfo should be 8 less than bulkout size. ++ pMLMEContext->BulkOutSize = BulkOutSize; ++ pMLMEContext->InUse = TRUE; ++ pMLMEContext->bWaitingBulkOut = TRUE; ++ ++ ++ //for debug ++ //hex_dump("RtmpUSBMgmtKickOut", &pMLMEContext->TransferBuffer->field.WirelessPacket[0], (pMLMEContext->BulkOutSize > 16 ? 16 : pMLMEContext->BulkOutSize)); ++ ++ //pAd->RalinkCounters.KickTxCount++; ++ //pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ //if (pAd->MgmtRing.TxSwFreeIdx == MGMT_RING_SIZE) ++ // needKickOut = TRUE; ++ ++ // Decrease the TxSwFreeIdx and Increase the TX_CTX_IDX ++ pAd->MgmtRing.TxSwFreeIdx--; ++ INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); ++ ++ RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ //if (needKickOut) ++ RTUSBKickBulkOut(pAd); ++ ++ return 0; ++} ++ ++ ++VOID RtmpUSBNullFrameKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR *pNullFrame, ++ IN UINT32 frameLen) ++{ ++ if (pAd->NullContext.InUse == FALSE) ++ { ++ PTX_CONTEXT pNullContext; ++ PTXINFO_STRUC pTxInfo; ++ PTXWI_STRUC pTxWI; ++ PUCHAR pWirelessPkt; ++ ++ pNullContext = &(pAd->NullContext); ++ ++ // Set the in use bit ++ pNullContext->InUse = TRUE; ++ pWirelessPkt = (PUCHAR)&pNullContext->TransferBuffer->field.WirelessPacket[0]; ++ ++ RTMPZeroMemory(&pWirelessPkt[0], 100); ++ pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[0]; ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxInfo->QSEL = FIFO_EDCA; ++ pTxWI = (PTXWI_STRUC)&pWirelessPkt[TXINFO_SIZE]; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), ++ 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)&pWirelessPkt[TXINFO_SIZE + TXWI_SIZE], DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; ++ ++ // Fill out frame length information for global Bulk out arbitor ++ //pNullContext->BulkOutSize = TransferBufferLength; ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - send NULL Frame @%d Mbps...\n", RateIdToMbps[pAd->CommonCfg.TxRate])); ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); ++ ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ } ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound ++ ++ Arguments: ++ pRxD Pointer to the Rx descriptor ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS No err ++ NDIS_STATUS_FAILURE Error ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxINFO) ++{ ++ PCIPHER_KEY pWpaKey; ++ INT dBm; ++ ++ if (pAd->bPromiscuous == TRUE) ++ return(NDIS_STATUS_SUCCESS); ++ if(pRxINFO == NULL) ++ return(NDIS_STATUS_FAILURE); ++ ++ // Phy errors & CRC errors ++ if (pRxINFO->Crc) ++ { ++ // Check RSSI for Noise Hist statistic collection. ++ dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; ++ if (dBm <= -87) ++ pAd->StaCfg.RPIDensity[0] += 1; ++ else if (dBm <= -82) ++ pAd->StaCfg.RPIDensity[1] += 1; ++ else if (dBm <= -77) ++ pAd->StaCfg.RPIDensity[2] += 1; ++ else if (dBm <= -72) ++ pAd->StaCfg.RPIDensity[3] += 1; ++ else if (dBm <= -67) ++ pAd->StaCfg.RPIDensity[4] += 1; ++ else if (dBm <= -62) ++ pAd->StaCfg.RPIDensity[5] += 1; ++ else if (dBm <= -57) ++ pAd->StaCfg.RPIDensity[6] += 1; ++ else if (dBm > -57) ++ pAd->StaCfg.RPIDensity[7] += 1; ++ ++ return(NDIS_STATUS_FAILURE); ++ } ++ ++ // Add Rx size to channel load counter, we should ignore error counts ++ pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount+ 14); ++ ++ // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics ++ if (pHeader->FC.ToDs) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n")); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // Paul 04-03 for OFDM Rx length issue ++ if (pRxWI->MPDUtotalByteCount > MAX_AGGREGATION_SIZE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // Drop not U2M frames, cant's drop here because we will drop beacon in this case ++ // I am kind of doubting the U2M bit operation ++ // if (pRxD->U2M == 0) ++ // return(NDIS_STATUS_FAILURE); ++ ++ // drop decyption fail frame ++ if (pRxINFO->Decrypted && pRxINFO->CipherErr) ++ { ++ ++ // ++ // MIC Error ++ // ++ if ((pRxINFO->CipherErr == 2) && pRxINFO->MyBss) ++ { ++ pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; ++ RTMPReportMicError(pAd, pWpaKey); ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n")); ++ } ++ ++ if (pRxINFO->Decrypted && ++ (pAd->SharedKey[BSS0][pRxWI->KeyIndex].CipherAlg == CIPHER_AES) && ++ (pHeader->Sequence == pAd->FragFrame.Sequence)) ++ { ++ // ++ // Acceptable since the First FragFrame no CipherErr problem. ++ // ++ return(NDIS_STATUS_SUCCESS); ++ } ++ ++ return(NDIS_STATUS_FAILURE); ++ } ++ ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++VOID RT28xxUsbStaAsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx) ++{ ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00); ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++} ++ ++VOID RT28xxUsbStaAsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ ++ // we have decided to SLEEP, so at least do it for a BEACON period. ++ if (TbttNumToNextWakeUp == 0) ++ TbttNumToNextWakeUp = 1; ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1; ++ AutoWakeupCfg.field.EnableAutoWakeup = 1; ++ AutoWakeupCfg.field.AutoLeadTime = 5; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); // send POWER-SAVE command to MCU. Timeout 40us. ++ ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RT28xxUsbMlmeRadioOn( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOn()\n")); ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00); ++ RTMPusecDelay(10000); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ NICResetFromError(pAd); ++ ++ // Enable Tx/Rx ++ RTMPEnableRxTx(pAd); ++ ++ // Clear Radio off flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTUSBBulkReceive(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_ON); ++} ++ ++VOID RT28xxUsbMlmeRadioOFF( ++ IN PRTMP_ADAPTER pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ UINT32 Value, i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOFF()\n")); ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_OFF); ++ // Set Radio off flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Link down first if any association exists ++ if (INFRA_ON(pAd) || ADHOC_ON(pAd)) ++ LinkDown(pAd, FALSE); ++ RTMPusecDelay(10000); ++ ++ //========================================== ++ // Clean up old bss table ++ BssTableInit(&pAd->ScanTab); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ // Disable MAC Tx/Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= (0xfffffff3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // MAC_SYS_CTRL => value = 0x0 => 40mA ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0); ++ ++ // PWR_PIN_CFG => value = 0x0 => 40mA ++ RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0); ++ ++ // TX_PIN_CFG => value = 0x0 => 20mA ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0); ++ ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ // Must using 40MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); ++ } ++ ++ // Waiting for DMA idle ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ }while (i++ < 100); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); ++#endif // CONFIG_STA_SUPPORT // ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/cmm_data.c +@@ -0,0 +1,2734 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#include "../rt_config.h" ++ ++#define MAX_TX_IN_TBTT (16) ++ ++ ++UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; ++// Add Cisco Aironet SNAP heade for CCX2 support ++UCHAR SNAP_AIRONET[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00}; ++UCHAR CKIP_LLC_SNAP[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; ++UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e}; ++UCHAR EAPOL[] = {0x88, 0x8e}; ++UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */ ++ ++UCHAR IPX[] = {0x81, 0x37}; ++UCHAR APPLE_TALK[] = {0x80, 0xf3}; ++UCHAR RateIdToPlcpSignal[12] = { ++ 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec ++ 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14 ++ 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14 ++ ++UCHAR OfdmSignalToRateId[16] = { ++ RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively ++ RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively ++ RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively ++ RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively ++}; ++ ++UCHAR OfdmRateToRxwiMCS[12] = { ++ 0, 0, 0, 0, ++ 0, 1, 2, 3, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 ++ 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 ++}; ++UCHAR RxwiMCSToOfdmRate[12] = { ++ RATE_6, RATE_9, RATE_12, RATE_18, ++ RATE_24, RATE_36, RATE_48, RATE_54, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 ++ 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 ++}; ++ ++char* MCSToMbps[] = {"1Mbps","2Mbps","5.5Mbps","11Mbps","06Mbps","09Mbps","12Mbps","18Mbps","24Mbps","36Mbps","48Mbps","54Mbps","MM-0","MM-1","MM-2","MM-3","MM-4","MM-5","MM-6","MM-7","MM-8","MM-9","MM-10","MM-11","MM-12","MM-13","MM-14","MM-15","MM-32","ee1","ee2","ee3"}; ++ ++UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2}; ++//UCHAR default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1}; ++UCHAR default_sta_aifsn[]={3,7,2,2}; ++ ++UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO}; ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ API for MLME to transmit management frame to AP (BSS Mode) ++ or station (IBSS Mode) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the outgoing 802.11 frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MiniportMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length) ++{ ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ULONG FreeNum; ++ UCHAR IrqState; ++ UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; ++ ++ ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); ++ ++ QueIdx=3; ++ ++ // 2860C use Tx Ring ++ ++ IrqState = pAd->irq_disabled; ++ ++ do ++ { ++ // Reset is in progress, stop immediately ++ if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| ++ !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ break; ++ } ++ ++ // Check Free priority queue ++ // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. ++ ++ // 2860C use Tx Ring ++ if (pAd->MACVersion == 0x28600100) ++ { ++ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); ++ } ++ else ++ { ++ FreeNum = GET_MGMTRING_FREENO(pAd); ++ } ++ ++ if ((FreeNum > 0)) ++ { ++ // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 ++ NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); ++ break; ++ } ++ ++ //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ //pAd->CommonCfg.MlmeRate = RATE_2; ++ ++ ++ Status = MlmeHardTransmit(pAd, QueIdx, pPacket); ++ if (Status != NDIS_STATUS_SUCCESS) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ } ++ else ++ { ++ pAd->RalinkCounters.MgmtRingFullCount++; ++ DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", ++ QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); ++ } ++ ++ } while (FALSE); ++ ++ ++ return Status; ++} ++ ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware transmit function ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuffer Pointer to memory of outgoing frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++#ifdef CARRIER_DETECTION_SUPPORT ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); ++ ++} ++ ++ ++ ++NDIS_STATUS MlmeHardTransmitMgmtRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PHEADER_802_11 pHeader_802_11; ++ BOOLEAN bAckRequired, bInsertTimestamp; ++ UCHAR MlmeRate; ++ PTXWI_STRUC pFirstTxWI; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ // Make sure MGMT ring resource won't be used by other threads ++// sample, for IRQ LOCK -> SEM LOCK ++// IrqState = pAd->irq_disabled; ++// if (!IrqState) ++ RTMP_SEM_LOCK(&pAd->MgmtRingLock); ++ ++ ++ if (pSrcBufVA == NULL) ++ { ++ // The buffer shouldn't be NULL ++// if (!IrqState) ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // outgoing frame always wakeup PHY to prevent frame lost ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE); ++ pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE); ++ ++ if (pHeader_802_11->Addr1[0] & 0x01) ++ { ++ MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ } ++ else ++ { ++ MlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ // Verify Mlme rate for a / g bands. ++ if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band ++ MlmeRate = RATE_6; ++ ++ if ((pHeader_802_11->FC.Type == BTYPE_DATA) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) ++ { ++ pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. ++ if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED ++#ifdef DOT11_N_SUPPORT ++ || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ if (pAd->LatchRfRegs.Channel > 14) ++ pAd->CommonCfg.MlmeTransmit.field.MODE = 1; ++ else ++ pAd->CommonCfg.MlmeTransmit.field.MODE = 0; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) ++ // Snice it's been set to 0 while on MgtMacHeaderInit ++ // By the way this will cause frame to be send on PWR_SAVE failed. ++ // ++ // pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE); ++ // ++ // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame ++#ifdef CONFIG_STA_SUPPORT ++ // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD ++ if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) ++ { ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ bInsertTimestamp = FALSE; ++ if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL ++ { ++#ifdef CONFIG_STA_SUPPORT ++ //Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue. ++ if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ bAckRequired = FALSE; ++ } ++ else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) ++ { ++ //pAd->Sequence++; ++ //pHeader_802_11->Sequence = pAd->Sequence; ++ ++ if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST ++ { ++ bAckRequired = FALSE; ++ pHeader_802_11->Duration = 0; ++ } ++ else ++ { ++ bAckRequired = TRUE; ++ pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); ++ if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) ++ { ++ bInsertTimestamp = TRUE; ++ } ++ } ++ } ++ ++ pHeader_802_11->Sequence = pAd->Sequence++; ++ if (pAd->Sequence >0xfff) ++ pAd->Sequence = 0; ++ ++ // Before radar detection done, mgmt frame can not be sent but probe req ++ // Because we need to use probe req to trigger driver to send probe req in passive scan ++ if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); ++// if (!IrqState) ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); ++#endif ++ ++ // ++ // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET ++ // should always has only one ohysical buffer, and the whole frame size equals ++ // to the first scatter buffer size ++ // ++ ++ // Initialize TX Descriptor ++ // For inter-frame gap, the number is for this frame and next frame ++ // For MLME rate, we will fix as 2Mb to match other vendor's implement ++// pAd->CommonCfg.MlmeTransmit.field.MODE = 1; ++ ++// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. ++ if (pMacEntry == NULL) ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, RESERVED_WCID, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, ++ bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, pMacEntry->Aid, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), ++ pMacEntry->MaxHTPhyMode.field.MCS, 0, ++ (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, ++ IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); ++#endif ++ ++ // Now do hardware-depened kick out. ++ HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); ++ ++ // Make sure to release MGMT ring resource ++// if (!IrqState) ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++/******************************************************************************** ++ ++ New DeQueue Procedures. ++ ++ ********************************************************************************/ ++ ++#define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \ ++ do{ \ ++ if (bIntContext == FALSE) \ ++ RTMP_IRQ_LOCK((lock), IrqFlags); \ ++ }while(0) ++ ++#define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \ ++ do{ \ ++ if (bIntContext == FALSE) \ ++ RTMP_IRQ_UNLOCK((lock), IrqFlags); \ ++ }while(0) ++ ++ ++#if 0 ++static VOID dumpTxBlk(TX_BLK *pTxBlk) ++{ ++ NDIS_PACKET *pPacket; ++ int i, frameNum; ++ PQUEUE_ENTRY pQEntry; ++ ++ printk("Dump TX_BLK Structure:\n"); ++ printk("\tTxFrameType=%d!\n", pTxBlk->TxFrameType); ++ printk("\tTotalFrameLen=%d\n", pTxBlk->TotalFrameLen); ++ printk("\tTotalFrameNum=%ld!\n", pTxBlk->TxPacketList.Number); ++ printk("\tTotalFragNum=%d!\n", pTxBlk->TotalFragNum); ++ printk("\tpPacketList=\n"); ++ ++ frameNum = pTxBlk->TxPacketList.Number; ++ ++ for(i=0; i < frameNum; i++) ++ { int j; ++ UCHAR *pBuf; ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (pPacket) ++ { ++ pBuf = GET_OS_PKT_DATAPTR(pPacket); ++ printk("\t\t[%d]:ptr=0x%x, Len=%d!\n", i, (UINT32)(GET_OS_PKT_DATAPTR(pPacket)), GET_OS_PKT_LEN(pPacket)); ++ printk("\t\t"); ++ for (j =0 ; j < GET_OS_PKT_LEN(pPacket); j++) ++ { ++ printk("%02x ", (pBuf[j] & 0xff)); ++ if (j == 16) ++ break; ++ } ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ } ++ } ++ printk("\tWcid=%d!\n", pTxBlk->Wcid); ++ printk("\tapidx=%d!\n", pTxBlk->apidx); ++ printk("----EndOfDump\n"); ++ ++} ++#endif ++ ++ ++/* ++ ======================================================================== ++ Tx Path design algorithm: ++ Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal), ++ Specific Packet Type. Following show the classification rule and policy for each kinds of packets. ++ Classification Rule=> ++ Multicast: (*addr1 & 0x01) == 0x01 ++ Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc. ++ 11N Rate : If peer support HT ++ (1).AMPDU -- If TXBA is negotiated. ++ (2).AMSDU -- If AMSDU is capable for both peer and ourself. ++ *). AMSDU can embedded in a AMPDU, but now we didn't support it. ++ (3).Normal -- Other packets which send as 11n rate. ++ ++ B/G Rate : If peer is b/g only. ++ (1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6 ++ (2).Normal -- Other packets which send as b/g rate. ++ Fragment: ++ The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment. ++ ++ Classified Packet Handle Rule=> ++ Multicast: ++ No ACK, //pTxBlk->bAckRequired = FALSE; ++ No WMM, //pTxBlk->bWMM = FALSE; ++ No piggyback, //pTxBlk->bPiggyBack = FALSE; ++ Force LowRate, //pTxBlk->bForceLowRate = TRUE; ++ Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use ++ the same policy to handle it. ++ Force LowRate, //pTxBlk->bForceLowRate = TRUE; ++ ++ 11N Rate : ++ No piggyback, //pTxBlk->bPiggyBack = FALSE; ++ ++ (1).AMSDU ++ pTxBlk->bWMM = TRUE; ++ (2).AMPDU ++ pTxBlk->bWMM = TRUE; ++ (3).Normal ++ ++ B/G Rate : ++ (1).ARALINK ++ ++ (2).Normal ++ ======================================================================== ++*/ ++static UCHAR TxPktClassification( ++ IN RTMP_ADAPTER *pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ UCHAR TxFrameType = TX_UNKOWN_FRAME; ++ UCHAR Wcid; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bHTRate = FALSE; ++#endif // DOT11_N_SUPPORT // ++ ++ Wcid = RTMP_GET_PACKET_WCID(pPacket); ++ if (Wcid == MCAST_WCID) ++ { // Handle for RA is Broadcast/Multicast Address. ++ return TX_MCAST_FRAME; ++ } ++ ++ // Handle for unicast packets ++ pMacEntry = &pAd->MacTab.Content[Wcid]; ++ if (RTMP_GET_PACKET_LOWRATE(pPacket)) ++ { // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++#ifdef DOT11_N_SUPPORT ++ else if (IS_HT_RATE(pMacEntry)) ++ { // it's a 11n capable packet ++ ++ // Depends on HTPhyMode to check if the peer support the HTRate transmission. ++ // Currently didn't support A-MSDU embedded in A-MPDU ++ bHTRate = TRUE; ++ if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE)) ++ TxFrameType = TX_LEGACY_FRAME; ++#ifdef UAPSD_AP_SUPPORT ++ else if (RTMP_GET_PACKET_EOSP(pPacket)) ++ TxFrameType = TX_LEGACY_FRAME; ++#endif // UAPSD_AP_SUPPORT // ++ else if((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0) ++ return TX_AMPDU_FRAME; ++ else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED)) ++ return TX_AMSDU_FRAME; ++ else ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++#endif // DOT11_N_SUPPORT // ++ else ++ { // it's a legacy b/g packet. ++ if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && ++ (RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) && ++ (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) ++ { // if peer support Ralink Aggregation, we use it. ++ TxFrameType = TX_RALINK_FRAME; ++ } ++ else ++ { ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++ } ++ ++ // Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU. ++ if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME)) ++ TxFrameType = TX_FRAG_FRAME; ++ ++ return TxFrameType; ++} ++ ++ ++BOOLEAN RTMP_FillTxBlkInfo( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PACKET_INFO PacketInfo; ++ PNDIS_PACKET pPacket; ++ PMAC_TABLE_ENTRY pMacEntry = NULL; ++ ++ pPacket = pTxBlk->pPacket; ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); ++ ++ pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); ++ pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket); ++ pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); ++ pTxBlk->FrameGap = IFS_HTTXOP; // ASIC determine Frame Gap ++ ++ if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); ++ else ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); ++ ++ // Default to clear this flag ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS); ++ ++ ++ if (pTxBlk->Wcid == MCAST_WCID) ++ { ++ pTxBlk->pMacEntry = NULL; ++ { ++#ifdef MCAST_RATE_SPECIFIC ++ PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); ++ if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff)) ++ pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode; ++ else ++#endif // MCAST_RATE_SPECIFIC // ++ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; ++ } ++ ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); // AckRequired = FALSE, when broadcast packet in Adhoc mode. ++ //TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate); ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag); ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); ++ if (RTMP_GET_PACKET_MOREDATA(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); ++ } ++ ++ } ++ else ++ { ++ pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; ++ pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; ++ ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ ++ // For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK. ++ if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); ++ else ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); ++ ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ // If support WMM, enable it. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) ++ { ++ if ( (RTMP_GET_PACKET_LOWRATE(pPacket)) || ++ ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1))) ++ { // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. ++ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; ++#ifdef DOT11_N_SUPPORT ++ // Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it??? ++ if (IS_HT_STA(pTxBlk->pMacEntry) && ++ (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && ++ ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))) ++ { ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ( (IS_HT_RATE(pMacEntry) == FALSE) && ++ (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) ++ { // Currently piggy-back only support when peer is operate in b/g mode. ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (RTMP_GET_PACKET_MOREDATA(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); ++ } ++#ifdef UAPSD_AP_SUPPORT ++ if (RTMP_GET_PACKET_EOSP(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP); ++ } ++#endif // UAPSD_AP_SUPPORT // ++ } ++ else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); ++ } ++ ++ pMacEntry->DebugTxCount++; ++ } ++ ++ return TRUE; ++ ++FillTxBlkErr: ++ return FALSE; ++} ++ ++ ++BOOLEAN CanDoAggregateTransmit( ++ IN RTMP_ADAPTER *pAd, ++ IN NDIS_PACKET *pPacket, ++ IN TX_BLK *pTxBlk) ++{ ++ ++ //printk("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType); ++ ++ if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID) ++ return FALSE; ++ ++ if (RTMP_GET_PACKET_DHCP(pPacket) || ++ RTMP_GET_PACKET_EAPOL(pPacket) || ++ RTMP_GET_PACKET_WAI(pPacket)) ++ return FALSE; ++ ++ if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) && ++ ((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100))) ++ { // For AMSDU, allow the packets with total length < max-amsdu size ++ return FALSE; ++ } ++ ++ if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) && ++ (pTxBlk->TxPacketList.Number == 2)) ++ { // For RALINK-Aggregation, allow two frames in one batch. ++ return FALSE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP ++ return TRUE; ++ else ++#endif // CONFIG_STA_SUPPORT // ++ return FALSE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ To do the enqueue operation and extract the first item of waiting ++ list. If a number of available shared memory segments could meet ++ the request of extracted item, the extracted item will be fragmented ++ into shared memory segments. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pQueue Pointer to Waiting Queue ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPDeQueuePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bIntContext, ++ IN UCHAR QIdx, /* BulkOutPipeId */ ++ IN UCHAR Max_Tx_Packets) ++{ ++ PQUEUE_ENTRY pEntry = NULL; ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ UCHAR Count=0; ++ PQUEUE_HEADER pQueue; ++ ULONG FreeNumber[NUM_OF_TX_RING]; ++ UCHAR QueIdx, sQIdx, eQIdx; ++ unsigned long IrqFlags = 0; ++ BOOLEAN hasTxDesc = FALSE; ++ TX_BLK TxBlk; ++ TX_BLK *pTxBlk; ++ ++#ifdef DBG_DIAGNOSE ++ BOOLEAN firstRound; ++ RtmpDiagStruct *pDiagStruct = &pAd->DiagStruct; ++#endif ++ ++ ++ if (QIdx == NUM_OF_TX_RING) ++ { ++ sQIdx = 0; ++ eQIdx = 3; // 4 ACs, start from 0. ++ } ++ else ++ { ++ sQIdx = eQIdx = QIdx; ++ } ++ ++ for (QueIdx=sQIdx; QueIdx <= eQIdx; QueIdx++) ++ { ++ Count=0; ++ ++ RT28XX_START_DEQUEUE(pAd, QueIdx, IrqFlags); ++ ++#ifdef DBG_DIAGNOSE ++ firstRound = ((QueIdx == 0) ? TRUE : FALSE); ++#endif // DBG_DIAGNOSE // ++ ++ while (1) ++ { ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); ++ return; ++ } ++ ++ if (Count >= Max_Tx_Packets) ++ break; ++ ++ DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ if (&pAd->TxSwQueue[QueIdx] == NULL) ++ { ++#ifdef DBG_DIAGNOSE ++ if (firstRound == TRUE) ++ pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][0]++; ++#endif // DBG_DIAGNOSE // ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ ++ // probe the Queue Head ++ pQueue = &pAd->TxSwQueue[QueIdx]; ++ if ((pEntry = pQueue->Head) == NULL) ++ { ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ pTxBlk = &TxBlk; ++ NdisZeroMemory((PUCHAR)pTxBlk, sizeof(TX_BLK)); ++ //InitializeQueueHeader(&pTxBlk->TxPacketList); // Didn't need it because we already memzero it. ++ pTxBlk->QueIdx = QueIdx; ++ ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ ++ // Early check to make sure we have enoguh Tx Resource. ++ hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); ++ if (!hasTxDesc) ++ { ++ pAd->PrivateInfo.TxRingFullCnt++; ++ ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ ++ break; ++ } ++ ++ pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket); ++ pEntry = RemoveHeadQueue(pQueue); ++ pTxBlk->TotalFrameNum++; ++ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary ++ pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); ++ pTxBlk->pPacket = pPacket; ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ ++ if (pTxBlk->TxFrameType == TX_RALINK_FRAME || pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ { ++ // Enhance SW Aggregation Mechanism ++ if (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, FreeNumber[QueIdx], pTxBlk->TxFrameType)) ++ { ++ InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ do{ ++ if((pEntry = pQueue->Head) == NULL) ++ break; ++ ++ // For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); ++ hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); ++ if ((hasTxDesc == FALSE) || (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE)) ++ break; ++ ++ //Remove the packet from the TxSwQueue and insert into pTxBlk ++ pEntry = RemoveHeadQueue(pQueue); ++ ASSERT(pEntry); ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ pTxBlk->TotalFrameNum++; ++ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary ++ pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ }while(1); ++ ++ if (pTxBlk->TxPacketList.Number == 1) ++ pTxBlk->TxFrameType = TX_LEGACY_FRAME; ++ } ++ ++#ifdef RT2870 ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++#endif // RT2870 // ++ ++ Count += pTxBlk->TxPacketList.Number; ++ ++ // Do HardTransmit now. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ Status = STAHardTransmit(pAd, pTxBlk, QueIdx); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#if 0 // We should not break if HardTransmit failed. Well, at least now we should not! ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE /*RT_DEBUG_INFO*/,("RTMPHardTransmit return failed!!!\n")); ++ break; ++ } ++#endif ++ } ++ ++ RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); ++ ++#ifdef RT2870 ++ if (!hasTxDesc) ++ RTUSBKickBulkOut(pAd); ++#endif // RT2870 // ++ ++#ifdef BLOCK_NET_IF ++ if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) ++ && (pAd->TxSwQueue[QueIdx].Number < 1)) ++ { ++ releaseNetIf(&pAd->blockQueueTab[QueIdx]); ++ } ++#endif // BLOCK_NET_IF // ++ ++ } ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Rate Transmit rate ++ Size Frame size in units of byte ++ ++ Return Value: ++ Duration number in units of usec ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++USHORT RTMPCalcDuration( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Rate, ++ IN ULONG Size) ++{ ++ ULONG Duration = 0; ++ ++ if (Rate < RATE_FIRST_OFDM_RATE) // CCK ++ { ++ if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED)) ++ Duration = 96; // 72+24 preamble+plcp ++ else ++ Duration = 192; // 144+48 preamble+plcp ++ ++ Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); ++ if ((Size << 4) % RateIdTo500Kbps[Rate]) ++ Duration ++; ++ } ++ else if (Rate <= RATE_LAST_OFDM_RATE)// OFDM rates ++ { ++ Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension ++ Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); ++ if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) ++ Duration += 4; ++ } ++ else //mimo rate ++ { ++ Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension ++ } ++ ++ return (USHORT)Duration; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pTxWI Pointer to head of each MPDU to HW. ++ Ack Setting for Ack requirement bit ++ Fragment Setting for Fragment bit ++ RetryMode Setting for retry mode ++ Ifs Setting for IFS gap ++ Rate Setting for transmit rate ++ Service Setting for service ++ Length Frame length ++ TxPreamble Short or Long preamble when using CCK rates ++ QueIdx - 0-3, according to 802.11e/d4.4 June/2003 ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ See also : BASmartHardTransmit() !!! ++ ++ ======================================================================== ++*/ ++VOID RTMPWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pOutTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit) ++{ ++ PMAC_TABLE_ENTRY pMac = NULL; ++ TXWI_STRUC TxWI; ++ PTXWI_STRUC pTxWI; ++ ++ if (WCID < MAX_LEN_OF_MAC_TABLE) ++ pMac = &pAd->MacTab.Content[WCID]; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(&TxWI, TXWI_SIZE); ++ pTxWI = &TxWI; ++ ++ pTxWI->FRAG= FRAG; ++ ++ pTxWI->CFACK = CFACK; ++ pTxWI->TS= InsTimestamp; ++ pTxWI->AMPDU = AMPDU; ++ pTxWI->ACK = Ack; ++ pTxWI->txop= Txopmode; ++ ++ pTxWI->NSEQ = NSeq; ++ // John tune the performace with Intel Client in 20 MHz performance ++#ifdef DOT11_N_SUPPORT ++ BASize = pAd->CommonCfg.TxBASize; ++ ++ if( BASize >7 ) ++ BASize =7; ++ pTxWI->BAWinSize = BASize; ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->WirelessCliID = WCID; ++ pTxWI->MPDUtotalByteCount = Length; ++ pTxWI->PacketId = PID; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ pTxWI->CFACK = CfAck; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pMac) ++ { ++ if (pAd->CommonCfg.bMIMOPSEnable) ++ { ++ if ((pMac->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMac->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ } ++ //pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0; ++ if (pMac->bIAmBadAtheros && (pMac->WepStatus != Ndis802_11WEPDisabled)) ++ { ++ pTxWI->MpduDensity = 7; ++ } ++ else ++ { ++ pTxWI->MpduDensity = pMac->MpduDensity; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->PacketId = pTxWI->MCS; ++ NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); ++} ++ ++ ++VOID RTMPWriteTxWI_Data( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk) ++{ ++ HTTRANSMIT_SETTING *pTransmit; ++ PMAC_TABLE_ENTRY pMacEntry; ++#ifdef DOT11_N_SUPPORT ++ UCHAR BASize; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ ASSERT(pTxWI); ++ ++ pTransmit = pTxBlk->pTransmit; ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(pTxWI, TXWI_SIZE); ++ ++ pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag); ++ pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); ++ pTxWI->txop = pTxBlk->FrameGap; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (pMacEntry && ++ (pAd->StaCfg.BssType == BSS_INFRA) && ++ (pMacEntry->ValidAsDls == TRUE)) ++ pTxWI->WirelessCliID = BSSID_WCID; ++ else ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ pTxWI->WirelessCliID = pTxBlk->Wcid; ++ ++ pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack); ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); ++ ++ // John tune the performace with Intel Client in 20 MHz performance ++ BASize = pAd->CommonCfg.TxBASize; ++ if((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry)) ++ { ++ UCHAR RABAOriIdx = 0; //The RA's BA Originator table index. ++ ++ RABAOriIdx = pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority]; ++ BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize; ++ } ++ ++#if 0 // 3*3 ++ if (BASize > 7) ++ BASize = 7; ++#endif ++ ++ pTxWI->TxBF = pTransmit->field.TxBF; ++ pTxWI->BAWinSize = BASize; ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pMacEntry) ++ { ++ if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMacEntry->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ ++ if (pMacEntry->bIAmBadAtheros && (pMacEntry->WepStatus != Ndis802_11WEPDisabled)) ++ { ++ pTxWI->MpduDensity = 7; ++ } ++ else ++ { ++ pTxWI->MpduDensity = pMacEntry->MpduDensity; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DBG_DIAGNOSE ++ if (pTxBlk->QueIdx== 0) ++ { ++ pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; ++ pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ // for rate adapation ++ pTxWI->PacketId = pTxWI->MCS; ++} ++ ++ ++VOID RTMPWriteTxWI_Cache( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk) ++{ ++ PHTTRANSMIT_SETTING /*pTxHTPhyMode,*/ pTransmit; ++ PMAC_TABLE_ENTRY pMacEntry; ++ ++ // ++ // update TXWI ++ // ++ pMacEntry = pTxBlk->pMacEntry; ++ pTransmit = pTxBlk->pTransmit; ++ ++ if (pMacEntry->bAutoTxRateSwitch) ++ { ++ pTxWI->txop = IFS_HTTXOP; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ ++ // set PID for TxRateSwitching ++ pTxWI->PacketId = pTransmit->field.MCS; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE); ++ pTxWI->MIMOps = 0; ++ ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ ++ if (pAd->CommonCfg.bMIMOPSEnable) ++ { ++ // MIMO Power Save Mode ++ if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMacEntry->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if ((pTransmit->field.MODE >= MODE_HTMIX) && (pTransmit->field.MCS > 7)) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DBG_DIAGNOSE ++ if (pTxBlk->QueIdx== 0) ++ { ++ pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; ++ pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pTxD Pointer to transmit descriptor ++ Ack Setting for Ack requirement bit ++ Fragment Setting for Fragment bit ++ RetryMode Setting for retry mode ++ Ifs Setting for IFS gap ++ Rate Setting for transmit rate ++ Service Setting for service ++ Length Frame length ++ TxPreamble Short or Long preamble when using CCK rates ++ QueIdx - 0-3, according to 802.11e/d4.4 June/2003 ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPWriteTxDescriptor( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXD_STRUC pTxD, ++ IN BOOLEAN bWIV, ++ IN UCHAR QueueSEL) ++{ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ ++ pTxD->WIV = (bWIV) ? 1: 0; ++ pTxD->QSEL= (QueueSEL); ++ //RT2860c?? fixed using EDCA queue for test... We doubt Queue1 has problem. 2006-09-26 Jan ++ //pTxD->QSEL= FIFO_EDCA; ++ if (pAd->bGenOneHCCA == TRUE) ++ pTxD->QSEL= FIFO_HCCA; ++ pTxD->DMADONE = 0; ++} ++ ++ ++// should be called only when - ++// 1. MEADIA_CONNECTED ++// 2. AGGREGATION_IN_USED ++// 3. Fragmentation not in used ++// 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible ++BOOLEAN TxFrameIsAggregatible( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pPrevAddr1, ++ IN PUCHAR p8023hdr) ++{ ++ ++ // can't aggregate EAPOL (802.1x) frame ++ if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e)) ++ return FALSE; ++ ++ // can't aggregate multicast/broadcast frame ++ if (p8023hdr[0] & 0x01) ++ return FALSE; ++ ++ if (INFRA_ON(pAd)) // must be unicast to AP ++ return TRUE; ++ else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) // unicast to same STA ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check the MSDU Aggregation policy ++ 1.HT aggregation is A-MSDU ++ 2.legaacy rate aggregation is software aggregation by Ralink. ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN PeerIsAggreOn( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG TxRate, ++ IN PMAC_TABLE_ENTRY pMacEntry) ++{ ++ ULONG AFlags = (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE); ++ ++ if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++ { ++ return TRUE; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) ++ { // legacy Ralink Aggregation support ++ return TRUE; ++ } ++#endif // AGGREGATION_SUPPORT // ++ } ++ ++ return FALSE; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check and fine the packet waiting in SW queue with highest priority ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ pQueue Pointer to Waiting Queue ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++PQUEUE_HEADER RTMPCheckTxSwQueue( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pQueIdx) ++{ ++ ++ ULONG Number; ++ // 2004-11-15 to be removed. test aggregation only ++// if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) && (*pNumber < 2)) ++// return NULL; ++ ++ Number = pAd->TxSwQueue[QID_AC_BK].Number ++ + pAd->TxSwQueue[QID_AC_BE].Number ++ + pAd->TxSwQueue[QID_AC_VI].Number ++ + pAd->TxSwQueue[QID_AC_VO].Number ++ + pAd->TxSwQueue[QID_HCCA].Number; ++ ++ if (pAd->TxSwQueue[QID_AC_VO].Head != NULL) ++ { ++ *pQueIdx = QID_AC_VO; ++ return (&pAd->TxSwQueue[QID_AC_VO]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL) ++ { ++ *pQueIdx = QID_AC_VI; ++ return (&pAd->TxSwQueue[QID_AC_VI]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL) ++ { ++ *pQueIdx = QID_AC_BE; ++ return (&pAd->TxSwQueue[QID_AC_BE]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL) ++ { ++ *pQueIdx = QID_AC_BK; ++ return (&pAd->TxSwQueue[QID_AC_BK]); ++ } ++ else if (pAd->TxSwQueue[QID_HCCA].Head != NULL) ++ { ++ *pQueIdx = QID_HCCA; ++ return (&pAd->TxSwQueue[QID_HCCA]); ++ } ++ ++ // No packet pending in Tx Sw queue ++ *pQueIdx = QID_AC_BK; ++ ++ return (NULL); ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Suspend MSDU transmission ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("SCANNING, suspend MSDU transmission ...\n")); ++ ++ ++ // ++ // Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and ++ // use Lowbound as R66 value on ScanNextChannel(...) ++ // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); ++ ++ // set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning) ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x26 + GET_LNA_GAIN(pAd))); ++ RTMPSetAGCInitValue(pAd, BW_20); ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x000f0000); // abort all TX rings ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Resume MSDU transmission ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd) ++{ ++// UCHAR IrqState; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n")); ++ ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++// sample, for IRQ LOCK to SEM LOCK ++// IrqState = pAd->irq_disabled; ++// if (IrqState) ++// RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++// else ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++} ++ ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ USHORT PayloadSize; ++ USHORT SubFrameSize; ++ PHEADER_802_3 pAMSDUsubheader; ++ UINT nMSDU; ++ UCHAR Header802_3[14]; ++ ++ PUCHAR pPayload, pDA, pSA, pRemovedLLCSNAP; ++ PNDIS_PACKET pClonePacket; ++ ++ ++ ++ nMSDU = 0; ++ ++ while (DataSize > LENGTH_802_3) ++ { ++ ++ nMSDU++; ++ ++ //hex_dump("subheader", pData, 64); ++ pAMSDUsubheader = (PHEADER_802_3)pData; ++ //pData += LENGTH_802_3; ++ PayloadSize = pAMSDUsubheader->Octet[1] + (pAMSDUsubheader->Octet[0]<<8); ++ SubFrameSize = PayloadSize + LENGTH_802_3; ++ ++ ++ if ((DataSize < SubFrameSize) || (PayloadSize > 1518 )) ++ { ++ break; ++ } ++ ++ //printk("%d subframe: Size = %d\n", nMSDU, PayloadSize); ++ ++ pPayload = pData + LENGTH_802_3; ++ pDA = pData; ++ pSA = pData + MAC_ADDR_LEN; ++ ++ // convert to 802.3 header ++ CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP); ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) ) ++ { ++ // avoid local heap overflow, use dyanamic allocation ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ memmove(Elem->Msg+(LENGTH_802_11 + LENGTH_802_1_H), pPayload, PayloadSize); ++ Elem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + PayloadSize; ++ WpaEAPOLKeyAction(pAd, Elem); ++ kfree(Elem); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pRemovedLLCSNAP) ++ { ++ pPayload -= LENGTH_802_3; ++ PayloadSize += LENGTH_802_3; ++ NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); ++ if (pClonePacket) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ // A-MSDU has padding to multiple of 4 including subframe header. ++ // align SubFrameSize up to multiple of 4 ++ SubFrameSize = (SubFrameSize+3)&(~0x3); ++ ++ ++ if (SubFrameSize > 1528 || SubFrameSize < 32) ++ { ++ break; ++ } ++ ++ if (DataSize > SubFrameSize) ++ { ++ pData += SubFrameSize; ++ DataSize -= SubFrameSize; ++ } ++ else ++ { ++ // end of A-MSDU ++ DataSize = 0; ++ } ++ } ++ ++ // finally release original rx packet ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ ++ return nMSDU; ++} ++ ++ ++UINT BA_Reorder_AMSDU_Annnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PUCHAR pData; ++ USHORT DataSize; ++ UINT nMSDU = 0; ++ ++ pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); ++ DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); ++ ++ nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); ++ ++ return nMSDU; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Look up the MAC address in the MAC table. Return NULL if not found. ++ Return: ++ pEntry - pointer to the MAC entry; NULL is not found ++ ========================================================================== ++*/ ++MAC_TABLE_ENTRY *MacTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ PUCHAR pAddr) ++{ ++ ULONG HashIdx; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = pAd->MacTab.Hash[HashIdx]; ++ ++ while (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsWDS || pEntry->ValidAsApCli || pEntry->ValidAsMesh)) ++ { ++ if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ break; ++ } ++ else ++ pEntry = pEntry->pNext; ++ } ++ ++ return pEntry; ++} ++ ++MAC_TABLE_ENTRY *MacTableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR apidx, ++ IN BOOLEAN CleanAll) ++{ ++ UCHAR HashIdx; ++ int i, FirstWcid; ++ MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; ++ ++ // if FULL, return ++ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) ++ return NULL; ++ ++ FirstWcid = 1; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ FirstWcid = 2; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // allocate one MAC entry ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ for (i = FirstWcid; i< MAX_LEN_OF_MAC_TABLE; i++) // skip entry#0 so that "entry index == AID" for fast lookup ++ { ++ // pick up the first available vacancy ++ if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) && ++ (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && ++ (pAd->MacTab.Content[i].ValidAsApCli== FALSE) && ++ (pAd->MacTab.Content[i].ValidAsMesh == FALSE) ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ && (pAd->MacTab.Content[i].ValidAsDls == FALSE) ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ if (CleanAll == TRUE) ++ { ++ pEntry->MaxSupportedRate = RATE_11; ++ pEntry->CurrTxRate = RATE_11; ++ NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); ++ pEntry->PairwiseKey.KeyLen = 0; ++ pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; ++ } ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (apidx >= MIN_NET_DEVICE_FOR_DLS) ++ { ++ pEntry->ValidAsCLI = FALSE; ++ pEntry->ValidAsWDS = FALSE; ++ pEntry->ValidAsApCli = FALSE; ++ pEntry->ValidAsMesh = FALSE; ++ pEntry->ValidAsDls = TRUE; ++ pEntry->isCached = FALSE; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry->ValidAsCLI = TRUE; ++ pEntry->ValidAsWDS = FALSE; ++ pEntry->ValidAsApCli = FALSE; ++ pEntry->ValidAsMesh = FALSE; ++ pEntry->ValidAsDls = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ pEntry->bIAmBadAtheros = FALSE; ++ pEntry->pAd = pAd; ++ pEntry->CMTimerRunning = FALSE; ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ pEntry->RSNIE_Len = 0; ++ NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter)); ++ pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR; ++ ++ if (pEntry->ValidAsMesh) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_MESH); ++ else if (pEntry->ValidAsApCli) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI); ++ else if (pEntry->ValidAsWDS) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ else if (pEntry->ValidAsDls) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_DLS); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ else ++ pEntry->apidx = apidx; ++ ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ pEntry->GTKState = REKEY_NEGOTIATING; ++ pEntry->PairwiseKey.KeyLen = 0; ++ pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry->ValidAsDls == TRUE) ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++#endif //QOS_DLS_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; ++ COPY_MAC_ADDR(pEntry->Addr, pAddr); ++ pEntry->Sst = SST_NOT_AUTH; ++ pEntry->AuthState = AS_NOT_AUTH; ++ pEntry->Aid = (USHORT)i; //0; ++ pEntry->CapabilityInfo = 0; ++ pEntry->PsMode = PWR_ACTIVE; ++ pEntry->PsQIdleCount = 0; ++ pEntry->NoDataIdleCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ InitializeQueueHeader(&pEntry->PsQueue); ++ ++ ++ pAd->MacTab.Size ++; ++ // Add this entry into ASIC RX WCID search table ++ RT28XX_STA_ENTRY_ADD(pAd, pEntry); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertEntry - allocate entry #%d, Total= %d\n",i, pAd->MacTab.Size)); ++ break; ++ } ++ } ++ ++ // add this MAC entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ if (pAd->MacTab.Hash[HashIdx] == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pAd->MacTab.Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ return pEntry; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Delete a specified client from MAC table ++ ========================================================================== ++ */ ++BOOLEAN MacTableDeleteEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr) ++{ ++ USHORT HashIdx; ++ MAC_TABLE_ENTRY *pEntry, *pPrevEntry, *pProbeEntry; ++ BOOLEAN Cancelled; ++ //USHORT offset; // unused variable ++ //UCHAR j; // unused variable ++ ++ if (wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ //pEntry = pAd->MacTab.Hash[HashIdx]; ++ pEntry = &pAd->MacTab.Content[wcid]; ++ ++ if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ || pEntry->ValidAsDls ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ )) ++ { ++ if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ ++ // Delete this entry from ASIC on-chip WCID Table ++ RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid); ++ ++#ifdef DOT11_N_SUPPORT ++ // free resources of BA ++ BASessionTearDownALL(pAd, pEntry->Aid); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ pPrevEntry = NULL; ++ pProbeEntry = pAd->MacTab.Hash[HashIdx]; ++ ASSERT(pProbeEntry); ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ // not found !!! ++ ASSERT(pProbeEntry != NULL); ++ ++ RT28XX_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid); ++ ++ ++ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) ++ { ++ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ } ++ ++ ++ NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); ++ pAd->MacTab.Size --; ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableDeleteEntry1 - Total= %d\n", pAd->MacTab.Size)); ++ } ++ else ++ { ++ printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid); ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ //Reset operating mode when no Sta. ++ if (pAd->MacTab.Size == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; ++#endif // DOT11_N_SUPPORT // ++ AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/); ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ This routine reset the entire MAC table. All packets pending in ++ the power-saving queues are freed here. ++ ========================================================================== ++ */ ++VOID MacTableReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n")); ++ //NdisAcquireSpinLock(&pAd->MacTabLock); ++ ++ for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) ++ { ++ ++#ifdef DOT11_N_SUPPORT ++ // free resources of BA ++ BASessionTearDownALL(pAd, i); ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->MacTab.Content[i].ValidAsCLI = FALSE; ++ ++ ++ ++#ifdef RT2870 ++ NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6); ++ RT28XX_STA_ENTRY_MAC_RESET(pAd, i); ++#endif // RT2870 // ++ ++ //AsicDelWcidTab(pAd, i); ++ } ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID AssocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, ++ IN PUCHAR pAddr, ++ IN USHORT CapabilityInfo, ++ IN ULONG Timeout, ++ IN USHORT ListenIntv) ++{ ++ COPY_MAC_ADDR(AssocReq->Addr, pAddr); ++ // Add mask to support 802.11b mode only ++ AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; // not cf-pollable, not cf-poll-request ++ AssocReq->Timeout = Timeout; ++ AssocReq->ListenIntv = ListenIntv; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID DisassocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, ++ IN PUCHAR pAddr, ++ IN USHORT Reason) ++{ ++ COPY_MAC_ADDR(DisassocReq->Addr, pAddr); ++ DisassocReq->Reason = Reason; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check the out going frame, if this is an DHCP or ARP datagram ++ will be duplicate another frame at low data rate transmit. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pPacket Pointer to outgoing Ndis frame ++ ++ Return Value: ++ TRUE To be duplicate at Low data rate transmit. (1mb) ++ FALSE Do nothing. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ MAC header + IP Header + UDP Header ++ 14 Bytes 20 Bytes ++ ++ UDP Header ++ 00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| ++ Source Port ++ 16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31| ++ Destination Port ++ ++ port 0x43 means Bootstrap Protocol, server. ++ Port 0x44 means Bootstrap Protocol, client. ++ ++ ======================================================================== ++*/ ++ ++BOOLEAN RTMPCheckDHCPFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ ULONG NumberOfBytesRead = 0; ++ ULONG CurrentOffset = 0; ++ PVOID pVirtualAddress = NULL; ++ UINT NdisBufferLength; ++ PUCHAR pSrc; ++ USHORT Protocol; ++ UCHAR ByteOffset36 = 0; ++ UCHAR ByteOffset38 = 0; ++ BOOLEAN ReadFirstParm = TRUE; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, (PUCHAR *)&pVirtualAddress, &NdisBufferLength); ++ ++ NumberOfBytesRead += NdisBufferLength; ++ pSrc = (PUCHAR) pVirtualAddress; ++ Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); ++ ++ // ++ // Check DHCP & BOOTP protocol ++ // ++ while (NumberOfBytesRead <= PacketInfo.TotalPacketLength) ++ { ++ if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE)) ++ { ++ CurrentOffset = 35 - (NumberOfBytesRead - NdisBufferLength); ++ ByteOffset36 = *(pSrc + CurrentOffset); ++ ReadFirstParm = FALSE; ++ } ++ ++ if (NumberOfBytesRead >= 37) ++ { ++ CurrentOffset = 37 - (NumberOfBytesRead - NdisBufferLength); ++ ByteOffset38 = *(pSrc + CurrentOffset); ++ //End of Read ++ break; ++ } ++ return FALSE; ++ } ++ ++ // Check for DHCP & BOOTP protocol ++ if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43)) ++ { ++ // ++ // 2054 (hex 0806) for ARP datagrams ++ // if this packet is not ARP datagrams, then do nothing ++ // ARP datagrams will also be duplicate at 1mb broadcast frames ++ // ++ if (Protocol != 0x0806 ) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++BOOLEAN RTMPCheckEtherType( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ USHORT TypeLen; ++ UCHAR Byte0, Byte1; ++ PUCHAR pSrcBuf; ++ UINT32 pktLen; ++ UINT16 srcPort, dstPort; ++ BOOLEAN status = TRUE; ++ ++ ++ pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); ++ pktLen = GET_OS_PKT_LEN(pPacket); ++ ++ ASSERT(pSrcBuf); ++ ++ RTMP_SET_PACKET_SPECIFIC(pPacket, 0); ++ ++ // get Ethernet protocol field ++ TypeLen = (pSrcBuf[12] << 8) + pSrcBuf[13]; ++ ++ pSrcBuf += LENGTH_802_3; // Skip the Ethernet Header. ++ ++ if (TypeLen <= 1500) ++ { // 802.3, 802.3 LLC ++ /* ++ DestMAC(6) + SrcMAC(6) + Lenght(2) + ++ DSAP(1) + SSAP(1) + Control(1) + ++ if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. ++ => + SNAP (5, OriginationID(3) + etherType(2)) ++ */ ++ if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) ++ { ++ Sniff2BytesFromNdisBuffer(pSrcBuf, 6, &Byte0, &Byte1); ++ RTMP_SET_PACKET_LLCSNAP(pPacket, 1); ++ TypeLen = (USHORT)((Byte0 << 8) + Byte1); ++ pSrcBuf += 8; // Skip this LLC/SNAP header ++ } ++ else ++ { ++ //It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it. ++ } ++ } ++ ++ // If it's a VLAN packet, get the real Type/Length field. ++ if (TypeLen == 0x8100) ++ { ++ /* 0x8100 means VLAN packets */ ++ ++ /* Dest. MAC Address (6-bytes) + ++ Source MAC Address (6-bytes) + ++ Length/Type = 802.1Q Tag Type (2-byte) + ++ Tag Control Information (2-bytes) + ++ Length / Type (2-bytes) + ++ data payload (0-n bytes) + ++ Pad (0-p bytes) + ++ Frame Check Sequence (4-bytes) */ ++ ++ RTMP_SET_PACKET_VLAN(pPacket, 1); ++ Sniff2BytesFromNdisBuffer(pSrcBuf, 2, &Byte0, &Byte1); ++ TypeLen = (USHORT)((Byte0 << 8) + Byte1); ++ ++ pSrcBuf += 4; // Skip the VLAN Header. ++ } ++ ++ switch (TypeLen) ++ { ++ case 0x0800: ++ { ++ ASSERT((pktLen > 34)); ++ if (*(pSrcBuf + 9) == 0x11) ++ { // udp packet ++ ASSERT((pktLen > 34)); // 14 for ethernet header, 20 for IP header ++ ++ pSrcBuf += 20; // Skip the IP header ++ srcPort = OS_NTOHS(*((UINT16 *)pSrcBuf)); ++ dstPort = OS_NTOHS(*((UINT16 *)(pSrcBuf +2))); ++ ++ if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44)) ++ { //It's a BOOTP/DHCP packet ++ RTMP_SET_PACKET_DHCP(pPacket, 1); ++ } ++ } ++ } ++ break; ++ case 0x0806: ++ { ++ //ARP Packet. ++ RTMP_SET_PACKET_DHCP(pPacket, 1); ++ } ++ break; ++ case 0x888e: ++ { ++ // EAPOL Packet. ++ RTMP_SET_PACKET_EAPOL(pPacket, 1); ++ } ++ break; ++ default: ++ status = FALSE; ++ break; ++ } ++ ++ return status; ++ ++} ++ ++ ++ ++VOID Update_Rssi_Sample( ++ IN PRTMP_ADAPTER pAd, ++ IN RSSI_SAMPLE *pRssi, ++ IN PRXWI_STRUC pRxWI) ++ { ++ CHAR rssi0 = pRxWI->RSSI0; ++ CHAR rssi1 = pRxWI->RSSI1; ++ CHAR rssi2 = pRxWI->RSSI2; ++ ++ if (rssi0 != 0) ++ { ++ pRssi->LastRssi0 = ConvertToRssi(pAd, (CHAR)rssi0, RSSI_0); ++ pRssi->AvgRssi0X8 = (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0; ++ pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3; ++ } ++ ++ if (rssi1 != 0) ++ { ++ pRssi->LastRssi1 = ConvertToRssi(pAd, (CHAR)rssi1, RSSI_1); ++ pRssi->AvgRssi1X8 = (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1; ++ pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3; ++ } ++ ++ if (rssi2 != 0) ++ { ++ pRssi->LastRssi2 = ConvertToRssi(pAd, (CHAR)rssi2, RSSI_2); ++ pRssi->AvgRssi2X8 = (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2; ++ pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3; ++ } ++} ++ ++ ++ ++// Normal legacy Rx packet indication ++VOID Indicate_Legacy_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ UCHAR Header802_3[LENGTH_802_3]; ++ ++ // 1. get 802.3 Header ++ // 2. remove LLC ++ // a. pointer pRxBlk->pData to payload ++ // b. modify pRxBlk->DataSize ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pRxBlk->DataSize > MAX_RX_PKT_LEN) ++ { ++#if 0 // sample take off, for multiple card design ++ static int err_size; ++ ++ err_size++; ++ if (err_size > 20) ++ { ++ printk("Legacy DataSize = %d\n", pRxBlk->DataSize); ++ hex_dump("802.3 Header", Header802_3, LENGTH_802_3); ++ hex_dump("Payload", pRxBlk->pData, 64); ++ err_size = 0; ++ } ++#endif ++ ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ++ STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); ++ ++#ifdef RT2870 ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.bDisableReordering == 0) ++ { ++ PBA_REC_ENTRY pBAEntry; ++ ULONG Now32; ++ UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; ++ UCHAR TID = pRxBlk->pRxWI->TID; ++ USHORT Idx; ++ ++#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx != 0) ++ { ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ // update last rx time ++ NdisGetSystemUpTime(&Now32); ++ if ((pBAEntry->list.qlen > 0) && ++ RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) ++ ) ++ { ++ printk("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", pRxBlk->Flags, pRxBlk->pRxWI->TID, pRxBlk->RxD.AMPDU); ++ hex_dump("Dump the legacy Packet:", GET_OS_PKT_DATAPTR(pRxBlk->pRxPacket), 64); ++ ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); ++ } ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++#endif // RT2870 // ++ ++ wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); ++ ++ // ++ // pass this 802.3 packet to upper layer or forward this packet to WM directly ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++ ++// Normal, AMPDU or AMSDU ++VOID CmmRxnonRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) ++ { ++ // handle A-MSDU ++ Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ } ++} ++ ++ ++VOID CmmRxRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ UCHAR Header802_3[LENGTH_802_3]; ++ UINT16 Msdu2Size; ++ UINT16 Payload1Size, Payload2Size; ++ PUCHAR pData2; ++ PNDIS_PACKET pPacket2 = NULL; ++ ++ ++ ++ Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData+1) << 8); ++ ++ if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize)) ++ { ++ /* skip two byte MSDU2 len */ ++ pRxBlk->pData += 2; ++ pRxBlk->DataSize -= 2; ++ } ++ else ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // get 802.3 Header and remove LLC ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ASSERT(pRxBlk->pRxPacket); ++ ++ // Ralink Aggregation frame ++ pAd->RalinkCounters.OneSecRxAggregationCount ++; ++ Payload1Size = pRxBlk->DataSize - Msdu2Size; ++ Payload2Size = Msdu2Size - LENGTH_802_3; ++ ++ pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (!pPacket2) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // update payload size of 1st packet ++ pRxBlk->DataSize = Payload1Size; ++ wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pPacket2) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++ ++#define RESET_FRAGFRAME(_fragFrame) \ ++ { \ ++ _fragFrame.RxSize = 0; \ ++ _fragFrame.Sequence = 0; \ ++ _fragFrame.LastFrag = 0; \ ++ _fragFrame.Flags = 0; \ ++ } ++ ++ ++PNDIS_PACKET RTMPDeFragmentDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ UCHAR *pData = pRxBlk->pData; ++ USHORT DataSize = pRxBlk->DataSize; ++ PNDIS_PACKET pRetPacket = NULL; ++ UCHAR *pFragBuffer = NULL; ++ BOOLEAN bReassDone = FALSE; ++ UCHAR HeaderRoom = 0; ++ ++ ++ ASSERT(pHeader); ++ ++ HeaderRoom = pData - (UCHAR *)pHeader; ++ ++ // Re-assemble the fragmented packets ++ if (pHeader->Frag == 0) // Frag. Number is 0 : First frag or only one pkt ++ { ++ // the first pkt of fragment, record it. ++ if (pHeader->FC.MoreFrag) ++ { ++ ASSERT(pAd->FragFrame.pFragPacket); ++ pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); ++ pAd->FragFrame.RxSize = DataSize + HeaderRoom; ++ NdisMoveMemory(pFragBuffer, pHeader, pAd->FragFrame.RxSize); ++ pAd->FragFrame.Sequence = pHeader->Sequence; ++ pAd->FragFrame.LastFrag = pHeader->Frag; // Should be 0 ++ ASSERT(pAd->FragFrame.LastFrag == 0); ++ goto done; // end of processing this frame ++ } ++ } ++ else //Middle & End of fragment ++ { ++ if ((pHeader->Sequence != pAd->FragFrame.Sequence) || ++ (pHeader->Frag != (pAd->FragFrame.LastFrag + 1))) ++ { ++ // Fragment is not the same sequence or out of fragment number order ++ // Reset Fragment control blk ++ RESET_FRAGFRAME(pAd->FragFrame); ++ DBGPRINT(RT_DEBUG_ERROR, ("Fragment is not the same sequence or out of fragment number order.\n")); ++ goto done; // give up this frame ++ } ++ else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE) ++ { ++ // Fragment frame is too large, it exeeds the maximum frame size. ++ // Reset Fragment control blk ++ RESET_FRAGFRAME(pAd->FragFrame); ++ DBGPRINT(RT_DEBUG_ERROR, ("Fragment frame is too large, it exeeds the maximum frame size.\n")); ++ goto done; // give up this frame ++ } ++ ++ // ++ // Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment. ++ // In this case, we will dropt it. ++ // ++ if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", pHeader->Sequence, pHeader->Frag)); ++ goto done; // give up this frame ++ } ++ ++ pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); ++ ++ // concatenate this fragment into the re-assembly buffer ++ NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, DataSize); ++ pAd->FragFrame.RxSize += DataSize; ++ pAd->FragFrame.LastFrag = pHeader->Frag; // Update fragment number ++ ++ // Last fragment ++ if (pHeader->FC.MoreFrag == FALSE) ++ { ++ bReassDone = TRUE; ++ } ++ } ++ ++done: ++ // always release rx fragmented packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ ++ // return defragmented packet if packet is reassembled completely ++ // otherwise return NULL ++ if (bReassDone) ++ { ++ PNDIS_PACKET pNewFragPacket; ++ ++ // allocate a new packet buffer for fragment ++ pNewFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); ++ if (pNewFragPacket) ++ { ++ // update RxBlk ++ pRetPacket = pAd->FragFrame.pFragPacket; ++ pAd->FragFrame.pFragPacket = pNewFragPacket; ++ pRxBlk->pHeader = (PHEADER_802_11) GET_OS_PKT_DATAPTR(pRetPacket); ++ pRxBlk->pData = (UCHAR *)pRxBlk->pHeader + HeaderRoom; ++ pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom; ++ pRxBlk->pRxPacket = pRetPacket; ++ } ++ else ++ { ++ RESET_FRAGFRAME(pAd->FragFrame); ++ } ++ } ++ ++ return pRetPacket; ++} ++ ++ ++VOID Indicate_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ UINT nMSDU; ++ ++ update_os_packet_info(pAd, pRxBlk, FromWhichBSSID); ++ RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); ++ nMSDU = deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, pRxBlk->DataSize); ++} ++ ++VOID Indicate_EAPOL_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pEntry == NULL) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n")); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++} ++ ++#define BCN_TBTT_OFFSET 64 //defer 64 us ++VOID ReSyncBeaconTime( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ UINT32 Offset; ++ ++ ++ Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET); ++ ++ pAd->TbttTickCount++; ++ ++ // ++ // The updated BeaconInterval Value will affect Beacon Interval after two TBTT ++ // beacasue the original BeaconInterval had been loaded into next TBTT_TIMER ++ // ++ if (Offset == (BCN_TBTT_OFFSET-2)) ++ { ++ BCN_TIME_CFG_STRUC csr; ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1 ; // ASIC register in units of 1/16 TU = 64us ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ } ++ else ++ { ++ if (Offset == (BCN_TBTT_OFFSET-1)) ++ { ++ BCN_TIME_CFG_STRUC csr; ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; // ASIC register in units of 1/16 TU ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/cmm_info.c +@@ -0,0 +1,3712 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#include "../rt_config.h" ++ ++INT Show_SSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef DOT11_N_SUPPORT ++INT Show_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // DOT11_N_SUPPORT // ++ ++INT Show_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_CountryCode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef AGGREGATION_SUPPORT ++INT Show_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // AGGREGATION_SUPPORT // ++ ++#ifdef WMM_SUPPORT ++INT Show_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // WMM_SUPPORT // ++ ++INT Show_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef CONFIG_STA_SUPPORT ++INT Show_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Show_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++static struct { ++ CHAR *name; ++ INT (*show_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC, RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC[] = { ++ {"SSID", Show_SSID_Proc}, ++ {"WirelessMode", Show_WirelessMode_Proc}, ++ {"TxBurst", Show_TxBurst_Proc}, ++ {"TxPreamble", Show_TxPreamble_Proc}, ++ {"TxPower", Show_TxPower_Proc}, ++ {"Channel", Show_Channel_Proc}, ++ {"BGProtection", Show_BGProtection_Proc}, ++ {"RTSThreshold", Show_RTSThreshold_Proc}, ++ {"FragThreshold", Show_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Show_HtBw_Proc}, ++ {"HtMcs", Show_HtMcs_Proc}, ++ {"HtGi", Show_HtGi_Proc}, ++ {"HtOpMode", Show_HtOpMode_Proc}, ++ {"HtExtcha", Show_HtExtcha_Proc}, ++ {"HtMpduDensity", Show_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Show_HtBaWinSize_Proc}, ++ {"HtRdg", Show_HtRdg_Proc}, ++ {"HtAmsdu", Show_HtAmsdu_Proc}, ++ {"HtAutoBa", Show_HtAutoBa_Proc}, ++#endif // DOT11_N_SUPPORT // ++ {"CountryRegion", Show_CountryRegion_Proc}, ++ {"CountryRegionABand", Show_CountryRegionABand_Proc}, ++ {"CountryCode", Show_CountryCode_Proc}, ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Show_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Show_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Show_IEEE80211H_Proc}, ++#ifdef CONFIG_STA_SUPPORT ++ {"NetworkType", Show_NetworkType_Proc}, ++#endif // CONFIG_STA_SUPPORT // ++ {"AuthMode", Show_AuthMode_Proc}, ++ {"EncrypType", Show_EncrypType_Proc}, ++ {"DefaultKeyID", Show_DefaultKeyID_Proc}, ++ {"Key1", Show_Key1_Proc}, ++ {"Key2", Show_Key2_Proc}, ++ {"Key3", Show_Key3_Proc}, ++ {"Key4", Show_Key4_Proc}, ++ {"WPAPSK", Show_WPAPSK_Proc}, ++ {NULL, NULL} ++}; ++ ++/* ++ ========================================================================== ++ Description: ++ Get Driver version. ++ ++ Return: ++ ========================================================================== ++*/ ++INT Set_DriverVersion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); ++#endif // CONFIG_STA_SUPPORT // ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Country Region. ++ This command will not work, if the field of CountryRegion in eeprom is programmed. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG region; ++ ++ region = simple_strtol(arg, 0, 10); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ return -EOPNOTSUPP; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Country can be set only when EEPROM not programmed ++ if (pAd->CommonCfg.CountryRegion & 0x80) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameter of CountryRegion in eeprom is programmed \n")); ++ return FALSE; ++ } ++ ++ if((region >= 0) && (region <= REGION_MAXIMUM_BG_BAND)) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) region; ++ } ++ else if (region == REGION_31_BG_BAND) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) region; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameters out of range\n")); ++ return FALSE; ++ } ++ ++ // if set country region, driver needs to be reset ++ BuildChannelList(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegion_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegion)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Country Region for A band. ++ This command will not work, if the field of CountryRegion in eeprom is programmed. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG region; ++ ++ region = simple_strtol(arg, 0, 10); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ return -EOPNOTSUPP; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Country can be set only when EEPROM not programmed ++ if (pAd->CommonCfg.CountryRegionForABand & 0x80) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameter of CountryRegion in eeprom is programmed \n")); ++ return FALSE; ++ } ++ ++ if((region >= 0) && (region <= REGION_MAXIMUM_A_BAND)) ++ { ++ pAd->CommonCfg.CountryRegionForABand = (UCHAR) region; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameters out of range\n")); ++ return FALSE; ++ } ++ ++ // if set country region, driver needs to be reset ++ BuildChannelList(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegionABand_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegionForABand)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Wireless Mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG WirelessMode; ++ INT success = TRUE; ++ ++ WirelessMode = simple_strtol(arg, 0, 10); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ INT MaxPhyMode = PHY_11G; ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ if (WirelessMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAd, WirelessMode); ++#ifdef DOT11_N_SUPPORT ++ if (WirelessMode >= PHY_11ABGN_MIXED) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ pAd->CommonCfg.REGBACapability.field.AutoBA = TRUE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ pAd->CommonCfg.REGBACapability.field.AutoBA = FALSE; ++ } ++#endif // DOT11_N_SUPPORT // ++ // Set AdhocMode rates ++ if (pAd->StaCfg.BssType == BSS_ADHOC) ++ { ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy to on-chip memory ++ } ++ } ++ else ++ { ++ success = FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // it is needed to set SSID to take effect ++ if (success == TRUE) ++ { ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WirelessMode_Proc::(=%ld)\n", WirelessMode)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_WirelessMode_Proc::parameters out of range\n")); ++ } ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Channel ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ INT success = TRUE; ++ UCHAR Channel; ++ ++ Channel = (UCHAR) simple_strtol(arg, 0, 10); ++ ++ // check if this channel is valid ++ if (ChannelSanity(pAd, Channel) == TRUE) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->CommonCfg.Channel = Channel; ++ ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ N_ChannelCheck(pAd); ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ N_SetCenCh(pAd); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40, control_channel(%d), CentralChannel(%d) \n", ++ pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAd->CommonCfg.Channel)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ success = TRUE; ++ } ++ else ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ success = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ if (success == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Channel_Proc::(Channel=%d)\n", pAd->CommonCfg.Channel)); ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Short Slot Time Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ShortSlot_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG ShortSlot; ++ ++ ShortSlot = simple_strtol(arg, 0, 10); ++ ++ if (ShortSlot == 1) ++ pAd->CommonCfg.bUseShortSlotTime = TRUE; ++ else if (ShortSlot == 0) ++ pAd->CommonCfg.bUseShortSlotTime = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ShortSlot_Proc::(ShortSlot=%d)\n", pAd->CommonCfg.bUseShortSlotTime)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Tx power ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG TxPower; ++ INT success = FALSE; ++ ++ TxPower = (ULONG) simple_strtol(arg, 0, 10); ++ if (TxPower <= 100) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->CommonCfg.TxPowerDefault = TxPower; ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ success = TRUE; ++ } ++ else ++ success = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPower_Proc::(TxPowerPercentage=%ld)\n", pAd->CommonCfg.TxPowerPercentage)); ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set 11B/11G Protection ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ switch (simple_strtol(arg, 0, 10)) ++ { ++ case 0: //AUTO ++ pAd->CommonCfg.UseBGProtection = 0; ++ break; ++ case 1: //Always On ++ pAd->CommonCfg.UseBGProtection = 1; ++ break; ++ case 2: //Always OFF ++ pAd->CommonCfg.UseBGProtection = 2; ++ break; ++ default: //Invalid argument ++ return FALSE; ++ } ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_BGProtection_Proc::(BGProtection=%ld)\n", pAd->CommonCfg.UseBGProtection)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set TxPreamble ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ RT_802_11_PREAMBLE Preamble; ++ ++ Preamble = simple_strtol(arg, 0, 10); ++ ++ ++ switch (Preamble) ++ { ++ case Rt802_11PreambleShort: ++ pAd->CommonCfg.TxPreamble = Preamble; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ case Rt802_11PreambleLong: ++#ifdef CONFIG_STA_SUPPORT ++ case Rt802_11PreambleAuto: ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++#endif // CONFIG_STA_SUPPORT // ++ pAd->CommonCfg.TxPreamble = Preamble; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ default: //Invalid argument ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPreamble_Proc::(TxPreamble=%ld)\n", pAd->CommonCfg.TxPreamble)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set RTS Threshold ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ ++ RtsThresh = simple_strtol(arg, 0, 10); ++ ++ if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) ++ pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++#ifdef CONFIG_STA_SUPPORT ++ else if (RtsThresh == 0) ++ pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; ++#endif // CONFIG_STA_SUPPORT // ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_RTSThreshold_Proc::(RTSThreshold=%d)\n", pAd->CommonCfg.RtsThreshold)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Fragment Threshold ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ ++ FragThresh = simple_strtol(arg, 0, 10); ++ ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ //Illegal FragThresh so we set it to default ++ pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ } ++ else if (FragThresh % 2 == 1) ++ { ++ // The length of each fragment shall always be an even number of octets, except for the last fragment ++ // of an MSDU or MMPDU, which may be either an even or an odd number of octets. ++ pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); ++ } ++ else ++ { ++ pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->CommonCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) ++ pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ else ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_FragThreshold_Proc::(FragThreshold=%d)\n", pAd->CommonCfg.FragmentThreshold)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set TxBurst ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG TxBurst; ++ ++ TxBurst = simple_strtol(arg, 0, 10); ++ if (TxBurst == 1) ++ pAd->CommonCfg.bEnableTxBurst = TRUE; ++ else if (TxBurst == 0) ++ pAd->CommonCfg.bEnableTxBurst = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxBurst_Proc::(TxBurst=%d)\n", pAd->CommonCfg.bEnableTxBurst)); ++ ++ return TRUE; ++} ++ ++#ifdef AGGREGATION_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set TxBurst ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG aggre; ++ ++ aggre = simple_strtol(arg, 0, 10); ++ ++ if (aggre == 1) ++ pAd->CommonCfg.bAggregationCapable = TRUE; ++ else if (aggre == 0) ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PktAggregate_Proc::(AGGRE=%d)\n", pAd->CommonCfg.bAggregationCapable)); ++ ++ return TRUE; ++} ++#endif ++ ++/* ++ ========================================================================== ++ Description: ++ Set IEEE80211H. ++ This parameter is 1 when needs radar detection, otherwise 0 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG ieee80211h; ++ ++ ieee80211h = simple_strtol(arg, 0, 10); ++ ++ if (ieee80211h == 1) ++ pAd->CommonCfg.bIEEE80211H = TRUE; ++ else if (ieee80211h == 0) ++ pAd->CommonCfg.bIEEE80211H = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_IEEE80211H_Proc::(IEEE80211H=%d)\n", pAd->CommonCfg.bIEEE80211H)); ++ ++ return TRUE; ++} ++ ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ For Debug information ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Debug_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> Set_Debug_Proc *******************\n")); ++ ++ if(simple_strtol(arg, 0, 10) <= RT_DEBUG_LOUD) ++ RTDebugLevel = simple_strtol(arg, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== Set_Debug_Proc(RTDebugLevel = %ld)\n", RTDebugLevel)); ++ ++ return TRUE; ++} ++#endif ++ ++INT Show_DescInfo_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Reset statistics counter ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ arg ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ResetStatCounter_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ //UCHAR i; ++ //MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>Set_ResetStatCounter_Proc\n")); ++ ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAd); ++ ++ NdisZeroMemory(&pAd->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAd->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAd->RalinkCounters, sizeof(COUNTER_RALINK)); ++ ++ // Reset HotSpot counter ++#if 0 // ToDo. ++ for (i = 0; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ if ((pEntry->Valid == FALSE) || (pEntry->Sst != SST_ASSOC)) ++ continue; ++ ++ pEntry->HSCounter.LastDataPacketTime = 0; ++ pEntry->HSCounter.TotalRxByteCount= 0; ++ pEntry->HSCounter.TotalTxByteCount= 0; ++ } ++#endif ++ ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Add WPA key process. ++ In Adhoc WPANONE, bPairwise = 0; KeyIdx = 0; ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuf Pointer to the where the key stored ++ ++ Return Value: ++ NDIS_SUCCESS Add key successfully ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#if 0 // remove by AlbertY ++NDIS_STATUS RTMPWPAAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf) ++{ ++ PNDIS_802_11_KEY pKey; ++ ULONG KeyIdx; ++// NDIS_STATUS Status; ++// ULONG offset; // unused variable, snowpin 2006.07.13 ++ ++ PUCHAR pTxMic, pRxMic; ++ BOOLEAN bTxKey; // Set the key as transmit key ++ BOOLEAN bPairwise; // Indicate the key is pairwise key ++ BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. ++ // Otherwise, it will set by the NIC. ++ BOOLEAN bAuthenticator; // indicate key is set by authenticator. ++ UCHAR apidx = BSS0; ++ ++ pKey = (PNDIS_802_11_KEY) pBuf; ++ KeyIdx = pKey->KeyIndex & 0xff; ++ // Bit 31 of Add-key, Tx Key ++ bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; ++ // Bit 30 of Add-key PairwiseKey ++ bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; ++ // Bit 29 of Add-key KeyRSC ++ bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; ++ // Bit 28 of Add-key Authenticator ++ bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPAAddKeyProc==>pKey->KeyIndex = %x. bPairwise= %d\n", pKey->KeyIndex, bPairwise)); ++ // 1. Check Group / Pairwise Key ++ if (bPairwise) // Pairwise Key ++ { ++ // 1. KeyIdx must be 0, otherwise, return NDIS_STATUS_INVALID_DATA ++ if (KeyIdx != 0) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 2. Check bTx, it must be true, otherwise, return NDIS_STATUS_INVALID_DATA ++ if (bTxKey == FALSE) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 3. If BSSID is all 0xff, return NDIS_STATUS_INVALID_DATA ++ if (MAC_ADDR_EQUAL(pKey->BSSID, BROADCAST_ADDR)) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 3.1 Check Pairwise key length for TKIP key. For AES, it's always 128 bits ++ //if ((pAdapter->PortCfg.WepStatus == Ndis802_11Encryption2Enabled) && (pKey->KeyLength != LEN_TKIP_KEY)) ++ if ((pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) && (pKey->KeyLength != LEN_TKIP_KEY)) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ pAd->SharedKey[apidx][KeyIdx].Type = PAIRWISE_KEY; ++ ++ if (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA2) ++ { ++ // Send media specific event to start PMKID caching ++ RTMPIndicateWPA2Status(pAd); ++ } ++ } ++ else ++ { ++ // 1. Check BSSID, if not current BSSID or Bcast, return NDIS_STATUS_INVALID_DATA ++ if ((! MAC_ADDR_EQUAL(pKey->BSSID, BROADCAST_ADDR)) && ++ (! MAC_ADDR_EQUAL(pKey->BSSID, pAd->ApCfg.MBSSID[apidx].Bssid))) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 2. Check Key index for supported Group Key ++ if (KeyIdx >= GROUP_KEY_NUM) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 3. Set as default Tx Key if bTxKey is TRUE ++ if (bTxKey == TRUE) ++ pAd->ApCfg.MBSSID[apidx].DefaultKeyId = (UCHAR) KeyIdx; ++ ++ pAd->SharedKey[apidx][KeyIdx].Type = GROUP_KEY; ++ } ++ ++ // 4. Select RxMic / TxMic based on Supp / Authenticator ++ if (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ // for WPA-None Tx, Rx MIC is the same ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pRxMic = pTxMic; ++ } ++ else if (bAuthenticator == TRUE) ++ { ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; ++ } ++ else ++ { ++ pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; ++ } ++ ++ // 6. Check RxTsc ++ if (bKeyRSC == TRUE) ++ { ++ NdisMoveMemory(pAd->SharedKey[apidx][KeyIdx].RxTsc, &pKey->KeyRSC, 6); ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.RxTsc, &pKey->KeyRSC, 6); ++ } ++ else ++ { ++ NdisZeroMemory(pAd->SharedKey[apidx][KeyIdx].RxTsc, 6); ++ } ++ ++ // 7. Copy information into Pairwise Key structure. ++ // pKey->KeyLength will include TxMic and RxMic, therefore, we use 16 bytes hardcoded. ++ pAd->SharedKey[apidx][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, 16); ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.Key, &pKey->KeyMaterial, 16); ++ if (pKey->KeyLength == LEN_TKIP_KEY) ++ { ++ // Only Key lenth equal to TKIP key have these ++ NdisMoveMemory(pAd->SharedKey[apidx][KeyIdx].RxMic, pRxMic, 8); ++ NdisMoveMemory(pAd->SharedKey[apidx][KeyIdx].TxMic, pTxMic, 8); ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.RxMic, pRxMic, 8); ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxMic, pTxMic, 8); ++ } ++ ++ COPY_MAC_ADDR(pAd->SharedKey[BSS0][KeyIdx].BssId, pKey->BSSID); ++ ++ // Init TxTsc to one based on WiFi WPA specs ++ pAd->SharedKey[apidx][KeyIdx].TxTsc[0] = 1; ++ pAd->SharedKey[apidx][KeyIdx].TxTsc[1] = 0; ++ pAd->SharedKey[apidx][KeyIdx].TxTsc[2] = 0; ++ pAd->SharedKey[apidx][KeyIdx].TxTsc[3] = 0; ++ pAd->SharedKey[apidx][KeyIdx].TxTsc[4] = 0; ++ pAd->SharedKey[apidx][KeyIdx].TxTsc[5] = 0; ++ // 4. Init TxTsc to one based on WiFi WPA specs ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[0] = 1; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[1] = 0; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[2] = 0; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[3] = 0; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[4] = 0; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.TxTsc[5] = 0; ++ ++ if (pAd->ApCfg.MBSSID[apidx].WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_AES; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_AES; ++ } ++ else if (pAd->ApCfg.MBSSID[apidx].WepStatus == Ndis802_11Encryption2Enabled) ++ { ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_TKIP; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_TKIP; ++ } ++ else if (pAd->ApCfg.MBSSID[apidx].WepStatus == Ndis802_11Encryption1Enabled) ++ { ++ if (pAd->SharedKey[apidx][KeyIdx].KeyLen == 5) ++ { ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_WEP64; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_WEP64; ++ } ++ else if (pAd->SharedKey[apidx][KeyIdx].KeyLen == 13) ++ { ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_WEP128; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_WEP128; ++ } ++ else ++ { ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_NONE; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_NONE; ++ } ++ } ++ else ++ { ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_NONE; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = CIPHER_NONE; ++ } ++ ++ if ((pAd->OpMode == OPMODE_STA)) // Pairwise Key. Add BSSID to WCTable ++ { ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = pAd->SharedKey[BSS0][KeyIdx].KeyLen; ++ } ++ ++ if ((pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->ApCfg.MBSSID[apidx].AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // ++ // On WPA2, Update Group Key Cipher. ++ // ++ if (!bPairwise) ++ { ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_AES; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg = CIPHER_TKIP; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->SharedKey[%d][%d].CipherAlg = %d\n", apidx, KeyIdx, pAd->SharedKey[apidx][KeyIdx].CipherAlg)); ++ ++#if 0 ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%s Key #%d", CipherName[pAd->SharedKey[apidx][KeyIdx].CipherAlg],KeyIdx)); ++ for (i = 0; i < 16; i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].Key[i])); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n Rx MIC Key = ")); ++ for (i = 0; i < 8; i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].RxMic[i])); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n Tx MIC Key = ")); ++ for (i = 0; i < 8; i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].TxMic[i])); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n RxTSC = ")); ++ for (i = 0; i < 6; i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("%02x:", pAd->SharedKey[apidx][KeyIdx].RxTsc[i])); ++ } ++#endif ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n pKey-> BSSID:%02x:%02x:%02x:%02x:%02x:%02x \n", ++ pKey->BSSID[0],pKey->BSSID[1],pKey->BSSID[2],pKey->BSSID[3],pKey->BSSID[4],pKey->BSSID[5])); ++ ++ if ((bTxKey) && (pAd->OpMode == OPMODE_STA)) // Pairwise Key. Add BSSID to WCTable ++ RTMPAddBSSIDCipher(pAd, BSSID_WCID, pKey, pAd->SharedKey[BSS0][KeyIdx].CipherAlg); ++ ++ ++ // No matter pairwise key or what leyidx is, always has a copy at on-chip SharedKeytable. ++ AsicAddSharedKeyEntry(pAd, ++ apidx, ++ (UCHAR)KeyIdx, ++ pAd->SharedKey[apidx][KeyIdx].CipherAlg, ++ pAd->SharedKey[apidx][KeyIdx].Key, ++ pAd->SharedKey[apidx][KeyIdx].TxMic, ++ pAd->SharedKey[apidx][KeyIdx].RxMic); ++ ++ // The WCID key specified in used at Tx. For STA, always use pairwise key. ++ ++ // ad-hoc mode need to specify WAP Group key with WCID index=BSS0Mcast_WCID. Let's always set this key here. ++/* if (bPairwise == FALSE) ++ { ++ offset = MAC_IVEIV_TABLE_BASE + (BSS0Mcast_WCID * HW_IVEIV_ENTRY_SIZE); ++ NdisZeroMemory(IVEIV, 8); ++ // 1. IV/EIV ++ // Specify key index to find shared key. ++ if ((pAd->SharedKey[BSS0][KeyIdx].CipherAlg==CIPHER_TKIP) || ++ (pAd->SharedKey[BSS0][KeyIdx].CipherAlg==CIPHER_AES)) ++ IVEIV[3] = 0x20; // Eiv bit on. keyid always 0 for pairwise key ++ IVEIV[3] |= (KeyIdx<< 6); // groupkey index is not 0 ++ for (i=0; i<8; i++) ++ { ++ RTMP_IO_WRITE8(pAd, offset+i, IVEIV[i]); ++ } ++ ++ // 2. WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:use share key, BSSIdx is 0 ++ WCIDAttri = (pAd->SharedKey[BSS0][KeyIdx].CipherAlg<<1)|PAIRWISEKEYTABLE; ++ offset = MAC_WCID_ATTRIBUTE_BASE + (BSS0Mcast_WCID* HW_WCID_ATTRI_SIZE); ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++ ++ } ++ ++*/ ++ ++ if (pAd->SharedKey[apidx][KeyIdx].Type == GROUP_KEY) ++ { ++ // 802.1x port control ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ DBGPRINT(RT_DEBUG_TRACE,("!!WPA_802_1X_PORT_SECURED!!\n")); ++ ++ } ++ ++ return (NDIS_STATUS_SUCCESS); ++} ++#endif ++ ++BOOLEAN RTMPCheckStrPrintAble( ++ IN CHAR *pInPutStr, ++ IN UCHAR strLen) ++{ ++ UCHAR i=0; ++ ++ for (i=0; i 0x7E)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Remove WPA Key process ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuf Pointer to the where the key stored ++ ++ Return Value: ++ NDIS_SUCCESS Add key successfully ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPSetDesiredRates( ++ IN PRTMP_ADAPTER pAdapter, ++ IN LONG Rates) ++{ ++ NDIS_802_11_RATES aryRates; ++ ++ memset(&aryRates, 0x00, sizeof(NDIS_802_11_RATES)); ++ switch (pAdapter->CommonCfg.PhyMode) ++ { ++ case PHY_11A: // A only ++ switch (Rates) ++ { ++ case 6000000: //6M ++ aryRates[0] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 9000000: //9M ++ aryRates[0] = 0x12; // 9M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 12000000: //12M ++ aryRates[0] = 0x18; // 12M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 18000000: //18M ++ aryRates[0] = 0x24; // 18M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 24000000: //24M ++ aryRates[0] = 0x30; // 24M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; ++ break; ++ case 36000000: //36M ++ aryRates[0] = 0x48; // 36M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; ++ break; ++ case 48000000: //48M ++ aryRates[0] = 0x60; // 48M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; ++ break; ++ case 54000000: //54M ++ aryRates[0] = 0x6c; // 54M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; ++ break; ++ case -1: //Auto ++ default: ++ aryRates[0] = 0x6c; // 54Mbps ++ aryRates[1] = 0x60; // 48Mbps ++ aryRates[2] = 0x48; // 36Mbps ++ aryRates[3] = 0x30; // 24Mbps ++ aryRates[4] = 0x24; // 18M ++ aryRates[5] = 0x18; // 12M ++ aryRates[6] = 0x12; // 9M ++ aryRates[7] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ break; ++ } ++ break; ++ case PHY_11BG_MIXED: // B/G Mixed ++ case PHY_11B: // B only ++ case PHY_11ABG_MIXED: // A/B/G Mixed ++ default: ++ switch (Rates) ++ { ++ case 1000000: //1M ++ aryRates[0] = 0x02; ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 2000000: //2M ++ aryRates[0] = 0x04; ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 5000000: //5.5M ++ aryRates[0] = 0x0b; // 5.5M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 11000000: //11M ++ aryRates[0] = 0x16; // 11M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 6000000: //6M ++ aryRates[0] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 9000000: //9M ++ aryRates[0] = 0x12; // 9M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 12000000: //12M ++ aryRates[0] = 0x18; // 12M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 18000000: //18M ++ aryRates[0] = 0x24; // 18M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 24000000: //24M ++ aryRates[0] = 0x30; // 24M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; ++ break; ++ case 36000000: //36M ++ aryRates[0] = 0x48; // 36M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; ++ break; ++ case 48000000: //48M ++ aryRates[0] = 0x60; // 48M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; ++ break; ++ case 54000000: //54M ++ aryRates[0] = 0x6c; // 54M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; ++ break; ++ case -1: //Auto ++ default: ++ if (pAdapter->CommonCfg.PhyMode == PHY_11B) ++ { //B Only ++ aryRates[0] = 0x16; // 11Mbps ++ aryRates[1] = 0x0b; // 5.5Mbps ++ aryRates[2] = 0x04; // 2Mbps ++ aryRates[3] = 0x02; // 1Mbps ++ } ++ else ++ { //(B/G) Mixed or (A/B/G) Mixed ++ aryRates[0] = 0x6c; // 54Mbps ++ aryRates[1] = 0x60; // 48Mbps ++ aryRates[2] = 0x48; // 36Mbps ++ aryRates[3] = 0x30; // 24Mbps ++ aryRates[4] = 0x16; // 11Mbps ++ aryRates[5] = 0x0b; // 5.5Mbps ++ aryRates[6] = 0x04; // 2Mbps ++ aryRates[7] = 0x02; // 1Mbps ++ } ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ break; ++ } ++ break; ++ } ++ ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, (" RTMPSetDesiredRates (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++} ++ ++NDIS_STATUS RTMPWPARemoveKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf) ++{ ++ PNDIS_802_11_REMOVE_KEY pKey; ++ ULONG KeyIdx; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ BOOLEAN bTxKey; // Set the key as transmit key ++ BOOLEAN bPairwise; // Indicate the key is pairwise key ++ BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. ++ // Otherwise, it will set by the NIC. ++ BOOLEAN bAuthenticator; // indicate key is set by authenticator. ++ INT i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("---> RTMPWPARemoveKeyProc\n")); ++ ++ pKey = (PNDIS_802_11_REMOVE_KEY) pBuf; ++ KeyIdx = pKey->KeyIndex & 0xff; ++ // Bit 31 of Add-key, Tx Key ++ bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; ++ // Bit 30 of Add-key PairwiseKey ++ bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; ++ // Bit 29 of Add-key KeyRSC ++ bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; ++ // Bit 28 of Add-key Authenticator ++ bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; ++ ++ // 1. If bTx is TRUE, return failure information ++ if (bTxKey == TRUE) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 2. Check Pairwise Key ++ if (bPairwise) ++ { ++ // a. If BSSID is broadcast, remove all pairwise keys. ++ // b. If not broadcast, remove the pairwise specified by BSSID ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ if (MAC_ADDR_EQUAL(pAd->SharedKey[BSS0][i].BssId, pKey->BSSID)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%d)\n", i)); ++ pAd->SharedKey[BSS0][i].KeyLen = 0; ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)i); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ } ++ } ++ // 3. Group Key ++ else ++ { ++ // a. If BSSID is broadcast, remove all group keys indexed ++ // b. If BSSID matched, delete the group key indexed. ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%ld)\n", KeyIdx)); ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx); ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ ++ return (Status); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Remove All WPA Keys ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPWPARemoveAllKeys( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ UCHAR i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveAllKeys(AuthMode=%d, WepStatus=%d)\n", pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus)); ++ ++ // For WEP/CKIP, there is no need to remove it, since WinXP won't set it again after ++ // Link up. And it will be replaced if user changed it. ++ if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return; ++ ++ // For WPA-None, there is no need to remove it, since WinXP won't set it again after ++ // Link up. And it will be replaced if user changed it. ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ return; ++ ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAd, BSS0, BSSID_WCID); ++ ++ // set all shared key mode as no-security. ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("remove %s key #%d\n", CipherName[pAd->SharedKey[BSS0][i].CipherAlg], i)); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][i], sizeof(CIPHER_KEY)); ++ ++ AsicRemoveSharedKeyEntry(pAd, BSS0, i); ++ } ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Change NIC PHY mode. Re-association may be necessary. possible settings ++ include - PHY_11B, PHY_11BG_MIXED, PHY_11A, and PHY_11ABG_MIXED ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPSetPhyMode( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG phymode) ++{ ++ INT i; ++ // the selected phymode must be supported by the RF IC encoded in E2PROM ++ ++ // if no change, do nothing ++ /* bug fix ++ if (pAd->CommonCfg.PhyMode == phymode) ++ return; ++ */ ++ pAd->CommonCfg.PhyMode = (UCHAR)phymode; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPSetPhyMode : PhyMode=%d, channel=%d \n", pAd->CommonCfg.PhyMode, pAd->CommonCfg.Channel)); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ BuildChannelListEx(pAd); ++#else ++ BuildChannelList(pAd); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // sanity check user setting ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->CommonCfg.Channel == pAd->ChannelList[i].Channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->CommonCfg.Channel = FirstChannel(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetPhyMode: channel is out of range, use first channel=%d \n", pAd->CommonCfg.Channel)); ++ } ++ ++ NdisZeroMemory(pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisZeroMemory(pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisZeroMemory(pAd->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ switch (phymode) { ++ case PHY_11B: ++ pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRateLen = 4; ++ pAd->CommonCfg.ExtRateLen = 0; ++ pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps ++ //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_CCK; // This MODE is only FYI. not use ++ break; ++ ++ case PHY_11G: ++ case PHY_11BG_MIXED: ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11N_2_4G: ++ case PHY_11ABGN_MIXED: ++ case PHY_11BGN_MIXED: ++ case PHY_11GN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[4] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[5] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[6] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRateLen = 8; ++ pAd->CommonCfg.ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[1] = 0x18; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[2] = 0x30; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[3] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRateLen = 4; ++ pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[4] = 12; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[5] = 18; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[6] = 24; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[7] = 36; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[8] = 48; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[9] = 72; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[10] = 96; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[11] = 108; // 54 mbps, in units of 0.5 Mbps ++ break; ++ ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AN_MIXED: ++ case PHY_11AGN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRateLen = 8; ++ pAd->CommonCfg.ExtRateLen = 0; ++ pAd->CommonCfg.DesireRate[0] = 12; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 18; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 24; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 36; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[4] = 48; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[5] = 72; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[6] = 96; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[7] = 108; // 54 mbps, in units of 0.5 Mbps ++ //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_OFDM; // This MODE is only FYI. not use ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++} ++ ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ======================================================================== ++ Routine Description: ++ Caller ensures we has 802.11n support. ++ Calls at setting HT from AP/STASetinformation ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ ======================================================================== ++*/ ++VOID RTMPSetHT( ++ IN PRTMP_ADAPTER pAd, ++ IN OID_SET_HT_PHYMODE *pHTPhyMode) ++{ ++ //ULONG *pmcs; ++ UINT32 Value = 0; ++ UCHAR BBPValue = 0; ++ UCHAR BBP3Value = 0; ++ UCHAR RxStream = pAd->CommonCfg.RxStream; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : HT_mode(%d), ExtOffset(%d), MCS(%d), BW(%d), STBC(%d), SHORTGI(%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, ++ pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ ++ // Don't zero supportedHyPhy structure. ++ RTMPZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); ++ RTMPZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); ++ RTMPZeroMemory(&pAd->CommonCfg.NewExtChanOffset, sizeof(pAd->CommonCfg.NewExtChanOffset)); ++ RTMPZeroMemory(&pAd->CommonCfg.DesiredHtPhy, sizeof(pAd->CommonCfg.DesiredHtPhy)); ++ ++ if (pAd->CommonCfg.bRdg) ++ { ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 1; ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 0; ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 0; ++ } ++ ++ pAd->CommonCfg.HtCapability.HtCapParm.MaxRAmpduFactor = 3; ++ pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor = 3; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : RxBAWinLimit = %d\n", pAd->CommonCfg.BACapability.field.RxBAWinLimit)); ++ ++ // Mimo power save, A-MSDU size, ++ pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize = (UCHAR)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.DesiredHtPhy.MimoPs = (UCHAR)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ ++ pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : AMsduSize = %d, MimoPs = %d, MpduDensity = %d, MaxRAmpduFactor = %d\n", ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize, ++ pAd->CommonCfg.DesiredHtPhy.MimoPs, ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity, ++ pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor)); ++ ++ if(pHTPhyMode->HtMode == HTMODE_GF) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.GF = 1; ++ pAd->CommonCfg.DesiredHtPhy.GF = 1; ++ } ++ else ++ pAd->CommonCfg.DesiredHtPhy.GF = 0; ++ ++ // Decide Rx MCSSet ++ switch (RxStream) ++ { ++ case 1: ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0x00; ++ break; ++ ++ case 2: ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; ++ break; ++ ++ case 3: // 3*3 ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[2] = 0xff; ++ break; ++ } ++ ++ if (pAd->CommonCfg.bForty_Mhz_Intolerant && (pAd->CommonCfg.Channel <= 14) && (pHTPhyMode->BW == BW_40) ) ++ { ++ pHTPhyMode->BW = BW_20; ++ pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant = 1; ++ } ++ ++ if(pHTPhyMode->BW == BW_40) ++ { ++ pAd->CommonCfg.HtCapability.MCSSet[4] = 0x1; // MCS 32 ++ pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 1; ++ if (pAd->CommonCfg.Channel <= 14) ++ pAd->CommonCfg.HtCapability.HtCapInfo.CCKmodein40 = 1; ++ ++ pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 1; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 1; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = (pHTPhyMode->ExtOffset == EXTCHA_BELOW)? (EXTCHA_BELOW): EXTCHA_ABOVE; ++ // Set Regsiter for extension channel position. ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBP3Value); ++ if ((pHTPhyMode->ExtOffset == EXTCHA_BELOW)) ++ { ++ Value |= 0x1; ++ BBP3Value |= (0x20); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ } ++ else if ((pHTPhyMode->ExtOffset == EXTCHA_ABOVE)) ++ { ++ Value &= 0xfe; ++ BBP3Value &= (~0x20); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ } ++ ++ // Turn on BBP 40MHz mode now only as AP . ++ // Sta can turn on BBP 40MHz after connection with 40MHz AP. Sta only broadcast 40MHz capability before connection. ++ if ((pAd->OpMode == OPMODE_AP) || INFRA_ON(pAd) || ADHOC_ON(pAd) ++ ) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBP3Value); ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 0; ++ pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 0; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 0; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = EXTCHA_NONE; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ // Turn on BBP 20MHz mode by request here. ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ } ++ } ++ ++ if(pHTPhyMode->STBC == STBC_USE) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 1; ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 1; ++ pAd->CommonCfg.HtCapability.HtCapInfo.RxSTBC = 1; ++ pAd->CommonCfg.DesiredHtPhy.RxSTBC = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; ++ pAd->CommonCfg.DesiredHtPhy.RxSTBC = 0; ++ } ++ ++#ifdef RT2870 ++ /* Frank recommend ,If not, Tx maybe block in high power. Rx has no problem*/ ++ if(IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 0; ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; ++ } ++#endif // RT2870 // ++ ++ if(pHTPhyMode->SHORTGI == GI_400) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 1; ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 1; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 1; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 0; ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 0; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 0; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 0; ++ } ++ ++ // We support link adaptation for unsolicit MCS feedback, set to 2. ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback = MCSFBK_NONE; //MCSFBK_UNSOLICIT; ++ pAd->CommonCfg.AddHTInfo.ControlChan = pAd->CommonCfg.Channel; ++ // 1, the extension channel above the control channel. ++ ++ // EDCA parameters used for AP's own transmission ++ if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) ++ { ++ pAd->CommonCfg.APEdcaParm.bValid = TRUE; ++ pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; ++ pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; ++ pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; ++ pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; ++ pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmax[0] = 6; ++ pAd->CommonCfg.APEdcaParm.Cwmax[1] = 10; ++ pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; ++ ++ pAd->CommonCfg.APEdcaParm.Txop[0] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[1] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[2] = 94; ++ pAd->CommonCfg.APEdcaParm.Txop[3] = 47; ++ } ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ RTMPSetIndividualHT(pAd, 0); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Caller ensures we has 802.11n support. ++ Calls at setting HT from AP/STASetinformation ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ ======================================================================== ++*/ ++VOID RTMPSetIndividualHT( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx) ++{ ++ PRT_HT_PHY_INFO pDesired_ht_phy = NULL; ++ UCHAR TxStream = pAd->CommonCfg.TxStream; ++ UCHAR DesiredMcs = MCS_AUTO; ++ ++ do ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pDesired_ht_phy = &pAd->StaCfg.DesiredHtPhyInfo; ++ DesiredMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; ++ //pAd->StaCfg.bAutoTxRateSwitch = (DesiredMcs == MCS_AUTO) ? TRUE : FALSE; ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } while (FALSE); ++ ++ if (pDesired_ht_phy == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetIndividualHT: invalid apidx(%d)\n", apidx)); ++ return; ++ } ++ RTMPZeroMemory(pDesired_ht_phy, sizeof(RT_HT_PHY_INFO)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetIndividualHT : Desired MCS = %d\n", DesiredMcs)); ++ // Check the validity of MCS ++ if ((TxStream == 1) && ((DesiredMcs >= MCS_8) && (DesiredMcs <= MCS_15))) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS(%d) is invalid in 1S, reset it as MCS_7\n", DesiredMcs)); ++ DesiredMcs = MCS_7; ++ } ++ ++ if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_20) && (DesiredMcs == MCS_32)) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS_32 is only supported in 40-MHz, reset it as MCS_0\n")); ++ DesiredMcs = MCS_0; ++ } ++ ++ pDesired_ht_phy->bHtEnable = TRUE; ++ ++ // Decide desired Tx MCS ++ switch (TxStream) ++ { ++ case 1: ++ if (DesiredMcs == MCS_AUTO) ++ { ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0x00; ++ } ++ else if (DesiredMcs <= MCS_7) ++ { ++ pDesired_ht_phy->MCSSet[0]= 1<MCSSet[1]= 0x00; ++ } ++ break; ++ ++ case 2: ++ if (DesiredMcs == MCS_AUTO) ++ { ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0xff; ++ } ++ else if (DesiredMcs <= MCS_15) ++ { ++ ULONG mode; ++ ++ mode = DesiredMcs / 8; ++ if (mode < 2) ++ pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); ++ } ++ break; ++ ++ case 3: // 3*3 ++ if (DesiredMcs == MCS_AUTO) ++ { ++ /* MCS0 ~ MCS23, 3 bytes */ ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0xff; ++ pDesired_ht_phy->MCSSet[2]= 0xff; ++ } ++ else if (DesiredMcs <= MCS_23) ++ { ++ ULONG mode; ++ ++ mode = DesiredMcs / 8; ++ if (mode < 3) ++ pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); ++ } ++ break; ++ } ++ ++ if(pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_40) ++ { ++ if (DesiredMcs == MCS_AUTO || DesiredMcs == MCS_32) ++ pDesired_ht_phy->MCSSet[4] = 0x1; ++ } ++ ++ // update HT Rate setting ++ if (pAd->OpMode == OPMODE_STA) ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ else ++ MlmeUpdateHtTxRates(pAd, apidx); ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Update HT IE from our capability. ++ ++ Arguments: ++ Send all HT IE in beacon/probe rsp/assoc rsp/action frame. ++ ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateHTIE( ++ IN RT_HT_CAPABILITY *pRtHt, ++ IN UCHAR *pMcsSet, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo) ++{ ++ RTMPZeroMemory(pHtCapability, sizeof(HT_CAPABILITY_IE)); ++ RTMPZeroMemory(pAddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ pHtCapability->HtCapInfo.ChannelWidth = pRtHt->ChannelWidth; ++ pHtCapability->HtCapInfo.MimoPs = pRtHt->MimoPs; ++ pHtCapability->HtCapInfo.GF = pRtHt->GF; ++ pHtCapability->HtCapInfo.ShortGIfor20 = pRtHt->ShortGIfor20; ++ pHtCapability->HtCapInfo.ShortGIfor40 = pRtHt->ShortGIfor40; ++ pHtCapability->HtCapInfo.TxSTBC = pRtHt->TxSTBC; ++ pHtCapability->HtCapInfo.RxSTBC = pRtHt->RxSTBC; ++ pHtCapability->HtCapInfo.AMsduSize = pRtHt->AmsduSize; ++ pHtCapability->HtCapParm.MaxRAmpduFactor = pRtHt->MaxRAmpduFactor; ++ pHtCapability->HtCapParm.MpduDensity = pRtHt->MpduDensity; ++ ++ pAddHtInfo->AddHtInfo.ExtChanOffset = pRtHt->ExtChanOffset ; ++ pAddHtInfo->AddHtInfo.RecomWidth = pRtHt->RecomWidth; ++ pAddHtInfo->AddHtInfo2.OperaionMode = pRtHt->OperaionMode; ++ pAddHtInfo->AddHtInfo2.NonGfPresent = pRtHt->NonGfPresent; ++ RTMPMoveMemory(pAddHtInfo->MCSSet, /*pRtHt->MCSSet*/pMcsSet, 4); // rt2860 only support MCS max=32, no need to copy all 16 uchar. ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPUpdateHTIE <== \n")); ++} ++#endif // DOT11_N_SUPPORT // ++ ++/* ++ ======================================================================== ++ Description: ++ Add Client security information into ASIC WCID table and IVEIV table. ++ Return: ++ ======================================================================== ++*/ ++VOID RTMPAddWcidAttributeEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ UINT32 WCIDAttri = 0; ++ USHORT offset; ++ UCHAR IVEIV = 0; ++ USHORT Wcid = 0; ++ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (BssIdx > BSS0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPAddWcidAttributeEntry: The BSS-index(%d) is out of range for Infra link. \n", BssIdx)); ++ return; ++ } ++ ++ // 1. In ADHOC mode, the AID is wcid number. And NO mesh link exists. ++ // 2. In Infra mode, the AID:1 MUST be wcid of infra STA. ++ // the AID:2~ assign to mesh link entry. ++ if (pEntry && ADHOC_ON(pAd)) ++ Wcid = pEntry->Aid; ++ else if (pEntry && INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry->ValidAsDls == TRUE) ++ Wcid = pEntry->Aid; ++ else ++#endif // QOS_DLS_SUPPORT // ++ Wcid = BSSID_WCID; ++ } ++ else ++ Wcid = MCAST_WCID; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // Update WCID attribute table ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pEntry && pEntry->ValidAsMesh) ++ WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; ++#ifdef QOS_DLS_SUPPORT ++ else if ((pEntry) && (pEntry->ValidAsDls) && ++ ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES) || ++ (CipherAlg == CIPHER_NONE))) ++ WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; ++#endif // QOS_DLS_SUPPORT // ++ else ++ WCIDAttri = (CipherAlg<<1) | SHAREDKEYTABLE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++ ++ ++ // Update IV/EIV table ++ offset = MAC_IVEIV_TABLE_BASE + (Wcid * HW_IVEIV_ENTRY_SIZE); ++ ++ // WPA mode ++ if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) || (CipherAlg == CIPHER_AES)) ++ { ++ // Eiv bit on. keyid always is 0 for pairwise key ++ IVEIV = (KeyIdx <<6) | 0x20; ++ } ++ else ++ { ++ // WEP KeyIdx is default tx key. ++ IVEIV = (KeyIdx << 6); ++ } ++ ++ // For key index and ext IV bit, so only need to update the position(offset+3). ++#ifdef RT2870 ++ RTUSBMultiWrite_OneByte(pAd, offset+3, &IVEIV); ++#endif // RT2870 // ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); ++ DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Parse encryption type ++Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ ========================================================================== ++*/ ++CHAR *GetEncryptType(CHAR enc) ++{ ++ if(enc == Ndis802_11WEPDisabled) ++ return "NONE"; ++ if(enc == Ndis802_11WEPEnabled) ++ return "WEP"; ++ if(enc == Ndis802_11Encryption2Enabled) ++ return "TKIP"; ++ if(enc == Ndis802_11Encryption3Enabled) ++ return "AES"; ++ if(enc == Ndis802_11Encryption4Enabled) ++ return "TKIPAES"; ++ else ++ return "UNKNOW"; ++} ++ ++CHAR *GetAuthMode(CHAR auth) ++{ ++ if(auth == Ndis802_11AuthModeOpen) ++ return "OPEN"; ++ if(auth == Ndis802_11AuthModeShared) ++ return "SHARED"; ++ if(auth == Ndis802_11AuthModeAutoSwitch) ++ return "AUTOWEP"; ++ if(auth == Ndis802_11AuthModeWPA) ++ return "WPA"; ++ if(auth == Ndis802_11AuthModeWPAPSK) ++ return "WPAPSK"; ++ if(auth == Ndis802_11AuthModeWPANone) ++ return "WPANONE"; ++ if(auth == Ndis802_11AuthModeWPA2) ++ return "WPA2"; ++ if(auth == Ndis802_11AuthModeWPA2PSK) ++ return "WPA2PSK"; ++ if(auth == Ndis802_11AuthModeWPA1WPA2) ++ return "WPA1WPA2"; ++ if(auth == Ndis802_11AuthModeWPA1PSKWPA2PSK) ++ return "WPA1PSKWPA2PSK"; ++ ++ return "UNKNOW"; ++} ++ ++#if 1 //#ifndef UCOS ++/* ++ ========================================================================== ++ Description: ++ Get site survey results ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) UI needs to wait 4 seconds after issue a site survey command ++ 2.) iwpriv ra0 get_site_survey ++ 3.) UI needs to prepare at least 4096bytes to get the results ++ ========================================================================== ++*/ ++#define LINE_LEN (4+33+20+8+10+9+7+3) // Channel+SSID+Bssid+WepStatus+AuthMode+Signal+WiressMode+NetworkType ++VOID RTMPIoctlGetSiteSurvey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *msg; ++ INT i=0; ++ INT WaitCnt; ++ INT Status=0; ++ CHAR Ssid[MAX_LEN_OF_SSID +1]; ++ INT Rssi = 0, max_len = LINE_LEN; ++ UINT Rssi_Quality = 0; ++ NDIS_802_11_NETWORK_TYPE wireless_mode; ++ ++ os_alloc_mem(NULL, (PUCHAR *)&msg, sizeof(CHAR)*((MAX_LEN_OF_BSS_TABLE)*max_len)); ++ ++ if (msg == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - msg memory alloc fail.\n")); ++ return; ++ } ++ ++ memset(msg, 0 ,(MAX_LEN_OF_BSS_TABLE)*max_len ); ++ memset(Ssid, 0 ,(MAX_LEN_OF_SSID +1)); ++ sprintf(msg,"%s","\n"); ++ sprintf(msg+strlen(msg),"%-4s%-33s%-20s%-8s%-10s%-9s%-7s%-3s\n", ++ "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", " NT"); ++ ++ ++ WaitCnt = 0; ++#ifdef CONFIG_STA_SUPPORT ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ while ((ScanRunning(pAdapter) == TRUE) && (WaitCnt++ < 200)) ++ OS_WAIT(500); ++#endif // CONFIG_STA_SUPPORT // ++ ++ for(i=0; iScanTab.BssNr ;i++) ++ { ++ if( pAdapter->ScanTab.BssEntry[i].Channel==0) ++ break; ++ ++ if((strlen(msg)+max_len ) >= IW_SCAN_MAX_DATA) ++ break; ++ ++ //Channel ++ sprintf(msg+strlen(msg),"%-4d", pAdapter->ScanTab.BssEntry[i].Channel); ++ //SSID ++ memcpy(Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ Ssid[pAdapter->ScanTab.BssEntry[i].SsidLen] = '\0'; ++ sprintf(msg+strlen(msg),"%-33s", Ssid); ++ //BSSID ++ sprintf(msg+strlen(msg),"%02x:%02x:%02x:%02x:%02x:%02x ", ++ pAdapter->ScanTab.BssEntry[i].Bssid[0], ++ pAdapter->ScanTab.BssEntry[i].Bssid[1], ++ pAdapter->ScanTab.BssEntry[i].Bssid[2], ++ pAdapter->ScanTab.BssEntry[i].Bssid[3], ++ pAdapter->ScanTab.BssEntry[i].Bssid[4], ++ pAdapter->ScanTab.BssEntry[i].Bssid[5]); ++ //Encryption Type ++ sprintf(msg+strlen(msg),"%-8s",GetEncryptType(pAdapter->ScanTab.BssEntry[i].WepStatus)); ++ //Authentication Mode ++ if (pAdapter->ScanTab.BssEntry[i].WepStatus == Ndis802_11WEPEnabled) ++ sprintf(msg+strlen(msg),"%-10s", "UNKNOW"); ++ else ++ sprintf(msg+strlen(msg),"%-10s",GetAuthMode(pAdapter->ScanTab.BssEntry[i].AuthMode)); ++ // Rssi ++ Rssi = (INT)pAdapter->ScanTab.BssEntry[i].Rssi; ++ if (Rssi >= -50) ++ Rssi_Quality = 100; ++ else if (Rssi >= -80) // between -50 ~ -80dbm ++ Rssi_Quality = (UINT)(24 + ((Rssi + 80) * 26)/10); ++ else if (Rssi >= -90) // between -80 ~ -90dbm ++ Rssi_Quality = (UINT)(((Rssi + 90) * 26)/10); ++ else // < -84 dbm ++ Rssi_Quality = 0; ++ sprintf(msg+strlen(msg),"%-9d", Rssi_Quality); ++ // Wireless Mode ++ wireless_mode = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ if (wireless_mode == Ndis802_11FH || ++ wireless_mode == Ndis802_11DS) ++ sprintf(msg+strlen(msg),"%-7s", "11b"); ++ else if (wireless_mode == Ndis802_11OFDM5) ++ sprintf(msg+strlen(msg),"%-7s", "11a"); ++ else if (wireless_mode == Ndis802_11OFDM5_N) ++ sprintf(msg+strlen(msg),"%-7s", "11a/n"); ++ else if (wireless_mode == Ndis802_11OFDM24) ++ sprintf(msg+strlen(msg),"%-7s", "11b/g"); ++ else if (wireless_mode == Ndis802_11OFDM24_N) ++ sprintf(msg+strlen(msg),"%-7s", "11b/g/n"); ++ else ++ sprintf(msg+strlen(msg),"%-7s", "unknow"); ++ //Network Type ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_ADHOC) ++ sprintf(msg+strlen(msg),"%-3s", " Ad"); ++ else ++ sprintf(msg+strlen(msg),"%-3s", " In"); ++ ++ sprintf(msg+strlen(msg),"\n"); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - wrq->u.data.length = %d\n", wrq->u.data.length)); ++ os_free_mem(NULL, (PUCHAR)msg); ++} ++ ++ ++#define MAC_LINE_LEN (14+4+4+10+10+10+6+6) // Addr+aid+psm+datatime+rxbyte+txbyte+current tx rate+last tx rate ++VOID RTMPIoctlGetMacTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq) ++{ ++ INT i; ++ RT_802_11_MAC_TABLE MacTab; ++ char *msg; ++ ++ MacTab.Num = 0; ++ for (i=0; iMacTab.Content[i].ValidAsCLI && (pAd->MacTab.Content[i].Sst == SST_ASSOC)) ++ { ++ COPY_MAC_ADDR(MacTab.Entry[MacTab.Num].Addr, &pAd->MacTab.Content[i].Addr); ++ MacTab.Entry[MacTab.Num].Aid = (UCHAR)pAd->MacTab.Content[i].Aid; ++ MacTab.Entry[MacTab.Num].Psm = pAd->MacTab.Content[i].PsMode; ++#ifdef DOT11_N_SUPPORT ++ MacTab.Entry[MacTab.Num].MimoPs = pAd->MacTab.Content[i].MmpsMode; ++#endif // DOT11_N_SUPPORT // ++ ++ // Fill in RSSI per entry ++ MacTab.Entry[MacTab.Num].AvgRssi0 = pAd->MacTab.Content[i].RssiSample.AvgRssi0; ++ MacTab.Entry[MacTab.Num].AvgRssi1 = pAd->MacTab.Content[i].RssiSample.AvgRssi1; ++ MacTab.Entry[MacTab.Num].AvgRssi2 = pAd->MacTab.Content[i].RssiSample.AvgRssi2; ++ ++ // the connected time per entry ++ MacTab.Entry[MacTab.Num].ConnectedTime = pAd->MacTab.Content[i].StaConnectTime; ++#if 0 // ToDo ++ MacTab.Entry[MacTab.Num].HSCounter.LastDataPacketTime = pAd->MacTab.Content[i].HSCounter.LastDataPacketTime; ++ MacTab.Entry[MacTab.Num].HSCounter.TotalRxByteCount = pAd->MacTab.Content[i].HSCounter.TotalRxByteCount; ++ MacTab.Entry[MacTab.Num].HSCounter.TotalTxByteCount = pAd->MacTab.Content[i].HSCounter.TotalTxByteCount; ++#endif ++ MacTab.Entry[MacTab.Num].TxRate.field.MCS = pAd->MacTab.Content[i].HTPhyMode.field.MCS; ++ MacTab.Entry[MacTab.Num].TxRate.field.BW = pAd->MacTab.Content[i].HTPhyMode.field.BW; ++ MacTab.Entry[MacTab.Num].TxRate.field.ShortGI = pAd->MacTab.Content[i].HTPhyMode.field.ShortGI; ++ MacTab.Entry[MacTab.Num].TxRate.field.STBC = pAd->MacTab.Content[i].HTPhyMode.field.STBC; ++ MacTab.Entry[MacTab.Num].TxRate.field.rsv = pAd->MacTab.Content[i].HTPhyMode.field.rsv; ++ MacTab.Entry[MacTab.Num].TxRate.field.MODE = pAd->MacTab.Content[i].HTPhyMode.field.MODE; ++ MacTab.Entry[MacTab.Num].TxRate.word = pAd->MacTab.Content[i].HTPhyMode.word; ++ ++ MacTab.Num += 1; ++ } ++ } ++ wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE); ++ if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); ++ } ++ ++ msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG); ++ memset(msg, 0 ,MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN ); ++ sprintf(msg,"%s","\n"); ++ sprintf(msg+strlen(msg),"%-14s%-4s%-4s%-10s%-10s%-10s%-6s%-6s\n", ++ "MAC", "AID", "PSM", "LDT", "RxB", "TxB","CTxR", "LTxR"); ++ ++ for (i=0; iMacTab.Content[i]; ++ if (pEntry->ValidAsCLI && (pEntry->Sst == SST_ASSOC)) ++ { ++ if((strlen(msg)+MAC_LINE_LEN ) >= (MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN) ) ++ break; ++ sprintf(msg+strlen(msg),"%02x%02x%02x%02x%02x%02x ", ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ sprintf(msg+strlen(msg),"%-4d", (int)pEntry->Aid); ++ sprintf(msg+strlen(msg),"%-4d", (int)pEntry->PsMode); ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.LastDataPacketTime*/); // ToDo ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalRxByteCount*/); // ToDo ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalTxByteCount*/); // ToDo ++ sprintf(msg+strlen(msg),"%-6d",RateIdToMbps[pAd->MacTab.Content[i].CurrTxRate]); ++ sprintf(msg+strlen(msg),"%-6d\n",0/*RateIdToMbps[pAd->MacTab.Content[i].LastTxRate]*/); // ToDo ++ } ++ } ++ // for compatible with old API just do the printk to console ++ //wrq->u.data.length = strlen(msg); ++ //if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s", msg)); ++ } ++ ++ kfree(msg); ++} ++#endif // UCOS // ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_BASetup_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++/* ++ The BASetup inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ //printk("\n%s\n", arg); ++ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > 15) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x\n", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nSetup BA Session: Tid = %d\n", tid); ++ BAOriSessionSetUp(pAd, pEntry, tid, 0, 100, TRUE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_BADecline_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG bBADecline; ++ ++ bBADecline = simple_strtol(arg, 0, 10); ++ ++ if (bBADecline == 0) ++ { ++ pAd->CommonCfg.bBADecline = FALSE; ++ } ++ else if (bBADecline == 1) ++ { ++ pAd->CommonCfg.bBADecline = TRUE; ++ } ++ else ++ { ++ return FALSE; //Invalid argument ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_BADecline_Proc::(BADecline=%d)\n", pAd->CommonCfg.bBADecline)); ++ ++ return TRUE; ++} ++ ++INT Set_BAOriTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BAOriTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > NUM_OF_TID) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nTear down Ori BA Session: Tid = %d\n", tid); ++ BAOriSessionTearDown(pAd, pEntry->Aid, tid, FALSE, TRUE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_BARecTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > NUM_OF_TID) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nTear down Rec BA Session: Tid = %d\n", tid); ++ BARecSessionTearDown(pAd, pEntry->Aid, tid, FALSE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtBw; ++ ++ HtBw = simple_strtol(arg, 0, 10); ++ if (HtBw == BW_40) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ else if (HtBw == BW_20) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBw_Proc::(HtBw=%d)\n", pAd->CommonCfg.RegTransmitSetting.field.BW)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtMcs, Mcs_tmp; ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN bAutoRate = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ Mcs_tmp = simple_strtol(arg, 0, 10); ++ ++ if (Mcs_tmp <= 15 || Mcs_tmp == 32) ++ HtMcs = Mcs_tmp; ++ else ++ HtMcs = MCS_AUTO; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = HtMcs; ++ pAd->StaCfg.bAutoTxRateSwitch = (HtMcs == MCS_AUTO) ? TRUE:FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(HtMcs=%d, bAutoTxRateSwitch = %d)\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS, pAd->StaCfg.bAutoTxRateSwitch)); ++ ++ if ((pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE < MODE_HTMIX)) ++ { ++ if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && ++ (HtMcs >= 0 && HtMcs <= 3) && ++ (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_CCK)) ++ { ++ RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs] * 1000000)); ++ } ++ else if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && ++ (HtMcs >= 0 && HtMcs <= 7) && ++ (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_OFDM)) ++ { ++ RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs+4] * 1000000)); ++ } ++ else ++ bAutoRate = TRUE; ++ ++ if (bAutoRate) ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ RTMPSetDesiredRates(pAd, -1); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(FixedTxMode=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode)); ++ } ++ if (ADHOC_ON(pAd)) ++ return TRUE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ SetCommonHT(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtGi; ++ ++ HtGi = simple_strtol(arg, 0, 10); ++ ++ if ( HtGi == GI_400) ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; ++ else if ( HtGi == GI_800 ) ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtGi_Proc::(ShortGI=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.ShortGI)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_HtTxBASize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR Size; ++ ++ Size = simple_strtol(arg, 0, 10); ++ ++ if (Size <=0 || Size >=64) ++ { ++ Size = 8; ++ } ++ pAd->CommonCfg.TxBASize = Size-1; ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_HtTxBASize ::(TxBASize= %d)\n", Size)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == HTMODE_GF) ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; ++ else if ( Value == HTMODE_MM ) ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtOpMode_Proc::(HtOpMode=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.HTMODE)); ++ ++ return TRUE; ++ ++} ++ ++INT Set_HtStbc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == STBC_USE) ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; ++ else if ( Value == STBC_NONE ) ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Stbc_Proc::(HtStbc=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.STBC)); ++ ++ return TRUE; ++} ++ ++INT Set_HtHtc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->HTCEnable = FALSE; ++ else if ( Value ==1 ) ++ pAd->HTCEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtHtc_Proc::(HtHtc=%d)\n",pAd->HTCEnable)); ++ ++ return TRUE; ++} ++ ++INT Set_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == 0) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ else if ( Value ==1 ) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtExtcha_Proc::(HtExtcha=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.EXTCHA)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value <=7 && Value >= 0) ++ pAd->CommonCfg.BACapability.field.MpduDensity = Value; ++ else ++ pAd->CommonCfg.BACapability.field.MpduDensity = 4; ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMpduDensity_Proc::(HtMpduDensity=%d)\n",pAd->CommonCfg.BACapability.field.MpduDensity)); ++ ++ return TRUE; ++} ++ ++INT Set_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ ++ if (Value >=1 && Value <= 64) ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; ++ } ++ else ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; ++ } ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBaWinSize_Proc::(HtBaWinSize=%d)\n",pAd->CommonCfg.BACapability.field.RxBAWinLimit)); ++ ++ return TRUE; ++} ++ ++INT Set_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == 0) ++ pAd->CommonCfg.bRdg = FALSE; ++ else if ( Value ==1 ) ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->CommonCfg.bRdg = TRUE; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtRdg_Proc::(HtRdg=%d)\n",pAd->CommonCfg.bRdg)); ++ ++ return TRUE; ++} ++ ++INT Set_HtLinkAdapt_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->bLinkAdapt = FALSE; ++ else if ( Value ==1 ) ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->bLinkAdapt = TRUE; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtLinkAdapt_Proc::(HtLinkAdapt=%d)\n",pAd->bLinkAdapt)); ++ ++ return TRUE; ++} ++ ++INT Set_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; ++ else if ( Value == 1 ) ++ pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAmsdu_Proc::(HtAmsdu=%d)\n",pAd->CommonCfg.BACapability.field.AmsduEnable)); ++ ++ return TRUE; ++} ++ ++INT Set_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAutoBa_Proc::(HtAutoBa=%d)\n",pAd->CommonCfg.BACapability.field.AutoBA)); ++ ++ return TRUE; ++ ++} ++ ++INT Set_HtProtect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.bHTProtect = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.bHTProtect = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtProtect_Proc::(HtProtect=%d)\n",pAd->CommonCfg.bHTProtect)); ++ ++ return TRUE; ++} ++ ++INT Set_SendPSMPAction_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], mode; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the mode value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and mode value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ mode = simple_strtol((token+1), 0, 10); ++ if (mode > MMPS_ENABLE) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], mode); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nSendPSMPAction MIPS mode = %d\n", mode); ++ SendPSMPAction(pAd, pEntry->Aid, mode); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++ ++} ++ ++INT Set_HtMIMOPSmode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value <=3 && Value >= 0) ++ pAd->CommonCfg.BACapability.field.MMPSmode = Value; ++ else ++ pAd->CommonCfg.BACapability.field.MMPSmode = 3; ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMIMOPSmode_Proc::(MIMOPS mode=%d)\n",pAd->CommonCfg.BACapability.field.MMPSmode)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_ForceShortGI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->WIFItestbed.bShortGI = FALSE; ++ else if (Value == 1) ++ pAd->WIFItestbed.bShortGI = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceShortGI_Proc::(ForceShortGI=%d)\n", pAd->WIFItestbed.bShortGI)); ++ ++ return TRUE; ++} ++ ++ ++ ++INT Set_ForceGF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->WIFItestbed.bGreenField = FALSE; ++ else if (Value == 1) ++ pAd->WIFItestbed.bGreenField = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceGF_Proc::(ForceGF=%d)\n", pAd->WIFItestbed.bGreenField)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMimoPs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.bMIMOPSEnable = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMimoPs_Proc::(HtMimoPs=%d)\n",pAd->CommonCfg.bMIMOPSEnable)); ++ ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++INT SetCommonHT( ++ IN PRTMP_ADAPTER pAd) ++{ ++ OID_SET_HT_PHYMODE SetHT; ++ ++ if (pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) ++ return FALSE; ++ ++ SetHT.PhyMode = pAd->CommonCfg.PhyMode; ++ SetHT.TransmitNo = ((UCHAR)pAd->Antenna.field.TxPath); ++ SetHT.HtMode = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.HTMODE; ++ SetHT.ExtOffset = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; ++ SetHT.MCS = MCS_AUTO; ++ SetHT.BW = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.BW; ++ SetHT.STBC = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.STBC; ++ SetHT.SHORTGI = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.ShortGI; ++ ++ RTMPSetHT(pAd, &SetHT); ++ ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_FixedTxMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR fix_tx_mode = FIXED_TXMODE_HT; ++ ++ if (strcmp(arg, "OFDM") == 0 || strcmp(arg, "ofdm") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_OFDM; ++ } ++ else if (strcmp(arg, "CCK") == 0 || strcmp(arg, "cck") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_CCK; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_FixedTxMode_Proc::(FixedTxMode=%d)\n", fix_tx_mode)); ++ ++ return TRUE; ++} ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++INT Set_OpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++#ifdef RT2870 ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++#endif // RT2870 // ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); ++ return FALSE; ++ } ++ ++ if (Value == 0) ++ pAd->OpMode = OPMODE_STA; ++ else if (Value == 1) ++ pAd->OpMode = OPMODE_AP; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_OpMode_Proc::(OpMode=%s)\n", pAd->OpMode == 1 ? "AP Mode" : "STA Mode")); ++ ++ return TRUE; ++} ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++ ++///////////////////////////////////////////////////////////////////////// ++PCHAR RTMPGetRalinkAuthModeStr( ++ IN NDIS_802_11_AUTHENTICATION_MODE authMode) ++{ ++ switch(authMode) ++ { ++ case Ndis802_11AuthModeOpen: ++ return "OPEN"; ++ case Ndis802_11AuthModeWPAPSK: ++ return "WPAPSK"; ++ case Ndis802_11AuthModeShared: ++ return "SHARED"; ++ case Ndis802_11AuthModeWPA: ++ return "WPA"; ++ case Ndis802_11AuthModeWPA2: ++ return "WPA2"; ++ case Ndis802_11AuthModeWPA2PSK: ++ return "WPA2PSK"; ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ return "WPAPSKWPA2PSK"; ++ case Ndis802_11AuthModeWPA1WPA2: ++ return "WPA1WPA2"; ++ case Ndis802_11AuthModeWPANone: ++ return "WPANONE"; ++ default: ++ return "UNKNOW"; ++ } ++} ++ ++PCHAR RTMPGetRalinkEncryModeStr( ++ IN USHORT encryMode) ++{ ++ switch(encryMode) ++ { ++ case Ndis802_11WEPDisabled: ++ return "NONE"; ++ case Ndis802_11WEPEnabled: ++ return "WEP"; ++ case Ndis802_11Encryption2Enabled: ++ return "TKIP"; ++ case Ndis802_11Encryption3Enabled: ++ return "AES"; ++ case Ndis802_11Encryption4Enabled: ++ return "TKIPAES"; ++ default: ++ return "UNKNOW"; ++ } ++} ++ ++INT RTMPShowCfgValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pName, ++ IN PUCHAR pBuf) ++{ ++ INT Status = 0; ++ ++ for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) ++ { ++ if (!strcmp(pName, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name)) ++ { ++ if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->show_proc(pAd, pBuf)) ++ Status = -EINVAL; ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name == NULL) ++ { ++ sprintf(pBuf, "\n"); ++ for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) ++ sprintf(pBuf, "%s%s\n", pBuf, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); ++ } ++ ++ return Status; ++} ++ ++INT Show_SSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); ++#endif // CONFIG_STA_SUPPORT // ++ return 0; ++} ++ ++INT Show_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11BG_MIXED: ++ sprintf(pBuf, "\t11B/G"); ++ break; ++ case PHY_11B: ++ sprintf(pBuf, "\t11B"); ++ break; ++ case PHY_11A: ++ sprintf(pBuf, "\t11A"); ++ break; ++ case PHY_11ABG_MIXED: ++ sprintf(pBuf, "\t11A/B/G"); ++ break; ++ case PHY_11G: ++ sprintf(pBuf, "\t11G"); ++ break; ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++ sprintf(pBuf, "\t11A/B/G/N"); ++ break; ++ case PHY_11N_2_4G: ++ sprintf(pBuf, "\t11N only with 2.4G"); ++ break; ++ case PHY_11GN_MIXED: ++ sprintf(pBuf, "\t11G/N"); ++ break; ++ case PHY_11AN_MIXED: ++ sprintf(pBuf, "\t11A/N"); ++ break; ++ case PHY_11BGN_MIXED: ++ sprintf(pBuf, "\t11B/G/N"); ++ break; ++ case PHY_11AGN_MIXED: ++ sprintf(pBuf, "\t11A/G/N"); ++ break; ++ case PHY_11N_5G: ++ sprintf(pBuf, "\t11N only with 5G"); ++ break; ++#endif // DOT11_N_SUPPORT // ++ default: ++ sprintf(pBuf, "\tUnknow Value(%d)", pAd->CommonCfg.PhyMode); ++ break; ++ } ++ return 0; ++} ++ ++ ++INT Show_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bEnableTxBurst ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.TxPreamble) ++ { ++ case Rt802_11PreambleShort: ++ sprintf(pBuf, "\tShort"); ++ break; ++ case Rt802_11PreambleLong: ++ sprintf(pBuf, "\tLong"); ++ break; ++ case Rt802_11PreambleAuto: ++ sprintf(pBuf, "\tAuto"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.TxPreamble); ++ break; ++ } ++ ++ return 0; ++} ++ ++INT Show_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%lu", pAd->CommonCfg.TxPowerPercentage); ++ return 0; ++} ++ ++INT Show_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.Channel); ++ return 0; ++} ++ ++INT Show_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.UseBGProtection) ++ { ++ case 1: //Always On ++ sprintf(pBuf, "\tON"); ++ break; ++ case 2: //Always OFF ++ sprintf(pBuf, "\tOFF"); ++ break; ++ case 0: //AUTO ++ sprintf(pBuf, "\tAuto"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.UseBGProtection); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.RtsThreshold); ++ return 0; ++} ++ ++INT Show_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.FragmentThreshold); ++ return 0; ++} ++ ++#ifdef DOT11_N_SUPPORT ++INT Show_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ sprintf(pBuf, "\t40 MHz"); ++ } ++ else ++ { ++ sprintf(pBuf, "\t20 MHz"); ++ } ++ return 0; ++} ++ ++INT Show_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++#endif // CONFIG_STA_SUPPORT // ++ return 0; ++} ++ ++INT Show_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.ShortGI) ++ { ++ case GI_400: ++ sprintf(pBuf, "\tGI_400"); ++ break; ++ case GI_800: ++ sprintf(pBuf, "\tGI_800"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.ShortGI); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.HTMODE) ++ { ++ case HTMODE_GF: ++ sprintf(pBuf, "\tGF"); ++ break; ++ case HTMODE_MM: ++ sprintf(pBuf, "\tMM"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.HTMODE); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.EXTCHA) ++ { ++ case EXTCHA_BELOW: ++ sprintf(pBuf, "\tBelow"); ++ break; ++ case EXTCHA_ABOVE: ++ sprintf(pBuf, "\tAbove"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.EXTCHA); ++ break; ++ } ++ return 0; ++} ++ ++ ++INT Show_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.MpduDensity); ++ return 0; ++} ++ ++INT Show_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ return 0; ++} ++ ++INT Show_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bRdg ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AmsduEnable ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AutoBA ? "TRUE":"FALSE"); ++ return 0; ++} ++#endif // DOT11_N_SUPPORT // ++ ++INT Show_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegion); ++ return 0; ++} ++ ++INT Show_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegionForABand); ++ return 0; ++} ++ ++INT Show_CountryCode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.CountryCode); ++ return 0; ++} ++ ++#ifdef AGGREGATION_SUPPORT ++INT Show_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bAggregationCapable ? "TRUE":"FALSE"); ++ return 0; ++} ++#endif // AGGREGATION_SUPPORT // ++ ++#ifdef WMM_SUPPORT ++INT Show_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); ++#endif // CONFIG_STA_SUPPORT // ++ ++ return 0; ++} ++#endif // WMM_SUPPORT // ++ ++INT Show_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bIEEE80211H ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++INT Show_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->StaCfg.BssType) ++ { ++ case BSS_ADHOC: ++ sprintf(pBuf, "\tAdhoc"); ++ break; ++ case BSS_INFRA: ++ sprintf(pBuf, "\tInfra"); ++ break; ++ case BSS_ANY: ++ sprintf(pBuf, "\tAny"); ++ break; ++ case BSS_MONITOR: ++ sprintf(pBuf, "\tMonitor"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%d)", pAd->StaCfg.BssType); ++ break; ++ } ++ return 0; ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Show_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeOpen; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AuthMode = pAd->StaCfg.AuthMode; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((AuthMode >= Ndis802_11AuthModeOpen) && ++ (AuthMode <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ sprintf(pBuf, "\t%s", RTMPGetRalinkAuthModeStr(AuthMode)); ++ else ++ sprintf(pBuf, "\tUnknow Value(%d)", AuthMode); ++ ++ return 0; ++} ++ ++INT Show_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ NDIS_802_11_WEP_STATUS WepStatus = Ndis802_11WEPDisabled; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ WepStatus = pAd->StaCfg.WepStatus; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((WepStatus >= Ndis802_11WEPEnabled) && ++ (WepStatus <= Ndis802_11Encryption4KeyAbsent)) ++ sprintf(pBuf, "\t%s", RTMPGetRalinkEncryModeStr(WepStatus)); ++ else ++ sprintf(pBuf, "\tUnknow Value(%d)", WepStatus); ++ ++ return 0; ++} ++ ++INT Show_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ UCHAR DefaultKeyId = 0; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ DefaultKeyId = pAd->StaCfg.DefaultKeyId; ++#endif // CONFIG_STA_SUPPORT // ++ ++ sprintf(pBuf, "\t%d", DefaultKeyId); ++ ++ return 0; ++} ++ ++INT Show_WepKey_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN INT KeyIdx, ++ OUT PUCHAR pBuf) ++{ ++ UCHAR Key[16] = {0}, KeyLength = 0; ++ INT index = BSS0; ++ ++ KeyLength = pAd->SharedKey[index][KeyIdx].KeyLen; ++ NdisMoveMemory(Key, pAd->SharedKey[index][KeyIdx].Key, KeyLength); ++ ++ //check key string is ASCII or not ++ if (RTMPCheckStrPrintAble(Key, KeyLength)) ++ sprintf(pBuf, "\t%s", Key); ++ else ++ { ++ int idx; ++ sprintf(pBuf, "\t"); ++ for (idx = 0; idx < KeyLength; idx++) ++ sprintf(pBuf+strlen(pBuf), "%02X", Key[idx]); ++ } ++ return 0; ++} ++ ++INT Show_Key1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 0, pBuf); ++ return 0; ++} ++ ++INT Show_Key2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 1, pBuf); ++ return 0; ++} ++ ++INT Show_Key3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 2, pBuf); ++ return 0; ++} ++ ++INT Show_Key4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 3, pBuf); ++ return 0; ++} ++ ++INT Show_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ INT idx; ++ UCHAR PMK[32] = {0}; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); ++#endif // CONFIG_STA_SUPPORT // ++ ++ sprintf(pBuf, "\tPMK = "); ++ for (idx = 0; idx < 32; idx++) ++ sprintf(pBuf+strlen(pBuf), "%02X", PMK[idx]); ++ ++ return 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/cmm_sanity.c +@@ -0,0 +1,1663 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sanity.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 add WMM support ++*/ ++#include "../rt_config.h" ++ ++ ++extern UCHAR CISCO_OUI[]; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR BROADCOM_OUI[]; ++extern UCHAR WPS_OUI[]; ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeAddBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2) ++{ ++ PMLME_ADDBA_REQ_STRUCT pInfo; ++ ++ pInfo = (MLME_ADDBA_REQ_STRUCT *)Msg; ++ ++ if ((MsgLen != sizeof(MLME_ADDBA_REQ_STRUCT))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - The peer Mac is not associated yet.\n")); ++ return FALSE; ++ } ++ ++ /* ++ if ((pInfo->BaBufSize > MAX_RX_REORDERBUF) || (pInfo->BaBufSize < 2)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - Rx Reordering buffer too big or too small\n")); ++ return FALSE; ++ } ++ */ ++ ++ if ((pInfo->pAddr[0]&0x01) == 0x01) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - broadcast address not support BA\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeDelBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen) ++{ ++ MLME_DELBA_REQ_STRUCT *pInfo; ++ pInfo = (MLME_DELBA_REQ_STRUCT *)Msg; ++ ++ if ((MsgLen != sizeof(MLME_DELBA_REQ_STRUCT))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer Mac is not associated yet.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->TID & 0xf0)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer TID is incorrect.\n")); ++ return FALSE; ++ } ++ ++ if (NdisEqualMemory(pAd->MacTab.Content[pInfo->Wcid].Addr, pInfo->Addr, MAC_ADDR_LEN) == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - the peer addr dosen't exist.\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerAddBAReqActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_ADDBA_REQ pAddFrame; ++ pAddFrame = (PFRAME_ADDBA_REQ)(pMsg); ++ if (MsgLen < (sizeof(FRAME_ADDBA_REQ))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ // we support immediate BA. ++ *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); ++ pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); ++ pAddFrame->BaStartSeq.word = cpu2le16(pAddFrame->BaStartSeq.word); ++ ++ if (pAddFrame->BaParm.BAPolicy != IMMED_BA) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); ++ DBGPRINT(RT_DEBUG_ERROR,("ADDBA Request. tid=%x, Bufsize=%x, AMSDUSupported=%x \n", pAddFrame->BaParm.TID, pAddFrame->BaParm.BufSize, pAddFrame->BaParm.AMSDUSupported)); ++ return FALSE; ++ } ++ ++ // we support immediate BA. ++ if (pAddFrame->BaParm.TID &0xfff0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request incorrect TID = %d\n", pAddFrame->BaParm.TID)); ++ return FALSE; ++ } ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ return TRUE; ++} ++ ++BOOLEAN PeerAddBARspActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen) ++{ ++ //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_ADDBA_RSP pAddFrame; ++ ++ pAddFrame = (PFRAME_ADDBA_RSP)(pMsg); ++ if (MsgLen < (sizeof(FRAME_ADDBA_RSP))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ // we support immediate BA. ++ *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); ++ pAddFrame->StatusCode = cpu2le16(pAddFrame->StatusCode); ++ pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); ++ ++ if (pAddFrame->BaParm.BAPolicy != IMMED_BA) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Response Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); ++ return FALSE; ++ } ++ ++ // we support immediate BA. ++ if (pAddFrame->BaParm.TID &0xfff0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response incorrect TID = %d\n", pAddFrame->BaParm.TID)); ++ return FALSE; ++ } ++ return TRUE; ++ ++} ++ ++BOOLEAN PeerDelBAActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN VOID *pMsg, ++ IN ULONG MsgLen ) ++{ ++ //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_DELBA_REQ pDelFrame; ++ if (MsgLen != (sizeof(FRAME_DELBA_REQ))) ++ return FALSE; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ pDelFrame = (PFRAME_DELBA_REQ)(pMsg); ++ ++ *(USHORT *)(&pDelFrame->DelbaParm) = cpu2le16(*(USHORT *)(&pDelFrame->DelbaParm)); ++ pDelFrame->ReasonCode = cpu2le16(pDelFrame->ReasonCode); ++ ++ if (pDelFrame->DelbaParm.TID &0xfff0) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgChannel, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pBssType, ++ OUT USHORT *pBeaconPeriod, ++ OUT UCHAR *pChannel, ++ OUT UCHAR *pNewChannel, ++ OUT LARGE_INTEGER *pTimestamp, ++ OUT CF_PARM *pCfParm, ++ OUT USHORT *pAtimWin, ++ OUT USHORT *pCapabilityInfo, ++ OUT UCHAR *pErp, ++ OUT UCHAR *pDtimCount, ++ OUT UCHAR *pDtimPeriod, ++ OUT UCHAR *pBcastFlag, ++ OUT UCHAR *pMessageToMe, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT UCHAR *pCkipFlag, ++ OUT UCHAR *pAironetCellPowerLimit, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT PQBSS_LOAD_PARM pQbssLoad, ++ OUT PQOS_CAPABILITY_PARM pQosCapability, ++ OUT ULONG *pRalinkIe, ++ OUT UCHAR *pHtCapabilityLen, ++#ifdef CONFIG_STA_SUPPORT ++ OUT UCHAR *pPreNHtCapabilityLen, ++#endif // CONFIG_STA_SUPPORT // ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT UCHAR *AddHtInfoLen, ++ OUT ADD_HT_INFO_IE *AddHtInfo, ++ OUT UCHAR *NewExtChannelOffset, // Ht extension channel offset(above or below) ++ OUT USHORT *LengthVIE, ++ OUT PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ CHAR *Ptr; ++#ifdef CONFIG_STA_SUPPORT ++ CHAR TimLen; ++#endif // CONFIG_STA_SUPPORT // ++ PFRAME_802_11 pFrame; ++ PEID_STRUCT pEid; ++ UCHAR SubType; ++ UCHAR Sanity; ++ //UCHAR ECWMin, ECWMax; ++ //MAC_CSR9_STRUC Csr9; ++ ULONG Length = 0; ++ ++ // For some 11a AP which didn't have DS_IE, we use two conditions to decide the channel ++ // 1. If the AP is 11n enabled, then check the control channel. ++ // 2. If the AP didn't have any info about channel, use the channel we received this frame as the channel. (May inaccuracy!!) ++ UCHAR CtrlChannel = 0; ++ ++ // Add for 3 necessary EID field check ++ Sanity = 0; ++ ++ *pAtimWin = 0; ++ *pErp = 0; ++ *pDtimCount = 0; ++ *pDtimPeriod = 0; ++ *pBcastFlag = 0; ++ *pMessageToMe = 0; ++ *pExtRateLen = 0; ++ *pCkipFlag = 0; // Default of CkipFlag is 0 ++ *pAironetCellPowerLimit = 0xFF; // Default of AironetCellPowerLimit is 0xFF ++ *LengthVIE = 0; // Set the length of VIE to init value 0 ++ *pHtCapabilityLen = 0; // Set the length of VIE to init value 0 ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ *pPreNHtCapabilityLen = 0; // Set the length of VIE to init value 0 ++#endif // CONFIG_STA_SUPPORT // ++ *AddHtInfoLen = 0; // Set the length of VIE to init value 0 ++ *pRalinkIe = 0; ++ *pNewChannel = 0; ++ *NewExtChannelOffset = 0xff; //Default 0xff means no such IE ++ pCfParm->bValid = FALSE; // default: no IE_CF found ++ pQbssLoad->bValid = FALSE; // default: no IE_QBSS_LOAD found ++ pEdcaParm->bValid = FALSE; // default: no IE_EDCA_PARAMETER found ++ pQosCapability->bValid = FALSE; // default: no IE_QOS_CAPABILITY found ++ ++ pFrame = (PFRAME_802_11)Msg; ++ ++ // get subtype from header ++ SubType = (UCHAR)pFrame->Hdr.FC.SubType; ++ ++ // get Addr2 and BSSID from header ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ COPY_MAC_ADDR(pBssid, pFrame->Hdr.Addr3); ++ ++// hex_dump("Beacon", Msg, MsgLen); ++ ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ // get timestamp from payload and advance the pointer ++ NdisMoveMemory(pTimestamp, Ptr, TIMESTAMP_LEN); ++ ++ pTimestamp->u.LowPart = cpu2le32(pTimestamp->u.LowPart); ++ pTimestamp->u.HighPart = cpu2le32(pTimestamp->u.HighPart); ++ ++ Ptr += TIMESTAMP_LEN; ++ Length += TIMESTAMP_LEN; ++ ++ // get beacon interval from payload and advance the pointer ++ NdisMoveMemory(pBeaconPeriod, Ptr, 2); ++ Ptr += 2; ++ Length += 2; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ Length += 2; ++ ++ if (CAP_IS_ESS_ON(*pCapabilityInfo)) ++ *pBssType = BSS_INFRA; ++ else ++ *pBssType = BSS_ADHOC; ++ ++ pEid = (PEID_STRUCT) Ptr; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ // ++ // Secure copy VIE to VarIE[MAX_VIE_LEN] didn't overflow. ++ // ++ if ((*LengthVIE + pEid->Len + 2) >= MAX_VIE_LEN) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - Variable IEs out of resource [len(=%d) > MAX_VIE_LEN(=%d)]\n", ++ (*LengthVIE + pEid->Len + 2), MAX_VIE_LEN)); ++ break; ++ } ++ ++ switch(pEid->Eid) ++ { ++ case IE_SSID: ++ // Already has one SSID EID in this beacon, ignore the second one ++ if (Sanity & 0x1) ++ break; ++ if(pEid->Len <= MAX_LEN_OF_SSID) ++ { ++ NdisMoveMemory(Ssid, pEid->Octet, pEid->Len); ++ *pSsidLen = pEid->Len; ++ Sanity |= 0x1; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_SUPP_RATES: ++ if(pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ Sanity |= 0x2; ++ NdisMoveMemory(SupRate, pEid->Octet, pEid->Len); ++ *pSupRateLen = pEid->Len; ++ ++ // TODO: 2004-09-14 not a good design here, cause it exclude extra rates ++ // from ScanTab. We should report as is. And filter out unsupported ++ // rates in MlmeAux. ++ // Check against the supported rates ++ // RTMPCheckRates(pAd, SupRate, pSupRateLen); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! ++ { ++ NdisMoveMemory(pHtCapability, pEid->Octet, sizeof(HT_CAPABILITY_IE)); ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ *pPreNHtCapabilityLen = 0; // Nnow we only support 26 bytes. ++ ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_HT_CAP. pEid->Len = %d\n", pEid->Len)); ++ } ++ ++ break; ++ case IE_ADD_HT: ++ if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) ++ { ++ // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only ++ // copy first sizeof(ADD_HT_INFO_IE) ++ NdisMoveMemory(AddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ ++ CtrlChannel = AddHtInfo->ControlChan; ++ ++ *(USHORT *)(&AddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo2)); ++ *(USHORT *)(&AddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo3)); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_ADD_HT. \n")); ++ } ++ ++ break; ++ case IE_SECONDARY_CH_OFFSET: ++ if (pEid->Len == 1) ++ { ++ *NewExtChannelOffset = pEid->Octet[0]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); ++ } ++ ++ break; ++ case IE_FH_PARM: ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n")); ++ break; ++ ++ case IE_DS_PARM: ++ if(pEid->Len == 1) ++ { ++ *pChannel = *pEid->Octet; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ChannelSanity(pAd, *pChannel) == 0) ++ { ++ ++ return FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ Sanity |= 0x4; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_CF_PARM: ++ if(pEid->Len == 6) ++ { ++ pCfParm->bValid = TRUE; ++ pCfParm->CfpCount = pEid->Octet[0]; ++ pCfParm->CfpPeriod = pEid->Octet[1]; ++ pCfParm->CfpMaxDuration = pEid->Octet[2] + 256 * pEid->Octet[3]; ++ pCfParm->CfpDurRemaining = pEid->Octet[4] + 256 * pEid->Octet[5]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n")); ++ return FALSE; ++ } ++ break; ++ ++ case IE_IBSS_PARM: ++ if(pEid->Len == 2) ++ { ++ NdisMoveMemory(pAtimWin, pEid->Octet, pEid->Len); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_IBSS_PARM\n")); ++ return FALSE; ++ } ++ break; ++ ++#ifdef CONFIG_STA_SUPPORT ++ case IE_TIM: ++ if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) ++ { ++ GetTimBit((PUCHAR)pEid, pAd->StaActive.Aid, &TimLen, pBcastFlag, pDtimCount, pDtimPeriod, pMessageToMe); ++ } ++ break; ++#endif // CONFIG_STA_SUPPORT // ++ case IE_CHANNEL_SWITCH_ANNOUNCEMENT: ++ if(pEid->Len == 3) ++ { ++ *pNewChannel = pEid->Octet[1]; //extract new channel number ++ } ++ break; ++ ++ // New for WPA ++ // CCX v2 has the same IE, we need to parse that too ++ // Wifi WMM use the same IE vale, need to parse that too ++ // case IE_WPA: ++ case IE_VENDOR_SPECIFIC: ++ // Check Broadcom/Atheros 802.11n OUI version, for HT Capability IE. ++ // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. ++ /*if (NdisEqualMemory(pEid->Octet, BROADCOM_OUI, 3) && (pEid->Len >= 4)) ++ { ++ if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 30)) ++ { ++ { ++ NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. ++ } ++ } ++ if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 26)) ++ { ++ { ++ NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; // Nnow we only support 26 bytes. ++ } ++ } ++ } ++ */ ++ // Check the OUI version, filter out non-standard usage ++ if (NdisEqualMemory(pEid->Octet, RALINK_OUI, 3) && (pEid->Len == 7)) ++ { ++ //*pRalinkIe = pEid->Octet[3]; ++ if (pEid->Octet[3] != 0) ++ *pRalinkIe = pEid->Octet[3]; ++ else ++ *pRalinkIe = 0xf0000000; // Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. ++ } ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++ // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. ++ ++ // Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, ++ // Check broadcom-defiend pre-802.11nD1.0 OUI for HT related IE, including HT Capatilities IE and HT Information IE ++ else if ((*pHtCapabilityLen == 0) && NdisEqualMemory(pEid->Octet, PRE_N_HT_OUI, 3) && (pEid->Len >= 4) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if ((pEid->Octet[3] == OUI_PREN_HT_CAP) && (pEid->Len >= 30) && (*pHtCapabilityLen == 0)) ++ { ++ NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); ++ *pPreNHtCapabilityLen = SIZE_HT_CAP_IE; ++ } ++ ++ if ((pEid->Octet[3] == OUI_PREN_ADD_HT) && (pEid->Len >= 26)) ++ { ++ NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ { ++ // Copy to pVIE which will report to microsoft bssid list. ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++ else if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) ++ { ++ PUCHAR ptr; ++ int i; ++ ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ptr = &pEid->Octet[8]; ++ for (i=0; i<4; i++) ++ { ++ UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX ++ pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM ++ pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN ++ pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin ++ pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax ++ pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us ++ ptr += 4; // point to next AC ++ } ++ } ++ else if (NdisEqualMemory(pEid->Octet, WME_INFO_ELEM, 6) && (pEid->Len == 7)) ++ { ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ++ // use default EDCA parameter ++ pEdcaParm->bACM[QID_AC_BE] = 0; ++ pEdcaParm->Aifsn[QID_AC_BE] = 3; ++ pEdcaParm->Cwmin[QID_AC_BE] = CW_MIN_IN_BITS; ++ pEdcaParm->Cwmax[QID_AC_BE] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_BE] = 0; ++ ++ pEdcaParm->bACM[QID_AC_BK] = 0; ++ pEdcaParm->Aifsn[QID_AC_BK] = 7; ++ pEdcaParm->Cwmin[QID_AC_BK] = CW_MIN_IN_BITS; ++ pEdcaParm->Cwmax[QID_AC_BK] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_BK] = 0; ++ ++ pEdcaParm->bACM[QID_AC_VI] = 0; ++ pEdcaParm->Aifsn[QID_AC_VI] = 2; ++ pEdcaParm->Cwmin[QID_AC_VI] = CW_MIN_IN_BITS-1; ++ pEdcaParm->Cwmax[QID_AC_VI] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_VI] = 96; // AC_VI: 96*32us ~= 3ms ++ ++ pEdcaParm->bACM[QID_AC_VO] = 0; ++ pEdcaParm->Aifsn[QID_AC_VO] = 2; ++ pEdcaParm->Cwmin[QID_AC_VO] = CW_MIN_IN_BITS-2; ++ pEdcaParm->Cwmax[QID_AC_VO] = CW_MAX_IN_BITS-1; ++ pEdcaParm->Txop[QID_AC_VO] = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); ++ *pExtRateLen = pEid->Len; ++ ++ // TODO: 2004-09-14 not a good design here, cause it exclude extra rates ++ // from ScanTab. We should report as is. And filter out unsupported ++ // rates in MlmeAux. ++ // Check against the supported rates ++ // RTMPCheckRates(pAd, ExtRate, pExtRateLen); ++ } ++ break; ++ ++ case IE_ERP: ++ if (pEid->Len == 1) ++ { ++ *pErp = (UCHAR)pEid->Octet[0]; ++ } ++ break; ++ ++ case IE_AIRONET_CKIP: ++ // 0. Check Aironet IE length, it must be larger or equal to 28 ++ // Cisco AP350 used length as 28 ++ // Cisco AP12XX used length as 30 ++ if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) ++ break; ++ ++ // 1. Copy CKIP flag byte to buffer for process ++ *pCkipFlag = *(pEid->Octet + 8); ++ break; ++ ++ case IE_AP_TX_POWER: ++ // AP Control of Client Transmit Power ++ //0. Check Aironet IE length, it must be 6 ++ if (pEid->Len != 0x06) ++ break; ++ ++ // Get cell power limit in dBm ++ if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) ++ *pAironetCellPowerLimit = *(pEid->Octet + 4); ++ break; ++ ++ // WPA2 & 802.11i RSN ++ case IE_RSN: ++ // There is no OUI for version anymore, check the group cipher OUI before copying ++ if (RTMPEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ { ++ // Copy to pVIE which will report to microsoft bssid list. ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++ break; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ case IE_COUNTRY: ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ break; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ default: ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ // For some 11a AP. it did not have the channel EID, patch here ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ UCHAR LatchRfChannel = MsgChannel; ++ if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) ++ { ++ if (CtrlChannel != 0) ++ *pChannel = CtrlChannel; ++ else ++ *pChannel = LatchRfChannel; ++ Sanity |= 0x4; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (Sanity != 0x7) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", Sanity)); ++ return FALSE; ++ } ++ else ++ { ++ return TRUE; ++ } ++ ++} ++ ++#ifdef DOT11N_DRAFT3 ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check for some IE addressed in 802.11n d3.03. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerBeaconAndProbeRspSanity2( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *RegClass) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 pFrame; ++ PEID_STRUCT pEid; ++ ULONG Length = 0; ++ ++ pFrame = (PFRAME_802_11)Msg; ++ ++ *RegClass = 0; ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ // get timestamp from payload and advance the pointer ++ Ptr += TIMESTAMP_LEN; ++ Length += TIMESTAMP_LEN; ++ ++ // get beacon interval from payload and advance the pointer ++ Ptr += 2; ++ Length += 2; ++ ++ // get capability info from payload and advance the pointer ++ Ptr += 2; ++ Length += 2; ++ ++ pEid = (PEID_STRUCT) Ptr; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ switch(pEid->Eid) ++ { ++ case IE_SUPP_REG_CLASS: ++ if(pEid->Len > 0) ++ { ++ *RegClass = *pEid->Octet; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ return TRUE; ++ ++} ++#endif // DOT11N_DRAFT3 // ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeScanReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *pBssType, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pScanType) ++{ ++ MLME_SCAN_REQ_STRUCT *Info; ++ ++ Info = (MLME_SCAN_REQ_STRUCT *)(Msg); ++ *pBssType = Info->BssType; ++ *pSsidLen = Info->SsidLen; ++ NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); ++ *pScanType = Info->ScanType; ++ ++ if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC || *pBssType == BSS_ANY) ++ && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE ++#ifdef CONFIG_STA_SUPPORT ++ || *pScanType == SCAN_CISCO_PASSIVE || *pScanType == SCAN_CISCO_ACTIVE ++ || *pScanType == SCAN_CISCO_CHANNEL_LOAD || *pScanType == SCAN_CISCO_NOISE ++#endif // CONFIG_STA_SUPPORT // ++ )) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqSanity fail - wrong BssType or ScanType\n")); ++ return FALSE; ++ } ++} ++ ++// IRQL = DISPATCH_LEVEL ++UCHAR ChannelSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++{ ++ int i; ++ ++ for (i = 0; i < pAd->ChannelListNum; i ++) ++ { ++ if (channel == pAd->ChannelList[i].Channel) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerDeauthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pReason) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pReason, &pFrame->Octet[0], 2); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT USHORT *pAlg, ++ OUT USHORT *pSeq, ++ OUT USHORT *pStatus, ++ CHAR *pChlgText) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pAlg, &pFrame->Octet[0], 2); ++ NdisMoveMemory(pSeq, &pFrame->Octet[2], 2); ++ NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); ++ ++ if ((*pAlg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (*pAlg == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ { ++ if (*pSeq == 1 || *pSeq == 2) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); ++ return FALSE; ++ } ++ } ++ else if (*pAlg == Ndis802_11AuthModeShared) ++ { ++ if (*pSeq == 1 || *pSeq == 4) ++ { ++ return TRUE; ++ } ++ else if (*pSeq == 2 || *pSeq == 3) ++ { ++ NdisMoveMemory(pChlgText, &pFrame->Octet[8], CIPHER_TEXT_LEN); ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); ++ return FALSE; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong algorithm\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeAuthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT ULONG *pTimeout, ++ OUT USHORT *pAlg) ++{ ++ MLME_AUTH_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_AUTH_REQ_STRUCT *)Msg; ++ COPY_MAC_ADDR(pAddr, pInfo->Addr); ++ *pTimeout = pInfo->Timeout; ++ *pAlg = pInfo->Alg; ++ ++ if (((*pAlg == Ndis802_11AuthModeShared) ||(*pAlg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (*pAlg == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) && ++ ((*pAddr & 0x01) == 0)) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAuthReqSanity fail - wrong algorithm\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeAssocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pApAddr, ++ OUT USHORT *pCapabilityInfo, ++ OUT ULONG *pTimeout, ++ OUT USHORT *pListenIntv) ++{ ++ MLME_ASSOC_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_ASSOC_REQ_STRUCT *)Msg; ++ *pTimeout = pInfo->Timeout; // timeout ++ COPY_MAC_ADDR(pApAddr, pInfo->Addr); // AP address ++ *pCapabilityInfo = pInfo->CapabilityInfo; // capability info ++ *pListenIntv = pInfo->ListenIntv; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerDisassocSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pReason) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pReason, &pFrame->Octet[0], 2); ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Sanity check NetworkType (11b, 11g or 11a) ++ ++ Arguments: ++ pBss - Pointer to BSS table. ++ ++ Return Value: ++ Ndis802_11DS .......(11b) ++ Ndis802_11OFDM24....(11g) ++ Ndis802_11OFDM5.....(11a) ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( ++ IN PBSS_ENTRY pBss) ++{ ++ NDIS_802_11_NETWORK_TYPE NetWorkType; ++ UCHAR rate, i; ++ ++ NetWorkType = Ndis802_11DS; ++ ++ if (pBss->Channel <= 14) ++ { ++ // ++ // First check support Rate. ++ // ++ for (i = 0; i < pBss->SupRateLen; i++) ++ { ++ rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit ++ if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) ++ { ++ continue; ++ } ++ else ++ { ++ // ++ // Otherwise (even rate > 108) means Ndis802_11OFDM24 ++ // ++ NetWorkType = Ndis802_11OFDM24; ++ break; ++ } ++ } ++ ++ // ++ // Second check Extend Rate. ++ // ++ if (NetWorkType != Ndis802_11OFDM24) ++ { ++ for (i = 0; i < pBss->ExtRateLen; i++) ++ { ++ rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit ++ if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) ++ { ++ continue; ++ } ++ else ++ { ++ // ++ // Otherwise (even rate > 108) means Ndis802_11OFDM24 ++ // ++ NetWorkType = Ndis802_11OFDM24; ++ break; ++ } ++ } ++ } ++ } ++ else ++ { ++ NetWorkType = Ndis802_11OFDM5; ++ } ++ ++ if (pBss->HtCapabilityLen != 0) ++ { ++ if (NetWorkType == Ndis802_11OFDM5) ++ NetWorkType = Ndis802_11OFDM5_N; ++ else ++ NetWorkType = Ndis802_11OFDM24_N; ++ } ++ ++ return NetWorkType; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ WPA message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN PeerWpaMessageSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN PEAPOL_PACKET pMsg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgType, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ UCHAR mic[LEN_KEY_DESC_MIC], digest[80], KEYDATA[MAX_LEN_OF_RSNIE]; ++ BOOLEAN bReplayDiff = FALSE; ++ BOOLEAN bWPA2 = FALSE; ++ KEY_INFO EapolKeyInfo; ++ UCHAR GroupKeyIndex = 0; ++ ++ ++ NdisZeroMemory(mic, sizeof(mic)); ++ NdisZeroMemory(digest, sizeof(digest)); ++ NdisZeroMemory(KEYDATA, sizeof(KEYDATA)); ++ NdisZeroMemory((PUCHAR)&EapolKeyInfo, sizeof(EapolKeyInfo)); ++ ++ NdisMoveMemory((PUCHAR)&EapolKeyInfo, (PUCHAR)&pMsg->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT *)&EapolKeyInfo) = cpu2le16(*((USHORT *)&EapolKeyInfo)); ++ ++ // Choose WPA2 or not ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ bWPA2 = TRUE; ++ ++ // 0. Check MsgType ++ if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("The message type is invalid(%d)! \n", MsgType)); ++ return FALSE; ++ } ++ ++ // 1. Replay counter check ++ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) // For supplicant ++ { ++ // First validate replay counter, only accept message with larger replay counter. ++ // Let equal pass, some AP start with all zero replay counter ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ if ((RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ { ++ bReplayDiff = TRUE; ++ } ++ } ++ else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) // For authenticator ++ { ++ // check Replay Counter coresponds to MSG from authenticator, otherwise discard ++ if (!NdisEqualMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY)) ++ { ++ bReplayDiff = TRUE; ++ } ++ } ++ ++ // Replay Counter different condition ++ if (bReplayDiff) ++ { ++ // send wireless event - for replay counter different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ if (MsgType < EAPOL_GROUP_MSG_1) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", MsgType)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); ++ } ++ ++ hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ hex_dump("Current replay counter ", pEntry->R_Counter, LEN_KEY_DESC_REPLAY); ++ return FALSE; ++ } ++ ++ // 2. Verify MIC except Pairwise Msg1 ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ { ++ UCHAR rcvd_mic[LEN_KEY_DESC_MIC]; ++ ++ // Record the received MIC for check later ++ NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ if (pEntry->WepStatus == Ndis802_11Encryption2Enabled) // TKIP ++ { ++ hmac_md5(pEntry->PTK, LEN_EAP_MICK, (PUCHAR)pMsg, MsgLen, mic); ++ } ++ else if (pEntry->WepStatus == Ndis802_11Encryption3Enabled) // AES ++ { ++ HMAC_SHA1((PUCHAR)pMsg, MsgLen, pEntry->PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); ++ } ++ ++ if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC)) ++ { ++ // send wireless event - for MIC different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_MIC_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ if (MsgType < EAPOL_GROUP_MSG_1) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in pairwise msg %d of 4-way handshake!\n", MsgType)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); ++ } ++ ++ hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC); ++ hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC); ++ ++ return FALSE; ++ } ++ } ++ ++ // Extract the context of the Key Data field if it exist ++ // The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is un-encrypted. ++ // The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted. ++ if (pMsg->KeyDesc.KeyDataLen[1] > 0) ++ { ++ // Decrypt this field ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ if(pEntry->WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ AES_GTK_KEY_UNWRAP(&pEntry->PTK[16], KEYDATA, pMsg->KeyDesc.KeyDataLen[1],pMsg->KeyDesc.KeyData); ++ } ++ else ++ { ++ INT i; ++ UCHAR Key[32]; ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pMsg->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pEntry->PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); ++ } ++ ++ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) ++ GroupKeyIndex = EapolKeyInfo.KeyIndex; ++ ++ } ++ else if ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2)) ++ { ++ NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); ++ } ++ else ++ { ++ ++ return TRUE; ++ } ++ ++ // Parse Key Data field to ++ // 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2) ++ // 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2 ++ // 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2) ++ if (!RTMPParseEapolKeyData(pAd, KEYDATA, pMsg->KeyDesc.KeyDataLen[1], GroupKeyIndex, MsgType, bWPA2, pEntry)) ++ { ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN MlmeDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PRT_802_11_DLS *pDLS, ++ OUT PUSHORT pReason) ++{ ++ MLME_DLS_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_DLS_REQ_STRUCT *)Msg; ++ ++ *pDLS = pInfo->pDLS; ++ *pReason = pInfo->Reason; ++ ++ return TRUE; ++} ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN PeerDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pDlsTimeout, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ PEID_STRUCT eid_ptr; ++ ++ // to prevent caller from using garbage output value ++ *pCapabilityInfo = 0; ++ *pDlsTimeout = 0; ++ *pHtCapabilityLen = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pDlsTimeout, Ptr, 2); ++ Ptr += 2; ++ ++ // Category and Action field + DA + SA + capability + Timeout ++ eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; ++ ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_SUPP_RATES: ++ if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) ++ { ++ NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); ++ DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); ++ *pRatesLen = eid_ptr->Len; ++ } ++ else ++ { ++ *pRatesLen = 8; ++ Rates[0] = 0x82; ++ Rates[1] = 0x84; ++ Rates[2] = 0x8b; ++ Rates[3] = 0x96; ++ Rates[4] = 0x12; ++ Rates[5] = 0x24; ++ Rates[6] = 0x48; ++ Rates[7] = 0x6c; ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); ++ *pRatesLen = (*pRatesLen) + eid_ptr->Len; ++ } ++ else ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); ++ *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) ++ { ++ NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_HT_CAP\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerDlsRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ PEID_STRUCT eid_ptr; ++ ++ // to prevent caller from using garbage output value ++ *pStatus = 0; ++ *pCapabilityInfo = 0; ++ *pHtCapabilityLen = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get status code from payload and advance the pointer ++ NdisMoveMemory(pStatus, Ptr, 2); ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ if (pStatus == 0) ++ { ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ } ++ ++ // Category and Action field + status code + DA + SA + capability ++ eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; ++ ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_SUPP_RATES: ++ if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) ++ { ++ NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); ++ DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); ++ *pRatesLen = eid_ptr->Len; ++ } ++ else ++ { ++ *pRatesLen = 8; ++ Rates[0] = 0x82; ++ Rates[1] = 0x84; ++ Rates[2] = 0x8b; ++ Rates[3] = 0x96; ++ Rates[4] = 0x12; ++ Rates[5] = 0x24; ++ Rates[6] = 0x48; ++ Rates[7] = 0x6c; ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); ++ *pRatesLen = (*pRatesLen) + eid_ptr->Len; ++ } ++ else ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); ++ *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) ++ { ++ NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_HT_CAP\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerDlsTearDownSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pReason) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ ++ // to prevent caller from using garbage output value ++ *pReason = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get reason code from payload and advance the pointer ++ NdisMoveMemory(pReason, Ptr, 2); ++ Ptr += 2; ++ ++ return TRUE; ++} ++#endif // QOS_DLS_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/cmm_sync.c +@@ -0,0 +1,711 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sync.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 modified for rt2561/2661 ++*/ ++#include "../rt_config.h" ++ ++// 2.4 Ghz channel plan index in the TxPower arrays. ++#define BG_BAND_REGION_0_START 0 // 1,2,3,4,5,6,7,8,9,10,11 ++#define BG_BAND_REGION_0_SIZE 11 ++#define BG_BAND_REGION_1_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13 ++#define BG_BAND_REGION_1_SIZE 13 ++#define BG_BAND_REGION_2_START 9 // 10,11 ++#define BG_BAND_REGION_2_SIZE 2 ++#define BG_BAND_REGION_3_START 9 // 10,11,12,13 ++#define BG_BAND_REGION_3_SIZE 4 ++#define BG_BAND_REGION_4_START 13 // 14 ++#define BG_BAND_REGION_4_SIZE 1 ++#define BG_BAND_REGION_5_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 ++#define BG_BAND_REGION_5_SIZE 14 ++#define BG_BAND_REGION_6_START 2 // 3,4,5,6,7,8,9 ++#define BG_BAND_REGION_6_SIZE 7 ++#define BG_BAND_REGION_7_START 4 // 5,6,7,8,9,10,11,12,13 ++#define BG_BAND_REGION_7_SIZE 9 ++#define BG_BAND_REGION_31_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 ++#define BG_BAND_REGION_31_SIZE 14 ++ ++// 5 Ghz channel plan index in the TxPower arrays. ++UCHAR A_BAND_REGION_0_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_1_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++UCHAR A_BAND_REGION_2_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64}; ++UCHAR A_BAND_REGION_3_CHANNEL_LIST[]={52, 56, 60, 64, 149, 153, 157, 161}; ++UCHAR A_BAND_REGION_4_CHANNEL_LIST[]={149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_5_CHANNEL_LIST[]={149, 153, 157, 161}; ++UCHAR A_BAND_REGION_6_CHANNEL_LIST[]={36, 40, 44, 48}; ++UCHAR A_BAND_REGION_7_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_8_CHANNEL_LIST[]={52, 56, 60, 64}; ++UCHAR A_BAND_REGION_9_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_10_CHANNEL_LIST[]={36, 40, 44, 48, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_11_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161}; ++ ++//BaSizeArray follows the 802.11n definition as MaxRxFactor. 2^(13+factor) bytes. When factor =0, it's about Ba buffer size =8. ++UCHAR BaSizeArray[4] = {8,16,32,64}; ++ ++/* ++ ========================================================================== ++ Description: ++ Update StaCfg->ChannelList[] according to 1) Country Region 2) RF IC type, ++ and 3) PHY-mode user selected. ++ The outcome is used by driver when doing site survey. ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID BuildChannelList( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i, j, index=0, num=0; ++ PUCHAR pChannelList = NULL; ++ ++ NdisZeroMemory(pAd->ChannelList, MAX_NUM_OF_CHANNELS * sizeof(CHANNEL_TX_POWER)); ++ ++ // if not 11a-only mode, channel list starts from 2.4Ghz band ++ if ((pAd->CommonCfg.PhyMode != PHY_11A) ++#ifdef DOT11_N_SUPPORT ++ && (pAd->CommonCfg.PhyMode != PHY_11AN_MIXED) && (pAd->CommonCfg.PhyMode != PHY_11N_5G) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ switch (pAd->CommonCfg.CountryRegion & 0x7f) ++ { ++ case REGION_0_BG_BAND: // 1 -11 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_0_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_0_SIZE); ++ index += BG_BAND_REGION_0_SIZE; ++ break; ++ case REGION_1_BG_BAND: // 1 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_1_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_1_SIZE); ++ index += BG_BAND_REGION_1_SIZE; ++ break; ++ case REGION_2_BG_BAND: // 10 - 11 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_2_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_2_SIZE); ++ index += BG_BAND_REGION_2_SIZE; ++ break; ++ case REGION_3_BG_BAND: // 10 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_3_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_3_SIZE); ++ index += BG_BAND_REGION_3_SIZE; ++ break; ++ case REGION_4_BG_BAND: // 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_4_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_4_SIZE); ++ index += BG_BAND_REGION_4_SIZE; ++ break; ++ case REGION_5_BG_BAND: // 1 - 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_5_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_5_SIZE); ++ index += BG_BAND_REGION_5_SIZE; ++ break; ++ case REGION_6_BG_BAND: // 3 - 9 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_6_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_6_SIZE); ++ index += BG_BAND_REGION_6_SIZE; ++ break; ++ case REGION_7_BG_BAND: // 5 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_7_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_7_SIZE); ++ index += BG_BAND_REGION_7_SIZE; ++ break; ++ case REGION_31_BG_BAND: // 1 - 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_31_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_31_SIZE); ++ index += BG_BAND_REGION_31_SIZE; ++ break; ++ default: // Error. should never happen ++ break; ++ } ++ for (i=0; iChannelList[i].MaxTxPwr = 20; ++ } ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11A) || (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ switch (pAd->CommonCfg.CountryRegionForABand & 0x7f) ++ { ++ case REGION_0_A_BAND: ++ num = sizeof(A_BAND_REGION_0_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_0_CHANNEL_LIST; ++ break; ++ case REGION_1_A_BAND: ++ num = sizeof(A_BAND_REGION_1_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_1_CHANNEL_LIST; ++ break; ++ case REGION_2_A_BAND: ++ num = sizeof(A_BAND_REGION_2_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_2_CHANNEL_LIST; ++ break; ++ case REGION_3_A_BAND: ++ num = sizeof(A_BAND_REGION_3_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_3_CHANNEL_LIST; ++ break; ++ case REGION_4_A_BAND: ++ num = sizeof(A_BAND_REGION_4_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_4_CHANNEL_LIST; ++ break; ++ case REGION_5_A_BAND: ++ num = sizeof(A_BAND_REGION_5_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_5_CHANNEL_LIST; ++ break; ++ case REGION_6_A_BAND: ++ num = sizeof(A_BAND_REGION_6_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_6_CHANNEL_LIST; ++ break; ++ case REGION_7_A_BAND: ++ num = sizeof(A_BAND_REGION_7_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_7_CHANNEL_LIST; ++ break; ++ case REGION_8_A_BAND: ++ num = sizeof(A_BAND_REGION_8_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_8_CHANNEL_LIST; ++ break; ++ case REGION_9_A_BAND: ++ num = sizeof(A_BAND_REGION_9_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_9_CHANNEL_LIST; ++ break; ++ ++ case REGION_10_A_BAND: ++ num = sizeof(A_BAND_REGION_10_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_10_CHANNEL_LIST; ++ break; ++ ++ case REGION_11_A_BAND: ++ num = sizeof(A_BAND_REGION_11_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_11_CHANNEL_LIST; ++ break; ++ ++ default: // Error. should never happen ++ DBGPRINT(RT_DEBUG_WARN,("countryregion=%d not support", pAd->CommonCfg.CountryRegionForABand)); ++ break; ++ } ++ ++ if (num != 0) ++ { ++ UCHAR RadarCh[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ for (i=0; iTxPower[j].Channel) ++ NdisMoveMemory(&pAd->ChannelList[index+i], &pAd->TxPower[j], sizeof(CHANNEL_TX_POWER)); ++ } ++ for (j=0; j<15; j++) ++ { ++ if (pChannelList[i] == RadarCh[j]) ++ pAd->ChannelList[index+i].DfsReq = TRUE; ++ } ++ pAd->ChannelList[index+i].MaxTxPwr = 20; ++ } ++ index += num; ++ } ++ } ++ ++ pAd->ChannelListNum = index; ++ DBGPRINT(RT_DEBUG_TRACE,("country code=%d/%d, RFIC=%d, PHY mode=%d, support %d channels\n", ++ pAd->CommonCfg.CountryRegion, pAd->CommonCfg.CountryRegionForABand, pAd->RfIcType, pAd->CommonCfg.PhyMode, pAd->ChannelListNum)); ++#ifdef DBG ++ for (i=0;iChannelListNum;i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("BuildChannel # %d :: Pwr0 = %d, Pwr1 =%d, \n ", pAd->ChannelList[i].Channel, pAd->ChannelList[i].Power, pAd->ChannelList[i].Power2)); ++ } ++#endif ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine return the first channel number according to the country ++ code selection and RF IC selection (signal band or dual band). It is called ++ whenever driver need to start a site survey of all supported channels. ++ Return: ++ ch - the first channel number of current country code setting ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++UCHAR FirstChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return pAd->ChannelList[0].Channel; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine returns the next channel number. This routine is called ++ during driver need to start a site survey of all supported channels. ++ Return: ++ next_channel - the next channel number valid in current country code setting. ++ Note: ++ return 0 if no more next channel ++ ========================================================================== ++ */ ++UCHAR NextChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++{ ++ int i; ++ UCHAR next_channel = 0; ++ ++ for (i = 0; i < (pAd->ChannelListNum - 1); i++) ++ if (channel == pAd->ChannelList[i].Channel) ++ { ++ next_channel = pAd->ChannelList[i+1].Channel; ++ break; ++ } ++ return next_channel; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is for Cisco Compatible Extensions 2.X ++ Spec31. AP Control of Client Transmit Power ++ Return: ++ None ++ Note: ++ Required by Aironet dBm(mW) ++ 0dBm(1mW), 1dBm(5mW), 13dBm(20mW), 15dBm(30mW), ++ 17dBm(50mw), 20dBm(100mW) ++ ++ We supported ++ 3dBm(Lowest), 6dBm(10%), 9dBm(25%), 12dBm(50%), ++ 14dBm(75%), 15dBm(100%) ++ ++ The client station's actual transmit power shall be within +/- 5dB of ++ the minimum value or next lower value. ++ ========================================================================== ++ */ ++VOID ChangeToCellPowerLimit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AironetCellPowerLimit) ++{ ++ //valud 0xFF means that hasn't found power limit information ++ //from the AP's Beacon/Probe response. ++ if (AironetCellPowerLimit == 0xFF) ++ return; ++ ++ if (AironetCellPowerLimit < 6) //Used Lowest Power Percentage. ++ pAd->CommonCfg.TxPowerPercentage = 6; ++ else if (AironetCellPowerLimit < 9) ++ pAd->CommonCfg.TxPowerPercentage = 10; ++ else if (AironetCellPowerLimit < 12) ++ pAd->CommonCfg.TxPowerPercentage = 25; ++ else if (AironetCellPowerLimit < 14) ++ pAd->CommonCfg.TxPowerPercentage = 50; ++ else if (AironetCellPowerLimit < 15) ++ pAd->CommonCfg.TxPowerPercentage = 75; ++ else ++ pAd->CommonCfg.TxPowerPercentage = 100; //else used maximum ++ ++ if (pAd->CommonCfg.TxPowerPercentage > pAd->CommonCfg.TxPowerDefault) ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ ++} ++ ++CHAR ConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ LNAGain = GET_LNA_GAIN(pAd); ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-12 - RssiOffset - LNAGain - Rssi); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan next channel ++ ========================================================================== ++ */ ++VOID ScanNextChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ HEADER_802_11 Hdr80211; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ UCHAR SsidLen = 0, ScanType = pAd->MlmeAux.ScanType, BBPValue = 0; ++#ifdef CONFIG_STA_SUPPORT ++ USHORT Status; ++ PHEADER_802_11 pHdr80211; ++#endif // CONFIG_STA_SUPPORT // ++ UINT ScanTimeIn5gChannel = SHORT_CHANNEL_TIME; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (MONITOR_ON(pAd)) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (pAd->MlmeAux.Channel == 0) ++ { ++ if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ++#ifdef CONFIG_STA_SUPPORT ++ && (INFRA_ON(pAd) ++ || (pAd->OpMode == OPMODE_AP)) ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); ++ } ++ else ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to channel %d, Total BSS[%02d]\n",pAd->CommonCfg.Channel, pAd->ScanTab.BssNr)); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // ++ // To prevent data lost. ++ // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. ++ // Now, we need to send an NULL data with turned PSM bit off to AP, when scan progress done ++ // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) ++ { ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ pHdr80211 = (PHEADER_802_11) pOutBuffer; ++ MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pHdr80211->Duration = 0; ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame\n")); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPusecDelay(5000); ++ } ++ } ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ } ++#ifdef RT2870 ++#ifdef CONFIG_STA_SUPPORT ++ else if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->OpMode == OPMODE_STA)) ++ { ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2870 // ++ else ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // BBP and RF are not accessible in PS mode, we has to wake them up first ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ ++ // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, TRUE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->MlmeAux.Channel > 14) ++ { ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) ++ { ++ ScanType = SCAN_PASSIVE; ++ ScanTimeIn5gChannel = MIN_CHANNEL_TIME; ++ } ++ } ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // carrier detection ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ ScanType = SCAN_PASSIVE; ++ ScanTimeIn5gChannel = MIN_CHANNEL_TIME; ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ //Global country domain(ch1-11:active scan, ch12-14 passive scan) ++ if ((pAd->MlmeAux.Channel <= 14) && (pAd->MlmeAux.Channel >= 12) && ((pAd->CommonCfg.CountryRegion & 0x7f) == REGION_31_BG_BAND)) ++ { ++ ScanType = SCAN_PASSIVE; ++ } ++ ++ // We need to shorten active scan time in order for WZC connect issue ++ // Chnage the channel scan time for CISCO stuff based on its IAPP announcement ++ if (ScanType == FAST_SCAN_ACTIVE) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, FAST_ACTIVE_SCAN_TIME); ++#ifdef CONFIG_STA_SUPPORT ++ else if (((ScanType == SCAN_CISCO_ACTIVE) || ++ (ScanType == SCAN_CISCO_PASSIVE) || ++ (ScanType == SCAN_CISCO_CHANNEL_LOAD) || ++ (ScanType == SCAN_CISCO_NOISE)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if (pAd->StaCfg.CCXScanTime < 25) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime * 2); ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ else // must be SCAN_PASSIVE or SCAN_ACTIVE ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ if (pAd->MlmeAux.Channel > 14) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, ScanTimeIn5gChannel); ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MIN_CHANNEL_TIME); ++ } ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MAX_CHANNEL_TIME); ++ } ++ ++ if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) || ++ (ScanType == SCAN_CISCO_ACTIVE)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - ScanNextChannel() allocate memory fail\n")); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return; ++ } ++ ++ // There is no need to send broadcast probe request if active scan is in effect. ++ if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) ++ ) ++ SsidLen = pAd->MlmeAux.SsidLen; ++ else ++ SsidLen = 0; ++ ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &SsidLen, ++ SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->CommonCfg.SupRateLen, ++ pAd->CommonCfg.SupRateLen, pAd->CommonCfg.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->CommonCfg.ExtRateLen) ++ { ++ ULONG Tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->CommonCfg.ExtRateLen, ++ pAd->CommonCfg.ExtRateLen, pAd->CommonCfg.ExtRate, ++ END_OF_ARGS); ++ FrameLen += Tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ ULONG Tmp; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ if (pAd->bBroadComHT == TRUE) ++ { ++ HtLen = pAd->MlmeAux.HtCapabilityLen + 4; ++#ifdef RT_BIG_ENDIAN ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#else ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++#endif // RT_BIG_ENDIAN // ++ } ++ else ++ { ++ HtLen = pAd->MlmeAux.HtCapabilityLen; ++#ifdef RT_BIG_ENDIAN ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, SIZE_HT_CAP_IE); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#else ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#endif // RT_BIG_ENDIAN // ++ } ++ FrameLen += Tmp; ++ ++#ifdef DOT11N_DRAFT3 ++ if (pAd->CommonCfg.BACapability.field.b2040CoexistScanSup == 1) ++ { ++ ULONG Tmp; ++ HtLen = 1; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtHtCapIe, ++ 1, &HtLen, ++ 1, &pAd->CommonCfg.BSSCoexist2040.word, ++ END_OF_ARGS); ++ ++ FrameLen += Tmp; ++ } ++#endif // DOT11N_DRAFT3 // ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ ++ // For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++} ++ ++VOID MgtProbReqMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SubType; ++ if (SubType == SUBTYPE_ACK) ++ pHdr80211->FC.Type = BTYPE_CNTL; ++ pHdr80211->FC.ToDs = ToDs; ++ COPY_MAC_ADDR(pHdr80211->Addr1, pDA); ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/cmm_wpa.c +@@ -0,0 +1,1654 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 03-07-22 Initial ++ Paul Lin 03-11-28 Modify for supplicant ++*/ ++#include "../rt_config.h" ++// WPA OUI ++UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; ++UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; ++UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; ++UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05}; ++UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; ++// WPA2 OUI ++UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; ++UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; ++UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; ++UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; ++UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; ++UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05}; ++// MSA OUI ++UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 ++UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The pseudo-random function(PRF) that hashes various inputs to ++ derive a pseudo-random value. To add liveness to the pseudo-random ++ value, a nonce should be one of the inputs. ++ ++ It is used to generate PTK, GTK or some specific random value. ++ ++ Arguments: ++ UCHAR *key, - the key material for HMAC_SHA1 use ++ INT key_len - the length of key ++ UCHAR *prefix - a prefix label ++ INT prefix_len - the length of the label ++ UCHAR *data - a specific data with variable length ++ INT data_len - the length of a specific data ++ INT len - the output lenght ++ ++ Return Value: ++ UCHAR *output - the calculated result ++ ++ Note: ++ 802.11i-2004 Annex H.3 ++ ++ ======================================================================== ++*/ ++VOID PRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *prefix, ++ IN INT prefix_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len) ++{ ++ INT i; ++ UCHAR *input; ++ INT currentindex = 0; ++ INT total_len; ++ ++ // Allocate memory for input ++ os_alloc_mem(NULL, (PUCHAR *)&input, 1024); ++ ++ if (input == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); ++ return; ++ } ++ ++ // Generate concatenation input ++ NdisMoveMemory(input, prefix, prefix_len); ++ ++ // Concatenate a single octet containing 0 ++ input[prefix_len] = 0; ++ ++ // Concatenate specific data ++ NdisMoveMemory(&input[prefix_len + 1], data, data_len); ++ total_len = prefix_len + 1 + data_len; ++ ++ // Concatenate a single octet containing 0 ++ // This octet shall be update later ++ input[total_len] = 0; ++ total_len++; ++ ++ // Iterate to calculate the result by hmac-sha-1 ++ // Then concatenate to last result ++ for (i = 0; i < (len + 19) / 20; i++) ++ { ++ HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); ++ currentindex += 20; ++ ++ // update the last octet ++ input[total_len - 1]++; ++ } ++ os_free_mem(NULL, input); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK. ++ It shall be called by 4-way handshake processing. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PMK - pointer to PMK ++ ANonce - pointer to ANonce ++ AA - pointer to Authenticator Address ++ SNonce - pointer to SNonce ++ SA - pointer to Supplicant Address ++ len - indicate the length of PTK (octet) ++ ++ Return Value: ++ Output pointer to the PTK ++ ++ Note: ++ Refer to IEEE 802.11i-2004 8.5.1.2 ++ ++ ======================================================================== ++*/ ++VOID WpaCountPTK( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *PMK, ++ IN UCHAR *ANonce, ++ IN UCHAR *AA, ++ IN UCHAR *SNonce, ++ IN UCHAR *SA, ++ OUT UCHAR *output, ++ IN UINT len) ++{ ++ UCHAR concatenation[76]; ++ UINT CurrPos = 0; ++ UCHAR temp[32]; ++ UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', ++ 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; ++ ++ // initiate the concatenation input ++ NdisZeroMemory(temp, sizeof(temp)); ++ NdisZeroMemory(concatenation, 76); ++ ++ // Get smaller address ++ if (RTMPCompareMemory(SA, AA, 6) == 1) ++ NdisMoveMemory(concatenation, AA, 6); ++ else ++ NdisMoveMemory(concatenation, SA, 6); ++ CurrPos += 6; ++ ++ // Get larger address ++ if (RTMPCompareMemory(SA, AA, 6) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], SA, 6); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], AA, 6); ++ ++ // store the larger mac address for backward compatible of ++ // ralink proprietary STA-key issue ++ NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN); ++ CurrPos += 6; ++ ++ // Get smaller Nonce ++ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) ++ NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue ++ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); ++ CurrPos += 32; ++ ++ // Get larger Nonce ++ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) ++ NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue ++ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); ++ CurrPos += 32; ++ ++ hex_dump("concatenation=", concatenation, 76); ++ ++ // Use PRF to generate PTK ++ PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Generate random number by software. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ macAddr - pointer to local MAC address ++ ++ Return Value: ++ ++ Note: ++ 802.1ii-2004 Annex H.5 ++ ++ ======================================================================== ++*/ ++VOID GenRandom( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *macAddr, ++ OUT UCHAR *random) ++{ ++ INT i, curr; ++ UCHAR local[80], KeyCounter[32]; ++ UCHAR result[80]; ++ ULONG CurrentTime; ++ UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; ++ ++ // Zero the related information ++ NdisZeroMemory(result, 80); ++ NdisZeroMemory(local, 80); ++ NdisZeroMemory(KeyCounter, 32); ++ ++ for (i = 0; i < 32; i++) ++ { ++ // copy the local MAC address ++ COPY_MAC_ADDR(local, macAddr); ++ curr = MAC_ADDR_LEN; ++ ++ // concatenate the current time ++ NdisGetSystemUpTime(&CurrentTime); ++ NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); ++ curr += sizeof(CurrentTime); ++ ++ // concatenate the last result ++ NdisMoveMemory(&local[curr], result, 32); ++ curr += 32; ++ ++ // concatenate a variable ++ NdisMoveMemory(&local[curr], &i, 2); ++ curr += 2; ++ ++ // calculate the result ++ PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); ++ } ++ ++ NdisMoveMemory(random, result, 32); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build cipher suite in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ WepStatus - indicate the encryption type ++ bMixCipher - a boolean to indicate the pairwise cipher and group ++ cipher are the same or not ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UINT WepStatus, ++ IN BOOLEAN bMixCipher, ++ IN UCHAR FlexibleCipher, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ UCHAR PairwiseCnt; ++ ++ *rsn_len = 0; ++ ++ // decide WPA2 or WPA1 ++ if (ElementID == Wpa2Ie) ++ { ++ RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; ++ ++ // Assign the verson as 1 ++ pRsnie_cipher->version = 1; ++ ++ switch (WepStatus) ++ { ++ // TKIP mode ++ case Ndis802_11Encryption2Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); ++ *rsn_len = sizeof(RSNIE2); ++ break; ++ ++ // AES mode ++ case Ndis802_11Encryption3Enabled: ++ if (bMixCipher) ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ else ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); ++ *rsn_len = sizeof(RSNIE2); ++ break; ++ ++ // TKIP-AES mix mode ++ case Ndis802_11Encryption4Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ ++ PairwiseCnt = 1; ++ // Insert WPA2 TKIP as the first pairwise cipher ++ if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); ++ // Insert WPA2 AES as the secondary pairwise cipher ++ if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); ++ PairwiseCnt = 2; ++ } ++ } ++ else ++ { ++ // Insert WPA2 AES as the first pairwise cipher ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); ++ } ++ ++ pRsnie_cipher->ucount = PairwiseCnt; ++ *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); ++ break; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) ++ { ++ UINT GroupCipher = pAd->StaCfg.GroupCipher; ++ switch(GroupCipher) ++ { ++ case Ndis802_11GroupWEP40Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP40, 4); ++ break; ++ case Ndis802_11GroupWEP104Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP104, 4); ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // swap for big-endian platform ++ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); ++ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); ++ } ++ else ++ { ++ RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; ++ ++ // Assign OUI and version ++ NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); ++ pRsnie_cipher->version = 1; ++ ++ switch (WepStatus) ++ { ++ // TKIP mode ++ case Ndis802_11Encryption2Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); ++ *rsn_len = sizeof(RSNIE); ++ break; ++ ++ // AES mode ++ case Ndis802_11Encryption3Enabled: ++ if (bMixCipher) ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ else ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); ++ *rsn_len = sizeof(RSNIE); ++ break; ++ ++ // TKIP-AES mix mode ++ case Ndis802_11Encryption4Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ ++ PairwiseCnt = 1; ++ // Insert WPA TKIP as the first pairwise cipher ++ if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); ++ // Insert WPA AES as the secondary pairwise cipher ++ if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); ++ PairwiseCnt = 2; ++ } ++ } ++ else ++ { ++ // Insert WPA AES as the first pairwise cipher ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); ++ } ++ ++ pRsnie_cipher->ucount = PairwiseCnt; ++ *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); ++ break; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) ++ { ++ UINT GroupCipher = pAd->StaCfg.GroupCipher; ++ switch(GroupCipher) ++ { ++ case Ndis802_11GroupWEP40Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP40, 4); ++ break; ++ case Ndis802_11GroupWEP104Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP104, 4); ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // swap for big-endian platform ++ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); ++ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build AKM suite in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ AuthMode - indicate the authentication mode ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeAKM( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UINT AuthMode, ++ IN UCHAR apidx, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ RSNIE_AUTH *pRsnie_auth; ++ ++ pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); ++ ++ // decide WPA2 or WPA1 ++ if (ElementID == Wpa2Ie) ++ { ++ switch (AuthMode) ++ { ++ case Ndis802_11AuthModeWPA2: ++ case Ndis802_11AuthModeWPA1WPA2: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPA2PSK: ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); ++ break; ++ } ++ } ++ else ++ { ++ switch (AuthMode) ++ { ++ case Ndis802_11AuthModeWPA: ++ case Ndis802_11AuthModeWPA1WPA2: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPAPSK: ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPANone: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); ++ break; ++ } ++ } ++ ++ pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount); ++ ++ (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build capability in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeCap( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UCHAR apidx, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ RSN_CAPABILITIES *pRSN_Cap; ++ ++ // it could be ignored in WPA1 mode ++ if (ElementID == WpaIe) ++ return; ++ ++ pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); ++ ++ ++ pRSN_Cap->word = cpu2le16(pRSN_Cap->word); ++ ++ (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build RSN IE context. It is not included element-ID and length. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ AuthMode - indicate the authentication mode ++ WepStatus - indicate the encryption type ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPMakeRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT AuthMode, ++ IN UINT WepStatus, ++ IN UCHAR apidx) ++{ ++ PUCHAR pRsnIe = NULL; // primary RSNIE ++ UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE ++ UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE ++ UCHAR PrimaryRsnie; ++ BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different ++ UCHAR p_offset; ++ WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode ++ ++ rsnielen_cur_p = NULL; ++ rsnielen_ex_cur_p = NULL; ++ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ if (AuthMode < Ndis802_11AuthModeWPA) ++ return; ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Support WPAPSK or WPA2PSK in STA-Infra mode ++ // Support WPANone in STA-Adhoc mode ++ if ((AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); ++ ++ // Zero RSNIE context ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); ++ ++ // Pointer to RSNIE ++ rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; ++ pRsnIe = pAd->StaCfg.RSN_IE; ++ ++ bMixCipher = pAd->StaCfg.bMixCipher; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // indicate primary RSNIE as WPA or WPA2 ++ if ((AuthMode == Ndis802_11AuthModeWPA) || ++ (AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (AuthMode == Ndis802_11AuthModeWPANone) || ++ (AuthMode == Ndis802_11AuthModeWPA1WPA2) || ++ (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ PrimaryRsnie = WpaIe; ++ else ++ PrimaryRsnie = Wpa2Ie; ++ ++ { ++ // Build the primary RSNIE ++ // 1. insert cipher suite ++ RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); ++ ++ // 2. insert AKM ++ RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); ++ ++ // 3. insert capability ++ RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); ++ } ++ ++ // 4. update the RSNIE length ++ *rsnielen_cur_p = p_offset; ++ ++ hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); ++ ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Check whether the received frame is EAP frame. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ pEntry - pointer to active entry ++ pData - the received frame ++ DataByteCount - the received frame's length ++ FromWhichBSSID - indicate the interface index ++ ++ Return: ++ TRUE - This frame is EAP frame ++ FALSE - otherwise ++ ========================================================================== ++*/ ++BOOLEAN RTMPCheckWPAframe( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR pData, ++ IN ULONG DataByteCount, ++ IN UCHAR FromWhichBSSID) ++{ ++ ULONG Body_len; ++ BOOLEAN Cancelled; ++ ++ ++ if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H)) ++ return FALSE; ++ ++ ++ // Skip LLC header ++ if (NdisEqualMemory(SNAP_802_1H, pData, 6) || ++ // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL ++ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) ++ { ++ pData += 6; ++ } ++ // Skip 2-bytes EAPoL type ++ if (NdisEqualMemory(EAPOL, pData, 2)) ++ { ++ pData += 2; ++ } ++ else ++ return FALSE; ++ ++ switch (*(pData+1)) ++ { ++ case EAPPacket: ++ Body_len = (*(pData+2)<<8) | (*(pData+3)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len)); ++ break; ++ case EAPOLStart: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n")); ++ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n")); ++ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ } ++ break; ++ case EAPOLLogoff: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n")); ++ break; ++ case EAPOLKey: ++ Body_len = (*(pData+2)<<8) | (*(pData+3)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len)); ++ break; ++ case EAPOLASFAlert: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n")); ++ break; ++ default: ++ return FALSE; ++ ++ } ++ return TRUE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ENCRYPT AES GTK before sending in EAPOL frame. ++ AES GTK length = 128 bit, so fix blocks for aes-key-wrap as 2 in this function. ++ This function references to RFC 3394 for aes key wrap algorithm. ++ Return: ++ ========================================================================== ++*/ ++VOID AES_GTK_KEY_WRAP( ++ IN UCHAR *key, ++ IN UCHAR *plaintext, ++ IN UCHAR p_len, ++ OUT UCHAR *ciphertext) ++{ ++ UCHAR A[8], BIN[16], BOUT[16]; ++ UCHAR R[512]; ++ INT num_blocks = p_len/8; // unit:64bits ++ INT i, j; ++ aes_context aesctx; ++ UCHAR xor; ++ ++ rtmp_aes_set_key(&aesctx, key, 128); ++ ++ // Init IA ++ for (i = 0; i < 8; i++) ++ A[i] = 0xa6; ++ ++ //Input plaintext ++ for (i = 0; i < num_blocks; i++) ++ { ++ for (j = 0 ; j < 8; j++) ++ R[8 * (i + 1) + j] = plaintext[8 * i + j]; ++ } ++ ++ // Key Mix ++ for (j = 0; j < 6; j++) ++ { ++ for(i = 1; i <= num_blocks; i++) ++ { ++ //phase 1 ++ NdisMoveMemory(BIN, A, 8); ++ NdisMoveMemory(&BIN[8], &R[8 * i], 8); ++ rtmp_aes_encrypt(&aesctx, BIN, BOUT); ++ ++ NdisMoveMemory(A, &BOUT[0], 8); ++ xor = num_blocks * j + i; ++ A[7] = BOUT[7] ^ xor; ++ NdisMoveMemory(&R[8 * i], &BOUT[8], 8); ++ } ++ } ++ ++ // Output ciphertext ++ NdisMoveMemory(ciphertext, A, 8); ++ ++ for (i = 1; i <= num_blocks; i++) ++ { ++ for (j = 0 ; j < 8; j++) ++ ciphertext[8 * i + j] = R[8 * i + j]; ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Misc function to decrypt AES body ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ This function references to RFC 3394 for aes key unwrap algorithm. ++ ++ ======================================================================== ++*/ ++VOID AES_GTK_KEY_UNWRAP( ++ IN UCHAR *key, ++ OUT UCHAR *plaintext, ++ IN UCHAR c_len, ++ IN UCHAR *ciphertext) ++ ++{ ++ UCHAR A[8], BIN[16], BOUT[16]; ++ UCHAR xor; ++ INT i, j; ++ aes_context aesctx; ++ UCHAR *R; ++ INT num_blocks = c_len/8; // unit:64bits ++ ++ ++ os_alloc_mem(NULL, (PUCHAR *)&R, 512); ++ ++ if (R == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); ++ return; ++ } /* End of if */ ++ ++ // Initialize ++ NdisMoveMemory(A, ciphertext, 8); ++ //Input plaintext ++ for(i = 0; i < (c_len-8); i++) ++ { ++ R[ i] = ciphertext[i + 8]; ++ } ++ ++ rtmp_aes_set_key(&aesctx, key, 128); ++ ++ for(j = 5; j >= 0; j--) ++ { ++ for(i = (num_blocks-1); i > 0; i--) ++ { ++ xor = (num_blocks -1 )* j + i; ++ NdisMoveMemory(BIN, A, 8); ++ BIN[7] = A[7] ^ xor; ++ NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); ++ rtmp_aes_decrypt(&aesctx, BIN, BOUT); ++ NdisMoveMemory(A, &BOUT[0], 8); ++ NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); ++ } ++ } ++ ++ // OUTPUT ++ for(i = 0; i < c_len; i++) ++ { ++ plaintext[i] = R[i]; ++ } ++ ++ ++ os_free_mem(NULL, R); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Report the EAP message type ++ ++ Arguments: ++ msg - EAPOL_PAIR_MSG_1 ++ EAPOL_PAIR_MSG_2 ++ EAPOL_PAIR_MSG_3 ++ EAPOL_PAIR_MSG_4 ++ EAPOL_GROUP_MSG_1 ++ EAPOL_GROUP_MSG_2 ++ ++ Return: ++ message type string ++ ++ ========================================================================== ++*/ ++CHAR *GetEapolMsgType(CHAR msg) ++{ ++ if(msg == EAPOL_PAIR_MSG_1) ++ return "Pairwise Message 1"; ++ else if(msg == EAPOL_PAIR_MSG_2) ++ return "Pairwise Message 2"; ++ else if(msg == EAPOL_PAIR_MSG_3) ++ return "Pairwise Message 3"; ++ else if(msg == EAPOL_PAIR_MSG_4) ++ return "Pairwise Message 4"; ++ else if(msg == EAPOL_GROUP_MSG_1) ++ return "Group Message 1"; ++ else if(msg == EAPOL_GROUP_MSG_2) ++ return "Group Message 2"; ++ else ++ return "Invalid Message"; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Sanity RSN IE of EAPoL message ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ IN MAC_TABLE_ENTRY *pEntry, ++ OUT UCHAR *Offset) ++{ ++ PUCHAR pVIE; ++ UCHAR len; ++ PEID_STRUCT pEid; ++ BOOLEAN result = FALSE; ++ ++ pVIE = pData; ++ len = DataLen; ++ *Offset = 0; ++ ++ while (len > sizeof(RSNIE2)) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // WPA RSN IE ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) ++ { ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) && ++ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && ++ (pEntry->RSNIE_Len == (pEid->Len + 2))) ++ { ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ // WPA2 RSN IE ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) ++ { ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) && ++ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && ++ (pEntry->RSNIE_Len == (pEid->Len + 2))/* ToDo-AlbertY for mesh*/) ++ { ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ else ++ { ++ break; ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ ++ ++ return result; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. ++ GTK is encaptulated in KDE format at p.83 802.11i D10 ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ 802.11i D10 ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPParseEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR GroupKeyIndex, ++ IN UCHAR MsgType, ++ IN BOOLEAN bWPA2, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ PKDE_ENCAP pKDE = NULL; ++ PUCHAR pMyKeyData = pKeyData; ++ UCHAR KeyDataLength = KeyDataLen; ++ UCHAR GTKLEN = 0; ++ UCHAR DefaultIdx = 0; ++ UCHAR skip_offset; ++ ++ // Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it ++ if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // Check RSN IE whether it is WPA2/WPA2PSK ++ if (!RTMPCheckRSNIE(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) ++ { ++ // send wireless event - for RSN IE different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_RSNIE_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in msg %d of 4-way handshake!\n", MsgType)); ++ hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen); ++ hex_dump("Desired RSN_IE ", pEntry->RSN_IE, pEntry->RSNIE_Len); ++ ++ return FALSE; ++ } ++ else ++ { ++ if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // skip RSN IE ++ pMyKeyData += skip_offset; ++ KeyDataLength -= skip_offset; ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); ++ } ++ else ++ return TRUE; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); ++ ++ // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 ++ if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ if (KeyDataLength >= 8) // KDE format exclude GTK length ++ { ++ pKDE = (PKDE_ENCAP) pMyKeyData; ++ ++ ++ DefaultIdx = pKDE->GTKEncap.Kid; ++ ++ // Sanity check - KED length ++ if (KeyDataLength < (pKDE->Len + 2)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); ++ return FALSE; ++ } ++ ++ // Get GTK length - refer to IEEE 802.11i-2004 p.82 ++ GTKLEN = pKDE->Len -6; ++ if (GTKLEN < LEN_AES_KEY) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); ++ return FALSE; ++ } ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KDE format length is too short \n")); ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN)); ++ // skip it ++ pMyKeyData += 8; ++ KeyDataLength -= 8; ++ ++ } ++ else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) ++ { ++ DefaultIdx = GroupKeyIndex; ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK DefaultKeyID=%d \n", DefaultIdx)); ++ } ++ ++ // Sanity check - shared key index must be 1 ~ 3 ++ if (DefaultIdx < 1 || DefaultIdx > 3) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index(%d) is invalid in %s %s \n", DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); ++ return FALSE; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ // Todo ++#endif // CONFIG_STA_SUPPORT // ++ ++ return TRUE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Construct EAPoL message for WPA handshaking ++ Its format is below, ++ ++ +--------------------+ ++ | Protocol Version | 1 octet ++ +--------------------+ ++ | Protocol Type | 1 octet ++ +--------------------+ ++ | Body Length | 2 octets ++ +--------------------+ ++ | Descriptor Type | 1 octet ++ +--------------------+ ++ | Key Information | 2 octets ++ +--------------------+ ++ | Key Length | 1 octet ++ +--------------------+ ++ | Key Repaly Counter | 8 octets ++ +--------------------+ ++ | Key Nonce | 32 octets ++ +--------------------+ ++ | Key IV | 16 octets ++ +--------------------+ ++ | Key RSC | 8 octets ++ +--------------------+ ++ | Key ID or Reserved | 8 octets ++ +--------------------+ ++ | Key MIC | 16 octets ++ +--------------------+ ++ | Key Data Length | 2 octets ++ +--------------------+ ++ | Key Data | n octets ++ +--------------------+ ++ ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ConstructEapolMsg( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AuthMode, ++ IN UCHAR WepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN UCHAR *ReplayCounter, ++ IN UCHAR *KeyNonce, ++ IN UCHAR *TxRSC, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_Len, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ BOOLEAN bWPA2 = FALSE; ++ ++ // Choose WPA2 or not ++ if ((AuthMode == Ndis802_11AuthModeWPA2) || (AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ bWPA2 = TRUE; ++ ++ // Init Packet and Fill header ++ pMsg->ProVer = EAPOL_VER; ++ pMsg->ProType = EAPOLKey; ++ ++ // Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field ++ pMsg->Body_Len[1] = LEN_EAPOL_KEY_MSG; ++ ++ // Fill in EAPoL descriptor ++ if (bWPA2) ++ pMsg->KeyDesc.Type = WPA2_KEY_DESC; ++ else ++ pMsg->KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 ++ // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used. ++ pMsg->KeyDesc.KeyInfo.KeyDescVer = ++ (((WepStatus == Ndis802_11Encryption3Enabled) || (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ // Specify Key Type as Group(0) or Pairwise(1) ++ if (MsgType >= EAPOL_GROUP_MSG_1) ++ pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY; ++ else ++ pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // Specify Key Index, only group_msg1_WPA1 ++ if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1)) ++ pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx; ++ ++ if (MsgType == EAPOL_PAIR_MSG_3) ++ pMsg->KeyDesc.KeyInfo.Install = 1; ++ ++ if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1)) ++ pMsg->KeyDesc.KeyInfo.KeyAck = 1; ++ ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ pMsg->KeyDesc.KeyInfo.KeyMic = 1; ++ ++ if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) || (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) ++ { ++ pMsg->KeyDesc.KeyInfo.Secure = 1; ++ } ++ ++ if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) ++ { ++ pMsg->KeyDesc.KeyInfo.EKD_DL = 1; ++ } ++ ++ // key Information element has done. ++ *(USHORT *)(&pMsg->KeyDesc.KeyInfo) = cpu2le16(*(USHORT *)(&pMsg->KeyDesc.KeyInfo)); ++ ++ // Fill in Key Length ++#if 0 ++ if (bWPA2) ++ { ++ // In WPA2 mode, the field indicates the length of pairwise key cipher, ++ // so only pairwise_msg_1 and pairwise_msg_3 need to fill. ++ if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3)) ++ pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); ++ } ++ else if (!bWPA2) ++#endif ++ { ++ if (MsgType >= EAPOL_GROUP_MSG_1) ++ { ++ // the length of group key cipher ++ pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH : LEN_AES_KEY); ++ } ++ else ++ { ++ // the length of pairwise key cipher ++ pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); ++ } ++ } ++ ++ // Fill in replay counter ++ NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Fill Key Nonce field ++ // ANonce : pairwise_msg1 & pairwise_msg3 ++ // SNonce : pairwise_msg2 ++ // GNonce : group_msg1_wpa1 ++ if ((MsgType <= EAPOL_PAIR_MSG_3) || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)))) ++ NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Fill key IV - WPA2 as 0, WPA1 as random ++ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ // Suggest IV be random number plus some number, ++ NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16], LEN_KEY_DESC_IV); ++ pMsg->KeyDesc.KeyIv[15] += 2; ++ } ++ ++ // Fill Key RSC field ++ // It contains the RSC for the GTK being installed. ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6); ++ } ++ ++ // Clear Key MIC field for MIC calculation later ++ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ ConstructEapolKeyData(pAd, ++ AuthMode, ++ WepStatus, ++ GroupKeyWepStatus, ++ MsgType, ++ DefaultKeyIdx, ++ bWPA2, ++ PTK, ++ GTK, ++ RSNIE, ++ RSNIE_Len, ++ pMsg); ++ ++ // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1. ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ { ++ CalculateMIC(pAd, WepStatus, PTK, pMsg); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); ++ DBGPRINT(RT_DEBUG_TRACE, (" Body length = %d \n", pMsg->Body_Len[1])); ++ DBGPRINT(RT_DEBUG_TRACE, (" Key length = %d \n", pMsg->KeyDesc.KeyLength[1])); ++ ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Construct the Key Data field of EAPoL message ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ConstructEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AuthMode, ++ IN UCHAR WepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN BOOLEAN bWPA2Capable, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_LEN, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ UCHAR *mpool, *Key_Data, *Rc4GTK; ++ UCHAR ekey[(LEN_KEY_DESC_IV+LEN_EAP_EK)]; ++ UCHAR data_offset; ++ ++ ++ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) ++ return; ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1500); ++ ++ if (mpool == NULL) ++ return; ++ ++ /* Rc4GTK Len = 512 */ ++ Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4); ++ /* Key_Data Len = 512 */ ++ Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4); ++ ++ NdisZeroMemory(Key_Data, 512); ++ pMsg->KeyDesc.KeyDataLen[1] = 0; ++ data_offset = 0; ++ ++ // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 ++ if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3))) ++ { ++ if (bWPA2Capable) ++ Key_Data[data_offset + 0] = IE_WPA2; ++ else ++ Key_Data[data_offset + 0] = IE_WPA; ++ ++ Key_Data[data_offset + 1] = RSNIE_LEN; ++ NdisMoveMemory(&Key_Data[data_offset + 2], RSNIE, RSNIE_LEN); ++ data_offset += (2 + RSNIE_LEN); ++ } ++ ++ // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 ++ if (bWPA2Capable && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) ++ { ++ // Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h ++ Key_Data[data_offset + 0] = 0xDD; ++ ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Key_Data[data_offset + 1] = 0x16;// 4+2+16(OUI+DataType+DataField) ++ } ++ else ++ { ++ Key_Data[data_offset + 1] = 0x26;// 4+2+32(OUI+DataType+DataField) ++ } ++ ++ Key_Data[data_offset + 2] = 0x00; ++ Key_Data[data_offset + 3] = 0x0F; ++ Key_Data[data_offset + 4] = 0xAC; ++ Key_Data[data_offset + 5] = 0x01; ++ ++ // GTK KDE format - 802.11i-2004 Figure-43x ++ Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03); ++ Key_Data[data_offset + 7] = 0x00; // Reserved Byte ++ ++ data_offset += 8; ++ } ++ ++ ++ // Encapsulate GTK and encrypt the key-data field with KEK. ++ // Only for pairwise_msg3_WPA2 and group_msg1 ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ // Fill in GTK ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ NdisMoveMemory(&Key_Data[data_offset], GTK, LEN_AES_KEY); ++ data_offset += LEN_AES_KEY; ++ } ++ else ++ { ++ NdisMoveMemory(&Key_Data[data_offset], GTK, TKIP_GTK_LENGTH); ++ data_offset += TKIP_GTK_LENGTH; ++ } ++ ++ // Still dont know why, but if not append will occur "GTK not include in MSG3" ++ // Patch for compatibility between zero config and funk ++ if (MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) ++ { ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Key_Data[data_offset + 0] = 0xDD; ++ Key_Data[data_offset + 1] = 0; ++ data_offset += 2; ++ } ++ else ++ { ++ Key_Data[data_offset + 0] = 0xDD; ++ Key_Data[data_offset + 1] = 0; ++ Key_Data[data_offset + 2] = 0; ++ Key_Data[data_offset + 3] = 0; ++ Key_Data[data_offset + 4] = 0; ++ Key_Data[data_offset + 5] = 0; ++ data_offset += 6; ++ } ++ } ++ ++ // Encrypt the data material in key data field ++ if (WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ AES_GTK_KEY_WRAP(&PTK[16], Key_Data, data_offset, Rc4GTK); ++ // AES wrap function will grow 8 bytes in length ++ data_offset += 8; ++ } ++ else ++ { ++ // PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV) ++ // put TxTsc in Key RSC field ++ pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. ++ ++ // ekey is the contanetion of IV-field, and PTK[16]->PTK[31] ++ NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv, LEN_KEY_DESC_IV); ++ NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &PTK[16], LEN_EAP_EK); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); //INIT SBOX, KEYLEN+3(IV) ++ pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data, data_offset); ++ WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK, Key_Data, data_offset); ++ } ++ ++ NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset); ++ } ++ else ++ { ++ NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset); ++ } ++ ++ // set key data length field and total length ++ pMsg->KeyDesc.KeyDataLen[1] = data_offset; ++ pMsg->Body_Len[1] += data_offset; ++ ++ os_free_mem(pAd, mpool); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calcaulate MIC. It is used during 4-ways handsharking. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PeerWepStatus - indicate the encryption type ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID CalculateMIC( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR *PTK, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ UCHAR *OutBuffer; ++ ULONG FrameLen = 0; ++ UCHAR mic[LEN_KEY_DESC_MIC]; ++ UCHAR digest[80]; ++ ++ // allocate memory for MIC calculation ++ os_alloc_mem(pAd, (PUCHAR *)&OutBuffer, 512); ++ ++ if (OutBuffer == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n")); ++ return; ++ } ++ ++ // make a frame for calculating MIC. ++ MakeOutgoingFrame(OutBuffer, &FrameLen, ++ pMsg->Body_Len[1] + 4, pMsg, ++ END_OF_ARGS); ++ ++ NdisZeroMemory(mic, sizeof(mic)); ++ ++ // Calculate MIC ++ if (PeerWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ HMAC_SHA1(OutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic); ++ } ++ ++ // store the calculated MIC ++ NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC); ++ ++ os_free_mem(pAd, OutBuffer); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Some received frames can't decrypt by Asic, so decrypt them by software. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PeerWepStatus - indicate the encryption type ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS - decryption successful ++ NDIS_STATUS_FAILURE - decryption failure ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPSoftDecryptBroadCastData( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, ++ IN PCIPHER_KEY pShard_key) ++{ ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ ++ ++ ++ // handle WEP decryption ++ if (GroupCipher == Ndis802_11Encryption1Enabled) ++ { ++ if (RTMPSoftDecryptWEP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, pShard_key)) ++ { ++ ++ //Minus IV[4] & ICV[4] ++ pRxWI->MPDUtotalByteCount -= 8; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : Software decrypt WEP data fails.\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ // handle TKIP decryption ++ else if (GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ if (RTMPSoftDecryptTKIP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, pShard_key)) ++ { ++ ++ //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV ++ pRxWI->MPDUtotalByteCount -= 20; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptTKIP Failed\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ // handle AES decryption ++ else if (GroupCipher == Ndis802_11Encryption3Enabled) ++ { ++ if (RTMPSoftDecryptAES(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount , pShard_key)) ++ { ++ ++ //8 bytes MIC, 8 bytes IV/EIV (CCMP Header) ++ pRxWI->MPDUtotalByteCount -= 16; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptAES Failed\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ else ++ { ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/dfs.c +@@ -0,0 +1,453 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ ap_dfs.c ++ ++ Abstract: ++ Support DFS function. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi 03-12-2007 created ++*/ ++ ++#include "../rt_config.h" ++ ++typedef struct _RADAR_DURATION_TABLE ++{ ++ ULONG RDDurRegion; ++ ULONG RadarSignalDuration; ++ ULONG Tolerance; ++} RADAR_DURATION_TABLE, *PRADAR_DURATION_TABLE; ++ ++ ++static UCHAR RdIdleTimeTable[MAX_RD_REGION][4] = ++{ ++ {9, 250, 250, 250}, // CE ++ {4, 250, 250, 250}, // FCC ++ {4, 250, 250, 250}, // JAP ++ {15, 250, 250, 250}, // JAP_W53 ++ {4, 250, 250, 250} // JAP_W56 ++}; ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Bbp Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID BbpRadarDetectionStart( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT8 RadarPeriod; ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 114, 0x02); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 121, 0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 122, 0x00); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 123, 0x08/*0x80*/); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 124, 0x28); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 125, 0xff); ++ ++#if 0 ++ // toggle Rx enable bit for radar detection. ++ // it's Andy's recommand. ++ { ++ UINT32 Value; ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (0x1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ Value &= ~(0x1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++#endif ++ RadarPeriod = ((UINT)RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + (UINT)pAd->CommonCfg.RadarDetect.DfsSessionTime) < 250 ? ++ (RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + pAd->CommonCfg.RadarDetect.DfsSessionTime) : 250; ++ ++ RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); ++ RTMP_IO_WRITE8(pAd, 0x7021, 0x40); ++ ++ RadarDetectionStart(pAd, 0, RadarPeriod); ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Bbp Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID BbpRadarDetectionStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); ++ RTMP_IO_WRITE8(pAd, 0x7021, 0x60); ++ ++ RadarDetectionStop(pAd); ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID RadarDetectionStart( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN CTSProtect, ++ IN UINT8 CTSPeriod) ++{ ++ UINT8 DfsActiveTime = (pAd->CommonCfg.RadarDetect.DfsSessionTime & 0x1f); ++ UINT8 CtsProtect = (CTSProtect == 1) ? 0x02 : 0x01; // CTS protect. ++ ++ if (CTSProtect != 0) ++ { ++ switch(pAd->CommonCfg.RadarDetect.RDDurRegion) ++ { ++ case FCC: ++ case JAP_W56: ++ CtsProtect = 0x03; ++ break; ++ ++ case CE: ++ case JAP_W53: ++ default: ++ CtsProtect = 0x02; ++ break; ++ } ++ } ++ else ++ CtsProtect = 0x01; ++ ++ ++ // send start-RD with CTS protection command to MCU ++ // highbyte [7] reserve ++ // highbyte [6:5] 0x: stop Carrier/Radar detection ++ // highbyte [10]: Start Carrier/Radar detection without CTS protection, 11: Start Carrier/Radar detection with CTS protection ++ // highbyte [4:0] Radar/carrier detection duration. In 1ms. ++ ++ // lowbyte [7:0] Radar/carrier detection period, in 1ms. ++ AsicSendCommandToMcu(pAd, 0x60, 0xff, CTSPeriod, DfsActiveTime | (CtsProtect << 5)); ++ //AsicSendCommandToMcu(pAd, 0x63, 0xff, 10, 0); ++ ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ TRUE Found radar signal ++ FALSE Not found radar signal ++ ++ ======================================================================== ++*/ ++VOID RadarDetectionStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("RadarDetectionStop.\n")); ++ AsicSendCommandToMcu(pAd, 0x60, 0xff, 0x00, 0x00); // send start-RD with CTS protection command to MCU ++ ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar channel check routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ TRUE need to do radar detect ++ FALSE need not to do radar detect ++ ++ ======================================================================== ++*/ ++BOOLEAN RadarChannelCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ch) ++{ ++#if 1 ++ INT i; ++ BOOLEAN result = FALSE; ++ ++ for (i=0; iChannelListNum; i++) ++ { ++ if (Ch == pAd->ChannelList[i].Channel) ++ { ++ result = pAd->ChannelList[i].DfsReq; ++ break; ++ } ++ } ++ ++ return result; ++#else ++ INT i; ++ UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ ++ for (i=0; i<15; i++) ++ { ++ if (Ch == Channel[i]) ++ { ++ break; ++ } ++ } ++ ++ if (i != 15) ++ return TRUE; ++ else ++ return FALSE; ++#endif ++} ++ ++ULONG JapRadarType( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ const UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ ++ if (pAd->CommonCfg.RadarDetect.RDDurRegion != JAP) ++ { ++ return pAd->CommonCfg.RadarDetect.RDDurRegion; ++ } ++ ++ for (i=0; i<15; i++) ++ { ++ if (pAd->CommonCfg.Channel == Channel[i]) ++ { ++ break; ++ } ++ } ++ ++ if (i < 4) ++ return JAP_W53; ++ else if (i < 15) ++ return JAP_W56; ++ else ++ return JAP; // W52 ++ ++} ++ ++ULONG RTMPBbpReadRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT8 byteValue = 0; ++ ULONG result; ++ ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R115, &byteValue); ++ ++ result = 0; ++ switch (byteValue) ++ { ++ case 1: // radar signal detected by pulse mode. ++ case 2: // radar signal detected by width mode. ++ result = RTMPReadRadarDuration(pAd); ++ break; ++ ++ case 0: // No radar signal. ++ default: ++ ++ result = 0; ++ break; ++ } ++ ++ return result; ++} ++ ++ULONG RTMPReadRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG result = 0; ++ ++#ifdef DFS_SUPPORT ++ UINT8 duration1 = 0, duration2 = 0, duration3 = 0; ++ ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R116, &duration1); ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R117, &duration2); ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R118, &duration3); ++ result = (duration1 << 16) + (duration2 << 8) + duration3; ++#endif // DFS_SUPPORT // ++ ++ return result; ++ ++} ++ ++VOID RTMPCleanRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Radar wave detection. The API should be invoke each second. ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID ApRadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i; ++ ++ pAd->CommonCfg.RadarDetect.InServiceMonitorCount++; ++ ++ for (i=0; iChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].RemainingTimeForUse > 0) ++ { ++ pAd->ChannelList[i].RemainingTimeForUse --; ++ if ((pAd->Mlme.PeriodicRound%5) == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RadarDetectPeriodic - ch=%d, RemainingTimeForUse=%d\n", pAd->ChannelList[i].Channel, pAd->ChannelList[i].RemainingTimeForUse)); ++ } ++ } ++ } ++ ++ //radar detect ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ RadarDetectPeriodic(pAd); ++ } ++ ++ return; ++} ++ ++// Periodic Radar detection, switch channel will occur in RTMPHandleTBTTInterrupt() ++// Before switch channel, driver needs doing channel switch announcement. ++VOID RadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // need to check channel availability, after switch channel ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_SILENCE_MODE) ++ return; ++ ++ // channel availability check time is 60sec, use 65 for assurance ++ if (pAd->CommonCfg.RadarDetect.RDCount++ > pAd->CommonCfg.RadarDetect.ChMovingTime) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Not found radar signal, start send beacon and radar detection in service monitor\n\n")); ++ BbpRadarDetectionStop(pAd); ++ AsicEnableBssSync(pAd); ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ ++ ++ return; ++ } ++ ++ return; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ change channel moving time for DFS testing. ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 set ChMovTime=[value] ++ ========================================================================== ++*/ ++INT Set_ChMovingTime_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT8 Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ pAd->CommonCfg.RadarDetect.ChMovingTime = Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ pAd->CommonCfg.RadarDetect.ChMovingTime)); ++ ++ return TRUE; ++} ++ ++INT Set_LongPulseRadarTh_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT8 Value; ++ ++ Value = simple_strtol(arg, 0, 10) > 10 ? 10 : simple_strtol(arg, 0, 10); ++ ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh)); ++ ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/eeprom.c +@@ -0,0 +1,254 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ eeprom.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#include "../rt_config.h" ++ ++#if 0 ++#define EEPROM_SIZE 0x200 ++#define NVRAM_OFFSET 0x30000 ++#define RF_OFFSET 0x40000 ++ ++static UCHAR init_flag = 0; ++static PUCHAR nv_ee_start = 0; ++ ++static UCHAR EeBuffer[EEPROM_SIZE]; ++#endif ++// IRQL = PASSIVE_LEVEL ++VOID RaiseClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x) ++{ ++ *x = *x | EESK; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); ++ RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID LowerClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x) ++{ ++ *x = *x & ~EESK; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); ++ RTMPusecDelay(1); ++} ++ ++// IRQL = PASSIVE_LEVEL ++USHORT ShiftInBits( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x,i; ++ USHORT data=0; ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~( EEDO | EEDI); ++ ++ for(i=0; i<16; i++) ++ { ++ data = data << 1; ++ RaiseClock(pAd, &x); ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EEDI); ++ if(x & EEDO) ++ data |= 1; ++ ++ LowerClock(pAd, &x); ++ } ++ ++ return data; ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID ShiftOutBits( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT data, ++ IN USHORT count) ++{ ++ UINT32 x,mask; ++ ++ mask = 0x01 << (count - 1); ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EEDO | EEDI); ++ ++ do ++ { ++ x &= ~EEDI; ++ if(data & mask) x |= EEDI; ++ ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ mask = mask >> 1; ++ } while(mask); ++ ++ x &= ~EEDI; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID EEpromCleanup( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EECS | EEDI); ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++} ++ ++VOID EWEN( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and six pulse in that order ++ ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); ++ ShiftOutBits(pAd, 0, 6); ++ ++ EEpromCleanup(pAd); ++} ++ ++VOID EWDS( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and six pulse in that order ++ ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); ++ ShiftOutBits(pAd, 0, 6); ++ ++ EEpromCleanup(pAd); ++} ++ ++// IRQL = PASSIVE_LEVEL ++USHORT RTMP_EEPROM_READ16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset) ++{ ++ UINT32 x; ++ USHORT data; ++ ++ Offset /= 2; ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and register number in that order ++ ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); ++ ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ++ ++ // Now read the data (16 bits) in from the selected EEPROM word ++ data = ShiftInBits(pAd); ++ ++ EEpromCleanup(pAd); ++ ++ return data; ++} //ReadEEprom ++ ++VOID RTMP_EEPROM_WRITE16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Data) ++{ ++ UINT32 x; ++ ++ Offset /= 2; ++ ++ EWEN(pAd); ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode ,register number and data in that order ++ ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); ++ ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ++ ShiftOutBits(pAd, Data, 16); // 16-bit access ++ ++ // read DO status ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ EEpromCleanup(pAd); ++ ++ RTMPusecDelay(10000); //delay for twp(MAX)=10ms ++ ++ EWDS(pAd); ++ ++ EEpromCleanup(pAd); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/firmware.h +@@ -0,0 +1,558 @@ ++/* ++ Copyright (c) 2007, Ralink Technology Corporation ++ All rights reserved. ++ ++ Redistribution. Redistribution and use in binary form, without ++ modification, are permitted provided that the following conditions are ++ met: ++ ++ * Redistributions must reproduce the above copyright notice and the ++ following disclaimer in the documentation and/or other materials ++ provided with the distribution. ++ * Neither the name of Ralink Technology Corporation nor the names of its ++ suppliers may be used to endorse or promote products derived from this ++ software without specific prior written permission. ++ * No reverse engineering, decompilation, or disassembly of this software ++ is permitted. ++ ++ Limited patent license. Ralink Technology Corporation grants a world-wide, ++ royalty-free, non-exclusive license under patents it now or hereafter ++ owns or controls to make, have made, use, import, offer to sell and ++ sell ("Utilize") this software, but solely to the extent that any ++ such patent is necessary to Utilize the software alone, or in ++ combination with an operating system licensed under an approved Open ++ Source license as listed by the Open Source Initiative at ++ http://opensource.org/licenses. The patent license shall not apply to ++ any other combinations which include this software. No hardware per ++ se is licensed hereunder. ++ ++ DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ++ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ++ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ++ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ++ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ++ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS ++ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ DAMAGE. ++*/ ++/* AUTO GEN PLEASE DO NOT MODIFY IT */ ++/* AUTO GEN PLEASE DO NOT MODIFY IT */ ++ ++ ++UCHAR FirmwareImage [] = { ++0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x12, 0x79, 0x02, ++0x12, 0x7a, 0x02, 0x12, 0x99, 0x02, 0x12, 0x9e, 0x12, 0x12, 0x9a, 0x22, 0x02, 0x16, 0x36, 0x02, ++0x17, 0x0c, 0x02, 0x13, 0x89, 0x02, 0x12, 0x9f, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x17, ++0xae, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40, ++0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4, ++0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4, ++0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01, ++0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xc8, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02, ++0x12, 0x6e, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0x9d, 0x10, ++0xb7, 0x31, 0x10, 0xe2, 0x50, 0x11, 0x08, 0x51, 0x11, 0x13, 0x52, 0x11, 0x13, 0x53, 0x11, 0x13, ++0x54, 0x11, 0x54, 0x55, 0x11, 0x79, 0x70, 0x11, 0xa4, 0x71, 0x11, 0xd2, 0x72, 0x12, 0x25, 0x73, ++0x12, 0x46, 0x80, 0x00, 0x00, 0x12, 0x6e, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf, ++0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, ++0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x6e, 0x02, 0x12, 0x67, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x02, ++0x12, 0x6e, 0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x12, 0x6e, 0x90, ++0x70, 0x11, 0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x12, 0x6e, 0x75, ++0x4e, 0x03, 0x75, 0x4f, 0x20, 0x02, 0x12, 0x6e, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47, ++0x02, 0x12, 0x6e, 0x90, 0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, ++0xe0, 0xff, 0x74, 0x47, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, ++0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, ++0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, ++0x6e, 0x02, 0x12, 0x67, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x05, ++0xe5, 0x47, 0xb4, 0x09, 0x08, 0x90, 0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe4, 0xfd, 0xaf, ++0x56, 0x12, 0x0b, 0x91, 0xd2, 0x04, 0x02, 0x12, 0x6e, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, ++0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, ++0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, ++0x6e, 0x02, 0x12, 0x67, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf5, ++0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, ++0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x6e, 0x02, ++0x12, 0x67, 0x90, 0x10, 0x02, 0xe0, 0xb4, 0x70, 0x1e, 0xa3, 0xe0, 0xb4, 0x30, 0x19, 0x90, 0x05, ++0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd, 0x90, 0x05, 0x05, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x04, 0xf0, ++0xed, 0x54, 0xfe, 0x90, 0x05, 0x08, 0xf0, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x3a, 0xff, 0xad, ++0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, ++0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x70, 0x40, ++0xe5, 0x3a, 0xf0, 0x80, 0x49, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf, ++0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, ++0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, ++0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, ++0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x70, ++0x42, 0xe5, 0x3a, 0xf0, 0xa3, 0x74, 0xab, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, ++0x09, 0xb2, 0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, ++0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22, 0xc2, 0x42, 0xd3, 0x22, 0x22, 0xc2, ++0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x0a, 0x9d, 0x12, 0xc1, 0x00, 0x13, 0x54, 0x04, 0x13, 0x50, ++0x08, 0x13, 0x2b, 0x10, 0x12, 0xd5, 0x20, 0x12, 0xf5, 0x60, 0x13, 0x06, 0xa0, 0x00, 0x00, 0x13, ++0x56, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, ++0x02, 0x13, 0x56, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, ++0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x66, ++0x53, 0x43, 0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, ++0x64, 0x06, 0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, ++0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, ++0x35, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, 0x06, ++0x53, 0x5e, 0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, 0x42, ++0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, 0x06, ++0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, 0xe5, ++0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, 0xe5, ++0x4a, 0xf0, 0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, 0xe5, ++0x42, 0xf0, 0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, 0x70, ++0x03, 0x12, 0x16, 0x16, 0x12, 0x13, 0x9e, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, ++0x90, 0x04, 0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, ++0x24, 0xff, 0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74, 0x1e, ++0xf0, 0xe5, 0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5, 0x5f, ++0x20, 0xe5, 0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, 0x25, ++0x70, 0x05, 0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, ++0x5f, 0x30, 0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, ++0x64, 0x03, 0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25, 0x70, ++0x03, 0x30, 0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02, 0x15, ++0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b, 0xe5, ++0x3a, 0x64, 0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, ++0x46, 0xe5, 0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, ++0x07, 0xe5, 0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, ++0xb2, 0x6c, 0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, ++0x80, 0x26, 0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, ++0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, ++0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, ++0x6a, 0x80, 0x26, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, ++0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, ++0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, ++0xa2, 0x6c, 0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, ++0xe1, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, ++0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x71, 0x92, 0x70, 0x90, 0x10, ++0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4c, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfe, ++0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, 0x60, 0x23, 0x24, 0x03, 0x60, ++0x03, 0x02, 0x16, 0x05, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0f, 0x80, 0x07, 0x90, 0x02, 0x28, ++0xe0, 0x20, 0x47, 0x06, 0x54, 0xfe, 0xf0, 0x02, 0x16, 0x05, 0x44, 0x01, 0xf0, 0x02, 0x16, 0x05, ++0xe5, 0x46, 0x30, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02, 0x28, 0xe0, 0x54, ++0xfe, 0x4f, 0xf0, 0x02, 0x16, 0x05, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0f, 0xe5, 0x47, 0x64, 0x08, ++0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02, 0x16, 0x05, 0xe4, 0xf5, 0x27, 0x90, 0x02, ++0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x36, ++0x24, 0xfc, 0x60, 0x5f, 0x24, 0xf9, 0x60, 0x1f, 0x24, 0x0e, 0x70, 0x69, 0xe5, 0x46, 0x13, 0x13, ++0x54, 0x3f, 0x75, 0xf0, 0x01, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, ++0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x45, 0xa2, 0x47, 0x80, 0x41, 0xe5, 0x46, 0x30, 0xe2, 0x03, ++0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, 0xc3, 0x94, 0x30, ++0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, 0x47, 0x04, 0x7d, ++0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, 0x47, 0xb3, 0x92, ++0x39, 0x80, 0x19, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x39, 0xa2, 0x47, ++0xb3, 0x92, 0x38, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, 0x02, 0x28, 0xe0, ++0x54, 0xfc, 0x45, 0x27, 0xf0, 0x90, 0x70, 0x9c, 0xe5, 0x3a, 0xf0, 0xa3, 0xe5, 0x47, 0xf0, 0x90, ++0x70, 0x41, 0xe5, 0x3a, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45, ++0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59, ++0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x62, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x46, ++0x14, 0x60, 0x62, 0x24, 0x02, 0x60, 0x03, 0x02, 0x16, 0xf0, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x90, ++0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0, 0x20, 0xe7, 0x22, 0x90, 0x04, 0x34, 0xe0, 0xb4, ++0x02, 0x1b, 0xa3, 0xe0, 0xb4, 0x02, 0x16, 0xa3, 0xe0, 0xb4, 0x02, 0x11, 0x7f, 0x20, 0x12, 0x16, ++0x2c, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x80, 0x73, 0xe5, 0x50, 0x70, ++0x05, 0x75, 0x62, 0x03, 0x80, 0x6a, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, 0x11, 0x7f, 0x20, ++0x12, 0x16, 0x2c, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02, 0x80, 0x51, 0xe5, ++0x50, 0x70, 0x02, 0x80, 0x46, 0x90, 0x02, 0xa3, 0xe0, 0x20, 0xe6, 0x3b, 0x90, 0x04, 0x37, 0xe0, ++0x64, 0x22, 0x70, 0x33, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96, 0xf0, 0x90, 0x12, ++0x04, 0x74, 0x0a, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xf0, 0xf0, ++0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54, 0xf9, 0xf0, 0x75, 0x62, 0x01, 0x75, ++0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, 0xf5, 0x51, ++0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xad, 0x62, 0xaf, 0x40, 0x12, ++0x17, 0x7a, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x30, 0x01, ++0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, 0x02, 0xaf, 0x40, ++0x12, 0x17, 0x7a, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70, 0x4c, 0x75, 0x52, 0x01, 0x75, 0x55, ++0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, ++0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, 0x03, 0xf0, 0x90, ++0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x0c, 0xf0, 0xe4, 0xf5, 0x52, ++0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, 0x12, 0x17, 0x7a, 0x80, 0x02, ++0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4, 0xfe, ++0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74, 0x14, ++0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82, 0xe4, ++0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, 0x22, 0x90, 0x70, ++0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, ++0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, ++0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, ++0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, ++0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01, 0xf0, 0xc2, 0x05, ++0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x69, 0x77, ++0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x12, 0x25, 0x02, ++0x12, 0x26, 0x02, 0x12, 0x39, 0x02, 0x12, 0x3e, 0x12, 0x12, 0x3a, 0x22, 0x02, 0x15, 0x72, 0x02, ++0x16, 0x48, 0x02, 0x13, 0x29, 0x02, 0x12, 0x3f, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x16, ++0xea, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40, ++0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4, ++0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4, ++0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01, ++0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xdd, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02, ++0x12, 0x1a, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0xb6, 0x10, ++0xb4, 0x31, 0x10, 0xdf, 0x50, 0x11, 0x05, 0x51, 0x11, 0x10, 0x52, 0x11, 0x10, 0x53, 0x11, 0x10, ++0x54, 0x11, 0x51, 0x55, 0x11, 0x70, 0x70, 0x11, 0x9a, 0x71, 0x11, 0xc4, 0x72, 0x11, 0xf2, 0x80, ++0x00, 0x00, 0x12, 0x1a, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf, 0x56, 0x12, 0x0b, ++0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, ++0x03, 0x02, 0x12, 0x1a, 0x02, 0x12, 0x13, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x02, 0x12, 0x1a, 0x90, ++0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x12, 0x1a, 0x90, 0x70, 0x11, 0xe0, ++0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x12, 0x1a, 0x75, 0x4e, 0x03, 0x75, ++0x4f, 0x20, 0x02, 0x12, 0x1a, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47, 0x02, 0x12, 0x1a, ++0x90, 0x04, 0x04, 0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0, 0xff, 0x74, ++0x47, 0x25, 0x57, 0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48, 0x25, 0x57, ++0xf8, 0xc6, 0xef, 0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, ++0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x1a, 0x02, 0x12, ++0x13, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x08, 0x08, 0x90, 0x70, 0x11, 0xe0, ++0x54, 0x07, 0xf5, 0x3a, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0xd2, 0x04, 0x02, 0x12, 0x1a, ++0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, ++0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, ++0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x1a, 0x80, 0x79, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, ++0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, ++0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, ++0x60, 0x58, 0x80, 0x4f, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x75, 0x3a, 0xff, 0xad, 0x57, 0xaf, 0x56, ++0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, ++0xf4, 0x60, 0x07, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x70, 0x40, 0xe5, 0x3a, 0xf0, ++0x80, 0x28, 0x90, 0x70, 0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, ++0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, ++0xf4, 0x60, 0x07, 0x90, 0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x70, 0x42, 0xe5, 0x3a, 0xf0, ++0xa3, 0x74, 0xab, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x70, 0x0e, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, ++0xe5, 0x4f, 0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22, 0xc2, 0x42, 0xd3, 0x22, 0x22, 0xc2, ++0x4b, 0xc2, 0x4c, 0xe5, 0x44, 0x12, 0x0a, 0xb6, 0x12, 0x61, 0x00, 0x12, 0xf4, 0x04, 0x12, 0xf0, ++0x08, 0x12, 0xcb, 0x10, 0x12, 0x75, 0x20, 0x12, 0x95, 0x60, 0x12, 0xa6, 0xa0, 0x00, 0x00, 0x12, ++0xf6, 0x85, 0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, ++0x02, 0x12, 0xf6, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, ++0x0f, 0xf5, 0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x66, ++0x53, 0x43, 0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, ++0x64, 0x06, 0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, ++0x54, 0x0f, 0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, ++0x35, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, 0x06, ++0x53, 0x5e, 0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, 0x42, ++0x09, 0xe5, 0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, 0x06, ++0xd2, 0x4b, 0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, 0xe5, ++0x43, 0x54, 0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, 0xe5, ++0x4a, 0xf0, 0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, 0xe5, ++0x42, 0xf0, 0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, 0x70, ++0x03, 0x12, 0x15, 0x52, 0x12, 0x13, 0x3e, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, ++0x90, 0x04, 0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, ++0x24, 0xff, 0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74, 0x1e, ++0xf0, 0xe5, 0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5, 0x5f, ++0x20, 0xe5, 0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, 0x25, ++0x70, 0x05, 0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, ++0x5f, 0x30, 0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, ++0x64, 0x03, 0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25, 0x70, ++0x03, 0x30, 0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02, 0x15, ++0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5, 0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, 0x5e, ++0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5, 0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, ++0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c, 0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, 0x75, ++0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x15, 0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe3, ++0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x73, ++0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, 0x15, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe3, ++0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x75, ++0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, 0x80, 0x15, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe3, ++0x80, 0x0c, 0xe5, 0x46, 0x54, 0xf0, 0xff, 0xbf, 0xf0, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x71, ++0x92, 0x70, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4c, 0x90, 0x02, ++0x29, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, 0x60, ++0x23, 0x24, 0x03, 0x60, 0x03, 0x02, 0x15, 0x41, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0f, 0x80, ++0x07, 0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x06, 0x54, 0xfe, 0xf0, 0x02, 0x15, 0x41, 0x44, 0x01, ++0xf0, 0x02, 0x15, 0x41, 0xe5, 0x46, 0x30, 0xe3, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, ++0x02, 0x28, 0xe0, 0x54, 0xfe, 0x4f, 0xf0, 0x02, 0x15, 0x41, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x09, ++0xe5, 0x47, 0x64, 0x08, 0x60, 0x03, 0x02, 0x15, 0x41, 0xe4, 0xf5, 0x27, 0x90, 0x02, 0x29, 0xe0, ++0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x26, 0x14, 0x60, 0x2e, 0x14, 0x60, 0x36, 0x24, 0x03, ++0x70, 0x5f, 0xe5, 0x46, 0x13, 0x13, 0x13, 0x54, 0x1f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, ++0x47, 0x04, 0x7e, 0x01, 0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x02, 0xa2, 0x47, ++0x92, 0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x3f, 0xe5, 0x46, 0x30, 0xe3, 0x03, 0xd3, 0x80, ++0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe3, 0x0d, 0x54, 0x70, 0xc3, 0x94, 0x60, 0x50, 0x06, ++0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, 0x47, 0x04, 0x7d, 0x01, 0x80, ++0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, 0x47, 0xb3, 0x92, 0x39, 0x80, ++0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, 0x02, 0x28, 0xe0, 0x54, 0xfc, 0x45, 0x27, ++0xf0, 0x90, 0x70, 0x9c, 0xe5, 0x3a, 0xf0, 0xa3, 0xe5, 0x47, 0xf0, 0x90, 0x70, 0x41, 0xe5, 0x3a, ++0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, 0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, ++0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, 0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, ++0x58, 0x22, 0xe4, 0xf5, 0x62, 0xc2, 0xaf, 0xe5, 0x51, 0x14, 0x60, 0x46, 0x14, 0x60, 0x62, 0x24, ++0x02, 0x60, 0x03, 0x02, 0x16, 0x2c, 0xd2, 0x59, 0x75, 0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, ++0x7f, 0xf0, 0xa3, 0xe0, 0x20, 0xe7, 0x22, 0x90, 0x04, 0x34, 0xe0, 0xb4, 0x02, 0x1b, 0xa3, 0xe0, ++0xb4, 0x02, 0x16, 0xa3, 0xe0, 0xb4, 0x02, 0x11, 0x7f, 0x20, 0x12, 0x15, 0x68, 0x90, 0x10, 0x04, ++0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x80, 0x73, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, ++0x80, 0x6a, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, 0x11, 0x7f, 0x20, 0x12, 0x15, 0x68, 0x90, ++0x02, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02, 0x80, 0x51, 0xe5, 0x50, 0x70, 0x02, 0x80, ++0x46, 0x90, 0x02, 0xa3, 0xe0, 0x20, 0xe6, 0x3b, 0x90, 0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x33, ++0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96, 0xf0, 0x90, 0x12, 0x04, 0x74, 0x0a, 0xf0, ++0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, ++0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54, 0xf9, 0xf0, 0x75, 0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, ++0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, ++0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xad, 0x62, 0xaf, 0x40, 0x12, 0x16, 0xb6, 0xe5, 0x62, ++0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, ++0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, 0x02, 0xaf, 0x40, 0x12, 0x16, 0xb6, 0xe5, ++0x52, 0x14, 0x60, 0x09, 0x04, 0x70, 0x4c, 0x75, 0x52, 0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, ++0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, ++0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, 0x03, 0xf0, 0x90, 0x02, 0xa2, 0xe0, 0x44, ++0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x0c, 0xf0, 0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, ++0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, 0x12, 0x16, 0xb6, 0x80, 0x02, 0xc2, 0x03, 0xe4, 0x90, ++0x01, 0x96, 0xf0, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, 0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, ++0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, 0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, ++0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, ++0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, 0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, ++0x4d, 0xc2, 0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10, 0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, ++0x10, 0x1d, 0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10, 0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, ++0x62, 0x90, 0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90, 0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, ++0x90, 0x10, 0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90, 0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, ++0x30, 0x4a, 0x07, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01, 0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, ++0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe9, 0x00, } ; +--- /dev/null ++++ b/drivers/staging/rt2870/common/md5.c +@@ -0,0 +1,1427 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ md5.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ jan 10-28-03 Initial ++ Rita 11-23-04 Modify MD5 and SHA-1 ++ Rita 10-14-05 Modify SHA-1 in big-endian platform ++ */ ++#include "../rt_config.h" ++ ++/** ++ * md5_mac: ++ * @key: pointer to the key used for MAC generation ++ * @key_len: length of the key in bytes ++ * @data: pointer to the data area for which the MAC is generated ++ * @data_len: length of the data in bytes ++ * @mac: pointer to the buffer holding space for the MAC; the buffer should ++ * have space for 128-bit (16 bytes) MD5 hash value ++ * ++ * md5_mac() determines the message authentication code by using secure hash ++ * MD5(key | data | key). ++ */ ++void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) ++{ ++ MD5_CTX context; ++ ++ MD5Init(&context); ++ MD5Update(&context, key, key_len); ++ MD5Update(&context, data, data_len); ++ MD5Update(&context, key, key_len); ++ MD5Final(mac, &context); ++} ++ ++/** ++ * hmac_md5: ++ * @key: pointer to the key used for MAC generation ++ * @key_len: length of the key in bytes ++ * @data: pointer to the data area for which the MAC is generated ++ * @data_len: length of the data in bytes ++ * @mac: pointer to the buffer holding space for the MAC; the buffer should ++ * have space for 128-bit (16 bytes) MD5 hash value ++ * ++ * hmac_md5() determines the message authentication code using HMAC-MD5. ++ * This implementation is based on the sample code presented in RFC 2104. ++ */ ++void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) ++{ ++ MD5_CTX context; ++ u8 k_ipad[65]; /* inner padding - key XORd with ipad */ ++ u8 k_opad[65]; /* outer padding - key XORd with opad */ ++ u8 tk[16]; ++ int i; ++ ++ //assert(key != NULL && data != NULL && mac != NULL); ++ ++ /* if key is longer than 64 bytes reset it to key = MD5(key) */ ++ if (key_len > 64) { ++ MD5_CTX ttcontext; ++ ++ MD5Init(&ttcontext); ++ MD5Update(&ttcontext, key, key_len); ++ MD5Final(tk, &ttcontext); ++ //key=(PUCHAR)ttcontext.buf; ++ key = tk; ++ key_len = 16; ++ } ++ ++ /* the HMAC_MD5 transform looks like: ++ * ++ * MD5(K XOR opad, MD5(K XOR ipad, text)) ++ * ++ * where K is an n byte key ++ * ipad is the byte 0x36 repeated 64 times ++ * opad is the byte 0x5c repeated 64 times ++ * and text is the data being protected */ ++ ++ /* start out by storing key in pads */ ++ NdisZeroMemory(k_ipad, sizeof(k_ipad)); ++ NdisZeroMemory(k_opad, sizeof(k_opad)); ++ //assert(key_len < sizeof(k_ipad)); ++ NdisMoveMemory(k_ipad, key, key_len); ++ NdisMoveMemory(k_opad, key, key_len); ++ ++ /* XOR key with ipad and opad values */ ++ for (i = 0; i < 64; i++) { ++ k_ipad[i] ^= 0x36; ++ k_opad[i] ^= 0x5c; ++ } ++ ++ /* perform inner MD5 */ ++ MD5Init(&context); /* init context for 1st pass */ ++ MD5Update(&context, k_ipad, 64); /* start with inner pad */ ++ MD5Update(&context, data, data_len); /* then text of datagram */ ++ MD5Final(mac, &context); /* finish up 1st pass */ ++ ++ /* perform outer MD5 */ ++ MD5Init(&context); /* init context for 2nd pass */ ++ MD5Update(&context, k_opad, 64); /* start with outer pad */ ++ MD5Update(&context, mac, 16); /* then results of 1st hash */ ++ MD5Final(mac, &context); /* finish up 2nd pass */ ++} ++ ++#ifndef RT_BIG_ENDIAN ++#define byteReverse(buf, len) /* Nothing */ ++#else ++void byteReverse(unsigned char *buf, unsigned longs); ++void byteReverse(unsigned char *buf, unsigned longs) ++{ ++ do { ++ *(UINT32 *)buf = SWAP32(*(UINT32 *)buf); ++ buf += 4; ++ } while (--longs); ++} ++#endif ++ ++ ++/* ========================== MD5 implementation =========================== */ ++// four base functions for MD5 ++#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z))) ++#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z))) ++#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z)) ++#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z))) ++#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s)))) ++ ++#define MD5Step(f, w, x, y, z, data, t, s) \ ++ ( w += f(x, y, z) + data + t, w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w += x ) ++ ++ ++/* ++ * Function Description: ++ * Initiate MD5 Context satisfied in RFC 1321 ++ * ++ * Arguments: ++ * pCtx Pointer to MD5 context ++ * ++ * Return Value: ++ * None ++ */ ++VOID MD5Init(MD5_CTX *pCtx) ++{ ++ pCtx->Buf[0]=0x67452301; ++ pCtx->Buf[1]=0xefcdab89; ++ pCtx->Buf[2]=0x98badcfe; ++ pCtx->Buf[3]=0x10325476; ++ ++ pCtx->LenInBitCount[0]=0; ++ pCtx->LenInBitCount[1]=0; ++} ++ ++ ++/* ++ * Function Description: ++ * Update MD5 Context, allow of an arrary of octets as the next portion ++ * of the message ++ * ++ * Arguments: ++ * pCtx Pointer to MD5 context ++ * pData Pointer to input data ++ * LenInBytes The length of input data (unit: byte) ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called after MD5Init or MD5Update(itself) ++ */ ++VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) ++{ ++ ++ UINT32 TfTimes; ++ UINT32 temp; ++ unsigned int i; ++ ++ temp = pCtx->LenInBitCount[0]; ++ ++ pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); ++ ++ if (pCtx->LenInBitCount[0] < temp) ++ pCtx->LenInBitCount[1]++; //carry in ++ ++ pCtx->LenInBitCount[1] += LenInBytes >> 29; ++ ++ // mod 64 bytes ++ temp = (temp >> 3) & 0x3f; ++ ++ // process lacks of 64-byte data ++ if (temp) ++ { ++ UCHAR *pAds = (UCHAR *) pCtx->Input + temp; ++ ++ if ((temp+LenInBytes) < 64) ++ { ++ NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); ++ return; ++ } ++ ++ NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp); ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ pData += 64-temp; ++ LenInBytes -= 64-temp; ++ } // end of if (temp) ++ ++ ++ TfTimes = (LenInBytes >> 6); ++ ++ for (i=TfTimes; i>0; i--) ++ { ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ pData += 64; ++ LenInBytes -= 64; ++ } // end of for ++ ++ // buffering lacks of 64-byte data ++ if(LenInBytes) ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); ++ ++} ++ ++ ++/* ++ * Function Description: ++ * Append padding bits and length of original message in the tail ++ * The message digest has to be completed in the end ++ * ++ * Arguments: ++ * Digest Output of Digest-Message for MD5 ++ * pCtx Pointer to MD5 context ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called after MD5Update ++ */ ++VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx) ++{ ++ UCHAR Remainder; ++ UCHAR PadLenInBytes; ++ UCHAR *pAppend=0; ++ unsigned int i; ++ ++ Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); ++ ++ PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); ++ ++ pAppend = (UCHAR *)pCtx->Input + Remainder; ++ ++ // padding bits without crossing block(64-byte based) boundary ++ if (Remainder < 56) ++ { ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); ++ ++ // add data-length field, from low to high ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); ++ } ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of if ++ ++ // padding bits with crossing block(64-byte based) boundary ++ else ++ { ++ // the first block === ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); ++ PadLenInBytes -= (64 - Remainder - 1); ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ ++ // the second block === ++ NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); ++ ++ // add data-length field ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); ++ } ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of else ++ ++ ++ NdisMoveMemory((UCHAR *)Digest, (UINT32 *)pCtx->Buf, 16); // output ++ byteReverse((UCHAR *)Digest, 4); ++ NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free ++} ++ ++ ++/* ++ * Function Description: ++ * The central algorithm of MD5, consists of four rounds and sixteen ++ * steps per round ++ * ++ * Arguments: ++ * Buf Buffers of four states (output: 16 bytes) ++ * Mes Input data (input: 64 bytes) ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called by MD5Update or MD5Final ++ */ ++VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]) ++{ ++ UINT32 Reg[4], Temp; ++ unsigned int i; ++ ++ static UCHAR LShiftVal[16] = ++ { ++ 7, 12, 17, 22, ++ 5, 9 , 14, 20, ++ 4, 11, 16, 23, ++ 6, 10, 15, 21, ++ }; ++ ++ ++ // [equal to 4294967296*abs(sin(index))] ++ static UINT32 MD5Table[64] = ++ { ++ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, ++ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, ++ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, ++ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, ++ ++ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, ++ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, ++ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, ++ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, ++ ++ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, ++ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, ++ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, ++ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, ++ ++ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, ++ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, ++ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, ++ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ++ }; ++ ++ ++ for (i=0; i<4; i++) ++ Reg[i]=Buf[i]; ++ ++ ++ // 64 steps in MD5 algorithm ++ for (i=0; i<16; i++) ++ { ++ MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i], ++ MD5Table[i], LShiftVal[i & 0x3]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=16; i<32; i++) ++ { ++ MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], ++ MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=32; i<48; i++) ++ { ++ MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], ++ MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=48; i<64; i++) ++ { ++ MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], ++ MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ ++ ++ // (temporary)output ++ for (i=0; i<4; i++) ++ Buf[i] += Reg[i]; ++ ++} ++ ++ ++ ++/* ========================= SHA-1 implementation ========================== */ ++// four base functions for SHA-1 ++#define SHA1_F1(b, c, d) (((b) & (c)) | ((~b) & (d))) ++#define SHA1_F2(b, c, d) ((b) ^ (c) ^ (d)) ++#define SHA1_F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) ++ ++ ++#define SHA1Step(f, a, b, c, d, e, w, k) \ ++ ( e += ( f(b, c, d) + w + k + CYCLIC_LEFT_SHIFT(a, 5)) & 0xffffffff, \ ++ b = CYCLIC_LEFT_SHIFT(b, 30) ) ++ ++//Initiate SHA-1 Context satisfied in RFC 3174 ++VOID SHAInit(SHA_CTX *pCtx) ++{ ++ pCtx->Buf[0]=0x67452301; ++ pCtx->Buf[1]=0xefcdab89; ++ pCtx->Buf[2]=0x98badcfe; ++ pCtx->Buf[3]=0x10325476; ++ pCtx->Buf[4]=0xc3d2e1f0; ++ ++ pCtx->LenInBitCount[0]=0; ++ pCtx->LenInBitCount[1]=0; ++} ++ ++/* ++ * Function Description: ++ * Update SHA-1 Context, allow of an arrary of octets as the next ++ * portion of the message ++ * ++ * Arguments: ++ * pCtx Pointer to SHA-1 context ++ * pData Pointer to input data ++ * LenInBytes The length of input data (unit: byte) ++ * ++ * Return Value: ++ * error indicate more than pow(2,64) bits of data ++ * ++ * Note: ++ * Called after SHAInit or SHAUpdate(itself) ++ */ ++UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) ++{ ++ UINT32 TfTimes; ++ UINT32 temp1,temp2; ++ unsigned int i; ++ UCHAR err=1; ++ ++ temp1 = pCtx->LenInBitCount[0]; ++ temp2 = pCtx->LenInBitCount[1]; ++ ++ pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); ++ if (pCtx->LenInBitCount[0] < temp1) ++ pCtx->LenInBitCount[1]++; //carry in ++ ++ ++ pCtx->LenInBitCount[1] = (UINT32) (pCtx->LenInBitCount[1] +(LenInBytes >> 29)); ++ if (pCtx->LenInBitCount[1] < temp2) ++ return (err); //check total length of original data ++ ++ ++ // mod 64 bytes ++ temp1 = (temp1 >> 3) & 0x3f; ++ ++ // process lacks of 64-byte data ++ if (temp1) ++ { ++ UCHAR *pAds = (UCHAR *) pCtx->Input + temp1; ++ ++ if ((temp1+LenInBytes) < 64) ++ { ++ NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); ++ return (0); ++ } ++ ++ NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp1); ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ pData += 64-temp1; ++ LenInBytes -= 64-temp1; ++ } // end of if (temp1) ++ ++ ++ TfTimes = (LenInBytes >> 6); ++ ++ for (i=TfTimes; i>0; i--) ++ { ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ pData += 64; ++ LenInBytes -= 64; ++ } // end of for ++ ++ // buffering lacks of 64-byte data ++ if(LenInBytes) ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); ++ ++ return (0); ++ ++} ++ ++// Append padding bits and length of original message in the tail ++// The message digest has to be completed in the end ++VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]) ++{ ++ UCHAR Remainder; ++ UCHAR PadLenInBytes; ++ UCHAR *pAppend=0; ++ unsigned int i; ++ ++ Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); ++ ++ pAppend = (UCHAR *)pCtx->Input + Remainder; ++ ++ PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); ++ ++ // padding bits without crossing block(64-byte based) boundary ++ if (Remainder < 56) ++ { ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); ++ ++ // add data-length field, from high to low ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); ++ } ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 14); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of if ++ ++ // padding bits with crossing block(64-byte based) boundary ++ else ++ { ++ // the first block === ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); ++ PadLenInBytes -= (64 - Remainder - 1); ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ ++ // the second block === ++ NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); ++ ++ // add data-length field ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); ++ } ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of else ++ ++ ++ //Output, bytereverse ++ for (i=0; i<20; i++) ++ { ++ Digest [i] = (UCHAR)(pCtx->Buf[i>>2] >> 8*(3-(i & 0x3))); ++ } ++ ++ NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free ++} ++ ++ ++// The central algorithm of SHA-1, consists of four rounds and ++// twenty steps per round ++VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]) ++{ ++ UINT32 Reg[5],Temp; ++ unsigned int i; ++ UINT32 W[80]; ++ ++ static UINT32 SHA1Table[4] = { 0x5a827999, 0x6ed9eba1, ++ 0x8f1bbcdc, 0xca62c1d6 }; ++ ++ Reg[0]=Buf[0]; ++ Reg[1]=Buf[1]; ++ Reg[2]=Buf[2]; ++ Reg[3]=Buf[3]; ++ Reg[4]=Buf[4]; ++ ++ //the first octet of a word is stored in the 0th element, bytereverse ++ for(i = 0; i < 16; i++) ++ { ++ W[i] = (Mes[i] >> 24) & 0xff; ++ W[i] |= (Mes[i] >> 8 ) & 0xff00; ++ W[i] |= (Mes[i] << 8 ) & 0xff0000; ++ W[i] |= (Mes[i] << 24) & 0xff000000; ++ } ++ ++ ++ for (i = 0; i < 64; i++) ++ W[16+i] = CYCLIC_LEFT_SHIFT(W[i] ^ W[2+i] ^ W[8+i] ^ W[13+i], 1); ++ ++ ++ // 80 steps in SHA-1 algorithm ++ for (i=0; i<80; i++) ++ { ++ if (i<20) ++ SHA1Step(SHA1_F1, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[0]); ++ ++ else if (i>=20 && i<40) ++ SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[1]); ++ ++ else if (i>=40 && i<60) ++ SHA1Step(SHA1_F3, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[2]); ++ ++ else ++ SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[3]); ++ ++ ++ // one-word right shift ++ Temp = Reg[4]; ++ Reg[4] = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ ++ } // end of for-loop ++ ++ ++ // (temporary)output ++ for (i=0; i<5; i++) ++ Buf[i] += Reg[i]; ++ ++} ++ ++ ++/* ========================= AES En/Decryption ========================== */ ++ ++/* forward S-box */ ++static uint32 FSb[256] = ++{ ++ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, ++ 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, ++ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, ++ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, ++ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, ++ 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, ++ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, ++ 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, ++ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, ++ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, ++ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, ++ 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, ++ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, ++ 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, ++ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, ++ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, ++ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, ++ 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, ++ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, ++ 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, ++ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, ++ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, ++ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, ++ 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, ++ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, ++ 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, ++ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, ++ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, ++ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, ++ 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, ++ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, ++ 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 ++}; ++ ++/* forward table */ ++#define FT \ ++\ ++ V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ ++ V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ ++ V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ ++ V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ ++ V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ ++ V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ ++ V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ ++ V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ ++ V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ ++ V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ ++ V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ ++ V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ ++ V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ ++ V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ ++ V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ ++ V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ ++ V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ ++ V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ ++ V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ ++ V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ ++ V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ ++ V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ ++ V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ ++ V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ ++ V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ ++ V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ ++ V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ ++ V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ ++ V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ ++ V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ ++ V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ ++ V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ ++ V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ ++ V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ ++ V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ ++ V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ ++ V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ ++ V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ ++ V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ ++ V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ ++ V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ ++ V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ ++ V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ ++ V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ ++ V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ ++ V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ ++ V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ ++ V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ ++ V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ ++ V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ ++ V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ ++ V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ ++ V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ ++ V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ ++ V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ ++ V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ ++ V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ ++ V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ ++ V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ ++ V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ ++ V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ ++ V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ ++ V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ ++ V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) ++ ++#define V(a,b,c,d) 0x##a##b##c##d ++static uint32 FT0[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##d##a##b##c ++static uint32 FT1[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##c##d##a##b ++static uint32 FT2[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##b##c##d##a ++static uint32 FT3[256] = { FT }; ++#undef V ++ ++#undef FT ++ ++/* reverse S-box */ ++ ++static uint32 RSb[256] = ++{ ++ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, ++ 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, ++ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, ++ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, ++ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, ++ 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, ++ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, ++ 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, ++ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, ++ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, ++ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, ++ 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, ++ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, ++ 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, ++ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, ++ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, ++ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, ++ 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, ++ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, ++ 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, ++ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, ++ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, ++ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, ++ 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, ++ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, ++ 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, ++ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, ++ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, ++ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, ++ 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, ++ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, ++ 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ++}; ++ ++/* reverse table */ ++ ++#define RT \ ++\ ++ V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ ++ V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ ++ V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ ++ V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ ++ V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ ++ V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ ++ V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ ++ V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ ++ V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ ++ V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ ++ V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ ++ V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ ++ V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ ++ V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ ++ V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ ++ V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ ++ V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ ++ V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ ++ V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ ++ V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ ++ V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ ++ V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ ++ V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ ++ V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ ++ V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ ++ V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ ++ V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ ++ V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ ++ V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ ++ V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ ++ V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ ++ V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ ++ V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ ++ V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ ++ V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ ++ V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ ++ V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ ++ V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ ++ V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ ++ V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ ++ V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ ++ V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ ++ V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ ++ V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ ++ V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ ++ V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ ++ V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ ++ V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ ++ V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ ++ V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ ++ V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ ++ V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ ++ V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ ++ V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ ++ V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ ++ V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ ++ V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ ++ V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ ++ V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ ++ V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ ++ V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ ++ V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ ++ V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ ++ V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) ++ ++#define V(a,b,c,d) 0x##a##b##c##d ++static uint32 RT0[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##d##a##b##c ++static uint32 RT1[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##c##d##a##b ++static uint32 RT2[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##b##c##d##a ++static uint32 RT3[256] = { RT }; ++#undef V ++ ++#undef RT ++ ++/* round constants */ ++ ++static uint32 RCON[10] = ++{ ++ 0x01000000, 0x02000000, 0x04000000, 0x08000000, ++ 0x10000000, 0x20000000, 0x40000000, 0x80000000, ++ 0x1B000000, 0x36000000 ++}; ++ ++/* key schedule tables */ ++ ++static int KT_init = 1; ++ ++static uint32 KT0[256]; ++static uint32 KT1[256]; ++static uint32 KT2[256]; ++static uint32 KT3[256]; ++ ++/* platform-independant 32-bit integer manipulation macros */ ++ ++#define GET_UINT32(n,b,i) \ ++{ \ ++ (n) = ( (uint32) (b)[(i) ] << 24 ) \ ++ | ( (uint32) (b)[(i) + 1] << 16 ) \ ++ | ( (uint32) (b)[(i) + 2] << 8 ) \ ++ | ( (uint32) (b)[(i) + 3] ); \ ++} ++ ++#define PUT_UINT32(n,b,i) \ ++{ \ ++ (b)[(i) ] = (uint8) ( (n) >> 24 ); \ ++ (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ ++ (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ ++ (b)[(i) + 3] = (uint8) ( (n) ); \ ++} ++ ++/* AES key scheduling routine */ ++ ++int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ) ++{ ++ int i; ++ uint32 *RK, *SK; ++ ++ switch( nbits ) ++ { ++ case 128: ctx->nr = 10; break; ++ case 192: ctx->nr = 12; break; ++ case 256: ctx->nr = 14; break; ++ default : return( 1 ); ++ } ++ ++ RK = ctx->erk; ++ ++ for( i = 0; i < (nbits >> 5); i++ ) ++ { ++ GET_UINT32( RK[i], key, i * 4 ); ++ } ++ ++ /* setup encryption round keys */ ++ ++ switch( nbits ) ++ { ++ case 128: ++ ++ for( i = 0; i < 10; i++, RK += 4 ) ++ { ++ RK[4] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); ++ ++ RK[5] = RK[1] ^ RK[4]; ++ RK[6] = RK[2] ^ RK[5]; ++ RK[7] = RK[3] ^ RK[6]; ++ } ++ break; ++ ++ case 192: ++ ++ for( i = 0; i < 8; i++, RK += 6 ) ++ { ++ RK[6] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); ++ ++ RK[7] = RK[1] ^ RK[6]; ++ RK[8] = RK[2] ^ RK[7]; ++ RK[9] = RK[3] ^ RK[8]; ++ RK[10] = RK[4] ^ RK[9]; ++ RK[11] = RK[5] ^ RK[10]; ++ } ++ break; ++ ++ case 256: ++ ++ for( i = 0; i < 7; i++, RK += 8 ) ++ { ++ RK[8] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); ++ ++ RK[9] = RK[1] ^ RK[8]; ++ RK[10] = RK[2] ^ RK[9]; ++ RK[11] = RK[3] ^ RK[10]; ++ ++ RK[12] = RK[4] ^ ++ ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[11] ) ] ); ++ ++ RK[13] = RK[5] ^ RK[12]; ++ RK[14] = RK[6] ^ RK[13]; ++ RK[15] = RK[7] ^ RK[14]; ++ } ++ break; ++ } ++ ++ /* setup decryption round keys */ ++ ++ if( KT_init ) ++ { ++ for( i = 0; i < 256; i++ ) ++ { ++ KT0[i] = RT0[ FSb[i] ]; ++ KT1[i] = RT1[ FSb[i] ]; ++ KT2[i] = RT2[ FSb[i] ]; ++ KT3[i] = RT3[ FSb[i] ]; ++ } ++ ++ KT_init = 0; ++ } ++ ++ SK = ctx->drk; ++ ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ ++ for( i = 1; i < ctx->nr; i++ ) ++ { ++ RK -= 8; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ } ++ ++ RK -= 8; ++ ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ ++ return( 0 ); ++} ++ ++/* AES 128-bit block encryption routine */ ++ ++void rtmp_aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16] ) ++{ ++ uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; ++ ++ RK = ctx->erk; ++ GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; ++ GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; ++ GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; ++ GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; ++ ++#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ ++{ \ ++ RK += 4; \ ++ \ ++ X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y3 ) ]; \ ++ \ ++ X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y0 ) ]; \ ++ \ ++ X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y1 ) ]; \ ++ \ ++ X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y2 ) ]; \ ++} ++ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ ++ ++ if( ctx->nr > 10 ) ++ { ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ ++ } ++ ++ if( ctx->nr > 12 ) ++ { ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ ++ } ++ ++ /* last round */ ++ ++ RK += 4; ++ ++ X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y3 ) ] ); ++ ++ X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y0 ) ] ); ++ ++ X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y1 ) ] ); ++ ++ X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y2 ) ] ); ++ ++ PUT_UINT32( X0, output, 0 ); ++ PUT_UINT32( X1, output, 4 ); ++ PUT_UINT32( X2, output, 8 ); ++ PUT_UINT32( X3, output, 12 ); ++} ++ ++/* AES 128-bit block decryption routine */ ++ ++void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) ++{ ++ uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; ++ ++ RK = ctx->drk; ++ ++ GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; ++ GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; ++ GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; ++ GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; ++ ++#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ ++{ \ ++ RK += 4; \ ++ \ ++ X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y1 ) ]; \ ++ \ ++ X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y2 ) ]; \ ++ \ ++ X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y3 ) ]; \ ++ \ ++ X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y0 ) ]; \ ++} ++ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ ++ ++ if( ctx->nr > 10 ) ++ { ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ ++ } ++ ++ if( ctx->nr > 12 ) ++ { ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ ++ } ++ ++ /* last round */ ++ ++ RK += 4; ++ ++ X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y1 ) ] ); ++ ++ X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y2 ) ] ); ++ ++ X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y3 ) ] ); ++ ++ X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y0 ) ] ); ++ ++ PUT_UINT32( X0, output, 0 ); ++ PUT_UINT32( X1, output, 4 ); ++ PUT_UINT32( X2, output, 8 ); ++ PUT_UINT32( X3, output, 12 ); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ SHA1 function ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID HMAC_SHA1( ++ IN UCHAR *text, ++ IN UINT text_len, ++ IN UCHAR *key, ++ IN UINT key_len, ++ IN UCHAR *digest) ++{ ++ SHA_CTX context; ++ UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */ ++ UCHAR k_opad[65]; /* outer padding - key XORd with opad */ ++ INT i; ++ ++ // if key is longer than 64 bytes reset it to key=SHA1(key) ++ if (key_len > 64) ++ { ++ SHA_CTX tctx; ++ SHAInit(&tctx); ++ SHAUpdate(&tctx, key, key_len); ++ SHAFinal(&tctx, key); ++ key_len = 20; ++ } ++ NdisZeroMemory(k_ipad, sizeof(k_ipad)); ++ NdisZeroMemory(k_opad, sizeof(k_opad)); ++ NdisMoveMemory(k_ipad, key, key_len); ++ NdisMoveMemory(k_opad, key, key_len); ++ ++ // XOR key with ipad and opad values ++ for (i = 0; i < 64; i++) ++ { ++ k_ipad[i] ^= 0x36; ++ k_opad[i] ^= 0x5c; ++ } ++ ++ // perform inner SHA1 ++ SHAInit(&context); /* init context for 1st pass */ ++ SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ ++ SHAUpdate(&context, text, text_len); /* then text of datagram */ ++ SHAFinal(&context, digest); /* finish up 1st pass */ ++ ++ //perform outer SHA1 ++ SHAInit(&context); /* init context for 2nd pass */ ++ SHAUpdate(&context, k_opad, 64); /* start with outer pad */ ++ SHAUpdate(&context, digest, 20); /* then results of 1st hash */ ++ SHAFinal(&context, digest); /* finish up 2nd pass */ ++ ++} ++ ++/* ++* F(P, S, c, i) = U1 xor U2 xor ... Uc ++* U1 = PRF(P, S || Int(i)) ++* U2 = PRF(P, U1) ++* Uc = PRF(P, Uc-1) ++*/ ++ ++void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) ++{ ++ unsigned char digest[36], digest1[SHA_DIGEST_LEN]; ++ int i, j; ++ ++ /* U1 = PRF(P, S || int(i)) */ ++ memcpy(digest, ssid, ssidlength); ++ digest[ssidlength] = (unsigned char)((count>>24) & 0xff); ++ digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); ++ digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); ++ digest[ssidlength+3] = (unsigned char)(count & 0xff); ++ HMAC_SHA1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update ++ ++ /* output = U1 */ ++ memcpy(output, digest1, SHA_DIGEST_LEN); ++ ++ for (i = 1; i < iterations; i++) ++ { ++ /* Un = PRF(P, Un-1) */ ++ HMAC_SHA1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update ++ memcpy(digest1, digest, SHA_DIGEST_LEN); ++ ++ /* output = output xor Un */ ++ for (j = 0; j < SHA_DIGEST_LEN; j++) ++ { ++ output[j] ^= digest[j]; ++ } ++ } ++} ++/* ++* password - ascii string up to 63 characters in length ++* ssid - octet string up to 32 octets ++* ssidlength - length of ssid in octets ++* output must be 40 octets in length and outputs 256 bits of key ++*/ ++int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) ++{ ++ if ((strlen(password) > 63) || (ssidlength > 32)) ++ return 0; ++ ++ F(password, ssid, ssidlength, 4096, 1, output); ++ F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); ++ return 1; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/mlme.c +@@ -0,0 +1,8609 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ mlme.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-08-25 Modify from RT2500 code base ++ John Chang 2004-09-06 modified for RT2600 ++*/ ++ ++#include "../rt_config.h" ++#include ++ ++UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96}; ++ ++UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; ++UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac}; ++UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72}; ++UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; ++UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; ++UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; ++UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++UCHAR RateSwitchTable[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x11, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x21, 0, 30, 50, ++ 0x05, 0x21, 1, 20, 50, ++ 0x06, 0x21, 2, 20, 50, ++ 0x07, 0x21, 3, 15, 50, ++ 0x08, 0x21, 4, 15, 30, ++ 0x09, 0x21, 5, 10, 25, ++ 0x0a, 0x21, 6, 8, 25, ++ 0x0b, 0x21, 7, 8, 25, ++ 0x0c, 0x20, 12, 15, 30, ++ 0x0d, 0x20, 13, 8, 20, ++ 0x0e, 0x20, 14, 8, 20, ++ 0x0f, 0x20, 15, 8, 25, ++ 0x10, 0x22, 15, 8, 25, ++ 0x11, 0x00, 0, 0, 0, ++ 0x12, 0x00, 0, 0, 0, ++ 0x13, 0x00, 0, 0, 0, ++ 0x14, 0x00, 0, 0, 0, ++ 0x15, 0x00, 0, 0, 0, ++ 0x16, 0x00, 0, 0, 0, ++ 0x17, 0x00, 0, 0, 0, ++ 0x18, 0x00, 0, 0, 0, ++ 0x19, 0x00, 0, 0, 0, ++ 0x1a, 0x00, 0, 0, 0, ++ 0x1b, 0x00, 0, 0, 0, ++ 0x1c, 0x00, 0, 0, 0, ++ 0x1d, 0x00, 0, 0, 0, ++ 0x1e, 0x00, 0, 0, 0, ++ 0x1f, 0x00, 0, 0, 0, ++}; ++ ++UCHAR RateSwitchTable11B[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x04, 0x03, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++}; ++ ++UCHAR RateSwitchTable11BG[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x10, 2, 20, 35, ++ 0x05, 0x10, 3, 16, 35, ++ 0x06, 0x10, 4, 10, 25, ++ 0x07, 0x10, 5, 16, 25, ++ 0x08, 0x10, 6, 10, 25, ++ 0x09, 0x10, 7, 10, 13, ++}; ++ ++UCHAR RateSwitchTable11G[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x08, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x10, 0, 20, 101, ++ 0x01, 0x10, 1, 20, 35, ++ 0x02, 0x10, 2, 20, 35, ++ 0x03, 0x10, 3, 16, 35, ++ 0x04, 0x10, 4, 10, 25, ++ 0x05, 0x10, 5, 16, 25, ++ 0x06, 0x10, 6, 10, 25, ++ 0x07, 0x10, 7, 10, 13, ++}; ++ ++#ifdef DOT11_N_SUPPORT ++UCHAR RateSwitchTable11N1S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x09, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 10, 25, ++ 0x06, 0x21, 6, 8, 14, ++ 0x07, 0x21, 7, 8, 14, ++ 0x08, 0x23, 7, 8, 14, ++}; ++ ++UCHAR RateSwitchTable11N2S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N3S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N2SForABand[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N3SForABand[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN1S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0d, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x21, 0, 30,101, //50 ++ 0x05, 0x21, 1, 20, 50, ++ 0x06, 0x21, 2, 20, 50, ++ 0x07, 0x21, 3, 15, 50, ++ 0x08, 0x21, 4, 15, 30, ++ 0x09, 0x21, 5, 10, 25, ++ 0x0a, 0x21, 6, 8, 14, ++ 0x0b, 0x21, 7, 8, 14, ++ 0x0c, 0x23, 7, 8, 14, ++}; ++ ++UCHAR RateSwitchTable11BGN2S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN3S[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 20, 50, ++ 0x04, 0x21, 4, 15, 50, ++#if 1 ++ 0x05, 0x20, 20, 15, 30, ++ 0x06, 0x20, 21, 8, 20, ++ 0x07, 0x20, 22, 8, 20, ++ 0x08, 0x20, 23, 8, 25, ++ 0x09, 0x22, 23, 8, 25, ++#else // for RT2860 2*3 test ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++#endif ++}; ++ ++UCHAR RateSwitchTable11BGN2SForABand[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0c, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x21, 12, 15, 30, ++ 0x07, 0x20, 20, 15, 30, ++ 0x08, 0x20, 21, 8, 20, ++ 0x09, 0x20, 22, 8, 20, ++ 0x0a, 0x20, 23, 8, 25, ++ 0x0b, 0x22, 23, 8, 25, ++}; ++#endif // DOT11_N_SUPPORT // ++ ++PUCHAR ReasonString[] = { ++ /* 0 */ "Reserved", ++ /* 1 */ "Unspecified Reason", ++ /* 2 */ "Previous Auth no longer valid", ++ /* 3 */ "STA is leaving / has left", ++ /* 4 */ "DIS-ASSOC due to inactivity", ++ /* 5 */ "AP unable to hanle all associations", ++ /* 6 */ "class 2 error", ++ /* 7 */ "class 3 error", ++ /* 8 */ "STA is leaving / has left", ++ /* 9 */ "require auth before assoc/re-assoc", ++ /* 10 */ "Reserved", ++ /* 11 */ "Reserved", ++ /* 12 */ "Reserved", ++ /* 13 */ "invalid IE", ++ /* 14 */ "MIC error", ++ /* 15 */ "4-way handshake timeout", ++ /* 16 */ "2-way (group key) handshake timeout", ++ /* 17 */ "4-way handshake IE diff among AssosReq/Rsp/Beacon", ++ /* 18 */ ++}; ++ ++extern UCHAR OfdmRateToRxwiMCS[]; ++// since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. ++// otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate ++ULONG BasicRateMask[12] = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */, ++ 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */, ++ 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */}; ++ ++UCHAR MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00}; ++UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than ++// this value, then it's quaranteed capable of operating in 36 mbps TX rate in ++// clean environment. ++// TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 ++CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; ++ ++UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; ++USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; ++ ++UCHAR SsidIe = IE_SSID; ++UCHAR SupRateIe = IE_SUPP_RATES; ++UCHAR ExtRateIe = IE_EXT_SUPP_RATES; ++#ifdef DOT11_N_SUPPORT ++UCHAR HtCapIe = IE_HT_CAP; ++UCHAR AddHtInfoIe = IE_ADD_HT; ++UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; ++#ifdef DOT11N_DRAFT3 ++UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++UCHAR ErpIe = IE_ERP; ++UCHAR DsIe = IE_DS_PARM; ++UCHAR TimIe = IE_TIM; ++UCHAR WpaIe = IE_WPA; ++UCHAR Wpa2Ie = IE_WPA2; ++UCHAR IbssIe = IE_IBSS_PARM; ++UCHAR Ccx2Ie = IE_CCX_V2; ++UCHAR WapiIe = IE_WAPI; ++ ++extern UCHAR WPA_OUI[]; ++ ++UCHAR SES_OUI[] = {0x00, 0x90, 0x4c}; ++ ++UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; ++ ++// Reset the RFIC setting to new series ++RTMP_RF_REGS RF2850RegTable[] = { ++// ch R1 R2 R3(TX0~4=0) R4 ++ {1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b}, ++ {2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f}, ++ {3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b}, ++ {4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f}, ++ {5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b}, ++ {6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f}, ++ {7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b}, ++ {8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f}, ++ {9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b}, ++ {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f}, ++ {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b}, ++ {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f}, ++ {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b}, ++ {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193}, ++ ++ // 802.11 UNI / HyperLan 2 ++ {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3}, ++ {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193}, ++ {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183}, ++ {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3}, ++ {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b}, ++ {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b}, ++ {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193}, ++ {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3}, ++ {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b}, ++ {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183}, ++ {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193}, ++ {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5. ++ ++ // 802.11 HyperLan 2 ++ {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783}, ++ ++ // 2008.04.30 modified ++ // The system team has AN to improve the EVM value ++ // for channel 102 to 108 for the RT2850/RT2750 dual band solution. ++ {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793}, ++ {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3}, ++ {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193}, ++ ++ {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183}, ++ {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b}, ++ {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3}, ++ {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193}, ++ {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183}, ++ {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193}, ++ {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927 ++ {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3}, ++ {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b}, ++ {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193}, ++ {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b}, ++ {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183}, ++ ++ // 802.11 UNII ++ {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7}, ++ {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187}, ++ {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f}, ++ {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f}, ++ {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7}, ++ {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187}, ++ {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197}, ++ ++ // Japan ++ {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b}, ++ {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13}, ++ {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b}, ++ {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23}, ++ {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13}, ++ {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b}, ++ {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23}, ++ ++ // still lack of MMAC(Japan) ch 34,38,42,46 ++}; ++UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS)); ++ ++FREQUENCY_ITEM FreqItems3020[] = ++{ ++ /**************************************************/ ++ // ISM : 2.4 to 2.483 GHz // ++ /**************************************************/ ++ // 11g ++ /**************************************************/ ++ //-CH---N-------R---K----------- ++ {1, 241, 2, 2}, ++ {2, 241, 2, 7}, ++ {3, 242, 2, 2}, ++ {4, 242, 2, 7}, ++ {5, 243, 2, 2}, ++ {6, 243, 2, 7}, ++ {7, 244, 2, 2}, ++ {8, 244, 2, 7}, ++ {9, 245, 2, 2}, ++ {10, 245, 2, 7}, ++ {11, 246, 2, 2}, ++ {12, 246, 2, 7}, ++ {13, 247, 2, 2}, ++ {14, 248, 2, 4}, ++}; ++#define NUM_OF_3020_CHNL (sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)) ++ ++/* ++ ========================================================================== ++ Description: ++ initialize the MLME task and its data structure (queue, spinlock, ++ timer, state machines). ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Return: ++ always return NDIS_STATUS_SUCCESS ++ ++ ========================================================================== ++*/ ++NDIS_STATUS MlmeInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n")); ++ ++ do ++ { ++ Status = MlmeQueueInit(&pAd->Mlme.Queue); ++ if(Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ pAd->Mlme.bRunning = FALSE; ++ NdisAllocateSpinLock(&pAd->Mlme.TaskLock); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ BssTableInit(&pAd->ScanTab); ++ ++ // init STA state machines ++ AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); ++ AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); ++ AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); ++ SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); ++ WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); ++ AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); ++ ++#ifdef QOS_DLS_SUPPORT ++ DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); ++#endif // QOS_DLS_SUPPORT // ++ ++ ++ // Since we are using switch/case to implement it, the init is different from the above ++ // state machine init ++ MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); ++ ++ // Init mlme periodic timer ++ RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE); ++ ++ // Set mlme periodic timer ++ RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); ++ ++ // software-based RX Antenna diversity ++ RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); ++ ++ } while (FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ main loop of the MLME ++ Pre: ++ Mlme has to be initialized, and there are something inside the queue ++ Note: ++ This function is invoked from MPSetInformation and MPReceive; ++ This task guarantee only one MlmeHandler will run. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeHandler( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_QUEUE_ELEM *Elem = NULL; ++#ifdef APCLI_SUPPORT ++ SHORT apcliIfIndex; ++#endif ++ ++ // Only accept MLME and Frame from peer side, no other (control/data) frame should ++ // get into this state machine ++ ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ if(pAd->Mlme.bRunning) ++ { ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ return; ++ } ++ else ++ { ++ pAd->Mlme.bRunning = TRUE; ++ } ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ ++ while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num)); ++ break; ++ } ++ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ ++ //From message type, determine which state machine I should drive ++ if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) ++ { ++#ifdef RT2870 ++ if (Elem->MsgType == MT2_RESET_CONF) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n")); ++ MlmeRestartStateMachine(pAd); ++ Elem->Occupied = FALSE; ++ Elem->MsgLen = 0; ++ continue; ++ } ++#endif // RT2870 // ++ ++ // if dequeue success ++ switch (Elem->Machine) ++ { ++ // STA state machines ++#ifdef CONFIG_STA_SUPPORT ++ case ASSOC_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); ++ break; ++ case AUTH_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); ++ break; ++ case AUTH_RSP_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); ++ break; ++ case SYNC_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); ++ break; ++ case MLME_CNTL_STATE_MACHINE: ++ MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); ++ break; ++ case WPA_PSK_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); ++ break; ++#ifdef LEAP_SUPPORT ++ case LEAP_STATE_MACHINE: ++ LeapMachinePerformAction(pAd, &pAd->Mlme.LeapMachine, Elem); ++ break; ++#endif ++ case AIRONET_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); ++ break; ++ ++#ifdef QOS_DLS_SUPPORT ++ case DLS_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); ++ break; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ case ACTION_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); ++ break; ++ ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine)); ++ break; ++ } // end of switch ++ ++ // free MLME element ++ Elem->Occupied = FALSE; ++ Elem->MsgLen = 0; ++ ++ } ++ else { ++ DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); ++ } ++ } ++ ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ pAd->Mlme.bRunning = FALSE; ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Destructor of MLME (Destroy queue, state machine, spin lock and timer) ++ Parameters: ++ Adapter - NIC Adapter pointer ++ Post: ++ The MLME task will no longer work properly ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeHalt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BOOLEAN Cancelled; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ // disable BEACON generation and other BEACON related hardware timers ++ AsicDisableSync(pAd); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef QOS_DLS_SUPPORT ++ UCHAR i; ++#endif // QOS_DLS_SUPPORT // ++ // Cancel pending timers ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++ ++#ifdef QOS_DLS_SUPPORT ++ for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); ++ } ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); ++ ++ ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ // Set LED ++ RTMPSetLED(pAd, LED_HALT); ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. ++#ifdef RT2870 ++ { ++ LED_CFG_STRUC LedCfg; ++ RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word); ++ LedCfg.field.LedPolar = 0; ++ LedCfg.field.RLedMode = 0; ++ LedCfg.field.GLedMode = 0; ++ LedCfg.field.YLedMode = 0; ++ RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word); ++ } ++#endif // RT2870 // ++ } ++ ++ RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled ++ ++ MlmeQueueDestroy(&pAd->Mlme.Queue); ++ NdisFreeSpinLock(&pAd->Mlme.TaskLock); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n")); ++} ++ ++VOID MlmeResetRalinkCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt; ++ // clear all OneSecxxx counters. ++ pAd->RalinkCounters.OneSecBeaconSentCnt = 0; ++ pAd->RalinkCounters.OneSecFalseCCACnt = 0; ++ pAd->RalinkCounters.OneSecRxFcsErrCnt = 0; ++ pAd->RalinkCounters.OneSecRxOkCnt = 0; ++ pAd->RalinkCounters.OneSecTxFailCount = 0; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0; ++ pAd->RalinkCounters.OneSecTxRetryOkCount = 0; ++ pAd->RalinkCounters.OneSecRxOkDataCnt = 0; ++ ++ // TODO: for debug only. to be removed ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0; ++ pAd->RalinkCounters.OneSecTxDoneCount = 0; ++ pAd->RalinkCounters.OneSecRxCount = 0; ++ pAd->RalinkCounters.OneSecTxAggregationCount = 0; ++ pAd->RalinkCounters.OneSecRxAggregationCount = 0; ++ ++ return; ++} ++ ++unsigned long rx_AMSDU; ++unsigned long rx_Total; ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is executed periodically to - ++ 1. Decide if it's a right time to turn on PwrMgmt bit of all ++ outgoiing frames ++ 2. Calculate ChannelQuality based on statistics of the last ++ period, so that TX rate won't toggling very frequently between a ++ successful TX and a failed TX. ++ 3. If the calculated ChannelQuality indicated current connection not ++ healthy, then a ROAMing attempt is tried here. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++#define ADHOC_BEACON_LOST_TIME (8*OS_HZ) // 8 sec ++VOID MlmePeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ULONG TxTotalCnt; ++ PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RADIO_MEASUREMENT | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS)))) ++ return; ++ ++ RT28XX_MLME_PRE_SANITY_CHECK(pAd); ++ ++#ifdef RALINK_ATE ++ /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) ++ { ++ pAd->Mlme.PeriodicRound ++; ++ return; ++ } ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ ++ if (pAd->Mlme.PeriodicRound & 0x1) ++ { ++ // This is the fix for wifi 11n extension channel overlapping test case. for 2860D ++ if (((pAd->MACVersion & 0xffff) == 0x0101) && ++ (STA_TGN_WIFI_ON(pAd)) && ++ (pAd->CommonCfg.IOTestParm.bToggle == FALSE)) ++ ++ { ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf); ++ pAd->CommonCfg.IOTestParm.bToggle = TRUE; ++ } ++ else if ((STA_TGN_WIFI_ON(pAd)) && ++ ((pAd->MACVersion & 0xffff) == 0x0101)) ++ { ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f); ++ pAd->CommonCfg.IOTestParm.bToggle = FALSE; ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->bUpdateBcnCntDone = FALSE; ++ ++// RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); ++ pAd->Mlme.PeriodicRound ++; ++ ++ // execute every 500ms ++ if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ // perform dynamic tx rate switching based on past TX history ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) ++ MlmeDynamicTxRateSwitching(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // Normal 1 second Mlme PeriodicExec. ++ if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) ++ { ++ pAd->Mlme.OneSecPeriodicRound ++; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ /* request from Baron : move this routine from later to here */ ++ /* for showing Rx error count in ATE RXFRAME */ ++ NICUpdateRawCounters(pAd); ++ if (pAd->ate.bRxFer == 1) ++ { ++ pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); ++ pAd->ate.RxCntPerSec = 0; ++ ++ if (pAd->ate.RxAntennaSel == 0) ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", ++ pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); ++ else ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); ++ } ++ MlmeResetRalinkCounters(pAd); ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ ++ if (rx_Total) ++ { ++ ++ // reset counters ++ rx_AMSDU = 0; ++ rx_Total = 0; ++ } ++ ++ //ORIBATimerTimeout(pAd); ++ ++ // Media status changed, report to NDIS ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ ++ } ++ else ++ { ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ } ++ } ++ ++ NdisGetSystemUpTime(&pAd->Mlme.Now32); ++ ++ // add the most up-to-date h/w raw counters into software variable, so that ++ // the dynamic tuning mechanism below are based on most up-to-date information ++ NICUpdateRawCounters(pAd); ++ ++#ifdef RT2870 ++ RT2870_WatchDog(pAd); ++#endif // RT2870 // ++ ++#ifdef DOT11_N_SUPPORT ++ // Need statistics after read counter. So put after NICUpdateRawCounters ++ ORIBATimerTimeout(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ // if MGMT RING is full more than twice within 1 second, we consider there's ++ // a hardware problem stucking the TX path. In this case, try a hardware reset ++ // to recover the system ++ // if (pAd->RalinkCounters.MgmtRingFullCount >= 2) ++ // RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR); ++ // else ++ // pAd->RalinkCounters.MgmtRingFullCount = 0; ++ ++ // The time period for checking antenna is according to traffic ++ if (pAd->Mlme.bEnableAutoAntennaCheck) ++ { ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt > 50) ++ { ++ if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) ++ { ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ else ++ { ++ if (pAd->Mlme.OneSecPeriodicRound % 3 == 0) ++ { ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ STAMlmePeriodicExec(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ MlmeResetRalinkCounters(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ { ++ // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock ++ // and sending CTS-to-self over and over. ++ // Software Patch Solution: ++ // 1. Polling debug state register 0x10F4 every one second. ++ // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. ++ // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. ++ ++ UINT32 MacReg = 0; ++ ++ RTMP_IO_READ32(pAd, 0x10F4, &MacReg); ++ if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20))) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ RTMPusecDelay(1); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC); ++ ++ DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n")); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ ++ pAd->bUpdateBcnCntDone = FALSE; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID STAMlmePeriodicExec( ++ PRTMP_ADAPTER pAd) ++{ ++ ULONG TxTotalCnt; ++ int i; ++ ++// ++// We return here in ATE mode, because the statistics ++// that ATE needs are not collected via this routine. ++// ++#ifdef RALINK_ATE ++ // It is supposed that we will never reach here in ATE mode. ++ ASSERT(!(ATE_ON(pAd))); ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // WPA MIC error should block association attempt for 60 seconds ++ if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) ++ pAd->StaCfg.bBlockAssoc = FALSE; ++ } ++ ++ if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ pAd->PreMediaState = pAd->IndicateMediaState; ++ } ++ ++ ++ ++ ++ AsicStaBbpTuning(pAd); ++ ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ // update channel quality for Roaming and UI LinkQuality display ++ MlmeCalculateChannelQuality(pAd, pAd->Mlme.Now32); ++ } ++ ++ // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if ++ // Radio is currently in noisy environment ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ AsicAdjustTxPower(pAd); ++ ++ if (INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ // Check DLS time out, then tear down those session ++ RTMPCheckDLSTimeOut(pAd); ++#endif // QOS_DLS_SUPPORT // ++ ++ // Is PSM bit consistent with user power management policy? ++ // This is the only place that will set PSM bit ON. ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ MlmeCheckPsmChange(pAd, pAd->Mlme.Now32); ++ ++ pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt; ++ ++ if ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && ++ ((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt < 600))) ++ { ++ RTMPSetAGCInitValue(pAd, BW_20); ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd)))); ++ } ++ ++ //if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && ++ // (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) ++ { ++ // When APSD is enabled, the period changes as 20 sec ++ if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8) ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ } ++ else ++ { ++ // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) ++ if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) ++ { ++ if (pAd->CommonCfg.bWmmCapable) ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ else ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); ++ } ++ } ++ } ++ ++ if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); ++ pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; ++ pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime; ++ ++ // Lost AP, send disconnect & link down event ++ LinkDown(pAd, FALSE); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ // RTMPPatchMacBbpBug(pAd); ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) ++ { ++ pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ ++ // Add auto seamless roaming ++ if (pAd->StaCfg.bFastRoaming) ++ { ++ SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam)); ++ ++ if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam) ++ { ++ MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32); ++ } ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ //radar detect ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ RadarDetectPeriodic(pAd); ++ } ++ ++ // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState ++ // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can ++ // join later. ++ if ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) && ++ OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ MLME_START_REQ_STRUCT StartReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n")); ++ LinkDown(pAd, FALSE); ++ ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; ++ ++ if (pEntry->ValidAsCLI == FALSE) ++ continue; ++ ++ if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) ++ MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); ++ } ++ } ++ else // no INFRA nor ADHOC connection ++ { ++ ++ if (pAd->StaCfg.bScanReqIsFromWebUI && ++ ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32)) ++ goto SKIP_AUTO_SCAN_CONN; ++ else ++ pAd->StaCfg.bScanReqIsFromWebUI = FALSE; ++ ++ if ((pAd->StaCfg.bAutoReconnect == TRUE) ++ && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) ++ && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) ++ { ++ if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) ++ { ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); ++ ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ // Reset Missed scan number ++ pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; ++ } ++ else if (pAd->StaCfg.BssType == BSS_ADHOC) // Quit the forever scan when in a very clean room ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) ++ { ++ MlmeAutoScan(pAd); ++ pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; ++ } ++ else ++ { ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else ++#endif // CARRIER_DETECTION_SUPPORT // ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ } ++ } ++ } ++ ++SKIP_AUTO_SCAN_CONN: ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) ++ { ++ pAd->MacTab.fAnyBASession = TRUE; ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++ else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE)) ++ { ++ pAd->MacTab.fAnyBASession = FALSE; ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) ++ TriEventCounterMaintenance(pAd); ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ return; ++} ++ ++// Link down report ++VOID LinkDownExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeAutoScan( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n")); ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeAutoReconnectLastSSID( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && ++ (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) ++ { ++ NDIS_802_11_SSID OidSsid; ++ OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen; ++ NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen)); ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ &OidSsid); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ========================================================================== ++ Validate SSID for connection try and rescan purpose ++ Valid SSID will have visible chars only. ++ The valid length is from 0 to 32. ++ IRQL = DISPATCH_LEVEL ++ ========================================================================== ++ */ ++BOOLEAN MlmeValidateSSID( ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen) ++{ ++ int index; ++ ++ if (SsidLen > MAX_LEN_OF_SSID) ++ return (FALSE); ++ ++ // Check each character value ++ for (index = 0; index < SsidLen; index++) ++ { ++ if (pSsid[index] < 0x20) ++ return (FALSE); ++ } ++ ++ // All checked ++ return (TRUE); ++} ++ ++VOID MlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx) ++{ ++ do ++ { ++ // decide the rate table for tuning ++ if (pAd->CommonCfg.TxRateTableSize > 0) ++ { ++ *ppTable = RateSwitchTable; ++ *pTableSize = RateSwitchTable[0]; ++ *pInitTxRateIdx = RateSwitchTable[1]; ++ ++ break; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && ++ (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ {// 11N 1S Adhoc ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ ++ } ++ else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && ++ (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ (pEntry->HTCapability.MCSSet[1] == 0xff) && ++ (pAd->Antenna.field.TxPath == 2)) ++ {// 11N 2S Adhoc ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if ((pEntry->RateLen == 4) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ } ++ else if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ } ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ //if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ++ // ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) ++ {// 11BGN 1S AP ++ *ppTable = RateSwitchTable11BGN1S; ++ *pTableSize = RateSwitchTable11BGN1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN1S[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ++ // (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) ++ if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) ++ {// 11BGN 2S AP ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11BGN2S; ++ *pTableSize = RateSwitchTable11BGN2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN2S[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11BGN2SForABand; ++ *pTableSize = RateSwitchTable11BGN2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1]; ++ ++ } ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) ++ {// 11N 1S AP ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) ++ if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) ++ {// 11N 2S AP ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ } ++ ++ break; ++ } ++#endif // DOT11_N_SUPPORT // ++ //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen == 4) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// B only AP ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen > 8) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// B/G mixed AP ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen == 8) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// G only AP ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef DOT11_N_SUPPORT ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) ++#endif // DOT11_N_SUPPORT // ++ { // Legacy mode ++ if (pAd->CommonCfg.MaxTxRate <= RATE_11) ++ { ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ } ++ else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11)) ++ { ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ } ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ if (pAd->CommonCfg.TxStream == 1) ++ { ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.TxStream == 1) ++ { ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", ++ pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } while(FALSE); ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ This routine checks if there're other APs out there capable for ++ roaming. Caller should call this routine only when Link up in INFRA mode ++ and channel quality is below CQI_GOOD_THRESHOLD. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Output: ++ ========================================================================== ++ */ ++VOID MlmeCheckForRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ USHORT i; ++ BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; ++ BSS_ENTRY *pBss; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n")); ++ // put all roaming candidates into RoamTab, and sort in RSSI order ++ BssTableInit(pRoamTab); ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ pBss = &pAd->ScanTab.BssEntry[i]; ++ ++ if ((pBss->LastBeaconRxTime + BEACON_LOST_TIME) < Now32) ++ continue; // AP disappear ++ if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) ++ continue; // RSSI too weak. forget it. ++ if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) ++ continue; // skip current AP ++ if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA)) ++ continue; // only AP with stronger RSSI is eligible for roaming ++ ++ // AP passing all above rules is put into roaming candidate table ++ NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); ++ pRoamTab->BssNr += 1; ++ } ++ ++ if (pRoamTab->BssNr > 0) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ pAd->RalinkCounters.PoorCQIRoamingCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine checks if there're other APs out there capable for ++ roaming. Caller should call this routine only when link up in INFRA mode ++ and channel quality is below CQI_GOOD_THRESHOLD. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Output: ++ ========================================================================== ++ */ ++VOID MlmeCheckForFastRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now) ++{ ++ USHORT i; ++ BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; ++ BSS_ENTRY *pBss; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n")); ++ // put all roaming candidates into RoamTab, and sort in RSSI order ++ BssTableInit(pRoamTab); ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ pBss = &pAd->ScanTab.BssEntry[i]; ++ ++ if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel)) ++ continue; // RSSI too weak. forget it. ++ if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) ++ continue; // skip current AP ++ if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) ++ continue; // skip different SSID ++ if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA)) ++ continue; // skip AP without better RSSI ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi)); ++ // AP passing all above rules is put into roaming candidate table ++ NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); ++ pRoamTab->BssNr += 1; ++ } ++ ++ if (pRoamTab->BssNr > 0) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ pAd->RalinkCounters.PoorCQIRoamingCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ } ++ // Maybe site survey required ++ else ++ { ++ if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); ++ pAd->StaCfg.ScanCnt = 2; ++ pAd->StaCfg.LastScanTime = Now; ++ MlmeAutoScan(pAd); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine calculates TxPER, RxPER of the past N-sec period. And ++ according to the calculation result, ChannelQuality is calculated here ++ to decide if current AP is still doing the job. ++ ++ If ChannelQuality is not good, a ROAMing attempt may be tried later. ++ Output: ++ StaCfg.ChannelQuality - 0..100 ++ ++ IRQL = DISPATCH_LEVEL ++ ++ NOTE: This routine decide channle quality based on RX CRC error ratio. ++ Caller should make sure a function call to NICUpdateRawCounters(pAd) ++ is performed right before this routine, so that this routine can decide ++ channel quality based on the most up-to-date information ++ ========================================================================== ++ */ ++VOID MlmeCalculateChannelQuality( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ ULONG TxOkCnt, TxCnt, TxPER, TxPRR; ++ ULONG RxCnt, RxPER; ++ UCHAR NorRssi; ++ CHAR MaxRssi; ++ ULONG BeaconLostTime = BEACON_LOST_TIME; ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // longer beacon lost time when carrier detection enabled ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ BeaconLostTime = BEACON_LOST_TIME + BEACON_LOST_TIME/2; ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); ++ ++ // ++ // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics ++ // ++ TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount; ++ TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount; ++ if (TxCnt < 5) ++ { ++ TxPER = 0; ++ TxPRR = 0; ++ } ++ else ++ { ++ TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt; ++ TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt; ++ } ++ ++ // ++ // calculate RX PER - don't take RxPER into consideration if too few sample ++ // ++ RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt; ++ if (RxCnt < 5) ++ RxPER = 0; ++ else ++ RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt; ++ ++ // ++ // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER ++ // ++ if (INFRA_ON(pAd) && ++ (pAd->RalinkCounters.OneSecTxNoRetryOkCount < 2) && // no heavy traffic ++ (pAd->StaCfg.LastBeaconRxTime + BeaconLostTime < Now32)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt)); ++ pAd->Mlme.ChannelQuality = 0; ++ } ++ else ++ { ++ // Normalize Rssi ++ if (MaxRssi > -40) ++ NorRssi = 100; ++ else if (MaxRssi < -90) ++ NorRssi = 0; ++ else ++ NorRssi = (MaxRssi + 90) * 2; ++ ++ // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) ++ pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi + ++ TX_WEIGHTING * (100 - TxPRR) + ++ RX_WEIGHTING* (100 - RxPER)) / 100; ++ if (pAd->Mlme.ChannelQuality >= 100) ++ pAd->Mlme.ChannelQuality = 100; ++ } ++ ++} ++ ++VOID MlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate) ++{ ++ UCHAR MaxMode = MODE_OFDM; ++ ++#ifdef DOT11_N_SUPPORT ++ MaxMode = MODE_HTGREENFIELD; ++ ++ if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; ++ ++ if (pTxRate->CurrMCS < MCS_AUTO) ++ pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS; ++ ++ if (pAd->StaCfg.HTPhyMode.field.MCS > 7) ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; ++ ++ if (ADHOC_ON(pAd)) ++ { ++ // If peer adhoc is b-only mode, we can't send 11g rate. ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ pEntry->HTPhyMode.field.STBC = STBC_NONE; ++ ++ // ++ // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary ++ // ++ pEntry->HTPhyMode.field.MODE = pTxRate->Mode; ++ pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ ++ // Patch speed error in status page ++ pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE; ++ } ++ else ++ { ++ if (pTxRate->Mode <= MaxMode) ++ pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ ++#ifdef DOT11_N_SUPPORT ++ // Reexam each bandwidth's SGI support. ++ if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) ++ { ++ if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE))) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE))) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ } ++ ++ // Turn RTS/CTS rate to 6Mbps. ++ if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) ++ { ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ if (pAd->MacTab.fAnyBASession) ++ { ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ else ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ } ++ else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) ++ { ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ if (pAd->MacTab.fAnyBASession) ++ { ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ else ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ } ++ else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) ++ { ++ AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ ++ } ++ else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) ++ { ++ AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; ++ pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && ++ pAd->WIFItestbed.bGreenField) ++ pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine calculates the acumulated TxPER of eaxh TxRate. And ++ according to the calculation result, change CommonCfg.TxRate which ++ is the stable TX Rate we expect the Radio situation could sustained. ++ ++ CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} ++ Output: ++ CommonCfg.TxRate - ++ ++ IRQL = DISPATCH_LEVEL ++ ++ NOTE: ++ call this routine every second ++ ========================================================================== ++ */ ++VOID MlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx; ++ ULONG i, AccuTxTotalCnt = 0, TxTotalCnt; ++ ULONG TxErrorRatio = 0; ++ BOOLEAN bTxRateChanged, bUpgradeQuality = FALSE; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; ++ CHAR Rssi, RssiOffset = 0; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; ++ MAC_TABLE_ENTRY *pEntry; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ // ++ // walk through MAC table, see if need to change AP's TX rate toward each entry ++ // ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ // check if this entry need to switch rate automatically ++ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) ++ continue; ++ ++ if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) ++ { ++ Rssi = RTMPMaxRssi(pAd, ++ pAd->StaCfg.RssiSample.AvgRssi0, ++ pAd->StaCfg.RssiSample.AvgRssi1, ++ pAd->StaCfg.RssiSample.AvgRssi2); ++ ++ // Update statistic counter ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ pAd->bUpdateBcnCntDone = TRUE; ++ TxRetransmit = StaTx1.field.TxRetransmit; ++ TxSuccess = StaTx1.field.TxSuccess; ++ TxFailCount = TxStaCnt0.field.TxFailCount; ++ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; ++ ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ ++ // if no traffic in the past 1-sec period, don't change TX rate, ++ // but clear all bad history. because the bad history may affect the next ++ // Chariot throughput test ++ AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; ++ } ++ else ++ { ++ if (INFRA_ON(pAd) && (i == 1)) ++ Rssi = RTMPMaxRssi(pAd, ++ pAd->StaCfg.RssiSample.AvgRssi0, ++ pAd->StaCfg.RssiSample.AvgRssi1, ++ pAd->StaCfg.RssiSample.AvgRssi2); ++ else ++ Rssi = RTMPMaxRssi(pAd, ++ pEntry->RssiSample.AvgRssi0, ++ pEntry->RssiSample.AvgRssi1, ++ pEntry->RssiSample.AvgRssi2); ++ ++ TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + ++ pEntry->OneSecTxRetryOkCount + ++ pEntry->OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; ++ } ++ ++ CurrRateIdx = pEntry->CurrTxRateIndex; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); ++ ++ if (CurrRateIdx >= TableSize) ++ { ++ CurrRateIdx = TableSize - 1; ++ } ++ ++ // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. ++ // So need to sync here. ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS) ++ //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ ) ++ { ++ ++ // Need to sync Real Tx rate and our record. ++ // Then return for next DRS. ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5]; ++ pEntry->CurrTxRateIndex = InitTxRateIdx; ++ MlmeSetTxRate(pAd, pEntry, pCurrTxRate); ++ ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ continue; ++ } ++ ++ // decide the next upgrade rate and downgrade rate, if any ++ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx -1; ++ } ++ else if (CurrRateIdx == 0) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx; ++ } ++ else if (CurrRateIdx == (TableSize - 1)) ++ { ++ UpRateIdx = CurrRateIdx; ++ DownRateIdx = CurrRateIdx - 1; ++ } ++ ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) ++ { ++ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); ++ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ TrainUp = pCurrTxRate->TrainUp; ++ TrainDown = pCurrTxRate->TrainDown; ++ } ++ ++ //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; ++ ++ // ++ // Keep the last time TxRateChangeAction status. ++ // ++ pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction; ++ ++ ++ ++ // ++ // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI ++ // (criteria copied from RT2500 for Netopia case) ++ // ++ if (TxTotalCnt <= 15) ++ { ++ CHAR idx = 0; ++ UCHAR TxRateIdx; ++ //UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; ++ UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0; ++ UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; ++ UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3 ++ ++ // check the existence and index of each needed MCS ++ while (idx < pTable[0]) ++ { ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5]; ++ ++ if (pCurrTxRate->CurrMCS == MCS_0) ++ { ++ MCS0 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_1) ++ { ++ MCS1 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_2) ++ { ++ MCS2 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_3) ++ { ++ MCS3 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_4) ++ { ++ MCS4 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_5) ++ { ++ MCS5 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_6) ++ { ++ MCS6 = idx; ++ } ++ //else if (pCurrTxRate->CurrMCS == MCS_7) ++ else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput ++ { ++ MCS7 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_12) ++ { ++ MCS12 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_13) ++ { ++ MCS13 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_14) ++ { ++ MCS14 = idx; ++ } ++ //else if ((pCurrTxRate->CurrMCS == MCS_15)/* && (pCurrTxRate->ShortGI == GI_800)*/) //we hope to use ShortGI as initial rate ++ else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) //we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI ++ { ++ MCS15 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3 ++ { ++ MCS20 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_21) ++ { ++ MCS21 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_22) ++ { ++ MCS22 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_23) ++ { ++ MCS23 = idx; ++ } ++ idx ++; ++ } ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ RssiOffset = 2; ++ } ++ else ++ { ++ RssiOffset = 5; ++ } ++ } ++ else ++ { ++ if (pAd->NicConfig2.field.ExternalLNAForA) ++ { ++ RssiOffset = 5; ++ } ++ else ++ { ++ RssiOffset = 8; ++ } ++ } ++#ifdef DOT11_N_SUPPORT ++ /*if (MCS15)*/ ++ if ((pTable == RateSwitchTable11BGN3S) || ++ (pTable == RateSwitchTable11N3S) || ++ (pTable == RateSwitchTable)) ++ {// N mode with 3 stream // 3*3 ++ if (MCS23 && (Rssi >= -70)) ++ TxRateIdx = MCS15; ++ else if (MCS22 && (Rssi >= -72)) ++ TxRateIdx = MCS14; ++ else if (MCS21 && (Rssi >= -76)) ++ TxRateIdx = MCS13; ++ else if (MCS20 && (Rssi >= -78)) ++ TxRateIdx = MCS12; ++ else if (MCS4 && (Rssi >= -82)) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi >= -84)) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi >= -86)) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi >= -88)) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++// else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) ++ else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3 ++ {// N mode with 2 stream ++ if (MCS15 && (Rssi >= (-70+RssiOffset))) ++ TxRateIdx = MCS15; ++ else if (MCS14 && (Rssi >= (-72+RssiOffset))) ++ TxRateIdx = MCS14; ++ else if (MCS13 && (Rssi >= (-76+RssiOffset))) ++ TxRateIdx = MCS13; ++ else if (MCS12 && (Rssi >= (-78+RssiOffset))) ++ TxRateIdx = MCS12; ++ else if (MCS4 && (Rssi >= (-82+RssiOffset))) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi >= (-84+RssiOffset))) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi >= (-86+RssiOffset))) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi >= (-88+RssiOffset))) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) ++ {// N mode with 1 stream ++ if (MCS7 && (Rssi > (-72+RssiOffset))) ++ TxRateIdx = MCS7; ++ else if (MCS6 && (Rssi > (-74+RssiOffset))) ++ TxRateIdx = MCS6; ++ else if (MCS5 && (Rssi > (-77+RssiOffset))) ++ TxRateIdx = MCS5; ++ else if (MCS4 && (Rssi > (-79+RssiOffset))) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi > (-81+RssiOffset))) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi > (-83+RssiOffset))) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi > (-86+RssiOffset))) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ {// Legacy mode ++ if (MCS7 && (Rssi > -70)) ++ TxRateIdx = MCS7; ++ else if (MCS6 && (Rssi > -74)) ++ TxRateIdx = MCS6; ++ else if (MCS5 && (Rssi > -78)) ++ TxRateIdx = MCS5; ++ else if (MCS4 && (Rssi > -82)) ++ TxRateIdx = MCS4; ++ else if (MCS4 == 0) // for B-only mode ++ TxRateIdx = MCS3; ++ else if (MCS3 && (Rssi > -85)) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi > -87)) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi > -90)) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ ++ // if (TxRateIdx != pAd->CommonCfg.TxRateIndex) ++ { ++ pEntry->CurrTxRateIndex = TxRateIdx; ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ ++ NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ pEntry->fLastSecAccordingRSSI = TRUE; ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ continue; ++ } ++ ++ if (pEntry->fLastSecAccordingRSSI == TRUE) ++ { ++ pEntry->fLastSecAccordingRSSI = FALSE; ++ pEntry->LastSecTxRateChangeAction = 0; ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ continue; ++ } ++ ++ do ++ { ++ BOOLEAN bTrainUpDown = FALSE; ++ ++ pEntry->CurrTxRateStableTime ++; ++ ++ // downgrade TX quality if PER >= Rate-Down threshold ++ if (TxErrorRatio >= TrainDown) ++ { ++ bTrainUpDown = TRUE; ++ pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ // upgrade TX quality if PER <= Rate-Up threshold ++ else if (TxErrorRatio <= TrainUp) ++ { ++ bTrainUpDown = TRUE; ++ bUpgradeQuality = TRUE; ++ if (pEntry->TxQuality[CurrRateIdx]) ++ pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate ++ ++ if (pEntry->TxRateUpPenalty) ++ pEntry->TxRateUpPenalty --; ++ else if (pEntry->TxQuality[UpRateIdx]) ++ pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality ++ } ++ ++ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio; ++ ++ if (bTrainUpDown) ++ { ++ // perform DRS - consider TxRate Down first, then rate up. ++ if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND)) ++ { ++ pEntry->CurrTxRateIndex = DownRateIdx; ++ } ++ else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0)) ++ { ++ pEntry->CurrTxRateIndex = UpRateIdx; ++ } ++ } ++ } while (FALSE); ++ ++ // if rate-up happen, clear all bad history of all TX rates ++ if (pEntry->CurrTxRateIndex > CurrRateIdx) ++ { ++ pEntry->CurrTxRateStableTime = 0; ++ pEntry->TxRateUpPenalty = 0; ++ pEntry->LastSecTxRateChangeAction = 1; // rate UP ++ NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ ++ // ++ // For TxRate fast train up ++ // ++ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) ++ { ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; ++ } ++ bTxRateChanged = TRUE; ++ } ++ // if rate-down happen, only clear DownRate's bad history ++ else if (pEntry->CurrTxRateIndex < CurrRateIdx) ++ { ++ pEntry->CurrTxRateStableTime = 0; ++ pEntry->TxRateUpPenalty = 0; // no penalty ++ pEntry->LastSecTxRateChangeAction = 2; // rate DOWN ++ pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; ++ pEntry->PER[pEntry->CurrTxRateIndex] = 0; ++ ++ // ++ // For TxRate fast train down ++ // ++ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) ++ { ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; ++ } ++ bTxRateChanged = TRUE; ++ } ++ else ++ { ++ pEntry->LastSecTxRateChangeAction = 0; // rate no change ++ bTxRateChanged = FALSE; ++ } ++ ++ pEntry->LastTxOkCount = TxSuccess; ++ ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; ++ if (bTxRateChanged && pNextTxRate) ++ { ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Station side, Auto TxRate faster train up timer call back function. ++ ++ Arguments: ++ SystemSpecific1 - Not used. ++ FunctionContext - Pointer to our Adapter context. ++ SystemSpecific2 - Not used. ++ SystemSpecific3 - Not used. ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID StaQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; ++ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; ++ ULONG TxTotalCnt; ++ ULONG TxErrorRatio = 0; ++ BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ CHAR Rssi, ratio; ++ ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; ++ MAC_TABLE_ENTRY *pEntry; ++ ULONG i; ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; ++ ++ // ++ // walk through MAC table, see if need to change AP's TX rate toward each entry ++ // ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ // check if this entry need to switch rate automatically ++ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) ++ continue; ++ ++ if (INFRA_ON(pAd) && (i == 1)) ++ Rssi = RTMPMaxRssi(pAd, ++ pAd->StaCfg.RssiSample.AvgRssi0, ++ pAd->StaCfg.RssiSample.AvgRssi1, ++ pAd->StaCfg.RssiSample.AvgRssi2); ++ else ++ Rssi = RTMPMaxRssi(pAd, ++ pEntry->RssiSample.AvgRssi0, ++ pEntry->RssiSample.AvgRssi1, ++ pEntry->RssiSample.AvgRssi2); ++ ++ CurrRateIdx = pAd->CommonCfg.TxRateIndex; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); ++ ++ // decide the next upgrade rate and downgrade rate, if any ++ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx -1; ++ } ++ else if (CurrRateIdx == 0) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx; ++ } ++ else if (CurrRateIdx == (TableSize - 1)) ++ { ++ UpRateIdx = CurrRateIdx; ++ DownRateIdx = CurrRateIdx - 1; ++ } ++ ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) ++ { ++ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); ++ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ TrainUp = pCurrTxRate->TrainUp; ++ TrainDown = pCurrTxRate->TrainDown; ++ } ++ ++ if (pAd->MacTab.Size == 1) ++ { ++ // Update statistic counter ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ ++ TxRetransmit = StaTx1.field.TxRetransmit; ++ TxSuccess = StaTx1.field.TxSuccess; ++ TxFailCount = TxStaCnt0.field.TxFailCount; ++ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; ++ ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ ++#if 0 // test by Gary. ++ // if no traffic in the past 1-sec period, don't change TX rate, ++ // but clear all bad history. because the bad history may affect the next ++ // Chariot throughput test ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++#endif ++ if (TxTotalCnt) ++ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; ++ } ++ else ++ { ++ TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + ++ pEntry->OneSecTxRetryOkCount + ++ pEntry->OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; ++ } ++ ++ ++ // ++ // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI ++ // (criteria copied from RT2500 for Netopia case) ++ // ++ if (TxTotalCnt <= 12) ++ { ++ NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ ++ if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) ++ { ++ pAd->CommonCfg.TxRateIndex = DownRateIdx; ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) ++ { ++ pAd->CommonCfg.TxRateIndex = UpRateIdx; ++ } ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n")); ++ return; ++ } ++ ++ do ++ { ++ ULONG OneSecTxNoRetryOKRationCount; ++ ++ if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0) ++ ratio = 5; ++ else ++ ratio = 4; ++ ++ // downgrade TX quality if PER >= Rate-Down threshold ++ if (TxErrorRatio >= TrainDown) ++ { ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ ++ pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio; ++ ++ OneSecTxNoRetryOKRationCount = (TxSuccess * ratio); ++ ++ // perform DRS - consider TxRate Down first, then rate up. ++ if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) ++ { ++ if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) ++ { ++ pAd->CommonCfg.TxRateIndex = DownRateIdx; ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ ++ } ++ ++ } ++ else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) ++ { ++ if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) ++ { ++ ++ } ++ else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) ++ { ++ pAd->CommonCfg.TxRateIndex = UpRateIdx; ++ } ++ } ++ }while (FALSE); ++ ++ // if rate-up happen, clear all bad history of all TX rates ++ if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) ++ { ++ pAd->DrsCounters.TxRateUpPenalty = 0; ++ NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ bTxRateChanged = TRUE; ++ } ++ // if rate-down happen, only clear DownRate's bad history ++ else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex)); ++ ++ pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty ++ pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; ++ pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; ++ bTxRateChanged = TRUE; ++ } ++ else ++ { ++ bTxRateChanged = FALSE; ++ } ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5]; ++ if (bTxRateChanged && pNextTxRate) ++ { ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is executed periodically inside MlmePeriodicExec() after ++ association with an AP. ++ It checks if StaCfg.Psm is consistent with user policy (recorded in ++ StaCfg.WindowsPowerMode). If not, enforce user policy. However, ++ there're some conditions to consider: ++ 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all ++ the time when Mibss==TRUE ++ 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE ++ if outgoing traffic available in TxRing or MgmtRing. ++ Output: ++ 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeCheckPsmChange( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ ULONG PowerMode; ++ ++ // condition - ++ // 1. Psm maybe ON only happen in INFRASTRUCTURE mode ++ // 2. user wants either MAX_PSP or FAST_PSP ++ // 3. but current psm is not in PWR_SAVE ++ // 4. CNTL state machine is not doing SCANning ++ // 5. no TX SUCCESS event for the past 1-sec period ++#ifdef NDIS51_MINIPORT ++ if (pAd->StaCfg.WindowsPowerProfile == NdisPowerProfileBattery) ++ PowerMode = pAd->StaCfg.WindowsBatteryPowerMode; ++ else ++#endif ++ PowerMode = pAd->StaCfg.WindowsPowerMode; ++ ++ if (INFRA_ON(pAd) && ++ (PowerMode != Ndis802_11PowerModeCAM) && ++ (pAd->StaCfg.Psm == PWR_ACTIVE) && ++// (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) /*&& ++ (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && ++ (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/) ++ { ++ NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); ++ pAd->RalinkCounters.RxCountSinceLastNULL = 0; ++ MlmeSetPsmBit(pAd, PWR_SAVE); ++ if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) ++ { ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); ++ } ++ else ++ { ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ } ++ } ++} ++ ++// IRQL = PASSIVE_LEVEL ++// IRQL = DISPATCH_LEVEL ++VOID MlmeSetPsmBit( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm) ++{ ++ AUTO_RSP_CFG_STRUC csr4; ++ ++ pAd->StaCfg.Psm = psm; ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); ++ csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm)); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeSetTxPreamble( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TxPreamble) ++{ ++ AUTO_RSP_CFG_STRUC csr4; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ //TxPreamble = Rt802_11PreambleLong; ++ ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); ++ if (TxPreamble == Rt802_11PreambleLong) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ csr4.field.AutoResponderPreamble = 0; ++ } ++ else ++ { ++ // NOTE: 1Mbps should always use long preamble ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n")); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ csr4.field.AutoResponderPreamble = 1; ++ } ++ ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Update basic rate bitmap ++ ========================================================================== ++ */ ++ ++VOID UpdateBasicRateBitmap( ++ IN PRTMP_ADAPTER pAdapter) ++{ ++ INT i, j; ++ /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */ ++ UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; ++ UCHAR *sup_p = pAdapter->CommonCfg.SupRate; ++ UCHAR *ext_p = pAdapter->CommonCfg.ExtRate; ++ ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap; ++ ++ ++ /* if A mode, always use fix BasicRateBitMap */ ++ //if (pAdapter->CommonCfg.Channel == PHY_11A) ++ if (pAdapter->CommonCfg.Channel > 14) ++ pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */ ++ /* End of if */ ++ ++ if (pAdapter->CommonCfg.BasicRateBitmap > 4095) ++ { ++ /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */ ++ return; ++ } /* End of if */ ++ ++ for(i=0; iCommonCfg.DesireRate[i] & 0x7f) ++ { ++ case 2: Rate = RATE_1; num++; break; ++ case 4: Rate = RATE_2; num++; break; ++ case 11: Rate = RATE_5_5; num++; break; ++ case 22: Rate = RATE_11; num++; break; ++ case 12: Rate = RATE_6; num++; break; ++ case 18: Rate = RATE_9; num++; break; ++ case 24: Rate = RATE_12; num++; break; ++ case 36: Rate = RATE_18; num++; break; ++ case 48: Rate = RATE_24; num++; break; ++ case 72: Rate = RATE_36; num++; break; ++ case 96: Rate = RATE_48; num++; break; ++ case 108: Rate = RATE_54; num++; break; ++ //default: Rate = RATE_1; break; ++ } ++ if (MaxDesire < Rate) MaxDesire = Rate; ++ } ++ ++//=========================================================================== ++//=========================================================================== ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pHtPhy = &pAd->StaCfg.HTPhyMode; ++ pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; ++ pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; ++ ++ auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; ++ HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; ++ ++ if ((pAd->StaCfg.BssType == BSS_ADHOC) && ++ (pAd->CommonCfg.PhyMode == PHY_11B) && ++ (MaxDesire > RATE_11)) ++ { ++ MaxDesire = RATE_11; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->CommonCfg.MaxDesiredRate = MaxDesire; ++ pMinHtPhy->word = 0; ++ pMaxHtPhy->word = 0; ++ pHtPhy->word = 0; ++ ++ // Auto rate switching is enabled only if more than one DESIRED RATES are ++ // specified; otherwise disabled ++ if (num <= 1) ++ { ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; ++ *auto_rate_cur_p = FALSE; ++ } ++ else ++ { ++ //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; ++ *auto_rate_cur_p = TRUE; ++ } ++ ++#if 1 ++ if (HtMcs != MCS_AUTO) ++ { ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; ++ *auto_rate_cur_p = FALSE; ++ } ++ else ++ { ++ //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; ++ *auto_rate_cur_p = TRUE; ++ } ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ pSupRate = &pAd->StaActive.SupRate[0]; ++ pExtRate = &pAd->StaActive.ExtRate[0]; ++ SupRateLen = pAd->StaActive.SupRateLen; ++ ExtRateLen = pAd->StaActive.ExtRateLen; ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ pSupRate = &pAd->CommonCfg.SupRate[0]; ++ pExtRate = &pAd->CommonCfg.ExtRate[0]; ++ SupRateLen = pAd->CommonCfg.SupRateLen; ++ ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ } ++ ++ // find max supported rate ++ for (i=0; i Rate) MinSupport = Rate; ++ } ++ ++ for (i=0; i Rate) MinSupport = Rate; ++ } ++ ++ RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap); ++ ++ // bug fix ++ // pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap; ++ ++ // calculate the exptected ACK rate for each TX rate. This info is used to caculate ++ // the DURATION field of outgoing uniicast DATA/MGMT frame ++ for (i=0; iCommonCfg.ExpectedACKRate[i] = CurrBasicRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire])); ++ // max tx rate = min {max desire rate, max supported rate} ++ if (MaxSupport < MaxDesire) ++ pAd->CommonCfg.MaxTxRate = MaxSupport; ++ else ++ pAd->CommonCfg.MaxTxRate = MaxDesire; ++ ++ pAd->CommonCfg.MinTxRate = MinSupport; ++ // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success ++ // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending ++ // on average RSSI ++ // 1. RSSI >= -70db, start at 54 Mbps (short distance) ++ // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) ++ // 3. -75 > RSSI, start at 11 Mbps (long distance) ++ //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* && ++ // OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/) ++ if (*auto_rate_cur_p) ++ { ++ short dbm = 0; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; ++#endif // CONFIG_STA_SUPPORT // ++ if (bLinkUp == TRUE) ++ pAd->CommonCfg.TxRate = RATE_24; ++ else ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ ++ if (dbm < -75) ++ pAd->CommonCfg.TxRate = RATE_11; ++ else if (dbm < -70) ++ pAd->CommonCfg.TxRate = RATE_24; ++ ++ // should never exceed MaxTxRate (consider 11B-only mode) ++ if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate) ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ ++ pAd->CommonCfg.TxRateIndex = 0; ++ } ++ else ++ { ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate; ++ pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK; ++ ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE; ++ } ++ ++ if (pAd->CommonCfg.TxRate <= RATE_11) ++ { ++ pMaxHtPhy->field.MODE = MODE_CCK; ++ pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate; ++ pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate; ++ } ++ else ++ { ++ pMaxHtPhy->field.MODE = MODE_OFDM; ++ pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate]; ++ if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54)) ++ {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];} ++ else ++ {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;} ++ } ++ ++ pHtPhy->word = (pMaxHtPhy->word); ++ if (bLinkUp && (pAd->OpMode == OPMODE_STA)) ++ { ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word; ++ pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word; ++ pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word; ++ } ++ else ++ { ++ switch (pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11BG_MIXED: ++ case PHY_11B: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11BGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.MlmeRate = RATE_1; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; ++ ++//#ifdef WIFI_TEST ++ pAd->CommonCfg.RtsRate = RATE_11; ++//#else ++// pAd->CommonCfg.RtsRate = RATE_1; ++//#endif ++ break; ++ case PHY_11G: ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AGN_MIXED: ++ case PHY_11GN_MIXED: ++ case PHY_11N_2_4G: ++ case PHY_11AN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ break; ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ pAd->CommonCfg.MlmeRate = RATE_1; ++ pAd->CommonCfg.RtsRate = RATE_1; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; ++ } ++ else ++ { ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ break; ++ default: // error ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->CommonCfg.RtsRate = RATE_1; ++ break; ++ } ++ // ++ // Keep Basic Mlme Rate. ++ // ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word; ++ if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM) ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24]; ++ else ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1; ++ pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n", ++ RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate], ++ /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n", ++ RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n", ++ pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); ++} ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ This function update HT Rate setting. ++ Input Wcid value is valid for 2 case : ++ 1. it's used for Station in infra mode that copy AP rate to Mactable. ++ 2. OR Station in adhoc mode to copy peer's HT rate to Mactable. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeUpdateHtTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx) ++{ ++ UCHAR StbcMcs; //j, StbcMcs, bitmask; ++ CHAR i; // 3*3 ++ RT_HT_CAPABILITY *pRtHtCap = NULL; ++ RT_HT_PHY_INFO *pActiveHtPhy = NULL; ++ ULONG BasicMCS; ++ UCHAR j, bitmask; ++ PRT_HT_PHY_INFO pDesireHtPhy = NULL; ++ PHTTRANSMIT_SETTING pHtPhy = NULL; ++ PHTTRANSMIT_SETTING pMaxHtPhy = NULL; ++ PHTTRANSMIT_SETTING pMinHtPhy = NULL; ++ BOOLEAN *auto_rate_cur_p; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n")); ++ ++ auto_rate_cur_p = NULL; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; ++ pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; ++ pHtPhy = &pAd->StaCfg.HTPhyMode; ++ pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; ++ pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; ++ ++ auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ return; ++ ++ pRtHtCap = &pAd->StaActive.SupportedHtPhy; ++ pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo; ++ StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs; ++ BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16); ++ if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) ++ pMaxHtPhy->field.STBC = STBC_USE; ++ else ++ pMaxHtPhy->field.STBC = STBC_NONE; ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ if (pDesireHtPhy->bHtEnable == FALSE) ++ return; ++ ++ pRtHtCap = &pAd->CommonCfg.DesiredHtPhy; ++ StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs; ++ BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16); ++ if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) ++ pMaxHtPhy->field.STBC = STBC_USE; ++ else ++ pMaxHtPhy->field.STBC = STBC_NONE; ++ } ++ ++ // Decide MAX ht rate. ++ if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ pMaxHtPhy->field.MODE = MODE_HTGREENFIELD; ++ else ++ pMaxHtPhy->field.MODE = MODE_HTMIX; ++ ++ if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth)) ++ pMaxHtPhy->field.BW = BW_40; ++ else ++ pMaxHtPhy->field.BW = BW_20; ++ ++ if (pMaxHtPhy->field.BW == BW_20) ++ pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20); ++ else ++ pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40); ++ ++ for (i=23; i>=0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ ++ if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask)) ++ { ++ pMaxHtPhy->field.MCS = i; ++ break; ++ } ++ ++ if (i==0) ++ break; ++ } ++ ++ // Copy MIN ht rate. rt2860??? ++ pMinHtPhy->field.BW = BW_20; ++ pMinHtPhy->field.MCS = 0; ++ pMinHtPhy->field.STBC = 0; ++ pMinHtPhy->field.ShortGI = 0; ++ //If STA assigns fixed rate. update to fixed here. ++#ifdef CONFIG_STA_SUPPORT ++ if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) ++ { ++ if (pDesireHtPhy->MCSSet[4] != 0) ++ { ++ pMaxHtPhy->field.MCS = 32; ++ pMinHtPhy->field.MCS = 32; ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS)); ++ } ++ ++ for (i=23; (CHAR)i >= 0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask)) ++ { ++ pMaxHtPhy->field.MCS = i; ++ pMinHtPhy->field.MCS = i; ++ break; ++ } ++ if (i==0) ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ // Decide ht rate ++ pHtPhy->field.STBC = pMaxHtPhy->field.STBC; ++ pHtPhy->field.BW = pMaxHtPhy->field.BW; ++ pHtPhy->field.MODE = pMaxHtPhy->field.MODE; ++ pHtPhy->field.MCS = pMaxHtPhy->field.MCS; ++ pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI; ++ ++ // use default now. rt2860 ++ if (pDesireHtPhy->MCSSet[0] != 0xff) ++ *auto_rate_cur_p = FALSE; ++ else ++ *auto_rate_cur_p = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize )); ++ DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS, ++ pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); ++} ++#endif // DOT11_N_SUPPORT // ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRadioOff( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RT28XX_MLME_RADIO_OFF(pAd); ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRadioOn( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RT28XX_MLME_RADIO_ON(pAd); ++} ++ ++// =========================================================================================== ++// bss_table.c ++// =========================================================================================== ++ ++ ++/*! \brief initialize BSS table ++ * \param p_tab pointer to the table ++ * \return none ++ * \pre ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID BssTableInit( ++ IN BSS_TABLE *Tab) ++{ ++ int i; ++ ++ Tab->BssNr = 0; ++ Tab->BssOverlapNr = 0; ++ for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) ++ { ++ NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY)); ++ Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value ++ } ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInit( ++ IN PRTMP_ADAPTER pAd, ++ IN BA_TABLE *Tab) ++{ ++ int i; ++ ++ Tab->numAsOriginator = 0; ++ Tab->numAsRecipient = 0; ++ NdisAllocateSpinLock(&pAd->BATabLock); ++ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE; ++ NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock)); ++ } ++ for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) ++ { ++ Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++/*! \brief search the BSS table by SSID ++ * \param p_tab pointer to the bss table ++ * \param ssid SSID string ++ * \return index of the table, BSS_NOT_FOUND if not in the table ++ * \pre ++ * \post ++ * \note search by sequential search ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++ULONG BssTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ // ++ // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. ++ // We should distinguish this case. ++ // ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++ULONG BssSsidTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ // ++ // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. ++ // We should distinguish this case. ++ // ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) && ++ SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++ULONG BssTableSearchWithSSID( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR Bssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) && ++ (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) || ++ (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) || ++ (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen)))) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableDeleteEntry( ++ IN OUT BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel) ++{ ++ UCHAR i, j; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ if ((Tab->BssEntry[i].Channel == Channel) && ++ (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) ++ { ++ for (j = i; j < Tab->BssNr - 1; j++) ++ { ++ NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); ++ } ++ NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY)); ++ Tab->BssNr -= 1; ++ return; ++ } ++ } ++} ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ======================================================================== ++ Routine Description: ++ Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed. ++ ++ Arguments: ++ // IRQL = DISPATCH_LEVEL ++ ======================================================================== ++*/ ++VOID BATableDeleteORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_ORI_ENTRY *pBAORIEntry) ++{ ++ ++ if (pBAORIEntry->ORI_BA_Status != Originator_NONE) ++ { ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ if (pBAORIEntry->ORI_BA_Status == Originator_Done) ++ { ++ pAd->BATable.numAsOriginator -= 1; ++ DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); ++ // Erase Bitmap flag. ++ } ++ pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here ++ pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here ++ pBAORIEntry->ORI_BA_Status = Originator_NONE; ++ pBAORIEntry->Token = 1; ++ // Not clear Sequence here. ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++/*! \brief ++ * \param ++ * \return ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID BssEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_ENTRY *pBss, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN PCF_PARM pCfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ COPY_MAC_ADDR(pBss->Bssid, pBssid); ++ // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID ++ pBss->Hidden = 1; ++ if (SsidLen > 0) ++ { ++ // For hidden SSID AP, it might send beacon with SSID len equal to 0 ++ // Or send beacon /probe response with SSID len matching real SSID length, ++ // but SSID is all zero. such as "00-00-00-00" with length 4. ++ // We have to prevent this case overwrite correct table ++ if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) ++ { ++ NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pBss->Ssid, Ssid, SsidLen); ++ pBss->SsidLen = SsidLen; ++ pBss->Hidden = 0; ++ } ++ } ++ else ++ pBss->SsidLen = 0; ++ pBss->BssType = BssType; ++ pBss->BeaconPeriod = BeaconPeriod; ++ if (BssType == BSS_INFRA) ++ { ++ if (pCfParm->bValid) ++ { ++ pBss->CfpCount = pCfParm->CfpCount; ++ pBss->CfpPeriod = pCfParm->CfpPeriod; ++ pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; ++ pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; ++ } ++ } ++ else ++ { ++ pBss->AtimWin = AtimWin; ++ } ++ ++ pBss->CapabilityInfo = CapabilityInfo; ++ // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES ++ // Combine with AuthMode, they will decide the connection methods. ++ pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); ++ ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES); ++ if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen); ++ else ++ NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pBss->SupRateLen = SupRateLen; ++ ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen); ++ NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); ++ NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); ++ pBss->NewExtChanOffset = NewExtChanOffset; ++ pBss->ExtRateLen = ExtRateLen; ++ pBss->Channel = Channel; ++ pBss->CentralChannel = Channel; ++ pBss->Rssi = Rssi; ++ // Update CkipFlag. if not exists, the value is 0x0 ++ pBss->CkipFlag = CkipFlag; ++ ++ // New for microsoft Fixed IEs ++ NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8); ++ pBss->FixIEs.BeaconInterval = BeaconPeriod; ++ pBss->FixIEs.Capabilities = CapabilityInfo; ++ ++ // New for microsoft Variable IEs ++ if (LengthVIE != 0) ++ { ++ pBss->VarIELen = LengthVIE; ++ NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen); ++ } ++ else ++ { ++ pBss->VarIELen = 0; ++ } ++ ++ pBss->AddHtInfoLen = 0; ++ pBss->HtCapabilityLen = 0; ++#ifdef DOT11_N_SUPPORT ++ if (HtCapabilityLen> 0) ++ { ++ pBss->HtCapabilityLen = HtCapabilityLen; ++ NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); ++ if (AddHtInfoLen > 0) ++ { ++ pBss->AddHtInfoLen = AddHtInfoLen; ++ NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); ++ ++ if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) ++ { ++ pBss->CentralChannel = pAddHtInfo->ControlChan - 2; ++ } ++ else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) ++ { ++ pBss->CentralChannel = pAddHtInfo->ControlChan + 2; ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ BssCipherParse(pBss); ++ ++ // new for QOS ++ if (pEdcaParm) ++ NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ else ++ pBss->EdcaParm.bValid = FALSE; ++ if (pQosCapability) ++ NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ else ++ pBss->QosCapability.bValid = FALSE; ++ if (pQbssLoad) ++ NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ else ++ pBss->QbssLoad.bValid = FALSE; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ PEID_STRUCT pEid; ++ USHORT Length = 0; ++ ++ ++ NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); ++ NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ NdisZeroMemory(&pBss->CountryString[0], 3); ++ pBss->bHasCountryIE = FALSE; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ pEid = (PEID_STRUCT) pVIE; ++ while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) ++ { ++ switch(pEid->Eid) ++ { ++ case IE_WPA: ++ if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ { ++ if ((pEid->Len + 2) > MAX_CUSTOM_LEN) ++ { ++ pBss->WpaIE.IELen = 0; ++ break; ++ } ++ pBss->WpaIE.IELen = pEid->Len + 2; ++ NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen); ++ } ++ break; ++ case IE_RSN: ++ if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ { ++ if ((pEid->Len + 2) > MAX_CUSTOM_LEN) ++ { ++ pBss->RsnIE.IELen = 0; ++ break; ++ } ++ pBss->RsnIE.IELen = pEid->Len + 2; ++ NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); ++ } ++ break; ++#ifdef EXT_BUILD_CHANNEL_LIST ++ case IE_COUNTRY: ++ NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); ++ pBss->bHasCountryIE = TRUE; ++ break; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ } ++ Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++} ++ ++/*! ++ * \brief insert an entry into the bss table ++ * \param p_tab The BSS table ++ * \param Bssid BSSID ++ * \param ssid SSID ++ * \param ssid_len Length of SSID ++ * \param bss_type ++ * \param beacon_period ++ * \param timestamp ++ * \param p_cf ++ * \param atim_win ++ * \param cap ++ * \param rates ++ * \param rates_len ++ * \param channel_idx ++ * \return none ++ * \pre ++ * \post ++ * \note If SSID is identical, the old entry will be replaced by the new one ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++ULONG BssTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN CF_PARM *CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR ChannelNo, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ ULONG Idx; ++ ++ Idx = BssTableSearchWithSSID(Tab, pBssid, Ssid, SsidLen, ChannelNo); ++ if (Idx == BSS_NOT_FOUND) ++ { ++ if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) ++ { ++ // ++ // It may happen when BSS Table was full. ++ // The desired AP will not be added into BSS Table ++ // In this case, if we found the desired AP then overwrite BSS Table. ++ // ++ if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) || ++ SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)) ++ { ++ Idx = Tab->BssOverlapNr; ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE; ++ } ++ return Idx; ++ } ++ else ++ { ++ return BSS_NOT_FOUND; ++ } ++ } ++ Idx = Tab->BssNr; ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ Tab->BssNr++; ++ } ++ else ++ { ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ } ++ ++ return Idx; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++VOID TriEventInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ ++ for (i = 0;i < MAX_TRIGGER_EVENT;i++) ++ pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; ++ ++ pAd->CommonCfg.TriggerEventTab.EventANo = 0; ++ pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; ++} ++ ++ULONG TriEventTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT TRIGGER_EVENT_TAB *Tab, ++ IN PUCHAR pBssid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR RegClass, ++ IN UCHAR ChannelNo) ++{ ++ // Event A ++ if (HtCapabilityLen == 0) ++ { ++ if (Tab->EventANo < MAX_TRIGGER_EVENT) ++ { ++ RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); ++ Tab->EventA[Tab->EventANo].bValid = TRUE; ++ Tab->EventA[Tab->EventANo].Channel = ChannelNo; ++ Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; ++ if (RegClass != 0) ++ { ++ // Beacon has Regulatory class IE. So use beacon's ++ Tab->EventA[Tab->EventANo].RegClass = RegClass; ++ } ++ else ++ { ++ // Use Station's Regulatory class instead. ++ if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) ++ { ++ if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) ++ { ++ Tab->EventA[Tab->EventANo].RegClass = 32; ++ } ++ else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) ++ Tab->EventA[Tab->EventANo].RegClass = 33; ++ } ++ else ++ Tab->EventA[Tab->EventANo].RegClass = ??; ++ ++ } ++ ++ Tab->EventANo ++; ++ } ++ } ++ else if (pHtCapability->HtCapInfo.Intolerant40) ++ { ++ Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Trigger Event table Maintainence called once every second. ++ ++ Arguments: ++ // IRQL = DISPATCH_LEVEL ++ ======================================================================== ++*/ ++VOID TriEventCounterMaintenance( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ BOOLEAN bNotify = FALSE; ++ for (i = 0;i < MAX_TRIGGER_EVENT;i++) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; ++ pAd->CommonCfg.TriggerEventTab.EventANo --; ++ // Need to send 20/40 Coexistence Notify frame if has status change. ++ bNotify = TRUE; ++ } ++ } ++ } ++ if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventBCountDown--; ++ if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) ++ bNotify = TRUE; ++ } ++ ++ if (bNotify == TRUE) ++ Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableSsidSort( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *OutTab, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen) ++{ ++ INT i; ++ BssTableInit(OutTab); ++ ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i]; ++ BOOLEAN bIsHiddenApIncluded = FALSE; ++ ++ if (((pAd->CommonCfg.bIEEE80211H == 1) && ++ (pAd->MlmeAux.Channel > 14) && ++ RadarChannelCheck(pAd, pInBss->Channel)) ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ if (pInBss->Hidden) ++ bIsHiddenApIncluded = TRUE; ++ } ++ ++ if ((pInBss->BssType == pAd->StaCfg.BssType) && ++ (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded)) ++ { ++ BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; ++ ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. ++ if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && ++ (pInBss->bHasCountryIE == FALSE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); ++ continue; ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef DOT11_N_SUPPORT ++ // 2.4G/5G N only mode ++ if ((pInBss->HtCapabilityLen == 0) && ++ ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); ++ continue; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // New for WPA2 ++ // Check the Authmode first ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode ++ if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) ++ // None matched ++ continue; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && ++ (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) && ++ (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled)) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) ++ continue; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA2.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && ++ (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) && ++ (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled)) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) ++ continue; ++ } ++ } ++ // Bss Type matched, SSID matched. ++ // We will check wepstatus for qualification Bss ++ else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus)); ++ // ++ // For the SESv2 case, we will not qualify WepStatus. ++ // ++ if (!pInBss->bSES) ++ continue; ++ } ++ ++ // Since the AP is using hidden SSID, and we are trying to connect to ANY ++ // It definitely will fail. So, skip it. ++ // CCX also require not even try to connect it!! ++ if (SsidLen == 0) ++ continue; ++ ++#ifdef DOT11_N_SUPPORT ++ // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region ++ // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, ++ if ((pInBss->CentralChannel != pInBss->Channel) && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ SetCommonHT(pAd); ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ else ++ { ++ if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20) ++ { ++ SetCommonHT(pAd); ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // copy matching BSS from InTab to OutTab ++ NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); ++ ++ OutTab->BssNr++; ++ } ++ else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0)) ++ { ++ BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; ++ ++ ++#ifdef DOT11_N_SUPPORT ++ // 2.4G/5G N only mode ++ if ((pInBss->HtCapabilityLen == 0) && ++ ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); ++ continue; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // New for WPA2 ++ // Check the Authmode first ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode ++ if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) ++ // None matched ++ continue; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) ++ continue; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA2.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) ++ continue; ++ } ++ } ++ // Bss Type matched, SSID matched. ++ // We will check wepstatus for qualification Bss ++ else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) ++ continue; ++ ++#ifdef DOT11_N_SUPPORT ++ // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region ++ // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, ++ if ((pInBss->CentralChannel != pInBss->Channel) && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ SetCommonHT(pAd); ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // copy matching BSS from InTab to OutTab ++ NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); ++ ++ OutTab->BssNr++; ++ } ++ ++ if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) ++ break; ++ } ++ ++ BssTableSortByRssi(OutTab); ++} ++ ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableSortByRssi( ++ IN OUT BSS_TABLE *OutTab) ++{ ++ INT i, j; ++ BSS_ENTRY TmpBss; ++ ++ for (i = 0; i < OutTab->BssNr - 1; i++) ++ { ++ for (j = i+1; j < OutTab->BssNr; j++) ++ { ++ if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) ++ { ++ NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); ++ NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); ++ NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); ++ } ++ } ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++VOID BssCipherParse( ++ IN OUT PBSS_ENTRY pBss) ++{ ++ PEID_STRUCT pEid; ++ PUCHAR pTmp; ++ PRSN_IE_HEADER_STRUCT pRsnHeader; ++ PCIPHER_SUITE_STRUCT pCipher; ++ PAKM_SUITE_STRUCT pAKM; ++ USHORT Count; ++ INT Length; ++ NDIS_802_11_ENCRYPTION_STATUS TmpCipher; ++ ++ // ++ // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. ++ // ++ if (pBss->Privacy) ++ { ++ pBss->WepStatus = Ndis802_11WEPEnabled; ++ } ++ else ++ { ++ pBss->WepStatus = Ndis802_11WEPDisabled; ++ } ++ // Set default to disable & open authentication before parsing variable IE ++ pBss->AuthMode = Ndis802_11AuthModeOpen; ++ pBss->AuthModeAux = Ndis802_11AuthModeOpen; ++ ++ // Init WPA setting ++ pBss->WPA.PairCipher = Ndis802_11WEPDisabled; ++ pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled; ++ pBss->WPA.GroupCipher = Ndis802_11WEPDisabled; ++ pBss->WPA.RsnCapability = 0; ++ pBss->WPA.bMixMode = FALSE; ++ ++ // Init WPA2 setting ++ pBss->WPA2.PairCipher = Ndis802_11WEPDisabled; ++ pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled; ++ pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled; ++ pBss->WPA2.RsnCapability = 0; ++ pBss->WPA2.bMixMode = FALSE; ++ ++ ++ Length = (INT) pBss->VarIELen; ++ ++ while (Length > 0) ++ { ++ // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently ++ pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length; ++ pEid = (PEID_STRUCT) pTmp; ++ switch (pEid->Eid) ++ { ++ case IE_WPA: ++ //Parse Cisco IE_WPA (LEAP, CCKM, etc.) ++ if ( NdisEqualMemory((pTmp+8), CISCO_OUI, 3)) ++ { ++ pTmp += 11; ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WepStatus = Ndis802_11Encryption1Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WepStatus = Ndis802_11Encryption2Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 4: ++ pBss->WepStatus = Ndis802_11Encryption3Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ default: ++ break; ++ } ++ ++ // if Cisco IE_WPA, break ++ break; ++ } ++ else if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7)) ++ { ++ pBss->bSES = TRUE; ++ break; ++ } ++ else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1) ++ { ++ // if unsupported vendor specific IE ++ break; ++ } ++ // Skip OUI, version, and multicast suite ++ // This part should be improved in the future when AP supported multiple cipher suite. ++ // For now, it's OK since almost all APs have fixed cipher suite supported. ++ // pTmp = (PUCHAR) pEid->Octet; ++ pTmp += 11; ++ ++ // Cipher Suite Selectors from Spec P802.11i/D3.2 P26. ++ // Value Meaning ++ // 0 None ++ // 1 WEP-40 ++ // 2 Tkip ++ // 3 WRAP ++ // 4 AES ++ // 5 WEP-104 ++ // Parse group cipher ++ switch (*pTmp) ++ { ++ case 1: ++ pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled; ++ break; ++ case 5: ++ pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled; ++ break; ++ case 2: ++ pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ // number of unicast suite ++ pTmp += 1; ++ ++ // skip all unicast cipher suites ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // Parsing all unicast cipher suite ++ while (Count > 0) ++ { ++ // Skip OUI ++ pTmp += 3; ++ TmpCipher = Ndis802_11WEPDisabled; ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ TmpCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ TmpCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ TmpCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ if (TmpCipher > pBss->WPA.PairCipher) ++ { ++ // Move the lower cipher suite to PairCipherAux ++ pBss->WPA.PairCipherAux = pBss->WPA.PairCipher; ++ pBss->WPA.PairCipher = TmpCipher; ++ } ++ else ++ { ++ pBss->WPA.PairCipherAux = TmpCipher; ++ } ++ pTmp++; ++ Count--; ++ } ++ ++ // 4. get AKM suite counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ pTmp += 3; ++ ++ switch (*pTmp) ++ { ++ case 1: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA; ++ break; ++ case 2: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPAPSK; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK; ++ break; ++ default: ++ break; ++ } ++ pTmp += 1; ++ ++ // Fixed for WPA-None ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ pBss->AuthMode = Ndis802_11AuthModeWPANone; ++ pBss->AuthModeAux = Ndis802_11AuthModeWPANone; ++ pBss->WepStatus = pBss->WPA.GroupCipher; ++ // Patched bugs for old driver ++ if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) ++ pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; ++ } ++ else ++ pBss->WepStatus = pBss->WPA.PairCipher; ++ ++ // Check the Pair & Group, if different, turn on mixed mode flag ++ if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher) ++ pBss->WPA.bMixMode = TRUE; ++ ++ break; ++ ++ case IE_RSN: ++ pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp; ++ ++ // 0. Version must be 1 ++ if (le2cpu16(pRsnHeader->Version) != 1) ++ break; ++ pTmp += sizeof(RSN_IE_HEADER_STRUCT); ++ ++ // 1. Check group cipher ++ pCipher = (PCIPHER_SUITE_STRUCT) pTmp; ++ if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) ++ break; ++ ++ // Parse group cipher ++ switch (pCipher->Type) ++ { ++ case 1: ++ pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled; ++ break; ++ case 5: ++ pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled; ++ break; ++ case 2: ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ // set to correct offset for next parsing ++ pTmp += sizeof(CIPHER_SUITE_STRUCT); ++ ++ // 2. Get pairwise cipher counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // 3. Get pairwise cipher ++ // Parsing all unicast cipher suite ++ while (Count > 0) ++ { ++ // Skip OUI ++ pCipher = (PCIPHER_SUITE_STRUCT) pTmp; ++ TmpCipher = Ndis802_11WEPDisabled; ++ switch (pCipher->Type) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ TmpCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ TmpCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ TmpCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ if (TmpCipher > pBss->WPA2.PairCipher) ++ { ++ // Move the lower cipher suite to PairCipherAux ++ pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher; ++ pBss->WPA2.PairCipher = TmpCipher; ++ } ++ else ++ { ++ pBss->WPA2.PairCipherAux = TmpCipher; ++ } ++ pTmp += sizeof(CIPHER_SUITE_STRUCT); ++ Count--; ++ } ++ ++ // 4. get AKM suite counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // 5. Get AKM ciphers ++ pAKM = (PAKM_SUITE_STRUCT) pTmp; ++ if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) ++ break; ++ ++ switch (pAKM->Type) ++ { ++ case 1: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA2; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA2; ++ break; ++ case 2: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA2PSK; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK; ++ break; ++ default: ++ break; ++ } ++ pTmp += (Count * sizeof(AKM_SUITE_STRUCT)); ++ ++ // Fixed for WPA-None ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ pBss->AuthMode = Ndis802_11AuthModeWPANone; ++ pBss->AuthModeAux = Ndis802_11AuthModeWPANone; ++ pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; ++ pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; ++ pBss->WepStatus = pBss->WPA.GroupCipher; ++ // Patched bugs for old driver ++ if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) ++ pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; ++ } ++ pBss->WepStatus = pBss->WPA2.PairCipher; ++ ++ // 6. Get RSN capability ++ //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp; ++ pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // Check the Pair & Group, if different, turn on mixed mode flag ++ if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher) ++ pBss->WPA2.bMixMode = TRUE; ++ ++ break; ++ default: ++ break; ++ } ++ Length -= (pEid->Len + 2); ++ } ++} ++ ++// =========================================================================================== ++// mac_table.c ++// =========================================================================================== ++ ++/*! \brief generates a random mac address value for IBSS BSSID ++ * \param Addr the bssid location ++ * \return none ++ * \pre ++ * \post ++ */ ++VOID MacAddrRandomBssid( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pAddr) ++{ ++ INT i; ++ ++ for (i = 0; i < MAC_ADDR_LEN; i++) ++ { ++ pAddr[i] = RandomByte(pAd); ++ } ++ ++ pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx ++} ++ ++/*! \brief init the management mac frame header ++ * \param p_hdr mac header ++ * \param subtype subtype of the frame ++ * \param p_ds destination address, don't care if it is a broadcast address ++ * \return none ++ * \pre the station has the following information in the pAd->StaCfg ++ * - bssid ++ * - station address ++ * \post ++ * \note this function initializes the following field ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID MgtMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SubType; ++// if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type ++// pHdr80211->FC.Type = BTYPE_CNTL; ++ pHdr80211->FC.ToDs = ToDs; ++ COPY_MAC_ADDR(pHdr80211->Addr1, pDA); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); ++} ++ ++// =========================================================================================== ++// mem_mgmt.c ++// =========================================================================================== ++ ++/*!*************************************************************************** ++ * This routine build an outgoing frame, and fill all information specified ++ * in argument list to the frame body. The actual frame size is the summation ++ * of all arguments. ++ * input params: ++ * Buffer - pointer to a pre-allocated memory segment ++ * args - a list of pairs. ++ * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this ++ * function will FAIL!!! ++ * return: ++ * Size of the buffer ++ * usage: ++ * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ****************************************************************************/ ++ULONG MakeOutgoingFrame( ++ OUT CHAR *Buffer, ++ OUT ULONG *FrameLen, ...) ++{ ++ CHAR *p; ++ int leng; ++ ULONG TotLeng; ++ va_list Args; ++ ++ // calculates the total length ++ TotLeng = 0; ++ va_start(Args, FrameLen); ++ do ++ { ++ leng = va_arg(Args, int); ++ if (leng == END_OF_ARGS) ++ { ++ break; ++ } ++ p = va_arg(Args, PVOID); ++ NdisMoveMemory(&Buffer[TotLeng], p, leng); ++ TotLeng = TotLeng + leng; ++ } while(TRUE); ++ ++ va_end(Args); /* clean up */ ++ *FrameLen = TotLeng; ++ return TotLeng; ++} ++ ++// =========================================================================================== ++// mlme_queue.c ++// =========================================================================================== ++ ++/*! \brief Initialize The MLME Queue, used by MLME Functions ++ * \param *Queue The MLME Queue ++ * \return Always Return NDIS_STATE_SUCCESS in this implementation ++ * \pre ++ * \post ++ * \note Because this is done only once (at the init stage), no need to be locked ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++NDIS_STATUS MlmeQueueInit( ++ IN MLME_QUEUE *Queue) ++{ ++ INT i; ++ ++ NdisAllocateSpinLock(&Queue->Lock); ++ ++ Queue->Num = 0; ++ Queue->Head = 0; ++ Queue->Tail = 0; ++ ++ for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) ++ { ++ Queue->Entry[i].Occupied = FALSE; ++ Queue->Entry[i].MsgLen = 0; ++ NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE); ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread ++ * \param *Queue The MLME Queue ++ * \param Machine The State Machine Id ++ * \param MsgType The Message Type ++ * \param MsgLen The Message length ++ * \param *Msg The message pointer ++ * \return TRUE if enqueue is successful, FALSE if the queue is full ++ * \pre ++ * \post ++ * \note The message has to be initialized ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeEnqueue( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Machine, ++ IN ULONG MsgType, ++ IN ULONG MsgLen, ++ IN VOID *Msg) ++{ ++ INT Tail; ++ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return FALSE; ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ ++ if (MlmeQueueFull(Queue)) ++ { ++ return FALSE; ++ } ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Tail = Queue->Tail; ++ Queue->Tail++; ++ Queue->Num++; ++ if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Tail = 0; ++ } ++ ++ Queue->Entry[Tail].Wcid = RESERVED_WCID; ++ Queue->Entry[Tail].Occupied = TRUE; ++ Queue->Entry[Tail].Machine = Machine; ++ Queue->Entry[Tail].MsgType = MsgType; ++ Queue->Entry[Tail].MsgLen = MsgLen; ++ ++ if (Msg != NULL) ++ { ++ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); ++ } ++ ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ return TRUE; ++} ++ ++/*! \brief This function is used when Recv gets a MLME message ++ * \param *Queue The MLME Queue ++ * \param TimeStampHigh The upper 32 bit of timestamp ++ * \param TimeStampLow The lower 32 bit of timestamp ++ * \param Rssi The receiving RSSI strength ++ * \param MsgLen The length of the message ++ * \param *Msg The message pointer ++ * \return TRUE if everything ok, FALSE otherwise (like Queue Full) ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG TimeStampHigh, ++ IN ULONG TimeStampLow, ++ IN UCHAR Rssi0, ++ IN UCHAR Rssi1, ++ IN UCHAR Rssi2, ++ IN ULONG MsgLen, ++ IN VOID *Msg, ++ IN UCHAR Signal) ++{ ++ INT Tail, Machine; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ INT MsgType; ++ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; ++ ++#ifdef RALINK_ATE ++ /* Nothing to do in ATE mode */ ++ if(ATE_ON(pAd)) ++ return FALSE; ++#endif // RALINK_ATE // ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); ++ return FALSE; ++ } ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ ++ if (MlmeQueueFull(Queue)) ++ { ++ return FALSE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType)); ++ return FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // OK, we got all the informations, it is time to put things into queue ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Tail = Queue->Tail; ++ Queue->Tail++; ++ Queue->Num++; ++ if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Tail = 0; ++ } ++ Queue->Entry[Tail].Occupied = TRUE; ++ Queue->Entry[Tail].Machine = Machine; ++ Queue->Entry[Tail].MsgType = MsgType; ++ Queue->Entry[Tail].MsgLen = MsgLen; ++ Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow; ++ Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh; ++ Queue->Entry[Tail].Rssi0 = Rssi0; ++ Queue->Entry[Tail].Rssi1 = Rssi1; ++ Queue->Entry[Tail].Rssi2 = Rssi2; ++ Queue->Entry[Tail].Signal = Signal; ++ Queue->Entry[Tail].Wcid = (UCHAR)Wcid; ++ ++ Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel; ++ ++ if (Msg != NULL) ++ { ++ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); ++ } ++ ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return TRUE; ++} ++ ++ ++/*! \brief Dequeue a message from the MLME Queue ++ * \param *Queue The MLME Queue ++ * \param *Elem The message dequeued from MLME Queue ++ * \return TRUE if the Elem contains something, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeDequeue( ++ IN MLME_QUEUE *Queue, ++ OUT MLME_QUEUE_ELEM **Elem) ++{ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ *Elem = &(Queue->Entry[Queue->Head]); ++ Queue->Num--; ++ Queue->Head++; ++ if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Head = 0; ++ } ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ return TRUE; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRestartStateMachine( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN Cancelled; ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef QOS_DLS_SUPPORT ++ UCHAR i; ++#endif // QOS_DLS_SUPPORT // ++ // Cancel all timer events ++ // Be careful to cancel new added timer ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++ ++#ifdef QOS_DLS_SUPPORT ++ for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); ++ } ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Change back to original channel in case of doing scan ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // Resume MSDU which is turned off durning scan ++ RTMPResumeMsduTransmission(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Set all state machines back IDLE ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ pAd->Mlme.ActMachine.CurrState = ACT_IDLE; ++#ifdef QOS_DLS_SUPPORT ++ pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++/*! \brief test if the MLME Queue is empty ++ * \param *Queue The MLME Queue ++ * \return TRUE if the Queue is empty, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeQueueEmpty( ++ IN MLME_QUEUE *Queue) ++{ ++ BOOLEAN Ans; ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Ans = (Queue->Num == 0); ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ return Ans; ++} ++ ++/*! \brief test if the MLME Queue is full ++ * \param *Queue The MLME Queue ++ * \return TRUE if the Queue is empty, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeQueueFull( ++ IN MLME_QUEUE *Queue) ++{ ++ BOOLEAN Ans; ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied); ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ return Ans; ++} ++ ++/*! \brief The destructor of MLME Queue ++ * \param ++ * \return ++ * \pre ++ * \post ++ * \note Clear Mlme Queue, Set Queue->Num to Zero. ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID MlmeQueueDestroy( ++ IN MLME_QUEUE *pQueue) ++{ ++ NdisAcquireSpinLock(&(pQueue->Lock)); ++ pQueue->Num = 0; ++ pQueue->Head = 0; ++ pQueue->Tail = 0; ++ NdisReleaseSpinLock(&(pQueue->Lock)); ++ NdisFreeSpinLock(&(pQueue->Lock)); ++} ++ ++/*! \brief To substitute the message type if the message is coming from external ++ * \param pFrame The frame received ++ * \param *Machine The state machine ++ * \param *MsgType the message type for the state machine ++ * \return TRUE if the substitution is successful, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++#ifdef CONFIG_STA_SUPPORT ++BOOLEAN MsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType) ++{ ++ USHORT Seq; ++ UCHAR EAPType; ++ PUCHAR pData; ++ ++ // Pointer to start of data frames including SNAP header ++ pData = (PUCHAR) pFrame + LENGTH_802_11; ++ ++ // The only data type will pass to this function is EAPOL frame ++ if (pFrame->Hdr.FC.Type == BTYPE_DATA) ++ { ++ if (NdisEqualMemory(SNAP_AIRONET, pData, LENGTH_802_1_H)) ++ { ++ // Cisco Aironet SNAP header ++ *Machine = AIRONET_STATE_MACHINE; ++ *MsgType = MT2_AIRONET_MSG; ++ return (TRUE); ++ } ++#ifdef LEAP_SUPPORT ++ if ( pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP ) //LEAP ++ { ++ // LEAP frames ++ *Machine = LEAP_STATE_MACHINE; ++ EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); ++ return (LeapMsgTypeSubst(EAPType, MsgType)); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ *Machine = WPA_PSK_STATE_MACHINE; ++ EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); ++ return(WpaMsgTypeSubst(EAPType, MsgType)); ++ } ++ } ++ ++ switch (pFrame->Hdr.FC.SubType) ++ { ++ case SUBTYPE_ASSOC_REQ: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ASSOC_REQ; ++ break; ++ case SUBTYPE_ASSOC_RSP: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ASSOC_RSP; ++ break; ++ case SUBTYPE_REASSOC_REQ: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_REASSOC_REQ; ++ break; ++ case SUBTYPE_REASSOC_RSP: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_REASSOC_RSP; ++ break; ++ case SUBTYPE_PROBE_REQ: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_PROBE_REQ; ++ break; ++ case SUBTYPE_PROBE_RSP: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_PROBE_RSP; ++ break; ++ case SUBTYPE_BEACON: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_BEACON; ++ break; ++ case SUBTYPE_ATIM: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ATIM; ++ break; ++ case SUBTYPE_DISASSOC: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_DISASSOC_REQ; ++ break; ++ case SUBTYPE_AUTH: ++ // get the sequence number from payload 24 Mac Header + 2 bytes algorithm ++ NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); ++ if (Seq == 1 || Seq == 3) ++ { ++ *Machine = AUTH_RSP_STATE_MACHINE; ++ *MsgType = MT2_PEER_AUTH_ODD; ++ } ++ else if (Seq == 2 || Seq == 4) ++ { ++ *Machine = AUTH_STATE_MACHINE; ++ *MsgType = MT2_PEER_AUTH_EVEN; ++ } ++ else ++ { ++ return FALSE; ++ } ++ break; ++ case SUBTYPE_DEAUTH: ++ *Machine = AUTH_RSP_STATE_MACHINE; ++ *MsgType = MT2_PEER_DEAUTH; ++ break; ++ case SUBTYPE_ACTION: ++ *Machine = ACTION_STATE_MACHINE; ++ // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support ++ if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) ++ { ++ *MsgType = MT2_ACT_INVALID; ++ } ++ else ++ { ++ *MsgType = (pFrame->Octet[0]&0x7F); ++ } ++ break; ++ default: ++ return FALSE; ++ break; ++ } ++ ++ return TRUE; ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++// =========================================================================================== ++// state_machine.c ++// =========================================================================================== ++ ++/*! \brief Initialize the state machine. ++ * \param *S pointer to the state machine ++ * \param Trans State machine transition function ++ * \param StNr number of states ++ * \param MsgNr number of messages ++ * \param DefFunc default function, when there is invalid state/message combination ++ * \param InitState initial state of the state machine ++ * \param Base StateMachine base, internal use only ++ * \pre p_sm should be a legal pointer ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID StateMachineInit( ++ IN STATE_MACHINE *S, ++ IN STATE_MACHINE_FUNC Trans[], ++ IN ULONG StNr, ++ IN ULONG MsgNr, ++ IN STATE_MACHINE_FUNC DefFunc, ++ IN ULONG InitState, ++ IN ULONG Base) ++{ ++ ULONG i, j; ++ ++ // set number of states and messages ++ S->NrState = StNr; ++ S->NrMsg = MsgNr; ++ S->Base = Base; ++ ++ S->TransFunc = Trans; ++ ++ // init all state transition to default function ++ for (i = 0; i < StNr; i++) ++ { ++ for (j = 0; j < MsgNr; j++) ++ { ++ S->TransFunc[i * MsgNr + j] = DefFunc; ++ } ++ } ++ ++ // set the starting state ++ S->CurrState = InitState; ++} ++ ++/*! \brief This function fills in the function pointer into the cell in the state machine ++ * \param *S pointer to the state machine ++ * \param St state ++ * \param Msg incoming message ++ * \param f the function to be executed when (state, message) combination occurs at the state machine ++ * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID StateMachineSetAction( ++ IN STATE_MACHINE *S, ++ IN ULONG St, ++ IN ULONG Msg, ++ IN STATE_MACHINE_FUNC Func) ++{ ++ ULONG MsgIdx; ++ ++ MsgIdx = Msg - S->Base; ++ ++ if (St < S->NrState && MsgIdx < S->NrMsg) ++ { ++ // boundary checking before setting the action ++ S->TransFunc[St * S->NrMsg + MsgIdx] = Func; ++ } ++} ++ ++/*! \brief This function does the state transition ++ * \param *Adapter the NIC adapter pointer ++ * \param *S the state machine ++ * \param *Elem the message to be executed ++ * \return None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID StateMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ The drop function, when machine executes this, the message is simply ++ ignored. This function does nothing, the message is freed in ++ StateMachinePerformAction() ++ ========================================================================== ++ */ ++VOID Drop( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++// =========================================================================================== ++// lfsr.c ++// =========================================================================================== ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID LfsrInit( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Seed) ++{ ++ if (Seed == 0) ++ pAd->Mlme.ShiftReg = 1; ++ else ++ pAd->Mlme.ShiftReg = Seed; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++UCHAR RandomByte( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ UCHAR R, Result; ++ ++ R = 0; ++ ++ if (pAd->Mlme.ShiftReg == 0) ++ NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg); ++ ++ for (i = 0; i < 8; i++) ++ { ++ if (pAd->Mlme.ShiftReg & 0x00000001) ++ { ++ pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; ++ Result = 1; ++ } ++ else ++ { ++ pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; ++ Result = 0; ++ } ++ R = (R << 1) | Result; ++ } ++ ++ return R; ++} ++ ++VOID AsicUpdateAutoFallBackTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRateTable) ++{ ++ UCHAR i; ++ HT_FBK_CFG0_STRUC HtCfg0; ++ HT_FBK_CFG1_STRUC HtCfg1; ++ LG_FBK_CFG0_STRUC LgCfg0; ++ LG_FBK_CFG1_STRUC LgCfg1; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate; ++ ++ // set to initial value ++ HtCfg0.word = 0x65432100; ++ HtCfg1.word = 0xedcba988; ++ LgCfg0.word = 0xedcba988; ++ LgCfg1.word = 0x00002100; ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1; ++ for (i = 1; i < *((PUCHAR) pRateTable); i++) ++ { ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1+i; ++ switch (pCurrTxRate->Mode) ++ { ++ case 0: //CCK ++ break; ++ case 1: //OFDM ++ { ++ switch(pCurrTxRate->CurrMCS) ++ { ++ case 0: ++ LgCfg0.field.OFDMMCS0FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 1: ++ LgCfg0.field.OFDMMCS1FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 2: ++ LgCfg0.field.OFDMMCS2FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 3: ++ LgCfg0.field.OFDMMCS3FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 4: ++ LgCfg0.field.OFDMMCS4FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 5: ++ LgCfg0.field.OFDMMCS5FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 6: ++ LgCfg0.field.OFDMMCS6FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 7: ++ LgCfg0.field.OFDMMCS7FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ } ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case 2: //HT-MIX ++ case 3: //HT-GF ++ { ++ if ((pNextTxRate->Mode >= MODE_HTMIX) && (pCurrTxRate->CurrMCS != pNextTxRate->CurrMCS)) ++ { ++ switch(pCurrTxRate->CurrMCS) ++ { ++ case 0: ++ HtCfg0.field.HTMCS0FBK = pNextTxRate->CurrMCS; ++ break; ++ case 1: ++ HtCfg0.field.HTMCS1FBK = pNextTxRate->CurrMCS; ++ break; ++ case 2: ++ HtCfg0.field.HTMCS2FBK = pNextTxRate->CurrMCS; ++ break; ++ case 3: ++ HtCfg0.field.HTMCS3FBK = pNextTxRate->CurrMCS; ++ break; ++ case 4: ++ HtCfg0.field.HTMCS4FBK = pNextTxRate->CurrMCS; ++ break; ++ case 5: ++ HtCfg0.field.HTMCS5FBK = pNextTxRate->CurrMCS; ++ break; ++ case 6: ++ HtCfg0.field.HTMCS6FBK = pNextTxRate->CurrMCS; ++ break; ++ case 7: ++ HtCfg0.field.HTMCS7FBK = pNextTxRate->CurrMCS; ++ break; ++ case 8: ++ HtCfg1.field.HTMCS8FBK = pNextTxRate->CurrMCS; ++ break; ++ case 9: ++ HtCfg1.field.HTMCS9FBK = pNextTxRate->CurrMCS; ++ break; ++ case 10: ++ HtCfg1.field.HTMCS10FBK = pNextTxRate->CurrMCS; ++ break; ++ case 11: ++ HtCfg1.field.HTMCS11FBK = pNextTxRate->CurrMCS; ++ break; ++ case 12: ++ HtCfg1.field.HTMCS12FBK = pNextTxRate->CurrMCS; ++ break; ++ case 13: ++ HtCfg1.field.HTMCS13FBK = pNextTxRate->CurrMCS; ++ break; ++ case 14: ++ HtCfg1.field.HTMCS14FBK = pNextTxRate->CurrMCS; ++ break; ++ case 15: ++ HtCfg1.field.HTMCS15FBK = pNextTxRate->CurrMCS; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicUpdateAutoFallBackTable: not support CurrMCS=%d\n", pCurrTxRate->CurrMCS)); ++ } ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ pNextTxRate = pCurrTxRate; ++ } ++ ++ RTMP_IO_WRITE32(pAd, HT_FBK_CFG0, HtCfg0.word); ++ RTMP_IO_WRITE32(pAd, HT_FBK_CFG1, HtCfg1.word); ++ RTMP_IO_WRITE32(pAd, LG_FBK_CFG0, LgCfg0.word); ++ RTMP_IO_WRITE32(pAd, LG_FBK_CFG1, LgCfg1.word); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set MAC register value according operation mode. ++ OperationMode AND bNonGFExist are for MM and GF Proteciton. ++ If MM or GF mask is not set, those passing argument doesn't not take effect. ++ ++ Operation mode meaning: ++ = 0 : Pure HT, no preotection. ++ = 0x01; there may be non-HT devices in both the control and extension channel, protection is optional in BSS. ++ = 0x10: No Transmission in 40M is protected. ++ = 0x11: Transmission in both 40M and 20M shall be protected ++ if (bNonGFExist) ++ we should choose not to use GF. But still set correct ASIC registers. ++ ======================================================================== ++*/ ++VOID AsicUpdateProtect( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT OperationMode, ++ IN UCHAR SetMask, ++ IN BOOLEAN bDisableBGProtect, ++ IN BOOLEAN bNonGFExist) ++{ ++ PROT_CFG_STRUC ProtCfg, ProtCfg4; ++ UINT32 Protect[6]; ++ USHORT offset; ++ UCHAR i; ++ UINT32 MacReg = 0; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++ if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8)) ++ { ++ return; ++ } ++ ++ if (pAd->BATable.numAsOriginator) ++ { ++ // ++ // enable the RTS/CTS to avoid channel collision ++ // ++ SetMask = ALLN_SETPROTECT; ++ OperationMode = 8; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Config ASIC RTS threshold register ++ RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); ++ MacReg &= 0xFF0000FF; ++#if 0 ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++#else ++ // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 ++ if (( ++#ifdef DOT11_N_SUPPORT ++ (pAd->CommonCfg.BACapability.field.AmsduEnable) || ++#endif // DOT11_N_SUPPORT // ++ (pAd->CommonCfg.bAggregationCapable == TRUE)) ++ && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD) ++ { ++ MacReg |= (0x1000 << 8); ++ } ++ else ++ { ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++ } ++#endif ++ ++ RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); ++ ++ // Initial common protection settings ++ RTMPZeroMemory(Protect, sizeof(Protect)); ++ ProtCfg4.word = 0; ++ ProtCfg.word = 0; ++ ProtCfg.field.TxopAllowGF40 = 1; ++ ProtCfg.field.TxopAllowGF20 = 1; ++ ProtCfg.field.TxopAllowMM40 = 1; ++ ProtCfg.field.TxopAllowMM20 = 1; ++ ProtCfg.field.TxopAllowOfdm = 1; ++ ProtCfg.field.TxopAllowCck = 1; ++ ProtCfg.field.RTSThEn = 1; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ++ // update PHY mode and rate ++ if (pAd->CommonCfg.Channel > 14) ++ ProtCfg.field.ProtectRate = 0x4000; ++ ProtCfg.field.ProtectRate |= pAd->CommonCfg.RtsRate; ++ ++ // Handle legacy(B/G) protection ++ if (bDisableBGProtect) ++ { ++ //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; ++ Protect[0] = ProtCfg.word; ++ Protect[1] = ProtCfg.word; ++ } ++ else ++ { ++ //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; // CCK do not need to be protected ++ Protect[0] = ProtCfg.word; ++ ProtCfg.field.ProtectCtrl = ASIC_CTS; // OFDM needs using CCK to protect ++ Protect[1] = ProtCfg.word; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // Decide HT frame protection. ++ if ((SetMask & ALLN_SETPROTECT) != 0) ++ { ++ switch(OperationMode) ++ { ++ case 0x0: ++ // NO PROTECT ++ // 1.All STAs in the BSS are 20/40 MHz HT ++ // 2. in ai 20/40MHz BSS ++ // 3. all STAs are 20MHz in a 20MHz BSS ++ // Pure HT. no protection. ++ ++ // MM20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[2] = 0x01744004; ++ ++ // MM40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[3] = 0x03f44084; ++ ++ // CF20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[4] = 0x01744004; ++ ++ // CF40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[5] = 0x03f44084; ++ ++ if (bNonGFExist) ++ { ++ // PROT_NAV(19:18) -- 01 (Short NAV protectiion) ++ // PROT_CTRL(17:16) -- 01 (RTS/CTS) ++ Protect[4] = 0x01754004; ++ Protect[5] = 0x03f54084; ++ } ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ break; ++ ++ case 1: ++ // This is "HT non-member protection mode." ++ // If there may be non-HT STAs my BSS ++ ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) ++ ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. ++ ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083; ++ } ++ //Assign Protection method for 20&40 MHz packets ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ ++ case 2: ++ // If only HT STAs are in BSS. at least one is 20MHz. Only protect 40MHz packets ++ ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) ++ ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. ++ ++ //Assign Protection method for 40MHz packets ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ if (bNonGFExist) ++ { ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ } ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ break; ++ ++ case 3: ++ // HT mixed mode. PROTECT ALL! ++ // Assign Rate ++ ProtCfg.word = 0x01744004; //duplicaet legacy 24M. BW set 1. ++ ProtCfg4.word = 0x03f44084; ++ // both 20MHz and 40MHz are protected. Whether use RTS or CTS-to-self depends on the ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. ++ ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083 ++ } ++ //Assign Protection method for 20&40 MHz packets ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ ++ case 8: ++ // Special on for Atheros problem n chip. ++ Protect[2] = 0x01754004; ++ Protect[3] = 0x03f54084; ++ Protect[4] = 0x01754004; ++ Protect[5] = 0x03f54084; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ offset = CCK_PROT_CFG; ++ for (i = 0;i < 6;i++) ++ { ++ if ((SetMask & (1<< i))) ++ { ++ RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN BOOLEAN bScan) ++{ ++ ULONG R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0; ++ CHAR TxPwer = 0, TxPwer2 = DEFAULT_RF_TX_POWER; //Bbp94 = BBPR94_DEFAULT, TxPwer2 = DEFAULT_RF_TX_POWER; ++ UCHAR index; ++ UINT32 Value = 0; //BbpReg, Value; ++ RTMP_RF_REGS *RFRegTable; ++ ++ // Search Tx power value ++ for (index = 0; index < pAd->ChannelListNum; index++) ++ { ++ if (Channel == pAd->ChannelList[index].Channel) ++ { ++ TxPwer = pAd->ChannelList[index].Power; ++ TxPwer2 = pAd->ChannelList[index].Power2; ++ break; ++ } ++ } ++ ++ if (index == MAX_NUM_OF_CHANNELS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Cant find the Channel#%d \n", Channel)); ++ } ++ ++#ifdef RT2870 ++ // The RF programming sequence is difference between 3xxx and 2xxx ++ if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020))) ++ { ++ /* modify by WY for Read RF Reg. error */ ++ UCHAR RFValue; ++ ++ for (index = 0; index < NUM_OF_3020_CHNL; index++) ++ { ++ if (Channel == FreqItems3020[index].Channel) ++ { ++ // Programming channel parameters ++ RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); ++ RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); ++ ++ RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RFValue); ++ RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; ++ RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RFValue); ++ ++ // Set Tx Power ++ RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); ++ RFValue = (RFValue & 0xE0) | TxPwer; ++ RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); ++ ++ // Set RF offset ++ RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); ++ RFValue = (RFValue & 0x80) | pAd->RfFreqOffset; ++ RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); ++ ++ // Set BW ++ if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) ++ { ++ RFValue = pAd->Mlme.CaliBW40RfR24; ++ //DISABLE_11N_CHECK(pAd); ++ } ++ else ++ { ++ RFValue = pAd->Mlme.CaliBW20RfR24; ++ } ++ RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR)RFValue); ++ ++ // Enable RF tuning ++ RT30xxReadRFRegister(pAd, RF_R07, (PUCHAR)&RFValue); ++ RFValue = RFValue | 0x1; ++ RT30xxWriteRFRegister(pAd, RF_R07, (UCHAR)RFValue); ++ ++ // latch channel for future usage. ++ pAd->LatchRfRegs.Channel = Channel; ++ ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", ++ Channel, ++ pAd->RfIcType, ++ TxPwer, ++ TxPwer2, ++ pAd->Antenna.field.TxPath, ++ FreqItems3020[index].N, ++ FreqItems3020[index].K, ++ FreqItems3020[index].R)); ++ } ++ else ++#endif // RT2870 // ++ { ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ R2 |= 0x40; // write 1 to off Rxpath. ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ ++ if (Channel > 14) ++ { ++ // initialize R3, R4 ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff); ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15); ++ ++ // 5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB ++ // R3 ++ if ((TxPwer >= -7) && (TxPwer < 0)) ++ { ++ TxPwer = (7+TxPwer); ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10); ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer=%d \n", TxPwer)); ++ } ++ else ++ { ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10) | (1 << 9); ++ } ++ ++ // R4 ++ if ((TxPwer2 >= -7) && (TxPwer2 < 0)) ++ { ++ TxPwer2 = (7+TxPwer2); ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7); ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); ++ } ++ else ++ { ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7) | (1 << 6); ++ } ++ } ++ else ++ { ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15) | (TxPwer2 <<6);// Set freq Offset & TxPwr1 ++ } ++ ++ // Based on BBP current mode before changing RF channel. ++ if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) ++ { ++ R4 |=0x200000; ++ } ++ ++ // Update variables ++ pAd->LatchRfRegs.Channel = Channel; ++ pAd->LatchRfRegs.R1 = RFRegTable[index].R1; ++ pAd->LatchRfRegs.R2 = R2; ++ pAd->LatchRfRegs.R3 = R3; ++ pAd->LatchRfRegs.R4 = R4; ++ ++ // Set RF value 1's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 2's set R3[bit2] = [1] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 3's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ // Change BBP setting during siwtch from a->g, g->a ++ if (Channel <= 14) ++ { ++ ULONG TxPinCfg = 0x00050F0A;//Gary 2007/08/09 0x050A0A ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ ++ // Rx High power VGA offset for LNA select ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); ++ } ++ ++ // 5G band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x04); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ else ++ { ++ ULONG TxPinCfg = 0x00050F05;//Gary 2007/8/9 0x050505 ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); ++ ++ // Rx High power VGA offset for LNA select ++ if (pAd->NicConfig2.field.ExternalLNAForA) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); ++ } ++ ++ // 5G band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x02); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ ++ // R66 should be set according to Channel and use 20MHz when scanning ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x2E + GET_LNA_GAIN(pAd))); ++ if (bScan) ++ RTMPSetAGCInitValue(pAd, BW_20); ++ else ++ RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); ++ ++ // ++ // On 11A, We should delay and wait RF/BBP to be stable ++ // and the appropriate time should be 1000 micro seconds ++ // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. ++ // ++ RTMPusecDelay(1000); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%lu, Pwr1=%lu, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ (R3 & 0x00003e00) >> 9, ++ (R4 & 0x000007c0) >> 6, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This function is required for 2421 only, and should not be used during ++ site survey. It's only required after NIC decided to stay at a channel ++ for a longer period. ++ When this function is called, it's always after AsicSwitchChannel(). ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicLockChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicAntennaSelect( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Antenna miscellaneous setting. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ BandState Indicate current Band State. ++ ++ Return Value: ++ None ++ ++ IRQL <= DISPATCH_LEVEL ++ ++ Note: ++ 1.) Frame End type control ++ only valid for G only (RF_2527 & RF_2529) ++ 0: means DPDT, set BBP R4 bit 5 to 1 ++ 1: means SPDT, set BBP R4 bit 5 to 0 ++ ++ ++ ======================================================================== ++*/ ++VOID AsicAntennaSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN ABGBAND_STATE BandState) ++{ ++} ++ ++VOID AsicRfTuningExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Gives CCK TX rate 2 more dB TX power. ++ This routine works only in LINK UP in INFRASTRUCTURE mode. ++ ++ calculate desired Tx power in RF R3.Tx0~5, should consider - ++ 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) ++ 1. TxPowerPercentage ++ 2. auto calibration based on TSSI feedback ++ 3. extra 2 db for CCK ++ 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP ++ ++ NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), ++ it should be called AFTER MlmeDynamicTxRatSwitching() ++ ========================================================================== ++ */ ++VOID AsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i, j; ++ CHAR DeltaPwr = 0; ++ BOOLEAN bAutoTxAgc = FALSE; ++ UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; ++ UCHAR BbpR1 = 0, BbpR49 = 0, idx; ++ PCHAR pTxAgcCompensate; ++ ULONG TxPwr[5]; ++ CHAR Value; ++ ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ if (pAd->CommonCfg.CentralChannel > 14) ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; ++ } ++ } ++ ++ // TX power compensation for temperature variation based on TSSI. try every 4 second ++ if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) ++ { ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ /* bg channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ TssiRef = pAd->TssiRefG; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; ++ TxAgcStep = pAd->TxAgcStepG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ /* a channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ TssiRef = pAd->TssiRefA; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; ++ TxAgcStep = pAd->TxAgcStepA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ { ++ /* BbpR1 is unsigned char */ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); ++ ++ /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ ++ /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ ++ /* step value is defined in pAd->TxAgcStepG for tx power value */ ++ ++ /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ ++ /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ above value are examined in mass factory production */ ++ /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ ++ ++ /* plus (+) is 0x00 ~ 0x45, minus (-) is 0xa0 ~ 0xf0 */ ++ /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ ++ /* if value is 0xa5, tx power will be -= TxAgcStep*(2-1) */ ++ ++ if (BbpR49 > pTssiMinusBoundary[1]) ++ { ++ // Reading is larger than the reference value ++ // check for how large we need to decrease the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should decrease, idx = 0 means there is nothing to compensate ++// if (R3 > (ULONG) (TxAgcStep * (idx-1))) ++ *pTxAgcCompensate = -(TxAgcStep * (idx-1)); ++// else ++// *pTxAgcCompensate = -((UCHAR)R3); ++ ++ DeltaPwr += (*pTxAgcCompensate); ++ DBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else if (BbpR49 < pTssiPlusBoundary[1]) ++ { ++ // Reading is smaller than the reference value ++ // check for how large we need to increase the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should increase, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = TxAgcStep * (idx-1); ++ DeltaPwr += (*pTxAgcCompensate); ++ DBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else ++ { ++ *pTxAgcCompensate = 0; ++ DBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R49=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, 0)); ++ } ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ DeltaPwr += (*pTxAgcCompensate); ++ } ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1); ++ BbpR1 &= 0xFC; ++ ++#ifdef SINGLE_SKU ++ // Handle regulatory max tx power constrain ++ do ++ { ++ UCHAR TxPwrInEEPROM = 0xFF, CountryTxPwr = 0xFF, criterion; ++ UCHAR AdjustMaxTxPwr[40]; ++ ++ if (pAd->CommonCfg.Channel > 14) // 5G band ++ TxPwrInEEPROM = ((pAd->CommonCfg.DefineMaxTxPwr & 0xFF00) >> 8); ++ else // 2.4G band ++ TxPwrInEEPROM = (pAd->CommonCfg.DefineMaxTxPwr & 0x00FF); ++ CountryTxPwr = GetCuntryMaxTxPwr(pAd, pAd->CommonCfg.Channel); ++ ++ // error handling, range check ++ if ((TxPwrInEEPROM > 0x50) || (CountryTxPwr > 0x50)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("AsicAdjustTxPower - Invalid max tx power (=0x%02x), CountryTxPwr=%d\n", TxPwrInEEPROM, CountryTxPwr)); ++ break; ++ } ++ ++ criterion = *((PUCHAR)TxPwr + 2) & 0xF; // FAE use OFDM 6M as criterion ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (criterion=%d, TxPwrInEEPROM=%d, CountryTxPwr=%d)\n", criterion, TxPwrInEEPROM, CountryTxPwr)); ++ ++ // Adjust max tx power according to the relationship of tx power in E2PROM ++ for (i=0; i<5; i++) ++ { ++ // CCK will have 4dBm larger than OFDM ++ // Therefore, we should separate to parse the tx power field ++ if (i == 0) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ if (j < 4) ++ { ++ // CCK will have 4dBm larger than OFDM ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion) + 4; ++ } ++ else ++ { ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ } ++ else ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ } ++ } ++ ++ // Adjust tx power according to the relationship ++ for (i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ // The system tx power is larger than the regulatory, the power should be restrain ++ if (AdjustMaxTxPwr[i*8+j] > CountryTxPwr) ++ { ++ // decrease to zero and don't need to take care BBPR1 ++ if ((Value - (AdjustMaxTxPwr[i*8+j] - CountryTxPwr)) > 0) ++ Value -= (AdjustMaxTxPwr[i*8+j] - CountryTxPwr); ++ else ++ Value = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ else ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d, no change)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ } ++ } ++ } while (FALSE); ++#endif // SINGLE_SKU // ++ ++ /* calculate delta power based on the percentage specified from UI */ ++ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) ++ // We lower TX power here according to the percentage specified from UI ++ if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW // DeltaPwr -= 1; ++ { ++ DeltaPwr -= 1; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW // DeltaPwr -= 3; ++ { ++ DeltaPwr -= 3; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW // DeltaPwr -= 6; ++ { ++ BbpR1 |= 0x01; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW // DeltaPwr -= 9; ++ { ++ BbpR1 |= 0x01; ++ DeltaPwr -= 3; ++ } ++ else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW // DeltaPwr -= 12; ++ { ++ BbpR1 |= 0x02; ++ } ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpR1); ++ ++ /* reset different new tx power for different TX rate */ ++ for(i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ ++ ++ if ((Value + DeltaPwr) < 0) ++ { ++ Value = 0; /* min */ ++ } ++ else if ((Value + DeltaPwr) > 0xF) ++ { ++ Value = 0xF; /* max */ ++ } ++ else ++ { ++ Value += DeltaPwr; /* temperature compensation */ ++ } ++ ++ /* fill new value to CSR offset */ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ ++ /* write tx power value to CSR */ ++ /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M ++ TX power for OFDM 6M/9M ++ TX power for CCK5.5M/11M ++ TX power for CCK1M/2M */ ++ /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); ++ } ++ } ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ put PHY to sleep here, and set next wakeup timer. PHY doesn't not wakeup ++ automatically. Instead, MCU will issue a TwakeUpInterrupt to host after ++ the wakeup timer timeout. Driver has to issue a separate command to wake ++ PHY up. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ AsicForceWakeup() is used whenever manual wakeup is required ++ AsicForceSleep() should only be used when not in INFRA BSS. When ++ in INFRA BSS, we should use AsicSleepThenAutoWakeup() instead. ++ ========================================================================== ++ */ ++VOID AsicForceSleep( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ AsicForceWakeup() is used whenever Twakeup timer (set via AsicSleepThenAutoWakeup) ++ expired. ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ========================================================================== ++ */ ++VOID AsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); ++ RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); ++} ++#endif // CONFIG_STA_SUPPORT // ++/* ++ ========================================================================== ++ Description: ++ Set My BSSID ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetBssid( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid) ++{ ++ ULONG Addr4; ++ DBGPRINT(RT_DEBUG_TRACE, ("==============> AsicSetBssid %x:%x:%x:%x:%x:%x\n", ++ pBssid[0],pBssid[1],pBssid[2],pBssid[3], pBssid[4],pBssid[5])); ++ ++ Addr4 = (ULONG)(pBssid[0]) | ++ (ULONG)(pBssid[1] << 8) | ++ (ULONG)(pBssid[2] << 16) | ++ (ULONG)(pBssid[3] << 24); ++ RTMP_IO_WRITE32(pAd, MAC_BSSID_DW0, Addr4); ++ ++ Addr4 = 0; ++ // always one BSSID in STA mode ++ Addr4 = (ULONG)(pBssid[4]) | (ULONG)(pBssid[5] << 8); ++ ++ RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, Addr4); ++} ++ ++VOID AsicSetMcastWC( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[MCAST_WCID]; ++ USHORT offset; ++ ++ pEntry->Sst = SST_ASSOC; ++ pEntry->Aid = MCAST_WCID; // Softap supports 1 BSSID and use WCID=0 as multicast Wcid index ++ pEntry->PsMode = PWR_ACTIVE; ++ pEntry->CurrTxRate = pAd->CommonCfg.MlmeRate; ++ offset = MAC_WCID_BASE + BSS0Mcast_WCID * HW_WCID_ENTRY_SIZE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDelWcidTab( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid) ++{ ++ ULONG Addr0 = 0x0, Addr1 = 0x0; ++ ULONG offset; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicDelWcidTab==>Wcid = 0x%x\n",Wcid)); ++ offset = MAC_WCID_BASE + Wcid * HW_WCID_ENTRY_SIZE; ++ RTMP_IO_WRITE32(pAd, offset, Addr0); ++ offset += 4; ++ RTMP_IO_WRITE32(pAd, offset, Addr1); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableRDG( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ UINT32 Data = 0; ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ TxLinkCfg.field.TxRDGEn = 1; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++ ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ Data |= 0x80; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDisableRDG( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ UINT32 Data = 0; ++ ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ TxLinkCfg.field.TxRDGEn = 0; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++ ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ ++ Data &= 0xFFFFFF00; ++ //Data |= 0x20; ++#ifndef WIFI_TEST ++ //if ( pAd->CommonCfg.bEnableTxBurst ) ++ // Data |= 0x60; // for performance issue not set the TXOP to 0 ++#endif ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE) ++#ifdef DOT11_N_SUPPORT ++ && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode ++ if (pAd->CommonCfg.bEnableTxBurst) ++ Data |= 0x20; ++ } ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDisableSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->Disable TSF synchronization\n")); ++ ++ // 2003-12-20 disable TSF and TBTT while NIC in power-saving have side effect ++ // that NIC will never wakes up because TSF stops and no more ++ // TBTT interrupts ++ pAd->TbttTickCount = 0; ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ csr.field.bTsfTicking = 0; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableBssSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n")); ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++// RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, 0x00000000); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU ++ csr.field.bTsfTicking = 1; ++ csr.field.TsfSyncMode = 1; // sync TSF in INFRASTRUCTURE mode ++ csr.field.bBeaconGen = 0; // do NOT generate BEACON ++ csr.field.bTBTTEnable = 1; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Note: ++ BEACON frame in shared memory should be built ok before this routine ++ can be called. Otherwise, a garbage frame maybe transmitted out every ++ Beacon period. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableIbssSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr9; ++ PUCHAR ptr; ++ UINT i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableIbssSync(ADHOC mode. MPDUtotalByteCount = %d)\n", pAd->BeaconTxWI.MPDUtotalByteCount)); ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr9.word); ++ csr9.field.bBeaconGen = 0; ++ csr9.field.bTBTTEnable = 0; ++ csr9.field.bTsfTicking = 0; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); ++ ++ ++#ifdef RT2870 ++ // move BEACON TXD and frame content to on-chip memory ++ ptr = (PUCHAR)&pAd->BeaconTxWI; ++ for (i=0; iBeaconBuf; ++ for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=2) ++ { ++ //UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24); ++ //RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, longptr); ++ RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, ptr, 2); ++ ptr +=2; ++ } ++#endif // RT2870 // ++ ++ // ++ // For Wi-Fi faily generated beacons between participating stations. ++ // Set TBTT phase adaptive adjustment step to 8us (default 16us) ++ // don't change settings 2006-5- by Jerry ++ //RTMP_IO_WRITE32(pAd, TBTT_SYNC_CFG, 0x00001010); ++ ++ // start sending BEACON ++ csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU ++ csr9.field.bTsfTicking = 1; ++ csr9.field.TsfSyncMode = 2; // sync TSF in IBSS mode ++ csr9.field.bTBTTEnable = 1; ++ csr9.field.bBeaconGen = 1; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetEdcaParm( ++ IN PRTMP_ADAPTER pAd, ++ IN PEDCA_PARM pEdcaParm) ++{ ++ EDCA_AC_CFG_STRUC Ac0Cfg, Ac1Cfg, Ac2Cfg, Ac3Cfg; ++ AC_TXOP_CSR0_STRUC csr0; ++ AC_TXOP_CSR1_STRUC csr1; ++ AIFSN_CSR_STRUC AifsnCsr; ++ CWMIN_CSR_STRUC CwminCsr; ++ CWMAX_CSR_STRUC CwmaxCsr; ++ int i; ++ ++ Ac0Cfg.word = 0; ++ Ac1Cfg.word = 0; ++ Ac2Cfg.word = 0; ++ Ac3Cfg.word = 0; ++ if ((pEdcaParm == NULL) || (pEdcaParm->bValid == FALSE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AsicSetEdcaParm\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WMM_INUSED); ++ for (i=0; iMacTab.Content[i].ValidAsCLI || pAd->MacTab.Content[i].ValidAsApCli) ++ CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[i], fCLIENT_STATUS_WMM_CAPABLE); ++ } ++ ++ //======================================================== ++ // MAC Register has a copy . ++ //======================================================== ++//#ifndef WIFI_TEST ++ if( pAd->CommonCfg.bEnableTxBurst ) ++ { ++ // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode ++ Ac0Cfg.field.AcTxop = 0x20; // Suggest by John for TxBurst in HT Mode ++ } ++ else ++ Ac0Cfg.field.AcTxop = 0; // QID_AC_BE ++//#else ++// Ac0Cfg.field.AcTxop = 0; // QID_AC_BE ++//#endif ++ Ac0Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac0Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac0Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); ++ ++ Ac1Cfg.field.AcTxop = 0; // QID_AC_BK ++ Ac1Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac1Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac1Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); ++ ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ Ac2Cfg.field.AcTxop = 192; // AC_VI: 192*32us ~= 6ms ++ Ac3Cfg.field.AcTxop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ Ac2Cfg.field.AcTxop = 96; // AC_VI: 96*32us ~= 3ms ++ Ac3Cfg.field.AcTxop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ Ac2Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac2Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac2Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); ++ Ac3Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac3Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac3Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); ++ ++ //======================================================== ++ // DMA Register has a copy too. ++ //======================================================== ++ csr0.field.Ac0Txop = 0; // QID_AC_BE ++ csr0.field.Ac1Txop = 0; // QID_AC_BK ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ csr1.field.Ac2Txop = 192; // AC_VI: 192*32us ~= 6ms ++ csr1.field.Ac3Txop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ csr1.field.Ac2Txop = 96; // AC_VI: 96*32us ~= 3ms ++ csr1.field.Ac3Txop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); ++ ++ CwminCsr.word = 0; ++ CwminCsr.field.Cwmin0 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin1 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin2 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin3 = CW_MIN_IN_BITS; ++ RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); ++ ++ CwmaxCsr.word = 0; ++ CwmaxCsr.field.Cwmax0 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax1 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax2 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax3 = CW_MAX_IN_BITS; ++ RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); ++ ++ RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, 0x00002222); ++ ++ NdisZeroMemory(&pAd->CommonCfg.APEdcaParm, sizeof(EDCA_PARM)); ++ } ++ else ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WMM_INUSED); ++ //======================================================== ++ // MAC Register has a copy. ++ //======================================================== ++ // ++ // Modify Cwmin/Cwmax/Txop on queue[QID_AC_VI], Recommend by Jerry 2005/07/27 ++ // To degrade our VIDO Queue's throughput for WiFi WMM S3T07 Issue. ++ // ++ //pEdcaParm->Txop[QID_AC_VI] = pEdcaParm->Txop[QID_AC_VI] * 7 / 10; // rt2860c need this ++ ++ Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE]; ++ Ac0Cfg.field.Cwmin= pEdcaParm->Cwmin[QID_AC_BE]; ++ Ac0Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BE]; ++ Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]; //+1; ++ ++ Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; ++ Ac1Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_BK]; //+2; ++ Ac1Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BK]; ++ Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; //+1; ++ ++ Ac2Cfg.field.AcTxop = (pEdcaParm->Txop[QID_AC_VI] * 6) / 10; ++ Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI]; ++ Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI]; ++ Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Tuning for Wi-Fi WMM S06 ++ if (pAd->CommonCfg.bWiFiTest && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ Ac2Cfg.field.Aifsn -= 1; ++ ++ // Tuning for TGn Wi-Fi 5.2.32 ++ // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta ++ if (STA_TGN_WIFI_ON(pAd) && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ { ++ Ac0Cfg.field.Aifsn = 3; ++ Ac2Cfg.field.AcTxop = 5; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO]; ++ Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO]; ++ Ac3Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VO]; ++ Ac3Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VO]; ++ ++//#ifdef WIFI_TEST ++ if (pAd->CommonCfg.bWiFiTest) ++ { ++ if (Ac3Cfg.field.AcTxop == 102) ++ { ++ Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE] ? pEdcaParm->Txop[QID_AC_BE] : 10; ++ Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]-1; /* AIFSN must >= 1 */ ++ Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; ++ Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; ++ Ac2Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VI]; ++ } /* End of if */ ++ } ++//#endif // WIFI_TEST // ++ ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); ++ ++ ++ //======================================================== ++ // DMA Register has a copy too. ++ //======================================================== ++ csr0.field.Ac0Txop = Ac0Cfg.field.AcTxop; ++ csr0.field.Ac1Txop = Ac1Cfg.field.AcTxop; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ ++ csr1.field.Ac2Txop = Ac2Cfg.field.AcTxop; ++ csr1.field.Ac3Txop = Ac3Cfg.field.AcTxop; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); ++ ++ CwminCsr.word = 0; ++ CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE]; ++ CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK]; ++ CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); ++ ++ CwmaxCsr.word = 0; ++ CwmaxCsr.field.Cwmax0 = pEdcaParm->Cwmax[QID_AC_BE]; ++ CwmaxCsr.field.Cwmax1 = pEdcaParm->Cwmax[QID_AC_BK]; ++ CwmaxCsr.field.Cwmax2 = pEdcaParm->Cwmax[QID_AC_VI]; ++ CwmaxCsr.field.Cwmax3 = pEdcaParm->Cwmax[QID_AC_VO]; ++ RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); ++ ++ AifsnCsr.word = 0; ++ AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE]; ++ AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK]; ++ AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Tuning for Wi-Fi WMM S06 ++ if (pAd->CommonCfg.bWiFiTest && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4; ++ ++ // Tuning for TGn Wi-Fi 5.2.32 ++ // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta ++ if (STA_TGN_WIFI_ON(pAd) && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ { ++ AifsnCsr.field.Aifsn0 = 3; ++ AifsnCsr.field.Aifsn2 = 7; ++ } ++ ++ if (INFRA_ON(pAd)) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_WMM_CAPABLE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word); ++ ++ NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ if (!ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("EDCA [#%d]: AIFSN CWmin CWmax TXOP(us) ACM\n", pEdcaParm->EdcaUpdateCount)); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_BE %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[0], ++ pEdcaParm->Cwmin[0], ++ pEdcaParm->Cwmax[0], ++ pEdcaParm->Txop[0]<<5, ++ pEdcaParm->bACM[0])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_BK %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[1], ++ pEdcaParm->Cwmin[1], ++ pEdcaParm->Cwmax[1], ++ pEdcaParm->Txop[1]<<5, ++ pEdcaParm->bACM[1])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_VI %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[2], ++ pEdcaParm->Cwmin[2], ++ pEdcaParm->Cwmax[2], ++ pEdcaParm->Txop[2]<<5, ++ pEdcaParm->bACM[2])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_VO %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[3], ++ pEdcaParm->Cwmin[3], ++ pEdcaParm->Cwmax[3], ++ pEdcaParm->Txop[3]<<5, ++ pEdcaParm->bACM[3])); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetSlotTime( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUseShortSlotTime) ++{ ++ ULONG SlotTime; ++ UINT32 RegValue = 0; ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->CommonCfg.Channel > 14) ++ bUseShortSlotTime = TRUE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (bUseShortSlotTime) ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); ++ else ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); ++ ++ SlotTime = (bUseShortSlotTime)? 9 : 20; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // force using short SLOT time for FAE to demo performance when TxBurst is ON ++ if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) ++#ifdef DOT11_N_SUPPORT ++ || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ // In this case, we will think it is doing Wi-Fi test ++ // And we will not set to short slot when bEnableTxBurst is TRUE. ++ } ++ else if (pAd->CommonCfg.bEnableTxBurst) ++ SlotTime = 9; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // For some reasons, always set it to short slot time. ++ // ++ // ToDo: Should consider capability with 11B ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.BssType == BSS_ADHOC) ++ SlotTime = 20; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue); ++ RegValue = RegValue & 0xFFFFFF00; ++ ++ RegValue |= SlotTime; ++ ++ RTMP_IO_WRITE32(pAd, BKOFF_SLOT_CFG, RegValue); ++} ++ ++/* ++ ======================================================================== ++ Description: ++ Add Shared key information into ASIC. ++ Update shared key, TxMic and RxMic to Asic Shared key table ++ Update its cipherAlg to Asic Shared key Mode. ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicAddSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic) ++{ ++ ULONG offset; //, csr0; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); ++//============================================================================================ ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicAddSharedKeyEntry: %s key #%d\n", CipherName[CipherAlg], BssIndex*4 + KeyIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); ++ if (pRxMic) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ if (pTxMic) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ } ++//============================================================================================ ++ // ++ // fill key material - key + TX MIC + RX MIC ++ // ++ ++#ifdef RT2870 ++{ ++ offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; ++ RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_SHARE_KEY); ++ ++ offset += MAX_LEN_OF_SHARE_KEY; ++ if (pTxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pTxMic, 8); ++ } ++ ++ offset += 8; ++ if (pRxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pRxMic, 8); ++ } ++} ++#endif // RT2870 // ++ ++ // ++ // Update cipher algorithm. WSTA always use BSS0 ++ // ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE,("Read: SHARED_KEY_MODE_BASE at this Bss[%d] KeyIdx[%d]= 0x%x \n", BssIndex,KeyIdx, csr1.word)); ++ if ((BssIndex%2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss0Key3CipherAlg = CipherAlg; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss1Key3CipherAlg = CipherAlg; ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); ++ ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID AsicRemoveSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx) ++{ ++ //ULONG SecCsr0; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicRemoveSharedKeyEntry: #%d \n", BssIndex*4 + KeyIdx)); ++ ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); ++ if ((BssIndex%2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = 0; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = 0; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = 0; ++ else ++ csr1.field.Bss0Key3CipherAlg = 0; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = 0; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = 0; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = 0; ++ else ++ csr1.field.Bss1Key3CipherAlg = 0; ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); ++ ASSERT(BssIndex < 4); ++ ASSERT(KeyIdx < 4); ++ ++} ++ ++ ++VOID AsicUpdateWCIDAttribute( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bUsePairewiseKeyTable) ++{ ++ ULONG WCIDAttri = 0, offset; ++ ++ // ++ // Update WCID attribute. ++ // Only TxKey could update WCID attribute. ++ // ++ offset = MAC_WCID_ATTRIBUTE_BASE + (WCID * HW_WCID_ATTRI_SIZE); ++ WCIDAttri = (BssIndex << 4) | (CipherAlg << 1) | (bUsePairewiseKeyTable); ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++} ++ ++VOID AsicUpdateWCIDIVEIV( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN ULONG uIV, ++ IN ULONG uEIV) ++{ ++ ULONG offset; ++ ++ offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); ++ ++ RTMP_IO_WRITE32(pAd, offset, uIV); ++ RTMP_IO_WRITE32(pAd, offset + 4, uEIV); ++} ++ ++VOID AsicUpdateRxWCIDTable( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN PUCHAR pAddr) ++{ ++ ULONG offset; ++ ULONG Addr; ++ ++ offset = MAC_WCID_BASE + (WCID * HW_WCID_ENTRY_SIZE); ++ Addr = pAddr[0] + (pAddr[1] << 8) +(pAddr[2] << 16) +(pAddr[3] << 24); ++ RTMP_IO_WRITE32(pAd, offset, Addr); ++ Addr = pAddr[4] + (pAddr[5] << 8); ++ RTMP_IO_WRITE32(pAd, offset + 4, Addr); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set Cipher Key, Cipher algorithm, IV/EIV to Asic ++ ++ Arguments: ++ pAd Pointer to our adapter ++ WCID WCID Entry number. ++ BssIndex BSSID index, station or none multiple BSSID support ++ this value should be 0. ++ KeyIdx This KeyIdx will set to IV's KeyID if bTxKey enabled ++ pCipherKey Pointer to Cipher Key. ++ bUsePairewiseKeyTable TRUE means saved the key in SharedKey table, ++ otherwise PairewiseKey table ++ bTxKey This is the transmit key if enabled. ++ ++ Return Value: ++ None ++ ++ Note: ++ This routine will set the relative key stuff to Asic including WCID attribute, ++ Cipher Key, Cipher algorithm and IV/EIV. ++ ++ IV/EIV will be update if this CipherKey is the transmission key because ++ ASIC will base on IV's KeyID value to select Cipher Key. ++ ++ If bTxKey sets to FALSE, this is not the TX key, but it could be ++ RX key ++ ++ For AP mode bTxKey must be always set to TRUE. ++ ======================================================================== ++*/ ++VOID AsicAddKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN PCIPHER_KEY pCipherKey, ++ IN BOOLEAN bUsePairewiseKeyTable, ++ IN BOOLEAN bTxKey) ++{ ++ ULONG offset; ++// ULONG WCIDAttri = 0; ++ UCHAR IV4 = 0; ++ PUCHAR pKey = pCipherKey->Key; ++// ULONG KeyLen = pCipherKey->KeyLen; ++ PUCHAR pTxMic = pCipherKey->TxMic; ++ PUCHAR pRxMic = pCipherKey->RxMic; ++ PUCHAR pTxtsc = pCipherKey->TxTsc; ++ UCHAR CipherAlg = pCipherKey->CipherAlg; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++// ASSERT(KeyLen <= MAX_LEN_OF_PEER_KEY); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); ++ // ++ // 1.) decide key table offset ++ // ++ if (bUsePairewiseKeyTable) ++ offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); ++ else ++ offset = SHARED_KEY_TABLE_BASE + (4 * BssIndex + KeyIdx) * HW_KEY_ENTRY_SIZE; ++ ++ // ++ // 2.) Set Key to Asic ++ // ++ //for (i = 0; i < KeyLen; i++) ++ ++#ifdef RT2870 ++ RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_PEER_KEY); ++ offset += MAX_LEN_OF_PEER_KEY; ++ ++ // ++ // 3.) Set MIC key if available ++ // ++ if (pTxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pTxMic, 8); ++ } ++ offset += LEN_TKIP_TXMICK; ++ ++ if (pRxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pRxMic, 8); ++ } ++#endif // RT2870 // ++ ++ // ++ // 4.) Modify IV/EIV if needs ++ // This will force Asic to use this key ID by setting IV. ++ // ++ if (bTxKey) ++ { ++ ++#ifdef RT2870 ++ UINT32 tmpVal; ++ ++ // ++ // Write IV ++ // ++ IV4 = (KeyIdx << 6); ++ if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES)) ++ IV4 |= 0x20; // turn on extension bit means EIV existence ++ ++ tmpVal = pTxtsc[1] + (((pTxtsc[1] | 0x20) & 0x7f) << 8) + (pTxtsc[0] << 16) + (IV4 << 24); ++ RTMP_IO_WRITE32(pAd, offset, tmpVal); ++ ++ // ++ // Write EIV ++ // ++ offset += 4; ++ RTMP_IO_WRITE32(pAd, offset, *(PUINT32)&pCipherKey->TxTsc[2]); ++#endif // RT2870 // ++ AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); ++ } ++ ++ if (!bUsePairewiseKeyTable) ++ { ++ // ++ // Only update the shared key security mode ++ // ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), &csr1.word); ++ if ((BssIndex % 2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss0Key3CipherAlg = CipherAlg; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss1Key3CipherAlg = CipherAlg; ++ } ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), csr1.word); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== AsicAddKeyEntry\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ Description: ++ Add Pair-wise key material into ASIC. ++ Update pairwise key, TxMic and RxMic to Asic Pair-wise key table ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicAddPairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR WCID, ++ IN CIPHER_KEY *pCipherKey) ++{ ++ INT i; ++ ULONG offset; ++ PUCHAR pKey = pCipherKey->Key; ++ PUCHAR pTxMic = pCipherKey->TxMic; ++ PUCHAR pRxMic = pCipherKey->RxMic; ++#ifdef DBG ++ UCHAR CipherAlg = pCipherKey->CipherAlg; ++#endif // DBG // ++ ++ // EKEY ++ offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); ++#ifdef RT2870 ++ RTUSBMultiWrite(pAd, offset, &pCipherKey->Key[0], MAX_LEN_OF_PEER_KEY); ++#endif // RT2870 // ++ for (i=0; iTxMic[0], 8); ++#endif // RT2870 // ++ } ++ offset += 8; ++ if (pRxMic) ++ { ++#ifdef RT2870 ++ RTUSBMultiWrite(pAd, offset, &pCipherKey->RxMic[0], 8); ++#endif // RT2870 // ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicAddPairwiseKeyEntry: WCID #%d Alg=%s\n",WCID, CipherName[CipherAlg])); ++ DBGPRINT(RT_DEBUG_TRACE,(" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); ++ if (pRxMic) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ if (pTxMic) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ } ++} ++/* ++ ======================================================================== ++ Description: ++ Remove Pair-wise key material from ASIC. ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicRemovePairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR Wcid) ++{ ++ ULONG WCIDAttri; ++ USHORT offset; ++ ++ // re-set the entry's WCID attribute as OPEN-NONE. ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); ++ WCIDAttri = (BssIdx<<4) | PAIRWISEKEYTABLE; ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++} ++ ++BOOLEAN AsicSendCommandToMcu( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command, ++ IN UCHAR Token, ++ IN UCHAR Arg0, ++ IN UCHAR Arg1) ++{ ++ HOST_CMD_CSR_STRUC H2MCmd; ++ H2M_MAILBOX_STRUC H2MMailbox; ++ ULONG i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); ++ if (H2MMailbox.field.Owner == 0) ++ break; ++ ++ RTMPusecDelay(2); ++ } while(i++ < 100); ++ ++ if (i >= 100) ++ { ++ { ++ DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); ++ } ++ return FALSE; ++ } ++ ++ ++ H2MMailbox.field.Owner = 1; // pass ownership to MCU ++ H2MMailbox.field.CmdToken = Token; ++ H2MMailbox.field.HighByte = Arg1; ++ H2MMailbox.field.LowByte = Arg0; ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); ++ ++ H2MCmd.word = 0; ++ H2MCmd.field.HostCommand = Command; ++ RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); ++ ++ if (Command != 0x80) ++ { ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for different PHY type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPCheckRates( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT UCHAR SupRate[], ++ IN OUT UCHAR *SupRateLen) ++{ ++ UCHAR RateIdx, i, j; ++ UCHAR NewRate[12], NewRateLen; ++ ++ NewRateLen = 0; ++ ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ RateIdx = 4; ++ else ++ RateIdx = 12; ++ ++ // Check for support rates exclude basic rate bit ++ for (i = 0; i < *SupRateLen; i++) ++ for (j = 0; j < RateIdx; j++) ++ if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ NewRate[NewRateLen++] = SupRate[i]; ++ ++ *SupRateLen = NewRateLen; ++ NdisMoveMemory(SupRate, NewRate, NewRateLen); ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++BOOLEAN RTMPCheckChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR CentralChannel, ++ IN UCHAR Channel) ++{ ++ UCHAR k; ++ UCHAR UpperChannel = 0, LowerChannel = 0; ++ UCHAR NoEffectChannelinList = 0; ++ ++ // Find upper and lower channel according to 40MHz current operation. ++ if (CentralChannel < Channel) ++ { ++ UpperChannel = Channel; ++ if (CentralChannel > 2) ++ LowerChannel = CentralChannel - 2; ++ else ++ return FALSE; ++ } ++ else if (CentralChannel > Channel) ++ { ++ UpperChannel = CentralChannel + 2; ++ LowerChannel = Channel; ++ } ++ ++ for (k = 0;k < pAd->ChannelListNum;k++) ++ { ++ if (pAd->ChannelList[k].Channel == UpperChannel) ++ { ++ NoEffectChannelinList ++; ++ } ++ if (pAd->ChannelList[k].Channel == LowerChannel) ++ { ++ NoEffectChannelinList ++; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList)); ++ if (NoEffectChannelinList == 2) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for HT phy type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode) ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckHt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo) ++{ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ // If use AMSDU, set flag. ++ if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED); ++ // Save Peer Capability ++ if (pHtCapability->HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE); ++ if (pHtCapability->HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE); ++ if (pHtCapability->HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (pHtCapability->HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) ++ { ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE); ++ } ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity; ++ } ++ ++ // Will check ChannelWidth for MCSSet[4] below ++ pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1; ++ switch (pAd->CommonCfg.RxStream) ++ { ++ case 1: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ case 2: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ case 3: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ } ++ ++ pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n", ++ pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth, ++ pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode)); ++ ++ pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF; ++ ++ // Send Assoc Req with my HT capability. ++ pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize; ++ pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs; ++ pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20); ++ pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40); ++ pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC); ++ pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC); ++ pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor; ++ pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity; ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; ++ pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; ++ if (pAd->CommonCfg.bRdg) ++ { ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport; ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1; ++ } ++ ++ if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20) ++ pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32 ++ ++ COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for different PHY type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateMlmeRate( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR MinimumRate; ++ UCHAR ProperMlmeRate; //= RATE_54; ++ UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++ BOOLEAN bMatch = FALSE; ++ ++ switch (pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11B: ++ ProperMlmeRate = RATE_11; ++ MinimumRate = RATE_1; ++ break; ++ case PHY_11BG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++ case PHY_11BGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ if ((pAd->MlmeAux.SupRateLen == 4) && ++ (pAd->MlmeAux.ExtRateLen == 0)) ++ // B only AP ++ ProperMlmeRate = RATE_11; ++ else ++ ProperMlmeRate = RATE_24; ++ ++ if (pAd->MlmeAux.Channel <= 14) ++ MinimumRate = RATE_1; ++ else ++ MinimumRate = RATE_6; ++ break; ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n ++ case PHY_11GN_MIXED: ++ case PHY_11AGN_MIXED: ++ case PHY_11AN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ ProperMlmeRate = RATE_24; ++ MinimumRate = RATE_6; ++ break; ++ case PHY_11ABG_MIXED: ++ ProperMlmeRate = RATE_24; ++ if (pAd->MlmeAux.Channel <= 14) ++ MinimumRate = RATE_1; ++ else ++ MinimumRate = RATE_6; ++ break; ++ default: // error ++ ProperMlmeRate = RATE_1; ++ MinimumRate = RATE_1; ++ break; ++ } ++ ++ for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) ++ { ++ for (j = 0; j < RateIdx; j++) ++ { ++ if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ { ++ if (j == ProperMlmeRate) ++ { ++ bMatch = TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (bMatch) ++ break; ++ } ++ ++ if (bMatch == FALSE) ++ { ++ for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) ++ { ++ for (j = 0; j < RateIdx; j++) ++ { ++ if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ { ++ if (j == ProperMlmeRate) ++ { ++ bMatch = TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (bMatch) ++ break; ++ } ++ } ++ ++ if (bMatch == FALSE) ++ { ++ ProperMlmeRate = MinimumRate; ++ } ++ ++ pAd->CommonCfg.MlmeRate = MinimumRate; ++ pAd->CommonCfg.RtsRate = ProperMlmeRate; ++ if (pAd->CommonCfg.MlmeRate >= RATE_6) ++ { ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ else ++ { ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word)); ++} ++ ++CHAR RTMPMaxRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi0, ++ IN CHAR Rssi1, ++ IN CHAR Rssi2) ++{ ++ CHAR larger = -127; ++ ++ if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) ++ { ++ larger = Rssi0; ++ } ++ ++ if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) ++ { ++ larger = max(Rssi0, Rssi1); ++ } ++ ++ if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) ++ { ++ larger = max(larger, Rssi2); ++ } ++ ++ if (larger == -127) ++ larger = 0; ++ ++ return larger; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Periodic evaluate antenna link status ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID AsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BBPR3 = 0; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_NIC_NOT_EXIST | ++ fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return; ++ ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ { ++ ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt > 50) ++ { ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); ++ pAd->Mlme.bLowThroughput = FALSE; ++ } ++ else ++ { ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); ++ pAd->Mlme.bLowThroughput = TRUE; ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ After evaluation, check antenna link status ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID AsicRxAntEvalTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR BBPR3 = 0; ++ CHAR larger = -127, rssi0, rssi1, rssi2; ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ return; ++ ++ ++ // if the traffic is low, use average rssi as the criteria ++ if (pAd->Mlme.bLowThroughput == TRUE) ++ { ++ rssi0 = pAd->StaCfg.RssiSample.LastRssi0; ++ rssi1 = pAd->StaCfg.RssiSample.LastRssi1; ++ rssi2 = pAd->StaCfg.RssiSample.LastRssi2; ++ } ++ else ++ { ++ rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; ++ rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; ++ rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; ++ } ++ ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ larger = max(rssi0, rssi1); ++ ++ if (larger > (rssi2 + 20)) ++ pAd->Mlme.RealRxPath = 2; ++ else ++ pAd->Mlme.RealRxPath = 3; ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ if (rssi0 > (rssi1 + 20)) ++ pAd->Mlme.RealRxPath = 1; ++ else ++ pAd->Mlme.RealRxPath = 2; ++ } ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Mlme.RealRxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Mlme.RealRxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Mlme.RealRxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++ ++ ++VOID APSDPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ return; ++ ++ pAd->CommonCfg.TriggerTimerCount++; ++ ++// Driver should not send trigger frame, it should be send by application layer ++/* ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable ++ && (pAd->CommonCfg.bNeedSendTriggerFrame || ++ (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO)))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n")); ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; ++ pAd->CommonCfg.TriggerTimerCount = 0; ++ pAd->CommonCfg.bInServicePeriod = TRUE; ++ }*/ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Set/reset MAC registers according to bPiggyBack parameter ++ ++ Arguments: ++ pAd - Adapter pointer ++ bPiggyBack - Enable / Disable Piggy-Back ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID RTMPSetPiggyBack( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bPiggyBack) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ ++ TxLinkCfg.field.TxCFAckEn = bPiggyBack; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ check if this entry need to switch rate automatically ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry) ++{ ++ BOOLEAN result = TRUE; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // only associated STA counts ++ if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) ++ { ++ result = pAd->StaCfg.bAutoTxRateSwitch; ++ } ++ else ++ result = FALSE; ++ ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry && (pEntry->ValidAsDls)) ++ result = pAd->StaCfg.bAutoTxRateSwitch; ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ return result; ++} ++ ++ ++BOOLEAN RTMPAutoRateSwitchCheck( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.bAutoTxRateSwitch) ++ return TRUE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ return FALSE; ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ check if this entry need to fix tx legacy rate ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++UCHAR RTMPStaFixedTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry) ++{ ++ UCHAR tx_mode = FIXED_TXMODE_HT; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return tx_mode; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified. ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateLegacyTxSetting( ++ UCHAR fixed_tx_mode, ++ PMAC_TABLE_ENTRY pEntry) ++{ ++ HTTRANSMIT_SETTING TransmitSetting; ++ ++ if (fixed_tx_mode == FIXED_TXMODE_HT) ++ return; ++ ++ TransmitSetting.word = 0; ++ ++ TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE; ++ TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS; ++ ++ if (fixed_tx_mode == FIXED_TXMODE_CCK) ++ { ++ TransmitSetting.field.MODE = MODE_CCK; ++ // CCK mode allow MCS 0~3 ++ if (TransmitSetting.field.MCS > MCS_3) ++ TransmitSetting.field.MCS = MCS_3; ++ } ++ else ++ { ++ TransmitSetting.field.MODE = MODE_OFDM; ++ // OFDM mode allow MCS 0~7 ++ if (TransmitSetting.field.MCS > MCS_7) ++ TransmitSetting.field.MCS = MCS_7; ++ } ++ ++ if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) ++ { ++ pEntry->HTPhyMode.word = TransmitSetting.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n", ++ pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS)); ++ } ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ dynamic tune BBP R66 to find a balance between sensibility and ++ noise isolation ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicStaBbpTuning( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30; ++ CHAR Rssi; ++ ++ // 2860C did not support Fase CCA, therefore can't tune ++ if (pAd->MACVersion == 0x28600100) ++ return; ++ ++ // ++ // work as a STA ++ // ++ if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING ++ return; ++ ++ if ((pAd->OpMode == OPMODE_STA) ++ && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ ) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); ++ R66 = OrigR66Value; ++ ++ if (pAd->Antenna.field.RxPath > 1) ++ Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; ++ else ++ Rssi = pAd->StaCfg.RssiSample.AvgRssi0; ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { //BG band ++#ifdef RT2870 ++ // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control ++ // Otherwise, it will have some throughput side effect when low RSSI ++ if (IS_RT3070(pAd)) ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; ++ if (OrigR66Value != R66) ++ { ++ RTUSBWriteBBPRegister(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x1C + 2*GET_LNA_GAIN(pAd); ++ if (OrigR66Value != R66) ++ { ++ RTUSBWriteBBPRegister(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ else ++#endif // RT2870 // ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ } ++ else ++ { //A band ++ if (pAd->CommonCfg.BBPCurrentBW == BW_20) ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ else ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ } ++ ++ ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RTMPSetAGCInitValue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BandWidth) ++{ ++ UCHAR R66 = 0x30; ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { // BG band ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { //A band ++ if (BandWidth == BW_20) ++ { ++ R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ { ++ R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++} ++ ++VOID AsicTurnOffRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ ++ // RF R2 bit 18 = 0 ++ UINT32 R1 = 0, R2 = 0, R3 = 0; ++ UCHAR index; ++ RTMP_RF_REGS *RFRegTable; ++ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R1 = RFRegTable[index].R1 & 0xffffdfff; ++ R2 = RFRegTable[index].R2 & 0xfffbffff; ++ R3 = RFRegTable[index].R3 & 0xfff3ffff; ++ ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ ++ // Program R1b13 to 1, R3/b18,19 to 0, R2b18 to 0. ++ // Set RF R2 bit18=0, R3 bit[18:19]=0 ++ //if (pAd->StaCfg.bRadio == FALSE) ++ if (1) ++ { ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x, R3 = 0x%08x \n", ++ Channel, pAd->RfIcType, R2, R3)); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x \n", ++ Channel, pAd->RfIcType, R2)); ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++ ++VOID AsicTurnOnRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ ++ // RF R2 bit 18 = 0 ++ UINT32 R1 = 0, R2 = 0, R3 = 0; ++ UCHAR index; ++ RTMP_RF_REGS *RFRegTable; ++ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R3 = pAd->LatchRfRegs.R3; ++ R3 &= 0xfff3ffff; ++ R3 |= 0x00080000; ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ ++ R1 = RFRegTable[index].R1; ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ R2 |= 0x40; // write 1 to off Rxpath. ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOnRFClk#%d(RF=%d, ) , R2=0x%08x\n", ++ Channel, ++ pAd->RfIcType, ++ R2)); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/netif_block.c +@@ -0,0 +1,144 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "../rt_config.h" ++#include "netif_block.h" ++ ++static NETIF_ENTRY freeNetIfEntryPool[FREE_NETIF_POOL_SIZE]; ++static LIST_HEADER freeNetIfEntryList; ++ ++void initblockQueueTab( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ ++ initList(&freeNetIfEntryList); ++ for (i = 0; i < FREE_NETIF_POOL_SIZE; i++) ++ insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)&freeNetIfEntryPool[i]); ++ ++ for (i=0; i < NUM_OF_TX_RING; i++) ++ initList(&pAd->blockQueueTab[i].NetIfList); ++ ++ return; ++} ++ ++BOOLEAN blockNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, ++ IN PNET_DEV pNetDev) ++{ ++ PNETIF_ENTRY pNetIfEntry = NULL; ++ ++ if ((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(&freeNetIfEntryList)) != NULL) ++ { ++ netif_stop_queue(pNetDev); ++ pNetIfEntry->pNetDev = pNetDev; ++ insertTailList(&pBlockQueueEntry->NetIfList, (PLIST_ENTRY)pNetIfEntry); ++ ++ pBlockQueueEntry->SwTxQueueBlockFlag = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("netif_stop_queue(%s)\n", pNetDev->name)); ++ } ++ else ++ return FALSE; ++ ++ return TRUE; ++} ++ ++VOID releaseNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry) ++{ ++ PNETIF_ENTRY pNetIfEntry = NULL; ++ PLIST_HEADER pNetIfList = &pBlockQueueEntry->NetIfList; ++ ++ while((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(pNetIfList)) != NULL) ++ { ++ PNET_DEV pNetDev = pNetIfEntry->pNetDev; ++ netif_wake_queue(pNetDev); ++ insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)pNetIfEntry); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("netif_wake_queue(%s)\n", pNetDev->name)); ++ } ++ pBlockQueueEntry->SwTxQueueBlockFlag = FALSE; ++ return; ++} ++ ++ ++VOID StopNetIfQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PNET_DEV NetDev = NULL; ++ UCHAR IfIdx = 0; ++ BOOLEAN valid = FALSE; ++ ++#ifdef APCLI_SUPPORT ++ if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_APCLI) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_APCLI) % MAX_APCLI_NUM; ++ NetDev = pAd->ApCfg.ApCliTab[IfIdx].dev; ++ } ++ else ++#endif // APCLI_SUPPORT // ++#ifdef WDS_SUPPORT ++ if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_WDS) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_WDS) % MAX_WDS_ENTRY; ++ NetDev = pAd->WdsTab.WdsEntry[IfIdx].dev; ++ } ++ else ++#endif // WDS_SUPPORT // ++ { ++#ifdef MBSS_SUPPORT ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_MBSSID) % MAX_MBSSID_NUM; ++ NetDev = pAd->ApCfg.MBSSID[IfIdx].MSSIDDev; ++ } ++ else ++ { ++ IfIdx = MAIN_MBSSID; ++ NetDev = pAd->net_dev; ++ } ++#else ++ IfIdx = MAIN_MBSSID; ++ NetDev = pAd->net_dev; ++#endif ++ } ++ ++ // WMM support 4 software queues. ++ // One software queue full doesn't mean device have no capbility to transmit packet. ++ // So disable block Net-If queue function while WMM enable. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ valid = (pAd->CommonCfg.bWmmCapable == TRUE) ? FALSE : TRUE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (valid) ++ blockNetIf(&pAd->blockQueueTab[QueIdx], NetDev); ++ return; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/rtmp_init.c +@@ -0,0 +1,4132 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_init.c ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme ++ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. ++*/ ++#include "../rt_config.h" ++#include "firmware.h" ++ ++//#define BIN_IN_FILE /* use *.bin firmware */ ++ ++UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; ++ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, ++ 0x00000010, 0x00000020, 0x00000040, 0x00000080, ++ 0x00000100, 0x00000200, 0x00000400, 0x00000800, ++ 0x00001000, 0x00002000, 0x00004000, 0x00008000, ++ 0x00010000, 0x00020000, 0x00040000, 0x00080000, ++ 0x00100000, 0x00200000, 0x00400000, 0x00800000, ++ 0x01000000, 0x02000000, 0x04000000, 0x08000000, ++ 0x10000000, 0x20000000, 0x40000000, 0x80000000}; ++ ++char* CipherName[] = {"none","wep64","wep128","TKIP","AES","CKIP64","CKIP128"}; ++ ++const unsigned short ccitt_16Table[] = { ++ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, ++ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, ++ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, ++ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, ++ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, ++ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, ++ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, ++ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, ++ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, ++ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, ++ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, ++ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, ++ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, ++ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, ++ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, ++ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, ++ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, ++ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, ++ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, ++ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, ++ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, ++ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, ++ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, ++ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, ++ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, ++ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, ++ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, ++ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, ++ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, ++ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, ++ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, ++ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 ++}; ++#define ByteCRC16(v, crc) \ ++ (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) ++ ++unsigned char BitReverse(unsigned char x) ++{ ++ int i; ++ unsigned char Temp=0; ++ for(i=0; ; i++) ++ { ++ if(x & 0x80) Temp |= 0x80; ++ if(i==7) break; ++ x <<= 1; ++ Temp >>= 1; ++ } ++ return Temp; ++} ++ ++// ++// BBP register initialization set ++// ++REG_PAIR BBPRegTable[] = { ++ {BBP_R65, 0x2C}, // fix rssi issue ++ {BBP_R66, 0x38}, // Also set this default value to pAd->BbpTuning.R66CurrentValue at initial ++ {BBP_R69, 0x12}, ++ {BBP_R70, 0xa}, // BBP_R70 will change to 0x8 in ApStartUp and LinkUp for rt2860C, otherwise value is 0xa ++ {BBP_R73, 0x10}, ++ {BBP_R81, 0x37}, ++ {BBP_R82, 0x62}, ++ {BBP_R83, 0x6A}, ++ {BBP_R84, 0x99}, // 0x19 is for rt2860E and after. This is for extension channel overlapping IOT. 0x99 is for rt2860D and before ++ {BBP_R86, 0x00}, // middle range issue, Rory @2008-01-28 ++ {BBP_R91, 0x04}, // middle range issue, Rory @2008-01-28 ++ {BBP_R92, 0x00}, // middle range issue, Rory @2008-01-28 ++ {BBP_R103, 0x00}, // near range high-power issue, requested from Gary @2008-0528 ++ {BBP_R105, 0x05}, // 0x05 is for rt2860E to turn on FEQ control. It is safe for rt2860D and before, because Bit 7:2 are reserved in rt2860D and before. ++}; ++#define NUM_BBP_REG_PARMS (sizeof(BBPRegTable) / sizeof(REG_PAIR)) ++ ++// ++// RF register initialization set ++// ++#ifdef RT2870 ++REG_PAIR RT30xx_RFRegTable[] = { ++ {RF_R04, 0x40}, ++ {RF_R05, 0x03}, ++ {RF_R06, 0x02}, ++ {RF_R07, 0x70}, ++ {RF_R09, 0x0F}, ++ {RF_R10, 0x71}, ++ {RF_R11, 0x21}, ++ {RF_R12, 0x7B}, ++ {RF_R14, 0x90}, ++ {RF_R15, 0x58}, ++ {RF_R16, 0xB3}, ++ {RF_R17, 0x92}, ++ {RF_R18, 0x2C}, ++ {RF_R19, 0x02}, ++ {RF_R20, 0xBA}, ++ {RF_R21, 0xDB}, ++ {RF_R24, 0x16}, ++ {RF_R25, 0x01}, ++ {RF_R27, 0x03}, ++ {RF_R29, 0x1F}, ++}; ++#define NUM_RF_REG_PARMS (sizeof(RT30xx_RFRegTable) / sizeof(REG_PAIR)) ++#endif // RT2870 // ++ ++// ++// ASIC register initialization sets ++// ++ ++RTMP_REG_PAIR MACRegTable[] = { ++#if defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x200) ++ {BCN_OFFSET0, 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ ++ {BCN_OFFSET1, 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ ++#elif defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x100) ++ {BCN_OFFSET0, 0xece8e4e0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ ++ {BCN_OFFSET1, 0xfcf8f4f0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ ++#else ++ #error You must re-calculate new value for BCN_OFFSET0 & BCN_OFFSET1 in MACRegTable[]!!! ++#endif // HW_BEACON_OFFSET // ++ ++ {LEGACY_BASIC_RATE, 0x0000013f}, // Basic rate set bitmap ++ {HT_BASIC_RATE, 0x00008003}, // Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI. ++ {MAC_SYS_CTRL, 0x00}, // 0x1004, , default Disable RX ++ {RX_FILTR_CFG, 0x17f97}, //0x1400 , RX filter control, ++ {BKOFF_SLOT_CFG, 0x209}, // default set short slot time, CC_DELAY_TIME should be 2 ++ {TX_SW_CFG0, 0x0}, // Gary,2008-05-21 for CWC test ++ {TX_SW_CFG1, 0x80606}, // Gary,2006-08-23 ++ {TX_LINK_CFG, 0x1020}, // Gary,2006-08-23 ++ //{TX_TIMEOUT_CFG, 0x00182090}, // CCK has some problem. So increase timieout value. 2006-10-09// MArvek RT ++ {TX_TIMEOUT_CFG, 0x000a2090}, // CCK has some problem. So increase timieout value. 2006-10-09// MArvek RT , Modify for 2860E ,2007-08-01 ++ {MAX_LEN_CFG, MAX_AGGREGATION_SIZE | 0x00001000}, // 0x3018, MAX frame length. Max PSDU = 16kbytes. ++ {LED_CFG, 0x7f031e46}, // Gary, 2006-08-23 ++ {PBF_MAX_PCNT, 0x1F3FBF9F}, //0x1F3f7f9f}, //Jan, 2006/04/20 ++ //{TX_RTY_CFG, 0x6bb80408}, // Jan, 2006/11/16 ++ {TX_RTY_CFG, 0x47d01f0f}, // Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03 ++ {AUTO_RSP_CFG, 0x00000013}, // Initial Auto_Responder, because QA will turn off Auto-Responder ++ {CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. ++ {OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. ++#ifdef RT2870 ++ {PBF_CFG, 0xf40006}, // Only enable Queue 2 ++ {MM40_PROT_CFG, 0x3F44084}, // Initial Auto_Responder, because QA will turn off Auto-Responder ++ {WPDMA_GLO_CFG, 0x00000030}, ++#endif // RT2870 // ++ {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS ++ {GF40_PROT_CFG, 0x03F44084}, ++ {MM20_PROT_CFG, 0x01744004}, ++ {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. ++ {TX_RTS_CFG, 0x00092b20}, ++//#ifdef WIFI_TEST ++ {EXP_ACK_TIME, 0x002400ca}, // default value ++//#else ++// {EXP_ACK_TIME, 0x005400ca}, // suggested by Gray @ 20070323 for 11n intel-sta throughput ++//#endif // end - WIFI_TEST // ++ {TXOP_HLDR_ET, 0x00000002}, ++ ++ /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us ++ is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0 ++ and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping ++ will always lost. So we change the SIFS of CCK from 10us to 16us. */ ++ {XIFS_TIME_CFG, 0x33a41010}, ++ {PWR_PIN_CFG, 0x00000003}, // patch for 2880-E ++}; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++RTMP_REG_PAIR STAMACRegTable[] = { ++ {WMM_AIFSN_CFG, 0x00002273}, ++ {WMM_CWMIN_CFG, 0x00002344}, ++ {WMM_CWMAX_CFG, 0x000034aa}, ++}; ++#endif // CONFIG_STA_SUPPORT // ++ ++#define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) ++#ifdef CONFIG_STA_SUPPORT ++#define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RT2870 ++// ++// RT2870 Firmware Spec only used 1 oct for version expression ++// ++#define FIRMWARE_MINOR_VERSION 7 ++ ++#endif // RT2870 // ++ ++// New 8k byte firmware size for RT3071/RT3072 ++#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 ++#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) ++#define FIRMWARE_MAJOR_VERSION 0 ++ ++#define FIRMWAREIMAGEV1_LENGTH 0x1000 ++#define FIRMWAREIMAGEV2_LENGTH 0x1000 ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Allocate RTMP_ADAPTER data block and do some initialization ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPAllocAdapterBlock( ++ IN PVOID handle, ++ OUT PRTMP_ADAPTER *ppAdapter) ++{ ++ PRTMP_ADAPTER pAd; ++ NDIS_STATUS Status; ++ INT index; ++ UCHAR *pBeaconBuf = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocAdapterBlock\n")); ++ ++ *ppAdapter = NULL; ++ ++ do ++ { ++ // Allocate RTMP_ADAPTER memory block ++ pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG); ++ if (pBeaconBuf == NULL) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n")); ++ break; ++ } ++ ++ Status = AdapterBlockAllocateMemory(handle, (PVOID *)&pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n")); ++ break; ++ } ++ pAd->BeaconBuf = pBeaconBuf; ++ printk("\n\n=== pAd = %p, size = %d ===\n\n", pAd, (UINT32)sizeof(RTMP_ADAPTER)); ++ ++ ++ // Init spin locks ++ NdisAllocateSpinLock(&pAd->MgmtRingLock); ++ ++ for (index =0 ; index < NUM_OF_TX_RING; index++) ++ { ++ NdisAllocateSpinLock(&pAd->TxSwQueueLock[index]); ++ NdisAllocateSpinLock(&pAd->DeQueueLock[index]); ++ pAd->DeQueueRunning[index] = FALSE; ++ } ++ ++ NdisAllocateSpinLock(&pAd->irq_lock); ++ ++ } while (FALSE); ++ ++ if ((Status != NDIS_STATUS_SUCCESS) && (pBeaconBuf)) ++ kfree(pBeaconBuf); ++ ++ *ppAdapter = pAd; ++ ++ DBGPRINT_S(Status, ("<-- RTMPAllocAdapterBlock, Status=%x\n", Status)); ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial Tx power per MCS and BW from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReadTxPwrPerRate( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG data, Adata, Gdata; ++ USHORT i, value, value2; ++ INT Apwrdelta, Gpwrdelta; ++ UCHAR t1,t2,t3,t4; ++ BOOLEAN bValid, bApwrdeltaMinus = TRUE, bGpwrdeltaMinus = TRUE; ++ ++ // ++ // Get power delta for 20MHz and 40MHz. ++ // ++ DBGPRINT(RT_DEBUG_TRACE, ("Txpower per Rate\n")); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_DELTA, value2); ++ Apwrdelta = 0; ++ Gpwrdelta = 0; ++ ++ if ((value2 & 0xff) != 0xff) ++ { ++ if ((value2 & 0x80)) ++ Gpwrdelta = (value2&0xf); ++ ++ if ((value2 & 0x40)) ++ bGpwrdeltaMinus = FALSE; ++ else ++ bGpwrdeltaMinus = TRUE; ++ } ++ if ((value2 & 0xff00) != 0xff00) ++ { ++ if ((value2 & 0x8000)) ++ Apwrdelta = ((value2&0xf00)>>8); ++ ++ if ((value2 & 0x4000)) ++ bApwrdeltaMinus = FALSE; ++ else ++ bApwrdeltaMinus = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Gpwrdelta = %x, Apwrdelta = %x .\n", Gpwrdelta, Apwrdelta)); ++ ++ // ++ // Get Txpower per MCS for 20MHz in 2.4G. ++ // ++ for (i=0; i<5; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4, value); ++ data = value; ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ data |= (value<<16); ++ ++ pAd->Tx20MPwrCfgABand[i] = pAd->Tx40MPwrCfgABand[i] = Adata; ++ pAd->Tx20MPwrCfgGBand[i] = pAd->Tx40MPwrCfgGBand[i] = Gdata; ++ ++ if (data != 0xffffffff) ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, data); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 2.4G band-%lx, Adata = %lx, Gdata = %lx \n", data, Adata, Gdata)); ++ } ++ ++ // ++ // Check this block is valid for 40MHz in 2.4G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 40MHz in 2.4G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4, value); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4 + 2, value); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx40MPwrCfgGBand[i+1] = (pAd->Tx40MPwrCfgGBand[i+1] & 0x0000FFFF) | (Gdata & 0xFFFF0000); ++ else ++ pAd->Tx40MPwrCfgGBand[i+1] = Gdata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 2.4G band, Gdata = %lx \n", Gdata)); ++ } ++ } ++ ++ // ++ // Check this block is valid for 20MHz in 5G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 20MHz in 5G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<5; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx20MPwrCfgABand[i] = (pAd->Tx20MPwrCfgABand[i] & 0x0000FFFF) | (Adata & 0xFFFF0000); ++ else ++ pAd->Tx20MPwrCfgABand[i] = Adata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 5GHz band, Adata = %lx \n", Adata)); ++ } ++ } ++ ++ // ++ // Check this block is valid for 40MHz in 5G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 40MHz in 5G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx40MPwrCfgABand[i+1] = (pAd->Tx40MPwrCfgABand[i+1] & 0x0000FFFF) | (Adata & 0xFFFF0000); ++ else ++ pAd->Tx40MPwrCfgABand[i+1] = Adata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 5GHz band, Adata = %lx \n", Adata)); ++ } ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial channel power parameters from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReadChannelPwr( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i, choffset; ++ EEPROM_TX_PWR_STRUC Power; ++ EEPROM_TX_PWR_STRUC Power2; ++ ++ // Read Tx power value for all channels ++ // Value from 1 - 0x7f. Default value is 24. ++ // Power value : 2.4G 0x00 (0) ~ 0x1F (31) ++ // : 5.5G 0xF9 (-7) ~ 0x0F (15) ++ ++ // 0. 11b/g, ch1 - ch 14 ++ for (i = 0; i < 7; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2, Power2.word); ++ pAd->TxPower[i * 2].Channel = i * 2 + 1; ++ pAd->TxPower[i * 2 + 1].Channel = i * 2 + 2; ++ ++ if ((Power.field.Byte0 > 31) || (Power.field.Byte0 < 0)) ++ pAd->TxPower[i * 2].Power = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 > 31) || (Power.field.Byte1 < 0)) ++ pAd->TxPower[i * 2 + 1].Power = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2 + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 > 31) || (Power2.field.Byte0 < 0)) ++ pAd->TxPower[i * 2].Power2 = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 > 31) || (Power2.field.Byte1 < 0)) ++ pAd->TxPower[i * 2 + 1].Power2 = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2 + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 1. U-NII lower/middle band: 36, 38, 40; 44, 46, 48; 52, 54, 56; 60, 62, 64 (including central frequency in BW 40MHz) ++ // 1.1 Fill up channel ++ choffset = 14; ++ for (i = 0; i < 4; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 36 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 36 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 36 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ ++ // 1.2 Fill up power ++ for (i = 0; i < 6; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 2. HipperLAN 2 100, 102 ,104; 108, 110, 112; 116, 118, 120; 124, 126, 128; 132, 134, 136; 140 (including central frequency in BW 40MHz) ++ // 2.1 Fill up channel ++ choffset = 14 + 12; ++ for (i = 0; i < 5; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 100 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 100 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 100 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ pAd->TxPower[3 * 5 + choffset + 0].Channel = 140; ++ pAd->TxPower[3 * 5 + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * 5 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ // 2.2 Fill up power ++ for (i = 0; i < 8; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 3. U-NII upper band: 149, 151, 153; 157, 159, 161; 165 (including central frequency in BW 40MHz) ++ // 3.1 Fill up channel ++ choffset = 14 + 12 + 16; ++ for (i = 0; i < 2; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 149 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 149 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 149 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ pAd->TxPower[3 * 2 + choffset + 0].Channel = 165; ++ pAd->TxPower[3 * 2 + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * 2 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ // 3.2 Fill up power ++ for (i = 0; i < 4; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 4. Print and Debug ++ choffset = 14 + 12 + 16 + 7; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read the following from the registry ++ 1. All the parameters ++ 2. NetworkAddres ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ WrapperConfigurationContext For use by NdisOpenConfiguration ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICReadRegParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status)); ++ return Status; ++} ++ ++ ++#ifdef RT2870 ++/* ++ ======================================================================== ++ ++ Routine Description: ++ For RF filter calibration purpose ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTUSBFilterCalibration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR R55x = 0, value, FilterTarget = 0x1E, BBPValue; ++ UINT loop = 0, count = 0, loopcnt = 0, ReTry = 0; ++ UCHAR RF_R24_Value = 0; ++ ++ // Give bbp filter initial value ++ pAd->Mlme.CaliBW20RfR24 = 0x16; ++ pAd->Mlme.CaliBW40RfR24 = 0x36; //Bit[5] must be 1 for BW 40 ++ ++ do ++ { ++ if (loop == 1) //BandWidth = 40 MHz ++ { ++ // Write 0x27 to RF_R24 to program filter ++ RF_R24_Value = 0x27; ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ FilterTarget = 0x19; ++ ++ // when calibrate BW40, BBP mask must set to BW40. ++ RTUSBReadBBPRegister(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTUSBWriteBBPRegister(pAd, BBP_R4, BBPValue); ++ } ++ else //BandWidth = 20 MHz ++ { ++ // Write 0x07 to RF_R24 to program filter ++ RF_R24_Value = 0x07; ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ FilterTarget = 0x16; ++ } ++ ++ // Write 0x01 to RF_R22 to enable baseband loopback mode ++ RT30xxReadRFRegister(pAd, RF_R22, &value); ++ value |= 0x01; ++ RT30xxWriteRFRegister(pAd, RF_R22, value); ++ ++ // Write 0x00 to BBP_R24 to set power & frequency of passband test tone ++ RTUSBWriteBBPRegister(pAd, BBP_R24, 0); ++ ++ do ++ { ++ // Write 0x90 to BBP_R25 to transmit test tone ++ RTUSBWriteBBPRegister(pAd, BBP_R25, 0x90); ++ ++ RTMPusecDelay(1000); ++ // Read BBP_R55[6:0] for received power, set R55x = BBP_R55[6:0] ++ RTUSBReadBBPRegister(pAd, BBP_R55, &value); ++ R55x = value & 0xFF; ++ ++ } while ((ReTry++ < 100) && (R55x == 0)); ++ ++ // Write 0x06 to BBP_R24 to set power & frequency of stopband test tone ++ RTUSBWriteBBPRegister(pAd, BBP_R24, 0x06); ++ ++ while(TRUE) ++ { ++ // Write 0x90 to BBP_R25 to transmit test tone ++ RTUSBWriteBBPRegister(pAd, BBP_R25, 0x90); ++ ++ //We need to wait for calibration ++ RTMPusecDelay(1000); ++ RTUSBReadBBPRegister(pAd, BBP_R55, &value); ++ value &= 0xFF; ++ if ((R55x - value) < FilterTarget) ++ { ++ RF_R24_Value ++; ++ } ++ else if ((R55x - value) == FilterTarget) ++ { ++ RF_R24_Value ++; ++ count ++; ++ } ++ else ++ { ++ break; ++ } ++ ++ // prevent infinite loop cause driver hang. ++ if (loopcnt++ > 100) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", loopcnt)); ++ break; ++ } ++ ++ // Write RF_R24 to program filter ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ } ++ ++ if (count > 0) ++ { ++ RF_R24_Value = RF_R24_Value - ((count) ? (1) : (0)); ++ } ++ ++ // Store for future usage ++ if (loopcnt < 100) ++ { ++ if (loop++ == 0) ++ { ++ //BandWidth = 20 MHz ++ pAd->Mlme.CaliBW20RfR24 = (UCHAR)RF_R24_Value; ++ } ++ else ++ { ++ //BandWidth = 40 MHz ++ pAd->Mlme.CaliBW40RfR24 = (UCHAR)RF_R24_Value; ++ break; ++ } ++ } ++ else ++ break; ++ ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ ++ // reset count ++ count = 0; ++ } while(TRUE); ++ ++ // ++ // Set back to initial state ++ // ++ RTUSBWriteBBPRegister(pAd, BBP_R24, 0); ++ ++ RT30xxReadRFRegister(pAd, RF_R22, &value); ++ value &= ~(0x01); ++ RT30xxWriteRFRegister(pAd, RF_R22, value); ++ ++ // set BBP back to BW20 ++ RTUSBReadBBPRegister(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ RTUSBWriteBBPRegister(pAd, BBP_R4, BBPValue); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTUSBFilterCalibration - CaliBW20RfR24=0x%x, CaliBW40RfR24=0x%x\n", pAd->Mlme.CaliBW20RfR24, pAd->Mlme.CaliBW40RfR24)); ++} ++ ++ ++VOID NICInitRT30xxRFRegisters(IN PRTMP_ADAPTER pAd) ++{ ++ INT i; ++ // Driver must read EEPROM to get RfIcType before initial RF registers ++ // Initialize RF register to default value ++ if (IS_RT3070(pAd) && ((pAd->RfIcType == RFIC_3020) ||(pAd->RfIcType == RFIC_2020))) ++ { ++ // Init RF calibration ++ // Driver should toggle RF R30 bit7 before init RF registers ++ ULONG RfReg = 0; ++ RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg); ++ RfReg |= 0x80; ++ RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); ++ RTMPusecDelay(1000); ++ RfReg &= 0x7F; ++ RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); ++ ++ // Initialize RF register to default value ++ for (i = 0; i < NUM_RF_REG_PARMS; i++) ++ { ++ RT30xxWriteRFRegister(pAd, RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value); ++ } ++ ++ //For RF filter Calibration ++ RTUSBFilterCalibration(pAd); ++ } ++ ++} ++#endif // RT2870 // ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial parameters from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NICReadEEPROMParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mac_addr) ++{ ++ UINT32 data = 0; ++ USHORT i, value, value2; ++ UCHAR TmpPhy; ++ EEPROM_TX_PWR_STRUC Power; ++ EEPROM_VERSION_STRUC Version; ++ EEPROM_ANTENNA_STRUC Antenna; ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICReadEEPROMParameters\n")); ++ ++ // Init EEPROM Address Number, before access EEPROM; if 93c46, EEPROMAddressNum=6, else if 93c66, EEPROMAddressNum=8 ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &data); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> E2PROM_CSR = 0x%x\n", data)); ++ ++ if((data & 0x30) == 0) ++ pAd->EEPROMAddressNum = 6; // 93C46 ++ else if((data & 0x30) == 0x10) ++ pAd->EEPROMAddressNum = 8; // 93C66 ++ else ++ pAd->EEPROMAddressNum = 8; // 93C86 ++ DBGPRINT(RT_DEBUG_TRACE, ("--> EEPROMAddressNum = %d\n", pAd->EEPROMAddressNum )); ++ ++ // RT2860 MAC no longer auto load MAC address from E2PROM. Driver has to intialize ++ // MAC address registers according to E2PROM setting ++ if (mac_addr == NULL || ++ strlen(mac_addr) != 17 || ++ mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' || ++ mac_addr[11] != ':' || mac_addr[14] != ':') ++ { ++ USHORT Addr01,Addr23,Addr45 ; ++ ++ RT28xx_EEPROM_READ16(pAd, 0x04, Addr01); ++ RT28xx_EEPROM_READ16(pAd, 0x06, Addr23); ++ RT28xx_EEPROM_READ16(pAd, 0x08, Addr45); ++ ++ pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); ++ pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); ++ pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); ++ pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); ++ pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); ++ pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from E2PROM \n")); ++ } ++ else ++ { ++ INT j; ++ PUCHAR macptr; ++ ++ macptr = mac_addr; ++ ++ for (j=0; jPermanentAddress[j], 1); ++ macptr=macptr+3; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from module parameter \n")); ++ } ++ ++ ++ { ++#if 0 ++ USHORT Addr01,Addr23,Addr45 ; ++ ++ Addr01=RTMP_EEPROM_READ16(pAd, 0x04); ++ Addr23=RTMP_EEPROM_READ16(pAd, 0x06); ++ Addr45=RTMP_EEPROM_READ16(pAd, 0x08); ++ ++ pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); ++ pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); ++ pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); ++ pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); ++ pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); ++ pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); ++#endif ++ //more conveninet to test mbssid, so ap's bssid &0xf1 ++ if (pAd->PermanentAddress[0] == 0xff) ++ pAd->PermanentAddress[0] = RandomByte(pAd)&0xf8; ++ ++ //if (pAd->PermanentAddress[5] == 0xff) ++ // pAd->PermanentAddress[5] = RandomByte(pAd)&0xf8; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->PermanentAddress[0], pAd->PermanentAddress[1], ++ pAd->PermanentAddress[2], pAd->PermanentAddress[3], ++ pAd->PermanentAddress[4], pAd->PermanentAddress[5])); ++ if (pAd->bLocalAdminMAC == FALSE) ++ { ++ MAC_DW0_STRUC csr2; ++ MAC_DW1_STRUC csr3; ++ COPY_MAC_ADDR(pAd->CurrentAddress, pAd->PermanentAddress); ++ csr2.field.Byte0 = pAd->CurrentAddress[0]; ++ csr2.field.Byte1 = pAd->CurrentAddress[1]; ++ csr2.field.Byte2 = pAd->CurrentAddress[2]; ++ csr2.field.Byte3 = pAd->CurrentAddress[3]; ++ RTMP_IO_WRITE32(pAd, MAC_ADDR_DW0, csr2.word); ++ csr3.word = 0; ++ csr3.field.Byte4 = pAd->CurrentAddress[4]; ++ csr3.field.Byte5 = pAd->CurrentAddress[5]; ++ csr3.field.U2MeMask = 0xff; ++ RTMP_IO_WRITE32(pAd, MAC_ADDR_DW1, csr3.word); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->PermanentAddress[0], pAd->PermanentAddress[1], ++ pAd->PermanentAddress[2], pAd->PermanentAddress[3], ++ pAd->PermanentAddress[4], pAd->PermanentAddress[5])); ++ } ++ } ++ ++ // if not return early. cause fail at emulation. ++ // Init the channel number for TX channel power ++ RTMPReadChannelPwr(pAd); ++ ++ // if E2PROM version mismatch with driver's expectation, then skip ++ // all subsequent E2RPOM retieval and set a system error bit to notify GUI ++ RT28xx_EEPROM_READ16(pAd, EEPROM_VERSION_OFFSET, Version.word); ++ pAd->EepromVersion = Version.field.Version + Version.field.FaeReleaseNumber * 256; ++ DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: Version = %d, FAE release #%d\n", Version.field.Version, Version.field.FaeReleaseNumber)); ++ ++ if (Version.field.Version > VALID_EEPROM_VERSION) ++ { ++ DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n",Version.field.Version, VALID_EEPROM_VERSION)); ++ /*pAd->SystemErrorBitmap |= 0x00000001; ++ ++ // hard-code default value when no proper E2PROM installed ++ pAd->bAutoTxAgcA = FALSE; ++ pAd->bAutoTxAgcG = FALSE; ++ ++ // Default the channel power ++ for (i = 0; i < MAX_NUM_OF_CHANNELS; i++) ++ pAd->TxPower[i].Power = DEFAULT_RF_TX_POWER; ++ ++ // Default the channel power ++ for (i = 0; i < MAX_NUM_OF_11JCHANNELS; i++) ++ pAd->TxPower11J[i].Power = DEFAULT_RF_TX_POWER; ++ ++ for(i = 0; i < NUM_EEPROM_BBP_PARMS; i++) ++ pAd->EEPROMDefaultValue[i] = 0xffff; ++ return; */ ++ } ++ ++ // Read BBP default value from EEPROM and store to array(EEPROMDefaultValue) in pAd ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, value); ++ pAd->EEPROMDefaultValue[0] = value; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC2_OFFSET, value); ++ pAd->EEPROMDefaultValue[1] = value; ++ ++ RT28xx_EEPROM_READ16(pAd, 0x38, value); // Country Region ++ pAd->EEPROMDefaultValue[2] = value; ++ ++ for(i = 0; i < 8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_BBP_BASE_OFFSET + i*2, value); ++ pAd->EEPROMDefaultValue[i+3] = value; ++ } ++ ++ // We have to parse NIC configuration 0 at here. ++ // If TSSI did not have preloaded value, it should reset the TxAutoAgc to false ++ // Therefore, we have to read TxAutoAgc control beforehand. ++ // Read Tx AGC control bit ++ Antenna.word = pAd->EEPROMDefaultValue[0]; ++ if (Antenna.word == 0xFFFF) ++ { ++ Antenna.word = 0; ++ Antenna.field.RfIcType = RFIC_2820; ++ Antenna.field.TxPath = 1; ++ Antenna.field.RxPath = 2; ++ DBGPRINT(RT_DEBUG_WARN, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); ++ } ++ ++ // Choose the desired Tx&Rx stream. ++ if ((pAd->CommonCfg.TxStream == 0) || (pAd->CommonCfg.TxStream > Antenna.field.TxPath)) ++ pAd->CommonCfg.TxStream = Antenna.field.TxPath; ++ ++ if ((pAd->CommonCfg.RxStream == 0) || (pAd->CommonCfg.RxStream > Antenna.field.RxPath)) ++ { ++ pAd->CommonCfg.RxStream = Antenna.field.RxPath; ++ ++ if ((pAd->MACVersion < RALINK_2883_VERSION) && ++ (pAd->CommonCfg.RxStream > 2)) ++ { ++ // only 2 Rx streams for RT2860 series ++ pAd->CommonCfg.RxStream = 2; ++ } ++ } ++ ++ // 3*3 ++ // read value from EEPROM and set them to CSR174 ~ 177 in chain0 ~ chain2 ++ // yet implement ++ for(i=0; i<3; i++) ++ { ++ } ++ ++ NicConfig2.word = pAd->EEPROMDefaultValue[1]; ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NicConfig2.word = 0; ++ if ((NicConfig2.word & 0x00ff) == 0xff) ++ { ++ NicConfig2.word &= 0xff00; ++ } ++ ++ if ((NicConfig2.word >> 8) == 0xff) ++ { ++ NicConfig2.word &= 0x00ff; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (NicConfig2.field.DynamicTxAgcControl == 1) ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; ++ else ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("NICReadEEPROMParameters: RxPath = %d, TxPath = %d\n", Antenna.field.RxPath, Antenna.field.TxPath)); ++ ++ // Save the antenna for future use ++ pAd->Antenna.word = Antenna.word; ++ ++ // ++ // Reset PhyMode if we don't support 802.11a ++ // Only RFIC_2850 & RFIC_2750 support 802.11a ++ // ++ if ((Antenna.field.RfIcType != RFIC_2850) && (Antenna.field.RfIcType != RFIC_2750)) ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11A)) ++ pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; ++#ifdef DOT11_N_SUPPORT ++ else if ((pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11N_5G)) ++ pAd->CommonCfg.PhyMode = PHY_11BGN_MIXED; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ // Read TSSI reference and TSSI boundary for temperature compensation. This is ugly ++ // 0. 11b/g ++ { ++ /* these are tempature reference value (0x00 ~ 0xFE) ++ ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ TssiPlusBoundaryG [4] [3] [2] [1] [0] (smaller) + ++ TssiMinusBoundaryG[0] [1] [2] [3] [4] (larger) */ ++ RT28xx_EEPROM_READ16(pAd, 0x6E, Power.word); ++ pAd->TssiMinusBoundaryG[4] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryG[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x70, Power.word); ++ pAd->TssiMinusBoundaryG[2] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryG[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x72, Power.word); ++ pAd->TssiRefG = Power.field.Byte0; /* reference value [0] */ ++ pAd->TssiPlusBoundaryG[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x74, Power.word); ++ pAd->TssiPlusBoundaryG[2] = Power.field.Byte0; ++ pAd->TssiPlusBoundaryG[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x76, Power.word); ++ pAd->TssiPlusBoundaryG[4] = Power.field.Byte0; ++ pAd->TxAgcStepG = Power.field.Byte1; ++ pAd->TxAgcCompensateG = 0; ++ pAd->TssiMinusBoundaryG[0] = pAd->TssiRefG; ++ pAd->TssiPlusBoundaryG[0] = pAd->TssiRefG; ++ ++ // Disable TxAgc if the based value is not right ++ if (pAd->TssiRefG == 0xff) ++ pAd->bAutoTxAgcG = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("E2PROM: G Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", ++ pAd->TssiMinusBoundaryG[4], pAd->TssiMinusBoundaryG[3], pAd->TssiMinusBoundaryG[2], pAd->TssiMinusBoundaryG[1], ++ pAd->TssiRefG, ++ pAd->TssiPlusBoundaryG[1], pAd->TssiPlusBoundaryG[2], pAd->TssiPlusBoundaryG[3], pAd->TssiPlusBoundaryG[4], ++ pAd->TxAgcStepG, pAd->bAutoTxAgcG)); ++ } ++ // 1. 11a ++ { ++ RT28xx_EEPROM_READ16(pAd, 0xD4, Power.word); ++ pAd->TssiMinusBoundaryA[4] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryA[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xD6, Power.word); ++ pAd->TssiMinusBoundaryA[2] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryA[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xD8, Power.word); ++ pAd->TssiRefA = Power.field.Byte0; ++ pAd->TssiPlusBoundaryA[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xDA, Power.word); ++ pAd->TssiPlusBoundaryA[2] = Power.field.Byte0; ++ pAd->TssiPlusBoundaryA[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xDC, Power.word); ++ pAd->TssiPlusBoundaryA[4] = Power.field.Byte0; ++ pAd->TxAgcStepA = Power.field.Byte1; ++ pAd->TxAgcCompensateA = 0; ++ pAd->TssiMinusBoundaryA[0] = pAd->TssiRefA; ++ pAd->TssiPlusBoundaryA[0] = pAd->TssiRefA; ++ ++ // Disable TxAgc if the based value is not right ++ if (pAd->TssiRefA == 0xff) ++ pAd->bAutoTxAgcA = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("E2PROM: A Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", ++ pAd->TssiMinusBoundaryA[4], pAd->TssiMinusBoundaryA[3], pAd->TssiMinusBoundaryA[2], pAd->TssiMinusBoundaryA[1], ++ pAd->TssiRefA, ++ pAd->TssiPlusBoundaryA[1], pAd->TssiPlusBoundaryA[2], pAd->TssiPlusBoundaryA[3], pAd->TssiPlusBoundaryA[4], ++ pAd->TxAgcStepA, pAd->bAutoTxAgcA)); ++ } ++ pAd->BbpRssiToDbmDelta = 0x0; ++ ++ // Read frequency offset setting for RF ++ RT28xx_EEPROM_READ16(pAd, EEPROM_FREQ_OFFSET, value); ++ if ((value & 0x00FF) != 0x00FF) ++ pAd->RfFreqOffset = (ULONG) (value & 0x00FF); ++ else ++ pAd->RfFreqOffset = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: RF FreqOffset=0x%lx \n", pAd->RfFreqOffset)); ++ ++ //CountryRegion byte offset (38h) ++ value = pAd->EEPROMDefaultValue[2] >> 8; // 2.4G band ++ value2 = pAd->EEPROMDefaultValue[2] & 0x00FF; // 5G band ++ ++ if ((value <= REGION_MAXIMUM_BG_BAND) && (value2 <= REGION_MAXIMUM_A_BAND)) ++ { ++ pAd->CommonCfg.CountryRegion = ((UCHAR) value) | 0x80; ++ pAd->CommonCfg.CountryRegionForABand = ((UCHAR) value2) | 0x80; ++ TmpPhy = pAd->CommonCfg.PhyMode; ++ pAd->CommonCfg.PhyMode = 0xff; ++ RTMPSetPhyMode(pAd, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ // ++ // Get RSSI Offset on EEPROM 0x9Ah & 0x9Ch. ++ // The valid value are (-10 ~ 10) ++ // ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, value); ++ pAd->BGRssiOffset0 = value & 0x00ff; ++ pAd->BGRssiOffset1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET+2, value); ++ pAd->BGRssiOffset2 = value & 0x00ff; ++ pAd->ALNAGain1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, value); ++ pAd->BLNAGain = value & 0x00ff; ++ pAd->ALNAGain0 = (value >> 8); ++ ++ // Validate 11b/g RSSI_0 offset. ++ if ((pAd->BGRssiOffset0 < -10) || (pAd->BGRssiOffset0 > 10)) ++ pAd->BGRssiOffset0 = 0; ++ ++ // Validate 11b/g RSSI_1 offset. ++ if ((pAd->BGRssiOffset1 < -10) || (pAd->BGRssiOffset1 > 10)) ++ pAd->BGRssiOffset1 = 0; ++ ++ // Validate 11b/g RSSI_2 offset. ++ if ((pAd->BGRssiOffset2 < -10) || (pAd->BGRssiOffset2 > 10)) ++ pAd->BGRssiOffset2 = 0; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, value); ++ pAd->ARssiOffset0 = value & 0x00ff; ++ pAd->ARssiOffset1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET+2), value); ++ pAd->ARssiOffset2 = value & 0x00ff; ++ pAd->ALNAGain2 = (value >> 8); ++ ++ if (((UCHAR)pAd->ALNAGain1 == 0xFF) || (pAd->ALNAGain1 == 0x00)) ++ pAd->ALNAGain1 = pAd->ALNAGain0; ++ if (((UCHAR)pAd->ALNAGain2 == 0xFF) || (pAd->ALNAGain2 == 0x00)) ++ pAd->ALNAGain2 = pAd->ALNAGain0; ++ ++ // Validate 11a RSSI_0 offset. ++ if ((pAd->ARssiOffset0 < -10) || (pAd->ARssiOffset0 > 10)) ++ pAd->ARssiOffset0 = 0; ++ ++ // Validate 11a RSSI_1 offset. ++ if ((pAd->ARssiOffset1 < -10) || (pAd->ARssiOffset1 > 10)) ++ pAd->ARssiOffset1 = 0; ++ ++ //Validate 11a RSSI_2 offset. ++ if ((pAd->ARssiOffset2 < -10) || (pAd->ARssiOffset2 > 10)) ++ pAd->ARssiOffset2 = 0; ++ ++ // ++ // Get LED Setting. ++ // ++ RT28xx_EEPROM_READ16(pAd, 0x3a, value); ++ pAd->LedCntl.word = (value&0xff00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED1_OFFSET, value); ++ pAd->Led1 = value; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED2_OFFSET, value); ++ pAd->Led2 = value; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED3_OFFSET, value); ++ pAd->Led3 = value; ++ ++ RTMPReadTxPwrPerRate(pAd); ++ ++#ifdef SINGLE_SKU ++ //pAd->CommonCfg.DefineMaxTxPwr = RTMP_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR, pAd->CommonCfg.DefineMaxTxPwr); ++#endif // SINGLE_SKU // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICReadEEPROMParameters\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set default value from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NICInitAsicFromEEPROM( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef CONFIG_STA_SUPPORT ++ UINT32 data = 0; ++ UCHAR BBPR1 = 0; ++#endif // CONFIG_STA_SUPPORT // ++ USHORT i; ++ EEPROM_ANTENNA_STRUC Antenna; ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ UCHAR BBPR3 = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitAsicFromEEPROM\n")); ++ for(i = 3; i < NUM_EEPROM_BBP_PARMS; i++) ++ { ++ UCHAR BbpRegIdx, BbpValue; ++ ++ if ((pAd->EEPROMDefaultValue[i] != 0xFFFF) && (pAd->EEPROMDefaultValue[i] != 0)) ++ { ++ BbpRegIdx = (UCHAR)(pAd->EEPROMDefaultValue[i] >> 8); ++ BbpValue = (UCHAR)(pAd->EEPROMDefaultValue[i] & 0xff); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BbpRegIdx, BbpValue); ++ } ++ } ++ ++ Antenna.word = pAd->Antenna.word; ++ pAd->Mlme.RealRxPath = (UCHAR) Antenna.field.RxPath; ++ pAd->RfIcType = (UCHAR) Antenna.field.RfIcType; ++ ++ NicConfig2.word = pAd->EEPROMDefaultValue[1]; ++ ++ ++ // Save the antenna for future use ++ pAd->NicConfig2.word = NicConfig2.word; ++ ++ // ++ // Send LED Setting to MCU. ++ // ++ if (pAd->LedCntl.word == 0xFF) ++ { ++ pAd->LedCntl.word = 0x01; ++ pAd->Led1 = 0x5555; ++ pAd->Led2 = 0x2221; ++ ++#ifdef RT2870 ++ pAd->Led3 = 0x5627; ++#endif // RT2870 // ++ } ++ ++ AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); ++ AsicSendCommandToMcu(pAd, 0x53, 0xff, (UCHAR)pAd->Led2, (UCHAR)(pAd->Led2 >> 8)); ++ AsicSendCommandToMcu(pAd, 0x54, 0xff, (UCHAR)pAd->Led3, (UCHAR)(pAd->Led3 >> 8)); ++ pAd->LedIndicatorStregth = 0xFF; ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, before link up ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Read Hardware controlled Radio state enable bit ++ if (NicConfig2.field.HardwareRadioControl == 1) ++ { ++ pAd->StaCfg.bHardwareRadio = TRUE; ++ ++ // Read GPIO pin2 as Hardware controlled radio state ++ RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); ++ if ((data & 0x04) == 0) ++ { ++ pAd->StaCfg.bHwRadio = FALSE; ++ pAd->StaCfg.bRadio = FALSE; ++// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ } ++ } ++ else ++ pAd->StaCfg.bHardwareRadio = FALSE; ++ ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ RTMPSetLED(pAd, LED_RADIO_OFF); ++ } ++ else ++ { ++ RTMPSetLED(pAd, LED_RADIO_ON); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Turn off patching for cardbus controller ++ if (NicConfig2.field.CardbusAcceleration == 1) ++ { ++// pAd->bTest1 = TRUE; ++ } ++ ++ if (NicConfig2.field.DynamicTxAgcControl == 1) ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; ++ else ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; ++ // ++ // Since BBP has been progamed, to make sure BBP setting will be ++ // upate inside of AsicAntennaSelect, so reset to UNKNOWN_BAND!! ++ // ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Handle the difference when 1T ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BBPR1); ++ if(pAd->Antenna.field.TxPath == 1) ++ { ++ BBPR1 &= (~0x18); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BBPR1); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Use Hw Radio Control Pin=%d; if used Pin=%d;\n", pAd->CommonCfg.bHardwareRadio, pAd->CommonCfg.bHardwareRadio)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPath = %d, RxPath = %d, RFIC=%d, Polar+LED mode=%x\n", pAd->Antenna.field.TxPath, pAd->Antenna.field.RxPath, pAd->RfIcType, pAd->LedCntl.word)); ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitAsicFromEEPROM\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize NIC hardware ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICInitializeAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ WPDMA_GLO_CFG_STRUC GloCfg; ++// INT_MASK_CSR_STRUC IntMask; ++ ULONG i =0, j=0; ++ AC_TXOP_CSR0_STRUC csr0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAdapter\n")); ++ ++ // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: ++retry: ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i<100); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ GloCfg.word &= 0xff0; ++ GloCfg.field.EnTXWriteBackDDONE =1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ // Record HW Beacon offset ++ pAd->BeaconOffset[0] = HW_BEACON_BASE0; ++ pAd->BeaconOffset[1] = HW_BEACON_BASE1; ++ pAd->BeaconOffset[2] = HW_BEACON_BASE2; ++ pAd->BeaconOffset[3] = HW_BEACON_BASE3; ++ pAd->BeaconOffset[4] = HW_BEACON_BASE4; ++ pAd->BeaconOffset[5] = HW_BEACON_BASE5; ++ pAd->BeaconOffset[6] = HW_BEACON_BASE6; ++ pAd->BeaconOffset[7] = HW_BEACON_BASE7; ++ ++ // ++ // write all shared Ring's base address into ASIC ++ // ++ ++ // asic simulation sequence put this ahead before loading firmware. ++ // pbf hardware reset ++ ++ // Initialze ASIC for TX & Rx operation ++ if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) ++ { ++ if (j++ == 0) ++ { ++ NICLoadFirmware(pAd); ++ goto retry; ++ } ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++ ++ ++ // WMM parameter ++ csr0.word = 0; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ csr0.field.Ac0Txop = 192; // AC_VI: 192*32us ~= 6ms ++ csr0.field.Ac1Txop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ csr0.field.Ac0Txop = 96; // AC_VI: 96*32us ~= 3ms ++ csr0.field.Ac1Txop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); ++ ++ ++ ++ ++ // reset action ++ // Load firmware ++ // Status = NICLoadFirmware(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAdapter\n")); ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize ASIC ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICInitializeAsic( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset) ++{ ++ ULONG Index = 0; ++ UCHAR R0 = 0xff; ++ UINT32 MacCsr12 = 0, Counter = 0; ++#ifdef RT2870 ++ UINT32 MacCsr0 = 0; ++ NTSTATUS Status; ++ UCHAR Value = 0xff; ++#endif // RT2870 // ++ USHORT KeyIdx; ++ INT i,apidx; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); ++ ++ ++#ifdef RT2870 ++ // ++ // Make sure MAC gets ready after NICLoadFirmware(). ++ // ++ Index = 0; ++ ++ //To avoid hang-on issue when interface up in kernel 2.4, ++ //we use a local variable "MacCsr0" instead of using "pAd->MACVersion" directly. ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); ++ ++ if ((MacCsr0 != 0x00) && (MacCsr0 != 0xFFFFFFFF)) ++ break; ++ ++ RTMPusecDelay(10); ++ } while (Index++ < 100); ++ ++ pAd->MACVersion = MacCsr0; ++ DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); ++ // turn on bit13 (set to zero) after rt2860D. This is to solve high-current issue. ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacCsr12); ++ MacCsr12 &= (~0x2000); ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, MacCsr12); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); ++ RTMP_IO_WRITE32(pAd, USB_DMA_CFG, 0x0); ++ Status = RTUSBVenderReset(pAd); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ ++ // Initialize MAC register to default value ++ for(Index=0; IndexMACVersion&0xffff) != 0x0101) ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); ++ ++#ifdef RT2870 ++ //write RT3070 BBP wchich different with 2870 after write RT2870 BBP ++ if (IS_RT3070(pAd)) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0a); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x99); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R105, 0x05); ++ } ++#endif // RT2870 // ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x12); ++ } ++ ++ if (pAd->MACVersion >= RALINK_2880E_VERSION && pAd->MACVersion < RALINK_3070_VERSION) // 3*3 ++ { ++ // enlarge MAX_LEN_CFG ++ UINT32 csr; ++ RTMP_IO_READ32(pAd, MAX_LEN_CFG, &csr); ++ csr &= 0xFFF; ++ csr |= 0x2000; ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, csr); ++ } ++ ++#ifdef RT2870 ++{ ++ UCHAR MAC_Value[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0}; ++ ++ //Initialize WCID table ++ Value = 0xff; ++ for(Index =0 ;Index < 254;Index++) ++ { ++ RTUSBMultiWrite(pAd, (USHORT)(MAC_WCID_BASE + Index * 8), MAC_Value, 8); ++ } ++} ++#endif // RT2870 // ++ ++ // Add radio off control ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set Radio Off\n")); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Clear raw counters ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); ++ ++ // ASIC will keep garbage value after boot ++ // Clear all seared key table when initial ++ // This routine can be ignored in radio-ON/OFF operation. ++ if (bHardReset) ++ { ++ for (KeyIdx = 0; KeyIdx < 4; KeyIdx++) ++ { ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4*KeyIdx, 0); ++ } ++ ++ // Clear all pairwise key table when initial ++ for (KeyIdx = 0; KeyIdx < 256; KeyIdx++) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_WCID_ATTRIBUTE_BASE + (KeyIdx * HW_WCID_ATTRI_SIZE), 1); ++ } ++ } ++ ++ // assert HOST ready bit ++// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x0); // 2004-09-14 asked by Mark ++// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x4); ++ ++ // It isn't necessary to clear this space when not hard reset. ++ if (bHardReset == TRUE) ++ { ++ // clear all on-chip BEACON frame space ++ for (apidx = 0; apidx < HW_BEACON_MAX_COUNT; apidx++) ++ { ++ for (i = 0; i < HW_BEACON_OFFSET>>2; i+=4) ++ RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[apidx] + i, 0x00); ++ } ++ } ++#ifdef RT2870 ++ AsicDisableSync(pAd); ++ // Clear raw counters ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); ++ // Default PCI clock cycle per ms is different as default setting, which is based on PCI. ++ RTMP_IO_READ32(pAd, USB_CYC_CFG, &Counter); ++ Counter&=0xffffff00; ++ Counter|=0x000001e; ++ RTMP_IO_WRITE32(pAd, USB_CYC_CFG, Counter); ++#endif // RT2870 // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // for rt2860E and after, init TXOP_CTRL_CFG with 0x583f. This is for extension channel overlapping IOT. ++ if ((pAd->MACVersion&0xffff) != 0x0101) ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x583f); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAsic\n")); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC Asics ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID NICIssueReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 Value = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICIssueReset\n")); ++ ++ // Abort Tx, prevent ASIC from writing to Host memory ++ //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x001f0000); ++ ++ // Disable Rx, register value supposed will remain after reset ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= (0xfffffff3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Issue reset and clear from reset state ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x03); // 2004-09-17 change from 0x01 ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x00); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICIssueReset\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check ASIC registers and find any reason the system might hang ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN NICCheckForHang( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return (FALSE); ++} ++ ++VOID NICUpdateFifoStaCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_STA_FIFO_STRUC StaFifo; ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR i = 0; ++ UCHAR pid = 0, wcid = 0; ++ CHAR reTry; ++ UCHAR succMCS; ++ ++#ifdef RALINK_ATE ++ /* Nothing to do in ATE mode */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ do ++ { ++ RTMP_IO_READ32(pAd, TX_STA_FIFO, &StaFifo.word); ++ ++ if (StaFifo.field.bValid == 0) ++ break; ++ ++ wcid = (UCHAR)StaFifo.field.wcid; ++ ++ ++ /* ignore NoACK and MGMT frame use 0xFF as WCID */ ++ if ((StaFifo.field.TxAckRequired == 0) || (wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ i++; ++ continue; ++ } ++ ++ /* PID store Tx MCS Rate */ ++ pid = (UCHAR)StaFifo.field.PidType; ++ ++ pEntry = &pAd->MacTab.Content[wcid]; ++ ++ pEntry->DebugFIFOCount++; ++ ++#ifdef DOT11_N_SUPPORT ++ if (StaFifo.field.TxBF) // 3*3 ++ pEntry->TxBFCount++; ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef UAPSD_AP_SUPPORT ++ UAPSD_SP_AUE_Handle(pAd, pEntry, StaFifo.field.TxSuccess); ++#endif // UAPSD_AP_SUPPORT // ++ ++ if (!StaFifo.field.TxSuccess) ++ { ++ pEntry->FIFOCount++; ++ pEntry->OneSecTxFailCount++; ++ ++ if (pEntry->FIFOCount >= 1) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("#")); ++#if 0 ++ SendRefreshBAR(pAd, pEntry); ++ pEntry->NoBADataCountDown = 64; ++#else ++#ifdef DOT11_N_SUPPORT ++ pEntry->NoBADataCountDown = 64; ++#endif // DOT11_N_SUPPORT // ++ ++ if(pEntry->PsMode == PWR_ACTIVE) ++ { ++#ifdef DOT11_N_SUPPORT ++ int tid; ++ for (tid=0; tidAid, tid, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Update the continuous transmission counter except PS mode ++ pEntry->ContinueTxFailCnt++; ++ } ++ else ++ { ++ // Clear the FIFOCount when sta in Power Save mode. Basically we assume ++ // this tx error happened due to sta just go to sleep. ++ pEntry->FIFOCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ } ++#endif ++ //pEntry->FIFOCount = 0; ++ } ++ //pEntry->bSendBAR = TRUE; ++ } ++ else ++ { ++#ifdef DOT11_N_SUPPORT ++ if ((pEntry->PsMode != PWR_SAVE) && (pEntry->NoBADataCountDown > 0)) ++ { ++ pEntry->NoBADataCountDown--; ++ if (pEntry->NoBADataCountDown==0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("@\n")); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ pEntry->FIFOCount = 0; ++ pEntry->OneSecTxNoRetryOkCount++; ++ // update NoDataIdleCount when sucessful send packet to STA. ++ pEntry->NoDataIdleCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ } ++ ++ succMCS = StaFifo.field.SuccessRate & 0x7F; ++ ++ reTry = pid - succMCS; ++ ++ if (StaFifo.field.TxSuccess) ++ { ++ pEntry->TXMCSExpected[pid]++; ++ if (pid == succMCS) ++ { ++ pEntry->TXMCSSuccessful[pid]++; ++ } ++ else ++ { ++ pEntry->TXMCSAutoFallBack[pid][succMCS]++; ++ } ++ } ++ else ++ { ++ pEntry->TXMCSFailed[pid]++; ++ } ++ ++ if (reTry > 0) ++ { ++ if ((pid >= 12) && succMCS <=7) ++ { ++ reTry -= 4; ++ } ++ pEntry->OneSecTxRetryOkCount += reTry; ++ } ++ ++ i++; ++ // ASIC store 16 stack ++ } while ( i < (2*TX_RING_SIZE) ); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read statistical counters from hardware registers and record them ++ in software variables for later on query ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID NICUpdateRawCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 OldValue; ++ RX_STA_CNT0_STRUC RxStaCnt0; ++ RX_STA_CNT1_STRUC RxStaCnt1; ++ RX_STA_CNT2_STRUC RxStaCnt2; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT2_STRUC StaTx2; ++ TX_AGG_CNT_STRUC TxAggCnt; ++ TX_AGG_CNT0_STRUC TxAggCnt0; ++ TX_AGG_CNT1_STRUC TxAggCnt1; ++ TX_AGG_CNT2_STRUC TxAggCnt2; ++ TX_AGG_CNT3_STRUC TxAggCnt3; ++ TX_AGG_CNT4_STRUC TxAggCnt4; ++ TX_AGG_CNT5_STRUC TxAggCnt5; ++ TX_AGG_CNT6_STRUC TxAggCnt6; ++ TX_AGG_CNT7_STRUC TxAggCnt7; ++ ++ ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &RxStaCnt0.word); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &RxStaCnt2.word); ++ ++ { ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &RxStaCnt1.word); ++ // Update RX PLCP error counter ++ pAd->PrivateInfo.PhyRxErrCnt += RxStaCnt1.field.PlcpErr; ++ // Update False CCA counter ++ pAd->RalinkCounters.OneSecFalseCCACnt += RxStaCnt1.field.FalseCca; ++ } ++ ++ // Update FCS counters ++ OldValue= pAd->WlanCounters.FCSErrorCount.u.LowPart; ++ pAd->WlanCounters.FCSErrorCount.u.LowPart += (RxStaCnt0.field.CrcErr); // >> 7); ++ if (pAd->WlanCounters.FCSErrorCount.u.LowPart < OldValue) ++ pAd->WlanCounters.FCSErrorCount.u.HighPart++; ++ ++ // Add FCS error count to private counters ++ pAd->RalinkCounters.OneSecRxFcsErrCnt += RxStaCnt0.field.CrcErr; ++ OldValue = pAd->RalinkCounters.RealFcsErrCount.u.LowPart; ++ pAd->RalinkCounters.RealFcsErrCount.u.LowPart += RxStaCnt0.field.CrcErr; ++ if (pAd->RalinkCounters.RealFcsErrCount.u.LowPart < OldValue) ++ pAd->RalinkCounters.RealFcsErrCount.u.HighPart++; ++ ++ // Update Duplicate Rcv check ++ pAd->RalinkCounters.DuplicateRcv += RxStaCnt2.field.RxDupliCount; ++ pAd->WlanCounters.FrameDuplicateCount.u.LowPart += RxStaCnt2.field.RxDupliCount; ++ // Update RX Overflow counter ++ pAd->Counters8023.RxNoBuffer += (RxStaCnt2.field.RxFifoOverflowCount); ++ ++ //pAd->RalinkCounters.RxCount = 0; ++#ifdef RT2870 ++ if (pAd->RalinkCounters.RxCount != pAd->watchDogRxCnt) ++ { ++ pAd->watchDogRxCnt = pAd->RalinkCounters.RxCount; ++ pAd->watchDogRxOverFlowCnt = 0; ++ } ++ else ++ { ++ if (RxStaCnt2.field.RxFifoOverflowCount) ++ pAd->watchDogRxOverFlowCnt++; ++ else ++ pAd->watchDogRxOverFlowCnt = 0; ++ } ++#endif // RT2870 // ++ ++ ++ //if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) || ++ // (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) && (pAd->MacTab.Size != 1))) ++ if (!pAd->bUpdateBcnCntDone) ++ { ++ // Update BEACON sent count ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &StaTx2.word); ++ pAd->RalinkCounters.OneSecBeaconSentCnt += TxStaCnt0.field.TxBeaconCount; ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ } ++ ++#if 0 ++ Retry = StaTx1.field.TxRetransmit; ++ Fail = TxStaCnt0.field.TxFailCount; ++ TxErrorRatio = 0; ++ OneSecTransmitCount = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart- pAd->WlanCounters.LastTransmittedFragmentCount.u.LowPart; ++ if ((OneSecTransmitCount+Retry + Fail) > 0) ++ TxErrorRatio = (( Retry + Fail) *100) / (OneSecTransmitCount+Retry + Fail); ++ ++ if ((OneSecTransmitCount+Retry + Fail) > 0) ++ TxErrorRatio = (( Retry + Fail) *100) / (OneSecTransmitCount+Retry + Fail); ++ DBGPRINT(RT_DEBUG_INFO, ("TX ERROR Rate = %ld %%, Retry = %ld, Fail = %ld, Total = %ld \n",TxErrorRatio, Retry, Fail, (OneSecTransmitCount+Retry + Fail))); ++ pAd->WlanCounters.LastTransmittedFragmentCount.u.LowPart = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart; ++#endif ++ ++ //if (pAd->bStaFifoTest == TRUE) ++ { ++ RTMP_IO_READ32(pAd, TX_AGG_CNT, &TxAggCnt.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT0, &TxAggCnt0.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT1, &TxAggCnt1.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT2, &TxAggCnt2.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT3, &TxAggCnt3.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT4, &TxAggCnt4.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT5, &TxAggCnt5.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT6, &TxAggCnt6.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT7, &TxAggCnt7.word); ++ pAd->RalinkCounters.TxAggCount += TxAggCnt.field.AggTxCount; ++ pAd->RalinkCounters.TxNonAggCount += TxAggCnt.field.NonAggTxCount; ++ pAd->RalinkCounters.TxAgg1MPDUCount += TxAggCnt0.field.AggSize1Count; ++ pAd->RalinkCounters.TxAgg2MPDUCount += TxAggCnt0.field.AggSize2Count; ++ ++ pAd->RalinkCounters.TxAgg3MPDUCount += TxAggCnt1.field.AggSize3Count; ++ pAd->RalinkCounters.TxAgg4MPDUCount += TxAggCnt1.field.AggSize4Count; ++ pAd->RalinkCounters.TxAgg5MPDUCount += TxAggCnt2.field.AggSize5Count; ++ pAd->RalinkCounters.TxAgg6MPDUCount += TxAggCnt2.field.AggSize6Count; ++ ++ pAd->RalinkCounters.TxAgg7MPDUCount += TxAggCnt3.field.AggSize7Count; ++ pAd->RalinkCounters.TxAgg8MPDUCount += TxAggCnt3.field.AggSize8Count; ++ pAd->RalinkCounters.TxAgg9MPDUCount += TxAggCnt4.field.AggSize9Count; ++ pAd->RalinkCounters.TxAgg10MPDUCount += TxAggCnt4.field.AggSize10Count; ++ ++ pAd->RalinkCounters.TxAgg11MPDUCount += TxAggCnt5.field.AggSize11Count; ++ pAd->RalinkCounters.TxAgg12MPDUCount += TxAggCnt5.field.AggSize12Count; ++ pAd->RalinkCounters.TxAgg13MPDUCount += TxAggCnt6.field.AggSize13Count; ++ pAd->RalinkCounters.TxAgg14MPDUCount += TxAggCnt6.field.AggSize14Count; ++ ++ pAd->RalinkCounters.TxAgg15MPDUCount += TxAggCnt7.field.AggSize15Count; ++ pAd->RalinkCounters.TxAgg16MPDUCount += TxAggCnt7.field.AggSize16Count; ++ ++ // Calculate the transmitted A-MPDU count ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += TxAggCnt0.field.AggSize1Count; ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt0.field.AggSize2Count / 2); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize3Count / 3); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize4Count / 4); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize5Count / 5); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize6Count / 6); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize7Count / 7); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize8Count / 8); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize9Count / 9); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize10Count / 10); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize11Count / 11); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize12Count / 12); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize13Count / 13); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize14Count / 14); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize15Count / 15); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize16Count / 16); ++ } ++ ++#ifdef DBG_DIAGNOSE ++ { ++ RtmpDiagStruct *pDiag; ++ COUNTER_RALINK *pRalinkCounters; ++ UCHAR ArrayCurIdx, i; ++ ++ pDiag = &pAd->DiagStruct; ++ pRalinkCounters = &pAd->RalinkCounters; ++ ArrayCurIdx = pDiag->ArrayCurIdx; ++ ++ if (pDiag->inited == 0) ++ { ++ NdisZeroMemory(pDiag, sizeof(struct _RtmpDiagStrcut_)); ++ pDiag->ArrayStartIdx = pDiag->ArrayCurIdx = 0; ++ pDiag->inited = 1; ++ } ++ else ++ { ++ // Tx ++ pDiag->TxFailCnt[ArrayCurIdx] = TxStaCnt0.field.TxFailCount; ++ pDiag->TxAggCnt[ArrayCurIdx] = TxAggCnt.field.AggTxCount; ++ pDiag->TxNonAggCnt[ArrayCurIdx] = TxAggCnt.field.NonAggTxCount; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][0] = TxAggCnt0.field.AggSize1Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][1] = TxAggCnt0.field.AggSize2Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][2] = TxAggCnt1.field.AggSize3Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][3] = TxAggCnt1.field.AggSize4Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][4] = TxAggCnt2.field.AggSize5Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][5] = TxAggCnt2.field.AggSize6Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][6] = TxAggCnt3.field.AggSize7Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][7] = TxAggCnt3.field.AggSize8Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][8] = TxAggCnt4.field.AggSize9Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][9] = TxAggCnt4.field.AggSize10Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][10] = TxAggCnt5.field.AggSize11Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][11] = TxAggCnt5.field.AggSize12Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][12] = TxAggCnt6.field.AggSize13Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][13] = TxAggCnt6.field.AggSize14Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][14] = TxAggCnt7.field.AggSize15Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][15] = TxAggCnt7.field.AggSize16Count; ++ ++ pDiag->RxCrcErrCnt[ArrayCurIdx] = RxStaCnt0.field.CrcErr; ++ ++ INC_RING_INDEX(pDiag->ArrayCurIdx, DIAGNOSE_TIME); ++ ArrayCurIdx = pDiag->ArrayCurIdx; ++ for (i =0; i < 9; i++) ++ { ++ pDiag->TxDescCnt[ArrayCurIdx][i]= 0; ++ pDiag->TxSWQueCnt[ArrayCurIdx][i] =0; ++ pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; ++ pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; ++ } ++ pDiag->TxDataCnt[ArrayCurIdx] = 0; ++ pDiag->TxFailCnt[ArrayCurIdx] = 0; ++ pDiag->RxDataCnt[ArrayCurIdx] = 0; ++ pDiag->RxCrcErrCnt[ArrayCurIdx] = 0; ++// for (i = 9; i < 16; i++) ++ for (i = 9; i < 24; i++) // 3*3 ++ { ++ pDiag->TxDescCnt[ArrayCurIdx][i] = 0; ++ pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; ++ pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; ++} ++ ++ if (pDiag->ArrayCurIdx == pDiag->ArrayStartIdx) ++ INC_RING_INDEX(pDiag->ArrayStartIdx, DIAGNOSE_TIME); ++ } ++ ++ } ++#endif // DBG_DIAGNOSE // ++ ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC from error ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Reset NIC from error state ++ ++ ======================================================================== ++*/ ++VOID NICResetFromError( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Reset BBP (according to alex, reset ASIC will force reset BBP ++ // Therefore, skip the reset BBP ++ // RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x2); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ // Remove ASIC from reset state ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ ++ NICInitializeAdapter(pAd, FALSE); ++ NICInitAsicFromEEPROM(pAd); ++ ++ // Switch to current channel, since during reset process, the connection should remains on. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ erase 8051 firmware image in MAC ASIC ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID NICEraseFirmware( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ ++ for(i=0; i %s\n", __FUNCTION__)); ++ ++ /* init */ ++ pFirmwareImage = NULL; ++ src = RTMP_FIRMWARE_FILE_NAME; ++ ++ /* save uid and gid used for filesystem access. ++ set user and group to 0 (root) */ ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ ++ FIRMWARE_MINOR_VERSION; ++ ++ ++ /* allocate firmware buffer */ ++ pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); ++ if (pFirmwareImage == NULL) ++ { ++ /* allocate fail, use default firmware array in firmware.h */ ++ printk("%s - Allocate memory fail!\n", __FUNCTION__); ++ NICLF_DEFAULT_USE(); ++ } ++ else ++ { ++ /* allocate ok! zero the firmware buffer */ ++ memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); ++ } /* End of if */ ++ ++ ++ /* if ok, read firmware file from *.bin file */ ++ if (flg_default_firm_use == FALSE) ++ { ++ do ++ { ++ /* open the bin file */ ++ srcf = filp_open(src, O_RDONLY, 0); ++ ++ if (IS_ERR(srcf)) ++ { ++ printk("%s - Error %ld opening %s\n", ++ __FUNCTION__, -PTR_ERR(srcf), src); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ ++ /* the object must have a read method */ ++ if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) ++ { ++ printk("%s - %s does not have a write method\n", __FUNCTION__, src); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ ++ /* read the firmware from the file *.bin */ ++ FileLength = srcf->f_op->read(srcf, ++ pFirmwareImage, ++ MAX_FIRMWARE_IMAGE_SIZE, ++ &srcf->f_pos); ++ ++ if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) ++ { ++ printk("%s: error file length (=%d) in RT2860AP.BIN\n", ++ __FUNCTION__, FileLength); ++ NICLF_DEFAULT_USE(); ++ break; ++ } ++ else ++ { ++ PUCHAR ptr = pFirmwareImage; ++ USHORT crc = 0xffff; ++ ++ ++ /* calculate firmware CRC */ ++ for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) ++ crc = ByteCRC16(BitReverse(*ptr), crc); ++ /* End of for */ ++ ++ if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ ++ (UCHAR)BitReverse((UCHAR)(crc>>8))) || ++ (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ ++ (UCHAR)BitReverse((UCHAR)crc))) ++ { ++ /* CRC fail */ ++ printk("%s: CRC = 0x%02x 0x%02x " ++ "error, should be 0x%02x 0x%02x\n", ++ __FUNCTION__, ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], ++ (UCHAR)(crc>>8), (UCHAR)(crc)); ++ NICLF_DEFAULT_USE(); ++ break; ++ } ++ else ++ { ++ /* firmware is ok */ ++ pAd->FirmwareVersion = \ ++ (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; ++ ++ /* check if firmware version of the file is too old */ ++ if ((pAd->FirmwareVersion) < \ ++ ((FIRMWARE_MAJOR_VERSION << 8) + ++ FIRMWARE_MINOR_VERSION)) ++ { ++ printk("%s: firmware version too old!\n", __FUNCTION__); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ } /* End of if */ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("NICLoadFirmware: CRC ok, ver=%d.%d\n", ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); ++ } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ ++ break; ++ } while(TRUE); ++ ++ /* close firmware file */ ++ if (IS_ERR(srcf)) ++ ; ++ else ++ { ++ retval = filp_close(srcf, NULL); ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("--> Error %d closing %s\n", -retval, src)); ++ } /* End of if */ ++ } /* End of if */ ++ } /* End of if */ ++ ++ ++ /* write firmware to ASIC */ ++ if (flg_default_firm_use == TRUE) ++ { ++ /* use default fimeware, free allocated buffer */ ++ if (pFirmwareImage != NULL) ++ kfree(pFirmwareImage); ++ /* End of if */ ++ ++ /* use default *.bin array */ ++ pFirmwareImage = FirmwareImage; ++ FileLength = sizeof(FirmwareImage); ++ } /* End of if */ ++ ++ /* enable Host program ram write selection */ ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); ++ ++ for(i=0; ifsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++#else ++ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ PUCHAR pFirmwareImage; ++ ULONG FileLength, Index; ++ //ULONG firm; ++ UINT32 MacReg = 0; ++#ifdef RT2870 ++ UINT32 Version = (pAd->MACVersion >> 16); ++#endif // RT2870 // ++ ++ pFirmwareImage = FirmwareImage; ++ FileLength = sizeof(FirmwareImage); ++#ifdef RT2870 ++ // New 8k byte firmware size for RT3071/RT3072 ++ //printk("Usb Chip\n"); ++ if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) ++ //The firmware image consists of two parts. One is the origianl and the other is the new. ++ //Use Second Part ++ { ++ if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) ++ { // Use Firmware V2. ++ //printk("KH:Use New Version,part2\n"); ++ pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; ++ FileLength = FIRMWAREIMAGEV2_LENGTH; ++ } ++ else ++ { ++ //printk("KH:Use New Version,part1\n"); ++ pFirmwareImage = FirmwareImage; ++ FileLength = FIRMWAREIMAGEV1_LENGTH; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ ++#endif // RT2870 // ++ ++#if 0 ++ /* enable Host program ram write selection */ ++ RT28XX_FIRMUD_INIT(pAd); ++ ++ for(i=0; i= 1000) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); ++ } /* End of if */ ++ ++#if 0 ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("<=== %s (src=%s, status=%d)\n", __FUNCTION__, src, Status)); ++#else ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("<=== %s (status=%d)\n", __FUNCTION__, Status)); ++#endif ++ return Status; ++} /* End of NICLoadFirmware */ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Load Tx rate switching parameters ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS firmware image load ok ++ NDIS_STATUS_FAILURE image not found ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Rate Table Format: ++ 1. (B0: Valid Item number) (B1:Initial item from zero) ++ 2. Item Number(Dec) Mode(Hex) Current MCS(Dec) TrainUp(Dec) TrainDown(Dec) ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICLoadRateSwitchingParams( ++ IN PRTMP_ADAPTER pAd) ++{ ++#if 0 ++ NDIS_STATUS Status; ++ ++ NDIS_HANDLE FileHandle; ++ UINT FileLength = 0, i, j; ++ PUCHAR pFirmwareImage; ++ NDIS_STRING FileName; ++ NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("===> NICLoadRateSwitchingParams \n")); ++ pAd->CommonCfg.TxRateTableSize = 0; ++ ++ if ((pAd->DeviceID == NIC2860_PCI_DEVICE_ID) || (pAd->DeviceID == NIC2860_PCIe_DEVICE_ID)) ++ { ++ NdisInitializeString(&FileName,"rate.bin"); ++ DBGPRINT(RT_DEBUG_TRACE, ("NICLoadRateSwitchingParams: load file - rate.bin for tx rate switch \n")); ++ } ++ else ++ { ++ DBGPRINT_ERR(("NICLoadRateSwitchingParams: wrong DeviceID = 0x%04x, can't find Tx rate switch parameters file\n", pAd->DeviceID)); ++ return NDIS_STATUS_SUCCESS; ++ } ++ NdisOpenFile(&Status, &FileHandle, &FileLength, &FileName, HighestAcceptableMax); ++ NdisFreeString(FileName); ++ ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("NICLoadRateSwitchingParams: NdisOpenFile() failed, used RateSwitchTable instead\n")); ++ return NDIS_STATUS_SUCCESS; ++ } ++ ++ if ((FileLength == 0) || (FileLength > (MAX_STEP_OF_TX_RATE_SWITCH+1)*16)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("NICLoadRateSwitchingParams: file size is not reasonable, used RateSwitchTable instead\n")); ++ ++ NdisCloseFile(FileHandle); ++ return NDIS_STATUS_SUCCESS; ++ } ++ else ++ { ++ // ++ // NDIS_STATUS_SUCCESS means ++ // The handle at FileHandle is valid for a subsequent call to NdisMapFile. ++ // ++ NdisMapFile(&Status, &pFirmwareImage, FileHandle); ++ DBGPRINT(RT_DEBUG_TRACE, ("NdisMapFile FileLength=%d\n", FileLength)); ++ } ++ ++ for (i=0, j=0; i>4) * 10 + (*(pFirmwareImage + i) & 0x0F); ++ } ++ ++ j++; ++ } ++ } ++ ++ pAd->CommonCfg.TxRateTableSize = RateSwitchTable[0]; // backup table size ++ ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ NdisUnmapFile(FileHandle); ++ NdisCloseFile(FileHandle); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("<=== NICLoadRateSwitchingParams(Valid TxRateTable item number=%d)\n", pAd->CommonCfg.TxRateTableSize)); ++#endif ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ if pSrc1 all zero with length Length, return 0. ++ If not all zero, return 1 ++ ++ Arguments: ++ pSrc1 ++ ++ Return Value: ++ 1: not all zero ++ 0: all zero ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPNotAllZero( ++ IN PVOID pSrc1, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ ULONG Index = 0; ++ ++ pMem1 = (PUCHAR) pSrc1; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ if (pMem1[Index] != 0x0) ++ { ++ break; ++ } ++ } ++ ++ if (Index == Length) ++ { ++ return (0); ++ } ++ else ++ { ++ return (1); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare two memory block ++ ++ Arguments: ++ pSrc1 Pointer to first memory address ++ pSrc2 Pointer to second memory address ++ ++ Return Value: ++ 0: memory is equal ++ 1: pSrc1 memory is larger ++ 2: pSrc2 memory is larger ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPCompareMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ PUCHAR pMem2; ++ ULONG Index = 0; ++ ++ pMem1 = (PUCHAR) pSrc1; ++ pMem2 = (PUCHAR) pSrc2; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ if (pMem1[Index] > pMem2[Index]) ++ return (1); ++ else if (pMem1[Index] < pMem2[Index]) ++ return (2); ++ } ++ ++ // Equal ++ return (0); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Zero out memory block ++ ++ Arguments: ++ pSrc1 Pointer to memory address ++ Length Size ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPZeroMemory( ++ IN PVOID pSrc, ++ IN ULONG Length) ++{ ++ PUCHAR pMem; ++ ULONG Index = 0; ++ ++ pMem = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem[Index] = 0x00; ++ } ++} ++ ++VOID RTMPFillMemory( ++ IN PVOID pSrc, ++ IN ULONG Length, ++ IN UCHAR Fill) ++{ ++ PUCHAR pMem; ++ ULONG Index = 0; ++ ++ pMem = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem[Index] = Fill; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy data from memory block 1 to memory block 2 ++ ++ Arguments: ++ pDest Pointer to destination memory address ++ pSrc Pointer to source memory address ++ Length Copy size ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPMoveMemory( ++ OUT PVOID pDest, ++ IN PVOID pSrc, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ PUCHAR pMem2; ++ UINT Index; ++ ++ ASSERT((Length==0) || (pDest && pSrc)); ++ ++ pMem1 = (PUCHAR) pDest; ++ pMem2 = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem1[Index] = pMem2[Index]; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize port configuration structure ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID UserCfgInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++// EDCA_PARM DefaultEdcaParm; ++ UINT key_index, bss_index; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit\n")); ++ ++ // ++ // part I. intialize common configuration ++ // ++#ifdef RT2870 ++ pAd->BulkOutReq = 0; ++ ++ pAd->BulkOutComplete = 0; ++ pAd->BulkOutCompleteOther = 0; ++ pAd->BulkOutCompleteCancel = 0; ++ pAd->BulkInReq = 0; ++ pAd->BulkInComplete = 0; ++ pAd->BulkInCompleteFail = 0; ++ ++ //pAd->QuickTimerP = 100; ++ //pAd->TurnAggrBulkInCount = 0; ++ pAd->bUsbTxBulkAggre = 0; ++ ++ // init as unsed value to ensure driver will set to MCU once. ++ pAd->LedIndicatorStregth = 0xFF; ++ ++ pAd->CommonCfg.MaxPktOneTxBulk = 2; ++ pAd->CommonCfg.TxBulkFactor = 1; ++ pAd->CommonCfg.RxBulkFactor =1; ++ ++ pAd->CommonCfg.TxPower = 100; //mW ++ ++ NdisZeroMemory(&pAd->CommonCfg.IOTestParm, sizeof(pAd->CommonCfg.IOTestParm)); ++#endif // RT2870 // ++ ++ for(key_index=0; key_indexSharedKey[bss_index][key_index].KeyLen = 0; ++ pAd->SharedKey[bss_index][key_index].CipherAlg = CIPHER_NONE; ++ } ++ } ++ ++ pAd->Antenna.word = 0; ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ ++ pAd->LedCntl.word = 0; ++ ++ pAd->bAutoTxAgcA = FALSE; // Default is OFF ++ pAd->bAutoTxAgcG = FALSE; // Default is OFF ++ pAd->RfIcType = RFIC_2820; ++ ++ // Init timer for reset complete event ++ pAd->CommonCfg.CentralChannel = 1; ++ pAd->bForcePrintTX = FALSE; ++ pAd->bForcePrintRX = FALSE; ++ pAd->bStaFifoTest = FALSE; ++ pAd->bProtectionTest = FALSE; ++ pAd->bHCCATest = FALSE; ++ pAd->bGenOneHCCA = FALSE; ++ pAd->CommonCfg.Dsifs = 10; // in units of usec ++ pAd->CommonCfg.TxPower = 100; //mW ++ pAd->CommonCfg.TxPowerPercentage = 0xffffffff; // AUTO ++ pAd->CommonCfg.TxPowerDefault = 0xffffffff; // AUTO ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleAuto; // use Long preamble on TX by defaut ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ pAd->CommonCfg.RtsThreshold = 2347; ++ pAd->CommonCfg.FragmentThreshold = 2346; ++ pAd->CommonCfg.UseBGProtection = 0; // 0: AUTO ++ pAd->CommonCfg.bEnableTxBurst = TRUE; //0; ++ pAd->CommonCfg.PhyMode = 0xff; // unknown ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++ pAd->CommonCfg.RadarDetect.CSPeriod = 10; ++ pAd->CommonCfg.RadarDetect.CSCount = 0; ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ pAd->CommonCfg.RadarDetect.ChMovingTime = 65; ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh = 3; ++ pAd->CommonCfg.bAPSDCapable = FALSE; ++ pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; ++ pAd->CommonCfg.TriggerTimerCount = 0; ++ pAd->CommonCfg.bAPSDForcePowerSave = FALSE; ++ pAd->CommonCfg.bCountryFlag = FALSE; ++ pAd->CommonCfg.TxStream = 0; ++ pAd->CommonCfg.RxStream = 0; ++ ++ NdisZeroMemory(&pAd->BeaconTxWI, sizeof(pAd->BeaconTxWI)); ++ ++#ifdef DOT11_N_SUPPORT ++ NdisZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); ++ pAd->HTCEnable = FALSE; ++ pAd->bBroadComHT = FALSE; ++ pAd->CommonCfg.bRdg = FALSE; ++ ++#ifdef DOT11N_DRAFT3 ++ pAd->CommonCfg.Dot11OBssScanPassiveDwell = dot11OBSSScanPassiveDwell; // Unit : TU. 5~1000 ++ pAd->CommonCfg.Dot11OBssScanActiveDwell = dot11OBSSScanActiveDwell; // Unit : TU. 10~1000 ++ pAd->CommonCfg.Dot11BssWidthTriggerScanInt = dot11BSSWidthTriggerScanInterval; // Unit : Second ++ pAd->CommonCfg.Dot11OBssScanPassiveTotalPerChannel = dot11OBSSScanPassiveTotalPerChannel; // Unit : TU. 200~10000 ++ pAd->CommonCfg.Dot11OBssScanActiveTotalPerChannel = dot11OBSSScanActiveTotalPerChannel; // Unit : TU. 20~10000 ++ pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor = dot11BSSWidthChannelTransactionDelayFactor; ++ pAd->CommonCfg.Dot11OBssScanActivityThre = dot11BSSScanActivityThreshold; // Unit : percentage ++ pAd->CommonCfg.Dot11BssWidthChanTranDelay = (pAd->CommonCfg.Dot11BssWidthTriggerScanInt * pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor); ++#endif // DOT11N_DRAFT3 // ++ ++ NdisZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ pAd->CommonCfg.BACapability.field.MpduDensity = 0; ++ pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; //32; ++ pAd->CommonCfg.BACapability.field.TxBAWinLimit = 64; //32; ++ DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit. BACapability = 0x%x\n", pAd->CommonCfg.BACapability.word)); ++ ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ BATableInit(pAd, &pAd->BATable); ++ ++ pAd->CommonCfg.bExtChannelSwitchAnnouncement = 1; ++ pAd->CommonCfg.bHTProtect = 1; ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ pAd->CommonCfg.bBADecline = FALSE; ++ pAd->CommonCfg.bDisableReordering = FALSE; ++ ++ pAd->CommonCfg.TxBASize = 7; ++ ++ pAd->CommonCfg.REGBACapability.word = pAd->CommonCfg.BACapability.word; ++#endif // DOT11_N_SUPPORT // ++ ++ //pAd->CommonCfg.HTPhyMode.field.BW = BW_20; ++ //pAd->CommonCfg.HTPhyMode.field.MCS = MCS_AUTO; ++ //pAd->CommonCfg.HTPhyMode.field.ShortGI = GI_800; ++ //pAd->CommonCfg.HTPhyMode.field.STBC = STBC_NONE; ++ pAd->CommonCfg.TxRate = RATE_6; ++ ++ pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.BW = BW_20; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ ++ pAd->CommonCfg.BeaconPeriod = 100; // in mSec ++ ++ // ++ // part II. intialize STA specific configuration ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_DIRECT); ++ RX_FILTER_CLEAR_FLAG(pAd, fRX_FILTER_ACCEPT_MULTICAST); ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_BROADCAST); ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_ALL_MULTICAST); ++ ++ pAd->StaCfg.Psm = PWR_ACTIVE; ++ ++ pAd->StaCfg.OrigWepStatus = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.PairCipher = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.GroupCipher = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.bMixCipher = FALSE; ++ pAd->StaCfg.DefaultKeyId = 0; ++ ++ // 802.1x port control ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.LastMicErrorTime = 0; ++ pAd->StaCfg.MicErrCnt = 0; ++ pAd->StaCfg.bBlockAssoc = FALSE; ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ ++ pAd->CommonCfg.NdisRadioStateOff = FALSE; // New to support microsoft disable radio with OID command ++ ++ pAd->StaCfg.RssiTrigger = 0; ++ NdisZeroMemory(&pAd->StaCfg.RssiSample, sizeof(RSSI_SAMPLE)); ++ pAd->StaCfg.RssiTriggerMode = RSSI_TRIGGERED_UPON_BELOW_THRESHOLD; ++ pAd->StaCfg.AtimWin = 0; ++ pAd->StaCfg.DefaultListenCount = 3;//default listen count; ++ pAd->StaCfg.BssType = BSS_INFRA; // BSS_INFRA or BSS_ADHOC or BSS_MONITOR ++ pAd->StaCfg.bScanReqIsFromWebUI = FALSE; ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); ++ ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ } ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ pAd->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ ++ // global variables mXXXX used in MAC protocol state machines ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ ++ // PHY specification ++ pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; // default PHY mode ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); // CCK use LONG preamble ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // user desired power mode ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.bWindowsACCAMEnable = FALSE; ++ ++#ifdef LEAP_SUPPORT ++ // CCX v1.0 releated init value ++ RTMPInitTimer(pAd, &pAd->StaCfg.LeapAuthTimer, GET_TIMER_FUNCTION(LeapAuthTimeout), pAd, FALSE); ++ pAd->StaCfg.LeapAuthMode = CISCO_AuthModeLEAPNone; ++ pAd->StaCfg.bCkipOn = FALSE; ++#endif // LEAP_SUPPORT // ++ ++ RTMPInitTimer(pAd, &pAd->StaCfg.StaQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(StaQuickResponeForRateUpExec), pAd, FALSE); ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; ++ ++ // Patch for Ndtest ++ pAd->StaCfg.ScanCnt = 0; ++ ++ // CCX 2.0 control flag init ++ pAd->StaCfg.CCXEnable = FALSE; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; ++ pAd->StaCfg.CCXQosECWMin = 4; ++ pAd->StaCfg.CCXQosECWMax = 10; ++ ++ pAd->StaCfg.bHwRadio = TRUE; // Default Hardware Radio status is On ++ pAd->StaCfg.bSwRadio = TRUE; // Default Software Radio status is On ++ pAd->StaCfg.bRadio = TRUE; // bHwRadio && bSwRadio ++ pAd->StaCfg.bHardwareRadio = FALSE; // Default is OFF ++ pAd->StaCfg.bShowHiddenSSID = FALSE; // Default no show ++ ++ // Nitro mode control ++ pAd->StaCfg.bAutoReconnect = TRUE; ++ ++ // Save the init time as last scan time, the system should do scan after 2 seconds. ++ // This patch is for driver wake up from standby mode, system will do scan right away. ++ pAd->StaCfg.LastScanTime = 0; ++ NdisZeroMemory(pAd->nickname, IW_ESSID_MAX_SIZE+1); ++ sprintf(pAd->nickname, "%s", STA_NIC_DEVICE_NAME); ++ RTMPInitTimer(pAd, &pAd->StaCfg.WpaDisassocAndBlockAssocTimer, GET_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc), pAd, FALSE); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAd->StaCfg.IEEE8021X = FALSE; ++ pAd->StaCfg.IEEE8021x_required_keys = FALSE; ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Default for extra information is not valid ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ ++ // Default Config change flag ++ pAd->bConfigChanged = FALSE; ++ ++ // ++ // part III. AP configurations ++ // ++ ++ ++ // ++ // part IV. others ++ // ++ // dynamic BBP R66:sensibity tuning to overcome background noise ++ pAd->BbpTuning.bEnable = TRUE; ++ pAd->BbpTuning.FalseCcaLowerThreshold = 100; ++ pAd->BbpTuning.FalseCcaUpperThreshold = 512; ++ pAd->BbpTuning.R66Delta = 4; ++ pAd->Mlme.bEnableAutoAntennaCheck = TRUE; ++ ++ // ++ // Also initial R66CurrentValue, RTUSBResumeMsduTransmission might use this value. ++ // if not initial this value, the default value will be 0. ++ // ++ pAd->BbpTuning.R66CurrentValue = 0x38; ++ ++ pAd->Bbp94 = BBPR94_DEFAULT; ++ pAd->BbpForCCK = FALSE; ++ ++ // Default is FALSE for test bit 1 ++ //pAd->bTest1 = FALSE; ++ ++ // initialize MAC table and allocate spin lock ++ NdisZeroMemory(&pAd->MacTab, sizeof(MAC_TABLE)); ++ InitializeQueueHeader(&pAd->MacTab.McastPsQueue); ++ NdisAllocateSpinLock(&pAd->MacTabLock); ++ ++ //RTMPInitTimer(pAd, &pAd->RECBATimer, RECBATimerTimeout, pAd, TRUE); ++ //RTMPSetTimer(&pAd->RECBATimer, REORDER_EXEC_INTV); ++ ++#ifdef RALINK_ATE ++ NdisZeroMemory(&pAd->ate, sizeof(ATE_INFO)); ++ pAd->ate.Mode = ATE_STOP; ++ pAd->ate.TxCount = 200;/* to exceed TX_RING_SIZE ... */ ++ pAd->ate.TxLength = 1024; ++ pAd->ate.TxWI.ShortGI = 0;// LONG GI : 800 ns ++ pAd->ate.TxWI.PHYMODE = MODE_CCK; ++ pAd->ate.TxWI.MCS = 3; ++ pAd->ate.TxWI.BW = BW_20; ++ pAd->ate.Channel = 1; ++ pAd->ate.QID = QID_AC_BE; ++ pAd->ate.Addr1[0] = 0x00; ++ pAd->ate.Addr1[1] = 0x11; ++ pAd->ate.Addr1[2] = 0x22; ++ pAd->ate.Addr1[3] = 0xAA; ++ pAd->ate.Addr1[4] = 0xBB; ++ pAd->ate.Addr1[5] = 0xCC; ++ NdisMoveMemory(pAd->ate.Addr2, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ NdisMoveMemory(pAd->ate.Addr3, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ pAd->ate.bRxFer = 0; ++ pAd->ate.bQATxStart = FALSE; ++ pAd->ate.bQARxStart = FALSE; ++#ifdef RALINK_28xx_QA ++ //pAd->ate.Repeat = 0; ++ pAd->ate.TxStatus = 0; ++ pAd->ate.AtePid = THREAD_PID_INIT_VALUE; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++ ++ pAd->CommonCfg.bWiFiTest = FALSE; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); ++} ++ ++// IRQL = PASSIVE_LEVEL ++UCHAR BtoH(char ch) ++{ ++ if (ch >= '0' && ch <= '9') return (ch - '0'); // Handle numerals ++ if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA); // Handle capitol hex digits ++ if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA); // Handle small hex digits ++ return(255); ++} ++ ++// ++// FUNCTION: AtoH(char *, UCHAR *, int) ++// ++// PURPOSE: Converts ascii string to network order hex ++// ++// PARAMETERS: ++// src - pointer to input ascii string ++// dest - pointer to output hex ++// destlen - size of dest ++// ++// COMMENTS: ++// ++// 2 ascii bytes make a hex byte so must put 1st ascii byte of pair ++// into upper nibble and 2nd ascii byte of pair into lower nibble. ++// ++// IRQL = PASSIVE_LEVEL ++ ++void AtoH(char * src, UCHAR * dest, int destlen) ++{ ++ char * srcptr; ++ PUCHAR destTemp; ++ ++ srcptr = src; ++ destTemp = (PUCHAR) dest; ++ ++ while(destlen--) ++ { ++ *destTemp = BtoH(*srcptr++) << 4; // Put 1st ascii byte in upper nibble. ++ *destTemp += BtoH(*srcptr++); // Add 2nd ascii byte to above. ++ destTemp++; ++ } ++} ++ ++VOID RTMPPatchMacBbpBug( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG Index; ++ ++ // Initialize BBP register to default value ++ for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, (UCHAR)BBPRegTable[Index].Value); ++ } ++ ++ // Initialize RF register to default value ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // Re-init BBP register from EEPROM value ++ NICInitAsicFromEEPROM(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTimer Timer structure ++ pTimerFunc Function to execute when timer expired ++ Repeat Ture for period timer ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitTimer( ++ IN PRTMP_ADAPTER pAd, ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN PVOID pTimerFunc, ++ IN PVOID pData, ++ IN BOOLEAN Repeat) ++{ ++ // ++ // Set Valid to TRUE for later used. ++ // It will crash if we cancel a timer or set a timer ++ // that we haven't initialize before. ++ // ++ pTimer->Valid = TRUE; ++ ++ pTimer->PeriodicType = Repeat; ++ pTimer->State = FALSE; ++ pTimer->cookie = (ULONG) pData; ++ ++#ifdef RT2870 ++ pTimer->pAd = pAd; ++#endif // RT2870 // ++ ++ RTMP_OS_Init_Timer(pAd, &pTimer->TimerObj, pTimerFunc, (PVOID) pTimer); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pTimer Timer structure ++ Value Timer value in milliseconds ++ ++ Return Value: ++ None ++ ++ Note: ++ To use this routine, must call RTMPInitTimer before. ++ ++ ======================================================================== ++*/ ++VOID RTMPSetTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value) ++{ ++ if (pTimer->Valid) ++ { ++ pTimer->TimerValue = Value; ++ pTimer->State = FALSE; ++ if (pTimer->PeriodicType == TRUE) ++ { ++ pTimer->Repeat = TRUE; ++ RTMP_SetPeriodicTimer(&pTimer->TimerObj, Value); ++ } ++ else ++ { ++ pTimer->Repeat = FALSE; ++ RTMP_OS_Add_Timer(&pTimer->TimerObj, Value); ++ } ++ } ++ else ++ { ++ DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pTimer Timer structure ++ Value Timer value in milliseconds ++ ++ Return Value: ++ None ++ ++ Note: ++ To use this routine, must call RTMPInitTimer before. ++ ++ ======================================================================== ++*/ ++VOID RTMPModTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value) ++{ ++ BOOLEAN Cancel; ++ ++ if (pTimer->Valid) ++ { ++ pTimer->TimerValue = Value; ++ pTimer->State = FALSE; ++ if (pTimer->PeriodicType == TRUE) ++ { ++ RTMPCancelTimer(pTimer, &Cancel); ++ RTMPSetTimer(pTimer, Value); ++ } ++ else ++ { ++ RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value); ++ } ++ } ++ else ++ { ++ DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Cancel timer objects ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ 1.) To use this routine, must call RTMPInitTimer before. ++ 2.) Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID RTMPCancelTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ OUT BOOLEAN *pCancelled) ++{ ++ if (pTimer->Valid) ++ { ++ if (pTimer->State == FALSE) ++ pTimer->Repeat = FALSE; ++ RTMP_OS_Del_Timer(&pTimer->TimerObj, pCancelled); ++ ++ if (*pCancelled == TRUE) ++ pTimer->State = TRUE; ++ ++#ifdef RT2870 ++ // We need to go-through the TimerQ to findout this timer handler and remove it if ++ // it's still waiting for execution. ++ ++ RT2870_TimerQ_Remove(pTimer->pAd, pTimer); ++#endif // RT2870 // ++ } ++ else ++ { ++ // ++ // NdisMCancelTimer just canced the timer and not mean release the timer. ++ // And don't set the "Valid" to False. So that we can use this timer again. ++ // ++ DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set LED Status ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Status LED Status ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSetLED( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Status) ++{ ++ //ULONG data; ++ UCHAR HighByte = 0; ++ UCHAR LowByte; ++ ++// In ATE mode of RT2860 AP/STA, we have erased 8051 firmware. ++// So LED mode is not supported when ATE is running. ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ LowByte = pAd->LedCntl.field.LedMode&0x7f; ++ switch (Status) ++ { ++ case LED_LINK_DOWN: ++ HighByte = 0x20; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ pAd->LedIndicatorStregth = 0; ++ break; ++ case LED_LINK_UP: ++ if (pAd->CommonCfg.Channel > 14) ++ HighByte = 0xa0; ++ else ++ HighByte = 0x60; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_RADIO_ON: ++ HighByte = 0x20; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_HALT: ++ LowByte = 0; // Driver sets MAC register and MAC controls LED ++ case LED_RADIO_OFF: ++ HighByte = 0; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_WPS: ++ HighByte = 0x10; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_ON_SITE_SURVEY: ++ HighByte = 0x08; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_POWER_UP: ++ HighByte = 0x04; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetLED::Unknown Status %d\n", Status)); ++ break; ++ } ++ ++ // ++ // Keep LED status for LED SiteSurvey mode. ++ // After SiteSurvey, we will set the LED mode to previous status. ++ // ++ if ((Status != LED_ON_SITE_SURVEY) && (Status != LED_POWER_UP)) ++ pAd->LedStatus = Status; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetLED::Mode=%d,HighByte=0x%02x,LowByte=0x%02x\n", pAd->LedCntl.field.LedMode, HighByte, LowByte)); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set LED Signal Stregth ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Dbm Signal Stregth ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Can be run on any IRQL level. ++ ++ According to Microsoft Zero Config Wireless Signal Stregth definition as belows. ++ <= -90 No Signal ++ <= -81 Very Low ++ <= -71 Low ++ <= -67 Good ++ <= -57 Very Good ++ > -57 Excellent ++ ======================================================================== ++*/ ++VOID RTMPSetSignalLED( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_802_11_RSSI Dbm) ++{ ++ UCHAR nLed = 0; ++ ++ // ++ // if not Signal Stregth, then do nothing. ++ // ++ if (pAd->LedCntl.field.LedMode != LED_MODE_SIGNAL_STREGTH) ++ { ++ return; ++ } ++ ++ if (Dbm <= -90) ++ nLed = 0; ++ else if (Dbm <= -81) ++ nLed = 1; ++ else if (Dbm <= -71) ++ nLed = 3; ++ else if (Dbm <= -67) ++ nLed = 7; ++ else if (Dbm <= -57) ++ nLed = 15; ++ else ++ nLed = 31; ++ ++ // ++ // Update Signal Stregth to firmware if changed. ++ // ++ if (pAd->LedIndicatorStregth != nLed) ++ { ++ AsicSendCommandToMcu(pAd, 0x51, 0xff, nLed, pAd->LedCntl.field.Polarity); ++ pAd->LedIndicatorStregth = nLed; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Enable RX ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL <= DISPATCH_LEVEL ++ ++ Note: ++ Before Enable RX, make sure you have enabled Interrupt. ++ ======================================================================== ++*/ ++VOID RTMPEnableRxTx( ++ IN PRTMP_ADAPTER pAd) ++{ ++// WPDMA_GLO_CFG_STRUC GloCfg; ++// ULONG i = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPEnableRxTx\n")); ++ ++#if 0 ++ // Enable Rx DMA. ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i <200); ++ ++ RTMPusecDelay(50); ++ RT28XX_DMA_WRITE_INIT(GloCfg); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ RT28XX_DMA_POST_WRITE(pAd); ++#else ++ // Enable Rx DMA. ++ RT28XXDMAEnable(pAd); ++#endif ++ ++ // enable RX of MAC block ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ UINT32 rx_filter_flag = APNORMAL; ++ ++ ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, rx_filter_flag); // enable RX of DMA block ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ } ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPEnableRxTx\n")); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/rtmp_tkip.c +@@ -0,0 +1,1613 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_tkip.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Wu 02-25-02 Initial ++*/ ++ ++#include "../rt_config.h" ++ ++// Rotation functions on 32 bit values ++#define ROL32( A, n ) \ ++ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) ++#define ROR32( A, n ) ROL32( (A), 32-(n) ) ++ ++UINT Tkip_Sbox_Lower[256] = ++{ ++ 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, ++ 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, ++ 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, ++ 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, ++ 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, ++ 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, ++ 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, ++ 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, ++ 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, ++ 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, ++ 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, ++ 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, ++ 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, ++ 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, ++ 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, ++ 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, ++ 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, ++ 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, ++ 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, ++ 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, ++ 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, ++ 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, ++ 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, ++ 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, ++ 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, ++ 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, ++ 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, ++ 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, ++ 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, ++ 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, ++ 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, ++ 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A ++}; ++ ++UINT Tkip_Sbox_Upper[256] = ++{ ++ 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, ++ 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, ++ 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, ++ 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, ++ 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, ++ 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, ++ 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, ++ 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, ++ 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, ++ 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, ++ 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, ++ 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, ++ 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, ++ 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, ++ 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, ++ 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, ++ 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, ++ 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, ++ 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, ++ 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, ++ 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, ++ 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, ++ 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, ++ 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, ++ 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, ++ 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, ++ 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, ++ 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, ++ 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, ++ 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, ++ 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, ++ 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C ++}; ++ ++/*****************************/ ++/******** SBOX Table *********/ ++/*****************************/ ++ ++UCHAR SboxTable[256] = ++{ ++ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, ++ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, ++ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, ++ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, ++ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, ++ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, ++ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, ++ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, ++ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, ++ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, ++ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, ++ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, ++ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, ++ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, ++ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, ++ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, ++ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, ++ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, ++ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, ++ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, ++ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, ++ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, ++ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, ++ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, ++ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, ++ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, ++ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, ++ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, ++ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, ++ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, ++ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, ++ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++}; ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round); ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a); ++// ++// Expanded IV for TKIP function. ++// ++typedef struct PACKED _IV_CONTROL_ ++{ ++ union PACKED ++ { ++ struct PACKED ++ { ++ UCHAR rc0; ++ UCHAR rc1; ++ UCHAR rc2; ++ ++ union PACKED ++ { ++ struct PACKED ++ { ++#ifdef RT_BIG_ENDIAN ++ UCHAR KeyID:2; ++ UCHAR ExtIV:1; ++ UCHAR Rsvd:5; ++#else ++ UCHAR Rsvd:5; ++ UCHAR ExtIV:1; ++ UCHAR KeyID:2; ++#endif ++ } field; ++ UCHAR Byte; ++ } CONTROL; ++ } field; ++ ++ ULONG word; ++ } IV16; ++ ++ ULONG IV32; ++} TKIP_IV, *PTKIP_IV; ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Convert from UCHAR[] to ULONG in a portable way ++ ++ Arguments: ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPTkipGetUInt32( ++ IN PUCHAR pMICKey) ++{ ++ ULONG res = 0; ++ INT i; ++ ++ for (i = 0; i < 4; i++) ++ { ++ res |= (*pMICKey++) << (8 * i); ++ } ++ ++ return res; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Convert from ULONG to UCHAR[] in a portable way ++ ++ Arguments: ++ pDst pointer to destination for convert ULONG to UCHAR[] ++ val the value for convert ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipPutUInt32( ++ IN OUT PUCHAR pDst, ++ IN ULONG val) ++{ ++ INT i; ++ ++ for(i = 0; i < 4; i++) ++ { ++ *pDst++ = (UCHAR) (val & 0xff); ++ val >>= 8; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set the MIC Key. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipSetMICKey( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pMICKey) ++{ ++ // Set the key ++ pTkip->K0 = RTMPTkipGetUInt32(pMICKey); ++ pTkip->K1 = RTMPTkipGetUInt32(pMICKey + 4); ++ // and reset the message ++ pTkip->L = pTkip->K0; ++ pTkip->R = pTkip->K1; ++ pTkip->nBytesInM = 0; ++ pTkip->M = 0; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ uChar Append this uChar ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipAppendByte( ++ IN PTKIP_KEY_INFO pTkip, ++ IN UCHAR uChar) ++{ ++ // Append the byte to our word-sized buffer ++ pTkip->M |= (uChar << (8* pTkip->nBytesInM)); ++ pTkip->nBytesInM++; ++ // Process the word if it is full. ++ if( pTkip->nBytesInM >= 4 ) ++ { ++ pTkip->L ^= pTkip->M; ++ pTkip->R ^= ROL32( pTkip->L, 17 ); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ((pTkip->L & 0xff00ff00) >> 8) | ((pTkip->L & 0x00ff00ff) << 8); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ROL32( pTkip->L, 3 ); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ROR32( pTkip->L, 2 ); ++ pTkip->L += pTkip->R; ++ // Clear the buffer ++ pTkip->M = 0; ++ pTkip->nBytesInM = 0; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to source data for Calculate MIC Value ++ Len Indicate the length of the source data ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipAppend( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pSrc, ++ IN UINT nBytes) ++{ ++ // This is simple ++ while(nBytes > 0) ++ { ++ RTMPTkipAppendByte(pTkip, *pSrc++); ++ nBytes--; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ the MIC Value is store in pAd->PrivateInfo.MIC ++ ======================================================================== ++*/ ++VOID RTMPTkipGetMIC( ++ IN PTKIP_KEY_INFO pTkip) ++{ ++ // Append the minimum padding ++ RTMPTkipAppendByte(pTkip, 0x5a ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ // and then zeroes until the length is a multiple of 4 ++ while( pTkip->nBytesInM != 0 ) ++ { ++ RTMPTkipAppendByte(pTkip, 0 ); ++ } ++ // The appendByte function has already computed the result. ++ RTMPTkipPutUInt32(pTkip->MIC, pTkip->L); ++ RTMPTkipPutUInt32(pTkip->MIC + 4, pTkip->R); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init Tkip function. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. ++ KeyId TK Key ID ++ pTA Pointer to transmitter address ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitTkipEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN PUCHAR pTA, ++ IN PUCHAR pMICKey, ++ IN PUCHAR pTSC, ++ OUT PULONG pIV16, ++ OUT PULONG pIV32) ++{ ++ TKIP_IV tkipIv; ++ ++ // Prepare 8 bytes TKIP encapsulation for MPDU ++ NdisZeroMemory(&tkipIv, sizeof(TKIP_IV)); ++ tkipIv.IV16.field.rc0 = *(pTSC + 1); ++ tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; ++ tkipIv.IV16.field.rc2 = *pTSC; ++ tkipIv.IV16.field.CONTROL.field.ExtIV = 1; // 0: non-extended IV, 1: an extended IV ++ tkipIv.IV16.field.CONTROL.field.KeyID = KeyId; ++// tkipIv.IV32 = *(PULONG)(pTSC + 2); ++ NdisMoveMemory(&tkipIv.IV32, (pTSC + 2), 4); // Copy IV ++ ++ *pIV16 = tkipIv.IV16.word; ++ *pIV32 = tkipIv.IV32; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init MIC Value calculation function which include set MIC key & ++ calculate first 16 bytes (DA + SA + priority + 0) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitMICEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN UCHAR UserPriority, ++ IN PUCHAR pMICKey) ++{ ++ ULONG Priority = UserPriority; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Tx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, (PUCHAR)&Priority, 4); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare MIC value of received MSDU ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to the received Plain text data ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ Len the length of the received plain text data exclude MIC value ++ ++ Return Value: ++ TRUE MIC value matched ++ FALSE MIC value mismatched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPTkipCompareMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UCHAR UserPriority, ++ IN UINT Len) ++{ ++ UCHAR OldMic[8]; ++ ULONG Priority = UserPriority; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); ++ ++ // Calculate MIC value from plain text data ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); ++ ++ // Get MIC valude from received frame ++ NdisMoveMemory(OldMic, pSrc + Len, 8); ++ ++ // Get MIC value from decrypted plain data ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); ++ ++ // Move MIC value from MSDU, this steps should move to data path. ++ // Since the MIC value might cross MPDUs. ++ if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValue(): TKIP MIC Error !\n")); //MIC error. ++ ++ ++ return (FALSE); ++ } ++ return (TRUE); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare MIC value of received MSDU ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pLLC LLC header ++ pSrc Pointer to the received Plain text data ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ Len the length of the received plain text data exclude MIC value ++ ++ Return Value: ++ TRUE MIC value matched ++ FALSE MIC value mismatched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPTkipCompareMICValueWithLLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pLLC, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UINT Len) ++{ ++ UCHAR OldMic[8]; ++ ULONG Priority = 0; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); ++ ++ // Start with LLC header ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pLLC, 8); ++ ++ // Calculate MIC value from plain text data ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); ++ ++ // Get MIC valude from received frame ++ NdisMoveMemory(OldMic, pSrc + Len, 8); ++ ++ // Get MIC value from decrypted plain data ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); ++ ++ // Move MIC value from MSDU, this steps should move to data path. ++ // Since the MIC value might cross MPDUs. ++ if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValueWithLLC(): TKIP MIC Error !\n")); //MIC error. ++ ++ ++ return (FALSE); ++ } ++ return (TRUE); ++} ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware transmit function ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to Ndis Packet for MIC calculation ++ pEncap Pointer to LLC encap data ++ LenEncap Total encap length, might be 0 which indicates no encap ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPCalculateMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pEncap, ++ IN PCIPHER_KEY pKey, ++ IN UCHAR apidx) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PUCHAR pSrc; ++ UCHAR UserPriority; ++ UCHAR vlan_offset = 0; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ UserPriority = RTMP_GET_PACKET_UP(pPacket); ++ pSrc = pSrcBufVA; ++ ++ // determine if this is a vlan packet ++ if (((*(pSrc + 12) << 8) + *(pSrc + 13)) == 0x8100) ++ vlan_offset = 4; ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ { ++ RTMPInitMICEngine( ++ pAd, ++ pKey->Key, ++ pSrc, ++ pSrc + 6, ++ UserPriority, ++ pKey->TxMic); ++ } ++ ++ ++ if (pEncap != NULL) ++ { ++ // LLC encapsulation ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pEncap, 6); ++ // Protocol Type ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc + 12 + vlan_offset, 2); ++ } ++ SrcBufLen -= (14 + vlan_offset); ++ pSrc += (14 + vlan_offset); ++ do ++ { ++ if (SrcBufLen > 0) ++ { ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc, SrcBufLen); ++ } ++ ++ break; // No need handle next packet ++ ++ } while (TRUE); // End of copying payload ++ ++ // Compute the final MIC Value ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); ++} ++ ++ ++/************************************************************/ ++/* tkip_sbox() */ ++/* Returns a 16 bit value from a 64K entry table. The Table */ ++/* is synthesized from two 256 entry byte wide tables. */ ++/************************************************************/ ++ ++UINT tkip_sbox(UINT index) ++{ ++ UINT index_low; ++ UINT index_high; ++ UINT left, right; ++ ++ index_low = (index % 256); ++ index_high = ((index >> 8) % 256); ++ ++ left = Tkip_Sbox_Lower[index_low] + (Tkip_Sbox_Upper[index_low] * 256); ++ right = Tkip_Sbox_Upper[index_high] + (Tkip_Sbox_Lower[index_high] * 256); ++ ++ return (left ^ right); ++} ++ ++UINT rotr1(UINT a) ++{ ++ unsigned int b; ++ ++ if ((a & 0x01) == 0x01) ++ { ++ b = (a >> 1) | 0x8000; ++ } ++ else ++ { ++ b = (a >> 1) & 0x7fff; ++ } ++ b = b % 65536; ++ return b; ++} ++ ++VOID RTMPTkipMixKey( ++ UCHAR *key, ++ UCHAR *ta, ++ ULONG pnl, /* Least significant 16 bits of PN */ ++ ULONG pnh, /* Most significant 32 bits of PN */ ++ UCHAR *rc4key, ++ UINT *p1k) ++{ ++ ++ UINT tsc0; ++ UINT tsc1; ++ UINT tsc2; ++ ++ UINT ppk0; ++ UINT ppk1; ++ UINT ppk2; ++ UINT ppk3; ++ UINT ppk4; ++ UINT ppk5; ++ ++ INT i; ++ INT j; ++ ++ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ ++ tsc1 = (unsigned int)(pnh % 65536); ++ tsc2 = (unsigned int)(pnl % 65536); /* lsb */ ++ ++ /* Phase 1, step 1 */ ++ p1k[0] = tsc1; ++ p1k[1] = tsc0; ++ p1k[2] = (UINT)(ta[0] + (ta[1]*256)); ++ p1k[3] = (UINT)(ta[2] + (ta[3]*256)); ++ p1k[4] = (UINT)(ta[4] + (ta[5]*256)); ++ ++ /* Phase 1, step 2 */ ++ for (i=0; i<8; i++) ++ { ++ j = 2*(i & 1); ++ p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*key[1+j]) + key[j])) % 65536 )) % 65536; ++ p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*key[5+j]) + key[4+j])) % 65536 )) % 65536; ++ p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*key[9+j]) + key[8+j])) % 65536 )) % 65536; ++ p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*key[13+j]) + key[12+j])) % 65536 )) % 65536; ++ p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*key[1+j]) + key[j]))) % 65536 )) % 65536; ++ p1k[4] = (p1k[4] + i) % 65536; ++ } ++ ++ /* Phase 2, Step 1 */ ++ ppk0 = p1k[0]; ++ ppk1 = p1k[1]; ++ ppk2 = p1k[2]; ++ ppk3 = p1k[3]; ++ ppk4 = p1k[4]; ++ ppk5 = (p1k[4] + tsc2) % 65536; ++ ++ /* Phase2, Step 2 */ ++ ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*key[1]) + key[0])) % 65536); ++ ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*key[3]) + key[2])) % 65536); ++ ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*key[5]) + key[4])) % 65536); ++ ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*key[7]) + key[6])) % 65536); ++ ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*key[9]) + key[8])) % 65536); ++ ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*key[11]) + key[10])) % 65536); ++ ++ ppk0 = ppk0 + rotr1(ppk5 ^ ((256*key[13]) + key[12])); ++ ppk1 = ppk1 + rotr1(ppk0 ^ ((256*key[15]) + key[14])); ++ ppk2 = ppk2 + rotr1(ppk1); ++ ppk3 = ppk3 + rotr1(ppk2); ++ ppk4 = ppk4 + rotr1(ppk3); ++ ppk5 = ppk5 + rotr1(ppk4); ++ ++ /* Phase 2, Step 3 */ ++ /* Phase 2, Step 3 */ ++ ++ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ ++ tsc1 = (unsigned int)(pnh % 65536); ++ tsc2 = (unsigned int)(pnl % 65536); /* lsb */ ++ ++ rc4key[0] = (tsc2 >> 8) % 256; ++ rc4key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f; ++ rc4key[2] = tsc2 % 256; ++ rc4key[3] = ((ppk5 ^ ((256*key[1]) + key[0])) >> 1) % 256; ++ ++ rc4key[4] = ppk0 % 256; ++ rc4key[5] = (ppk0 >> 8) % 256; ++ ++ rc4key[6] = ppk1 % 256; ++ rc4key[7] = (ppk1 >> 8) % 256; ++ ++ rc4key[8] = ppk2 % 256; ++ rc4key[9] = (ppk2 >> 8) % 256; ++ ++ rc4key[10] = ppk3 % 256; ++ rc4key[11] = (ppk3 >> 8) % 256; ++ ++ rc4key[12] = ppk4 % 256; ++ rc4key[13] = (ppk4 >> 8) % 256; ++ ++ rc4key[14] = ppk5 % 256; ++ rc4key[15] = (ppk5 >> 8) % 256; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header1() */ ++/* Builds the first MIC header block from */ ++/* header fields. */ ++/************************************************/ ++ ++void construct_mic_header1( ++ unsigned char *mic_header1, ++ int header_length, ++ unsigned char *mpdu) ++{ ++ mic_header1[0] = (unsigned char)((header_length - 2) / 256); ++ mic_header1[1] = (unsigned char)((header_length - 2) % 256); ++ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ ++ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ ++ mic_header1[4] = mpdu[4]; /* A1 */ ++ mic_header1[5] = mpdu[5]; ++ mic_header1[6] = mpdu[6]; ++ mic_header1[7] = mpdu[7]; ++ mic_header1[8] = mpdu[8]; ++ mic_header1[9] = mpdu[9]; ++ mic_header1[10] = mpdu[10]; /* A2 */ ++ mic_header1[11] = mpdu[11]; ++ mic_header1[12] = mpdu[12]; ++ mic_header1[13] = mpdu[13]; ++ mic_header1[14] = mpdu[14]; ++ mic_header1[15] = mpdu[15]; ++} ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++ ++void construct_mic_header2( ++ unsigned char *mic_header2, ++ unsigned char *mpdu, ++ int a4_exists, ++ int qc_exists) ++{ ++ int i; ++ ++ for (i = 0; i<16; i++) mic_header2[i]=0x00; ++ ++ mic_header2[0] = mpdu[16]; /* A3 */ ++ mic_header2[1] = mpdu[17]; ++ mic_header2[2] = mpdu[18]; ++ mic_header2[3] = mpdu[19]; ++ mic_header2[4] = mpdu[20]; ++ mic_header2[5] = mpdu[21]; ++ ++ // In Sequence Control field, mute sequence numer bits (12-bit) ++ mic_header2[6] = mpdu[22] & 0x0f; /* SC */ ++ mic_header2[7] = 0x00; /* mpdu[23]; */ ++ ++ if ((!qc_exists) & a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ } ++ ++ if (qc_exists && (!a4_exists)) ++ { ++ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ ++ mic_header2[9] = mpdu[25] & 0x00; ++ } ++ ++ if (qc_exists && a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ mic_header2[14] = mpdu[30] & 0x0f; ++ mic_header2[15] = mpdu[31] & 0x00; ++ } ++} ++ ++ ++/************************************************/ ++/* construct_mic_iv() */ ++/* Builds the MIC IV from header fields and PN */ ++/************************************************/ ++ ++void construct_mic_iv( ++ unsigned char *mic_iv, ++ int qc_exists, ++ int a4_exists, ++ unsigned char *mpdu, ++ unsigned int payload_length, ++ unsigned char *pn_vector) ++{ ++ int i; ++ ++ mic_iv[0] = 0x59; ++ if (qc_exists && a4_exists) ++ mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ ++ if (qc_exists && !a4_exists) ++ mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ ++ if (!qc_exists) ++ mic_iv[1] = 0x00; ++ for (i = 2; i < 8; i++) ++ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ ++#ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ ++#else ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ ++#endif ++ i = (payload_length / 256); ++ i = (payload_length % 256); ++ mic_iv[14] = (unsigned char) (payload_length / 256); ++ mic_iv[15] = (unsigned char) (payload_length % 256); ++ ++} ++ ++ ++ ++/************************************/ ++/* bitwise_xor() */ ++/* A 128 bit, bitwise exclusive or */ ++/************************************/ ++ ++void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out) ++{ ++ int i; ++ for (i=0; i<16; i++) ++ { ++ out[i] = ina[i] ^ inb[i]; ++ } ++} ++ ++ ++void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext) ++{ ++ int round; ++ int i; ++ unsigned char intermediatea[16]; ++ unsigned char intermediateb[16]; ++ unsigned char round_key[16]; ++ ++ for(i=0; i<16; i++) round_key[i] = key[i]; ++ ++ for (round = 0; round < 11; round++) ++ { ++ if (round == 0) ++ { ++ xor_128(round_key, data, ciphertext); ++ next_key(round_key, round); ++ } ++ else if (round == 10) ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ xor_128(intermediateb, round_key, ciphertext); ++ } ++ else /* 1 - 9 */ ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ mix_column(&intermediateb[0], &intermediatea[0]); ++ mix_column(&intermediateb[4], &intermediatea[4]); ++ mix_column(&intermediateb[8], &intermediatea[8]); ++ mix_column(&intermediateb[12], &intermediatea[12]); ++ xor_128(intermediatea, round_key, ciphertext); ++ next_key(round_key, round); ++ } ++ } ++ ++} ++ ++void construct_ctr_preload( ++ unsigned char *ctr_preload, ++ int a4_exists, ++ int qc_exists, ++ unsigned char *mpdu, ++ unsigned char *pn_vector, ++ int c) ++{ ++ ++ int i = 0; ++ for (i=0; i<16; i++) ctr_preload[i] = 0x00; ++ i = 0; ++ ++ ctr_preload[0] = 0x01; /* flag */ ++ if (qc_exists && a4_exists) ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ ++ if (qc_exists && !a4_exists) ctr_preload[1] = mpdu[24] & 0x0f; ++ ++ for (i = 2; i < 8; i++) ++ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ ++#ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ ++#else ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ ++#endif ++ ctr_preload[14] = (unsigned char) (c / 256); // Ctr ++ ctr_preload[15] = (unsigned char) (c % 256); ++ ++} ++ ++ ++// ++// TRUE: Success! ++// FALSE: Decrypt Error! ++// ++BOOLEAN RTMPSoftDecryptTKIP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN UCHAR UserPriority, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ UCHAR KeyID; ++ UINT HeaderLen; ++ UCHAR fc0; ++ UCHAR fc1; ++ USHORT fc; ++ UINT frame_type; ++ UINT frame_subtype; ++ UINT from_ds; ++ UINT to_ds; ++ INT a4_exists; ++ INT qc_exists; ++ USHORT duration; ++ USHORT seq_control; ++ USHORT qos_control; ++ UCHAR TA[MAC_ADDR_LEN]; ++ UCHAR DA[MAC_ADDR_LEN]; ++ UCHAR SA[MAC_ADDR_LEN]; ++ UCHAR RC4Key[16]; ++ UINT p1k[5]; //for mix_key; ++ ULONG pnl;/* Least significant 16 bits of PN */ ++ ULONG pnh;/* Most significant 32 bits of PN */ ++ UINT num_blocks; ++ UINT payload_remainder; ++ ARCFOURCONTEXT ArcFourContext; ++ UINT crc32 = 0; ++ UINT trailfcs = 0; ++ UCHAR MIC[8]; ++ UCHAR TrailMIC[8]; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ fc0 = *pData; ++ fc1 = *(pData + 1); ++ ++ fc = *((PUSHORT)pData); ++ ++ frame_type = ((fc0 >> 2) & 0x03); ++ frame_subtype = ((fc0 >> 4) & 0x0f); ++ ++ from_ds = (fc1 & 0x2) >> 1; ++ to_ds = (fc1 & 0x1); ++ ++ a4_exists = (from_ds & to_ds); ++ qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ ++ (frame_subtype == 0x09) || /* Likely to change. */ ++ (frame_subtype == 0x0a) || ++ (frame_subtype == 0x0b) ++ ); ++ ++ HeaderLen = 24; ++ if (a4_exists) ++ HeaderLen += 6; ++ ++ KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); ++ KeyID = KeyID >> 6; ++ ++ if (pWpaKey[KeyID].KeyLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP failed!(KeyID[%d] Length can not be 0)\n", KeyID)); ++ return FALSE; ++ } ++ ++ duration = *((PUSHORT)(pData+2)); ++ ++ seq_control = *((PUSHORT)(pData+22)); ++ ++ if (qc_exists) ++ { ++ if (a4_exists) ++ { ++ qos_control = *((PUSHORT)(pData+30)); ++ } ++ else ++ { ++ qos_control = *((PUSHORT)(pData+24)); ++ } ++ } ++ ++ if (to_ds == 0 && from_ds == 1) ++ { ++ NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+16, MAC_ADDR_LEN); ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); //BSSID ++ } ++ else if (to_ds == 0 && from_ds == 0 ) ++ { ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); ++ } ++ else if (to_ds == 1 && from_ds == 0) ++ { ++ NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); ++ } ++ else if (to_ds == 1 && from_ds == 1) ++ { ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+22, MAC_ADDR_LEN); ++ } ++ ++ num_blocks = (DataByteCnt - 16) / 16; ++ payload_remainder = (DataByteCnt - 16) % 16; ++ ++ pnl = (*(pData + HeaderLen)) * 256 + *(pData + HeaderLen + 2); ++ pnh = *((PULONG)(pData + HeaderLen + 4)); ++ pnh = cpu2le32(pnh); ++ RTMPTkipMixKey(pWpaKey[KeyID].Key, TA, pnl, pnh, RC4Key, p1k); ++ ++ ARCFOUR_INIT(&ArcFourContext, RC4Key, 16); ++ ++ ARCFOUR_DECRYPT(&ArcFourContext, pData + HeaderLen, pData + HeaderLen + 8, DataByteCnt - HeaderLen - 8); ++ NdisMoveMemory(&trailfcs, pData + DataByteCnt - 8 - 4, 4); ++ crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 4); //Skip IV+EIV 8 bytes & Skip last 4 bytes(FCS). ++ crc32 ^= 0xffffffff; /* complement */ ++ ++ if(crc32 != cpu2le32(trailfcs)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP, WEP Data ICV Error !\n")); //ICV error. ++ ++ return (FALSE); ++ } ++ ++ NdisMoveMemory(TrailMIC, pData + DataByteCnt - 8 - 8 - 4, 8); ++ RTMPInitMICEngine(pAd, pWpaKey[KeyID].Key, DA, SA, UserPriority, pWpaKey[KeyID].RxMic); ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 12); ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); ++ NdisMoveMemory(MIC, pAd->PrivateInfo.Tx.MIC, 8); ++ ++ if (!NdisEqualMemory(MIC, TrailMIC, 8)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptTKIP, WEP Data MIC Error !\n")); //MIC error. ++ //RTMPReportMicError(pAd, &pWpaKey[KeyID]); // marked by AlbertY @ 20060630 ++ return (FALSE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ //DBGPRINT(RT_DEBUG_TRACE, "RTMPSoftDecryptTKIP Decript done!!\n"); ++ return TRUE; ++} ++ ++ ++ ++ ++BOOLEAN RTMPSoftDecryptAES( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ UCHAR KeyID; ++ UINT HeaderLen; ++ UCHAR PN[6]; ++ UINT payload_len; ++ UINT num_blocks; ++ UINT payload_remainder; ++ USHORT fc; ++ UCHAR fc0; ++ UCHAR fc1; ++ UINT frame_type; ++ UINT frame_subtype; ++ UINT from_ds; ++ UINT to_ds; ++ INT a4_exists; ++ INT qc_exists; ++ UCHAR aes_out[16]; ++ int payload_index; ++ UINT i; ++ UCHAR ctr_preload[16]; ++ UCHAR chain_buffer[16]; ++ UCHAR padded_buffer[16]; ++ UCHAR mic_iv[16]; ++ UCHAR mic_header1[16]; ++ UCHAR mic_header2[16]; ++ UCHAR MIC[8]; ++ UCHAR TrailMIC[8]; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ fc0 = *pData; ++ fc1 = *(pData + 1); ++ ++ fc = *((PUSHORT)pData); ++ ++ frame_type = ((fc0 >> 2) & 0x03); ++ frame_subtype = ((fc0 >> 4) & 0x0f); ++ ++ from_ds = (fc1 & 0x2) >> 1; ++ to_ds = (fc1 & 0x1); ++ ++ a4_exists = (from_ds & to_ds); ++ qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ ++ (frame_subtype == 0x09) || /* Likely to change. */ ++ (frame_subtype == 0x0a) || ++ (frame_subtype == 0x0b) ++ ); ++ ++ HeaderLen = 24; ++ if (a4_exists) ++ HeaderLen += 6; ++ ++ KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); ++ KeyID = KeyID >> 6; ++ ++ if (pWpaKey[KeyID].KeyLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptAES failed!(KeyID[%d] Length can not be 0)\n", KeyID)); ++ return FALSE; ++ } ++ ++ PN[0] = *(pData+ HeaderLen); ++ PN[1] = *(pData+ HeaderLen + 1); ++ PN[2] = *(pData+ HeaderLen + 4); ++ PN[3] = *(pData+ HeaderLen + 5); ++ PN[4] = *(pData+ HeaderLen + 6); ++ PN[5] = *(pData+ HeaderLen + 7); ++ ++ payload_len = DataByteCnt - HeaderLen - 8 - 8; // 8 bytes for CCMP header , 8 bytes for MIC ++ payload_remainder = (payload_len) % 16; ++ num_blocks = (payload_len) / 16; ++ ++ ++ ++ // Find start of payload ++ payload_index = HeaderLen + 8; //IV+EIV ++ ++ for (i=0; i< num_blocks; i++) ++ { ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ i+1 ); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, pData + payload_index, chain_buffer); ++ NdisMoveMemory(pData + payload_index - 8, chain_buffer, 16); ++ payload_index += 16; ++ } ++ ++ // ++ // If there is a short final block, then pad it ++ // encrypt it and copy the unpadded part back ++ // ++ if (payload_remainder > 0) ++ { ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ num_blocks + 1); ++ ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ NdisMoveMemory(pData + payload_index - 8, chain_buffer, payload_remainder); ++ payload_index += payload_remainder; ++ } ++ ++ // ++ // Descrypt the MIC ++ // ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ 0); ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, 8); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ ++ NdisMoveMemory(TrailMIC, chain_buffer, 8); ++ ++ // ++ // Calculate MIC ++ // ++ ++ //Force the protected frame bit on ++ *(pData + 1) = *(pData + 1) | 0x40; ++ ++ // Find start of payload ++ // Because the CCMP header has been removed ++ payload_index = HeaderLen; ++ ++ construct_mic_iv( ++ mic_iv, ++ qc_exists, ++ a4_exists, ++ pData, ++ payload_len, ++ PN); ++ ++ construct_mic_header1( ++ mic_header1, ++ HeaderLen, ++ pData); ++ ++ construct_mic_header2( ++ mic_header2, ++ pData, ++ a4_exists, ++ qc_exists); ++ ++ aes128k128d(pWpaKey[KeyID].Key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ ++ // iterate through each 16 byte payload block ++ for (i = 0; i < num_blocks; i++) ++ { ++ bitwise_xor(aes_out, pData + payload_index, chain_buffer); ++ payload_index += 16; ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ } ++ ++ // Add on the final payload block if it needs padding ++ if (payload_remainder > 0) ++ { ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ } ++ ++ // aes_out contains padded mic, discard most significant ++ // 8 bytes to generate 64 bit MIC ++ for (i = 0 ; i < 8; i++) MIC[i] = aes_out[i]; ++ ++ if (!NdisEqualMemory(MIC, TrailMIC, 8)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptAES, MIC Error !\n")); //MIC error. ++ return FALSE; ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ return TRUE; ++} ++ ++/****************************************/ ++/* aes128k128d() */ ++/* Performs a 128 bit AES encrypt with */ ++/* 128 bit data. */ ++/****************************************/ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0;i<16; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round) ++{ ++ UCHAR rcon; ++ UCHAR sbox_key[4]; ++ UCHAR rcon_table[12] = ++ { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++ 0x1b, 0x36, 0x36, 0x36 ++ }; ++ ++ sbox_key[0] = RTMPCkipSbox(key[13]); ++ sbox_key[1] = RTMPCkipSbox(key[14]); ++ sbox_key[2] = RTMPCkipSbox(key[15]); ++ sbox_key[3] = RTMPCkipSbox(key[12]); ++ ++ rcon = rcon_table[round]; ++ ++ xor_32(&key[0], sbox_key, &key[0]); ++ key[0] = key[0] ^ rcon; ++ ++ xor_32(&key[4], &key[0], &key[4]); ++ xor_32(&key[8], &key[4], &key[8]); ++ xor_32(&key[12], &key[8], &key[12]); ++} ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0;i<4; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0; i< 16; i++) ++ { ++ out[i] = RTMPCkipSbox(in[i]); ++ } ++} ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a) ++{ ++ return SboxTable[(int)a]; ++} ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ out[0] = in[0]; ++ out[1] = in[5]; ++ out[2] = in[10]; ++ out[3] = in[15]; ++ out[4] = in[4]; ++ out[5] = in[9]; ++ out[6] = in[14]; ++ out[7] = in[3]; ++ out[8] = in[8]; ++ out[9] = in[13]; ++ out[10] = in[2]; ++ out[11] = in[7]; ++ out[12] = in[12]; ++ out[13] = in[1]; ++ out[14] = in[6]; ++ out[15] = in[11]; ++} ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ INT i; ++ UCHAR add1b[4]; ++ UCHAR add1bf7[4]; ++ UCHAR rotl[4]; ++ UCHAR swap_halfs[4]; ++ UCHAR andf7[4]; ++ UCHAR rotr[4]; ++ UCHAR temp[4]; ++ UCHAR tempb[4]; ++ ++ for (i=0 ; i<4; i++) ++ { ++ if ((in[i] & 0x80)== 0x80) ++ add1b[i] = 0x1b; ++ else ++ add1b[i] = 0x00; ++ } ++ ++ swap_halfs[0] = in[2]; /* Swap halfs */ ++ swap_halfs[1] = in[3]; ++ swap_halfs[2] = in[0]; ++ swap_halfs[3] = in[1]; ++ ++ rotl[0] = in[3]; /* Rotate left 8 bits */ ++ rotl[1] = in[0]; ++ rotl[2] = in[1]; ++ rotl[3] = in[2]; ++ ++ andf7[0] = in[0] & 0x7f; ++ andf7[1] = in[1] & 0x7f; ++ andf7[2] = in[2] & 0x7f; ++ andf7[3] = in[3] & 0x7f; ++ ++ for (i = 3; i>0; i--) /* logical shift left 1 bit */ ++ { ++ andf7[i] = andf7[i] << 1; ++ if ((andf7[i-1] & 0x80) == 0x80) ++ { ++ andf7[i] = (andf7[i] | 0x01); ++ } ++ } ++ andf7[0] = andf7[0] << 1; ++ andf7[0] = andf7[0] & 0xfe; ++ ++ xor_32(add1b, andf7, add1bf7); ++ ++ xor_32(in, add1bf7, rotr); ++ ++ temp[0] = rotr[0]; /* Rotate right 8 bits */ ++ rotr[0] = rotr[1]; ++ rotr[1] = rotr[2]; ++ rotr[2] = rotr[3]; ++ rotr[3] = temp[0]; ++ ++ xor_32(add1bf7, rotr, temp); ++ xor_32(swap_halfs, rotl,tempb); ++ xor_32(temp, tempb, out); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/rtmp_wep.c +@@ -0,0 +1,508 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_wep.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Wu 10-28-02 Initial ++*/ ++ ++#include "../rt_config.h" ++ ++UINT FCSTAB_32[256] = ++{ ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, ++ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, ++ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ++ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, ++ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, ++ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, ++ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ++ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, ++ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, ++ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, ++ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, ++ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, ++ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, ++ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ++ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, ++ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, ++ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, ++ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ++ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, ++ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, ++ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, ++ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, ++ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ++ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, ++ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, ++ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, ++ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ++ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, ++ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, ++ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, ++ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, ++ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, ++ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, ++ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ++ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, ++ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, ++ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, ++ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ++ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, ++ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, ++ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, ++ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, ++ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ++ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ++}; ++ ++/* ++UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ */ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init WEP function. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pKey Pointer to the WEP KEY ++ KeyId WEP Key ID ++ KeyLen the length of WEP KEY ++ pDest Pointer to the destination which Encryption data will store in. ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitWepEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN UCHAR KeyLen, ++ IN OUT PUCHAR pDest) ++{ ++ UINT i; ++ UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ ++ pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10) && (pAd->OpMode == OPMODE_STA)) ++ { ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, pKey, KeyLen); //INIT SBOX, KEYLEN+3(IV) ++ NdisMoveMemory(pDest, pKey, 3); //Append Init Vector ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ NdisMoveMemory(WEPKEY + 3, pKey, KeyLen); ++ ++ for(i = 0; i < 3; i++) ++ WEPKEY[i] = RandomByte(pAd); //Call mlme RandomByte() function. ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, KeyLen + 3); //INIT SBOX, KEYLEN+3(IV) ++ ++ NdisMoveMemory(pDest, WEPKEY, 3); //Append Init Vector ++ } ++ *(pDest+3) = (KeyId << 6); //Append KEYID ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Encrypt transimitted data ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to the transimitted source data that will be encrypt ++ pDest Pointer to the destination where entryption data will be store in. ++ Len Indicate the length of the source data ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPEncryptData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDest, ++ IN UINT Len) ++{ ++ pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, pSrc, Len); ++ ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, pSrc, Len); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Decrypt received WEP data ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ pSrc Pointer to the received data ++ Len the length of the received data ++ ++ Return Value: ++ TRUE Decrypt WEP data success ++ FALSE Decrypt WEP data failed ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPSoftDecryptWEP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pGroupKey) ++{ ++ UINT trailfcs; ++ UINT crc32; ++ UCHAR KeyIdx; ++ UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ UCHAR *pPayload = (UCHAR *)pData + LENGTH_802_11; ++ ULONG payload_len = DataByteCnt - LENGTH_802_11; ++ ++ NdisMoveMemory(WEPKEY, pPayload, 3); //Get WEP IV ++ ++ KeyIdx = (*(pPayload + 3) & 0xc0) >> 6; ++ if (pGroupKey[KeyIdx].KeyLen == 0) ++ return (FALSE); ++ ++ NdisMoveMemory(WEPKEY + 3, pGroupKey[KeyIdx].Key, pGroupKey[KeyIdx].KeyLen); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, pGroupKey[KeyIdx].KeyLen + 3); ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, pPayload, pPayload + 4, payload_len - 4); ++ NdisMoveMemory(&trailfcs, pPayload + payload_len - 8, 4); ++ crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pPayload, payload_len - 8); //Skip last 4 bytes(FCS). ++ crc32 ^= 0xffffffff; /* complement */ ++ ++ if(crc32 != cpu2le32(trailfcs)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("! WEP Data CRC Error !\n")); //CRC error. ++ return (FALSE); ++ } ++ return (TRUE); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm "ARCFOUR" initialize ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pKey Pointer to the WEP KEY ++ KeyLen Indicate the length fo the WEP KEY ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_INIT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pKey, ++ IN UINT KeyLen) ++{ ++ UCHAR t, u; ++ UINT keyindex; ++ UINT stateindex; ++ PUCHAR state; ++ UINT counter; ++ ++ state = Ctx->STATE; ++ Ctx->X = 0; ++ Ctx->Y = 0; ++ for (counter = 0; counter < 256; counter++) ++ state[counter] = (UCHAR)counter; ++ keyindex = 0; ++ stateindex = 0; ++ for (counter = 0; counter < 256; counter++) ++ { ++ t = state[counter]; ++ stateindex = (stateindex + pKey[keyindex] + t) & 0xff; ++ u = state[stateindex]; ++ state[stateindex] = t; ++ state[counter] = u; ++ if (++keyindex >= KeyLen) ++ keyindex = 0; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get bytes from ARCFOUR CONTEXT (S-BOX) ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ ++ Return Value: ++ UCHAR - the value of the ARCFOUR CONTEXT (S-BOX) ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UCHAR ARCFOUR_BYTE( ++ IN PARCFOURCONTEXT Ctx) ++{ ++ UINT x; ++ UINT y; ++ UCHAR sx, sy; ++ PUCHAR state; ++ ++ state = Ctx->STATE; ++ x = (Ctx->X + 1) & 0xff; ++ sx = state[x]; ++ y = (sx + Ctx->Y) & 0xff; ++ sy = state[y]; ++ Ctx->X = x; ++ Ctx->Y = y; ++ state[y] = sx; ++ state[x] = sy; ++ ++ return(state[(sx + sy) & 0xff]); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Decryption Algorithm ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source data ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_DECRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source dta ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm which conform to the special requirement to encrypt GTK. ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source dta ++ ++ ++ ======================================================================== ++*/ ++ ++VOID WPAARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ //discard first 256 bytes ++ for (i = 0; i < 256; i++) ++ ARCFOUR_BYTE(Ctx); ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate a new FCS given the current FCS and the new data. ++ ++ Arguments: ++ Fcs the original FCS value ++ Cp pointer to the data which will be calculate the FCS ++ Len the length of the data ++ ++ Return Value: ++ UINT - FCS 32 bits ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UINT RTMP_CALC_FCS32( ++ IN UINT Fcs, ++ IN PUCHAR Cp, ++ IN INT Len) ++{ ++ while (Len--) ++ Fcs = (((Fcs) >> 8) ^ FCSTAB_32[((Fcs) ^ (*Cp++)) & 0xff]); ++ ++ return (Fcs); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get last FCS and encrypt it to the destination ++ ++ Arguments: ++ pDest Pointer to the Destination ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSetICV( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest) ++{ ++ pAd->PrivateInfo.FCSCRC32 ^= 0xffffffff; /* complement */ ++ pAd->PrivateInfo.FCSCRC32 = cpu2le32(pAd->PrivateInfo.FCSCRC32); ++ ++ ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, (PUCHAR) &pAd->PrivateInfo.FCSCRC32, 4); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/rtusb_bulk.c +@@ -0,0 +1,1981 @@ ++ /* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtusb_bulk.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 06-25-2004 created ++ ++*/ ++ ++#include "../rt_config.h" ++// Match total 6 bulkout endpoint to corresponding queue. ++UCHAR EpToQueue[6]={FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_MGMT}; ++ ++//static BOOLEAN SingleBulkOut = FALSE; ++ ++void RTUSB_FILL_BULK_URB (struct urb *pUrb, ++ struct usb_device *pUsb_Dev, ++ unsigned int bulkpipe, ++ void *pTransferBuf, ++ int BufSize, ++ usb_complete_t Complete, ++ void *pContext) ++{ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ usb_fill_bulk_urb(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, (usb_complete_t)Complete, pContext); ++#else ++ FILL_BULK_URB(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, Complete, pContext); ++#endif ++ ++} ++ ++VOID RTUSBInitTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PTX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN usb_complete_t Func) ++{ ++ PURB pUrb; ++ PUCHAR pSrc = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pUrb = pTxContext->pUrb; ++ ASSERT(pUrb); ++ ++ // Store BulkOut PipeId ++ pTxContext->BulkOutPipeId = BulkOutPipeId; ++ ++ if (pTxContext->bAggregatible) ++ { ++ pSrc = &pTxContext->TransferBuffer->Aggregation[2]; ++ } ++ else ++ { ++ pSrc = (PUCHAR) pTxContext->TransferBuffer->field.WirelessPacket; ++ } ++ ++ ++ //Initialize a tx bulk urb ++ RTUSB_FILL_BULK_URB(pUrb, ++ pObj->pUsb_Dev, ++ usb_sndbulkpipe(pObj->pUsb_Dev, pAd->BulkOutEpAddr[BulkOutPipeId]), ++ pSrc, ++ pTxContext->BulkOutSize, ++ Func, ++ pTxContext); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ if (pTxContext->bAggregatible) ++ pUrb->transfer_dma = (pTxContext->data_dma + TX_BUFFER_NORMSIZE + 2); ++ else ++ pUrb->transfer_dma = pTxContext->data_dma; ++ ++ pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++#endif ++ ++} ++ ++VOID RTUSBInitHTTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PHT_TX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN ULONG BulkOutSize, ++ IN usb_complete_t Func) ++{ ++ PURB pUrb; ++ PUCHAR pSrc = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pUrb = pTxContext->pUrb; ++ ASSERT(pUrb); ++ ++ // Store BulkOut PipeId ++ pTxContext->BulkOutPipeId = BulkOutPipeId; ++ ++ pSrc = &pTxContext->TransferBuffer->field.WirelessPacket[pTxContext->NextBulkOutPosition]; ++ ++ ++ //Initialize a tx bulk urb ++ RTUSB_FILL_BULK_URB(pUrb, ++ pObj->pUsb_Dev, ++ usb_sndbulkpipe(pObj->pUsb_Dev, pAd->BulkOutEpAddr[BulkOutPipeId]), ++ pSrc, ++ BulkOutSize, ++ Func, ++ pTxContext); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ pUrb->transfer_dma = (pTxContext->data_dma + pTxContext->NextBulkOutPosition); ++ pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++#endif ++ ++} ++ ++VOID RTUSBInitRxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PRX_CONTEXT pRxContext) ++{ ++ PURB pUrb; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ULONG RX_bulk_size; ++ ++ ++ pUrb = pRxContext->pUrb; ++ ASSERT(pUrb); ++ ++ if ( pAd->BulkInMaxPacketSize == 64) ++ RX_bulk_size = 4096; ++ else ++ RX_bulk_size = MAX_RXBULK_SIZE; ++ ++ //Initialize a rx bulk urb ++ RTUSB_FILL_BULK_URB(pUrb, ++ pObj->pUsb_Dev, ++ usb_rcvbulkpipe(pObj->pUsb_Dev, pAd->BulkInEpAddr), ++ &(pRxContext->TransferBuffer[pAd->NextRxBulkInPosition]), ++ RX_bulk_size - (pAd->NextRxBulkInPosition), ++ (usb_complete_t)RTUSBBulkRxComplete, ++ (void *)pRxContext); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ pUrb->transfer_dma = pRxContext->data_dma + pAd->NextRxBulkInPosition; ++ pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++#endif ++ ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++#define BULK_OUT_LOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_LOCK((pLock), IrqFlags); ++ ++#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_UNLOCK((pLock), IrqFlags); ++ ++ ++VOID RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UCHAR Index) ++{ ++ ++ PHT_TX_CONTEXT pHTTXContext; ++ PURB pUrb; ++ int ret = 0; ++ PTXINFO_STRUC pTxInfo, pLastTxInfo = NULL; ++ PTXWI_STRUC pTxWI; ++ ULONG TmpBulkEndPos, ThisBulkSize; ++ unsigned long IrqFlags = 0, IrqFlags2 = 0; ++ PUCHAR pWirelessPkt, pAppendant; ++ BOOLEAN bTxQLastRound = FALSE; ++ UCHAR allzero[4]= {0x0,0x0,0x0,0x0}; ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ if ((pAd->BulkOutPending[BulkOutPipeId] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[BulkOutPipeId] = TRUE; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ { ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ ++ pHTTXContext = &(pAd->TxContext[BulkOutPipeId]); ++ ++ BULK_OUT_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) ++ || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) ++ { ++ BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ ++ // Clear Data flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId)); ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ ++ // Clear Data flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId)); ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ ++ //DBGPRINT(RT_DEBUG_TRACE,("BulkOut-B:I=0x%lx, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", in_interrupt(), ++ // pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, ++ // pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ pHTTXContext->NextBulkOutPosition = pHTTXContext->ENextBulkOutPosition; ++ ThisBulkSize = 0; ++ TmpBulkEndPos = pHTTXContext->NextBulkOutPosition; ++ pWirelessPkt = &pHTTXContext->TransferBuffer->field.WirelessPacket[0]; ++ ++ if ((pHTTXContext->bCopySavePad == TRUE)) ++ { ++ if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero,4)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("e1, allzero : %x %x %x %x %x %x %x %x \n", ++ pHTTXContext->SavedPad[0], pHTTXContext->SavedPad[1], pHTTXContext->SavedPad[2],pHTTXContext->SavedPad[3] ++ ,pHTTXContext->SavedPad[4], pHTTXContext->SavedPad[5], pHTTXContext->SavedPad[6],pHTTXContext->SavedPad[7])); ++ } ++ NdisMoveMemory(&pWirelessPkt[TmpBulkEndPos], pHTTXContext->SavedPad, 8); ++ pHTTXContext->bCopySavePad = FALSE; ++ if (pAd->bForcePrintTX == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE,("RTUSBBulkOutDataPacket --> COPY PAD. CurWrite = %ld, NextBulk = %ld. ENextBulk = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition)); ++ } ++ ++ do ++ { ++ pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[TmpBulkEndPos]; ++ pTxWI = (PTXWI_STRUC)&pWirelessPkt[TmpBulkEndPos + TXINFO_SIZE]; ++ ++ if (pAd->bForcePrintTX == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkOutDataPacket AMPDU = %d.\n", pTxWI->AMPDU)); ++ ++ // add by Iverson, limit BulkOut size to 4k to pass WMM b mode 2T1R test items ++ //if ((ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) ++ if ((ThisBulkSize != 0) && (pTxWI->PHYMODE == MODE_CCK)) ++ { ++ if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x1000) == 0x1000)) ++ { ++ // Limit BulkOut size to about 4k bytes. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0) ) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))*/) ++ { ++ // For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. ++ // For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++ // end Iverson ++ else ++ { ++ if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000)) ++ { // Limit BulkOut size to about 24k bytes. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0) ) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))*/) ++ { // For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. ++ // For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++ ++ if (TmpBulkEndPos == pHTTXContext->CurWritePosition) ++ { ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ ++ if (pTxInfo->QSEL != FIFO_EDCA) ++ { ++ printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __FUNCTION__, pTxInfo->QSEL); ++ printk("\tCWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad); ++ hex_dump("Wrong QSel Pkt:", (PUCHAR)&pWirelessPkt[TmpBulkEndPos], (pHTTXContext->CurWritePosition - pHTTXContext->NextBulkOutPosition)); ++ } ++ ++ if (pTxInfo->USBDMATxPktLen <= 8) ++ { ++ BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ DBGPRINT(RT_DEBUG_ERROR /*RT_DEBUG_TRACE*/,("e2, USBDMATxPktLen==0, Size=%ld, bCSPad=%d, CWPos=%ld, NBPos=%ld, CWRPos=%ld!\n", ++ pHTTXContext->BulkOutSize, pHTTXContext->bCopySavePad, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->CurWriteRealPos)); ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR /*RT_DEBUG_TRACE*/,("%x %x %x %x %x %x %x %x \n", ++ pHTTXContext->SavedPad[0], pHTTXContext->SavedPad[1], pHTTXContext->SavedPad[2],pHTTXContext->SavedPad[3] ++ ,pHTTXContext->SavedPad[4], pHTTXContext->SavedPad[5], pHTTXContext->SavedPad[6],pHTTXContext->SavedPad[7])); ++ } ++ pAd->bForcePrintTX = TRUE; ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ //DBGPRINT(RT_DEBUG_LOUD,("Out:pTxInfo->USBDMATxPktLen=%d!\n", pTxInfo->USBDMATxPktLen)); ++ return; ++ } ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.OneSecTransmittedByteCount += pTxWI->MPDUtotalByteCount; ++ pAd->RalinkCounters.TransmittedByteCount += pTxWI->MPDUtotalByteCount; ++ ++ pLastTxInfo = pTxInfo; ++ ++ // Make sure we use EDCA QUEUE. ++ pTxInfo->QSEL = FIFO_EDCA; ++ ThisBulkSize += (pTxInfo->USBDMATxPktLen+4); ++ TmpBulkEndPos += (pTxInfo->USBDMATxPktLen+4); ++ ++ if (TmpBulkEndPos != pHTTXContext->CurWritePosition) ++ pTxInfo->USBDMANextVLD = 1; ++ ++ if (pTxInfo->SwUseLastRound == 1) ++ { ++ if (pHTTXContext->CurWritePosition == 8) ++ pTxInfo->USBDMANextVLD = 0; ++ pTxInfo->SwUseLastRound = 0; ++ ++ bTxQLastRound = TRUE; ++ pHTTXContext->ENextBulkOutPosition = 8; ++ ++ #ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++ #endif // RT_BIG_ENDIAN // ++ ++ break; ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ }while (TRUE); ++ ++ // adjust the pTxInfo->USBDMANextVLD value of last pTxInfo. ++ if (pLastTxInfo) ++ { ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ pLastTxInfo->USBDMANextVLD = 0; ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ } ++ ++ /* ++ We need to copy SavedPad when following condition matched! ++ 1. Not the last round of the TxQueue and ++ 2. any match of following cases: ++ (1). The End Position of this bulk out is reach to the Currenct Write position and ++ the TxInfo and related header already write to the CurWritePosition. ++ =>(ENextBulkOutPosition == CurWritePosition) && (CurWriteRealPos > CurWritePosition) ++ ++ (2). The EndPosition of the bulk out is not reach to the Current Write Position. ++ =>(ENextBulkOutPosition != CurWritePosition) ++ */ ++ if ((bTxQLastRound == FALSE) && ++ (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) && (pHTTXContext->CurWriteRealPos > pHTTXContext->CurWritePosition)) || ++ (pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition)) ++ ) ++ { ++ NdisMoveMemory(pHTTXContext->SavedPad, &pWirelessPkt[pHTTXContext->ENextBulkOutPosition], 8); ++ pHTTXContext->bCopySavePad = TRUE; ++ if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero,4)) ++ { ++ PUCHAR pBuf = &pHTTXContext->SavedPad[0]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("WARNING-Zero-3:%02x%02x%02x%02x%02x%02x%02x%02x,CWPos=%ld, CWRPos=%ld, bCW=%d, NBPos=%ld, TBPos=%ld, TBSize=%ld\n", ++ pBuf[0], pBuf[1], pBuf[2],pBuf[3],pBuf[4], pBuf[5], pBuf[6],pBuf[7], pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, ++ pHTTXContext->bCurWriting, pHTTXContext->NextBulkOutPosition, TmpBulkEndPos, ThisBulkSize)); ++ ++ pBuf = &pWirelessPkt[pHTTXContext->CurWritePosition]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("\tCWPos=%02x%02x%02x%02x%02x%02x%02x%02x\n", pBuf[0], pBuf[1], pBuf[2],pBuf[3],pBuf[4], pBuf[5], pBuf[6],pBuf[7])); ++ } ++ //DBGPRINT(RT_DEBUG_LOUD,("ENPos==CWPos=%ld, CWRPos=%ld, bCSPad=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->bCopySavePad)); ++ } ++ ++ if (pAd->bForcePrintTX == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE,("BulkOut-A:Size=%ld, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ //DBGPRINT(RT_DEBUG_LOUD,("BulkOut-A:Size=%ld, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, bLRound=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, bTxQLastRound)); ++ ++ // USB DMA engine requires to pad extra 4 bytes. This pad doesn't count into real bulkoutsize. ++ pAppendant = &pWirelessPkt[TmpBulkEndPos]; ++ NdisZeroMemory(pAppendant, 8); ++ ThisBulkSize += 4; ++ pHTTXContext->LastOne = TRUE; ++ if ((ThisBulkSize % pAd->BulkOutMaxPacketSize) == 0) ++ ThisBulkSize += 4; ++ pHTTXContext->BulkOutSize = ThisBulkSize; ++ ++ pAd->watchDogTxPendingCnt[BulkOutPipeId] = 1; ++ BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ ++ // Init Tx context descriptor ++ RTUSBInitHTTxDesc(pAd, pHTTXContext, BulkOutPipeId, ThisBulkSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); ++ ++ pUrb = pHTTXContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ return; ++ } ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pHTTXContext->IRPPending = TRUE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutReq++; ++ ++} ++ ++ ++VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++#if 0 // sample, IRQ LOCK ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ++ DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutDataPacketComplete\n")); ++ ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ Status = pUrb->status; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pHTTXContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ //DBGPRINT(RT_DEBUG_LOUD, ("Done-B(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", BulkOutPipeId, in_interrupt(), pHTTXContext->CurWritePosition, ++ // pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pHTTXContext->IRPPending = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ pAd->BulkOutComplete++; ++ ++ pAd->Counters8023.GoodTransmits++; ++ //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ FREE_HTTX_RING(pAd, BulkOutPipeId, pHTTXContext); ++ //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ ++ } ++ else // STATUS_OTHER ++ { ++ PUCHAR pBuf; ++ ++ pAd->BulkOutCompleteOther++; ++ ++ pBuf = &pHTTXContext->TransferBuffer->WirelessPacket[pHTTXContext->NextBulkOutPosition]; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkOutDataPacket failed: ReasonCode=%d!\n", Status)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOut Header:%x %x %x %x %x %x %x %x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7])); ++ //DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOutCompleteCancel=0x%x, BulkOutCompleteOther=0x%x\n", pAd->BulkOutCompleteCancel, pAd->BulkOutCompleteOther)); ++ ++ if (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST | ++ fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = BulkOutPipeId; ++ } ++ } ++ ++ // ++ // bInUse = TRUE, means some process are filling TX data, after that must turn on bWaitingBulkOut ++ // bWaitingBulkOut = TRUE, means the TX data are waiting for bulk out. ++ // ++ //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition) && ++ (pHTTXContext->ENextBulkOutPosition != (pHTTXContext->CurWritePosition+8)) && ++ !RTUSB_TEST_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId))) ++ { ++ // Indicate There is data avaliable ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protection of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++ ++ //DBGPRINT(RT_DEBUG_LOUD,("Done-A(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d\n", BulkOutPipeId, in_interrupt(), ++ // pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ ++ switch (BulkOutPipeId) ++ { ++ case 0: ++ pObj->ac0_dma_done_task.data = (unsigned long)pAd; ++ tasklet_hi_schedule(&pObj->ac0_dma_done_task); ++ break; ++ case 1: ++ pObj->ac1_dma_done_task.data = (unsigned long)pAd; ++ tasklet_hi_schedule(&pObj->ac1_dma_done_task); ++ break; ++ case 2: ++ pObj->ac2_dma_done_task.data = (unsigned long)pAd; ++ tasklet_hi_schedule(&pObj->ac2_dma_done_task); ++ break; ++ case 3: ++ pObj->ac3_dma_done_task.data = (unsigned long)pAd; ++ tasklet_hi_schedule(&pObj->ac3_dma_done_task); ++ break; ++ case 4: ++ pObj->hcca_dma_done_task.data = (unsigned long)pAd; ++ tasklet_hi_schedule(&pObj->hcca_dma_done_task); ++ break; ++ } ++#else ++ ++{ ++ PHT_TX_CONTEXT pHTTXContext; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ UCHAR BulkOutPipeId; ++ ++ ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pHTTXContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ switch (BulkOutPipeId) ++ { ++ case 0: ++ pObj->ac0_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac0_dma_done_task); ++ break; ++ case 1: ++ pObj->ac1_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac1_dma_done_task); ++ break; ++ case 2: ++ pObj->ac2_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac2_dma_done_task); ++ break; ++ case 3: ++ pObj->ac3_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac3_dma_done_task); ++ break; ++ case 4: ++ pObj->hcca_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->hcca_dma_done_task); ++ break; ++ } ++} ++#endif ++ ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: NULL frame use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutNullFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ if ((pAd->BulkOutPending[0] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[0] = TRUE; ++ pAd->watchDogTxPendingCnt[0] = 1; ++ pNullContext->IRPPending = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; ++ ++ ++ // Clear Null frame bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pNullContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pNullContext, 0, (usb_complete_t)RTUSBBulkOutNullFrameComplete); ++ ++ pUrb = pNullContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ pNullContext->IRPPending = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutNullFrame: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++} ++ ++// NULL frame use BulkOutPipeId = 0 ++VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pNullContext; ++ NTSTATUS Status; ++#if 0 // sample, IRQ LOCK ++ unsigned long IrqFlags; ++#endif ++ POS_COOKIE pObj; ++ ++ ++ pNullContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pNullContext->pAd; ++ Status = pUrb->status; ++ ++#if 0 // sample, IRQ LOCK ++ // Reset Null frame context flags ++ pNullContext->IRPPending = FALSE; ++ pNullContext->InUse = FALSE; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ // Don't worry about the queue is empty or not, this function will check itself ++ //RTMPUSBDeQueuePacket(pAd, 0); ++ RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out Null Frame Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ } ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++#else ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pObj->null_frame_complete_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->null_frame_complete_task); ++#endif ++ ++} ++ ++#if 0 // For RT2870, RTS frame not used now, but maybe will use it latter. ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: RTS frame use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutRTSFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTX_CONTEXT pRTSContext = &(pAd->RTSContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ UCHAR PipeID=0; ++ ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) ++ PipeID= 3; ++ else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) ++ PipeID= 2; ++ else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) ++ PipeID= 1; ++ else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) ++ PipeID= 0; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[PipeID], IrqFlags); ++ if ((pAd->BulkOutPending[PipeID] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[PipeID], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[PipeID] = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[PipeID], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.TransmittedByteCount += pRTSContext->BulkOutSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutRTSFrame \n")); ++ ++ // Clear RTS frame bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_RTS); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pRTSContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pRTSContext, PipeID, (usb_complete_t)RTUSBBulkOutRTSFrameComplete); ++ pRTSContext->IRPPending = TRUE; ++ ++ pUrb = pRTSContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutRTSFrame: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++ DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutRTSFrame \n")); ++ ++} ++ ++// RTS frame use BulkOutPipeId = 0 ++VOID RTUSBBulkOutRTSFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pRTSContext; ++ NTSTATUS Status; ++#if 0 // sample, IRQ LOCK ++ unsigned long IrqFlags; ++#endif ++ POS_COOKIE pObj; ++ ++ DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutRTSFrameComplete\n")); ++ ++ pRTSContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pRTSContext->pAd; ++ Status = pUrb->status; ++ ++#if 0 // sample, IRQ LOCK ++ // Reset RTS frame context flags ++ pRTSContext->IRPPending = FALSE; ++ pRTSContext->InUse = FALSE; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ // Don't worry about the queue is empty or not, this function will check itself ++ //RTMPUSBDeQueuePacket(pAd, pRTSContext->BulkOutPipeId); ++ RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out RTS Frame Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ } ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[pRTSContext->BulkOutPipeId] = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++#else ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pObj->rts_frame_complete_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->rts_frame_complete_task); ++#endif ++ ++ DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutRTSFrameComplete\n")); ++ ++} ++#endif ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: MLME use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutMLMEPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PTX_CONTEXT pMLMEContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa; ++ pUrb = pMLMEContext->pUrb; ++ ++ if ((pAd->MgmtRing.TxSwFreeIdx >= MGMT_RING_SIZE) || ++ (pMLMEContext->InUse == FALSE) || ++ (pMLMEContext->bWaitingBulkOut == FALSE)) ++ { ++ ++ ++ // Clear MLME bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ ++ return; ++ } ++ ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ if ((pAd->BulkOutPending[MGMTPIPEIDX] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ return; ++ } ++ ++ pAd->BulkOutPending[MGMTPIPEIDX] = TRUE; ++ pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 1; ++ pMLMEContext->IRPPending = TRUE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.TransmittedByteCount += pMLMEContext->BulkOutSize; ++ ++ // Clear MLME bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ ++ ++ //DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacket\n")); ++#if 0 // for debug ++{ ++ printk("MLME-Out, C=%d!, D=%d, F=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); ++ ++ //TODO: Need to remove it when formal release ++ PTXINFO_STRUC pTxInfo; ++ ++ pTxInfo = (PTXINFO_STRUC)pMLMEContext->TransferBuffer; ++ if (pTxInfo->QSEL != FIFO_EDCA) ++ { ++ printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __FUNCTION__, pTxInfo->QSEL); ++ printk("\tMLME_Index=%d!\n", Index); ++ hex_dump("Wrong QSel Pkt:", (PUCHAR)pMLMEContext->TransferBuffer, pTxInfo->USBDMATxPktLen); ++ } ++} ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pMLMEContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pMLMEContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutMLMEPacketComplete); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ //For mgmt urb buffer, because we use sk_buff, so we need to notify the USB controller do dma mapping. ++ pUrb->transfer_dma = 0; ++ pUrb->transfer_flags &= (~URB_NO_TRANSFER_DMA_MAP); ++#endif ++ ++ pUrb = pMLMEContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutMLMEPacket: Submit MLME URB failed %d\n", ret)); ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 0; ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->bWaitingBulkOut = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ return; ++ } ++ ++ //DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacket \n")); ++// printk("<---RTUSBBulkOutMLMEPacket,Cpu=%d!, Dma=%d, SwIdx=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); ++} ++ ++ ++VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PTX_CONTEXT pMLMEContext; ++ PRTMP_ADAPTER pAd; ++ NTSTATUS Status; ++ POS_COOKIE pObj; ++ int index; ++#if 0 // sample, IRQ LOCK ++ unsigned long IrqFlags; ++ PNDIS_PACKET pPacket; ++#endif ++ ++ ++ //DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacketComplete\n")); ++ pMLMEContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pMLMEContext->pAd; ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ Status = pUrb->status; ++ index = pMLMEContext->SelfIdx; ++ ++ ++#if 0 // sample, IRQ LOCK ++ ASSERT((pAd->MgmtRing.TxDmaIdx == index)); ++ //printk("MLME-Done-B: C=%d, D=%d, F=%d, Self=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx, pMLMEContext->SelfIdx); ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ ++ if (Status != USB_ST_NOERROR) ++ { ++ //Bulk-Out fail status handle ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); ++ // TODO: How to handle about the MLMEBulkOut failed issue. Need to resend the mgmt pkt? ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ } ++ } ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ // Reset MLME context flags ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->InUse = FALSE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ pMLMEContext->BulkOutSize = 0; ++ ++ pPacket = pAd->MgmtRing.Cell[index].pNdisPacket; ++ pAd->MgmtRing.Cell[index].pNdisPacket = NULL; ++ ++ // Increase MgmtRing Index ++ INC_RING_INDEX(pAd->MgmtRing.TxDmaIdx, MGMT_RING_SIZE); ++ pAd->MgmtRing.TxSwFreeIdx++; ++ ++ RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ // No-matter success or fail, we free the mgmt packet. ++ if (pPacket) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ ++#if 0 ++ //Bulk-Out fail status handle ++ if (Status != USB_ST_NOERROR) ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); ++ // TODO: How to handle about the MLMEBulkOut failed issue. Need to reset the endpoint? ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ } ++ } ++#endif ++ ++ //printk("MLME-Done-A: C=%d, D=%d, F=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); ++ ++ pObj->mgmt_dma_done_task.data = (unsigned long)pAd; ++ tasklet_hi_schedule(&pObj->mgmt_dma_done_task); ++ ++ //DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacketComplete\n")); ++// printk("<---RTUSBBulkOutMLMEPacketComplete, Cpu=%d, Dma=%d, SwIdx=%d!\n", ++// pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); ++ ++#else ++ ++ pObj->mgmt_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->mgmt_dma_done_task); ++#endif ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: PsPoll use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutPsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTX_CONTEXT pPsPollContext = &(pAd->PsPollContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ if ((pAd->BulkOutPending[0] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[0] = TRUE; ++ pAd->watchDogTxPendingCnt[0] = 1; ++ pPsPollContext->IRPPending = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ ++ // Clear PS-Poll bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pPsPollContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pPsPollContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutPsPollComplete); ++ ++ pUrb = pPsPollContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ pPsPollContext->IRPPending = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutPsPoll: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++} ++ ++// PS-Poll frame use BulkOutPipeId = 0 ++VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb,struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pPsPollContext; ++ NTSTATUS Status; ++#if 0 // sample, IRQ LOCK ++ unsigned long IrqFlags; ++#endif ++ POS_COOKIE pObj; ++ ++ ++ pPsPollContext= (PTX_CONTEXT)pUrb->context; ++ pAd = pPsPollContext->pAd; ++ Status = pUrb->status; ++ ++#if 0 // sample, IRQ LOCK ++ // Reset PsPoll context flags ++ pPsPollContext->IRPPending = FALSE; ++ pPsPollContext->InUse = FALSE; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ // Don't worry about the queue is empty or not, this function will check itself ++ RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out PSPoll Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ } ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++#else ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pObj->pspoll_frame_complete_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->pspoll_frame_complete_task); ++#endif ++} ++ ++ ++#if 0 ++/* ++ ======================================================================== ++ ++ Routine Description: ++ USB_RxPacket initializes a URB and uses the Rx IRP to submit it ++ to USB. It checks if an Rx Descriptor is available and passes the ++ the coresponding buffer to be filled. If no descriptor is available ++ fails the request. When setting the completion routine we pass our ++ Adapter Object as Context. ++ ++ Arguments: ++ ++ Return Value: ++ TRUE found matched tuple cache ++ FALSE no matched found ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkReceive( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ ++ /* device had been closed */ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS)) ++ return; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Last is time point between 2 separate URB. ++ if (pAd->NextRxBulkInPosition == 0) ++ { ++ //pAd->NextRxBulkInIndex = (pAd->NextRxBulkInIndex + 1) % (RX_RING_SIZE); ++ INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); ++ } ++ else if ((pAd->NextRxBulkInPosition&0x1ff) != 0) ++ { ++ //pAd->NextRxBulkInIndex = (pAd->NextRxBulkInIndex + 1) % (RX_RING_SIZE); ++ INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("pAd->NextRxBulkInPosition = 0x%lx. End of URB.\n", pAd->NextRxBulkInPosition )); ++ pAd->NextRxBulkInPosition = 0; ++ } ++ ++ if (pAd->NextRxBulkInPosition == MAX_RXBULK_SIZE) ++ pAd->NextRxBulkInPosition = 0; ++ ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); ++ ++ // TODO: Why need to check if pRxContext->InUsed == TRUE? ++ //if ((pRxContext->InUse == TRUE) || (pRxContext->Readable == TRUE)) ++ if ((pRxContext->InUse == FALSE) && (pRxContext->Readable == TRUE)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("pRxContext[%d] InUse = %d.pRxContext->Readable = %d. Return.\n", pAd->NextRxBulkInIndex,pRxContext->InUse, pRxContext->Readable )); ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // read RxContext, Since not ++#ifdef CONFIG_STA_SUPPORT ++ STARxDoneInterruptHandle(pAd, TRUE); ++#endif // CONFIG_STA_SUPPORT // ++ ++ //return; ++ } ++ pRxContext->InUse = TRUE; ++ pRxContext->IRPPending= TRUE; ++ ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Init Rx context descriptor ++ NdisZeroMemory(pRxContext->TransferBuffer, BUFFER_SIZE); ++ RTUSBInitRxDesc(pAd, pRxContext); ++ ++ pUrb = pRxContext->pUrb; ++ if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret)); ++ return; ++ } ++ else // success ++ { ++ NdisInterlockedIncrement(&pAd->PendingRx); ++ pAd->BulkInReq++; ++ } ++ ++ // read RxContext, Since not ++#ifdef CONFIG_STA_SUPPORT ++ STARxDoneInterruptHandle(pAd, FALSE); ++#endif // CONFIG_STA_SUPPORT // ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ This routine process Rx Irp and call rx complete function. ++ ++ Arguments: ++ DeviceObject Pointer to the device object for next lower ++ device. DeviceObject passed in here belongs to ++ the next lower driver in the stack because we ++ were invoked via IoCallDriver in USB_RxPacket ++ AND it is not OUR device object ++ Irp Ptr to completed IRP ++ Context Ptr to our Adapter object (context specified ++ in IoSetCompletionRoutine ++ ++ Return Value: ++ Always returns STATUS_MORE_PROCESSING_REQUIRED ++ ++ Note: ++ Always returns STATUS_MORE_PROCESSING_REQUIRED ++ ======================================================================== ++*/ ++VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++#if 0 ++ PRX_CONTEXT pRxContext; ++ PRTMP_ADAPTER pAd; ++ NTSTATUS Status; ++// POS_COOKIE pObj; ++ ++ pRxContext = (PRX_CONTEXT)pUrb->context; ++ pAd = pRxContext->pAd; ++// pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ Status = pUrb->status; ++ //pRxContext->pIrp = NULL; ++ ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ pAd->BulkInComplete++; ++ pRxContext->Readable = TRUE; ++ pAd->NextRxBulkInPosition = 0; ++ ++ } ++ else // STATUS_OTHER ++ { ++ pAd->BulkInCompleteFail++; ++ // Still read this packet although it may comtain wrong bytes. ++ pRxContext->Readable = FALSE; ++ // Parsing all packets. because after reset, the index will reset to all zero. ++ ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk In Failed. Status = %d\n", Status)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("==>NextRxBulkInIndex=0x%x, NextRxBulkInReadIndex=0x%x, TransferBufferLength= 0x%x\n", ++ pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pRxContext->pUrb->actual_length)); ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); ++ } ++ //pUrb = NULL; ++ } ++ ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET)) && ++// (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ RTUSBBulkReceive(pAd); ++#if 0 ++#if 1 ++ STARxDoneInterruptHandle(pAd, FALSE); ++#else ++ pObj->rx_bh.data = (unsigned long)pUrb; ++ tasklet_schedule(&pObj->rx_bh); ++#endif ++#endif ++ } ++ ++ // Call RxPacket to process packet and return the status ++ NdisInterlockedDecrement(&pAd->PendingRx); ++#else ++ ++ ++ // use a receive tasklet to handle received packets; ++ // or sometimes hardware IRQ will be disabled here, so we can not ++ // use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< ++ PRX_CONTEXT pRxContext; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ ++ pRxContext = (PRX_CONTEXT)pUrb->context; ++ pAd = pRxContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pObj->rx_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->rx_done_task); ++#endif ++} ++ ++#else ++ ++VOID DoBulkIn(IN RTMP_ADAPTER *pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); ++ if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE) || (pRxContext->InUse == TRUE)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ return; ++ } ++ pRxContext->InUse = TRUE; ++ pRxContext->IRPPending = TRUE; ++ pAd->PendingRx++; ++ pAd->BulkInReq++; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Init Rx context descriptor ++ NdisZeroMemory(pRxContext->TransferBuffer, pRxContext->BulkInOffset); ++ RTUSBInitRxDesc(pAd, pRxContext); ++ ++ pUrb = pRxContext->pUrb; ++ if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { // fail ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pAd->PendingRx--; ++ pAd->BulkInReq--; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret)); ++ } ++ else ++ { // success ++#if 0 ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->IRPPending = TRUE; ++ //NdisInterlockedIncrement(&pAd->PendingRx); ++ pAd->PendingRx++; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ pAd->BulkInReq++; ++#endif ++ ASSERT((pRxContext->InUse == pRxContext->IRPPending)); ++ //printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ USB_RxPacket initializes a URB and uses the Rx IRP to submit it ++ to USB. It checks if an Rx Descriptor is available and passes the ++ the coresponding buffer to be filled. If no descriptor is available ++ fails the request. When setting the completion routine we pass our ++ Adapter Object as Context. ++ ++ Arguments: ++ ++ Return Value: ++ TRUE found matched tuple cache ++ FALSE no matched found ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#define fRTMP_ADAPTER_NEED_STOP_RX \ ++ (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ ++ fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \ ++ fRTMP_ADAPTER_REMOVE_IN_PROGRESS | fRTMP_ADAPTER_BULKIN_RESET) ++ ++#define fRTMP_ADAPTER_NEED_STOP_HANDLE_RX \ ++ (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ ++ fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \ ++ fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ++ ++VOID RTUSBBulkReceive( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ unsigned long IrqFlags; ++ ++ ++ /* sanity check */ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_HANDLE_RX)) ++ return; ++ ++ while(1) ++ { ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInReadIndex]); ++ if (((pRxContext->InUse == FALSE) && (pRxContext->Readable == TRUE)) && ++ (pRxContext->bRxHandling == FALSE)) ++ { ++ pRxContext->bRxHandling = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // read RxContext, Since not ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ STARxDoneInterruptHandle(pAd, TRUE); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Finish to handle this bulkIn buffer. ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->BulkInOffset = 0; ++ pRxContext->Readable = FALSE; ++ pRxContext->bRxHandling = FALSE; ++ pAd->ReadPosition = 0; ++ pAd->TransferBufferLength = 0; ++ INC_RING_INDEX(pAd->NextRxBulkInReadIndex, RX_RING_SIZE); ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ break; ++ } ++ } ++ ++ if (!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_RX))) ++ DoBulkIn(pAd); ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ This routine process Rx Irp and call rx complete function. ++ ++ Arguments: ++ DeviceObject Pointer to the device object for next lower ++ device. DeviceObject passed in here belongs to ++ the next lower driver in the stack because we ++ were invoked via IoCallDriver in USB_RxPacket ++ AND it is not OUR device object ++ Irp Ptr to completed IRP ++ Context Ptr to our Adapter object (context specified ++ in IoSetCompletionRoutine ++ ++ Return Value: ++ Always returns STATUS_MORE_PROCESSING_REQUIRED ++ ++ Note: ++ Always returns STATUS_MORE_PROCESSING_REQUIRED ++ ======================================================================== ++*/ ++VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ // use a receive tasklet to handle received packets; ++ // or sometimes hardware IRQ will be disabled here, so we can not ++ // use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< ++ PRX_CONTEXT pRxContext; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ ++ pRxContext = (PRX_CONTEXT)pUrb->context; ++ pAd = pRxContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pObj->rx_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->rx_done_task); ++ ++} ++ ++#endif ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBKickBulkOut( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // BulkIn Reset will reset whole USB PHY. So we need to make sure fRTMP_ADAPTER_BULKIN_RESET not flaged. ++ if (!RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX) ++#ifdef RALINK_ATE ++ && !(ATE_ON(pAd)) ++#endif // RALINK_ATE // ++ ) ++ { ++#if 0 // not used now in RT28xx, but may used latter. ++ // 1. Data Fragment has highest priority ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 0, pAd->NextBulkOutIndex[0]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG_2)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 1, pAd->NextBulkOutIndex[1]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG_3)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 2, pAd->NextBulkOutIndex[2]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_FRAG_4)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 3, pAd->NextBulkOutIndex[3]); ++ } ++ } ++#endif ++ ++ // 2. PS-Poll frame is next ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL)) ++ { ++ RTUSBBulkOutPsPoll(pAd); ++ } ++ ++ // 5. Mlme frame is next ++ else if ((RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME)) && ++ (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE)) ++ { ++ RTUSBBulkOutMLMEPacket(pAd, pAd->MgmtRing.TxDmaIdx); ++ } ++ ++ // 6. Data frame normal is next ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 0, pAd->NextBulkOutIndex[0]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 1, pAd->NextBulkOutIndex[1]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 2, pAd->NextBulkOutIndex[2]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 3, pAd->NextBulkOutIndex[3]); ++ } ++ } ++ ++ // 7. Null frame is the last ++ else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL)) ++ { ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ RTUSBBulkOutNullFrame(pAd); ++ } ++ } ++ ++ // 8. No data avaliable ++ else ++ { ++ ++ } ++ } ++#ifdef RALINK_ATE ++ /* If the mode is in ATE mode. */ ++ else if((ATE_ON(pAd)) && ++ !RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX))// PETER : watch out ! ++ { ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE)) ++ { ++ ATE_RTUSBBulkOutDataPacket(pAd, 0); ++ } ++ } ++#endif // RALINK_ATE // ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Call from Reset action after BulkOut failed. ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCleanUpDataBulkOutQueue( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR Idx; ++ PHT_TX_CONTEXT pTxContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpDataBulkOutQueue\n")); ++ ++ for (Idx = 0; Idx < 4; Idx++) ++ { ++ pTxContext = &pAd->TxContext[Idx]; ++ ++ pTxContext->CurWritePosition = pTxContext->NextBulkOutPosition; ++ pTxContext->LastOne = FALSE; ++ NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]); ++ pAd->BulkOutPending[Idx] = FALSE; ++ NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpDataBulkOutQueue\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCleanUpMLMEBulkOutQueue( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpMLMEBulkOutQueue\n")); ++ ++#if 0 // Do nothing! ++ NdisAcquireSpinLock(&pAd->MLMEBulkOutLock); ++ while (pAd->PrioRingTxCnt > 0) ++ { ++ pAd->MLMEContext[pAd->PrioRingFirstIndex].InUse = FALSE; ++ ++ pAd->PrioRingFirstIndex++; ++ if (pAd->PrioRingFirstIndex >= MGMT_RING_SIZE) ++ { ++ pAd->PrioRingFirstIndex = 0; ++ } ++ ++ pAd->PrioRingTxCnt--; ++ } ++ NdisReleaseSpinLock(&pAd->MLMEBulkOutLock); ++#endif ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpMLMEBulkOutQueue\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCancelPendingIRPs( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RTUSBCancelPendingBulkInIRP(pAd); ++ RTUSBCancelPendingBulkOutIRP(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ UINT i; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->RTUSBCancelPendingBulkInIRP\n")); ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ pRxContext = &(pAd->RxContext[i]); ++ if(pRxContext->IRPPending == TRUE) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ pRxContext->IRPPending = FALSE; ++ pRxContext->InUse = FALSE; ++ //NdisInterlockedDecrement(&pAd->PendingRx); ++ //pAd->PendingRx--; ++ } ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("<---RTUSBCancelPendingBulkInIRP\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCancelPendingBulkOutIRP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PHT_TX_CONTEXT pHTTXContext; ++ PTX_CONTEXT pMLMEContext; ++ PTX_CONTEXT pBeaconContext; ++ PTX_CONTEXT pNullContext; ++ PTX_CONTEXT pPsPollContext; ++ PTX_CONTEXT pRTSContext; ++ UINT i, Idx; ++// unsigned int IrqFlags; ++// NDIS_SPIN_LOCK *pLock; ++// BOOLEAN *pPending; ++ ++ ++// pLock = &pAd->BulkOutLock[MGMTPIPEIDX]; ++// pPending = &pAd->BulkOutPending[MGMTPIPEIDX]; ++ ++ for (Idx = 0; Idx < 4; Idx++) ++ { ++ pHTTXContext = &(pAd->TxContext[Idx]); ++ ++ if (pHTTXContext->IRPPending == TRUE) ++ { ++ ++ // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself ++ // remove it from the HeadPendingSendList and NULL out HeadPendingSendList ++ // when the last IRP on the list has been cancelled; that's how we exit this loop ++ // ++ ++ RTUSB_UNLINK_URB(pHTTXContext->pUrb); ++ ++ // Sleep 200 microseconds to give cancellation time to work ++ RTMPusecDelay(200); ++ } ++ ++#ifdef RALINK_ATE ++ pHTTXContext->bCopySavePad = 0; ++ pHTTXContext->CurWritePosition = 0; ++ pHTTXContext->CurWriteRealPos = 0; ++ pHTTXContext->bCurWriting = FALSE; ++ pHTTXContext->NextBulkOutPosition = 0; ++ pHTTXContext->ENextBulkOutPosition = 0; ++#endif // RALINK_ATE // ++ pAd->BulkOutPending[Idx] = FALSE; ++ } ++ ++ //RTMP_IRQ_LOCK(pLock, IrqFlags); ++ for (i = 0; i < MGMT_RING_SIZE; i++) ++ { ++ pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[i].AllocVa; ++ if(pMLMEContext && (pMLMEContext->IRPPending == TRUE)) ++ { ++ ++ // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself ++ // remove it from the HeadPendingSendList and NULL out HeadPendingSendList ++ // when the last IRP on the list has been cancelled; that's how we exit this loop ++ // ++ ++ RTUSB_UNLINK_URB(pMLMEContext->pUrb); ++ pMLMEContext->IRPPending = FALSE; ++ ++ // Sleep 200 microsecs to give cancellation time to work ++ RTMPusecDelay(200); ++ } ++ } ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ //RTMP_IRQ_UNLOCK(pLock, IrqFlags); ++ ++ ++ for (i = 0; i < BEACON_RING_SIZE; i++) ++ { ++ pBeaconContext = &(pAd->BeaconContext[i]); ++ ++ if(pBeaconContext->IRPPending == TRUE) ++ { ++ ++ // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself ++ // remove it from the HeadPendingSendList and NULL out HeadPendingSendList ++ // when the last IRP on the list has been cancelled; that's how we exit this loop ++ // ++ ++ RTUSB_UNLINK_URB(pBeaconContext->pUrb); ++ ++ // Sleep 200 microsecs to give cancellation time to work ++ RTMPusecDelay(200); ++ } ++ } ++ ++ pNullContext = &(pAd->NullContext); ++ if (pNullContext->IRPPending == TRUE) ++ RTUSB_UNLINK_URB(pNullContext->pUrb); ++ ++ pRTSContext = &(pAd->RTSContext); ++ if (pRTSContext->IRPPending == TRUE) ++ RTUSB_UNLINK_URB(pRTSContext->pUrb); ++ ++ pPsPollContext = &(pAd->PsPollContext); ++ if (pPsPollContext->IRPPending == TRUE) ++ RTUSB_UNLINK_URB(pPsPollContext->pUrb); ++ ++ for (Idx = 0; Idx < 4; Idx++) ++ { ++ NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]); ++ pAd->BulkOutPending[Idx] = FALSE; ++ NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/rtusb_data.c +@@ -0,0 +1,229 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtusb_data.c ++ ++ Abstract: ++ Ralink USB driver Tx/Rx functions. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan 03-25-2006 created ++ ++*/ ++#include "../rt_config.h" ++ ++extern UCHAR Phy11BGNextRateUpward[]; // defined in mlme.c ++extern UCHAR EpToQueue[]; ++ ++VOID REPORT_AMSDU_FRAMES_TO_LLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ PNDIS_PACKET pPacket; ++ UINT nMSDU; ++ struct sk_buff *pSkb; ++ ++ nMSDU = 0; ++ /* allocate a rx packet */ ++ pSkb = dev_alloc_skb(RX_BUFFER_AGGRESIZE); ++ pPacket = (PNDIS_PACKET)OSPKT_TO_RTPKT(pSkb); ++ if (pSkb) ++ { ++ ++ /* convert 802.11 to 802.3 packet */ ++ pSkb->dev = get_netdev_from_bssid(pAd, BSS0); ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++ deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("Can't allocate skb\n")); ++ } ++} ++ ++NDIS_STATUS RTUSBFreeDescriptorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UINT32 NumberRequired) ++{ ++// UCHAR FreeNumber = 0; ++// UINT Index; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ ++ ++ pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->CurWritePosition < pHTTXContext->NextBulkOutPosition) && ((pHTTXContext->CurWritePosition + NumberRequired + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition)) ++ { ++ ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < (NumberRequired + LOCAL_TXBUF_SIZE))) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ else if (pHTTXContext->bCurWriting == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RTUSBFreeD c3 --> QueIdx=%d, CWPos=%ld, NBOutPos=%ld!\n", BulkOutPipeId, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ else ++ { ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ ++ return (Status); ++} ++ ++NDIS_STATUS RTUSBFreeDescriptorRelease( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR BulkOutPipeId) ++{ ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ ++ pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ pHTTXContext->bCurWriting = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++ ++BOOLEAN RTUSBNeedQueueBackForAgg( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR BulkOutPipeId) ++{ ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ BOOLEAN needQueBack = FALSE; ++ ++ pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->IRPPending == TRUE) /*&& (pAd->TxSwQueue[BulkOutPipeId].Number == 0) */) ++ { ++#if 0 ++ if ((pHTTXContext->CurWritePosition <= 8) && ++ (pHTTXContext->NextBulkOutPosition > 8 && (pHTTXContext->NextBulkOutPosition+MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT)) ++ { ++ needQueBack = TRUE; ++ } ++ else if ((pHTTXContext->CurWritePosition < pHTTXContext->NextBulkOutPosition) && ++ ((pHTTXContext->NextBulkOutPosition + MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT)) ++ { ++ needQueBack = TRUE; ++ } ++#else ++ if ((pHTTXContext->CurWritePosition < pHTTXContext->ENextBulkOutPosition) && ++ (((pHTTXContext->ENextBulkOutPosition+MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT) || (pHTTXContext->CurWritePosition > MAX_AGGREGATION_SIZE))) ++ { ++ needQueBack = TRUE; ++ } ++#endif ++ else if ((pHTTXContext->CurWritePosition > pHTTXContext->ENextBulkOutPosition) && ++ ((pHTTXContext->ENextBulkOutPosition + MAX_AGGREGATION_SIZE) < pHTTXContext->CurWritePosition)) ++ { ++ needQueBack = TRUE; ++ } ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ return needQueBack; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBRejectPendingPackets( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR Index; ++ PQUEUE_ENTRY pEntry; ++ PNDIS_PACKET pPacket; ++ PQUEUE_HEADER pQueue; ++ ++ ++ for (Index = 0; Index < 4; Index++) ++ { ++ NdisAcquireSpinLock(&pAd->TxSwQueueLock[Index]); ++ while (pAd->TxSwQueue[Index].Head != NULL) ++ { ++ pQueue = (PQUEUE_HEADER) &(pAd->TxSwQueue[Index]); ++ pEntry = RemoveHeadQueue(pQueue); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ NdisReleaseSpinLock(&pAd->TxSwQueueLock[Index]); ++ ++ } ++ ++} ++ ++VOID RTMPWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst) ++{ ++ pTxInfo->USBDMATxPktLen = USBDMApktLen; ++ pTxInfo->QSEL = QueueSel; ++ if (QueueSel != FIFO_EDCA) ++ DBGPRINT(RT_DEBUG_TRACE, ("====> QueueSel != FIFO_EDCA<============\n")); ++ pTxInfo->USBDMANextVLD = FALSE; //NextValid; // Need to check with Jan about this. ++ pTxInfo->USBDMATxburst = TxBurst; ++ pTxInfo->WIV = bWiv; ++ pTxInfo->SwUseLastRound = 0; ++ pTxInfo->rsv = 0; ++ pTxInfo->rsv2 = 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/rtusb_io.c +@@ -0,0 +1,2006 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtusb_io.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 06-25-2004 created ++*/ ++ ++#include "../rt_config.h" ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: NIC initialization complete ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++NTSTATUS RTUSBFirmwareRun( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x01, ++ 0x8, ++ 0, ++ NULL, ++ 0); ++ ++ return Status; ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write Firmware to NIC. ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBFirmwareWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFwImage, ++ IN ULONG FwLen) ++{ ++ UINT32 MacReg; ++ NTSTATUS Status; ++// ULONG i; ++ USHORT writeLen; ++ ++ Status = RTUSBReadMACRegister(pAd, MAC_CSR0, &MacReg); ++ ++ ++ writeLen = FwLen; ++ RTUSBMultiWrite(pAd, FIRMWARE_IMAGE_BASE, pFwImage, writeLen); ++ ++ Status = RTUSBWriteMACRegister(pAd, 0x7014, 0xffffffff); ++ Status = RTUSBWriteMACRegister(pAd, 0x701c, 0xffffffff); ++ Status = RTUSBFirmwareRun(pAd); ++ ++ return Status; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Get current firmware operation mode (Return Value) ++ ++ Arguments: ++ ++ Return Value: ++ 0 or 1 = Downloaded by host driver ++ others = Driver doesn't download firmware ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBFirmwareOpmode( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUINT32 pValue) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x1, ++ 0x11, ++ 0, ++ pValue, ++ 4); ++ return Status; ++} ++NTSTATUS RTUSBVenderReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status; ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("-->RTUSBVenderReset\n")); ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x01, ++ 0x1, ++ 0, ++ NULL, ++ 0); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("<--RTUSBVenderReset\n")); ++ return Status; ++} ++/* ++ ======================================================================== ++ ++ Routine Description: Read various length data from RT2573 ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBMultiRead( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x7, ++ 0, ++ Offset, ++ pData, ++ length); ++ ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write various length data to RT2573 ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBMultiWrite_OneByte( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData) ++{ ++ NTSTATUS Status; ++ ++ // TODO: In 2870, use this funciton carefully cause it's not stable. ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x6, ++ 0, ++ Offset, ++ pData, ++ 1); ++ ++ return Status; ++} ++ ++NTSTATUS RTUSBMultiWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length) ++{ ++ NTSTATUS Status; ++ ++ ++ USHORT index = 0,Value; ++ PUCHAR pSrc = pData; ++ USHORT resude = 0; ++ ++ resude = length % 2; ++ length += resude; ++ do ++ { ++ Value =(USHORT)( *pSrc | (*(pSrc + 1) << 8)); ++ Status = RTUSBSingleWrite(pAd,Offset + index,Value); ++ index +=2; ++ length -= 2; ++ pSrc = pSrc + 2; ++ }while(length > 0); ++ ++ return Status; ++} ++ ++ ++NTSTATUS RTUSBSingleWrite( ++ IN RTMP_ADAPTER *pAd, ++ IN USHORT Offset, ++ IN USHORT Value) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x2, ++ Value, ++ Offset, ++ NULL, ++ 0); ++ ++ return Status; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Read 32-bit MAC register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUINT32 pValue) ++{ ++ NTSTATUS Status; ++ UINT32 localVal; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x7, ++ 0, ++ Offset, ++ &localVal, ++ 4); ++ ++ *pValue = le2cpu32(localVal); ++ ++ ++ if (Status < 0) ++ *pValue = 0xffffffff; ++ ++ return Status; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write 32-bit MAC register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN UINT32 Value) ++{ ++ NTSTATUS Status; ++ UINT32 localVal; ++ ++ localVal = Value; ++ ++ Status = RTUSBSingleWrite(pAd, Offset, (USHORT)(localVal & 0xffff)); ++ Status = RTUSBSingleWrite(pAd, Offset + 2, (USHORT)((localVal & 0xffff0000) >> 16)); ++ ++ return Status; ++} ++ ++ ++ ++#if 1 ++/* ++ ======================================================================== ++ ++ Routine Description: Read 8-bit BBP register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN PUCHAR pValue) ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ UINT i = 0; ++ NTSTATUS status; ++ ++ // Verify the busy condition ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); ++ if(status >= 0) ++ { ++ if (!(BbpCsr.field.Busy == BUSY)) ++ break; ++ } ++ printk("RTUSBReadBBPRegister(BBP_CSR_CFG_1):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ // ++ // Read failed then Return Default value. ++ // ++ *pValue = pAd->BbpWriteLatch[Id]; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ // Prepare for write material ++ BbpCsr.word = 0; ++ BbpCsr.field.fRead = 1; ++ BbpCsr.field.Busy = 1; ++ BbpCsr.field.RegNum = Id; ++ RTUSBWriteMACRegister(pAd, BBP_CSR_CFG, BbpCsr.word); ++ ++ i = 0; ++ // Verify the busy condition ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); ++ if (status >= 0) ++ { ++ if (!(BbpCsr.field.Busy == BUSY)) ++ { ++ *pValue = (UCHAR)BbpCsr.field.Value; ++ break; ++ } ++ } ++ printk("RTUSBReadBBPRegister(BBP_CSR_CFG_2):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ // ++ // Read failed then Return Default value. ++ // ++ *pValue = pAd->BbpWriteLatch[Id]; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ return STATUS_SUCCESS; ++} ++#else ++/* ++ ======================================================================== ++ ++ Routine Description: Read 8-bit BBP register via firmware ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN PUCHAR pValue) ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ int i, k; ++ for (i=0; iBbpWriteLatch[Id]; ++ return STATUS_UNSUCCESSFUL; ++ } ++ return STATUS_SUCCESS; ++} ++#endif ++ ++#if 1 ++/* ++ ======================================================================== ++ ++ Routine Description: Write 8-bit BBP register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN UCHAR Value) ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ UINT i = 0; ++ NTSTATUS status; ++ // Verify the busy condition ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); ++ if (status >= 0) ++ { ++ if (!(BbpCsr.field.Busy == BUSY)) ++ break; ++ } ++ printk("RTUSBWriteBBPRegister(BBP_CSR_CFG):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ // Prepare for write material ++ BbpCsr.word = 0; ++ BbpCsr.field.fRead = 0; ++ BbpCsr.field.Value = Value; ++ BbpCsr.field.Busy = 1; ++ BbpCsr.field.RegNum = Id; ++ RTUSBWriteMACRegister(pAd, BBP_CSR_CFG, BbpCsr.word); ++ ++ pAd->BbpWriteLatch[Id] = Value; ++ ++ return STATUS_SUCCESS; ++} ++#else ++/* ++ ======================================================================== ++ ++ Routine Description: Write 8-bit BBP register via firmware ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++NTSTATUS RTUSBWriteBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN UCHAR Value) ++ ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ int BusyCnt; ++ for (BusyCnt=0; BusyCntBbpWriteLatch[Id] = Value; ++ break; ++ } ++ if (BusyCnt == MAX_BUSY_COUNT) ++ { ++ DBGPRINT_ERR(("BBP write R%d=0x%x fail\n", Id, BbpCsr.word)); ++ return STATUS_UNSUCCESSFUL; ++ } ++ return STATUS_SUCCESS; ++} ++#endif ++/* ++ ======================================================================== ++ ++ Routine Description: Write RF register through MAC ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 Value) ++{ ++ PHY_CSR4_STRUC PhyCsr4; ++ UINT i = 0; ++ NTSTATUS status; ++ ++ NdisZeroMemory(&PhyCsr4, sizeof(PHY_CSR4_STRUC)); ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, RF_CSR_CFG0, &PhyCsr4.word); ++ if (status >= 0) ++ { ++ if (!(PhyCsr4.field.Busy)) ++ break; ++ } ++ printk("RTUSBWriteRFRegister(RF_CSR_CFG0):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ RTUSBWriteMACRegister(pAd, RF_CSR_CFG0, Value); ++ ++ return STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write RT3070 RF register through MAC ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RT30xxWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN UCHAR Value) ++{ ++ RF_CSR_CFG_STRUC rfcsr; ++ UINT i = 0; ++ ++ do ++ { ++ RTUSBReadMACRegister(pAd, RF_CSR_CFG, &rfcsr.word); ++ ++ if (!rfcsr.field.RF_CSR_KICK) ++ break; ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ rfcsr.field.RF_CSR_WR = 1; ++ rfcsr.field.RF_CSR_KICK = 1; ++ rfcsr.field.TESTCSR_RFACC_REGNUM = RegID; ++ rfcsr.field.RF_CSR_DATA = Value; ++ ++ RTUSBWriteMACRegister(pAd, RF_CSR_CFG, rfcsr.word); ++ ++ return STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Read RT3070 RF register through MAC ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RT30xxReadRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN PUCHAR pValue) ++{ ++ RF_CSR_CFG_STRUC rfcsr; ++ UINT i=0, k; ++ ++ for (i=0; ihead = NULL; ++ cmdq->tail = NULL; ++ cmdq->size = 0; ++ cmdq->CmdQState = RT2870_THREAD_INITED; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTUSBEnqueueCmdFromNdis( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN BOOLEAN SetInformation, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength) ++{ ++ NDIS_STATUS status; ++ PCmdQElmt cmdqelmt = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) ++ return (NDIS_STATUS_RESOURCES); ++ ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt == NULL)) ++ return (NDIS_STATUS_RESOURCES); ++ ++ cmdqelmt->buffer = NULL; ++ if (pInformationBuffer != NULL) ++ { ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt->buffer, InformationBufferLength); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt->buffer == NULL)) ++ { ++ kfree(cmdqelmt); ++ return (NDIS_STATUS_RESOURCES); ++ } ++ else ++ { ++ NdisMoveMemory(cmdqelmt->buffer, pInformationBuffer, InformationBufferLength); ++ cmdqelmt->bufferlength = InformationBufferLength; ++ } ++ } ++ else ++ cmdqelmt->bufferlength = 0; ++ ++ cmdqelmt->command = Oid; ++ cmdqelmt->CmdFromNdis = TRUE; ++ if (SetInformation == TRUE) ++ cmdqelmt->SetOperation = TRUE; ++ else ++ cmdqelmt->SetOperation = FALSE; ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ if (pAd->CmdQ.CmdQState & RT2870_THREAD_CAN_DO_INSERT) ++ { ++ EnqueueCmd((&pAd->CmdQ), cmdqelmt); ++ status = NDIS_STATUS_SUCCESS; ++ } ++ else ++ { ++ status = NDIS_STATUS_FAILURE; ++ } ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ if (status == NDIS_STATUS_FAILURE) ++ { ++ if (cmdqelmt->buffer) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ RTUSBCMDUp(pAd); ++ ++ ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTUSBEnqueueInternalCmd( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength) ++{ ++ NDIS_STATUS status; ++ PCmdQElmt cmdqelmt = NULL; ++ ++ ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt == NULL)) ++ return (NDIS_STATUS_RESOURCES); ++ NdisZeroMemory(cmdqelmt, sizeof(CmdQElmt)); ++ ++ if(InformationBufferLength > 0) ++ { ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt->buffer, InformationBufferLength); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt->buffer == NULL)) ++ { ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ return (NDIS_STATUS_RESOURCES); ++ } ++ else ++ { ++ NdisMoveMemory(cmdqelmt->buffer, pInformationBuffer, InformationBufferLength); ++ cmdqelmt->bufferlength = InformationBufferLength; ++ } ++ } ++ else ++ { ++ cmdqelmt->buffer = NULL; ++ cmdqelmt->bufferlength = 0; ++ } ++ ++ cmdqelmt->command = Oid; ++ cmdqelmt->CmdFromNdis = FALSE; ++ ++ if (cmdqelmt != NULL) ++ { ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ if (pAd->CmdQ.CmdQState & RT2870_THREAD_CAN_DO_INSERT) ++ { ++ EnqueueCmd((&pAd->CmdQ), cmdqelmt); ++ status = NDIS_STATUS_SUCCESS; ++ } ++ else ++ { ++ status = NDIS_STATUS_FAILURE; ++ } ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ if (status == NDIS_STATUS_FAILURE) ++ { ++ if (cmdqelmt->buffer) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ RTUSBCMDUp(pAd); ++ } ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBDequeueCmd( ++ IN PCmdQ cmdq, ++ OUT PCmdQElmt *pcmdqelmt) ++{ ++ *pcmdqelmt = cmdq->head; ++ ++ if (*pcmdqelmt != NULL) ++ { ++ cmdq->head = cmdq->head->next; ++ cmdq->size--; ++ if (cmdq->size == 0) ++ cmdq->tail = NULL; ++ } ++} ++ ++/* ++ ======================================================================== ++ usb_control_msg - Builds a control urb, sends it off and waits for completion ++ @dev: pointer to the usb device to send the message to ++ @pipe: endpoint "pipe" to send the message to ++ @request: USB message request value ++ @requesttype: USB message request type value ++ @value: USB message value ++ @index: USB message index value ++ @data: pointer to the data to send ++ @size: length in bytes of the data to send ++ @timeout: time in jiffies to wait for the message to complete before ++ timing out (if 0 the wait is forever) ++ Context: !in_interrupt () ++ ++ This function sends a simple control message to a specified endpoint ++ and waits for the message to complete, or timeout. ++ If successful, it returns the number of bytes transferred, otherwise a negative error number. ++ ++ Don't use this function from within an interrupt context, like a ++ bottom half handler. If you need an asynchronous message, or need to send ++ a message from within interrupt context, use usb_submit_urb() ++ If a thread in your driver uses this call, make sure your disconnect() ++ method can wait for it to complete. Since you don't have a handle on ++ the URB used, you can't cancel the request. ++ ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSB_VendorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TransferFlags, ++ IN UCHAR RequestType, ++ IN UCHAR Request, ++ IN USHORT Value, ++ IN USHORT Index, ++ IN PVOID TransferBuffer, ++ IN UINT32 TransferBufferLength) ++{ ++ int ret; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("device disconnected\n")); ++ return -1; ++ } ++ else if (in_interrupt()) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("in_interrupt, RTUSB_VendorRequest Request%02x Value%04x Offset%04x\n",Request,Value,Index)); ++ ++ return -1; ++ } ++ else ++ { ++#define MAX_RETRY_COUNT 10 ++ ++ int retryCount = 0; ++ void *tmpBuf = TransferBuffer; ++ ++ // Acquire Control token ++#ifdef INF_AMAZON_SE ++ //Semaphore fix INF_AMAZON_SE hang ++ //pAd->UsbVendorReqBuf is the swap for DEVICE_VENDOR_REQUEST_IN to fix dma bug. ++ ret = down_interruptible(&(pAd->UsbVendorReq_semaphore)); ++ if (pAd->UsbVendorReqBuf) ++ { ++ ASSERT(TransferBufferLength UsbVendorReqBuf; ++ NdisZeroMemory(pAd->UsbVendorReqBuf, TransferBufferLength); ++ ++ if (RequestType == DEVICE_VENDOR_REQUEST_OUT) ++ NdisMoveMemory(tmpBuf, TransferBuffer, TransferBufferLength); ++ } ++#endif // INF_AMAZON_SE // ++ do { ++ if( RequestType == DEVICE_VENDOR_REQUEST_OUT) ++ ret=usb_control_msg(pObj->pUsb_Dev, usb_sndctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); ++ else if(RequestType == DEVICE_VENDOR_REQUEST_IN) ++ ret=usb_control_msg(pObj->pUsb_Dev, usb_rcvctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("vendor request direction is failed\n")); ++ ret = -1; ++ } ++ ++ retryCount++; ++ if (ret < 0) { ++ printk("#\n"); ++ RTMPusecDelay(5000); ++ } ++ } while((ret < 0) && (retryCount < MAX_RETRY_COUNT)); ++ ++#ifdef INF_AMAZON_SE ++ if ((pAd->UsbVendorReqBuf) && (RequestType == DEVICE_VENDOR_REQUEST_IN)) ++ NdisMoveMemory(TransferBuffer, tmpBuf, TransferBufferLength); ++ up(&(pAd->UsbVendorReq_semaphore)); ++#endif // INF_AMAZON_SE // ++ ++ if (ret < 0) { ++// DBGPRINT(RT_DEBUG_ERROR, ("USBVendorRequest failed ret=%d \n",ret)); ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSB_VendorRequest failed(%d),TxFlags=0x%x, ReqType=%s, Req=0x%x, Index=0x%x\n", ++ ret, TransferFlags, (RequestType == DEVICE_VENDOR_REQUEST_OUT ? "OUT" : "IN"), Request, Index)); ++ if (Request == 0x2) ++ DBGPRINT(RT_DEBUG_ERROR, ("\tRequest Value=0x%04x!\n", Value)); ++ ++ if ((TransferBuffer!= NULL) && (TransferBufferLength > 0)) ++ hex_dump("Failed TransferBuffer value", TransferBuffer, TransferBufferLength); ++ } ++ ++#if 0 ++ // retry ++ if (ret < 0) { ++ int temp_i=0; ++ DBGPRINT(RT_DEBUG_ERROR, ("USBVendorRequest failed ret=%d, \n",ret)); ++ ret = 0; ++ do ++ { ++ if( RequestType == DEVICE_VENDOR_REQUEST_OUT) ++ ret=usb_control_msg(pObj->pUsb_Dev, usb_sndctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, TransferBuffer, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); ++ else if(RequestType == DEVICE_VENDOR_REQUEST_IN) ++ ret=usb_control_msg(pObj->pUsb_Dev, usb_rcvctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, TransferBuffer, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); ++ temp_i++; ++ } while( (ret < 0) && (temp_i <= 1) ); ++ ++ if( ret >= 0) ++ return ret; ++ ++ } ++#endif ++ ++ } ++ return ret; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Creates an IRP to submite an IOCTL_INTERNAL_USB_RESET_PORT ++ synchronously. Callers of this function must be running at ++ PASSIVE LEVEL. ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSB_ResetDevice( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status = TRUE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->USB_ResetDevice\n")); ++ //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); ++ return Status; ++} ++ ++VOID CMDHandler( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PCmdQElmt cmdqelmt; ++ PUCHAR pData; ++ NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; ++// ULONG Now = 0; ++ NTSTATUS ntStatus; ++// unsigned long IrqFlags; ++ ++ while (pAd->CmdQ.size > 0) ++ { ++ NdisStatus = NDIS_STATUS_SUCCESS; ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ RTUSBDequeueCmd(&pAd->CmdQ, &cmdqelmt); ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ if (cmdqelmt == NULL) ++ break; ++ ++ pData = cmdqelmt->buffer; ++ ++ if(!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) ++ { ++ switch (cmdqelmt->command) ++ { ++ case CMDTHREAD_CHECK_GPIO: ++ { ++#ifdef CONFIG_STA_SUPPORT ++ UINT32 data; ++#endif // CONFIG_STA_SUPPORT // ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ ++ ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Read GPIO pin2 as Hardware controlled radio state ++ ++ RTUSBReadMACRegister( pAd, GPIO_CTRL_CFG, &data); ++ ++ if (data & 0x04) ++ { ++ pAd->StaCfg.bHwRadio = TRUE; ++ } ++ else ++ { ++ pAd->StaCfg.bHwRadio = FALSE; ++ } ++ ++ if(pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if(pAd->StaCfg.bRadio == TRUE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("!!! Radio On !!!\n")); ++ ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("!!! Radio Off !!!\n")); ++ ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = HW_RADIO_OFF; ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ break; ++ ++#ifdef CONFIG_STA_SUPPORT ++ case CMDTHREAD_QKERIODIC_EXECUT: ++ { ++ StaQuickResponeForRateUpExec(NULL, pAd, NULL, NULL); ++ } ++ break; ++#endif // CONFIG_STA_SUPPORT // ++ ++ case CMDTHREAD_RESET_BULK_OUT: ++ { ++ UINT32 MACValue; ++ UCHAR Index; ++ int ret=0; ++ PHT_TX_CONTEXT pHTTXContext; ++// RTMP_TX_RING *pTxRing; ++ unsigned long IrqFlags; ++#ifdef RALINK_ATE ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++#endif // RALINK_ATE // ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT(ResetPipeid=0x%0x)===>\n", pAd->bulkResetPipeid)); ++ // All transfers must be aborted or cancelled before attempting to reset the pipe. ++ //RTUSBCancelPendingBulkOutIRP(pAd); ++ // Wait 10ms to let previous packet that are already in HW FIFO to clear. by MAXLEE 12-25-2007 ++ Index = 0; ++ do ++ { ++ RTUSBReadMACRegister(pAd, TXRXQ_PCNT, &MACValue); ++ if ((MACValue & 0xf00000/*0x800000*/) == 0) ++ break; ++ Index++; ++ RTMPusecDelay(10000); ++ }while(Index < 100); ++ MACValue = 0; ++ RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); ++ // To prevent Read Register error, we 2nd check the validity. ++ if ((MACValue & 0xc00000) == 0) ++ RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); ++ // To prevent Read Register error, we 3rd check the validity. ++ if ((MACValue & 0xc00000) == 0) ++ RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); ++ MACValue |= 0x80000; ++ RTUSBWriteMACRegister(pAd, USB_DMA_CFG, MACValue); ++ ++ // Wait 1ms to prevent next URB to bulkout before HW reset. by MAXLEE 12-25-2007 ++ RTMPusecDelay(1000); ++ ++ MACValue &= (~0x80000); ++ RTUSBWriteMACRegister(pAd, USB_DMA_CFG, MACValue); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tSet 0x2a0 bit19. Clear USB DMA TX path\n")); ++ ++ // Wait 5ms to prevent next URB to bulkout before HW reset. by MAXLEE 12-25-2007 ++ //RTMPusecDelay(5000); ++ ++ if ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ } ++ RTUSBKickBulkOut(pAd); ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tTX MGMT RECOVER Done!\n")); ++ } ++ else ++ { ++ pHTTXContext = &(pAd->TxContext[pAd->bulkResetPipeid]); ++ //NdisAcquireSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); ++ RTMP_INT_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ if ( pAd->BulkOutPending[pAd->bulkResetPipeid] == FALSE) ++ { ++ pAd->BulkOutPending[pAd->bulkResetPipeid] = TRUE; ++ pHTTXContext->IRPPending = TRUE; ++ pAd->watchDogTxPendingCnt[pAd->bulkResetPipeid] = 1; ++ ++ // no matter what, clean the flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ ++ //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); ++ RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++/*-----------------------------------------------------------------------------------------------*/ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ pNullContext->IRPPending = TRUE; ++ // ++ // If driver is still in ATE TXFRAME mode, ++ // keep on transmitting ATE frames. ++ // ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("pAd->ate.Mode == %d\npAd->ContinBulkOut == %d\npAd->BulkOutRemained == %d\n", pAd->ate.Mode, pAd->ContinBulkOut, atomic_read(&pAd->BulkOutRemained))); ++ if((pAd->ate.Mode == ATE_TXFRAME) && ((pAd->ContinBulkOut == TRUE) || (atomic_read(&pAd->BulkOutRemained) > 0))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("After CMDTHREAD_RESET_BULK_OUT, continue to bulk out frames !\n")); ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pNullContext, 0/* pAd->bulkResetPipeid */, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); ++ ++ if((ret = RTUSB_SUBMIT_URB(pNullContext->pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); ++ } ++ ++ pAd->BulkOutReq++; ++ } ++ } ++ else ++#endif // RALINK_ATE // ++/*-----------------------------------------------------------------------------------------------*/ ++ { ++ RTUSBInitHTTxDesc(pAd, pHTTXContext, pAd->bulkResetPipeid, pHTTXContext->BulkOutSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); ++ ++ if((ret = RTUSB_SUBMIT_URB(pHTTXContext->pUrb))!=0) ++ { ++ RTMP_INT_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ pAd->BulkOutPending[pAd->bulkResetPipeid] = FALSE; ++ pHTTXContext->IRPPending = FALSE; ++ pAd->watchDogTxPendingCnt[pAd->bulkResetPipeid] = 0; ++ RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("CmdThread : CMDTHREAD_RESET_BULK_OUT: Submit Tx URB failed %d\n", ret)); ++ } ++ else ++ { ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("\tCMDTHREAD_RESET_BULK_OUT: TxContext[%d]:CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, pending=%d!\n", ++ pAd->bulkResetPipeid, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, ++ pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, pAd->BulkOutPending[pAd->bulkResetPipeid])); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("\t\tBulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", ++ pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tCMDTHREAD_RESET_BULK_OUT: Submit Tx DATA URB for failed BulkReq(0x%lx) Done, status=%d!\n", pAd->bulkResetReq[pAd->bulkResetPipeid], pHTTXContext->pUrb->status)); ++ ++ } ++ } ++ } ++ else ++ { ++ //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); ++ //RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("CmdThread : TX DATA RECOVER FAIL for BulkReq(0x%lx) because BulkOutPending[%d] is TRUE!\n", pAd->bulkResetReq[pAd->bulkResetPipeid], pAd->bulkResetPipeid)); ++ if (pAd->bulkResetPipeid == 0) ++ { ++ UCHAR pendingContext = 0; ++ PHT_TX_CONTEXT pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[pAd->bulkResetPipeid ]); ++ PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); ++ PTX_CONTEXT pNULLContext = (PTX_CONTEXT)(&pAd->PsPollContext); ++ PTX_CONTEXT pPsPollContext = (PTX_CONTEXT)(&pAd->NullContext); ++ ++ if (pHTTXContext->IRPPending) ++ pendingContext |= 1; ++ else if (pMLMEContext->IRPPending) ++ pendingContext |= 2; ++ else if (pNULLContext->IRPPending) ++ pendingContext |= 4; ++ else if (pPsPollContext->IRPPending) ++ pendingContext |= 8; ++ else ++ pendingContext = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("\tTX Occupied by %d!\n", pendingContext)); ++ } ++ ++ // no matter what, clean the flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ ++ RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << pAd->bulkResetPipeid)); ++ } ++ ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ //RTUSBKickBulkOut(pAd); ++ } ++ ++ } ++ /* ++ // Don't cancel BULKIN. ++ while ((atomic_read(&pAd->PendingRx) > 0) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ if (atomic_read(&pAd->PendingRx) > 0) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkIn IRP Pending!!cancel it!\n")); ++ RTUSBCancelPendingBulkInIRP(pAd); ++ } ++ RTMPusecDelay(100000); ++ } ++ ++ if ((atomic_read(&pAd->PendingRx) == 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) ++ { ++ UCHAR i; ++ RTUSBRxPacket(pAd); ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = 0; // Rx Bulk pointer ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ pRxContext->pAd = pAd; ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ pRxContext->ReorderInUse = FALSE; ++ ++ } ++ RTUSBBulkReceive(pAd); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTUSBBulkReceive\n")); ++ }*/ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT<===\n")); ++ break; ++ ++ case CMDTHREAD_RESET_BULK_IN: ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_IN === >\n")); ++ ++ // All transfers must be aborted or cancelled before attempting to reset the pipe. ++ { ++ UINT32 MACValue; ++/*-----------------------------------------------------------------------------------------------*/ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("ATE : BulkIn IRP Pending!!!\n")); ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++ RTMPusecDelay(100000); ++ pAd->PendingRx = 0; ++ } ++ } ++ else ++#endif // RALINK_ATE // ++/*-----------------------------------------------------------------------------------------------*/ ++ { ++ //while ((atomic_read(&pAd->PendingRx) > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkIn IRP Pending!!!\n")); ++ RTUSBCancelPendingBulkInIRP(pAd); ++ RTMPusecDelay(100000); ++ pAd->PendingRx = 0; ++ } ++ } ++ ++ // Wait 10ms before reading register. ++ RTMPusecDelay(10000); ++ ntStatus = RTUSBReadMACRegister(pAd, MAC_CSR0, &MACValue); ++ ++ if ((NT_SUCCESS(ntStatus) == TRUE) && ++ (!(RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))))) ++ { ++ UCHAR i; ++ ++ if (RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ break; ++ pAd->NextRxBulkInPosition = pAd->RxContext[pAd->NextRxBulkInIndex].BulkInOffset; ++ DBGPRINT(RT_DEBUG_TRACE, ("BULK_IN_RESET: NBIIdx=0x%x,NBIRIdx=0x%x, BIRPos=0x%lx. BIReq=x%lx, BIComplete=0x%lx, BICFail0x%lx\n", ++ pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pAd->NextRxBulkInPosition, pAd->BulkInReq, pAd->BulkInComplete, pAd->BulkInCompleteFail)); ++ for (i = 0; i < RX_RING_SIZE; i++) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("\tRxContext[%d]: IRPPending=%d, InUse=%d, Readable=%d!\n" ++ , i, pAd->RxContext[i].IRPPending, pAd->RxContext[i].InUse, pAd->RxContext[i].Readable)); ++ } ++ /* ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("==========================================\n")); ++ ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = 0; // Rx Bulk pointer ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ pRxContext->pAd = pAd; ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ pRxContext->ReorderInUse = FALSE; ++ ++ }*/ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ for (i = 0; i < pAd->CommonCfg.NumOfBulkInIRP; i++) ++ { ++ //RTUSBBulkReceive(pAd); ++ PRX_CONTEXT pRxContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); ++ if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE) || (pRxContext->InUse == TRUE)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ break; ++ } ++ pRxContext->InUse = TRUE; ++ pRxContext->IRPPending = TRUE; ++ pAd->PendingRx++; ++ pAd->BulkInReq++; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Init Rx context descriptor ++ RTUSBInitRxDesc(pAd, pRxContext); ++ pUrb = pRxContext->pUrb; ++ if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { // fail ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pAd->PendingRx--; ++ pAd->BulkInReq--; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ DBGPRINT(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB failed(%d), status=%d\n", ret, pUrb->status)); ++ } ++ else ++ { // success ++#if 0 ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->IRPPending = TRUE; ++ //NdisInterlockedIncrement(&pAd->PendingRx); ++ pAd->PendingRx++; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ pAd->BulkInReq++; ++#endif ++ //printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB Done, status=%d!\n", pUrb->status)); ++ ASSERT((pRxContext->InUse == pRxContext->IRPPending)); ++ } ++ } ++ ++ } ++ else ++ { ++ // Card must be removed ++ if (NT_SUCCESS(ntStatus) != TRUE) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Read Register Failed!Card must be removed!!\n\n")); ++ } ++ else ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Cannot do bulk in because flags(0x%lx) on !\n", pAd->Flags)); ++ } ++ } ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_IN <===\n")); ++ break; ++ ++ case CMDTHREAD_SET_ASIC_WCID: ++ { ++ RT_SET_ASIC_WCID SetAsicWcid; ++ USHORT offset; ++ UINT32 MACValue, MACRValue = 0; ++ SetAsicWcid = *((PRT_SET_ASIC_WCID)(pData)); ++ ++ if (SetAsicWcid.WCID >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ offset = MAC_WCID_BASE + ((UCHAR)SetAsicWcid.WCID)*HW_WCID_ENTRY_SIZE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_SET_ASIC_WCID : WCID = %ld, SetTid = %lx, DeleteTid = %lx.\n", SetAsicWcid.WCID, SetAsicWcid.SetTid, SetAsicWcid.DeleteTid)); ++ MACValue = (pAd->MacTab.Content[SetAsicWcid.WCID].Addr[3]<<24)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[2]<<16)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[1]<<8)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[0]); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("1-MACValue= %x,\n", MACValue)); ++ RTUSBWriteMACRegister(pAd, offset, MACValue); ++ // Read bitmask ++ RTUSBReadMACRegister(pAd, offset+4, &MACRValue); ++ if ( SetAsicWcid.DeleteTid != 0xffffffff) ++ MACRValue &= (~SetAsicWcid.DeleteTid); ++ if (SetAsicWcid.SetTid != 0xffffffff) ++ MACRValue |= (SetAsicWcid.SetTid); ++ MACRValue &= 0xffff0000; ++ ++ MACValue = (pAd->MacTab.Content[SetAsicWcid.WCID].Addr[5]<<8)+pAd->MacTab.Content[SetAsicWcid.WCID].Addr[4]; ++ MACValue |= MACRValue; ++ RTUSBWriteMACRegister(pAd, offset+4, MACValue); ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-MACValue= %x,\n", MACValue)); ++ } ++ break; ++ ++ case CMDTHREAD_SET_ASIC_WCID_CIPHER: ++ { ++#ifdef CONFIG_STA_SUPPORT ++ RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; ++ USHORT offset; ++ UINT32 MACRValue = 0; ++ SHAREDKEY_MODE_STRUC csr1; ++ SetAsicWcidAttri = *((PRT_SET_ASIC_WCID_ATTRI)(pData)); ++ ++ if (SetAsicWcidAttri.WCID >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ offset = MAC_WCID_ATTRIBUTE_BASE + ((UCHAR)SetAsicWcidAttri.WCID)*HW_WCID_ATTRI_SIZE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("Cmd : CMDTHREAD_SET_ASIC_WCID_CIPHER : WCID = %ld, Cipher = %lx.\n", SetAsicWcidAttri.WCID, SetAsicWcidAttri.Cipher)); ++ // Read bitmask ++ RTUSBReadMACRegister(pAd, offset, &MACRValue); ++ MACRValue = 0; ++ MACRValue |= (((UCHAR)SetAsicWcidAttri.Cipher) << 1); ++ ++ RTUSBWriteMACRegister(pAd, offset, MACRValue); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-offset = %x , MACValue= %x,\n", offset, MACRValue)); ++ ++ offset = PAIRWISE_IVEIV_TABLE_BASE + ((UCHAR)SetAsicWcidAttri.WCID)*HW_IVEIV_ENTRY_SIZE; ++ MACRValue = 0; ++ if ( (SetAsicWcidAttri.Cipher <= CIPHER_WEP128)) ++ MACRValue |= ( pAd->StaCfg.DefaultKeyId << 30); ++ else ++ MACRValue |= (0x20000000); ++ RTUSBWriteMACRegister(pAd, offset, MACRValue); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-offset = %x , MACValue= %x,\n", offset, MACRValue)); ++ ++ // ++ // Update cipher algorithm. WSTA always use BSS0 ++ // ++ // for adhoc mode only ,because wep status slow than add key, when use zero config ++ if (pAd->StaCfg.BssType == BSS_ADHOC ) ++ { ++ offset = MAC_WCID_ATTRIBUTE_BASE; ++ ++ RTUSBReadMACRegister(pAd, offset, &MACRValue); ++ MACRValue &= (~0xe); ++ MACRValue |= (((UCHAR)SetAsicWcidAttri.Cipher) << 1); ++ ++ RTUSBWriteMACRegister(pAd, offset, MACRValue); ++ ++ //Update group key cipher,,because wep status slow than add key, when use zero config ++ RTUSBReadMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), &csr1.word); ++ ++ csr1.field.Bss0Key0CipherAlg = SetAsicWcidAttri.Cipher; ++ csr1.field.Bss0Key1CipherAlg = SetAsicWcidAttri.Cipher; ++ ++ RTUSBWriteMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), csr1.word); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ break; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ // avoid in interrupt when write key ++ case RT_CMD_SET_KEY_TABLE: //General call for AsicAddPairwiseKeyEntry() ++ { ++ RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; ++ KeyInfo = *((PRT_ADD_PAIRWISE_KEY_ENTRY)(pData)); ++ AsicAddPairwiseKeyEntry(pAd, ++ KeyInfo.MacAddr, ++ (UCHAR)KeyInfo.MacTabMatchWCID, ++ &KeyInfo.CipherKey); ++ } ++ break; ++ ++ case RT_CMD_SET_RX_WCID_TABLE: //General call for RTMPAddWcidAttributeEntry() ++ { ++ PMAC_TABLE_ENTRY pEntry ; ++ pEntry = (PMAC_TABLE_ENTRY)(pData); ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pEntry->PairwiseKey.CipherAlg, ++ pEntry); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ case CMDTHREAD_SET_CLIENT_MAC_ENTRY: ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ pEntry = (MAC_TABLE_ENTRY *)pData; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)pEntry->Aid); ++ if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) ++ { ++ UINT32 uIV = 0; ++ PUCHAR ptr; ++ ++ ptr = (PUCHAR) &uIV; ++ *(ptr + 3) = (pAd->StaCfg.DefaultKeyId << 6); ++ AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, uIV, 0); ++ AsicUpdateWCIDAttribute(pAd, pEntry->Aid, BSS0, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, FALSE); ++ } ++ else if (pEntry->AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ UINT32 uIV = 0; ++ PUCHAR ptr; ++ ++ ptr = (PUCHAR) &uIV; ++ *(ptr + 3) = (pAd->StaCfg.DefaultKeyId << 6); ++ AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, uIV, 0); ++ AsicUpdateWCIDAttribute(pAd, pEntry->Aid, BSS0, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, FALSE); ++ } ++ else ++ { ++ // ++ // Other case, disable engine. ++ // Don't worry WPA key, we will add WPA Key after 4-Way handshaking. ++ // ++ USHORT offset; ++ offset = MAC_WCID_ATTRIBUTE_BASE + (pEntry->Aid * HW_WCID_ATTRI_SIZE); ++ // RX_PKEY_MODE:0 for no security; RX_KEY_TAB:0 for shared key table; BSS_IDX:0 ++ RTUSBWriteMACRegister(pAd, offset, 0); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ AsicUpdateRxWCIDTable(pAd, pEntry->Aid, pEntry->Addr); ++ printk("UpdateRxWCIDTable(): Aid=%d, Addr=%02x:%02x:%02x:%02x:%02x:%02x!\n", pEntry->Aid, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ } ++ break; ++ ++ case OID_802_11_ADD_WEP: ++ { ++#ifdef CONFIG_STA_SUPPORT ++ UINT i; ++ UINT32 KeyIdx; ++ PNDIS_802_11_WEP pWepKey; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP \n")); ++ ++ pWepKey = (PNDIS_802_11_WEP)pData; ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ ++ // it is a shared key ++ if ((KeyIdx >= 4) || ((pWepKey->KeyLength != 5) && (pWepKey->KeyLength != 13))) ++ { ++ NdisStatus = NDIS_STATUS_INVALID_DATA; ++ DBGPRINT(RT_DEBUG_ERROR, ("CmdThread::OID_802_11_ADD_WEP, INVALID_DATA!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg; ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ CipherAlg = (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 5)? CIPHER_WEP64 : CIPHER_WEP128; ++ ++ // ++ // Change the WEP cipher to CKIP cipher if CKIP KP on. ++ // Funk UI or Meetinghouse UI will add ckip key from this path. ++ // ++ ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = pAd->SharedKey[BSS0][KeyIdx].KeyLen; ++ } ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ UCHAR IVEIV[8]; ++ UINT32 WCIDAttri, Value; ++ USHORT offset, offset2; ++ NdisZeroMemory(IVEIV, 8); ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ // Add BSSID to WCTable. because this is Tx wep key. ++ // WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:1=PAIRWISE KEY, BSSIdx is 0 ++ WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; ++ ++ offset = MAC_WCID_ATTRIBUTE_BASE + (BSSID_WCID* HW_WCID_ATTRI_SIZE); ++ RTUSBWriteMACRegister(pAd, offset, WCIDAttri); ++ // 1. IV/EIV ++ // Specify key index to find shared key. ++ IVEIV[3] = (UCHAR)(KeyIdx<< 6); //WEP Eiv bit off. groupkey index is not 0 ++ offset = PAIRWISE_IVEIV_TABLE_BASE + (BSS0Mcast_WCID * HW_IVEIV_ENTRY_SIZE); ++ offset2 = PAIRWISE_IVEIV_TABLE_BASE + (BSSID_WCID* HW_IVEIV_ENTRY_SIZE); ++ for (i=0; i<8;) ++ { ++ Value = IVEIV[i]; ++ Value += (IVEIV[i+1]<<8); ++ Value += (IVEIV[i+2]<<16); ++ Value += (IVEIV[i+3]<<24); ++ RTUSBWriteMACRegister(pAd, offset+i, Value); ++ RTUSBWriteMACRegister(pAd, offset2+i, Value); ++ i+=4; ++ } ++ ++ // 2. WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:use share key, BSSIdx is 0 ++ WCIDAttri = (pAd->SharedKey[BSS0][KeyIdx].CipherAlg<<1)|SHAREDKEYTABLE; ++ offset = MAC_WCID_ATTRIBUTE_BASE + (BSS0Mcast_WCID* HW_WCID_ATTRI_SIZE); ++ DBGPRINT(RT_DEBUG_TRACE, ("BSS0Mcast_WCID : offset = %x, WCIDAttri = %x\n", offset, WCIDAttri)); ++ RTUSBWriteMACRegister(pAd, offset, WCIDAttri); ++ ++ } ++ AsicAddSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx, CipherAlg, pWepKey->KeyMaterial, NULL, NULL); ++ DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP (KeyIdx=%d, Len=%d-byte)\n", KeyIdx, pWepKey->KeyLength)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ break; ++ ++ case CMDTHREAD_802_11_COUNTER_MEASURE: ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Control Thread !! ERROR !! Unknown(cmdqelmt->command=0x%x) !! \n", cmdqelmt->command)); ++ break; ++ } ++ } ++ ++ if (cmdqelmt->CmdFromNdis == TRUE) ++ { ++ if (cmdqelmt->buffer != NULL) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ { ++ if ((cmdqelmt->buffer != NULL) && (cmdqelmt->bufferlength != 0)) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ { ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ } ++ } /* end of while */ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/common/spectrum.c +@@ -0,0 +1,1876 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ action.c ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ --------- ---------- ---------------------------------------------- ++ Fonchi Wu 2008 created for 802.11h ++ */ ++ ++#include "../rt_config.h" ++#include "action.h" ++ ++VOID MeasureReqTabInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC); ++ if (pAd->CommonCfg.pMeasureReqTab) ++ NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB)); ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__)); ++ ++ return; ++} ++ ++VOID MeasureReqTabExit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock); ++ ++ if (pAd->CommonCfg.pMeasureReqTab) ++ kfree(pAd->CommonCfg.pMeasureReqTab); ++ pAd->CommonCfg.pMeasureReqTab = NULL; ++ ++ return; ++} ++ ++static PMEASURE_REQ_ENTRY MeasureReqLookUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ UINT HashIdx; ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ++ if (pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ pEntry = pTab->Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if (pEntry->DialogToken == DialogToken) ++ break; ++ else ++ { ++ pPrevEntry = pEntry; ++ pEntry = pEntry->pNext; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ return pEntry; ++} ++ ++static PMEASURE_REQ_ENTRY MeasureReqInsert( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ INT i; ++ ULONG HashIdx; ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry; ++ ULONG Now; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ pEntry = MeasureReqLookUp(pAd, DialogToken); ++ if (pEntry == NULL) ++ { ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry = &pTab->Content[i]; ++ ++ if ((pEntry->Valid == TRUE) ++ && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT))) ++ { ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); ++ pTab->Size--; ++ ++ break; ++ } ++ ++ if (pEntry->Valid == FALSE) ++ break; ++ } ++ ++ if (i < MAX_MEASURE_REQ_TAB_SIZE) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry->lastTime = Now; ++ pEntry->Valid = TRUE; ++ pEntry->DialogToken = DialogToken; ++ pTab->Size++; ++ } ++ else ++ { ++ pEntry = NULL; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__)); ++ } ++ ++ // add this Neighbor entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ if (pTab->Hash[HashIdx] == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pTab->Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ } ++ ++ return pEntry; ++} ++ ++static VOID MeasureReqDelete( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return; ++ } ++ ++ // if empty, return ++ if (pTab->Size == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n")); ++ return; ++ } ++ ++ pEntry = MeasureReqLookUp(pAd, DialogToken); ++ if (pEntry != NULL) ++ { ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); ++ pTab->Size--; ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ } ++ ++ return; ++} ++ ++VOID TpcReqTabInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock); ++ ++ pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC); ++ if (pAd->CommonCfg.pTpcReqTab) ++ NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB)); ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__)); ++ ++ return; ++} ++ ++VOID TpcReqTabExit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock); ++ ++ if (pAd->CommonCfg.pTpcReqTab) ++ kfree(pAd->CommonCfg.pTpcReqTab); ++ pAd->CommonCfg.pTpcReqTab = NULL; ++ ++ return; ++} ++ ++static PTPC_REQ_ENTRY TpcReqLookUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ UINT HashIdx; ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ++ if (pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ ++ HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ pEntry = pTab->Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if (pEntry->DialogToken == DialogToken) ++ break; ++ else ++ { ++ pPrevEntry = pEntry; ++ pEntry = pEntry->pNext; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ ++ return pEntry; ++} ++ ++ ++static PTPC_REQ_ENTRY TpcReqInsert( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ INT i; ++ ULONG HashIdx; ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry; ++ ULONG Now; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ pEntry = TpcReqLookUp(pAd, DialogToken); ++ if (pEntry == NULL) ++ { ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry = &pTab->Content[i]; ++ ++ if ((pEntry->Valid == TRUE) ++ && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT))) ++ { ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); ++ pTab->Size--; ++ ++ break; ++ } ++ ++ if (pEntry->Valid == FALSE) ++ break; ++ } ++ ++ if (i < MAX_TPC_REQ_TAB_SIZE) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry->lastTime = Now; ++ pEntry->Valid = TRUE; ++ pEntry->DialogToken = DialogToken; ++ pTab->Size++; ++ } ++ else ++ { ++ pEntry = NULL; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__)); ++ } ++ ++ // add this Neighbor entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ if (pTab->Hash[HashIdx] == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pTab->Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ } ++ ++ return pEntry; ++} ++ ++static VOID TpcReqDelete( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return; ++ } ++ ++ // if empty, return ++ if (pTab->Size == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n")); ++ return; ++ } ++ ++ pEntry = TpcReqLookUp(pAd, DialogToken); ++ if (pEntry != NULL) ++ { ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); ++ pTab->Size--; ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Get Current TimeS tamp. ++ ++ Parametrs: ++ ++ Return : Current Time Stamp. ++ ========================================================================== ++ */ ++static UINT64 GetCurrentTimeStamp( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // get current time stamp. ++ return 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Get Current Transmit Power. ++ ++ Parametrs: ++ ++ Return : Current Time Stamp. ++ ========================================================================== ++ */ ++static UINT8 GetCurTxPwr( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 Wcid) ++{ ++ return 16; /* 16 dBm */ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Dialog Token into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Dialog token. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertDialogToken( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 DialogToken) ++{ ++ ULONG TempLen; ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &DialogToken, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert TPC Request IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ static VOID InsertTpcReqIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen) ++{ ++ ULONG TempLen; ++ ULONG Len = 0; ++ UINT8 ElementID = IE_TPC_REQUEST; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert TPC Report IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Transmit Power. ++ 4. Link Margin. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ static VOID InsertTpcReportIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin) ++{ ++ ULONG TempLen; ++ ULONG Len = sizeof(TPC_REPORT_INFO); ++ UINT8 ElementID = IE_TPC_REPORT; ++ TPC_REPORT_INFO TpcReportIE; ++ ++ TpcReportIE.TxPwr = TxPwr; ++ TpcReportIE.LinkMargin = LinkMargin; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, &TpcReportIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Channel Switch Announcement IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. channel switch announcement mode. ++ 4. new selected channel. ++ 5. channel switch announcement count. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertChSwAnnIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewChannel, ++ IN UINT8 ChSwCnt) ++{ ++ ULONG TempLen; ++ ULONG Len = sizeof(CH_SW_ANN_INFO); ++ UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT; ++ CH_SW_ANN_INFO ChSwAnnIE; ++ ++ ChSwAnnIE.ChSwMode = ChSwMode; ++ ChSwAnnIE.Channel = NewChannel; ++ ChSwAnnIE.ChSwCnt = ChSwCnt; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, &ChSwAnnIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Measure Request IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Measure Token. ++ 4. Measure Request Mode. ++ 5. Measure Request Type. ++ 6. Measure Channel. ++ 7. Measure Start time. ++ 8. Measure Duration. ++ ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertMeasureReqIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN PMEASURE_REQ_INFO pMeasureReqIE) ++{ ++ ULONG TempLen; ++ UINT8 Len = sizeof(MEASURE_REQ_INFO); ++ UINT8 ElementID = IE_MEASUREMENT_REQUEST; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, pMeasureReqIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Measure Report IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Measure Token. ++ 4. Measure Request Mode. ++ 5. Measure Request Type. ++ 6. Length of Report Infomation ++ 7. Pointer of Report Infomation Buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertMeasureReportIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN PMEASURE_REPORT_INFO pMeasureReportIE, ++ IN UINT8 ReportLnfoLen, ++ IN PUINT8 pReportInfo) ++{ ++ ULONG TempLen; ++ ULONG Len; ++ UINT8 ElementID = IE_MEASUREMENT_REPORT; ++ ++ Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, pMeasureReportIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ if ((ReportLnfoLen > 0) && (pReportInfo != NULL)) ++ { ++ MakeOutgoingFrame(pFrameBuf + *pFrameLen, &TempLen, ++ ReportLnfoLen, pReportInfo, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ } ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 MeasureCh, ++ IN UINT16 MeasureDuration) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ HEADER_802_11 ActHdr; ++ MEASURE_REQ_INFO MeasureReqIE; ++ UINT8 RmReqDailogToken = RandomByte(pAd); ++ UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd); ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken); ++ ++ // prepare Measurement IE. ++ NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO)); ++ MeasureReqIE.Token = RmReqDailogToken; ++ MeasureReqIE.ReqMode.word = MeasureReqMode; ++ MeasureReqIE.ReqType = MeasureReqType; ++ MeasureReqIE.MeasureReq.ChNum = MeasureCh; ++ MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime); ++ MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration); ++ InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 ReportInfoLen, ++ IN PUINT8 pReportInfo) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ HEADER_802_11 ActHdr; ++ MEASURE_REPORT_INFO MeasureRepIE; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // prepare Measurement IE. ++ NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO)); ++ MeasureRepIE.Token = MeasureToken; ++ MeasureRepIE.ReportMode.word = MeasureReqMode; ++ MeasureRepIE.ReportType = MeasureReqType; ++ InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UCHAR DialogToken) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // Insert TPC Request IE. ++ InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // Insert TPC Request IE. ++ InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Channel Switch Announcement action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ 2. Channel switch announcement mode. ++ 2. a New selected channel. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueChSwAnn( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewCh) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH); ++ ++ InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++static BOOLEAN DfsRequirementCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 Channel) ++{ ++ BOOLEAN Result = FALSE; ++ INT i; ++ ++ do ++ { ++ // check DFS procedure is running. ++ // make sure DFS procedure won't start twice. ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++ { ++ Result = FALSE; ++ break; ++ } ++ ++ // check the new channel carried from Channel Switch Announcemnet is valid. ++ for (i=0; iChannelListNum; i++) ++ { ++ if ((Channel == pAd->ChannelList[i].Channel) ++ &&(pAd->ChannelList[i].RemainingTimeForUse == 0)) ++ { ++ // found radar signal in the channel. the channel can't use at least for 30 minutes. ++ pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec ++ Result = TRUE; ++ break; ++ } ++ } ++ } while(FALSE); ++ ++ return Result; ++} ++ ++VOID NotifyChSwAnnToPeerAPs( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRA, ++ IN PUCHAR pTA, ++ IN UINT8 ChSwMode, ++ IN UINT8 Channel) ++{ ++#ifdef WDS_SUPPORT ++ if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address. ++ { ++ INT i; ++ // info neighbor APs that Radar signal found throgh WDS link. ++ for (i = 0; i < MAX_WDS_ENTRY; i++) ++ { ++ if (ValidWdsEntry(pAd, i)) ++ { ++ PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr; ++ ++ // DA equal to SA. have no necessary orignal AP which found Radar signal. ++ if (MAC_ADDR_EQUAL(pTA, pDA)) ++ continue; ++ ++ // send Channel Switch Action frame to info Neighbro APs. ++ EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel); ++ } ++ } ++ } ++#endif // WDS_SUPPORT // ++} ++ ++static VOID StartDFSProcedure( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN UINT8 ChSwMode) ++{ ++ // start DFS procedure ++ pAd->CommonCfg.Channel = Channel; ++#ifdef DOT11_N_SUPPORT ++ N_ChannelCheck(pAd); ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE; ++ pAd->CommonCfg.RadarDetect.CSCount = 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Channel Switch Announcement action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Channel switch announcement infomation buffer. ++ ++ ++ Return : None. ++ ========================================================================== ++ */ ++ ++/* ++ Channel Switch Announcement IE. ++ +----+-----+-----------+------------+-----------+ ++ | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt | ++ +----+-----+-----------+------------+-----------+ ++ 1 1 1 1 1 ++*/ ++static BOOLEAN PeerChSwAnnSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PCH_SW_ANN_INFO pChSwAnnInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pChSwAnnInfo == NULL) ++ return result; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_CHANNEL_SWITCH_ANNOUNCEMENT: ++ NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1); ++ ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement request action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Measurement request infomation buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerMeasureReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PMEASURE_REQ_INFO pMeasureReqInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ PUCHAR ptr; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pMeasureReqInfo == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_MEASUREMENT_REQUEST: ++ NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1); ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1); ++ NdisMoveMemory(&MeasureStartTime, ptr + 1, 8); ++ pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime); ++ NdisMoveMemory(&MeasureDuration, ptr + 9, 2); ++ pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration); ++ ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement report action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Measurement report infomation buffer. ++ 4. basic report infomation buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ ++/* ++ Measurement Report IE. ++ +----+-----+-------+-------------+--------------+----------------+ ++ | ID | Len | Token | Report Mode | Measure Type | Measure Report | ++ +----+-----+-------+-------------+--------------+----------------+ ++ 1 1 1 1 1 variable ++ ++ Basic Report. ++ +--------+------------+----------+-----+ ++ | Ch Num | Start Time | Duration | Map | ++ +--------+------------+----------+-----+ ++ 1 8 2 1 ++ ++ Map Field Bit Format. ++ +-----+---------------+---------------------+-------+------------+----------+ ++ | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved | ++ +-----+---------------+---------------------+-------+------------+----------+ ++ 0 1 2 3 4 5-7 ++*/ ++static BOOLEAN PeerMeasureReportSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PMEASURE_REPORT_INFO pMeasureReportInfo, ++ OUT PUINT8 pReportBuf) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ PUCHAR ptr; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pMeasureReportInfo == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_MEASUREMENT_REPORT: ++ NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1); ++ if (pMeasureReportInfo->ReportType == RM_BASIC) ++ { ++ PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->Map, ptr + 11, 1); ++ ++ } ++ else if (pMeasureReportInfo->ReportType == RM_CCA) ++ { ++ PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1); ++ ++ } ++ else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM) ++ { ++ PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8); ++ } ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Request action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Dialog Token. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerTpcReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pDialogToken == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_TPC_REQUEST: ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Report action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Dialog Token. ++ 4. TPC Report IE. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerTpcRepSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PTPC_REPORT_INFO pTpcRepInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pDialogToken == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_TPC_REPORT: ++ NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1); ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Channel Switch Announcement action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerChSwAnnAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ CH_SW_ANN_INFO ChSwAnnInfo; ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR index = 0, Channel = 0, NewChannel = 0; ++ ULONG Bssidx = 0; ++#endif // CONFIG_STA_SUPPORT // ++ ++ NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO)); ++ if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n")); ++ return; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n")); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel)); ++ hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6); ++ ++ Channel = pAd->CommonCfg.Channel; ++ NewChannel = ChSwAnnInfo.Channel; ++ ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) ++ { ++ // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). ++ // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. ++ AsicSwitchChannel(pAd, 1, FALSE); ++ AsicLockChannel(pAd, 1); ++ LinkDown(pAd, FALSE); ++ MlmeQueueInit(&pAd->Mlme.Queue); ++ BssTableInit(&pAd->ScanTab); ++ RTMPusecDelay(1000000); // use delay to prevent STA do reassoc ++ ++ // channel sanity check ++ for (index = 0 ; index < pAd->ChannelListNum; index++) ++ { ++ if (pAd->ChannelList[index].Channel == NewChannel) ++ { ++ pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; ++ pAd->CommonCfg.Channel = NewChannel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); ++ break; ++ } ++ } ++ ++ if (index >= pAd->ChannelListNum) ++ { ++ DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement Request action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerMeasureReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ UINT8 DialogToken; ++ MEASURE_REQ_INFO MeasureReqInfo; ++ MEASURE_REPORT_MODE ReportMode; ++ ++ if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo)) ++ { ++ ReportMode.word = 0; ++ ReportMode.field.Incapable = 1; ++ EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL); ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement Report action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerMeasureReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MEASURE_REPORT_INFO MeasureReportInfo; ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ UINT8 DialogToken; ++ PUINT8 pMeasureReportInfo; ++ ++// if (pAd->CommonCfg.bIEEE80211H != TRUE) ++// return; ++ ++ if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT))); ++ return; ++ } ++ ++ NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO)); ++ NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT)); ++ if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo)) ++ { ++ do { ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ ++ // Not a autonomous measure report. ++ // check the dialog token field. drop it if the dialog token doesn't match. ++ if ((DialogToken != 0) ++ && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL)) ++ break; ++ ++ if (pEntry != NULL) ++ MeasureReqDelete(pAd, pEntry->DialogToken); ++ ++ if (MeasureReportInfo.ReportType == RM_BASIC) ++ { ++ PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo; ++ if ((pBasicReport->Map.field.Radar) ++ && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE)) ++ { ++ NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum); ++ StartDFSProcedure(pAd, pBasicReport->ChNum, 1); ++ } ++ } ++ } while (FALSE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n")); ++ ++ kfree(pMeasureReportInfo); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Request action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerTpcReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ PUCHAR pFramePtr = pFr->Octet; ++ UINT8 DialogToken; ++ UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid); ++ UINT8 LinkMargin = 0; ++ CHAR RealRssi; ++ ++ // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The ++ // STA may incorporate rate information and channel conditions, including interference, into its computation ++ // of link margin. ++ ++ RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ++ ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ++ ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ // skip Category and action code. ++ pFramePtr += 2; ++ ++ // Dialog token. ++ NdisMoveMemory(&DialogToken, pFramePtr, 1); ++ ++ LinkMargin = (RealRssi / MIN_RCV_PWR); ++ if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken)) ++ EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Report action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerTpcRepAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UINT8 DialogToken; ++ TPC_REPORT_INFO TpcRepInfo; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ ++ NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO)); ++ if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo)) ++ { ++ if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL) ++ { ++ TpcReqDelete(pAd, pEntry->DialogToken); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n", ++ __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); ++ } ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Spectrun action frames Handler such as channel switch annoucement, ++ measurement report, measurement request actions frames. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID PeerSpectrumAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ if (pAd->CommonCfg.bIEEE80211H != TRUE) ++ return; ++ ++ switch(Action) ++ { ++ case SPEC_MRQ: ++ // current rt2860 unable do such measure specified in Measurement Request. ++ // reject all measurement request. ++ PeerMeasureReqAction(pAd, Elem); ++ break; ++ ++ case SPEC_MRP: ++ PeerMeasureReportAction(pAd, Elem); ++ break; ++ ++ case SPEC_TPCRQ: ++ PeerTpcReqAction(pAd, Elem); ++ break; ++ ++ case SPEC_TPCRP: ++ PeerTpcRepAction(pAd, Elem); ++ break; ++ ++ case SPEC_CHANNEL_SWITCH: ++{ ++#ifdef DOT11N_DRAFT3 ++ SEC_CHA_OFFSET_IE Secondary; ++ CHA_SWITCH_ANNOUNCE_IE ChannelSwitch; ++ ++ // 802.11h only has Channel Switch Announcement IE. ++ RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE)); ++ ++ // 802.11n D3.03 adds secondary channel offset element in the end. ++ if (Elem->MsgLen == (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE))) ++ { ++ RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE)); ++ } ++ else ++ { ++ Secondary.SecondaryChannelOffset = 0; ++ } ++ ++ if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3)) ++ { ++ ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset); ++ } ++#endif // DOT11N_DRAFT3 // ++} ++ PeerChSwAnnAction(pAd, Elem); ++ break; ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Parametrs: ++ ++ Return : None. ++ ========================================================================== ++ */ ++INT Set_MeasureReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT Aid = 1; ++ UINT ArgIdx; ++ PUCHAR thisChar; ++ ++ MEASURE_REQ_MODE MeasureReqMode; ++ UINT8 MeasureReqToken = RandomByte(pAd); ++ UINT8 MeasureReqType = RM_BASIC; ++ UINT8 MeasureCh = 1; ++ ++ ArgIdx = 1; ++ while ((thisChar = strsep((char **)&arg, "-")) != NULL) ++ { ++ switch(ArgIdx) ++ { ++ case 1: // Aid. ++ Aid = simple_strtol(thisChar, 0, 16); ++ break; ++ ++ case 2: // Measurement Request Type. ++ MeasureReqType = simple_strtol(thisChar, 0, 16); ++ if (MeasureReqType > 3) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType)); ++ return TRUE; ++ } ++ break; ++ ++ case 3: // Measurement channel. ++ MeasureCh = simple_strtol(thisChar, 0, 16); ++ break; ++ } ++ ArgIdx++; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh)); ++ if (!VALID_WCID(Aid)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ return TRUE; ++ } ++ ++ MeasureReqMode.word = 0; ++ MeasureReqMode.field.Enable = 1; ++ ++ MeasureReqInsert(pAd, MeasureReqToken); ++ ++ EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr, ++ MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000); ++ ++ return TRUE; ++} ++ ++INT Set_TpcReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT Aid; ++ ++ UINT8 TpcReqToken = RandomByte(pAd); ++ ++ Aid = simple_strtol(arg, 0, 16); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid)); ++ if (!VALID_WCID(Aid)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ return TRUE; ++ } ++ ++ TpcReqInsert(pAd, TpcReqToken); ++ ++ EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken); ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/dfs.h +@@ -0,0 +1,100 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ dfs.h ++ ++ Abstract: ++ Support DFS function. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi 03-12-2007 created ++*/ ++ ++#define RADAR_PULSE 1 ++#define RADAR_WIDTH 2 ++ ++#define WIDTH_RD_IDLE 0 ++#define WIDTH_RD_CHECK 1 ++ ++ ++VOID BbpRadarDetectionStart( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BbpRadarDetectionStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RadarDetectionStart( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN CTS_Protect, ++ IN UINT8 CTSPeriod); ++ ++VOID RadarDetectionStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++BOOLEAN RadarChannelCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ch); ++ ++ULONG JapRadarType( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPBbpReadRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPReadRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPCleanRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPrepareRDCTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN ULONG Duration, ++ IN UCHAR RTSRate, ++ IN ULONG CTSBaseAddr, ++ IN UCHAR FrameGap); ++ ++VOID RTMPPrepareRadarDetectParams( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++INT Set_ChMovingTime_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_LongPulseRadarTh_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/Kconfig +@@ -0,0 +1,6 @@ ++config RT2870 ++ tristate "Ralink 2870 wireless support" ++ depends on USB && X86 && WLAN_80211 ++ ---help--- ++ This is an experimental driver for the Ralink 2870 wireless chip. ++ +--- /dev/null ++++ b/drivers/staging/rt2870/leap.h +@@ -0,0 +1,215 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ leap.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef __LEAP_H__ ++#define __LEAP_H__ ++ ++// Messages for Associate state machine ++#define LEAP_MACHINE_BASE 30 ++ ++#define LEAP_MSG_REQUEST_IDENTITY 31 ++#define LEAP_MSG_REQUEST_LEAP 32 ++#define LEAP_MSG_SUCCESS 33 ++#define LEAP_MSG_FAILED 34 ++#define LEAP_MSG_RESPONSE_LEAP 35 ++#define LEAP_MSG_EAPOLKEY 36 ++#define LEAP_MSG_UNKNOWN 37 ++#define LEAP_MSG 38 ++//! assoc state-machine states ++#define LEAP_IDLE 0 ++#define LEAP_WAIT_IDENTITY_REQUEST 1 ++#define LEAP_WAIT_CHANLLENGE_REQUEST 2 ++#define LEAP_WAIT_SUCCESS 3 ++#define LEAP_WAIT_CHANLLENGE_RESPONSE 4 ++#define LEAP_WAIT_EAPOLKEY 5 ++ ++#define LEAP_REASON_INVALID_AUTH 0x01 ++#define LEAP_REASON_AUTH_TIMEOUT 0x02 ++#define LEAP_REASON_CHALLENGE_FROM_AP_FAILED 0x03 ++#define LEAP_REASON_CHALLENGE_TO_AP_FAILED 0x04 ++ ++#define CISCO_AuthModeLEAP 0x80 ++#define CISCO_AuthModeLEAPNone 0x00 ++#define LEAP_AUTH_TIMEOUT 30000 ++#define LEAP_CHALLENGE_RESPONSE_LENGTH 24 ++#define LEAP_CHALLENGE_REQUEST_LENGTH 8 ++ ++typedef struct _LEAP_EAPOL_HEADER_ { ++ UCHAR Version; ++ UCHAR Type; ++ UCHAR Length[2]; ++} LEAP_EAPOL_HEADER, *PLEAP_EAPOL_HEADER; ++ ++typedef struct _LEAP_EAPOL_PACKET_ { ++ UCHAR Code; ++ UCHAR Identifier; ++ UCHAR Length[2]; ++ UCHAR Type; ++} LEAP_EAPOL_PACKET, *PLEAP_EAPOL_PACKET; ++ ++typedef struct _LEAP_EAP_CONTENTS_ { ++ UCHAR Version; ++ UCHAR Reserved; ++ UCHAR Length; ++} LEAP_EAP_CONTENTS, *PLEAP_EAP_CONTENTS; ++ ++/*** EAPOL key ***/ ++typedef struct _EAPOL_KEY_HEADER_ { ++ UCHAR Type; ++ UCHAR Length[2]; ++ UCHAR Counter[8]; ++ UCHAR IV[16]; ++ UCHAR Index; ++ UCHAR Signature[16]; ++} EAPOL_KEY_HEADER, *PEAPOL_KEY_HEADER; ++ ++BOOLEAN LeapMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT ULONG *MsgType); ++ ++VOID LeapMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr3); ++ ++VOID LeapStartAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapIdentityAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapPeerChallengeAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HashPwd( ++ IN PUCHAR pwd, ++ IN INT pwdlen, ++ OUT PUCHAR hash); ++ ++VOID PeerChallengeResponse( ++ IN PUCHAR szChallenge, ++ IN PUCHAR smbPasswd, ++ OUT PUCHAR szResponse); ++ ++VOID ParityKey( ++ OUT PUCHAR szOut, ++ IN PUCHAR szIn); ++ ++VOID DesKey( ++ OUT ULONG k[16][2], ++ IN PUCHAR key, ++ IN INT decrypt); ++ ++VOID Des( ++ IN ULONG ks[16][2], ++ OUT UCHAR block[8]); ++ ++VOID DesEncrypt( ++ IN PUCHAR szClear, ++ IN PUCHAR szKey, ++ OUT PUCHAR szOut); ++ ++VOID LeapNetworkChallengeAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapNetworkChallengeResponse( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HashpwdHash( ++ IN PUCHAR hash, ++ IN PUCHAR hashhash); ++ ++VOID ProcessSessionKey( ++ OUT PUCHAR SessionKey, ++ IN PUCHAR hash2, ++ IN PUCHAR ChallengeToRadius, ++ IN PUCHAR ChallengeResponseFromRadius, ++ IN PUCHAR ChallengeFromRadius, ++ IN PUCHAR ChallengeResponseToRadius); ++ ++VOID LeapEapolKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID RogueApTableInit( ++ IN ROGUEAP_TABLE *Tab); ++ ++ULONG RogueApTableSearch( ++ IN ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr); ++ ++VOID RogueApEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT ROGUEAP_ENTRY *pRogueAp, ++ IN PUCHAR pAddr, ++ IN UCHAR FaileCode); ++ ++ULONG RogueApTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr, ++ IN UCHAR FaileCode); ++ ++VOID RogueApTableDeleteEntry( ++ IN OUT ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr); ++ ++VOID LeapAuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LeapSendRogueAPReport( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN CCKMAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen); ++ ++#endif // __LEAP_H__ +--- /dev/null ++++ b/drivers/staging/rt2870/link_list.h +@@ -0,0 +1,134 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __LINK_LIST_H__ ++#define __LINK_LIST_H__ ++ ++typedef struct _LIST_ENTRY ++{ ++ struct _LIST_ENTRY *pNext; ++} LIST_ENTRY, *PLIST_ENTRY; ++ ++typedef struct _LIST_HEADR ++{ ++ PLIST_ENTRY pHead; ++ PLIST_ENTRY pTail; ++ UCHAR size; ++} LIST_HEADER, *PLIST_HEADER; ++ ++static inline VOID initList( ++ IN PLIST_HEADER pList) ++{ ++ pList->pHead = pList->pTail = NULL; ++ pList->size = 0; ++ return; ++} ++ ++static inline VOID insertTailList( ++ IN PLIST_HEADER pList, ++ IN PLIST_ENTRY pEntry) ++{ ++ pEntry->pNext = NULL; ++ if (pList->pTail) ++ pList->pTail->pNext = pEntry; ++ else ++ pList->pHead = pEntry; ++ pList->pTail = pEntry; ++ pList->size++; ++ ++ return; ++} ++ ++static inline PLIST_ENTRY removeHeadList( ++ IN PLIST_HEADER pList) ++{ ++ PLIST_ENTRY pNext; ++ PLIST_ENTRY pEntry; ++ ++ pEntry = pList->pHead; ++ if (pList->pHead != NULL) ++ { ++ pNext = pList->pHead->pNext; ++ pList->pHead = pNext; ++ if (pNext == NULL) ++ pList->pTail = NULL; ++ pList->size--; ++ } ++ return pEntry; ++} ++ ++static inline int getListSize( ++ IN PLIST_HEADER pList) ++{ ++ return pList->size; ++} ++ ++static inline PLIST_ENTRY delEntryList( ++ IN PLIST_HEADER pList, ++ IN PLIST_ENTRY pEntry) ++{ ++ PLIST_ENTRY pCurEntry; ++ PLIST_ENTRY pPrvEntry; ++ ++ if(pList->pHead == NULL) ++ return NULL; ++ ++ if(pEntry == pList->pHead) ++ { ++ pCurEntry = pList->pHead; ++ pList->pHead = pCurEntry->pNext; ++ ++ if(pList->pHead == NULL) ++ pList->pTail = NULL; ++ ++ pList->size--; ++ return pCurEntry; ++ } ++ ++ pPrvEntry = pList->pHead; ++ pCurEntry = pPrvEntry->pNext; ++ while(pCurEntry != NULL) ++ { ++ if (pEntry == pCurEntry) ++ { ++ pPrvEntry->pNext = pCurEntry->pNext; ++ ++ if(pEntry == pList->pTail) ++ pList->pTail = pPrvEntry; ++ ++ pList->size--; ++ break; ++ } ++ pPrvEntry = pCurEntry; ++ pCurEntry = pPrvEntry->pNext; ++ } ++ ++ return pCurEntry; ++} ++ ++#endif // ___LINK_LIST_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/Makefile +@@ -0,0 +1,47 @@ ++obj-$(CONFIG_RT2870) += rt2870sta.o ++ ++# TODO: all of these should be removed ++EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT ++EXTRA_CFLAGS += -DRT2870 ++EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT ++EXTRA_CFLAGS += -DDBG ++EXTRA_CFLAGS += -DDOT11_N_SUPPORT ++EXTRA_CFLAGS += -DWPA_SUPPLICANT_SUPPORT ++EXTRA_CFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT ++ ++rt2870sta-objs := \ ++ common/md5.o \ ++ common/mlme.o \ ++ common/rtmp_wep.o \ ++ common/action.o \ ++ common/cmm_data.o \ ++ common/rtmp_init.o \ ++ common/rtmp_tkip.o \ ++ common/cmm_sync.o \ ++ common/eeprom.o \ ++ common/cmm_sanity.o \ ++ common/cmm_info.o \ ++ common/cmm_wpa.o \ ++ common/dfs.o \ ++ common/spectrum.o \ ++ sta/assoc.o \ ++ sta/aironet.o \ ++ sta/auth.o \ ++ sta/auth_rsp.o \ ++ sta/sync.o \ ++ sta/sanity.o \ ++ sta/rtmp_data.o \ ++ sta/connect.o \ ++ sta/wpa.o \ ++ rt_linux.o \ ++ rt_profile.o \ ++ rt_main_dev.o \ ++ sta_ioctl.o \ ++ common/ba_action.o \ ++ 2870_main_dev.o \ ++ common/2870_rtmp_init.o \ ++ common/rtusb_io.o \ ++ common/rtusb_bulk.o \ ++ common/rtusb_data.o \ ++ common/cmm_data_2870.o ++ +--- /dev/null ++++ b/drivers/staging/rt2870/md4.h +@@ -0,0 +1,42 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __MD4_H__ ++#define __MD4_H__ ++ ++/* MD4 context. */ ++typedef struct _MD4_CTX_ { ++ ULONG state[4]; /* state (ABCD) */ ++ ULONG count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ UCHAR buffer[64]; /* input buffer */ ++} MD4_CTX; ++ ++VOID MD4Init (MD4_CTX *); ++VOID MD4Update (MD4_CTX *, PUCHAR, UINT); ++VOID MD4Final (UCHAR [16], MD4_CTX *); ++ ++#endif //__MD4_H__ +\ No newline at end of file +--- /dev/null ++++ b/drivers/staging/rt2870/md5.h +@@ -0,0 +1,107 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ md5.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ jan 10-28-03 Initial ++ Rita 11-23-04 Modify MD5 and SHA-1 ++*/ ++ ++#ifndef uint8 ++#define uint8 unsigned char ++#endif ++ ++#ifndef uint32 ++#define uint32 unsigned long int ++#endif ++ ++ ++#ifndef __MD5_H__ ++#define __MD5_H__ ++ ++#define MD5_MAC_LEN 16 ++ ++typedef struct _MD5_CTX { ++ UINT32 Buf[4]; // buffers of four states ++ UCHAR Input[64]; // input message ++ UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits ++} MD5_CTX; ++ ++VOID MD5Init(MD5_CTX *pCtx); ++VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); ++VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx); ++VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]); ++ ++void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); ++void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); ++ ++// ++// SHA context ++// ++typedef struct _SHA_CTX ++{ ++ UINT32 Buf[5]; // buffers of five states ++ UCHAR Input[80]; // input message ++ UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits ++ ++} SHA_CTX; ++ ++VOID SHAInit(SHA_CTX *pCtx); ++UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); ++VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]); ++VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]); ++ ++#define SHA_DIGEST_LEN 20 ++#endif // __MD5_H__ ++ ++/******************************************************************************/ ++#ifndef _AES_H ++#define _AES_H ++ ++typedef struct ++{ ++ uint32 erk[64]; /* encryption round keys */ ++ uint32 drk[64]; /* decryption round keys */ ++ int nr; /* number of rounds */ ++} ++aes_context; ++ ++int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ); ++void rtmp_aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); ++void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); ++ ++void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output); ++int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output); ++ ++#endif /* aes.h */ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/mlme.h +@@ -0,0 +1,1471 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ mlme.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2003-08-28 Created ++ John Chang 2004-09-06 modified for RT2600 ++ ++*/ ++#ifndef __MLME_H__ ++#define __MLME_H__ ++ ++//extern UCHAR BROADCAST_ADDR[]; ++ ++// maximum supported capability information - ++// ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot ++#define SUPPORTED_CAPABILITY_INFO 0x0533 ++ ++#define END_OF_ARGS -1 ++#define LFSR_MASK 0x80000057 ++#define MLME_TASK_EXEC_INTV 100/*200*/ // ++#define LEAD_TIME 5 ++#define MLME_TASK_EXEC_MULTIPLE 10 /*5*/ // MLME_TASK_EXEC_MULTIPLE * MLME_TASK_EXEC_INTV = 1 sec ++#define REORDER_EXEC_INTV 100 // 0.1 sec ++//#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps ++ ++// The definition of Radar detection duration region ++#define CE 0 ++#define FCC 1 ++#define JAP 2 ++#define JAP_W53 3 ++#define JAP_W56 4 ++#define MAX_RD_REGION 5 ++ ++#ifdef NDIS51_MINIPORT ++#define BEACON_LOST_TIME 4000 // 2048 msec = 2 sec ++#else ++#define BEACON_LOST_TIME 4 * OS_HZ // 2048 msec = 2 sec ++#endif ++ ++#define DLS_TIMEOUT 1200 // unit: msec ++#define AUTH_TIMEOUT 300 // unit: msec ++#define ASSOC_TIMEOUT 300 // unit: msec ++#define JOIN_TIMEOUT 2 * OS_HZ // unit: msec ++#define SHORT_CHANNEL_TIME 90 // unit: msec ++#define MIN_CHANNEL_TIME 110 // unit: msec, for dual band scan ++#define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan ++#define FAST_ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time ++#define CW_MIN_IN_BITS 4 // actual CwMin = 2^CW_MIN_IN_BITS - 1 ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifndef CONFIG_AP_SUPPORT ++#define CW_MAX_IN_BITS 10 // actual CwMax = 2^CW_MAX_IN_BITS - 1 ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++extern UINT32 CW_MAX_IN_BITS; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++// Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). ++// SHould not refer to this constant anymore ++//#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm ++#define RSSI_FOR_MID_TX_POWER -55 // -55 db is considered mid-distance ++#define RSSI_FOR_LOW_TX_POWER -45 // -45 db is considered very short distance and ++ // eligible to use a lower TX power ++#define RSSI_FOR_LOWEST_TX_POWER -30 ++//#define MID_TX_POWER_DELTA 0 // 0 db from full TX power upon mid-distance to AP ++#define LOW_TX_POWER_DELTA 6 // -3 db from full TX power upon very short distance. 1 grade is 0.5 db ++#define LOWEST_TX_POWER_DELTA 16 // -8 db from full TX power upon shortest distance. 1 grade is 0.5 db ++ ++#define RSSI_TRIGGERED_UPON_BELOW_THRESHOLD 0 ++#define RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD 1 ++#define RSSI_THRESHOLD_FOR_ROAMING 25 ++#define RSSI_DELTA 5 ++ ++// Channel Quality Indication ++#define CQI_IS_GOOD(cqi) ((cqi) >= 50) ++//#define CQI_IS_FAIR(cqi) (((cqi) >= 20) && ((cqi) < 50)) ++#define CQI_IS_POOR(cqi) (cqi < 50) //(((cqi) >= 5) && ((cqi) < 20)) ++#define CQI_IS_BAD(cqi) (cqi < 5) ++#define CQI_IS_DEAD(cqi) (cqi == 0) ++ ++// weighting factor to calculate Channel quality, total should be 100% ++#define RSSI_WEIGHTING 50 ++#define TX_WEIGHTING 30 ++#define RX_WEIGHTING 20 ++ ++//#define PEER_KEY_NOT_USED 0 ++//#define PEER_KEY_64_BIT 64 ++//#define PEER_KEY_128_BIT 128 ++ ++//#define PEER_KEY_64BIT_LEN 8 ++//#define PEER_KEY_128BIT_LEN 16 ++ ++#define BSS_NOT_FOUND 0xFFFFFFFF ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define MAX_LEN_OF_MLME_QUEUE 40 //10 ++#endif // CONFIG_STA_SUPPORT // ++ ++#define SCAN_PASSIVE 18 // scan with no probe request, only wait beacon and probe response ++#define SCAN_ACTIVE 19 // scan with probe request, and wait beacon and probe response ++#define SCAN_CISCO_PASSIVE 20 // Single channel passive scan ++#define SCAN_CISCO_ACTIVE 21 // Single channel active scan ++#define SCAN_CISCO_NOISE 22 // Single channel passive scan for noise histogram collection ++#define SCAN_CISCO_CHANNEL_LOAD 23 // Single channel passive scan for channel load collection ++#define FAST_SCAN_ACTIVE 24 // scan with probe request, and wait beacon and probe response ++ ++#ifdef DOT11N_DRAFT3 ++#define SCAN_2040_BSS_COEXIST 26 ++#endif // DOT11N_DRAFT3 // ++ ++//#define BSS_TABLE_EMPTY(x) ((x).BssNr == 0) ++#define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01)) ++#define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) ++#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) ++#define TID_MAC_HASH(Addr,TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) ++#define TID_MAC_HASH_INDEX(Addr,TID) (TID_MAC_HASH(Addr,TID) % HASH_TABLE_SIZE) ++ ++// LED Control ++// assoiation ON. one LED ON. another blinking when TX, OFF when idle ++// no association, both LED off ++#define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46) ++#define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46) ++ ++// bit definition of the 2-byte pBEACON->Capability field ++#define CAP_IS_ESS_ON(x) (((x) & 0x0001) != 0) ++#define CAP_IS_IBSS_ON(x) (((x) & 0x0002) != 0) ++#define CAP_IS_CF_POLLABLE_ON(x) (((x) & 0x0004) != 0) ++#define CAP_IS_CF_POLL_REQ_ON(x) (((x) & 0x0008) != 0) ++#define CAP_IS_PRIVACY_ON(x) (((x) & 0x0010) != 0) ++#define CAP_IS_SHORT_PREAMBLE_ON(x) (((x) & 0x0020) != 0) ++#define CAP_IS_PBCC_ON(x) (((x) & 0x0040) != 0) ++#define CAP_IS_AGILITY_ON(x) (((x) & 0x0080) != 0) ++#define CAP_IS_SPECTRUM_MGMT(x) (((x) & 0x0100) != 0) // 802.11e d9 ++#define CAP_IS_QOS(x) (((x) & 0x0200) != 0) // 802.11e d9 ++#define CAP_IS_SHORT_SLOT(x) (((x) & 0x0400) != 0) ++#define CAP_IS_APSD(x) (((x) & 0x0800) != 0) // 802.11e d9 ++#define CAP_IS_IMMED_BA(x) (((x) & 0x1000) != 0) // 802.11e d9 ++#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0) ++#define CAP_IS_DELAY_BA(x) (((x) & 0x4000) != 0) // 802.11e d9 ++ ++#define CAP_GENERATE(ess,ibss,priv,s_pre,s_slot,spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000)) ++ ++//#define STA_QOS_CAPABILITY 0 // 1-byte. see 802.11e d9.0 for bit definition ++ ++#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) // 802.11g ++#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) // 802.11g ++#define ERP_IS_USE_BARKER_PREAMBLE(x) (((x) & 0x04) != 0) // 802.11g ++ ++#define DRS_TX_QUALITY_WORST_BOUND 8// 3 // just test by gary ++#define DRS_PENALTY 8 ++ ++#define BA_NOTUSE 2 ++//BA Policy subfiled value in ADDBA frame ++#define IMMED_BA 1 ++#define DELAY_BA 0 ++ ++// BA Initiator subfield in DELBA frame ++#define ORIGINATOR 1 ++#define RECIPIENT 0 ++ ++// ADDBA Status Code ++#define ADDBA_RESULTCODE_SUCCESS 0 ++#define ADDBA_RESULTCODE_REFUSED 37 ++#define ADDBA_RESULTCODE_INVALID_PARAMETERS 38 ++ ++// DELBA Reason Code ++#define DELBA_REASONCODE_QSTA_LEAVING 36 ++#define DELBA_REASONCODE_END_BA 37 ++#define DELBA_REASONCODE_UNKNOWN_BA 38 ++#define DELBA_REASONCODE_TIMEOUT 39 ++ ++// reset all OneSecTx counters ++#define RESET_ONE_SEC_TX_CNT(__pEntry) \ ++if (((__pEntry)) != NULL) \ ++{ \ ++ (__pEntry)->OneSecTxRetryOkCount = 0; \ ++ (__pEntry)->OneSecTxFailCount = 0; \ ++ (__pEntry)->OneSecTxNoRetryOkCount = 0; \ ++} ++ ++// ++// 802.11 frame formats ++// ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT LSIGTxopProSup:1; ++ USHORT Forty_Mhz_Intolerant:1; ++ USHORT PSMP:1; ++ USHORT CCKmodein40:1; ++ USHORT AMsduSize:1; ++ USHORT DelayedBA:1; //rt2860c not support ++ USHORT RxSTBC:2; ++ USHORT TxSTBC:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT ShortGIfor20:1; ++ USHORT GF:1; //green field ++ USHORT MimoPs:2;//momi power safe ++ USHORT ChannelWidth:1; ++ USHORT AdvCoding:1; ++#else ++ USHORT AdvCoding:1; ++ USHORT ChannelWidth:1; ++ USHORT MimoPs:2;//momi power safe ++ USHORT GF:1; //green field ++ USHORT ShortGIfor20:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT TxSTBC:1; ++ USHORT RxSTBC:2; ++ USHORT DelayedBA:1; //rt2860c not support ++ USHORT AMsduSize:1; // only support as zero ++ USHORT CCKmodein40:1; ++ USHORT PSMP:1; ++ USHORT Forty_Mhz_Intolerant:1; ++ USHORT LSIGTxopProSup:1; ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CAP_INFO, *PHT_CAP_INFO; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:3;//momi power safe ++ UCHAR MpduDensity:3; ++ UCHAR MaxRAmpduFactor:2; ++#else ++ UCHAR MaxRAmpduFactor:2; ++ UCHAR MpduDensity:3; ++ UCHAR rsv:3;//momi power safe ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CAP_PARM, *PHT_CAP_PARM; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++ UCHAR MCSSet[10]; ++ UCHAR SupRate[2]; // unit : 1Mbps ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:3; ++ UCHAR MpduDensity:1; ++ UCHAR TxStream:2; ++ UCHAR TxRxNotEqual:1; ++ UCHAR TxMCSSetDefined:1; ++#else ++ UCHAR TxMCSSetDefined:1; ++ UCHAR TxRxNotEqual:1; ++ UCHAR TxStream:2; ++ UCHAR MpduDensity:1; ++ UCHAR rsv:3; ++#endif // RT_BIG_ENDIAN // ++ UCHAR rsv3[3]; ++} HT_MCS_SET, *PHT_MCS_SET; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:4; ++ USHORT RDGSupport:1; //reverse Direction Grant support ++ USHORT PlusHTC:1; //+HTC control field support ++ USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. ++ USHORT rsv:5;//momi power safe ++ USHORT TranTime:2; ++ USHORT Pco:1; ++#else ++ USHORT Pco:1; ++ USHORT TranTime:2; ++ USHORT rsv:5;//momi power safe ++ USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. ++ USHORT PlusHTC:1; //+HTC control field support ++ USHORT RDGSupport:1; //reverse Direction Grant support ++ USHORT rsv2:4; ++#endif /* RT_BIG_ENDIAN */ ++} EXT_HT_CAP_INFO, *PEXT_HT_CAP_INFO; ++ ++// HT Beamforming field in HT Cap IE . ++typedef struct PACKED _HT_BF_CAP{ ++#ifdef RT_BIG_ENDIAN ++ ULONG rsv:3; ++ ULONG ChanEstimation:2; ++ ULONG CSIRowBFSup:2; ++ ULONG ComSteerBFAntSup:2; ++ ULONG NoComSteerBFAntSup:2; ++ ULONG CSIBFAntSup:2; ++ ULONG MinGrouping:2; ++ ULONG ExpComBF:2; ++ ULONG ExpNoComBF:2; ++ ULONG ExpCSIFbk:2; ++ ULONG ExpComSteerCapable:1; ++ ULONG ExpNoComSteerCapable:1; ++ ULONG ExpCSICapable:1; ++ ULONG Calibration:2; ++ ULONG ImpTxBFCapable:1; ++ ULONG TxNDPCapable:1; ++ ULONG RxNDPCapable:1; ++ ULONG TxSoundCapable:1; ++ ULONG RxSoundCapable:1; ++ ULONG TxBFRecCapable:1; ++#else ++ ULONG TxBFRecCapable:1; ++ ULONG RxSoundCapable:1; ++ ULONG TxSoundCapable:1; ++ ULONG RxNDPCapable:1; ++ ULONG TxNDPCapable:1; ++ ULONG ImpTxBFCapable:1; ++ ULONG Calibration:2; ++ ULONG ExpCSICapable:1; ++ ULONG ExpNoComSteerCapable:1; ++ ULONG ExpComSteerCapable:1; ++ ULONG ExpCSIFbk:2; ++ ULONG ExpNoComBF:2; ++ ULONG ExpComBF:2; ++ ULONG MinGrouping:2; ++ ULONG CSIBFAntSup:2; ++ ULONG NoComSteerBFAntSup:2; ++ ULONG ComSteerBFAntSup:2; ++ ULONG CSIRowBFSup:2; ++ ULONG ChanEstimation:2; ++ ULONG rsv:3; ++#endif // RT_BIG_ENDIAN // ++} HT_BF_CAP, *PHT_BF_CAP; ++ ++// HT antenna selection field in HT Cap IE . ++typedef struct PACKED _HT_AS_CAP{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:1; ++ UCHAR TxSoundPPDU:1; ++ UCHAR RxASel:1; ++ UCHAR AntIndFbk:1; ++ UCHAR ExpCSIFbk:1; ++ UCHAR AntIndFbkTxASEL:1; ++ UCHAR ExpCSIFbkTxASEL:1; ++ UCHAR AntSelect:1; ++#else ++ UCHAR AntSelect:1; ++ UCHAR ExpCSIFbkTxASEL:1; ++ UCHAR AntIndFbkTxASEL:1; ++ UCHAR ExpCSIFbk:1; ++ UCHAR AntIndFbk:1; ++ UCHAR RxASel:1; ++ UCHAR TxSoundPPDU:1; ++ UCHAR rsv:1; ++#endif // RT_BIG_ENDIAN // ++} HT_AS_CAP, *PHT_AS_CAP; ++ ++// Draft 1.0 set IE length 26, but is extensible.. ++#define SIZE_HT_CAP_IE 26 ++// The structure for HT Capability IE. ++typedef struct PACKED _HT_CAPABILITY_IE{ ++ HT_CAP_INFO HtCapInfo; ++ HT_CAP_PARM HtCapParm; ++// HT_MCS_SET HtMCSSet; ++ UCHAR MCSSet[16]; ++ EXT_HT_CAP_INFO ExtHtCapInfo; ++ HT_BF_CAP TxBFCap; // beamforming cap. rt2860c not support beamforming. ++ HT_AS_CAP ASCap; //antenna selection. ++} HT_CAPABILITY_IE, *PHT_CAPABILITY_IE; ++ ++ ++// 802.11n draft3 related structure definitions. ++// 7.3.2.60 ++#define dot11OBSSScanPassiveDwell 20 // in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. ++#define dot11OBSSScanActiveDwell 10 // in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. ++#define dot11BSSWidthTriggerScanInterval 300 // in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. ++#define dot11OBSSScanPassiveTotalPerChannel 200 // in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. ++#define dot11OBSSScanActiveTotalPerChannel 20 //in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan ++#define dot11BSSWidthChannelTransactionDelayFactor 5 // min ratio between the delay time in performing a switch from 20MHz BSS to 20/40 BSS operation and the maxima ++ // interval between overlapping BSS scan operations. ++#define dot11BSSScanActivityThreshold 25 // in %%, max total time that a STA may be active on the medium during a period of ++ // (dot11BSSWidthChannelTransactionDelayFactor * dot11BSSWidthTriggerScanInterval) seconds without ++ // being obligated to perform OBSS Scan operations. default is 25(== 0.25%) ++ ++typedef struct PACKED _OVERLAP_BSS_SCAN_IE{ ++ USHORT ScanPassiveDwell; ++ USHORT ScanActiveDwell; ++ USHORT TriggerScanInt; // Trigger scan interval ++ USHORT PassiveTalPerChannel; // passive total per channel ++ USHORT ActiveTalPerChannel; // active total per channel ++ USHORT DelayFactor; // BSS width channel transition delay factor ++ USHORT ScanActThre; // Scan Activity threshold ++}OVERLAP_BSS_SCAN_IE, *POVERLAP_BSS_SCAN_IE; ++ ++ ++// 7.3.2.56. 20/40 Coexistence element used in Element ID = 72 = IE_2040_BSS_COEXIST ++typedef union PACKED _BSS_2040_COEXIST_IE{ ++ struct PACKED { ++ #ifdef RT_BIG_ENDIAN ++ UCHAR rsv:5; ++ UCHAR BSS20WidthReq:1; ++ UCHAR Intolerant40:1; ++ UCHAR InfoReq:1; ++ #else ++ UCHAR InfoReq:1; ++ UCHAR Intolerant40:1; // Inter-BSS. set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS. ++ UCHAR BSS20WidthReq:1; // Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS. ++ UCHAR rsv:5; ++#endif // RT_BIG_ENDIAN // ++ } field; ++ UCHAR word; ++} BSS_2040_COEXIST_IE, *PBSS_2040_COEXIST_IE; ++ ++ ++typedef struct _TRIGGER_EVENTA{ ++ BOOLEAN bValid; ++ UCHAR BSSID[6]; ++ UCHAR RegClass; // Regulatory Class ++ USHORT Channel; ++ ULONG CDCounter; // Maintain a seperate count down counter for each Event A. ++} TRIGGER_EVENTA, *PTRIGGER_EVENTA; ++ ++// 20/40 trigger event table ++// If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. ++#define MAX_TRIGGER_EVENT 64 ++typedef struct _TRIGGER_EVENT_TAB{ ++ UCHAR EventANo; ++ TRIGGER_EVENTA EventA[MAX_TRIGGER_EVENT]; ++ ULONG EventBCountDown; // Count down counter for Event B. ++} TRIGGER_EVENT_TAB, *PTRIGGER_EVENT_TAB; ++ ++// 7.3.27 20/40 Bss Coexistence Mgmt capability used in extended capabilities information IE( ID = 127 = IE_EXT_CAPABILITY). ++// This is the first octet and was defined in 802.11n D3.03 and 802.11yD9.0 ++typedef struct PACKED _EXT_CAP_INFO_ELEMENT{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv2:5; ++ UCHAR ExtendChannelSwitch:1; ++ UCHAR rsv:1; ++ UCHAR BssCoexistMgmtSupport:1; ++#else ++ UCHAR BssCoexistMgmtSupport:1; ++ UCHAR rsv:1; ++ UCHAR ExtendChannelSwitch:1; ++ UCHAR rsv2:5; ++#endif // RT_BIG_ENDIAN // ++}EXT_CAP_INFO_ELEMENT, *PEXT_CAP_INFO_ELEMENT; ++ ++ ++// 802.11n 7.3.2.61 ++typedef struct PACKED _BSS_2040_COEXIST_ELEMENT{ ++ UCHAR ElementID; // ID = IE_2040_BSS_COEXIST = 72 ++ UCHAR Len; ++ BSS_2040_COEXIST_IE BssCoexistIe; ++}BSS_2040_COEXIST_ELEMENT, *PBSS_2040_COEXIST_ELEMENT; ++ ++ ++//802.11n 7.3.2.59 ++typedef struct PACKED _BSS_2040_INTOLERANT_CH_REPORT{ ++ UCHAR ElementID; // ID = IE_2040_BSS_INTOLERANT_REPORT = 73 ++ UCHAR Len; ++ UCHAR RegulatoryClass; ++ UCHAR ChList[0]; ++}BSS_2040_INTOLERANT_CH_REPORT, *PBSS_2040_INTOLERANT_CH_REPORT; ++ ++ ++// The structure for channel switch annoucement IE. This is in 802.11n D3.03 ++typedef struct PACKED _CHA_SWITCH_ANNOUNCE_IE{ ++ UCHAR SwitchMode; //channel switch mode ++ UCHAR NewChannel; // ++ UCHAR SwitchCount; // ++} CHA_SWITCH_ANNOUNCE_IE, *PCHA_SWITCH_ANNOUNCE_IE; ++ ++ ++// The structure for channel switch annoucement IE. This is in 802.11n D3.03 ++typedef struct PACKED _SEC_CHA_OFFSET_IE{ ++ UCHAR SecondaryChannelOffset; // 1: Secondary above, 3: Secondary below, 0: no Secondary ++} SEC_CHA_OFFSET_IE, *PSEC_CHA_OFFSET_IE; ++ ++ ++// This structure is extracted from struct RT_HT_CAPABILITY ++typedef struct { ++ BOOLEAN bHtEnable; // If we should use ht rate. ++ BOOLEAN bPreNHt; // If we should use ht rate. ++ //Substract from HT Capability IE ++ UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , ++} RT_HT_PHY_INFO, *PRT_HT_PHY_INFO; ++ ++//This structure substracts ralink supports from all 802.11n-related features. ++//Features not listed here but contained in 802.11n spec are not supported in rt2860. ++typedef struct { ++#if 0 // move to ++ BOOLEAN bHtEnable; // If we should use ht rate. ++ BOOLEAN bPreNHt; // If we should use ht rate. ++ //Substract from HT Capability IE ++ UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , ++#endif ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv:5; ++ USHORT AmsduSize:1; // Max receiving A-MSDU size ++ USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n ++ USHORT RxSTBC:2; // 2 bits ++ USHORT TxSTBC:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT ShortGIfor20:1; ++ USHORT GF:1; //green field ++ USHORT MimoPs:2;//mimo power safe MMPS_ ++ USHORT ChannelWidth:1; ++#else ++ USHORT ChannelWidth:1; ++ USHORT MimoPs:2;//mimo power safe MMPS_ ++ USHORT GF:1; //green field ++ USHORT ShortGIfor20:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT TxSTBC:1; ++ USHORT RxSTBC:2; // 2 bits ++ USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n ++ USHORT AmsduSize:1; // Max receiving A-MSDU size ++ USHORT rsv:5; ++#endif ++ ++ //Substract from Addiont HT INFO IE ++#ifdef RT_BIG_ENDIAN ++ UCHAR RecomWidth:1; ++ UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n ++ UCHAR MpduDensity:3; ++ UCHAR MaxRAmpduFactor:2; ++#else ++ UCHAR MaxRAmpduFactor:2; ++ UCHAR MpduDensity:3; ++ UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n ++ UCHAR RecomWidth:1; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:11; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv3:1; ++ USHORT NonGfPresent:1; ++ USHORT OperaionMode:2; ++#else ++ USHORT OperaionMode:2; ++ USHORT NonGfPresent:1; ++ USHORT rsv3:1; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv2:11; ++#endif ++ ++ // New Extension Channel Offset IE ++ UCHAR NewExtChannelOffset; ++ // Extension Capability IE = 127 ++ UCHAR BSSCoexist2040; ++} RT_HT_CAPABILITY, *PRT_HT_CAPABILITY; ++ ++// field in Addtional HT Information IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR SerInterGranu:3; ++ UCHAR S_PSMPSup:1; ++ UCHAR RifsMode:1; ++ UCHAR RecomWidth:1; ++ UCHAR ExtChanOffset:2; ++#else ++ UCHAR ExtChanOffset:2; ++ UCHAR RecomWidth:1; ++ UCHAR RifsMode:1; ++ UCHAR S_PSMPSup:1; //Indicate support for scheduled PSMP ++ UCHAR SerInterGranu:3; //service interval granularity ++#endif ++} ADD_HTINFO, *PADD_HTINFO; ++ ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:11; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv:1; ++ USHORT NonGfPresent:1; ++ USHORT OperaionMode:2; ++#else ++ USHORT OperaionMode:2; ++ USHORT NonGfPresent:1; ++ USHORT rsv:1; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv2:11; ++#endif ++} ADD_HTINFO2, *PADD_HTINFO2; ++ ++ ++// TODO: Need sync with spec about the definition of StbcMcs. In Draft 3.03, it's reserved. ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv:4; ++ USHORT PcoPhase:1; ++ USHORT PcoActive:1; ++ USHORT LsigTxopProt:1; ++ USHORT STBCBeacon:1; ++ USHORT DualCTSProtect:1; ++ USHORT DualBeacon:1; ++ USHORT StbcMcs:6; ++#else ++ USHORT StbcMcs:6; ++ USHORT DualBeacon:1; ++ USHORT DualCTSProtect:1; ++ USHORT STBCBeacon:1; ++ USHORT LsigTxopProt:1; // L-SIG TXOP protection full support ++ USHORT PcoActive:1; ++ USHORT PcoPhase:1; ++ USHORT rsv:4; ++#endif // RT_BIG_ENDIAN // ++} ADD_HTINFO3, *PADD_HTINFO3; ++ ++#define SIZE_ADD_HT_INFO_IE 22 ++typedef struct PACKED{ ++ UCHAR ControlChan; ++ ADD_HTINFO AddHtInfo; ++ ADD_HTINFO2 AddHtInfo2; ++ ADD_HTINFO3 AddHtInfo3; ++ UCHAR MCSSet[16]; // Basic MCS set ++} ADD_HT_INFO_IE, *PADD_HT_INFO_IE; ++ ++typedef struct PACKED{ ++ UCHAR NewExtChanOffset; ++} NEW_EXT_CHAN_IE, *PNEW_EXT_CHAN_IE; ++ ++ ++// 4-byte HTC field. maybe included in any frame except non-QOS data frame. The Order bit must set 1. ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UINT32 RDG:1; //RDG / More PPDU ++ UINT32 ACConstraint:1; //feedback request ++ UINT32 rsv:5; //calibration sequence ++ UINT32 ZLFAnnouce:1; // ZLF announcement ++ UINT32 CSISTEERING:2; //CSI/ STEERING ++ UINT32 FBKReq:2; //feedback request ++ UINT32 CalSeq:2; //calibration sequence ++ UINT32 CalPos:2; // calibration position ++ UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available ++ UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. ++ UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. ++ UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback ++ UINT32 TRQ:1; //sounding request ++ UINT32 MA:1; //management action payload exist in (QoS Null+HTC) ++#else ++ UINT32 MA:1; //management action payload exist in (QoS Null+HTC) ++ UINT32 TRQ:1; //sounding request ++ UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback ++ UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. ++ UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. ++ UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available ++ UINT32 CalPos:2; // calibration position ++ UINT32 CalSeq:2; //calibration sequence ++ UINT32 FBKReq:2; //feedback request ++ UINT32 CSISTEERING:2; //CSI/ STEERING ++ UINT32 ZLFAnnouce:1; // ZLF announcement ++ UINT32 rsv:5; //calibration sequence ++ UINT32 ACConstraint:1; //feedback request ++ UINT32 RDG:1; //RDG / More PPDU ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CONTROL, *PHT_CONTROL; ++ ++// 2-byte QOS CONTROL field ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Txop_QueueSize:8; ++ USHORT AMsduPresent:1; ++ USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA ++ USHORT EOSP:1; ++ USHORT TID:4; ++#else ++ USHORT TID:4; ++ USHORT EOSP:1; ++ USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA ++ USHORT AMsduPresent:1; ++ USHORT Txop_QueueSize:8; ++#endif /* !RT_BIG_ENDIAN */ ++} QOS_CONTROL, *PQOS_CONTROL; ++ ++// 2-byte Frame control field ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Order:1; // Strict order expected ++ USHORT Wep:1; // Wep data ++ USHORT MoreData:1; // More data bit ++ USHORT PwrMgmt:1; // Power management bit ++ USHORT Retry:1; // Retry status bit ++ USHORT MoreFrag:1; // More fragment bit ++ USHORT FrDs:1; // From DS indication ++ USHORT ToDs:1; // To DS indication ++ USHORT SubType:4; // MSDU subtype ++ USHORT Type:2; // MSDU type ++ USHORT Ver:2; // Protocol version ++#else ++ USHORT Ver:2; // Protocol version ++ USHORT Type:2; // MSDU type ++ USHORT SubType:4; // MSDU subtype ++ USHORT ToDs:1; // To DS indication ++ USHORT FrDs:1; // From DS indication ++ USHORT MoreFrag:1; // More fragment bit ++ USHORT Retry:1; // Retry status bit ++ USHORT PwrMgmt:1; // Power management bit ++ USHORT MoreData:1; // More data bit ++ USHORT Wep:1; // Wep data ++ USHORT Order:1; // Strict order expected ++#endif /* !RT_BIG_ENDIAN */ ++} FRAME_CONTROL, *PFRAME_CONTROL; ++ ++typedef struct PACKED _HEADER_802_11 { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR Addr3[MAC_ADDR_LEN]; ++#ifdef RT_BIG_ENDIAN ++ USHORT Sequence:12; ++ USHORT Frag:4; ++#else ++ USHORT Frag:4; ++ USHORT Sequence:12; ++#endif /* !RT_BIG_ENDIAN */ ++ UCHAR Octet[0]; ++} HEADER_802_11, *PHEADER_802_11; ++ ++typedef struct PACKED _FRAME_802_11 { ++ HEADER_802_11 Hdr; ++ UCHAR Octet[1]; ++} FRAME_802_11, *PFRAME_802_11; ++ ++// QoSNull embedding of management action. When HT Control MA field set to 1. ++typedef struct PACKED _MA_BODY { ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Octet[1]; ++} MA_BODY, *PMA_BODY; ++ ++typedef struct PACKED _HEADER_802_3 { ++ UCHAR DAAddr1[MAC_ADDR_LEN]; ++ UCHAR SAAddr2[MAC_ADDR_LEN]; ++ UCHAR Octet[2]; ++} HEADER_802_3, *PHEADER_802_3; ++////Block ACK related format ++// 2-byte BA Parameter field in DELBA frames to terminate an already set up bA ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; // value of TC os TS ++ USHORT Initiator:1; // 1: originator 0:recipient ++ USHORT Rsv:11; // always set to 0 ++#else ++ USHORT Rsv:11; // always set to 0 ++ USHORT Initiator:1; // 1: originator 0:recipient ++ USHORT TID:4; // value of TC os TS ++#endif /* !RT_BIG_ENDIAN */ ++} DELBA_PARM, *PDELBA_PARM; ++ ++// 2-byte BA Parameter Set field in ADDBA frames to signal parm for setting up a BA ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT BufSize:10; // number of buffe of size 2304 octetsr ++ USHORT TID:4; // value of TC os TS ++ USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA ++ USHORT AMSDUSupported:1; // 0: not permitted 1: permitted ++#else ++ USHORT AMSDUSupported:1; // 0: not permitted 1: permitted ++ USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA ++ USHORT TID:4; // value of TC os TS ++ USHORT BufSize:10; // number of buffe of size 2304 octetsr ++#endif /* !RT_BIG_ENDIAN */ ++} BA_PARM, *PBA_PARM; ++ ++// 2-byte BA Starting Seq CONTROL field ++typedef union PACKED { ++ struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent ++ USHORT FragNum:4; // always set to 0 ++#else ++ USHORT FragNum:4; // always set to 0 ++ USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent ++#endif /* RT_BIG_ENDIAN */ ++ } field; ++ USHORT word; ++} BASEQ_CONTROL, *PBASEQ_CONTROL; ++ ++//BAControl and BARControl are the same ++// 2-byte BA CONTROL field in BA frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; //EWC V1.24 ++ USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK ++#else ++ USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK ++ USHORT MTID:1; //EWC V1.24 ++ USHORT Compressed:1; ++ USHORT Rsv:9; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} BA_CONTROL, *PBA_CONTROL; ++ ++// 2-byte BAR CONTROL field in BAR frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv1:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ ++ USHORT ACKPolicy:1; ++#else ++ USHORT ACKPolicy:1; // 0:normal ack, 1:no ack. ++ USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ ++ USHORT Compressed:1; ++ USHORT Rsv1:9; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} BAR_CONTROL, *PBAR_CONTROL; ++ ++// BARControl in MTBAR frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT NumTID:4; ++ USHORT Rsv1:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; ++ USHORT ACKPolicy:1; ++#else ++ USHORT ACKPolicy:1; ++ USHORT MTID:1; ++ USHORT Compressed:1; ++ USHORT Rsv1:9; ++ USHORT NumTID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} MTBAR_CONTROL, *PMTBAR_CONTROL; ++ ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv1:12; ++#else ++ USHORT Rsv1:12; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} PER_TID_INFO, *PPER_TID_INFO; ++ ++typedef struct { ++ PER_TID_INFO PerTID; ++ BASEQ_CONTROL BAStartingSeq; ++} EACH_TID, *PEACH_TID; ++ ++ ++typedef struct PACKED _PSPOLL_FRAME { ++ FRAME_CONTROL FC; ++ USHORT Aid; ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR Ta[MAC_ADDR_LEN]; ++} PSPOLL_FRAME, *PPSPOLL_FRAME; ++ ++typedef struct PACKED _RTS_FRAME { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++}RTS_FRAME, *PRTS_FRAME; ++ ++// BAREQ AND MTBAREQ have the same subtype BAR, 802.11n BAR use compressed bitmap. ++typedef struct PACKED _FRAME_BA_REQ { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BARControl; ++ BASEQ_CONTROL BAStartingSeq; ++} FRAME_BA_REQ, *PFRAME_BA_REQ; ++ ++typedef struct PACKED _FRAME_MTBA_REQ { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ MTBAR_CONTROL MTBARControl; ++ PER_TID_INFO PerTIDInfo; ++ BASEQ_CONTROL BAStartingSeq; ++} FRAME_MTBA_REQ, *PFRAME_MTBA_REQ; ++ ++// Compressed format is mandantory in HT STA ++typedef struct PACKED _FRAME_MTBA { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BA_CONTROL BAControl; ++ BASEQ_CONTROL BAStartingSeq; ++ UCHAR BitMap[8]; ++} FRAME_MTBA, *PFRAME_MTBA; ++ ++typedef struct PACKED _FRAME_PSMP_ACTION { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Psmp; // 7.3.1.25 ++} FRAME_PSMP_ACTION, *PFRAME_PSMP_ACTION; ++ ++typedef struct PACKED _FRAME_ACTION_HDR { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++} FRAME_ACTION_HDR, *PFRAME_ACTION_HDR; ++ ++//Action Frame ++//Action Frame Category:Spectrum, Action:Channel Switch. 7.3.2.20 ++typedef struct PACKED _CHAN_SWITCH_ANNOUNCE { ++ UCHAR ElementID; // ID = IE_CHANNEL_SWITCH_ANNOUNCEMENT = 37 ++ UCHAR Len; ++ CHA_SWITCH_ANNOUNCE_IE CSAnnounceIe; ++} CHAN_SWITCH_ANNOUNCE, *PCHAN_SWITCH_ANNOUNCE; ++ ++ ++//802.11n : 7.3.2.20a ++typedef struct PACKED _SECOND_CHAN_OFFSET { ++ UCHAR ElementID; // ID = IE_SECONDARY_CH_OFFSET = 62 ++ UCHAR Len; ++ SEC_CHA_OFFSET_IE SecChOffsetIe; ++} SECOND_CHAN_OFFSET, *PSECOND_CHAN_OFFSET; ++ ++ ++typedef struct PACKED _FRAME_SPETRUM_CS { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ CHAN_SWITCH_ANNOUNCE CSAnnounce; ++ SECOND_CHAN_OFFSET SecondChannel; ++} FRAME_SPETRUM_CS, *PFRAME_SPETRUM_CS; ++ ++ ++typedef struct PACKED _FRAME_ADDBA_REQ { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; // 1 ++ BA_PARM BaParm; // 2 - 10 ++ USHORT TimeOutValue; // 0 - 0 ++ BASEQ_CONTROL BaStartSeq; // 0-0 ++} FRAME_ADDBA_REQ, *PFRAME_ADDBA_REQ; ++ ++typedef struct PACKED _FRAME_ADDBA_RSP { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; ++ USHORT StatusCode; ++ BA_PARM BaParm; //0 - 2 ++ USHORT TimeOutValue; ++} FRAME_ADDBA_RSP, *PFRAME_ADDBA_RSP; ++ ++typedef struct PACKED _FRAME_DELBA_REQ { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ DELBA_PARM DelbaParm; ++ USHORT ReasonCode; ++} FRAME_DELBA_REQ, *PFRAME_DELBA_REQ; ++ ++ ++//7.2.1.7 ++typedef struct PACKED _FRAME_BAR { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BarControl; ++ BASEQ_CONTROL StartingSeq; ++} FRAME_BAR, *PFRAME_BAR; ++ ++//7.2.1.7 ++typedef struct PACKED _FRAME_BA { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BarControl; ++ BASEQ_CONTROL StartingSeq; ++ UCHAR bitmask[8]; ++} FRAME_BA, *PFRAME_BA; ++ ++ ++// Radio Measuement Request Frame Format ++typedef struct PACKED _FRAME_RM_REQ_ACTION { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; ++ USHORT Repetition; ++ UCHAR data[0]; ++} FRAME_RM_REQ_ACTION, *PFRAME_RM_REQ_ACTION; ++ ++typedef struct PACKED { ++ UCHAR ID; ++ UCHAR Length; ++ UCHAR ChannelSwitchMode; ++ UCHAR NewRegClass; ++ UCHAR NewChannelNum; ++ UCHAR ChannelSwitchCount; ++} HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE, *PHT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE; ++ ++ ++// ++// _Limit must be the 2**n - 1 ++// _SEQ1 , _SEQ2 must be within 0 ~ _Limit ++// ++#define SEQ_STEPONE(_SEQ1, _SEQ2, _Limit) ((_SEQ1 == ((_SEQ2+1) & _Limit))) ++#define SEQ_SMALLER(_SEQ1, _SEQ2, _Limit) (((_SEQ1-_SEQ2) & ((_Limit+1)>>1))) ++#define SEQ_LARGER(_SEQ1, _SEQ2, _Limit) ((_SEQ1 != _SEQ2) && !(((_SEQ1-_SEQ2) & ((_Limit+1)>>1)))) ++#define SEQ_WITHIN_WIN(_SEQ1, _SEQ2, _WIN, _Limit) (SEQ_LARGER(_SEQ1, _SEQ2, _Limit) && \ ++ SEQ_SMALLER(_SEQ1, ((_SEQ2+_WIN+1)&_Limit), _Limit)) ++ ++// ++// Contention-free parameter (without ID and Length) ++// ++typedef struct PACKED { ++ BOOLEAN bValid; // 1: variable contains valid value ++ UCHAR CfpCount; ++ UCHAR CfpPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpDurRemaining; ++} CF_PARM, *PCF_PARM; ++ ++typedef struct _CIPHER_SUITE { ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher 1, this one has more secured cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipherAux; // Unicast cipher 2 if AP announce two unicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Group cipher ++ USHORT RsnCapability; // RSN capability from beacon ++ BOOLEAN bMixMode; // Indicate Pair & Group cipher might be different ++} CIPHER_SUITE, *PCIPHER_SUITE; ++ ++// EDCA configuration from AP's BEACON/ProbeRsp ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ BOOLEAN bAdd; // 1: variable contains valid value ++ BOOLEAN bQAck; ++ BOOLEAN bQueueRequest; ++ BOOLEAN bTxopRequest; ++ BOOLEAN bAPSDCapable; ++// BOOLEAN bMoreDataAck; ++ UCHAR EdcaUpdateCount; ++ UCHAR Aifsn[4]; // 0:AC_BK, 1:AC_BE, 2:AC_VI, 3:AC_VO ++ UCHAR Cwmin[4]; ++ UCHAR Cwmax[4]; ++ USHORT Txop[4]; // in unit of 32-us ++ BOOLEAN bACM[4]; // 1: Admission Control of AC_BK is mandattory ++} EDCA_PARM, *PEDCA_PARM; ++ ++// QBSS LOAD information from QAP's BEACON/ProbeRsp ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ USHORT StaNum; ++ UCHAR ChannelUtilization; ++ USHORT RemainingAdmissionControl; // in unit of 32-us ++} QBSS_LOAD_PARM, *PQBSS_LOAD_PARM; ++ ++// QBSS Info field in QSTA's assoc req ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR Rsv2:1; ++ UCHAR MaxSPLength:2; ++ UCHAR Rsv1:1; ++ UCHAR UAPSD_AC_BE:1; ++ UCHAR UAPSD_AC_BK:1; ++ UCHAR UAPSD_AC_VI:1; ++ UCHAR UAPSD_AC_VO:1; ++#else ++ UCHAR UAPSD_AC_VO:1; ++ UCHAR UAPSD_AC_VI:1; ++ UCHAR UAPSD_AC_BK:1; ++ UCHAR UAPSD_AC_BE:1; ++ UCHAR Rsv1:1; ++ UCHAR MaxSPLength:2; ++ UCHAR Rsv2:1; ++#endif /* !RT_BIG_ENDIAN */ ++} QBSS_STA_INFO_PARM, *PQBSS_STA_INFO_PARM; ++ ++// QBSS Info field in QAP's Beacon/ProbeRsp ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR UAPSD:1; ++ UCHAR Rsv:3; ++ UCHAR ParamSetCount:4; ++#else ++ UCHAR ParamSetCount:4; ++ UCHAR Rsv:3; ++ UCHAR UAPSD:1; ++#endif /* !RT_BIG_ENDIAN */ ++} QBSS_AP_INFO_PARM, *PQBSS_AP_INFO_PARM; ++ ++// QOS Capability reported in QAP's BEACON/ProbeRsp ++// QOS Capability sent out in QSTA's AssociateReq/ReAssociateReq ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ BOOLEAN bQAck; ++ BOOLEAN bQueueRequest; ++ BOOLEAN bTxopRequest; ++// BOOLEAN bMoreDataAck; ++ UCHAR EdcaUpdateCount; ++} QOS_CAPABILITY_PARM, *PQOS_CAPABILITY_PARM; ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef struct { ++ UCHAR IELen; ++ UCHAR IE[MAX_CUSTOM_LEN]; ++} WPA_IE_; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++typedef struct { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR Channel; ++ UCHAR CentralChannel; //Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. ++ UCHAR BssType; ++ USHORT AtimWin; ++ USHORT BeaconPeriod; ++ ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen; ++ HT_CAPABILITY_IE HtCapability; ++ UCHAR HtCapabilityLen; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChanOffset; ++ CHAR Rssi; ++ UCHAR Privacy; // Indicate security function ON/OFF. Don't mess up with auth mode. ++ UCHAR Hidden; ++ ++ USHORT DtimPeriod; ++ USHORT CapabilityInfo; ++ ++ USHORT CfpCount; ++ USHORT CfpPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpDurRemaining; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ ++ ULONG LastBeaconRxTime; // OS's timestamp ++ ++ BOOLEAN bSES; ++ ++ // New for WPA2 ++ CIPHER_SUITE WPA; // AP announced WPA cipher suite ++ CIPHER_SUITE WPA2; // AP announced WPA2 cipher suite ++ ++ // New for microsoft WPA support ++ NDIS_802_11_FIXED_IEs FixIEs; ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeAux; // Addition mode for WPA2 / WPA capable AP ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; // Unicast Encryption Algorithm extract from VAR_IE ++ USHORT VarIELen; // Length of next VIE include EID & Length ++ UCHAR VarIEs[MAX_VIE_LEN]; ++ ++ // CCX Ckip information ++ UCHAR CkipFlag; ++ ++ // CCX 2 TSF ++ UCHAR PTSF[4]; // Parent TSF ++ UCHAR TTSF[8]; // Target TSF ++ ++ // 802.11e d9, and WMM ++ EDCA_PARM EdcaParm; ++ QOS_CAPABILITY_PARM QosCapability; ++ QBSS_LOAD_PARM QbssLoad; ++#ifdef CONFIG_STA_SUPPORT ++ WPA_IE_ WpaIE; ++ WPA_IE_ RsnIE; ++#ifdef EXT_BUILD_CHANNEL_LIST ++ UCHAR CountryString[3]; ++ BOOLEAN bHasCountryIE; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++} BSS_ENTRY, *PBSS_ENTRY; ++ ++typedef struct { ++ UCHAR BssNr; ++ UCHAR BssOverlapNr; ++ BSS_ENTRY BssEntry[MAX_LEN_OF_BSS_TABLE]; ++} BSS_TABLE, *PBSS_TABLE; ++ ++ ++typedef struct _MLME_QUEUE_ELEM { ++ ULONG Machine; ++ ULONG MsgType; ++ ULONG MsgLen; ++ UCHAR Msg[MGMT_DMA_BUFFER_SIZE]; ++ LARGE_INTEGER TimeStamp; ++ UCHAR Rssi0; ++ UCHAR Rssi1; ++ UCHAR Rssi2; ++ UCHAR Signal; ++ UCHAR Channel; ++ UCHAR Wcid; ++ BOOLEAN Occupied; ++} MLME_QUEUE_ELEM, *PMLME_QUEUE_ELEM; ++ ++typedef struct _MLME_QUEUE { ++ ULONG Num; ++ ULONG Head; ++ ULONG Tail; ++ NDIS_SPIN_LOCK Lock; ++ MLME_QUEUE_ELEM Entry[MAX_LEN_OF_MLME_QUEUE]; ++} MLME_QUEUE, *PMLME_QUEUE; ++ ++typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem); ++ ++typedef struct _STATE_MACHINE { ++ ULONG Base; ++ ULONG NrState; ++ ULONG NrMsg; ++ ULONG CurrState; ++ STATE_MACHINE_FUNC *TransFunc; ++} STATE_MACHINE, *PSTATE_MACHINE; ++ ++ ++// MLME AUX data structure that hold temporarliy settings during a connection attempt. ++// Once this attemp succeeds, all settings will be copy to pAd->StaActive. ++// A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of ++// several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely ++// separate this under-trial settings away from pAd->StaActive so that once ++// this new attempt failed, driver can auto-recover back to the active settings. ++typedef struct _MLME_AUX { ++ UCHAR BssType; ++ UCHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR AutoReconnectSsid[MAX_LEN_OF_SSID]; ++ UCHAR AutoReconnectSsidLen; ++ USHORT Alg; ++ UCHAR ScanType; ++ UCHAR Channel; ++ UCHAR CentralChannel; ++ USHORT Aid; ++ USHORT CapabilityInfo; ++ USHORT BeaconPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpPeriod; ++ USHORT AtimWin; ++ ++ // Copy supported rate from desired AP's beacon. We are trying to match ++ // AP's supported and extended rate settings. ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRateLen; ++ HT_CAPABILITY_IE HtCapability; ++ UCHAR HtCapabilityLen; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR NewExtChannelOffset; ++ //RT_HT_CAPABILITY SupportedHtPhy; ++ ++ // new for QOS ++ QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP ++ EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP ++ QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP ++ ++ // new to keep Ralink specific feature ++ ULONG APRalinkIe; ++ ++ BSS_TABLE SsidBssTab; // AP list for the same SSID ++ BSS_TABLE RoamTab; // AP list eligible for roaming ++ ULONG BssIdx; ++ ULONG RoamIdx; ++ ++ BOOLEAN CurrReqIsFromNdis; ++ ++ RALINK_TIMER_STRUCT BeaconTimer, ScanTimer; ++ RALINK_TIMER_STRUCT AuthTimer; ++ RALINK_TIMER_STRUCT AssocTimer, ReassocTimer, DisassocTimer; ++} MLME_AUX, *PMLME_AUX; ++ ++typedef struct _MLME_ADDBA_REQ_STRUCT{ ++ UCHAR Wcid; // ++ UCHAR pAddr[MAC_ADDR_LEN]; ++ UCHAR BaBufSize; ++ USHORT TimeOutValue; ++ UCHAR TID; ++ UCHAR Token; ++ USHORT BaStartSeq; ++} MLME_ADDBA_REQ_STRUCT, *PMLME_ADDBA_REQ_STRUCT; ++ ++ ++typedef struct _MLME_DELBA_REQ_STRUCT{ ++ UCHAR Wcid; // ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR TID; ++ UCHAR Initiator; ++} MLME_DELBA_REQ_STRUCT, *PMLME_DELBA_REQ_STRUCT; ++ ++// assoc struct is equal to reassoc ++typedef struct _MLME_ASSOC_REQ_STRUCT{ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT CapabilityInfo; ++ USHORT ListenIntv; ++ ULONG Timeout; ++} MLME_ASSOC_REQ_STRUCT, *PMLME_ASSOC_REQ_STRUCT, MLME_REASSOC_REQ_STRUCT, *PMLME_REASSOC_REQ_STRUCT; ++ ++typedef struct _MLME_DISASSOC_REQ_STRUCT{ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Reason; ++} MLME_DISASSOC_REQ_STRUCT, *PMLME_DISASSOC_REQ_STRUCT; ++ ++typedef struct _MLME_AUTH_REQ_STRUCT { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Alg; ++ ULONG Timeout; ++} MLME_AUTH_REQ_STRUCT, *PMLME_AUTH_REQ_STRUCT; ++ ++typedef struct _MLME_DEAUTH_REQ_STRUCT { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Reason; ++} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; ++ ++typedef struct { ++ ULONG BssIdx; ++} MLME_JOIN_REQ_STRUCT; ++ ++typedef struct _MLME_SCAN_REQ_STRUCT { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR BssType; ++ UCHAR ScanType; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++} MLME_SCAN_REQ_STRUCT, *PMLME_SCAN_REQ_STRUCT; ++ ++typedef struct _MLME_START_REQ_STRUCT { ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++} MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++// structure for DLS ++typedef struct _RT_802_11_DLS { ++ USHORT TimeOut; // Use to time out while slience, unit: second , set by UI ++ USHORT CountDownTimer; // Use to time out while slience,unit: second , used by driver only ++ NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI ++ UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only ++ BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link ++ RALINK_TIMER_STRUCT Timer; // Use to time out while handshake ++ USHORT Sequence; ++ USHORT MacTabMatchWCID; // ASIC ++ BOOLEAN bHTCap; ++ PVOID pAd; ++} RT_802_11_DLS, *PRT_802_11_DLS; ++ ++typedef struct _MLME_DLS_REQ_STRUCT { ++ PRT_802_11_DLS pDLS; ++ USHORT Reason; ++} MLME_DLS_REQ_STRUCT, *PMLME_DLS_REQ_STRUCT; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct PACKED { ++ UCHAR Eid; ++ UCHAR Len; ++ CHAR Octet[1]; ++} EID_STRUCT,*PEID_STRUCT, BEACON_EID_STRUCT, *PBEACON_EID_STRUCT; ++ ++typedef struct PACKED _RTMP_TX_RATE_SWITCH ++{ ++ UCHAR ItemNo; ++#ifdef RT_BIG_ENDIAN ++ UCHAR Rsv2:2; ++ UCHAR Mode:2; ++ UCHAR Rsv1:1; ++ UCHAR BW:1; ++ UCHAR ShortGI:1; ++ UCHAR STBC:1; ++#else ++ UCHAR STBC:1; ++ UCHAR ShortGI:1; ++ UCHAR BW:1; ++ UCHAR Rsv1:1; ++ UCHAR Mode:2; ++ UCHAR Rsv2:2; ++#endif ++ UCHAR CurrMCS; ++ UCHAR TrainUp; ++ UCHAR TrainDown; ++} RRTMP_TX_RATE_SWITCH, *PRTMP_TX_RATE_SWITCH; ++ ++// ========================== AP mlme.h =============================== ++#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps ++#define DEFAULT_DTIM_PERIOD 1 ++ ++// weighting factor to calculate Channel quality, total should be 100% ++//#define RSSI_WEIGHTING 0 ++//#define TX_WEIGHTING 40 ++//#define RX_WEIGHTING 60 ++ ++#define MAC_TABLE_AGEOUT_TIME 300 // unit: sec ++#define MAC_TABLE_ASSOC_TIMEOUT 5 // unit: sec ++#define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE) ++ ++// AP shall drop the sta if contine Tx fail count reach it. ++#define MAC_ENTRY_LIFE_CHECK_CNT 20 // packet cnt. ++ ++// Value domain of pMacEntry->Sst ++typedef enum _Sst { ++ SST_NOT_AUTH, // 0: equivalent to IEEE 802.11/1999 state 1 ++ SST_AUTH, // 1: equivalent to IEEE 802.11/1999 state 2 ++ SST_ASSOC // 2: equivalent to IEEE 802.11/1999 state 3 ++} SST; ++ ++// value domain of pMacEntry->AuthState ++typedef enum _AuthState { ++ AS_NOT_AUTH, ++ AS_AUTH_OPEN, // STA has been authenticated using OPEN SYSTEM ++ AS_AUTH_KEY, // STA has been authenticated using SHARED KEY ++ AS_AUTHENTICATING // STA is waiting for AUTH seq#3 using SHARED KEY ++} AUTH_STATE; ++ ++//for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _ApWpaState { ++ AS_NOTUSE, // 0 ++ AS_DISCONNECT, // 1 ++ AS_DISCONNECTED, // 2 ++ AS_INITIALIZE, // 3 ++ AS_AUTHENTICATION, // 4 ++ AS_AUTHENTICATION2, // 5 ++ AS_INITPMK, // 6 ++ AS_INITPSK, // 7 ++ AS_PTKSTART, // 8 ++ AS_PTKINIT_NEGOTIATING, // 9 ++ AS_PTKINITDONE, // 10 ++ AS_UPDATEKEYS, // 11 ++ AS_INTEGRITY_FAILURE, // 12 ++ AS_KEYUPDATE, // 13 ++} AP_WPA_STATE; ++ ++// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _GTKState { ++ REKEY_NEGOTIATING, ++ REKEY_ESTABLISHED, ++ KEYERROR, ++} GTK_STATE; ++ ++// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _WpaGTKState { ++ SETKEYS, ++ SETKEYS_DONE, ++} WPA_GTK_STATE; ++// ====================== end of AP mlme.h ============================ ++ ++ ++#endif // MLME_H__ +--- /dev/null ++++ b/drivers/staging/rt2870/netif_block.h +@@ -0,0 +1,58 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __NET_IF_BLOCK_H__ ++#define __NET_IF_BLOCK_H__ ++ ++//#include ++#include "link_list.h" ++#include "rtmp.h" ++ ++#define FREE_NETIF_POOL_SIZE 32 ++ ++typedef struct _NETIF_ENTRY ++{ ++ struct _NETIF_ENTRY *pNext; ++ PNET_DEV pNetDev; ++} NETIF_ENTRY, *PNETIF_ENTRY; ++ ++void initblockQueueTab( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN blockNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, ++ IN PNET_DEV pNetDev); ++ ++VOID releaseNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry); ++ ++VOID StopNetIfQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++#endif // __NET_IF_BLOCK_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/oid.h +@@ -0,0 +1,1091 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ oid.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef _OID_H_ ++#define _OID_H_ ++ ++#define TRUE 1 ++#define FALSE 0 ++// ++// IEEE 802.11 Structures and definitions ++// ++#define MAX_TX_POWER_LEVEL 100 /* mW */ ++#define MAX_RSSI_TRIGGER -10 /* dBm */ ++#define MIN_RSSI_TRIGGER -200 /* dBm */ ++#define MAX_FRAG_THRESHOLD 2346 /* byte count */ ++#define MIN_FRAG_THRESHOLD 256 /* byte count */ ++#define MAX_RTS_THRESHOLD 2347 /* byte count */ ++ ++// new types for Media Specific Indications ++// Extension channel offset ++#define EXTCHA_NONE 0 ++#define EXTCHA_ABOVE 0x1 ++#define EXTCHA_BELOW 0x3 ++ ++// BW ++#define BAND_WIDTH_20 0 ++#define BAND_WIDTH_40 1 ++#define BAND_WIDTH_BOTH 2 ++#define BAND_WIDTH_10 3 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. ++// SHORTGI ++#define GAP_INTERVAL_400 1 // only support in HT mode ++#define GAP_INTERVAL_800 0 ++#define GAP_INTERVAL_BOTH 2 ++ ++#define NdisMediaStateConnected 1 ++#define NdisMediaStateDisconnected 0 ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++#define MAC_ADDR_LENGTH 6 ++#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc ++#define MAX_NUMBER_OF_EVENT 10 // entry # in EVENT table ++#define MAX_NUMBER_OF_MAC 32 // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 ++#define MAX_NUMBER_OF_ACL 64 ++#define MAX_LENGTH_OF_SUPPORT_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define MAX_NUMBER_OF_DLS_ENTRY 4 ++ ++#ifndef UNDER_CE ++// OID definition, since NDIS 5.0 didn't define these, we need to define for our own ++//#if _WIN32_WINNT<=0x0500 ++ ++#define OID_GEN_MACHINE_NAME 0x0001021A ++ ++#ifdef RALINK_ATE ++#define RT_QUERY_ATE_TXDONE_COUNT 0x0401 ++#endif // RALINK_ATE // ++#define RT_QUERY_SIGNAL_CONTEXT 0x0402 ++#define RT_SET_IAPP_PID 0x0404 ++#define RT_SET_APD_PID 0x0405 ++#define RT_SET_DEL_MAC_ENTRY 0x0406 ++ ++// ++// IEEE 802.11 OIDs ++// ++#define OID_GET_SET_TOGGLE 0x8000 ++ ++#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0103 ++#define OID_802_11_NETWORK_TYPE_IN_USE 0x0104 ++#define OID_802_11_RSSI_TRIGGER 0x0107 ++#define RT_OID_802_11_RSSI 0x0108 //rt2860 only , kathy ++#define RT_OID_802_11_RSSI_1 0x0109 //rt2860 only , kathy ++#define RT_OID_802_11_RSSI_2 0x010A //rt2860 only , kathy ++#define OID_802_11_NUMBER_OF_ANTENNAS 0x010B ++#define OID_802_11_RX_ANTENNA_SELECTED 0x010C ++#define OID_802_11_TX_ANTENNA_SELECTED 0x010D ++#define OID_802_11_SUPPORTED_RATES 0x010E ++#define OID_802_11_ADD_WEP 0x0112 ++#define OID_802_11_REMOVE_WEP 0x0113 ++#define OID_802_11_DISASSOCIATE 0x0114 ++#define OID_802_11_PRIVACY_FILTER 0x0118 ++#define OID_802_11_ASSOCIATION_INFORMATION 0x011E ++#define OID_802_11_TEST 0x011F ++#define RT_OID_802_11_COUNTRY_REGION 0x0507 ++#define OID_802_11_BSSID_LIST_SCAN 0x0508 ++#define OID_802_11_SSID 0x0509 ++#define OID_802_11_BSSID 0x050A ++#define RT_OID_802_11_RADIO 0x050B ++#define RT_OID_802_11_PHY_MODE 0x050C ++#define RT_OID_802_11_STA_CONFIG 0x050D ++#define OID_802_11_DESIRED_RATES 0x050E ++#define RT_OID_802_11_PREAMBLE 0x050F ++#define OID_802_11_WEP_STATUS 0x0510 ++#define OID_802_11_AUTHENTICATION_MODE 0x0511 ++#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 ++#define RT_OID_802_11_RESET_COUNTERS 0x0513 ++#define OID_802_11_RTS_THRESHOLD 0x0514 ++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0515 ++#define OID_802_11_POWER_MODE 0x0516 ++#define OID_802_11_TX_POWER_LEVEL 0x0517 ++#define RT_OID_802_11_ADD_WPA 0x0518 ++#define OID_802_11_REMOVE_KEY 0x0519 ++#define OID_802_11_ADD_KEY 0x0520 ++#define OID_802_11_CONFIGURATION 0x0521 ++#define OID_802_11_TX_PACKET_BURST 0x0522 ++#define RT_OID_802_11_QUERY_NOISE_LEVEL 0x0523 ++#define RT_OID_802_11_EXTRA_INFO 0x0524 ++#ifdef DBG ++#define RT_OID_802_11_HARDWARE_REGISTER 0x0525 ++#endif ++#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS ++#define OID_802_11_DEAUTHENTICATION 0x0526 ++#define OID_802_11_DROP_UNENCRYPTED 0x0527 ++#define OID_802_11_MIC_FAILURE_REPORT_FRAME 0x0528 ++ ++// For 802.1x daemin using to require current driver configuration ++#define OID_802_11_RADIUS_QUERY_SETTING 0x0540 ++ ++#define RT_OID_DEVICE_NAME 0x0607 ++#define RT_OID_VERSION_INFO 0x0608 ++#define OID_802_11_BSSID_LIST 0x0609 ++#define OID_802_3_CURRENT_ADDRESS 0x060A ++#define OID_GEN_MEDIA_CONNECT_STATUS 0x060B ++#define RT_OID_802_11_QUERY_LINK_STATUS 0x060C ++#define OID_802_11_RSSI 0x060D ++#define OID_802_11_STATISTICS 0x060E ++#define OID_GEN_RCV_OK 0x060F ++#define OID_GEN_RCV_NO_BUFFER 0x0610 ++#define RT_OID_802_11_QUERY_EEPROM_VERSION 0x0611 ++#define RT_OID_802_11_QUERY_FIRMWARE_VERSION 0x0612 ++#define RT_OID_802_11_QUERY_LAST_RX_RATE 0x0613 ++#define RT_OID_802_11_TX_POWER_LEVEL_1 0x0614 ++#define RT_OID_802_11_QUERY_PIDVID 0x0615 ++//for WPA_SUPPLICANT_SUPPORT ++#define OID_SET_COUNTERMEASURES 0x0616 ++#define OID_802_11_SET_IEEE8021X 0x0617 ++#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 ++#define OID_802_11_PMKID 0x0620 ++#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 ++#define RT_OID_WE_VERSION_COMPILED 0x0622 ++#define RT_OID_NEW_DRIVER 0x0623 ++ ++ ++//rt2860 , kathy ++#define RT_OID_802_11_SNR_0 0x0630 ++#define RT_OID_802_11_SNR_1 0x0631 ++#define RT_OID_802_11_QUERY_LAST_TX_RATE 0x0632 ++#define RT_OID_802_11_QUERY_HT_PHYMODE 0x0633 ++#define RT_OID_802_11_SET_HT_PHYMODE 0x0634 ++#define OID_802_11_RELOAD_DEFAULTS 0x0635 ++#define RT_OID_802_11_QUERY_APSD_SETTING 0x0636 ++#define RT_OID_802_11_SET_APSD_SETTING 0x0637 ++#define RT_OID_802_11_QUERY_APSD_PSM 0x0638 ++#define RT_OID_802_11_SET_APSD_PSM 0x0639 ++#define RT_OID_802_11_QUERY_DLS 0x063A ++#define RT_OID_802_11_SET_DLS 0x063B ++#define RT_OID_802_11_QUERY_DLS_PARAM 0x063C ++#define RT_OID_802_11_SET_DLS_PARAM 0x063D ++#define RT_OID_802_11_QUERY_WMM 0x063E ++#define RT_OID_802_11_SET_WMM 0x063F ++#define RT_OID_802_11_QUERY_IMME_BA_CAP 0x0640 ++#define RT_OID_802_11_SET_IMME_BA_CAP 0x0641 ++#define RT_OID_802_11_QUERY_BATABLE 0x0642 ++#define RT_OID_802_11_ADD_IMME_BA 0x0643 ++#define RT_OID_802_11_TEAR_IMME_BA 0x0644 ++#define RT_OID_DRIVER_DEVICE_NAME 0x0645 ++#define RT_OID_802_11_QUERY_DAT_HT_PHYMODE 0x0646 ++#define RT_OID_QUERY_MULTIPLE_CARD_SUPPORT 0x0647 ++ ++// Ralink defined OIDs ++// Dennis Lee move to platform specific ++ ++#define RT_OID_802_11_BSSID (OID_GET_SET_TOGGLE | OID_802_11_BSSID) ++#define RT_OID_802_11_SSID (OID_GET_SET_TOGGLE | OID_802_11_SSID) ++#define RT_OID_802_11_INFRASTRUCTURE_MODE (OID_GET_SET_TOGGLE | OID_802_11_INFRASTRUCTURE_MODE) ++#define RT_OID_802_11_ADD_WEP (OID_GET_SET_TOGGLE | OID_802_11_ADD_WEP) ++#define RT_OID_802_11_ADD_KEY (OID_GET_SET_TOGGLE | OID_802_11_ADD_KEY) ++#define RT_OID_802_11_REMOVE_WEP (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_WEP) ++#define RT_OID_802_11_REMOVE_KEY (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_KEY) ++#define RT_OID_802_11_DISASSOCIATE (OID_GET_SET_TOGGLE | OID_802_11_DISASSOCIATE) ++#define RT_OID_802_11_AUTHENTICATION_MODE (OID_GET_SET_TOGGLE | OID_802_11_AUTHENTICATION_MODE) ++#define RT_OID_802_11_PRIVACY_FILTER (OID_GET_SET_TOGGLE | OID_802_11_PRIVACY_FILTER) ++#define RT_OID_802_11_BSSID_LIST_SCAN (OID_GET_SET_TOGGLE | OID_802_11_BSSID_LIST_SCAN) ++#define RT_OID_802_11_WEP_STATUS (OID_GET_SET_TOGGLE | OID_802_11_WEP_STATUS) ++#define RT_OID_802_11_RELOAD_DEFAULTS (OID_GET_SET_TOGGLE | OID_802_11_RELOAD_DEFAULTS) ++#define RT_OID_802_11_NETWORK_TYPE_IN_USE (OID_GET_SET_TOGGLE | OID_802_11_NETWORK_TYPE_IN_USE) ++#define RT_OID_802_11_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | OID_802_11_TX_POWER_LEVEL) ++#define RT_OID_802_11_RSSI_TRIGGER (OID_GET_SET_TOGGLE | OID_802_11_RSSI_TRIGGER) ++#define RT_OID_802_11_FRAGMENTATION_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_FRAGMENTATION_THRESHOLD) ++#define RT_OID_802_11_RTS_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_RTS_THRESHOLD) ++#define RT_OID_802_11_RX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_RX_ANTENNA_SELECTED) ++#define RT_OID_802_11_TX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_TX_ANTENNA_SELECTED) ++#define RT_OID_802_11_SUPPORTED_RATES (OID_GET_SET_TOGGLE | OID_802_11_SUPPORTED_RATES) ++#define RT_OID_802_11_DESIRED_RATES (OID_GET_SET_TOGGLE | OID_802_11_DESIRED_RATES) ++#define RT_OID_802_11_CONFIGURATION (OID_GET_SET_TOGGLE | OID_802_11_CONFIGURATION) ++#define RT_OID_802_11_POWER_MODE (OID_GET_SET_TOGGLE | OID_802_11_POWER_MODE) ++ ++typedef enum _NDIS_802_11_STATUS_TYPE ++{ ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; ++ ++typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; ++ ++typedef struct _NDIS_802_11_STATUS_INDICATION ++{ ++ NDIS_802_11_STATUS_TYPE StatusType; ++} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; ++ ++// mask for authentication/integrity fields ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++ ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST ++{ ++ ULONG Length; // Length of structure ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ULONG Flags; ++} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; ++ ++//Added new types for PMKID Candidate lists. ++typedef struct _PMKID_CANDIDATE { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ ULONG Flags; ++} PMKID_CANDIDATE, *PPMKID_CANDIDATE; ++ ++typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST ++{ ++ ULONG Version; // Version of the structure ++ ULONG NumCandidates; // No. of pmkid candidates ++ PMKID_CANDIDATE CandidateList[1]; ++} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; ++ ++//Flags for PMKID Candidate list structure ++#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++ ++// Added new types for OFDM 5G and 2.4G ++typedef enum _NDIS_802_11_NETWORK_TYPE ++{ ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM5_N, ++ Ndis802_11OFDM24, ++ Ndis802_11OFDM24_N, ++ Ndis802_11Automode, ++ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; ++ ++typedef struct _NDIS_802_11_NETWORK_TYPE_LIST ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_802_11_NETWORK_TYPE NetworkType [1]; ++} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST; ++ ++typedef enum _NDIS_802_11_POWER_MODE ++{ ++ Ndis802_11PowerModeCAM, ++ Ndis802_11PowerModeMAX_PSP, ++ Ndis802_11PowerModeFast_PSP, ++ Ndis802_11PowerModeLegacy_PSP, ++ Ndis802_11PowerModeMax // not a real mode, defined as an upper bound ++} NDIS_802_11_POWER_MODE, *PNDIS_802_11_POWER_MODE; ++ ++typedef ULONG NDIS_802_11_TX_POWER_LEVEL; // in milliwatts ++ ++// ++// Received Signal Strength Indication ++// ++typedef LONG NDIS_802_11_RSSI; // in dBm ++ ++typedef struct _NDIS_802_11_CONFIGURATION_FH ++{ ++ ULONG Length; // Length of structure ++ ULONG HopPattern; // As defined by 802.11, MSB set ++ ULONG HopSet; // to one if non-802.11 ++ ULONG DwellTime; // units are Kusec ++} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; ++ ++typedef struct _NDIS_802_11_CONFIGURATION ++{ ++ ULONG Length; // Length of structure ++ ULONG BeaconPeriod; // units are Kusec ++ ULONG ATIMWindow; // units are Kusec ++ ULONG DSConfig; // Frequency, units are kHz ++ NDIS_802_11_CONFIGURATION_FH FHConfig; ++} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; ++ ++typedef struct _NDIS_802_11_STATISTICS ++{ ++ ULONG Length; // Length of structure ++ LARGE_INTEGER TransmittedFragmentCount; ++ LARGE_INTEGER MulticastTransmittedFrameCount; ++ LARGE_INTEGER FailedCount; ++ LARGE_INTEGER RetryCount; ++ LARGE_INTEGER MultipleRetryCount; ++ LARGE_INTEGER RTSSuccessCount; ++ LARGE_INTEGER RTSFailureCount; ++ LARGE_INTEGER ACKFailureCount; ++ LARGE_INTEGER FrameDuplicateCount; ++ LARGE_INTEGER ReceivedFragmentCount; ++ LARGE_INTEGER MulticastReceivedFrameCount; ++ LARGE_INTEGER FCSErrorCount; ++ LARGE_INTEGER TKIPLocalMICFailures; ++ LARGE_INTEGER TKIPRemoteMICErrors; ++ LARGE_INTEGER TKIPICVErrors; ++ LARGE_INTEGER TKIPCounterMeasuresInvoked; ++ LARGE_INTEGER TKIPReplays; ++ LARGE_INTEGER CCMPFormatErrors; ++ LARGE_INTEGER CCMPReplays; ++ LARGE_INTEGER CCMPDecryptErrors; ++ LARGE_INTEGER FourWayHandshakeFailures; ++} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS; ++ ++typedef ULONG NDIS_802_11_KEY_INDEX; ++typedef ULONGLONG NDIS_802_11_KEY_RSC; ++ ++#define MAX_RADIUS_SRV_NUM 2 // 802.1x failover number ++ ++typedef struct PACKED _RADIUS_SRV_INFO { ++ UINT32 radius_ip; ++ UINT32 radius_port; ++ UCHAR radius_key[64]; ++ UCHAR radius_key_len; ++} RADIUS_SRV_INFO, *PRADIUS_SRV_INFO; ++ ++typedef struct PACKED _RADIUS_KEY_INFO ++{ ++ UCHAR radius_srv_num; ++ RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; ++ UCHAR ieee8021xWEP; // dynamic WEP ++ UCHAR key_index; ++ UCHAR key_length; // length of key in bytes ++ UCHAR key_material[13]; ++} RADIUS_KEY_INFO, *PRADIUS_KEY_INFO; ++ ++// It's used by 802.1x daemon to require relative configuration ++typedef struct PACKED _RADIUS_CONF ++{ ++ UINT32 Length; // Length of this structure ++ UCHAR mbss_num; // indicate multiple BSS number ++ UINT32 own_ip_addr; ++ UINT32 retry_interval; ++ UINT32 session_timeout_interval; ++ UCHAR EAPifname[IFNAMSIZ]; ++ UCHAR EAPifname_len; ++ UCHAR PreAuthifname[IFNAMSIZ]; ++ UCHAR PreAuthifname_len; ++ RADIUS_KEY_INFO RadiusInfo[8/*MAX_MBSSID_NUM*/]; ++} RADIUS_CONF, *PRADIUS_CONF; ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++// Key mapping keys require a BSSID ++typedef struct _NDIS_802_11_KEY ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; ++ UINT KeyLength; // length of key in bytes ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_KEY_RSC KeyRSC; ++ UCHAR KeyMaterial[1]; // variable length depending on above field ++} NDIS_802_11_KEY, *PNDIS_802_11_KEY; ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct _NDIS_802_11_REMOVE_KEY ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; ++ NDIS_802_11_MAC_ADDRESS BSSID; ++} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; ++ ++typedef struct _NDIS_802_11_WEP ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; // 0 is the per-client key, 1-N are the ++ // global keys ++ UINT KeyLength; // length of key in bytes ++ UCHAR KeyMaterial[1];// variable length depending on above field ++} NDIS_802_11_WEP, *PNDIS_802_11_WEP; ++ ++ ++typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE ++{ ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11Monitor, ++ Ndis802_11InfrastructureMax // Not a real value, defined as upper bound ++} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; ++ ++// Add new authentication modes ++typedef enum _NDIS_802_11_AUTHENTICATION_MODE ++{ ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWPA2, ++ Ndis802_11AuthModeWPA2PSK, ++ Ndis802_11AuthModeWPA1WPA2, ++ Ndis802_11AuthModeWPA1PSKWPA2PSK, ++ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound ++} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; ++ ++typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates ++typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates ++ ++typedef struct PACKED _NDIS_802_11_SSID ++{ ++ UINT SsidLength; // length of SSID field below, in bytes; ++ // this can be zero. ++ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field ++} NDIS_802_11_SSID, *PNDIS_802_11_SSID; ++ ++ ++typedef struct PACKED _NDIS_WLAN_BSSID ++{ ++ ULONG Length; // Length of this structure ++ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID ++ UCHAR Reserved[2]; ++ NDIS_802_11_SSID Ssid; // SSID ++ ULONG Privacy; // WEP encryption requirement ++ NDIS_802_11_RSSI Rssi; // receive signal strength in dBm ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES SupportedRates; ++} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; ++ ++typedef struct PACKED _NDIS_802_11_BSSID_LIST ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_WLAN_BSSID Bssid[1]; ++} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; ++ ++// Added Capabilities, IELength and IEs for each BSSID ++typedef struct PACKED _NDIS_WLAN_BSSID_EX ++{ ++ ULONG Length; // Length of this structure ++ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID ++ UCHAR Reserved[2]; ++ NDIS_802_11_SSID Ssid; // SSID ++ UINT Privacy; // WEP encryption requirement ++ NDIS_802_11_RSSI Rssi; // receive signal ++ // strength in dBm ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ ULONG IELength; ++ UCHAR IEs[1]; ++} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; ++ ++typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_WLAN_BSSID_EX Bssid[1]; ++} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; ++ ++typedef struct PACKED _NDIS_802_11_FIXED_IEs ++{ ++ UCHAR Timestamp[8]; ++ USHORT BeaconInterval; ++ USHORT Capabilities; ++} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; ++ ++typedef struct _NDIS_802_11_VARIABLE_IEs ++{ ++ UCHAR ElementID; ++ UCHAR Length; // Number of bytes in data field ++ UCHAR data[1]; ++} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; ++ ++typedef ULONG NDIS_802_11_FRAGMENTATION_THRESHOLD; ++ ++typedef ULONG NDIS_802_11_RTS_THRESHOLD; ++ ++typedef ULONG NDIS_802_11_ANTENNA; ++ ++typedef enum _NDIS_802_11_PRIVACY_FILTER ++{ ++ Ndis802_11PrivFilterAcceptAll, ++ Ndis802_11PrivFilter8021xWEP ++} NDIS_802_11_PRIVACY_FILTER, *PNDIS_802_11_PRIVACY_FILTER; ++ ++// Added new encryption types ++// Also aliased typedef to new name ++typedef enum _NDIS_802_11_WEP_STATUS ++{ ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent, ++ Ndis802_11Encryption4Enabled, // TKIP or AES mix ++ Ndis802_11Encryption4KeyAbsent, ++ Ndis802_11GroupWEP40Enabled, ++ Ndis802_11GroupWEP104Enabled, ++} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, ++ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; ++ ++typedef enum _NDIS_802_11_RELOAD_DEFAULTS ++{ ++ Ndis802_11ReloadWEPKeys ++} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++typedef struct _NDIS_802_11_AI_REQFI ++{ ++ USHORT Capabilities; ++ USHORT ListenInterval; ++ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; ++} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; ++ ++typedef struct _NDIS_802_11_AI_RESFI ++{ ++ USHORT Capabilities; ++ USHORT StatusCode; ++ USHORT AssociationId; ++} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; ++ ++typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION ++{ ++ ULONG Length; ++ USHORT AvailableRequestFixedIEs; ++ NDIS_802_11_AI_REQFI RequestFixedIEs; ++ ULONG RequestIELength; ++ ULONG OffsetRequestIEs; ++ USHORT AvailableResponseFixedIEs; ++ NDIS_802_11_AI_RESFI ResponseFixedIEs; ++ ULONG ResponseIELength; ++ ULONG OffsetResponseIEs; ++} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_EVENT ++{ ++ NDIS_802_11_STATUS_INDICATION Status; ++ NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; ++} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; ++ ++/* ++typedef struct _NDIS_802_11_TEST ++{ ++ ULONG Length; ++ ULONG Type; ++ union ++ { ++ NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; ++ NDIS_802_11_RSSI RssiTrigger; ++ }; ++} NDIS_802_11_TEST, *PNDIS_802_11_TEST; ++ */ ++ ++// 802.11 Media stream constraints, associated with OID_802_11_MEDIA_STREAM_MODE ++typedef enum _NDIS_802_11_MEDIA_STREAM_MODE ++{ ++ Ndis802_11MediaStreamOff, ++ Ndis802_11MediaStreamOn, ++} NDIS_802_11_MEDIA_STREAM_MODE, *PNDIS_802_11_MEDIA_STREAM_MODE; ++ ++// PMKID Structures ++typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef struct _BSSID_INFO ++{ ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_PMKID_VALUE PMKID; ++} BSSID_INFO, *PBSSID_INFO; ++ ++typedef struct _NDIS_802_11_PMKID ++{ ++ UINT Length; ++ UINT BSSIDInfoCount; ++ BSSID_INFO BSSIDInfo[1]; ++} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; ++ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; ++} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; ++ ++typedef struct _NDIS_802_11_CAPABILITY ++{ ++ ULONG Length; ++ ULONG Version; ++ ULONG NoOfPMKIDs; ++ ULONG NoOfAuthEncryptPairsSupported; ++ NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; ++} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; ++ ++//#endif //of WIN 2k ++#endif //UNDER_CE ++ ++#if WIRELESS_EXT <= 11 ++#ifndef SIOCDEVPRIVATE ++#define SIOCDEVPRIVATE 0x8BE0 ++#endif ++#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) ++ ++#ifdef DBG ++#define RTPRIV_IOCTL_BBP (SIOCIWFIRSTPRIV + 0x03) ++#define RTPRIV_IOCTL_MAC (SIOCIWFIRSTPRIV + 0x05) ++#define RTPRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x07) ++#endif ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++#define RTPRIV_IOCTL_ATE (SIOCIWFIRSTPRIV + 0x08) ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#define RTPRIV_IOCTL_STATISTICS (SIOCIWFIRSTPRIV + 0x09) ++#define RTPRIV_IOCTL_ADD_PMKID_CACHE (SIOCIWFIRSTPRIV + 0x0A) ++#define RTPRIV_IOCTL_RADIUS_DATA (SIOCIWFIRSTPRIV + 0x0C) ++#define RTPRIV_IOCTL_GSITESURVEY (SIOCIWFIRSTPRIV + 0x0D) ++#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) // Sync. with RT61 (for wpa_supplicant) ++#define RTPRIV_IOCTL_GET_MAC_TABLE (SIOCIWFIRSTPRIV + 0x0F) ++ ++#define RTPRIV_IOCTL_SHOW (SIOCIWFIRSTPRIV + 0x11) ++enum { ++ SHOW_CONN_STATUS = 4, ++ SHOW_DRVIER_VERION = 5, ++ SHOW_BA_INFO = 6, ++ SHOW_DESC_INFO = 7, ++#ifdef RT2870 ++ SHOW_RXBULK_INFO = 8, ++ SHOW_TXBULK_INFO = 9, ++#endif // RT2870 // ++ RAIO_OFF = 10, ++ RAIO_ON = 11, ++#ifdef QOS_DLS_SUPPORT ++ SHOW_DLS_ENTRY_INFO = 19, ++#endif // QOS_DLS_SUPPORT // ++ SHOW_CFG_VALUE = 20, ++ SHOW_ADHOC_ENTRY_INFO = 21, ++}; ++ ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++//SNMP ieee 802dot11, kathy , 2008_0220 ++// dot11res(3) ++#define RT_OID_802_11_MANUFACTUREROUI 0x0700 ++#define RT_OID_802_11_MANUFACTURERNAME 0x0701 ++#define RT_OID_802_11_RESOURCETYPEIDNAME 0x0702 ++ ++// dot11smt(1) ++#define RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED 0x0703 ++#define RT_OID_802_11_POWERMANAGEMENTMODE 0x0704 ++#define OID_802_11_WEPDEFAULTKEYVALUE 0x0705 // read , write ++#define OID_802_11_WEPDEFAULTKEYID 0x0706 ++#define RT_OID_802_11_WEPKEYMAPPINGLENGTH 0x0707 ++#define OID_802_11_SHORTRETRYLIMIT 0x0708 ++#define OID_802_11_LONGRETRYLIMIT 0x0709 ++#define RT_OID_802_11_PRODUCTID 0x0710 ++#define RT_OID_802_11_MANUFACTUREID 0x0711 ++ ++// //dot11Phy(4) ++#define OID_802_11_CURRENTCHANNEL 0x0712 ++ ++//dot11mac ++#define RT_OID_802_11_MAC_ADDRESS 0x0713 ++#endif // SNMP_SUPPORT // ++ ++#define OID_802_11_BUILD_CHANNEL_EX 0x0714 ++#define OID_802_11_GET_CH_LIST 0x0715 ++#define OID_802_11_GET_COUNTRY_CODE 0x0716 ++#define OID_802_11_GET_CHANNEL_GEOGRAPHY 0x0717 ++ ++#ifdef LLTD_SUPPORT ++// for consistency with RT61 ++#define RT_OID_GET_PHY_MODE 0x761 ++#endif // LLTD_SUPPORT // ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! ++typedef union _HTTRANSMIT_SETTING { ++#ifdef RT_BIG_ENDIAN ++ struct { ++ USHORT MODE:2; // Use definition MODE_xxx. ++// USHORT rsv:3; ++ USHORT TxBF:1; ++ USHORT rsv:2; ++ USHORT STBC:2; //SPACE ++ USHORT ShortGI:1; ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT MCS:7; // MCS ++ } field; ++#else ++ struct { ++ USHORT MCS:7; // MCS ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++// USHORT rsv:3; ++ USHORT rsv:2; ++ USHORT TxBF:1; ++ USHORT MODE:2; // Use definition MODE_xxx. ++ } field; ++#endif ++ USHORT word; ++ } HTTRANSMIT_SETTING, *PHTTRANSMIT_SETTING; ++ ++typedef enum _RT_802_11_PREAMBLE { ++ Rt802_11PreambleLong, ++ Rt802_11PreambleShort, ++ Rt802_11PreambleAuto ++} RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; ++ ++// Only for STA, need to sync with AP ++typedef enum _RT_802_11_PHY_MODE { ++ PHY_11BG_MIXED = 0, ++ PHY_11B, ++ PHY_11A, ++ PHY_11ABG_MIXED, ++ PHY_11G, ++#ifdef DOT11_N_SUPPORT ++ PHY_11ABGN_MIXED, // both band 5 ++ PHY_11N_2_4G, // 11n-only with 2.4G band 6 ++ PHY_11GN_MIXED, // 2.4G band 7 ++ PHY_11AN_MIXED, // 5G band 8 ++ PHY_11BGN_MIXED, // if check 802.11b. 9 ++ PHY_11AGN_MIXED, // if check 802.11b. 10 ++ PHY_11N_5G, // 11n-only with 5G band 11 ++#endif // DOT11_N_SUPPORT // ++} RT_802_11_PHY_MODE; ++ ++// put all proprietery for-query objects here to reduce # of Query_OID ++typedef struct _RT_802_11_LINK_STATUS { ++ ULONG CurrTxRate; // in units of 0.5Mbps ++ ULONG ChannelQuality; // 0..100 % ++ ULONG TxByteCount; // both ok and fail ++ ULONG RxByteCount; // both ok and fail ++ ULONG CentralChannel; // 40MHz central channel number ++} RT_802_11_LINK_STATUS, *PRT_802_11_LINK_STATUS; ++ ++typedef struct _RT_802_11_EVENT_LOG { ++ LARGE_INTEGER SystemTime; // timestammp via NdisGetCurrentSystemTime() ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ USHORT Event; // EVENT_xxx ++} RT_802_11_EVENT_LOG, *PRT_802_11_EVENT_LOG; ++ ++typedef struct _RT_802_11_EVENT_TABLE { ++ ULONG Num; ++ ULONG Rsv; // to align Log[] at LARGE_INEGER boundary ++ RT_802_11_EVENT_LOG Log[MAX_NUMBER_OF_EVENT]; ++} RT_802_11_EVENT_TABLE, PRT_802_11_EVENT_TABLE; ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! ++typedef union _MACHTTRANSMIT_SETTING { ++ struct { ++ USHORT MCS:7; // MCS ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:3; ++ USHORT MODE:2; // Use definition MODE_xxx. ++ } field; ++ USHORT word; ++ } MACHTTRANSMIT_SETTING, *PMACHTTRANSMIT_SETTING; ++ ++typedef struct _RT_802_11_MAC_ENTRY { ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ UCHAR Aid; ++ UCHAR Psm; // 0:PWR_ACTIVE, 1:PWR_SAVE ++ UCHAR MimoPs; // 0:MMPS_STATIC, 1:MMPS_DYNAMIC, 3:MMPS_Enabled ++ CHAR AvgRssi0; ++ CHAR AvgRssi1; ++ CHAR AvgRssi2; ++ UINT32 ConnectedTime; ++ MACHTTRANSMIT_SETTING TxRate; ++} RT_802_11_MAC_ENTRY, *PRT_802_11_MAC_ENTRY; ++ ++typedef struct _RT_802_11_MAC_TABLE { ++ ULONG Num; ++ RT_802_11_MAC_ENTRY Entry[MAX_NUMBER_OF_MAC]; ++} RT_802_11_MAC_TABLE, *PRT_802_11_MAC_TABLE; ++ ++// structure for query/set hardware register - MAC, BBP, RF register ++typedef struct _RT_802_11_HARDWARE_REGISTER { ++ ULONG HardwareType; // 0:MAC, 1:BBP, 2:RF register, 3:EEPROM ++ ULONG Offset; // Q/S register offset addr ++ ULONG Data; // R/W data buffer ++} RT_802_11_HARDWARE_REGISTER, *PRT_802_11_HARDWARE_REGISTER; ++ ++// structure to tune BBP R17 "RX AGC VGC init" ++//typedef struct _RT_802_11_RX_AGC_VGC_TUNING { ++// UCHAR FalseCcaLowerThreshold; // 0-255, def 10 ++// UCHAR FalseCcaUpperThreshold; // 0-255, def 100 ++// UCHAR VgcDelta; // R17 +-= VgcDelta whenever flase CCA over UpprThreshold ++// // or lower than LowerThresholdupper threshold ++// UCHAR VgcUpperBound; // max value of R17 ++//} RT_802_11_RX_AGC_VGC_TUNING, *PRT_802_11_RX_AGC_VGC_TUNING; ++ ++typedef struct _RT_802_11_AP_CONFIG { ++ ULONG EnableTxBurst; // 0-disable, 1-enable ++ ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate ++ ULONG IsolateInterStaTraffic; // 0-disable, 1-enable isolation ++ ULONG HideSsid; // 0-disable, 1-enable hiding ++ ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF ++ ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time ++ ULONG Rsv1; // must be 0 ++ ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY ++} RT_802_11_AP_CONFIG, *PRT_802_11_AP_CONFIG; ++ ++// structure to query/set STA_CONFIG ++typedef struct _RT_802_11_STA_CONFIG { ++ ULONG EnableTxBurst; // 0-disable, 1-enable ++ ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate ++ ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF ++ ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time when applicable ++ ULONG AdhocMode; // 0-11b rates only (WIFI spec), 1 - b/g mixed, 2 - g only ++ ULONG HwRadioStatus; // 0-OFF, 1-ON, default is 1, Read-Only ++ ULONG Rsv1; // must be 0 ++ ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY ++} RT_802_11_STA_CONFIG, *PRT_802_11_STA_CONFIG; ++ ++// ++// For OID Query or Set about BA structure ++// ++typedef struct _OID_BACAP_STRUC { ++ UCHAR RxBAWinLimit; ++ UCHAR TxBAWinLimit; ++ UCHAR Policy; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid ++ UCHAR MpduDensity; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid ++ UCHAR AmsduEnable; //Enable AMSDU transmisstion ++ UCHAR AmsduSize; // 0:3839, 1:7935 bytes. UINT MSDUSizeToBytes[] = { 3839, 7935}; ++ UCHAR MMPSmode; // MIMO power save more, 0:static, 1:dynamic, 2:rsv, 3:mimo enable ++ BOOLEAN AutoBA; // Auto BA will automatically ++} OID_BACAP_STRUC, *POID_BACAP_STRUC; ++ ++typedef struct _RT_802_11_ACL_ENTRY { ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ USHORT Rsv; ++} RT_802_11_ACL_ENTRY, *PRT_802_11_ACL_ENTRY; ++ ++typedef struct PACKED _RT_802_11_ACL { ++ ULONG Policy; // 0-disable, 1-positive list, 2-negative list ++ ULONG Num; ++ RT_802_11_ACL_ENTRY Entry[MAX_NUMBER_OF_ACL]; ++} RT_802_11_ACL, *PRT_802_11_ACL; ++ ++typedef struct _RT_802_11_WDS { ++ ULONG Num; ++ NDIS_802_11_MAC_ADDRESS Entry[24/*MAX_NUM_OF_WDS_LINK*/]; ++ ULONG KeyLength; ++ UCHAR KeyMaterial[32]; ++} RT_802_11_WDS, *PRT_802_11_WDS; ++ ++typedef struct _RT_802_11_TX_RATES_ { ++ UCHAR SupRateLen; ++ UCHAR SupRate[MAX_LENGTH_OF_SUPPORT_RATES]; ++ UCHAR ExtRateLen; ++ UCHAR ExtRate[MAX_LENGTH_OF_SUPPORT_RATES]; ++} RT_802_11_TX_RATES, *PRT_802_11_TX_RATES; ++ ++ ++// Definition of extra information code ++#define GENERAL_LINK_UP 0x0 // Link is Up ++#define GENERAL_LINK_DOWN 0x1 // Link is Down ++#define HW_RADIO_OFF 0x2 // Hardware radio off ++#define SW_RADIO_OFF 0x3 // Software radio off ++#define AUTH_FAIL 0x4 // Open authentication fail ++#define AUTH_FAIL_KEYS 0x5 // Shared authentication fail ++#define ASSOC_FAIL 0x6 // Association failed ++#define EAP_MIC_FAILURE 0x7 // Deauthencation because MIC failure ++#define EAP_4WAY_TIMEOUT 0x8 // Deauthencation on 4-way handshake timeout ++#define EAP_GROUP_KEY_TIMEOUT 0x9 // Deauthencation on group key handshake timeout ++#define EAP_SUCCESS 0xa // EAP succeed ++#define DETECT_RADAR_SIGNAL 0xb // Radar signal occur in current channel ++#define EXTRA_INFO_MAX 0xb // Indicate Last OID ++ ++#define EXTRA_INFO_CLEAR 0xffffffff ++ ++// This is OID setting structure. So only GF or MM as Mode. This is valid when our wirelss mode has 802.11n in use. ++typedef struct { ++ RT_802_11_PHY_MODE PhyMode; // ++ UCHAR TransmitNo; ++ UCHAR HtMode; //HTMODE_GF or HTMODE_MM ++ UCHAR ExtOffset; //extension channel above or below ++ UCHAR MCS; ++ UCHAR BW; ++ UCHAR STBC; ++ UCHAR SHORTGI; ++ UCHAR rsv; ++} OID_SET_HT_PHYMODE, *POID_SET_HT_PHYMODE; ++ ++#ifdef NINTENDO_AP ++#define NINTENDO_MAX_ENTRY 16 ++#define NINTENDO_SSID_NAME_LN 8 ++#define NINTENDO_SSID_NAME "NWCUSBAP" ++#define NINTENDO_PROBE_REQ_FLAG_MASK 0x03 ++#define NINTENDO_PROBE_REQ_ON 0x01 ++#define NINTENDO_PROBE_REQ_SIGNAL 0x02 ++#define NINTENDO_PROBE_RSP_ON 0x01 ++#define NINTENDO_SSID_NICKNAME_LN 20 ++ ++#define NINTENDO_WEPKEY_LN 13 ++ ++typedef struct _NINTENDO_SSID ++{ ++ UCHAR NINTENDOFixChar[NINTENDO_SSID_NAME_LN]; ++ UCHAR zero1; ++ UCHAR registe; ++ UCHAR ID; ++ UCHAR zero2; ++ UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; ++} RT_NINTENDO_SSID, *PRT_NINTENDO_SSID; ++ ++typedef struct _NINTENDO_ENTRY ++{ ++ UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; ++ UCHAR DS_Addr[ETH_LENGTH_OF_ADDRESS]; ++ UCHAR registe; ++ UCHAR UserSpaceAck; ++} RT_NINTENDO_ENTRY, *PRT_NINTENDO_ENTRY; ++ ++//RTPRIV_IOCTL_NINTENDO_GET_TABLE ++//RTPRIV_IOCTL_NINTENDO_SET_TABLE ++typedef struct _NINTENDO_TABLE ++{ ++ UINT number; ++ RT_NINTENDO_ENTRY entry[NINTENDO_MAX_ENTRY]; ++} RT_NINTENDO_TABLE, *PRT_NINTENDO_TABLE; ++ ++//RTPRIV_IOCTL_NINTENDO_SEED_WEPKEY ++typedef struct _NINTENDO_SEED_WEPKEY ++{ ++ UCHAR seed[NINTENDO_SSID_NICKNAME_LN]; ++ UCHAR wepkey[16];//use 13 for 104 bits wep key ++} RT_NINTENDO_SEED_WEPKEY, *PRT_NINTENDO_SEED_WEPKEY; ++#endif // NINTENDO_AP // ++ ++#ifdef LLTD_SUPPORT ++typedef struct _RT_LLTD_ASSOICATION_ENTRY { ++ UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; ++ unsigned short MOR; // maximum operational rate ++ UCHAR phyMode; ++} RT_LLTD_ASSOICATION_ENTRY, *PRT_LLTD_ASSOICATION_ENTRY; ++ ++typedef struct _RT_LLTD_ASSOICATION_TABLE { ++ unsigned int Num; ++ RT_LLTD_ASSOICATION_ENTRY Entry[MAX_NUMBER_OF_MAC]; ++} RT_LLTD_ASSOICATION_TABLE, *PRT_LLTD_ASSOICATION_TABLE; ++#endif // LLTD_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++//rt2860, kathy 2007-0118 ++// structure for DLS ++typedef struct _RT_802_11_DLS_UI { ++ USHORT TimeOut; // unit: second , set by UI ++ USHORT CountDownTimer; // unit: second , used by driver only ++ NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI ++ UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only ++ BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link ++} RT_802_11_DLS_UI, *PRT_802_11_DLS_UI; ++ ++typedef struct _RT_802_11_DLS_INFO { ++ RT_802_11_DLS_UI Entry[MAX_NUMBER_OF_DLS_ENTRY]; ++ UCHAR num; ++} RT_802_11_DLS_INFO, *PRT_802_11_DLS_INFO; ++ ++typedef enum _RT_802_11_DLS_MODE { ++ DLS_NONE, ++ DLS_WAIT_KEY, ++ DLS_FINISH ++} RT_802_11_DLS_MODE; ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++#define RT_ASSOC_EVENT_FLAG 0x0101 ++#define RT_DISASSOC_EVENT_FLAG 0x0102 ++#define RT_REQIE_EVENT_FLAG 0x0103 ++#define RT_RESPIE_EVENT_FLAG 0x0104 ++#define RT_ASSOCINFO_EVENT_FLAG 0x0105 ++#define RT_PMKIDCAND_FLAG 0x0106 ++#define RT_INTERFACE_DOWN 0x0107 ++#define RT_INTERFACE_UP 0x0108 ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#define MAX_CUSTOM_LEN 128 ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef enum _RT_802_11_D_CLIENT_MODE ++{ ++ Rt802_11_D_None, ++ Rt802_11_D_Flexible, ++ Rt802_11_D_Strict, ++} RT_802_11_D_CLIENT_MODE, *PRT_802_11_D_CLIENT_MODE; ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct _RT_CHANNEL_LIST_INFO ++{ ++ UCHAR ChannelList[MAX_NUM_OF_CHS]; // list all supported channels for site survey ++ UCHAR ChannelListNum; // number of channel in ChannelList[] ++} RT_CHANNEL_LIST_INFO, *PRT_CHANNEL_LIST_INFO; ++ ++// WSC configured credential ++typedef struct _WSC_CREDENTIAL ++{ ++ NDIS_802_11_SSID SSID; // mandatory ++ USHORT AuthType; // mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk ++ USHORT EncrType; // mandatory, 1: none, 2: wep, 4: tkip, 8: aes ++ UCHAR Key[64]; // mandatory, Maximum 64 byte ++ USHORT KeyLength; ++ UCHAR MacAddr[6]; // mandatory, AP MAC address ++ UCHAR KeyIndex; // optional, default is 1 ++ UCHAR Rsvd[3]; // Make alignment ++} WSC_CREDENTIAL, *PWSC_CREDENTIAL; ++ ++// WSC configured profiles ++typedef struct _WSC_PROFILE ++{ ++ UINT ProfileCnt; ++ WSC_CREDENTIAL Profile[8]; // Support up to 8 profiles ++} WSC_PROFILE, *PWSC_PROFILE; ++ ++ ++#endif // _OID_H_ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rt2870.h +@@ -0,0 +1,761 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __RT2870_H__ ++#define __RT2870_H__ ++ ++//usb header files ++#include ++ ++/* rtmp_def.h */ ++// ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define BULKAGGRE_ZISE 100 ++#define RT28XX_DRVDATA_SET(_a) usb_set_intfdata(_a, pAd); ++#define RT28XX_PUT_DEVICE usb_put_dev ++#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso, GFP_ATOMIC) ++#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb, GFP_ATOMIC) ++#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) usb_buffer_alloc(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr) ++#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) usb_buffer_free(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) ++#else ++#define BULKAGGRE_ZISE 60 ++#define RT28XX_DRVDATA_SET(_a) ++#define RT28XX_PUT_DEVICE(dev_p) ++#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso) ++#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb) ++#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) kmalloc(BufSize, GFP_ATOMIC) ++#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) kfree(pTransferBuf) ++#endif ++ ++#define RXBULKAGGRE_ZISE 12 ++#define MAX_TXBULK_LIMIT (LOCAL_TXBUF_SIZE*(BULKAGGRE_ZISE-1)) ++#define MAX_TXBULK_SIZE (LOCAL_TXBUF_SIZE*BULKAGGRE_ZISE) ++#define MAX_RXBULK_SIZE (LOCAL_TXBUF_SIZE*RXBULKAGGRE_ZISE) ++#define MAX_MLME_HANDLER_MEMORY 20 ++#define RETRY_LIMIT 10 ++#define BUFFER_SIZE 2400 //2048 ++#define TX_RING 0xa ++#define PRIO_RING 0xc ++ ++ ++// Flags for Bulkflags control for bulk out data ++// ++#define fRTUSB_BULK_OUT_DATA_NULL 0x00000001 ++#define fRTUSB_BULK_OUT_RTS 0x00000002 ++#define fRTUSB_BULK_OUT_MLME 0x00000004 ++ ++#define fRTUSB_BULK_OUT_DATA_NORMAL 0x00010000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_2 0x00020000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_3 0x00040000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_4 0x00080000 ++ ++#define fRTUSB_BULK_OUT_PSPOLL 0x00000020 ++#define fRTUSB_BULK_OUT_DATA_FRAG 0x00000040 ++#define fRTUSB_BULK_OUT_DATA_FRAG_2 0x00000080 ++#define fRTUSB_BULK_OUT_DATA_FRAG_3 0x00000100 ++#define fRTUSB_BULK_OUT_DATA_FRAG_4 0x00000200 ++ ++#ifdef RALINK_ATE ++#define fRTUSB_BULK_OUT_DATA_ATE 0x00100000 ++#endif // RALINK_ATE // ++ ++#define RT2870_USB_DEVICES \ ++{ \ ++ {USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \ ++ {USB_DEVICE(0x148F,0x2870)}, /* Ralink */ \ ++ {USB_DEVICE(0x148F,0x3070)}, /* Ralink */ \ ++ {USB_DEVICE(0x0B05,0x1731)}, /* Asus */ \ ++ {USB_DEVICE(0x0B05,0x1732)}, /* Asus */ \ ++ {USB_DEVICE(0x0B05,0x1742)}, /* Asus */ \ ++ {USB_DEVICE(0x0DF6,0x0017)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x002B)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */ \ ++ {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ ++ {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ ++ {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ ++ {USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */ \ ++ {USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */ \ ++ {USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */ \ ++ {USB_DEVICE(0x14B2,0x3C07)}, /* AL */ \ ++ {USB_DEVICE(0x14B2,0x3C12)}, /* AL */ \ ++ {USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \ ++ {USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \ ++ {USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \ ++ {USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \ ++ {USB_DEVICE(0x07AA,0x003C)}, /* Corega */ \ ++ {USB_DEVICE(0x07AA,0x003F)}, /* Corega */ \ ++ {USB_DEVICE(0x18C5,0x0012)}, /* Corega */ \ ++ {USB_DEVICE(0x1044,0x800B)}, /* Gigabyte */ \ ++ {USB_DEVICE(0x15A9,0x0006)}, /* Sparklan */ \ ++ {USB_DEVICE(0x083A,0xB522)}, /* SMC */ \ ++ {USB_DEVICE(0x083A,0xA618)}, /* SMC */ \ ++ {USB_DEVICE(0x083A,0x7522)}, /* Arcadyan */ \ ++ {USB_DEVICE(0x0CDE,0x0022)}, /* ZCOM */ \ ++ {USB_DEVICE(0x0586,0x3416)}, /* Zyxel */ \ ++ {USB_DEVICE(0x0CDE,0x0025)}, /* Zyxel */ \ ++ {USB_DEVICE(0x1740,0x9701)}, /* EnGenius */ \ ++ {USB_DEVICE(0x1740,0x9702)}, /* EnGenius */ \ ++ {USB_DEVICE(0x0471,0x200f)}, /* Philips */ \ ++ {USB_DEVICE(0x14B2,0x3C25)}, /* Draytek */ \ ++ {USB_DEVICE(0x13D3,0x3247)}, /* AzureWave */ \ ++ {USB_DEVICE(0x083A,0x6618)}, /* Accton */ \ ++ {USB_DEVICE(0x15c5,0x0008)}, /* Amit */ \ ++ {USB_DEVICE(0x0E66,0x0001)}, /* Hawking */ \ ++ {USB_DEVICE(0x0E66,0x0003)}, /* Hawking */ \ ++ {USB_DEVICE(0x129B,0x1828)}, /* Siemens */ \ ++ {USB_DEVICE(0x157E,0x300E)}, /* U-Media */ \ ++ {USB_DEVICE(0x050d,0x805c)}, \ ++ {USB_DEVICE(0x1482,0x3C09)}, /* Abocom*/ \ ++ {USB_DEVICE(0x14B2,0x3C09)}, /* Alpha */ \ ++ {USB_DEVICE(0x04E8,0x2018)}, /* samsung */ \ ++ {USB_DEVICE(0x07B8,0x3070)}, /* AboCom */ \ ++ {USB_DEVICE(0x07B8,0x3071)}, /* AboCom */ \ ++ {USB_DEVICE(0x07B8,0x2870)}, /* AboCom */ \ ++ {USB_DEVICE(0x07B8,0x2770)}, /* AboCom */ \ ++ {USB_DEVICE(0x7392,0x7711)}, /* Edimax */ \ ++ {USB_DEVICE(0x5A57,0x0280)}, /* Zinwell */ \ ++ {USB_DEVICE(0x5A57,0x0282)}, /* Zinwell */ \ ++ {USB_DEVICE(0x0789,0x0162)}, /* Logitec */ \ ++ {USB_DEVICE(0x0789,0x0163)}, /* Logitec */ \ ++ {USB_DEVICE(0x0789,0x0164)}, /* Logitec */ \ ++ { }/* Terminating entry */ \ ++} ++ ++#define FREE_HTTX_RING(_p, _b, _t) \ ++{ \ ++ if ((_t)->ENextBulkOutPosition == (_t)->CurWritePosition) \ ++ { \ ++ (_t)->bRingEmpty = TRUE; \ ++ } \ ++ /*NdisInterlockedDecrement(&(_p)->TxCount); */\ ++} ++ ++// ++// RXINFO appends at the end of each rx packet. ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _RXINFO_STRUC { ++ UINT32 PlcpSignal:12; ++ UINT32 LastAMSDU:1; ++ UINT32 CipherAlg:1; ++ UINT32 PlcpRssil:1; ++ UINT32 Decrypted:1; ++ UINT32 AMPDU:1; // To be moved ++ UINT32 L2PAD:1; ++ UINT32 RSSI:1; ++ UINT32 HTC:1; ++ UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. ++ UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid ++ UINT32 Crc:1; // 1: CRC error ++ UINT32 MyBss:1; // 1: this frame belongs to the same BSSID ++ UINT32 Bcast:1; // 1: this is a broadcast frame ++ UINT32 Mcast:1; // 1: this is a multicast frame ++ UINT32 U2M:1; // 1: this RX frame is unicast to me ++ UINT32 FRAG:1; ++ UINT32 NULLDATA:1; ++ UINT32 DATA:1; ++ UINT32 BA:1; ++} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; ++#else ++typedef struct PACKED _RXINFO_STRUC { ++ UINT32 BA:1; ++ UINT32 DATA:1; ++ UINT32 NULLDATA:1; ++ UINT32 FRAG:1; ++ UINT32 U2M:1; // 1: this RX frame is unicast to me ++ UINT32 Mcast:1; // 1: this is a multicast frame ++ UINT32 Bcast:1; // 1: this is a broadcast frame ++ UINT32 MyBss:1; // 1: this frame belongs to the same BSSID ++ UINT32 Crc:1; // 1: CRC error ++ UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid ++ UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. ++ UINT32 HTC:1; ++ UINT32 RSSI:1; ++ UINT32 L2PAD:1; ++ UINT32 AMPDU:1; // To be moved ++ UINT32 Decrypted:1; ++ UINT32 PlcpRssil:1; ++ UINT32 CipherAlg:1; ++ UINT32 LastAMSDU:1; ++ UINT32 PlcpSignal:12; ++} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; ++#endif ++ ++ ++// ++// TXINFO ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct _TXINFO_STRUC { ++ // Word 0 ++ UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint ++ UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid ++ UINT32 rsv2:2; // Software use. ++ UINT32 SwUseLastRound:1; // Software use. ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 rsv:8; ++ UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. ++} TXINFO_STRUC, *PTXINFO_STRUC; ++#else ++typedef struct _TXINFO_STRUC { ++ // Word 0 ++ UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. ++ UINT32 rsv:8; ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 SwUseLastRound:1; // Software use. ++ UINT32 rsv2:2; // Software use. ++ UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid ++ UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint ++} TXINFO_STRUC, *PTXINFO_STRUC; ++#endif ++ ++#define TXINFO_SIZE 4 ++#define RXINFO_SIZE 4 ++#define TXPADDING_SIZE 11 ++ ++// ++// Management ring buffer format ++// ++typedef struct _MGMT_STRUC { ++ BOOLEAN Valid; ++ PUCHAR pBuffer; ++ ULONG Length; ++} MGMT_STRUC, *PMGMT_STRUC; ++ ++ ++/* ----------------- EEPROM Related MACRO ----------------- */ ++#define RT28xx_EEPROM_READ16(pAd, offset, var) \ ++ do { \ ++ RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ ++ var = le2cpu16(var); \ ++ }while(0) ++ ++#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ ++ do{ \ ++ USHORT _tmpVar; \ ++ _tmpVar = cpu2le16(var); \ ++ RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ ++ }while(0) ++ ++/* ----------------- TASK/THREAD Related MACRO ----------------- */ ++#define RT28XX_TASK_THREAD_INIT(pAd, Status) \ ++ Status = CreateThreads(net_dev); ++ ++ ++/* ----------------- Frimware Related MACRO ----------------- */ ++#if 0 ++#define RT28XX_FIRMUD_INIT(pAd) \ ++ { UINT32 MacReg; \ ++ RTUSBReadMACRegister(pAd, MAC_CSR0, &MacReg); } ++ ++#define RT28XX_FIRMUD_END(pAd) \ ++ RTUSBWriteMACRegister(pAd, 0x7014, 0xffffffff); \ ++ RTUSBWriteMACRegister(pAd, 0x701c, 0xffffffff); \ ++ RTUSBFirmwareRun(pAd); ++#else ++#define RT28XX_WRITE_FIRMWARE(_pAd, _pFwImage, _FwLen) \ ++ RTUSBFirmwareWrite(_pAd, _pFwImage, _FwLen) ++#endif ++ ++/* ----------------- TX Related MACRO ----------------- */ ++#define RT28XX_START_DEQUEUE(pAd, QueIdx, irqFlags) \ ++ { \ ++ RTMP_IRQ_LOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ ++ if (pAd->DeQueueRunning[QueIdx]) \ ++ { \ ++ RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags);\ ++ printk("DeQueueRunning[%d]= TRUE!\n", QueIdx); \ ++ continue; \ ++ } \ ++ else \ ++ { \ ++ pAd->DeQueueRunning[QueIdx] = TRUE; \ ++ RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags);\ ++ } \ ++ } ++#define RT28XX_STOP_DEQUEUE(pAd, QueIdx, irqFlags) \ ++ do{ \ ++ RTMP_IRQ_LOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ ++ pAd->DeQueueRunning[QueIdx] = FALSE; \ ++ RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ ++ }while(0) ++ ++ ++#define RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, freeNum, pPacket) \ ++ (RTUSBFreeDescriptorRequest(pAd, pTxBlk->QueIdx, (pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))) == NDIS_STATUS_SUCCESS) ++ ++#define RT28XX_RELEASE_DESC_RESOURCE(pAd, QueIdx) \ ++ do{}while(0) ++ ++#define NEED_QUEUE_BACK_FOR_AGG(_pAd, _QueIdx, _freeNum, _TxFrameType) \ ++ ((_TxFrameType == TX_RALINK_FRAME) && (RTUSBNeedQueueBackForAgg(_pAd, _QueIdx))) ++ ++ ++ ++#define fRTMP_ADAPTER_NEED_STOP_TX \ ++ (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_BULKOUT_RESET | \ ++ fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ++ ++ ++#define HAL_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) \ ++ RtmpUSB_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) ++ ++#define HAL_WriteTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) \ ++ RtmpUSB_WriteSingleTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) ++ ++#define HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) \ ++ RtmpUSB_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) ++ ++#define HAL_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) \ ++ RtmpUSB_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) ++ ++#define HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, TxIdx) \ ++ RtmpUSB_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, TxIdx) ++ ++#define HAL_LastTxIdx(pAd, QueIdx,TxIdx) \ ++ /*RtmpUSBDataLastTxIdx(pAd, QueIdx,TxIdx)*/ ++ ++#define HAL_KickOutTx(pAd, pTxBlk, QueIdx) \ ++ RtmpUSBDataKickOut(pAd, pTxBlk, QueIdx) ++ ++ ++#define HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen) \ ++ RtmpUSBMgmtKickOut(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen) ++ ++#define HAL_KickOutNullFrameTx(_pAd, _QueIdx, _pNullFrame, _frameLen) \ ++ RtmpUSBNullFrameKickOut(_pAd, _QueIdx, _pNullFrame, _frameLen) ++ ++#define RTMP_PKT_TAIL_PADDING 11 // 3(max 4 byte padding) + 4 (last packet padding) + 4 (MaxBulkOutsize align padding) ++ ++extern UCHAR EpToQueue[6]; ++ ++ ++#ifdef RT2870 ++#define GET_TXRING_FREENO(_pAd, _QueIdx) (_QueIdx) //(_pAd->TxRing[_QueIdx].TxSwFreeIdx) ++#define GET_MGMTRING_FREENO(_pAd) (_pAd->MgmtRing.TxSwFreeIdx) ++#endif // RT2870 // ++ ++ ++/* ----------------- RX Related MACRO ----------------- */ ++//#define RT28XX_RX_ERROR_CHECK RTMPCheckRxWI ++ ++#if 0 ++#define RT28XX_RCV_INIT(pAd) \ ++ pAd->TransferBufferLength = 0; \ ++ pAd->ReadPosition = 0; \ ++ pAd->pCurrRxContext = NULL; ++#endif ++ ++#define RT28XX_RV_ALL_BUF_END(bBulkReceive) \ ++ /* We return STATUS_MORE_PROCESSING_REQUIRED so that the completion */ \ ++ /* routine (IofCompleteRequest) will stop working on the irp. */ \ ++ if (bBulkReceive == TRUE) RTUSBBulkReceive(pAd); ++ ++ ++/* ----------------- ASIC Related MACRO ----------------- */ ++#if 0 ++#define RT28XX_DMA_WRITE_INIT(GloCfg) \ ++ { GloCfg.field.EnTXWriteBackDDONE = 1; \ ++ GloCfg.field.EnableRxDMA = 1; \ ++ GloCfg.field.EnableTxDMA = 1; } ++ ++#define RT28XX_DMA_POST_WRITE(_pAd) \ ++ do{ USB_DMA_CFG_STRUC UsbCfg; \ ++ UsbCfg.word = 0; \ ++ /* for last packet, PBF might use more than limited, so minus 2 to prevent from error */ \ ++ UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3; \ ++ UsbCfg.field.phyclear = 0; \ ++ /* usb version is 1.1,do not use bulk in aggregation */ \ ++ if (_pAd->BulkInMaxPacketSize == 512) \ ++ UsbCfg.field.RxBulkAggEn = 1; \ ++ UsbCfg.field.RxBulkEn = 1; \ ++ UsbCfg.field.TxBulkEn = 1; \ ++ UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */ \ ++ RTUSBWriteMACRegister(_pAd, USB_DMA_CFG, UsbCfg.word); \ ++ }while(0) ++#endif ++ ++// reset MAC of a station entry to 0xFFFFFFFFFFFF ++#define RT28XX_STA_ENTRY_MAC_RESET(pAd, Wcid) \ ++ { RT_SET_ASIC_WCID SetAsicWcid; \ ++ SetAsicWcid.WCID = Wcid; \ ++ SetAsicWcid.SetTid = 0xffffffff; \ ++ SetAsicWcid.DeleteTid = 0xffffffff; \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_ASIC_WCID, \ ++ &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); } ++ ++// add this entry into ASIC RX WCID search table ++#define RT28XX_STA_ENTRY_ADD(pAd, pEntry) \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_CLIENT_MAC_ENTRY, \ ++ pEntry, sizeof(MAC_TABLE_ENTRY)); ++ ++// remove Pair-wise key material from ASIC ++// yet implement ++#define RT28XX_STA_ENTRY_KEY_DEL(pAd, BssIdx, Wcid) ++ ++// add Client security information into ASIC WCID table and IVEIV table ++#define RT28XX_STA_SECURITY_INFO_ADD(pAd, apidx, KeyID, pEntry) \ ++ { RT28XX_STA_ENTRY_MAC_RESET(pAd, pEntry->Aid); \ ++ if (pEntry->Aid >= 1) { \ ++ RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; \ ++ SetAsicWcidAttri.WCID = pEntry->Aid; \ ++ if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && \ ++ (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) \ ++ { \ ++ SetAsicWcidAttri.Cipher = pAd->SharedKey[apidx][KeyID].CipherAlg; \ ++ } \ ++ else if (pEntry->AuthMode == Ndis802_11AuthModeWPANone) \ ++ { \ ++ SetAsicWcidAttri.Cipher = pAd->SharedKey[apidx][KeyID].CipherAlg; \ ++ } \ ++ else SetAsicWcidAttri.Cipher = 0; \ ++ DBGPRINT(RT_DEBUG_TRACE, ("aid cipher = %ld\n",SetAsicWcidAttri.Cipher)); \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_ASIC_WCID_CIPHER, \ ++ &SetAsicWcidAttri, sizeof(RT_SET_ASIC_WCID_ATTRI)); } } ++ ++// Insert the BA bitmap to ASIC for the Wcid entry ++#define RT28XX_ADD_BA_SESSION_TO_ASIC(_pAd, _Aid, _TID) \ ++ do{ \ ++ RT_SET_ASIC_WCID SetAsicWcid; \ ++ SetAsicWcid.WCID = (_Aid); \ ++ SetAsicWcid.SetTid = (0x10000<<(_TID)); \ ++ SetAsicWcid.DeleteTid = 0xffffffff; \ ++ RTUSBEnqueueInternalCmd((_pAd), CMDTHREAD_SET_ASIC_WCID, &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); \ ++ }while(0) ++ ++// Remove the BA bitmap from ASIC for the Wcid entry ++#define RT28XX_DEL_BA_SESSION_FROM_ASIC(_pAd, _Wcid, _TID) \ ++ do{ \ ++ RT_SET_ASIC_WCID SetAsicWcid; \ ++ SetAsicWcid.WCID = (_Wcid); \ ++ SetAsicWcid.SetTid = (0xffffffff); \ ++ SetAsicWcid.DeleteTid = (0x10000<<(_TID) ); \ ++ RTUSBEnqueueInternalCmd((_pAd), CMDTHREAD_SET_ASIC_WCID, &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); \ ++ }while(0) ++ ++ ++/* ----------------- PCI/USB Related MACRO ----------------- */ ++#define RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p) \ ++ ((POS_COOKIE)handle)->pUsb_Dev = dev_p; ++ ++// no use ++#define RT28XX_UNMAP() ++#define RT28XX_IRQ_REQUEST(net_dev) ++#define RT28XX_IRQ_RELEASE(net_dev) ++#define RT28XX_IRQ_INIT(pAd) ++#define RT28XX_IRQ_ENABLE(pAd) ++ ++ ++/* ----------------- MLME Related MACRO ----------------- */ ++#define RT28XX_MLME_HANDLER(pAd) RTUSBMlmeUp(pAd) ++ ++#define RT28XX_MLME_PRE_SANITY_CHECK(pAd) \ ++ { if ((pAd->CommonCfg.bHardwareRadio == TRUE) && \ ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && \ ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) { \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_CHECK_GPIO, NULL, 0); } } ++ ++#define RT28XX_MLME_STA_QUICK_RSP_WAKE_UP(pAd) \ ++ { RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_QKERIODIC_EXECUT, NULL, 0); \ ++ RTUSBMlmeUp(pAd); } ++ ++#define RT28XX_MLME_RESET_STATE_MACHINE(pAd) \ ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_RESET_CONF, 0, NULL); \ ++ RTUSBMlmeUp(pAd); ++ ++#define RT28XX_HANDLE_COUNTER_MEASURE(_pAd, _pEntry) \ ++ { RTUSBEnqueueInternalCmd(_pAd, CMDTHREAD_802_11_COUNTER_MEASURE, _pEntry, sizeof(MAC_TABLE_ENTRY)); \ ++ RTUSBMlmeUp(_pAd); \ ++ } ++ ++ ++/* ----------------- Power Save Related MACRO ----------------- */ ++#define RT28XX_PS_POLL_ENQUEUE(pAd) \ ++ { RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); \ ++ RTUSBKickBulkOut(pAd); } ++ ++#define RT28xx_CHIP_NAME "RT2870" ++#define USB_CYC_CFG 0x02a4 ++#define STATUS_SUCCESS 0x00 ++#define STATUS_UNSUCCESSFUL 0x01 ++#define NT_SUCCESS(status) (((status) > 0) ? (1):(0)) ++#define InterlockedIncrement atomic_inc ++#define NdisInterlockedIncrement atomic_inc ++#define InterlockedDecrement atomic_dec ++#define NdisInterlockedDecrement atomic_dec ++#define InterlockedExchange atomic_set ++//#define NdisMSendComplete RTMP_SendComplete ++#define NdisMCancelTimer RTMPCancelTimer ++#define NdisAllocMemory(_ptr, _size, _flag) \ ++ do{_ptr = kmalloc((_size),(_flag));}while(0) ++#define NdisFreeMemory(a, b, c) kfree((a)) ++#define NdisMSleep RTMPusecDelay /* unit: microsecond */ ++ ++ ++#define USBD_TRANSFER_DIRECTION_OUT 0 ++#define USBD_TRANSFER_DIRECTION_IN 0 ++#define USBD_SHORT_TRANSFER_OK 0 ++#define PURB purbb_t ++ ++#define RTUSB_FREE_URB(pUrb) usb_free_urb(pUrb) ++ ++//#undef MlmeAllocateMemory ++//#undef MlmeFreeMemory ++ ++typedef int NTSTATUS; ++typedef struct usb_device * PUSB_DEV; ++ ++/* MACRO for linux usb */ ++typedef struct urb *purbb_t; ++typedef struct usb_ctrlrequest devctrlrequest; ++#define PIRP PVOID ++#define PMDL PVOID ++#define NDIS_OID UINT ++#ifndef USB_ST_NOERROR ++#define USB_ST_NOERROR 0 ++#endif ++ ++// vendor-specific control operations ++#define CONTROL_TIMEOUT_JIFFIES ( (100 * HZ) / 1000) ++#define UNLINK_TIMEOUT_MS 3 ++ ++/* unlink urb */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) ++#define RTUSB_UNLINK_URB(pUrb) usb_kill_urb(pUrb) ++#else ++#define RTUSB_UNLINK_URB(pUrb) usb_unlink_urb(pUrb) ++#endif ++ ++// Prototypes of completion funuc. ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++#define RTUSBBulkOutDataPacketComplete(purb, pt_regs) RTUSBBulkOutDataPacketComplete(purb) ++#define RTUSBBulkOutMLMEPacketComplete(pUrb, pt_regs) RTUSBBulkOutMLMEPacketComplete(pUrb) ++#define RTUSBBulkOutNullFrameComplete(pUrb, pt_regs) RTUSBBulkOutNullFrameComplete(pUrb) ++#define RTUSBBulkOutRTSFrameComplete(pUrb, pt_regs) RTUSBBulkOutRTSFrameComplete(pUrb) ++#define RTUSBBulkOutPsPollComplete(pUrb, pt_regs) RTUSBBulkOutPsPollComplete(pUrb) ++#define RTUSBBulkRxComplete(pUrb, pt_regs) RTUSBBulkRxComplete(pUrb) ++#endif ++ ++ ++VOID RTUSBBulkOutDataPacketComplete(purbb_t purb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutRTSFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++ ++ ++#define RTUSBMlmeUp(pAd) \ ++{ \ ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ ++ CHECK_PID_LEGALITY(pObj->MLMEThr_pid) \ ++ up(&(pAd->mlme_semaphore)); \ ++} ++ ++#define RTUSBCMDUp(pAd) \ ++{ \ ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ ++ CHECK_PID_LEGALITY(pObj->RTUSBCmdThr_pid) \ ++ up(&(pAd->RTUSBCmd_semaphore)); \ ++} ++ ++ ++static inline NDIS_STATUS RTMPAllocateMemory( ++ OUT PVOID *ptr, ++ IN size_t size) ++{ ++ *ptr = kmalloc(size, GFP_ATOMIC); ++ if(*ptr) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_RESOURCES; ++} ++ ++/* rtmp.h */ ++#define BEACON_RING_SIZE 2 ++#define DEVICE_VENDOR_REQUEST_OUT 0x40 ++#define DEVICE_VENDOR_REQUEST_IN 0xc0 ++#define INTERFACE_VENDOR_REQUEST_OUT 0x41 ++#define INTERFACE_VENDOR_REQUEST_IN 0xc1 ++#define MGMTPIPEIDX 0 // EP6 is highest priority ++ ++#define BULKOUT_MGMT_RESET_FLAG 0x80 ++ ++#define RTUSB_SET_BULK_FLAG(_M, _F) ((_M)->BulkFlags |= (_F)) ++#define RTUSB_CLEAR_BULK_FLAG(_M, _F) ((_M)->BulkFlags &= ~(_F)) ++#define RTUSB_TEST_BULK_FLAG(_M, _F) (((_M)->BulkFlags & (_F)) != 0) ++ ++#define EnqueueCmd(cmdq, cmdqelmt) \ ++{ \ ++ if (cmdq->size == 0) \ ++ cmdq->head = cmdqelmt; \ ++ else \ ++ cmdq->tail->next = cmdqelmt; \ ++ cmdq->tail = cmdqelmt; \ ++ cmdqelmt->next = NULL; \ ++ cmdq->size++; \ ++} ++ ++typedef struct _RT_SET_ASIC_WCID { ++ ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG SetTid; // time-based: seconds, packet-based: kilo-packets ++ ULONG DeleteTid; // time-based: seconds, packet-based: kilo-packets ++ UCHAR Addr[MAC_ADDR_LEN]; // avoid in interrupt when write key ++} RT_SET_ASIC_WCID,*PRT_SET_ASIC_WCID; ++ ++typedef struct _RT_SET_ASIC_WCID_ATTRI { ++ ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG Cipher; // ASIC Cipher definition ++ UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; ++} RT_SET_ASIC_WCID_ATTRI,*PRT_SET_ASIC_WCID_ATTRI; ++ ++typedef struct _MLME_MEMORY_STRUCT { ++ PVOID AllocVa; //Pointer to the base virtual address of the allocated memory ++ struct _MLME_MEMORY_STRUCT *Next; //Pointer to the next virtual address of the allocated memory ++} MLME_MEMORY_STRUCT, *PMLME_MEMORY_STRUCT; ++ ++typedef struct _MLME_MEMORY_HANDLER { ++ BOOLEAN MemRunning; //The flag of the Mlme memory handler's status ++ UINT MemoryCount; //Total nonpaged system-space memory not size ++ UINT InUseCount; //Nonpaged system-space memory in used counts ++ UINT UnUseCount; //Nonpaged system-space memory available counts ++ INT PendingCount; //Nonpaged system-space memory for free counts ++ PMLME_MEMORY_STRUCT pInUseHead; //Pointer to the first nonpaed memory not used ++ PMLME_MEMORY_STRUCT pInUseTail; //Pointer to the last nonpaged memory not used ++ PMLME_MEMORY_STRUCT pUnUseHead; //Pointer to the first nonpaged memory in used ++ PMLME_MEMORY_STRUCT pUnUseTail; //Pointer to the last nonpaged memory in used ++ PULONG MemFreePending[MAX_MLME_HANDLER_MEMORY]; //an array to keep pending free-memory's pointer (32bits) ++} MLME_MEMORY_HANDLER, *PMLME_MEMORY_HANDLER; ++ ++typedef struct _CmdQElmt { ++ UINT command; ++ PVOID buffer; ++ ULONG bufferlength; ++ BOOLEAN CmdFromNdis; ++ BOOLEAN SetOperation; ++ struct _CmdQElmt *next; ++} CmdQElmt, *PCmdQElmt; ++ ++typedef struct _CmdQ { ++ UINT size; ++ CmdQElmt *head; ++ CmdQElmt *tail; ++ UINT32 CmdQState; ++}CmdQ, *PCmdQ; ++ ++// ++// For WPA SUPPLICANT: WIRELESS EXT support wireless events: v14 or newer ++// ++#if WIRELESS_EXT >= 14 ++//#define WPA_SUPPLICANT_SUPPORT 1 ++#endif ++ ++/* oid.h */ ++// Cipher suite type for mixed mode group cipher, P802.11i-2004 ++typedef enum _RT_802_11_CIPHER_SUITE_TYPE { ++ Cipher_Type_NONE, ++ Cipher_Type_WEP40, ++ Cipher_Type_TKIP, ++ Cipher_Type_RSVD, ++ Cipher_Type_CCMP, ++ Cipher_Type_WEP104 ++} RT_802_11_CIPHER_SUITE_TYPE, *PRT_802_11_CIPHER_SUITE_TYPE; ++ ++//CMDTHREAD_MULTI_READ_MAC ++//CMDTHREAD_MULTI_WRITE_MAC ++//CMDTHREAD_VENDOR_EEPROM_READ ++//CMDTHREAD_VENDOR_EEPROM_WRITE ++typedef struct _CMDHandler_TLV { ++ USHORT Offset; ++ USHORT Length; ++ UCHAR DataFirst; ++} CMDHandler_TLV, *PCMDHandler_TLV; ++ ++// New for MeetingHouse Api support ++#define CMDTHREAD_VENDOR_RESET 0x0D730101 // cmd ++#define CMDTHREAD_VENDOR_UNPLUG 0x0D730102 // cmd ++#define CMDTHREAD_VENDOR_SWITCH_FUNCTION 0x0D730103 // cmd ++#define CMDTHREAD_MULTI_WRITE_MAC 0x0D730107 // cmd ++#define CMDTHREAD_MULTI_READ_MAC 0x0D730108 // cmd ++#define CMDTHREAD_VENDOR_EEPROM_WRITE 0x0D73010A // cmd ++#define CMDTHREAD_VENDOR_EEPROM_READ 0x0D73010B // cmd ++#define CMDTHREAD_VENDOR_ENTER_TESTMODE 0x0D73010C // cmd ++#define CMDTHREAD_VENDOR_EXIT_TESTMODE 0x0D73010D // cmd ++#define CMDTHREAD_VENDOR_WRITE_BBP 0x0D730119 // cmd ++#define CMDTHREAD_VENDOR_READ_BBP 0x0D730118 // cmd ++#define CMDTHREAD_VENDOR_WRITE_RF 0x0D73011A // cmd ++#define CMDTHREAD_VENDOR_FLIP_IQ 0x0D73011D // cmd ++#define CMDTHREAD_RESET_BULK_OUT 0x0D730210 // cmd ++#define CMDTHREAD_RESET_BULK_IN 0x0D730211 // cmd ++#define CMDTHREAD_SET_PSM_BIT_SAVE 0x0D730212 // cmd ++#define CMDTHREAD_SET_RADIO 0x0D730214 // cmd ++#define CMDTHREAD_UPDATE_TX_RATE 0x0D730216 // cmd ++#define CMDTHREAD_802_11_ADD_KEY_WEP 0x0D730218 // cmd ++#define CMDTHREAD_RESET_FROM_ERROR 0x0D73021A // cmd ++#define CMDTHREAD_LINK_DOWN 0x0D73021B // cmd ++#define CMDTHREAD_RESET_FROM_NDIS 0x0D73021C // cmd ++#define CMDTHREAD_CHECK_GPIO 0x0D730215 // cmd ++#define CMDTHREAD_FORCE_WAKE_UP 0x0D730222 // cmd ++#define CMDTHREAD_SET_BW 0x0D730225 // cmd ++#define CMDTHREAD_SET_ASIC_WCID 0x0D730226 // cmd ++#define CMDTHREAD_SET_ASIC_WCID_CIPHER 0x0D730227 // cmd ++#define CMDTHREAD_QKERIODIC_EXECUT 0x0D73023D // cmd ++#define RT_CMD_SET_KEY_TABLE 0x0D730228 // cmd ++#define RT_CMD_SET_RX_WCID_TABLE 0x0D730229 // cmd ++#define CMDTHREAD_SET_CLIENT_MAC_ENTRY 0x0D73023E // cmd ++#define CMDTHREAD_802_11_QUERY_HARDWARE_REGISTER 0x0D710105 // cmd ++#define CMDTHREAD_802_11_SET_PHY_MODE 0x0D79010C // cmd ++#define CMDTHREAD_802_11_SET_STA_CONFIG 0x0D790111 // cmd ++#define CMDTHREAD_802_11_SET_PREAMBLE 0x0D790101 // cmd ++#define CMDTHREAD_802_11_COUNTER_MEASURE 0x0D790102 // cmd ++ ++ ++#define WPA1AKMBIT 0x01 ++#define WPA2AKMBIT 0x02 ++#define WPA1PSKAKMBIT 0x04 ++#define WPA2PSKAKMBIT 0x08 ++#define TKIPBIT 0x01 ++#define CCMPBIT 0x02 ++ ++ ++#define RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx) \ ++ RT28xxUsbStaAsicForceWakeup(pAd, bFromTx); ++ ++#define RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp) \ ++ RT28xxUsbStaAsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ ++#define RT28XX_MLME_RADIO_ON(pAd) \ ++ RT28xxUsbMlmeRadioOn(pAd); ++ ++#define RT28XX_MLME_RADIO_OFF(pAd) \ ++ RT28xxUsbMlmeRadioOFF(pAd); ++ ++#endif //__RT2870_H__ +--- /dev/null ++++ b/drivers/staging/rt2870/rt28xx.h +@@ -0,0 +1,2689 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt28xx.h ++ ++ Abstract: ++ RT28xx ASIC related definition & structures ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee Jan-3-2006 created for RT2860c ++*/ ++ ++#ifndef __RT28XX_H__ ++#define __RT28XX_H__ ++ ++ ++// ++// PCI registers - base address 0x0000 ++// ++#define PCI_CFG 0x0000 ++#define PCI_EECTRL 0x0004 ++#define PCI_MCUCTRL 0x0008 ++ ++// ++// SCH/DMA registers - base address 0x0200 ++// ++// INT_SOURCE_CSR: Interrupt source register. Write one to clear corresponding bit ++// ++#define DMA_CSR0 0x200 ++#define INT_SOURCE_CSR 0x200 ++#ifdef RT_BIG_ENDIAN ++typedef union _INT_SOURCE_CSR_STRUC { ++ struct { ++ UINT32 :14; ++ UINT32 TxCoherent:1; ++ UINT32 RxCoherent:1; ++ UINT32 GPTimer:1; ++ UINT32 AutoWakeup:1;//bit14 ++ UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c ++ UINT32 PreTBTT:1; ++ UINT32 TBTTInt:1; ++ UINT32 RxTxCoherent:1; ++ UINT32 MCUCommandINT:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 RxDone:1; ++ UINT32 TxDelayINT:1; //delayed interrupt, not interrupt until several int or time limit hit ++ UINT32 RxDelayINT:1; //dealyed interrupt ++ } field; ++ UINT32 word; ++} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; ++#else ++typedef union _INT_SOURCE_CSR_STRUC { ++ struct { ++ UINT32 RxDelayINT:1; ++ UINT32 TxDelayINT:1; ++ UINT32 RxDone:1; ++ UINT32 Ac0DmaDone:1;//4 ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 HccaDmaDone:1; // bit7 ++ UINT32 MgmtDmaDone:1; ++ UINT32 MCUCommandINT:1;//bit 9 ++ UINT32 RxTxCoherent:1; ++ UINT32 TBTTInt:1; ++ UINT32 PreTBTT:1; ++ UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c ++ UINT32 AutoWakeup:1;//bit14 ++ UINT32 GPTimer:1; ++ UINT32 RxCoherent:1;//bit16 ++ UINT32 TxCoherent:1; ++ UINT32 :14; ++ } field; ++ UINT32 word; ++} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; ++#endif ++ ++// ++// INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF ++// ++#define INT_MASK_CSR 0x204 ++#ifdef RT_BIG_ENDIAN ++typedef union _INT_MASK_CSR_STRUC { ++ struct { ++ UINT32 TxCoherent:1; ++ UINT32 RxCoherent:1; ++ UINT32 :20; ++ UINT32 MCUCommandINT:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 RxDone:1; ++ UINT32 TxDelay:1; ++ UINT32 RXDelay_INT_MSK:1; ++ } field; ++ UINT32 word; ++}INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; ++#else ++typedef union _INT_MASK_CSR_STRUC { ++ struct { ++ UINT32 RXDelay_INT_MSK:1; ++ UINT32 TxDelay:1; ++ UINT32 RxDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 MCUCommandINT:1; ++ UINT32 :20; ++ UINT32 RxCoherent:1; ++ UINT32 TxCoherent:1; ++ } field; ++ UINT32 word; ++} INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; ++#endif ++#define WPDMA_GLO_CFG 0x208 ++#ifdef RT_BIG_ENDIAN ++typedef union _WPDMA_GLO_CFG_STRUC { ++ struct { ++ UINT32 HDR_SEG_LEN:16; ++ UINT32 RXHdrScater:8; ++ UINT32 BigEndian:1; ++ UINT32 EnTXWriteBackDDONE:1; ++ UINT32 WPDMABurstSIZE:2; ++ UINT32 RxDMABusy:1; ++ UINT32 EnableRxDMA:1; ++ UINT32 TxDMABusy:1; ++ UINT32 EnableTxDMA:1; ++ } field; ++ UINT32 word; ++}WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; ++#else ++typedef union _WPDMA_GLO_CFG_STRUC { ++ struct { ++ UINT32 EnableTxDMA:1; ++ UINT32 TxDMABusy:1; ++ UINT32 EnableRxDMA:1; ++ UINT32 RxDMABusy:1; ++ UINT32 WPDMABurstSIZE:2; ++ UINT32 EnTXWriteBackDDONE:1; ++ UINT32 BigEndian:1; ++ UINT32 RXHdrScater:8; ++ UINT32 HDR_SEG_LEN:16; ++ } field; ++ UINT32 word; ++} WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; ++#endif ++#define WPDMA_RST_IDX 0x20c ++#ifdef RT_BIG_ENDIAN ++typedef union _WPDMA_RST_IDX_STRUC { ++ struct { ++ UINT32 :15; ++ UINT32 RST_DRX_IDX0:1; ++ UINT32 rsv:10; ++ UINT32 RST_DTX_IDX5:1; ++ UINT32 RST_DTX_IDX4:1; ++ UINT32 RST_DTX_IDX3:1; ++ UINT32 RST_DTX_IDX2:1; ++ UINT32 RST_DTX_IDX1:1; ++ UINT32 RST_DTX_IDX0:1; ++ } field; ++ UINT32 word; ++}WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; ++#else ++typedef union _WPDMA_RST_IDX_STRUC { ++ struct { ++ UINT32 RST_DTX_IDX0:1; ++ UINT32 RST_DTX_IDX1:1; ++ UINT32 RST_DTX_IDX2:1; ++ UINT32 RST_DTX_IDX3:1; ++ UINT32 RST_DTX_IDX4:1; ++ UINT32 RST_DTX_IDX5:1; ++ UINT32 rsv:10; ++ UINT32 RST_DRX_IDX0:1; ++ UINT32 :15; ++ } field; ++ UINT32 word; ++} WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; ++#endif ++#define DELAY_INT_CFG 0x0210 ++#ifdef RT_BIG_ENDIAN ++typedef union _DELAY_INT_CFG_STRUC { ++ struct { ++ UINT32 TXDLY_INT_EN:1; ++ UINT32 TXMAX_PINT:7; ++ UINT32 TXMAX_PTIME:8; ++ UINT32 RXDLY_INT_EN:1; ++ UINT32 RXMAX_PINT:7; ++ UINT32 RXMAX_PTIME:8; ++ } field; ++ UINT32 word; ++}DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; ++#else ++typedef union _DELAY_INT_CFG_STRUC { ++ struct { ++ UINT32 RXMAX_PTIME:8; ++ UINT32 RXMAX_PINT:7; ++ UINT32 RXDLY_INT_EN:1; ++ UINT32 TXMAX_PTIME:8; ++ UINT32 TXMAX_PINT:7; ++ UINT32 TXDLY_INT_EN:1; ++ } field; ++ UINT32 word; ++} DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; ++#endif ++#define WMM_AIFSN_CFG 0x0214 ++#ifdef RT_BIG_ENDIAN ++typedef union _AIFSN_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Aifsn3:4; // for AC_VO ++ UINT32 Aifsn2:4; // for AC_VI ++ UINT32 Aifsn1:4; // for AC_BK ++ UINT32 Aifsn0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; ++#else ++typedef union _AIFSN_CSR_STRUC { ++ struct { ++ UINT32 Aifsn0:4; // for AC_BE ++ UINT32 Aifsn1:4; // for AC_BK ++ UINT32 Aifsn2:4; // for AC_VI ++ UINT32 Aifsn3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; ++#endif ++// ++// CWMIN_CSR: CWmin for each EDCA AC ++// ++#define WMM_CWMIN_CFG 0x0218 ++#ifdef RT_BIG_ENDIAN ++typedef union _CWMIN_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Cwmin3:4; // for AC_VO ++ UINT32 Cwmin2:4; // for AC_VI ++ UINT32 Cwmin1:4; // for AC_BK ++ UINT32 Cwmin0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; ++#else ++typedef union _CWMIN_CSR_STRUC { ++ struct { ++ UINT32 Cwmin0:4; // for AC_BE ++ UINT32 Cwmin1:4; // for AC_BK ++ UINT32 Cwmin2:4; // for AC_VI ++ UINT32 Cwmin3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; ++#endif ++ ++// ++// CWMAX_CSR: CWmin for each EDCA AC ++// ++#define WMM_CWMAX_CFG 0x021c ++#ifdef RT_BIG_ENDIAN ++typedef union _CWMAX_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Cwmax3:4; // for AC_VO ++ UINT32 Cwmax2:4; // for AC_VI ++ UINT32 Cwmax1:4; // for AC_BK ++ UINT32 Cwmax0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; ++#else ++typedef union _CWMAX_CSR_STRUC { ++ struct { ++ UINT32 Cwmax0:4; // for AC_BE ++ UINT32 Cwmax1:4; // for AC_BK ++ UINT32 Cwmax2:4; // for AC_VI ++ UINT32 Cwmax3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; ++#endif ++ ++ ++// ++// AC_TXOP_CSR0: AC_BK/AC_BE TXOP register ++// ++#define WMM_TXOP0_CFG 0x0220 ++#ifdef RT_BIG_ENDIAN ++typedef union _AC_TXOP_CSR0_STRUC { ++ struct { ++ USHORT Ac1Txop; // for AC_BE, in unit of 32us ++ USHORT Ac0Txop; // for AC_BK, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; ++#else ++typedef union _AC_TXOP_CSR0_STRUC { ++ struct { ++ USHORT Ac0Txop; // for AC_BK, in unit of 32us ++ USHORT Ac1Txop; // for AC_BE, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; ++#endif ++ ++// ++// AC_TXOP_CSR1: AC_VO/AC_VI TXOP register ++// ++#define WMM_TXOP1_CFG 0x0224 ++#ifdef RT_BIG_ENDIAN ++typedef union _AC_TXOP_CSR1_STRUC { ++ struct { ++ USHORT Ac3Txop; // for AC_VO, in unit of 32us ++ USHORT Ac2Txop; // for AC_VI, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; ++#else ++typedef union _AC_TXOP_CSR1_STRUC { ++ struct { ++ USHORT Ac2Txop; // for AC_VI, in unit of 32us ++ USHORT Ac3Txop; // for AC_VO, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; ++#endif ++#define RINGREG_DIFF 0x10 ++#define GPIO_CTRL_CFG 0x0228 //MAC_CSR13 ++#define MCU_CMD_CFG 0x022c ++#define TX_BASE_PTR0 0x0230 //AC_BK base address ++#define TX_MAX_CNT0 0x0234 ++#define TX_CTX_IDX0 0x0238 ++#define TX_DTX_IDX0 0x023c ++#define TX_BASE_PTR1 0x0240 //AC_BE base address ++#define TX_MAX_CNT1 0x0244 ++#define TX_CTX_IDX1 0x0248 ++#define TX_DTX_IDX1 0x024c ++#define TX_BASE_PTR2 0x0250 //AC_VI base address ++#define TX_MAX_CNT2 0x0254 ++#define TX_CTX_IDX2 0x0258 ++#define TX_DTX_IDX2 0x025c ++#define TX_BASE_PTR3 0x0260 //AC_VO base address ++#define TX_MAX_CNT3 0x0264 ++#define TX_CTX_IDX3 0x0268 ++#define TX_DTX_IDX3 0x026c ++#define TX_BASE_PTR4 0x0270 //HCCA base address ++#define TX_MAX_CNT4 0x0274 ++#define TX_CTX_IDX4 0x0278 ++#define TX_DTX_IDX4 0x027c ++#define TX_BASE_PTR5 0x0280 //MGMT base address ++#define TX_MAX_CNT5 0x0284 ++#define TX_CTX_IDX5 0x0288 ++#define TX_DTX_IDX5 0x028c ++#define TX_MGMTMAX_CNT TX_MAX_CNT5 ++#define TX_MGMTCTX_IDX TX_CTX_IDX5 ++#define TX_MGMTDTX_IDX TX_DTX_IDX5 ++#define RX_BASE_PTR 0x0290 //RX base address ++#define RX_MAX_CNT 0x0294 ++#define RX_CRX_IDX 0x0298 ++#define RX_DRX_IDX 0x029c ++#define USB_DMA_CFG 0x02a0 ++#ifdef RT_BIG_ENDIAN ++typedef union _USB_DMA_CFG_STRUC { ++ struct { ++ UINT32 TxBusy:1; //USB DMA TX FSM busy . debug only ++ UINT32 RxBusy:1; //USB DMA RX FSM busy . debug only ++ UINT32 EpoutValid:6; //OUT endpoint data valid. debug only ++ UINT32 TxBulkEn:1; //Enable USB DMA Tx ++ UINT32 RxBulkEn:1; //Enable USB DMA Rx ++ UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation ++ UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. ++ UINT32 TxClear:1; //Clear USB DMA TX path ++ UINT32 rsv:2; ++ UINT32 phyclear:1; //phy watch dog enable. write 1 ++ UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 1024 bytes ++ UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns ++ } field; ++ UINT32 word; ++} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; ++#else ++typedef union _USB_DMA_CFG_STRUC { ++ struct { ++ UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns ++ UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 256 bytes ++ UINT32 phyclear:1; //phy watch dog enable. write 1 ++ UINT32 rsv:2; ++ UINT32 TxClear:1; //Clear USB DMA TX path ++ UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. ++ UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation ++ UINT32 RxBulkEn:1; //Enable USB DMA Rx ++ UINT32 TxBulkEn:1; //Enable USB DMA Tx ++ UINT32 EpoutValid:6; //OUT endpoint data valid ++ UINT32 RxBusy:1; //USB DMA RX FSM busy ++ UINT32 TxBusy:1; //USB DMA TX FSM busy ++ } field; ++ UINT32 word; ++} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; ++#endif ++ ++// ++// 3 PBF registers ++// ++// ++// Most are for debug. Driver doesn't touch PBF register. ++#define PBF_SYS_CTRL 0x0400 ++#define PBF_CFG 0x0408 ++#define PBF_MAX_PCNT 0x040C ++#define PBF_CTRL 0x0410 ++#define PBF_INT_STA 0x0414 ++#define PBF_INT_ENA 0x0418 ++#define TXRXQ_PCNT 0x0438 ++#define PBF_DBG 0x043c ++#define PBF_CAP_CTRL 0x0440 ++ ++// ++// 4 MAC registers ++// ++// ++// 4.1 MAC SYSTEM configuration registers (offset:0x1000) ++// ++#define MAC_CSR0 0x1000 ++#ifdef RT_BIG_ENDIAN ++typedef union _ASIC_VER_ID_STRUC { ++ struct { ++ USHORT ASICVer; // version : 2860 ++ USHORT ASICRev; // reversion : 0 ++ } field; ++ UINT32 word; ++} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; ++#else ++typedef union _ASIC_VER_ID_STRUC { ++ struct { ++ USHORT ASICRev; // reversion : 0 ++ USHORT ASICVer; // version : 2860 ++ } field; ++ UINT32 word; ++} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; ++#endif ++#define MAC_SYS_CTRL 0x1004 //MAC_CSR1 ++#define MAC_ADDR_DW0 0x1008 // MAC ADDR DW0 ++#define MAC_ADDR_DW1 0x100c // MAC ADDR DW1 ++// ++// MAC_CSR2: STA MAC register 0 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_DW0_STRUC { ++ struct { ++ UCHAR Byte3; // MAC address byte 3 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte0; // MAC address byte 0 ++ } field; ++ UINT32 word; ++} MAC_DW0_STRUC, *PMAC_DW0_STRUC; ++#else ++typedef union _MAC_DW0_STRUC { ++ struct { ++ UCHAR Byte0; // MAC address byte 0 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte3; // MAC address byte 3 ++ } field; ++ UINT32 word; ++} MAC_DW0_STRUC, *PMAC_DW0_STRUC; ++#endif ++ ++// ++// MAC_CSR3: STA MAC register 1 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_DW1_STRUC { ++ struct { ++ UCHAR Rsvd1; ++ UCHAR U2MeMask; ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Byte4; // MAC address byte 4 ++ } field; ++ UINT32 word; ++} MAC_DW1_STRUC, *PMAC_DW1_STRUC; ++#else ++typedef union _MAC_DW1_STRUC { ++ struct { ++ UCHAR Byte4; // MAC address byte 4 ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR U2MeMask; ++ UCHAR Rsvd1; ++ } field; ++ UINT32 word; ++} MAC_DW1_STRUC, *PMAC_DW1_STRUC; ++#endif ++ ++#define MAC_BSSID_DW0 0x1010 // MAC BSSID DW0 ++#define MAC_BSSID_DW1 0x1014 // MAC BSSID DW1 ++ ++// ++// MAC_CSR5: BSSID register 1 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_CSR5_STRUC { ++ struct { ++ USHORT Rsvd:11; ++ USHORT MBssBcnNum:3; ++ USHORT BssIdMode:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID ++ UCHAR Byte5; // BSSID byte 5 ++ UCHAR Byte4; // BSSID byte 4 ++ } field; ++ UINT32 word; ++} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; ++#else ++typedef union _MAC_CSR5_STRUC { ++ struct { ++ UCHAR Byte4; // BSSID byte 4 ++ UCHAR Byte5; // BSSID byte 5 ++ USHORT BssIdMask:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID ++ USHORT MBssBcnNum:3; ++ USHORT Rsvd:11; ++ } field; ++ UINT32 word; ++} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; ++#endif ++ ++#define MAX_LEN_CFG 0x1018 // rt2860b max 16k bytes. bit12:13 Maximum PSDU length (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 ++#define BBP_CSR_CFG 0x101c // ++// ++// BBP_CSR_CFG: BBP serial control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _BBP_CSR_CFG_STRUC { ++ struct { ++ UINT32 :12; ++ UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel ++ UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles ++ UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. ++ UINT32 fRead:1; // 0: Write BBP, 1: Read BBP ++ UINT32 RegNum:8; // Selected BBP register ++ UINT32 Value:8; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; ++#else ++typedef union _BBP_CSR_CFG_STRUC { ++ struct { ++ UINT32 Value:8; // Register value to program into BBP ++ UINT32 RegNum:8; // Selected BBP register ++ UINT32 fRead:1; // 0: Write BBP, 1: Read BBP ++ UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. ++ UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles ++ UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel ++ UINT32 :12; ++ } field; ++ UINT32 word; ++} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; ++#endif ++#define RF_CSR_CFG0 0x1020 ++// ++// RF_CSR_CFG: RF control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG0_STRUC { ++ struct { ++ UINT32 Busy:1; // 0: idle 1: 8busy ++ UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate ++ UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby ++ UINT32 bitwidth:5; // Selected BBP register ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; ++#else ++typedef union _RF_CSR_CFG0_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 bitwidth:5; // Selected BBP register ++ UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby ++ UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate ++ UINT32 Busy:1; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; ++#endif ++#define RF_CSR_CFG1 0x1024 ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG1_STRUC { ++ struct { ++ UINT32 rsv:7; // 0: idle 1: 8busy ++ UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; ++#else ++typedef union _RF_CSR_CFG1_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) ++ UINT32 rsv:7; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; ++#endif ++#define RF_CSR_CFG2 0x1028 // ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG2_STRUC { ++ struct { ++ UINT32 rsv:8; // 0: idle 1: 8busy ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; ++#else ++typedef union _RF_CSR_CFG2_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 rsv:8; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; ++#endif ++#define LED_CFG 0x102c // MAC_CSR14 ++#ifdef RT_BIG_ENDIAN ++typedef union _LED_CFG_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high ++ UINT32 YLedMode:2; // yellow Led Mode ++ UINT32 GLedMode:2; // green Led Mode ++ UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on ++ UINT32 rsv:2; ++ UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms ++ UINT32 OffPeriod:8; // blinking off period unit 1ms ++ UINT32 OnPeriod:8; // blinking on period unit 1ms ++ } field; ++ UINT32 word; ++} LED_CFG_STRUC, *PLED_CFG_STRUC; ++#else ++typedef union _LED_CFG_STRUC { ++ struct { ++ UINT32 OnPeriod:8; // blinking on period unit 1ms ++ UINT32 OffPeriod:8; // blinking off period unit 1ms ++ UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms ++ UINT32 rsv:2; ++ UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on ++ UINT32 GLedMode:2; // green Led Mode ++ UINT32 YLedMode:2; // yellow Led Mode ++ UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} LED_CFG_STRUC, *PLED_CFG_STRUC; ++#endif ++// ++// 4.2 MAC TIMING configuration registers (offset:0x1100) ++// ++#define XIFS_TIME_CFG 0x1100 // MAC_CSR8 MAC_CSR9 ++#ifdef RT_BIG_ENDIAN ++typedef union _IFS_SLOT_CFG_STRUC { ++ struct { ++ UINT32 rsv:2; ++ UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer ++ UINT32 EIFS:9; // unit 1us ++ UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND ++ UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX ++ UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX ++ } field; ++ UINT32 word; ++} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; ++#else ++typedef union _IFS_SLOT_CFG_STRUC { ++ struct { ++ UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX ++ UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX ++ UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND ++ UINT32 EIFS:9; // unit 1us ++ UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer ++ UINT32 rsv:2; ++ } field; ++ UINT32 word; ++} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; ++#endif ++ ++#define BKOFF_SLOT_CFG 0x1104 // mac_csr9 last 8 bits ++#define NAV_TIME_CFG 0x1108 // NAV (MAC_CSR15) ++#define CH_TIME_CFG 0x110C // Count as channel busy ++#define PBF_LIFE_TIMER 0x1110 //TX/RX MPDU timestamp timer (free run)Unit: 1us ++#define BCN_TIME_CFG 0x1114 // TXRX_CSR9 ++ ++#define BCN_OFFSET0 0x042C ++#define BCN_OFFSET1 0x0430 ++ ++// ++// BCN_TIME_CFG : Synchronization control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _BCN_TIME_CFG_STRUC { ++ struct { ++ UINT32 TxTimestampCompensate:8; ++ UINT32 :3; ++ UINT32 bBeaconGen:1; // Enable beacon generator ++ UINT32 bTBTTEnable:1; ++ UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode ++ UINT32 bTsfTicking:1; // Enable TSF auto counting ++ UINT32 BeaconInterval:16; // in unit of 1/16 TU ++ } field; ++ UINT32 word; ++} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; ++#else ++typedef union _BCN_TIME_CFG_STRUC { ++ struct { ++ UINT32 BeaconInterval:16; // in unit of 1/16 TU ++ UINT32 bTsfTicking:1; // Enable TSF auto counting ++ UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode ++ UINT32 bTBTTEnable:1; ++ UINT32 bBeaconGen:1; // Enable beacon generator ++ UINT32 :3; ++ UINT32 TxTimestampCompensate:8; ++ } field; ++ UINT32 word; ++} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; ++#endif ++#define TBTT_SYNC_CFG 0x1118 // txrx_csr10 ++#define TSF_TIMER_DW0 0x111C // Local TSF timer lsb 32 bits. Read-only ++#define TSF_TIMER_DW1 0x1120 // msb 32 bits. Read-only. ++#define TBTT_TIMER 0x1124 // TImer remains till next TBTT. Read-only. TXRX_CSR14 ++#define INT_TIMER_CFG 0x1128 // ++#define INT_TIMER_EN 0x112c // GP-timer and pre-tbtt Int enable ++#define CH_IDLE_STA 0x1130 // channel idle time ++#define CH_BUSY_STA 0x1134 // channle busy time ++// ++// 4.2 MAC POWER configuration registers (offset:0x1200) ++// ++#define MAC_STATUS_CFG 0x1200 // old MAC_CSR12 ++#define PWR_PIN_CFG 0x1204 // old MAC_CSR12 ++#define AUTO_WAKEUP_CFG 0x1208 // old MAC_CSR10 ++// ++// AUTO_WAKEUP_CFG: Manual power control / status register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _AUTO_WAKEUP_STRUC { ++ struct { ++ UINT32 :16; ++ UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake ++ UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set ++ UINT32 AutoLeadTime:8; ++ } field; ++ UINT32 word; ++} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; ++#else ++typedef union _AUTO_WAKEUP_STRUC { ++ struct { ++ UINT32 AutoLeadTime:8; ++ UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set ++ UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake ++ UINT32 :16; ++ } field; ++ UINT32 word; ++} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; ++#endif ++// ++// 4.3 MAC TX configuration registers (offset:0x1300) ++// ++ ++#define EDCA_AC0_CFG 0x1300 //AC_TXOP_CSR0 0x3474 ++#define EDCA_AC1_CFG 0x1304 ++#define EDCA_AC2_CFG 0x1308 ++#define EDCA_AC3_CFG 0x130c ++#ifdef RT_BIG_ENDIAN ++typedef union _EDCA_AC_CFG_STRUC { ++ struct { ++ UINT32 :12; // ++ UINT32 Cwmax:4; //unit power of 2 ++ UINT32 Cwmin:4; // ++ UINT32 Aifsn:4; // # of slot time ++ UINT32 AcTxop:8; // in unit of 32us ++ } field; ++ UINT32 word; ++} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; ++#else ++typedef union _EDCA_AC_CFG_STRUC { ++ struct { ++ UINT32 AcTxop:8; // in unit of 32us ++ UINT32 Aifsn:4; // # of slot time ++ UINT32 Cwmin:4; // ++ UINT32 Cwmax:4; //unit power of 2 ++ UINT32 :12; // ++ } field; ++ UINT32 word; ++} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; ++#endif ++ ++#define EDCA_TID_AC_MAP 0x1310 ++#define TX_PWR_CFG_0 0x1314 ++#define TX_PWR_CFG_1 0x1318 ++#define TX_PWR_CFG_2 0x131C ++#define TX_PWR_CFG_3 0x1320 ++#define TX_PWR_CFG_4 0x1324 ++#define TX_PIN_CFG 0x1328 ++#define TX_BAND_CFG 0x132c // 0x1 use upper 20MHz. 0 juse lower 20MHz ++#define TX_SW_CFG0 0x1330 ++#define TX_SW_CFG1 0x1334 ++#define TX_SW_CFG2 0x1338 ++#define TXOP_THRES_CFG 0x133c ++#define TXOP_CTRL_CFG 0x1340 ++#define TX_RTS_CFG 0x1344 ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_RTS_CFG_STRUC { ++ struct { ++ UINT32 rsv:7; ++ UINT32 RtsFbkEn:1; // enable rts rate fallback ++ UINT32 RtsThres:16; // unit:byte ++ UINT32 AutoRtsRetryLimit:8; ++ } field; ++ UINT32 word; ++} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; ++#else ++typedef union _TX_RTS_CFG_STRUC { ++ struct { ++ UINT32 AutoRtsRetryLimit:8; ++ UINT32 RtsThres:16; // unit:byte ++ UINT32 RtsFbkEn:1; // enable rts rate fallback ++ UINT32 rsv:7; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; ++#endif ++#define TX_TIMEOUT_CFG 0x1348 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_TIMEOUT_CFG_STRUC { ++ struct { ++ UINT32 rsv2:8; ++ UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) ++ UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure ++ UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us ++ UINT32 rsv:4; ++ } field; ++ UINT32 word; ++} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; ++#else ++typedef union _TX_TIMEOUT_CFG_STRUC { ++ struct { ++ UINT32 rsv:4; ++ UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us ++ UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure ++ UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) ++ UINT32 rsv2:8; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; ++#endif ++#define TX_RTY_CFG 0x134c ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_RTY_CFG_STRUC { ++ struct { ++ UINT32 rsv:1; ++ UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable ++ UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 LongRtyThre:12; // Long retry threshoold ++ UINT32 LongRtyLimit:8; //long retry limit ++ UINT32 ShortRtyLimit:8; // short retry limit ++ ++ } field; ++ UINT32 word; ++} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; ++#else ++typedef union PACKED _TX_RTY_CFG_STRUC { ++ struct { ++ UINT32 ShortRtyLimit:8; // short retry limit ++ UINT32 LongRtyLimit:8; //long retry limit ++ UINT32 LongRtyThre:12; // Long retry threshoold ++ UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable ++ UINT32 rsv:1; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; ++#endif ++#define TX_LINK_CFG 0x1350 ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_LINK_CFG_STRUC { ++ struct PACKED { ++ UINT32 RemotMFS:8; //remote MCS feedback sequence number ++ UINT32 RemotMFB:8; // remote MCS feedback ++ UINT32 rsv:3; // ++ UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable ++ UINT32 TxRDGEn:1; // RDG TX enable ++ UINT32 TxMRQEn:1; // MCS request TX enable ++ UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) ++ UINT32 MFBEnable:1; // TX apply remote MFB 1:enable ++ UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us ++ } field; ++ UINT32 word; ++} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; ++#else ++typedef union PACKED _TX_LINK_CFG_STRUC { ++ struct PACKED { ++ UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us ++ UINT32 MFBEnable:1; // TX apply remote MFB 1:enable ++ UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) ++ UINT32 TxMRQEn:1; // MCS request TX enable ++ UINT32 TxRDGEn:1; // RDG TX enable ++ UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable ++ UINT32 rsv:3; // ++ UINT32 RemotMFB:8; // remote MCS feedback ++ UINT32 RemotMFS:8; //remote MCS feedback sequence number ++ } field; ++ UINT32 word; ++} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; ++#endif ++#define HT_FBK_CFG0 0x1354 ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _HT_FBK_CFG0_STRUC { ++ struct { ++ UINT32 HTMCS7FBK:4; ++ UINT32 HTMCS6FBK:4; ++ UINT32 HTMCS5FBK:4; ++ UINT32 HTMCS4FBK:4; ++ UINT32 HTMCS3FBK:4; ++ UINT32 HTMCS2FBK:4; ++ UINT32 HTMCS1FBK:4; ++ UINT32 HTMCS0FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; ++#else ++typedef union PACKED _HT_FBK_CFG0_STRUC { ++ struct { ++ UINT32 HTMCS0FBK:4; ++ UINT32 HTMCS1FBK:4; ++ UINT32 HTMCS2FBK:4; ++ UINT32 HTMCS3FBK:4; ++ UINT32 HTMCS4FBK:4; ++ UINT32 HTMCS5FBK:4; ++ UINT32 HTMCS6FBK:4; ++ UINT32 HTMCS7FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; ++#endif ++#define HT_FBK_CFG1 0x1358 ++#ifdef RT_BIG_ENDIAN ++typedef union _HT_FBK_CFG1_STRUC { ++ struct { ++ UINT32 HTMCS15FBK:4; ++ UINT32 HTMCS14FBK:4; ++ UINT32 HTMCS13FBK:4; ++ UINT32 HTMCS12FBK:4; ++ UINT32 HTMCS11FBK:4; ++ UINT32 HTMCS10FBK:4; ++ UINT32 HTMCS9FBK:4; ++ UINT32 HTMCS8FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; ++#else ++typedef union _HT_FBK_CFG1_STRUC { ++ struct { ++ UINT32 HTMCS8FBK:4; ++ UINT32 HTMCS9FBK:4; ++ UINT32 HTMCS10FBK:4; ++ UINT32 HTMCS11FBK:4; ++ UINT32 HTMCS12FBK:4; ++ UINT32 HTMCS13FBK:4; ++ UINT32 HTMCS14FBK:4; ++ UINT32 HTMCS15FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; ++#endif ++#define LG_FBK_CFG0 0x135c ++#ifdef RT_BIG_ENDIAN ++typedef union _LG_FBK_CFG0_STRUC { ++ struct { ++ UINT32 OFDMMCS7FBK:4; //initial value is 6 ++ UINT32 OFDMMCS6FBK:4; //initial value is 5 ++ UINT32 OFDMMCS5FBK:4; //initial value is 4 ++ UINT32 OFDMMCS4FBK:4; //initial value is 3 ++ UINT32 OFDMMCS3FBK:4; //initial value is 2 ++ UINT32 OFDMMCS2FBK:4; //initial value is 1 ++ UINT32 OFDMMCS1FBK:4; //initial value is 0 ++ UINT32 OFDMMCS0FBK:4; //initial value is 0 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; ++#else ++typedef union _LG_FBK_CFG0_STRUC { ++ struct { ++ UINT32 OFDMMCS0FBK:4; //initial value is 0 ++ UINT32 OFDMMCS1FBK:4; //initial value is 0 ++ UINT32 OFDMMCS2FBK:4; //initial value is 1 ++ UINT32 OFDMMCS3FBK:4; //initial value is 2 ++ UINT32 OFDMMCS4FBK:4; //initial value is 3 ++ UINT32 OFDMMCS5FBK:4; //initial value is 4 ++ UINT32 OFDMMCS6FBK:4; //initial value is 5 ++ UINT32 OFDMMCS7FBK:4; //initial value is 6 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; ++#endif ++#define LG_FBK_CFG1 0x1360 ++#ifdef RT_BIG_ENDIAN ++typedef union _LG_FBK_CFG1_STRUC { ++ struct { ++ UINT32 rsv:16; ++ UINT32 CCKMCS3FBK:4; //initial value is 2 ++ UINT32 CCKMCS2FBK:4; //initial value is 1 ++ UINT32 CCKMCS1FBK:4; //initial value is 0 ++ UINT32 CCKMCS0FBK:4; //initial value is 0 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; ++#else ++typedef union _LG_FBK_CFG1_STRUC { ++ struct { ++ UINT32 CCKMCS0FBK:4; //initial value is 0 ++ UINT32 CCKMCS1FBK:4; //initial value is 0 ++ UINT32 CCKMCS2FBK:4; //initial value is 1 ++ UINT32 CCKMCS3FBK:4; //initial value is 2 ++ UINT32 rsv:16; ++ } field; ++ UINT32 word; ++} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; ++#endif ++ ++//======================================================= ++//================ Protection Paramater================================ ++//======================================================= ++#define CCK_PROT_CFG 0x1364 //CCK Protection ++#define ASIC_SHORTNAV 1 ++#define ASIC_LONGNAV 2 ++#define ASIC_RTS 1 ++#define ASIC_CTS 2 ++#ifdef RT_BIG_ENDIAN ++typedef union _PROT_CFG_STRUC { ++ struct { ++ UINT32 rsv:5; ++ UINT32 RTSThEn:1; //RTS threshold enable on CCK TX ++ UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. ++ UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. ++ UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv ++ UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv ++ UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). ++ } field; ++ UINT32 word; ++} PROT_CFG_STRUC, *PPROT_CFG_STRUC; ++#else ++typedef union _PROT_CFG_STRUC { ++ struct { ++ UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). ++ UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv ++ UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv ++ UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. ++ UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 RTSThEn:1; //RTS threshold enable on CCK TX ++ UINT32 rsv:5; ++ } field; ++ UINT32 word; ++} PROT_CFG_STRUC, *PPROT_CFG_STRUC; ++#endif ++ ++#define OFDM_PROT_CFG 0x1368 //OFDM Protection ++#define MM20_PROT_CFG 0x136C //MM20 Protection ++#define MM40_PROT_CFG 0x1370 //MM40 Protection ++#define GF20_PROT_CFG 0x1374 //GF20 Protection ++#define GF40_PROT_CFG 0x1378 //GR40 Protection ++#define EXP_CTS_TIME 0x137C // ++#define EXP_ACK_TIME 0x1380 // ++ ++// ++// 4.4 MAC RX configuration registers (offset:0x1400) ++// ++#define RX_FILTR_CFG 0x1400 //TXRX_CSR0 ++#define AUTO_RSP_CFG 0x1404 //TXRX_CSR4 ++// ++// TXRX_CSR4: Auto-Responder/ ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _AUTO_RSP_CFG_STRUC { ++ struct { ++ UINT32 :24; ++ UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame ++ UINT32 DualCTSEn:1; // Power bit value in conrtrol frame ++ UINT32 rsv:1; // Power bit value in conrtrol frame ++ UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble ++ UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode ++ UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode ++ UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble ++ UINT32 AutoResponderEnable:1; ++ } field; ++ UINT32 word; ++} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; ++#else ++typedef union _AUTO_RSP_CFG_STRUC { ++ struct { ++ UINT32 AutoResponderEnable:1; ++ UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble ++ UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode ++ UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode ++ UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble ++ UINT32 rsv:1; // Power bit value in conrtrol frame ++ UINT32 DualCTSEn:1; // Power bit value in conrtrol frame ++ UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame ++ UINT32 :24; ++ } field; ++ UINT32 word; ++} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; ++#endif ++ ++#define LEGACY_BASIC_RATE 0x1408 // TXRX_CSR5 0x3054 ++#define HT_BASIC_RATE 0x140c ++#define HT_CTRL_CFG 0x1410 ++#define SIFS_COST_CFG 0x1414 ++#define RX_PARSER_CFG 0x1418 //Set NAV for all received frames ++ ++// ++// 4.5 MAC Security configuration (offset:0x1500) ++// ++#define TX_SEC_CNT0 0x1500 // ++#define RX_SEC_CNT0 0x1504 // ++#define CCMP_FC_MUTE 0x1508 // ++// ++// 4.6 HCCA/PSMP (offset:0x1600) ++// ++#define TXOP_HLDR_ADDR0 0x1600 ++#define TXOP_HLDR_ADDR1 0x1604 ++#define TXOP_HLDR_ET 0x1608 ++#define QOS_CFPOLL_RA_DW0 0x160c ++#define QOS_CFPOLL_A1_DW1 0x1610 ++#define QOS_CFPOLL_QC 0x1614 ++// ++// 4.7 MAC Statistis registers (offset:0x1700) ++// ++#define RX_STA_CNT0 0x1700 // ++#define RX_STA_CNT1 0x1704 // ++#define RX_STA_CNT2 0x1708 // ++ ++// ++// RX_STA_CNT0_STRUC: RX PLCP error count & RX CRC error count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT0_STRUC { ++ struct { ++ USHORT PhyErr; ++ USHORT CrcErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; ++#else ++typedef union _RX_STA_CNT0_STRUC { ++ struct { ++ USHORT CrcErr; ++ USHORT PhyErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; ++#endif ++ ++// ++// RX_STA_CNT1_STRUC: RX False CCA count & RX LONG frame count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT1_STRUC { ++ struct { ++ USHORT PlcpErr; ++ USHORT FalseCca; ++ } field; ++ UINT32 word; ++} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; ++#else ++typedef union _RX_STA_CNT1_STRUC { ++ struct { ++ USHORT FalseCca; ++ USHORT PlcpErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; ++#endif ++ ++// ++// RX_STA_CNT2_STRUC: ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT2_STRUC { ++ struct { ++ USHORT RxFifoOverflowCount; ++ USHORT RxDupliCount; ++ } field; ++ UINT32 word; ++} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; ++#else ++typedef union _RX_STA_CNT2_STRUC { ++ struct { ++ USHORT RxDupliCount; ++ USHORT RxFifoOverflowCount; ++ } field; ++ UINT32 word; ++} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; ++#endif ++#define TX_STA_CNT0 0x170C // ++// ++// STA_CSR3: TX Beacon count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT0_STRUC { ++ struct { ++ USHORT TxBeaconCount; ++ USHORT TxFailCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; ++#else ++typedef union _TX_STA_CNT0_STRUC { ++ struct { ++ USHORT TxFailCount; ++ USHORT TxBeaconCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; ++#endif ++#define TX_STA_CNT1 0x1710 // ++// ++// TX_STA_CNT1: TX tx count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT1_STRUC { ++ struct { ++ USHORT TxRetransmit; ++ USHORT TxSuccess; ++ } field; ++ UINT32 word; ++} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; ++#else ++typedef union _TX_STA_CNT1_STRUC { ++ struct { ++ USHORT TxSuccess; ++ USHORT TxRetransmit; ++ } field; ++ UINT32 word; ++} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; ++#endif ++#define TX_STA_CNT2 0x1714 // ++// ++// TX_STA_CNT2: TX tx count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT2_STRUC { ++ struct { ++ USHORT TxUnderFlowCount; ++ USHORT TxZeroLenCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; ++#else ++typedef union _TX_STA_CNT2_STRUC { ++ struct { ++ USHORT TxZeroLenCount; ++ USHORT TxUnderFlowCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; ++#endif ++#define TX_STA_FIFO 0x1718 // ++// ++// TX_STA_FIFO_STRUC: TX Result for specific PID status fifo register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_STA_FIFO_STRUC { ++ struct { ++ UINT32 Reserve:2; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 wcid:8; //wireless client index ++ UINT32 TxAckRequired:1; // ack required ++ UINT32 TxAggre:1; // Tx is aggregated ++ UINT32 TxSuccess:1; // Tx success. whether success or not ++ UINT32 PidType:4; ++ UINT32 bValid:1; // 1:This register contains a valid TX result ++ } field; ++ UINT32 word; ++} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; ++#else ++typedef union PACKED _TX_STA_FIFO_STRUC { ++ struct { ++ UINT32 bValid:1; // 1:This register contains a valid TX result ++ UINT32 PidType:4; ++ UINT32 TxSuccess:1; // Tx No retry success ++ UINT32 TxAggre:1; // Tx Retry Success ++ UINT32 TxAckRequired:1; // Tx fail ++ UINT32 wcid:8; //wireless client index ++// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 TxBF:1; ++ UINT32 Reserve:2; ++ } field; ++ UINT32 word; ++} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT 0x171c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT_STRUC { ++ struct { ++ USHORT AggTxCount; ++ USHORT NonAggTxCount; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; ++#else ++typedef union _TX_AGG_CNT_STRUC { ++ struct { ++ USHORT NonAggTxCount; ++ USHORT AggTxCount; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT0 0x1720 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT0_STRUC { ++ struct { ++ USHORT AggSize2Count; ++ USHORT AggSize1Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; ++#else ++typedef union _TX_AGG_CNT0_STRUC { ++ struct { ++ USHORT AggSize1Count; ++ USHORT AggSize2Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT1 0x1724 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT1_STRUC { ++ struct { ++ USHORT AggSize4Count; ++ USHORT AggSize3Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; ++#else ++typedef union _TX_AGG_CNT1_STRUC { ++ struct { ++ USHORT AggSize3Count; ++ USHORT AggSize4Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; ++#endif ++#define TX_AGG_CNT2 0x1728 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT2_STRUC { ++ struct { ++ USHORT AggSize6Count; ++ USHORT AggSize5Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; ++#else ++typedef union _TX_AGG_CNT2_STRUC { ++ struct { ++ USHORT AggSize5Count; ++ USHORT AggSize6Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT3 0x172c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT3_STRUC { ++ struct { ++ USHORT AggSize8Count; ++ USHORT AggSize7Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; ++#else ++typedef union _TX_AGG_CNT3_STRUC { ++ struct { ++ USHORT AggSize7Count; ++ USHORT AggSize8Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT4 0x1730 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT4_STRUC { ++ struct { ++ USHORT AggSize10Count; ++ USHORT AggSize9Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; ++#else ++typedef union _TX_AGG_CNT4_STRUC { ++ struct { ++ USHORT AggSize9Count; ++ USHORT AggSize10Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; ++#endif ++#define TX_AGG_CNT5 0x1734 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT5_STRUC { ++ struct { ++ USHORT AggSize12Count; ++ USHORT AggSize11Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; ++#else ++typedef union _TX_AGG_CNT5_STRUC { ++ struct { ++ USHORT AggSize11Count; ++ USHORT AggSize12Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; ++#endif ++#define TX_AGG_CNT6 0x1738 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT6_STRUC { ++ struct { ++ USHORT AggSize14Count; ++ USHORT AggSize13Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; ++#else ++typedef union _TX_AGG_CNT6_STRUC { ++ struct { ++ USHORT AggSize13Count; ++ USHORT AggSize14Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; ++#endif ++#define TX_AGG_CNT7 0x173c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT7_STRUC { ++ struct { ++ USHORT AggSize16Count; ++ USHORT AggSize15Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; ++#else ++typedef union _TX_AGG_CNT7_STRUC { ++ struct { ++ USHORT AggSize15Count; ++ USHORT AggSize16Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; ++#endif ++#define MPDU_DENSITY_CNT 0x1740 ++#ifdef RT_BIG_ENDIAN ++typedef union _MPDU_DEN_CNT_STRUC { ++ struct { ++ USHORT RXZeroDelCount; //RX zero length delimiter count ++ USHORT TXZeroDelCount; //TX zero length delimiter count ++ } field; ++ UINT32 word; ++} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; ++#else ++typedef union _MPDU_DEN_CNT_STRUC { ++ struct { ++ USHORT TXZeroDelCount; //TX zero length delimiter count ++ USHORT RXZeroDelCount; //RX zero length delimiter count ++ } field; ++ UINT32 word; ++} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; ++#endif ++// ++// TXRX control registers - base address 0x3000 ++// ++// rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. ++#define TXRX_CSR1 0x77d0 ++ ++// ++// Security key table memory, base address = 0x1000 ++// ++#define MAC_WCID_BASE 0x1800 //8-bytes(use only 6-bytes) * 256 entry = ++#define HW_WCID_ENTRY_SIZE 8 ++#define PAIRWISE_KEY_TABLE_BASE 0x4000 // 32-byte * 256-entry = -byte ++#define HW_KEY_ENTRY_SIZE 0x20 ++#define PAIRWISE_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte ++#define MAC_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte ++#define HW_IVEIV_ENTRY_SIZE 8 ++#define MAC_WCID_ATTRIBUTE_BASE 0x6800 // 4-byte * 256-entry = -byte ++#define HW_WCID_ATTRI_SIZE 4 ++#define WCID_RESERVED 0x6bfc ++#define SHARED_KEY_TABLE_BASE 0x6c00 // 32-byte * 16-entry = 512-byte ++#define SHARED_KEY_MODE_BASE 0x7000 // 32-byte * 16-entry = 512-byte ++#define HW_SHARED_KEY_MODE_SIZE 4 ++#define SHAREDKEYTABLE 0 ++#define PAIRWISEKEYTABLE 1 ++ ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _SHAREDKEY_MODE_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 Bss1Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key0CipherAlg:3; ++ } field; ++ UINT32 word; ++} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; ++#else ++typedef union _SHAREDKEY_MODE_STRUC { ++ struct { ++ UINT32 Bss0Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key3CipherAlg:3; ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; ++#endif ++// 64-entry for pairwise key table ++typedef struct _HW_WCID_ENTRY { // 8-byte per entry ++ UCHAR Address[6]; ++ UCHAR Rsv[2]; ++} HW_WCID_ENTRY, PHW_WCID_ENTRY; ++ ++ ++ ++// ++// Other on-chip shared memory space, base = 0x2000 ++// ++ ++// CIS space - base address = 0x2000 ++#define HW_CIS_BASE 0x2000 ++ ++// Carrier-sense CTS frame base address. It's where mac stores carrier-sense frame for carrier-sense function. ++#define HW_CS_CTS_BASE 0x7700 ++// DFS CTS frame base address. It's where mac stores CTS frame for DFS. ++#define HW_DFS_CTS_BASE 0x7780 ++#define HW_CTS_FRAME_SIZE 0x80 ++ ++// 2004-11-08 john - since NULL frame won't be that long (256 byte). We steal 16 tail bytes ++// to save debugging settings ++#define HW_DEBUG_SETTING_BASE 0x77f0 // 0x77f0~0x77ff total 16 bytes ++#define HW_DEBUG_SETTING_BASE2 0x7770 // 0x77f0~0x77ff total 16 bytes ++ ++#if 0 ++// on-chip BEACON frame space - base address = 0x7800 ++#define HW_BEACON_MAX_SIZE 0x0800 /* unit: byte */ ++#define HW_BEACON_BASE0 0x7800 ++#define HW_BEACON_BASE1 0x7900 ++#define HW_BEACON_BASE2 0x7a00 ++#define HW_BEACON_BASE3 0x7b00 ++#define HW_BEACON_BASE4 0x7c00 ++#define HW_BEACON_BASE5 0x7d00 ++#define HW_BEACON_BASE6 0x7e00 ++#define HW_BEACON_BASE7 0x7f00 ++/* 1. HW_BEACON_OFFSET/64B must be 0; ++ 2. BCN_OFFSET0 must also be changed in NICInitializeAsic(); ++ 3. max 0x0800 for 8 beacon frames; */ ++#else ++// In order to support maximum 8 MBSS and its maximum length is 512 for each beacon ++// Three section discontinue memory segments will be used. ++// 1. The original region for BCN 0~3 ++// 2. Extract memory from FCE table for BCN 4~5 ++// 3. Extract memory from Pair-wise key table for BCN 6~7 ++// It occupied those memory of wcid 238~253 for BCN 6 ++// and wcid 222~237 for BCN 7 ++#define HW_BEACON_MAX_SIZE 0x1000 /* unit: byte */ ++#define HW_BEACON_BASE0 0x7800 ++#define HW_BEACON_BASE1 0x7A00 ++#define HW_BEACON_BASE2 0x7C00 ++#define HW_BEACON_BASE3 0x7E00 ++#define HW_BEACON_BASE4 0x7200 ++#define HW_BEACON_BASE5 0x7400 ++#define HW_BEACON_BASE6 0x5DC0 ++#define HW_BEACON_BASE7 0x5BC0 ++#endif ++ ++#define HW_BEACON_MAX_COUNT 8 ++#define HW_BEACON_OFFSET 0x0200 ++#define HW_BEACON_CONTENT_LEN (HW_BEACON_OFFSET - TXWI_SIZE) ++ ++// HOST-MCU shared memory - base address = 0x2100 ++#define HOST_CMD_CSR 0x404 ++#define H2M_MAILBOX_CSR 0x7010 ++#define H2M_MAILBOX_CID 0x7014 ++#define H2M_MAILBOX_STATUS 0x701c ++#define H2M_INT_SRC 0x7024 ++#define H2M_BBP_AGENT 0x7028 ++#define M2H_CMD_DONE_CSR 0x000c ++#define MCU_TXOP_ARRAY_BASE 0x000c // TODO: to be provided by Albert ++#define MCU_TXOP_ENTRY_SIZE 32 // TODO: to be provided by Albert ++#define MAX_NUM_OF_TXOP_ENTRY 16 // TODO: must be same with 8051 firmware ++#define MCU_MBOX_VERSION 0x01 // TODO: to be confirmed by Albert ++#define MCU_MBOX_VERSION_OFFSET 5 // TODO: to be provided by Albert ++ ++// ++// Host DMA registers - base address 0x200 . TX0-3=EDCAQid0-3, TX4=HCCA, TX5=MGMT, ++// ++// ++// DMA RING DESCRIPTOR ++// ++#define E2PROM_CSR 0x0004 ++#define IO_CNTL_CSR 0x77d0 ++ ++#ifdef RT2870 ++// 8051 firmware image for usb - use last-half base address = 0x3000 ++#define FIRMWARE_IMAGE_BASE 0x3000 ++#define MAX_FIRMWARE_IMAGE_SIZE 0x1000 // 4kbyte ++#endif // RT2870 // ++ ++// TODO: ????? old RT2560 registers. to keep them or remove them? ++//#define MCAST0 0x0178 // multicast filter register 0 ++//#define MCAST1 0x017c // multicast filter register 1 ++ ++ ++// ================================================================ ++// Tx / Rx / Mgmt ring descriptor definition ++// ================================================================ ++ ++// the following PID values are used to mark outgoing frame type in TXD->PID so that ++// proper TX statistics can be collected based on these categories ++// b3-2 of PID field - ++#define PID_MGMT 0x05 ++#define PID_BEACON 0x0c ++#define PID_DATA_NORMALUCAST 0x02 ++#define PID_DATA_AMPDU 0x04 ++#define PID_DATA_NO_ACK 0x08 ++#define PID_DATA_NOT_NORM_ACK 0x03 ++#if 0 ++#define PTYPE_DATA_REQUIRE_ACK 0x00 // b7-6:00, b5-0: 0~59 is MAC table index (AID?), 60~63 is WDS index ++#define PTYPE_NULL_AT_HIGH_RATE 0x04 // b7-6:01, b5-0: 0~59 is MAC table index (AID?), 60~63 is WDS index ++#define PTYPE_RESERVED 0x08 // b7-6:10 ++#define PTYPE_SPECIAL 0x0c // b7-6:11 ++ ++// when b3-2=11 (PTYPE_SPECIAL), b1-0 coube be ... ++#define PSUBTYPE_DATA_NO_ACK 0x00 ++#define PSUBTYPE_MGMT 0x01 ++#define PSUBTYPE_OTHER_CNTL 0x02 ++#define PSUBTYPE_RTS 0x03 ++#endif ++// value domain of pTxD->HostQId (4-bit: 0~15) ++#define QID_AC_BK 1 // meet ACI definition in 802.11e ++#define QID_AC_BE 0 // meet ACI definition in 802.11e ++#define QID_AC_VI 2 ++#define QID_AC_VO 3 ++#define QID_HCCA 4 ++#define NUM_OF_TX_RING 5 ++#define QID_MGMT 13 ++#define QID_RX 14 ++#define QID_OTHER 15 ++ ++ ++// ------------------------------------------------------ ++// BBP & RF definition ++// ------------------------------------------------------ ++#define BUSY 1 ++#define IDLE 0 ++ ++#define RF_R00 0 ++#define RF_R01 1 ++#define RF_R02 2 ++#define RF_R03 3 ++#define RF_R04 4 ++#define RF_R05 5 ++#define RF_R06 6 ++#define RF_R07 7 ++#define RF_R08 8 ++#define RF_R09 9 ++#define RF_R10 10 ++#define RF_R11 11 ++#define RF_R12 12 ++#define RF_R13 13 ++#define RF_R14 14 ++#define RF_R15 15 ++#define RF_R16 16 ++#define RF_R17 17 ++#define RF_R18 18 ++#define RF_R19 19 ++#define RF_R20 20 ++#define RF_R21 21 ++#define RF_R22 22 ++#define RF_R23 23 ++#define RF_R24 24 ++#define RF_R25 25 ++#define RF_R26 26 ++#define RF_R27 27 ++#define RF_R28 28 ++#define RF_R29 29 ++#define RF_R30 30 ++#define RF_R31 31 ++ ++#define BBP_R0 0 // version ++#define BBP_R1 1 // TSSI ++#define BBP_R2 2 // TX configure ++#define BBP_R3 3 ++#define BBP_R4 4 ++#define BBP_R5 5 ++#define BBP_R6 6 ++#define BBP_R14 14 // RX configure ++#define BBP_R16 16 ++#define BBP_R17 17 // RX sensibility ++#define BBP_R18 18 ++#define BBP_R21 21 ++#define BBP_R22 22 ++#define BBP_R24 24 ++#define BBP_R25 25 ++#define BBP_R49 49 //TSSI ++#define BBP_R50 50 ++#define BBP_R51 51 ++#define BBP_R52 52 ++#define BBP_R55 55 ++#define BBP_R62 62 // Rx SQ0 Threshold HIGH ++#define BBP_R63 63 ++#define BBP_R64 64 ++#define BBP_R65 65 ++#define BBP_R66 66 ++#define BBP_R67 67 ++#define BBP_R68 68 ++#define BBP_R69 69 ++#define BBP_R70 70 // Rx AGC SQ CCK Xcorr threshold ++#define BBP_R73 73 ++#define BBP_R75 75 ++#define BBP_R77 77 ++#define BBP_R81 81 ++#define BBP_R82 82 ++#define BBP_R83 83 ++#define BBP_R84 84 ++#define BBP_R86 86 ++#define BBP_R91 91 ++#define BBP_R92 92 ++#define BBP_R94 94 // Tx Gain Control ++#define BBP_R103 103 ++#define BBP_R105 105 ++#define BBP_R113 113 ++#define BBP_R114 114 ++#define BBP_R115 115 ++#define BBP_R116 116 ++#define BBP_R117 117 ++#define BBP_R118 118 ++#define BBP_R119 119 ++#define BBP_R120 120 ++#define BBP_R121 121 ++#define BBP_R122 122 ++#define BBP_R123 123 ++ ++ ++#define BBPR94_DEFAULT 0x06 // Add 1 value will gain 1db ++ ++//#define PHY_TR_SWITCH_TIME 5 // usec ++ ++//#define BBP_R17_LOW_SENSIBILITY 0x50 ++//#define BBP_R17_MID_SENSIBILITY 0x41 ++//#define BBP_R17_DYNAMIC_UP_BOUND 0x40 ++#define RSSI_FOR_VERY_LOW_SENSIBILITY -35 ++#define RSSI_FOR_LOW_SENSIBILITY -58 ++#define RSSI_FOR_MID_LOW_SENSIBILITY -80 ++#define RSSI_FOR_MID_SENSIBILITY -90 ++ ++//------------------------------------------------------------------------- ++// EEPROM definition ++//------------------------------------------------------------------------- ++#define EEDO 0x08 ++#define EEDI 0x04 ++#define EECS 0x02 ++#define EESK 0x01 ++#define EERL 0x80 ++ ++#define EEPROM_WRITE_OPCODE 0x05 ++#define EEPROM_READ_OPCODE 0x06 ++#define EEPROM_EWDS_OPCODE 0x10 ++#define EEPROM_EWEN_OPCODE 0x13 ++ ++#define NUM_EEPROM_BBP_PARMS 19 // Include NIC Config 0, 1, CR, TX ALC step, BBPs ++#define NUM_EEPROM_TX_G_PARMS 7 ++#define EEPROM_NIC1_OFFSET 0x34 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_NIC2_OFFSET 0x36 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_BBP_BASE_OFFSET 0xf0 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_G_TX_PWR_OFFSET 0x52 ++#define EEPROM_G_TX2_PWR_OFFSET 0x60 ++#define EEPROM_LED1_OFFSET 0x3c ++#define EEPROM_LED2_OFFSET 0x3e ++#define EEPROM_LED3_OFFSET 0x40 ++#define EEPROM_LNA_OFFSET 0x44 ++#define EEPROM_RSSI_BG_OFFSET 0x46 ++#define EEPROM_RSSI_A_OFFSET 0x4a ++#define EEPROM_DEFINE_MAX_TXPWR 0x4e ++#define EEPROM_TXPOWER_BYRATE_20MHZ_2_4G 0xde // 20MHZ 2.4G tx power. ++#define EEPROM_TXPOWER_BYRATE_40MHZ_2_4G 0xee // 40MHZ 2.4G tx power. ++#define EEPROM_TXPOWER_BYRATE_20MHZ_5G 0xfa // 20MHZ 5G tx power. ++#define EEPROM_TXPOWER_BYRATE_40MHZ_5G 0x10a // 40MHZ 5G tx power. ++#define EEPROM_A_TX_PWR_OFFSET 0x78 ++#define EEPROM_A_TX2_PWR_OFFSET 0xa6 ++//#define EEPROM_Japan_TX_PWR_OFFSET 0x90 // 802.11j ++//#define EEPROM_Japan_TX2_PWR_OFFSET 0xbe ++//#define EEPROM_TSSI_REF_OFFSET 0x54 ++//#define EEPROM_TSSI_DELTA_OFFSET 0x24 ++//#define EEPROM_CCK_TX_PWR_OFFSET 0x62 ++//#define EEPROM_CALIBRATE_OFFSET 0x7c ++#define EEPROM_VERSION_OFFSET 0x02 ++#define EEPROM_FREQ_OFFSET 0x3a ++#define EEPROM_TXPOWER_BYRATE 0xde // 20MHZ power. ++#define EEPROM_TXPOWER_DELTA 0x50 // 20MHZ AND 40 MHZ use different power. This is delta in 40MHZ. ++#define VALID_EEPROM_VERSION 1 ++ ++// PairKeyMode definition ++#define PKMODE_NONE 0 ++#define PKMODE_WEP64 1 ++#define PKMODE_WEP128 2 ++#define PKMODE_TKIP 3 ++#define PKMODE_AES 4 ++#define PKMODE_CKIP64 5 ++#define PKMODE_CKIP128 6 ++#define PKMODE_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table ++ ++// ================================================================================= ++// WCID format ++// ================================================================================= ++//7.1 WCID ENTRY format : 8bytes ++typedef struct _WCID_ENTRY_STRUC { ++ UCHAR RXBABitmap7; // bit0 for TID8, bit7 for TID 15 ++ UCHAR RXBABitmap0; // bit0 for TID0, bit7 for TID 7 ++ UCHAR MAC[6]; // 0 for shared key table. 1 for pairwise key table ++} WCID_ENTRY_STRUC, *PWCID_ENTRY_STRUC; ++ ++//8.1.1 SECURITY KEY format : 8DW ++// 32-byte per entry, total 16-entry for shared key table, 64-entry for pairwise key table ++typedef struct _HW_KEY_ENTRY { // 32-byte per entry ++ UCHAR Key[16]; ++ UCHAR TxMic[8]; ++ UCHAR RxMic[8]; ++} HW_KEY_ENTRY, *PHW_KEY_ENTRY; ++ ++//8.1.2 IV/EIV format : 2DW ++ ++//8.1.3 RX attribute entry format : 1DW ++#ifdef RT_BIG_ENDIAN ++typedef struct _MAC_ATTRIBUTE_STRUC { ++ UINT32 rsv:22; ++ UINT32 RXWIUDF:3; ++ UINT32 BSSIDIdx:3; //multipleBSS index for the WCID ++ UINT32 PairKeyMode:3; ++ UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table ++} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; ++#else ++typedef struct _MAC_ATTRIBUTE_STRUC { ++ UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table ++ UINT32 PairKeyMode:3; ++ UINT32 BSSIDIdx:3; //multipleBSS index for the WCID ++ UINT32 RXWIUDF:3; ++ UINT32 rsv:22; ++} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; ++#endif ++ ++ ++// ================================================================================= ++// TX / RX ring descriptor format ++// ================================================================================= ++ ++// the first 24-byte in TXD is called TXINFO and will be DMAed to MAC block through TXFIFO. ++// MAC block use this TXINFO to control the transmission behavior of this frame. ++#define FIFO_MGMT 0 ++#define FIFO_HCCA 1 ++#define FIFO_EDCA 2 ++ ++// ++// TX descriptor format, Tx ring, Mgmt Ring ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _TXD_STRUC { ++ // Word 0 ++ UINT32 SDPtr0; ++ // Word 1 ++ UINT32 DMADONE:1; ++ UINT32 LastSec0:1; ++ UINT32 SDLen0:14; ++ UINT32 Burst:1; ++ UINT32 LastSec1:1; ++ UINT32 SDLen1:14; ++ // Word 2 ++ UINT32 SDPtr1; ++ // Word 3 ++ UINT32 ICO:1; ++ UINT32 UCO:1; ++ UINT32 TCO:1; ++ UINT32 rsv:2; ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 rsv2:24; ++} TXD_STRUC, *PTXD_STRUC; ++#else ++typedef struct PACKED _TXD_STRUC { ++ // Word 0 ++ UINT32 SDPtr0; ++ // Word 1 ++ UINT32 SDLen1:14; ++ UINT32 LastSec1:1; ++ UINT32 Burst:1; ++ UINT32 SDLen0:14; ++ UINT32 LastSec0:1; ++ UINT32 DMADONE:1; ++ //Word2 ++ UINT32 SDPtr1; ++ //Word3 ++ UINT32 rsv2:24; ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 rsv:2; ++ UINT32 TCO:1; // ++ UINT32 UCO:1; // ++ UINT32 ICO:1; // ++} TXD_STRUC, *PTXD_STRUC; ++#endif ++ ++ ++// ++// TXD Wireless Information format for Tx ring and Mgmt Ring ++// ++//txop : for txop mode ++// 0:txop for the MPDU frame will be handles by ASIC by register ++// 1/2/3:the MPDU frame is send after PIFS/backoff/SIFS ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _TXWI_STRUC { ++ // Word 0 ++ UINT32 PHYMODE:2; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 rsv2:1; ++// UINT32 rsv2:2; ++ UINT32 Ifs:1; // ++ UINT32 STBC:2; //channel bandwidth 20MHz or 40 MHz ++ UINT32 ShortGI:1; ++ UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz ++ UINT32 MCS:7; ++ ++ UINT32 rsv:6; ++ UINT32 txop:2; //tx back off mode 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. ++ UINT32 MpduDensity:3; ++ UINT32 AMPDU:1; ++ ++ UINT32 TS:1; ++ UINT32 CFACK:1; ++ UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode ++ UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. ++ // Word 1 ++ UINT32 PacketId:4; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 WirelessCliID:8; ++ UINT32 BAWinSize:6; ++ UINT32 NSEQ:1; ++ UINT32 ACK:1; ++ // Word 2 ++ UINT32 IV; ++ // Word 3 ++ UINT32 EIV; ++} TXWI_STRUC, *PTXWI_STRUC; ++#else ++typedef struct PACKED _TXWI_STRUC { ++ // Word 0 ++ UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. ++ UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode ++ UINT32 CFACK:1; ++ UINT32 TS:1; ++ ++ UINT32 AMPDU:1; ++ UINT32 MpduDensity:3; ++ UINT32 txop:2; //FOR "THIS" frame. 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. ++ UINT32 rsv:6; ++ ++ UINT32 MCS:7; ++ UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz ++ UINT32 ShortGI:1; ++ UINT32 STBC:2; // 1: STBC support MCS =0-7, 2,3 : RESERVE ++ UINT32 Ifs:1; // ++// UINT32 rsv2:2; //channel bandwidth 20MHz or 40 MHz ++ UINT32 rsv2:1; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 PHYMODE:2; ++ // Word 1 ++ UINT32 ACK:1; ++ UINT32 NSEQ:1; ++ UINT32 BAWinSize:6; ++ UINT32 WirelessCliID:8; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 PacketId:4; ++ //Word2 ++ UINT32 IV; ++ //Word3 ++ UINT32 EIV; ++} TXWI_STRUC, *PTXWI_STRUC; ++#endif ++// ++// Rx descriptor format, Rx Ring ++// ++// ++// RXWI wireless information format, in PBF. invisible in driver. ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _RXWI_STRUC { ++ // Word 0 ++ UINT32 TID:4; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 UDF:3; ++ UINT32 BSSID:3; ++ UINT32 KeyIndex:2; ++ UINT32 WirelessCliID:8; ++ // Word 1 ++ UINT32 PHYMODE:2; // 1: this RX frame is unicast to me ++ UINT32 rsv:3; ++ UINT32 STBC:2; ++ UINT32 ShortGI:1; ++ UINT32 BW:1; ++ UINT32 MCS:7; ++ UINT32 SEQUENCE:12; ++ UINT32 FRAG:4; ++ // Word 2 ++ UINT32 rsv1:8; ++ UINT32 RSSI2:8; ++ UINT32 RSSI1:8; ++ UINT32 RSSI0:8; ++ // Word 3 ++ UINT32 rsv2:16; ++ UINT32 SNR1:8; ++ UINT32 SNR0:8; ++} RXWI_STRUC, *PRXWI_STRUC; ++#else ++typedef struct PACKED _RXWI_STRUC { ++ // Word 0 ++ UINT32 WirelessCliID:8; ++ UINT32 KeyIndex:2; ++ UINT32 BSSID:3; ++ UINT32 UDF:3; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 TID:4; ++ // Word 1 ++ UINT32 FRAG:4; ++ UINT32 SEQUENCE:12; ++ UINT32 MCS:7; ++ UINT32 BW:1; ++ UINT32 ShortGI:1; ++ UINT32 STBC:2; ++ UINT32 rsv:3; ++ UINT32 PHYMODE:2; // 1: this RX frame is unicast to me ++ //Word2 ++ UINT32 RSSI0:8; ++ UINT32 RSSI1:8; ++ UINT32 RSSI2:8; ++ UINT32 rsv1:8; ++ //Word3 ++ UINT32 SNR0:8; ++ UINT32 SNR1:8; ++ UINT32 rsv2:16; ++} RXWI_STRUC, *PRXWI_STRUC; ++#endif ++ ++ ++// ================================================================================= ++// HOST-MCU communication data structure ++// ================================================================================= ++ ++// ++// H2M_MAILBOX_CSR: Host-to-MCU Mailbox ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _H2M_MAILBOX_STRUC { ++ struct { ++ UINT32 Owner:8; ++ UINT32 CmdToken:8; // 0xff tells MCU not to report CmdDoneInt after excuting the command ++ UINT32 HighByte:8; ++ UINT32 LowByte:8; ++ } field; ++ UINT32 word; ++} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; ++#else ++typedef union _H2M_MAILBOX_STRUC { ++ struct { ++ UINT32 LowByte:8; ++ UINT32 HighByte:8; ++ UINT32 CmdToken:8; ++ UINT32 Owner:8; ++ } field; ++ UINT32 word; ++} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; ++#endif ++ ++// ++// M2H_CMD_DONE_CSR: MCU-to-Host command complete indication ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _M2H_CMD_DONE_STRUC { ++ struct { ++ UINT32 CmdToken3; ++ UINT32 CmdToken2; ++ UINT32 CmdToken1; ++ UINT32 CmdToken0; ++ } field; ++ UINT32 word; ++} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; ++#else ++typedef union _M2H_CMD_DONE_STRUC { ++ struct { ++ UINT32 CmdToken0; ++ UINT32 CmdToken1; ++ UINT32 CmdToken2; ++ UINT32 CmdToken3; ++ } field; ++ UINT32 word; ++} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; ++#endif ++ ++ ++ ++// ++// MCU_LEDCS: MCU LED Control Setting. ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MCU_LEDCS_STRUC { ++ struct { ++ UCHAR Polarity:1; ++ UCHAR LedMode:7; ++ } field; ++ UCHAR word; ++} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; ++#else ++typedef union _MCU_LEDCS_STRUC { ++ struct { ++ UCHAR LedMode:7; ++ UCHAR Polarity:1; ++ } field; ++ UCHAR word; ++} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; ++#endif ++// ================================================================================= ++// Register format ++// ================================================================================= ++ ++ ++ ++//NAV_TIME_CFG :NAV ++#ifdef RT_BIG_ENDIAN ++typedef union _NAV_TIME_CFG_STRUC { ++ struct { ++ USHORT rsv:6; ++ USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable ++ USHORT Eifs:9; // in unit of 1-us ++ UCHAR SlotTime; // in unit of 1-us ++ UCHAR Sifs; // in unit of 1-us ++ } field; ++ UINT32 word; ++} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; ++#else ++typedef union _NAV_TIME_CFG_STRUC { ++ struct { ++ UCHAR Sifs; // in unit of 1-us ++ UCHAR SlotTime; // in unit of 1-us ++ USHORT Eifs:9; // in unit of 1-us ++ USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable ++ USHORT rsv:6; ++ } field; ++ UINT32 word; ++} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; ++#endif ++ ++ ++ ++ ++ ++// ++// RX_FILTR_CFG: /RX configuration register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union RX_FILTR_CFG_STRUC { ++ struct { ++ UINT32 :15; ++ UINT32 DropRsvCntlType:1; ++ ++ UINT32 DropBAR:1; // ++ UINT32 DropBA:1; // ++ UINT32 DropPsPoll:1; // Drop Ps-Poll ++ UINT32 DropRts:1; // Drop Ps-Poll ++ ++ UINT32 DropCts:1; // Drop Ps-Poll ++ UINT32 DropAck:1; // Drop Ps-Poll ++ UINT32 DropCFEnd:1; // Drop Ps-Poll ++ UINT32 DropCFEndAck:1; // Drop Ps-Poll ++ ++ UINT32 DropDuplicate:1; // Drop duplicate frame ++ UINT32 DropBcast:1; // Drop broadcast frames ++ UINT32 DropMcast:1; // Drop multicast frames ++ UINT32 DropVerErr:1; // Drop version error frame ++ ++ UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true ++ UINT32 DropNotToMe:1; // Drop not to me unicast frame ++ UINT32 DropPhyErr:1; // Drop physical error ++ UINT32 DropCRCErr:1; // Drop CRC error ++ } field; ++ UINT32 word; ++} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; ++#else ++typedef union _RX_FILTR_CFG_STRUC { ++ struct { ++ UINT32 DropCRCErr:1; // Drop CRC error ++ UINT32 DropPhyErr:1; // Drop physical error ++ UINT32 DropNotToMe:1; // Drop not to me unicast frame ++ UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true ++ ++ UINT32 DropVerErr:1; // Drop version error frame ++ UINT32 DropMcast:1; // Drop multicast frames ++ UINT32 DropBcast:1; // Drop broadcast frames ++ UINT32 DropDuplicate:1; // Drop duplicate frame ++ ++ UINT32 DropCFEndAck:1; // Drop Ps-Poll ++ UINT32 DropCFEnd:1; // Drop Ps-Poll ++ UINT32 DropAck:1; // Drop Ps-Poll ++ UINT32 DropCts:1; // Drop Ps-Poll ++ ++ UINT32 DropRts:1; // Drop Ps-Poll ++ UINT32 DropPsPoll:1; // Drop Ps-Poll ++ UINT32 DropBA:1; // ++ UINT32 DropBAR:1; // ++ ++ UINT32 DropRsvCntlType:1; ++ UINT32 :15; ++ } field; ++ UINT32 word; ++} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; ++#endif ++ ++ ++ ++ ++// ++// PHY_CSR4: RF serial control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _PHY_CSR4_STRUC { ++ struct { ++ UINT32 Busy:1; // 1: ASIC is busy execute RF programming. ++ UINT32 PLL_LD:1; // RF PLL_LD status ++ UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program ++ UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) ++ UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. ++ } field; ++ UINT32 word; ++} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; ++#else ++typedef union _PHY_CSR4_STRUC { ++ struct { ++ UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. ++ UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) ++ UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program ++ UINT32 PLL_LD:1; // RF PLL_LD status ++ UINT32 Busy:1; // 1: ASIC is busy execute RF programming. ++ } field; ++ UINT32 word; ++} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; ++#endif ++ ++ ++// ++// SEC_CSR5: shared key table security mode register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _SEC_CSR5_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 Bss3Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key0CipherAlg:3; ++ } field; ++ UINT32 word; ++} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; ++#else ++typedef union _SEC_CSR5_STRUC { ++ struct { ++ UINT32 Bss2Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key3CipherAlg:3; ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; ++#endif ++ ++ ++// ++// HOST_CMD_CSR: For HOST to interrupt embedded processor ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _HOST_CMD_CSR_STRUC { ++ struct { ++ UINT32 Rsv:24; ++ UINT32 HostCommand:8; ++ } field; ++ UINT32 word; ++} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; ++#else ++typedef union _HOST_CMD_CSR_STRUC { ++ struct { ++ UINT32 HostCommand:8; ++ UINT32 Rsv:24; ++ } field; ++ UINT32 word; ++} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; ++#endif ++ ++ ++// ++// AIFSN_CSR: AIFSN for each EDCA AC ++// ++ ++ ++ ++// ++// E2PROM_CSR: EEPROM control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _E2PROM_CSR_STRUC { ++ struct { ++ UINT32 Rsvd:25; ++ UINT32 LoadStatus:1; // 1:loading, 0:done ++ UINT32 Type:1; // 1: 93C46, 0:93C66 ++ UINT32 EepromDO:1; ++ UINT32 EepromDI:1; ++ UINT32 EepromCS:1; ++ UINT32 EepromSK:1; ++ UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. ++ } field; ++ UINT32 word; ++} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; ++#else ++typedef union _E2PROM_CSR_STRUC { ++ struct { ++ UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. ++ UINT32 EepromSK:1; ++ UINT32 EepromCS:1; ++ UINT32 EepromDI:1; ++ UINT32 EepromDO:1; ++ UINT32 Type:1; // 1: 93C46, 0:93C66 ++ UINT32 LoadStatus:1; // 1:loading, 0:done ++ UINT32 Rsvd:25; ++ } field; ++ UINT32 word; ++} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; ++#endif ++ ++ ++// ------------------------------------------------------------------- ++// E2PROM data layout ++// ------------------------------------------------------------------- ++ ++// ++// EEPROM antenna select format ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_ANTENNA_STRUC { ++ struct { ++ USHORT Rsv:4; ++ USHORT RfIcType:4; // see E2PROM document ++ USHORT TxPath:4; // 1: 1T, 2: 2T ++ USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R ++ } field; ++ USHORT word; ++} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; ++#else ++typedef union _EEPROM_ANTENNA_STRUC { ++ struct { ++ USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R ++ USHORT TxPath:4; // 1: 1T, 2: 2T ++ USHORT RfIcType:4; // see E2PROM document ++ USHORT Rsv:4; ++ } field; ++ USHORT word; ++} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_NIC_CINFIG2_STRUC { ++ struct { ++ USHORT Rsv2:6; // must be 0 ++ USHORT BW40MAvailForA:1; // 0:enable, 1:disable ++ USHORT BW40MAvailForG:1; // 0:enable, 1:disable ++ USHORT EnableWPSPBC:1; // WPS PBC Control bit ++ USHORT BW40MSidebandForA:1; ++ USHORT BW40MSidebandForG:1; ++ USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable ++ USHORT ExternalLNAForA:1; // external LNA enable for 5G ++ USHORT ExternalLNAForG:1; // external LNA enable for 2.4G ++ USHORT DynamicTxAgcControl:1; // ++ USHORT HardwareRadioControl:1; // Whether RF is controlled by driver or HW. 1:enable hw control, 0:disable ++ } field; ++ USHORT word; ++} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; ++#else ++typedef union _EEPROM_NIC_CINFIG2_STRUC { ++ struct { ++ USHORT HardwareRadioControl:1; // 1:enable, 0:disable ++ USHORT DynamicTxAgcControl:1; // ++ USHORT ExternalLNAForG:1; // ++ USHORT ExternalLNAForA:1; // external LNA enable for 2.4G ++ USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable ++ USHORT BW40MSidebandForG:1; ++ USHORT BW40MSidebandForA:1; ++ USHORT EnableWPSPBC:1; // WPS PBC Control bit ++ USHORT BW40MAvailForG:1; // 0:enable, 1:disable ++ USHORT BW40MAvailForA:1; // 0:enable, 1:disable ++ USHORT Rsv2:6; // must be 0 ++ } field; ++ USHORT word; ++} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; ++#endif ++ ++// ++// TX_PWR Value valid range 0xFA(-6) ~ 0x24(36) ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_TX_PWR_STRUC { ++ struct { ++ CHAR Byte1; // High Byte ++ CHAR Byte0; // Low Byte ++ } field; ++ USHORT word; ++} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; ++#else ++typedef union _EEPROM_TX_PWR_STRUC { ++ struct { ++ CHAR Byte0; // Low Byte ++ CHAR Byte1; // High Byte ++ } field; ++ USHORT word; ++} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_VERSION_STRUC { ++ struct { ++ UCHAR Version; // High Byte ++ UCHAR FaeReleaseNumber; // Low Byte ++ } field; ++ USHORT word; ++} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; ++#else ++typedef union _EEPROM_VERSION_STRUC { ++ struct { ++ UCHAR FaeReleaseNumber; // Low Byte ++ UCHAR Version; // High Byte ++ } field; ++ USHORT word; ++} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_LED_STRUC { ++ struct { ++ USHORT Rsvd:3; // Reserved ++ USHORT LedMode:5; // Led mode. ++ USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. ++ USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. ++ USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. ++ USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. ++ USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. ++ USHORT PolarityACT:1; // Polarity ACT setting. ++ USHORT PolarityRDY_A:1; // Polarity RDY_A setting. ++ USHORT PolarityRDY_G:1; // Polarity RDY_G setting. ++ } field; ++ USHORT word; ++} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; ++#else ++typedef union _EEPROM_LED_STRUC { ++ struct { ++ USHORT PolarityRDY_G:1; // Polarity RDY_G setting. ++ USHORT PolarityRDY_A:1; // Polarity RDY_A setting. ++ USHORT PolarityACT:1; // Polarity ACT setting. ++ USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. ++ USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. ++ USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. ++ USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. ++ USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. ++ USHORT LedMode:5; // Led mode. ++ USHORT Rsvd:3; // Reserved ++ } field; ++ USHORT word; ++} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_TXPOWER_DELTA_STRUC { ++ struct { ++ UCHAR TxPowerEnable:1;// Enable ++ UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value ++ UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) ++ } field; ++ UCHAR value; ++} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; ++#else ++typedef union _EEPROM_TXPOWER_DELTA_STRUC { ++ struct { ++ UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) ++ UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value ++ UCHAR TxPowerEnable:1;// Enable ++ } field; ++ UCHAR value; ++} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; ++#endif ++ ++// ++// QOS_CSR0: TXOP holder address0 register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _QOS_CSR0_STRUC { ++ struct { ++ UCHAR Byte3; // MAC address byte 3 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte0; // MAC address byte 0 ++ } field; ++ UINT32 word; ++} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; ++#else ++typedef union _QOS_CSR0_STRUC { ++ struct { ++ UCHAR Byte0; // MAC address byte 0 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte3; // MAC address byte 3 ++ } field; ++ UINT32 word; ++} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; ++#endif ++ ++// ++// QOS_CSR1: TXOP holder address1 register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _QOS_CSR1_STRUC { ++ struct { ++ UCHAR Rsvd1; ++ UCHAR Rsvd0; ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Byte4; // MAC address byte 4 ++ } field; ++ UINT32 word; ++} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; ++#else ++typedef union _QOS_CSR1_STRUC { ++ struct { ++ UCHAR Byte4; // MAC address byte 4 ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Rsvd0; ++ UCHAR Rsvd1; ++ } field; ++ UINT32 word; ++} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; ++#endif ++ ++#define RF_CSR_CFG 0x500 ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG_STRUC { ++ struct { ++ UINT Rsvd1:14; // Reserved ++ UINT RF_CSR_KICK:1; // kick RF register read/write ++ UINT RF_CSR_WR:1; // 0: read 1: write ++ UINT Rsvd2:3; // Reserved ++ UINT TESTCSR_RFACC_REGNUM:5; // RF register ID ++ UINT RF_CSR_DATA:8; // DATA ++ } field; ++ UINT word; ++} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; ++#else ++typedef union _RF_CSR_CFG_STRUC { ++ struct { ++ UINT RF_CSR_DATA:8; // DATA ++ UINT TESTCSR_RFACC_REGNUM:5; // RF register ID ++ UINT Rsvd2:3; // Reserved ++ UINT RF_CSR_WR:1; // 0: read 1: write ++ UINT RF_CSR_KICK:1; // kick RF register read/write ++ UINT Rsvd1:14; // Reserved ++ } field; ++ UINT word; ++} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; ++#endif ++ ++#endif // __RT28XX_H__ +--- /dev/null ++++ b/drivers/staging/rt2870/rt_ate.c +@@ -0,0 +1,6452 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++#ifdef UCOS ++INT IoctlResponse(PUCHAR payload, PUCHAR msg, INT len); ++#endif // UCOS // ++ ++#ifdef RALINK_ATE ++UCHAR TemplateFrame[24] = {0x08/* Data type */,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes ++extern RTMP_RF_REGS RF2850RegTable[]; ++extern UCHAR NUM_OF_2850_CHNL; ++ ++#ifdef RT2870 ++extern UCHAR EpToQueue[]; ++extern VOID RTUSBRejectPendingPackets( IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++#ifdef UCOS ++extern INT ConsoleResponse(IN PUCHAR buff); ++extern int (*remote_display)(char *); ++#endif // UCOS // ++ ++static CHAR CCKRateTable[] = {0, 1, 2, 3, 8, 9, 10, 11, -1}; /* CCK Mode. */ ++static CHAR OFDMRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; /* OFDM Mode. */ ++static CHAR HTMIXRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}; /* HT Mix Mode. */ ++ ++static INT TxDmaBusy( ++ IN PRTMP_ADAPTER pAd); ++ ++static INT RxDmaBusy( ++ IN PRTMP_ADAPTER pAd); ++ ++static VOID RtmpDmaEnable( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Enable); ++ ++static VOID BbpSoftReset( ++ IN PRTMP_ADAPTER pAd); ++ ++static VOID RtmpRfIoWrite( ++ IN PRTMP_ADAPTER pAd); ++ ++static INT ATESetUpFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TxIdx); ++ ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index); ++ ++static INT ATECmdHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++static int CheckMCSValid( ++ IN UCHAR Mode, ++ IN UCHAR Mcs); ++ ++ ++#ifdef RT2870 ++static VOID ATEWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst); ++ ++static VOID ATEWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR MIMOps, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING Transmit); ++ ++#endif // RT2870 // ++ ++static VOID SetJapanFilter( ++ IN PRTMP_ADAPTER pAd); ++ ++/*=========================end of prototype=========================*/ ++ ++ ++#ifdef RT2870 ++static INT TxDmaBusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT result; ++ USB_DMA_CFG_STRUC UsbCfg; ++ ++ RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA ++ if (UsbCfg.field.TxBusy) ++ result = 1; ++ else ++ result = 0; ++ ++ return result; ++} ++ ++static INT RxDmaBusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT result; ++ USB_DMA_CFG_STRUC UsbCfg; ++ ++ RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA ++ if (UsbCfg.field.RxBusy) ++ result = 1; ++ else ++ result = 0; ++ ++ return result; ++} ++ ++static VOID RtmpDmaEnable( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Enable) ++{ ++ BOOLEAN value; ++ ULONG WaitCnt; ++ USB_DMA_CFG_STRUC UsbCfg; ++ ++ value = Enable > 0 ? 1 : 0; ++ ++ // check DMA is in busy mode. ++ WaitCnt = 0; ++ while (TxDmaBusy(pAd) || RxDmaBusy(pAd)) ++ { ++ RTMPusecDelay(10); ++ if (WaitCnt++ > 100) ++ break; ++ } ++ ++ //Why not to clear USB DMA TX path first ??? ++ RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA ++ UsbCfg.field.TxBulkEn = value; ++ UsbCfg.field.RxBulkEn = value; ++ RTMP_IO_WRITE32(pAd, USB_DMA_CFG, UsbCfg.word); // abort all TX rings ++ RTMPusecDelay(5000); ++ ++ return; ++} ++#endif // RT2870 // ++ ++static VOID BbpSoftReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BbpData = 0; ++ ++ // Soft reset, set BBP R21 bit0=1->0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); ++ BbpData |= 0x00000001; //set bit0=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); ++ BbpData &= ~(0x00000001); //set bit0=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); ++ ++ return; ++} ++ ++static VOID RtmpRfIoWrite( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Set RF value 1's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 2's set R3[bit2] = [1] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 3's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ return; ++} ++ ++static int CheckMCSValid( ++ UCHAR Mode, ++ UCHAR Mcs) ++{ ++ int i; ++ PCHAR pRateTab; ++ ++ switch(Mode) ++ { ++ case 0: ++ pRateTab = CCKRateTable; ++ break; ++ case 1: ++ pRateTab = OFDMRateTable; ++ break; ++ case 2: ++ case 3: ++ pRateTab = HTMIXRateTable; ++ break; ++ default: ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("unrecognizable Tx Mode %d\n", Mode)); ++ return -1; ++ break; ++ } ++ ++ i = 0; ++ while(pRateTab[i] != -1) ++ { ++ if (pRateTab[i] == Mcs) ++ return 0; ++ i++; ++ } ++ ++ return -1; ++} ++ ++#if 1 ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index) ++{ ++ ULONG R; ++ CHAR TxPower; ++ UCHAR Bbp94 = 0; ++ BOOLEAN bPowerReduce = FALSE; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power ++ ** are not synchronized. ++ */ ++/* ++ pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; ++ pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; ++*/ ++ return 0; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (TxPower > 31) ++ { ++ // ++ // R3, R4 can't large than 31 (0x24), 31 ~ 36 used by BBP 94 ++ // ++ R = 31; ++ if (TxPower <= 36) ++ Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 ++ // ++ R = 0; ++ if (TxPower >= -6) ++ Bbp94 = BBPR94_DEFAULT + TxPower; ++ } ++ else ++ { ++ // 0 ~ 31 ++ R = (ULONG) TxPower; ++ Bbp94 = BBPR94_DEFAULT; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ } ++ else// 5.5 GHz ++ { ++ if (TxPower > 15) ++ { ++ // ++ // R3, R4 can't large than 15 (0x0F) ++ // ++ R = 15; ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0 ++ // ++ // -1 ~ -7 ++ ASSERT((TxPower >= -7)); ++ R = (ULONG)(TxPower + 7); ++ bPowerReduce = TRUE; ++ } ++ else ++ { ++ // 0 ~ 15 ++ R = (ULONG) TxPower; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R)); ++ } ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (index == 0) ++ { ++ R = R << 9; // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = R << 6; // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else// 5.5GHz ++ { ++ if (bPowerReduce == FALSE) ++ { ++ if (index == 0) ++ { ++ R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else ++ { ++ if (index == 0) ++ { ++ R = (R << 10); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ ++ /* Clear bit 9 of R3 to reduce 7dB. */ ++ pAd->LatchRfRegs.R3 = (R & (~(1 << 9))); ++ } ++ else ++ { ++ R = (R << 7); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ ++ /* Clear bit 6 of R4 to reduce 7dB. */ ++ pAd->LatchRfRegs.R4 = (R & (~(1 << 6))); ++ } ++ } ++ } ++ ++ RtmpRfIoWrite(pAd); ++ ++ return 0; ++ } ++} ++#else// 1 // ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index) ++{ ++ ULONG R; ++ CHAR TxPower; ++ UCHAR Bbp94 = 0; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ // TODO: how to get current TxPower0/1 from pAd->LatchRfRegs ? ++ /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power ++ ** are not synchronized. ++ */ ++/* ++ pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; ++ pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; ++*/ ++ return 0; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; ++ ++ if (TxPower > 31) ++ { ++ // ++ // R3, R4 can't large than 36 (0x24), 31 ~ 36 used by BBP 94 ++ // ++ R = 31; ++ if (TxPower <= 36) ++ Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 ++ // ++ R = 0; ++ if (TxPower >= -6) ++ Bbp94 = BBPR94_DEFAULT + TxPower; ++ } ++ else ++ { ++ // 0 ~ 31 ++ R = (ULONG) TxPower; ++ Bbp94 = BBPR94_DEFAULT; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (index == 0) ++ { ++ R = R << 9; // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = R << 6; // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else ++ { ++ if (index == 0) ++ { ++ R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ ++ RtmpRfIoWrite(pAd); ++ ++ return 0; ++ } ++} ++#endif // 1 // ++/* ++ ========================================================================== ++ Description: ++ Set ATE operation mode to ++ 0. ATESTART = Start ATE Mode ++ 1. ATESTOP = Stop ATE Mode ++ 2. TXCONT = Continuous Transmit ++ 3. TXCARR = Transmit Carrier ++ 4. TXFRAME = Transmit Frames ++ 5. RXFRAME = Receive Frames ++#ifdef RALINK_28xx_QA ++ 6. TXSTOP = Stop Any Type of Transmition ++ 7. RXSTOP = Stop Receiving Frames ++#endif // RALINK_28xx_QA // ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++/* */ ++/* */ ++/*=======================End of RT2860=======================*/ ++ ++ ++/*======================Start of RT2870======================*/ ++/* */ ++/* */ ++ ++#ifdef RT2870 ++static INT ATECmdHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 Value; ++ UCHAR BbpData; ++ UINT32 MacData; ++ UINT i=0, atemode; ++ //NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ //PUCHAR pDest; ++ UINT32 temp; ++ ULONG IrqFlags; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> ATECmdHandler()\n")); ++ ATEAsicSwitchChannel(pAd); ++ /* AsicLockChannel() is empty function so far in fact */ ++ AsicLockChannel(pAd, pAd->ate.Channel); ++ ++ RTMPusecDelay(5000); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ /* Enter ATE mode and set Tx/Rx Idle */ ++ if (!strcmp(arg, "ATESTART")) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN Cancelled; ++#endif // CONFIG_STA_SUPPORT // ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTART\n")); ++ ++ netif_stop_queue(pAd->net_dev); ++ ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode = ATE_START; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable auto responder ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); ++ temp = temp & 0xFFFFFFFE; ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); ++ ++ // read MAC_SYS_CTRL and backup MAC_SYS_CTRL value. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ // clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ // Stop continuous TX production test. ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData);//disable or cancel pending irp first ??? ++ ++ if (atemode & ATE_TXCARR) ++ { ++ // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ else if (atemode & ATE_TXCARRSUPP) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // No Carrier Suppression set BBP R24 bit0=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); ++ BbpData &= 0xFFFFFFFE; //clear bit0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); ++ } ++ // We should free some resource which allocate when ATE_TXFRAME , ATE_STOP, and ATE_TXCONT. ++ // TODO:Should we free some resource which was allocated when LoopBack and ATE_STOP ? ++ else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) ++ { ++ if (atemode & ATE_TXCONT) ++ { ++ // Not Cont. TX anymore, so set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ // Abort Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ { ++ // It seems nothing to free, ++ // because we didn't allocate any resource when we entered ATE_TXFRAME mode latestly. ++ } ++ ++ // Start Tx, RX DMA ++ RtmpDmaEnable(pAd, 1); ++ } ++ ++ RTUSBRejectPendingPackets(pAd); ++ RTUSBCleanUpDataBulkOutQueue(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ // ++ // It will be called in MlmeSuspend(). ++ // ++ // Cancel pending timers ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++#endif // CONFIG_STA_SUPPORT // ++ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); /* not used in RT28xx */ ++ RTUSBCleanUpMLMEBulkOutQueue(pAd); ++ ++ // Sometimes kernel will hang on, so we avoid calling MlmeSuspend(). ++// MlmeSuspend(pAd, TRUE); ++ //RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Make sure there are no pending bulk in/out IRPs before we go on. ++/*=========================================================================*/ ++ /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ ++// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ while ((pAd->PendingRx > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++ NdisInterlockedDecrement(&pAd->PendingRx); ++#endif ++ /* delay 0.5 seconds */ ++ RTMPusecDelay(500000); ++ pAd->PendingRx = 0; ++ } ++ /* peter : why don't we have to get BulkOutLock first ? */ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ /* pAd->BulkOutPending[y] will be set to FALSE in RTUSBCancelPendingBulkOutIRP(pAd) */ ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ /* we have enough time delay in RTUSBCancelPendingBulkOutIRP(pAd) ++ ** so this is not necessary ++ */ ++// RTMPusecDelay(500000); ++ } ++ ++ /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ ++// ASSERT(atomic_read(&pAd->PendingRx) == 0); ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++ ++ // reset Rx statistics. ++ pAd->ate.LastSNR0 = 0; ++ pAd->ate.LastSNR1 = 0; ++ pAd->ate.LastRssi0 = 0; ++ pAd->ate.LastRssi1 = 0; ++ pAd->ate.LastRssi2 = 0; ++ pAd->ate.AvgRssi0 = 0; ++ pAd->ate.AvgRssi1 = 0; ++ pAd->ate.AvgRssi2 = 0; ++ pAd->ate.AvgRssi0X8 = 0; ++ pAd->ate.AvgRssi1X8 = 0; ++ pAd->ate.AvgRssi2X8 = 0; ++ pAd->ate.NumOfAvgRssiSample = 0; ++ ++#ifdef RALINK_28xx_QA ++ // Tx frame ++ pAd->ate.bQATxStart = FALSE; ++ pAd->ate.bQARxStart = FALSE; ++ pAd->ate.seq = 0; ++ ++ // counters ++ pAd->ate.U2M = 0; ++ pAd->ate.OtherData = 0; ++ pAd->ate.Beacon = 0; ++ pAd->ate.OtherCount = 0; ++ pAd->ate.TxAc0 = 0; ++ pAd->ate.TxAc1 = 0; ++ pAd->ate.TxAc2 = 0; ++ pAd->ate.TxAc3 = 0; ++ pAd->ate.TxHCCA = 0; ++ pAd->ate.TxMgmt = 0; ++ pAd->ate.RSSI0 = 0; ++ pAd->ate.RSSI1 = 0; ++ pAd->ate.RSSI2 = 0; ++ pAd->ate.SNR0 = 0; ++ pAd->ate.SNR1 = 0; ++ ++ // control ++ pAd->ate.TxDoneCount = 0; ++ pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running ++#endif // RALINK_28xx_QA // ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AsicDisableSync(pAd); ++ ++ /* ++ ** If we skip "LinkDown()", we should disable protection ++ ** to prevent from sending out RTS or CTS-to-self. ++ */ ++ ATEDisableAsicProtect(pAd); ++ RTMPStationStop(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ //Clean ATE Bulk in/out counter and continue setup ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ ++ /* NdisAcquireSpinLock()/NdisReleaseSpinLock() need only one argument in RT28xx */ ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = FALSE; ++ pAd->ContinBulkIn = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ } ++ else if (!strcmp(arg, "ATESTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE : ATESTOP ===>\n")); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData);//0820 ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); // recover the MAC_SYS_CTRL register back. ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ /* ++ ** Abort Tx, RX DMA. ++ ** Q : How to do the following I/O if Tx, Rx DMA is aborted ? ++ ** Ans : Bulk endpoints are aborted, while the control endpoint is not. ++ */ ++ RtmpDmaEnable(pAd, 0); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ /* Make sure there are no pending bulk in/out IRPs before we go on. */ ++/*=========================================================================*/ ++// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ while (pAd->PendingRx > 0) ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++// NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++#endif ++ RTMPusecDelay(500000); ++ } ++ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ RTMPusecDelay(500000); ++ } ++ ++// ASSERT(atomic_read(&pAd->PendingRx) == 0); ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++/* Reset Rx RING */ ++/*=========================================================================*/ ++// InterlockedExchange(&pAd->PendingRx, 0); ++ pAd->PendingRx = 0; ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer ++ pAd->NextRxBulkInPosition = 0; ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); ++ /* peter : why don't we have to get BulkInLock first ? */ ++ pRxContext->pAd = pAd; ++ pRxContext->pIrp = NULL; ++ /* peter debug ++ */ ++ pRxContext->BulkInOffset = 0; ++ pRxContext->bRxHandling = FALSE; ++ /* peter debug -- */ ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++// pRxContext->ReorderInUse = FALSE; ++// pRxContext->ReadPosOffset = 0; ++ } ++ ++/*=========================================================================*/ ++/* Reset Tx RING */ ++/*=========================================================================*/ ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++/*=========================================================================*/ ++ // Enable auto responder. ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); ++ temp = temp | (0x01); ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); ++ ++/*================================================*/ ++ AsicEnableBssSync(pAd); ++ ++ /* Soft reset BBP.*/ ++ /* In 2870 chipset, ATE_BBP_IO_READ8_BY_REG_ID() == RTMP_BBP_IO_READ8_BY_REG_ID() */ ++ /* Both rt2870ap and rt2870sta use BbpSoftReset(pAd) to do BBP soft reset */ ++ BbpSoftReset(pAd); ++/*================================================*/ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ // Set all state machines back IDLE ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ pAd->Mlme.ActMachine.CurrState = ACT_IDLE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // ===> refer to MlmeRestartStateMachine(). ++ // When we entered ATE_START mode, PeriodicTimer was not cancelled. ++ // So we don't have to set it here. ++ // ++ //RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); ++ ++ ASSERT(pAd->CommonCfg.Channel != 0); ++ ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ RTMPStationStart(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ } ++// ++// These two steps have been done when entering ATE_STOP mode. ++// ++#if 0 ++ RTUSBWriteBBPRegister(pAd, BBP_R22, BbpData); ++ RTUSBWriteMACRegister(pAd, MAC_SYS_CTRL, MacData); ++#endif ++ // Clean ATE Bulk in/out counter and continue setup. ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = FALSE; ++ pAd->ContinBulkIn = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ /* Wait 50ms to prevent next URB to bulkout during HW reset. */ ++ /* todo : remove this if not necessary */ ++ NdisMSleep(50000); ++ ++ pAd->ate.Mode = ATE_STOP; ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++/*=========================================================================*/ ++ /* restore RX_FILTR_CFG */ ++#ifdef CONFIG_STA_SUPPORT ++ /* restore RX_FILTR_CFG in order that QA maybe set it to 0x3 */ ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); ++#endif // CONFIG_STA_SUPPORT // ++/*=========================================================================*/ ++ ++ // Enable Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Wait 10ms to wait all of the bulk-in URBs to complete. ++ /* todo : remove this if not necessary */ ++ NdisMSleep(10000); ++ ++ // Everything is ready to start normal Tx/Rx. ++ RTUSBBulkReceive(pAd); ++ netif_start_queue(pAd->net_dev); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATE : ATESTOP \n")); ++ } ++ else if (!strcmp(arg, "TXCARR")) // Tx Carrier ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCARR\n")); ++ pAd->ate.Mode |= ATE_TXCARR; ++ ++ // Disable Rx ++ // May be we need not to do this, because these have been done in ATE_START mode ??? ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // QA has done the following steps if it is used. ++ if (pAd->ate.bQATxStart == FALSE) ++ { ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Carrier Test set BBP R22 bit7=1, bit6=1, bit[5~0]=0x01 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ BbpData |= 0x000000C1; //set bit7=1, bit6=1, bit[5~0]=0x01 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1 ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value = Value | 0x00000010; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ } ++ else if (!strcmp(arg, "TXCONT")) // Tx Continue ++ { ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ /* set MAC_SYS_CTRL(0x1004) bit4(Continuous Tx Production Test) ++ and bit2(MAC TX enable) back to zero. */ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData &= 0xFFFFFFEB; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ // set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF7F; //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ ++ /* for TxCont mode. ++ ** Step 1: Send 50 packets first then wait for a moment. ++ ** Step 2: Send more 50 packet then start continue mode. ++ */ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCONT\n")); ++ // Step 1: send 50 packets first. ++ pAd->ate.Mode |= ATE_TXCONT; ++ pAd->ate.TxCount = 50; ++ pAd->ate.TxDoneCount = 0; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ ++ /* Only needed if we have to send some normal frames. */ ++ SetJapanFilter(pAd); ++ ++ // Setup frame format. ++ ATESetUpFrame(pAd, 0); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#endif // RALINK_28xx_QA // ++ ++ NdisAcquireSpinLock(&pAd->GenericLock);//0820 ++ pAd->ContinBulkOut = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ ++ /* To make sure all the 50 frames have been bulk out before executing step 2 */ ++ while (atomic_read(&pAd->BulkOutRemained) > 0) ++ { ++ RTMPusecDelay(5000); ++ } ++ ++ // Step 2: send more 50 packets then start continue mode. ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Cont. TX set BBP R22 bit7=1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData |= 0x00000080; //set bit7=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ pAd->ate.TxCount = 50; ++ pAd->ate.TxDoneCount = 0; ++ ++ SetJapanFilter(pAd); ++ ++ // Setup frame format. ++ ATESetUpFrame(pAd, 0); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#endif // RALINK_28xx_QA // ++ ++ NdisAcquireSpinLock(&pAd->GenericLock);//0820 ++ pAd->ContinBulkOut = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ ++#if 1 ++ RTMPusecDelay(500); ++#else ++ while (atomic_read(&pAd->BulkOutRemained) > 0) ++ { ++ RTMPusecDelay(5000); ++ } ++#endif // 1 // ++ ++ // Set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData |= 0x00000010; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ } ++ else if (!strcmp(arg, "TXFRAME")) // Tx Frames ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXFRAME(Count=0x%08x)\n", pAd->ate.TxCount)); ++ pAd->ate.Mode |= ATE_TXFRAME; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++#ifdef RALINK_28xx_QA ++ // add this for LoopBack mode ++ if (pAd->ate.bQARxStart == FALSE) ++ { ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#else ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++#endif // RALINK_28xx_QA // ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ SetJapanFilter(pAd); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ pAd->ate.TxDoneCount = 0; ++ ++ // Setup frame format ++ ATESetUpFrame(pAd, 0); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Check count is continuous or not yet. ++ // ++ // Due to the type mismatch between "pAd->BulkOutRemained"(atomic_t) and "pAd->ate.TxCount"(UINT32) ++ // ++ if (pAd->ate.TxCount == 0) ++ { ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ } ++ else ++ { ++ InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); ++ } ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("bulk out count = %d\n", atomic_read(&pAd->BulkOutRemained))); ++ ASSERT((atomic_read(&pAd->BulkOutRemained) >= 0)); ++ ++ if (atomic_read(&pAd->BulkOutRemained) == 0) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packet countinuously\n")); ++ ++ /* In 28xx, NdisAcquireSpinLock() == spin_lock_bh() */ ++ /* NdisAcquireSpinLock only need one argument in 28xx. */ ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = TRUE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ /* In 28xx, BULK_OUT_LOCK() == spin_lock_irqsave() */ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK ++ pAd->BulkOutPending[0] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packets depend on counter\n")); ++ ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ } ++#ifdef RALINK_28xx_QA ++ else if (!strcmp(arg, "TXSTOP")) //Enter ATE mode and set Tx/Rx Idle ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXSTOP\n")); ++ ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode &= ATE_TXSTOP; ++ pAd->ate.bQATxStart = FALSE; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ ++/*=========================================================================*/ ++ if (atemode & ATE_TXCARR) ++ { ++ // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ else if (atemode & ATE_TXCARRSUPP) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // No Carrier Suppression set BBP R24 bit0=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); ++ BbpData &= 0xFFFFFFFE; //clear bit0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); ++ } ++ else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) ++ { ++ if (atemode & ATE_TXCONT) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ } ++ ++/*=========================================================================*/ ++ RTUSBRejectPendingPackets(pAd); ++ RTUSBCleanUpDataBulkOutQueue(pAd); ++ ++ /* not used in RT28xx */ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); ++ /* empty function so far */ ++ RTUSBCleanUpMLMEBulkOutQueue(pAd); ++/*=========================================================================*/ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++/*=========================================================================*/ ++ ++ /* In 28xx, pAd->PendingRx is not of type atomic_t anymore */ ++// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ /* peter todo : BulkInLock */ ++ while (pAd->PendingRx > 0) ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++// NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++#endif ++ RTMPusecDelay(500000); ++ } ++ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ RTMPusecDelay(500000); ++ } ++ ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++ // Enable Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ /* task Tx status : 0 --> task is idle, 1 --> task is running */ ++ pAd->ate.TxStatus = 0; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData &= (0xfffffffb); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ //Clean ATE Bulk in/out counter and continue setup ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ ++ pAd->ContinBulkOut = FALSE; ++ } ++ else if (!strcmp(arg, "RXSTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXSTOP\n")); ++ atemode = pAd->ate.Mode; ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ pAd->ate.Mode &= ATE_RXSTOP; ++ pAd->ate.bQARxStart = FALSE; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ ++/*=========================================================================*/ ++ RTUSBRejectPendingPackets(pAd); ++ RTUSBCleanUpDataBulkOutQueue(pAd); ++ ++ /* not used in RT28xx */ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); ++ RTUSBCleanUpMLMEBulkOutQueue(pAd); ++/*=========================================================================*/ ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++/*=========================================================================*/ ++// while ((atomic_read(&pAd->PendingRx) > 0)) ++ while (pAd->PendingRx > 0) ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++// NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++#endif ++ RTMPusecDelay(500000); ++ } ++ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ RTMPusecDelay(500000); ++ } ++ ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ pAd->ContinBulkIn = FALSE; ++ } ++#endif // RALINK_28xx_QA // ++ else if (!strcmp(arg, "RXFRAME")) // Rx Frames ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXFRAME\n")); ++ ++ // Disable Rx of MAC block ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ pAd->ate.Mode |= ATE_RXFRAME; ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Disable TX of MAC block ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Reset Rx RING. ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ ++ // ++ // Get the urb from kernel back to driver. ++ // ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ ++ /* Sleep 200 microsecs to give cancellation time to work. */ ++ NdisMSleep(200); ++ pAd->BulkInReq = 0; ++ ++// InterlockedExchange(&pAd->PendingRx, 0); ++ pAd->PendingRx = 0; ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer ++ pAd->NextRxBulkInPosition = 0; ++ } ++ ++ // read to clear counters ++ RTUSBReadMACRegister(pAd, RX_STA_CNT0, &temp); //RX PHY & RX CRC count ++ RTUSBReadMACRegister(pAd, RX_STA_CNT1, &temp); //RX PLCP error count & CCA false alarm count ++ RTUSBReadMACRegister(pAd, RX_STA_CNT2, &temp); //RX FIFO overflow frame count & RX duplicated filtered frame count ++ ++ pAd->ContinBulkIn = TRUE; ++ ++ // Enable Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable RX of MAC block ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Kick bulk in ++ RTUSBBulkReceive(pAd); ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: Invalid arg!\n")); ++ return FALSE; ++ } ++ RTMPusecDelay(5000); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATECmdHandler()\n")); ++ ++ return TRUE; ++} ++#endif // RT2870 // ++ ++INT Set_ATE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (ATECmdHandler(pAd, arg)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Success\n")); ++ ++ ++ return TRUE; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Failed\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR1=DA for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR3=DA for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_DA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr3[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_DA_Proc (DA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr3[0], ++ pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_DA_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR3=SA for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR2=SA for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_SA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr2[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_SA_Proc (SA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr2[0], ++ pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_SA_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR2=BSSID for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR1=BSSID for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_BSSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr1[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_BSSID_Proc (BSSID = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr1[0], ++ pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_BSSID_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Channel ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_CHANNEL_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR channel; ++ ++ channel = simple_strtol(arg, 0, 10); ++ ++ if ((channel < 1) || (channel > 216))// to allow A band channel : ((channel < 1) || (channel > 14)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_CHANNEL_Proc::Out of range, it should be in range of 1~14.\n")); ++ return FALSE; ++ } ++ pAd->ate.Channel = channel; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAd->ate.Channel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_CHANNEL_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Power0 ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_POWER0_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR TxPower; ++ ++ TxPower = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if ((TxPower > 31) || (TxPower < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ else// 5.5GHz ++ { ++ if ((TxPower > 15) || (TxPower < -7)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ ++ pAd->ate.TxPower0 = TxPower; ++ ATETxPwrHandler(pAd, 0); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER0_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Power1 ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_POWER1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR TxPower; ++ ++ TxPower = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if ((TxPower > 31) || (TxPower < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ else ++ { ++ if ((TxPower > 15) || (TxPower < -7)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ ++ pAd->ate.TxPower1 = TxPower; ++ ATETxPwrHandler(pAd, 1); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER1_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Antenna ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR value; ++ ++ value = simple_strtol(arg, 0, 10); ++ ++ if ((value > 2) || (value < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_Antenna_Proc::Out of range (Value=%d)\n", value)); ++ return FALSE; ++ } ++ ++ pAd->ate.TxAntennaSel = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_Antenna_Proc (Antenna = %d)\n", pAd->ate.TxAntennaSel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Ralink: Set_ATE_TX_Antenna_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Rx Antenna ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_RX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR value; ++ ++ value = simple_strtol(arg, 0, 10); ++ ++ if ((value > 3) || (value < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_RX_Antenna_Proc::Out of range (Value=%d)\n", value)); ++ return FALSE; ++ } ++ ++ pAd->ate.RxAntennaSel = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_Antenna_Proc (Antenna = %d)\n", pAd->ate.RxAntennaSel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_Antenna_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE RF frequence offset ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_FREQOFFSET_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR RFFreqOffset; ++ ULONG R4; ++ ++ RFFreqOffset = simple_strtol(arg, 0, 10); ++ ++ if(RFFreqOffset >= 64) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_FREQOFFSET_Proc::Out of range, it should be in range of 0~63.\n")); ++ return FALSE; ++ } ++ ++ pAd->ate.RFFreqOffset = RFFreqOffset; ++ R4 = pAd->ate.RFFreqOffset << 15; // shift TX power control to correct RF register bit position ++ R4 |= (pAd->LatchRfRegs.R4 & ((~0x001f8000))); ++ pAd->LatchRfRegs.R4 = R4; ++ ++ RtmpRfIoWrite(pAd); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_FREQOFFSET_Proc (RFFreqOffset = %d)\n", pAd->ate.RFFreqOffset)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_FREQOFFSET_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE RF BW ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_BW_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ int i; ++ UCHAR value = 0; ++ UCHAR BBPCurrentBW; ++ ++ BBPCurrentBW = simple_strtol(arg, 0, 10); ++ ++ if(BBPCurrentBW == 0) ++ pAd->ate.TxWI.BW = BW_20; ++ else ++ pAd->ate.TxWI.BW = BW_40; ++ ++ if(pAd->ate.TxWI.BW == BW_20) ++ { ++ if(pAd->ate.Channel <= 14) ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx20MPwrCfgGBand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgGBand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ else ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx20MPwrCfgABand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgABand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ ++ //Set BBP R4 bit[4:3]=0:0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value &= (~0x18); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ ++ //Set BBP R66=0x3C ++ value = 0x3C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); ++ //Set BBP R68=0x0B ++ //to improve Rx sensitivity. ++ value = 0x0B; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); ++ //Set BBP R69=0x16 ++ value = 0x16; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); ++ //Set BBP R70=0x08 ++ value = 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); ++ //Set BBP R73=0x11 ++ value = 0x11; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); ++ ++ // If Channel=14, Bandwidth=20M and Mode=CCK, Set BBP R4 bit5=1 ++ // (Japan filter coefficients) ++ // This segment of code will only works when ATETXMODE and ATECHANNEL ++ // were set to MODE_CCK and 14 respectively before ATETXBW is set to 0. ++ //===================================================================== ++ if (pAd->ate.Channel == 14) ++ { ++ int TxMode = pAd->ate.TxWI.PHYMODE; ++ if (TxMode == MODE_CCK) ++ { ++ // when Channel==14 && Mode==CCK && BandWidth==20M, BBP R4 bit5=1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value |= 0x20; //set bit5=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ } ++ } ++ ++ //===================================================================== ++ // If bandwidth != 40M, RF Reg4 bit 21 = 0. ++ pAd->LatchRfRegs.R4 &= ~0x00200000; ++ RtmpRfIoWrite(pAd); ++ } ++ else if(pAd->ate.TxWI.BW == BW_40) ++ { ++ if(pAd->ate.Channel <= 14) ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx40MPwrCfgGBand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgGBand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ else ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx40MPwrCfgABand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgABand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->ate.TxWI.PHYMODE >= MODE_HTMIX) && (pAd->ate.TxWI.MCS == 7)) ++ { ++ value = 0x28; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R67, value); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ //Set BBP R4 bit[4:3]=1:0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value &= (~0x18); ++ value |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ ++ //Set BBP R66=0x3C ++ value = 0x3C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); ++ //Set BBP R68=0x0C ++ //to improve Rx sensitivity. ++ value = 0x0C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); ++ //Set BBP R69=0x1A ++ value = 0x1A; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); ++ //Set BBP R70=0x0A ++ value = 0x0A; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); ++ //Set BBP R73=0x16 ++ value = 0x16; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); ++ ++ // If bandwidth = 40M, set RF Reg4 bit 21 = 1. ++ pAd->LatchRfRegs.R4 |= 0x00200000; ++ RtmpRfIoWrite(pAd); ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_BW_Proc (BBPCurrentBW = %d)\n", pAd->ate.TxWI.BW)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_BW_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame length ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_LENGTH_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxLength = simple_strtol(arg, 0, 10); ++ ++ if((pAd->ate.TxLength < 24) || (pAd->ate.TxLength > (MAX_FRAME_SIZE - 34/* == 2312 */))) ++ { ++ pAd->ate.TxLength = (MAX_FRAME_SIZE - 34/* == 2312 */); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_LENGTH_Proc::Out of range, it should be in range of 24~%d.\n", (MAX_FRAME_SIZE - 34/* == 2312 */))); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_LENGTH_Proc (TxLength = %d)\n", pAd->ate.TxLength)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_LENGTH_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame count ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_COUNT_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxCount = simple_strtol(arg, 0, 10); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAd->ate.TxCount)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame MCS ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_MCS_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR MCS; ++ int result; ++ ++ MCS = simple_strtol(arg, 0, 10); ++ result = CheckMCSValid(pAd->ate.TxWI.PHYMODE, MCS); ++ ++ if (result != -1) ++ { ++ pAd->ate.TxWI.MCS = (UCHAR)MCS; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MCS_Proc::Out of range, refer to rate table.\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MCS_Proc (MCS = %d)\n", pAd->ate.TxWI.MCS)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MCS_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame Mode ++ 0: MODE_CCK ++ 1: MODE_OFDM ++ 2: MODE_HTMIX ++ 3: MODE_HTGREENFIELD ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_MODE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxWI.PHYMODE = simple_strtol(arg, 0, 10); ++ ++ if(pAd->ate.TxWI.PHYMODE > 3) ++ { ++ pAd->ate.TxWI.PHYMODE = 0; ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MODE_Proc::Out of range. it should be in range of 0~3\n")); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("0: CCK, 1: OFDM, 2: HT_MIX, 3: HT_GREEN_FIELD.\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MODE_Proc (TxMode = %d)\n", pAd->ate.TxWI.PHYMODE)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MODE_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame GI ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_GI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxWI.ShortGI = simple_strtol(arg, 0, 10); ++ ++ if(pAd->ate.TxWI.ShortGI > 1) ++ { ++ pAd->ate.TxWI.ShortGI = 0; ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_GI_Proc::Out of range\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_GI_Proc (GI = %d)\n", pAd->ate.TxWI.ShortGI)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_GI_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++INT Set_ATE_RX_FER_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.bRxFer = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.bRxFer == 1) ++ { ++ pAd->ate.RxCntPerSec = 0; ++ pAd->ate.RxTotalCnt = 0; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_FER_Proc (bRxFer = %d)\n", pAd->ate.bRxFer)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_FER_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Read_RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print(KERN_EMERG "R1 = %lx\n", pAd->LatchRfRegs.R1); ++ ate_print(KERN_EMERG "R2 = %lx\n", pAd->LatchRfRegs.R2); ++ ate_print(KERN_EMERG "R3 = %lx\n", pAd->LatchRfRegs.R3); ++ ate_print(KERN_EMERG "R4 = %lx\n", pAd->LatchRfRegs.R4); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R1 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R2 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R3 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R4 = value; ++ RtmpRfIoWrite(pAd); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Load and Write EEPROM from a binary file prepared in advance. ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++#ifndef UCOS ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN ret = FALSE; ++ PUCHAR src = EEPROM_BIN_FILE_NAME; ++ struct file *srcf; ++ INT32 retval, orgfsuid, orgfsgid; ++ mm_segment_t orgfs; ++ USHORT WriteEEPROM[(EEPROM_SIZE/2)]; ++ UINT32 FileLength = 0; ++ UINT32 value = simple_strtol(arg, 0, 10); ++ ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value)); ++ ++ if (value > 0) ++ { ++ /* zero the e2p buffer */ ++ NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); ++ ++ /* save uid and gid used for filesystem access. ++ ** set user and group to 0 (root) ++ */ ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ /* as root */ ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ do ++ { ++ /* open the bin file */ ++ srcf = filp_open(src, O_RDONLY, 0); ++ ++ if (IS_ERR(srcf)) ++ { ++ ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src); ++ break; ++ } ++ ++ /* the object must have a read method */ ++ if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) ++ { ++ ate_print("%s - %s does not have a read method\n", __FUNCTION__, src); ++ break; ++ } ++ ++ /* read the firmware from the file *.bin */ ++ FileLength = srcf->f_op->read(srcf, ++ (PUCHAR)WriteEEPROM, ++ EEPROM_SIZE, ++ &srcf->f_pos); ++ ++ if (FileLength != EEPROM_SIZE) ++ { ++ ate_print("%s: error file length (=%d) in e2p.bin\n", ++ __FUNCTION__, FileLength); ++ break; ++ } ++ else ++ { ++ /* write the content of .bin file to EEPROM */ ++ rt_ee_write_all(pAd, WriteEEPROM); ++ ret = TRUE; ++ } ++ break; ++ } while(TRUE); ++ ++ /* close firmware file */ ++ if (IS_ERR(srcf)) ++ { ++ ; ++ } ++ else ++ { ++ retval = filp_close(srcf, NULL); ++ if (retval) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); ++ ++ } ++ } ++ ++ /* restore */ ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ } ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret)); ++ ++ return ret; ++ ++} ++#else ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT WriteEEPROM[(EEPROM_SIZE/2)]; ++ struct iwreq *wrq = (struct iwreq *)arg; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length)); ++ ++ if (wrq->u.data.length != EEPROM_SIZE) ++ { ++ ate_print("%s: error length (=%d) from host\n", ++ __FUNCTION__, wrq->u.data.length); ++ return FALSE; ++ } ++ else/* (wrq->u.data.length == EEPROM_SIZE) */ ++ { ++ /* zero the e2p buffer */ ++ NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); ++ ++ /* fill the local buffer */ ++ NdisMoveMemory((PUCHAR)WriteEEPROM, wrq->u.data.pointer, wrq->u.data.length); ++ ++ do ++ { ++ /* write the content of .bin file to EEPROM */ ++ rt_ee_write_all(pAd, WriteEEPROM); ++ ++ } while(FALSE); ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__)); ++ ++ return TRUE; ++ ++} ++#endif // !UCOS // ++ ++INT Set_ATE_Read_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT buffer[EEPROM_SIZE/2]; ++ USHORT *p; ++ int i; ++ ++ rt_ee_read_all(pAd, (USHORT *)buffer); ++ p = buffer; ++ for (i = 0; i < (EEPROM_SIZE/2); i++) ++ { ++ ate_print("%4.4x ", *p); ++ if (((i+1) % 16) == 0) ++ ate_print("\n"); ++ p++; ++ } ++ return TRUE; ++} ++ ++INT Set_ATE_Show_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print("Mode=%d\n", pAd->ate.Mode); ++ ate_print("TxPower0=%d\n", pAd->ate.TxPower0); ++ ate_print("TxPower1=%d\n", pAd->ate.TxPower1); ++ ate_print("TxAntennaSel=%d\n", pAd->ate.TxAntennaSel); ++ ate_print("RxAntennaSel=%d\n", pAd->ate.RxAntennaSel); ++ ate_print("BBPCurrentBW=%d\n", pAd->ate.TxWI.BW); ++ ate_print("GI=%d\n", pAd->ate.TxWI.ShortGI); ++ ate_print("MCS=%d\n", pAd->ate.TxWI.MCS); ++ ate_print("TxMode=%d\n", pAd->ate.TxWI.PHYMODE); ++ ate_print("Addr1=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr1[0], pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5]); ++ ate_print("Addr2=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr2[0], pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5]); ++ ate_print("Addr3=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr3[0], pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5]); ++ ate_print("Channel=%d\n", pAd->ate.Channel); ++ ate_print("TxLength=%d\n", pAd->ate.TxLength); ++ ate_print("TxCount=%u\n", pAd->ate.TxCount); ++ ate_print("RFFreqOffset=%d\n", pAd->ate.RFFreqOffset); ++ ate_print(KERN_EMERG "Set_ATE_Show_Proc Success\n"); ++ return TRUE; ++} ++ ++INT Set_ATE_Help_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print("ATE=ATESTART, ATESTOP, TXCONT, TXCARR, TXFRAME, RXFRAME\n"); ++ ate_print("ATEDA\n"); ++ ate_print("ATESA\n"); ++ ate_print("ATEBSSID\n"); ++ ate_print("ATECHANNEL, range:0~14(unless A band !)\n"); ++ ate_print("ATETXPOW0, set power level of antenna 1.\n"); ++ ate_print("ATETXPOW1, set power level of antenna 2.\n"); ++ ate_print("ATETXANT, set TX antenna. 0:all, 1:antenna one, 2:antenna two.\n"); ++ ate_print("ATERXANT, set RX antenna.0:all, 1:antenna one, 2:antenna two, 3:antenna three.\n"); ++ ate_print("ATETXFREQOFFSET, set frequency offset, range 0~63\n"); ++ ate_print("ATETXBW, set BandWidth, 0:20MHz, 1:40MHz.\n"); ++ ate_print("ATETXLEN, set Frame length, range 24~%d\n", (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ ate_print("ATETXCNT, set how many frame going to transmit.\n"); ++ ate_print("ATETXMCS, set MCS, reference to rate table.\n"); ++ ate_print("ATETXMODE, set Mode 0:CCK, 1:OFDM, 2:HT-Mix, 3:GreenField, reference to rate table.\n"); ++ ate_print("ATETXGI, set GI interval, 0:Long, 1:Short\n"); ++ ate_print("ATERXFER, 0:disable Rx Frame error rate. 1:enable Rx Frame error rate.\n"); ++ ate_print("ATERRF, show all RF registers.\n"); ++ ate_print("ATEWRF1, set RF1 register.\n"); ++ ate_print("ATEWRF2, set RF2 register.\n"); ++ ate_print("ATEWRF3, set RF3 register.\n"); ++ ate_print("ATEWRF4, set RF4 register.\n"); ++ ate_print("ATELDE2P, load EEPROM from .bin file.\n"); ++ ate_print("ATERE2P, display all EEPROM content.\n"); ++ ate_print("ATESHOW, display all parameters of ATE.\n"); ++ ate_print("ATEHELP, online help.\n"); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ AsicSwitchChannel() dedicated for ATE. ++ ++ ========================================================================== ++*/ ++VOID ATEAsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0, Value = 0; ++ CHAR TxPwer = 0, TxPwer2 = 0; ++ UCHAR index, BbpValue = 0, R66 = 0x30; ++ RTMP_RF_REGS *RFRegTable; ++ UCHAR Channel; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ if (pAd->ate.Channel != pAd->LatchRfRegs.Channel) ++ { ++ pAd->ate.Channel = pAd->LatchRfRegs.Channel; ++ } ++ return; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ Channel = pAd->ate.Channel; ++ ++ // Select antenna ++ AsicAntennaSelect(pAd, Channel); ++ ++ // fill Tx power value ++ TxPwer = pAd->ate.TxPower0; ++ TxPwer2 = pAd->ate.TxPower1; ++ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ /* But only 2850 and 2750 support 5.5GHz band... */ ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ switch (pAd->ate.RxAntennaSel) ++ { ++ case 1: ++ R2 |= 0x20040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x00; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 2: ++ R2 |= 0x10040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x01; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ default: ++ R2 |= 0x40; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ /* Only enable two Antenna to receive. */ ++ BbpValue |= 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ } ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ if (pAd->ate.TxAntennaSel == 1) ++ { ++ R2 |= 0x4000; // If TX Antenna select is 1 , bit 14 = 1; Disable Ant 2 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; //11100111B ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ else if (pAd->ate.TxAntennaSel == 2) ++ { ++ R2 |= 0x8000; // If TX Antenna select is 2 , bit 15 = 1; Disable Ant 1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; ++ BbpValue |= 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ else ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; ++ BbpValue |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ } ++ if (pAd->Antenna.field.RxPath == 3) ++ { ++ switch (pAd->ate.RxAntennaSel) ++ { ++ case 1: ++ R2 |= 0x20040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x00; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 2: ++ R2 |= 0x10040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x01; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 3: ++ R2 |= 0x30000; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x02; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ default: ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ } ++ } ++ ++ if (Channel > 14) ++ { ++ // initialize R3, R4 ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff); ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15); ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ // 5.5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB ++ // R3 ++ if ((TxPwer >= -7) && (TxPwer < 0)) ++ { ++ TxPwer = (7+TxPwer); ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer=%d \n", TxPwer)); ++ } ++ else ++ { ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10) | (1 << 9); ++ } ++ ++ // R4 ++ if ((TxPwer2 >= -7) && (TxPwer2 < 0)) ++ { ++ TxPwer2 = (7+TxPwer2); ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); ++ } ++ else ++ { ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7) | (1 << 6); ++ } ++ } ++ else ++ { ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15) | (TxPwer2 <<6);// Set freq offset & TxPwr1 ++ } ++ ++ // Based on BBP current mode before changing RF channel. ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ R4 |=0x200000; ++ } ++ ++ // Update variables ++ pAd->LatchRfRegs.Channel = Channel; ++ pAd->LatchRfRegs.R1 = RFRegTable[index].R1; ++ pAd->LatchRfRegs.R2 = R2; ++ pAd->LatchRfRegs.R3 = R3; ++ pAd->LatchRfRegs.R4 = R4; ++ ++ RtmpRfIoWrite(pAd); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ // Change BBP setting during switch from a->g, g->a ++ if (Channel <= 14) ++ { ++ ULONG TxPinCfg = 0x00050F0A;// 2007.10.09 by Brian : 0x0005050A ==> 0x00050F0A ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ ++ /* For 1T/2R chip only... */ ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ } ++ else ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); ++ } ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ if ((BbpValue != 0x00)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); ++ } ++ ++ // 5.5GHz band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x04); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R. ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ else ++ { ++ ULONG TxPinCfg = 0x00050F05;//2007.10.09 by Brian : 0x00050505 ==> 0x00050F05 ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ if ((BbpValue != 0x00)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); ++ } ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R91, &BbpValue); ++ ASSERT((BbpValue == 0x04)); ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R92, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ ++ // 5.5GHz band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x02); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R. ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ ++ // R66 should be set according to Channel and use 20MHz when scanning ++ if (Channel <= 14) ++ { ++ // BG band ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { ++ // 5.5 GHz band ++ if (pAd->ate.TxWI.BW == BW_20) ++ { ++ R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { ++ R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ ++ // ++ // On 11A, We should delay and wait RF/BBP to be stable ++ // and the appropriate time should be 1000 micro seconds ++ // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. ++ // ++ RTMPusecDelay(1000); ++ ++ if (Channel > 14) ++ { ++ // When 5.5GHz band the LSB of TxPwr will be used to reduced 7dB or not. ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%u, Pwr1=%u, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ (R3 & 0x00003e00) >> 9, ++ (R4 & 0x000007c0) >> 6, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++ } ++} ++ ++// ++// In fact, no one will call this routine so far ! ++// ++/* ++ ========================================================================== ++ Description: ++ Gives CCK TX rate 2 more dB TX power. ++ This routine works only in ATE mode. ++ ++ calculate desired Tx power in RF R3.Tx0~5, should consider - ++ 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) ++ 1. TxPowerPercentage ++ 2. auto calibration based on TSSI feedback ++ 3. extra 2 db for CCK ++ 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP ++ ++ NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), ++ it should be called AFTER MlmeDynamicTxRateSwitching() ++ ========================================================================== ++ */ ++VOID ATEAsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i, j; ++ CHAR DeltaPwr = 0; ++ BOOLEAN bAutoTxAgc = FALSE; ++ UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; ++ UCHAR BbpR49 = 0, idx; ++ PCHAR pTxAgcCompensate; ++ ULONG TxPwr[5]; ++ CHAR Value; ++ ++ /* no one calls this procedure so far */ ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ if (pAd->ate.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; ++ } ++ } ++ else ++ { ++ if (pAd->ate.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; ++ } ++ } ++ ++ // TX power compensation for temperature variation based on TSSI. ++ // Do it per 4 seconds. ++ if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ /* bg channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ TssiRef = pAd->TssiRefG; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; ++ TxAgcStep = pAd->TxAgcStepG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ /* a channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ TssiRef = pAd->TssiRefA; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; ++ TxAgcStep = pAd->TxAgcStepA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ { ++ /* BbpR49 is unsigned char */ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); ++ ++ /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ ++ /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ ++ /* step value is defined in pAd->TxAgcStepG for tx power value */ ++ ++ /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ ++ /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ above value are examined in mass factory production */ ++ /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ ++ ++ /* plus is 0x10 ~ 0x40, minus is 0x60 ~ 0x90 */ ++ /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ ++ /* if value is 0x65, tx power will be -= TxAgcStep*(2-1) */ ++ ++ if (BbpR49 > pTssiMinusBoundary[1]) ++ { ++ // Reading is larger than the reference value. ++ // Check for how large we need to decrease the Tx power. ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should decrease, idx = 0 means there is nothing to compensate ++// if (R3 > (ULONG) (TxAgcStep * (idx-1))) ++ *pTxAgcCompensate = -(TxAgcStep * (idx-1)); ++// else ++// *pTxAgcCompensate = -((UCHAR)R3); ++ ++ DeltaPwr += (*pTxAgcCompensate); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else if (BbpR49 < pTssiPlusBoundary[1]) ++ { ++ // Reading is smaller than the reference value ++ // check for how large we need to increase the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should increase, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = TxAgcStep * (idx-1); ++ DeltaPwr += (*pTxAgcCompensate); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else ++ { ++ *pTxAgcCompensate = 0; ++ ATEDBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, 0)); ++ } ++ } ++ } ++ else ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ DeltaPwr += (*pTxAgcCompensate); ++ } ++ ++ /* calculate delta power based on the percentage specified from UI */ ++ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) ++ // We lower TX power here according to the percentage specified from UI ++ if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW ++ { ++ DeltaPwr -= 1; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW ++ { ++ DeltaPwr -= 3; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW ++ { ++ DeltaPwr -= 6; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW ++ { ++ DeltaPwr -= 9; ++ } ++ else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW ++ { ++ DeltaPwr -= 12; ++ } ++ ++ /* reset different new tx power for different TX rate */ ++ for(i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ ++ ++ if ((Value + DeltaPwr) < 0) ++ { ++ Value = 0; /* min */ ++ } ++ else if ((Value + DeltaPwr) > 0xF) ++ { ++ Value = 0xF; /* max */ ++ } ++ else ++ { ++ Value += DeltaPwr; /* temperature compensation */ ++ } ++ ++ /* fill new value to CSR offset */ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ ++ /* write tx power value to CSR */ ++ /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M ++ TX power for OFDM 6M/9M ++ TX power for CCK5.5M/11M ++ TX power for CCK1M/2M */ ++ /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); ++ ++ ++ } ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Write TxWI for ATE mode. ++ ++ Return Value: ++ None ++ ======================================================================== ++*/ ++ ++#ifdef RT2870 ++static VOID ATEWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR MIMOps, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING Transmit) ++{ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ pTxWI->FRAG= FRAG; ++ pTxWI->TS= InsTimestamp; ++ pTxWI->AMPDU = AMPDU; ++ ++ pTxWI->MIMOps = PWR_ACTIVE; ++ pTxWI->MpduDensity = 4; ++ pTxWI->ACK = Ack; ++ pTxWI->txop = Txopmode; ++ pTxWI->NSEQ = NSeq; ++ pTxWI->BAWinSize = BASize; ++ ++ pTxWI->WirelessCliID = WCID; ++ pTxWI->MPDUtotalByteCount = Length; ++ pTxWI->PacketId = PID; ++ ++ pTxWI->BW = Transmit.field.BW; ++ pTxWI->ShortGI = Transmit.field.ShortGI; ++ pTxWI->STBC= Transmit.field.STBC; ++ ++ pTxWI->MCS = Transmit.field.MCS; ++ pTxWI->PHYMODE= Transmit.field.MODE; ++ ++#ifdef DOT11_N_SUPPORT ++ // ++ // MMPS is 802.11n features. Because TxWI->MCS > 7 must be HT mode, ++ // so need not check if it's HT rate. ++ // ++ if ((MIMOps == MMPS_STATIC) && (pTxWI->MCS > 7)) ++ pTxWI->MCS = 7; ++ ++ if ((MIMOps == MMPS_DYNAMIC) && (pTxWI->MCS > 7)) // SMPS protect 2 spatial. ++ pTxWI->MIMOps = 1; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->CFACK = CfAck; ++ ++ return; ++} ++#endif // RT2870 // ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Disable protection for ATE. ++ ======================================================================== ++*/ ++VOID ATEDisableAsicProtect( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PROT_CFG_STRUC ProtCfg, ProtCfg4; ++ UINT32 Protect[6]; ++ USHORT offset; ++ UCHAR i; ++ UINT32 MacReg = 0; ++ ++ // Config ASIC RTS threshold register ++ RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); ++ MacReg &= 0xFF0000FF; ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++ RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); ++ ++ // Initial common protection settings ++ RTMPZeroMemory(Protect, sizeof(Protect)); ++ ProtCfg4.word = 0; ++ ProtCfg.word = 0; ++ ProtCfg.field.TxopAllowGF40 = 1; ++ ProtCfg.field.TxopAllowGF20 = 1; ++ ProtCfg.field.TxopAllowMM40 = 1; ++ ProtCfg.field.TxopAllowMM20 = 1; ++ ProtCfg.field.TxopAllowOfdm = 1; ++ ProtCfg.field.TxopAllowCck = 1; ++ ProtCfg.field.RTSThEn = 1; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ++ // Handle legacy(B/G) protection ++ ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; ++ Protect[0] = ProtCfg.word; ++ Protect[1] = ProtCfg.word; ++ ++ // NO PROTECT ++ // 1.All STAs in the BSS are 20/40 MHz HT ++ // 2. in ai 20/40MHz BSS ++ // 3. all STAs are 20MHz in a 20MHz BSS ++ // Pure HT. no protection. ++ ++ // MM20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[2] = 0x01744004; ++ ++ // MM40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[3] = 0x03f44084; ++ ++ // CF20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[4] = 0x01744004; ++ ++ // CF40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[5] = 0x03f44084; ++ ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ ++ offset = CCK_PROT_CFG; ++ for (i = 0;i < 6;i++) ++ RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); ++ ++} ++ ++#ifdef RT2870 ++/* ++ ======================================================================== ++ Routine Description: ++ Write TxInfo for ATE mode. ++ ++ Return Value: ++ None ++ ======================================================================== ++*/ ++static VOID ATEWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst) ++{ ++ pTxInfo->USBDMATxPktLen = USBDMApktLen; ++ pTxInfo->QSEL = QueueSel; ++ ++ if (QueueSel != FIFO_EDCA) ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("=======> QueueSel != FIFO_EDCA<=======\n")); ++ ++ pTxInfo->USBDMANextVLD = NextValid; ++ pTxInfo->USBDMATxburst = TxBurst; ++ pTxInfo->WIV = bWiv; ++ pTxInfo->SwUseLastRound = 0; ++ pTxInfo->rsv = 0; ++ pTxInfo->rsv2 = 0; ++ ++ return; ++} ++#endif // RT2870 // ++ ++/* There are two ways to convert Rssi */ ++#if 1 ++// ++// The way used with GET_LNA_GAIN(). ++// ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ LNAGain = GET_LNA_GAIN(pAd); ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-12 - RssiOffset - LNAGain - Rssi); ++} ++#else ++// ++// The way originally used in ATE of rt2860ap. ++// ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ LNAGain = pAd->ALNAGain; ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ LNAGain = pAd->BLNAGain; ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-32 - RssiOffset + LNAGain - Rssi); ++} ++#endif /* end of #if 1 */ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set Japan filter coefficients if needed. ++ Note: ++ This routine should only be called when ++ entering TXFRAME mode or TXCONT mode. ++ ++ ======================================================================== ++*/ ++static VOID SetJapanFilter( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BbpData = 0; ++ ++ // ++ // If Channel=14 and Bandwidth=20M and Mode=CCK, set BBP R4 bit5=1 ++ // (Japan Tx filter coefficients)when (TXFRAME or TXCONT). ++ // ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BbpData); ++ ++ if ((pAd->ate.TxWI.PHYMODE == MODE_CCK) && (pAd->ate.Channel == 14) && (pAd->ate.TxWI.BW == BW_20)) ++ { ++ BbpData |= 0x20; // turn on ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SetJapanFilter!!!\n")); ++ } ++ else ++ { ++ BbpData &= 0xdf; // turn off ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ClearJapanFilter!!!\n")); ++ } ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BbpData); ++} ++ ++VOID ATESampleRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI) ++{ ++ /* There are two ways to collect RSSI. */ ++#if 1 ++ //pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; ++ if (pRxWI->RSSI0 != 0) ++ { ++ pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); ++ pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; ++ pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; ++ } ++ if (pRxWI->RSSI1 != 0) ++ { ++ pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); ++ pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; ++ pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; ++ } ++ if (pRxWI->RSSI2 != 0) ++ { ++ pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); ++ pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; ++ pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; ++ } ++ ++ pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0);// CHAR ==> UCHAR ? ++ pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1);// CHAR ==> UCHAR ? ++ ++ pAd->ate.NumOfAvgRssiSample ++; ++#else ++ pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0); ++ pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1); ++ pAd->ate.RxCntPerSec++; ++ pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); ++ pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); ++ pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); ++ pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; ++ pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; ++ pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; ++ pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; ++ pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; ++ pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; ++ pAd->ate.NumOfAvgRssiSample ++; ++#endif ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPStationStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++// BOOLEAN Cancelled; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStop\n")); ++ ++#if 0 ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++#endif ++ // For rx statistics, we need to keep this timer running. ++// RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStop\n")); ++} ++ ++VOID RTMPStationStart( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Setup Frame format. ++ NOTE: ++ This routine should only be used in ATE mode. ++ ========================================================================== ++ */ ++ ++#ifdef RT2870 ++/*======================Start of RT2870======================*/ ++/* */ ++/* */ ++static INT ATESetUpFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TxIdx) ++{ ++ UINT j; ++ PTX_CONTEXT pNullContext; ++ PUCHAR pDest; ++ HTTRANSMIT_SETTING TxHTPhyMode; ++ PTXWI_STRUC pTxWI; ++ PTXINFO_STRUC pTxInfo; ++ UINT32 TransferBufferLength, OrgBufferLength = 0; ++ UCHAR padLen = 0; ++#ifdef RALINK_28xx_QA ++ PHEADER_802_11 pHeader80211 = NULL; ++#endif // RALINK_28xx_QA // ++ ++ if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ return -1; ++ } ++ ++ /* We always use QID_AC_BE and FIFO_EDCA in ATE mode. */ ++ ++ pNullContext = &(pAd->NullContext); ++ ASSERT(pNullContext != NULL); ++ ++ if (pNullContext->InUse == FALSE) ++ { ++ // Set the in use bit ++ pNullContext->InUse = TRUE; ++ NdisZeroMemory(&(pAd->NullFrame), sizeof(HEADER_802_11)); ++ ++ // Fill 802.11 header. ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pHeader80211 = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); ++// pDest = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); ++// pHeader80211 = (PHEADER_802_11)pDest; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ // Fill 802.11 header. ++ NdisMoveMemory(&(pAd->NullFrame), TemplateFrame, sizeof(HEADER_802_11)); ++ } ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)&(pAd->NullFrame), DIR_READ, FALSE); ++#endif // RT_BIG_ENDIAN // ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ /* modify sequence number.... */ ++ if (pAd->ate.TxDoneCount == 0) ++ { ++ pAd->ate.seq = pHeader80211->Sequence; ++ } ++ else ++ { ++ pHeader80211->Sequence = ++pAd->ate.seq; ++ } ++ /* We already got all the addr. fields from QA GUI. */ ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->ate.Addr1); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->ate.Addr2); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->ate.Addr3); ++ } ++ ++ RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], TX_BUFFER_NORMSIZE);//??? ++ pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // Avoid to exceed the range of WirelessPacket[]. ++ ASSERT(pAd->ate.TxInfo.USBDMATxPktLen <= (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ NdisMoveMemory(pTxInfo, &(pAd->ate.TxInfo), sizeof(pAd->ate.TxInfo)); ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ // Avoid to exceed the range of WirelessPacket[]. ++ ASSERT(pAd->ate.TxLength <= (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ ++ // pTxInfo->USBDMATxPktLen will be updated to include padding later. ++ ATEWriteTxInfo(pAd, pTxInfo, (USHORT)(TXWI_SIZE + pAd->ate.TxLength), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxInfo->QSEL = FIFO_EDCA; ++ } ++ ++ pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; ++ ++ // Fill TxWI. ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; ++ TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; ++ TxHTPhyMode.field.STBC = pAd->ate.TxWI.STBC; ++ TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; ++ TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; ++ ATEWriteTxWI(pAd, pTxWI, pAd->ate.TxWI.FRAG, pAd->ate.TxWI.TS, pAd->ate.TxWI.AMPDU, pAd->ate.TxWI.ACK, pAd->ate.TxWI.NSEQ, ++ pAd->ate.TxWI.BAWinSize, BSSID_WCID, pAd->ate.TxWI.MPDUtotalByteCount/* include 802.11 header */, pAd->ate.TxWI.PacketId, 0, pAd->ate.TxWI.txop/*IFS_HTTXOP*/, pAd->ate.TxWI.CFACK/*FALSE*/, TxHTPhyMode); ++ } ++ else ++ { ++ TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; ++ TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; ++ TxHTPhyMode.field.STBC = 0; ++ TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; ++ TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; ++ ++ ATEWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE/* No ack required. */, FALSE, 0, BSSID_WCID, pAd->ate.TxLength, ++ 0, 0, IFS_HTTXOP, FALSE, TxHTPhyMode);// "MMPS_STATIC" instead of "MMPS_DYNAMIC" ??? ++ } ++ ++ RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); ++ ++ pDest = &(pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE+sizeof(HEADER_802_11)]); ++ ++ // Prepare frame payload ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // copy pattern ++ if ((pAd->ate.PLen != 0)) ++ { ++ for (j = 0; j < pAd->ate.DLen; j+=pAd->ate.PLen) ++ { ++ RTMPMoveMemory(pDest, pAd->ate.Pattern, pAd->ate.PLen); ++ pDest += pAd->ate.PLen; ++ } ++ } ++ TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxWI.MPDUtotalByteCount; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ for (j = 0; j < (pAd->ate.TxLength - sizeof(HEADER_802_11)); j++) ++ { ++ *pDest = 0xA5; ++ pDest += 1; ++ } ++ TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxLength; ++ } ++ ++#if 1 ++ OrgBufferLength = TransferBufferLength; ++ TransferBufferLength = (TransferBufferLength + 3) & (~3); ++ ++ // Always add 4 extra bytes at every packet. ++ padLen = TransferBufferLength - OrgBufferLength + 4;/* 4 == last packet padding */ ++ ASSERT((padLen <= (RTMP_PKT_TAIL_PADDING - 4/* 4 == MaxBulkOutsize alignment padding */))); ++ ++ /* Now memzero all extra padding bytes. */ ++ NdisZeroMemory(pDest, padLen); ++ pDest += padLen; ++#else ++ if ((TransferBufferLength % 4) == 1) ++ { ++ NdisZeroMemory(pDest, 7); ++ pDest += 7; ++ TransferBufferLength += 3; ++ } ++ else if ((TransferBufferLength % 4) == 2) ++ { ++ NdisZeroMemory(pDest, 6); ++ pDest += 6; ++ TransferBufferLength += 2; ++ } ++ else if ((TransferBufferLength % 4) == 3) ++ { ++ NdisZeroMemory(pDest, 5); ++ pDest += 5; ++ TransferBufferLength += 1; ++ } ++#endif // 1 // ++ ++ // Update pTxInfo->USBDMATxPktLen to include padding. ++ pTxInfo->USBDMATxPktLen = TransferBufferLength - TXINFO_SIZE; ++ ++ TransferBufferLength += 4; ++ ++ // If TransferBufferLength is multiple of 64, add extra 4 bytes again. ++ if ((TransferBufferLength % pAd->BulkOutMaxPacketSize) == 0) ++ { ++ NdisZeroMemory(pDest, 4); ++ TransferBufferLength += 4; ++ } ++ ++ // Fill out frame length information for global Bulk out arbitor ++ pAd->NullContext.BulkOutSize = TransferBufferLength; ++ } ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++ RTMPFrameEndianChange(pAd, (((PUCHAR)pTxInfo)+TXWI_SIZE+TXINFO_SIZE), DIR_WRITE, FALSE); ++ RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ return 0; ++} ++ ++VOID ATE_RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pNullContext; ++ UCHAR BulkOutPipeId; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ULONG OldValue; ++ ++ pNullContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pNullContext->pAd; ++ ++ ++ // Reset Null frame context flags ++ pNullContext->IRPPending = FALSE; ++ pNullContext->InUse = FALSE; ++ Status = pUrb->status; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pNullContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++#ifdef RALINK_28xx_QA ++ if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) ++ { ++ if (pAd->ate.QID == BulkOutPipeId) ++ { ++ // Let Rx can have a chance to break in during Tx process, ++ // especially for loopback mode in QA ATE. ++ // To trade off between tx performance and loopback mode integrity. ++ /* Q : Now Rx is handled by tasklet, do we still need this delay ? */ ++ /* Ans : Even tasklet is used, Rx/Tx < 1 if we do not delay for a while right here. */ ++ RTMPusecDelay(500); ++ pAd->ate.TxDoneCount++; ++ pAd->RalinkCounters.KickTxCount++; ++ ASSERT(pAd->ate.QID == 0); ++ pAd->ate.TxAc0++; ++ } ++ } ++#endif // RALINK_28xx_QA // ++ pAd->BulkOutComplete++; ++ ++ pAd->Counters8023.GoodTransmits++; ++ ++ /* Don't worry about the queue is empty or not. This function will check itself. */ ++ RTMPDeQueuePacket(pAd, TRUE, BulkOutPipeId, MAX_TX_PROCESS); ++ ++ /* In 28xx, SendTxWaitQueue ==> TxSwQueue */ ++/* ++ if (pAd->SendTxWaitQueue[BulkOutPipeId].Number > 0) ++ { ++ RTMPDeQueuePacket(pAd, BulkOutPipeId); ++ } ++*/ ++ } ++ else // STATUS_OTHER ++ { ++ pAd->BulkOutCompleteOther++; ++ ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("BulkOutDataPacket Failed STATUS_OTHER = 0x%x . \n", Status)); ++ ATEDBGPRINT(RT_DEBUG_ERROR, (">>BulkOutReq=0x%lx, BulkOutComplete=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete)); ++ ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ /* In 28xx, RT_OID_USB_RESET_BULK_OUT ==> CMDTHREAD_RESET_BULK_OUT */ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ // Check ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pAd->bulkResetPipeid = BulkOutPipeId; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ } ++ ++ ++ ++ if (atomic_read(&pAd->BulkOutRemained) > 0) ++ { ++ atomic_dec(&pAd->BulkOutRemained); ++ } ++ ++ // 1st - Transmit Success ++ OldValue = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart++; ++ ++ if (pAd->WlanCounters.TransmittedFragmentCount.u.LowPart < OldValue) ++ { ++ pAd->WlanCounters.TransmittedFragmentCount.u.HighPart++; ++ } ++ ++ if(((pAd->ContinBulkOut == TRUE ) ||(atomic_read(&pAd->BulkOutRemained) > 0)) && (pAd->ate.Mode & ATE_TXFRAME)) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ } ++ else ++ { ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++#ifdef RALINK_28xx_QA ++ pAd->ate.TxStatus = 0; ++#endif // RALINK_28xx_QA // ++ } ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protection of rest bulk should be in BulkOut routine. ++ RTUSBKickBulkOut(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ATE_RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId) ++{ ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ ++ ASSERT(BulkOutPipeId == 0); ++ ++ /* Build up the frame first. */ ++// ATESetUpFrame(pAd, 0); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ if (pAd->BulkOutPending[BulkOutPipeId] == TRUE) ++ { ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ ++ pAd->BulkOutPending[BulkOutPipeId] = TRUE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.OneSecTransmittedByteCount += pNullContext->BulkOutSize; ++ pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; ++ ++ // Clear ATE frame bulk out flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ ++ // Init Tx context descriptor ++ pNullContext->IRPPending = TRUE; ++ RTUSBInitTxDesc(pAd, pNullContext, BulkOutPipeId, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); ++ pUrb = pNullContext->pUrb; ++ ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++ pAd->BulkOutReq++; ++ return; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ATE_RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ UINT i; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("--->ATE_RTUSBCancelPendingBulkInIRP\n")); ++#if 1 ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ pRxContext = &(pAd->RxContext[i]); ++ if(pRxContext->IRPPending == TRUE) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ pRxContext->IRPPending = FALSE; ++ pRxContext->InUse = FALSE; ++ //NdisInterlockedDecrement(&pAd->PendingRx); ++ //pAd->PendingRx--; ++ } ++ } ++#else ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ pRxContext = &(pAd->RxContext[i]); ++ if(atomic_read(&pRxContext->IrpLock) == IRPLOCK_CANCELABLE) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ } ++ InterlockedExchange(&pRxContext->IrpLock, IRPLOCK_CANCE_START); ++ } ++#endif // 1 // ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<---ATE_RTUSBCancelPendingBulkInIRP\n")); ++ return; ++} ++#endif // RT2870 // ++ ++VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) ++{ ++ USHORT i; ++ USHORT value; ++ ++ for (i = 0 ; i < EEPROM_SIZE/2 ; ) ++ { ++ /* "value" is expecially for some compilers... */ ++ RT28xx_EEPROM_READ16(pAd, i*2, value); ++ Data[i] = value; ++ i++; ++ } ++} ++ ++VOID rt_ee_write_all(PRTMP_ADAPTER pAd, USHORT *Data) ++{ ++ USHORT i; ++ USHORT value; ++ ++ for (i = 0 ; i < EEPROM_SIZE/2 ; ) ++ { ++ /* "value" is expecially for some compilers... */ ++ value = Data[i]; ++ RT28xx_EEPROM_WRITE16(pAd, i*2, value); ++ i ++; ++ } ++} ++#ifdef RALINK_28xx_QA ++VOID ATE_QA_Statistics( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN PHEADER_802_11 pHeader) ++{ ++ // update counter first ++ if (pHeader != NULL) ++ { ++ if (pHeader->FC.Type == BTYPE_DATA) ++ { ++ if (pRxD->U2M) ++ pAd->ate.U2M++; ++ else ++ pAd->ate.OtherData++; ++ } ++ else if (pHeader->FC.Type == BTYPE_MGMT) ++ { ++ if (pHeader->FC.SubType == SUBTYPE_BEACON) ++ pAd->ate.Beacon++; ++ else ++ pAd->ate.OtherCount++; ++ } ++ else if (pHeader->FC.Type == BTYPE_CNTL) ++ { ++ pAd->ate.OtherCount++; ++ } ++ } ++ pAd->ate.RSSI0 = pRxWI->RSSI0; ++ pAd->ate.RSSI1 = pRxWI->RSSI1; ++ pAd->ate.RSSI2 = pRxWI->RSSI2; ++ pAd->ate.SNR0 = pRxWI->SNR0; ++ pAd->ate.SNR1 = pRxWI->SNR1; ++} ++ ++/* command id with Cmd Type == 0x0008(for 28xx)/0x0005(for iNIC) */ ++#define RACFG_CMD_RF_WRITE_ALL 0x0000 ++#define RACFG_CMD_E2PROM_READ16 0x0001 ++#define RACFG_CMD_E2PROM_WRITE16 0x0002 ++#define RACFG_CMD_E2PROM_READ_ALL 0x0003 ++#define RACFG_CMD_E2PROM_WRITE_ALL 0x0004 ++#define RACFG_CMD_IO_READ 0x0005 ++#define RACFG_CMD_IO_WRITE 0x0006 ++#define RACFG_CMD_IO_READ_BULK 0x0007 ++#define RACFG_CMD_BBP_READ8 0x0008 ++#define RACFG_CMD_BBP_WRITE8 0x0009 ++#define RACFG_CMD_BBP_READ_ALL 0x000a ++#define RACFG_CMD_GET_COUNTER 0x000b ++#define RACFG_CMD_CLEAR_COUNTER 0x000c ++ ++#define RACFG_CMD_RSV1 0x000d ++#define RACFG_CMD_RSV2 0x000e ++#define RACFG_CMD_RSV3 0x000f ++ ++#define RACFG_CMD_TX_START 0x0010 ++#define RACFG_CMD_GET_TX_STATUS 0x0011 ++#define RACFG_CMD_TX_STOP 0x0012 ++#define RACFG_CMD_RX_START 0x0013 ++#define RACFG_CMD_RX_STOP 0x0014 ++#define RACFG_CMD_GET_NOISE_LEVEL 0x0015 ++ ++#define RACFG_CMD_ATE_START 0x0080 ++#define RACFG_CMD_ATE_STOP 0x0081 ++ ++#define RACFG_CMD_ATE_START_TX_CARRIER 0x0100 ++#define RACFG_CMD_ATE_START_TX_CONT 0x0101 ++#define RACFG_CMD_ATE_START_TX_FRAME 0x0102 ++#define RACFG_CMD_ATE_SET_BW 0x0103 ++#define RACFG_CMD_ATE_SET_TX_POWER0 0x0104 ++#define RACFG_CMD_ATE_SET_TX_POWER1 0x0105 ++#define RACFG_CMD_ATE_SET_FREQ_OFFSET 0x0106 ++#define RACFG_CMD_ATE_GET_STATISTICS 0x0107 ++#define RACFG_CMD_ATE_RESET_COUNTER 0x0108 ++#define RACFG_CMD_ATE_SEL_TX_ANTENNA 0x0109 ++#define RACFG_CMD_ATE_SEL_RX_ANTENNA 0x010a ++#define RACFG_CMD_ATE_SET_PREAMBLE 0x010b ++#define RACFG_CMD_ATE_SET_CHANNEL 0x010c ++#define RACFG_CMD_ATE_SET_ADDR1 0x010d ++#define RACFG_CMD_ATE_SET_ADDR2 0x010e ++#define RACFG_CMD_ATE_SET_ADDR3 0x010f ++#define RACFG_CMD_ATE_SET_RATE 0x0110 ++#define RACFG_CMD_ATE_SET_TX_FRAME_LEN 0x0111 ++#define RACFG_CMD_ATE_SET_TX_FRAME_COUNT 0x0112 ++#define RACFG_CMD_ATE_START_RX_FRAME 0x0113 ++#define RACFG_CMD_ATE_E2PROM_READ_BULK 0x0114 ++#define RACFG_CMD_ATE_E2PROM_WRITE_BULK 0x0115 ++#define RACFG_CMD_ATE_IO_WRITE_BULK 0x0116 ++#define RACFG_CMD_ATE_BBP_READ_BULK 0x0117 ++#define RACFG_CMD_ATE_BBP_WRITE_BULK 0x0118 ++#define RACFG_CMD_ATE_RF_READ_BULK 0x0119 ++#define RACFG_CMD_ATE_RF_WRITE_BULK 0x011a ++ ++ ++ ++#define A2Hex(_X, _p) \ ++{ \ ++ UCHAR *p; \ ++ _X = 0; \ ++ p = _p; \ ++ while (((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= '0') && (*p <= '9'))) \ ++ { \ ++ if ((*p >= 'a') && (*p <= 'f')) \ ++ _X = _X * 16 + *p - 87; \ ++ else if ((*p >= 'A') && (*p <= 'F')) \ ++ _X = _X * 16 + *p - 55; \ ++ else if ((*p >= '0') && (*p <= '9')) \ ++ _X = _X * 16 + *p - 48; \ ++ p++; \ ++ } \ ++} ++ ++ ++static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); ++static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); ++static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len); ++ ++#ifdef UCOS ++int ate_copy_to_user( ++ IN PUCHAR payload, ++ IN PUCHAR msg, ++ IN INT len) ++{ ++ memmove(payload, msg, len); ++ return 0; ++} ++ ++#undef copy_to_user ++#define copy_to_user(x,y,z) ate_copy_to_user((PUCHAR)x, (PUCHAR)y, z) ++#endif // UCOS // ++ ++#define LEN_OF_ARG 16 ++ ++VOID RtmpDoAte( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ unsigned short Command_Id; ++ struct ate_racfghdr *pRaCfg; ++ INT Status = NDIS_STATUS_SUCCESS; ++ ++ ++ ++ if((pRaCfg = kmalloc(sizeof(struct ate_racfghdr), GFP_KERNEL)) == NULL) ++ { ++ Status = -EINVAL; ++ return; ++ } ++ ++ NdisZeroMemory(pRaCfg, sizeof(struct ate_racfghdr)); ++ ++ if (copy_from_user((PUCHAR)pRaCfg, wrq->u.data.pointer, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ kfree(pRaCfg); ++ return; ++ } ++ ++ ++ Command_Id = ntohs(pRaCfg->command_id); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id)); ++ ++ switch (Command_Id) ++ { ++ // We will get this command when QA starts. ++ case RACFG_CMD_ATE_START: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START\n")); ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_ATE_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START is done !\n")); ++ } ++ Set_ATE_Proc(pAdapter, "ATESTART"); ++ } ++ break; ++ ++ // We will get this command either QA is closed or ated is killed by user. ++ case RACFG_CMD_ATE_STOP: ++ { ++#ifndef UCOS ++ INT32 ret; ++#endif // !UCOS // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_STOP\n")); ++ ++ // Distinguish this command came from QA(via ated) ++ // or ate daemon according to the existence of pid in payload. ++ // No need to prepare feedback if this cmd came directly from ate daemon. ++ pRaCfg->length = ntohs(pRaCfg->length); ++ ++ if (pRaCfg->length == sizeof(pAdapter->ate.AtePid)) ++ { ++ // This command came from QA. ++ // Get the pid of ATE daemon. ++ memcpy((UCHAR *)&pAdapter->ate.AtePid, ++ (&pRaCfg->data[0]) - 2/* == &(pRaCfg->status) */, ++ sizeof(pAdapter->ate.AtePid)); ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_STOP\n")); ++ Status = -EFAULT; ++ } ++ ++ // ++ // kill ATE daemon when leaving ATE mode. ++ // We must kill ATE daemon first before setting ATESTOP, ++ // or Microsoft will report sth. wrong. ++#ifndef UCOS ++ ret = KILL_THREAD_PID(pAdapter->ate.AtePid, SIGTERM, 1); ++ if (ret) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("%s: unable to signal thread\n", pAdapter->net_dev->name)); ++ } ++#endif // !UCOS // ++ } ++ ++ // AP might have in ATE_STOP mode due to cmd from QA. ++ if (ATE_ON(pAdapter)) ++ { ++ // Someone has killed ate daemon while QA GUI is still open. ++ Set_ATE_Proc(pAdapter, "ATESTOP"); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_AP_START is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RF_WRITE_ALL: ++ { ++ UINT32 R1, R2, R3, R4; ++ USHORT channel; ++ ++ memcpy(&R1, pRaCfg->data-2, 4); ++ memcpy(&R2, pRaCfg->data+2, 4); ++ memcpy(&R3, pRaCfg->data+6, 4); ++ memcpy(&R4, pRaCfg->data+10, 4); ++ memcpy(&channel, pRaCfg->data+14, 2); ++ ++ pAdapter->LatchRfRegs.R1 = ntohl(R1); ++ pAdapter->LatchRfRegs.R2 = ntohl(R2); ++ pAdapter->LatchRfRegs.R3 = ntohl(R3); ++ pAdapter->LatchRfRegs.R4 = ntohl(R4); ++ pAdapter->LatchRfRegs.Channel = ntohs(channel); ++ ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R3); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R4); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RF_WRITE_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RF_WRITE_ALL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_READ16: ++ { ++ USHORT offset, value, tmp; ++ ++ offset = ntohs(pRaCfg->status); ++ /* "tmp" is expecially for some compilers... */ ++ RT28xx_EEPROM_READ16(pAdapter, offset, tmp); ++ value = tmp; ++ value = htons(value); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("EEPROM Read offset = 0x%04x, value = 0x%04x\n", offset, value)); ++ ++ // prepare feedback ++ pRaCfg->length = htons(4); ++ pRaCfg->status = htons(0); ++ memcpy(pRaCfg->data, &value, 2); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("sizeof(struct ate_racfghdr) = %d\n", sizeof(struct ate_racfghdr))); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ16\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ16 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_WRITE16: ++ { ++ USHORT offset, value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&value, pRaCfg->data, 2); ++ value = ntohs(value); ++ RT28xx_EEPROM_WRITE16(pAdapter, offset, value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE16\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_WRITE16 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_READ_ALL: ++ { ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer, EEPROM_SIZE); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+EEPROM_SIZE); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ_ALL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_WRITE_ALL: ++ { ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ NdisZeroMemory((UCHAR *)buffer, EEPROM_SIZE); ++ memcpy_exs(pAdapter, (UCHAR *)buffer, (UCHAR *)&pRaCfg->status, EEPROM_SIZE); ++ rt_ee_write_all(pAdapter,(USHORT *)buffer); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_E2PROM_WRITE_ALL is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_IO_READ: ++ { ++ UINT32 offset; ++ UINT32 value; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract the offset out. ++ offset &= 0x0000FFFF; ++ RTMP_IO_READ32(pAdapter, offset, &value); ++ value = htonl(value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(6); ++ pRaCfg->status = htons(0); ++ memcpy(pRaCfg->data, &value, 4); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_IO_WRITE: ++ { ++ UINT32 offset, value; ++ ++ memcpy(&offset, pRaCfg->data-2, 4); ++ memcpy(&value, pRaCfg->data+2, 4); ++ ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract out the offset. ++ offset &= 0x0000FFFF; ++ value = ntohl(value); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_IO_WRITE: offset = %x, value = %x\n", offset, value)); ++ RTMP_IO_WRITE32(pAdapter, offset, value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_WRITE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_WRITE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_IO_READ_BULK: ++ { ++ UINT32 offset; ++ USHORT len; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract the offset. ++ offset &= 0x0000FFFF; ++ memcpy(&len, pRaCfg->data+2, 2); ++ len = ntohs(len); ++ ++ if (len > 371) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("len is too large, make it smaller\n")); ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(1); ++ break; ++ } ++ ++ RTMP_IO_READ_BULK(pAdapter, pRaCfg->data, (UCHAR *)offset, len*4);// unit in four bytes ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len*4);// unit in four bytes ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ_BULK is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_BBP_READ8: ++ { ++ USHORT offset; ++ UCHAR value; ++ ++ value = 0; ++ offset = ntohs(pRaCfg->status); ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); ++ } ++ // prepare feedback ++ pRaCfg->length = htons(3); ++ pRaCfg->status = htons(0); ++ pRaCfg->data[0] = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("BBP value = %x\n", value)); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ8\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ8 is done !\n")); ++ } ++ } ++ break; ++ case RACFG_CMD_BBP_WRITE8: ++ { ++ USHORT offset; ++ UCHAR value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&value, pRaCfg->data, 1); ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); ++ } ++ ++ if ((offset == BBP_R1) || (offset == BBP_R3)) ++ { ++ SyncTxRxConfig(pAdapter, offset, value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_WRITE8\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_WRITE8 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_BBP_READ_ALL: ++ { ++ USHORT j; ++ ++ for (j = 0; j < 137; j++) ++ { ++ pRaCfg->data[j] = 0; ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+137); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ_ALL is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_ATE_E2PROM_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ if (offset + len <= EEPROM_SIZE) ++ memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer+offset, len); ++ else ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("exceed EEPROM size\n")); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_E2PROM_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_E2PROM_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ memcpy_exs(pAdapter, (UCHAR *)buffer + offset, (UCHAR *)pRaCfg->data + 2, len); ++ rt_ee_write_all(pAdapter,(USHORT *)buffer); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_E2PROM_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_IO_WRITE_BULK: ++ { ++ UINT32 offset, i, value; ++ USHORT len; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ memcpy(&len, pRaCfg->data+2, 2); ++ len = ntohs(len); ++ ++ for (i = 0; i < len; i += 4) ++ { ++ memcpy_exl(pAdapter, (UCHAR *)&value, pRaCfg->data+4+i, 4); ++ printk("Write %x %x\n", offset + i, value); ++ RTMP_IO_WRITE32(pAdapter, (offset +i) & 0xffff, value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_IO_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_IO_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_BBP_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ pRaCfg->data[j - offset] = 0; ++ ++ if (pAdapter->ate.Mode == ATE_STOP) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ else ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_BBP_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ UCHAR *value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ value = pRaCfg->data + 2 + (j - offset); ++ if (pAdapter->ate.Mode == ATE_STOP) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); ++ } ++ else ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_WRITE_BULK is done !\n")); ++ } ++ } ++ break; ++ ++#ifdef CONFIG_RALINK_RT3052 ++ case RACFG_CMD_ATE_RF_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ pRaCfg->data[j - offset] = 0; ++ RT30xxReadRFRegister(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_RF_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ UCHAR *value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ value = pRaCfg->data + 2 + (j - offset); ++ RT30xxWriteRFRegister(pAdapter, j, *value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++#endif ++ ++ ++ case RACFG_CMD_GET_NOISE_LEVEL: ++ { ++ UCHAR channel; ++ INT32 buffer[3][10];/* 3 : RxPath ; 10 : no. of per rssi samples */ ++ ++ channel = (ntohs(pRaCfg->status) & 0x00FF); ++ CalNoiseLevel(pAdapter, channel, buffer); ++ memcpy_exl(pAdapter, (UCHAR *)pRaCfg->data, (UCHAR *)&(buffer[0][0]), (sizeof(INT32)*3*10)); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2 + (sizeof(INT32)*3*10)); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_NOISE_LEVEL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_NOISE_LEVEL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_GET_COUNTER: ++ { ++ memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.U2M, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->ate.OtherData, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->ate.Beacon, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->ate.OtherCount, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->ate.TxAc0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->ate.TxAc1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->ate.TxAc2, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->ate.TxAc3, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->ate.TxHCCA, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->ate.TxMgmt, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&pAdapter->ate.RSSI0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&pAdapter->ate.RSSI1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&pAdapter->ate.RSSI2, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[52], (UCHAR *)&pAdapter->ate.SNR0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[56], (UCHAR *)&pAdapter->ate.SNR1, 4); ++ ++ pRaCfg->length = htons(2+60); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_COUNTER is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_CLEAR_COUNTER: ++ { ++ pAdapter->ate.U2M = 0; ++ pAdapter->ate.OtherData = 0; ++ pAdapter->ate.Beacon = 0; ++ pAdapter->ate.OtherCount = 0; ++ pAdapter->ate.TxAc0 = 0; ++ pAdapter->ate.TxAc1 = 0; ++ pAdapter->ate.TxAc2 = 0; ++ pAdapter->ate.TxAc3 = 0; ++ pAdapter->ate.TxHCCA = 0; ++ pAdapter->ate.TxMgmt = 0; ++ pAdapter->ate.TxDoneCount = 0; ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_CLEAR_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_CLEAR_COUNTER is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_TX_START: ++ { ++ USHORT *p; ++ USHORT err = 1; ++ UCHAR Bbp22Value = 0, Bbp24Value = 0; ++ ++ if ((pAdapter->ate.TxStatus != 0) && (pAdapter->ate.Mode & ATE_TXFRAME)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Ate Tx is already running, to run next Tx, you must stop it first\n")); ++ err = 2; ++ goto TX_START_ERROR; ++ } ++ else if ((pAdapter->ate.TxStatus != 0) && !(pAdapter->ate.Mode & ATE_TXFRAME)) ++ { ++ int i = 0; ++ ++ while ((i++ < 10) && (pAdapter->ate.TxStatus != 0)) ++ { ++ RTMPusecDelay(5000); ++ } ++ ++ // force it to stop ++ pAdapter->ate.TxStatus = 0; ++ pAdapter->ate.TxDoneCount = 0; ++ //pAdapter->ate.Repeat = 0; ++ pAdapter->ate.bQATxStart = FALSE; ++ } ++ ++ // If pRaCfg->length == 0, this "RACFG_CMD_TX_START" is for Carrier test or Carrier Suppression. ++ if (ntohs(pRaCfg->length) != 0) ++ { ++ // Get frame info ++#ifdef RT2870 ++ NdisMoveMemory(&pAdapter->ate.TxInfo, pRaCfg->data - 2, 4); ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR) &pAdapter->ate.TxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++#endif // RT2870 // ++ ++ NdisMoveMemory(&pAdapter->ate.TxWI, pRaCfg->data + 2, 16); ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)&pAdapter->ate.TxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ NdisMoveMemory(&pAdapter->ate.TxCount, pRaCfg->data + 18, 4); ++ pAdapter->ate.TxCount = ntohl(pAdapter->ate.TxCount); ++ ++ p = (USHORT *)(&pRaCfg->data[22]); ++ //p = pRaCfg->data + 22; ++ // always use QID_AC_BE ++ pAdapter->ate.QID = 0; ++ p = (USHORT *)(&pRaCfg->data[24]); ++ //p = pRaCfg->data + 24; ++ pAdapter->ate.HLen = ntohs(*p); ++ ++ if (pAdapter->ate.HLen > 32) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.HLen > 32\n")); ++ err = 3; ++ goto TX_START_ERROR; ++ } ++ ++ NdisMoveMemory(&pAdapter->ate.Header, pRaCfg->data + 26, pAdapter->ate.HLen); ++ ++ ++ pAdapter->ate.PLen = ntohs(pRaCfg->length) - (pAdapter->ate.HLen + 28); ++ ++ if (pAdapter->ate.PLen > 32) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.PLen > 32\n")); ++ err = 4; ++ goto TX_START_ERROR; ++ } ++ ++ NdisMoveMemory(&pAdapter->ate.Pattern, pRaCfg->data + 26 + pAdapter->ate.HLen, pAdapter->ate.PLen); ++ pAdapter->ate.DLen = pAdapter->ate.TxWI.MPDUtotalByteCount - pAdapter->ate.HLen; ++ } ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R22, &Bbp22Value); ++ ++ switch (Bbp22Value) ++ { ++ case BBP22_TXFRAME: ++ { ++ if (pAdapter->ate.TxCount == 0) ++ { ++ } ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXFRAME"); ++ } ++ break; ++ ++ case BBP22_TXCONT_OR_CARRSUPP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("BBP22_TXCONT_OR_CARRSUPP\n")); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, 24, &Bbp24Value); ++ ++ switch (Bbp24Value) ++ { ++ case BBP24_TXCONT: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCONT\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXCONT"); ++ } ++ break; ++ ++ case BBP24_CARRSUPP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARRSUPP\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ pAdapter->ate.Mode |= ATE_TXCARRSUPP; ++ } ++ break; ++ ++ default: ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); ++ } ++ break; ++ } ++ } ++ break; ++ ++ case BBP22_TXCARR: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARR\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXCARR"); ++ } ++ break; ++ ++ default: ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); ++ } ++ break; ++ } ++ ++ if (pAdapter->ate.bQATxStart == TRUE) ++ { ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() was failed in case RACFG_CMD_TX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_START is done !\n")); ++ } ++ break; ++ } ++ ++TX_START_ERROR: ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(err); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_TX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("feedback of TX_START_ERROR is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_GET_TX_STATUS: ++ { ++ UINT32 count; ++ ++ // prepare feedback ++ pRaCfg->length = htons(6); ++ pRaCfg->status = htons(0); ++ count = htonl(pAdapter->ate.TxDoneCount); ++ NdisMoveMemory(pRaCfg->data, &count, 4); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_TX_STATUS\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_TX_STATUS is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_TX_STOP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_TX_STOP\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXSTOP"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_TX_STOP\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_STOP is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RX_START: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); ++ ++ pAdapter->ate.bQARxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "RXFRAME"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RX_STOP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_STOP\n")); ++ ++ Set_ATE_Proc(pAdapter, "RXSTOP"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_STOP\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_STOP is done !\n")); ++ } ++ } ++ break; ++ ++ /* The following cases are for new ATE GUI(not QA). */ ++ /*==================================================*/ ++ case RACFG_CMD_ATE_START_TX_CARRIER: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CARRIER\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXCARR"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CARRIER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CARRIER is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_TX_CONT: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CONT\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXCONT"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CONT\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CONT is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_TX_FRAME: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_FRAME\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXFRAME"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_FRAME\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_FRAME is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_BW: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_BW\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ ++ Set_ATE_TX_BW_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_BW\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_BW is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_POWER0: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER0\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_POWER0_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER0\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER0 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_POWER1: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER1\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_POWER1_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER1\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER1 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_FREQ_OFFSET: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_FREQOFFSET_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_FREQ_OFFSET is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_GET_STATISTICS: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_GET_STATISTICS\n")); ++ ++ memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.TxDoneCount, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->WlanCounters.RetryCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->WlanCounters.FailedCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->WlanCounters.RTSSuccessCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->WlanCounters.RTSFailureCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->WlanCounters.FCSErrorCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->Counters8023.RxNoBuffer, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->RalinkCounters.OneSecFalseCCACnt, 4); ++ ++ if (pAdapter->ate.RxAntennaSel == 0) ++ { ++ INT32 RSSI0 = 0; ++ INT32 RSSI1 = 0; ++ INT32 RSSI2 = 0; ++ ++ RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); ++ RSSI1 = (INT32)(pAdapter->ate.LastRssi1 - pAdapter->BbpRssiToDbmDelta); ++ RSSI2 = (INT32)(pAdapter->ate.LastRssi2 - pAdapter->BbpRssiToDbmDelta); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&RSSI1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&RSSI2, 4); ++ pRaCfg->length = htons(2+52); ++ } ++ else ++ { ++ INT32 RSSI0 = 0; ++ ++ RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); ++ pRaCfg->length = htons(2+44); ++ } ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_GET_STATISTICS\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_GET_STATISTICS is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_RESET_COUNTER: ++ { ++ SHORT value = 1; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_RESET_COUNTER\n")); ++ ++ sprintf((PCHAR)str, "%d", value); ++ Set_ResetStatCounter_Proc(pAdapter, str); ++ ++ pAdapter->ate.TxDoneCount = 0; ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RESET_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RESET_COUNTER is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_ATE_SEL_TX_ANTENNA: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_Antenna_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_TX_ANTENNA is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SEL_RX_ANTENNA: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_RX_Antenna_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_RX_ANTENNA is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_PREAMBLE: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_PREAMBLE\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_MODE_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_PREAMBLE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_PREAMBLE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_CHANNEL: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_CHANNEL\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_CHANNEL_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_CHANNEL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_CHANNEL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR1: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR1\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr1, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR1\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR1 is done !\n (ADDR1 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr1[0], ++ pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR2: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR2\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr2, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR2\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR2 is done !\n (ADDR2 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr2[0], ++ pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR3: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR3\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr3, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR3\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR3 is done !\n (ADDR3 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr3[0], ++ pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_RATE: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_RATE\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_MCS_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_RATE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_RATE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_FRAME_LEN: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_LENGTH_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_LEN is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_FRAME_COUNT: ++ { ++ USHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ { ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_COUNT_Proc(pAdapter, str); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_COUNT is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_RX_FRAME: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); ++ ++ Set_ATE_Proc(pAdapter, "RXFRAME"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ ASSERT(pRaCfg != NULL); ++ if (pRaCfg != NULL) ++ { ++ kfree(pRaCfg); ++ } ++ return; ++} ++ ++VOID BubbleSort(INT32 n, INT32 a[]) ++{ ++ INT32 k, j, temp; ++ ++ for (k = n-1; k>0; k--) ++ { ++ for (j = 0; j a[j+1]) ++ { ++ temp = a[j]; ++ a[j]=a[j+1]; ++ a[j+1]=temp; ++ } ++ } ++ } ++} ++ ++VOID CalNoiseLevel(PRTMP_ADAPTER pAd, UCHAR channel, INT32 RSSI[3][10]) ++{ ++ INT32 RSSI0, RSSI1, RSSI2; ++ CHAR Rssi0Offset, Rssi1Offset, Rssi2Offset; ++ UCHAR BbpR50Rssi0 = 0, BbpR51Rssi1 = 0, BbpR52Rssi2 = 0; ++ UCHAR Org_BBP66value = 0, Org_BBP69value = 0, Org_BBP70value = 0, data = 0; ++ USHORT LNA_Gain = 0; ++ INT32 j = 0; ++ UCHAR Org_Channel = pAd->ate.Channel; ++ USHORT GainValue = 0, OffsetValue = 0; ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &Org_BBP66value); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R69, &Org_BBP69value); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R70, &Org_BBP70value); ++ ++ //********************************************************************** ++ // Read the value of LNA gain and Rssi offset ++ //********************************************************************** ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, GainValue); ++ ++ // for Noise Level ++ if (channel <= 14) ++ { ++ LNA_Gain = GainValue & 0x00FF; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, OffsetValue); ++ Rssi0Offset = OffsetValue & 0x00FF; ++ Rssi1Offset = (OffsetValue & 0xFF00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_BG_OFFSET + 2)/* 0x48 */, OffsetValue); ++ Rssi2Offset = OffsetValue & 0x00FF; ++ } ++ else ++ { ++ LNA_Gain = (GainValue & 0xFF00) >> 8; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, OffsetValue); ++ Rssi0Offset = OffsetValue & 0x00FF; ++ Rssi1Offset = (OffsetValue & 0xFF00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET + 2)/* 0x4C */, OffsetValue); ++ Rssi2Offset = OffsetValue & 0x00FF; ++ } ++ //********************************************************************** ++ { ++ pAd->ate.Channel = channel; ++ ATEAsicSwitchChannel(pAd); ++ mdelay(5); ++ ++ data = 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, data); ++ data = 0x40; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, data); ++ data = 0x40; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, data); ++ mdelay(5); ++ ++ // Start Rx ++ pAd->ate.bQARxStart = TRUE; ++ Set_ATE_Proc(pAd, "RXFRAME"); ++ ++ mdelay(5); ++ ++ for (j = 0; j < 10; j++) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &BbpR50Rssi0); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &BbpR51Rssi1); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &BbpR52Rssi2); ++ ++ mdelay(10); ++ ++ // Calculate RSSI 0 ++ if (BbpR50Rssi0 == 0) ++ { ++ RSSI0 = -100; ++ } ++ else ++ { ++ RSSI0 = (INT32)(-12 - BbpR50Rssi0 - LNA_Gain - Rssi0Offset); ++ } ++ RSSI[0][j] = RSSI0; ++ ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ // Calculate RSSI 1 ++ if (BbpR51Rssi1 == 0) ++ { ++ RSSI1 = -100; ++ } ++ else ++ { ++ RSSI1 = (INT32)(-12 - BbpR51Rssi1 - LNA_Gain - Rssi1Offset); ++ } ++ RSSI[1][j] = RSSI1; ++ } ++ ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ // Calculate RSSI 2 ++ if (BbpR52Rssi2 == 0) ++ RSSI2 = -100; ++ else ++ RSSI2 = (INT32)(-12 - BbpR52Rssi2 - LNA_Gain - Rssi2Offset); ++ ++ RSSI[2][j] = RSSI2; ++ } ++ } ++ ++ // Stop Rx ++ Set_ATE_Proc(pAd, "RXSTOP"); ++ ++ mdelay(5); ++ ++#if 0// Debug Message................ ++ ate_print("\n**********************************************************\n"); ++ ate_print("Noise Level: Channel %d\n", channel); ++ ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[0][0], RSSI[0][1], RSSI[0][2], ++ RSSI[0][3], RSSI[0][4], RSSI[0][5], ++ RSSI[0][6], RSSI[0][7], RSSI[0][8], ++ RSSI[0][9]); ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[1][0], RSSI[1][1], RSSI[1][2], ++ RSSI[1][3], RSSI[1][4], RSSI[1][5], ++ RSSI[1][6], RSSI[1][7], RSSI[1][8], ++ RSSI[1][9]); ++ } ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[2][0], RSSI[2][1], RSSI[2][2], ++ RSSI[2][3], RSSI[2][4], RSSI[2][5], ++ RSSI[2][6], RSSI[2][7], RSSI[2][8], ++ RSSI[2][9]); ++ } ++#endif // 0 // ++ BubbleSort(10, RSSI[0]); // 1R ++ ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ BubbleSort(10, RSSI[1]); ++ } ++ ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ BubbleSort(10, RSSI[2]); ++ } ++ ++#if 0// Debug Message................ ++ ate_print("\nAfter Sorting....Channel %d\n", channel); ++ ate_print("RSSI0 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[0][0], RSSI[0][1], RSSI[0][2], ++ RSSI[0][3], RSSI[0][4], RSSI[0][5], ++ RSSI[0][6], RSSI[0][7], RSSI[0][8], ++ RSSI[0][9]); ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ ate_print("RSSI1 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[1][0], RSSI[1][1], RSSI[1][2], ++ RSSI[1][3], RSSI[1][4], RSSI[1][5], ++ RSSI[1][6], RSSI[1][7], RSSI[1][8], ++ RSSI[1][9]); ++ } ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ ate_print("RSSI2 = %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", ++ RSSI[2][0], RSSI[2][1], RSSI[2][2], ++ RSSI[2][3], RSSI[2][4], RSSI[2][5], ++ RSSI[2][6], RSSI[2][7], RSSI[2][8], ++ RSSI[2][9]); ++ } ++ ate_print("**********************************************************\n"); ++#endif // 0 // ++ } ++ ++ pAd->ate.Channel = Org_Channel; ++ ATEAsicSwitchChannel(pAd); ++ ++ // Restore original value ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, Org_BBP66value); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, Org_BBP69value); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, Org_BBP70value); ++ ++ return; ++} ++ ++BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value) ++{ ++ UCHAR tmp = 0, bbp_data = 0; ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); ++ } ++ ++ /* confirm again */ ++ ASSERT(bbp_data == value); ++ ++ switch(offset) ++ { ++ case BBP_R1: ++ /* Need to sync. tx configuration with legacy ATE. */ ++ tmp = (bbp_data & ((1 << 4) | (1 << 3))/* 0x18 */) >> 3; ++ switch(tmp) ++ { ++ /* The BBP R1 bit[4:3] = 2 :: Both DACs will be used by QA. */ ++ case 2: ++ /* All */ ++ pAd->ate.TxAntennaSel = 0; ++ break; ++ /* The BBP R1 bit[4:3] = 0 :: DAC 0 will be used by QA. */ ++ case 0: ++ /* Antenna one */ ++ pAd->ate.TxAntennaSel = 1; ++ break; ++ /* The BBP R1 bit[4:3] = 1 :: DAC 1 will be used by QA. */ ++ case 1: ++ /* Antenna two */ ++ pAd->ate.TxAntennaSel = 2; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ } ++ break;/* case BBP_R1 */ ++ ++ case BBP_R3: ++ /* Need to sync. rx configuration with legacy ATE. */ ++ tmp = (bbp_data & ((1 << 1) | (1 << 0))/* 0x03 */); ++ switch(tmp) ++ { ++ /* The BBP R3 bit[1:0] = 3 :: All ADCs will be used by QA. */ ++ case 3: ++ /* All */ ++ pAd->ate.RxAntennaSel = 0; ++ break; ++ /* The BBP R3 bit[1:0] = 0 :: ADC 0 will be used by QA, */ ++ /* unless the BBP R3 bit[4:3] = 2 */ ++ case 0: ++ /* Antenna one */ ++ pAd->ate.RxAntennaSel = 1; ++ tmp = ((bbp_data & ((1 << 4) | (1 << 3))/* 0x03 */) >> 3); ++ if (tmp == 2)// 3R ++ { ++ /* Default : All ADCs will be used by QA */ ++ pAd->ate.RxAntennaSel = 0; ++ } ++ break; ++ /* The BBP R3 bit[1:0] = 1 :: ADC 1 will be used by QA. */ ++ case 1: ++ /* Antenna two */ ++ pAd->ate.RxAntennaSel = 2; ++ break; ++ /* The BBP R3 bit[1:0] = 2 :: ADC 2 will be used by QA. */ ++ case 2: ++ /* Antenna three */ ++ pAd->ate.RxAntennaSel = 3; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ } ++ break;/* case BBP_R3 */ ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ ++ } ++ return TRUE; ++} ++ ++static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) ++{ ++ ULONG i, Value = 0; ++ ULONG *pDst, *pSrc; ++ UCHAR *p8; ++ ++ p8 = src; ++ pDst = (ULONG *) dst; ++ pSrc = (ULONG *) src; ++ ++ for (i = 0 ; i < (len/4); i++) ++ { ++ /* For alignment issue, we need a variable "Value". */ ++ memmove(&Value, pSrc, 4); ++ Value = htonl(Value); ++ memmove(pDst, &Value, 4); ++ pDst++; ++ pSrc++; ++ } ++ if ((len % 4) != 0) ++ { ++ /* wish that it will never reach here */ ++ memmove(&Value, pSrc, (len % 4)); ++ Value = htonl(Value); ++ memmove(pDst, &Value, (len % 4)); ++ } ++} ++ ++static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) ++{ ++ ULONG i; ++ UCHAR *pDst, *pSrc; ++ ++ pDst = dst; ++ pSrc = src; ++ ++ for (i = 0; i < (len/2); i++) ++ { ++ memmove(pDst, pSrc, 2); ++ *((USHORT *)pDst) = htons(*((USHORT *)pDst)); ++ pDst+=2; ++ pSrc+=2; ++ } ++ ++ if ((len % 2) != 0) ++ { ++ memmove(pDst, pSrc, 1); ++ } ++} ++ ++static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len) ++{ ++ UINT32 i, Value; ++ UINT32 *pDst, *pSrc; ++ ++ pDst = (UINT32 *) dst; ++ pSrc = (UINT32 *) src; ++ ++ for (i = 0 ; i < (len/4); i++) ++ { ++ RTMP_IO_READ32(pAd, (ULONG)pSrc, &Value); ++ Value = htonl(Value); ++ memmove(pDst, &Value, 4); ++ pDst++; ++ pSrc++; ++ } ++ return; ++} ++ ++// TODO: ++#if 0 ++/* These work only when RALINK_ATE is defined */ ++INT Set_TxStart_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG value = simple_strtol(arg, 0, 10); ++ UCHAR buffer[26] = {0x88, 0x02, 0x2c, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00, 0x55, 0x44, 0x33, 0x22, 0x11, 0xc0, 0x22, 0x00, 0x00}; ++ POS_COOKIE pObj; ++ ++ if (pAd->ate.TxStatus != 0) ++ return FALSE; ++ ++ pAd->ate.TxInfo = 0x04000000; ++ bzero(&pAd->ate.TxWI, sizeof(TXWI_STRUC)); ++ pAd->ate.TxWI.PHYMODE = 0;// MODE_CCK ++ pAd->ate.TxWI.MPDUtotalByteCount = 1226; ++ pAd->ate.TxWI.MCS = 3; ++ //pAd->ate.Mode = ATE_START; ++ pAd->ate.Mode |= ATE_TXFRAME; ++ pAd->ate.TxCount = value; ++ pAd->ate.QID = 0; ++ pAd->ate.HLen = 26; ++ pAd->ate.PLen = 0; ++ pAd->ate.DLen = 1200; ++ memcpy(pAd->ate.Header, buffer, 26); ++ pAd->ate.bQATxStart = TRUE; ++ //pObj = (POS_COOKIE) pAd->OS_Cookie; ++ //tasklet_hi_schedule(&pObj->AteTxTask); ++ return TRUE; ++} ++#endif /* end of #if 0 */ ++ ++INT Set_TxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Set_TxStop_Proc\n")); ++ ++ if (Set_ATE_Proc(pAd, "TXSTOP")) ++ { ++ return TRUE; ++} ++ else ++ { ++ return FALSE; ++ } ++} ++ ++INT Set_RxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Set_RxStop_Proc\n")); ++ ++ if (Set_ATE_Proc(pAd, "RXSTOP")) ++ { ++ return TRUE; ++} ++ else ++ { ++ return FALSE; ++ } ++} ++ ++#if 0 ++INT Set_EEWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT offset = 0, value; ++ PUCHAR p2 = arg; ++ ++ while((*p2 != ':') && (*p2 != '\0')) ++ { ++ p2++; ++ } ++ ++ if (*p2 == ':') ++ { ++ A2Hex(offset, arg); ++ A2Hex(value, p2+ 1); ++ } ++ else ++ { ++ A2Hex(value, arg); ++ } ++ ++ if (offset >= EEPROM_SIZE) ++ { ++ ate_print("Offset can not exceed EEPROM_SIZE( == 0x%04x)\n", EEPROM_SIZE); ++ return FALSE; ++ } ++ ++ RTMP_EEPROM_WRITE16(pAd, offset, value); ++ ++ return TRUE; ++} ++ ++INT Set_BBPRead_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR value = 0, offset; ++ ++ A2Hex(offset, arg); ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &value); ++ } ++ ++ ate_print("%x\n", value); ++ ++ return TRUE; ++} ++ ++ ++INT Set_BBPWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT offset = 0; ++ PUCHAR p2 = arg; ++ UCHAR value; ++ ++ while((*p2 != ':') && (*p2 != '\0')) ++ { ++ p2++; ++ } ++ ++ if (*p2 == ':') ++ { ++ A2Hex(offset, arg); ++ A2Hex(value, p2+ 1); ++ } ++ else ++ { ++ A2Hex(value, arg); ++ } ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); ++ } ++ else ++ { ++ RTNP_BBP_IO_WRITE8_BY_REG_ID(pAd, offset, value); ++ } ++ ++ return TRUE; ++} ++ ++INT Set_RFWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ PUCHAR p2, p3, p4; ++ ULONG R1, R2, R3, R4; ++ ++ p2 = arg; ++ ++ while((*p2 != ':') && (*p2 != '\0')) ++ { ++ p2++; ++ } ++ ++ if (*p2 != ':') ++ return FALSE; ++ ++ p3 = p2 + 1; ++ ++ while((*p3 != ':') && (*p3 != '\0')) ++ { ++ p3++; ++ } ++ ++ if (*p3 != ':') ++ return FALSE; ++ ++ p4 = p3 + 1; ++ ++ while((*p4 != ':') && (*p4 != '\0')) ++ { ++ p4++; ++ } ++ ++ if (*p4 != ':') ++ return FALSE; ++ ++ ++ A2Hex(R1, arg); ++ A2Hex(R2, p2 + 1); ++ A2Hex(R3, p3 + 1); ++ A2Hex(R4, p4 + 1); ++ ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ RTMP_RF_IO_WRITE32(pAd, R4); ++ ++ return TRUE; ++} ++#endif // end of #if 0 // ++#endif // RALINK_28xx_QA // ++ ++#endif // RALINK_ATE // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rt_ate.h +@@ -0,0 +1,315 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __ATE_H__ ++#define __ATE_H__ ++ ++#ifndef UCOS ++#define ate_print printk ++#define ATEDBGPRINT DBGPRINT ++ ++#ifdef RT2870 ++#define EEPROM_SIZE 0x400 ++#ifdef CONFIG_STA_SUPPORT ++#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2870 // ++#else // !UCOS // ++#define fATE_LOAD_EEPROM 0x0C43 ++#ifdef CONFIG_PRINTK ++extern INT ConsoleResponse(IN PUCHAR buff); ++extern int (*remote_display)(char *); ++extern void puts (const char *s); ++ ++/* specificly defined to redirect and show ate-related messages to host. */ ++/* Try to define ate_print as a macro. */ ++#define ate_print(fmt, args...) \ ++do{ int (*org_remote_display)(char *) = NULL; \ ++ org_remote_display = remote_display;\ ++ /* Save original "remote_display" */\ ++ remote_display = (int (*)(char *))ConsoleResponse; \ ++ printk(fmt, ## args); \ ++ /* Restore the remote_display function pointer */ \ ++ remote_display = org_remote_display; }while(0) ++ ++#define ATEDBGPRINT(Level, Fmt) \ ++{ \ ++ if ((Level) <= RTDebugLevel) \ ++ { \ ++ ate_print Fmt; \ ++ } \ ++} ++#endif // CONFIG_PRINTK // ++#endif // !UCOS // ++ ++#define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) ++ ++/* RT2880_iNIC will define "RT2860". */ ++ ++/* RT2880_iNIC will define RT2860. */ ++ ++#ifdef RT2870 ++#define EEPROM_SIZE 0x400 ++#ifdef CONFIG_STA_SUPPORT ++#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2870 // ++ ++#ifdef RT2870 ++#define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) ++#define ATE_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) ++ ++#define BULK_OUT_LOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_LOCK((pLock), IrqFlags); ++ ++#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_UNLOCK((pLock), IrqFlags); ++ ++// Prototypes of completion funuc. ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++#define ATE_RTUSBBulkOutDataPacketComplete(purb, pt_regs) ATE_RTUSBBulkOutDataPacketComplete(purb) ++#endif ++ ++VOID ATE_RTUSBBulkOutDataPacketComplete( ++ IN purbb_t purb, ++ OUT struct pt_regs *pt_regs); ++ ++VOID ATE_RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId); ++ ++VOID ATE_RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++VOID rt_ee_read_all( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Data); ++ ++ ++VOID rt_ee_write_all( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT *Data); ++ ++INT Set_ATE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_DA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_SA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_BSSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_CHANNEL_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_POWER0_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_POWER1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_RX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_FREQOFFSET_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_BW_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_LENGTH_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_COUNT_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_MCS_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_MODE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_GI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_ATE_RX_FER_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Read_RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Read_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Show_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Help_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++VOID ATE_QA_Statistics( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC p28xxRxD, ++ IN PHEADER_802_11 pHeader); ++ ++VOID RtmpDoAte( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID BubbleSort( ++ IN INT32 n, ++ IN INT32 a[]); ++ ++VOID CalNoiseLevel( ++ IN PRTMP_ADAPTER pAdapter, ++ IN UCHAR channel, ++ OUT INT32 buffer[3][10]); ++ ++BOOLEAN SyncTxRxConfig( ++ IN PRTMP_ADAPTER pAdapter, ++ IN USHORT offset, ++ IN UCHAR value); ++ ++#if 0 ++INT Set_TxStart_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // 0 // ++ ++INT Set_TxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#if 0 ++INT Set_EERead_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_EEWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BBPRead_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BBPWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RFWrite_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // end of #if 0 // ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++VOID ATEAsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ATEAsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ATEDisableAsicProtect( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber); ++ ++VOID ATESampleRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPStationStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPStationStart( ++ IN PRTMP_ADAPTER pAd); ++#endif // CONFIG_STA_SUPPORT // ++#endif // __ATE_H__ // +--- /dev/null ++++ b/drivers/staging/rt2870/rt_config.h +@@ -0,0 +1,104 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt_config.h ++ ++ Abstract: ++ Central header file to maintain all include files for all NDIS ++ miniport driver routines. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ ++*/ ++#ifndef __RT_CONFIG_H__ ++#define __RT_CONFIG_H__ ++ ++#include "rtmp_type.h" ++#ifdef UCOS ++#include "includes.h" ++#include ++#include "rt_ucos.h" ++#endif ++ ++#ifdef LINUX ++#include "rt_linux.h" ++#endif ++#include "rtmp_def.h" ++#include "rt28xx.h" ++ ++ ++#ifdef RT2870 ++#include "rt2870.h" ++#endif // RT2870 // ++ ++#include "oid.h" ++#include "mlme.h" ++#include "wpa.h" ++#include "md5.h" ++#include "rtmp.h" ++#include "ap.h" ++#include "dfs.h" ++#include "chlist.h" ++#include "spectrum.h" ++ ++ ++#ifdef LEAP_SUPPORT ++#include "leap.h" ++#endif // LEAP_SUPPORT // ++ ++#ifdef BLOCK_NET_IF ++#include "netif_block.h" ++#endif // BLOCK_NET_IF // ++ ++#ifdef IGMP_SNOOP_SUPPORT ++#include "igmp_snoop.h" ++#endif // IGMP_SNOOP_SUPPORT // ++ ++#ifdef RALINK_ATE ++#include "rt_ate.h" ++#endif // RALINK_ATE // ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifndef WPA_SUPPLICANT_SUPPORT ++#error "Build for being controlled by NetworkManager or wext, please set HAS_WPA_SUPPLICANT=y and HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y" ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef IKANOS_VX_1X0 ++#include "vr_ikans.h" ++#endif // IKANOS_VX_1X0 // ++ ++#endif // __RT_CONFIG_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rt_linux.c +@@ -0,0 +1,1095 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++ULONG RTDebugLevel = RT_DEBUG_ERROR; ++ ++BUILD_TIMER_FUNCTION(MlmePeriodicExec); ++//BUILD_TIMER_FUNCTION(MlmeRssiReportExec); ++BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); ++BUILD_TIMER_FUNCTION(APSDPeriodicExec); ++BUILD_TIMER_FUNCTION(AsicRfTuningExec); ++#ifdef RT2870 ++BUILD_TIMER_FUNCTION(BeaconUpdateExec); ++#endif // RT2870 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++BUILD_TIMER_FUNCTION(BeaconTimeout); ++BUILD_TIMER_FUNCTION(ScanTimeout); ++BUILD_TIMER_FUNCTION(AuthTimeout); ++BUILD_TIMER_FUNCTION(AssocTimeout); ++BUILD_TIMER_FUNCTION(ReassocTimeout); ++BUILD_TIMER_FUNCTION(DisassocTimeout); ++BUILD_TIMER_FUNCTION(LinkDownExec); ++#ifdef LEAP_SUPPORT ++BUILD_TIMER_FUNCTION(LeapAuthTimeout); ++#endif ++BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); ++BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); ++#ifdef QOS_DLS_SUPPORT ++BUILD_TIMER_FUNCTION(DlsTimeoutAction); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++// for wireless system event message ++char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = { ++ // system status event ++ "had associated successfully", /* IW_ASSOC_EVENT_FLAG */ ++ "had disassociated", /* IW_DISASSOC_EVENT_FLAG */ ++ "had deauthenticated", /* IW_DEAUTH_EVENT_FLAG */ ++ "had been aged-out and disassociated", /* IW_AGEOUT_EVENT_FLAG */ ++ "occurred CounterMeasures attack", /* IW_COUNTER_MEASURES_EVENT_FLAG */ ++ "occurred replay counter different in Key Handshaking", /* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */ ++ "occurred RSNIE different in Key Handshaking", /* IW_RSNIE_DIFF_EVENT_FLAG */ ++ "occurred MIC different in Key Handshaking", /* IW_MIC_DIFF_EVENT_FLAG */ ++ "occurred ICV error in RX", /* IW_ICV_ERROR_EVENT_FLAG */ ++ "occurred MIC error in RX", /* IW_MIC_ERROR_EVENT_FLAG */ ++ "Group Key Handshaking timeout", /* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */ ++ "Pairwise Key Handshaking timeout", /* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */ ++ "RSN IE sanity check failure", /* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */ ++ "set key done in WPA/WPAPSK", /* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */ ++ "set key done in WPA2/WPA2PSK", /* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */ ++ "connects with our wireless client", /* IW_STA_LINKUP_EVENT_FLAG */ ++ "disconnects with our wireless client", /* IW_STA_LINKDOWN_EVENT_FLAG */ ++ "scan completed" /* IW_SCAN_COMPLETED_EVENT_FLAG */ ++ "scan terminate!! Busy!! Enqueue fail!!" /* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */ ++ }; ++ ++// for wireless IDS_spoof_attack event message ++char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = { ++ "detected conflict SSID", /* IW_CONFLICT_SSID_EVENT_FLAG */ ++ "detected spoofed association response", /* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */ ++ "detected spoofed reassociation responses", /* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */ ++ "detected spoofed probe response", /* IW_SPOOF_PROBE_RESP_EVENT_FLAG */ ++ "detected spoofed beacon", /* IW_SPOOF_BEACON_EVENT_FLAG */ ++ "detected spoofed disassociation", /* IW_SPOOF_DISASSOC_EVENT_FLAG */ ++ "detected spoofed authentication", /* IW_SPOOF_AUTH_EVENT_FLAG */ ++ "detected spoofed deauthentication", /* IW_SPOOF_DEAUTH_EVENT_FLAG */ ++ "detected spoofed unknown management frame", /* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */ ++ "detected replay attack" /* IW_REPLAY_ATTACK_EVENT_FLAG */ ++ }; ++ ++// for wireless IDS_flooding_attack event message ++char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = { ++ "detected authentication flooding", /* IW_FLOOD_AUTH_EVENT_FLAG */ ++ "detected association request flooding", /* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */ ++ "detected reassociation request flooding", /* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */ ++ "detected probe request flooding", /* IW_FLOOD_PROBE_REQ_EVENT_FLAG */ ++ "detected disassociation flooding", /* IW_FLOOD_DISASSOC_EVENT_FLAG */ ++ "detected deauthentication flooding", /* IW_FLOOD_DEAUTH_EVENT_FLAG */ ++ "detected 802.1x eap-request flooding" /* IW_FLOOD_EAP_REQ_EVENT_FLAG */ ++ }; ++ ++/* timeout -- ms */ ++VOID RTMP_SetPeriodicTimer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ timeout = ((timeout*HZ) / 1000); ++ pTimer->expires = jiffies + timeout; ++ add_timer(pTimer); ++} ++ ++/* convert NdisMInitializeTimer --> RTMP_OS_Init_Timer */ ++VOID RTMP_OS_Init_Timer( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN TIMER_FUNCTION function, ++ IN PVOID data) ++{ ++ init_timer(pTimer); ++ pTimer->data = (unsigned long)data; ++ pTimer->function = function; ++} ++ ++ ++VOID RTMP_OS_Add_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ if (timer_pending(pTimer)) ++ return; ++ ++ timeout = ((timeout*HZ) / 1000); ++ pTimer->expires = jiffies + timeout; ++ add_timer(pTimer); ++} ++ ++VOID RTMP_OS_Mod_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ timeout = ((timeout*HZ) / 1000); ++ mod_timer(pTimer, jiffies + timeout); ++} ++ ++VOID RTMP_OS_Del_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ OUT BOOLEAN *pCancelled) ++{ ++ if (timer_pending(pTimer)) ++ { ++ *pCancelled = del_timer_sync(pTimer); ++ } ++ else ++ { ++ *pCancelled = TRUE; ++ } ++ ++} ++ ++VOID RTMP_OS_Release_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_ENTRY pEntry) ++{ ++ //RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); ++} ++ ++// Unify all delay routine by using udelay ++VOID RTMPusecDelay( ++ IN ULONG usec) ++{ ++ ULONG i; ++ ++ for (i = 0; i < (usec / 50); i++) ++ udelay(50); ++ ++ if (usec % 50) ++ udelay(usec % 50); ++} ++ ++void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time) ++{ ++ time->u.LowPart = jiffies; ++} ++ ++// pAd MUST allow to be NULL ++NDIS_STATUS os_alloc_mem( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR *mem, ++ IN ULONG size) ++{ ++ *mem = (PUCHAR) kmalloc(size, GFP_ATOMIC); ++ if (*mem) ++ return (NDIS_STATUS_SUCCESS); ++ else ++ return (NDIS_STATUS_FAILURE); ++} ++ ++// pAd MUST allow to be NULL ++NDIS_STATUS os_free_mem( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mem) ++{ ++ ++ ASSERT(mem); ++ kfree(mem); ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++ ++PNDIS_PACKET RTMP_AllocateFragPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length) ++{ ++ struct sk_buff *pkt; ++ ++ pkt = dev_alloc_skb(Length); ++ ++ if (pkt == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate frag rx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) ++ { ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++PNDIS_PACKET RTMP_AllocateTxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress) ++{ ++ struct sk_buff *pkt; ++ ++ pkt = dev_alloc_skb(Length); ++ ++ if (pkt == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate tx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) ++ { ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ *VirtualAddress = (PVOID) pkt->data; ++ } ++ else ++ { ++ *VirtualAddress = (PVOID) NULL; ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++VOID build_tx_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pFrame, ++ IN ULONG FrameLen) ++{ ++ ++ struct sk_buff *pTxPkt; ++ ++ ASSERT(pPacket); ++ pTxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen); ++} ++ ++VOID RTMPFreeAdapter( ++ IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE os_cookie; ++ int index; ++ ++ os_cookie=(POS_COOKIE)pAd->OS_Cookie; ++ ++ kfree(pAd->BeaconBuf); ++ ++ ++ NdisFreeSpinLock(&pAd->MgmtRingLock); ++ ++ ++ for (index =0 ; index < NUM_OF_TX_RING; index++) ++ { ++ NdisFreeSpinLock(&pAd->TxSwQueueLock[index]); ++ NdisFreeSpinLock(&pAd->DeQueueLock[index]); ++ pAd->DeQueueRunning[index] = FALSE; ++ } ++ ++ NdisFreeSpinLock(&pAd->irq_lock); ++ ++ ++ vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); ++ kfree(os_cookie); ++} ++ ++BOOLEAN OS_Need_Clone_Packet(void) ++{ ++ return (FALSE); ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ clone an input NDIS PACKET to another one. The new internally created NDIS PACKET ++ must have only one NDIS BUFFER ++ return - byte copied. 0 means can't create NDIS PACKET ++ NOTE: internally created NDIS_PACKET should be destroyed by RTMPFreeNdisPacket ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU. ++ *pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet. ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPCloneNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN pInsAMSDUHdr, ++ IN PNDIS_PACKET pInPacket, ++ OUT PNDIS_PACKET *ppOutPacket) ++{ ++ ++ struct sk_buff *pkt; ++ ++ ASSERT(pInPacket); ++ ASSERT(ppOutPacket); ++ ++ // 1. Allocate a packet ++ pkt = dev_alloc_skb(2048); ++ ++ if (pkt == NULL) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ skb_put(pkt, GET_OS_PKT_LEN(pInPacket)); ++ NdisMoveMemory(pkt->data, GET_OS_PKT_DATAPTR(pInPacket), GET_OS_PKT_LEN(pInPacket)); ++ *ppOutPacket = OSPKT_TO_RTPKT(pkt); ++ ++ ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ ++ printk("###Clone###\n"); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++// the allocated NDIS PACKET must be freed via RTMPFreeNdisPacket() ++NDIS_STATUS RTMPAllocateNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ OUT PNDIS_PACKET *ppPacket, ++ IN PUCHAR pHeader, ++ IN UINT HeaderLen, ++ IN PUCHAR pData, ++ IN UINT DataLen) ++{ ++ PNDIS_PACKET pPacket; ++ ASSERT(pData); ++ ASSERT(DataLen); ++ ++ // 1. Allocate a packet ++ pPacket = (PNDIS_PACKET *) dev_alloc_skb(HeaderLen + DataLen + TXPADDING_SIZE); ++ if (pPacket == NULL) ++ { ++ *ppPacket = NULL; ++#ifdef DEBUG ++ printk("RTMPAllocateNdisPacket Fail\n\n"); ++#endif ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // 2. clone the frame content ++ if (HeaderLen > 0) ++ NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket), pHeader, HeaderLen); ++ if (DataLen > 0) ++ NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket) + HeaderLen, pData, DataLen); ++ ++ // 3. update length of packet ++ skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen); ++ ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket)); ++ *ppPacket = pPacket; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ Description: ++ This routine frees a miniport internally allocated NDIS_PACKET and its ++ corresponding NDIS_BUFFER and allocated memory. ++ ======================================================================== ++*/ ++VOID RTMPFreeNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ dev_kfree_skb_any(RTPKT_TO_OSPKT(pPacket)); ++} ++ ++ ++// IRQL = DISPATCH_LEVEL ++// NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same ++// scatter gather buffer ++NDIS_STATUS Sniff2BytesFromNdisBuffer( ++ IN PNDIS_BUFFER pFirstBuffer, ++ IN UCHAR DesiredOffset, ++ OUT PUCHAR pByte0, ++ OUT PUCHAR pByte1) ++{ ++ *pByte0 = *(PUCHAR)(pFirstBuffer + DesiredOffset); ++ *pByte1 = *(PUCHAR)(pFirstBuffer + DesiredOffset + 1); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++void RTMP_QueryPacketInfo( ++ IN PNDIS_PACKET pPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen) ++{ ++ pPacketInfo->BufferCount = 1; ++ pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); ++ pPacketInfo->PhysicalBufferCount = 1; ++ pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); ++ ++ *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ *pSrcBufLen = GET_OS_PKT_LEN(pPacket); ++} ++ ++void RTMP_QueryNextPacketInfo( ++ IN PNDIS_PACKET *ppPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen) ++{ ++ PNDIS_PACKET pPacket = NULL; ++ ++ if (*ppPacket) ++ pPacket = GET_OS_PKT_NEXT(*ppPacket); ++ ++ if (pPacket) ++ { ++ pPacketInfo->BufferCount = 1; ++ pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); ++ pPacketInfo->PhysicalBufferCount = 1; ++ pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); ++ ++ *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ *pSrcBufLen = GET_OS_PKT_LEN(pPacket); ++ *ppPacket = GET_OS_PKT_NEXT(pPacket); ++ } ++ else ++ { ++ pPacketInfo->BufferCount = 0; ++ pPacketInfo->pFirstBuffer = NULL; ++ pPacketInfo->PhysicalBufferCount = 0; ++ pPacketInfo->TotalPacketLength = 0; ++ ++ *pSrcBufVA = NULL; ++ *pSrcBufLen = 0; ++ *ppPacket = NULL; ++ } ++} ++ ++// not yet support MBSS ++PNET_DEV get_netdev_from_bssid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNET_DEV dev_p = NULL; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ dev_p = pAd->net_dev; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ASSERT(dev_p); ++ return dev_p; /* return one of MBSS */ ++} ++ ++PNDIS_PACKET DuplicatePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *skb; ++ PNDIS_PACKET pRetPacket = NULL; ++ USHORT DataSize; ++ UCHAR *pData; ++ ++ DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); ++ pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); ++ ++ ++ skb = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG); ++ if (skb) ++ { ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pRetPacket = OSPKT_TO_RTPKT(skb); ++ } ++ ++#if 0 ++ if ((skb = __dev_alloc_skb(DataSize + 2+32, MEM_ALLOC_FLAG)) != NULL) ++ { ++ skb_reserve(skb, 2+32); ++ NdisMoveMemory(skb->tail, pData, DataSize); ++ skb_put(skb, DataSize); ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pRetPacket = OSPKT_TO_RTPKT(skb); ++ } ++#endif ++ ++ return pRetPacket; ++ ++} ++ ++PNDIS_PACKET duplicate_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *skb; ++ PNDIS_PACKET pPacket = NULL; ++ ++ ++ if ((skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != NULL) ++ { ++ skb_reserve(skb, 2); ++ NdisMoveMemory(skb->tail, pHeader802_3, HdrLen); ++ skb_put(skb, HdrLen); ++ NdisMoveMemory(skb->tail, pData, DataSize); ++ skb_put(skb, DataSize); ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pPacket = OSPKT_TO_RTPKT(skb); ++ } ++ ++ return pPacket; ++} ++ ++ ++#define TKIP_TX_MIC_SIZE 8 ++PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ struct sk_buff *skb, *newskb; ++ ++ ++ skb = RTPKT_TO_OSPKT(pPacket); ++ if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE) ++ { ++ // alloc a new skb and copy the packet ++ newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); ++ dev_kfree_skb_any(skb); ++ if (newskb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC for packet failed!, dropping packet!\n")); ++ return NULL; ++ } ++ skb = newskb; ++ } ++ ++ return OSPKT_TO_RTPKT(skb); ++ ++#if 0 ++ if ((data = skb_put(skb, TKIP_TX_MIC_SIZE)) != NULL) ++ { // If we can extend it, well, copy it first. ++ NdisMoveMemory(data, pAd->PrivateInfo.Tx.MIC, TKIP_TX_MIC_SIZE); ++ } ++ else ++ { ++ // Otherwise, copy the packet. ++ newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); ++ dev_kfree_skb_any(skb); ++ if (newskb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC to packet failed!, dropping packet\n")); ++ return NULL; ++ } ++ skb = newskb; ++ ++ NdisMoveMemory(skb->tail, pAd->PrivateInfo.Tx.MIC, TKIP_TX_MIC_SIZE); ++ skb_put(skb, TKIP_TX_MIC_SIZE); ++ } ++ ++ return OSPKT_TO_RTPKT(skb); ++#endif ++ ++} ++ ++ ++ ++ ++PNDIS_PACKET ClonePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ struct sk_buff *pRxPkt; ++ struct sk_buff *pClonedPkt; ++ ++ ASSERT(pPacket); ++ pRxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ // clone the packet ++ pClonedPkt = skb_clone(pRxPkt, MEM_ALLOC_FLAG); ++ ++ if (pClonedPkt) ++ { ++ // set the correct dataptr and data len ++ pClonedPkt->dev = pRxPkt->dev; ++ pClonedPkt->data = pData; ++ pClonedPkt->len = DataSize; ++ pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len; ++ ASSERT(DataSize < 1530); ++ } ++ return pClonedPkt; ++} ++ ++// ++// change OS packet DataPtr and DataLen ++// ++void update_os_packet_info( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *pOSPkt; ++ ++ ASSERT(pRxBlk->pRxPacket); ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pOSPkt->data = pRxBlk->pData; ++ pOSPkt->len = pRxBlk->DataSize; ++ pOSPkt->tail = pOSPkt->data + pOSPkt->len; ++} ++ ++ ++void wlan_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN PUCHAR pHeader802_3, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *pOSPkt; ++ ++ ASSERT(pRxBlk->pRxPacket); ++ ASSERT(pHeader802_3); ++ ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pOSPkt->data = pRxBlk->pData; ++ pOSPkt->len = pRxBlk->DataSize; ++ pOSPkt->tail = pOSPkt->data + pOSPkt->len; ++ ++ // ++ // copy 802.3 header ++ // ++ // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ ++void announce_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ ++ struct sk_buff *pRxPkt; ++ ++ ASSERT(pPacket); ++ ++ pRxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ /* Push up the protocol stack */ ++#ifdef IKANOS_VX_1X0 ++ IKANOS_DataFrameRx(pAd, pRxPkt->dev, pRxPkt, pRxPkt->len); ++#else ++ pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev); ++ ++//#ifdef CONFIG_5VT_ENHANCE ++// *(int*)(pRxPkt->cb) = BRIDGE_TAG; ++//#endif ++ netif_rx(pRxPkt); ++#endif // IKANOS_VX_1X0 // ++} ++ ++ ++PRTMP_SCATTER_GATHER_LIST ++rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg) ++{ ++ sg->NumberOfElements = 1; ++ sg->Elements[0].Address = GET_OS_PKT_DATAPTR(pPacket); ++ sg->Elements[0].Length = GET_OS_PKT_LEN(pPacket); ++ return (sg); ++} ++ ++void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) ++{ ++ unsigned char *pt; ++ int x; ++ ++ if (RTDebugLevel < RT_DEBUG_TRACE) ++ return; ++ ++ pt = pSrcBufVA; ++ printk("%s: %p, len = %d\n",str, pSrcBufVA, SrcBufLen); ++ for (x=0; x= 15 ++ ++ union iwreq_data wrqu; ++ PUCHAR pBuf = NULL, pBufPtr = NULL; ++ USHORT event, type, BufLen; ++ UCHAR event_table_len = 0; ++ ++ type = Event_flag & 0xFF00; ++ event = Event_flag & 0x00FF; ++ ++ switch (type) ++ { ++ case IW_SYS_EVENT_FLAG_START: ++ event_table_len = IW_SYS_EVENT_TYPE_NUM; ++ break; ++ ++ case IW_SPOOF_EVENT_FLAG_START: ++ event_table_len = IW_SPOOF_EVENT_TYPE_NUM; ++ break; ++ ++ case IW_FLOOD_EVENT_FLAG_START: ++ event_table_len = IW_FLOOD_EVENT_TYPE_NUM; ++ break; ++ } ++ ++ if (event_table_len == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type)); ++ return; ++ } ++ ++ if (event >= event_table_len) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event)); ++ return; ++ } ++ ++ //Allocate memory and copy the msg. ++ if((pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC)) != NULL) ++ { ++ //Prepare the payload ++ memset(pBuf, 0, IW_CUSTOM_MAX_LEN); ++ ++ pBufPtr = pBuf; ++ ++ if (pAddr) ++ pBufPtr += sprintf(pBufPtr, "(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ", PRINT_MAC(pAddr)); ++ else if (BssIdx < MAX_MBSSID_NUM) ++ pBufPtr += sprintf(pBufPtr, "(RT2860) BSS(ra%d) ", BssIdx); ++ else ++ pBufPtr += sprintf(pBufPtr, "(RT2860) "); ++ ++ if (type == IW_SYS_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s", pWirelessSysEventText[event]); ++ else if (type == IW_SPOOF_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s (RSSI=%d)", pWirelessSpoofEventText[event], Rssi); ++ else if (type == IW_FLOOD_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s", pWirelessFloodEventText[event]); ++ else ++ pBufPtr += sprintf(pBufPtr, "%s", "unknown event"); ++ ++ pBufPtr[pBufPtr - pBuf] = '\0'; ++ BufLen = pBufPtr - pBuf; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = Event_flag; ++ wrqu.data.length = BufLen; ++ ++ //send wireless event ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf); ++ ++ //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf)); ++ ++ kfree(pBuf); ++ } ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__)); ++#else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__)); ++#endif /* WIRELESS_EXT >= 15 */ ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++void send_monitor_packets( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ struct sk_buff *pOSPkt; ++ wlan_ng_prism2_header *ph; ++ int rate_index = 0; ++ USHORT header_len = 0; ++ UCHAR temp_header[40] = {0}; ++ ++ u_int32_t ralinkrate[256] = {2,4,11,22, 12,18,24,36,48,72,96, 108, 109, 110, 111, 112, 13, 26, 39, 52,78,104, 117, 130, 26, 52, 78,104, 156, 208, 234, 260, 27, 54,81,108,162, 216, 243, 270, // Last 38 ++ 54, 108, 162, 216, 324, 432, 486, 540, 14, 29, 43, 57, 87, 115, 130, 144, 29, 59,87,115, 173, 230,260, 288, 30, 60,90,120,180,240,270,300,60,120,180,240,360,480,540,600, 0,1,2,3,4,5,6,7,8,9,10, ++ 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80}; ++ ++ ++ ASSERT(pRxBlk->pRxPacket); ++ if (pRxBlk->DataSize < 10) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize)); ++ goto err_free_sk_buff; ++ } ++ ++ if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); ++ goto err_free_sk_buff; ++ } ++ ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ pOSPkt->dev = get_netdev_from_bssid(pAd, BSS0); ++ if (pRxBlk->pHeader->FC.Type == BTYPE_DATA) ++ { ++ pRxBlk->DataSize -= LENGTH_802_11; ++ if ((pRxBlk->pHeader->FC.ToDs == 1) && ++ (pRxBlk->pHeader->FC.FrDs == 1)) ++ header_len = LENGTH_802_11_WITH_ADDR4; ++ else ++ header_len = LENGTH_802_11; ++ ++ // QOS ++ if (pRxBlk->pHeader->FC.SubType & 0x08) ++ { ++ header_len += 2; ++ // Data skip QOS contorl field ++ pRxBlk->DataSize -=2; ++ } ++ ++ // Order bit: A-Ralink or HTC+ ++ if (pRxBlk->pHeader->FC.Order) ++ { ++ header_len += 4; ++ // Data skip HTC contorl field ++ pRxBlk->DataSize -= 4; ++ } ++ ++ // Copy Header ++ if (header_len <= 40) ++ NdisMoveMemory(temp_header, pRxBlk->pData, header_len); ++ ++ // skip HW padding ++ if (pRxBlk->RxD.L2PAD) ++ pRxBlk->pData += (header_len + 2); ++ else ++ pRxBlk->pData += header_len; ++ } //end if ++ ++ ++ if (pRxBlk->DataSize < pOSPkt->len) { ++ skb_trim(pOSPkt,pRxBlk->DataSize); ++ } else { ++ skb_put(pOSPkt,(pRxBlk->DataSize - pOSPkt->len)); ++ } //end if ++ ++ if ((pRxBlk->pData - pOSPkt->data) > 0) { ++ skb_put(pOSPkt,(pRxBlk->pData - pOSPkt->data)); ++ skb_pull(pOSPkt,(pRxBlk->pData - pOSPkt->data)); ++ } //end if ++ ++ if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) { ++ if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__)); ++ goto err_free_sk_buff; ++ } //end if ++ } //end if ++ ++ if (header_len > 0) ++ NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header, header_len); ++ ++ ph = (wlan_ng_prism2_header *) skb_push(pOSPkt, sizeof(wlan_ng_prism2_header)); ++ NdisZeroMemory(ph, sizeof(wlan_ng_prism2_header)); ++ ++ ph->msgcode = DIDmsg_lnxind_wlansniffrm; ++ ph->msglen = sizeof(wlan_ng_prism2_header); ++ strcpy(ph->devname, pAd->net_dev->name); ++ ++ ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; ++ ph->hosttime.status = 0; ++ ph->hosttime.len = 4; ++ ph->hosttime.data = jiffies; ++ ++ ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; ++ ph->mactime.status = 0; ++ ph->mactime.len = 0; ++ ph->mactime.data = 0; ++ ++ ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; ++ ph->istx.status = 0; ++ ph->istx.len = 0; ++ ph->istx.data = 0; ++ ++ ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; ++ ph->channel.status = 0; ++ ph->channel.len = 4; ++ ++ ph->channel.data = (u_int32_t)pAd->CommonCfg.Channel; ++ ++ ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; ++ ph->rssi.status = 0; ++ ph->rssi.len = 4; ++ ph->rssi.data = (u_int32_t)RTMPMaxRssi(pAd, ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI0, RSSI_0), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI1, RSSI_1), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2, RSSI_2));; ++ ++ ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; ++ ph->signal.status = 0; ++ ph->signal.len = 4; ++ ph->signal.data = 0; //rssi + noise; ++ ++ ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; ++ ph->noise.status = 0; ++ ph->noise.len = 4; ++ ph->noise.data = 0; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) ++ { ++ rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) ++ rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; ++ else ++ rate_index = (UCHAR)(pRxBlk->pRxWI->MCS); ++ if (rate_index < 0) ++ rate_index = 0; ++ if (rate_index > 255) ++ rate_index = 255; ++ ++ ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; ++ ph->rate.status = 0; ++ ph->rate.len = 4; ++ ph->rate.data = ralinkrate[rate_index]; ++ ++ ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; ++ ph->frmlen.status = 0; ++ ph->frmlen.len = 4; ++ ph->frmlen.data = (u_int32_t)pRxBlk->DataSize; ++ ++ ++ pOSPkt->pkt_type = PACKET_OTHERHOST; ++ pOSPkt->protocol = eth_type_trans(pOSPkt, pOSPkt->dev); ++ pOSPkt->ip_summed = CHECKSUM_NONE; ++ netif_rx(pOSPkt); ++ ++ return; ++ ++err_free_sk_buff: ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) ++{ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ daemonize(pThreadName /*"%s",pAd->net_dev->name*/); ++ ++ allow_signal(SIGTERM); ++ allow_signal(SIGKILL); ++ current->flags |= PF_NOFREEZE; ++#else ++ unsigned long flags; ++ ++ daemonize(); ++ reparent_to_init(); ++ strcpy(current->comm, pThreadName); ++ ++ siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); ++ ++ /* Allow interception of SIGKILL only ++ * Don't allow other signals to interrupt the transmission */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) ++ spin_lock_irqsave(¤t->sigmask_lock, flags); ++ flush_signals(current); ++ recalc_sigpending(current); ++ spin_unlock_irqrestore(¤t->sigmask_lock, flags); ++#endif ++#endif ++ ++ /* signal that we've started the thread */ ++ complete(pNotify); ++ ++} ++ ++void RTMP_IndicateMediaState( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ else ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rt_linux.h +@@ -0,0 +1,908 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++/***********************************************************************/ ++/* */ ++/* Program: rt_linux.c */ ++/* Created: 4/21/2006 1:17:38 PM */ ++/* Author: Wu Xi-Kun */ ++/* Comments: `description` */ ++/* */ ++/*---------------------------------------------------------------------*/ ++/* */ ++/* History: */ ++/* Revision 1.1 4/21/2006 1:17:38 PM xsikun */ ++/* Initial revision */ ++/* */ ++/***********************************************************************/ ++ ++#include "rtmp_type.h" ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++ ++// load firmware ++#define __KERNEL_SYSCALLS__ ++#include ++#include ++ ++ ++#define MEM_ALLOC_FLAG (GFP_ATOMIC) //(GFP_DMA | GFP_ATOMIC) ++ ++#ifndef IFNAMSIZ ++#define IFNAMSIZ 16 ++#endif ++ ++//#define CONFIG_CKIP_SUPPORT ++ ++#undef __inline ++#define __inline static inline ++ ++typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_dev); ++ ++// add by kathy ++ ++#ifdef CONFIG_STA_SUPPORT ++ ++#ifdef RT2870 ++#define STA_PROFILE_PATH "/etc/Wireless/RT2870STA/RT2870STA.dat" ++#define STA_RT2870_IMAGE_FILE_NAME "/etc/Wireless/RT2870STA/rt2870.bin" ++#define STA_NIC_DEVICE_NAME "RT2870STA" ++#define STA_DRIVER_VERSION "1.4.0.0" ++#ifdef MULTIPLE_CARD_SUPPORT ++#define CARD_INFO_PATH "/etc/Wireless/RT2870STA/RT2870STACard.dat" ++#endif // MULTIPLE_CARD_SUPPORT // ++#endif // RT2870 // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ ++#define RTMP_TIME_AFTER(a,b) \ ++ (typecheck(unsigned long, (unsigned long)a) && \ ++ typecheck(unsigned long, (unsigned long)b) && \ ++ ((long)(b) - (long)(a) < 0)) ++ ++#define RTMP_TIME_AFTER_EQ(a,b) \ ++ (typecheck(unsigned long, (unsigned long)a) && \ ++ typecheck(unsigned long, (unsigned long)b) && \ ++ ((long)(a) - (long)(b) >= 0)) ++#define RTMP_TIME_BEFORE(a,b) RTMP_TIME_AFTER_EQ(b,a) ++#else ++#define RTMP_TIME_AFTER(a,b) time_after(a, b) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define RT_MOD_INC_USE_COUNT() \ ++ if (!try_module_get(THIS_MODULE)) \ ++ { \ ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \ ++ return -1; \ ++ } ++ ++#define RT_MOD_DEC_USE_COUNT() module_put(THIS_MODULE); ++#else ++#define RT_MOD_INC_USE_COUNT() MOD_INC_USE_COUNT; ++#define RT_MOD_DEC_USE_COUNT() MOD_DEC_USE_COUNT; ++#endif ++ ++#define OS_HZ HZ ++ ++#define ETH_LENGTH_OF_ADDRESS 6 ++ ++#define IN ++#define OUT ++ ++#define NDIS_STATUS INT ++#define NDIS_STATUS_SUCCESS 0x00 ++#define NDIS_STATUS_FAILURE 0x01 ++#define NDIS_STATUS_INVALID_DATA 0x02 ++#define NDIS_STATUS_RESOURCES 0x03 ++ ++#define MIN_NET_DEVICE_FOR_AID 0x00 //0x00~0x3f ++#define MIN_NET_DEVICE_FOR_MBSSID 0x00 //0x00,0x10,0x20,0x30 ++#define MIN_NET_DEVICE_FOR_WDS 0x10 //0x40,0x50,0x60,0x70 ++#define MIN_NET_DEVICE_FOR_APCLI 0x20 ++#define MIN_NET_DEVICE_FOR_MESH 0x30 ++#ifdef CONFIG_STA_SUPPORT ++#define MIN_NET_DEVICE_FOR_DLS 0x40 ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define NDIS_PACKET_TYPE_DIRECTED 0 ++#define NDIS_PACKET_TYPE_MULTICAST 1 ++#define NDIS_PACKET_TYPE_BROADCAST 2 ++#define NDIS_PACKET_TYPE_ALL_MULTICAST 3 ++#endif // CONFIG_STA_SUPPORT // ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++typedef struct pid * THREAD_PID; ++#define THREAD_PID_INIT_VALUE NULL ++#define GET_PID(_v) find_get_pid(_v) ++#define GET_PID_NUMBER(_v) pid_nr(_v) ++#define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0) ++#define KILL_THREAD_PID(_A, _B, _C) kill_pid(_A, _B, _C) ++#else ++typedef pid_t THREAD_PID; ++#define THREAD_PID_INIT_VALUE -1 ++#define GET_PID(_v) _v ++#define GET_PID_NUMBER(_v) _v ++#define CHECK_PID_LEGALITY(_pid) if (_pid >= 0) ++#define KILL_THREAD_PID(_A, _B, _C) kill_proc(_A, _B, _C) ++#endif ++ ++struct os_lock { ++ spinlock_t lock; ++ unsigned long flags; ++}; ++ ++ ++struct os_cookie { ++ ++#ifdef RT2870 ++ struct usb_device *pUsb_Dev; ++ ++ THREAD_PID MLMEThr_pid; ++ THREAD_PID RTUSBCmdThr_pid; ++ THREAD_PID TimerQThr_pid; ++#endif // RT2870 // ++ ++ struct tasklet_struct rx_done_task; ++ struct tasklet_struct mgmt_dma_done_task; ++ struct tasklet_struct ac0_dma_done_task; ++ struct tasklet_struct ac1_dma_done_task; ++ struct tasklet_struct ac2_dma_done_task; ++ struct tasklet_struct ac3_dma_done_task; ++ struct tasklet_struct hcca_dma_done_task; ++ struct tasklet_struct tbtt_task; ++#ifdef RT2870 ++ struct tasklet_struct null_frame_complete_task; ++ struct tasklet_struct rts_frame_complete_task; ++ struct tasklet_struct pspoll_frame_complete_task; ++#endif // RT2870 // ++ ++ ++ unsigned long apd_pid; //802.1x daemon pid ++ INT ioctl_if_type; ++ INT ioctl_if; ++}; ++ ++typedef struct _VIRTUAL_ADAPTER ++{ ++ struct net_device *RtmpDev; ++ struct net_device *VirtualDev; ++} VIRTUAL_ADAPTER, PVIRTUAL_ADAPTER; ++ ++#undef ASSERT ++#define ASSERT(x) \ ++{ \ ++ if (!(x)) \ ++ { \ ++ printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ ++ } \ ++} ++ ++typedef struct os_cookie * POS_COOKIE; ++typedef struct pci_dev * PPCI_DEV; ++typedef struct net_device * PNET_DEV; ++typedef void * PNDIS_PACKET; ++typedef char NDIS_PACKET; ++typedef PNDIS_PACKET * PPNDIS_PACKET; ++typedef dma_addr_t NDIS_PHYSICAL_ADDRESS; ++typedef dma_addr_t * PNDIS_PHYSICAL_ADDRESS; ++//typedef struct timer_list RALINK_TIMER_STRUCT; ++//typedef struct timer_list * PRALINK_TIMER_STRUCT; ++//typedef struct os_lock NDIS_SPIN_LOCK; ++typedef spinlock_t NDIS_SPIN_LOCK; ++typedef struct timer_list NDIS_MINIPORT_TIMER; ++typedef void * NDIS_HANDLE; ++typedef char * PNDIS_BUFFER; ++ ++ ++ ++void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen); ++ ++dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, int sd_idx, int direction); ++void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int direction); ++ ++ ++//////////////////////////////////////// ++// MOVE TO rtmp.h ? ++///////////////////////////////////////// ++#define PKTSRC_NDIS 0x7f ++#define PKTSRC_DRIVER 0x0f ++#define PRINT_MAC(addr) \ ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ++ ++ ++#define RT2860_PCI_DEVICE_ID 0x0601 ++ ++ ++#ifdef RT2870 ++#define PCI_MAP_SINGLE(_handle, _ptr, _size, _dir) (ULONG)0 ++ ++#define PCI_UNMAP_SINGLE(_handle, _ptr, _size, _dir) ++#endif // RT2870 // ++ ++ ++#define BEACON_FRAME_DMA_CACHE_WBACK(_ptr, _size) \ ++ dma_cache_wback(_ptr, _size) ++ ++ ++////////////////////////////////////////// ++// ++////////////////////////////////////////// ++ ++ ++#define NdisMIndicateStatus(_w, _x, _y, _z) ++ ++typedef struct timer_list RTMP_OS_TIMER; ++ ++#ifdef RT2870 ++/* ----------------- Timer Related MARCO ---------------*/ ++// In RT2870, we have a lot of timer functions and will read/write register, it's ++// not allowed in Linux USB sub-system to do it ( because of sleep issue when submit ++// to ctrl pipe). So we need a wrapper function to take care it. ++ ++typedef VOID (*RT2870_TIMER_HANDLE)( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // RT2870 // ++ ++ ++typedef struct _RALINK_TIMER_STRUCT { ++ RTMP_OS_TIMER TimerObj; // Ndis Timer object ++ BOOLEAN Valid; // Set to True when call RTMPInitTimer ++ BOOLEAN State; // True if timer cancelled ++ BOOLEAN PeriodicType; // True if timer is periodic timer ++ BOOLEAN Repeat; // True if periodic timer ++ ULONG TimerValue; // Timer value in milliseconds ++ ULONG cookie; // os specific object ++#ifdef RT2870 ++ RT2870_TIMER_HANDLE handle; ++ void *pAd; ++#endif // RT2870 // ++} RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; ++ ++ ++#ifdef RT2870 ++ ++typedef enum _RT2870_KERNEL_THREAD_STATUS_ ++{ ++ RT2870_THREAD_UNKNOWN = 0, ++ RT2870_THREAD_INITED = 1, ++ RT2870_THREAD_RUNNING = 2, ++ RT2870_THREAD_STOPED = 4, ++}RT2870_KERNEL_THREAD_STATUS; ++ ++#define RT2870_THREAD_CAN_DO_INSERT (RT2870_THREAD_INITED |RT2870_THREAD_RUNNING) ++ ++typedef struct _RT2870_TIMER_ENTRY_ ++{ ++ RALINK_TIMER_STRUCT *pRaTimer; ++ struct _RT2870_TIMER_ENTRY_ *pNext; ++}RT2870_TIMER_ENTRY; ++ ++ ++#define TIMER_QUEUE_SIZE_MAX 128 ++typedef struct _RT2870_TIMER_QUEUE_ ++{ ++ unsigned int status; ++ //wait_queue_head_t timerWaitQ; ++ //atomic_t count; ++ UCHAR *pTimerQPoll; ++ RT2870_TIMER_ENTRY *pQPollFreeList; ++ RT2870_TIMER_ENTRY *pQHead; ++ RT2870_TIMER_ENTRY *pQTail; ++}RT2870_TIMER_QUEUE; ++#endif // RT2870 // ++ ++ ++//#define DBG 1 ++ ++// ++// MACRO for debugging information ++// ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++ ++#define DBGPRINT_RAW(Level, Fmt) \ ++{ \ ++ if (Level <= RTDebugLevel) \ ++ { \ ++ printk Fmt; \ ++ } \ ++} ++ ++#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt) ++ ++ ++#define DBGPRINT_ERR(Fmt) \ ++{ \ ++ printk("ERROR!!! "); \ ++ printk Fmt; \ ++} ++ ++#define DBGPRINT_S(Status, Fmt) \ ++{ \ ++ printk Fmt; \ ++} ++ ++ ++#else ++#define DBGPRINT(Level, Fmt) ++#define DBGPRINT_RAW(Level, Fmt) ++#define DBGPRINT_S(Status, Fmt) ++#define DBGPRINT_ERR(Fmt) ++#endif ++ ++ ++// ++// spin_lock enhanced for Nested spin lock ++// ++#define NdisAllocateSpinLock(__lock) \ ++{ \ ++ spin_lock_init((spinlock_t *)(__lock)); \ ++} ++ ++#define NdisFreeSpinLock(lock) \ ++{ \ ++} ++ ++ ++#define RTMP_SEM_LOCK(__lock) \ ++{ \ ++ spin_lock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#define RTMP_SEM_UNLOCK(__lock) \ ++{ \ ++ spin_unlock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#if 0 // sample, IRQ LOCK ++#define RTMP_IRQ_LOCK(__lock, __irqflags) \ ++{ \ ++ spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ ++ pAd->irq_disabled |= 1; \ ++} ++ ++#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ ++{ \ ++ pAd->irq_disabled &= 0; \ ++ spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ ++} ++#else ++ ++// sample, use semaphore lock to replace IRQ lock, 2007/11/15 ++#define RTMP_IRQ_LOCK(__lock, __irqflags) \ ++{ \ ++ __irqflags = 0; \ ++ spin_lock_bh((spinlock_t *)(__lock)); \ ++ pAd->irq_disabled |= 1; \ ++} ++ ++#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ ++{ \ ++ pAd->irq_disabled &= 0; \ ++ spin_unlock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#define RTMP_INT_LOCK(__lock, __irqflags) \ ++{ \ ++ spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ ++} ++ ++#define RTMP_INT_UNLOCK(__lock, __irqflag) \ ++{ \ ++ spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ ++} ++#endif ++ ++ ++ ++#ifdef RT2870 ++//Patch for ASIC turst read/write bug, needs to remove after metel fix ++#define RTMP_IO_READ32(_A, _R, _pV) \ ++ RTUSBReadMACRegister(_A, _R, _pV) ++ ++#define RTMP_IO_READ8(_A, _R, _pV) \ ++{ \ ++} ++ ++#define RTMP_IO_WRITE32(_A, _R, _V) \ ++ RTUSBWriteMACRegister(_A, _R, _V) ++ ++ ++#define RTMP_IO_WRITE8(_A, _R, _V) \ ++{ \ ++ USHORT _Val = _V; \ ++ RTUSBSingleWrite(_A, _R, _Val); \ ++} ++ ++ ++#define RTMP_IO_WRITE16(_A, _R, _V) \ ++{ \ ++ RTUSBSingleWrite(_A, _R, _V); \ ++} ++#endif // RT2870 // ++ ++#ifndef wait_event_interruptible_timeout ++#define __wait_event_interruptible_timeout(wq, condition, ret) \ ++do { \ ++ wait_queue_t __wait; \ ++ init_waitqueue_entry(&__wait, current); \ ++ add_wait_queue(&wq, &__wait); \ ++ for (;;) { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (!signal_pending(current)) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ continue; \ ++ } \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&wq, &__wait); \ ++} while (0) ++ ++#define wait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!(condition)) \ ++ __wait_event_interruptible_timeout(wq, condition, __ret); \ ++ __ret; \ ++}) ++#endif ++#define ONE_TICK 1 ++#define OS_WAIT(_time) \ ++{ int _i; \ ++ long _loop = ((_time)/(1000/OS_HZ)) > 0 ? ((_time)/(1000/OS_HZ)) : 1;\ ++ wait_queue_head_t _wait; \ ++ init_waitqueue_head(&_wait); \ ++ for (_i=0; _i<(_loop); _i++) \ ++ wait_event_interruptible_timeout(_wait, 0, ONE_TICK); } ++ ++ ++typedef void (*TIMER_FUNCTION)(unsigned long); ++ ++#define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), MAC_ADDR_LEN) ++ ++#define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) ++#define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) ++ ++ ++#ifdef RT2870 ++#define BUILD_TIMER_FUNCTION(_func) \ ++void linux_##_func(unsigned long data) \ ++{ \ ++ PRALINK_TIMER_STRUCT _pTimer = (PRALINK_TIMER_STRUCT)data; \ ++ RT2870_TIMER_ENTRY *_pQNode; \ ++ RTMP_ADAPTER *_pAd; \ ++ \ ++ _pTimer->handle = _func; \ ++ _pAd = (RTMP_ADAPTER *)_pTimer->pAd; \ ++ _pQNode = RT2870_TimerQ_Insert(_pAd, _pTimer); \ ++ if ((_pQNode == NULL) && (_pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT)) \ ++ RTMP_OS_Add_Timer(&_pTimer->TimerObj, HZ); \ ++} ++#endif // RT2870 // ++ ++ ++#define DECLARE_TIMER_FUNCTION(_func) \ ++void linux_##_func(unsigned long data) ++ ++#define GET_TIMER_FUNCTION(_func) \ ++ linux_##_func ++ ++DECLARE_TIMER_FUNCTION(MlmePeriodicExec); ++DECLARE_TIMER_FUNCTION(MlmeRssiReportExec); ++DECLARE_TIMER_FUNCTION(AsicRxAntEvalTimeout); ++DECLARE_TIMER_FUNCTION(APSDPeriodicExec); ++DECLARE_TIMER_FUNCTION(AsicRfTuningExec); ++#ifdef RT2870 ++DECLARE_TIMER_FUNCTION(BeaconUpdateExec); ++#endif // RT2870 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++DECLARE_TIMER_FUNCTION(BeaconTimeout); ++DECLARE_TIMER_FUNCTION(ScanTimeout); ++DECLARE_TIMER_FUNCTION(AuthTimeout); ++DECLARE_TIMER_FUNCTION(AssocTimeout); ++DECLARE_TIMER_FUNCTION(ReassocTimeout); ++DECLARE_TIMER_FUNCTION(DisassocTimeout); ++DECLARE_TIMER_FUNCTION(LinkDownExec); ++#ifdef LEAP_SUPPORT ++DECLARE_TIMER_FUNCTION(LeapAuthTimeout); ++#endif ++DECLARE_TIMER_FUNCTION(StaQuickResponeForRateUpExec); ++DECLARE_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); ++DECLARE_TIMER_FUNCTION(PsPollWakeExec); ++DECLARE_TIMER_FUNCTION(RadioOnExec); ++ ++#ifdef QOS_DLS_SUPPORT ++DECLARE_TIMER_FUNCTION(DlsTimeoutAction); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); ++ ++ ++/* ++ * packet helper ++ * - convert internal rt packet to os packet or ++ * os packet to rt packet ++ */ ++#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) ++#define OSPKT_TO_RTPKT(_p) ((PNDIS_PACKET)(_p)) ++ ++#define GET_OS_PKT_DATAPTR(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->data) ++ ++#define GET_OS_PKT_LEN(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->len) ++ ++#define GET_OS_PKT_DATATAIL(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->tail) ++ ++#define GET_OS_PKT_HEAD(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->head) ++ ++#define GET_OS_PKT_END(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->end) ++ ++#define GET_OS_PKT_NETDEV(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->dev) ++ ++#define GET_OS_PKT_TYPE(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)) ++ ++#define GET_OS_PKT_NEXT(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->next) ++ ++ ++#define OS_NTOHS(_Val) \ ++ (ntohs(_Val)) ++#define OS_HTONS(_Val) \ ++ (htons(_Val)) ++#define OS_NTOHL(_Val) \ ++ (ntohl(_Val)) ++#define OS_HTONL(_Val) \ ++ (htonl(_Val)) ++ ++/* statistics counter */ ++#define STATS_INC_RX_PACKETS(_pAd, _dev) ++#define STATS_INC_TX_PACKETS(_pAd, _dev) ++ ++#define STATS_INC_RX_BYTESS(_pAd, _dev, len) ++#define STATS_INC_TX_BYTESS(_pAd, _dev, len) ++ ++#define STATS_INC_RX_ERRORS(_pAd, _dev) ++#define STATS_INC_TX_ERRORS(_pAd, _dev) ++ ++#define STATS_INC_RX_DROPPED(_pAd, _dev) ++#define STATS_INC_TX_DROPPED(_pAd, _dev) ++ ++ ++#define CB_OFF 10 ++ ++ ++// check DDK NDIS_PACKET data structure and find out only MiniportReservedEx[0..7] can be used by our driver without ++// ambiguity. Fields after pPacket->MiniportReservedEx[8] may be used by other wrapper layer thus crashes the driver ++// ++//#define RTMP_GET_PACKET_MR(_p) (RTPKT_TO_OSPKT(_p)) ++ ++// User Priority ++#define RTMP_SET_PACKET_UP(_p, _prio) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0] = _prio) ++#define RTMP_GET_PACKET_UP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0]) ++ ++// Fragment # ++#define RTMP_SET_PACKET_FRAGMENTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1] = _num) ++#define RTMP_GET_PACKET_FRAGMENTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1]) ++ ++// 0x0 ~0x7f: TX to AP's own BSS which has the specified AID. if AID>127, set bit 7 in RTMP_SET_PACKET_EMACTAB too. ++//(this value also as MAC(on-chip WCID) table index) ++// 0x80~0xff: TX to a WDS link. b0~6: WDS index ++#define RTMP_SET_PACKET_WCID(_p, _wdsidx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2] = _wdsidx) ++#define RTMP_GET_PACKET_WCID(_p) ((UCHAR)(RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2])) ++ ++// 0xff: PKTSRC_NDIS, others: local TX buffer index. This value affects how to a packet ++#define RTMP_SET_PACKET_SOURCE(_p, _pktsrc) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3] = _pktsrc) ++#define RTMP_GET_PACKET_SOURCE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3]) ++ ++// RTS/CTS-to-self protection method ++#define RTMP_SET_PACKET_RTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4] = _num) ++#define RTMP_GET_PACKET_RTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4]) ++// see RTMP_S(G)ET_PACKET_EMACTAB ++ ++// TX rate index ++#define RTMP_SET_PACKET_TXRATE(_p, _rate) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5] = _rate) ++#define RTMP_GET_PACKET_TXRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5]) ++ ++// From which Interface ++#define RTMP_SET_PACKET_IF(_p, _ifdx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6] = _ifdx) ++#define RTMP_GET_PACKET_IF(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6]) ++#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) RTMP_SET_PACKET_IF((_p), (_bss)) ++#define RTMP_SET_PACKET_NET_DEVICE_WDS(_p, _bss) RTMP_SET_PACKET_IF((_p), ((_bss) + MIN_NET_DEVICE_FOR_WDS)) ++#define RTMP_SET_PACKET_NET_DEVICE_APCLI(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_APCLI)) ++#define RTMP_SET_PACKET_NET_DEVICE_MESH(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_MESH)) ++#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) RTMP_GET_PACKET_IF((_p)) ++#define RTMP_GET_PACKET_NET_DEVICE(_p) RTMP_GET_PACKET_IF((_p)) ++ ++#define RTMP_SET_PACKET_MOREDATA(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7] = _morebit) ++#define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) ++ ++//#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) (RTPKT_TO_OSPKT(_p)->cb[8] = _bss) ++//#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) (RTPKT_TO_OSPKT(_p)->cb[8]) ++ ++ ++ ++ ++#if 0 ++//#define RTMP_SET_PACKET_DHCP(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) ++//#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) ++#else ++// ++// Sepcific Pakcet Type definition ++// ++#define RTMP_PACKET_SPECIFIC_CB_OFFSET 11 ++ ++#define RTMP_PACKET_SPECIFIC_DHCP 0x01 ++#define RTMP_PACKET_SPECIFIC_EAPOL 0x02 ++#define RTMP_PACKET_SPECIFIC_IPV4 0x04 ++#define RTMP_PACKET_SPECIFIC_WAI 0x08 ++#define RTMP_PACKET_SPECIFIC_VLAN 0x10 ++#define RTMP_PACKET_SPECIFIC_LLCSNAP 0x20 ++ ++//Specific ++#define RTMP_SET_PACKET_SPECIFIC(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) ++ ++//DHCP ++#define RTMP_SET_PACKET_DHCP(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_DHCP); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_DHCP); \ ++ }while(0) ++#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_DHCP) ++ ++//EAPOL ++#define RTMP_SET_PACKET_EAPOL(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_EAPOL); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_EAPOL); \ ++ }while(0) ++#define RTMP_GET_PACKET_EAPOL(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_EAPOL) ++ ++//WAI ++#define RTMP_SET_PACKET_WAI(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_WAI); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_WAI); \ ++ }while(0) ++#define RTMP_GET_PACKET_WAI(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_WAI) ++ ++#define RTMP_GET_PACKET_LOWRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & (RTMP_PACKET_SPECIFIC_EAPOL | RTMP_PACKET_SPECIFIC_DHCP | RTMP_PACKET_SPECIFIC_WAI)) ++ ++//VLAN ++#define RTMP_SET_PACKET_VLAN(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_VLAN); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_VLAN); \ ++ }while(0) ++#define RTMP_GET_PACKET_VLAN(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_VLAN) ++ ++//LLC/SNAP ++#define RTMP_SET_PACKET_LLCSNAP(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_LLCSNAP); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_LLCSNAP); \ ++ }while(0) ++ ++#define RTMP_GET_PACKET_LLCSNAP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_LLCSNAP) ++ ++// IP ++#define RTMP_SET_PACKET_IPV4(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_IPV4); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_IPV4); \ ++ }while(0) ++ ++#define RTMP_GET_PACKET_IPV4(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_IPV4) ++ ++#endif ++ ++ ++// If this flag is set, it indicates that this EAPoL frame MUST be clear. ++#define RTMP_SET_PACKET_CLEAR_EAP_FRAME(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12] = _flg) ++#define RTMP_GET_PACKET_CLEAR_EAP_FRAME(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12]) ++ ++#define RTMP_SET_PACKET_5VT(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22] = _flg) ++#define RTMP_GET_PACKET_5VT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22]) ++ ++ ++#ifdef CONFIG_5VT_ENHANCE ++#define BRIDGE_TAG 0x35564252 // depends on 5VT define in br_input.c ++#endif ++ ++ ++#define NDIS_SET_PACKET_STATUS(_p, _status) ++ ++ ++#define GET_SG_LIST_FROM_PACKET(_p, _sc) \ ++ rt_get_sg_list_from_packet(_p, _sc) ++ ++ ++#define NdisMoveMemory(Destination, Source, Length) memmove(Destination, Source, Length) ++#define NdisZeroMemory(Destination, Length) memset(Destination, 0, Length) ++#define NdisFillMemory(Destination, Length, Fill) memset(Destination, Fill, Length) ++#define NdisEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) ++#define RTMPEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) ++ ++ ++#define RTMP_INC_REF(_A) 0 ++#define RTMP_DEC_REF(_A) 0 ++#define RTMP_GET_REF(_A) 0 ++ ++ ++ ++/* ++ * ULONG ++ * RTMP_GetPhysicalAddressLow( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ */ ++#define RTMP_GetPhysicalAddressLow(PhysicalAddress) (PhysicalAddress) ++ ++/* ++ * ULONG ++ * RTMP_GetPhysicalAddressHigh( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ */ ++#define RTMP_GetPhysicalAddressHigh(PhysicalAddress) (0) ++ ++/* ++ * VOID ++ * RTMP_SetPhysicalAddressLow( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, ++ * IN ULONG Value); ++ */ ++#define RTMP_SetPhysicalAddressLow(PhysicalAddress, Value) \ ++ PhysicalAddress = Value; ++ ++/* ++ * VOID ++ * RTMP_SetPhysicalAddressHigh( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, ++ * IN ULONG Value); ++ */ ++#define RTMP_SetPhysicalAddressHigh(PhysicalAddress, Value) ++ ++ ++//CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); ++#define QUEUE_ENTRY_TO_PACKET(pEntry) \ ++ (PNDIS_PACKET)(pEntry) ++ ++#define PACKET_TO_QUEUE_ENTRY(pPacket) \ ++ (PQUEUE_ENTRY)(pPacket) ++ ++ ++#ifndef CONTAINING_RECORD ++#define CONTAINING_RECORD(address, type, field) \ ++((type *)((PCHAR)(address) - offsetof(type, field))) ++#endif ++ ++ ++#define RELEASE_NDIS_PACKET(_pAd, _pPacket, _Status) \ ++{ \ ++ RTMPFreeNdisPacket(_pAd, _pPacket); \ ++} ++ ++ ++#define SWITCH_PhyAB(_pAA, _pBB) \ ++{ \ ++ ULONG AABasePaHigh; \ ++ ULONG AABasePaLow; \ ++ ULONG BBBasePaHigh; \ ++ ULONG BBBasePaLow; \ ++ BBBasePaHigh = RTMP_GetPhysicalAddressHigh(_pBB); \ ++ BBBasePaLow = RTMP_GetPhysicalAddressLow(_pBB); \ ++ AABasePaHigh = RTMP_GetPhysicalAddressHigh(_pAA); \ ++ AABasePaLow = RTMP_GetPhysicalAddressLow(_pAA); \ ++ RTMP_SetPhysicalAddressHigh(_pAA, BBBasePaHigh); \ ++ RTMP_SetPhysicalAddressLow(_pAA, BBBasePaLow); \ ++ RTMP_SetPhysicalAddressHigh(_pBB, AABasePaHigh); \ ++ RTMP_SetPhysicalAddressLow(_pBB, AABasePaLow); \ ++} ++ ++ ++#define NdisWriteErrorLogEntry(_a, _b, _c, _d) ++#define NdisMAllocateMapRegisters(_a, _b, _c, _d, _e) NDIS_STATUS_SUCCESS ++ ++ ++#define NdisAcquireSpinLock RTMP_SEM_LOCK ++#define NdisReleaseSpinLock RTMP_SEM_UNLOCK ++ ++static inline void NdisGetSystemUpTime(ULONG *time) ++{ ++ *time = jiffies; ++} ++ ++//pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); ++#define QUEUE_ENTRY_TO_PKT(pEntry) \ ++ ((PNDIS_PACKET) (pEntry)) ++ ++int rt28xx_packet_xmit(struct sk_buff *skb); ++ ++ ++ ++void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rt_main_dev.c +@@ -0,0 +1,1863 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt_main_dev.c ++ ++ Abstract: ++ Create and register network interface. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Sample Mar/21/07 Merge RT2870 and RT2860 drivers. ++*/ ++ ++#include "rt_config.h" ++ ++#define FORTY_MHZ_INTOLERANT_INTERVAL (60*1000) // 1 min ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// record whether the card in the card list is used in the card file ++UINT8 MC_CardUsed[MAX_NUM_OF_MULTIPLE_CARD]; ++// record used card mac address in the card list ++static UINT8 MC_CardMac[MAX_NUM_OF_MULTIPLE_CARD][6]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++/*---------------------------------------------------------------------*/ ++/* Private Variables Used */ ++/*---------------------------------------------------------------------*/ ++//static RALINK_TIMER_STRUCT PeriodicTimer; ++ ++char *mac = ""; // default 00:00:00:00:00:00 ++char *hostname = ""; ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) ++MODULE_PARM (mac, "s"); ++#else ++module_param (mac, charp, 0); ++#endif ++MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); ++ ++ ++/*---------------------------------------------------------------------*/ ++/* Prototypes of Functions Used */ ++/*---------------------------------------------------------------------*/ ++#ifdef DOT11_N_SUPPORT ++extern BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); ++extern void ba_reordering_resource_release(PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); ++ ++ ++// public function prototype ++INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, ++ IN UINT argc, OUT PRTMP_ADAPTER *ppAd); ++ ++// private function prototype ++static int rt28xx_init(IN struct net_device *net_dev); ++INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev); ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++struct net_device *alloc_netdev( ++ int sizeof_priv, ++ const char *mask, ++ void (*setup)(struct net_device *)); ++#endif // LINUX_VERSION_CODE // ++ ++static void CfgInitHook(PRTMP_ADAPTER pAd); ++//static BOOLEAN RT28XXAvailRANameAssign(IN CHAR *name_p); ++ ++#ifdef CONFIG_STA_SUPPORT ++extern const struct iw_handler_def rt28xx_iw_handler_def; ++#endif // CONFIG_STA_SUPPORT // ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev); ++#endif ++ ++struct net_device_stats *RT28xx_get_ether_stats( ++ IN struct net_device *net_dev); ++ ++/* ++======================================================================== ++Routine Description: ++ Close raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int MainVirtualIF_close(IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ netif_carrier_off(pAd->net_dev); ++ netif_stop_queue(pAd->net_dev); ++ ++ ++ ++ VIRTUAL_IF_DOWN(pAd); ++ ++ RT_MOD_DEC_USE_COUNT(); ++ ++ return 0; // close ok ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Open raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int MainVirtualIF_open(IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ if (VIRTUAL_IF_UP(pAd) != 0) ++ return -1; ++ ++ // increase MODULE use count ++ RT_MOD_INC_USE_COUNT(); ++ ++ netif_start_queue(net_dev); ++ netif_carrier_on(net_dev); ++ netif_wake_queue(net_dev); ++ ++ return 0; ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Close raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int rt28xx_close(IN PNET_DEV dev) ++{ ++ struct net_device * net_dev = (struct net_device *)dev; ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ BOOLEAN Cancelled = FALSE; ++ UINT32 i = 0; ++#ifdef RT2870 ++ DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); ++ DECLARE_WAITQUEUE(wait, current); ++ ++ //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); ++#endif // RT2870 // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt28xx_close\n")); ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ // If dirver doesn't wake up firmware here, ++ // NICLoadFirmware will hang forever when interface is up again. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AsicForceWakeup(pAd, TRUE); ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ // send DLS-TEAR_DOWN message, ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ UCHAR i; ++ ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ RT28XX_MLME_HANDLER(pAd); ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ if (INFRA_ON(pAd) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ MLME_DISASSOC_REQ_STRUCT DisReq; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ COPY_MAC_ADDR(DisReq.Addr, pAd->CommonCfg.Bssid); ++ DisReq.Reason = REASON_DEAUTH_STA_LEAVING; ++ ++ MsgElem->Machine = ASSOC_STATE_MACHINE; ++ MsgElem->MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAd->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, MsgElem); ++ kfree(MsgElem); ++ ++ RTMPusecDelay(1000); ++ } ++ ++#ifdef RT2870 ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); ++#endif // RT2870 // ++ ++#ifdef CCX_SUPPORT ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &Cancelled); ++#endif ++ ++ RTMPCancelTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, &Cancelled); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ // send wireless event to wpa_supplicant for infroming interface down. ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_INTERFACE_DOWN; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ MlmeRadioOff(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ ++ for (i = 0 ; i < NUM_OF_TX_RING; i++) ++ { ++ while (pAd->DeQueueRunning[i] == TRUE) ++ { ++ printk("Waiting for TxQueue[%d] done..........\n", i); ++ RTMPusecDelay(1000); ++ } ++ } ++ ++#ifdef RT2870 ++ // ensure there are no more active urbs. ++ add_wait_queue (&unlink_wakeup, &wait); ++ pAd->wait = &unlink_wakeup; ++ ++ // maybe wait for deletions to finish. ++ i = 0; ++ //while((i < 25) && atomic_read(&pAd->PendingRx) > 0) ++ while(i < 25) ++ { ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ if (pAd->PendingRx == 0) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ break; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) ++ msleep(UNLINK_TIMEOUT_MS); //Time in millisecond ++#else ++ RTMPusecDelay(UNLINK_TIMEOUT_MS*1000); //Time in microsecond ++#endif ++ i++; ++ } ++ pAd->wait = NULL; ++ remove_wait_queue (&unlink_wakeup, &wait); ++#endif // RT2870 // ++ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); /*not used in RT28xx*/ ++ ++ ++#ifdef RT2870 ++ // We need clear timerQ related structure before exits of the timer thread. ++ RT2870_TimerQ_Exit(pAd); ++ // Close kernel threads or tasklets ++ RT28xxThreadTerminate(pAd); ++#endif // RT2870 // ++ ++ // Stop Mlme state machine ++ MlmeHalt(pAd); ++ ++ // Close kernel threads or tasklets ++ kill_thread_task(pAd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ MacTableReset(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ MeasureReqTabExit(pAd); ++ TpcReqTabExit(pAd); ++ ++ ++ ++ ++ // Free Ring or USB buffers ++ RTMPFreeTxRxRingMemory(pAd); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ ++#ifdef DOT11_N_SUPPORT ++ // Free BA reorder resource ++ ba_reordering_resource_release(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef RT2870 ++#ifdef INF_AMAZON_SE ++ if (pAd->UsbVendorReqBuf) ++ os_free_mem(pAd, pAd->UsbVendorReqBuf); ++#endif // INF_AMAZON_SE // ++#endif // RT2870 // ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_START_UP); ++ ++ return 0; // close ok ++} /* End of rt28xx_close */ ++ ++static int rt28xx_init(IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->priv; ++ UINT index; ++ UCHAR TmpPhy; ++ NDIS_STATUS Status; ++ UINT32 MacCsr0 = 0; ++ ++#ifdef RT2870 ++#ifdef INF_AMAZON_SE ++ init_MUTEX(&(pAd->UsbVendorReq_semaphore)); ++ os_alloc_mem(pAd, (PUCHAR)&pAd->UsbVendorReqBuf, MAX_PARAM_BUFFER_SIZE - 1); ++ if (pAd->UsbVendorReqBuf == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Allocate vendor request temp buffer failed!\n")); ++ goto err0; ++ } ++#endif // INF_AMAZON_SE // ++#endif // RT2870 // ++ ++#ifdef DOT11_N_SUPPORT ++ // Allocate BA Reordering memory ++ ba_reordering_resource_init(pAd, MAX_REORDERING_MPDU_NUM); ++#endif // DOT11_N_SUPPORT // ++ ++ // Make sure MAC gets ready. ++ index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); ++ pAd->MACVersion = MacCsr0; ++ ++ if ((pAd->MACVersion != 0x00) && (pAd->MACVersion != 0xFFFFFFFF)) ++ break; ++ ++ RTMPusecDelay(10); ++ } while (index++ < 100); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); ++ ++ // Disable DMA ++ RT28XXDMADisable(pAd); ++ ++ ++ // Load 8051 firmware ++ Status = NICLoadFirmware(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); ++ goto err1; ++ } ++ ++ NICLoadRateSwitchingParams(pAd); ++ ++ // Disable interrupts here which is as soon as possible ++ // This statement should never be true. We might consider to remove it later ++ ++ Status = RTMPAllocTxRxRingMemory(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status)); ++ goto err1; ++ } ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ ++ // initialize MLME ++ // ++ ++ Status = MlmeInit(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status)); ++ goto err2; ++ } ++ ++ // Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default ++ // ++ UserCfgInit(pAd); ++ ++#ifdef RT2870 ++ // We need init timerQ related structure before create the timer thread. ++ RT2870_TimerQ_Init(pAd); ++#endif // RT2870 // ++ ++ RT28XX_TASK_THREAD_INIT(pAd, Status); ++ if (Status != NDIS_STATUS_SUCCESS) ++ goto err1; ++ ++// COPY_MAC_ADDR(pAd->ApCfg.MBSSID[apidx].Bssid, netif->hwaddr); ++// pAd->bForcePrintTX = TRUE; ++ ++ CfgInitHook(pAd); ++ ++ ++#ifdef BLOCK_NET_IF ++ initblockQueueTab(pAd); ++#endif // BLOCK_NET_IF // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisAllocateSpinLock(&pAd->MacTabLock); ++#endif // CONFIG_STA_SUPPORT // ++ ++ MeasureReqTabInit(pAd); ++ TpcReqTabInit(pAd); ++ ++ // ++ // Init the hardware, we need to init asic before read registry, otherwise mac register will be reset ++ // ++ Status = NICInitializeAdapter(pAd, TRUE); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n", Status)); ++ if (Status != NDIS_STATUS_SUCCESS) ++ goto err3; ++ } ++ ++ // Read parameters from Config File ++ Status = RTMPReadParametersHook(pAd); ++ ++ printk("1. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICReadRegParameters failed, Status[=0x%08x]\n",Status)); ++ goto err4; ++ } ++ ++#ifdef RT2870 ++ pAd->CommonCfg.bMultipleIRP = FALSE; ++ ++ if (pAd->CommonCfg.bMultipleIRP) ++ pAd->CommonCfg.NumOfBulkInIRP = RX_RING_SIZE; ++ else ++ pAd->CommonCfg.NumOfBulkInIRP = 1; ++#endif // RT2870 // ++ ++ ++ //Init Ba Capability parameters. ++// RT28XX_BA_INIT(pAd); ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.DesiredHtPhy.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ // UPdata to HT IE ++ pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++#endif // DOT11_N_SUPPORT // ++ ++ // after reading Registry, we now know if in AP mode or STA mode ++ ++ // Load 8051 firmware; crash when FW image not existent ++ // Status = NICLoadFirmware(pAd); ++ // if (Status != NDIS_STATUS_SUCCESS) ++ // break; ++ ++ printk("2. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ ++ // We should read EEPROM for all cases. rt2860b ++ NICReadEEPROMParameters(pAd, mac); ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ printk("3. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ ++ NICInitAsicFromEEPROM(pAd); //rt2860b ++ ++ // Set PHY to appropriate mode ++ TmpPhy = pAd->CommonCfg.PhyMode; ++ pAd->CommonCfg.PhyMode = 0xff; ++ RTMPSetPhyMode(pAd, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ // No valid channels. ++ if (pAd->ChannelListNum == 0) ++ { ++ printk("Wrong configuration. No valid channel found. Check \"ContryCode\" and \"ChannelGeography\" setting.\n"); ++ goto err4; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ printk("MCS Set = %02x %02x %02x %02x %02x\n", pAd->CommonCfg.HtCapability.MCSSet[0], ++ pAd->CommonCfg.HtCapability.MCSSet[1], pAd->CommonCfg.HtCapability.MCSSet[2], ++ pAd->CommonCfg.HtCapability.MCSSet[3], pAd->CommonCfg.HtCapability.MCSSet[4]); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef RT2870 ++ //Init RT30xx RFRegisters after read RFIC type from EEPROM ++ NICInitRT30xxRFRegisters(pAd); ++#endif // RT2870 // ++ ++#if 0 ++ // Patch cardbus controller if EEPROM said so. ++ if (pAd->bTest1 == FALSE) ++ RTMPPatchCardBus(pAd); ++#endif ++ ++ ++// APInitialize(pAd); ++ ++#ifdef IKANOS_VX_1X0 ++ VR_IKANOS_FP_Init(pAd->ApCfg.BssidNum, pAd->PermanentAddress); ++#endif // IKANOS_VX_1X0 // ++ ++ // ++ // Initialize RF register to default value ++ // ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // 8051 firmware require the signal during booting time. ++ AsicSendCommandToMcu(pAd, 0x72, 0xFF, 0x00, 0x00); ++ ++ if (pAd && (Status != NDIS_STATUS_SUCCESS)) ++ { ++ // ++ // Undo everything if it failed ++ // ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++// NdisMDeregisterInterrupt(&pAd->Interrupt); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ } ++// RTMPFreeAdapter(pAd); // we will free it in disconnect() ++ } ++ else if (pAd) ++ { ++ // Microsoft HCT require driver send a disconnect event after driver initialization. ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++// pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event B!\n")); ++ ++ ++#ifdef RT2870 ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); ++ ++ // ++ // Support multiple BulkIn IRP, ++ // the value on pAd->CommonCfg.NumOfBulkInIRP may be large than 1. ++ // ++ for(index=0; indexCommonCfg.NumOfBulkInIRP; index++) ++ { ++ RTUSBBulkReceive(pAd); ++ DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkReceive!\n" )); ++ } ++#endif // RT2870 // ++ }// end of else ++ ++ ++ DBGPRINT_S(Status, ("<==== RTMPInitialize, Status=%x\n", Status)); ++ ++ return TRUE; ++ ++ ++err4: ++err3: ++ MlmeHalt(pAd); ++err2: ++ RTMPFreeTxRxRingMemory(pAd); ++// RTMPFreeAdapter(pAd); ++err1: ++ ++#ifdef DOT11_N_SUPPORT ++ os_free_mem(pAd, pAd->mpdu_blk_pool.mem); // free BA pool ++#endif // DOT11_N_SUPPORT // ++ RT28XX_IRQ_RELEASE(net_dev); ++ ++ // shall not set priv to NULL here because the priv didn't been free yet. ++ //net_dev->priv = 0; ++#ifdef INF_AMAZON_SE ++err0: ++#endif // INF_AMAZON_SE // ++ printk("!!! %s Initialized fail !!!\n", RT28xx_CHIP_NAME); ++ return FALSE; ++} /* End of rt28xx_init */ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Open raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++======================================================================== ++*/ ++int rt28xx_open(IN PNET_DEV dev) ++{ ++ struct net_device * net_dev = (struct net_device *)dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->priv; ++ int retval = 0; ++ POS_COOKIE pObj; ++ ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -1; ++ } ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ CW_MAX_IN_BITS = 6; ++ } ++ else if (pAd->OpMode == OPMODE_STA) ++ { ++ CW_MAX_IN_BITS = 10; ++ } ++ ++#if WIRELESS_EXT >= 12 ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ if (pAd->OpMode == OPMODE_AP) ++ net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_ap_iw_handler_def; ++ else if (pAd->OpMode == OPMODE_STA) ++ net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_iw_handler_def; ++ } ++#endif // WIRELESS_EXT >= 12 // ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Init ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ // reset Adapter flags ++ RTMP_CLEAR_FLAGS(pAd); ++ ++ // Request interrupt service routine for PCI device ++ // register the interrupt routine with the os ++ RT28XX_IRQ_REQUEST(net_dev); ++ ++ ++ // Init BssTab & ChannelInfo tabbles for auto channel select. ++ ++ ++ // Chip & other init ++ if (rt28xx_init(net_dev) == FALSE) ++ goto err; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NdisZeroMemory(pAd->StaCfg.dev_name, 16); ++ NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Set up the Mac address ++ NdisMoveMemory(net_dev->dev_addr, (void *) pAd->CurrentAddress, 6); ++ ++ // Init IRQ parameters ++ RT28XX_IRQ_INIT(pAd); ++ ++ // Various AP function init ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ // send wireless event to wpa_supplicant for infroming interface down. ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_INTERFACE_UP; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Enable Interrupt ++ RT28XX_IRQ_ENABLE(pAd); ++ ++ // Now Enable RxTx ++ RTMPEnableRxTx(pAd); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP); ++ ++ { ++ UINT32 reg = 0; ++ RTMP_IO_READ32(pAd, 0x1300, ®); // clear garbage interrupts ++ printk("0x1300 = %08x\n", reg); ++ } ++ ++ { ++// u32 reg; ++// u8 byte; ++// u16 tmp; ++ ++// RTMP_IO_READ32(pAd, XIFS_TIME_CFG, ®); ++ ++// tmp = 0x0805; ++// reg = (reg & 0xffff0000) | tmp; ++// RTMP_IO_WRITE32(pAd, XIFS_TIME_CFG, reg); ++ ++ } ++ ++#if 0 ++ /* ++ * debugging helper ++ * show the size of main table in Adapter structure ++ * MacTab -- 185K ++ * BATable -- 137K ++ * Total -- 385K !!!!! (5/26/2006) ++ */ ++ printk("sizeof(pAd->MacTab) = %ld\n", sizeof(pAd->MacTab)); ++ printk("sizeof(pAd->AccessControlList) = %ld\n", sizeof(pAd->AccessControlList)); ++ printk("sizeof(pAd->ApCfg) = %ld\n", sizeof(pAd->ApCfg)); ++ printk("sizeof(pAd->BATable) = %ld\n", sizeof(pAd->BATable)); ++ BUG(); ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ return (retval); ++ ++err: ++ return (-1); ++} /* End of rt28xx_open */ ++ ++ ++/* Must not be called for mdev and apdev */ ++static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status; ++ INT i=0; ++ CHAR slot_name[IFNAMSIZ]; ++ struct net_device *device; ++ ++ ++ //ether_setup(dev); ++ dev->hard_start_xmit = rt28xx_send_packets; ++ ++#ifdef IKANOS_VX_1X0 ++ dev->hard_start_xmit = IKANOS_DataFramesTx; ++#endif // IKANOS_VX_1X0 // ++ ++// dev->set_multicast_list = ieee80211_set_multicast_list; ++// dev->change_mtu = ieee80211_change_mtu; ++#ifdef CONFIG_STA_SUPPORT ++#if WIRELESS_EXT >= 12 ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ dev->wireless_handlers = &rt28xx_iw_handler_def; ++ } ++#endif //WIRELESS_EXT >= 12 ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++#if WIRELESS_EXT >= 12 ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ dev->wireless_handlers = &rt28xx_ap_iw_handler_def; ++ } ++#endif //WIRELESS_EXT >= 12 ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#if WIRELESS_EXT < 21 ++ dev->get_wireless_stats = rt28xx_get_wireless_stats; ++#endif ++ dev->get_stats = RT28xx_get_ether_stats; ++ dev->open = MainVirtualIF_open; //rt28xx_open; ++ dev->stop = MainVirtualIF_close; //rt28xx_close; ++// dev->uninit = ieee80211_if_reinit; ++// dev->destructor = ieee80211_if_free; ++ dev->priv_flags = INT_MAIN; ++ dev->do_ioctl = rt28xx_ioctl; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++ dev->validate_addr = NULL; ++#endif ++ // find available device name ++ for (i = 0; i < 8; i++) ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if (pAd->MC_RowID >= 0) ++ sprintf(slot_name, "ra%02d_%d", pAd->MC_RowID, i); ++ else ++#endif // MULTIPLE_CARD_SUPPORT // ++ sprintf(slot_name, "ra%d", i); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ device = dev_get_by_name(dev_net(dev), slot_name); ++#else ++ device = dev_get_by_name(dev->nd_net, slot_name); ++#endif ++#else ++ device = dev_get_by_name(slot_name); ++#endif ++ if (device != NULL) dev_put(device); ++#else ++ for (device = dev_base; device != NULL; device = device->next) ++ { ++ if (strncmp(device->name, slot_name, 4) == 0) ++ break; ++ } ++#endif ++ if(device == NULL) ++ break; ++ } ++ ++ if(i == 8) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if (pAd->MC_RowID >= 0) ++ sprintf(dev->name, "ra%02d_%d", pAd->MC_RowID, i); ++ else ++#endif // MULTIPLE_CARD_SUPPORT // ++ sprintf(dev->name, "ra%d", i); ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ ++ return Status; ++ ++} ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++/* ++======================================================================== ++Routine Description: ++ Get card profile path. ++ ++Arguments: ++ pAd ++ ++Return Value: ++ TRUE - Find a card profile ++ FALSE - use default profile ++ ++Note: ++======================================================================== ++*/ ++extern INT RTMPGetKeyParameter( ++ IN PCHAR key, ++ OUT PCHAR dest, ++ IN INT destsize, ++ IN PCHAR buffer); ++ ++BOOLEAN RTMP_CardInfoRead( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define MC_SELECT_CARDID 0 /* use CARD ID (0 ~ 31) to identify different cards */ ++#define MC_SELECT_MAC 1 /* use CARD MAC to identify different cards */ ++#define MC_SELECT_CARDTYPE 2 /* use CARD type (abgn or bgn) to identify different cards */ ++ ++#define LETTER_CASE_TRANSLATE(txt_p, card_id) \ ++ { UINT32 _len; char _char; \ ++ for(_len=0; _lenfsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ // get RF IC type ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &data); ++ ++ if ((data & 0x30) == 0) ++ pAd->EEPROMAddressNum = 6; // 93C46 ++ else if ((data & 0x30) == 0x10) ++ pAd->EEPROMAddressNum = 8; // 93C66 ++ else ++ pAd->EEPROMAddressNum = 8; // 93C86 ++ ++ //antenna.word = RTMP_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, antenna.word); ++ ++ if ((antenna.field.RfIcType == RFIC_2850) || ++ (antenna.field.RfIcType == RFIC_2750)) ++ { ++ /* ABGN card */ ++ strcpy(RFIC_word, "abgn"); ++ } ++ else ++ { ++ /* BGN card */ ++ strcpy(RFIC_word, "bgn"); ++ } ++ ++ // get MAC address ++ //addr01 = RTMP_EEPROM_READ16(pAd, 0x04); ++ //addr23 = RTMP_EEPROM_READ16(pAd, 0x06); ++ //addr45 = RTMP_EEPROM_READ16(pAd, 0x08); ++ RT28xx_EEPROM_READ16(pAd, 0x04, addr01); ++ RT28xx_EEPROM_READ16(pAd, 0x06, addr23); ++ RT28xx_EEPROM_READ16(pAd, 0x08, addr45); ++ ++ mac[0] = (UCHAR)(addr01 & 0xff); ++ mac[1] = (UCHAR)(addr01 >> 8); ++ mac[2] = (UCHAR)(addr23 & 0xff); ++ mac[3] = (UCHAR)(addr23 >> 8); ++ mac[4] = (UCHAR)(addr45 & 0xff); ++ mac[5] = (UCHAR)(addr45 >> 8); ++ ++ // open card information file ++ srcf = filp_open(CARD_INFO_PATH, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ /* card information file does not exist */ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("--> Error %ld opening %s\n", -PTR_ERR(srcf), CARD_INFO_PATH)); ++ return FALSE; ++ } ++ ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ /* card information file exists so reading the card information */ ++ memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); ++ retval = srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); ++ if (retval < 0) ++ { ++ /* read fail */ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("--> Read %s error %d\n", CARD_INFO_PATH, -retval)); ++ } ++ else ++ { ++ /* get card selection method */ ++ memset(tmpbuf, 0x00, MAX_PARAM_BUFFER_SIZE); ++ card_select_method = MC_SELECT_CARDTYPE; // default ++ ++ if (RTMPGetKeyParameter("SELECT", tmpbuf, 256, buffer)) ++ { ++ if (strcmp(tmpbuf, "CARDID") == 0) ++ card_select_method = MC_SELECT_CARDID; ++ else if (strcmp(tmpbuf, "MAC") == 0) ++ card_select_method = MC_SELECT_MAC; ++ else if (strcmp(tmpbuf, "CARDTYPE") == 0) ++ card_select_method = MC_SELECT_CARDTYPE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("MC> Card Selection = %d\n", card_select_method)); ++ ++ // init ++ card_free_id = -1; ++ card_nouse_id = -1; ++ card_same_mac_id = -1; ++ card_match_id = -1; ++ ++ // search current card information records ++ for(card_index=0; ++ card_index Free = %d, Same = %d, NOUSE = %d\n", ++ card_free_id, card_same_mac_id, card_nouse_id)); ++ ++ if ((card_same_mac_id >= 0) && ++ ((card_select_method == MC_SELECT_CARDID) || ++ (card_select_method == MC_SELECT_CARDTYPE))) ++ { ++ // same MAC entry is found ++ card_match_id = card_same_mac_id; ++ ++ if (card_select_method == MC_SELECT_CARDTYPE) ++ { ++ // for CARDTYPE ++ sprintf(card_id_buf, "%02dCARDTYPE%s", ++ card_match_id, RFIC_word); ++ ++ if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) ++ { ++ // we found the card ID ++ LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); ++ } ++ } ++ } ++ else ++ { ++ // the card is 1st plug-in, try to find the match card profile ++ switch(card_select_method) ++ { ++ case MC_SELECT_CARDID: // CARDID ++ default: ++ if (card_free_id >= 0) ++ card_match_id = card_free_id; ++ else ++ card_match_id = card_nouse_id; ++ break; ++ ++ case MC_SELECT_MAC: // MAC ++ sprintf(card_id_buf, "MAC%02x:%02x:%02x:%02x:%02x:%02x", ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ ++ /* try to find the key word in the card file */ ++ if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) ++ { ++ LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); ++ ++ /* get the row ID (2 ASCII characters) */ ++ start_ptr -= 2; ++ card_id_buf[0] = *(start_ptr); ++ card_id_buf[1] = *(start_ptr+1); ++ card_id_buf[2] = 0x00; ++ ++ card_match_id = simple_strtol(card_id_buf, 0, 10); ++ } ++ break; ++ ++ case MC_SELECT_CARDTYPE: // CARDTYPE ++ card_nouse_id = -1; ++ ++ for(card_index=0; ++ card_index= 0) ++ { ++ // make up search keyword ++ switch(card_select_method) ++ { ++ case MC_SELECT_CARDID: // CARDID ++ sprintf(card_id_buf, "%02dCARDID", card_match_id); ++ break; ++ ++ case MC_SELECT_MAC: // MAC ++ sprintf(card_id_buf, ++ "%02dmac%02x:%02x:%02x:%02x:%02x:%02x", ++ card_match_id, ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ break; ++ ++ case MC_SELECT_CARDTYPE: // CARDTYPE ++ default: ++ sprintf(card_id_buf, "%02dcardtype%s", ++ card_match_id, RFIC_word); ++ break; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Search Keyword = %s\n", card_id_buf)); ++ ++ // read card file path ++ if (RTMPGetKeyParameter(card_id_buf, tmpbuf, 256, buffer)) ++ { ++ if (strlen(tmpbuf) < sizeof(pAd->MC_FileName)) ++ { ++ // backup card information ++ pAd->MC_RowID = card_match_id; /* base 0 */ ++ MC_CardUsed[card_match_id] = 1; ++ memcpy(MC_CardMac[card_match_id], mac, sizeof(mac)); ++ ++ // backup card file path ++ NdisMoveMemory(pAd->MC_FileName, tmpbuf , strlen(tmpbuf)); ++ pAd->MC_FileName[strlen(tmpbuf)] = '\0'; ++ flg_match_ok = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("Card Profile Name = %s\n", pAd->MC_FileName)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("Card Profile Name length too large!\n")); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("Can not find search key word in card.dat!\n")); ++ } ++ ++ if ((flg_match_ok != TRUE) && ++ (card_match_id < MAX_NUM_OF_MULTIPLE_CARD)) ++ { ++ MC_CardUsed[card_match_id] = 0; ++ memset(MC_CardMac[card_match_id], 0, sizeof(mac)); ++ } ++ } // if (card_match_id >= 0) ++ } ++ } ++ ++ // close file ++ retval = filp_close(srcf, NULL); ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ kfree(buffer); ++ kfree(tmpbuf); ++ return flg_match_ok; ++} ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Probe RT28XX chipset. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ _dev_id_p Point to the PCI or USB device ID ++ ++Return Value: ++ 0 Probe OK ++ -ENODEV Probe Fail ++ ++Note: ++======================================================================== ++*/ ++INT __devinit rt28xx_probe( ++ IN void *_dev_p, ++ IN void *_dev_id_p, ++ IN UINT argc, ++ OUT PRTMP_ADAPTER *ppAd) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; ++ INT status; ++ PVOID handle; ++#ifdef RT2870 ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++#else ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_device *dev_p = interface_to_usbdev(intf); ++ ++ dev_p = usb_get_dev(dev_p); ++#endif // LINUX_VERSION_CODE // ++#endif // RT2870 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Check chipset vendor/product ID ++// if (RT28XXChipsetCheck(_dev_p) == FALSE) ++// goto err_out; ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++ net_dev = alloc_netdev(sizeof(PRTMP_ADAPTER), "eth%d", ether_setup); ++#else ++ net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); ++#endif ++ if (net_dev == NULL) ++ { ++ printk("alloc_netdev failed\n"); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ module_put(THIS_MODULE); ++#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++#else ++ MOD_DEC_USE_COUNT; ++#endif ++ goto err_out; ++ } ++ ++// sample ++// if (rt_ieee80211_if_setup(net_dev) != NDIS_STATUS_SUCCESS) ++// goto err_out; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(net_dev); ++#endif ++ ++ netif_stop_queue(net_dev); ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++/* for supporting Network Manager */ ++/* Set the sysfs physical device reference for the network logical device ++ * if set prior to registration will cause a symlink during initialization. ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ SET_NETDEV_DEV(net_dev, &(dev_p->dev)); ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ // Allocate RTMP_ADAPTER miniport adapter structure ++ handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); ++ RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p); ++ ++ status = RTMPAllocAdapterBlock(handle, &pAd); ++ if (status != NDIS_STATUS_SUCCESS) ++ goto err_out_free_netdev; ++ ++ net_dev->priv = (PVOID)pAd; ++ pAd->net_dev = net_dev; // must be before RT28XXNetDevInit() ++ ++ RT28XXNetDevInit(_dev_p, net_dev, pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAd->StaCfg.OriDevType = net_dev->type; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Find and assign a free interface name, raxx ++// RT28XXAvailRANameAssign(net_dev->name); ++ ++ // Post config ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ if (RT28XXProbePostConfig(_dev_p, pAd, argc) == FALSE) ++ goto err_out_unmap; ++#else ++ if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) ++ goto err_out_unmap; ++#endif // LINUX_VERSION_CODE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAd->OpMode = OPMODE_STA; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++ // find its profile path ++ pAd->MC_RowID = -1; // use default profile path ++ RTMP_CardInfoRead(pAd); ++ ++ if (pAd->MC_RowID == -1) ++#ifdef CONFIG_STA_SUPPORT ++ strcpy(pAd->MC_FileName, STA_PROFILE_PATH); ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("MC> ROW = %d, PATH = %s\n", pAd->MC_RowID, pAd->MC_FileName)); ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ // sample move ++ if (rt_ieee80211_if_setup(net_dev, pAd) != NDIS_STATUS_SUCCESS) ++ goto err_out_unmap; ++ ++ // Register this device ++ status = register_netdev(net_dev); ++ if (status) ++ goto err_out_unmap; ++ ++ // Set driver data ++ RT28XX_DRVDATA_SET(_dev_p); ++ ++ ++ ++ *ppAd = pAd; ++ return 0; // probe ok ++ ++ ++ /* --------------------------- ERROR HANDLE --------------------------- */ ++err_out_unmap: ++ RTMPFreeAdapter(pAd); ++ RT28XX_UNMAP(); ++ ++err_out_free_netdev: ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ free_netdev(net_dev); ++#else ++ kfree(net_dev); ++#endif ++ ++err_out: ++ RT28XX_PUT_DEVICE(dev_p); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return (LONG)NULL; ++#else ++ return -ENODEV; /* probe fail */ ++#endif // LINUX_VERSION_CODE // ++} /* End of rt28xx_probe */ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ The entry point for Linux kernel sent packet to our driver. ++ ++Arguments: ++ sk_buff *skb the pointer refer to a sk_buffer. ++ ++Return Value: ++ 0 ++ ++Note: ++ This function is the entry point of Tx Path for Os delivery packet to ++ our driver. You only can put OS-depened & STA/AP common handle procedures ++ in here. ++======================================================================== ++*/ ++int rt28xx_packet_xmit(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = skb->dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ int status = 0; ++ PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; ++ ++ /* RT2870STA does this in RTMPSendPackets() */ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); ++ return 0; ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Drop send request since we are in monitor mode ++ if (MONITOR_ON(pAd)) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ goto done; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // EapolStart size is 18 ++ if (skb->len < 14) ++ { ++ //printk("bad packet size: %d\n", pkt->len); ++ hex_dump("bad packet", skb->data, skb->len); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ goto done; ++ } ++ ++#if 0 ++// if ((pkt->data[0] & 0x1) == 0) ++ { ++ //hex_dump(__FUNCTION__, pkt->data, pkt->len); ++ printk("pPacket = %x\n", pPacket); ++ } ++#endif ++ ++ RTMP_SET_PACKET_5VT(pPacket, 0); ++// MiniportMMRequest(pAd, pkt->data, pkt->len); ++#ifdef CONFIG_5VT_ENHANCE ++ if (*(int*)(skb->cb) == BRIDGE_TAG) { ++ RTMP_SET_PACKET_5VT(pPacket, 1); ++ } ++#endif ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ status = 0; ++done: ++ ++ return status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Send a packet to WLAN. ++ ++Arguments: ++ skb_p points to our adapter ++ dev_p which WLAN network interface ++ ++Return Value: ++ 0: transmit successfully ++ otherwise: transmit fail ++ ++Note: ++======================================================================== ++*/ ++INT rt28xx_send_packets( ++ IN struct sk_buff *skb_p, ++ IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->priv; ++ ++ if (!(net_dev->flags & IFF_UP)) ++ { ++ RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); ++ return 0; ++ } ++ ++ NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); ++ RTMP_SET_PACKET_NET_DEVICE_MBSSID(skb_p, MAIN_MBSSID); ++ ++ return rt28xx_packet_xmit(skb_p); ++} /* End of MBSS_VirtualIF_PacketSend */ ++ ++ ++ ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++//static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) //sample ++struct net_device *alloc_netdev( ++ int sizeof_priv, ++ const char *mask, ++ void (*setup)(struct net_device *)) ++{ ++ struct net_device *dev; ++ INT alloc_size; ++ ++ ++ /* ensure 32-byte alignment of the private area */ ++ alloc_size = sizeof (*dev) + sizeof_priv + 31; ++ ++ dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); ++ if (dev == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("alloc_netdev: Unable to allocate device memory.\n")); ++ return NULL; ++ } ++ ++ memset(dev, 0, alloc_size); ++ ++ if (sizeof_priv) ++ dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); ++ ++ setup(dev); ++ strcpy(dev->name, mask); ++ ++ return dev; ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++void CfgInitHook(PRTMP_ADAPTER pAd) ++{ ++ pAd->bBroadComHT = TRUE; ++} /* End of CfgInitHook */ ++ ++ ++#if 0 // Not used now, should keep it in our source tree?? ++/* ++======================================================================== ++Routine Description: ++ Find and assign a free interface name (raxx). ++ ++Arguments: ++ *name_p the interface name pointer ++ ++Return Value: ++ TRUE OK ++ FALSE FAIL ++ ++Note: ++======================================================================== ++*/ ++static BOOLEAN RT28XXAvailRANameAssign( ++ IN CHAR *name_p) ++{ ++ CHAR slot_name[IFNAMSIZ]; ++ struct net_device *device; ++ UINT32 if_id; ++ ++ ++ for(if_id=0; if_id<8; if_id++) ++ { ++ sprintf(slot_name, "ra%d", if_id); ++ ++ for(device=dev_base; device!=NULL; device=device->next) ++ { ++ if (strncmp(device->name, slot_name, 4) == 0) ++ break; ++ } ++ ++ if (device == NULL) ++ break; ++ } ++ ++ if (if_id == 8) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); ++ return FALSE; ++ } ++ ++ sprintf(name_p, "ra%d", if_id); ++ return TRUE; ++} /* End of RT28XXAvailRANameAssign */ ++#endif ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt28xx_get_wireless_stats --->\n")); ++ ++ pAd->iw_stats.status = 0; // Status - device dependent for now ++ ++ // link quality ++ pAd->iw_stats.qual.qual = ((pAd->Mlme.ChannelQuality * 12)/10 + 10); ++ if(pAd->iw_stats.qual.qual > 100) ++ pAd->iw_stats.qual.qual = 100; ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ pAd->iw_stats.qual.level = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->iw_stats.qual.noise = pAd->BbpWriteLatch[66]; // noise level (dBm) ++ ++ pAd->iw_stats.qual.noise += 256 - 143; ++ pAd->iw_stats.qual.updated = 1; // Flags to know if updated ++#ifdef IW_QUAL_DBM ++ pAd->iw_stats.qual.updated |= IW_QUAL_DBM; // Level + Noise are dBm ++#endif // IW_QUAL_DBM // ++ ++ pAd->iw_stats.discard.nwid = 0; // Rx : Wrong nwid/essid ++ pAd->iw_stats.miss.beacon = 0; // Missed beacons/superframe ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- rt28xx_get_wireless_stats\n")); ++ return &pAd->iw_stats; ++} /* End of rt28xx_get_wireless_stats */ ++#endif // WIRELESS_EXT // ++ ++ ++ ++void tbtt_tasklet(unsigned long data) ++{ ++#define MAX_TX_IN_TBTT (16) ++ ++} ++ ++INT rt28xx_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ INT ret = 0; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ret = rt28xx_sta_ioctl(net_dev, rq, cmd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return ret; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ return ethernet statistics counter ++ ++ Arguments: ++ net_dev Pointer to net_device ++ ++ Return Value: ++ net_device_stats* ++ ++ Note: ++ ++ ======================================================================== ++*/ ++struct net_device_stats *RT28xx_get_ether_stats( ++ IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = NULL; ++ ++ if (net_dev) ++ pAd = net_dev->priv; ++ ++ if (pAd) ++ { ++ ++ pAd->stats.rx_packets = pAd->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pAd->stats.tx_packets = pAd->WlanCounters.TransmittedFragmentCount.QuadPart; ++ ++ pAd->stats.rx_bytes = pAd->RalinkCounters.ReceivedByteCount; ++ pAd->stats.tx_bytes = pAd->RalinkCounters.TransmittedByteCount; ++ ++ pAd->stats.rx_errors = pAd->Counters8023.RxErrors; ++ pAd->stats.tx_errors = pAd->Counters8023.TxErrors; ++ ++ pAd->stats.rx_dropped = 0; ++ pAd->stats.tx_dropped = 0; ++ ++ pAd->stats.multicast = pAd->WlanCounters.MulticastReceivedFrameCount.QuadPart; // multicast packets received ++ pAd->stats.collisions = pAd->Counters8023.OneCollision + pAd->Counters8023.MoreCollisions; // Collision packets ++ ++ pAd->stats.rx_length_errors = 0; ++ pAd->stats.rx_over_errors = pAd->Counters8023.RxNoBuffer; // receiver ring buff overflow ++ pAd->stats.rx_crc_errors = 0;//pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error ++ pAd->stats.rx_frame_errors = pAd->Counters8023.RcvAlignmentErrors; // recv'd frame alignment error ++ pAd->stats.rx_fifo_errors = pAd->Counters8023.RxNoBuffer; // recv'r fifo overrun ++ pAd->stats.rx_missed_errors = 0; // receiver missed packet ++ ++ // detailed tx_errors ++ pAd->stats.tx_aborted_errors = 0; ++ pAd->stats.tx_carrier_errors = 0; ++ pAd->stats.tx_fifo_errors = 0; ++ pAd->stats.tx_heartbeat_errors = 0; ++ pAd->stats.tx_window_errors = 0; ++ ++ // for cslip etc ++ pAd->stats.rx_compressed = 0; ++ pAd->stats.tx_compressed = 0; ++ ++ return &pAd->stats; ++ } ++ else ++ return NULL; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rtmp_ckipmic.h +@@ -0,0 +1,113 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_ckipmic.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef __RTMP_CKIPMIC_H__ ++#define __RTMP_CKIPMIC_H__ ++ ++typedef struct _MIC_CONTEXT { ++ /* --- MMH context */ ++ UCHAR CK[16]; /* the key */ ++ UCHAR coefficient[16]; /* current aes counter mode coefficients */ ++ ULONGLONG accum; /* accumulated mic, reduced to u32 in final() */ ++ UINT position; /* current position (byte offset) in message */ ++ UCHAR part[4]; /* for conversion of message to u32 for mmh */ ++} MIC_CONTEXT, *PMIC_CONTEXT; ++ ++VOID CKIP_key_permute( ++ OUT UCHAR *PK, /* output permuted key */ ++ IN UCHAR *CK, /* input CKIP key */ ++ IN UCHAR toDsFromDs, /* input toDs/FromDs bits */ ++ IN UCHAR *piv); /* input pointer to IV */ ++ ++VOID RTMPCkipMicInit( ++ IN PMIC_CONTEXT pContext, ++ IN PUCHAR CK); ++ ++VOID RTMPMicUpdate( ++ IN PMIC_CONTEXT pContext, ++ IN PUCHAR pOctets, ++ IN INT len); ++ ++ULONG RTMPMicGetCoefficient( ++ IN PMIC_CONTEXT pContext); ++ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a); ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round); ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID RTMPAesEncrypt( ++ IN PUCHAR key, ++ IN PUCHAR data, ++ IN PUCHAR ciphertext); ++ ++VOID RTMPMicFinal( ++ IN PMIC_CONTEXT pContext, ++ OUT UCHAR digest[4]); ++ ++VOID RTMPCkipInsertCMIC( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pMIC, ++ IN PUCHAR p80211hdr, ++ IN PNDIS_PACKET pPacket, ++ IN PCIPHER_KEY pKey, ++ IN PUCHAR mic_snap); ++ ++#endif //__RTMP_CKIPMIC_H__ +--- /dev/null ++++ b/drivers/staging/rt2870/rtmp_def.h +@@ -0,0 +1,1622 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_def.h ++ ++ Abstract: ++ Miniport related definition header ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ John Chang 08-05-2003 add definition for 11g & other drafts ++*/ ++#ifndef __RTMP_DEF_H__ ++#define __RTMP_DEF_H__ ++ ++#include "oid.h" ++ ++// ++// Debug information verbosity: lower values indicate higher urgency ++// ++#define RT_DEBUG_OFF 0 ++#define RT_DEBUG_ERROR 1 ++#define RT_DEBUG_WARN 2 ++#define RT_DEBUG_TRACE 3 ++#define RT_DEBUG_INFO 4 ++#define RT_DEBUG_LOUD 5 ++ ++#define NIC_TAG ((ULONG)'0682') ++#define NIC_DBG_STRING ("**RT28xx**") ++ ++#ifdef SNMP_SUPPORT ++// for snmp ++// to get manufacturer OUI, kathy, 2008_0220 ++#define ManufacturerOUI_LEN 3 ++#define ManufacturerNAME ("Ralink Technology Company.") ++#define ResourceTypeIdName ("Ralink_ID") ++#endif ++ ++ ++//#define PACKED ++ ++#define RALINK_2883_VERSION ((UINT32)0x28830300) ++#define RALINK_2880E_VERSION ((UINT32)0x28720200) ++#define RALINK_3070_VERSION ((UINT32)0x30700200) ++ ++// ++// NDIS version in use by the NIC driver. ++// The high byte is the major version. The low byte is the minor version. ++// ++#ifdef NDIS51_MINIPORT ++#define NIC_DRIVER_VERSION 0x0501 ++#else ++#define NIC_DRIVER_VERSION 0x0500 ++#endif ++ ++// ++// NDIS media type, current is ethernet, change if native wireless supported ++// ++#define NIC_MEDIA_TYPE NdisMedium802_3 ++#define NIC_PCI_HDR_LENGTH 0xe2 ++#define NIC_MAX_PACKET_SIZE 2304 ++#define NIC_HEADER_SIZE 14 ++#define MAX_MAP_REGISTERS_NEEDED 32 ++#define MIN_MAP_REGISTERS_NEEDED 2 //Todo: should consider fragment issue. ++ ++// ++// interface type, we use PCI ++// ++#define NIC_INTERFACE_TYPE NdisInterfacePci ++#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive ++ ++// ++// buffer size passed in NdisMQueryAdapterResources ++// We should only need three adapter resources (IO, interrupt and memory), ++// Some devices get extra resources, so have room for 10 resources ++// UF_SIZE (sizeof(NDIS_RESOURCE_LIST) + (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))) ++ ++ ++#define NIC_RESOURCE_B// ++// IO space length ++// ++#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC) ++ ++#define MAX_RX_PKT_LEN 1520 ++ ++// ++// Entry number for each DMA descriptor ring ++// ++ ++ ++#ifdef RT2870 ++#define TX_RING_SIZE 8 // 1 ++#define PRIO_RING_SIZE 8 ++#define MGMT_RING_SIZE 32 // PRIO_RING_SIZE ++#define RX_RING_SIZE 8 ++#define MAX_TX_PROCESS 4 ++#define LOCAL_TXBUF_SIZE 2048 ++#endif // RT2870 // ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// MC: Multple Cards ++#define MAX_NUM_OF_MULTIPLE_CARD 32 ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#define MAX_RX_PROCESS 128 //64 //32 ++#define NUM_OF_LOCAL_TXBUF 2 ++#define TXD_SIZE 16 ++#define TXWI_SIZE 16 ++#define RXD_SIZE 16 ++#define RXWI_SIZE 16 ++// TXINFO_SIZE + TXWI_SIZE + 802.11 Header Size + AMSDU sub frame header ++#define TX_DMA_1ST_BUFFER_SIZE 96 // only the 1st physical buffer is pre-allocated ++#define MGMT_DMA_BUFFER_SIZE 1536 //2048 ++#define RX_BUFFER_AGGRESIZE 3840 //3904 //3968 //4096 //2048 //4096 ++#define RX_BUFFER_NORMSIZE 3840 //3904 //3968 //4096 //2048 //4096 ++#define TX_BUFFER_NORMSIZE RX_BUFFER_NORMSIZE ++#define MAX_FRAME_SIZE 2346 // Maximum 802.11 frame size ++#define MAX_AGGREGATION_SIZE 3840 //3904 //3968 //4096 ++#define MAX_NUM_OF_TUPLE_CACHE 2 ++#define MAX_MCAST_LIST_SIZE 32 ++#define MAX_LEN_OF_VENDOR_DESC 64 ++//#define MAX_SIZE_OF_MCAST_PSQ (NUM_OF_LOCAL_TXBUF >> 2) // AP won't spend more than 1/4 of total buffers on M/BCAST PSQ ++#define MAX_SIZE_OF_MCAST_PSQ 32 ++ ++#define MAX_RX_PROCESS_CNT (RX_RING_SIZE) ++ ++ ++#define MAX_PACKETS_IN_QUEUE (512) //(512) // to pass WMM A5-WPAPSK ++#define MAX_PACKETS_IN_MCAST_PS_QUEUE 32 ++#define MAX_PACKETS_IN_PS_QUEUE 128 //32 ++#define WMM_NUM_OF_AC 4 /* AC0, AC1, AC2, and AC3 */ ++ ++ ++ ++// RxFilter ++#define STANORMAL 0x17f97 ++#define APNORMAL 0x15f97 ++// ++// RTMP_ADAPTER flags ++// ++#define fRTMP_ADAPTER_MAP_REGISTER 0x00000001 ++#define fRTMP_ADAPTER_INTERRUPT_IN_USE 0x00000002 ++#define fRTMP_ADAPTER_HARDWARE_ERROR 0x00000004 ++#define fRTMP_ADAPTER_SCATTER_GATHER 0x00000008 ++#define fRTMP_ADAPTER_SEND_PACKET_ERROR 0x00000010 ++#define fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS 0x00000020 ++#define fRTMP_ADAPTER_HALT_IN_PROGRESS 0x00000040 ++#define fRTMP_ADAPTER_RESET_IN_PROGRESS 0x00000080 ++#define fRTMP_ADAPTER_NIC_NOT_EXIST 0x00000100 ++#define fRTMP_ADAPTER_TX_RING_ALLOCATED 0x00000200 ++#define fRTMP_ADAPTER_REMOVE_IN_PROGRESS 0x00000400 ++#define fRTMP_ADAPTER_MIMORATE_INUSED 0x00000800 ++#define fRTMP_ADAPTER_RX_RING_ALLOCATED 0x00001000 ++#define fRTMP_ADAPTER_INTERRUPT_ACTIVE 0x00002000 ++#define fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS 0x00004000 ++#define fRTMP_ADAPTER_REASSOC_IN_PROGRESS 0x00008000 ++#define fRTMP_ADAPTER_MEDIA_STATE_PENDING 0x00010000 ++#define fRTMP_ADAPTER_RADIO_OFF 0x00020000 ++#define fRTMP_ADAPTER_BULKOUT_RESET 0x00040000 ++#define fRTMP_ADAPTER_BULKIN_RESET 0x00080000 ++#define fRTMP_ADAPTER_RDG_ACTIVE 0x00100000 ++#define fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE 0x00200000 ++#define fRTMP_ADAPTER_SCAN_2040 0x04000000 ++#define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000 ++ ++#define fRTMP_ADAPTER_START_UP 0x10000000 //Devive already initialized and enabled Tx/Rx. ++#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000 ++#define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000 ++ ++// Lock bit for accessing different ring buffers ++//#define fRTMP_ADAPTER_TX_RING_BUSY 0x80000000 ++//#define fRTMP_ADAPTER_MGMT_RING_BUSY 0x40000000 ++//#define fRTMP_ADAPTER_ATIM_RING_BUSY 0x20000000 ++//#define fRTMP_ADAPTER_RX_RING_BUSY 0x10000000 ++ ++// Lock bit for accessing different queue ++//#define fRTMP_ADAPTER_TX_QUEUE_BUSY 0x08000000 ++//#define fRTMP_ADAPTER_MGMT_QUEUE_BUSY 0x04000000 ++ ++// ++// STA operation status flags ++// ++#define fOP_STATUS_INFRA_ON 0x00000001 ++#define fOP_STATUS_ADHOC_ON 0x00000002 ++#define fOP_STATUS_BG_PROTECTION_INUSED 0x00000004 ++#define fOP_STATUS_SHORT_SLOT_INUSED 0x00000008 ++#define fOP_STATUS_SHORT_PREAMBLE_INUSED 0x00000010 ++#define fOP_STATUS_RECEIVE_DTIM 0x00000020 ++//#define fOP_STATUS_TX_RATE_SWITCH_ENABLED 0x00000040 ++#define fOP_STATUS_MEDIA_STATE_CONNECTED 0x00000080 ++#define fOP_STATUS_WMM_INUSED 0x00000100 ++#define fOP_STATUS_AGGREGATION_INUSED 0x00000200 ++#define fOP_STATUS_DOZE 0x00000400 // debug purpose ++#define fOP_STATUS_PIGGYBACK_INUSED 0x00000800 // piggy-back, and aggregation ++#define fOP_STATUS_APSD_INUSED 0x00001000 ++#define fOP_STATUS_TX_AMSDU_INUSED 0x00002000 ++#define fOP_STATUS_MAX_RETRY_ENABLED 0x00004000 ++#define fOP_STATUS_WAKEUP_NOW 0x00008000 ++#define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 ++ ++#ifdef DOT11N_DRAFT3 ++#define fOP_STATUS_SCAN_2040 0x00040000 ++#endif // DOT11N_DRAFT3 // ++ ++#define CCKSETPROTECT 0x1 ++#define OFDMSETPROTECT 0x2 ++#define MM20SETPROTECT 0x4 ++#define MM40SETPROTECT 0x8 ++#define GF20SETPROTECT 0x10 ++#define GR40SETPROTECT 0x20 ++#define ALLN_SETPROTECT (GR40SETPROTECT | GF20SETPROTECT | MM40SETPROTECT | MM20SETPROTECT) ++ ++// ++// AP's client table operation status flags ++// ++#define fCLIENT_STATUS_WMM_CAPABLE 0x00000001 // CLIENT can parse QOS DATA frame ++#define fCLIENT_STATUS_AGGREGATION_CAPABLE 0x00000002 // CLIENT can receive Ralink's proprietary TX aggregation frame ++#define fCLIENT_STATUS_PIGGYBACK_CAPABLE 0x00000004 // CLIENT support piggy-back ++#define fCLIENT_STATUS_AMSDU_INUSED 0x00000008 ++#define fCLIENT_STATUS_SGI20_CAPABLE 0x00000010 ++#define fCLIENT_STATUS_SGI40_CAPABLE 0x00000020 ++#define fCLIENT_STATUS_TxSTBC_CAPABLE 0x00000040 ++#define fCLIENT_STATUS_RxSTBC_CAPABLE 0x00000080 ++#define fCLIENT_STATUS_HTC_CAPABLE 0x00000100 ++#define fCLIENT_STATUS_RDG_CAPABLE 0x00000200 ++#define fCLIENT_STATUS_MCSFEEDBACK_CAPABLE 0x00000400 ++#define fCLIENT_STATUS_APSD_CAPABLE 0x00000800 /* UAPSD STATION */ ++ ++#ifdef DOT11N_DRAFT3 ++#define fCLIENT_STATUS_BSSCOEXIST_CAPABLE 0x00001000 ++#endif // DOT11N_DRAFT3 // ++ ++#define fCLIENT_STATUS_RALINK_CHIPSET 0x00100000 ++// ++// STA configuration flags ++// ++//#define fSTA_CFG_ENABLE_TX_BURST 0x00000001 ++ ++// 802.11n Operating Mode Definition. 0-3 also used in ASICUPdateProtect switch case ++#define HT_NO_PROTECT 0 ++#define HT_LEGACY_PROTECT 1 ++#define HT_40_PROTECT 2 ++#define HT_2040_PROTECT 3 ++#define HT_RTSCTS_6M 7 ++//following is our own definition in order to turn on our ASIC protection register in INFRASTRUCTURE. ++#define HT_ATHEROS 8 // rt2860c has problem with atheros chip. we need to turn on RTS/CTS . ++#define HT_FORCERTSCTS 9 // Force turn on RTS/CTS first. then go to evaluate if this force RTS is necessary. ++ ++// ++// RX Packet Filter control flags. Apply on pAd->PacketFilter ++// ++#define fRX_FILTER_ACCEPT_DIRECT NDIS_PACKET_TYPE_DIRECTED ++#define fRX_FILTER_ACCEPT_MULTICAST NDIS_PACKET_TYPE_MULTICAST ++#define fRX_FILTER_ACCEPT_BROADCAST NDIS_PACKET_TYPE_BROADCAST ++#define fRX_FILTER_ACCEPT_ALL_MULTICAST NDIS_PACKET_TYPE_ALL_MULTICAST ++ ++// ++// Error code section ++// ++// NDIS_ERROR_CODE_ADAPTER_NOT_FOUND ++#define ERRLOG_READ_PCI_SLOT_FAILED 0x00000101L ++#define ERRLOG_WRITE_PCI_SLOT_FAILED 0x00000102L ++#define ERRLOG_VENDOR_DEVICE_NOMATCH 0x00000103L ++ ++// NDIS_ERROR_CODE_ADAPTER_DISABLED ++#define ERRLOG_BUS_MASTER_DISABLED 0x00000201L ++ ++// NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION ++#define ERRLOG_INVALID_SPEED_DUPLEX 0x00000301L ++#define ERRLOG_SET_SECONDARY_FAILED 0x00000302L ++ ++// NDIS_ERROR_CODE_OUT_OF_RESOURCES ++#define ERRLOG_OUT_OF_MEMORY 0x00000401L ++#define ERRLOG_OUT_OF_SHARED_MEMORY 0x00000402L ++#define ERRLOG_OUT_OF_MAP_REGISTERS 0x00000403L ++#define ERRLOG_OUT_OF_BUFFER_POOL 0x00000404L ++#define ERRLOG_OUT_OF_NDIS_BUFFER 0x00000405L ++#define ERRLOG_OUT_OF_PACKET_POOL 0x00000406L ++#define ERRLOG_OUT_OF_NDIS_PACKET 0x00000407L ++#define ERRLOG_OUT_OF_LOOKASIDE_MEMORY 0x00000408L ++ ++// NDIS_ERROR_CODE_HARDWARE_FAILURE ++#define ERRLOG_SELFTEST_FAILED 0x00000501L ++#define ERRLOG_INITIALIZE_ADAPTER 0x00000502L ++#define ERRLOG_REMOVE_MINIPORT 0x00000503L ++ ++// NDIS_ERROR_CODE_RESOURCE_CONFLICT ++#define ERRLOG_MAP_IO_SPACE 0x00000601L ++#define ERRLOG_QUERY_ADAPTER_RESOURCES 0x00000602L ++#define ERRLOG_NO_IO_RESOURCE 0x00000603L ++#define ERRLOG_NO_INTERRUPT_RESOURCE 0x00000604L ++#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L ++ ++ ++// WDS definition ++#define MAX_WDS_ENTRY 4 ++#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table ++ ++#define WDS_DISABLE_MODE 0 ++#define WDS_RESTRICT_MODE 1 ++#define WDS_BRIDGE_MODE 2 ++#define WDS_REPEATER_MODE 3 ++#define WDS_LAZY_MODE 4 ++ ++ ++#define MAX_MESH_NUM 0 ++ ++#define MAX_APCLI_NUM 0 ++#ifdef APCLI_SUPPORT ++#undef MAX_APCLI_NUM ++#define MAX_APCLI_NUM 1 ++#endif // APCLI_SUPPORT // ++ ++#define MAX_MBSSID_NUM 1 ++ ++/* sanity check for apidx */ ++#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ ++ { if (apidx > MAX_MBSSID_NUM) { \ ++ printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \ ++ apidx = MAIN_MBSSID; } } ++ ++#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE ) ++ ++#define MAIN_MBSSID 0 ++#define FIRST_MBSSID 1 ++ ++ ++#define MAX_BEACON_SIZE 512 ++// If the MAX_MBSSID_NUM is larger than 6, ++// it shall reserve some WCID space(wcid 222~253) for beacon frames. ++// - these wcid 238~253 are reserved for beacon#6(ra6). ++// - these wcid 222~237 are reserved for beacon#7(ra7). ++#if defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 8) ++#define HW_RESERVED_WCID 222 ++#elif defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 7) ++#define HW_RESERVED_WCID 238 ++#else ++#define HW_RESERVED_WCID 255 ++#endif ++ ++// Then dedicate wcid of DFS and Carrier-Sense. ++#define DFS_CTS_WCID (HW_RESERVED_WCID - 1) ++#define CS_CTS_WCID (HW_RESERVED_WCID - 2) ++#define LAST_SPECIFIC_WCID (HW_RESERVED_WCID - 2) ++ ++// If MAX_MBSSID_NUM is 8, the maximum available wcid for the associated STA is 211. ++// If MAX_MBSSID_NUM is 7, the maximum available wcid for the associated STA is 228. ++#define MAX_AVAILABLE_CLIENT_WCID (LAST_SPECIFIC_WCID - MAX_MBSSID_NUM - 1) ++ ++// TX need WCID to find Cipher Key ++// these wcid 212 ~ 219 are reserved for bc/mc packets if MAX_MBSSID_NUM is 8. ++#define GET_GroupKey_WCID(__wcid, __bssidx) \ ++ { \ ++ __wcid = LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM) + __bssidx; \ ++ } ++ ++#define IsGroupKeyWCID(__wcid) (((__wcid) < LAST_SPECIFIC_WCID) && ((__wcid) >= (LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM)))) ++ ++ ++// definition to support multiple BSSID ++#define BSS0 0 ++#define BSS1 1 ++#define BSS2 2 ++#define BSS3 3 ++#define BSS4 4 ++#define BSS5 5 ++#define BSS6 6 ++#define BSS7 7 ++ ++ ++//============================================================ ++// Length definitions ++#define PEER_KEY_NO 2 ++#define MAC_ADDR_LEN 6 ++#define TIMESTAMP_LEN 8 ++#define MAX_LEN_OF_SUPPORTED_RATES MAX_LENGTH_OF_SUPPORT_RATES // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define MAX_LEN_OF_KEY 32 // 32 octets == 256 bits, Redefine for WPA ++#define MAX_NUM_OF_CHANNELS MAX_NUM_OF_CHS // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination ++#define MAX_NUM_OF_11JCHANNELS 20 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination ++#define MAX_LEN_OF_SSID 32 ++#define CIPHER_TEXT_LEN 128 ++#define HASH_TABLE_SIZE 256 ++#define MAX_VIE_LEN 1024 // New for WPA cipher suite variable IE sizes. ++#define MAX_SUPPORT_MCS 32 ++ ++//============================================================ ++// ASIC WCID Table definition. ++//============================================================ ++#define BSSID_WCID 1 // in infra mode, always put bssid with this WCID ++#define MCAST_WCID 0x0 ++#define BSS0Mcast_WCID 0x0 ++#define BSS1Mcast_WCID 0xf8 ++#define BSS2Mcast_WCID 0xf9 ++#define BSS3Mcast_WCID 0xfa ++#define BSS4Mcast_WCID 0xfb ++#define BSS5Mcast_WCID 0xfc ++#define BSS6Mcast_WCID 0xfd ++#define BSS7Mcast_WCID 0xfe ++#define RESERVED_WCID 0xff ++ ++#define MAX_NUM_OF_ACL_LIST MAX_NUMBER_OF_ACL ++ ++#define MAX_LEN_OF_MAC_TABLE MAX_NUMBER_OF_MAC // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 ++ ++#if MAX_LEN_OF_MAC_TABLE>MAX_AVAILABLE_CLIENT_WCID ++#error MAX_LEN_OF_MAC_TABLE can not be larger than MAX_AVAILABLE_CLIENT_WCID!!!! ++#endif ++ ++#define MAX_NUM_OF_WDS_LINK_PERBSSID 3 ++#define MAX_NUM_OF_WDS_LINK (MAX_NUM_OF_WDS_LINK_PERBSSID*MAX_MBSSID_NUM) ++#define MAX_NUM_OF_EVENT MAX_NUMBER_OF_EVENT ++#define WDS_LINK_START_WCID (MAX_LEN_OF_MAC_TABLE-1) ++ ++#define NUM_OF_TID 8 ++#define MAX_AID_BA 4 ++#define MAX_LEN_OF_BA_REC_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) //Block ACK recipient ++#define MAX_LEN_OF_BA_ORI_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) // Block ACK originator ++#define MAX_LEN_OF_BSS_TABLE 64 ++#define MAX_REORDERING_MPDU_NUM 512 ++ ++// key related definitions ++#define SHARE_KEY_NUM 4 ++#define MAX_LEN_OF_SHARE_KEY 16 // byte count ++#define MAX_LEN_OF_PEER_KEY 16 // byte count ++#define PAIRWISE_KEY_NUM 64 // in MAC ASIC pairwise key table ++#define GROUP_KEY_NUM 4 ++#define PMK_LEN 32 ++#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table ++#define PMKID_NO 4 // Number of PMKID saved supported ++#define MAX_LEN_OF_MLME_BUFFER 2048 ++ ++// power status related definitions ++#define PWR_ACTIVE 0 ++#define PWR_SAVE 1 ++#define PWR_MMPS 2 //MIMO power save ++//#define PWR_UNKNOWN 2 ++ ++// Auth and Assoc mode related definitions ++#define AUTH_MODE_OPEN 0x00 ++#define AUTH_MODE_KEY 0x01 ++//#define AUTH_MODE_AUTO_SWITCH 0x03 ++//#define AUTH_MODE_DEAUTH 0x04 ++//#define AUTH_MODE_UPLAYER 0x05 // reserved for 802.11i use ++ ++// BSS Type definitions ++#define BSS_ADHOC 0 // = Ndis802_11IBSS ++#define BSS_INFRA 1 // = Ndis802_11Infrastructure ++#define BSS_ANY 2 // = Ndis802_11AutoUnknown ++#define BSS_MONITOR 3 // = Ndis802_11Monitor ++ ++ ++// Reason code definitions ++#define REASON_RESERVED 0 ++#define REASON_UNSPECIFY 1 ++#define REASON_NO_LONGER_VALID 2 ++#define REASON_DEAUTH_STA_LEAVING 3 ++#define REASON_DISASSOC_INACTIVE 4 ++#define REASON_DISASSPC_AP_UNABLE 5 ++#define REASON_CLS2ERR 6 ++#define REASON_CLS3ERR 7 ++#define REASON_DISASSOC_STA_LEAVING 8 ++#define REASON_STA_REQ_ASSOC_NOT_AUTH 9 ++#define REASON_INVALID_IE 13 ++#define REASON_MIC_FAILURE 14 ++#define REASON_4_WAY_TIMEOUT 15 ++#define REASON_GROUP_KEY_HS_TIMEOUT 16 ++#define REASON_IE_DIFFERENT 17 ++#define REASON_MCIPHER_NOT_VALID 18 ++#define REASON_UCIPHER_NOT_VALID 19 ++#define REASON_AKMP_NOT_VALID 20 ++#define REASON_UNSUPPORT_RSNE_VER 21 ++#define REASON_INVALID_RSNE_CAP 22 ++#define REASON_8021X_AUTH_FAIL 23 ++#define REASON_CIPHER_SUITE_REJECTED 24 ++#define REASON_DECLINED 37 ++ ++#define REASON_QOS_UNSPECIFY 32 ++#define REASON_QOS_LACK_BANDWIDTH 33 ++#define REASON_POOR_CHANNEL_CONDITION 34 ++#define REASON_QOS_OUTSIDE_TXOP_LIMITION 35 ++#define REASON_QOS_QSTA_LEAVING_QBSS 36 ++#define REASON_QOS_UNWANTED_MECHANISM 37 ++#define REASON_QOS_MECH_SETUP_REQUIRED 38 ++#define REASON_QOS_REQUEST_TIMEOUT 39 ++#define REASON_QOS_CIPHER_NOT_SUPPORT 45 ++ ++// Status code definitions ++#define MLME_SUCCESS 0 ++#define MLME_UNSPECIFY_FAIL 1 ++#define MLME_CANNOT_SUPPORT_CAP 10 ++#define MLME_REASSOC_DENY_ASSOC_EXIST 11 ++#define MLME_ASSOC_DENY_OUT_SCOPE 12 ++#define MLME_ALG_NOT_SUPPORT 13 ++#define MLME_SEQ_NR_OUT_OF_SEQUENCE 14 ++#define MLME_REJ_CHALLENGE_FAILURE 15 ++#define MLME_REJ_TIMEOUT 16 ++#define MLME_ASSOC_REJ_UNABLE_HANDLE_STA 17 ++#define MLME_ASSOC_REJ_DATA_RATE 18 ++ ++#define MLME_ASSOC_REJ_NO_EXT_RATE 22 ++#define MLME_ASSOC_REJ_NO_EXT_RATE_PBCC 23 ++#define MLME_ASSOC_REJ_NO_CCK_OFDM 24 ++ ++#define MLME_QOS_UNSPECIFY 32 ++#define MLME_REQUEST_DECLINED 37 ++#define MLME_REQUEST_WITH_INVALID_PARAM 38 ++#define MLME_DLS_NOT_ALLOW_IN_QBSS 48 ++#define MLME_DEST_STA_NOT_IN_QBSS 49 ++#define MLME_DEST_STA_IS_NOT_A_QSTA 50 ++ ++#define MLME_INVALID_FORMAT 0x51 ++#define MLME_FAIL_NO_RESOURCE 0x52 ++#define MLME_STATE_MACHINE_REJECT 0x53 ++#define MLME_MAC_TABLE_FAIL 0x54 ++ ++// IE code ++#define IE_SSID 0 ++#define IE_SUPP_RATES 1 ++#define IE_FH_PARM 2 ++#define IE_DS_PARM 3 ++#define IE_CF_PARM 4 ++#define IE_TIM 5 ++#define IE_IBSS_PARM 6 ++#define IE_COUNTRY 7 // 802.11d ++#define IE_802_11D_REQUEST 10 // 802.11d ++#define IE_QBSS_LOAD 11 // 802.11e d9 ++#define IE_EDCA_PARAMETER 12 // 802.11e d9 ++#define IE_TSPEC 13 // 802.11e d9 ++#define IE_TCLAS 14 // 802.11e d9 ++#define IE_SCHEDULE 15 // 802.11e d9 ++#define IE_CHALLENGE_TEXT 16 ++#define IE_POWER_CONSTRAINT 32 // 802.11h d3.3 ++#define IE_POWER_CAPABILITY 33 // 802.11h d3.3 ++#define IE_TPC_REQUEST 34 // 802.11h d3.3 ++#define IE_TPC_REPORT 35 // 802.11h d3.3 ++#define IE_SUPP_CHANNELS 36 // 802.11h d3.3 ++#define IE_CHANNEL_SWITCH_ANNOUNCEMENT 37 // 802.11h d3.3 ++#define IE_MEASUREMENT_REQUEST 38 // 802.11h d3.3 ++#define IE_MEASUREMENT_REPORT 39 // 802.11h d3.3 ++#define IE_QUIET 40 // 802.11h d3.3 ++#define IE_IBSS_DFS 41 // 802.11h d3.3 ++#define IE_ERP 42 // 802.11g ++#define IE_TS_DELAY 43 // 802.11e d9 ++#define IE_TCLAS_PROCESSING 44 // 802.11e d9 ++#define IE_QOS_CAPABILITY 46 // 802.11e d6 ++#define IE_HT_CAP 45 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD ++#define IE_AP_CHANNEL_REPORT 51 // 802.11k d6 ++#define IE_HT_CAP2 52 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD ++#define IE_RSN 48 // 802.11i d3.0 ++#define IE_WPA2 48 // WPA2 ++#define IE_EXT_SUPP_RATES 50 // 802.11g ++#define IE_SUPP_REG_CLASS 59 // 802.11y. Supported regulatory classes. ++#define IE_EXT_CHANNEL_SWITCH_ANNOUNCEMENT 60 // 802.11n ++#define IE_ADD_HT 61 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD ++#define IE_ADD_HT2 53 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD ++ ++ ++// For 802.11n D3.03 ++//#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet ++#define IE_SECONDARY_CH_OFFSET 62 // 802.11n D3.03 Secondary Channel Offset element ++#define IE_WAPI 68 // WAPI information element ++#define IE_2040_BSS_COEXIST 72 // 802.11n D3.0.3 ++#define IE_2040_BSS_INTOLERANT_REPORT 73 // 802.11n D3.03 ++#define IE_OVERLAPBSS_SCAN_PARM 74 // 802.11n D3.03 ++#define IE_EXT_CAPABILITY 127 // 802.11n D3.03 ++ ++ ++#define IE_WPA 221 // WPA ++#define IE_VENDOR_SPECIFIC 221 // Wifi WMM (WME) ++ ++#define OUI_BROADCOM_HT 51 // ++#define OUI_BROADCOM_HTADD 52 // ++#define OUI_PREN_HT_CAP 51 // ++#define OUI_PREN_ADD_HT 52 // ++ ++// CCX information ++#define IE_AIRONET_CKIP 133 // CCX1.0 ID 85H for CKIP ++#define IE_AP_TX_POWER 150 // CCX 2.0 for AP transmit power ++#define IE_MEASUREMENT_CAPABILITY 221 // CCX 2.0 ++#define IE_CCX_V2 221 ++#define IE_AIRONET_IPADDRESS 149 // CCX ID 95H for IP Address ++#define IE_AIRONET_CCKMREASSOC 156 // CCX ID 9CH for CCKM Reassociation Request element ++#define CKIP_NEGOTIATION_LENGTH 30 ++#define AIRONET_IPADDRESS_LENGTH 10 ++#define AIRONET_CCKMREASSOC_LENGTH 24 ++ ++// ======================================================== ++// MLME state machine definition ++// ======================================================== ++ ++// STA MLME state mahcines ++#define ASSOC_STATE_MACHINE 1 ++#define AUTH_STATE_MACHINE 2 ++#define AUTH_RSP_STATE_MACHINE 3 ++#define SYNC_STATE_MACHINE 4 ++#define MLME_CNTL_STATE_MACHINE 5 ++#define WPA_PSK_STATE_MACHINE 6 ++#define LEAP_STATE_MACHINE 7 ++#define AIRONET_STATE_MACHINE 8 ++#define ACTION_STATE_MACHINE 9 ++ ++// AP MLME state machines ++#define AP_ASSOC_STATE_MACHINE 11 ++#define AP_AUTH_STATE_MACHINE 12 ++#define AP_AUTH_RSP_STATE_MACHINE 13 ++#define AP_SYNC_STATE_MACHINE 14 ++#define AP_CNTL_STATE_MACHINE 15 ++#define AP_WPA_STATE_MACHINE 16 ++ ++#ifdef QOS_DLS_SUPPORT ++#define DLS_STATE_MACHINE 26 ++#endif // QOS_DLS_SUPPORT // ++ ++// ++// STA's CONTROL/CONNECT state machine: states, events, total function # ++// ++#define CNTL_IDLE 0 ++#define CNTL_WAIT_DISASSOC 1 ++#define CNTL_WAIT_JOIN 2 ++#define CNTL_WAIT_REASSOC 3 ++#define CNTL_WAIT_START 4 ++#define CNTL_WAIT_AUTH 5 ++#define CNTL_WAIT_ASSOC 6 ++#define CNTL_WAIT_AUTH2 7 ++#define CNTL_WAIT_OID_LIST_SCAN 8 ++#define CNTL_WAIT_OID_DISASSOC 9 ++#ifdef RT2870 ++#define CNTL_WAIT_SCAN_FOR_CONNECT 10 ++#endif // RT2870 // ++ ++#define MT2_ASSOC_CONF 34 ++#define MT2_AUTH_CONF 35 ++#define MT2_DEAUTH_CONF 36 ++#define MT2_DISASSOC_CONF 37 ++#define MT2_REASSOC_CONF 38 ++#define MT2_PWR_MGMT_CONF 39 ++#define MT2_JOIN_CONF 40 ++#define MT2_SCAN_CONF 41 ++#define MT2_START_CONF 42 ++#define MT2_GET_CONF 43 ++#define MT2_SET_CONF 44 ++#define MT2_RESET_CONF 45 ++#define MT2_MLME_ROAMING_REQ 52 ++ ++#define CNTL_FUNC_SIZE 1 ++ ++// ++// STA's ASSOC state machine: states, events, total function # ++// ++#define ASSOC_IDLE 0 ++#define ASSOC_WAIT_RSP 1 ++#define REASSOC_WAIT_RSP 2 ++#define DISASSOC_WAIT_RSP 3 ++#define MAX_ASSOC_STATE 4 ++ ++#define ASSOC_MACHINE_BASE 0 ++#define MT2_MLME_ASSOC_REQ 0 ++#define MT2_MLME_REASSOC_REQ 1 ++#define MT2_MLME_DISASSOC_REQ 2 ++#define MT2_PEER_DISASSOC_REQ 3 ++#define MT2_PEER_ASSOC_REQ 4 ++#define MT2_PEER_ASSOC_RSP 5 ++#define MT2_PEER_REASSOC_REQ 6 ++#define MT2_PEER_REASSOC_RSP 7 ++#define MT2_DISASSOC_TIMEOUT 8 ++#define MT2_ASSOC_TIMEOUT 9 ++#define MT2_REASSOC_TIMEOUT 10 ++#define MAX_ASSOC_MSG 11 ++ ++#define ASSOC_FUNC_SIZE (MAX_ASSOC_STATE * MAX_ASSOC_MSG) ++ ++// ++// ACT state machine: states, events, total function # ++// ++#define ACT_IDLE 0 ++#define MAX_ACT_STATE 1 ++ ++#define ACT_MACHINE_BASE 0 ++ ++//Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. ++//Category ++#define MT2_PEER_SPECTRUM_CATE 0 ++#define MT2_PEER_QOS_CATE 1 ++#define MT2_PEER_DLS_CATE 2 ++#define MT2_PEER_BA_CATE 3 ++#define MT2_PEER_PUBLIC_CATE 4 ++#define MT2_PEER_RM_CATE 5 ++#define MT2_PEER_HT_CATE 7 // 7.4.7 ++#define MAX_PEER_CATE_MSG 7 ++#define MT2_MLME_ADD_BA_CATE 8 ++#define MT2_MLME_ORI_DELBA_CATE 9 ++#define MT2_MLME_REC_DELBA_CATE 10 ++#define MT2_MLME_QOS_CATE 11 ++#define MT2_MLME_DLS_CATE 12 ++#define MT2_ACT_INVALID 13 ++#define MAX_ACT_MSG 14 ++ ++//Category field ++#define CATEGORY_SPECTRUM 0 ++#define CATEGORY_QOS 1 ++#define CATEGORY_DLS 2 ++#define CATEGORY_BA 3 ++#define CATEGORY_PUBLIC 4 ++#define CATEGORY_RM 5 ++#define CATEGORY_HT 7 ++ ++ ++// DLS Action frame definition ++#define ACTION_DLS_REQUEST 0 ++#define ACTION_DLS_RESPONSE 1 ++#define ACTION_DLS_TEARDOWN 2 ++ ++//Spectrum Action field value 802.11h 7.4.1 ++#define SPEC_MRQ 0 // Request ++#define SPEC_MRP 1 //Report ++#define SPEC_TPCRQ 2 ++#define SPEC_TPCRP 3 ++#define SPEC_CHANNEL_SWITCH 4 ++ ++ ++//BA Action field value ++#define ADDBA_REQ 0 ++#define ADDBA_RESP 1 ++#define DELBA 2 ++ ++//Public's Action field value in Public Category. Some in 802.11y and some in 11n ++#define ACTION_BSS_2040_COEXIST 0 // 11n ++#define ACTION_DSE_ENABLEMENT 1 // 11y D9.0 ++#define ACTION_DSE_DEENABLEMENT 2 // 11y D9.0 ++#define ACTION_DSE_REG_LOCATION_ANNOUNCE 3 // 11y D9.0 ++#define ACTION_EXT_CH_SWITCH_ANNOUNCE 4 // 11y D9.0 ++#define ACTION_DSE_MEASUREMENT_REQ 5 // 11y D9.0 ++#define ACTION_DSE_MEASUREMENT_REPORT 6 // 11y D9.0 ++#define ACTION_MEASUREMENT_PILOT_ACTION 7 // 11y D9.0 ++#define ACTION_DSE_POWER_CONSTRAINT 8 // 11y D9.0 ++ ++ ++//HT Action field value ++#define NOTIFY_BW_ACTION 0 ++#define SMPS_ACTION 1 ++#define PSMP_ACTION 2 ++#define SETPCO_ACTION 3 ++#define MIMO_CHA_MEASURE_ACTION 4 ++#define MIMO_N_BEACONFORM 5 ++#define MIMO_BEACONFORM 6 ++#define ANTENNA_SELECT 7 ++#define HT_INFO_EXCHANGE 8 ++ ++#define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG) ++// ++// STA's AUTHENTICATION state machine: states, evvents, total function # ++// ++#define AUTH_REQ_IDLE 0 ++#define AUTH_WAIT_SEQ2 1 ++#define AUTH_WAIT_SEQ4 2 ++#define MAX_AUTH_STATE 3 ++ ++#define AUTH_MACHINE_BASE 0 ++#define MT2_MLME_AUTH_REQ 0 ++#define MT2_PEER_AUTH_EVEN 1 ++#define MT2_AUTH_TIMEOUT 2 ++#define MAX_AUTH_MSG 3 ++ ++#define AUTH_FUNC_SIZE (MAX_AUTH_STATE * MAX_AUTH_MSG) ++ ++// ++// STA's AUTH_RSP state machine: states, events, total function # ++// ++#define AUTH_RSP_IDLE 0 ++#define AUTH_RSP_WAIT_CHAL 1 ++#define MAX_AUTH_RSP_STATE 2 ++ ++#define AUTH_RSP_MACHINE_BASE 0 ++#define MT2_AUTH_CHALLENGE_TIMEOUT 0 ++#define MT2_PEER_AUTH_ODD 1 ++#define MT2_PEER_DEAUTH 2 ++#define MAX_AUTH_RSP_MSG 3 ++ ++#define AUTH_RSP_FUNC_SIZE (MAX_AUTH_RSP_STATE * MAX_AUTH_RSP_MSG) ++ ++// ++// STA's SYNC state machine: states, events, total function # ++// ++#define SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define JOIN_WAIT_BEACON 1 ++#define SCAN_LISTEN 2 ++#define MAX_SYNC_STATE 3 ++ ++#define SYNC_MACHINE_BASE 0 ++#define MT2_MLME_SCAN_REQ 0 ++#define MT2_MLME_JOIN_REQ 1 ++#define MT2_MLME_START_REQ 2 ++#define MT2_PEER_BEACON 3 ++#define MT2_PEER_PROBE_RSP 4 ++#define MT2_PEER_ATIM 5 ++#define MT2_SCAN_TIMEOUT 6 ++#define MT2_BEACON_TIMEOUT 7 ++#define MT2_ATIM_TIMEOUT 8 ++#define MT2_PEER_PROBE_REQ 9 ++#define MAX_SYNC_MSG 10 ++ ++#define SYNC_FUNC_SIZE (MAX_SYNC_STATE * MAX_SYNC_MSG) ++ ++//Messages for the DLS state machine ++#define DLS_IDLE 0 ++#define MAX_DLS_STATE 1 ++ ++#define DLS_MACHINE_BASE 0 ++#define MT2_MLME_DLS_REQ 0 ++#define MT2_PEER_DLS_REQ 1 ++#define MT2_PEER_DLS_RSP 2 ++#define MT2_MLME_DLS_TEAR_DOWN 3 ++#define MT2_PEER_DLS_TEAR_DOWN 4 ++#define MAX_DLS_MSG 5 ++ ++#define DLS_FUNC_SIZE (MAX_DLS_STATE * MAX_DLS_MSG) ++ ++// ++// STA's WPA-PSK State machine: states, events, total function # ++// ++#define WPA_PSK_IDLE 0 ++#define MAX_WPA_PSK_STATE 1 ++ ++#define WPA_MACHINE_BASE 0 ++#define MT2_EAPPacket 0 ++#define MT2_EAPOLStart 1 ++#define MT2_EAPOLLogoff 2 ++#define MT2_EAPOLKey 3 ++#define MT2_EAPOLASFAlert 4 ++#define MAX_WPA_PSK_MSG 5 ++ ++#define WPA_PSK_FUNC_SIZE (MAX_WPA_PSK_STATE * MAX_WPA_PSK_MSG) ++ ++// ++// STA's CISCO-AIRONET State machine: states, events, total function # ++// ++#define AIRONET_IDLE 0 ++#define AIRONET_SCANNING 1 ++#define MAX_AIRONET_STATE 2 ++ ++#define AIRONET_MACHINE_BASE 0 ++#define MT2_AIRONET_MSG 0 ++#define MT2_AIRONET_SCAN_REQ 1 ++#define MT2_AIRONET_SCAN_DONE 2 ++#define MAX_AIRONET_MSG 3 ++ ++#define AIRONET_FUNC_SIZE (MAX_AIRONET_STATE * MAX_AIRONET_MSG) ++ ++// ++// AP's CONTROL/CONNECT state machine: states, events, total function # ++// ++#define AP_CNTL_FUNC_SIZE 1 ++ ++// ++// AP's ASSOC state machine: states, events, total function # ++// ++#define AP_ASSOC_IDLE 0 ++#define AP_MAX_ASSOC_STATE 1 ++ ++#define AP_ASSOC_MACHINE_BASE 0 ++#define APMT2_MLME_DISASSOC_REQ 0 ++#define APMT2_PEER_DISASSOC_REQ 1 ++#define APMT2_PEER_ASSOC_REQ 2 ++#define APMT2_PEER_REASSOC_REQ 3 ++#define APMT2_CLS3ERR 4 ++#define AP_MAX_ASSOC_MSG 5 ++ ++#define AP_ASSOC_FUNC_SIZE (AP_MAX_ASSOC_STATE * AP_MAX_ASSOC_MSG) ++ ++// ++// AP's AUTHENTICATION state machine: states, events, total function # ++// ++#define AP_AUTH_REQ_IDLE 0 ++#define AP_MAX_AUTH_STATE 1 ++ ++#define AP_AUTH_MACHINE_BASE 0 ++#define APMT2_MLME_DEAUTH_REQ 0 ++#define APMT2_CLS2ERR 1 ++#define AP_MAX_AUTH_MSG 2 ++ ++#define AP_AUTH_FUNC_SIZE (AP_MAX_AUTH_STATE * AP_MAX_AUTH_MSG) ++ ++// ++// AP's AUTH-RSP state machine: states, events, total function # ++// ++#define AP_AUTH_RSP_IDLE 0 ++#define AP_MAX_AUTH_RSP_STATE 1 ++ ++#define AP_AUTH_RSP_MACHINE_BASE 0 ++#define APMT2_AUTH_CHALLENGE_TIMEOUT 0 ++#define APMT2_PEER_AUTH_ODD 1 ++#define APMT2_PEER_DEAUTH 2 ++#define AP_MAX_AUTH_RSP_MSG 3 ++ ++#define AP_AUTH_RSP_FUNC_SIZE (AP_MAX_AUTH_RSP_STATE * AP_MAX_AUTH_RSP_MSG) ++ ++// ++// AP's SYNC state machine: states, events, total function # ++// ++#define AP_SYNC_IDLE 0 ++#define AP_SCAN_LISTEN 1 ++#define AP_MAX_SYNC_STATE 2 ++ ++#define AP_SYNC_MACHINE_BASE 0 ++#define APMT2_PEER_PROBE_REQ 0 ++#define APMT2_PEER_BEACON 1 ++#define APMT2_MLME_SCAN_REQ 2 ++#define APMT2_PEER_PROBE_RSP 3 ++#define APMT2_SCAN_TIMEOUT 4 ++#define APMT2_MLME_SCAN_CNCL 5 ++#define AP_MAX_SYNC_MSG 6 ++ ++#define AP_SYNC_FUNC_SIZE (AP_MAX_SYNC_STATE * AP_MAX_SYNC_MSG) ++ ++// ++// AP's WPA state machine: states, events, total function # ++// ++#define AP_WPA_PTK 0 ++#define AP_MAX_WPA_PTK_STATE 1 ++ ++#define AP_WPA_MACHINE_BASE 0 ++#define APMT2_EAPPacket 0 ++#define APMT2_EAPOLStart 1 ++#define APMT2_EAPOLLogoff 2 ++#define APMT2_EAPOLKey 3 ++#define APMT2_EAPOLASFAlert 4 ++#define AP_MAX_WPA_MSG 5 ++ ++#define AP_WPA_FUNC_SIZE (AP_MAX_WPA_PTK_STATE * AP_MAX_WPA_MSG) ++ ++#ifdef APCLI_SUPPORT ++//ApCli authentication state machine ++#define APCLI_AUTH_REQ_IDLE 0 ++#define APCLI_AUTH_WAIT_SEQ2 1 ++#define APCLI_AUTH_WAIT_SEQ4 2 ++#define APCLI_MAX_AUTH_STATE 3 ++ ++#define APCLI_AUTH_MACHINE_BASE 0 ++#define APCLI_MT2_MLME_AUTH_REQ 0 ++#define APCLI_MT2_MLME_DEAUTH_REQ 1 ++#define APCLI_MT2_PEER_AUTH_EVEN 2 ++#define APCLI_MT2_PEER_DEAUTH 3 ++#define APCLI_MT2_AUTH_TIMEOUT 4 ++#define APCLI_MAX_AUTH_MSG 5 ++ ++#define APCLI_AUTH_FUNC_SIZE (APCLI_MAX_AUTH_STATE * APCLI_MAX_AUTH_MSG) ++ ++//ApCli association state machine ++#define APCLI_ASSOC_IDLE 0 ++#define APCLI_ASSOC_WAIT_RSP 1 ++#define APCLI_MAX_ASSOC_STATE 2 ++ ++#define APCLI_ASSOC_MACHINE_BASE 0 ++#define APCLI_MT2_MLME_ASSOC_REQ 0 ++#define APCLI_MT2_MLME_DISASSOC_REQ 1 ++#define APCLI_MT2_PEER_DISASSOC_REQ 2 ++#define APCLI_MT2_PEER_ASSOC_RSP 3 ++#define APCLI_MT2_ASSOC_TIMEOUT 4 ++#define APCLI_MAX_ASSOC_MSG 5 ++ ++#define APCLI_ASSOC_FUNC_SIZE (APCLI_MAX_ASSOC_STATE * APCLI_MAX_ASSOC_MSG) ++ ++//ApCli sync state machine ++#define APCLI_SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define APCLI_JOIN_WAIT_PROBE_RSP 1 ++#define APCLI_MAX_SYNC_STATE 2 ++ ++#define APCLI_SYNC_MACHINE_BASE 0 ++#define APCLI_MT2_MLME_PROBE_REQ 0 ++#define APCLI_MT2_PEER_PROBE_RSP 1 ++#define APCLI_MT2_PROBE_TIMEOUT 2 ++#define APCLI_MAX_SYNC_MSG 3 ++ ++#define APCLI_SYNC_FUNC_SIZE (APCLI_MAX_SYNC_STATE * APCLI_MAX_SYNC_MSG) ++ ++//ApCli ctrl state machine ++#define APCLI_CTRL_DISCONNECTED 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define APCLI_CTRL_PROBE 1 ++#define APCLI_CTRL_AUTH 2 ++#define APCLI_CTRL_AUTH_2 3 ++#define APCLI_CTRL_ASSOC 4 ++#define APCLI_CTRL_DEASSOC 5 ++#define APCLI_CTRL_CONNECTED 6 ++#define APCLI_MAX_CTRL_STATE 7 ++ ++#define APCLI_CTRL_MACHINE_BASE 0 ++#define APCLI_CTRL_JOIN_REQ 0 ++#define APCLI_CTRL_PROBE_RSP 1 ++#define APCLI_CTRL_AUTH_RSP 2 ++#define APCLI_CTRL_DISCONNECT_REQ 3 ++#define APCLI_CTRL_PEER_DISCONNECT_REQ 4 ++#define APCLI_CTRL_ASSOC_RSP 5 ++#define APCLI_CTRL_DEASSOC_RSP 6 ++#define APCLI_CTRL_JOIN_REQ_TIMEOUT 7 ++#define APCLI_CTRL_AUTH_REQ_TIMEOUT 8 ++#define APCLI_CTRL_ASSOC_REQ_TIMEOUT 9 ++#define APCLI_MAX_CTRL_MSG 10 ++ ++#define APCLI_CTRL_FUNC_SIZE (APCLI_MAX_CTRL_STATE * APCLI_MAX_CTRL_MSG) ++ ++#if 0 // remove those variables by AlbertY ++// ApCli WPA state machine ++#define APCLI_WPA_PSK_IDLE 0 ++#define APCLI_MAX_WPA_PSK_STATE 1 ++ ++// ApCli WPA MSG Type ++#define APCLI_WPA_MACHINE_BASE 0 ++#define APCLI_MT2_EAPPacket 0 ++#define APCLI_MT2_EAPOLStart 1 ++#define APCLI_MT2_EAPOLLogoff 2 ++#define APCLI_MT2_EAPOLKey 3 ++#define APCLI_MT2_EAPOLASFAlert 4 ++#define APCLI_MAX_WPA_PSK_MSG 5 ++ ++#define APCLI_WPA_PSK_FUNC_SIZE (APCLI_MAX_WPA_PSK_STATE * APCLI_MAX_WPA_PSK_MSG) ++#endif // end - 0 // ++ ++#endif // APCLI_SUPPORT // ++ ++ ++// ============================================================================= ++ ++// value domain of 802.11 header FC.Tyte, which is b3..b2 of the 1st-byte of MAC header ++#define BTYPE_MGMT 0 ++#define BTYPE_CNTL 1 ++#define BTYPE_DATA 2 ++ ++// value domain of 802.11 MGMT frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_ASSOC_REQ 0 ++#define SUBTYPE_ASSOC_RSP 1 ++#define SUBTYPE_REASSOC_REQ 2 ++#define SUBTYPE_REASSOC_RSP 3 ++#define SUBTYPE_PROBE_REQ 4 ++#define SUBTYPE_PROBE_RSP 5 ++#define SUBTYPE_BEACON 8 ++#define SUBTYPE_ATIM 9 ++#define SUBTYPE_DISASSOC 10 ++#define SUBTYPE_AUTH 11 ++#define SUBTYPE_DEAUTH 12 ++#define SUBTYPE_ACTION 13 ++#define SUBTYPE_ACTION_NO_ACK 14 ++ ++// value domain of 802.11 CNTL frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_WRAPPER 7 ++#define SUBTYPE_BLOCK_ACK_REQ 8 ++#define SUBTYPE_BLOCK_ACK 9 ++#define SUBTYPE_PS_POLL 10 ++#define SUBTYPE_RTS 11 ++#define SUBTYPE_CTS 12 ++#define SUBTYPE_ACK 13 ++#define SUBTYPE_CFEND 14 ++#define SUBTYPE_CFEND_CFACK 15 ++ ++// value domain of 802.11 DATA frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_DATA 0 ++#define SUBTYPE_DATA_CFACK 1 ++#define SUBTYPE_DATA_CFPOLL 2 ++#define SUBTYPE_DATA_CFACK_CFPOLL 3 ++#define SUBTYPE_NULL_FUNC 4 ++#define SUBTYPE_CFACK 5 ++#define SUBTYPE_CFPOLL 6 ++#define SUBTYPE_CFACK_CFPOLL 7 ++#define SUBTYPE_QDATA 8 ++#define SUBTYPE_QDATA_CFACK 9 ++#define SUBTYPE_QDATA_CFPOLL 10 ++#define SUBTYPE_QDATA_CFACK_CFPOLL 11 ++#define SUBTYPE_QOS_NULL 12 ++#define SUBTYPE_QOS_CFACK 13 ++#define SUBTYPE_QOS_CFPOLL 14 ++#define SUBTYPE_QOS_CFACK_CFPOLL 15 ++ ++// ACK policy of QOS Control field bit 6:5 ++#define NORMAL_ACK 0x00 // b6:5 = 00 ++#define NO_ACK 0x20 // b6:5 = 01 ++#define NO_EXPLICIT_ACK 0x40 // b6:5 = 10 ++#define BLOCK_ACK 0x60 // b6:5 = 11 ++ ++// ++// rtmp_data.c use these definition ++// ++#define LENGTH_802_11 24 ++#define LENGTH_802_11_AND_H 30 ++#define LENGTH_802_11_CRC_H 34 ++#define LENGTH_802_11_CRC 28 ++#define LENGTH_802_11_WITH_ADDR4 30 ++#define LENGTH_802_3 14 ++#define LENGTH_802_3_TYPE 2 ++#define LENGTH_802_1_H 8 ++#define LENGTH_EAPOL_H 4 ++#define LENGTH_WMMQOS_H 2 ++#define LENGTH_CRC 4 ++#define MAX_SEQ_NUMBER 0x0fff ++#define LENGTH_802_3_NO_TYPE 12 ++#define LENGTH_802_1Q 4 /* VLAN related */ ++ ++// STA_CSR4.field.TxResult ++#define TX_RESULT_SUCCESS 0 ++#define TX_RESULT_ZERO_LENGTH 1 ++#define TX_RESULT_UNDER_RUN 2 ++#define TX_RESULT_OHY_ERROR 4 ++#define TX_RESULT_RETRY_FAIL 6 ++ ++// All PHY rate summary in TXD ++// Preamble MODE in TxD ++#define MODE_CCK 0 ++#define MODE_OFDM 1 ++#ifdef DOT11_N_SUPPORT ++#define MODE_HTMIX 2 ++#define MODE_HTGREENFIELD 3 ++#endif // DOT11_N_SUPPORT // ++// MCS for CCK. BW.SGI.STBC are reserved ++#define MCS_LONGP_RATE_1 0 // long preamble CCK 1Mbps ++#define MCS_LONGP_RATE_2 1 // long preamble CCK 1Mbps ++#define MCS_LONGP_RATE_5_5 2 ++#define MCS_LONGP_RATE_11 3 ++#define MCS_SHORTP_RATE_1 4 // long preamble CCK 1Mbps. short is forbidden in 1Mbps ++#define MCS_SHORTP_RATE_2 5 // short preamble CCK 2Mbps ++#define MCS_SHORTP_RATE_5_5 6 ++#define MCS_SHORTP_RATE_11 7 ++// To send duplicate legacy OFDM. set BW=BW_40. SGI.STBC are reserved ++#define MCS_RATE_6 0 // legacy OFDM ++#define MCS_RATE_9 1 // OFDM ++#define MCS_RATE_12 2 // OFDM ++#define MCS_RATE_18 3 // OFDM ++#define MCS_RATE_24 4 // OFDM ++#define MCS_RATE_36 5 // OFDM ++#define MCS_RATE_48 6 // OFDM ++#define MCS_RATE_54 7 // OFDM ++// HT ++#define MCS_0 0 // 1S ++#define MCS_1 1 ++#define MCS_2 2 ++#define MCS_3 3 ++#define MCS_4 4 ++#define MCS_5 5 ++#define MCS_6 6 ++#define MCS_7 7 ++#define MCS_8 8 // 2S ++#define MCS_9 9 ++#define MCS_10 10 ++#define MCS_11 11 ++#define MCS_12 12 ++#define MCS_13 13 ++#define MCS_14 14 ++#define MCS_15 15 ++#define MCS_16 16 // 3*3 ++#define MCS_17 17 ++#define MCS_18 18 ++#define MCS_19 19 ++#define MCS_20 20 ++#define MCS_21 21 ++#define MCS_22 22 ++#define MCS_23 23 ++#define MCS_32 32 ++#define MCS_AUTO 33 ++ ++#ifdef DOT11_N_SUPPORT ++// OID_HTPHYMODE ++// MODE ++#define HTMODE_MM 0 ++#define HTMODE_GF 1 ++#endif // DOT11_N_SUPPORT // ++ ++// Fixed Tx MODE - HT, CCK or OFDM ++#define FIXED_TXMODE_HT 0 ++#define FIXED_TXMODE_CCK 1 ++#define FIXED_TXMODE_OFDM 2 ++// BW ++#define BW_20 BAND_WIDTH_20 ++#define BW_40 BAND_WIDTH_40 ++#define BW_BOTH BAND_WIDTH_BOTH ++#define BW_10 BAND_WIDTH_10 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. ++ ++#ifdef DOT11_N_SUPPORT ++// SHORTGI ++#define GI_400 GAP_INTERVAL_400 // only support in HT mode ++#define GI_BOTH GAP_INTERVAL_BOTH ++#endif // DOT11_N_SUPPORT // ++#define GI_800 GAP_INTERVAL_800 ++// STBC ++#define STBC_NONE 0 ++#ifdef DOT11_N_SUPPORT ++#define STBC_USE 1 // limited use in rt2860b phy ++#define RXSTBC_ONE 1 // rx support of one spatial stream ++#define RXSTBC_TWO 2 // rx support of 1 and 2 spatial stream ++#define RXSTBC_THR 3 // rx support of 1~3 spatial stream ++// MCS FEEDBACK ++#define MCSFBK_NONE 0 // not support mcs feedback / ++#define MCSFBK_RSV 1 // reserved ++#define MCSFBK_UNSOLICIT 2 // only support unsolict mcs feedback ++#define MCSFBK_MRQ 3 // response to both MRQ and unsolict mcs feedback ++ ++// MIMO power safe ++#define MMPS_STATIC 0 ++#define MMPS_DYNAMIC 1 ++#define MMPS_RSV 2 ++#define MMPS_ENABLE 3 ++ ++ ++// A-MSDU size ++#define AMSDU_0 0 ++#define AMSDU_1 1 ++ ++#endif // DOT11_N_SUPPORT // ++ ++// MCS use 7 bits ++#define TXRATEMIMO 0x80 ++#define TXRATEMCS 0x7F ++#define TXRATEOFDM 0x7F ++#define RATE_1 0 ++#define RATE_2 1 ++#define RATE_5_5 2 ++#define RATE_11 3 ++#define RATE_6 4 // OFDM ++#define RATE_9 5 // OFDM ++#define RATE_12 6 // OFDM ++#define RATE_18 7 // OFDM ++#define RATE_24 8 // OFDM ++#define RATE_36 9 // OFDM ++#define RATE_48 10 // OFDM ++#define RATE_54 11 // OFDM ++#define RATE_FIRST_OFDM_RATE RATE_6 ++#define RATE_LAST_OFDM_RATE RATE_54 ++#define RATE_6_5 12 // HT mix ++#define RATE_13 13 // HT mix ++#define RATE_19_5 14 // HT mix ++#define RATE_26 15 // HT mix ++#define RATE_39 16 // HT mix ++#define RATE_52 17 // HT mix ++#define RATE_58_5 18 // HT mix ++#define RATE_65 19 // HT mix ++#define RATE_78 20 // HT mix ++#define RATE_104 21 // HT mix ++#define RATE_117 22 // HT mix ++#define RATE_130 23 // HT mix ++//#define RATE_AUTO_SWITCH 255 // for StaCfg.FixedTxRate only ++#define HTRATE_0 12 ++#define RATE_FIRST_MM_RATE HTRATE_0 ++#define RATE_FIRST_HT_RATE HTRATE_0 ++#define RATE_LAST_HT_RATE HTRATE_0 ++ ++// pTxWI->txop ++#define IFS_HTTXOP 0 // The txop will be handles by ASIC. ++#define IFS_PIFS 1 ++#define IFS_SIFS 2 ++#define IFS_BACKOFF 3 ++ ++// pTxD->RetryMode ++#define LONG_RETRY 1 ++#define SHORT_RETRY 0 ++ ++// Country Region definition ++#define REGION_MINIMUM_BG_BAND 0 ++#define REGION_0_BG_BAND 0 // 1-11 ++#define REGION_1_BG_BAND 1 // 1-13 ++#define REGION_2_BG_BAND 2 // 10-11 ++#define REGION_3_BG_BAND 3 // 10-13 ++#define REGION_4_BG_BAND 4 // 14 ++#define REGION_5_BG_BAND 5 // 1-14 ++#define REGION_6_BG_BAND 6 // 3-9 ++#define REGION_7_BG_BAND 7 // 5-13 ++#define REGION_31_BG_BAND 31 // 5-13 ++#define REGION_MAXIMUM_BG_BAND 7 ++ ++#define REGION_MINIMUM_A_BAND 0 ++#define REGION_0_A_BAND 0 // 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165 ++#define REGION_1_A_BAND 1 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 ++#define REGION_2_A_BAND 2 // 36, 40, 44, 48, 52, 56, 60, 64 ++#define REGION_3_A_BAND 3 // 52, 56, 60, 64, 149, 153, 157, 161 ++#define REGION_4_A_BAND 4 // 149, 153, 157, 161, 165 ++#define REGION_5_A_BAND 5 // 149, 153, 157, 161 ++#define REGION_6_A_BAND 6 // 36, 40, 44, 48 ++#define REGION_7_A_BAND 7 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 ++#define REGION_8_A_BAND 8 // 52, 56, 60, 64 ++#define REGION_9_A_BAND 9 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165 ++#define REGION_10_A_BAND 10 // 36, 40, 44, 48, 149, 153, 157, 161, 165 ++#define REGION_11_A_BAND 11 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161 ++#define REGION_MAXIMUM_A_BAND 11 ++ ++// pTxD->CipherAlg ++#define CIPHER_NONE 0 ++#define CIPHER_WEP64 1 ++#define CIPHER_WEP128 2 ++#define CIPHER_TKIP 3 ++#define CIPHER_AES 4 ++#define CIPHER_CKIP64 5 ++#define CIPHER_CKIP128 6 ++#define CIPHER_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table ++#define CIPHER_SMS4 8 ++ ++// value domain of pAd->RfIcType ++#define RFIC_2820 1 // 2.4G 2T3R ++#define RFIC_2850 2 // 2.4G/5G 2T3R ++#define RFIC_2720 3 // 2.4G 1T2R ++#define RFIC_2750 4 // 2.4G/5G 1T2R ++#define RFIC_3020 5 // 2.4G 1T1R ++#define RFIC_2020 6 // 2.4G B/G ++ ++// LED Status. ++#define LED_LINK_DOWN 0 ++#define LED_LINK_UP 1 ++#define LED_RADIO_OFF 2 ++#define LED_RADIO_ON 3 ++#define LED_HALT 4 ++#define LED_WPS 5 ++#define LED_ON_SITE_SURVEY 6 ++#define LED_POWER_UP 7 ++ ++// value domain of pAd->LedCntl.LedMode and E2PROM ++#define LED_MODE_DEFAULT 0 ++#define LED_MODE_TWO_LED 1 ++#define LED_MODE_SIGNAL_STREGTH 8 // EEPROM define =8 ++ ++// RC4 init value, used fro WEP & TKIP ++#define PPPINITFCS32 0xffffffff /* Initial FCS value */ ++ ++// value domain of pAd->StaCfg.PortSecured. 802.1X controlled port definition ++#define WPA_802_1X_PORT_SECURED 1 ++#define WPA_802_1X_PORT_NOT_SECURED 2 ++ ++#define PAIRWISE_KEY 1 ++#define GROUP_KEY 2 ++ ++//definition of DRS ++#define MAX_STEP_OF_TX_RATE_SWITCH 32 ++ ++ ++// pre-allocated free NDIS PACKET/BUFFER poll for internal usage ++#define MAX_NUM_OF_FREE_NDIS_PACKET 128 ++ ++//Block ACK ++#define MAX_TX_REORDERBUF 64 ++#define MAX_RX_REORDERBUF 64 ++#define DEFAULT_TX_TIMEOUT 30 ++#define DEFAULT_RX_TIMEOUT 30 ++ ++// definition of Recipient or Originator ++#define I_RECIPIENT TRUE ++#define I_ORIGINATOR FALSE ++ ++#define DEFAULT_BBP_TX_POWER 0 ++#define DEFAULT_RF_TX_POWER 5 ++ ++#define MAX_INI_BUFFER_SIZE 4096 ++#define MAX_PARAM_BUFFER_SIZE (2048) // enough for ACL (18*64) ++ //18 : the length of Mac address acceptable format "01:02:03:04:05:06;") ++ //64 : MAX_NUM_OF_ACL_LIST ++// definition of pAd->OpMode ++#define OPMODE_STA 0 ++#define OPMODE_AP 1 ++//#define OPMODE_L3_BRG 2 // as AP and STA at the same time ++ ++#ifdef RT_BIG_ENDIAN ++#define DIR_READ 0 ++#define DIR_WRITE 1 ++#define TYPE_TXD 0 ++#define TYPE_RXD 1 ++#define TYPE_TXINFO 0 ++#define TYPE_RXINFO 1 ++#define TYPE_TXWI 0 ++#define TYPE_RXWI 1 ++#endif ++ ++// ========================= AP rtmp_def.h =========================== ++// value domain for pAd->EventTab.Log[].Event ++#define EVENT_RESET_ACCESS_POINT 0 // Log = "hh:mm:ss Restart Access Point" ++#define EVENT_ASSOCIATED 1 // Log = "hh:mm:ss STA 00:01:02:03:04:05 associated" ++#define EVENT_DISASSOCIATED 2 // Log = "hh:mm:ss STA 00:01:02:03:04:05 left this BSS" ++#define EVENT_AGED_OUT 3 // Log = "hh:mm:ss STA 00:01:02:03:04:05 was aged-out and removed from this BSS" ++#define EVENT_COUNTER_M 4 ++#define EVENT_INVALID_PSK 5 ++#define EVENT_MAX_EVENT_TYPE 6 ++// ==== end of AP rtmp_def.h ============ ++ ++// definition RSSI Number ++#define RSSI_0 0 ++#define RSSI_1 1 ++#define RSSI_2 2 ++ ++// definition of radar detection ++#define RD_NORMAL_MODE 0 // Not found radar signal ++#define RD_SWITCHING_MODE 1 // Found radar signal, and doing channel switch ++#define RD_SILENCE_MODE 2 // After channel switch, need to be silence a while to ensure radar not found ++ ++//Driver defined cid for mapping status and command. ++#define SLEEPCID 0x11 ++#define WAKECID 0x22 ++#define QUERYPOWERCID 0x33 ++#define OWNERMCU 0x1 ++#define OWNERCPU 0x0 ++ ++// MBSSID definition ++#define ENTRY_NOT_FOUND 0xFF ++ ++ ++/* After Linux 2.6.9, ++ * VLAN module use Private (from user) interface flags (netdevice->priv_flags). ++ * #define IFF_802_1Q_VLAN 0x1 -- 802.1Q VLAN device. in if.h ++ * ref to ip_sabotage_out() [ out->priv_flags & IFF_802_1Q_VLAN ] in br_netfilter.c ++ * ++ * For this reason, we MUST use EVEN value in priv_flags ++ */ ++#define INT_MAIN 0x0100 ++#define INT_MBSSID 0x0200 ++#define INT_WDS 0x0300 ++#define INT_APCLI 0x0400 ++#define INT_MESH 0x0500 ++ ++// Use bitmap to allow coexist of ATE_TXFRAME and ATE_RXFRAME(i.e.,to support LoopBack mode) ++#ifdef RALINK_ATE ++#define ATE_START 0x00 // Start ATE ++#define ATE_STOP 0x80 // Stop ATE ++#define ATE_TXCONT 0x05 // Continuous Transmit ++#define ATE_TXCARR 0x09 // Transmit Carrier ++#define ATE_TXCARRSUPP 0x11 // Transmit Carrier Suppression ++#define ATE_TXFRAME 0x01 // Transmit Frames ++#define ATE_RXFRAME 0x02 // Receive Frames ++#ifdef RALINK_28xx_QA ++#define ATE_TXSTOP 0xe2 // Stop Transmition(i.e., TXCONT, TXCARR, TXCARRSUPP, and TXFRAME) ++#define ATE_RXSTOP 0xfd // Stop receiving Frames ++#define BBP22_TXFRAME 0x00 // Transmit Frames ++#define BBP22_TXCONT_OR_CARRSUPP 0x80 // Continuous Transmit or Carrier Suppression ++#define BBP22_TXCARR 0xc1 // Transmit Carrier ++#define BBP24_TXCONT 0x00 // Continuous Transmit ++#define BBP24_CARRSUPP 0x01 // Carrier Suppression ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++// WEP Key TYPE ++#define WEP_HEXADECIMAL_TYPE 0 ++#define WEP_ASCII_TYPE 1 ++ ++ ++ ++// WIRELESS EVENTS definition ++/* Max number of char in custom event, refer to wireless_tools.28/wireless.20.h */ ++#define IW_CUSTOM_MAX_LEN 255 /* In bytes */ ++ ++// For system event - start ++#define IW_SYS_EVENT_FLAG_START 0x0200 ++#define IW_ASSOC_EVENT_FLAG 0x0200 ++#define IW_DISASSOC_EVENT_FLAG 0x0201 ++#define IW_DEAUTH_EVENT_FLAG 0x0202 ++#define IW_AGEOUT_EVENT_FLAG 0x0203 ++#define IW_COUNTER_MEASURES_EVENT_FLAG 0x0204 ++#define IW_REPLAY_COUNTER_DIFF_EVENT_FLAG 0x0205 ++#define IW_RSNIE_DIFF_EVENT_FLAG 0x0206 ++#define IW_MIC_DIFF_EVENT_FLAG 0x0207 ++#define IW_ICV_ERROR_EVENT_FLAG 0x0208 ++#define IW_MIC_ERROR_EVENT_FLAG 0x0209 ++#define IW_GROUP_HS_TIMEOUT_EVENT_FLAG 0x020A ++#define IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG 0x020B ++#define IW_RSNIE_SANITY_FAIL_EVENT_FLAG 0x020C ++#define IW_SET_KEY_DONE_WPA1_EVENT_FLAG 0x020D ++#define IW_SET_KEY_DONE_WPA2_EVENT_FLAG 0x020E ++#define IW_STA_LINKUP_EVENT_FLAG 0x020F ++#define IW_STA_LINKDOWN_EVENT_FLAG 0x0210 ++#define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211 ++#define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212 ++// if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END ++#define IW_SYS_EVENT_FLAG_END 0x0212 ++#define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1) ++// For system event - end ++ ++// For spoof attack event - start ++#define IW_SPOOF_EVENT_FLAG_START 0x0300 ++#define IW_CONFLICT_SSID_EVENT_FLAG 0x0300 ++#define IW_SPOOF_ASSOC_RESP_EVENT_FLAG 0x0301 ++#define IW_SPOOF_REASSOC_RESP_EVENT_FLAG 0x0302 ++#define IW_SPOOF_PROBE_RESP_EVENT_FLAG 0x0303 ++#define IW_SPOOF_BEACON_EVENT_FLAG 0x0304 ++#define IW_SPOOF_DISASSOC_EVENT_FLAG 0x0305 ++#define IW_SPOOF_AUTH_EVENT_FLAG 0x0306 ++#define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307 ++#define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308 ++#define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309 ++// if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END ++#define IW_SPOOF_EVENT_FLAG_END 0x0309 ++#define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1) ++// For spoof attack event - end ++ ++// For flooding attack event - start ++#define IW_FLOOD_EVENT_FLAG_START 0x0400 ++#define IW_FLOOD_AUTH_EVENT_FLAG 0x0400 ++#define IW_FLOOD_ASSOC_REQ_EVENT_FLAG 0x0401 ++#define IW_FLOOD_REASSOC_REQ_EVENT_FLAG 0x0402 ++#define IW_FLOOD_PROBE_REQ_EVENT_FLAG 0x0403 ++#define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404 ++#define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405 ++#define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406 ++// if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END ++#define IW_FLOOD_EVENT_FLAG_END 0x0406 ++#define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1) ++// For flooding attack - end ++ ++// End - WIRELESS EVENTS definition ++ ++#ifdef CONFIG_STA_SUPPORT ++// definition for DLS, kathy ++#define MAX_NUM_OF_INIT_DLS_ENTRY 1 ++#define MAX_NUM_OF_DLS_ENTRY MAX_NUMBER_OF_DLS_ENTRY ++ ++//Block ACK , rt2860, kathy ++#define MAX_TX_REORDERBUF 64 ++#define MAX_RX_REORDERBUF 64 ++#define DEFAULT_TX_TIMEOUT 30 ++#define DEFAULT_RX_TIMEOUT 30 ++#ifndef CONFIG_AP_SUPPORT ++#define MAX_BARECI_SESSION 8 ++#endif ++ ++#ifndef IW_ESSID_MAX_SIZE ++/* Maximum size of the ESSID and pAd->nickname strings */ ++#define IW_ESSID_MAX_SIZE 32 ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef MCAST_RATE_SPECIFIC ++#define MCAST_DISABLE 0 ++#define MCAST_CCK 1 ++#define MCAST_OFDM 2 ++#define MCAST_HTMIX 3 ++#endif // MCAST_RATE_SPECIFIC // ++ ++// For AsicRadioOff/AsicRadioOn function ++#define DOT11POWERSAVE 0 ++#define GUIRADIO_OFF 1 ++#define RTMP_HALT 2 ++#define GUI_IDLE_POWER_SAVE 3 ++// -- ++ ++ ++// definition for WpaSupport flag ++#define WPA_SUPPLICANT_DISABLE 0 ++#define WPA_SUPPLICANT_ENABLE 1 ++#define WPA_SUPPLICANT_ENABLE_WITH_WEB_UI 2 ++ ++// Endian byte swapping codes ++#define SWAP16(x) \ ++ ((UINT16)( \ ++ (((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \ ++ (((UINT16)(x) & (UINT16) 0xff00U) >> 8) )) ++ ++#define SWAP32(x) \ ++ ((UINT32)( \ ++ (((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \ ++ (((UINT32)(x) & (UINT32) 0x0000ff00UL) << 8) | \ ++ (((UINT32)(x) & (UINT32) 0x00ff0000UL) >> 8) | \ ++ (((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) )) ++ ++#define SWAP64(x) \ ++ ((UINT64)( \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) << 8) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >> 8) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) ++ ++#ifdef RT_BIG_ENDIAN ++ ++#define cpu2le64(x) SWAP64((x)) ++#define le2cpu64(x) SWAP64((x)) ++#define cpu2le32(x) SWAP32((x)) ++#define le2cpu32(x) SWAP32((x)) ++#define cpu2le16(x) SWAP16((x)) ++#define le2cpu16(x) SWAP16((x)) ++#define cpu2be64(x) ((UINT64)(x)) ++#define be2cpu64(x) ((UINT64)(x)) ++#define cpu2be32(x) ((UINT32)(x)) ++#define be2cpu32(x) ((UINT32)(x)) ++#define cpu2be16(x) ((UINT16)(x)) ++#define be2cpu16(x) ((UINT16)(x)) ++ ++#else // Little_Endian ++ ++#define cpu2le64(x) ((UINT64)(x)) ++#define le2cpu64(x) ((UINT64)(x)) ++#define cpu2le32(x) ((UINT32)(x)) ++#define le2cpu32(x) ((UINT32)(x)) ++#define cpu2le16(x) ((UINT16)(x)) ++#define le2cpu16(x) ((UINT16)(x)) ++#define cpu2be64(x) SWAP64((x)) ++#define be2cpu64(x) SWAP64((x)) ++#define cpu2be32(x) SWAP32((x)) ++#define be2cpu32(x) SWAP32((x)) ++#define cpu2be16(x) SWAP16((x)) ++#define be2cpu16(x) SWAP16((x)) ++ ++#endif // RT_BIG_ENDIAN ++ ++#endif // __RTMP_DEF_H__ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rtmp.h +@@ -0,0 +1,7586 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp.h ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ James Tan 2002-09-06 modified (Revise NTCRegTable) ++ John Chang 2004-09-06 modified for RT2600 ++*/ ++#ifndef __RTMP_H__ ++#define __RTMP_H__ ++ ++#include "link_list.h" ++#include "spectrum_def.h" ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#include "aironet.h" ++#endif // CONFIG_STA_SUPPORT // ++ ++//#define DBG 1 ++ ++//#define DBG_DIAGNOSE 1 ++ ++#if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_STA_SUPPORT) ++#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) if(_pAd->OpMode == OPMODE_AP) ++#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) if(_pAd->OpMode == OPMODE_STA) ++#else ++#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) ++#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) ++#endif ++ ++#define VIRTUAL_IF_INC(__pAd) ((__pAd)->VirtualIfCnt++) ++#define VIRTUAL_IF_DEC(__pAd) ((__pAd)->VirtualIfCnt--) ++#define VIRTUAL_IF_NUM(__pAd) ((__pAd)->VirtualIfCnt) ++ ++#ifdef RT2870 ++//////////////////////////////////////////////////////////////////////////// ++// The TX_BUFFER structure forms the transmitted USB packet to the device ++//////////////////////////////////////////////////////////////////////////// ++typedef struct __TX_BUFFER{ ++ union { ++ UCHAR WirelessPacket[TX_BUFFER_NORMSIZE]; ++ HEADER_802_11 NullFrame; ++ PSPOLL_FRAME PsPollPacket; ++ RTS_FRAME RTSFrame; ++ }field; ++ UCHAR Aggregation[4]; //Buffer for save Aggregation size. ++} TX_BUFFER, *PTX_BUFFER; ++ ++typedef struct __HTTX_BUFFER{ ++ union { ++ UCHAR WirelessPacket[MAX_TXBULK_SIZE]; ++ HEADER_802_11 NullFrame; ++ PSPOLL_FRAME PsPollPacket; ++ RTS_FRAME RTSFrame; ++ }field; ++ UCHAR Aggregation[4]; //Buffer for save Aggregation size. ++} HTTX_BUFFER, *PHTTX_BUFFER; ++ ++ ++// used to track driver-generated write irps ++typedef struct _TX_CONTEXT ++{ ++ PVOID pAd; //Initialized in MiniportInitialize ++ PURB pUrb; //Initialized in MiniportInitialize ++ PIRP pIrp; //used to cancel pending bulk out. ++ //Initialized in MiniportInitialize ++ PTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize ++ ULONG BulkOutSize; ++ UCHAR BulkOutPipeId; ++ UCHAR SelfIdx; ++ BOOLEAN InUse; ++ BOOLEAN bWaitingBulkOut; // at least one packet is in this TxContext, ready for making IRP anytime. ++ BOOLEAN bFullForBulkOut; // all tx buffer are full , so waiting for tx bulkout. ++ BOOLEAN IRPPending; ++ BOOLEAN LastOne; ++ BOOLEAN bAggregatible; ++ UCHAR Header_802_3[LENGTH_802_3]; ++ UCHAR Rsv[2]; ++ ULONG DataOffset; ++ UINT TxRate; ++ dma_addr_t data_dma; // urb dma on linux ++ ++} TX_CONTEXT, *PTX_CONTEXT, **PPTX_CONTEXT; ++ ++ ++// used to track driver-generated write irps ++typedef struct _HT_TX_CONTEXT ++{ ++ PVOID pAd; //Initialized in MiniportInitialize ++ PURB pUrb; //Initialized in MiniportInitialize ++ PIRP pIrp; //used to cancel pending bulk out. ++ //Initialized in MiniportInitialize ++ PHTTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize ++ ULONG BulkOutSize; // Indicate the total bulk-out size in bytes in one bulk-transmission ++ UCHAR BulkOutPipeId; ++ BOOLEAN IRPPending; ++ BOOLEAN LastOne; ++ BOOLEAN bCurWriting; ++ BOOLEAN bRingEmpty; ++ BOOLEAN bCopySavePad; ++ UCHAR SavedPad[8]; ++ UCHAR Header_802_3[LENGTH_802_3]; ++ ULONG CurWritePosition; // Indicate the buffer offset which packet will be inserted start from. ++ ULONG CurWriteRealPos; // Indicate the buffer offset which packet now are writing to. ++ ULONG NextBulkOutPosition; // Indicate the buffer start offset of a bulk-transmission ++ ULONG ENextBulkOutPosition; // Indicate the buffer end offset of a bulk-transmission ++ UINT TxRate; ++ dma_addr_t data_dma; // urb dma on linux ++} HT_TX_CONTEXT, *PHT_TX_CONTEXT, **PPHT_TX_CONTEXT; ++ ++ ++// ++// Structure to keep track of receive packets and buffers to indicate ++// receive data to the protocol. ++// ++typedef struct _RX_CONTEXT ++{ ++ PUCHAR TransferBuffer; ++ PVOID pAd; ++ PIRP pIrp;//used to cancel pending bulk in. ++ PURB pUrb; ++ //These 2 Boolean shouldn't both be 1 at the same time. ++ ULONG BulkInOffset; // number of packets waiting for reordering . ++// BOOLEAN ReorderInUse; // At least one packet in this buffer are in reordering buffer and wait for receive indication ++ BOOLEAN bRxHandling; // Notify this packet is being process now. ++ BOOLEAN InUse; // USB Hardware Occupied. Wait for USB HW to put packet. ++ BOOLEAN Readable; // Receive Complete back. OK for driver to indicate receiving packet. ++ BOOLEAN IRPPending; // TODO: To be removed ++ atomic_t IrpLock; ++ NDIS_SPIN_LOCK RxContextLock; ++ dma_addr_t data_dma; // urb dma on linux ++} RX_CONTEXT, *PRX_CONTEXT; ++#endif // RT2870 // ++ ++ ++// ++// NDIS Version definitions ++// ++#ifdef NDIS50_MINIPORT ++#define RTMP_NDIS_MAJOR_VERSION 5 ++#define RTMP_NDIS_MINOR_VERSION 0 ++#endif ++ ++#ifdef NDIS51_MINIPORT ++#define RTMP_NDIS_MAJOR_VERSION 5 ++#define RTMP_NDIS_MINOR_VERSION 1 ++#endif ++ ++extern char NIC_VENDOR_DESC[]; ++extern int NIC_VENDOR_DESC_LEN; ++ ++extern unsigned char SNAP_AIRONET[]; ++extern unsigned char CipherSuiteCiscoCCKM[]; ++extern unsigned char CipherSuiteCiscoCCKMLen; ++extern unsigned char CipherSuiteCiscoCCKM24[]; ++extern unsigned char CipherSuiteCiscoCCKM24Len; ++extern unsigned char CipherSuiteCCXTkip[]; ++extern unsigned char CipherSuiteCCXTkipLen; ++extern unsigned char CISCO_OUI[]; ++extern UCHAR BaSizeArray[4]; ++ ++extern UCHAR BROADCAST_ADDR[MAC_ADDR_LEN]; ++extern UCHAR MULTICAST_ADDR[MAC_ADDR_LEN]; ++extern UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN]; ++extern ULONG BIT32[32]; ++extern UCHAR BIT8[8]; ++extern char* CipherName[]; ++extern char* MCSToMbps[]; ++extern UCHAR RxwiMCSToOfdmRate[12]; ++extern UCHAR SNAP_802_1H[6]; ++extern UCHAR SNAP_BRIDGE_TUNNEL[6]; ++extern UCHAR SNAP_AIRONET[8]; ++extern UCHAR CKIP_LLC_SNAP[8]; ++extern UCHAR EAPOL_LLC_SNAP[8]; ++extern UCHAR EAPOL[2]; ++extern UCHAR IPX[2]; ++extern UCHAR APPLE_TALK[2]; ++extern UCHAR RateIdToPlcpSignal[12]; // see IEEE802.11a-1999 p.14 ++extern UCHAR OfdmRateToRxwiMCS[]; ++extern UCHAR OfdmSignalToRateId[16] ; ++extern UCHAR default_cwmin[4]; ++extern UCHAR default_cwmax[4]; ++extern UCHAR default_sta_aifsn[4]; ++extern UCHAR MapUserPriorityToAccessCategory[8]; ++ ++extern USHORT RateUpPER[]; ++extern USHORT RateDownPER[]; ++extern UCHAR Phy11BNextRateDownward[]; ++extern UCHAR Phy11BNextRateUpward[]; ++extern UCHAR Phy11BGNextRateDownward[]; ++extern UCHAR Phy11BGNextRateUpward[]; ++extern UCHAR Phy11ANextRateDownward[]; ++extern UCHAR Phy11ANextRateUpward[]; ++extern CHAR RssiSafeLevelForTxRate[]; ++extern UCHAR RateIdToMbps[]; ++extern USHORT RateIdTo500Kbps[]; ++ ++extern UCHAR CipherSuiteWpaNoneTkip[]; ++extern UCHAR CipherSuiteWpaNoneTkipLen; ++ ++extern UCHAR CipherSuiteWpaNoneAes[]; ++extern UCHAR CipherSuiteWpaNoneAesLen; ++ ++extern UCHAR SsidIe; ++extern UCHAR SupRateIe; ++extern UCHAR ExtRateIe; ++ ++#ifdef DOT11_N_SUPPORT ++extern UCHAR HtCapIe; ++extern UCHAR AddHtInfoIe; ++extern UCHAR NewExtChanIe; ++#ifdef DOT11N_DRAFT3 ++extern UCHAR ExtHtCapIe; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++extern UCHAR ErpIe; ++extern UCHAR DsIe; ++extern UCHAR TimIe; ++extern UCHAR WpaIe; ++extern UCHAR Wpa2Ie; ++extern UCHAR IbssIe; ++extern UCHAR Ccx2Ie; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR Ccx2IeInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR PowerConstraintIE[]; ++ ++ ++extern UCHAR RateSwitchTable[]; ++extern UCHAR RateSwitchTable11B[]; ++extern UCHAR RateSwitchTable11G[]; ++extern UCHAR RateSwitchTable11BG[]; ++ ++#ifdef DOT11_N_SUPPORT ++extern UCHAR RateSwitchTable11BGN1S[]; ++extern UCHAR RateSwitchTable11BGN2S[]; ++extern UCHAR RateSwitchTable11BGN2SForABand[]; ++extern UCHAR RateSwitchTable11N1S[]; ++extern UCHAR RateSwitchTable11N2S[]; ++extern UCHAR RateSwitchTable11N2SForABand[]; ++ ++#ifdef CONFIG_STA_SUPPORT ++extern UCHAR PRE_N_HT_OUI[]; ++#endif // CONFIG_STA_SUPPORT // ++#endif // DOT11_N_SUPPORT // ++ ++#define MAXSEQ (0xFFF) ++ ++#ifdef RALINK_ATE ++typedef struct _ATE_INFO { ++ UCHAR Mode; ++ CHAR TxPower0; ++ CHAR TxPower1; ++ CHAR TxAntennaSel; ++ CHAR RxAntennaSel; ++ TXWI_STRUC TxWI; // TXWI ++ USHORT QID; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR Addr3[MAC_ADDR_LEN]; ++ UCHAR Channel; ++ UINT32 TxLength; ++ UINT32 TxCount; ++ UINT32 TxDoneCount; // Tx DMA Done ++ UINT32 RFFreqOffset; ++ BOOLEAN bRxFer; ++ BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. ++ BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. ++ UINT32 RxTotalCnt; ++ UINT32 RxCntPerSec; ++ ++ CHAR LastSNR0; // last received SNR ++ CHAR LastSNR1; // last received SNR for 2nd antenna ++ CHAR LastRssi0; // last received RSSI ++ CHAR LastRssi1; // last received RSSI for 2nd antenna ++ CHAR LastRssi2; // last received RSSI for 3rd antenna ++ CHAR AvgRssi0; // last 8 frames' average RSSI ++ CHAR AvgRssi1; // last 8 frames' average RSSI ++ CHAR AvgRssi2; // last 8 frames' average RSSI ++ SHORT AvgRssi0X8; // sum of last 8 frames' RSSI ++ SHORT AvgRssi1X8; // sum of last 8 frames' RSSI ++ SHORT AvgRssi2X8; // sum of last 8 frames' RSSI ++ ++ UINT32 NumOfAvgRssiSample; ++ ++#ifdef RALINK_28xx_QA ++ // Tx frame ++#ifdef RT2870 ++ /* not used in RT2860 */ ++ TXINFO_STRUC TxInfo; // TxInfo ++#endif // RT2870 // ++ USHORT HLen; // Header Length ++ USHORT PLen; // Pattern Length ++ UCHAR Header[32]; // Header buffer ++ UCHAR Pattern[32]; // Pattern buffer ++ USHORT DLen; // Data Length ++ USHORT seq; ++ UINT32 CID; ++ THREAD_PID AtePid; ++ // counters ++ UINT32 U2M; ++ UINT32 OtherData; ++ UINT32 Beacon; ++ UINT32 OtherCount; ++ UINT32 TxAc0; ++ UINT32 TxAc1; ++ UINT32 TxAc2; ++ UINT32 TxAc3; ++ UINT32 TxHCCA; ++ UINT32 TxMgmt; ++ UINT32 RSSI0; ++ UINT32 RSSI1; ++ UINT32 RSSI2; ++ UINT32 SNR0; ++ UINT32 SNR1; ++ // control ++ //UINT32 Repeat; // Tx Cpu count ++ UCHAR TxStatus; // task Tx status // 0 --> task is idle, 1 --> task is running ++#endif // RALINK_28xx_QA // ++} ATE_INFO, *PATE_INFO; ++ ++#ifdef RALINK_28xx_QA ++struct ate_racfghdr { ++ UINT32 magic_no; ++ USHORT command_type; ++ USHORT command_id; ++ USHORT length; ++ USHORT sequence; ++ USHORT status; ++ UCHAR data[2046]; ++} __attribute__((packed)); ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++struct reordering_mpdu ++{ ++ struct reordering_mpdu *next; ++ PNDIS_PACKET pPacket; /* coverted to 802.3 frame */ ++ int Sequence; /* sequence number of MPDU */ ++ BOOLEAN bAMSDU; ++}; ++ ++struct reordering_list ++{ ++ struct reordering_mpdu *next; ++ int qlen; ++}; ++ ++struct reordering_mpdu_pool ++{ ++ PVOID mem; ++ NDIS_SPIN_LOCK lock; ++ struct reordering_list freelist; ++}; ++#endif // DOT11_N_SUPPORT // ++ ++typedef struct _RSSI_SAMPLE { ++ CHAR LastRssi0; // last received RSSI ++ CHAR LastRssi1; // last received RSSI ++ CHAR LastRssi2; // last received RSSI ++ CHAR AvgRssi0; ++ CHAR AvgRssi1; ++ CHAR AvgRssi2; ++ SHORT AvgRssi0X8; ++ SHORT AvgRssi1X8; ++ SHORT AvgRssi2X8; ++} RSSI_SAMPLE; ++ ++// ++// Queue structure and macros ++// ++typedef struct _QUEUE_ENTRY { ++ struct _QUEUE_ENTRY *Next; ++} QUEUE_ENTRY, *PQUEUE_ENTRY; ++ ++// Queue structure ++typedef struct _QUEUE_HEADER { ++ PQUEUE_ENTRY Head; ++ PQUEUE_ENTRY Tail; ++ ULONG Number; ++} QUEUE_HEADER, *PQUEUE_HEADER; ++ ++#define InitializeQueueHeader(QueueHeader) \ ++{ \ ++ (QueueHeader)->Head = (QueueHeader)->Tail = NULL; \ ++ (QueueHeader)->Number = 0; \ ++} ++ ++#define RemoveHeadQueue(QueueHeader) \ ++(QueueHeader)->Head; \ ++{ \ ++ PQUEUE_ENTRY pNext; \ ++ if ((QueueHeader)->Head != NULL) \ ++ { \ ++ pNext = (QueueHeader)->Head->Next; \ ++ (QueueHeader)->Head = pNext; \ ++ if (pNext == NULL) \ ++ (QueueHeader)->Tail = NULL; \ ++ (QueueHeader)->Number--; \ ++ } \ ++} ++ ++#define InsertHeadQueue(QueueHeader, QueueEntry) \ ++{ \ ++ ((PQUEUE_ENTRY)QueueEntry)->Next = (QueueHeader)->Head; \ ++ (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ ++ if ((QueueHeader)->Tail == NULL) \ ++ (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Number++; \ ++} ++ ++#define InsertTailQueue(QueueHeader, QueueEntry) \ ++{ \ ++ ((PQUEUE_ENTRY)QueueEntry)->Next = NULL; \ ++ if ((QueueHeader)->Tail) \ ++ (QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(QueueEntry); \ ++ else \ ++ (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Number++; \ ++} ++ ++// ++// Macros for flag and ref count operations ++// ++#define RTMP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) ++#define RTMP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) ++#define RTMP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) ++#define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) ++#define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) ++ ++#define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) ++#define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) ++#define OPSTATUS_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.OpStatusFlags & (_F)) != 0) ++ ++#define CLIENT_STATUS_SET_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags |= (_F)) ++#define CLIENT_STATUS_CLEAR_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags &= ~(_F)) ++#define CLIENT_STATUS_TEST_FLAG(_pEntry,_F) (((_pEntry)->ClientStatusFlags & (_F)) != 0) ++ ++#define RX_FILTER_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter |= (_F)) ++#define RX_FILTER_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter &= ~(_F)) ++#define RX_FILTER_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.PacketFilter & (_F)) != 0) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define STA_NO_SECURITY_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) ++#define STA_WEP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) ++#define STA_TKIP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++#define STA_AES_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ ++#define STA_TGN_WIFI_ON(_p) (_p->StaCfg.bTGnWifiTest == TRUE) ++#endif // CONFIG_STA_SUPPORT // ++ ++#define CKIP_KP_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x10) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) ++#define CKIP_CMIC_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x08) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) ++ ++ ++#define INC_RING_INDEX(_idx, _RingSize) \ ++{ \ ++ (_idx) = (_idx+1) % (_RingSize); \ ++} ++ ++#define IS_RT3070(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30700000) ++ ++#define RING_PACKET_INIT(_TxRing, _idx) \ ++{ \ ++ _TxRing->Cell[_idx].pNdisPacket = NULL; \ ++ _TxRing->Cell[_idx].pNextNdisPacket = NULL; \ ++} ++ ++#define TXDT_INIT(_TxD) \ ++{ \ ++ NdisZeroMemory(_TxD, TXD_SIZE); \ ++ _TxD->DMADONE = 1; \ ++} ++ ++//Set last data segment ++#define RING_SET_LASTDS(_TxD, _IsSD0) \ ++{ \ ++ if (_IsSD0) {_TxD->LastSec0 = 1;} \ ++ else {_TxD->LastSec1 = 1;} \ ++} ++ ++// Increase TxTsc value for next transmission ++// TODO: ++// When i==6, means TSC has done one full cycle, do re-keying stuff follow specs ++// Should send a special event microsoft defined to request re-key ++#define INC_TX_TSC(_tsc) \ ++{ \ ++ int i=0; \ ++ while (++_tsc[i] == 0x0) \ ++ { \ ++ i++; \ ++ if (i == 6) \ ++ break; \ ++ } \ ++} ++ ++#ifdef DOT11_N_SUPPORT ++// StaActive.SupportedHtPhy.MCSSet is copied from AP beacon. Don't need to update here. ++#define COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ ++{ \ ++ _pAd->StaActive.SupportedHtPhy.ChannelWidth = _pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth; \ ++ _pAd->StaActive.SupportedHtPhy.MimoPs = _pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs; \ ++ _pAd->StaActive.SupportedHtPhy.GF = _pAd->MlmeAux.HtCapability.HtCapInfo.GF; \ ++ _pAd->StaActive.SupportedHtPhy.ShortGIfor20 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20; \ ++ _pAd->StaActive.SupportedHtPhy.ShortGIfor40 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40; \ ++ _pAd->StaActive.SupportedHtPhy.TxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC; \ ++ _pAd->StaActive.SupportedHtPhy.RxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC; \ ++ _pAd->StaActive.SupportedHtPhy.ExtChanOffset = _pAd->MlmeAux.AddHtInfo.AddHtInfo.ExtChanOffset; \ ++ _pAd->StaActive.SupportedHtPhy.RecomWidth = _pAd->MlmeAux.AddHtInfo.AddHtInfo.RecomWidth; \ ++ _pAd->StaActive.SupportedHtPhy.OperaionMode = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode; \ ++ _pAd->StaActive.SupportedHtPhy.NonGfPresent = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent; \ ++ NdisMoveMemory((_pAd)->MacTab.Content[BSSID_WCID].HTCapability.MCSSet, (_pAd)->StaActive.SupportedPhyInfo.MCSSet, sizeof(UCHAR) * 16);\ ++} ++ ++#define COPY_AP_HTSETTINGS_FROM_BEACON(_pAd, _pHtCapability) \ ++{ \ ++ _pAd->MacTab.Content[BSSID_WCID].AMsduSize = (UCHAR)(_pHtCapability->HtCapInfo.AMsduSize); \ ++ _pAd->MacTab.Content[BSSID_WCID].MmpsMode= (UCHAR)(_pHtCapability->HtCapInfo.MimoPs); \ ++ _pAd->MacTab.Content[BSSID_WCID].MaxRAmpduFactor = (UCHAR)(_pHtCapability->HtCapParm.MaxRAmpduFactor); \ ++} ++#endif // DOT11_N_SUPPORT // ++ ++// ++// BBP & RF are using indirect access. Before write any value into it. ++// We have to make sure there is no outstanding command pending via checking busy bit. ++// ++#define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register ++// ++ ++#ifdef RT2870 ++#define RTMP_RF_IO_WRITE32(_A, _V) RTUSBWriteRFRegister(_A, _V) ++#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) ++#define RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) ++ ++#define BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) ++#define BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) ++#endif // RT2870 // ++ ++#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ ++ switch (ch) \ ++ { \ ++ case 1: khz = 2412000; break; \ ++ case 2: khz = 2417000; break; \ ++ case 3: khz = 2422000; break; \ ++ case 4: khz = 2427000; break; \ ++ case 5: khz = 2432000; break; \ ++ case 6: khz = 2437000; break; \ ++ case 7: khz = 2442000; break; \ ++ case 8: khz = 2447000; break; \ ++ case 9: khz = 2452000; break; \ ++ case 10: khz = 2457000; break; \ ++ case 11: khz = 2462000; break; \ ++ case 12: khz = 2467000; break; \ ++ case 13: khz = 2472000; break; \ ++ case 14: khz = 2484000; break; \ ++ case 36: /* UNII */ khz = 5180000; break; \ ++ case 40: /* UNII */ khz = 5200000; break; \ ++ case 44: /* UNII */ khz = 5220000; break; \ ++ case 48: /* UNII */ khz = 5240000; break; \ ++ case 52: /* UNII */ khz = 5260000; break; \ ++ case 56: /* UNII */ khz = 5280000; break; \ ++ case 60: /* UNII */ khz = 5300000; break; \ ++ case 64: /* UNII */ khz = 5320000; break; \ ++ case 149: /* UNII */ khz = 5745000; break; \ ++ case 153: /* UNII */ khz = 5765000; break; \ ++ case 157: /* UNII */ khz = 5785000; break; \ ++ case 161: /* UNII */ khz = 5805000; break; \ ++ case 165: /* UNII */ khz = 5825000; break; \ ++ case 100: /* HiperLAN2 */ khz = 5500000; break; \ ++ case 104: /* HiperLAN2 */ khz = 5520000; break; \ ++ case 108: /* HiperLAN2 */ khz = 5540000; break; \ ++ case 112: /* HiperLAN2 */ khz = 5560000; break; \ ++ case 116: /* HiperLAN2 */ khz = 5580000; break; \ ++ case 120: /* HiperLAN2 */ khz = 5600000; break; \ ++ case 124: /* HiperLAN2 */ khz = 5620000; break; \ ++ case 128: /* HiperLAN2 */ khz = 5640000; break; \ ++ case 132: /* HiperLAN2 */ khz = 5660000; break; \ ++ case 136: /* HiperLAN2 */ khz = 5680000; break; \ ++ case 140: /* HiperLAN2 */ khz = 5700000; break; \ ++ case 34: /* Japan MMAC */ khz = 5170000; break; \ ++ case 38: /* Japan MMAC */ khz = 5190000; break; \ ++ case 42: /* Japan MMAC */ khz = 5210000; break; \ ++ case 46: /* Japan MMAC */ khz = 5230000; break; \ ++ case 184: /* Japan */ khz = 4920000; break; \ ++ case 188: /* Japan */ khz = 4940000; break; \ ++ case 192: /* Japan */ khz = 4960000; break; \ ++ case 196: /* Japan */ khz = 4980000; break; \ ++ case 208: /* Japan, means J08 */ khz = 5040000; break; \ ++ case 212: /* Japan, means J12 */ khz = 5060000; break; \ ++ case 216: /* Japan, means J16 */ khz = 5080000; break; \ ++ default: khz = 2412000; break; \ ++ } \ ++ } ++ ++#define MAP_KHZ_TO_CHANNEL_ID(khz, ch) { \ ++ switch (khz) \ ++ { \ ++ case 2412000: ch = 1; break; \ ++ case 2417000: ch = 2; break; \ ++ case 2422000: ch = 3; break; \ ++ case 2427000: ch = 4; break; \ ++ case 2432000: ch = 5; break; \ ++ case 2437000: ch = 6; break; \ ++ case 2442000: ch = 7; break; \ ++ case 2447000: ch = 8; break; \ ++ case 2452000: ch = 9; break; \ ++ case 2457000: ch = 10; break; \ ++ case 2462000: ch = 11; break; \ ++ case 2467000: ch = 12; break; \ ++ case 2472000: ch = 13; break; \ ++ case 2484000: ch = 14; break; \ ++ case 5180000: ch = 36; /* UNII */ break; \ ++ case 5200000: ch = 40; /* UNII */ break; \ ++ case 5220000: ch = 44; /* UNII */ break; \ ++ case 5240000: ch = 48; /* UNII */ break; \ ++ case 5260000: ch = 52; /* UNII */ break; \ ++ case 5280000: ch = 56; /* UNII */ break; \ ++ case 5300000: ch = 60; /* UNII */ break; \ ++ case 5320000: ch = 64; /* UNII */ break; \ ++ case 5745000: ch = 149; /* UNII */ break; \ ++ case 5765000: ch = 153; /* UNII */ break; \ ++ case 5785000: ch = 157; /* UNII */ break; \ ++ case 5805000: ch = 161; /* UNII */ break; \ ++ case 5825000: ch = 165; /* UNII */ break; \ ++ case 5500000: ch = 100; /* HiperLAN2 */ break; \ ++ case 5520000: ch = 104; /* HiperLAN2 */ break; \ ++ case 5540000: ch = 108; /* HiperLAN2 */ break; \ ++ case 5560000: ch = 112; /* HiperLAN2 */ break; \ ++ case 5580000: ch = 116; /* HiperLAN2 */ break; \ ++ case 5600000: ch = 120; /* HiperLAN2 */ break; \ ++ case 5620000: ch = 124; /* HiperLAN2 */ break; \ ++ case 5640000: ch = 128; /* HiperLAN2 */ break; \ ++ case 5660000: ch = 132; /* HiperLAN2 */ break; \ ++ case 5680000: ch = 136; /* HiperLAN2 */ break; \ ++ case 5700000: ch = 140; /* HiperLAN2 */ break; \ ++ case 5170000: ch = 34; /* Japan MMAC */ break; \ ++ case 5190000: ch = 38; /* Japan MMAC */ break; \ ++ case 5210000: ch = 42; /* Japan MMAC */ break; \ ++ case 5230000: ch = 46; /* Japan MMAC */ break; \ ++ case 4920000: ch = 184; /* Japan */ break; \ ++ case 4940000: ch = 188; /* Japan */ break; \ ++ case 4960000: ch = 192; /* Japan */ break; \ ++ case 4980000: ch = 196; /* Japan */ break; \ ++ case 5040000: ch = 208; /* Japan, means J08 */ break; \ ++ case 5060000: ch = 212; /* Japan, means J12 */ break; \ ++ case 5080000: ch = 216; /* Japan, means J16 */ break; \ ++ default: ch = 1; break; \ ++ } \ ++ } ++ ++// ++// Common fragment list structure - Identical to the scatter gather frag list structure ++// ++//#define RTMP_SCATTER_GATHER_ELEMENT SCATTER_GATHER_ELEMENT ++//#define PRTMP_SCATTER_GATHER_ELEMENT PSCATTER_GATHER_ELEMENT ++#define NIC_MAX_PHYS_BUF_COUNT 8 ++ ++typedef struct _RTMP_SCATTER_GATHER_ELEMENT { ++ PVOID Address; ++ ULONG Length; ++ PULONG Reserved; ++} RTMP_SCATTER_GATHER_ELEMENT, *PRTMP_SCATTER_GATHER_ELEMENT; ++ ++ ++typedef struct _RTMP_SCATTER_GATHER_LIST { ++ ULONG NumberOfElements; ++ PULONG Reserved; ++ RTMP_SCATTER_GATHER_ELEMENT Elements[NIC_MAX_PHYS_BUF_COUNT]; ++} RTMP_SCATTER_GATHER_LIST, *PRTMP_SCATTER_GATHER_LIST; ++ ++// ++// Some utility macros ++// ++#ifndef min ++#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) ++#endif ++ ++#ifndef max ++#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) ++#endif ++ ++#define GET_LNA_GAIN(_pAd) ((_pAd->LatchRfRegs.Channel <= 14) ? (_pAd->BLNAGain) : ((_pAd->LatchRfRegs.Channel <= 64) ? (_pAd->ALNAGain0) : ((_pAd->LatchRfRegs.Channel <= 128) ? (_pAd->ALNAGain1) : (_pAd->ALNAGain2)))) ++ ++#define INC_COUNTER64(Val) (Val.QuadPart++) ++ ++#define INFRA_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_INFRA_ON)) ++#define ADHOC_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_ADHOC_ON)) ++#define MONITOR_ON(_p) (((_p)->StaCfg.BssType) == BSS_MONITOR) ++#define IDLE_ON(_p) (!INFRA_ON(_p) && !ADHOC_ON(_p)) ++ ++// Check LEAP & CCKM flags ++#define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) ++#define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE)) ++ ++// if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required ++#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \ ++{ \ ++ if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_802_1H; \ ++ if (NdisEqualMemory(IPX, _pBufVA + 12, 2) || \ ++ NdisEqualMemory(APPLE_TALK, _pBufVA + 12, 2)) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ _pExtraLlcSnapEncap = NULL; \ ++ } \ ++} ++ ++// New Define for new Tx Path. ++#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(_pBufVA, _pExtraLlcSnapEncap) \ ++{ \ ++ if (((*(_pBufVA) << 8) + *(_pBufVA + 1)) > 1500) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_802_1H; \ ++ if (NdisEqualMemory(IPX, _pBufVA, 2) || \ ++ NdisEqualMemory(APPLE_TALK, _pBufVA, 2)) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ _pExtraLlcSnapEncap = NULL; \ ++ } \ ++} ++ ++ ++#define MAKE_802_3_HEADER(_p, _pMac1, _pMac2, _pType) \ ++{ \ ++ NdisMoveMemory(_p, _pMac1, MAC_ADDR_LEN); \ ++ NdisMoveMemory((_p + MAC_ADDR_LEN), _pMac2, MAC_ADDR_LEN); \ ++ NdisMoveMemory((_p + MAC_ADDR_LEN * 2), _pType, LENGTH_802_3_TYPE); \ ++} ++ ++// if pData has no LLC/SNAP (neither RFC1042 nor Bridge tunnel), keep it that way. ++// else if the received frame is LLC/SNAP-encaped IPX or APPLETALK, preserve the LLC/SNAP field ++// else remove the LLC/SNAP field from the result Ethernet frame ++// Patch for WHQL only, which did not turn on Netbios but use IPX within its payload ++// Note: ++// _pData & _DataSize may be altered (remove 8-byte LLC/SNAP) by this MACRO ++// _pRemovedLLCSNAP: pointer to removed LLC/SNAP; NULL is not removed ++#define CONVERT_TO_802_3(_p8023hdr, _pDA, _pSA, _pData, _DataSize, _pRemovedLLCSNAP) \ ++{ \ ++ char LLC_Len[2]; \ ++ \ ++ _pRemovedLLCSNAP = NULL; \ ++ if (NdisEqualMemory(SNAP_802_1H, _pData, 6) || \ ++ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, _pData, 6)) \ ++ { \ ++ PUCHAR pProto = _pData + 6; \ ++ \ ++ if ((NdisEqualMemory(IPX, pProto, 2) || NdisEqualMemory(APPLE_TALK, pProto, 2)) && \ ++ NdisEqualMemory(SNAP_802_1H, _pData, 6)) \ ++ { \ ++ LLC_Len[0] = (UCHAR)(_DataSize / 256); \ ++ LLC_Len[1] = (UCHAR)(_DataSize % 256); \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ ++ } \ ++ else \ ++ { \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, pProto); \ ++ _pRemovedLLCSNAP = _pData; \ ++ _DataSize -= LENGTH_802_1_H; \ ++ _pData += LENGTH_802_1_H; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ LLC_Len[0] = (UCHAR)(_DataSize / 256); \ ++ LLC_Len[1] = (UCHAR)(_DataSize % 256); \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ ++ } \ ++} ++ ++#define SWITCH_AB( _pAA, _pBB) \ ++{ \ ++ PVOID pCC; \ ++ pCC = _pBB; \ ++ _pBB = _pAA; \ ++ _pAA = pCC; \ ++} ++ ++// Enqueue this frame to MLME engine ++// We need to enqueue the whole frame because MLME need to pass data type ++// information from 802.11 header ++#ifdef RT2870 ++#define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ ++{ \ ++ UINT32 High32TSF=0, Low32TSF=0; \ ++ MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ ++} ++#endif // RT2870 // ++ ++#define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ ++ NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) ++ ++#define MAC_ADDR_EQUAL(pAddr1,pAddr2) RTMPEqualMemory((PVOID)(pAddr1), (PVOID)(pAddr2), MAC_ADDR_LEN) ++#define SSID_EQUAL(ssid1, len1, ssid2, len2) ((len1==len2) && (RTMPEqualMemory(ssid1, ssid2, len1))) ++ ++// ++// Check if it is Japan W53(ch52,56,60,64) channel. ++// ++#define JapanChannelCheck(channel) ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define STA_PORT_SECURED(_pAd) \ ++{ \ ++ _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ ++ NdisAcquireSpinLock(&_pAd->MacTabLock); \ ++ _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ ++ NdisReleaseSpinLock(&_pAd->MacTabLock); \ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// ++// Register set pair for initialzation register set definition ++// ++typedef struct _RTMP_REG_PAIR ++{ ++ ULONG Register; ++ ULONG Value; ++} RTMP_REG_PAIR, *PRTMP_REG_PAIR; ++ ++typedef struct _REG_PAIR ++{ ++ UCHAR Register; ++ UCHAR Value; ++} REG_PAIR, *PREG_PAIR; ++ ++// ++// Register set pair for initialzation register set definition ++// ++typedef struct _RTMP_RF_REGS ++{ ++ UCHAR Channel; ++ ULONG R1; ++ ULONG R2; ++ ULONG R3; ++ ULONG R4; ++} RTMP_RF_REGS, *PRTMP_RF_REGS; ++ ++typedef struct _FREQUENCY_ITEM { ++ UCHAR Channel; ++ UCHAR N; ++ UCHAR R; ++ UCHAR K; ++} FREQUENCY_ITEM, *PFREQUENCY_ITEM; ++ ++// ++// Data buffer for DMA operation, the buffer must be contiguous physical memory ++// Both DMA to / from CPU use the same structure. ++// ++typedef struct _RTMP_DMABUF ++{ ++ ULONG AllocSize; ++ PVOID AllocVa; // TxBuf virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address ++} RTMP_DMABUF, *PRTMP_DMABUF; ++ ++ ++typedef union _HEADER_802_11_SEQ{ ++#ifdef RT_BIG_ENDIAN ++ struct { ++ USHORT Sequence:12; ++ USHORT Frag:4; ++ } field; ++#else ++ struct { ++ USHORT Frag:4; ++ USHORT Sequence:12; ++ } field; ++#endif ++ USHORT value; ++} HEADER_802_11_SEQ, *PHEADER_802_11_SEQ; ++ ++// ++// Data buffer for DMA operation, the buffer must be contiguous physical memory ++// Both DMA to / from CPU use the same structure. ++// ++typedef struct _RTMP_REORDERBUF ++{ ++ BOOLEAN IsFull; ++ PVOID AllocVa; // TxBuf virtual address ++ UCHAR Header802_3[14]; ++ HEADER_802_11_SEQ Sequence; //support compressed bitmap BA, so no consider fragment in BA ++ UCHAR DataOffset; ++ USHORT Datasize; ++ ULONG AllocSize; ++#ifdef RT2870 ++ PUCHAR AllocPa; ++#endif // RT2870 // ++} RTMP_REORDERBUF, *PRTMP_REORDERBUF; ++ ++// ++// Control block (Descriptor) for all ring descriptor DMA operation, buffer must be ++// contiguous physical memory. NDIS_PACKET stored the binding Rx packet descriptor ++// which won't be released, driver has to wait until upper layer return the packet ++// before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair ++// to describe the packet buffer. For Tx, NDIS_PACKET stored the tx packet descriptor ++// which driver should ACK upper layer when the tx is physically done or failed. ++// ++typedef struct _RTMP_DMACB ++{ ++ ULONG AllocSize; // Control block size ++ PVOID AllocVa; // Control block virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address ++ PNDIS_PACKET pNdisPacket; ++ PNDIS_PACKET pNextNdisPacket; ++ ++ RTMP_DMABUF DmaBuf; // Associated DMA buffer structure ++} RTMP_DMACB, *PRTMP_DMACB; ++ ++typedef struct _RTMP_TX_BUF ++{ ++ PQUEUE_ENTRY Next; ++ UCHAR Index; ++ ULONG AllocSize; // Control block size ++ PVOID AllocVa; // Control block virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address ++} RTMP_TXBUF, *PRTMP_TXBUF; ++ ++typedef struct _RTMP_RX_BUF ++{ ++ BOOLEAN InUse; ++ ULONG ByBaRecIndex; ++ RTMP_REORDERBUF MAP_RXBuf[MAX_RX_REORDERBUF]; ++} RTMP_RXBUF, *PRTMP_RXBUF; ++typedef struct _RTMP_TX_RING ++{ ++ RTMP_DMACB Cell[TX_RING_SIZE]; ++ UINT32 TxCpuIdx; ++ UINT32 TxDmaIdx; ++ UINT32 TxSwFreeIdx; // software next free tx index ++} RTMP_TX_RING, *PRTMP_TX_RING; ++ ++typedef struct _RTMP_RX_RING ++{ ++ RTMP_DMACB Cell[RX_RING_SIZE]; ++ UINT32 RxCpuIdx; ++ UINT32 RxDmaIdx; ++ INT32 RxSwReadIdx; // software next read index ++} RTMP_RX_RING, *PRTMP_RX_RING; ++ ++typedef struct _RTMP_MGMT_RING ++{ ++ RTMP_DMACB Cell[MGMT_RING_SIZE]; ++ UINT32 TxCpuIdx; ++ UINT32 TxDmaIdx; ++ UINT32 TxSwFreeIdx; // software next free tx index ++} RTMP_MGMT_RING, *PRTMP_MGMT_RING; ++ ++// ++// Statistic counter structure ++// ++typedef struct _COUNTER_802_3 ++{ ++ // General Stats ++ ULONG GoodTransmits; ++ ULONG GoodReceives; ++ ULONG TxErrors; ++ ULONG RxErrors; ++ ULONG RxNoBuffer; ++ ++ // Ethernet Stats ++ ULONG RcvAlignmentErrors; ++ ULONG OneCollision; ++ ULONG MoreCollisions; ++ ++} COUNTER_802_3, *PCOUNTER_802_3; ++ ++typedef struct _COUNTER_802_11 { ++ ULONG Length; ++ LARGE_INTEGER LastTransmittedFragmentCount; ++ LARGE_INTEGER TransmittedFragmentCount; ++ LARGE_INTEGER MulticastTransmittedFrameCount; ++ LARGE_INTEGER FailedCount; ++ LARGE_INTEGER RetryCount; ++ LARGE_INTEGER MultipleRetryCount; ++ LARGE_INTEGER RTSSuccessCount; ++ LARGE_INTEGER RTSFailureCount; ++ LARGE_INTEGER ACKFailureCount; ++ LARGE_INTEGER FrameDuplicateCount; ++ LARGE_INTEGER ReceivedFragmentCount; ++ LARGE_INTEGER MulticastReceivedFrameCount; ++ LARGE_INTEGER FCSErrorCount; ++} COUNTER_802_11, *PCOUNTER_802_11; ++ ++typedef struct _COUNTER_RALINK { ++ ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput ++ ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput ++ ULONG BeenDisassociatedCount; ++ ULONG BadCQIAutoRecoveryCount; ++ ULONG PoorCQIRoamingCount; ++ ULONG MgmtRingFullCount; ++ ULONG RxCountSinceLastNULL; ++ ULONG RxCount; ++ ULONG RxRingErrCount; ++ ULONG KickTxCount; ++ ULONG TxRingErrCount; ++ LARGE_INTEGER RealFcsErrCount; ++ ULONG PendingNdisPacketCount; ++ ++ ULONG OneSecOsTxCount[NUM_OF_TX_RING]; ++ ULONG OneSecDmaDoneCount[NUM_OF_TX_RING]; ++ UINT32 OneSecTxDoneCount; ++ ULONG OneSecRxCount; ++ UINT32 OneSecTxAggregationCount; ++ UINT32 OneSecRxAggregationCount; ++ ++ UINT32 OneSecFrameDuplicateCount; ++ ++#ifdef RT2870 ++ ULONG OneSecTransmittedByteCount; // both successful and failure, used to calculate TX throughput ++#endif // RT2870 // ++ ++ UINT32 OneSecTxNoRetryOkCount; ++ UINT32 OneSecTxRetryOkCount; ++ UINT32 OneSecTxFailCount; ++ UINT32 OneSecFalseCCACnt; // CCA error count, for debug purpose, might move to global counter ++ UINT32 OneSecRxOkCnt; // RX without error ++ UINT32 OneSecRxOkDataCnt; // unicast-to-me DATA frame count ++ UINT32 OneSecRxFcsErrCnt; // CRC error ++ UINT32 OneSecBeaconSentCnt; ++ UINT32 LastOneSecTotalTxCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount ++ UINT32 LastOneSecRxOkDataCnt; // OneSecRxOkDataCnt ++ ULONG DuplicateRcv; ++ ULONG TxAggCount; ++ ULONG TxNonAggCount; ++ ULONG TxAgg1MPDUCount; ++ ULONG TxAgg2MPDUCount; ++ ULONG TxAgg3MPDUCount; ++ ULONG TxAgg4MPDUCount; ++ ULONG TxAgg5MPDUCount; ++ ULONG TxAgg6MPDUCount; ++ ULONG TxAgg7MPDUCount; ++ ULONG TxAgg8MPDUCount; ++ ULONG TxAgg9MPDUCount; ++ ULONG TxAgg10MPDUCount; ++ ULONG TxAgg11MPDUCount; ++ ULONG TxAgg12MPDUCount; ++ ULONG TxAgg13MPDUCount; ++ ULONG TxAgg14MPDUCount; ++ ULONG TxAgg15MPDUCount; ++ ULONG TxAgg16MPDUCount; ++ ++ LARGE_INTEGER TransmittedOctetsInAMSDU; ++ LARGE_INTEGER TransmittedAMSDUCount; ++ LARGE_INTEGER ReceivedOctesInAMSDUCount; ++ LARGE_INTEGER ReceivedAMSDUCount; ++ LARGE_INTEGER TransmittedAMPDUCount; ++ LARGE_INTEGER TransmittedMPDUsInAMPDUCount; ++ LARGE_INTEGER TransmittedOctetsInAMPDUCount; ++ LARGE_INTEGER MPDUInReceivedAMPDUCount; ++} COUNTER_RALINK, *PCOUNTER_RALINK; ++ ++typedef struct _PID_COUNTER { ++ ULONG TxAckRequiredCount; // CRC error ++ ULONG TxAggreCount; ++ ULONG TxSuccessCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount ++ ULONG LastSuccessRate; ++} PID_COUNTER, *PPID_COUNTER; ++ ++typedef struct _COUNTER_DRS { ++ // to record the each TX rate's quality. 0 is best, the bigger the worse. ++ USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++ ULONG CurrTxRateStableTime; // # of second in current TX rate ++ BOOLEAN fNoisyEnvironment; ++ BOOLEAN fLastSecAccordingRSSI; ++ UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down ++ UCHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction ++ ULONG LastTxOkCount; ++} COUNTER_DRS, *PCOUNTER_DRS; ++ ++// ++// Arcfour Structure Added by PaulWu ++// ++typedef struct _ARCFOUR ++{ ++ UINT X; ++ UINT Y; ++ UCHAR STATE[256]; ++} ARCFOURCONTEXT, *PARCFOURCONTEXT; ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI too. just copy to TXWI. ++typedef struct _RECEIVE_SETTING { ++#ifdef RT_BIG_ENDIAN ++ USHORT MIMO:1; ++ USHORT OFDM:1; ++ USHORT rsv:3; ++ USHORT STBC:2; //SPACE ++ USHORT ShortGI:1; ++ USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz ++ USHORT NumOfRX:2; // MIMO. WE HAVE 3R ++#else ++ USHORT NumOfRX:2; // MIMO. WE HAVE 3R ++ USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:3; ++ USHORT OFDM:1; ++ USHORT MIMO:1; ++#endif ++ } RECEIVE_SETTING, *PRECEIVE_SETTING; ++ ++// Shared key data structure ++typedef struct _WEP_KEY { ++ UCHAR KeyLen; // Key length for each key, 0: entry is invalid ++ UCHAR Key[MAX_LEN_OF_KEY]; // right now we implement 4 keys, 128 bits max ++} WEP_KEY, *PWEP_KEY; ++ ++typedef struct _CIPHER_KEY { ++ UCHAR Key[16]; // right now we implement 4 keys, 128 bits max ++ UCHAR RxMic[8]; // make alignment ++ UCHAR TxMic[8]; ++ UCHAR TxTsc[6]; // 48bit TSC value ++ UCHAR RxTsc[6]; // 48bit TSC value ++ UCHAR CipherAlg; // 0-none, 1:WEP64, 2:WEP128, 3:TKIP, 4:AES, 5:CKIP64, 6:CKIP128 ++ UCHAR KeyLen; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR BssId[6]; ++#endif // CONFIG_STA_SUPPORT // ++ // Key length for each key, 0: entry is invalid ++ UCHAR Type; // Indicate Pairwise/Group when reporting MIC error ++} CIPHER_KEY, *PCIPHER_KEY; ++ ++typedef struct _BBP_TUNING_STRUCT { ++ BOOLEAN Enable; ++ UCHAR FalseCcaCountUpperBound; // 100 per sec ++ UCHAR FalseCcaCountLowerBound; // 10 per sec ++ UCHAR R17LowerBound; // specified in E2PROM ++ UCHAR R17UpperBound; // 0x68 according to David Tung ++ UCHAR CurrentR17Value; ++} BBP_TUNING, *PBBP_TUNING; ++ ++typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { ++ UCHAR EvaluatePeriod; // 0:not evalute status, 1: evaluate status, 2: switching status ++ UCHAR Pair1PrimaryRxAnt; // 0:Ant-E1, 1:Ant-E2 ++ UCHAR Pair1SecondaryRxAnt; // 0:Ant-E1, 1:Ant-E2 ++ UCHAR Pair2PrimaryRxAnt; // 0:Ant-E3, 1:Ant-E4 ++ UCHAR Pair2SecondaryRxAnt; // 0:Ant-E3, 1:Ant-E4 ++ SHORT Pair1AvgRssi[2]; // AvgRssi[0]:E1, AvgRssi[1]:E2 ++ SHORT Pair2AvgRssi[2]; // AvgRssi[0]:E3, AvgRssi[1]:E4 ++ SHORT Pair1LastAvgRssi; // ++ SHORT Pair2LastAvgRssi; // ++ ULONG RcvPktNumWhenEvaluate; ++ BOOLEAN FirstPktArrivedWhenEvaluate; ++ RALINK_TIMER_STRUCT RxAntDiversityTimer; ++} SOFT_RX_ANT_DIVERSITY, *PSOFT_RX_ANT_DIVERSITY; ++ ++typedef struct _LEAP_AUTH_INFO { ++ BOOLEAN Enabled; //Ture: Enable LEAP Authentication ++ BOOLEAN CCKM; //Ture: Use Fast Reauthentication with CCKM ++ UCHAR Reserve[2]; ++ UCHAR UserName[256]; //LEAP, User name ++ ULONG UserNameLen; ++ UCHAR Password[256]; //LEAP, User Password ++ ULONG PasswordLen; ++} LEAP_AUTH_INFO, *PLEAP_AUTH_INFO; ++ ++typedef struct { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR ErrorCode[2]; //00 01-Invalid authentication type ++ //00 02-Authentication timeout ++ //00 03-Challenge from AP failed ++ //00 04-Challenge to AP failed ++ BOOLEAN Reported; ++} ROGUEAP_ENTRY, *PROGUEAP_ENTRY; ++ ++typedef struct { ++ UCHAR RogueApNr; ++ ROGUEAP_ENTRY RogueApEntry[MAX_LEN_OF_BSS_TABLE]; ++} ROGUEAP_TABLE, *PROGUEAP_TABLE; ++ ++typedef struct { ++ BOOLEAN Enable; ++ UCHAR Delta; ++ BOOLEAN PlusSign; ++} CCK_TX_POWER_CALIBRATE, *PCCK_TX_POWER_CALIBRATE; ++ ++// ++// Receive Tuple Cache Format ++// ++typedef struct _TUPLE_CACHE { ++ BOOLEAN Valid; ++ UCHAR MacAddress[MAC_ADDR_LEN]; ++ USHORT Sequence; ++ USHORT Frag; ++} TUPLE_CACHE, *PTUPLE_CACHE; ++ ++// ++// Fragment Frame structure ++// ++typedef struct _FRAGMENT_FRAME { ++ PNDIS_PACKET pFragPacket; ++ ULONG RxSize; ++ USHORT Sequence; ++ USHORT LastFrag; ++ ULONG Flags; // Some extra frame information. bit 0: LLC presented ++} FRAGMENT_FRAME, *PFRAGMENT_FRAME; ++ ++ ++// ++// Packet information for NdisQueryPacket ++// ++typedef struct _PACKET_INFO { ++ UINT PhysicalBufferCount; // Physical breaks of buffer descripor chained ++ UINT BufferCount ; // Number of Buffer descriptor chained ++ UINT TotalPacketLength ; // Self explained ++ PNDIS_BUFFER pFirstBuffer; // Pointer to first buffer descriptor ++} PACKET_INFO, *PPACKET_INFO; ++ ++// ++// Tkip Key structure which RC4 key & MIC calculation ++// ++typedef struct _TKIP_KEY_INFO { ++ UINT nBytesInM; // # bytes in M for MICKEY ++ ULONG IV16; ++ ULONG IV32; ++ ULONG K0; // for MICKEY Low ++ ULONG K1; // for MICKEY Hig ++ ULONG L; // Current state for MICKEY ++ ULONG R; // Current state for MICKEY ++ ULONG M; // Message accumulator for MICKEY ++ UCHAR RC4KEY[16]; ++ UCHAR MIC[8]; ++} TKIP_KEY_INFO, *PTKIP_KEY_INFO; ++ ++// ++// Private / Misc data, counters for driver internal use ++// ++typedef struct __PRIVATE_STRUC { ++ UINT SystemResetCnt; // System reset counter ++ UINT TxRingFullCnt; // Tx ring full occurrance number ++ UINT PhyRxErrCnt; // PHY Rx error count, for debug purpose, might move to global counter ++ // Variables for WEP encryption / decryption in rtmp_wep.c ++ UINT FCSCRC32; ++ ARCFOURCONTEXT WEPCONTEXT; ++ // Tkip stuff ++ TKIP_KEY_INFO Tx; ++ TKIP_KEY_INFO Rx; ++} PRIVATE_STRUC, *PPRIVATE_STRUC; ++ ++// structure to tune BBP R66 (BBP TUNING) ++typedef struct _BBP_R66_TUNING { ++ BOOLEAN bEnable; ++ USHORT FalseCcaLowerThreshold; // default 100 ++ USHORT FalseCcaUpperThreshold; // default 512 ++ UCHAR R66Delta; ++ UCHAR R66CurrentValue; ++ BOOLEAN R66LowerUpperSelect; //Before LinkUp, Used LowerBound or UpperBound as R66 value. ++} BBP_R66_TUNING, *PBBP_R66_TUNING; ++ ++// structure to store channel TX power ++typedef struct _CHANNEL_TX_POWER { ++ USHORT RemainingTimeForUse; //unit: sec ++ UCHAR Channel; ++#ifdef DOT11N_DRAFT3 ++ BOOLEAN bEffectedChannel; // For BW 40 operating in 2.4GHz , the "effected channel" is the channel that is covered in 40Mhz. ++#endif // DOT11N_DRAFT3 // ++ CHAR Power; ++ CHAR Power2; ++ UCHAR MaxTxPwr; ++ UCHAR DfsReq; ++} CHANNEL_TX_POWER, *PCHANNEL_TX_POWER; ++ ++// structure to store 802.11j channel TX power ++typedef struct _CHANNEL_11J_TX_POWER { ++ UCHAR Channel; ++ UCHAR BW; // BW_10 or BW_20 ++ CHAR Power; ++ CHAR Power2; ++ USHORT RemainingTimeForUse; //unit: sec ++} CHANNEL_11J_TX_POWER, *PCHANNEL_11J_TX_POWER; ++ ++typedef enum _ABGBAND_STATE_ { ++ UNKNOWN_BAND, ++ BG_BAND, ++ A_BAND, ++} ABGBAND_STATE; ++ ++typedef struct _MLME_STRUCT { ++#ifdef CONFIG_STA_SUPPORT ++ // STA state machines ++ STATE_MACHINE CntlMachine; ++ STATE_MACHINE AssocMachine; ++ STATE_MACHINE AuthMachine; ++ STATE_MACHINE AuthRspMachine; ++ STATE_MACHINE SyncMachine; ++ STATE_MACHINE WpaPskMachine; ++ STATE_MACHINE LeapMachine; ++ STATE_MACHINE AironetMachine; ++ STATE_MACHINE_FUNC AssocFunc[ASSOC_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AuthFunc[AUTH_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AuthRspFunc[AUTH_RSP_FUNC_SIZE]; ++ STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE]; ++ STATE_MACHINE_FUNC WpaPskFunc[WPA_PSK_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AironetFunc[AIRONET_FUNC_SIZE]; ++#endif // CONFIG_STA_SUPPORT // ++ STATE_MACHINE_FUNC ActFunc[ACT_FUNC_SIZE]; ++ // Action ++ STATE_MACHINE ActMachine; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ STATE_MACHINE DlsMachine; ++ STATE_MACHINE_FUNC DlsFunc[DLS_FUNC_SIZE]; ++#endif // QOS_DLS_SUPPORT // ++ ++ ++ ++ ++ ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming ++ ULONG Now32; // latch the value of NdisGetSystemUpTime() ++ ULONG LastSendNULLpsmTime; ++ ++ BOOLEAN bRunning; ++ NDIS_SPIN_LOCK TaskLock; ++ MLME_QUEUE Queue; ++ ++ UINT ShiftReg; ++ ++ RALINK_TIMER_STRUCT PeriodicTimer; ++ RALINK_TIMER_STRUCT APSDPeriodicTimer; ++ RALINK_TIMER_STRUCT LinkDownTimer; ++ RALINK_TIMER_STRUCT LinkUpTimer; ++ ULONG PeriodicRound; ++ ULONG OneSecPeriodicRound; ++ ++ UCHAR RealRxPath; ++ BOOLEAN bLowThroughput; ++ BOOLEAN bEnableAutoAntennaCheck; ++ RALINK_TIMER_STRUCT RxAntEvalTimer; ++ ++#ifdef RT2870 ++ UCHAR CaliBW40RfR24; ++ UCHAR CaliBW20RfR24; ++#endif // RT2870 // ++ ++} MLME_STRUCT, *PMLME_STRUCT; ++ ++// structure for radar detection and channel switch ++typedef struct _RADAR_DETECT_STRUCT { ++ //BOOLEAN IEEE80211H; // 0: disable, 1: enable IEEE802.11h ++ UCHAR CSCount; //Channel switch counter ++ UCHAR CSPeriod; //Channel switch period (beacon count) ++ UCHAR RDCount; //Radar detection counter ++ UCHAR RDMode; //Radar Detection mode ++ UCHAR RDDurRegion; //Radar detection duration region ++ UCHAR BBPR16; ++ UCHAR BBPR17; ++ UCHAR BBPR18; ++ UCHAR BBPR21; ++ UCHAR BBPR22; ++ UCHAR BBPR64; ++ ULONG InServiceMonitorCount; // unit: sec ++ UINT8 DfsSessionTime; ++ BOOLEAN bFastDfs; ++ UINT8 ChMovingTime; ++ UINT8 LongPulseRadarTh; ++} RADAR_DETECT_STRUCT, *PRADAR_DETECT_STRUCT; ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++typedef enum CD_STATE_n ++{ ++ CD_NORMAL, ++ CD_SILENCE, ++ CD_MAX_STATE ++} CD_STATE; ++ ++typedef struct CARRIER_DETECTION_s ++{ ++ BOOLEAN Enable; ++ UINT8 CDSessionTime; ++ UINT8 CDPeriod; ++ CD_STATE CD_State; ++} CARRIER_DETECTION, *PCARRIER_DETECTION; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++typedef enum _REC_BLOCKACK_STATUS ++{ ++ Recipient_NONE=0, ++ Recipient_USED, ++ Recipient_HandleRes, ++ Recipient_Accept ++} REC_BLOCKACK_STATUS, *PREC_BLOCKACK_STATUS; ++ ++typedef enum _ORI_BLOCKACK_STATUS ++{ ++ Originator_NONE=0, ++ Originator_USED, ++ Originator_WaitRes, ++ Originator_Done ++} ORI_BLOCKACK_STATUS, *PORI_BLOCKACK_STATUS; ++ ++#ifdef DOT11_N_SUPPORT ++typedef struct _BA_ORI_ENTRY{ ++ UCHAR Wcid; ++ UCHAR TID; ++ UCHAR BAWinSize; ++ UCHAR Token; ++// Sequence is to fill every outgoing QoS DATA frame's sequence field in 802.11 header. ++ USHORT Sequence; ++ USHORT TimeOutValue; ++ ORI_BLOCKACK_STATUS ORI_BA_Status; ++ RALINK_TIMER_STRUCT ORIBATimer; ++ PVOID pAdapter; ++} BA_ORI_ENTRY, *PBA_ORI_ENTRY; ++ ++typedef struct _BA_REC_ENTRY { ++ UCHAR Wcid; ++ UCHAR TID; ++ UCHAR BAWinSize; // 7.3.1.14. each buffer is capable of holding a max AMSDU or MSDU. ++ //UCHAR NumOfRxPkt; ++ //UCHAR Curindidx; // the head in the RX reordering buffer ++ USHORT LastIndSeq; ++// USHORT LastIndSeqAtTimer; ++ USHORT TimeOutValue; ++ RALINK_TIMER_STRUCT RECBATimer; ++ ULONG LastIndSeqAtTimer; ++ ULONG nDropPacket; ++ ULONG rcvSeq; ++ REC_BLOCKACK_STATUS REC_BA_Status; ++// UCHAR RxBufIdxUsed; ++ // corresponding virtual address for RX reordering packet storage. ++ //RTMP_REORDERDMABUF MAP_RXBuf[MAX_RX_REORDERBUF]; ++ NDIS_SPIN_LOCK RxReRingLock; // Rx Ring spinlock ++// struct _BA_REC_ENTRY *pNext; ++ PVOID pAdapter; ++ struct reordering_list list; ++} BA_REC_ENTRY, *PBA_REC_ENTRY; ++ ++ ++typedef struct { ++ ULONG numAsRecipient; // I am recipient of numAsRecipient clients. These client are in the BARecEntry[] ++ ULONG numAsOriginator; // I am originator of numAsOriginator clients. These clients are in the BAOriEntry[] ++ BA_ORI_ENTRY BAOriEntry[MAX_LEN_OF_BA_ORI_TABLE]; ++ BA_REC_ENTRY BARecEntry[MAX_LEN_OF_BA_REC_TABLE]; ++} BA_TABLE, *PBA_TABLE; ++ ++//For QureyBATableOID use; ++typedef struct PACKED _OID_BA_REC_ENTRY{ ++ UCHAR MACAddr[MAC_ADDR_LEN]; ++ UCHAR BaBitmap; // if (BaBitmap&(1<> 3) + 1) /* /8 + 1 */ ++#define WLAN_CT_TIM_BCMC_OFFSET 0 /* unit: 32B */ ++ ++/* clear bcmc TIM bit */ ++#define WLAN_MR_TIM_BCMC_CLEAR(apidx) \ ++ pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] &= ~BIT8[0]; ++ ++/* set bcmc TIM bit */ ++#define WLAN_MR_TIM_BCMC_SET(apidx) \ ++ pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] |= BIT8[0]; ++ ++/* clear a station PS TIM bit */ ++#define WLAN_MR_TIM_BIT_CLEAR(ad_p, apidx, wcid) \ ++ { UCHAR tim_offset = wcid >> 3; \ ++ UCHAR bit_offset = wcid & 0x7; \ ++ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] &= (~BIT8[bit_offset]); } ++ ++/* set a station PS TIM bit */ ++#define WLAN_MR_TIM_BIT_SET(ad_p, apidx, wcid) \ ++ { UCHAR tim_offset = wcid >> 3; \ ++ UCHAR bit_offset = wcid & 0x7; \ ++ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] |= BIT8[bit_offset]; } ++ ++#ifdef RT2870 ++#define BEACON_BITMAP_MASK 0xff ++typedef struct _BEACON_SYNC_STRUCT_ ++{ ++ UCHAR BeaconBuf[HW_BEACON_MAX_COUNT][HW_BEACON_OFFSET]; ++ UCHAR BeaconTxWI[HW_BEACON_MAX_COUNT][TXWI_SIZE]; ++ ULONG TimIELocationInBeacon[HW_BEACON_MAX_COUNT]; ++ ULONG CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT]; ++ BOOLEAN EnableBeacon; // trigger to enable beacon transmission. ++ UCHAR BeaconBitMap; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. ++ UCHAR DtimBitOn; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. ++}BEACON_SYNC_STRUCT; ++#endif // RT2870 // ++ ++typedef struct _MULTISSID_STRUCT { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ USHORT CapabilityInfo; ++ ++ PNET_DEV MSSIDDev; ++ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++ WPA_MIX_PAIR_CIPHER WpaMixPairCipher; ++ ++ ULONG TxCount; ++ ULONG RxCount; ++ ULONG ReceivedByteCount; ++ ULONG TransmittedByteCount; ++ ULONG RxErrorCount; ++ ULONG RxDropCount; ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. this is for reading registry setting only. not useful. ++ BOOLEAN bAutoTxRateSwitch; ++ ++ //CIPHER_KEY SharedKey[SHARE_KEY_NUM]; // ref pAd->SharedKey[BSS][4] ++ UCHAR DefaultKeyId; ++ ++ UCHAR TxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11, ... ++ UCHAR DesiredRates[MAX_LEN_OF_SUPPORTED_RATES];// OID_802_11_DESIRED_RATES ++ UCHAR DesiredRatesIndex; ++ UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ ++// ULONG TimBitmap; // bit0 for broadcast, 1 for AID1, 2 for AID2, ...so on ++// ULONG TimBitmap2; // b0 for AID32, b1 for AID33, ... and so on ++ UCHAR TimBitmaps[WLAN_MAX_NUM_OF_TIM]; ++ ++ // WPA ++ UCHAR GMK[32]; ++ UCHAR PMK[32]; ++ UCHAR GTK[32]; ++ BOOLEAN IEEE8021X; ++ BOOLEAN PreAuth; ++ UCHAR GNonce[32]; ++ UCHAR PortSecured; ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; ++ UCHAR BANClass3Data; ++ ULONG IsolateInterStaTraffic; ++ ++ UCHAR RSNIE_Len[2]; ++ UCHAR RSN_IE[2][MAX_LEN_OF_RSNIE]; ++ ++ ++ UCHAR TimIELocationInBeacon; ++ UCHAR CapabilityInfoLocationInBeacon; ++ // outgoing BEACON frame buffer and corresponding TXWI ++ // PTXWI_STRUC BeaconTxWI; // ++ CHAR BeaconBuf[MAX_BEACON_SIZE]; // NOTE: BeaconBuf should be 4-byte aligned ++ ++ BOOLEAN bHideSsid; ++ UINT16 StationKeepAliveTime; // unit: second ++ ++ USHORT VLAN_VID; ++ USHORT VLAN_Priority; ++ ++ RT_802_11_ACL AccessControlList; ++ ++ // EDCA Qos ++ BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM ++ BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS ++ ++ UCHAR DlsPTK[64]; // Due to windows dirver count on meetinghouse to handle 4-way shake ++ ++ // For 802.1x daemon setting per BSS ++ UCHAR radius_srv_num; ++ RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; ++ ++#ifdef RTL865X_SOC ++ unsigned int mylinkid; ++#endif ++ ++ ++ UINT32 RcvdConflictSsidCount; ++ UINT32 RcvdSpoofedAssocRespCount; ++ UINT32 RcvdSpoofedReassocRespCount; ++ UINT32 RcvdSpoofedProbeRespCount; ++ UINT32 RcvdSpoofedBeaconCount; ++ UINT32 RcvdSpoofedDisassocCount; ++ UINT32 RcvdSpoofedAuthCount; ++ UINT32 RcvdSpoofedDeauthCount; ++ UINT32 RcvdSpoofedUnknownMgmtCount; ++ UINT32 RcvdReplayAttackCount; ++ ++ CHAR RssiOfRcvdConflictSsid; ++ CHAR RssiOfRcvdSpoofedAssocResp; ++ CHAR RssiOfRcvdSpoofedReassocResp; ++ CHAR RssiOfRcvdSpoofedProbeResp; ++ CHAR RssiOfRcvdSpoofedBeacon; ++ CHAR RssiOfRcvdSpoofedDisassoc; ++ CHAR RssiOfRcvdSpoofedAuth; ++ CHAR RssiOfRcvdSpoofedDeauth; ++ CHAR RssiOfRcvdSpoofedUnknownMgmt; ++ CHAR RssiOfRcvdReplayAttack; ++ ++ BOOLEAN bBcnSntReq; ++ UCHAR BcnBufIdx; ++} MULTISSID_STRUCT, *PMULTISSID_STRUCT; ++ ++ ++ ++#ifdef DOT11N_DRAFT3 ++typedef enum _BSS2040COEXIST_FLAG{ ++ BSS_2040_COEXIST_DISABLE = 0, ++ BSS_2040_COEXIST_TIMER_FIRED = 1, ++ BSS_2040_COEXIST_INFO_SYNC = 2, ++ BSS_2040_COEXIST_INFO_NOTIFY = 4, ++}BSS2040COEXIST_FLAG; ++#endif // DOT11N_DRAFT3 // ++ ++// configuration common to OPMODE_AP as well as OPMODE_STA ++typedef struct _COMMON_CONFIG { ++ ++ BOOLEAN bCountryFlag; ++ UCHAR CountryCode[3]; ++ UCHAR Geography; ++ UCHAR CountryRegion; // Enum of country region, 0:FCC, 1:IC, 2:ETSI, 3:SPAIN, 4:France, 5:MKK, 6:MKK1, 7:Israel ++ UCHAR CountryRegionForABand; // Enum of country region for A band ++ UCHAR PhyMode; // PHY_11A, PHY_11B, PHY_11BG_MIXED, PHY_ABG_MIXED ++ USHORT Dsifs; // in units of usec ++ ULONG PacketFilter; // Packet filter for receiving ++ ++ CHAR Ssid[MAX_LEN_OF_SSID]; // NOT NULL-terminated ++ UCHAR SsidLen; // the actual ssid length in used ++ UCHAR LastSsidLen; // the actual ssid length in used ++ CHAR LastSsid[MAX_LEN_OF_SSID]; // NOT NULL-terminated ++ UCHAR LastBssid[MAC_ADDR_LEN]; ++ ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ USHORT BeaconPeriod; ++ UCHAR Channel; ++ UCHAR CentralChannel; // Central Channel when using 40MHz is indicating. not real channel. ++ ++#if 0 // move to STA_ADMIN_CONFIG ++ UCHAR DefaultKeyId; ++ ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++#endif ++ ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen; ++ UCHAR DesireRate[MAX_LEN_OF_SUPPORTED_RATES]; // OID_802_11_DESIRED_RATES ++ UCHAR MaxDesiredRate; ++ UCHAR ExpectedACKRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ ++ ULONG BasicRateBitmap; // backup basic ratebitmap ++ ++ BOOLEAN bAPSDCapable; ++ BOOLEAN bInServicePeriod; ++ BOOLEAN bAPSDAC_BE; ++ BOOLEAN bAPSDAC_BK; ++ BOOLEAN bAPSDAC_VI; ++ BOOLEAN bAPSDAC_VO; ++ BOOLEAN bNeedSendTriggerFrame; ++ BOOLEAN bAPSDForcePowerSave; // Force power save mode, should only use in APSD-STAUT ++ ULONG TriggerTimerCount; ++ UCHAR MaxSPLength; ++ UCHAR BBPCurrentBW; // BW_10, BW_20, BW_40 ++ // move to MULTISSID_STRUCT for MBSS ++ //HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ REG_TRANSMIT_SETTING RegTransmitSetting; //registry transmit setting. this is for reading registry setting only. not useful. ++ //UCHAR FixedTxMode; // Fixed Tx Mode (CCK, OFDM), for HT fixed tx mode (GF, MIX) , refer to RegTransmitSetting.field.HTMode ++ UCHAR TxRate; // Same value to fill in TXD. TxRate is 6-bit ++ UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ UCHAR TxRateIndex; // Tx rate index in RateSwitchTable ++ UCHAR TxRateTableSize; // Valid Tx rate table size in RateSwitchTable ++ //BOOLEAN bAutoTxRateSwitch; ++ UCHAR MinTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ UCHAR RtsRate; // RATE_xxx ++ HTTRANSMIT_SETTING MlmeTransmit; // MGMT frame PHY rate setting when operatin at Ht rate. ++ UCHAR MlmeRate; // RATE_xxx, used to send MLME frames ++ UCHAR BasicMlmeRate; // Default Rate for sending MLME frames ++ ++ USHORT RtsThreshold; // in unit of BYTE ++ USHORT FragmentThreshold; // in unit of BYTE ++ ++ UCHAR TxPower; // in unit of mW ++ ULONG TxPowerPercentage; // 0~100 % ++ ULONG TxPowerDefault; // keep for TxPowerPercentage ++ ++#ifdef DOT11_N_SUPPORT ++ BACAP_STRUC BACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 ++ BACAP_STRUC REGBACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 ++#endif // DOT11_N_SUPPORT // ++ IOT_STRUC IOTestParm; // 802.11n InterOpbility Test Parameter; ++ ULONG TxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto ++ BOOLEAN bUseZeroToDisableFragment; // Microsoft use 0 as disable ++ ULONG UseBGProtection; // 0: auto, 1: always use, 2: always not use ++ BOOLEAN bUseShortSlotTime; // 0: disable, 1 - use short slot (9us) ++ BOOLEAN bEnableTxBurst; // 1: enble TX PACKET BURST, 0: disable TX PACKET BURST ++ BOOLEAN bAggregationCapable; // 1: enable TX aggregation when the peer supports it ++ BOOLEAN bPiggyBackCapable; // 1: enable TX piggy-back according MAC's version ++ BOOLEAN bIEEE80211H; // 1: enable IEEE802.11h spec. ++ ULONG DisableOLBCDetect; // 0: enable OLBC detect; 1 disable OLBC detect ++ ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bRdg; ++#endif // DOT11_N_SUPPORT // ++ BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM ++ QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP ++ EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP ++ QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP ++ UCHAR AckPolicy[4]; // ACK policy of the specified AC. see ACK_xxx ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS ++#endif // CONFIG_STA_SUPPORT // ++ // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular ++ // BOOLEAN control, either ON or OFF. These flags should always be accessed via ++ // OPSTATUS_TEST_FLAG(), OPSTATUS_SET_FLAG(), OP_STATUS_CLEAR_FLAG() macros. ++ // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition ++ ULONG OpStatusFlags; ++ ++ BOOLEAN NdisRadioStateOff; //For HCT 12.0, set this flag to TRUE instead of called MlmeRadioOff. ++ ABGBAND_STATE BandState; // For setting BBP used on B/G or A mode. ++ ++ // IEEE802.11H--DFS. ++ RADAR_DETECT_STRUCT RadarDetect; ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++ CARRIER_DETECTION CarrierDetect; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ UCHAR BASize; // USer desired BAWindowSize. Should not exceed our max capability ++ //RT_HT_CAPABILITY SupportedHtPhy; ++ RT_HT_CAPABILITY DesiredHtPhy; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHTInfo; // Useful as AP. ++ //This IE is used with channel switch announcement element when changing to a new 40MHz. ++ //This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. ++ NEW_EXT_CHAN_IE NewExtChanOffset; //7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present ++ ++#ifdef DOT11N_DRAFT3 ++ UCHAR Bss2040CoexistFlag; // bit 0: bBssCoexistTimerRunning, bit 1: NeedSyncAddHtInfo. ++ RALINK_TIMER_STRUCT Bss2040CoexistTimer; ++ ++ //This IE is used for 20/40 BSS Coexistence. ++ BSS_2040_COEXIST_IE BSS2040CoexistInfo; ++ // ====== 11n D3.0 =======================> ++ USHORT Dot11OBssScanPassiveDwell; // Unit : TU. 5~1000 ++ USHORT Dot11OBssScanActiveDwell; // Unit : TU. 10~1000 ++ USHORT Dot11BssWidthTriggerScanInt; // Unit : Second ++ USHORT Dot11OBssScanPassiveTotalPerChannel; // Unit : TU. 200~10000 ++ USHORT Dot11OBssScanActiveTotalPerChannel; // Unit : TU. 20~10000 ++ USHORT Dot11BssWidthChanTranDelayFactor; ++ USHORT Dot11OBssScanActivityThre; // Unit : percentage ++ ++ ULONG Dot11BssWidthChanTranDelay; // multiple of (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) ++ ULONG CountDownCtr; // CountDown Counter from (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) ++ ++ NDIS_SPIN_LOCK TriggerEventTabLock; ++ BSS_2040_COEXIST_IE LastBSSCoexist2040; ++ BSS_2040_COEXIST_IE BSSCoexist2040; ++ TRIGGER_EVENT_TAB TriggerEventTab; ++ UCHAR ChannelListIdx; ++ // <====== 11n D3.0 ======================= ++ BOOLEAN bOverlapScanning; ++#endif // DOT11N_DRAFT3 // ++ ++ BOOLEAN bHTProtect; ++ BOOLEAN bMIMOPSEnable; ++ BOOLEAN bBADecline; ++ BOOLEAN bDisableReordering; ++ BOOLEAN bForty_Mhz_Intolerant; ++ BOOLEAN bExtChannelSwitchAnnouncement; ++ BOOLEAN bRcvBSSWidthTriggerEvents; ++ ULONG LastRcvBSSWidthTriggerEventsTime; ++ ++ UCHAR TxBASize; ++#endif // DOT11_N_SUPPORT // ++ ++ // Enable wireless event ++ BOOLEAN bWirelessEvent; ++ BOOLEAN bWiFiTest; // Enable this parameter for WiFi test ++ ++ // Tx & Rx Stream number selection ++ UCHAR TxStream; ++ UCHAR RxStream; ++ ++ // transmit phy mode, trasmit rate for Multicast. ++#ifdef MCAST_RATE_SPECIFIC ++ UCHAR McastTransmitMcs; ++ UCHAR McastTransmitPhyMode; ++#endif // MCAST_RATE_SPECIFIC // ++ ++ BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled ++ ++#ifdef RT2870 ++ BOOLEAN bMultipleIRP; // Multiple Bulk IN flag ++ UCHAR NumOfBulkInIRP; // if bMultipleIRP == TRUE, NumOfBulkInIRP will be 4 otherwise be 1 ++ RT_HT_CAPABILITY SupportedHtPhy; ++ ULONG MaxPktOneTxBulk; ++ UCHAR TxBulkFactor; ++ UCHAR RxBulkFactor; ++ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ RALINK_TIMER_STRUCT BeaconUpdateTimer; ++ UINT32 BeaconAdjust; ++ UINT32 BeaconFactor; ++ UINT32 BeaconRemain; ++#endif // RT2870 // ++ ++ ++ NDIS_SPIN_LOCK MeasureReqTabLock; ++ PMEASURE_REQ_TAB pMeasureReqTab; ++ ++ NDIS_SPIN_LOCK TpcReqTabLock; ++ PTPC_REQ_TAB pTpcReqTab; ++ ++ // transmit phy mode, trasmit rate for Multicast. ++#ifdef MCAST_RATE_SPECIFIC ++ HTTRANSMIT_SETTING MCastPhyMode; ++#endif // MCAST_RATE_SPECIFIC // ++ ++#ifdef SINGLE_SKU ++ UINT16 DefineMaxTxPwr; ++#endif // SINGLE_SKU // ++ ++ ++} COMMON_CONFIG, *PCOMMON_CONFIG; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++// STA configuration and status ++typedef struct _STA_ADMIN_CONFIG { ++ // GROUP 1 - ++ // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe ++ // the user intended configuration, but not necessary fully equal to the final ++ // settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either ++ // AP or IBSS holder). ++ // Once initialized, user configuration can only be changed via OID_xxx ++ UCHAR BssType; // BSS_INFRA or BSS_ADHOC ++ USHORT AtimWin; // used when starting a new IBSS ++ ++ // GROUP 2 - ++ // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe ++ // the user intended configuration, and should be always applied to the final ++ // settings in ACTIVE BSS without compromising with the BSS holder. ++ // Once initialized, user configuration can only be changed via OID_xxx ++ UCHAR RssiTrigger; ++ UCHAR RssiTriggerMode; // RSSI_TRIGGERED_UPON_BELOW_THRESHOLD or RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD ++ USHORT DefaultListenCount; // default listen count; ++ ULONG WindowsPowerMode; // Power mode for AC power ++ ULONG WindowsBatteryPowerMode; // Power mode for battery if exists ++ BOOLEAN bWindowsACCAMEnable; // Enable CAM power mode when AC on ++ BOOLEAN bAutoReconnect; // Set to TRUE when setting OID_802_11_SSID with no matching BSSID ++ ULONG WindowsPowerProfile; // Windows power profile, for NDIS5.1 PnP ++ ++ // MIB:ieee802dot11.dot11smt(1).dot11StationConfigTable(1) ++ USHORT Psm; // power management mode (PWR_ACTIVE|PWR_SAVE) ++ USHORT DisassocReason; ++ UCHAR DisassocSta[MAC_ADDR_LEN]; ++ USHORT DeauthReason; ++ UCHAR DeauthSta[MAC_ADDR_LEN]; ++ USHORT AuthFailReason; ++ UCHAR AuthFailSta[MAC_ADDR_LEN]; ++ ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++ ++ UCHAR PMK[32]; // WPA PSK mode PMK ++ UCHAR PTK[64]; // WPA PSK mode PTK ++ UCHAR GTK[32]; // GTK from authenticator ++ BSSID_INFO SavedPMK[PMKID_NO]; ++ UINT SavedPMKNum; // Saved PMKID number ++ ++ UCHAR DefaultKeyId; ++ ++ ++ // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED ++ UCHAR PortSecured; ++ ++ // For WPA countermeasures ++ ULONG LastMicErrorTime; // record last MIC error time ++ ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). ++ BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. ++ // For WPA-PSK supplicant state ++ WPA_STATE WpaState; // Default is SS_NOTUSE and handled by microsoft 802.1x ++ UCHAR ReplayCounter[8]; ++ UCHAR ANonce[32]; // ANonce for WPA-PSK from aurhenticator ++ UCHAR SNonce[32]; // SNonce for WPA-PSK ++ ++ UCHAR LastSNR0; // last received BEACON's SNR ++ UCHAR LastSNR1; // last received BEACON's SNR for 2nd antenna ++ RSSI_SAMPLE RssiSample; ++ ULONG NumOfAvgRssiSample; ++ ++ ULONG LastBeaconRxTime; // OS's timestamp of the last BEACON RX time ++ ULONG Last11bBeaconRxTime; // OS's timestamp of the last 11B BEACON RX time ++ ULONG Last11gBeaconRxTime; // OS's timestamp of the last 11G BEACON RX time ++ ULONG Last20NBeaconRxTime; // OS's timestamp of the last 20MHz N BEACON RX time ++ ++ ULONG LastScanTime; // Record last scan time for issue BSSID_SCAN_LIST ++ ULONG ScanCnt; // Scan counts since most recent SSID, BSSID, SCAN OID request ++ BOOLEAN bSwRadio; // Software controlled Radio On/Off, TRUE: On ++ BOOLEAN bHwRadio; // Hardware controlled Radio On/Off, TRUE: On ++ BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state ++ BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled ++ BOOLEAN bShowHiddenSSID; // Show all known SSID in SSID list get operation ++ ++ ++ // New for WPA, windows want us to to keep association information and ++ // Fixed IEs from last association response ++ NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; ++ USHORT ReqVarIELen; // Length of next VIE include EID & Length ++ UCHAR ReqVarIEs[MAX_VIE_LEN]; // The content saved here should be little-endian format. ++ USHORT ResVarIELen; // Length of next VIE include EID & Length ++ UCHAR ResVarIEs[MAX_VIE_LEN]; ++ ++ UCHAR RSNIE_Len; ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be little-endian format. ++ ++ // New variables used for CCX 1.0 ++ BOOLEAN bCkipOn; ++ BOOLEAN bCkipCmicOn; ++ UCHAR CkipFlag; ++ UCHAR GIV[3]; //for CCX iv ++ UCHAR RxSEQ[4]; ++ UCHAR TxSEQ[4]; ++ UCHAR CKIPMIC[4]; ++ UCHAR LeapAuthMode; ++ LEAP_AUTH_INFO LeapAuthInfo; ++ UCHAR HashPwd[16]; ++ UCHAR NetworkChallenge[8]; ++ UCHAR NetworkChallengeResponse[24]; ++ UCHAR PeerChallenge[8]; ++ ++ UCHAR PeerChallengeResponse[24]; ++ UCHAR SessionKey[16]; //Network session keys (NSK) ++ RALINK_TIMER_STRUCT LeapAuthTimer; ++ ROGUEAP_TABLE RogueApTab; //Cisco CCX1 Rogue AP Detection ++ ++ // New control flags for CCX ++ CCX_CONTROL CCXControl; // Master administration state ++ BOOLEAN CCXEnable; // Actual CCX state ++ UCHAR CCXScanChannel; // Selected channel for CCX beacon request ++ USHORT CCXScanTime; // Time out to wait for beacon and probe response ++ UCHAR CCXReqType; // Current processing CCX request type ++ BSS_TABLE CCXBssTab; // BSS Table ++ UCHAR FrameReportBuf[2048]; // Buffer for creating frame report ++ USHORT FrameReportLen; // Current Frame report length ++ ULONG CLBusyBytes; // Save the total bytes received durning channel load scan time ++ USHORT RPIDensity[8]; // Array for RPI density collection ++ // Start address of each BSS table within FrameReportBuf ++ // It's important to update the RxPower of the corresponding Bss ++ USHORT BssReportOffset[MAX_LEN_OF_BSS_TABLE]; ++ USHORT BeaconToken; // Token for beacon report ++ ULONG LastBssIndex; // Most current reported Bss index ++ RM_REQUEST_ACTION MeasurementRequest[16]; // Saved measurement request ++ UCHAR RMReqCnt; // Number of measurement request saved. ++ UCHAR CurrentRMReqIdx; // Number of measurement request saved. ++ BOOLEAN ParallelReq; // Parallel measurement, only one request performed, ++ // It must be the same channel with maximum duration ++ USHORT ParallelDuration; // Maximum duration for parallel measurement ++ UCHAR ParallelChannel; // Only one channel with parallel measurement ++ USHORT IAPPToken; // IAPP dialog token ++ UCHAR CCXQosECWMin; // Cisco QOS ECWMin for AC 0 ++ UCHAR CCXQosECWMax; // Cisco QOS ECWMax for AC 0 ++ // Hack for channel load and noise histogram parameters ++ UCHAR NHFactor; // Parameter for Noise histogram ++ UCHAR CLFactor; // Parameter for channel load ++ ++ UCHAR KRK[16]; //Key Refresh Key. ++ UCHAR BTK[32]; //Base Transient Key ++ BOOLEAN CCKMLinkUpFlag; ++ ULONG CCKMRN; //(Re)Association request number. ++ LARGE_INTEGER CCKMBeaconAtJoinTimeStamp; //TSF timer for Re-assocaite to the new AP ++ UCHAR AironetCellPowerLimit; //in dBm ++ UCHAR AironetIPAddress[4]; //eg. 192.168.1.1 ++ BOOLEAN CCXAdjacentAPReportFlag; //flag for determining report Assoc Lost time ++ CHAR CCXAdjacentAPSsid[MAX_LEN_OF_SSID]; //Adjacent AP's SSID report ++ UCHAR CCXAdjacentAPSsidLen; // the actual ssid length in used ++ UCHAR CCXAdjacentAPBssid[MAC_ADDR_LEN]; //Adjacent AP's BSSID report ++ USHORT CCXAdjacentAPChannel; ++ ULONG CCXAdjacentAPLinkDownTime; //for Spec S32. ++ ++ RALINK_TIMER_STRUCT StaQuickResponeForRateUpTimer; ++ BOOLEAN StaQuickResponeForRateUpTimerRunning; ++ ++ UCHAR DtimCount; // 0.. DtimPeriod-1 ++ UCHAR DtimPeriod; // default = 3 ++ ++#ifdef QOS_DLS_SUPPORT ++ RT_802_11_DLS DLSEntry[MAX_NUM_OF_DLS_ENTRY]; ++ UCHAR DlsReplayCounter[8]; ++#endif // QOS_DLS_SUPPORT // ++ //////////////////////////////////////////////////////////////////////////////////////// ++ // This is only for WHQL test. ++ BOOLEAN WhqlTest; ++ //////////////////////////////////////////////////////////////////////////////////////// ++ ++ RALINK_TIMER_STRUCT WpaDisassocAndBlockAssocTimer; ++ // Fast Roaming ++ BOOLEAN bFastRoaming; // 0:disable fast roaming, 1:enable fast roaming ++ CHAR dBmToRoam; // the condition to roam when receiving Rssi less than this value. It's negative value. ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ BOOLEAN IEEE8021X; ++ BOOLEAN IEEE8021x_required_keys; ++ CIPHER_KEY DesireSharedKey[4]; // Record user desired WEP keys ++ UCHAR DesireSharedKeyId; ++ ++ // 0: driver ignores wpa_supplicant ++ // 1: wpa_supplicant initiates scanning and AP selection ++ // 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters ++ UCHAR WpaSupplicantUP; ++ UCHAR WpaSupplicantScanCount; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ CHAR dev_name[16]; ++ USHORT OriDevType; ++ ++ BOOLEAN bTGnWifiTest; ++ BOOLEAN bScanReqIsFromWebUI; ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ UCHAR IEEE80211dClientMode; ++ UCHAR StaOriCountryCode[3]; ++ UCHAR StaOriGeography; ++#endif // EXT_BUILD_CHANNEL_LIST // ++} STA_ADMIN_CONFIG, *PSTA_ADMIN_CONFIG; ++ ++// This data structure keep the current active BSS/IBSS's configuration that this STA ++// had agreed upon joining the network. Which means these parameters are usually decided ++// by the BSS/IBSS creator instead of user configuration. Data in this data structurre ++// is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. ++// Normally, after SCAN or failed roaming attempts, we need to recover back to ++// the current active settings. ++typedef struct _STA_ACTIVE_CONFIG { ++ USHORT Aid; ++ USHORT AtimWin; // in kusec; IBSS parameter set element ++ USHORT CapabilityInfo; ++ USHORT CfpMaxDuration; ++ USHORT CfpPeriod; ++ ++ // Copy supported rate from desired AP's beacon. We are trying to match ++ // AP's supported and extended rate settings. ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRateLen; ++ // Copy supported ht from desired AP's beacon. We are trying to match ++ RT_HT_PHY_INFO SupportedPhyInfo; ++ RT_HT_CAPABILITY SupportedHtPhy; ++} STA_ACTIVE_CONFIG, *PSTA_ACTIVE_CONFIG; ++ ++#ifdef RT2870 ++// for USB interface, avoid in interrupt when write key ++typedef struct RT_ADD_PAIRWISE_KEY_ENTRY { ++ NDIS_802_11_MAC_ADDRESS MacAddr; ++ USHORT MacTabMatchWCID; // ASIC ++ CIPHER_KEY CipherKey; ++} RT_ADD_PAIRWISE_KEY_ENTRY,*PRT_ADD_PAIRWISE_KEY_ENTRY; ++#endif // RT2870 // ++#endif // CONFIG_STA_SUPPORT // ++ ++// ----------- start of AP -------------------------- ++// AUTH-RSP State Machine Aux data structure ++typedef struct _AP_MLME_AUX { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Alg; ++ CHAR Challenge[CIPHER_TEXT_LEN]; ++} AP_MLME_AUX, *PAP_MLME_AUX; ++ ++// structure to define WPA Group Key Rekey Interval ++typedef struct PACKED _RT_802_11_WPA_REKEY { ++ ULONG ReKeyMethod; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG ReKeyInterval; // time-based: seconds, packet-based: kilo-packets ++} RT_WPA_REKEY,*PRT_WPA_REKEY, RT_802_11_WPA_REKEY, *PRT_802_11_WPA_REKEY; ++ ++typedef struct _MAC_TABLE_ENTRY { ++ //Choose 1 from ValidAsWDS and ValidAsCLI to validize. ++ BOOLEAN ValidAsCLI; // Sta mode, set this TRUE after Linkup,too. ++ BOOLEAN ValidAsWDS; // This is WDS Entry. only for AP mode. ++ BOOLEAN ValidAsApCli; //This is a AP-Client entry, only for AP mode which enable AP-Client functions. ++ BOOLEAN ValidAsMesh; ++ BOOLEAN ValidAsDls; // This is DLS Entry. only for STA mode. ++ BOOLEAN isCached; ++ BOOLEAN bIAmBadAtheros; // Flag if this is Atheros chip that has IOT problem. We need to turn on RTS/CTS protection. ++ ++ UCHAR EnqueueEapolStartTimerRunning; // Enqueue EAPoL-Start for triggering EAP SM ++ //jan for wpa ++ // record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB ++ UCHAR CMTimerRunning; ++ UCHAR apidx; // MBSS number ++ UCHAR RSNIE_Len; ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; ++ UCHAR ANonce[LEN_KEY_DESC_NONCE]; ++ UCHAR R_Counter[LEN_KEY_DESC_REPLAY]; ++ UCHAR PTK[64]; ++ UCHAR ReTryCounter; ++ RALINK_TIMER_STRUCT RetryTimer; ++ RALINK_TIMER_STRUCT EnqueueStartForPSKTimer; // A timer which enqueue EAPoL-Start for triggering PSK SM ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ AP_WPA_STATE WpaState; ++ GTK_STATE GTKState; ++ USHORT PortSecured; ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ CIPHER_KEY PairwiseKey; ++ PVOID pAd; ++ INT PMKID_CacheIdx; ++ UCHAR PMKID[LEN_PMKID]; ++ ++ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR PsMode; ++ SST Sst; ++ AUTH_STATE AuthState; // for SHARED KEY authentication state machine used only ++ BOOLEAN IsReassocSta; // Indicate whether this is a reassociation procedure ++ USHORT Aid; ++ USHORT CapabilityInfo; ++ UCHAR LastRssi; ++ ULONG NoDataIdleCount; ++ UINT16 StationKeepAliveCount; // unit: second ++ ULONG PsQIdleCount; ++ QUEUE_HEADER PsQueue; ++ ++ UINT32 StaConnectTime; // the live time of this station since associated with AP ++ ++ ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bSendBAR; ++ USHORT NoBADataCountDown; ++ ++ UINT32 CachedBuf[16]; // UINT (4 bytes) for alignment ++ UINT TxBFCount; // 3*3 ++#endif // DOT11_N_SUPPORT // ++ UINT FIFOCount; ++ UINT DebugFIFOCount; ++ UINT DebugTxCount; ++ BOOLEAN bDlsInit; ++ ++ ++//==================================================== ++//WDS entry needs these ++// rt2860 add this. if ValidAsWDS==TRUE, MatchWDSTabIdx is the index in WdsTab.MacTab ++ UINT MatchWDSTabIdx; ++ UCHAR MaxSupportedRate; ++ UCHAR CurrTxRate; ++ UCHAR CurrTxRateIndex; ++ // to record the each TX rate's quality. 0 is best, the bigger the worse. ++ USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; ++// USHORT OneSecTxOkCount; ++ UINT32 OneSecTxNoRetryOkCount; ++ UINT32 OneSecTxRetryOkCount; ++ UINT32 OneSecTxFailCount; ++ UINT32 ContinueTxFailCnt; ++ UINT32 CurrTxRateStableTime; // # of second in current TX rate ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++//==================================================== ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ UINT MatchDlsEntryIdx; // indicate the index in pAd->StaCfg.DLSEntry ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ BOOLEAN fNoisyEnvironment; ++ BOOLEAN fLastSecAccordingRSSI; ++ UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down ++ CHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction ++ ULONG LastTxOkCount; ++ UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; ++ ++ // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular ++ // BOOLEAN control, either ON or OFF. These flags should always be accessed via ++ // CLIENT_STATUS_TEST_FLAG(), CLIENT_STATUS_SET_FLAG(), CLIENT_STATUS_CLEAR_FLAG() macros. ++ // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition. fCLIENT_STATUS_AMSDU_INUSED ++ ULONG ClientStatusFlags; ++ ++ // TODO: Shall we move that to DOT11_N_SUPPORT??? ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ ++#ifdef DOT11_N_SUPPORT ++ // HT EWC MIMO-N used parameters ++ USHORT RXBAbitmap; // fill to on-chip RXWI_BA_BITMASK in 8.1.3RX attribute entry format ++ USHORT TXBAbitmap; // This bitmap as originator, only keep in software used to mark AMPDU bit in TXWI ++ USHORT TXAutoBAbitmap; ++ USHORT BADeclineBitmap; ++ USHORT BARecWcidArray[NUM_OF_TID]; // The mapping wcid of recipient session. if RXBAbitmap bit is masked ++ USHORT BAOriWcidArray[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked ++ USHORT BAOriSequence[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked ++ ++ // 802.11n features. ++ UCHAR MpduDensity; ++ UCHAR MaxRAmpduFactor; ++ UCHAR AMsduSize; ++ UCHAR MmpsMode; // MIMO power save more. ++ ++ HT_CAPABILITY_IE HTCapability; ++ ++#ifdef DOT11N_DRAFT3 ++ UCHAR BSS2040CoexistenceMgmtSupport; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ BOOLEAN bAutoTxRateSwitch; ++ ++ UCHAR RateLen; ++ struct _MAC_TABLE_ENTRY *pNext; ++ USHORT TxSeq[NUM_OF_TID]; ++ USHORT NonQosDataSeq; ++ ++ RSSI_SAMPLE RssiSample; ++ ++ UINT32 TXMCSExpected[16]; ++ UINT32 TXMCSSuccessful[16]; ++ UINT32 TXMCSFailed[16]; ++ UINT32 TXMCSAutoFallBack[16][16]; ++ ++#ifdef CONFIG_STA_SUPPORT ++ ULONG LastBeaconRxTime; ++#endif // CONFIG_STA_SUPPORT // ++} MAC_TABLE_ENTRY, *PMAC_TABLE_ENTRY; ++ ++typedef struct _MAC_TABLE { ++ USHORT Size; ++ MAC_TABLE_ENTRY *Hash[HASH_TABLE_SIZE]; ++ MAC_TABLE_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; ++ QUEUE_HEADER McastPsQueue; ++ ULONG PsQIdleCount; ++ BOOLEAN fAnyStationInPsm; ++ BOOLEAN fAnyStationBadAtheros; // Check if any Station is atheros 802.11n Chip. We need to use RTS/CTS with Atheros 802,.11n chip. ++ BOOLEAN fAnyTxOPForceDisable; // Check if it is necessary to disable BE TxOP ++ BOOLEAN fAllStationAsRalink; // Check if all stations are ralink-chipset ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN fAnyStationIsLegacy; // Check if I use legacy rate to transmit to my BSS Station/ ++ BOOLEAN fAnyStationNonGF; // Check if any Station can't support GF. ++ BOOLEAN fAnyStation20Only; // Check if any Station can't support GF. ++ BOOLEAN fAnyStationMIMOPSDynamic; // Check if any Station is MIMO Dynamic ++ BOOLEAN fAnyBASession; // Check if there is BA session. Force turn on RTS/CTS ++#endif // DOT11_N_SUPPORT // ++} MAC_TABLE, *PMAC_TABLE; ++ ++#ifdef DOT11_N_SUPPORT ++#define IS_HT_STA(_pMacEntry) \ ++ (_pMacEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) ++ ++#define IS_HT_RATE(_pMacEntry) \ ++ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++ ++#define PEER_IS_HT_RATE(_pMacEntry) \ ++ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++#endif // DOT11_N_SUPPORT // ++ ++typedef struct _WDS_ENTRY { ++ BOOLEAN Valid; ++ UCHAR Addr[MAC_ADDR_LEN]; ++ ULONG NoDataIdleCount; ++ struct _WDS_ENTRY *pNext; ++} WDS_ENTRY, *PWDS_ENTRY; ++ ++typedef struct _WDS_TABLE_ENTRY { ++ USHORT Size; ++ UCHAR WdsAddr[MAC_ADDR_LEN]; ++ WDS_ENTRY *Hash[HASH_TABLE_SIZE]; ++ WDS_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; ++ UCHAR MaxSupportedRate; ++ UCHAR CurrTxRate; ++ USHORT TxQuality[MAX_LEN_OF_SUPPORTED_RATES]; ++ USHORT OneSecTxOkCount; ++ USHORT OneSecTxRetryOkCount; ++ USHORT OneSecTxFailCount; ++ ULONG CurrTxRateStableTime; // # of second in current TX rate ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++} WDS_TABLE_ENTRY, *PWDS_TABLE_ENTRY; ++ ++typedef struct _RT_802_11_WDS_ENTRY { ++ PNET_DEV dev; ++ UCHAR Valid; ++ UCHAR PhyMode; ++ UCHAR PeerWdsAddr[MAC_ADDR_LEN]; ++ UCHAR MacTabMatchWCID; // ASIC ++ NDIS_802_11_WEP_STATUS WepStatus; ++ UCHAR KeyIdx; ++ CIPHER_KEY WdsKey; ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. ++} RT_802_11_WDS_ENTRY, *PRT_802_11_WDS_ENTRY; ++ ++typedef struct _WDS_TABLE { ++ UCHAR Mode; ++ ULONG Size; ++ RT_802_11_WDS_ENTRY WdsEntry[MAX_WDS_ENTRY]; ++} WDS_TABLE, *PWDS_TABLE; ++ ++typedef struct _APCLI_STRUCT { ++ PNET_DEV dev; ++#ifdef RTL865X_SOC ++ unsigned int mylinkid; ++#endif ++ BOOLEAN Enable; // Set it as 1 if the apcli interface was configured to "1" or by iwpriv cmd "ApCliEnable" ++ BOOLEAN Valid; // Set it as 1 if the apcli interface associated success to remote AP. ++ UCHAR MacTabWCID; //WCID value, which point to the entry of ASIC Mac table. ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ ++ UCHAR CfgSsidLen; ++ CHAR CfgSsid[MAX_LEN_OF_SSID]; ++ UCHAR CfgApCliBssid[ETH_LENGTH_OF_ADDRESS]; ++ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS]; ++ ++ ULONG ApCliRcvBeaconTime; ++ ++ ULONG CtrlCurrState; ++ ULONG SyncCurrState; ++ ULONG AuthCurrState; ++ ULONG AssocCurrState; ++ ULONG WpaPskCurrState; ++ ++ USHORT AuthReqCnt; ++ USHORT AssocReqCnt; ++ ++ ULONG ClientStatusFlags; ++ UCHAR MpduDensity; ++ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ UCHAR PSK[100]; // reserve PSK key material ++ UCHAR PSKLen; ++ UCHAR PMK[32]; // WPA PSK mode PMK ++ //UCHAR PTK[64]; // WPA PSK mode PTK ++ UCHAR GTK[32]; // GTK from authenticator ++ ++ //CIPHER_KEY PairwiseKey; ++ CIPHER_KEY SharedKey[SHARE_KEY_NUM]; ++ UCHAR DefaultKeyId; ++ ++ // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED ++ //UCHAR PortSecured; ++ ++ // store RSN_IE built by driver ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be convert to little-endian format. ++ UCHAR RSNIE_Len; ++ ++ // For WPA countermeasures ++ ULONG LastMicErrorTime; // record last MIC error time ++ //ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). ++ BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. ++ ++ // For WPA-PSK supplicant state ++ //WPA_STATE WpaState; // Default is SS_NOTUSE ++ //UCHAR ReplayCounter[8]; ++ //UCHAR ANonce[32]; // ANonce for WPA-PSK from authenticator ++ UCHAR SNonce[32]; // SNonce for WPA-PSK ++ UCHAR GNonce[32]; // GNonce for WPA-PSK from authenticator ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. ++} APCLI_STRUCT, *PAPCLI_STRUCT; ++ ++// ----------- end of AP ---------------------------- ++ ++#ifdef BLOCK_NET_IF ++typedef struct _BLOCK_QUEUE_ENTRY ++{ ++ BOOLEAN SwTxQueueBlockFlag; ++ LIST_HEADER NetIfList; ++} BLOCK_QUEUE_ENTRY, *PBLOCK_QUEUE_ENTRY; ++#endif // BLOCK_NET_IF // ++ ++struct wificonf ++{ ++ BOOLEAN bShortGI; ++ BOOLEAN bGreenField; ++}; ++ ++ ++ ++typedef struct _INF_PCI_CONFIG ++{ ++ PUCHAR CSRBaseAddress; // PCI MMIO Base Address, all access will use ++}INF_PCI_CONFIG; ++ ++typedef struct _INF_USB_CONFIG ++{ ++ UINT BulkInEpAddr; // bulk-in endpoint address ++ UINT BulkOutEpAddr[6]; // bulk-out endpoint address ++ ++}INF_USB_CONFIG; ++ ++#ifdef IKANOS_VX_1X0 ++ typedef void (*IkanosWlanTxCbFuncP)(void *, void *); ++ ++ struct IKANOS_TX_INFO ++ { ++ struct net_device *netdev; ++ IkanosWlanTxCbFuncP *fp; ++ }; ++#endif // IKANOS_VX_1X0 // ++ ++#ifdef NINTENDO_AP ++typedef struct _NINDO_CTRL_BLOCK { ++ ++ RT_NINTENDO_TABLE DS_TABLE; ++ ++#ifdef CHIP25XX ++ spinlock_t NINTENDO_TABLE_Lock; ++#else ++ NDIS_SPIN_LOCK NINTENDO_TABLE_Lock; ++#endif // CHIP25XX // ++ ++ UCHAR NINTENDO_UP_BUFFER[512]; ++ UCHAR Local_KeyIdx; ++ CIPHER_KEY Local_SharedKey; ++ UCHAR Local_bHideSsid; ++ UCHAR Local_AuthMode; ++ UCHAR Local_WepStatus; ++ USHORT Local_CapabilityInfo; ++} NINDO_CTRL_BLOCK; ++#endif // NINTENDO_AP // ++ ++ ++#ifdef DBG_DIAGNOSE ++#define DIAGNOSE_TIME 10 // 10 sec ++typedef struct _RtmpDiagStrcut_ ++{ // Diagnosis Related element ++ unsigned char inited; ++ unsigned char qIdx; ++ unsigned char ArrayStartIdx; ++ unsigned char ArrayCurIdx; ++ // Tx Related Count ++ USHORT TxDataCnt[DIAGNOSE_TIME]; ++ USHORT TxFailCnt[DIAGNOSE_TIME]; ++// USHORT TxDescCnt[DIAGNOSE_TIME][16]; // TxDesc queue length in scale of 0~14, >=15 ++ USHORT TxDescCnt[DIAGNOSE_TIME][24]; // 3*3 // TxDesc queue length in scale of 0~14, >=15 ++// USHORT TxMcsCnt[DIAGNOSE_TIME][16]; // TxDate MCS Count in range from 0 to 15, step in 1. ++ USHORT TxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 ++ USHORT TxSWQueCnt[DIAGNOSE_TIME][9]; // TxSwQueue length in scale of 0, 1, 2, 3, 4, 5, 6, 7, >=8 ++ ++ USHORT TxAggCnt[DIAGNOSE_TIME]; ++ USHORT TxNonAggCnt[DIAGNOSE_TIME]; ++// USHORT TxAMPDUCnt[DIAGNOSE_TIME][16]; // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. ++ USHORT TxAMPDUCnt[DIAGNOSE_TIME][24]; // 3*3 // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. ++ USHORT TxRalinkCnt[DIAGNOSE_TIME]; // TxRalink Aggregation Count in 1 sec scale. ++ USHORT TxAMSDUCnt[DIAGNOSE_TIME]; // TxAMSUD Aggregation Count in 1 sec scale. ++ ++ // Rx Related Count ++ USHORT RxDataCnt[DIAGNOSE_TIME]; // Rx Total Data count. ++ USHORT RxCrcErrCnt[DIAGNOSE_TIME]; ++// USHORT RxMcsCnt[DIAGNOSE_TIME][16]; // Rx MCS Count in range from 0 to 15, step in 1. ++ USHORT RxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 ++}RtmpDiagStruct; ++#endif // DBG_DIAGNOSE // ++ ++ ++// ++// The miniport adapter structure ++// ++typedef struct _RTMP_ADAPTER ++{ ++ PVOID OS_Cookie; // save specific structure relative to OS ++ PNET_DEV net_dev; ++ ULONG VirtualIfCnt; ++ ++ ++ ++ NDIS_SPIN_LOCK irq_lock; ++ UCHAR irq_disabled; ++ ++#ifdef RT2870 ++/*****************************************************************************************/ ++/* USB related parameters */ ++/*****************************************************************************************/ ++ struct usb_config_descriptor *config; ++ UINT BulkInEpAddr; // bulk-in endpoint address ++ UINT BulkOutEpAddr[6]; // bulk-out endpoint address ++ ++ UINT NumberOfPipes; ++ USHORT BulkOutMaxPacketSize; ++ USHORT BulkInMaxPacketSize; ++ ++ //======Control Flags ++ LONG PendingIoCount; ++ ULONG BulkFlags; ++ BOOLEAN bUsbTxBulkAggre; // Flags for bulk out data priority ++ ++ ++ //======Timer Thread ++ RT2870_TIMER_QUEUE TimerQ; ++ NDIS_SPIN_LOCK TimerQLock; ++ ++ ++ //======Cmd Thread ++ CmdQ CmdQ; ++ NDIS_SPIN_LOCK CmdQLock; // CmdQLock spinlock ++ ++ BOOLEAN TimerFunc_kill; ++ BOOLEAN mlme_kill; ++ ++ ++ //======Semaphores (event) ++ struct semaphore mlme_semaphore; /* to sleep thread on */ ++ struct semaphore RTUSBCmd_semaphore; /* to sleep thread on */ ++ struct semaphore RTUSBTimer_semaphore; ++#ifdef INF_AMAZON_SE ++ struct semaphore UsbVendorReq_semaphore; ++ PVOID UsbVendorReqBuf; ++#endif // INF_AMAZON_SE // ++ struct completion TimerQComplete; ++ struct completion mlmeComplete; ++ struct completion CmdQComplete; ++ wait_queue_head_t *wait; ++ ++ //======Lock for 2870 ATE ++#ifdef RALINK_ATE ++ NDIS_SPIN_LOCK GenericLock; // ATE Tx/Rx generic spinlock ++#endif // RALINK_ATE // ++ ++#endif // RT2870 // ++ ++ ++/*****************************************************************************************/ ++ /* Both PCI/USB related parameters */ ++/*****************************************************************************************/ ++ ++ ++/*****************************************************************************************/ ++/* Tx related parameters */ ++/*****************************************************************************************/ ++ BOOLEAN DeQueueRunning[NUM_OF_TX_RING]; // for ensuring RTUSBDeQueuePacket get call once ++ NDIS_SPIN_LOCK DeQueueLock[NUM_OF_TX_RING]; ++ ++#ifdef RT2870 ++ // Data related context and AC specified, 4 AC supported ++ NDIS_SPIN_LOCK BulkOutLock[6]; // BulkOut spinlock for 4 ACs ++ NDIS_SPIN_LOCK MLMEBulkOutLock; // MLME BulkOut lock ++ ++ HT_TX_CONTEXT TxContext[NUM_OF_TX_RING]; ++ NDIS_SPIN_LOCK TxContextQueueLock[NUM_OF_TX_RING]; // TxContextQueue spinlock ++ ++ // 4 sets of Bulk Out index and pending flag ++ UCHAR NextBulkOutIndex[4]; // only used for 4 EDCA bulkout pipe ++ ++ BOOLEAN BulkOutPending[6]; // used for total 6 bulkout pipe ++ UCHAR bulkResetPipeid; ++ BOOLEAN MgmtBulkPending; ++ ULONG bulkResetReq[6]; ++#endif // RT2870 // ++ ++ // resource for software backlog queues ++ QUEUE_HEADER TxSwQueue[NUM_OF_TX_RING]; // 4 AC + 1 HCCA ++ NDIS_SPIN_LOCK TxSwQueueLock[NUM_OF_TX_RING]; // TxSwQueue spinlock ++ ++ RTMP_DMABUF MgmtDescRing; // Shared memory for MGMT descriptors ++ RTMP_MGMT_RING MgmtRing; ++ NDIS_SPIN_LOCK MgmtRingLock; // Prio Ring spinlock ++ ++ ++/*****************************************************************************************/ ++/* Rx related parameters */ ++/*****************************************************************************************/ ++ ++ ++#ifdef RT2870 ++ RX_CONTEXT RxContext[RX_RING_SIZE]; // 1 for redundant multiple IRP bulk in. ++ NDIS_SPIN_LOCK BulkInLock; // BulkIn spinlock for 4 ACs ++ UCHAR PendingRx; // The Maxima pending Rx value should be RX_RING_SIZE. ++ UCHAR NextRxBulkInIndex; // Indicate the current RxContext Index which hold by Host controller. ++ UCHAR NextRxBulkInReadIndex; // Indicate the current RxContext Index which driver can read & process it. ++ ULONG NextRxBulkInPosition; // Want to contatenate 2 URB buffer while 1st is bulkin failed URB. This Position is 1st URB TransferLength. ++ ULONG TransferBufferLength; // current length of the packet buffer ++ ULONG ReadPosition; // current read position in a packet buffer ++#endif // RT2870 // ++ ++ ++/*****************************************************************************************/ ++/* ASIC related parameters */ ++/*****************************************************************************************/ ++ UINT32 MACVersion; // MAC version. Record rt2860C(0x28600100) or rt2860D (0x28600101).. ++ ++ // --------------------------- ++ // E2PROM ++ // --------------------------- ++ ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused ++ UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 ++ USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; ++ ULONG FirmwareVersion; // byte 0: Minor version, byte 1: Major version, otherwise unused. ++ ++ // --------------------------- ++ // BBP Control ++ // --------------------------- ++ UCHAR BbpWriteLatch[140]; // record last BBP register value written via BBP_IO_WRITE/BBP_IO_WRITE_VY_REG_ID ++ UCHAR BbpRssiToDbmDelta; ++ BBP_R66_TUNING BbpTuning; ++ ++ // ---------------------------- ++ // RFIC control ++ // ---------------------------- ++ UCHAR RfIcType; // RFIC_xxx ++ ULONG RfFreqOffset; // Frequency offset for channel switching ++ RTMP_RF_REGS LatchRfRegs; // latch th latest RF programming value since RF IC doesn't support READ ++ ++ EEPROM_ANTENNA_STRUC Antenna; // Since ANtenna definition is different for a & g. We need to save it for future reference. ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ ++ // This soft Rx Antenna Diversity mechanism is used only when user set ++ // RX Antenna = DIVERSITY ON ++ SOFT_RX_ANT_DIVERSITY RxAnt; ++ ++ UCHAR RFProgSeq; ++ CHANNEL_TX_POWER TxPower[MAX_NUM_OF_CHANNELS]; // Store Tx power value for all channels. ++ CHANNEL_TX_POWER ChannelList[MAX_NUM_OF_CHANNELS]; // list all supported channels for site survey ++ CHANNEL_11J_TX_POWER TxPower11J[MAX_NUM_OF_11JCHANNELS]; // 802.11j channel and bw ++ CHANNEL_11J_TX_POWER ChannelList11J[MAX_NUM_OF_11JCHANNELS]; // list all supported channels for site survey ++ ++ UCHAR ChannelListNum; // number of channel in ChannelList[] ++ UCHAR Bbp94; ++ BOOLEAN BbpForCCK; ++ ULONG Tx20MPwrCfgABand[5]; ++ ULONG Tx20MPwrCfgGBand[5]; ++ ULONG Tx40MPwrCfgABand[5]; ++ ULONG Tx40MPwrCfgGBand[5]; ++ ++ BOOLEAN bAutoTxAgcA; // Enable driver auto Tx Agc control ++ UCHAR TssiRefA; // Store Tssi reference value as 25 temperature. ++ UCHAR TssiPlusBoundaryA[5]; // Tssi boundary for increase Tx power to compensate. ++ UCHAR TssiMinusBoundaryA[5]; // Tssi boundary for decrease Tx power to compensate. ++ UCHAR TxAgcStepA; // Store Tx TSSI delta increment / decrement value ++ CHAR TxAgcCompensateA; // Store the compensation (TxAgcStep * (idx-1)) ++ ++ BOOLEAN bAutoTxAgcG; // Enable driver auto Tx Agc control ++ UCHAR TssiRefG; // Store Tssi reference value as 25 temperature. ++ UCHAR TssiPlusBoundaryG[5]; // Tssi boundary for increase Tx power to compensate. ++ UCHAR TssiMinusBoundaryG[5]; // Tssi boundary for decrease Tx power to compensate. ++ UCHAR TxAgcStepG; // Store Tx TSSI delta increment / decrement value ++ CHAR TxAgcCompensateG; // Store the compensation (TxAgcStep * (idx-1)) ++ ++ //+++For RT2870, the parameteres is start from BGRssiOffset1 ~ BGRssiOffset3 ++ CHAR BGRssiOffset0; // Store B/G RSSI#0 Offset value on EEPROM 0x46h ++ CHAR BGRssiOffset1; // Store B/G RSSI#1 Offset value ++ CHAR BGRssiOffset2; // Store B/G RSSI#2 Offset value ++ //--- ++ ++ //+++For RT2870, the parameteres is start from ARssiOffset1 ~ ARssiOffset3 ++ CHAR ARssiOffset0; // Store A RSSI#0 Offset value on EEPROM 0x4Ah ++ CHAR ARssiOffset1; // Store A RSSI#1 Offset value ++ CHAR ARssiOffset2; // Store A RSSI#2 Offset value ++ //--- ++ ++ CHAR BLNAGain; // Store B/G external LNA#0 value on EEPROM 0x44h ++ CHAR ALNAGain0; // Store A external LNA#0 value for ch36~64 ++ CHAR ALNAGain1; // Store A external LNA#1 value for ch100~128 ++ CHAR ALNAGain2; // Store A external LNA#2 value for ch132~165 ++ ++ // ---------------------------- ++ // LED control ++ // ---------------------------- ++ MCU_LEDCS_STRUC LedCntl; ++ USHORT Led1; // read from EEPROM 0x3c ++ USHORT Led2; // EEPROM 0x3e ++ USHORT Led3; // EEPROM 0x40 ++ UCHAR LedIndicatorStregth; ++ UCHAR RssiSingalstrengthOffet; ++ BOOLEAN bLedOnScanning; ++ UCHAR LedStatus; ++ ++/*****************************************************************************************/ ++/* 802.11 related parameters */ ++/*****************************************************************************************/ ++ // outgoing BEACON frame buffer and corresponding TXD ++ TXWI_STRUC BeaconTxWI; ++ PUCHAR BeaconBuf; ++ USHORT BeaconOffset[HW_BEACON_MAX_COUNT]; ++ ++ // pre-build PS-POLL and NULL frame upon link up. for efficiency purpose. ++ PSPOLL_FRAME PsPollFrame; ++ HEADER_802_11 NullFrame; ++ ++#ifdef RT2870 ++ TX_CONTEXT BeaconContext[BEACON_RING_SIZE]; ++ TX_CONTEXT NullContext; ++ TX_CONTEXT PsPollContext; ++ TX_CONTEXT RTSContext; ++#endif // RT2870 // ++ ++ ++ ++//=========AP=========== ++ ++ ++//=======STA=========== ++#ifdef CONFIG_STA_SUPPORT ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++ // ----------------------------------------------- ++ // STA specific configuration & operation status ++ // used only when pAd->OpMode == OPMODE_STA ++ // ----------------------------------------------- ++ STA_ADMIN_CONFIG StaCfg; // user desired settings ++ STA_ACTIVE_CONFIG StaActive; // valid only when ADHOC_ON(pAd) || INFRA_ON(pAd) ++ CHAR nickname[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f ++ NDIS_MEDIA_STATE PreMediaState; ++#endif // CONFIG_STA_SUPPORT // ++ ++//=======Common=========== ++ // OP mode: either AP or STA ++ UCHAR OpMode; // OPMODE_STA, OPMODE_AP ++ ++ NDIS_MEDIA_STATE IndicateMediaState; // Base on Indication state, default is NdisMediaStateDisConnected ++ ++ ++ // configuration: read from Registry & E2PROM ++ BOOLEAN bLocalAdminMAC; // Use user changed MAC ++ UCHAR PermanentAddress[MAC_ADDR_LEN]; // Factory default MAC address ++ UCHAR CurrentAddress[MAC_ADDR_LEN]; // User changed MAC address ++ ++ // ------------------------------------------------------ ++ // common configuration to both OPMODE_STA and OPMODE_AP ++ // ------------------------------------------------------ ++ COMMON_CONFIG CommonCfg; ++ MLME_STRUCT Mlme; ++ ++ // AP needs those vaiables for site survey feature. ++ MLME_AUX MlmeAux; // temporary settings used during MLME state machine ++ BSS_TABLE ScanTab; // store the latest SCAN result ++ ++ //About MacTab, the sta driver will use #0 and #1 for multicast and AP. ++ MAC_TABLE MacTab; // ASIC on-chip WCID entry table. At TX, ASIC always use key according to this on-chip table. ++ NDIS_SPIN_LOCK MacTabLock; ++ ++#ifdef DOT11_N_SUPPORT ++ BA_TABLE BATable; ++#endif // DOT11_N_SUPPORT // ++ NDIS_SPIN_LOCK BATabLock; ++ RALINK_TIMER_STRUCT RECBATimer; ++ ++ // encryption/decryption KEY tables ++ CIPHER_KEY SharedKey[MAX_MBSSID_NUM][4]; // STA always use SharedKey[BSS0][0..3] ++ ++ // RX re-assembly buffer for fragmentation ++ FRAGMENT_FRAME FragFrame; // Frame storage for fragment frame ++ ++ // various Counters ++ COUNTER_802_3 Counters8023; // 802.3 counters ++ COUNTER_802_11 WlanCounters; // 802.11 MIB counters ++ COUNTER_RALINK RalinkCounters; // Ralink propriety counters ++ COUNTER_DRS DrsCounters; // counters for Dynamic TX Rate Switching ++ PRIVATE_STRUC PrivateInfo; // Private information & counters ++ ++ // flags, see fRTMP_ADAPTER_xxx flags ++ ULONG Flags; // Represent current device status ++ ++ // current TX sequence # ++ USHORT Sequence; ++ ++ // Control disconnect / connect event generation ++ //+++Didn't used anymore ++ ULONG LinkDownTime; ++ //--- ++ ULONG LastRxRate; ++ ULONG LastTxRate; ++ //+++Used only for Station ++ BOOLEAN bConfigChanged; // Config Change flag for the same SSID setting ++ //--- ++ ++ ULONG ExtraInfo; // Extra information for displaying status ++ ULONG SystemErrorBitmap; // b0: E2PROM version error ++ ++ //+++Didn't used anymore ++ ULONG MacIcVersion; // MAC/BBP serial interface issue solved after ver.D ++ //--- ++ ++ // --------------------------- ++ // System event log ++ // --------------------------- ++ RT_802_11_EVENT_TABLE EventTab; ++ ++ ++ BOOLEAN HTCEnable; ++ ++ /*****************************************************************************************/ ++ /* Statistic related parameters */ ++ /*****************************************************************************************/ ++#ifdef RT2870 ++ ULONG BulkOutDataOneSecCount; ++ ULONG BulkInDataOneSecCount; ++ ULONG BulkLastOneSecCount; // BulkOutDataOneSecCount + BulkInDataOneSecCount ++ ULONG watchDogRxCnt; ++ ULONG watchDogRxOverFlowCnt; ++ ULONG watchDogTxPendingCnt[NUM_OF_TX_RING]; ++#endif // RT2870 // ++ ++ BOOLEAN bUpdateBcnCntDone; ++ ULONG watchDogMacDeadlock; // prevent MAC/BBP into deadlock condition ++ // ---------------------------- ++ // DEBUG paramerts ++ // ---------------------------- ++ //ULONG DebugSetting[4]; ++ BOOLEAN bBanAllBaSetup; ++ BOOLEAN bPromiscuous; ++ ++ // ---------------------------- ++ // rt2860c emulation-use Parameters ++ // ---------------------------- ++ ULONG rtsaccu[30]; ++ ULONG ctsaccu[30]; ++ ULONG cfendaccu[30]; ++ ULONG bacontent[16]; ++ ULONG rxint[RX_RING_SIZE+1]; ++ UCHAR rcvba[60]; ++ BOOLEAN bLinkAdapt; ++ BOOLEAN bForcePrintTX; ++ BOOLEAN bForcePrintRX; ++ BOOLEAN bDisablescanning; //defined in RT2870 USB ++ BOOLEAN bStaFifoTest; ++ BOOLEAN bProtectionTest; ++ BOOLEAN bHCCATest; ++ BOOLEAN bGenOneHCCA; ++ BOOLEAN bBroadComHT; ++ //+++Following add from RT2870 USB. ++ ULONG BulkOutReq; ++ ULONG BulkOutComplete; ++ ULONG BulkOutCompleteOther; ++ ULONG BulkOutCompleteCancel; // seems not use now? ++ ULONG BulkInReq; ++ ULONG BulkInComplete; ++ ULONG BulkInCompleteFail; ++ //--- ++ ++ struct wificonf WIFItestbed; ++ ++#ifdef RALINK_ATE ++ ATE_INFO ate; ++#ifdef RT2870 ++ BOOLEAN ContinBulkOut; //ATE bulk out control ++ BOOLEAN ContinBulkIn; //ATE bulk in control ++ atomic_t BulkOutRemained; ++ atomic_t BulkInRemained; ++#endif // RT2870 // ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++ struct reordering_mpdu_pool mpdu_blk_pool; ++#endif // DOT11_N_SUPPORT // ++ ++ ULONG OneSecondnonBEpackets; // record non BE packets per second ++ ++#if WIRELESS_EXT >= 12 ++ struct iw_statistics iw_stats; ++#endif ++ ++ struct net_device_stats stats; ++ ++#ifdef BLOCK_NET_IF ++ BLOCK_QUEUE_ENTRY blockQueueTab[NUM_OF_TX_RING]; ++#endif // BLOCK_NET_IF // ++ ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++ INT32 MC_RowID; ++ UCHAR MC_FileName[256]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ULONG TbttTickCount; ++#ifdef PCI_MSI_SUPPORT ++ BOOLEAN HaveMsi; ++#endif // PCI_MSI_SUPPORT // ++ ++ ++ UCHAR is_on; ++ ++#define TIME_BASE (1000000/OS_HZ) ++#define TIME_ONE_SECOND (1000000/TIME_BASE) ++ UCHAR flg_be_adjust; ++ ULONG be_adjust_last_time; ++ ++ ++#ifdef IKANOS_VX_1X0 ++ struct IKANOS_TX_INFO IkanosTxInfo; ++ struct IKANOS_TX_INFO IkanosRxInfo[MAX_MBSSID_NUM + MAX_WDS_ENTRY + MAX_APCLI_NUM + MAX_MESH_NUM]; ++#endif // IKANOS_VX_1X0 // ++ ++ ++#ifdef DBG_DIAGNOSE ++ RtmpDiagStruct DiagStruct; ++#endif // DBG_DIAGNOSE // ++ ++ ++ UINT8 PM_FlgSuspend; ++} RTMP_ADAPTER, *PRTMP_ADAPTER; ++ ++// ++// Cisco IAPP format ++// ++typedef struct _CISCO_IAPP_CONTENT_ ++{ ++ USHORT Length; //IAPP Length ++ UCHAR MessageType; //IAPP type ++ UCHAR FunctionCode; //IAPP function type ++ UCHAR DestinaionMAC[MAC_ADDR_LEN]; ++ UCHAR SourceMAC[MAC_ADDR_LEN]; ++ USHORT Tag; //Tag(element IE) - Adjacent AP report ++ USHORT TagLength; //Length of element not including 4 byte header ++ UCHAR OUI[4]; //0x00, 0x40, 0x96, 0x00 ++ UCHAR PreviousAP[MAC_ADDR_LEN]; //MAC Address of access point ++ USHORT Channel; ++ USHORT SsidLen; ++ UCHAR Ssid[MAX_LEN_OF_SSID]; ++ USHORT Seconds; //Seconds that the client has been disassociated. ++} CISCO_IAPP_CONTENT, *PCISCO_IAPP_CONTENT; ++ ++#define DELAYINTMASK 0x0003fffb ++#define INTMASK 0x0003fffb ++#define IndMask 0x0003fffc ++#define RxINT 0x00000005 // Delayed Rx or indivi rx ++#define TxDataInt 0x000000fa // Delayed Tx or indivi tx ++#define TxMgmtInt 0x00000102 // Delayed Tx or indivi tx ++#define TxCoherent 0x00020000 // tx coherent ++#define RxCoherent 0x00010000 // rx coherent ++#define McuCommand 0x00000200 // mcu ++#define PreTBTTInt 0x00001000 // Pre-TBTT interrupt ++#define TBTTInt 0x00000800 // TBTT interrupt ++#define GPTimeOutInt 0x00008000 // GPtimeout interrupt ++#define AutoWakeupInt 0x00004000 // AutoWakeupInt interrupt ++#define FifoStaFullInt 0x00002000 // fifo statistics full interrupt ++ ++ ++typedef struct _RX_BLK_ ++{ ++// RXD_STRUC RxD; // sample ++ RT28XX_RXD_STRUC RxD; ++ PRXWI_STRUC pRxWI; ++ PHEADER_802_11 pHeader; ++ PNDIS_PACKET pRxPacket; ++ UCHAR *pData; ++ USHORT DataSize; ++ USHORT Flags; ++ UCHAR UserPriority; // for calculate TKIP MIC using ++} RX_BLK; ++ ++ ++#define RX_BLK_SET_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags |= _flag) ++#define RX_BLK_TEST_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags & _flag) ++#define RX_BLK_CLEAR_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags &= ~(_flag)) ++ ++ ++#define fRX_WDS 0x0001 ++#define fRX_AMSDU 0x0002 ++#define fRX_ARALINK 0x0004 ++#define fRX_HTC 0x0008 ++#define fRX_PAD 0x0010 ++#define fRX_AMPDU 0x0020 ++#define fRX_QOS 0x0040 ++#define fRX_INFRA 0x0080 ++#define fRX_EAP 0x0100 ++#define fRX_MESH 0x0200 ++#define fRX_APCLI 0x0400 ++#define fRX_DLS 0x0800 ++#define fRX_WPI 0x1000 ++ ++#define LENGTH_AMSDU_SUBFRAMEHEAD 14 ++#define LENGTH_ARALINK_SUBFRAMEHEAD 14 ++#define LENGTH_ARALINK_HEADER_FIELD 2 ++ ++#define TX_UNKOWN_FRAME 0x00 ++#define TX_MCAST_FRAME 0x01 ++#define TX_LEGACY_FRAME 0x02 ++#define TX_AMPDU_FRAME 0x04 ++#define TX_AMSDU_FRAME 0x08 ++#define TX_RALINK_FRAME 0x10 ++#define TX_FRAG_FRAME 0x20 ++ ++ ++// Currently the sizeof(TX_BLK) is 148 bytes. ++typedef struct _TX_BLK_ ++{ ++ UCHAR QueIdx; ++ UCHAR TxFrameType; // Indicate the Transmission type of the all frames in one batch ++ UCHAR TotalFrameNum; // Total frame number want to send-out in one batch ++ USHORT TotalFragNum; // Total frame fragments required in one batch ++ USHORT TotalFrameLen; // Total length of all frames want to send-out in one batch ++ ++ QUEUE_HEADER TxPacketList; ++ MAC_TABLE_ENTRY *pMacEntry; // NULL: packet with 802.11 RA field is multicast/broadcast address ++ HTTRANSMIT_SETTING *pTransmit; ++ ++ // Following structure used for the characteristics of a specific packet. ++ PNDIS_PACKET pPacket; ++ PUCHAR pSrcBufHeader; // Reference to the head of sk_buff->data ++ PUCHAR pSrcBufData; // Reference to the sk_buff->data, will changed depends on hanlding progresss ++ UINT SrcBufLen; // Length of packet payload which not including Layer 2 header ++ PUCHAR pExtraLlcSnapEncap; // NULL means no extra LLC/SNAP is required ++ UCHAR HeaderBuf[80]; // TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP ++ UCHAR MpduHeaderLen; // 802.11 header length NOT including the padding ++ UCHAR HdrPadLen; // recording Header Padding Length; ++ UCHAR apidx; // The interface associated to this packet ++ UCHAR Wcid; // The MAC entry associated to this packet ++ UCHAR UserPriority; // priority class of packet ++ UCHAR FrameGap; // what kind of IFS this packet use ++ UCHAR MpduReqNum; // number of fragments of this frame ++ UCHAR TxRate; // TODO: Obsoleted? Should change to MCS? ++ UCHAR CipherAlg; // cipher alogrithm ++ PCIPHER_KEY pKey; ++ ++ ++ ++ USHORT Flags; //See following definitions for detail. ++ ++ //YOU SHOULD NOT TOUCH IT! Following parameters are used for hardware-depended layer. ++ ULONG Priv; // Hardware specific value saved in here. ++} TX_BLK, *PTX_BLK; ++ ++ ++#define fTX_bRtsRequired 0x0001 // Indicate if need send RTS frame for protection. Not used in RT2860/RT2870. ++#define fTX_bAckRequired 0x0002 // the packet need ack response ++#define fTX_bPiggyBack 0x0004 // Legacy device use Piggback or not ++#define fTX_bHTRate 0x0008 // allow to use HT rate ++//#define fTX_bForceLowRate 0x0010 // force to use Low Rate ++#define fTX_bForceNonQoS 0x0010 // force to transmit frame without WMM-QoS in HT mode ++#define fTX_bAllowFrag 0x0020 // allow to fragment the packet, A-MPDU, A-MSDU, A-Ralink is not allowed to fragment ++#define fTX_bMoreData 0x0040 // there are more data packets in PowerSave Queue ++#define fTX_bWMM 0x0080 // QOS Data ++ ++#define fTX_bClearEAPFrame 0x0100 ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++#define TX_BLK_ASSIGN_FLAG(_pTxBlk, _flag, value) \ ++ do { \ ++ if (value) \ ++ (_pTxBlk->Flags |= _flag) \ ++ else \ ++ (_pTxBlk->Flags &= ~(_flag)) \ ++ }while(0) ++ ++#define TX_BLK_SET_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags |= _flag) ++#define TX_BLK_TEST_FLAG(_pTxBlk, _flag) (((_pTxBlk->Flags & _flag) == _flag) ? 1 : 0) ++#define TX_BLK_CLEAR_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags &= ~(_flag)) ++ ++ ++ ++ ++ ++//------------------------------------------------------------------------------------------ ++ ++ ++ ++#ifdef RT_BIG_ENDIAN ++static inline VOID WriteBackToDescriptor( ++ IN PUCHAR Dest, ++ IN PUCHAR Src, ++ IN BOOLEAN DoEncrypt, ++ IN ULONG DescriptorType) ++{ ++ UINT32 *p1, *p2; ++ ++ p1 = ((UINT32 *)Dest); ++ p2 = ((UINT32 *)Src); ++ ++ *p1 = *p2; ++ *(p1+2) = *(p2+2); ++ *(p1+3) = *(p2+3); ++ *(p1+1) = *(p2+1); // Word 1; this must be written back last ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of Tx/Rx descriptor . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to Tx/Rx descriptor ++ DescriptorType Direction of the frame ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update descriptor ++ ======================================================================== ++*/ ++static inline VOID RTMPWIEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType) ++{ ++ int size; ++ int i; ++ ++ size = ((DescriptorType == TYPE_TXWI) ? TXWI_SIZE : RXWI_SIZE); ++ ++ if(DescriptorType == TYPE_TXWI) ++ { ++ *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 ++ *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData+4))); // Byte 4~7 ++ } ++ else ++ { ++ for(i=0; i < size/4 ; i++) ++ *(((UINT32 *)pData) +i) = SWAP32(*(((UINT32 *)pData)+i)); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of Tx/Rx descriptor . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to Tx/Rx descriptor ++ DescriptorType Direction of the frame ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update descriptor ++ ======================================================================== ++*/ ++ ++#ifdef RT2870 ++static inline VOID RTMPDescriptorEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType) ++{ ++ *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); ++} ++#endif // RT2870 // ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of all kinds of 802.11 frames . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the 802.11 frame structure ++ Dir Direction of the frame ++ FromRxDoneInt Caller is from RxDone interrupt ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update buffer data ++ ======================================================================== ++*/ ++static inline VOID RTMPFrameEndianChange( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG Dir, ++ IN BOOLEAN FromRxDoneInt) ++{ ++ PHEADER_802_11 pFrame; ++ PUCHAR pMacHdr; ++ ++ // swab 16 bit fields - Frame Control field ++ if(Dir == DIR_READ) ++ { ++ *(USHORT *)pData = SWAP16(*(USHORT *)pData); ++ } ++ ++ pFrame = (PHEADER_802_11) pData; ++ pMacHdr = (PUCHAR) pFrame; ++ ++ // swab 16 bit fields - Duration/ID field ++ *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); ++ ++ // swab 16 bit fields - Sequence Control field ++ *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); ++ ++ if(pFrame->FC.Type == BTYPE_MGMT) ++ { ++ switch(pFrame->FC.SubType) ++ { ++ case SUBTYPE_ASSOC_REQ: ++ case SUBTYPE_REASSOC_REQ: ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Listen Interval field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_ASSOC_RSP: ++ case SUBTYPE_REASSOC_RSP: ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Status Code field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - AID field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_AUTH: ++ // If from APHandleRxDoneInterrupt routine, it is still a encrypt format. ++ // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. ++ if(!FromRxDoneInt && pFrame->FC.Wep == 1) ++ break; ++ else ++ { ++ // swab 16 bit fields - Auth Alg No. field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Auth Seq No. field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Status Code field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ } ++ break; ++ ++ case SUBTYPE_BEACON: ++ case SUBTYPE_PROBE_RSP: ++ // swab 16 bit fields - BeaconInterval field ++ pMacHdr += (sizeof(HEADER_802_11) + TIMESTAMP_LEN); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(USHORT); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_DEAUTH: ++ case SUBTYPE_DISASSOC: ++ // swab 16 bit fields - Reason code field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ } ++ } ++ else if( pFrame->FC.Type == BTYPE_DATA ) ++ { ++ } ++ else if(pFrame->FC.Type == BTYPE_CNTL) ++ { ++ switch(pFrame->FC.SubType) ++ { ++ case SUBTYPE_BLOCK_ACK_REQ: ++ { ++ PFRAME_BA_REQ pBAReq = (PFRAME_BA_REQ)pFrame; ++ *(USHORT *)(&pBAReq->BARControl) = SWAP16(*(USHORT *)(&pBAReq->BARControl)); ++ pBAReq->BAStartingSeq.word = SWAP16(pBAReq->BAStartingSeq.word); ++ } ++ break; ++ case SUBTYPE_BLOCK_ACK: ++ // For Block Ack packet, the HT_CONTROL field is in the same offset with Addr3 ++ *(UINT32 *)(&pFrame->Addr3[0]) = SWAP32(*(UINT32 *)(&pFrame->Addr3[0])); ++ break; ++ ++ case SUBTYPE_ACK: ++ //For ACK packet, the HT_CONTROL field is in the same offset with Addr2 ++ *(UINT32 *)(&pFrame->Addr2[0])= SWAP32(*(UINT32 *)(&pFrame->Addr2[0])); ++ break; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("Invalid Frame Type!!!\n")); ++ } ++ ++ // swab 16 bit fields - Frame Control ++ if(Dir == DIR_WRITE) ++ { ++ *(USHORT *)pData = SWAP16(*(USHORT *)pData); ++ } ++} ++#endif // RT_BIG_ENDIAN // ++ ++ ++static inline VOID ConvertMulticastIP2MAC( ++ IN PUCHAR pIpAddr, ++ IN PUCHAR *ppMacAddr, ++ IN UINT16 ProtoType) ++{ ++ if (pIpAddr == NULL) ++ return; ++ ++ if (ppMacAddr == NULL || *ppMacAddr == NULL) ++ return; ++ ++ switch (ProtoType) ++ { ++ case ETH_P_IPV6: ++// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); ++ *(*ppMacAddr) = 0x33; ++ *(*ppMacAddr + 1) = 0x33; ++ *(*ppMacAddr + 2) = pIpAddr[12]; ++ *(*ppMacAddr + 3) = pIpAddr[13]; ++ *(*ppMacAddr + 4) = pIpAddr[14]; ++ *(*ppMacAddr + 5) = pIpAddr[15]; ++ break; ++ ++ case ETH_P_IP: ++ default: ++// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); ++ *(*ppMacAddr) = 0x01; ++ *(*ppMacAddr + 1) = 0x00; ++ *(*ppMacAddr + 2) = 0x5e; ++ *(*ppMacAddr + 3) = pIpAddr[1] & 0x7f; ++ *(*ppMacAddr + 4) = pIpAddr[2]; ++ *(*ppMacAddr + 5) = pIpAddr[3]; ++ break; ++ } ++ ++ return; ++} ++ ++BOOLEAN RTMPCheckForHang( ++ IN NDIS_HANDLE MiniportAdapterContext ++ ); ++ ++VOID RTMPHalt( ++ IN NDIS_HANDLE MiniportAdapterContext ++ ); ++ ++// ++// Private routines in rtmp_init.c ++// ++NDIS_STATUS RTMPAllocAdapterBlock( ++ IN PVOID handle, ++ OUT PRTMP_ADAPTER *ppAdapter ++ ); ++ ++NDIS_STATUS RTMPAllocTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++NDIS_STATUS RTMPFindAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ); ++ ++NDIS_STATUS RTMPReadParametersHook( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++VOID RTMPFreeAdapter( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++NDIS_STATUS NICReadRegParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ); ++ ++#ifdef RT2870 ++VOID NICInitRT30xxRFRegisters( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++VOID NICReadEEPROMParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mac_addr); ++ ++VOID NICInitAsicFromEEPROM( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICInitTxRxRingAndBacklogQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICInitializeAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset); ++ ++NDIS_STATUS NICInitializeAsic( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset); ++ ++VOID NICIssueReset( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPRingCleanUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType); ++ ++VOID RxTest( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS DbgSendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++VOID UserCfgInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICResetFromError( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICEraseFirmware( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICLoadFirmware( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICLoadRateSwitchingParams( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN NICCheckForHang( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICUpdateFifoStaCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICUpdateRawCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++#if 0 ++ULONG RTMPEqualMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length); ++#endif ++ ++ULONG RTMPNotAllZero( ++ IN PVOID pSrc1, ++ IN ULONG Length); ++ ++VOID RTMPZeroMemory( ++ IN PVOID pSrc, ++ IN ULONG Length); ++ ++ULONG RTMPCompareMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length); ++ ++VOID RTMPMoveMemory( ++ OUT PVOID pDest, ++ IN PVOID pSrc, ++ IN ULONG Length); ++ ++VOID AtoH( ++ char *src, ++ UCHAR *dest, ++ int destlen); ++ ++UCHAR BtoH( ++ char ch); ++ ++VOID RTMPPatchMacBbpBug( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPatchCardBus( ++ IN PRTMP_ADAPTER pAdapter); ++ ++VOID RTMPPatchRalinkCardBus( ++ IN PRTMP_ADAPTER pAdapter, ++ IN ULONG Bus); ++ ++ULONG RTMPReadCBConfig( ++ IN ULONG Bus, ++ IN ULONG Slot, ++ IN ULONG Func, ++ IN ULONG Offset); ++ ++VOID RTMPWriteCBConfig( ++ IN ULONG Bus, ++ IN ULONG Slot, ++ IN ULONG Func, ++ IN ULONG Offset, ++ IN ULONG Value); ++ ++VOID RTMPInitTimer( ++ IN PRTMP_ADAPTER pAd, ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN PVOID pTimerFunc, ++ IN PVOID pData, ++ IN BOOLEAN Repeat); ++ ++VOID RTMPSetTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value); ++ ++ ++VOID RTMPModTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value); ++ ++VOID RTMPCancelTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ OUT BOOLEAN *pCancelled); ++ ++VOID RTMPSetLED( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Status); ++ ++VOID RTMPSetSignalLED( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_802_11_RSSI Dbm); ++ ++VOID RTMPEnableRxTx( ++ IN PRTMP_ADAPTER pAd); ++ ++// ++// prototype in action.c ++// ++VOID ActionStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeADDBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDELBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeInvalidAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerAddBAReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAddBARspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDelBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // DOT11_N_SUPPORT // ++ ++VOID SendPSMPAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Psmp); ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID SendBSS2040CoexistMgmtAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx, ++ IN UCHAR InfoReq); ++ ++VOID SendNotifyBWActionFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx); ++ ++BOOLEAN ChannelSwitchSanityCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary); ++ ++VOID ChannelSwitchAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Channel, ++ IN UCHAR Secondary); ++ ++ULONG BuildIntolerantChannelRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest); ++ ++VOID Update2040CoexistFrameAndNotify( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha); ++ ++VOID Send2040CoexistAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha); ++#endif // DOT11N_DRAFT3 // ++ ++VOID PeerRMAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID StaPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Bss2040Coexist); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++VOID PeerBSSTranAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerHTAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // DOT11_N_SUPPORT // ++ ++VOID PeerQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef QOS_DLS_SUPPORT ++VOID PeerDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++VOID DlsParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, ++ IN PRT_802_11_DLS pDls, ++ IN USHORT reason); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID RECBATimerTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID ORIBATimerTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID SendRefreshBAR( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++#endif // DOT11_N_SUPPORT // ++ ++VOID ActHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN PUCHAR Addr1, ++ IN PUCHAR Addr2, ++ IN PUCHAR Addr3); ++ ++VOID BarHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PFRAME_BAR pCntlBar, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA); ++ ++VOID InsertActField( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 Category, ++ IN UINT8 ActCode); ++ ++BOOLEAN QosBADataParse( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bAMSDU, ++ IN PUCHAR p8023Header, ++ IN UCHAR WCID, ++ IN UCHAR TID, ++ IN USHORT Sequence, ++ IN UCHAR DataOffset, ++ IN USHORT Datasize, ++ IN UINT CurRxIndex); ++ ++#ifdef DOT11_N_SUPPORT ++BOOLEAN CntlEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG MsgLen, ++ IN PFRAME_BA_REQ pMsg); ++ ++VOID BaAutoManSwitch( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++ ++VOID HTIOTCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BatRecIdx); ++ ++// ++// Private routines in rtmp_data.c ++// ++BOOLEAN RTMPHandleRxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleTxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd, ++ IN INT_SOURCE_CSR_STRUC TxRingBitmap); ++ ++VOID RTMPHandleMgmtRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandlePreTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++void RTMPHandleTwakeupInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleRxCoherentInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN TxFrameIsAggregatible( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pPrevAddr1, ++ IN PUCHAR p8023hdr); ++ ++BOOLEAN PeerIsAggreOn( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG TxRate, ++ IN PMAC_TABLE_ENTRY pMacEntry); ++ ++#if 0 // It's not be used ++HTTRANSMIT_SETTING *GetTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk); ++#endif ++ ++NDIS_STATUS Sniff2BytesFromNdisBuffer( ++ IN PNDIS_BUFFER pFirstBuffer, ++ IN UCHAR DesiredOffset, ++ OUT PUCHAR pByte0, ++ OUT PUCHAR pByte1); ++ ++NDIS_STATUS STASendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++VOID STASendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets); ++ ++VOID RTMPDeQueuePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bIntContext, ++ IN UCHAR QueIdx, ++ IN UCHAR Max_Tx_Packets); ++ ++NDIS_STATUS RTMPHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR QueIdx, ++ OUT PULONG pFreeTXDLeft); ++ ++NDIS_STATUS STAHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++VOID STARxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++NDIS_STATUS RTMPFreeTXDRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType, ++ IN UCHAR NumberRequired, ++ IN PUCHAR FreeNumberIs); ++ ++NDIS_STATUS MlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++NDIS_STATUS MlmeHardTransmitMgmtRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++NDIS_STATUS MlmeHardTransmitTxRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++USHORT RTMPCalcDuration( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Rate, ++ IN ULONG Size); ++ ++VOID RTMPWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit); ++ ++ ++VOID RTMPWriteTxWI_Data( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk); ++ ++ ++VOID RTMPWriteTxWI_Cache( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk); ++ ++VOID RTMPWriteTxDescriptor( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXD_STRUC pTxD, ++ IN BOOLEAN bWIV, ++ IN UCHAR QSEL); ++ ++VOID RTMPSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS MiniportMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length); ++ ++NDIS_STATUS MiniportDataMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length); ++ ++VOID RTMPSendNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull); ++ ++VOID RTMPSendDisassociationFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSendRTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN unsigned int NextMpduSize, ++ IN UCHAR TxRate, ++ IN UCHAR RTSRate, ++ IN USHORT AckDuration, ++ IN UCHAR QueIdx, ++ IN UCHAR FrameGap); ++ ++ ++NDIS_STATUS RTMPApplyPacketFilter( ++ IN PRTMP_ADAPTER pAd, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN PHEADER_802_11 pHeader); ++ ++PQUEUE_HEADER RTMPCheckTxSwQueue( ++ IN PRTMP_ADAPTER pAd, ++ OUT UCHAR *QueIdx); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPReportMicError( ++ IN PRTMP_ADAPTER pAd, ++ IN PCIPHER_KEY pWpaKey); ++ ++VOID WpaMicFailureReportFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaDisassocApAndBlockAssoc( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // CONFIG_STA_SUPPORT // ++ ++NDIS_STATUS RTMPCloneNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN pInsAMSDUHdr, ++ IN PNDIS_PACKET pInPacket, ++ OUT PNDIS_PACKET *ppOutPacket); ++ ++NDIS_STATUS RTMPAllocateNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET *pPacket, ++ IN PUCHAR pHeader, ++ IN UINT HeaderLen, ++ IN PUCHAR pData, ++ IN UINT DataLen); ++ ++VOID RTMPFreeNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++BOOLEAN RTMPFreeTXDUponTxDmaDone( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx); ++ ++BOOLEAN RTMPCheckDHCPFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++BOOLEAN RTMPCheckEtherType( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++VOID RTMPCckBbpTuning( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT TxRate); ++ ++// ++// Private routines in rtmp_wep.c ++// ++VOID RTMPInitWepEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN UCHAR KeyLen, ++ IN PUCHAR pDest); ++ ++VOID RTMPEncryptData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDest, ++ IN UINT Len); ++ ++BOOLEAN RTMPDecryptData( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR pSrc, ++ IN UINT Len, ++ IN UINT idx); ++ ++BOOLEAN RTMPSoftDecryptWEP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pGroupKey); ++ ++VOID RTMPSetICV( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest); ++ ++VOID ARCFOUR_INIT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pKey, ++ IN UINT KeyLen); ++ ++UCHAR ARCFOUR_BYTE( ++ IN PARCFOURCONTEXT Ctx); ++ ++VOID ARCFOUR_DECRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++VOID ARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++VOID WPAARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++UINT RTMP_CALC_FCS32( ++ IN UINT Fcs, ++ IN PUCHAR Cp, ++ IN INT Len); ++ ++// ++// MLME routines ++// ++ ++// Asic/RF/BBP related functions ++ ++VOID AsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicUpdateProtect( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT OperaionMode, ++ IN UCHAR SetMask, ++ IN BOOLEAN bDisableBGProtect, ++ IN BOOLEAN bNonGFExist); ++ ++VOID AsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN BOOLEAN bScan); ++ ++VOID AsicLockChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ; ++ ++VOID AsicAntennaSelect( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++VOID AsicAntennaSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN ABGBAND_STATE BandState); ++ ++VOID AsicRfTuningExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID AsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp); ++ ++VOID AsicForceSleep( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx); ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID AsicSetBssid( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid); ++ ++VOID AsicSetMcastWC( ++ IN PRTMP_ADAPTER pAd); ++ ++#if 0 // removed by AlbertY ++VOID AsicSetBssidWC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid); ++#endif ++ ++VOID AsicDelWcidTab( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid); ++ ++VOID AsicEnableRDG( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDisableRDG( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDisableSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicEnableBssSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicEnableIbssSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicSetEdcaParm( ++ IN PRTMP_ADAPTER pAd, ++ IN PEDCA_PARM pEdcaParm); ++ ++VOID AsicSetSlotTime( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUseShortSlotTime); ++ ++#if 0 ++VOID AsicAddWcidCipherEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyTable, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pAddr, ++ IN CIPHER_KEY *pCipherKey); ++#endif ++ ++VOID AsicAddSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic); ++ ++VOID AsicRemoveSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx); ++ ++VOID AsicUpdateWCIDAttribute( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bUsePairewiseKeyTable); ++ ++VOID AsicUpdateWCIDIVEIV( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN ULONG uIV, ++ IN ULONG uEIV); ++ ++VOID AsicUpdateRxWCIDTable( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN PUCHAR pAddr); ++ ++VOID AsicAddKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN PCIPHER_KEY pCipherKey, ++ IN BOOLEAN bUsePairewiseKeyTable, ++ IN BOOLEAN bTxKey); ++ ++VOID AsicAddPairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR WCID, ++ IN CIPHER_KEY *pCipherKey); ++ ++VOID AsicRemovePairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR Wcid); ++ ++BOOLEAN AsicSendCommandToMcu( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command, ++ IN UCHAR Token, ++ IN UCHAR Arg0, ++ IN UCHAR Arg1); ++ ++ ++VOID MacAddrRandomBssid( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pAddr); ++ ++VOID MgtMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid); ++ ++VOID MlmeRadioOff( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeRadioOn( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++VOID BssTableInit( ++ IN BSS_TABLE *Tab); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInit( ++ IN PRTMP_ADAPTER pAd, ++ IN BA_TABLE *Tab); ++#endif // DOT11_N_SUPPORT // ++ ++ULONG BssTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel); ++ ++ULONG BssSsidTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel); ++ ++ULONG BssTableSearchWithSSID( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR Bssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel); ++ ++VOID BssTableDeleteEntry( ++ IN OUT PBSS_TABLE pTab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableDeleteORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_ORI_ENTRY *pBAORIEntry); ++ ++VOID BATableDeleteRECEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_REC_ENTRY *pBARECEntry); ++ ++VOID BATableTearORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR TID, ++ IN UCHAR Wcid, ++ IN BOOLEAN bForceDelete, ++ IN BOOLEAN ALL); ++ ++VOID BATableTearRECEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR TID, ++ IN UCHAR WCID, ++ IN BOOLEAN ALL); ++#endif // DOT11_N_SUPPORT // ++ ++VOID BssEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT PBSS_ENTRY pBss, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN PCF_PARM CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++ULONG BssTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT PBSS_TABLE pTab, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN CF_PARM *CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Aid, ++ IN USHORT TimeOutValue, ++ IN USHORT StartingSeq, ++ IN UCHAR TID, ++ IN UCHAR BAWinSize, ++ IN UCHAR OriginatorStatus, ++ IN BOOLEAN IsRecipient); ++ ++#ifdef DOT11N_DRAFT3 ++VOID Bss2040CoexistTimeOut( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++VOID TriEventInit( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG TriEventTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT TRIGGER_EVENT_TAB *Tab, ++ IN PUCHAR pBssid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR RegClass, ++ IN UCHAR ChannelNo); ++ ++VOID TriEventCounterMaintenance( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++VOID BssTableSsidSort( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *OutTab, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen); ++ ++VOID BssTableSortByRssi( ++ IN OUT BSS_TABLE *OutTab); ++ ++VOID BssCipherParse( ++ IN OUT PBSS_ENTRY pBss); ++ ++NDIS_STATUS MlmeQueueInit( ++ IN MLME_QUEUE *Queue); ++ ++VOID MlmeQueueDestroy( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MlmeEnqueue( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Machine, ++ IN ULONG MsgType, ++ IN ULONG MsgLen, ++ IN VOID *Msg); ++ ++BOOLEAN MlmeEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG TimeStampHigh, ++ IN ULONG TimeStampLow, ++ IN UCHAR Rssi0, ++ IN UCHAR Rssi1, ++ IN UCHAR Rssi2, ++ IN ULONG MsgLen, ++ IN PVOID Msg, ++ IN UCHAR Signal); ++ ++ ++BOOLEAN MlmeDequeue( ++ IN MLME_QUEUE *Queue, ++ OUT MLME_QUEUE_ELEM **Elem); ++ ++VOID MlmeRestartStateMachine( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeQueueEmpty( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MlmeQueueFull( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType); ++ ++VOID StateMachineInit( ++ IN STATE_MACHINE *Sm, ++ IN STATE_MACHINE_FUNC Trans[], ++ IN ULONG StNr, ++ IN ULONG MsgNr, ++ IN STATE_MACHINE_FUNC DefFunc, ++ IN ULONG InitState, ++ IN ULONG Base); ++ ++VOID StateMachineSetAction( ++ IN STATE_MACHINE *S, ++ IN ULONG St, ++ ULONG Msg, ++ IN STATE_MACHINE_FUNC F); ++ ++VOID StateMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Drop( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID ReassocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID AssocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID DisassocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++//---------------------------------------------- ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAssocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerReassocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDisassocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID DisassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AssocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ReassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Cls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID SwitchBetweenWepAndCkip( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID InvalidStateWhenAssoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenReassoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenDisassociate( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef RT2870 ++VOID MlmeCntlConfirm( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG MsgType, ++ IN USHORT Msg); ++#endif // RT2870 // ++ ++VOID ComposePsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ComposeNullFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AssocPostProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr2, ++ IN USHORT CapabilityInfo, ++ IN USHORT Aid, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN PEDCA_PARM pEdcaParm, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID AuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID AuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID MlmeAuthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthRspAtSeq2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthRspAtSeq4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AuthTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Cls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID MlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenAuth( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++//============================================= ++ ++VOID AuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]); ++ ++VOID PeerDeauthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT Reason, ++ IN USHORT Status); ++ ++// ++// Private routines in dls.c ++// ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++void DlsStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID RTMPCheckDLSTimeOut( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPRcvFrameDLSCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN ULONG Len, ++ IN PRT28XX_RXD_STRUC pRxD); ++ ++INT RTMPCheckDLSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++NDIS_STATUS RTMPSendSTAKeyRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++NDIS_STATUS RTMPSendSTAKeyHandShake( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++VOID DlsTimeoutAction( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN MlmeDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PRT_802_11_DLS *pDLS, ++ OUT PUSHORT pReason); ++ ++INT Set_DlsEntryInfo_Display_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++MAC_TABLE_ENTRY *MacTableInsertDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UINT DlsEntryIdx); ++ ++BOOLEAN MacTableDeleteDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr); ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount); ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR wcid, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount); ++ ++INT Set_DlsAddEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_DlsTearDownEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN PeerDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pDlsTimeout, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDlsRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDlsTearDownSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pReason); ++#endif // QOS_DLS_SUPPORT // ++ ++//======================================== ++ ++VOID SyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID BeaconTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID ScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenJoin( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenStart( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID EnqueueProbeRequest( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN ScanRunning( ++ IN PRTMP_ADAPTER pAd); ++//========================================= ++ ++VOID MlmeCntlInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeCntlMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlIdleProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlOidScanProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlOidSsidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlOidRTBssidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlMlmeRoamingProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlWaitDisassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitJoinProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitReassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitStartProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAuthProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAuthProc2( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAssocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef QOS_DLS_SUPPORT ++VOID CntlOidDLSSetupProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // QOS_DLS_SUPPORT // ++ ++VOID LinkUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssType); ++ ++VOID LinkDown( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN IsReqFromAP); ++ ++VOID IterateOnBssTab( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID IterateOnBssTab2( ++ IN PRTMP_ADAPTER pAd);; ++ ++VOID JoinParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, ++ IN ULONG BssIdx); ++ ++VOID AssocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, ++ IN PUCHAR pAddr, ++ IN USHORT CapabilityInfo, ++ IN ULONG Timeout, ++ IN USHORT ListenIntv); ++ ++VOID ScanParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN UCHAR ScanType); ++ ++VOID DisassocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, ++ IN PUCHAR pAddr, ++ IN USHORT Reason); ++ ++VOID StartParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_START_REQ_STRUCT *StartReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen); ++ ++VOID AuthParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, ++ IN PUCHAR pAddr, ++ IN USHORT Alg); ++ ++VOID EnqueuePsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EnqueueBeaconFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeJoinReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeStartReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID BeaconTimeoutAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeaconAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ScanNextChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG MakeIbssBeacon( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID CCXAdjacentAPReport( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeScanReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *BssType, ++ OUT CHAR ssid[], ++ OUT UCHAR *SsidLen, ++ OUT UCHAR *ScanType); ++ ++BOOLEAN PeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgChannel, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pBssType, ++ OUT USHORT *pBeaconPeriod, ++ OUT UCHAR *pChannel, ++ OUT UCHAR *pNewChannel, ++ OUT LARGE_INTEGER *pTimestamp, ++ OUT CF_PARM *pCfParm, ++ OUT USHORT *pAtimWin, ++ OUT USHORT *pCapabilityInfo, ++ OUT UCHAR *pErp, ++ OUT UCHAR *pDtimCount, ++ OUT UCHAR *pDtimPeriod, ++ OUT UCHAR *pBcastFlag, ++ OUT UCHAR *pMessageToMe, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT UCHAR *pCkipFlag, ++ OUT UCHAR *pAironetCellPowerLimit, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT PQBSS_LOAD_PARM pQbssLoad, ++ OUT PQOS_CAPABILITY_PARM pQosCapability, ++ OUT ULONG *pRalinkIe, ++ OUT UCHAR *pHtCapabilityLen, ++#ifdef CONFIG_STA_SUPPORT ++ OUT UCHAR *pPreNHtCapabilityLen, ++#endif // CONFIG_STA_SUPPORT // ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT UCHAR *AddHtInfoLen, ++ OUT ADD_HT_INFO_IE *AddHtInfo, ++ OUT UCHAR *NewExtChannel, ++ OUT USHORT *LengthVIE, ++ OUT PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++BOOLEAN PeerAddBAReqActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2); ++ ++BOOLEAN PeerAddBARspActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen); ++ ++BOOLEAN PeerDelBAActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN VOID *pMsg, ++ IN ULONG MsgLen); ++ ++BOOLEAN MlmeAssocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pApAddr, ++ OUT USHORT *CapabilityInfo, ++ OUT ULONG *Timeout, ++ OUT USHORT *ListenIntv); ++ ++BOOLEAN MlmeAuthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT ULONG *Timeout, ++ OUT USHORT *Alg); ++ ++BOOLEAN MlmeStartReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT CHAR Ssid[], ++ OUT UCHAR *Ssidlen); ++ ++BOOLEAN PeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT USHORT *Alg, ++ OUT USHORT *Seq, ++ OUT USHORT *Status, ++ OUT CHAR ChlgText[]); ++ ++BOOLEAN PeerAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT USHORT *pAid, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ OUT UCHAR *pHtCapabilityLen, ++ OUT UCHAR *pAddHtInfoLen, ++ OUT UCHAR *pNewExtChannelOffset, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT UCHAR *pCkipFlag); ++ ++BOOLEAN PeerDisassocSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerWpaMessageSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN PEAPOL_PACKET pMsg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgType, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN PeerDeauthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen); ++ ++BOOLEAN GetTimBit( ++ IN CHAR *Ptr, ++ IN USHORT Aid, ++ OUT UCHAR *TimLen, ++ OUT UCHAR *BcastFlag, ++ OUT UCHAR *DtimCount, ++ OUT UCHAR *DtimPeriod, ++ OUT UCHAR *MessageToMe); ++ ++UCHAR ChannelSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel); ++ ++NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( ++ IN PBSS_ENTRY pBss); ++ ++#if 0 // It's omitted ++NDIS_STATUS RTMPWepKeySanity( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PVOID pBuf); ++#endif ++ ++BOOLEAN MlmeDelBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen); ++ ++BOOLEAN MlmeAddBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2); ++ ++ULONG MakeOutgoingFrame( ++ OUT CHAR *Buffer, ++ OUT ULONG *Length, ...); ++ ++VOID LfsrInit( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Seed); ++ ++UCHAR RandomByte( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicUpdateAutoFallBackTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pTxRate); ++ ++VOID MlmePeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LinkDownExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LinkUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID STAMlmePeriodicExec( ++ PRTMP_ADAPTER pAd); ++ ++VOID MlmeAutoScan( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeAutoReconnectLastSSID( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeValidateSSID( ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen); ++ ++VOID MlmeCheckForRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32); ++ ++VOID MlmeCheckForFastRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now); ++ ++VOID MlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate); ++ ++VOID MlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx); ++ ++VOID MlmeCalculateChannelQuality( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now); ++ ++VOID MlmeCheckPsmChange( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32); ++ ++VOID MlmeSetPsmBit( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm); ++ ++VOID MlmeSetTxPreamble( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TxPreamble); ++ ++VOID UpdateBasicRateBitmap( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeUpdateTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bLinkUp, ++ IN UCHAR apidx); ++ ++#ifdef DOT11_N_SUPPORT ++VOID MlmeUpdateHtTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx); ++#endif // DOT11_N_SUPPORT // ++ ++VOID RTMPCheckRates( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT UCHAR SupRate[], ++ IN OUT UCHAR *SupRateLen); ++ ++#ifdef CONFIG_STA_SUPPORT ++BOOLEAN RTMPCheckChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR CentralChannel, ++ IN UCHAR Channel); ++#endif // CONFIG_STA_SUPPORT // ++ ++BOOLEAN RTMPCheckHt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN OUT HT_CAPABILITY_IE *pHtCapability, ++ IN OUT ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID StaQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID AsicBbpTuning1( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicBbpTuning2( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPUpdateMlmeRate( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR RTMPMaxRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi0, ++ IN CHAR Rssi1, ++ IN CHAR Rssi2); ++ ++VOID AsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicRxAntEvalTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID APSDPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++ ++UCHAR RTMPStaFixedTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++ ++VOID RTMPUpdateLegacyTxSetting( ++ UCHAR fixed_tx_mode, ++ PMAC_TABLE_ENTRY pEntry); ++ ++BOOLEAN RTMPAutoRateSwitchCheck( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS MlmeInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeHandler( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeHalt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeResetRalinkCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BuildChannelList( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR FirstChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR NextChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel); ++ ++VOID ChangeToCellPowerLimit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AironetCellPowerLimit); ++ ++VOID RaiseClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x); ++ ++VOID LowerClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x); ++ ++USHORT ShiftInBits( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ShiftOutBits( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT data, ++ IN USHORT count); ++ ++VOID EEpromCleanup( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EWDS( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EWEN( ++ IN PRTMP_ADAPTER pAd); ++ ++USHORT RTMP_EEPROM_READ16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset); ++ ++VOID RTMP_EEPROM_WRITE16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Data); ++ ++// ++// Prototypes of function definition in rtmp_tkip.c ++// ++VOID RTMPInitTkipEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pTKey, ++ IN UCHAR KeyId, ++ IN PUCHAR pTA, ++ IN PUCHAR pMICKey, ++ IN PUCHAR pTSC, ++ OUT PULONG pIV16, ++ OUT PULONG pIV32); ++ ++VOID RTMPInitMICEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN UCHAR UserPriority, ++ IN PUCHAR pMICKey); ++ ++BOOLEAN RTMPTkipCompareMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UCHAR UserPriority, ++ IN UINT Len); ++ ++VOID RTMPCalculateMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pEncap, ++ IN PCIPHER_KEY pKey, ++ IN UCHAR apidx); ++ ++BOOLEAN RTMPTkipCompareMICValueWithLLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pLLC, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UINT Len); ++ ++VOID RTMPTkipAppendByte( ++ IN PTKIP_KEY_INFO pTkip, ++ IN UCHAR uChar); ++ ++VOID RTMPTkipAppend( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pSrc, ++ IN UINT nBytes); ++ ++VOID RTMPTkipGetMIC( ++ IN PTKIP_KEY_INFO pTkip); ++ ++BOOLEAN RTMPSoftDecryptTKIP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN UCHAR UserPriority, ++ IN PCIPHER_KEY pWpaKey); ++ ++BOOLEAN RTMPSoftDecryptAES( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pWpaKey); ++ ++#if 0 // removed by AlbertY ++NDIS_STATUS RTMPWPAAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++#endif ++ ++// ++// Prototypes of function definition in cmm_info.c ++// ++NDIS_STATUS RTMPWPARemoveKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++VOID RTMPWPARemoveAllKeys( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPCheckStrPrintAble( ++ IN CHAR *pInPutStr, ++ IN UCHAR strLen); ++ ++VOID RTMPSetPhyMode( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG phymode); ++ ++VOID RTMPUpdateHTIE( ++ IN RT_HT_CAPABILITY *pRtHt, ++ IN UCHAR *pMcsSet, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID RTMPAddWcidAttributeEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++CHAR *GetEncryptType( ++ CHAR enc); ++ ++CHAR *GetAuthMode( ++ CHAR auth); ++ ++VOID RTMPIoctlGetSiteSurvey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlGetMacTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIndicateWPA2Status( ++ IN PRTMP_ADAPTER pAdapter); ++ ++VOID RTMPOPModeSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPAddBSSIDCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Aid, ++ IN PNDIS_802_11_KEY pKey, ++ IN UCHAR CipherAlg); ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID RTMPSetHT( ++ IN PRTMP_ADAPTER pAd, ++ IN OID_SET_HT_PHYMODE *pHTPhyMode); ++ ++VOID RTMPSetIndividualHT( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx); ++#endif // DOT11_N_SUPPORT // ++ ++VOID RTMPSendWirelessEvent( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Event_flag, ++ IN PUCHAR pAddr, ++ IN UCHAR BssIdx, ++ IN CHAR Rssi); ++ ++VOID NICUpdateCntlCounters( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN UCHAR SubType, ++ IN PRXWI_STRUC pRxWI); ++// ++// prototype in wpa.c ++// ++BOOLEAN WpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType); ++ ++VOID WpaPskStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID WpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaPairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaPairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaGroupMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr1); ++ ++VOID Wpa2PairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Wpa2PairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++BOOLEAN ParseKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR bPairewise); ++ ++VOID RTMPToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN is4wayFrame); ++ ++VOID HMAC_SHA1( ++ IN UCHAR *text, ++ IN UINT text_len, ++ IN UCHAR *key, ++ IN UINT key_len, ++ IN UCHAR *digest); ++ ++VOID PRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *prefix, ++ IN INT prefix_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len); ++ ++VOID CCKMPRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len); ++ ++VOID WpaCountPTK( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *PMK, ++ IN UCHAR *ANonce, ++ IN UCHAR *AA, ++ IN UCHAR *SNonce, ++ IN UCHAR *SA, ++ OUT UCHAR *output, ++ IN UINT len); ++ ++VOID GenRandom( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *macAddr, ++ OUT UCHAR *random); ++ ++// ++// prototype in aironet.c ++// ++VOID AironetStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID AironetMsgAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AironetRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ChannelLoadRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID NoiseHistRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID BeaconRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ChannelLoadReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID NoiseHistReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetFinalReportAction( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BeaconReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetAddBeaconReport( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Index, ++ IN PMLME_QUEUE_ELEM pElem); ++ ++VOID AironetCreateBeaconReportFromBssTable( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID DBGPRINT_TX_RING( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx); ++ ++VOID DBGPRINT_RX_RING( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR ConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber); ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID BuildEffectedChannelList( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11N_DRAFT3 // ++ ++ ++VOID APAsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++VOID APAsicRxAntEvalTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++// ++// function prototype in cmm_wpa.c ++// ++BOOLEAN RTMPCheckWPAframe( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR pData, ++ IN ULONG DataByteCount, ++ IN UCHAR FromWhichBSSID); ++ ++VOID AES_GTK_KEY_UNWRAP( ++ IN UCHAR *key, ++ OUT UCHAR *plaintext, ++ IN UCHAR c_len, ++ IN UCHAR *ciphertext); ++ ++BOOLEAN RTMPCheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ IN MAC_TABLE_ENTRY *pEntry, ++ OUT UCHAR *Offset); ++ ++BOOLEAN RTMPParseEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR GroupKeyIndex, ++ IN UCHAR MsgType, ++ IN BOOLEAN bWPA2, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID ConstructEapolMsg( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerAuthMode, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR MyGroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN UCHAR *ReplayCounter, ++ IN UCHAR *KeyNonce, ++ IN UCHAR *TxRSC, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_Len, ++ OUT PEAPOL_PACKET pMsg); ++ ++VOID CalculateMIC( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR *PTK, ++ OUT PEAPOL_PACKET pMsg); ++ ++NDIS_STATUS RTMPSoftDecryptBroadCastData( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, ++ IN PCIPHER_KEY pShard_key); ++ ++VOID ConstructEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerAuthMode, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN BOOLEAN bWPA2Capable, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_LEN, ++ OUT PEAPOL_PACKET pMsg); ++ ++VOID RTMPMakeRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT AuthMode, ++ IN UINT WepStatus, ++ IN UCHAR apidx); ++ ++// ++// function prototype in ap_wpa.c ++// ++ ++BOOLEAN APWpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType) ; ++ ++MAC_TABLE_ENTRY *PACInquiry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid); ++ ++BOOLEAN RTMPCheckMcast( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN RTMPCheckUcast( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN RTMPCheckAUTH( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID WPAStart4WayHS( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN ULONG TimeInterval); ++ ++VOID WPAStart2WayGroupHS( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID APWpaEAPPacketAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLStartAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLLogoffAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLASFAlertAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HandleCounterMeasure( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID PeerPairMsg2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerPairMsg4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CMTimerExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID WPARetryExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID EnqueueStartForPSKExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID RTMPHandleSTAKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#if 0 // merge into PeerPairMsg4Action ++VOID Wpa1PeerPairMsg4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Wpa2PeerPairMsg4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // 0 // ++ ++VOID PeerGroupMsg2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN VOID *Msg, ++ IN UINT MsgLen); ++ ++#if 0 // replaced by WPAStart2WayGroupHS ++NDIS_STATUS APWpaHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++#endif // 0 // ++ ++VOID PairDisAssocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN USHORT Reason); ++ ++VOID MlmeDeAuthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN USHORT Reason); ++ ++VOID GREKEYPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID CountGTK( ++ IN UCHAR *PMK, ++ IN UCHAR *GNonce, ++ IN UCHAR *AA, ++ OUT UCHAR *output, ++ IN UINT len); ++ ++VOID GetSmall( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ OUT PUCHAR out, ++ IN ULONG Length); ++ ++VOID GetLarge( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ OUT PUCHAR out, ++ IN ULONG Length); ++ ++VOID APGenRandom( ++ IN PRTMP_ADAPTER pAd, ++ OUT UCHAR *random); ++ ++VOID AES_GTK_KEY_WRAP( ++ IN UCHAR *key, ++ IN UCHAR *plaintext, ++ IN UCHAR p_len, ++ OUT UCHAR *ciphertext); ++ ++VOID WpaSend( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR pPacket, ++ IN ULONG Len); ++ ++VOID APToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN bClearFrame); ++ ++VOID RTMPAddPMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN PUCHAR pAddr, ++ IN UCHAR *PMKID, ++ IN UCHAR *PMK); ++ ++INT RTMPSearchPMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN PUCHAR pAddr); ++ ++VOID RTMPDeletePMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN INT idx); ++ ++VOID RTMPMaintainPMKIDCache( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSendTriggerFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuffer, ++ IN ULONG Length, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull); ++ ++ ++//typedef void (*TIMER_FUNCTION)(unsigned long); ++ ++ ++/* timeout -- ms */ ++VOID RTMP_SetPeriodicTimer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++VOID RTMP_OS_Init_Timer( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN TIMER_FUNCTION function, ++ IN PVOID data); ++ ++VOID RTMP_OS_Add_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++VOID RTMP_OS_Mod_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++ ++VOID RTMP_OS_Del_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ OUT BOOLEAN *pCancelled); ++ ++ ++VOID RTMP_OS_Release_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_ENTRY pEntry); ++ ++VOID RTMPusecDelay( ++ IN ULONG usec); ++ ++NDIS_STATUS os_alloc_mem( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR *mem, ++ IN ULONG size); ++ ++NDIS_STATUS os_free_mem( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mem); ++ ++ ++void RTMP_AllocateSharedMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++VOID RTMPFreeTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS AdapterBlockAllocateMemory( ++ IN PVOID handle, ++ OUT PVOID *ppAd); ++ ++void RTMP_AllocateTxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateFirstTxBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateMgmtDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateRxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++PNDIS_PACKET RTMP_AllocateRxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++PNDIS_PACKET RTMP_AllocateTxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress); ++ ++PNDIS_PACKET RTMP_AllocateFragPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length); ++ ++void RTMP_QueryPacketInfo( ++ IN PNDIS_PACKET pPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen); ++ ++void RTMP_QueryNextPacketInfo( ++ IN PNDIS_PACKET *ppPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen); ++ ++ ++BOOLEAN RTMP_FillTxBlkInfo( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk); ++ ++ ++PRTMP_SCATTER_GATHER_LIST ++rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg); ++ ++ ++ void announce_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++UINT BA_Reorder_AMSDU_Annnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++UINT Handle_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++void convert_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR p8023hdr, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNET_DEV get_netdev_from_bssid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET duplicate_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pOldPkt); ++ ++PNDIS_PACKET duplicate_pkt_with_VLAN( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++PNDIS_PACKET duplicate_pkt_with_WPI( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UINT32 ext_head_len, ++ IN UINT32 ext_tail_len); ++ ++UCHAR VLAN_8023_Header_Copy( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ OUT PUCHAR pData, ++ IN UCHAR FromWhichBSSID); ++ ++#ifdef DOT11_N_SUPPORT ++void ba_flush_reordering_timeout_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN ULONG Now32); ++ ++ ++VOID BAOriSessionSetUp( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN UCHAR TID, ++ IN USHORT TimeOut, ++ IN ULONG DelayTime, ++ IN BOOLEAN isForced); ++ ++VOID BASessionTearDownALL( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid); ++#endif // DOT11_N_SUPPORT // ++ ++BOOLEAN OS_Need_Clone_Packet(void); ++ ++ ++VOID build_tx_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pFrame, ++ IN ULONG FrameLen); ++ ++ ++VOID BAOriSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive, ++ IN BOOLEAN bForceSend); ++ ++VOID BARecSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive); ++ ++BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); ++void ba_reordering_resource_release(PRTMP_ADAPTER pAd); ++ ++ULONG AutoChBssInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR ChannelNo, ++ IN CHAR Rssi); ++ ++void AutoChBssTableInit( ++ IN PRTMP_ADAPTER pAd); ++ ++void ChannelInfoInit( ++ IN PRTMP_ADAPTER pAd); ++ ++void AutoChBssTableDestroy( ++ IN PRTMP_ADAPTER pAd); ++ ++void ChannelInfoDestroy( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR New_ApAutoSelectChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN rtstrmactohex( ++ IN char *s1, ++ IN char *s2); ++ ++BOOLEAN rtstrcasecmp( ++ IN char *s1, ++ IN char *s2); ++ ++char *rtstrstruncasecmp( ++ IN char *s1, ++ IN char *s2); ++ ++char *rtstrstr( ++ IN const char * s1, ++ IN const char * s2); ++ ++char *rstrtok( ++ IN char * s, ++ IN const char * ct); ++ ++int rtinet_aton( ++ const char *cp, ++ unsigned int *addr); ++ ++////////// common ioctl functions ////////// ++INT Set_DriverVersion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ShortSlot_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef AGGREGATION_SUPPORT ++INT Set_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef DBG ++INT Set_Debug_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Show_DescInfo_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ResetStatCounter_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_BASetup_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BADecline_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BAOriTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BARecTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtStbc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtHtc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtLinkAdapt_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtProtect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMimoPs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_ForceShortGI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ForceGF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT SetCommonHT( ++ IN PRTMP_ADAPTER pAd); ++ ++INT Set_SendPSMPAction_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMIMOPSmode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_HtTxBASize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++//Dls , kathy ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++#ifdef DOT11_N_SUPPORT ++//Block ACK ++VOID QueryBATABLE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PQUERYBA_TABLE pBAT); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT WpaCheckEapCode( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFrame, ++ IN USHORT FrameLen, ++ IN USHORT OffSet); ++ ++VOID WpaSendMicFailureToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUnicast); ++ ++VOID SendAssocIEsToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++int wext_notify_event_assoc( ++ IN RTMP_ADAPTER *pAd); ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++#ifdef DOT11_N_SUPPORT ++VOID Handle_BSS_Width_Trigger_Events( ++ IN PRTMP_ADAPTER pAd); ++ ++void build_ext_channel_switch_ie( ++ IN PRTMP_ADAPTER pAd, ++ IN HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE *pIE); ++#endif // DOT11_N_SUPPORT // ++ ++ ++BOOLEAN APRxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN STARxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN argc); ++ ++#ifdef DOT11_N_SUPPORT ++// AMPDU packet indication ++VOID Indicate_AMPDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++// AMSDU packet indication ++VOID Indicate_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++#endif // DOT11_N_SUPPORT // ++ ++// Normal legacy Rx packet indication ++VOID Indicate_Legacy_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Indicate_EAPOL_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++void update_os_packet_info( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++void wlan_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN PUCHAR pHeader802_3, ++ IN UCHAR FromWhichBSSID); ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++// remove LLC and get 802_3 Header ++#define RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(_pRxBlk, _pHeader802_3) \ ++{ \ ++ PUCHAR _pRemovedLLCSNAP = NULL, _pDA, _pSA; \ ++ \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_MESH)) \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr3; \ ++ _pSA = (PUCHAR)_pRxBlk->pHeader + sizeof(HEADER_802_11); \ ++ } \ ++ else \ ++ { \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_INFRA)) \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr1; \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_DLS)) \ ++ _pSA = _pRxBlk->pHeader->Addr2; \ ++ else \ ++ _pSA = _pRxBlk->pHeader->Addr3; \ ++ } \ ++ else \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr1; \ ++ _pSA = _pRxBlk->pHeader->Addr2; \ ++ } \ ++ } \ ++ \ ++ CONVERT_TO_802_3(_pHeader802_3, _pDA, _pSA, _pRxBlk->pData, \ ++ _pRxBlk->DataSize, _pRemovedLLCSNAP); \ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++BOOLEAN APFowardWirelessStaToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN ULONG FromWhichBSSID); ++ ++VOID Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Sta_Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define ANNOUNCE_OR_FORWARD_802_3_PACKET(_pAd, _pPacket, _FromWhichBSS)\ ++ Sta_Announce_or_Forward_802_3_Packet(_pAd, _pPacket, _FromWhichBSS); ++ //announce_802_3_packet(_pAd, _pPacket); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++PNDIS_PACKET DuplicatePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET ClonePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++ ++// Normal, AMPDU or AMSDU ++VOID CmmRxnonRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID CmmRxRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Update_Rssi_Sample( ++ IN PRTMP_ADAPTER pAd, ++ IN RSSI_SAMPLE *pRssi, ++ IN PRXWI_STRUC pRxWI); ++ ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending); ++ ++PNDIS_PACKET RTMPDeFragmentDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk); ++ ++//////////////////////////////////////// ++ ++ ++ ++ ++ ++#ifdef SNMP_SUPPORT ++//for snmp , kathy ++typedef struct _DefaultKeyIdxValue ++{ ++ UCHAR KeyIdx; ++ UCHAR Value[16]; ++} DefaultKeyIdxValue, *PDefaultKeyIdxValue; ++#endif ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++enum { ++ DIDmsg_lnxind_wlansniffrm = 0x00000044, ++ DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, ++ DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, ++ DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, ++ DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, ++ DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, ++ DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, ++ DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, ++ DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, ++ DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, ++ DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 ++}; ++enum { ++ P80211ENUM_msgitem_status_no_value = 0x00 ++}; ++enum { ++ P80211ENUM_truth_false = 0x00, ++ P80211ENUM_truth_true = 0x01 ++}; ++ ++/* Definition from madwifi */ ++typedef struct { ++ UINT32 did; ++ UINT16 status; ++ UINT16 len; ++ UINT32 data; ++} p80211item_uint32_t; ++ ++typedef struct { ++ UINT32 msgcode; ++ UINT32 msglen; ++#define WLAN_DEVNAMELEN_MAX 16 ++ UINT8 devname[WLAN_DEVNAMELEN_MAX]; ++ p80211item_uint32_t hosttime; ++ p80211item_uint32_t mactime; ++ p80211item_uint32_t channel; ++ p80211item_uint32_t rssi; ++ p80211item_uint32_t sq; ++ p80211item_uint32_t signal; ++ p80211item_uint32_t noise; ++ p80211item_uint32_t rate; ++ p80211item_uint32_t istx; ++ p80211item_uint32_t frmlen; ++} wlan_ng_prism2_header; ++ ++/* The radio capture header precedes the 802.11 header. */ ++typedef struct PACKED _ieee80211_radiotap_header { ++ UINT8 it_version; /* Version 0. Only increases ++ * for drastic changes, ++ * introduction of compatible ++ * new fields does not count. ++ */ ++ UINT8 it_pad; ++ UINT16 it_len; /* length of the whole ++ * header in bytes, including ++ * it_version, it_pad, ++ * it_len, and data fields. ++ */ ++ UINT32 it_present; /* A bitmap telling which ++ * fields are present. Set bit 31 ++ * (0x80000000) to extend the ++ * bitmap by another 32 bits. ++ * Additional extensions are made ++ * by setting bit 31. ++ */ ++}ieee80211_radiotap_header ; ++ ++enum ieee80211_radiotap_type { ++ IEEE80211_RADIOTAP_TSFT = 0, ++ IEEE80211_RADIOTAP_FLAGS = 1, ++ IEEE80211_RADIOTAP_RATE = 2, ++ IEEE80211_RADIOTAP_CHANNEL = 3, ++ IEEE80211_RADIOTAP_FHSS = 4, ++ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, ++ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, ++ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, ++ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, ++ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, ++ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, ++ IEEE80211_RADIOTAP_ANTENNA = 11, ++ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, ++ IEEE80211_RADIOTAP_DB_ANTNOISE = 13 ++}; ++ ++#define WLAN_RADIOTAP_PRESENT ( \ ++ (1 << IEEE80211_RADIOTAP_TSFT) | \ ++ (1 << IEEE80211_RADIOTAP_FLAGS) | \ ++ (1 << IEEE80211_RADIOTAP_RATE) | \ ++ 0) ++ ++typedef struct _wlan_radiotap_header { ++ ieee80211_radiotap_header wt_ihdr; ++ INT64 wt_tsft; ++ UINT8 wt_flags; ++ UINT8 wt_rate; ++} wlan_radiotap_header; ++/* Definition from madwifi */ ++ ++void send_monitor_packets( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk); ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev); ++#endif ++ ++VOID RTMPSetDesiredRates( ++ IN PRTMP_ADAPTER pAdapter, ++ IN LONG Rates); ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Set_FixedTxMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++INT Set_OpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++static inline char* GetPhyMode( ++ int Mode) ++{ ++ switch(Mode) ++ { ++ case MODE_CCK: ++ return "CCK"; ++ ++ case MODE_OFDM: ++ return "OFDM"; ++#ifdef DOT11_N_SUPPORT ++ case MODE_HTMIX: ++ return "HTMIX"; ++ ++ case MODE_HTGREENFIELD: ++ return "GREEN"; ++#endif // DOT11_N_SUPPORT // ++ default: ++ return "N/A"; ++ } ++} ++ ++ ++static inline char* GetBW( ++ int BW) ++{ ++ switch(BW) ++ { ++ case BW_10: ++ return "10M"; ++ ++ case BW_20: ++ return "20M"; ++#ifdef DOT11_N_SUPPORT ++ case BW_40: ++ return "40M"; ++#endif // DOT11_N_SUPPORT // ++ default: ++ return "N/A"; ++ } ++} ++ ++ ++VOID RT28xxThreadTerminate( ++ IN RTMP_ADAPTER *pAd); ++ ++BOOLEAN RT28XXChipsetCheck( ++ IN void *_dev_p); ++ ++BOOLEAN RT28XXNetDevInit( ++ IN void *_dev_p, ++ IN struct net_device *net_dev, ++ IN RTMP_ADAPTER *pAd); ++ ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 argc); ++ ++VOID RT28XXDMADisable( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT28XXDMAEnable( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT28xx_UpdateBeaconToAsic( ++ IN RTMP_ADAPTER * pAd, ++ IN INT apidx, ++ IN ULONG BeaconLen, ++ IN ULONG UpdatePos); ++ ++INT rt28xx_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd); ++#endif // CONFIG_STA_SUPPORT // ++ ++BOOLEAN RT28XXSecurityKeyAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG apidx, ++ IN ULONG KeyIdx, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++//////////////////////////////////////// ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending); ++ ++ ++void kill_thread_task(PRTMP_ADAPTER pAd); ++ ++void tbtt_tasklet(unsigned long data); ++ ++ ++VOID AsicTurnOffRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++VOID AsicTurnOnRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++#ifdef RT2870 ++// ++// Function Prototype in rtusb_bulk.c ++// ++VOID RTUSBInitTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PTX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN usb_complete_t Func); ++ ++VOID RTUSBInitHTTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PHT_TX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN ULONG BulkOutSize, ++ IN usb_complete_t Func); ++ ++VOID RTUSBInitRxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PRX_CONTEXT pRxContext); ++ ++VOID RTUSBCleanUpDataBulkOutQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCancelPendingBulkOutIRP( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UCHAR Index); ++ ++VOID RTUSBBulkOutNullFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkOutRTSFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCancelPendingIRPs( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkOutMLMEPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID RTUSBBulkOutPsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCleanUpMLMEBulkOutQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBKickBulkOut( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkReceive( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID DoBulkIn( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RTUSBInitRxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PRX_CONTEXT pRxContext); ++ ++VOID RTUSBBulkRxHandle( ++ IN unsigned long data); ++ ++// ++// Function Prototype in rtusb_io.c ++// ++NTSTATUS RTUSBMultiRead( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length); ++ ++NTSTATUS RTUSBMultiWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length); ++ ++NTSTATUS RTUSBMultiWrite_OneByte( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData); ++ ++NTSTATUS RTUSBReadBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN PUCHAR pValue); ++ ++NTSTATUS RTUSBWriteBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN UCHAR Value); ++ ++NTSTATUS RTUSBWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 Value); ++ ++NTSTATUS RT30xxWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN UCHAR Value); ++ ++NTSTATUS RT30xxReadRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN PUCHAR pValue); ++ ++NTSTATUS RTUSB_VendorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TransferFlags, ++ IN UCHAR ReservedBits, ++ IN UCHAR Request, ++ IN USHORT Value, ++ IN USHORT Index, ++ IN PVOID TransferBuffer, ++ IN UINT32 TransferBufferLength); ++ ++NTSTATUS RTUSBReadEEPROM( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length); ++ ++NTSTATUS RTUSBWriteEEPROM( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length); ++ ++VOID RTUSBPutToSleep( ++ IN PRTMP_ADAPTER pAd); ++ ++NTSTATUS RTUSBWakeUp( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBInitializeCmdQ( ++ IN PCmdQ cmdq); ++ ++NDIS_STATUS RTUSBEnqueueCmdFromNdis( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN BOOLEAN SetInformation, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength); ++ ++NDIS_STATUS RTUSBEnqueueInternalCmd( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength); ++ ++VOID RTUSBDequeueCmd( ++ IN PCmdQ cmdq, ++ OUT PCmdQElmt *pcmdqelmt); ++ ++INT RTUSBCmdThread( ++ IN OUT PVOID Context); ++ ++INT TimerQThread( ++ IN OUT PVOID Context); ++ ++RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer); ++ ++BOOLEAN RT2870_TimerQ_Remove( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer); ++ ++void RT2870_TimerQ_Exit( ++ IN RTMP_ADAPTER *pAd); ++ ++void RT2870_TimerQ_Init( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_BssBeaconExit( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_BssBeaconStop( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_BssBeaconStart( ++ IN RTMP_ADAPTER * pAd); ++ ++VOID RT2870_BssBeaconInit( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_WatchDog( ++ IN RTMP_ADAPTER *pAd); ++ ++NTSTATUS RTUSBWriteMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN UINT32 Value); ++ ++NTSTATUS RTUSBReadMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUINT32 pValue); ++ ++NTSTATUS RTUSBSingleWrite( ++ IN RTMP_ADAPTER *pAd, ++ IN USHORT Offset, ++ IN USHORT Value); ++ ++NTSTATUS RTUSBFirmwareRun( ++ IN PRTMP_ADAPTER pAd); ++ ++NTSTATUS RTUSBFirmwareWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFwImage, ++ IN ULONG FwLen); ++ ++NTSTATUS RTUSBFirmwareOpmode( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUINT32 pValue); ++ ++NTSTATUS RTUSBVenderReset( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS RTUSBSetHardWareRegister( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PVOID pBuf); ++ ++NDIS_STATUS RTUSBQueryHardWareRegister( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PVOID pBuf); ++ ++VOID CMDHandler( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++NDIS_STATUS CreateThreads( ++ IN struct net_device *net_dev ); ++ ++ ++VOID MacTableInitialize( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeSetPsm( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm); ++ ++NDIS_STATUS RTMPWPAAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++VOID AsicRxAntEvalAction( ++ IN PRTMP_ADAPTER pAd); ++ ++#if 0 // Mark because not used in RT28xx. ++NTSTATUS RTUSBRxPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bBulkReceive); ++ ++VOID RTUSBDequeueMLMEPacket( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCleanUpMLMEWaitQueue( ++ IN PRTMP_ADAPTER pAd); ++#endif ++ ++void append_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ OUT PNDIS_PACKET *ppPacket); ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++NDIS_STATUS RTMPCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxINFO); ++ ++ ++VOID RTUSBMlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN PMGMT_STRUC pMgmt); ++ ++INT MlmeThread( ++ IN PVOID Context); ++ ++#if 0 ++VOID RTUSBResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++#endif ++ ++// ++// Function Prototype in rtusb_data.c ++// ++NDIS_STATUS RTUSBFreeDescriptorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UINT32 NumberRequired); ++ ++ ++BOOLEAN RTUSBNeedQueueBackForAgg( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR BulkOutPipeId); ++ ++ ++VOID RTMPWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst); ++ ++// ++// Function Prototype in cmm_data_2870.c ++// ++USHORT RtmpUSB_WriteSubTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpUSB_WriteSingleTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpUSB_WriteFragTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR fragNum, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpUSB_WriteMultiTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR frameNum, ++ OUT USHORT *FreeNumber); ++ ++VOID RtmpUSB_FinalWriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN USHORT totalMPDUSize, ++ IN USHORT TxIdx); ++ ++VOID RtmpUSBDataLastTxIdx( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN USHORT TxIdx); ++ ++VOID RtmpUSBDataKickOut( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++ ++int RtmpUSBMgmtKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pSrcBufVA, ++ IN UINT SrcBufLen); ++ ++VOID RtmpUSBNullFrameKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR *pNullFrame, ++ IN UINT32 frameLen); ++ ++VOID RT28xxUsbStaAsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx); ++ ++VOID RT28xxUsbStaAsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp); ++ ++VOID RT28xxUsbMlmeRadioOn( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RT28xxUsbMlmeRadioOFF( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++//////////////////////////////////////// ++ ++VOID QBSS_LoadInit( ++ IN RTMP_ADAPTER *pAd); ++ ++UINT32 QBSS_LoadElementAppend( ++ IN RTMP_ADAPTER *pAd, ++ OUT UINT8 *buf_p); ++ ++VOID QBSS_LoadUpdate( ++ IN RTMP_ADAPTER *pAd); ++ ++/////////////////////////////////////// ++INT RTMPShowCfgValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pName, ++ IN PUCHAR pBuf); ++ ++PCHAR RTMPGetRalinkAuthModeStr( ++ IN NDIS_802_11_AUTHENTICATION_MODE authMode); ++ ++PCHAR RTMPGetRalinkEncryModeStr( ++ IN USHORT encryMode); ++////////////////////////////////////// ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID AsicStaBbpTuning( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN StaAddMacTableEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN USHORT CapabilityInfo); ++#endif // CONFIG_STA_SUPPORT // ++ ++void RTMP_IndicateMediaState( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ReSyncBeaconTime( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSetAGCInitValue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BandWidth); ++ ++int rt28xx_close(IN PNET_DEV dev); ++int rt28xx_open(IN PNET_DEV dev); ++ ++__inline INT VIRTUAL_IF_UP(PRTMP_ADAPTER pAd) ++{ ++extern VOID MeshMakeBeacon(IN PRTMP_ADAPTER pAd, IN UCHAR idx); ++extern VOID MeshUpdateBeaconFrame(IN PRTMP_ADAPTER pAd, IN UCHAR idx); ++ ++ if (VIRTUAL_IF_NUM(pAd) == 0) ++ { ++ if (rt28xx_open(pAd->net_dev) != 0) ++ return -1; ++ } ++ else ++ { ++ } ++ VIRTUAL_IF_INC(pAd); ++ return 0; ++} ++ ++__inline VOID VIRTUAL_IF_DOWN(PRTMP_ADAPTER pAd) ++{ ++ VIRTUAL_IF_DEC(pAd); ++ if (VIRTUAL_IF_NUM(pAd) == 0) ++ rt28xx_close(pAd->net_dev); ++ return; ++} ++ ++ ++#endif // __RTMP_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rtmp_type.h +@@ -0,0 +1,94 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_type.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 1-2-2004 ++*/ ++#ifndef __RTMP_TYPE_H__ ++#define __RTMP_TYPE_H__ ++ ++#define PACKED __attribute__ ((packed)) ++ ++// Put platform dependent declaration here ++// For example, linux type definition ++typedef unsigned char UINT8; ++typedef unsigned short UINT16; ++typedef unsigned int UINT32; ++typedef unsigned long long UINT64; ++typedef int INT32; ++typedef long long INT64; ++ ++typedef unsigned char * PUINT8; ++typedef unsigned short * PUINT16; ++typedef unsigned int * PUINT32; ++typedef unsigned long long * PUINT64; ++typedef int * PINT32; ++typedef long long * PINT64; ++ ++typedef signed char CHAR; ++typedef signed short SHORT; ++typedef signed int INT; ++typedef signed long LONG; ++typedef signed long long LONGLONG; ++ ++ ++typedef unsigned char UCHAR; ++typedef unsigned short USHORT; ++typedef unsigned int UINT; ++typedef unsigned long ULONG; ++typedef unsigned long long ULONGLONG; ++ ++typedef unsigned char BOOLEAN; ++typedef void VOID; ++ ++typedef VOID * PVOID; ++typedef CHAR * PCHAR; ++typedef UCHAR * PUCHAR; ++typedef USHORT * PUSHORT; ++typedef LONG * PLONG; ++typedef ULONG * PULONG; ++typedef UINT * PUINT; ++ ++typedef unsigned int NDIS_MEDIA_STATE; ++ ++typedef union _LARGE_INTEGER { ++ struct { ++ UINT LowPart; ++ INT32 HighPart; ++ } u; ++ INT64 QuadPart; ++} LARGE_INTEGER; ++ ++#endif // __RTMP_TYPE_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/rt_profile.c +@@ -0,0 +1,2016 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++#ifdef DOT11_N_SUPPORT ++static void HTParametersHook( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR *pValueStr, ++ IN CHAR *pInput); ++#endif // DOT11_N_SUPPORT // ++ ++#define ETH_MAC_ADDR_STR_LEN 17 // in format of xx:xx:xx:xx:xx:xx ++ ++// We assume the s1 is a sting, s2 is a memory space with 6 bytes. and content of s1 will be changed. ++BOOLEAN rtstrmactohex(char *s1, char *s2) ++{ ++ int i = 0; ++ char *ptokS = s1, *ptokE = s1; ++ ++ if (strlen(s1) != ETH_MAC_ADDR_STR_LEN) ++ return FALSE; ++ ++ while((*ptokS) != '\0') ++ { ++ if((ptokE = strchr(ptokS, ':')) != NULL) ++ *ptokE++ = '\0'; ++ if ((strlen(ptokS) != 2) || (!isxdigit(*ptokS)) || (!isxdigit(*(ptokS+1)))) ++ break; // fail ++ AtoH(ptokS, &s2[i++], 1); ++ ptokS = ptokE; ++ if (i == 6) ++ break; // parsing finished ++ } ++ ++ return ( i == 6 ? TRUE : FALSE); ++ ++} ++ ++ ++// we assume the s1 and s2 both are strings. ++BOOLEAN rtstrcasecmp(char *s1, char *s2) ++{ ++ char *p1 = s1, *p2 = s2; ++ ++ if (strlen(s1) != strlen(s2)) ++ return FALSE; ++ ++ while(*p1 != '\0') ++ { ++ if((*p1 != *p2) && ((*p1 ^ *p2) != 0x20)) ++ return FALSE; ++ p1++; ++ p2++; ++ } ++ ++ return TRUE; ++} ++ ++// we assume the s1 (buffer) and s2 (key) both are strings. ++char * rtstrstruncasecmp(char * s1, char * s2) ++{ ++ INT l1, l2, i; ++ char temp1, temp2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *) s1; ++ ++ l1 = strlen(s1); ++ ++ while (l1 >= l2) ++ { ++ l1--; ++ ++ for(i=0; i= l2) ++ { ++ l1--; ++ if (!memcmp(s1,s2,l2)) ++ return (char *) s1; ++ s1++; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * rstrtok - Split a string into tokens ++ * @s: The string to be searched ++ * @ct: The characters to search for ++ * * WARNING: strtok is deprecated, use strsep instead. However strsep is not compatible with old architecture. ++ */ ++char * __rstrtok; ++char * rstrtok(char * s,const char * ct) ++{ ++ char *sbegin, *send; ++ ++ sbegin = s ? s : __rstrtok; ++ if (!sbegin) ++ { ++ return NULL; ++ } ++ ++ sbegin += strspn(sbegin,ct); ++ if (*sbegin == '\0') ++ { ++ __rstrtok = NULL; ++ return( NULL ); ++ } ++ ++ send = strpbrk( sbegin, ct); ++ if (send && *send != '\0') ++ *send++ = '\0'; ++ ++ __rstrtok = send; ++ ++ return (sbegin); ++} ++ ++/** ++ * delimitcnt - return the count of a given delimiter in a given string. ++ * @s: The string to be searched. ++ * @ct: The delimiter to search for. ++ * Notice : We suppose the delimiter is a single-char string(for example : ";"). ++ */ ++INT delimitcnt(char * s,const char * ct) ++{ ++ INT count = 0; ++ /* point to the beginning of the line */ ++ const char *token = s; ++ ++ for ( ;; ) ++ { ++ token = strpbrk(token, ct); /* search for delimiters */ ++ ++ if ( token == NULL ) ++ { ++ /* advanced to the terminating null character */ ++ break; ++ } ++ /* skip the delimiter */ ++ ++token; ++ ++ /* ++ * Print the found text: use len with %.*s to specify field width. ++ */ ++ ++ /* accumulate delimiter count */ ++ ++count; ++ } ++ return count; ++} ++ ++/* ++ * converts the Internet host address from the standard numbers-and-dots notation ++ * into binary data. ++ * returns nonzero if the address is valid, zero if not. ++ */ ++int rtinet_aton(const char *cp, unsigned int *addr) ++{ ++ unsigned int val; ++ int base, n; ++ char c; ++ unsigned int parts[4]; ++ unsigned int *pp = parts; ++ ++ for (;;) ++ { ++ /* ++ * Collect number up to ``.''. ++ * Values are specified as for C: ++ * 0x=hex, 0=octal, other=decimal. ++ */ ++ val = 0; ++ base = 10; ++ if (*cp == '0') ++ { ++ if (*++cp == 'x' || *cp == 'X') ++ base = 16, cp++; ++ else ++ base = 8; ++ } ++ while ((c = *cp) != '\0') ++ { ++ if (isdigit((unsigned char) c)) ++ { ++ val = (val * base) + (c - '0'); ++ cp++; ++ continue; ++ } ++ if (base == 16 && isxdigit((unsigned char) c)) ++ { ++ val = (val << 4) + ++ (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); ++ cp++; ++ continue; ++ } ++ break; ++ } ++ if (*cp == '.') ++ { ++ /* ++ * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) ++ * a.b (with b treated as 24 bits) ++ */ ++ if (pp >= parts + 3 || val > 0xff) ++ return 0; ++ *pp++ = val, cp++; ++ } ++ else ++ break; ++ } ++ ++ /* ++ * Check for trailing junk. ++ */ ++ while (*cp) ++ if (!isspace((unsigned char) *cp++)) ++ return 0; ++ ++ /* ++ * Concoct the address according to the number of parts specified. ++ */ ++ n = pp - parts + 1; ++ switch (n) ++ { ++ ++ case 1: /* a -- 32 bits */ ++ break; ++ ++ case 2: /* a.b -- 8.24 bits */ ++ if (val > 0xffffff) ++ return 0; ++ val |= parts[0] << 24; ++ break; ++ ++ case 3: /* a.b.c -- 8.8.16 bits */ ++ if (val > 0xffff) ++ return 0; ++ val |= (parts[0] << 24) | (parts[1] << 16); ++ break; ++ ++ case 4: /* a.b.c.d -- 8.8.8.8 bits */ ++ if (val > 0xff) ++ return 0; ++ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); ++ break; ++ } ++ ++ *addr = htonl(val); ++ return 1; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Find key section for Get key parameter. ++ ++ Arguments: ++ buffer Pointer to the buffer to start find the key section ++ section the key of the secion to be find ++ ++ Return Value: ++ NULL Fail ++ Others Success ++ ======================================================================== ++*/ ++PUCHAR RTMPFindSection( ++ IN PCHAR buffer) ++{ ++ CHAR temp_buf[32]; ++ PUCHAR ptr; ++ ++ strcpy(temp_buf, "Default"); ++ ++ if((ptr = rtstrstr(buffer, temp_buf)) != NULL) ++ return (ptr+strlen("\n")); ++ else ++ return NULL; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get key parameter. ++ ++ Arguments: ++ key Pointer to key string ++ dest Pointer to destination ++ destsize The datasize of the destination ++ buffer Pointer to the buffer to start find the key ++ ++ Return Value: ++ TRUE Success ++ FALSE Fail ++ ++ Note: ++ This routine get the value with the matched key (case case-sensitive) ++ ======================================================================== ++*/ ++INT RTMPGetKeyParameter( ++ IN PCHAR key, ++ OUT PCHAR dest, ++ IN INT destsize, ++ IN PCHAR buffer) ++{ ++ UCHAR *temp_buf1 = NULL; ++ UCHAR *temp_buf2 = NULL; ++ CHAR *start_ptr; ++ CHAR *end_ptr; ++ CHAR *ptr; ++ CHAR *offset = 0; ++ INT len; ++ ++ //temp_buf1 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ os_alloc_mem(NULL, &temp_buf1, MAX_PARAM_BUFFER_SIZE); ++ ++ if(temp_buf1 == NULL) ++ return (FALSE); ++ ++ //temp_buf2 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ os_alloc_mem(NULL, &temp_buf2, MAX_PARAM_BUFFER_SIZE); ++ if(temp_buf2 == NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ return (FALSE); ++ } ++ ++ //find section ++ if((offset = RTMPFindSection(buffer)) == NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ os_free_mem(NULL, temp_buf2); ++ return (FALSE); ++ } ++ ++ strcpy(temp_buf1, "\n"); ++ strcat(temp_buf1, key); ++ strcat(temp_buf1, "="); ++ ++ //search key ++ if((start_ptr=rtstrstr(offset, temp_buf1))==NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ os_free_mem(NULL, temp_buf2); ++ return (FALSE); ++ } ++ ++ start_ptr+=strlen("\n"); ++ if((end_ptr=rtstrstr(start_ptr, "\n"))==NULL) ++ end_ptr=start_ptr+strlen(start_ptr); ++ ++ if (end_ptrSharedKey[i][idx].KeyLen = KeyLen / 2; ++ AtoH(keybuff, pAd->SharedKey[i][idx].Key, KeyLen / 2); ++ if (KeyLen == 10) ++ CipherAlg = CIPHER_WEP64; ++ else ++ CipherAlg = CIPHER_WEP128; ++ pAd->SharedKey[i][idx].CipherAlg = CipherAlg; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("I/F(ra%d) Key%dStr=%s and type=%s\n", i, idx+1, keybuff, (KeyType == 0) ? "Hex":"Ascii")); ++ return 1; ++ } ++ else ++ {//Invalid key length ++ DBGPRINT(RT_DEBUG_ERROR, ("I/F(ra%d) Key%dStr is Invalid key length! KeyLen = %ld!\n", i, idx+1, KeyLen)); ++ return 0; ++ } ++ } ++} ++static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) ++{ ++ char tok_str[16]; ++ PUCHAR macptr; ++ INT i = 0, idx; ++ ULONG KeyType[MAX_MBSSID_NUM]; ++ ULONG KeyIdx; ++ ++ NdisZeroMemory(KeyType, MAX_MBSSID_NUM); ++ ++ //DefaultKeyID ++ if(RTMPGetKeyParameter("DefaultKeyID", tmpbuf, 25, buffer)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ KeyIdx = simple_strtol(tmpbuf, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1); ++ else ++ pAd->StaCfg.DefaultKeyId = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyID(0~3)=%d\n", pAd->StaCfg.DefaultKeyId)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ for (idx = 0; idx < 4; idx++) ++ { ++ sprintf(tok_str, "Key%dType", idx + 1); ++ //Key1Type ++ if (RTMPGetKeyParameter(tok_str, tmpbuf, 128, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ KeyType[i] = simple_strtol(macptr, 0, 10); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ sprintf(tok_str, "Key%dStr", idx + 1); ++ if (RTMPGetCriticalParameter(tok_str, tmpbuf, 128, buffer)) ++ { ++ rtmp_parse_key_buffer_from_file(pAd, tmpbuf, KeyType[BSS0], BSS0, idx); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ } ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) ++{ ++ PUCHAR macptr; ++ INT i=0; ++ BOOLEAN bWmmEnable = FALSE; ++ ++ //WmmCapable ++ if(RTMPGetKeyParameter("WmmCapable", tmpbuf, 32, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ { ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ bWmmEnable = TRUE; ++ } ++ else //Disable ++ { ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WmmCapable=%d\n", pAd->CommonCfg.bWmmCapable)); ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ //DLSCapable ++ if(RTMPGetKeyParameter("DLSCapable", tmpbuf, 32, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ { ++ pAd->CommonCfg.bDLSCapable = TRUE; ++ } ++ else //Disable ++ { ++ pAd->CommonCfg.bDLSCapable = FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("bDLSCapable=%d\n", pAd->CommonCfg.bDLSCapable)); ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ //AckPolicy for AC_BK, AC_BE, AC_VI, AC_VO ++ if(RTMPGetKeyParameter("AckPolicy", tmpbuf, 32, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ pAd->CommonCfg.AckPolicy[i] = (UCHAR)simple_strtol(macptr, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AckPolicy[%d]=%d\n", i, pAd->CommonCfg.AckPolicy[i])); ++ } ++ } ++ ++ if (bWmmEnable) ++ { ++ //APSDCapable ++ if(RTMPGetKeyParameter("APSDCapable", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bAPSDCapable = TRUE; ++ else ++ pAd->CommonCfg.bAPSDCapable = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("APSDCapable=%d\n", pAd->CommonCfg.bAPSDCapable)); ++ } ++ ++ //APSDAC for AC_BE, AC_BK, AC_VI, AC_VO ++ if(RTMPGetKeyParameter("APSDAC", tmpbuf, 32, buffer)) ++ { ++ BOOLEAN apsd_ac[4]; ++ ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ apsd_ac[i] = (BOOLEAN)simple_strtol(macptr, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("APSDAC%d %d\n", i, apsd_ac[i])); ++ } ++ ++ pAd->CommonCfg.bAPSDAC_BE = apsd_ac[0]; ++ pAd->CommonCfg.bAPSDAC_BK = apsd_ac[1]; ++ pAd->CommonCfg.bAPSDAC_VI = apsd_ac[2]; ++ pAd->CommonCfg.bAPSDAC_VO = apsd_ac[3]; ++ } ++ } ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++NDIS_STATUS RTMPReadParametersHook( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PUCHAR src = NULL; ++ struct file *srcf; ++ INT retval, orgfsuid, orgfsgid; ++ mm_segment_t orgfs; ++ CHAR *buffer; ++ CHAR *tmpbuf; ++ ULONG RtsThresh; ++ ULONG FragThresh; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR keyMaterial[40]; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ PUCHAR macptr; ++ INT i = 0; ++ ++ buffer = kmalloc(MAX_INI_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ if(buffer == NULL) ++ return NDIS_STATUS_FAILURE; ++ ++ tmpbuf = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ if(tmpbuf == NULL) ++ { ++ kfree(buffer); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ src = STA_PROFILE_PATH; ++#endif // CONFIG_STA_SUPPORT // ++#ifdef MULTIPLE_CARD_SUPPORT ++ src = pAd->MC_FileName; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ // Save uid and gid used for filesystem access. ++ // Set user and group to 0 (root) ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid=current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ if (src && *src) ++ { ++ srcf = filp_open(src, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); ++ } ++ else ++ { ++ // The object must have a read method ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); ++ retval=srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); ++ if (retval < 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Read %s error %d\n", src, -retval)); ++ } ++ else ++ { ++ // set file parameter to portcfg ++ //CountryRegion ++ if(RTMPGetKeyParameter("CountryRegion", tmpbuf, 25, buffer)) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryRegion=%d\n", pAd->CommonCfg.CountryRegion)); ++ } ++ //CountryRegionABand ++ if(RTMPGetKeyParameter("CountryRegionABand", tmpbuf, 25, buffer)) ++ { ++ pAd->CommonCfg.CountryRegionForABand= (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryRegionABand=%d\n", pAd->CommonCfg.CountryRegionForABand)); ++ } ++ //CountryCode ++ if(RTMPGetKeyParameter("CountryCode", tmpbuf, 25, buffer)) ++ { ++ NdisMoveMemory(pAd->CommonCfg.CountryCode, tmpbuf , 2); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(pAd->StaCfg.StaOriCountryCode, tmpbuf , 2); ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ if (strlen(pAd->CommonCfg.CountryCode) != 0) ++ { ++ pAd->CommonCfg.bCountryFlag = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryCode=%s\n", pAd->CommonCfg.CountryCode)); ++ } ++ //ChannelGeography ++ if(RTMPGetKeyParameter("ChannelGeography", tmpbuf, 25, buffer)) ++ { ++ UCHAR Geography = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ if (Geography <= BOTH) ++ { ++ pAd->CommonCfg.Geography = Geography; ++ pAd->CommonCfg.CountryCode[2] = ++ (pAd->CommonCfg.Geography == BOTH) ? ' ' : ((pAd->CommonCfg.Geography == IDOR) ? 'I' : 'O'); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.StaOriGeography = pAd->CommonCfg.Geography; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelGeography=%d\n", pAd->CommonCfg.Geography)); ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.Geography = BOTH; ++ pAd->CommonCfg.CountryCode[2] = ' '; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //SSID ++ if (RTMPGetCriticalParameter("SSID", tmpbuf, 256, buffer)) ++ { ++ if (strlen(tmpbuf) <= 32) ++ { ++ pAd->CommonCfg.SsidLen = (UCHAR) strlen(tmpbuf); ++ NdisZeroMemory(pAd->CommonCfg.Ssid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->CommonCfg.Ssid, tmpbuf, pAd->CommonCfg.SsidLen); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->CommonCfg.SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, tmpbuf, pAd->MlmeAux.AutoReconnectSsidLen); ++ pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //NetworkType ++ if (RTMPGetKeyParameter("NetworkType", tmpbuf, 25, buffer)) ++ { ++ pAd->bConfigChanged = TRUE; ++ if (strcmp(tmpbuf, "Adhoc") == 0) ++ pAd->StaCfg.BssType = BSS_ADHOC; ++ else //Default Infrastructure mode ++ pAd->StaCfg.BssType = BSS_INFRA; ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ //Channel ++ if(RTMPGetKeyParameter("Channel", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.Channel = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("Channel=%d\n", pAd->CommonCfg.Channel)); ++ } ++ //WirelessMode ++ if(RTMPGetKeyParameter("WirelessMode", tmpbuf, 10, buffer)) ++ { ++ int value = 0, maxPhyMode = PHY_11G; ++ ++#ifdef DOT11_N_SUPPORT ++ maxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ value = simple_strtol(tmpbuf, 0, 10); ++ ++ if (value <= maxPhyMode) ++ { ++ pAd->CommonCfg.PhyMode = value; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("PhyMode=%d\n", pAd->CommonCfg.PhyMode)); ++ } ++ //BasicRate ++ if(RTMPGetKeyParameter("BasicRate", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.BasicRateBitmap = (ULONG) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("BasicRate=%ld\n", pAd->CommonCfg.BasicRateBitmap)); ++ } ++ //BeaconPeriod ++ if(RTMPGetKeyParameter("BeaconPeriod", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.BeaconPeriod = (USHORT) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconPeriod=%d\n", pAd->CommonCfg.BeaconPeriod)); ++ } ++ //TxPower ++ if(RTMPGetKeyParameter("TxPower", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.TxPowerPercentage = (ULONG) simple_strtol(tmpbuf, 0, 10); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPower=%ld\n", pAd->CommonCfg.TxPowerPercentage)); ++ } ++ //BGProtection ++ if(RTMPGetKeyParameter("BGProtection", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //Always On ++ pAd->CommonCfg.UseBGProtection = 1; ++ break; ++ case 2: //Always OFF ++ pAd->CommonCfg.UseBGProtection = 2; ++ break; ++ case 0: //AUTO ++ default: ++ pAd->CommonCfg.UseBGProtection = 0; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("BGProtection=%ld\n", pAd->CommonCfg.UseBGProtection)); ++ } ++ //OLBCDetection ++ if(RTMPGetKeyParameter("DisableOLBC", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //disable OLBC Detection ++ pAd->CommonCfg.DisableOLBCDetect = 1; ++ break; ++ case 0: //enable OLBC Detection ++ pAd->CommonCfg.DisableOLBCDetect = 0; ++ break; ++ default: ++ pAd->CommonCfg.DisableOLBCDetect= 0; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("OLBCDetection=%ld\n", pAd->CommonCfg.DisableOLBCDetect)); ++ } ++ //TxPreamble ++ if(RTMPGetKeyParameter("TxPreamble", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case Rt802_11PreambleShort: ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleShort; ++ break; ++ case Rt802_11PreambleLong: ++ default: ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleLong; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPreamble=%ld\n", pAd->CommonCfg.TxPreamble)); ++ } ++ //RTSThreshold ++ if(RTMPGetKeyParameter("RTSThreshold", tmpbuf, 10, buffer)) ++ { ++ RtsThresh = simple_strtol(tmpbuf, 0, 10); ++ if( (RtsThresh >= 1) && (RtsThresh <= MAX_RTS_THRESHOLD) ) ++ pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ else ++ pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTSThreshold=%d\n", pAd->CommonCfg.RtsThreshold)); ++ } ++ //FragThreshold ++ if(RTMPGetKeyParameter("FragThreshold", tmpbuf, 10, buffer)) ++ { ++ FragThresh = simple_strtol(tmpbuf, 0, 10); ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { //illegal FragThresh so we set it to default ++ pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else if (FragThresh % 2 == 1) ++ { ++ // The length of each fragment shall always be an even number of octets, except for the last fragment ++ // of an MSDU or MMPDU, which may be either an even or an odd number of octets. ++ pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); ++ } ++ else ++ { ++ pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ //pAd->CommonCfg.AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; ++ DBGPRINT(RT_DEBUG_TRACE, ("FragThreshold=%d\n", pAd->CommonCfg.FragmentThreshold)); ++ } ++ //TxBurst ++ if(RTMPGetKeyParameter("TxBurst", tmpbuf, 10, buffer)) ++ { ++//#ifdef WIFI_TEST ++// pAd->CommonCfg.bEnableTxBurst = FALSE; ++//#else ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bEnableTxBurst = TRUE; ++ else //Disable ++ pAd->CommonCfg.bEnableTxBurst = FALSE; ++//#endif ++ DBGPRINT(RT_DEBUG_TRACE, ("TxBurst=%d\n", pAd->CommonCfg.bEnableTxBurst)); ++ } ++ ++#ifdef AGGREGATION_SUPPORT ++ //PktAggregate ++ if(RTMPGetKeyParameter("PktAggregate", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bAggregationCapable = TRUE; ++ else //Disable ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++#ifdef PIGGYBACK_SUPPORT ++ pAd->CommonCfg.bPiggyBackCapable = pAd->CommonCfg.bAggregationCapable; ++#endif // PIGGYBACK_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("PktAggregate=%d\n", pAd->CommonCfg.bAggregationCapable)); ++ } ++#else ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++ pAd->CommonCfg.bPiggyBackCapable = FALSE; ++#endif // AGGREGATION_SUPPORT // ++ ++ // WmmCapable ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); ++#endif // CONFIG_STA_SUPPORT // ++ ++ //ShortSlot ++ if(RTMPGetKeyParameter("ShortSlot", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bUseShortSlotTime = TRUE; ++ else //Disable ++ pAd->CommonCfg.bUseShortSlotTime = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortSlot=%d\n", pAd->CommonCfg.bUseShortSlotTime)); ++ } ++ //IEEE80211H ++ if(RTMPGetKeyParameter("IEEE80211H", tmpbuf, 10, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ if(simple_strtol(macptr, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bIEEE80211H = TRUE; ++ else //Disable ++ pAd->CommonCfg.bIEEE80211H = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IEEE80211H=%d\n", pAd->CommonCfg.bIEEE80211H)); ++ } ++ } ++ //CSPeriod ++ if(RTMPGetKeyParameter("CSPeriod", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.RadarDetect.CSPeriod = simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.RadarDetect.CSPeriod = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CSPeriod=%d\n", pAd->CommonCfg.RadarDetect.CSPeriod)); ++ } ++ ++ //RDRegion ++ if(RTMPGetKeyParameter("RDRegion", tmpbuf, 128, buffer)) ++ { ++ if ((strncmp(tmpbuf, "JAP_W53", 7) == 0) || (strncmp(tmpbuf, "jap_w53", 7) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W53; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 15; ++ } ++ else if ((strncmp(tmpbuf, "JAP_W56", 7) == 0) || (strncmp(tmpbuf, "jap_w56", 7) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W56; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ else if ((strncmp(tmpbuf, "JAP", 3) == 0) || (strncmp(tmpbuf, "jap", 3) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; ++ } ++ else if ((strncmp(tmpbuf, "FCC", 3) == 0) || (strncmp(tmpbuf, "fcc", 3) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = FCC; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; ++ } ++ else if ((strncmp(tmpbuf, "CE", 2) == 0) || (strncmp(tmpbuf, "ce", 2) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ else ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RDRegion=%d\n", pAd->CommonCfg.RadarDetect.RDDurRegion)); ++ } ++ else ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ ++ //WirelessEvent ++ if(RTMPGetKeyParameter("WirelessEvent", tmpbuf, 10, buffer)) ++ { ++#if WIRELESS_EXT >= 15 ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.bWirelessEvent = simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.bWirelessEvent = 0; // disable ++#else ++ pAd->CommonCfg.bWirelessEvent = 0; // disable ++#endif ++ DBGPRINT(RT_DEBUG_TRACE, ("WirelessEvent=%d\n", pAd->CommonCfg.bWirelessEvent)); ++ } ++ if(RTMPGetKeyParameter("WiFiTest", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.bWiFiTest= simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.bWiFiTest = 0; // disable ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WiFiTest=%d\n", pAd->CommonCfg.bWiFiTest)); ++ } ++ //AuthMode ++ if(RTMPGetKeyParameter("AuthMode", tmpbuf, 128, buffer)) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((strcmp(tmpbuf, "WEPAUTO") == 0) || (strcmp(tmpbuf, "wepauto") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(tmpbuf, "SHARED") == 0) || (strcmp(tmpbuf, "shared") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(tmpbuf, "WPAPSK") == 0) || (strcmp(tmpbuf, "wpapsk") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(tmpbuf, "WPANONE") == 0) || (strcmp(tmpbuf, "wpanone") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(tmpbuf, "WPA2PSK") == 0) || (strcmp(tmpbuf, "wpa2psk") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(tmpbuf, "WPA") == 0) || (strcmp(tmpbuf, "wpa") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(tmpbuf, "WPA2") == 0) || (strcmp(tmpbuf, "wpa2") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ //EncrypType ++ if(RTMPGetKeyParameter("EncrypType", tmpbuf, 128, buffer)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ else if ((strcmp(tmpbuf, "TKIP") == 0) || (strcmp(tmpbuf, "tkip") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ else if ((strcmp(tmpbuf, "AES") == 0) || (strcmp(tmpbuf, "aes") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ else ++ pAd->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ ++ // Update all wepstatus related ++ pAd->StaCfg.PairCipher = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.bMixCipher = FALSE; ++ ++ //RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if(RTMPGetCriticalParameter("WPAPSK", tmpbuf, 512, buffer)) ++ { ++ int err=0; ++ ++ tmpbuf[strlen(tmpbuf)] = '\0'; // make STA can process .$^& for WPAPSK input ++ ++ if ((pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ { ++ err = 1; ++ } ++ else if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) < 64)) ++ { ++ PasswordHash((char *)tmpbuf, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, keyMaterial); ++ NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else if (strlen(tmpbuf) == 64) ++ { ++ AtoH(tmpbuf, keyMaterial, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); ++ } ++ else ++ { ++ err = 1; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__)); ++ } ++ ++ if (err == 0) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // Start STA supplicant state machine ++ pAd->StaCfg.WpaState = SS_START; ++ } ++ else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ /* ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ */ ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ //DefaultKeyID, KeyType, KeyStr ++ rtmp_read_key_parms_from_file(pAd, tmpbuf, buffer); ++ ++ ++ //HSCounter ++ /*if(RTMPGetKeyParameter("HSCounter", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //Enable ++ pAd->CommonCfg.bEnableHSCounter = TRUE; ++ break; ++ case 0: //Disable ++ default: ++ pAd->CommonCfg.bEnableHSCounter = FALSE; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, "HSCounter=%d\n", pAd->CommonCfg.bEnableHSCounter); ++ }*/ ++ ++#ifdef DOT11_N_SUPPORT ++ HTParametersHook(pAd, tmpbuf, buffer); ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++ //CarrierDetect ++ if(RTMPGetKeyParameter("CarrierDetect", tmpbuf, 128, buffer)) ++ { ++ if ((strncmp(tmpbuf, "0", 1) == 0)) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else if ((strncmp(tmpbuf, "1", 1) == 0)) ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CarrierDetect.Enable=%d\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ } ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //PSMode ++ if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) ++ { ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(tmpbuf, "MAX_PSP") == 0) || (strcmp(tmpbuf, "max_psp") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsm(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAd->StaCfg.DefaultListenCount = 5; ++ } ++ else if ((strcmp(tmpbuf, "Fast_PSP") == 0) || (strcmp(tmpbuf, "fast_psp") == 0) ++ || (strcmp(tmpbuf, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsmBit(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAd->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(tmpbuf, "Legacy_PSP") == 0) || (strcmp(tmpbuf, "legacy_psp") == 0) ++ || (strcmp(tmpbuf, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsmBit(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAd->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("PSMode=%ld\n", pAd->StaCfg.WindowsPowerMode)); ++ } ++ } ++ // FastRoaming ++ if (RTMPGetKeyParameter("FastRoaming", tmpbuf, 32, buffer)) ++ { ++ if (simple_strtol(tmpbuf, 0, 10) == 0) ++ pAd->StaCfg.bFastRoaming = FALSE; ++ else ++ pAd->StaCfg.bFastRoaming = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FastRoaming=%d\n", pAd->StaCfg.bFastRoaming)); ++ } ++ // RoamThreshold ++ if (RTMPGetKeyParameter("RoamThreshold", tmpbuf, 32, buffer)) ++ { ++ long lInfo = simple_strtol(tmpbuf, 0, 10); ++ ++ if (lInfo > 90 || lInfo < 60) ++ pAd->StaCfg.dBmToRoam = -70; ++ else ++ pAd->StaCfg.dBmToRoam = (CHAR)(-1)*lInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RoamThreshold=%d dBm\n", pAd->StaCfg.dBmToRoam)); ++ } ++ ++ if(RTMPGetKeyParameter("TGnWifiTest", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("TGnWifiTest=%d\n", pAd->StaCfg.bTGnWifiTest)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> %s does not have a write method\n", src)); ++ } ++ ++ retval=filp_close(srcf,NULL); ++ ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); ++ } ++ } ++ } ++ ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ ++ kfree(buffer); ++ kfree(tmpbuf); ++ ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++#ifdef DOT11_N_SUPPORT ++static void HTParametersHook( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR *pValueStr, ++ IN CHAR *pInput) ++{ ++ ++ INT Value; ++ ++ if (RTMPGetKeyParameter("HT_PROTECT", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bHTProtect = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bHTProtect = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Protection = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ if (RTMPGetKeyParameter("HT_MIMOPSEnable", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bMIMOPSEnable = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPSEnable = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ ++ if (RTMPGetKeyParameter("HT_MIMOPSMode", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value > MMPS_ENABLE) ++ { ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ } ++ else ++ { ++ //TODO: add mimo power saving mechanism ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ //pAd->CommonCfg.BACapability.field.MMPSmode = Value; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPS Mode = %d\n", Value)); ++ } ++ ++ if (RTMPGetKeyParameter("HT_BADecline", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bBADecline = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bBADecline = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Decline = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ ++ if (RTMPGetKeyParameter("HT_DisableReordering", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bDisableReordering = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bDisableReordering = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: DisableReordering = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ if (RTMPGetKeyParameter("HT_AutoBA", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ } ++ pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Auto BA = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // Tx_+HTC frame ++ if (RTMPGetKeyParameter("HT_HTC", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->HTCEnable = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx +HTC frame = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // Enable HT Link Adaptation Control ++ if (RTMPGetKeyParameter("HT_LinkAdapt", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->bLinkAdapt = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->bLinkAdapt = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Link Adaptation Control = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); ++ } ++ ++ // Reverse Direction Mechanism ++ if (RTMPGetKeyParameter("HT_RDG", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bRdg = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->CommonCfg.bRdg = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: RDG = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); ++ } ++ ++ ++ ++ ++ // Tx A-MSUD ? ++ if (RTMPGetKeyParameter("HT_AMSDU", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx A-MSDU = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // MPDU Density ++ if (RTMPGetKeyParameter("HT_MpduDensity", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value <=7 && Value >= 0) ++ { ++ pAd->CommonCfg.BACapability.field.MpduDensity = Value; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d\n", Value)); ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.MpduDensity = 4; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d (Default)\n", 4)); ++ } ++ } ++ ++ // Max Rx BA Window Size ++ if (RTMPGetKeyParameter("HT_BAWinSize", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value >=1 && Value <= 64) ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = %d\n", Value)); ++ } ++ else ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = 64 (Defualt)\n")); ++ } ++ ++ } ++ ++ // Guard Interval ++ if (RTMPGetKeyParameter("HT_GI", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == GI_400) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Guard Interval = %s\n", (Value==GI_400) ? "400" : "800" )); ++ } ++ ++ // HT Operation Mode : Mixed Mode , Green Field ++ if (RTMPGetKeyParameter("HT_OpMode", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == HTMODE_GF) ++ { ++ ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Operate Mode = %s\n", (Value==HTMODE_GF) ? "Green Field" : "Mixed Mode" )); ++ } ++ ++ // Fixed Tx mode : CCK, OFDM ++ if (RTMPGetKeyParameter("FixedTxMode", pValueStr, 25, pInput)) ++ { ++ UCHAR fix_tx_mode; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ fix_tx_mode = FIXED_TXMODE_HT; ++ ++ if (strcmp(pValueStr, "OFDM") == 0 || strcmp(pValueStr, "ofdm") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_OFDM; ++ } ++ else if (strcmp(pValueStr, "CCK") == 0 || strcmp(pValueStr, "cck") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_CCK; ++ } ++ else if (strcmp(pValueStr, "HT") == 0 || strcmp(pValueStr, "ht") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_HT; ++ } ++ else ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ // 1 : CCK ++ // 2 : OFDM ++ // otherwise : HT ++ if (Value == FIXED_TXMODE_CCK || Value == FIXED_TXMODE_OFDM) ++ fix_tx_mode = Value; ++ else ++ fix_tx_mode = FIXED_TXMODE_HT; ++ } ++ ++ pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; ++ DBGPRINT(RT_DEBUG_TRACE, ("Fixed Tx Mode = %d\n", fix_tx_mode)); ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ // Channel Width ++ if (RTMPGetKeyParameter("HT_BW", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == BW_40) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } ++ ++#ifdef MCAST_RATE_SPECIFIC ++ pAd->CommonCfg.MCastPhyMode.field.BW = pAd->CommonCfg.RegTransmitSetting.field.BW; ++#endif // MCAST_RATE_SPECIFIC // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Channel Width = %s\n", (Value==BW_40) ? "40 MHz" : "20 MHz" )); ++ } ++ ++ if (RTMPGetKeyParameter("HT_EXTCHA", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == 0) ++ { ++ ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Ext Channel = %s\n", (Value==0) ? "BELOW" : "ABOVE" )); ++ } ++ ++ // MSC ++ if (RTMPGetKeyParameter("HT_MCS", pValueStr, 50, pInput)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++// if ((Value >= 0 && Value <= 15) || (Value == 32)) ++ if ((Value >= 0 && Value <= 23) || (Value == 32)) // 3*3 ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = Value; ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = %d\n", pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = AUTO\n")); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // STBC ++ if (RTMPGetKeyParameter("HT_STBC", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == STBC_USE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: STBC = %d\n", pAd->CommonCfg.RegTransmitSetting.field.STBC)); ++ } ++ ++ // 40_Mhz_Intolerant ++ if (RTMPGetKeyParameter("HT_40MHZ_INTOLERANT", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bForty_Mhz_Intolerant = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bForty_Mhz_Intolerant = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: 40MHZ INTOLERANT = %d\n", pAd->CommonCfg.bForty_Mhz_Intolerant)); ++ } ++ //HT_TxStream ++ if(RTMPGetKeyParameter("HT_TxStream", pValueStr, 10, pInput)) ++ { ++ switch (simple_strtol(pValueStr, 0, 10)) ++ { ++ case 1: ++ pAd->CommonCfg.TxStream = 1; ++ break; ++ case 2: ++ pAd->CommonCfg.TxStream = 2; ++ break; ++ case 3: // 3*3 ++ default: ++ pAd->CommonCfg.TxStream = 3; ++ ++ if (pAd->MACVersion < RALINK_2883_VERSION) ++ pAd->CommonCfg.TxStream = 2; // only 2 tx streams for RT2860 series ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx Stream = %d\n", pAd->CommonCfg.TxStream)); ++ } ++ //HT_RxStream ++ if(RTMPGetKeyParameter("HT_RxStream", pValueStr, 10, pInput)) ++ { ++ switch (simple_strtol(pValueStr, 0, 10)) ++ { ++ case 1: ++ pAd->CommonCfg.RxStream = 1; ++ break; ++ case 2: ++ pAd->CommonCfg.RxStream = 2; ++ break; ++ case 3: ++ default: ++ pAd->CommonCfg.RxStream = 3; ++ ++ if (pAd->MACVersion < RALINK_2883_VERSION) ++ pAd->CommonCfg.RxStream = 2; // only 2 rx streams for RT2860 series ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Rx Stream = %d\n", pAd->CommonCfg.RxStream)); ++ } ++ ++} ++#endif // DOT11_N_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/spectrum_def.h +@@ -0,0 +1,95 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ spectrum_def.h ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ --------- ---------- ---------------------------------------------- ++ Fonchi Wu 2008 created for 802.11h ++ */ ++ ++#ifndef __SPECTRUM_DEF_H__ ++#define __SPECTRUM_DEF_H__ ++ ++#define MAX_MEASURE_REQ_TAB_SIZE 3 ++#define MAX_HASH_MEASURE_REQ_TAB_SIZE MAX_MEASURE_REQ_TAB_SIZE ++ ++#define MAX_TPC_REQ_TAB_SIZE 3 ++#define MAX_HASH_TPC_REQ_TAB_SIZE MAX_TPC_REQ_TAB_SIZE ++ ++#define MIN_RCV_PWR 100 /* Negative value ((dBm) */ ++ ++#define RM_TPC_REQ 0 ++#define RM_MEASURE_REQ 1 ++ ++#define RM_BASIC 0 ++#define RM_CCA 1 ++#define RM_RPI_HISTOGRAM 2 ++ ++#define TPC_REQ_AGE_OUT 500 /* ms */ ++#define MQ_REQ_AGE_OUT 500 /* ms */ ++ ++#define TPC_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_HASH_TPC_REQ_TAB_SIZE) ++#define MQ_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_MEASURE_REQ_TAB_SIZE) ++ ++typedef struct _MEASURE_REQ_ENTRY ++{ ++ struct _MEASURE_REQ_ENTRY *pNext; ++ ULONG lastTime; ++ BOOLEAN Valid; ++ UINT8 DialogToken; ++ UINT8 MeasureDialogToken[3]; // 0:basic measure, 1: CCA measure, 2: RPI_Histogram measure. ++} MEASURE_REQ_ENTRY, *PMEASURE_REQ_ENTRY; ++ ++typedef struct _MEASURE_REQ_TAB ++{ ++ UCHAR Size; ++ PMEASURE_REQ_ENTRY Hash[MAX_HASH_MEASURE_REQ_TAB_SIZE]; ++ MEASURE_REQ_ENTRY Content[MAX_MEASURE_REQ_TAB_SIZE]; ++} MEASURE_REQ_TAB, *PMEASURE_REQ_TAB; ++ ++typedef struct _TPC_REQ_ENTRY ++{ ++ struct _TPC_REQ_ENTRY *pNext; ++ ULONG lastTime; ++ BOOLEAN Valid; ++ UINT8 DialogToken; ++} TPC_REQ_ENTRY, *PTPC_REQ_ENTRY; ++ ++typedef struct _TPC_REQ_TAB ++{ ++ UCHAR Size; ++ PTPC_REQ_ENTRY Hash[MAX_HASH_TPC_REQ_TAB_SIZE]; ++ TPC_REQ_ENTRY Content[MAX_TPC_REQ_TAB_SIZE]; ++} TPC_REQ_TAB, *PTPC_REQ_TAB; ++ ++#endif // __SPECTRUM_DEF_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/spectrum.h +@@ -0,0 +1,322 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __SPECTRUM_H__ ++#define __SPECTRUM_H__ ++ ++#include "rtmp_type.h" ++#include "spectrum_def.h" ++ ++typedef struct PACKED _TPC_REPORT_INFO ++{ ++ UINT8 TxPwr; ++ UINT8 LinkMargin; ++} TPC_REPORT_INFO, *PTPC_REPORT_INFO; ++ ++typedef struct PACKED _CH_SW_ANN_INFO ++{ ++ UINT8 ChSwMode; ++ UINT8 Channel; ++ UINT8 ChSwCnt; ++} CH_SW_ANN_INFO, *PCH_SW_ANN_INFO; ++ ++typedef union PACKED _MEASURE_REQ_MODE ++{ ++#ifdef RT_BIG_ENDIAN ++ struct PACKED ++ { ++ UINT8 Rev1:4; ++ UINT8 Report:1; ++ UINT8 Request:1; ++ UINT8 Enable:1; ++ UINT8 Rev0:1; ++ } field; ++#else ++ struct PACKED ++ { ++ UINT8 Rev0:1; ++ UINT8 Enable:1; ++ UINT8 Request:1; ++ UINT8 Report:1; ++ UINT8 Rev1:4; ++ } field; ++#endif // RT_BIG_ENDIAN // ++ UINT8 word; ++} MEASURE_REQ_MODE, *PMEASURE_REQ_MODE; ++ ++typedef struct PACKED _MEASURE_REQ ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++} MEASURE_REQ, *PMEASURE_REQ; ++ ++typedef struct PACKED _MEASURE_REQ_INFO ++{ ++ UINT8 Token; ++ MEASURE_REQ_MODE ReqMode; ++ UINT8 ReqType; ++ MEASURE_REQ MeasureReq; ++} MEASURE_REQ_INFO, *PMEASURE_REQ_INFO; ++ ++typedef union PACKED _MEASURE_BASIC_REPORT_MAP ++{ ++#ifdef RT_BIG_ENDIAN ++ struct PACKED ++ { ++ UINT8 Rev:3; ++ UINT8 Unmeasure:1; ++ UINT8 Radar:1; ++ UINT8 UnidentifiedSignal:1; ++ UINT8 OfdmPreamble:1; ++ UINT8 BSS:1; ++ } field; ++#else ++ struct PACKED ++ { ++ UINT8 BSS:1; ++ UINT8 OfdmPreamble:1; ++ UINT8 UnidentifiedSignal:1; ++ UINT8 Radar:1; ++ UINT8 Unmeasure:1; ++ UINT8 Rev:3; ++ } field; ++#endif // RT_BIG_ENDIAN // ++ UINT8 word; ++} MEASURE_BASIC_REPORT_MAP, *PMEASURE_BASIC_REPORT_MAP; ++ ++typedef struct PACKED _MEASURE_BASIC_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ MEASURE_BASIC_REPORT_MAP Map; ++} MEASURE_BASIC_REPORT, *PMEASURE_BASIC_REPORT; ++ ++typedef struct PACKED _MEASURE_CCA_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ UINT8 CCA_Busy_Fraction; ++} MEASURE_CCA_REPORT, *PMEASURE_CCA_REPORT; ++ ++typedef struct PACKED _MEASURE_RPI_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ UINT8 RPI_Density[8]; ++} MEASURE_RPI_REPORT, *PMEASURE_RPI_REPORT; ++ ++typedef union PACKED _MEASURE_REPORT_MODE ++{ ++ struct PACKED ++ { ++#ifdef RT_BIG_ENDIAN ++ UINT8 Rev:5; ++ UINT8 Refused:1; ++ UINT8 Incapable:1; ++ UINT8 Late:1; ++#else ++ UINT8 Late:1; ++ UINT8 Incapable:1; ++ UINT8 Refused:1; ++ UINT8 Rev:5; ++#endif // RT_BIG_ENDIAN // ++ } field; ++ UINT8 word; ++} MEASURE_REPORT_MODE, *PMEASURE_REPORT_MODE; ++ ++typedef struct PACKED _MEASURE_REPORT_INFO ++{ ++ UINT8 Token; ++ MEASURE_REPORT_MODE ReportMode; ++ UINT8 ReportType; ++ UINT8 Octect[0]; ++} MEASURE_REPORT_INFO, *PMEASURE_REPORT_INFO; ++ ++typedef struct PACKED _QUIET_INFO ++{ ++ UINT8 QuietCnt; ++ UINT8 QuietPeriod; ++ UINT8 QuietDuration; ++ UINT8 QuietOffset; ++} QUIET_INFO, *PQUIET_INFO; ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 MeasureCh, ++ IN UINT16 MeasureDuration); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 ReportInfoLen, ++ IN PUINT8 pReportInfo); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UCHAR DialogToken); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Channel Switch Announcement action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ 2. Channel switch announcement mode. ++ 2. a New selected channel. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueChSwAnn( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewCh); ++ ++/* ++ ========================================================================== ++ Description: ++ Spectrun action frames Handler such as channel switch annoucement, ++ measurement report, measurement request actions frames. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID PeerSpectrumAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Parametrs: ++ ++ Return : None. ++ ========================================================================== ++ */ ++INT Set_MeasureReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TpcReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++VOID MeasureReqTabInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MeasureReqTabExit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID TpcReqTabInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID TpcReqTabExit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NotifyChSwAnnToPeerAPs( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRA, ++ IN PUCHAR pTA, ++ IN UINT8 ChSwMode, ++ IN UINT8 Channel); ++#endif // __SPECTRUM_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/aironet.c +@@ -0,0 +1,1312 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 04-06-15 Initial ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ========================================================================== ++ */ ++VOID AironetStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE); ++ StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction); ++ StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction); ++ StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This is state machine function. ++ When receiving EAPOL packets which is for 802.1x key management. ++ Use both in WPA, and WPAPSK case. ++ In this function, further dispatch to different functions according to the received packet. 3 categories are : ++ 1. normal 4-way pairwisekey and 2-way groupkey handshake ++ 2. MIC error (Countermeasures attack) report packet from STA. ++ 3. Request for pairwise/group key update from STA ++ Return: ++ ========================================================================== ++*/ ++VOID AironetMsgAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Length; ++ UCHAR Index, i; ++ PUCHAR pData; ++ PAIRONET_RM_REQUEST_FRAME pRMReq; ++ PRM_REQUEST_ACTION pReqElem; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n")); ++ ++ // 0. Get Aironet IAPP header first ++ pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11]; ++ pData = (PUCHAR) &Elem->Msg[LENGTH_802_11]; ++ ++ // 1. Change endian format form network to little endian ++ Length = be2cpu16(pRMReq->IAPP.Length); ++ ++ // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled ++ if (pAd->StaCfg.CCXEnable != TRUE) ++ return; ++ ++ // 2.1 Radio measurement must be on ++ if (pAd->StaCfg.CCXControl.field.RMEnable != 1) ++ return; ++ ++ // 2.2. Debug print all bit information ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset)); ++ ++ // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension ++ if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n")); ++ return; ++ } ++ ++ // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request. ++ // Since we are acting as client only, we will disregards reply subtype. ++ if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n")); ++ return; ++ } ++ ++ // 5. Verify Destination MAC and Source MAC, both should be all zeros. ++ if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n")); ++ return; ++ } ++ ++ if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n")); ++ return; ++ } ++ ++ // 6. Reinit all report related fields ++ NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048); ++ NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE); ++ NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4); ++ ++ // 7. Point to the start of first element report element ++ pAd->StaCfg.FrameReportLen = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER); ++ DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); ++ pAd->StaCfg.LastBssIndex = 0xff; ++ pAd->StaCfg.RMReqCnt = 0; ++ pAd->StaCfg.ParallelReq = FALSE; ++ pAd->StaCfg.ParallelDuration = 0; ++ pAd->StaCfg.ParallelChannel = 0; ++ pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; ++ pAd->StaCfg.CurrentRMReqIdx = 0; ++ pAd->StaCfg.CLBusyBytes = 0; ++ // Reset the statistics ++ for (i = 0; i < 8; i++) ++ pAd->StaCfg.RPIDensity[i] = 0; ++ ++ Index = 0; ++ ++ // 8. Save dialog token for report ++ pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; ++ ++ // Save Activation delay & measurement offset, Not really needed ++ ++ // 9. Point to the first request element ++ pData += sizeof(AIRONET_RM_REQUEST_FRAME); ++ // Length should exclude the CISCO Aironet SNAP header ++ Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H); ++ ++ // 10. Start Parsing the Measurement elements. ++ // Be careful about multiple MR elements within one frames. ++ while (Length > 0) ++ { ++ pReqElem = (PRM_REQUEST_ACTION) pData; ++ switch (pReqElem->ReqElem.Eid) ++ { ++ case IE_MEASUREMENT_REQUEST: ++ // From the example, it seems we only need to support one request in one frame ++ // There is no multiple request in one frame. ++ // Besides, looks like we need to take care the measurement request only. ++ // The measurement request is always 4 bytes. ++ ++ // Start parsing this type of request. ++ // 0. Eid is IE_MEASUREMENT_REQUEST ++ // 1. Length didn't include Eid and Length field, it always be 8. ++ // 2. Measurement Token, we nned to save it for the corresponding report. ++ // 3. Measurement Mode, Although there are definitions, but we din't see value other than ++ // 0 from test specs examples. ++ // 4. Measurement Type, this is what we need to do. ++ switch (pReqElem->ReqElem.Type) ++ { ++ case MSRN_TYPE_CHANNEL_LOAD_REQ: ++ case MSRN_TYPE_NOISE_HIST_REQ: ++ case MSRN_TYPE_BEACON_REQ: ++ // Check the Enable non-serving channel measurement control ++ if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0) ++ { ++ // Check channel before enqueue the action ++ if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) ++ break; ++ } ++ else ++ { ++ // If off channel measurement, check the TU duration limit ++ if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) ++ if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit) ++ break; ++ } ++ ++ // Save requests and execute actions later ++ NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION)); ++ Index += 1; ++ break; ++ ++ case MSRN_TYPE_FRAME_REQ: ++ // Since it's option, we will support later ++ // FrameRequestAction(pAd, pData); ++ break; ++ ++ default: ++ break; ++ } ++ ++ // Point to next Measurement request ++ pData += sizeof(RM_REQUEST_ACTION); ++ Length -= sizeof(RM_REQUEST_ACTION); ++ break; ++ ++ // We accept request only, all others are dropped ++ case IE_MEASUREMENT_REPORT: ++ case IE_AP_TX_POWER: ++ case IE_MEASUREMENT_CAPABILITY: ++ default: ++ return; ++ } ++ } ++ ++ // 11. Update some flags and index ++ pAd->StaCfg.RMReqCnt = Index; ++ ++ if (Index) ++ { ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRM_REQUEST_ACTION pReq; ++ ++ // 1. Point to next request element ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ // 2. Parse measurement type and call appropriate functions ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) ++ // Beacon measurement request ++ BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else ++ // Unknown. Do nothing and return, this should never happen ++ return; ++ ++ // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one ++ if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt) ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1]; ++ // Check for parallel bit ++ if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel)) ++ { ++ // Update parallel mode request information ++ pAd->StaCfg.ParallelReq = TRUE; ++ pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ? ++ (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime)); ++ } ++ } ++ ++ // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used ++ RT28XX_MLME_HANDLER(pAd); ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare channel load report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ChannelLoadRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32]; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ // Passive scan Mode ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer;; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_CHANNEL_LOAD_REQ; ++ pAd->StaCfg.CLBusyBytes = 0; ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); ++ ++ // Set channel load measurement flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare noise histogram report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NoiseHistRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32], i; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ // Passive scan Mode ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_NOISE_HIST_REQ; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ // Reset the statistics ++ for (i = 0; i < 8; i++) ++ pAd->StaCfg.RPIDensity[i] = 0; ++ ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); ++ ++ // Set channel load measurement flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare Beacon report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID BeaconRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE) ++ { ++ // Passive scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n")); ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ } ++ else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE) ++ { ++ // Active scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n")); ++ ++ // Control state machine is not idle, reject the request ++ if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ } ++ else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE) ++ { ++ // Beacon report Mode, report all the APS in current bss table ++ DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n")); ++ ++ // Copy current BSS table to CCX table, we can omit this step later on. ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE)); ++ ++ // Create beacon report from Bss table ++ AironetCreateBeaconReportFromBssTable(pAd); ++ ++ // Set state to scanning ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ // Enqueue report request ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++ else ++ { ++ // Wrong scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n")); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRM_REQUEST_ACTION pReq; ++ ULONG Now32; ++ ++ NdisGetSystemUpTime(&Now32); ++ pAd->StaCfg.LastBeaconRxTime = Now32; ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n")); ++ ++ // 1. Parse measurement type and call appropriate functions ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) ++ // Beacon measurement request ++ BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else ++ // Unknown. Do nothing and return ++ ; ++ ++ // 2. Point to the correct index of action element, start from 0 ++ pAd->StaCfg.CurrentRMReqIdx++; ++ ++ // 3. Check for parallel actions ++ if (pAd->StaCfg.ParallelReq == TRUE) ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ // Process next action right away ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ ++ pAd->StaCfg.ParallelReq = FALSE; ++ pAd->StaCfg.CurrentRMReqIdx++; ++ } ++ ++ if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt) ++ { ++ // 4. There is no more unprocessed measurement request, go for transmit this report ++ AironetFinalReportAction(pAd); ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ } ++ else ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ if (pReq->Measurement.Channel != pAd->CommonCfg.Channel) ++ { ++ RTMPusecDelay(100000); ++ } ++ ++ // 5. There are more requests to be measure ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetFinalReportAction( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PUCHAR pDest; ++ PAIRONET_IAPP_HEADER pIAPP; ++ PHEADER_802_11 pHeader; ++ UCHAR AckRate = RATE_2; ++ USHORT AckDuration = 0; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n")); ++ ++ // 0. Set up the frame pointer, Frame was inited at the end of message action ++ pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11]; ++ ++ // 1. Update report IAPP fields ++ pIAPP = (PAIRONET_IAPP_HEADER) pDest; ++ ++ // 2. Copy Cisco SNAP header ++ NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H); ++ ++ // 3. network order for this 16bit length ++ pIAPP->Length = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H); ++ ++ // 3.1 sanity check the report length, ignore it if there is nothing to report ++ if (be2cpu16(pIAPP->Length) <= 18) ++ return; ++ ++ // 4. Type must be 0x32 ++ pIAPP->Type = AIRONET_IAPP_TYPE; ++ ++ // 5. SubType for report must be 0x81 ++ pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT; ++ ++ // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function ++ // We will do it again here. We can use BSSID instead ++ COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid); ++ ++ // 7. SA is the client reporting which must be our MAC ++ COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress); ++ ++ // 8. Copy the saved dialog token ++ pIAPP->Token = pAd->StaCfg.IAPPToken; ++ ++ // 9. Make the Report frame 802.11 header ++ // Reuse function in wpa.c ++ pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf; ++ pAd->Sequence ++; ++ WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid); ++ ++ // ACK size is 14 include CRC, and its rate is based on real time information ++ AckRate = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate]; ++ AckDuration = RTMPCalcDuration(pAd, AckRate, 14); ++ pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration; ++ ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything. ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf, ++ END_OF_ARGS); ++ ++ // 11. Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ChannelLoadReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PCHANNEL_LOAD_REPORT pLoad; ++ PUCHAR pDest; ++ UCHAR CCABusyFraction; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n")); ++ ++ // Disable Rx with promiscuous reception, make it back to normal ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ ++ // 0. Setup pointer for processing beacon & probe response ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ ++ // 1. Fill Measurement report element field. ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ // Fixed Length at 9, not include Eid and length fields ++ pReport->Length = 9; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_CHANNEL_LOAD_REQ; ++ ++ // 2. Fill channel report measurement data ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pLoad = (PCHANNEL_LOAD_REPORT) pDest; ++ pLoad->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; ++ pLoad->Spare = 0; ++ pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; ++ ++ // 3. Calculate the CCA Busy Fraction ++ // (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed ++ // = (Bytes + ACK) / 12 / duration ++ // 9 is the good value for pAd->StaCfg.CLFactor ++ // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration); ++ CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration); ++ if (CCABusyFraction < 10) ++ CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1; ++ ++ pLoad->CCABusy = CCABusyFraction; ++ DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); ++ pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); ++ ++ // 4. Clear channel load measurement flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ // 5. reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NoiseHistReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PNOISE_HIST_REPORT pNoise; ++ PUCHAR pDest; ++ UCHAR i,NoiseCnt; ++ USHORT TotalRPICnt, TotalRPISum; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n")); ++ ++ // 0. Disable Rx with promiscuous reception, make it back to normal ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ // 1. Setup pointer for processing beacon & probe response ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ ++ // 2. Fill Measurement report element field. ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ // Fixed Length at 16, not include Eid and length fields ++ pReport->Length = 16; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_NOISE_HIST_REQ; ++ ++ // 3. Fill noise histogram report measurement data ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pNoise = (PNOISE_HIST_REPORT) pDest; ++ pNoise->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; ++ pNoise->Spare = 0; ++ pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; ++ // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU ++ // We estimate 4000 normal packets received durning 10 seconds test. ++ // Adjust it if required. ++ // 3 is a good value for pAd->StaCfg.NHFactor ++ // TotalRPICnt = pNoise->Duration * 3 / 10; ++ TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10; ++ TotalRPISum = 0; ++ ++ for (i = 0; i < 8; i++) ++ { ++ TotalRPISum += pAd->StaCfg.RPIDensity[i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i])); ++ } ++ ++ // Double check if the counter is larger than our expectation. ++ // We will replace it with the total number plus a fraction. ++ if (TotalRPISum > TotalRPICnt) ++ TotalRPICnt = TotalRPISum + pNoise->Duration / 20; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt)); ++ ++ // 5. Initialize noise count for the total summation of 0xff ++ NoiseCnt = 0; ++ for (i = 1; i < 8; i++) ++ { ++ pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt); ++ if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0)) ++ pNoise->Density[i]++; ++ NoiseCnt += pNoise->Density[i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d] = 0x%02x\n", i, pNoise->Density[i])); ++ } ++ ++ // 6. RPI[0] represents the rest of counts ++ pNoise->Density[0] = 0xff - NoiseCnt; ++ DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0] = 0x%02x\n", pNoise->Density[0])); ++ ++ pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT)); ++ ++ // 7. Clear channel load measurement flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ // 8. reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare Beacon report action, ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID BeaconReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n")); ++ ++ // Looks like we don't have anything thing need to do here. ++ // All measurement report already finished in AddBeaconReport ++ // The length is in the FrameReportLen ++ ++ // reset Beacon index for next beacon request ++ pAd->StaCfg.LastBssIndex = 0xff; ++ ++ // reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Index Current BSSID in CCXBsstab entry index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetAddBeaconReport( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Index, ++ IN PMLME_QUEUE_ELEM pElem) ++{ ++ PVOID pMsg; ++ PUCHAR pSrc, pDest; ++ UCHAR ReqIdx; ++ ULONG MsgLen; ++ USHORT Length; ++ PFRAME_802_11 pFrame; ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PEID_STRUCT pEid; ++ PBEACON_REPORT pBeaconReport; ++ PBSS_ENTRY pBss; ++ ++ // 0. Setup pointer for processing beacon & probe response ++ pMsg = pElem->Msg; ++ MsgLen = pElem->MsgLen; ++ pFrame = (PFRAME_802_11) pMsg; ++ pSrc = pFrame->Octet; // Start from AP TSF ++ pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; ++ ReqIdx = pAd->StaCfg.CurrentRMReqIdx; ++ ++ // 1 Check the Index, if we already create this entry, only update the average RSSI ++ if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff)) ++ { ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]]; ++ // Point to bss report information ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ ++ // Update Rx power, in dBm ++ // Get the original RSSI readback from BBP ++ pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta; ++ // Average the Rssi reading ++ pBeaconReport->RxPower = (pBeaconReport->RxPower + pBss->Rssi) / 2; ++ // Get to dBm format ++ pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", ++ pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], ++ pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index])); ++ ++ // Update other information here ++ ++ // Done ++ return; ++ } ++ ++ // 2. Update reported Index ++ pAd->StaCfg.LastBssIndex = Index; ++ ++ // 3. Setup the buffer address for copying this BSSID into reporting frame ++ // The offset should start after 802.11 header and report frame header. ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ ++ // 4. Save the start offset of each Bss in report frame ++ pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen; ++ ++ // 5. Fill Measurement report fields ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ pReport->Length = 0; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_BEACON_REQ; ++ Length = sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ ++ // 6. Start thebeacon report format ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ pDest += sizeof(BEACON_REPORT); ++ Length += sizeof(BEACON_REPORT); ++ ++ // 7. Copy Channel number ++ pBeaconReport->Channel = pBss->Channel; ++ pBeaconReport->Spare = 0; ++ pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; ++ pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); ++ // 8. Rx power, in dBm ++ pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", ++ pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], ++ pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen)); ++ ++ pBeaconReport->BeaconInterval = pBss->BeaconPeriod; ++ COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3); ++ NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4); ++ NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4); ++ ++ // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo ++ pSrc += (TIMESTAMP_LEN + 2); ++ pBeaconReport->CapabilityInfo = *(USHORT *)pSrc; ++ ++ // 10. Point to start of element ID ++ pSrc += 2; ++ pEid = (PEID_STRUCT) pSrc; ++ ++ // 11. Start process all variable Eid oayload and add the appropriate to the frame report ++ while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen)) ++ { ++ // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate, ++ // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set, ++ // TIM (report first 4 bytes only, radio measurement capability ++ switch (pEid->Eid) ++ { ++ case IE_SSID: ++ case IE_SUPP_RATES: ++ case IE_FH_PARM: ++ case IE_DS_PARM: ++ case IE_CF_PARM: ++ case IE_IBSS_PARM: ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ break; ++ ++ case IE_MEASUREMENT_CAPABILITY: ++ // Since this IE is duplicated with WPA security IE, we has to do sanity check before ++ // recognize it. ++ // 1. It also has fixed 6 bytes IE length. ++ if (pEid->Len != 6) ++ break; ++ // 2. Check the Cisco Aironet OUI ++ if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3)) ++ { ++ // Matched, this is what we want ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ } ++ break; ++ ++ case IE_TIM: ++ if (pEid->Len > 4) ++ { ++ // May truncate and report the first 4 bytes only, with the eid & len, total should be 6 ++ NdisMoveMemory(pDest, pEid, 6); ++ pDest += 6; ++ Length += 6; ++ } ++ else ++ { ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ // 12. Move to next element ID ++ pSrc += (2 + pEid->Len); ++ pEid = (PEID_STRUCT) pSrc; ++ } ++ ++ // 13. Update the length in the header, not include EID and length ++ pReport->Length = Length - 4; ++ ++ // 14. Update the frame report buffer data length ++ pAd->StaCfg.FrameReportLen += Length; ++ DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Index Current BSSID in CCXBsstab entry index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetCreateBeaconReportFromBssTable( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PBEACON_REPORT pBeaconReport; ++ UCHAR Index, ReqIdx; ++ USHORT Length; ++ PUCHAR pDest; ++ PBSS_ENTRY pBss; ++ ++ // 0. setup base pointer ++ ReqIdx = pAd->StaCfg.CurrentRMReqIdx; ++ ++ for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++) ++ { ++ // 1. Setup the buffer address for copying this BSSID into reporting frame ++ // The offset should start after 802.11 header and report frame header. ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; ++ Length = 0; ++ ++ // 2. Fill Measurement report fields ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ pReport->Length = 0; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_BEACON_REQ; ++ Length = sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ ++ // 3. Start the beacon report format ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ pDest += sizeof(BEACON_REPORT); ++ Length += sizeof(BEACON_REPORT); ++ ++ // 4. Copy Channel number ++ pBeaconReport->Channel = pBss->Channel; ++ pBeaconReport->Spare = 0; ++ pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; ++ pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); ++ pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; ++ pBeaconReport->BeaconInterval = pBss->BeaconPeriod; ++ pBeaconReport->CapabilityInfo = pBss->CapabilityInfo; ++ COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid); ++ NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4); ++ NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8); ++ ++ // 5. Create SSID ++ *pDest++ = 0x00; ++ *pDest++ = pBss->SsidLen; ++ NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen); ++ pDest += pBss->SsidLen; ++ Length += (2 + pBss->SsidLen); ++ ++ // 6. Create SupportRates ++ *pDest++ = 0x01; ++ *pDest++ = pBss->SupRateLen; ++ NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen); ++ pDest += pBss->SupRateLen; ++ Length += (2 + pBss->SupRateLen); ++ ++ // 7. DS Parameter ++ *pDest++ = 0x03; ++ *pDest++ = 1; ++ *pDest++ = pBss->Channel; ++ Length += 3; ++ ++ // 8. IBSS parameter if presents ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ *pDest++ = 0x06; ++ *pDest++ = 2; ++ *(PUSHORT) pDest = pBss->AtimWin; ++ pDest += 2; ++ Length += 4; ++ } ++ ++ // 9. Update length field, not include EID and length ++ pReport->Length = Length - 4; ++ ++ // 10. Update total frame size ++ pAd->StaCfg.FrameReportLen += Length; ++ } ++} +--- /dev/null ++++ b/drivers/staging/rt2870/sta/assoc.c +@@ -0,0 +1,2039 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ assoc.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-9-3 porting from RT2500 ++*/ ++#include "../rt_config.h" ++ ++UCHAR CipherWpaTemplate[] = { ++ 0xdd, // WPA IE ++ 0x16, // Length ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x01 // authentication ++ }; ++ ++UCHAR CipherWpa2Template[] = { ++ 0x30, // RSN IE ++ 0x14, // Length ++ 0x01, 0x00, // Version ++ 0x00, 0x0f, 0xac, 0x02, // group cipher, TKIP ++ 0x01, 0x00, // number of pairwise ++ 0x00, 0x0f, 0xac, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x0f, 0xac, 0x02, // authentication ++ 0x00, 0x00, // RSN capability ++ }; ++ ++UCHAR Ccx2IeInfo[] = { 0x00, 0x40, 0x96, 0x03, 0x02}; ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE); ++ ++ // first column ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ ++ // second column ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); ++ // ++ // Patch 3Com AP MOde:3CRWE454G72 ++ // We send Assoc request frame to this AP, it always send Reassoc Rsp not Associate Rsp. ++ // ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction); ++ ++ // third column ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); ++ // ++ // Patch, AP doesn't send Reassociate Rsp frame to Station. ++ // ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction); ++ ++ // fourth column ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction); ++ ++ // initialize the timer ++ RTMPInitTimer(pAd, &pAd->MlmeAux.AssocTimer, GET_TIMER_FUNCTION(AssocTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.ReassocTimer, GET_TIMER_FUNCTION(ReassocTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.DisassocTimer, GET_TIMER_FUNCTION(DisassocTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Association timeout procedure. After association timeout, this function ++ will be called and it will put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Reassociation timeout procedure. After reassociation timeout, this ++ function will be called and put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ReassocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Disassociation timeout procedure. After disassociation timeout, this ++ function will be called and put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID DisassocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ mlme assoc req handling procedure ++ Parameters: ++ Adapter - Adapter pointer ++ Elem - MLME Queue Element ++ Pre: ++ the station has been authenticated and the following information is stored in the config ++ -# SSID ++ -# supported rates and their length ++ -# listen interval (Adapter->StaCfg.default_listen_count) ++ -# Transmit power (Adapter->StaCfg.tx_power) ++ Post : ++ -# An association request frame is generated and sent to the air ++ -# Association timer starts ++ -# Association state -> ASSOC_WAIT_RSP ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR ApAddr[6]; ++ HEADER_802_11 AssocHdr; ++ UCHAR Ccx2Len = 5; ++ UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ USHORT ListenIntv; ++ ULONG Timeout; ++ USHORT CapabilityInfo; ++ BOOLEAN TimerCancelled; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ ULONG tmp; ++ USHORT VarIesOffset; ++ UCHAR CkipFlag; ++ UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; ++ UCHAR AironetCkipIe = IE_AIRONET_CKIP; ++ UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; ++ UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; ++ UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; ++ UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; ++ USHORT Status; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block Assoc request durning WPA block period!\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ // check sanity first ++ else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); ++ ++ // Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() allocate memory failed \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ // Add by James 03/06/27 ++ pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ // Association don't need to report MAC address ++ pAd->StaCfg.AssocInfo.AvailableRequestFixedIEs = ++ NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL; ++ pAd->StaCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo; ++ pAd->StaCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv; ++ // Only reassociate need this ++ //COPY_MAC_ADDR(pAd->StaCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, ApAddr); ++ pAd->StaCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ ++ NdisZeroMemory(pAd->StaCfg.ReqVarIEs, MAX_VIE_LEN); ++ // First add SSID ++ VarIesOffset = 0; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SsidLen, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ VarIesOffset += pAd->MlmeAux.SsidLen; ++ ++ // Second add Supported rates ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SupRateIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SupRateLen, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.SupRate, pAd->MlmeAux.SupRateLen); ++ VarIesOffset += pAd->MlmeAux.SupRateLen; ++ // End Add by James ++ ++ if ((pAd->CommonCfg.Channel > 14) && ++ (pAd->CommonCfg.bIEEE80211H == TRUE)) ++ CapabilityInfo |= 0x0100; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send ASSOC request...\n")); ++ MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, ApAddr, ApAddr); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AssocHdr, ++ 2, &CapabilityInfo, ++ 2, &ListenIntv, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) ++ { ++ HtLen = SIZE_HT_CAP_IE + 4; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisZeroMemory(&HtCapabilityTmp, sizeof(HT_CAPABILITY_IE)); ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, pAd->MlmeAux.HtCapabilityLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen,&HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION ++ // Case I: (Aggregation + Piggy-Back) ++ // 1. user enable aggregation, AND ++ // 2. Mac support piggy-back ++ // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON ++ // Case II: (Aggregation) ++ // 1. user enable aggregation, AND ++ // 2. AP annouces it's AGGREGATION-capable in BEACON ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ } ++ else ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x06, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ ++ if (pAd->MlmeAux.APEdcaParm.bValid) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) ++ { ++ QBSS_STA_INFO_PARM QosInfo; ++ ++ NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); ++ QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; ++ QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; ++ QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; ++ QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; ++ QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; ++ WmeIe[8] |= *(PUCHAR)&QosInfo; ++ } ++ else ++ { ++ // The Parameter Set Count is set to ¡§0¡¨ in the association request frames ++ // WmeIe[8] |= (pAd->MlmeAux.APEdcaParm.EdcaUpdateCount & 0x0f); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 9, &WmeIe[0], ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // ++ // Let WPA(#221) Element ID on the end of this association frame. ++ // Otherwise some AP will fail on parsing Element ID and set status fail on Assoc Rsp. ++ // For example: Put Vendor Specific IE on the front of WPA IE. ++ // This happens on AP (Model No:Linksys WRK54G) ++ // ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ++ ) ++ ) ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ { ++ RSNIe = IE_WPA2; ++ } ++ ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ ++ // Check for WPA PMK cache list ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ++ { ++ INT idx; ++ BOOLEAN FoundPMK = FALSE; ++ // Search chched PMKID, append it if existed ++ for (idx = 0; idx < PMKID_NO; idx++) ++ { ++ if (NdisEqualMemory(ApAddr, &pAd->StaCfg.SavedPMK[idx].BSSID, 6)) ++ { ++ FoundPMK = TRUE; ++ break; ++ } ++ } ++ ++ if (FoundPMK) ++ { ++ // Set PMK number ++ *(PUSHORT) &pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len] = 1; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len + 2], &pAd->StaCfg.SavedPMK[idx].PMKID, 16); ++ pAd->StaCfg.RSNIE_Len += 18; ++ } ++ } ++ ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ } ++ ++ FrameLen += tmp; ++ ++ { ++ // Append Variable IE ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->StaCfg.RSNIE_Len, 1); ++ VarIesOffset += 1; ++ } ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ VarIesOffset += pAd->StaCfg.RSNIE_Len; ++ ++ // Set Variable IEs Length ++ pAd->StaCfg.ReqVarIELen = VarIesOffset; ++ } ++ ++ // We have update that at PeerBeaconAtJoinRequest() ++ CkipFlag = pAd->StaCfg.CkipFlag; ++ if (CkipFlag != 0) ++ { ++ NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); ++ CkipNegotiationBuffer[2] = 0x66; ++ // Make it try KP & MIC, since we have to follow the result from AssocRsp ++ CkipNegotiationBuffer[8] = 0x18; ++ CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; ++ CkipFlag = 0x18; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCkipIe, ++ 1, &AironetCkipLen, ++ AironetCkipLen, CkipNegotiationBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // Add CCX v2 request if CCX2 admin state is on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ { ++ ++ // ++ // Add AironetIPAddressIE for Cisco CCX 2.X ++ // Add CCX Version ++ // ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetIPAddressIE, ++ 1, &AironetIPAddressLen, ++ AironetIPAddressLen, AironetIPAddressBuffer, ++ 1, &Ccx2Ie, ++ 1, &Ccx2Len, ++ Ccx2Len, Ccx2IeInfo, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // ++ // Add CipherSuite CCKM or LeapTkip if setting. ++ // ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCiscoCCKMLen, CipherSuiteCiscoCCKM, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // Third add RSN ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); //Save CipherSuite ++ VarIesOffset += CipherSuiteCiscoCCKMLen; ++ } ++ else if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCCXTkipLen, CipherSuiteCCXTkip, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // Third add RSN ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCCXTkip, CipherSuiteCCXTkipLen); ++ VarIesOffset += CipherSuiteCCXTkipLen; ++ } ++#endif // LEAP_SUPPORT // ++ ++ // Add by James 03/06/27 ++ // Set Variable IEs Length ++ pAd->StaCfg.ReqVarIELen = VarIesOffset; ++ pAd->StaCfg.AssocInfo.RequestIELength = VarIesOffset; ++ ++ // OffsetResponseIEs follow ReqVarIE ++ pAd->StaCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->StaCfg.ReqVarIELen; ++ // End Add by James ++ } ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AssocTimer, Timeout); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ mlme reassoc req handling procedure ++ Parameters: ++ Elem - ++ Pre: ++ -# SSID (Adapter->StaCfg.ssid[]) ++ -# BSSID (AP address, Adapter->StaCfg.bssid) ++ -# Supported rates (Adapter->StaCfg.supported_rates[]) ++ -# Supported rates length (Adapter->StaCfg.supported_rates_len) ++ -# Tx power (Adapter->StaCfg.tx_power) ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR ApAddr[6]; ++ HEADER_802_11 ReassocHdr; ++ UCHAR Ccx2Len = 5; ++ UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ USHORT CapabilityInfo, ListenIntv; ++ ULONG Timeout; ++ ULONG FrameLen = 0; ++ BOOLEAN TimerCancelled; ++ NDIS_STATUS NStatus; ++ ULONG tmp; ++ PUCHAR pOutBuffer = NULL; ++//CCX 2.X ++#ifdef LEAP_SUPPORT ++ UCHAR CkipFlag; ++ UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; ++ UCHAR AironetCkipIe = IE_AIRONET_CKIP; ++ UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; ++ UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; ++ UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; ++ UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; ++ UCHAR AironetCCKMReassocIE = IE_AIRONET_CCKMREASSOC; ++ UCHAR AironetCCKMReassocLen = AIRONET_CCKMREASSOC_LENGTH; ++ UCHAR AironetCCKMReassocBuffer[AIRONET_CCKMREASSOC_LENGTH]; ++ UCHAR AironetOUI[] = {0x00, 0x40, 0x96, 0x00}; ++ UCHAR MICMN[16]; ++ UCHAR CalcMicBuffer[80]; ++ ULONG CalcMicBufferLen = 0; ++#endif // LEAP_SUPPORT // ++ USHORT Status; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block ReAssoc request durning WPA block period!\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ // the parameters are the same as the association ++ else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() allocate memory failed \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); ++ ++ // make frame, use bssid as the AP address?? ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send RE-ASSOC request...\n")); ++ MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, ApAddr, ApAddr); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &ReassocHdr, ++ 2, &CapabilityInfo, ++ 2, &ListenIntv, ++ MAC_ADDR_LEN, ApAddr, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ if (pAd->MlmeAux.APEdcaParm.bValid) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) ++ { ++ QBSS_STA_INFO_PARM QosInfo; ++ ++ NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); ++ QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; ++ QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; ++ QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; ++ QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; ++ QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; ++ WmeIe[8] |= *(PUCHAR)&QosInfo; ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 9, &WmeIe[0], ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) ++ { ++ HtLen = SIZE_HT_CAP_IE + 4; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION ++ // Case I: (Aggregation + Piggy-Back) ++ // 1. user enable aggregation, AND ++ // 2. Mac support piggy-back ++ // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON ++ // Case II: (Aggregation) ++ // 1. user enable aggregation, AND ++ // 2. AP annouces it's AGGREGATION-capable in BEACON ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ } ++ else ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x04, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ CkipFlag = pAd->StaCfg.CkipFlag; // We have update that at PeerBeaconAtJoinRequest() ++ if (CkipFlag != 0) ++ { ++ NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); ++ CkipNegotiationBuffer[2] = 0x66; ++ // Make it try KP & MIC, since we have to follow the result from AssocRsp ++ CkipNegotiationBuffer[8] = 0x18; ++ CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCkipIe, ++ 1, &AironetCkipLen, ++ AironetCkipLen, CkipNegotiationBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetIPAddressIE, ++ 1, &AironetIPAddressLen, ++ AironetIPAddressLen, AironetIPAddressBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // ++ // The RN is incremented before each reassociation request. ++ // ++ pAd->StaCfg.CCKMRN++; ++ // ++ // Calculate MIC = hmac-md5(krk, STA-ID|BSSID|RSNIE|TSF|RN); ++ // ++ COPY_MAC_ADDR(CalcMicBuffer, pAd->CurrentAddress); ++ CalcMicBufferLen = MAC_ADDR_LEN; ++ COPY_MAC_ADDR(CalcMicBuffer + CalcMicBufferLen, pAd->MlmeAux.Bssid); ++ CalcMicBufferLen += MAC_ADDR_LEN; ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); ++ CalcMicBufferLen += CipherSuiteCiscoCCKMLen; ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR) &pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp)); ++ CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp); ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR)&pAd->StaCfg.CCKMRN, sizeof(pAd->StaCfg.CCKMRN)); ++ CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMRN); ++ hmac_md5(pAd->StaCfg.KRK, LEN_EAP_MICK, CalcMicBuffer, CalcMicBufferLen, MICMN); ++ ++ // ++ // fill up CCKM reassociation request element ++ // ++ NdisMoveMemory(AironetCCKMReassocBuffer, AironetOUI, 4); ++ NdisMoveMemory(AironetCCKMReassocBuffer + 4, (PUCHAR)&pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, 8); ++ NdisMoveMemory(AironetCCKMReassocBuffer + 12, (PUCHAR) &pAd->StaCfg.CCKMRN, 4); ++ NdisMoveMemory(AironetCCKMReassocBuffer +16, MICMN, 8); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCCKMReassocIE, ++ 1, &AironetCCKMReassocLen, ++ AironetCCKMReassocLen, AironetCCKMReassocBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCiscoCCKMLen,CipherSuiteCiscoCCKM, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++#endif // LEAP_SUPPORT // ++ ++ // Add CCX v2 request if CCX2 admin state is on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ { ++ // ++ // Add CCX Version ++ // ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &Ccx2Ie, ++ 1, &Ccx2Len, ++ Ccx2Len, Ccx2IeInfo, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.ReassocTimer, Timeout); /* in mSec */ ++ pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Upper layer issues disassoc request ++ Parameters: ++ Elem - ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PMLME_DISASSOC_REQ_STRUCT pDisassocReq; ++ HEADER_802_11 DisassocHdr; ++ PHEADER_802_11 pDisassocHdr; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ NDIS_STATUS NStatus; ++ BOOLEAN TimerCancelled; ++ ULONG Timeout = 0; ++ USHORT Status; ++ ++#ifdef QOS_DLS_SUPPORT ++ // send DLS-TEAR_DOWN message, ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ UCHAR i; ++ ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // skip sanity check ++ pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - MlmeDisassocReqAction() allocate memory failed\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ ++ ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &TimerCancelled); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send DISASSOC request[BSSID::%02x:%02x:%02x:%02x:%02x:%02x (Reason=%d)\n", ++ pDisassocReq->Addr[0], pDisassocReq->Addr[1], pDisassocReq->Addr[2], ++ pDisassocReq->Addr[3], pDisassocReq->Addr[4], pDisassocReq->Addr[5], pDisassocReq->Reason)); ++ MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pDisassocReq->Addr, pDisassocReq->Addr); // patch peap ttls switching issue ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DisassocHdr, ++ 2, &pDisassocReq->Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ // To patch Instance and Buffalo(N) AP ++ // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine ++ // Therefore, we send both of them. ++ pDisassocHdr = (PHEADER_802_11)pOutBuffer; ++ pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING; ++ COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr); ++ ++ RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */ ++ pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends assoc rsp back ++ Parameters: ++ Elme - MLME message containing the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAssocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo, Status, Aid; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BOOLEAN TimerCancelled; ++ UCHAR CkipFlag; ++ EDCA_PARM EdcaParm; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, ++ &HtCapability,&AddHtInfo, &HtCapabilityLen,&AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) ++ { ++ // The frame is for me ? ++ if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status)); ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++#endif // DOT11_N_SUPPORT // ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); ++ if(Status == MLME_SUCCESS) ++ { ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR idx; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (idx=0; idxMacTab.Content[BSSID_WCID], MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo); ++ ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ if (CkipFlag & 0x18) ++ { ++ NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); ++ pAd->StaCfg.GIV[0] = RandomByte(pAd); ++ pAd->StaCfg.GIV[1] = RandomByte(pAd); ++ pAd->StaCfg.GIV[2] = RandomByte(pAd); ++ pAd->StaCfg.bCkipOn = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); ++ } ++ } ++ else ++ { ++ // Faile on Association, we need to check the status code ++ // Is that a Rogue AP? ++#ifdef LEAP_SUPPORT ++ if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (Status == MLME_ALG_NOT_SUPPORT)) ++ { //Possibly Rogue AP ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, pAd->MlmeAux.Bssid, LEAP_REASON_INVALID_AUTH); ++ } ++#endif // LEAP_SUPPORT // ++ } ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerAssocRspAction() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends reassoc rsp ++ Parametrs: ++ Elem - MLME message cntaining the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerReassocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo; ++ USHORT Status; ++ USHORT Aid; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR CkipFlag; ++ BOOLEAN TimerCancelled; ++ EDCA_PARM EdcaParm; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, ++ &HtCapability, &AddHtInfo, &HtCapabilityLen, &AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) ++ { ++ if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) // The frame is for me ? ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status)); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); ++ ++ if(Status == MLME_SUCCESS) ++ { ++ // go to procedure listed on page 376 ++ AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ } ++ ++ // ++ // Cisco Leap CCKM supported Re-association. ++ // ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ if (CCKMAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen) == TRUE) ++ { ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ if (CkipFlag & 0x18) ++ { ++ NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); ++ pAd->StaCfg.GIV[0] = RandomByte(pAd); ++ pAd->StaCfg.GIV[1] = RandomByte(pAd); ++ pAd->StaCfg.GIV[2] = RandomByte(pAd); ++ pAd->StaCfg.bCkipOn = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); ++ } ++ ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - CCKMAssocRspSanity() sanity check fail\n")); ++ } ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ // CkipFlag is no use for reassociate ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerReassocRspAction() sanity check fail\n")); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ procedures on IEEE 802.11/1999 p.376 ++ Parametrs: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocPostProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr2, ++ IN USHORT CapabilityInfo, ++ IN USHORT Aid, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN PEDCA_PARM pEdcaParm, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN ADD_HT_INFO_IE *pAddHtInfo) // AP might use this additional ht info IE ++{ ++ ULONG Idx; ++ ++ pAd->MlmeAux.BssType = BSS_INFRA; ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2); ++ pAd->MlmeAux.Aid = Aid; ++ pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; ++#ifdef DOT11_N_SUPPORT ++ // Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. ++ if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) ++ { ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->Aifsn[0] = 3; ++ pEdcaParm->Aifsn[1] = 7; ++ pEdcaParm->Aifsn[2] = 2; ++ pEdcaParm->Aifsn[3] = 2; ++ ++ pEdcaParm->Cwmin[0] = 4; ++ pEdcaParm->Cwmin[1] = 4; ++ pEdcaParm->Cwmin[2] = 3; ++ pEdcaParm->Cwmin[3] = 2; ++ ++ pEdcaParm->Cwmax[0] = 10; ++ pEdcaParm->Cwmax[1] = 10; ++ pEdcaParm->Cwmax[2] = 4; ++ pEdcaParm->Cwmax[3] = 3; ++ ++ pEdcaParm->Txop[0] = 0; ++ pEdcaParm->Txop[1] = 0; ++ pEdcaParm->Txop[2] = 96; ++ pEdcaParm->Txop[3] = 48; ++ ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ ++ // filter out un-supported rates ++ pAd->MlmeAux.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ ++ // filter out un-supported rates ++ pAd->MlmeAux.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++ ++#ifdef DOT11_N_SUPPORT ++ if (HtCapabilityLen > 0) ++ { ++ RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> AP.AMsduSize = %d. ClientStatusFlags = 0x%lx \n", pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n", ++ pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize)); ++#endif // DOT11_N_SUPPORT // ++ ++ // Set New WPA information ++ Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); ++ if (Idx == BSS_NOT_FOUND) ++ { ++ DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n")); ++ } ++ else ++ { ++ // Init variable ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0; ++ NdisZeroMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, MAX_LEN_OF_RSNIE); ++ ++ // Store appropriate RSN_IE for WPA SM negotiation later ++ if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAd->ScanTab.BssEntry[Idx].VarIELen != 0)) ++ { ++ PUCHAR pVIE; ++ USHORT len; ++ PEID_STRUCT pEid; ++ ++ pVIE = pAd->ScanTab.BssEntry[Idx].VarIEs; ++ len = pAd->ScanTab.BssEntry[Idx].VarIELen; ++ ++ while (len > 0) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // For WPA/WPAPSK ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA SM negotiation \n")); ++ } ++ // For WPA2/WPA2PSK ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA2 SM negotiation \n")); ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ } ++ ++ if (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> no RSN_IE \n")); ++ } ++ else ++ { ++ hex_dump("RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ left part of IEEE 802.11/1999 p.374 ++ Parameters: ++ Elem - MLME message containing the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDisassocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Reason; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction()\n")); ++ if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() Reason = %d\n", Reason)); ++ if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, Addr2)) ++ { ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ // Cisco_LEAP has start a timer ++ // We should cancel it if using LEAP ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); ++ //Check is it mach the LEAP Authentication failed as possible a Rogue AP ++ //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Association. ++ if ((pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE) && (pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); ++ } ++ } ++#endif // LEAP_SUPPORT // ++ // ++ // Get Current System time and Turn on AdjacentAPReport ++ // ++ NdisGetSystemUpTime(&pAd->StaCfg.CCXAdjacentAPLinkDownTime); ++ pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; ++ LinkDown(pAd, TRUE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() sanity check fail\n")); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after assoc timeout ++ Parameters: ++ Elme - ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - AssocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after reassoc timeout ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ReassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - ReassocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after disassoc timeout ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID DisassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - DisassocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenAssoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenAssoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenReassoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenReassoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenDisassociate( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenDisassoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ right part of IEEE 802.11/1999 page 374 ++ Note: ++ This event should never cause ASSOC state machine perform state ++ transition, and has no relationship with CNTL machine. So we separate ++ this routine as a service outside of ASSOC state transition table. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID Cls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr) ++{ ++ HEADER_802_11 DisassocHdr; ++ PHEADER_802_11 pDisassocHdr; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ NDIS_STATUS NStatus; ++ USHORT Reason = REASON_CLS3ERR; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Class 3 Error, Send DISASSOC frame\n")); ++ MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, pAd->CommonCfg.Bssid); // patch peap ttls switching issue ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DisassocHdr, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ // To patch Instance and Buffalo(N) AP ++ // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine ++ // Therefore, we send both of them. ++ pDisassocHdr = (PHEADER_802_11)pOutBuffer; ++ pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DisassocReason = REASON_CLS3ERR; ++ COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pAddr); ++} ++ ++ /* ++ ========================================================================== ++ Description: ++ Switch between WEP and CKIP upon new association up. ++ Parameters: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID SwitchBetweenWepAndCkip( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ // if KP is required. change the CipherAlg in hardware shard key table from WEP ++ // to CKIP. else remain as WEP ++ if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10)) ++ { ++ // modify hardware key table so that MAC use correct algorithm to decrypt RX ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); ++ if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP128; ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); ++ ++ // modify software key table so that driver can specify correct algorithm in TXD upon TX ++ for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_WEP64) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP64; ++ else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP128) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP128; ++ } ++ } ++ ++ // else if KP NOT inused. change the CipherAlg in hardware shard key table from CKIP ++ // to WEP. ++ else ++ { ++ // modify hardware key table so that MAC use correct algorithm to decrypt RX ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); ++ if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_WEP128; ++ ++ // modify software key table so that driver can specify correct algorithm in TXD upon TX ++ for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_CKIP64) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP64; ++ else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP128) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP128; ++ } ++ ++ // ++ // On WPA-NONE, must update CipherAlg. ++ // Because the OID_802_11_WEP_STATUS was been set after OID_802_11_ADD_KEY ++ // and CipherAlg will be CIPHER_NONE by Windows ZeroConfig. ++ // So we need to update CipherAlg after connect. ++ // ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ if (pAd->SharedKey[BSS0][i].KeyLen != 0) ++ { ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_TKIP; ++ } ++ else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_AES; ++ } ++ } ++ else ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; ++ } ++ } ++ ++ csr1.field.Bss0Key0CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ csr1.field.Bss0Key1CipherAlg = pAd->SharedKey[BSS0][1].CipherAlg; ++ csr1.field.Bss0Key2CipherAlg = pAd->SharedKey[BSS0][2].CipherAlg; ++ csr1.field.Bss0Key3CipherAlg = pAd->SharedKey[BSS0][3].CipherAlg; ++ } ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); ++ } ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++VOID SendAssocIEsToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd) ++{ ++ union iwreq_data wrqu; ++ unsigned char custom[IW_CUSTOM_MAX] = {0}; ++ ++ if ((pAd->StaCfg.ReqVarIELen + 17) <= IW_CUSTOM_MAX) ++ { ++ sprintf(custom, "ASSOCINFO_ReqIEs="); ++ NdisMoveMemory(custom+17, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = pAd->StaCfg.ReqVarIELen + 17; ++ wrqu.data.flags = RT_REQIE_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOCINFO_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen + 17 > MAX_CUSTOM_LEN\n")); ++ ++ return; ++} ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++int wext_notify_event_assoc( ++ IN RTMP_ADAPTER *pAd) ++{ ++ union iwreq_data wrqu; ++ char custom[IW_CUSTOM_MAX] = {0}; ++ ++#if WIRELESS_EXT > 17 ++ if (pAd->StaCfg.ReqVarIELen <= IW_CUSTOM_MAX) ++ { ++ wrqu.data.length = pAd->StaCfg.ReqVarIELen; ++ memcpy(custom, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); ++ wireless_send_event(pAd->net_dev, IWEVASSOCREQIE, &wrqu, custom); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen > MAX_CUSTOM_LEN\n")); ++#else ++ if (((pAd->StaCfg.ReqVarIELen*2) + 17) <= IW_CUSTOM_MAX) ++ { ++ UCHAR idx; ++ wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17; ++ sprintf(custom, "ASSOCINFO(ReqIEs="); ++ for (idx=0; idxStaCfg.ReqVarIELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAd->StaCfg.ReqVarIEs[idx]); ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("(pAd->StaCfg.ReqVarIELen*2) + 17 > MAX_CUSTOM_LEN\n")); ++#endif ++ ++ return 0; ++ ++} ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ ++BOOLEAN StaAddMacTableEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN USHORT CapabilityInfo) ++{ ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ if (ADHOC_ON(pAd)) ++ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11G) && (MaxSupportedRate < RATE_FIRST_OFDM_RATE)) ++ return FALSE; ++ ++#ifdef DOT11_N_SUPPORT ++ // 11n only ++ if (((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))&& (HtCapabilityLen == 0)) ++ return FALSE; ++#endif // DOT11_N_SUPPORT // ++ ++ if (!pEntry) ++ return FALSE; ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ if (pEntry) ++ { ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ if ((MaxSupportedRate < RATE_FIRST_OFDM_RATE) || ++ (pAd->CommonCfg.PhyMode == PHY_11B)) ++ { ++ pEntry->RateLen = 4; ++ if (MaxSupportedRate >= RATE_FIRST_OFDM_RATE) ++ MaxSupportedRate = RATE_11; ++ } ++ else ++ pEntry->RateLen = 12; ++ ++ pEntry->MaxHTPhyMode.word = 0; ++ pEntry->MinHTPhyMode.word = 0; ++ pEntry->HTPhyMode.word = 0; ++ pEntry->MaxSupportedRate = MaxSupportedRate; ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ pEntry->CapabilityInfo = CapabilityInfo; ++ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE); ++ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR i; ++ ++ if (ADHOC_ON(pAd)) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ if ((pHtCapability->HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((pHtCapability->HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(pHtCapability->HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(pHtCapability->HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // 3*3 ++ if (pAd->MACVersion >= RALINK_2883_VERSION && pAd->MACVersion < RALINK_3070_VERSION) ++ pEntry->MaxHTPhyMode.field.TxBF = pAd->CommonCfg.RegTransmitSetting.field.TxBF; ++ ++ // find max fixed rate ++ for (i=23; i>=0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ if ((pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j] & bitmask) && (pHtCapability->MCSSet[j] & bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = i; ++ break; ++ } ++ if (i==0) ++ break; ++ } ++ ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); ++ if (pHtCapability->HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (pHtCapability->HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (pHtCapability->HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (pHtCapability->HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (pHtCapability->ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (pHtCapability->ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ } ++ else ++ { ++ pAd->MacTab.fAnyStationIsLegacy = TRUE; ++ } ++ ++ NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE)); ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ ++ // Set asic auto fall back ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ // If the legacy mode is set, overwrite the transmit setting of this entry. ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ pEntry->Sst = SST_ASSOC; ++ pEntry->AuthState = AS_AUTH_OPEN; ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/auth.c +@@ -0,0 +1,474 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ auth.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-9-3 porting from RT2500 ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ authenticate state machine init, including state transition and timer init ++ Parameters: ++ Sm - pointer to the auth state machine ++ Note: ++ The state machine looks like this ++ ++ AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4 ++ MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth ++ MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action ++ MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++ ++void AuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE); ++ ++ // the first column ++ StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction); ++ ++ // the second column ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); ++ ++ // the third column ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); ++ ++ RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ function to be executed at timer thread when auth timer expires ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n")); ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ // send a de-auth to reset AP's state machine (Patch AP-Dir635) ++ if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2) ++ Cls2errAction(pAd, pAd->MlmeAux.Bssid); ++ ++ ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeAuthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr[6]; ++ USHORT Alg, Seq, Status; ++ ULONG Timeout; ++ HEADER_802_11 AuthHdr; ++ BOOLEAN TimerCancelled; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg)) ++ { ++ // reset timer ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr); ++ pAd->MlmeAux.Alg = Alg; ++ Seq = 1; ++ Status = MLME_SUCCESS; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg)); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg)); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&AuthHdr, ++ 2, &Alg, ++ 2, &Seq, ++ 2, &Status, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; ++ } ++ else ++ { ++ DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAuthRspAtSeq2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Seq, Status, RemoteStatus, Alg; ++ UCHAR ChlgText[CIPHER_TEXT_LEN]; ++ UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; ++ UCHAR Element[2]; ++ HEADER_802_11 AuthHdr; ++ BOOLEAN TimerCancelled; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Status2; ++ ++ if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) ++ { ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status)); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ ++ if (Status == MLME_SUCCESS) ++ { ++ // Authentication Mode "LEAP" has allow for CCX 1.X ++ if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ { ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++#ifdef LEAP_SUPPORT ++ pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE; ++#endif // LEAP_SUPPORT // ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ else ++ { ++ // 2. shared key, need to be challenged ++ Seq++; ++ RemoteStatus = MLME_SUCCESS; ++ ++ // Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status2 = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n")); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid); ++ AuthHdr.FC.Wep = 1; ++ // Encrypt challenge text & auth information ++ RTMPInitWepEngine( ++ pAd, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen, ++ CyperChlgText); ++ ++ Alg = cpu2le16(*(USHORT *)&Alg); ++ Seq = cpu2le16(*(USHORT *)&Seq); ++ RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus); ++ ++ RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2); ++ RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2); ++ RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2); ++ Element[0] = 16; ++ Element[1] = 128; ++ RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2); ++ RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128); ++ RTMPSetICV(pAd, CyperChlgText + 140); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AuthHdr, ++ CIPHER_TEXT_LEN + 16, CyperChlgText, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; ++ } ++ } ++ else ++ { ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ //Invalid Authentication possible rogue AP ++ //Add this Ap to Rogue AP. ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH); ++ } ++#endif // LEAP_SUPPORT // ++ pAd->StaCfg.AuthFailReason = Status; ++ COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAuthRspAtSeq4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Alg, Seq, Status; ++ CHAR ChlgText[CIPHER_TEXT_LEN]; ++ BOOLEAN TimerCancelled; ++ ++ if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) ++ { ++ if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n")); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ ++ if (Status != MLME_SUCCESS) ++ { ++ pAd->StaCfg.AuthFailReason = Status; ++ COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); ++ } ++ ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ HEADER_802_11 DeauthHdr; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Status; ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason)); ++ MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DeauthHdr, ++ 2, &pInfo->Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DeauthReason = pInfo->Reason; ++ COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); ++ ++ // send wireless event - for deauthentication ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID InvalidStateWhenAuth( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState)); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Some STA/AP ++ Note: ++ This action should never trigger AUTH state transition, therefore we ++ separate it from AUTH state machine, and make it as a standalone service ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID Cls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr) ++{ ++ HEADER_802_11 DeauthHdr; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Reason = REASON_CLS2ERR; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n")); ++ MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DeauthHdr, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DeauthReason = Reason; ++ COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/auth_rsp.c +@@ -0,0 +1,166 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ auth_rsp.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-10-1 copy from RT2560 ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ authentication state machine init procedure ++ Parameters: ++ Sm - the state machine ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE); ++ ++ // column 1 ++ StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); ++ ++ // column 2 ++ StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID PeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT Reason, ++ IN USHORT Status) ++{ ++ HEADER_802_11 AuthHdr; ++ ULONG FrameLen = 0; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ++ if (Reason != MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Peer AUTH fail...\n")); ++ return; ++ } ++ ++ //Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send AUTH response (seq#2)...\n")); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, pHdr80211->Addr2, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AuthHdr, ++ 2, &Alg, ++ 2, &Seq, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID PeerDeauthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMLME_QUEUE_ELEM Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Reason; ++ ++ if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) ++ { ++ if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(Addr2, pAd->CommonCfg.Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason)); ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ ++ // send wireless event - for deauthentication ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ LinkDown(pAd, TRUE); ++ ++ // Authentication Mode Cisco_LEAP has start a timer ++ // We should cancel it if using LEAP ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); ++ //Check is it mach the LEAP Authentication failed as possible a Rogue AP ++ //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Authenticaton. ++ if ((pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED) && (pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE)) ++ { ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); ++ } ++ } ++#endif // LEAP_SUPPORT // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - PeerDeauthAction() sanity check fail\n")); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/connect.c +@@ -0,0 +1,2822 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ connect.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-08-08 Major modification from RT2560 ++*/ ++#include "../rt_config.h" ++ ++UCHAR CipherSuiteWpaNoneTkip[] = { ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x00 // authentication ++ }; ++UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteWpaNoneAes[] = { ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x04, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x04, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x00 // authentication ++ }; ++UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR)); ++ ++// The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS, ++// or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS ++// All settings successfuly negotiated furing MLME state machines become final settings ++// and are copied to pAd->StaActive ++#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ ++{ \ ++ (_pAd)->CommonCfg.SsidLen = (_pAd)->MlmeAux.SsidLen; \ ++ NdisMoveMemory((_pAd)->CommonCfg.Ssid, (_pAd)->MlmeAux.Ssid, (_pAd)->MlmeAux.SsidLen); \ ++ COPY_MAC_ADDR((_pAd)->CommonCfg.Bssid, (_pAd)->MlmeAux.Bssid); \ ++ (_pAd)->CommonCfg.Channel = (_pAd)->MlmeAux.Channel; \ ++ (_pAd)->CommonCfg.CentralChannel = (_pAd)->MlmeAux.CentralChannel; \ ++ (_pAd)->StaActive.Aid = (_pAd)->MlmeAux.Aid; \ ++ (_pAd)->StaActive.AtimWin = (_pAd)->MlmeAux.AtimWin; \ ++ (_pAd)->StaActive.CapabilityInfo = (_pAd)->MlmeAux.CapabilityInfo; \ ++ (_pAd)->CommonCfg.BeaconPeriod = (_pAd)->MlmeAux.BeaconPeriod; \ ++ (_pAd)->StaActive.CfpMaxDuration = (_pAd)->MlmeAux.CfpMaxDuration; \ ++ (_pAd)->StaActive.CfpPeriod = (_pAd)->MlmeAux.CfpPeriod; \ ++ (_pAd)->StaActive.SupRateLen = (_pAd)->MlmeAux.SupRateLen; \ ++ NdisMoveMemory((_pAd)->StaActive.SupRate, (_pAd)->MlmeAux.SupRate, (_pAd)->MlmeAux.SupRateLen);\ ++ (_pAd)->StaActive.ExtRateLen = (_pAd)->MlmeAux.ExtRateLen; \ ++ NdisMoveMemory((_pAd)->StaActive.ExtRate, (_pAd)->MlmeAux.ExtRate, (_pAd)->MlmeAux.ExtRateLen);\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APEdcaParm, &(_pAd)->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APQosCapability, &(_pAd)->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APQbssLoad, &(_pAd)->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));\ ++ COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].Addr, (_pAd)->MlmeAux.Bssid); \ ++ (_pAd)->MacTab.Content[BSSID_WCID].Aid = (_pAd)->MlmeAux.Aid; \ ++ (_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = (_pAd)->StaCfg.PairCipher;\ ++ COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.BssId, (_pAd)->MlmeAux.Bssid);\ ++ (_pAd)->MacTab.Content[BSSID_WCID].RateLen = (_pAd)->StaActive.SupRateLen + (_pAd)->StaActive.ExtRateLen;\ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++*/ ++VOID MlmeCntlInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ // Control state machine differs from other state machines, the interface ++ // follows the standard interface ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID MlmeCntlMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ switch(pAd->Mlme.CntlMachine.CurrState) ++ { ++ case CNTL_IDLE: ++ CntlIdleProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_DISASSOC: ++ CntlWaitDisassocProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_JOIN: ++ CntlWaitJoinProc(pAd, Elem); ++ break; ++ ++ // CNTL_WAIT_REASSOC is the only state in CNTL machine that does ++ // not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". ++ // Therefore not protected by NDIS's "only one outstanding OID request" ++ // rule. Which means NDIS may SET OID in the middle of ROAMing attempts. ++ // Current approach is to block new SET request at RTMPSetInformation() ++ // when CntlMachine.CurrState is not CNTL_IDLE ++ case CNTL_WAIT_REASSOC: ++ CntlWaitReassocProc(pAd, Elem); ++ break; ++ ++ case CNTL_WAIT_START: ++ CntlWaitStartProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_AUTH: ++ CntlWaitAuthProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_AUTH2: ++ CntlWaitAuthProc2(pAd, Elem); ++ break; ++ case CNTL_WAIT_ASSOC: ++ CntlWaitAssocProc(pAd, Elem); ++ break; ++ ++ case CNTL_WAIT_OID_LIST_SCAN: ++ if(Elem->MsgType == MT2_SCAN_CONF) ++ { ++ // Resume TxRing after SCANING complete. We hope the out-of-service time ++ // won't be too long to let upper layer time-out the waiting frames ++ RTMPResumeMsduTransmission(pAd); ++ if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) ++ { ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ ++ // ++ // Set LED status to previous status. ++ // ++ if (pAd->bLedOnScanning) ++ { ++ pAd->bLedOnScanning = FALSE; ++ RTMPSetLED(pAd, pAd->LedStatus); ++ } ++#ifdef DOT11N_DRAFT3 ++ // AP sent a 2040Coexistence mgmt frame, then station perform a scan, and then send back the respone. ++ if (pAd->CommonCfg.BSSCoexist2040.field.InfoReq == 1) ++ { ++ Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); ++ } ++#endif // DOT11N_DRAFT3 // ++ } ++ break; ++ ++ case CNTL_WAIT_OID_DISASSOC: ++ if (Elem->MsgType == MT2_DISASSOC_CONF) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++ break; ++#ifdef RT2870 ++ // ++ // This state is for that we want to connect to an AP but ++ // it didn't find on BSS List table. So we need to scan the air first, ++ // after that we can try to connect to the desired AP if available. ++ // ++ case CNTL_WAIT_SCAN_FOR_CONNECT: ++ if(Elem->MsgType == MT2_SCAN_CONF) ++ { ++ // Resume TxRing after SCANING complete. We hope the out-of-service time ++ // won't be too long to let upper layer time-out the waiting frames ++ RTMPResumeMsduTransmission(pAd); ++#ifdef CCX_SUPPORT ++ if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) ++ { ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++#endif // CCX_SUPPORT // ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ ++ // ++ // Check if we can connect to. ++ // ++ BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ if (pAd->MlmeAux.SsidBssTab.BssNr > 0) ++ { ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ } ++ break; ++#endif // RT2870 // ++ default: ++ DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType)); ++ break; ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlIdleProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ switch(Elem->MsgType) ++ { ++ case OID_802_11_SSID: ++ CntlOidSsidProc(pAd, Elem); ++ break; ++ ++ case OID_802_11_BSSID: ++ CntlOidRTBssidProc(pAd,Elem); ++ break; ++ ++ case OID_802_11_BSSID_LIST_SCAN: ++ CntlOidScanProc(pAd,Elem); ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAd->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ } ++ break; ++ ++ case MT2_MLME_ROAMING_REQ: ++ CntlMlmeRoamingProc(pAd, Elem); ++ break; ++ ++ case OID_802_11_MIC_FAILURE_REPORT_FRAME: ++ WpaMicFailureReportFrame(pAd, Elem); ++ break; ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS_PARAM: ++ CntlOidDLSSetupProc(pAd, Elem); ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType)); ++ break; ++ } ++} ++ ++VOID CntlOidScanProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ULONG BssIdx = BSS_NOT_FOUND; ++ BSS_ENTRY CurrBss; ++ ++#ifdef RALINK_ATE ++/* Disable scanning when ATE is running. */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++ // record current BSS if network is connected. ++ // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ BssIdx = BssSsidTableSearch(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->CommonCfg.Channel); ++ if (BssIdx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(&CurrBss, &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); ++ } ++ } ++ ++ // clean up previous SCAN result, add current BSS back to table if any ++ BssTableInit(&pAd->ScanTab); ++ if (BssIdx != BSS_NOT_FOUND) ++ { ++ // DDK Note: If the NIC is associated with a particular BSSID and SSID ++ // that are not contained in the list of BSSIDs generated by this scan, the ++ // BSSID description of the currently associated BSSID and SSID should be ++ // appended to the list of BSSIDs in the NIC's database. ++ // To ensure this, we append this BSS as the first entry in SCAN result ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY)); ++ pAd->ScanTab.BssNr = 1; ++ } ++ ++ ScanParmFill(pAd, &ScanReq, "", 0, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, ++ sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Before calling this routine, user desired SSID should already been ++ recorded in CommonCfg.Ssid[] ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidSsidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem) ++{ ++ PNDIS_802_11_SSID pOidSsid = (NDIS_802_11_SSID *)Elem->Msg; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ULONG Now; ++ ++ // Step 1. record the desired user settings to MlmeAux ++ NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength); ++ pAd->MlmeAux.SsidLen = (UCHAR)pOidSsid->SsidLength; ++ NdisZeroMemory(pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ pAd->MlmeAux.BssType = pAd->StaCfg.BssType; ++ ++ ++ // ++ // Update Reconnect Ssid, that user desired to connect. ++ // ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; ++ ++ // step 2. find all matching BSS in the lastest SCAN result (inBssTab) ++ // & log them into MlmeAux.SsidBssTab for later-on iteration. Sort by RSSI order ++ BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - %d BSS of %d BSS match the desire (%d)SSID - %s\n", ++ pAd->MlmeAux.SsidBssTab.BssNr, pAd->ScanTab.BssNr, pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid)); ++ NdisGetSystemUpTime(&Now); ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ (pAd->CommonCfg.SsidLen == pAd->MlmeAux.SsidBssTab.BssEntry[0].SsidLen) && ++ NdisEqualMemory(pAd->CommonCfg.Ssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Ssid, pAd->CommonCfg.SsidLen) && ++ MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Bssid)) ++ { ++ // Case 1. already connected with an AP who has the desired SSID ++ // with highest RSSI ++ ++ // Add checking Mode "LEAP" for CCX 1.0 ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ // case 1.1 For WPA, WPA-PSK, if the 1x port is not secured, we have to redo ++ // connection process ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else if (pAd->bConfigChanged == TRUE) ++ { ++ // case 1.2 Important Config has changed, we have to reconnect to the same AP ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP Because config changed...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ // case 1.3. already connected to the SSID with highest RSSI. ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - already with this BSSID. ignore this SET_SSID request\n")); ++ // ++ // (HCT 12.1) 1c_wlan_mediaevents required ++ // media connect events are indicated when associating with the same AP ++ // ++ if (INFRA_ON(pAd)) ++ { ++ // ++ // Since MediaState already is NdisMediaStateConnected ++ // We just indicate the connect event again to meet the WHQL required. ++ // ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up ++ } ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ else if (INFRA_ON(pAd)) ++ { ++ // ++ // For RT61 ++ // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) ++ // RT61 may lost SSID, and not connect to NDTEST_WEP_AP2 and will connect to NDTEST_WEP_AP2 by Autoreconnect ++ // But media status is connected, so the SSID not report correctly. ++ // ++ if (!SSID_EQUAL(pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen)) ++ { ++ // ++ // Different SSID means not Roaming case, so we let LinkDown() to Indicate a disconnect event. ++ // ++ pAd->MlmeAux.CurrReqIsFromNdis = TRUE; ++ } ++ // case 2. active INFRA association existent ++ // roaming is done within miniport driver, nothing to do with configuration ++ // utility. so upon a new SET(OID_802_11_SSID) is received, we just ++ // disassociate with the current associated AP, ++ // then perform a new association with this new SSID, no matter the ++ // new/old SSID are the same or not. ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ if (ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - drop current ADHOC\n")); ++ LinkDown(pAd, FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); ++ } ++ ++ if ((pAd->MlmeAux.SsidBssTab.BssNr == 0) && ++ (pAd->StaCfg.bAutoReconnect == TRUE) && ++ (pAd->MlmeAux.BssType == BSS_INFRA) && ++ (MlmeValidateSSID(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen) == TRUE) ++ ) ++ { ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - No matching BSS, start a new scan\n")); ++ ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ // Reset Missed scan number ++ pAd->StaCfg.LastScanTime = Now; ++ } ++ else ++ { ++ pAd->MlmeAux.BssIdx = 0; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidRTBssidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem) ++{ ++ ULONG BssIdx; ++ PUCHAR pOidBssid = (PUCHAR)Elem->Msg; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ MLME_JOIN_REQ_STRUCT JoinReq; ++ ++#ifdef RALINK_ATE ++/* No need to perform this routine when ATE is running. */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ // record user desired settings ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid); ++ pAd->MlmeAux.BssType = pAd->StaCfg.BssType; ++ ++ // ++ // Update Reconnect Ssid, that user desired to connect. ++ // ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ ++ // find the desired BSS in the latest SCAN result table ++ BssIdx = BssTableSearch(&pAd->ScanTab, pOidBssid, pAd->MlmeAux.Channel); ++ if (BssIdx == BSS_NOT_FOUND) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ return; ++ } ++ ++ // copy the matched BSS entry from ScanTab to MlmeAux.SsidBssTab. Why? ++ // Because we need this entry to become the JOIN target in later on SYNC state machine ++ pAd->MlmeAux.BssIdx = 0; ++ pAd->MlmeAux.SsidBssTab.BssNr = 1; ++ NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); ++ ++ //pAd->MlmeAux.AutoReconnectSsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; ++ //NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->ScanTab.BssEntry[BssIdx].SsidLen); ++ ++ // Add SSID into MlmeAux for site surey joining hidden SSID ++ //pAd->MlmeAux.SsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; ++ //NdisMoveMemory(pAd->MlmeAux.Ssid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->MlmeAux.SsidLen); ++ ++ // 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP ++ // we just follow normal procedure. The reason of user doing this may because he/she changed ++ // AP to another channel, but we still received BEACON from it thus don't claim Link Down. ++ // Since user knows he's changed AP channel, he'll re-connect again. By skipping the following ++ // checking, we'll disassociate then re-do normal association with this AP at the new channel. ++ // 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do ++ // connection when setting the same BSSID. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pOidBssid)) ++ { ++ // already connected to the same BSSID, go back to idle state directly ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ else ++ { ++ if (INFRA_ON(pAd)) ++ { ++ // disassoc from current AP first ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - disassociate with current AP ...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ if (ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n")); ++ LinkDown(pAd, FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); ++ } ++ ++ // Change the wepstatus to original wepstatus ++ pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ // Set the Pairwise and Group cipher to match the intended AP setting ++ // We can only connect to AP with less secured cipher setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher; ++ else if (pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher; ++ else if (pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ ++ // RSN capability ++ pAd->StaCfg.RsnCapability = pAd->ScanTab.BssEntry[BssIdx].WPA2.RsnCapability; ++ } ++ ++ // Set Mix cipher flag ++ pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; ++ if (pAd->StaCfg.bMixCipher == TRUE) ++ { ++ // If mix cipher, re-build RSNIE ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ } ++ // No active association, join the BSS immediately ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pOidBssid[0],pOidBssid[1],pOidBssid[2],pOidBssid[3],pOidBssid[4],pOidBssid[5])); ++ ++ JoinParmFill(pAd, &JoinReq, pAd->MlmeAux.BssIdx); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; ++ } ++ } ++} ++ ++// Roaming is the only external request triggering CNTL state machine ++// despite of other "SET OID" operation. All "SET OID" related oerations ++// happen in sequence, because no other SET OID will be sent to this device ++// until the the previous SET operation is complete (successful o failed). ++// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? ++// or been corrupted by other "SET OID"? ++// ++// IRQL = DISPATCH_LEVEL ++VOID CntlMlmeRoamingProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ // TODO: ++ // AP in different channel may show lower RSSI than actual value?? ++ // should we add a weighting factor to compensate it? ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - Roaming in MlmeAux.RoamTab...\n")); ++ ++ NdisMoveMemory(&pAd->MlmeAux.SsidBssTab, &pAd->MlmeAux.RoamTab, sizeof(pAd->MlmeAux.RoamTab)); ++ pAd->MlmeAux.SsidBssTab.BssNr = pAd->MlmeAux.RoamTab.BssNr; ++ ++ BssTableSortByRssi(&pAd->MlmeAux.SsidBssTab); ++ pAd->MlmeAux.BssIdx = 0; ++ IterateOnBssTab(pAd); ++} ++ ++#ifdef QOS_DLS_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidDLSSetupProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRT_802_11_DLS pDLS = (PRT_802_11_DLS)Elem->Msg; ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ INT i; ++ USHORT reason = REASON_UNSPECIFY; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - (OID set %02x:%02x:%02x:%02x:%02x:%02x with Valid=%d, Status=%d, TimeOut=%d, CountDownTimer=%d)\n", ++ pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5], ++ pDLS->Valid, pDLS->Status, pDLS->TimeOut, pDLS->CountDownTimer)); ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ // DLS will not be supported when Adhoc mode ++ if (INFRA_ON(pAd)) ++ { ++ for (i = 0; i < MAX_NUM_OF_DLS_ENTRY; i++) ++ { ++ if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ (pDLS->TimeOut == pAd->StaCfg.DLSEntry[i].TimeOut) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 1. Same setting, just drop it ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - setting unchanged\n")); ++ break; ++ } ++ else if (!pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 2. Disable DLS link case, just tear down DLS link ++ reason = REASON_QOS_UNWANTED_MECHANISM; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - start tear down procedure\n")); ++ break; ++ } ++ else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && !pAd->StaCfg.DLSEntry[i].Valid) ++ { ++ // 3. Enable case, start DLS setup procedure ++ NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); ++ ++ //Update countdown timer ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS setup case\n")); ++ break; ++ } ++ else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && !MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 4. update mac case, tear down old DLS and setup new DLS ++ reason = REASON_QOS_UNWANTED_MECHANISM; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS tear down and restart case\n")); ++ break; ++ } ++ else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr) && (pAd->StaCfg.DLSEntry[i].TimeOut != pDLS->TimeOut)) ++ { ++ // 5. update timeout case, start DLS setup procedure (no tear down) ++ pAd->StaCfg.DLSEntry[i].TimeOut = pDLS->TimeOut; ++ //Update countdown timer ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS update timeout case\n")); ++ break; ++ } ++ else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ (pAd->StaCfg.DLSEntry[i].Status != DLS_FINISH) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 6. re-setup case, start DLS setup procedure (no tear down) ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS retry setup procedure\n")); ++ break; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN,("CNTL - DLS not changed in entry - %d - Valid=%d, Status=%d, TimeOut=%d\n", ++ i, pAd->StaCfg.DLSEntry[i].Valid, pAd->StaCfg.DLSEntry[i].Status, pAd->StaCfg.DLSEntry[i].TimeOut)); ++ } ++ } ++ } ++} ++#endif // QOS_DLS_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitDisassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_START_REQ_STRUCT StartReq; ++ ++ if (Elem->MsgType == MT2_DISASSOC_CONF) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Dis-associate successful\n")); ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ LinkDown(pAd, FALSE); ++ ++ // case 1. no matching BSS, and user wants ADHOC, so we just start a new one ++ if ((pAd->MlmeAux.SsidBssTab.BssNr==0) && (pAd->StaCfg.BssType == BSS_ADHOC)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ // case 2. try each matched BSS ++ else ++ { ++ pAd->MlmeAux.BssIdx = 0; ++ ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitJoinProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_JOIN_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ // 1. joined an IBSS, we are pretty much done here ++ if (pAd->MlmeAux.BssType == BSS_ADHOC) ++ { ++ // ++ // 5G bands rules of Japan: ++ // Ad hoc must be disabled in W53(ch52,56,60,64) channels. ++ // ++ if ( (pAd->CommonCfg.bIEEE80211H == 1) && ++ RadarChannelCheck(pAd, pAd->CommonCfg.Channel) ++ ) ++ { ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Join adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); ++ return; ++ } ++ ++ LinkUp(pAd, BSS_ADHOC); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - join the IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ } ++ // 2. joined a new INFRA network, start from authentication ++ else ++ { ++#ifdef LEAP_SUPPORT ++ // Add AuthMode "LEAP" for CCX 1.X ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); ++ } ++ else ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ } ++ } ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH; ++ } ++ } ++ else ++ { ++ // 3. failed, try next BSS ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitStartProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Result; ++ ++ if (Elem->MsgType == MT2_START_CONF) ++ { ++ NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); ++ if (Result == MLME_SUCCESS) ++ { ++ // ++ // 5G bands rules of Japan: ++ // Ad hoc must be disabled in W53(ch52,56,60,64) channels. ++ // ++ if ( (pAd->CommonCfg.bIEEE80211H == 1) && ++ RadarChannelCheck(pAd, pAd->CommonCfg.Channel) ++ ) ++ { ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); ++ return; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ N_ChannelCheck(pAd); ++ SetCommonHT(pAd); ++ NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &pAd->CommonCfg.AddHTInfo, sizeof(ADD_HT_INFO_IE)); ++ RTMPCheckHt(pAd, BSSID_WCID, &pAd->CommonCfg.HtCapability, &pAd->CommonCfg.AddHTInfo); ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ NdisZeroMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], 16); ++ NdisMoveMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], &pAd->CommonCfg.HtCapability.MCSSet[0], 16); ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ ++ if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) ++ { ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) ++ { ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ } ++ LinkUp(pAd, BSS_ADHOC); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ // Before send beacon, driver need do radar detection ++ if ((pAd->CommonCfg.Channel > 14 ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE; ++ pAd->CommonCfg.RadarDetect.RDCount = 0; ++#ifdef DFS_SUPPORT ++ BbpRadarDetectionStart(pAd); ++#endif // DFS_SUPPORT // ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Start IBSS fail. BUG!!!!!\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAuthProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_ASSOC_REQ_STRUCT AssocReq; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_AUTH_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); ++ AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ ++#ifdef LEAP_SUPPORT ++ // ++ // Cisco Leap CCKM supported Re-association. ++ // ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ //if CCKM is turn on , that's mean Fast Reauthentication ++ //Use CCKM Reassociation instead of normal association for Fast Roaming. ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; ++ } ++ } ++ else ++ { ++ // This fail may because of the AP already keep us in its MAC table without ++ // ageing-out. The previous authentication attempt must have let it remove us. ++ // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n")); ++#ifdef LEAP_SUPPORT ++ //Add AuthMode "LEAP" for CCX 1.X ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) ++ { ++ // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); ++ } ++ else ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ } ++ } ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAuthProc2( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_ASSOC_REQ_STRUCT AssocReq; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_AUTH_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); ++ AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; ++ } ++ else ++ { ++#ifdef LEAP_SUPPORT ++ // Process LEAP first, since it use different control variable ++ // We don't want to affect other poven operation ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ // LEAP Auth not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - *LEAP* AUTH FAIL, give up; try next BSS\n")); ++ DBGPRINT(RT_DEBUG_TRACE, ("Total match BSSID [=%d]\n", pAd->MlmeAux.SsidBssTab.BssNr)); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && ++ (pAd->MlmeAux.Alg == Ndis802_11AuthModeShared)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try OPEN system...\n")); ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; ++ } ++ else ++ { ++ // not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, give up; try next BSS\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //??????? ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAssocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ ++ if (Elem->MsgType == MT2_ASSOC_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ LinkUp(pAd, BSS_INFRA); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association successful on BSS #%ld\n",pAd->MlmeAux.BssIdx)); ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++ else ++ { ++ // not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association fails on BSS #%ld\n",pAd->MlmeAux.BssIdx)); ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitReassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Result; ++ ++ if (Elem->MsgType == MT2_REASSOC_CONF) ++ { ++ NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); ++ if (Result == MLME_SUCCESS) ++ { ++ // ++ // NDIS requires a new Link UP indication but no Link Down for RE-ASSOC ++ // ++ LinkUp(pAd, BSS_INFRA); ++ ++ // send wireless event - for association ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ STA_PORT_SECURED(pAd); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++#endif // LEAP_SUPPORT // ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); ++ } ++ else ++ { ++ // reassoc failed, try to pick next BSS in the BSS Table ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition fails on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); ++ pAd->MlmeAux.RoamIdx++; ++ IterateOnBssTab2(pAd); ++ } ++ } ++} ++ ++ ++VOID AdhocTurnOnQos( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define AC0_DEF_TXOP 0 ++#define AC1_DEF_TXOP 0 ++#define AC2_DEF_TXOP 94 ++#define AC3_DEF_TXOP 47 ++ ++ // Turn on QOs if use HT rate. ++ if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) ++ { ++ pAd->CommonCfg.APEdcaParm.bValid = TRUE; ++ pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; ++ pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; ++ pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; ++ pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; ++ pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10; ++ pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6; ++ pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; ++ ++ pAd->CommonCfg.APEdcaParm.Txop[0] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[1] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP; ++ pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP; ++ } ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID LinkUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssType) ++{ ++ ULONG Now; ++ UINT32 Data; ++ BOOLEAN Cancelled; ++ UCHAR Value = 0, idx; ++ MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; ++ ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ ++ // ++ // ASSOC - DisassocTimeoutAction ++ // CNTL - Dis-associate successful ++ // !!! LINK DOWN !!! ++ // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) ++ // ++ // To prevent DisassocTimeoutAction to call Link down after we link up, ++ // cancel the DisassocTimer no matter what it start or not. ++ // ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ ++ COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ ++#ifdef DOT11_N_SUPPORT ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++#endif // DOT11_N_SUPPORT // ++ // It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS ++ // is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place ++ // to examine if cipher algorithm switching is required. ++ //rt2860b. Don't know why need this ++ SwitchBetweenWepAndCkip(pAd); ++ ++ ++ if (BssType == BSS_ADHOC) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // No carrier detection when adhoc ++ // CarrierDetectionStop(pAd); ++ pAd->CommonCfg.CarrierDetect.CD_State = CD_NORMAL; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ AdhocTurnOnQos(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" )); ++ } ++ else ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!Infra LINK UP !!! \n" )); ++ } ++ ++ // 3*3 ++ // reset Tx beamforming bit ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x01); ++ Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++#ifdef DOT11_N_SUPPORT ++ // Change to AP channel ++ if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! 20MHz LINK UP !!! \n" )); ++ } ++ ++ RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); ++ // ++ // Save BBP_R66 value, it will be used in RTUSBResumeMsduTransmission ++ // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n", ++ BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); ++ ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity)); ++#endif // DOT11_N_SUPPORT // ++ ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ ++ AsicSetSlotTime(pAd, TRUE); ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++ ++ // Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit ++ AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) ++ { ++ // Update HT protectionfor based on AP's operating mode. ++ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); ++ } ++ else ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS)); ++ ++ NdisGetSystemUpTime(&Now); ++ pAd->StaCfg.LastBeaconRxTime = Now; // last RX timestamp ++ ++ if ((pAd->CommonCfg.TxPreamble != Rt802_11PreambleLong) && ++ CAP_IS_SHORT_PREAMBLE_ON(pAd->StaActive.CapabilityInfo)) ++ { ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); ++ } ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ ++ if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE) ++ { ++#ifdef DFS_SUPPORT ++ RadarDetectionStop(pAd); ++#endif // DFS_SUPPORT // ++ } ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ ++ if (BssType == BSS_ADHOC) ++ { ++ MakeIbssBeacon(pAd); ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ ; //Do nothing ++ } ++ else ++ { ++ AsicEnableIbssSync(pAd); ++ } ++ ++ // In ad hoc mode, use MAC table from index 1. ++ // p.s ASIC use all 0xff as termination of WCID table search.To prevent it's 0xff-ff-ff-ff-ff-ff, Write 0 here. ++ RTMP_IO_WRITE32(pAd, MAC_WCID_BASE, 0x00); ++ RTMP_IO_WRITE32(pAd, 0x1808, 0x00); ++ ++ // If WEP is enabled, add key material and cipherAlg into Asic ++ // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) ++ ++ if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ ++ for (idx=0; idx < SHARE_KEY_NUM; idx++) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][idx].Key; ++ ++ if (pAd->SharedKey[BSS0][idx].KeyLen > 0) ++ { ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ if (idx == pAd->StaCfg.DefaultKeyId) ++ { ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ } ++ } ++ ++ ++ } ++ } ++ // If WPANone is enabled, add key material and cipherAlg into Asic ++ // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) ++ else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAd->StaCfg.DefaultKeyId = 0; // always be zero ++ ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); ++ ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Unknow Cipher (=%d), set Cipher to AES\n", pAd->StaCfg.PairCipher)); ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ } ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, NULL); ++ ++ } ++ ++ } ++ else // BSS_INFRA ++ { ++ // Check the new SSID with last SSID ++ while (Cancelled == TRUE) ++ { ++ if (pAd->CommonCfg.LastSsidLen == pAd->CommonCfg.SsidLen) ++ { ++ if (RTMPCompareMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen) == 0) ++ { ++ // Link to the old one no linkdown is required. ++ break; ++ } ++ } ++ // Send link down event before set to link up ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event AA!\n")); ++ break; ++ } ++ ++ // ++ // On WPA mode, Remove All Keys if not connect to the last BSSID ++ // Key will be set after 4-way handshake. ++ // ++ if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ ULONG IV; ++ ++ // Remove all WPA keys ++ RTMPWPARemoveAllKeys(pAd); ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ ++ // Fixed connection failed with Range Maximizer - 515 AP (Marvell Chip) when security is WPAPSK/TKIP ++ // If IV related values are too large in GroupMsg2, AP would ignore this message. ++ IV = 0; ++ IV |= (pAd->StaCfg.DefaultKeyId << 30); ++ AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); ++ } ++ // NOTE: ++ // the decision of using "short slot time" or not may change dynamically due to ++ // new STA association to the AP. so we have to decide that upon parsing BEACON, not here ++ ++ // NOTE: ++ // the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically ++ // due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here ++ ++ ComposePsPoll(pAd); ++ ComposeNullFrame(pAd); ++ ++ AsicEnableBssSync(pAd); ++ ++ // Add BSSID to WCID search table ++ AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid); ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ // add this BSSID entry into HASH table ++ { ++ UCHAR HashIdx; ++ ++ //pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ HashIdx = MAC_ADDR_HASH_INDEX(pAd->CommonCfg.Bssid); ++ if (pAd->MacTab.Hash[HashIdx] == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pAd->MacTab.Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ ++ // If WEP is enabled, add paiewise and shared key ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (((pAd->StaCfg.WpaSupplicantUP)&& ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&& ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || ++ ((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&& ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled))) ++#else ++ if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ ++ for (idx=0; idx < SHARE_KEY_NUM; idx++) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][idx].Key; ++ ++ if (pAd->SharedKey[BSS0][idx].KeyLen > 0) ++ { ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ if (idx == pAd->StaCfg.DefaultKeyId) ++ { ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry); ++ } ++ } ++ } ++ } ++ ++ // only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode ++ // should wait until at least 2 active nodes in this BSSID. ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ // For GUI ++ ++ if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ { ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ RTMP_IndicateMediaState(pAd); ++ } ++ // -- ++ ++ // Add BSSID in my MAC Table. ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ RTMPMoveMemory(pAd->MacTab.Content[BSSID_WCID].Addr, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); ++ pAd->MacTab.Content[BSSID_WCID].Aid = BSSID_WCID; ++ pAd->MacTab.Content[BSSID_WCID].pAd = pAd; ++ pAd->MacTab.Content[BSSID_WCID].ValidAsCLI = TRUE; //Although this is bssid..still set ValidAsCl ++ pAd->MacTab.Size = 1; // infra mode always set MACtab size =1. ++ pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC; ++ pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC; ++ pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! ClientStatusFlags=%lx)\n", ++ pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++ ++ MlmeUpdateTxRates(pAd, TRUE, BSS0); ++#ifdef DOT11_N_SUPPORT ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable)); ++#endif // DOT11_N_SUPPORT // ++ ++ // ++ // Report Adjacent AP report. ++ // ++#ifdef LEAP_SUPPORT ++ CCXAdjacentAPReport(pAd); ++#endif // LEAP_SUPPORT // ++ ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && (pAd->MlmeAux.APRalinkIe & 0x00000003) == 3) ++ { ++ ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ RTMPSetPiggyBack(pAd, TRUE); ++ DBGPRINT(RT_DEBUG_TRACE, ("Turn on Piggy-Back\n")); ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ } ++ } ++ ++ if (pAd->MlmeAux.APRalinkIe != 0x0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE)) ++ { ++ AsicEnableRDG(pAd); ++ } ++#endif // DOT11_N_SUPPORT // ++ OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); ++ } ++ else ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); ++ CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); ++ } ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++#endif // DOT11_N_SUPPORT // ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_LINK_UP); ++ ++ pAd->Mlme.PeriodicRound = 0; ++ pAd->Mlme.OneSecPeriodicRound = 0; ++ pAd->bConfigChanged = FALSE; // Reset config flag ++ pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up ++ ++ // Set asic auto fall back ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, &pAd->MacTab.Content[BSSID_WCID], &pTable, &TableSize, &pAd->CommonCfg.TxRateIndex); ++ AsicUpdateAutoFallBackTable(pAd, pTable); ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ pEntry->MaxHTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ if (pAd->StaCfg.bAutoTxRateSwitch == FALSE) ++ { ++ pEntry->bAutoTxRateSwitch = FALSE; ++#ifdef DOT11_N_SUPPORT ++ if (pEntry->HTPhyMode.field.MCS == 32) ++ pEntry->HTPhyMode.field.ShortGI = GI_800; ++ ++ if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32)) ++ pEntry->HTPhyMode.field.STBC = STBC_NONE; ++#endif // DOT11_N_SUPPORT // ++ // If the legacy mode is set, overwrite the transmit setting of this entry. ++ if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM) ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ else ++ pEntry->bAutoTxRateSwitch = TRUE; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ // Let Link Status Page display first initial rate. ++ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); ++ // Select DAC according to HT or Legacy ++ if (pAd->StaActive.SupportedPhyInfo.MCSSet[0] != 0x00) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); ++ Value &= (~0x18); ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ Value |= 0x10; ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ { ++ } ++ else if (pEntry->MaxRAmpduFactor == 0) ++ { ++ // If HT AP doesn't support MaxRAmpduFactor = 1, we need to set max PSDU to 0. ++ // Because our Init value is 1 at MACRegTable. ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Patch for Marvel AP to gain high throughput ++ // Need to set as following, ++ // 1. Set txop in register-EDCA_AC0_CFG as 0x60 ++ // 2. Set EnTXWriteBackDDONE in register-WPDMA_GLO_CFG as zero ++ // 3. PBF_MAX_PCNT as 0x1F3FBF9F ++ // 4. kick per two packets when dequeue ++ // ++ // Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable ++ // ++ // if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is. ++#ifdef DOT11_N_SUPPORT ++ if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))) ++ || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE))) ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n")); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.bEnableTxBurst) ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ Data |= 0x60; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = TRUE; ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3FBF9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 2\n")); ++ } ++ else ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n")); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // Re-check to turn on TX burst or not. ++ if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd)))) ++ { ++ pAd->CommonCfg.IOTestParm.bNextDisableRxBA = TRUE; ++ if (pAd->CommonCfg.bEnableTxBurst) ++ { ++ UINT32 MACValue = 0; ++ // Force disable TXOP value in this case. The same action in MLMEUpdateProtect too. ++ // I didn't change PBF_MAX_PCNT setting. ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &MACValue); ++ MACValue &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, MACValue); ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE; ++ COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!pAd->bNextDisableRxBA= %d \n", pAd->CommonCfg.IOTestParm.bNextDisableRxBA)); ++ // BSSID add in one MAC entry too. Because in Tx, ASIC need to check Cipher and IV/EIV, BAbitmap ++ // Pther information in MACTab.Content[BSSID_WCID] is not necessary for driver. ++ // Note: As STA, The MACTab.Content[BSSID_WCID]. PairwiseKey and Shared Key for BSS0 are the same. ++ ++ if (pAd->StaCfg.WepStatus <= Ndis802_11WEPDisabled) ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll; ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pEntry->PortSecured = pAd->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ // ++ // Patch Atheros AP TX will breakdown issue. ++ // AP Model: DLink DWL-8200AP ++ // ++ if (INFRA_ON(pAd) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && STA_TKIP_ON(pAd)) ++ { ++ RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x01); ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x00); ++ } ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if ((pAd->CommonCfg.BACapability.field.b2040CoexistScanSup) && (pAd->CommonCfg.Channel <= 11)) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SCAN_2040); ++ BuildEffectedChannelList(pAd); ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++} ++ ++/* ++ ========================================================================== ++ ++ Routine Description: ++ Disconnect current BSSID ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ IsReqFromAP - Request from AP ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ We need more information to know it's this requst from AP. ++ If yes! we need to do extra handling, for example, remove the WPA key. ++ Otherwise on 4-way handshaking will faied, since the WPA key didn't be ++ remove while auto reconnect. ++ Disconnect request from AP, it means we will start afresh 4-way handshaking ++ on WPA mode. ++ ++ ========================================================================== ++*/ ++VOID LinkDown( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN IsReqFromAP) ++{ ++ UCHAR i, ByteValue = 0; ++ ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ ++ if (ADHOC_ON(pAd)) // Adhoc mode link down ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MacTab.Size=%d !!!\n", pAd->MacTab.Size)); ++ } ++ else // Infra structure mode ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n")); ++ ++#ifdef QOS_DLS_SUPPORT ++ // DLS tear down frame must be sent before link down ++ // send DLS-TEAR_DOWN message ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ // Saved last SSID for linkup comparison ++ pAd->CommonCfg.LastSsidLen = pAd->CommonCfg.SsidLen; ++ NdisMoveMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen); ++ COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); ++ if (pAd->MlmeAux.CurrReqIsFromNdis == TRUE) ++ { ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event A!\n")); ++ pAd->MlmeAux.CurrReqIsFromNdis = FALSE; ++ } ++ else ++ { ++ // ++ // If disassociation request is from NDIS, then we don't need to delete BSSID from entry. ++ // Otherwise lost beacon or receive De-Authentication from AP, ++ // then we should delete BSSID from BssTable. ++ // If we don't delete from entry, roaming will fail. ++ // ++ BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); ++ } ++ ++ // restore back to - ++ // 1. long slot (20 us) or short slot (9 us) time ++ // 2. turn on/off RTS/CTS and/or CTS-to-self protection ++ // 3. short preamble ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ ++ if (pAd->StaCfg.CCXAdjacentAPReportFlag == TRUE) ++ { ++ // ++ // Record current AP's information. ++ // for later used reporting Adjacent AP report. ++ // ++ pAd->StaCfg.CCXAdjacentAPChannel = pAd->CommonCfg.Channel; ++ pAd->StaCfg.CCXAdjacentAPSsidLen = pAd->CommonCfg.SsidLen; ++ NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen); ++ COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid); ++ } ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // Country IE of the AP will be evaluated and will be used. ++ if (pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) ++ { ++ NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pAd->StaCfg.StaOriCountryCode[0], 2); ++ pAd->CommonCfg.Geography = pAd->StaCfg.StaOriGeography; ++ BuildChannelListEx(pAd); ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ } ++ ++ for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) ++ MacTableDeleteEntry(pAd, pAd->MacTab.Content[i].Aid, pAd->MacTab.Content[i].Addr); ++ } ++ ++ pAd->StaCfg.CCXQosECWMin = 4; ++ pAd->StaCfg.CCXQosECWMax = 10; ++ ++ AsicSetSlotTime(pAd, TRUE); //FALSE); ++ AsicSetEdcaParm(pAd, NULL); ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_LINK_DOWN); ++ pAd->LedIndicatorStregth = 0xF0; ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. ++ ++ AsicDisableSync(pAd); ++ ++ pAd->Mlme.PeriodicRound = 0; ++ pAd->Mlme.OneSecPeriodicRound = 0; ++ ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ { ++ // Remove StaCfg Information after link down ++ NdisZeroMemory(pAd->CommonCfg.Bssid, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->CommonCfg.Ssid, MAX_LEN_OF_SSID); ++ pAd->CommonCfg.SsidLen = 0; ++ } ++#ifdef DOT11_N_SUPPORT ++ NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE)); ++ NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ pAd->MlmeAux.HtCapabilityLen = 0; ++ pAd->MlmeAux.NewExtChannelOffset = 0xff; ++#endif // DOT11_N_SUPPORT // ++ ++ // Reset WPA-PSK state. Only reset when supplicant enabled ++ if (pAd->StaCfg.WpaState != SS_NOTUSE) ++ { ++ pAd->StaCfg.WpaState = SS_START; ++ // Clear Replay counter ++ NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); ++ ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->CommonCfg.bDLSCapable) ++ NdisZeroMemory(pAd->StaCfg.DlsReplayCounter, 8); ++#endif // QOS_DLS_SUPPORT // ++ } ++ ++ ++ // ++ // if link down come from AP, we need to remove all WPA keys on WPA mode. ++ // otherwise will cause 4-way handshaking failed, since the WPA key not empty. ++ // ++ if ((IsReqFromAP) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ // Remove all WPA keys ++ RTMPWPARemoveAllKeys(pAd); ++ } ++ ++ // 802.1x port control ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Prevent clear PortSecured here with static WEP ++ // NetworkManger set security policy first then set SSID to connect AP. ++ if (pAd->StaCfg.WpaSupplicantUP && ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) && ++ (pAd->StaCfg.IEEE8021X == FALSE)) ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pAd->MacTab.Content[BSSID_WCID].PortSecured = pAd->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ pAd->StaCfg.MicErrCnt = 0; ++ ++ // Turn off Ckip control flag ++ pAd->StaCfg.bCkipOn = FALSE; ++ pAd->StaCfg.CCXEnable = FALSE; ++ ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ // Update extra information to link is up ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ ++ //pAd->StaCfg.AdhocBOnlyJoined = FALSE; ++ //pAd->StaCfg.AdhocBGJoined = FALSE; ++ //pAd->StaCfg.Adhoc20NJoined = FALSE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ ++ // Reset the Current AP's IP address ++ NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4); ++#ifdef RT2870 ++ pAd->bUsbTxBulkAggre = FALSE; ++#endif // RT2870 // ++ ++ // Clean association information ++ NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); ++ pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ pAd->StaCfg.ReqVarIELen = 0; ++ pAd->StaCfg.ResVarIELen = 0; ++ ++ // ++ // Reset RSSI value after link down ++ // ++ pAd->StaCfg.RssiSample.AvgRssi0 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi0X8 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi1 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi1X8 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi2 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi2X8 = 0; ++ ++ // Restore MlmeRate ++ pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate; ++ ++#ifdef DOT11_N_SUPPORT ++ // ++ // After Link down, reset piggy-back setting in ASIC. Disable RDG. ++ // ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &ByteValue); ++ ByteValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue); ++ } ++#endif // DOT11_N_SUPPORT // ++ // Reset DAC ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue); ++ ByteValue &= (~0x18); ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ ByteValue |= 0x10; ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, ByteValue); ++ ++ RTMPSetPiggyBack(pAd,FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); ++ ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word; ++#endif // DOT11_N_SUPPORT // ++ ++ // Restore all settings in the following. ++ AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE); ++ AsicDisableRDG(pAd); ++ pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE; ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SCAN_2040); ++ pAd->CommonCfg.BSSCoexist2040.word = 0; ++ TriEventInit(pAd); ++ for (i = 0; i < (pAd->ChannelListNum - 1); i++) ++ { ++ pAd->ChannelList[i].bEffectedChannel = FALSE; ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID IterateOnBssTab( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_START_REQ_STRUCT StartReq; ++ MLME_JOIN_REQ_STRUCT JoinReq; ++ ULONG BssIdx; ++ ++ // Change the wepstatus to original wepstatus ++ pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; ++ ++ BssIdx = pAd->MlmeAux.BssIdx; ++ if (BssIdx < pAd->MlmeAux.SsidBssTab.BssNr) ++ { ++ // Check cipher suite, AP must have more secured cipher than station setting ++ // Set the Pairwise and Group cipher to match the intended AP setting ++ // We can only connect to AP with less secured cipher setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher; ++ else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher; ++ else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ ++ // RSN capability ++ pAd->StaCfg.RsnCapability = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.RsnCapability; ++ } ++ ++ // Set Mix cipher flag ++ pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; ++ if (pAd->StaCfg.bMixCipher == TRUE) ++ { ++ // If mix cipher, re-build RSNIE ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.SsidBssTab.BssNr)); ++ JoinParmFill(pAd, &JoinReq, BssIdx); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), ++ &JoinReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; ++ } ++ else if (pAd->StaCfg.BssType == BSS_ADHOC) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ else // no more BSS ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All roaming failed, stay @ ch #%d\n", pAd->CommonCfg.Channel)); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++} ++ ++// for re-association only ++// IRQL = DISPATCH_LEVEL ++VOID IterateOnBssTab2( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_REASSOC_REQ_STRUCT ReassocReq; ++ ULONG BssIdx; ++ BSS_ENTRY *pBss; ++ ++ BssIdx = pAd->MlmeAux.RoamIdx; ++ pBss = &pAd->MlmeAux.RoamTab.BssEntry[BssIdx]; ++ ++ if (BssIdx < pAd->MlmeAux.RoamTab.BssNr) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.RoamTab.BssNr)); ++ ++ AsicSwitchChannel(pAd, pBss->Channel, FALSE); ++ AsicLockChannel(pAd, pBss->Channel); ++ ++ // reassociate message has the same structure as associate message ++ AssocParmFill(pAd, &ReassocReq, pBss->Bssid, pBss->CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, ++ sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; ++ } ++ else // no more BSS ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All fast roaming failed, back to ch #%d\n",pAd->CommonCfg.Channel)); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID JoinParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, ++ IN ULONG BssIdx) ++{ ++ JoinReq->BssIdx = BssIdx; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID ScanParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN UCHAR ScanType) ++{ ++ NdisZeroMemory(ScanReq->Ssid, MAX_LEN_OF_SSID); ++ ScanReq->SsidLen = SsidLen; ++ NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen); ++ ScanReq->BssType = BssType; ++ ScanReq->ScanType = ScanType; ++} ++ ++#ifdef QOS_DLS_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID DlsParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, ++ IN PRT_802_11_DLS pDls, ++ IN USHORT reason) ++{ ++ pDlsReq->pDLS = pDls; ++ pDlsReq->Reason = reason; ++} ++#endif // QOS_DLS_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID StartParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_START_REQ_STRUCT *StartReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen) ++{ ++ ASSERT(SsidLen <= MAX_LEN_OF_SSID); ++ NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen); ++ StartReq->SsidLen = SsidLen; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID AuthParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, ++ IN PUCHAR pAddr, ++ IN USHORT Alg) ++{ ++ COPY_MAC_ADDR(AuthReq->Addr, pAddr); ++ AuthReq->Alg = Alg; ++ AuthReq->Timeout = AUTH_TIMEOUT; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++ ++ ++#ifdef RT2870 ++ ++VOID MlmeCntlConfirm( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG MsgType, ++ IN USHORT Msg) ++{ ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg); ++} ++ ++VOID ComposePsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTXINFO_STRUC pTxInfo; ++ PTXWI_STRUC pTxWI; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ComposePsPoll\n")); ++ NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++ ++ pAd->PsPollFrame.FC.PwrMgmt = 0; ++ pAd->PsPollFrame.FC.Type = BTYPE_CNTL; ++ pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL; ++ pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000; ++ COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress); ++ ++ RTMPZeroMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0], 100); ++ pTxInfo = (PTXINFO_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0]; ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(PSPOLL_FRAME)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxWI = (PTXWI_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(PSPOLL_FRAME)), ++ 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ RTMPMoveMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++ // Append 4 extra zero bytes. ++ pAd->PsPollContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(PSPOLL_FRAME) + 4; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID ComposeNullFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTXINFO_STRUC pTxInfo; ++ PTXWI_STRUC pTxWI; ++ ++ NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11)); ++ pAd->NullFrame.FC.Type = BTYPE_DATA; ++ pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC; ++ pAd->NullFrame.FC.ToDs = 1; ++ COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); ++ RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], 100); ++ pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), ++ 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); ++ pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; ++} ++#endif // RT2870 // ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Pre-build a BEACON frame in the shared memory ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++ULONG MakeIbssBeacon( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR DsLen = 1, IbssLen = 2; ++ UCHAR LocalErpIe[3] = {IE_ERP, 1, 0x04}; ++ HEADER_802_11 BcnHdr; ++ USHORT CapabilityInfo; ++ LARGE_INTEGER FakeTimestamp; ++ ULONG FrameLen = 0; ++ PTXWI_STRUC pTxWI = &pAd->BeaconTxWI; ++ CHAR *pBeaconFrame = pAd->BeaconBuf; ++ BOOLEAN Privacy; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen = 0; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen = 0; ++ UCHAR RSNIe = IE_WPA; ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11B) && (pAd->CommonCfg.Channel <= 14)) ++ { ++ SupRate[0] = 0x82; // 1 mbps ++ SupRate[1] = 0x84; // 2 mbps ++ SupRate[2] = 0x8b; // 5.5 mbps ++ SupRate[3] = 0x96; // 11 mbps ++ SupRateLen = 4; ++ ExtRateLen = 0; ++ } ++ else if (pAd->CommonCfg.Channel > 14) ++ { ++ SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ SupRateLen = 8; ++ ExtRateLen = 0; ++ ++ // ++ // Also Update MlmeRate & RtsRate for G only & A only ++ // ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ else ++ { ++ SupRate[0] = 0x82; // 1 mbps ++ SupRate[1] = 0x84; // 2 mbps ++ SupRate[2] = 0x8b; // 5.5 mbps ++ SupRate[3] = 0x96; // 11 mbps ++ SupRateLen = 4; ++ ++ ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps, ++ ExtRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ ExtRate[2] = 0x18; // 12 mbps, in units of 0.5 Mbps, ++ ExtRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ ExtRate[4] = 0x30; // 24 mbps, in units of 0.5 Mbps, ++ ExtRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ ExtRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ ExtRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ ExtRateLen = 8; ++ } ++ ++ pAd->StaActive.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->StaActive.SupRate, SupRate, SupRateLen); ++ pAd->StaActive.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, ExtRateLen); ++ ++ // compose IBSS beacon frame ++ MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR, pAd->CommonCfg.Bssid); ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); ++ ++ MakeOutgoingFrame(pBeaconFrame, &FrameLen, ++ sizeof(HEADER_802_11), &BcnHdr, ++ TIMESTAMP_LEN, &FakeTimestamp, ++ 2, &pAd->CommonCfg.BeaconPeriod, ++ 2, &CapabilityInfo, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &SupRateLen, ++ SupRateLen, SupRate, ++ 1, &DsIe, ++ 1, &DsLen, ++ 1, &pAd->CommonCfg.Channel, ++ 1, &IbssIe, ++ 1, &IbssLen, ++ 2, &pAd->StaActive.AtimWin, ++ END_OF_ARGS); ++ ++ // add ERP_IE and EXT_RAE IE of in 802.11g ++ if (ExtRateLen) ++ { ++ ULONG tmp; ++ ++ MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, ++ 3, LocalErpIe, ++ 1, &ExtRateIe, ++ 1, &ExtRateLen, ++ ExtRateLen, ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // If adhoc secruity is set for WPA-None, append the cipher suite IE ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ ULONG tmp; ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ ++ MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen, HtLen1; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++ ADD_HT_INFO_IE addHTInfoTmp; ++ USHORT b2lTmp, b2lTmp2; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(pAd->CommonCfg.HtCapability); ++ HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ 1, &AddHtInfoIe, ++ 1, &HtLen1, ++ HtLen1, &pAd->CommonCfg.AddHTInfo, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1); ++ *(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2)); ++ *(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3)); ++ ++ MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ 1, &AddHtInfoIe, ++ 1, &HtLen1, ++ HtLen1, &addHTInfoTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ //beacon use reserved WCID 0xff ++ if (pAd->CommonCfg.Channel > 14) ++ { ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, ++ PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ // Set to use 1Mbps for Adhoc beacon. ++ HTTRANSMIT_SETTING Transmit; ++ Transmit.word = 0; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, ++ PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n", ++ FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode)); ++ return FrameLen; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/dls.c +@@ -0,0 +1,2210 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ dls.c ++ ++ Abstract: ++ Handle WMM-DLS state machine ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 02-14-2006 ++ Arvin Tai 06-03-2008 Modified for RT28xx ++ */ ++ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ dls state machine init, including state transition and timer init ++ Parameters: ++ Sm - pointer to the dls state machine ++ Note: ++ The state machine looks like this ++ ++ DLS_IDLE ++ MT2_MLME_DLS_REQUEST MlmeDlsReqAction ++ MT2_PEER_DLS_REQUEST PeerDlsReqAction ++ MT2_PEER_DLS_RESPONSE PeerDlsRspAction ++ MT2_MLME_DLS_TEARDOWN MlmeTearDownAction ++ MT2_PEER_DLS_TEARDOWN PeerTearDownAction ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++void DlsStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ UCHAR i; ++ ++ StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_DLS_STATE, MAX_DLS_MSG, (STATE_MACHINE_FUNC)Drop, DLS_IDLE, DLS_MACHINE_BASE); ++ ++ // the first column ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_REQ, (STATE_MACHINE_FUNC)MlmeDlsReqAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_REQ, (STATE_MACHINE_FUNC)PeerDlsReqAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_RSP, (STATE_MACHINE_FUNC)PeerDlsRspAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)MlmeDlsTearDownAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)PeerDlsTearDownAction); ++ ++ for (i=0; iStaCfg.DLSEntry[i].pAd = pAd; ++ RTMPInitTimer(pAd, &pAd->StaCfg.DLSEntry[i].Timer, GET_TIMER_FUNCTION(DlsTimeoutAction), pAd, FALSE); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ HEADER_802_11 DlsReqHdr; ++ PRT_802_11_DLS pDLS = NULL; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_REQUEST; ++ ULONG tmp; ++ USHORT reason; ++ ULONG Timeout; ++ BOOLEAN TimerCancelled; ++ ++ if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &reason)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsReqAction() \n")); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsReqAction() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsReqHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsReqHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, &pDLS->MacAddr, ++ 6, pAd->CurrentAddress, ++ 2, &pAd->StaActive.CapabilityInfo, ++ 2, &pDLS->TimeOut, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR HtLen; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(HT_CAPABILITY_IE); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen = FrameLen + tmp; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ Timeout = DLS_TIMEOUT; ++ RTMPSetTimer(&pDLS->Timer, Timeout); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT StatusCode = MLME_SUCCESS; ++ HEADER_802_11 DlsRspHdr; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_RESPONSE; ++ ULONG tmp; ++ USHORT CapabilityInfo; ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT DLSTimeOut; ++ SHORT i; ++ ULONG Timeout; ++ BOOLEAN TimerCancelled; ++ PRT_802_11_DLS pDLS = NULL; ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR SupportedRatesLen; ++ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR HtCapabilityLen; ++ HT_CAPABILITY_IE HtCapability; ++ ++ if (!PeerDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &DLSTimeOut, ++ &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) ++ return; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (i = 0; i < SupportedRatesLen; i++) ++ { ++ if (MaxSupportedRateIn500Kbps < (SupportedRates[i] & 0x7f)) ++ MaxSupportedRateIn500Kbps = SupportedRates[i] & 0x7f; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() from %02x:%02x:%02x:%02x:%02x:%02x\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() allocate memory failed \n")); ++ return; ++ } ++ ++ if (!INFRA_ON(pAd)) ++ { ++ StatusCode = MLME_REQUEST_DECLINED; ++ } ++ else if (!pAd->CommonCfg.bWmmCapable) ++ { ++ StatusCode = MLME_DEST_STA_IS_NOT_A_QSTA; ++ } ++ else if (!pAd->CommonCfg.bDLSCapable) ++ { ++ StatusCode = MLME_REQUEST_DECLINED; ++ } ++ else ++ { ++ // find table to update parameters ++ for (i = (MAX_NUM_OF_DLS_ENTRY-1); i >= 0; i--) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ } ++ ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ pDLS = &pAd->StaCfg.DLSEntry[i]; ++ break; ++ } ++ } ++ ++ // can not find in table, create a new one ++ if (i < 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() can not find same entry \n")); ++ for (i=(MAX_NUM_OF_DLS_ENTRY - 1); i >= MAX_NUM_OF_INIT_DLS_ENTRY; i--) ++ { ++ if (!pAd->StaCfg.DLSEntry[i].Valid) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ } ++ ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ pAd->StaCfg.DLSEntry[i].Valid = TRUE; ++ pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; ++ NdisMoveMemory(pAd->StaCfg.DLSEntry[i].MacAddr, SA, MAC_ADDR_LEN); ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ pDLS = &pAd->StaCfg.DLSEntry[i]; ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsReqAction() Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ ++ printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ break; ++ } ++ } ++ } ++ StatusCode = MLME_SUCCESS; ++ ++ // can not find in table, create a new one ++ if (i < 0) ++ { ++ StatusCode = MLME_QOS_UNSPECIFY; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() DLSEntry table full(only can support %d DLS session) \n", MAX_NUM_OF_DLS_ENTRY - MAX_NUM_OF_INIT_DLS_ENTRY)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() use entry(%d) %02x:%02x:%02x:%02x:%02x:%02x\n", ++ i, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ } ++ ++ ActHeaderInit(pAd, &DlsRspHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsRspHdr, ++ 1, &Category, ++ 1, &Action, ++ 2, &StatusCode, ++ 6, SA, ++ 6, pAd->CurrentAddress, ++ 2, &pAd->StaActive.CapabilityInfo, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR HtLen; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(HT_CAPABILITY_IE); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen = FrameLen + tmp; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (pDLS && (pDLS->Status != DLS_FINISH)) ++ { ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ Timeout = DLS_TIMEOUT; ++ RTMPSetTimer(&pDLS->Timer, Timeout); ++ } ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsRspHdr, ++ 1, &Category, ++ 1, &Action, ++ 2, &StatusCode, ++ 6, SA, ++ 6, pAd->CurrentAddress, ++ END_OF_ARGS); ++ } ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo; ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT StatusCode; ++ SHORT i; ++ BOOLEAN TimerCancelled; ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR SupportedRatesLen; ++ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR HtCapabilityLen; ++ HT_CAPABILITY_IE HtCapability; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (!INFRA_ON(pAd)) ++ return; ++ ++ if (!PeerDlsRspSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &StatusCode, ++ &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) ++ return; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); ++ } ++ else ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); ++ } ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ ++ //initialize seq no for DLS frames. ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ } ++ else ++ { ++ // DLS setup procedure failed. ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); ++ } ++ } ++ } ++ ++ if (i >= MAX_NUM_OF_INIT_DLS_ENTRY) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() update timeout value \n")); ++ for (i=(MAX_NUM_OF_DLS_ENTRY-1); i>=MAX_NUM_OF_INIT_DLS_ENTRY; i--) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ DBGPRINT(RT_DEBUG_OFF, ("DLS - PeerDlsRspAction Receive Peer HT Capable STA from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); ++ } ++ else ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); ++ } ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ } ++ else ++ { ++ // DLS setup procedure failed. ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); ++ } ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_TEARDOWN; ++ USHORT ReasonCode = REASON_QOS_UNSPECIFY; ++ HEADER_802_11 DlsTearDownHdr; ++ PRT_802_11_DLS pDLS; ++ BOOLEAN TimerCancelled; ++ UCHAR i; ++ ++ if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &ReasonCode)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsTearDownAction() with ReasonCode=%d \n", ReasonCode)); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsTearDownAction() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsTearDownHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, &pDLS->MacAddr, ++ 6, pAd->CurrentAddress, ++ 2, &ReasonCode, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ ++ // Remove key in local dls table entry ++ for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // clear peer dls table entry ++ for (i = MAX_NUM_OF_INIT_DLS_ENTRY; i < MAX_NUM_OF_DLS_ENTRY; i++) ++ { ++ if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT ReasonCode; ++ UINT i; ++ BOOLEAN TimerCancelled; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (!INFRA_ON(pAd)) ++ return; ++ ++ if (!PeerDlsTearDownSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &ReasonCode)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsTearDownAction() from %02x:%02x:%02x:%02x:%02x:%02x with ReasonCode=%d\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5], ReasonCode)); ++ ++ // clear local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // clear peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID RTMPCheckDLSTimeOut( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_UNSPECIFY; ++ ++ if (! pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (! INFRA_ON(pAd)) ++ return; ++ ++ // If timeout value is equaled to zero, it means always not be timeout. ++ ++ // update local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer --; ++ ++ if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ } ++ } ++ ++ // update peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer --; ++ ++ if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN RTMPRcvFrameDLSCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN ULONG Len, ++ IN PRT28XX_RXD_STRUC pRxD) ++{ ++ ULONG i; ++ BOOLEAN bFindEntry = FALSE; ++ BOOLEAN bSTAKeyFrame = FALSE; ++ PEAPOL_PACKET pEap; ++ PUCHAR pProto, pAddr = NULL; ++ PUCHAR pSTAKey = NULL; ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR digest[80]; ++ UCHAR DlsPTK[80]; ++ UCHAR temp[64]; ++ BOOLEAN TimerCancelled; ++ CIPHER_KEY PairwiseKey; ++ ++ ++ if (! pAd->CommonCfg.bDLSCapable) ++ return bSTAKeyFrame; ++ ++ if (! INFRA_ON(pAd)) ++ return bSTAKeyFrame; ++ ++ if (! (pHeader->FC.SubType & 0x08)) ++ return bSTAKeyFrame; ++ ++ if (Len < LENGTH_802_11 + 6 + 2 + 2) ++ return bSTAKeyFrame; ++ ++ pProto = (PUCHAR)pHeader + LENGTH_802_11 + 2 + 6; // QOS Control field , 0xAA 0xAA 0xAA 0x00 0x00 0x00 ++ pAddr = pHeader->Addr2; ++ ++ // L2PAD bit on will pad 2 bytes at LLC ++ if (pRxD->L2PAD) ++ { ++ pProto += 2; ++ } ++ ++ if (RTMPEqualMemory(EAPOL, pProto, 2) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ pEap = (PEAPOL_PACKET) (pProto + 2); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff Len=%ld, DataLen=%d, KeyMic=%d, Install=%d, KeyAck=%d, Secure=%d, EKD_DL=%d, Error=%d, Request=%d\n", Len, ++ (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16), ++ pEap->KeyDesc.KeyInfo.KeyMic, ++ pEap->KeyDesc.KeyInfo.Install, ++ pEap->KeyDesc.KeyInfo.KeyAck, ++ pEap->KeyDesc.KeyInfo.Secure, ++ pEap->KeyDesc.KeyInfo.EKD_DL, ++ pEap->KeyDesc.KeyInfo.Error, ++ pEap->KeyDesc.KeyInfo.Request)); ++ ++ if ((Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16)) && pEap->KeyDesc.KeyInfo.KeyMic ++ && pEap->KeyDesc.KeyInfo.Install && pEap->KeyDesc.KeyInfo.KeyAck && pEap->KeyDesc.KeyInfo.Secure ++ && pEap->KeyDesc.KeyInfo.EKD_DL && !pEap->KeyDesc.KeyInfo.Error && !pEap->KeyDesc.KeyInfo.Request) ++ { ++ // First validate replay counter, only accept message with larger replay counter ++ // Let equal pass, some AP start with all zero replay counter ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ if ((RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ return bSTAKeyFrame; ++ ++ //RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter (%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", ++ pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], ++ pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], ++ pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); ++ ++ // put these code segment to get the replay counter ++ if (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) ++ return bSTAKeyFrame; ++ ++ // Check MIC value ++ // Save the MIC and replace with zero ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ NdisMoveMemory(OldMic, pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1((PUCHAR) pEap, pEap->Body_Len[1] + 4, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(DlsPTK, LEN_EAP_MICK, (PUCHAR) pEap, pEap->Body_Len[1] + 4, Mic); ++ } ++ ++ if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in Msg1 of STAKey handshake! \n")); ++ return bSTAKeyFrame; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("MIC VALID in Msg1 of STAKey handshake! \n")); ++#if 1 ++ if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0C) ++ && (pEap->KeyDesc.KeyData[4] == 0x43) && (pEap->KeyDesc.KeyData[5] == 0x02)) ++ { ++ pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) ++ pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%ld, KeyDataLen=%d\n", ++ pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); ++ ++ bSTAKeyFrame = TRUE; ++ } ++#else ++ if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0F) ++ && (pEap->KeyDesc.KeyData[4] == 0xAC) && (pEap->KeyDesc.KeyData[5] == 0x02)) ++ { ++ pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) ++ pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%d, KeyDataLen=%d\n", ++ pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); ++ ++ bSTAKeyFrame = TRUE; ++ } ++#endif ++ ++ } ++ else if (Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE)) ++ { ++#if 0 ++ RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++#endif ++ RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter 2(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", ++ pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], ++ pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], ++ pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); ++ ++ } ++ } ++ ++ // If timeout value is equaled to zero, it means always not be timeout. ++ // update local dls table entry ++ for (i= 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (bSTAKeyFrame) ++ { ++ PMAC_TABLE_ENTRY pEntry; ++ ++ // STAKey frame, add pairwise key table ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ ++ PairwiseKey.KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); ++ NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); ++ ++ PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; ++ ++ pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ // Add Pair-wise key to Asic ++#ifdef RT2870 ++ { ++ RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; ++ COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); ++ KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; ++ NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); ++ } ++ { ++ PMAC_TABLE_ENTRY pDLSEntry; ++ pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); ++ } ++#endif // RT2870 // ++ NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); ++ ++ RTMPSendSTAKeyHandShake(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Initiator side)\n")); ++ } ++ else ++ { ++ // Data frame, update timeout value ++ if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ } ++ } ++ ++ bFindEntry = TRUE; ++ } ++ } ++ ++ // update peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (bSTAKeyFrame) ++ { ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ // STAKey frame, add pairwise key table, and send STAkey Msg-2 ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ ++ PairwiseKey.KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); ++ NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); ++ ++ PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; ++ ++ pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ // Add Pair-wise key to Asic ++#ifdef RT2870 ++ { ++ RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; ++ COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); ++ KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; ++ NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); ++ } ++ { ++ PMAC_TABLE_ENTRY pDLSEntry; ++ pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); ++ } ++#endif // RT2870 // ++ NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); ++ ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyHandShake(pAd, pAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Peer side)\n")); ++ } ++ } ++ else ++ { ++ // Data frame, update timeout value ++ if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ } ++ } ++ ++ bFindEntry = TRUE; ++ } ++ } ++ ++ ++ return bSTAKeyFrame; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check if the frame can be sent through DLS direct link interface ++ ++ Arguments: ++ pAd Pointer to adapter ++ ++ Return Value: ++ DLS entry index ++ ++ Note: ++ ++ ======================================================================== ++*/ ++INT RTMPCheckDLSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ INT rval = -1; ++ INT i; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return rval; ++ ++ if (!INFRA_ON(pAd)) ++ return rval; ++ ++ do{ ++ // check local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ rval = i; ++ break; ++ } ++ } ++ ++ // check peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ rval = i; ++ break; ++ } ++ } ++ } while (FALSE); ++ ++ return rval; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ HEADER_802_11 DlsTearDownHdr; ++ ULONG FrameLen = 0; ++ USHORT Reason = REASON_QOS_QSTA_LEAVING_QBSS; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_TEARDOWN; ++ UCHAR i = 0; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame \n")); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ASSOC - RTMPSendDLSTearDownFrame() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsTearDownHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, pDA, ++ 6, pAd->CurrentAddress, ++ 2, &Reason, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ // Remove key in local dls table entry ++ for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // Remove key in peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame and remove key in (i=%d) \n", i)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++NDIS_STATUS RTMPSendSTAKeyRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ UCHAR Header802_3[14]; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ UCHAR digest[80]; ++ PUCHAR pOutBuffer = NULL; ++ PNDIS_PACKET pNdisPacket; ++ UCHAR temp[64]; ++ UCHAR DlsPTK[80]; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyRequest() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); ++ ++ pAd->Sequence ++; ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE andPeer MAC address ++ ++ // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ ++ // Key descriptor version ++ Packet.KeyDesc.KeyInfo.KeyDescVer = ++ (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ Packet.KeyDesc.KeyInfo.Request = 1; ++ ++ Packet.KeyDesc.KeyDataLen[1] = 12; ++ ++ // use our own OUI to distinguish proprietary with standard. ++ Packet.KeyDesc.KeyData[0] = 0xDD; ++ Packet.KeyDesc.KeyData[1] = 0x0A; ++ Packet.KeyDesc.KeyData[2] = 0x00; ++ Packet.KeyDesc.KeyData[3] = 0x0C; ++ Packet.KeyDesc.KeyData[4] = 0x43; ++ Packet.KeyDesc.KeyData[5] = 0x03; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); ++ ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Allocate buffer for transmitting message ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return NStatus; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ // calculate MIC ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ NdisZeroMemory(digest, sizeof(digest)); ++ HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(Header802_3), Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); ++ STASendPacket(pAd, pNdisPacket); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyRequest- Send STAKey request (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); ++ ++ return NStatus; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++NDIS_STATUS RTMPSendSTAKeyHandShake( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ UCHAR Header802_3[14]; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ UCHAR digest[80]; ++ PUCHAR pOutBuffer = NULL; ++ PNDIS_PACKET pNdisPacket; ++ UCHAR temp[64]; ++ UCHAR DlsPTK[80]; // Due to dirver can not get PTK, use proprietary PTK ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyHandShake() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); ++ ++ pAd->Sequence ++; ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE and Peer MAC address ++ ++ // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ ++ // Key descriptor version ++ Packet.KeyDesc.KeyInfo.KeyDescVer = ++ (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ Packet.KeyDesc.KeyDataLen[1] = 12; ++ ++ // use our own OUI to distinguish proprietary with standard. ++ Packet.KeyDesc.KeyData[0] = 0xDD; ++ Packet.KeyDesc.KeyData[1] = 0x0A; ++ Packet.KeyDesc.KeyData[2] = 0x00; ++ Packet.KeyDesc.KeyData[3] = 0x0C; ++ Packet.KeyDesc.KeyData[4] = 0x43; ++ Packet.KeyDesc.KeyData[5] = 0x03; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); ++ ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Allocate buffer for transmitting message ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return NStatus; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ // calculate MIC ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ NdisZeroMemory(digest, sizeof(digest)); ++ HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(Header802_3), Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); ++ STASendPacket(pAd, pNdisPacket); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyHandShake- Send STAKey Message-2 (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); ++ ++ return NStatus; ++} ++ ++VOID DlsTimeoutAction( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason; ++ PRT_802_11_DLS pDLS = (PRT_802_11_DLS)FunctionContext; ++ PRTMP_ADAPTER pAd = pDLS->pAd; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("DlsTimeout - Tear down DLS links (%02x:%02x:%02x:%02x:%02x:%02x)\n", ++ pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5])); ++ ++ if ((pDLS) && (pDLS->Valid)) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pDLS->Valid = FALSE; ++ pDLS->Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, pDLS, reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++ ++/* ++================================================================ ++Description : because DLS and CLI share the same WCID table in ASIC. ++Mesh entry also insert to pAd->MacTab.content[]. Such is marked as ValidAsDls = TRUE. ++Also fills the pairwise key. ++Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Dls ++from index MAX_AID_BA. ++================================================================ ++*/ ++MAC_TABLE_ENTRY *MacTableInsertDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UINT DlsEntryIdx) ++{ ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableInsertDlsEntry\n")); ++ // if FULL, return ++ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) ++ return NULL; ++ ++ do ++ { ++ if((pEntry = DlsEntryTableLookup(pAd, pAddr, TRUE)) != NULL) ++ break; ++ ++ // allocate one MAC entry ++ pEntry = MacTableInsertEntry(pAd, pAddr, DlsEntryIdx + MIN_NET_DEVICE_FOR_DLS, TRUE); ++ if (pEntry) ++ { ++ pAd->StaCfg.DLSEntry[DlsEntryIdx].MacTabMatchWCID = pEntry->Aid; ++ pEntry->MatchDlsEntryIdx = DlsEntryIdx; ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertDlsEntry - allocate entry #%d, Total= %d\n",pEntry->Aid, pAd->MacTab.Size)); ++ ++ // If legacy WEP is used, set pair-wise cipherAlg into WCID attribute table for this entry ++ if ((pEntry->ValidAsDls) && (pEntry->WepStatus == Ndis802_11WEPEnabled)) ++ { ++ UCHAR KeyIdx = 0; ++ UCHAR CipherAlg = 0; ++ ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pEntry); ++ } ++ ++ break; ++ } ++ } while(FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableInsertDlsEntry\n")); ++ ++ return pEntry; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Delete all Mesh Entry in pAd->MacTab ++ ========================================================================== ++ */ ++BOOLEAN MacTableDeleteDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableDeleteDlsEntry\n")); ++ ++ if (!VALID_WCID(wcid)) ++ return FALSE; ++ ++ MacTableDeleteEntry(pAd, wcid, pAddr); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableDeleteDlsEntry\n")); ++ ++ return TRUE; ++} ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount) ++{ ++ ULONG HashIdx; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ RTMP_SEM_LOCK(&pAd->MacTabLock); ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = pAd->MacTab.Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if ((pEntry->ValidAsDls == TRUE) ++ && MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ if(bResetIdelCount) ++ pEntry->NoDataIdleCount = 0; ++ break; ++ } ++ else ++ pEntry = pEntry->pNext; ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->MacTabLock); ++ return pEntry; ++} ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR wcid, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount) ++{ ++ ULONG DLsIndex; ++ PMAC_TABLE_ENTRY pCurEntry = NULL; ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ if (!VALID_WCID(wcid)) ++ return NULL; ++ ++ RTMP_SEM_LOCK(&pAd->MacTabLock); ++ ++ do ++ { ++ pCurEntry = &pAd->MacTab.Content[wcid]; ++ ++ DLsIndex = 0xff; ++ if ((pCurEntry) && (pCurEntry->ValidAsDls== TRUE)) ++ { ++ DLsIndex = pCurEntry->MatchDlsEntryIdx; ++ } ++ ++ if (DLsIndex == 0xff) ++ break; ++ ++ if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) ++ { ++ if(bResetIdelCount) ++ pCurEntry->NoDataIdleCount = 0; ++ pEntry = pCurEntry; ++ break; ++ } ++ } while(FALSE); ++ ++ RTMP_SEM_UNLOCK(&pAd->MacTabLock); ++ ++ return pEntry; ++} ++ ++INT Set_DlsEntryInfo_Display_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ INT i; ++ ++ printk("\n%-19s%-8s\n", "MAC", "TIMEOUT\n"); ++ for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[pAd->StaCfg.DLSEntry[i].MacTabMatchWCID]; ++ ++ printk("%02x:%02x:%02x:%02x:%02x:%02x ", ++ pAd->StaCfg.DLSEntry[i].MacAddr[0], pAd->StaCfg.DLSEntry[i].MacAddr[1], pAd->StaCfg.DLSEntry[i].MacAddr[2], ++ pAd->StaCfg.DLSEntry[i].MacAddr[3], pAd->StaCfg.DLSEntry[i].MacAddr[4], pAd->StaCfg.DLSEntry[i].MacAddr[5]); ++ printk("%-8d\n", pAd->StaCfg.DLSEntry[i].TimeOut); ++ ++ printk("\n"); ++ printk("\n%-19s%-4s%-4s%-4s%-4s%-7s%-7s%-7s","MAC", "AID", "BSS", "PSM", "WMM", "RSSI0", "RSSI1", "RSSI2"); ++#ifdef DOT11_N_SUPPORT ++ printk("%-8s%-10s%-6s%-6s%-6s%-6s", "MIMOPS", "PhMd", "BW", "MCS", "SGI", "STBC"); ++#endif // DOT11_N_SUPPORT // ++ printk("\n%02X:%02X:%02X:%02X:%02X:%02X ", ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ printk("%-4d", (int)pEntry->Aid); ++ printk("%-4d", (int)pEntry->apidx); ++ printk("%-4d", (int)pEntry->PsMode); ++ printk("%-4d", (int)CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)); ++ printk("%-7d", pEntry->RssiSample.AvgRssi0); ++ printk("%-7d", pEntry->RssiSample.AvgRssi1); ++ printk("%-7d", pEntry->RssiSample.AvgRssi2); ++#ifdef DOT11_N_SUPPORT ++ printk("%-8d", (int)pEntry->MmpsMode); ++ printk("%-10s", GetPhyMode(pEntry->HTPhyMode.field.MODE)); ++ printk("%-6s", GetBW(pEntry->HTPhyMode.field.BW)); ++ printk("%-6d", pEntry->HTPhyMode.field.MCS); ++ printk("%-6d", pEntry->HTPhyMode.field.ShortGI); ++ printk("%-6d", pEntry->HTPhyMode.field.STBC); ++#endif // DOT11_N_SUPPORT // ++ printk("%-10d, %d, %d%%\n", pEntry->DebugFIFOCount, pEntry->DebugTxCount, ++ (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); ++ printk("\n"); ++ ++ } ++ } ++ ++ return TRUE; ++} ++ ++INT Set_DlsAddEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[MAC_ADDR_LEN]; ++ USHORT Timeout; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ RT_802_11_DLS Dls; ++ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and timeout value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ Timeout = simple_strtol((token+1), 0, 10); ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%d", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], (int)Timeout); ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ Dls.TimeOut = Timeout; ++ COPY_MAC_ADDR(Dls.MacAddr, mac); ++ Dls.Valid = 1; ++ ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_DlsTearDownEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR macAddr[MAC_ADDR_LEN]; ++ CHAR *value; ++ INT i; ++ RT_802_11_DLS Dls; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ AtoH(value, &macAddr[i++], 2); ++ } ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], ++ macAddr[2], macAddr[3], macAddr[4], macAddr[5]); ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ COPY_MAC_ADDR(Dls.MacAddr, macAddr); ++ Dls.Valid = 0; ++ ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta_ioctl.c +@@ -0,0 +1,7068 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sta_ioctl.c ++ ++ Abstract: ++ IOCTL related subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 01-03-2003 created ++ Rory Chen 02-14-2005 modify to support RT61 ++*/ ++ ++#include "rt_config.h" ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++#endif ++ ++#define NR_WEP_KEYS 4 ++#define WEP_SMALL_KEY_LEN (40/8) ++#define WEP_LARGE_KEY_LEN (104/8) ++ ++#define GROUP_KEY_NO 4 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) ++#else ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) ++#endif ++ ++extern UCHAR CipherWpa2Template[]; ++extern UCHAR CipherWpaPskTkip[]; ++extern UCHAR CipherWpaPskTkipLen; ++ ++typedef struct PACKED _RT_VERSION_INFO{ ++ UCHAR DriverVersionW; ++ UCHAR DriverVersionX; ++ UCHAR DriverVersionY; ++ UCHAR DriverVersionZ; ++ UINT DriverBuildYear; ++ UINT DriverBuildMonth; ++ UINT DriverBuildDay; ++} RT_VERSION_INFO, *PRT_VERSION_INFO; ++ ++struct iw_priv_args privtab[] = { ++{ RTPRIV_IOCTL_SET, ++ IW_PRIV_TYPE_CHAR | 1024, 0, ++ "set"}, ++ ++{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++/* --- sub-ioctls definitions --- */ ++ { SHOW_CONN_STATUS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, ++ { SHOW_DRVIER_VERION, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, ++ { SHOW_BA_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, ++ { SHOW_DESC_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, ++ { RAIO_OFF, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, ++ { RAIO_ON, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, ++#ifdef QOS_DLS_SUPPORT ++ { SHOW_DLS_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, ++#endif // QOS_DLS_SUPPORT // ++ { SHOW_CFG_VALUE, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, ++ { SHOW_ADHOC_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, ++ ++/* --- sub-ioctls relations --- */ ++ ++#ifdef DBG ++{ RTPRIV_IOCTL_BBP, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "bbp"}, ++{ RTPRIV_IOCTL_MAC, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "mac"}, ++{ RTPRIV_IOCTL_E2P, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "e2p"}, ++#endif /* DBG */ ++ ++{ RTPRIV_IOCTL_STATISTICS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "stat"}, ++{ RTPRIV_IOCTL_GSITESURVEY, ++ 0, IW_PRIV_TYPE_CHAR | 1024, ++ "get_site_survey"}, ++}; ++ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WMM_SUPPORT ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++VOID RTMPIoctlBBP( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++#endif // DBG // ++ ++ ++NDIS_STATUS RTMPWPANoneAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++INT Set_FragTest_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++INT Show_Adhoc_MacTable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PCHAR extra); ++ ++static struct { ++ CHAR *name; ++ INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { ++ {"DriverVersion", Set_DriverVersion_Proc}, ++ {"CountryRegion", Set_CountryRegion_Proc}, ++ {"CountryRegionABand", Set_CountryRegionABand_Proc}, ++ {"SSID", Set_SSID_Proc}, ++ {"WirelessMode", Set_WirelessMode_Proc}, ++ {"TxBurst", Set_TxBurst_Proc}, ++ {"TxPreamble", Set_TxPreamble_Proc}, ++ {"TxPower", Set_TxPower_Proc}, ++ {"Channel", Set_Channel_Proc}, ++ {"BGProtection", Set_BGProtection_Proc}, ++ {"RTSThreshold", Set_RTSThreshold_Proc}, ++ {"FragThreshold", Set_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Set_HtBw_Proc}, ++ {"HtMcs", Set_HtMcs_Proc}, ++ {"HtGi", Set_HtGi_Proc}, ++ {"HtOpMode", Set_HtOpMode_Proc}, ++ {"HtExtcha", Set_HtExtcha_Proc}, ++ {"HtMpduDensity", Set_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Set_HtBaWinSize_Proc}, ++ {"HtRdg", Set_HtRdg_Proc}, ++ {"HtAmsdu", Set_HtAmsdu_Proc}, ++ {"HtAutoBa", Set_HtAutoBa_Proc}, ++ {"HtBaDecline", Set_BADecline_Proc}, ++ {"HtProtect", Set_HtProtect_Proc}, ++ {"HtMimoPs", Set_HtMimoPs_Proc}, ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Set_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Set_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Set_IEEE80211H_Proc}, ++ {"NetworkType", Set_NetworkType_Proc}, ++ {"AuthMode", Set_AuthMode_Proc}, ++ {"EncrypType", Set_EncrypType_Proc}, ++ {"DefaultKeyID", Set_DefaultKeyID_Proc}, ++ {"Key1", Set_Key1_Proc}, ++ {"Key2", Set_Key2_Proc}, ++ {"Key3", Set_Key3_Proc}, ++ {"Key4", Set_Key4_Proc}, ++ {"WPAPSK", Set_WPAPSK_Proc}, ++ {"ResetCounter", Set_ResetStatCounter_Proc}, ++ {"PSMode", Set_PSMode_Proc}, ++#ifdef DBG ++ {"Debug", Set_Debug_Proc}, ++#endif ++ ++#ifdef RALINK_ATE ++ {"ATE", Set_ATE_Proc}, ++ {"ATEDA", Set_ATE_DA_Proc}, ++ {"ATESA", Set_ATE_SA_Proc}, ++ {"ATEBSSID", Set_ATE_BSSID_Proc}, ++ {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, ++ {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, ++ {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, ++ {"ATETXANT", Set_ATE_TX_Antenna_Proc}, ++ {"ATERXANT", Set_ATE_RX_Antenna_Proc}, ++ {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, ++ {"ATETXBW", Set_ATE_TX_BW_Proc}, ++ {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, ++ {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, ++ {"ATETXMCS", Set_ATE_TX_MCS_Proc}, ++ {"ATETXMODE", Set_ATE_TX_MODE_Proc}, ++ {"ATETXGI", Set_ATE_TX_GI_Proc}, ++ {"ATERXFER", Set_ATE_RX_FER_Proc}, ++ {"ATERRF", Set_ATE_Read_RF_Proc}, ++ {"ATEWRF1", Set_ATE_Write_RF1_Proc}, ++ {"ATEWRF2", Set_ATE_Write_RF2_Proc}, ++ {"ATEWRF3", Set_ATE_Write_RF3_Proc}, ++ {"ATEWRF4", Set_ATE_Write_RF4_Proc}, ++ {"ATELDE2P", Set_ATE_Load_E2P_Proc}, ++ {"ATERE2P", Set_ATE_Read_E2P_Proc}, ++ {"ATESHOW", Set_ATE_Show_Proc}, ++ {"ATEHELP", Set_ATE_Help_Proc}, ++ ++#ifdef RALINK_28xx_QA ++ {"TxStop", Set_TxStop_Proc}, ++ {"RxStop", Set_RxStop_Proc}, ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ {"WpaSupport", Set_Wpa_Support}, ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++ {"FixedTxMode", Set_FixedTxMode_Proc}, ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ {"OpMode", Set_OpMode_Proc}, ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++#ifdef DOT11_N_SUPPORT ++ {"TGnWifiTest", Set_TGnWifiTest_Proc}, ++ {"ForceGF", Set_ForceGF_Proc}, ++#endif // DOT11_N_SUPPORT // ++#ifdef QOS_DLS_SUPPORT ++ {"DlsAddEntry", Set_DlsAddEntry_Proc}, ++ {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, ++#endif // QOS_DLS_SUPPORT // ++ {"LongRetry", Set_LongRetryLimit_Proc}, ++ {"ShortRetry", Set_ShortRetryLimit_Proc}, ++#ifdef EXT_BUILD_CHANNEL_LIST ++ {"11dClientMode", Set_Ieee80211dClientMode_Proc}, ++#endif // EXT_BUILD_CHANNEL_LIST // ++#ifdef CARRIER_DETECTION_SUPPORT ++ {"CarrierDetect", Set_CarrierDetect_Proc}, ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ {NULL,} ++}; ++ ++ ++VOID RTMPAddKey( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_802_11_KEY pKey) ++{ ++ ULONG KeyIdx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ NdisZeroMemory(pAd->StaCfg.PMK, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); ++ goto end; ++ } ++ // Update PTK ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else ++ { ++ // Update GTK ++ pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else // dynamic WEP from wpa_supplicant ++ { ++ UCHAR CipherAlg; ++ PUCHAR Key; ++ ++ if(pKey->KeyLength == 32) ++ goto end; ++ ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ ++ if (KeyIdx < 4) ++ { ++ // it is a default shared key, for Pairwise key setting ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ pEntry = MacTableLookup(pAd, pKey->BSSID); ++ ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); ++ ++ // set key material and key length ++ pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // set Cipher type ++ if (pKey->KeyLength == 5) ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; ++ else ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; ++ ++ // Add Pair-wise key to Asic ++ AsicAddPairwiseKeyEntry( ++ pAd, ++ pEntry->Addr, ++ (UCHAR)pEntry->Aid, ++ &pEntry->PairwiseKey); ++ ++ // update WCID attribute table and IVEIV table for this entry ++ RTMPAddWcidAttributeEntry( ++ pAd, ++ BSS0, ++ KeyIdx, // The value may be not zero ++ pEntry->PairwiseKey.CipherAlg, ++ pEntry); ++ ++ } ++ } ++ else ++ { ++ // Default key for tx (shared key) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ ++ // set key material and key length ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // Set Ciper type ++ if (pKey->KeyLength == 5) ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; ++ else ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ } ++ } ++ } ++end: ++ return; ++} ++ ++char * rtstrchr(const char * s, int c) ++{ ++ for(; *s != (char) c; ++s) ++ if (*s == '\0') ++ return NULL; ++ return (char *) s; ++} ++ ++/* ++This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function ++*/ ++ ++int ++rt_ioctl_giwname(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++#ifdef RT2870 ++ strncpy(name, "RT2870 Wireless", IFNAMSIZ); ++#endif // RT2870 // ++ return 0; ++} ++ ++int rt_ioctl_siwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int chan = -1; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ ++ if (freq->e > 1) ++ return -EINVAL; ++ ++ if((freq->e == 0) && (freq->m <= 1000)) ++ chan = freq->m; // Setting by channel number ++ else ++ MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, ++ ++ if (ChannelSanity(pAdapter, chan) == TRUE) ++ { ++ pAdapter->CommonCfg.Channel = chan; ++ DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); ++ } ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++int rt_ioctl_giwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter = NULL; ++ UCHAR ch; ++ ULONG m; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ch = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); ++ ++ MAP_CHANNEL_ID_TO_KHZ(ch, m); ++ freq->m = m * 100; ++ freq->e = 1; ++ return 0; ++} ++ ++int rt_ioctl_siwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (*mode) ++ { ++ case IW_MODE_ADHOC: ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ break; ++ case IW_MODE_INFRA: ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ break; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ case IW_MODE_MONITOR: ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ break; ++#endif ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); ++ return -EINVAL; ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (ADHOC_ON(pAdapter)) ++ *mode = IW_MODE_ADHOC; ++ else if (INFRA_ON(pAdapter)) ++ *mode = IW_MODE_INFRA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ else if (MONITOR_ON(pAdapter)) ++ { ++ *mode = IW_MODE_MONITOR; ++ } ++#endif ++ else ++ *mode = IW_MODE_AUTO; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); ++ return 0; ++} ++ ++int rt_ioctl_siwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ return 0; ++} ++ ++int rt_ioctl_giwrange(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ struct iw_range *range = (struct iw_range *) extra; ++ u16 val; ++ int i; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_DBM; ++ ++ if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) ++ { ++ range->min_pmp = 1 * 1024; ++ range->max_pmp = 65535 * 1024; ++ range->min_pmt = 1 * 1024; ++ range->max_pmt = 1000 * 1024; ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_TIMEOUT; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | ++ IW_POWER_UNICAST_R | IW_POWER_ALL_R; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 14; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = pAdapter->ChannelListNum; ++ ++ val = 0; ++ for (i = 1; i <= range->num_channels; i++) ++ { ++ u32 m; ++ range->freq[val].i = pAdapter->ChannelList[i-1].Channel; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); ++ range->freq[val].m = m * 100; /* HZ */ ++ ++ range->freq[val].e = 1; ++ val++; ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ range->num_frequency = val; ++ ++ range->max_qual.qual = 100; /* what is correct max? This was not ++ * documented exactly. At least ++ * 69 has been observed. */ ++ range->max_qual.level = 0; /* dB */ ++ range->max_qual.noise = 0; /* dB */ ++ ++ /* What would be suitable values for "average/typical" qual? */ ++ range->avg_qual.qual = 20; ++ range->avg_qual.level = -60; ++ range->avg_qual.noise = -95; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = NR_WEP_KEYS; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++#if WIRELESS_EXT > 17 ++ /* IW_ENC_CAPA_* bit field */ ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ return 0; ++} ++ ++int rt_ioctl_siwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ memset(Bssid, 0, MAC_ADDR_LEN); ++ memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ ++ return 0; ++} ++ ++int rt_ioctl_giwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); ++ return -ENOTCONN; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Units are in db above the noise floor. That means the ++ * rssi values reported in the tx/rx descriptors in the ++ * driver are the SNR expressed in db. ++ * ++ * If you assume that the noise floor is -95, which is an ++ * excellent assumption 99.5 % of the time, then you can ++ * derive the absolute signal level (i.e. -95 + rssi). ++ * There are some other slight factors to take into account ++ * depending on whether the rssi measurement is from 11b, ++ * 11g, or 11a. These differences are at most 2db and ++ * can be documented. ++ * ++ * NB: various calculations are based on the orinoco/wavelan ++ * drivers for compatibility ++ */ ++static void set_quality(PRTMP_ADAPTER pAdapter, ++ struct iw_quality *iq, ++ signed char rssi) ++{ ++ __u8 ChannelQuality; ++ ++ // Normalize Rssi ++ if (rssi >= -50) ++ ChannelQuality = 100; ++ else if (rssi >= -80) // between -50 ~ -80dbm ++ ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); ++ else if (rssi >= -90) // between -80 ~ -90dbm ++ ChannelQuality = (__u8)((rssi + 90) * 26)/10; ++ else ++ ChannelQuality = 0; ++ ++ iq->qual = (__u8)ChannelQuality; ++ ++ iq->level = (__u8)(rssi); ++ iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) ++ iq->noise += 256 - 143; ++ iq->updated = pAdapter->iw_stats.qual.updated; ++} ++ ++int rt_ioctl_iwaplist(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ struct sockaddr addr[IW_MAX_AP]; ++ struct iw_quality qual[IW_MAX_AP]; ++ int i; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ data->length = 0; ++ return 0; ++ //return -ENETDOWN; ++ } ++ ++ for (i = 0; i = pAdapter->ScanTab.BssNr) ++ break; ++ addr[i].sa_family = ARPHRD_ETHER; ++ memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); ++ } ++ data->length = i; ++ memcpy(extra, &addr, i*sizeof(addr[0])); ++ data->flags = 1; /* signal quality present (sort of) */ ++ memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); ++ ++ return 0; ++} ++ ++#ifdef SIOCGIWSCAN ++int rt_ioctl_siwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ULONG Now; ++ int Status = NDIS_STATUS_SUCCESS; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ return -EINVAL; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount++; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return 0; ++ do{ ++ Now = jiffies; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && ++ (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ RT28XX_MLME_HANDLER(pAdapter); ++ }while(0); ++ return 0; ++} ++ ++int rt_ioctl_giwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int i=0; ++ char *current_ev = extra, *previous_ev = extra; ++ char *end_buf; ++ char *current_val, custom[MAX_CUSTOM_LEN] = {0}; ++#ifndef IWEVGENIE ++ char idx; ++#endif // IWEVGENIE // ++ struct iw_event iwe; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ return -EAGAIN; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount = 0; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if (pAdapter->ScanTab.BssNr == 0) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++#if WIRELESS_EXT >= 17 ++ if (data->length > 0) ++ end_buf = extra + data->length; ++ else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#endif ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ if (current_ev >= end_buf) ++ { ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //MAC address ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //ESSID ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ iwe.u.data.flags = 1; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Network Type ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) ++ { ++ iwe.u.mode = IW_MODE_ADHOC; ++ } ++ else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) ++ { ++ iwe.u.mode = IW_MODE_INFRA; ++ } ++ else ++ { ++ iwe.u.mode = IW_MODE_AUTO; ++ } ++ iwe.len = IW_EV_UINT_LEN; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Channel and Frequency ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ else ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Add quality statistics ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.level = 0; ++ iwe.u.qual.noise = 0; ++ set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Encyption key ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) ++ iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Bit Rate ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].SupRateLen) ++ { ++ UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWRATE; ++ current_val = current_ev + IW_EV_LCP_LEN; ++ if (tmpRate == 0x82) ++ iwe.u.bitrate.value = 1 * 1000000; ++ else if (tmpRate == 0x84) ++ iwe.u.bitrate.value = 2 * 1000000; ++ else if (tmpRate == 0x8B) ++ iwe.u.bitrate.value = 5.5 * 1000000; ++ else if (tmpRate == 0x96) ++ iwe.u.bitrate.value = 11 * 1000000; ++ else ++ iwe.u.bitrate.value = (tmpRate/2) * 1000000; ++ ++ iwe.u.bitrate.disabled = 0; ++ current_val = IWE_STREAM_ADD_VALUE(info, current_ev, ++ current_val, end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ ++ if((current_val-current_ev)>IW_EV_LCP_LEN) ++ current_ev = current_val; ++ else ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++#ifdef IWEVGENIE ++ //WPA IE ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#else ++ //WPA IE ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "wpa_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "rsn_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#endif // IWEVGENIE // ++ } ++ ++ data->length = current_ev - extra; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); ++ return 0; ++} ++#endif ++ ++int rt_ioctl_siwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->flags) ++ { ++ PCHAR pSsidString = NULL; ++ ++ // Includes null character. ++ if (data->length > (IW_ESSID_MAX_SIZE + 1)) ++ return -E2BIG; ++ ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, essid, data->length); ++ if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) ++ return -EINVAL; ++ } ++ else ++ return -ENOMEM; ++ } ++ else ++ { ++ // ANY ssid ++ if (Set_SSID_Proc(pAdapter, "") == FALSE) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int rt_ioctl_giwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ data->flags = 1; ++ if (MONITOR_ON(pAdapter)) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#ifdef RT2870 ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // RT2870 // ++ else ++ {//the ANY ssid was specified ++ data->length = 0; ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); ++ } ++ ++ return 0; ++ ++} ++ ++int rt_ioctl_siwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->length > IW_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); ++ memcpy(pAdapter->nickname, nickname, data->length); ++ ++ ++ return 0; ++} ++ ++int rt_ioctl_giwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (data->length > strlen(pAdapter->nickname) + 1) ++ data->length = strlen(pAdapter->nickname) + 1; ++ if (data->length > 0) { ++ memcpy(nickname, pAdapter->nickname, data->length-1); ++ nickname[data->length-1] = '\0'; ++ } ++ return 0; ++} ++ ++int rt_ioctl_siwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (rts->disabled) ++ val = MAX_RTS_THRESHOLD; ++ else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ else if (rts->value == 0) ++ val = MAX_RTS_THRESHOLD; ++ else ++ val = rts->value; ++ ++ if (val != pAdapter->CommonCfg.RtsThreshold) ++ pAdapter->CommonCfg.RtsThreshold = val; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ rts->value = pAdapter->CommonCfg.RtsThreshold; ++ rts->disabled = (rts->value == MAX_RTS_THRESHOLD); ++ rts->fixed = 1; ++ ++ return 0; ++} ++ ++int rt_ioctl_siwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (frag->disabled) ++ val = MAX_FRAG_THRESHOLD; ++ else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) ++ val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ ++ else if (frag->value == 0) ++ val = MAX_FRAG_THRESHOLD; ++ else ++ return -EINVAL; ++ ++ pAdapter->CommonCfg.FragmentThreshold = val; ++ return 0; ++} ++ ++int rt_ioctl_giwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ frag->value = pAdapter->CommonCfg.FragmentThreshold; ++ frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); ++ frag->fixed = 1; ++ ++ return 0; ++} ++ ++#define MAX_WEP_KEY_SIZE 13 ++#define MIN_WEP_KEY_SIZE 5 ++int rt_ioctl_siwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_DISABLED)) ++ { ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ else if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ if (erq->flags & IW_ENCODE_RESTRICTED) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ ++ if (erq->length > 0) ++ { ++ int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; ++ /* Check the size of the key */ ++ if (erq->length > MAX_WEP_KEY_SIZE) { ++ return -EINVAL; ++ } ++ /* Check key index */ ++ if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", ++ keyIdx, pAdapter->StaCfg.DefaultKeyId)); ++ ++ //Using default key ++ keyIdx = pAdapter->StaCfg.DefaultKeyId; ++ } ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ ++ if (erq->length == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (erq->length == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ /* Disable the key */ ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ ++ /* Check if the key is not marked as invalid */ ++ if(!(erq->flags & IW_ENCODE_NOKEY)) { ++ /* Copy the key in the driver */ ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); ++ } ++ } ++ else ++ { ++ /* Do we want to just set the transmit key index ? */ ++ int index = (erq->flags & IW_ENCODE_INDEX) - 1; ++ if ((index >= 0) && (index < 4)) ++ { ++ pAdapter->StaCfg.DefaultKeyId = index; ++ } ++ else ++ /* Don't complain if only change the mode */ ++ if(!erq->flags & IW_ENCODE_MODE) { ++ return -EINVAL; ++ } ++ } ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); ++ return 0; ++} ++ ++int ++rt_ioctl_giwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ int kid; ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ kid = erq->flags & IW_ENCODE_INDEX; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); ++ ++ if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ++ { ++ erq->length = 0; ++ erq->flags = IW_ENCODE_DISABLED; ++ } ++ else if ((kid > 0) && (kid <=4)) ++ { ++ // copy wep key ++ erq->flags = kid ; /* NB: base 1 */ ++ if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) ++ erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); ++ //if ((kid == pAdapter->PortCfg.DefaultKeyId)) ++ //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ ++ } ++ else if (kid == 0) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); ++ // copy default key ID ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ ++ erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ } ++ ++ return 0; ++ ++} ++ ++static int ++rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter; ++ POS_COOKIE pObj; ++ char *this_char = extra; ++ char *value; ++ int Status=0; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAdapter->OS_Cookie; ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (!*this_char) ++ return -EINVAL; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value) ++ return -EINVAL; ++ ++ // reject setting nothing besides ANY ssid(ssidLen=0) ++ if (!*value && (strcmp(this_char, "SSID") != 0)) ++ return -EINVAL; ++ ++ for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) ++ { ++ if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) ++ { ++ if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) ++ { //FALSE:Set private failed then return Invalid argument ++ Status = -EINVAL; ++ } ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_SET_PROC->name == NULL) ++ { //Not found argument ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); ++ } ++ ++ return Status; ++} ++ ++ ++static int ++rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n\n"); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ } ++ sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); ++ sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->ate.RxAntennaSel == 0) ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++ else ++ { ++ sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); ++ ++ return Status; ++} ++ ++#ifdef DOT11_N_SUPPORT ++void getBaInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pOutBuf) ++{ ++ INT i, j; ++ BA_ORI_ENTRY *pOriBAEntry; ++ BA_REC_ENTRY *pRecBAEntry; ++ ++ for (i=0; iMacTab.Content[i]; ++ if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) ++ { ++ sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", ++ pOutBuf, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); ++ ++ sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BARecWcidArray[j] != 0) ++ { ++ pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); ++ } ++ } ++ sprintf(pOutBuf, "%s\n", pOutBuf); ++ ++ sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BAOriWcidArray[j] != 0) ++ { ++ pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); ++ } ++ } ++ sprintf(pOutBuf, "%s\n\n", pOutBuf); ++ } ++ if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ } ++ ++ return; ++} ++#endif // DOT11_N_SUPPORT // ++ ++static int ++rt_private_show(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ u32 subcmd = wrq->flags; ++ ++ if (dev->priv_flags == INT_MAIN) ++ pAd = dev->priv; ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(subcmd) ++ { ++ ++ case SHOW_CONN_STATUS: ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW) ++ sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); ++ else ++#endif // DOT11_N_SUPPORT // ++ sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); ++ } ++ else ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", ++ pAd->CommonCfg.Ssid, ++ pAd->CommonCfg.Bssid[0], ++ pAd->CommonCfg.Bssid[1], ++ pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3], ++ pAd->CommonCfg.Bssid[4], ++ pAd->CommonCfg.Bssid[5]); ++ DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); ++ } ++ else if (ADHOC_ON(pAd)) ++ sprintf(extra, "Connected\n"); ++ } ++ else ++ { ++ sprintf(extra, "Disconnected\n"); ++ DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); ++ } ++ } ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case SHOW_DRVIER_VERION: ++ sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#ifdef DOT11_N_SUPPORT ++ case SHOW_BA_INFO: ++ getBaInfo(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SHOW_DESC_INFO: ++ { ++ Show_DescInfo_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++ case RAIO_OFF: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = FALSE; ++ if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ sprintf(extra, "Radio Off\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case RAIO_ON: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = TRUE; ++ //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ } ++ sprintf(extra, "Radio On\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case SHOW_DLS_ENTRY_INFO: ++ { ++ Set_DlsEntryInfo_Display_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ case SHOW_CFG_VALUE: ++ { ++ Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); ++ if (Status == 0) ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ } ++ break; ++ case SHOW_ADHOC_ENTRY_INFO: ++ Show_Adhoc_MacTable_Proc(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); ++ break; ++ } ++ ++ return Status; ++} ++ ++#ifdef SIOCSIWMLME ++int rt_ioctl_siwmlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; ++ MLME_QUEUE_ELEM MsgElem; ++ MLME_DISASSOC_REQ_STRUCT DisAssocReq; ++ MLME_DEAUTH_REQ_STRUCT DeAuthReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); ++ ++ if (pMlme == NULL) ++ return -EINVAL; ++ ++ switch(pMlme->cmd) ++ { ++#ifdef IW_MLME_DEAUTH ++ case IW_MLME_DEAUTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); ++ DeAuthReq.Reason = pMlme->reason_code; ++ MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); ++ MlmeDeauthReqAction(pAd, &MsgElem); ++ if (INFRA_ON(pAd)) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ break; ++#endif // IW_MLME_DEAUTH // ++#ifdef IW_MLME_DISASSOC ++ case IW_MLME_DISASSOC: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); ++ DisAssocReq.Reason = pMlme->reason_code; ++ ++ MsgElem.Machine = ASSOC_STATE_MACHINE; ++ MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, &MsgElem); ++ break; ++#endif // IW_MLME_DISASSOC // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); ++ break; ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWMLME // ++ ++#if WIRELESS_EXT > 17 ++int rt_ioctl_siwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ if (param->value == IW_AUTH_WPA_VERSION_WPA) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ } ++ else if (param->value == IW_AUTH_WPA_VERSION_WPA2) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_KEY_MGMT: ++ if (param->value == IW_AUTH_KEY_MGMT_802_1X) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else ++ // WEP 1x ++ pAdapter->StaCfg.IEEE8021X = TRUE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == 0) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ /*if (param->value == 0) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ }*/ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ if (param->value != 0) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ } ++ else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ } ++ else ++ return -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); ++ break; ++ default: ++ return -EOPNOTSUPP; ++} ++ ++ return 0; ++} ++ ++int rt_ioctl_giwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); ++ return 0; ++} ++ ++void fnSetCipherKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN INT keyIdx, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bGTK, ++ IN struct iw_encode_ext *ext) ++{ ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ pAdapter->SharedKey[BSS0][keyIdx].Key, ++ pAdapter->SharedKey[BSS0][keyIdx].TxMic, ++ pAdapter->SharedKey[BSS0][keyIdx].RxMic); ++ ++ if (bGTK) ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ NULL); ++ else ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ &pAdapter->MacTab.Content[BSSID_WCID]); ++} ++ ++int rt_ioctl_siwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++ { ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int keyIdx, alg = ext->alg; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ { ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); ++ } ++ else ++ { ++ // Get Key Index and convet to our own defined key index ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ return -EINVAL; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ pAdapter->StaCfg.DefaultKeyId = keyIdx; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); ++ } ++ ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); ++ break; ++ case IW_ENCODE_ALG_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); ++ if (ext->key_len == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (ext->key_len == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ return -EINVAL; ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); ++ ++ if (pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled || ++ pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) ++ { ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, pAdapter->SharedKey[BSS0][keyIdx].Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, NULL); ++ ++ STA_PORT_SECURED(pAdapter); ++ ++ // Indicate Connected for GUI ++ pAdapter->IndicateMediaState = NdisMediaStateConnected; ++ } ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); ++ if (ext->key_len == 32) ++ { ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else ++ return -EINVAL; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++rt_ioctl_giwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PCHAR pKey = NULL; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) ++ { ++ if (idx < 1 || idx > 4) ++ return -EINVAL; ++ idx--; ++ ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) ++ { ++ if (idx != pAd->StaCfg.DefaultKeyId) ++ { ++ ext->key_len = 0; ++ return 0; ++ } ++ } ++ } ++ else ++ idx = pAd->StaCfg.DefaultKeyId; ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ ext->key_len = 0; ++ switch(pAd->StaCfg.WepStatus) { ++ case Ndis802_11WEPDisabled: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ encoding->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11WEPEnabled: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; ++ pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ else ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ ++ if (max_key_len < 32) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = 32; ++ pKey = &pAd->StaCfg.PMK[0]; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ext->key_len && pKey) ++ { ++ encoding->flags |= IW_ENCODE_ENABLED; ++ memcpy(ext->key, pKey, ext->key_len); ++ } ++ ++ return 0; ++} ++ ++#ifdef SIOCSIWGENIE ++int rt_ioctl_siwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (wrqu->data.length > MAX_LEN_OF_RSNIE || ++ (wrqu->data.length && extra == NULL)) ++ return -EINVAL; ++ ++ if (wrqu->data.length) ++ { ++ pAd->StaCfg.RSNIE_Len = wrqu->data.length; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); ++ } ++ else ++ { ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWGENIE // ++ ++int rt_ioctl_giwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if ((pAd->StaCfg.RSNIE_Len == 0) || ++ (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) ++ { ++ wrqu->data.length = 0; ++ return 0; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) ++ return -E2BIG; ++ ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ else ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len ++ return -E2BIG; ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ RSNIe = IE_RSN; ++ ++ extra[0] = (char)RSNIe; ++ extra[1] = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_siwpmksa(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; ++ INT CachedIdx = 0, idx = 0; ++ ++ if (pPmksa == NULL) ++ return -EINVAL; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); ++ switch(pPmksa->cmd) ++ { ++ case IW_PMKSA_FLUSH: ++ NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); ++ break; ++ case IW_PMKSA_REMOVE: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ { ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); ++ for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) ++ { ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); ++ } ++ pAd->StaCfg.SavedPMKNum--; ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); ++ break; ++ case IW_PMKSA_ADD: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ pAd->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); ++ break; ++ } ++ ++ return 0; ++} ++#endif // #if WIRELESS_EXT > 17 ++ ++#ifdef DBG ++static int ++rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++ { ++ CHAR *this_char; ++ CHAR *value = NULL; ++ UCHAR regBBP = 0; ++// CHAR arg[255]={0}; ++ UINT32 bbpId; ++ UINT32 bbpValue; ++ BOOLEAN bIsPrintAllBBP = FALSE; ++ INT Status = 0; ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ if (wrq->length > 1) //No parameters. ++ { ++ sprintf(extra, "\n"); ++ ++ //Parsing Read or Write ++ this_char = wrq->pointer; ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); ++ if (sscanf(this_char, "%d", &(bbpId)) == 1) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Write ++ if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ bIsPrintAllBBP = TRUE; ++ ++next: ++ if (bIsPrintAllBBP) ++ { ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n"); ++ for (bbpId = 0; bbpId <= 136; bbpId++) ++ { ++ if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) ++ break; ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); ++ if (bbpId%5 == 4) ++ sprintf(extra+strlen(extra), "\n"); ++ } ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); ++ ++ return Status; ++} ++#endif // DBG // ++ ++int rt_ioctl_siwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); ++ /* rate = -1 => auto rate ++ rate = X, fixed = 1 => (fixed rate X) ++ */ ++ if (rate == -1) ++ { ++ //Auto Rate ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, -1); ++ ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ else ++ { ++ if (fixed) ++ { ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, rate); ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ // TODO: rate = X, fixed = 0 => (rates <= X) ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ int rate_index = 0, rate_count = 0; ++ HTTRANSMIT_SETTING ht_setting; ++ __s32 ralinkrate[] = ++ {2, 4, 11, 22, // CCK ++ 12, 18, 24, 36, 48, 72, 96, 108, // OFDM ++ 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 ++ 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 ++ 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 ++ 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 ++ 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 ++ 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 ++ 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 ++ 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 ++ ++ rate_count = sizeof(ralinkrate)/sizeof(__s32); ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && ++ (INFRA_ON(pAd)) && ++ ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) ++ ht_setting.word = pAd->StaCfg.HTPhyMode.word; ++ else ++ ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ ++#ifdef DOT11_N_SUPPORT ++ if (ht_setting.field.MODE >= MODE_HTMIX) ++ { ++// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); ++ rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (ht_setting.field.MODE == MODE_OFDM) ++ rate_index = (UCHAR)(ht_setting.field.MCS) + 4; ++ else if (ht_setting.field.MODE == MODE_CCK) ++ rate_index = (UCHAR)(ht_setting.field.MCS); ++ ++ if (rate_index < 0) ++ rate_index = 0; ++ ++ if (rate_index > rate_count) ++ rate_index = rate_count; ++ ++ wrqu->bitrate.value = ralinkrate[rate_index] * 500000; ++ wrqu->bitrate.disabled = 0; ++ ++ return 0; ++} ++ ++static const iw_handler rt_handler[] = ++{ ++ (iw_handler) NULL, /* SIOCSIWCOMMIT */ ++ (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ ++ (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ ++ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ ++ (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ ++ (iw_handler) NULL, /* SIOCSIWSPY */ ++ (iw_handler) NULL, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* SIOCSIWTHRSPY */ ++ (iw_handler) NULL, /* SIOCGIWTHRSPY */ ++ (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ ++ (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ ++#ifdef SIOCSIWMLME ++ (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* SIOCSIWMLME */ ++#endif // SIOCSIWMLME // ++ (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ ++#ifdef SIOCGIWSCAN ++ (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ ++#else ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* SIOCGIWSCAN */ ++ (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ ++ (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ ++ (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ ++ (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) NULL, /* SIOCSIWTXPOW */ ++ (iw_handler) NULL, /* SIOCGIWTXPOW */ ++ (iw_handler) NULL, /* SIOCSIWRETRY */ ++ (iw_handler) NULL, /* SIOCGIWRETRY */ ++ (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) NULL, /* SIOCSIWPOWER */ ++ (iw_handler) NULL, /* SIOCGIWPOWER */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ ++ (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ ++ (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ ++ (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ ++ (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ ++#endif ++}; ++ ++static const iw_handler rt_priv_handlers[] = { ++ (iw_handler) NULL, /* + 0x00 */ ++ (iw_handler) NULL, /* + 0x01 */ ++#ifndef CONFIG_AP_SUPPORT ++ (iw_handler) rt_ioctl_setparam, /* + 0x02 */ ++#else ++ (iw_handler) NULL, /* + 0x02 */ ++#endif // CONFIG_AP_SUPPORT // ++#ifdef DBG ++ (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ ++#else ++ (iw_handler) NULL, /* + 0x03 */ ++#endif ++ (iw_handler) NULL, /* + 0x04 */ ++ (iw_handler) NULL, /* + 0x05 */ ++ (iw_handler) NULL, /* + 0x06 */ ++ (iw_handler) NULL, /* + 0x07 */ ++ (iw_handler) NULL, /* + 0x08 */ ++ (iw_handler) rt_private_get_statistics, /* + 0x09 */ ++ (iw_handler) NULL, /* + 0x0A */ ++ (iw_handler) NULL, /* + 0x0B */ ++ (iw_handler) NULL, /* + 0x0C */ ++ (iw_handler) NULL, /* + 0x0D */ ++ (iw_handler) NULL, /* + 0x0E */ ++ (iw_handler) NULL, /* + 0x0F */ ++ (iw_handler) NULL, /* + 0x10 */ ++ (iw_handler) rt_private_show, /* + 0x11 */ ++ (iw_handler) NULL, /* + 0x12 */ ++ (iw_handler) NULL, /* + 0x13 */ ++ (iw_handler) NULL, /* + 0x15 */ ++ (iw_handler) NULL, /* + 0x17 */ ++ (iw_handler) NULL, /* + 0x18 */ ++}; ++ ++const struct iw_handler_def rt28xx_iw_handler_def = ++{ ++#define N(a) (sizeof (a) / sizeof (a[0])) ++ .standard = (iw_handler *) rt_handler, ++ .num_standard = sizeof(rt_handler) / sizeof(iw_handler), ++ .private = (iw_handler *) rt_priv_handlers, ++ .num_private = N(rt_priv_handlers), ++ .private_args = (struct iw_priv_args *) privtab, ++ .num_private_args = N(privtab), ++#if IW_HANDLER_VERSION >= 7 ++ .get_wireless_stats = rt28xx_get_wireless_stats, ++#endif ++}; ++ ++INT RTMPSetInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ RT_802_11_PHY_MODE PhyMode; ++ RT_802_11_STA_CONFIG StaConfig; ++ NDIS_802_11_RATES aryRates; ++ RT_802_11_PREAMBLE Preamble; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ PNDIS_802_11_KEY pKey = NULL; ++ PNDIS_802_11_WEP pWepKey =NULL; ++ PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; ++ NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; ++ NDIS_802_11_NETWORK_TYPE NetType; ++ ULONG Now; ++ UINT KeyIdx = 0; ++ INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; ++ ULONG PowerTemp; ++ BOOLEAN RadioState; ++ BOOLEAN StateMachineTouched = FALSE; ++#ifdef DOT11_N_SUPPORT ++ OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy ++#endif // DOT11_N_SUPPORT // ++#ifdef WPA_SUPPLICANT_SUPPORT ++ PNDIS_802_11_PMKID pPmkId = NULL; ++ BOOLEAN IEEE8021xState = FALSE; ++ BOOLEAN IEEE8021x_required_keys = FALSE; ++ UCHAR wpa_supplicant_enable = 0; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR ctmp; ++#endif // SNMP_SUPPORT // ++ ++ ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); ++ switch(cmd & 0x7FFF) { ++ case RT_OID_802_11_COUNTRY_REGION: ++ if (wrq->u.data.length < sizeof(UCHAR)) ++ Status = -EINVAL; ++ // Only avaliable when EEPROM not programming ++ else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) ++ { ++ ULONG Country; ++ UCHAR TmpPhy; ++ ++ Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); ++ pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); ++ TmpPhy = pAdapter->CommonCfg.PhyMode; ++ pAdapter->CommonCfg.PhyMode = 0xff; ++ // Build all corresponding channel information ++ RTMPSetPhyMode(pAdapter, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, ++ pAdapter->CommonCfg.CountryRegion)); ++ } ++ break; ++ case OID_802_11_BSSID_LIST_SCAN: ++ #ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ Now = jiffies; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ break; ++ } ++ ++ //Benson add 20080527, when radio off, sta don't need to scan ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) ++ break; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ break; ++ case OID_802_11_SSID: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) ++ Status = -EINVAL; ++ else ++ { ++ PCHAR pSsidString = NULL; ++ Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ if (Ssid.SsidLength > MAX_LEN_OF_SSID) ++ Status = -EINVAL; ++ else ++ { ++ if (Ssid.SsidLength == 0) ++ { ++ Set_SSID_Proc(pAdapter, ""); ++ } ++ else ++ { ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); ++ Set_SSID_Proc(pAdapter, pSsidString); ++ kfree(pSsidString); ++ } ++ else ++ Status = -ENOMEM; ++ } ++ } ++ } ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ } ++ break; ++ case RT_OID_802_11_RADIO: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); ++ if (pAdapter->StaCfg.bSwRadio != RadioState) ++ { ++ pAdapter->StaCfg.bSwRadio = RadioState; ++ if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) ++ { ++ pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); ++ if (pAdapter->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ MlmeRadioOff(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PhyMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAdapter, PhyMode); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); ++ } ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; ++ pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; ++ pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable ++ if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && ++ (StaConfig.AdhocMode <= MaxPhyMode)) ++ { ++ // allow dynamic change of "USE OFDM rate or not" in ADHOC mode ++ // if setting changed, need to reset current TX rate as well as BEACON frame format ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ { ++ pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; ++ RTMPSetPhyMode(pAdapter, PhyMode); ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ MakeIbssBeacon(pAdapter); // re-build BEACON frame ++ AsicEnableIbssSync(pAdapter); // copy to on-chip memory ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", ++ pAdapter->CommonCfg.bEnableTxBurst, ++ pAdapter->CommonCfg.UseBGProtection, ++ pAdapter->CommonCfg.bUseShortSlotTime)); ++ } ++ break; ++ case OID_802_11_DESIRED_RATES: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ } ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); ++ if (Preamble == Rt802_11PreambleShort) ++ { ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); ++ } ++ else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) ++ { ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); ++ } ++ break; ++ case OID_802_11_WEP_STATUS: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); ++ // Since TKIP, AES, WEP are all supported. It should not have any invalid setting ++ if (WepStatus <= Ndis802_11Encryption3KeyAbsent) ++ { ++ if (pAdapter->StaCfg.WepStatus != WepStatus) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.WepStatus = WepStatus; ++ pAdapter->StaCfg.OrigWepStatus = WepStatus; ++ pAdapter->StaCfg.PairCipher = WepStatus; ++ pAdapter->StaCfg.GroupCipher = WepStatus; ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); ++ } ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (AuthMode > Ndis802_11AuthModeMax) ++ { ++ Status = -EINVAL; ++ break; ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode != AuthMode) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.AuthMode = AuthMode; ++ } ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); ++ } ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (BssType == Ndis802_11IBSS) ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ else if (BssType == Ndis802_11Infrastructure) ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ else if (BssType == Ndis802_11Monitor) ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ else ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); ++ } ++ } ++ break; ++ case OID_802_11_REMOVE_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); ++ if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) ++ { ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx >= 4){ ++ Status = -EINVAL; ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_RESET_COUNTERS: ++ NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); ++ pAdapter->Counters8023.RxNoBuffer = 0; ++ pAdapter->Counters8023.GoodReceives = 0; ++ pAdapter->Counters8023.RxNoBuffer = 0; ++#ifdef RT2870 ++ pAdapter->BulkOutComplete = 0; ++ pAdapter->BulkOutCompleteOther= 0; ++ pAdapter->BulkOutCompleteCancel = 0; ++ pAdapter->BulkOutReq = 0; ++ pAdapter->BulkInReq= 0; ++ pAdapter->BulkInComplete = 0; ++ pAdapter->BulkInCompleteFail = 0; ++#endif // RT2870 // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); ++ if (RtsThresh > MAX_RTS_THRESHOLD) ++ Status = -EINVAL; ++ else ++ pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ if (FragThresh == 0) ++ { ++ pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else ++ Status = -EINVAL; ++ } ++ else ++ pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerMode == Ndis802_11PowerModeCAM) ++ Set_PSMode_Proc(pAdapter, "CAM"); ++ else if (PowerMode == Ndis802_11PowerModeMAX_PSP) ++ Set_PSMode_Proc(pAdapter, "Max_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeFast_PSP) ++ Set_PSMode_Proc(pAdapter, "Fast_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) ++ Set_PSMode_Proc(pAdapter, "Legacy_PSP"); ++ else ++ Status = -EINVAL; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ if (wrq->u.data.length < sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerTemp > 100) ++ PowerTemp = 0xffffffff; // AUTO ++ pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. ++ pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ } ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (NetType == Ndis802_11DS) ++ RTMPSetPhyMode(pAdapter, PHY_11B); ++ else if (NetType == Ndis802_11OFDM24) ++ RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); ++ else if (NetType == Ndis802_11OFDM5) ++ RTMPSetPhyMode(pAdapter, PHY_11A); ++ else ++ Status = -EINVAL; ++#ifdef DOT11_N_SUPPORT ++ if (Status == NDIS_STATUS_SUCCESS) ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); ++ } ++ break; ++ // For WPA PSK PMK key ++ case RT_OID_802_11_ADD_WPA: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); ++ } ++ else ++ { ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) ++ { ++ Status = -EOPNOTSUPP; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); ++ } ++ else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode ++ { ++ NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); ++ // Use RaConfig as PSK agent. ++ // Start STA supplicant state machine ++ if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ pAdapter->StaCfg.WpaState = SS_START; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ else ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_REMOVE_KEY: ++ pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pRemoveKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pRemoveKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); ++ } ++ else ++ { ++ KeyIdx = pRemoveKey->KeyIndex; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx > 3) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); ++ } ++ } ++ } ++ } ++ kfree(pRemoveKey); ++ break; ++ // New for WPA ++ case OID_802_11_ADD_KEY: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); ++ } ++ else ++ { ++ RTMPAddKey(pAdapter, pKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_CONFIGURATION: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); ++ pConfig = &Config; ++ ++ if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) ++ pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; ++ ++ pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; ++ MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); ++ // ++ // Save the channel on MlmeAux for CntlOidRTBssidProc used. ++ // ++ pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", ++ pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_HT_PHYMODE: ++ if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) ++ Status = -EINVAL; ++ else ++ { ++ POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; ++ ++ Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", ++ pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ RTMPSetHT(pAdapter, pHTPhyMode); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", ++ pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, ++ pAdapter->StaCfg.HTPhyMode.field.STBC)); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case RT_OID_802_11_SET_APSD_SETTING: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ ULONG apsd ; ++ Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); ++ ++ /*------------------------------------------------------------------- ++ |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | ++ --------------------------------------------------------------------- ++ | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | ++ ---------------------------------------------------------------------*/ ++ pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; ++ pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, ++ pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_APSD_PSM: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ // Driver needs to notify AP when PSM changes ++ Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); ++ if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) ++ { ++ MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); ++ RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ } ++ break; ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; ++ Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); ++ if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) ++ { ++ int i; ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_DLS_PARAM: ++ if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) ++ Status = -EINVAL; ++ else ++ { ++ RT_802_11_DLS Dls; ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ case RT_OID_802_11_SET_WMM: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); ++ } ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ // ++ // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. ++ // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 ++ // when query OID_802_11_BSSID_LIST. ++ // ++ // TRUE: NumberOfItems will set to 0. ++ // FALSE: NumberOfItems no change. ++ // ++ pAdapter->CommonCfg.NdisRadioStateOff = TRUE; ++ // Set to immediately send the media disconnect event ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_DISASSOCIATE, ++ 0, ++ NULL); ++ ++ StateMachineTouched = TRUE; ++ } ++ break; ++ ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_IMME_BA_CAP: ++ if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) ++ Status = -EINVAL; ++ else ++ { ++ OID_BACAP_STRUC Orde ; ++ Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); ++ if (Orde.Policy > BA_NOTUSE) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ } ++ else if (Orde.Policy == BA_NOTUSE) ++ { ++ pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ } ++ else ++ { ++ pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; ++ pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ ++ if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; ++ ++ } ++ ++ pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); ++ } ++ ++ break; ++ case RT_OID_802_11_ADD_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ UCHAR index; ++ OID_ADD_BA_ENTRY BA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); ++ if (BA.TID > 15) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ else ++ { ++ //BATableInsertEntry ++ //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. ++ index = BA.TID; ++ // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too ++ pEntry = MacTableLookup(pAdapter, BA.MACAddr); ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); ++ break; ++ } ++ if (BA.IsRecipient == FALSE) ++ { ++ if (pEntry->bIAmBadAtheros == TRUE) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; ++ ++ BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); ++ } ++ else ++ { ++ //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", ++ BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] ++ , BA.MACAddr[4], BA.MACAddr[5])); ++ } ++ } ++ break; ++ ++ case RT_OID_802_11_TEAR_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ POID_ADD_BA_ENTRY pBA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if (pBA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); ++ ++ if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (pBA->IsRecipient == FALSE) ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); ++ BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ if (pEntry) ++ { ++ BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ kfree(pBA); ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ ++ // For WPA_SUPPLICANT to set static wep key ++ case OID_802_11_ADD_WEP: ++ pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pWepKey == NULL) ++ { ++ Status = -ENOMEM; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); ++ break; ++ } ++ Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (Status) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); ++ } ++ else ++ { ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ // KeyIdx must be 0 ~ 3 ++ if (KeyIdx > 4) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg = 0; ++ PUCHAR Key; ++ ++ // set key material and key length ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ ++ switch(pWepKey->KeyLength) ++ { ++ case 5: ++ CipherAlg = CIPHER_WEP64; ++ break; ++ case 13: ++ CipherAlg = CIPHER_WEP128; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); ++ Status = -EINVAL; ++ break; ++ } ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ ++ // Default key for tx (shared key) ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // set key material and key length ++ NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if ((pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) && ++ (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ Key = pWepKey->KeyMaterial; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ STA_PORT_SECURED(pAdapter); ++ ++ // Indicate Connected for GUI ++ pAdapter->IndicateMediaState = NdisMediaStateConnected; ++ } ++ else if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ++#endif // WPA_SUPPLICANT_SUPPORT ++ { ++ Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); ++ } ++ } ++ kfree(pWepKey); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case OID_SET_COUNTERMEASURES: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.bBlockAssoc = TRUE; ++ else ++ // WPA MIC error should block association attempt for 60 seconds ++ pAdapter->StaCfg.bBlockAssoc = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ } ++ break; ++ case OID_802_11_DEAUTHENTICATION: ++ if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) ++ Status = -EINVAL; ++ else ++ { ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; ++ Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); ++ MlmeDeauthReqAction(pAdapter, MsgElem); ++ kfree(MsgElem); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ LinkDown(pAdapter, FALSE); ++ pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); ++ } ++ break; ++ case OID_802_11_DROP_UNENCRYPTED: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ NdisAcquireSpinLock(&pAdapter->MacTabLock); ++ pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAdapter->MacTabLock); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021X = IEEE8021xState; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); ++ } ++ break; ++ case OID_802_11_PMKID: ++ pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pPmkId == NULL) { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // check the PMKID information ++ if (pPmkId->BSSIDInfoCount == 0) ++ NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ else ++ { ++ PBSSID_INFO pBssIdInfo; ++ UINT BssIdx; ++ UINT CachedIdx; ++ ++ for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) ++ { ++ // point to the indexed BSSID_INFO structure ++ pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); ++ // Find the entry in the saved data base. ++ for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ pAdapter->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ } ++ } ++ } ++ if(pPmkId) ++ kfree(pPmkId); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++#ifdef SNMP_SUPPORT ++ case OID_802_11_SHORTRETRYLIMIT: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); ++ pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ //pKey = &WepKey; ++ ++ if ( pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); ++ } ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); ++ ++ // it is a shared key ++ if (KeyIdx > 4) ++ Status = -EINVAL; ++ else ++ { ++ pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ //RestartAPIsRequired = TRUE; ++ } ++ break; ++ ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); ++ ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ break; ++ ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); ++ sprintf(&ctmp,"%d", ctmp); ++ Set_Channel_Proc(pAdapter, &ctmp); ++ } ++ break; ++#endif ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ ++ return Status; ++} ++ ++INT RTMPQueryInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; ++ PNDIS_WLAN_BSSID_EX pBss; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_CONFIGURATION *pConfiguration = NULL; ++ RT_802_11_LINK_STATUS *pLinkStatus = NULL; ++ RT_802_11_STA_CONFIG *pStaConfig = NULL; ++ NDIS_802_11_STATISTICS *pStatistics = NULL; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ RT_802_11_PREAMBLE PreamType; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_MEDIA_STATE MediaState; ++ ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; ++ USHORT BssLen = 0; ++ PUCHAR pBuf = NULL, pPtr; ++ INT Status = NDIS_STATUS_SUCCESS; ++ UINT we_version_compiled; ++ UCHAR i, Padding = 0; ++ BOOLEAN RadioState; ++ UCHAR driverVersion[8]; ++ OID_SET_HT_PHYMODE *pHTPhyMode = NULL; ++ ++ ++#ifdef SNMP_SUPPORT ++ //for snmp, kathy ++ DefaultKeyIdxValue *pKeyIdxValue; ++ INT valueLen; ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR tmp[64]; ++#endif //SNMP ++ ++ switch(cmd) ++ { ++ case RT_OID_DEVICE_NAME: ++ wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); ++ Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); ++ break; ++ case RT_OID_VERSION_INFO: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); ++ wrq->u.data.length = 8*sizeof(UCHAR); ++ sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); ++ driverVersion[7] = '\0'; ++ if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#ifdef RALINK_ATE ++ case RT_QUERY_ATE_TXDONE_COUNT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); ++ wrq->u.data.length = sizeof(UINT32); ++ if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#endif // RALINK_ATE // ++ case OID_802_11_BSSID_LIST: ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); ++ return -EAGAIN; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ // Claculate total buffer size required ++ BssBufSize = sizeof(ULONG); ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ // Align pointer to 4 bytes boundary. ++ //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); ++ //if (Padding == 4) ++ // Padding = 0; ++ BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ } ++ ++ // For safety issue, we add 256 bytes just in case ++ BssBufSize += 256; ++ // Allocate the same size as passed from higher layer ++ pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); ++ if(pBuf == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ // Init 802_11_BSSID_LIST_EX structure ++ NdisZeroMemory(pBuf, BssBufSize); ++ pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; ++ pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; ++ ++ // Calculate total buffer length ++ BssLen = 4; // Consist of NumberOfItems ++ // Point to start of NDIS_WLAN_BSSID_EX ++ // pPtr = pBuf + sizeof(ULONG); ++ pPtr = (PUCHAR) &pBssidList->Bssid[0]; ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ pBss = (PNDIS_WLAN_BSSID_EX) pPtr; ++ NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) ++ { ++ // ++ // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation ++ // and then failed to send EAPOl farame. ++ // ++ if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ else ++ pBss->Ssid.SsidLength = 0; ++ } ++ else ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; ++ pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; ++ pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; ++ pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; ++ ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); ++ ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) ++ pBss->InfrastructureMode = Ndis802_11Infrastructure; ++ else ++ pBss->InfrastructureMode = Ndis802_11IBSS; ++ ++ NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); ++ NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, ++ pAdapter->ScanTab.BssEntry[i].ExtRate, ++ pAdapter->ScanTab.BssEntry[i].ExtRateLen); ++ ++ if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) ++ { ++ pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ } ++ else ++ { ++ pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; ++ } ++ pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ ++#if WIRELESS_EXT < 17 ++ if ((BssLen + pBss->Length) < wrq->u.data.length) ++ BssLen += pBss->Length; ++ else ++ { ++ pBssidList->NumberOfItems = i; ++ break; ++ } ++#else ++ BssLen += pBss->Length; ++#endif ++ } ++ ++#if WIRELESS_EXT < 17 ++ wrq->u.data.length = BssLen; ++#else ++ if (BssLen > wrq->u.data.length) ++ { ++ kfree(pBssidList); ++ return -E2BIG; ++ } ++ else ++ wrq->u.data.length = BssLen; ++#endif ++ Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); ++ kfree(pBssidList); ++ break; ++ case OID_802_3_CURRENT_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ case OID_GEN_MEDIA_CONNECT_STATUS: ++ if (pAdapter->IndicateMediaState == NdisMediaStateConnected) ++ MediaState = NdisMediaStateConnected; ++ else ++ MediaState = NdisMediaStateDisconnected; ++ ++ wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); ++ Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++#endif // RALINK_ATE // ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); ++ Status = -ENOTCONN; ++ } ++ break; ++ case OID_802_11_SSID: ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); ++ Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; ++ memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); ++ wrq->u.data.length = sizeof(NDIS_802_11_SSID); ++ Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); ++ break; ++ case RT_OID_802_11_QUERY_LINK_STATUS: ++ pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); ++ if (pLinkStatus) ++ { ++ pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps ++ pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; ++ pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; ++ pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; ++ pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; ++ wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); ++ Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); ++ kfree(pLinkStatus); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_CONFIGURATION: ++ pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); ++ if (pConfiguration) ++ { ++ pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; ++ pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); ++ wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); ++ Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", ++ pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ kfree(pConfiguration); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_SNR_0: ++ if ((pAdapter->StaCfg.LastSNR0 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ break; ++ case RT_OID_802_11_SNR_1: ++ if ((pAdapter->Antenna.field.RxPath > 1) && ++ (pAdapter->StaCfg.LastSNR1 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); ++ break; ++ case OID_802_11_RSSI_TRIGGER: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); ++ break; ++ case OID_802_11_RSSI: ++ case RT_OID_802_11_RSSI: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_1: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_2: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_802_11_STATISTICS: ++ pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); ++ if (pStatistics) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAdapter); ++ ++ // Sanity check for calculation of sucessful count ++ if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) ++ pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ ++ pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; ++ pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; ++ pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; ++ pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; ++ pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; ++ pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; ++ pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; ++ pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; ++ pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; ++#ifdef DBG ++ pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; ++#else ++ pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; ++ pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; ++#endif ++ wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); ++ Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); ++ kfree(pStatistics); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_GEN_RCV_OK: ++ ulInfo = pAdapter->Counters8023.GoodReceives; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_GEN_RCV_NO_BUFFER: ++ ulInfo = pAdapter->Counters8023.RxNoBuffer; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); ++ if (pStaConfig) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); ++ pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; ++ pStaConfig->EnableTurboRate = 0; ++ pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; ++ pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; ++ //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; ++ pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; ++ pStaConfig->Rsv1 = 0; ++ pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; ++ wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); ++ Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); ++ kfree(pStaConfig); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ RtsThresh = pAdapter->CommonCfg.RtsThreshold; ++ wrq->u.data.length = sizeof(RtsThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ FragThresh = pAdapter->CommonCfg.FragmentThreshold; ++ if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) ++ FragThresh = 0; ++ wrq->u.data.length = sizeof(FragThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ PowerMode = pAdapter->StaCfg.WindowsPowerMode; ++ wrq->u.data.length = sizeof(PowerMode); ++ Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); ++ break; ++ case RT_OID_802_11_RADIO: ++ RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; ++ wrq->u.data.length = sizeof(RadioState); ++ Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ BssType = Ndis802_11IBSS; ++ else if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ BssType = Ndis802_11Infrastructure; ++ else if (pAdapter->StaCfg.BssType == BSS_MONITOR) ++ BssType = Ndis802_11Monitor; ++ else ++ BssType = Ndis802_11AutoUnknown; ++ ++ wrq->u.data.length = sizeof(BssType); ++ Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ PreamType = pAdapter->CommonCfg.TxPreamble; ++ wrq->u.data.length = sizeof(PreamType); ++ Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ AuthMode = pAdapter->StaCfg.AuthMode; ++ wrq->u.data.length = sizeof(AuthMode); ++ Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); ++ break; ++ case OID_802_11_WEP_STATUS: ++ WepStatus = pAdapter->StaCfg.WepStatus; ++ wrq->u.data.length = sizeof(WepStatus); ++ Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); ++ break; ++ case OID_802_11_TX_POWER_LEVEL: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ break; ++ case OID_802_11_NETWORK_TYPES_SUPPORTED: ++ if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) ++ { ++ NetworkTypeList[0] = 3; // NumberOfItems = 3 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a ++ wrq->u.data.length = 16; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ else ++ { ++ NetworkTypeList[0] = 2; // NumberOfItems = 2 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ wrq->u.data.length = 12; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ wrq->u.data.length = sizeof(ULONG); ++ if (pAdapter->CommonCfg.PhyMode == PHY_11A) ++ ulInfo = Ndis802_11OFDM5; ++ else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) ++ ulInfo = Ndis802_11OFDM24; ++ else ++ ulInfo = Ndis802_11DS; ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_LAST_RX_RATE: ++ ulInfo = (ULONG)pAdapter->LastRxRate; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_LAST_TX_RATE: ++ //ulInfo = (ULONG)pAdapter->LastTxRate; ++ ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_EEPROM_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_FIRMWARE_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_NOISE_LEVEL: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); ++ break; ++ case RT_OID_802_11_EXTRA_INFO: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); ++ break; ++ case RT_OID_WE_VERSION_COMPILED: ++ wrq->u.data.length = sizeof(UINT); ++ we_version_compiled = WIRELESS_EXT; ++ Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_APSD_SETTING: ++ apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) ++ | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); ++ ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", ++ apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); ++ break; ++ case RT_OID_802_11_QUERY_APSD_PSM: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ break; ++ case RT_OID_802_11_QUERY_WMM: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case RT_OID_NEW_DRIVER: ++ { ++ UCHAR enabled = 1; ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ case RT_OID_DRIVER_DEVICE_NAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); ++ wrq->u.data.length = 16; ++ if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; ++ ++ pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_COUNTRY_REGION: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); ++ wrq->u.data.length = sizeof(ulInfo); ++ ulInfo = pAdapter->CommonCfg.CountryRegionForABand; ++ ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); ++ if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; ++ ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ i = 0; ++#ifdef MULTIPLE_CARD_SUPPORT ++ i = 1; ++#endif // MULTIPLE_CARD_SUPPORT // ++ if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); ++ break; ++#ifdef SNMP_SUPPORT ++ case RT_OID_802_11_MAC_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREROUI: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); ++ wrq->u.data.length = ManufacturerOUI_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTURERNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_RESOURCETYPEIDNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); ++ wrq->u.data.length = strlen(ResourceTypeIdName); ++ Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); ++ ulInfo = 1; // 1 is support wep else 2 is not support. ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_POWERMANAGEMENTMODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); ++ if (pAdapter->StaCfg.Psm == PSMP_ACTION) ++ ulInfo = 1; // 1 is power active else 2 is power save. ++ else ++ ulInfo = 2; ++ ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); ++ //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; ++ pKeyIdxValue = wrq->u.data.pointer; ++ DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); ++ valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ NdisMoveMemory(pKeyIdxValue->Value, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, ++ valueLen); ++ pKeyIdxValue->Value[valueLen]='\0'; ++ ++ wrq->u.data.length = sizeof(DefaultKeyIdxValue); ++ ++ Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ pAdapter->SharedKey[BSS0][0].Key[0], ++ pAdapter->SharedKey[BSS0][1].Key[0], ++ pAdapter->SharedKey[BSS0][2].Key[0], ++ pAdapter->SharedKey[BSS0][3].Key[0])); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); ++ break; ++ ++ case RT_OID_802_11_WEPKEYMAPPINGLENGTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ wrq->u.data.length); ++ break; ++ ++ case OID_802_11_SHORTRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRODUCTID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); ++ ++#ifdef RT2870 ++ sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); ++ ++#endif // RT2870 // ++ wrq->u.data.length = strlen(tmp); ++ Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++#endif //SNMP_SUPPORT ++ ++ case OID_802_11_BUILD_CHANNEL_EX: ++ { ++ UCHAR value; ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 1; ++#else ++ DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 0; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ Status = copy_to_user(wrq->u.data.pointer, &value, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ } ++ break; ++ ++ case OID_802_11_GET_CH_LIST: ++ { ++ PRT_CHANNEL_LIST_INFO pChListBuf; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); ++ if (pAdapter->ChannelListNum == 0) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); ++ if (pChListBuf == NULL) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf->ChannelListNum = pAdapter->ChannelListNum; ++ for (i = 0; i < pChListBuf->ChannelListNum; i++) ++ pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; ++ ++ wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ ++ if (pChListBuf) ++ kfree(pChListBuf); ++ } ++ break; ++ ++ case OID_802_11_GET_COUNTRY_CODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); ++ wrq->u.data.length = 2; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ case OID_802_11_GET_CHANNEL_GEOGRAPHY: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); ++ wrq->u.data.length = 1; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_QUERY_DLS: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ break; ++ ++ case RT_OID_802_11_QUERY_DLS_PARAM: ++ { ++ PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); ++ if (pDlsInfo == NULL) ++ break; ++ ++ for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); ++ } ++ ++ pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; ++ wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); ++ ++ if (pDlsInfo) ++ kfree(pDlsInfo); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ return Status; ++} ++ ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ POS_COOKIE pObj; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ struct iwreq *wrq = (struct iwreq *) rq; ++ BOOLEAN StateMachineTouched = FALSE; ++ INT Status = NDIS_STATUS_SUCCESS; ++ USHORT subcmd; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (wrq->u.data.pointer == NULL) ++ { ++ return Status; ++ } ++ ++ if (strstr(wrq->u.data.pointer, "OpMode") == NULL) ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ } ++ ++ { // determine this ioctl command is comming from which interface. ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(cmd) ++ { ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++ case RTPRIV_IOCTL_ATE: ++ { ++ RtmpDoAte(pAd, wrq); ++ } ++ break; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ case SIOCGIFHWADDR: ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); ++ memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); ++ break; ++ case SIOCGIWNAME: ++ { ++ char *name=&wrq->u.name[0]; ++ rt_ioctl_giwname(net_dev, NULL, name, NULL); ++ break; ++ } ++ case SIOCGIWESSID: //Get ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWESSID: //Set ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWNWID: // set network id (the cell) ++ case SIOCGIWNWID: // get network id ++ Status = -EOPNOTSUPP; ++ break; ++ case SIOCSIWFREQ: //set channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCGIWFREQ: // get channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCSIWNICKN: //set node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_siwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWNICKN: //get node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_giwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWRATE: //get default bit rate (bps) ++ rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCSIWRATE: //set default bit rate (bps) ++ rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCGIWRTS: // get RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_giwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCSIWRTS: //set RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_siwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCGIWFRAG: //get fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCSIWFRAG: //set fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCGIWENCODE: //get encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCSIWENCODE: //set encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCGIWAP: //get access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCSIWAP: //set access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCGIWMODE: //get operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_giwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCSIWMODE: //set operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_siwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCGIWSENS: //get sensitivity (dBm) ++ case SIOCSIWSENS: //set sensitivity (dBm) ++ case SIOCGIWPOWER: //get Power Management settings ++ case SIOCSIWPOWER: //set Power Management settings ++ case SIOCGIWTXPOW: //get transmit power (dBm) ++ case SIOCSIWTXPOW: //set transmit power (dBm) ++ case SIOCGIWRANGE: //Get range of parameters ++ case SIOCGIWRETRY: //get retry limits and lifetime ++ case SIOCSIWRETRY: //set retry limits and lifetime ++ Status = -EOPNOTSUPP; ++ break; ++ case RT_PRIV_IOCTL: ++ subcmd = wrq->u.data.flags; ++ if( subcmd & OID_GET_SET_TOGGLE) ++ Status = RTMPSetInformation(pAd, rq, subcmd); ++ else ++ Status = RTMPQueryInformation(pAd, rq, subcmd); ++ break; ++ case SIOCGIWPRIV: ++ if (wrq->u.data.pointer) ++ { ++ if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) ++ break; ++ wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); ++ if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) ++ Status = -EFAULT; ++ } ++ break; ++ case RTPRIV_IOCTL_SET: ++ if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) ++ break; ++ rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); ++ break; ++ case RTPRIV_IOCTL_GSITESURVEY: ++ RTMPIoctlGetSiteSurvey(pAd, wrq); ++ break; ++#ifdef DBG ++ case RTPRIV_IOCTL_MAC: ++ RTMPIoctlMAC(pAd, wrq); ++ break; ++ case RTPRIV_IOCTL_E2P: ++ RTMPIoctlE2PROM(pAd, wrq); ++ break; ++#endif // DBG // ++ case SIOCETHTOOL: ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ if(StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set SSID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_SSID Ssid, *pSsid=NULL; ++ BOOLEAN StateMachineTouched = FALSE; ++ int success = TRUE; ++ ++ if( strlen(arg) <= MAX_LEN_OF_SSID) ++ { ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ if (strlen(arg) != 0) ++ { ++ NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); ++ Ssid.SsidLength = strlen(arg); ++ } ++ else //ANY ssid ++ { ++ Ssid.SsidLength = 0; ++ memcpy(Ssid.Ssid, "", 0); ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; ++ } ++ pSsid = &Ssid; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ pAdapter->bConfigChanged = TRUE; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ (VOID *)pSsid); ++ ++ StateMachineTouched = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ } ++ else ++ success = FALSE; ++ ++ if (StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAdapter); ++ ++ return success; ++} ++ ++#ifdef WMM_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WmmCapable Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN bWmmCapable; ++ ++ bWmmCapable = simple_strtol(arg, 0, 10); ++ ++ if ((bWmmCapable == 1) ++#ifdef RT2870 ++ && (pAd->NumberOfPipes >= 5) ++#endif // RT2870 // ++ ) ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ else if (bWmmCapable == 0) ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", ++ pAd->CommonCfg.bWmmCapable)); ++ ++ return TRUE; ++} ++#endif // WMM_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Set Network Type(Infrastructure/Adhoc mode) ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UINT32 Value = 0; ++ ++ if (strcmp(arg, "Adhoc") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_ADHOC) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (INFRA_ON(pAdapter)) ++ { ++ //BOOLEAN Cancelled; ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_ADHOC; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); ++ } ++ else if (strcmp(arg, "Infra") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_INFRA) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (ADHOC_ON(pAdapter)) ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); ++ ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ } ++ else if (strcmp(arg, "Monitor") == 0) ++ { ++ UCHAR bbpValue = 0; ++ BCN_TIME_CFG_STRUC csr; ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ // disable all periodic state machine ++ pAdapter->StaCfg.bAutoReconnect = FALSE; ++ // reset all mlme state machine ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); ++ if (pAdapter->CommonCfg.CentralChannel == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ pAdapter->CommonCfg.CentralChannel = 36; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAdapter->CommonCfg.CentralChannel = 6; ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ N_ChannelCheck(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ // 40MHz ,control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) ++ { ++ // 40MHz ,control channel at upper ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value |= 0x1; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // 20MHz ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_20; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); ++ } ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); ++ // ASIC supporsts sniffer function with replacing RSSI with timestamp. ++ //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ //Value |= (0x80); ++ //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ // disable sync ++ RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); ++ ++ pAdapter->StaCfg.BssType = BSS_MONITOR; ++ pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Authentication mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Encryption Type ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Default Key ID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ ULONG KeyIdx; ++ ++ KeyIdx = simple_strtol(arg, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY1 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ ++ pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 0, ++ pAdapter->SharedKey[BSS0][0].CipherAlg, ++ pAdapter->SharedKey[BSS0][0].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ ++ Description: ++ Set WEP KEY2 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 1, ++ pAdapter->SharedKey[BSS0][1].CipherAlg, ++ pAdapter->SharedKey[BSS0][1].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY3 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 2, ++ pAdapter->SharedKey[BSS0][2].CipherAlg, ++ pAdapter->SharedKey[BSS0][2].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY4 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 3, ++ pAdapter->SharedKey[BSS0][3].CipherAlg, ++ pAdapter->SharedKey[BSS0][3].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WPA PSK key ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UCHAR keyMaterial[40]; ++ ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return TRUE; // do nothing ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); ++ ++ NdisZeroMemory(keyMaterial, 40); ++ ++ if ((strlen(arg) < 8) || (strlen(arg) > 64)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); ++ return FALSE; ++ } ++ ++ if (strlen(arg) == 64) ++ { ++ AtoH(arg, keyMaterial, 32); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else ++ { ++ PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ } ++ ++ ++ ++ if(pAdapter->StaCfg.BssType == BSS_ADHOC && ++ pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ } ++ else ++ { ++ // Start STA supplicant state machine ++ pAdapter->StaCfg.WpaState = SS_START; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Power Saving mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(arg, "Max_PSP") == 0) || ++ (strcmp(arg, "max_psp") == 0) || ++ (strcmp(arg, "MAX_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ pAdapter->StaCfg.DefaultListenCount = 5; ++ ++ } ++ else if ((strcmp(arg, "Fast_PSP") == 0) || ++ (strcmp(arg, "fast_psp") == 0) || ++ (strcmp(arg, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(arg, "Legacy_PSP") == 0) || ++ (strcmp(arg, "legacy_psp") == 0) || ++ (strcmp(arg, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { ++ //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAdapter, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); ++ } ++ else ++ return FALSE; ++ ++ ++ return TRUE; ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WpaSupport flag. ++ Value: ++ 0: Driver ignore wpa_supplicant. ++ 1: wpa_supplicant initiates scanning and AP selection. ++ 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ if ( simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ else if ( simple_strtol(arg, 0, 10) == 1) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++ else if ( simple_strtol(arg, 0, 10) == 2) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; ++ else ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); ++ ++ return TRUE; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ Read / Write MAC ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 ++ 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 ++ ========================================================================== ++*/ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ ULONG macAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ UINT32 macValue = 0; ++ INT Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // Mac Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ if (macAddr < 0xFFFF) ++ { ++ RTMP_IO_READ32(pAdapter, macAddr, &macValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[8-k+j] = temp2[j]; ++ } ++ ++ while(k < 8) ++ temp2[7-k++]='0'; ++ temp2[8]='\0'; ++ ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 4); ++ macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; ++ ++ // debug mode ++ if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) ++ { ++ // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning ++ if (macValue & 0x000000ff) ++ { ++ pAdapter->BbpTuning.bEnable = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); ++ } ++ else ++ { ++ UCHAR R66; ++ pAdapter->BbpTuning.bEnable = FALSE; ++ R66 = 0x26 + GET_LNA_GAIN(pAdapter); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); ++ } ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); ++ ++ RTMP_IO_WRITE32(pAdapter, macAddr, macValue); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); ++ } ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Read / Write E2PROM ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 ++ 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 ++ ========================================================================== ++*/ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ USHORT eepAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ USHORT eepValue; ++ int Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ ++ ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // E2PROM addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ if (eepAddr < 0xFFFF) ++ { ++ RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[4-k+j] = temp2[j]; ++ } ++ ++ while(k < 4) ++ temp2[3-k++]='0'; ++ temp2[4]='\0'; ++ ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 2); ++ eepValue = *temp*256 + temp[1]; ++ ++ RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); ++} ++#endif // DBG // ++ ++ ++ ++ ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); ++ return TRUE; ++} ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++ else if (simple_strtol(arg, 0, 10) == 1) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; ++ else if (simple_strtol(arg, 0, 10) == 2) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; ++ else ++ return FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); ++ return TRUE; ++} ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ return TRUE; ++} ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ ++INT Show_Adhoc_MacTable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PCHAR extra) ++{ ++ INT i; ++ ++ sprintf(extra, "\n"); ++ ++#ifdef DOT11_N_SUPPORT ++ sprintf(extra, "%sHT Operating Mode : %d\n", extra, pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); ++#endif // DOT11_N_SUPPORT // ++ ++ sprintf(extra, "%s\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", extra, ++ "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); ++ ++ for (i=1; iMacTab.Content[i]; ++ ++ if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ { ++ sprintf(extra, "%s%02X:%02X:%02X:%02X:%02X:%02X ", extra, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ sprintf(extra, "%s%-4d", extra, (int)pEntry->Aid); ++ sprintf(extra, "%s%-4d", extra, (int)pEntry->apidx); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi0); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi1); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi2); ++ sprintf(extra, "%s%-10s", extra, GetPhyMode(pEntry->HTPhyMode.field.MODE)); ++ sprintf(extra, "%s%-6s", extra, GetBW(pEntry->HTPhyMode.field.BW)); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.MCS); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.ShortGI); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.STBC); ++ sprintf(extra, "%s%-10d, %d, %d%%\n", extra, pEntry->DebugFIFOCount, pEntry->DebugTxCount, ++ (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); ++ sprintf(extra, "%s\n", extra); ++ } ++ } ++ ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta_ioctl.c.patch +@@ -0,0 +1,18 @@ ++--- sta_ioctl.c 2008-09-19 14:37:52.000000000 +0800 +++++ sta_ioctl.c.fc9 2008-09-19 14:38:20.000000000 +0800 ++@@ -49,15 +49,9 @@ ++ ++ #define GROUP_KEY_NO 4 ++ ++-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ #define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) ++ #define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) ++ #define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) ++-#else ++-#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) ++-#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) ++-#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) ++-#endif ++ ++ extern UCHAR CipherWpa2Template[]; ++ extern UCHAR CipherWpaPskTkip[]; +--- /dev/null ++++ b/drivers/staging/rt2870/sta/rtmp_data.c +@@ -0,0 +1,2619 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_data.c ++ ++ Abstract: ++ Data path subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Aug/17/04 major modification for RT2561/2661 ++ Jan Lee Mar/17/06 major modification for RT2860 New Ring Design ++*/ ++#include "../rt_config.h" ++ ++ ++VOID STARxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ UCHAR *pTmpBuf; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) ++ // TBD : process fragmented EAPol frames ++ { ++ // In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable ++ if ( pAd->StaCfg.IEEE8021X == TRUE && ++ (EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H))) ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ int idx = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n")); ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ if (pAd->StaCfg.IEEE8021x_required_keys == FALSE) ++ { ++ idx = pAd->StaCfg.DesireSharedKeyId; ++ CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg; ++ Key = pAd->StaCfg.DesireSharedKey[idx].Key; ++ ++ if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) ++ { ++#ifdef RT2870 ++ union ++ { ++ char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1]; ++ NDIS_802_11_WEP keyinfo; ++ } WepKey; ++ int len; ++ ++ ++ NdisZeroMemory(&WepKey, sizeof(WepKey)); ++ len =pAd->StaCfg.DesireSharedKey[idx].KeyLen; ++ ++ NdisMoveMemory(WepKey.keyinfo.KeyMaterial, ++ pAd->StaCfg.DesireSharedKey[idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].KeyLen); ++ ++ WepKey.keyinfo.KeyIndex = 0x80000000 + idx; ++ WepKey.keyinfo.KeyLength = len; ++ pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ // need to enqueue cmd to thread ++ RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1); ++#endif // RT2870 // ++ // For Preventing ShardKey Table is cleared by remove key procedure. ++ pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; ++ pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; ++ NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].KeyLen); ++ } ++ } ++ } ++ ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Special DATA frame that has to pass to MLME ++ // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process ++ // 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process ++ { ++ pTmpBuf = pRxBlk->pData - LENGTH_802_11; ++ NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); ++ REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize)); ++ } ++ } ++ ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ ++} ++ ++VOID STARxDataFrameAnnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ ++ // non-EAP frame ++ if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) ++ { ++ { ++ // drop all non-EAP DATA frame before ++ // this client's Port-Access-Control is secured ++ if (pRxBlk->pHeader->FC.Wep) ++ { ++ // unsupported cipher suite ++ if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ else ++ { ++ // encryption in-use but receive a non-EAPOL clear text frame, drop it ++ if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ } ++ RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) ++ { ++ // Normal legacy, AMPDU or AMSDU ++ CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID); ++ ++ } ++ else ++ { ++ // ARALINK ++ CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ } ++#ifdef QOS_DLS_SUPPORT ++ RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); ++#endif // QOS_DLS_SUPPORT // ++ } ++ else ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // Determin the destination of the EAP frame ++ // to WPA state machine or upper layer ++ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ } ++ } ++} ++ ++ ++// For TKIP frame, calculate the MIC value ++BOOLEAN STACheckTkipMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk) ++{ ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ UCHAR *pData = pRxBlk->pData; ++ USHORT DataSize = pRxBlk->DataSize; ++ UCHAR UserPriority = pRxBlk->UserPriority; ++ PCIPHER_KEY pWpaKey; ++ UCHAR *pDA, *pSA; ++ ++ pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; ++ ++ pDA = pHeader->Addr1; ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) ++ { ++ pSA = pHeader->Addr3; ++ } ++ else ++ { ++ pSA = pHeader->Addr2; ++ } ++ ++ if (RTMPTkipCompareMICValue(pAd, ++ pData, ++ pDA, ++ pSA, ++ pWpaKey->RxMic, ++ UserPriority, ++ DataSize) == FALSE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ RTMPReportMicError(pAd, pWpaKey); ++ } ++ ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++// ++// All Rx routines use RX_BLK structure to hande rx events ++// It is very important to build pRxBlk attributes ++// 1. pHeader pointer to 802.11 Header ++// 2. pData pointer to payload including LLC (just skip Header) ++// 3. set payload size including LLC to DataSize ++// 4. set some flags with RX_BLK_SET_FLAG() ++// ++VOID STAHandleRxDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ BOOLEAN bFragment = FALSE; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ UCHAR FromWhichBSSID = BSS0; ++ UCHAR UserPriority = 0; ++ ++ { ++ // before LINK UP, all DATA frames are rejected ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) ++ if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) ++ { ++ return; ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // Drop not my BSS frames ++ if (pRxD->MyBss == 0) ++ { ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ ++ pAd->RalinkCounters.RxCountSinceLastNULL++; ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08)) ++ { ++ UCHAR *pData; ++ DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n")); ++ ++ // Qos bit 4 ++ pData = (PUCHAR)pHeader + LENGTH_802_11; ++ if ((*pData >> 4) & 0x01) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); ++ pAd->CommonCfg.bInServicePeriod = FALSE; ++ ++ // Force driver to fall into sleep mode when rcv EOSP frame ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ USHORT TbttNumToNextWakeUp; ++ USHORT NextDtim = pAd->StaCfg.DtimPeriod; ++ ULONG Now; ++ ++ NdisGetSystemUpTime(&Now); ++ NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod; ++ ++ TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) ++ TbttNumToNextWakeUp = NextDtim; ++ ++ MlmeSetPsmBit(pAd, PWR_SAVE); ++ // if WMM-APSD is failed, try to disable following line ++ AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ } ++ } ++ ++ if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n")); ++ } ++ } ++ ++ // Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame ++ if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // Drop not my BSS frame (we can not only check the MyBss bit in RxD) ++#ifdef QOS_DLS_SUPPORT ++ if (!pAd->CommonCfg.bDLSCapable) ++ { ++#endif // QOS_DLS_SUPPORT // ++ if (INFRA_ON(pAd)) ++ { ++ // Infrastructure mode, check address 2 for BSSID ++ if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) ++ { ++ // Receive frame not my BSSID ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ else // Ad-Hoc mode or Not associated ++ { ++ // Ad-Hoc mode, check address 3 for BSSID ++ if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) ++ { ++ // Receive frame not my BSSID ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++#ifdef QOS_DLS_SUPPORT ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // ++ // find pEntry ++ // ++ if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) ++ { ++ pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; ++ } ++ else ++ { ++ // 1. release packet if infra mode ++ // 2. new a pEntry if ad-hoc mode ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // infra or ad-hoc ++ if (INFRA_ON(pAd)) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); ++#ifdef QOS_DLS_SUPPORT ++ if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) ++ RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ASSERT(pRxWI->WirelessCliID == BSSID_WCID); ++ } ++ ++ // check Atheros Client ++ if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry )) ++ { ++ pEntry->bIAmBadAtheros = TRUE; ++ pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; ++ pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; ++ if (!STA_AES_ON(pAd)) ++ { ++ AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE); ++ } ++ } ++ } ++ ++ pRxBlk->pData = (UCHAR *)pHeader; ++ ++ // ++ // update RxBlk->pData, DataSize ++ // 802.11 Header, QOS, HTC, Hw Padding ++ // ++ ++ // 1. skip 802.11 HEADER ++ { ++ pRxBlk->pData += LENGTH_802_11; ++ pRxBlk->DataSize -= LENGTH_802_11; ++ } ++ ++ // 2. QOS ++ if (pHeader->FC.SubType & 0x08) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); ++ UserPriority = *(pRxBlk->pData) & 0x0f; ++ // bit 7 in QoS Control field signals the HT A-MSDU format ++ if ((*pRxBlk->pData) & 0x80) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); ++ } ++ ++ // skip QOS contorl field ++ pRxBlk->pData += 2; ++ pRxBlk->DataSize -=2; ++ } ++ pRxBlk->UserPriority = UserPriority; ++ ++ // 3. Order bit: A-Ralink or HTC+ ++ if (pHeader->FC.Order) ++ { ++#ifdef AGGREGATION_SUPPORT ++ if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); ++ } ++ else ++#endif ++ { ++#ifdef DOT11_N_SUPPORT ++ RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); ++ // skip HTC contorl field ++ pRxBlk->pData += 4; ++ pRxBlk->DataSize -= 4; ++#endif // DOT11_N_SUPPORT // ++ } ++ } ++ ++ // 4. skip HW padding ++ if (pRxD->L2PAD) ++ { ++ // just move pData pointer ++ // because DataSize excluding HW padding ++ RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); ++ pRxBlk->pData += 2; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pRxD->BA) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++ // ++ // Case I Process Broadcast & Multicast data frame ++ // ++ if (pRxD->Bcast || pRxD->Mcast) ++ { ++ INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); ++ ++ // Drop Mcast/Bcast frame with fragment bit on ++ if (pHeader->FC.MoreFrag) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // Filter out Bcast frame which AP relayed for us ++ if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ else if (pRxD->U2M) ++ { ++ pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) ++ { ++ MAC_TABLE_ENTRY *pDlsEntry = NULL; ++ ++ pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); ++ if(pDlsEntry) ++ Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ if (ADHOC_ON(pAd)) ++ { ++ pEntry = MacTableLookup(pAd, pHeader->Addr2); ++ if (pEntry) ++ Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI); ++ } ++ ++ ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); ++ ++ pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); ++ pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); ++ ++ pAd->RalinkCounters.OneSecRxOkDataCnt++; ++ ++ ++ if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) ++ { ++ // re-assemble the fragmented packets ++ // return complete frame (pRxPacket) or NULL ++ bFragment = TRUE; ++ pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); ++ } ++ ++ if (pRxPacket) ++ { ++ pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; ++ ++ // process complete frame ++ if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled)) ++ { ++ // Minus MIC length ++ pRxBlk->DataSize -= 8; ++ ++ // For TKIP frame, calculate the MIC value ++ if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE) ++ { ++ return; ++ } ++ } ++ ++ STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ else ++ { ++ // just return ++ // because RTMPDeFragmentDataFrame() will release rx packet, ++ // if packet is fragmented ++ return; ++ } ++ } ++ ++ ASSERT(0); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++} ++ ++VOID STAHandleRxMgmtFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ ++ do ++ { ++ ++ // We should collect RSSI not only U2M data but also my beacon ++ if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))) ++ { ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); ++ ++ pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); ++ pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); ++ } ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); ++ break; ++ } ++ ++ REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount, ++ pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); ++ } while (FALSE); ++ ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); ++} ++ ++VOID STAHandleRxControlFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++#ifdef DOT11_N_SUPPORT ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++#endif // DOT11_N_SUPPORT // ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ ++ switch (pHeader->FC.SubType) ++ { ++ case SUBTYPE_BLOCK_ACK_REQ: ++#ifdef DOT11_N_SUPPORT ++ { ++ CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SUBTYPE_BLOCK_ACK: ++ case SUBTYPE_ACK: ++ default: ++ break; ++ } ++ ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process RxDone interrupt, running in DPC level ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ This routine has to maintain Rx ring read pointer. ++ Need to consider QOS DATA format when converting to 802.3 ++ ======================================================================== ++*/ ++BOOLEAN STARxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN argc) ++{ ++ NDIS_STATUS Status; ++ UINT32 RxProcessed, RxPending; ++ BOOLEAN bReschedule = FALSE; ++ RT28XX_RXD_STRUC *pRxD; ++ UCHAR *pData; ++ PRXWI_STRUC pRxWI; ++ PNDIS_PACKET pRxPacket; ++ PHEADER_802_11 pHeader; ++ RX_BLK RxCell; ++ ++ RxProcessed = RxPending = 0; ++ ++ // process whole rx ring ++ while (1) ++ { ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST) || ++ !RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP)) ++ { ++ break; ++ } ++ ++ ++ RxProcessed ++; // test ++ ++ // 1. allocate a new data packet into rx ring to replace received packet ++ // then processing the received packet ++ // 2. the callee must take charge of release of packet ++ // 3. As far as driver is concerned , ++ // the rx packet must ++ // a. be indicated to upper layer or ++ // b. be released if it is discarded ++ pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending); ++ if (pRxPacket == NULL) ++ { ++ // no more packet to process ++ break; ++ } ++ ++ // get rx ring descriptor ++ pRxD = &(RxCell.RxD); ++ // get rx data buffer ++ pData = GET_OS_PKT_DATAPTR(pRxPacket); ++ pRxWI = (PRXWI_STRUC) pData; ++ pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); ++ RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); ++#endif ++ ++ // build RxCell ++ RxCell.pRxWI = pRxWI; ++ RxCell.pHeader = pHeader; ++ RxCell.pRxPacket = pRxPacket; ++ RxCell.pData = (UCHAR *) pHeader; ++ RxCell.DataSize = pRxWI->MPDUtotalByteCount; ++ RxCell.Flags = 0; ++ ++ // Increase Total receive byte counter after real data received no mater any error or not ++ pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount; ++ pAd->RalinkCounters.RxCount ++; ++ ++ INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); ++ ++ if (pRxWI->MPDUtotalByteCount < 14) ++ Status = NDIS_STATUS_FAILURE; ++ ++ if (MONITOR_ON(pAd)) ++ { ++ send_monitor_packets(pAd, &RxCell); ++ break; ++ } ++ /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ pAd->ate.RxCntPerSec++; ++ ATESampleRssi(pAd, pRxWI); ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQARxStart == TRUE) ++ { ++ /* (*pRxD) has been swapped in GetPacketFromRxRing() */ ++ ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); ++ } ++#endif // RALINK_28xx_QA // ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); ++ continue; ++ } ++#endif // RALINK_ATE // ++ ++ // Check for all RxD errors ++ Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); ++ ++ // Handle the received frame ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ switch (pHeader->FC.Type) ++ { ++ // CASE I, receive a DATA frame ++ case BTYPE_DATA: ++ { ++ // process DATA frame ++ STAHandleRxDataFrame(pAd, &RxCell); ++ } ++ break; ++ // CASE II, receive a MGMT frame ++ case BTYPE_MGMT: ++ { ++ STAHandleRxMgmtFrame(pAd, &RxCell); ++ } ++ break; ++ // CASE III. receive a CNTL frame ++ case BTYPE_CNTL: ++ { ++ STAHandleRxControlFrame(pAd, &RxCell); ++ } ++ break; ++ // discard other type ++ default: ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ break; ++ } ++ } ++ else ++ { ++ pAd->Counters8023.RxErrors++; ++ // discard this frame ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ } ++ ++ return bReschedule; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Arguments: ++ pAd Pointer to our adapter ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPHandleTwakeupInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ AsicForceWakeup(pAd, FALSE); ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Early checking and OS-depened parsing for Tx packet send to our STA driver. ++ ++Arguments: ++ NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. ++ PPNDIS_PACKET ppPacketArray The packet array need to do transmission. ++ UINT NumberOfPackets Number of packet in packet array. ++ ++Return Value: ++ NONE ++ ++Note: ++ This function do early checking and classification for send-out packet. ++ You only can put OS-depened & STA related code in here. ++======================================================================== ++*/ ++VOID STASendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets) ++{ ++ UINT Index; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext; ++ PNDIS_PACKET pPacket; ++ BOOLEAN allowToSend = FALSE; ++ ++ ++ for (Index = 0; Index < NumberOfPackets; Index++) ++ { ++ pPacket = ppPacketArray[Index]; ++ ++ do ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ { ++ // Drop send request since hardware is in reset state ++ break; ++ } ++ else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) ++ { ++ // Drop send request since there are no physical connection yet ++ break; ++ } ++ else ++ { ++ // Record that orignal packet source is from NDIS layer,so that ++ // later on driver knows how to release this NDIS PACKET ++#ifdef QOS_DLS_SUPPORT ++ MAC_TABLE_ENTRY *pEntry; ++ PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ ++ pEntry = MacTableLookup(pAd, pSrcBufVA); ++ if (pEntry && (pEntry->ValidAsDls == TRUE)) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++ NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); ++ pAd->RalinkCounters.PendingNdisPacketCount++; ++ ++ allowToSend = TRUE; ++ } ++ } while(FALSE); ++ ++ if (allowToSend == TRUE) ++ STASendPacket(pAd, pPacket); ++ else ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ ++ // Dequeue outgoing frames from TxSwQueue[] and process it ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ This routine is used to do packet parsing and classification for Tx packet ++ to STA device, and it will en-queue packets to our TxSwQueue depends on AC ++ class. ++ ++Arguments: ++ pAd Pointer to our adapter ++ pPacket Pointer to send packet ++ ++Return Value: ++ NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue. ++ NDIS_STATUS_FAILURE If failed to do en-queue. ++ ++Note: ++ You only can put OS-indepened & STA related code in here. ++======================================================================== ++*/ ++NDIS_STATUS STASendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ UINT AllowFragSize; ++ UCHAR NumberOfFrag; ++// UCHAR RTSRequired; ++ UCHAR QueIdx, UserPriority; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ unsigned int IrqFlags; ++ UCHAR FlgIsIP = 0; ++ UCHAR Rate; ++ ++ // Prepare packet information structure for buffer descriptor ++ // chained within a single NDIS packet. ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ if (pSrcBufVA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen)); ++ // Resourece is low, system did not allocate virtual address ++ // return NDIS_STATUS_FAILURE directly to upper layer ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++ if (SrcBufLen < 14) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++ // In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. ++ // Note multicast packets in adhoc also use BSSID_WCID index. ++ { ++ if(INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ USHORT tmpWcid; ++ ++ tmpWcid = RTMP_GET_PACKET_WCID(pPacket); ++ if (VALID_WCID(tmpWcid) && ++ (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) ++ { ++ pEntry = &pAd->MacTab.Content[tmpWcid]; ++ Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); ++ Rate = pAd->CommonCfg.TxRate; ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ if (*pSrcBufVA & 0x01) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); ++ pEntry = &pAd->MacTab.Content[MCAST_WCID]; ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAd, pSrcBufVA); ++ } ++ Rate = pAd->CommonCfg.TxRate; ++ } ++ } ++ ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA))); ++ // Resourece is low, system did not allocate virtual address ++ // return NDIS_STATUS_FAILURE directly to upper layer ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ if (ADHOC_ON(pAd) ++ ) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid); ++ } ++ ++ // ++ // Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. ++ // Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). ++ RTMPCheckEtherType(pAd, pPacket); ++ ++ ++ ++ // ++ // WPA 802.1x secured port control - drop all non-802.1x frame before port secured ++ // ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef WPA_SUPPLICANT_SUPPORT ++ || (pAd->StaCfg.IEEE8021X == TRUE) ++#endif // WPA_SUPPLICANT_SUPPORT // ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) ++ && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++ ++ // STEP 1. Decide number of fragments required to deliver this MSDU. ++ // The estimation here is not very accurate because difficult to ++ // take encryption overhead into consideration here. The result ++ // "NumberOfFrag" is then just used to pre-check if enough free ++ // TXD are available to hold this MSDU. ++ ++ ++ if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast ++ NumberOfFrag = 1; ++ else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) ++ NumberOfFrag = 1; // Aggregation overwhelms fragmentation ++ else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) ++ NumberOfFrag = 1; // Aggregation overwhelms fragmentation ++#ifdef DOT11_N_SUPPORT ++ else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) ++ NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation ++#endif // DOT11_N_SUPPORT // ++ else ++ { ++ // The calculated "NumberOfFrag" is a rough estimation because of various ++ // encryption/encapsulation overhead not taken into consideration. This number is just ++ // used to make sure enough free TXD are available before fragmentation takes place. ++ // In case the actual required number of fragments of an NDIS packet ++ // excceeds "NumberOfFrag"caculated here and not enough free TXD available, the ++ // last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of ++ // resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should ++ // rarely happen and the penalty is just like a TX RETRY fail. Affordable. ++ ++ AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; ++ NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; ++ // To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size ++ if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) ++ { ++ NumberOfFrag--; ++ } ++ } ++ ++ // Save fragment number to Ndis packet reserved field ++ RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); ++ ++ ++ // STEP 2. Check the requirement of RTS: ++ // If multiple fragment required, RTS is required only for the first fragment ++ // if the fragment size large than RTS threshold ++ // For RT28xx, Let ASIC send RTS/CTS ++ RTMP_SET_PACKET_RTS(pPacket, 0); ++ RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); ++ ++ // ++ // STEP 3. Traffic classification. outcome = ++ // ++ UserPriority = 0; ++ QueIdx = QID_AC_BE; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) ++ { ++ USHORT Protocol; ++ UCHAR LlcSnapLen = 0, Byte0, Byte1; ++ do ++ { ++ // get Ethernet protocol field ++ Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); ++ if (Protocol <= 1500) ++ { ++ // get Ethernet protocol field from LLC/SNAP ++ if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) ++ break; ++ ++ Protocol = (USHORT)((Byte0 << 8) + Byte1); ++ LlcSnapLen = 8; ++ } ++ ++ // always AC_BE for non-IP packet ++ if (Protocol != 0x0800) ++ break; ++ ++ // get IP header ++ if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) ++ break; ++ ++ // return AC_BE if packet is not IPv4 ++ if ((Byte0 & 0xf0) != 0x40) ++ break; ++ ++ FlgIsIP = 1; ++ UserPriority = (Byte1 & 0xe0) >> 5; ++ QueIdx = MapUserPriorityToAccessCategory[UserPriority]; ++ ++ // TODO: have to check ACM bit. apply TSPEC if ACM is ON ++ // TODO: downgrade UP & QueIdx before passing ACM ++ if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) ++ { ++ UserPriority = 0; ++ QueIdx = QID_AC_BE; ++ } ++ } while (FALSE); ++ } ++ ++ RTMP_SET_PACKET_UP(pPacket, UserPriority); ++ ++ ++ ++ // Make sure SendTxWait queue resource won't be used by other threads ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++ if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++#ifdef BLOCK_NET_IF ++ StopNetIfQueue(pAd, QueIdx, pPacket); ++#endif // BLOCK_NET_IF // ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ ++ return NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket)); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& ++ IS_HT_STA(pEntry)) ++ { ++ //PMAC_TABLE_ENTRY pMacEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1<PortSecured == WPA_802_1X_PORT_SECURED) ++ // For IOT compatibility, if ++ // 1. It is Ralink chip or ++ // 2. It is OPEN or AES mode, ++ // then BA session can be bulit. ++ && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) || ++ (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled)) ++ ) ++ { ++ BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ This subroutine will scan through releative ring descriptor to find ++ out avaliable free ring descriptor and compare with request size. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ QueIdx Selected TX Ring ++ ++ Return Value: ++ NDIS_STATUS_FAILURE Not enough free descriptor ++ NDIS_STATUS_SUCCESS Enough free descriptor ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++#ifdef RT2870 ++/* ++ Actually, this function used to check if the TxHardware Queue still has frame need to send. ++ If no frame need to send, go to sleep, else, still wake up. ++*/ ++NDIS_STATUS RTMPFreeTXDRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR NumberRequired, ++ IN PUCHAR FreeNumberIs) ++{ ++ //ULONG FreeNumber = 0; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ ++ switch (QueIdx) ++ { ++ case QID_AC_BK: ++ case QID_AC_BE: ++ case QID_AC_VI: ++ case QID_AC_VO: ++ case QID_HCCA: ++ { ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) || ++ (pHTTXContext->IRPPending == TRUE)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ } ++ break; ++ ++ case QID_MGMT: ++ if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) ++ Status = NDIS_STATUS_FAILURE; ++ else ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); ++ break; ++ } ++ ++ return (Status); ++ ++} ++#endif // RT2870 // ++ ++ ++VOID RTMPSendDisassociationFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++} ++ ++VOID RTMPSendNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull) ++{ ++ UCHAR NullFrame[48]; ++ ULONG Length; ++ PHEADER_802_11 pHeader_802_11; ++ ++ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ // WPA 802.1x secured port control ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef WPA_SUPPLICANT_SUPPORT ++ || (pAd->StaCfg.IEEE8021X == TRUE) ++#endif ++ ) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ return; ++ } ++ ++ NdisZeroMemory(NullFrame, 48); ++ Length = sizeof(HEADER_802_11); ++ ++ pHeader_802_11 = (PHEADER_802_11) NullFrame; ++ ++ pHeader_802_11->FC.Type = BTYPE_DATA; ++ pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; ++ pHeader_802_11->FC.ToDs = 1; ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ } ++ else ++ { ++ pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0; ++ } ++ pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); ++ ++ pAd->Sequence++; ++ pHeader_802_11->Sequence = pAd->Sequence; ++ ++ // Prepare QosNull function frame ++ if (bQosNull) ++ { ++ pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; ++ ++ // copy QOS control bytes ++ NullFrame[Length] = 0; ++ NullFrame[Length+1] = 0; ++ Length += 2;// if pad with 2 bytes for alignment, APSD will fail ++ } ++ ++ HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); ++ ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID RTMPSendRTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN unsigned int NextMpduSize, ++ IN UCHAR TxRate, ++ IN UCHAR RTSRate, ++ IN USHORT AckDuration, ++ IN UCHAR QueIdx, ++ IN UCHAR FrameGap) ++{ ++} ++ ++ ++ ++// -------------------------------------------------------- ++// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM ++// Find the WPA key, either Group or Pairwise Key ++// LEAP + TKIP also use WPA key. ++// -------------------------------------------------------- ++// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst ++// In Cisco CCX 2.0 Leap Authentication ++// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey ++// Instead of the SharedKey, SharedKey Length may be Zero. ++VOID STAFindCipherAlgorithm( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet ++ UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm ++ UCHAR KeyIdx = 0xff; ++ PUCHAR pSrcBufVA; ++ PCIPHER_KEY pKey = NULL; ++ ++ pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); ++ ++ { ++ // Select Cipher ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) ++ Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast ++ else ++ Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast ++ ++ if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) ++ { ++ ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128); ++ ++ // 4-way handshaking frame must be clear ++ if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) && ++ (pAd->SharedKey[BSS0][0].KeyLen)) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ KeyIdx = 0; ++ } ++ } ++ else if (Cipher == Ndis802_11Encryption1Enabled) ++ { ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on ++ { ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) ++ KeyIdx = 1; ++ else ++ KeyIdx = 0; ++ } ++ else ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ else if (LEAP_CCKM_ON(pAd)) ++ { ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) ++ KeyIdx = 1; ++ else ++ KeyIdx = 0; ++ } ++ else // standard WEP64 or WEP128 ++#endif // LEAP_SUPPORT // ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ else if ((Cipher == Ndis802_11Encryption2Enabled) || ++ (Cipher == Ndis802_11Encryption3Enabled)) ++ { ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ else if (pAd->SharedKey[BSS0][0].KeyLen) ++ KeyIdx = 0; ++ else ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ ++ if (KeyIdx == 0xff) ++ CipherAlg = CIPHER_NONE; ++ else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) ++ CipherAlg = CIPHER_NONE; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ( pAd->StaCfg.WpaSupplicantUP && ++ (Cipher == Ndis802_11Encryption1Enabled) && ++ (pAd->StaCfg.IEEE8021X == TRUE) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ CipherAlg = CIPHER_NONE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ //Header_802_11.FC.Wep = 1; ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ pKey = &pAd->SharedKey[BSS0][KeyIdx]; ++ } ++ } ++ ++ pTxBlk->CipherAlg = CipherAlg; ++ pTxBlk->pKey = pKey; ++} ++ ++ ++VOID STABuildCommon802_11Header( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ ++ HEADER_802_11 *pHeader_802_11; ++#ifdef QOS_DLS_SUPPORT ++ BOOLEAN bDLSFrame = FALSE; ++ INT DlsEntryIndex = 0; ++#endif // QOS_DLS_SUPPORT // ++ ++ // ++ // MAKE A COMMON 802.11 HEADER ++ // ++ ++ // normal wlan header size : 24 octets ++ pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); ++ ++ pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ ++ NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11)); ++ ++ pHeader_802_11->FC.FrDs = 0; ++ pHeader_802_11->FC.Type = BTYPE_DATA; ++ pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); ++ ++#ifdef QOS_DLS_SUPPORT ++ if (INFRA_ON(pAd)) ++ { ++ // Check if the frame can be sent through DLS direct link interface ++ // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) ++ DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); ++ if (DlsEntryIndex >= 0) ++ bDLSFrame = TRUE; ++ else ++ bDLSFrame = FALSE; ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ if (pTxBlk->pMacEntry) ++ { ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) ++ { ++ pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq; ++ pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ; ++ } ++ else ++ { ++ pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; ++ pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; ++ } ++ } ++ else ++ { ++ pHeader_802_11->Sequence = pAd->Sequence; ++ pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence ++ } ++ ++ pHeader_802_11->Frag = 0; ++ ++ pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); ++ ++ { ++ if (INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ pHeader_802_11->FC.ToDs = 0; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader); ++ pHeader_802_11->FC.ToDs = 1; ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ pHeader_802_11->FC.ToDs = 0; ++ } ++ } ++ ++ if (pTxBlk->CipherAlg != CIPHER_NONE) ++ pHeader_802_11->FC.Wep = 1; ++ ++ // ----------------------------------------------------------------- ++ // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. ++ // ----------------------------------------------------------------- ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID STABuildCache802_11Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR *pHeader) ++{ ++ MAC_TABLE_ENTRY *pMacEntry; ++ PHEADER_802_11 pHeader80211; ++ ++ pHeader80211 = (PHEADER_802_11)pHeader; ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ // ++ // Update the cached 802.11 HEADER ++ // ++ ++ // normal wlan header size : 24 octets ++ pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); ++ ++ // More Bit ++ pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); ++ ++ // Sequence ++ pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; ++ pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; ++ ++ { ++ // Check if the frame can be sent through DLS direct link interface ++ // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) ++#ifdef QOS_DLS_SUPPORT ++ BOOLEAN bDLSFrame = FALSE; ++ INT DlsEntryIndex = 0; ++ ++ DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); ++ if (DlsEntryIndex >= 0) ++ bDLSFrame = TRUE; ++ else ++ bDLSFrame = FALSE; ++#endif // QOS_DLS_SUPPORT // ++ ++ // The addr3 of normal packet send from DS is Dest Mac address. ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); ++ pHeader80211->FC.ToDs = 0; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ if (ADHOC_ON(pAd)) ++ COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); ++ else ++ COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader); ++ } ++ ++ // ----------------------------------------------------------------- ++ // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. ++ // ----------------------------------------------------------------- ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ pHeader80211->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++} ++#endif // DOT11_N_SUPPORT // ++ ++static inline PUCHAR STA_Build_ARalink_Frame_Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ HEADER_802_11 *pHeader_802_11; ++ PNDIS_PACKET pNextPacket; ++ UINT32 nextBufLen; ++ PQUEUE_ENTRY pQEntry; ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // steal "order" bit to mark "aggregation" ++ pHeader_802_11->FC.Order = 1; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // padding at front of LLC header. LLC header should at 4-bytes aligment. ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ // For RA Aggregation, ++ // put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format ++ pQEntry = pTxBlk->TxPacketList.Head; ++ pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry); ++ nextBufLen = GET_OS_PKT_LEN(pNextPacket); ++ if (RTMP_GET_PACKET_VLAN(pNextPacket)) ++ nextBufLen -= LENGTH_802_1Q; ++ ++ *pHeaderBufPtr = (UCHAR)nextBufLen & 0xff; ++ *(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8); ++ ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ return pHeaderBufPtr; ++ ++} ++ ++#ifdef DOT11_N_SUPPORT ++static inline PUCHAR STA_Build_AMSDU_Frame_Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr;//, pSaveBufPtr; ++ HEADER_802_11 *pHeader_802_11; ++ ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ // ++ // A-MSDU packet ++ // ++ *pHeaderBufPtr |= 0x80; ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ //pSaveBufPtr = pHeaderBufPtr; ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ // @@@ MpduHeaderLen excluding padding @@@ ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ return pHeaderBufPtr; ++ ++} ++ ++ ++VOID STA_AMPDU_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ MAC_TABLE_ENTRY *pMacEntry; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ASSERT(pTxBlk); ++ ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ pMacEntry = pTxBlk->pMacEntry; ++ if (pMacEntry->isCached) ++ { ++ // NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! ++ NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11)); ++ pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); ++ STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); ++ } ++ else ++ { ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ } ++ ++ ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ // ++ // build HTC+ ++ // HTC control filed following QoS field ++ // ++ if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)) ++ { ++ if (pMacEntry->isCached == FALSE) ++ { ++ // mark HTC bit ++ pHeader_802_11->FC.Order = 1; ++ ++ NdisZeroMemory(pHeaderBufPtr, 4); ++ *(pHeaderBufPtr+3) |= 0x80; ++ } ++ pHeaderBufPtr += 4; ++ pTxBlk->MpduHeaderLen += 4; ++ } ++ ++ //pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; ++ ASSERT(pTxBlk->MpduHeaderLen >= 24); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ // @@@ MpduHeaderLen excluding padding @@@ ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ { ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ } ++ ++ if (pMacEntry->isCached) ++ { ++ RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ } ++ else ++ { ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf)); ++ NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]))); ++ pMacEntry->isCached = TRUE; ++ } ++ ++ // calculate Transmitted AMPDU count and ByteCount ++ { ++ pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++; ++ pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen; ++ } ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ } ++ ++} ++ ++ ++VOID STA_AMSDU_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding. ++ USHORT totalMPDUSize=0; ++ UCHAR *subFrameHeader; ++ UCHAR padding = 0; ++ USHORT FirstTx = 0, LastTxIdx = 0; ++ BOOLEAN bVLANPkt; ++ int frameNum = 0; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ ASSERT((pTxBlk->TxPacketList.Number > 1)); ++ ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ if (frameNum == 0) ++ { ++ pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); ++ ++ // NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ } ++ else ++ { ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; ++ padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen); ++ NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD); ++ pHeaderBufPtr += padding; ++ pTxBlk->MpduHeaderLen = padding; ++ } ++ ++ // ++ // A-MSDU subframe ++ // DA(6)+SA(6)+Length(2) + LLC/SNAP Encap ++ // ++ subFrameHeader = pHeaderBufPtr; ++ subFramePayloadLen = pTxBlk->SrcBufLen; ++ ++ NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); ++ ++ ++ pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; ++ pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ ++ subFramePayloadLen = pTxBlk->SrcBufLen; ++ ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ subFramePayloadLen += LENGTH_802_1_H; ++ } ++ ++ // update subFrame Length field ++ subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; ++ subFrameHeader[13] = subFramePayloadLen & 0xFF; ++ ++ totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++ if (frameNum ==0) ++ FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ else ++ LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ ++ frameNum++; ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // calculate Transmitted AMSDU Count and ByteCount ++ { ++ pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++; ++ pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize; ++ } ++ ++ } ++ ++ HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); ++ HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID STA_Legacy_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ASSERT(pTxBlk); ++ ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ if (pTxBlk->TxFrameType == TX_MCAST_FRAME) ++ { ++ INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); ++ } ++ ++ if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); ++ else ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) ++ pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // The remaining content of MPDU header should locate at 4-octets aligment ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ { ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ // ++ // if original Ethernet frame contains no LLC/SNAP, ++ // then an extra LLC/SNAP encap is required ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ UCHAR vlan_size; ++ ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // skip vlan tag ++ vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ } ++ ++ // ++ // prepare for TXWI ++ // use Wcid as Key Index ++ // ++ ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++ ++ ++VOID STA_ARalink_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ USHORT totalMPDUSize=0; ++ USHORT FirstTx, LastTxIdx; ++ int frameNum = 0; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ ASSERT((pTxBlk->TxPacketList.Number== 2)); ++ ++ ++ FirstTx = LastTxIdx = 0; // Is it ok init they as 0? ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ if (frameNum == 0) ++ { // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header ++ ++ pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk); ++ ++ // It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount ++ // will be updated after final frame was handled. ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ } ++ else ++ { // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; ++ pTxBlk->MpduHeaderLen = 0; ++ ++ // A-Ralink sub-sequent frame header is the same as 802.3 header. ++ // DA(6)+SA(6)+FrameType(2) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12); ++ pHeaderBufPtr += 12; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; ++ } ++ ++ totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ if (frameNum ==0) ++ FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ else ++ LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ ++ frameNum++; ++ ++ pAd->RalinkCounters.OneSecTxAggregationCount++; ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ } ++ ++ HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); ++ HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ ++} ++ ++ ++VOID STA_Fragment_Frame_Tx( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ UCHAR fragNum = 0; ++ PACKET_INFO PacketInfo; ++ USHORT EncryptionOverhead = 0; ++ UINT32 FreeMpduSize, SrcRemainingBytes; ++ USHORT AckDuration; ++ UINT NextMpduSize; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ { ++ pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); ++ if (pTxBlk->pPacket == NULL) ++ return; ++ RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); ++ } ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr; ++ ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ // ++ // if original Ethernet frame contains no LLC/SNAP, ++ // then an extra LLC/SNAP encap is required ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ UCHAR vlan_size; ++ ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // skip vlan tag ++ vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ ++ // If TKIP is used and fragmentation is required. Driver has to ++ // append TKIP MIC at tail of the scatter buffer ++ // MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC ++ if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ { ++ ++ // NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust ++ // to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. ++ NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); ++ //skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); ++ pTxBlk->SrcBufLen += 8; ++ pTxBlk->TotalFrameLen += 8; ++ pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; ++ } ++ ++ // ++ // calcuate the overhead bytes that encryption algorithm may add. This ++ // affects the calculate of "duration" field ++ // ++ if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128)) ++ EncryptionOverhead = 8; //WEP: IV[4] + ICV[4]; ++ else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) ++ EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength ++ else if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] ++ else if (pTxBlk->CipherAlg == CIPHER_AES) ++ EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8] ++ else ++ EncryptionOverhead = 0; ++ ++ // decide how much time an ACK/CTS frame will consume in the air ++ AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14); ++ ++ // Init the total payload length of this frame. ++ SrcRemainingBytes = pTxBlk->SrcBufLen; ++ ++ pTxBlk->TotalFragNum = 0xff; ++ ++ do { ++ ++ FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; ++ ++ FreeMpduSize -= pTxBlk->MpduHeaderLen; ++ ++ if (SrcRemainingBytes <= FreeMpduSize) ++ { // this is the last or only fragment ++ ++ pTxBlk->SrcBufLen = SrcRemainingBytes; ++ ++ pHeader_802_11->FC.MoreFrag = 0; ++ pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration; ++ ++ // Indicate the lower layer that this's the last fragment. ++ pTxBlk->TotalFragNum = fragNum; ++ } ++ else ++ { // more fragment is required ++ ++ pTxBlk->SrcBufLen = FreeMpduSize; ++ ++ NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold)); ++ pHeader_802_11->FC.MoreFrag = 1; ++ pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead); ++ } ++ ++ if (fragNum == 0) ++ pTxBlk->FrameGap = IFS_HTTXOP; ++ else ++ pTxBlk->FrameGap = IFS_SIFS; ++ ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // Update the frame number, remaining size of the NDIS packet payload. ++ ++ // space for 802.11 header. ++ if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) ++ pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; ++ ++ fragNum++; ++ SrcRemainingBytes -= pTxBlk->SrcBufLen; ++ pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; ++ ++ pHeader_802_11->Frag++; // increase Frag # ++ ++ }while(SrcRemainingBytes > 0); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++ ++ ++#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ ++ while(_pTxBlk->TxPacketList.Head) \ ++ { \ ++ _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ ++ RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ ++ } ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware encryption before really ++ sent out to air. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to outgoing Ndis frame ++ NumberOfFrag Number of fragment required ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS STAHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx) ++{ ++ NDIS_PACKET *pPacket; ++ PQUEUE_ENTRY pQEntry; ++ ++ // --------------------------------------------- ++ // STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. ++ // --------------------------------------------- ++ // ++ ASSERT(pTxBlk->TxPacketList.Number); ++ if (pTxBlk->TxPacketList.Head == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number)); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); ++ ++#if 0 //def CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ if ((pAd->CommonCfg.CarrierDetect.Enable == TRUE) && (isCarrierDetectExist(pAd) == TRUE)) ++ { ++ DBGPRINT(RT_DEBUG_INFO,("STAHardTransmit --> radar detect not in normal mode !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return (NDIS_STATUS_FAILURE); ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ // ------------------------------------------------------------------ ++ // STEP 1. WAKE UP PHY ++ // outgoing frame always wakeup PHY to prevent frame lost and ++ // turn off PSM bit to improve performance ++ // ------------------------------------------------------------------ ++ // not to change PSM bit, just send this frame out? ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); ++ AsicForceWakeup(pAd, TRUE); ++ } ++ ++ // It should not change PSM bit, when APSD turn on. ++ if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) ++ || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) ++ || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) ++ { ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && ++ (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP)) ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ } ++ ++ switch (pTxBlk->TxFrameType) ++ { ++#ifdef DOT11_N_SUPPORT ++ case TX_AMPDU_FRAME: ++ STA_AMPDU_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_AMSDU_FRAME: ++ STA_AMSDU_Frame_Tx(pAd, pTxBlk); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case TX_LEGACY_FRAME: ++ STA_Legacy_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_MCAST_FRAME: ++ STA_Legacy_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_RALINK_FRAME: ++ STA_ARalink_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_FRAG_FRAME: ++ STA_Fragment_Frame_Tx(pAd, pTxBlk); ++ break; ++ default: ++ { ++ // It should not happened! ++ DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n")); ++ while(pTxBlk->TxPacketList.Number) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (pPacket) ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ } ++ break; ++ } ++ ++ return (NDIS_STATUS_SUCCESS); ++ ++} ++ ++ULONG HashBytesPolynomial(UCHAR *value, unsigned int len) ++{ ++ unsigned char *word = value; ++ unsigned int ret = 0; ++ unsigned int i; ++ ++ for(i=0; i < len; i++) ++ { ++ int mod = i % 32; ++ ret ^=(unsigned int) (word[i]) << mod; ++ ret ^=(unsigned int) (word[i]) >> (32 - mod); ++ } ++ return ret; ++} ++ ++VOID Sta_Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID) ++{ ++ if (TRUE ++ ) ++ { ++ announce_802_3_packet(pAd, pPacket); ++ } ++ else ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/sanity.c +@@ -0,0 +1,420 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sanity.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 add WMM support ++*/ ++#include "../rt_config.h" ++ ++extern UCHAR CISCO_OUI[]; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR BROADCOM_OUI[]; ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeStartReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen) ++{ ++ MLME_START_REQ_STRUCT *Info; ++ ++ Info = (MLME_START_REQ_STRUCT *)(Msg); ++ ++ if (Info->SsidLen > MAX_LEN_OF_SSID) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqSanity fail - wrong SSID length\n")); ++ return FALSE; ++ } ++ ++ *pSsidLen = Info->SsidLen; ++ NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT USHORT *pAid, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ OUT UCHAR *pHtCapabilityLen, ++ OUT UCHAR *pAddHtInfoLen, ++ OUT UCHAR *pNewExtChannelOffset, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT UCHAR *pCkipFlag) ++{ ++ CHAR IeType, *Ptr; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PEID_STRUCT pEid; ++ ULONG Length = 0; ++ ++ *pNewExtChannelOffset = 0xff; ++ *pHtCapabilityLen = 0; ++ *pAddHtInfoLen = 0; ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2); ++ Length += 2; ++ NdisMoveMemory(pStatus, &pFrame->Octet[2], 2); ++ Length += 2; ++ *pCkipFlag = 0; ++ *pExtRateLen = 0; ++ pEdcaParm->bValid = FALSE; ++ ++ if (*pStatus != MLME_SUCCESS) ++ return TRUE; ++ ++ NdisMoveMemory(pAid, &pFrame->Octet[4], 2); ++ Length += 2; ++ ++ // Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform ++ *pAid = (*pAid) & 0x3fff; // AID is low 14-bit ++ ++ // -- get supported rates from payload and advance the pointer ++ IeType = pFrame->Octet[6]; ++ *pSupRateLen = pFrame->Octet[7]; ++ if ((IeType != IE_SUPP_RATES) || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity fail - wrong SupportedRates IE\n")); ++ return FALSE; ++ } ++ else ++ NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen); ++ ++ Length = Length + 2 + *pSupRateLen; ++ ++ // many AP implement proprietary IEs in non-standard order, we'd better ++ // tolerate mis-ordered IEs to get best compatibility ++ pEid = (PEID_STRUCT) &pFrame->Octet[8 + (*pSupRateLen)]; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ switch (pEid->Eid) ++ { ++ case IE_EXT_SUPP_RATES: ++ if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); ++ *pExtRateLen = pEid->Len; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ case IE_HT_CAP2: ++ if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! ++ { ++ NdisMoveMemory(pHtCapability, pEid->Octet, SIZE_HT_CAP_IE); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_HT_CAP. \n")); ++ } ++ ++ break; ++#ifdef DOT11_N_SUPPORT ++ case IE_ADD_HT: ++ case IE_ADD_HT2: ++ if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) ++ { ++ // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only ++ // copy first sizeof(ADD_HT_INFO_IE) ++ NdisMoveMemory(pAddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); ++ ++ *(USHORT *)(&pAddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo2)); ++ *(USHORT *)(&pAddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo3)); ++ ++ *pAddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_ADD_HT. \n")); ++ } ++ ++ break; ++ case IE_SECONDARY_CH_OFFSET: ++ if (pEid->Len == 1) ++ { ++ *pNewExtChannelOffset = pEid->Octet[0]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); ++ } ++#endif // DOT11_N_SUPPORT // ++ break; ++ case IE_AIRONET_CKIP: ++ // 0. Check Aironet IE length, it must be larger or equal to 28 ++ // Cisco's AP VxWork version(will not be supported) used this IE length as 28 ++ // Cisco's AP IOS version used this IE length as 30 ++ if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) ++ break; ++ ++ // 1. Copy CKIP flag byte to buffer for process ++ *pCkipFlag = *(pEid->Octet + 8); ++ break; ++ ++ case IE_AIRONET_IPADDRESS: ++ if (pEid->Len != 0x0A) ++ break; ++ ++ // Get Cisco Aironet IP information ++ if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) ++ NdisMoveMemory(pAd->StaCfg.AironetIPAddress, pEid->Octet + 4, 4); ++ break; ++ ++ // CCX2, WMM use the same IE value ++ // case IE_CCX_V2: ++ case IE_VENDOR_SPECIFIC: ++ // handle WME PARAMTER ELEMENT ++ if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) ++ { ++ PUCHAR ptr; ++ int i; ++ ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ //pEdcaParm->bMoreDataAck = FALSE; // pEid->Octet[0] & 0x80; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ptr = &pEid->Octet[8]; ++ for (i=0; i<4; i++) ++ { ++ UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX ++ pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM ++ pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN ++ pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin ++ pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax ++ pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us ++ ptr += 4; // point to next AC ++ } ++ } ++ ++ // handle CCX IE ++ else ++ { ++ // 0. Check the size and CCX admin control ++ if (pAd->StaCfg.CCXControl.field.Enable == 0) ++ break; ++ if (pEid->Len != 5) ++ break; ++ ++ // Turn CCX2 if matched ++ if (NdisEqualMemory(pEid->Octet, Ccx2IeInfo, 5) == 1) ++ pAd->StaCfg.CCXEnable = TRUE; ++ break; ++ } ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity - ignore unrecognized EID = %d\n", pEid->Eid)); ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ // Force CCX2 enable to TRUE for those AP didn't replay CCX v2 IE, we still force it to be on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ pAd->StaCfg.CCXEnable = TRUE; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen) ++{ ++ UCHAR Idx; ++ UCHAR RateLen; ++ CHAR IeType; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ ++ if ((pFrame->Octet[0] != IE_SSID) || (pFrame->Octet[1] > MAX_LEN_OF_SSID)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",pFrame->Octet[0],pFrame->Octet[1])); ++ return FALSE; ++ } ++ ++ *pSsidLen = pFrame->Octet[1]; ++ NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen); ++ ++ Idx = *pSsidLen + 2; ++ ++ // -- get supported rates from payload and advance the pointer ++ IeType = pFrame->Octet[Idx]; ++ RateLen = pFrame->Octet[Idx + 1]; ++ if (IeType != IE_SUPP_RATES) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",pFrame->Octet[Idx],pFrame->Octet[Idx+1])); ++ return FALSE; ++ } ++ else ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8)) ++ return (FALSE); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN GetTimBit( ++ IN CHAR *Ptr, ++ IN USHORT Aid, ++ OUT UCHAR *TimLen, ++ OUT UCHAR *BcastFlag, ++ OUT UCHAR *DtimCount, ++ OUT UCHAR *DtimPeriod, ++ OUT UCHAR *MessageToMe) ++{ ++ UCHAR BitCntl, N1, N2, MyByte, MyBit; ++ CHAR *IdxPtr; ++ ++ IdxPtr = Ptr; ++ ++ IdxPtr ++; ++ *TimLen = *IdxPtr; ++ ++ // get DTIM Count from TIM element ++ IdxPtr ++; ++ *DtimCount = *IdxPtr; ++ ++ // get DTIM Period from TIM element ++ IdxPtr++; ++ *DtimPeriod = *IdxPtr; ++ ++ // get Bitmap Control from TIM element ++ IdxPtr++; ++ BitCntl = *IdxPtr; ++ ++ if ((*DtimCount == 0) && (BitCntl & 0x01)) ++ *BcastFlag = TRUE; ++ else ++ *BcastFlag = FALSE; ++ ++ // Parse Partial Virtual Bitmap from TIM element ++ N1 = BitCntl & 0xfe; // N1 is the first bitmap byte# ++ N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte# ++ ++ if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3))) ++ *MessageToMe = FALSE; ++ else ++ { ++ MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream ++ MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0); ++ ++ IdxPtr += (MyByte + 1); ++ ++ //if (*IdxPtr) ++ // DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); ++ ++ if (*IdxPtr & (0x01 << MyBit)) ++ *MessageToMe = TRUE; ++ else ++ *MessageToMe = FALSE; ++ } ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/sync.c +@@ -0,0 +1,1753 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sync.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 modified for rt2561/2661 ++ Jan Lee 2006-08-01 modified for rt2860 for 802.11n ++*/ ++#include "../rt_config.h" ++ ++#define ADHOC_ENTRY_BEACON_LOST_TIME (2*OS_HZ) // 2 sec ++ ++/* ++ ========================================================================== ++ Description: ++ The sync state machine, ++ Parameters: ++ Sm - pointer to the state machine ++ Note: ++ the state machine looks like the following ++ ++ ========================================================================== ++ */ ++VOID SyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE); ++ ++ // column 1 ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction); ++ ++ //column 2 ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction); ++ ++ // column 3 ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction); ++ ++ // timer init ++ RTMPInitTimer(pAd, &pAd->MlmeAux.BeaconTimer, GET_TIMER_FUNCTION(BeaconTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.ScanTimer, GET_TIMER_FUNCTION(ScanTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Beacon timeout handler, executed in timer thread ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID BeaconTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SYNC - BeaconTimeout\n")); ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ++ ) ++ { ++ UCHAR BBPValue = 0; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan timeout handler, executed in timer thread ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++ if (MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL)) ++ { ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ else ++ { ++ // To prevent SyncMachine.CurrState is SCAN_LISTEN forever. ++ pAd->MlmeAux.Channel = 0; ++ ScanNextChannel(pAd); ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME SCAN req state machine procedure ++ ========================================================================== ++ */ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType, BBPValue = 0; ++ BOOLEAN TimerCancelled; ++ ULONG Now; ++ USHORT Status; ++ PHEADER_802_11 pHdr80211; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ++ // Check the total scan tries for one single OID command ++ // If this is the CCX 2.0 Case, skip that! ++ if ( !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeScanReqAction before Startup\n")); ++ return; ++ } ++ ++ // Increase the scan retry counters. ++ pAd->StaCfg.ScanCnt++; ++ ++ ++ // first check the parameter sanity ++ if (MlmeScanReqSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ &BssType, ++ Ssid, ++ &SsidLen, ++ &ScanType)) ++ { ++ ++ // Check for channel load and noise hist request ++ // Suspend MSDU only at scan request, not the last two mentioned ++ if ((ScanType == SCAN_CISCO_NOISE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD)) ++ { ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ RTMPSuspendMsduTransmission(pAd); // Suspend MSDU transmission here ++ } ++ else ++ { ++ // Suspend MSDU transmission here ++ RTMPSuspendMsduTransmission(pAd); ++ } ++ ++ // ++ // To prevent data lost. ++ // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. ++ // And should send an NULL data with turned PSM bit off to AP, when scan progress done ++ // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) ++ { ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ pHdr80211 = (PHEADER_802_11) pOutBuffer; ++ MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pHdr80211->Duration = 0; ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame for off channel RM\n")); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPusecDelay(5000); ++ } ++ } ++ ++ NdisGetSystemUpTime(&Now); ++ pAd->StaCfg.LastScanTime = Now; ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ ++ // record desired BSS parameters ++ pAd->MlmeAux.BssType = BssType; ++ pAd->MlmeAux.ScanType = ScanType; ++ pAd->MlmeAux.SsidLen = SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ ++ // start from the first channel ++ pAd->MlmeAux.Channel = FirstChannel(pAd); ++ ++ // Change the scan channel when dealing with CCX beacon report ++ if ((ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_ACTIVE) || ++ (ScanType == SCAN_CISCO_CHANNEL_LOAD) || (ScanType == SCAN_CISCO_NOISE)) ++ pAd->MlmeAux.Channel = pAd->StaCfg.CCXScanChannel; ++ ++ // Let BBP register at 20MHz to do scan ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ++ ScanNextChannel(pAd); ++ } ++ else ++ { ++ DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME JOIN req state machine procedure ++ ========================================================================== ++ */ ++VOID MlmeJoinReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR BBPValue = 0; ++ BSS_ENTRY *pBss; ++ BOOLEAN TimerCancelled; ++ HEADER_802_11 Hdr80211; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ PUCHAR pOutBuffer = NULL; ++ PUCHAR pSupRate = NULL; ++ UCHAR SupRateLen; ++ PUCHAR pExtRate = NULL; ++ UCHAR ExtRateLen; ++ UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C}; ++ UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR); ++ MLME_JOIN_REQ_STRUCT *pInfo = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); ++ ++ ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ pBss = &pAd->MlmeAux.SsidBssTab.BssEntry[pInfo->BssIdx]; ++ ++ // record the desired SSID & BSSID we're waiting for ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pBss->Bssid); ++ ++ // If AP's SSID is not hidden, it is OK for updating ssid to MlmeAux again. ++ if (pBss->Hidden == 0) ++ { ++ NdisMoveMemory(pAd->MlmeAux.Ssid, pBss->Ssid, pBss->SsidLen); ++ pAd->MlmeAux.SsidLen = pBss->SsidLen; ++ } ++ ++ pAd->MlmeAux.BssType = pBss->BssType; ++ pAd->MlmeAux.Channel = pBss->Channel; ++ pAd->MlmeAux.CentralChannel = pBss->CentralChannel; ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // Country IE of the AP will be evaluated and will be used. ++ if ((pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) && ++ (pBss->bHasCountryIE == TRUE)) ++ { ++ NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pBss->CountryString[0], 2); ++ if (pBss->CountryString[2] == 'I') ++ pAd->CommonCfg.Geography = IDOR; ++ else if (pBss->CountryString[2] == 'O') ++ pAd->CommonCfg.Geography = ODOR; ++ else ++ pAd->CommonCfg.Geography = BOTH; ++ BuildChannelListEx(pAd); ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Let BBP register at 20MHz to do scan ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ++ ++ // switch channel and waiting for beacon timer ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ RTMPSetTimer(&pAd->MlmeAux.BeaconTimer, JOIN_TIMEOUT); ++ ++ do ++ { ++ if (((pAd->CommonCfg.bIEEE80211H == 1) && ++ (pAd->MlmeAux.Channel > 14) && ++ RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ // ++ // We can't send any Probe request frame to meet 802.11h. ++ // ++ if (pBss->Hidden == 0) ++ break; ++ } ++ ++ // ++ // send probe request ++ // ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ if (pAd->MlmeAux.Channel <= 14) ++ { ++ pSupRate = pAd->CommonCfg.SupRate; ++ SupRateLen = pAd->CommonCfg.SupRateLen; ++ pExtRate = pAd->CommonCfg.ExtRate; ++ ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ } ++ else ++ { ++ // ++ // Overwrite Support Rate, CCK rate are not allowed ++ // ++ pSupRate = ASupRate; ++ SupRateLen = ASupRateLen; ++ ExtRateLen = 0; ++ } ++ ++ if (pAd->MlmeAux.BssType == BSS_INFRA) ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, pAd->MlmeAux.Bssid, pAd->MlmeAux.Bssid); ++ else ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &SupRateLen, ++ SupRateLen, pSupRate, ++ END_OF_ARGS); ++ ++ if (ExtRateLen) ++ { ++ ULONG Tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtRateIe, ++ 1, &ExtRateLen, ++ ExtRateLen, pExtRate, ++ END_OF_ARGS); ++ FrameLen += Tmp; ++ } ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } while (FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Switch to ch %d, Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ ++ pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME START Request state machine procedure, starting an IBSS ++ ========================================================================== ++ */ ++VOID MlmeStartReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen; ++ BOOLEAN TimerCancelled; ++ ++ // New for WPA security suites ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ LARGE_INTEGER TimeStamp; ++ BOOLEAN Privacy; ++ USHORT Status; ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ TimeStamp.u.LowPart = 0; ++ TimeStamp.u.HighPart = 0; ++ ++ if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen)) ++ { ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ // ++ // Start a new IBSS. All IBSS parameters are decided now.... ++ // ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - Start a new IBSS. All IBSS parameters are decided now.... \n")); ++ pAd->MlmeAux.BssType = BSS_ADHOC; ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ pAd->MlmeAux.SsidLen = SsidLen; ++ ++ // generate a radom number as BSSID ++ MacAddrRandomBssid(pAd, pAd->MlmeAux.Bssid); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - generate a radom number as BSSID \n")); ++ ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ pAd->MlmeAux.CapabilityInfo = CAP_GENERATE(0,1,Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 1, 0); ++ pAd->MlmeAux.BeaconPeriod = pAd->CommonCfg.BeaconPeriod; ++ pAd->MlmeAux.AtimWin = pAd->StaCfg.AtimWin; ++ pAd->MlmeAux.Channel = pAd->CommonCfg.Channel; ++ ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.CentralChannel; ++ ++ pAd->MlmeAux.SupRateLen= pAd->CommonCfg.SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); ++ pAd->MlmeAux.HtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ // Not turn pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE here. ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n")); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->MlmeAux.HtCapabilityLen = 0; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ } ++ // temporarily not support QOS in IBSS ++ NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeStartReqAction(ch= %d,sup rates= %d, ext rates=%d)\n", ++ pAd->MlmeAux.Channel, pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++ } ++ else ++ { ++ DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends beacon back when scanning ++ ========================================================================== ++ */ ++VOID PeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, NewChannel, ++ SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe; ++ CF_PARM CfParm; ++ USHORT BeaconPeriod, AtimWin, CapabilityInfo; ++ PFRAME_802_11 pFrame; ++ LARGE_INTEGER TimeStamp; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ USHORT LenVIE; ++ UCHAR CkipFlag; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ ULONG RalinkIe; ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ ++ // NdisFillMemory(Ssid, MAX_LEN_OF_SSID, 0x00); ++ pFrame = (PFRAME_802_11) Elem->Msg; ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++#ifdef DOT11_N_SUPPORT ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++#endif // DOT11_N_SUPPORT // ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &CfParm, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ ULONG Idx; ++ CHAR Rssi = 0; ++ ++ Idx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Idx != BSS_NOT_FOUND) ++ Rssi = pAd->ScanTab.BssEntry[Idx].Rssi; ++ ++ Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ ++#ifdef DOT11_N_SUPPORT ++ if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) ++ HtCapabilityLen = SIZE_HT_CAP_IE; ++#endif // DOT11_N_SUPPORT // ++ if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel)) ++ { ++ Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen,ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++ if (Idx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(pAd->StaCfg.CCXBssTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ if (pAd->StaCfg.CCXReqType == MSRN_TYPE_BEACON_REQ) ++ AironetAddBeaconReport(pAd, Idx, Elem); ++ } ++ } ++ else ++ { ++ Idx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (pAd->ChannelList[pAd->CommonCfg.ChannelListIdx].bEffectedChannel == TRUE) ++ { ++ UCHAR RegClass; ++ PeerBeaconAndProbeRspSanity2(pAd, Elem->Msg, Elem->MsgLen, &RegClass); ++ TriEventTableSetEntry(pAd, &pAd->CommonCfg.TriggerEventTab, Bssid, &HtCapability, HtCapabilityLen, RegClass, Channel); ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ if (Idx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ } ++ } ++ } ++ // sanity check fail, ignored ++} ++ ++/* ++ ========================================================================== ++ Description: ++ When waiting joining the (I)BSS, beacon received from external ++ ========================================================================== ++ */ ++VOID PeerBeaconAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, MessageToMe, ++ DtimCount, DtimPeriod, BcastFlag, NewChannel; ++ LARGE_INTEGER TimeStamp; ++ USHORT BeaconPeriod, AtimWin, CapabilityInfo; ++ CF_PARM Cf; ++ BOOLEAN TimerCancelled; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ UCHAR CkipFlag; ++ USHORT LenVIE; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ USHORT Status; ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ ULONG RalinkIe; ++ ULONG Idx; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++#ifdef DOT11_N_SUPPORT ++ UCHAR CentralChannel; ++#endif // DOT11_N_SUPPORT // ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &Cf, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ // Disqualify 11b only adhoc when we are in 11g only adhoc mode ++ if ((BssType == BSS_ADHOC) && (pAd->CommonCfg.PhyMode == PHY_11G) && ((SupRateLen+ExtRateLen)< 12)) ++ return; ++ ++ // BEACON from desired BSS/IBSS found. We should be able to decide most ++ // BSS parameters here. ++ // Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? ++ // Do we need to receover back all parameters belonging to previous BSS? ++ // A. Should be not. There's no back-door recover to previous AP. It still need ++ // a new JOIN-AUTH-ASSOC sequence. ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - receive desired BEACON at JoinWaitBeacon... Channel = %d\n", Channel)); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ // Update RSSI to prevent No signal display when cards first initialized ++ pAd->StaCfg.RssiSample.LastRssi0 = ConvertToRssi(pAd, Elem->Rssi0, RSSI_0); ++ pAd->StaCfg.RssiSample.LastRssi1 = ConvertToRssi(pAd, Elem->Rssi1, RSSI_1); ++ pAd->StaCfg.RssiSample.LastRssi2 = ConvertToRssi(pAd, Elem->Rssi2, RSSI_2); ++ pAd->StaCfg.RssiSample.AvgRssi0 = pAd->StaCfg.RssiSample.LastRssi0; ++ pAd->StaCfg.RssiSample.AvgRssi0X8 = pAd->StaCfg.RssiSample.AvgRssi0 << 3; ++ pAd->StaCfg.RssiSample.AvgRssi1 = pAd->StaCfg.RssiSample.LastRssi1; ++ pAd->StaCfg.RssiSample.AvgRssi1X8 = pAd->StaCfg.RssiSample.AvgRssi1 << 3; ++ pAd->StaCfg.RssiSample.AvgRssi2 = pAd->StaCfg.RssiSample.LastRssi2; ++ pAd->StaCfg.RssiSample.AvgRssi2X8 = pAd->StaCfg.RssiSample.AvgRssi2 << 3; ++ ++ // ++ // We need to check if SSID only set to any, then we can record the current SSID. ++ // Otherwise will cause hidden SSID association failed. ++ // ++ if (pAd->MlmeAux.SsidLen == 0) ++ { ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ pAd->MlmeAux.SsidLen = SsidLen; ++ } ++ else ++ { ++ Idx = BssSsidTableSearch(&pAd->ScanTab, Bssid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Channel); ++ ++ if (Idx != BSS_NOT_FOUND) ++ { ++ // ++ // Multiple SSID case, used correct CapabilityInfo ++ // ++ CapabilityInfo = pAd->ScanTab.BssEntry[Idx].CapabilityInfo; ++ } ++ } ++ NdisMoveMemory(pAd->MlmeAux.Bssid, Bssid, MAC_ADDR_LEN); ++ pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; ++ pAd->MlmeAux.BssType = BssType; ++ pAd->MlmeAux.BeaconPeriod = BeaconPeriod; ++ pAd->MlmeAux.Channel = Channel; ++ pAd->MlmeAux.AtimWin = AtimWin; ++ pAd->MlmeAux.CfpPeriod = Cf.CfpPeriod; ++ pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration; ++ pAd->MlmeAux.APRalinkIe = RalinkIe; ++ ++ // Copy AP's supported rate to MlmeAux for creating assoication request ++ // Also filter out not supported rate ++ pAd->MlmeAux.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ pAd->MlmeAux.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++ ++ NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16); ++#ifdef DOT11_N_SUPPORT ++ pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; ++ pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen; ++ ++ // filter out un-supported ht rates ++ if (((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ ++ // StaActive.SupportedHtPhy.MCSSet stores Peer AP's 11n Rx capability ++ NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16); ++ pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; ++ pAd->MlmeAux.HtCapabilityLen = SIZE_HT_CAP_IE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ if (PreNHtCapabilityLen > 0) ++ pAd->StaActive.SupportedPhyInfo.bPreNHt = TRUE; ++ RTMPCheckHt(pAd, BSSID_WCID, &HtCapability, &AddHtInfo); ++ // Copy AP Parameter to StaActive. This is also in LinkUp. ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction! (MpduDensity=%d, MaxRAmpduFactor=%d, BW=%d)\n", ++ pAd->StaActive.SupportedHtPhy.MpduDensity, pAd->StaActive.SupportedHtPhy.MaxRAmpduFactor, HtCapability.HtCapInfo.ChannelWidth)); ++ ++ if (AddHtInfoLen > 0) ++ { ++ CentralChannel = AddHtInfo.ControlChan; ++ // Check again the Bandwidth capability of this AP. ++ if ((AddHtInfo.ControlChan > 2)&& (AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ CentralChannel = AddHtInfo.ControlChan - 2; ++ } ++ else if ((AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ CentralChannel = AddHtInfo.ControlChan + 2; ++ } ++ ++ // Check Error . ++ if (pAd->MlmeAux.CentralChannel != CentralChannel) ++ DBGPRINT(RT_DEBUG_ERROR, ("PeerBeaconAtJoinAction HT===>Beacon Central Channel = %d, Control Channel = %d. Mlmeaux CentralChannel = %d\n", CentralChannel, AddHtInfo.ControlChan, pAd->MlmeAux.CentralChannel)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction HT===>Central Channel = %d, Control Channel = %d, .\n", CentralChannel, AddHtInfo.ControlChan)); ++ ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // To prevent error, let legacy AP must have same CentralChannel and Channel. ++ if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0)) ++ pAd->MlmeAux.CentralChannel = pAd->MlmeAux.Channel; ++ ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ } ++ ++ RTMPUpdateMlmeRate(pAd); ++ ++ // copy QOS related information ++ if ((pAd->CommonCfg.bWmmCapable) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM)); ++ NdisMoveMemory(&pAd->MlmeAux.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisMoveMemory(&pAd->MlmeAux.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ else ++ { ++ NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n", ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); ++ ++#ifdef LEAP_SUPPORT ++ // Update CkipFlag ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ ++ // Keep TimeStamp for Re-Association used. ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ pAd->StaCfg.CCKMBeaconAtJoinTimeStamp = TimeStamp; ++#endif // LEAP_SUPPORT // ++ ++ if (AironetCellPowerLimit != 0xFF) ++ { ++ //We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power ++ ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); ++ } ++ else //Used the default TX Power Percentage. ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++ } ++ // not to me BEACON, ignored ++ } ++ // sanity check fail, ignore this frame ++} ++ ++/* ++ ========================================================================== ++ Description: ++ receive BEACON from peer ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ CF_PARM CfParm; ++ UCHAR SsidLen, MessageToMe=0, BssType, Channel, NewChannel, index=0; ++ UCHAR DtimCount=0, DtimPeriod=0, BcastFlag=0; ++ USHORT CapabilityInfo, AtimWin, BeaconPeriod; ++ LARGE_INTEGER TimeStamp; ++ USHORT TbttNumToNextWakeUp; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ UCHAR CkipFlag; ++ USHORT LenVIE; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ ULONG RalinkIe; ++ // New for WPA security suites ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen, PreNHtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ if (!(INFRA_ON(pAd) || ADHOC_ON(pAd) ++ )) ++ return; ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &CfParm, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ BOOLEAN is_my_bssid, is_my_ssid; ++ ULONG Bssidx, Now; ++ BSS_ENTRY *pBss; ++ CHAR RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ is_my_bssid = MAC_ADDR_EQUAL(Bssid, pAd->CommonCfg.Bssid)? TRUE : FALSE; ++ is_my_ssid = SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)? TRUE:FALSE; ++ ++ ++ // ignore BEACON not for my SSID ++ if ((! is_my_ssid) && (! is_my_bssid)) ++ return; ++ ++ // It means STA waits disassoc completely from this AP, ignores this beacon. ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC) ++ return; ++ ++#ifdef DOT11_N_SUPPORT ++ // Copy Control channel for this BSSID. ++ if (AddHtInfoLen != 0) ++ Channel = AddHtInfo.ControlChan; ++ ++ if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) ++ HtCapabilityLen = SIZE_HT_CAP_IE; ++#endif // DOT11_N_SUPPORT // ++ ++ // ++ // Housekeeping "SsidBssTab" table for later-on ROAMing usage. ++ // ++ Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ // discover new AP of this network, create BSS entry ++ Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &HtCapability, &AddHtInfo,HtCapabilityLen,AddHtInfoLen,NewExtChannelOffset, Channel, ++ RealRssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability, ++ &QbssLoad, LenVIE, pVIE); ++ if (Bssidx == BSS_NOT_FOUND) // return if BSS table full ++ return; ++ ++ NdisMoveMemory(pAd->ScanTab.BssEntry[Bssidx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ ++ ++ ++ } ++ ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) ++ { ++ // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). ++ // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. ++ AsicSwitchChannel(pAd, 1, FALSE); ++ AsicLockChannel(pAd, 1); ++ LinkDown(pAd, FALSE); ++ MlmeQueueInit(&pAd->Mlme.Queue); ++ BssTableInit(&pAd->ScanTab); ++ RTMPusecDelay(1000000); // use delay to prevent STA do reassoc ++ ++ // channel sanity check ++ for (index = 0 ; index < pAd->ChannelListNum; index++) ++ { ++ if (pAd->ChannelList[index].Channel == NewChannel) ++ { ++ pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; ++ pAd->CommonCfg.Channel = NewChannel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeacon - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); ++ break; ++ } ++ } ++ ++ if (index >= pAd->ChannelListNum) ++ { ++ DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); ++ } ++ } ++ ++ // if the ssid matched & bssid unmatched, we should select the bssid with large value. ++ // This might happened when two STA start at the same time ++ if ((! is_my_bssid) && ADHOC_ON(pAd)) ++ { ++ INT i; ++ ++ // Add the safeguard against the mismatch of adhoc wep status ++ if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus) ++ { ++ return; ++ } ++ ++ // collapse into the ADHOC network which has bigger BSSID value. ++ for (i = 0; i < 6; i++) ++ { ++ if (Bssid[i] > pAd->CommonCfg.Bssid[i]) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - merge to the IBSS with bigger BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ AsicDisableSync(pAd); ++ COPY_MAC_ADDR(pAd->CommonCfg.Bssid, Bssid); ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy BEACON frame to on-chip memory ++ is_my_bssid = TRUE; ++ break; ++ } ++ else if (Bssid[i] < pAd->CommonCfg.Bssid[i]) ++ break; ++ } ++ } ++ ++ ++ NdisGetSystemUpTime(&Now); ++ pBss = &pAd->ScanTab.BssEntry[Bssidx]; ++ pBss->Rssi = RealRssi; // lastest RSSI ++ pBss->LastBeaconRxTime = Now; // last RX timestamp ++ ++ // ++ // BEACON from my BSSID - either IBSS or INFRA network ++ // ++ if (is_my_bssid) ++ { ++ RXWI_STRUC RxWI; ++ ++ pAd->StaCfg.DtimCount = DtimCount; ++ pAd->StaCfg.DtimPeriod = DtimPeriod; ++ pAd->StaCfg.LastBeaconRxTime = Now; ++ ++ ++ RxWI.RSSI0 = Elem->Rssi0; ++ RxWI.RSSI1 = Elem->Rssi1; ++ RxWI.RSSI2 = Elem->Rssi2; ++ ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, &RxWI); ++ if (AironetCellPowerLimit != 0xFF) ++ { ++ // ++ // We get the Cisco (ccx) "TxPower Limit" required ++ // Changed to appropriate TxPower Limit for Ciso Compatible Extensions ++ // ++ ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); ++ } ++ else ++ { ++ // ++ // AironetCellPowerLimit equal to 0xFF means the Cisco (ccx) "TxPower Limit" not exist. ++ // Used the default TX Power Percentage, that set from UI. ++ // ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ } ++ ++ if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo))) ++ { ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR idx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (idx=0; idxWcid == RESERVED_WCID)) || ++ (pEntry && ((pEntry->LastBeaconRxTime + ADHOC_ENTRY_BEACON_LOST_TIME) < Now))) ++ { ++ if (pEntry == NULL) ++ // Another adhoc joining, add to our MAC table. ++ pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE); ++ ++ if (StaAddMacTableEntry(pAd, pEntry, MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo) == FALSE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ADHOC - Add Entry failed.\n")); ++ return; ++ } ++ ++ if (pEntry && ++ (Elem->Wcid == RESERVED_WCID)) ++ { ++ idx = pAd->StaCfg.DefaultKeyId; ++ RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry); ++ } ++ } ++ ++ if (pEntry && pEntry->ValidAsCLI) ++ pEntry->LastBeaconRxTime = Now; ++ ++ // At least another peer in this IBSS, declare MediaState as CONNECTED ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ ++ // 2003/03/12 - john ++ // Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that ++ // "site survey" result should always include the current connected network. ++ // ++ Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n")); ++ } ++ } ++ ++ if (INFRA_ON(pAd)) ++ { ++ BOOLEAN bUseShortSlot, bUseBGProtection; ++ ++ // decide to use/change to - ++ // 1. long slot (20 us) or short slot (9 us) time ++ // 2. turn on/off RTS/CTS and/or CTS-to-self protection ++ // 3. short preamble ++ ++ //bUseShortSlot = pAd->CommonCfg.bUseShortSlotTime && CAP_IS_SHORT_SLOT(CapabilityInfo); ++ bUseShortSlot = CAP_IS_SHORT_SLOT(CapabilityInfo); ++ if (bUseShortSlot != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED)) ++ AsicSetSlotTime(pAd, bUseShortSlot); ++ ++ bUseBGProtection = (pAd->CommonCfg.UseBGProtection == 1) || // always use ++ ((pAd->CommonCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp)); ++ ++ if (pAd->CommonCfg.Channel > 14) // always no BG protection in A-band. falsely happened when switching A/G band to a dual-band AP ++ bUseBGProtection = FALSE; ++ ++ if (bUseBGProtection != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ if (bUseBGProtection) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),FALSE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); ++ } ++ else ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),TRUE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); ++ } ++ ++ DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection)); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // check Ht protection mode. and adhere to the Non-GF device indication by AP. ++ if ((AddHtInfoLen != 0) && ++ ((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) || ++ (AddHtInfo.AddHtInfo2.NonGfPresent != pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent))) ++ { ++ pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent = AddHtInfo.AddHtInfo2.NonGfPresent; ++ pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode = AddHtInfo.AddHtInfo2.OperaionMode; ++ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); ++ } ++ else ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) && ++ ERP_IS_USE_BARKER_PREAMBLE(Erp)) ++ { ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP forced to use LONG preamble\n")); ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ (EdcaParm.bValid == TRUE) && ++ (EdcaParm.EdcaUpdateCount != pAd->CommonCfg.APEdcaParm.EdcaUpdateCount)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP change EDCA parameters(from %d to %d)\n", ++ pAd->CommonCfg.APEdcaParm.EdcaUpdateCount, ++ EdcaParm.EdcaUpdateCount)); ++ AsicSetEdcaParm(pAd, &EdcaParm); ++ } ++ ++ // copy QOS related information ++ NdisMoveMemory(&pAd->CommonCfg.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisMoveMemory(&pAd->CommonCfg.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ ++ // only INFRASTRUCTURE mode support power-saving feature ++ if ((INFRA_ON(pAd) && (pAd->StaCfg.Psm == PWR_SAVE)) || (pAd->CommonCfg.bAPSDForcePowerSave)) ++ { ++ UCHAR FreeNumber; ++ // 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL ++ // 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE ++ // 3. we have outgoing frames in TxRing or MgmtRing, better stay AWAKE ++ // 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE ++ // 5. otherwise, put PHY back to sleep to save battery. ++ if (MessageToMe) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && ++ pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) ++ { ++ pAd->CommonCfg.bNeedSendTriggerFrame = TRUE; ++ } ++ else ++ RT28XX_PS_POLL_ENQUEUE(pAd); ++ } ++ else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) ++ { ++ } ++ else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_BE].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_VI].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_VO].Number != 0) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_BK, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_BE, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_VI, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_VO, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_MGMT, MGMT_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS)) ++ { ++ // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme ++ // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? ++ } ++ else ++ { ++ USHORT NextDtim = DtimCount; ++ ++ if (NextDtim == 0) ++ NextDtim = DtimPeriod; ++ ++ TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) ++ TbttNumToNextWakeUp = NextDtim; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ } ++ } ++ } ++ } ++ // not my BSSID, ignore it ++ } ++ // sanity check fail, ignore this frame ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Receive PROBE REQ from remote peer when operating in IBSS mode ++ ========================================================================== ++ */ ++VOID PeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++#ifdef DOT11_N_SUPPORT ++ UCHAR HtLen, AddHtLen, NewExtLen; ++#endif // DOT11_N_SUPPORT // ++ HEADER_802_11 ProbeRspHdr; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ LARGE_INTEGER FakeTimestamp; ++ UCHAR DsLen = 1, IbssLen = 2; ++ UCHAR LocalErpIe[3] = {IE_ERP, 1, 0}; ++ BOOLEAN Privacy; ++ USHORT CapabilityInfo; ++ UCHAR RSNIe = IE_WPA; ++ ++ if (! ADHOC_ON(pAd)) ++ return; ++ ++ if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, Ssid, &SsidLen)) ++ { ++ if ((SsidLen == 0) || SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) ++ { ++ // allocate and send out ProbeRsp frame ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ //pAd->StaCfg.AtimWin = 0; // ?????? ++ ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &ProbeRspHdr, ++ TIMESTAMP_LEN, &FakeTimestamp, ++ 2, &pAd->CommonCfg.BeaconPeriod, ++ 2, &CapabilityInfo, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->StaActive.SupRateLen, ++ pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, ++ 1, &DsIe, ++ 1, &DsLen, ++ 1, &pAd->CommonCfg.Channel, ++ 1, &IbssIe, ++ 1, &IbssLen, ++ 2, &pAd->StaActive.AtimWin, ++ END_OF_ARGS); ++ ++ if (pAd->StaActive.ExtRateLen) ++ { ++ ULONG tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 3, LocalErpIe, ++ 1, &ExtRateIe, ++ 1, &pAd->StaActive.ExtRateLen, ++ pAd->StaActive.ExtRateLen, &pAd->StaActive.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // If adhoc secruity is set for WPA-None, append the cipher suite IE ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ ULONG tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ ULONG TmpLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ HtLen = sizeof(pAd->CommonCfg.HtCapability); ++ AddHtLen = sizeof(pAd->CommonCfg.AddHTInfo); ++ NewExtLen = 1; ++ //New extension channel offset IE is included in Beacon, Probe Rsp or channel Switch Announcement Frame ++ if (pAd->bBroadComHT == TRUE) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ sizeof(HT_CAPABILITY_IE), &pAd->CommonCfg.HtCapability, ++ 1, &AddHtInfoIe, ++ 1, &AddHtLen, ++ sizeof(ADD_HT_INFO_IE), &pAd->CommonCfg.AddHTInfo, ++ 1, &NewExtChanIe, ++ 1, &NewExtLen, ++ sizeof(NEW_EXT_CHAN_IE), &pAd->CommonCfg.NewExtChanOffset, ++ END_OF_ARGS); ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } ++} ++ ++VOID BeaconTimeoutAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BeaconTimeoutAtJoinAction\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan timeout procedure. basically add channel index by 1 and rescan ++ ========================================================================== ++ */ ++VOID ScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ pAd->MlmeAux.Channel = NextChannel(pAd, pAd->MlmeAux.Channel); ++ ++ // Only one channel scanned for CISCO beacon request ++ if ((pAd->MlmeAux.ScanType == SCAN_CISCO_ACTIVE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_PASSIVE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_NOISE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_CHANNEL_LOAD)) ++ pAd->MlmeAux.Channel = 0; ++ ++ // this routine will stop if pAd->MlmeAux.Channel == 0 ++ ScanNextChannel(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AYNC - InvalidStateWhenScan(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenJoin( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenJoin(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenStart( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenStart(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID EnqueuePsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ ++ if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP) ++ pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE; ++ MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID EnqueueProbeRequest( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS NState; ++ PUCHAR pOutBuffer; ++ ULONG FrameLen = 0; ++ HEADER_802_11 Hdr80211; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("force out a ProbeRequest ...\n")); ++ ++ NState = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NState == NDIS_STATUS_SUCCESS) ++ { ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ ++ // this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->StaActive.SupRateLen, ++ pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ ++} ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++VOID BuildEffectedChannelList( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR EChannel[11]; ++ UCHAR i, j, k; ++ UCHAR UpperChannel = 0, LowerChannel = 0; ++ ++ RTMPZeroMemory(EChannel, 11); ++ i = 0; ++ // Find upper channel and lower channel. ++ if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) ++ { ++ UpperChannel = pAd->CommonCfg.Channel; ++ LowerChannel = pAd->CommonCfg.CentralChannel; ++ } ++ else if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) ++ { ++ UpperChannel = pAd->CommonCfg.CentralChannel; ++ LowerChannel = pAd->CommonCfg.Channel; ++ } ++ else ++ { ++ return; ++ } ++ ++ // Record channels that is below lower channel.. ++ if (LowerChannel > 1) ++ { ++ EChannel[0] = LowerChannel - 1; ++ i = 1; ++ if (LowerChannel > 2) ++ { ++ EChannel[1] = LowerChannel - 2; ++ i = 2; ++ if (LowerChannel > 3) ++ { ++ EChannel[2] = LowerChannel - 3; ++ i = 3; ++ } ++ } ++ } ++ // Record channels that is between lower channel and upper channel. ++ for (k = LowerChannel;k < UpperChannel;k++) ++ { ++ EChannel[i] = k; ++ i++; ++ } ++ // Record channels that is above upper channel.. ++ if (LowerChannel < 11) ++ { ++ EChannel[i] = UpperChannel + 1; ++ i++; ++ if (LowerChannel < 10) ++ { ++ EChannel[i] = LowerChannel + 2; ++ i++; ++ if (LowerChannel < 9) ++ { ++ EChannel[i] = LowerChannel + 3; ++ i++; ++ } ++ } ++ } ++ // ++ for (j = 0;j < i;j++) ++ { ++ for (k = 0;k < pAd->ChannelListNum;k++) ++ { ++ if (pAd->ChannelList[k].Channel == EChannel[j]) ++ { ++ pAd->ChannelList[k].bEffectedChannel = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,(" EffectedChannel( =%d)\n", EChannel[j])); ++ break; ++ } ++ } ++ } ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++BOOLEAN ScanRunning( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return (pAd->Mlme.SyncMachine.CurrState == SCAN_LISTEN) ? TRUE : FALSE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/sta/wpa.c +@@ -0,0 +1,2107 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 03-07-22 Initial ++ Paul Lin 03-11-28 Modify for supplicant ++*/ ++#include "../rt_config.h" ++ ++#define WPARSNIE 0xdd ++#define WPA2RSNIE 0x30 ++ ++//extern UCHAR BIT8[]; ++UCHAR CipherWpaPskTkip[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x02 // authentication ++ }; ++UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); ++ ++UCHAR CipherWpaPskAes[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x04, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x04, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x02 // authentication ++ }; ++UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCiscoCCKM[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x40, 0x96, 0x01, // Multicast ++ 0x01, 0x00, // Number of uicast ++ 0x00, 0x40, 0x96, 0x01, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x40, 0x96, 0x00 // Authentication ++ }; ++UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCiscoCCKM24[] = { ++ 0xDD, 0x18, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x40, 0x96, 0x01, // Multicast ++ 0x01, 0x00, // Number of uicast ++ 0x00, 0x40, 0x96, 0x01, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x40, 0x96, 0x00, ++ 0x28, 0x00// Authentication ++ }; ++ ++UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCCXTkip[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x01 // authentication ++ }; ++UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR)); ++ ++UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; ++UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; ++ ++UCHAR EAPOL_FRAME[] = {0x88, 0x8E}; ++ ++BOOLEAN CheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ OUT UCHAR *Offset); ++ ++void inc_byte_array(UCHAR *counter, int len); ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Classify WPA EAP message type ++ ++ Arguments: ++ EAPType Value of EAP message type ++ MsgType Internal Message definition for MLME state machine ++ ++ Return Value: ++ TRUE Found appropriate message type ++ FALSE No appropriate message type ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ All these constants are defined in wpa.h ++ For supplicant, there is only EAPOL Key message avaliable ++ ++ ======================================================================== ++*/ ++BOOLEAN WpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType) ++{ ++ switch (EAPType) ++ { ++ case EAPPacket: ++ *MsgType = MT2_EAPPacket; ++ break; ++ case EAPOLStart: ++ *MsgType = MT2_EAPOLStart; ++ break; ++ case EAPOLLogoff: ++ *MsgType = MT2_EAPOLLogoff; ++ break; ++ case EAPOLKey: ++ *MsgType = MT2_EAPOLKey; ++ break; ++ case EAPOLASFAlert: ++ *MsgType = MT2_EAPOLASFAlert; ++ break; ++ default: ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ========================================================================== ++ */ ++VOID WpaPskStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); ++ StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This is state machine function. ++ When receiving EAPOL packets which is for 802.1x key management. ++ Use both in WPA, and WPAPSK case. ++ In this function, further dispatch to different functions according to the received packet. 3 categories are : ++ 1. normal 4-way pairwisekey and 2-way groupkey handshake ++ 2. MIC error (Countermeasures attack) report packet from STA. ++ 3. Request for pairwise/group key update from STA ++ Return: ++ ========================================================================== ++*/ ++VOID WpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ INT MsgType = EAPOL_MSG_INVALID; ++ PKEY_DESCRIPTER pKeyDesc; ++ PHEADER_802_11 pHeader; //red ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ UCHAR EapolVr; ++ KEY_INFO peerKeyInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n")); ++ ++ // Get 802.11 header first ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Get EAPoL-Key Descriptor ++ pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo)); ++ ++ ++ // 1. Check EAPOL frame version and type ++ EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H]; ++ ++ if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n")); ++ return; ++ } ++ ++ // First validate replay counter, only accept message with larger replay counter ++ // Let equal pass, some AP start with all zero replay counter ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ ++ if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n")); ++ return; ++ } ++ ++ // Process WPA2PSK frame ++ if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.EKD_DL == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 0) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); ++ } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.EKD_DL == 1) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_3; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); ++ } else if((peerKeyInfo.KeyType == GROUPKEY) && ++ (peerKeyInfo.EKD_DL == 1) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_GROUP_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); ++ } ++ ++ // We will assume link is up (assoc suceess and port not secured). ++ // All state has to be able to process message from previous state ++ switch(pAd->StaCfg.WpaState) ++ { ++ case SS_START: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ break; ++ ++ case SS_WAIT_MSG_3: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ Wpa2PairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ break; ++ ++ case SS_WAIT_GROUP: // When doing group key exchange ++ case SS_FINISH: // This happened when update group key ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ Wpa2PairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ else if(MsgType == EAPOL_GROUP_MSG_1) ++ { ++ WpaGroupMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ // Process WPAPSK Frame ++ // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant ++ else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.KeyIndex == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 0) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); ++ } ++ else if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.KeyIndex == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_3; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); ++ } ++ else if((peerKeyInfo.KeyType == GROUPKEY) && ++ (peerKeyInfo.KeyIndex != 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_GROUP_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); ++ } ++ ++ // We will assume link is up (assoc suceess and port not secured). ++ // All state has to be able to process message from previous state ++ switch(pAd->StaCfg.WpaState) ++ { ++ case SS_START: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ break; ++ ++ case SS_WAIT_MSG_3: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ WpaPairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ break; ++ ++ case SS_WAIT_GROUP: // When doing group key exchange ++ case SS_FINISH: // This happened when update group key ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ WpaPairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ } ++ else if(MsgType == EAPOL_GROUP_MSG_1) ++ { ++ WpaGroupMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Pairwise key 4-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaPairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PHEADER_802_11 pHeader; ++ UCHAR *mpool, *PTK, *digest; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ PEAPOL_PACKET pMsg1; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n")); ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); ++ ++ if (mpool == NULL) ++ return; ++ ++ // PTK Len = 80. ++ PTK = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(PTK + 80, 4); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 1 from authenticator ++ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ // 1. Save Replay counter, it will use to verify message 3 and construct message 2 ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Save ANonce ++ NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Generate random SNonce ++ GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); ++ ++ // Calc PTK(ANonce, SNonce) ++ WpaCountPTK(pAd, ++ pAd->StaCfg.PMK, ++ pAd->StaCfg.ANonce, ++ pAd->CommonCfg.Bssid, ++ pAd->StaCfg.SNonce, ++ pAd->CurrentAddress, ++ PTK, ++ LEN_PTK); ++ ++ // Save key to PTK entry ++ NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Message 2 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ // ++ // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ // 1. Key descriptor version and appropriate RSN IE ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ // fill in Data Material and its length ++ Packet.KeyDesc.KeyData[0] = IE_WPA; ++ Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; ++ Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; ++ ++ // Update Key length ++ Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; ++ // 2. Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // 3. KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ //Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ ++ // 4. Fill SNonce ++ NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); ++ ++ // 5. Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE) ++ // Out buffer for transmitting message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, mpool); ++ return; ++ } ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // 6. Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ ++ HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring and send Msg 2 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n")); ++} ++ ++VOID Wpa2PairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PHEADER_802_11 pHeader; ++ UCHAR *mpool, *PTK, *digest; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ PEAPOL_PACKET pMsg1; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n")); ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); ++ ++ if (mpool == NULL) ++ return; ++ ++ // PTK Len = 80. ++ PTK = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(PTK + 80, 4); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 1 from authenticator ++ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ // 1. Save Replay counter, it will use to verify message 3 and construct message 2 ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Save ANonce ++ NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Generate random SNonce ++ GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); ++ ++ if(pMsg1->KeyDesc.KeyDataLen[1] > 0 ) ++ { ++ // cached PMKID ++ } ++ ++ // Calc PTK(ANonce, SNonce) ++ WpaCountPTK(pAd, ++ pAd->StaCfg.PMK, ++ pAd->StaCfg.ANonce, ++ pAd->CommonCfg.Bssid, ++ pAd->StaCfg.SNonce, ++ pAd->CurrentAddress, ++ PTK, ++ LEN_PTK); ++ ++ // Save key to PTK entry ++ NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message 2 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ // ++ // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ ++ // 1. Key descriptor version and appropriate RSN IE ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ // fill in Data Material and its length ++ Packet.KeyDesc.KeyData[0] = IE_WPA2; ++ Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; ++ Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; ++ ++ // 2. Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // 3. KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = 0; ++ Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; ++ ++ // 4. Fill SNonce ++ NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); ++ ++ // 5. Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // Out buffer for transmitting message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // 6. Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ ++ // Make Transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ os_free_mem(pAd, mpool); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n")); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Pairwise key 4-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaPairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PHEADER_802_11 pHeader; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pMsg3; ++ UCHAR Mic[16], OldMic[16]; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ UCHAR skip_offset; ++ KEY_INFO peerKeyInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n")); ++ ++ // Record 802.11 header & the received EAPOL packet Msg3 ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ ++ // 1. Verify cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) ++ { ++ return; ++ } ++ else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ return; ++ } ++ ++ // Verify RSN IE ++ //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) ++ if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n")); ++ hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); ++ hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n")); ++ ++ ++ // 2. Check MIC value ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ UCHAR digest[80]; ++ ++ HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else // TKIP ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ ++ // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ return; ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 4. Double check ANonce ++ if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) ++ return; ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Message 4 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) ++ // ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; ++ ++ // Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS ++ // Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3 ++ Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting message 4 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ return; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ UCHAR digest[80]; ++ ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ // Update PTK ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ // Make transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // Copy frame to Tx ring and Send Message 4 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n")); ++} ++ ++VOID Wpa2PairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PHEADER_802_11 pHeader; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pMsg3; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR *mpool, *KEYDATA, *digest; ++ UCHAR Key[32]; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ KEY_INFO peerKeyInfo; ++ ++ // allocate memory ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); ++ ++ if(mpool == NULL) ++ return; ++ ++ // KEYDATA Len = 512. ++ KEYDATA = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n")); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 3 frame. ++ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ // 1. Verify cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // 2. Check MIC value ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ ++ // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 4. Double check ANonce ++ if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Obtain GTK ++ // 5. Decrypt GTK from Key Data ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // Decrypt AES GTK ++ AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData); ++ } ++ else // TKIP ++ { ++ INT i; ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); ++ } ++ ++ if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update GTK to ASIC ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message 4 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) ++ // ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; ++ ++ // Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting message 4 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ // Update PTK ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ // Make Transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // Copy frame to Tx ring and Send Message 4 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ ++ // send wireless event - for set key done WPA2 ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n")); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Group key 2-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaGroupMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pGroup; ++ UCHAR *mpool, *digest, *KEYDATA; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR GTK[32], Key[32]; ++ KEY_INFO peerKeyInfo; ++ ++ // allocate memory ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); ++ ++ if(mpool == NULL) ++ return; ++ ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(mpool, 4); ++ // KEYDATA Len = 512. ++ KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n")); ++ ++ // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) ++ pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ // 0. Check cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // 1. Verify Replay counter ++ // Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Verify MIC is valid ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n")); ++ MlmeFreeMemory(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n")); ++ ++ ++ // 3. Decrypt GTK from Key Data ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // Decrypt AES GTK ++ AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData); ++ } ++ else // TKIP ++ { ++ INT i; ++ ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]); ++ } ++ ++ // Process decrypted key data material ++ // Parse keyData to handle KDE format for WPA2PSK ++ if (peerKeyInfo.EKD_DL) ++ { ++ if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ } ++ else // WPAPSK ++ { ++ // set key material, TxMic and RxMic for WPAPSK ++ NdisMoveMemory(GTK, KEYDATA, 32); ++ NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32); ++ pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex; ++ ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, >K[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, >K[24], LEN_TKIP_TXMICK); ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; ++ ++ //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); ++ } ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ ++ // init header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Group message 1 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) ++ // ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ else ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1]; ++ ++ // Key Index as G-Msg 1 ++ if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex; ++ ++ // Key Type Group key ++ Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Secure bit ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting group message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ MlmeFreeMemory(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring and prepare for encryption ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); ++ ++ // 6 Free allocated memory ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ // send wireless event - for set key done WPA2 ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init WPA MAC header ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr1) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.ToDs = 1; ++ if (wep == 1) ++ pHdr80211->FC.Wep = 1; ++ ++ // Addr1: BSSID, Addr2: SA, Addr3: DA ++ COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1); ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid); ++ pHdr80211->Sequence = pAd->Sequence; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware encryption before really ++ sent out to air. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to outgoing Ndis frame ++ NumberOfFrag Number of fragment required ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN is4wayFrame) ++ ++{ ++ NDIS_STATUS Status; ++ PNDIS_PACKET pPacket; ++ UCHAR Index; ++ ++ do ++ { ++ // 1. build a NDIS packet and call RTMPSendPacket(); ++ // be careful about how/when to release this internal allocated NDIS PACKET buffer ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ if (is4wayFrame) ++ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1); ++ else ++ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0); ++ ++ // 2. send out the packet ++ Status = STASendPacket(pAd, pPacket); ++ if(Status == NDIS_STATUS_SUCCESS) ++ { ++ // Dequeue one frame from TxSwQueue0..3 queue and process it ++ // There are three place calling dequeue for TX ring. ++ // 1. Here, right after queueing the frame. ++ // 2. At the end of TxRingTxDone service routine. ++ // 3. Upon NDIS call RTMPSendPackets ++ if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) ++ { ++ for(Index = 0; Index < 5; Index ++) ++ if(pAd->TxSwQueue[Index].Number > 0) ++ RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS); ++ } ++ } ++ } while(FALSE); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Sanity RSN IE form AP ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ ======================================================================== ++*/ ++BOOLEAN CheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ OUT UCHAR *Offset) ++{ ++ PUCHAR pVIE; ++ UCHAR len; ++ PEID_STRUCT pEid; ++ BOOLEAN result = FALSE; ++ ++ pVIE = pData; ++ len = DataLen; ++ *Offset = 0; ++ ++ while (len > sizeof(RSNIE2)) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // WPA RSN IE ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && ++ (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && ++ (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ // WPA2 RSN IE ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) && ++ (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && ++ (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ else ++ { ++ break; ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset)); ++ ++ return result; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. ++ GTK is encaptulated in KDE format at p.83 802.11i D10 ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ 802.11i D10 ++ ++ ======================================================================== ++*/ ++BOOLEAN ParseKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR bPairewise) ++{ ++ PKDE_ENCAP pKDE = NULL; ++ PUCHAR pMyKeyData = pKeyData; ++ UCHAR KeyDataLength = KeyDataLen; ++ UCHAR GTKLEN; ++ UCHAR skip_offset; ++ ++ // Verify The RSN IE contained in Pairewise-Msg 3 and skip it ++ if (bPairewise) ++ { ++ // Check RSN IE whether it is WPA2/WPA2PSK ++ if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n")); ++ hex_dump("Get KEYDATA :", pKeyData, KeyDataLen); ++ return FALSE; ++ } ++ else ++ { ++ // skip RSN IE ++ pMyKeyData += skip_offset; ++ KeyDataLength -= skip_offset; ++ ++ //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); ++ ++ // Parse EKD format ++ if (KeyDataLength >= 8) ++ { ++ pKDE = (PKDE_ENCAP) pMyKeyData; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n")); ++ return FALSE; ++ } ++ ++ ++ // Sanity check - shared key index should not be 0 ++ if (pKDE->GTKEncap.Kid == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n")); ++ return FALSE; ++ } ++ ++ // Sanity check - KED length ++ if (KeyDataLength < (pKDE->Len + 2)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); ++ return FALSE; ++ } ++ ++ // Get GTK length - refer to IEEE 802.11i-2004 p.82 ++ GTKLEN = pKDE->Len -6; ++ ++ if (GTKLEN < MIN_LEN_OF_GTK) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); ++ return FALSE; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN)); ++ ++ // Update GTK ++ // set key material, TxMic and RxMic for WPAPSK ++ NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32); ++ pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid; ++ ++ // Update shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK); ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; ++ ++ return TRUE; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Cisco CCKM PRF function ++ ++ Arguments: ++ key Cisco Base Transient Key (BTK) ++ key_len The key length of the BTK ++ data Ruquest Number(RN) + BSSID ++ data_len The length of the data ++ output Store for PTK(Pairwise transient keys) ++ len The length of the output ++ Return Value: ++ None ++ ++ Note: ++ 802.1i Annex F.9 ++ ++ ======================================================================== ++*/ ++VOID CCKMPRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len) ++{ ++ INT i; ++ UCHAR input[1024]; ++ INT currentindex = 0; ++ INT total_len; ++ ++ NdisMoveMemory(input, data, data_len); ++ total_len = data_len; ++ input[total_len] = 0; ++ total_len++; ++ for (i = 0; i < (len + 19) / 20; i++) ++ { ++ HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); ++ currentindex += 20; ++ input[total_len - 1]++; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process MIC error indication and record MIC error timer. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pWpaKey Pointer to the WPA key structure ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReportMicError( ++ IN PRTMP_ADAPTER pAd, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ ULONG Now; ++ UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0); ++ ++ // Record Last MIC error time and count ++ Now = jiffies; ++ if (pAd->StaCfg.MicErrCnt == 0) ++ { ++ pAd->StaCfg.MicErrCnt++; ++ pAd->StaCfg.LastMicErrorTime = Now; ++ NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); ++ } ++ else if (pAd->StaCfg.MicErrCnt == 1) ++ { ++ if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) ++ { ++ // Update Last MIC error time, this did not violate two MIC errors within 60 seconds ++ pAd->StaCfg.LastMicErrorTime = Now; ++ } ++ else ++ { ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ pAd->StaCfg.LastMicErrorTime = Now; ++ // Violate MIC error counts, MIC countermeasures kicks in ++ pAd->StaCfg.MicErrCnt++; ++ // We shall block all reception ++ // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame ++ // ++ // No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets ++ // if pAd->StaCfg.MicErrCnt greater than 2. ++ // ++ // RTMPRingCleanUp(pAd, QID_AC_BK); ++ // RTMPRingCleanUp(pAd, QID_AC_BE); ++ // RTMPRingCleanUp(pAd, QID_AC_VI); ++ // RTMPRingCleanUp(pAd, QID_AC_VO); ++ // RTMPRingCleanUp(pAd, QID_HCCA); ++ } ++ } ++ else ++ { ++ // MIC error count >= 2 ++ // This should not happen ++ ; ++ } ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_MIC_FAILURE_REPORT_FRAME, ++ 1, ++ &unicastKey); ++ ++ if (pAd->StaCfg.MicErrCnt == 2) ++ { ++ RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); ++ } ++} ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#define LENGTH_EAP_H 4 ++// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). ++INT WpaCheckEapCode( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFrame, ++ IN USHORT FrameLen, ++ IN USHORT OffSet) ++{ ++ ++ PUCHAR pData; ++ INT result = 0; ++ ++ if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H ) ++ return result; ++ ++ pData = pFrame + OffSet; // skip offset bytes ++ ++ if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type ++ { ++ result = *(pData+4); // EAP header - Code ++ } ++ ++ return result; ++} ++ ++VOID WpaSendMicFailureToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUnicast) ++{ ++ union iwreq_data wrqu; ++ char custom[IW_CUSTOM_MAX] = {0}; ++ ++ sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); ++ if (bUnicast) ++ sprintf(custom, "%s unicast", custom); ++ wrqu.data.length = strlen(custom); ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ ++ return; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++VOID WpaMicFailureReportFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ BOOLEAN bUnicast; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); ++ ++ bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE); ++ pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Request field presented ++ Packet.KeyDesc.KeyInfo.Request = 1; ++ ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Error field presented ++ Packet.KeyDesc.KeyInfo.Error = 1; ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; ++ ++ // Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ inc_byte_array(pAd->StaCfg.ReplayCounter, 8); ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ UCHAR digest[20] = {0}; ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // opy frame to Tx ring and send MIC failure report frame to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); ++} ++ ++/** from wpa_supplicant ++ * inc_byte_array - Increment arbitrary length byte array by one ++ * @counter: Pointer to byte array ++ * @len: Length of the counter in bytes ++ * ++ * This function increments the last byte of the counter by one and continues ++ * rolling over to more significant bytes if the byte was incremented from ++ * 0xff to 0x00. ++ */ ++void inc_byte_array(UCHAR *counter, int len) ++{ ++ int pos = len - 1; ++ while (pos >= 0) { ++ counter[pos]++; ++ if (counter[pos] != 0) ++ break; ++ pos--; ++ } ++} ++ ++VOID WpaDisassocApAndBlockAssoc( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ++ // disassoc from current AP first ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ pAd->StaCfg.bBlockAssoc = TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt2870/tmp60 +@@ -0,0 +1,7037 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sta_ioctl.c ++ ++ Abstract: ++ IOCTL related subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 01-03-2003 created ++ Rory Chen 02-14-2005 modify to support RT61 ++*/ ++ ++#include "rt_config.h" ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++#endif ++ ++#define NR_WEP_KEYS 4 ++#define WEP_SMALL_KEY_LEN (40/8) ++#define WEP_LARGE_KEY_LEN (104/8) ++ ++#define GROUP_KEY_NO 4 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) ++#else ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) ++#endif ++ ++extern UCHAR CipherWpa2Template[]; ++extern UCHAR CipherWpaPskTkip[]; ++extern UCHAR CipherWpaPskTkipLen; ++ ++typedef struct PACKED _RT_VERSION_INFO{ ++ UCHAR DriverVersionW; ++ UCHAR DriverVersionX; ++ UCHAR DriverVersionY; ++ UCHAR DriverVersionZ; ++ UINT DriverBuildYear; ++ UINT DriverBuildMonth; ++ UINT DriverBuildDay; ++} RT_VERSION_INFO, *PRT_VERSION_INFO; ++ ++struct iw_priv_args privtab[] = { ++{ RTPRIV_IOCTL_SET, ++ IW_PRIV_TYPE_CHAR | 1024, 0, ++ "set"}, ++ ++{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++/* --- sub-ioctls definitions --- */ ++ { SHOW_CONN_STATUS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, ++ { SHOW_DRVIER_VERION, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, ++ { SHOW_BA_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, ++ { SHOW_DESC_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, ++ { RAIO_OFF, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, ++ { RAIO_ON, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, ++#ifdef QOS_DLS_SUPPORT ++ { SHOW_DLS_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, ++#endif // QOS_DLS_SUPPORT // ++ { SHOW_CFG_VALUE, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, ++ { SHOW_ADHOC_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, ++ ++/* --- sub-ioctls relations --- */ ++ ++#ifdef DBG ++{ RTPRIV_IOCTL_BBP, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "bbp"}, ++{ RTPRIV_IOCTL_MAC, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "mac"}, ++{ RTPRIV_IOCTL_E2P, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "e2p"}, ++#endif /* DBG */ ++ ++{ RTPRIV_IOCTL_STATISTICS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "stat"}, ++{ RTPRIV_IOCTL_GSITESURVEY, ++ 0, IW_PRIV_TYPE_CHAR | 1024, ++ "get_site_survey"}, ++}; ++ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WMM_SUPPORT ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++VOID RTMPIoctlBBP( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++#endif // DBG // ++ ++ ++NDIS_STATUS RTMPWPANoneAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++INT Set_FragTest_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++INT Show_Adhoc_MacTable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PCHAR extra); ++ ++static struct { ++ CHAR *name; ++ INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { ++ {"DriverVersion", Set_DriverVersion_Proc}, ++ {"CountryRegion", Set_CountryRegion_Proc}, ++ {"CountryRegionABand", Set_CountryRegionABand_Proc}, ++ {"SSID", Set_SSID_Proc}, ++ {"WirelessMode", Set_WirelessMode_Proc}, ++ {"TxBurst", Set_TxBurst_Proc}, ++ {"TxPreamble", Set_TxPreamble_Proc}, ++ {"TxPower", Set_TxPower_Proc}, ++ {"Channel", Set_Channel_Proc}, ++ {"BGProtection", Set_BGProtection_Proc}, ++ {"RTSThreshold", Set_RTSThreshold_Proc}, ++ {"FragThreshold", Set_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Set_HtBw_Proc}, ++ {"HtMcs", Set_HtMcs_Proc}, ++ {"HtGi", Set_HtGi_Proc}, ++ {"HtOpMode", Set_HtOpMode_Proc}, ++ {"HtExtcha", Set_HtExtcha_Proc}, ++ {"HtMpduDensity", Set_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Set_HtBaWinSize_Proc}, ++ {"HtRdg", Set_HtRdg_Proc}, ++ {"HtAmsdu", Set_HtAmsdu_Proc}, ++ {"HtAutoBa", Set_HtAutoBa_Proc}, ++ {"HtBaDecline", Set_BADecline_Proc}, ++ {"HtProtect", Set_HtProtect_Proc}, ++ {"HtMimoPs", Set_HtMimoPs_Proc}, ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Set_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Set_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Set_IEEE80211H_Proc}, ++ {"NetworkType", Set_NetworkType_Proc}, ++ {"AuthMode", Set_AuthMode_Proc}, ++ {"EncrypType", Set_EncrypType_Proc}, ++ {"DefaultKeyID", Set_DefaultKeyID_Proc}, ++ {"Key1", Set_Key1_Proc}, ++ {"Key2", Set_Key2_Proc}, ++ {"Key3", Set_Key3_Proc}, ++ {"Key4", Set_Key4_Proc}, ++ {"WPAPSK", Set_WPAPSK_Proc}, ++ {"ResetCounter", Set_ResetStatCounter_Proc}, ++ {"PSMode", Set_PSMode_Proc}, ++#ifdef DBG ++ {"Debug", Set_Debug_Proc}, ++#endif ++ ++#ifdef RALINK_ATE ++ {"ATE", Set_ATE_Proc}, ++ {"ATEDA", Set_ATE_DA_Proc}, ++ {"ATESA", Set_ATE_SA_Proc}, ++ {"ATEBSSID", Set_ATE_BSSID_Proc}, ++ {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, ++ {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, ++ {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, ++ {"ATETXANT", Set_ATE_TX_Antenna_Proc}, ++ {"ATERXANT", Set_ATE_RX_Antenna_Proc}, ++ {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, ++ {"ATETXBW", Set_ATE_TX_BW_Proc}, ++ {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, ++ {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, ++ {"ATETXMCS", Set_ATE_TX_MCS_Proc}, ++ {"ATETXMODE", Set_ATE_TX_MODE_Proc}, ++ {"ATETXGI", Set_ATE_TX_GI_Proc}, ++ {"ATERXFER", Set_ATE_RX_FER_Proc}, ++ {"ATERRF", Set_ATE_Read_RF_Proc}, ++ {"ATEWRF1", Set_ATE_Write_RF1_Proc}, ++ {"ATEWRF2", Set_ATE_Write_RF2_Proc}, ++ {"ATEWRF3", Set_ATE_Write_RF3_Proc}, ++ {"ATEWRF4", Set_ATE_Write_RF4_Proc}, ++ {"ATELDE2P", Set_ATE_Load_E2P_Proc}, ++ {"ATERE2P", Set_ATE_Read_E2P_Proc}, ++ {"ATESHOW", Set_ATE_Show_Proc}, ++ {"ATEHELP", Set_ATE_Help_Proc}, ++ ++#ifdef RALINK_28xx_QA ++ {"TxStop", Set_TxStop_Proc}, ++ {"RxStop", Set_RxStop_Proc}, ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ {"WpaSupport", Set_Wpa_Support}, ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++ {"FixedTxMode", Set_FixedTxMode_Proc}, ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ {"OpMode", Set_OpMode_Proc}, ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++#ifdef DOT11_N_SUPPORT ++ {"TGnWifiTest", Set_TGnWifiTest_Proc}, ++ {"ForceGF", Set_ForceGF_Proc}, ++#endif // DOT11_N_SUPPORT // ++#ifdef QOS_DLS_SUPPORT ++ {"DlsAddEntry", Set_DlsAddEntry_Proc}, ++ {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, ++#endif // QOS_DLS_SUPPORT // ++ {"LongRetry", Set_LongRetryLimit_Proc}, ++ {"ShortRetry", Set_ShortRetryLimit_Proc}, ++#ifdef EXT_BUILD_CHANNEL_LIST ++ {"11dClientMode", Set_Ieee80211dClientMode_Proc}, ++#endif // EXT_BUILD_CHANNEL_LIST // ++#ifdef CARRIER_DETECTION_SUPPORT ++ {"CarrierDetect", Set_CarrierDetect_Proc}, ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ {NULL,} ++}; ++ ++ ++VOID RTMPAddKey( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_802_11_KEY pKey) ++{ ++ ULONG KeyIdx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ NdisZeroMemory(pAd->StaCfg.PMK, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); ++ goto end; ++ } ++ // Update PTK ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else ++ { ++ // Update GTK ++ pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else // dynamic WEP from wpa_supplicant ++ { ++ UCHAR CipherAlg; ++ PUCHAR Key; ++ ++ if(pKey->KeyLength == 32) ++ goto end; ++ ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ ++ if (KeyIdx < 4) ++ { ++ // it is a default shared key, for Pairwise key setting ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ pEntry = MacTableLookup(pAd, pKey->BSSID); ++ ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); ++ ++ // set key material and key length ++ pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // set Cipher type ++ if (pKey->KeyLength == 5) ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; ++ else ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; ++ ++ // Add Pair-wise key to Asic ++ AsicAddPairwiseKeyEntry( ++ pAd, ++ pEntry->Addr, ++ (UCHAR)pEntry->Aid, ++ &pEntry->PairwiseKey); ++ ++ // update WCID attribute table and IVEIV table for this entry ++ RTMPAddWcidAttributeEntry( ++ pAd, ++ BSS0, ++ KeyIdx, // The value may be not zero ++ pEntry->PairwiseKey.CipherAlg, ++ pEntry); ++ ++ } ++ } ++ else ++ { ++ // Default key for tx (shared key) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ ++ // set key material and key length ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // Set Ciper type ++ if (pKey->KeyLength == 5) ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; ++ else ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ } ++ } ++ } ++end: ++ return; ++} ++ ++char * rtstrchr(const char * s, int c) ++{ ++ for(; *s != (char) c; ++s) ++ if (*s == '\0') ++ return NULL; ++ return (char *) s; ++} ++ ++/* ++This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function ++*/ ++ ++int ++rt_ioctl_giwname(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++#ifdef RT2870 ++ strncpy(name, "RT2870 Wireless", IFNAMSIZ); ++#endif // RT2870 // ++ return 0; ++} ++ ++int rt_ioctl_siwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int chan = -1; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ ++ if (freq->e > 1) ++ return -EINVAL; ++ ++ if((freq->e == 0) && (freq->m <= 1000)) ++ chan = freq->m; // Setting by channel number ++ else ++ MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, ++ ++ if (ChannelSanity(pAdapter, chan) == TRUE) ++ { ++ pAdapter->CommonCfg.Channel = chan; ++ DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); ++ } ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++int rt_ioctl_giwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter = NULL; ++ UCHAR ch; ++ ULONG m; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ch = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); ++ ++ MAP_CHANNEL_ID_TO_KHZ(ch, m); ++ freq->m = m * 100; ++ freq->e = 1; ++ return 0; ++} ++ ++int rt_ioctl_siwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (*mode) ++ { ++ case IW_MODE_ADHOC: ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ break; ++ case IW_MODE_INFRA: ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ break; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ case IW_MODE_MONITOR: ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ break; ++#endif ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); ++ return -EINVAL; ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (ADHOC_ON(pAdapter)) ++ *mode = IW_MODE_ADHOC; ++ else if (INFRA_ON(pAdapter)) ++ *mode = IW_MODE_INFRA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ else if (MONITOR_ON(pAdapter)) ++ { ++ *mode = IW_MODE_MONITOR; ++ } ++#endif ++ else ++ *mode = IW_MODE_AUTO; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); ++ return 0; ++} ++ ++int rt_ioctl_siwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ return 0; ++} ++ ++int rt_ioctl_giwrange(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ struct iw_range *range = (struct iw_range *) extra; ++ u16 val; ++ int i; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_DBM; ++ ++ if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) ++ { ++ range->min_pmp = 1 * 1024; ++ range->max_pmp = 65535 * 1024; ++ range->min_pmt = 1 * 1024; ++ range->max_pmt = 1000 * 1024; ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_TIMEOUT; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | ++ IW_POWER_UNICAST_R | IW_POWER_ALL_R; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 14; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = pAdapter->ChannelListNum; ++ ++ val = 0; ++ for (i = 1; i <= range->num_channels; i++) ++ { ++ u32 m; ++ range->freq[val].i = pAdapter->ChannelList[i-1].Channel; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); ++ range->freq[val].m = m * 100; /* HZ */ ++ ++ range->freq[val].e = 1; ++ val++; ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ range->num_frequency = val; ++ ++ range->max_qual.qual = 100; /* what is correct max? This was not ++ * documented exactly. At least ++ * 69 has been observed. */ ++ range->max_qual.level = 0; /* dB */ ++ range->max_qual.noise = 0; /* dB */ ++ ++ /* What would be suitable values for "average/typical" qual? */ ++ range->avg_qual.qual = 20; ++ range->avg_qual.level = -60; ++ range->avg_qual.noise = -95; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = NR_WEP_KEYS; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++#if WIRELESS_EXT > 17 ++ /* IW_ENC_CAPA_* bit field */ ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ return 0; ++} ++ ++int rt_ioctl_siwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ memset(Bssid, 0, MAC_ADDR_LEN); ++ memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ ++ return 0; ++} ++ ++int rt_ioctl_giwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); ++ return -ENOTCONN; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Units are in db above the noise floor. That means the ++ * rssi values reported in the tx/rx descriptors in the ++ * driver are the SNR expressed in db. ++ * ++ * If you assume that the noise floor is -95, which is an ++ * excellent assumption 99.5 % of the time, then you can ++ * derive the absolute signal level (i.e. -95 + rssi). ++ * There are some other slight factors to take into account ++ * depending on whether the rssi measurement is from 11b, ++ * 11g, or 11a. These differences are at most 2db and ++ * can be documented. ++ * ++ * NB: various calculations are based on the orinoco/wavelan ++ * drivers for compatibility ++ */ ++static void set_quality(PRTMP_ADAPTER pAdapter, ++ struct iw_quality *iq, ++ signed char rssi) ++{ ++ __u8 ChannelQuality; ++ ++ // Normalize Rssi ++ if (rssi >= -50) ++ ChannelQuality = 100; ++ else if (rssi >= -80) // between -50 ~ -80dbm ++ ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); ++ else if (rssi >= -90) // between -80 ~ -90dbm ++ ChannelQuality = (__u8)((rssi + 90) * 26)/10; ++ else ++ ChannelQuality = 0; ++ ++ iq->qual = (__u8)ChannelQuality; ++ ++ iq->level = (__u8)(rssi); ++ iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) ++ iq->noise += 256 - 143; ++ iq->updated = pAdapter->iw_stats.qual.updated; ++} ++ ++int rt_ioctl_iwaplist(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ struct sockaddr addr[IW_MAX_AP]; ++ struct iw_quality qual[IW_MAX_AP]; ++ int i; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ data->length = 0; ++ return 0; ++ //return -ENETDOWN; ++ } ++ ++ for (i = 0; i = pAdapter->ScanTab.BssNr) ++ break; ++ addr[i].sa_family = ARPHRD_ETHER; ++ memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); ++ } ++ data->length = i; ++ memcpy(extra, &addr, i*sizeof(addr[0])); ++ data->flags = 1; /* signal quality present (sort of) */ ++ memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); ++ ++ return 0; ++} ++ ++#ifdef SIOCGIWSCAN ++int rt_ioctl_siwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ULONG Now; ++ int Status = NDIS_STATUS_SUCCESS; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ return -EINVAL; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount++; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return 0; ++ do{ ++ Now = jiffies; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && ++ (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ RT28XX_MLME_HANDLER(pAdapter); ++ }while(0); ++ return 0; ++} ++ ++int rt_ioctl_giwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int i=0; ++ char *current_ev = extra, *previous_ev = extra; ++ char *end_buf; ++ char *current_val, custom[MAX_CUSTOM_LEN] = {0}; ++#ifndef IWEVGENIE ++ char idx; ++#endif // IWEVGENIE // ++ struct iw_event iwe; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ return -EAGAIN; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount = 0; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if (pAdapter->ScanTab.BssNr == 0) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++#if WIRELESS_EXT >= 17 ++ if (data->length > 0) ++ end_buf = extra + data->length; ++ else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#endif ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ if (current_ev >= end_buf) ++ { ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //MAC address ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //ESSID ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ iwe.u.data.flags = 1; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Network Type ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) ++ { ++ iwe.u.mode = IW_MODE_ADHOC; ++ } ++ else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) ++ { ++ iwe.u.mode = IW_MODE_INFRA; ++ } ++ else ++ { ++ iwe.u.mode = IW_MODE_AUTO; ++ } ++ iwe.len = IW_EV_UINT_LEN; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Channel and Frequency ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ else ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Add quality statistics ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.level = 0; ++ iwe.u.qual.noise = 0; ++ set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Encyption key ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) ++ iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Bit Rate ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].SupRateLen) ++ { ++ UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWRATE; ++ current_val = current_ev + IW_EV_LCP_LEN; ++ if (tmpRate == 0x82) ++ iwe.u.bitrate.value = 1 * 1000000; ++ else if (tmpRate == 0x84) ++ iwe.u.bitrate.value = 2 * 1000000; ++ else if (tmpRate == 0x8B) ++ iwe.u.bitrate.value = 5.5 * 1000000; ++ else if (tmpRate == 0x96) ++ iwe.u.bitrate.value = 11 * 1000000; ++ else ++ iwe.u.bitrate.value = (tmpRate/2) * 1000000; ++ ++ iwe.u.bitrate.disabled = 0; ++ current_val = IWE_STREAM_ADD_VALUE(info, current_ev, ++ current_val, end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ ++ if((current_val-current_ev)>IW_EV_LCP_LEN) ++ current_ev = current_val; ++ else ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++#ifdef IWEVGENIE ++ //WPA IE ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#else ++ //WPA IE ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "wpa_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "rsn_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#endif // IWEVGENIE // ++ } ++ ++ data->length = current_ev - extra; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); ++ return 0; ++} ++#endif ++ ++int rt_ioctl_siwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->flags) ++ { ++ PCHAR pSsidString = NULL; ++ ++ // Includes null character. ++ if (data->length > (IW_ESSID_MAX_SIZE + 1)) ++ return -E2BIG; ++ ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, essid, data->length); ++ if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) ++ return -EINVAL; ++ } ++ else ++ return -ENOMEM; ++ } ++ else ++ { ++ // ANY ssid ++ if (Set_SSID_Proc(pAdapter, "") == FALSE) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int rt_ioctl_giwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ data->flags = 1; ++ if (MONITOR_ON(pAdapter)) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#ifdef RT2870 ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // RT2870 // ++ else ++ {//the ANY ssid was specified ++ data->length = 0; ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); ++ } ++ ++ return 0; ++ ++} ++ ++int rt_ioctl_siwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->length > IW_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); ++ memcpy(pAdapter->nickname, nickname, data->length); ++ ++ ++ return 0; ++} ++ ++int rt_ioctl_giwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (data->length > strlen(pAdapter->nickname) + 1) ++ data->length = strlen(pAdapter->nickname) + 1; ++ if (data->length > 0) { ++ memcpy(nickname, pAdapter->nickname, data->length-1); ++ nickname[data->length-1] = '\0'; ++ } ++ return 0; ++} ++ ++int rt_ioctl_siwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (rts->disabled) ++ val = MAX_RTS_THRESHOLD; ++ else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ else if (rts->value == 0) ++ val = MAX_RTS_THRESHOLD; ++ else ++ val = rts->value; ++ ++ if (val != pAdapter->CommonCfg.RtsThreshold) ++ pAdapter->CommonCfg.RtsThreshold = val; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ rts->value = pAdapter->CommonCfg.RtsThreshold; ++ rts->disabled = (rts->value == MAX_RTS_THRESHOLD); ++ rts->fixed = 1; ++ ++ return 0; ++} ++ ++int rt_ioctl_siwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (frag->disabled) ++ val = MAX_FRAG_THRESHOLD; ++ else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) ++ val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ ++ else if (frag->value == 0) ++ val = MAX_FRAG_THRESHOLD; ++ else ++ return -EINVAL; ++ ++ pAdapter->CommonCfg.FragmentThreshold = val; ++ return 0; ++} ++ ++int rt_ioctl_giwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ frag->value = pAdapter->CommonCfg.FragmentThreshold; ++ frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); ++ frag->fixed = 1; ++ ++ return 0; ++} ++ ++#define MAX_WEP_KEY_SIZE 13 ++#define MIN_WEP_KEY_SIZE 5 ++int rt_ioctl_siwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_DISABLED)) ++ { ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ else if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ if (erq->flags & IW_ENCODE_RESTRICTED) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ ++ if (erq->length > 0) ++ { ++ int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; ++ /* Check the size of the key */ ++ if (erq->length > MAX_WEP_KEY_SIZE) { ++ return -EINVAL; ++ } ++ /* Check key index */ ++ if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", ++ keyIdx, pAdapter->StaCfg.DefaultKeyId)); ++ ++ //Using default key ++ keyIdx = pAdapter->StaCfg.DefaultKeyId; ++ } ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ ++ if (erq->length == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (erq->length == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ /* Disable the key */ ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ ++ /* Check if the key is not marked as invalid */ ++ if(!(erq->flags & IW_ENCODE_NOKEY)) { ++ /* Copy the key in the driver */ ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); ++ } ++ } ++ else ++ { ++ /* Do we want to just set the transmit key index ? */ ++ int index = (erq->flags & IW_ENCODE_INDEX) - 1; ++ if ((index >= 0) && (index < 4)) ++ { ++ pAdapter->StaCfg.DefaultKeyId = index; ++ } ++ else ++ /* Don't complain if only change the mode */ ++ if(!erq->flags & IW_ENCODE_MODE) { ++ return -EINVAL; ++ } ++ } ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); ++ return 0; ++} ++ ++int ++rt_ioctl_giwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ int kid; ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ kid = erq->flags & IW_ENCODE_INDEX; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); ++ ++ if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ++ { ++ erq->length = 0; ++ erq->flags = IW_ENCODE_DISABLED; ++ } ++ else if ((kid > 0) && (kid <=4)) ++ { ++ // copy wep key ++ erq->flags = kid ; /* NB: base 1 */ ++ if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) ++ erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); ++ //if ((kid == pAdapter->PortCfg.DefaultKeyId)) ++ //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ ++ } ++ else if (kid == 0) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); ++ // copy default key ID ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ ++ erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ } ++ ++ return 0; ++ ++} ++ ++static int ++rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter; ++ POS_COOKIE pObj; ++ char *this_char = extra; ++ char *value; ++ int Status=0; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAdapter->OS_Cookie; ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (!*this_char) ++ return -EINVAL; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value) ++ return -EINVAL; ++ ++ // reject setting nothing besides ANY ssid(ssidLen=0) ++ if (!*value && (strcmp(this_char, "SSID") != 0)) ++ return -EINVAL; ++ ++ for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) ++ { ++ if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) ++ { ++ if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) ++ { //FALSE:Set private failed then return Invalid argument ++ Status = -EINVAL; ++ } ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_SET_PROC->name == NULL) ++ { //Not found argument ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); ++ } ++ ++ return Status; ++} ++ ++ ++static int ++rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n\n"); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ } ++ sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); ++ sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->ate.RxAntennaSel == 0) ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++ else ++ { ++ sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); ++ ++ return Status; ++} ++ ++#ifdef DOT11_N_SUPPORT ++void getBaInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pOutBuf) ++{ ++ INT i, j; ++ BA_ORI_ENTRY *pOriBAEntry; ++ BA_REC_ENTRY *pRecBAEntry; ++ ++ for (i=0; iMacTab.Content[i]; ++ if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) ++ { ++ sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", ++ pOutBuf, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); ++ ++ sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BARecWcidArray[j] != 0) ++ { ++ pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); ++ } ++ } ++ sprintf(pOutBuf, "%s\n", pOutBuf); ++ ++ sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BAOriWcidArray[j] != 0) ++ { ++ pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); ++ } ++ } ++ sprintf(pOutBuf, "%s\n\n", pOutBuf); ++ } ++ if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ } ++ ++ return; ++} ++#endif // DOT11_N_SUPPORT // ++ ++static int ++rt_private_show(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ u32 subcmd = wrq->flags; ++ ++ if (dev->priv_flags == INT_MAIN) ++ pAd = dev->priv; ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(subcmd) ++ { ++ ++ case SHOW_CONN_STATUS: ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW) ++ sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); ++ else ++#endif // DOT11_N_SUPPORT // ++ sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); ++ } ++ else ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", ++ pAd->CommonCfg.Ssid, ++ pAd->CommonCfg.Bssid[0], ++ pAd->CommonCfg.Bssid[1], ++ pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3], ++ pAd->CommonCfg.Bssid[4], ++ pAd->CommonCfg.Bssid[5]); ++ DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); ++ } ++ else if (ADHOC_ON(pAd)) ++ sprintf(extra, "Connected\n"); ++ } ++ else ++ { ++ sprintf(extra, "Disconnected\n"); ++ DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); ++ } ++ } ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case SHOW_DRVIER_VERION: ++ sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#ifdef DOT11_N_SUPPORT ++ case SHOW_BA_INFO: ++ getBaInfo(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SHOW_DESC_INFO: ++ { ++ Show_DescInfo_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++ case RAIO_OFF: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = FALSE; ++ if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ sprintf(extra, "Radio Off\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case RAIO_ON: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = TRUE; ++ //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ } ++ sprintf(extra, "Radio On\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case SHOW_DLS_ENTRY_INFO: ++ { ++ Set_DlsEntryInfo_Display_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ case SHOW_CFG_VALUE: ++ { ++ Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); ++ if (Status == 0) ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ } ++ break; ++ case SHOW_ADHOC_ENTRY_INFO: ++ Show_Adhoc_MacTable_Proc(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); ++ break; ++ } ++ ++ return Status; ++} ++ ++#ifdef SIOCSIWMLME ++int rt_ioctl_siwmlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; ++ MLME_QUEUE_ELEM MsgElem; ++ MLME_DISASSOC_REQ_STRUCT DisAssocReq; ++ MLME_DEAUTH_REQ_STRUCT DeAuthReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); ++ ++ if (pMlme == NULL) ++ return -EINVAL; ++ ++ switch(pMlme->cmd) ++ { ++#ifdef IW_MLME_DEAUTH ++ case IW_MLME_DEAUTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); ++ DeAuthReq.Reason = pMlme->reason_code; ++ MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); ++ MlmeDeauthReqAction(pAd, &MsgElem); ++ if (INFRA_ON(pAd)) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ break; ++#endif // IW_MLME_DEAUTH // ++#ifdef IW_MLME_DISASSOC ++ case IW_MLME_DISASSOC: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); ++ DisAssocReq.Reason = pMlme->reason_code; ++ ++ MsgElem.Machine = ASSOC_STATE_MACHINE; ++ MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, &MsgElem); ++ break; ++#endif // IW_MLME_DISASSOC // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); ++ break; ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWMLME // ++ ++#if WIRELESS_EXT > 17 ++int rt_ioctl_siwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ if (param->value == IW_AUTH_WPA_VERSION_WPA) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ } ++ else if (param->value == IW_AUTH_WPA_VERSION_WPA2) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_KEY_MGMT: ++ if (param->value == IW_AUTH_KEY_MGMT_802_1X) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else ++ // WEP 1x ++ pAdapter->StaCfg.IEEE8021X = TRUE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == 0) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ /*if (param->value == 0) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ }*/ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ if (param->value != 0) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ } ++ else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ } ++ else ++ return -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); ++ break; ++ default: ++ return -EOPNOTSUPP; ++} ++ ++ return 0; ++} ++ ++int rt_ioctl_giwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); ++ return 0; ++} ++ ++void fnSetCipherKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN INT keyIdx, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bGTK, ++ IN struct iw_encode_ext *ext) ++{ ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ pAdapter->SharedKey[BSS0][keyIdx].Key, ++ pAdapter->SharedKey[BSS0][keyIdx].TxMic, ++ pAdapter->SharedKey[BSS0][keyIdx].RxMic); ++ ++ if (bGTK) ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ NULL); ++ else ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ &pAdapter->MacTab.Content[BSSID_WCID]); ++} ++ ++int rt_ioctl_siwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++ { ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int keyIdx, alg = ext->alg; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ { ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); ++ } ++ else ++ { ++ // Get Key Index and convet to our own defined key index ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ return -EINVAL; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ pAdapter->StaCfg.DefaultKeyId = keyIdx; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); ++ } ++ ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); ++ break; ++ case IW_ENCODE_ALG_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); ++ if (ext->key_len == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (ext->key_len == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ return -EINVAL; ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); ++ if (ext->key_len == 32) ++ { ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else ++ return -EINVAL; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++rt_ioctl_giwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PCHAR pKey = NULL; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) ++ { ++ if (idx < 1 || idx > 4) ++ return -EINVAL; ++ idx--; ++ ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) ++ { ++ if (idx != pAd->StaCfg.DefaultKeyId) ++ { ++ ext->key_len = 0; ++ return 0; ++ } ++ } ++ } ++ else ++ idx = pAd->StaCfg.DefaultKeyId; ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ ext->key_len = 0; ++ switch(pAd->StaCfg.WepStatus) { ++ case Ndis802_11WEPDisabled: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ encoding->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11WEPEnabled: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; ++ pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ else ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ ++ if (max_key_len < 32) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = 32; ++ pKey = &pAd->StaCfg.PMK[0]; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ext->key_len && pKey) ++ { ++ encoding->flags |= IW_ENCODE_ENABLED; ++ memcpy(ext->key, pKey, ext->key_len); ++ } ++ ++ return 0; ++} ++ ++#ifdef SIOCSIWGENIE ++int rt_ioctl_siwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (wrqu->data.length > MAX_LEN_OF_RSNIE || ++ (wrqu->data.length && extra == NULL)) ++ return -EINVAL; ++ ++ if (wrqu->data.length) ++ { ++ pAd->StaCfg.RSNIE_Len = wrqu->data.length; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); ++ } ++ else ++ { ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWGENIE // ++ ++int rt_ioctl_giwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if ((pAd->StaCfg.RSNIE_Len == 0) || ++ (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) ++ { ++ wrqu->data.length = 0; ++ return 0; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) ++ return -E2BIG; ++ ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ else ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len ++ return -E2BIG; ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ RSNIe = IE_RSN; ++ ++ extra[0] = (char)RSNIe; ++ extra[1] = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_siwpmksa(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; ++ INT CachedIdx = 0, idx = 0; ++ ++ if (pPmksa == NULL) ++ return -EINVAL; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); ++ switch(pPmksa->cmd) ++ { ++ case IW_PMKSA_FLUSH: ++ NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); ++ break; ++ case IW_PMKSA_REMOVE: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ { ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); ++ for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) ++ { ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); ++ } ++ pAd->StaCfg.SavedPMKNum--; ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); ++ break; ++ case IW_PMKSA_ADD: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ pAd->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); ++ break; ++ } ++ ++ return 0; ++} ++#endif // #if WIRELESS_EXT > 17 ++ ++#ifdef DBG ++static int ++rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++ { ++ CHAR *this_char; ++ CHAR *value = NULL; ++ UCHAR regBBP = 0; ++// CHAR arg[255]={0}; ++ UINT32 bbpId; ++ UINT32 bbpValue; ++ BOOLEAN bIsPrintAllBBP = FALSE; ++ INT Status = 0; ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ if (wrq->length > 1) //No parameters. ++ { ++ sprintf(extra, "\n"); ++ ++ //Parsing Read or Write ++ this_char = wrq->pointer; ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); ++ if (sscanf(this_char, "%d", &(bbpId)) == 1) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Write ++ if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ bIsPrintAllBBP = TRUE; ++ ++next: ++ if (bIsPrintAllBBP) ++ { ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n"); ++ for (bbpId = 0; bbpId <= 136; bbpId++) ++ { ++ if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) ++ break; ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); ++ if (bbpId%5 == 4) ++ sprintf(extra+strlen(extra), "\n"); ++ } ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); ++ ++ return Status; ++} ++#endif // DBG // ++ ++int rt_ioctl_siwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); ++ /* rate = -1 => auto rate ++ rate = X, fixed = 1 => (fixed rate X) ++ */ ++ if (rate == -1) ++ { ++ //Auto Rate ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, -1); ++ ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ else ++ { ++ if (fixed) ++ { ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, rate); ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ // TODO: rate = X, fixed = 0 => (rates <= X) ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ int rate_index = 0, rate_count = 0; ++ HTTRANSMIT_SETTING ht_setting; ++ __s32 ralinkrate[] = ++ {2, 4, 11, 22, // CCK ++ 12, 18, 24, 36, 48, 72, 96, 108, // OFDM ++ 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 ++ 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 ++ 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 ++ 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 ++ 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 ++ 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 ++ 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 ++ 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 ++ ++ rate_count = sizeof(ralinkrate)/sizeof(__s32); ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && ++ (INFRA_ON(pAd)) && ++ ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) ++ ht_setting.word = pAd->StaCfg.HTPhyMode.word; ++ else ++ ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ ++#ifdef DOT11_N_SUPPORT ++ if (ht_setting.field.MODE >= MODE_HTMIX) ++ { ++// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); ++ rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (ht_setting.field.MODE == MODE_OFDM) ++ rate_index = (UCHAR)(ht_setting.field.MCS) + 4; ++ else if (ht_setting.field.MODE == MODE_CCK) ++ rate_index = (UCHAR)(ht_setting.field.MCS); ++ ++ if (rate_index < 0) ++ rate_index = 0; ++ ++ if (rate_index > rate_count) ++ rate_index = rate_count; ++ ++ wrqu->bitrate.value = ralinkrate[rate_index] * 500000; ++ wrqu->bitrate.disabled = 0; ++ ++ return 0; ++} ++ ++static const iw_handler rt_handler[] = ++{ ++ (iw_handler) NULL, /* SIOCSIWCOMMIT */ ++ (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ ++ (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ ++ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ ++ (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ ++ (iw_handler) NULL, /* SIOCSIWSPY */ ++ (iw_handler) NULL, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* SIOCSIWTHRSPY */ ++ (iw_handler) NULL, /* SIOCGIWTHRSPY */ ++ (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ ++ (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ ++#ifdef SIOCSIWMLME ++ (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* SIOCSIWMLME */ ++#endif // SIOCSIWMLME // ++ (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ ++#ifdef SIOCGIWSCAN ++ (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ ++#else ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* SIOCGIWSCAN */ ++ (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ ++ (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ ++ (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ ++ (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) NULL, /* SIOCSIWTXPOW */ ++ (iw_handler) NULL, /* SIOCGIWTXPOW */ ++ (iw_handler) NULL, /* SIOCSIWRETRY */ ++ (iw_handler) NULL, /* SIOCGIWRETRY */ ++ (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) NULL, /* SIOCSIWPOWER */ ++ (iw_handler) NULL, /* SIOCGIWPOWER */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ ++ (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ ++ (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ ++ (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ ++ (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ ++#endif ++}; ++ ++static const iw_handler rt_priv_handlers[] = { ++ (iw_handler) NULL, /* + 0x00 */ ++ (iw_handler) NULL, /* + 0x01 */ ++#ifndef CONFIG_AP_SUPPORT ++ (iw_handler) rt_ioctl_setparam, /* + 0x02 */ ++#else ++ (iw_handler) NULL, /* + 0x02 */ ++#endif // CONFIG_AP_SUPPORT // ++#ifdef DBG ++ (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ ++#else ++ (iw_handler) NULL, /* + 0x03 */ ++#endif ++ (iw_handler) NULL, /* + 0x04 */ ++ (iw_handler) NULL, /* + 0x05 */ ++ (iw_handler) NULL, /* + 0x06 */ ++ (iw_handler) NULL, /* + 0x07 */ ++ (iw_handler) NULL, /* + 0x08 */ ++ (iw_handler) rt_private_get_statistics, /* + 0x09 */ ++ (iw_handler) NULL, /* + 0x0A */ ++ (iw_handler) NULL, /* + 0x0B */ ++ (iw_handler) NULL, /* + 0x0C */ ++ (iw_handler) NULL, /* + 0x0D */ ++ (iw_handler) NULL, /* + 0x0E */ ++ (iw_handler) NULL, /* + 0x0F */ ++ (iw_handler) NULL, /* + 0x10 */ ++ (iw_handler) rt_private_show, /* + 0x11 */ ++ (iw_handler) NULL, /* + 0x12 */ ++ (iw_handler) NULL, /* + 0x13 */ ++ (iw_handler) NULL, /* + 0x15 */ ++ (iw_handler) NULL, /* + 0x17 */ ++ (iw_handler) NULL, /* + 0x18 */ ++}; ++ ++const struct iw_handler_def rt28xx_iw_handler_def = ++{ ++#define N(a) (sizeof (a) / sizeof (a[0])) ++ .standard = (iw_handler *) rt_handler, ++ .num_standard = sizeof(rt_handler) / sizeof(iw_handler), ++ .private = (iw_handler *) rt_priv_handlers, ++ .num_private = N(rt_priv_handlers), ++ .private_args = (struct iw_priv_args *) privtab, ++ .num_private_args = N(privtab), ++#if IW_HANDLER_VERSION >= 7 ++ .get_wireless_stats = rt28xx_get_wireless_stats, ++#endif ++}; ++ ++INT RTMPSetInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ RT_802_11_PHY_MODE PhyMode; ++ RT_802_11_STA_CONFIG StaConfig; ++ NDIS_802_11_RATES aryRates; ++ RT_802_11_PREAMBLE Preamble; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ PNDIS_802_11_KEY pKey = NULL; ++ PNDIS_802_11_WEP pWepKey =NULL; ++ PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; ++ NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; ++ NDIS_802_11_NETWORK_TYPE NetType; ++ ULONG Now; ++ UINT KeyIdx = 0; ++ INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; ++ ULONG PowerTemp; ++ BOOLEAN RadioState; ++ BOOLEAN StateMachineTouched = FALSE; ++#ifdef DOT11_N_SUPPORT ++ OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy ++#endif // DOT11_N_SUPPORT // ++#ifdef WPA_SUPPLICANT_SUPPORT ++ PNDIS_802_11_PMKID pPmkId = NULL; ++ BOOLEAN IEEE8021xState = FALSE; ++ BOOLEAN IEEE8021x_required_keys = FALSE; ++ UCHAR wpa_supplicant_enable = 0; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR ctmp; ++#endif // SNMP_SUPPORT // ++ ++ ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); ++ switch(cmd & 0x7FFF) { ++ case RT_OID_802_11_COUNTRY_REGION: ++ if (wrq->u.data.length < sizeof(UCHAR)) ++ Status = -EINVAL; ++ // Only avaliable when EEPROM not programming ++ else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) ++ { ++ ULONG Country; ++ UCHAR TmpPhy; ++ ++ Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); ++ pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); ++ TmpPhy = pAdapter->CommonCfg.PhyMode; ++ pAdapter->CommonCfg.PhyMode = 0xff; ++ // Build all corresponding channel information ++ RTMPSetPhyMode(pAdapter, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, ++ pAdapter->CommonCfg.CountryRegion)); ++ } ++ break; ++ case OID_802_11_BSSID_LIST_SCAN: ++ #ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ Now = jiffies; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ break; ++ } ++ ++ //Benson add 20080527, when radio off, sta don't need to scan ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) ++ break; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ break; ++ case OID_802_11_SSID: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) ++ Status = -EINVAL; ++ else ++ { ++ PCHAR pSsidString = NULL; ++ Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ if (Ssid.SsidLength > MAX_LEN_OF_SSID) ++ Status = -EINVAL; ++ else ++ { ++ if (Ssid.SsidLength == 0) ++ { ++ Set_SSID_Proc(pAdapter, ""); ++ } ++ else ++ { ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); ++ Set_SSID_Proc(pAdapter, pSsidString); ++ kfree(pSsidString); ++ } ++ else ++ Status = -ENOMEM; ++ } ++ } ++ } ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ } ++ break; ++ case RT_OID_802_11_RADIO: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); ++ if (pAdapter->StaCfg.bSwRadio != RadioState) ++ { ++ pAdapter->StaCfg.bSwRadio = RadioState; ++ if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) ++ { ++ pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); ++ if (pAdapter->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ MlmeRadioOff(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PhyMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAdapter, PhyMode); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); ++ } ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; ++ pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; ++ pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable ++ if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && ++ (StaConfig.AdhocMode <= MaxPhyMode)) ++ { ++ // allow dynamic change of "USE OFDM rate or not" in ADHOC mode ++ // if setting changed, need to reset current TX rate as well as BEACON frame format ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ { ++ pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; ++ RTMPSetPhyMode(pAdapter, PhyMode); ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ MakeIbssBeacon(pAdapter); // re-build BEACON frame ++ AsicEnableIbssSync(pAdapter); // copy to on-chip memory ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", ++ pAdapter->CommonCfg.bEnableTxBurst, ++ pAdapter->CommonCfg.UseBGProtection, ++ pAdapter->CommonCfg.bUseShortSlotTime)); ++ } ++ break; ++ case OID_802_11_DESIRED_RATES: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ } ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); ++ if (Preamble == Rt802_11PreambleShort) ++ { ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); ++ } ++ else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) ++ { ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); ++ } ++ break; ++ case OID_802_11_WEP_STATUS: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); ++ // Since TKIP, AES, WEP are all supported. It should not have any invalid setting ++ if (WepStatus <= Ndis802_11Encryption3KeyAbsent) ++ { ++ if (pAdapter->StaCfg.WepStatus != WepStatus) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.WepStatus = WepStatus; ++ pAdapter->StaCfg.OrigWepStatus = WepStatus; ++ pAdapter->StaCfg.PairCipher = WepStatus; ++ pAdapter->StaCfg.GroupCipher = WepStatus; ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); ++ } ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (AuthMode > Ndis802_11AuthModeMax) ++ { ++ Status = -EINVAL; ++ break; ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode != AuthMode) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.AuthMode = AuthMode; ++ } ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); ++ } ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (BssType == Ndis802_11IBSS) ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ else if (BssType == Ndis802_11Infrastructure) ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ else if (BssType == Ndis802_11Monitor) ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ else ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); ++ } ++ } ++ break; ++ case OID_802_11_REMOVE_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); ++ if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) ++ { ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx >= 4){ ++ Status = -EINVAL; ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_RESET_COUNTERS: ++ NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); ++ pAdapter->Counters8023.RxNoBuffer = 0; ++ pAdapter->Counters8023.GoodReceives = 0; ++ pAdapter->Counters8023.RxNoBuffer = 0; ++#ifdef RT2870 ++ pAdapter->BulkOutComplete = 0; ++ pAdapter->BulkOutCompleteOther= 0; ++ pAdapter->BulkOutCompleteCancel = 0; ++ pAdapter->BulkOutReq = 0; ++ pAdapter->BulkInReq= 0; ++ pAdapter->BulkInComplete = 0; ++ pAdapter->BulkInCompleteFail = 0; ++#endif // RT2870 // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); ++ if (RtsThresh > MAX_RTS_THRESHOLD) ++ Status = -EINVAL; ++ else ++ pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ if (FragThresh == 0) ++ { ++ pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else ++ Status = -EINVAL; ++ } ++ else ++ pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerMode == Ndis802_11PowerModeCAM) ++ Set_PSMode_Proc(pAdapter, "CAM"); ++ else if (PowerMode == Ndis802_11PowerModeMAX_PSP) ++ Set_PSMode_Proc(pAdapter, "Max_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeFast_PSP) ++ Set_PSMode_Proc(pAdapter, "Fast_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) ++ Set_PSMode_Proc(pAdapter, "Legacy_PSP"); ++ else ++ Status = -EINVAL; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ if (wrq->u.data.length < sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerTemp > 100) ++ PowerTemp = 0xffffffff; // AUTO ++ pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. ++ pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ } ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (NetType == Ndis802_11DS) ++ RTMPSetPhyMode(pAdapter, PHY_11B); ++ else if (NetType == Ndis802_11OFDM24) ++ RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); ++ else if (NetType == Ndis802_11OFDM5) ++ RTMPSetPhyMode(pAdapter, PHY_11A); ++ else ++ Status = -EINVAL; ++#ifdef DOT11_N_SUPPORT ++ if (Status == NDIS_STATUS_SUCCESS) ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); ++ } ++ break; ++ // For WPA PSK PMK key ++ case RT_OID_802_11_ADD_WPA: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); ++ } ++ else ++ { ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) ++ { ++ Status = -EOPNOTSUPP; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); ++ } ++ else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode ++ { ++ NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); ++ // Use RaConfig as PSK agent. ++ // Start STA supplicant state machine ++ if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ pAdapter->StaCfg.WpaState = SS_START; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ else ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_REMOVE_KEY: ++ pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pRemoveKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pRemoveKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); ++ } ++ else ++ { ++ KeyIdx = pRemoveKey->KeyIndex; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx > 3) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); ++ } ++ } ++ } ++ } ++ kfree(pRemoveKey); ++ break; ++ // New for WPA ++ case OID_802_11_ADD_KEY: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); ++ } ++ else ++ { ++ RTMPAddKey(pAdapter, pKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_CONFIGURATION: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); ++ pConfig = &Config; ++ ++ if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) ++ pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; ++ ++ pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; ++ MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); ++ // ++ // Save the channel on MlmeAux for CntlOidRTBssidProc used. ++ // ++ pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", ++ pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_HT_PHYMODE: ++ if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) ++ Status = -EINVAL; ++ else ++ { ++ POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; ++ ++ Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", ++ pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ RTMPSetHT(pAdapter, pHTPhyMode); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", ++ pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, ++ pAdapter->StaCfg.HTPhyMode.field.STBC)); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case RT_OID_802_11_SET_APSD_SETTING: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ ULONG apsd ; ++ Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); ++ ++ /*------------------------------------------------------------------- ++ |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | ++ --------------------------------------------------------------------- ++ | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | ++ ---------------------------------------------------------------------*/ ++ pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; ++ pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, ++ pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_APSD_PSM: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ // Driver needs to notify AP when PSM changes ++ Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); ++ if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) ++ { ++ MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); ++ RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ } ++ break; ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; ++ Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); ++ if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) ++ { ++ int i; ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_DLS_PARAM: ++ if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) ++ Status = -EINVAL; ++ else ++ { ++ RT_802_11_DLS Dls; ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ case RT_OID_802_11_SET_WMM: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); ++ } ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ // ++ // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. ++ // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 ++ // when query OID_802_11_BSSID_LIST. ++ // ++ // TRUE: NumberOfItems will set to 0. ++ // FALSE: NumberOfItems no change. ++ // ++ pAdapter->CommonCfg.NdisRadioStateOff = TRUE; ++ // Set to immediately send the media disconnect event ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_DISASSOCIATE, ++ 0, ++ NULL); ++ ++ StateMachineTouched = TRUE; ++ } ++ break; ++ ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_IMME_BA_CAP: ++ if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) ++ Status = -EINVAL; ++ else ++ { ++ OID_BACAP_STRUC Orde ; ++ Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); ++ if (Orde.Policy > BA_NOTUSE) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ } ++ else if (Orde.Policy == BA_NOTUSE) ++ { ++ pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ } ++ else ++ { ++ pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; ++ pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ ++ if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; ++ ++ } ++ ++ pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); ++ } ++ ++ break; ++ case RT_OID_802_11_ADD_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ UCHAR index; ++ OID_ADD_BA_ENTRY BA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); ++ if (BA.TID > 15) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ else ++ { ++ //BATableInsertEntry ++ //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. ++ index = BA.TID; ++ // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too ++ pEntry = MacTableLookup(pAdapter, BA.MACAddr); ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); ++ break; ++ } ++ if (BA.IsRecipient == FALSE) ++ { ++ if (pEntry->bIAmBadAtheros == TRUE) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; ++ ++ BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); ++ } ++ else ++ { ++ //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", ++ BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] ++ , BA.MACAddr[4], BA.MACAddr[5])); ++ } ++ } ++ break; ++ ++ case RT_OID_802_11_TEAR_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ POID_ADD_BA_ENTRY pBA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if (pBA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); ++ ++ if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (pBA->IsRecipient == FALSE) ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); ++ BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ if (pEntry) ++ { ++ BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ kfree(pBA); ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ ++ // For WPA_SUPPLICANT to set static wep key ++ case OID_802_11_ADD_WEP: ++ pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pWepKey == NULL) ++ { ++ Status = -ENOMEM; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); ++ break; ++ } ++ Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (Status) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); ++ } ++ else ++ { ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ // KeyIdx must be 0 ~ 3 ++ if (KeyIdx > 4) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg = 0; ++ PUCHAR Key; ++ ++ // set key material and key length ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ ++ switch(pWepKey->KeyLength) ++ { ++ case 5: ++ CipherAlg = CIPHER_WEP64; ++ break; ++ case 13: ++ CipherAlg = CIPHER_WEP128; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); ++ Status = -EINVAL; ++ break; ++ } ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ ++ // Default key for tx (shared key) ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // set key material and key length ++ NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ++#endif // WPA_SUPPLICANT_SUPPORT ++ { ++ Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); ++ } ++ } ++ kfree(pWepKey); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case OID_SET_COUNTERMEASURES: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.bBlockAssoc = TRUE; ++ else ++ // WPA MIC error should block association attempt for 60 seconds ++ pAdapter->StaCfg.bBlockAssoc = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ } ++ break; ++ case OID_802_11_DEAUTHENTICATION: ++ if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) ++ Status = -EINVAL; ++ else ++ { ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; ++ Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); ++ MlmeDeauthReqAction(pAdapter, MsgElem); ++ kfree(MsgElem); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ LinkDown(pAdapter, FALSE); ++ pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); ++ } ++ break; ++ case OID_802_11_DROP_UNENCRYPTED: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ NdisAcquireSpinLock(&pAdapter->MacTabLock); ++ pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAdapter->MacTabLock); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021X = IEEE8021xState; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); ++ } ++ break; ++ case OID_802_11_PMKID: ++ pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pPmkId == NULL) { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // check the PMKID information ++ if (pPmkId->BSSIDInfoCount == 0) ++ NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ else ++ { ++ PBSSID_INFO pBssIdInfo; ++ UINT BssIdx; ++ UINT CachedIdx; ++ ++ for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) ++ { ++ // point to the indexed BSSID_INFO structure ++ pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); ++ // Find the entry in the saved data base. ++ for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ pAdapter->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ } ++ } ++ } ++ if(pPmkId) ++ kfree(pPmkId); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++#ifdef SNMP_SUPPORT ++ case OID_802_11_SHORTRETRYLIMIT: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); ++ pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ //pKey = &WepKey; ++ ++ if ( pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); ++ } ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); ++ ++ // it is a shared key ++ if (KeyIdx > 4) ++ Status = -EINVAL; ++ else ++ { ++ pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ //RestartAPIsRequired = TRUE; ++ } ++ break; ++ ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); ++ ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ break; ++ ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); ++ sprintf(&ctmp,"%d", ctmp); ++ Set_Channel_Proc(pAdapter, &ctmp); ++ } ++ break; ++#endif ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ ++ return Status; ++} ++ ++INT RTMPQueryInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; ++ PNDIS_WLAN_BSSID_EX pBss; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_CONFIGURATION *pConfiguration = NULL; ++ RT_802_11_LINK_STATUS *pLinkStatus = NULL; ++ RT_802_11_STA_CONFIG *pStaConfig = NULL; ++ NDIS_802_11_STATISTICS *pStatistics = NULL; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ RT_802_11_PREAMBLE PreamType; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_MEDIA_STATE MediaState; ++ ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; ++ USHORT BssLen = 0; ++ PUCHAR pBuf = NULL, pPtr; ++ INT Status = NDIS_STATUS_SUCCESS; ++ UINT we_version_compiled; ++ UCHAR i, Padding = 0; ++ BOOLEAN RadioState; ++ UCHAR driverVersion[8]; ++ OID_SET_HT_PHYMODE *pHTPhyMode = NULL; ++ ++ ++#ifdef SNMP_SUPPORT ++ //for snmp, kathy ++ DefaultKeyIdxValue *pKeyIdxValue; ++ INT valueLen; ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR tmp[64]; ++#endif //SNMP ++ ++ switch(cmd) ++ { ++ case RT_OID_DEVICE_NAME: ++ wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); ++ Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); ++ break; ++ case RT_OID_VERSION_INFO: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); ++ wrq->u.data.length = 8*sizeof(UCHAR); ++ sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); ++ driverVersion[7] = '\0'; ++ if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#ifdef RALINK_ATE ++ case RT_QUERY_ATE_TXDONE_COUNT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); ++ wrq->u.data.length = sizeof(UINT32); ++ if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#endif // RALINK_ATE // ++ case OID_802_11_BSSID_LIST: ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); ++ return -EAGAIN; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ // Claculate total buffer size required ++ BssBufSize = sizeof(ULONG); ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ // Align pointer to 4 bytes boundary. ++ //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); ++ //if (Padding == 4) ++ // Padding = 0; ++ BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ } ++ ++ // For safety issue, we add 256 bytes just in case ++ BssBufSize += 256; ++ // Allocate the same size as passed from higher layer ++ pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); ++ if(pBuf == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ // Init 802_11_BSSID_LIST_EX structure ++ NdisZeroMemory(pBuf, BssBufSize); ++ pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; ++ pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; ++ ++ // Calculate total buffer length ++ BssLen = 4; // Consist of NumberOfItems ++ // Point to start of NDIS_WLAN_BSSID_EX ++ // pPtr = pBuf + sizeof(ULONG); ++ pPtr = (PUCHAR) &pBssidList->Bssid[0]; ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ pBss = (PNDIS_WLAN_BSSID_EX) pPtr; ++ NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) ++ { ++ // ++ // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation ++ // and then failed to send EAPOl farame. ++ // ++ if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ else ++ pBss->Ssid.SsidLength = 0; ++ } ++ else ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; ++ pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; ++ pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; ++ pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; ++ ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); ++ ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) ++ pBss->InfrastructureMode = Ndis802_11Infrastructure; ++ else ++ pBss->InfrastructureMode = Ndis802_11IBSS; ++ ++ NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); ++ NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, ++ pAdapter->ScanTab.BssEntry[i].ExtRate, ++ pAdapter->ScanTab.BssEntry[i].ExtRateLen); ++ ++ if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) ++ { ++ pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ } ++ else ++ { ++ pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; ++ } ++ pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ ++#if WIRELESS_EXT < 17 ++ if ((BssLen + pBss->Length) < wrq->u.data.length) ++ BssLen += pBss->Length; ++ else ++ { ++ pBssidList->NumberOfItems = i; ++ break; ++ } ++#else ++ BssLen += pBss->Length; ++#endif ++ } ++ ++#if WIRELESS_EXT < 17 ++ wrq->u.data.length = BssLen; ++#else ++ if (BssLen > wrq->u.data.length) ++ { ++ kfree(pBssidList); ++ return -E2BIG; ++ } ++ else ++ wrq->u.data.length = BssLen; ++#endif ++ Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); ++ kfree(pBssidList); ++ break; ++ case OID_802_3_CURRENT_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ case OID_GEN_MEDIA_CONNECT_STATUS: ++ if (pAdapter->IndicateMediaState == NdisMediaStateConnected) ++ MediaState = NdisMediaStateConnected; ++ else ++ MediaState = NdisMediaStateDisconnected; ++ ++ wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); ++ Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++#endif // RALINK_ATE // ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); ++ Status = -ENOTCONN; ++ } ++ break; ++ case OID_802_11_SSID: ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); ++ Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; ++ memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); ++ wrq->u.data.length = sizeof(NDIS_802_11_SSID); ++ Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); ++ break; ++ case RT_OID_802_11_QUERY_LINK_STATUS: ++ pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); ++ if (pLinkStatus) ++ { ++ pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps ++ pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; ++ pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; ++ pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; ++ pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; ++ wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); ++ Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); ++ kfree(pLinkStatus); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_CONFIGURATION: ++ pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); ++ if (pConfiguration) ++ { ++ pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; ++ pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); ++ wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); ++ Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", ++ pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ kfree(pConfiguration); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_SNR_0: ++ if ((pAdapter->StaCfg.LastSNR0 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ break; ++ case RT_OID_802_11_SNR_1: ++ if ((pAdapter->Antenna.field.RxPath > 1) && ++ (pAdapter->StaCfg.LastSNR1 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); ++ break; ++ case OID_802_11_RSSI_TRIGGER: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); ++ break; ++ case OID_802_11_RSSI: ++ case RT_OID_802_11_RSSI: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_1: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_2: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_802_11_STATISTICS: ++ pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); ++ if (pStatistics) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAdapter); ++ ++ // Sanity check for calculation of sucessful count ++ if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) ++ pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ ++ pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; ++ pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; ++ pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; ++ pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; ++ pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; ++ pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; ++ pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; ++ pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; ++ pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; ++#ifdef DBG ++ pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; ++#else ++ pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; ++ pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; ++#endif ++ wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); ++ Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); ++ kfree(pStatistics); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_GEN_RCV_OK: ++ ulInfo = pAdapter->Counters8023.GoodReceives; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_GEN_RCV_NO_BUFFER: ++ ulInfo = pAdapter->Counters8023.RxNoBuffer; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); ++ if (pStaConfig) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); ++ pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; ++ pStaConfig->EnableTurboRate = 0; ++ pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; ++ pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; ++ //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; ++ pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; ++ pStaConfig->Rsv1 = 0; ++ pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; ++ wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); ++ Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); ++ kfree(pStaConfig); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ RtsThresh = pAdapter->CommonCfg.RtsThreshold; ++ wrq->u.data.length = sizeof(RtsThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ FragThresh = pAdapter->CommonCfg.FragmentThreshold; ++ if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) ++ FragThresh = 0; ++ wrq->u.data.length = sizeof(FragThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ PowerMode = pAdapter->StaCfg.WindowsPowerMode; ++ wrq->u.data.length = sizeof(PowerMode); ++ Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); ++ break; ++ case RT_OID_802_11_RADIO: ++ RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; ++ wrq->u.data.length = sizeof(RadioState); ++ Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ BssType = Ndis802_11IBSS; ++ else if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ BssType = Ndis802_11Infrastructure; ++ else if (pAdapter->StaCfg.BssType == BSS_MONITOR) ++ BssType = Ndis802_11Monitor; ++ else ++ BssType = Ndis802_11AutoUnknown; ++ ++ wrq->u.data.length = sizeof(BssType); ++ Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ PreamType = pAdapter->CommonCfg.TxPreamble; ++ wrq->u.data.length = sizeof(PreamType); ++ Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ AuthMode = pAdapter->StaCfg.AuthMode; ++ wrq->u.data.length = sizeof(AuthMode); ++ Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); ++ break; ++ case OID_802_11_WEP_STATUS: ++ WepStatus = pAdapter->StaCfg.WepStatus; ++ wrq->u.data.length = sizeof(WepStatus); ++ Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); ++ break; ++ case OID_802_11_TX_POWER_LEVEL: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ break; ++ case OID_802_11_NETWORK_TYPES_SUPPORTED: ++ if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) ++ { ++ NetworkTypeList[0] = 3; // NumberOfItems = 3 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a ++ wrq->u.data.length = 16; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ else ++ { ++ NetworkTypeList[0] = 2; // NumberOfItems = 2 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ wrq->u.data.length = 12; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ wrq->u.data.length = sizeof(ULONG); ++ if (pAdapter->CommonCfg.PhyMode == PHY_11A) ++ ulInfo = Ndis802_11OFDM5; ++ else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) ++ ulInfo = Ndis802_11OFDM24; ++ else ++ ulInfo = Ndis802_11DS; ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_LAST_RX_RATE: ++ ulInfo = (ULONG)pAdapter->LastRxRate; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_LAST_TX_RATE: ++ //ulInfo = (ULONG)pAdapter->LastTxRate; ++ ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_EEPROM_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_FIRMWARE_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_NOISE_LEVEL: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); ++ break; ++ case RT_OID_802_11_EXTRA_INFO: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); ++ break; ++ case RT_OID_WE_VERSION_COMPILED: ++ wrq->u.data.length = sizeof(UINT); ++ we_version_compiled = WIRELESS_EXT; ++ Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_APSD_SETTING: ++ apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) ++ | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); ++ ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", ++ apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); ++ break; ++ case RT_OID_802_11_QUERY_APSD_PSM: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ break; ++ case RT_OID_802_11_QUERY_WMM: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case RT_OID_NEW_DRIVER: ++ { ++ UCHAR enabled = 1; ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ case RT_OID_DRIVER_DEVICE_NAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); ++ wrq->u.data.length = 16; ++ if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; ++ ++ pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_COUNTRY_REGION: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); ++ wrq->u.data.length = sizeof(ulInfo); ++ ulInfo = pAdapter->CommonCfg.CountryRegionForABand; ++ ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); ++ if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; ++ ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ i = 0; ++#ifdef MULTIPLE_CARD_SUPPORT ++ i = 1; ++#endif // MULTIPLE_CARD_SUPPORT // ++ if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); ++ break; ++#ifdef SNMP_SUPPORT ++ case RT_OID_802_11_MAC_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREROUI: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); ++ wrq->u.data.length = ManufacturerOUI_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTURERNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_RESOURCETYPEIDNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); ++ wrq->u.data.length = strlen(ResourceTypeIdName); ++ Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); ++ ulInfo = 1; // 1 is support wep else 2 is not support. ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_POWERMANAGEMENTMODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); ++ if (pAdapter->StaCfg.Psm == PSMP_ACTION) ++ ulInfo = 1; // 1 is power active else 2 is power save. ++ else ++ ulInfo = 2; ++ ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); ++ //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; ++ pKeyIdxValue = wrq->u.data.pointer; ++ DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); ++ valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ NdisMoveMemory(pKeyIdxValue->Value, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, ++ valueLen); ++ pKeyIdxValue->Value[valueLen]='\0'; ++ ++ wrq->u.data.length = sizeof(DefaultKeyIdxValue); ++ ++ Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ pAdapter->SharedKey[BSS0][0].Key[0], ++ pAdapter->SharedKey[BSS0][1].Key[0], ++ pAdapter->SharedKey[BSS0][2].Key[0], ++ pAdapter->SharedKey[BSS0][3].Key[0])); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); ++ break; ++ ++ case RT_OID_802_11_WEPKEYMAPPINGLENGTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ wrq->u.data.length); ++ break; ++ ++ case OID_802_11_SHORTRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRODUCTID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); ++ ++#ifdef RT2870 ++ sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); ++ ++#endif // RT2870 // ++ wrq->u.data.length = strlen(tmp); ++ Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++#endif //SNMP_SUPPORT ++ ++ case OID_802_11_BUILD_CHANNEL_EX: ++ { ++ UCHAR value; ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 1; ++#else ++ DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 0; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ Status = copy_to_user(wrq->u.data.pointer, &value, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ } ++ break; ++ ++ case OID_802_11_GET_CH_LIST: ++ { ++ PRT_CHANNEL_LIST_INFO pChListBuf; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); ++ if (pAdapter->ChannelListNum == 0) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); ++ if (pChListBuf == NULL) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf->ChannelListNum = pAdapter->ChannelListNum; ++ for (i = 0; i < pChListBuf->ChannelListNum; i++) ++ pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; ++ ++ wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ ++ if (pChListBuf) ++ kfree(pChListBuf); ++ } ++ break; ++ ++ case OID_802_11_GET_COUNTRY_CODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); ++ wrq->u.data.length = 2; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ case OID_802_11_GET_CHANNEL_GEOGRAPHY: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); ++ wrq->u.data.length = 1; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_QUERY_DLS: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ break; ++ ++ case RT_OID_802_11_QUERY_DLS_PARAM: ++ { ++ PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); ++ if (pDlsInfo == NULL) ++ break; ++ ++ for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); ++ } ++ ++ pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; ++ wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); ++ ++ if (pDlsInfo) ++ kfree(pDlsInfo); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ return Status; ++} ++ ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ POS_COOKIE pObj; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ struct iwreq *wrq = (struct iwreq *) rq; ++ BOOLEAN StateMachineTouched = FALSE; ++ INT Status = NDIS_STATUS_SUCCESS; ++ USHORT subcmd; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (wrq->u.data.pointer == NULL) ++ { ++ return Status; ++ } ++ ++ if (strstr(wrq->u.data.pointer, "OpMode") == NULL) ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ } ++ ++ { // determine this ioctl command is comming from which interface. ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(cmd) ++ { ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++ case RTPRIV_IOCTL_ATE: ++ { ++ RtmpDoAte(pAd, wrq); ++ } ++ break; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ case SIOCGIFHWADDR: ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); ++ memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); ++ break; ++ case SIOCGIWNAME: ++ { ++ char *name=&wrq->u.name[0]; ++ rt_ioctl_giwname(net_dev, NULL, name, NULL); ++ break; ++ } ++ case SIOCGIWESSID: //Get ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWESSID: //Set ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWNWID: // set network id (the cell) ++ case SIOCGIWNWID: // get network id ++ Status = -EOPNOTSUPP; ++ break; ++ case SIOCSIWFREQ: //set channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCGIWFREQ: // get channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCSIWNICKN: //set node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_siwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWNICKN: //get node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_giwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWRATE: //get default bit rate (bps) ++ rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCSIWRATE: //set default bit rate (bps) ++ rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCGIWRTS: // get RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_giwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCSIWRTS: //set RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_siwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCGIWFRAG: //get fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCSIWFRAG: //set fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCGIWENCODE: //get encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCSIWENCODE: //set encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCGIWAP: //get access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCSIWAP: //set access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCGIWMODE: //get operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_giwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCSIWMODE: //set operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_siwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCGIWSENS: //get sensitivity (dBm) ++ case SIOCSIWSENS: //set sensitivity (dBm) ++ case SIOCGIWPOWER: //get Power Management settings ++ case SIOCSIWPOWER: //set Power Management settings ++ case SIOCGIWTXPOW: //get transmit power (dBm) ++ case SIOCSIWTXPOW: //set transmit power (dBm) ++ case SIOCGIWRANGE: //Get range of parameters ++ case SIOCGIWRETRY: //get retry limits and lifetime ++ case SIOCSIWRETRY: //set retry limits and lifetime ++ Status = -EOPNOTSUPP; ++ break; ++ case RT_PRIV_IOCTL: ++ subcmd = wrq->u.data.flags; ++ if( subcmd & OID_GET_SET_TOGGLE) ++ Status = RTMPSetInformation(pAd, rq, subcmd); ++ else ++ Status = RTMPQueryInformation(pAd, rq, subcmd); ++ break; ++ case SIOCGIWPRIV: ++ if (wrq->u.data.pointer) ++ { ++ if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) ++ break; ++ wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); ++ if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) ++ Status = -EFAULT; ++ } ++ break; ++ case RTPRIV_IOCTL_SET: ++ if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) ++ break; ++ rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); ++ break; ++ case RTPRIV_IOCTL_GSITESURVEY: ++ RTMPIoctlGetSiteSurvey(pAd, wrq); ++ break; ++#ifdef DBG ++ case RTPRIV_IOCTL_MAC: ++ RTMPIoctlMAC(pAd, wrq); ++ break; ++ case RTPRIV_IOCTL_E2P: ++ RTMPIoctlE2PROM(pAd, wrq); ++ break; ++#endif // DBG // ++ case SIOCETHTOOL: ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ if(StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set SSID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_SSID Ssid, *pSsid=NULL; ++ BOOLEAN StateMachineTouched = FALSE; ++ int success = TRUE; ++ ++ if( strlen(arg) <= MAX_LEN_OF_SSID) ++ { ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ if (strlen(arg) != 0) ++ { ++ NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); ++ Ssid.SsidLength = strlen(arg); ++ } ++ else //ANY ssid ++ { ++ Ssid.SsidLength = 0; ++ memcpy(Ssid.Ssid, "", 0); ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; ++ } ++ pSsid = &Ssid; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ pAdapter->bConfigChanged = TRUE; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ (VOID *)pSsid); ++ ++ StateMachineTouched = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ } ++ else ++ success = FALSE; ++ ++ if (StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAdapter); ++ ++ return success; ++} ++ ++#ifdef WMM_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WmmCapable Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN bWmmCapable; ++ ++ bWmmCapable = simple_strtol(arg, 0, 10); ++ ++ if ((bWmmCapable == 1) ++#ifdef RT2870 ++ && (pAd->NumberOfPipes >= 5) ++#endif // RT2870 // ++ ) ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ else if (bWmmCapable == 0) ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", ++ pAd->CommonCfg.bWmmCapable)); ++ ++ return TRUE; ++} ++#endif // WMM_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Set Network Type(Infrastructure/Adhoc mode) ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UINT32 Value = 0; ++ ++ if (strcmp(arg, "Adhoc") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_ADHOC) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (INFRA_ON(pAdapter)) ++ { ++ //BOOLEAN Cancelled; ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_ADHOC; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); ++ } ++ else if (strcmp(arg, "Infra") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_INFRA) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (ADHOC_ON(pAdapter)) ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); ++ ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ } ++ else if (strcmp(arg, "Monitor") == 0) ++ { ++ UCHAR bbpValue = 0; ++ BCN_TIME_CFG_STRUC csr; ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ // disable all periodic state machine ++ pAdapter->StaCfg.bAutoReconnect = FALSE; ++ // reset all mlme state machine ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); ++ if (pAdapter->CommonCfg.CentralChannel == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ pAdapter->CommonCfg.CentralChannel = 36; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAdapter->CommonCfg.CentralChannel = 6; ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ N_ChannelCheck(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ // 40MHz ,control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) ++ { ++ // 40MHz ,control channel at upper ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value |= 0x1; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // 20MHz ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_20; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); ++ } ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); ++ // ASIC supporsts sniffer function with replacing RSSI with timestamp. ++ //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ //Value |= (0x80); ++ //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ // disable sync ++ RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); ++ ++ pAdapter->StaCfg.BssType = BSS_MONITOR; ++ pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Authentication mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Encryption Type ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Default Key ID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ ULONG KeyIdx; ++ ++ KeyIdx = simple_strtol(arg, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY1 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ ++ pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 0, ++ pAdapter->SharedKey[BSS0][0].CipherAlg, ++ pAdapter->SharedKey[BSS0][0].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ ++ Description: ++ Set WEP KEY2 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 1, ++ pAdapter->SharedKey[BSS0][1].CipherAlg, ++ pAdapter->SharedKey[BSS0][1].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY3 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 2, ++ pAdapter->SharedKey[BSS0][2].CipherAlg, ++ pAdapter->SharedKey[BSS0][2].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY4 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 3, ++ pAdapter->SharedKey[BSS0][3].CipherAlg, ++ pAdapter->SharedKey[BSS0][3].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WPA PSK key ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UCHAR keyMaterial[40]; ++ ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return TRUE; // do nothing ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); ++ ++ NdisZeroMemory(keyMaterial, 40); ++ ++ if ((strlen(arg) < 8) || (strlen(arg) > 64)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); ++ return FALSE; ++ } ++ ++ if (strlen(arg) == 64) ++ { ++ AtoH(arg, keyMaterial, 32); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else ++ { ++ PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ } ++ ++ ++ ++ if(pAdapter->StaCfg.BssType == BSS_ADHOC && ++ pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ } ++ else ++ { ++ // Start STA supplicant state machine ++ pAdapter->StaCfg.WpaState = SS_START; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Power Saving mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(arg, "Max_PSP") == 0) || ++ (strcmp(arg, "max_psp") == 0) || ++ (strcmp(arg, "MAX_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ pAdapter->StaCfg.DefaultListenCount = 5; ++ ++ } ++ else if ((strcmp(arg, "Fast_PSP") == 0) || ++ (strcmp(arg, "fast_psp") == 0) || ++ (strcmp(arg, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(arg, "Legacy_PSP") == 0) || ++ (strcmp(arg, "legacy_psp") == 0) || ++ (strcmp(arg, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { ++ //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAdapter, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); ++ } ++ else ++ return FALSE; ++ ++ ++ return TRUE; ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WpaSupport flag. ++ Value: ++ 0: Driver ignore wpa_supplicant. ++ 1: wpa_supplicant initiates scanning and AP selection. ++ 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ if ( simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ else if ( simple_strtol(arg, 0, 10) == 1) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++ else if ( simple_strtol(arg, 0, 10) == 2) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; ++ else ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); ++ ++ return TRUE; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ Read / Write MAC ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 ++ 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 ++ ========================================================================== ++*/ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ ULONG macAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ UINT32 macValue = 0; ++ INT Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // Mac Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ if (macAddr < 0xFFFF) ++ { ++ RTMP_IO_READ32(pAdapter, macAddr, &macValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[8-k+j] = temp2[j]; ++ } ++ ++ while(k < 8) ++ temp2[7-k++]='0'; ++ temp2[8]='\0'; ++ ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 4); ++ macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; ++ ++ // debug mode ++ if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) ++ { ++ // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning ++ if (macValue & 0x000000ff) ++ { ++ pAdapter->BbpTuning.bEnable = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); ++ } ++ else ++ { ++ UCHAR R66; ++ pAdapter->BbpTuning.bEnable = FALSE; ++ R66 = 0x26 + GET_LNA_GAIN(pAdapter); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); ++ } ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); ++ ++ RTMP_IO_WRITE32(pAdapter, macAddr, macValue); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); ++ } ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Read / Write E2PROM ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 ++ 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 ++ ========================================================================== ++*/ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ USHORT eepAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ USHORT eepValue; ++ int Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ ++ ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // E2PROM addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ if (eepAddr < 0xFFFF) ++ { ++ RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[4-k+j] = temp2[j]; ++ } ++ ++ while(k < 4) ++ temp2[3-k++]='0'; ++ temp2[4]='\0'; ++ ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 2); ++ eepValue = *temp*256 + temp[1]; ++ ++ RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); ++} ++#endif // DBG // ++ ++ ++ ++ ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); ++ return TRUE; ++} ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++ else if (simple_strtol(arg, 0, 10) == 1) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; ++ else if (simple_strtol(arg, 0, 10) == 2) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; ++ else ++ return FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); ++ return TRUE; ++} ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ return TRUE; ++} ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ ++INT Show_Adhoc_MacTable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PCHAR extra) ++{ ++ INT i; ++ ++ sprintf(extra, "\n"); ++ ++#ifdef DOT11_N_SUPPORT ++ sprintf(extra, "%sHT Operating Mode : %d\n", extra, pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); ++#endif // DOT11_N_SUPPORT // ++ ++ sprintf(extra, "%s\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", extra, ++ "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); ++ ++ for (i=1; iMacTab.Content[i]; ++ ++ if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ { ++ sprintf(extra, "%s%02X:%02X:%02X:%02X:%02X:%02X ", extra, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ sprintf(extra, "%s%-4d", extra, (int)pEntry->Aid); ++ sprintf(extra, "%s%-4d", extra, (int)pEntry->apidx); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi0); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi1); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi2); ++ sprintf(extra, "%s%-10s", extra, GetPhyMode(pEntry->HTPhyMode.field.MODE)); ++ sprintf(extra, "%s%-6s", extra, GetBW(pEntry->HTPhyMode.field.BW)); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.MCS); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.ShortGI); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.STBC); ++ sprintf(extra, "%s%-10d, %d, %d%%\n", extra, pEntry->DebugFIFOCount, pEntry->DebugTxCount, ++ (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); ++ sprintf(extra, "%s\n", extra); ++ } ++ } ++ ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/tmp61 +@@ -0,0 +1,7037 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sta_ioctl.c ++ ++ Abstract: ++ IOCTL related subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 01-03-2003 created ++ Rory Chen 02-14-2005 modify to support RT61 ++*/ ++ ++#include "rt_config.h" ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++#endif ++ ++#define NR_WEP_KEYS 4 ++#define WEP_SMALL_KEY_LEN (40/8) ++#define WEP_LARGE_KEY_LEN (104/8) ++ ++#define GROUP_KEY_NO 4 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) ++#else ++#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) ++#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) ++#endif ++ ++extern UCHAR CipherWpa2Template[]; ++extern UCHAR CipherWpaPskTkip[]; ++extern UCHAR CipherWpaPskTkipLen; ++ ++typedef struct PACKED _RT_VERSION_INFO{ ++ UCHAR DriverVersionW; ++ UCHAR DriverVersionX; ++ UCHAR DriverVersionY; ++ UCHAR DriverVersionZ; ++ UINT DriverBuildYear; ++ UINT DriverBuildMonth; ++ UINT DriverBuildDay; ++} RT_VERSION_INFO, *PRT_VERSION_INFO; ++ ++struct iw_priv_args privtab[] = { ++{ RTPRIV_IOCTL_SET, ++ IW_PRIV_TYPE_CHAR | 1024, 0, ++ "set"}, ++ ++{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++/* --- sub-ioctls definitions --- */ ++ { SHOW_CONN_STATUS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, ++ { SHOW_DRVIER_VERION, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, ++ { SHOW_BA_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, ++ { SHOW_DESC_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, ++ { RAIO_OFF, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, ++ { RAIO_ON, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, ++#ifdef QOS_DLS_SUPPORT ++ { SHOW_DLS_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, ++#endif // QOS_DLS_SUPPORT // ++ { SHOW_CFG_VALUE, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, ++ { SHOW_ADHOC_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "adhocEntry" }, ++ ++/* --- sub-ioctls relations --- */ ++ ++#ifdef DBG ++{ RTPRIV_IOCTL_BBP, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "bbp"}, ++{ RTPRIV_IOCTL_MAC, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "mac"}, ++{ RTPRIV_IOCTL_E2P, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "e2p"}, ++#endif /* DBG */ ++ ++{ RTPRIV_IOCTL_STATISTICS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "stat"}, ++{ RTPRIV_IOCTL_GSITESURVEY, ++ 0, IW_PRIV_TYPE_CHAR | 1024, ++ "get_site_survey"}, ++}; ++ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WMM_SUPPORT ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++VOID RTMPIoctlBBP( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++#endif // DBG // ++ ++ ++NDIS_STATUS RTMPWPANoneAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++INT Set_FragTest_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++INT Show_Adhoc_MacTable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PCHAR extra); ++ ++static struct { ++ CHAR *name; ++ INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { ++ {"DriverVersion", Set_DriverVersion_Proc}, ++ {"CountryRegion", Set_CountryRegion_Proc}, ++ {"CountryRegionABand", Set_CountryRegionABand_Proc}, ++ {"SSID", Set_SSID_Proc}, ++ {"WirelessMode", Set_WirelessMode_Proc}, ++ {"TxBurst", Set_TxBurst_Proc}, ++ {"TxPreamble", Set_TxPreamble_Proc}, ++ {"TxPower", Set_TxPower_Proc}, ++ {"Channel", Set_Channel_Proc}, ++ {"BGProtection", Set_BGProtection_Proc}, ++ {"RTSThreshold", Set_RTSThreshold_Proc}, ++ {"FragThreshold", Set_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Set_HtBw_Proc}, ++ {"HtMcs", Set_HtMcs_Proc}, ++ {"HtGi", Set_HtGi_Proc}, ++ {"HtOpMode", Set_HtOpMode_Proc}, ++ {"HtExtcha", Set_HtExtcha_Proc}, ++ {"HtMpduDensity", Set_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Set_HtBaWinSize_Proc}, ++ {"HtRdg", Set_HtRdg_Proc}, ++ {"HtAmsdu", Set_HtAmsdu_Proc}, ++ {"HtAutoBa", Set_HtAutoBa_Proc}, ++ {"HtBaDecline", Set_BADecline_Proc}, ++ {"HtProtect", Set_HtProtect_Proc}, ++ {"HtMimoPs", Set_HtMimoPs_Proc}, ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Set_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Set_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Set_IEEE80211H_Proc}, ++ {"NetworkType", Set_NetworkType_Proc}, ++ {"AuthMode", Set_AuthMode_Proc}, ++ {"EncrypType", Set_EncrypType_Proc}, ++ {"DefaultKeyID", Set_DefaultKeyID_Proc}, ++ {"Key1", Set_Key1_Proc}, ++ {"Key2", Set_Key2_Proc}, ++ {"Key3", Set_Key3_Proc}, ++ {"Key4", Set_Key4_Proc}, ++ {"WPAPSK", Set_WPAPSK_Proc}, ++ {"ResetCounter", Set_ResetStatCounter_Proc}, ++ {"PSMode", Set_PSMode_Proc}, ++#ifdef DBG ++ {"Debug", Set_Debug_Proc}, ++#endif ++ ++#ifdef RALINK_ATE ++ {"ATE", Set_ATE_Proc}, ++ {"ATEDA", Set_ATE_DA_Proc}, ++ {"ATESA", Set_ATE_SA_Proc}, ++ {"ATEBSSID", Set_ATE_BSSID_Proc}, ++ {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, ++ {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, ++ {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, ++ {"ATETXANT", Set_ATE_TX_Antenna_Proc}, ++ {"ATERXANT", Set_ATE_RX_Antenna_Proc}, ++ {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, ++ {"ATETXBW", Set_ATE_TX_BW_Proc}, ++ {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, ++ {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, ++ {"ATETXMCS", Set_ATE_TX_MCS_Proc}, ++ {"ATETXMODE", Set_ATE_TX_MODE_Proc}, ++ {"ATETXGI", Set_ATE_TX_GI_Proc}, ++ {"ATERXFER", Set_ATE_RX_FER_Proc}, ++ {"ATERRF", Set_ATE_Read_RF_Proc}, ++ {"ATEWRF1", Set_ATE_Write_RF1_Proc}, ++ {"ATEWRF2", Set_ATE_Write_RF2_Proc}, ++ {"ATEWRF3", Set_ATE_Write_RF3_Proc}, ++ {"ATEWRF4", Set_ATE_Write_RF4_Proc}, ++ {"ATELDE2P", Set_ATE_Load_E2P_Proc}, ++ {"ATERE2P", Set_ATE_Read_E2P_Proc}, ++ {"ATESHOW", Set_ATE_Show_Proc}, ++ {"ATEHELP", Set_ATE_Help_Proc}, ++ ++#ifdef RALINK_28xx_QA ++ {"TxStop", Set_TxStop_Proc}, ++ {"RxStop", Set_RxStop_Proc}, ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ {"WpaSupport", Set_Wpa_Support}, ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++ {"FixedTxMode", Set_FixedTxMode_Proc}, ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ {"OpMode", Set_OpMode_Proc}, ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++#ifdef DOT11_N_SUPPORT ++ {"TGnWifiTest", Set_TGnWifiTest_Proc}, ++ {"ForceGF", Set_ForceGF_Proc}, ++#endif // DOT11_N_SUPPORT // ++#ifdef QOS_DLS_SUPPORT ++ {"DlsAddEntry", Set_DlsAddEntry_Proc}, ++ {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, ++#endif // QOS_DLS_SUPPORT // ++ {"LongRetry", Set_LongRetryLimit_Proc}, ++ {"ShortRetry", Set_ShortRetryLimit_Proc}, ++#ifdef EXT_BUILD_CHANNEL_LIST ++ {"11dClientMode", Set_Ieee80211dClientMode_Proc}, ++#endif // EXT_BUILD_CHANNEL_LIST // ++#ifdef CARRIER_DETECTION_SUPPORT ++ {"CarrierDetect", Set_CarrierDetect_Proc}, ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ {NULL,} ++}; ++ ++ ++VOID RTMPAddKey( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_802_11_KEY pKey) ++{ ++ ULONG KeyIdx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ NdisZeroMemory(pAd->StaCfg.PMK, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); ++ goto end; ++ } ++ // Update PTK ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else ++ { ++ // Update GTK ++ pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else // dynamic WEP from wpa_supplicant ++ { ++ UCHAR CipherAlg; ++ PUCHAR Key; ++ ++ if(pKey->KeyLength == 32) ++ goto end; ++ ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ ++ if (KeyIdx < 4) ++ { ++ // it is a default shared key, for Pairwise key setting ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ pEntry = MacTableLookup(pAd, pKey->BSSID); ++ ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); ++ ++ // set key material and key length ++ pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // set Cipher type ++ if (pKey->KeyLength == 5) ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; ++ else ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; ++ ++ // Add Pair-wise key to Asic ++ AsicAddPairwiseKeyEntry( ++ pAd, ++ pEntry->Addr, ++ (UCHAR)pEntry->Aid, ++ &pEntry->PairwiseKey); ++ ++ // update WCID attribute table and IVEIV table for this entry ++ RTMPAddWcidAttributeEntry( ++ pAd, ++ BSS0, ++ KeyIdx, // The value may be not zero ++ pEntry->PairwiseKey.CipherAlg, ++ pEntry); ++ ++ } ++ } ++ else ++ { ++ // Default key for tx (shared key) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ ++ // set key material and key length ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // Set Ciper type ++ if (pKey->KeyLength == 5) ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; ++ else ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ } ++ } ++ } ++end: ++ return; ++} ++ ++char * rtstrchr(const char * s, int c) ++{ ++ for(; *s != (char) c; ++s) ++ if (*s == '\0') ++ return NULL; ++ return (char *) s; ++} ++ ++/* ++This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function ++*/ ++ ++int ++rt_ioctl_giwname(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++#ifdef RT2870 ++ strncpy(name, "RT2870 Wireless", IFNAMSIZ); ++#endif // RT2870 // ++ return 0; ++} ++ ++int rt_ioctl_siwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int chan = -1; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ ++ if (freq->e > 1) ++ return -EINVAL; ++ ++ if((freq->e == 0) && (freq->m <= 1000)) ++ chan = freq->m; // Setting by channel number ++ else ++ MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, ++ ++ if (ChannelSanity(pAdapter, chan) == TRUE) ++ { ++ pAdapter->CommonCfg.Channel = chan; ++ DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); ++ } ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++int rt_ioctl_giwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter = NULL; ++ UCHAR ch; ++ ULONG m; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ch = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); ++ ++ MAP_CHANNEL_ID_TO_KHZ(ch, m); ++ freq->m = m * 100; ++ freq->e = 1; ++ return 0; ++} ++ ++int rt_ioctl_siwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (*mode) ++ { ++ case IW_MODE_ADHOC: ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ break; ++ case IW_MODE_INFRA: ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ break; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ case IW_MODE_MONITOR: ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ break; ++#endif ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); ++ return -EINVAL; ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (ADHOC_ON(pAdapter)) ++ *mode = IW_MODE_ADHOC; ++ else if (INFRA_ON(pAdapter)) ++ *mode = IW_MODE_INFRA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ else if (MONITOR_ON(pAdapter)) ++ { ++ *mode = IW_MODE_MONITOR; ++ } ++#endif ++ else ++ *mode = IW_MODE_AUTO; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); ++ return 0; ++} ++ ++int rt_ioctl_siwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ return 0; ++} ++ ++int rt_ioctl_giwrange(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ struct iw_range *range = (struct iw_range *) extra; ++ u16 val; ++ int i; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_DBM; ++ ++ if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) ++ { ++ range->min_pmp = 1 * 1024; ++ range->max_pmp = 65535 * 1024; ++ range->min_pmt = 1 * 1024; ++ range->max_pmt = 1000 * 1024; ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_TIMEOUT; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | ++ IW_POWER_UNICAST_R | IW_POWER_ALL_R; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 14; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = pAdapter->ChannelListNum; ++ ++ val = 0; ++ for (i = 1; i <= range->num_channels; i++) ++ { ++ u32 m; ++ range->freq[val].i = pAdapter->ChannelList[i-1].Channel; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); ++ range->freq[val].m = m * 100; /* HZ */ ++ ++ range->freq[val].e = 1; ++ val++; ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ range->num_frequency = val; ++ ++ range->max_qual.qual = 100; /* what is correct max? This was not ++ * documented exactly. At least ++ * 69 has been observed. */ ++ range->max_qual.level = 0; /* dB */ ++ range->max_qual.noise = 0; /* dB */ ++ ++ /* What would be suitable values for "average/typical" qual? */ ++ range->avg_qual.qual = 20; ++ range->avg_qual.level = -60; ++ range->avg_qual.noise = -95; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = NR_WEP_KEYS; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++#if WIRELESS_EXT > 17 ++ /* IW_ENC_CAPA_* bit field */ ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ return 0; ++} ++ ++int rt_ioctl_siwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ memset(Bssid, 0, MAC_ADDR_LEN); ++ memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ ++ return 0; ++} ++ ++int rt_ioctl_giwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); ++ return -ENOTCONN; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Units are in db above the noise floor. That means the ++ * rssi values reported in the tx/rx descriptors in the ++ * driver are the SNR expressed in db. ++ * ++ * If you assume that the noise floor is -95, which is an ++ * excellent assumption 99.5 % of the time, then you can ++ * derive the absolute signal level (i.e. -95 + rssi). ++ * There are some other slight factors to take into account ++ * depending on whether the rssi measurement is from 11b, ++ * 11g, or 11a. These differences are at most 2db and ++ * can be documented. ++ * ++ * NB: various calculations are based on the orinoco/wavelan ++ * drivers for compatibility ++ */ ++static void set_quality(PRTMP_ADAPTER pAdapter, ++ struct iw_quality *iq, ++ signed char rssi) ++{ ++ __u8 ChannelQuality; ++ ++ // Normalize Rssi ++ if (rssi >= -50) ++ ChannelQuality = 100; ++ else if (rssi >= -80) // between -50 ~ -80dbm ++ ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); ++ else if (rssi >= -90) // between -80 ~ -90dbm ++ ChannelQuality = (__u8)((rssi + 90) * 26)/10; ++ else ++ ChannelQuality = 0; ++ ++ iq->qual = (__u8)ChannelQuality; ++ ++ iq->level = (__u8)(rssi); ++ iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) ++ iq->noise += 256 - 143; ++ iq->updated = pAdapter->iw_stats.qual.updated; ++} ++ ++int rt_ioctl_iwaplist(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ struct sockaddr addr[IW_MAX_AP]; ++ struct iw_quality qual[IW_MAX_AP]; ++ int i; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ data->length = 0; ++ return 0; ++ //return -ENETDOWN; ++ } ++ ++ for (i = 0; i = pAdapter->ScanTab.BssNr) ++ break; ++ addr[i].sa_family = ARPHRD_ETHER; ++ memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); ++ } ++ data->length = i; ++ memcpy(extra, &addr, i*sizeof(addr[0])); ++ data->flags = 1; /* signal quality present (sort of) */ ++ memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); ++ ++ return 0; ++} ++ ++#ifdef SIOCGIWSCAN ++int rt_ioctl_siwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ULONG Now; ++ int Status = NDIS_STATUS_SUCCESS; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ return -EINVAL; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount++; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return 0; ++ do{ ++ Now = jiffies; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && ++ (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ RT28XX_MLME_HANDLER(pAdapter); ++ }while(0); ++ return 0; ++} ++ ++int rt_ioctl_giwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ int i=0; ++ char *current_ev = extra, *previous_ev = extra; ++ char *end_buf; ++ char *current_val, custom[MAX_CUSTOM_LEN] = {0}; ++#ifndef IWEVGENIE ++ char idx; ++#endif // IWEVGENIE // ++ struct iw_event iwe; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ return -EAGAIN; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount = 0; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if (pAdapter->ScanTab.BssNr == 0) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++#if WIRELESS_EXT >= 17 ++ if (data->length > 0) ++ end_buf = extra + data->length; ++ else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#endif ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ if (current_ev >= end_buf) ++ { ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //MAC address ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //ESSID ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ iwe.u.data.flags = 1; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev,end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Network Type ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) ++ { ++ iwe.u.mode = IW_MODE_ADHOC; ++ } ++ else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) ++ { ++ iwe.u.mode = IW_MODE_INFRA; ++ } ++ else ++ { ++ iwe.u.mode = IW_MODE_AUTO; ++ } ++ iwe.len = IW_EV_UINT_LEN; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Channel and Frequency ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ else ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev,end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Add quality statistics ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.level = 0; ++ iwe.u.qual.noise = 0; ++ set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); ++ current_ev = IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Encyption key ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) ++ iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Bit Rate ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].SupRateLen) ++ { ++ UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWRATE; ++ current_val = current_ev + IW_EV_LCP_LEN; ++ if (tmpRate == 0x82) ++ iwe.u.bitrate.value = 1 * 1000000; ++ else if (tmpRate == 0x84) ++ iwe.u.bitrate.value = 2 * 1000000; ++ else if (tmpRate == 0x8B) ++ iwe.u.bitrate.value = 5.5 * 1000000; ++ else if (tmpRate == 0x96) ++ iwe.u.bitrate.value = 11 * 1000000; ++ else ++ iwe.u.bitrate.value = (tmpRate/2) * 1000000; ++ ++ iwe.u.bitrate.disabled = 0; ++ current_val = IWE_STREAM_ADD_VALUE(info, current_ev, ++ current_val, end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ ++ if((current_val-current_ev)>IW_EV_LCP_LEN) ++ current_ev = current_val; ++ else ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++#ifdef IWEVGENIE ++ //WPA IE ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#else ++ //WPA IE ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "wpa_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "rsn_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#endif // IWEVGENIE // ++ } ++ ++ data->length = current_ev - extra; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); ++ return 0; ++} ++#endif ++ ++int rt_ioctl_siwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->flags) ++ { ++ PCHAR pSsidString = NULL; ++ ++ // Includes null character. ++ if (data->length > (IW_ESSID_MAX_SIZE + 1)) ++ return -E2BIG; ++ ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, essid, data->length); ++ if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) ++ return -EINVAL; ++ } ++ else ++ return -ENOMEM; ++ } ++ else ++ { ++ // ANY ssid ++ if (Set_SSID_Proc(pAdapter, "") == FALSE) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int rt_ioctl_giwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ data->flags = 1; ++ if (MONITOR_ON(pAdapter)) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#ifdef RT2870 ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // RT2870 // ++ else ++ {//the ANY ssid was specified ++ data->length = 0; ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); ++ } ++ ++ return 0; ++ ++} ++ ++int rt_ioctl_siwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->length > IW_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); ++ memcpy(pAdapter->nickname, nickname, data->length); ++ ++ ++ return 0; ++} ++ ++int rt_ioctl_giwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (data->length > strlen(pAdapter->nickname) + 1) ++ data->length = strlen(pAdapter->nickname) + 1; ++ if (data->length > 0) { ++ memcpy(nickname, pAdapter->nickname, data->length-1); ++ nickname[data->length-1] = '\0'; ++ } ++ return 0; ++} ++ ++int rt_ioctl_siwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (rts->disabled) ++ val = MAX_RTS_THRESHOLD; ++ else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ else if (rts->value == 0) ++ val = MAX_RTS_THRESHOLD; ++ else ++ val = rts->value; ++ ++ if (val != pAdapter->CommonCfg.RtsThreshold) ++ pAdapter->CommonCfg.RtsThreshold = val; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ rts->value = pAdapter->CommonCfg.RtsThreshold; ++ rts->disabled = (rts->value == MAX_RTS_THRESHOLD); ++ rts->fixed = 1; ++ ++ return 0; ++} ++ ++int rt_ioctl_siwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (frag->disabled) ++ val = MAX_FRAG_THRESHOLD; ++ else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) ++ val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ ++ else if (frag->value == 0) ++ val = MAX_FRAG_THRESHOLD; ++ else ++ return -EINVAL; ++ ++ pAdapter->CommonCfg.FragmentThreshold = val; ++ return 0; ++} ++ ++int rt_ioctl_giwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ frag->value = pAdapter->CommonCfg.FragmentThreshold; ++ frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); ++ frag->fixed = 1; ++ ++ return 0; ++} ++ ++#define MAX_WEP_KEY_SIZE 13 ++#define MIN_WEP_KEY_SIZE 5 ++int rt_ioctl_siwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_DISABLED)) ++ { ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ else if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN)) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ if (erq->flags & IW_ENCODE_RESTRICTED) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ ++ if (erq->length > 0) ++ { ++ int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; ++ /* Check the size of the key */ ++ if (erq->length > MAX_WEP_KEY_SIZE) { ++ return -EINVAL; ++ } ++ /* Check key index */ ++ if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", ++ keyIdx, pAdapter->StaCfg.DefaultKeyId)); ++ ++ //Using default key ++ keyIdx = pAdapter->StaCfg.DefaultKeyId; ++ } ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ ++ if (erq->length == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (erq->length == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ /* Disable the key */ ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ ++ /* Check if the key is not marked as invalid */ ++ if(!(erq->flags & IW_ENCODE_NOKEY)) { ++ /* Copy the key in the driver */ ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); ++ } ++ } ++ else ++ { ++ /* Do we want to just set the transmit key index ? */ ++ int index = (erq->flags & IW_ENCODE_INDEX) - 1; ++ if ((index >= 0) && (index < 4)) ++ { ++ pAdapter->StaCfg.DefaultKeyId = index; ++ } ++ else ++ /* Don't complain if only change the mode */ ++ if(!erq->flags & IW_ENCODE_MODE) { ++ return -EINVAL; ++ } ++ } ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); ++ return 0; ++} ++ ++int ++rt_ioctl_giwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ int kid; ++ PRTMP_ADAPTER pAdapter = NULL; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ if (pVirtualAd && pVirtualAd->RtmpDev) ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ kid = erq->flags & IW_ENCODE_INDEX; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); ++ ++ if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ++ { ++ erq->length = 0; ++ erq->flags = IW_ENCODE_DISABLED; ++ } ++ else if ((kid > 0) && (kid <=4)) ++ { ++ // copy wep key ++ erq->flags = kid ; /* NB: base 1 */ ++ if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) ++ erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); ++ //if ((kid == pAdapter->PortCfg.DefaultKeyId)) ++ //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ ++ } ++ else if (kid == 0) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); ++ // copy default key ID ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ ++ erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ } ++ ++ return 0; ++ ++} ++ ++static int ++rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter; ++ POS_COOKIE pObj; ++ char *this_char = extra; ++ char *value; ++ int Status=0; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->priv; ++ } ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAdapter = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAdapter->OS_Cookie; ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (!*this_char) ++ return -EINVAL; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value) ++ return -EINVAL; ++ ++ // reject setting nothing besides ANY ssid(ssidLen=0) ++ if (!*value && (strcmp(this_char, "SSID") != 0)) ++ return -EINVAL; ++ ++ for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) ++ { ++ if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) ++ { ++ if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) ++ { //FALSE:Set private failed then return Invalid argument ++ Status = -EINVAL; ++ } ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_SET_PROC->name == NULL) ++ { //Not found argument ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); ++ } ++ ++ return Status; ++} ++ ++ ++static int ++rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n\n"); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ } ++ sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); ++ sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->ate.RxAntennaSel == 0) ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++ else ++ { ++ sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); ++ ++ return Status; ++} ++ ++#ifdef DOT11_N_SUPPORT ++void getBaInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pOutBuf) ++{ ++ INT i, j; ++ BA_ORI_ENTRY *pOriBAEntry; ++ BA_REC_ENTRY *pRecBAEntry; ++ ++ for (i=0; iMacTab.Content[i]; ++ if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) ++ { ++ sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", ++ pOutBuf, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); ++ ++ sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BARecWcidArray[j] != 0) ++ { ++ pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); ++ } ++ } ++ sprintf(pOutBuf, "%s\n", pOutBuf); ++ ++ sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BAOriWcidArray[j] != 0) ++ { ++ pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); ++ } ++ } ++ sprintf(pOutBuf, "%s\n\n", pOutBuf); ++ } ++ if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ } ++ ++ return; ++} ++#endif // DOT11_N_SUPPORT // ++ ++static int ++rt_private_show(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ u32 subcmd = wrq->flags; ++ ++ if (dev->priv_flags == INT_MAIN) ++ pAd = dev->priv; ++ else ++ { ++ pVirtualAd = dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(subcmd) ++ { ++ ++ case SHOW_CONN_STATUS: ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW) ++ sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); ++ else ++#endif // DOT11_N_SUPPORT // ++ sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); ++ } ++ else ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", ++ pAd->CommonCfg.Ssid, ++ pAd->CommonCfg.Bssid[0], ++ pAd->CommonCfg.Bssid[1], ++ pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3], ++ pAd->CommonCfg.Bssid[4], ++ pAd->CommonCfg.Bssid[5]); ++ DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); ++ } ++ else if (ADHOC_ON(pAd)) ++ sprintf(extra, "Connected\n"); ++ } ++ else ++ { ++ sprintf(extra, "Disconnected\n"); ++ DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); ++ } ++ } ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case SHOW_DRVIER_VERION: ++ sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#ifdef DOT11_N_SUPPORT ++ case SHOW_BA_INFO: ++ getBaInfo(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SHOW_DESC_INFO: ++ { ++ Show_DescInfo_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++ case RAIO_OFF: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = FALSE; ++ if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ sprintf(extra, "Radio Off\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case RAIO_ON: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = TRUE; ++ //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ } ++ sprintf(extra, "Radio On\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case SHOW_DLS_ENTRY_INFO: ++ { ++ Set_DlsEntryInfo_Display_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ case SHOW_CFG_VALUE: ++ { ++ Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); ++ if (Status == 0) ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ } ++ break; ++ case SHOW_ADHOC_ENTRY_INFO: ++ Show_Adhoc_MacTable_Proc(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); ++ break; ++ } ++ ++ return Status; ++} ++ ++#ifdef SIOCSIWMLME ++int rt_ioctl_siwmlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; ++ MLME_QUEUE_ELEM MsgElem; ++ MLME_DISASSOC_REQ_STRUCT DisAssocReq; ++ MLME_DEAUTH_REQ_STRUCT DeAuthReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); ++ ++ if (pMlme == NULL) ++ return -EINVAL; ++ ++ switch(pMlme->cmd) ++ { ++#ifdef IW_MLME_DEAUTH ++ case IW_MLME_DEAUTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); ++ DeAuthReq.Reason = pMlme->reason_code; ++ MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); ++ MlmeDeauthReqAction(pAd, &MsgElem); ++ if (INFRA_ON(pAd)) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ break; ++#endif // IW_MLME_DEAUTH // ++#ifdef IW_MLME_DISASSOC ++ case IW_MLME_DISASSOC: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); ++ DisAssocReq.Reason = pMlme->reason_code; ++ ++ MsgElem.Machine = ASSOC_STATE_MACHINE; ++ MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, &MsgElem); ++ break; ++#endif // IW_MLME_DISASSOC // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); ++ break; ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWMLME // ++ ++#if WIRELESS_EXT > 17 ++int rt_ioctl_siwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ if (param->value == IW_AUTH_WPA_VERSION_WPA) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ } ++ else if (param->value == IW_AUTH_WPA_VERSION_WPA2) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_KEY_MGMT: ++ if (param->value == IW_AUTH_KEY_MGMT_802_1X) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else ++ // WEP 1x ++ pAdapter->StaCfg.IEEE8021X = TRUE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == 0) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ /*if (param->value == 0) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ }*/ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ if (param->value != 0) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ } ++ else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ } ++ else ++ return -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); ++ break; ++ default: ++ return -EOPNOTSUPP; ++} ++ ++ return 0; ++} ++ ++int rt_ioctl_giwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); ++ return 0; ++} ++ ++void fnSetCipherKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN INT keyIdx, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bGTK, ++ IN struct iw_encode_ext *ext) ++{ ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ pAdapter->SharedKey[BSS0][keyIdx].Key, ++ pAdapter->SharedKey[BSS0][keyIdx].TxMic, ++ pAdapter->SharedKey[BSS0][keyIdx].RxMic); ++ ++ if (bGTK) ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ NULL); ++ else ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ &pAdapter->MacTab.Content[BSSID_WCID]); ++} ++ ++int rt_ioctl_siwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++ { ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int keyIdx, alg = ext->alg; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ { ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); ++ } ++ else ++ { ++ // Get Key Index and convet to our own defined key index ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ return -EINVAL; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ pAdapter->StaCfg.DefaultKeyId = keyIdx; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); ++ } ++ ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); ++ break; ++ case IW_ENCODE_ALG_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); ++ if (ext->key_len == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (ext->key_len == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ return -EINVAL; ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); ++ if (ext->key_len == 32) ++ { ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else ++ return -EINVAL; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++rt_ioctl_giwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PCHAR pKey = NULL; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) ++ { ++ if (idx < 1 || idx > 4) ++ return -EINVAL; ++ idx--; ++ ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) ++ { ++ if (idx != pAd->StaCfg.DefaultKeyId) ++ { ++ ext->key_len = 0; ++ return 0; ++ } ++ } ++ } ++ else ++ idx = pAd->StaCfg.DefaultKeyId; ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ ext->key_len = 0; ++ switch(pAd->StaCfg.WepStatus) { ++ case Ndis802_11WEPDisabled: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ encoding->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11WEPEnabled: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; ++ pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ else ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ ++ if (max_key_len < 32) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = 32; ++ pKey = &pAd->StaCfg.PMK[0]; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ext->key_len && pKey) ++ { ++ encoding->flags |= IW_ENCODE_ENABLED; ++ memcpy(ext->key, pKey, ext->key_len); ++ } ++ ++ return 0; ++} ++ ++#ifdef SIOCSIWGENIE ++int rt_ioctl_siwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if (wrqu->data.length > MAX_LEN_OF_RSNIE || ++ (wrqu->data.length && extra == NULL)) ++ return -EINVAL; ++ ++ if (wrqu->data.length) ++ { ++ pAd->StaCfg.RSNIE_Len = wrqu->data.length; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); ++ } ++ else ++ { ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWGENIE // ++ ++int rt_ioctl_giwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ ++ if ((pAd->StaCfg.RSNIE_Len == 0) || ++ (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) ++ { ++ wrqu->data.length = 0; ++ return 0; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) ++ return -E2BIG; ++ ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ else ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len ++ return -E2BIG; ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ RSNIe = IE_RSN; ++ ++ extra[0] = (char)RSNIe; ++ extra[1] = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_siwpmksa(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; ++ INT CachedIdx = 0, idx = 0; ++ ++ if (pPmksa == NULL) ++ return -EINVAL; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); ++ switch(pPmksa->cmd) ++ { ++ case IW_PMKSA_FLUSH: ++ NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); ++ break; ++ case IW_PMKSA_REMOVE: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ { ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); ++ for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) ++ { ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); ++ } ++ pAd->StaCfg.SavedPMKNum--; ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); ++ break; ++ case IW_PMKSA_ADD: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ pAd->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); ++ break; ++ } ++ ++ return 0; ++} ++#endif // #if WIRELESS_EXT > 17 ++ ++#ifdef DBG ++static int ++rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++ { ++ CHAR *this_char; ++ CHAR *value = NULL; ++ UCHAR regBBP = 0; ++// CHAR arg[255]={0}; ++ UINT32 bbpId; ++ UINT32 bbpValue; ++ BOOLEAN bIsPrintAllBBP = FALSE; ++ INT Status = 0; ++ PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ if (wrq->length > 1) //No parameters. ++ { ++ sprintf(extra, "\n"); ++ ++ //Parsing Read or Write ++ this_char = wrq->pointer; ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); ++ if (sscanf(this_char, "%d", &(bbpId)) == 1) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Write ++ if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) ++ { ++ if (bbpId <= 136) ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ bIsPrintAllBBP = TRUE; ++ ++next: ++ if (bIsPrintAllBBP) ++ { ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n"); ++ for (bbpId = 0; bbpId <= 136; bbpId++) ++ { ++ if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) ++ break; ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); ++ if (bbpId%5 == 4) ++ sprintf(extra+strlen(extra), "\n"); ++ } ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); ++ ++ return Status; ++} ++#endif // DBG // ++ ++int rt_ioctl_siwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); ++ /* rate = -1 => auto rate ++ rate = X, fixed = 1 => (fixed rate X) ++ */ ++ if (rate == -1) ++ { ++ //Auto Rate ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, -1); ++ ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ else ++ { ++ if (fixed) ++ { ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, rate); ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ // TODO: rate = X, fixed = 0 => (rates <= X) ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ int rate_index = 0, rate_count = 0; ++ HTTRANSMIT_SETTING ht_setting; ++ __s32 ralinkrate[] = ++ {2, 4, 11, 22, // CCK ++ 12, 18, 24, 36, 48, 72, 96, 108, // OFDM ++ 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 ++ 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 ++ 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 ++ 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 ++ 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 ++ 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 ++ 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 ++ 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 ++ ++ rate_count = sizeof(ralinkrate)/sizeof(__s32); ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && ++ (INFRA_ON(pAd)) && ++ ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) ++ ht_setting.word = pAd->StaCfg.HTPhyMode.word; ++ else ++ ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ ++#ifdef DOT11_N_SUPPORT ++ if (ht_setting.field.MODE >= MODE_HTMIX) ++ { ++// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); ++ rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (ht_setting.field.MODE == MODE_OFDM) ++ rate_index = (UCHAR)(ht_setting.field.MCS) + 4; ++ else if (ht_setting.field.MODE == MODE_CCK) ++ rate_index = (UCHAR)(ht_setting.field.MCS); ++ ++ if (rate_index < 0) ++ rate_index = 0; ++ ++ if (rate_index > rate_count) ++ rate_index = rate_count; ++ ++ wrqu->bitrate.value = ralinkrate[rate_index] * 500000; ++ wrqu->bitrate.disabled = 0; ++ ++ return 0; ++} ++ ++static const iw_handler rt_handler[] = ++{ ++ (iw_handler) NULL, /* SIOCSIWCOMMIT */ ++ (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ ++ (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ ++ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ ++ (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ ++ (iw_handler) NULL, /* SIOCSIWSPY */ ++ (iw_handler) NULL, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* SIOCSIWTHRSPY */ ++ (iw_handler) NULL, /* SIOCGIWTHRSPY */ ++ (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ ++ (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ ++#ifdef SIOCSIWMLME ++ (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* SIOCSIWMLME */ ++#endif // SIOCSIWMLME // ++ (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ ++#ifdef SIOCGIWSCAN ++ (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ ++#else ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* SIOCGIWSCAN */ ++ (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ ++ (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ ++ (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ ++ (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) NULL, /* SIOCSIWTXPOW */ ++ (iw_handler) NULL, /* SIOCGIWTXPOW */ ++ (iw_handler) NULL, /* SIOCSIWRETRY */ ++ (iw_handler) NULL, /* SIOCGIWRETRY */ ++ (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) NULL, /* SIOCSIWPOWER */ ++ (iw_handler) NULL, /* SIOCGIWPOWER */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ ++ (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ ++ (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ ++ (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ ++ (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ ++#endif ++}; ++ ++static const iw_handler rt_priv_handlers[] = { ++ (iw_handler) NULL, /* + 0x00 */ ++ (iw_handler) NULL, /* + 0x01 */ ++#ifndef CONFIG_AP_SUPPORT ++ (iw_handler) rt_ioctl_setparam, /* + 0x02 */ ++#else ++ (iw_handler) NULL, /* + 0x02 */ ++#endif // CONFIG_AP_SUPPORT // ++#ifdef DBG ++ (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ ++#else ++ (iw_handler) NULL, /* + 0x03 */ ++#endif ++ (iw_handler) NULL, /* + 0x04 */ ++ (iw_handler) NULL, /* + 0x05 */ ++ (iw_handler) NULL, /* + 0x06 */ ++ (iw_handler) NULL, /* + 0x07 */ ++ (iw_handler) NULL, /* + 0x08 */ ++ (iw_handler) rt_private_get_statistics, /* + 0x09 */ ++ (iw_handler) NULL, /* + 0x0A */ ++ (iw_handler) NULL, /* + 0x0B */ ++ (iw_handler) NULL, /* + 0x0C */ ++ (iw_handler) NULL, /* + 0x0D */ ++ (iw_handler) NULL, /* + 0x0E */ ++ (iw_handler) NULL, /* + 0x0F */ ++ (iw_handler) NULL, /* + 0x10 */ ++ (iw_handler) rt_private_show, /* + 0x11 */ ++ (iw_handler) NULL, /* + 0x12 */ ++ (iw_handler) NULL, /* + 0x13 */ ++ (iw_handler) NULL, /* + 0x15 */ ++ (iw_handler) NULL, /* + 0x17 */ ++ (iw_handler) NULL, /* + 0x18 */ ++}; ++ ++const struct iw_handler_def rt28xx_iw_handler_def = ++{ ++#define N(a) (sizeof (a) / sizeof (a[0])) ++ .standard = (iw_handler *) rt_handler, ++ .num_standard = sizeof(rt_handler) / sizeof(iw_handler), ++ .private = (iw_handler *) rt_priv_handlers, ++ .num_private = N(rt_priv_handlers), ++ .private_args = (struct iw_priv_args *) privtab, ++ .num_private_args = N(privtab), ++#if IW_HANDLER_VERSION >= 7 ++ .get_wireless_stats = rt28xx_get_wireless_stats, ++#endif ++}; ++ ++INT RTMPSetInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ RT_802_11_PHY_MODE PhyMode; ++ RT_802_11_STA_CONFIG StaConfig; ++ NDIS_802_11_RATES aryRates; ++ RT_802_11_PREAMBLE Preamble; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ PNDIS_802_11_KEY pKey = NULL; ++ PNDIS_802_11_WEP pWepKey =NULL; ++ PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; ++ NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; ++ NDIS_802_11_NETWORK_TYPE NetType; ++ ULONG Now; ++ UINT KeyIdx = 0; ++ INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; ++ ULONG PowerTemp; ++ BOOLEAN RadioState; ++ BOOLEAN StateMachineTouched = FALSE; ++#ifdef DOT11_N_SUPPORT ++ OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy ++#endif // DOT11_N_SUPPORT // ++#ifdef WPA_SUPPLICANT_SUPPORT ++ PNDIS_802_11_PMKID pPmkId = NULL; ++ BOOLEAN IEEE8021xState = FALSE; ++ BOOLEAN IEEE8021x_required_keys = FALSE; ++ UCHAR wpa_supplicant_enable = 0; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR ctmp; ++#endif // SNMP_SUPPORT // ++ ++ ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); ++ switch(cmd & 0x7FFF) { ++ case RT_OID_802_11_COUNTRY_REGION: ++ if (wrq->u.data.length < sizeof(UCHAR)) ++ Status = -EINVAL; ++ // Only avaliable when EEPROM not programming ++ else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) ++ { ++ ULONG Country; ++ UCHAR TmpPhy; ++ ++ Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); ++ pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); ++ TmpPhy = pAdapter->CommonCfg.PhyMode; ++ pAdapter->CommonCfg.PhyMode = 0xff; ++ // Build all corresponding channel information ++ RTMPSetPhyMode(pAdapter, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, ++ pAdapter->CommonCfg.CountryRegion)); ++ } ++ break; ++ case OID_802_11_BSSID_LIST_SCAN: ++ #ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ Now = jiffies; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ break; ++ } ++ ++ //Benson add 20080527, when radio off, sta don't need to scan ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) ++ break; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ break; ++ case OID_802_11_SSID: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) ++ Status = -EINVAL; ++ else ++ { ++ PCHAR pSsidString = NULL; ++ Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ if (Ssid.SsidLength > MAX_LEN_OF_SSID) ++ Status = -EINVAL; ++ else ++ { ++ if (Ssid.SsidLength == 0) ++ { ++ Set_SSID_Proc(pAdapter, ""); ++ } ++ else ++ { ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); ++ Set_SSID_Proc(pAdapter, pSsidString); ++ kfree(pSsidString); ++ } ++ else ++ Status = -ENOMEM; ++ } ++ } ++ } ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ } ++ break; ++ case RT_OID_802_11_RADIO: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); ++ if (pAdapter->StaCfg.bSwRadio != RadioState) ++ { ++ pAdapter->StaCfg.bSwRadio = RadioState; ++ if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) ++ { ++ pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); ++ if (pAdapter->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ MlmeRadioOff(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PhyMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAdapter, PhyMode); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); ++ } ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; ++ pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; ++ pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable ++ if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && ++ (StaConfig.AdhocMode <= MaxPhyMode)) ++ { ++ // allow dynamic change of "USE OFDM rate or not" in ADHOC mode ++ // if setting changed, need to reset current TX rate as well as BEACON frame format ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ { ++ pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; ++ RTMPSetPhyMode(pAdapter, PhyMode); ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ MakeIbssBeacon(pAdapter); // re-build BEACON frame ++ AsicEnableIbssSync(pAdapter); // copy to on-chip memory ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", ++ pAdapter->CommonCfg.bEnableTxBurst, ++ pAdapter->CommonCfg.UseBGProtection, ++ pAdapter->CommonCfg.bUseShortSlotTime)); ++ } ++ break; ++ case OID_802_11_DESIRED_RATES: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ } ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); ++ if (Preamble == Rt802_11PreambleShort) ++ { ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); ++ } ++ else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) ++ { ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); ++ } ++ break; ++ case OID_802_11_WEP_STATUS: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); ++ // Since TKIP, AES, WEP are all supported. It should not have any invalid setting ++ if (WepStatus <= Ndis802_11Encryption3KeyAbsent) ++ { ++ if (pAdapter->StaCfg.WepStatus != WepStatus) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.WepStatus = WepStatus; ++ pAdapter->StaCfg.OrigWepStatus = WepStatus; ++ pAdapter->StaCfg.PairCipher = WepStatus; ++ pAdapter->StaCfg.GroupCipher = WepStatus; ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); ++ } ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (AuthMode > Ndis802_11AuthModeMax) ++ { ++ Status = -EINVAL; ++ break; ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode != AuthMode) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.AuthMode = AuthMode; ++ } ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); ++ } ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (BssType == Ndis802_11IBSS) ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ else if (BssType == Ndis802_11Infrastructure) ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ else if (BssType == Ndis802_11Monitor) ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ else ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); ++ } ++ } ++ break; ++ case OID_802_11_REMOVE_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); ++ if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) ++ { ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx >= 4){ ++ Status = -EINVAL; ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_RESET_COUNTERS: ++ NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); ++ pAdapter->Counters8023.RxNoBuffer = 0; ++ pAdapter->Counters8023.GoodReceives = 0; ++ pAdapter->Counters8023.RxNoBuffer = 0; ++#ifdef RT2870 ++ pAdapter->BulkOutComplete = 0; ++ pAdapter->BulkOutCompleteOther= 0; ++ pAdapter->BulkOutCompleteCancel = 0; ++ pAdapter->BulkOutReq = 0; ++ pAdapter->BulkInReq= 0; ++ pAdapter->BulkInComplete = 0; ++ pAdapter->BulkInCompleteFail = 0; ++#endif // RT2870 // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); ++ if (RtsThresh > MAX_RTS_THRESHOLD) ++ Status = -EINVAL; ++ else ++ pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ if (FragThresh == 0) ++ { ++ pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else ++ Status = -EINVAL; ++ } ++ else ++ pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerMode == Ndis802_11PowerModeCAM) ++ Set_PSMode_Proc(pAdapter, "CAM"); ++ else if (PowerMode == Ndis802_11PowerModeMAX_PSP) ++ Set_PSMode_Proc(pAdapter, "Max_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeFast_PSP) ++ Set_PSMode_Proc(pAdapter, "Fast_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) ++ Set_PSMode_Proc(pAdapter, "Legacy_PSP"); ++ else ++ Status = -EINVAL; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ if (wrq->u.data.length < sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerTemp > 100) ++ PowerTemp = 0xffffffff; // AUTO ++ pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. ++ pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ } ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (NetType == Ndis802_11DS) ++ RTMPSetPhyMode(pAdapter, PHY_11B); ++ else if (NetType == Ndis802_11OFDM24) ++ RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); ++ else if (NetType == Ndis802_11OFDM5) ++ RTMPSetPhyMode(pAdapter, PHY_11A); ++ else ++ Status = -EINVAL; ++#ifdef DOT11_N_SUPPORT ++ if (Status == NDIS_STATUS_SUCCESS) ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); ++ } ++ break; ++ // For WPA PSK PMK key ++ case RT_OID_802_11_ADD_WPA: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); ++ } ++ else ++ { ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) ++ { ++ Status = -EOPNOTSUPP; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); ++ } ++ else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode ++ { ++ NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); ++ // Use RaConfig as PSK agent. ++ // Start STA supplicant state machine ++ if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ pAdapter->StaCfg.WpaState = SS_START; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ else ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_REMOVE_KEY: ++ pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pRemoveKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pRemoveKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); ++ } ++ else ++ { ++ KeyIdx = pRemoveKey->KeyIndex; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx > 3) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); ++ } ++ } ++ } ++ } ++ kfree(pRemoveKey); ++ break; ++ // New for WPA ++ case OID_802_11_ADD_KEY: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); ++ } ++ else ++ { ++ RTMPAddKey(pAdapter, pKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_CONFIGURATION: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); ++ pConfig = &Config; ++ ++ if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) ++ pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; ++ ++ pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; ++ MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); ++ // ++ // Save the channel on MlmeAux for CntlOidRTBssidProc used. ++ // ++ pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", ++ pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_HT_PHYMODE: ++ if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) ++ Status = -EINVAL; ++ else ++ { ++ POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; ++ ++ Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", ++ pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ RTMPSetHT(pAdapter, pHTPhyMode); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", ++ pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, ++ pAdapter->StaCfg.HTPhyMode.field.STBC)); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case RT_OID_802_11_SET_APSD_SETTING: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ ULONG apsd ; ++ Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); ++ ++ /*------------------------------------------------------------------- ++ |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | ++ --------------------------------------------------------------------- ++ | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | ++ ---------------------------------------------------------------------*/ ++ pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; ++ pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, ++ pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_APSD_PSM: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ // Driver needs to notify AP when PSM changes ++ Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); ++ if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) ++ { ++ MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); ++ RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ } ++ break; ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; ++ Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); ++ if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) ++ { ++ int i; ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_DLS_PARAM: ++ if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) ++ Status = -EINVAL; ++ else ++ { ++ RT_802_11_DLS Dls; ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ case RT_OID_802_11_SET_WMM: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); ++ } ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ // ++ // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. ++ // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 ++ // when query OID_802_11_BSSID_LIST. ++ // ++ // TRUE: NumberOfItems will set to 0. ++ // FALSE: NumberOfItems no change. ++ // ++ pAdapter->CommonCfg.NdisRadioStateOff = TRUE; ++ // Set to immediately send the media disconnect event ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_DISASSOCIATE, ++ 0, ++ NULL); ++ ++ StateMachineTouched = TRUE; ++ } ++ break; ++ ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_IMME_BA_CAP: ++ if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) ++ Status = -EINVAL; ++ else ++ { ++ OID_BACAP_STRUC Orde ; ++ Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); ++ if (Orde.Policy > BA_NOTUSE) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ } ++ else if (Orde.Policy == BA_NOTUSE) ++ { ++ pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ } ++ else ++ { ++ pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; ++ pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ ++ if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; ++ ++ } ++ ++ pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); ++ } ++ ++ break; ++ case RT_OID_802_11_ADD_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ UCHAR index; ++ OID_ADD_BA_ENTRY BA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); ++ if (BA.TID > 15) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ else ++ { ++ //BATableInsertEntry ++ //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. ++ index = BA.TID; ++ // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too ++ pEntry = MacTableLookup(pAdapter, BA.MACAddr); ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); ++ break; ++ } ++ if (BA.IsRecipient == FALSE) ++ { ++ if (pEntry->bIAmBadAtheros == TRUE) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; ++ ++ BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); ++ } ++ else ++ { ++ //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", ++ BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] ++ , BA.MACAddr[4], BA.MACAddr[5])); ++ } ++ } ++ break; ++ ++ case RT_OID_802_11_TEAR_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ POID_ADD_BA_ENTRY pBA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if (pBA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); ++ ++ if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (pBA->IsRecipient == FALSE) ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); ++ BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ if (pEntry) ++ { ++ BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ kfree(pBA); ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ ++ // For WPA_SUPPLICANT to set static wep key ++ case OID_802_11_ADD_WEP: ++ pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pWepKey == NULL) ++ { ++ Status = -ENOMEM; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); ++ break; ++ } ++ Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (Status) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); ++ } ++ else ++ { ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ // KeyIdx must be 0 ~ 3 ++ if (KeyIdx > 4) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg = 0; ++ PUCHAR Key; ++ ++ // set key material and key length ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ ++ switch(pWepKey->KeyLength) ++ { ++ case 5: ++ CipherAlg = CIPHER_WEP64; ++ break; ++ case 13: ++ CipherAlg = CIPHER_WEP128; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); ++ Status = -EINVAL; ++ break; ++ } ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ ++ // Default key for tx (shared key) ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // set key material and key length ++ NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ++#endif // WPA_SUPPLICANT_SUPPORT ++ { ++ Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); ++ } ++ } ++ kfree(pWepKey); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case OID_SET_COUNTERMEASURES: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.bBlockAssoc = TRUE; ++ else ++ // WPA MIC error should block association attempt for 60 seconds ++ pAdapter->StaCfg.bBlockAssoc = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ } ++ break; ++ case OID_802_11_DEAUTHENTICATION: ++ if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) ++ Status = -EINVAL; ++ else ++ { ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; ++ Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); ++ MlmeDeauthReqAction(pAdapter, MsgElem); ++ kfree(MsgElem); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ LinkDown(pAdapter, FALSE); ++ pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); ++ } ++ break; ++ case OID_802_11_DROP_UNENCRYPTED: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ NdisAcquireSpinLock(&pAdapter->MacTabLock); ++ pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAdapter->MacTabLock); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021X = IEEE8021xState; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); ++ } ++ break; ++ case OID_802_11_PMKID: ++ pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pPmkId == NULL) { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // check the PMKID information ++ if (pPmkId->BSSIDInfoCount == 0) ++ NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ else ++ { ++ PBSSID_INFO pBssIdInfo; ++ UINT BssIdx; ++ UINT CachedIdx; ++ ++ for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) ++ { ++ // point to the indexed BSSID_INFO structure ++ pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); ++ // Find the entry in the saved data base. ++ for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ pAdapter->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ } ++ } ++ } ++ if(pPmkId) ++ kfree(pPmkId); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++#ifdef SNMP_SUPPORT ++ case OID_802_11_SHORTRETRYLIMIT: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); ++ pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ //pKey = &WepKey; ++ ++ if ( pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); ++ } ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); ++ ++ // it is a shared key ++ if (KeyIdx > 4) ++ Status = -EINVAL; ++ else ++ { ++ pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ //RestartAPIsRequired = TRUE; ++ } ++ break; ++ ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); ++ ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ break; ++ ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); ++ sprintf(&ctmp,"%d", ctmp); ++ Set_Channel_Proc(pAdapter, &ctmp); ++ } ++ break; ++#endif ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ ++ return Status; ++} ++ ++INT RTMPQueryInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; ++ PNDIS_WLAN_BSSID_EX pBss; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_CONFIGURATION *pConfiguration = NULL; ++ RT_802_11_LINK_STATUS *pLinkStatus = NULL; ++ RT_802_11_STA_CONFIG *pStaConfig = NULL; ++ NDIS_802_11_STATISTICS *pStatistics = NULL; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ RT_802_11_PREAMBLE PreamType; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_MEDIA_STATE MediaState; ++ ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; ++ USHORT BssLen = 0; ++ PUCHAR pBuf = NULL, pPtr; ++ INT Status = NDIS_STATUS_SUCCESS; ++ UINT we_version_compiled; ++ UCHAR i, Padding = 0; ++ BOOLEAN RadioState; ++ UCHAR driverVersion[8]; ++ OID_SET_HT_PHYMODE *pHTPhyMode = NULL; ++ ++ ++#ifdef SNMP_SUPPORT ++ //for snmp, kathy ++ DefaultKeyIdxValue *pKeyIdxValue; ++ INT valueLen; ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR tmp[64]; ++#endif //SNMP ++ ++ switch(cmd) ++ { ++ case RT_OID_DEVICE_NAME: ++ wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); ++ Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); ++ break; ++ case RT_OID_VERSION_INFO: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); ++ wrq->u.data.length = 8*sizeof(UCHAR); ++ sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); ++ driverVersion[7] = '\0'; ++ if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#ifdef RALINK_ATE ++ case RT_QUERY_ATE_TXDONE_COUNT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); ++ wrq->u.data.length = sizeof(UINT32); ++ if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#endif // RALINK_ATE // ++ case OID_802_11_BSSID_LIST: ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); ++ return -EAGAIN; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ // Claculate total buffer size required ++ BssBufSize = sizeof(ULONG); ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ // Align pointer to 4 bytes boundary. ++ //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); ++ //if (Padding == 4) ++ // Padding = 0; ++ BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ } ++ ++ // For safety issue, we add 256 bytes just in case ++ BssBufSize += 256; ++ // Allocate the same size as passed from higher layer ++ pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); ++ if(pBuf == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ // Init 802_11_BSSID_LIST_EX structure ++ NdisZeroMemory(pBuf, BssBufSize); ++ pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; ++ pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; ++ ++ // Calculate total buffer length ++ BssLen = 4; // Consist of NumberOfItems ++ // Point to start of NDIS_WLAN_BSSID_EX ++ // pPtr = pBuf + sizeof(ULONG); ++ pPtr = (PUCHAR) &pBssidList->Bssid[0]; ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ pBss = (PNDIS_WLAN_BSSID_EX) pPtr; ++ NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) ++ { ++ // ++ // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation ++ // and then failed to send EAPOl farame. ++ // ++ if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ else ++ pBss->Ssid.SsidLength = 0; ++ } ++ else ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; ++ pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; ++ pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; ++ pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; ++ ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); ++ ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) ++ pBss->InfrastructureMode = Ndis802_11Infrastructure; ++ else ++ pBss->InfrastructureMode = Ndis802_11IBSS; ++ ++ NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); ++ NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, ++ pAdapter->ScanTab.BssEntry[i].ExtRate, ++ pAdapter->ScanTab.BssEntry[i].ExtRateLen); ++ ++ if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) ++ { ++ pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ } ++ else ++ { ++ pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; ++ } ++ pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ ++#if WIRELESS_EXT < 17 ++ if ((BssLen + pBss->Length) < wrq->u.data.length) ++ BssLen += pBss->Length; ++ else ++ { ++ pBssidList->NumberOfItems = i; ++ break; ++ } ++#else ++ BssLen += pBss->Length; ++#endif ++ } ++ ++#if WIRELESS_EXT < 17 ++ wrq->u.data.length = BssLen; ++#else ++ if (BssLen > wrq->u.data.length) ++ { ++ kfree(pBssidList); ++ return -E2BIG; ++ } ++ else ++ wrq->u.data.length = BssLen; ++#endif ++ Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); ++ kfree(pBssidList); ++ break; ++ case OID_802_3_CURRENT_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ case OID_GEN_MEDIA_CONNECT_STATUS: ++ if (pAdapter->IndicateMediaState == NdisMediaStateConnected) ++ MediaState = NdisMediaStateConnected; ++ else ++ MediaState = NdisMediaStateDisconnected; ++ ++ wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); ++ Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++#endif // RALINK_ATE // ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); ++ Status = -ENOTCONN; ++ } ++ break; ++ case OID_802_11_SSID: ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); ++ Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; ++ memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); ++ wrq->u.data.length = sizeof(NDIS_802_11_SSID); ++ Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); ++ break; ++ case RT_OID_802_11_QUERY_LINK_STATUS: ++ pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); ++ if (pLinkStatus) ++ { ++ pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps ++ pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; ++ pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; ++ pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; ++ pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; ++ wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); ++ Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); ++ kfree(pLinkStatus); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_CONFIGURATION: ++ pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); ++ if (pConfiguration) ++ { ++ pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; ++ pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); ++ wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); ++ Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", ++ pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ kfree(pConfiguration); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_SNR_0: ++ if ((pAdapter->StaCfg.LastSNR0 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ break; ++ case RT_OID_802_11_SNR_1: ++ if ((pAdapter->Antenna.field.RxPath > 1) && ++ (pAdapter->StaCfg.LastSNR1 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); ++ break; ++ case OID_802_11_RSSI_TRIGGER: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); ++ break; ++ case OID_802_11_RSSI: ++ case RT_OID_802_11_RSSI: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_1: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_2: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_802_11_STATISTICS: ++ pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); ++ if (pStatistics) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAdapter); ++ ++ // Sanity check for calculation of sucessful count ++ if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) ++ pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ ++ pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; ++ pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; ++ pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; ++ pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; ++ pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; ++ pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; ++ pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; ++ pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; ++ pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; ++#ifdef DBG ++ pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; ++#else ++ pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; ++ pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; ++#endif ++ wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); ++ Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); ++ kfree(pStatistics); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_GEN_RCV_OK: ++ ulInfo = pAdapter->Counters8023.GoodReceives; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_GEN_RCV_NO_BUFFER: ++ ulInfo = pAdapter->Counters8023.RxNoBuffer; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); ++ if (pStaConfig) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); ++ pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; ++ pStaConfig->EnableTurboRate = 0; ++ pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; ++ pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; ++ //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; ++ pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; ++ pStaConfig->Rsv1 = 0; ++ pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; ++ wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); ++ Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); ++ kfree(pStaConfig); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ RtsThresh = pAdapter->CommonCfg.RtsThreshold; ++ wrq->u.data.length = sizeof(RtsThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ FragThresh = pAdapter->CommonCfg.FragmentThreshold; ++ if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) ++ FragThresh = 0; ++ wrq->u.data.length = sizeof(FragThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ PowerMode = pAdapter->StaCfg.WindowsPowerMode; ++ wrq->u.data.length = sizeof(PowerMode); ++ Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); ++ break; ++ case RT_OID_802_11_RADIO: ++ RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; ++ wrq->u.data.length = sizeof(RadioState); ++ Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ BssType = Ndis802_11IBSS; ++ else if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ BssType = Ndis802_11Infrastructure; ++ else if (pAdapter->StaCfg.BssType == BSS_MONITOR) ++ BssType = Ndis802_11Monitor; ++ else ++ BssType = Ndis802_11AutoUnknown; ++ ++ wrq->u.data.length = sizeof(BssType); ++ Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ PreamType = pAdapter->CommonCfg.TxPreamble; ++ wrq->u.data.length = sizeof(PreamType); ++ Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ AuthMode = pAdapter->StaCfg.AuthMode; ++ wrq->u.data.length = sizeof(AuthMode); ++ Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); ++ break; ++ case OID_802_11_WEP_STATUS: ++ WepStatus = pAdapter->StaCfg.WepStatus; ++ wrq->u.data.length = sizeof(WepStatus); ++ Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); ++ break; ++ case OID_802_11_TX_POWER_LEVEL: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ break; ++ case OID_802_11_NETWORK_TYPES_SUPPORTED: ++ if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) ++ { ++ NetworkTypeList[0] = 3; // NumberOfItems = 3 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a ++ wrq->u.data.length = 16; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ else ++ { ++ NetworkTypeList[0] = 2; // NumberOfItems = 2 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ wrq->u.data.length = 12; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ wrq->u.data.length = sizeof(ULONG); ++ if (pAdapter->CommonCfg.PhyMode == PHY_11A) ++ ulInfo = Ndis802_11OFDM5; ++ else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) ++ ulInfo = Ndis802_11OFDM24; ++ else ++ ulInfo = Ndis802_11DS; ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_LAST_RX_RATE: ++ ulInfo = (ULONG)pAdapter->LastRxRate; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_LAST_TX_RATE: ++ //ulInfo = (ULONG)pAdapter->LastTxRate; ++ ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_EEPROM_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_FIRMWARE_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_NOISE_LEVEL: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); ++ break; ++ case RT_OID_802_11_EXTRA_INFO: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); ++ break; ++ case RT_OID_WE_VERSION_COMPILED: ++ wrq->u.data.length = sizeof(UINT); ++ we_version_compiled = WIRELESS_EXT; ++ Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_APSD_SETTING: ++ apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) ++ | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); ++ ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", ++ apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); ++ break; ++ case RT_OID_802_11_QUERY_APSD_PSM: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ break; ++ case RT_OID_802_11_QUERY_WMM: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case RT_OID_NEW_DRIVER: ++ { ++ UCHAR enabled = 1; ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ case RT_OID_DRIVER_DEVICE_NAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); ++ wrq->u.data.length = 16; ++ if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; ++ ++ pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_COUNTRY_REGION: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); ++ wrq->u.data.length = sizeof(ulInfo); ++ ulInfo = pAdapter->CommonCfg.CountryRegionForABand; ++ ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); ++ if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; ++ ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ i = 0; ++#ifdef MULTIPLE_CARD_SUPPORT ++ i = 1; ++#endif // MULTIPLE_CARD_SUPPORT // ++ if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); ++ break; ++#ifdef SNMP_SUPPORT ++ case RT_OID_802_11_MAC_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREROUI: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); ++ wrq->u.data.length = ManufacturerOUI_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTURERNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_RESOURCETYPEIDNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); ++ wrq->u.data.length = strlen(ResourceTypeIdName); ++ Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); ++ ulInfo = 1; // 1 is support wep else 2 is not support. ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_POWERMANAGEMENTMODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); ++ if (pAdapter->StaCfg.Psm == PSMP_ACTION) ++ ulInfo = 1; // 1 is power active else 2 is power save. ++ else ++ ulInfo = 2; ++ ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); ++ //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; ++ pKeyIdxValue = wrq->u.data.pointer; ++ DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); ++ valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ NdisMoveMemory(pKeyIdxValue->Value, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, ++ valueLen); ++ pKeyIdxValue->Value[valueLen]='\0'; ++ ++ wrq->u.data.length = sizeof(DefaultKeyIdxValue); ++ ++ Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ pAdapter->SharedKey[BSS0][0].Key[0], ++ pAdapter->SharedKey[BSS0][1].Key[0], ++ pAdapter->SharedKey[BSS0][2].Key[0], ++ pAdapter->SharedKey[BSS0][3].Key[0])); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); ++ break; ++ ++ case RT_OID_802_11_WEPKEYMAPPINGLENGTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ wrq->u.data.length); ++ break; ++ ++ case OID_802_11_SHORTRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRODUCTID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); ++ ++#ifdef RT2870 ++ sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); ++ ++#endif // RT2870 // ++ wrq->u.data.length = strlen(tmp); ++ Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++#endif //SNMP_SUPPORT ++ ++ case OID_802_11_BUILD_CHANNEL_EX: ++ { ++ UCHAR value; ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 1; ++#else ++ DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 0; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ Status = copy_to_user(wrq->u.data.pointer, &value, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ } ++ break; ++ ++ case OID_802_11_GET_CH_LIST: ++ { ++ PRT_CHANNEL_LIST_INFO pChListBuf; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); ++ if (pAdapter->ChannelListNum == 0) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); ++ if (pChListBuf == NULL) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf->ChannelListNum = pAdapter->ChannelListNum; ++ for (i = 0; i < pChListBuf->ChannelListNum; i++) ++ pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; ++ ++ wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ ++ if (pChListBuf) ++ kfree(pChListBuf); ++ } ++ break; ++ ++ case OID_802_11_GET_COUNTRY_CODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); ++ wrq->u.data.length = 2; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ case OID_802_11_GET_CHANNEL_GEOGRAPHY: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); ++ wrq->u.data.length = 1; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_QUERY_DLS: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ break; ++ ++ case RT_OID_802_11_QUERY_DLS_PARAM: ++ { ++ PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); ++ if (pDlsInfo == NULL) ++ break; ++ ++ for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); ++ } ++ ++ pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; ++ wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); ++ ++ if (pDlsInfo) ++ kfree(pDlsInfo); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ return Status; ++} ++ ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ POS_COOKIE pObj; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ struct iwreq *wrq = (struct iwreq *) rq; ++ BOOLEAN StateMachineTouched = FALSE; ++ INT Status = NDIS_STATUS_SUCCESS; ++ USHORT subcmd; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->priv; ++ pAd = pVirtualAd->RtmpDev->priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (wrq->u.data.pointer == NULL) ++ { ++ return Status; ++ } ++ ++ if (strstr(wrq->u.data.pointer, "OpMode") == NULL) ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ } ++ ++ { // determine this ioctl command is comming from which interface. ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(cmd) ++ { ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++ case RTPRIV_IOCTL_ATE: ++ { ++ RtmpDoAte(pAd, wrq); ++ } ++ break; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ case SIOCGIFHWADDR: ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); ++ memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); ++ break; ++ case SIOCGIWNAME: ++ { ++ char *name=&wrq->u.name[0]; ++ rt_ioctl_giwname(net_dev, NULL, name, NULL); ++ break; ++ } ++ case SIOCGIWESSID: //Get ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWESSID: //Set ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWNWID: // set network id (the cell) ++ case SIOCGIWNWID: // get network id ++ Status = -EOPNOTSUPP; ++ break; ++ case SIOCSIWFREQ: //set channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCGIWFREQ: // get channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCSIWNICKN: //set node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_siwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWNICKN: //get node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_giwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWRATE: //get default bit rate (bps) ++ rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCSIWRATE: //set default bit rate (bps) ++ rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCGIWRTS: // get RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_giwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCSIWRTS: //set RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_siwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCGIWFRAG: //get fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCSIWFRAG: //set fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCGIWENCODE: //get encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCSIWENCODE: //set encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCGIWAP: //get access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCSIWAP: //set access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCGIWMODE: //get operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_giwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCSIWMODE: //set operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_siwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCGIWSENS: //get sensitivity (dBm) ++ case SIOCSIWSENS: //set sensitivity (dBm) ++ case SIOCGIWPOWER: //get Power Management settings ++ case SIOCSIWPOWER: //set Power Management settings ++ case SIOCGIWTXPOW: //get transmit power (dBm) ++ case SIOCSIWTXPOW: //set transmit power (dBm) ++ case SIOCGIWRANGE: //Get range of parameters ++ case SIOCGIWRETRY: //get retry limits and lifetime ++ case SIOCSIWRETRY: //set retry limits and lifetime ++ Status = -EOPNOTSUPP; ++ break; ++ case RT_PRIV_IOCTL: ++ subcmd = wrq->u.data.flags; ++ if( subcmd & OID_GET_SET_TOGGLE) ++ Status = RTMPSetInformation(pAd, rq, subcmd); ++ else ++ Status = RTMPQueryInformation(pAd, rq, subcmd); ++ break; ++ case SIOCGIWPRIV: ++ if (wrq->u.data.pointer) ++ { ++ if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) ++ break; ++ wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); ++ if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) ++ Status = -EFAULT; ++ } ++ break; ++ case RTPRIV_IOCTL_SET: ++ if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) ++ break; ++ rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); ++ break; ++ case RTPRIV_IOCTL_GSITESURVEY: ++ RTMPIoctlGetSiteSurvey(pAd, wrq); ++ break; ++#ifdef DBG ++ case RTPRIV_IOCTL_MAC: ++ RTMPIoctlMAC(pAd, wrq); ++ break; ++ case RTPRIV_IOCTL_E2P: ++ RTMPIoctlE2PROM(pAd, wrq); ++ break; ++#endif // DBG // ++ case SIOCETHTOOL: ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ if(StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set SSID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_SSID Ssid, *pSsid=NULL; ++ BOOLEAN StateMachineTouched = FALSE; ++ int success = TRUE; ++ ++ if( strlen(arg) <= MAX_LEN_OF_SSID) ++ { ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ if (strlen(arg) != 0) ++ { ++ NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); ++ Ssid.SsidLength = strlen(arg); ++ } ++ else //ANY ssid ++ { ++ Ssid.SsidLength = 0; ++ memcpy(Ssid.Ssid, "", 0); ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; ++ } ++ pSsid = &Ssid; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ pAdapter->bConfigChanged = TRUE; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ (VOID *)pSsid); ++ ++ StateMachineTouched = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ } ++ else ++ success = FALSE; ++ ++ if (StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAdapter); ++ ++ return success; ++} ++ ++#ifdef WMM_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WmmCapable Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN bWmmCapable; ++ ++ bWmmCapable = simple_strtol(arg, 0, 10); ++ ++ if ((bWmmCapable == 1) ++#ifdef RT2870 ++ && (pAd->NumberOfPipes >= 5) ++#endif // RT2870 // ++ ) ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ else if (bWmmCapable == 0) ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", ++ pAd->CommonCfg.bWmmCapable)); ++ ++ return TRUE; ++} ++#endif // WMM_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Set Network Type(Infrastructure/Adhoc mode) ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UINT32 Value = 0; ++ ++ if (strcmp(arg, "Adhoc") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_ADHOC) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (INFRA_ON(pAdapter)) ++ { ++ //BOOLEAN Cancelled; ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_ADHOC; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); ++ } ++ else if (strcmp(arg, "Infra") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_INFRA) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (ADHOC_ON(pAdapter)) ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); ++ ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ } ++ else if (strcmp(arg, "Monitor") == 0) ++ { ++ UCHAR bbpValue = 0; ++ BCN_TIME_CFG_STRUC csr; ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ // disable all periodic state machine ++ pAdapter->StaCfg.bAutoReconnect = FALSE; ++ // reset all mlme state machine ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); ++ if (pAdapter->CommonCfg.CentralChannel == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ pAdapter->CommonCfg.CentralChannel = 36; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAdapter->CommonCfg.CentralChannel = 6; ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ N_ChannelCheck(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ // 40MHz ,control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) ++ { ++ // 40MHz ,control channel at upper ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value |= 0x1; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // 20MHz ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_20; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); ++ } ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); ++ // ASIC supporsts sniffer function with replacing RSSI with timestamp. ++ //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ //Value |= (0x80); ++ //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ // disable sync ++ RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); ++ ++ pAdapter->StaCfg.BssType = BSS_MONITOR; ++ pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Authentication mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Encryption Type ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Default Key ID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ ULONG KeyIdx; ++ ++ KeyIdx = simple_strtol(arg, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY1 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ ++ pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 0, ++ pAdapter->SharedKey[BSS0][0].CipherAlg, ++ pAdapter->SharedKey[BSS0][0].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ ++ Description: ++ Set WEP KEY2 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 1, ++ pAdapter->SharedKey[BSS0][1].CipherAlg, ++ pAdapter->SharedKey[BSS0][1].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY3 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 2, ++ pAdapter->SharedKey[BSS0][2].CipherAlg, ++ pAdapter->SharedKey[BSS0][2].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY4 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 3, ++ pAdapter->SharedKey[BSS0][3].CipherAlg, ++ pAdapter->SharedKey[BSS0][3].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WPA PSK key ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UCHAR keyMaterial[40]; ++ ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return TRUE; // do nothing ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); ++ ++ NdisZeroMemory(keyMaterial, 40); ++ ++ if ((strlen(arg) < 8) || (strlen(arg) > 64)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); ++ return FALSE; ++ } ++ ++ if (strlen(arg) == 64) ++ { ++ AtoH(arg, keyMaterial, 32); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else ++ { ++ PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ } ++ ++ ++ ++ if(pAdapter->StaCfg.BssType == BSS_ADHOC && ++ pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ } ++ else ++ { ++ // Start STA supplicant state machine ++ pAdapter->StaCfg.WpaState = SS_START; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Power Saving mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(arg, "Max_PSP") == 0) || ++ (strcmp(arg, "max_psp") == 0) || ++ (strcmp(arg, "MAX_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ pAdapter->StaCfg.DefaultListenCount = 5; ++ ++ } ++ else if ((strcmp(arg, "Fast_PSP") == 0) || ++ (strcmp(arg, "fast_psp") == 0) || ++ (strcmp(arg, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(arg, "Legacy_PSP") == 0) || ++ (strcmp(arg, "legacy_psp") == 0) || ++ (strcmp(arg, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { ++ //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAdapter, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); ++ } ++ else ++ return FALSE; ++ ++ ++ return TRUE; ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WpaSupport flag. ++ Value: ++ 0: Driver ignore wpa_supplicant. ++ 1: wpa_supplicant initiates scanning and AP selection. ++ 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ if ( simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ else if ( simple_strtol(arg, 0, 10) == 1) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++ else if ( simple_strtol(arg, 0, 10) == 2) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; ++ else ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); ++ ++ return TRUE; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ Read / Write MAC ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 ++ 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 ++ ========================================================================== ++*/ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ ULONG macAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ UINT32 macValue = 0; ++ INT Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // Mac Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ if (macAddr < 0xFFFF) ++ { ++ RTMP_IO_READ32(pAdapter, macAddr, &macValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[8-k+j] = temp2[j]; ++ } ++ ++ while(k < 8) ++ temp2[7-k++]='0'; ++ temp2[8]='\0'; ++ ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 4); ++ macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; ++ ++ // debug mode ++ if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) ++ { ++ // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning ++ if (macValue & 0x000000ff) ++ { ++ pAdapter->BbpTuning.bEnable = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); ++ } ++ else ++ { ++ UCHAR R66; ++ pAdapter->BbpTuning.bEnable = FALSE; ++ R66 = 0x26 + GET_LNA_GAIN(pAdapter); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); ++ } ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); ++ ++ RTMP_IO_WRITE32(pAdapter, macAddr, macValue); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); ++ } ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Read / Write E2PROM ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 ++ 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 ++ ========================================================================== ++*/ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ USHORT eepAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ USHORT eepValue; ++ int Status; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ ++ ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // E2PROM addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ if (eepAddr < 0xFFFF) ++ { ++ RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[4-k+j] = temp2[j]; ++ } ++ ++ while(k < 4) ++ temp2[3-k++]='0'; ++ temp2[4]='\0'; ++ ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 2); ++ eepValue = *temp*256 + temp[1]; ++ ++ RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); ++ } ++ } ++next: ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); ++} ++#endif // DBG // ++ ++ ++ ++ ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); ++ return TRUE; ++} ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++ else if (simple_strtol(arg, 0, 10) == 1) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; ++ else if (simple_strtol(arg, 0, 10) == 2) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; ++ else ++ return FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); ++ return TRUE; ++} ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ return TRUE; ++} ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ ++INT Show_Adhoc_MacTable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PCHAR extra) ++{ ++ INT i; ++ ++ sprintf(extra, "\n"); ++ ++#ifdef DOT11_N_SUPPORT ++ sprintf(extra, "%sHT Operating Mode : %d\n", extra, pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode); ++#endif // DOT11_N_SUPPORT // ++ ++ sprintf(extra, "%s\n%-19s%-4s%-4s%-7s%-7s%-7s%-10s%-6s%-6s%-6s%-6s\n", extra, ++ "MAC", "AID", "BSS", "RSSI0", "RSSI1", "RSSI2", "PhMd", "BW", "MCS", "SGI", "STBC"); ++ ++ for (i=1; iMacTab.Content[i]; ++ ++ if (strlen(extra) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ if ((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ { ++ sprintf(extra, "%s%02X:%02X:%02X:%02X:%02X:%02X ", extra, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ sprintf(extra, "%s%-4d", extra, (int)pEntry->Aid); ++ sprintf(extra, "%s%-4d", extra, (int)pEntry->apidx); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi0); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi1); ++ sprintf(extra, "%s%-7d", extra, pEntry->RssiSample.AvgRssi2); ++ sprintf(extra, "%s%-10s", extra, GetPhyMode(pEntry->HTPhyMode.field.MODE)); ++ sprintf(extra, "%s%-6s", extra, GetBW(pEntry->HTPhyMode.field.BW)); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.MCS); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.ShortGI); ++ sprintf(extra, "%s%-6d", extra, pEntry->HTPhyMode.field.STBC); ++ sprintf(extra, "%s%-10d, %d, %d%%\n", extra, pEntry->DebugFIFOCount, pEntry->DebugTxCount, ++ (pEntry->DebugTxCount) ? ((pEntry->DebugTxCount-pEntry->DebugFIFOCount)*100/pEntry->DebugTxCount) : 0); ++ sprintf(extra, "%s\n", extra); ++ } ++ } ++ ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt2870/TODO +@@ -0,0 +1,10 @@ ++TODO: ++ - checkpatch.pl clean ++ - sparse clean ++ - port to in-kernel 80211 stack ++ - remove reading from /etc/ config files ++ - review by the wireless developer community ++ ++Please send any patches or complaints about this driver to Greg ++Kroah-Hartman and don't bother the upstream wireless ++kernel developers about it, they want nothing to do with it. +--- /dev/null ++++ b/drivers/staging/rt2870/wpa.h +@@ -0,0 +1,357 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++ ++#ifndef __WPA_H__ ++#define __WPA_H__ ++ ++// EAPOL Key descripter frame format related length ++#define LEN_KEY_DESC_NONCE 32 ++#define LEN_KEY_DESC_IV 16 ++#define LEN_KEY_DESC_RSC 8 ++#define LEN_KEY_DESC_ID 8 ++#define LEN_KEY_DESC_REPLAY 8 ++#define LEN_KEY_DESC_MIC 16 ++ ++// The length is the EAPoL-Key frame except key data field. ++// Please refer to 802.11i-2004 ,Figure 43u in p.78 ++#define LEN_EAPOL_KEY_MSG (sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE) ++ ++// EAP Code Type. ++#define EAP_CODE_REQUEST 1 ++#define EAP_CODE_RESPONSE 2 ++#define EAP_CODE_SUCCESS 3 ++#define EAP_CODE_FAILURE 4 ++ ++// EAPOL frame Protocol Version ++#define EAPOL_VER 1 ++#define EAPOL_VER2 2 ++ ++// EAPOL-KEY Descriptor Type ++#define WPA1_KEY_DESC 0xfe ++#define WPA2_KEY_DESC 0x02 ++ ++// Key Descriptor Version of Key Information ++#define DESC_TYPE_TKIP 1 ++#define DESC_TYPE_AES 2 ++#define DESC_TYPE_MESH 3 ++ ++#define LEN_MSG1_2WAY 0x7f ++#define MAX_LEN_OF_EAP_HS 256 ++ ++#define LEN_MASTER_KEY 32 ++ ++// EAPOL EK, MK ++#define LEN_EAP_EK 16 ++#define LEN_EAP_MICK 16 ++#define LEN_EAP_KEY ((LEN_EAP_EK)+(LEN_EAP_MICK)) ++// TKIP key related ++#define LEN_PMKID 16 ++#define LEN_TKIP_EK 16 ++#define LEN_TKIP_RXMICK 8 ++#define LEN_TKIP_TXMICK 8 ++#define LEN_AES_EK 16 ++#define LEN_AES_KEY LEN_AES_EK ++#define LEN_TKIP_KEY ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) ++#define TKIP_AP_TXMICK_OFFSET ((LEN_EAP_KEY)+(LEN_TKIP_EK)) ++#define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) ++#define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) ++#define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) ++#define MIN_LEN_OF_GTK 5 ++ ++// RSN IE Length definition ++#define MAX_LEN_OF_RSNIE 90 ++#define MIN_LEN_OF_RSNIE 8 ++ ++//EAP Packet Type ++#define EAPPacket 0 ++#define EAPOLStart 1 ++#define EAPOLLogoff 2 ++#define EAPOLKey 3 ++#define EAPOLASFAlert 4 ++#define EAPTtypeMax 5 ++ ++#define EAPOL_MSG_INVALID 0 ++#define EAPOL_PAIR_MSG_1 1 ++#define EAPOL_PAIR_MSG_2 2 ++#define EAPOL_PAIR_MSG_3 3 ++#define EAPOL_PAIR_MSG_4 4 ++#define EAPOL_GROUP_MSG_1 5 ++#define EAPOL_GROUP_MSG_2 6 ++ ++#define PAIRWISEKEY 1 ++#define GROUPKEY 0 ++ ++// Retry timer counter initial value ++#define PEER_MSG1_RETRY_TIMER_CTR 0 ++#define PEER_MSG3_RETRY_TIMER_CTR 10 ++#define GROUP_MSG1_RETRY_TIMER_CTR 20 ++ ++ ++#define EAPOL_START_DISABLE 0 ++#define EAPOL_START_PSK 1 ++#define EAPOL_START_1X 2 ++ ++#define MIX_CIPHER_WPA_TKIP_ON(x) (((x) & 0x08) != 0) ++#define MIX_CIPHER_WPA_AES_ON(x) (((x) & 0x04) != 0) ++#define MIX_CIPHER_WPA2_TKIP_ON(x) (((x) & 0x02) != 0) ++#define MIX_CIPHER_WPA2_AES_ON(x) (((x) & 0x01) != 0) ++ ++#define ROUND_UP(__x, __y) \ ++ (((ULONG)((__x)+((__y)-1))) & ((ULONG)~((__y)-1))) ++ ++#define ADD_ONE_To_64BIT_VAR(_V) \ ++{ \ ++ UCHAR cnt = LEN_KEY_DESC_REPLAY; \ ++ do \ ++ { \ ++ cnt--; \ ++ _V[cnt]++; \ ++ if (cnt == 0) \ ++ break; \ ++ }while (_V[cnt] == 0); \ ++} ++ ++#define IS_WPA_CAPABILITY(a) (((a) >= Ndis802_11AuthModeWPA) && ((a) <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ ++// EAPOL Key Information definition within Key descriptor format ++typedef struct PACKED _KEY_INFO ++{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR KeyAck:1; ++ UCHAR Install:1; ++ UCHAR KeyIndex:2; ++ UCHAR KeyType:1; ++ UCHAR KeyDescVer:3; ++ UCHAR Rsvd:3; ++ UCHAR EKD_DL:1; // EKD for AP; DL for STA ++ UCHAR Request:1; ++ UCHAR Error:1; ++ UCHAR Secure:1; ++ UCHAR KeyMic:1; ++#else ++ UCHAR KeyMic:1; ++ UCHAR Secure:1; ++ UCHAR Error:1; ++ UCHAR Request:1; ++ UCHAR EKD_DL:1; // EKD for AP; DL for STA ++ UCHAR Rsvd:3; ++ UCHAR KeyDescVer:3; ++ UCHAR KeyType:1; ++ UCHAR KeyIndex:2; ++ UCHAR Install:1; ++ UCHAR KeyAck:1; ++#endif ++} KEY_INFO, *PKEY_INFO; ++ ++// EAPOL Key descriptor format ++typedef struct PACKED _KEY_DESCRIPTER ++{ ++ UCHAR Type; ++ KEY_INFO KeyInfo; ++ UCHAR KeyLength[2]; ++ UCHAR ReplayCounter[LEN_KEY_DESC_REPLAY]; ++ UCHAR KeyNonce[LEN_KEY_DESC_NONCE]; ++ UCHAR KeyIv[LEN_KEY_DESC_IV]; ++ UCHAR KeyRsc[LEN_KEY_DESC_RSC]; ++ UCHAR KeyId[LEN_KEY_DESC_ID]; ++ UCHAR KeyMic[LEN_KEY_DESC_MIC]; ++ UCHAR KeyDataLen[2]; ++ UCHAR KeyData[MAX_LEN_OF_RSNIE]; ++} KEY_DESCRIPTER, *PKEY_DESCRIPTER; ++ ++typedef struct PACKED _EAPOL_PACKET ++{ ++ UCHAR ProVer; ++ UCHAR ProType; ++ UCHAR Body_Len[2]; ++ KEY_DESCRIPTER KeyDesc; ++} EAPOL_PACKET, *PEAPOL_PACKET; ++ ++//802.11i D10 page 83 ++typedef struct PACKED _GTK_ENCAP ++{ ++#ifndef RT_BIG_ENDIAN ++ UCHAR Kid:2; ++ UCHAR tx:1; ++ UCHAR rsv:5; ++ UCHAR rsv1; ++#else ++ UCHAR rsv:5; ++ UCHAR tx:1; ++ UCHAR Kid:2; ++ UCHAR rsv1; ++#endif ++ UCHAR GTK[TKIP_GTK_LENGTH]; ++} GTK_ENCAP, *PGTK_ENCAP; ++ ++typedef struct PACKED _KDE_ENCAP ++{ ++ UCHAR Type; ++ UCHAR Len; ++ UCHAR OUI[3]; ++ UCHAR DataType; ++ GTK_ENCAP GTKEncap; ++} KDE_ENCAP, *PKDE_ENCAP; ++ ++// For WPA1 ++typedef struct PACKED _RSNIE { ++ UCHAR oui[4]; ++ USHORT version; ++ UCHAR mcast[4]; ++ USHORT ucount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }ucast[1]; ++} RSNIE, *PRSNIE; ++ ++// For WPA2 ++typedef struct PACKED _RSNIE2 { ++ USHORT version; ++ UCHAR mcast[4]; ++ USHORT ucount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }ucast[1]; ++} RSNIE2, *PRSNIE2; ++ ++// AKM Suite ++typedef struct PACKED _RSNIE_AUTH { ++ USHORT acount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }auth[1]; ++} RSNIE_AUTH,*PRSNIE_AUTH; ++ ++typedef union PACKED _RSN_CAPABILITIES { ++ struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Rsvd:10; ++ USHORT GTKSA_R_Counter:2; ++ USHORT PTKSA_R_Counter:2; ++ USHORT No_Pairwise:1; ++ USHORT PreAuth:1; ++#else ++ USHORT PreAuth:1; ++ USHORT No_Pairwise:1; ++ USHORT PTKSA_R_Counter:2; ++ USHORT GTKSA_R_Counter:2; ++ USHORT Rsvd:10; ++#endif ++ } field; ++ USHORT word; ++} RSN_CAPABILITIES, *PRSN_CAPABILITIES; ++ ++typedef struct PACKED _EAP_HDR { ++ UCHAR ProVer; ++ UCHAR ProType; ++ UCHAR Body_Len[2]; ++ UCHAR code; ++ UCHAR identifier; ++ UCHAR length[2]; // including code and identifier, followed by length-2 octets of data ++} EAP_HDR, *PEAP_HDR; ++ ++// For supplicant state machine states. 802.11i Draft 4.1, p. 97 ++// We simplified it ++typedef enum _WpaState ++{ ++ SS_NOTUSE, // 0 ++ SS_START, // 1 ++ SS_WAIT_MSG_3, // 2 ++ SS_WAIT_GROUP, // 3 ++ SS_FINISH, // 4 ++ SS_KEYUPDATE, // 5 ++} WPA_STATE; ++ ++// ++// The definition of the cipher combination ++// ++// bit3 bit2 bit1 bit0 ++// +------------+------------+ ++// | WPA | WPA2 | ++// +------+-----+------+-----+ ++// | TKIP | AES | TKIP | AES | ++// | 0 | 1 | 1 | 0 | -> 0x06 ++// | 0 | 1 | 1 | 1 | -> 0x07 ++// | 1 | 0 | 0 | 1 | -> 0x09 ++// | 1 | 0 | 1 | 1 | -> 0x0B ++// | 1 | 1 | 0 | 1 | -> 0x0D ++// | 1 | 1 | 1 | 0 | -> 0x0E ++// | 1 | 1 | 1 | 1 | -> 0x0F ++// +------+-----+------+-----+ ++// ++typedef enum _WpaMixPairCipher ++{ ++ MIX_CIPHER_NOTUSE = 0x00, ++ WPA_NONE_WPA2_TKIPAES = 0x03, // WPA2-TKIPAES ++ WPA_AES_WPA2_TKIP = 0x06, ++ WPA_AES_WPA2_TKIPAES = 0x07, ++ WPA_TKIP_WPA2_AES = 0x09, ++ WPA_TKIP_WPA2_TKIPAES = 0x0B, ++ WPA_TKIPAES_WPA2_NONE = 0x0C, // WPA-TKIPAES ++ WPA_TKIPAES_WPA2_AES = 0x0D, ++ WPA_TKIPAES_WPA2_TKIP = 0x0E, ++ WPA_TKIPAES_WPA2_TKIPAES = 0x0F, ++} WPA_MIX_PAIR_CIPHER; ++ ++typedef struct PACKED _RSN_IE_HEADER_STRUCT { ++ UCHAR Eid; ++ UCHAR Length; ++ USHORT Version; // Little endian format ++} RSN_IE_HEADER_STRUCT, *PRSN_IE_HEADER_STRUCT; ++ ++// Cipher suite selector types ++typedef struct PACKED _CIPHER_SUITE_STRUCT { ++ UCHAR Oui[3]; ++ UCHAR Type; ++} CIPHER_SUITE_STRUCT, *PCIPHER_SUITE_STRUCT; ++ ++// Authentication and Key Management suite selector ++typedef struct PACKED _AKM_SUITE_STRUCT { ++ UCHAR Oui[3]; ++ UCHAR Type; ++} AKM_SUITE_STRUCT, *PAKM_SUITE_STRUCT; ++ ++// RSN capability ++typedef struct PACKED _RSN_CAPABILITY { ++ USHORT Rsv:10; ++ USHORT GTKSAReplayCnt:2; ++ USHORT PTKSAReplayCnt:2; ++ USHORT NoPairwise:1; ++ USHORT PreAuth:1; ++} RSN_CAPABILITY, *PRSN_CAPABILITY; ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt3070-wireless-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt3070-wireless-driver.patch new file mode 100644 index 000000000..52ff39b89 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rt3070-wireless-driver.patch @@ -0,0 +1,97652 @@ +From 74165ca9acb4060a4cd2de0095f4ff3f0885da3f Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 25 Feb 2009 16:14:55 -0800 +Subject: Staging: add rt3070 wireless driver + +From: Greg Kroah-Hartman + +This is the Ralink RT3070 driver from the company that does horrible +things like reading a config file from /etc. However, the driver that +is currently under development from the wireless development community +is not working at all yet, so distros and users are using this version +instead (quite common hardware on a lot of netbook machines). + +So here is this driver, for now, until the wireless developers get a +"clean" version into the main tree, or until this version is cleaned up +sufficiently to move out of the staging tree. + +Ported to the Linux build system, fixed lots of build issues, forward +ported to the current kernel version, and other minor cleanups were all +done by me. + +Cc: Linux wireless +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/rt3070/2870_main_dev.c | 1627 ++++ + drivers/staging/rt3070/Kconfig | 6 + drivers/staging/rt3070/Makefile | 47 + drivers/staging/rt3070/action.h | 68 + drivers/staging/rt3070/aironet.h | 210 + drivers/staging/rt3070/ap.h | 557 + + drivers/staging/rt3070/chlist.h | 1253 +++ + drivers/staging/rt3070/common/2870_rtmp_init.c | 1762 ++++ + drivers/staging/rt3070/common/action.c | 1038 ++ + drivers/staging/rt3070/common/ba_action.c | 1810 ++++ + drivers/staging/rt3070/common/cmm_data.c | 2827 +++++++ + drivers/staging/rt3070/common/cmm_data_2870.c | 980 ++ + drivers/staging/rt3070/common/cmm_info.c | 3395 +++++++++ + drivers/staging/rt3070/common/cmm_sanity.c | 1669 ++++ + drivers/staging/rt3070/common/cmm_sync.c | 711 + + drivers/staging/rt3070/common/cmm_wpa.c | 1606 ++++ + drivers/staging/rt3070/common/dfs.c | 441 + + drivers/staging/rt3070/common/eeprom.c | 1498 ++++ + drivers/staging/rt3070/common/md5.c | 1427 +++ + drivers/staging/rt3070/common/mlme.c | 9136 +++++++++++++++++++++++++ + drivers/staging/rt3070/common/netif_block.c | 136 + drivers/staging/rt3070/common/rtmp_init.c | 4197 +++++++++++ + drivers/staging/rt3070/common/rtmp_tkip.c | 1613 ++++ + drivers/staging/rt3070/common/rtmp_wep.c | 508 + + drivers/staging/rt3070/common/rtusb_bulk.c | 1382 +++ + drivers/staging/rt3070/common/rtusb_data.c | 218 + drivers/staging/rt3070/common/rtusb_io.c | 1908 +++++ + drivers/staging/rt3070/common/spectrum.c | 1876 +++++ + drivers/staging/rt3070/dfs.h | 100 + drivers/staging/rt3070/firmware.h | 558 + + drivers/staging/rt3070/leap.h | 215 + drivers/staging/rt3070/link_list.h | 134 + drivers/staging/rt3070/md4.h | 42 + drivers/staging/rt3070/md5.h | 107 + drivers/staging/rt3070/mlme.h | 1468 ++++ + drivers/staging/rt3070/netif_block.h | 58 + drivers/staging/rt3070/oid.h | 1142 +++ + drivers/staging/rt3070/rt2870.h | 756 ++ + drivers/staging/rt3070/rt28xx.h | 2725 +++++++ + drivers/staging/rt3070/rt_ate.c | 6506 +++++++++++++++++ + drivers/staging/rt3070/rt_ate.h | 294 + drivers/staging/rt3070/rt_config.h | 121 + drivers/staging/rt3070/rt_linux.c | 1063 ++ + drivers/staging/rt3070/rt_linux.h | 887 ++ + drivers/staging/rt3070/rt_main_dev.c | 1800 ++++ + drivers/staging/rt3070/rt_profile.c | 2041 +++++ + drivers/staging/rt3070/rtmp.h | 7728 +++++++++++++++++++++ + drivers/staging/rt3070/rtmp_ckipmic.h | 113 + drivers/staging/rt3070/rtmp_def.h | 1559 ++++ + drivers/staging/rt3070/rtmp_type.h | 95 + drivers/staging/rt3070/spectrum.h | 322 + drivers/staging/rt3070/spectrum_def.h | 95 + drivers/staging/rt3070/sta/aironet.c | 1312 +++ + drivers/staging/rt3070/sta/assoc.c | 2060 +++++ + drivers/staging/rt3070/sta/auth.c | 475 + + drivers/staging/rt3070/sta/auth_rsp.c | 167 + drivers/staging/rt3070/sta/connect.c | 2857 +++++++ + drivers/staging/rt3070/sta/dls.c | 2170 +++++ + drivers/staging/rt3070/sta/rtmp_data.c | 2637 +++++++ + drivers/staging/rt3070/sta/sanity.c | 420 + + drivers/staging/rt3070/sta/sync.c | 1755 ++++ + drivers/staging/rt3070/sta/wpa.c | 2099 +++++ + drivers/staging/rt3070/sta_ioctl.c | 7203 +++++++++++++++++++ + drivers/staging/rt3070/wpa.h | 356 + 66 files changed, 97349 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -51,6 +51,8 @@ source "drivers/staging/rt2860/Kconfig" + + source "drivers/staging/rt2870/Kconfig" + ++source "drivers/staging/rt3070/Kconfig" ++ + source "drivers/staging/benet/Kconfig" + + source "drivers/staging/rtl8187se/Kconfig" +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -17,5 +17,6 @@ obj-$(CONFIG_AGNX) += agnx/ + obj-$(CONFIG_OTUS) += otus/ + obj-$(CONFIG_RT2860) += rt2860/ + obj-$(CONFIG_RT2870) += rt2870/ ++obj-$(CONFIG_RT3070) += rt3070/ + obj-$(CONFIG_BENET) += benet/ + obj-$(CONFIG_RTL8187SE) += rtl8187se/ +--- /dev/null ++++ b/drivers/staging/rt3070/2870_main_dev.c +@@ -0,0 +1,1627 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_main.c ++ ++ Abstract: ++ main initialization routines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Jan Lee 01-10-2005 modified ++ Sample Jun/01/07 Merge RT2870 and RT2860 drivers. ++*/ ++ ++#include "rt_config.h" ++ ++ ++// Following information will be show when you run 'modinfo' ++// *** If you have a solution for the bug in current version of driver, please mail to me. ++// Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** ++MODULE_AUTHOR("Paul Lin "); ++MODULE_DESCRIPTION("RT2870 Wireless Lan Linux Driver"); ++#ifdef CONFIG_STA_SUPPORT ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_VERSION ++MODULE_VERSION(STA_DRIVER_VERSION); ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// record whether the card in the card list is used in the card file ++extern UINT8 MC_CardUsed[]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++/* Kernel thread and vars, which handles packets that are completed. Only ++ * packets that have a "complete" function are sent here. This way, the ++ * completion is run out of kernel context, and doesn't block the rest of ++ * the stack. */ ++//static int mlme_kill = 0; // Mlme kernel thread ++//static int RTUSBCmd_kill = 0; // Command kernel thread ++//static int TimerFunc_kill = 0; // TimerQ kernel thread ++ ++//static wait_queue_head_t timerWaitQ; ++//static wait_queue_t waitQ; ++ ++extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, ++ IN UINT argc, OUT PRTMP_ADAPTER *ppAd); ++ ++ ++/* module table */ ++struct usb_device_id rtusb_usb_id[] = RT2870_USB_DEVICES; ++INT const rtusb_usb_id_len = sizeof(rtusb_usb_id) / sizeof(struct usb_device_id); ++MODULE_DEVICE_TABLE(usb, rtusb_usb_id); ++ ++#ifndef PF_NOFREEZE ++#define PF_NOFREEZE 0 ++#endif ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ ++/**************************************************************************/ ++/**************************************************************************/ ++//tested for kernel 2.4 series ++/**************************************************************************/ ++/**************************************************************************/ ++static void *rtusb_probe(struct usb_device *dev, UINT interface, ++ const struct usb_device_id *id_table); ++static void rtusb_disconnect(struct usb_device *dev, void *ptr); ++ ++struct usb_driver rtusb_driver = { ++ name:"rt2870", ++ probe:rtusb_probe, ++ disconnect:rtusb_disconnect, ++ id_table:rtusb_usb_id, ++ }; ++ ++#else ++ ++#ifdef CONFIG_PM ++static int rt2870_suspend(struct usb_interface *intf, pm_message_t state); ++static int rt2870_resume(struct usb_interface *intf); ++#endif // CONFIG_PM // ++ ++/**************************************************************************/ ++/**************************************************************************/ ++//tested for kernel 2.6series ++/**************************************************************************/ ++/**************************************************************************/ ++static int rtusb_probe (struct usb_interface *intf, ++ const struct usb_device_id *id); ++static void rtusb_disconnect(struct usb_interface *intf); ++ ++struct usb_driver rtusb_driver = { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ .owner = THIS_MODULE, ++#endif ++ .name="rt2870", ++ .probe=rtusb_probe, ++ .disconnect=rtusb_disconnect, ++ .id_table=rtusb_usb_id, ++ ++#ifdef CONFIG_PM ++ suspend: rt2870_suspend, ++ resume: rt2870_resume, ++#endif ++ }; ++ ++#ifdef CONFIG_PM ++ ++VOID RT2860RejectPendingPackets( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // clear PS packets ++ // clear TxSw packets ++} ++ ++static int rt2870_suspend( ++ struct usb_interface *intf, ++ pm_message_t state) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = usb_get_intfdata(intf); ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_suspend()\n")); ++ net_dev = pAd->net_dev; ++ netif_device_detach(net_dev); ++ ++ pAd->PM_FlgSuspend = 1; ++ if (netif_running(net_dev)) { ++ RTUSBCancelPendingBulkInIRP(pAd); ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_suspend()\n")); ++ return 0; ++} ++ ++static int rt2870_resume( ++ struct usb_interface *intf) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = usb_get_intfdata(intf); ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt2870_resume()\n")); ++ ++ pAd->PM_FlgSuspend = 0; ++ net_dev = pAd->net_dev; ++ netif_device_attach(net_dev); ++ netif_start_queue(net_dev); ++ netif_carrier_on(net_dev); ++ netif_wake_queue(net_dev); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2870_resume()\n")); ++ return 0; ++} ++#endif // CONFIG_PM // ++#endif // LINUX_VERSION_CODE // ++ ++ ++// Init driver module ++INT __init rtusb_init(void) ++{ ++ printk("rtusb init --->\n"); ++ return usb_register(&rtusb_driver); ++} ++ ++// Deinit driver module ++VOID __exit rtusb_exit(void) ++{ ++ usb_deregister(&rtusb_driver); ++ printk("<--- rtusb exit\n"); ++} ++ ++module_init(rtusb_init); ++module_exit(rtusb_exit); ++ ++ ++ ++ ++/*--------------------------------------------------------------------- */ ++/* function declarations */ ++/*--------------------------------------------------------------------- */ ++ ++/* ++======================================================================== ++Routine Description: ++ MLME kernel thread. ++ ++Arguments: ++ *Context the pAd, driver control block pointer ++ ++Return Value: ++ 0 close the thread ++ ++Note: ++======================================================================== ++*/ ++INT MlmeThread( ++ IN void *Context) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; ++ POS_COOKIE pObj; ++ int status; ++ ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ rtmp_os_thread_init("rt2870MlmeThread", (PVOID)&(pAd->mlmeComplete)); ++ ++ while (pAd->mlme_kill == 0) ++ { ++ /* lock the device pointers */ ++ //down(&(pAd->mlme_semaphore)); ++ status = down_interruptible(&(pAd->mlme_semaphore)); ++ ++ /* lock the device pointers , need to check if required*/ ++ //down(&(pAd->usbdev_semaphore)); ++ ++ if (!pAd->PM_FlgSuspend) ++ MlmeHandler(pAd); ++ ++ /* unlock the device pointers */ ++ //up(&(pAd->usbdev_semaphore)); ++ if (status != 0) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ break; ++ } ++ } ++ ++ /* notify the exit routine that we're actually exiting now ++ * ++ * complete()/wait_for_completion() is similar to up()/down(), ++ * except that complete() is safe in the case where the structure ++ * is getting deleted in a parallel mode of execution (i.e. just ++ * after the down() -- that's necessary for the thread-shutdown ++ * case. ++ * ++ * complete_and_exit() goes even further than this -- it is safe in ++ * the case that the thread of the caller is going away (not just ++ * the structure) -- this is necessary for the module-remove case. ++ * This is important in preemption kernels, which transfer the flow ++ * of execution immediately upon a complete(). ++ */ ++ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); ++ ++ pObj->MLMEThr_pid = NULL; ++ ++ complete_and_exit (&pAd->mlmeComplete, 0); ++ return 0; ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ USB command kernel thread. ++ ++Arguments: ++ *Context the pAd, driver control block pointer ++ ++Return Value: ++ 0 close the thread ++ ++Note: ++======================================================================== ++*/ ++INT RTUSBCmdThread( ++ IN void * Context) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)Context; ++ POS_COOKIE pObj; ++ int status; ++ ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ rtmp_os_thread_init("rt2870CmdThread", (PVOID)&(pAd->CmdQComplete)); ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ pAd->CmdQ.CmdQState = RT2870_THREAD_RUNNING; ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ while (pAd->CmdQ.CmdQState == RT2870_THREAD_RUNNING) ++ { ++ /* lock the device pointers */ ++ //down(&(pAd->RTUSBCmd_semaphore)); ++ status = down_interruptible(&(pAd->RTUSBCmd_semaphore)); ++ ++ if (pAd->CmdQ.CmdQState == RT2870_THREAD_STOPED) ++ break; ++ ++ if (status != 0) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ break; ++ } ++ /* lock the device pointers , need to check if required*/ ++ //down(&(pAd->usbdev_semaphore)); ++ ++ if (!pAd->PM_FlgSuspend) ++ CMDHandler(pAd); ++ ++ /* unlock the device pointers */ ++ //up(&(pAd->usbdev_semaphore)); ++ } ++ ++ if (!pAd->PM_FlgSuspend) ++ { // Clear the CmdQElements. ++ CmdQElmt *pCmdQElmt = NULL; ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; ++ while(pAd->CmdQ.size) ++ { ++ RTUSBDequeueCmd(&pAd->CmdQ, &pCmdQElmt); ++ if (pCmdQElmt) ++ { ++ if (pCmdQElmt->CmdFromNdis == TRUE) ++ { ++ if (pCmdQElmt->buffer != NULL) ++ NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); ++ ++ NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ { ++ if ((pCmdQElmt->buffer != NULL) && (pCmdQElmt->bufferlength != 0)) ++ NdisFreeMemory(pCmdQElmt->buffer, pCmdQElmt->bufferlength, 0); ++ { ++ NdisFreeMemory(pCmdQElmt, sizeof(CmdQElmt), 0); ++ } ++ } ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ } ++ /* notify the exit routine that we're actually exiting now ++ * ++ * complete()/wait_for_completion() is similar to up()/down(), ++ * except that complete() is safe in the case where the structure ++ * is getting deleted in a parallel mode of execution (i.e. just ++ * after the down() -- that's necessary for the thread-shutdown ++ * case. ++ * ++ * complete_and_exit() goes even further than this -- it is safe in ++ * the case that the thread of the caller is going away (not just ++ * the structure) -- this is necessary for the module-remove case. ++ * This is important in preemption kernels, which transfer the flow ++ * of execution immediately upon a complete(). ++ */ ++ DBGPRINT(RT_DEBUG_TRACE,( "<---RTUSBCmdThread\n")); ++ ++ pObj->RTUSBCmdThr_pid = NULL; ++ ++ complete_and_exit (&pAd->CmdQComplete, 0); ++ return 0; ++ ++} ++ ++ ++static void RT2870_TimerQ_Handle(RTMP_ADAPTER *pAd) ++{ ++ int status; ++ RALINK_TIMER_STRUCT *pTimer; ++ RT2870_TIMER_ENTRY *pEntry; ++ unsigned long irqFlag; ++ ++ while(!pAd->TimerFunc_kill) ++ { ++// printk("waiting for event!\n"); ++ pTimer = NULL; ++ ++ status = down_interruptible(&(pAd->RTUSBTimer_semaphore)); ++ ++ if (pAd->TimerQ.status == RT2870_THREAD_STOPED) ++ break; ++ ++ // event happened. ++ while(pAd->TimerQ.pQHead) ++ { ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlag); ++ pEntry = pAd->TimerQ.pQHead; ++ if (pEntry) ++ { ++ pTimer = pEntry->pRaTimer; ++ ++ // update pQHead ++ pAd->TimerQ.pQHead = pEntry->pNext; ++ if (pEntry == pAd->TimerQ.pQTail) ++ pAd->TimerQ.pQTail = NULL; ++ ++ // return this queue entry to timerQFreeList. ++ pEntry->pNext = pAd->TimerQ.pQPollFreeList; ++ pAd->TimerQ.pQPollFreeList = pEntry; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlag); ++ ++ if (pTimer) ++ { ++ if (pTimer->handle != NULL) ++ if (!pAd->PM_FlgSuspend) ++ pTimer->handle(NULL, (PVOID) pTimer->cookie, NULL, pTimer); ++ if ((pTimer->Repeat) && (pTimer->State == FALSE)) ++ RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); ++ } ++ } ++ ++ if (status != 0) ++ { ++ pAd->TimerQ.status = RT2870_THREAD_STOPED; ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ break; ++ } ++ } ++} ++ ++ ++INT TimerQThread( ++ IN OUT PVOID Context) ++{ ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ pAd = (PRTMP_ADAPTER)Context; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ rtmp_os_thread_init("rt2870TimerQHandle", (PVOID)&(pAd->TimerQComplete)); ++ ++ RT2870_TimerQ_Handle(pAd); ++ ++ /* notify the exit routine that we're actually exiting now ++ * ++ * complete()/wait_for_completion() is similar to up()/down(), ++ * except that complete() is safe in the case where the structure ++ * is getting deleted in a parallel mode of execution (i.e. just ++ * after the down() -- that's necessary for the thread-shutdown ++ * case. ++ * ++ * complete_and_exit() goes even further than this -- it is safe in ++ * the case that the thread of the caller is going away (not just ++ * the structure) -- this is necessary for the module-remove case. ++ * This is important in preemption kernels, which transfer the flow ++ * of execution immediately upon a complete(). ++ */ ++ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__)); ++ ++ pObj->TimerQThr_pid = NULL; ++ ++ complete_and_exit(&pAd->TimerQComplete, 0); ++ return 0; ++ ++} ++ ++ ++RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer) ++{ ++ RT2870_TIMER_ENTRY *pQNode = NULL, *pQTail; ++ unsigned long irqFlags; ++ ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ if (pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT) ++ { ++ if(pAd->TimerQ.pQPollFreeList) ++ { ++ pQNode = pAd->TimerQ.pQPollFreeList; ++ pAd->TimerQ.pQPollFreeList = pQNode->pNext; ++ ++ pQNode->pRaTimer = pTimer; ++ pQNode->pNext = NULL; ++ ++ pQTail = pAd->TimerQ.pQTail; ++ if (pAd->TimerQ.pQTail != NULL) ++ pQTail->pNext = pQNode; ++ pAd->TimerQ.pQTail = pQNode; ++ if (pAd->TimerQ.pQHead == NULL) ++ pAd->TimerQ.pQHead = pQNode; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ ++ if (pQNode) ++ up(&pAd->RTUSBTimer_semaphore); ++ //wake_up(&timerWaitQ); ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ } ++ return pQNode; ++} ++ ++ ++BOOLEAN RT2870_TimerQ_Remove( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer) ++{ ++ RT2870_TIMER_ENTRY *pNode, *pPrev = NULL; ++ unsigned long irqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ if (pAd->TimerQ.status >= RT2870_THREAD_INITED) ++ { ++ pNode = pAd->TimerQ.pQHead; ++ while (pNode) ++ { ++ if (pNode->pRaTimer == pTimer) ++ break; ++ pPrev = pNode; ++ pNode = pNode->pNext; ++ } ++ ++ // Now move it to freeList queue. ++ if (pNode) ++ { ++ if (pNode == pAd->TimerQ.pQHead) ++ pAd->TimerQ.pQHead = pNode->pNext; ++ if (pNode == pAd->TimerQ.pQTail) ++ pAd->TimerQ.pQTail = pPrev; ++ if (pPrev != NULL) ++ pPrev->pNext = pNode->pNext; ++ ++ // return this queue entry to timerQFreeList. ++ pNode->pNext = pAd->TimerQ.pQPollFreeList; ++ pAd->TimerQ.pQPollFreeList = pNode; ++ } ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ ++ return TRUE; ++} ++ ++ ++void RT2870_TimerQ_Exit(RTMP_ADAPTER *pAd) ++{ ++ RT2870_TIMER_ENTRY *pTimerQ; ++ unsigned long irqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ while (pAd->TimerQ.pQHead) ++ { ++ pTimerQ = pAd->TimerQ.pQHead; ++ pAd->TimerQ.pQHead = pTimerQ->pNext; ++ // remove the timeQ ++ } ++ pAd->TimerQ.pQPollFreeList = NULL; ++ os_free_mem(pAd, pAd->TimerQ.pTimerQPoll); ++ pAd->TimerQ.pQTail = NULL; ++ pAd->TimerQ.pQHead = NULL; ++ pAd->TimerQ.status = RT2870_THREAD_STOPED; ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++ ++} ++ ++ ++void RT2870_TimerQ_Init(RTMP_ADAPTER *pAd) ++{ ++ int i; ++ RT2870_TIMER_ENTRY *pQNode, *pEntry; ++ unsigned long irqFlags; ++ ++ NdisAllocateSpinLock(&pAd->TimerQLock); ++ ++ RTMP_IRQ_LOCK(&pAd->TimerQLock, irqFlags); ++ NdisZeroMemory(&pAd->TimerQ, sizeof(pAd->TimerQ)); ++ //InterlockedExchange(&pAd->TimerQ.count, 0); ++ ++ /* Initialise the wait q head */ ++ //init_waitqueue_head(&timerWaitQ); ++ ++ os_alloc_mem(pAd, &pAd->TimerQ.pTimerQPoll, sizeof(RT2870_TIMER_ENTRY) * TIMER_QUEUE_SIZE_MAX); ++ if (pAd->TimerQ.pTimerQPoll) ++ { ++ pEntry = NULL; ++ pQNode = (RT2870_TIMER_ENTRY *)pAd->TimerQ.pTimerQPoll; ++ for (i = 0 ;i pNext = pEntry; ++ pEntry = pQNode; ++ pQNode++; ++ } ++ pAd->TimerQ.pQPollFreeList = pEntry; ++ pAd->TimerQ.pQHead = NULL; ++ pAd->TimerQ.pQTail = NULL; ++ pAd->TimerQ.status = RT2870_THREAD_INITED; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TimerQLock, irqFlags); ++} ++ ++ ++VOID RT2870_WatchDog(IN RTMP_ADAPTER *pAd) ++{ ++ PHT_TX_CONTEXT pHTTXContext; ++ int idx; ++ ULONG irqFlags; ++ PURB pUrb; ++ BOOLEAN needDumpSeq = FALSE; ++ UINT32 MACValue; ++ ++ ++ idx = 0; ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); ++ if ((MACValue & 0xff) !=0 ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 0 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40012); ++ while((MACValue &0xff) != 0 && (idx++ < 10)) ++ { ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); ++ NdisMSleep(1); ++ } ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); ++ } ++ ++//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ idx = 0; ++ if ((MACValue & 0xff00) !=0 ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("TX QUEUE 1 Not EMPTY(Value=0x%0x). !!!!!!!!!!!!!!!\n", MACValue)); ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf4000a); ++ while((MACValue &0xff00) != 0 && (idx++ < 10)) ++ { ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); ++ NdisMSleep(1); ++ } ++ RTMP_IO_WRITE32(pAd, PBF_CFG, 0xf40006); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pAd->watchDogRxOverFlowCnt >= 2) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Rx Bulk-In hanged! Cancel the pending Rx bulks request!\n")); ++ if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_BULKIN_RESET | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Call CMDTHREAD_RESET_BULK_IN to cancel the pending Rx Bulk!\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); ++ needDumpSeq = TRUE; ++ } ++ pAd->watchDogRxOverFlowCnt = 0; ++ } ++ ++ ++ for (idx = 0; idx < NUM_OF_TX_RING; idx++) ++ { ++ pUrb = NULL; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[idx], irqFlags); ++ if ((pAd->BulkOutPending[idx] == TRUE) && pAd->watchDogTxPendingCnt) ++ { ++ pAd->watchDogTxPendingCnt[idx]++; ++ ++ if ((pAd->watchDogTxPendingCnt[idx] > 2) && ++ (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_BULKOUT_RESET))) ++ ) ++ { ++ // FIXME: Following code just support single bulk out. If you wanna support multiple bulk out. Modify it! ++ pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[idx]); ++ if (pHTTXContext->IRPPending) ++ { // Check TxContext. ++ pUrb = pHTTXContext->pUrb; ++ } ++ else if (idx == MGMTPIPEIDX) ++ { ++ PTX_CONTEXT pMLMEContext, pNULLContext, pPsPollContext; ++ ++ //Check MgmtContext. ++ pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); ++ pPsPollContext = (PTX_CONTEXT)(&pAd->PsPollContext); ++ pNULLContext = (PTX_CONTEXT)(&pAd->NullContext); ++ ++ if (pMLMEContext->IRPPending) ++ { ++ ASSERT(pMLMEContext->IRPPending); ++ pUrb = pMLMEContext->pUrb; ++ } ++ else if (pNULLContext->IRPPending) ++ { ++ ASSERT(pNULLContext->IRPPending); ++ pUrb = pNULLContext->pUrb; ++ } ++ else if (pPsPollContext->IRPPending) ++ { ++ ASSERT(pPsPollContext->IRPPending); ++ pUrb = pPsPollContext->pUrb; ++ } ++ } ++ ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Maybe the Tx Bulk-Out hanged! Cancel the pending Tx bulks request of idx(%d)!\n", idx)); ++ if (pUrb) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Unlink the pending URB!\n")); ++ // unlink it now ++ RTUSB_UNLINK_URB(pUrb); ++ // Sleep 200 microseconds to give cancellation time to work ++ RTMPusecDelay(200); ++ needDumpSeq = TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Unkonw bulkOut URB maybe hanged!!!!!!!!!!!!\n")); ++ } ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); ++ } ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[idx], irqFlags); ++ } ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // For Sigma debug, dump the ba_reordering sequence. ++ if((needDumpSeq == TRUE) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ USHORT Idx; ++ PBA_REC_ENTRY pBAEntry = NULL; ++ UCHAR count = 0; ++ struct reordering_mpdu *mpdu_blk; ++ ++ Idx = pAd->MacTab.Content[BSSID_WCID].BARecWcidArray[0]; ++ ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ if((pBAEntry->list.qlen > 0) && (pBAEntry->list.next != NULL)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("NICUpdateRawCounters():The Queueing pkt in reordering buffer:\n")); ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ mpdu_blk = pBAEntry->list.next; ++ while (mpdu_blk) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("\t%d:Seq-%d, bAMSDU-%d!\n", count, mpdu_blk->Sequence, mpdu_blk->bAMSDU)); ++ mpdu_blk = mpdu_blk->next; ++ count++; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\npBAEntry->LastIndSeq=%d!\n", pBAEntry->LastIndSeq)); ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Release allocated resources. ++ ++Arguments: ++ *dev Point to the PCI or USB device ++ pAd driver control block pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++static void _rtusb_disconnect(struct usb_device *dev, PRTMP_ADAPTER pAd) ++{ ++ struct net_device *net_dev = NULL; ++ ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("rtusb_disconnect: unregister usbnet usb-%s-%s\n", ++ dev->bus->bus_name, dev->devpath)); ++ if (!pAd) ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD)) ++ MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ while(MOD_IN_USE > 0) ++ { ++ MOD_DEC_USE_COUNT; ++ } ++#else ++ usb_put_dev(dev); ++#endif // LINUX_VERSION_CODE // ++ ++ printk("rtusb_disconnect: pAd == NULL!\n"); ++ return; ++ } ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); ++ ++ ++ ++ // for debug, wait to show some messages to /proc system ++ udelay(1); ++ ++ ++ ++ ++ net_dev = pAd->net_dev; ++ if (pAd->net_dev != NULL) ++ { ++ printk("rtusb_disconnect: unregister_netdev(), dev->name=%s!\n", net_dev->name); ++ unregister_netdev (pAd->net_dev); ++ } ++ udelay(1); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++#else ++ flush_scheduled_work(); ++#endif // LINUX_VERSION_CODE // ++ udelay(1); ++ ++ // free net_device memory ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ kfree(net_dev); ++#else ++ free_netdev(net_dev); ++#endif // LINUX_VERSION_CODE // ++ ++ // free adapter memory ++ RTMPFreeAdapter(pAd); ++ ++ // release a use of the usb device structure ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ while(MOD_IN_USE > 0) ++ { ++ MOD_DEC_USE_COUNT; ++ } ++#else ++ usb_put_dev(dev); ++#endif // LINUX_VERSION_CODE // ++ udelay(1); ++ ++ DBGPRINT(RT_DEBUG_ERROR, (" RTUSB disconnect successfully\n")); ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Probe RT28XX chipset. ++ ++Arguments: ++ *dev Point to the PCI or USB device ++ interface ++ *id_table Point to the PCI or USB device ID ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++static void *rtusb_probe(struct usb_device *dev, UINT interface, ++ const struct usb_device_id *id) ++{ ++ PRTMP_ADAPTER pAd; ++ rt28xx_probe((void *)dev, (void *)id, interface, &pAd); ++ return (void *)pAd; ++} ++ ++//Disconnect function is called within exit routine ++static void rtusb_disconnect(struct usb_device *dev, void *ptr) ++{ ++ _rtusb_disconnect(dev, ((PRTMP_ADAPTER)ptr)); ++} ++ ++#else /* kernel 2.6 series */ ++static int rtusb_probe (struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ PRTMP_ADAPTER pAd; ++ return (int)rt28xx_probe((void *)intf, (void *)id, 0, &pAd); ++} ++ ++ ++static void rtusb_disconnect(struct usb_interface *intf) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ PRTMP_ADAPTER pAd; ++ ++ ++ pAd = usb_get_intfdata(intf); ++ usb_set_intfdata(intf, NULL); ++ ++ _rtusb_disconnect(dev, pAd); ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Close kernel threads. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ NONE ++ ++Note: ++======================================================================== ++*/ ++VOID RT28xxThreadTerminate( ++ IN RTMP_ADAPTER *pAd) ++{ ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ INT ret; ++ ++ ++ // Sleep 50 milliseconds so pending io might finish normally ++ RTMPusecDelay(50000); ++ ++ // We want to wait until all pending receives and sends to the ++ // device object. We cancel any ++ // irps. Wait until sends and receives have stopped. ++ RTUSBCancelPendingIRPs(pAd); ++ ++ // Terminate Threads ++ if (pObj->MLMEThr_pid) ++ { ++ printk("Terminate the MLMEThr_pid=%d!\n", pid_nr(pObj->MLMEThr_pid)); ++ mb(); ++ pAd->mlme_kill = 1; ++ //RT28XX_MLME_HANDLER(pAd); ++ mb(); ++ ret = kill_pid(pObj->MLMEThr_pid, SIGTERM, 1); ++ if (ret) ++ { ++ printk (KERN_WARNING "%s: unable to Mlme thread, pid=%d, ret=%d!\n", ++ pAd->net_dev->name, pid_nr(pObj->MLMEThr_pid), ret); ++ } ++ else ++ { ++ //wait_for_completion (&pAd->notify); ++ wait_for_completion (&pAd->mlmeComplete); ++ pObj->MLMEThr_pid = NULL; ++ } ++ } ++ ++ if (pObj->RTUSBCmdThr_pid >= 0) ++ { ++ printk("Terminate the RTUSBCmdThr_pid=%d!\n", pid_nr(pObj->RTUSBCmdThr_pid)); ++ mb(); ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ pAd->CmdQ.CmdQState = RT2870_THREAD_STOPED; ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ mb(); ++ //RTUSBCMDUp(pAd); ++ ret = kill_pid(pObj->RTUSBCmdThr_pid, SIGTERM, 1); ++ if (ret) ++ { ++ printk(KERN_WARNING "%s: unable to RTUSBCmd thread, pid=%d, ret=%d!\n", ++ pAd->net_dev->name, pid_nr(pObj->RTUSBCmdThr_pid), ret); ++ } ++ else ++ { ++ //wait_for_completion (&pAd->notify); ++ wait_for_completion (&pAd->CmdQComplete); ++ pObj->RTUSBCmdThr_pid = NULL; ++ } ++ } ++ if (pObj->TimerQThr_pid >= 0) ++ { ++ POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ printk("Terminate the TimerQThr_pid=%d!\n", pid_nr(pObj->TimerQThr_pid)); ++ mb(); ++ pAd->TimerFunc_kill = 1; ++ mb(); ++ ret = kill_pid(pObj->TimerQThr_pid, SIGTERM, 1); ++ if (ret) ++ { ++ printk(KERN_WARNING "%s: unable to stop TimerQThread, pid=%d, ret=%d!\n", ++ pAd->net_dev->name, pid_nr(pObj->TimerQThr_pid), ret); ++ } ++ else ++ { ++ printk("wait_for_completion TimerQThr\n"); ++ wait_for_completion(&pAd->TimerQComplete); ++ pObj->TimerQThr_pid = NULL; ++ } ++ } ++ // Kill tasklets ++ pAd->mlme_kill = 0; ++ pAd->CmdQ.CmdQState = RT2870_THREAD_UNKNOWN; ++ pAd->TimerFunc_kill = 0; ++} ++ ++ ++void kill_thread_task(IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE pObj; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ tasklet_kill(&pObj->rx_done_task); ++ tasklet_kill(&pObj->mgmt_dma_done_task); ++ tasklet_kill(&pObj->ac0_dma_done_task); ++ tasklet_kill(&pObj->ac1_dma_done_task); ++ tasklet_kill(&pObj->ac2_dma_done_task); ++ tasklet_kill(&pObj->ac3_dma_done_task); ++ tasklet_kill(&pObj->hcca_dma_done_task); ++ tasklet_kill(&pObj->tbtt_task); ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Check the chipset vendor/product ID. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ ++Return Value: ++ TRUE Check ok ++ FALSE Check fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXChipsetCheck( ++ IN void *_dev_p) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++#else ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_device *dev_p = interface_to_usbdev(intf); ++#endif // LINUX_VERSION_CODE // ++ UINT32 i; ++ ++ ++ for(i=0; idescriptor.idVendor == rtusb_usb_id[i].idVendor && ++ dev_p->descriptor.idProduct == rtusb_usb_id[i].idProduct) ++ { ++ printk("rt2870: idVendor = 0x%x, idProduct = 0x%x\n", ++ dev_p->descriptor.idVendor, dev_p->descriptor.idProduct); ++ break; ++ } ++ } ++ ++ if (i == rtusb_usb_id_len) ++ { ++ printk("rt2870: Error! Device Descriptor not matching!\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Init net device structure. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ *net_dev Point to the net device ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ TRUE Init ok ++ FALSE Init fail ++ ++Note: ++======================================================================== ++*/ ++BOOLEAN RT28XXNetDevInit( ++ IN void *_dev_p, ++ IN struct net_device *net_dev, ++ IN RTMP_ADAPTER *pAd) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++#else ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_device *dev_p = interface_to_usbdev(intf); ++#endif // LINUX_VERSION_CODE // ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ pAd->config = dev_p->config; ++#else ++ pAd->config = &dev_p->config->desc; ++#endif // LINUX_VERSION_CODE // ++ return TRUE; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Init net device structure. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ TRUE Config ok ++ FALSE Config fail ++ ++Note: ++======================================================================== ++*/ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 interface) ++{ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++ struct usb_interface *intf; ++ struct usb_interface_descriptor *iface_desc; ++ struct usb_endpoint_descriptor *endpoint; ++ ULONG BulkOutIdx; ++ UINT32 i; ++ ++ ++ /* get the active interface descriptor */ ++ intf = &dev_p->actconfig->interface[interface]; ++ iface_desc = &intf->altsetting[0]; ++ ++ /* get # of enpoints */ ++ pAd->NumberOfPipes = iface_desc->bNumEndpoints; ++ DBGPRINT(RT_DEBUG_TRACE, ("NumEndpoints=%d\n", iface_desc->bNumEndpoints)); ++ ++ /* Configure Pipes */ ++ endpoint = &iface_desc->endpoint[0]; ++ BulkOutIdx = 0; ++ ++ for(i=0; iNumberOfPipes; i++) ++ { ++ if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && ++ ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) ++ { ++ pAd->BulkInEpAddr = endpoint[i].bEndpointAddress; ++ pAd->BulkInMaxPacketSize = endpoint[i].wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); ++ } ++ else if ((endpoint[i].bmAttributes == USB_ENDPOINT_XFER_BULK) && ++ ((endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) ++ { ++ // There are 6 bulk out EP. EP6 highest priority. ++ // EP1-4 is EDCA. EP5 is HCCA. ++ pAd->BulkOutEpAddr[BulkOutIdx++] = endpoint[i].bEndpointAddress; ++ pAd->BulkOutMaxPacketSize = endpoint[i].wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x \n", endpoint[i].bEndpointAddress)); ++ } ++ } ++ ++ if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) ++ { ++ printk("Could not find both bulk-in and bulk-out endpoints\n"); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++#else ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 interface) ++{ ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_host_interface *iface_desc; ++ ULONG BulkOutIdx; ++ UINT32 i; ++ ++ ++ /* get the active interface descriptor */ ++ iface_desc = intf->cur_altsetting; ++ ++ /* get # of enpoints */ ++ pAd->NumberOfPipes = iface_desc->desc.bNumEndpoints; ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("NumEndpoints=%d\n", iface_desc->desc.bNumEndpoints)); ++ ++ /* Configure Pipes */ ++ BulkOutIdx = 0; ++ ++ for(i=0; iNumberOfPipes; i++) ++ { ++ if ((iface_desc->endpoint[i].desc.bmAttributes == ++ USB_ENDPOINT_XFER_BULK) && ++ ((iface_desc->endpoint[i].desc.bEndpointAddress & ++ USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)) ++ { ++ pAd->BulkInEpAddr = iface_desc->endpoint[i].desc.bEndpointAddress; ++ pAd->BulkInMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK IN MaximumPacketSize = %d\n", pAd->BulkInMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x\n", iface_desc->endpoint[i].desc.bEndpointAddress)); ++ } ++ else if ((iface_desc->endpoint[i].desc.bmAttributes == ++ USB_ENDPOINT_XFER_BULK) && ++ ((iface_desc->endpoint[i].desc.bEndpointAddress & ++ USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) ++ { ++ // there are 6 bulk out EP. EP6 highest priority. ++ // EP1-4 is EDCA. EP5 is HCCA. ++ pAd->BulkOutEpAddr[BulkOutIdx++] = iface_desc->endpoint[i].desc.bEndpointAddress; ++ pAd->BulkOutMaxPacketSize = iface_desc->endpoint[i].desc.wMaxPacketSize; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("BULK OUT MaximumPacketSize = %d\n", pAd->BulkOutMaxPacketSize)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ++ ("EP address = 0x%2x \n", iface_desc->endpoint[i].desc.bEndpointAddress)); ++ } ++ } ++ ++ if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0])) ++ { ++ printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Disable DMA. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28XXDMADisable( ++ IN RTMP_ADAPTER *pAd) ++{ ++ // no use ++} ++ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Enable DMA. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28XXDMAEnable( ++ IN RTMP_ADAPTER *pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ USB_DMA_CFG_STRUC UsbCfg; ++ int i = 0; ++ ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4); ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n")); ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i <200); ++ ++ ++ RTMPusecDelay(50); ++ GloCfg.field.EnTXWriteBackDDONE = 1; ++ GloCfg.field.EnableRxDMA = 1; ++ GloCfg.field.EnableTxDMA = 1; ++ DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ UsbCfg.word = 0; ++ UsbCfg.field.phyclear = 0; ++ /* usb version is 1.1,do not use bulk in aggregation */ ++ if (pAd->BulkInMaxPacketSize == 512) ++ UsbCfg.field.RxBulkAggEn = 1; ++ /* for last packet, PBF might use more than limited, so minus 2 to prevent from error */ ++ UsbCfg.field.RxBulkAggLmt = (MAX_RXBULK_SIZE /1024)-3; ++ UsbCfg.field.RxBulkAggTOut = 0x80; /* 2006-10-18 */ ++ UsbCfg.field.RxBulkEn = 1; ++ UsbCfg.field.TxBulkEn = 1; ++ ++ RTUSBWriteMACRegister(pAd, USB_DMA_CFG, UsbCfg.word); ++ ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Write Beacon buffer to Asic. ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RT28xx_UpdateBeaconToAsic( ++ IN RTMP_ADAPTER *pAd, ++ IN INT apidx, ++ IN ULONG FrameLen, ++ IN ULONG UpdatePos) ++{ ++ PUCHAR pBeaconFrame = NULL; ++ UCHAR *ptr; ++ UINT i, padding; ++ BEACON_SYNC_STRUCT *pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ UINT32 longValue; ++// USHORT shortValue; ++ BOOLEAN bBcnReq = FALSE; ++ UCHAR bcn_idx = 0; ++ ++ ++ if (pBeaconFrame == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("pBeaconFrame is NULL!\n")); ++ return; ++ } ++ ++ if (pBeaconSync == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("pBeaconSync is NULL!\n")); ++ return; ++ } ++ ++ //if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE) || ++ // ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL) || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP)) ++ // ) ++ if (bBcnReq == FALSE) ++ { ++ /* when the ra interface is down, do not send its beacon frame */ ++ /* clear all zero */ ++ for(i=0; iBeaconOffset[bcn_idx] + i, 0x00); ++ } ++ pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[bcn_idx], TXWI_SIZE); ++ } ++ else ++ { ++ ptr = (PUCHAR)&pAd->BeaconTxWI; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(ptr, TYPE_TXWI); ++#endif ++ if (NdisEqualMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE) == FALSE) ++ { // If BeaconTxWI changed, we need to rewrite the TxWI for the Beacon frames. ++ pBeaconSync->BeaconBitMap &= (~(BEACON_BITMAP_MASK & (1 << bcn_idx))); ++ NdisMoveMemory(pBeaconSync->BeaconTxWI[bcn_idx], &pAd->BeaconTxWI, TXWI_SIZE); ++ } ++ ++ if ((pBeaconSync->BeaconBitMap & (1 << bcn_idx)) != (1 << bcn_idx)) ++ { ++ for (i=0; iBeaconOffset[bcn_idx] + i, longValue); ++ ptr += 4; ++ } ++ } ++ ++ ptr = pBeaconSync->BeaconBuf[bcn_idx]; ++ padding = (FrameLen & 0x01); ++ NdisZeroMemory((PUCHAR)(pBeaconFrame + FrameLen), padding); ++ FrameLen += padding; ++ for (i = 0 ; i < FrameLen /*HW_BEACON_OFFSET*/; i += 2) ++ { ++ if (NdisEqualMemory(ptr, pBeaconFrame, 2) == FALSE) ++ { ++ NdisMoveMemory(ptr, pBeaconFrame, 2); ++ //shortValue = *ptr + (*(ptr+1)<<8); ++ //RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, shortValue); ++ RTUSBMultiWrite(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, ptr, 2); ++ } ++ ptr +=2; ++ pBeaconFrame += 2; ++ } ++ ++ pBeaconSync->BeaconBitMap |= (1 << bcn_idx); ++ ++ // For AP interface, set the DtimBitOn so that we can send Bcast/Mcast frame out after this beacon frame. ++ } ++ ++} ++ ++ ++VOID RT2870_BssBeaconStop( ++ IN RTMP_ADAPTER *pAd) ++{ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ int i, offset; ++ BOOLEAN Cancelled = TRUE; ++ ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ if (pBeaconSync && pBeaconSync->EnableBeacon) ++ { ++ INT NumOfBcn; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NumOfBcn = MAX_MESH_NUM; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); ++ ++ for(i=0; iBeaconBuf[i], HW_BEACON_OFFSET); ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); ++ ++ for (offset=0; offsetBeaconOffset[i] + offset, 0x00); ++ ++ pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; ++ pBeaconSync->TimIELocationInBeacon[i] = 0; ++ } ++ pBeaconSync->BeaconBitMap = 0; ++ pBeaconSync->DtimBitOn = 0; ++ } ++} ++ ++ ++VOID RT2870_BssBeaconStart( ++ IN RTMP_ADAPTER *pAd) ++{ ++ int apidx; ++ BEACON_SYNC_STRUCT *pBeaconSync; ++// LARGE_INTEGER tsfTime, deltaTime; ++ ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ if (pBeaconSync && pBeaconSync->EnableBeacon) ++ { ++ INT NumOfBcn; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NumOfBcn = MAX_MESH_NUM; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ for(apidx=0; apidxBeaconBuf[apidx], HW_BEACON_OFFSET); ++ pBeaconSync->CapabilityInfoLocationInBeacon[apidx] = CapabilityInfoLocationInBeacon; ++ pBeaconSync->TimIELocationInBeacon[apidx] = TimIELocationInBeacon; ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[apidx], TXWI_SIZE); ++ } ++ pBeaconSync->BeaconBitMap = 0; ++ pBeaconSync->DtimBitOn = 0; ++ pAd->CommonCfg.BeaconUpdateTimer.Repeat = TRUE; ++ ++ pAd->CommonCfg.BeaconAdjust = 0; ++ pAd->CommonCfg.BeaconFactor = 0xffffffff / (pAd->CommonCfg.BeaconPeriod << 10); ++ pAd->CommonCfg.BeaconRemain = (0xffffffff % (pAd->CommonCfg.BeaconPeriod << 10)) + 1; ++ printk("RT2870_BssBeaconStart:BeaconFactor=%d, BeaconRemain=%d!\n", pAd->CommonCfg.BeaconFactor, pAd->CommonCfg.BeaconRemain); ++ RTMPSetTimer(&pAd->CommonCfg.BeaconUpdateTimer, pAd->CommonCfg.BeaconPeriod); ++ ++ } ++} ++ ++ ++VOID RT2870_BssBeaconInit( ++ IN RTMP_ADAPTER *pAd) ++{ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ int i; ++ ++ NdisAllocMemory(pAd->CommonCfg.pBeaconSync, sizeof(BEACON_SYNC_STRUCT), MEM_ALLOC_FLAG); ++ if (pAd->CommonCfg.pBeaconSync) ++ { ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ NdisZeroMemory(pBeaconSync, sizeof(BEACON_SYNC_STRUCT)); ++ for(i=0; i < HW_BEACON_MAX_COUNT; i++) ++ { ++ NdisZeroMemory(pBeaconSync->BeaconBuf[i], HW_BEACON_OFFSET); ++ pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; ++ pBeaconSync->TimIELocationInBeacon[i] = 0; ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); ++ } ++ pBeaconSync->BeaconBitMap = 0; ++ ++ //RTMPInitTimer(pAd, &pAd->CommonCfg.BeaconUpdateTimer, GET_TIMER_FUNCTION(BeaconUpdateExec), pAd, TRUE); ++ pBeaconSync->EnableBeacon = TRUE; ++ } ++} ++ ++ ++VOID RT2870_BssBeaconExit( ++ IN RTMP_ADAPTER *pAd) ++{ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ BOOLEAN Cancelled = TRUE; ++ int i; ++ ++ if (pAd->CommonCfg.pBeaconSync) ++ { ++ pBeaconSync = pAd->CommonCfg.pBeaconSync; ++ pBeaconSync->EnableBeacon = FALSE; ++ RTMPCancelTimer(&pAd->CommonCfg.BeaconUpdateTimer, &Cancelled); ++ pBeaconSync->BeaconBitMap = 0; ++ ++ for(i=0; iBeaconBuf[i], HW_BEACON_OFFSET); ++ pBeaconSync->CapabilityInfoLocationInBeacon[i] = 0; ++ pBeaconSync->TimIELocationInBeacon[i] = 0; ++ NdisZeroMemory(pBeaconSync->BeaconTxWI[i], TXWI_SIZE); ++ } ++ ++ NdisFreeMemory(pAd->CommonCfg.pBeaconSync, HW_BEACON_OFFSET * HW_BEACON_MAX_COUNT, 0); ++ pAd->CommonCfg.pBeaconSync = NULL; ++ } ++} ++ ++VOID BeaconUpdateExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; ++ LARGE_INTEGER tsfTime_a;//, tsfTime_b, deltaTime_exp, deltaTime_ab; ++ UINT32 delta, remain, remain_low, remain_high; ++// BOOLEAN positive; ++ ++ ReSyncBeaconTime(pAd); ++ ++ ++ ++ RTMP_IO_READ32(pAd, TSF_TIMER_DW0, &tsfTime_a.u.LowPart); ++ RTMP_IO_READ32(pAd, TSF_TIMER_DW1, &tsfTime_a.u.HighPart); ++ ++ ++ //positive=getDeltaTime(tsfTime_a, expectedTime, &deltaTime_exp); ++ remain_high = pAd->CommonCfg.BeaconRemain * tsfTime_a.u.HighPart; ++ remain_low = tsfTime_a.u.LowPart % (pAd->CommonCfg.BeaconPeriod << 10); ++ remain = (remain_high + remain_low)%(pAd->CommonCfg.BeaconPeriod << 10); ++ delta = (pAd->CommonCfg.BeaconPeriod << 10) - remain; ++ ++ pAd->CommonCfg.BeaconUpdateTimer.TimerValue = (delta >> 10) + 10; ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/action.h +@@ -0,0 +1,68 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 04-06-15 Initial ++*/ ++ ++#ifndef __ACTION_H__ ++#define __ACTION_H__ ++ ++typedef struct PACKED __HT_INFO_OCTET ++{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR Reserved:5; ++ UCHAR STA_Channel_Width:1; ++ UCHAR Forty_MHz_Intolerant:1; ++ UCHAR Request:1; ++#else ++ UCHAR Request:1; ++ UCHAR Forty_MHz_Intolerant:1; ++ UCHAR STA_Channel_Width:1; ++ UCHAR Reserved:5; ++#endif ++} HT_INFORMATION_OCTET; ++ ++ ++typedef struct PACKED __FRAME_HT_INFO ++{ ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ HT_INFORMATION_OCTET HT_Info; ++} FRAME_HT_INFO, *PFRAME_HT_INFO; ++ ++#endif /* __ACTION_H__ */ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/aironet.h +@@ -0,0 +1,210 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 04-06-15 Initial ++*/ ++ ++#ifndef __AIRONET_H__ ++#define __AIRONET_H__ ++ ++// Measurement Type definition ++#define MSRN_TYPE_UNUSED 0 ++#define MSRN_TYPE_CHANNEL_LOAD_REQ 1 ++#define MSRN_TYPE_NOISE_HIST_REQ 2 ++#define MSRN_TYPE_BEACON_REQ 3 ++#define MSRN_TYPE_FRAME_REQ 4 ++ ++// Scan Mode in Beacon Request ++#define MSRN_SCAN_MODE_PASSIVE 0 ++#define MSRN_SCAN_MODE_ACTIVE 1 ++#define MSRN_SCAN_MODE_BEACON_TABLE 2 ++ ++// PHY type definition for Aironet beacon report, CCX 2 table 36-9 ++#define PHY_FH 1 ++#define PHY_DSS 2 ++#define PHY_UNUSED 3 ++#define PHY_OFDM 4 ++#define PHY_HR_DSS 5 ++#define PHY_ERP 6 ++ ++// RPI table in dBm ++#define RPI_0 0 // Power <= -87 ++#define RPI_1 1 // -87 < Power <= -82 ++#define RPI_2 2 // -82 < Power <= -77 ++#define RPI_3 3 // -77 < Power <= -72 ++#define RPI_4 4 // -72 < Power <= -67 ++#define RPI_5 5 // -67 < Power <= -62 ++#define RPI_6 6 // -62 < Power <= -57 ++#define RPI_7 7 // -57 < Power ++ ++// Cisco Aironet IAPP definetions ++#define AIRONET_IAPP_TYPE 0x32 ++#define AIRONET_IAPP_SUBTYPE_REQUEST 0x01 ++#define AIRONET_IAPP_SUBTYPE_REPORT 0x81 ++ ++// Measurement Request detail format ++typedef struct _MEASUREMENT_REQUEST { ++ UCHAR Channel; ++ UCHAR ScanMode; // Use only in beacon request, other requests did not use this field ++ USHORT Duration; ++} MEASUREMENT_REQUEST, *PMEASUREMENT_REQUEST; ++ ++// Beacon Measurement Report ++// All these field might change to UCHAR, because we didn't do anything to these report. ++// We copy all these beacons and report to CCX 2 AP. ++typedef struct _BEACON_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR PhyType; // Definiation is listed above table 36-9 ++ UCHAR RxPower; ++ UCHAR BSSID[6]; ++ UCHAR ParentTSF[4]; ++ UCHAR TargetTSF[8]; ++ USHORT BeaconInterval; ++ USHORT CapabilityInfo; ++} BEACON_REPORT, *PBEACON_REPORT; ++ ++// Frame Measurement Report (Optional) ++typedef struct _FRAME_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR TA; ++ UCHAR BSSID[6]; ++ UCHAR RSSI; ++ UCHAR Count; ++} FRAME_REPORT, *PFRAME_REPORT; ++ ++#pragma pack(1) ++// Channel Load Report ++typedef struct _CHANNEL_LOAD_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR CCABusy; ++} CHANNEL_LOAD_REPORT, *PCHANNEL_LOAD_REPORT; ++#pragma pack() ++ ++// Nosie Histogram Report ++typedef struct _NOISE_HIST_REPORT { ++ UCHAR Channel; ++ UCHAR Spare; ++ USHORT Duration; ++ UCHAR Density[8]; ++} NOISE_HIST_REPORT, *PNOISE_HIST_REPORT; ++ ++// Radio Management Capability element ++typedef struct _RADIO_MANAGEMENT_CAPABILITY { ++ UCHAR Eid; // TODO: Why the Eid is 1 byte, not normal 2 bytes??? ++ UCHAR Length; ++ UCHAR AironetOui[3]; // AIronet OUI (00 40 96) ++ UCHAR Type; // Type / Version ++ USHORT Status; // swap16 required ++} RADIO_MANAGEMENT_CAPABILITY, *PRADIO_MANAGEMENT_CAPABILITY; ++ ++// Measurement Mode Bit definition ++typedef struct _MEASUREMENT_MODE { ++ UCHAR Rsvd:4; ++ UCHAR Report:1; ++ UCHAR NotUsed:1; ++ UCHAR Enable:1; ++ UCHAR Parallel:1; ++} MEASUREMENT_MODE, *PMEASUREMENT_MODE; ++ ++// Measurement Request element, This is little endian mode ++typedef struct _MEASUREMENT_REQUEST_ELEMENT { ++ USHORT Eid; ++ USHORT Length; // swap16 required ++ USHORT Token; // non-zero unique token ++ UCHAR Mode; // Measurement Mode ++ UCHAR Type; // Measurement type ++} MEASUREMENT_REQUEST_ELEMENT, *PMEASUREMENT_REQUEST_ELEMENT; ++ ++// Measurement Report element, This is little endian mode ++typedef struct _MEASUREMENT_REPORT_ELEMENT { ++ USHORT Eid; ++ USHORT Length; // swap16 required ++ USHORT Token; // non-zero unique token ++ UCHAR Mode; // Measurement Mode ++ UCHAR Type; // Measurement type ++} MEASUREMENT_REPORT_ELEMENT, *PMEASUREMENT_REPORT_ELEMENT; ++ ++// Cisco Aironet IAPP Frame Header, Network byte order used ++typedef struct _AIRONET_IAPP_HEADER { ++ UCHAR CiscoSnapHeader[8]; // 8 bytes Cisco snap header ++ USHORT Length; // IAPP ID & length, remember to swap16 in LE system ++ UCHAR Type; // IAPP type ++ UCHAR SubType; // IAPP subtype ++ UCHAR DA[6]; // Destination MAC address ++ UCHAR SA[6]; // Source MAC address ++ USHORT Token; // Dialog token, no need to swap16 since it is for yoken usage only ++} AIRONET_IAPP_HEADER, *PAIRONET_IAPP_HEADER; ++ ++// Radio Measurement Request frame ++typedef struct _AIRONET_RM_REQUEST_FRAME { ++ AIRONET_IAPP_HEADER IAPP; // Common header ++ UCHAR Delay; // Activation Delay ++ UCHAR Offset; // Measurement offset ++} AIRONET_RM_REQUEST_FRAME, *PAIRONET_RM_REQUEST_FRAME; ++ ++// Radio Measurement Report frame ++typedef struct _AIRONET_RM_REPORT_FRAME { ++ AIRONET_IAPP_HEADER IAPP; // Common header ++} AIRONET_RM_REPORT_FRAME, *PAIRONET_RM_REPORT_FRAME; ++ ++// Saved element request actions which will saved in StaCfg. ++typedef struct _RM_REQUEST_ACTION { ++ MEASUREMENT_REQUEST_ELEMENT ReqElem; // Saved request element ++ MEASUREMENT_REQUEST Measurement; // Saved measurement within the request element ++} RM_REQUEST_ACTION, *PRM_REQUEST_ACTION; ++ ++// CCX administration control ++typedef union _CCX_CONTROL { ++ struct { ++ UINT32 Enable:1; // Enable CCX2 ++ UINT32 LeapEnable:1; // Enable LEAP at CCX2 ++ UINT32 RMEnable:1; // Radio Measurement Enable ++ UINT32 DCRMEnable:1; // Non serving channel Radio Measurement enable ++ UINT32 QOSEnable:1; // Enable QOS for CCX 2.0 support ++ UINT32 FastRoamEnable:1; // Enable fast roaming ++ UINT32 Rsvd:2; // Not used ++ UINT32 dBmToRoam:8; // the condition to roam when receiving Rssi less than this value. It's negative value. ++ UINT32 TuLimit:16; // Limit for different channel scan ++ } field; ++ UINT32 word; ++} CCX_CONTROL, *PCCX_CONTROL; ++ ++#endif // __AIRONET_H__ +--- /dev/null ++++ b/drivers/staging/rt3070/ap.h +@@ -0,0 +1,557 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ ap.h ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ James Tan 09-06-2002 modified (Revise NTCRegTable) ++ John Chang 12-22-2004 modified for RT2561/2661. merge with STA driver ++*/ ++#ifndef __AP_H__ ++#define __AP_H__ ++ ++ ++ ++// ========================= AP RTMP.h ================================ ++ ++ ++ ++// ============================================================= ++// Function Prototypes ++// ============================================================= ++ ++// ap_data.c ++ ++BOOLEAN APBridgeToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN ULONG fromwdsidx); ++ ++BOOLEAN APHandleRxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APSendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets); ++ ++NDIS_STATUS APSendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++NDIS_STATUS APHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++VOID APRxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++NDIS_STATUS APCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN UCHAR Wcid); ++ ++BOOLEAN APCheckClass2Class3Error( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++VOID APHandleRxPsPoll( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN USHORT Aid, ++ IN BOOLEAN isActive); ++ ++VOID RTMPDescriptorEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType); ++ ++VOID RTMPFrameEndianChange( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG Dir, ++ IN BOOLEAN FromRxDoneInt); ++ ++// ap_assoc.c ++ ++VOID APAssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APPeerAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MbssKickOutStas( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN USHORT Reason); ++ ++VOID APMlmeKickOutSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pStaAddr, ++ IN UCHAR Wcid, ++ IN USHORT Reason); ++ ++VOID APMlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APCls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++ ++USHORT APBuildAssociation( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN USHORT CapabilityInfo, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN UCHAR *RSN, ++ IN UCHAR *pRSNLen, ++ IN BOOLEAN bWmmCapable, ++ IN ULONG RalinkIe, ++#ifdef DOT11N_DRAFT3 ++ IN EXT_CAP_INFO_ELEMENT ExtCapInfo, ++#endif // DOT11N_DRAFT3 // ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ OUT USHORT *pAid); ++ ++/* ++VOID RTMPAddClientSec( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic, ++ IN MAC_TABLE_ENTRY *pEntry); ++*/ ++ ++// ap_auth.c ++ ++void APAuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APMlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APCls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN PHEADER_802_11 pHeader); ++ ++// ap_authrsp.c ++ ++VOID APAuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]); ++ ++VOID APPeerAuthAtAuthRspIdleAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT StatusCode); ++ ++// ap_connect.c ++ ++BOOLEAN BeaconTransmitRequired( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APMakeBssBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APUpdateBeaconFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx); ++ ++VOID APMakeAllBssBeacon( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APUpdateAllBeaconFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++// ap_sync.c ++ ++VOID APSyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID APScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID APInvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerBeaconAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APMlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APPeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APScanCnclAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ApSiteSurvey( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID SupportRate( ++ IN PUCHAR SupRate, ++ IN UCHAR SupRateLen, ++ IN PUCHAR ExtRate, ++ IN UCHAR ExtRateLen, ++ OUT PUCHAR *Rates, ++ OUT PUCHAR RatesLen, ++ OUT PUCHAR pMaxSupportRate); ++ ++ ++BOOLEAN ApScanRunning( ++ IN PRTMP_ADAPTER pAd); ++ ++#ifdef DOT11N_DRAFT3 ++VOID APOverlappingBSSScan( ++ IN RTMP_ADAPTER *pAd); ++#endif // DOT11N_DRAFT3 // ++ ++// ap_wpa.c ++ ++VOID APWpaStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++// ap_mlme.c ++ ++VOID APMlmePeriodicExec( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APMlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx); ++ ++VOID APMlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate); ++ ++VOID APMlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN APMsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType); ++ ++VOID APQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++#ifdef RT2870 ++VOID BeaconUpdateExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // RT2870 // ++ ++VOID RTMPSetPiggyBack( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bPiggyBack); ++ ++VOID APAsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APAsicRxAntEvalTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++// ap.c ++ ++VOID APSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Channel); ++ ++NDIS_STATUS APInitialize( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APShutdown( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APStartUp( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID APCleanupPsQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_HEADER pQueue); ++ ++VOID MacTableReset( ++ IN PRTMP_ADAPTER pAd); ++ ++MAC_TABLE_ENTRY *MacTableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR apidx, ++ IN BOOLEAN CleanAll); ++ ++BOOLEAN MacTableDeleteEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr); ++ ++MAC_TABLE_ENTRY *MacTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID MacTableMaintenance( ++ IN PRTMP_ADAPTER pAd); ++ ++UINT32 MacTableAssocStaNumGet( ++ IN PRTMP_ADAPTER pAd); ++ ++MAC_TABLE_ENTRY *APSsPsInquiry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ OUT SST *Sst, ++ OUT USHORT *Aid, ++ OUT UCHAR *PsMode, ++ OUT UCHAR *Rate); ++ ++BOOLEAN APPsIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN ULONG Wcid, ++ IN UCHAR Psm); ++ ++VOID ApLogEvent( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN USHORT Event); ++ ++#ifdef DOT11_N_SUPPORT ++VOID APUpdateOperationMode( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++ ++VOID APUpdateCapabilityAndErpIe( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN ApCheckAccessControlList( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR Apidx); ++ ++VOID ApUpdateAccessControlList( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Apidx); ++ ++VOID ApEnqueueNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR TxRate, ++ IN UCHAR PID, ++ IN UCHAR apidx, ++ IN BOOLEAN bQosNull, ++ IN BOOLEAN bEOSP, ++ IN UCHAR OldUP); ++ ++VOID ApSendFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuffer, ++ IN ULONG Length, ++ IN UCHAR TxRate, ++ IN UCHAR PID); ++ ++VOID ApEnqueueAckFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR TxRate, ++ IN UCHAR apidx); ++ ++UCHAR APAutoSelectChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN Optimal); ++ ++// ap_sanity.c ++ ++ ++BOOLEAN PeerAssocReqCmmSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN isRessoc, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pListenInterval, ++ OUT PUCHAR pApAddr, ++ OUT UCHAR *pSsidLen, ++ OUT char *Ssid, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *RSN, ++ OUT UCHAR *pRSNLen, ++ OUT BOOLEAN *pbWmmCapable, ++ OUT ULONG *pRalinkIe, ++#ifdef DOT11N_DRAFT3 ++ OUT EXT_CAP_INFO_ELEMENT *pExtCapInfo, ++#endif // DOT11N_DRAFT3 // ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++ ++BOOLEAN PeerDisassocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerDeauthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN APPeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr1, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Alg, ++ OUT USHORT *Seq, ++ OUT USHORT *Status, ++ CHAR *ChlgText); ++ ++BOOLEAN APPeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *SsidLen); ++ ++BOOLEAN APPeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *SsidLen, ++ OUT UCHAR *BssType, ++ OUT USHORT *BeaconPeriod, ++ OUT UCHAR *Channel, ++ OUT LARGE_INTEGER *Timestamp, ++ OUT USHORT *CapabilityInfo, ++ OUT UCHAR Rate[], ++ OUT UCHAR *RateLen, ++ OUT BOOLEAN *ExtendedRateIeExist, ++ OUT UCHAR *Erp); ++ ++ ++// ================== end of AP RTMP.h ======================== ++ ++ ++#endif // __AP_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/chlist.h +@@ -0,0 +1,1253 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ chlist.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi Wu 2007-12-19 created ++*/ ++ ++#ifndef __CHLIST_H__ ++#define __CHLIST_H__ ++ ++#include "rtmp_type.h" ++#include "rtmp_def.h" ++ ++ ++#define ODOR 0 ++#define IDOR 1 ++#define BOTH 2 ++ ++#define BAND_5G 0 ++#define BAND_24G 1 ++#define BAND_BOTH 2 ++ ++typedef struct _CH_DESP { ++ UCHAR FirstChannel; ++ UCHAR NumOfCh; ++ CHAR MaxTxPwr; // dBm ++ UCHAR Geography; // 0:out door, 1:in door, 2:both ++ BOOLEAN DfsReq; // Dfs require, 0: No, 1: yes. ++} CH_DESP, *PCH_DESP; ++ ++typedef struct _CH_REGION { ++ UCHAR CountReg[3]; ++ UCHAR DfsType; // 0: CE, 1: FCC, 2: JAP, 3:JAP_W53, JAP_W56 ++ CH_DESP ChDesp[10]; ++} CH_REGION, *PCH_REGION; ++ ++static CH_REGION ChRegion[] = ++{ ++ { // Antigua and Berbuda ++ "AG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Argentina ++ "AR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Aruba ++ "AW", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Australia ++ "AU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Austria ++ "AT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bahamas ++ "BS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Barbados ++ "BB", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bermuda ++ "BM", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Brazil ++ "BR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 24, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Belgium ++ "BE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 18, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 18, IDOR, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Bulgaria ++ "BG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Canada ++ "CA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Cayman IsLands ++ "KY", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Chile ++ "CL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // China ++ "CN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Colombia ++ "CO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Costa Rica ++ "CR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Cyprus ++ "CY", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Czech_Republic ++ "CZ", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Denmark ++ "DK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Dominican Republic ++ "DO", ++ CE, ++ { ++ { 1, 0, 20, BOTH, FALSE}, // 2.4 G, ch 0 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Equador ++ "EC", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 100, 11, 27, BOTH, FALSE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // El Salvador ++ "SV", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 30, BOTH, TRUE}, // 5G, ch 52~64 ++ { 149, 4, 36, BOTH, TRUE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Finland ++ "FI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // France ++ "FR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Germany ++ "DE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Greece ++ "GR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Guam ++ "GU", ++ CE, ++ { ++ { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Guatemala ++ "GT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Haiti ++ "HT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Honduras ++ "HN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Hong Kong ++ "HK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Hungary ++ "HU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Iceland ++ "IS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // India ++ "IN", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 24, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Indonesia ++ "ID", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Ireland ++ "IE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Israel ++ "IL", ++ CE, ++ { ++ { 1, 3, 20, IDOR, FALSE}, // 2.4 G, ch 1~3 ++ { 4, 6, 20, BOTH, FALSE}, // 2.4 G, ch 4~9 ++ { 10, 4, 20, IDOR, FALSE}, // 2.4 G, ch 10~13 ++ { 0}, // end ++ } ++ }, ++ ++ { // Italy ++ "IT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, ODOR, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Japan ++ "JP", ++ JAP, ++ { ++ { 1, 14, 20, BOTH, FALSE}, // 2.4 G, ch 1~14 ++ { 34, 4, 23, IDOR, FALSE}, // 5G, ch 34~46 ++ { 0}, // end ++ } ++ }, ++ ++ { // Jordan ++ "JO", ++ CE, ++ { ++ { 1, 13, 20, IDOR, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 149, 4, 23, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Latvia ++ "LV", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Liechtenstein ++ "LI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Lithuania ++ "LT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Luxemburg ++ "LU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Malaysia ++ "MY", ++ CE, ++ { ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Malta ++ "MT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Marocco ++ "MA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 ++ { 0}, // end ++ } ++ }, ++ ++ { // Mexico ++ "MX", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 5, 30, IDOR, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Netherlands ++ "NL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // New Zealand ++ "NZ", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Norway ++ "NO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 24, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 24, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Peru ++ "PE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Portugal ++ "PT", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Poland ++ "PL", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Romania ++ "RO", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Russia ++ "RU", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 149, 4, 20, IDOR, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Saudi Arabia ++ "SA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 23, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Serbia_and_Montenegro ++ "CS", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 0}, // end ++ } ++ }, ++ ++ { // Singapore ++ "SG", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Slovakia ++ "SK", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Slovenia ++ "SI", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // South Africa ++ "ZA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 149, 4, 30, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // South Korea ++ "KR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 8, 20, BOTH, FALSE}, // 5G, ch 100~128 ++ { 149, 4, 20, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Spain ++ "ES", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 17, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Sweden ++ "SE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Switzerland ++ "CH", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~13 ++ { 36, 4, 23, IDOR, TRUE}, // 5G, ch 36~48 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Taiwan ++ "TW", ++ CE, ++ { ++ { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 52, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // Turkey ++ "TR", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 23, BOTH, FALSE}, // 5G, ch 36~48 ++ { 52, 4, 23, BOTH, FALSE}, // 5G, ch 52~64 ++ { 0}, // end ++ } ++ }, ++ ++ { // UK ++ "GB", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 23, IDOR, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 23, IDOR, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 0}, // end ++ } ++ }, ++ ++ { // Ukraine ++ "UA", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 0}, // end ++ } ++ }, ++ ++ { // United_Arab_Emirates ++ "AE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 0}, // end ++ } ++ }, ++ ++ { // United_States ++ "US", ++ CE, ++ { ++ { 1, 11, 30, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 17, IDOR, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 24, BOTH, TRUE}, // 5G, ch 52~64 ++ { 100, 11, 30, BOTH, TRUE}, // 5G, ch 100~140 ++ { 149, 5, 30, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++ ++ { // Venezuela ++ "VE", ++ CE, ++ { ++ { 1, 13, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 149, 4, 27, BOTH, FALSE}, // 5G, ch 149~161 ++ { 0}, // end ++ } ++ }, ++ ++ { // Default ++ "", ++ CE, ++ { ++ { 1, 11, 20, BOTH, FALSE}, // 2.4 G, ch 1~11 ++ { 36, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 52, 4, 20, BOTH, FALSE}, // 5G, ch 52~64 ++ { 100, 11, 20, BOTH, FALSE}, // 5G, ch 100~140 ++ { 149, 5, 20, BOTH, FALSE}, // 5G, ch 149~165 ++ { 0}, // end ++ } ++ }, ++}; ++ ++static inline PCH_REGION GetChRegion( ++ IN PUCHAR CntryCode) ++{ ++ INT loop = 0; ++ PCH_REGION pChRegion = NULL; ++ ++ while (strcmp(ChRegion[loop].CountReg, "") != 0) ++ { ++ if (strncmp(ChRegion[loop].CountReg, CntryCode, 2) == 0) ++ { ++ pChRegion = &ChRegion[loop]; ++ break; ++ } ++ loop++; ++ } ++ ++ if (pChRegion == NULL) ++ pChRegion = &ChRegion[loop]; ++ return pChRegion; ++} ++ ++static inline VOID ChBandCheck( ++ IN UCHAR PhyMode, ++ OUT PUCHAR pChType) ++{ ++ switch(PhyMode) ++ { ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ *pChType = BAND_5G; ++ break; ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AGN_MIXED: ++ case PHY_11ABGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ *pChType = BAND_BOTH; ++ break; ++ ++ default: ++ *pChType = BAND_24G; ++ break; ++ } ++} ++ ++static inline UCHAR FillChList( ++ IN PRTMP_ADAPTER pAd, ++ IN PCH_DESP pChDesp, ++ IN UCHAR Offset, ++ IN UCHAR increment) ++{ ++ INT i, j, l; ++ UCHAR channel; ++ ++ j = Offset; ++ for (i = 0; i < pChDesp->NumOfCh; i++) ++ { ++ channel = pChDesp->FirstChannel + i * increment; ++ for (l=0; lTxPower[l].Channel) ++ { ++ pAd->ChannelList[j].Power = pAd->TxPower[l].Power; ++ pAd->ChannelList[j].Power2 = pAd->TxPower[l].Power2; ++ break; ++ } ++ } ++ if (l == MAX_NUM_OF_CHANNELS) ++ continue; ++ ++ pAd->ChannelList[j].Channel = pChDesp->FirstChannel + i * increment; ++ pAd->ChannelList[j].MaxTxPwr = pChDesp->MaxTxPwr; ++ pAd->ChannelList[j].DfsReq = pChDesp->DfsReq; ++ j++; ++ } ++ pAd->ChannelListNum = j; ++ ++ return j; ++} ++ ++static inline VOID CreateChList( ++ IN PRTMP_ADAPTER pAd, ++ IN PCH_REGION pChRegion, ++ IN UCHAR Geography) ++{ ++ INT i; ++ UCHAR offset = 0; ++ PCH_DESP pChDesp; ++ UCHAR ChType; ++ UCHAR increment; ++ ++ if (pChRegion == NULL) ++ return; ++ ++ ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); ++ ++ for (i=0; i<10; i++) ++ { ++ pChDesp = &pChRegion->ChDesp[i]; ++ if (pChDesp->FirstChannel == 0) ++ break; ++ ++ if (ChType == BAND_5G) ++ { ++ if (pChDesp->FirstChannel <= 14) ++ continue; ++ } ++ else if (ChType == BAND_24G) ++ { ++ if (pChDesp->FirstChannel > 14) ++ continue; ++ } ++ ++ if ((pChDesp->Geography == BOTH) ++ || (pChDesp->Geography == Geography)) ++ { ++ if (pChDesp->FirstChannel > 14) ++ increment = 4; ++ else ++ increment = 1; ++ offset = FillChList(pAd, pChDesp, offset, increment); ++ } ++ } ++} ++ ++static inline VOID BuildChannelListEx( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PCH_REGION pChReg; ++ ++ pChReg = GetChRegion(pAd->CommonCfg.CountryCode); ++ CreateChList(pAd, pChReg, pAd->CommonCfg.Geography); ++} ++ ++static inline VOID BuildBeaconChList( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf, ++ OUT PULONG pBufLen) ++{ ++ INT i; ++ ULONG TmpLen; ++ PCH_REGION pChRegion; ++ PCH_DESP pChDesp; ++ UCHAR ChType; ++ ++ pChRegion = GetChRegion(pAd->CommonCfg.CountryCode); ++ ++ if (pChRegion == NULL) ++ return; ++ ++ ChBandCheck(pAd->CommonCfg.PhyMode, &ChType); ++ *pBufLen = 0; ++ ++ for (i=0; i<10; i++) ++ { ++ pChDesp = &pChRegion->ChDesp[i]; ++ if (pChDesp->FirstChannel == 0) ++ break; ++ ++ if (ChType == BAND_5G) ++ { ++ if (pChDesp->FirstChannel <= 14) ++ continue; ++ } ++ else if (ChType == BAND_24G) ++ { ++ if (pChDesp->FirstChannel > 14) ++ continue; ++ } ++ ++ if ((pChDesp->Geography == BOTH) ++ || (pChDesp->Geography == pAd->CommonCfg.Geography)) ++ { ++ MakeOutgoingFrame(pBuf + *pBufLen, &TmpLen, ++ 1, &pChDesp->FirstChannel, ++ 1, &pChDesp->NumOfCh, ++ 1, &pChDesp->MaxTxPwr, ++ END_OF_ARGS); ++ *pBufLen += TmpLen; ++ } ++ } ++} ++ ++ ++#ifdef DOT11_N_SUPPORT ++static inline BOOLEAN IsValidChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++ ++{ ++ INT i; ++ ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].Channel == channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++ ++static inline UCHAR GetExtCh( ++ IN UCHAR Channel, ++ IN UCHAR Direction) ++{ ++ CHAR ExtCh; ++ ++ if (Direction == EXTCHA_ABOVE) ++ ExtCh = Channel + 4; ++ else ++ ExtCh = (Channel - 4) > 0 ? (Channel - 4) : 0; ++ ++ return ExtCh; ++} ++ ++ ++static inline VOID N_ChannelCheck( ++ IN PRTMP_ADAPTER pAd) ++{ ++ //UCHAR ChannelNum = pAd->ChannelListNum; ++ UCHAR Channel = pAd->CommonCfg.Channel; ++ ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (Channel > 14) ++ { ++ if ((Channel == 36) || (Channel == 44) || (Channel == 52) || (Channel == 60) || (Channel == 100) || (Channel == 108) || ++ (Channel == 116) || (Channel == 124) || (Channel == 132) || (Channel == 149) || (Channel == 157)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ else if ((Channel == 40) || (Channel == 48) || (Channel == 56) || (Channel == 64) || (Channel == 104) || (Channel == 112) || ++ (Channel == 120) || (Channel == 128) || (Channel == 136) || (Channel == 153) || (Channel == 161)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } ++ } ++ else ++ { ++ do ++ { ++ UCHAR ExtCh; ++ UCHAR Dir = pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; ++ ExtCh = GetExtCh(Channel, Dir); ++ if (IsValidChannel(pAd, ExtCh)) ++ break; ++ ++ Dir = (Dir == EXTCHA_ABOVE) ? EXTCHA_BELOW : EXTCHA_ABOVE; ++ ExtCh = GetExtCh(Channel, Dir); ++ if (IsValidChannel(pAd, ExtCh)) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = Dir; ++ break; ++ } ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } while(FALSE); ++ ++ if (Channel == 14) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ //pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_NONE; // We didn't set the ExtCh as NONE due to it'll set in RTMPSetHT() ++ } ++ } ++ } ++ ++ ++} ++ ++ ++static inline VOID N_SetCenCh( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ if (pAd->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel == 14) ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 1; ++ else ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++ ++static inline UINT8 GetCuntryMaxTxPwr( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 channel) ++{ ++ int i; ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].Channel == channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return 0xff; ++ else ++ return pAd->ChannelList[i].MaxTxPwr; ++} ++#endif // __CHLIST_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/2870_rtmp_init.c +@@ -0,0 +1,1762 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ 2870_rtmp_init.c ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme ++ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. ++ Sample Lin 2007-05-31 Merge RT2860 and RT2870 drivers. ++*/ ++ ++#include "../rt_config.h" ++ ++ ++static void rx_done_tasklet(unsigned long data); ++static void rt2870_hcca_dma_done_tasklet(unsigned long data); ++static void rt2870_ac3_dma_done_tasklet(unsigned long data); ++static void rt2870_ac2_dma_done_tasklet(unsigned long data); ++static void rt2870_ac1_dma_done_tasklet(unsigned long data); ++static void rt2870_ac0_dma_done_tasklet(unsigned long data); ++static void rt2870_mgmt_dma_done_tasklet(unsigned long data); ++static void rt2870_null_frame_complete_tasklet(unsigned long data); ++static void rt2870_rts_frame_complete_tasklet(unsigned long data); ++static void rt2870_pspoll_frame_complete_tasklet(unsigned long data); ++static void rt2870_dataout_complete_tasklet(unsigned long data); ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Initialize receive data structures. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_RESOURCES ++ ++Note: ++ Initialize all receive releated private buffer, include those define ++ in RTMP_ADAPTER structure and all private data structures. The mahor ++ work is to allocate buffer for each packet and chain buffer to ++ NDIS packet descriptor. ++======================================================================== ++*/ ++NDIS_STATUS NICInitRecv( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitRecv\n")); ++ pObj = pObj; ++ ++ //InterlockedExchange(&pAd->PendingRx, 0); ++ pAd->PendingRx = 0; ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = 0 ; //RX_RING_SIZE -1; // Rx Bulk pointer ++ pAd->NextRxBulkInPosition = 0; ++ ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ //Allocate URB ++ pRxContext->pUrb = RTUSB_ALLOC_URB(0); ++ if (pRxContext->pUrb == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ goto out1; ++ } ++ ++ // Allocate transfer buffer ++ pRxContext->TransferBuffer = RTUSB_URB_ALLOC_BUFFER(pObj->pUsb_Dev, MAX_RXBULK_SIZE, &pRxContext->data_dma); ++ if (pRxContext->TransferBuffer == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ goto out1; ++ } ++ ++ NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); ++ ++ pRxContext->pAd = pAd; ++ pRxContext->pIrp = NULL; ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ //pRxContext->ReorderInUse = FALSE; ++ pRxContext->bRxHandling = FALSE; ++ pRxContext->BulkInOffset = 0; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitRecv\n")); ++ return Status; ++ ++out1: ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ if (NULL != pRxContext->TransferBuffer) ++ { ++ RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, MAX_RXBULK_SIZE, ++ pRxContext->TransferBuffer, pRxContext->data_dma); ++ pRxContext->TransferBuffer = NULL; ++ } ++ ++ if (NULL != pRxContext->pUrb) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ RTUSB_FREE_URB(pRxContext->pUrb); ++ pRxContext->pUrb = NULL; ++ } ++ } ++ ++ return Status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Initialize transmit data structures. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_RESOURCES ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS NICInitTransmit( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define LM_USB_ALLOC(pObj, Context, TB_Type, BufferSize, Status, msg1, err1, msg2, err2) \ ++ Context->pUrb = RTUSB_ALLOC_URB(0); \ ++ if (Context->pUrb == NULL) { \ ++ DBGPRINT(RT_DEBUG_ERROR, msg1); \ ++ Status = NDIS_STATUS_RESOURCES; \ ++ goto err1; } \ ++ \ ++ Context->TransferBuffer = \ ++ (TB_Type)RTUSB_URB_ALLOC_BUFFER(pObj->pUsb_Dev, BufferSize, &Context->data_dma); \ ++ if (Context->TransferBuffer == NULL) { \ ++ DBGPRINT(RT_DEBUG_ERROR, msg2); \ ++ Status = NDIS_STATUS_RESOURCES; \ ++ goto err2; } ++ ++#define LM_URB_FREE(pObj, Context, BufferSize) \ ++ if (NULL != Context->pUrb) { \ ++ RTUSB_UNLINK_URB(Context->pUrb); \ ++ RTUSB_FREE_URB(Context->pUrb); \ ++ Context->pUrb = NULL; } \ ++ if (NULL != Context->TransferBuffer) { \ ++ RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, BufferSize, \ ++ Context->TransferBuffer, \ ++ Context->data_dma); \ ++ Context->TransferBuffer = NULL; } ++ ++ UCHAR i, acidx; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++ PTX_CONTEXT pPsPollContext = &(pAd->PsPollContext); ++ PTX_CONTEXT pRTSContext = &(pAd->RTSContext); ++ PTX_CONTEXT pMLMEContext = NULL; ++// PHT_TX_CONTEXT pHTTXContext = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ PVOID RingBaseVa; ++// RTMP_TX_RING *pTxRing; ++ RTMP_MGMT_RING *pMgmtRing; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitTransmit\n")); ++ pObj = pObj; ++ ++ // Init 4 set of Tx parameters ++ for(acidx = 0; acidx < NUM_OF_TX_RING; acidx++) ++ { ++ // Initialize all Transmit releated queues ++ InitializeQueueHeader(&pAd->TxSwQueue[acidx]); ++ ++ // Next Local tx ring pointer waiting for buck out ++ pAd->NextBulkOutIndex[acidx] = acidx; ++ pAd->BulkOutPending[acidx] = FALSE; // Buck Out control flag ++ //pAd->DataBulkDoneIdx[acidx] = 0; ++ } ++ ++ //pAd->NextMLMEIndex = 0; ++ //pAd->PushMgmtIndex = 0; ++ //pAd->PopMgmtIndex = 0; ++ //InterlockedExchange(&pAd->MgmtQueueSize, 0); ++ //InterlockedExchange(&pAd->TxCount, 0); ++ ++ //pAd->PrioRingFirstIndex = 0; ++ //pAd->PrioRingTxCnt = 0; ++ ++ do ++ { ++ // ++ // TX_RING_SIZE, 4 ACs ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ for(acidx=0; acidx<4; acidx++) ++#endif // CONFIG_STA_SUPPORT // ++ { ++#if 1 //def DOT11_N_SUPPORT ++ PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); ++ ++ NdisZeroMemory(pHTTXContext, sizeof(HT_TX_CONTEXT)); ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pHTTXContext, PHTTX_BUFFER, sizeof(HTTX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX TxContext[%d] urb!! \n", acidx), ++ done, ++ ("<-- ERROR in Alloc TX TxContext[%d] HTTX_BUFFER !! \n", acidx), ++ out1); ++ ++ NdisZeroMemory(pHTTXContext->TransferBuffer->Aggregation, 4); ++ pHTTXContext->pAd = pAd; ++ pHTTXContext->pIrp = NULL; ++ pHTTXContext->IRPPending = FALSE; ++ pHTTXContext->NextBulkOutPosition = 0; ++ pHTTXContext->ENextBulkOutPosition = 0; ++ pHTTXContext->CurWritePosition = 0; ++ pHTTXContext->CurWriteRealPos = 0; ++ pHTTXContext->BulkOutSize = 0; ++ pHTTXContext->BulkOutPipeId = acidx; ++ pHTTXContext->bRingEmpty = TRUE; ++ pHTTXContext->bCopySavePad = FALSE; ++#endif // DOT11_N_SUPPORT // ++ pAd->BulkOutPending[acidx] = FALSE; ++ } ++ ++ ++ // ++ // MGMT_RING_SIZE ++ // ++ // Allocate MGMT ring descriptor's memory ++ pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * sizeof(TX_CONTEXT); ++ RTMPAllocateMemory(&pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); ++ if (pAd->MgmtDescRing.AllocVa == NULL) ++ { ++ DBGPRINT_ERR(("Failed to allocate a big buffer for MgmtDescRing!\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ goto out1; ++ } ++ NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize); ++ RingBaseVa = pAd->MgmtDescRing.AllocVa; ++ ++ // Initialize MGMT Ring and associated buffer memory ++ pMgmtRing = &pAd->MgmtRing; ++ for (i = 0; i < MGMT_RING_SIZE; i++) ++ { ++ // link the pre-allocated Mgmt buffer to MgmtRing.Cell ++ pMgmtRing->Cell[i].AllocSize = sizeof(TX_CONTEXT); ++ pMgmtRing->Cell[i].AllocVa = RingBaseVa; ++ pMgmtRing->Cell[i].pNdisPacket = NULL; ++ pMgmtRing->Cell[i].pNextNdisPacket = NULL; ++ ++ //Allocate URB for MLMEContext ++ pMLMEContext = (PTX_CONTEXT) pAd->MgmtRing.Cell[i].AllocVa; ++ pMLMEContext->pUrb = RTUSB_ALLOC_URB(0); ++ if (pMLMEContext->pUrb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("<-- ERROR in Alloc TX MLMEContext[%d] urb!! \n", i)); ++ Status = NDIS_STATUS_RESOURCES; ++ goto out2; ++ } ++ pMLMEContext->pAd = pAd; ++ pMLMEContext->pIrp = NULL; ++ pMLMEContext->TransferBuffer = NULL; ++ pMLMEContext->InUse = FALSE; ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ pMLMEContext->BulkOutSize = 0; ++ pMLMEContext->SelfIdx = i; ++ ++ // Offset to next ring descriptor address ++ RingBaseVa = (PUCHAR) RingBaseVa + sizeof(TX_CONTEXT); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", i)); ++ ++ //pAd->MgmtRing.TxSwFreeIdx = (MGMT_RING_SIZE - 1); ++ pAd->MgmtRing.TxSwFreeIdx = MGMT_RING_SIZE; ++ pAd->MgmtRing.TxCpuIdx = 0; ++ pAd->MgmtRing.TxDmaIdx = 0; ++ ++ // ++ // BEACON_RING_SIZE ++ // ++ for(i=0; iBeaconContext[i]); ++ ++ ++ NdisZeroMemory(pBeaconContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pBeaconContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX BeaconContext[%d] urb!! \n", i), ++ out2, ++ ("<-- ERROR in Alloc TX BeaconContext[%d] TX_BUFFER !! \n", i), ++ out3); ++ ++ pBeaconContext->pAd = pAd; ++ pBeaconContext->pIrp = NULL; ++ pBeaconContext->InUse = FALSE; ++ pBeaconContext->IRPPending = FALSE; ++ } ++ ++ // ++ // NullContext ++ // ++ NdisZeroMemory(pNullContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pNullContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX NullContext urb!! \n"), ++ out3, ++ ("<-- ERROR in Alloc TX NullContext TX_BUFFER !! \n"), ++ out4); ++ ++ pNullContext->pAd = pAd; ++ pNullContext->pIrp = NULL; ++ pNullContext->InUse = FALSE; ++ pNullContext->IRPPending = FALSE; ++ ++ // ++ // RTSContext ++ // ++ NdisZeroMemory(pRTSContext, sizeof(TX_CONTEXT)); ++ ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pRTSContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX RTSContext urb!! \n"), ++ out4, ++ ("<-- ERROR in Alloc TX RTSContext TX_BUFFER !! \n"), ++ out5); ++ ++ pRTSContext->pAd = pAd; ++ pRTSContext->pIrp = NULL; ++ pRTSContext->InUse = FALSE; ++ pRTSContext->IRPPending = FALSE; ++ ++ // ++ // PsPollContext ++ // ++ //NdisZeroMemory(pPsPollContext, sizeof(TX_CONTEXT)); ++ //Allocate URB ++ LM_USB_ALLOC(pObj, pPsPollContext, PTX_BUFFER, sizeof(TX_BUFFER), Status, ++ ("<-- ERROR in Alloc TX PsPollContext urb!! \n"), ++ out5, ++ ("<-- ERROR in Alloc TX PsPollContext TX_BUFFER !! \n"), ++ out6); ++ ++ pPsPollContext->pAd = pAd; ++ pPsPollContext->pIrp = NULL; ++ pPsPollContext->InUse = FALSE; ++ pPsPollContext->IRPPending = FALSE; ++ pPsPollContext->bAggregatible = FALSE; ++ pPsPollContext->LastOne = TRUE; ++ ++ } while (FALSE); ++ ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitTransmit\n")); ++ ++ return Status; ++ ++ /* --------------------------- ERROR HANDLE --------------------------- */ ++out6: ++ LM_URB_FREE(pObj, pPsPollContext, sizeof(TX_BUFFER)); ++ ++out5: ++ LM_URB_FREE(pObj, pRTSContext, sizeof(TX_BUFFER)); ++ ++out4: ++ LM_URB_FREE(pObj, pNullContext, sizeof(TX_BUFFER)); ++ ++out3: ++ for(i=0; iBeaconContext[i]); ++ if (pBeaconContext) ++ LM_URB_FREE(pObj, pBeaconContext, sizeof(TX_BUFFER)); ++ } ++ ++out2: ++ if (pAd->MgmtDescRing.AllocVa) ++ { ++ pMgmtRing = &pAd->MgmtRing; ++ for(i=0; iMgmtRing.Cell[i].AllocVa; ++ if (pMLMEContext) ++ LM_URB_FREE(pObj, pMLMEContext, sizeof(TX_BUFFER)); ++ } ++ NdisFreeMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize, 0); ++ pAd->MgmtDescRing.AllocVa = NULL; ++ } ++ ++out1: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ for(acidx=0; acidx<4; acidx++) ++#endif // CONFIG_STA_SUPPORT // ++ { ++ PHT_TX_CONTEXT pTxContext = &(pAd->TxContext[acidx]); ++ if (pTxContext) ++ LM_URB_FREE(pObj, pTxContext, sizeof(HTTX_BUFFER)); ++ } ++ ++ // Here we didn't have any pre-allocated memory need to free. ++ ++ return Status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Allocate DMA memory blocks for send, receive. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS RTMPAllocTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd) ++{ ++// COUNTER_802_11 pCounter = &pAd->WlanCounters; ++ NDIS_STATUS Status; ++ INT num; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n")); ++ ++ ++ do ++ { ++ // Init the CmdQ and CmdQLock ++ NdisAllocateSpinLock(&pAd->CmdQLock); ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ RTUSBInitializeCmdQ(&pAd->CmdQ); ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ ++ NdisAllocateSpinLock(&pAd->MLMEBulkOutLock); ++ //NdisAllocateSpinLock(&pAd->MLMEWaitQueueLock); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[0]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[1]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[2]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[3]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[4]); ++ NdisAllocateSpinLock(&pAd->BulkOutLock[5]); ++ NdisAllocateSpinLock(&pAd->BulkInLock); ++ ++ for (num = 0; num < NUM_OF_TX_RING; num++) ++ { ++ NdisAllocateSpinLock(&pAd->TxContextQueueLock[num]); ++ } ++ ++#ifdef RALINK_ATE ++ NdisAllocateSpinLock(&pAd->GenericLock); ++#endif // RALINK_ATE // ++ ++// NdisAllocateSpinLock(&pAd->MemLock); // Not used in RT28XX ++ ++// NdisAllocateSpinLock(&pAd->MacTabLock); // init it in UserCfgInit() ++// NdisAllocateSpinLock(&pAd->BATabLock); // init it in BATableInit() ++ ++// for(num=0; numBATable.BARecEntry[num].RxReRingLock); ++// } ++ ++ // ++ // Init Mac Table ++ // ++// MacTableInitialize(pAd); ++ ++ // ++ // Init send data structures and related parameters ++ // ++ Status = NICInitTransmit(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ // ++ // Init receive data structures and related parameters ++ // ++ Status = NICInitRecv(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ pAd->PendingIoCount = 1; ++ ++ } while (FALSE); ++ ++ NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME)); ++ pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); ++ ++ if (pAd->FragFrame.pFragPacket == NULL) ++ { ++ Status = NDIS_STATUS_RESOURCES; ++ } ++ ++ DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status)); ++ return Status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Calls USB_InterfaceStop and frees memory allocated for the URBs ++ calls NdisMDeregisterDevice and frees the memory ++ allocated in VNetInitialize for the Adapter Object ++ ++Arguments: ++ *pAd the raxx interface data pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++VOID RTMPFreeTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define LM_URB_FREE(pObj, Context, BufferSize) \ ++ if (NULL != Context->pUrb) { \ ++ RTUSB_UNLINK_URB(Context->pUrb); \ ++ RTUSB_FREE_URB(Context->pUrb); \ ++ Context->pUrb = NULL; } \ ++ if (NULL != Context->TransferBuffer) { \ ++ RTUSB_URB_FREE_BUFFER(pObj->pUsb_Dev, BufferSize, \ ++ Context->TransferBuffer, \ ++ Context->data_dma); \ ++ Context->TransferBuffer = NULL; } ++ ++ ++ UINT i, acidx; ++ PTX_CONTEXT pNullContext = &pAd->NullContext; ++ PTX_CONTEXT pPsPollContext = &pAd->PsPollContext; ++ PTX_CONTEXT pRTSContext = &pAd->RTSContext; ++// PHT_TX_CONTEXT pHTTXContext; ++ //PRTMP_REORDERBUF pReorderBuf; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++// RTMP_TX_RING *pTxRing; ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("---> RTMPFreeTxRxRingMemory\n")); ++ pObj = pObj; ++ ++ // Free all resources for the RECEIVE buffer queue. ++ for(i=0; i<(RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ if (pRxContext) ++ LM_URB_FREE(pObj, pRxContext, MAX_RXBULK_SIZE); ++ } ++ ++ // Free PsPoll frame resource ++ LM_URB_FREE(pObj, pPsPollContext, sizeof(TX_BUFFER)); ++ ++ // Free NULL frame resource ++ LM_URB_FREE(pObj, pNullContext, sizeof(TX_BUFFER)); ++ ++ // Free RTS frame resource ++ LM_URB_FREE(pObj, pRTSContext, sizeof(TX_BUFFER)); ++ ++ ++ // Free beacon frame resource ++ for(i=0; iBeaconContext[i]); ++ if (pBeaconContext) ++ LM_URB_FREE(pObj, pBeaconContext, sizeof(TX_BUFFER)); ++ } ++ ++ ++ // Free mgmt frame resource ++ for(i = 0; i < MGMT_RING_SIZE; i++) ++ { ++ PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[i].AllocVa; ++ //LM_URB_FREE(pObj, pMLMEContext, sizeof(TX_BUFFER)); ++ if (NULL != pAd->MgmtRing.Cell[i].pNdisPacket) ++ { ++ RTMPFreeNdisPacket(pAd, pAd->MgmtRing.Cell[i].pNdisPacket); ++ pAd->MgmtRing.Cell[i].pNdisPacket = NULL; ++ pMLMEContext->TransferBuffer = NULL; ++ } ++ ++ if (pMLMEContext) ++ { ++ if (NULL != pMLMEContext->pUrb) ++ { ++ RTUSB_UNLINK_URB(pMLMEContext->pUrb); ++ RTUSB_FREE_URB(pMLMEContext->pUrb); ++ pMLMEContext->pUrb = NULL; ++ } ++ } ++ } ++ if (pAd->MgmtDescRing.AllocVa) ++ NdisFreeMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize, 0); ++ ++ ++ // Free Tx frame resource ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ for(acidx=0; acidx<4; acidx++) ++#endif // CONFIG_STA_SUPPORT // ++ { ++ PHT_TX_CONTEXT pHTTXContext = &(pAd->TxContext[acidx]); ++ if (pHTTXContext) ++ LM_URB_FREE(pObj, pHTTXContext, sizeof(HTTX_BUFFER)); ++ } ++ ++ if (pAd->FragFrame.pFragPacket) ++ RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS); ++ ++ for(i=0; i<6; i++) ++ { ++ NdisFreeSpinLock(&pAd->BulkOutLock[i]); ++ } ++ ++ NdisFreeSpinLock(&pAd->BulkInLock); ++ NdisFreeSpinLock(&pAd->MLMEBulkOutLock); ++ ++ NdisFreeSpinLock(&pAd->CmdQLock); ++#ifdef RALINK_ATE ++ NdisFreeSpinLock(&pAd->GenericLock); ++#endif // RALINK_ATE // ++ // Clear all pending bulk-out request flags. ++ RTUSB_CLEAR_BULK_FLAG(pAd, 0xffffffff); ++ ++// NdisFreeSpinLock(&pAd->MacTabLock); ++ ++// for(i=0; iBATable.BARecEntry[i].RxReRingLock); ++// } ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("<--- ReleaseAdapter\n")); ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Allocate memory for adapter control block. ++ ++Arguments: ++ pAd Pointer to our adapter ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS AdapterBlockAllocateMemory( ++ IN PVOID handle, ++ OUT PVOID *ppAd) ++{ ++ PUSB_DEV usb_dev; ++ POS_COOKIE pObj = (POS_COOKIE) handle; ++ ++ ++ usb_dev = pObj->pUsb_Dev; ++ ++ pObj->MLMEThr_pid = NULL; ++ pObj->RTUSBCmdThr_pid = NULL; ++ ++ *ppAd = (PVOID)vmalloc(sizeof(RTMP_ADAPTER)); ++ ++ if (*ppAd) ++ { ++ NdisZeroMemory(*ppAd, sizeof(RTMP_ADAPTER)); ++ ((PRTMP_ADAPTER)*ppAd)->OS_Cookie = handle; ++ return (NDIS_STATUS_SUCCESS); ++ } ++ else ++ { ++ return (NDIS_STATUS_FAILURE); ++ } ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Create kernel threads & tasklets. ++ ++Arguments: ++ *net_dev Pointer to wireless net device interface ++ ++Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++Note: ++======================================================================== ++*/ ++NDIS_STATUS CreateThreads( ++ IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pid_t pid_number; ++ ++ //init_MUTEX(&(pAd->usbdev_semaphore)); ++ ++ init_MUTEX_LOCKED(&(pAd->mlme_semaphore)); ++ init_completion (&pAd->mlmeComplete); ++ ++ init_MUTEX_LOCKED(&(pAd->RTUSBCmd_semaphore)); ++ init_completion (&pAd->CmdQComplete); ++ ++ init_MUTEX_LOCKED(&(pAd->RTUSBTimer_semaphore)); ++ init_completion (&pAd->TimerQComplete); ++ ++ // Creat MLME Thread ++ pObj->MLMEThr_pid = NULL; ++ pid_number = kernel_thread(MlmeThread, pAd, CLONE_VM); ++ if (pid_number < 0) ++ { ++ printk (KERN_WARNING "%s: unable to start Mlme thread\n",pAd->net_dev->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ pObj->MLMEThr_pid = find_get_pid(pid_number); ++ // Wait for the thread to start ++ wait_for_completion(&(pAd->mlmeComplete)); ++ ++ // Creat Command Thread ++ pObj->RTUSBCmdThr_pid = NULL; ++ pid_number = kernel_thread(RTUSBCmdThread, pAd, CLONE_VM); ++ if (pid_number < 0) ++ { ++ printk (KERN_WARNING "%s: unable to start RTUSBCmd thread\n",pAd->net_dev->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ pObj->RTUSBCmdThr_pid = find_get_pid(pid_number); ++ wait_for_completion(&(pAd->CmdQComplete)); ++ ++ pObj->TimerQThr_pid = NULL; ++ pid_number = kernel_thread(TimerQThread, pAd, CLONE_VM); ++ if (pid_number < 0) ++ { ++ printk (KERN_WARNING "%s: unable to start TimerQThread\n",pAd->net_dev->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ pObj->TimerQThr_pid = find_get_pid(pid_number); ++ // Wait for the thread to start ++ wait_for_completion(&(pAd->TimerQComplete)); ++ ++ // Create receive tasklet ++ tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (ULONG)pAd); ++ tasklet_init(&pObj->mgmt_dma_done_task, rt2870_mgmt_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac0_dma_done_task, rt2870_ac0_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac1_dma_done_task, rt2870_ac1_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac2_dma_done_task, rt2870_ac2_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->ac3_dma_done_task, rt2870_ac3_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->hcca_dma_done_task, rt2870_hcca_dma_done_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->null_frame_complete_task, rt2870_null_frame_complete_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->rts_frame_complete_task, rt2870_rts_frame_complete_tasklet, (unsigned long)pAd); ++ tasklet_init(&pObj->pspoll_frame_complete_task, rt2870_pspoll_frame_complete_tasklet, (unsigned long)pAd); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++======================================================================== ++Routine Description: ++ As STA's BSSID is a WC too, it uses shared key table. ++ This function write correct unicast TX key to ASIC WCID. ++ And we still make a copy in our MacTab.Content[BSSID_WCID].PairwiseKey. ++ Caller guarantee TKIP/AES always has keyidx = 0. (pairwise key) ++ Caller guarantee WEP calls this function when set Txkey, default key index=0~3. ++ ++Arguments: ++ pAd Pointer to our adapter ++ pKey Pointer to the where the key stored ++ ++Return Value: ++ NDIS_SUCCESS Add key successfully ++ ++Note: ++======================================================================== ++*/ ++VOID RTMPAddBSSIDCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Aid, ++ IN PNDIS_802_11_KEY pKey, ++ IN UCHAR CipherAlg) ++{ ++ PUCHAR pTxMic, pRxMic; ++ BOOLEAN bKeyRSC, bAuthenticator; // indicate the receive SC set by KeyRSC value ++// UCHAR CipherAlg; ++ UCHAR i; ++ ULONG WCIDAttri; ++ USHORT offset; ++ UCHAR KeyIdx, IVEIV[8]; ++ UINT32 Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddBSSIDCipher==> Aid = %d\n",Aid)); ++ ++ // Bit 29 of Add-key KeyRSC ++ bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; ++ ++ // Bit 28 of Add-key Authenticator ++ bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; ++ KeyIdx = (UCHAR)pKey->KeyIndex&0xff; ++ ++ if (KeyIdx > 4) ++ return; ++ ++ ++ if (pAd->MacTab.Content[Aid].PairwiseKey.CipherAlg == CIPHER_TKIP) ++ { if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ // for WPA-None Tx, Rx MIC is the same ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pRxMic = pTxMic; ++ } ++ else if (bAuthenticator == TRUE) ++ { ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; ++ } ++ else ++ { ++ pRxMic = (PUCHAR) (&pKey->KeyMaterial) + 16; ++ pTxMic = (PUCHAR) (&pKey->KeyMaterial) + 24; ++ } ++ ++ offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE) + 0x10; ++ for (i=0; i<8; ) ++ { ++ Value = *(pTxMic+i); ++ Value += (*(pTxMic+i+1)<<8); ++ Value += (*(pTxMic+i+2)<<16); ++ Value += (*(pTxMic+i+3)<<24); ++ RTUSBWriteMACRegister(pAd, offset+i, Value); ++ i+=4; ++ } ++ ++ offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE) + 0x18; ++ for (i=0; i<8; ) ++ { ++ Value = *(pRxMic+i); ++ Value += (*(pRxMic+i+1)<<8); ++ Value += (*(pRxMic+i+2)<<16); ++ Value += (*(pRxMic+i+3)<<24); ++ RTUSBWriteMACRegister(pAd, offset+i, Value); ++ i+=4; ++ } ++ ++ // Only Key lenth equal to TKIP key have these ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxMic, pRxMic, 8); ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.TxMic, pTxMic, 8); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ (" TxMIC = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3], ++ pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ DBGPRINT(RT_DEBUG_TRACE, ++ (" RxMIC = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3], ++ pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ ++ // 2. Record Security Key. ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen= (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // 3. Check RxTsc. And used to init to ASIC IV. ++ if (bKeyRSC == TRUE) ++ NdisMoveMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxTsc, &pKey->KeyRSC, 6); ++ else ++ NdisZeroMemory(pAd->MacTab.Content[Aid].PairwiseKey.RxTsc, 6); ++ ++ // 4. Init TxTsc to one based on WiFi WPA specs ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[0] = 1; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[1] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[2] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[3] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[4] = 0; ++ pAd->MacTab.Content[Aid].PairwiseKey.TxTsc[5] = 0; ++ ++ CipherAlg = pAd->MacTab.Content[Aid].PairwiseKey.CipherAlg; ++ ++ offset = PAIRWISE_KEY_TABLE_BASE + (Aid * HW_KEY_ENTRY_SIZE); ++ RTUSBMultiWrite(pAd, (USHORT) offset, pKey->KeyMaterial, ++ ((pKey->KeyLength == LEN_TKIP_KEY) ? 16 : (USHORT)pKey->KeyLength)); ++ ++ offset = SHARED_KEY_TABLE_BASE + (KeyIdx * HW_KEY_ENTRY_SIZE); ++ RTUSBMultiWrite(pAd, (USHORT) offset, pKey->KeyMaterial, (USHORT)pKey->KeyLength); ++ ++ offset = PAIRWISE_IVEIV_TABLE_BASE + (Aid * HW_IVEIV_ENTRY_SIZE); ++ NdisZeroMemory(IVEIV, 8); ++ ++ // IV/EIV ++ if ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES)) ++ { ++ IVEIV[3] = 0x20; // Eiv bit on. keyid always 0 for pairwise key ++ } ++ // default key idx needs to set. ++ // in TKIP/AES KeyIdx = 0 , WEP KeyIdx is default tx key. ++ else ++ { ++ IVEIV[3] |= (KeyIdx<< 6); ++ } ++ RTUSBMultiWrite(pAd, (USHORT) offset, IVEIV, 8); ++ ++ // WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:1=PAIRWISE KEY, BSSIdx is 0 ++ if ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES)) ++ { ++ WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; ++ } ++ else ++ WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; ++ ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Aid* HW_WCID_ATTRI_SIZE); ++ RTUSBWriteMACRegister(pAd, offset, WCIDAttri); ++ RTUSBReadMACRegister(pAd, offset, &Value); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BSSID_WCID : offset = %x, WCIDAttri = %lx\n", ++ offset, WCIDAttri)); ++ ++ // pAddr ++ // Add Bssid mac address at linkup. not here. check! ++ /*offset = MAC_WCID_BASE + (BSSID_WCID * HW_WCID_ENTRY_SIZE); ++ *for (i=0; iBSSID[i]); ++ } ++ */ ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("AddBSSIDasWCIDEntry: Alg=%s, KeyLength = %d\n", ++ CipherName[CipherAlg], pKey->KeyLength)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Key [idx=%x] [KeyLen = %d]\n", ++ pKey->KeyIndex, pKey->KeyLength)); ++ for(i=0; iKeyLength; i++) ++ DBGPRINT_RAW(RT_DEBUG_TRACE,(" %x:", pKey->KeyMaterial[i])); ++ DBGPRINT(RT_DEBUG_TRACE,(" \n")); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++======================================================================== ++Routine Description: ++ Get a received packet. ++ ++Arguments: ++ pAd device control block ++ pSaveRxD receive descriptor information ++ *pbReschedule need reschedule flag ++ *pRxPending pending received packet flag ++ ++Return Value: ++ the recieved packet ++ ++Note: ++======================================================================== ++*/ ++#define RT2870_RXDMALEN_FIELD_SIZE 4 ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending) ++{ ++ PRX_CONTEXT pRxContext; ++ PNDIS_PACKET pSkb; ++ PUCHAR pData; ++ ULONG ThisFrameLen; ++ ULONG RxBufferLength; ++ PRXWI_STRUC pRxWI; ++ ++ pRxContext = &pAd->RxContext[pAd->NextRxBulkInReadIndex]; ++ if ((pRxContext->Readable == FALSE) || (pRxContext->InUse == TRUE)) ++ return NULL; ++ ++ RxBufferLength = pRxContext->BulkInOffset - pAd->ReadPosition; ++ if (RxBufferLength < (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXWI_STRUC) + sizeof(RXINFO_STRUC))) ++ { ++ goto label_null; ++ } ++ ++ pData = &pRxContext->TransferBuffer[pAd->ReadPosition]; /* 4KB */ ++ // The RXDMA field is 4 bytes, now just use the first 2 bytes. The Length including the (RXWI + MSDU + Padding) ++ ThisFrameLen = *pData + (*(pData+1)<<8); ++ if (ThisFrameLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("BIRIdx(%d): RXDMALen is zero.[%ld], BulkInBufLen = %ld)\n", ++ pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset)); ++ goto label_null; ++ } ++ if ((ThisFrameLen&0x3) != 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("BIRIdx(%d): RXDMALen not multiple of 4.[%ld], BulkInBufLen = %ld)\n", ++ pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset)); ++ goto label_null; ++ } ++ ++ if ((ThisFrameLen + 8)> RxBufferLength) // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BIRIdx(%d):FrameLen(0x%lx) outranges. BulkInLen=0x%lx, remaining RxBufLen=0x%lx, ReadPos=0x%lx\n", ++ pAd->NextRxBulkInReadIndex, ThisFrameLen, pRxContext->BulkInOffset, RxBufferLength, pAd->ReadPosition)); ++ ++ // error frame. finish this loop ++ goto label_null; ++ } ++ ++ // skip USB frame length field ++ pData += RT2870_RXDMALEN_FIELD_SIZE; ++ pRxWI = (PRXWI_STRUC)pData; ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(pData, TYPE_RXWI); ++#endif // RT_BIG_ENDIAN // ++ if (pRxWI->MPDUtotalByteCount > ThisFrameLen) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n", ++ __FUNCTION__, pRxWI->MPDUtotalByteCount, ThisFrameLen)); ++ goto label_null; ++ } ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange(pData, TYPE_RXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ // allocate a rx packet ++ pSkb = dev_alloc_skb(ThisFrameLen); ++ if (pSkb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", __FUNCTION__)); ++ goto label_null; ++ } ++ ++ // copy the rx packet ++ memcpy(skb_put(pSkb, ThisFrameLen), pData, ThisFrameLen); ++ RTPKT_TO_OSPKT(pSkb)->dev = get_netdev_from_bssid(pAd, BSS0); ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pSkb), PKTSRC_NDIS); ++ ++ // copy RxD ++ *pSaveRxD = *(PRXINFO_STRUC)(pData + ThisFrameLen); ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pSaveRxD, TYPE_RXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // update next packet read position. ++ pAd->ReadPosition += (ThisFrameLen + RT2870_RXDMALEN_FIELD_SIZE + RXINFO_SIZE); // 8 for (RT2870_RXDMALEN_FIELD_SIZE + sizeof(RXINFO_STRUC)) ++ ++ return pSkb; ++ ++label_null: ++ ++ return NULL; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Handle received packets. ++ ++Arguments: ++ data - URB information pointer ++ ++Return Value: ++ None ++ ++Note: ++======================================================================== ++*/ ++static void rx_done_tasklet(unsigned long data) ++{ ++ purbb_t pUrb; ++ PRX_CONTEXT pRxContext; ++ PRTMP_ADAPTER pAd; ++ NTSTATUS Status; ++ unsigned int IrqFlags; ++ ++ pUrb = (purbb_t)data; ++ pRxContext = (PRX_CONTEXT)pUrb->context; ++ pAd = pRxContext->pAd; ++ Status = pUrb->status; ++ ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->BulkInOffset += pUrb->actual_length; ++ //NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ pAd->BulkInComplete++; ++ pAd->NextRxBulkInPosition = 0; ++ if (pRxContext->BulkInOffset) // As jan's comment, it may bulk-in success but size is zero. ++ { ++ pRxContext->Readable = TRUE; ++ INC_RING_INDEX(pAd->NextRxBulkInIndex, RX_RING_SIZE); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ } ++ else // STATUS_OTHER ++ { ++ pAd->BulkInCompleteFail++; ++ // Still read this packet although it may comtain wrong bytes. ++ pRxContext->Readable = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Parsing all packets. because after reset, the index will reset to all zero. ++ if ((!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_BULKIN_RESET | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk In Failed. Status=%d, BIIdx=0x%x, BIRIdx=0x%x, actual_length= 0x%x\n", ++ Status, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pRxContext->pUrb->actual_length)); ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_IN, NULL, 0); ++ } ++ } ++ ++ ASSERT((pRxContext->InUse == pRxContext->IRPPending)); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ // If the driver is in ATE mode and Rx frame is set into here. ++ if (pAd->ContinBulkIn == TRUE) ++ { ++ RTUSBBulkReceive(pAd); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ RTUSBBulkReceive(pAd); ++ ++ return; ++ ++} ++ ++ ++static void rt2870_mgmt_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pMLMEContext; ++ int index; ++ PNDIS_PACKET pPacket; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ++ ++ pUrb = (purbb_t)data; ++ pMLMEContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pMLMEContext->pAd; ++ Status = pUrb->status; ++ index = pMLMEContext->SelfIdx; ++ ++ ASSERT((pAd->MgmtRing.TxDmaIdx == index)); ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ ++ if (Status != USB_ST_NOERROR) ++ { ++ //Bulk-Out fail status handle ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out MLME Failed, Status=%d!\n", Status)); ++ // TODO: How to handle about the MLMEBulkOut failed issue. Need to resend the mgmt pkt? ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ } ++ } ++ ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ // Reset MLME context flags ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->InUse = FALSE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ pMLMEContext->BulkOutSize = 0; ++ ++ pPacket = pAd->MgmtRing.Cell[index].pNdisPacket; ++ pAd->MgmtRing.Cell[index].pNdisPacket = NULL; ++ ++ // Increase MgmtRing Index ++ INC_RING_INDEX(pAd->MgmtRing.TxDmaIdx, MGMT_RING_SIZE); ++ pAd->MgmtRing.TxSwFreeIdx++; ++ RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ // No-matter success or fail, we free the mgmt packet. ++ if (pPacket) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET) && ++ ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG)) ++ { // For Mgmt Bulk-Out failed, ignore it now. ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ } ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++} ++ ++ ++static void rt2870_hcca_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 4; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<4); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++} ++ ++ ++static void rt2870_ac3_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 3; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<3); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++} ++ ++ ++static void rt2870_ac2_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 2; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<2); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ return; ++} ++ ++ ++static void rt2870_ac1_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 1; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /*((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL<<1); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++} ++ ++ ++static void rt2870_ac0_dma_done_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId = 0; ++ purbb_t pUrb; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ ++ rt2870_dataout_complete_tasklet((unsigned long)pUrb); ++ ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ // do nothing and return directly. ++ } ++ else ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) ++ { ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ if ((pAd->TxSwQueue[BulkOutPipeId].Number > 0) && ++ /* ((pHTTXContext->CurWritePosition > (pHTTXContext->NextBulkOutPosition + 0x6000)) || (pHTTXContext->NextBulkOutPosition > pHTTXContext->CurWritePosition + 0x6000)) && */ ++ (pAd->DeQueueRunning[BulkOutPipeId] == FALSE) && ++ (pHTTXContext->bCurWriting == FALSE)) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, BulkOutPipeId, MAX_TX_PROCESS); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL); ++ RTUSBKickBulkOut(pAd); ++ } ++ } ++ ++ ++ return; ++ ++} ++ ++ ++static void rt2870_null_frame_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pNullContext; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ unsigned long irqFlag; ++ ++ ++ pUrb = (purbb_t)data; ++ pNullContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pNullContext->pAd; ++ Status = pUrb->status; ++ ++ // Reset Null frame context flags ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); ++ pNullContext->IRPPending = FALSE; ++ pNullContext->InUse = FALSE; ++ pAd->BulkOutPending[0] = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out Null Frame Failed, ReasonCode=%d!\n", Status)); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ } ++ } ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++static void rt2870_rts_frame_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pRTSContext; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ unsigned long irqFlag; ++ ++ ++ pUrb = (purbb_t)data; ++ pRTSContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pRTSContext->pAd; ++ Status = pUrb->status; ++ ++ // Reset RTS frame context flags ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], irqFlag); ++ pRTSContext->IRPPending = FALSE; ++ pRTSContext->InUse = FALSE; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out RTS Frame Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], irqFlag); ++ } ++ } ++ ++ RTMP_SEM_LOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); ++ pAd->BulkOutPending[pRTSContext->BulkOutPipeId] = FALSE; ++ RTMP_SEM_UNLOCK(&pAd->BulkOutLock[pRTSContext->BulkOutPipeId]); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++static void rt2870_pspoll_frame_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pPsPollContext; ++ purbb_t pUrb; ++ NTSTATUS Status; ++ ++ ++ pUrb = (purbb_t)data; ++ pPsPollContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pPsPollContext->pAd; ++ Status = pUrb->status; ++ ++ // Reset PsPoll context flags ++ pPsPollContext->IRPPending = FALSE; ++ pPsPollContext->InUse = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ else // STATUS_OTHER ++ { ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Bulk Out PSPoll Failed\n")); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = (MGMTPIPEIDX | BULKOUT_MGMT_RESET_FLAG); ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ } ++ } ++ ++ RTMP_SEM_LOCK(&pAd->BulkOutLock[0]); ++ pAd->BulkOutPending[0] = FALSE; ++ RTMP_SEM_UNLOCK(&pAd->BulkOutLock[0]); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protectioon of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++static void rt2870_dataout_complete_tasklet(unsigned long data) ++{ ++ PRTMP_ADAPTER pAd; ++ purbb_t pUrb; ++ POS_COOKIE pObj; ++ PHT_TX_CONTEXT pHTTXContext; ++ UCHAR BulkOutPipeId; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ++ ++ pUrb = (purbb_t)data; ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ Status = pUrb->status; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pHTTXContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ //DBGPRINT(RT_DEBUG_LOUD, ("Done-B(%d):I=0x%lx, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", BulkOutPipeId, in_interrupt(), pHTTXContext->CurWritePosition, ++ // pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pHTTXContext->IRPPending = FALSE; ++ pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++ pAd->BulkOutComplete++; ++ ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ pAd->Counters8023.GoodTransmits++; ++ //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ FREE_HTTX_RING(pAd, BulkOutPipeId, pHTTXContext); ++ //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ ++ } ++ else // STATUS_OTHER ++ { ++ PUCHAR pBuf; ++ ++ pAd->BulkOutCompleteOther++; ++ ++ pBuf = &pHTTXContext->TransferBuffer->field.WirelessPacket[pHTTXContext->NextBulkOutPosition]; ++ ++ if (!RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST | ++ fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ pAd->bulkResetPipeid = BulkOutPipeId; ++ pAd->bulkResetReq[BulkOutPipeId] = pAd->BulkOutReq; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkOutDataPacket failed: ReasonCode=%d!\n", Status)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("\t>>BulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("\t>>BulkOut Header:%x %x %x %x %x %x %x %x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7])); ++ //DBGPRINT_RAW(RT_DEBUG_ERROR, (">>BulkOutCompleteCancel=0x%x, BulkOutCompleteOther=0x%x\n", pAd->BulkOutCompleteCancel, pAd->BulkOutCompleteOther)); ++ ++ } ++ ++ // ++ // bInUse = TRUE, means some process are filling TX data, after that must turn on bWaitingBulkOut ++ // bWaitingBulkOut = TRUE, means the TX data are waiting for bulk out. ++ // ++ //RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition) && ++ (pHTTXContext->ENextBulkOutPosition != (pHTTXContext->CurWritePosition+8)) && ++ !RTUSB_TEST_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId))) ++ { ++ // Indicate There is data avaliable ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ //RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protection of rest bulk should be in BulkOut routine ++ RTUSBKickBulkOut(pAd); ++} ++ ++/* End of 2870_rtmp_init.c */ +--- /dev/null ++++ b/drivers/staging/rt3070/common/action.c +@@ -0,0 +1,1038 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ action.c ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 2006 created for rt2860 ++ */ ++ ++#include "../rt_config.h" ++#include "../action.h" ++ ++ ++static VOID ReservedAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ Note: ++ The state machine looks like the following ++ ++ ASSOC_IDLE ++ MT2_MLME_DISASSOC_REQ mlme_disassoc_req_action ++ MT2_PEER_DISASSOC_REQ peer_disassoc_action ++ MT2_PEER_ASSOC_REQ drop ++ MT2_PEER_REASSOC_REQ drop ++ MT2_CLS3ERR cls3err_action ++ ========================================================================== ++ */ ++VOID ActionStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, (STATE_MACHINE_FUNC *)Trans, MAX_ACT_STATE, MAX_ACT_MSG, (STATE_MACHINE_FUNC)Drop, ACT_IDLE, ACT_MACHINE_BASE); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_SPECTRUM_CATE, (STATE_MACHINE_FUNC)PeerSpectrumAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_QOS_CATE, (STATE_MACHINE_FUNC)PeerQOSAction); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)ReservedAction); ++#ifdef QOS_DLS_SUPPORT ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_DLS_CATE, (STATE_MACHINE_FUNC)PeerDLSAction); ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_BA_CATE, (STATE_MACHINE_FUNC)PeerBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_HT_CATE, (STATE_MACHINE_FUNC)PeerHTAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ADD_BA_CATE, (STATE_MACHINE_FUNC)MlmeADDBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_ORI_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_REC_DELBA_CATE, (STATE_MACHINE_FUNC)MlmeDELBAAction); ++#endif // DOT11_N_SUPPORT // ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_PUBLIC_CATE, (STATE_MACHINE_FUNC)PeerPublicAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_PEER_RM_CATE, (STATE_MACHINE_FUNC)PeerRMAction); ++ ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_QOS_CATE, (STATE_MACHINE_FUNC)MlmeQOSAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_MLME_DLS_CATE, (STATE_MACHINE_FUNC)MlmeDLSAction); ++ StateMachineSetAction(S, ACT_IDLE, MT2_ACT_INVALID, (STATE_MACHINE_FUNC)MlmeInvalidAction); ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID MlmeADDBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ MLME_ADDBA_REQ_STRUCT *pInfo; ++ UCHAR Addr[6]; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG Idx; ++ FRAME_ADDBA_REQ Frame; ++ ULONG FrameLen; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ ++ pInfo = (MLME_ADDBA_REQ_STRUCT *)Elem->Msg; ++ NdisZeroMemory(&Frame, sizeof(FRAME_ADDBA_REQ)); ++ ++ if(MlmeAddBAReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++ // 1. find entry ++ Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; ++ if (Idx == 0) ++ { ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() can't find BAOriEntry \n")); ++ return; ++ } ++ else ++ { ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &Frame.Hdr, pInfo->pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pInfo->pAddr); ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ Frame.Category = CATEGORY_BA; ++ Frame.Action = ADDBA_REQ; ++ Frame.BaParm.AMSDUSupported = 0; ++ Frame.BaParm.BAPolicy = IMMED_BA; ++ Frame.BaParm.TID = pInfo->TID; ++ Frame.BaParm.BufSize = pInfo->BaBufSize; ++ Frame.Token = pInfo->Token; ++ Frame.TimeOutValue = pInfo->TimeOutValue; ++ Frame.BaStartSeq.field.FragNum = 0; ++ Frame.BaStartSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; ++ ++ *(USHORT *)(&Frame.BaParm) = cpu2le16(*(USHORT *)(&Frame.BaParm)); ++ Frame.TimeOutValue = cpu2le16(Frame.TimeOutValue); ++ Frame.BaStartSeq.word = cpu2le16(Frame.BaStartSeq.word); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ADDBA_REQ), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ //MiniportDataMMRequest(pAd, MapUserPriorityToAccessCategory[pInfo->TID], pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BA - Send ADDBA request. StartSeq = %x, FrameLen = %ld. BufSize = %d\n", Frame.BaStartSeq.field.StartSeq, FrameLen, Frame.BaParm.BufSize)); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ send DELBA and delete BaEntry if any ++ Parametrs: ++ Elem - MLME message MLME_DELBA_REQ_STRUCT ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDELBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DELBA_REQ_STRUCT *pInfo; ++ PUCHAR pOutBuffer = NULL; ++ PUCHAR pOutBuffer2 = NULL; ++ NDIS_STATUS NStatus; ++ ULONG Idx; ++ FRAME_DELBA_REQ Frame; ++ ULONG FrameLen; ++ FRAME_BAR FrameBar; ++ ++ pInfo = (MLME_DELBA_REQ_STRUCT *)Elem->Msg; ++ // must send back DELBA ++ NdisZeroMemory(&Frame, sizeof(FRAME_DELBA_REQ)); ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeDELBAAction(), Initiator(%d) \n", pInfo->Initiator)); ++ ++ if(MlmeDelBAReqSanity(pAd, Elem->Msg, Elem->MsgLen)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeDELBAAction() allocate memory failed 1. \n")); ++ return; ++ } ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR, ("BA - MlmeDELBAAction() allocate memory failed 2. \n")); ++ return; ++ } ++ ++ // SEND BAR (Send BAR to refresh peer reordering buffer.) ++ Idx = pAd->MacTab.Content[pInfo->Wcid].BAOriWcidArray[pInfo->TID]; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL funciton. ++ FrameBar.StartingSeq.field.StartSeq = pAd->MacTab.Content[pInfo->Wcid].TxSeq[pInfo->TID]; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = pInfo->TID; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.ACKPolicy = IMMED_BA; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.Compressed = 1; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.MTID = 0; // make sure sequence not clear in DEL funciton. ++ ++ MakeOutgoingFrame(pOutBuffer2, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer2); ++ DBGPRINT(RT_DEBUG_TRACE,("BA - MlmeDELBAAction() . Send BAR to refresh peer reordering buffer \n")); ++ ++ // SEND DELBA FRAME ++ FrameLen = 0; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[pInfo->Wcid].Addr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[pInfo->Wcid].Addr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ Frame.Category = CATEGORY_BA; ++ Frame.Action = DELBA; ++ Frame.DelbaParm.Initiator = pInfo->Initiator; ++ Frame.DelbaParm.TID = pInfo->TID; ++ Frame.ReasonCode = 39; // Time Out ++ *(USHORT *)(&Frame.DelbaParm) = cpu2le16(*(USHORT *)(&Frame.DelbaParm)); ++ Frame.ReasonCode = cpu2le16(Frame.ReasonCode); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_DELBA_REQ), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("BA - MlmeDELBAAction() . 3 DELBA sent. Initiator(%d)\n", pInfo->Initiator)); ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID MlmeQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++VOID MlmeDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++VOID MlmeInvalidAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ //PUCHAR pOutBuffer = NULL; ++ //Return the receiving frame except the MSB of category filed set to 1. 7.3.1.11 ++} ++ ++VOID PeerQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++#ifdef QOS_DLS_SUPPORT ++VOID PeerDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ switch(Action) ++ { ++ case ACTION_DLS_REQUEST: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsReqAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ ++ case ACTION_DLS_RESPONSE: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsRspAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ ++ case ACTION_DLS_TEARDOWN: ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ PeerDlsTearDownAction(pAd, Elem); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ } ++} ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ switch(Action) ++ { ++ case ADDBA_REQ: ++ PeerAddBAReqAction(pAd,Elem); ++ break; ++ case ADDBA_RESP: ++ PeerAddBARspAction(pAd,Elem); ++ break; ++ case DELBA: ++ PeerDelBAAction(pAd,Elem); ++ break; ++ } ++} ++ ++ ++#ifdef DOT11N_DRAFT3 ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID StaPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Bss2040Coexist) ++{ ++ BSS_2040_COEXIST_IE BssCoexist; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ BssCoexist.word = Bss2040Coexist; ++ // AP asks Station to return a 20/40 BSS Coexistence mgmt frame. So we first starts a scan, then send back 20/40 BSS Coexistence mgmt frame ++ if ((BssCoexist.field.InfoReq == 1) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040))) ++ { ++ // Clear record first. After scan , will update those bit and send back to transmiter. ++ pAd->CommonCfg.BSSCoexist2040.field.InfoReq = 1; ++ pAd->CommonCfg.BSSCoexist2040.field.Intolerant40 = 0; ++ pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 0; ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_2040_BSS_COEXIST); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ } ++} ++ ++ ++/* ++Description : Build Intolerant Channel Rerpot from Trigger event table. ++return : how many bytes copied. ++*/ ++ULONG BuildIntolerantChannelRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest) ++{ ++ ULONG FrameLen = 0; ++ ULONG ReadOffset = 0; ++ UCHAR i; ++ UCHAR LastRegClass = 0xff; ++ PUCHAR pLen; ++ ++ for ( i = 0;i < MAX_TRIGGER_EVENT;i++) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid == TRUE) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass == LastRegClass) ++ { ++ *(pDest + ReadOffset) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; ++ *pLen++; ++ ReadOffset++; ++ FrameLen++; ++ } ++ else ++ { ++ *(pDest + ReadOffset) = IE_2040_BSS_INTOLERANT_REPORT; // IE ++ *(pDest + ReadOffset + 1) = 2; // Len = RegClass byte + channel byte. ++ pLen = pDest + ReadOffset + 1; ++ LastRegClass = pAd->CommonCfg.TriggerEventTab.EventA[i].RegClass; ++ *(pDest + ReadOffset + 2) = LastRegClass; // Len = RegClass byte + channel byte. ++ *(pDest + ReadOffset + 3) = (UCHAR)pAd->CommonCfg.TriggerEventTab.EventA[i].Channel; ++ FrameLen += 4; ++ ReadOffset += 4; ++ } ++ ++ } ++ } ++ return FrameLen; ++} ++ ++ ++/* ++Description : Send 20/40 BSS Coexistence Action frame If one trigger event is triggered. ++*/ ++VOID Send2040CoexistAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ FRAME_ACTION_HDR Frame; ++ ULONG FrameLen; ++ ULONG IntolerantChaRepLen; ++ ++ IntolerantChaRepLen = 0; ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction() allocate memory failed \n")); ++ return; ++ } ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->MacTab.Content[Wcid].Addr, pAd->CommonCfg.Bssid); ++ Frame.Category = CATEGORY_PUBLIC; ++ Frame.Action = ACTION_BSS_2040_COEXIST; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ACTION_HDR), &Frame, ++ END_OF_ARGS); ++ ++ *(pOutBuffer + FrameLen) = pAd->CommonCfg.BSSCoexist2040.word; ++ FrameLen++; ++ ++ if (bAddIntolerantCha == TRUE) ++ IntolerantChaRepLen = BuildIntolerantChannelRep(pAd, pOutBuffer + FrameLen); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen + IntolerantChaRepLen); ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - Send2040CoexistAction( BSSCoexist2040 = 0x%x ) \n", pAd->CommonCfg.BSSCoexist2040.word)); ++ ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ After scan, Update 20/40 BSS Coexistence IE and send out. ++ According to 802.11n D3.03 11.14.10 ++ ++ Parameters: ++ ========================================================================== ++ */ ++VOID Update2040CoexistFrameAndNotify( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha) ++{ ++ BSS_2040_COEXIST_IE OldValue; ++ ++ OldValue.word = pAd->CommonCfg.BSSCoexist2040.word; ++ if ((pAd->CommonCfg.TriggerEventTab.EventANo > 0) || (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0)) ++ pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq = 1; ++ ++ // Need to check !!!! ++ // How STA will set Intolerant40 if implementation dependent. Now we don't set this bit first.!!!!! ++ // So Only check BSS20WidthReq change. ++ if (OldValue.field.BSS20WidthReq != pAd->CommonCfg.BSSCoexist2040.field.BSS20WidthReq) ++ { ++ Send2040CoexistAction(pAd, Wcid, bAddIntolerantCha); ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++BOOLEAN ChannelSwitchSanityCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary) ++{ ++ UCHAR i; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ if ((NewChannel > 7) && (Secondary == 1)) ++ return FALSE; ++ ++ if ((NewChannel < 5) && (Secondary == 3)) ++ return FALSE; ++ ++ // 0. Check if new channel is in the channellist. ++ for (i = 0;i < pAd->ChannelListNum;i++) ++ { ++ if (pAd->ChannelList[i].Channel == NewChannel) ++ { ++ break; ++ } ++ } ++ ++ if (i == pAd->ChannelListNum) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++VOID ChannelSwitchAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary) ++{ ++ UCHAR BBPValue = 0; ++ ULONG MACValue; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SPECTRUM - ChannelSwitchAction(NewChannel = %d , Secondary = %d) \n", NewChannel, Secondary)); ++ ++ if (ChannelSwitchSanityCheck(pAd, Wcid, NewChannel, Secondary) == FALSE) ++ return; ++ ++ // 1. Switches to BW = 20. ++ if (Secondary == 0) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ pAd->CommonCfg.Channel = NewChannel; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel,FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz !!! \n" )); ++ } ++ // 1. Switches to BW = 40 And Station supports BW = 40. ++ else if (((Secondary == 1) || (Secondary == 3)) && (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == 1)) ++ { ++ pAd->CommonCfg.Channel = NewChannel; ++ ++ if (Secondary == 1) ++ { ++ // Secondary above. ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); ++ MACValue &= 0xfe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); ++ BBPValue&= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++ { ++ // Secondary below. ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &MACValue); ++ MACValue &= 0xfe; ++ MACValue |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, MACValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPValue); ++ BBPValue&= (~0x20); ++ BBPValue|= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ pAd->MacTab.Content[Wcid].HTPhyMode.field.BW = 1; ++ } ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++VOID PeerPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++#ifdef DOT11N_DRAFT3 ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++#endif // DOT11N_DRAFT3 // ++ ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++#ifdef DOT11N_DRAFT3 ++ switch(Action) ++ { ++ case ACTION_BSS_2040_COEXIST: // Format defined in IEEE 7.4.7a.1 in 11n Draf3.03 ++ { ++ //UCHAR BssCoexist; ++ BSS_2040_COEXIST_ELEMENT *pCoexistInfo; ++ BSS_2040_COEXIST_IE *pBssCoexistIe; ++ BSS_2040_INTOLERANT_CH_REPORT *pIntolerantReport = NULL; ++ ++ if (Elem->MsgLen <= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT)) ) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ACTION - 20/40 BSS Coexistence Management Frame length too short! len = %ld!\n", Elem->MsgLen)); ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("ACTION - 20/40 BSS Coexistence Management action----> \n")); ++ hex_dump("CoexistenceMgmtFrame", Elem->Msg, Elem->MsgLen); ++ ++ ++ pCoexistInfo = (BSS_2040_COEXIST_ELEMENT *) &Elem->Msg[LENGTH_802_11+2]; ++ //hex_dump("CoexistInfo", (PUCHAR)pCoexistInfo, sizeof(BSS_2040_COEXIST_ELEMENT)); ++ if (Elem->MsgLen >= (LENGTH_802_11 + sizeof(BSS_2040_COEXIST_ELEMENT) + sizeof(BSS_2040_INTOLERANT_CH_REPORT))) ++ { ++ pIntolerantReport = (BSS_2040_INTOLERANT_CH_REPORT *)((PUCHAR)pCoexistInfo + sizeof(BSS_2040_COEXIST_ELEMENT)); ++ } ++ //hex_dump("IntolerantReport ", (PUCHAR)pIntolerantReport, sizeof(BSS_2040_INTOLERANT_CH_REPORT)); ++ ++ pBssCoexistIe = (BSS_2040_COEXIST_IE *)(&pCoexistInfo->BssCoexistIe); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ StaPublicAction(pAd, pCoexistInfo); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++ break; ++ } ++ ++#endif // DOT11N_DRAFT3 // ++ ++} ++ ++ ++static VOID ReservedAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Category; ++ ++ if (Elem->MsgLen <= LENGTH_802_11) ++ { ++ return; ++ } ++ ++ Category = Elem->Msg[LENGTH_802_11]; ++ DBGPRINT(RT_DEBUG_TRACE,("Rcv reserved category(%d) Action Frame\n", Category)); ++ hex_dump("Reserved Action Frame", &Elem->Msg[0], Elem->MsgLen); ++} ++ ++VOID PeerRMAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ return; ++} ++ ++#ifdef DOT11_N_SUPPORT ++static VOID respond_ht_information_exchange_action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ FRAME_HT_INFO HTINFOframe, *pFrame; ++ UCHAR *pAddr; ++ ++ ++ // 2. Always send back ADDBA Response ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - respond_ht_information_exchange_action() allocate memory failed \n")); ++ return; ++ } ++ ++ // get RA ++ pFrame = (FRAME_HT_INFO *) &Elem->Msg[0]; ++ pAddr = pFrame->Hdr.Addr2; ++ ++ NdisZeroMemory(&HTINFOframe, sizeof(FRAME_HT_INFO)); ++ // 2-1. Prepare ADDBA Response frame. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &HTINFOframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++ ActHeaderInit(pAd, &HTINFOframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ HTINFOframe.Category = CATEGORY_HT; ++ HTINFOframe.Action = HT_INFO_EXCHANGE; ++ HTINFOframe.HT_Info.Request = 0; ++ HTINFOframe.HT_Info.Forty_MHz_Intolerant = pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant; ++ HTINFOframe.HT_Info.STA_Channel_Width = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_HT_INFO), &HTINFOframe, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID SendNotifyBWActionFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ FRAME_ACTION_HDR Frame; ++ ULONG FrameLen; ++ PUCHAR pAddr1; ++ ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ACT - SendNotifyBWAction() allocate memory failed \n")); ++ return; ++ } ++ ++ if (Wcid == MCAST_WCID) ++ pAddr1 = &BROADCAST_ADDR[0]; ++ else ++ pAddr1 = pAd->MacTab.Content[Wcid].Addr; ++ ActHeaderInit(pAd, &Frame.Hdr, pAddr1, pAd->ApCfg.MBSSID[apidx].Bssid, pAd->ApCfg.MBSSID[apidx].Bssid); ++ ++ Frame.Category = CATEGORY_HT; ++ Frame.Action = NOTIFY_BW_ACTION; ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ACTION_HDR), &Frame, ++ END_OF_ARGS); ++ ++ *(pOutBuffer + FrameLen) = pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth; ++ FrameLen++; ++ ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ DBGPRINT(RT_DEBUG_TRACE,("ACT - SendNotifyBWAction(NotifyBW= %d)!\n", pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth)); ++ ++} ++#endif // DOT11N_DRAFT3 // ++ ++ ++VOID PeerHTAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ switch(Action) ++ { ++ case NOTIFY_BW_ACTION: ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Notify Channel bandwidth action----> \n")); ++#ifdef CONFIG_STA_SUPPORT ++ if(pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ { ++ // Note, this is to patch DIR-1353 AP. When the AP set to Wep, it will use legacy mode. But AP still keeps ++ // sending BW_Notify Action frame, and cause us to linkup and linkdown. ++ // In legacy mode, don't need to parse HT action frame. ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION -Ignore HT Notify Channel BW when link as legacy mode. BW = %d---> \n", ++ Elem->Msg[LENGTH_802_11+2] )); ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (Elem->Msg[LENGTH_802_11+2] == 0) // 7.4.8.2. if value is 1, keep the same as supported channel bandwidth. ++ pAd->MacTab.Content[Elem->Wcid].HTPhyMode.field.BW = 0; ++ ++ break; ++ ++ case SMPS_ACTION: ++ // 7.3.1.25 ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - SMPS action----> \n")); ++ if (((Elem->Msg[LENGTH_802_11+2]&0x1) == 0)) ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_ENABLE; ++ } ++ else if (((Elem->Msg[LENGTH_802_11+2]&0x2) == 0)) ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_STATIC; ++ } ++ else ++ { ++ pAd->MacTab.Content[Elem->Wcid].MmpsMode = MMPS_DYNAMIC; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Aid(%d) MIMO PS = %d\n", Elem->Wcid, pAd->MacTab.Content[Elem->Wcid].MmpsMode)); ++ // rt2860c : add something for smps change. ++ break; ++ ++ case SETPCO_ACTION: ++ break; ++ ++ case MIMO_CHA_MEASURE_ACTION: ++ break; ++ ++ case HT_INFO_EXCHANGE: ++ { ++ HT_INFORMATION_OCTET *pHT_info; ++ ++ pHT_info = (HT_INFORMATION_OCTET *) &Elem->Msg[LENGTH_802_11+2]; ++ // 7.4.8.10 ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - HT Information Exchange action----> \n")); ++ if (pHT_info->Request) ++ { ++ respond_ht_information_exchange_action(pAd, Elem); ++ } ++ } ++ break; ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Retry sending ADDBA Reqest. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Parametrs: ++ p8023Header: if this is already 802.3 format, p8023Header is NULL ++ ++ Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. ++ FALSE , then continue indicaterx at this moment. ++ ========================================================================== ++ */ ++VOID ORIBATimerTimeout( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MAC_TABLE_ENTRY *pEntry; ++ INT i, total; ++// FRAME_BAR FrameBar; ++// ULONG FrameLen; ++// NDIS_STATUS NStatus; ++// PUCHAR pOutBuffer = NULL; ++// USHORT Sequence; ++ UCHAR TID; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ total = pAd->MacTab.Size * NUM_OF_TID; ++ ++ for (i = 1; ((i 0)) ; i++) ++ { ++ if (pAd->BATable.BAOriEntry[i].ORI_BA_Status == Originator_Done) ++ { ++ pEntry = &pAd->MacTab.Content[pAd->BATable.BAOriEntry[i].Wcid]; ++ TID = pAd->BATable.BAOriEntry[i].TID; ++ ++ ASSERT(pAd->BATable.BAOriEntry[i].Wcid < MAX_LEN_OF_MAC_TABLE); ++ } ++ total --; ++ } ++} ++ ++ ++VOID SendRefreshBAR( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ FRAME_BAR FrameBar; ++ ULONG FrameLen; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ USHORT Sequence; ++ UCHAR i, TID; ++ USHORT idx; ++ BA_ORI_ENTRY *pBAEntry; ++ ++ for (i = 0; i BAOriWcidArray[i]; ++ if (idx == 0) ++ { ++ continue; ++ } ++ pBAEntry = &pAd->BATable.BAOriEntry[idx]; ++ ++ if (pBAEntry->ORI_BA_Status == Originator_Done) ++ { ++ TID = pBAEntry->TID; ++ ++ ASSERT(pBAEntry->Wcid < MAX_LEN_OF_MAC_TABLE); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++ ++ Sequence = pEntry->TxSeq[TID]; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pEntry->Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. ++ FrameBar.StartingSeq.field.StartSeq = Sequence; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = TID; // make sure sequence not clear in DEL funciton. ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ //if (!(CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_RALINK_CHIPSET))) ++ if (1) // Now we always send BAR. ++ { ++ //MiniportMMRequestUnlock(pAd, 0, pOutBuffer, FrameLen); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ //MiniportDataMMRequest(pAd, MapUserPriorityToAccessCategory[TID], pOutBuffer, FrameLen); ++ } ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID ActHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN PUCHAR Addr1, ++ IN PUCHAR Addr2, ++ IN PUCHAR Addr3) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SUBTYPE_ACTION; ++ ++ COPY_MAC_ADDR(pHdr80211->Addr1, Addr1); ++ COPY_MAC_ADDR(pHdr80211->Addr2, Addr2); ++ COPY_MAC_ADDR(pHdr80211->Addr3, Addr3); ++} ++ ++VOID BarHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PFRAME_BAR pCntlBar, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA) ++{ ++// USHORT Duration; ++ ++ NdisZeroMemory(pCntlBar, sizeof(FRAME_BAR)); ++ pCntlBar->FC.Type = BTYPE_CNTL; ++ pCntlBar->FC.SubType = SUBTYPE_BLOCK_ACK_REQ; ++ pCntlBar->BarControl.MTID = 0; ++ pCntlBar->BarControl.Compressed = 1; ++ pCntlBar->BarControl.ACKPolicy = 0; ++ ++ ++ pCntlBar->Duration = 16 + RTMPCalcDuration(pAd, RATE_1, sizeof(FRAME_BA)); ++ ++ COPY_MAC_ADDR(pCntlBar->Addr1, pDA); ++ COPY_MAC_ADDR(pCntlBar->Addr2, pSA); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Category and action code into the action frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. category code of the frame. ++ 4. action code of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID InsertActField( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 Category, ++ IN UINT8 ActCode) ++{ ++ ULONG TempLen; ++ ++ MakeOutgoingFrame( pFrameBuf, &TempLen, ++ 1, &Category, ++ 1, &ActCode, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} +--- /dev/null ++++ b/drivers/staging/rt3070/common/ba_action.c +@@ -0,0 +1,1810 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++ ++#ifdef DOT11_N_SUPPORT ++ ++#include "../rt_config.h" ++ ++ ++ ++#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) //1 // inital sequence number of BA session ++ ++#define ORI_SESSION_MAX_RETRY 8 ++#define ORI_BA_SESSION_TIMEOUT (2000) // ms ++#define REC_BA_SESSION_IDLE_TIMEOUT (1000) // ms ++ ++#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms ++#define MAX_REORDERING_PACKET_TIMEOUT ((3000 * HZ)/1000) // system ticks -- 100 ms ++ ++#define RESET_RCV_SEQ (0xFFFF) ++ ++static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk); ++ ++ ++BA_ORI_ENTRY *BATableAllocOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx); ++ ++BA_REC_ENTRY *BATableAllocRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx); ++ ++VOID BAOriSessionSetupTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID BARecSessionIdleTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++BUILD_TIMER_FUNCTION(BAOriSessionSetupTimeout); ++BUILD_TIMER_FUNCTION(BARecSessionIdleTimeout); ++ ++#define ANNOUNCE_REORDERING_PACKET(_pAd, _mpdu_blk) \ ++ Announce_Reordering_Packet(_pAd, _mpdu_blk); ++ ++VOID BA_MaxWinSizeReasign( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntryPeer, ++ OUT UCHAR *pWinSize) ++{ ++ UCHAR MaxSize; ++ ++ ++ if (pAd->MACVersion >= RALINK_2883_VERSION) // 3*3 ++ { ++ if (pAd->MACVersion >= RALINK_3070_VERSION) ++ { ++ if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) ++ MaxSize = 7; // for non-open mode ++ else ++ MaxSize = 13; ++ } ++ else ++ MaxSize = 31; ++ } ++ else if (pAd->MACVersion >= RALINK_2880E_VERSION) // 2880 e ++ { ++ if (pEntryPeer->WepStatus != Ndis802_11EncryptionDisabled) ++ MaxSize = 7; // for non-open mode ++ else ++ MaxSize = 13; ++ } ++ else ++ MaxSize = 7; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ba> Win Size = %d, Max Size = %d\n", ++ *pWinSize, MaxSize)); ++ ++ if ((*pWinSize) > MaxSize) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ba> reassign max win size from %d to %d\n", ++ *pWinSize, MaxSize)); ++ ++ *pWinSize = MaxSize; ++ } ++} ++ ++void Announce_Reordering_Packet(IN PRTMP_ADAPTER pAd, ++ IN struct reordering_mpdu *mpdu) ++{ ++ PNDIS_PACKET pPacket; ++ ++ pPacket = mpdu->pPacket; ++ ++ if (mpdu->bAMSDU) ++ { ++ ASSERT(0); ++ BA_Reorder_AMSDU_Annnounce(pAd, pPacket); ++ } ++ else ++ { ++ // ++ // pass this 802.3 packet to upper layer or forward this packet to WM directly ++ // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket, RTMP_GET_PACKET_IF(pPacket)); ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++/* ++ * Insert a reordering mpdu into sorted linked list by sequence no. ++ */ ++BOOLEAN ba_reordering_mpdu_insertsorted(struct reordering_list *list, struct reordering_mpdu *mpdu) ++{ ++ ++ struct reordering_mpdu **ppScan = &list->next; ++ ++ while (*ppScan != NULL) ++ { ++ if (SEQ_SMALLER((*ppScan)->Sequence, mpdu->Sequence, MAXSEQ)) ++ { ++ ppScan = &(*ppScan)->next; ++ } ++ else if ((*ppScan)->Sequence == mpdu->Sequence) ++ { ++ /* give up this duplicated frame */ ++ return(FALSE); ++ } ++ else ++ { ++ /* find position */ ++ break; ++ } ++ } ++ ++ mpdu->next = *ppScan; ++ *ppScan = mpdu; ++ list->qlen++; ++ return TRUE; ++} ++ ++ ++/* ++ * caller lock critical section if necessary ++ */ ++static inline void ba_enqueue(struct reordering_list *list, struct reordering_mpdu *mpdu_blk) ++{ ++ list->qlen++; ++ mpdu_blk->next = list->next; ++ list->next = mpdu_blk; ++} ++ ++/* ++ * caller lock critical section if necessary ++ */ ++static inline struct reordering_mpdu * ba_dequeue(struct reordering_list *list) ++{ ++ struct reordering_mpdu *mpdu_blk = NULL; ++ ++ ASSERT(list); ++ ++ if (list->qlen) ++ { ++ list->qlen--; ++ mpdu_blk = list->next; ++ if (mpdu_blk) ++ { ++ list->next = mpdu_blk->next; ++ mpdu_blk->next = NULL; ++ } ++ } ++ return mpdu_blk; ++} ++ ++ ++static inline struct reordering_mpdu *ba_reordering_mpdu_dequeue(struct reordering_list *list) ++{ ++ return(ba_dequeue(list)); ++} ++ ++ ++static inline struct reordering_mpdu *ba_reordering_mpdu_probe(struct reordering_list *list) ++ { ++ ASSERT(list); ++ ++ return(list->next); ++ } ++ ++ ++/* ++ * free all resource for reordering mechanism ++ */ ++void ba_reordering_resource_release(PRTMP_ADAPTER pAd) ++{ ++ BA_TABLE *Tab; ++ PBA_REC_ENTRY pBAEntry; ++ struct reordering_mpdu *mpdu_blk; ++ int i; ++ ++ Tab = &pAd->BATable; ++ ++ /* I. release all pending reordering packet */ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ pBAEntry = &Tab->BARecEntry[i]; ++ if (pBAEntry->REC_BA_Status != Recipient_NONE) ++ { ++ while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) ++ { ++ ASSERT(mpdu_blk->pPacket); ++ RELEASE_NDIS_PACKET(pAd, mpdu_blk->pPacket, NDIS_STATUS_FAILURE); ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ } ++ } ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ ++ ASSERT(pBAEntry->list.qlen == 0); ++ /* II. free memory of reordering mpdu table */ ++ NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); ++ os_free_mem(pAd, pAd->mpdu_blk_pool.mem); ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++} ++ ++ ++ ++/* ++ * Allocate all resource for reordering mechanism ++ */ ++BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num) ++{ ++ int i; ++ PUCHAR mem; ++ struct reordering_mpdu *mpdu_blk; ++ struct reordering_list *freelist; ++ ++ /* allocate spinlock */ ++ NdisAllocateSpinLock(&pAd->mpdu_blk_pool.lock); ++ ++ /* initialize freelist */ ++ freelist = &pAd->mpdu_blk_pool.freelist; ++ freelist->next = NULL; ++ freelist->qlen = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Allocate %d memory for BA reordering\n", (UINT32)(num*sizeof(struct reordering_mpdu)))); ++ ++ /* allocate number of mpdu_blk memory */ ++ os_alloc_mem(pAd, (PUCHAR *)&mem, (num*sizeof(struct reordering_mpdu))); ++ ++ pAd->mpdu_blk_pool.mem = mem; ++ ++ if (mem == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Can't Allocate Memory for BA Reordering\n")); ++ return(FALSE); ++ } ++ ++ /* build mpdu_blk free list */ ++ for (i=0; impdu_blk_pool.lock); ++ mpdu_blk = ba_dequeue(&pAd->mpdu_blk_pool.freelist); ++ if (mpdu_blk) ++ { ++// blk_count++; ++ /* reset mpdu_blk */ ++ NdisZeroMemory(mpdu_blk, sizeof(struct reordering_mpdu)); ++ } ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++ return mpdu_blk; ++} ++ ++static void ba_mpdu_blk_free(PRTMP_ADAPTER pAd, struct reordering_mpdu *mpdu_blk) ++{ ++ ASSERT(mpdu_blk); ++ ++ NdisAcquireSpinLock(&pAd->mpdu_blk_pool.lock); ++// blk_count--; ++ ba_enqueue(&pAd->mpdu_blk_pool.freelist, mpdu_blk); ++ NdisReleaseSpinLock(&pAd->mpdu_blk_pool.lock); ++} ++ ++ ++static USHORT ba_indicate_reordering_mpdus_in_order( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN USHORT StartSeq) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ USHORT LastIndSeq = RESET_RCV_SEQ; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) ++ { ++ /* find in-order frame */ ++ if (!SEQ_STEPONE(mpdu_blk->Sequence, StartSeq, MAXSEQ)) ++ { ++ break; ++ } ++ /* dequeue in-order frame from reodering list */ ++ mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ /* move to next sequence */ ++ StartSeq = mpdu_blk->Sequence; ++ LastIndSeq = StartSeq; ++ /* free mpdu_blk */ ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ ++ /* update last indicated sequence */ ++ return LastIndSeq; ++} ++ ++static void ba_indicate_reordering_mpdus_le_seq( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN USHORT Sequence) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ while ((mpdu_blk = ba_reordering_mpdu_probe(&pBAEntry->list))) ++ { ++ /* find in-order frame */ ++ if ((mpdu_blk->Sequence == Sequence) || SEQ_SMALLER(mpdu_blk->Sequence, Sequence, MAXSEQ)) ++ { ++ /* dequeue in-order frame from reodering list */ ++ mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list); ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ /* free mpdu_blk */ ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ else ++ { ++ break; ++ } ++ } ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++} ++ ++ ++static void ba_refresh_reordering_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ PBA_REC_ENTRY pBAEntry) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ /* dequeue in-order frame from reodering list */ ++ while ((mpdu_blk = ba_reordering_mpdu_dequeue(&pBAEntry->list))) ++ { ++ /* pass this frame up */ ++ ANNOUNCE_REORDERING_PACKET(pAd, mpdu_blk); ++ ++ pBAEntry->LastIndSeq = mpdu_blk->Sequence; ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ ++ /* update last indicated sequence */ ++ } ++ ASSERT(pBAEntry->list.qlen == 0); ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++} ++ ++ ++//static ++void ba_flush_reordering_timeout_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN ULONG Now32) ++ ++{ ++ USHORT Sequence; ++ ++// if ((RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+REORDERING_PACKET_TIMEOUT)) && ++// (pBAEntry->list.qlen > ((pBAEntry->BAWinSize*7)/8))) //|| ++// (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(10*REORDERING_PACKET_TIMEOUT))) && ++// (pBAEntry->list.qlen > (pBAEntry->BAWinSize/8))) ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(MAX_REORDERING_PACKET_TIMEOUT/6))) ++ &&(pBAEntry->list.qlen > 1) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("timeout[%d] (%08lx-%08lx = %d > %d): %x, flush all!\n ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++ (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), MAX_REORDERING_PACKET_TIMEOUT, ++ pBAEntry->LastIndSeq)); ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++ else ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) ++ && (pBAEntry->list.qlen > 0) ++ ) ++ { ++// printk("timeout[%d] (%lx-%lx = %d > %d): %x, ", pBAEntry->list.qlen, Now32, (pBAEntry->LastIndSeqAtTimer), ++// (int)((long) Now32 - (long)(pBAEntry->LastIndSeqAtTimer)), REORDERING_PACKET_TIMEOUT, ++// pBAEntry->LastIndSeq); ++ // ++ // force LastIndSeq to shift to LastIndSeq+1 ++ // ++ Sequence = (pBAEntry->LastIndSeq+1) & MAXSEQ; ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ pBAEntry->LastIndSeq = Sequence; ++ // ++ // indicate in-order mpdus ++ // ++ Sequence = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, Sequence); ++ if (Sequence != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = Sequence; ++ } ++ ++ //printk("%x, flush one!\n", pBAEntry->LastIndSeq); ++ ++ } ++} ++ ++ ++/* ++ * generate ADDBA request to ++ * set up BA agreement ++ */ ++VOID BAOriSessionSetUp( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN UCHAR TID, ++ IN USHORT TimeOut, ++ IN ULONG DelayTime, ++ IN BOOLEAN isForced) ++ ++{ ++ //MLME_ADDBA_REQ_STRUCT AddbaReq; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ USHORT Idx; ++ BOOLEAN Cancelled; ++ ++ if ((pAd->CommonCfg.BACapability.field.AutoBA != TRUE) && (isForced == FALSE)) ++ return; ++ ++ // if this entry is limited to use legacy tx mode, it doesn't generate BA. ++ if (RTMPStaFixedTxMode(pAd, pEntry) != FIXED_TXMODE_HT) ++ return; ++ ++ if ((pEntry->BADeclineBitmap & (1<BAOriWcidArray[TID]; ++ if (Idx == 0) ++ { ++ // allocate a BA session ++ pBAEntry = BATableAllocOriEntry(pAd, &Idx); ++ if (pBAEntry == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ADDBA - MlmeADDBAAction() allocate BA session failed \n")); ++ return; ++ } ++ } ++ else ++ { ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ } ++ ++ if (pBAEntry->ORI_BA_Status >= Originator_WaitRes) ++ { ++ return; ++ } ++ ++ pEntry->BAOriWcidArray[TID] = Idx; ++ ++ // Initialize BA session ++ pBAEntry->ORI_BA_Status = Originator_WaitRes; ++ pBAEntry->Wcid = pEntry->Aid; ++ pBAEntry->BAWinSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; ++ pBAEntry->Sequence = BA_ORI_INIT_SEQ; ++ pBAEntry->Token = 1; // (2008-01-21) Jan Lee recommends it - this token can't be 0 ++ pBAEntry->TID = TID; ++ pBAEntry->TimeOutValue = TimeOut; ++ pBAEntry->pAdapter = pAd; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Send AddBA to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d isForced:%d Wcid:%d\n" ++ ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2] ++ ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5] ++ ,TID,isForced,pEntry->Aid)); ++ ++ if (!(pEntry->TXBAbitmap & (1<ORIBATimer, GET_TIMER_FUNCTION(BAOriSessionSetupTimeout), pBAEntry, FALSE); ++ } ++ else ++ RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); ++ ++ // set timer to send ADDBA request ++ RTMPSetTimer(&pBAEntry->ORIBATimer, DelayTime); ++} ++ ++VOID BAOriSessionAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PFRAME_ADDBA_RSP pFrame) ++{ ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ BOOLEAN Cancelled; ++ UCHAR TID; ++ USHORT Idx; ++ PUCHAR pOutBuffer2 = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ FRAME_BAR FrameBar; ++ ++ TID = pFrame->BaParm.TID; ++ Idx = pEntry->BAOriWcidArray[TID]; ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ ++ // Start fill in parameters. ++ if ((Idx !=0) && (pBAEntry->TID == TID) && (pBAEntry->ORI_BA_Status == Originator_WaitRes)) ++ { ++ pBAEntry->BAWinSize = min(pBAEntry->BAWinSize, ((UCHAR)pFrame->BaParm.BufSize)); ++ BA_MaxWinSizeReasign(pAd, pEntry, &pBAEntry->BAWinSize); ++ ++ pBAEntry->TimeOutValue = pFrame->TimeOutValue; ++ pBAEntry->ORI_BA_Status = Originator_Done; ++ // reset sequence number ++ pBAEntry->Sequence = BA_ORI_INIT_SEQ; ++ // Set Bitmap flag. ++ pEntry->TXBAbitmap |= (1<ORIBATimer, &Cancelled); ++ ++ pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap, ++ pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue)); ++ ++ // SEND BAR ; ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer2); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - BAOriSessionAdd() allocate memory failed \n")); ++ return; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ BarHeaderInit(pAd, &FrameBar, pAd->MacTab.Content[pBAEntry->Wcid].Addr, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ ++ FrameBar.StartingSeq.field.FragNum = 0; // make sure sequence not clear in DEL function. ++ FrameBar.StartingSeq.field.StartSeq = pBAEntry->Sequence; // make sure sequence not clear in DEL funciton. ++ FrameBar.BarControl.TID = pBAEntry->TID; // make sure sequence not clear in DEL funciton. ++ MakeOutgoingFrame(pOutBuffer2, &FrameLen, ++ sizeof(FRAME_BAR), &FrameBar, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer2, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer2); ++ ++ ++ if (pBAEntry->ORIBATimer.TimerValue) ++ RTMPSetTimer(&pBAEntry->ORIBATimer, pBAEntry->ORIBATimer.TimerValue); // in mSec ++ } ++} ++ ++BOOLEAN BARecSessionAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PFRAME_ADDBA_REQ pFrame) ++{ ++ BA_REC_ENTRY *pBAEntry = NULL; ++ BOOLEAN Status = TRUE; ++ BOOLEAN Cancelled; ++ USHORT Idx; ++ UCHAR TID; ++ UCHAR BAWinSize; ++ //UINT32 Value; ++ //UINT offset; ++ ++ ++ ASSERT(pEntry); ++ ++ // find TID ++ TID = pFrame->BaParm.TID; ++ ++ BAWinSize = min(((UCHAR)pFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ ++ // Intel patch ++ if (BAWinSize == 0) ++ { ++ BAWinSize = 64; ++ } ++ ++ Idx = pEntry->BARecWcidArray[TID]; ++ ++ ++ if (Idx == 0) ++ { ++ pBAEntry = BATableAllocRecEntry(pAd, &Idx); ++ } ++ else ++ { ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx, ++ pFrame->BaParm.BufSize, BAWinSize)); ++ ++ // Start fill in parameters. ++ if (pBAEntry != NULL) ++ { ++ ASSERT(pBAEntry->list.qlen == 0); ++ ++ pBAEntry->REC_BA_Status = Recipient_HandleRes; ++ pBAEntry->BAWinSize = BAWinSize; ++ pBAEntry->Wcid = pEntry->Aid; ++ pBAEntry->TID = TID; ++ pBAEntry->TimeOutValue = pFrame->TimeOutValue; ++ pBAEntry->REC_BA_Status = Recipient_Accept; ++ // initial sequence number ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; //pFrame->BaStartSeq.field.StartSeq; ++ ++ printk("Start Seq = %08x\n", pFrame->BaStartSeq.field.StartSeq); ++ ++ if (pEntry->RXBAbitmap & (1<RECBATimer, &Cancelled); ++ } ++ else ++ { ++ RTMPInitTimer(pAd, &pBAEntry->RECBATimer, GET_TIMER_FUNCTION(BARecSessionIdleTimeout), pBAEntry, TRUE); ++ } ++ ++ // Set Bitmap flag. ++ pEntry->RXBAbitmap |= (1<BARecWcidArray[TID] = Idx; ++ ++ pEntry->BADeclineBitmap &= ~(1<Aid, TID); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MACEntry[%d]RXBAbitmap = 0x%x. BARecWcidArray=%d\n", ++ pEntry->Aid, pEntry->RXBAbitmap, pEntry->BARecWcidArray[TID])); ++ } ++ else ++ { ++ Status = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE,("Can't Accept ADDBA for %02x:%02x:%02x:%02x:%02x:%02x TID = %d\n", ++ PRINT_MAC(pEntry->Addr), TID)); ++ } ++ return(Status); ++} ++ ++ ++BA_REC_ENTRY *BATableAllocRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx) ++{ ++ int i; ++ BA_REC_ENTRY *pBAEntry = NULL; ++ ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ if (pAd->BATable.numAsRecipient >= MAX_BARECI_SESSION) ++ { ++ printk("BA Recipeint Session (%ld) > %d\n", pAd->BATable.numAsRecipient, ++ MAX_BARECI_SESSION); ++ goto done; ++ } ++ ++ // reserve idx 0 to identify BAWcidArray[TID] as empty ++ for (i=1; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ pBAEntry =&pAd->BATable.BARecEntry[i]; ++ if ((pBAEntry->REC_BA_Status == Recipient_NONE)) ++ { ++ // get one ++ pAd->BATable.numAsRecipient++; ++ pBAEntry->REC_BA_Status = Recipient_USED; ++ *Idx = i; ++ break; ++ } ++ } ++ ++done: ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ return pBAEntry; ++} ++ ++BA_ORI_ENTRY *BATableAllocOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Idx) ++{ ++ int i; ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ if (pAd->BATable.numAsOriginator >= (MAX_LEN_OF_BA_ORI_TABLE)) ++ { ++ goto done; ++ } ++ ++ // reserve idx 0 to identify BAWcidArray[TID] as empty ++ for (i=1; iBATable.BAOriEntry[i]; ++ if ((pBAEntry->ORI_BA_Status == Originator_NONE)) ++ { ++ // get one ++ pAd->BATable.numAsOriginator++; ++ pBAEntry->ORI_BA_Status = Originator_USED; ++ pBAEntry->pAdapter = pAd; ++ *Idx = i; ++ break; ++ } ++ } ++ ++done: ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ return pBAEntry; ++} ++ ++ ++VOID BATableFreeOriEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Idx) ++{ ++ BA_ORI_ENTRY *pBAEntry = NULL; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) ++ return; ++ ++ pBAEntry =&pAd->BATable.BAOriEntry[Idx]; ++ ++ if (pBAEntry->ORI_BA_Status != Originator_NONE) ++ { ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ pEntry->BAOriWcidArray[pBAEntry->TID] = 0; ++ ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ if (pBAEntry->ORI_BA_Status == Originator_Done) ++ { ++ pEntry->TXBAbitmap &= (~(1<<(pBAEntry->TID) )); ++ DBGPRINT(RT_DEBUG_TRACE, ("BATableFreeOriEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); ++ // Erase Bitmap flag. ++ } ++ ++ ASSERT(pAd->BATable.numAsOriginator != 0); ++ ++ pAd->BATable.numAsOriginator -= 1; ++ ++ pBAEntry->ORI_BA_Status = Originator_NONE; ++ pBAEntry->Token = 0; ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++ ++ ++VOID BATableFreeRecEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Idx) ++{ ++ BA_REC_ENTRY *pBAEntry = NULL; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_REC_TABLE)) ++ return; ++ ++ pBAEntry =&pAd->BATable.BARecEntry[Idx]; ++ ++ if (pBAEntry->REC_BA_Status != Recipient_NONE) ++ { ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ pEntry->BARecWcidArray[pBAEntry->TID] = 0; ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ ASSERT(pAd->BATable.numAsRecipient != 0); ++ ++ pAd->BATable.numAsRecipient -= 1; ++ ++ pBAEntry->REC_BA_Status = Recipient_NONE; ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++ ++ ++VOID BAOriSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive, ++ IN BOOLEAN bForceSend) ++{ ++ ULONG Idx = 0; ++ BA_ORI_ENTRY *pBAEntry; ++ BOOLEAN Cancelled; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ { ++ return; ++ } ++ ++ // ++ // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). ++ // ++ Idx = pAd->MacTab.Content[Wcid].BAOriWcidArray[TID]; ++ if ((Idx == 0) || (Idx >= MAX_LEN_OF_BA_ORI_TABLE)) ++ { ++ if (bForceSend == TRUE) ++ { ++ // force send specified TID DelBA ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = TID; ++ DelbaReq.Initiator = ORIGINATOR; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ ++ pBAEntry = &pAd->BATable.BAOriEntry[Idx]; ++ DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status)); ++ // ++ // Prepare DelBA action frame and send to the peer. ++ // ++ if ((bPassive == FALSE) && (TID == pBAEntry->TID) && (pBAEntry->ORI_BA_Status == Originator_Done)) ++ { ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = pBAEntry->TID; ++ DelbaReq.Initiator = ORIGINATOR; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ RTMPCancelTimer(&pBAEntry->ORIBATimer, &Cancelled); ++ BATableFreeOriEntry(pAd, Idx); ++ ++ if (bPassive) ++ { ++ //BAOriSessionSetUp(pAd, &pAd->MacTab.Content[Wcid], TID, 0, 10000, TRUE); ++ } ++} ++ ++VOID BARecSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive) ++{ ++ ULONG Idx = 0; ++ BA_REC_ENTRY *pBAEntry; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ { ++ return; ++ } ++ ++ // ++ // Locate corresponding BA Originator Entry in BA Table with the (pAddr,TID). ++ // ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx == 0) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ ++ ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, REC_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->REC_BA_Status)); ++ // ++ // Prepare DelBA action frame and send to the peer. ++ // ++ if ((TID == pBAEntry->TID) && (pBAEntry->REC_BA_Status == Recipient_Accept)) ++ { ++ MLME_DELBA_REQ_STRUCT DelbaReq; ++ BOOLEAN Cancelled; ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ //ULONG offset; ++ //UINT32 VALUE; ++ ++ RTMPCancelTimer(&pBAEntry->RECBATimer, &Cancelled); ++ ++ // ++ // 1. Send DELBA Action Frame ++ // ++ if (bPassive == FALSE) ++ { ++ NdisZeroMemory(&DelbaReq, sizeof(DelbaReq)); ++ NdisZeroMemory(Elem, sizeof(MLME_QUEUE_ELEM)); ++ ++ COPY_MAC_ADDR(DelbaReq.Addr, pAd->MacTab.Content[Wcid].Addr); ++ DelbaReq.Wcid = Wcid; ++ DelbaReq.TID = TID; ++ DelbaReq.Initiator = RECIPIENT; ++#if 1 ++ Elem->MsgLen = sizeof(DelbaReq); ++ NdisMoveMemory(Elem->Msg, &DelbaReq, sizeof(DelbaReq)); ++ MlmeDELBAAction(pAd, Elem); ++ kfree(Elem); ++#else ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ORI_DELBA_CATE, sizeof(MLME_DELBA_REQ_STRUCT), (PVOID)&DelbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++#endif ++ } ++ ++ ++ // ++ // 2. Free resource of BA session ++ // ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ ++ // Erase Bitmap flag. ++ pBAEntry->LastIndSeq = RESET_RCV_SEQ; ++ pBAEntry->BAWinSize = 0; ++ // Erase Bitmap flag at software mactable ++ pAd->MacTab.Content[Wcid].RXBAbitmap &= (~(1<<(pBAEntry->TID))); ++ pAd->MacTab.Content[Wcid].BARecWcidArray[TID] = 0; ++ ++ RT28XX_DEL_BA_SESSION_FROM_ASIC(pAd, Wcid, TID); ++ ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ ++ } ++ ++ BATableFreeRecEntry(pAd, Idx); ++} ++ ++VOID BASessionTearDownALL( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid) ++{ ++ int i; ++ ++ for (i=0; ipAdapter; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ pEntry = &pAd->MacTab.Content[pBAEntry->Wcid]; ++ ++ if ((pBAEntry->ORI_BA_Status == Originator_WaitRes) && (pBAEntry->Token < ORI_SESSION_MAX_RETRY)) ++ { ++ MLME_ADDBA_REQ_STRUCT AddbaReq; ++ ++ NdisZeroMemory(&AddbaReq, sizeof(AddbaReq)); ++ COPY_MAC_ADDR(AddbaReq.pAddr, pEntry->Addr); ++ AddbaReq.Wcid = (UCHAR)(pEntry->Aid); ++ AddbaReq.TID = pBAEntry->TID; ++ AddbaReq.BaBufSize = pAd->CommonCfg.BACapability.field.RxBAWinLimit; ++ AddbaReq.TimeOutValue = 0; ++ AddbaReq.Token = pBAEntry->Token; ++ MlmeEnqueue(pAd, ACTION_STATE_MACHINE, MT2_MLME_ADD_BA_CATE, sizeof(MLME_ADDBA_REQ_STRUCT), (PVOID)&AddbaReq); ++ RT28XX_MLME_HANDLER(pAd); ++ //DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) : Send ADD BA again\n", pBAEntry->Token)); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("BA Ori Session Timeout(%d) to %02x:%02x:%02x:%02x:%02x:%02x Tid:%d Wcid:%d\n" ++ ,pBAEntry->Token ++ ,pEntry->Addr[0],pEntry->Addr[1],pEntry->Addr[2] ++ ,pEntry->Addr[3],pEntry->Addr[4],pEntry->Addr[5] ++ ,pBAEntry->TID,pEntry->Aid)); ++ ++ pBAEntry->Token++; ++ RTMPSetTimer(&pBAEntry->ORIBATimer, ORI_BA_SESSION_TIMEOUT); ++ } ++ else ++ { ++ BATableFreeOriEntry(pAd, pEntry->BAOriWcidArray[pBAEntry->TID]); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Retry sending ADDBA Reqest. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Parametrs: ++ p8023Header: if this is already 802.3 format, p8023Header is NULL ++ ++ Return : TRUE if put into rx reordering buffer, shouldn't indicaterxhere. ++ FALSE , then continue indicaterx at this moment. ++ ========================================================================== ++ */ ++VOID BARecSessionIdleTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ++ BA_REC_ENTRY *pBAEntry = (BA_REC_ENTRY *)FunctionContext; ++ PRTMP_ADAPTER pAd; ++ ULONG Now32; ++ ++ if (pBAEntry == NULL) ++ return; ++ ++ if ((pBAEntry->REC_BA_Status == Recipient_Accept)) ++ { ++ NdisGetSystemUpTime(&Now32); ++ ++ if (RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer + REC_BA_SESSION_IDLE_TIMEOUT))) ++ { ++ pAd = pBAEntry->pAdapter; ++ // flush all pending reordering mpdus ++ ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ printk("%ld: REC BA session Timeout\n", Now32); ++ } ++ } ++} ++ ++ ++VOID PeerAddBAReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ // 7.4.4.1 ++ //ULONG Idx; ++ UCHAR Status = 1; ++ UCHAR pAddr[6]; ++ FRAME_ADDBA_RSP ADDframe; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ PFRAME_ADDBA_REQ pAddreqFrame = NULL; ++ //UCHAR BufSize; ++ ULONG FrameLen; ++ PULONG ptemp; ++ PMAC_TABLE_ENTRY pMacEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid)); ++ ++ //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); ++ ++ //ADDBA Request from unknown peer, ignore this. ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ pMacEntry = &pAd->MacTab.Content[Elem->Wcid]; ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerAddBAReqAction----> \n")); ++ ptemp = (PULONG)Elem->Msg; ++ //DBGPRINT_RAW(RT_DEBUG_EMU, ("%08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x:: %08x\n", *(ptemp), *(ptemp+1), *(ptemp+2), *(ptemp+3), *(ptemp+4), *(ptemp+5), *(ptemp+6), *(ptemp+7), *(ptemp+8))); ++ ++ if (PeerAddBAReqActionSanity(pAd, Elem->Msg, Elem->MsgLen, pAddr)) ++ { ++ ++ if ((pAd->CommonCfg.bBADecline == FALSE) && IS_HT_STA(pMacEntry)) ++ { ++ pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); ++ printk("Rcv Wcid(%d) AddBAReq\n", Elem->Wcid); ++ if (BARecSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pAddreqFrame)) ++ Status = 0; ++ else ++ Status = 38; // more parameters have invalid values ++ } ++ else ++ { ++ Status = 37; // the request has been declined. ++ } ++ } ++ ++ if (pAd->MacTab.Content[Elem->Wcid].ValidAsCLI) ++ ASSERT(pAd->MacTab.Content[Elem->Wcid].Sst == SST_ASSOC); ++ ++ pAddreqFrame = (PFRAME_ADDBA_REQ)(&Elem->Msg[0]); ++ // 2. Always send back ADDBA Response ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ACTION - PeerBAAction() allocate memory failed \n")); ++ return; ++ } ++ ++ NdisZeroMemory(&ADDframe, sizeof(FRAME_ADDBA_RSP)); ++ // 2-1. Prepare ADDBA Response frame. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ADHOC_ON(pAd)) ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAddr, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ else ++ ActHeaderInit(pAd, &ADDframe.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAddr); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ADDframe.Category = CATEGORY_BA; ++ ADDframe.Action = ADDBA_RESP; ++ ADDframe.Token = pAddreqFrame->Token; ++ // What is the Status code?? need to check. ++ ADDframe.StatusCode = Status; ++ ADDframe.BaParm.BAPolicy = IMMED_BA; ++ ADDframe.BaParm.AMSDUSupported = 0; ++ ADDframe.BaParm.TID = pAddreqFrame->BaParm.TID; ++ ADDframe.BaParm.BufSize = min(((UCHAR)pAddreqFrame->BaParm.BufSize), (UCHAR)pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ if (ADDframe.BaParm.BufSize == 0) ++ { ++ ADDframe.BaParm.BufSize = 64; ++ } ++ ADDframe.TimeOutValue = 0; //pAddreqFrame->TimeOutValue; ++ ++ *(USHORT *)(&ADDframe.BaParm) = cpu2le16(*(USHORT *)(&ADDframe.BaParm)); ++ ADDframe.StatusCode = cpu2le16(ADDframe.StatusCode); ++ ADDframe.TimeOutValue = cpu2le16(ADDframe.TimeOutValue); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_ADDBA_RSP), &ADDframe, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID, ++ ADDframe.BaParm.BufSize)); ++} ++ ++ ++VOID PeerAddBARspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ //UCHAR Idx, i; ++ //PUCHAR pOutBuffer = NULL; ++ PFRAME_ADDBA_RSP pFrame = NULL; ++ //PBA_ORI_ENTRY pBAEntry; ++ ++ //ADDBA Response from unknown peer, ignore this. ++ if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid)); ++ ++ //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); ++ ++ if (PeerAddBARspActionSanity(pAd, Elem->Msg, Elem->MsgLen)) ++ { ++ pFrame = (PFRAME_ADDBA_RSP)(&Elem->Msg[0]); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\t\t StatusCode = %d\n", pFrame->StatusCode)); ++ switch (pFrame->StatusCode) ++ { ++ case 0: ++ // I want a BAsession with this peer as an originator. ++ BAOriSessionAdd(pAd, &pAd->MacTab.Content[Elem->Wcid], pFrame); ++ break; ++ default: ++ // check status == USED ??? ++ BAOriSessionTearDown(pAd, Elem->Wcid, pFrame->BaParm.TID, TRUE, FALSE); ++ break; ++ } ++ // Rcv Decline StatusCode ++ if ((pFrame->StatusCode == 37) ++#ifdef CONFIG_STA_SUPPORT ++ || ((pAd->OpMode == OPMODE_STA) && STA_TGN_WIFI_ON(pAd) && (pFrame->StatusCode != 0)) ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ pAd->MacTab.Content[Elem->Wcid].BADeclineBitmap |= 1<BaParm.TID; ++ } ++ } ++} ++ ++VOID PeerDelBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ //UCHAR Idx; ++ //PUCHAR pOutBuffer = NULL; ++ PFRAME_DELBA_REQ pDelFrame = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__)); ++ //DELBA Request from unknown peer, ignore this. ++ if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) ++ { ++ pDelFrame = (PFRAME_DELBA_REQ)(&Elem->Msg[0]); ++ if (pDelFrame->DelbaParm.Initiator == ORIGINATOR) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> ORIGINATOR\n")); ++ BARecSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("BA - PeerDelBAAction----> RECIPIENT, Reason = %d\n", pDelFrame->ReasonCode)); ++ //hex_dump("DelBA Frame", pDelFrame, Elem->MsgLen); ++ BAOriSessionTearDown(pAd, Elem->Wcid, pDelFrame->DelbaParm.TID, TRUE, FALSE); ++ } ++ } ++} ++ ++ ++BOOLEAN CntlEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG MsgLen, ++ IN PFRAME_BA_REQ pMsg) ++{ ++ PFRAME_BA_REQ pFrame = pMsg; ++ //PRTMP_REORDERBUF pBuffer; ++ //PRTMP_REORDERBUF pDmaBuf; ++ PBA_REC_ENTRY pBAEntry; ++ //BOOLEAN Result; ++ ULONG Idx; ++ //UCHAR NumRxPkt; ++ UCHAR TID;//, i; ++ ++ TID = (UCHAR)pFrame->BARControl.TID; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID)); ++ //hex_dump("BAR", (PCHAR) pFrame, MsgLen); ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return FALSE; ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ else if (MsgLen != sizeof(FRAME_BA_REQ)) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ else if (MsgLen != sizeof(FRAME_BA_REQ)) ++ { ++ DBGPRINT_ERR(("CntlEnqueueForRecv: BlockAck Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ ++ if ((Wcid < MAX_LEN_OF_MAC_TABLE) && (TID < 8)) ++ { ++ // if this receiving packet is from SA that is in our OriEntry. Since WCID <9 has direct mapping. no need search. ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ } ++ else ++ { ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BAR(%ld) : Tid (%d) - %04x:%04x\n", Wcid, TID, pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq )); ++ ++ if (SEQ_SMALLER(pBAEntry->LastIndSeq, pFrame->BAStartingSeq.field.StartSeq, MAXSEQ)) ++ { ++ //printk("BAR Seq = %x, LastIndSeq = %x\n", pFrame->BAStartingSeq.field.StartSeq, pBAEntry->LastIndSeq); ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, pFrame->BAStartingSeq.field.StartSeq); ++ pBAEntry->LastIndSeq = (pFrame->BAStartingSeq.field.StartSeq == 0) ? MAXSEQ :(pFrame->BAStartingSeq.field.StartSeq -1); ++ } ++ //ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ return TRUE; ++} ++ ++/* ++Description : Send PSMP Action frame If PSMP mode switches. ++*/ ++VOID SendPSMPAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Psmp) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ //ULONG Idx; ++ FRAME_PSMP_ACTION Frame; ++ ULONG FrameLen; ++#ifdef RT30xx ++ UCHAR bbpdata=0; ++ UINT32 macdata; ++#endif // RT30xx // ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("BA - MlmeADDBAAction() allocate memory failed \n")); ++ return; ++ } ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ActHeaderInit(pAd, &Frame.Hdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->MacTab.Content[Wcid].Addr); ++#endif // CONFIG_STA_SUPPORT // ++ ++ Frame.Category = CATEGORY_HT; ++ Frame.Action = SMPS_ACTION; ++ switch (Psmp) ++ { ++ case MMPS_ENABLE: ++#ifdef RT30xx ++ if (IS_RT3090(pAd)) ++ { ++ // disable MMPS BBP control register ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); ++ bbpdata &= ~(0x04); //bit 2 ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); ++ ++ // disable MMPS MAC control register ++ RTMP_IO_READ32(pAd, 0x1210, &macdata); ++ macdata &= ~(0x09); //bit 0, 3 ++ RTMP_IO_WRITE32(pAd, 0x1210, macdata); ++ } ++#endif // RT30xx // ++ Frame.Psmp = 0; ++ break; ++ case MMPS_DYNAMIC: ++#ifdef RT30xx ++ if (IS_RT3090(pAd)) ++ { ++ // enable MMPS BBP control register ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); ++ bbpdata |= 0x04; //bit 2 ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); ++ ++ // enable MMPS MAC control register ++ RTMP_IO_READ32(pAd, 0x1210, &macdata); ++ macdata |= 0x09; //bit 0, 3 ++ RTMP_IO_WRITE32(pAd, 0x1210, macdata); ++ } ++#endif // RT30xx // ++ Frame.Psmp = 3; ++ break; ++ case MMPS_STATIC: ++#ifdef RT30xx ++ if (IS_RT3090(pAd)) ++ { ++ // enable MMPS BBP control register ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &bbpdata); ++ bbpdata |= 0x04; //bit 2 ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, bbpdata); ++ ++ // enable MMPS MAC control register ++ RTMP_IO_READ32(pAd, 0x1210, &macdata); ++ macdata |= 0x09; //bit 0, 3 ++ RTMP_IO_WRITE32(pAd, 0x1210, macdata); ++ } ++#endif // RT30xx // ++ Frame.Psmp = 1; ++ break; ++ } ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(FRAME_PSMP_ACTION), &Frame, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_ERROR,("HT - SendPSMPAction( %d ) \n", Frame.Psmp)); ++} ++ ++ ++#define RADIO_MEASUREMENT_REQUEST_ACTION 0 ++ ++typedef struct PACKED ++{ ++ UCHAR RegulatoryClass; ++ UCHAR ChannelNumber; ++ USHORT RandomInterval; ++ USHORT MeasurementDuration; ++ UCHAR MeasurementMode; ++ UCHAR BSSID[MAC_ADDR_LEN]; ++ UCHAR ReportingCondition; ++ UCHAR Threshold; ++ UCHAR SSIDIE[2]; // 2 byte ++} BEACON_REQUEST; ++ ++typedef struct PACKED ++{ ++ UCHAR ID; ++ UCHAR Length; ++ UCHAR Token; ++ UCHAR RequestMode; ++ UCHAR Type; ++} MEASUREMENT_REQ; ++ ++ ++ ++ ++void convert_reordering_packet_to_preAMSDU_or_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNDIS_PACKET pRxPkt; ++ UCHAR Header802_3[LENGTH_802_3]; ++ ++ // 1. get 802.3 Header ++ // 2. remove LLC ++ // a. pointer pRxBlk->pData to payload ++ // b. modify pRxBlk->DataSize ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ASSERT(pRxBlk->pRxPacket); ++ pRxPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ RTPKT_TO_OSPKT(pRxPkt)->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ RTPKT_TO_OSPKT(pRxPkt)->data = pRxBlk->pData; ++ RTPKT_TO_OSPKT(pRxPkt)->len = pRxBlk->DataSize; ++ RTPKT_TO_OSPKT(pRxPkt)->tail = RTPKT_TO_OSPKT(pRxPkt)->data + RTPKT_TO_OSPKT(pRxPkt)->len; ++ ++ // ++ // copy 802.3 header, if necessary ++ // ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef LINUX ++ NdisMoveMemory(skb_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); ++#endif ++#ifdef UCOS ++ NdisMoveMemory(net_pkt_push(pRxPkt, LENGTH_802_3), Header802_3, LENGTH_802_3); ++#endif ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++ ++#define INDICATE_LEGACY_OR_AMSDU(_pAd, _pRxBlk, _fromWhichBSSID) \ ++ do \ ++ { \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_AMSDU)) \ ++ { \ ++ Indicate_AMSDU_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ else if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_EAP)) \ ++ { \ ++ Indicate_EAPOL_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ else \ ++ { \ ++ Indicate_Legacy_Packet(_pAd, _pRxBlk, _fromWhichBSSID); \ ++ } \ ++ } while (0); ++ ++ ++ ++static VOID ba_enqueue_reordering_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct reordering_mpdu *mpdu_blk; ++ UINT16 Sequence = (UINT16) pRxBlk->pHeader->Sequence; ++ ++ mpdu_blk = ba_mpdu_blk_alloc(pAd); ++ if (mpdu_blk != NULL) ++ { ++ // Write RxD buffer address & allocated buffer length ++ NdisAcquireSpinLock(&pBAEntry->RxReRingLock); ++ ++ mpdu_blk->Sequence = Sequence; ++ ++ mpdu_blk->bAMSDU = RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU); ++ ++ convert_reordering_packet_to_preAMSDU_or_802_3_packet(pAd, pRxBlk, FromWhichBSSID); ++ ++ STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); ++ ++ // ++ // it is necessary for reordering packet to record ++ // which BSS it come from ++ // ++ RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); ++ ++ mpdu_blk->pPacket = pRxBlk->pRxPacket; ++ ++ if (ba_reordering_mpdu_insertsorted(&pBAEntry->list, mpdu_blk) == FALSE) ++ { ++ // had been already within reordering list ++ // don't indicate ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_SUCCESS); ++ ba_mpdu_blk_free(pAd, mpdu_blk); ++ } ++ ++ ASSERT((0<= pBAEntry->list.qlen) && (pBAEntry->list.qlen <= pBAEntry->BAWinSize)); ++ NdisReleaseSpinLock(&pBAEntry->RxReRingLock); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!! (%d) Can't allocate reordering mpdu blk\n", ++ pBAEntry->list.qlen)); ++ /* ++ * flush all pending reordering mpdus ++ * and receving mpdu to upper layer ++ * make tcp/ip to take care reordering mechanism ++ */ ++ //ba_refresh_reordering_mpdus(pAd, pBAEntry); ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, Sequence); ++ ++ pBAEntry->LastIndSeq = Sequence; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Indicate this packet to upper layer or put it into reordering buffer ++ ++ Parametrs: ++ pRxBlk : carry necessary packet info 802.11 format ++ FromWhichBSSID : the packet received from which BSS ++ ++ Return : ++ none ++ ++ Note : ++ the packet queued into reordering buffer need to cover to 802.3 format ++ or pre_AMSDU format ++ ========================================================================== ++ */ ++ ++VOID Indicate_AMPDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ USHORT Idx; ++ PBA_REC_ENTRY pBAEntry = NULL; ++ UINT16 Sequence = pRxBlk->pHeader->Sequence; ++ ULONG Now32; ++ UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; ++ UCHAR TID = pRxBlk->pRxWI->TID; ++ ++ ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU) && (pRxBlk->DataSize > MAX_RX_PKT_LEN)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx == 0) ++ { ++ /* Rec BA Session had been torn down */ ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ } ++ else ++ { ++ // impossible !!! ++ ASSERT(0); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ASSERT(pBAEntry); ++ ++ // update last rx time ++ NdisGetSystemUpTime(&Now32); ++ ++ pBAEntry->rcvSeq = Sequence; ++ ++ ++ ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ ++ // ++ // Reset Last Indicate Sequence ++ // ++ if (pBAEntry->LastIndSeq == RESET_RCV_SEQ) ++ { ++ ASSERT((pBAEntry->list.qlen == 0) && (pBAEntry->list.next == NULL)); ++ ++ // reset rcv sequence of BA session ++ pBAEntry->LastIndSeq = Sequence; ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ ++ ++ // ++ // I. Check if in order. ++ // ++ if (SEQ_STEPONE(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) ++ { ++ USHORT LastIndSeq; ++ ++ pBAEntry->LastIndSeq = Sequence; ++ INDICATE_LEGACY_OR_AMSDU(pAd, pRxBlk, FromWhichBSSID); ++ LastIndSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); ++ if (LastIndSeq != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = LastIndSeq; ++ } ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ } ++ // ++ // II. Drop Duplicated Packet ++ // ++ else if (Sequence == pBAEntry->LastIndSeq) ++ { ++ ++ // drop and release packet ++ pBAEntry->nDropPacket++; ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ // ++ // III. Drop Old Received Packet ++ // ++ else if (SEQ_SMALLER(Sequence, pBAEntry->LastIndSeq, MAXSEQ)) ++ { ++ ++ // drop and release packet ++ pBAEntry->nDropPacket++; ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ // ++ // IV. Receive Sequence within Window Size ++ // ++ else if (SEQ_SMALLER(Sequence, (((pBAEntry->LastIndSeq+pBAEntry->BAWinSize+1)) & MAXSEQ), MAXSEQ)) ++ { ++ ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); ++ } ++ // ++ // V. Receive seq surpasses Win(lastseq + nMSDU). So refresh all reorder buffer ++ // ++ else ++ { ++ LONG WinStartSeq, TmpSeq; ++ ++ ++ TmpSeq = Sequence - (pBAEntry->BAWinSize) -1; ++ if (TmpSeq < 0) ++ { ++ TmpSeq = (MAXSEQ+1) + TmpSeq; ++ } ++ WinStartSeq = (TmpSeq+1) & MAXSEQ; ++ ba_indicate_reordering_mpdus_le_seq(pAd, pBAEntry, WinStartSeq); ++ pBAEntry->LastIndSeq = WinStartSeq; //TmpSeq; ++ ++ pBAEntry->LastIndSeqAtTimer = Now32; ++ ++ ba_enqueue_reordering_packet(pAd, pBAEntry, pRxBlk, FromWhichBSSID); ++ ++ TmpSeq = ba_indicate_reordering_mpdus_in_order(pAd, pBAEntry, pBAEntry->LastIndSeq); ++ if (TmpSeq != RESET_RCV_SEQ) ++ { ++ pBAEntry->LastIndSeq = TmpSeq; ++ } ++ } ++} ++ ++#endif // DOT11_N_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/cmm_data_2870.c +@@ -0,0 +1,980 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++/* ++ All functions in this file must be USB-depended, or you should out your function ++ in other files. ++ ++*/ ++#include "../rt_config.h" ++ ++ ++/* ++ We can do copy the frame into pTxContext when match following conditions. ++ => ++ => ++ => ++*/ ++static inline NDIS_STATUS RtmpUSBCanDoWrite( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN HT_TX_CONTEXT *pHTTXContext) ++{ ++ NDIS_STATUS canWrite = NDIS_STATUS_RESOURCES; ++ ++ if (((pHTTXContext->CurWritePosition) < pHTTXContext->NextBulkOutPosition) && (pHTTXContext->CurWritePosition + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c1!\n")); ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); ++ } ++ else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < LOCAL_TXBUF_SIZE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c2!\n")); ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); ++ } ++ else if (pHTTXContext->bCurWriting == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("RtmpUSBCanDoWrite c3!\n")); ++ } ++ else ++ { ++ canWrite = NDIS_STATUS_SUCCESS; ++ } ++ ++ ++ return canWrite; ++} ++ ++ ++USHORT RtmpUSB_WriteSubTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber) ++{ ++ ++ // Dummy function. Should be removed in the future. ++ return 0; ++ ++} ++ ++USHORT RtmpUSB_WriteFragTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR fragNum, ++ OUT USHORT *FreeNumber) ++{ ++ HT_TX_CONTEXT *pHTTXContext; ++ USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ PUCHAR pWirelessPacket = NULL; ++ UCHAR QueIdx; ++ NDIS_STATUS Status; ++ unsigned long IrqFlags; ++ UINT32 USBDMApktLen = 0, DMAHdrLen, padding; ++ BOOLEAN TxQLastRound = FALSE; ++ ++ // ++ // get Tx Ring Resource & Dma Buffer address ++ // ++ QueIdx = pTxBlk->QueIdx; ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ fillOffset = pHTTXContext->CurWritePosition; ++ ++ if(fragNum == 0) ++ { ++ // Check if we have enough space for this bulk-out batch. ++ Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ pHTTXContext->bCurWriting = TRUE; ++ ++ // Reserve space for 8 bytes padding. ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) ++ { ++ pHTTXContext->ENextBulkOutPosition += 8; ++ pHTTXContext->CurWritePosition += 8; ++ fillOffset += 8; ++ } ++ pTxBlk->Priv = 0; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return(Status); ++ } ++ } ++ else ++ { ++ // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. ++ Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ fillOffset += pTxBlk->Priv; ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return(Status); ++ } ++ } ++ ++ NdisZeroMemory((PUCHAR)(&pTxBlk->HeaderBuf[0]), TXINFO_SIZE); ++ pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); ++ pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); ++ ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ // copy TXWI + WLAN Header + LLC into DMA Header Buffer ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ // Build our URB for USBD ++ DMAHdrLen = TXWI_SIZE + hwHdrLen; ++ USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; ++ padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment ++ USBDMApktLen += padding; ++ ++ pTxBlk->Priv += (TXINFO_SIZE + USBDMApktLen); ++ ++ // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); ++ ++ if (fragNum == pTxBlk->TotalFragNum) ++ { ++ pTxInfo->USBDMATxburst = 0; ++ if ((pHTTXContext->CurWritePosition + pTxBlk->Priv + 3906)> MAX_TXBULK_LIMIT) ++ { ++ pTxInfo->SwUseLastRound = 1; ++ TxQLastRound = TRUE; ++ } ++ } ++ else ++ { ++ pTxInfo->USBDMATxburst = 1; ++ } ++ ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); ++ ++ // Zero the last padding. ++ pWirelessPacket += pTxBlk->SrcBufLen; ++ NdisZeroMemory(pWirelessPacket, padding + 8); ++ ++ if (fragNum == pTxBlk->TotalFragNum) ++ { ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ // Update the pHTTXContext->CurWritePosition. 3906 used to prevent the NextBulkOut is a A-RALINK/A-MSDU Frame. ++ pHTTXContext->CurWritePosition += pTxBlk->Priv; ++ if (TxQLastRound == TRUE) ++ pHTTXContext->CurWritePosition = 8; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ ++ // Finally, set bCurWriting as FALSE ++ pHTTXContext->bCurWriting = FALSE; ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ // succeed and release the skb buffer ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); ++ } ++ ++ ++ return(Status); ++ ++} ++ ++ ++USHORT RtmpUSB_WriteSingleTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber) ++{ ++ HT_TX_CONTEXT *pHTTXContext; ++ USHORT hwHdrLen; ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ PUCHAR pWirelessPacket; ++ UCHAR QueIdx; ++ unsigned long IrqFlags; ++ NDIS_STATUS Status; ++ UINT32 USBDMApktLen = 0, DMAHdrLen, padding; ++ BOOLEAN bTxQLastRound = FALSE; ++ ++ // For USB, didn't need PCI_MAP_SINGLE() ++ //SrcBufPA = PCI_MAP_SINGLE(pAd, (char *) pTxBlk->pSrcBufData, pTxBlk->SrcBufLen, PCI_DMA_TODEVICE); ++ ++ ++ // ++ // get Tx Ring Resource & Dma Buffer address ++ // ++ QueIdx = pTxBlk->QueIdx; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ fillOffset = pHTTXContext->CurWritePosition; ++ ++ ++ ++ // Check ring full. ++ Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); ++ if(Status == NDIS_STATUS_SUCCESS) ++ { ++ pHTTXContext->bCurWriting = TRUE; ++ ++ pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); ++ pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); ++ ++ // Reserve space for 8 bytes padding. ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) ++ { ++ pHTTXContext->ENextBulkOutPosition += 8; ++ pHTTXContext->CurWritePosition += 8; ++ fillOffset += 8; ++ } ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ // copy TXWI + WLAN Header + LLC into DMA Header Buffer ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ // Build our URB for USBD ++ DMAHdrLen = TXWI_SIZE + hwHdrLen; ++ USBDMApktLen = DMAHdrLen + pTxBlk->SrcBufLen; ++ padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment ++ USBDMApktLen += padding; ++ ++ pTxBlk->Priv = (TXINFO_SIZE + USBDMApktLen); ++ ++ // For TxInfo, the length of USBDMApktLen = TXWI_SIZE + 802.11 header + payload ++ //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(USBDMApktLen), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((pHTTXContext->CurWritePosition + 3906 + pTxBlk->Priv) > MAX_TXBULK_LIMIT) ++ { ++ pTxInfo->SwUseLastRound = 1; ++ bTxQLastRound = TRUE; ++ } ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pWirelessPacket += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ ++ // We unlock it here to prevent the first 8 bytes maybe over-writed issue. ++ // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxcontext. ++ // 2. An interrupt break our routine and handle bulk-out complete. ++ // 3. In the bulk-out compllete, it need to do another bulk-out, ++ // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, ++ // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. ++ // 4. Interrupt complete. ++ // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. ++ // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. ++ // and the packet will wrong. ++ pHTTXContext->CurWriteRealPos += (TXINFO_SIZE + TXWI_SIZE + hwHdrLen); ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); ++ pWirelessPacket += pTxBlk->SrcBufLen; ++ NdisZeroMemory(pWirelessPacket, padding + 8); ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ pHTTXContext->CurWritePosition += pTxBlk->Priv; ++ if (bTxQLastRound) ++ pHTTXContext->CurWritePosition = 8; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ pHTTXContext->bCurWriting = FALSE; ++ } ++ ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ ++ // succeed and release the skb buffer ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); ++ ++ return(Status); ++ ++} ++ ++ ++USHORT RtmpUSB_WriteMultiTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR frameNum, ++ OUT USHORT *FreeNumber) ++{ ++ HT_TX_CONTEXT *pHTTXContext; ++ USHORT hwHdrLen; // The hwHdrLen consist of 802.11 header length plus the header padding length. ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ PUCHAR pWirelessPacket = NULL; ++ UCHAR QueIdx; ++ NDIS_STATUS Status; ++ unsigned long IrqFlags; ++ //UINT32 USBDMApktLen = 0, DMAHdrLen, padding; ++ ++ // ++ // get Tx Ring Resource & Dma Buffer address ++ // ++ QueIdx = pTxBlk->QueIdx; ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ if(frameNum == 0) ++ { ++ // Check if we have enough space for this bulk-out batch. ++ Status = RtmpUSBCanDoWrite(pAd, QueIdx, pHTTXContext); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ pHTTXContext->bCurWriting = TRUE; ++ ++ pTxInfo = (PTXINFO_STRUC)(&pTxBlk->HeaderBuf[0]); ++ pTxWI= (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]); ++ ++ ++ // Reserve space for 8 bytes padding. ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition)) ++ { ++ ++ pHTTXContext->CurWritePosition += 8; ++ pHTTXContext->ENextBulkOutPosition += 8; ++ } ++ fillOffset = pHTTXContext->CurWritePosition; ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ // ++ // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer ++ // ++ if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD; ++ hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD; ++ else if (pTxBlk->TxFrameType == TX_RALINK_FRAME) ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD; ++ hwHdrLen = pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD; ++ else ++ //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4); ++ hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen; ++ ++ // Update the pTxBlk->Priv. ++ pTxBlk->Priv = TXINFO_SIZE + TXWI_SIZE + hwHdrLen; ++ ++ // pTxInfo->USBDMApktLen now just a temp value and will to correct latter. ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(pTxBlk->Priv), FALSE, FIFO_EDCA, FALSE /*NextValid*/, FALSE); ++ ++ // Copy it. ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->Priv); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)(pWirelessPacket+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pHTTXContext->CurWriteRealPos += pTxBlk->Priv; ++ pWirelessPacket += pTxBlk->Priv; ++ } ++ } ++ else ++ { // For sub-sequent frames of this bulk-out batch. Just copy it to our bulk-out buffer. ++ ++ Status = ((pHTTXContext->bCurWriting == TRUE) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE); ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ fillOffset = (pHTTXContext->CurWritePosition + pTxBlk->Priv); ++ pWirelessPacket = &pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]; ++ ++ //hwHdrLen = pTxBlk->MpduHeaderLen; ++ NdisMoveMemory(pWirelessPacket, pTxBlk->HeaderBuf, pTxBlk->MpduHeaderLen); ++ pWirelessPacket += (pTxBlk->MpduHeaderLen); ++ pTxBlk->Priv += pTxBlk->MpduHeaderLen; ++ } ++ else ++ { // It should not happened now unless we are going to shutdown. ++ DBGPRINT(RT_DEBUG_ERROR, ("WriteMultiTxResource():bCurWriting is FALSE when handle sub-sequent frames.\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ } ++ ++ ++ // We unlock it here to prevent the first 8 bytes maybe over-write issue. ++ // 1. First we got CurWritePosition but the first 8 bytes still not write to the pTxContext. ++ // 2. An interrupt break our routine and handle bulk-out complete. ++ // 3. In the bulk-out compllete, it need to do another bulk-out, ++ // if the ENextBulkOutPosition is just the same as CurWritePosition, it will save the first 8 bytes from CurWritePosition, ++ // but the payload still not copyed. the pTxContext->SavedPad[] will save as allzero. and set the bCopyPad = TRUE. ++ // 4. Interrupt complete. ++ // 5. Our interrupted routine go back and fill the first 8 bytes to pTxContext. ++ // 6. Next time when do bulk-out, it found the bCopyPad==TRUE and will copy the SavedPad[] to pTxContext->NextBulkOutPosition. ++ // and the packet will wrong. ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("WriteMultiTxResource: CWPos = %ld, NBOutPos = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); ++ goto done; ++ } ++ ++ // Copy the frame content into DMA buffer and update the pTxBlk->Priv ++ NdisMoveMemory(pWirelessPacket, pTxBlk->pSrcBufData, pTxBlk->SrcBufLen); ++ pWirelessPacket += pTxBlk->SrcBufLen; ++ pTxBlk->Priv += pTxBlk->SrcBufLen; ++ ++done: ++ // Release the skb buffer here ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_SUCCESS); ++ ++ return(Status); ++ ++} ++ ++ ++VOID RtmpUSB_FinalWriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN USHORT totalMPDUSize, ++ IN USHORT TxIdx) ++{ ++ UCHAR QueIdx; ++ HT_TX_CONTEXT *pHTTXContext; ++ UINT32 fillOffset; ++ TXINFO_STRUC *pTxInfo; ++ TXWI_STRUC *pTxWI; ++ UINT32 USBDMApktLen, padding; ++ unsigned long IrqFlags; ++ PUCHAR pWirelessPacket; ++ ++ QueIdx = pTxBlk->QueIdx; ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++ if (pHTTXContext->bCurWriting == TRUE) ++ { ++ fillOffset = pHTTXContext->CurWritePosition; ++ if (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) ++ && (pHTTXContext->bCopySavePad == TRUE)) ++ pWirelessPacket = (PUCHAR)(&pHTTXContext->SavedPad[0]); ++ else ++ pWirelessPacket = (PUCHAR)(&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset]); ++ ++ // ++ // Update TxInfo->USBDMApktLen , ++ // the length = TXWI_SIZE + 802.11_hdr + 802.11_hdr_pad + payload_of_all_batch_frames + Bulk-Out-padding ++ // ++ pTxInfo = (PTXINFO_STRUC)(pWirelessPacket); ++ ++ // Calculate the bulk-out padding ++ USBDMApktLen = pTxBlk->Priv - TXINFO_SIZE; ++ padding = (4 - (USBDMApktLen % 4)) & 0x03; // round up to 4 byte alignment ++ USBDMApktLen += padding; ++ ++ pTxInfo->USBDMATxPktLen = USBDMApktLen; ++ ++ // ++ // Update TXWI->MPDUtotalByteCount , ++ // the length = 802.11 header + payload_of_all_batch_frames ++ pTxWI= (PTXWI_STRUC)(pWirelessPacket + TXINFO_SIZE); ++ pTxWI->MPDUtotalByteCount = totalMPDUSize; ++ ++ // ++ // Update the pHTTXContext->CurWritePosition ++ // ++ pHTTXContext->CurWritePosition += (TXINFO_SIZE + USBDMApktLen); ++ if ((pHTTXContext->CurWritePosition + 3906)> MAX_TXBULK_LIMIT) ++ { // Add 3906 for prevent the NextBulkOut packet size is a A-RALINK/A-MSDU Frame. ++ pHTTXContext->CurWritePosition = 8; ++ pTxInfo->SwUseLastRound = 1; ++ } ++ pHTTXContext->CurWriteRealPos = pHTTXContext->CurWritePosition; ++ ++ ++ // ++ // Zero the last padding. ++ // ++ pWirelessPacket = (&pHTTXContext->TransferBuffer->field.WirelessPacket[fillOffset + pTxBlk->Priv]); ++ NdisZeroMemory(pWirelessPacket, padding + 8); ++ ++ // Finally, set bCurWriting as FALSE ++ pHTTXContext->bCurWriting = FALSE; ++ ++ } ++ else ++ { // It should not happened now unless we are going to shutdown. ++ DBGPRINT(RT_DEBUG_ERROR, ("FinalWriteTxResource():bCurWriting is FALSE when handle last frames.\n")); ++ } ++ ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ ++} ++ ++ ++VOID RtmpUSBDataLastTxIdx( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN USHORT TxIdx) ++{ ++ // DO nothing for USB. ++} ++ ++ ++/* ++ When can do bulk-out: ++ 1. TxSwFreeIdx < TX_RING_SIZE; ++ It means has at least one Ring entity is ready for bulk-out, kick it out. ++ 2. If TxSwFreeIdx == TX_RING_SIZE ++ Check if the CurWriting flag is FALSE, if it's FALSE, we can do kick out. ++ ++*/ ++VOID RtmpUSBDataKickOut( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx) ++{ ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << QueIdx)); ++ RTUSBKickBulkOut(pAd); ++ ++} ++ ++ ++/* ++ Must be run in Interrupt context ++ This function handle RT2870 specific TxDesc and cpu index update and kick the packet out. ++ */ ++int RtmpUSBMgmtKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pSrcBufVA, ++ IN UINT SrcBufLen) ++{ ++ PTXINFO_STRUC pTxInfo; ++ ULONG BulkOutSize; ++ UCHAR padLen; ++ PUCHAR pDest; ++ ULONG SwIdx = pAd->MgmtRing.TxCpuIdx; ++ PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[SwIdx].AllocVa; ++ unsigned long IrqFlags; ++ ++ ++ pTxInfo = (PTXINFO_STRUC)(pSrcBufVA); ++ ++ // Build our URB for USBD ++ BulkOutSize = SrcBufLen; ++ BulkOutSize = (BulkOutSize + 3) & (~3); ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(BulkOutSize - TXINFO_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ ++ BulkOutSize += 4; // Always add 4 extra bytes at every packet. ++ ++ // If BulkOutSize is multiple of BulkOutMaxPacketSize, add extra 4 bytes again. ++ if ((BulkOutSize % pAd->BulkOutMaxPacketSize) == 0) ++ BulkOutSize += 4; ++ ++ padLen = BulkOutSize - SrcBufLen; ++ ASSERT((padLen <= RTMP_PKT_TAIL_PADDING)); ++ ++ // Now memzero all extra padding bytes. ++ pDest = (PUCHAR)(pSrcBufVA + SrcBufLen); ++ skb_put(GET_OS_PKT_TYPE(pPacket), padLen); ++ NdisZeroMemory(pDest, padLen); ++ ++ RTMP_IRQ_LOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ pAd->MgmtRing.Cell[pAd->MgmtRing.TxCpuIdx].pNdisPacket = pPacket; ++ pMLMEContext->TransferBuffer = (PTX_BUFFER)(GET_OS_PKT_DATAPTR(pPacket)); ++ ++ // Length in TxInfo should be 8 less than bulkout size. ++ pMLMEContext->BulkOutSize = BulkOutSize; ++ pMLMEContext->InUse = TRUE; ++ pMLMEContext->bWaitingBulkOut = TRUE; ++ ++ ++ //for debug ++ //hex_dump("RtmpUSBMgmtKickOut", &pMLMEContext->TransferBuffer->field.WirelessPacket[0], (pMLMEContext->BulkOutSize > 16 ? 16 : pMLMEContext->BulkOutSize)); ++ ++ //pAd->RalinkCounters.KickTxCount++; ++ //pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ //if (pAd->MgmtRing.TxSwFreeIdx == MGMT_RING_SIZE) ++ // needKickOut = TRUE; ++ ++ // Decrease the TxSwFreeIdx and Increase the TX_CTX_IDX ++ pAd->MgmtRing.TxSwFreeIdx--; ++ INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE); ++ ++ RTMP_IRQ_UNLOCK(&pAd->MLMEBulkOutLock, IrqFlags); ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ //if (needKickOut) ++ RTUSBKickBulkOut(pAd); ++ ++ return 0; ++} ++ ++ ++VOID RtmpUSBNullFrameKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR *pNullFrame, ++ IN UINT32 frameLen) ++{ ++ if (pAd->NullContext.InUse == FALSE) ++ { ++ PTX_CONTEXT pNullContext; ++ PTXINFO_STRUC pTxInfo; ++ PTXWI_STRUC pTxWI; ++ PUCHAR pWirelessPkt; ++ ++ pNullContext = &(pAd->NullContext); ++ ++ // Set the in use bit ++ pNullContext->InUse = TRUE; ++ pWirelessPkt = (PUCHAR)&pNullContext->TransferBuffer->field.WirelessPacket[0]; ++ ++ RTMPZeroMemory(&pWirelessPkt[0], 100); ++ pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[0]; ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxInfo->QSEL = FIFO_EDCA; ++ pTxWI = (PTXWI_STRUC)&pWirelessPkt[TXINFO_SIZE]; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), ++ 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ RTMPMoveMemory(&pWirelessPkt[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)&pWirelessPkt[TXINFO_SIZE + TXWI_SIZE], DIR_WRITE, FALSE); ++#endif // RT_BIG_ENDIAN // ++ pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; ++ ++ // Fill out frame length information for global Bulk out arbitor ++ //pNullContext->BulkOutSize = TransferBufferLength; ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - send NULL Frame @%d Mbps...\n", RateIdToMbps[pAd->CommonCfg.TxRate])); ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); ++ ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ } ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound ++ ++ Arguments: ++ pRxD Pointer to the Rx descriptor ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS No err ++ NDIS_STATUS_FAILURE Error ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxINFO) ++{ ++ PCIPHER_KEY pWpaKey; ++ INT dBm; ++ ++ if (pAd->bPromiscuous == TRUE) ++ return(NDIS_STATUS_SUCCESS); ++ if(pRxINFO == NULL) ++ return(NDIS_STATUS_FAILURE); ++ ++ // Phy errors & CRC errors ++ if (pRxINFO->Crc) ++ { ++ // Check RSSI for Noise Hist statistic collection. ++ dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta; ++ if (dBm <= -87) ++ pAd->StaCfg.RPIDensity[0] += 1; ++ else if (dBm <= -82) ++ pAd->StaCfg.RPIDensity[1] += 1; ++ else if (dBm <= -77) ++ pAd->StaCfg.RPIDensity[2] += 1; ++ else if (dBm <= -72) ++ pAd->StaCfg.RPIDensity[3] += 1; ++ else if (dBm <= -67) ++ pAd->StaCfg.RPIDensity[4] += 1; ++ else if (dBm <= -62) ++ pAd->StaCfg.RPIDensity[5] += 1; ++ else if (dBm <= -57) ++ pAd->StaCfg.RPIDensity[6] += 1; ++ else if (dBm > -57) ++ pAd->StaCfg.RPIDensity[7] += 1; ++ ++ return(NDIS_STATUS_FAILURE); ++ } ++ ++ // Add Rx size to channel load counter, we should ignore error counts ++ pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount+ 14); ++ ++ // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics ++ if (pHeader->FC.ToDs) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n")); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // Paul 04-03 for OFDM Rx length issue ++ if (pRxWI->MPDUtotalByteCount > MAX_AGGREGATION_SIZE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // Drop not U2M frames, cant's drop here because we will drop beacon in this case ++ // I am kind of doubting the U2M bit operation ++ // if (pRxD->U2M == 0) ++ // return(NDIS_STATUS_FAILURE); ++ ++ // drop decyption fail frame ++ if (pRxINFO->Decrypted && pRxINFO->CipherErr) ++ { ++ ++ // ++ // MIC Error ++ // ++ if ((pRxINFO->CipherErr == 2) && pRxINFO->MyBss) ++ { ++ pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex]; ++ RTMPReportMicError(pAd, pWpaKey); ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n")); ++ } ++ ++ if (pRxINFO->Decrypted && ++ (pAd->SharedKey[BSS0][pRxWI->KeyIndex].CipherAlg == CIPHER_AES) && ++ (pHeader->Sequence == pAd->FragFrame.Sequence)) ++ { ++ // ++ // Acceptable since the First FragFrame no CipherErr problem. ++ // ++ return(NDIS_STATUS_SUCCESS); ++ } ++ ++ return(NDIS_STATUS_FAILURE); ++ } ++ ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++VOID RT28xxUsbStaAsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx) ++{ ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++} ++ ++VOID RT28xxUsbStaAsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ AUTO_WAKEUP_STRUC AutoWakeupCfg; ++ ++ // we have decided to SLEEP, so at least do it for a BEACON period. ++ if (TbttNumToNextWakeUp == 0) ++ TbttNumToNextWakeUp = 1; ++ ++ AutoWakeupCfg.word = 0; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1; ++ AutoWakeupCfg.field.EnableAutoWakeup = 1; ++ AutoWakeupCfg.field.AutoLeadTime = 5; ++ RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ ++ AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); // send POWER-SAVE command to MCU. Timeout 40us. ++ ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RT28xxUsbMlmeRadioOn( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOn()\n")); ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02); ++ RTMPusecDelay(10000); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ NICResetFromError(pAd); ++ ++ // Enable Tx/Rx ++ RTMPEnableRxTx(pAd); ++ ++#ifdef RT3070 ++ if (IS_RT3071(pAd)) ++ { ++ RT30xxReverseRFSleepModeSetup(pAd); ++ } ++#endif // RT3070 // ++ ++ // Clear Radio off flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTUSBBulkReceive(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_ON); ++} ++ ++VOID RT28xxUsbMlmeRadioOFF( ++ IN PRTMP_ADAPTER pAd) ++{ ++ WPDMA_GLO_CFG_STRUC GloCfg; ++ UINT32 Value, i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RT28xxUsbMlmeRadioOFF()\n")); ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_RADIO_OFF); ++ // Set Radio off flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Link down first if any association exists ++ if (INFRA_ON(pAd) || ADHOC_ON(pAd)) ++ LinkDown(pAd, FALSE); ++ RTMPusecDelay(10000); ++ ++ //========================================== ++ // Clean up old bss table ++ BssTableInit(&pAd->ScanTab); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ // Must using 40MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); ++ } ++ ++ // Disable Tx/Rx DMA ++ RTUSBReadMACRegister(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA ++ GloCfg.field.EnableTxDMA = 0; ++ GloCfg.field.EnableRxDMA = 0; ++ RTUSBWriteMACRegister(pAd, WPDMA_GLO_CFG, GloCfg.word); // abort all TX rings ++ ++ // Waiting for DMA idle ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ }while (i++ < 100); ++ ++ // Disable MAC Tx/Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= (0xfffffff3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // MAC_SYS_CTRL => value = 0x0 => 40mA ++ //RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0); ++ ++ // PWR_PIN_CFG => value = 0x0 => 40mA ++ //RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0); ++ ++ // TX_PIN_CFG => value = 0x0 => 20mA ++ //RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); ++#endif // CONFIG_STA_SUPPORT // ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/cmm_data.c +@@ -0,0 +1,2827 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#include "../rt_config.h" ++ ++#define MAX_TX_IN_TBTT (16) ++ ++ ++UCHAR SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; ++UCHAR SNAP_BRIDGE_TUNNEL[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8}; ++// Add Cisco Aironet SNAP heade for CCX2 support ++UCHAR SNAP_AIRONET[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x00}; ++UCHAR CKIP_LLC_SNAP[] = {0xaa, 0xaa, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; ++UCHAR EAPOL_LLC_SNAP[]= {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e}; ++UCHAR EAPOL[] = {0x88, 0x8e}; ++UCHAR TPID[] = {0x81, 0x00}; /* VLAN related */ ++ ++UCHAR IPX[] = {0x81, 0x37}; ++UCHAR APPLE_TALK[] = {0x80, 0xf3}; ++UCHAR RateIdToPlcpSignal[12] = { ++ 0, /* RATE_1 */ 1, /* RATE_2 */ 2, /* RATE_5_5 */ 3, /* RATE_11 */ // see BBP spec ++ 11, /* RATE_6 */ 15, /* RATE_9 */ 10, /* RATE_12 */ 14, /* RATE_18 */ // see IEEE802.11a-1999 p.14 ++ 9, /* RATE_24 */ 13, /* RATE_36 */ 8, /* RATE_48 */ 12 /* RATE_54 */ }; // see IEEE802.11a-1999 p.14 ++ ++UCHAR OfdmSignalToRateId[16] = { ++ RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 0, 1, 2, 3 respectively ++ RATE_54, RATE_54, RATE_54, RATE_54, // OFDM PLCP Signal = 4, 5, 6, 7 respectively ++ RATE_48, RATE_24, RATE_12, RATE_6, // OFDM PLCP Signal = 8, 9, 10, 11 respectively ++ RATE_54, RATE_36, RATE_18, RATE_9, // OFDM PLCP Signal = 12, 13, 14, 15 respectively ++}; ++ ++UCHAR OfdmRateToRxwiMCS[12] = { ++ 0, 0, 0, 0, ++ 0, 1, 2, 3, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 ++ 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 ++}; ++UCHAR RxwiMCSToOfdmRate[12] = { ++ RATE_6, RATE_9, RATE_12, RATE_18, ++ RATE_24, RATE_36, RATE_48, RATE_54, // OFDM rate 6,9,12,18 = rxwi mcs 0,1,2,3 ++ 4, 5, 6, 7, // OFDM rate 24,36,48,54 = rxwi mcs 4,5,6,7 ++}; ++ ++char* MCSToMbps[] = {"1Mbps","2Mbps","5.5Mbps","11Mbps","06Mbps","09Mbps","12Mbps","18Mbps","24Mbps","36Mbps","48Mbps","54Mbps","MM-0","MM-1","MM-2","MM-3","MM-4","MM-5","MM-6","MM-7","MM-8","MM-9","MM-10","MM-11","MM-12","MM-13","MM-14","MM-15","MM-32","ee1","ee2","ee3"}; ++ ++UCHAR default_cwmin[]={CW_MIN_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1, CW_MIN_IN_BITS-2}; ++//UCHAR default_cwmax[]={CW_MAX_IN_BITS, CW_MAX_IN_BITS, CW_MIN_IN_BITS, CW_MIN_IN_BITS-1}; ++UCHAR default_sta_aifsn[]={3,7,2,2}; ++ ++UCHAR MapUserPriorityToAccessCategory[8] = {QID_AC_BE, QID_AC_BK, QID_AC_BK, QID_AC_BE, QID_AC_VI, QID_AC_VI, QID_AC_VO, QID_AC_VO}; ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ API for MLME to transmit management frame to AP (BSS Mode) ++ or station (IBSS Mode) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the outgoing 802.11 frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MiniportMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length) ++{ ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ULONG FreeNum; ++ UCHAR IrqState; ++ UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; ++ ++ ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); ++ ++ QueIdx=3; ++ ++ // 2860C use Tx Ring ++ ++ IrqState = pAd->irq_disabled; ++ ++ do ++ { ++ // Reset is in progress, stop immediately ++ if ( RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| ++ !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ break; ++ } ++ ++ // Check Free priority queue ++ // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. ++ ++ // 2860C use Tx Ring ++ if (pAd->MACVersion == 0x28600100) ++ { ++ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); ++ } ++ else ++ { ++ FreeNum = GET_MGMTRING_FREENO(pAd); ++ } ++ ++ if ((FreeNum > 0)) ++ { ++ // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 ++ NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); ++ break; ++ } ++ ++ //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ //pAd->CommonCfg.MlmeRate = RATE_2; ++ ++ ++ Status = MlmeHardTransmit(pAd, QueIdx, pPacket); ++ if (Status != NDIS_STATUS_SUCCESS) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ } ++ else ++ { ++ pAd->RalinkCounters.MgmtRingFullCount++; ++ DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in MgmtRing, MgmtRingFullCount=%ld!\n", ++ QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); ++ } ++ ++ } while (FALSE); ++ ++ ++ return Status; ++} ++ ++ ++ ++NDIS_STATUS MlmeDataHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++#define MAX_DATAMM_RETRY 3 ++/* ++ ======================================================================== ++ ++ Routine Description: ++ API for MLME to transmit management frame to AP (BSS Mode) ++ or station (IBSS Mode) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the outgoing 802.11 frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MiniportDataMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length) ++{ ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ULONG FreeNum; ++ int retry = 0; ++ UCHAR IrqState; ++ UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; ++ ++ ASSERT(Length <= MGMT_DMA_BUFFER_SIZE); ++ ++ // 2860C use Tx Ring ++ IrqState = pAd->irq_disabled; ++ ++ do ++ { ++ // Reset is in progress, stop immediately ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)|| ++ !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ break; ++ } ++ ++ // Check Free priority queue ++ // Since we use PBF Queue2 for management frame. Its corresponding DMA ring should be using TxRing. ++ ++ // 2860C use Tx Ring ++ ++ // free Tx(QueIdx) resources ++ FreeNum = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ if ((FreeNum > 0)) ++ { ++ // We need to reserve space for rtmp hardware header. i.e., TxWI for RT2860 and TxInfo+TxWI for RT2870 ++ NdisZeroMemory(&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE)); ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, (PUCHAR)&rtmpHwHdr, (TXINFO_SIZE + TXWI_SIZE), pData, Length); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("MiniportMMRequest (error:: can't allocate NDIS PACKET)\n")); ++ break; ++ } ++ ++ //pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ //pAd->CommonCfg.MlmeRate = RATE_2; ++ ++ ++ Status = MlmeDataHardTransmit(pAd, QueIdx, pPacket); ++ if (Status != NDIS_STATUS_SUCCESS) ++ RTMPFreeNdisPacket(pAd, pPacket); ++ retry = MAX_DATAMM_RETRY; ++ } ++ else ++ { ++ retry ++; ++ ++ printk("retry %d\n", retry); ++ pAd->RalinkCounters.MgmtRingFullCount++; ++ ++ if (retry >= MAX_DATAMM_RETRY) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Qidx(%d), not enough space in DataRing, MgmtRingFullCount=%ld!\n", ++ QueIdx, pAd->RalinkCounters.MgmtRingFullCount)); ++ } ++ } ++ ++ } while (retry < MAX_DATAMM_RETRY); ++ ++ ++ return Status; ++} ++ ++ ++ ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware transmit function ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuffer Pointer to memory of outgoing frame ++ Length Size of outgoing management frame ++ ++ Return Value: ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_PENDING ++ NDIS_STATUS_SUCCESS ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS MlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++#ifdef CARRIER_DETECTION_SUPPORT ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); ++ ++} ++ ++NDIS_STATUS MlmeDataHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++#ifdef CARRIER_DETECTION_SUPPORT ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef RT2870 ++ return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); ++#endif // RT2870 // ++} ++ ++ ++ ++ ++ ++NDIS_STATUS MlmeHardTransmitMgmtRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PHEADER_802_11 pHeader_802_11; ++ BOOLEAN bAckRequired, bInsertTimestamp; ++ UCHAR MlmeRate; ++ PTXWI_STRUC pFirstTxWI; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ // Make sure MGMT ring resource won't be used by other threads ++// sample, for IRQ LOCK -> SEM LOCK ++// IrqState = pAd->irq_disabled; ++// if (!IrqState) ++ RTMP_SEM_LOCK(&pAd->MgmtRingLock); ++ ++ ++ if (pSrcBufVA == NULL) ++ { ++ // The buffer shouldn't be NULL ++// if (!IrqState) ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // outgoing frame always wakeup PHY to prevent frame lost ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pFirstTxWI = (PTXWI_STRUC)(pSrcBufVA + TXINFO_SIZE); ++ pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXINFO_SIZE + TXWI_SIZE); //TXWI_SIZE); ++ ++ if (pHeader_802_11->Addr1[0] & 0x01) ++ { ++ MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ } ++ else ++ { ++ MlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ // Verify Mlme rate for a / g bands. ++ if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band ++ MlmeRate = RATE_6; ++ ++ if ((pHeader_802_11->FC.Type == BTYPE_DATA) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) ++ { ++ pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Fixed W52 with Activity scan issue in ABG_MIXED and ABGN_MIXED mode. ++ if (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED ++#ifdef DOT11_N_SUPPORT ++ || pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ if (pAd->LatchRfRegs.Channel > 14) ++ pAd->CommonCfg.MlmeTransmit.field.MODE = 1; ++ else ++ pAd->CommonCfg.MlmeTransmit.field.MODE = 0; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE) ++ // Snice it's been set to 0 while on MgtMacHeaderInit ++ // By the way this will cause frame to be send on PWR_SAVE failed. ++ // ++ // pHeader_802_11->FC.PwrMgmt = 0; // (pAd->StaCfg.Psm == PWR_SAVE); ++ // ++ // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame ++#ifdef CONFIG_STA_SUPPORT ++ // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD ++ if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) ++ { ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && ++ (pHeader_802_11->FC.SubType == SUBTYPE_ACTION)) ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ bInsertTimestamp = FALSE; ++ if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL ++ { ++#ifdef CONFIG_STA_SUPPORT ++ //Set PM bit in ps-poll, to fix WLK 1.2 PowerSaveMode_ext failure issue. ++ if ((pAd->OpMode == OPMODE_STA) && (pHeader_802_11->FC.SubType == SUBTYPE_PS_POLL)) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ bAckRequired = FALSE; ++ } ++ else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame) ++ { ++ //pAd->Sequence++; ++ //pHeader_802_11->Sequence = pAd->Sequence; ++ ++ if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST ++ { ++ bAckRequired = FALSE; ++ pHeader_802_11->Duration = 0; ++ } ++ else ++ { ++ bAckRequired = TRUE; ++ pHeader_802_11->Duration = RTMPCalcDuration(pAd, MlmeRate, 14); ++ if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) ++ { ++ bInsertTimestamp = TRUE; ++ } ++ } ++ } ++ ++ pHeader_802_11->Sequence = pAd->Sequence++; ++ if (pAd->Sequence >0xfff) ++ pAd->Sequence = 0; ++ ++ // Before radar detection done, mgmt frame can not be sent but probe req ++ // Because we need to use probe req to trigger driver to send probe req in passive scan ++ if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("MlmeHardTransmit --> radar detect not in normal mode !!!\n")); ++// if (!IrqState) ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader_802_11, DIR_WRITE, FALSE); ++#endif ++ ++ // ++ // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET ++ // should always has only one ohysical buffer, and the whole frame size equals ++ // to the first scatter buffer size ++ // ++ ++ // Initialize TX Descriptor ++ // For inter-frame gap, the number is for this frame and next frame ++ // For MLME rate, we will fix as 2Mb to match other vendor's implement ++// pAd->CommonCfg.MlmeTransmit.field.MODE = 1; ++ ++// management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not. ++ if (pMacEntry == NULL) ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, RESERVED_WCID, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), PID_MGMT, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, ++ bInsertTimestamp, FALSE, bAckRequired, FALSE, ++ 0, pMacEntry->Aid, (SrcBufLen - TXINFO_SIZE - TXWI_SIZE), ++ pMacEntry->MaxHTPhyMode.field.MCS, 0, ++ (UCHAR)pMacEntry->MaxHTPhyMode.field.MCS, ++ IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pFirstTxWI, TYPE_TXWI); ++#endif ++ ++ // Now do hardware-depened kick out. ++ HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen); ++ ++ // Make sure to release MGMT ring resource ++// if (!IrqState) ++ RTMP_SEM_UNLOCK(&pAd->MgmtRingLock); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++/******************************************************************************** ++ ++ New DeQueue Procedures. ++ ++ ********************************************************************************/ ++ ++#define DEQUEUE_LOCK(lock, bIntContext, IrqFlags) \ ++ do{ \ ++ if (bIntContext == FALSE) \ ++ RTMP_IRQ_LOCK((lock), IrqFlags); \ ++ }while(0) ++ ++#define DEQUEUE_UNLOCK(lock, bIntContext, IrqFlags) \ ++ do{ \ ++ if (bIntContext == FALSE) \ ++ RTMP_IRQ_UNLOCK((lock), IrqFlags); \ ++ }while(0) ++ ++ ++/* ++ ======================================================================== ++ Tx Path design algorithm: ++ Basically, we divide the packets into four types, Broadcast/Multicast, 11N Rate(AMPDU, AMSDU, Normal), B/G Rate(ARALINK, Normal), ++ Specific Packet Type. Following show the classification rule and policy for each kinds of packets. ++ Classification Rule=> ++ Multicast: (*addr1 & 0x01) == 0x01 ++ Specific : bDHCPFrame, bARPFrame, bEAPOLFrame, etc. ++ 11N Rate : If peer support HT ++ (1).AMPDU -- If TXBA is negotiated. ++ (2).AMSDU -- If AMSDU is capable for both peer and ourself. ++ *). AMSDU can embedded in a AMPDU, but now we didn't support it. ++ (3).Normal -- Other packets which send as 11n rate. ++ ++ B/G Rate : If peer is b/g only. ++ (1).ARALINK-- If both of peer/us supprot Ralink proprietary Aggregation and the TxRate is large than RATE_6 ++ (2).Normal -- Other packets which send as b/g rate. ++ Fragment: ++ The packet must be unicast, NOT A-RALINK, NOT A-MSDU, NOT 11n, then can consider about fragment. ++ ++ Classified Packet Handle Rule=> ++ Multicast: ++ No ACK, //pTxBlk->bAckRequired = FALSE; ++ No WMM, //pTxBlk->bWMM = FALSE; ++ No piggyback, //pTxBlk->bPiggyBack = FALSE; ++ Force LowRate, //pTxBlk->bForceLowRate = TRUE; ++ Specific : Basically, for specific packet, we should handle it specifically, but now all specific packets are use ++ the same policy to handle it. ++ Force LowRate, //pTxBlk->bForceLowRate = TRUE; ++ ++ 11N Rate : ++ No piggyback, //pTxBlk->bPiggyBack = FALSE; ++ ++ (1).AMSDU ++ pTxBlk->bWMM = TRUE; ++ (2).AMPDU ++ pTxBlk->bWMM = TRUE; ++ (3).Normal ++ ++ B/G Rate : ++ (1).ARALINK ++ ++ (2).Normal ++ ======================================================================== ++*/ ++static UCHAR TxPktClassification( ++ IN RTMP_ADAPTER *pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ UCHAR TxFrameType = TX_UNKOWN_FRAME; ++ UCHAR Wcid; ++ MAC_TABLE_ENTRY *pMacEntry = NULL; ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bHTRate = FALSE; ++#endif // DOT11_N_SUPPORT // ++ ++ Wcid = RTMP_GET_PACKET_WCID(pPacket); ++ if (Wcid == MCAST_WCID) ++ { // Handle for RA is Broadcast/Multicast Address. ++ return TX_MCAST_FRAME; ++ } ++ ++ // Handle for unicast packets ++ pMacEntry = &pAd->MacTab.Content[Wcid]; ++ if (RTMP_GET_PACKET_LOWRATE(pPacket)) ++ { // It's a specific packet need to force low rate, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++#ifdef DOT11_N_SUPPORT ++ else if (IS_HT_RATE(pMacEntry)) ++ { // it's a 11n capable packet ++ ++ // Depends on HTPhyMode to check if the peer support the HTRate transmission. ++ // Currently didn't support A-MSDU embedded in A-MPDU ++ bHTRate = TRUE; ++ if (RTMP_GET_PACKET_MOREDATA(pPacket) || (pMacEntry->PsMode == PWR_SAVE)) ++ TxFrameType = TX_LEGACY_FRAME; ++#ifdef UAPSD_AP_SUPPORT ++ else if (RTMP_GET_PACKET_EOSP(pPacket)) ++ TxFrameType = TX_LEGACY_FRAME; ++#endif // UAPSD_AP_SUPPORT // ++ else if((pMacEntry->TXBAbitmap & (1<<(RTMP_GET_PACKET_UP(pPacket)))) != 0) ++ return TX_AMPDU_FRAME; ++ else if(CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AMSDU_INUSED)) ++ return TX_AMSDU_FRAME; ++ else ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++#endif // DOT11_N_SUPPORT // ++ else ++ { // it's a legacy b/g packet. ++ if ((CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE) && pAd->CommonCfg.bAggregationCapable) && ++ (RTMP_GET_PACKET_TXRATE(pPacket) >= RATE_6) && ++ (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) ++ { // if peer support Ralink Aggregation, we use it. ++ TxFrameType = TX_RALINK_FRAME; ++ } ++ else ++ { ++ TxFrameType = TX_LEGACY_FRAME; ++ } ++ } ++ ++ // Currently, our fragment only support when a unicast packet send as NOT-ARALINK, NOT-AMSDU and NOT-AMPDU. ++ if ((RTMP_GET_PACKET_FRAGMENTS(pPacket) > 1) && (TxFrameType == TX_LEGACY_FRAME)) ++ TxFrameType = TX_FRAG_FRAME; ++ ++ return TxFrameType; ++} ++ ++ ++BOOLEAN RTMP_FillTxBlkInfo( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PACKET_INFO PacketInfo; ++ PNDIS_PACKET pPacket; ++ PMAC_TABLE_ENTRY pMacEntry = NULL; ++ ++ pPacket = pTxBlk->pPacket; ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); ++ ++ pTxBlk->Wcid = RTMP_GET_PACKET_WCID(pPacket); ++ pTxBlk->apidx = RTMP_GET_PACKET_IF(pPacket); ++ pTxBlk->UserPriority = RTMP_GET_PACKET_UP(pPacket); ++ pTxBlk->FrameGap = IFS_HTTXOP; // ASIC determine Frame Gap ++ ++ if (RTMP_GET_PACKET_CLEAR_EAP_FRAME(pTxBlk->pPacket)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bClearEAPFrame); ++ else ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bClearEAPFrame); ++ ++ // Default to clear this flag ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bForceNonQoS); ++ ++ ++ if (pTxBlk->Wcid == MCAST_WCID) ++ { ++ pTxBlk->pMacEntry = NULL; ++ { ++#ifdef MCAST_RATE_SPECIFIC ++ PUCHAR pDA = GET_OS_PKT_DATAPTR(pPacket); ++ if (((*pDA & 0x01) == 0x01) && (*pDA != 0xff)) ++ pTxBlk->pTransmit = &pAd->CommonCfg.MCastPhyMode; ++ else ++#endif // MCAST_RATE_SPECIFIC // ++ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; ++ } ++ ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); // AckRequired = FALSE, when broadcast packet in Adhoc mode. ++ //TX_BLK_SET_FLAG(pTxBlk, fTX_bForceLowRate); ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAllowFrag); ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); ++ if (RTMP_GET_PACKET_MOREDATA(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); ++ } ++ ++ } ++ else ++ { ++ pTxBlk->pMacEntry = &pAd->MacTab.Content[pTxBlk->Wcid]; ++ pTxBlk->pTransmit = &pTxBlk->pMacEntry->HTPhyMode; ++ ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ ++ // For all unicast packets, need Ack unless the Ack Policy is not set as NORMAL_ACK. ++ if (pAd->CommonCfg.AckPolicy[pTxBlk->QueIdx] != NORMAL_ACK) ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bAckRequired); ++ else ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bAckRequired); ++ ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ // If support WMM, enable it. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM); ++ ++// if (pAd->StaCfg.bAutoTxRateSwitch) ++// TX_BLK_SET_FLAG(pTxBlk, fTX_AutoRateSwitch); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if (pTxBlk->TxFrameType == TX_LEGACY_FRAME) ++ { ++ if ( (RTMP_GET_PACKET_LOWRATE(pPacket)) || ++ ((pAd->OpMode == OPMODE_AP) && (pMacEntry->MaxHTPhyMode.field.MODE == MODE_CCK) && (pMacEntry->MaxHTPhyMode.field.MCS == RATE_1))) ++ { // Specific packet, i.e., bDHCPFrame, bEAPOLFrame, bWAIFrame, need force low rate. ++ pTxBlk->pTransmit = &pAd->MacTab.Content[MCAST_WCID].HTPhyMode; ++#ifdef DOT11_N_SUPPORT ++ // Modify the WMM bit for ICV issue. If we have a packet with EOSP field need to set as 1, how to handle it??? ++ if (IS_HT_STA(pTxBlk->pMacEntry) && ++ (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RALINK_CHIPSET)) && ++ ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))) ++ { ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bWMM); ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bForceNonQoS); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ( (IS_HT_RATE(pMacEntry) == FALSE) && ++ (CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE))) ++ { // Currently piggy-back only support when peer is operate in b/g mode. ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bPiggyBack); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (RTMP_GET_PACKET_MOREDATA(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bMoreData); ++ } ++#ifdef UAPSD_AP_SUPPORT ++ if (RTMP_GET_PACKET_EOSP(pPacket)) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bWMM_UAPSD_EOSP); ++ } ++#endif // UAPSD_AP_SUPPORT // ++ } ++ else if (pTxBlk->TxFrameType == TX_FRAG_FRAME) ++ { ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bAllowFrag); ++ } ++ ++ pMacEntry->DebugTxCount++; ++ } ++ ++ return TRUE; ++ ++FillTxBlkErr: ++ return FALSE; ++} ++ ++ ++BOOLEAN CanDoAggregateTransmit( ++ IN RTMP_ADAPTER *pAd, ++ IN NDIS_PACKET *pPacket, ++ IN TX_BLK *pTxBlk) ++{ ++ ++ //printk("Check if can do aggregation! TxFrameType=%d!\n", pTxBlk->TxFrameType); ++ ++ if (RTMP_GET_PACKET_WCID(pPacket) == MCAST_WCID) ++ return FALSE; ++ ++ if (RTMP_GET_PACKET_DHCP(pPacket) || ++ RTMP_GET_PACKET_EAPOL(pPacket) || ++ RTMP_GET_PACKET_WAI(pPacket)) ++ return FALSE; ++ ++ if ((pTxBlk->TxFrameType == TX_AMSDU_FRAME) && ++ ((pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))> (RX_BUFFER_AGGRESIZE - 100))) ++ { // For AMSDU, allow the packets with total length < max-amsdu size ++ return FALSE; ++ } ++ ++ if ((pTxBlk->TxFrameType == TX_RALINK_FRAME) && ++ (pTxBlk->TxPacketList.Number == 2)) ++ { // For RALINK-Aggregation, allow two frames in one batch. ++ return FALSE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) // must be unicast to AP ++ return TRUE; ++ else ++#endif // CONFIG_STA_SUPPORT // ++ return FALSE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ To do the enqueue operation and extract the first item of waiting ++ list. If a number of available shared memory segments could meet ++ the request of extracted item, the extracted item will be fragmented ++ into shared memory segments. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pQueue Pointer to Waiting Queue ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPDeQueuePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bIntContext, ++ IN UCHAR QIdx, /* BulkOutPipeId */ ++ IN UCHAR Max_Tx_Packets) ++{ ++ PQUEUE_ENTRY pEntry = NULL; ++ PNDIS_PACKET pPacket; ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ UCHAR Count=0; ++ PQUEUE_HEADER pQueue; ++ ULONG FreeNumber[NUM_OF_TX_RING]; ++ UCHAR QueIdx, sQIdx, eQIdx; ++ unsigned long IrqFlags = 0; ++ BOOLEAN hasTxDesc = FALSE; ++ TX_BLK TxBlk; ++ TX_BLK *pTxBlk; ++ ++#ifdef DBG_DIAGNOSE ++ BOOLEAN firstRound; ++ RtmpDiagStruct *pDiagStruct = &pAd->DiagStruct; ++#endif ++ ++ ++ if (QIdx == NUM_OF_TX_RING) ++ { ++ sQIdx = 0; ++//PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ eQIdx = 3; // 4 ACs, start from 0. ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ sQIdx = eQIdx = QIdx; ++ } ++ ++ for (QueIdx=sQIdx; QueIdx <= eQIdx; QueIdx++) ++ { ++ Count=0; ++ ++ RT28XX_START_DEQUEUE(pAd, QueIdx, IrqFlags); ++ ++#ifdef DBG_DIAGNOSE ++ firstRound = ((QueIdx == 0) ? TRUE : FALSE); ++#endif // DBG_DIAGNOSE // ++ ++ while (1) ++ { ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST)))) ++ { ++ RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); ++ return; ++ } ++ ++ if (Count >= Max_Tx_Packets) ++ break; ++ ++ DEQUEUE_LOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ if (&pAd->TxSwQueue[QueIdx] == NULL) ++ { ++#ifdef DBG_DIAGNOSE ++ if (firstRound == TRUE) ++ pDiagStruct->TxSWQueCnt[pDiagStruct->ArrayCurIdx][0]++; ++#endif // DBG_DIAGNOSE // ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ ++ // probe the Queue Head ++ pQueue = &pAd->TxSwQueue[QueIdx]; ++ if ((pEntry = pQueue->Head) == NULL) ++ { ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ pTxBlk = &TxBlk; ++ NdisZeroMemory((PUCHAR)pTxBlk, sizeof(TX_BLK)); ++ //InitializeQueueHeader(&pTxBlk->TxPacketList); // Didn't need it because we already memzero it. ++ pTxBlk->QueIdx = QueIdx; ++ ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ ++ // Early check to make sure we have enoguh Tx Resource. ++ hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); ++ if (!hasTxDesc) ++ { ++ pAd->PrivateInfo.TxRingFullCnt++; ++ ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ ++ break; ++ } ++ ++ pTxBlk->TxFrameType = TxPktClassification(pAd, pPacket); ++ pEntry = RemoveHeadQueue(pQueue); ++ pTxBlk->TotalFrameNum++; ++ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary ++ pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); ++ pTxBlk->pPacket = pPacket; ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ ++ if (pTxBlk->TxFrameType == TX_RALINK_FRAME || pTxBlk->TxFrameType == TX_AMSDU_FRAME) ++ { ++ // Enhance SW Aggregation Mechanism ++ if (NEED_QUEUE_BACK_FOR_AGG(pAd, QueIdx, FreeNumber[QueIdx], pTxBlk->TxFrameType)) ++ { ++ InsertHeadQueue(pQueue, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++ break; ++ } ++ ++ do{ ++ if((pEntry = pQueue->Head) == NULL) ++ break; ++ ++ // For TX_AMSDU_FRAME/TX_RALINK_FRAME, Need to check if next pakcet can do aggregation. ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); ++ hasTxDesc = RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, FreeNumber[QueIdx], pPacket); ++ if ((hasTxDesc == FALSE) || (CanDoAggregateTransmit(pAd, pPacket, pTxBlk) == FALSE)) ++ break; ++ ++ //Remove the packet from the TxSwQueue and insert into pTxBlk ++ pEntry = RemoveHeadQueue(pQueue); ++ ASSERT(pEntry); ++ pPacket = QUEUE_ENTRY_TO_PKT(pEntry); ++ pTxBlk->TotalFrameNum++; ++ pTxBlk->TotalFragNum += RTMP_GET_PACKET_FRAGMENTS(pPacket); // The real fragment number maybe vary ++ pTxBlk->TotalFrameLen += GET_OS_PKT_LEN(pPacket); ++ InsertTailQueue(&pTxBlk->TxPacketList, PACKET_TO_QUEUE_ENTRY(pPacket)); ++ }while(1); ++ ++ if (pTxBlk->TxPacketList.Number == 1) ++ pTxBlk->TxFrameType = TX_LEGACY_FRAME; ++ } ++ ++#ifdef RT2870 ++ DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); ++#endif // RT2870 // ++ ++ Count += pTxBlk->TxPacketList.Number; ++ ++ // Do HardTransmit now. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ Status = STAHardTransmit(pAd, pTxBlk, QueIdx); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); ++ ++#ifdef RT2870 ++ if (!hasTxDesc) ++ RTUSBKickBulkOut(pAd); ++#endif // RT2870 // ++ ++#ifdef BLOCK_NET_IF ++ if ((pAd->blockQueueTab[QueIdx].SwTxQueueBlockFlag == TRUE) ++ && (pAd->TxSwQueue[QueIdx].Number < 1)) ++ { ++ releaseNetIf(&pAd->blockQueueTab[QueIdx]); ++ } ++#endif // BLOCK_NET_IF // ++ ++ } ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Rate Transmit rate ++ Size Frame size in units of byte ++ ++ Return Value: ++ Duration number in units of usec ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++USHORT RTMPCalcDuration( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Rate, ++ IN ULONG Size) ++{ ++ ULONG Duration = 0; ++ ++ if (Rate < RATE_FIRST_OFDM_RATE) // CCK ++ { ++ if ((Rate > RATE_1) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED)) ++ Duration = 96; // 72+24 preamble+plcp ++ else ++ Duration = 192; // 144+48 preamble+plcp ++ ++ Duration += (USHORT)((Size << 4) / RateIdTo500Kbps[Rate]); ++ if ((Size << 4) % RateIdTo500Kbps[Rate]) ++ Duration ++; ++ } ++ else if (Rate <= RATE_LAST_OFDM_RATE)// OFDM rates ++ { ++ Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension ++ Duration += 4 * (USHORT)((11 + Size * 4) / RateIdTo500Kbps[Rate]); ++ if ((11 + Size * 4) % RateIdTo500Kbps[Rate]) ++ Duration += 4; ++ } ++ else //mimo rate ++ { ++ Duration = 20 + 6; // 16+4 preamble+plcp + Signal Extension ++ } ++ ++ return (USHORT)Duration; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pTxWI Pointer to head of each MPDU to HW. ++ Ack Setting for Ack requirement bit ++ Fragment Setting for Fragment bit ++ RetryMode Setting for retry mode ++ Ifs Setting for IFS gap ++ Rate Setting for transmit rate ++ Service Setting for service ++ Length Frame length ++ TxPreamble Short or Long preamble when using CCK rates ++ QueIdx - 0-3, according to 802.11e/d4.4 June/2003 ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ See also : BASmartHardTransmit() !!! ++ ++ ======================================================================== ++*/ ++VOID RTMPWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pOutTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit) ++{ ++ PMAC_TABLE_ENTRY pMac = NULL; ++ TXWI_STRUC TxWI; ++ PTXWI_STRUC pTxWI; ++ ++ if (WCID < MAX_LEN_OF_MAC_TABLE) ++ pMac = &pAd->MacTab.Content[WCID]; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(&TxWI, TXWI_SIZE); ++ pTxWI = &TxWI; ++ ++ pTxWI->FRAG= FRAG; ++ ++ pTxWI->CFACK = CFACK; ++ pTxWI->TS= InsTimestamp; ++ pTxWI->AMPDU = AMPDU; ++ pTxWI->ACK = Ack; ++ pTxWI->txop= Txopmode; ++ ++ pTxWI->NSEQ = NSeq; ++ // John tune the performace with Intel Client in 20 MHz performance ++#ifdef DOT11_N_SUPPORT ++ BASize = pAd->CommonCfg.TxBASize; ++ ++ if( BASize >7 ) ++ BASize =7; ++ pTxWI->BAWinSize = BASize; ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->WirelessCliID = WCID; ++ pTxWI->MPDUtotalByteCount = Length; ++ pTxWI->PacketId = PID; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ pTxWI->CFACK = CfAck; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pMac) ++ { ++ if (pAd->CommonCfg.bMIMOPSEnable) ++ { ++ if ((pMac->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMac->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ } ++ //pTxWI->MIMOps = (pMac->PsMode == PWR_MMPS)? 1:0; ++ if (pMac->bIAmBadAtheros && (pMac->WepStatus != Ndis802_11WEPDisabled)) ++ { ++ pTxWI->MpduDensity = 7; ++ } ++ else ++ { ++ pTxWI->MpduDensity = pMac->MpduDensity; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->PacketId = pTxWI->MCS; ++ NdisMoveMemory(pOutTxWI, &TxWI, sizeof(TXWI_STRUC)); ++} ++ ++ ++VOID RTMPWriteTxWI_Data( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk) ++{ ++ HTTRANSMIT_SETTING *pTransmit; ++ PMAC_TABLE_ENTRY pMacEntry; ++#ifdef DOT11_N_SUPPORT ++ UCHAR BASize; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ ASSERT(pTxWI); ++ ++ pTransmit = pTxBlk->pTransmit; ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ NdisZeroMemory(pTxWI, TXWI_SIZE); ++ ++ pTxWI->FRAG = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag); ++ pTxWI->ACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bAckRequired); ++ pTxWI->txop = pTxBlk->FrameGap; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (pMacEntry && ++ (pAd->StaCfg.BssType == BSS_INFRA) && ++ (pMacEntry->ValidAsDls == TRUE)) ++ pTxWI->WirelessCliID = BSSID_WCID; ++ else ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ pTxWI->WirelessCliID = pTxBlk->Wcid; ++ ++ pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ pTxWI->CFACK = TX_BLK_TEST_FLAG(pTxBlk, fTX_bPiggyBack); ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ pTxWI->AMPDU = ((pTxBlk->TxFrameType == TX_AMPDU_FRAME) ? TRUE : FALSE); ++ ++ // John tune the performace with Intel Client in 20 MHz performance ++ BASize = pAd->CommonCfg.TxBASize; ++ if((pTxBlk->TxFrameType == TX_AMPDU_FRAME) && (pMacEntry)) ++ { ++ UCHAR RABAOriIdx = 0; //The RA's BA Originator table index. ++ ++ RABAOriIdx = pTxBlk->pMacEntry->BAOriWcidArray[pTxBlk->UserPriority]; ++ BASize = pAd->BATable.BAOriEntry[RABAOriIdx].BAWinSize; ++ } ++ ++ pTxWI->TxBF = pTransmit->field.TxBF; ++ pTxWI->BAWinSize = BASize; ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pMacEntry) ++ { ++ if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMacEntry->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if (pTransmit->field.MODE >= MODE_HTMIX && pTransmit->field.MCS > 7) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ ++ if (pMacEntry->bIAmBadAtheros && (pMacEntry->WepStatus != Ndis802_11WEPDisabled)) ++ { ++ pTxWI->MpduDensity = 7; ++ } ++ else ++ { ++ pTxWI->MpduDensity = pMacEntry->MpduDensity; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DBG_DIAGNOSE ++ if (pTxBlk->QueIdx== 0) ++ { ++ pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; ++ pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ // for rate adapation ++ pTxWI->PacketId = pTxWI->MCS; ++#ifdef INF_AMAZON_SE ++/*Iverson patch for WMM A5-T07 ,WirelessStaToWirelessSta do not bulk out aggregate */ ++ if( RTMP_GET_PACKET_NOBULKOUT(pTxBlk->pPacket)) ++ { ++ if(pTxWI->PHYMODE == MODE_CCK) ++ { ++ pTxWI->PacketId = 6; ++ } ++ } ++#endif // INF_AMAZON_SE // ++} ++ ++ ++VOID RTMPWriteTxWI_Cache( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk) ++{ ++ PHTTRANSMIT_SETTING /*pTxHTPhyMode,*/ pTransmit; ++ PMAC_TABLE_ENTRY pMacEntry; ++ ++ // ++ // update TXWI ++ // ++ pMacEntry = pTxBlk->pMacEntry; ++ pTransmit = pTxBlk->pTransmit; ++ ++ //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) ++ //if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pMacEntry)) ++ //if (TX_BLK_TEST_FLAG(pTxBlk, fTX_AutoRateSwitch)) ++ if (pMacEntry->bAutoTxRateSwitch) ++ { ++ pTxWI->txop = IFS_HTTXOP; ++ ++ // If CCK or OFDM, BW must be 20 ++ pTxWI->BW = (pTransmit->field.MODE <= MODE_OFDM) ? (BW_20) : (pTransmit->field.BW); ++ pTxWI->ShortGI = pTransmit->field.ShortGI; ++ pTxWI->STBC = pTransmit->field.STBC; ++ ++ pTxWI->MCS = pTransmit->field.MCS; ++ pTxWI->PHYMODE = pTransmit->field.MODE; ++ ++ // set PID for TxRateSwitching ++ pTxWI->PacketId = pTransmit->field.MCS; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ pTxWI->AMPDU = ((pMacEntry->NoBADataCountDown == 0) ? TRUE: FALSE); ++ pTxWI->MIMOps = 0; ++ ++#ifdef DOT11N_DRAFT3 ++ if (pTxWI->BW) ++ pTxWI->BW = (pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth == 0) ? (BW_20) : (pTransmit->field.BW); ++#endif // DOT11N_DRAFT3 // ++ ++ if (pAd->CommonCfg.bMIMOPSEnable) ++ { ++ // MIMO Power Save Mode ++ if ((pMacEntry->MmpsMode == MMPS_DYNAMIC) && (pTransmit->field.MCS > 7)) ++ { ++ // Dynamic MIMO Power Save Mode ++ pTxWI->MIMOps = 1; ++ } ++ else if (pMacEntry->MmpsMode == MMPS_STATIC) ++ { ++ // Static MIMO Power Save Mode ++ if ((pTransmit->field.MODE >= MODE_HTMIX) && (pTransmit->field.MCS > 7)) ++ { ++ pTxWI->MCS = 7; ++ pTxWI->MIMOps = 0; ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DBG_DIAGNOSE ++ if (pTxBlk->QueIdx== 0) ++ { ++ pAd->DiagStruct.TxDataCnt[pAd->DiagStruct.ArrayCurIdx]++; ++ pAd->DiagStruct.TxMcsCnt[pAd->DiagStruct.ArrayCurIdx][pTxWI->MCS]++; ++ } ++#endif // DBG_DIAGNOSE // ++ ++ pTxWI->MPDUtotalByteCount = pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculates the duration which is required to transmit out frames ++ with given size and specified rate. ++ ++ Arguments: ++ pTxD Pointer to transmit descriptor ++ Ack Setting for Ack requirement bit ++ Fragment Setting for Fragment bit ++ RetryMode Setting for retry mode ++ Ifs Setting for IFS gap ++ Rate Setting for transmit rate ++ Service Setting for service ++ Length Frame length ++ TxPreamble Short or Long preamble when using CCK rates ++ QueIdx - 0-3, according to 802.11e/d4.4 June/2003 ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPWriteTxDescriptor( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXD_STRUC pTxD, ++ IN BOOLEAN bWIV, ++ IN UCHAR QueueSEL) ++{ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ ++ pTxD->WIV = (bWIV) ? 1: 0; ++ pTxD->QSEL= (QueueSEL); ++ if (pAd->bGenOneHCCA == TRUE) ++ pTxD->QSEL= FIFO_HCCA; ++ pTxD->DMADONE = 0; ++} ++ ++ ++// should be called only when - ++// 1. MEADIA_CONNECTED ++// 2. AGGREGATION_IN_USED ++// 3. Fragmentation not in used ++// 4. either no previous frame (pPrevAddr1=NULL) .OR. previoud frame is aggregatible ++BOOLEAN TxFrameIsAggregatible( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pPrevAddr1, ++ IN PUCHAR p8023hdr) ++{ ++ ++ // can't aggregate EAPOL (802.1x) frame ++ if ((p8023hdr[12] == 0x88) && (p8023hdr[13] == 0x8e)) ++ return FALSE; ++ ++ // can't aggregate multicast/broadcast frame ++ if (p8023hdr[0] & 0x01) ++ return FALSE; ++ ++ if (INFRA_ON(pAd)) // must be unicast to AP ++ return TRUE; ++ else if ((pPrevAddr1 == NULL) || MAC_ADDR_EQUAL(pPrevAddr1, p8023hdr)) // unicast to same STA ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check the MSDU Aggregation policy ++ 1.HT aggregation is A-MSDU ++ 2.legaacy rate aggregation is software aggregation by Ralink. ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN PeerIsAggreOn( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG TxRate, ++ IN PMAC_TABLE_ENTRY pMacEntry) ++{ ++ ULONG AFlags = (fCLIENT_STATUS_AMSDU_INUSED | fCLIENT_STATUS_AGGREGATION_CAPABLE); ++ ++ if (pMacEntry != NULL && CLIENT_STATUS_TEST_FLAG(pMacEntry, AFlags)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++ { ++ return TRUE; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ if (TxRate >= RATE_6 && pAd->CommonCfg.bAggregationCapable && (!(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && CLIENT_STATUS_TEST_FLAG(pMacEntry, fCLIENT_STATUS_WMM_CAPABLE)))) ++ { // legacy Ralink Aggregation support ++ return TRUE; ++ } ++#endif // AGGREGATION_SUPPORT // ++ } ++ ++ return FALSE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check and fine the packet waiting in SW queue with highest priority ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ pQueue Pointer to Waiting Queue ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++PQUEUE_HEADER RTMPCheckTxSwQueue( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pQueIdx) ++{ ++ ++ ULONG Number; ++ // 2004-11-15 to be removed. test aggregation only ++// if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) && (*pNumber < 2)) ++// return NULL; ++ ++ Number = pAd->TxSwQueue[QID_AC_BK].Number ++ + pAd->TxSwQueue[QID_AC_BE].Number ++ + pAd->TxSwQueue[QID_AC_VI].Number ++ + pAd->TxSwQueue[QID_AC_VO].Number ++ + pAd->TxSwQueue[QID_HCCA].Number; ++ ++ if (pAd->TxSwQueue[QID_AC_VO].Head != NULL) ++ { ++ *pQueIdx = QID_AC_VO; ++ return (&pAd->TxSwQueue[QID_AC_VO]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_VI].Head != NULL) ++ { ++ *pQueIdx = QID_AC_VI; ++ return (&pAd->TxSwQueue[QID_AC_VI]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_BE].Head != NULL) ++ { ++ *pQueIdx = QID_AC_BE; ++ return (&pAd->TxSwQueue[QID_AC_BE]); ++ } ++ else if (pAd->TxSwQueue[QID_AC_BK].Head != NULL) ++ { ++ *pQueIdx = QID_AC_BK; ++ return (&pAd->TxSwQueue[QID_AC_BK]); ++ } ++ else if (pAd->TxSwQueue[QID_HCCA].Head != NULL) ++ { ++ *pQueIdx = QID_HCCA; ++ return (&pAd->TxSwQueue[QID_HCCA]); ++ } ++ ++ // No packet pending in Tx Sw queue ++ *pQueIdx = QID_AC_BK; ++ ++ return (NULL); ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Suspend MSDU transmission ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("SCANNING, suspend MSDU transmission ...\n")); ++ ++ ++ // ++ // Before BSS_SCAN_IN_PROGRESS, we need to keep Current R66 value and ++ // use Lowbound as R66 value on ScanNextChannel(...) ++ // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); ++ ++ // set BBP_R66 to 0x30/0x40 when scanning (AsicSwitchChannel will set R66 according to channel when scanning) ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x26 + GET_LNA_GAIN(pAd))); ++ RTMPSetAGCInitValue(pAd, BW_20); ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x000f0000); // abort all TX rings ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Resume MSDU transmission ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd) ++{ ++// UCHAR IrqState; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SCAN done, resume MSDU transmission ...\n")); ++ ++ ++ // After finish BSS_SCAN_IN_PROGRESS, we need to restore Current R66 value ++ // R66 should not be 0 ++ if (pAd->BbpTuning.R66CurrentValue == 0) ++ { ++ pAd->BbpTuning.R66CurrentValue = 0x38; ++ DBGPRINT_ERR(("RTMPResumeMsduTransmission, R66CurrentValue=0...\n")); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, pAd->BbpTuning.R66CurrentValue); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++// sample, for IRQ LOCK to SEM LOCK ++// IrqState = pAd->irq_disabled; ++// if (IrqState) ++// RTMPDeQueuePacket(pAd, TRUE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++// else ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++} ++ ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ USHORT PayloadSize; ++ USHORT SubFrameSize; ++ PHEADER_802_3 pAMSDUsubheader; ++ UINT nMSDU; ++ UCHAR Header802_3[14]; ++ ++ PUCHAR pPayload, pDA, pSA, pRemovedLLCSNAP; ++ PNDIS_PACKET pClonePacket; ++ ++ ++ ++ nMSDU = 0; ++ ++ while (DataSize > LENGTH_802_3) ++ { ++ ++ nMSDU++; ++ ++ //hex_dump("subheader", pData, 64); ++ pAMSDUsubheader = (PHEADER_802_3)pData; ++ //pData += LENGTH_802_3; ++ PayloadSize = pAMSDUsubheader->Octet[1] + (pAMSDUsubheader->Octet[0]<<8); ++ SubFrameSize = PayloadSize + LENGTH_802_3; ++ ++ ++ if ((DataSize < SubFrameSize) || (PayloadSize > 1518 )) ++ { ++ break; ++ } ++ ++ //printk("%d subframe: Size = %d\n", nMSDU, PayloadSize); ++ ++ pPayload = pData + LENGTH_802_3; ++ pDA = pData; ++ pSA = pData + MAC_ADDR_LEN; ++ ++ // convert to 802.3 header ++ CONVERT_TO_802_3(Header802_3, pDA, pSA, pPayload, PayloadSize, pRemovedLLCSNAP); ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((Header802_3[12] == 0x88) && (Header802_3[13] == 0x8E) ) ++ { ++ // avoid local heap overflow, use dyanamic allocation ++ MLME_QUEUE_ELEM *Elem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ memmove(Elem->Msg+(LENGTH_802_11 + LENGTH_802_1_H), pPayload, PayloadSize); ++ Elem->MsgLen = LENGTH_802_11 + LENGTH_802_1_H + PayloadSize; ++ WpaEAPOLKeyAction(pAd, Elem); ++ kfree(Elem); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pRemovedLLCSNAP) ++ { ++ pPayload -= LENGTH_802_3; ++ PayloadSize += LENGTH_802_3; ++ NdisMoveMemory(pPayload, &Header802_3[0], LENGTH_802_3); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pClonePacket = ClonePacket(pAd, pPacket, pPayload, PayloadSize); ++ if (pClonePacket) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pClonePacket, RTMP_GET_PACKET_IF(pPacket)); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ // A-MSDU has padding to multiple of 4 including subframe header. ++ // align SubFrameSize up to multiple of 4 ++ SubFrameSize = (SubFrameSize+3)&(~0x3); ++ ++ ++ if (SubFrameSize > 1528 || SubFrameSize < 32) ++ { ++ break; ++ } ++ ++ if (DataSize > SubFrameSize) ++ { ++ pData += SubFrameSize; ++ DataSize -= SubFrameSize; ++ } ++ else ++ { ++ // end of A-MSDU ++ DataSize = 0; ++ } ++ } ++ ++ // finally release original rx packet ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS); ++ ++ return nMSDU; ++} ++ ++ ++UINT BA_Reorder_AMSDU_Annnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PUCHAR pData; ++ USHORT DataSize; ++ UINT nMSDU = 0; ++ ++ pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); ++ DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); ++ ++ nMSDU = deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); ++ ++ return nMSDU; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Look up the MAC address in the MAC table. Return NULL if not found. ++ Return: ++ pEntry - pointer to the MAC entry; NULL is not found ++ ========================================================================== ++*/ ++MAC_TABLE_ENTRY *MacTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ PUCHAR pAddr) ++{ ++ ULONG HashIdx; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = pAd->MacTab.Hash[HashIdx]; ++ ++ while (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsWDS || pEntry->ValidAsApCli || pEntry->ValidAsMesh)) ++ { ++ if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ break; ++ } ++ else ++ pEntry = pEntry->pNext; ++ } ++ ++ return pEntry; ++} ++ ++MAC_TABLE_ENTRY *MacTableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR apidx, ++ IN BOOLEAN CleanAll) ++{ ++ UCHAR HashIdx; ++ int i, FirstWcid; ++ MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; ++// USHORT offset; ++// ULONG addr; ++ ++ // if FULL, return ++ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) ++ return NULL; ++ ++ FirstWcid = 1; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ FirstWcid = 2; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // allocate one MAC entry ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ for (i = FirstWcid; i< MAX_LEN_OF_MAC_TABLE; i++) // skip entry#0 so that "entry index == AID" for fast lookup ++ { ++ // pick up the first available vacancy ++ if ((pAd->MacTab.Content[i].ValidAsCLI == FALSE) && ++ (pAd->MacTab.Content[i].ValidAsWDS == FALSE) && ++ (pAd->MacTab.Content[i].ValidAsApCli== FALSE) && ++ (pAd->MacTab.Content[i].ValidAsMesh == FALSE) ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ && (pAd->MacTab.Content[i].ValidAsDls == FALSE) ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ if (CleanAll == TRUE) ++ { ++ pEntry->MaxSupportedRate = RATE_11; ++ pEntry->CurrTxRate = RATE_11; ++ NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); ++ pEntry->PairwiseKey.KeyLen = 0; ++ pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; ++ } ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (apidx >= MIN_NET_DEVICE_FOR_DLS) ++ { ++ pEntry->ValidAsCLI = FALSE; ++ pEntry->ValidAsWDS = FALSE; ++ pEntry->ValidAsApCli = FALSE; ++ pEntry->ValidAsMesh = FALSE; ++ pEntry->ValidAsDls = TRUE; ++ pEntry->isCached = FALSE; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry->ValidAsCLI = TRUE; ++ pEntry->ValidAsWDS = FALSE; ++ pEntry->ValidAsApCli = FALSE; ++ pEntry->ValidAsMesh = FALSE; ++ pEntry->ValidAsDls = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ pEntry->bIAmBadAtheros = FALSE; ++ pEntry->pAd = pAd; ++ pEntry->CMTimerRunning = FALSE; ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ pEntry->RSNIE_Len = 0; ++ NdisZeroMemory(pEntry->R_Counter, sizeof(pEntry->R_Counter)); ++ pEntry->ReTryCounter = PEER_MSG1_RETRY_TIMER_CTR; ++ ++ if (pEntry->ValidAsMesh) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_MESH); ++ else if (pEntry->ValidAsApCli) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_APCLI); ++ else if (pEntry->ValidAsWDS) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_WDS); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ else if (pEntry->ValidAsDls) ++ pEntry->apidx = (apidx - MIN_NET_DEVICE_FOR_DLS); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ else ++ pEntry->apidx = apidx; ++ ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ pEntry->GTKState = REKEY_NEGOTIATING; ++ pEntry->PairwiseKey.KeyLen = 0; ++ pEntry->PairwiseKey.CipherAlg = CIPHER_NONE; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry->ValidAsDls == TRUE) ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ else ++#endif //QOS_DLS_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ pEntry->PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pEntry->PMKID_CacheIdx = ENTRY_NOT_FOUND; ++ COPY_MAC_ADDR(pEntry->Addr, pAddr); ++ pEntry->Sst = SST_NOT_AUTH; ++ pEntry->AuthState = AS_NOT_AUTH; ++ pEntry->Aid = (USHORT)i; //0; ++ pEntry->CapabilityInfo = 0; ++ pEntry->PsMode = PWR_ACTIVE; ++ pEntry->PsQIdleCount = 0; ++ pEntry->NoDataIdleCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ InitializeQueueHeader(&pEntry->PsQueue); ++ ++ ++ pAd->MacTab.Size ++; ++ ++ // Add this entry into ASIC RX WCID search table ++ RT28XX_STA_ENTRY_ADD(pAd, pEntry); ++ ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertEntry - allocate entry #%d, Total= %d\n",i, pAd->MacTab.Size)); ++ break; ++ } ++ } ++ ++ // add this MAC entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ if (pAd->MacTab.Hash[HashIdx] == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pAd->MacTab.Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ return pEntry; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Delete a specified client from MAC table ++ ========================================================================== ++ */ ++BOOLEAN MacTableDeleteEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr) ++{ ++ USHORT HashIdx; ++ MAC_TABLE_ENTRY *pEntry, *pPrevEntry, *pProbeEntry; ++ BOOLEAN Cancelled; ++ //USHORT offset; // unused variable ++ //UCHAR j; // unused variable ++ ++ if (wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ //pEntry = pAd->MacTab.Hash[HashIdx]; ++ pEntry = &pAd->MacTab.Content[wcid]; ++ ++ if (pEntry && (pEntry->ValidAsCLI || pEntry->ValidAsApCli || pEntry->ValidAsWDS || pEntry->ValidAsMesh ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ || pEntry->ValidAsDls ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ )) ++ { ++ if (MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ ++ // Delete this entry from ASIC on-chip WCID Table ++ RT28XX_STA_ENTRY_MAC_RESET(pAd, wcid); ++ ++#ifdef DOT11_N_SUPPORT ++ // free resources of BA ++ BASessionTearDownALL(pAd, pEntry->Aid); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ pPrevEntry = NULL; ++ pProbeEntry = pAd->MacTab.Hash[HashIdx]; ++ ASSERT(pProbeEntry); ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ // not found !!! ++ ASSERT(pProbeEntry != NULL); ++ ++ RT28XX_STA_ENTRY_KEY_DEL(pAd, BSS0, wcid); ++ ++ ++ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) ++ { ++ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ } ++ ++ ++ NdisZeroMemory(pEntry, sizeof(MAC_TABLE_ENTRY)); ++ pAd->MacTab.Size --; ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableDeleteEntry1 - Total= %d\n", pAd->MacTab.Size)); ++ } ++ else ++ { ++ printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid); ++ } ++ } ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ //Reset operating mode when no Sta. ++ if (pAd->MacTab.Size == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode = 0; ++#endif // DOT11_N_SUPPORT // ++ //AsicUpdateProtect(pAd, 0 /*pAd->CommonCfg.AddHTInfo.AddHtInfo2.OperaionMode*/, (ALLN_SETPROTECT), TRUE, 0 /*pAd->MacTab.fAnyStationNonGF*/); ++ RT28XX_UPDATE_PROTECT(pAd); // edit by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ This routine reset the entire MAC table. All packets pending in ++ the power-saving queues are freed here. ++ ========================================================================== ++ */ ++VOID MacTableReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableReset\n")); ++ //NdisAcquireSpinLock(&pAd->MacTabLock); ++ ++ for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) ++ { ++ ++#ifdef DOT11_N_SUPPORT ++ // free resources of BA ++ BASessionTearDownALL(pAd, i); ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->MacTab.Content[i].ValidAsCLI = FALSE; ++ ++ ++ ++#ifdef RT2870 ++ NdisZeroMemory(pAd->MacTab.Content[i].Addr, 6); ++ RT28XX_STA_ENTRY_MAC_RESET(pAd, i); ++#endif // RT2870 // ++ ++ //AsicDelWcidTab(pAd, i); ++ } ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID AssocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, ++ IN PUCHAR pAddr, ++ IN USHORT CapabilityInfo, ++ IN ULONG Timeout, ++ IN USHORT ListenIntv) ++{ ++ COPY_MAC_ADDR(AssocReq->Addr, pAddr); ++ // Add mask to support 802.11b mode only ++ AssocReq->CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; // not cf-pollable, not cf-poll-request ++ AssocReq->Timeout = Timeout; ++ AssocReq->ListenIntv = ListenIntv; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID DisassocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, ++ IN PUCHAR pAddr, ++ IN USHORT Reason) ++{ ++ COPY_MAC_ADDR(DisassocReq->Addr, pAddr); ++ DisassocReq->Reason = Reason; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check the out going frame, if this is an DHCP or ARP datagram ++ will be duplicate another frame at low data rate transmit. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pPacket Pointer to outgoing Ndis frame ++ ++ Return Value: ++ TRUE To be duplicate at Low data rate transmit. (1mb) ++ FALSE Do nothing. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ MAC header + IP Header + UDP Header ++ 14 Bytes 20 Bytes ++ ++ UDP Header ++ 00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15| ++ Source Port ++ 16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31| ++ Destination Port ++ ++ port 0x43 means Bootstrap Protocol, server. ++ Port 0x44 means Bootstrap Protocol, client. ++ ++ ======================================================================== ++*/ ++ ++BOOLEAN RTMPCheckDHCPFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ ULONG NumberOfBytesRead = 0; ++ ULONG CurrentOffset = 0; ++ PVOID pVirtualAddress = NULL; ++ UINT NdisBufferLength; ++ PUCHAR pSrc; ++ USHORT Protocol; ++ UCHAR ByteOffset36 = 0; ++ UCHAR ByteOffset38 = 0; ++ BOOLEAN ReadFirstParm = TRUE; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, (PUCHAR *)&pVirtualAddress, &NdisBufferLength); ++ ++ NumberOfBytesRead += NdisBufferLength; ++ pSrc = (PUCHAR) pVirtualAddress; ++ Protocol = *(pSrc + 12) * 256 + *(pSrc + 13); ++ ++ // ++ // Check DHCP & BOOTP protocol ++ // ++ while (NumberOfBytesRead <= PacketInfo.TotalPacketLength) ++ { ++ if ((NumberOfBytesRead >= 35) && (ReadFirstParm == TRUE)) ++ { ++ CurrentOffset = 35 - (NumberOfBytesRead - NdisBufferLength); ++ ByteOffset36 = *(pSrc + CurrentOffset); ++ ReadFirstParm = FALSE; ++ } ++ ++ if (NumberOfBytesRead >= 37) ++ { ++ CurrentOffset = 37 - (NumberOfBytesRead - NdisBufferLength); ++ ByteOffset38 = *(pSrc + CurrentOffset); ++ //End of Read ++ break; ++ } ++ return FALSE; ++ } ++ ++ // Check for DHCP & BOOTP protocol ++ if ((ByteOffset36 != 0x44) || (ByteOffset38 != 0x43)) ++ { ++ // ++ // 2054 (hex 0806) for ARP datagrams ++ // if this packet is not ARP datagrams, then do nothing ++ // ARP datagrams will also be duplicate at 1mb broadcast frames ++ // ++ if (Protocol != 0x0806 ) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++BOOLEAN RTMPCheckEtherType( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ USHORT TypeLen; ++ UCHAR Byte0, Byte1; ++ PUCHAR pSrcBuf; ++ UINT32 pktLen; ++ UINT16 srcPort, dstPort; ++ BOOLEAN status = TRUE; ++ ++ ++ pSrcBuf = GET_OS_PKT_DATAPTR(pPacket); ++ pktLen = GET_OS_PKT_LEN(pPacket); ++ ++ ASSERT(pSrcBuf); ++ ++ RTMP_SET_PACKET_SPECIFIC(pPacket, 0); ++ ++ // get Ethernet protocol field ++ TypeLen = (pSrcBuf[12] << 8) + pSrcBuf[13]; ++ ++ pSrcBuf += LENGTH_802_3; // Skip the Ethernet Header. ++ ++ if (TypeLen <= 1500) ++ { // 802.3, 802.3 LLC ++ /* ++ DestMAC(6) + SrcMAC(6) + Lenght(2) + ++ DSAP(1) + SSAP(1) + Control(1) + ++ if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. ++ => + SNAP (5, OriginationID(3) + etherType(2)) ++ */ ++ if (pSrcBuf[0] == 0xAA && pSrcBuf[1] == 0xAA && pSrcBuf[2] == 0x03) ++ { ++ Sniff2BytesFromNdisBuffer(pSrcBuf, 6, &Byte0, &Byte1); ++ RTMP_SET_PACKET_LLCSNAP(pPacket, 1); ++ TypeLen = (USHORT)((Byte0 << 8) + Byte1); ++ pSrcBuf += 8; // Skip this LLC/SNAP header ++ } ++ else ++ { ++ //It just has 3-byte LLC header, maybe a legacy ether type frame. we didn't handle it. ++ } ++ } ++ ++ // If it's a VLAN packet, get the real Type/Length field. ++ if (TypeLen == 0x8100) ++ { ++ /* 0x8100 means VLAN packets */ ++ ++ /* Dest. MAC Address (6-bytes) + ++ Source MAC Address (6-bytes) + ++ Length/Type = 802.1Q Tag Type (2-byte) + ++ Tag Control Information (2-bytes) + ++ Length / Type (2-bytes) + ++ data payload (0-n bytes) + ++ Pad (0-p bytes) + ++ Frame Check Sequence (4-bytes) */ ++ ++ RTMP_SET_PACKET_VLAN(pPacket, 1); ++ Sniff2BytesFromNdisBuffer(pSrcBuf, 2, &Byte0, &Byte1); ++ TypeLen = (USHORT)((Byte0 << 8) + Byte1); ++ ++ pSrcBuf += 4; // Skip the VLAN Header. ++ } ++ ++ switch (TypeLen) ++ { ++ case 0x0800: ++ { ++ ASSERT((pktLen > 34)); ++ if (*(pSrcBuf + 9) == 0x11) ++ { // udp packet ++ ASSERT((pktLen > 34)); // 14 for ethernet header, 20 for IP header ++ ++ pSrcBuf += 20; // Skip the IP header ++ srcPort = OS_NTOHS(*((UINT16 *)pSrcBuf)); ++ dstPort = OS_NTOHS(*((UINT16 *)(pSrcBuf +2))); ++ ++ if ((srcPort==0x44 && dstPort==0x43) || (srcPort==0x43 && dstPort==0x44)) ++ { //It's a BOOTP/DHCP packet ++ RTMP_SET_PACKET_DHCP(pPacket, 1); ++ } ++ } ++ } ++ break; ++ case 0x0806: ++ { ++ //ARP Packet. ++ RTMP_SET_PACKET_DHCP(pPacket, 1); ++ } ++ break; ++ case 0x888e: ++ { ++ // EAPOL Packet. ++ RTMP_SET_PACKET_EAPOL(pPacket, 1); ++ } ++ break; ++ default: ++ status = FALSE; ++ break; ++ } ++ ++ return status; ++ ++} ++ ++ ++ ++VOID Update_Rssi_Sample( ++ IN PRTMP_ADAPTER pAd, ++ IN RSSI_SAMPLE *pRssi, ++ IN PRXWI_STRUC pRxWI) ++ { ++ CHAR rssi0 = pRxWI->RSSI0; ++ CHAR rssi1 = pRxWI->RSSI1; ++ CHAR rssi2 = pRxWI->RSSI2; ++ ++ if (rssi0 != 0) ++ { ++ pRssi->LastRssi0 = ConvertToRssi(pAd, (CHAR)rssi0, RSSI_0); ++ pRssi->AvgRssi0X8 = (pRssi->AvgRssi0X8 - pRssi->AvgRssi0) + pRssi->LastRssi0; ++ pRssi->AvgRssi0 = pRssi->AvgRssi0X8 >> 3; ++ } ++ ++ if (rssi1 != 0) ++ { ++ pRssi->LastRssi1 = ConvertToRssi(pAd, (CHAR)rssi1, RSSI_1); ++ pRssi->AvgRssi1X8 = (pRssi->AvgRssi1X8 - pRssi->AvgRssi1) + pRssi->LastRssi1; ++ pRssi->AvgRssi1 = pRssi->AvgRssi1X8 >> 3; ++ } ++ ++ if (rssi2 != 0) ++ { ++ pRssi->LastRssi2 = ConvertToRssi(pAd, (CHAR)rssi2, RSSI_2); ++ pRssi->AvgRssi2X8 = (pRssi->AvgRssi2X8 - pRssi->AvgRssi2) + pRssi->LastRssi2; ++ pRssi->AvgRssi2 = pRssi->AvgRssi2X8 >> 3; ++ } ++} ++ ++ ++ ++// Normal legacy Rx packet indication ++VOID Indicate_Legacy_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ UCHAR Header802_3[LENGTH_802_3]; ++ ++ // 1. get 802.3 Header ++ // 2. remove LLC ++ // a. pointer pRxBlk->pData to payload ++ // b. modify pRxBlk->DataSize ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pRxBlk->DataSize > MAX_RX_PKT_LEN) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ++ STATS_INC_RX_PACKETS(pAd, FromWhichBSSID); ++ ++#ifdef RT2870 ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.bDisableReordering == 0) ++ { ++ PBA_REC_ENTRY pBAEntry; ++ ULONG Now32; ++ UCHAR Wcid = pRxBlk->pRxWI->WirelessCliID; ++ UCHAR TID = pRxBlk->pRxWI->TID; ++ USHORT Idx; ++ ++#define REORDERING_PACKET_TIMEOUT ((100 * HZ)/1000) // system ticks -- 100 ms ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ Idx = pAd->MacTab.Content[Wcid].BARecWcidArray[TID]; ++ if (Idx != 0) ++ { ++ pBAEntry = &pAd->BATable.BARecEntry[Idx]; ++ // update last rx time ++ NdisGetSystemUpTime(&Now32); ++ if ((pBAEntry->list.qlen > 0) && ++ RTMP_TIME_AFTER((unsigned long)Now32, (unsigned long)(pBAEntry->LastIndSeqAtTimer+(REORDERING_PACKET_TIMEOUT))) ++ ) ++ { ++ printk("Indicate_Legacy_Packet():flush reordering_timeout_mpdus! RxWI->Flags=%d, pRxWI.TID=%d, RxD->AMPDU=%d!\n", pRxBlk->Flags, pRxBlk->pRxWI->TID, pRxBlk->RxD.AMPDU); ++ hex_dump("Dump the legacy Packet:", GET_OS_PKT_DATAPTR(pRxBlk->pRxPacket), 64); ++ ba_flush_reordering_timeout_mpdus(pAd, pBAEntry, Now32); ++ } ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++#endif // RT2870 // ++ ++ wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); ++ ++ // ++ // pass this 802.3 packet to upper layer or forward this packet to WM directly ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxPacket, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++ ++// Normal, AMPDU or AMSDU ++VOID CmmRxnonRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMSDU)) ++ { ++ // handle A-MSDU ++ Indicate_AMSDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ } ++} ++ ++ ++VOID CmmRxRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ UCHAR Header802_3[LENGTH_802_3]; ++ UINT16 Msdu2Size; ++ UINT16 Payload1Size, Payload2Size; ++ PUCHAR pData2; ++ PNDIS_PACKET pPacket2 = NULL; ++ ++ ++ ++ Msdu2Size = *(pRxBlk->pData) + (*(pRxBlk->pData+1) << 8); ++ ++ if ((Msdu2Size <= 1536) && (Msdu2Size < pRxBlk->DataSize)) ++ { ++ /* skip two byte MSDU2 len */ ++ pRxBlk->pData += 2; ++ pRxBlk->DataSize -= 2; ++ } ++ else ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // get 802.3 Header and remove LLC ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(pRxBlk, Header802_3); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ASSERT(pRxBlk->pRxPacket); ++ ++ // Ralink Aggregation frame ++ pAd->RalinkCounters.OneSecRxAggregationCount ++; ++ Payload1Size = pRxBlk->DataSize - Msdu2Size; ++ Payload2Size = Msdu2Size - LENGTH_802_3; ++ ++ pData2 = pRxBlk->pData + Payload1Size + LENGTH_802_3; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pPacket2 = duplicate_pkt(pAd, (pData2-LENGTH_802_3), LENGTH_802_3, pData2, Payload2Size, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (!pPacket2) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // update payload size of 1st packet ++ pRxBlk->DataSize = Payload1Size; ++ wlan_802_11_to_802_3_packet(pAd, pRxBlk, Header802_3, FromWhichBSSID); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pRxBlk->pRxPacket, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pPacket2) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ ANNOUNCE_OR_FORWARD_802_3_PACKET(pAd, pPacket2, FromWhichBSSID); ++#endif // CONFIG_STA_SUPPORT // ++ } ++} ++ ++ ++#define RESET_FRAGFRAME(_fragFrame) \ ++ { \ ++ _fragFrame.RxSize = 0; \ ++ _fragFrame.Sequence = 0; \ ++ _fragFrame.LastFrag = 0; \ ++ _fragFrame.Flags = 0; \ ++ } ++ ++ ++PNDIS_PACKET RTMPDeFragmentDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ UCHAR *pData = pRxBlk->pData; ++ USHORT DataSize = pRxBlk->DataSize; ++ PNDIS_PACKET pRetPacket = NULL; ++ UCHAR *pFragBuffer = NULL; ++ BOOLEAN bReassDone = FALSE; ++ UCHAR HeaderRoom = 0; ++ ++ ++ ASSERT(pHeader); ++ ++ HeaderRoom = pData - (UCHAR *)pHeader; ++ ++ // Re-assemble the fragmented packets ++ if (pHeader->Frag == 0) // Frag. Number is 0 : First frag or only one pkt ++ { ++ // the first pkt of fragment, record it. ++ if (pHeader->FC.MoreFrag) ++ { ++ ASSERT(pAd->FragFrame.pFragPacket); ++ pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); ++ pAd->FragFrame.RxSize = DataSize + HeaderRoom; ++ NdisMoveMemory(pFragBuffer, pHeader, pAd->FragFrame.RxSize); ++ pAd->FragFrame.Sequence = pHeader->Sequence; ++ pAd->FragFrame.LastFrag = pHeader->Frag; // Should be 0 ++ ASSERT(pAd->FragFrame.LastFrag == 0); ++ goto done; // end of processing this frame ++ } ++ } ++ else //Middle & End of fragment ++ { ++ if ((pHeader->Sequence != pAd->FragFrame.Sequence) || ++ (pHeader->Frag != (pAd->FragFrame.LastFrag + 1))) ++ { ++ // Fragment is not the same sequence or out of fragment number order ++ // Reset Fragment control blk ++ RESET_FRAGFRAME(pAd->FragFrame); ++ DBGPRINT(RT_DEBUG_ERROR, ("Fragment is not the same sequence or out of fragment number order.\n")); ++ goto done; // give up this frame ++ } ++ else if ((pAd->FragFrame.RxSize + DataSize) > MAX_FRAME_SIZE) ++ { ++ // Fragment frame is too large, it exeeds the maximum frame size. ++ // Reset Fragment control blk ++ RESET_FRAGFRAME(pAd->FragFrame); ++ DBGPRINT(RT_DEBUG_ERROR, ("Fragment frame is too large, it exeeds the maximum frame size.\n")); ++ goto done; // give up this frame ++ } ++ ++ // ++ // Broadcom AP(BCM94704AGR) will send out LLC in fragment's packet, LLC only can accpet at first fragment. ++ // In this case, we will dropt it. ++ // ++ if (NdisEqualMemory(pData, SNAP_802_1H, sizeof(SNAP_802_1H))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Find another LLC at Middle or End fragment(SN=%d, Frag=%d)\n", pHeader->Sequence, pHeader->Frag)); ++ goto done; // give up this frame ++ } ++ ++ pFragBuffer = GET_OS_PKT_DATAPTR(pAd->FragFrame.pFragPacket); ++ ++ // concatenate this fragment into the re-assembly buffer ++ NdisMoveMemory((pFragBuffer + pAd->FragFrame.RxSize), pData, DataSize); ++ pAd->FragFrame.RxSize += DataSize; ++ pAd->FragFrame.LastFrag = pHeader->Frag; // Update fragment number ++ ++ // Last fragment ++ if (pHeader->FC.MoreFrag == FALSE) ++ { ++ bReassDone = TRUE; ++ } ++ } ++ ++done: ++ // always release rx fragmented packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ ++ // return defragmented packet if packet is reassembled completely ++ // otherwise return NULL ++ if (bReassDone) ++ { ++ PNDIS_PACKET pNewFragPacket; ++ ++ // allocate a new packet buffer for fragment ++ pNewFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE); ++ if (pNewFragPacket) ++ { ++ // update RxBlk ++ pRetPacket = pAd->FragFrame.pFragPacket; ++ pAd->FragFrame.pFragPacket = pNewFragPacket; ++ pRxBlk->pHeader = (PHEADER_802_11) GET_OS_PKT_DATAPTR(pRetPacket); ++ pRxBlk->pData = (UCHAR *)pRxBlk->pHeader + HeaderRoom; ++ pRxBlk->DataSize = pAd->FragFrame.RxSize - HeaderRoom; ++ pRxBlk->pRxPacket = pRetPacket; ++ } ++ else ++ { ++ RESET_FRAGFRAME(pAd->FragFrame); ++ } ++ } ++ ++ return pRetPacket; ++} ++ ++ ++VOID Indicate_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ UINT nMSDU; ++ ++ update_os_packet_info(pAd, pRxBlk, FromWhichBSSID); ++ RTMP_SET_PACKET_IF(pRxBlk->pRxPacket, FromWhichBSSID); ++ nMSDU = deaggregate_AMSDU_announce(pAd, pRxBlk->pRxPacket, pRxBlk->pData, pRxBlk->DataSize); ++} ++ ++VOID Indicate_EAPOL_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pEntry == NULL) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("Indicate_EAPOL_Packet: drop and release the invalid packet.\n")); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++} ++ ++#define BCN_TBTT_OFFSET 64 //defer 64 us ++VOID ReSyncBeaconTime( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ UINT32 Offset; ++ ++ ++ Offset = (pAd->TbttTickCount) % (BCN_TBTT_OFFSET); ++ ++ pAd->TbttTickCount++; ++ ++ // ++ // The updated BeaconInterval Value will affect Beacon Interval after two TBTT ++ // beacasue the original BeaconInterval had been loaded into next TBTT_TIMER ++ // ++ if (Offset == (BCN_TBTT_OFFSET-2)) ++ { ++ BCN_TIME_CFG_STRUC csr; ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod << 4) - 1 ; // ASIC register in units of 1/16 TU = 64us ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ } ++ else ++ { ++ if (Offset == (BCN_TBTT_OFFSET-1)) ++ { ++ BCN_TIME_CFG_STRUC csr; ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.BeaconInterval = (pAd->CommonCfg.BeaconPeriod) << 4; // ASIC register in units of 1/16 TU ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/cmm_info.c +@@ -0,0 +1,3395 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++*/ ++ ++#include "../rt_config.h" ++ ++INT Show_SSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef DOT11_N_SUPPORT ++INT Show_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // DOT11_N_SUPPORT // ++ ++INT Show_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_CountryCode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef AGGREGATION_SUPPORT ++INT Show_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // AGGREGATION_SUPPORT // ++ ++#ifdef WMM_SUPPORT ++INT Show_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // WMM_SUPPORT // ++ ++INT Show_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++#ifdef CONFIG_STA_SUPPORT ++INT Show_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Show_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_Key4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++INT Show_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf); ++ ++static struct { ++ CHAR *name; ++ INT (*show_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC, RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC[] = { ++ {"SSID", Show_SSID_Proc}, ++ {"WirelessMode", Show_WirelessMode_Proc}, ++ {"TxBurst", Show_TxBurst_Proc}, ++ {"TxPreamble", Show_TxPreamble_Proc}, ++ {"TxPower", Show_TxPower_Proc}, ++ {"Channel", Show_Channel_Proc}, ++ {"BGProtection", Show_BGProtection_Proc}, ++ {"RTSThreshold", Show_RTSThreshold_Proc}, ++ {"FragThreshold", Show_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Show_HtBw_Proc}, ++ {"HtMcs", Show_HtMcs_Proc}, ++ {"HtGi", Show_HtGi_Proc}, ++ {"HtOpMode", Show_HtOpMode_Proc}, ++ {"HtExtcha", Show_HtExtcha_Proc}, ++ {"HtMpduDensity", Show_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Show_HtBaWinSize_Proc}, ++ {"HtRdg", Show_HtRdg_Proc}, ++ {"HtAmsdu", Show_HtAmsdu_Proc}, ++ {"HtAutoBa", Show_HtAutoBa_Proc}, ++#endif // DOT11_N_SUPPORT // ++ {"CountryRegion", Show_CountryRegion_Proc}, ++ {"CountryRegionABand", Show_CountryRegionABand_Proc}, ++ {"CountryCode", Show_CountryCode_Proc}, ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Show_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Show_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Show_IEEE80211H_Proc}, ++#ifdef CONFIG_STA_SUPPORT ++ {"NetworkType", Show_NetworkType_Proc}, ++#endif // CONFIG_STA_SUPPORT // ++ {"AuthMode", Show_AuthMode_Proc}, ++ {"EncrypType", Show_EncrypType_Proc}, ++ {"DefaultKeyID", Show_DefaultKeyID_Proc}, ++ {"Key1", Show_Key1_Proc}, ++ {"Key2", Show_Key2_Proc}, ++ {"Key3", Show_Key3_Proc}, ++ {"Key4", Show_Key4_Proc}, ++ {"WPAPSK", Show_WPAPSK_Proc}, ++ {NULL, NULL} ++}; ++ ++/* ++ ========================================================================== ++ Description: ++ Get Driver version. ++ ++ Return: ++ ========================================================================== ++*/ ++INT Set_DriverVersion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ DBGPRINT(RT_DEBUG_TRACE, ("Driver version-%s\n", STA_DRIVER_VERSION)); ++#endif // CONFIG_STA_SUPPORT // ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Country Region. ++ This command will not work, if the field of CountryRegion in eeprom is programmed. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG region; ++ ++ region = simple_strtol(arg, 0, 10); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ return -EOPNOTSUPP; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Country can be set only when EEPROM not programmed ++ if (pAd->CommonCfg.CountryRegion & 0x80) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameter of CountryRegion in eeprom is programmed \n")); ++ return FALSE; ++ } ++ ++ if((region >= 0) && (region <= REGION_MAXIMUM_BG_BAND)) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) region; ++ } ++ else if (region == REGION_31_BG_BAND) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) region; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegion_Proc::parameters out of range\n")); ++ return FALSE; ++ } ++ ++ // if set country region, driver needs to be reset ++ BuildChannelList(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegion_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegion)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Country Region for A band. ++ This command will not work, if the field of CountryRegion in eeprom is programmed. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG region; ++ ++ region = simple_strtol(arg, 0, 10); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ return -EOPNOTSUPP; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Country can be set only when EEPROM not programmed ++ if (pAd->CommonCfg.CountryRegionForABand & 0x80) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameter of CountryRegion in eeprom is programmed \n")); ++ return FALSE; ++ } ++ ++ if((region >= 0) && (region <= REGION_MAXIMUM_A_BAND)) ++ { ++ pAd->CommonCfg.CountryRegionForABand = (UCHAR) region; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_CountryRegionABand_Proc::parameters out of range\n")); ++ return FALSE; ++ } ++ ++ // if set country region, driver needs to be reset ++ BuildChannelList(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_CountryRegionABand_Proc::(CountryRegion=%d)\n", pAd->CommonCfg.CountryRegionForABand)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Wireless Mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG WirelessMode; ++ INT success = TRUE; ++ ++ WirelessMode = simple_strtol(arg, 0, 10); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ INT MaxPhyMode = PHY_11G; ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ if (WirelessMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAd, WirelessMode); ++#ifdef DOT11_N_SUPPORT ++ if (WirelessMode >= PHY_11ABGN_MIXED) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ pAd->CommonCfg.REGBACapability.field.AutoBA = TRUE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ pAd->CommonCfg.REGBACapability.field.AutoBA = FALSE; ++ } ++#endif // DOT11_N_SUPPORT // ++ // Set AdhocMode rates ++ if (pAd->StaCfg.BssType == BSS_ADHOC) ++ { ++ MlmeUpdateTxRates(pAd, FALSE, 0); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy to on-chip memory ++ } ++ } ++ else ++ { ++ success = FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // it is needed to set SSID to take effect ++ if (success == TRUE) ++ { ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WirelessMode_Proc::(=%ld)\n", WirelessMode)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_WirelessMode_Proc::parameters out of range\n")); ++ } ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Channel ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ INT success = TRUE; ++ UCHAR Channel; ++ ++ Channel = (UCHAR) simple_strtol(arg, 0, 10); ++ ++ // check if this channel is valid ++ if (ChannelSanity(pAd, Channel) == TRUE) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->CommonCfg.Channel = Channel; ++ ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ N_ChannelCheck(pAd); ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ N_SetCenCh(pAd); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40, control_channel(%d), CentralChannel(%d) \n", ++ pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAd->CommonCfg.Channel)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ success = TRUE; ++ } ++ else ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ success = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ if (success == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Channel_Proc::(Channel=%d)\n", pAd->CommonCfg.Channel)); ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Short Slot Time Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ShortSlot_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG ShortSlot; ++ ++ ShortSlot = simple_strtol(arg, 0, 10); ++ ++ if (ShortSlot == 1) ++ pAd->CommonCfg.bUseShortSlotTime = TRUE; ++ else if (ShortSlot == 0) ++ pAd->CommonCfg.bUseShortSlotTime = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ShortSlot_Proc::(ShortSlot=%d)\n", pAd->CommonCfg.bUseShortSlotTime)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Tx power ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG TxPower; ++ INT success = FALSE; ++ ++ TxPower = (ULONG) simple_strtol(arg, 0, 10); ++ if (TxPower <= 100) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->CommonCfg.TxPowerDefault = TxPower; ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ success = TRUE; ++ } ++ else ++ success = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPower_Proc::(TxPowerPercentage=%ld)\n", pAd->CommonCfg.TxPowerPercentage)); ++ ++ return success; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set 11B/11G Protection ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ switch (simple_strtol(arg, 0, 10)) ++ { ++ case 0: //AUTO ++ pAd->CommonCfg.UseBGProtection = 0; ++ break; ++ case 1: //Always On ++ pAd->CommonCfg.UseBGProtection = 1; ++ break; ++ case 2: //Always OFF ++ pAd->CommonCfg.UseBGProtection = 2; ++ break; ++ default: //Invalid argument ++ return FALSE; ++ } ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_BGProtection_Proc::(BGProtection=%ld)\n", pAd->CommonCfg.UseBGProtection)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set TxPreamble ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ RT_802_11_PREAMBLE Preamble; ++ ++ Preamble = simple_strtol(arg, 0, 10); ++ ++ ++ switch (Preamble) ++ { ++ case Rt802_11PreambleShort: ++ pAd->CommonCfg.TxPreamble = Preamble; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ case Rt802_11PreambleLong: ++#ifdef CONFIG_STA_SUPPORT ++ case Rt802_11PreambleAuto: ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++#endif // CONFIG_STA_SUPPORT // ++ pAd->CommonCfg.TxPreamble = Preamble; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); ++#endif // CONFIG_STA_SUPPORT // ++ break; ++ default: //Invalid argument ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxPreamble_Proc::(TxPreamble=%ld)\n", pAd->CommonCfg.TxPreamble)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set RTS Threshold ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ ++ RtsThresh = simple_strtol(arg, 0, 10); ++ ++ if((RtsThresh > 0) && (RtsThresh <= MAX_RTS_THRESHOLD)) ++ pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++#ifdef CONFIG_STA_SUPPORT ++ else if (RtsThresh == 0) ++ pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; ++#endif // CONFIG_STA_SUPPORT // ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_RTSThreshold_Proc::(RTSThreshold=%d)\n", pAd->CommonCfg.RtsThreshold)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Fragment Threshold ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ ++ FragThresh = simple_strtol(arg, 0, 10); ++ ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ //Illegal FragThresh so we set it to default ++ pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ } ++ else if (FragThresh % 2 == 1) ++ { ++ // The length of each fragment shall always be an even number of octets, except for the last fragment ++ // of an MSDU or MMPDU, which may be either an even or an odd number of octets. ++ pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); ++ } ++ else ++ { ++ pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->CommonCfg.FragmentThreshold == MAX_FRAG_THRESHOLD) ++ pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ else ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_FragThreshold_Proc::(FragThreshold=%d)\n", pAd->CommonCfg.FragmentThreshold)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set TxBurst ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG TxBurst; ++ ++ TxBurst = simple_strtol(arg, 0, 10); ++ if (TxBurst == 1) ++ pAd->CommonCfg.bEnableTxBurst = TRUE; ++ else if (TxBurst == 0) ++ pAd->CommonCfg.bEnableTxBurst = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_TxBurst_Proc::(TxBurst=%d)\n", pAd->CommonCfg.bEnableTxBurst)); ++ ++ return TRUE; ++} ++ ++#ifdef AGGREGATION_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set TxBurst ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG aggre; ++ ++ aggre = simple_strtol(arg, 0, 10); ++ ++ if (aggre == 1) ++ pAd->CommonCfg.bAggregationCapable = TRUE; ++ else if (aggre == 0) ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PktAggregate_Proc::(AGGRE=%d)\n", pAd->CommonCfg.bAggregationCapable)); ++ ++ return TRUE; ++} ++#endif ++ ++/* ++ ========================================================================== ++ Description: ++ Set IEEE80211H. ++ This parameter is 1 when needs radar detection, otherwise 0 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG ieee80211h; ++ ++ ieee80211h = simple_strtol(arg, 0, 10); ++ ++ if (ieee80211h == 1) ++ pAd->CommonCfg.bIEEE80211H = TRUE; ++ else if (ieee80211h == 0) ++ pAd->CommonCfg.bIEEE80211H = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_IEEE80211H_Proc::(IEEE80211H=%d)\n", pAd->CommonCfg.bIEEE80211H)); ++ ++ return TRUE; ++} ++ ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ For Debug information ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Debug_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> Set_Debug_Proc *******************\n")); ++ ++ if(simple_strtol(arg, 0, 10) <= RT_DEBUG_LOUD) ++ RTDebugLevel = simple_strtol(arg, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== Set_Debug_Proc(RTDebugLevel = %ld)\n", RTDebugLevel)); ++ ++ return TRUE; ++} ++#endif ++ ++INT Show_DescInfo_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Reset statistics counter ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ arg ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ResetStatCounter_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ //UCHAR i; ++ //MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>Set_ResetStatCounter_Proc\n")); ++ ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAd); ++ ++ NdisZeroMemory(&pAd->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAd->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAd->RalinkCounters, sizeof(COUNTER_RALINK)); ++ ++ return TRUE; ++} ++ ++BOOLEAN RTMPCheckStrPrintAble( ++ IN CHAR *pInPutStr, ++ IN UCHAR strLen) ++{ ++ UCHAR i=0; ++ ++ for (i=0; i 0x7E)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Remove WPA Key process ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pBuf Pointer to the where the key stored ++ ++ Return Value: ++ NDIS_SUCCESS Add key successfully ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPSetDesiredRates( ++ IN PRTMP_ADAPTER pAdapter, ++ IN LONG Rates) ++{ ++ NDIS_802_11_RATES aryRates; ++ ++ memset(&aryRates, 0x00, sizeof(NDIS_802_11_RATES)); ++ switch (pAdapter->CommonCfg.PhyMode) ++ { ++ case PHY_11A: // A only ++ switch (Rates) ++ { ++ case 6000000: //6M ++ aryRates[0] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 9000000: //9M ++ aryRates[0] = 0x12; // 9M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 12000000: //12M ++ aryRates[0] = 0x18; // 12M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 18000000: //18M ++ aryRates[0] = 0x24; // 18M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 24000000: //24M ++ aryRates[0] = 0x30; // 24M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; ++ break; ++ case 36000000: //36M ++ aryRates[0] = 0x48; // 36M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; ++ break; ++ case 48000000: //48M ++ aryRates[0] = 0x60; // 48M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; ++ break; ++ case 54000000: //54M ++ aryRates[0] = 0x6c; // 54M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; ++ break; ++ case -1: //Auto ++ default: ++ aryRates[0] = 0x6c; // 54Mbps ++ aryRates[1] = 0x60; // 48Mbps ++ aryRates[2] = 0x48; // 36Mbps ++ aryRates[3] = 0x30; // 24Mbps ++ aryRates[4] = 0x24; // 18M ++ aryRates[5] = 0x18; // 12M ++ aryRates[6] = 0x12; // 9M ++ aryRates[7] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ break; ++ } ++ break; ++ case PHY_11BG_MIXED: // B/G Mixed ++ case PHY_11B: // B only ++ case PHY_11ABG_MIXED: // A/B/G Mixed ++ default: ++ switch (Rates) ++ { ++ case 1000000: //1M ++ aryRates[0] = 0x02; ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 2000000: //2M ++ aryRates[0] = 0x04; ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 5000000: //5.5M ++ aryRates[0] = 0x0b; // 5.5M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 11000000: //11M ++ aryRates[0] = 0x16; // 11M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 6000000: //6M ++ aryRates[0] = 0x0c; // 6M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_0; ++ break; ++ case 9000000: //9M ++ aryRates[0] = 0x12; // 9M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_1; ++ break; ++ case 12000000: //12M ++ aryRates[0] = 0x18; // 12M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_2; ++ break; ++ case 18000000: //18M ++ aryRates[0] = 0x24; // 18M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_3; ++ break; ++ case 24000000: //24M ++ aryRates[0] = 0x30; // 24M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_4; ++ break; ++ case 36000000: //36M ++ aryRates[0] = 0x48; // 36M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_5; ++ break; ++ case 48000000: //48M ++ aryRates[0] = 0x60; // 48M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_6; ++ break; ++ case 54000000: //54M ++ aryRates[0] = 0x6c; // 54M ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_7; ++ break; ++ case -1: //Auto ++ default: ++ if (pAdapter->CommonCfg.PhyMode == PHY_11B) ++ { //B Only ++ aryRates[0] = 0x16; // 11Mbps ++ aryRates[1] = 0x0b; // 5.5Mbps ++ aryRates[2] = 0x04; // 2Mbps ++ aryRates[3] = 0x02; // 1Mbps ++ } ++ else ++ { //(B/G) Mixed or (A/B/G) Mixed ++ aryRates[0] = 0x6c; // 54Mbps ++ aryRates[1] = 0x60; // 48Mbps ++ aryRates[2] = 0x48; // 36Mbps ++ aryRates[3] = 0x30; // 24Mbps ++ aryRates[4] = 0x16; // 11Mbps ++ aryRates[5] = 0x0b; // 5.5Mbps ++ aryRates[6] = 0x04; // 2Mbps ++ aryRates[7] = 0x02; // 1Mbps ++ } ++ pAdapter->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ break; ++ } ++ break; ++ } ++ ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, (" RTMPSetDesiredRates (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++} ++ ++NDIS_STATUS RTMPWPARemoveKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf) ++{ ++ PNDIS_802_11_REMOVE_KEY pKey; ++ ULONG KeyIdx; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ BOOLEAN bTxKey; // Set the key as transmit key ++ BOOLEAN bPairwise; // Indicate the key is pairwise key ++ BOOLEAN bKeyRSC; // indicate the receive SC set by KeyRSC value. ++ // Otherwise, it will set by the NIC. ++ BOOLEAN bAuthenticator; // indicate key is set by authenticator. ++ INT i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("---> RTMPWPARemoveKeyProc\n")); ++ ++ pKey = (PNDIS_802_11_REMOVE_KEY) pBuf; ++ KeyIdx = pKey->KeyIndex & 0xff; ++ // Bit 31 of Add-key, Tx Key ++ bTxKey = (pKey->KeyIndex & 0x80000000) ? TRUE : FALSE; ++ // Bit 30 of Add-key PairwiseKey ++ bPairwise = (pKey->KeyIndex & 0x40000000) ? TRUE : FALSE; ++ // Bit 29 of Add-key KeyRSC ++ bKeyRSC = (pKey->KeyIndex & 0x20000000) ? TRUE : FALSE; ++ // Bit 28 of Add-key Authenticator ++ bAuthenticator = (pKey->KeyIndex & 0x10000000) ? TRUE : FALSE; ++ ++ // 1. If bTx is TRUE, return failure information ++ if (bTxKey == TRUE) ++ return(NDIS_STATUS_INVALID_DATA); ++ ++ // 2. Check Pairwise Key ++ if (bPairwise) ++ { ++ // a. If BSSID is broadcast, remove all pairwise keys. ++ // b. If not broadcast, remove the pairwise specified by BSSID ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ if (MAC_ADDR_EQUAL(pAd->SharedKey[BSS0][i].BssId, pKey->BSSID)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%d)\n", i)); ++ pAd->SharedKey[BSS0][i].KeyLen = 0; ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)i); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ } ++ } ++ // 3. Group Key ++ else ++ { ++ // a. If BSSID is broadcast, remove all group keys indexed ++ // b. If BSSID matched, delete the group key indexed. ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveKeyProc(KeyIdx=%ld)\n", KeyIdx)); ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx); ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ ++ return (Status); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Remove All WPA Keys ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPWPARemoveAllKeys( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ UCHAR i; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPARemoveAllKeys(AuthMode=%d, WepStatus=%d)\n", pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus)); ++ ++ // For WEP/CKIP, there is no need to remove it, since WinXP won't set it again after ++ // Link up. And it will be replaced if user changed it. ++ if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return; ++ ++ // For WPA-None, there is no need to remove it, since WinXP won't set it again after ++ // Link up. And it will be replaced if user changed it. ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ return; ++ ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAd, BSS0, BSSID_WCID); ++ ++ // set all shared key mode as no-security. ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("remove %s key #%d\n", CipherName[pAd->SharedKey[BSS0][i].CipherAlg], i)); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][i], sizeof(CIPHER_KEY)); ++ ++ AsicRemoveSharedKeyEntry(pAd, BSS0, i); ++ } ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Change NIC PHY mode. Re-association may be necessary. possible settings ++ include - PHY_11B, PHY_11BG_MIXED, PHY_11A, and PHY_11ABG_MIXED ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPSetPhyMode( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG phymode) ++{ ++ INT i; ++ // the selected phymode must be supported by the RF IC encoded in E2PROM ++ ++ pAd->CommonCfg.PhyMode = (UCHAR)phymode; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPSetPhyMode : PhyMode=%d, channel=%d \n", pAd->CommonCfg.PhyMode, pAd->CommonCfg.Channel)); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ BuildChannelListEx(pAd); ++#else ++ BuildChannelList(pAd); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // sanity check user setting ++ for (i = 0; i < pAd->ChannelListNum; i++) ++ { ++ if (pAd->CommonCfg.Channel == pAd->ChannelList[i].Channel) ++ break; ++ } ++ ++ if (i == pAd->ChannelListNum) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->CommonCfg.Channel = FirstChannel(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetPhyMode: channel is out of range, use first channel=%d \n", pAd->CommonCfg.Channel)); ++ } ++ ++ NdisZeroMemory(pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisZeroMemory(pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisZeroMemory(pAd->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ switch (phymode) { ++ case PHY_11B: ++ pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRateLen = 4; ++ pAd->CommonCfg.ExtRateLen = 0; ++ pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps ++ //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_CCK; // This MODE is only FYI. not use ++ break; ++ ++ case PHY_11G: ++ case PHY_11BG_MIXED: ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11N_2_4G: ++ case PHY_11ABGN_MIXED: ++ case PHY_11BGN_MIXED: ++ case PHY_11GN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.SupRate[0] = 0x82; // 1 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x84; // 2 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[2] = 0x8B; // 5.5 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x96; // 11 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[4] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[5] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[6] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRateLen = 8; ++ pAd->CommonCfg.ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[1] = 0x18; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[2] = 0x30; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRate[3] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.ExtRateLen = 4; ++ pAd->CommonCfg.DesireRate[0] = 2; // 1 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 4; // 2 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 11; // 5.5 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 22; // 11 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[4] = 12; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[5] = 18; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[6] = 24; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[7] = 36; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[8] = 48; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[9] = 72; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[10] = 96; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[11] = 108; // 54 mbps, in units of 0.5 Mbps ++ break; ++ ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AN_MIXED: ++ case PHY_11AGN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate ++ pAd->CommonCfg.SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.SupRateLen = 8; ++ pAd->CommonCfg.ExtRateLen = 0; ++ pAd->CommonCfg.DesireRate[0] = 12; // 6 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[1] = 18; // 9 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[2] = 24; // 12 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[3] = 36; // 18 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[4] = 48; // 24 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[5] = 72; // 36 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[6] = 96; // 48 mbps, in units of 0.5 Mbps ++ pAd->CommonCfg.DesireRate[7] = 108; // 54 mbps, in units of 0.5 Mbps ++ //pAd->CommonCfg.HTPhyMode.field.MODE = MODE_OFDM; // This MODE is only FYI. not use ++ break; ++ ++ default: ++ break; ++ } ++ ++ ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++} ++ ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ======================================================================== ++ Routine Description: ++ Caller ensures we has 802.11n support. ++ Calls at setting HT from AP/STASetinformation ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ ======================================================================== ++*/ ++VOID RTMPSetHT( ++ IN PRTMP_ADAPTER pAd, ++ IN OID_SET_HT_PHYMODE *pHTPhyMode) ++{ ++ //ULONG *pmcs; ++ UINT32 Value = 0; ++ UCHAR BBPValue = 0; ++ UCHAR BBP3Value = 0; ++ UCHAR RxStream = pAd->CommonCfg.RxStream; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : HT_mode(%d), ExtOffset(%d), MCS(%d), BW(%d), STBC(%d), SHORTGI(%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, ++ pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ ++ // Don't zero supportedHyPhy structure. ++ RTMPZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); ++ RTMPZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); ++ RTMPZeroMemory(&pAd->CommonCfg.NewExtChanOffset, sizeof(pAd->CommonCfg.NewExtChanOffset)); ++ RTMPZeroMemory(&pAd->CommonCfg.DesiredHtPhy, sizeof(pAd->CommonCfg.DesiredHtPhy)); ++ ++ if (pAd->CommonCfg.bRdg) ++ { ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 1; ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.PlusHTC = 0; ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.RDGSupport = 0; ++ } ++ ++ pAd->CommonCfg.HtCapability.HtCapParm.MaxRAmpduFactor = 3; ++ pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor = 3; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : RxBAWinLimit = %d\n", pAd->CommonCfg.BACapability.field.RxBAWinLimit)); ++ ++ // Mimo power save, A-MSDU size, ++ pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize = (UCHAR)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.DesiredHtPhy.MimoPs = (UCHAR)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ ++ pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetHT : AMsduSize = %d, MimoPs = %d, MpduDensity = %d, MaxRAmpduFactor = %d\n", ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize, ++ pAd->CommonCfg.DesiredHtPhy.MimoPs, ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity, ++ pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor)); ++ ++ if(pHTPhyMode->HtMode == HTMODE_GF) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.GF = 1; ++ pAd->CommonCfg.DesiredHtPhy.GF = 1; ++ } ++ else ++ pAd->CommonCfg.DesiredHtPhy.GF = 0; ++ ++ // Decide Rx MCSSet ++ switch (RxStream) ++ { ++ case 1: ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0x00; ++ break; ++ ++ case 2: ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; ++ break; ++ ++ case 3: // 3*3 ++ pAd->CommonCfg.HtCapability.MCSSet[0] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[1] = 0xff; ++ pAd->CommonCfg.HtCapability.MCSSet[2] = 0xff; ++ break; ++ } ++ ++ if (pAd->CommonCfg.bForty_Mhz_Intolerant && (pAd->CommonCfg.Channel <= 14) && (pHTPhyMode->BW == BW_40) ) ++ { ++ pHTPhyMode->BW = BW_20; ++ pAd->CommonCfg.HtCapability.HtCapInfo.Forty_Mhz_Intolerant = 1; ++ } ++ ++ if(pHTPhyMode->BW == BW_40) ++ { ++ pAd->CommonCfg.HtCapability.MCSSet[4] = 0x1; // MCS 32 ++ pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 1; ++ if (pAd->CommonCfg.Channel <= 14) ++ pAd->CommonCfg.HtCapability.HtCapInfo.CCKmodein40 = 1; ++ ++ pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 1; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 1; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = (pHTPhyMode->ExtOffset == EXTCHA_BELOW)? (EXTCHA_BELOW): EXTCHA_ABOVE; ++ // Set Regsiter for extension channel position. ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBP3Value); ++ if ((pHTPhyMode->ExtOffset == EXTCHA_BELOW)) ++ { ++ Value |= 0x1; ++ BBP3Value |= (0x20); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ } ++ else if ((pHTPhyMode->ExtOffset == EXTCHA_ABOVE)) ++ { ++ Value &= 0xfe; ++ BBP3Value &= (~0x20); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ } ++ ++ // Turn on BBP 40MHz mode now only as AP . ++ // Sta can turn on BBP 40MHz after connection with 40MHz AP. Sta only broadcast 40MHz capability before connection. ++ if ((pAd->OpMode == OPMODE_AP) || INFRA_ON(pAd) || ADHOC_ON(pAd) ++ ) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBP3Value); ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth = 0; ++ pAd->CommonCfg.DesiredHtPhy.ChannelWidth = 0; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.RecomWidth = 0; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset = EXTCHA_NONE; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ // Turn on BBP 20MHz mode by request here. ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ } ++ } ++ ++ if(pHTPhyMode->STBC == STBC_USE) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.TxSTBC = 1; ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 1; ++ pAd->CommonCfg.HtCapability.HtCapInfo.RxSTBC = 1; ++ pAd->CommonCfg.DesiredHtPhy.RxSTBC = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.DesiredHtPhy.TxSTBC = 0; ++ pAd->CommonCfg.DesiredHtPhy.RxSTBC = 0; ++ } ++ ++ if(pHTPhyMode->SHORTGI == GI_400) ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 1; ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 1; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 1; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 1; ++ } ++ else ++ { ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor20 = 0; ++ pAd->CommonCfg.HtCapability.HtCapInfo.ShortGIfor40 = 0; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 = 0; ++ pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 = 0; ++ } ++ ++ // We support link adaptation for unsolicit MCS feedback, set to 2. ++ pAd->CommonCfg.HtCapability.ExtHtCapInfo.MCSFeedback = MCSFBK_NONE; //MCSFBK_UNSOLICIT; ++ pAd->CommonCfg.AddHTInfo.ControlChan = pAd->CommonCfg.Channel; ++ // 1, the extension channel above the control channel. ++ ++ // EDCA parameters used for AP's own transmission ++ if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) ++ { ++ pAd->CommonCfg.APEdcaParm.bValid = TRUE; ++ pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; ++ pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; ++ pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; ++ pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; ++ pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmax[0] = 6; ++ pAd->CommonCfg.APEdcaParm.Cwmax[1] = 10; ++ pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; ++ ++ pAd->CommonCfg.APEdcaParm.Txop[0] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[1] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[2] = 94; ++ pAd->CommonCfg.APEdcaParm.Txop[3] = 47; ++ } ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ RTMPSetIndividualHT(pAd, 0); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Caller ensures we has 802.11n support. ++ Calls at setting HT from AP/STASetinformation ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ phymode - ++ ++ ======================================================================== ++*/ ++VOID RTMPSetIndividualHT( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx) ++{ ++ PRT_HT_PHY_INFO pDesired_ht_phy = NULL; ++ UCHAR TxStream = pAd->CommonCfg.TxStream; ++ UCHAR DesiredMcs = MCS_AUTO; ++ ++ do ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pDesired_ht_phy = &pAd->StaCfg.DesiredHtPhyInfo; ++ DesiredMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; ++ //pAd->StaCfg.bAutoTxRateSwitch = (DesiredMcs == MCS_AUTO) ? TRUE : FALSE; ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } while (FALSE); ++ ++ if (pDesired_ht_phy == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSetIndividualHT: invalid apidx(%d)\n", apidx)); ++ return; ++ } ++ RTMPZeroMemory(pDesired_ht_phy, sizeof(RT_HT_PHY_INFO)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetIndividualHT : Desired MCS = %d\n", DesiredMcs)); ++ // Check the validity of MCS ++ if ((TxStream == 1) && ((DesiredMcs >= MCS_8) && (DesiredMcs <= MCS_15))) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS(%d) is invalid in 1S, reset it as MCS_7\n", DesiredMcs)); ++ DesiredMcs = MCS_7; ++ } ++ ++ if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_20) && (DesiredMcs == MCS_32)) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetIndividualHT: MCS_32 is only supported in 40-MHz, reset it as MCS_0\n")); ++ DesiredMcs = MCS_0; ++ } ++ ++ pDesired_ht_phy->bHtEnable = TRUE; ++ ++ // Decide desired Tx MCS ++ switch (TxStream) ++ { ++ case 1: ++ if (DesiredMcs == MCS_AUTO) ++ { ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0x00; ++ } ++ else if (DesiredMcs <= MCS_7) ++ { ++ pDesired_ht_phy->MCSSet[0]= 1<MCSSet[1]= 0x00; ++ } ++ break; ++ ++ case 2: ++ if (DesiredMcs == MCS_AUTO) ++ { ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0xff; ++ } ++ else if (DesiredMcs <= MCS_15) ++ { ++ ULONG mode; ++ ++ mode = DesiredMcs / 8; ++ if (mode < 2) ++ pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); ++ } ++ break; ++ ++ case 3: // 3*3 ++ if (DesiredMcs == MCS_AUTO) ++ { ++ /* MCS0 ~ MCS23, 3 bytes */ ++ pDesired_ht_phy->MCSSet[0]= 0xff; ++ pDesired_ht_phy->MCSSet[1]= 0xff; ++ pDesired_ht_phy->MCSSet[2]= 0xff; ++ } ++ else if (DesiredMcs <= MCS_23) ++ { ++ ULONG mode; ++ ++ mode = DesiredMcs / 8; ++ if (mode < 3) ++ pDesired_ht_phy->MCSSet[mode] = (1 << (DesiredMcs - mode * 8)); ++ } ++ break; ++ } ++ ++ if(pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BW_40) ++ { ++ if (DesiredMcs == MCS_AUTO || DesiredMcs == MCS_32) ++ pDesired_ht_phy->MCSSet[4] = 0x1; ++ } ++ ++ // update HT Rate setting ++ if (pAd->OpMode == OPMODE_STA) ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ else ++ MlmeUpdateHtTxRates(pAd, apidx); ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Update HT IE from our capability. ++ ++ Arguments: ++ Send all HT IE in beacon/probe rsp/assoc rsp/action frame. ++ ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateHTIE( ++ IN RT_HT_CAPABILITY *pRtHt, ++ IN UCHAR *pMcsSet, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo) ++{ ++ RTMPZeroMemory(pHtCapability, sizeof(HT_CAPABILITY_IE)); ++ RTMPZeroMemory(pAddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ pHtCapability->HtCapInfo.ChannelWidth = pRtHt->ChannelWidth; ++ pHtCapability->HtCapInfo.MimoPs = pRtHt->MimoPs; ++ pHtCapability->HtCapInfo.GF = pRtHt->GF; ++ pHtCapability->HtCapInfo.ShortGIfor20 = pRtHt->ShortGIfor20; ++ pHtCapability->HtCapInfo.ShortGIfor40 = pRtHt->ShortGIfor40; ++ pHtCapability->HtCapInfo.TxSTBC = pRtHt->TxSTBC; ++ pHtCapability->HtCapInfo.RxSTBC = pRtHt->RxSTBC; ++ pHtCapability->HtCapInfo.AMsduSize = pRtHt->AmsduSize; ++ pHtCapability->HtCapParm.MaxRAmpduFactor = pRtHt->MaxRAmpduFactor; ++ pHtCapability->HtCapParm.MpduDensity = pRtHt->MpduDensity; ++ ++ pAddHtInfo->AddHtInfo.ExtChanOffset = pRtHt->ExtChanOffset ; ++ pAddHtInfo->AddHtInfo.RecomWidth = pRtHt->RecomWidth; ++ pAddHtInfo->AddHtInfo2.OperaionMode = pRtHt->OperaionMode; ++ pAddHtInfo->AddHtInfo2.NonGfPresent = pRtHt->NonGfPresent; ++ RTMPMoveMemory(pAddHtInfo->MCSSet, /*pRtHt->MCSSet*/pMcsSet, 4); // rt2860 only support MCS max=32, no need to copy all 16 uchar. ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPUpdateHTIE <== \n")); ++} ++#endif // DOT11_N_SUPPORT // ++ ++/* ++ ======================================================================== ++ Description: ++ Add Client security information into ASIC WCID table and IVEIV table. ++ Return: ++ ======================================================================== ++*/ ++VOID RTMPAddWcidAttributeEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ UINT32 WCIDAttri = 0; ++ USHORT offset; ++ UCHAR IVEIV = 0; ++ USHORT Wcid = 0; ++ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (BssIdx > BSS0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPAddWcidAttributeEntry: The BSS-index(%d) is out of range for Infra link. \n", BssIdx)); ++ return; ++ } ++ ++ // 1. In ADHOC mode, the AID is wcid number. And NO mesh link exists. ++ // 2. In Infra mode, the AID:1 MUST be wcid of infra STA. ++ // the AID:2~ assign to mesh link entry. ++ if (pEntry && ADHOC_ON(pAd)) ++ Wcid = pEntry->Aid; ++ else if (pEntry && INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (pEntry->ValidAsDls == TRUE) ++ Wcid = pEntry->Aid; ++ else ++#endif // QOS_DLS_SUPPORT // ++ Wcid = BSSID_WCID; ++ } ++ else ++ Wcid = MCAST_WCID; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // Update WCID attribute table ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pEntry && pEntry->ValidAsMesh) ++ WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; ++#ifdef QOS_DLS_SUPPORT ++ else if ((pEntry) && (pEntry->ValidAsDls) && ++ ((CipherAlg == CIPHER_TKIP) || ++ (CipherAlg == CIPHER_TKIP_NO_MIC) || ++ (CipherAlg == CIPHER_AES) || ++ (CipherAlg == CIPHER_NONE))) ++ WCIDAttri = (CipherAlg<<1) | PAIRWISEKEYTABLE; ++#endif // QOS_DLS_SUPPORT // ++ else ++ WCIDAttri = (CipherAlg<<1) | SHAREDKEYTABLE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++ ++ ++ // Update IV/EIV table ++ offset = MAC_IVEIV_TABLE_BASE + (Wcid * HW_IVEIV_ENTRY_SIZE); ++ ++ // WPA mode ++ if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) || (CipherAlg == CIPHER_AES)) ++ { ++ // Eiv bit on. keyid always is 0 for pairwise key ++ IVEIV = (KeyIdx <<6) | 0x20; ++ } ++ else ++ { ++ // WEP KeyIdx is default tx key. ++ IVEIV = (KeyIdx << 6); ++ } ++ ++ // For key index and ext IV bit, so only need to update the position(offset+3). ++#ifdef RT2870 ++ RTUSBMultiWrite_OneByte(pAd, offset+3, &IVEIV); ++#endif // RT2870 // ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); ++ DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Parse encryption type ++Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ ========================================================================== ++*/ ++CHAR *GetEncryptType(CHAR enc) ++{ ++ if(enc == Ndis802_11WEPDisabled) ++ return "NONE"; ++ if(enc == Ndis802_11WEPEnabled) ++ return "WEP"; ++ if(enc == Ndis802_11Encryption2Enabled) ++ return "TKIP"; ++ if(enc == Ndis802_11Encryption3Enabled) ++ return "AES"; ++ if(enc == Ndis802_11Encryption4Enabled) ++ return "TKIPAES"; ++ else ++ return "UNKNOW"; ++} ++ ++CHAR *GetAuthMode(CHAR auth) ++{ ++ if(auth == Ndis802_11AuthModeOpen) ++ return "OPEN"; ++ if(auth == Ndis802_11AuthModeShared) ++ return "SHARED"; ++ if(auth == Ndis802_11AuthModeAutoSwitch) ++ return "AUTOWEP"; ++ if(auth == Ndis802_11AuthModeWPA) ++ return "WPA"; ++ if(auth == Ndis802_11AuthModeWPAPSK) ++ return "WPAPSK"; ++ if(auth == Ndis802_11AuthModeWPANone) ++ return "WPANONE"; ++ if(auth == Ndis802_11AuthModeWPA2) ++ return "WPA2"; ++ if(auth == Ndis802_11AuthModeWPA2PSK) ++ return "WPA2PSK"; ++ if(auth == Ndis802_11AuthModeWPA1WPA2) ++ return "WPA1WPA2"; ++ if(auth == Ndis802_11AuthModeWPA1PSKWPA2PSK) ++ return "WPA1PSKWPA2PSK"; ++ ++ return "UNKNOW"; ++} ++ ++#if 1 //#ifndef UCOS ++/* ++ ========================================================================== ++ Description: ++ Get site survey results ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) UI needs to wait 4 seconds after issue a site survey command ++ 2.) iwpriv ra0 get_site_survey ++ 3.) UI needs to prepare at least 4096bytes to get the results ++ ========================================================================== ++*/ ++#define LINE_LEN (4+33+20+8+10+9+7+3) // Channel+SSID+Bssid+WepStatus+AuthMode+Signal+WiressMode+NetworkType ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++VOID RTMPIoctlGetSiteSurvey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *msg; ++ INT i=0; ++ INT WaitCnt; ++ INT Status=0; ++ CHAR Ssid[MAX_LEN_OF_SSID +1]; ++ INT Rssi = 0, max_len = LINE_LEN; ++ UINT Rssi_Quality = 0; ++ NDIS_802_11_NETWORK_TYPE wireless_mode; ++ ++ os_alloc_mem(NULL, (PUCHAR *)&msg, sizeof(CHAR)*((MAX_LEN_OF_BSS_TABLE)*max_len)); ++ ++ if (msg == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - msg memory alloc fail.\n")); ++ return; ++ } ++ ++ memset(msg, 0 ,(MAX_LEN_OF_BSS_TABLE)*max_len ); ++ memset(Ssid, 0 ,(MAX_LEN_OF_SSID +1)); ++ sprintf(msg,"%s","\n"); ++ sprintf(msg+strlen(msg),"%-4s%-33s%-20s%-8s%-10s%-9s%-7s%-3s\n", ++ "Ch", "SSID", "BSSID", "Enc", "Auth", "Siganl(%)", "W-Mode", " NT"); ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ WaitCnt = 0; ++#ifdef CONFIG_STA_SUPPORT ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ while ((ScanRunning(pAdapter) == TRUE) && (WaitCnt++ < 200)) ++ OS_WAIT(500); ++#endif // CONFIG_STA_SUPPORT // ++ ++ for(i=0; iScanTab.BssNr ;i++) ++ { ++ if( pAdapter->ScanTab.BssEntry[i].Channel==0) ++ break; ++ ++ if((strlen(msg)+max_len ) >= IW_SCAN_MAX_DATA) ++ break; ++ ++ //Channel ++ sprintf(msg+strlen(msg),"%-4d", pAdapter->ScanTab.BssEntry[i].Channel); ++ //SSID ++ memcpy(Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ Ssid[pAdapter->ScanTab.BssEntry[i].SsidLen] = '\0'; ++ sprintf(msg+strlen(msg),"%-33s", Ssid); ++ //BSSID ++ sprintf(msg+strlen(msg),"%02x:%02x:%02x:%02x:%02x:%02x ", ++ pAdapter->ScanTab.BssEntry[i].Bssid[0], ++ pAdapter->ScanTab.BssEntry[i].Bssid[1], ++ pAdapter->ScanTab.BssEntry[i].Bssid[2], ++ pAdapter->ScanTab.BssEntry[i].Bssid[3], ++ pAdapter->ScanTab.BssEntry[i].Bssid[4], ++ pAdapter->ScanTab.BssEntry[i].Bssid[5]); ++ //Encryption Type ++ sprintf(msg+strlen(msg),"%-8s",GetEncryptType(pAdapter->ScanTab.BssEntry[i].WepStatus)); ++ //Authentication Mode ++ if (pAdapter->ScanTab.BssEntry[i].WepStatus == Ndis802_11WEPEnabled) ++ sprintf(msg+strlen(msg),"%-10s", "UNKNOW"); ++ else ++ sprintf(msg+strlen(msg),"%-10s",GetAuthMode(pAdapter->ScanTab.BssEntry[i].AuthMode)); ++ // Rssi ++ Rssi = (INT)pAdapter->ScanTab.BssEntry[i].Rssi; ++ if (Rssi >= -50) ++ Rssi_Quality = 100; ++ else if (Rssi >= -80) // between -50 ~ -80dbm ++ Rssi_Quality = (UINT)(24 + ((Rssi + 80) * 26)/10); ++ else if (Rssi >= -90) // between -80 ~ -90dbm ++ Rssi_Quality = (UINT)(((Rssi + 90) * 26)/10); ++ else // < -84 dbm ++ Rssi_Quality = 0; ++ sprintf(msg+strlen(msg),"%-9d", Rssi_Quality); ++ // Wireless Mode ++ wireless_mode = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ if (wireless_mode == Ndis802_11FH || ++ wireless_mode == Ndis802_11DS) ++ sprintf(msg+strlen(msg),"%-7s", "11b"); ++ else if (wireless_mode == Ndis802_11OFDM5) ++ sprintf(msg+strlen(msg),"%-7s", "11a"); ++ else if (wireless_mode == Ndis802_11OFDM5_N) ++ sprintf(msg+strlen(msg),"%-7s", "11a/n"); ++ else if (wireless_mode == Ndis802_11OFDM24) ++ sprintf(msg+strlen(msg),"%-7s", "11b/g"); ++ else if (wireless_mode == Ndis802_11OFDM24_N) ++ sprintf(msg+strlen(msg),"%-7s", "11b/g/n"); ++ else ++ sprintf(msg+strlen(msg),"%-7s", "unknow"); ++ //Network Type ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_ADHOC) ++ sprintf(msg+strlen(msg),"%-3s", " Ad"); ++ else ++ sprintf(msg+strlen(msg),"%-3s", " In"); ++ ++ sprintf(msg+strlen(msg),"\n"); ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPIoctlGetSiteSurvey - wrq->u.data.length = %d\n", wrq->u.data.length)); ++ os_free_mem(NULL, (PUCHAR)msg); ++} ++ ++ ++#define MAC_LINE_LEN (14+4+4+10+10+10+6+6) // Addr+aid+psm+datatime+rxbyte+txbyte+current tx rate+last tx rate ++VOID RTMPIoctlGetMacTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq) ++{ ++ INT i; ++ RT_802_11_MAC_TABLE MacTab; ++ char *msg; ++ ++ MacTab.Num = 0; ++ for (i=0; iMacTab.Content[i].ValidAsCLI && (pAd->MacTab.Content[i].Sst == SST_ASSOC)) ++ { ++ COPY_MAC_ADDR(MacTab.Entry[MacTab.Num].Addr, &pAd->MacTab.Content[i].Addr); ++ MacTab.Entry[MacTab.Num].Aid = (UCHAR)pAd->MacTab.Content[i].Aid; ++ MacTab.Entry[MacTab.Num].Psm = pAd->MacTab.Content[i].PsMode; ++#ifdef DOT11_N_SUPPORT ++ MacTab.Entry[MacTab.Num].MimoPs = pAd->MacTab.Content[i].MmpsMode; ++#endif // DOT11_N_SUPPORT // ++ ++ // Fill in RSSI per entry ++ MacTab.Entry[MacTab.Num].AvgRssi0 = pAd->MacTab.Content[i].RssiSample.AvgRssi0; ++ MacTab.Entry[MacTab.Num].AvgRssi1 = pAd->MacTab.Content[i].RssiSample.AvgRssi1; ++ MacTab.Entry[MacTab.Num].AvgRssi2 = pAd->MacTab.Content[i].RssiSample.AvgRssi2; ++ ++ // the connected time per entry ++ MacTab.Entry[MacTab.Num].ConnectedTime = pAd->MacTab.Content[i].StaConnectTime; ++ MacTab.Entry[MacTab.Num].TxRate.field.MCS = pAd->MacTab.Content[i].HTPhyMode.field.MCS; ++ MacTab.Entry[MacTab.Num].TxRate.field.BW = pAd->MacTab.Content[i].HTPhyMode.field.BW; ++ MacTab.Entry[MacTab.Num].TxRate.field.ShortGI = pAd->MacTab.Content[i].HTPhyMode.field.ShortGI; ++ MacTab.Entry[MacTab.Num].TxRate.field.STBC = pAd->MacTab.Content[i].HTPhyMode.field.STBC; ++ MacTab.Entry[MacTab.Num].TxRate.field.rsv = pAd->MacTab.Content[i].HTPhyMode.field.rsv; ++ MacTab.Entry[MacTab.Num].TxRate.field.MODE = pAd->MacTab.Content[i].HTPhyMode.field.MODE; ++ MacTab.Entry[MacTab.Num].TxRate.word = pAd->MacTab.Content[i].HTPhyMode.word; ++ ++ MacTab.Num += 1; ++ } ++ } ++ wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE); ++ if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); ++ } ++ ++ msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG); ++ memset(msg, 0 ,MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN ); ++ sprintf(msg,"%s","\n"); ++ sprintf(msg+strlen(msg),"%-14s%-4s%-4s%-10s%-10s%-10s%-6s%-6s\n", ++ "MAC", "AID", "PSM", "LDT", "RxB", "TxB","CTxR", "LTxR"); ++ ++ for (i=0; iMacTab.Content[i]; ++ if (pEntry->ValidAsCLI && (pEntry->Sst == SST_ASSOC)) ++ { ++ if((strlen(msg)+MAC_LINE_LEN ) >= (MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN) ) ++ break; ++ sprintf(msg+strlen(msg),"%02x%02x%02x%02x%02x%02x ", ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ sprintf(msg+strlen(msg),"%-4d", (int)pEntry->Aid); ++ sprintf(msg+strlen(msg),"%-4d", (int)pEntry->PsMode); ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.LastDataPacketTime*/); // ToDo ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalRxByteCount*/); // ToDo ++ sprintf(msg+strlen(msg),"%-10d",0/*pAd->MacTab.Content[i].HSCounter.TotalTxByteCount*/); // ToDo ++ sprintf(msg+strlen(msg),"%-6d",RateIdToMbps[pAd->MacTab.Content[i].CurrTxRate]); ++ sprintf(msg+strlen(msg),"%-6d\n",0/*RateIdToMbps[pAd->MacTab.Content[i].LastTxRate]*/); // ToDo ++ } ++ } ++ // for compatible with old API just do the printk to console ++ //wrq->u.data.length = strlen(msg); ++ //if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s", msg)); ++ } ++ ++ kfree(msg); ++} ++#endif // UCOS // ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_BASetup_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++/* ++ The BASetup inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ //printk("\n%s\n", arg); ++ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > 15) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x\n", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nSetup BA Session: Tid = %d\n", tid); ++ BAOriSessionSetUp(pAd, pEntry, tid, 0, 100, TRUE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_BADecline_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG bBADecline; ++ ++ bBADecline = simple_strtol(arg, 0, 10); ++ ++ if (bBADecline == 0) ++ { ++ pAd->CommonCfg.bBADecline = FALSE; ++ } ++ else if (bBADecline == 1) ++ { ++ pAd->CommonCfg.bBADecline = TRUE; ++ } ++ else ++ { ++ return FALSE; //Invalid argument ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_BADecline_Proc::(BADecline=%d)\n", pAd->CommonCfg.bBADecline)); ++ ++ return TRUE; ++} ++ ++INT Set_BAOriTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BAOriTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > NUM_OF_TID) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nTear down Ori BA Session: Tid = %d\n", tid); ++ BAOriSessionTearDown(pAd, pEntry->Aid, tid, FALSE, TRUE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_BARecTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], tid; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the tid value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and tid value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ tid = simple_strtol((token+1), 0, 10); ++ if (tid > NUM_OF_TID) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], tid); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nTear down Rec BA Session: Tid = %d\n", tid); ++ BARecSessionTearDown(pAd, pEntry->Aid, tid, FALSE); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtBw; ++ ++ HtBw = simple_strtol(arg, 0, 10); ++ if (HtBw == BW_40) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ else if (HtBw == BW_20) ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBw_Proc::(HtBw=%d)\n", pAd->CommonCfg.RegTransmitSetting.field.BW)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtMcs, Mcs_tmp; ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN bAutoRate = FALSE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ Mcs_tmp = simple_strtol(arg, 0, 10); ++ ++ if (Mcs_tmp <= 15 || Mcs_tmp == 32) ++ HtMcs = Mcs_tmp; ++ else ++ HtMcs = MCS_AUTO; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = HtMcs; ++ pAd->StaCfg.bAutoTxRateSwitch = (HtMcs == MCS_AUTO) ? TRUE:FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(HtMcs=%d, bAutoTxRateSwitch = %d)\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS, pAd->StaCfg.bAutoTxRateSwitch)); ++ ++ if ((pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE < MODE_HTMIX)) ++ { ++ if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && ++ (HtMcs >= 0 && HtMcs <= 3) && ++ (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_CCK)) ++ { ++ RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs] * 1000000)); ++ } ++ else if ((pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) && ++ (HtMcs >= 0 && HtMcs <= 7) && ++ (pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode == FIXED_TXMODE_OFDM)) ++ { ++ RTMPSetDesiredRates(pAd, (LONG) (RateIdToMbps[HtMcs+4] * 1000000)); ++ } ++ else ++ bAutoRate = TRUE; ++ ++ if (bAutoRate) ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ RTMPSetDesiredRates(pAd, -1); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMcs_Proc::(FixedTxMode=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode)); ++ } ++ if (ADHOC_ON(pAd)) ++ return TRUE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ SetCommonHT(pAd); ++ ++ return TRUE; ++} ++ ++INT Set_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG HtGi; ++ ++ HtGi = simple_strtol(arg, 0, 10); ++ ++ if ( HtGi == GI_400) ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; ++ else if ( HtGi == GI_800 ) ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtGi_Proc::(ShortGI=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.ShortGI)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_HtTxBASize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR Size; ++ ++ Size = simple_strtol(arg, 0, 10); ++ ++ if (Size <=0 || Size >=64) ++ { ++ Size = 8; ++ } ++ pAd->CommonCfg.TxBASize = Size-1; ++ DBGPRINT(RT_DEBUG_ERROR, ("Set_HtTxBASize ::(TxBASize= %d)\n", Size)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == HTMODE_GF) ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; ++ else if ( Value == HTMODE_MM ) ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtOpMode_Proc::(HtOpMode=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.HTMODE)); ++ ++ return TRUE; ++ ++} ++ ++INT Set_HtStbc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == STBC_USE) ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; ++ else if ( Value == STBC_NONE ) ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Stbc_Proc::(HtStbc=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.STBC)); ++ ++ return TRUE; ++} ++ ++INT Set_HtHtc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->HTCEnable = FALSE; ++ else if ( Value ==1 ) ++ pAd->HTCEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtHtc_Proc::(HtHtc=%d)\n",pAd->HTCEnable)); ++ ++ return TRUE; ++} ++ ++INT Set_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == 0) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ else if ( Value ==1 ) ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtExtcha_Proc::(HtExtcha=%d)\n",pAd->CommonCfg.RegTransmitSetting.field.EXTCHA)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value <=7 && Value >= 0) ++ pAd->CommonCfg.BACapability.field.MpduDensity = Value; ++ else ++ pAd->CommonCfg.BACapability.field.MpduDensity = 4; ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMpduDensity_Proc::(HtMpduDensity=%d)\n",pAd->CommonCfg.BACapability.field.MpduDensity)); ++ ++ return TRUE; ++} ++ ++INT Set_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ ++ if (Value >=1 && Value <= 64) ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; ++ } ++ else ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; ++ } ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtBaWinSize_Proc::(HtBaWinSize=%d)\n",pAd->CommonCfg.BACapability.field.RxBAWinLimit)); ++ ++ return TRUE; ++} ++ ++INT Set_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value == 0) ++ pAd->CommonCfg.bRdg = FALSE; ++ else if ( Value ==1 ) ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->CommonCfg.bRdg = TRUE; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtRdg_Proc::(HtRdg=%d)\n",pAd->CommonCfg.bRdg)); ++ ++ return TRUE; ++} ++ ++INT Set_HtLinkAdapt_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->bLinkAdapt = FALSE; ++ else if ( Value ==1 ) ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->bLinkAdapt = TRUE; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtLinkAdapt_Proc::(HtLinkAdapt=%d)\n",pAd->bLinkAdapt)); ++ ++ return TRUE; ++} ++ ++INT Set_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; ++ else if ( Value == 1 ) ++ pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAmsdu_Proc::(HtAmsdu=%d)\n",pAd->CommonCfg.BACapability.field.AmsduEnable)); ++ ++ return TRUE; ++} ++ ++INT Set_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ pAd->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ } ++ else if (Value == 1) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; ++ } ++ else ++ return FALSE; //Invalid argument ++ ++ pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; ++ pAd->CommonCfg.REGBACapability.field.Policy = pAd->CommonCfg.BACapability.field.Policy; ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtAutoBa_Proc::(HtAutoBa=%d)\n",pAd->CommonCfg.BACapability.field.AutoBA)); ++ ++ return TRUE; ++ ++} ++ ++INT Set_HtProtect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.bHTProtect = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.bHTProtect = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtProtect_Proc::(HtProtect=%d)\n",pAd->CommonCfg.bHTProtect)); ++ ++ return TRUE; ++} ++ ++INT Set_SendPSMPAction_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[6], mode; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ //printk("\n%s\n", arg); ++/* ++ The BARecTearDown inupt string format should be xx:xx:xx:xx:xx:xx-d, ++ =>The six 2 digit hex-decimal number previous are the Mac address, ++ =>The seventh decimal number is the mode value. ++*/ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and mode value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ mode = simple_strtol((token+1), 0, 10); ++ if (mode > MMPS_ENABLE) ++ return FALSE; ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%02x", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], mode); ++ ++ pEntry = MacTableLookup(pAd, mac); ++ ++ if (pEntry) { ++ printk("\nSendPSMPAction MIPS mode = %d\n", mode); ++ SendPSMPAction(pAd, pEntry->Aid, mode); ++ } ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++ ++} ++ ++INT Set_HtMIMOPSmode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ if (Value <=3 && Value >= 0) ++ pAd->CommonCfg.BACapability.field.MMPSmode = Value; ++ else ++ pAd->CommonCfg.BACapability.field.MMPSmode = 3; ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMIMOPSmode_Proc::(MIMOPS mode=%d)\n",pAd->CommonCfg.BACapability.field.MMPSmode)); ++ ++ return TRUE; ++} ++ ++ ++INT Set_ForceShortGI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->WIFItestbed.bShortGI = FALSE; ++ else if (Value == 1) ++ pAd->WIFItestbed.bShortGI = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceShortGI_Proc::(ForceShortGI=%d)\n", pAd->WIFItestbed.bShortGI)); ++ ++ return TRUE; ++} ++ ++ ++ ++INT Set_ForceGF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->WIFItestbed.bGreenField = FALSE; ++ else if (Value == 1) ++ pAd->WIFItestbed.bGreenField = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ SetCommonHT(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_ForceGF_Proc::(ForceGF=%d)\n", pAd->WIFItestbed.bGreenField)); ++ ++ return TRUE; ++} ++ ++INT Set_HtMimoPs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ if (Value == 0) ++ pAd->CommonCfg.bMIMOPSEnable = FALSE; ++ else if (Value == 1) ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_HtMimoPs_Proc::(HtMimoPs=%d)\n",pAd->CommonCfg.bMIMOPSEnable)); ++ ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++INT SetCommonHT( ++ IN PRTMP_ADAPTER pAd) ++{ ++ OID_SET_HT_PHYMODE SetHT; ++ ++ if (pAd->CommonCfg.PhyMode < PHY_11ABGN_MIXED) ++ return FALSE; ++ ++ SetHT.PhyMode = pAd->CommonCfg.PhyMode; ++ SetHT.TransmitNo = ((UCHAR)pAd->Antenna.field.TxPath); ++ SetHT.HtMode = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.HTMODE; ++ SetHT.ExtOffset = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.EXTCHA; ++ SetHT.MCS = MCS_AUTO; ++ SetHT.BW = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.BW; ++ SetHT.STBC = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.STBC; ++ SetHT.SHORTGI = (UCHAR)pAd->CommonCfg.RegTransmitSetting.field.ShortGI; ++ ++ RTMPSetHT(pAd, &SetHT); ++ ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_FixedTxMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR fix_tx_mode = FIXED_TXMODE_HT; ++ ++ if (strcmp(arg, "OFDM") == 0 || strcmp(arg, "ofdm") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_OFDM; ++ } ++ else if (strcmp(arg, "CCK") == 0 || strcmp(arg, "cck") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_CCK; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_FixedTxMode_Proc::(FixedTxMode=%d)\n", fix_tx_mode)); ++ ++ return TRUE; ++} ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++INT Set_OpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ULONG Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++#ifdef RT2870 ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++#endif // RT2870 // ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); ++ return FALSE; ++ } ++ ++ if (Value == 0) ++ pAd->OpMode = OPMODE_STA; ++ else if (Value == 1) ++ pAd->OpMode = OPMODE_AP; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_OpMode_Proc::(OpMode=%s)\n", pAd->OpMode == 1 ? "AP Mode" : "STA Mode")); ++ ++ return TRUE; ++} ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++ ++///////////////////////////////////////////////////////////////////////// ++PCHAR RTMPGetRalinkAuthModeStr( ++ IN NDIS_802_11_AUTHENTICATION_MODE authMode) ++{ ++ switch(authMode) ++ { ++ case Ndis802_11AuthModeOpen: ++ return "OPEN"; ++ default: ++ case Ndis802_11AuthModeWPAPSK: ++ return "WPAPSK"; ++ case Ndis802_11AuthModeShared: ++ return "SHARED"; ++ case Ndis802_11AuthModeWPA: ++ return "WPA"; ++ case Ndis802_11AuthModeWPA2: ++ return "WPA2"; ++ case Ndis802_11AuthModeWPA2PSK: ++ return "WPA2PSK"; ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ return "WPAPSKWPA2PSK"; ++ case Ndis802_11AuthModeWPA1WPA2: ++ return "WPA1WPA2"; ++ } ++} ++ ++PCHAR RTMPGetRalinkEncryModeStr( ++ IN USHORT encryMode) ++{ ++ switch(encryMode) ++ { ++ default: ++ case Ndis802_11WEPDisabled: ++ return "NONE"; ++ case Ndis802_11WEPEnabled: ++ return "WEP"; ++ case Ndis802_11Encryption2Enabled: ++ return "TKIP"; ++ case Ndis802_11Encryption3Enabled: ++ return "AES"; ++ case Ndis802_11Encryption4Enabled: ++ return "TKIPAES"; ++ } ++} ++ ++INT RTMPShowCfgValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pName, ++ IN PUCHAR pBuf) ++{ ++ INT Status = 0; ++ ++ for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) ++ { ++ if (!strcmp(pName, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name)) ++ { ++ if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->show_proc(pAd, pBuf)) ++ Status = -EINVAL; ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name == NULL) ++ { ++ sprintf(pBuf, "\n"); ++ for (PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC = RTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name; PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC++) ++ sprintf(pBuf, "%s%s\n", pBuf, PRTMP_PRIVATE_STA_SHOW_CFG_VALUE_PROC->name); ++ } ++ ++ return Status; ++} ++ ++INT Show_SSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.Ssid); ++#endif // CONFIG_STA_SUPPORT // ++ return 0; ++} ++ ++INT Show_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11BG_MIXED: ++ sprintf(pBuf, "\t11B/G"); ++ break; ++ case PHY_11B: ++ sprintf(pBuf, "\t11B"); ++ break; ++ case PHY_11A: ++ sprintf(pBuf, "\t11A"); ++ break; ++ case PHY_11ABG_MIXED: ++ sprintf(pBuf, "\t11A/B/G"); ++ break; ++ case PHY_11G: ++ sprintf(pBuf, "\t11G"); ++ break; ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++ sprintf(pBuf, "\t11A/B/G/N"); ++ break; ++ case PHY_11N_2_4G: ++ sprintf(pBuf, "\t11N only with 2.4G"); ++ break; ++ case PHY_11GN_MIXED: ++ sprintf(pBuf, "\t11G/N"); ++ break; ++ case PHY_11AN_MIXED: ++ sprintf(pBuf, "\t11A/N"); ++ break; ++ case PHY_11BGN_MIXED: ++ sprintf(pBuf, "\t11B/G/N"); ++ break; ++ case PHY_11AGN_MIXED: ++ sprintf(pBuf, "\t11A/G/N"); ++ break; ++ case PHY_11N_5G: ++ sprintf(pBuf, "\t11N only with 5G"); ++ break; ++#endif // DOT11_N_SUPPORT // ++ default: ++ sprintf(pBuf, "\tUnknow Value(%d)", pAd->CommonCfg.PhyMode); ++ break; ++ } ++ return 0; ++} ++ ++ ++INT Show_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bEnableTxBurst ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.TxPreamble) ++ { ++ case Rt802_11PreambleShort: ++ sprintf(pBuf, "\tShort"); ++ break; ++ case Rt802_11PreambleLong: ++ sprintf(pBuf, "\tLong"); ++ break; ++ case Rt802_11PreambleAuto: ++ sprintf(pBuf, "\tAuto"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.TxPreamble); ++ break; ++ } ++ ++ return 0; ++} ++ ++INT Show_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%lu", pAd->CommonCfg.TxPowerPercentage); ++ return 0; ++} ++ ++INT Show_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.Channel); ++ return 0; ++} ++ ++INT Show_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.UseBGProtection) ++ { ++ case 1: //Always On ++ sprintf(pBuf, "\tON"); ++ break; ++ case 2: //Always OFF ++ sprintf(pBuf, "\tOFF"); ++ break; ++ case 0: //AUTO ++ sprintf(pBuf, "\tAuto"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%lu)", pAd->CommonCfg.UseBGProtection); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.RtsThreshold); ++ return 0; ++} ++ ++INT Show_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.FragmentThreshold); ++ return 0; ++} ++ ++#ifdef DOT11_N_SUPPORT ++INT Show_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ if (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40) ++ { ++ sprintf(pBuf, "\t40 MHz"); ++ } ++ else ++ { ++ sprintf(pBuf, "\t20 MHz"); ++ } ++ return 0; ++} ++ ++INT Show_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%u", pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++#endif // CONFIG_STA_SUPPORT // ++ return 0; ++} ++ ++INT Show_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.ShortGI) ++ { ++ case GI_400: ++ sprintf(pBuf, "\tGI_400"); ++ break; ++ case GI_800: ++ sprintf(pBuf, "\tGI_800"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.ShortGI); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.HTMODE) ++ { ++ case HTMODE_GF: ++ sprintf(pBuf, "\tGF"); ++ break; ++ case HTMODE_MM: ++ sprintf(pBuf, "\tMM"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.HTMODE); ++ break; ++ } ++ return 0; ++} ++ ++INT Show_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->CommonCfg.RegTransmitSetting.field.EXTCHA) ++ { ++ case EXTCHA_BELOW: ++ sprintf(pBuf, "\tBelow"); ++ break; ++ case EXTCHA_ABOVE: ++ sprintf(pBuf, "\tAbove"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%u)", pAd->CommonCfg.RegTransmitSetting.field.EXTCHA); ++ break; ++ } ++ return 0; ++} ++ ++ ++INT Show_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.MpduDensity); ++ return 0; ++} ++ ++INT Show_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%u", pAd->CommonCfg.BACapability.field.RxBAWinLimit); ++ return 0; ++} ++ ++INT Show_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bRdg ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AmsduEnable ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++INT Show_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.BACapability.field.AutoBA ? "TRUE":"FALSE"); ++ return 0; ++} ++#endif // DOT11_N_SUPPORT // ++ ++INT Show_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegion); ++ return 0; ++} ++ ++INT Show_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%d", pAd->CommonCfg.CountryRegionForABand); ++ return 0; ++} ++ ++INT Show_CountryCode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.CountryCode); ++ return 0; ++} ++ ++#ifdef AGGREGATION_SUPPORT ++INT Show_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bAggregationCapable ? "TRUE":"FALSE"); ++ return 0; ++} ++#endif // AGGREGATION_SUPPORT // ++ ++#ifdef WMM_SUPPORT ++INT Show_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bWmmCapable ? "TRUE":"FALSE"); ++#endif // CONFIG_STA_SUPPORT // ++ ++ return 0; ++} ++#endif // WMM_SUPPORT // ++ ++INT Show_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ sprintf(pBuf, "\t%s", pAd->CommonCfg.bIEEE80211H ? "TRUE":"FALSE"); ++ return 0; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++INT Show_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ switch(pAd->StaCfg.BssType) ++ { ++ case BSS_ADHOC: ++ sprintf(pBuf, "\tAdhoc"); ++ break; ++ case BSS_INFRA: ++ sprintf(pBuf, "\tInfra"); ++ break; ++ case BSS_ANY: ++ sprintf(pBuf, "\tAny"); ++ break; ++ case BSS_MONITOR: ++ sprintf(pBuf, "\tMonitor"); ++ break; ++ default: ++ sprintf(pBuf, "\tUnknow Value(%d)", pAd->StaCfg.BssType); ++ break; ++ } ++ return 0; ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Show_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeOpen; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AuthMode = pAd->StaCfg.AuthMode; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((AuthMode >= Ndis802_11AuthModeOpen) && ++ (AuthMode <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ sprintf(pBuf, "\t%s", RTMPGetRalinkAuthModeStr(AuthMode)); ++ else ++ sprintf(pBuf, "\tUnknow Value(%d)", AuthMode); ++ ++ return 0; ++} ++ ++INT Show_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ NDIS_802_11_WEP_STATUS WepStatus = Ndis802_11WEPDisabled; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ WepStatus = pAd->StaCfg.WepStatus; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if ((WepStatus >= Ndis802_11WEPEnabled) && ++ (WepStatus <= Ndis802_11Encryption4KeyAbsent)) ++ sprintf(pBuf, "\t%s", RTMPGetRalinkEncryModeStr(WepStatus)); ++ else ++ sprintf(pBuf, "\tUnknow Value(%d)", WepStatus); ++ ++ return 0; ++} ++ ++INT Show_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ UCHAR DefaultKeyId = 0; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ DefaultKeyId = pAd->StaCfg.DefaultKeyId; ++#endif // CONFIG_STA_SUPPORT // ++ ++ sprintf(pBuf, "\t%d", DefaultKeyId); ++ ++ return 0; ++} ++ ++INT Show_WepKey_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN INT KeyIdx, ++ OUT PUCHAR pBuf) ++{ ++ UCHAR Key[16] = {0}, KeyLength = 0; ++ INT index = BSS0; ++ ++ KeyLength = pAd->SharedKey[index][KeyIdx].KeyLen; ++ NdisMoveMemory(Key, pAd->SharedKey[index][KeyIdx].Key, KeyLength); ++ ++ //check key string is ASCII or not ++ if (RTMPCheckStrPrintAble(Key, KeyLength)) ++ sprintf(pBuf, "\t%s", Key); ++ else ++ { ++ int idx; ++ sprintf(pBuf, "\t"); ++ for (idx = 0; idx < KeyLength; idx++) ++ sprintf(pBuf+strlen(pBuf), "%02X", Key[idx]); ++ } ++ return 0; ++} ++ ++INT Show_Key1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 0, pBuf); ++ return 0; ++} ++ ++INT Show_Key2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 1, pBuf); ++ return 0; ++} ++ ++INT Show_Key3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 2, pBuf); ++ return 0; ++} ++ ++INT Show_Key4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ Show_WepKey_Proc(pAd, 3, pBuf); ++ return 0; ++} ++ ++INT Show_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pBuf) ++{ ++ INT idx; ++ UCHAR PMK[32] = {0}; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(PMK, pAd->StaCfg.PMK, 32); ++#endif // CONFIG_STA_SUPPORT // ++ ++ sprintf(pBuf, "\tPMK = "); ++ for (idx = 0; idx < 32; idx++) ++ sprintf(pBuf+strlen(pBuf), "%02X", PMK[idx]); ++ ++ return 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/cmm_sanity.c +@@ -0,0 +1,1669 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sanity.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 add WMM support ++*/ ++#include "../rt_config.h" ++ ++ ++extern UCHAR CISCO_OUI[]; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR BROADCOM_OUI[]; ++extern UCHAR WPS_OUI[]; ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeAddBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2) ++{ ++ PMLME_ADDBA_REQ_STRUCT pInfo; ++ ++ pInfo = (MLME_ADDBA_REQ_STRUCT *)Msg; ++ ++ if ((MsgLen != sizeof(MLME_ADDBA_REQ_STRUCT))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - The peer Mac is not associated yet.\n")); ++ return FALSE; ++ } ++ ++ /* ++ if ((pInfo->BaBufSize > MAX_RX_REORDERBUF) || (pInfo->BaBufSize < 2)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - Rx Reordering buffer too big or too small\n")); ++ return FALSE; ++ } ++ */ ++ ++ if ((pInfo->pAddr[0]&0x01) == 0x01) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAddBAReqSanity fail - broadcast address not support BA\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeDelBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen) ++{ ++ MLME_DELBA_REQ_STRUCT *pInfo; ++ pInfo = (MLME_DELBA_REQ_STRUCT *)Msg; ++ ++ if ((MsgLen != sizeof(MLME_DELBA_REQ_STRUCT))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->Wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer Mac is not associated yet.\n")); ++ return FALSE; ++ } ++ ++ if ((pInfo->TID & 0xf0)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - The peer TID is incorrect.\n")); ++ return FALSE; ++ } ++ ++ if (NdisEqualMemory(pAd->MacTab.Content[pInfo->Wcid].Addr, pInfo->Addr, MAC_ADDR_LEN) == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MlmeDelBAReqSanity fail - the peer addr dosen't exist.\n")); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerAddBAReqActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_ADDBA_REQ pAddFrame; ++ pAddFrame = (PFRAME_ADDBA_REQ)(pMsg); ++ if (MsgLen < (sizeof(FRAME_ADDBA_REQ))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ // we support immediate BA. ++ *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); ++ pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); ++ pAddFrame->BaStartSeq.word = cpu2le16(pAddFrame->BaStartSeq.word); ++ ++ if (pAddFrame->BaParm.BAPolicy != IMMED_BA) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); ++ DBGPRINT(RT_DEBUG_ERROR,("ADDBA Request. tid=%x, Bufsize=%x, AMSDUSupported=%x \n", pAddFrame->BaParm.TID, pAddFrame->BaParm.BufSize, pAddFrame->BaParm.AMSDUSupported)); ++ return FALSE; ++ } ++ ++ // we support immediate BA. ++ if (pAddFrame->BaParm.TID &0xfff0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Request incorrect TID = %d\n", pAddFrame->BaParm.TID)); ++ return FALSE; ++ } ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ return TRUE; ++} ++ ++BOOLEAN PeerAddBARspActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen) ++{ ++ //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_ADDBA_RSP pAddFrame; ++ ++ pAddFrame = (PFRAME_ADDBA_RSP)(pMsg); ++ if (MsgLen < (sizeof(FRAME_ADDBA_RSP))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response frame length size = %ld incorrect\n", MsgLen)); ++ return FALSE; ++ } ++ // we support immediate BA. ++ *(USHORT *)(&pAddFrame->BaParm) = cpu2le16(*(USHORT *)(&pAddFrame->BaParm)); ++ pAddFrame->StatusCode = cpu2le16(pAddFrame->StatusCode); ++ pAddFrame->TimeOutValue = cpu2le16(pAddFrame->TimeOutValue); ++ ++ if (pAddFrame->BaParm.BAPolicy != IMMED_BA) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBAReqActionSanity: ADDBA Response Ba Policy[%d] not support\n", pAddFrame->BaParm.BAPolicy)); ++ return FALSE; ++ } ++ ++ // we support immediate BA. ++ if (pAddFrame->BaParm.TID &0xfff0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("PeerAddBARspActionSanity: ADDBA Response incorrect TID = %d\n", pAddFrame->BaParm.TID)); ++ return FALSE; ++ } ++ return TRUE; ++ ++} ++ ++BOOLEAN PeerDelBAActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN VOID *pMsg, ++ IN ULONG MsgLen ) ++{ ++ //PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PFRAME_DELBA_REQ pDelFrame; ++ if (MsgLen != (sizeof(FRAME_DELBA_REQ))) ++ return FALSE; ++ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ pDelFrame = (PFRAME_DELBA_REQ)(pMsg); ++ ++ *(USHORT *)(&pDelFrame->DelbaParm) = cpu2le16(*(USHORT *)(&pDelFrame->DelbaParm)); ++ pDelFrame->ReasonCode = cpu2le16(pDelFrame->ReasonCode); ++ ++ if (pDelFrame->DelbaParm.TID &0xfff0) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgChannel, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pBssType, ++ OUT USHORT *pBeaconPeriod, ++ OUT UCHAR *pChannel, ++ OUT UCHAR *pNewChannel, ++ OUT LARGE_INTEGER *pTimestamp, ++ OUT CF_PARM *pCfParm, ++ OUT USHORT *pAtimWin, ++ OUT USHORT *pCapabilityInfo, ++ OUT UCHAR *pErp, ++ OUT UCHAR *pDtimCount, ++ OUT UCHAR *pDtimPeriod, ++ OUT UCHAR *pBcastFlag, ++ OUT UCHAR *pMessageToMe, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT UCHAR *pCkipFlag, ++ OUT UCHAR *pAironetCellPowerLimit, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT PQBSS_LOAD_PARM pQbssLoad, ++ OUT PQOS_CAPABILITY_PARM pQosCapability, ++ OUT ULONG *pRalinkIe, ++ OUT UCHAR *pHtCapabilityLen, ++#ifdef CONFIG_STA_SUPPORT ++ OUT UCHAR *pPreNHtCapabilityLen, ++#endif // CONFIG_STA_SUPPORT // ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT UCHAR *AddHtInfoLen, ++ OUT ADD_HT_INFO_IE *AddHtInfo, ++ OUT UCHAR *NewExtChannelOffset, // Ht extension channel offset(above or below) ++ OUT USHORT *LengthVIE, ++ OUT PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ CHAR *Ptr; ++#ifdef CONFIG_STA_SUPPORT ++ CHAR TimLen; ++#endif // CONFIG_STA_SUPPORT // ++ PFRAME_802_11 pFrame; ++ PEID_STRUCT pEid; ++ UCHAR SubType; ++ UCHAR Sanity; ++ //UCHAR ECWMin, ECWMax; ++ //MAC_CSR9_STRUC Csr9; ++ ULONG Length = 0; ++ ++ // For some 11a AP which didn't have DS_IE, we use two conditions to decide the channel ++ // 1. If the AP is 11n enabled, then check the control channel. ++ // 2. If the AP didn't have any info about channel, use the channel we received this frame as the channel. (May inaccuracy!!) ++ UCHAR CtrlChannel = 0; ++ ++ // Add for 3 necessary EID field check ++ Sanity = 0; ++ ++ *pAtimWin = 0; ++ *pErp = 0; ++ *pDtimCount = 0; ++ *pDtimPeriod = 0; ++ *pBcastFlag = 0; ++ *pMessageToMe = 0; ++ *pExtRateLen = 0; ++ *pCkipFlag = 0; // Default of CkipFlag is 0 ++ *pAironetCellPowerLimit = 0xFF; // Default of AironetCellPowerLimit is 0xFF ++ *LengthVIE = 0; // Set the length of VIE to init value 0 ++ *pHtCapabilityLen = 0; // Set the length of VIE to init value 0 ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ *pPreNHtCapabilityLen = 0; // Set the length of VIE to init value 0 ++#endif // CONFIG_STA_SUPPORT // ++ *AddHtInfoLen = 0; // Set the length of VIE to init value 0 ++ *pRalinkIe = 0; ++ *pNewChannel = 0; ++ *NewExtChannelOffset = 0xff; //Default 0xff means no such IE ++ pCfParm->bValid = FALSE; // default: no IE_CF found ++ pQbssLoad->bValid = FALSE; // default: no IE_QBSS_LOAD found ++ pEdcaParm->bValid = FALSE; // default: no IE_EDCA_PARAMETER found ++ pQosCapability->bValid = FALSE; // default: no IE_QOS_CAPABILITY found ++ ++ pFrame = (PFRAME_802_11)Msg; ++ ++ // get subtype from header ++ SubType = (UCHAR)pFrame->Hdr.FC.SubType; ++ ++ // get Addr2 and BSSID from header ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ COPY_MAC_ADDR(pBssid, pFrame->Hdr.Addr3); ++ ++// hex_dump("Beacon", Msg, MsgLen); ++ ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ // get timestamp from payload and advance the pointer ++ NdisMoveMemory(pTimestamp, Ptr, TIMESTAMP_LEN); ++ ++ pTimestamp->u.LowPart = cpu2le32(pTimestamp->u.LowPart); ++ pTimestamp->u.HighPart = cpu2le32(pTimestamp->u.HighPart); ++ ++ Ptr += TIMESTAMP_LEN; ++ Length += TIMESTAMP_LEN; ++ ++ // get beacon interval from payload and advance the pointer ++ NdisMoveMemory(pBeaconPeriod, Ptr, 2); ++ Ptr += 2; ++ Length += 2; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ Length += 2; ++ ++ if (CAP_IS_ESS_ON(*pCapabilityInfo)) ++ *pBssType = BSS_INFRA; ++ else ++ *pBssType = BSS_ADHOC; ++ ++ pEid = (PEID_STRUCT) Ptr; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ // ++ // Secure copy VIE to VarIE[MAX_VIE_LEN] didn't overflow. ++ // ++ if ((*LengthVIE + pEid->Len + 2) >= MAX_VIE_LEN) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - Variable IEs out of resource [len(=%d) > MAX_VIE_LEN(=%d)]\n", ++ (*LengthVIE + pEid->Len + 2), MAX_VIE_LEN)); ++ break; ++ } ++ ++ switch(pEid->Eid) ++ { ++ case IE_SSID: ++ // Already has one SSID EID in this beacon, ignore the second one ++ if (Sanity & 0x1) ++ break; ++ if(pEid->Len <= MAX_LEN_OF_SSID) ++ { ++ NdisMoveMemory(Ssid, pEid->Octet, pEid->Len); ++ *pSsidLen = pEid->Len; ++ Sanity |= 0x1; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_SUPP_RATES: ++ if(pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ Sanity |= 0x2; ++ NdisMoveMemory(SupRate, pEid->Octet, pEid->Len); ++ *pSupRateLen = pEid->Len; ++ ++ // TODO: 2004-09-14 not a good design here, cause it exclude extra rates ++ // from ScanTab. We should report as is. And filter out unsupported ++ // rates in MlmeAux. ++ // Check against the supported rates ++ // RTMPCheckRates(pAd, SupRate, pSupRateLen); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SUPP_RATES (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! ++ { ++ NdisMoveMemory(pHtCapability, pEid->Octet, sizeof(HT_CAPABILITY_IE)); ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ *pPreNHtCapabilityLen = 0; // Nnow we only support 26 bytes. ++ ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_HT_CAP. pEid->Len = %d\n", pEid->Len)); ++ } ++ ++ break; ++ case IE_ADD_HT: ++ if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) ++ { ++ // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only ++ // copy first sizeof(ADD_HT_INFO_IE) ++ NdisMoveMemory(AddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ ++ CtrlChannel = AddHtInfo->ControlChan; ++ ++ *(USHORT *)(&AddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo2)); ++ *(USHORT *)(&AddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&AddHtInfo->AddHtInfo3)); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_ADD_HT. \n")); ++ } ++ ++ break; ++ case IE_SECONDARY_CH_OFFSET: ++ if (pEid->Len == 1) ++ { ++ *NewExtChannelOffset = pEid->Octet[0]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); ++ } ++ ++ break; ++ case IE_FH_PARM: ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity(IE_FH_PARM) \n")); ++ break; ++ ++ case IE_DS_PARM: ++ if(pEid->Len == 1) ++ { ++ *pChannel = *pEid->Octet; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (ChannelSanity(pAd, *pChannel) == 0) ++ { ++ ++ return FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ Sanity |= 0x4; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_DS_PARM (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ ++ case IE_CF_PARM: ++ if(pEid->Len == 6) ++ { ++ pCfParm->bValid = TRUE; ++ pCfParm->CfpCount = pEid->Octet[0]; ++ pCfParm->CfpPeriod = pEid->Octet[1]; ++ pCfParm->CfpMaxDuration = pEid->Octet[2] + 256 * pEid->Octet[3]; ++ pCfParm->CfpDurRemaining = pEid->Octet[4] + 256 * pEid->Octet[5]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_CF_PARM\n")); ++ return FALSE; ++ } ++ break; ++ ++ case IE_IBSS_PARM: ++ if(pEid->Len == 2) ++ { ++ NdisMoveMemory(pAtimWin, pEid->Octet, pEid->Len); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_IBSS_PARM\n")); ++ return FALSE; ++ } ++ break; ++ ++#ifdef CONFIG_STA_SUPPORT ++ case IE_TIM: ++ if(INFRA_ON(pAd) && SubType == SUBTYPE_BEACON) ++ { ++ GetTimBit((PUCHAR)pEid, pAd->StaActive.Aid, &TimLen, pBcastFlag, pDtimCount, pDtimPeriod, pMessageToMe); ++ } ++ break; ++#endif // CONFIG_STA_SUPPORT // ++ case IE_CHANNEL_SWITCH_ANNOUNCEMENT: ++ if(pEid->Len == 3) ++ { ++ *pNewChannel = pEid->Octet[1]; //extract new channel number ++ } ++ break; ++ ++ // New for WPA ++ // CCX v2 has the same IE, we need to parse that too ++ // Wifi WMM use the same IE vale, need to parse that too ++ // case IE_WPA: ++ case IE_VENDOR_SPECIFIC: ++ // Check Broadcom/Atheros 802.11n OUI version, for HT Capability IE. ++ // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. ++ /*if (NdisEqualMemory(pEid->Octet, BROADCOM_OUI, 3) && (pEid->Len >= 4)) ++ { ++ if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 30)) ++ { ++ { ++ NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; // Nnow we only support 26 bytes. ++ } ++ } ++ if ((pEid->Octet[3] == OUI_BROADCOM_HT) && (pEid->Len >= 26)) ++ { ++ { ++ NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; // Nnow we only support 26 bytes. ++ } ++ } ++ } ++ */ ++ // Check the OUI version, filter out non-standard usage ++ if (NdisEqualMemory(pEid->Octet, RALINK_OUI, 3) && (pEid->Len == 7)) ++ { ++ //*pRalinkIe = pEid->Octet[3]; ++ if (pEid->Octet[3] != 0) ++ *pRalinkIe = pEid->Octet[3]; ++ else ++ *pRalinkIe = 0xf0000000; // Set to non-zero value (can't set bit0-2) to represent this is Ralink Chip. So at linkup, we will set ralinkchip flag. ++ } ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++ // This HT IE is before IEEE draft set HT IE value.2006-09-28 by Jan. ++ ++ // Other vendors had production before IE_HT_CAP value is assigned. To backward support those old-firmware AP, ++ // Check broadcom-defiend pre-802.11nD1.0 OUI for HT related IE, including HT Capatilities IE and HT Information IE ++ else if ((*pHtCapabilityLen == 0) && NdisEqualMemory(pEid->Octet, PRE_N_HT_OUI, 3) && (pEid->Len >= 4) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if ((pEid->Octet[3] == OUI_PREN_HT_CAP) && (pEid->Len >= 30) && (*pHtCapabilityLen == 0)) ++ { ++ NdisMoveMemory(pHtCapability, &pEid->Octet[4], sizeof(HT_CAPABILITY_IE)); ++ *pPreNHtCapabilityLen = SIZE_HT_CAP_IE; ++ } ++ ++ if ((pEid->Octet[3] == OUI_PREN_ADD_HT) && (pEid->Len >= 26)) ++ { ++ NdisMoveMemory(AddHtInfo, &pEid->Octet[4], sizeof(ADD_HT_INFO_IE)); ++ *AddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ { ++ // Copy to pVIE which will report to microsoft bssid list. ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++ else if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) ++ { ++ PUCHAR ptr; ++ int i; ++ ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ptr = &pEid->Octet[8]; ++ for (i=0; i<4; i++) ++ { ++ UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX ++ pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM ++ pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN ++ pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin ++ pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax ++ pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us ++ ptr += 4; // point to next AC ++ } ++ } ++ else if (NdisEqualMemory(pEid->Octet, WME_INFO_ELEM, 6) && (pEid->Len == 7)) ++ { ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ++ // use default EDCA parameter ++ pEdcaParm->bACM[QID_AC_BE] = 0; ++ pEdcaParm->Aifsn[QID_AC_BE] = 3; ++ pEdcaParm->Cwmin[QID_AC_BE] = CW_MIN_IN_BITS; ++ pEdcaParm->Cwmax[QID_AC_BE] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_BE] = 0; ++ ++ pEdcaParm->bACM[QID_AC_BK] = 0; ++ pEdcaParm->Aifsn[QID_AC_BK] = 7; ++ pEdcaParm->Cwmin[QID_AC_BK] = CW_MIN_IN_BITS; ++ pEdcaParm->Cwmax[QID_AC_BK] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_BK] = 0; ++ ++ pEdcaParm->bACM[QID_AC_VI] = 0; ++ pEdcaParm->Aifsn[QID_AC_VI] = 2; ++ pEdcaParm->Cwmin[QID_AC_VI] = CW_MIN_IN_BITS-1; ++ pEdcaParm->Cwmax[QID_AC_VI] = CW_MAX_IN_BITS; ++ pEdcaParm->Txop[QID_AC_VI] = 96; // AC_VI: 96*32us ~= 3ms ++ ++ pEdcaParm->bACM[QID_AC_VO] = 0; ++ pEdcaParm->Aifsn[QID_AC_VO] = 2; ++ pEdcaParm->Cwmin[QID_AC_VO] = CW_MIN_IN_BITS-2; ++ pEdcaParm->Cwmax[QID_AC_VO] = CW_MAX_IN_BITS-1; ++ pEdcaParm->Txop[QID_AC_VO] = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ else ++ { ++ } ++ ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); ++ *pExtRateLen = pEid->Len; ++ ++ // TODO: 2004-09-14 not a good design here, cause it exclude extra rates ++ // from ScanTab. We should report as is. And filter out unsupported ++ // rates in MlmeAux. ++ // Check against the supported rates ++ // RTMPCheckRates(pAd, ExtRate, pExtRateLen); ++ } ++ break; ++ ++ case IE_ERP: ++ if (pEid->Len == 1) ++ { ++ *pErp = (UCHAR)pEid->Octet[0]; ++ } ++ break; ++ ++ case IE_AIRONET_CKIP: ++ // 0. Check Aironet IE length, it must be larger or equal to 28 ++ // Cisco AP350 used length as 28 ++ // Cisco AP12XX used length as 30 ++ if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) ++ break; ++ ++ // 1. Copy CKIP flag byte to buffer for process ++ *pCkipFlag = *(pEid->Octet + 8); ++ break; ++ ++ case IE_AP_TX_POWER: ++ // AP Control of Client Transmit Power ++ //0. Check Aironet IE length, it must be 6 ++ if (pEid->Len != 0x06) ++ break; ++ ++ // Get cell power limit in dBm ++ if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) ++ *pAironetCellPowerLimit = *(pEid->Octet + 4); ++ break; ++ ++ // WPA2 & 802.11i RSN ++ case IE_RSN: ++ // There is no OUI for version anymore, check the group cipher OUI before copying ++ if (RTMPEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ { ++ // Copy to pVIE which will report to microsoft bssid list. ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ } ++ break; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ case IE_COUNTRY: ++ Ptr = (PUCHAR) pVIE; ++ NdisMoveMemory(Ptr + *LengthVIE, &pEid->Eid, pEid->Len + 2); ++ *LengthVIE += (pEid->Len + 2); ++ break; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ default: ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ // For some 11a AP. it did not have the channel EID, patch here ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ UCHAR LatchRfChannel = MsgChannel; ++ if ((pAd->LatchRfRegs.Channel > 14) && ((Sanity & 0x4) == 0)) ++ { ++ if (CtrlChannel != 0) ++ *pChannel = CtrlChannel; ++ else ++ *pChannel = LatchRfChannel; ++ Sanity |= 0x4; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (Sanity != 0x7) ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerBeaconAndProbeRspSanity - missing field, Sanity=0x%02x\n", Sanity)); ++ return FALSE; ++ } ++ else ++ { ++ return TRUE; ++ } ++ ++} ++ ++#ifdef DOT11N_DRAFT3 ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check for some IE addressed in 802.11n d3.03. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerBeaconAndProbeRspSanity2( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *RegClass) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 pFrame; ++ PEID_STRUCT pEid; ++ ULONG Length = 0; ++ ++ pFrame = (PFRAME_802_11)Msg; ++ ++ *RegClass = 0; ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ // get timestamp from payload and advance the pointer ++ Ptr += TIMESTAMP_LEN; ++ Length += TIMESTAMP_LEN; ++ ++ // get beacon interval from payload and advance the pointer ++ Ptr += 2; ++ Length += 2; ++ ++ // get capability info from payload and advance the pointer ++ Ptr += 2; ++ Length += 2; ++ ++ pEid = (PEID_STRUCT) Ptr; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ switch(pEid->Eid) ++ { ++ case IE_SUPP_REG_CLASS: ++ if(pEid->Len > 0) ++ { ++ *RegClass = *pEid->Octet; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAndProbeRspSanity - wrong IE_SSID (len=%d)\n",pEid->Len)); ++ return FALSE; ++ } ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ return TRUE; ++ ++} ++#endif // DOT11N_DRAFT3 // ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeScanReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *pBssType, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pScanType) ++{ ++ MLME_SCAN_REQ_STRUCT *Info; ++ ++ Info = (MLME_SCAN_REQ_STRUCT *)(Msg); ++ *pBssType = Info->BssType; ++ *pSsidLen = Info->SsidLen; ++ NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); ++ *pScanType = Info->ScanType; ++ ++ if ((*pBssType == BSS_INFRA || *pBssType == BSS_ADHOC || *pBssType == BSS_ANY) ++ && (*pScanType == SCAN_ACTIVE || *pScanType == SCAN_PASSIVE ++#ifdef CONFIG_STA_SUPPORT ++ || *pScanType == SCAN_CISCO_PASSIVE || *pScanType == SCAN_CISCO_ACTIVE ++ || *pScanType == SCAN_CISCO_CHANNEL_LOAD || *pScanType == SCAN_CISCO_NOISE ++#endif // CONFIG_STA_SUPPORT // ++ )) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqSanity fail - wrong BssType or ScanType\n")); ++ return FALSE; ++ } ++} ++ ++// IRQL = DISPATCH_LEVEL ++UCHAR ChannelSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++{ ++ int i; ++ ++ for (i = 0; i < pAd->ChannelListNum; i ++) ++ { ++ if (channel == pAd->ChannelList[i].Channel) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerDeauthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pReason) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pReason, &pFrame->Octet[0], 2); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT USHORT *pAlg, ++ OUT USHORT *pSeq, ++ OUT USHORT *pStatus, ++ CHAR *pChlgText) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pAlg, &pFrame->Octet[0], 2); ++ NdisMoveMemory(pSeq, &pFrame->Octet[2], 2); ++ NdisMoveMemory(pStatus, &pFrame->Octet[4], 2); ++ ++ if ((*pAlg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (*pAlg == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ { ++ if (*pSeq == 1 || *pSeq == 2) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); ++ return FALSE; ++ } ++ } ++ else if (*pAlg == Ndis802_11AuthModeShared) ++ { ++ if (*pSeq == 1 || *pSeq == 4) ++ { ++ return TRUE; ++ } ++ else if (*pSeq == 2 || *pSeq == 3) ++ { ++ NdisMoveMemory(pChlgText, &pFrame->Octet[8], CIPHER_TEXT_LEN); ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong Seg#\n")); ++ return FALSE; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAuthSanity fail - wrong algorithm\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeAuthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT ULONG *pTimeout, ++ OUT USHORT *pAlg) ++{ ++ MLME_AUTH_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_AUTH_REQ_STRUCT *)Msg; ++ COPY_MAC_ADDR(pAddr, pInfo->Addr); ++ *pTimeout = pInfo->Timeout; ++ *pAlg = pInfo->Alg; ++ ++ if (((*pAlg == Ndis802_11AuthModeShared) ||(*pAlg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (*pAlg == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) && ++ ((*pAddr & 0x01) == 0)) ++ { ++ return TRUE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeAuthReqSanity fail - wrong algorithm\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN MlmeAssocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pApAddr, ++ OUT USHORT *pCapabilityInfo, ++ OUT ULONG *pTimeout, ++ OUT USHORT *pListenIntv) ++{ ++ MLME_ASSOC_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_ASSOC_REQ_STRUCT *)Msg; ++ *pTimeout = pInfo->Timeout; // timeout ++ COPY_MAC_ADDR(pApAddr, pInfo->Addr); // AP address ++ *pCapabilityInfo = pInfo->CapabilityInfo; // capability info ++ *pListenIntv = pInfo->ListenIntv; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerDisassocSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pReason) ++{ ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ NdisMoveMemory(pReason, &pFrame->Octet[0], 2); ++ ++ return TRUE; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Sanity check NetworkType (11b, 11g or 11a) ++ ++ Arguments: ++ pBss - Pointer to BSS table. ++ ++ Return Value: ++ Ndis802_11DS .......(11b) ++ Ndis802_11OFDM24....(11g) ++ Ndis802_11OFDM5.....(11a) ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( ++ IN PBSS_ENTRY pBss) ++{ ++ NDIS_802_11_NETWORK_TYPE NetWorkType; ++ UCHAR rate, i; ++ ++ NetWorkType = Ndis802_11DS; ++ ++ if (pBss->Channel <= 14) ++ { ++ // ++ // First check support Rate. ++ // ++ for (i = 0; i < pBss->SupRateLen; i++) ++ { ++ rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit ++ if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) ++ { ++ continue; ++ } ++ else ++ { ++ // ++ // Otherwise (even rate > 108) means Ndis802_11OFDM24 ++ // ++ NetWorkType = Ndis802_11OFDM24; ++ break; ++ } ++ } ++ ++ // ++ // Second check Extend Rate. ++ // ++ if (NetWorkType != Ndis802_11OFDM24) ++ { ++ for (i = 0; i < pBss->ExtRateLen; i++) ++ { ++ rate = pBss->SupRate[i] & 0x7f; // Mask out basic rate set bit ++ if ((rate == 2) || (rate == 4) || (rate == 11) || (rate == 22)) ++ { ++ continue; ++ } ++ else ++ { ++ // ++ // Otherwise (even rate > 108) means Ndis802_11OFDM24 ++ // ++ NetWorkType = Ndis802_11OFDM24; ++ break; ++ } ++ } ++ } ++ } ++ else ++ { ++ NetWorkType = Ndis802_11OFDM5; ++ } ++ ++ if (pBss->HtCapabilityLen != 0) ++ { ++ if (NetWorkType == Ndis802_11OFDM5) ++ NetWorkType = Ndis802_11OFDM5_N; ++ else ++ NetWorkType = Ndis802_11OFDM24_N; ++ } ++ ++ return NetWorkType; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ WPA message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN PeerWpaMessageSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN PEAPOL_PACKET pMsg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgType, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ UCHAR mic[LEN_KEY_DESC_MIC], digest[80], KEYDATA[MAX_LEN_OF_RSNIE]; ++ BOOLEAN bReplayDiff = FALSE; ++ BOOLEAN bWPA2 = FALSE; ++ KEY_INFO EapolKeyInfo; ++ UCHAR GroupKeyIndex = 0; ++ ++ ++ NdisZeroMemory(mic, sizeof(mic)); ++ NdisZeroMemory(digest, sizeof(digest)); ++ NdisZeroMemory(KEYDATA, sizeof(KEYDATA)); ++ NdisZeroMemory((PUCHAR)&EapolKeyInfo, sizeof(EapolKeyInfo)); ++ ++ NdisMoveMemory((PUCHAR)&EapolKeyInfo, (PUCHAR)&pMsg->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT *)&EapolKeyInfo) = cpu2le16(*((USHORT *)&EapolKeyInfo)); ++ ++ // Choose WPA2 or not ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2) || (pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ bWPA2 = TRUE; ++ ++ // 0. Check MsgType ++ if ((MsgType > EAPOL_GROUP_MSG_2) || (MsgType < EAPOL_PAIR_MSG_1)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("The message type is invalid(%d)! \n", MsgType)); ++ return FALSE; ++ } ++ ++ // 1. Replay counter check ++ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1) // For supplicant ++ { ++ // First validate replay counter, only accept message with larger replay counter. ++ // Let equal pass, some AP start with all zero replay counter ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ if ((RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pMsg->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ { ++ bReplayDiff = TRUE; ++ } ++ } ++ else if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) // For authenticator ++ { ++ // check Replay Counter coresponds to MSG from authenticator, otherwise discard ++ if (!NdisEqualMemory(pMsg->KeyDesc.ReplayCounter, pEntry->R_Counter, LEN_KEY_DESC_REPLAY)) ++ { ++ bReplayDiff = TRUE; ++ } ++ } ++ ++ // Replay Counter different condition ++ if (bReplayDiff) ++ { ++ // send wireless event - for replay counter different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_REPLAY_COUNTER_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ if (MsgType < EAPOL_GROUP_MSG_1) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in pairwise msg %d of 4-way handshake!\n", MsgType)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Replay Counter Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); ++ } ++ ++ hex_dump("Receive replay counter ", pMsg->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ hex_dump("Current replay counter ", pEntry->R_Counter, LEN_KEY_DESC_REPLAY); ++ return FALSE; ++ } ++ ++ // 2. Verify MIC except Pairwise Msg1 ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ { ++ UCHAR rcvd_mic[LEN_KEY_DESC_MIC]; ++ ++ // Record the received MIC for check later ++ NdisMoveMemory(rcvd_mic, pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ if (pEntry->WepStatus == Ndis802_11Encryption2Enabled) // TKIP ++ { ++ hmac_md5(pEntry->PTK, LEN_EAP_MICK, (PUCHAR)pMsg, MsgLen, mic); ++ } ++ else if (pEntry->WepStatus == Ndis802_11Encryption3Enabled) // AES ++ { ++ HMAC_SHA1((PUCHAR)pMsg, MsgLen, pEntry->PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); ++ } ++ ++ if (!NdisEqualMemory(rcvd_mic, mic, LEN_KEY_DESC_MIC)) ++ { ++ // send wireless event - for MIC different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_MIC_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ if (MsgType < EAPOL_GROUP_MSG_1) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in pairwise msg %d of 4-way handshake!\n", MsgType)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in group msg %d of 2-way handshake!\n", (MsgType - EAPOL_PAIR_MSG_4))); ++ } ++ ++ hex_dump("Received MIC", rcvd_mic, LEN_KEY_DESC_MIC); ++ hex_dump("Desired MIC", mic, LEN_KEY_DESC_MIC); ++ ++ return FALSE; ++ } ++ } ++ ++ // Extract the context of the Key Data field if it exist ++ // The field in pairwise_msg_2_WPA1(WPA2) & pairwise_msg_3_WPA1 is un-encrypted. ++ // The field in group_msg_1_WPA1(WPA2) & pairwise_msg_3_WPA2 is encrypted. ++ if (pMsg->KeyDesc.KeyDataLen[1] > 0) ++ { ++ // Decrypt this field ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ if(pEntry->WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ AES_GTK_KEY_UNWRAP(&pEntry->PTK[16], KEYDATA, pMsg->KeyDesc.KeyDataLen[1],pMsg->KeyDesc.KeyData); ++ } ++ else ++ { ++ INT i; ++ UCHAR Key[32]; ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pMsg->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pEntry->PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); ++ } ++ ++ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) ++ GroupKeyIndex = EapolKeyInfo.KeyIndex; ++ ++ } ++ else if ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3 && !bWPA2)) ++ { ++ NdisMoveMemory(KEYDATA, pMsg->KeyDesc.KeyData, pMsg->KeyDesc.KeyDataLen[1]); ++ } ++ else ++ { ++ ++ return TRUE; ++ } ++ ++ // Parse Key Data field to ++ // 1. verify RSN IE for pairwise_msg_2_WPA1(WPA2) ,pairwise_msg_3_WPA1(WPA2) ++ // 2. verify KDE format for pairwise_msg_3_WPA2, group_msg_1_WPA2 ++ // 3. update shared key for pairwise_msg_3_WPA2, group_msg_1_WPA1(WPA2) ++ if (!RTMPParseEapolKeyData(pAd, KEYDATA, pMsg->KeyDesc.KeyDataLen[1], GroupKeyIndex, MsgType, bWPA2, pEntry)) ++ { ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN MlmeDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PRT_802_11_DLS *pDLS, ++ OUT PUSHORT pReason) ++{ ++ MLME_DLS_REQ_STRUCT *pInfo; ++ ++ pInfo = (MLME_DLS_REQ_STRUCT *)Msg; ++ ++ *pDLS = pInfo->pDLS; ++ *pReason = pInfo->Reason; ++ ++ return TRUE; ++} ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN PeerDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pDlsTimeout, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ PEID_STRUCT eid_ptr; ++ ++ // to prevent caller from using garbage output value ++ *pCapabilityInfo = 0; ++ *pDlsTimeout = 0; ++ *pHtCapabilityLen = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pDlsTimeout, Ptr, 2); ++ Ptr += 2; ++ ++ // Category and Action field + DA + SA + capability + Timeout ++ eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; ++ ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_SUPP_RATES: ++ if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) ++ { ++ NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); ++ DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); ++ *pRatesLen = eid_ptr->Len; ++ } ++ else ++ { ++ *pRatesLen = 8; ++ Rates[0] = 0x82; ++ Rates[1] = 0x84; ++ Rates[2] = 0x8b; ++ Rates[3] = 0x96; ++ Rates[4] = 0x12; ++ Rates[5] = 0x24; ++ Rates[6] = 0x48; ++ Rates[7] = 0x6c; ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); ++ *pRatesLen = (*pRatesLen) + eid_ptr->Len; ++ } ++ else ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); ++ *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) ++ { ++ NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - IE_HT_CAP\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsReqSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerDlsRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ PEID_STRUCT eid_ptr; ++ ++ // to prevent caller from using garbage output value ++ *pStatus = 0; ++ *pCapabilityInfo = 0; ++ *pHtCapabilityLen = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get status code from payload and advance the pointer ++ NdisMoveMemory(pStatus, Ptr, 2); ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ if (pStatus == 0) ++ { ++ // get capability info from payload and advance the pointer ++ NdisMoveMemory(pCapabilityInfo, Ptr, 2); ++ Ptr += 2; ++ } ++ ++ // Category and Action field + status code + DA + SA + capability ++ eid_ptr = (PEID_STRUCT) &Fr->Octet[18]; ++ ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((UCHAR*)Fr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_SUPP_RATES: ++ if ((eid_ptr->Len <= MAX_LEN_OF_SUPPORTED_RATES) && (eid_ptr->Len > 0)) ++ { ++ NdisMoveMemory(Rates, eid_ptr->Octet, eid_ptr->Len); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_SUPP_RATES., Len=%d. Rates[0]=%x\n",eid_ptr->Len, Rates[0])); ++ DBGPRINT(RT_DEBUG_TRACE, ("Rates[1]=%x %x %x %x %x %x %x\n", Rates[1], Rates[2], Rates[3], Rates[4], Rates[5], Rates[6], Rates[7])); ++ *pRatesLen = eid_ptr->Len; ++ } ++ else ++ { ++ *pRatesLen = 8; ++ Rates[0] = 0x82; ++ Rates[1] = 0x84; ++ Rates[2] = 0x8b; ++ Rates[3] = 0x96; ++ Rates[4] = 0x12; ++ Rates[5] = 0x24; ++ Rates[6] = 0x48; ++ Rates[7] = 0x6c; ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_SUPP_RATES., Len=%d\n",eid_ptr->Len)); ++ } ++ break; ++ ++ case IE_EXT_SUPP_RATES: ++ if (eid_ptr->Len + *pRatesLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, eid_ptr->Len); ++ *pRatesLen = (*pRatesLen) + eid_ptr->Len; ++ } ++ else ++ { ++ NdisMoveMemory(&Rates[*pRatesLen], eid_ptr->Octet, MAX_LEN_OF_SUPPORTED_RATES - (*pRatesLen)); ++ *pRatesLen = MAX_LEN_OF_SUPPORTED_RATES; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ if (eid_ptr->Len >= sizeof(HT_CAPABILITY_IE)) ++ { ++ NdisMoveMemory(pHtCapability, eid_ptr->Octet, sizeof(HT_CAPABILITY_IE)); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ *pHtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - IE_HT_CAP\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerDlsRspSanity - wrong IE_HT_CAP.eid_ptr->Len = %d\n", eid_ptr->Len)); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return TRUE; ++} ++ ++BOOLEAN PeerDlsTearDownSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pReason) ++{ ++ CHAR *Ptr; ++ PFRAME_802_11 Fr = (PFRAME_802_11)Msg; ++ ++ // to prevent caller from using garbage output value ++ *pReason = 0; ++ ++ Ptr = Fr->Octet; ++ ++ // offset to destination MAC address (Category and Action field) ++ Ptr += 2; ++ ++ // get DA from payload and advance the pointer ++ NdisMoveMemory(pDA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get SA from payload and advance the pointer ++ NdisMoveMemory(pSA, Ptr, MAC_ADDR_LEN); ++ Ptr += MAC_ADDR_LEN; ++ ++ // get reason code from payload and advance the pointer ++ NdisMoveMemory(pReason, Ptr, 2); ++ Ptr += 2; ++ ++ return TRUE; ++} ++#endif // QOS_DLS_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/cmm_sync.c +@@ -0,0 +1,711 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sync.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 modified for rt2561/2661 ++*/ ++#include "../rt_config.h" ++ ++// 2.4 Ghz channel plan index in the TxPower arrays. ++#define BG_BAND_REGION_0_START 0 // 1,2,3,4,5,6,7,8,9,10,11 ++#define BG_BAND_REGION_0_SIZE 11 ++#define BG_BAND_REGION_1_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13 ++#define BG_BAND_REGION_1_SIZE 13 ++#define BG_BAND_REGION_2_START 9 // 10,11 ++#define BG_BAND_REGION_2_SIZE 2 ++#define BG_BAND_REGION_3_START 9 // 10,11,12,13 ++#define BG_BAND_REGION_3_SIZE 4 ++#define BG_BAND_REGION_4_START 13 // 14 ++#define BG_BAND_REGION_4_SIZE 1 ++#define BG_BAND_REGION_5_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 ++#define BG_BAND_REGION_5_SIZE 14 ++#define BG_BAND_REGION_6_START 2 // 3,4,5,6,7,8,9 ++#define BG_BAND_REGION_6_SIZE 7 ++#define BG_BAND_REGION_7_START 4 // 5,6,7,8,9,10,11,12,13 ++#define BG_BAND_REGION_7_SIZE 9 ++#define BG_BAND_REGION_31_START 0 // 1,2,3,4,5,6,7,8,9,10,11,12,13,14 ++#define BG_BAND_REGION_31_SIZE 14 ++ ++// 5 Ghz channel plan index in the TxPower arrays. ++UCHAR A_BAND_REGION_0_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_1_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++UCHAR A_BAND_REGION_2_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64}; ++UCHAR A_BAND_REGION_3_CHANNEL_LIST[]={52, 56, 60, 64, 149, 153, 157, 161}; ++UCHAR A_BAND_REGION_4_CHANNEL_LIST[]={149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_5_CHANNEL_LIST[]={149, 153, 157, 161}; ++UCHAR A_BAND_REGION_6_CHANNEL_LIST[]={36, 40, 44, 48}; ++UCHAR A_BAND_REGION_7_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_8_CHANNEL_LIST[]={52, 56, 60, 64}; ++UCHAR A_BAND_REGION_9_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_10_CHANNEL_LIST[]={36, 40, 44, 48, 149, 153, 157, 161, 165}; ++UCHAR A_BAND_REGION_11_CHANNEL_LIST[]={36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161}; ++ ++//BaSizeArray follows the 802.11n definition as MaxRxFactor. 2^(13+factor) bytes. When factor =0, it's about Ba buffer size =8. ++UCHAR BaSizeArray[4] = {8,16,32,64}; ++ ++/* ++ ========================================================================== ++ Description: ++ Update StaCfg->ChannelList[] according to 1) Country Region 2) RF IC type, ++ and 3) PHY-mode user selected. ++ The outcome is used by driver when doing site survey. ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID BuildChannelList( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i, j, index=0, num=0; ++ PUCHAR pChannelList = NULL; ++ ++ NdisZeroMemory(pAd->ChannelList, MAX_NUM_OF_CHANNELS * sizeof(CHANNEL_TX_POWER)); ++ ++ // if not 11a-only mode, channel list starts from 2.4Ghz band ++ if ((pAd->CommonCfg.PhyMode != PHY_11A) ++#ifdef DOT11_N_SUPPORT ++ && (pAd->CommonCfg.PhyMode != PHY_11AN_MIXED) && (pAd->CommonCfg.PhyMode != PHY_11N_5G) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ switch (pAd->CommonCfg.CountryRegion & 0x7f) ++ { ++ case REGION_0_BG_BAND: // 1 -11 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_0_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_0_SIZE); ++ index += BG_BAND_REGION_0_SIZE; ++ break; ++ case REGION_1_BG_BAND: // 1 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_1_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_1_SIZE); ++ index += BG_BAND_REGION_1_SIZE; ++ break; ++ case REGION_2_BG_BAND: // 10 - 11 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_2_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_2_SIZE); ++ index += BG_BAND_REGION_2_SIZE; ++ break; ++ case REGION_3_BG_BAND: // 10 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_3_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_3_SIZE); ++ index += BG_BAND_REGION_3_SIZE; ++ break; ++ case REGION_4_BG_BAND: // 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_4_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_4_SIZE); ++ index += BG_BAND_REGION_4_SIZE; ++ break; ++ case REGION_5_BG_BAND: // 1 - 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_5_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_5_SIZE); ++ index += BG_BAND_REGION_5_SIZE; ++ break; ++ case REGION_6_BG_BAND: // 3 - 9 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_6_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_6_SIZE); ++ index += BG_BAND_REGION_6_SIZE; ++ break; ++ case REGION_7_BG_BAND: // 5 - 13 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_7_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_7_SIZE); ++ index += BG_BAND_REGION_7_SIZE; ++ break; ++ case REGION_31_BG_BAND: // 1 - 14 ++ NdisMoveMemory(&pAd->ChannelList[index], &pAd->TxPower[BG_BAND_REGION_31_START], sizeof(CHANNEL_TX_POWER) * BG_BAND_REGION_31_SIZE); ++ index += BG_BAND_REGION_31_SIZE; ++ break; ++ default: // Error. should never happen ++ break; ++ } ++ for (i=0; iChannelList[i].MaxTxPwr = 20; ++ } ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11A) || (pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11N_5G) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ switch (pAd->CommonCfg.CountryRegionForABand & 0x7f) ++ { ++ case REGION_0_A_BAND: ++ num = sizeof(A_BAND_REGION_0_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_0_CHANNEL_LIST; ++ break; ++ case REGION_1_A_BAND: ++ num = sizeof(A_BAND_REGION_1_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_1_CHANNEL_LIST; ++ break; ++ case REGION_2_A_BAND: ++ num = sizeof(A_BAND_REGION_2_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_2_CHANNEL_LIST; ++ break; ++ case REGION_3_A_BAND: ++ num = sizeof(A_BAND_REGION_3_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_3_CHANNEL_LIST; ++ break; ++ case REGION_4_A_BAND: ++ num = sizeof(A_BAND_REGION_4_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_4_CHANNEL_LIST; ++ break; ++ case REGION_5_A_BAND: ++ num = sizeof(A_BAND_REGION_5_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_5_CHANNEL_LIST; ++ break; ++ case REGION_6_A_BAND: ++ num = sizeof(A_BAND_REGION_6_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_6_CHANNEL_LIST; ++ break; ++ case REGION_7_A_BAND: ++ num = sizeof(A_BAND_REGION_7_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_7_CHANNEL_LIST; ++ break; ++ case REGION_8_A_BAND: ++ num = sizeof(A_BAND_REGION_8_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_8_CHANNEL_LIST; ++ break; ++ case REGION_9_A_BAND: ++ num = sizeof(A_BAND_REGION_9_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_9_CHANNEL_LIST; ++ break; ++ ++ case REGION_10_A_BAND: ++ num = sizeof(A_BAND_REGION_10_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_10_CHANNEL_LIST; ++ break; ++ ++ case REGION_11_A_BAND: ++ num = sizeof(A_BAND_REGION_11_CHANNEL_LIST)/sizeof(UCHAR); ++ pChannelList = A_BAND_REGION_11_CHANNEL_LIST; ++ break; ++ ++ default: // Error. should never happen ++ DBGPRINT(RT_DEBUG_WARN,("countryregion=%d not support", pAd->CommonCfg.CountryRegionForABand)); ++ break; ++ } ++ ++ if (num != 0) ++ { ++ UCHAR RadarCh[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ for (i=0; iTxPower[j].Channel) ++ NdisMoveMemory(&pAd->ChannelList[index+i], &pAd->TxPower[j], sizeof(CHANNEL_TX_POWER)); ++ } ++ for (j=0; j<15; j++) ++ { ++ if (pChannelList[i] == RadarCh[j]) ++ pAd->ChannelList[index+i].DfsReq = TRUE; ++ } ++ pAd->ChannelList[index+i].MaxTxPwr = 20; ++ } ++ index += num; ++ } ++ } ++ ++ pAd->ChannelListNum = index; ++ DBGPRINT(RT_DEBUG_TRACE,("country code=%d/%d, RFIC=%d, PHY mode=%d, support %d channels\n", ++ pAd->CommonCfg.CountryRegion, pAd->CommonCfg.CountryRegionForABand, pAd->RfIcType, pAd->CommonCfg.PhyMode, pAd->ChannelListNum)); ++#ifdef DBG ++ for (i=0;iChannelListNum;i++) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("BuildChannel # %d :: Pwr0 = %d, Pwr1 =%d, \n ", pAd->ChannelList[i].Channel, pAd->ChannelList[i].Power, pAd->ChannelList[i].Power2)); ++ } ++#endif ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine return the first channel number according to the country ++ code selection and RF IC selection (signal band or dual band). It is called ++ whenever driver need to start a site survey of all supported channels. ++ Return: ++ ch - the first channel number of current country code setting ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++UCHAR FirstChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return pAd->ChannelList[0].Channel; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine returns the next channel number. This routine is called ++ during driver need to start a site survey of all supported channels. ++ Return: ++ next_channel - the next channel number valid in current country code setting. ++ Note: ++ return 0 if no more next channel ++ ========================================================================== ++ */ ++UCHAR NextChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel) ++{ ++ int i; ++ UCHAR next_channel = 0; ++ ++ for (i = 0; i < (pAd->ChannelListNum - 1); i++) ++ if (channel == pAd->ChannelList[i].Channel) ++ { ++ next_channel = pAd->ChannelList[i+1].Channel; ++ break; ++ } ++ return next_channel; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is for Cisco Compatible Extensions 2.X ++ Spec31. AP Control of Client Transmit Power ++ Return: ++ None ++ Note: ++ Required by Aironet dBm(mW) ++ 0dBm(1mW), 1dBm(5mW), 13dBm(20mW), 15dBm(30mW), ++ 17dBm(50mw), 20dBm(100mW) ++ ++ We supported ++ 3dBm(Lowest), 6dBm(10%), 9dBm(25%), 12dBm(50%), ++ 14dBm(75%), 15dBm(100%) ++ ++ The client station's actual transmit power shall be within +/- 5dB of ++ the minimum value or next lower value. ++ ========================================================================== ++ */ ++VOID ChangeToCellPowerLimit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AironetCellPowerLimit) ++{ ++ //valud 0xFF means that hasn't found power limit information ++ //from the AP's Beacon/Probe response. ++ if (AironetCellPowerLimit == 0xFF) ++ return; ++ ++ if (AironetCellPowerLimit < 6) //Used Lowest Power Percentage. ++ pAd->CommonCfg.TxPowerPercentage = 6; ++ else if (AironetCellPowerLimit < 9) ++ pAd->CommonCfg.TxPowerPercentage = 10; ++ else if (AironetCellPowerLimit < 12) ++ pAd->CommonCfg.TxPowerPercentage = 25; ++ else if (AironetCellPowerLimit < 14) ++ pAd->CommonCfg.TxPowerPercentage = 50; ++ else if (AironetCellPowerLimit < 15) ++ pAd->CommonCfg.TxPowerPercentage = 75; ++ else ++ pAd->CommonCfg.TxPowerPercentage = 100; //else used maximum ++ ++ if (pAd->CommonCfg.TxPowerPercentage > pAd->CommonCfg.TxPowerDefault) ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ ++} ++ ++CHAR ConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ LNAGain = GET_LNA_GAIN(pAd); ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-12 - RssiOffset - LNAGain - Rssi); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan next channel ++ ========================================================================== ++ */ ++VOID ScanNextChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ HEADER_802_11 Hdr80211; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ UCHAR SsidLen = 0, ScanType = pAd->MlmeAux.ScanType, BBPValue = 0; ++#ifdef CONFIG_STA_SUPPORT ++ USHORT Status; ++ PHEADER_802_11 pHdr80211; ++#endif // CONFIG_STA_SUPPORT // ++ UINT ScanTimeIn5gChannel = SHORT_CHANNEL_TIME; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (MONITOR_ON(pAd)) ++ return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (pAd->MlmeAux.Channel == 0) ++ { ++ if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ++#ifdef CONFIG_STA_SUPPORT ++ && (INFRA_ON(pAd) ++ || (pAd->OpMode == OPMODE_AP)) ++#endif // CONFIG_STA_SUPPORT // ++ ) ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); ++ } ++ else ++ { ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to channel %d, Total BSS[%02d]\n",pAd->CommonCfg.Channel, pAd->ScanTab.BssNr)); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // ++ // To prevent data lost. ++ // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. ++ // Now, we need to send an NULL data with turned PSM bit off to AP, when scan progress done ++ // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) ++ { ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ pHdr80211 = (PHEADER_802_11) pOutBuffer; ++ MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pHdr80211->Duration = 0; ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame\n")); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPusecDelay(5000); ++ } ++ } ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ } ++#ifdef RT2870 ++#ifdef CONFIG_STA_SUPPORT ++ else if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->OpMode == OPMODE_STA)) ++ { ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ MlmeCntlConfirm(pAd, MT2_SCAN_CONF, MLME_FAIL_NO_RESOURCE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2870 // ++ else ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // BBP and RF are not accessible in PS mode, we has to wake them up first ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, TRUE); ++ ++ // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, TRUE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->MlmeAux.Channel > 14) ++ { ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) ++ { ++ ScanType = SCAN_PASSIVE; ++ ScanTimeIn5gChannel = MIN_CHANNEL_TIME; ++ } ++ } ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // carrier detection ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ ScanType = SCAN_PASSIVE; ++ ScanTimeIn5gChannel = MIN_CHANNEL_TIME; ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ //Global country domain(ch1-11:active scan, ch12-14 passive scan) ++ if ((pAd->MlmeAux.Channel <= 14) && (pAd->MlmeAux.Channel >= 12) && ((pAd->CommonCfg.CountryRegion & 0x7f) == REGION_31_BG_BAND)) ++ { ++ ScanType = SCAN_PASSIVE; ++ } ++ ++ // We need to shorten active scan time in order for WZC connect issue ++ // Chnage the channel scan time for CISCO stuff based on its IAPP announcement ++ if (ScanType == FAST_SCAN_ACTIVE) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, FAST_ACTIVE_SCAN_TIME); ++#ifdef CONFIG_STA_SUPPORT ++ else if (((ScanType == SCAN_CISCO_ACTIVE) || ++ (ScanType == SCAN_CISCO_PASSIVE) || ++ (ScanType == SCAN_CISCO_CHANNEL_LOAD) || ++ (ScanType == SCAN_CISCO_NOISE)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if (pAd->StaCfg.CCXScanTime < 25) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime * 2); ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, pAd->StaCfg.CCXScanTime); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ else // must be SCAN_PASSIVE or SCAN_ACTIVE ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ if (pAd->MlmeAux.Channel > 14) ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, ScanTimeIn5gChannel); ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MIN_CHANNEL_TIME); ++ } ++ else ++ RTMPSetTimer(&pAd->MlmeAux.ScanTimer, MAX_CHANNEL_TIME); ++ } ++ ++ if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) || ++ (ScanType == SCAN_CISCO_ACTIVE)) ++ { ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - ScanNextChannel() allocate memory fail\n")); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return; ++ } ++ ++ // There is no need to send broadcast probe request if active scan is in effect. ++ if ((ScanType == SCAN_ACTIVE) || (ScanType == FAST_SCAN_ACTIVE) ++ ) ++ SsidLen = pAd->MlmeAux.SsidLen; ++ else ++ SsidLen = 0; ++ ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &SsidLen, ++ SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->CommonCfg.SupRateLen, ++ pAd->CommonCfg.SupRateLen, pAd->CommonCfg.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->CommonCfg.ExtRateLen) ++ { ++ ULONG Tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->CommonCfg.ExtRateLen, ++ pAd->CommonCfg.ExtRateLen, pAd->CommonCfg.ExtRate, ++ END_OF_ARGS); ++ FrameLen += Tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ ULONG Tmp; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ if (pAd->bBroadComHT == TRUE) ++ { ++ HtLen = pAd->MlmeAux.HtCapabilityLen + 4; ++#ifdef RT_BIG_ENDIAN ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#else ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++#endif // RT_BIG_ENDIAN // ++ } ++ else ++ { ++ HtLen = pAd->MlmeAux.HtCapabilityLen; ++#ifdef RT_BIG_ENDIAN ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, SIZE_HT_CAP_IE); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#else ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#endif // RT_BIG_ENDIAN // ++ } ++ FrameLen += Tmp; ++ ++#ifdef DOT11N_DRAFT3 ++ if (pAd->CommonCfg.BACapability.field.b2040CoexistScanSup == 1) ++ { ++ ULONG Tmp; ++ HtLen = 1; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtHtCapIe, ++ 1, &HtLen, ++ 1, &pAd->CommonCfg.BSSCoexist2040.word, ++ END_OF_ARGS); ++ ++ FrameLen += Tmp; ++ } ++#endif // DOT11N_DRAFT3 // ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ ++ // For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; ++#endif // CONFIG_STA_SUPPORT // ++ ++ } ++} ++ ++VOID MgtProbReqMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SubType; ++ if (SubType == SUBTYPE_ACK) ++ pHdr80211->FC.Type = BTYPE_CNTL; ++ pHdr80211->FC.ToDs = ToDs; ++ COPY_MAC_ADDR(pHdr80211->Addr1, pDA); ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/cmm_wpa.c +@@ -0,0 +1,1606 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 03-07-22 Initial ++ Paul Lin 03-11-28 Modify for supplicant ++*/ ++#include "../rt_config.h" ++// WPA OUI ++UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; ++UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; ++UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; ++UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; ++// WPA2 OUI ++UCHAR OUI_WPA2_WEP40[4] = {0x00, 0x0F, 0xAC, 0x01}; ++UCHAR OUI_WPA2_TKIP[4] = {0x00, 0x0F, 0xAC, 0x02}; ++UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; ++UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; ++UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; ++// MSA OUI ++UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 ++UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The pseudo-random function(PRF) that hashes various inputs to ++ derive a pseudo-random value. To add liveness to the pseudo-random ++ value, a nonce should be one of the inputs. ++ ++ It is used to generate PTK, GTK or some specific random value. ++ ++ Arguments: ++ UCHAR *key, - the key material for HMAC_SHA1 use ++ INT key_len - the length of key ++ UCHAR *prefix - a prefix label ++ INT prefix_len - the length of the label ++ UCHAR *data - a specific data with variable length ++ INT data_len - the length of a specific data ++ INT len - the output lenght ++ ++ Return Value: ++ UCHAR *output - the calculated result ++ ++ Note: ++ 802.11i-2004 Annex H.3 ++ ++ ======================================================================== ++*/ ++VOID PRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *prefix, ++ IN INT prefix_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len) ++{ ++ INT i; ++ UCHAR *input; ++ INT currentindex = 0; ++ INT total_len; ++ ++ // Allocate memory for input ++ os_alloc_mem(NULL, (PUCHAR *)&input, 1024); ++ ++ if (input == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!PRF: no memory!!!\n")); ++ return; ++ } ++ ++ // Generate concatenation input ++ NdisMoveMemory(input, prefix, prefix_len); ++ ++ // Concatenate a single octet containing 0 ++ input[prefix_len] = 0; ++ ++ // Concatenate specific data ++ NdisMoveMemory(&input[prefix_len + 1], data, data_len); ++ total_len = prefix_len + 1 + data_len; ++ ++ // Concatenate a single octet containing 0 ++ // This octet shall be update later ++ input[total_len] = 0; ++ total_len++; ++ ++ // Iterate to calculate the result by hmac-sha-1 ++ // Then concatenate to last result ++ for (i = 0; i < (len + 19) / 20; i++) ++ { ++ HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); ++ currentindex += 20; ++ ++ // update the last octet ++ input[total_len - 1]++; ++ } ++ os_free_mem(NULL, input); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ It utilizes PRF-384 or PRF-512 to derive session-specific keys from a PMK. ++ It shall be called by 4-way handshake processing. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PMK - pointer to PMK ++ ANonce - pointer to ANonce ++ AA - pointer to Authenticator Address ++ SNonce - pointer to SNonce ++ SA - pointer to Supplicant Address ++ len - indicate the length of PTK (octet) ++ ++ Return Value: ++ Output pointer to the PTK ++ ++ Note: ++ Refer to IEEE 802.11i-2004 8.5.1.2 ++ ++ ======================================================================== ++*/ ++VOID WpaCountPTK( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *PMK, ++ IN UCHAR *ANonce, ++ IN UCHAR *AA, ++ IN UCHAR *SNonce, ++ IN UCHAR *SA, ++ OUT UCHAR *output, ++ IN UINT len) ++{ ++ UCHAR concatenation[76]; ++ UINT CurrPos = 0; ++ UCHAR temp[32]; ++ UCHAR Prefix[] = {'P', 'a', 'i', 'r', 'w', 'i', 's', 'e', ' ', 'k', 'e', 'y', ' ', ++ 'e', 'x', 'p', 'a', 'n', 's', 'i', 'o', 'n'}; ++ ++ // initiate the concatenation input ++ NdisZeroMemory(temp, sizeof(temp)); ++ NdisZeroMemory(concatenation, 76); ++ ++ // Get smaller address ++ if (RTMPCompareMemory(SA, AA, 6) == 1) ++ NdisMoveMemory(concatenation, AA, 6); ++ else ++ NdisMoveMemory(concatenation, SA, 6); ++ CurrPos += 6; ++ ++ // Get larger address ++ if (RTMPCompareMemory(SA, AA, 6) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], SA, 6); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], AA, 6); ++ ++ // store the larger mac address for backward compatible of ++ // ralink proprietary STA-key issue ++ NdisMoveMemory(temp, &concatenation[CurrPos], MAC_ADDR_LEN); ++ CurrPos += 6; ++ ++ // Get smaller Nonce ++ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) ++ NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue ++ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); ++ CurrPos += 32; ++ ++ // Get larger Nonce ++ if (RTMPCompareMemory(ANonce, SNonce, 32) == 0) ++ NdisMoveMemory(&concatenation[CurrPos], temp, 32); // patch for ralink proprietary STA-key issue ++ else if (RTMPCompareMemory(ANonce, SNonce, 32) == 1) ++ NdisMoveMemory(&concatenation[CurrPos], ANonce, 32); ++ else ++ NdisMoveMemory(&concatenation[CurrPos], SNonce, 32); ++ CurrPos += 32; ++ ++ hex_dump("concatenation=", concatenation, 76); ++ ++ // Use PRF to generate PTK ++ PRF(PMK, LEN_MASTER_KEY, Prefix, 22, concatenation, 76, output, len); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Generate random number by software. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ macAddr - pointer to local MAC address ++ ++ Return Value: ++ ++ Note: ++ 802.1ii-2004 Annex H.5 ++ ++ ======================================================================== ++*/ ++VOID GenRandom( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *macAddr, ++ OUT UCHAR *random) ++{ ++ INT i, curr; ++ UCHAR local[80], KeyCounter[32]; ++ UCHAR result[80]; ++ ULONG CurrentTime; ++ UCHAR prefix[] = {'I', 'n', 'i', 't', ' ', 'C', 'o', 'u', 'n', 't', 'e', 'r'}; ++ ++ // Zero the related information ++ NdisZeroMemory(result, 80); ++ NdisZeroMemory(local, 80); ++ NdisZeroMemory(KeyCounter, 32); ++ ++ for (i = 0; i < 32; i++) ++ { ++ // copy the local MAC address ++ COPY_MAC_ADDR(local, macAddr); ++ curr = MAC_ADDR_LEN; ++ ++ // concatenate the current time ++ NdisGetSystemUpTime(&CurrentTime); ++ NdisMoveMemory(&local[curr], &CurrentTime, sizeof(CurrentTime)); ++ curr += sizeof(CurrentTime); ++ ++ // concatenate the last result ++ NdisMoveMemory(&local[curr], result, 32); ++ curr += 32; ++ ++ // concatenate a variable ++ NdisMoveMemory(&local[curr], &i, 2); ++ curr += 2; ++ ++ // calculate the result ++ PRF(KeyCounter, 32, prefix,12, local, curr, result, 32); ++ } ++ ++ NdisMoveMemory(random, result, 32); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build cipher suite in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ WepStatus - indicate the encryption type ++ bMixCipher - a boolean to indicate the pairwise cipher and group ++ cipher are the same or not ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UINT WepStatus, ++ IN BOOLEAN bMixCipher, ++ IN UCHAR FlexibleCipher, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ UCHAR PairwiseCnt; ++ ++ *rsn_len = 0; ++ ++ // decide WPA2 or WPA1 ++ if (ElementID == Wpa2Ie) ++ { ++ RSNIE2 *pRsnie_cipher = (RSNIE2*)pRsnIe; ++ ++ // Assign the verson as 1 ++ pRsnie_cipher->version = 1; ++ ++ switch (WepStatus) ++ { ++ // TKIP mode ++ case Ndis802_11Encryption2Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); ++ *rsn_len = sizeof(RSNIE2); ++ break; ++ ++ // AES mode ++ case Ndis802_11Encryption3Enabled: ++ if (bMixCipher) ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ else ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_CCMP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); ++ *rsn_len = sizeof(RSNIE2); ++ break; ++ ++ // TKIP-AES mix mode ++ case Ndis802_11Encryption4Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_TKIP, 4); ++ ++ PairwiseCnt = 1; ++ // Insert WPA2 TKIP as the first pairwise cipher ++ if (MIX_CIPHER_WPA2_TKIP_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_TKIP, 4); ++ // Insert WPA2 AES as the secondary pairwise cipher ++ if (MIX_CIPHER_WPA2_AES_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA2_CCMP, 4); ++ PairwiseCnt = 2; ++ } ++ } ++ else ++ { ++ // Insert WPA2 AES as the first pairwise cipher ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA2_CCMP, 4); ++ } ++ ++ pRsnie_cipher->ucount = PairwiseCnt; ++ *rsn_len = sizeof(RSNIE2) + (4 * (PairwiseCnt - 1)); ++ break; ++ } ++ ++ // swap for big-endian platform ++ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); ++ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); ++ } ++ else ++ { ++ RSNIE *pRsnie_cipher = (RSNIE*)pRsnIe; ++ ++ // Assign OUI and version ++ NdisMoveMemory(pRsnie_cipher->oui, OUI_WPA_VERSION, 4); ++ pRsnie_cipher->version = 1; ++ ++ switch (WepStatus) ++ { ++ // TKIP mode ++ case Ndis802_11Encryption2Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); ++ *rsn_len = sizeof(RSNIE); ++ break; ++ ++ // AES mode ++ case Ndis802_11Encryption3Enabled: ++ if (bMixCipher) ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ else ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_CCMP, 4); ++ pRsnie_cipher->ucount = 1; ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); ++ *rsn_len = sizeof(RSNIE); ++ break; ++ ++ // TKIP-AES mix mode ++ case Ndis802_11Encryption4Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_TKIP, 4); ++ ++ PairwiseCnt = 1; ++ // Insert WPA TKIP as the first pairwise cipher ++ if (MIX_CIPHER_WPA_TKIP_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_TKIP, 4); ++ // Insert WPA AES as the secondary pairwise cipher ++ if (MIX_CIPHER_WPA_AES_ON(FlexibleCipher)) ++ { ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui + 4, OUI_WPA_CCMP, 4); ++ PairwiseCnt = 2; ++ } ++ } ++ else ++ { ++ // Insert WPA AES as the first pairwise cipher ++ NdisMoveMemory(pRsnie_cipher->ucast[0].oui, OUI_WPA_CCMP, 4); ++ } ++ ++ pRsnie_cipher->ucount = PairwiseCnt; ++ *rsn_len = sizeof(RSNIE) + (4 * (PairwiseCnt - 1)); ++ break; ++ } ++ ++ // swap for big-endian platform ++ pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); ++ pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build AKM suite in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ AuthMode - indicate the authentication mode ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeAKM( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UINT AuthMode, ++ IN UCHAR apidx, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ RSNIE_AUTH *pRsnie_auth; ++ ++ pRsnie_auth = (RSNIE_AUTH*)(pRsnIe + (*rsn_len)); ++ ++ // decide WPA2 or WPA1 ++ if (ElementID == Wpa2Ie) ++ { ++ switch (AuthMode) ++ { ++ case Ndis802_11AuthModeWPA2: ++ case Ndis802_11AuthModeWPA1WPA2: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_8021X_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPA2PSK: ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA2_PSK_AKM, 4); ++ break; ++ } ++ } ++ else ++ { ++ switch (AuthMode) ++ { ++ case Ndis802_11AuthModeWPA: ++ case Ndis802_11AuthModeWPA1WPA2: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_8021X_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPAPSK: ++ case Ndis802_11AuthModeWPA1PSKWPA2PSK: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_PSK_AKM, 4); ++ break; ++ ++ case Ndis802_11AuthModeWPANone: ++ pRsnie_auth->acount = 1; ++ NdisMoveMemory(pRsnie_auth->auth[0].oui, OUI_WPA_NONE_AKM, 4); ++ break; ++ } ++ } ++ ++ pRsnie_auth->acount = cpu2le16(pRsnie_auth->acount); ++ ++ (*rsn_len) += sizeof(RSNIE_AUTH); // update current RSNIE length ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build capability in RSN-IE. ++ It only shall be called by RTMPMakeRSNIE. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ ElementID - indicate the WPA1 or WPA2 ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++static VOID RTMPInsertRsnIeCap( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR ElementID, ++ IN UCHAR apidx, ++ OUT PUCHAR pRsnIe, ++ OUT UCHAR *rsn_len) ++{ ++ RSN_CAPABILITIES *pRSN_Cap; ++ ++ // it could be ignored in WPA1 mode ++ if (ElementID == WpaIe) ++ return; ++ ++ pRSN_Cap = (RSN_CAPABILITIES*)(pRsnIe + (*rsn_len)); ++ ++ ++ pRSN_Cap->word = cpu2le16(pRSN_Cap->word); ++ ++ (*rsn_len) += sizeof(RSN_CAPABILITIES); // update current RSNIE length ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Build RSN IE context. It is not included element-ID and length. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ AuthMode - indicate the authentication mode ++ WepStatus - indicate the encryption type ++ apidx - indicate the interface index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPMakeRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT AuthMode, ++ IN UINT WepStatus, ++ IN UCHAR apidx) ++{ ++ PUCHAR pRsnIe = NULL; // primary RSNIE ++ UCHAR *rsnielen_cur_p = 0; // the length of the primary RSNIE ++ UCHAR *rsnielen_ex_cur_p = 0; // the length of the secondary RSNIE ++ UCHAR PrimaryRsnie; ++ BOOLEAN bMixCipher = FALSE; // indicate the pairwise and group cipher are different ++ UCHAR p_offset; ++ WPA_MIX_PAIR_CIPHER FlexibleCipher = MIX_CIPHER_NOTUSE; // it provide the more flexible cipher combination in WPA-WPA2 and TKIPAES mode ++ ++ rsnielen_cur_p = NULL; ++ rsnielen_ex_cur_p = NULL; ++ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ if (AuthMode < Ndis802_11AuthModeWPA) ++ return; ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Support WPAPSK or WPA2PSK in STA-Infra mode ++ // Support WPANone in STA-Adhoc mode ++ if ((AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==> RTMPMakeRSNIE(STA)\n")); ++ ++ // Zero RSNIE context ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(pAd->StaCfg.RSN_IE, MAX_LEN_OF_RSNIE); ++ ++ // Pointer to RSNIE ++ rsnielen_cur_p = &pAd->StaCfg.RSNIE_Len; ++ pRsnIe = pAd->StaCfg.RSN_IE; ++ ++ bMixCipher = pAd->StaCfg.bMixCipher; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // indicate primary RSNIE as WPA or WPA2 ++ if ((AuthMode == Ndis802_11AuthModeWPA) || ++ (AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (AuthMode == Ndis802_11AuthModeWPANone) || ++ (AuthMode == Ndis802_11AuthModeWPA1WPA2) || ++ (AuthMode == Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ PrimaryRsnie = WpaIe; ++ else ++ PrimaryRsnie = Wpa2Ie; ++ ++ { ++ // Build the primary RSNIE ++ // 1. insert cipher suite ++ RTMPInsertRsnIeCipher(pAd, PrimaryRsnie, WepStatus, bMixCipher, FlexibleCipher, pRsnIe, &p_offset); ++ ++ // 2. insert AKM ++ RTMPInsertRsnIeAKM(pAd, PrimaryRsnie, AuthMode, apidx, pRsnIe, &p_offset); ++ ++ // 3. insert capability ++ RTMPInsertRsnIeCap(pAd, PrimaryRsnie, apidx, pRsnIe, &p_offset); ++ } ++ ++ // 4. update the RSNIE length ++ *rsnielen_cur_p = p_offset; ++ ++ hex_dump("The primary RSNIE", pRsnIe, (*rsnielen_cur_p)); ++ ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Check whether the received frame is EAP frame. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ pEntry - pointer to active entry ++ pData - the received frame ++ DataByteCount - the received frame's length ++ FromWhichBSSID - indicate the interface index ++ ++ Return: ++ TRUE - This frame is EAP frame ++ FALSE - otherwise ++ ========================================================================== ++*/ ++BOOLEAN RTMPCheckWPAframe( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR pData, ++ IN ULONG DataByteCount, ++ IN UCHAR FromWhichBSSID) ++{ ++ ULONG Body_len; ++ BOOLEAN Cancelled; ++ ++ ++ if(DataByteCount < (LENGTH_802_1_H + LENGTH_EAPOL_H)) ++ return FALSE; ++ ++ ++ // Skip LLC header ++ if (NdisEqualMemory(SNAP_802_1H, pData, 6) || ++ // Cisco 1200 AP may send packet with SNAP_BRIDGE_TUNNEL ++ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, pData, 6)) ++ { ++ pData += 6; ++ } ++ // Skip 2-bytes EAPoL type ++ if (NdisEqualMemory(EAPOL, pData, 2)) ++ { ++ pData += 2; ++ } ++ else ++ return FALSE; ++ ++ switch (*(pData+1)) ++ { ++ case EAPPacket: ++ Body_len = (*(pData+2)<<8) | (*(pData+3)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAP-Packet frame, TYPE = 0, Length = %ld\n", Body_len)); ++ break; ++ case EAPOLStart: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Start frame, TYPE = 1 \n")); ++ if (pEntry->EnqueueEapolStartTimerRunning != EAPOL_START_DISABLE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Cancel the EnqueueEapolStartTimerRunning \n")); ++ RTMPCancelTimer(&pEntry->EnqueueStartForPSKTimer, &Cancelled); ++ pEntry->EnqueueEapolStartTimerRunning = EAPOL_START_DISABLE; ++ } ++ break; ++ case EAPOLLogoff: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLLogoff frame, TYPE = 2 \n")); ++ break; ++ case EAPOLKey: ++ Body_len = (*(pData+2)<<8) | (*(pData+3)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL-Key frame, TYPE = 3, Length = %ld\n", Body_len)); ++ break; ++ case EAPOLASFAlert: ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOLASFAlert frame, TYPE = 4 \n")); ++ break; ++ default: ++ return FALSE; ++ ++ } ++ return TRUE; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ENCRYPT AES GTK before sending in EAPOL frame. ++ AES GTK length = 128 bit, so fix blocks for aes-key-wrap as 2 in this function. ++ This function references to RFC 3394 for aes key wrap algorithm. ++ Return: ++ ========================================================================== ++*/ ++VOID AES_GTK_KEY_WRAP( ++ IN UCHAR *key, ++ IN UCHAR *plaintext, ++ IN UCHAR p_len, ++ OUT UCHAR *ciphertext) ++{ ++ UCHAR A[8], BIN[16], BOUT[16]; ++ UCHAR R[512]; ++ INT num_blocks = p_len/8; // unit:64bits ++ INT i, j; ++ aes_context aesctx; ++ UCHAR xor; ++ ++ rtmp_aes_set_key(&aesctx, key, 128); ++ ++ // Init IA ++ for (i = 0; i < 8; i++) ++ A[i] = 0xa6; ++ ++ //Input plaintext ++ for (i = 0; i < num_blocks; i++) ++ { ++ for (j = 0 ; j < 8; j++) ++ R[8 * (i + 1) + j] = plaintext[8 * i + j]; ++ } ++ ++ // Key Mix ++ for (j = 0; j < 6; j++) ++ { ++ for(i = 1; i <= num_blocks; i++) ++ { ++ //phase 1 ++ NdisMoveMemory(BIN, A, 8); ++ NdisMoveMemory(&BIN[8], &R[8 * i], 8); ++ rtmp_aes_encrypt(&aesctx, BIN, BOUT); ++ ++ NdisMoveMemory(A, &BOUT[0], 8); ++ xor = num_blocks * j + i; ++ A[7] = BOUT[7] ^ xor; ++ NdisMoveMemory(&R[8 * i], &BOUT[8], 8); ++ } ++ } ++ ++ // Output ciphertext ++ NdisMoveMemory(ciphertext, A, 8); ++ ++ for (i = 1; i <= num_blocks; i++) ++ { ++ for (j = 0 ; j < 8; j++) ++ ciphertext[8 * i + j] = R[8 * i + j]; ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Misc function to decrypt AES body ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ This function references to RFC 3394 for aes key unwrap algorithm. ++ ++ ======================================================================== ++*/ ++VOID AES_GTK_KEY_UNWRAP( ++ IN UCHAR *key, ++ OUT UCHAR *plaintext, ++ IN UCHAR c_len, ++ IN UCHAR *ciphertext) ++ ++{ ++ UCHAR A[8], BIN[16], BOUT[16]; ++ UCHAR xor; ++ INT i, j; ++ aes_context aesctx; ++ UCHAR *R; ++ INT num_blocks = c_len/8; // unit:64bits ++ ++ ++ os_alloc_mem(NULL, (PUCHAR *)&R, 512); ++ ++ if (R == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!AES_GTK_KEY_UNWRAP: no memory!!!\n")); ++ return; ++ } /* End of if */ ++ ++ // Initialize ++ NdisMoveMemory(A, ciphertext, 8); ++ //Input plaintext ++ for(i = 0; i < (c_len-8); i++) ++ { ++ R[ i] = ciphertext[i + 8]; ++ } ++ ++ rtmp_aes_set_key(&aesctx, key, 128); ++ ++ for(j = 5; j >= 0; j--) ++ { ++ for(i = (num_blocks-1); i > 0; i--) ++ { ++ xor = (num_blocks -1 )* j + i; ++ NdisMoveMemory(BIN, A, 8); ++ BIN[7] = A[7] ^ xor; ++ NdisMoveMemory(&BIN[8], &R[(i-1)*8], 8); ++ rtmp_aes_decrypt(&aesctx, BIN, BOUT); ++ NdisMoveMemory(A, &BOUT[0], 8); ++ NdisMoveMemory(&R[(i-1)*8], &BOUT[8], 8); ++ } ++ } ++ ++ // OUTPUT ++ for(i = 0; i < c_len; i++) ++ { ++ plaintext[i] = R[i]; ++ } ++ ++ ++ os_free_mem(NULL, R); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Report the EAP message type ++ ++ Arguments: ++ msg - EAPOL_PAIR_MSG_1 ++ EAPOL_PAIR_MSG_2 ++ EAPOL_PAIR_MSG_3 ++ EAPOL_PAIR_MSG_4 ++ EAPOL_GROUP_MSG_1 ++ EAPOL_GROUP_MSG_2 ++ ++ Return: ++ message type string ++ ++ ========================================================================== ++*/ ++CHAR *GetEapolMsgType(CHAR msg) ++{ ++ if(msg == EAPOL_PAIR_MSG_1) ++ return "Pairwise Message 1"; ++ else if(msg == EAPOL_PAIR_MSG_2) ++ return "Pairwise Message 2"; ++ else if(msg == EAPOL_PAIR_MSG_3) ++ return "Pairwise Message 3"; ++ else if(msg == EAPOL_PAIR_MSG_4) ++ return "Pairwise Message 4"; ++ else if(msg == EAPOL_GROUP_MSG_1) ++ return "Group Message 1"; ++ else if(msg == EAPOL_GROUP_MSG_2) ++ return "Group Message 2"; ++ else ++ return "Invalid Message"; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Sanity RSN IE of EAPoL message ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ IN MAC_TABLE_ENTRY *pEntry, ++ OUT UCHAR *Offset) ++{ ++ PUCHAR pVIE; ++ UCHAR len; ++ PEID_STRUCT pEid; ++ BOOLEAN result = FALSE; ++ ++ pVIE = pData; ++ len = DataLen; ++ *Offset = 0; ++ ++ while (len > sizeof(RSNIE2)) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // WPA RSN IE ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) ++ { ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA || pEntry->AuthMode == Ndis802_11AuthModeWPAPSK) && ++ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && ++ (pEntry->RSNIE_Len == (pEid->Len + 2))) ++ { ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ // WPA2 RSN IE ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) ++ { ++ if ((pEntry->AuthMode == Ndis802_11AuthModeWPA2 || pEntry->AuthMode == Ndis802_11AuthModeWPA2PSK) && ++ (NdisEqualMemory(pVIE, pEntry->RSN_IE, pEntry->RSNIE_Len)) && ++ (pEntry->RSNIE_Len == (pEid->Len + 2))/* ToDo-AlbertY for mesh*/) ++ { ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ else ++ { ++ break; ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ ++ ++ return result; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. ++ GTK is encaptulated in KDE format at p.83 802.11i D10 ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ 802.11i D10 ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPParseEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR GroupKeyIndex, ++ IN UCHAR MsgType, ++ IN BOOLEAN bWPA2, ++ IN MAC_TABLE_ENTRY *pEntry) ++{ ++ PKDE_ENCAP pKDE = NULL; ++ PUCHAR pMyKeyData = pKeyData; ++ UCHAR KeyDataLength = KeyDataLen; ++ UCHAR GTKLEN = 0; ++ UCHAR DefaultIdx = 0; ++ UCHAR skip_offset; ++ ++ // Verify The RSN IE contained in pairewise_msg_2 && pairewise_msg_3 and skip it ++ if (MsgType == EAPOL_PAIR_MSG_2 || MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // Check RSN IE whether it is WPA2/WPA2PSK ++ if (!RTMPCheckRSNIE(pAd, pKeyData, KeyDataLen, pEntry, &skip_offset)) ++ { ++ // send wireless event - for RSN IE different ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_RSNIE_DIFF_EVENT_FLAG, pEntry->Addr, pEntry->apidx, 0); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in msg %d of 4-way handshake!\n", MsgType)); ++ hex_dump("Receive RSN_IE ", pKeyData, KeyDataLen); ++ hex_dump("Desired RSN_IE ", pEntry->RSN_IE, pEntry->RSNIE_Len); ++ ++ return FALSE; ++ } ++ else ++ { ++ if (bWPA2 && MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // skip RSN IE ++ pMyKeyData += skip_offset; ++ KeyDataLength -= skip_offset; ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPParseEapolKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); ++ } ++ else ++ return TRUE; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPParseEapolKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); ++ ++ // Parse EKD format in pairwise_msg_3_WPA2 && group_msg_1_WPA2 ++ if (bWPA2 && (MsgType == EAPOL_PAIR_MSG_3 || MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ if (KeyDataLength >= 8) // KDE format exclude GTK length ++ { ++ pKDE = (PKDE_ENCAP) pMyKeyData; ++ ++ ++ DefaultIdx = pKDE->GTKEncap.Kid; ++ ++ // Sanity check - KED length ++ if (KeyDataLength < (pKDE->Len + 2)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); ++ return FALSE; ++ } ++ ++ // Get GTK length - refer to IEEE 802.11i-2004 p.82 ++ GTKLEN = pKDE->Len -6; ++ if (GTKLEN < LEN_AES_KEY) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); ++ return FALSE; ++ } ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KDE format length is too short \n")); ++ return FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK in KDE format ,DefaultKeyID=%d, KeyLen=%d \n", DefaultIdx, GTKLEN)); ++ // skip it ++ pMyKeyData += 8; ++ KeyDataLength -= 8; ++ ++ } ++ else if (!bWPA2 && MsgType == EAPOL_GROUP_MSG_1) ++ { ++ DefaultIdx = GroupKeyIndex; ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK DefaultKeyID=%d \n", DefaultIdx)); ++ } ++ ++ // Sanity check - shared key index must be 1 ~ 3 ++ if (DefaultIdx < 1 || DefaultIdx > 3) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index(%d) is invalid in %s %s \n", DefaultIdx, ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); ++ return FALSE; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ // Todo ++#endif // CONFIG_STA_SUPPORT // ++ ++ return TRUE; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Construct EAPoL message for WPA handshaking ++ Its format is below, ++ ++ +--------------------+ ++ | Protocol Version | 1 octet ++ +--------------------+ ++ | Protocol Type | 1 octet ++ +--------------------+ ++ | Body Length | 2 octets ++ +--------------------+ ++ | Descriptor Type | 1 octet ++ +--------------------+ ++ | Key Information | 2 octets ++ +--------------------+ ++ | Key Length | 1 octet ++ +--------------------+ ++ | Key Repaly Counter | 8 octets ++ +--------------------+ ++ | Key Nonce | 32 octets ++ +--------------------+ ++ | Key IV | 16 octets ++ +--------------------+ ++ | Key RSC | 8 octets ++ +--------------------+ ++ | Key ID or Reserved | 8 octets ++ +--------------------+ ++ | Key MIC | 16 octets ++ +--------------------+ ++ | Key Data Length | 2 octets ++ +--------------------+ ++ | Key Data | n octets ++ +--------------------+ ++ ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ConstructEapolMsg( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AuthMode, ++ IN UCHAR WepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN UCHAR *ReplayCounter, ++ IN UCHAR *KeyNonce, ++ IN UCHAR *TxRSC, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_Len, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ BOOLEAN bWPA2 = FALSE; ++ ++ // Choose WPA2 or not ++ if ((AuthMode == Ndis802_11AuthModeWPA2) || (AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ bWPA2 = TRUE; ++ ++ // Init Packet and Fill header ++ pMsg->ProVer = EAPOL_VER; ++ pMsg->ProType = EAPOLKey; ++ ++ // Default 95 bytes, the EAPoL-Key descriptor exclude Key-data field ++ pMsg->Body_Len[1] = LEN_EAPOL_KEY_MSG; ++ ++ // Fill in EAPoL descriptor ++ if (bWPA2) ++ pMsg->KeyDesc.Type = WPA2_KEY_DESC; ++ else ++ pMsg->KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Fill in Key information, refer to IEEE Std 802.11i-2004 page 78 ++ // When either the pairwise or the group cipher is AES, the DESC_TYPE_AES(2) shall be used. ++ pMsg->KeyDesc.KeyInfo.KeyDescVer = ++ (((WepStatus == Ndis802_11Encryption3Enabled) || (GroupKeyWepStatus == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ // Specify Key Type as Group(0) or Pairwise(1) ++ if (MsgType >= EAPOL_GROUP_MSG_1) ++ pMsg->KeyDesc.KeyInfo.KeyType = GROUPKEY; ++ else ++ pMsg->KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // Specify Key Index, only group_msg1_WPA1 ++ if (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1)) ++ pMsg->KeyDesc.KeyInfo.KeyIndex = DefaultKeyIdx; ++ ++ if (MsgType == EAPOL_PAIR_MSG_3) ++ pMsg->KeyDesc.KeyInfo.Install = 1; ++ ++ if ((MsgType == EAPOL_PAIR_MSG_1) || (MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1)) ++ pMsg->KeyDesc.KeyInfo.KeyAck = 1; ++ ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ pMsg->KeyDesc.KeyInfo.KeyMic = 1; ++ ++ if ((bWPA2 && (MsgType >= EAPOL_PAIR_MSG_3)) || (!bWPA2 && (MsgType >= EAPOL_GROUP_MSG_1))) ++ { ++ pMsg->KeyDesc.KeyInfo.Secure = 1; ++ } ++ ++ if (bWPA2 && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) ++ { ++ pMsg->KeyDesc.KeyInfo.EKD_DL = 1; ++ } ++ ++ // key Information element has done. ++ *(USHORT *)(&pMsg->KeyDesc.KeyInfo) = cpu2le16(*(USHORT *)(&pMsg->KeyDesc.KeyInfo)); ++ ++ // Fill in Key Length ++ { ++ if (MsgType >= EAPOL_GROUP_MSG_1) ++ { ++ // the length of group key cipher ++ pMsg->KeyDesc.KeyLength[1] = ((GroupKeyWepStatus == Ndis802_11Encryption2Enabled) ? TKIP_GTK_LENGTH : LEN_AES_KEY); ++ } ++ else ++ { ++ // the length of pairwise key cipher ++ pMsg->KeyDesc.KeyLength[1] = ((WepStatus == Ndis802_11Encryption2Enabled) ? LEN_TKIP_KEY : LEN_AES_KEY); ++ } ++ } ++ ++ // Fill in replay counter ++ NdisMoveMemory(pMsg->KeyDesc.ReplayCounter, ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Fill Key Nonce field ++ // ANonce : pairwise_msg1 & pairwise_msg3 ++ // SNonce : pairwise_msg2 ++ // GNonce : group_msg1_wpa1 ++ if ((MsgType <= EAPOL_PAIR_MSG_3) || ((!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)))) ++ NdisMoveMemory(pMsg->KeyDesc.KeyNonce, KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Fill key IV - WPA2 as 0, WPA1 as random ++ if (!bWPA2 && (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ // Suggest IV be random number plus some number, ++ NdisMoveMemory(pMsg->KeyDesc.KeyIv, &KeyNonce[16], LEN_KEY_DESC_IV); ++ pMsg->KeyDesc.KeyIv[15] += 2; ++ } ++ ++ // Fill Key RSC field ++ // It contains the RSC for the GTK being installed. ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ NdisMoveMemory(pMsg->KeyDesc.KeyRsc, TxRSC, 6); ++ } ++ ++ // Clear Key MIC field for MIC calculation later ++ NdisZeroMemory(pMsg->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ ConstructEapolKeyData(pAd, ++ AuthMode, ++ WepStatus, ++ GroupKeyWepStatus, ++ MsgType, ++ DefaultKeyIdx, ++ bWPA2, ++ PTK, ++ GTK, ++ RSNIE, ++ RSNIE_Len, ++ pMsg); ++ ++ // Calculate MIC and fill in KeyMic Field except Pairwise Msg 1. ++ if (MsgType != EAPOL_PAIR_MSG_1) ++ { ++ CalculateMIC(pAd, WepStatus, PTK, pMsg); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> ConstructEapolMsg for %s %s\n", ((bWPA2) ? "WPA2" : "WPA"), GetEapolMsgType(MsgType))); ++ DBGPRINT(RT_DEBUG_TRACE, (" Body length = %d \n", pMsg->Body_Len[1])); ++ DBGPRINT(RT_DEBUG_TRACE, (" Key length = %d \n", pMsg->KeyDesc.KeyLength[1])); ++ ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Construct the Key Data field of EAPoL message ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ConstructEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AuthMode, ++ IN UCHAR WepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN BOOLEAN bWPA2Capable, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_LEN, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ UCHAR *mpool, *Key_Data, *Rc4GTK; ++ UCHAR ekey[(LEN_KEY_DESC_IV+LEN_EAP_EK)]; ++ UCHAR data_offset; ++ ++ ++ if (MsgType == EAPOL_PAIR_MSG_1 || MsgType == EAPOL_PAIR_MSG_4 || MsgType == EAPOL_GROUP_MSG_2) ++ return; ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1500); ++ ++ if (mpool == NULL) ++ return; ++ ++ /* Rc4GTK Len = 512 */ ++ Rc4GTK = (UCHAR *) ROUND_UP(mpool, 4); ++ /* Key_Data Len = 512 */ ++ Key_Data = (UCHAR *) ROUND_UP(Rc4GTK + 512, 4); ++ ++ NdisZeroMemory(Key_Data, 512); ++ pMsg->KeyDesc.KeyDataLen[1] = 0; ++ data_offset = 0; ++ ++ // Encapsulate RSNIE in pairwise_msg2 & pairwise_msg3 ++ if (RSNIE_LEN && ((MsgType == EAPOL_PAIR_MSG_2) || (MsgType == EAPOL_PAIR_MSG_3))) ++ { ++ if (bWPA2Capable) ++ Key_Data[data_offset + 0] = IE_WPA2; ++ else ++ Key_Data[data_offset + 0] = IE_WPA; ++ ++ Key_Data[data_offset + 1] = RSNIE_LEN; ++ NdisMoveMemory(&Key_Data[data_offset + 2], RSNIE, RSNIE_LEN); ++ data_offset += (2 + RSNIE_LEN); ++ } ++ ++ // Encapsulate KDE format in pairwise_msg3_WPA2 & group_msg1_WPA2 ++ if (bWPA2Capable && ((MsgType == EAPOL_PAIR_MSG_3) || (MsgType == EAPOL_GROUP_MSG_1))) ++ { ++ // Key Data Encapsulation (KDE) format - 802.11i-2004 Figure-43w and Table-20h ++ Key_Data[data_offset + 0] = 0xDD; ++ ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Key_Data[data_offset + 1] = 0x16;// 4+2+16(OUI+DataType+DataField) ++ } ++ else ++ { ++ Key_Data[data_offset + 1] = 0x26;// 4+2+32(OUI+DataType+DataField) ++ } ++ ++ Key_Data[data_offset + 2] = 0x00; ++ Key_Data[data_offset + 3] = 0x0F; ++ Key_Data[data_offset + 4] = 0xAC; ++ Key_Data[data_offset + 5] = 0x01; ++ ++ // GTK KDE format - 802.11i-2004 Figure-43x ++ Key_Data[data_offset + 6] = (DefaultKeyIdx & 0x03); ++ Key_Data[data_offset + 7] = 0x00; // Reserved Byte ++ ++ data_offset += 8; ++ } ++ ++ ++ // Encapsulate GTK and encrypt the key-data field with KEK. ++ // Only for pairwise_msg3_WPA2 and group_msg1 ++ if ((MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) || (MsgType == EAPOL_GROUP_MSG_1)) ++ { ++ // Fill in GTK ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ NdisMoveMemory(&Key_Data[data_offset], GTK, LEN_AES_KEY); ++ data_offset += LEN_AES_KEY; ++ } ++ else ++ { ++ NdisMoveMemory(&Key_Data[data_offset], GTK, TKIP_GTK_LENGTH); ++ data_offset += TKIP_GTK_LENGTH; ++ } ++ ++ // Still dont know why, but if not append will occur "GTK not include in MSG3" ++ // Patch for compatibility between zero config and funk ++ if (MsgType == EAPOL_PAIR_MSG_3 && bWPA2Capable) ++ { ++ if (GroupKeyWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Key_Data[data_offset + 0] = 0xDD; ++ Key_Data[data_offset + 1] = 0; ++ data_offset += 2; ++ } ++ else ++ { ++ Key_Data[data_offset + 0] = 0xDD; ++ Key_Data[data_offset + 1] = 0; ++ Key_Data[data_offset + 2] = 0; ++ Key_Data[data_offset + 3] = 0; ++ Key_Data[data_offset + 4] = 0; ++ Key_Data[data_offset + 5] = 0; ++ data_offset += 6; ++ } ++ } ++ ++ // Encrypt the data material in key data field ++ if (WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ AES_GTK_KEY_WRAP(&PTK[16], Key_Data, data_offset, Rc4GTK); ++ // AES wrap function will grow 8 bytes in length ++ data_offset += 8; ++ } ++ else ++ { ++ // PREPARE Encrypted "Key DATA" field. (Encrypt GTK with RC4, usinf PTK[16]->[31] as Key, IV-field as IV) ++ // put TxTsc in Key RSC field ++ pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. ++ ++ // ekey is the contanetion of IV-field, and PTK[16]->PTK[31] ++ NdisMoveMemory(ekey, pMsg->KeyDesc.KeyIv, LEN_KEY_DESC_IV); ++ NdisMoveMemory(&ekey[LEN_KEY_DESC_IV], &PTK[16], LEN_EAP_EK); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, ekey, sizeof(ekey)); //INIT SBOX, KEYLEN+3(IV) ++ pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, Key_Data, data_offset); ++ WPAARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, Rc4GTK, Key_Data, data_offset); ++ } ++ ++ NdisMoveMemory(pMsg->KeyDesc.KeyData, Rc4GTK, data_offset); ++ } ++ else ++ { ++ NdisMoveMemory(pMsg->KeyDesc.KeyData, Key_Data, data_offset); ++ } ++ ++ // set key data length field and total length ++ pMsg->KeyDesc.KeyDataLen[1] = data_offset; ++ pMsg->Body_Len[1] += data_offset; ++ ++ os_free_mem(pAd, mpool); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calcaulate MIC. It is used during 4-ways handsharking. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PeerWepStatus - indicate the encryption type ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID CalculateMIC( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR *PTK, ++ OUT PEAPOL_PACKET pMsg) ++{ ++ UCHAR *OutBuffer; ++ ULONG FrameLen = 0; ++ UCHAR mic[LEN_KEY_DESC_MIC]; ++ UCHAR digest[80]; ++ ++ // allocate memory for MIC calculation ++ os_alloc_mem(pAd, (PUCHAR *)&OutBuffer, 512); ++ ++ if (OutBuffer == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("!!!CalculateMIC: no memory!!!\n")); ++ return; ++ } ++ ++ // make a frame for calculating MIC. ++ MakeOutgoingFrame(OutBuffer, &FrameLen, ++ pMsg->Body_Len[1] + 4, pMsg, ++ END_OF_ARGS); ++ ++ NdisZeroMemory(mic, sizeof(mic)); ++ ++ // Calculate MIC ++ if (PeerWepStatus == Ndis802_11Encryption3Enabled) ++ { ++ HMAC_SHA1(OutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(PTK, LEN_EAP_MICK, OutBuffer, FrameLen, mic); ++ } ++ ++ // store the calculated MIC ++ NdisMoveMemory(pMsg->KeyDesc.KeyMic, mic, LEN_KEY_DESC_MIC); ++ ++ os_free_mem(pAd, OutBuffer); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Some received frames can't decrypt by Asic, so decrypt them by software. ++ ++ Arguments: ++ pAd - pointer to our pAdapter context ++ PeerWepStatus - indicate the encryption type ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS - decryption successful ++ NDIS_STATUS_FAILURE - decryption failure ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPSoftDecryptBroadCastData( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, ++ IN PCIPHER_KEY pShard_key) ++{ ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ ++ ++ ++ // handle WEP decryption ++ if (GroupCipher == Ndis802_11Encryption1Enabled) ++ { ++ if (RTMPSoftDecryptWEP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, pShard_key)) ++ { ++ ++ //Minus IV[4] & ICV[4] ++ pRxWI->MPDUtotalByteCount -= 8; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : Software decrypt WEP data fails.\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ // handle TKIP decryption ++ else if (GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ if (RTMPSoftDecryptTKIP(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount, 0, pShard_key)) ++ { ++ ++ //Minus 8 bytes MIC, 8 bytes IV/EIV, 4 bytes ICV ++ pRxWI->MPDUtotalByteCount -= 20; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptTKIP Failed\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ // handle AES decryption ++ else if (GroupCipher == Ndis802_11Encryption3Enabled) ++ { ++ if (RTMPSoftDecryptAES(pAd, pRxBlk->pData, pRxWI->MPDUtotalByteCount , pShard_key)) ++ { ++ ++ //8 bytes MIC, 8 bytes IV/EIV (CCMP Header) ++ pRxWI->MPDUtotalByteCount -= 16; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR : RTMPSoftDecryptAES Failed\n")); ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ else ++ { ++ // give up this frame ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/dfs.c +@@ -0,0 +1,441 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ ap_dfs.c ++ ++ Abstract: ++ Support DFS function. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi 03-12-2007 created ++*/ ++ ++#include "../rt_config.h" ++ ++typedef struct _RADAR_DURATION_TABLE ++{ ++ ULONG RDDurRegion; ++ ULONG RadarSignalDuration; ++ ULONG Tolerance; ++} RADAR_DURATION_TABLE, *PRADAR_DURATION_TABLE; ++ ++ ++static UCHAR RdIdleTimeTable[MAX_RD_REGION][4] = ++{ ++ {9, 250, 250, 250}, // CE ++ {4, 250, 250, 250}, // FCC ++ {4, 250, 250, 250}, // JAP ++ {15, 250, 250, 250}, // JAP_W53 ++ {4, 250, 250, 250} // JAP_W56 ++}; ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Bbp Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID BbpRadarDetectionStart( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT8 RadarPeriod; ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 114, 0x02); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 121, 0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 122, 0x00); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 123, 0x08/*0x80*/); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 124, 0x28); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, 125, 0xff); ++ ++ RadarPeriod = ((UINT)RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + (UINT)pAd->CommonCfg.RadarDetect.DfsSessionTime) < 250 ? ++ (RdIdleTimeTable[pAd->CommonCfg.RadarDetect.RDDurRegion][0] + pAd->CommonCfg.RadarDetect.DfsSessionTime) : 250; ++ ++ RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); ++ RTMP_IO_WRITE8(pAd, 0x7021, 0x40); ++ ++ RadarDetectionStart(pAd, 0, RadarPeriod); ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Bbp Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID BbpRadarDetectionStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RTMP_IO_WRITE8(pAd, 0x7020, 0x1d); ++ RTMP_IO_WRITE8(pAd, 0x7021, 0x60); ++ ++ RadarDetectionStop(pAd); ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ ++ ======================================================================== ++*/ ++VOID RadarDetectionStart( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN CTSProtect, ++ IN UINT8 CTSPeriod) ++{ ++ UINT8 DfsActiveTime = (pAd->CommonCfg.RadarDetect.DfsSessionTime & 0x1f); ++ UINT8 CtsProtect = (CTSProtect == 1) ? 0x02 : 0x01; // CTS protect. ++ ++ if (CTSProtect != 0) ++ { ++ switch(pAd->CommonCfg.RadarDetect.RDDurRegion) ++ { ++ case FCC: ++ case JAP_W56: ++ CtsProtect = 0x03; ++ break; ++ ++ case CE: ++ case JAP_W53: ++ default: ++ CtsProtect = 0x02; ++ break; ++ } ++ } ++ else ++ CtsProtect = 0x01; ++ ++ ++ // send start-RD with CTS protection command to MCU ++ // highbyte [7] reserve ++ // highbyte [6:5] 0x: stop Carrier/Radar detection ++ // highbyte [10]: Start Carrier/Radar detection without CTS protection, 11: Start Carrier/Radar detection with CTS protection ++ // highbyte [4:0] Radar/carrier detection duration. In 1ms. ++ ++ // lowbyte [7:0] Radar/carrier detection period, in 1ms. ++ AsicSendCommandToMcu(pAd, 0x60, 0xff, CTSPeriod, DfsActiveTime | (CtsProtect << 5)); ++ //AsicSendCommandToMcu(pAd, 0x63, 0xff, 10, 0); ++ ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar detection routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ TRUE Found radar signal ++ FALSE Not found radar signal ++ ++ ======================================================================== ++*/ ++VOID RadarDetectionStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE,("RadarDetectionStop.\n")); ++ AsicSendCommandToMcu(pAd, 0x60, 0xff, 0x00, 0x00); // send start-RD with CTS protection command to MCU ++ ++ return; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Radar channel check routine ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ TRUE need to do radar detect ++ FALSE need not to do radar detect ++ ++ ======================================================================== ++*/ ++BOOLEAN RadarChannelCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ch) ++{ ++#if 1 ++ INT i; ++ BOOLEAN result = FALSE; ++ ++ for (i=0; iChannelListNum; i++) ++ { ++ if (Ch == pAd->ChannelList[i].Channel) ++ { ++ result = pAd->ChannelList[i].DfsReq; ++ break; ++ } ++ } ++ ++ return result; ++#else ++ INT i; ++ UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ ++ for (i=0; i<15; i++) ++ { ++ if (Ch == Channel[i]) ++ { ++ break; ++ } ++ } ++ ++ if (i != 15) ++ return TRUE; ++ else ++ return FALSE; ++#endif ++} ++ ++ULONG JapRadarType( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ const UCHAR Channel[15]={52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}; ++ ++ if (pAd->CommonCfg.RadarDetect.RDDurRegion != JAP) ++ { ++ return pAd->CommonCfg.RadarDetect.RDDurRegion; ++ } ++ ++ for (i=0; i<15; i++) ++ { ++ if (pAd->CommonCfg.Channel == Channel[i]) ++ { ++ break; ++ } ++ } ++ ++ if (i < 4) ++ return JAP_W53; ++ else if (i < 15) ++ return JAP_W56; ++ else ++ return JAP; // W52 ++ ++} ++ ++ULONG RTMPBbpReadRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT8 byteValue = 0; ++ ULONG result; ++ ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R115, &byteValue); ++ ++ result = 0; ++ switch (byteValue) ++ { ++ case 1: // radar signal detected by pulse mode. ++ case 2: // radar signal detected by width mode. ++ result = RTMPReadRadarDuration(pAd); ++ break; ++ ++ case 0: // No radar signal. ++ default: ++ ++ result = 0; ++ break; ++ } ++ ++ return result; ++} ++ ++ULONG RTMPReadRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG result = 0; ++ ++#ifdef DFS_SUPPORT ++ UINT8 duration1 = 0, duration2 = 0, duration3 = 0; ++ ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R116, &duration1); ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R117, &duration2); ++ BBP_IO_READ8_BY_REG_ID(pAd, BBP_R118, &duration3); ++ result = (duration1 << 16) + (duration2 << 8) + duration3; ++#endif // DFS_SUPPORT // ++ ++ return result; ++ ++} ++ ++VOID RTMPCleanRadarDuration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Radar wave detection. The API should be invoke each second. ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID ApRadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i; ++ ++ pAd->CommonCfg.RadarDetect.InServiceMonitorCount++; ++ ++ for (i=0; iChannelListNum; i++) ++ { ++ if (pAd->ChannelList[i].RemainingTimeForUse > 0) ++ { ++ pAd->ChannelList[i].RemainingTimeForUse --; ++ if ((pAd->Mlme.PeriodicRound%5) == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RadarDetectPeriodic - ch=%d, RemainingTimeForUse=%d\n", pAd->ChannelList[i].Channel, pAd->ChannelList[i].RemainingTimeForUse)); ++ } ++ } ++ } ++ ++ //radar detect ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ RadarDetectPeriodic(pAd); ++ } ++ ++ return; ++} ++ ++// Periodic Radar detection, switch channel will occur in RTMPHandleTBTTInterrupt() ++// Before switch channel, driver needs doing channel switch announcement. ++VOID RadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // need to check channel availability, after switch channel ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_SILENCE_MODE) ++ return; ++ ++ // channel availability check time is 60sec, use 65 for assurance ++ if (pAd->CommonCfg.RadarDetect.RDCount++ > pAd->CommonCfg.RadarDetect.ChMovingTime) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Not found radar signal, start send beacon and radar detection in service monitor\n\n")); ++ BbpRadarDetectionStop(pAd); ++ AsicEnableBssSync(pAd); ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ ++ ++ return; ++ } ++ ++ return; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ change channel moving time for DFS testing. ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 set ChMovTime=[value] ++ ========================================================================== ++*/ ++INT Set_ChMovingTime_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT8 Value; ++ ++ Value = simple_strtol(arg, 0, 10); ++ ++ pAd->CommonCfg.RadarDetect.ChMovingTime = Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ pAd->CommonCfg.RadarDetect.ChMovingTime)); ++ ++ return TRUE; ++} ++ ++INT Set_LongPulseRadarTh_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT8 Value; ++ ++ Value = simple_strtol(arg, 0, 10) > 10 ? 10 : simple_strtol(arg, 0, 10); ++ ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh)); ++ ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/eeprom.c +@@ -0,0 +1,1498 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ eeprom.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#include "../rt_config.h" ++ ++// IRQL = PASSIVE_LEVEL ++VOID RaiseClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x) ++{ ++ *x = *x | EESK; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); ++ RTMPusecDelay(1); // Max frequency = 1MHz in Spec. definition ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID LowerClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x) ++{ ++ *x = *x & ~EESK; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, *x); ++ RTMPusecDelay(1); ++} ++ ++// IRQL = PASSIVE_LEVEL ++USHORT ShiftInBits( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x,i; ++ USHORT data=0; ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~( EEDO | EEDI); ++ ++ for(i=0; i<16; i++) ++ { ++ data = data << 1; ++ RaiseClock(pAd, &x); ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ LowerClock(pAd, &x); //prevent read failed ++ ++ x &= ~(EEDI); ++ if(x & EEDO) ++ data |= 1; ++ } ++ ++ return data; ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID ShiftOutBits( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT data, ++ IN USHORT count) ++{ ++ UINT32 x,mask; ++ ++ mask = 0x01 << (count - 1); ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EEDO | EEDI); ++ ++ do ++ { ++ x &= ~EEDI; ++ if(data & mask) x |= EEDI; ++ ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ mask = mask >> 1; ++ } while(mask); ++ ++ x &= ~EEDI; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++} ++ ++// IRQL = PASSIVE_LEVEL ++VOID EEpromCleanup( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ x &= ~(EECS | EEDI); ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++} ++ ++VOID EWEN( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and six pulse in that order ++ ShiftOutBits(pAd, EEPROM_EWEN_OPCODE, 5); ++ ShiftOutBits(pAd, 0, 6); ++ ++ EEpromCleanup(pAd); ++} ++ ++VOID EWDS( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 x; ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ ++ // output the read_opcode and six pulse in that order ++ ShiftOutBits(pAd, EEPROM_EWDS_OPCODE, 5); ++ ShiftOutBits(pAd, 0, 6); ++ ++ EEpromCleanup(pAd); ++} ++ ++// IRQL = PASSIVE_LEVEL ++USHORT RTMP_EEPROM_READ16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset) ++{ ++ UINT32 x; ++ USHORT data; ++ ++ if (pAd->NicConfig2.field.AntDiversity) ++ { ++ pAd->EepromAccess = TRUE; ++ } ++//2008/09/11:KH add to support efuse<-- ++//2008/09/11:KH add to support efuse--> ++{ ++ Offset /= 2; ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // patch can not access e-Fuse issue ++ if (!IS_RT3090(pAd)) ++ { ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ } ++ ++ // output the read_opcode and register number in that order ++ ShiftOutBits(pAd, EEPROM_READ_OPCODE, 3); ++ ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ++ ++ // Now read the data (16 bits) in from the selected EEPROM word ++ data = ShiftInBits(pAd); ++ ++ EEpromCleanup(pAd); ++ ++ // Antenna and EEPROM access are both using EESK pin, ++ // Therefor we should avoid accessing EESK at the same time ++ // Then restore antenna after EEPROM access ++ if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) ++ { ++ pAd->EepromAccess = FALSE; ++ AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); ++ } ++} ++ return data; ++} //ReadEEprom ++ ++VOID RTMP_EEPROM_WRITE16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Data) ++{ ++ UINT32 x; ++ ++ if (pAd->NicConfig2.field.AntDiversity) ++ { ++ pAd->EepromAccess = TRUE; ++ } ++ //2008/09/11:KH add to support efuse<-- ++//2008/09/11:KH add to support efuse--> ++ { ++ Offset /= 2; ++ ++ EWEN(pAd); ++ ++ // reset bits and set EECS ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EEDI | EEDO | EESK); ++ x |= EECS; ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ // patch can not access e-Fuse issue ++ if (!IS_RT3090(pAd)) ++ { ++ // kick a pulse ++ RaiseClock(pAd, &x); ++ LowerClock(pAd, &x); ++ } ++ ++ // output the read_opcode ,register number and data in that order ++ ShiftOutBits(pAd, EEPROM_WRITE_OPCODE, 3); ++ ShiftOutBits(pAd, Offset, pAd->EEPROMAddressNum); ++ ShiftOutBits(pAd, Data, 16); // 16-bit access ++ ++ // read DO status ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ ++ EEpromCleanup(pAd); ++ ++ RTMPusecDelay(10000); //delay for twp(MAX)=10ms ++ ++ EWDS(pAd); ++ ++ EEpromCleanup(pAd); ++ ++ // Antenna and EEPROM access are both using EESK pin, ++ // Therefor we should avoid accessing EESK at the same time ++ // Then restore antenna after EEPROM access ++ if ((pAd->NicConfig2.field.AntDiversity) || (pAd->RfIcType == RFIC_3020)) ++ { ++ pAd->EepromAccess = FALSE; ++ AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); ++ } ++} ++} ++ ++//2008/09/11:KH add to support efuse<-- ++#ifdef RT30xx ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UCHAR eFuseReadRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ OUT USHORT* pData) ++{ ++ EFUSE_CTRL_STRUC eFuseCtrlStruc; ++ int i; ++ USHORT efuseDataOffset; ++ UINT32 data; ++ ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ ++ //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. ++ //Use the eeprom logical address and covert to address to block number ++ eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; ++ ++ //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 0. ++ eFuseCtrlStruc.field.EFSROM_MODE = 0; ++ ++ //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. ++ eFuseCtrlStruc.field.EFSROM_KICK = 1; ++ ++ NdisMoveMemory(&data, &eFuseCtrlStruc, 4); ++ RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); ++ ++ //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. ++ i = 0; ++ while(i < 100) ++ { ++ //rtmp.HwMemoryReadDword(EFUSE_CTRL, (DWORD *) &eFuseCtrlStruc, 4); ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ if(eFuseCtrlStruc.field.EFSROM_KICK == 0) ++ { ++ break; ++ } ++ RTMPusecDelay(2); ++ i++; ++ } ++ ++ //if EFSROM_AOUT is not found in physical address, write 0xffff ++ if (eFuseCtrlStruc.field.EFSROM_AOUT == 0x3f) ++ { ++ for(i=0; i> (8*(Offset & 0x3)); ++#endif ++ ++ NdisMoveMemory(pData, &data, Length); ++ } ++ ++ return (UCHAR) eFuseCtrlStruc.field.EFSROM_AOUT; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID eFusePhysicalReadRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ OUT USHORT* pData) ++{ ++ EFUSE_CTRL_STRUC eFuseCtrlStruc; ++ int i; ++ USHORT efuseDataOffset; ++ UINT32 data; ++ ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ ++ //Step0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. ++ eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; ++ ++ //Step1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. ++ //Read in physical view ++ eFuseCtrlStruc.field.EFSROM_MODE = 1; ++ ++ //Step2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. ++ eFuseCtrlStruc.field.EFSROM_KICK = 1; ++ ++ NdisMoveMemory(&data, &eFuseCtrlStruc, 4); ++ RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); ++ ++ //Step3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. ++ i = 0; ++ while(i < 100) ++ { ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ if(eFuseCtrlStruc.field.EFSROM_KICK == 0) ++ break; ++ RTMPusecDelay(2); ++ i++; ++ } ++ ++ //Step4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) ++ //Because the size of each EFUSE_DATA is 4 Bytes, the size of address of each is 2 bits. ++ //The previous 2 bits is the EFUSE_DATA number, the last 2 bits is used to decide which bytes ++ //Decide which EFUSE_DATA to read ++ //590:F E D C ++ //594:B A 9 8 ++ //598:7 6 5 4 ++ //59C:3 2 1 0 ++ efuseDataOffset = EFUSE_DATA3 - (Offset & 0xC) ; ++ ++ RTMP_IO_READ32(pAd, efuseDataOffset, &data); ++ ++#ifdef RT_BIG_ENDIAN ++ data = data << (8*((Offset & 0x3)^0x2)); ++#else ++ data = data >> (8*(Offset & 0x3)); ++#endif ++ ++ NdisMoveMemory(pData, &data, Length); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID eFuseReadPhysical( ++ IN PRTMP_ADAPTER pAd, ++ IN PUSHORT lpInBuffer, ++ IN ULONG nInBufferSize, ++ OUT PUSHORT lpOutBuffer, ++ IN ULONG nOutBufferSize ++) ++{ ++ USHORT* pInBuf = (USHORT*)lpInBuffer; ++ USHORT* pOutBuf = (USHORT*)lpOutBuffer; ++ ++ USHORT Offset = pInBuf[0]; //addr ++ USHORT Length = pInBuf[1]; //length ++ int i; ++ ++ for(i=0; i> 2; ++ data = pData[0] & 0xffff; ++ //The offset should be 0x***10 or 0x***00 ++ if((Offset % 4) != 0) ++ { ++ eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff) | (data << 16); ++ } ++ else ++ { ++ eFuseDataBuffer[efuseDataOffset] = (eFuseDataBuffer[efuseDataOffset] & 0xffff0000) | data; ++ } ++ ++ efuseDataOffset = EFUSE_DATA3; ++ for(i=0; i< 4; i++) ++ { ++ RTMP_IO_WRITE32(pAd, efuseDataOffset, eFuseDataBuffer[i]); ++ efuseDataOffset -= 4; ++ } ++ ///////////////////////////////////////////////////////////////// ++ ++ //Step1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. ++ eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; ++ ++ //Step2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. ++ eFuseCtrlStruc.field.EFSROM_MODE = 3; ++ ++ //Step3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. ++ eFuseCtrlStruc.field.EFSROM_KICK = 1; ++ ++ NdisMoveMemory(&data, &eFuseCtrlStruc, 4); ++ RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); ++ ++ //Step4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It¡¦s done. ++ i = 0; ++ while(i < 100) ++ { ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ ++ if(eFuseCtrlStruc.field.EFSROM_KICK == 0) ++ break; ++ ++ RTMPusecDelay(2); ++ i++; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS eFuseWriteRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ IN USHORT* pData) ++{ ++ USHORT i; ++ USHORT eFuseData; ++ USHORT LogicalAddress, BlkNum = 0xffff; ++ UCHAR EFSROM_AOUT; ++ ++ USHORT addr,tmpaddr, InBuf[3], tmpOffset; ++ USHORT buffer[8]; ++ BOOLEAN bWriteSuccess = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters Offset=%x, pData=%x\n", Offset, *pData)); ++ ++ //Step 0. find the entry in the mapping table ++ //The address of EEPROM is 2-bytes alignment. ++ //The last bit is used for alignment, so it must be 0. ++ tmpOffset = Offset & 0xfffe; ++ EFSROM_AOUT = eFuseReadRegisters(pAd, tmpOffset, 2, &eFuseData); ++ ++ if( EFSROM_AOUT == 0x3f) ++ { //find available logical address pointer ++ //the logical address does not exist, find an empty one ++ //from the first address of block 45=16*45=0x2d0 to the last address of block 47 ++ //==>48*16-3(reserved)=2FC ++ for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) ++ { ++ //Retrive the logical block nubmer form each logical address pointer ++ //It will access two logical address pointer each time. ++ eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); ++ if( (LogicalAddress & 0xff) == 0) ++ {//Not used logical address pointer ++ BlkNum = i-EFUSE_USAGE_MAP_START; ++ break; ++ } ++ else if(( (LogicalAddress >> 8) & 0xff) == 0) ++ {//Not used logical address pointer ++ if (i != EFUSE_USAGE_MAP_END) ++ { ++ BlkNum = i-EFUSE_USAGE_MAP_START+1; ++ } ++ break; ++ } ++ } ++ } ++ else ++ { ++ BlkNum = EFSROM_AOUT; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); ++ ++ if(BlkNum == 0xffff) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); ++ return FALSE; ++ } ++ ++ //Step 1. Save data of this block which is pointed by the avaible logical address pointer ++ // read and save the original block data ++ for(i =0; i<8; i++) ++ { ++ addr = BlkNum * 0x10 ; ++ ++ InBuf[0] = addr+2*i; ++ InBuf[1] = 2; ++ InBuf[2] = 0x0; ++ ++ eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); ++ ++ buffer[i] = InBuf[2]; ++ } ++ ++ //Step 2. Update the data in buffer, and write the data to Efuse ++ buffer[ (Offset >> 1) % 8] = pData[0]; ++ ++ do ++ { ++ //Step 3. Write the data to Efuse ++ if(!bWriteSuccess) ++ { ++ for(i =0; i<8; i++) ++ { ++ addr = BlkNum * 0x10 ; ++ ++ InBuf[0] = addr+2*i; ++ InBuf[1] = 2; ++ InBuf[2] = buffer[i]; ++ ++ eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); ++ } ++ } ++ else ++ { ++ addr = BlkNum * 0x10 ; ++ ++ InBuf[0] = addr+(Offset % 16); ++ InBuf[1] = 2; ++ InBuf[2] = pData[0]; ++ ++ eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); ++ } ++ ++ //Step 4. Write mapping table ++ addr = EFUSE_USAGE_MAP_START+BlkNum; ++ ++ tmpaddr = addr; ++ ++ if(addr % 2 != 0) ++ addr = addr -1; ++ InBuf[0] = addr; ++ InBuf[1] = 2; ++ ++ //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry ++ tmpOffset = Offset; ++ tmpOffset >>= 4; ++ tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; ++ tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; ++ ++ // write the logical address ++ if(tmpaddr%2 != 0) ++ InBuf[2] = tmpOffset<<8; ++ else ++ InBuf[2] = tmpOffset; ++ ++ eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); ++ ++ //Step 5. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted ++ bWriteSuccess = TRUE; ++ for(i =0; i<8; i++) ++ { ++ addr = BlkNum * 0x10 ; ++ ++ InBuf[0] = addr+2*i; ++ InBuf[1] = 2; ++ InBuf[2] = 0x0; ++ ++ eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); ++ ++ if(buffer[i] != InBuf[2]) ++ { ++ bWriteSuccess = FALSE; ++ break; ++ } ++ } ++ ++ //Step 6. invlidate mapping entry and find a free mapping entry if not succeed ++ if (!bWriteSuccess) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess BlkNum = %d\n", BlkNum)); ++ ++ // the offset of current mapping entry ++ addr = EFUSE_USAGE_MAP_START+BlkNum; ++ ++ //find a new mapping entry ++ BlkNum = 0xffff; ++ for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) ++ { ++ eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); ++ if( (LogicalAddress & 0xff) == 0) ++ { ++ BlkNum = i-EFUSE_USAGE_MAP_START; ++ break; ++ } ++ else if(( (LogicalAddress >> 8) & 0xff) == 0) ++ { ++ if (i != EFUSE_USAGE_MAP_END) ++ { ++ BlkNum = i+1-EFUSE_USAGE_MAP_START; ++ } ++ break; ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Not bWriteSuccess new BlkNum = %d\n", BlkNum)); ++ if(BlkNum == 0xffff) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); ++ return FALSE; ++ } ++ ++ //invalidate the original mapping entry if new entry is not found ++ tmpaddr = addr; ++ ++ if(addr % 2 != 0) ++ addr = addr -1; ++ InBuf[0] = addr; ++ InBuf[1] = 2; ++ ++ eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); ++ ++ // write the logical address ++ if(tmpaddr%2 != 0) ++ { ++ // Invalidate the high byte ++ for (i=8; i<15; i++) ++ { ++ if( ( (InBuf[2] >> i) & 0x01) == 0) ++ { ++ InBuf[2] |= (0x1 <> i) & 0x01) == 0) ++ { ++ InBuf[2] |= (0x1 <bUseEfuse) ++ return FALSE; ++ for (i = EFUSE_USAGE_MAP_START; i <= EFUSE_USAGE_MAP_END; i+=2) ++ { ++ eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); ++ if( (LogicalAddress & 0xff) == 0) ++ { ++ efusefreenum= (UCHAR) (EFUSE_USAGE_MAP_END-i+1); ++ break; ++ } ++ else if(( (LogicalAddress >> 8) & 0xff) == 0) ++ { ++ efusefreenum = (UCHAR) (EFUSE_USAGE_MAP_END-i); ++ break; ++ } ++ ++ if(i == EFUSE_USAGE_MAP_END) ++ efusefreenum = 0; ++ } ++ printk("efuseFreeNumber is %d\n",efusefreenum); ++ return TRUE; ++} ++INT set_eFusedump_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++USHORT InBuf[3]; ++ INT i=0; ++ if(!pAd->bUseEfuse) ++ return FALSE; ++ for(i =0; i0) ++ { ++ ++ NdisMoveMemory(src, arg, strlen(arg)); ++ } ++ ++ else ++ { ++ ++ NdisMoveMemory(src, "RT30xxEEPROM.bin", BinFileSize); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FileName=%s\n",src)); ++ buffer = kmalloc(MAX_EEPROM_BIN_FILE_SIZE, MEM_ALLOC_FLAG); ++ ++ if(buffer == NULL) ++ { ++ kfree(src); ++ return FALSE; ++} ++ PDATA=kmalloc(sizeof(USHORT)*8,MEM_ALLOC_FLAG); ++ ++ if(PDATA==NULL) ++ { ++ kfree(src); ++ ++ kfree(buffer); ++ return FALSE; ++ } ++ /* Don't change to uid 0, let the file be opened as the "normal" user */ ++#if 0 ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid=current->fsgid = 0; ++#endif ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ if (src && *src) ++ { ++ srcf = filp_open(src, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); ++ return FALSE; ++ } ++ else ++ { ++ // The object must have a read method ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ memset(buffer, 0x00, MAX_EEPROM_BIN_FILE_SIZE); ++ while(srcf->f_op->read(srcf, &buffer[i], 1, &srcf->f_pos)==1) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%02X ",buffer[i])); ++ if((i+1)%8==0) ++ DBGPRINT(RT_DEBUG_TRACE, ("\n")); ++ i++; ++ if(i>=MAX_EEPROM_BIN_FILE_SIZE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld reading %s, The file is too large[1024]\n", -PTR_ERR(srcf),src)); ++ kfree(PDATA); ++ kfree(buffer); ++ kfree(src); ++ return FALSE; ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error!! System doest not support read function\n")); ++ kfree(PDATA); ++ kfree(buffer); ++ kfree(src); ++ return FALSE; ++ } ++ } ++ ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error src or srcf is null\n")); ++ kfree(PDATA); ++ kfree(buffer); ++ return FALSE; ++ ++ } ++ ++ ++ retval=filp_close(srcf,NULL); ++ ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); ++ } ++ set_fs(orgfs); ++#if 0 ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++#endif ++ for(j=0;j48*16-3(reserved)=2FC ++ bAllocateNewBlk=TRUE; ++ for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) ++ { ++ //Retrive the logical block nubmer form each logical address pointer ++ //It will access two logical address pointer each time. ++ eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); ++ if( (LogicalAddress & 0xff) == 0) ++ {//Not used logical address pointer ++ BlkNum = i-EFUSE_USAGE_MAP_START; ++ break; ++ } ++ else if(( (LogicalAddress >> 8) & 0xff) == 0) ++ {//Not used logical address pointer ++ if (i != EFUSE_USAGE_MAP_END) ++ { ++ BlkNum = i-EFUSE_USAGE_MAP_START+1; ++ } ++ break; ++ } ++ } ++ } ++ else ++ { ++ bAllocateNewBlk=FALSE; ++ BlkNum = EFSROM_AOUT; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters BlkNum = %d \n", BlkNum)); ++ ++ if(BlkNum == 0xffff) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegisters: out of free E-fuse space!!!\n")); ++ return FALSE; ++ } ++ //Step 1.1.0 ++ //If the block is not existing in mapping table, create one ++ //and write down the 16-bytes data to the new block ++ if(bAllocateNewBlk) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk\n")); ++ efuseDataOffset = EFUSE_DATA3; ++ for(i=0; i< 4; i++) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Allocate New Blk, Data%d=%04x%04x\n",3-i,pData[2*i+1],pData[2*i])); ++ tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; ++ ++ ++ RTMP_IO_WRITE32(pAd, efuseDataOffset,tempbuffer); ++ efuseDataOffset -= 4; ++ ++ } ++ ///////////////////////////////////////////////////////////////// ++ ++ //Step1.1.1. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. ++ eFuseCtrlStruc.field.EFSROM_AIN = BlkNum* 0x10 ; ++ ++ //Step1.1.2. Write EFSROM_MODE (0x580, bit7:bit6) to 3. ++ eFuseCtrlStruc.field.EFSROM_MODE = 3; ++ ++ //Step1.1.3. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical write procedure. ++ eFuseCtrlStruc.field.EFSROM_KICK = 1; ++ ++ NdisMoveMemory(&data, &eFuseCtrlStruc, 4); ++ ++ RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); ++ ++ //Step1.1.4. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. It¡¦s done. ++ i = 0; ++ while(i < 100) ++ { ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ ++ if(eFuseCtrlStruc.field.EFSROM_KICK == 0) ++ break; ++ ++ RTMPusecDelay(2); ++ i++; ++ } ++ ++ } ++ else ++ { //Step1.2. ++ //If the same logical number is existing, check if the writting data and the data ++ //saving in this block are the same. ++ ///////////////////////////////////////////////////////////////// ++ //read current values of 16-byte block ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ ++ //Step1.2.0. Write 10-bit of address to EFSROM_AIN (0x580, bit25:bit16). The address must be 16-byte alignment. ++ eFuseCtrlStruc.field.EFSROM_AIN = Offset & 0xfff0; ++ ++ //Step1.2.1. Write EFSROM_MODE (0x580, bit7:bit6) to 1. ++ eFuseCtrlStruc.field.EFSROM_MODE = 0; ++ ++ //Step1.2.2. Write EFSROM_KICK (0x580, bit30) to 1 to kick-off physical read procedure. ++ eFuseCtrlStruc.field.EFSROM_KICK = 1; ++ ++ NdisMoveMemory(&data, &eFuseCtrlStruc, 4); ++ RTMP_IO_WRITE32(pAd, EFUSE_CTRL, data); ++ ++ //Step1.2.3. Polling EFSROM_KICK(0x580, bit30) until it become 0 again. ++ i = 0; ++ while(i < 100) ++ { ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, (PUINT32) &eFuseCtrlStruc); ++ ++ if(eFuseCtrlStruc.field.EFSROM_KICK == 0) ++ break; ++ RTMPusecDelay(2); ++ i++; ++ } ++ ++ //Step1.2.4. Read 16-byte of data from EFUSE_DATA0-3 (0x59C-0x590) ++ efuseDataOffset = EFUSE_DATA3; ++ for(i=0; i< 4; i++) ++ { ++ RTMP_IO_READ32(pAd, efuseDataOffset, (PUINT32) &buffer[i]); ++ efuseDataOffset -= 4; ++ } ++ //Step1.2.5. Check if the data of efuse and the writing data are the same. ++ for(i =0; i<4; i++) ++ { ++ tempbuffer=((pData[2*i+1]<<16)&0xffff0000)|pData[2*i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("buffer[%d]=%x,pData[%d]=%x,pData[%d]=%x,tempbuffer=%x\n",i,buffer[i],2*i,pData[2*i],2*i+1,pData[2*i+1],tempbuffer)); ++ ++ if(((buffer[i]&0xffff0000)==(pData[2*i+1]<<16))&&((buffer[i]&0xffff)==pData[2*i])) ++ bNotWrite&=TRUE; ++ else ++ { ++ bNotWrite&=FALSE; ++ break; ++ } ++ } ++ if(!bNotWrite) ++ { ++ printk("The data is not the same\n"); ++ ++ for(i =0; i<8; i++) ++ { ++ addr = BlkNum * 0x10 ; ++ ++ InBuf[0] = addr+2*i; ++ InBuf[1] = 2; ++ InBuf[2] = pData[i]; ++ ++ eFuseWritePhysical(pAd, &InBuf[0], 6, NULL, 2); ++ } ++ ++ } ++ else ++ return TRUE; ++ } ++ ++ ++ ++ //Step 2. Write mapping table ++ addr = EFUSE_USAGE_MAP_START+BlkNum; ++ ++ tmpaddr = addr; ++ ++ if(addr % 2 != 0) ++ addr = addr -1; ++ InBuf[0] = addr; ++ InBuf[1] = 2; ++ ++ //convert the address from 10 to 8 bit ( bit7, 6 = parity and bit5 ~ 0 = bit9~4), and write to logical map entry ++ tmpOffset = Offset; ++ tmpOffset >>= 4; ++ tmpOffset |= ((~((tmpOffset & 0x01) ^ ( tmpOffset >> 1 & 0x01) ^ (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01))) << 6) & 0x40; ++ tmpOffset |= ((~( (tmpOffset >> 2 & 0x01) ^ (tmpOffset >> 3 & 0x01) ^ (tmpOffset >> 4 & 0x01) ^ ( tmpOffset >> 5 & 0x01))) << 7) & 0x80; ++ ++ // write the logical address ++ if(tmpaddr%2 != 0) ++ InBuf[2] = tmpOffset<<8; ++ else ++ InBuf[2] = tmpOffset; ++ ++ eFuseWritePhysical(pAd,&InBuf[0], 6, NULL, 0); ++ ++ //Step 3. Compare data if not the same, invalidate the mapping entry, then re-write the data until E-fuse is exhausted ++ bWriteSuccess = TRUE; ++ for(i =0; i<8; i++) ++ { ++ addr = BlkNum * 0x10 ; ++ ++ InBuf[0] = addr+2*i; ++ InBuf[1] = 2; ++ InBuf[2] = 0x0; ++ ++ eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("addr=%x, buffer[i]=%x,InBuf[2]=%x\n",InBuf[0],pData[i],InBuf[2])); ++ if(pData[i] != InBuf[2]) ++ { ++ bWriteSuccess = FALSE; ++ break; ++ } ++ } ++ ++ //Step 4. invlidate mapping entry and find a free mapping entry if not succeed ++ ++ if (!bWriteSuccess&&Loop<2) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess BlkNum = %d\n", BlkNum)); ++ ++ // the offset of current mapping entry ++ addr = EFUSE_USAGE_MAP_START+BlkNum; ++ ++ //find a new mapping entry ++ BlkNum = 0xffff; ++ for (i=EFUSE_USAGE_MAP_START; i<=EFUSE_USAGE_MAP_END; i+=2) ++ { ++ eFusePhysicalReadRegisters(pAd, i, 2, &LogicalAddress); ++ if( (LogicalAddress & 0xff) == 0) ++ { ++ BlkNum = i-EFUSE_USAGE_MAP_START; ++ break; ++ } ++ else if(( (LogicalAddress >> 8) & 0xff) == 0) ++ { ++ if (i != EFUSE_USAGE_MAP_END) ++ { ++ BlkNum = i+1-EFUSE_USAGE_MAP_START; ++ } ++ break; ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin::Not bWriteSuccess new BlkNum = %d\n", BlkNum)); ++ if(BlkNum == 0xffff) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("eFuseWriteRegistersFromBin: out of free E-fuse space!!!\n")); ++ return FALSE; ++ } ++ ++ //invalidate the original mapping entry if new entry is not found ++ tmpaddr = addr; ++ ++ if(addr % 2 != 0) ++ addr = addr -1; ++ InBuf[0] = addr; ++ InBuf[1] = 2; ++ ++ eFuseReadPhysical(pAd, &InBuf[0], 4, &InBuf[2], 2); ++ ++ // write the logical address ++ if(tmpaddr%2 != 0) ++ { ++ // Invalidate the high byte ++ for (i=8; i<15; i++) ++ { ++ if( ( (InBuf[2] >> i) & 0x01) == 0) ++ { ++ InBuf[2] |= (0x1 <> i) & 0x01) == 0) ++ { ++ InBuf[2] |= (0x1 < ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/md5.c +@@ -0,0 +1,1427 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ md5.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ jan 10-28-03 Initial ++ Rita 11-23-04 Modify MD5 and SHA-1 ++ Rita 10-14-05 Modify SHA-1 in big-endian platform ++ */ ++#include "../rt_config.h" ++ ++/** ++ * md5_mac: ++ * @key: pointer to the key used for MAC generation ++ * @key_len: length of the key in bytes ++ * @data: pointer to the data area for which the MAC is generated ++ * @data_len: length of the data in bytes ++ * @mac: pointer to the buffer holding space for the MAC; the buffer should ++ * have space for 128-bit (16 bytes) MD5 hash value ++ * ++ * md5_mac() determines the message authentication code by using secure hash ++ * MD5(key | data | key). ++ */ ++void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) ++{ ++ MD5_CTX context; ++ ++ MD5Init(&context); ++ MD5Update(&context, key, key_len); ++ MD5Update(&context, data, data_len); ++ MD5Update(&context, key, key_len); ++ MD5Final(mac, &context); ++} ++ ++/** ++ * hmac_md5: ++ * @key: pointer to the key used for MAC generation ++ * @key_len: length of the key in bytes ++ * @data: pointer to the data area for which the MAC is generated ++ * @data_len: length of the data in bytes ++ * @mac: pointer to the buffer holding space for the MAC; the buffer should ++ * have space for 128-bit (16 bytes) MD5 hash value ++ * ++ * hmac_md5() determines the message authentication code using HMAC-MD5. ++ * This implementation is based on the sample code presented in RFC 2104. ++ */ ++void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac) ++{ ++ MD5_CTX context; ++ u8 k_ipad[65]; /* inner padding - key XORd with ipad */ ++ u8 k_opad[65]; /* outer padding - key XORd with opad */ ++ u8 tk[16]; ++ int i; ++ ++ //assert(key != NULL && data != NULL && mac != NULL); ++ ++ /* if key is longer than 64 bytes reset it to key = MD5(key) */ ++ if (key_len > 64) { ++ MD5_CTX ttcontext; ++ ++ MD5Init(&ttcontext); ++ MD5Update(&ttcontext, key, key_len); ++ MD5Final(tk, &ttcontext); ++ //key=(PUCHAR)ttcontext.buf; ++ key = tk; ++ key_len = 16; ++ } ++ ++ /* the HMAC_MD5 transform looks like: ++ * ++ * MD5(K XOR opad, MD5(K XOR ipad, text)) ++ * ++ * where K is an n byte key ++ * ipad is the byte 0x36 repeated 64 times ++ * opad is the byte 0x5c repeated 64 times ++ * and text is the data being protected */ ++ ++ /* start out by storing key in pads */ ++ NdisZeroMemory(k_ipad, sizeof(k_ipad)); ++ NdisZeroMemory(k_opad, sizeof(k_opad)); ++ //assert(key_len < sizeof(k_ipad)); ++ NdisMoveMemory(k_ipad, key, key_len); ++ NdisMoveMemory(k_opad, key, key_len); ++ ++ /* XOR key with ipad and opad values */ ++ for (i = 0; i < 64; i++) { ++ k_ipad[i] ^= 0x36; ++ k_opad[i] ^= 0x5c; ++ } ++ ++ /* perform inner MD5 */ ++ MD5Init(&context); /* init context for 1st pass */ ++ MD5Update(&context, k_ipad, 64); /* start with inner pad */ ++ MD5Update(&context, data, data_len); /* then text of datagram */ ++ MD5Final(mac, &context); /* finish up 1st pass */ ++ ++ /* perform outer MD5 */ ++ MD5Init(&context); /* init context for 2nd pass */ ++ MD5Update(&context, k_opad, 64); /* start with outer pad */ ++ MD5Update(&context, mac, 16); /* then results of 1st hash */ ++ MD5Final(mac, &context); /* finish up 2nd pass */ ++} ++ ++#ifndef RT_BIG_ENDIAN ++#define byteReverse(buf, len) /* Nothing */ ++#else ++void byteReverse(unsigned char *buf, unsigned longs); ++void byteReverse(unsigned char *buf, unsigned longs) ++{ ++ do { ++ *(UINT32 *)buf = SWAP32(*(UINT32 *)buf); ++ buf += 4; ++ } while (--longs); ++} ++#endif ++ ++ ++/* ========================== MD5 implementation =========================== */ ++// four base functions for MD5 ++#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z))) ++#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z))) ++#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z)) ++#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z))) ++#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s)))) ++ ++#define MD5Step(f, w, x, y, z, data, t, s) \ ++ ( w += f(x, y, z) + data + t, w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w += x ) ++ ++ ++/* ++ * Function Description: ++ * Initiate MD5 Context satisfied in RFC 1321 ++ * ++ * Arguments: ++ * pCtx Pointer to MD5 context ++ * ++ * Return Value: ++ * None ++ */ ++VOID MD5Init(MD5_CTX *pCtx) ++{ ++ pCtx->Buf[0]=0x67452301; ++ pCtx->Buf[1]=0xefcdab89; ++ pCtx->Buf[2]=0x98badcfe; ++ pCtx->Buf[3]=0x10325476; ++ ++ pCtx->LenInBitCount[0]=0; ++ pCtx->LenInBitCount[1]=0; ++} ++ ++ ++/* ++ * Function Description: ++ * Update MD5 Context, allow of an arrary of octets as the next portion ++ * of the message ++ * ++ * Arguments: ++ * pCtx Pointer to MD5 context ++ * pData Pointer to input data ++ * LenInBytes The length of input data (unit: byte) ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called after MD5Init or MD5Update(itself) ++ */ ++VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) ++{ ++ ++ UINT32 TfTimes; ++ UINT32 temp; ++ unsigned int i; ++ ++ temp = pCtx->LenInBitCount[0]; ++ ++ pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); ++ ++ if (pCtx->LenInBitCount[0] < temp) ++ pCtx->LenInBitCount[1]++; //carry in ++ ++ pCtx->LenInBitCount[1] += LenInBytes >> 29; ++ ++ // mod 64 bytes ++ temp = (temp >> 3) & 0x3f; ++ ++ // process lacks of 64-byte data ++ if (temp) ++ { ++ UCHAR *pAds = (UCHAR *) pCtx->Input + temp; ++ ++ if ((temp+LenInBytes) < 64) ++ { ++ NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); ++ return; ++ } ++ ++ NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp); ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ pData += 64-temp; ++ LenInBytes -= 64-temp; ++ } // end of if (temp) ++ ++ ++ TfTimes = (LenInBytes >> 6); ++ ++ for (i=TfTimes; i>0; i--) ++ { ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ pData += 64; ++ LenInBytes -= 64; ++ } // end of for ++ ++ // buffering lacks of 64-byte data ++ if(LenInBytes) ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); ++ ++} ++ ++ ++/* ++ * Function Description: ++ * Append padding bits and length of original message in the tail ++ * The message digest has to be completed in the end ++ * ++ * Arguments: ++ * Digest Output of Digest-Message for MD5 ++ * pCtx Pointer to MD5 context ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called after MD5Update ++ */ ++VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx) ++{ ++ UCHAR Remainder; ++ UCHAR PadLenInBytes; ++ UCHAR *pAppend=0; ++ unsigned int i; ++ ++ Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); ++ ++ PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); ++ ++ pAppend = (UCHAR *)pCtx->Input + Remainder; ++ ++ // padding bits without crossing block(64-byte based) boundary ++ if (Remainder < 56) ++ { ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); ++ ++ // add data-length field, from low to high ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); ++ } ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of if ++ ++ // padding bits with crossing block(64-byte based) boundary ++ else ++ { ++ // the first block === ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); ++ PadLenInBytes -= (64 - Remainder - 1); ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ ++ // the second block === ++ NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); ++ ++ // add data-length field ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff); ++ } ++ ++ byteReverse(pCtx->Input, 16); ++ MD5Transform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of else ++ ++ ++ NdisMoveMemory((UCHAR *)Digest, (UINT32 *)pCtx->Buf, 16); // output ++ byteReverse((UCHAR *)Digest, 4); ++ NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free ++} ++ ++ ++/* ++ * Function Description: ++ * The central algorithm of MD5, consists of four rounds and sixteen ++ * steps per round ++ * ++ * Arguments: ++ * Buf Buffers of four states (output: 16 bytes) ++ * Mes Input data (input: 64 bytes) ++ * ++ * Return Value: ++ * None ++ * ++ * Note: ++ * Called by MD5Update or MD5Final ++ */ ++VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]) ++{ ++ UINT32 Reg[4], Temp; ++ unsigned int i; ++ ++ static UCHAR LShiftVal[16] = ++ { ++ 7, 12, 17, 22, ++ 5, 9 , 14, 20, ++ 4, 11, 16, 23, ++ 6, 10, 15, 21, ++ }; ++ ++ ++ // [equal to 4294967296*abs(sin(index))] ++ static UINT32 MD5Table[64] = ++ { ++ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, ++ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, ++ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, ++ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, ++ ++ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, ++ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, ++ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, ++ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, ++ ++ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, ++ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, ++ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, ++ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, ++ ++ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, ++ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, ++ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, ++ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ++ }; ++ ++ ++ for (i=0; i<4; i++) ++ Reg[i]=Buf[i]; ++ ++ ++ // 64 steps in MD5 algorithm ++ for (i=0; i<16; i++) ++ { ++ MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i], ++ MD5Table[i], LShiftVal[i & 0x3]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=16; i<32; i++) ++ { ++ MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], ++ MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=32; i<48; i++) ++ { ++ MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], ++ MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ for (i=48; i<64; i++) ++ { ++ MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], ++ MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]); ++ ++ // one-word right shift ++ Temp = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ } ++ ++ ++ // (temporary)output ++ for (i=0; i<4; i++) ++ Buf[i] += Reg[i]; ++ ++} ++ ++ ++ ++/* ========================= SHA-1 implementation ========================== */ ++// four base functions for SHA-1 ++#define SHA1_F1(b, c, d) (((b) & (c)) | ((~b) & (d))) ++#define SHA1_F2(b, c, d) ((b) ^ (c) ^ (d)) ++#define SHA1_F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) ++ ++ ++#define SHA1Step(f, a, b, c, d, e, w, k) \ ++ ( e += ( f(b, c, d) + w + k + CYCLIC_LEFT_SHIFT(a, 5)) & 0xffffffff, \ ++ b = CYCLIC_LEFT_SHIFT(b, 30) ) ++ ++//Initiate SHA-1 Context satisfied in RFC 3174 ++VOID SHAInit(SHA_CTX *pCtx) ++{ ++ pCtx->Buf[0]=0x67452301; ++ pCtx->Buf[1]=0xefcdab89; ++ pCtx->Buf[2]=0x98badcfe; ++ pCtx->Buf[3]=0x10325476; ++ pCtx->Buf[4]=0xc3d2e1f0; ++ ++ pCtx->LenInBitCount[0]=0; ++ pCtx->LenInBitCount[1]=0; ++} ++ ++/* ++ * Function Description: ++ * Update SHA-1 Context, allow of an arrary of octets as the next ++ * portion of the message ++ * ++ * Arguments: ++ * pCtx Pointer to SHA-1 context ++ * pData Pointer to input data ++ * LenInBytes The length of input data (unit: byte) ++ * ++ * Return Value: ++ * error indicate more than pow(2,64) bits of data ++ * ++ * Note: ++ * Called after SHAInit or SHAUpdate(itself) ++ */ ++UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes) ++{ ++ UINT32 TfTimes; ++ UINT32 temp1,temp2; ++ unsigned int i; ++ UCHAR err=1; ++ ++ temp1 = pCtx->LenInBitCount[0]; ++ temp2 = pCtx->LenInBitCount[1]; ++ ++ pCtx->LenInBitCount[0] = (UINT32) (pCtx->LenInBitCount[0] + (LenInBytes << 3)); ++ if (pCtx->LenInBitCount[0] < temp1) ++ pCtx->LenInBitCount[1]++; //carry in ++ ++ ++ pCtx->LenInBitCount[1] = (UINT32) (pCtx->LenInBitCount[1] +(LenInBytes >> 29)); ++ if (pCtx->LenInBitCount[1] < temp2) ++ return (err); //check total length of original data ++ ++ ++ // mod 64 bytes ++ temp1 = (temp1 >> 3) & 0x3f; ++ ++ // process lacks of 64-byte data ++ if (temp1) ++ { ++ UCHAR *pAds = (UCHAR *) pCtx->Input + temp1; ++ ++ if ((temp1+LenInBytes) < 64) ++ { ++ NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes); ++ return (0); ++ } ++ ++ NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp1); ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ pData += 64-temp1; ++ LenInBytes -= 64-temp1; ++ } // end of if (temp1) ++ ++ ++ TfTimes = (LenInBytes >> 6); ++ ++ for (i=TfTimes; i>0; i--) ++ { ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64); ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ pData += 64; ++ LenInBytes -= 64; ++ } // end of for ++ ++ // buffering lacks of 64-byte data ++ if(LenInBytes) ++ NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes); ++ ++ return (0); ++ ++} ++ ++// Append padding bits and length of original message in the tail ++// The message digest has to be completed in the end ++VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]) ++{ ++ UCHAR Remainder; ++ UCHAR PadLenInBytes; ++ UCHAR *pAppend=0; ++ unsigned int i; ++ ++ Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f); ++ ++ pAppend = (UCHAR *)pCtx->Input + Remainder; ++ ++ PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder); ++ ++ // padding bits without crossing block(64-byte based) boundary ++ if (Remainder < 56) ++ { ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); ++ ++ // add data-length field, from high to low ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); ++ } ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 14); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of if ++ ++ // padding bits with crossing block(64-byte based) boundary ++ else ++ { ++ // the first block === ++ *pAppend = 0x80; ++ PadLenInBytes --; ++ ++ NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); ++ PadLenInBytes -= (64 - Remainder - 1); ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ ++ ++ // the second block === ++ NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); ++ ++ // add data-length field ++ for (i=0; i<4; i++) ++ { ++ pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[1] >> ((3-i) << 3)) & 0xff); ++ pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[0] >> ((3-i) << 3)) & 0xff); ++ } ++ ++ byteReverse((UCHAR *)pCtx->Input, 16); ++ NdisZeroMemory((UCHAR *)pCtx->Input + 64, 16); ++ SHATransform(pCtx->Buf, (UINT32 *)pCtx->Input); ++ } // end of else ++ ++ ++ //Output, bytereverse ++ for (i=0; i<20; i++) ++ { ++ Digest [i] = (UCHAR)(pCtx->Buf[i>>2] >> 8*(3-(i & 0x3))); ++ } ++ ++ NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free ++} ++ ++ ++// The central algorithm of SHA-1, consists of four rounds and ++// twenty steps per round ++VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]) ++{ ++ UINT32 Reg[5],Temp; ++ unsigned int i; ++ UINT32 W[80]; ++ ++ static UINT32 SHA1Table[4] = { 0x5a827999, 0x6ed9eba1, ++ 0x8f1bbcdc, 0xca62c1d6 }; ++ ++ Reg[0]=Buf[0]; ++ Reg[1]=Buf[1]; ++ Reg[2]=Buf[2]; ++ Reg[3]=Buf[3]; ++ Reg[4]=Buf[4]; ++ ++ //the first octet of a word is stored in the 0th element, bytereverse ++ for(i = 0; i < 16; i++) ++ { ++ W[i] = (Mes[i] >> 24) & 0xff; ++ W[i] |= (Mes[i] >> 8 ) & 0xff00; ++ W[i] |= (Mes[i] << 8 ) & 0xff0000; ++ W[i] |= (Mes[i] << 24) & 0xff000000; ++ } ++ ++ ++ for (i = 0; i < 64; i++) ++ W[16+i] = CYCLIC_LEFT_SHIFT(W[i] ^ W[2+i] ^ W[8+i] ^ W[13+i], 1); ++ ++ ++ // 80 steps in SHA-1 algorithm ++ for (i=0; i<80; i++) ++ { ++ if (i<20) ++ SHA1Step(SHA1_F1, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[0]); ++ ++ else if (i>=20 && i<40) ++ SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[1]); ++ ++ else if (i>=40 && i<60) ++ SHA1Step(SHA1_F3, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[2]); ++ ++ else ++ SHA1Step(SHA1_F2, Reg[0], Reg[1], Reg[2], Reg[3], Reg[4], ++ W[i], SHA1Table[3]); ++ ++ ++ // one-word right shift ++ Temp = Reg[4]; ++ Reg[4] = Reg[3]; ++ Reg[3] = Reg[2]; ++ Reg[2] = Reg[1]; ++ Reg[1] = Reg[0]; ++ Reg[0] = Temp; ++ ++ } // end of for-loop ++ ++ ++ // (temporary)output ++ for (i=0; i<5; i++) ++ Buf[i] += Reg[i]; ++ ++} ++ ++ ++/* ========================= AES En/Decryption ========================== */ ++ ++/* forward S-box */ ++static uint32 FSb[256] = ++{ ++ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, ++ 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, ++ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, ++ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, ++ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, ++ 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, ++ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, ++ 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, ++ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, ++ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, ++ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, ++ 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, ++ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, ++ 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, ++ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, ++ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, ++ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, ++ 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, ++ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, ++ 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, ++ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, ++ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, ++ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, ++ 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, ++ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, ++ 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, ++ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, ++ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, ++ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, ++ 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, ++ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, ++ 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 ++}; ++ ++/* forward table */ ++#define FT \ ++\ ++ V(C6,63,63,A5), V(F8,7C,7C,84), V(EE,77,77,99), V(F6,7B,7B,8D), \ ++ V(FF,F2,F2,0D), V(D6,6B,6B,BD), V(DE,6F,6F,B1), V(91,C5,C5,54), \ ++ V(60,30,30,50), V(02,01,01,03), V(CE,67,67,A9), V(56,2B,2B,7D), \ ++ V(E7,FE,FE,19), V(B5,D7,D7,62), V(4D,AB,AB,E6), V(EC,76,76,9A), \ ++ V(8F,CA,CA,45), V(1F,82,82,9D), V(89,C9,C9,40), V(FA,7D,7D,87), \ ++ V(EF,FA,FA,15), V(B2,59,59,EB), V(8E,47,47,C9), V(FB,F0,F0,0B), \ ++ V(41,AD,AD,EC), V(B3,D4,D4,67), V(5F,A2,A2,FD), V(45,AF,AF,EA), \ ++ V(23,9C,9C,BF), V(53,A4,A4,F7), V(E4,72,72,96), V(9B,C0,C0,5B), \ ++ V(75,B7,B7,C2), V(E1,FD,FD,1C), V(3D,93,93,AE), V(4C,26,26,6A), \ ++ V(6C,36,36,5A), V(7E,3F,3F,41), V(F5,F7,F7,02), V(83,CC,CC,4F), \ ++ V(68,34,34,5C), V(51,A5,A5,F4), V(D1,E5,E5,34), V(F9,F1,F1,08), \ ++ V(E2,71,71,93), V(AB,D8,D8,73), V(62,31,31,53), V(2A,15,15,3F), \ ++ V(08,04,04,0C), V(95,C7,C7,52), V(46,23,23,65), V(9D,C3,C3,5E), \ ++ V(30,18,18,28), V(37,96,96,A1), V(0A,05,05,0F), V(2F,9A,9A,B5), \ ++ V(0E,07,07,09), V(24,12,12,36), V(1B,80,80,9B), V(DF,E2,E2,3D), \ ++ V(CD,EB,EB,26), V(4E,27,27,69), V(7F,B2,B2,CD), V(EA,75,75,9F), \ ++ V(12,09,09,1B), V(1D,83,83,9E), V(58,2C,2C,74), V(34,1A,1A,2E), \ ++ V(36,1B,1B,2D), V(DC,6E,6E,B2), V(B4,5A,5A,EE), V(5B,A0,A0,FB), \ ++ V(A4,52,52,F6), V(76,3B,3B,4D), V(B7,D6,D6,61), V(7D,B3,B3,CE), \ ++ V(52,29,29,7B), V(DD,E3,E3,3E), V(5E,2F,2F,71), V(13,84,84,97), \ ++ V(A6,53,53,F5), V(B9,D1,D1,68), V(00,00,00,00), V(C1,ED,ED,2C), \ ++ V(40,20,20,60), V(E3,FC,FC,1F), V(79,B1,B1,C8), V(B6,5B,5B,ED), \ ++ V(D4,6A,6A,BE), V(8D,CB,CB,46), V(67,BE,BE,D9), V(72,39,39,4B), \ ++ V(94,4A,4A,DE), V(98,4C,4C,D4), V(B0,58,58,E8), V(85,CF,CF,4A), \ ++ V(BB,D0,D0,6B), V(C5,EF,EF,2A), V(4F,AA,AA,E5), V(ED,FB,FB,16), \ ++ V(86,43,43,C5), V(9A,4D,4D,D7), V(66,33,33,55), V(11,85,85,94), \ ++ V(8A,45,45,CF), V(E9,F9,F9,10), V(04,02,02,06), V(FE,7F,7F,81), \ ++ V(A0,50,50,F0), V(78,3C,3C,44), V(25,9F,9F,BA), V(4B,A8,A8,E3), \ ++ V(A2,51,51,F3), V(5D,A3,A3,FE), V(80,40,40,C0), V(05,8F,8F,8A), \ ++ V(3F,92,92,AD), V(21,9D,9D,BC), V(70,38,38,48), V(F1,F5,F5,04), \ ++ V(63,BC,BC,DF), V(77,B6,B6,C1), V(AF,DA,DA,75), V(42,21,21,63), \ ++ V(20,10,10,30), V(E5,FF,FF,1A), V(FD,F3,F3,0E), V(BF,D2,D2,6D), \ ++ V(81,CD,CD,4C), V(18,0C,0C,14), V(26,13,13,35), V(C3,EC,EC,2F), \ ++ V(BE,5F,5F,E1), V(35,97,97,A2), V(88,44,44,CC), V(2E,17,17,39), \ ++ V(93,C4,C4,57), V(55,A7,A7,F2), V(FC,7E,7E,82), V(7A,3D,3D,47), \ ++ V(C8,64,64,AC), V(BA,5D,5D,E7), V(32,19,19,2B), V(E6,73,73,95), \ ++ V(C0,60,60,A0), V(19,81,81,98), V(9E,4F,4F,D1), V(A3,DC,DC,7F), \ ++ V(44,22,22,66), V(54,2A,2A,7E), V(3B,90,90,AB), V(0B,88,88,83), \ ++ V(8C,46,46,CA), V(C7,EE,EE,29), V(6B,B8,B8,D3), V(28,14,14,3C), \ ++ V(A7,DE,DE,79), V(BC,5E,5E,E2), V(16,0B,0B,1D), V(AD,DB,DB,76), \ ++ V(DB,E0,E0,3B), V(64,32,32,56), V(74,3A,3A,4E), V(14,0A,0A,1E), \ ++ V(92,49,49,DB), V(0C,06,06,0A), V(48,24,24,6C), V(B8,5C,5C,E4), \ ++ V(9F,C2,C2,5D), V(BD,D3,D3,6E), V(43,AC,AC,EF), V(C4,62,62,A6), \ ++ V(39,91,91,A8), V(31,95,95,A4), V(D3,E4,E4,37), V(F2,79,79,8B), \ ++ V(D5,E7,E7,32), V(8B,C8,C8,43), V(6E,37,37,59), V(DA,6D,6D,B7), \ ++ V(01,8D,8D,8C), V(B1,D5,D5,64), V(9C,4E,4E,D2), V(49,A9,A9,E0), \ ++ V(D8,6C,6C,B4), V(AC,56,56,FA), V(F3,F4,F4,07), V(CF,EA,EA,25), \ ++ V(CA,65,65,AF), V(F4,7A,7A,8E), V(47,AE,AE,E9), V(10,08,08,18), \ ++ V(6F,BA,BA,D5), V(F0,78,78,88), V(4A,25,25,6F), V(5C,2E,2E,72), \ ++ V(38,1C,1C,24), V(57,A6,A6,F1), V(73,B4,B4,C7), V(97,C6,C6,51), \ ++ V(CB,E8,E8,23), V(A1,DD,DD,7C), V(E8,74,74,9C), V(3E,1F,1F,21), \ ++ V(96,4B,4B,DD), V(61,BD,BD,DC), V(0D,8B,8B,86), V(0F,8A,8A,85), \ ++ V(E0,70,70,90), V(7C,3E,3E,42), V(71,B5,B5,C4), V(CC,66,66,AA), \ ++ V(90,48,48,D8), V(06,03,03,05), V(F7,F6,F6,01), V(1C,0E,0E,12), \ ++ V(C2,61,61,A3), V(6A,35,35,5F), V(AE,57,57,F9), V(69,B9,B9,D0), \ ++ V(17,86,86,91), V(99,C1,C1,58), V(3A,1D,1D,27), V(27,9E,9E,B9), \ ++ V(D9,E1,E1,38), V(EB,F8,F8,13), V(2B,98,98,B3), V(22,11,11,33), \ ++ V(D2,69,69,BB), V(A9,D9,D9,70), V(07,8E,8E,89), V(33,94,94,A7), \ ++ V(2D,9B,9B,B6), V(3C,1E,1E,22), V(15,87,87,92), V(C9,E9,E9,20), \ ++ V(87,CE,CE,49), V(AA,55,55,FF), V(50,28,28,78), V(A5,DF,DF,7A), \ ++ V(03,8C,8C,8F), V(59,A1,A1,F8), V(09,89,89,80), V(1A,0D,0D,17), \ ++ V(65,BF,BF,DA), V(D7,E6,E6,31), V(84,42,42,C6), V(D0,68,68,B8), \ ++ V(82,41,41,C3), V(29,99,99,B0), V(5A,2D,2D,77), V(1E,0F,0F,11), \ ++ V(7B,B0,B0,CB), V(A8,54,54,FC), V(6D,BB,BB,D6), V(2C,16,16,3A) ++ ++#define V(a,b,c,d) 0x##a##b##c##d ++static uint32 FT0[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##d##a##b##c ++static uint32 FT1[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##c##d##a##b ++static uint32 FT2[256] = { FT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##b##c##d##a ++static uint32 FT3[256] = { FT }; ++#undef V ++ ++#undef FT ++ ++/* reverse S-box */ ++ ++static uint32 RSb[256] = ++{ ++ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, ++ 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, ++ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, ++ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, ++ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, ++ 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, ++ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, ++ 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, ++ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, ++ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, ++ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, ++ 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, ++ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, ++ 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, ++ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, ++ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, ++ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, ++ 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, ++ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, ++ 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, ++ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, ++ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, ++ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, ++ 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, ++ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, ++ 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, ++ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, ++ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, ++ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, ++ 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, ++ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, ++ 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ++}; ++ ++/* reverse table */ ++ ++#define RT \ ++\ ++ V(51,F4,A7,50), V(7E,41,65,53), V(1A,17,A4,C3), V(3A,27,5E,96), \ ++ V(3B,AB,6B,CB), V(1F,9D,45,F1), V(AC,FA,58,AB), V(4B,E3,03,93), \ ++ V(20,30,FA,55), V(AD,76,6D,F6), V(88,CC,76,91), V(F5,02,4C,25), \ ++ V(4F,E5,D7,FC), V(C5,2A,CB,D7), V(26,35,44,80), V(B5,62,A3,8F), \ ++ V(DE,B1,5A,49), V(25,BA,1B,67), V(45,EA,0E,98), V(5D,FE,C0,E1), \ ++ V(C3,2F,75,02), V(81,4C,F0,12), V(8D,46,97,A3), V(6B,D3,F9,C6), \ ++ V(03,8F,5F,E7), V(15,92,9C,95), V(BF,6D,7A,EB), V(95,52,59,DA), \ ++ V(D4,BE,83,2D), V(58,74,21,D3), V(49,E0,69,29), V(8E,C9,C8,44), \ ++ V(75,C2,89,6A), V(F4,8E,79,78), V(99,58,3E,6B), V(27,B9,71,DD), \ ++ V(BE,E1,4F,B6), V(F0,88,AD,17), V(C9,20,AC,66), V(7D,CE,3A,B4), \ ++ V(63,DF,4A,18), V(E5,1A,31,82), V(97,51,33,60), V(62,53,7F,45), \ ++ V(B1,64,77,E0), V(BB,6B,AE,84), V(FE,81,A0,1C), V(F9,08,2B,94), \ ++ V(70,48,68,58), V(8F,45,FD,19), V(94,DE,6C,87), V(52,7B,F8,B7), \ ++ V(AB,73,D3,23), V(72,4B,02,E2), V(E3,1F,8F,57), V(66,55,AB,2A), \ ++ V(B2,EB,28,07), V(2F,B5,C2,03), V(86,C5,7B,9A), V(D3,37,08,A5), \ ++ V(30,28,87,F2), V(23,BF,A5,B2), V(02,03,6A,BA), V(ED,16,82,5C), \ ++ V(8A,CF,1C,2B), V(A7,79,B4,92), V(F3,07,F2,F0), V(4E,69,E2,A1), \ ++ V(65,DA,F4,CD), V(06,05,BE,D5), V(D1,34,62,1F), V(C4,A6,FE,8A), \ ++ V(34,2E,53,9D), V(A2,F3,55,A0), V(05,8A,E1,32), V(A4,F6,EB,75), \ ++ V(0B,83,EC,39), V(40,60,EF,AA), V(5E,71,9F,06), V(BD,6E,10,51), \ ++ V(3E,21,8A,F9), V(96,DD,06,3D), V(DD,3E,05,AE), V(4D,E6,BD,46), \ ++ V(91,54,8D,B5), V(71,C4,5D,05), V(04,06,D4,6F), V(60,50,15,FF), \ ++ V(19,98,FB,24), V(D6,BD,E9,97), V(89,40,43,CC), V(67,D9,9E,77), \ ++ V(B0,E8,42,BD), V(07,89,8B,88), V(E7,19,5B,38), V(79,C8,EE,DB), \ ++ V(A1,7C,0A,47), V(7C,42,0F,E9), V(F8,84,1E,C9), V(00,00,00,00), \ ++ V(09,80,86,83), V(32,2B,ED,48), V(1E,11,70,AC), V(6C,5A,72,4E), \ ++ V(FD,0E,FF,FB), V(0F,85,38,56), V(3D,AE,D5,1E), V(36,2D,39,27), \ ++ V(0A,0F,D9,64), V(68,5C,A6,21), V(9B,5B,54,D1), V(24,36,2E,3A), \ ++ V(0C,0A,67,B1), V(93,57,E7,0F), V(B4,EE,96,D2), V(1B,9B,91,9E), \ ++ V(80,C0,C5,4F), V(61,DC,20,A2), V(5A,77,4B,69), V(1C,12,1A,16), \ ++ V(E2,93,BA,0A), V(C0,A0,2A,E5), V(3C,22,E0,43), V(12,1B,17,1D), \ ++ V(0E,09,0D,0B), V(F2,8B,C7,AD), V(2D,B6,A8,B9), V(14,1E,A9,C8), \ ++ V(57,F1,19,85), V(AF,75,07,4C), V(EE,99,DD,BB), V(A3,7F,60,FD), \ ++ V(F7,01,26,9F), V(5C,72,F5,BC), V(44,66,3B,C5), V(5B,FB,7E,34), \ ++ V(8B,43,29,76), V(CB,23,C6,DC), V(B6,ED,FC,68), V(B8,E4,F1,63), \ ++ V(D7,31,DC,CA), V(42,63,85,10), V(13,97,22,40), V(84,C6,11,20), \ ++ V(85,4A,24,7D), V(D2,BB,3D,F8), V(AE,F9,32,11), V(C7,29,A1,6D), \ ++ V(1D,9E,2F,4B), V(DC,B2,30,F3), V(0D,86,52,EC), V(77,C1,E3,D0), \ ++ V(2B,B3,16,6C), V(A9,70,B9,99), V(11,94,48,FA), V(47,E9,64,22), \ ++ V(A8,FC,8C,C4), V(A0,F0,3F,1A), V(56,7D,2C,D8), V(22,33,90,EF), \ ++ V(87,49,4E,C7), V(D9,38,D1,C1), V(8C,CA,A2,FE), V(98,D4,0B,36), \ ++ V(A6,F5,81,CF), V(A5,7A,DE,28), V(DA,B7,8E,26), V(3F,AD,BF,A4), \ ++ V(2C,3A,9D,E4), V(50,78,92,0D), V(6A,5F,CC,9B), V(54,7E,46,62), \ ++ V(F6,8D,13,C2), V(90,D8,B8,E8), V(2E,39,F7,5E), V(82,C3,AF,F5), \ ++ V(9F,5D,80,BE), V(69,D0,93,7C), V(6F,D5,2D,A9), V(CF,25,12,B3), \ ++ V(C8,AC,99,3B), V(10,18,7D,A7), V(E8,9C,63,6E), V(DB,3B,BB,7B), \ ++ V(CD,26,78,09), V(6E,59,18,F4), V(EC,9A,B7,01), V(83,4F,9A,A8), \ ++ V(E6,95,6E,65), V(AA,FF,E6,7E), V(21,BC,CF,08), V(EF,15,E8,E6), \ ++ V(BA,E7,9B,D9), V(4A,6F,36,CE), V(EA,9F,09,D4), V(29,B0,7C,D6), \ ++ V(31,A4,B2,AF), V(2A,3F,23,31), V(C6,A5,94,30), V(35,A2,66,C0), \ ++ V(74,4E,BC,37), V(FC,82,CA,A6), V(E0,90,D0,B0), V(33,A7,D8,15), \ ++ V(F1,04,98,4A), V(41,EC,DA,F7), V(7F,CD,50,0E), V(17,91,F6,2F), \ ++ V(76,4D,D6,8D), V(43,EF,B0,4D), V(CC,AA,4D,54), V(E4,96,04,DF), \ ++ V(9E,D1,B5,E3), V(4C,6A,88,1B), V(C1,2C,1F,B8), V(46,65,51,7F), \ ++ V(9D,5E,EA,04), V(01,8C,35,5D), V(FA,87,74,73), V(FB,0B,41,2E), \ ++ V(B3,67,1D,5A), V(92,DB,D2,52), V(E9,10,56,33), V(6D,D6,47,13), \ ++ V(9A,D7,61,8C), V(37,A1,0C,7A), V(59,F8,14,8E), V(EB,13,3C,89), \ ++ V(CE,A9,27,EE), V(B7,61,C9,35), V(E1,1C,E5,ED), V(7A,47,B1,3C), \ ++ V(9C,D2,DF,59), V(55,F2,73,3F), V(18,14,CE,79), V(73,C7,37,BF), \ ++ V(53,F7,CD,EA), V(5F,FD,AA,5B), V(DF,3D,6F,14), V(78,44,DB,86), \ ++ V(CA,AF,F3,81), V(B9,68,C4,3E), V(38,24,34,2C), V(C2,A3,40,5F), \ ++ V(16,1D,C3,72), V(BC,E2,25,0C), V(28,3C,49,8B), V(FF,0D,95,41), \ ++ V(39,A8,01,71), V(08,0C,B3,DE), V(D8,B4,E4,9C), V(64,56,C1,90), \ ++ V(7B,CB,84,61), V(D5,32,B6,70), V(48,6C,5C,74), V(D0,B8,57,42) ++ ++#define V(a,b,c,d) 0x##a##b##c##d ++static uint32 RT0[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##d##a##b##c ++static uint32 RT1[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##c##d##a##b ++static uint32 RT2[256] = { RT }; ++#undef V ++ ++#define V(a,b,c,d) 0x##b##c##d##a ++static uint32 RT3[256] = { RT }; ++#undef V ++ ++#undef RT ++ ++/* round constants */ ++ ++static uint32 RCON[10] = ++{ ++ 0x01000000, 0x02000000, 0x04000000, 0x08000000, ++ 0x10000000, 0x20000000, 0x40000000, 0x80000000, ++ 0x1B000000, 0x36000000 ++}; ++ ++/* key schedule tables */ ++ ++static int KT_init = 1; ++ ++static uint32 KT0[256]; ++static uint32 KT1[256]; ++static uint32 KT2[256]; ++static uint32 KT3[256]; ++ ++/* platform-independant 32-bit integer manipulation macros */ ++ ++#define GET_UINT32(n,b,i) \ ++{ \ ++ (n) = ( (uint32) (b)[(i) ] << 24 ) \ ++ | ( (uint32) (b)[(i) + 1] << 16 ) \ ++ | ( (uint32) (b)[(i) + 2] << 8 ) \ ++ | ( (uint32) (b)[(i) + 3] ); \ ++} ++ ++#define PUT_UINT32(n,b,i) \ ++{ \ ++ (b)[(i) ] = (uint8) ( (n) >> 24 ); \ ++ (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ ++ (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ ++ (b)[(i) + 3] = (uint8) ( (n) ); \ ++} ++ ++/* AES key scheduling routine */ ++ ++int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ) ++{ ++ int i; ++ uint32 *RK, *SK; ++ ++ switch( nbits ) ++ { ++ case 128: ctx->nr = 10; break; ++ case 192: ctx->nr = 12; break; ++ case 256: ctx->nr = 14; break; ++ default : return( 1 ); ++ } ++ ++ RK = ctx->erk; ++ ++ for( i = 0; i < (nbits >> 5); i++ ) ++ { ++ GET_UINT32( RK[i], key, i * 4 ); ++ } ++ ++ /* setup encryption round keys */ ++ ++ switch( nbits ) ++ { ++ case 128: ++ ++ for( i = 0; i < 10; i++, RK += 4 ) ++ { ++ RK[4] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[3] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[3] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[3] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[3] >> 24 ) ] ); ++ ++ RK[5] = RK[1] ^ RK[4]; ++ RK[6] = RK[2] ^ RK[5]; ++ RK[7] = RK[3] ^ RK[6]; ++ } ++ break; ++ ++ case 192: ++ ++ for( i = 0; i < 8; i++, RK += 6 ) ++ { ++ RK[6] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[5] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[5] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[5] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[5] >> 24 ) ] ); ++ ++ RK[7] = RK[1] ^ RK[6]; ++ RK[8] = RK[2] ^ RK[7]; ++ RK[9] = RK[3] ^ RK[8]; ++ RK[10] = RK[4] ^ RK[9]; ++ RK[11] = RK[5] ^ RK[10]; ++ } ++ break; ++ ++ case 256: ++ ++ for( i = 0; i < 7; i++, RK += 8 ) ++ { ++ RK[8] = RK[0] ^ RCON[i] ^ ++ ( FSb[ (uint8) ( RK[7] >> 16 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[7] >> 8 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[7] ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[7] >> 24 ) ] ); ++ ++ RK[9] = RK[1] ^ RK[8]; ++ RK[10] = RK[2] ^ RK[9]; ++ RK[11] = RK[3] ^ RK[10]; ++ ++ RK[12] = RK[4] ^ ++ ( FSb[ (uint8) ( RK[11] >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( RK[11] >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( RK[11] >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( RK[11] ) ] ); ++ ++ RK[13] = RK[5] ^ RK[12]; ++ RK[14] = RK[6] ^ RK[13]; ++ RK[15] = RK[7] ^ RK[14]; ++ } ++ break; ++ } ++ ++ /* setup decryption round keys */ ++ ++ if( KT_init ) ++ { ++ for( i = 0; i < 256; i++ ) ++ { ++ KT0[i] = RT0[ FSb[i] ]; ++ KT1[i] = RT1[ FSb[i] ]; ++ KT2[i] = RT2[ FSb[i] ]; ++ KT3[i] = RT3[ FSb[i] ]; ++ } ++ ++ KT_init = 0; ++ } ++ ++ SK = ctx->drk; ++ ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ ++ for( i = 1; i < ctx->nr; i++ ) ++ { ++ RK -= 8; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ ++ *SK++ = KT0[ (uint8) ( *RK >> 24 ) ] ^ ++ KT1[ (uint8) ( *RK >> 16 ) ] ^ ++ KT2[ (uint8) ( *RK >> 8 ) ] ^ ++ KT3[ (uint8) ( *RK ) ]; RK++; ++ } ++ ++ RK -= 8; ++ ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ *SK++ = *RK++; ++ ++ return( 0 ); ++} ++ ++/* AES 128-bit block encryption routine */ ++ ++void rtmp_aes_encrypt(aes_context *ctx, uint8 input[16], uint8 output[16] ) ++{ ++ uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; ++ ++ RK = ctx->erk; ++ GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; ++ GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; ++ GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; ++ GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; ++ ++#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ ++{ \ ++ RK += 4; \ ++ \ ++ X0 = RK[0] ^ FT0[ (uint8) ( Y0 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y1 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y2 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y3 ) ]; \ ++ \ ++ X1 = RK[1] ^ FT0[ (uint8) ( Y1 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y2 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y3 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y0 ) ]; \ ++ \ ++ X2 = RK[2] ^ FT0[ (uint8) ( Y2 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y3 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y0 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y1 ) ]; \ ++ \ ++ X3 = RK[3] ^ FT0[ (uint8) ( Y3 >> 24 ) ] ^ \ ++ FT1[ (uint8) ( Y0 >> 16 ) ] ^ \ ++ FT2[ (uint8) ( Y1 >> 8 ) ] ^ \ ++ FT3[ (uint8) ( Y2 ) ]; \ ++} ++ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ ++ ++ if( ctx->nr > 10 ) ++ { ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ ++ } ++ ++ if( ctx->nr > 12 ) ++ { ++ AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ ++ AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ ++ } ++ ++ /* last round */ ++ ++ RK += 4; ++ ++ X0 = RK[0] ^ ( FSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y3 ) ] ); ++ ++ X1 = RK[1] ^ ( FSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y0 ) ] ); ++ ++ X2 = RK[2] ^ ( FSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y1 ) ] ); ++ ++ X3 = RK[3] ^ ( FSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ ++ ( FSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ ++ ( FSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ ++ ( FSb[ (uint8) ( Y2 ) ] ); ++ ++ PUT_UINT32( X0, output, 0 ); ++ PUT_UINT32( X1, output, 4 ); ++ PUT_UINT32( X2, output, 8 ); ++ PUT_UINT32( X3, output, 12 ); ++} ++ ++/* AES 128-bit block decryption routine */ ++ ++void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ) ++{ ++ uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; ++ ++ RK = ctx->drk; ++ ++ GET_UINT32( X0, input, 0 ); X0 ^= RK[0]; ++ GET_UINT32( X1, input, 4 ); X1 ^= RK[1]; ++ GET_UINT32( X2, input, 8 ); X2 ^= RK[2]; ++ GET_UINT32( X3, input, 12 ); X3 ^= RK[3]; ++ ++#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ ++{ \ ++ RK += 4; \ ++ \ ++ X0 = RK[0] ^ RT0[ (uint8) ( Y0 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y3 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y2 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y1 ) ]; \ ++ \ ++ X1 = RK[1] ^ RT0[ (uint8) ( Y1 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y0 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y3 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y2 ) ]; \ ++ \ ++ X2 = RK[2] ^ RT0[ (uint8) ( Y2 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y1 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y0 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y3 ) ]; \ ++ \ ++ X3 = RK[3] ^ RT0[ (uint8) ( Y3 >> 24 ) ] ^ \ ++ RT1[ (uint8) ( Y2 >> 16 ) ] ^ \ ++ RT2[ (uint8) ( Y1 >> 8 ) ] ^ \ ++ RT3[ (uint8) ( Y0 ) ]; \ ++} ++ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 1 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 2 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 3 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 4 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 5 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 6 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 7 */ ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 8 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 9 */ ++ ++ if( ctx->nr > 10 ) ++ { ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 10 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 11 */ ++ } ++ ++ if( ctx->nr > 12 ) ++ { ++ AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); /* round 12 */ ++ AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); /* round 13 */ ++ } ++ ++ /* last round */ ++ ++ RK += 4; ++ ++ X0 = RK[0] ^ ( RSb[ (uint8) ( Y0 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y3 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y2 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y1 ) ] ); ++ ++ X1 = RK[1] ^ ( RSb[ (uint8) ( Y1 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y0 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y3 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y2 ) ] ); ++ ++ X2 = RK[2] ^ ( RSb[ (uint8) ( Y2 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y1 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y0 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y3 ) ] ); ++ ++ X3 = RK[3] ^ ( RSb[ (uint8) ( Y3 >> 24 ) ] << 24 ) ^ ++ ( RSb[ (uint8) ( Y2 >> 16 ) ] << 16 ) ^ ++ ( RSb[ (uint8) ( Y1 >> 8 ) ] << 8 ) ^ ++ ( RSb[ (uint8) ( Y0 ) ] ); ++ ++ PUT_UINT32( X0, output, 0 ); ++ PUT_UINT32( X1, output, 4 ); ++ PUT_UINT32( X2, output, 8 ); ++ PUT_UINT32( X3, output, 12 ); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ SHA1 function ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID HMAC_SHA1( ++ IN UCHAR *text, ++ IN UINT text_len, ++ IN UCHAR *key, ++ IN UINT key_len, ++ IN UCHAR *digest) ++{ ++ SHA_CTX context; ++ UCHAR k_ipad[65]; /* inner padding - key XORd with ipad */ ++ UCHAR k_opad[65]; /* outer padding - key XORd with opad */ ++ INT i; ++ ++ // if key is longer than 64 bytes reset it to key=SHA1(key) ++ if (key_len > 64) ++ { ++ SHA_CTX tctx; ++ SHAInit(&tctx); ++ SHAUpdate(&tctx, key, key_len); ++ SHAFinal(&tctx, key); ++ key_len = 20; ++ } ++ NdisZeroMemory(k_ipad, sizeof(k_ipad)); ++ NdisZeroMemory(k_opad, sizeof(k_opad)); ++ NdisMoveMemory(k_ipad, key, key_len); ++ NdisMoveMemory(k_opad, key, key_len); ++ ++ // XOR key with ipad and opad values ++ for (i = 0; i < 64; i++) ++ { ++ k_ipad[i] ^= 0x36; ++ k_opad[i] ^= 0x5c; ++ } ++ ++ // perform inner SHA1 ++ SHAInit(&context); /* init context for 1st pass */ ++ SHAUpdate(&context, k_ipad, 64); /* start with inner pad */ ++ SHAUpdate(&context, text, text_len); /* then text of datagram */ ++ SHAFinal(&context, digest); /* finish up 1st pass */ ++ ++ //perform outer SHA1 ++ SHAInit(&context); /* init context for 2nd pass */ ++ SHAUpdate(&context, k_opad, 64); /* start with outer pad */ ++ SHAUpdate(&context, digest, 20); /* then results of 1st hash */ ++ SHAFinal(&context, digest); /* finish up 2nd pass */ ++ ++} ++ ++/* ++* F(P, S, c, i) = U1 xor U2 xor ... Uc ++* U1 = PRF(P, S || Int(i)) ++* U2 = PRF(P, U1) ++* Uc = PRF(P, Uc-1) ++*/ ++ ++void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output) ++{ ++ unsigned char digest[36], digest1[SHA_DIGEST_LEN]; ++ int i, j; ++ ++ /* U1 = PRF(P, S || int(i)) */ ++ memcpy(digest, ssid, ssidlength); ++ digest[ssidlength] = (unsigned char)((count>>24) & 0xff); ++ digest[ssidlength+1] = (unsigned char)((count>>16) & 0xff); ++ digest[ssidlength+2] = (unsigned char)((count>>8) & 0xff); ++ digest[ssidlength+3] = (unsigned char)(count & 0xff); ++ HMAC_SHA1(digest, ssidlength+4, (unsigned char*) password, (int) strlen(password), digest1); // for WPA update ++ ++ /* output = U1 */ ++ memcpy(output, digest1, SHA_DIGEST_LEN); ++ ++ for (i = 1; i < iterations; i++) ++ { ++ /* Un = PRF(P, Un-1) */ ++ HMAC_SHA1(digest1, SHA_DIGEST_LEN, (unsigned char*) password, (int) strlen(password), digest); // for WPA update ++ memcpy(digest1, digest, SHA_DIGEST_LEN); ++ ++ /* output = output xor Un */ ++ for (j = 0; j < SHA_DIGEST_LEN; j++) ++ { ++ output[j] ^= digest[j]; ++ } ++ } ++} ++/* ++* password - ascii string up to 63 characters in length ++* ssid - octet string up to 32 octets ++* ssidlength - length of ssid in octets ++* output must be 40 octets in length and outputs 256 bits of key ++*/ ++int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output) ++{ ++ if ((strlen(password) > 63) || (ssidlength > 32)) ++ return 0; ++ ++ F(password, ssid, ssidlength, 4096, 1, output); ++ F(password, ssid, ssidlength, 4096, 2, &output[SHA_DIGEST_LEN]); ++ return 1; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/mlme.c +@@ -0,0 +1,9136 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ mlme.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-08-25 Modify from RT2500 code base ++ John Chang 2004-09-06 modified for RT2600 ++*/ ++ ++#include "../rt_config.h" ++#include ++ ++UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96}; ++ ++UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; ++UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac}; ++UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72}; ++UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; ++UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; ++UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; ++UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++UCHAR RateSwitchTable[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x11, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x21, 0, 30, 50, ++ 0x05, 0x21, 1, 20, 50, ++ 0x06, 0x21, 2, 20, 50, ++ 0x07, 0x21, 3, 15, 50, ++ 0x08, 0x21, 4, 15, 30, ++ 0x09, 0x21, 5, 10, 25, ++ 0x0a, 0x21, 6, 8, 25, ++ 0x0b, 0x21, 7, 8, 25, ++ 0x0c, 0x20, 12, 15, 30, ++ 0x0d, 0x20, 13, 8, 20, ++ 0x0e, 0x20, 14, 8, 20, ++ 0x0f, 0x20, 15, 8, 25, ++ 0x10, 0x22, 15, 8, 25, ++ 0x11, 0x00, 0, 0, 0, ++ 0x12, 0x00, 0, 0, 0, ++ 0x13, 0x00, 0, 0, 0, ++ 0x14, 0x00, 0, 0, 0, ++ 0x15, 0x00, 0, 0, 0, ++ 0x16, 0x00, 0, 0, 0, ++ 0x17, 0x00, 0, 0, 0, ++ 0x18, 0x00, 0, 0, 0, ++ 0x19, 0x00, 0, 0, 0, ++ 0x1a, 0x00, 0, 0, 0, ++ 0x1b, 0x00, 0, 0, 0, ++ 0x1c, 0x00, 0, 0, 0, ++ 0x1d, 0x00, 0, 0, 0, ++ 0x1e, 0x00, 0, 0, 0, ++ 0x1f, 0x00, 0, 0, 0, ++}; ++ ++UCHAR RateSwitchTable11B[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x04, 0x03, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++}; ++ ++UCHAR RateSwitchTable11BG[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x10, 2, 20, 35, ++ 0x05, 0x10, 3, 16, 35, ++ 0x06, 0x10, 4, 10, 25, ++ 0x07, 0x10, 5, 16, 25, ++ 0x08, 0x10, 6, 10, 25, ++ 0x09, 0x10, 7, 10, 13, ++}; ++ ++UCHAR RateSwitchTable11G[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x08, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x10, 0, 20, 101, ++ 0x01, 0x10, 1, 20, 35, ++ 0x02, 0x10, 2, 20, 35, ++ 0x03, 0x10, 3, 16, 35, ++ 0x04, 0x10, 4, 10, 25, ++ 0x05, 0x10, 5, 16, 25, ++ 0x06, 0x10, 6, 10, 25, ++ 0x07, 0x10, 7, 10, 13, ++}; ++ ++#ifdef DOT11_N_SUPPORT ++UCHAR RateSwitchTable11N1S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x09, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 10, 25, ++ 0x06, 0x21, 6, 8, 14, ++ 0x07, 0x21, 7, 8, 14, ++ 0x08, 0x23, 7, 8, 14, ++}; ++ ++UCHAR RateSwitchTable11N2S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N3S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N2SForABand[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11N3SForABand[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30, 101, ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN1S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0d, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x00, 0, 40, 101, ++ 0x01, 0x00, 1, 40, 50, ++ 0x02, 0x00, 2, 35, 45, ++ 0x03, 0x00, 3, 20, 45, ++ 0x04, 0x21, 0, 30,101, //50 ++ 0x05, 0x21, 1, 20, 50, ++ 0x06, 0x21, 2, 20, 50, ++ 0x07, 0x21, 3, 15, 50, ++ 0x08, 0x21, 4, 15, 30, ++ 0x09, 0x21, 5, 10, 25, ++ 0x0a, 0x21, 6, 8, 14, ++ 0x0b, 0x21, 7, 8, 14, ++ 0x0c, 0x23, 7, 8, 14, ++}; ++ ++UCHAR RateSwitchTable11BGN2S[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN3S[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0a, 0x00, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 20, 50, ++ 0x04, 0x21, 4, 15, 50, ++#if 1 ++ 0x05, 0x20, 20, 15, 30, ++ 0x06, 0x20, 21, 8, 20, ++ 0x07, 0x20, 22, 8, 20, ++ 0x08, 0x20, 23, 8, 25, ++ 0x09, 0x22, 23, 8, 25, ++#else // for RT2860 2*3 test ++ 0x05, 0x20, 12, 15, 30, ++ 0x06, 0x20, 13, 8, 20, ++ 0x07, 0x20, 14, 8, 20, ++ 0x08, 0x20, 15, 8, 25, ++ 0x09, 0x22, 15, 8, 25, ++#endif ++}; ++ ++UCHAR RateSwitchTable11BGN2SForABand[] = { ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0b, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x20, 12, 15, 30, ++ 0x07, 0x20, 13, 8, 20, ++ 0x08, 0x20, 14, 8, 20, ++ 0x09, 0x20, 15, 8, 25, ++ 0x0a, 0x22, 15, 8, 25, ++}; ++ ++UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 ++// Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) ++ 0x0c, 0x09, 0, 0, 0, // Initial used item after association ++ 0x00, 0x21, 0, 30,101, //50 ++ 0x01, 0x21, 1, 20, 50, ++ 0x02, 0x21, 2, 20, 50, ++ 0x03, 0x21, 3, 15, 50, ++ 0x04, 0x21, 4, 15, 30, ++ 0x05, 0x21, 5, 15, 30, ++ 0x06, 0x21, 12, 15, 30, ++ 0x07, 0x20, 20, 15, 30, ++ 0x08, 0x20, 21, 8, 20, ++ 0x09, 0x20, 22, 8, 20, ++ 0x0a, 0x20, 23, 8, 25, ++ 0x0b, 0x22, 23, 8, 25, ++}; ++#endif // DOT11_N_SUPPORT // ++ ++PUCHAR ReasonString[] = { ++ /* 0 */ "Reserved", ++ /* 1 */ "Unspecified Reason", ++ /* 2 */ "Previous Auth no longer valid", ++ /* 3 */ "STA is leaving / has left", ++ /* 4 */ "DIS-ASSOC due to inactivity", ++ /* 5 */ "AP unable to hanle all associations", ++ /* 6 */ "class 2 error", ++ /* 7 */ "class 3 error", ++ /* 8 */ "STA is leaving / has left", ++ /* 9 */ "require auth before assoc/re-assoc", ++ /* 10 */ "Reserved", ++ /* 11 */ "Reserved", ++ /* 12 */ "Reserved", ++ /* 13 */ "invalid IE", ++ /* 14 */ "MIC error", ++ /* 15 */ "4-way handshake timeout", ++ /* 16 */ "2-way (group key) handshake timeout", ++ /* 17 */ "4-way handshake IE diff among AssosReq/Rsp/Beacon", ++ /* 18 */ ++}; ++ ++extern UCHAR OfdmRateToRxwiMCS[]; ++// since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. ++// otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate ++ULONG BasicRateMask[12] = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */, ++ 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */, ++ 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */}; ++ ++UCHAR MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00}; ++UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++// e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than ++// this value, then it's quaranteed capable of operating in 36 mbps TX rate in ++// clean environment. ++// TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 ++CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; ++ ++UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; ++USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; ++ ++UCHAR SsidIe = IE_SSID; ++UCHAR SupRateIe = IE_SUPP_RATES; ++UCHAR ExtRateIe = IE_EXT_SUPP_RATES; ++#ifdef DOT11_N_SUPPORT ++UCHAR HtCapIe = IE_HT_CAP; ++UCHAR AddHtInfoIe = IE_ADD_HT; ++UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; ++#ifdef DOT11N_DRAFT3 ++UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++UCHAR ErpIe = IE_ERP; ++UCHAR DsIe = IE_DS_PARM; ++UCHAR TimIe = IE_TIM; ++UCHAR WpaIe = IE_WPA; ++UCHAR Wpa2Ie = IE_WPA2; ++UCHAR IbssIe = IE_IBSS_PARM; ++UCHAR Ccx2Ie = IE_CCX_V2; ++UCHAR WapiIe = IE_WAPI; ++ ++extern UCHAR WPA_OUI[]; ++ ++UCHAR SES_OUI[] = {0x00, 0x90, 0x4c}; ++ ++UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; ++ ++// Reset the RFIC setting to new series ++RTMP_RF_REGS RF2850RegTable[] = { ++// ch R1 R2 R3(TX0~4=0) R4 ++ {1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b}, ++ {2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f}, ++ {3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b}, ++ {4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f}, ++ {5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b}, ++ {6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f}, ++ {7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b}, ++ {8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f}, ++ {9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b}, ++ {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f}, ++ {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b}, ++ {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f}, ++ {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b}, ++ {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193}, ++ ++ // 802.11 UNI / HyperLan 2 ++ {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3}, ++ {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193}, ++ {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183}, ++ {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3}, ++ {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b}, ++ {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b}, ++ {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193}, ++ {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3}, ++ {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b}, ++ {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183}, ++ {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193}, ++ {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5. ++ ++ // 802.11 HyperLan 2 ++ {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783}, ++ ++ // 2008.04.30 modified ++ // The system team has AN to improve the EVM value ++ // for channel 102 to 108 for the RT2850/RT2750 dual band solution. ++ {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793}, ++ {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3}, ++ {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193}, ++ ++ {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183}, ++ {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b}, ++ {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3}, ++ {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193}, ++ {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183}, ++ {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193}, ++ {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927 ++ {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3}, ++ {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b}, ++ {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193}, ++ {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b}, ++ {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183}, ++ ++ // 802.11 UNII ++ {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7}, ++ {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187}, ++ {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f}, ++ {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f}, ++ {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7}, ++ {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187}, ++ {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197}, ++ ++ // Japan ++ {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b}, ++ {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13}, ++ {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b}, ++ {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23}, ++ {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13}, ++ {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b}, ++ {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23}, ++ ++ // still lack of MMAC(Japan) ch 34,38,42,46 ++}; ++UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS)); ++ ++FREQUENCY_ITEM FreqItems3020[] = ++{ ++ /**************************************************/ ++ // ISM : 2.4 to 2.483 GHz // ++ /**************************************************/ ++ // 11g ++ /**************************************************/ ++ //-CH---N-------R---K----------- ++ {1, 241, 2, 2}, ++ {2, 241, 2, 7}, ++ {3, 242, 2, 2}, ++ {4, 242, 2, 7}, ++ {5, 243, 2, 2}, ++ {6, 243, 2, 7}, ++ {7, 244, 2, 2}, ++ {8, 244, 2, 7}, ++ {9, 245, 2, 2}, ++ {10, 245, 2, 7}, ++ {11, 246, 2, 2}, ++ {12, 246, 2, 7}, ++ {13, 247, 2, 2}, ++ {14, 248, 2, 4}, ++}; ++//2008/07/10:KH Modified to share this variable ++UCHAR NUM_OF_3020_CHNL=(sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)); ++ ++/* ++ ========================================================================== ++ Description: ++ initialize the MLME task and its data structure (queue, spinlock, ++ timer, state machines). ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Return: ++ always return NDIS_STATUS_SUCCESS ++ ++ ========================================================================== ++*/ ++NDIS_STATUS MlmeInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n")); ++ ++ do ++ { ++ Status = MlmeQueueInit(&pAd->Mlme.Queue); ++ if(Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ pAd->Mlme.bRunning = FALSE; ++ NdisAllocateSpinLock(&pAd->Mlme.TaskLock); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ BssTableInit(&pAd->ScanTab); ++ ++ // init STA state machines ++ AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); ++ AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); ++ AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); ++ SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); ++ WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); ++ AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); ++ ++#ifdef QOS_DLS_SUPPORT ++ DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); ++#endif // QOS_DLS_SUPPORT // ++ ++ ++ // Since we are using switch/case to implement it, the init is different from the above ++ // state machine init ++ MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); ++ ++ // Init mlme periodic timer ++ RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE); ++ ++ // Set mlme periodic timer ++ RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); ++ ++ // software-based RX Antenna diversity ++ RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ } while (FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ main loop of the MLME ++ Pre: ++ Mlme has to be initialized, and there are something inside the queue ++ Note: ++ This function is invoked from MPSetInformation and MPReceive; ++ This task guarantee only one MlmeHandler will run. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeHandler( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_QUEUE_ELEM *Elem = NULL; ++ ++ // Only accept MLME and Frame from peer side, no other (control/data) frame should ++ // get into this state machine ++ ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ if(pAd->Mlme.bRunning) ++ { ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ return; ++ } ++ else ++ { ++ pAd->Mlme.bRunning = TRUE; ++ } ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++ ++ while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) ++ { ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num)); ++ break; ++ } ++ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ ++ //From message type, determine which state machine I should drive ++ if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) ++ { ++#ifdef RT2870 ++ if (Elem->MsgType == MT2_RESET_CONF) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n")); ++ MlmeRestartStateMachine(pAd); ++ Elem->Occupied = FALSE; ++ Elem->MsgLen = 0; ++ continue; ++ } ++#endif // RT2870 // ++ ++ // if dequeue success ++ switch (Elem->Machine) ++ { ++ // STA state machines ++#ifdef CONFIG_STA_SUPPORT ++ case ASSOC_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); ++ break; ++ case AUTH_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); ++ break; ++ case AUTH_RSP_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); ++ break; ++ case SYNC_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); ++ break; ++ case MLME_CNTL_STATE_MACHINE: ++ MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); ++ break; ++ case WPA_PSK_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); ++ break; ++#ifdef LEAP_SUPPORT ++ case LEAP_STATE_MACHINE: ++ LeapMachinePerformAction(pAd, &pAd->Mlme.LeapMachine, Elem); ++ break; ++#endif ++ case AIRONET_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); ++ break; ++ ++#ifdef QOS_DLS_SUPPORT ++ case DLS_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); ++ break; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ case ACTION_STATE_MACHINE: ++ StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); ++ break; ++ ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine)); ++ break; ++ } // end of switch ++ ++ // free MLME element ++ Elem->Occupied = FALSE; ++ Elem->MsgLen = 0; ++ ++ } ++ else { ++ DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); ++ } ++ } ++ ++ NdisAcquireSpinLock(&pAd->Mlme.TaskLock); ++ pAd->Mlme.bRunning = FALSE; ++ NdisReleaseSpinLock(&pAd->Mlme.TaskLock); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Destructor of MLME (Destroy queue, state machine, spin lock and timer) ++ Parameters: ++ Adapter - NIC Adapter pointer ++ Post: ++ The MLME task will no longer work properly ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeHalt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BOOLEAN Cancelled; ++#ifdef RT3070 ++ UINT32 TxPinCfg = 0x00050F0F; ++#endif // RT3070 // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ // disable BEACON generation and other BEACON related hardware timers ++ AsicDisableSync(pAd); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef QOS_DLS_SUPPORT ++ UCHAR i; ++#endif // QOS_DLS_SUPPORT // ++ // Cancel pending timers ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++ ++#ifdef QOS_DLS_SUPPORT ++ for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); ++ } ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); ++ ++ ++ ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ // Set LED ++ RTMPSetLED(pAd, LED_HALT); ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. ++#ifdef RT2870 ++ { ++ LED_CFG_STRUC LedCfg; ++ RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word); ++ LedCfg.field.LedPolar = 0; ++ LedCfg.field.RLedMode = 0; ++ LedCfg.field.GLedMode = 0; ++ LedCfg.field.YLedMode = 0; ++ RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word); ++ } ++#endif // RT2870 // ++#ifdef RT3070 ++ // ++ // Turn off LNA_PE ++ // ++ if (IS_RT3070(pAd) || IS_RT3071(pAd)) ++ { ++ TxPinCfg &= 0xFFFFF0F0; ++ RTUSBWriteMACRegister(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++#endif // RT3070 // ++ } ++ ++ RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled ++ ++ MlmeQueueDestroy(&pAd->Mlme.Queue); ++ NdisFreeSpinLock(&pAd->Mlme.TaskLock); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n")); ++} ++ ++VOID MlmeResetRalinkCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt; ++ // clear all OneSecxxx counters. ++ pAd->RalinkCounters.OneSecBeaconSentCnt = 0; ++ pAd->RalinkCounters.OneSecFalseCCACnt = 0; ++ pAd->RalinkCounters.OneSecRxFcsErrCnt = 0; ++ pAd->RalinkCounters.OneSecRxOkCnt = 0; ++ pAd->RalinkCounters.OneSecTxFailCount = 0; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0; ++ pAd->RalinkCounters.OneSecTxRetryOkCount = 0; ++ pAd->RalinkCounters.OneSecRxOkDataCnt = 0; ++ ++ // TODO: for debug only. to be removed ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0; ++ pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0; ++ pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0; ++ pAd->RalinkCounters.OneSecTxDoneCount = 0; ++ pAd->RalinkCounters.OneSecRxCount = 0; ++ pAd->RalinkCounters.OneSecTxAggregationCount = 0; ++ pAd->RalinkCounters.OneSecRxAggregationCount = 0; ++ ++ return; ++} ++ ++unsigned long rx_AMSDU; ++unsigned long rx_Total; ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is executed periodically to - ++ 1. Decide if it's a right time to turn on PwrMgmt bit of all ++ outgoiing frames ++ 2. Calculate ChannelQuality based on statistics of the last ++ period, so that TX rate won't toggling very frequently between a ++ successful TX and a failed TX. ++ 3. If the calculated ChannelQuality indicated current connection not ++ healthy, then a ROAMing attempt is tried here. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++#define ADHOC_BEACON_LOST_TIME (8*OS_HZ) // 8 sec ++VOID MlmePeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ULONG TxTotalCnt; ++ PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RADIO_MEASUREMENT | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS)))) ++ return; ++ ++ RT28XX_MLME_PRE_SANITY_CHECK(pAd); ++ ++#ifdef RALINK_ATE ++ /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) ++ { ++ pAd->Mlme.PeriodicRound ++; ++ return; ++ } ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ ++ if (pAd->Mlme.PeriodicRound & 0x1) ++ { ++ // This is the fix for wifi 11n extension channel overlapping test case. for 2860D ++ if (((pAd->MACVersion & 0xffff) == 0x0101) && ++ (STA_TGN_WIFI_ON(pAd)) && ++ (pAd->CommonCfg.IOTestParm.bToggle == FALSE)) ++ ++ { ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf); ++ pAd->CommonCfg.IOTestParm.bToggle = TRUE; ++ } ++ else if ((STA_TGN_WIFI_ON(pAd)) && ++ ((pAd->MACVersion & 0xffff) == 0x0101)) ++ { ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f); ++ pAd->CommonCfg.IOTestParm.bToggle = FALSE; ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->bUpdateBcnCntDone = FALSE; ++ ++// RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); ++ pAd->Mlme.PeriodicRound ++; ++ ++#ifdef RT2870 ++ // execute every 100ms, update the Tx FIFO Cnt for update Tx Rate. ++ NICUpdateFifoStaCounters(pAd); ++#endif // RT2870 // ++ // execute every 500ms ++ if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ // perform dynamic tx rate switching based on past TX history ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) ++ MlmeDynamicTxRateSwitching(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // Normal 1 second Mlme PeriodicExec. ++ if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) ++ { ++ pAd->Mlme.OneSecPeriodicRound ++; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ /* request from Baron : move this routine from later to here */ ++ /* for showing Rx error count in ATE RXFRAME */ ++ NICUpdateRawCounters(pAd); ++ if (pAd->ate.bRxFer == 1) ++ { ++ pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); ++ pAd->ate.RxCntPerSec = 0; ++ ++ if (pAd->ate.RxAntennaSel == 0) ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", ++ pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); ++ else ++ ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); ++ } ++ MlmeResetRalinkCounters(pAd); ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ ++ if (rx_Total) ++ { ++ ++ // reset counters ++ rx_AMSDU = 0; ++ rx_Total = 0; ++ } ++ ++ //ORIBATimerTimeout(pAd); ++ ++ // Media status changed, report to NDIS ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ ++ } ++ else ++ { ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ } ++ } ++ ++ NdisGetSystemUpTime(&pAd->Mlme.Now32); ++ ++ // add the most up-to-date h/w raw counters into software variable, so that ++ // the dynamic tuning mechanism below are based on most up-to-date information ++ NICUpdateRawCounters(pAd); ++ ++#ifdef RT2870 ++ RT2870_WatchDog(pAd); ++#endif // RT2870 // ++ ++#ifdef DOT11_N_SUPPORT ++ // Need statistics after read counter. So put after NICUpdateRawCounters ++ ORIBATimerTimeout(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ // The time period for checking antenna is according to traffic ++ { ++ if (pAd->Mlme.bEnableAutoAntennaCheck) ++ { ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ // dynamic adjust antenna evaluation period according to the traffic ++ if (TxTotalCnt > 50) ++ { ++ if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) ++ { ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ else ++ { ++ if (pAd->Mlme.OneSecPeriodicRound % 3 == 0) ++ { ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ } ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ STAMlmePeriodicExec(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ MlmeResetRalinkCounters(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ { ++ // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock ++ // and sending CTS-to-self over and over. ++ // Software Patch Solution: ++ // 1. Polling debug state register 0x10F4 every one second. ++ // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. ++ // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. ++ ++ UINT32 MacReg = 0; ++ ++ RTMP_IO_READ32(pAd, 0x10F4, &MacReg); ++ if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20))) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ RTMPusecDelay(1); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC); ++ ++ DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n")); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ ++ pAd->bUpdateBcnCntDone = FALSE; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID STAMlmePeriodicExec( ++ PRTMP_ADAPTER pAd) ++{ ++ ULONG TxTotalCnt; ++ int i; ++ ++// ++// We return here in ATE mode, because the statistics ++// that ATE needs are not collected via this routine. ++// ++#ifdef RALINK_ATE ++ // It is supposed that we will never reach here in ATE mode. ++ ASSERT(!(ATE_ON(pAd))); ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // WPA MIC error should block association attempt for 60 seconds ++ if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) ++ pAd->StaCfg.bBlockAssoc = FALSE; ++ } ++ ++ if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ pAd->PreMediaState = pAd->IndicateMediaState; ++ } ++ ++ ++ ++ ++ AsicStaBbpTuning(pAd); ++ ++ TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ // update channel quality for Roaming and UI LinkQuality display ++ MlmeCalculateChannelQuality(pAd, pAd->Mlme.Now32); ++ } ++ ++ // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if ++ // Radio is currently in noisy environment ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ AsicAdjustTxPower(pAd); ++ ++ if (INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ // Check DLS time out, then tear down those session ++ RTMPCheckDLSTimeOut(pAd); ++#endif // QOS_DLS_SUPPORT // ++ ++ // Is PSM bit consistent with user power management policy? ++ // This is the only place that will set PSM bit ON. ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ MlmeCheckPsmChange(pAd, pAd->Mlme.Now32); ++ ++ pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt; ++ ++ if ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && ++ ((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt < 600))) ++ { ++ RTMPSetAGCInitValue(pAd, BW_20); ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd)))); ++ } ++ ++ //if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && ++ // (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) ++ { ++ // When APSD is enabled, the period changes as 20 sec ++ if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8) ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ } ++ else ++ { ++ // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) ++ if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) ++ { ++ if (pAd->CommonCfg.bWmmCapable) ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ else ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); ++ } ++ } ++ } ++ ++ if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); ++ pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; ++ pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime; ++ ++ // Lost AP, send disconnect & link down event ++ LinkDown(pAd, FALSE); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ // RTMPPatchMacBbpBug(pAd); ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) ++ { ++ pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ ++ // Add auto seamless roaming ++ if (pAd->StaCfg.bFastRoaming) ++ { ++ SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam)); ++ ++ if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam) ++ { ++ MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32); ++ } ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ //radar detect ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ RadarDetectPeriodic(pAd); ++ } ++ ++ // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState ++ // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can ++ // join later. ++ if ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) && ++ OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ MLME_START_REQ_STRUCT StartReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n")); ++ LinkDown(pAd, FALSE); ++ ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; ++ ++ if (pEntry->ValidAsCLI == FALSE) ++ continue; ++ ++ if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) ++ MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); ++ } ++ } ++ else // no INFRA nor ADHOC connection ++ { ++ ++ if (pAd->StaCfg.bScanReqIsFromWebUI && ++ ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32)) ++ goto SKIP_AUTO_SCAN_CONN; ++ else ++ pAd->StaCfg.bScanReqIsFromWebUI = FALSE; ++ ++ if ((pAd->StaCfg.bAutoReconnect == TRUE) ++ && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) ++ && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) ++ { ++ if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) ++ { ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); ++ ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ // Reset Missed scan number ++ pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; ++ } ++ else if (pAd->StaCfg.BssType == BSS_ADHOC) // Quit the forever scan when in a very clean room ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) ++ { ++ MlmeAutoScan(pAd); ++ pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; ++ } ++ else ++ { ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ else ++#endif // CARRIER_DETECTION_SUPPORT // ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ } ++ } ++ } ++ ++SKIP_AUTO_SCAN_CONN: ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) ++ { ++ pAd->MacTab.fAnyBASession = TRUE; ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++ else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE)) ++ { ++ pAd->MacTab.fAnyBASession = FALSE; ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) ++ TriEventCounterMaintenance(pAd); ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ return; ++} ++ ++// Link down report ++VOID LinkDownExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeAutoScan( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n")); ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeAutoReconnectLastSSID( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++ ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && ++ (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) ++ { ++ NDIS_802_11_SSID OidSsid; ++ OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen; ++ NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen)); ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ &OidSsid); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ========================================================================== ++ Validate SSID for connection try and rescan purpose ++ Valid SSID will have visible chars only. ++ The valid length is from 0 to 32. ++ IRQL = DISPATCH_LEVEL ++ ========================================================================== ++ */ ++BOOLEAN MlmeValidateSSID( ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen) ++{ ++ int index; ++ ++ if (SsidLen > MAX_LEN_OF_SSID) ++ return (FALSE); ++ ++ // Check each character value ++ for (index = 0; index < SsidLen; index++) ++ { ++ if (pSsid[index] < 0x20) ++ return (FALSE); ++ } ++ ++ // All checked ++ return (TRUE); ++} ++ ++VOID MlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx) ++{ ++ do ++ { ++ // decide the rate table for tuning ++ if (pAd->CommonCfg.TxRateTableSize > 0) ++ { ++ *ppTable = RateSwitchTable; ++ *pTableSize = RateSwitchTable[0]; ++ *pInitTxRateIdx = RateSwitchTable[1]; ++ ++ break; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && ++ (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ {// 11N 1S Adhoc ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ ++ } ++ else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && ++ (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ (pEntry->HTCapability.MCSSet[1] == 0xff) && ++ (pAd->Antenna.field.TxPath == 2)) ++ {// 11N 2S Adhoc ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if ((pEntry->RateLen == 4) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ } ++ else if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ } ++ break; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ //if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ++ // ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) ++ {// 11BGN 1S AP ++ *ppTable = RateSwitchTable11BGN1S; ++ *pTableSize = RateSwitchTable11BGN1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN1S[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ++ // (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) ++ if ((pEntry->RateLen == 12) && (pEntry->HTCapability.MCSSet[0] == 0xff) && ++ (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) ++ {// 11BGN 2S AP ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11BGN2S; ++ *pTableSize = RateSwitchTable11BGN2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN2S[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11BGN2SForABand; ++ *pTableSize = RateSwitchTable11BGN2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1]; ++ ++ } ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) ++ if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) ++ {// 11N 1S AP ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) ++ if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) ++ {// 11N 2S AP ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ } ++ ++ break; ++ } ++#endif // DOT11_N_SUPPORT // ++ //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen == 4) ++#ifdef DOT11_N_SUPPORT ++//Iverson mark for Adhoc b mode,sta will use rate 54 Mbps when connect with sta b/g/n mode ++// && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// B only AP ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen > 8) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// B/G mixed AP ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ ++ break; ++ } ++ ++ //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->RateLen == 8) ++#ifdef DOT11_N_SUPPORT ++ && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) ++#endif // DOT11_N_SUPPORT // ++ ) ++ {// G only AP ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef DOT11_N_SUPPORT ++ //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) ++ if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) ++#endif // DOT11_N_SUPPORT // ++ { // Legacy mode ++ if (pAd->CommonCfg.MaxTxRate <= RATE_11) ++ { ++ *ppTable = RateSwitchTable11B; ++ *pTableSize = RateSwitchTable11B[0]; ++ *pInitTxRateIdx = RateSwitchTable11B[1]; ++ } ++ else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11)) ++ { ++ *ppTable = RateSwitchTable11G; ++ *pTableSize = RateSwitchTable11G[0]; ++ *pInitTxRateIdx = RateSwitchTable11G[1]; ++ ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11BG; ++ *pTableSize = RateSwitchTable11BG[0]; ++ *pInitTxRateIdx = RateSwitchTable11BG[1]; ++ } ++ break; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ if (pAd->CommonCfg.TxStream == 1) ++ { ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2S; ++ *pTableSize = RateSwitchTable11N2S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.TxStream == 1) ++ { ++ *ppTable = RateSwitchTable11N1S; ++ *pTableSize = RateSwitchTable11N1S[0]; ++ *pInitTxRateIdx = RateSwitchTable11N1S[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); ++ } ++ else ++ { ++ *ppTable = RateSwitchTable11N2SForABand; ++ *pTableSize = RateSwitchTable11N2SForABand[0]; ++ *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", ++ pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } while(FALSE); ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ This routine checks if there're other APs out there capable for ++ roaming. Caller should call this routine only when Link up in INFRA mode ++ and channel quality is below CQI_GOOD_THRESHOLD. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Output: ++ ========================================================================== ++ */ ++VOID MlmeCheckForRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ USHORT i; ++ BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; ++ BSS_ENTRY *pBss; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n")); ++ // put all roaming candidates into RoamTab, and sort in RSSI order ++ BssTableInit(pRoamTab); ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ pBss = &pAd->ScanTab.BssEntry[i]; ++ ++ if ((pBss->LastBeaconRxTime + BEACON_LOST_TIME) < Now32) ++ continue; // AP disappear ++ if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) ++ continue; // RSSI too weak. forget it. ++ if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) ++ continue; // skip current AP ++ if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA)) ++ continue; // only AP with stronger RSSI is eligible for roaming ++ ++ // AP passing all above rules is put into roaming candidate table ++ NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); ++ pRoamTab->BssNr += 1; ++ } ++ ++ if (pRoamTab->BssNr > 0) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ pAd->RalinkCounters.PoorCQIRoamingCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine checks if there're other APs out there capable for ++ roaming. Caller should call this routine only when link up in INFRA mode ++ and channel quality is below CQI_GOOD_THRESHOLD. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Output: ++ ========================================================================== ++ */ ++VOID MlmeCheckForFastRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now) ++{ ++ USHORT i; ++ BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; ++ BSS_ENTRY *pBss; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n")); ++ // put all roaming candidates into RoamTab, and sort in RSSI order ++ BssTableInit(pRoamTab); ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ pBss = &pAd->ScanTab.BssEntry[i]; ++ ++ if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel)) ++ continue; // RSSI too weak. forget it. ++ if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) ++ continue; // skip current AP ++ if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) ++ continue; // skip different SSID ++ if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA)) ++ continue; // skip AP without better RSSI ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi)); ++ // AP passing all above rules is put into roaming candidate table ++ NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); ++ pRoamTab->BssNr += 1; ++ } ++ ++ if (pRoamTab->BssNr > 0) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) ++ { ++ pAd->RalinkCounters.PoorCQIRoamingCount ++; ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ } ++ // Maybe site survey required ++ else ++ { ++ if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now) ++ { ++ // check CntlMachine.CurrState to avoid collision with NDIS SetOID request ++ DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); ++ pAd->StaCfg.ScanCnt = 2; ++ pAd->StaCfg.LastScanTime = Now; ++ MlmeAutoScan(pAd); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine calculates TxPER, RxPER of the past N-sec period. And ++ according to the calculation result, ChannelQuality is calculated here ++ to decide if current AP is still doing the job. ++ ++ If ChannelQuality is not good, a ROAMing attempt may be tried later. ++ Output: ++ StaCfg.ChannelQuality - 0..100 ++ ++ IRQL = DISPATCH_LEVEL ++ ++ NOTE: This routine decide channle quality based on RX CRC error ratio. ++ Caller should make sure a function call to NICUpdateRawCounters(pAd) ++ is performed right before this routine, so that this routine can decide ++ channel quality based on the most up-to-date information ++ ========================================================================== ++ */ ++VOID MlmeCalculateChannelQuality( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ ULONG TxOkCnt, TxCnt, TxPER, TxPRR; ++ ULONG RxCnt, RxPER; ++ UCHAR NorRssi; ++ CHAR MaxRssi; ++ ULONG BeaconLostTime = BEACON_LOST_TIME; ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // longer beacon lost time when carrier detection enabled ++ if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++ { ++ BeaconLostTime = BEACON_LOST_TIME + BEACON_LOST_TIME/2; ++ } ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++ MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); ++ ++ // ++ // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics ++ // ++ TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount; ++ TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount; ++ if (TxCnt < 5) ++ { ++ TxPER = 0; ++ TxPRR = 0; ++ } ++ else ++ { ++ TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt; ++ TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt; ++ } ++ ++ // ++ // calculate RX PER - don't take RxPER into consideration if too few sample ++ // ++ RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt; ++ if (RxCnt < 5) ++ RxPER = 0; ++ else ++ RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt; ++ ++ // ++ // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER ++ // ++ if (INFRA_ON(pAd) && ++ (pAd->RalinkCounters.OneSecTxNoRetryOkCount < 2) && // no heavy traffic ++ (pAd->StaCfg.LastBeaconRxTime + BeaconLostTime < Now32)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt)); ++ pAd->Mlme.ChannelQuality = 0; ++ } ++ else ++ { ++ // Normalize Rssi ++ if (MaxRssi > -40) ++ NorRssi = 100; ++ else if (MaxRssi < -90) ++ NorRssi = 0; ++ else ++ NorRssi = (MaxRssi + 90) * 2; ++ ++ // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) ++ pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi + ++ TX_WEIGHTING * (100 - TxPRR) + ++ RX_WEIGHTING* (100 - RxPER)) / 100; ++ if (pAd->Mlme.ChannelQuality >= 100) ++ pAd->Mlme.ChannelQuality = 100; ++ } ++ ++} ++ ++VOID MlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate) ++{ ++ UCHAR MaxMode = MODE_OFDM; ++ ++#ifdef DOT11_N_SUPPORT ++ MaxMode = MODE_HTGREENFIELD; ++ ++ if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; ++ ++ if (pTxRate->CurrMCS < MCS_AUTO) ++ pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS; ++ ++ if (pAd->StaCfg.HTPhyMode.field.MCS > 7) ++ pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; ++ ++ if (ADHOC_ON(pAd)) ++ { ++ // If peer adhoc is b-only mode, we can't send 11g rate. ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ pEntry->HTPhyMode.field.STBC = STBC_NONE; ++ ++ // ++ // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary ++ // ++ pEntry->HTPhyMode.field.MODE = pTxRate->Mode; ++ pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ ++ // Patch speed error in status page ++ pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE; ++ } ++ else ++ { ++ if (pTxRate->Mode <= MaxMode) ++ pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ ++#ifdef DOT11_N_SUPPORT ++ // Reexam each bandwidth's SGI support. ++ if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) ++ { ++ if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE))) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE))) ++ pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; ++ } ++ ++ // Turn RTS/CTS rate to 6Mbps. ++ if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) ++ { ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ if (pAd->MacTab.fAnyBASession) ++ { ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ else ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ } ++ else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) ++ { ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ if (pAd->MacTab.fAnyBASession) ++ { ++ AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ else ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++ } ++ else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) ++ { ++ AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ ++ } ++ else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) ++ { ++ AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; ++ pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && ++ pAd->WIFItestbed.bGreenField) ++ pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine calculates the acumulated TxPER of eaxh TxRate. And ++ according to the calculation result, change CommonCfg.TxRate which ++ is the stable TX Rate we expect the Radio situation could sustained. ++ ++ CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} ++ Output: ++ CommonCfg.TxRate - ++ ++ IRQL = DISPATCH_LEVEL ++ ++ NOTE: ++ call this routine every second ++ ========================================================================== ++ */ ++VOID MlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx; ++ ULONG i, AccuTxTotalCnt = 0, TxTotalCnt; ++ ULONG TxErrorRatio = 0; ++ BOOLEAN bTxRateChanged, bUpgradeQuality = FALSE; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; ++ CHAR Rssi, RssiOffset = 0; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; ++ MAC_TABLE_ENTRY *pEntry; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ // ++ // walk through MAC table, see if need to change AP's TX rate toward each entry ++ // ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ // check if this entry need to switch rate automatically ++ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) ++ continue; ++ ++ if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) ++ { ++ Rssi = RTMPMaxRssi(pAd, ++ pAd->StaCfg.RssiSample.AvgRssi0, ++ pAd->StaCfg.RssiSample.AvgRssi1, ++ pAd->StaCfg.RssiSample.AvgRssi2); ++ ++ // Update statistic counter ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ pAd->bUpdateBcnCntDone = TRUE; ++ TxRetransmit = StaTx1.field.TxRetransmit; ++ TxSuccess = StaTx1.field.TxSuccess; ++ TxFailCount = TxStaCnt0.field.TxFailCount; ++ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; ++ ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ ++ // if no traffic in the past 1-sec period, don't change TX rate, ++ // but clear all bad history. because the bad history may affect the next ++ // Chariot throughput test ++ AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; ++ } ++ else ++ { ++ if (INFRA_ON(pAd) && (i == 1)) ++ Rssi = RTMPMaxRssi(pAd, ++ pAd->StaCfg.RssiSample.AvgRssi0, ++ pAd->StaCfg.RssiSample.AvgRssi1, ++ pAd->StaCfg.RssiSample.AvgRssi2); ++ else ++ Rssi = RTMPMaxRssi(pAd, ++ pEntry->RssiSample.AvgRssi0, ++ pEntry->RssiSample.AvgRssi1, ++ pEntry->RssiSample.AvgRssi2); ++ ++ TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + ++ pEntry->OneSecTxRetryOkCount + ++ pEntry->OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; ++ } ++ ++ CurrRateIdx = pEntry->CurrTxRateIndex; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); ++ ++ if (CurrRateIdx >= TableSize) ++ { ++ CurrRateIdx = TableSize - 1; ++ } ++ ++ // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. ++ // So need to sync here. ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS) ++ //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ ) ++ { ++ ++ // Need to sync Real Tx rate and our record. ++ // Then return for next DRS. ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5]; ++ pEntry->CurrTxRateIndex = InitTxRateIdx; ++ MlmeSetTxRate(pAd, pEntry, pCurrTxRate); ++ ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ continue; ++ } ++ ++ // decide the next upgrade rate and downgrade rate, if any ++ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx -1; ++ } ++ else if (CurrRateIdx == 0) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx; ++ } ++ else if (CurrRateIdx == (TableSize - 1)) ++ { ++ UpRateIdx = CurrRateIdx; ++ DownRateIdx = CurrRateIdx - 1; ++ } ++ ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) ++ { ++ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); ++ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ TrainUp = pCurrTxRate->TrainUp; ++ TrainDown = pCurrTxRate->TrainDown; ++ } ++ ++ //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; ++ ++ // ++ // Keep the last time TxRateChangeAction status. ++ // ++ pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction; ++ ++ ++ ++ // ++ // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI ++ // (criteria copied from RT2500 for Netopia case) ++ // ++ if (TxTotalCnt <= 15) ++ { ++ CHAR idx = 0; ++ UCHAR TxRateIdx; ++ //UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; ++ UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0; ++ UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; ++ UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3 ++ ++ // check the existence and index of each needed MCS ++ while (idx < pTable[0]) ++ { ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5]; ++ ++ if (pCurrTxRate->CurrMCS == MCS_0) ++ { ++ MCS0 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_1) ++ { ++ MCS1 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_2) ++ { ++ MCS2 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_3) ++ { ++ MCS3 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_4) ++ { ++ MCS4 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_5) ++ { ++ MCS5 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_6) ++ { ++ MCS6 = idx; ++ } ++ //else if (pCurrTxRate->CurrMCS == MCS_7) ++ else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput ++ { ++ MCS7 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_12) ++ { ++ MCS12 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_13) ++ { ++ MCS13 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_14) ++ { ++ MCS14 = idx; ++ } ++ else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) ++ { ++ MCS15 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3 ++ { ++ MCS20 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_21) ++ { ++ MCS21 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_22) ++ { ++ MCS22 = idx; ++ } ++ else if (pCurrTxRate->CurrMCS == MCS_23) ++ { ++ MCS23 = idx; ++ } ++ idx ++; ++ } ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ RssiOffset = 2; ++ } ++ else ++ { ++ RssiOffset = 5; ++ } ++ } ++ else ++ { ++ if (pAd->NicConfig2.field.ExternalLNAForA) ++ { ++ RssiOffset = 5; ++ } ++ else ++ { ++ RssiOffset = 8; ++ } ++ } ++#ifdef DOT11_N_SUPPORT ++ /*if (MCS15)*/ ++ if ((pTable == RateSwitchTable11BGN3S) || ++ (pTable == RateSwitchTable11N3S) || ++ (pTable == RateSwitchTable)) ++ {// N mode with 3 stream // 3*3 ++ if (MCS23 && (Rssi >= -70)) ++ TxRateIdx = MCS15; ++ else if (MCS22 && (Rssi >= -72)) ++ TxRateIdx = MCS14; ++ else if (MCS21 && (Rssi >= -76)) ++ TxRateIdx = MCS13; ++ else if (MCS20 && (Rssi >= -78)) ++ TxRateIdx = MCS12; ++ else if (MCS4 && (Rssi >= -82)) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi >= -84)) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi >= -86)) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi >= -88)) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++// else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) ++ else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3 ++ {// N mode with 2 stream ++ if (MCS15 && (Rssi >= (-70+RssiOffset))) ++ TxRateIdx = MCS15; ++ else if (MCS14 && (Rssi >= (-72+RssiOffset))) ++ TxRateIdx = MCS14; ++ else if (MCS13 && (Rssi >= (-76+RssiOffset))) ++ TxRateIdx = MCS13; ++ else if (MCS12 && (Rssi >= (-78+RssiOffset))) ++ TxRateIdx = MCS12; ++ else if (MCS4 && (Rssi >= (-82+RssiOffset))) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi >= (-84+RssiOffset))) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi >= (-86+RssiOffset))) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi >= (-88+RssiOffset))) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) ++ {// N mode with 1 stream ++ if (MCS7 && (Rssi > (-72+RssiOffset))) ++ TxRateIdx = MCS7; ++ else if (MCS6 && (Rssi > (-74+RssiOffset))) ++ TxRateIdx = MCS6; ++ else if (MCS5 && (Rssi > (-77+RssiOffset))) ++ TxRateIdx = MCS5; ++ else if (MCS4 && (Rssi > (-79+RssiOffset))) ++ TxRateIdx = MCS4; ++ else if (MCS3 && (Rssi > (-81+RssiOffset))) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi > (-83+RssiOffset))) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi > (-86+RssiOffset))) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ {// Legacy mode ++ if (MCS7 && (Rssi > -70)) ++ TxRateIdx = MCS7; ++ else if (MCS6 && (Rssi > -74)) ++ TxRateIdx = MCS6; ++ else if (MCS5 && (Rssi > -78)) ++ TxRateIdx = MCS5; ++ else if (MCS4 && (Rssi > -82)) ++ TxRateIdx = MCS4; ++ else if (MCS4 == 0) // for B-only mode ++ TxRateIdx = MCS3; ++ else if (MCS3 && (Rssi > -85)) ++ TxRateIdx = MCS3; ++ else if (MCS2 && (Rssi > -87)) ++ TxRateIdx = MCS2; ++ else if (MCS1 && (Rssi > -90)) ++ TxRateIdx = MCS1; ++ else ++ TxRateIdx = MCS0; ++ } ++ ++ // if (TxRateIdx != pAd->CommonCfg.TxRateIndex) ++ { ++ pEntry->CurrTxRateIndex = TxRateIdx; ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ ++ NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ pEntry->fLastSecAccordingRSSI = TRUE; ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ continue; ++ } ++ ++ if (pEntry->fLastSecAccordingRSSI == TRUE) ++ { ++ pEntry->fLastSecAccordingRSSI = FALSE; ++ pEntry->LastSecTxRateChangeAction = 0; ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ continue; ++ } ++ ++ do ++ { ++ BOOLEAN bTrainUpDown = FALSE; ++ ++ pEntry->CurrTxRateStableTime ++; ++ ++ // downgrade TX quality if PER >= Rate-Down threshold ++ if (TxErrorRatio >= TrainDown) ++ { ++ bTrainUpDown = TRUE; ++ pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ // upgrade TX quality if PER <= Rate-Up threshold ++ else if (TxErrorRatio <= TrainUp) ++ { ++ bTrainUpDown = TRUE; ++ bUpgradeQuality = TRUE; ++ if (pEntry->TxQuality[CurrRateIdx]) ++ pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate ++ ++ if (pEntry->TxRateUpPenalty) ++ pEntry->TxRateUpPenalty --; ++ else if (pEntry->TxQuality[UpRateIdx]) ++ pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality ++ } ++ ++ pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio; ++ ++ if (bTrainUpDown) ++ { ++ // perform DRS - consider TxRate Down first, then rate up. ++ if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND)) ++ { ++ pEntry->CurrTxRateIndex = DownRateIdx; ++ } ++ else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0)) ++ { ++ pEntry->CurrTxRateIndex = UpRateIdx; ++ } ++ } ++ } while (FALSE); ++ ++ // if rate-up happen, clear all bad history of all TX rates ++ if (pEntry->CurrTxRateIndex > CurrRateIdx) ++ { ++ pEntry->CurrTxRateStableTime = 0; ++ pEntry->TxRateUpPenalty = 0; ++ pEntry->LastSecTxRateChangeAction = 1; // rate UP ++ NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ ++ // ++ // For TxRate fast train up ++ // ++ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) ++ { ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; ++ } ++ bTxRateChanged = TRUE; ++ } ++ // if rate-down happen, only clear DownRate's bad history ++ else if (pEntry->CurrTxRateIndex < CurrRateIdx) ++ { ++ pEntry->CurrTxRateStableTime = 0; ++ pEntry->TxRateUpPenalty = 0; // no penalty ++ pEntry->LastSecTxRateChangeAction = 2; // rate DOWN ++ pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; ++ pEntry->PER[pEntry->CurrTxRateIndex] = 0; ++ ++ // ++ // For TxRate fast train down ++ // ++ if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) ++ { ++ RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; ++ } ++ bTxRateChanged = TRUE; ++ } ++ else ++ { ++ pEntry->LastSecTxRateChangeAction = 0; // rate no change ++ bTxRateChanged = FALSE; ++ } ++ ++ pEntry->LastTxOkCount = TxSuccess; ++ ++ // reset all OneSecTx counters ++ RESET_ONE_SEC_TX_CNT(pEntry); ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; ++ if (bTxRateChanged && pNextTxRate) ++ { ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Station side, Auto TxRate faster train up timer call back function. ++ ++ Arguments: ++ SystemSpecific1 - Not used. ++ FunctionContext - Pointer to our Adapter context. ++ SystemSpecific2 - Not used. ++ SystemSpecific3 - Not used. ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID StaQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; ++ UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; ++ ULONG TxTotalCnt; ++ ULONG TxErrorRatio = 0; ++ BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ CHAR Rssi, ratio; ++ ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; ++ MAC_TABLE_ENTRY *pEntry; ++ ULONG i; ++ ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; ++ ++ // ++ // walk through MAC table, see if need to change AP's TX rate toward each entry ++ // ++ for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) ++ { ++ pEntry = &pAd->MacTab.Content[i]; ++ ++ // check if this entry need to switch rate automatically ++ if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) ++ continue; ++ ++ if (INFRA_ON(pAd) && (i == 1)) ++ Rssi = RTMPMaxRssi(pAd, ++ pAd->StaCfg.RssiSample.AvgRssi0, ++ pAd->StaCfg.RssiSample.AvgRssi1, ++ pAd->StaCfg.RssiSample.AvgRssi2); ++ else ++ Rssi = RTMPMaxRssi(pAd, ++ pEntry->RssiSample.AvgRssi0, ++ pEntry->RssiSample.AvgRssi1, ++ pEntry->RssiSample.AvgRssi2); ++ ++ CurrRateIdx = pAd->CommonCfg.TxRateIndex; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); ++ ++ // decide the next upgrade rate and downgrade rate, if any ++ if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx -1; ++ } ++ else if (CurrRateIdx == 0) ++ { ++ UpRateIdx = CurrRateIdx + 1; ++ DownRateIdx = CurrRateIdx; ++ } ++ else if (CurrRateIdx == (TableSize - 1)) ++ { ++ UpRateIdx = CurrRateIdx; ++ DownRateIdx = CurrRateIdx - 1; ++ } ++ ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) ++ { ++ TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); ++ TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ TrainUp = pCurrTxRate->TrainUp; ++ TrainDown = pCurrTxRate->TrainDown; ++ } ++ ++ if (pAd->MacTab.Size == 1) ++ { ++ // Update statistic counter ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ ++ TxRetransmit = StaTx1.field.TxRetransmit; ++ TxSuccess = StaTx1.field.TxSuccess; ++ TxFailCount = TxStaCnt0.field.TxFailCount; ++ TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; ++ ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; ++ } ++ else ++ { ++ TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + ++ pEntry->OneSecTxRetryOkCount + ++ pEntry->OneSecTxFailCount; ++ ++ if (TxTotalCnt) ++ TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; ++ } ++ ++ ++ // ++ // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI ++ // (criteria copied from RT2500 for Netopia case) ++ // ++ if (TxTotalCnt <= 12) ++ { ++ NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ ++ if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) ++ { ++ pAd->CommonCfg.TxRateIndex = DownRateIdx; ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) ++ { ++ pAd->CommonCfg.TxRateIndex = UpRateIdx; ++ } ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n")); ++ return; ++ } ++ ++ do ++ { ++ ULONG OneSecTxNoRetryOKRationCount; ++ ++ if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0) ++ ratio = 5; ++ else ++ ratio = 4; ++ ++ // downgrade TX quality if PER >= Rate-Down threshold ++ if (TxErrorRatio >= TrainDown) ++ { ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ } ++ ++ pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio; ++ ++ OneSecTxNoRetryOKRationCount = (TxSuccess * ratio); ++ ++ // perform DRS - consider TxRate Down first, then rate up. ++ if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) ++ { ++ if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) ++ { ++ pAd->CommonCfg.TxRateIndex = DownRateIdx; ++ pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; ++ ++ } ++ ++ } ++ else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) ++ { ++ if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) ++ { ++ ++ } ++ else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) ++ { ++ pAd->CommonCfg.TxRateIndex = UpRateIdx; ++ } ++ } ++ }while (FALSE); ++ ++ // if rate-up happen, clear all bad history of all TX rates ++ if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) ++ { ++ pAd->DrsCounters.TxRateUpPenalty = 0; ++ NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); ++ NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); ++ bTxRateChanged = TRUE; ++ } ++ // if rate-down happen, only clear DownRate's bad history ++ else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex)); ++ ++ pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty ++ pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; ++ pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; ++ bTxRateChanged = TRUE; ++ } ++ else ++ { ++ bTxRateChanged = FALSE; ++ } ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5]; ++ if (bTxRateChanged && pNextTxRate) ++ { ++ MlmeSetTxRate(pAd, pEntry, pNextTxRate); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This routine is executed periodically inside MlmePeriodicExec() after ++ association with an AP. ++ It checks if StaCfg.Psm is consistent with user policy (recorded in ++ StaCfg.WindowsPowerMode). If not, enforce user policy. However, ++ there're some conditions to consider: ++ 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all ++ the time when Mibss==TRUE ++ 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE ++ if outgoing traffic available in TxRing or MgmtRing. ++ Output: ++ 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeCheckPsmChange( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32) ++{ ++ ULONG PowerMode; ++ ++ // condition - ++ // 1. Psm maybe ON only happen in INFRASTRUCTURE mode ++ // 2. user wants either MAX_PSP or FAST_PSP ++ // 3. but current psm is not in PWR_SAVE ++ // 4. CNTL state machine is not doing SCANning ++ // 5. no TX SUCCESS event for the past 1-sec period ++#ifdef NDIS51_MINIPORT ++ if (pAd->StaCfg.WindowsPowerProfile == NdisPowerProfileBattery) ++ PowerMode = pAd->StaCfg.WindowsBatteryPowerMode; ++ else ++#endif ++ PowerMode = pAd->StaCfg.WindowsPowerMode; ++ ++ if (INFRA_ON(pAd) && ++ (PowerMode != Ndis802_11PowerModeCAM) && ++ (pAd->StaCfg.Psm == PWR_ACTIVE) && ++// (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) /*&& ++ (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && ++ (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/) ++ { ++ // add by johnli, use Rx OK data count per second to calculate throughput ++ // If Ttraffic is too high ( > 400 Rx per second), don't go to sleep mode. If tx rate is low, use low criteria ++ // Mode=CCK/MCS=3 => 11 Mbps, Mode=OFDM/MCS=3 => 18 Mbps ++ if (((pAd->StaCfg.HTPhyMode.field.MCS <= 3) && ++/* Iverson mark ++ (pAd->StaCfg.HTPhyMode.field.MODE <= MODE_OFDM) && ++*/ ++ (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)100)) || ++ ((pAd->StaCfg.HTPhyMode.field.MCS > 3) && ++/* Iverson mark ++ (pAd->StaCfg.HTPhyMode.field.MODE > MODE_OFDM) && ++*/ ++ (pAd->RalinkCounters.OneSecRxOkDataCnt < (ULONG)400))) ++ { ++ // Get this time ++ NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); ++ pAd->RalinkCounters.RxCountSinceLastNULL = 0; ++ MlmeSetPsmBit(pAd, PWR_SAVE); ++ if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) ++ { ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); ++ } ++ else ++ { ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ } ++ } ++ } ++} ++ ++// IRQL = PASSIVE_LEVEL ++// IRQL = DISPATCH_LEVEL ++VOID MlmeSetPsmBit( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm) ++{ ++ AUTO_RSP_CFG_STRUC csr4; ++ ++ pAd->StaCfg.Psm = psm; ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); ++ csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeSetTxPreamble( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TxPreamble) ++{ ++ AUTO_RSP_CFG_STRUC csr4; ++ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ //TxPreamble = Rt802_11PreambleLong; ++ ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); ++ if (TxPreamble == Rt802_11PreambleLong) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ csr4.field.AutoResponderPreamble = 0; ++ } ++ else ++ { ++ // NOTE: 1Mbps should always use long preamble ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n")); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ csr4.field.AutoResponderPreamble = 1; ++ } ++ ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Update basic rate bitmap ++ ========================================================================== ++ */ ++ ++VOID UpdateBasicRateBitmap( ++ IN PRTMP_ADAPTER pAdapter) ++{ ++ INT i, j; ++ /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */ ++ UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; ++ UCHAR *sup_p = pAdapter->CommonCfg.SupRate; ++ UCHAR *ext_p = pAdapter->CommonCfg.ExtRate; ++ ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap; ++ ++ ++ /* if A mode, always use fix BasicRateBitMap */ ++ //if (pAdapter->CommonCfg.Channel == PHY_11A) ++ if (pAdapter->CommonCfg.Channel > 14) ++ pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */ ++ /* End of if */ ++ ++ if (pAdapter->CommonCfg.BasicRateBitmap > 4095) ++ { ++ /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */ ++ return; ++ } /* End of if */ ++ ++ for(i=0; iCommonCfg.DesireRate[i] & 0x7f) ++ { ++ case 2: Rate = RATE_1; num++; break; ++ case 4: Rate = RATE_2; num++; break; ++ case 11: Rate = RATE_5_5; num++; break; ++ case 22: Rate = RATE_11; num++; break; ++ case 12: Rate = RATE_6; num++; break; ++ case 18: Rate = RATE_9; num++; break; ++ case 24: Rate = RATE_12; num++; break; ++ case 36: Rate = RATE_18; num++; break; ++ case 48: Rate = RATE_24; num++; break; ++ case 72: Rate = RATE_36; num++; break; ++ case 96: Rate = RATE_48; num++; break; ++ case 108: Rate = RATE_54; num++; break; ++ //default: Rate = RATE_1; break; ++ } ++ if (MaxDesire < Rate) MaxDesire = Rate; ++ } ++ ++//=========================================================================== ++//=========================================================================== ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pHtPhy = &pAd->StaCfg.HTPhyMode; ++ pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; ++ pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; ++ ++ auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; ++ HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; ++ ++ if ((pAd->StaCfg.BssType == BSS_ADHOC) && ++ (pAd->CommonCfg.PhyMode == PHY_11B) && ++ (MaxDesire > RATE_11)) ++ { ++ MaxDesire = RATE_11; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->CommonCfg.MaxDesiredRate = MaxDesire; ++ pMinHtPhy->word = 0; ++ pMaxHtPhy->word = 0; ++ pHtPhy->word = 0; ++ ++ // Auto rate switching is enabled only if more than one DESIRED RATES are ++ // specified; otherwise disabled ++ if (num <= 1) ++ { ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; ++ *auto_rate_cur_p = FALSE; ++ } ++ else ++ { ++ //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; ++ *auto_rate_cur_p = TRUE; ++ } ++ ++#if 1 ++ if (HtMcs != MCS_AUTO) ++ { ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; ++ *auto_rate_cur_p = FALSE; ++ } ++ else ++ { ++ //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); ++ //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; ++ *auto_rate_cur_p = TRUE; ++ } ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ pSupRate = &pAd->StaActive.SupRate[0]; ++ pExtRate = &pAd->StaActive.ExtRate[0]; ++ SupRateLen = pAd->StaActive.SupRateLen; ++ ExtRateLen = pAd->StaActive.ExtRateLen; ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ pSupRate = &pAd->CommonCfg.SupRate[0]; ++ pExtRate = &pAd->CommonCfg.ExtRate[0]; ++ SupRateLen = pAd->CommonCfg.SupRateLen; ++ ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ } ++ ++ // find max supported rate ++ for (i=0; i Rate) MinSupport = Rate; ++ } ++ ++ for (i=0; i Rate) MinSupport = Rate; ++ } ++ ++ RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap); ++ ++ // calculate the exptected ACK rate for each TX rate. This info is used to caculate ++ // the DURATION field of outgoing uniicast DATA/MGMT frame ++ for (i=0; iCommonCfg.ExpectedACKRate[i] = CurrBasicRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire])); ++ // max tx rate = min {max desire rate, max supported rate} ++ if (MaxSupport < MaxDesire) ++ pAd->CommonCfg.MaxTxRate = MaxSupport; ++ else ++ pAd->CommonCfg.MaxTxRate = MaxDesire; ++ ++ pAd->CommonCfg.MinTxRate = MinSupport; ++ // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success ++ // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending ++ // on average RSSI ++ // 1. RSSI >= -70db, start at 54 Mbps (short distance) ++ // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) ++ // 3. -75 > RSSI, start at 11 Mbps (long distance) ++ //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* && ++ // OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/) ++ if (*auto_rate_cur_p) ++ { ++ short dbm = 0; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; ++#endif // CONFIG_STA_SUPPORT // ++ if (bLinkUp == TRUE) ++ pAd->CommonCfg.TxRate = RATE_24; ++ else ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ ++ if (dbm < -75) ++ pAd->CommonCfg.TxRate = RATE_11; ++ else if (dbm < -70) ++ pAd->CommonCfg.TxRate = RATE_24; ++ ++ // should never exceed MaxTxRate (consider 11B-only mode) ++ if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate) ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ ++ pAd->CommonCfg.TxRateIndex = 0; ++ } ++ else ++ { ++ pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; ++ pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate; ++ pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK; ++ ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS; ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE; ++ } ++ ++ if (pAd->CommonCfg.TxRate <= RATE_11) ++ { ++ pMaxHtPhy->field.MODE = MODE_CCK; ++ pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate; ++ pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate; ++ } ++ else ++ { ++ pMaxHtPhy->field.MODE = MODE_OFDM; ++ pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate]; ++ if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54)) ++ {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];} ++ else ++ {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;} ++ } ++ ++ pHtPhy->word = (pMaxHtPhy->word); ++ if (bLinkUp && (pAd->OpMode == OPMODE_STA)) ++ { ++ pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word; ++ pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word; ++ pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word; ++ } ++ else ++ { ++ switch (pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11BG_MIXED: ++ case PHY_11B: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11BGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.MlmeRate = RATE_1; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; ++ ++//#ifdef WIFI_TEST ++ pAd->CommonCfg.RtsRate = RATE_11; ++//#else ++// pAd->CommonCfg.RtsRate = RATE_1; ++//#endif ++ break; ++ case PHY_11G: ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11AGN_MIXED: ++ case PHY_11GN_MIXED: ++ case PHY_11N_2_4G: ++ case PHY_11AN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ break; ++ case PHY_11ABG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ pAd->CommonCfg.MlmeRate = RATE_1; ++ pAd->CommonCfg.RtsRate = RATE_1; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; ++ } ++ else ++ { ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ break; ++ default: // error ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->CommonCfg.RtsRate = RATE_1; ++ break; ++ } ++ // ++ // Keep Basic Mlme Rate. ++ // ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word; ++ if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM) ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24]; ++ else ++ pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1; ++ pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n", ++ RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate], ++ /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n", ++ RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n", ++ pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); ++} ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ This function update HT Rate setting. ++ Input Wcid value is valid for 2 case : ++ 1. it's used for Station in infra mode that copy AP rate to Mactable. ++ 2. OR Station in adhoc mode to copy peer's HT rate to Mactable. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeUpdateHtTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx) ++{ ++ UCHAR StbcMcs; //j, StbcMcs, bitmask; ++ CHAR i; // 3*3 ++ RT_HT_CAPABILITY *pRtHtCap = NULL; ++ RT_HT_PHY_INFO *pActiveHtPhy = NULL; ++ ULONG BasicMCS; ++ UCHAR j, bitmask; ++ PRT_HT_PHY_INFO pDesireHtPhy = NULL; ++ PHTTRANSMIT_SETTING pHtPhy = NULL; ++ PHTTRANSMIT_SETTING pMaxHtPhy = NULL; ++ PHTTRANSMIT_SETTING pMinHtPhy = NULL; ++ BOOLEAN *auto_rate_cur_p; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n")); ++ ++ auto_rate_cur_p = NULL; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; ++ pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; ++ pHtPhy = &pAd->StaCfg.HTPhyMode; ++ pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; ++ pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; ++ ++ auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) ++ { ++ if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ return; ++ ++ pRtHtCap = &pAd->StaActive.SupportedHtPhy; ++ pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo; ++ StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs; ++ BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16); ++ if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) ++ pMaxHtPhy->field.STBC = STBC_USE; ++ else ++ pMaxHtPhy->field.STBC = STBC_NONE; ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ if (pDesireHtPhy->bHtEnable == FALSE) ++ return; ++ ++ pRtHtCap = &pAd->CommonCfg.DesiredHtPhy; ++ StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs; ++ BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16); ++ if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) ++ pMaxHtPhy->field.STBC = STBC_USE; ++ else ++ pMaxHtPhy->field.STBC = STBC_NONE; ++ } ++ ++ // Decide MAX ht rate. ++ if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ pMaxHtPhy->field.MODE = MODE_HTGREENFIELD; ++ else ++ pMaxHtPhy->field.MODE = MODE_HTMIX; ++ ++ if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth)) ++ pMaxHtPhy->field.BW = BW_40; ++ else ++ pMaxHtPhy->field.BW = BW_20; ++ ++ if (pMaxHtPhy->field.BW == BW_20) ++ pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20); ++ else ++ pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40); ++ ++ for (i=23; i>=0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ ++ if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask)) ++ { ++ pMaxHtPhy->field.MCS = i; ++ break; ++ } ++ ++ if (i==0) ++ break; ++ } ++ ++ // Copy MIN ht rate. rt2860??? ++ pMinHtPhy->field.BW = BW_20; ++ pMinHtPhy->field.MCS = 0; ++ pMinHtPhy->field.STBC = 0; ++ pMinHtPhy->field.ShortGI = 0; ++ //If STA assigns fixed rate. update to fixed here. ++#ifdef CONFIG_STA_SUPPORT ++ if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) ++ { ++ if (pDesireHtPhy->MCSSet[4] != 0) ++ { ++ pMaxHtPhy->field.MCS = 32; ++ pMinHtPhy->field.MCS = 32; ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS)); ++ } ++ ++ for (i=23; (CHAR)i >= 0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask)) ++ { ++ pMaxHtPhy->field.MCS = i; ++ pMinHtPhy->field.MCS = i; ++ break; ++ } ++ if (i==0) ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ // Decide ht rate ++ pHtPhy->field.STBC = pMaxHtPhy->field.STBC; ++ pHtPhy->field.BW = pMaxHtPhy->field.BW; ++ pHtPhy->field.MODE = pMaxHtPhy->field.MODE; ++ pHtPhy->field.MCS = pMaxHtPhy->field.MCS; ++ pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI; ++ ++ // use default now. rt2860 ++ if (pDesireHtPhy->MCSSet[0] != 0xff) ++ *auto_rate_cur_p = FALSE; ++ else ++ *auto_rate_cur_p = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize )); ++ DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS, ++ pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); ++ DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); ++} ++#endif // DOT11_N_SUPPORT // ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRadioOff( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RT28XX_MLME_RADIO_OFF(pAd); ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRadioOn( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RT28XX_MLME_RADIO_ON(pAd); ++} ++ ++// =========================================================================================== ++// bss_table.c ++// =========================================================================================== ++ ++ ++/*! \brief initialize BSS table ++ * \param p_tab pointer to the table ++ * \return none ++ * \pre ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID BssTableInit( ++ IN BSS_TABLE *Tab) ++{ ++ int i; ++ ++ Tab->BssNr = 0; ++ Tab->BssOverlapNr = 0; ++ for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) ++ { ++ NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY)); ++ Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value ++ } ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInit( ++ IN PRTMP_ADAPTER pAd, ++ IN BA_TABLE *Tab) ++{ ++ int i; ++ ++ Tab->numAsOriginator = 0; ++ Tab->numAsRecipient = 0; ++ NdisAllocateSpinLock(&pAd->BATabLock); ++ for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) ++ { ++ Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE; ++ NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock)); ++ } ++ for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) ++ { ++ Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++/*! \brief search the BSS table by SSID ++ * \param p_tab pointer to the bss table ++ * \param ssid SSID string ++ * \return index of the table, BSS_NOT_FOUND if not in the table ++ * \pre ++ * \post ++ * \note search by sequential search ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++ULONG BssTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ // ++ // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. ++ // We should distinguish this case. ++ // ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++ULONG BssSsidTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ // ++ // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. ++ // We should distinguish this case. ++ // ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) && ++ SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++ULONG BssTableSearchWithSSID( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR Bssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel) ++{ ++ UCHAR i; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || ++ ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && ++ MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) && ++ (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) || ++ (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) || ++ (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen)))) ++ { ++ return i; ++ } ++ } ++ return (ULONG)BSS_NOT_FOUND; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableDeleteEntry( ++ IN OUT BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel) ++{ ++ UCHAR i, j; ++ ++ for (i = 0; i < Tab->BssNr; i++) ++ { ++ if ((Tab->BssEntry[i].Channel == Channel) && ++ (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) ++ { ++ for (j = i; j < Tab->BssNr - 1; j++) ++ { ++ NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); ++ } ++ NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY)); ++ Tab->BssNr -= 1; ++ return; ++ } ++ } ++} ++ ++#ifdef DOT11_N_SUPPORT ++/* ++ ======================================================================== ++ Routine Description: ++ Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed. ++ ++ Arguments: ++ // IRQL = DISPATCH_LEVEL ++ ======================================================================== ++*/ ++VOID BATableDeleteORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_ORI_ENTRY *pBAORIEntry) ++{ ++ ++ if (pBAORIEntry->ORI_BA_Status != Originator_NONE) ++ { ++ NdisAcquireSpinLock(&pAd->BATabLock); ++ if (pBAORIEntry->ORI_BA_Status == Originator_Done) ++ { ++ pAd->BATable.numAsOriginator -= 1; ++ DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); ++ // Erase Bitmap flag. ++ } ++ pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here ++ pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here ++ pBAORIEntry->ORI_BA_Status = Originator_NONE; ++ pBAORIEntry->Token = 1; ++ // Not clear Sequence here. ++ NdisReleaseSpinLock(&pAd->BATabLock); ++ } ++} ++#endif // DOT11_N_SUPPORT // ++ ++/*! \brief ++ * \param ++ * \return ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID BssEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_ENTRY *pBss, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN PCF_PARM pCfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ COPY_MAC_ADDR(pBss->Bssid, pBssid); ++ // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID ++ pBss->Hidden = 1; ++ if (SsidLen > 0) ++ { ++ // For hidden SSID AP, it might send beacon with SSID len equal to 0 ++ // Or send beacon /probe response with SSID len matching real SSID length, ++ // but SSID is all zero. such as "00-00-00-00" with length 4. ++ // We have to prevent this case overwrite correct table ++ if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) ++ { ++ NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pBss->Ssid, Ssid, SsidLen); ++ pBss->SsidLen = SsidLen; ++ pBss->Hidden = 0; ++ } ++ } ++ else ++ pBss->SsidLen = 0; ++ pBss->BssType = BssType; ++ pBss->BeaconPeriod = BeaconPeriod; ++ if (BssType == BSS_INFRA) ++ { ++ if (pCfParm->bValid) ++ { ++ pBss->CfpCount = pCfParm->CfpCount; ++ pBss->CfpPeriod = pCfParm->CfpPeriod; ++ pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; ++ pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; ++ } ++ } ++ else ++ { ++ pBss->AtimWin = AtimWin; ++ } ++ ++ pBss->CapabilityInfo = CapabilityInfo; ++ // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES ++ // Combine with AuthMode, they will decide the connection methods. ++ pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); ++ ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES); ++ if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES) ++ NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen); ++ else ++ NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ pBss->SupRateLen = SupRateLen; ++ ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen); ++ NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); ++ NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); ++ pBss->NewExtChanOffset = NewExtChanOffset; ++ pBss->ExtRateLen = ExtRateLen; ++ pBss->Channel = Channel; ++ pBss->CentralChannel = Channel; ++ pBss->Rssi = Rssi; ++ // Update CkipFlag. if not exists, the value is 0x0 ++ pBss->CkipFlag = CkipFlag; ++ ++ // New for microsoft Fixed IEs ++ NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8); ++ pBss->FixIEs.BeaconInterval = BeaconPeriod; ++ pBss->FixIEs.Capabilities = CapabilityInfo; ++ ++ // New for microsoft Variable IEs ++ if (LengthVIE != 0) ++ { ++ pBss->VarIELen = LengthVIE; ++ NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen); ++ } ++ else ++ { ++ pBss->VarIELen = 0; ++ } ++ ++ pBss->AddHtInfoLen = 0; ++ pBss->HtCapabilityLen = 0; ++#ifdef DOT11_N_SUPPORT ++ if (HtCapabilityLen> 0) ++ { ++ pBss->HtCapabilityLen = HtCapabilityLen; ++ NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); ++ if (AddHtInfoLen > 0) ++ { ++ pBss->AddHtInfoLen = AddHtInfoLen; ++ NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); ++ ++ if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) ++ { ++ pBss->CentralChannel = pAddHtInfo->ControlChan - 2; ++ } ++ else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) ++ { ++ pBss->CentralChannel = pAddHtInfo->ControlChan + 2; ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ BssCipherParse(pBss); ++ ++ // new for QOS ++ if (pEdcaParm) ++ NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ else ++ pBss->EdcaParm.bValid = FALSE; ++ if (pQosCapability) ++ NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ else ++ pBss->QosCapability.bValid = FALSE; ++ if (pQbssLoad) ++ NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ else ++ pBss->QbssLoad.bValid = FALSE; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ PEID_STRUCT pEid; ++ USHORT Length = 0; ++ ++ ++ NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); ++ NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ NdisZeroMemory(&pBss->CountryString[0], 3); ++ pBss->bHasCountryIE = FALSE; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ pEid = (PEID_STRUCT) pVIE; ++ while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) ++ { ++ switch(pEid->Eid) ++ { ++ case IE_WPA: ++ if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ { ++ if ((pEid->Len + 2) > MAX_CUSTOM_LEN) ++ { ++ pBss->WpaIE.IELen = 0; ++ break; ++ } ++ pBss->WpaIE.IELen = pEid->Len + 2; ++ NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen); ++ } ++ break; ++ case IE_RSN: ++ if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ { ++ if ((pEid->Len + 2) > MAX_CUSTOM_LEN) ++ { ++ pBss->RsnIE.IELen = 0; ++ break; ++ } ++ pBss->RsnIE.IELen = pEid->Len + 2; ++ NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); ++ } ++ break; ++#ifdef EXT_BUILD_CHANNEL_LIST ++ case IE_COUNTRY: ++ NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); ++ pBss->bHasCountryIE = TRUE; ++ break; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ } ++ Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++} ++ ++/*! ++ * \brief insert an entry into the bss table ++ * \param p_tab The BSS table ++ * \param Bssid BSSID ++ * \param ssid SSID ++ * \param ssid_len Length of SSID ++ * \param bss_type ++ * \param beacon_period ++ * \param timestamp ++ * \param p_cf ++ * \param atim_win ++ * \param cap ++ * \param rates ++ * \param rates_len ++ * \param channel_idx ++ * \return none ++ * \pre ++ * \post ++ * \note If SSID is identical, the old entry will be replaced by the new one ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++ULONG BssTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN CF_PARM *CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR ChannelNo, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE) ++{ ++ ULONG Idx; ++ ++ Idx = BssTableSearchWithSSID(Tab, pBssid, Ssid, SsidLen, ChannelNo); ++ if (Idx == BSS_NOT_FOUND) ++ { ++ if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) ++ { ++ // ++ // It may happen when BSS Table was full. ++ // The desired AP will not be added into BSS Table ++ // In this case, if we found the desired AP then overwrite BSS Table. ++ // ++ if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) || ++ SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)) ++ { ++ Idx = Tab->BssOverlapNr; ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE; ++ } ++ return Idx; ++ } ++ else ++ { ++ return BSS_NOT_FOUND; ++ } ++ } ++ Idx = Tab->BssNr; ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ Tab->BssNr++; ++ } ++ else ++ { ++ /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */ ++ if ((SSID_EQUAL(Ssid, SsidLen, Tab->BssEntry[Idx].Ssid, Tab->BssEntry[Idx].SsidLen)) || ++ (NdisEqualMemory(Tab->BssEntry[Idx].Ssid, ZeroSsid, Tab->BssEntry[Idx].SsidLen))) ++ { ++ BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, ++ CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, ++ NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); ++ } ++ } ++ ++ return Idx; ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++VOID TriEventInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ ++ for (i = 0;i < MAX_TRIGGER_EVENT;i++) ++ pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; ++ ++ pAd->CommonCfg.TriggerEventTab.EventANo = 0; ++ pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; ++} ++ ++ULONG TriEventTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT TRIGGER_EVENT_TAB *Tab, ++ IN PUCHAR pBssid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR RegClass, ++ IN UCHAR ChannelNo) ++{ ++ // Event A ++ if (HtCapabilityLen == 0) ++ { ++ if (Tab->EventANo < MAX_TRIGGER_EVENT) ++ { ++ RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); ++ Tab->EventA[Tab->EventANo].bValid = TRUE; ++ Tab->EventA[Tab->EventANo].Channel = ChannelNo; ++ Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; ++ if (RegClass != 0) ++ { ++ // Beacon has Regulatory class IE. So use beacon's ++ Tab->EventA[Tab->EventANo].RegClass = RegClass; ++ } ++ else ++ { ++ // Use Station's Regulatory class instead. ++ if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) ++ { ++ if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) ++ { ++ Tab->EventA[Tab->EventANo].RegClass = 32; ++ } ++ else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) ++ Tab->EventA[Tab->EventANo].RegClass = 33; ++ } ++ else ++ Tab->EventA[Tab->EventANo].RegClass = ??; ++ ++ } ++ ++ Tab->EventANo ++; ++ } ++ } ++ else if (pHtCapability->HtCapInfo.Intolerant40) ++ { ++ Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Trigger Event table Maintainence called once every second. ++ ++ Arguments: ++ // IRQL = DISPATCH_LEVEL ++ ======================================================================== ++*/ ++VOID TriEventCounterMaintenance( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i; ++ BOOLEAN bNotify = FALSE; ++ for (i = 0;i < MAX_TRIGGER_EVENT;i++) ++ { ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; ++ if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; ++ pAd->CommonCfg.TriggerEventTab.EventANo --; ++ // Need to send 20/40 Coexistence Notify frame if has status change. ++ bNotify = TRUE; ++ } ++ } ++ } ++ if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) ++ { ++ pAd->CommonCfg.TriggerEventTab.EventBCountDown--; ++ if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) ++ bNotify = TRUE; ++ } ++ ++ if (bNotify == TRUE) ++ Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableSsidSort( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *OutTab, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen) ++{ ++ INT i; ++ BssTableInit(OutTab); ++ ++ for (i = 0; i < pAd->ScanTab.BssNr; i++) ++ { ++ BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i]; ++ BOOLEAN bIsHiddenApIncluded = FALSE; ++ ++ if (((pAd->CommonCfg.bIEEE80211H == 1) && ++ (pAd->MlmeAux.Channel > 14) && ++ RadarChannelCheck(pAd, pInBss->Channel)) ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ if (pInBss->Hidden) ++ bIsHiddenApIncluded = TRUE; ++ } ++ ++ if ((pInBss->BssType == pAd->StaCfg.BssType) && ++ (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded)) ++ { ++ BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; ++ ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. ++ if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && ++ (pInBss->bHasCountryIE == FALSE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); ++ continue; ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef DOT11_N_SUPPORT ++ // 2.4G/5G N only mode ++ if ((pInBss->HtCapabilityLen == 0) && ++ ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); ++ continue; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // New for WPA2 ++ // Check the Authmode first ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode ++ if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) ++ // None matched ++ continue; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) ++ continue; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA2.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) ++ continue; ++ } ++ } ++ // Bss Type matched, SSID matched. ++ // We will check wepstatus for qualification Bss ++ else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus)); ++ // ++ // For the SESv2 case, we will not qualify WepStatus. ++ // ++ if (!pInBss->bSES) ++ continue; ++ } ++ ++ // Since the AP is using hidden SSID, and we are trying to connect to ANY ++ // It definitely will fail. So, skip it. ++ // CCX also require not even try to connect it!! ++ if (SsidLen == 0) ++ continue; ++ ++#ifdef DOT11_N_SUPPORT ++ // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region ++ // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, ++ if ((pInBss->CentralChannel != pInBss->Channel) && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ SetCommonHT(pAd); ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ else ++ { ++ if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20) ++ { ++ SetCommonHT(pAd); ++ } ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // copy matching BSS from InTab to OutTab ++ NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); ++ ++ OutTab->BssNr++; ++ } ++ else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0)) ++ { ++ BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; ++ ++ ++#ifdef DOT11_N_SUPPORT ++ // 2.4G/5G N only mode ++ if ((pInBss->HtCapabilityLen == 0) && ++ ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); ++ continue; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // New for WPA2 ++ // Check the Authmode first ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode ++ if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) ++ // None matched ++ continue; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) ++ continue; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // If it's not mixed mode, we should only let BSS pass with the same encryption ++ if (pInBss->WPA2.bMixMode == FALSE) ++ if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check group cipher ++ if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) ++ continue; ++ ++ // check pairwise cipher, skip if none matched ++ // If profile set to AES, let it pass without question. ++ // If profile set to TKIP, we must find one mateched ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && ++ (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) ++ continue; ++ } ++ } ++ // Bss Type matched, SSID matched. ++ // We will check wepstatus for qualification Bss ++ else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) ++ continue; ++ ++#ifdef DOT11_N_SUPPORT ++ // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region ++ // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, ++ if ((pInBss->CentralChannel != pInBss->Channel) && ++ (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) ++ { ++ if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ SetCommonHT(pAd); ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // copy matching BSS from InTab to OutTab ++ NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); ++ ++ OutTab->BssNr++; ++ } ++ ++ if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) ++ break; ++ } ++ ++ BssTableSortByRssi(OutTab); ++} ++ ++ ++// IRQL = DISPATCH_LEVEL ++VOID BssTableSortByRssi( ++ IN OUT BSS_TABLE *OutTab) ++{ ++ INT i, j; ++ BSS_ENTRY TmpBss; ++ ++ for (i = 0; i < OutTab->BssNr - 1; i++) ++ { ++ for (j = i+1; j < OutTab->BssNr; j++) ++ { ++ if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) ++ { ++ NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); ++ NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); ++ NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); ++ } ++ } ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++VOID BssCipherParse( ++ IN OUT PBSS_ENTRY pBss) ++{ ++ PEID_STRUCT pEid; ++ PUCHAR pTmp; ++ PRSN_IE_HEADER_STRUCT pRsnHeader; ++ PCIPHER_SUITE_STRUCT pCipher; ++ PAKM_SUITE_STRUCT pAKM; ++ USHORT Count; ++ INT Length; ++ NDIS_802_11_ENCRYPTION_STATUS TmpCipher; ++ ++ // ++ // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. ++ // ++ if (pBss->Privacy) ++ { ++ pBss->WepStatus = Ndis802_11WEPEnabled; ++ } ++ else ++ { ++ pBss->WepStatus = Ndis802_11WEPDisabled; ++ } ++ // Set default to disable & open authentication before parsing variable IE ++ pBss->AuthMode = Ndis802_11AuthModeOpen; ++ pBss->AuthModeAux = Ndis802_11AuthModeOpen; ++ ++ // Init WPA setting ++ pBss->WPA.PairCipher = Ndis802_11WEPDisabled; ++ pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled; ++ pBss->WPA.GroupCipher = Ndis802_11WEPDisabled; ++ pBss->WPA.RsnCapability = 0; ++ pBss->WPA.bMixMode = FALSE; ++ ++ // Init WPA2 setting ++ pBss->WPA2.PairCipher = Ndis802_11WEPDisabled; ++ pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled; ++ pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled; ++ pBss->WPA2.RsnCapability = 0; ++ pBss->WPA2.bMixMode = FALSE; ++ ++ ++ Length = (INT) pBss->VarIELen; ++ ++ while (Length > 0) ++ { ++ // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently ++ pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length; ++ pEid = (PEID_STRUCT) pTmp; ++ switch (pEid->Eid) ++ { ++ case IE_WPA: ++ //Parse Cisco IE_WPA (LEAP, CCKM, etc.) ++ if ( NdisEqualMemory((pTmp+8), CISCO_OUI, 3)) ++ { ++ pTmp += 11; ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WepStatus = Ndis802_11Encryption1Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WepStatus = Ndis802_11Encryption2Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 4: ++ pBss->WepStatus = Ndis802_11Encryption3Enabled; ++ pBss->WPA.PairCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ default: ++ break; ++ } ++ ++ // if Cisco IE_WPA, break ++ break; ++ } ++ else if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7)) ++ { ++ pBss->bSES = TRUE; ++ break; ++ } ++ else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1) ++ { ++ // if unsupported vendor specific IE ++ break; ++ } ++ // Skip OUI, version, and multicast suite ++ // This part should be improved in the future when AP supported multiple cipher suite. ++ // For now, it's OK since almost all APs have fixed cipher suite supported. ++ // pTmp = (PUCHAR) pEid->Octet; ++ pTmp += 11; ++ ++ // Cipher Suite Selectors from Spec P802.11i/D3.2 P26. ++ // Value Meaning ++ // 0 None ++ // 1 WEP-40 ++ // 2 Tkip ++ // 3 WRAP ++ // 4 AES ++ // 5 WEP-104 ++ // Parse group cipher ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ // number of unicast suite ++ pTmp += 1; ++ ++ // skip all unicast cipher suites ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // Parsing all unicast cipher suite ++ while (Count > 0) ++ { ++ // Skip OUI ++ pTmp += 3; ++ TmpCipher = Ndis802_11WEPDisabled; ++ switch (*pTmp) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ TmpCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ TmpCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ TmpCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ if (TmpCipher > pBss->WPA.PairCipher) ++ { ++ // Move the lower cipher suite to PairCipherAux ++ pBss->WPA.PairCipherAux = pBss->WPA.PairCipher; ++ pBss->WPA.PairCipher = TmpCipher; ++ } ++ else ++ { ++ pBss->WPA.PairCipherAux = TmpCipher; ++ } ++ pTmp++; ++ Count--; ++ } ++ ++ // 4. get AKM suite counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ pTmp += 3; ++ ++ switch (*pTmp) ++ { ++ case 1: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA; ++ break; ++ case 2: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPAPSK; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK; ++ break; ++ default: ++ break; ++ } ++ pTmp += 1; ++ ++ // Fixed for WPA-None ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ pBss->AuthMode = Ndis802_11AuthModeWPANone; ++ pBss->AuthModeAux = Ndis802_11AuthModeWPANone; ++ pBss->WepStatus = pBss->WPA.GroupCipher; ++ if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) ++ pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; ++ } ++ else ++ pBss->WepStatus = pBss->WPA.PairCipher; ++ ++ // Check the Pair & Group, if different, turn on mixed mode flag ++ if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher) ++ pBss->WPA.bMixMode = TRUE; ++ ++ break; ++ ++ case IE_RSN: ++ pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp; ++ ++ // 0. Version must be 1 ++ if (le2cpu16(pRsnHeader->Version) != 1) ++ break; ++ pTmp += sizeof(RSN_IE_HEADER_STRUCT); ++ ++ // 1. Check group cipher ++ pCipher = (PCIPHER_SUITE_STRUCT) pTmp; ++ if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) ++ break; ++ ++ // Parse group cipher ++ switch (pCipher->Type) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ // set to correct offset for next parsing ++ pTmp += sizeof(CIPHER_SUITE_STRUCT); ++ ++ // 2. Get pairwise cipher counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // 3. Get pairwise cipher ++ // Parsing all unicast cipher suite ++ while (Count > 0) ++ { ++ // Skip OUI ++ pCipher = (PCIPHER_SUITE_STRUCT) pTmp; ++ TmpCipher = Ndis802_11WEPDisabled; ++ switch (pCipher->Type) ++ { ++ case 1: ++ case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway ++ TmpCipher = Ndis802_11Encryption1Enabled; ++ break; ++ case 2: ++ TmpCipher = Ndis802_11Encryption2Enabled; ++ break; ++ case 4: ++ TmpCipher = Ndis802_11Encryption3Enabled; ++ break; ++ default: ++ break; ++ } ++ if (TmpCipher > pBss->WPA2.PairCipher) ++ { ++ // Move the lower cipher suite to PairCipherAux ++ pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher; ++ pBss->WPA2.PairCipher = TmpCipher; ++ } ++ else ++ { ++ pBss->WPA2.PairCipherAux = TmpCipher; ++ } ++ pTmp += sizeof(CIPHER_SUITE_STRUCT); ++ Count--; ++ } ++ ++ // 4. get AKM suite counts ++ //Count = *(PUSHORT) pTmp; ++ Count = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // 5. Get AKM ciphers ++ pAKM = (PAKM_SUITE_STRUCT) pTmp; ++ if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) ++ break; ++ ++ switch (pAKM->Type) ++ { ++ case 1: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA2; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA2; ++ break; ++ case 2: ++ // Set AP support WPA mode ++ if (pBss->AuthMode == Ndis802_11AuthModeOpen) ++ pBss->AuthMode = Ndis802_11AuthModeWPA2PSK; ++ else ++ pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK; ++ break; ++ default: ++ break; ++ } ++ pTmp += (Count * sizeof(AKM_SUITE_STRUCT)); ++ ++ // Fixed for WPA-None ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ pBss->AuthMode = Ndis802_11AuthModeWPANone; ++ pBss->AuthModeAux = Ndis802_11AuthModeWPANone; ++ pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; ++ pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; ++ pBss->WepStatus = pBss->WPA.GroupCipher; ++ if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) ++ pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; ++ } ++ pBss->WepStatus = pBss->WPA2.PairCipher; ++ ++ // 6. Get RSN capability ++ //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp; ++ pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0]; ++ pTmp += sizeof(USHORT); ++ ++ // Check the Pair & Group, if different, turn on mixed mode flag ++ if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher) ++ pBss->WPA2.bMixMode = TRUE; ++ ++ break; ++ default: ++ break; ++ } ++ Length -= (pEid->Len + 2); ++ } ++} ++ ++// =========================================================================================== ++// mac_table.c ++// =========================================================================================== ++ ++/*! \brief generates a random mac address value for IBSS BSSID ++ * \param Addr the bssid location ++ * \return none ++ * \pre ++ * \post ++ */ ++VOID MacAddrRandomBssid( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pAddr) ++{ ++ INT i; ++ ++ for (i = 0; i < MAC_ADDR_LEN; i++) ++ { ++ pAddr[i] = RandomByte(pAd); ++ } ++ ++ pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx ++} ++ ++/*! \brief init the management mac frame header ++ * \param p_hdr mac header ++ * \param subtype subtype of the frame ++ * \param p_ds destination address, don't care if it is a broadcast address ++ * \return none ++ * \pre the station has the following information in the pAd->StaCfg ++ * - bssid ++ * - station address ++ * \post ++ * \note this function initializes the following field ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID MgtMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ ++ pHdr80211->FC.Type = BTYPE_MGMT; ++ pHdr80211->FC.SubType = SubType; ++// if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type ++// pHdr80211->FC.Type = BTYPE_CNTL; ++ pHdr80211->FC.ToDs = ToDs; ++ COPY_MAC_ADDR(pHdr80211->Addr1, pDA); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++#endif // CONFIG_STA_SUPPORT // ++ COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); ++} ++ ++// =========================================================================================== ++// mem_mgmt.c ++// =========================================================================================== ++ ++/*!*************************************************************************** ++ * This routine build an outgoing frame, and fill all information specified ++ * in argument list to the frame body. The actual frame size is the summation ++ * of all arguments. ++ * input params: ++ * Buffer - pointer to a pre-allocated memory segment ++ * args - a list of pairs. ++ * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this ++ * function will FAIL!!! ++ * return: ++ * Size of the buffer ++ * usage: ++ * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ****************************************************************************/ ++ULONG MakeOutgoingFrame( ++ OUT CHAR *Buffer, ++ OUT ULONG *FrameLen, ...) ++{ ++ CHAR *p; ++ int leng; ++ ULONG TotLeng; ++ va_list Args; ++ ++ // calculates the total length ++ TotLeng = 0; ++ va_start(Args, FrameLen); ++ do ++ { ++ leng = va_arg(Args, int); ++ if (leng == END_OF_ARGS) ++ { ++ break; ++ } ++ p = va_arg(Args, PVOID); ++ NdisMoveMemory(&Buffer[TotLeng], p, leng); ++ TotLeng = TotLeng + leng; ++ } while(TRUE); ++ ++ va_end(Args); /* clean up */ ++ *FrameLen = TotLeng; ++ return TotLeng; ++} ++ ++// =========================================================================================== ++// mlme_queue.c ++// =========================================================================================== ++ ++/*! \brief Initialize The MLME Queue, used by MLME Functions ++ * \param *Queue The MLME Queue ++ * \return Always Return NDIS_STATE_SUCCESS in this implementation ++ * \pre ++ * \post ++ * \note Because this is done only once (at the init stage), no need to be locked ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++NDIS_STATUS MlmeQueueInit( ++ IN MLME_QUEUE *Queue) ++{ ++ INT i; ++ ++ NdisAllocateSpinLock(&Queue->Lock); ++ ++ Queue->Num = 0; ++ Queue->Head = 0; ++ Queue->Tail = 0; ++ ++ for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) ++ { ++ Queue->Entry[i].Occupied = FALSE; ++ Queue->Entry[i].MsgLen = 0; ++ NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE); ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread ++ * \param *Queue The MLME Queue ++ * \param Machine The State Machine Id ++ * \param MsgType The Message Type ++ * \param MsgLen The Message length ++ * \param *Msg The message pointer ++ * \return TRUE if enqueue is successful, FALSE if the queue is full ++ * \pre ++ * \post ++ * \note The message has to be initialized ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeEnqueue( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Machine, ++ IN ULONG MsgType, ++ IN ULONG MsgLen, ++ IN VOID *Msg) ++{ ++ INT Tail; ++ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return FALSE; ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ ++ if (MlmeQueueFull(Queue)) ++ { ++ return FALSE; ++ } ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Tail = Queue->Tail; ++ Queue->Tail++; ++ Queue->Num++; ++ if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Tail = 0; ++ } ++ ++ Queue->Entry[Tail].Wcid = RESERVED_WCID; ++ Queue->Entry[Tail].Occupied = TRUE; ++ Queue->Entry[Tail].Machine = Machine; ++ Queue->Entry[Tail].MsgType = MsgType; ++ Queue->Entry[Tail].MsgLen = MsgLen; ++ ++ if (Msg != NULL) ++ { ++ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); ++ } ++ ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ return TRUE; ++} ++ ++/*! \brief This function is used when Recv gets a MLME message ++ * \param *Queue The MLME Queue ++ * \param TimeStampHigh The upper 32 bit of timestamp ++ * \param TimeStampLow The lower 32 bit of timestamp ++ * \param Rssi The receiving RSSI strength ++ * \param MsgLen The length of the message ++ * \param *Msg The message pointer ++ * \return TRUE if everything ok, FALSE otherwise (like Queue Full) ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG TimeStampHigh, ++ IN ULONG TimeStampLow, ++ IN UCHAR Rssi0, ++ IN UCHAR Rssi1, ++ IN UCHAR Rssi2, ++ IN ULONG MsgLen, ++ IN VOID *Msg, ++ IN UCHAR Signal) ++{ ++ INT Tail, Machine; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ INT MsgType; ++ MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; ++ ++#ifdef RALINK_ATE ++ /* Nothing to do in ATE mode */ ++ if(ATE_ON(pAd)) ++ return FALSE; ++#endif // RALINK_ATE // ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); ++ return FALSE; ++ } ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (MsgLen > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); ++ return FALSE; ++ } ++ ++ if (MlmeQueueFull(Queue)) ++ { ++ return FALSE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) ++ { ++ DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType)); ++ return FALSE; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // OK, we got all the informations, it is time to put things into queue ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Tail = Queue->Tail; ++ Queue->Tail++; ++ Queue->Num++; ++ if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Tail = 0; ++ } ++ Queue->Entry[Tail].Occupied = TRUE; ++ Queue->Entry[Tail].Machine = Machine; ++ Queue->Entry[Tail].MsgType = MsgType; ++ Queue->Entry[Tail].MsgLen = MsgLen; ++ Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow; ++ Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh; ++ Queue->Entry[Tail].Rssi0 = Rssi0; ++ Queue->Entry[Tail].Rssi1 = Rssi1; ++ Queue->Entry[Tail].Rssi2 = Rssi2; ++ Queue->Entry[Tail].Signal = Signal; ++ Queue->Entry[Tail].Wcid = (UCHAR)Wcid; ++ ++ Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel; ++ ++ if (Msg != NULL) ++ { ++ NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); ++ } ++ ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return TRUE; ++} ++ ++ ++/*! \brief Dequeue a message from the MLME Queue ++ * \param *Queue The MLME Queue ++ * \param *Elem The message dequeued from MLME Queue ++ * \return TRUE if the Elem contains something, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeDequeue( ++ IN MLME_QUEUE *Queue, ++ OUT MLME_QUEUE_ELEM **Elem) ++{ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ *Elem = &(Queue->Entry[Queue->Head]); ++ Queue->Num--; ++ Queue->Head++; ++ if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) ++ { ++ Queue->Head = 0; ++ } ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ return TRUE; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID MlmeRestartStateMachine( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN Cancelled; ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef QOS_DLS_SUPPORT ++ UCHAR i; ++#endif // QOS_DLS_SUPPORT // ++ // Cancel all timer events ++ // Be careful to cancel new added timer ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++ ++#ifdef QOS_DLS_SUPPORT ++ for (i=0; iStaCfg.DLSEntry[i].Timer, &Cancelled); ++ } ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Change back to original channel in case of doing scan ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // Resume MSDU which is turned off durning scan ++ RTMPResumeMsduTransmission(pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Set all state machines back IDLE ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ pAd->Mlme.ActMachine.CurrState = ACT_IDLE; ++#ifdef QOS_DLS_SUPPORT ++ pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; ++#endif // QOS_DLS_SUPPORT // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++/*! \brief test if the MLME Queue is empty ++ * \param *Queue The MLME Queue ++ * \return TRUE if the Queue is empty, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeQueueEmpty( ++ IN MLME_QUEUE *Queue) ++{ ++ BOOLEAN Ans; ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Ans = (Queue->Num == 0); ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ return Ans; ++} ++ ++/*! \brief test if the MLME Queue is full ++ * \param *Queue The MLME Queue ++ * \return TRUE if the Queue is empty, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++BOOLEAN MlmeQueueFull( ++ IN MLME_QUEUE *Queue) ++{ ++ BOOLEAN Ans; ++ ++ NdisAcquireSpinLock(&(Queue->Lock)); ++ Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied); ++ NdisReleaseSpinLock(&(Queue->Lock)); ++ ++ return Ans; ++} ++ ++/*! \brief The destructor of MLME Queue ++ * \param ++ * \return ++ * \pre ++ * \post ++ * \note Clear Mlme Queue, Set Queue->Num to Zero. ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID MlmeQueueDestroy( ++ IN MLME_QUEUE *pQueue) ++{ ++ NdisAcquireSpinLock(&(pQueue->Lock)); ++ pQueue->Num = 0; ++ pQueue->Head = 0; ++ pQueue->Tail = 0; ++ NdisReleaseSpinLock(&(pQueue->Lock)); ++ NdisFreeSpinLock(&(pQueue->Lock)); ++} ++ ++/*! \brief To substitute the message type if the message is coming from external ++ * \param pFrame The frame received ++ * \param *Machine The state machine ++ * \param *MsgType the message type for the state machine ++ * \return TRUE if the substitution is successful, FALSE otherwise ++ * \pre ++ * \post ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++#ifdef CONFIG_STA_SUPPORT ++BOOLEAN MsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType) ++{ ++ USHORT Seq; ++ UCHAR EAPType; ++ PUCHAR pData; ++ ++ // Pointer to start of data frames including SNAP header ++ pData = (PUCHAR) pFrame + LENGTH_802_11; ++ ++ // The only data type will pass to this function is EAPOL frame ++ if (pFrame->Hdr.FC.Type == BTYPE_DATA) ++ { ++ if (NdisEqualMemory(SNAP_AIRONET, pData, LENGTH_802_1_H)) ++ { ++ // Cisco Aironet SNAP header ++ *Machine = AIRONET_STATE_MACHINE; ++ *MsgType = MT2_AIRONET_MSG; ++ return (TRUE); ++ } ++#ifdef LEAP_SUPPORT ++ if ( pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP ) //LEAP ++ { ++ // LEAP frames ++ *Machine = LEAP_STATE_MACHINE; ++ EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); ++ return (LeapMsgTypeSubst(EAPType, MsgType)); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ *Machine = WPA_PSK_STATE_MACHINE; ++ EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); ++ return(WpaMsgTypeSubst(EAPType, MsgType)); ++ } ++ } ++ ++ switch (pFrame->Hdr.FC.SubType) ++ { ++ case SUBTYPE_ASSOC_REQ: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ASSOC_REQ; ++ break; ++ case SUBTYPE_ASSOC_RSP: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ASSOC_RSP; ++ break; ++ case SUBTYPE_REASSOC_REQ: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_REASSOC_REQ; ++ break; ++ case SUBTYPE_REASSOC_RSP: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_REASSOC_RSP; ++ break; ++ case SUBTYPE_PROBE_REQ: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_PROBE_REQ; ++ break; ++ case SUBTYPE_PROBE_RSP: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_PROBE_RSP; ++ break; ++ case SUBTYPE_BEACON: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_BEACON; ++ break; ++ case SUBTYPE_ATIM: ++ *Machine = SYNC_STATE_MACHINE; ++ *MsgType = MT2_PEER_ATIM; ++ break; ++ case SUBTYPE_DISASSOC: ++ *Machine = ASSOC_STATE_MACHINE; ++ *MsgType = MT2_PEER_DISASSOC_REQ; ++ break; ++ case SUBTYPE_AUTH: ++ // get the sequence number from payload 24 Mac Header + 2 bytes algorithm ++ NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); ++ if (Seq == 1 || Seq == 3) ++ { ++ *Machine = AUTH_RSP_STATE_MACHINE; ++ *MsgType = MT2_PEER_AUTH_ODD; ++ } ++ else if (Seq == 2 || Seq == 4) ++ { ++ *Machine = AUTH_STATE_MACHINE; ++ *MsgType = MT2_PEER_AUTH_EVEN; ++ } ++ else ++ { ++ return FALSE; ++ } ++ break; ++ case SUBTYPE_DEAUTH: ++ *Machine = AUTH_RSP_STATE_MACHINE; ++ *MsgType = MT2_PEER_DEAUTH; ++ break; ++ case SUBTYPE_ACTION: ++ *Machine = ACTION_STATE_MACHINE; ++ // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support ++ if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) ++ { ++ *MsgType = MT2_ACT_INVALID; ++ } ++ else ++ { ++ *MsgType = (pFrame->Octet[0]&0x7F); ++ } ++ break; ++ default: ++ return FALSE; ++ break; ++ } ++ ++ return TRUE; ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++// =========================================================================================== ++// state_machine.c ++// =========================================================================================== ++ ++/*! \brief Initialize the state machine. ++ * \param *S pointer to the state machine ++ * \param Trans State machine transition function ++ * \param StNr number of states ++ * \param MsgNr number of messages ++ * \param DefFunc default function, when there is invalid state/message combination ++ * \param InitState initial state of the state machine ++ * \param Base StateMachine base, internal use only ++ * \pre p_sm should be a legal pointer ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID StateMachineInit( ++ IN STATE_MACHINE *S, ++ IN STATE_MACHINE_FUNC Trans[], ++ IN ULONG StNr, ++ IN ULONG MsgNr, ++ IN STATE_MACHINE_FUNC DefFunc, ++ IN ULONG InitState, ++ IN ULONG Base) ++{ ++ ULONG i, j; ++ ++ // set number of states and messages ++ S->NrState = StNr; ++ S->NrMsg = MsgNr; ++ S->Base = Base; ++ ++ S->TransFunc = Trans; ++ ++ // init all state transition to default function ++ for (i = 0; i < StNr; i++) ++ { ++ for (j = 0; j < MsgNr; j++) ++ { ++ S->TransFunc[i * MsgNr + j] = DefFunc; ++ } ++ } ++ ++ // set the starting state ++ S->CurrState = InitState; ++} ++ ++/*! \brief This function fills in the function pointer into the cell in the state machine ++ * \param *S pointer to the state machine ++ * \param St state ++ * \param Msg incoming message ++ * \param f the function to be executed when (state, message) combination occurs at the state machine ++ * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state ++ * \post ++ ++ IRQL = PASSIVE_LEVEL ++ ++ */ ++VOID StateMachineSetAction( ++ IN STATE_MACHINE *S, ++ IN ULONG St, ++ IN ULONG Msg, ++ IN STATE_MACHINE_FUNC Func) ++{ ++ ULONG MsgIdx; ++ ++ MsgIdx = Msg - S->Base; ++ ++ if (St < S->NrState && MsgIdx < S->NrMsg) ++ { ++ // boundary checking before setting the action ++ S->TransFunc[St * S->NrMsg + MsgIdx] = Func; ++ } ++} ++ ++/*! \brief This function does the state transition ++ * \param *Adapter the NIC adapter pointer ++ * \param *S the state machine ++ * \param *Elem the message to be executed ++ * \return None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ */ ++VOID StateMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ The drop function, when machine executes this, the message is simply ++ ignored. This function does nothing, the message is freed in ++ StateMachinePerformAction() ++ ========================================================================== ++ */ ++VOID Drop( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++} ++ ++// =========================================================================================== ++// lfsr.c ++// =========================================================================================== ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID LfsrInit( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Seed) ++{ ++ if (Seed == 0) ++ pAd->Mlme.ShiftReg = 1; ++ else ++ pAd->Mlme.ShiftReg = Seed; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++UCHAR RandomByte( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ UCHAR R, Result; ++ ++ R = 0; ++ ++ if (pAd->Mlme.ShiftReg == 0) ++ NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg); ++ ++ for (i = 0; i < 8; i++) ++ { ++ if (pAd->Mlme.ShiftReg & 0x00000001) ++ { ++ pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; ++ Result = 1; ++ } ++ else ++ { ++ pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; ++ Result = 0; ++ } ++ R = (R << 1) | Result; ++ } ++ ++ return R; ++} ++ ++VOID AsicUpdateAutoFallBackTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRateTable) ++{ ++ UCHAR i; ++ HT_FBK_CFG0_STRUC HtCfg0; ++ HT_FBK_CFG1_STRUC HtCfg1; ++ LG_FBK_CFG0_STRUC LgCfg0; ++ LG_FBK_CFG1_STRUC LgCfg1; ++ PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate; ++ ++ // set to initial value ++ HtCfg0.word = 0x65432100; ++ HtCfg1.word = 0xedcba988; ++ LgCfg0.word = 0xedcba988; ++ LgCfg1.word = 0x00002100; ++ ++ pNextTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1; ++ for (i = 1; i < *((PUCHAR) pRateTable); i++) ++ { ++ pCurrTxRate = (PRTMP_TX_RATE_SWITCH)pRateTable+1+i; ++ switch (pCurrTxRate->Mode) ++ { ++ case 0: //CCK ++ break; ++ case 1: //OFDM ++ { ++ switch(pCurrTxRate->CurrMCS) ++ { ++ case 0: ++ LgCfg0.field.OFDMMCS0FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 1: ++ LgCfg0.field.OFDMMCS1FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 2: ++ LgCfg0.field.OFDMMCS2FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 3: ++ LgCfg0.field.OFDMMCS3FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 4: ++ LgCfg0.field.OFDMMCS4FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 5: ++ LgCfg0.field.OFDMMCS5FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 6: ++ LgCfg0.field.OFDMMCS6FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ case 7: ++ LgCfg0.field.OFDMMCS7FBK = (pNextTxRate->Mode == MODE_OFDM) ? (pNextTxRate->CurrMCS+8): pNextTxRate->CurrMCS; ++ break; ++ } ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case 2: //HT-MIX ++ case 3: //HT-GF ++ { ++ if ((pNextTxRate->Mode >= MODE_HTMIX) && (pCurrTxRate->CurrMCS != pNextTxRate->CurrMCS)) ++ { ++ switch(pCurrTxRate->CurrMCS) ++ { ++ case 0: ++ HtCfg0.field.HTMCS0FBK = pNextTxRate->CurrMCS; ++ break; ++ case 1: ++ HtCfg0.field.HTMCS1FBK = pNextTxRate->CurrMCS; ++ break; ++ case 2: ++ HtCfg0.field.HTMCS2FBK = pNextTxRate->CurrMCS; ++ break; ++ case 3: ++ HtCfg0.field.HTMCS3FBK = pNextTxRate->CurrMCS; ++ break; ++ case 4: ++ HtCfg0.field.HTMCS4FBK = pNextTxRate->CurrMCS; ++ break; ++ case 5: ++ HtCfg0.field.HTMCS5FBK = pNextTxRate->CurrMCS; ++ break; ++ case 6: ++ HtCfg0.field.HTMCS6FBK = pNextTxRate->CurrMCS; ++ break; ++ case 7: ++ HtCfg0.field.HTMCS7FBK = pNextTxRate->CurrMCS; ++ break; ++ case 8: ++ HtCfg1.field.HTMCS8FBK = pNextTxRate->CurrMCS; ++ break; ++ case 9: ++ HtCfg1.field.HTMCS9FBK = pNextTxRate->CurrMCS; ++ break; ++ case 10: ++ HtCfg1.field.HTMCS10FBK = pNextTxRate->CurrMCS; ++ break; ++ case 11: ++ HtCfg1.field.HTMCS11FBK = pNextTxRate->CurrMCS; ++ break; ++ case 12: ++ HtCfg1.field.HTMCS12FBK = pNextTxRate->CurrMCS; ++ break; ++ case 13: ++ HtCfg1.field.HTMCS13FBK = pNextTxRate->CurrMCS; ++ break; ++ case 14: ++ HtCfg1.field.HTMCS14FBK = pNextTxRate->CurrMCS; ++ break; ++ case 15: ++ HtCfg1.field.HTMCS15FBK = pNextTxRate->CurrMCS; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicUpdateAutoFallBackTable: not support CurrMCS=%d\n", pCurrTxRate->CurrMCS)); ++ } ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ pNextTxRate = pCurrTxRate; ++ } ++ ++ RTMP_IO_WRITE32(pAd, HT_FBK_CFG0, HtCfg0.word); ++ RTMP_IO_WRITE32(pAd, HT_FBK_CFG1, HtCfg1.word); ++ RTMP_IO_WRITE32(pAd, LG_FBK_CFG0, LgCfg0.word); ++ RTMP_IO_WRITE32(pAd, LG_FBK_CFG1, LgCfg1.word); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set MAC register value according operation mode. ++ OperationMode AND bNonGFExist are for MM and GF Proteciton. ++ If MM or GF mask is not set, those passing argument doesn't not take effect. ++ ++ Operation mode meaning: ++ = 0 : Pure HT, no preotection. ++ = 0x01; there may be non-HT devices in both the control and extension channel, protection is optional in BSS. ++ = 0x10: No Transmission in 40M is protected. ++ = 0x11: Transmission in both 40M and 20M shall be protected ++ if (bNonGFExist) ++ we should choose not to use GF. But still set correct ASIC registers. ++ ======================================================================== ++*/ ++VOID AsicUpdateProtect( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT OperationMode, ++ IN UCHAR SetMask, ++ IN BOOLEAN bDisableBGProtect, ++ IN BOOLEAN bNonGFExist) ++{ ++ PROT_CFG_STRUC ProtCfg, ProtCfg4; ++ UINT32 Protect[6]; ++ USHORT offset; ++ UCHAR i; ++ UINT32 MacReg = 0; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++ if (!(pAd->CommonCfg.bHTProtect) && (OperationMode != 8)) ++ { ++ return; ++ } ++ ++ if (pAd->BATable.numAsOriginator) ++ { ++ // ++ // enable the RTS/CTS to avoid channel collision ++ // ++ SetMask = ALLN_SETPROTECT; ++ OperationMode = 8; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Config ASIC RTS threshold register ++ RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); ++ MacReg &= 0xFF0000FF; ++ ++ // If the user want disable RtsThreshold and enbale Amsdu/Ralink-Aggregation, set the RtsThreshold as 4096 ++ if (( ++#ifdef DOT11_N_SUPPORT ++ (pAd->CommonCfg.BACapability.field.AmsduEnable) || ++#endif // DOT11_N_SUPPORT // ++ (pAd->CommonCfg.bAggregationCapable == TRUE)) ++ && pAd->CommonCfg.RtsThreshold == MAX_RTS_THRESHOLD) ++ { ++ MacReg |= (0x1000 << 8); ++ } ++ else ++ { ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); ++ ++ // Initial common protection settings ++ RTMPZeroMemory(Protect, sizeof(Protect)); ++ ProtCfg4.word = 0; ++ ProtCfg.word = 0; ++ ProtCfg.field.TxopAllowGF40 = 1; ++ ProtCfg.field.TxopAllowGF20 = 1; ++ ProtCfg.field.TxopAllowMM40 = 1; ++ ProtCfg.field.TxopAllowMM20 = 1; ++ ProtCfg.field.TxopAllowOfdm = 1; ++ ProtCfg.field.TxopAllowCck = 1; ++ ProtCfg.field.RTSThEn = 1; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ++ // update PHY mode and rate ++ if (pAd->CommonCfg.Channel > 14) ++ ProtCfg.field.ProtectRate = 0x4000; ++ ProtCfg.field.ProtectRate |= pAd->CommonCfg.RtsRate; ++ ++ // Handle legacy(B/G) protection ++ if (bDisableBGProtect) ++ { ++ //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; ++ Protect[0] = ProtCfg.word; ++ Protect[1] = ProtCfg.word; ++ } ++ else ++ { ++ //ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; // CCK do not need to be protected ++ Protect[0] = ProtCfg.word; ++ ProtCfg.field.ProtectCtrl = ASIC_CTS; // OFDM needs using CCK to protect ++ Protect[1] = ProtCfg.word; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // Decide HT frame protection. ++ if ((SetMask & ALLN_SETPROTECT) != 0) ++ { ++ switch(OperationMode) ++ { ++ case 0x0: ++ // NO PROTECT ++ // 1.All STAs in the BSS are 20/40 MHz HT ++ // 2. in ai 20/40MHz BSS ++ // 3. all STAs are 20MHz in a 20MHz BSS ++ // Pure HT. no protection. ++ ++ // MM20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[2] = 0x01744004; ++ ++ // MM40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[3] = 0x03f44084; ++ ++ // CF20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[4] = 0x01744004; ++ ++ // CF40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[5] = 0x03f44084; ++ ++ if (bNonGFExist) ++ { ++ // PROT_NAV(19:18) -- 01 (Short NAV protectiion) ++ // PROT_CTRL(17:16) -- 01 (RTS/CTS) ++ Protect[4] = 0x01754004; ++ Protect[5] = 0x03f54084; ++ } ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ break; ++ ++ case 1: ++ // This is "HT non-member protection mode." ++ // If there may be non-HT STAs my BSS ++ ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) ++ ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. ++ ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083; ++ } ++ //Assign Protection method for 20&40 MHz packets ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ ++ case 2: ++ // If only HT STAs are in BSS. at least one is 20MHz. Only protect 40MHz packets ++ ProtCfg.word = 0x01744004; // PROT_CTRL(17:16) : 0 (None) ++ ProtCfg4.word = 0x03f44084; // duplicaet legacy 24M. BW set 1. ++ ++ //Assign Protection method for 40MHz packets ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ if (bNonGFExist) ++ { ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ } ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ break; ++ ++ case 3: ++ // HT mixed mode. PROTECT ALL! ++ // Assign Rate ++ ProtCfg.word = 0x01744004; //duplicaet legacy 24M. BW set 1. ++ ProtCfg4.word = 0x03f44084; ++ // both 20MHz and 40MHz are protected. Whether use RTS or CTS-to-self depends on the ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ ProtCfg.word = 0x01740003; //ERP use Protection bit is set, use protection rate at Clause 18.. ++ ProtCfg4.word = 0x03f40003; // Don't duplicate RTS/CTS in CCK mode. 0x03f40083 ++ } ++ //Assign Protection method for 20&40 MHz packets ++ ProtCfg.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ProtCfg4.field.ProtectCtrl = ASIC_RTS; ++ ProtCfg4.field.ProtectNav = ASIC_SHORTNAV; ++ Protect[2] = ProtCfg.word; ++ Protect[3] = ProtCfg4.word; ++ Protect[4] = ProtCfg.word; ++ Protect[5] = ProtCfg4.word; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ ++ case 8: ++ Protect[2] = 0x01754004; ++ Protect[3] = 0x03f54084; ++ Protect[4] = 0x01754004; ++ Protect[5] = 0x03f54084; ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = TRUE; ++ break; ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ offset = CCK_PROT_CFG; ++ for (i = 0;i < 6;i++) ++ { ++ if ((SetMask & (1<< i))) ++ { ++ RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); ++ } ++ } ++} ++ ++ ++#ifdef RT30xx ++/* ++ ======================================================================== ++ ++ Routine Description: Write RT30xx RF register through MAC ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RT30xxWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN UCHAR Value) ++{ ++ RF_CSR_CFG_STRUC rfcsr; ++ UINT i = 0; ++ ++ do ++ { ++ RTMP_IO_READ32(pAd, RF_CSR_CFG, &rfcsr.word); ++ ++ if (!rfcsr.field.RF_CSR_KICK) ++ break; ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ rfcsr.field.RF_CSR_WR = 1; ++ rfcsr.field.RF_CSR_KICK = 1; ++ rfcsr.field.TESTCSR_RFACC_REGNUM = RegID; ++ rfcsr.field.RF_CSR_DATA = Value; ++ ++ RTMP_IO_WRITE32(pAd, RF_CSR_CFG, rfcsr.word); ++ ++ return STATUS_SUCCESS; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Read RT30xx RF register through MAC ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RT30xxReadRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN PUCHAR pValue) ++{ ++ RF_CSR_CFG_STRUC rfcsr; ++ UINT i=0, k=0; ++ ++ for (i=0; iMACVersion & 0xffff) >= 0x0211) && (pAd->NicConfig2.field.ExternalLNAForG == 0)) ++ { ++ RFValue |= 0x20; ++ } ++ RT30xxWriteRFRegister(pAd, RF_R17, RFValue); ++ ++ // RX_LO1_en, RF R20 register Bit 3 to 0 ++ RT30xxReadRFRegister(pAd, RF_R20, &RFValue); ++ RFValue &= (~0x08); ++ RT30xxWriteRFRegister(pAd, RF_R20, RFValue); ++ ++ // RX_LO2_en, RF R21 register Bit 3 to 0 ++ RT30xxReadRFRegister(pAd, RF_R21, &RFValue); ++ RFValue &= (~0x08); ++ RT30xxWriteRFRegister(pAd, RF_R21, RFValue); ++ ++ // LDORF_VC, RF R27 register Bit 2 to 0 ++ RT30xxReadRFRegister(pAd, RF_R27, &RFValue); ++ if ((pAd->MACVersion & 0xffff) < 0x0211) ++ RFValue = (RFValue & (~0x77)) | 0x3; ++ else ++ RFValue = (RFValue & (~0x77)); ++ RT30xxWriteRFRegister(pAd, RF_R27, RFValue); ++ /* end johnli */ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Load RF sleep-mode setup ++ ++ ========================================================================== ++ */ ++VOID RT30xxLoadRFSleepModeSetup( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR RFValue; ++ UINT32 MACValue; ++ ++ // RF_BLOCK_en. RF R1 register Bit 0 to 0 ++ RT30xxReadRFRegister(pAd, RF_R01, &RFValue); ++ RFValue &= (~0x01); ++ RT30xxWriteRFRegister(pAd, RF_R01, RFValue); ++ ++ // VCO_IC, RF R7 register Bit 4 & Bit 5 to 0 ++ RT30xxReadRFRegister(pAd, RF_R07, &RFValue); ++ RFValue &= (~0x30); ++ RT30xxWriteRFRegister(pAd, RF_R07, RFValue); ++ ++ // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 0 ++ RT30xxReadRFRegister(pAd, RF_R09, &RFValue); ++ RFValue &= (~0x0E); ++ RT30xxWriteRFRegister(pAd, RF_R09, RFValue); ++ ++ // RX_CTB_en, RF R21 register Bit 7 to 0 ++ RT30xxReadRFRegister(pAd, RF_R21, &RFValue); ++ RFValue &= (~0x80); ++ RT30xxWriteRFRegister(pAd, RF_R21, RFValue); ++ ++ // LDORF_VC, RF R27 register Bit 0, Bit 1 & Bit 2 to 1 ++ RT30xxReadRFRegister(pAd, RF_R27, &RFValue); ++ RFValue |= 0x77; ++ RT30xxWriteRFRegister(pAd, RF_R27, RFValue); ++ ++ RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); ++ MACValue |= 0x1D000000; ++ RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Reverse RF sleep-mode setup ++ ++ ========================================================================== ++ */ ++VOID RT30xxReverseRFSleepModeSetup( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR RFValue; ++ UINT32 MACValue; ++ ++ // RF_BLOCK_en, RF R1 register Bit 0 to 1 ++ RT30xxReadRFRegister(pAd, RF_R01, &RFValue); ++ RFValue |= 0x01; ++ RT30xxWriteRFRegister(pAd, RF_R01, RFValue); ++ ++ // VCO_IC, RF R7 register Bit 4 & Bit 5 to 1 ++ RT30xxReadRFRegister(pAd, RF_R07, &RFValue); ++ RFValue |= 0x30; ++ RT30xxWriteRFRegister(pAd, RF_R07, RFValue); ++ ++ // Idoh, RF R9 register Bit 1, Bit 2 & Bit 3 to 1 ++ RT30xxReadRFRegister(pAd, RF_R09, &RFValue); ++ RFValue |= 0x0E; ++ RT30xxWriteRFRegister(pAd, RF_R09, RFValue); ++ ++ // RX_CTB_en, RF R21 register Bit 7 to 1 ++ RT30xxReadRFRegister(pAd, RF_R21, &RFValue); ++ RFValue |= 0x80; ++ RT30xxWriteRFRegister(pAd, RF_R21, RFValue); ++ ++ // LDORF_VC, RF R27 register Bit 2 to 0 ++ RT30xxReadRFRegister(pAd, RF_R27, &RFValue); ++ if ((pAd->MACVersion & 0xffff) < 0x0211) ++ RFValue = (RFValue & (~0x77)) | 0x3; ++ else ++ RFValue = (RFValue & (~0x77)); ++ RT30xxWriteRFRegister(pAd, RF_R27, RFValue); ++ ++ // RT3071 version E has fixed this issue ++ if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211)) ++ { ++ // patch tx EVM issue temporarily ++ RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); ++ MACValue = ((MACValue & 0xE0FFFFFF) | 0x0D000000); ++ RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); ++ } ++ else ++ { ++ RTMP_IO_READ32(pAd, LDO_CFG0, &MACValue); ++ MACValue = ((MACValue & 0xE0FFFFFF) | 0x01000000); ++ RTMP_IO_WRITE32(pAd, LDO_CFG0, MACValue); ++ } ++} ++// end johnli ++#endif // RT30xx // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN BOOLEAN bScan) ++{ ++ ULONG R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0; ++ CHAR TxPwer = 0, TxPwer2 = DEFAULT_RF_TX_POWER; //Bbp94 = BBPR94_DEFAULT, TxPwer2 = DEFAULT_RF_TX_POWER; ++ UCHAR index; ++ UINT32 Value = 0; //BbpReg, Value; ++ RTMP_RF_REGS *RFRegTable; ++ ++ // Search Tx power value ++#if 1 ++ // We can't use ChannelList to search channel, since some central channl's txpowr doesn't list ++ // in ChannelList, so use TxPower array instead. ++ // ++ for (index = 0; index < MAX_NUM_OF_CHANNELS; index++) ++ { ++ if (Channel == pAd->TxPower[index].Channel) ++ { ++ TxPwer = pAd->TxPower[index].Power; ++ TxPwer2 = pAd->TxPower[index].Power2; ++ break; ++ } ++ } ++#else ++ for (index = 0; index < pAd->ChannelListNum; index++) ++ { ++ if (Channel == pAd->ChannelList[index].Channel) ++ { ++ TxPwer = pAd->ChannelList[index].Power; ++ TxPwer2 = pAd->ChannelList[index].Power2; ++ break; ++ } ++ } ++#endif ++ ++ if (index == MAX_NUM_OF_CHANNELS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: Can't find the Channel#%d \n", Channel)); ++ } ++ ++#ifdef RT30xx ++ // The RF programming sequence is difference between 3xxx and 2xxx ++ if ((IS_RT3070(pAd) || IS_RT3090(pAd)) && ((pAd->RfIcType == RFIC_3020) || (pAd->RfIcType == RFIC_2020) || ++ (pAd->RfIcType == RFIC_3021) || (pAd->RfIcType == RFIC_3022))) ++ { ++ /* modify by WY for Read RF Reg. error */ ++ UCHAR RFValue; ++ ++ for (index = 0; index < NUM_OF_3020_CHNL; index++) ++ { ++ if (Channel == FreqItems3020[index].Channel) ++ { ++ // Programming channel parameters ++ RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); ++ RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); ++ RT30xxReadRFRegister(pAd, RF_R06, &RFValue); ++ RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; ++ RT30xxWriteRFRegister(pAd, RF_R06, RFValue); ++ ++ // Set Tx0 Power ++ RT30xxReadRFRegister(pAd, RF_R12, &RFValue); ++ RFValue = (RFValue & 0xE0) | TxPwer; ++ RT30xxWriteRFRegister(pAd, RF_R12, RFValue); ++ ++ // Set Tx1 Power ++ RT30xxReadRFRegister(pAd, RF_R13, &RFValue); ++ RFValue = (RFValue & 0xE0) | TxPwer2; ++ RT30xxWriteRFRegister(pAd, RF_R13, RFValue); ++ ++ // Tx/Rx Stream setting ++ RT30xxReadRFRegister(pAd, RF_R01, &RFValue); ++ //if (IS_RT3090(pAd)) ++ // RFValue |= 0x01; // Enable RF block. ++ RFValue &= 0x03; //clear bit[7~2] ++ if (pAd->Antenna.field.TxPath == 1) ++ RFValue |= 0xA0; ++ else if (pAd->Antenna.field.TxPath == 2) ++ RFValue |= 0x80; ++ if (pAd->Antenna.field.RxPath == 1) ++ RFValue |= 0x50; ++ else if (pAd->Antenna.field.RxPath == 2) ++ RFValue |= 0x40; ++ RT30xxWriteRFRegister(pAd, RF_R01, RFValue); ++ ++ // Set RF offset ++ RT30xxReadRFRegister(pAd, RF_R23, &RFValue); ++ RFValue = (RFValue & 0x80) | pAd->RfFreqOffset; ++ RT30xxWriteRFRegister(pAd, RF_R23, RFValue); ++ ++ // Set BW ++ if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) ++ { ++ RFValue = pAd->Mlme.CaliBW40RfR24; ++ //DISABLE_11N_CHECK(pAd); ++ } ++ else ++ { ++ RFValue = pAd->Mlme.CaliBW20RfR24; ++ } ++ RT30xxWriteRFRegister(pAd, RF_R24, RFValue); ++ RT30xxWriteRFRegister(pAd, RF_R31, RFValue); ++ ++ // Enable RF tuning ++ RT30xxReadRFRegister(pAd, RF_R07, &RFValue); ++ RFValue = RFValue | 0x1; ++ RT30xxWriteRFRegister(pAd, RF_R07, RFValue); ++ ++ // latch channel for future usage. ++ pAd->LatchRfRegs.Channel = Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", ++ Channel, ++ pAd->RfIcType, ++ TxPwer, ++ TxPwer2, ++ pAd->Antenna.field.TxPath, ++ FreqItems3020[index].N, ++ FreqItems3020[index].K, ++ FreqItems3020[index].R)); ++ ++ break; ++ } ++ } ++ } ++ else ++#endif // RT30xx // ++ ++ { ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ R2 |= 0x40; // write 1 to off Rxpath. ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ ++ if (Channel > 14) ++ { ++ // initialize R3, R4 ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff); ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15); ++ ++ // 5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB ++ // R3 ++ if ((TxPwer >= -7) && (TxPwer < 0)) ++ { ++ TxPwer = (7+TxPwer); ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10); ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer=%d \n", TxPwer)); ++ } ++ else ++ { ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10) | (1 << 9); ++ } ++ ++ // R4 ++ if ((TxPwer2 >= -7) && (TxPwer2 < 0)) ++ { ++ TxPwer2 = (7+TxPwer2); ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7); ++ DBGPRINT(RT_DEBUG_ERROR, ("AsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); ++ } ++ else ++ { ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7) | (1 << 6); ++ } ++ } ++ else ++ { ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->RfFreqOffset << 15) | (TxPwer2 <<6);// Set freq Offset & TxPwr1 ++ } ++ ++ // Based on BBP current mode before changing RF channel. ++ if (!bScan && (pAd->CommonCfg.BBPCurrentBW == BW_40)) ++ { ++ R4 |=0x200000; ++ } ++ ++ // Update variables ++ pAd->LatchRfRegs.Channel = Channel; ++ pAd->LatchRfRegs.R1 = RFRegTable[index].R1; ++ pAd->LatchRfRegs.R2 = R2; ++ pAd->LatchRfRegs.R3 = R3; ++ pAd->LatchRfRegs.R4 = R4; ++ ++ // Set RF value 1's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 2's set R3[bit2] = [1] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 3's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ // Change BBP setting during siwtch from a->g, g->a ++ if (Channel <= 14) ++ { ++ ULONG TxPinCfg = 0x00050F0A;//Gary 2007/08/09 0x050A0A ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ ++ // Rx High power VGA offset for LNA select ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); ++ } ++ ++ // 5G band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x04); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ else ++ { ++ ULONG TxPinCfg = 0x00050F05;//Gary 2007/8/9 0x050505 ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0);//(0x44 - GET_LNA_GAIN(pAd))); // According the Rory's suggestion to solve the middle range issue. ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); ++ ++ // Rx High power VGA offset for LNA select ++ if (pAd->NicConfig2.field.ExternalLNAForA) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x46); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R75, 0x50); ++ } ++ ++ // 5G band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x02); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ ++ // R66 should be set according to Channel and use 20MHz when scanning ++ //RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, (0x2E + GET_LNA_GAIN(pAd))); ++ if (bScan) ++ RTMPSetAGCInitValue(pAd, BW_20); ++ else ++ RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); ++ ++ // ++ // On 11A, We should delay and wait RF/BBP to be stable ++ // and the appropriate time should be 1000 micro seconds ++ // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. ++ // ++ RTMPusecDelay(1000); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%lu, Pwr1=%lu, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ (R3 & 0x00003e00) >> 9, ++ (R4 & 0x000007c0) >> 6, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This function is required for 2421 only, and should not be used during ++ site survey. It's only required after NIC decided to stay at a channel ++ for a longer period. ++ When this function is called, it's always after AsicSwitchChannel(). ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicLockChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicAntennaSelect( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ if (pAd->Mlme.OneSecPeriodicRound % 2 == 1) ++ { ++ // patch for AsicSetRxAnt failed ++ pAd->RxAnt.EvaluatePeriod = 0; ++ ++ // check every 2 second. If rcv-beacon less than 5 in the past 2 second, then AvgRSSI is no longer a ++ // valid indication of the distance between this AP and its clients. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ SHORT realavgrssi1; ++ ++ // if no traffic then reset average rssi to trigger evaluation ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->StaCfg.NumOfAvgRssiSample < 5) ++ { ++ pAd->RxAnt.Pair1LastAvgRssi = (-99); ++ pAd->RxAnt.Pair2LastAvgRssi = (-99); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no traffic/beacon, reset RSSI\n")); ++ } ++ ++ pAd->StaCfg.NumOfAvgRssiSample = 0; ++#endif // CONFIG_STA_SUPPORT // ++ realavgrssi1 = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt] >> 3); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Ant-realrssi0(%d), Lastrssi0(%d), EvaluateStableCnt=%d\n", realavgrssi1, pAd->RxAnt.Pair1LastAvgRssi, pAd->RxAnt.EvaluateStableCnt)); ++ ++ // if the difference between two rssi is larger or less than 5, then evaluate the other antenna ++ if ((pAd->RxAnt.EvaluateStableCnt < 2) || (realavgrssi1 > (pAd->RxAnt.Pair1LastAvgRssi + 5)) || (realavgrssi1 < (pAd->RxAnt.Pair1LastAvgRssi - 5))) ++ { ++ pAd->RxAnt.Pair1LastAvgRssi = realavgrssi1; ++ AsicEvaluateRxAnt(pAd); ++ } ++ } ++ else ++ { ++ // if not connected, always switch antenna to try to connect ++ UCHAR temp; ++ ++ temp = pAd->RxAnt.Pair1PrimaryRxAnt; ++ pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; ++ pAd->RxAnt.Pair1SecondaryRxAnt = temp; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmePeriodicExec: no connect, switch to another one to try connection\n")); ++ ++ AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Antenna miscellaneous setting. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ BandState Indicate current Band State. ++ ++ Return Value: ++ None ++ ++ IRQL <= DISPATCH_LEVEL ++ ++ Note: ++ 1.) Frame End type control ++ only valid for G only (RF_2527 & RF_2529) ++ 0: means DPDT, set BBP R4 bit 5 to 1 ++ 1: means SPDT, set BBP R4 bit 5 to 0 ++ ++ ++ ======================================================================== ++*/ ++VOID AsicAntennaSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN ABGBAND_STATE BandState) ++{ ++} ++ ++VOID AsicRfTuningExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Gives CCK TX rate 2 more dB TX power. ++ This routine works only in LINK UP in INFRASTRUCTURE mode. ++ ++ calculate desired Tx power in RF R3.Tx0~5, should consider - ++ 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) ++ 1. TxPowerPercentage ++ 2. auto calibration based on TSSI feedback ++ 3. extra 2 db for CCK ++ 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP ++ ++ NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), ++ it should be called AFTER MlmeDynamicTxRatSwitching() ++ ========================================================================== ++ */ ++VOID AsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i, j; ++ CHAR DeltaPwr = 0; ++ BOOLEAN bAutoTxAgc = FALSE; ++ UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; ++ UCHAR BbpR1 = 0, BbpR49 = 0, idx; ++ PCHAR pTxAgcCompensate; ++ ULONG TxPwr[5]; ++ CHAR Value; ++ ++ ++ ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ if (pAd->CommonCfg.CentralChannel > 14) ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; ++ } ++ } ++ ++ // TX power compensation for temperature variation based on TSSI. try every 4 second ++ if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) ++ { ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ /* bg channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ TssiRef = pAd->TssiRefG; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; ++ TxAgcStep = pAd->TxAgcStepG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ /* a channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ TssiRef = pAd->TssiRefA; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; ++ TxAgcStep = pAd->TxAgcStepA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ { ++ /* BbpR1 is unsigned char */ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); ++ ++ /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ ++ /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ ++ /* step value is defined in pAd->TxAgcStepG for tx power value */ ++ ++ /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ ++ /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ above value are examined in mass factory production */ ++ /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ ++ ++ /* plus (+) is 0x00 ~ 0x45, minus (-) is 0xa0 ~ 0xf0 */ ++ /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ ++ /* if value is 0xa5, tx power will be -= TxAgcStep*(2-1) */ ++ ++ if (BbpR49 > pTssiMinusBoundary[1]) ++ { ++ // Reading is larger than the reference value ++ // check for how large we need to decrease the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should decrease, idx = 0 means there is nothing to compensate ++// if (R3 > (ULONG) (TxAgcStep * (idx-1))) ++ *pTxAgcCompensate = -(TxAgcStep * (idx-1)); ++// else ++// *pTxAgcCompensate = -((UCHAR)R3); ++ ++ DeltaPwr += (*pTxAgcCompensate); ++ DBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else if (BbpR49 < pTssiPlusBoundary[1]) ++ { ++ // Reading is smaller than the reference value ++ // check for how large we need to increase the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should increase, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = TxAgcStep * (idx-1); ++ DeltaPwr += (*pTxAgcCompensate); ++ DBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else ++ { ++ *pTxAgcCompensate = 0; ++ DBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R49=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, 0)); ++ } ++ } ++ } ++ else ++ { ++ if (pAd->CommonCfg.Channel <= 14) ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ DeltaPwr += (*pTxAgcCompensate); ++ } ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpR1); ++ BbpR1 &= 0xFC; ++ ++#ifdef SINGLE_SKU ++ // Handle regulatory max tx power constrain ++ do ++ { ++ UCHAR TxPwrInEEPROM = 0xFF, CountryTxPwr = 0xFF, criterion; ++ UCHAR AdjustMaxTxPwr[40]; ++ ++ if (pAd->CommonCfg.Channel > 14) // 5G band ++ TxPwrInEEPROM = ((pAd->CommonCfg.DefineMaxTxPwr & 0xFF00) >> 8); ++ else // 2.4G band ++ TxPwrInEEPROM = (pAd->CommonCfg.DefineMaxTxPwr & 0x00FF); ++ CountryTxPwr = GetCuntryMaxTxPwr(pAd, pAd->CommonCfg.Channel); ++ ++ // error handling, range check ++ if ((TxPwrInEEPROM > 0x50) || (CountryTxPwr > 0x50)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("AsicAdjustTxPower - Invalid max tx power (=0x%02x), CountryTxPwr=%d\n", TxPwrInEEPROM, CountryTxPwr)); ++ break; ++ } ++ ++ criterion = *((PUCHAR)TxPwr + 2) & 0xF; // FAE use OFDM 6M as criterion ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (criterion=%d, TxPwrInEEPROM=%d, CountryTxPwr=%d)\n", criterion, TxPwrInEEPROM, CountryTxPwr)); ++ ++ // Adjust max tx power according to the relationship of tx power in E2PROM ++ for (i=0; i<5; i++) ++ { ++ // CCK will have 4dBm larger than OFDM ++ // Therefore, we should separate to parse the tx power field ++ if (i == 0) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ if (j < 4) ++ { ++ // CCK will have 4dBm larger than OFDM ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion) + 4; ++ } ++ else ++ { ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ } ++ else ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ AdjustMaxTxPwr[i*8+j] = TxPwrInEEPROM + (Value - criterion); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ } ++ } ++ ++ // Adjust tx power according to the relationship ++ for (i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); ++ ++ // The system tx power is larger than the regulatory, the power should be restrain ++ if (AdjustMaxTxPwr[i*8+j] > CountryTxPwr) ++ { ++ // decrease to zero and don't need to take care BBPR1 ++ if ((Value - (AdjustMaxTxPwr[i*8+j] - CountryTxPwr)) > 0) ++ Value -= (AdjustMaxTxPwr[i*8+j] - CountryTxPwr); ++ else ++ Value = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ } ++ else ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("AsicAdjustTxPower (i/j=%d/%d, Value=%d, %d, no change)\n", i, j, Value, AdjustMaxTxPwr[i*8+j])); ++ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ } ++ } ++ } while (FALSE); ++#endif // SINGLE_SKU // ++ ++ /* calculate delta power based on the percentage specified from UI */ ++ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) ++ // We lower TX power here according to the percentage specified from UI ++ if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW // DeltaPwr -= 1; ++ { ++ DeltaPwr -= 1; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW // DeltaPwr -= 3; ++ { ++ DeltaPwr -= 3; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW // DeltaPwr -= 6; ++ { ++ BbpR1 |= 0x01; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW // DeltaPwr -= 9; ++ { ++ BbpR1 |= 0x01; ++ DeltaPwr -= 3; ++ } ++ else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW // DeltaPwr -= 12; ++ { ++ BbpR1 |= 0x02; ++ } ++ ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpR1); ++ ++ /* reset different new tx power for different TX rate */ ++ for(i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ ++ ++ if ((Value + DeltaPwr) < 0) ++ { ++ Value = 0; /* min */ ++ } ++ else if ((Value + DeltaPwr) > 0xF) ++ { ++ Value = 0xF; /* max */ ++ } ++ else ++ { ++ Value += DeltaPwr; /* temperature compensation */ ++ } ++ ++ /* fill new value to CSR offset */ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ ++ /* write tx power value to CSR */ ++ /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M ++ TX power for OFDM 6M/9M ++ TX power for CCK5.5M/11M ++ TX power for CCK1M/2M */ ++ /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); ++ } ++ } ++ ++ ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ put PHY to sleep here, and set next wakeup timer. PHY doesn't not wakeup ++ automatically. Instead, MCU will issue a TwakeUpInterrupt to host after ++ the wakeup timer timeout. Driver has to issue a separate command to wake ++ PHY up. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp) ++{ ++ RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ AsicForceWakeup() is used whenever manual wakeup is required ++ AsicForceSleep() should only be used when not in INFRA BSS. When ++ in INFRA BSS, we should use AsicSleepThenAutoWakeup() instead. ++ ========================================================================== ++ */ ++VOID AsicForceSleep( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ AsicForceWakeup() is used whenever Twakeup timer (set via AsicSleepThenAutoWakeup) ++ expired. ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ========================================================================== ++ */ ++VOID AsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); ++ RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); ++} ++#endif // CONFIG_STA_SUPPORT // ++/* ++ ========================================================================== ++ Description: ++ Set My BSSID ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetBssid( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid) ++{ ++ ULONG Addr4; ++ DBGPRINT(RT_DEBUG_TRACE, ("==============> AsicSetBssid %x:%x:%x:%x:%x:%x\n", ++ pBssid[0],pBssid[1],pBssid[2],pBssid[3], pBssid[4],pBssid[5])); ++ ++ Addr4 = (ULONG)(pBssid[0]) | ++ (ULONG)(pBssid[1] << 8) | ++ (ULONG)(pBssid[2] << 16) | ++ (ULONG)(pBssid[3] << 24); ++ RTMP_IO_WRITE32(pAd, MAC_BSSID_DW0, Addr4); ++ ++ Addr4 = 0; ++ // always one BSSID in STA mode ++ Addr4 = (ULONG)(pBssid[4]) | (ULONG)(pBssid[5] << 8); ++ ++ RTMP_IO_WRITE32(pAd, MAC_BSSID_DW1, Addr4); ++} ++ ++VOID AsicSetMcastWC( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[MCAST_WCID]; ++ USHORT offset; ++ ++ pEntry->Sst = SST_ASSOC; ++ pEntry->Aid = MCAST_WCID; // Softap supports 1 BSSID and use WCID=0 as multicast Wcid index ++ pEntry->PsMode = PWR_ACTIVE; ++ pEntry->CurrTxRate = pAd->CommonCfg.MlmeRate; ++ offset = MAC_WCID_BASE + BSS0Mcast_WCID * HW_WCID_ENTRY_SIZE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDelWcidTab( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid) ++{ ++ ULONG Addr0 = 0x0, Addr1 = 0x0; ++ ULONG offset; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicDelWcidTab==>Wcid = 0x%x\n",Wcid)); ++ offset = MAC_WCID_BASE + Wcid * HW_WCID_ENTRY_SIZE; ++ RTMP_IO_WRITE32(pAd, offset, Addr0); ++ offset += 4; ++ RTMP_IO_WRITE32(pAd, offset, Addr1); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableRDG( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ UINT32 Data = 0; ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ TxLinkCfg.field.TxRDGEn = 1; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++ ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ Data |= 0x80; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDisableRDG( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ UINT32 Data = 0; ++ ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ TxLinkCfg.field.TxRDGEn = 0; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++ ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ ++ Data &= 0xFFFFFF00; ++ //Data |= 0x20; ++#ifndef WIFI_TEST ++ //if ( pAd->CommonCfg.bEnableTxBurst ) ++ // Data |= 0x60; // for performance issue not set the TXOP to 0 ++#endif ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE) ++#ifdef DOT11_N_SUPPORT ++ && (pAd->MacTab.fAnyStationMIMOPSDynamic == FALSE) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode ++ if (pAd->CommonCfg.bEnableTxBurst) ++ Data |= 0x20; ++ } ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicDisableSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->Disable TSF synchronization\n")); ++ ++ // 2003-12-20 disable TSF and TBTT while NIC in power-saving have side effect ++ // that NIC will never wakes up because TSF stops and no more ++ // TBTT interrupts ++ pAd->TbttTickCount = 0; ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ csr.field.bTsfTicking = 0; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableBssSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableBssSync(INFRA mode)\n")); ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr.word); ++// RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, 0x00000000); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ csr.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU ++ csr.field.bTsfTicking = 1; ++ csr.field.TsfSyncMode = 1; // sync TSF in INFRASTRUCTURE mode ++ csr.field.bBeaconGen = 0; // do NOT generate BEACON ++ csr.field.bTBTTEnable = 1; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Note: ++ BEACON frame in shared memory should be built ok before this routine ++ can be called. Otherwise, a garbage frame maybe transmitted out every ++ Beacon period. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicEnableIbssSync( ++ IN PRTMP_ADAPTER pAd) ++{ ++ BCN_TIME_CFG_STRUC csr9; ++ PUCHAR ptr; ++ UINT i; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->AsicEnableIbssSync(ADHOC mode. MPDUtotalByteCount = %d)\n", pAd->BeaconTxWI.MPDUtotalByteCount)); ++ ++ RTMP_IO_READ32(pAd, BCN_TIME_CFG, &csr9.word); ++ csr9.field.bBeaconGen = 0; ++ csr9.field.bTBTTEnable = 0; ++ csr9.field.bTsfTicking = 0; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); ++ ++ ++#ifdef RT2870 ++ // move BEACON TXD and frame content to on-chip memory ++ ptr = (PUCHAR)&pAd->BeaconTxWI; ++ for (i=0; iBeaconBuf; ++ for (i=0; i< pAd->BeaconTxWI.MPDUtotalByteCount; i+=2) ++ { ++ //UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24); ++ //RTMP_IO_WRITE32(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, longptr); ++ RTUSBMultiWrite(pAd, HW_BEACON_BASE0 + TXWI_SIZE + i, ptr, 2); ++ ptr +=2; ++ } ++#endif // RT2870 // ++ ++ // ++ // For Wi-Fi faily generated beacons between participating stations. ++ // Set TBTT phase adaptive adjustment step to 8us (default 16us) ++ // don't change settings 2006-5- by Jerry ++ //RTMP_IO_WRITE32(pAd, TBTT_SYNC_CFG, 0x00001010); ++ ++ // start sending BEACON ++ csr9.field.BeaconInterval = pAd->CommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU ++ csr9.field.bTsfTicking = 1; ++ csr9.field.TsfSyncMode = 2; // sync TSF in IBSS mode ++ csr9.field.bTBTTEnable = 1; ++ csr9.field.bBeaconGen = 1; ++ RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetEdcaParm( ++ IN PRTMP_ADAPTER pAd, ++ IN PEDCA_PARM pEdcaParm) ++{ ++ EDCA_AC_CFG_STRUC Ac0Cfg, Ac1Cfg, Ac2Cfg, Ac3Cfg; ++ AC_TXOP_CSR0_STRUC csr0; ++ AC_TXOP_CSR1_STRUC csr1; ++ AIFSN_CSR_STRUC AifsnCsr; ++ CWMIN_CSR_STRUC CwminCsr; ++ CWMAX_CSR_STRUC CwmaxCsr; ++ int i; ++ ++ Ac0Cfg.word = 0; ++ Ac1Cfg.word = 0; ++ Ac2Cfg.word = 0; ++ Ac3Cfg.word = 0; ++ if ((pEdcaParm == NULL) || (pEdcaParm->bValid == FALSE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AsicSetEdcaParm\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WMM_INUSED); ++ for (i=0; iMacTab.Content[i].ValidAsCLI || pAd->MacTab.Content[i].ValidAsApCli) ++ CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[i], fCLIENT_STATUS_WMM_CAPABLE); ++ } ++ ++ //======================================================== ++ // MAC Register has a copy . ++ //======================================================== ++//#ifndef WIFI_TEST ++ if( pAd->CommonCfg.bEnableTxBurst ) ++ { ++ // For CWC test, change txop from 0x30 to 0x20 in TxBurst mode ++ Ac0Cfg.field.AcTxop = 0x20; // Suggest by John for TxBurst in HT Mode ++ } ++ else ++ Ac0Cfg.field.AcTxop = 0; // QID_AC_BE ++//#else ++// Ac0Cfg.field.AcTxop = 0; // QID_AC_BE ++//#endif ++ Ac0Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac0Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac0Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); ++ ++ Ac1Cfg.field.AcTxop = 0; // QID_AC_BK ++ Ac1Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac1Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac1Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); ++ ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ Ac2Cfg.field.AcTxop = 192; // AC_VI: 192*32us ~= 6ms ++ Ac3Cfg.field.AcTxop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ Ac2Cfg.field.AcTxop = 96; // AC_VI: 96*32us ~= 3ms ++ Ac3Cfg.field.AcTxop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ Ac2Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac2Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac2Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); ++ Ac3Cfg.field.Cwmin = CW_MIN_IN_BITS; ++ Ac3Cfg.field.Cwmax = CW_MAX_IN_BITS; ++ Ac3Cfg.field.Aifsn = 2; ++ RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); ++ ++ //======================================================== ++ // DMA Register has a copy too. ++ //======================================================== ++ csr0.field.Ac0Txop = 0; // QID_AC_BE ++ csr0.field.Ac1Txop = 0; // QID_AC_BK ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ csr1.field.Ac2Txop = 192; // AC_VI: 192*32us ~= 6ms ++ csr1.field.Ac3Txop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ csr1.field.Ac2Txop = 96; // AC_VI: 96*32us ~= 3ms ++ csr1.field.Ac3Txop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); ++ ++ CwminCsr.word = 0; ++ CwminCsr.field.Cwmin0 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin1 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin2 = CW_MIN_IN_BITS; ++ CwminCsr.field.Cwmin3 = CW_MIN_IN_BITS; ++ RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); ++ ++ CwmaxCsr.word = 0; ++ CwmaxCsr.field.Cwmax0 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax1 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax2 = CW_MAX_IN_BITS; ++ CwmaxCsr.field.Cwmax3 = CW_MAX_IN_BITS; ++ RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); ++ ++ RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, 0x00002222); ++ ++ NdisZeroMemory(&pAd->CommonCfg.APEdcaParm, sizeof(EDCA_PARM)); ++ } ++ else ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WMM_INUSED); ++ //======================================================== ++ // MAC Register has a copy. ++ //======================================================== ++ // ++ // Modify Cwmin/Cwmax/Txop on queue[QID_AC_VI], Recommend by Jerry 2005/07/27 ++ // To degrade our VIDO Queue's throughput for WiFi WMM S3T07 Issue. ++ // ++ //pEdcaParm->Txop[QID_AC_VI] = pEdcaParm->Txop[QID_AC_VI] * 7 / 10; // rt2860c need this ++ ++ Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE]; ++ Ac0Cfg.field.Cwmin= pEdcaParm->Cwmin[QID_AC_BE]; ++ Ac0Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BE]; ++ Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]; //+1; ++ ++ Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; ++ Ac1Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_BK]; //+2; ++ Ac1Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_BK]; ++ Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; //+1; ++ ++ Ac2Cfg.field.AcTxop = (pEdcaParm->Txop[QID_AC_VI] * 6) / 10; ++ Ac2Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VI]; ++ Ac2Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VI]; ++ Ac2Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VI]; ++#ifdef INF_AMAZON_SE ++#endif // INF_AMAZON_SE // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Tuning for Wi-Fi WMM S06 ++ if (pAd->CommonCfg.bWiFiTest && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ Ac2Cfg.field.Aifsn -= 1; ++ ++ // Tuning for TGn Wi-Fi 5.2.32 ++ // STA TestBed changes in this item: conexant legacy sta ==> broadcom 11n sta ++ if (STA_TGN_WIFI_ON(pAd) && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ { ++ Ac0Cfg.field.Aifsn = 3; ++ Ac2Cfg.field.AcTxop = 5; ++ } ++ ++#ifdef RT30xx ++ if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) ++ { ++ // Tuning for WiFi WMM S3-T07: connexant legacy sta ==> broadcom 11n sta. ++ Ac2Cfg.field.Aifsn = 5; ++ } ++#endif // RT30xx // ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ Ac3Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VO]; ++ Ac3Cfg.field.Cwmin = pEdcaParm->Cwmin[QID_AC_VO]; ++ Ac3Cfg.field.Cwmax = pEdcaParm->Cwmax[QID_AC_VO]; ++ Ac3Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_VO]; ++ ++//#ifdef WIFI_TEST ++ if (pAd->CommonCfg.bWiFiTest) ++ { ++ if (Ac3Cfg.field.AcTxop == 102) ++ { ++ Ac0Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BE] ? pEdcaParm->Txop[QID_AC_BE] : 10; ++ Ac0Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BE]-1; /* AIFSN must >= 1 */ ++ Ac1Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_BK]; ++ Ac1Cfg.field.Aifsn = pEdcaParm->Aifsn[QID_AC_BK]; ++ Ac2Cfg.field.AcTxop = pEdcaParm->Txop[QID_AC_VI]; ++ } /* End of if */ ++ } ++//#endif // WIFI_TEST // ++ ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Ac0Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC1_CFG, Ac1Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC2_CFG, Ac2Cfg.word); ++ RTMP_IO_WRITE32(pAd, EDCA_AC3_CFG, Ac3Cfg.word); ++ ++ ++ //======================================================== ++ // DMA Register has a copy too. ++ //======================================================== ++ csr0.field.Ac0Txop = Ac0Cfg.field.AcTxop; ++ csr0.field.Ac1Txop = Ac1Cfg.field.AcTxop; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ ++ csr1.field.Ac2Txop = Ac2Cfg.field.AcTxop; ++ csr1.field.Ac3Txop = Ac3Cfg.field.AcTxop; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr1.word); ++ ++ CwminCsr.word = 0; ++ CwminCsr.field.Cwmin0 = pEdcaParm->Cwmin[QID_AC_BE]; ++ CwminCsr.field.Cwmin1 = pEdcaParm->Cwmin[QID_AC_BK]; ++ CwminCsr.field.Cwmin2 = pEdcaParm->Cwmin[QID_AC_VI]; ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ CwminCsr.field.Cwmin3 = pEdcaParm->Cwmin[QID_AC_VO] - 1; //for TGn wifi test ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, WMM_CWMIN_CFG, CwminCsr.word); ++ ++ CwmaxCsr.word = 0; ++ CwmaxCsr.field.Cwmax0 = pEdcaParm->Cwmax[QID_AC_BE]; ++ CwmaxCsr.field.Cwmax1 = pEdcaParm->Cwmax[QID_AC_BK]; ++ CwmaxCsr.field.Cwmax2 = pEdcaParm->Cwmax[QID_AC_VI]; ++ CwmaxCsr.field.Cwmax3 = pEdcaParm->Cwmax[QID_AC_VO]; ++ RTMP_IO_WRITE32(pAd, WMM_CWMAX_CFG, CwmaxCsr.word); ++ ++ AifsnCsr.word = 0; ++ AifsnCsr.field.Aifsn0 = Ac0Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BE]; ++ AifsnCsr.field.Aifsn1 = Ac1Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_BK]; ++ AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn; //pEdcaParm->Aifsn[QID_AC_VI]; ++#ifdef INF_AMAZON_SE ++#endif // INF_AMAZON_SE // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Tuning for Wi-Fi WMM S06 ++ if (pAd->CommonCfg.bWiFiTest && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ AifsnCsr.field.Aifsn2 = Ac2Cfg.field.Aifsn - 4; ++ ++ // Tuning for TGn Wi-Fi 5.2.32 ++ // STA TestBed changes in this item: connexant legacy sta ==> broadcom 11n sta ++ if (STA_TGN_WIFI_ON(pAd) && ++ pEdcaParm->Aifsn[QID_AC_VI] == 10) ++ { ++ AifsnCsr.field.Aifsn0 = 3; ++ AifsnCsr.field.Aifsn2 = 7; ++ } ++ ++ if (INFRA_ON(pAd)) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_WMM_CAPABLE); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AifsnCsr.field.Aifsn3 = Ac3Cfg.field.Aifsn - 1; //pEdcaParm->Aifsn[QID_AC_VO]; //for TGn wifi test ++#ifdef RT30xx ++ if (pAd->RfIcType == RFIC_3020 || pAd->RfIcType == RFIC_2020) ++ { ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ AifsnCsr.field.Aifsn2 = 0x2; //pEdcaParm->Aifsn[QID_AC_VI]; //for WiFi WMM S4-T04. ++ } ++#endif // RT30xx // ++#endif // CONFIG_STA_SUPPORT // ++ RTMP_IO_WRITE32(pAd, WMM_AIFSN_CFG, AifsnCsr.word); ++ ++ NdisMoveMemory(&pAd->CommonCfg.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ if (!ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("EDCA [#%d]: AIFSN CWmin CWmax TXOP(us) ACM\n", pEdcaParm->EdcaUpdateCount)); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_BE %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[0], ++ pEdcaParm->Cwmin[0], ++ pEdcaParm->Cwmax[0], ++ pEdcaParm->Txop[0]<<5, ++ pEdcaParm->bACM[0])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_BK %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[1], ++ pEdcaParm->Cwmin[1], ++ pEdcaParm->Cwmax[1], ++ pEdcaParm->Txop[1]<<5, ++ pEdcaParm->bACM[1])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_VI %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[2], ++ pEdcaParm->Cwmin[2], ++ pEdcaParm->Cwmax[2], ++ pEdcaParm->Txop[2]<<5, ++ pEdcaParm->bACM[2])); ++ DBGPRINT(RT_DEBUG_TRACE,(" AC_VO %2d %2d %2d %4d %d\n", ++ pEdcaParm->Aifsn[3], ++ pEdcaParm->Cwmin[3], ++ pEdcaParm->Cwmax[3], ++ pEdcaParm->Txop[3]<<5, ++ pEdcaParm->bACM[3])); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicSetSlotTime( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUseShortSlotTime) ++{ ++ ULONG SlotTime; ++ UINT32 RegValue = 0; ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->CommonCfg.Channel > 14) ++ bUseShortSlotTime = TRUE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (bUseShortSlotTime) ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); ++ else ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED); ++ ++ SlotTime = (bUseShortSlotTime)? 9 : 20; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // force using short SLOT time for FAE to demo performance when TxBurst is ON ++ if (pAd->CommonCfg.bEnableTxBurst) ++ SlotTime = 9; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // For some reasons, always set it to short slot time. ++ // ++ // ToDo: Should consider capability with 11B ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.BssType == BSS_ADHOC) ++ SlotTime = 20; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_IO_READ32(pAd, BKOFF_SLOT_CFG, &RegValue); ++ RegValue = RegValue & 0xFFFFFF00; ++ ++ RegValue |= SlotTime; ++ ++ RTMP_IO_WRITE32(pAd, BKOFF_SLOT_CFG, RegValue); ++} ++ ++/* ++ ======================================================================== ++ Description: ++ Add Shared key information into ASIC. ++ Update shared key, TxMic and RxMic to Asic Shared key table ++ Update its cipherAlg to Asic Shared key Mode. ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicAddSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic) ++{ ++ ULONG offset; //, csr0; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); ++//============================================================================================ ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicAddSharedKeyEntry: %s key #%d\n", CipherName[CipherAlg], BssIndex*4 + KeyIdx)); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); ++ if (pRxMic) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ if (pTxMic) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ } ++//============================================================================================ ++ // ++ // fill key material - key + TX MIC + RX MIC ++ // ++ ++#ifdef RT2870 ++{ ++ offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; ++ RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_SHARE_KEY); ++ ++ offset += MAX_LEN_OF_SHARE_KEY; ++ if (pTxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pTxMic, 8); ++ } ++ ++ offset += 8; ++ if (pRxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pRxMic, 8); ++ } ++} ++#endif // RT2870 // ++ ++ // ++ // Update cipher algorithm. WSTA always use BSS0 ++ // ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE,("Read: SHARED_KEY_MODE_BASE at this Bss[%d] KeyIdx[%d]= 0x%x \n", BssIndex,KeyIdx, csr1.word)); ++ if ((BssIndex%2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss0Key3CipherAlg = CipherAlg; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss1Key3CipherAlg = CipherAlg; ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); ++ ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID AsicRemoveSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx) ++{ ++ //ULONG SecCsr0; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicRemoveSharedKeyEntry: #%d \n", BssIndex*4 + KeyIdx)); ++ ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), &csr1.word); ++ if ((BssIndex%2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = 0; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = 0; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = 0; ++ else ++ csr1.field.Bss0Key3CipherAlg = 0; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = 0; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = 0; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = 0; ++ else ++ csr1.field.Bss1Key3CipherAlg = 0; ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("Write: SHARED_KEY_MODE_BASE at this Bss[%d] = 0x%x \n", BssIndex, csr1.word)); ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE+4*(BssIndex/2), csr1.word); ++ ASSERT(BssIndex < 4); ++ ASSERT(KeyIdx < 4); ++ ++} ++ ++ ++VOID AsicUpdateWCIDAttribute( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bUsePairewiseKeyTable) ++{ ++ ULONG WCIDAttri = 0, offset; ++ ++ // ++ // Update WCID attribute. ++ // Only TxKey could update WCID attribute. ++ // ++ offset = MAC_WCID_ATTRIBUTE_BASE + (WCID * HW_WCID_ATTRI_SIZE); ++ WCIDAttri = (BssIndex << 4) | (CipherAlg << 1) | (bUsePairewiseKeyTable); ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++} ++ ++VOID AsicUpdateWCIDIVEIV( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN ULONG uIV, ++ IN ULONG uEIV) ++{ ++ ULONG offset; ++ ++ offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); ++ ++ RTMP_IO_WRITE32(pAd, offset, uIV); ++ RTMP_IO_WRITE32(pAd, offset + 4, uEIV); ++} ++ ++VOID AsicUpdateRxWCIDTable( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN PUCHAR pAddr) ++{ ++ ULONG offset; ++ ULONG Addr; ++ ++ offset = MAC_WCID_BASE + (WCID * HW_WCID_ENTRY_SIZE); ++ Addr = pAddr[0] + (pAddr[1] << 8) +(pAddr[2] << 16) +(pAddr[3] << 24); ++ RTMP_IO_WRITE32(pAd, offset, Addr); ++ Addr = pAddr[4] + (pAddr[5] << 8); ++ RTMP_IO_WRITE32(pAd, offset + 4, Addr); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set Cipher Key, Cipher algorithm, IV/EIV to Asic ++ ++ Arguments: ++ pAd Pointer to our adapter ++ WCID WCID Entry number. ++ BssIndex BSSID index, station or none multiple BSSID support ++ this value should be 0. ++ KeyIdx This KeyIdx will set to IV's KeyID if bTxKey enabled ++ pCipherKey Pointer to Cipher Key. ++ bUsePairewiseKeyTable TRUE means saved the key in SharedKey table, ++ otherwise PairewiseKey table ++ bTxKey This is the transmit key if enabled. ++ ++ Return Value: ++ None ++ ++ Note: ++ This routine will set the relative key stuff to Asic including WCID attribute, ++ Cipher Key, Cipher algorithm and IV/EIV. ++ ++ IV/EIV will be update if this CipherKey is the transmission key because ++ ASIC will base on IV's KeyID value to select Cipher Key. ++ ++ If bTxKey sets to FALSE, this is not the TX key, but it could be ++ RX key ++ ++ For AP mode bTxKey must be always set to TRUE. ++ ======================================================================== ++*/ ++VOID AsicAddKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN PCIPHER_KEY pCipherKey, ++ IN BOOLEAN bUsePairewiseKeyTable, ++ IN BOOLEAN bTxKey) ++{ ++ ULONG offset; ++// ULONG WCIDAttri = 0; ++ UCHAR IV4 = 0; ++ PUCHAR pKey = pCipherKey->Key; ++// ULONG KeyLen = pCipherKey->KeyLen; ++ PUCHAR pTxMic = pCipherKey->TxMic; ++ PUCHAR pRxMic = pCipherKey->RxMic; ++ PUCHAR pTxtsc = pCipherKey->TxTsc; ++ UCHAR CipherAlg = pCipherKey->CipherAlg; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++// ASSERT(KeyLen <= MAX_LEN_OF_PEER_KEY); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); ++ // ++ // 1.) decide key table offset ++ // ++ if (bUsePairewiseKeyTable) ++ offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); ++ else ++ offset = SHARED_KEY_TABLE_BASE + (4 * BssIndex + KeyIdx) * HW_KEY_ENTRY_SIZE; ++ ++ // ++ // 2.) Set Key to Asic ++ // ++ //for (i = 0; i < KeyLen; i++) ++ ++#ifdef RT2870 ++ RTUSBMultiWrite(pAd, offset, pKey, MAX_LEN_OF_PEER_KEY); ++ offset += MAX_LEN_OF_PEER_KEY; ++ ++ // ++ // 3.) Set MIC key if available ++ // ++ if (pTxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pTxMic, 8); ++ } ++ offset += LEN_TKIP_TXMICK; ++ ++ if (pRxMic) ++ { ++ RTUSBMultiWrite(pAd, offset, pRxMic, 8); ++ } ++#endif // RT2870 // ++ ++ // ++ // 4.) Modify IV/EIV if needs ++ // This will force Asic to use this key ID by setting IV. ++ // ++ if (bTxKey) ++ { ++ ++#ifdef RT2870 ++ UINT32 tmpVal; ++ ++ // ++ // Write IV ++ // ++ IV4 = (KeyIdx << 6); ++ if ((CipherAlg == CIPHER_TKIP) || (CipherAlg == CIPHER_TKIP_NO_MIC) ||(CipherAlg == CIPHER_AES)) ++ IV4 |= 0x20; // turn on extension bit means EIV existence ++ ++ tmpVal = pTxtsc[1] + (((pTxtsc[1] | 0x20) & 0x7f) << 8) + (pTxtsc[0] << 16) + (IV4 << 24); ++ RTMP_IO_WRITE32(pAd, offset, tmpVal); ++ ++ // ++ // Write EIV ++ // ++ offset += 4; ++ RTMP_IO_WRITE32(pAd, offset, *(PUINT32)&pCipherKey->TxTsc[2]); ++#endif // RT2870 // ++ AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); ++ } ++ ++ if (!bUsePairewiseKeyTable) ++ { ++ // ++ // Only update the shared key security mode ++ // ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), &csr1.word); ++ if ((BssIndex % 2) == 0) ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss0Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss0Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss0Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss0Key3CipherAlg = CipherAlg; ++ } ++ else ++ { ++ if (KeyIdx == 0) ++ csr1.field.Bss1Key0CipherAlg = CipherAlg; ++ else if (KeyIdx == 1) ++ csr1.field.Bss1Key1CipherAlg = CipherAlg; ++ else if (KeyIdx == 2) ++ csr1.field.Bss1Key2CipherAlg = CipherAlg; ++ else ++ csr1.field.Bss1Key3CipherAlg = CipherAlg; ++ } ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4 * (BssIndex / 2), csr1.word); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<== AsicAddKeyEntry\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ Description: ++ Add Pair-wise key material into ASIC. ++ Update pairwise key, TxMic and RxMic to Asic Pair-wise key table ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicAddPairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR WCID, ++ IN CIPHER_KEY *pCipherKey) ++{ ++ INT i; ++ ULONG offset; ++ PUCHAR pKey = pCipherKey->Key; ++ PUCHAR pTxMic = pCipherKey->TxMic; ++ PUCHAR pRxMic = pCipherKey->RxMic; ++#ifdef DBG ++ UCHAR CipherAlg = pCipherKey->CipherAlg; ++#endif // DBG // ++ ++ // EKEY ++ offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); ++#ifdef RT2870 ++ RTUSBMultiWrite(pAd, offset, &pCipherKey->Key[0], MAX_LEN_OF_PEER_KEY); ++#endif // RT2870 // ++ for (i=0; iTxMic[0], 8); ++#endif // RT2870 // ++ } ++ offset += 8; ++ if (pRxMic) ++ { ++#ifdef RT2870 ++ RTUSBMultiWrite(pAd, offset, &pCipherKey->RxMic[0], 8); ++#endif // RT2870 // ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicAddPairwiseKeyEntry: WCID #%d Alg=%s\n",WCID, CipherName[CipherAlg])); ++ DBGPRINT(RT_DEBUG_TRACE,(" Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pKey[0],pKey[1],pKey[2],pKey[3],pKey[4],pKey[5],pKey[6],pKey[7],pKey[8],pKey[9],pKey[10],pKey[11],pKey[12],pKey[13],pKey[14],pKey[15])); ++ if (pRxMic) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" Rx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pRxMic[0],pRxMic[1],pRxMic[2],pRxMic[3],pRxMic[4],pRxMic[5],pRxMic[6],pRxMic[7])); ++ } ++ if (pTxMic) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" Tx MIC Key = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pTxMic[0],pTxMic[1],pTxMic[2],pTxMic[3],pTxMic[4],pTxMic[5],pTxMic[6],pTxMic[7])); ++ } ++} ++/* ++ ======================================================================== ++ Description: ++ Remove Pair-wise key material from ASIC. ++ ++ Return: ++ ======================================================================== ++*/ ++VOID AsicRemovePairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR Wcid) ++{ ++ ULONG WCIDAttri; ++ USHORT offset; ++ ++ // re-set the entry's WCID attribute as OPEN-NONE. ++ offset = MAC_WCID_ATTRIBUTE_BASE + (Wcid * HW_WCID_ATTRI_SIZE); ++ WCIDAttri = (BssIdx<<4) | PAIRWISEKEYTABLE; ++ RTMP_IO_WRITE32(pAd, offset, WCIDAttri); ++} ++ ++BOOLEAN AsicSendCommandToMcu( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command, ++ IN UCHAR Token, ++ IN UCHAR Arg0, ++ IN UCHAR Arg1) ++{ ++ HOST_CMD_CSR_STRUC H2MCmd; ++ H2M_MAILBOX_STRUC H2MMailbox; ++ ULONG i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, H2M_MAILBOX_CSR, &H2MMailbox.word); ++ if (H2MMailbox.field.Owner == 0) ++ break; ++ ++ RTMPusecDelay(2); ++ } while(i++ < 100); ++ ++ if (i >= 100) ++ { ++ { ++ DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); ++ } ++ return FALSE; ++ } ++ ++ ++ H2MMailbox.field.Owner = 1; // pass ownership to MCU ++ H2MMailbox.field.CmdToken = Token; ++ H2MMailbox.field.HighByte = Arg1; ++ H2MMailbox.field.LowByte = Arg0; ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, H2MMailbox.word); ++ ++ H2MCmd.word = 0; ++ H2MCmd.field.HostCommand = Command; ++ RTMP_IO_WRITE32(pAd, HOST_CMD_CSR, H2MCmd.word); ++ ++ if (Command != 0x80) ++ { ++ } ++ ++ return TRUE; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for different PHY type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPCheckRates( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT UCHAR SupRate[], ++ IN OUT UCHAR *SupRateLen) ++{ ++ UCHAR RateIdx, i, j; ++ UCHAR NewRate[12], NewRateLen; ++ ++ NewRateLen = 0; ++ ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ RateIdx = 4; ++ else ++ RateIdx = 12; ++ ++ // Check for support rates exclude basic rate bit ++ for (i = 0; i < *SupRateLen; i++) ++ for (j = 0; j < RateIdx; j++) ++ if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ NewRate[NewRateLen++] = SupRate[i]; ++ ++ *SupRateLen = NewRateLen; ++ NdisMoveMemory(SupRate, NewRate, NewRateLen); ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef DOT11_N_SUPPORT ++BOOLEAN RTMPCheckChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR CentralChannel, ++ IN UCHAR Channel) ++{ ++ UCHAR k; ++ UCHAR UpperChannel = 0, LowerChannel = 0; ++ UCHAR NoEffectChannelinList = 0; ++ ++ // Find upper and lower channel according to 40MHz current operation. ++ if (CentralChannel < Channel) ++ { ++ UpperChannel = Channel; ++ if (CentralChannel > 2) ++ LowerChannel = CentralChannel - 2; ++ else ++ return FALSE; ++ } ++ else if (CentralChannel > Channel) ++ { ++ UpperChannel = CentralChannel + 2; ++ LowerChannel = Channel; ++ } ++ ++ for (k = 0;k < pAd->ChannelListNum;k++) ++ { ++ if (pAd->ChannelList[k].Channel == UpperChannel) ++ { ++ NoEffectChannelinList ++; ++ } ++ if (pAd->ChannelList[k].Channel == LowerChannel) ++ { ++ NoEffectChannelinList ++; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList)); ++ if (NoEffectChannelinList == 2) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for HT phy type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode) ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckHt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo) ++{ ++ if (Wcid >= MAX_LEN_OF_MAC_TABLE) ++ return FALSE; ++ ++ // If use AMSDU, set flag. ++ if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED); ++ // Save Peer Capability ++ if (pHtCapability->HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE); ++ if (pHtCapability->HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE); ++ if (pHtCapability->HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (pHtCapability->HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) ++ { ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE); ++ } ++ ++ if (Wcid < MAX_LEN_OF_MAC_TABLE) ++ { ++ pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity; ++ } ++ ++ // Will check ChannelWidth for MCSSet[4] below ++ pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1; ++ switch (pAd->CommonCfg.RxStream) ++ { ++ case 1: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ case 2: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ case 3: ++ pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff; ++ pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; ++ break; ++ } ++ ++ pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n", ++ pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth, ++ pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode)); ++ ++ pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF; ++ ++ // Send Assoc Req with my HT capability. ++ pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize; ++ pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs; ++ pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20); ++ pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40); ++ pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC); ++ pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC); ++ pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor; ++ pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity; ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; ++ pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; ++ if (pAd->CommonCfg.bRdg) ++ { ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport; ++ pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1; ++ } ++ ++ if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20) ++ pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32 ++ ++ COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); ++ return TRUE; ++} ++#endif // DOT11_N_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Verify the support rate for different PHY type ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateMlmeRate( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR MinimumRate; ++ UCHAR ProperMlmeRate; //= RATE_54; ++ UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++ BOOLEAN bMatch = FALSE; ++ ++ switch (pAd->CommonCfg.PhyMode) ++ { ++ case PHY_11B: ++ ProperMlmeRate = RATE_11; ++ MinimumRate = RATE_1; ++ break; ++ case PHY_11BG_MIXED: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11ABGN_MIXED: ++ case PHY_11BGN_MIXED: ++#endif // DOT11_N_SUPPORT // ++ if ((pAd->MlmeAux.SupRateLen == 4) && ++ (pAd->MlmeAux.ExtRateLen == 0)) ++ // B only AP ++ ProperMlmeRate = RATE_11; ++ else ++ ProperMlmeRate = RATE_24; ++ ++ if (pAd->MlmeAux.Channel <= 14) ++ MinimumRate = RATE_1; ++ else ++ MinimumRate = RATE_6; ++ break; ++ case PHY_11A: ++#ifdef DOT11_N_SUPPORT ++ case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n ++ case PHY_11GN_MIXED: ++ case PHY_11AGN_MIXED: ++ case PHY_11AN_MIXED: ++ case PHY_11N_5G: ++#endif // DOT11_N_SUPPORT // ++ ProperMlmeRate = RATE_24; ++ MinimumRate = RATE_6; ++ break; ++ case PHY_11ABG_MIXED: ++ ProperMlmeRate = RATE_24; ++ if (pAd->MlmeAux.Channel <= 14) ++ MinimumRate = RATE_1; ++ else ++ MinimumRate = RATE_6; ++ break; ++ default: // error ++ ProperMlmeRate = RATE_1; ++ MinimumRate = RATE_1; ++ break; ++ } ++ ++ for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) ++ { ++ for (j = 0; j < RateIdx; j++) ++ { ++ if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ { ++ if (j == ProperMlmeRate) ++ { ++ bMatch = TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (bMatch) ++ break; ++ } ++ ++ if (bMatch == FALSE) ++ { ++ for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) ++ { ++ for (j = 0; j < RateIdx; j++) ++ { ++ if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j]) ++ { ++ if (j == ProperMlmeRate) ++ { ++ bMatch = TRUE; ++ break; ++ } ++ } ++ } ++ ++ if (bMatch) ++ break; ++ } ++ } ++ ++ if (bMatch == FALSE) ++ { ++ ProperMlmeRate = MinimumRate; ++ } ++ ++ pAd->CommonCfg.MlmeRate = MinimumRate; ++ pAd->CommonCfg.RtsRate = ProperMlmeRate; ++ if (pAd->CommonCfg.MlmeRate >= RATE_6) ++ { ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ else ++ { ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word)); ++} ++ ++CHAR RTMPMaxRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi0, ++ IN CHAR Rssi1, ++ IN CHAR Rssi2) ++{ ++ CHAR larger = -127; ++ ++ if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) ++ { ++ larger = Rssi0; ++ } ++ ++ if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) ++ { ++ larger = max(Rssi0, Rssi1); ++ } ++ ++ if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) ++ { ++ larger = max(larger, Rssi2); ++ } ++ ++ if (larger == -127) ++ larger = 0; ++ ++ return larger; ++} ++ ++ ++// Antenna divesity use GPIO3 and EESK pin for control ++// Antenna and EEPROM access are both using EESK pin, ++// Therefor we should avoid accessing EESK at the same time ++// Then restore antenna after EEPROM access ++VOID AsicSetRxAnt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ant) ++{ ++#ifdef RT30xx ++ UINT32 Value; ++ UINT32 x; ++ ++ if ((pAd->EepromAccess) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ return; ++ } ++ ++ // the antenna selection is through firmware and MAC register(GPIO3) ++ if (Ant == 0) ++ { ++ // Main antenna ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x |= (EESK); ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value); ++ Value &= ~(0x0808); ++ RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to main antenna\n")); ++ } ++ else ++ { ++ // Aux antenna ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &x); ++ x &= ~(EESK); ++ RTMP_IO_WRITE32(pAd, E2PROM_CSR, x); ++ ++ RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &Value); ++ Value &= ~(0x0808); ++ Value |= 0x08; ++ RTMP_IO_WRITE32(pAd, GPIO_CTRL_CFG, Value); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicSetRxAnt, switch to aux antenna\n")); ++ } ++#endif // RT30xx // ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Periodic evaluate antenna link status ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID AsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BBPR3 = 0; ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_NIC_NOT_EXIST | ++ fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) || ++ OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) ++#ifdef RT30xx ++ || (pAd->EepromAccess) ++#endif // RT30xx // ++ ) ++ return; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //if (pAd->StaCfg.Psm == PWR_SAVE) ++ // return; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // two antenna selection mechanism- one is antenna diversity, the other is failed antenna remove ++ // one is antenna diversity:there is only one antenna can rx and tx ++ // the other is failed antenna remove:two physical antenna can rx and tx ++ if (pAd->NicConfig2.field.AntDiversity) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AntDiv - before evaluate Pair1-Ant (%d,%d)\n", ++ pAd->RxAnt.Pair1PrimaryRxAnt, pAd->RxAnt.Pair1SecondaryRxAnt)); ++ ++ AsicSetRxAnt(pAd, pAd->RxAnt.Pair1SecondaryRxAnt); ++ ++ pAd->RxAnt.EvaluatePeriod = 1; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt ++ pAd->RxAnt.FirstPktArrivedWhenEvaluate = FALSE; ++ pAd->RxAnt.RcvPktNumWhenEvaluate = 0; ++ ++ // a one-shot timer to end the evalution ++ // dynamic adjust antenna evaluation period according to the traffic ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 100); ++ else ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); ++ } ++ else ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ return; ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ { ++ ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + ++ pAd->RalinkCounters.OneSecTxRetryOkCount + ++ pAd->RalinkCounters.OneSecTxFailCount; ++ ++ // dynamic adjust antenna evaluation period according to the traffic ++ if (TxTotalCnt > 50) ++ { ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); ++ pAd->Mlme.bLowThroughput = FALSE; ++ } ++ else ++ { ++ RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); ++ pAd->Mlme.bLowThroughput = TRUE; ++ } ++ } ++ } ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ After evaluation, check antenna link status ++ ++ Arguments: ++ pAd - Adapter pointer ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID AsicRxAntEvalTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR BBPR3 = 0; ++ CHAR larger = -127, rssi0, rssi1, rssi2; ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_NIC_NOT_EXIST) || ++ OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) ++#ifdef RT30xx ++ || (pAd->EepromAccess) ++#endif // RT30xx // ++ ) ++ return; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //if (pAd->StaCfg.Psm == PWR_SAVE) ++ // return; ++ ++ if (pAd->NicConfig2.field.AntDiversity) ++ { ++ if ((pAd->RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >= pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt])) ++ { ++ UCHAR temp; ++ ++ // ++ // select PrimaryRxAntPair ++ // Role change, Used Pair1SecondaryRxAnt as PrimaryRxAntPair. ++ // Since Pair1SecondaryRxAnt Quality good than Pair1PrimaryRxAnt ++ // ++ temp = pAd->RxAnt.Pair1PrimaryRxAnt; ++ pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; ++ pAd->RxAnt.Pair1SecondaryRxAnt = temp; ++ ++ pAd->RxAnt.Pair1LastAvgRssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >> 3); ++ pAd->RxAnt.EvaluateStableCnt = 0; ++ } ++ else ++ { ++ // if the evaluated antenna is not better than original, switch back to original antenna ++ AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); ++ pAd->RxAnt.EvaluateStableCnt ++; ++ } ++ ++ pAd->RxAnt.EvaluatePeriod = 0; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AsicRxAntEvalAction::After Eval(fix in #%d), <%d, %d>, RcvPktNumWhenEvaluate=%ld\n", ++ pAd->RxAnt.Pair1PrimaryRxAnt, (pAd->RxAnt.Pair1AvgRssi[0] >> 3), (pAd->RxAnt.Pair1AvgRssi[1] >> 3), pAd->RxAnt.RcvPktNumWhenEvaluate)); ++ } ++ else ++ { ++ if (pAd->StaCfg.Psm == PWR_SAVE) ++ return; ++ ++ // if the traffic is low, use average rssi as the criteria ++ if (pAd->Mlme.bLowThroughput == TRUE) ++ { ++ rssi0 = pAd->StaCfg.RssiSample.LastRssi0; ++ rssi1 = pAd->StaCfg.RssiSample.LastRssi1; ++ rssi2 = pAd->StaCfg.RssiSample.LastRssi2; ++ } ++ else ++ { ++ rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; ++ rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; ++ rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; ++ } ++ ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ larger = max(rssi0, rssi1); ++ ++ if (larger > (rssi2 + 20)) ++ pAd->Mlme.RealRxPath = 2; ++ else ++ pAd->Mlme.RealRxPath = 3; ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ if (rssi0 > (rssi1 + 20)) ++ pAd->Mlme.RealRxPath = 1; ++ else ++ pAd->Mlme.RealRxPath = 2; ++ } ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Mlme.RealRxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Mlme.RealRxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Mlme.RealRxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++ } ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++} ++ ++ ++ ++VOID APSDPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ return; ++ ++ pAd->CommonCfg.TriggerTimerCount++; ++ ++// Driver should not send trigger frame, it should be send by application layer ++/* ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable ++ && (pAd->CommonCfg.bNeedSendTriggerFrame || ++ (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO)))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n")); ++ RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); ++ pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; ++ pAd->CommonCfg.TriggerTimerCount = 0; ++ pAd->CommonCfg.bInServicePeriod = TRUE; ++ }*/ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Set/reset MAC registers according to bPiggyBack parameter ++ ++ Arguments: ++ pAd - Adapter pointer ++ bPiggyBack - Enable / Disable Piggy-Back ++ ++ Return Value: ++ None ++ ++ ======================================================================== ++*/ ++VOID RTMPSetPiggyBack( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bPiggyBack) ++{ ++ TX_LINK_CFG_STRUC TxLinkCfg; ++ ++ RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); ++ ++ TxLinkCfg.field.TxCFAckEn = bPiggyBack; ++ RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ check if this entry need to switch rate automatically ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry) ++{ ++ BOOLEAN result = TRUE; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // only associated STA counts ++ if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) ++ { ++ result = pAd->StaCfg.bAutoTxRateSwitch; ++ } ++ else ++ result = FALSE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ return result; ++} ++ ++ ++BOOLEAN RTMPAutoRateSwitchCheck( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.bAutoTxRateSwitch) ++ return TRUE; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ return FALSE; ++} ++ ++ ++/* ++ ======================================================================== ++ Routine Description: ++ check if this entry need to fix tx legacy rate ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++UCHAR RTMPStaFixedTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry) ++{ ++ UCHAR tx_mode = FIXED_TXMODE_HT; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return tx_mode; ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified. ++ ++ Arguments: ++ pAd ++ pEntry ++ ++ Return Value: ++ TURE ++ FALSE ++ ++ ======================================================================== ++*/ ++VOID RTMPUpdateLegacyTxSetting( ++ UCHAR fixed_tx_mode, ++ PMAC_TABLE_ENTRY pEntry) ++{ ++ HTTRANSMIT_SETTING TransmitSetting; ++ ++ if (fixed_tx_mode == FIXED_TXMODE_HT) ++ return; ++ ++ TransmitSetting.word = 0; ++ ++ TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE; ++ TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS; ++ ++ if (fixed_tx_mode == FIXED_TXMODE_CCK) ++ { ++ TransmitSetting.field.MODE = MODE_CCK; ++ // CCK mode allow MCS 0~3 ++ if (TransmitSetting.field.MCS > MCS_3) ++ TransmitSetting.field.MCS = MCS_3; ++ } ++ else ++ { ++ TransmitSetting.field.MODE = MODE_OFDM; ++ // OFDM mode allow MCS 0~7 ++ if (TransmitSetting.field.MCS > MCS_7) ++ TransmitSetting.field.MCS = MCS_7; ++ } ++ ++ if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) ++ { ++ pEntry->HTPhyMode.word = TransmitSetting.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n", ++ pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS)); ++ } ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ dynamic tune BBP R66 to find a balance between sensibility and ++ noise isolation ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AsicStaBbpTuning( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30; ++ CHAR Rssi; ++ ++ // 2860C did not support Fase CCA, therefore can't tune ++ if (pAd->MACVersion == 0x28600100) ++ return; ++ ++ // ++ // work as a STA ++ // ++ if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING ++ return; ++ ++ if ((pAd->OpMode == OPMODE_STA) ++ && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ ) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); ++ R66 = OrigR66Value; ++ ++ if (pAd->Antenna.field.RxPath > 1) ++ Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; ++ else ++ Rssi = pAd->StaCfg.RssiSample.AvgRssi0; ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { //BG band ++#ifdef RT30xx ++ // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control ++ // Otherwise, it will have some throughput side effect when low RSSI ++ if (IS_RT30xx(pAd)) ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x1C + 2*GET_LNA_GAIN(pAd); ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ else ++#endif // RT30xx // ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ ++ } ++ else ++ { //A band ++ if (pAd->CommonCfg.BBPCurrentBW == BW_20) ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ else ++ { ++ if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) ++ { ++ R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ else ++ { ++ R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3; ++ if (OrigR66Value != R66) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ } ++ } ++ ++ ++ } ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID RTMPSetAGCInitValue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BandWidth) ++{ ++ UCHAR R66 = 0x30; ++ ++ if (pAd->LatchRfRegs.Channel <= 14) ++ { // BG band ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { //A band ++ if (BandWidth == BW_20) ++ { ++ R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ { ++ R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++} ++ ++VOID AsicTurnOffRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ // RF R2 bit 18 = 0 ++ UINT32 R1 = 0, R2 = 0, R3 = 0; ++ UCHAR index; ++ RTMP_RF_REGS *RFRegTable; ++ ++#ifdef RT30xx ++ // The RF programming sequence is difference between 3xxx and 2xxx ++ if (IS_RT3090(pAd)) ++ { ++ RT30xxLoadRFSleepModeSetup(pAd); // add by johnli, RF power sequence setup, load RF sleep-mode setup ++ } ++ else ++ { ++#endif // RT30xx // ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R1 = RFRegTable[index].R1 & 0xffffdfff; ++ R2 = RFRegTable[index].R2 & 0xfffbffff; ++ R3 = RFRegTable[index].R3 & 0xfff3ffff; ++ ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ ++ // Program R1b13 to 1, R3/b18,19 to 0, R2b18 to 0. ++ // Set RF R2 bit18=0, R3 bit[18:19]=0 ++ //if (pAd->StaCfg.bRadio == FALSE) ++ if (1) ++ { ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x, R3 = 0x%08x \n", ++ Channel, pAd->RfIcType, R2, R3)); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("AsicTurnOffRFClk#%d(RF=%d, ) , R2=0x%08x \n", ++ Channel, pAd->RfIcType, R2)); ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++#ifdef RT30xx ++ } ++#endif // RT30xx // ++ ++} ++ ++ ++VOID AsicTurnOnRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ++{ ++ // RF R2 bit 18 = 0 ++ UINT32 R1 = 0, R2 = 0, R3 = 0; ++ UCHAR index; ++ RTMP_RF_REGS *RFRegTable; ++ ++#ifdef RT30xx ++ // The RF programming sequence is difference between 3xxx and 2xxx ++ if (IS_RT3090(pAd)) ++ { ++ } ++ else ++ { ++#endif // RT30xx // ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R3 = pAd->LatchRfRegs.R3; ++ R3 &= 0xfff3ffff; ++ R3 |= 0x00080000; ++ RTMP_RF_IO_WRITE32(pAd, R3); ++ ++ R1 = RFRegTable[index].R1; ++ RTMP_RF_IO_WRITE32(pAd, R1); ++ ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ R2 |= 0x40; // write 1 to off Rxpath. ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ RTMP_RF_IO_WRITE32(pAd, R2); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++#ifdef RT30xx ++ } ++#endif // RT30xx // ++ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/netif_block.c +@@ -0,0 +1,136 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "../rt_config.h" ++#include "netif_block.h" ++ ++static NETIF_ENTRY freeNetIfEntryPool[FREE_NETIF_POOL_SIZE]; ++static LIST_HEADER freeNetIfEntryList; ++ ++void initblockQueueTab( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ ++ initList(&freeNetIfEntryList); ++ for (i = 0; i < FREE_NETIF_POOL_SIZE; i++) ++ insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)&freeNetIfEntryPool[i]); ++ ++ for (i=0; i < NUM_OF_TX_RING; i++) ++ initList(&pAd->blockQueueTab[i].NetIfList); ++ ++ return; ++} ++ ++BOOLEAN blockNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, ++ IN PNET_DEV pNetDev) ++{ ++ PNETIF_ENTRY pNetIfEntry = NULL; ++ ++ if ((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(&freeNetIfEntryList)) != NULL) ++ { ++ netif_stop_queue(pNetDev); ++ pNetIfEntry->pNetDev = pNetDev; ++ insertTailList(&pBlockQueueEntry->NetIfList, (PLIST_ENTRY)pNetIfEntry); ++ ++ pBlockQueueEntry->SwTxQueueBlockFlag = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("netif_stop_queue(%s)\n", pNetDev->name)); ++ } ++ else ++ return FALSE; ++ ++ return TRUE; ++} ++ ++VOID releaseNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry) ++{ ++ PNETIF_ENTRY pNetIfEntry = NULL; ++ PLIST_HEADER pNetIfList = &pBlockQueueEntry->NetIfList; ++ ++ while((pNetIfEntry = (PNETIF_ENTRY)removeHeadList(pNetIfList)) != NULL) ++ { ++ PNET_DEV pNetDev = pNetIfEntry->pNetDev; ++ netif_wake_queue(pNetDev); ++ insertTailList(&freeNetIfEntryList, (PLIST_ENTRY)pNetIfEntry); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("netif_wake_queue(%s)\n", pNetDev->name)); ++ } ++ pBlockQueueEntry->SwTxQueueBlockFlag = FALSE; ++ return; ++} ++ ++ ++VOID StopNetIfQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket) ++{ ++ PNET_DEV NetDev = NULL; ++ UCHAR IfIdx = 0; ++ BOOLEAN valid = FALSE; ++ ++#ifdef WDS_SUPPORT ++ if (RTMP_GET_PACKET_NET_DEVICE(pPacket) >= MIN_NET_DEVICE_FOR_WDS) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_WDS) % MAX_WDS_ENTRY; ++ NetDev = pAd->WdsTab.WdsEntry[IfIdx].dev; ++ } ++ else ++#endif // WDS_SUPPORT // ++ { ++#ifdef MBSS_SUPPORT ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ IfIdx = (RTMP_GET_PACKET_NET_DEVICE(pPacket) - MIN_NET_DEVICE_FOR_MBSSID) % MAX_MBSSID_NUM; ++ NetDev = pAd->ApCfg.MBSSID[IfIdx].MSSIDDev; ++ } ++ else ++ { ++ IfIdx = MAIN_MBSSID; ++ NetDev = pAd->net_dev; ++ } ++#else ++ IfIdx = MAIN_MBSSID; ++ NetDev = pAd->net_dev; ++#endif ++ } ++ ++ // WMM support 4 software queues. ++ // One software queue full doesn't mean device have no capbility to transmit packet. ++ // So disable block Net-If queue function while WMM enable. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ valid = (pAd->CommonCfg.bWmmCapable == TRUE) ? FALSE : TRUE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (valid) ++ blockNetIf(&pAd->blockQueueTab[QueIdx], NetDev); ++ return; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/rtmp_init.c +@@ -0,0 +1,4197 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_init.c ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ John Chang 2004-08-20 RT2561/2661 use scatter-gather scheme ++ Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. ++*/ ++#include "../rt_config.h" ++#include "../firmware.h" ++ ++//#define BIN_IN_FILE /* use *.bin firmware */ ++ ++UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; ++ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, ++ 0x00000010, 0x00000020, 0x00000040, 0x00000080, ++ 0x00000100, 0x00000200, 0x00000400, 0x00000800, ++ 0x00001000, 0x00002000, 0x00004000, 0x00008000, ++ 0x00010000, 0x00020000, 0x00040000, 0x00080000, ++ 0x00100000, 0x00200000, 0x00400000, 0x00800000, ++ 0x01000000, 0x02000000, 0x04000000, 0x08000000, ++ 0x10000000, 0x20000000, 0x40000000, 0x80000000}; ++ ++char* CipherName[] = {"none","wep64","wep128","TKIP","AES","CKIP64","CKIP128"}; ++ ++const unsigned short ccitt_16Table[] = { ++ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, ++ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, ++ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, ++ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, ++ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, ++ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, ++ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, ++ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, ++ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, ++ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, ++ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, ++ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, ++ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, ++ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, ++ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, ++ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, ++ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, ++ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, ++ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, ++ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, ++ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, ++ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, ++ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, ++ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, ++ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, ++ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, ++ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, ++ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, ++ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, ++ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, ++ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, ++ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 ++}; ++#define ByteCRC16(v, crc) \ ++ (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) ++ ++unsigned char BitReverse(unsigned char x) ++{ ++ int i; ++ unsigned char Temp=0; ++ for(i=0; ; i++) ++ { ++ if(x & 0x80) Temp |= 0x80; ++ if(i==7) break; ++ x <<= 1; ++ Temp >>= 1; ++ } ++ return Temp; ++} ++ ++// ++// BBP register initialization set ++// ++REG_PAIR BBPRegTable[] = { ++ {BBP_R65, 0x2C}, // fix rssi issue ++ {BBP_R66, 0x38}, // Also set this default value to pAd->BbpTuning.R66CurrentValue at initial ++ {BBP_R69, 0x12}, ++ {BBP_R70, 0xa}, // BBP_R70 will change to 0x8 in ApStartUp and LinkUp for rt2860C, otherwise value is 0xa ++ {BBP_R73, 0x10}, ++ {BBP_R81, 0x37}, ++ {BBP_R82, 0x62}, ++ {BBP_R83, 0x6A}, ++ {BBP_R84, 0x99}, // 0x19 is for rt2860E and after. This is for extension channel overlapping IOT. 0x99 is for rt2860D and before ++ {BBP_R86, 0x00}, // middle range issue, Rory @2008-01-28 ++ {BBP_R91, 0x04}, // middle range issue, Rory @2008-01-28 ++ {BBP_R92, 0x00}, // middle range issue, Rory @2008-01-28 ++ {BBP_R103, 0x00}, // near range high-power issue, requested from Gary @2008-0528 ++ {BBP_R105, 0x05}, // 0x05 is for rt2860E to turn on FEQ control. It is safe for rt2860D and before, because Bit 7:2 are reserved in rt2860D and before. ++}; ++#define NUM_BBP_REG_PARMS (sizeof(BBPRegTable) / sizeof(REG_PAIR)) ++ ++// ++// RF register initialization set ++// ++#ifdef RT30xx ++REG_PAIR RT30xx_RFRegTable[] = { ++ {RF_R04, 0x40}, ++ {RF_R05, 0x03}, ++ {RF_R06, 0x02}, ++ {RF_R07, 0x70}, ++ {RF_R09, 0x0F}, ++ {RF_R10, 0x41}, ++ {RF_R11, 0x21}, ++ {RF_R12, 0x7B}, ++ {RF_R14, 0x90}, ++ {RF_R15, 0x58}, ++ {RF_R16, 0xB3}, ++ {RF_R17, 0x92}, ++ {RF_R18, 0x2C}, ++ {RF_R19, 0x02}, ++ {RF_R20, 0xBA}, ++ {RF_R21, 0xDB}, ++ {RF_R24, 0x16}, ++ {RF_R25, 0x01}, ++ {RF_R29, 0x1F}, ++}; ++#define NUM_RF_REG_PARMS (sizeof(RT30xx_RFRegTable) / sizeof(REG_PAIR)) ++#endif // RT30xx // ++ ++// ++// ASIC register initialization sets ++// ++ ++RTMP_REG_PAIR MACRegTable[] = { ++#if defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x200) ++ {BCN_OFFSET0, 0xf8f0e8e0}, /* 0x3800(e0), 0x3A00(e8), 0x3C00(f0), 0x3E00(f8), 512B for each beacon */ ++ {BCN_OFFSET1, 0x6f77d0c8}, /* 0x3200(c8), 0x3400(d0), 0x1DC0(77), 0x1BC0(6f), 512B for each beacon */ ++#elif defined(HW_BEACON_OFFSET) && (HW_BEACON_OFFSET == 0x100) ++ {BCN_OFFSET0, 0xece8e4e0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ ++ {BCN_OFFSET1, 0xfcf8f4f0}, /* 0x3800, 0x3A00, 0x3C00, 0x3E00, 512B for each beacon */ ++#else ++ #error You must re-calculate new value for BCN_OFFSET0 & BCN_OFFSET1 in MACRegTable[]!!! ++#endif // HW_BEACON_OFFSET // ++ ++ {LEGACY_BASIC_RATE, 0x0000013f}, // Basic rate set bitmap ++ {HT_BASIC_RATE, 0x00008003}, // Basic HT rate set , 20M, MCS=3, MM. Format is the same as in TXWI. ++ {MAC_SYS_CTRL, 0x00}, // 0x1004, , default Disable RX ++ {RX_FILTR_CFG, 0x17f97}, //0x1400 , RX filter control, ++ {BKOFF_SLOT_CFG, 0x209}, // default set short slot time, CC_DELAY_TIME should be 2 ++ //{TX_SW_CFG0, 0x40a06}, // Gary,2006-08-23 ++ {TX_SW_CFG0, 0x0}, // Gary,2008-05-21 for CWC test ++ {TX_SW_CFG1, 0x80606}, // Gary,2006-08-23 ++ {TX_LINK_CFG, 0x1020}, // Gary,2006-08-23 ++ {TX_TIMEOUT_CFG, 0x000a2090}, ++ {MAX_LEN_CFG, MAX_AGGREGATION_SIZE | 0x00001000}, // 0x3018, MAX frame length. Max PSDU = 16kbytes. ++ {LED_CFG, 0x7f031e46}, // Gary, 2006-08-23 ++ ++//#ifdef CONFIG_STA_SUPPORT ++// {WMM_AIFSN_CFG, 0x00002273}, ++// {WMM_CWMIN_CFG, 0x00002344}, ++// {WMM_CWMAX_CFG, 0x000034aa}, ++//#endif // CONFIG_STA_SUPPORT // ++#ifdef INF_AMAZON_SE ++ {PBF_MAX_PCNT, 0x1F3F6F6F}, //iverson modify for usb issue, 2008/09/19 ++ // 6F + 6F < total page count FE ++ // so that RX doesn't occupy TX's buffer space when WMM congestion. ++#else ++ {PBF_MAX_PCNT, 0x1F3FBF9F}, //0x1F3f7f9f}, //Jan, 2006/04/20 ++#endif // INF_AMAZON_SE // ++ //{TX_RTY_CFG, 0x6bb80408}, // Jan, 2006/11/16 ++ {TX_RTY_CFG, 0x47d01f0f}, // Jan, 2006/11/16, Set TxWI->ACK =0 in Probe Rsp Modify for 2860E ,2007-08-03 ++ {AUTO_RSP_CFG, 0x00000013}, // Initial Auto_Responder, because QA will turn off Auto-Responder ++ {CCK_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. ++ {OFDM_PROT_CFG, 0x05740003 /*0x01740003*/}, // Initial Auto_Responder, because QA will turn off Auto-Responder. And RTS threshold is enabled. ++//PS packets use Tx1Q (for HCCA) when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++#ifdef RT2870 ++#ifdef CONFIG_STA_SUPPORT ++ {PBF_CFG, 0xf40006}, // Only enable Queue 2 ++#endif // CONFIG_STA_SUPPORT // ++ {MM40_PROT_CFG, 0x3F44084}, // Initial Auto_Responder, because QA will turn off Auto-Responder ++ {WPDMA_GLO_CFG, 0x00000030}, ++#endif // RT2870 // ++ {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS ++ {GF40_PROT_CFG, 0x03F44084}, ++ {MM20_PROT_CFG, 0x01744004}, ++ {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. ++ {TX_RTS_CFG, 0x00092b20}, ++//#ifdef WIFI_TEST ++ {EXP_ACK_TIME, 0x002400ca}, // default value ++//#else ++// {EXP_ACK_TIME, 0x005400ca}, // suggested by Gray @ 20070323 for 11n intel-sta throughput ++//#endif // end - WIFI_TEST // ++ {TXOP_HLDR_ET, 0x00000002}, ++ ++ /* Jerry comments 2008/01/16: we use SIFS = 10us in CCK defaultly, but it seems that 10us ++ is too small for INTEL 2200bg card, so in MBSS mode, the delta time between beacon0 ++ and beacon1 is SIFS (10us), so if INTEL 2200bg card connects to BSS0, the ping ++ will always lost. So we change the SIFS of CCK from 10us to 16us. */ ++ {XIFS_TIME_CFG, 0x33a41010}, ++ {PWR_PIN_CFG, 0x00000003}, // patch for 2880-E ++}; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++RTMP_REG_PAIR STAMACRegTable[] = { ++ {WMM_AIFSN_CFG, 0x00002273}, ++ {WMM_CWMIN_CFG, 0x00002344}, ++ {WMM_CWMAX_CFG, 0x000034aa}, ++}; ++#endif // CONFIG_STA_SUPPORT // ++ ++#define NUM_MAC_REG_PARMS (sizeof(MACRegTable) / sizeof(RTMP_REG_PAIR)) ++#ifdef CONFIG_STA_SUPPORT ++#define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RT2870 ++// ++// RT2870 Firmware Spec only used 1 oct for version expression ++// ++#define FIRMWARE_MINOR_VERSION 7 ++ ++#endif // RT2870 // ++ ++// New 8k byte firmware size for RT3071/RT3072 ++#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 ++#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) ++#define FIRMWARE_MAJOR_VERSION 0 ++ ++#define FIRMWAREIMAGEV1_LENGTH 0x1000 ++#define FIRMWAREIMAGEV2_LENGTH 0x1000 ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Allocate RTMP_ADAPTER data block and do some initialization ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPAllocAdapterBlock( ++ IN PVOID handle, ++ OUT PRTMP_ADAPTER *ppAdapter) ++{ ++ PRTMP_ADAPTER pAd; ++ NDIS_STATUS Status; ++ INT index; ++ UCHAR *pBeaconBuf = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocAdapterBlock\n")); ++ ++ *ppAdapter = NULL; ++ ++ do ++ { ++ // Allocate RTMP_ADAPTER memory block ++ pBeaconBuf = kmalloc(MAX_BEACON_SIZE, MEM_ALLOC_FLAG); ++ if (pBeaconBuf == NULL) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ DBGPRINT_ERR(("Failed to allocate memory - BeaconBuf!\n")); ++ break; ++ } ++ ++ Status = AdapterBlockAllocateMemory(handle, (PVOID *)&pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("Failed to allocate memory - ADAPTER\n")); ++ break; ++ } ++ pAd->BeaconBuf = pBeaconBuf; ++ printk("\n\n=== pAd = %p, size = %d ===\n\n", pAd, (UINT32)sizeof(RTMP_ADAPTER)); ++ ++ ++ // Init spin locks ++ NdisAllocateSpinLock(&pAd->MgmtRingLock); ++ ++ for (index =0 ; index < NUM_OF_TX_RING; index++) ++ { ++ NdisAllocateSpinLock(&pAd->TxSwQueueLock[index]); ++ NdisAllocateSpinLock(&pAd->DeQueueLock[index]); ++ pAd->DeQueueRunning[index] = FALSE; ++ } ++ ++ NdisAllocateSpinLock(&pAd->irq_lock); ++ ++ } while (FALSE); ++ ++ if ((Status != NDIS_STATUS_SUCCESS) && (pBeaconBuf)) ++ kfree(pBeaconBuf); ++ ++ *ppAdapter = pAd; ++ ++ DBGPRINT_S(Status, ("<-- RTMPAllocAdapterBlock, Status=%x\n", Status)); ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial Tx power per MCS and BW from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReadTxPwrPerRate( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG data, Adata, Gdata; ++ USHORT i, value, value2; ++ INT Apwrdelta, Gpwrdelta; ++ UCHAR t1,t2,t3,t4; ++ BOOLEAN bValid, bApwrdeltaMinus = TRUE, bGpwrdeltaMinus = TRUE; ++ ++ // ++ // Get power delta for 20MHz and 40MHz. ++ // ++ DBGPRINT(RT_DEBUG_TRACE, ("Txpower per Rate\n")); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_DELTA, value2); ++ Apwrdelta = 0; ++ Gpwrdelta = 0; ++ ++ if ((value2 & 0xff) != 0xff) ++ { ++ if ((value2 & 0x80)) ++ Gpwrdelta = (value2&0xf); ++ ++ if ((value2 & 0x40)) ++ bGpwrdeltaMinus = FALSE; ++ else ++ bGpwrdeltaMinus = TRUE; ++ } ++ if ((value2 & 0xff00) != 0xff00) ++ { ++ if ((value2 & 0x8000)) ++ Apwrdelta = ((value2&0xf00)>>8); ++ ++ if ((value2 & 0x4000)) ++ bApwrdeltaMinus = FALSE; ++ else ++ bApwrdeltaMinus = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Gpwrdelta = %x, Apwrdelta = %x .\n", Gpwrdelta, Apwrdelta)); ++ ++ // ++ // Get Txpower per MCS for 20MHz in 2.4G. ++ // ++ for (i=0; i<5; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4, value); ++ data = value; ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_2_4G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ data |= (value<<16); ++ ++ pAd->Tx20MPwrCfgABand[i] = pAd->Tx40MPwrCfgABand[i] = Adata; ++ pAd->Tx20MPwrCfgGBand[i] = pAd->Tx40MPwrCfgGBand[i] = Gdata; ++ ++ if (data != 0xffffffff) ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, data); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 2.4G band-%lx, Adata = %lx, Gdata = %lx \n", data, Adata, Gdata)); ++ } ++ ++ // ++ // Check this block is valid for 40MHz in 2.4G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 40MHz in 2.4G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4, value); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_2_4G + i*4 + 2, value); ++ if (bGpwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Gpwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Gpwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Gpwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Gpwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Gpwrdelta) ++ t1 = (value&0xf)-(Gpwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Gpwrdelta) ++ t2 = ((value&0xf0)>>4)-(Gpwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Gpwrdelta) ++ t3 = ((value&0xf00)>>8)-(Gpwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Gpwrdelta) ++ t4 = ((value&0xf000)>>12)-(Gpwrdelta); ++ else ++ t4 = 0; ++ } ++ Gdata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx40MPwrCfgGBand[i+1] = (pAd->Tx40MPwrCfgGBand[i+1] & 0x0000FFFF) | (Gdata & 0xFFFF0000); ++ else ++ pAd->Tx40MPwrCfgGBand[i+1] = Gdata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 2.4G band, Gdata = %lx \n", Gdata)); ++ } ++ } ++ ++ // ++ // Check this block is valid for 20MHz in 5G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 20MHz in 5G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<5; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_20MHZ_5G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx20MPwrCfgABand[i] = (pAd->Tx20MPwrCfgABand[i] & 0x0000FFFF) | (Adata & 0xFFFF0000); ++ else ++ pAd->Tx20MPwrCfgABand[i] = Adata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("20MHz BW, 5GHz band, Adata = %lx \n", Adata)); ++ } ++ } ++ ++ // ++ // Check this block is valid for 40MHz in 5G. If invalid, use parameter for 20MHz in 2.4G ++ // ++ bValid = TRUE; ++ for (i=0; i<6; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + 2 + i*2, value); ++ if (((value & 0x00FF) == 0x00FF) || ((value & 0xFF00) == 0xFF00)) ++ { ++ bValid = FALSE; ++ break; ++ } ++ } ++ ++ // ++ // Get Txpower per MCS for 40MHz in 5G. ++ // ++ if (bValid) ++ { ++ for (i=0; i<4; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata = t1 + (t2<<4) + (t3<<8) + (t4<<12); ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_TXPOWER_BYRATE_40MHZ_5G + i*4 + 2, value); ++ if (bApwrdeltaMinus == FALSE) ++ { ++ t1 = (value&0xf)+(Apwrdelta); ++ if (t1 > 0xf) ++ t1 = 0xf; ++ t2 = ((value&0xf0)>>4)+(Apwrdelta); ++ if (t2 > 0xf) ++ t2 = 0xf; ++ t3 = ((value&0xf00)>>8)+(Apwrdelta); ++ if (t3 > 0xf) ++ t3 = 0xf; ++ t4 = ((value&0xf000)>>12)+(Apwrdelta); ++ if (t4 > 0xf) ++ t4 = 0xf; ++ } ++ else ++ { ++ if ((value&0xf) > Apwrdelta) ++ t1 = (value&0xf)-(Apwrdelta); ++ else ++ t1 = 0; ++ if (((value&0xf0)>>4) > Apwrdelta) ++ t2 = ((value&0xf0)>>4)-(Apwrdelta); ++ else ++ t2 = 0; ++ if (((value&0xf00)>>8) > Apwrdelta) ++ t3 = ((value&0xf00)>>8)-(Apwrdelta); ++ else ++ t3 = 0; ++ if (((value&0xf000)>>12) > Apwrdelta) ++ t4 = ((value&0xf000)>>12)-(Apwrdelta); ++ else ++ t4 = 0; ++ } ++ Adata |= ((t1<<16) + (t2<<20) + (t3<<24) + (t4<<28)); ++ ++ if (i == 0) ++ pAd->Tx40MPwrCfgABand[i+1] = (pAd->Tx40MPwrCfgABand[i+1] & 0x0000FFFF) | (Adata & 0xFFFF0000); ++ else ++ pAd->Tx40MPwrCfgABand[i+1] = Adata; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("40MHz BW, 5GHz band, Adata = %lx \n", Adata)); ++ } ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial channel power parameters from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReadChannelPwr( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR i, choffset; ++ EEPROM_TX_PWR_STRUC Power; ++ EEPROM_TX_PWR_STRUC Power2; ++ ++ // Read Tx power value for all channels ++ // Value from 1 - 0x7f. Default value is 24. ++ // Power value : 2.4G 0x00 (0) ~ 0x1F (31) ++ // : 5.5G 0xF9 (-7) ~ 0x0F (15) ++ ++ // 0. 11b/g, ch1 - ch 14 ++ for (i = 0; i < 7; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX_PWR_OFFSET + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_G_TX2_PWR_OFFSET + i * 2, Power2.word); ++ pAd->TxPower[i * 2].Channel = i * 2 + 1; ++ pAd->TxPower[i * 2 + 1].Channel = i * 2 + 2; ++ ++ if ((Power.field.Byte0 > 31) || (Power.field.Byte0 < 0)) ++ pAd->TxPower[i * 2].Power = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 > 31) || (Power.field.Byte1 < 0)) ++ pAd->TxPower[i * 2 + 1].Power = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2 + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 > 31) || (Power2.field.Byte0 < 0)) ++ pAd->TxPower[i * 2].Power2 = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 > 31) || (Power2.field.Byte1 < 0)) ++ pAd->TxPower[i * 2 + 1].Power2 = DEFAULT_RF_TX_POWER; ++ else ++ pAd->TxPower[i * 2 + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 1. U-NII lower/middle band: 36, 38, 40; 44, 46, 48; 52, 54, 56; 60, 62, 64 (including central frequency in BW 40MHz) ++ // 1.1 Fill up channel ++ choffset = 14; ++ for (i = 0; i < 4; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 36 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 36 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 36 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ ++ // 1.2 Fill up power ++ for (i = 0; i < 6; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 2. HipperLAN 2 100, 102 ,104; 108, 110, 112; 116, 118, 120; 124, 126, 128; 132, 134, 136; 140 (including central frequency in BW 40MHz) ++ // 2.1 Fill up channel ++ choffset = 14 + 12; ++ for (i = 0; i < 5; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 100 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 100 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 100 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ pAd->TxPower[3 * 5 + choffset + 0].Channel = 140; ++ pAd->TxPower[3 * 5 + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * 5 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ // 2.2 Fill up power ++ for (i = 0; i < 8; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 3. U-NII upper band: 149, 151, 153; 157, 159, 161; 165 (including central frequency in BW 40MHz) ++ // 3.1 Fill up channel ++ choffset = 14 + 12 + 16; ++ for (i = 0; i < 2; i++) ++ { ++ pAd->TxPower[3 * i + choffset + 0].Channel = 149 + i * 8 + 0; ++ pAd->TxPower[3 * i + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 1].Channel = 149 + i * 8 + 2; ++ pAd->TxPower[3 * i + choffset + 1].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 1].Power2 = DEFAULT_RF_TX_POWER; ++ ++ pAd->TxPower[3 * i + choffset + 2].Channel = 149 + i * 8 + 4; ++ pAd->TxPower[3 * i + choffset + 2].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * i + choffset + 2].Power2 = DEFAULT_RF_TX_POWER; ++ } ++ pAd->TxPower[3 * 2 + choffset + 0].Channel = 165; ++ pAd->TxPower[3 * 2 + choffset + 0].Power = DEFAULT_RF_TX_POWER; ++ pAd->TxPower[3 * 2 + choffset + 0].Power2 = DEFAULT_RF_TX_POWER; ++ ++ // 3.2 Fill up power ++ for (i = 0; i < 4; i++) ++ { ++// Power.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2); ++// Power2.word = RTMP_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX_PWR_OFFSET + (choffset - 14) + i * 2, Power.word); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_A_TX2_PWR_OFFSET + (choffset - 14) + i * 2, Power2.word); ++ ++ if ((Power.field.Byte0 < 16) && (Power.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power = Power.field.Byte0; ++ ++ if ((Power.field.Byte1 < 16) && (Power.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power = Power.field.Byte1; ++ ++ if ((Power2.field.Byte0 < 16) && (Power2.field.Byte0 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 0].Power2 = Power2.field.Byte0; ++ ++ if ((Power2.field.Byte1 < 16) && (Power2.field.Byte1 >= -7)) ++ pAd->TxPower[i * 2 + choffset + 1].Power2 = Power2.field.Byte1; ++ } ++ ++ // 4. Print and Debug ++ choffset = 14 + 12 + 16 + 7; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read the following from the registry ++ 1. All the parameters ++ 2. NetworkAddres ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ WrapperConfigurationContext For use by NdisOpenConfiguration ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ NDIS_STATUS_RESOURCES ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICReadRegParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ DBGPRINT_S(Status, ("<-- NICReadRegParameters, Status=%x\n", Status)); ++ return Status; ++} ++ ++ ++#ifdef RT30xx ++/* ++ ======================================================================== ++ ++ Routine Description: ++ For RF filter calibration purpose ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPFilterCalibration( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR R55x = 0, value, FilterTarget = 0x1E, BBPValue=0; ++ UINT loop = 0, count = 0, loopcnt = 0, ReTry = 0; ++ UCHAR RF_R24_Value = 0; ++ ++ // Give bbp filter initial value ++ pAd->Mlme.CaliBW20RfR24 = 0x1F; ++ pAd->Mlme.CaliBW40RfR24 = 0x2F; //Bit[5] must be 1 for BW 40 ++ ++ do ++ { ++ if (loop == 1) //BandWidth = 40 MHz ++ { ++ // Write 0x27 to RF_R24 to program filter ++ RF_R24_Value = 0x27; ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ if (IS_RT3090(pAd)) ++ FilterTarget = 0x15; ++ else ++ FilterTarget = 0x19; ++ ++ // when calibrate BW40, BBP mask must set to BW40. ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ BBPValue|= (0x10); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ ++ // set to BW40 ++ RT30xxReadRFRegister(pAd, RF_R31, &value); ++ value |= 0x20; ++ RT30xxWriteRFRegister(pAd, RF_R31, value); ++ } ++ else //BandWidth = 20 MHz ++ { ++ // Write 0x07 to RF_R24 to program filter ++ RF_R24_Value = 0x07; ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ if (IS_RT3090(pAd)) ++ FilterTarget = 0x13; ++ else ++ FilterTarget = 0x16; ++ ++ // set to BW20 ++ RT30xxReadRFRegister(pAd, RF_R31, &value); ++ value &= (~0x20); ++ RT30xxWriteRFRegister(pAd, RF_R31, value); ++ } ++ ++ // Write 0x01 to RF_R22 to enable baseband loopback mode ++ RT30xxReadRFRegister(pAd, RF_R22, &value); ++ value |= 0x01; ++ RT30xxWriteRFRegister(pAd, RF_R22, value); ++ ++ // Write 0x00 to BBP_R24 to set power & frequency of passband test tone ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0); ++ ++ do ++ { ++ // Write 0x90 to BBP_R25 to transmit test tone ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R25, 0x90); ++ ++ RTMPusecDelay(1000); ++ // Read BBP_R55[6:0] for received power, set R55x = BBP_R55[6:0] ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R55, &value); ++ R55x = value & 0xFF; ++ ++ } while ((ReTry++ < 100) && (R55x == 0)); ++ ++ // Write 0x06 to BBP_R24 to set power & frequency of stopband test tone ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0x06); ++ ++ while(TRUE) ++ { ++ // Write 0x90 to BBP_R25 to transmit test tone ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R25, 0x90); ++ ++ //We need to wait for calibration ++ RTMPusecDelay(1000); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R55, &value); ++ value &= 0xFF; ++ if ((R55x - value) < FilterTarget) ++ { ++ RF_R24_Value ++; ++ } ++ else if ((R55x - value) == FilterTarget) ++ { ++ RF_R24_Value ++; ++ count ++; ++ } ++ else ++ { ++ break; ++ } ++ ++ // prevent infinite loop cause driver hang. ++ if (loopcnt++ > 100) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPFilterCalibration - can't find a valid value, loopcnt=%d stop calibrating", loopcnt)); ++ break; ++ } ++ ++ // Write RF_R24 to program filter ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ } ++ ++ if (count > 0) ++ { ++ RF_R24_Value = RF_R24_Value - ((count) ? (1) : (0)); ++ } ++ ++ // Store for future usage ++ if (loopcnt < 100) ++ { ++ if (loop++ == 0) ++ { ++ //BandWidth = 20 MHz ++ pAd->Mlme.CaliBW20RfR24 = (UCHAR)RF_R24_Value; ++ } ++ else ++ { ++ //BandWidth = 40 MHz ++ pAd->Mlme.CaliBW40RfR24 = (UCHAR)RF_R24_Value; ++ break; ++ } ++ } ++ else ++ break; ++ ++ RT30xxWriteRFRegister(pAd, RF_R24, RF_R24_Value); ++ ++ // reset count ++ count = 0; ++ } while(TRUE); ++ ++ // ++ // Set back to initial state ++ // ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, 0); ++ ++ RT30xxReadRFRegister(pAd, RF_R22, &value); ++ value &= ~(0x01); ++ RT30xxWriteRFRegister(pAd, RF_R22, value); ++ ++ // set BBP back to BW20 ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue&= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPFilterCalibration - CaliBW20RfR24=0x%x, CaliBW40RfR24=0x%x\n", pAd->Mlme.CaliBW20RfR24, pAd->Mlme.CaliBW40RfR24)); ++} ++#endif // RT30xx // ++ ++ ++#ifdef RT3070 ++VOID NICInitRT30xxRFRegisters(IN PRTMP_ADAPTER pAd) ++{ ++ INT i; ++ // Driver must read EEPROM to get RfIcType before initial RF registers ++ // Initialize RF register to default value ++ if (IS_RT3070(pAd) || IS_RT3071(pAd)) ++ { ++ // Init RF calibration ++ // Driver should toggle RF R30 bit7 before init RF registers ++ UINT32 RfReg = 0; ++ UINT32 data; ++ ++ RT30xxReadRFRegister(pAd, RF_R30, (PUCHAR)&RfReg); ++ RfReg |= 0x80; ++ RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); ++ RTMPusecDelay(1000); ++ RfReg &= 0x7F; ++ RT30xxWriteRFRegister(pAd, RF_R30, (UCHAR)RfReg); ++ ++ // Initialize RF register to default value ++ for (i = 0; i < NUM_RF_REG_PARMS; i++) ++ { ++ RT30xxWriteRFRegister(pAd, RT30xx_RFRegTable[i].Register, RT30xx_RFRegTable[i].Value); ++ } ++ ++ // add by johnli ++ if (IS_RT3070(pAd)) ++ { ++ // Update MAC 0x05D4 from 01xxxxxx to 0Dxxxxxx (voltage 1.2V to 1.35V) for RT3070 to improve yield rate ++ RTUSBReadMACRegister(pAd, LDO_CFG0, &data); ++ data = ((data & 0xF0FFFFFF) | 0x0D000000); ++ RTUSBWriteMACRegister(pAd, LDO_CFG0, data); ++ } ++ else if (IS_RT3071(pAd)) ++ { ++ // Driver should set RF R6 bit6 on before init RF registers ++ RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RfReg); ++ RfReg |= 0x40; ++ RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RfReg); ++ ++ // init R31 ++ RT30xxWriteRFRegister(pAd, RF_R31, 0x14); ++ ++ // RT3071 version E has fixed this issue ++ if ((pAd->NicConfig2.field.DACTestBit == 1) && ((pAd->MACVersion & 0xffff) < 0x0211)) ++ { ++ // patch tx EVM issue temporarily ++ RTUSBReadMACRegister(pAd, LDO_CFG0, &data); ++ data = ((data & 0xE0FFFFFF) | 0x0D000000); ++ RTUSBWriteMACRegister(pAd, LDO_CFG0, data); ++ } ++ else ++ { ++ RTMP_IO_READ32(pAd, LDO_CFG0, &data); ++ data = ((data & 0xE0FFFFFF) | 0x01000000); ++ RTMP_IO_WRITE32(pAd, LDO_CFG0, data); ++ } ++ ++ // patch LNA_PE_G1 failed issue ++ RTUSBReadMACRegister(pAd, GPIO_SWITCH, &data); ++ data &= ~(0x20); ++ RTUSBWriteMACRegister(pAd, GPIO_SWITCH, data); ++ } ++ ++ //For RF filter Calibration ++ RTMPFilterCalibration(pAd); ++ ++ // Initialize RF R27 register, set RF R27 must be behind RTMPFilterCalibration() ++ if ((pAd->MACVersion & 0xffff) < 0x0211) ++ RT30xxWriteRFRegister(pAd, RF_R27, 0x3); ++ ++ // set led open drain enable ++ RTUSBReadMACRegister(pAd, OPT_14, &data); ++ data |= 0x01; ++ RTUSBWriteMACRegister(pAd, OPT_14, data); ++ ++ if (IS_RT3071(pAd)) ++ { ++ // add by johnli, RF power sequence setup, load RF normal operation-mode setup ++ RT30xxLoadRFNormalModeSetup(pAd); ++ } ++ } ++ ++} ++#endif // RT3070 // ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read initial parameters from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NICReadEEPROMParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mac_addr) ++{ ++ UINT32 data = 0; ++ USHORT i, value, value2; ++ UCHAR TmpPhy; ++ EEPROM_TX_PWR_STRUC Power; ++ EEPROM_VERSION_STRUC Version; ++ EEPROM_ANTENNA_STRUC Antenna; ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICReadEEPROMParameters\n")); ++ ++ // Init EEPROM Address Number, before access EEPROM; if 93c46, EEPROMAddressNum=6, else if 93c66, EEPROMAddressNum=8 ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &data); ++ DBGPRINT(RT_DEBUG_TRACE, ("--> E2PROM_CSR = 0x%x\n", data)); ++ ++ if((data & 0x30) == 0) ++ pAd->EEPROMAddressNum = 6; // 93C46 ++ else if((data & 0x30) == 0x10) ++ pAd->EEPROMAddressNum = 8; // 93C66 ++ else ++ pAd->EEPROMAddressNum = 8; // 93C86 ++ DBGPRINT(RT_DEBUG_TRACE, ("--> EEPROMAddressNum = %d\n", pAd->EEPROMAddressNum )); ++ ++ // RT2860 MAC no longer auto load MAC address from E2PROM. Driver has to intialize ++ // MAC address registers according to E2PROM setting ++ if (mac_addr == NULL || ++ strlen(mac_addr) != 17 || ++ mac_addr[2] != ':' || mac_addr[5] != ':' || mac_addr[8] != ':' || ++ mac_addr[11] != ':' || mac_addr[14] != ':') ++ { ++ USHORT Addr01,Addr23,Addr45 ; ++ ++ RT28xx_EEPROM_READ16(pAd, 0x04, Addr01); ++ RT28xx_EEPROM_READ16(pAd, 0x06, Addr23); ++ RT28xx_EEPROM_READ16(pAd, 0x08, Addr45); ++ ++ pAd->PermanentAddress[0] = (UCHAR)(Addr01 & 0xff); ++ pAd->PermanentAddress[1] = (UCHAR)(Addr01 >> 8); ++ pAd->PermanentAddress[2] = (UCHAR)(Addr23 & 0xff); ++ pAd->PermanentAddress[3] = (UCHAR)(Addr23 >> 8); ++ pAd->PermanentAddress[4] = (UCHAR)(Addr45 & 0xff); ++ pAd->PermanentAddress[5] = (UCHAR)(Addr45 >> 8); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from E2PROM \n")); ++ } ++ else ++ { ++ INT j; ++ PUCHAR macptr; ++ ++ macptr = mac_addr; ++ ++ for (j=0; jPermanentAddress[j], 1); ++ macptr=macptr+3; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Initialize MAC Address from module parameter \n")); ++ } ++ ++ ++ { ++ //more conveninet to test mbssid, so ap's bssid &0xf1 ++ if (pAd->PermanentAddress[0] == 0xff) ++ pAd->PermanentAddress[0] = RandomByte(pAd)&0xf8; ++ ++ //if (pAd->PermanentAddress[5] == 0xff) ++ // pAd->PermanentAddress[5] = RandomByte(pAd)&0xf8; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->PermanentAddress[0], pAd->PermanentAddress[1], ++ pAd->PermanentAddress[2], pAd->PermanentAddress[3], ++ pAd->PermanentAddress[4], pAd->PermanentAddress[5])); ++ if (pAd->bLocalAdminMAC == FALSE) ++ { ++ MAC_DW0_STRUC csr2; ++ MAC_DW1_STRUC csr3; ++ COPY_MAC_ADDR(pAd->CurrentAddress, pAd->PermanentAddress); ++ csr2.field.Byte0 = pAd->CurrentAddress[0]; ++ csr2.field.Byte1 = pAd->CurrentAddress[1]; ++ csr2.field.Byte2 = pAd->CurrentAddress[2]; ++ csr2.field.Byte3 = pAd->CurrentAddress[3]; ++ RTMP_IO_WRITE32(pAd, MAC_ADDR_DW0, csr2.word); ++ csr3.word = 0; ++ csr3.field.Byte4 = pAd->CurrentAddress[4]; ++ csr3.field.Byte5 = pAd->CurrentAddress[5]; ++ csr3.field.U2MeMask = 0xff; ++ RTMP_IO_WRITE32(pAd, MAC_ADDR_DW1, csr3.word); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("E2PROM MAC: =%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->PermanentAddress[0], pAd->PermanentAddress[1], ++ pAd->PermanentAddress[2], pAd->PermanentAddress[3], ++ pAd->PermanentAddress[4], pAd->PermanentAddress[5])); ++ } ++ } ++ ++ // if not return early. cause fail at emulation. ++ // Init the channel number for TX channel power ++ RTMPReadChannelPwr(pAd); ++ ++ // if E2PROM version mismatch with driver's expectation, then skip ++ // all subsequent E2RPOM retieval and set a system error bit to notify GUI ++ RT28xx_EEPROM_READ16(pAd, EEPROM_VERSION_OFFSET, Version.word); ++ pAd->EepromVersion = Version.field.Version + Version.field.FaeReleaseNumber * 256; ++ DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: Version = %d, FAE release #%d\n", Version.field.Version, Version.field.FaeReleaseNumber)); ++ ++ if (Version.field.Version > VALID_EEPROM_VERSION) ++ { ++ DBGPRINT_ERR(("E2PROM: WRONG VERSION 0x%x, should be %d\n",Version.field.Version, VALID_EEPROM_VERSION)); ++ /*pAd->SystemErrorBitmap |= 0x00000001; ++ ++ // hard-code default value when no proper E2PROM installed ++ pAd->bAutoTxAgcA = FALSE; ++ pAd->bAutoTxAgcG = FALSE; ++ ++ // Default the channel power ++ for (i = 0; i < MAX_NUM_OF_CHANNELS; i++) ++ pAd->TxPower[i].Power = DEFAULT_RF_TX_POWER; ++ ++ // Default the channel power ++ for (i = 0; i < MAX_NUM_OF_11JCHANNELS; i++) ++ pAd->TxPower11J[i].Power = DEFAULT_RF_TX_POWER; ++ ++ for(i = 0; i < NUM_EEPROM_BBP_PARMS; i++) ++ pAd->EEPROMDefaultValue[i] = 0xffff; ++ return; */ ++ } ++ ++ // Read BBP default value from EEPROM and store to array(EEPROMDefaultValue) in pAd ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, value); ++ pAd->EEPROMDefaultValue[0] = value; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC2_OFFSET, value); ++ pAd->EEPROMDefaultValue[1] = value; ++ ++ RT28xx_EEPROM_READ16(pAd, 0x38, value); // Country Region ++ pAd->EEPROMDefaultValue[2] = value; ++ ++ for(i = 0; i < 8; i++) ++ { ++ RT28xx_EEPROM_READ16(pAd, EEPROM_BBP_BASE_OFFSET + i*2, value); ++ pAd->EEPROMDefaultValue[i+3] = value; ++ } ++ ++ // We have to parse NIC configuration 0 at here. ++ // If TSSI did not have preloaded value, it should reset the TxAutoAgc to false ++ // Therefore, we have to read TxAutoAgc control beforehand. ++ // Read Tx AGC control bit ++ Antenna.word = pAd->EEPROMDefaultValue[0]; ++ if (Antenna.word == 0xFFFF) ++ { ++#ifdef RT30xx ++ if(IS_RT3090(pAd)) ++ { ++ Antenna.word = 0; ++ Antenna.field.RfIcType = RFIC_3020; ++ Antenna.field.TxPath = 1; ++ Antenna.field.RxPath = 1; ++ } ++ else ++ { ++#endif // RT30xx // ++ Antenna.word = 0; ++ Antenna.field.RfIcType = RFIC_2820; ++ Antenna.field.TxPath = 1; ++ Antenna.field.RxPath = 2; ++ DBGPRINT(RT_DEBUG_WARN, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); ++#ifdef RT30xx ++ } ++#endif // RT30xx // ++ } ++ ++ // Choose the desired Tx&Rx stream. ++ if ((pAd->CommonCfg.TxStream == 0) || (pAd->CommonCfg.TxStream > Antenna.field.TxPath)) ++ pAd->CommonCfg.TxStream = Antenna.field.TxPath; ++ ++ if ((pAd->CommonCfg.RxStream == 0) || (pAd->CommonCfg.RxStream > Antenna.field.RxPath)) ++ { ++ pAd->CommonCfg.RxStream = Antenna.field.RxPath; ++ ++ if ((pAd->MACVersion < RALINK_2883_VERSION) && ++ (pAd->CommonCfg.RxStream > 2)) ++ { ++ // only 2 Rx streams for RT2860 series ++ pAd->CommonCfg.RxStream = 2; ++ } ++ } ++ ++ // 3*3 ++ // read value from EEPROM and set them to CSR174 ~ 177 in chain0 ~ chain2 ++ // yet implement ++ for(i=0; i<3; i++) ++ { ++ } ++ ++ NicConfig2.word = pAd->EEPROMDefaultValue[1]; ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((NicConfig2.word & 0x00ff) == 0xff) ++ { ++ NicConfig2.word &= 0xff00; ++ } ++ ++ if ((NicConfig2.word >> 8) == 0xff) ++ { ++ NicConfig2.word &= 0x00ff; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (NicConfig2.field.DynamicTxAgcControl == 1) ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; ++ else ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("NICReadEEPROMParameters: RxPath = %d, TxPath = %d\n", Antenna.field.RxPath, Antenna.field.TxPath)); ++ ++ // Save the antenna for future use ++ pAd->Antenna.word = Antenna.word; ++ ++ // ++ // Reset PhyMode if we don't support 802.11a ++ // Only RFIC_2850 & RFIC_2750 support 802.11a ++ // ++ if ((Antenna.field.RfIcType != RFIC_2850) && (Antenna.field.RfIcType != RFIC_2750)) ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11ABG_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11A)) ++ pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; ++#ifdef DOT11_N_SUPPORT ++ else if ((pAd->CommonCfg.PhyMode == PHY_11ABGN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11AN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11AGN_MIXED) || ++ (pAd->CommonCfg.PhyMode == PHY_11N_5G)) ++ pAd->CommonCfg.PhyMode = PHY_11BGN_MIXED; ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ // Read TSSI reference and TSSI boundary for temperature compensation. This is ugly ++ // 0. 11b/g ++ { ++ /* these are tempature reference value (0x00 ~ 0xFE) ++ ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ TssiPlusBoundaryG [4] [3] [2] [1] [0] (smaller) + ++ TssiMinusBoundaryG[0] [1] [2] [3] [4] (larger) */ ++ RT28xx_EEPROM_READ16(pAd, 0x6E, Power.word); ++ pAd->TssiMinusBoundaryG[4] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryG[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x70, Power.word); ++ pAd->TssiMinusBoundaryG[2] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryG[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x72, Power.word); ++ pAd->TssiRefG = Power.field.Byte0; /* reference value [0] */ ++ pAd->TssiPlusBoundaryG[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x74, Power.word); ++ pAd->TssiPlusBoundaryG[2] = Power.field.Byte0; ++ pAd->TssiPlusBoundaryG[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0x76, Power.word); ++ pAd->TssiPlusBoundaryG[4] = Power.field.Byte0; ++ pAd->TxAgcStepG = Power.field.Byte1; ++ pAd->TxAgcCompensateG = 0; ++ pAd->TssiMinusBoundaryG[0] = pAd->TssiRefG; ++ pAd->TssiPlusBoundaryG[0] = pAd->TssiRefG; ++ ++ // Disable TxAgc if the based value is not right ++ if (pAd->TssiRefG == 0xff) ++ pAd->bAutoTxAgcG = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("E2PROM: G Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", ++ pAd->TssiMinusBoundaryG[4], pAd->TssiMinusBoundaryG[3], pAd->TssiMinusBoundaryG[2], pAd->TssiMinusBoundaryG[1], ++ pAd->TssiRefG, ++ pAd->TssiPlusBoundaryG[1], pAd->TssiPlusBoundaryG[2], pAd->TssiPlusBoundaryG[3], pAd->TssiPlusBoundaryG[4], ++ pAd->TxAgcStepG, pAd->bAutoTxAgcG)); ++ } ++ // 1. 11a ++ { ++ RT28xx_EEPROM_READ16(pAd, 0xD4, Power.word); ++ pAd->TssiMinusBoundaryA[4] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryA[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xD6, Power.word); ++ pAd->TssiMinusBoundaryA[2] = Power.field.Byte0; ++ pAd->TssiMinusBoundaryA[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xD8, Power.word); ++ pAd->TssiRefA = Power.field.Byte0; ++ pAd->TssiPlusBoundaryA[1] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xDA, Power.word); ++ pAd->TssiPlusBoundaryA[2] = Power.field.Byte0; ++ pAd->TssiPlusBoundaryA[3] = Power.field.Byte1; ++ RT28xx_EEPROM_READ16(pAd, 0xDC, Power.word); ++ pAd->TssiPlusBoundaryA[4] = Power.field.Byte0; ++ pAd->TxAgcStepA = Power.field.Byte1; ++ pAd->TxAgcCompensateA = 0; ++ pAd->TssiMinusBoundaryA[0] = pAd->TssiRefA; ++ pAd->TssiPlusBoundaryA[0] = pAd->TssiRefA; ++ ++ // Disable TxAgc if the based value is not right ++ if (pAd->TssiRefA == 0xff) ++ pAd->bAutoTxAgcA = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("E2PROM: A Tssi[-4 .. +4] = %d %d %d %d - %d -%d %d %d %d, step=%d, tuning=%d\n", ++ pAd->TssiMinusBoundaryA[4], pAd->TssiMinusBoundaryA[3], pAd->TssiMinusBoundaryA[2], pAd->TssiMinusBoundaryA[1], ++ pAd->TssiRefA, ++ pAd->TssiPlusBoundaryA[1], pAd->TssiPlusBoundaryA[2], pAd->TssiPlusBoundaryA[3], pAd->TssiPlusBoundaryA[4], ++ pAd->TxAgcStepA, pAd->bAutoTxAgcA)); ++ } ++ pAd->BbpRssiToDbmDelta = 0x0; ++ ++ // Read frequency offset setting for RF ++ RT28xx_EEPROM_READ16(pAd, EEPROM_FREQ_OFFSET, value); ++ if ((value & 0x00FF) != 0x00FF) ++ pAd->RfFreqOffset = (ULONG) (value & 0x00FF); ++ else ++ pAd->RfFreqOffset = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("E2PROM: RF FreqOffset=0x%lx \n", pAd->RfFreqOffset)); ++ ++ //CountryRegion byte offset (38h) ++ value = pAd->EEPROMDefaultValue[2] >> 8; // 2.4G band ++ value2 = pAd->EEPROMDefaultValue[2] & 0x00FF; // 5G band ++ ++ if ((value <= REGION_MAXIMUM_BG_BAND) && (value2 <= REGION_MAXIMUM_A_BAND)) ++ { ++ pAd->CommonCfg.CountryRegion = ((UCHAR) value) | 0x80; ++ pAd->CommonCfg.CountryRegionForABand = ((UCHAR) value2) | 0x80; ++ TmpPhy = pAd->CommonCfg.PhyMode; ++ pAd->CommonCfg.PhyMode = 0xff; ++ RTMPSetPhyMode(pAd, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ // ++ // Get RSSI Offset on EEPROM 0x9Ah & 0x9Ch. ++ // The valid value are (-10 ~ 10) ++ // ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, value); ++ pAd->BGRssiOffset0 = value & 0x00ff; ++ pAd->BGRssiOffset1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET+2, value); ++ pAd->BGRssiOffset2 = value & 0x00ff; ++ pAd->ALNAGain1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, value); ++ pAd->BLNAGain = value & 0x00ff; ++ pAd->ALNAGain0 = (value >> 8); ++ ++ // Validate 11b/g RSSI_0 offset. ++ if ((pAd->BGRssiOffset0 < -10) || (pAd->BGRssiOffset0 > 10)) ++ pAd->BGRssiOffset0 = 0; ++ ++ // Validate 11b/g RSSI_1 offset. ++ if ((pAd->BGRssiOffset1 < -10) || (pAd->BGRssiOffset1 > 10)) ++ pAd->BGRssiOffset1 = 0; ++ ++ // Validate 11b/g RSSI_2 offset. ++ if ((pAd->BGRssiOffset2 < -10) || (pAd->BGRssiOffset2 > 10)) ++ pAd->BGRssiOffset2 = 0; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, value); ++ pAd->ARssiOffset0 = value & 0x00ff; ++ pAd->ARssiOffset1 = (value >> 8); ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET+2), value); ++ pAd->ARssiOffset2 = value & 0x00ff; ++ pAd->ALNAGain2 = (value >> 8); ++ ++ if (((UCHAR)pAd->ALNAGain1 == 0xFF) || (pAd->ALNAGain1 == 0x00)) ++ pAd->ALNAGain1 = pAd->ALNAGain0; ++ if (((UCHAR)pAd->ALNAGain2 == 0xFF) || (pAd->ALNAGain2 == 0x00)) ++ pAd->ALNAGain2 = pAd->ALNAGain0; ++ ++ // Validate 11a RSSI_0 offset. ++ if ((pAd->ARssiOffset0 < -10) || (pAd->ARssiOffset0 > 10)) ++ pAd->ARssiOffset0 = 0; ++ ++ // Validate 11a RSSI_1 offset. ++ if ((pAd->ARssiOffset1 < -10) || (pAd->ARssiOffset1 > 10)) ++ pAd->ARssiOffset1 = 0; ++ ++ //Validate 11a RSSI_2 offset. ++ if ((pAd->ARssiOffset2 < -10) || (pAd->ARssiOffset2 > 10)) ++ pAd->ARssiOffset2 = 0; ++ ++ // ++ // Get LED Setting. ++ // ++ RT28xx_EEPROM_READ16(pAd, 0x3a, value); ++ pAd->LedCntl.word = (value&0xff00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED1_OFFSET, value); ++ pAd->Led1 = value; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED2_OFFSET, value); ++ pAd->Led2 = value; ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LED3_OFFSET, value); ++ pAd->Led3 = value; ++ ++ RTMPReadTxPwrPerRate(pAd); ++ ++#ifdef SINGLE_SKU ++ //pAd->CommonCfg.DefineMaxTxPwr = RTMP_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_DEFINE_MAX_TXPWR, pAd->CommonCfg.DefineMaxTxPwr); ++#endif // SINGLE_SKU // ++#ifdef RT30xx ++ if (IS_RT30xx(pAd)) ++ { ++ eFusePhysicalReadRegisters(pAd, EFUSE_TAG, 2, &value); ++ pAd->EFuseTag = (value & 0xff); ++ } ++#endif // RT30xx // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICReadEEPROMParameters\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set default value from EEPROM ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NICInitAsicFromEEPROM( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef CONFIG_STA_SUPPORT ++ UINT32 data = 0; ++ UCHAR BBPR1 = 0; ++#endif // CONFIG_STA_SUPPORT // ++ USHORT i; ++ EEPROM_ANTENNA_STRUC Antenna; ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ UCHAR BBPR3 = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitAsicFromEEPROM\n")); ++ for(i = 3; i < NUM_EEPROM_BBP_PARMS; i++) ++ { ++ UCHAR BbpRegIdx, BbpValue; ++ ++ if ((pAd->EEPROMDefaultValue[i] != 0xFFFF) && (pAd->EEPROMDefaultValue[i] != 0)) ++ { ++ BbpRegIdx = (UCHAR)(pAd->EEPROMDefaultValue[i] >> 8); ++ BbpValue = (UCHAR)(pAd->EEPROMDefaultValue[i] & 0xff); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BbpRegIdx, BbpValue); ++ } ++ } ++ ++ Antenna.word = pAd->EEPROMDefaultValue[0]; ++ if (Antenna.word == 0xFFFF) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("E2PROM error, hard code as 0x%04x\n", Antenna.word)); ++ BUG_ON(Antenna.word == 0xFFFF); ++ } ++ pAd->Mlme.RealRxPath = (UCHAR) Antenna.field.RxPath; ++ pAd->RfIcType = (UCHAR) Antenna.field.RfIcType; ++ ++ DBGPRINT(RT_DEBUG_WARN, ("pAd->RfIcType = %d, RealRxPath=%d, TxPath = %d\n", pAd->RfIcType, pAd->Mlme.RealRxPath,Antenna.field.TxPath)); ++ ++ // Save the antenna for future use ++ pAd->Antenna.word = Antenna.word; ++ ++ NicConfig2.word = pAd->EEPROMDefaultValue[1]; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((NicConfig2.word & 0x00ff) == 0xff) ++ { ++ NicConfig2.word &= 0xff00; ++ } ++ ++ if ((NicConfig2.word >> 8) == 0xff) ++ { ++ NicConfig2.word &= 0x00ff; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Save the antenna for future use ++ pAd->NicConfig2.word = NicConfig2.word; ++ ++ // set default antenna as main ++ if (pAd->RfIcType == RFIC_3020) ++ AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); ++ ++ // ++ // Send LED Setting to MCU. ++ // ++ if (pAd->LedCntl.word == 0xFF) ++ { ++ pAd->LedCntl.word = 0x01; ++ pAd->Led1 = 0x5555; ++ pAd->Led2 = 0x2221; ++ ++#ifdef RT2870 ++ pAd->Led3 = 0x5627; ++#endif // RT2870 // ++ } ++ ++ AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); ++ AsicSendCommandToMcu(pAd, 0x53, 0xff, (UCHAR)pAd->Led2, (UCHAR)(pAd->Led2 >> 8)); ++ AsicSendCommandToMcu(pAd, 0x54, 0xff, (UCHAR)pAd->Led3, (UCHAR)(pAd->Led3 >> 8)); ++ pAd->LedIndicatorStregth = 0xFF; ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, before link up ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Read Hardware controlled Radio state enable bit ++ if (NicConfig2.field.HardwareRadioControl == 1) ++ { ++ pAd->StaCfg.bHardwareRadio = TRUE; ++ ++ // Read GPIO pin2 as Hardware controlled radio state ++ RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); ++ if ((data & 0x04) == 0) ++ { ++ pAd->StaCfg.bHwRadio = FALSE; ++ pAd->StaCfg.bRadio = FALSE; ++// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ } ++ } ++ else ++ pAd->StaCfg.bHardwareRadio = FALSE; ++ ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ RTMPSetLED(pAd, LED_RADIO_OFF); ++ } ++ else ++ { ++ RTMPSetLED(pAd, LED_RADIO_ON); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Turn off patching for cardbus controller ++ if (NicConfig2.field.CardbusAcceleration == 1) ++ { ++// pAd->bTest1 = TRUE; ++ } ++ ++ if (NicConfig2.field.DynamicTxAgcControl == 1) ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = TRUE; ++ else ++ pAd->bAutoTxAgcA = pAd->bAutoTxAgcG = FALSE; ++ // ++ // Since BBP has been progamed, to make sure BBP setting will be ++ // upate inside of AsicAntennaSelect, so reset to UNKNOWN_BAND!! ++ // ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); ++ BBPR3 &= (~0x18); ++ if(pAd->Antenna.field.RxPath == 3) ++ { ++ BBPR3 |= (0x10); ++ } ++ else if(pAd->Antenna.field.RxPath == 2) ++ { ++ BBPR3 |= (0x8); ++ } ++ else if(pAd->Antenna.field.RxPath == 1) ++ { ++ BBPR3 |= (0x0); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Handle the difference when 1T ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BBPR1); ++ if(pAd->Antenna.field.TxPath == 1) ++ { ++ BBPR1 &= (~0x18); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BBPR1); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Use Hw Radio Control Pin=%d; if used Pin=%d;\n", pAd->CommonCfg.bHardwareRadio, pAd->CommonCfg.bHardwareRadio)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPath = %d, RxPath = %d, RFIC=%d, Polar+LED mode=%x\n", pAd->Antenna.field.TxPath, pAd->Antenna.field.RxPath, pAd->RfIcType, pAd->LedCntl.word)); ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitAsicFromEEPROM\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize NIC hardware ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICInitializeAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset) ++{ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ WPDMA_GLO_CFG_STRUC GloCfg; ++// INT_MASK_CSR_STRUC IntMask; ++ ULONG i =0, j=0; ++ AC_TXOP_CSR0_STRUC csr0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAdapter\n")); ++ ++ // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: ++retry: ++ i = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); ++ if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0)) ++ break; ++ ++ RTMPusecDelay(1000); ++ i++; ++ }while ( i<100); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== DMA offset 0x208 = 0x%x\n", GloCfg.word)); ++ GloCfg.word &= 0xff0; ++ GloCfg.field.EnTXWriteBackDDONE =1; ++ RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word); ++ ++ // Record HW Beacon offset ++ pAd->BeaconOffset[0] = HW_BEACON_BASE0; ++ pAd->BeaconOffset[1] = HW_BEACON_BASE1; ++ pAd->BeaconOffset[2] = HW_BEACON_BASE2; ++ pAd->BeaconOffset[3] = HW_BEACON_BASE3; ++ pAd->BeaconOffset[4] = HW_BEACON_BASE4; ++ pAd->BeaconOffset[5] = HW_BEACON_BASE5; ++ pAd->BeaconOffset[6] = HW_BEACON_BASE6; ++ pAd->BeaconOffset[7] = HW_BEACON_BASE7; ++ ++ // ++ // write all shared Ring's base address into ASIC ++ // ++ ++ // asic simulation sequence put this ahead before loading firmware. ++ // pbf hardware reset ++ ++ // Initialze ASIC for TX & Rx operation ++ if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) ++ { ++ if (j++ == 0) ++ { ++ NICLoadFirmware(pAd); ++ goto retry; ++ } ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++ ++ ++ // WMM parameter ++ csr0.word = 0; ++ RTMP_IO_WRITE32(pAd, WMM_TXOP0_CFG, csr0.word); ++ if (pAd->CommonCfg.PhyMode == PHY_11B) ++ { ++ csr0.field.Ac0Txop = 192; // AC_VI: 192*32us ~= 6ms ++ csr0.field.Ac1Txop = 96; // AC_VO: 96*32us ~= 3ms ++ } ++ else ++ { ++ csr0.field.Ac0Txop = 96; // AC_VI: 96*32us ~= 3ms ++ csr0.field.Ac1Txop = 48; // AC_VO: 48*32us ~= 1.5ms ++ } ++ RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); ++ ++ ++ ++ ++ // reset action ++ // Load firmware ++ // Status = NICLoadFirmware(pAd); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAdapter\n")); ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize ASIC ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICInitializeAsic( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset) ++{ ++ ULONG Index = 0; ++ UCHAR R0 = 0xff; ++ UINT32 MacCsr12 = 0, Counter = 0; ++#ifdef RT2870 ++ UINT32 MacCsr0 = 0; ++ NTSTATUS Status; ++ UCHAR Value = 0xff; ++#endif // RT2870 // ++#ifdef RT30xx ++ UINT32 eFuseCtrl; ++#endif // RT30xx // ++ USHORT KeyIdx; ++ INT i,apidx; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); ++ ++ ++#ifdef RT2870 ++ // ++ // Make sure MAC gets ready after NICLoadFirmware(). ++ // ++ Index = 0; ++ ++ //To avoid hang-on issue when interface up in kernel 2.4, ++ //we use a local variable "MacCsr0" instead of using "pAd->MACVersion" directly. ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); ++ ++ if ((MacCsr0 != 0x00) && (MacCsr0 != 0xFFFFFFFF)) ++ break; ++ ++ RTMPusecDelay(10); ++ } while (Index++ < 100); ++ ++ pAd->MACVersion = MacCsr0; ++ DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); ++ // turn on bit13 (set to zero) after rt2860D. This is to solve high-current issue. ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacCsr12); ++ MacCsr12 &= (~0x2000); ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, MacCsr12); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); ++ RTMP_IO_WRITE32(pAd, USB_DMA_CFG, 0x0); ++ Status = RTUSBVenderReset(pAd); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ ++ // Initialize MAC register to default value ++ for(Index=0; IndexMACVersion & 0xffff) < 0x0211) ++ { ++ if (pAd->NicConfig2.field.DACTestBit == 1) ++ { ++ RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x1F); // To fix throughput drop drastically ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x0F); // To fix throughput drop drastically ++ } ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x0); ++ } ++ } ++ else if (IS_RT3070(pAd)) ++ { ++ RTMP_IO_WRITE32(pAd, TX_SW_CFG1, 0); ++ RTMP_IO_WRITE32(pAd, TX_SW_CFG2, 0x1F); // To fix throughput drop drastically ++ } ++#endif // RT30xx // ++ ++ // ++ // Before program BBP, we need to wait BBP/RF get wake up. ++ // ++ Index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_STATUS_CFG, &MacCsr12); ++ ++ if ((MacCsr12 & 0x03) == 0) // if BB.RF is stable ++ break; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Check MAC_STATUS_CFG = Busy = %x\n", MacCsr12)); ++ RTMPusecDelay(1000); ++ } while (Index++ < 100); ++ ++ // The commands to firmware should be after these commands, these commands will init firmware ++ // PCI and USB are not the same because PCI driver needs to wait for PCI bus ready ++ RTMP_IO_WRITE32(pAd, H2M_BBP_AGENT, 0); // initialize BBP R/W access agent ++ RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CSR, 0); ++ RTMPusecDelay(1000); ++ ++ // Read BBP register, make sure BBP is up and running before write new data ++ Index = 0; ++ do ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R0, &R0); ++ DBGPRINT(RT_DEBUG_TRACE, ("BBP version = %x\n", R0)); ++ } while ((++Index < 20) && ((R0 == 0xff) || (R0 == 0x00))); ++ //ASSERT(Index < 20); //this will cause BSOD on Check-build driver ++ ++ if ((R0 == 0xff) || (R0 == 0x00)) ++ return NDIS_STATUS_FAILURE; ++ ++ // Initialize BBP register to default value ++ for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, BBPRegTable[Index].Value); ++ } ++ ++ // for rt2860E and after, init BBP_R84 with 0x19. This is for extension channel overlapping IOT. ++ // RT3090 should not program BBP R84 to 0x19, otherwise TX will block. ++ if (((pAd->MACVersion&0xffff) != 0x0101) && (!IS_RT30xx(pAd))) ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R84, 0x19); ++ ++// add by johnli, RF power sequence setup ++#ifdef RT30xx ++ if (IS_RT30xx(pAd)) ++ { //update for RT3070/71/72/90/91/92. ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R79, 0x13); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R80, 0x05); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R81, 0x33); ++ } ++ ++ if (IS_RT3090(pAd)) ++ { ++ UCHAR bbpreg=0; ++ ++ // enable DC filter ++ if ((pAd->MACVersion & 0xffff) >= 0x0211) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R103, 0xc0); ++ } ++ ++ // improve power consumption ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R138, &bbpreg); ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ // turn off tx DAC_1 ++ bbpreg = (bbpreg | 0x20); ++ } ++ ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ // turn off tx ADC_1 ++ bbpreg &= (~0x2); ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R138, bbpreg); ++ ++ // improve power consumption in RT3071 Ver.E ++ if ((pAd->MACVersion & 0xffff) >= 0x0211) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R31, &bbpreg); ++ bbpreg &= (~0x3); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R31, bbpreg); ++ } ++ } ++#endif // RT30xx // ++// end johnli ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x12); ++ } ++ ++ if (pAd->MACVersion >= RALINK_2880E_VERSION && pAd->MACVersion < RALINK_3070_VERSION) // 3*3 ++ { ++ // enlarge MAX_LEN_CFG ++ UINT32 csr; ++ RTMP_IO_READ32(pAd, MAX_LEN_CFG, &csr); ++ csr &= 0xFFF; ++ csr |= 0x2000; ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, csr); ++ } ++ ++#ifdef RT2870 ++{ ++ UCHAR MAC_Value[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0,0}; ++ ++ //Initialize WCID table ++ Value = 0xff; ++ for(Index =0 ;Index < 254;Index++) ++ { ++ RTUSBMultiWrite(pAd, (USHORT)(MAC_WCID_BASE + Index * 8), MAC_Value, 8); ++ } ++} ++#endif // RT2870 // ++ ++ // Add radio off control ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++// RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0x00001818); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set Radio Off\n")); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Clear raw counters ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); ++ ++ // ASIC will keep garbage value after boot ++ // Clear all seared key table when initial ++ // This routine can be ignored in radio-ON/OFF operation. ++ if (bHardReset) ++ { ++ for (KeyIdx = 0; KeyIdx < 4; KeyIdx++) ++ { ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE + 4*KeyIdx, 0); ++ } ++ ++ // Clear all pairwise key table when initial ++ for (KeyIdx = 0; KeyIdx < 256; KeyIdx++) ++ { ++ RTMP_IO_WRITE32(pAd, MAC_WCID_ATTRIBUTE_BASE + (KeyIdx * HW_WCID_ATTRI_SIZE), 1); ++ } ++ } ++ ++ // assert HOST ready bit ++// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x0); // 2004-09-14 asked by Mark ++// RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x4); ++ ++ // It isn't necessary to clear this space when not hard reset. ++ if (bHardReset == TRUE) ++ { ++ // clear all on-chip BEACON frame space ++ for (apidx = 0; apidx < HW_BEACON_MAX_COUNT; apidx++) ++ { ++ for (i = 0; i < HW_BEACON_OFFSET>>2; i+=4) ++ RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[apidx] + i, 0x00); ++ } ++ } ++#ifdef RT2870 ++ AsicDisableSync(pAd); ++ // Clear raw counters ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &Counter); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &Counter); ++ // Default PCI clock cycle per ms is different as default setting, which is based on PCI. ++ RTMP_IO_READ32(pAd, USB_CYC_CFG, &Counter); ++ Counter&=0xffffff00; ++ Counter|=0x000001e; ++ RTMP_IO_WRITE32(pAd, USB_CYC_CFG, Counter); ++#endif // RT2870 // ++#ifdef RT30xx ++ pAd->bUseEfuse=FALSE; ++ RTMP_IO_READ32(pAd, EFUSE_CTRL, &eFuseCtrl); ++ pAd->bUseEfuse = ( (eFuseCtrl & 0x80000000) == 0x80000000) ? 1 : 0; ++ if(pAd->bUseEfuse) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("NVM is Efuse\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("NVM is EEPROM\n")); ++ ++ } ++#endif // RT30xx // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // for rt2860E and after, init TXOP_CTRL_CFG with 0x583f. This is for extension channel overlapping IOT. ++ if ((pAd->MACVersion&0xffff) != 0x0101) ++ RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x583f); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitializeAsic\n")); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC Asics ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID NICIssueReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 Value = 0; ++ DBGPRINT(RT_DEBUG_TRACE, ("--> NICIssueReset\n")); ++ ++ // Abort Tx, prevent ASIC from writing to Host memory ++ //RTMP_IO_WRITE32(pAd, TX_CNTL_CSR, 0x001f0000); ++ ++ // Disable Rx, register value supposed will remain after reset ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= (0xfffffff3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Issue reset and clear from reset state ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x03); // 2004-09-17 change from 0x01 ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x00); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- NICIssueReset\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check ASIC registers and find any reason the system might hang ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++BOOLEAN NICCheckForHang( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return (FALSE); ++} ++ ++VOID NICUpdateFifoStaCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ TX_STA_FIFO_STRUC StaFifo; ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR i = 0; ++ UCHAR pid = 0, wcid = 0; ++ CHAR reTry; ++ UCHAR succMCS; ++ ++#ifdef RALINK_ATE ++ /* Nothing to do in ATE mode */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ do ++ { ++ RTMP_IO_READ32(pAd, TX_STA_FIFO, &StaFifo.word); ++ ++ if (StaFifo.field.bValid == 0) ++ break; ++ ++ wcid = (UCHAR)StaFifo.field.wcid; ++ ++ ++ /* ignore NoACK and MGMT frame use 0xFF as WCID */ ++ if ((StaFifo.field.TxAckRequired == 0) || (wcid >= MAX_LEN_OF_MAC_TABLE)) ++ { ++ i++; ++ continue; ++ } ++ ++ /* PID store Tx MCS Rate */ ++ pid = (UCHAR)StaFifo.field.PidType; ++ ++ pEntry = &pAd->MacTab.Content[wcid]; ++ ++ pEntry->DebugFIFOCount++; ++ ++#ifdef DOT11_N_SUPPORT ++ if (StaFifo.field.TxBF) // 3*3 ++ pEntry->TxBFCount++; ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef UAPSD_AP_SUPPORT ++ UAPSD_SP_AUE_Handle(pAd, pEntry, StaFifo.field.TxSuccess); ++#endif // UAPSD_AP_SUPPORT // ++ ++ if (!StaFifo.field.TxSuccess) ++ { ++ pEntry->FIFOCount++; ++ pEntry->OneSecTxFailCount++; ++ ++ if (pEntry->FIFOCount >= 1) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("#")); ++#ifdef DOT11_N_SUPPORT ++ pEntry->NoBADataCountDown = 64; ++#endif // DOT11_N_SUPPORT // ++ ++ if(pEntry->PsMode == PWR_ACTIVE) ++ { ++#ifdef DOT11_N_SUPPORT ++ int tid; ++ for (tid=0; tidAid, tid, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Update the continuous transmission counter except PS mode ++ pEntry->ContinueTxFailCnt++; ++ } ++ else ++ { ++ // Clear the FIFOCount when sta in Power Save mode. Basically we assume ++ // this tx error happened due to sta just go to sleep. ++ pEntry->FIFOCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ } ++ //pEntry->FIFOCount = 0; ++ } ++ //pEntry->bSendBAR = TRUE; ++ } ++ else ++ { ++#ifdef DOT11_N_SUPPORT ++ if ((pEntry->PsMode != PWR_SAVE) && (pEntry->NoBADataCountDown > 0)) ++ { ++ pEntry->NoBADataCountDown--; ++ if (pEntry->NoBADataCountDown==0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("@\n")); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ pEntry->FIFOCount = 0; ++ pEntry->OneSecTxNoRetryOkCount++; ++ // update NoDataIdleCount when sucessful send packet to STA. ++ pEntry->NoDataIdleCount = 0; ++ pEntry->ContinueTxFailCnt = 0; ++ } ++ ++ succMCS = StaFifo.field.SuccessRate & 0x7F; ++ ++ reTry = pid - succMCS; ++ ++ if (StaFifo.field.TxSuccess) ++ { ++ pEntry->TXMCSExpected[pid]++; ++ if (pid == succMCS) ++ { ++ pEntry->TXMCSSuccessful[pid]++; ++ } ++ else ++ { ++ pEntry->TXMCSAutoFallBack[pid][succMCS]++; ++ } ++ } ++ else ++ { ++ pEntry->TXMCSFailed[pid]++; ++ } ++ ++ if (reTry > 0) ++ { ++ if ((pid >= 12) && succMCS <=7) ++ { ++ reTry -= 4; ++ } ++ pEntry->OneSecTxRetryOkCount += reTry; ++ } ++ ++ i++; ++ // ASIC store 16 stack ++ } while ( i < (2*TX_RING_SIZE) ); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Read statistical counters from hardware registers and record them ++ in software variables for later on query ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID NICUpdateRawCounters( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 OldValue;//, Value2; ++ //ULONG PageSum, OneSecTransmitCount; ++ //ULONG TxErrorRatio, Retry, Fail; ++ RX_STA_CNT0_STRUC RxStaCnt0; ++ RX_STA_CNT1_STRUC RxStaCnt1; ++ RX_STA_CNT2_STRUC RxStaCnt2; ++ TX_STA_CNT0_STRUC TxStaCnt0; ++ TX_STA_CNT1_STRUC StaTx1; ++ TX_STA_CNT2_STRUC StaTx2; ++ TX_AGG_CNT_STRUC TxAggCnt; ++ TX_AGG_CNT0_STRUC TxAggCnt0; ++ TX_AGG_CNT1_STRUC TxAggCnt1; ++ TX_AGG_CNT2_STRUC TxAggCnt2; ++ TX_AGG_CNT3_STRUC TxAggCnt3; ++ TX_AGG_CNT4_STRUC TxAggCnt4; ++ TX_AGG_CNT5_STRUC TxAggCnt5; ++ TX_AGG_CNT6_STRUC TxAggCnt6; ++ TX_AGG_CNT7_STRUC TxAggCnt7; ++ ++ RTMP_IO_READ32(pAd, RX_STA_CNT0, &RxStaCnt0.word); ++ RTMP_IO_READ32(pAd, RX_STA_CNT2, &RxStaCnt2.word); ++ ++ { ++ RTMP_IO_READ32(pAd, RX_STA_CNT1, &RxStaCnt1.word); ++ // Update RX PLCP error counter ++ pAd->PrivateInfo.PhyRxErrCnt += RxStaCnt1.field.PlcpErr; ++ // Update False CCA counter ++ pAd->RalinkCounters.OneSecFalseCCACnt += RxStaCnt1.field.FalseCca; ++ } ++ ++ // Update FCS counters ++ OldValue= pAd->WlanCounters.FCSErrorCount.u.LowPart; ++ pAd->WlanCounters.FCSErrorCount.u.LowPart += (RxStaCnt0.field.CrcErr); // >> 7); ++ if (pAd->WlanCounters.FCSErrorCount.u.LowPart < OldValue) ++ pAd->WlanCounters.FCSErrorCount.u.HighPart++; ++ ++ // Add FCS error count to private counters ++ pAd->RalinkCounters.OneSecRxFcsErrCnt += RxStaCnt0.field.CrcErr; ++ OldValue = pAd->RalinkCounters.RealFcsErrCount.u.LowPart; ++ pAd->RalinkCounters.RealFcsErrCount.u.LowPart += RxStaCnt0.field.CrcErr; ++ if (pAd->RalinkCounters.RealFcsErrCount.u.LowPart < OldValue) ++ pAd->RalinkCounters.RealFcsErrCount.u.HighPart++; ++ ++ // Update Duplicate Rcv check ++ pAd->RalinkCounters.DuplicateRcv += RxStaCnt2.field.RxDupliCount; ++ pAd->WlanCounters.FrameDuplicateCount.u.LowPart += RxStaCnt2.field.RxDupliCount; ++ // Update RX Overflow counter ++ pAd->Counters8023.RxNoBuffer += (RxStaCnt2.field.RxFifoOverflowCount); ++ ++ //pAd->RalinkCounters.RxCount = 0; ++#ifdef RT2870 ++ if (pAd->RalinkCounters.RxCount != pAd->watchDogRxCnt) ++ { ++ pAd->watchDogRxCnt = pAd->RalinkCounters.RxCount; ++ pAd->watchDogRxOverFlowCnt = 0; ++ } ++ else ++ { ++ if (RxStaCnt2.field.RxFifoOverflowCount) ++ pAd->watchDogRxOverFlowCnt++; ++ else ++ pAd->watchDogRxOverFlowCnt = 0; ++ } ++#endif // RT2870 // ++ ++ ++ //if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) || ++ // (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) && (pAd->MacTab.Size != 1))) ++ if (!pAd->bUpdateBcnCntDone) ++ { ++ // Update BEACON sent count ++ RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); ++ RTMP_IO_READ32(pAd, TX_STA_CNT2, &StaTx2.word); ++ pAd->RalinkCounters.OneSecBeaconSentCnt += TxStaCnt0.field.TxBeaconCount; ++ pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; ++ pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; ++ pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; ++ pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; ++ pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; ++ } ++ ++ //if (pAd->bStaFifoTest == TRUE) ++ { ++ RTMP_IO_READ32(pAd, TX_AGG_CNT, &TxAggCnt.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT0, &TxAggCnt0.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT1, &TxAggCnt1.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT2, &TxAggCnt2.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT3, &TxAggCnt3.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT4, &TxAggCnt4.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT5, &TxAggCnt5.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT6, &TxAggCnt6.word); ++ RTMP_IO_READ32(pAd, TX_AGG_CNT7, &TxAggCnt7.word); ++ pAd->RalinkCounters.TxAggCount += TxAggCnt.field.AggTxCount; ++ pAd->RalinkCounters.TxNonAggCount += TxAggCnt.field.NonAggTxCount; ++ pAd->RalinkCounters.TxAgg1MPDUCount += TxAggCnt0.field.AggSize1Count; ++ pAd->RalinkCounters.TxAgg2MPDUCount += TxAggCnt0.field.AggSize2Count; ++ ++ pAd->RalinkCounters.TxAgg3MPDUCount += TxAggCnt1.field.AggSize3Count; ++ pAd->RalinkCounters.TxAgg4MPDUCount += TxAggCnt1.field.AggSize4Count; ++ pAd->RalinkCounters.TxAgg5MPDUCount += TxAggCnt2.field.AggSize5Count; ++ pAd->RalinkCounters.TxAgg6MPDUCount += TxAggCnt2.field.AggSize6Count; ++ ++ pAd->RalinkCounters.TxAgg7MPDUCount += TxAggCnt3.field.AggSize7Count; ++ pAd->RalinkCounters.TxAgg8MPDUCount += TxAggCnt3.field.AggSize8Count; ++ pAd->RalinkCounters.TxAgg9MPDUCount += TxAggCnt4.field.AggSize9Count; ++ pAd->RalinkCounters.TxAgg10MPDUCount += TxAggCnt4.field.AggSize10Count; ++ ++ pAd->RalinkCounters.TxAgg11MPDUCount += TxAggCnt5.field.AggSize11Count; ++ pAd->RalinkCounters.TxAgg12MPDUCount += TxAggCnt5.field.AggSize12Count; ++ pAd->RalinkCounters.TxAgg13MPDUCount += TxAggCnt6.field.AggSize13Count; ++ pAd->RalinkCounters.TxAgg14MPDUCount += TxAggCnt6.field.AggSize14Count; ++ ++ pAd->RalinkCounters.TxAgg15MPDUCount += TxAggCnt7.field.AggSize15Count; ++ pAd->RalinkCounters.TxAgg16MPDUCount += TxAggCnt7.field.AggSize16Count; ++ ++ // Calculate the transmitted A-MPDU count ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += TxAggCnt0.field.AggSize1Count; ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt0.field.AggSize2Count / 2); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize3Count / 3); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt1.field.AggSize4Count / 4); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize5Count / 5); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt2.field.AggSize6Count / 6); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize7Count / 7); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt3.field.AggSize8Count / 8); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize9Count / 9); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt4.field.AggSize10Count / 10); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize11Count / 11); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt5.field.AggSize12Count / 12); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize13Count / 13); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt6.field.AggSize14Count / 14); ++ ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize15Count / 15); ++ pAd->RalinkCounters.TransmittedAMPDUCount.u.LowPart += (TxAggCnt7.field.AggSize16Count / 16); ++ } ++ ++#ifdef DBG_DIAGNOSE ++ { ++ RtmpDiagStruct *pDiag; ++ COUNTER_RALINK *pRalinkCounters; ++ UCHAR ArrayCurIdx, i; ++ ++ pDiag = &pAd->DiagStruct; ++ pRalinkCounters = &pAd->RalinkCounters; ++ ArrayCurIdx = pDiag->ArrayCurIdx; ++ ++ if (pDiag->inited == 0) ++ { ++ NdisZeroMemory(pDiag, sizeof(struct _RtmpDiagStrcut_)); ++ pDiag->ArrayStartIdx = pDiag->ArrayCurIdx = 0; ++ pDiag->inited = 1; ++ } ++ else ++ { ++ // Tx ++ pDiag->TxFailCnt[ArrayCurIdx] = TxStaCnt0.field.TxFailCount; ++ pDiag->TxAggCnt[ArrayCurIdx] = TxAggCnt.field.AggTxCount; ++ pDiag->TxNonAggCnt[ArrayCurIdx] = TxAggCnt.field.NonAggTxCount; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][0] = TxAggCnt0.field.AggSize1Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][1] = TxAggCnt0.field.AggSize2Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][2] = TxAggCnt1.field.AggSize3Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][3] = TxAggCnt1.field.AggSize4Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][4] = TxAggCnt2.field.AggSize5Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][5] = TxAggCnt2.field.AggSize6Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][6] = TxAggCnt3.field.AggSize7Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][7] = TxAggCnt3.field.AggSize8Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][8] = TxAggCnt4.field.AggSize9Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][9] = TxAggCnt4.field.AggSize10Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][10] = TxAggCnt5.field.AggSize11Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][11] = TxAggCnt5.field.AggSize12Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][12] = TxAggCnt6.field.AggSize13Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][13] = TxAggCnt6.field.AggSize14Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][14] = TxAggCnt7.field.AggSize15Count; ++ pDiag->TxAMPDUCnt[ArrayCurIdx][15] = TxAggCnt7.field.AggSize16Count; ++ ++ pDiag->RxCrcErrCnt[ArrayCurIdx] = RxStaCnt0.field.CrcErr; ++ ++ INC_RING_INDEX(pDiag->ArrayCurIdx, DIAGNOSE_TIME); ++ ArrayCurIdx = pDiag->ArrayCurIdx; ++ for (i =0; i < 9; i++) ++ { ++ pDiag->TxDescCnt[ArrayCurIdx][i]= 0; ++ pDiag->TxSWQueCnt[ArrayCurIdx][i] =0; ++ pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; ++ pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; ++ } ++ pDiag->TxDataCnt[ArrayCurIdx] = 0; ++ pDiag->TxFailCnt[ArrayCurIdx] = 0; ++ pDiag->RxDataCnt[ArrayCurIdx] = 0; ++ pDiag->RxCrcErrCnt[ArrayCurIdx] = 0; ++// for (i = 9; i < 16; i++) ++ for (i = 9; i < 24; i++) // 3*3 ++ { ++ pDiag->TxDescCnt[ArrayCurIdx][i] = 0; ++ pDiag->TxMcsCnt[ArrayCurIdx][i] = 0; ++ pDiag->RxMcsCnt[ArrayCurIdx][i] = 0; ++} ++ ++ if (pDiag->ArrayCurIdx == pDiag->ArrayStartIdx) ++ INC_RING_INDEX(pDiag->ArrayStartIdx, DIAGNOSE_TIME); ++ } ++ ++ } ++#endif // DBG_DIAGNOSE // ++ ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Reset NIC from error ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Reset NIC from error state ++ ++ ======================================================================== ++*/ ++VOID NICResetFromError( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Reset BBP (according to alex, reset ASIC will force reset BBP ++ // Therefore, skip the reset BBP ++ // RTMP_IO_WRITE32(pAd, MAC_CSR1, 0x2); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); ++ // Remove ASIC from reset state ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ ++ NICInitializeAdapter(pAd, FALSE); ++ NICInitAsicFromEEPROM(pAd); ++ ++ // Switch to current channel, since during reset process, the connection should remains on. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ erase 8051 firmware image in MAC ASIC ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ======================================================================== ++*/ ++VOID NICEraseFirmware( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ ++ for(i=0; i %s\n", __FUNCTION__)); ++ ++ /* init */ ++ pFirmwareImage = NULL; ++ src = RTMP_FIRMWARE_FILE_NAME; ++ ++ /* save uid and gid used for filesystem access. ++ set user and group to 0 (root) */ ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ ++ FIRMWARE_MINOR_VERSION; ++ ++ ++ /* allocate firmware buffer */ ++ pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); ++ if (pFirmwareImage == NULL) ++ { ++ /* allocate fail, use default firmware array in firmware.h */ ++ printk("%s - Allocate memory fail!\n", __FUNCTION__); ++ NICLF_DEFAULT_USE(); ++ } ++ else ++ { ++ /* allocate ok! zero the firmware buffer */ ++ memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); ++ } /* End of if */ ++ ++ ++ /* if ok, read firmware file from *.bin file */ ++ if (flg_default_firm_use == FALSE) ++ { ++ do ++ { ++ /* open the bin file */ ++ srcf = filp_open(src, O_RDONLY, 0); ++ ++ if (IS_ERR(srcf)) ++ { ++ printk("%s - Error %ld opening %s\n", ++ __FUNCTION__, -PTR_ERR(srcf), src); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ ++ /* the object must have a read method */ ++ if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) ++ { ++ printk("%s - %s does not have a write method\n", __FUNCTION__, src); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ ++ /* read the firmware from the file *.bin */ ++ FileLength = srcf->f_op->read(srcf, ++ pFirmwareImage, ++ MAX_FIRMWARE_IMAGE_SIZE, ++ &srcf->f_pos); ++ ++ if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) ++ { ++ printk("%s: error file length (=%d) in RT2860AP.BIN\n", ++ __FUNCTION__, FileLength); ++ NICLF_DEFAULT_USE(); ++ break; ++ } ++ else ++ { ++ PUCHAR ptr = pFirmwareImage; ++ USHORT crc = 0xffff; ++ ++ ++ /* calculate firmware CRC */ ++ for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) ++ crc = ByteCRC16(BitReverse(*ptr), crc); ++ /* End of for */ ++ ++ if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ ++ (UCHAR)BitReverse((UCHAR)(crc>>8))) || ++ (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ ++ (UCHAR)BitReverse((UCHAR)crc))) ++ { ++ /* CRC fail */ ++ printk("%s: CRC = 0x%02x 0x%02x " ++ "error, should be 0x%02x 0x%02x\n", ++ __FUNCTION__, ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], ++ (UCHAR)(crc>>8), (UCHAR)(crc)); ++ NICLF_DEFAULT_USE(); ++ break; ++ } ++ else ++ { ++ /* firmware is ok */ ++ pAd->FirmwareVersion = \ ++ (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; ++ ++ /* check if firmware version of the file is too old */ ++ if ((pAd->FirmwareVersion) < \ ++ ((FIRMWARE_MAJOR_VERSION << 8) + ++ FIRMWARE_MINOR_VERSION)) ++ { ++ printk("%s: firmware version too old!\n", __FUNCTION__); ++ NICLF_DEFAULT_USE(); ++ break; ++ } /* End of if */ ++ } /* End of if */ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("NICLoadFirmware: CRC ok, ver=%d.%d\n", ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], ++ pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); ++ } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ ++ break; ++ } while(TRUE); ++ ++ /* close firmware file */ ++ if (IS_ERR(srcf)) ++ ; ++ else ++ { ++ retval = filp_close(srcf, NULL); ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("--> Error %d closing %s\n", -retval, src)); ++ } /* End of if */ ++ } /* End of if */ ++ } /* End of if */ ++ ++ ++ /* write firmware to ASIC */ ++ if (flg_default_firm_use == TRUE) ++ { ++ /* use default fimeware, free allocated buffer */ ++ if (pFirmwareImage != NULL) ++ kfree(pFirmwareImage); ++ /* End of if */ ++ ++ /* use default *.bin array */ ++ pFirmwareImage = FirmwareImage; ++ FileLength = sizeof(FirmwareImage); ++ } /* End of if */ ++ ++ /* enable Host program ram write selection */ ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); ++ ++ for(i=0; ifsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++#else ++ ++ NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ PUCHAR pFirmwareImage; ++ ULONG FileLength, Index; ++ //ULONG firm; ++ UINT32 MacReg = 0; ++ UINT32 Version = (pAd->MACVersion >> 16); ++ ++ pFirmwareImage = FirmwareImage; ++ FileLength = sizeof(FirmwareImage); ++ ++ // New 8k byte firmware size for RT3071/RT3072 ++ //printk("Usb Chip\n"); ++ if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) ++ //The firmware image consists of two parts. One is the origianl and the other is the new. ++ //Use Second Part ++ { ++#ifdef RT2870 ++ if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) ++ { // Use Firmware V2. ++ //printk("KH:Use New Version,part2\n"); ++ pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; ++ FileLength = FIRMWAREIMAGEV2_LENGTH; ++ } ++ else ++ { ++ //printk("KH:Use New Version,part1\n"); ++ pFirmwareImage = FirmwareImage; ++ FileLength = FIRMWAREIMAGEV1_LENGTH; ++ } ++#endif // RT2870 // ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ ++ RT28XX_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); ++ ++#endif ++ ++ /* check if MCU is ready */ ++ Index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &MacReg); ++ ++ if (MacReg & 0x80) ++ break; ++ ++ RTMPusecDelay(1000); ++ } while (Index++ < 1000); ++ ++ if (Index >= 1000) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); ++ } /* End of if */ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("<=== %s (status=%d)\n", __FUNCTION__, Status)); ++ return Status; ++} /* End of NICLoadFirmware */ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Load Tx rate switching parameters ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS firmware image load ok ++ NDIS_STATUS_FAILURE image not found ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Rate Table Format: ++ 1. (B0: Valid Item number) (B1:Initial item from zero) ++ 2. Item Number(Dec) Mode(Hex) Current MCS(Dec) TrainUp(Dec) TrainDown(Dec) ++ ++ ======================================================================== ++*/ ++NDIS_STATUS NICLoadRateSwitchingParams( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ if pSrc1 all zero with length Length, return 0. ++ If not all zero, return 1 ++ ++ Arguments: ++ pSrc1 ++ ++ Return Value: ++ 1: not all zero ++ 0: all zero ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPNotAllZero( ++ IN PVOID pSrc1, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ ULONG Index = 0; ++ ++ pMem1 = (PUCHAR) pSrc1; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ if (pMem1[Index] != 0x0) ++ { ++ break; ++ } ++ } ++ ++ if (Index == Length) ++ { ++ return (0); ++ } ++ else ++ { ++ return (1); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare two memory block ++ ++ Arguments: ++ pSrc1 Pointer to first memory address ++ pSrc2 Pointer to second memory address ++ ++ Return Value: ++ 0: memory is equal ++ 1: pSrc1 memory is larger ++ 2: pSrc2 memory is larger ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPCompareMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ PUCHAR pMem2; ++ ULONG Index = 0; ++ ++ pMem1 = (PUCHAR) pSrc1; ++ pMem2 = (PUCHAR) pSrc2; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ if (pMem1[Index] > pMem2[Index]) ++ return (1); ++ else if (pMem1[Index] < pMem2[Index]) ++ return (2); ++ } ++ ++ // Equal ++ return (0); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Zero out memory block ++ ++ Arguments: ++ pSrc1 Pointer to memory address ++ Length Size ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPZeroMemory( ++ IN PVOID pSrc, ++ IN ULONG Length) ++{ ++ PUCHAR pMem; ++ ULONG Index = 0; ++ ++ pMem = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem[Index] = 0x00; ++ } ++} ++ ++VOID RTMPFillMemory( ++ IN PVOID pSrc, ++ IN ULONG Length, ++ IN UCHAR Fill) ++{ ++ PUCHAR pMem; ++ ULONG Index = 0; ++ ++ pMem = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem[Index] = Fill; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy data from memory block 1 to memory block 2 ++ ++ Arguments: ++ pDest Pointer to destination memory address ++ pSrc Pointer to source memory address ++ Length Copy size ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPMoveMemory( ++ OUT PVOID pDest, ++ IN PVOID pSrc, ++ IN ULONG Length) ++{ ++ PUCHAR pMem1; ++ PUCHAR pMem2; ++ UINT Index; ++ ++ ASSERT((Length==0) || (pDest && pSrc)); ++ ++ pMem1 = (PUCHAR) pDest; ++ pMem2 = (PUCHAR) pSrc; ++ ++ for (Index = 0; Index < Length; Index++) ++ { ++ pMem1[Index] = pMem2[Index]; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Initialize port configuration structure ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID UserCfgInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++// EDCA_PARM DefaultEdcaParm; ++ UINT key_index, bss_index; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit\n")); ++ ++ // ++ // part I. intialize common configuration ++ // ++#ifdef RT2870 ++ pAd->BulkOutReq = 0; ++ ++ pAd->BulkOutComplete = 0; ++ pAd->BulkOutCompleteOther = 0; ++ pAd->BulkOutCompleteCancel = 0; ++ pAd->BulkInReq = 0; ++ pAd->BulkInComplete = 0; ++ pAd->BulkInCompleteFail = 0; ++ ++ //pAd->QuickTimerP = 100; ++ //pAd->TurnAggrBulkInCount = 0; ++ pAd->bUsbTxBulkAggre = 0; ++ ++ // init as unsed value to ensure driver will set to MCU once. ++ pAd->LedIndicatorStregth = 0xFF; ++ ++ pAd->CommonCfg.MaxPktOneTxBulk = 2; ++ pAd->CommonCfg.TxBulkFactor = 1; ++ pAd->CommonCfg.RxBulkFactor =1; ++ ++ pAd->CommonCfg.TxPower = 100; //mW ++ ++ NdisZeroMemory(&pAd->CommonCfg.IOTestParm, sizeof(pAd->CommonCfg.IOTestParm)); ++#endif // RT2870 // ++ ++ for(key_index=0; key_indexSharedKey[bss_index][key_index].KeyLen = 0; ++ pAd->SharedKey[bss_index][key_index].CipherAlg = CIPHER_NONE; ++ } /* End of for */ ++ } /* End of for */ ++ ++ pAd->EepromAccess = FALSE; ++ ++ pAd->Antenna.word = 0; ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ ++ pAd->LedCntl.word = 0; ++ ++ pAd->bAutoTxAgcA = FALSE; // Default is OFF ++ pAd->bAutoTxAgcG = FALSE; // Default is OFF ++ pAd->RfIcType = RFIC_2820; ++ ++ // Init timer for reset complete event ++ pAd->CommonCfg.CentralChannel = 1; ++ pAd->bForcePrintTX = FALSE; ++ pAd->bForcePrintRX = FALSE; ++ pAd->bStaFifoTest = FALSE; ++ pAd->bProtectionTest = FALSE; ++ pAd->bHCCATest = FALSE; ++ pAd->bGenOneHCCA = FALSE; ++ pAd->CommonCfg.Dsifs = 10; // in units of usec ++ pAd->CommonCfg.TxPower = 100; //mW ++ pAd->CommonCfg.TxPowerPercentage = 0xffffffff; // AUTO ++ pAd->CommonCfg.TxPowerDefault = 0xffffffff; // AUTO ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleAuto; // use Long preamble on TX by defaut ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ pAd->CommonCfg.RtsThreshold = 2347; ++ pAd->CommonCfg.FragmentThreshold = 2346; ++ pAd->CommonCfg.UseBGProtection = 0; // 0: AUTO ++ pAd->CommonCfg.bEnableTxBurst = TRUE; //0; ++ pAd->CommonCfg.PhyMode = 0xff; // unknown ++ pAd->CommonCfg.BandState = UNKNOWN_BAND; ++ pAd->CommonCfg.RadarDetect.CSPeriod = 10; ++ pAd->CommonCfg.RadarDetect.CSCount = 0; ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ pAd->CommonCfg.RadarDetect.ChMovingTime = 65; ++ pAd->CommonCfg.RadarDetect.LongPulseRadarTh = 3; ++ pAd->CommonCfg.bAPSDCapable = FALSE; ++ pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; ++ pAd->CommonCfg.TriggerTimerCount = 0; ++ pAd->CommonCfg.bAPSDForcePowerSave = FALSE; ++ pAd->CommonCfg.bCountryFlag = FALSE; ++ pAd->CommonCfg.TxStream = 0; ++ pAd->CommonCfg.RxStream = 0; ++ ++ NdisZeroMemory(&pAd->BeaconTxWI, sizeof(pAd->BeaconTxWI)); ++ ++#ifdef DOT11_N_SUPPORT ++ NdisZeroMemory(&pAd->CommonCfg.HtCapability, sizeof(pAd->CommonCfg.HtCapability)); ++ pAd->HTCEnable = FALSE; ++ pAd->bBroadComHT = FALSE; ++ pAd->CommonCfg.bRdg = FALSE; ++ ++#ifdef DOT11N_DRAFT3 ++ pAd->CommonCfg.Dot11OBssScanPassiveDwell = dot11OBSSScanPassiveDwell; // Unit : TU. 5~1000 ++ pAd->CommonCfg.Dot11OBssScanActiveDwell = dot11OBSSScanActiveDwell; // Unit : TU. 10~1000 ++ pAd->CommonCfg.Dot11BssWidthTriggerScanInt = dot11BSSWidthTriggerScanInterval; // Unit : Second ++ pAd->CommonCfg.Dot11OBssScanPassiveTotalPerChannel = dot11OBSSScanPassiveTotalPerChannel; // Unit : TU. 200~10000 ++ pAd->CommonCfg.Dot11OBssScanActiveTotalPerChannel = dot11OBSSScanActiveTotalPerChannel; // Unit : TU. 20~10000 ++ pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor = dot11BSSWidthChannelTransactionDelayFactor; ++ pAd->CommonCfg.Dot11OBssScanActivityThre = dot11BSSScanActivityThreshold; // Unit : percentage ++ pAd->CommonCfg.Dot11BssWidthChanTranDelay = (pAd->CommonCfg.Dot11BssWidthTriggerScanInt * pAd->CommonCfg.Dot11BssWidthChanTranDelayFactor); ++#endif // DOT11N_DRAFT3 // ++ ++ NdisZeroMemory(&pAd->CommonCfg.AddHTInfo, sizeof(pAd->CommonCfg.AddHTInfo)); ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ pAd->CommonCfg.BACapability.field.MpduDensity = 0; ++ pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; //32; ++ pAd->CommonCfg.BACapability.field.TxBAWinLimit = 64; //32; ++ DBGPRINT(RT_DEBUG_TRACE, ("--> UserCfgInit. BACapability = 0x%x\n", pAd->CommonCfg.BACapability.word)); ++ ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ BATableInit(pAd, &pAd->BATable); ++ ++ pAd->CommonCfg.bExtChannelSwitchAnnouncement = 1; ++ pAd->CommonCfg.bHTProtect = 1; ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ pAd->CommonCfg.bBADecline = FALSE; ++ pAd->CommonCfg.bDisableReordering = FALSE; ++ ++ pAd->CommonCfg.TxBASize = 7; ++ ++ pAd->CommonCfg.REGBACapability.word = pAd->CommonCfg.BACapability.word; ++#endif // DOT11_N_SUPPORT // ++ ++ //pAd->CommonCfg.HTPhyMode.field.BW = BW_20; ++ //pAd->CommonCfg.HTPhyMode.field.MCS = MCS_AUTO; ++ //pAd->CommonCfg.HTPhyMode.field.ShortGI = GI_800; ++ //pAd->CommonCfg.HTPhyMode.field.STBC = STBC_NONE; ++ pAd->CommonCfg.TxRate = RATE_6; ++ ++ pAd->CommonCfg.MlmeTransmit.field.MCS = MCS_RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.BW = BW_20; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ ++ pAd->CommonCfg.BeaconPeriod = 100; // in mSec ++ ++ // ++ // part II. intialize STA specific configuration ++ // ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_DIRECT); ++ RX_FILTER_CLEAR_FLAG(pAd, fRX_FILTER_ACCEPT_MULTICAST); ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_BROADCAST); ++ RX_FILTER_SET_FLAG(pAd, fRX_FILTER_ACCEPT_ALL_MULTICAST); ++ ++ pAd->StaCfg.Psm = PWR_ACTIVE; ++ ++ pAd->StaCfg.OrigWepStatus = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.PairCipher = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.GroupCipher = Ndis802_11EncryptionDisabled; ++ pAd->StaCfg.bMixCipher = FALSE; ++ pAd->StaCfg.DefaultKeyId = 0; ++ ++ // 802.1x port control ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.LastMicErrorTime = 0; ++ pAd->StaCfg.MicErrCnt = 0; ++ pAd->StaCfg.bBlockAssoc = FALSE; ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ ++ pAd->CommonCfg.NdisRadioStateOff = FALSE; // New to support microsoft disable radio with OID command ++ ++ pAd->StaCfg.RssiTrigger = 0; ++ NdisZeroMemory(&pAd->StaCfg.RssiSample, sizeof(RSSI_SAMPLE)); ++ pAd->StaCfg.RssiTriggerMode = RSSI_TRIGGERED_UPON_BELOW_THRESHOLD; ++ pAd->StaCfg.AtimWin = 0; ++ pAd->StaCfg.DefaultListenCount = 3;//default listen count; ++ pAd->StaCfg.BssType = BSS_INFRA; // BSS_INFRA or BSS_ADHOC or BSS_MONITOR ++ pAd->StaCfg.bScanReqIsFromWebUI = FALSE; ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); ++ ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ } ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ pAd->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ ++ // global variables mXXXX used in MAC protocol state machines ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ ++ // PHY specification ++ pAd->CommonCfg.PhyMode = PHY_11BG_MIXED; // default PHY mode ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); // CCK use LONG preamble ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // user desired power mode ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.bWindowsACCAMEnable = FALSE; ++ ++#ifdef LEAP_SUPPORT ++ // CCX v1.0 releated init value ++ RTMPInitTimer(pAd, &pAd->StaCfg.LeapAuthTimer, GET_TIMER_FUNCTION(LeapAuthTimeout), pAd, FALSE); ++ pAd->StaCfg.LeapAuthMode = CISCO_AuthModeLEAPNone; ++ pAd->StaCfg.bCkipOn = FALSE; ++#endif // LEAP_SUPPORT // ++ ++ RTMPInitTimer(pAd, &pAd->StaCfg.StaQuickResponeForRateUpTimer, GET_TIMER_FUNCTION(StaQuickResponeForRateUpExec), pAd, FALSE); ++ pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; ++ ++ // Patch for Ndtest ++ pAd->StaCfg.ScanCnt = 0; ++ ++ // CCX 2.0 control flag init ++ pAd->StaCfg.CCXEnable = FALSE; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; ++ pAd->StaCfg.CCXQosECWMin = 4; ++ pAd->StaCfg.CCXQosECWMax = 10; ++ ++ pAd->StaCfg.bHwRadio = TRUE; // Default Hardware Radio status is On ++ pAd->StaCfg.bSwRadio = TRUE; // Default Software Radio status is On ++ pAd->StaCfg.bRadio = TRUE; // bHwRadio && bSwRadio ++ pAd->StaCfg.bHardwareRadio = FALSE; // Default is OFF ++ pAd->StaCfg.bShowHiddenSSID = FALSE; // Default no show ++ ++ // Nitro mode control ++ pAd->StaCfg.bAutoReconnect = TRUE; ++ ++ // Save the init time as last scan time, the system should do scan after 2 seconds. ++ // This patch is for driver wake up from standby mode, system will do scan right away. ++ pAd->StaCfg.LastScanTime = 0; ++ NdisZeroMemory(pAd->nickname, IW_ESSID_MAX_SIZE+1); ++ sprintf(pAd->nickname, "%s", STA_NIC_DEVICE_NAME); ++ RTMPInitTimer(pAd, &pAd->StaCfg.WpaDisassocAndBlockAssocTimer, GET_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc), pAd, FALSE); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAd->StaCfg.IEEE8021X = FALSE; ++ pAd->StaCfg.IEEE8021x_required_keys = FALSE; ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Default for extra information is not valid ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ ++ // Default Config change flag ++ pAd->bConfigChanged = FALSE; ++ ++ // ++ // part III. AP configurations ++ // ++ ++ ++ // ++ // part IV. others ++ // ++ // dynamic BBP R66:sensibity tuning to overcome background noise ++ pAd->BbpTuning.bEnable = TRUE; ++ pAd->BbpTuning.FalseCcaLowerThreshold = 100; ++ pAd->BbpTuning.FalseCcaUpperThreshold = 512; ++ pAd->BbpTuning.R66Delta = 4; ++ pAd->Mlme.bEnableAutoAntennaCheck = TRUE; ++ ++ // ++ // Also initial R66CurrentValue, RTUSBResumeMsduTransmission might use this value. ++ // if not initial this value, the default value will be 0. ++ // ++ pAd->BbpTuning.R66CurrentValue = 0x38; ++ ++ pAd->Bbp94 = BBPR94_DEFAULT; ++ pAd->BbpForCCK = FALSE; ++ ++ // Default is FALSE for test bit 1 ++ //pAd->bTest1 = FALSE; ++ ++ // initialize MAC table and allocate spin lock ++ NdisZeroMemory(&pAd->MacTab, sizeof(MAC_TABLE)); ++ InitializeQueueHeader(&pAd->MacTab.McastPsQueue); ++ NdisAllocateSpinLock(&pAd->MacTabLock); ++ ++ //RTMPInitTimer(pAd, &pAd->RECBATimer, RECBATimerTimeout, pAd, TRUE); ++ //RTMPSetTimer(&pAd->RECBATimer, REORDER_EXEC_INTV); ++ ++#ifdef RALINK_ATE ++ NdisZeroMemory(&pAd->ate, sizeof(ATE_INFO)); ++ pAd->ate.Mode = ATE_STOP; ++ pAd->ate.TxCount = 200;/* to exceed TX_RING_SIZE ... */ ++ pAd->ate.TxLength = 1024; ++ pAd->ate.TxWI.ShortGI = 0;// LONG GI : 800 ns ++ pAd->ate.TxWI.PHYMODE = MODE_CCK; ++ pAd->ate.TxWI.MCS = 3; ++ pAd->ate.TxWI.BW = BW_20; ++ pAd->ate.Channel = 1; ++ pAd->ate.QID = QID_AC_BE; ++ pAd->ate.Addr1[0] = 0x00; ++ pAd->ate.Addr1[1] = 0x11; ++ pAd->ate.Addr1[2] = 0x22; ++ pAd->ate.Addr1[3] = 0xAA; ++ pAd->ate.Addr1[4] = 0xBB; ++ pAd->ate.Addr1[5] = 0xCC; ++ NdisMoveMemory(pAd->ate.Addr2, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ NdisMoveMemory(pAd->ate.Addr3, pAd->ate.Addr1, ETH_LENGTH_OF_ADDRESS); ++ pAd->ate.bRxFer = 0; ++ pAd->ate.bQATxStart = FALSE; ++ pAd->ate.bQARxStart = FALSE; ++#ifdef RALINK_28xx_QA ++ //pAd->ate.Repeat = 0; ++ pAd->ate.TxStatus = 0; ++ pAd->ate.AtePid = 0; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++ ++ pAd->CommonCfg.bWiFiTest = FALSE; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); ++} ++ ++// IRQL = PASSIVE_LEVEL ++UCHAR BtoH(char ch) ++{ ++ if (ch >= '0' && ch <= '9') return (ch - '0'); // Handle numerals ++ if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA); // Handle capitol hex digits ++ if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA); // Handle small hex digits ++ return(255); ++} ++ ++// ++// FUNCTION: AtoH(char *, UCHAR *, int) ++// ++// PURPOSE: Converts ascii string to network order hex ++// ++// PARAMETERS: ++// src - pointer to input ascii string ++// dest - pointer to output hex ++// destlen - size of dest ++// ++// COMMENTS: ++// ++// 2 ascii bytes make a hex byte so must put 1st ascii byte of pair ++// into upper nibble and 2nd ascii byte of pair into lower nibble. ++// ++// IRQL = PASSIVE_LEVEL ++ ++void AtoH(char * src, UCHAR * dest, int destlen) ++{ ++ char * srcptr; ++ PUCHAR destTemp; ++ ++ srcptr = src; ++ destTemp = (PUCHAR) dest; ++ ++ while(destlen--) ++ { ++ *destTemp = BtoH(*srcptr++) << 4; // Put 1st ascii byte in upper nibble. ++ *destTemp += BtoH(*srcptr++); // Add 2nd ascii byte to above. ++ destTemp++; ++ } ++} ++ ++VOID RTMPPatchMacBbpBug( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG Index; ++ ++ // Initialize BBP register to default value ++ for (Index = 0; Index < NUM_BBP_REG_PARMS; Index++) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[Index].Register, (UCHAR)BBPRegTable[Index].Value); ++ } ++ ++ // Initialize RF register to default value ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ // Re-init BBP register from EEPROM value ++ NICInitAsicFromEEPROM(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTimer Timer structure ++ pTimerFunc Function to execute when timer expired ++ Repeat Ture for period timer ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitTimer( ++ IN PRTMP_ADAPTER pAd, ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN PVOID pTimerFunc, ++ IN PVOID pData, ++ IN BOOLEAN Repeat) ++{ ++ // ++ // Set Valid to TRUE for later used. ++ // It will crash if we cancel a timer or set a timer ++ // that we haven't initialize before. ++ // ++ pTimer->Valid = TRUE; ++ ++ pTimer->PeriodicType = Repeat; ++ pTimer->State = FALSE; ++ pTimer->cookie = (ULONG) pData; ++ ++#ifdef RT2870 ++ pTimer->pAd = pAd; ++#endif // RT2870 // ++ ++ RTMP_OS_Init_Timer(pAd, &pTimer->TimerObj, pTimerFunc, (PVOID) pTimer); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pTimer Timer structure ++ Value Timer value in milliseconds ++ ++ Return Value: ++ None ++ ++ Note: ++ To use this routine, must call RTMPInitTimer before. ++ ++ ======================================================================== ++*/ ++VOID RTMPSetTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value) ++{ ++ if (pTimer->Valid) ++ { ++ pTimer->TimerValue = Value; ++ pTimer->State = FALSE; ++ if (pTimer->PeriodicType == TRUE) ++ { ++ pTimer->Repeat = TRUE; ++ RTMP_SetPeriodicTimer(&pTimer->TimerObj, Value); ++ } ++ else ++ { ++ pTimer->Repeat = FALSE; ++ RTMP_OS_Add_Timer(&pTimer->TimerObj, Value); ++ } ++ } ++ else ++ { ++ DBGPRINT_ERR(("RTMPSetTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init timer objects ++ ++ Arguments: ++ pTimer Timer structure ++ Value Timer value in milliseconds ++ ++ Return Value: ++ None ++ ++ Note: ++ To use this routine, must call RTMPInitTimer before. ++ ++ ======================================================================== ++*/ ++VOID RTMPModTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value) ++{ ++ BOOLEAN Cancel; ++ ++ if (pTimer->Valid) ++ { ++ pTimer->TimerValue = Value; ++ pTimer->State = FALSE; ++ if (pTimer->PeriodicType == TRUE) ++ { ++ RTMPCancelTimer(pTimer, &Cancel); ++ RTMPSetTimer(pTimer, Value); ++ } ++ else ++ { ++ RTMP_OS_Mod_Timer(&pTimer->TimerObj, Value); ++ } ++ } ++ else ++ { ++ DBGPRINT_ERR(("RTMPModTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Cancel timer objects ++ ++ Arguments: ++ Adapter Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ 1.) To use this routine, must call RTMPInitTimer before. ++ 2.) Reset NIC to initial state AS IS system boot up time. ++ ++ ======================================================================== ++*/ ++VOID RTMPCancelTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ OUT BOOLEAN *pCancelled) ++{ ++ if (pTimer->Valid) ++ { ++ if (pTimer->State == FALSE) ++ pTimer->Repeat = FALSE; ++ RTMP_OS_Del_Timer(&pTimer->TimerObj, pCancelled); ++ ++ if (*pCancelled == TRUE) ++ pTimer->State = TRUE; ++ ++#ifdef RT2870 ++ // We need to go-through the TimerQ to findout this timer handler and remove it if ++ // it's still waiting for execution. ++ ++ RT2870_TimerQ_Remove(pTimer->pAd, pTimer); ++#endif // RT2870 // ++ } ++ else ++ { ++ // ++ // NdisMCancelTimer just canced the timer and not mean release the timer. ++ // And don't set the "Valid" to False. So that we can use this timer again. ++ // ++ DBGPRINT_ERR(("RTMPCancelTimer failed, Timer hasn't been initialize!\n")); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set LED Status ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Status LED Status ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSetLED( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Status) ++{ ++ //ULONG data; ++ UCHAR HighByte = 0; ++ UCHAR LowByte; ++ ++// In ATE mode of RT2860 AP/STA, we have erased 8051 firmware. ++// So LED mode is not supported when ATE is running. ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ LowByte = pAd->LedCntl.field.LedMode&0x7f; ++ switch (Status) ++ { ++ case LED_LINK_DOWN: ++ HighByte = 0x20; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ pAd->LedIndicatorStregth = 0; ++ break; ++ case LED_LINK_UP: ++ if (pAd->CommonCfg.Channel > 14) ++ HighByte = 0xa0; ++ else ++ HighByte = 0x60; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_RADIO_ON: ++ HighByte = 0x20; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_HALT: ++ LowByte = 0; // Driver sets MAC register and MAC controls LED ++ case LED_RADIO_OFF: ++ HighByte = 0; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_WPS: ++ HighByte = 0x10; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_ON_SITE_SURVEY: ++ HighByte = 0x08; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ case LED_POWER_UP: ++ HighByte = 0x04; ++ AsicSendCommandToMcu(pAd, 0x50, 0xff, LowByte, HighByte); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_WARN, ("RTMPSetLED::Unknown Status %d\n", Status)); ++ break; ++ } ++ ++ // ++ // Keep LED status for LED SiteSurvey mode. ++ // After SiteSurvey, we will set the LED mode to previous status. ++ // ++ if ((Status != LED_ON_SITE_SURVEY) && (Status != LED_POWER_UP)) ++ pAd->LedStatus = Status; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSetLED::Mode=%d,HighByte=0x%02x,LowByte=0x%02x\n", pAd->LedCntl.field.LedMode, HighByte, LowByte)); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set LED Signal Stregth ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Dbm Signal Stregth ++ ++ Return Value: ++ None ++ ++ IRQL = PASSIVE_LEVEL ++ ++ Note: ++ Can be run on any IRQL level. ++ ++ According to Microsoft Zero Config Wireless Signal Stregth definition as belows. ++ <= -90 No Signal ++ <= -81 Very Low ++ <= -71 Low ++ <= -67 Good ++ <= -57 Very Good ++ > -57 Excellent ++ ======================================================================== ++*/ ++VOID RTMPSetSignalLED( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_802_11_RSSI Dbm) ++{ ++ UCHAR nLed = 0; ++ ++ // ++ // if not Signal Stregth, then do nothing. ++ // ++ if (pAd->LedCntl.field.LedMode != LED_MODE_SIGNAL_STREGTH) ++ { ++ return; ++ } ++ ++ if (Dbm <= -90) ++ nLed = 0; ++ else if (Dbm <= -81) ++ nLed = 1; ++ else if (Dbm <= -71) ++ nLed = 3; ++ else if (Dbm <= -67) ++ nLed = 7; ++ else if (Dbm <= -57) ++ nLed = 15; ++ else ++ nLed = 31; ++ ++ // ++ // Update Signal Stregth to firmware if changed. ++ // ++ if (pAd->LedIndicatorStregth != nLed) ++ { ++ AsicSendCommandToMcu(pAd, 0x51, 0xff, nLed, pAd->LedCntl.field.Polarity); ++ pAd->LedIndicatorStregth = nLed; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Enable RX ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL <= DISPATCH_LEVEL ++ ++ Note: ++ Before Enable RX, make sure you have enabled Interrupt. ++ ======================================================================== ++*/ ++VOID RTMPEnableRxTx( ++ IN PRTMP_ADAPTER pAd) ++{ ++// WPDMA_GLO_CFG_STRUC GloCfg; ++// ULONG i = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPEnableRxTx\n")); ++ ++ // Enable Rx DMA. ++ RT28XXDMAEnable(pAd); ++ ++ // enable RX of MAC block ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ UINT32 rx_filter_flag = APNORMAL; ++ ++ ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, rx_filter_flag); // enable RX of DMA block ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ } ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc); ++ DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPEnableRxTx\n")); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/rtmp_tkip.c +@@ -0,0 +1,1613 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_tkip.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Wu 02-25-02 Initial ++*/ ++ ++#include "../rt_config.h" ++ ++// Rotation functions on 32 bit values ++#define ROL32( A, n ) \ ++ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) ) ++#define ROR32( A, n ) ROL32( (A), 32-(n) ) ++ ++UINT Tkip_Sbox_Lower[256] = ++{ ++ 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54, ++ 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A, ++ 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B, ++ 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B, ++ 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F, ++ 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F, ++ 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5, ++ 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F, ++ 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB, ++ 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97, ++ 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED, ++ 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A, ++ 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94, ++ 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3, ++ 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04, ++ 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D, ++ 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39, ++ 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95, ++ 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83, ++ 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76, ++ 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4, ++ 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B, ++ 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0, ++ 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18, ++ 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51, ++ 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85, ++ 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12, ++ 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9, ++ 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7, ++ 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A, ++ 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8, ++ 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A ++}; ++ ++UINT Tkip_Sbox_Upper[256] = ++{ ++ 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91, ++ 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC, ++ 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB, ++ 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B, ++ 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83, ++ 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A, ++ 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F, ++ 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA, ++ 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B, ++ 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13, ++ 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6, ++ 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85, ++ 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11, ++ 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B, ++ 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1, ++ 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF, ++ 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E, ++ 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6, ++ 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B, ++ 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD, ++ 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8, ++ 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2, ++ 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49, ++ 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10, ++ 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97, ++ 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F, ++ 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C, ++ 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27, ++ 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33, ++ 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5, ++ 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0, ++ 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C ++}; ++ ++/*****************************/ ++/******** SBOX Table *********/ ++/*****************************/ ++ ++UCHAR SboxTable[256] = ++{ ++ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, ++ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, ++ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, ++ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, ++ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, ++ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, ++ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, ++ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, ++ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, ++ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, ++ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, ++ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, ++ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, ++ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, ++ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, ++ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, ++ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, ++ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, ++ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, ++ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, ++ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, ++ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, ++ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, ++ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, ++ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, ++ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, ++ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, ++ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, ++ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, ++ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, ++ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, ++ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++}; ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round); ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a); ++// ++// Expanded IV for TKIP function. ++// ++typedef struct PACKED _IV_CONTROL_ ++{ ++ union PACKED ++ { ++ struct PACKED ++ { ++ UCHAR rc0; ++ UCHAR rc1; ++ UCHAR rc2; ++ ++ union PACKED ++ { ++ struct PACKED ++ { ++#ifdef RT_BIG_ENDIAN ++ UCHAR KeyID:2; ++ UCHAR ExtIV:1; ++ UCHAR Rsvd:5; ++#else ++ UCHAR Rsvd:5; ++ UCHAR ExtIV:1; ++ UCHAR KeyID:2; ++#endif ++ } field; ++ UCHAR Byte; ++ } CONTROL; ++ } field; ++ ++ ULONG word; ++ } IV16; ++ ++ ULONG IV32; ++} TKIP_IV, *PTKIP_IV; ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Convert from UCHAR[] to ULONG in a portable way ++ ++ Arguments: ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ULONG RTMPTkipGetUInt32( ++ IN PUCHAR pMICKey) ++{ ++ ULONG res = 0; ++ INT i; ++ ++ for (i = 0; i < 4; i++) ++ { ++ res |= (*pMICKey++) << (8 * i); ++ } ++ ++ return res; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Convert from ULONG to UCHAR[] in a portable way ++ ++ Arguments: ++ pDst pointer to destination for convert ULONG to UCHAR[] ++ val the value for convert ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipPutUInt32( ++ IN OUT PUCHAR pDst, ++ IN ULONG val) ++{ ++ INT i; ++ ++ for(i = 0; i < 4; i++) ++ { ++ *pDst++ = (UCHAR) (val & 0xff); ++ val >>= 8; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set the MIC Key. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipSetMICKey( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pMICKey) ++{ ++ // Set the key ++ pTkip->K0 = RTMPTkipGetUInt32(pMICKey); ++ pTkip->K1 = RTMPTkipGetUInt32(pMICKey + 4); ++ // and reset the message ++ pTkip->L = pTkip->K0; ++ pTkip->R = pTkip->K1; ++ pTkip->nBytesInM = 0; ++ pTkip->M = 0; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ uChar Append this uChar ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipAppendByte( ++ IN PTKIP_KEY_INFO pTkip, ++ IN UCHAR uChar) ++{ ++ // Append the byte to our word-sized buffer ++ pTkip->M |= (uChar << (8* pTkip->nBytesInM)); ++ pTkip->nBytesInM++; ++ // Process the word if it is full. ++ if( pTkip->nBytesInM >= 4 ) ++ { ++ pTkip->L ^= pTkip->M; ++ pTkip->R ^= ROL32( pTkip->L, 17 ); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ((pTkip->L & 0xff00ff00) >> 8) | ((pTkip->L & 0x00ff00ff) << 8); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ROL32( pTkip->L, 3 ); ++ pTkip->L += pTkip->R; ++ pTkip->R ^= ROR32( pTkip->L, 2 ); ++ pTkip->L += pTkip->R; ++ // Clear the buffer ++ pTkip->M = 0; ++ pTkip->nBytesInM = 0; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to source data for Calculate MIC Value ++ Len Indicate the length of the source data ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPTkipAppend( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pSrc, ++ IN UINT nBytes) ++{ ++ // This is simple ++ while(nBytes > 0) ++ { ++ RTMPTkipAppendByte(pTkip, *pSrc++); ++ nBytes--; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get the MIC Value. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ the MIC Value is store in pAd->PrivateInfo.MIC ++ ======================================================================== ++*/ ++VOID RTMPTkipGetMIC( ++ IN PTKIP_KEY_INFO pTkip) ++{ ++ // Append the minimum padding ++ RTMPTkipAppendByte(pTkip, 0x5a ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ RTMPTkipAppendByte(pTkip, 0 ); ++ // and then zeroes until the length is a multiple of 4 ++ while( pTkip->nBytesInM != 0 ) ++ { ++ RTMPTkipAppendByte(pTkip, 0 ); ++ } ++ // The appendByte function has already computed the result. ++ RTMPTkipPutUInt32(pTkip->MIC, pTkip->L); ++ RTMPTkipPutUInt32(pTkip->MIC + 4, pTkip->R); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init Tkip function. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. ++ KeyId TK Key ID ++ pTA Pointer to transmitter address ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitTkipEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN PUCHAR pTA, ++ IN PUCHAR pMICKey, ++ IN PUCHAR pTSC, ++ OUT PULONG pIV16, ++ OUT PULONG pIV32) ++{ ++ TKIP_IV tkipIv; ++ ++ // Prepare 8 bytes TKIP encapsulation for MPDU ++ NdisZeroMemory(&tkipIv, sizeof(TKIP_IV)); ++ tkipIv.IV16.field.rc0 = *(pTSC + 1); ++ tkipIv.IV16.field.rc1 = (tkipIv.IV16.field.rc0 | 0x20) & 0x7f; ++ tkipIv.IV16.field.rc2 = *pTSC; ++ tkipIv.IV16.field.CONTROL.field.ExtIV = 1; // 0: non-extended IV, 1: an extended IV ++ tkipIv.IV16.field.CONTROL.field.KeyID = KeyId; ++// tkipIv.IV32 = *(PULONG)(pTSC + 2); ++ NdisMoveMemory(&tkipIv.IV32, (pTSC + 2), 4); // Copy IV ++ ++ *pIV16 = tkipIv.IV16.word; ++ *pIV32 = tkipIv.IV32; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init MIC Value calculation function which include set MIC key & ++ calculate first 16 bytes (DA + SA + priority + 0) ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pTKey Pointer to the Temporal Key (TK), TK shall be 128bits. ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitMICEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN UCHAR UserPriority, ++ IN PUCHAR pMICKey) ++{ ++ ULONG Priority = UserPriority; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Tx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, (PUCHAR)&Priority, 4); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare MIC value of received MSDU ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to the received Plain text data ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ Len the length of the received plain text data exclude MIC value ++ ++ Return Value: ++ TRUE MIC value matched ++ FALSE MIC value mismatched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPTkipCompareMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UCHAR UserPriority, ++ IN UINT Len) ++{ ++ UCHAR OldMic[8]; ++ ULONG Priority = UserPriority; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); ++ ++ // Calculate MIC value from plain text data ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); ++ ++ // Get MIC valude from received frame ++ NdisMoveMemory(OldMic, pSrc + Len, 8); ++ ++ // Get MIC value from decrypted plain data ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); ++ ++ // Move MIC value from MSDU, this steps should move to data path. ++ // Since the MIC value might cross MPDUs. ++ if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValue(): TKIP MIC Error !\n")); //MIC error. ++ ++ ++ return (FALSE); ++ } ++ return (TRUE); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Compare MIC value of received MSDU ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pLLC LLC header ++ pSrc Pointer to the received Plain text data ++ pDA Pointer to DA address ++ pSA Pointer to SA address ++ pMICKey pointer to MIC Key ++ Len the length of the received plain text data exclude MIC value ++ ++ Return Value: ++ TRUE MIC value matched ++ FALSE MIC value mismatched ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPTkipCompareMICValueWithLLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pLLC, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UINT Len) ++{ ++ UCHAR OldMic[8]; ++ ULONG Priority = 0; ++ ++ // Init MIC value calculation ++ RTMPTkipSetMICKey(&pAd->PrivateInfo.Rx, pMICKey); ++ // DA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pDA, MAC_ADDR_LEN); ++ // SA ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSA, MAC_ADDR_LEN); ++ // Priority + 3 bytes of 0 ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, (PUCHAR)&Priority, 4); ++ ++ // Start with LLC header ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pLLC, 8); ++ ++ // Calculate MIC value from plain text data ++ RTMPTkipAppend(&pAd->PrivateInfo.Rx, pSrc, Len); ++ ++ // Get MIC valude from received frame ++ NdisMoveMemory(OldMic, pSrc + Len, 8); ++ ++ // Get MIC value from decrypted plain data ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Rx); ++ ++ // Move MIC value from MSDU, this steps should move to data path. ++ // Since the MIC value might cross MPDUs. ++ if(!NdisEqualMemory(pAd->PrivateInfo.Rx.MIC, OldMic, 8)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTMPTkipCompareMICValueWithLLC(): TKIP MIC Error !\n")); //MIC error. ++ ++ ++ return (FALSE); ++ } ++ return (TRUE); ++} ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware transmit function ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to Ndis Packet for MIC calculation ++ pEncap Pointer to LLC encap data ++ LenEncap Total encap length, might be 0 which indicates no encap ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPCalculateMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pEncap, ++ IN PCIPHER_KEY pKey, ++ IN UCHAR apidx) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ PUCHAR pSrc; ++ UCHAR UserPriority; ++ UCHAR vlan_offset = 0; ++ ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ UserPriority = RTMP_GET_PACKET_UP(pPacket); ++ pSrc = pSrcBufVA; ++ ++ // determine if this is a vlan packet ++ if (((*(pSrc + 12) << 8) + *(pSrc + 13)) == 0x8100) ++ vlan_offset = 4; ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ { ++ RTMPInitMICEngine( ++ pAd, ++ pKey->Key, ++ pSrc, ++ pSrc + 6, ++ UserPriority, ++ pKey->TxMic); ++ } ++ ++ ++ if (pEncap != NULL) ++ { ++ // LLC encapsulation ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pEncap, 6); ++ // Protocol Type ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc + 12 + vlan_offset, 2); ++ } ++ SrcBufLen -= (14 + vlan_offset); ++ pSrc += (14 + vlan_offset); ++ do ++ { ++ if (SrcBufLen > 0) ++ { ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pSrc, SrcBufLen); ++ } ++ ++ break; // No need handle next packet ++ ++ } while (TRUE); // End of copying payload ++ ++ // Compute the final MIC Value ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); ++} ++ ++ ++/************************************************************/ ++/* tkip_sbox() */ ++/* Returns a 16 bit value from a 64K entry table. The Table */ ++/* is synthesized from two 256 entry byte wide tables. */ ++/************************************************************/ ++ ++UINT tkip_sbox(UINT index) ++{ ++ UINT index_low; ++ UINT index_high; ++ UINT left, right; ++ ++ index_low = (index % 256); ++ index_high = ((index >> 8) % 256); ++ ++ left = Tkip_Sbox_Lower[index_low] + (Tkip_Sbox_Upper[index_low] * 256); ++ right = Tkip_Sbox_Upper[index_high] + (Tkip_Sbox_Lower[index_high] * 256); ++ ++ return (left ^ right); ++} ++ ++UINT rotr1(UINT a) ++{ ++ unsigned int b; ++ ++ if ((a & 0x01) == 0x01) ++ { ++ b = (a >> 1) | 0x8000; ++ } ++ else ++ { ++ b = (a >> 1) & 0x7fff; ++ } ++ b = b % 65536; ++ return b; ++} ++ ++VOID RTMPTkipMixKey( ++ UCHAR *key, ++ UCHAR *ta, ++ ULONG pnl, /* Least significant 16 bits of PN */ ++ ULONG pnh, /* Most significant 32 bits of PN */ ++ UCHAR *rc4key, ++ UINT *p1k) ++{ ++ ++ UINT tsc0; ++ UINT tsc1; ++ UINT tsc2; ++ ++ UINT ppk0; ++ UINT ppk1; ++ UINT ppk2; ++ UINT ppk3; ++ UINT ppk4; ++ UINT ppk5; ++ ++ INT i; ++ INT j; ++ ++ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ ++ tsc1 = (unsigned int)(pnh % 65536); ++ tsc2 = (unsigned int)(pnl % 65536); /* lsb */ ++ ++ /* Phase 1, step 1 */ ++ p1k[0] = tsc1; ++ p1k[1] = tsc0; ++ p1k[2] = (UINT)(ta[0] + (ta[1]*256)); ++ p1k[3] = (UINT)(ta[2] + (ta[3]*256)); ++ p1k[4] = (UINT)(ta[4] + (ta[5]*256)); ++ ++ /* Phase 1, step 2 */ ++ for (i=0; i<8; i++) ++ { ++ j = 2*(i & 1); ++ p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*key[1+j]) + key[j])) % 65536 )) % 65536; ++ p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*key[5+j]) + key[4+j])) % 65536 )) % 65536; ++ p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*key[9+j]) + key[8+j])) % 65536 )) % 65536; ++ p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*key[13+j]) + key[12+j])) % 65536 )) % 65536; ++ p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*key[1+j]) + key[j]))) % 65536 )) % 65536; ++ p1k[4] = (p1k[4] + i) % 65536; ++ } ++ ++ /* Phase 2, Step 1 */ ++ ppk0 = p1k[0]; ++ ppk1 = p1k[1]; ++ ppk2 = p1k[2]; ++ ppk3 = p1k[3]; ++ ppk4 = p1k[4]; ++ ppk5 = (p1k[4] + tsc2) % 65536; ++ ++ /* Phase2, Step 2 */ ++ ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*key[1]) + key[0])) % 65536); ++ ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*key[3]) + key[2])) % 65536); ++ ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*key[5]) + key[4])) % 65536); ++ ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*key[7]) + key[6])) % 65536); ++ ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*key[9]) + key[8])) % 65536); ++ ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*key[11]) + key[10])) % 65536); ++ ++ ppk0 = ppk0 + rotr1(ppk5 ^ ((256*key[13]) + key[12])); ++ ppk1 = ppk1 + rotr1(ppk0 ^ ((256*key[15]) + key[14])); ++ ppk2 = ppk2 + rotr1(ppk1); ++ ppk3 = ppk3 + rotr1(ppk2); ++ ppk4 = ppk4 + rotr1(ppk3); ++ ppk5 = ppk5 + rotr1(ppk4); ++ ++ /* Phase 2, Step 3 */ ++ /* Phase 2, Step 3 */ ++ ++ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */ ++ tsc1 = (unsigned int)(pnh % 65536); ++ tsc2 = (unsigned int)(pnl % 65536); /* lsb */ ++ ++ rc4key[0] = (tsc2 >> 8) % 256; ++ rc4key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f; ++ rc4key[2] = tsc2 % 256; ++ rc4key[3] = ((ppk5 ^ ((256*key[1]) + key[0])) >> 1) % 256; ++ ++ rc4key[4] = ppk0 % 256; ++ rc4key[5] = (ppk0 >> 8) % 256; ++ ++ rc4key[6] = ppk1 % 256; ++ rc4key[7] = (ppk1 >> 8) % 256; ++ ++ rc4key[8] = ppk2 % 256; ++ rc4key[9] = (ppk2 >> 8) % 256; ++ ++ rc4key[10] = ppk3 % 256; ++ rc4key[11] = (ppk3 >> 8) % 256; ++ ++ rc4key[12] = ppk4 % 256; ++ rc4key[13] = (ppk4 >> 8) % 256; ++ ++ rc4key[14] = ppk5 % 256; ++ rc4key[15] = (ppk5 >> 8) % 256; ++} ++ ++ ++/************************************************/ ++/* construct_mic_header1() */ ++/* Builds the first MIC header block from */ ++/* header fields. */ ++/************************************************/ ++ ++void construct_mic_header1( ++ unsigned char *mic_header1, ++ int header_length, ++ unsigned char *mpdu) ++{ ++ mic_header1[0] = (unsigned char)((header_length - 2) / 256); ++ mic_header1[1] = (unsigned char)((header_length - 2) % 256); ++ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ ++ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ ++ mic_header1[4] = mpdu[4]; /* A1 */ ++ mic_header1[5] = mpdu[5]; ++ mic_header1[6] = mpdu[6]; ++ mic_header1[7] = mpdu[7]; ++ mic_header1[8] = mpdu[8]; ++ mic_header1[9] = mpdu[9]; ++ mic_header1[10] = mpdu[10]; /* A2 */ ++ mic_header1[11] = mpdu[11]; ++ mic_header1[12] = mpdu[12]; ++ mic_header1[13] = mpdu[13]; ++ mic_header1[14] = mpdu[14]; ++ mic_header1[15] = mpdu[15]; ++} ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++ ++void construct_mic_header2( ++ unsigned char *mic_header2, ++ unsigned char *mpdu, ++ int a4_exists, ++ int qc_exists) ++{ ++ int i; ++ ++ for (i = 0; i<16; i++) mic_header2[i]=0x00; ++ ++ mic_header2[0] = mpdu[16]; /* A3 */ ++ mic_header2[1] = mpdu[17]; ++ mic_header2[2] = mpdu[18]; ++ mic_header2[3] = mpdu[19]; ++ mic_header2[4] = mpdu[20]; ++ mic_header2[5] = mpdu[21]; ++ ++ // In Sequence Control field, mute sequence numer bits (12-bit) ++ mic_header2[6] = mpdu[22] & 0x0f; /* SC */ ++ mic_header2[7] = 0x00; /* mpdu[23]; */ ++ ++ if ((!qc_exists) & a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ } ++ ++ if (qc_exists && (!a4_exists)) ++ { ++ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ ++ mic_header2[9] = mpdu[25] & 0x00; ++ } ++ ++ if (qc_exists && a4_exists) ++ { ++ for (i=0;i<6;i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ ++ ++ mic_header2[14] = mpdu[30] & 0x0f; ++ mic_header2[15] = mpdu[31] & 0x00; ++ } ++} ++ ++ ++/************************************************/ ++/* construct_mic_iv() */ ++/* Builds the MIC IV from header fields and PN */ ++/************************************************/ ++ ++void construct_mic_iv( ++ unsigned char *mic_iv, ++ int qc_exists, ++ int a4_exists, ++ unsigned char *mpdu, ++ unsigned int payload_length, ++ unsigned char *pn_vector) ++{ ++ int i; ++ ++ mic_iv[0] = 0x59; ++ if (qc_exists && a4_exists) ++ mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ ++ if (qc_exists && !a4_exists) ++ mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ ++ if (!qc_exists) ++ mic_iv[1] = 0x00; ++ for (i = 2; i < 8; i++) ++ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ ++#ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ ++#else ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ ++#endif ++ i = (payload_length / 256); ++ i = (payload_length % 256); ++ mic_iv[14] = (unsigned char) (payload_length / 256); ++ mic_iv[15] = (unsigned char) (payload_length % 256); ++ ++} ++ ++ ++ ++/************************************/ ++/* bitwise_xor() */ ++/* A 128 bit, bitwise exclusive or */ ++/************************************/ ++ ++void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out) ++{ ++ int i; ++ for (i=0; i<16; i++) ++ { ++ out[i] = ina[i] ^ inb[i]; ++ } ++} ++ ++ ++void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext) ++{ ++ int round; ++ int i; ++ unsigned char intermediatea[16]; ++ unsigned char intermediateb[16]; ++ unsigned char round_key[16]; ++ ++ for(i=0; i<16; i++) round_key[i] = key[i]; ++ ++ for (round = 0; round < 11; round++) ++ { ++ if (round == 0) ++ { ++ xor_128(round_key, data, ciphertext); ++ next_key(round_key, round); ++ } ++ else if (round == 10) ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ xor_128(intermediateb, round_key, ciphertext); ++ } ++ else /* 1 - 9 */ ++ { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ mix_column(&intermediateb[0], &intermediatea[0]); ++ mix_column(&intermediateb[4], &intermediatea[4]); ++ mix_column(&intermediateb[8], &intermediatea[8]); ++ mix_column(&intermediateb[12], &intermediatea[12]); ++ xor_128(intermediatea, round_key, ciphertext); ++ next_key(round_key, round); ++ } ++ } ++ ++} ++ ++void construct_ctr_preload( ++ unsigned char *ctr_preload, ++ int a4_exists, ++ int qc_exists, ++ unsigned char *mpdu, ++ unsigned char *pn_vector, ++ int c) ++{ ++ ++ int i = 0; ++ for (i=0; i<16; i++) ctr_preload[i] = 0x00; ++ i = 0; ++ ++ ctr_preload[0] = 0x01; /* flag */ ++ if (qc_exists && a4_exists) ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ ++ if (qc_exists && !a4_exists) ctr_preload[1] = mpdu[24] & 0x0f; ++ ++ for (i = 2; i < 8; i++) ++ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ ++#ifdef CONSISTENT_PN_ORDER ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ ++#else ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ ++#endif ++ ctr_preload[14] = (unsigned char) (c / 256); // Ctr ++ ctr_preload[15] = (unsigned char) (c % 256); ++ ++} ++ ++ ++// ++// TRUE: Success! ++// FALSE: Decrypt Error! ++// ++BOOLEAN RTMPSoftDecryptTKIP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN UCHAR UserPriority, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ UCHAR KeyID; ++ UINT HeaderLen; ++ UCHAR fc0; ++ UCHAR fc1; ++ USHORT fc; ++ UINT frame_type; ++ UINT frame_subtype; ++ UINT from_ds; ++ UINT to_ds; ++ INT a4_exists; ++ INT qc_exists; ++ USHORT duration; ++ USHORT seq_control; ++ USHORT qos_control; ++ UCHAR TA[MAC_ADDR_LEN]; ++ UCHAR DA[MAC_ADDR_LEN]; ++ UCHAR SA[MAC_ADDR_LEN]; ++ UCHAR RC4Key[16]; ++ UINT p1k[5]; //for mix_key; ++ ULONG pnl;/* Least significant 16 bits of PN */ ++ ULONG pnh;/* Most significant 32 bits of PN */ ++ UINT num_blocks; ++ UINT payload_remainder; ++ ARCFOURCONTEXT ArcFourContext; ++ UINT crc32 = 0; ++ UINT trailfcs = 0; ++ UCHAR MIC[8]; ++ UCHAR TrailMIC[8]; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ fc0 = *pData; ++ fc1 = *(pData + 1); ++ ++ fc = *((PUSHORT)pData); ++ ++ frame_type = ((fc0 >> 2) & 0x03); ++ frame_subtype = ((fc0 >> 4) & 0x0f); ++ ++ from_ds = (fc1 & 0x2) >> 1; ++ to_ds = (fc1 & 0x1); ++ ++ a4_exists = (from_ds & to_ds); ++ qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ ++ (frame_subtype == 0x09) || /* Likely to change. */ ++ (frame_subtype == 0x0a) || ++ (frame_subtype == 0x0b) ++ ); ++ ++ HeaderLen = 24; ++ if (a4_exists) ++ HeaderLen += 6; ++ ++ KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); ++ KeyID = KeyID >> 6; ++ ++ if (pWpaKey[KeyID].KeyLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP failed!(KeyID[%d] Length can not be 0)\n", KeyID)); ++ return FALSE; ++ } ++ ++ duration = *((PUSHORT)(pData+2)); ++ ++ seq_control = *((PUSHORT)(pData+22)); ++ ++ if (qc_exists) ++ { ++ if (a4_exists) ++ { ++ qos_control = *((PUSHORT)(pData+30)); ++ } ++ else ++ { ++ qos_control = *((PUSHORT)(pData+24)); ++ } ++ } ++ ++ if (to_ds == 0 && from_ds == 1) ++ { ++ NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+16, MAC_ADDR_LEN); ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); //BSSID ++ } ++ else if (to_ds == 0 && from_ds == 0 ) ++ { ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+4, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); ++ } ++ else if (to_ds == 1 && from_ds == 0) ++ { ++ NdisMoveMemory(SA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); ++ } ++ else if (to_ds == 1 && from_ds == 1) ++ { ++ NdisMoveMemory(TA, pData+10, MAC_ADDR_LEN); ++ NdisMoveMemory(DA, pData+16, MAC_ADDR_LEN); ++ NdisMoveMemory(SA, pData+22, MAC_ADDR_LEN); ++ } ++ ++ num_blocks = (DataByteCnt - 16) / 16; ++ payload_remainder = (DataByteCnt - 16) % 16; ++ ++ pnl = (*(pData + HeaderLen)) * 256 + *(pData + HeaderLen + 2); ++ pnh = *((PULONG)(pData + HeaderLen + 4)); ++ pnh = cpu2le32(pnh); ++ RTMPTkipMixKey(pWpaKey[KeyID].Key, TA, pnl, pnh, RC4Key, p1k); ++ ++ ARCFOUR_INIT(&ArcFourContext, RC4Key, 16); ++ ++ ARCFOUR_DECRYPT(&ArcFourContext, pData + HeaderLen, pData + HeaderLen + 8, DataByteCnt - HeaderLen - 8); ++ NdisMoveMemory(&trailfcs, pData + DataByteCnt - 8 - 4, 4); ++ crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 4); //Skip IV+EIV 8 bytes & Skip last 4 bytes(FCS). ++ crc32 ^= 0xffffffff; /* complement */ ++ ++ if(crc32 != cpu2le32(trailfcs)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptTKIP, WEP Data ICV Error !\n")); //ICV error. ++ ++ return (FALSE); ++ } ++ ++ NdisMoveMemory(TrailMIC, pData + DataByteCnt - 8 - 8 - 4, 8); ++ RTMPInitMICEngine(pAd, pWpaKey[KeyID].Key, DA, SA, UserPriority, pWpaKey[KeyID].RxMic); ++ RTMPTkipAppend(&pAd->PrivateInfo.Tx, pData + HeaderLen, DataByteCnt - HeaderLen - 8 - 12); ++ RTMPTkipGetMIC(&pAd->PrivateInfo.Tx); ++ NdisMoveMemory(MIC, pAd->PrivateInfo.Tx.MIC, 8); ++ ++ if (!NdisEqualMemory(MIC, TrailMIC, 8)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptTKIP, WEP Data MIC Error !\n")); //MIC error. ++ //RTMPReportMicError(pAd, &pWpaKey[KeyID]); // marked by AlbertY @ 20060630 ++ return (FALSE); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ //DBGPRINT(RT_DEBUG_TRACE, "RTMPSoftDecryptTKIP Decript done!!\n"); ++ return TRUE; ++} ++ ++ ++ ++ ++BOOLEAN RTMPSoftDecryptAES( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ UCHAR KeyID; ++ UINT HeaderLen; ++ UCHAR PN[6]; ++ UINT payload_len; ++ UINT num_blocks; ++ UINT payload_remainder; ++ USHORT fc; ++ UCHAR fc0; ++ UCHAR fc1; ++ UINT frame_type; ++ UINT frame_subtype; ++ UINT from_ds; ++ UINT to_ds; ++ INT a4_exists; ++ INT qc_exists; ++ UCHAR aes_out[16]; ++ int payload_index; ++ UINT i; ++ UCHAR ctr_preload[16]; ++ UCHAR chain_buffer[16]; ++ UCHAR padded_buffer[16]; ++ UCHAR mic_iv[16]; ++ UCHAR mic_header1[16]; ++ UCHAR mic_header2[16]; ++ UCHAR MIC[8]; ++ UCHAR TrailMIC[8]; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ fc0 = *pData; ++ fc1 = *(pData + 1); ++ ++ fc = *((PUSHORT)pData); ++ ++ frame_type = ((fc0 >> 2) & 0x03); ++ frame_subtype = ((fc0 >> 4) & 0x0f); ++ ++ from_ds = (fc1 & 0x2) >> 1; ++ to_ds = (fc1 & 0x1); ++ ++ a4_exists = (from_ds & to_ds); ++ qc_exists = ((frame_subtype == 0x08) || /* Assumed QoS subtypes */ ++ (frame_subtype == 0x09) || /* Likely to change. */ ++ (frame_subtype == 0x0a) || ++ (frame_subtype == 0x0b) ++ ); ++ ++ HeaderLen = 24; ++ if (a4_exists) ++ HeaderLen += 6; ++ ++ KeyID = *((PUCHAR)(pData+ HeaderLen + 3)); ++ KeyID = KeyID >> 6; ++ ++ if (pWpaKey[KeyID].KeyLen == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSoftDecryptAES failed!(KeyID[%d] Length can not be 0)\n", KeyID)); ++ return FALSE; ++ } ++ ++ PN[0] = *(pData+ HeaderLen); ++ PN[1] = *(pData+ HeaderLen + 1); ++ PN[2] = *(pData+ HeaderLen + 4); ++ PN[3] = *(pData+ HeaderLen + 5); ++ PN[4] = *(pData+ HeaderLen + 6); ++ PN[5] = *(pData+ HeaderLen + 7); ++ ++ payload_len = DataByteCnt - HeaderLen - 8 - 8; // 8 bytes for CCMP header , 8 bytes for MIC ++ payload_remainder = (payload_len) % 16; ++ num_blocks = (payload_len) / 16; ++ ++ ++ ++ // Find start of payload ++ payload_index = HeaderLen + 8; //IV+EIV ++ ++ for (i=0; i< num_blocks; i++) ++ { ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ i+1 ); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, pData + payload_index, chain_buffer); ++ NdisMoveMemory(pData + payload_index - 8, chain_buffer, 16); ++ payload_index += 16; ++ } ++ ++ // ++ // If there is a short final block, then pad it ++ // encrypt it and copy the unpadded part back ++ // ++ if (payload_remainder > 0) ++ { ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ num_blocks + 1); ++ ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ NdisMoveMemory(pData + payload_index - 8, chain_buffer, payload_remainder); ++ payload_index += payload_remainder; ++ } ++ ++ // ++ // Descrypt the MIC ++ // ++ construct_ctr_preload(ctr_preload, ++ a4_exists, ++ qc_exists, ++ pData, ++ PN, ++ 0); ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, 8); ++ ++ aes128k128d(pWpaKey[KeyID].Key, ctr_preload, aes_out); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ ++ NdisMoveMemory(TrailMIC, chain_buffer, 8); ++ ++ // ++ // Calculate MIC ++ // ++ ++ //Force the protected frame bit on ++ *(pData + 1) = *(pData + 1) | 0x40; ++ ++ // Find start of payload ++ // Because the CCMP header has been removed ++ payload_index = HeaderLen; ++ ++ construct_mic_iv( ++ mic_iv, ++ qc_exists, ++ a4_exists, ++ pData, ++ payload_len, ++ PN); ++ ++ construct_mic_header1( ++ mic_header1, ++ HeaderLen, ++ pData); ++ ++ construct_mic_header2( ++ mic_header2, ++ pData, ++ a4_exists, ++ qc_exists); ++ ++ aes128k128d(pWpaKey[KeyID].Key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ ++ // iterate through each 16 byte payload block ++ for (i = 0; i < num_blocks; i++) ++ { ++ bitwise_xor(aes_out, pData + payload_index, chain_buffer); ++ payload_index += 16; ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ } ++ ++ // Add on the final payload block if it needs padding ++ if (payload_remainder > 0) ++ { ++ NdisZeroMemory(padded_buffer, 16); ++ NdisMoveMemory(padded_buffer, pData + payload_index, payload_remainder); ++ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(pWpaKey[KeyID].Key, chain_buffer, aes_out); ++ } ++ ++ // aes_out contains padded mic, discard most significant ++ // 8 bytes to generate 64 bit MIC ++ for (i = 0 ; i < 8; i++) MIC[i] = aes_out[i]; ++ ++ if (!NdisEqualMemory(MIC, TrailMIC, 8)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTMPSoftDecryptAES, MIC Error !\n")); //MIC error. ++ return FALSE; ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pData, DIR_READ, FALSE); ++#endif ++ ++ return TRUE; ++} ++ ++/****************************************/ ++/* aes128k128d() */ ++/* Performs a 128 bit AES encrypt with */ ++/* 128 bit data. */ ++/****************************************/ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0;i<16; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round) ++{ ++ UCHAR rcon; ++ UCHAR sbox_key[4]; ++ UCHAR rcon_table[12] = ++ { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++ 0x1b, 0x36, 0x36, 0x36 ++ }; ++ ++ sbox_key[0] = RTMPCkipSbox(key[13]); ++ sbox_key[1] = RTMPCkipSbox(key[14]); ++ sbox_key[2] = RTMPCkipSbox(key[15]); ++ sbox_key[3] = RTMPCkipSbox(key[12]); ++ ++ rcon = rcon_table[round]; ++ ++ xor_32(&key[0], sbox_key, &key[0]); ++ key[0] = key[0] ^ rcon; ++ ++ xor_32(&key[4], &key[0], &key[4]); ++ xor_32(&key[8], &key[4], &key[8]); ++ xor_32(&key[12], &key[8], &key[12]); ++} ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0;i<4; i++) ++ { ++ out[i] = a[i] ^ b[i]; ++ } ++} ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ INT i; ++ ++ for (i=0; i< 16; i++) ++ { ++ out[i] = RTMPCkipSbox(in[i]); ++ } ++} ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a) ++{ ++ return SboxTable[(int)a]; ++} ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ out[0] = in[0]; ++ out[1] = in[5]; ++ out[2] = in[10]; ++ out[3] = in[15]; ++ out[4] = in[4]; ++ out[5] = in[9]; ++ out[6] = in[14]; ++ out[7] = in[3]; ++ out[8] = in[8]; ++ out[9] = in[13]; ++ out[10] = in[2]; ++ out[11] = in[7]; ++ out[12] = in[12]; ++ out[13] = in[1]; ++ out[14] = in[6]; ++ out[15] = in[11]; ++} ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out) ++{ ++ INT i; ++ UCHAR add1b[4]; ++ UCHAR add1bf7[4]; ++ UCHAR rotl[4]; ++ UCHAR swap_halfs[4]; ++ UCHAR andf7[4]; ++ UCHAR rotr[4]; ++ UCHAR temp[4]; ++ UCHAR tempb[4]; ++ ++ for (i=0 ; i<4; i++) ++ { ++ if ((in[i] & 0x80)== 0x80) ++ add1b[i] = 0x1b; ++ else ++ add1b[i] = 0x00; ++ } ++ ++ swap_halfs[0] = in[2]; /* Swap halfs */ ++ swap_halfs[1] = in[3]; ++ swap_halfs[2] = in[0]; ++ swap_halfs[3] = in[1]; ++ ++ rotl[0] = in[3]; /* Rotate left 8 bits */ ++ rotl[1] = in[0]; ++ rotl[2] = in[1]; ++ rotl[3] = in[2]; ++ ++ andf7[0] = in[0] & 0x7f; ++ andf7[1] = in[1] & 0x7f; ++ andf7[2] = in[2] & 0x7f; ++ andf7[3] = in[3] & 0x7f; ++ ++ for (i = 3; i>0; i--) /* logical shift left 1 bit */ ++ { ++ andf7[i] = andf7[i] << 1; ++ if ((andf7[i-1] & 0x80) == 0x80) ++ { ++ andf7[i] = (andf7[i] | 0x01); ++ } ++ } ++ andf7[0] = andf7[0] << 1; ++ andf7[0] = andf7[0] & 0xfe; ++ ++ xor_32(add1b, andf7, add1bf7); ++ ++ xor_32(in, add1bf7, rotr); ++ ++ temp[0] = rotr[0]; /* Rotate right 8 bits */ ++ rotr[0] = rotr[1]; ++ rotr[1] = rotr[2]; ++ rotr[2] = rotr[3]; ++ rotr[3] = temp[0]; ++ ++ xor_32(add1bf7, rotr, temp); ++ xor_32(swap_halfs, rotl,tempb); ++ xor_32(temp, tempb, out); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/rtmp_wep.c +@@ -0,0 +1,508 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_wep.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Wu 10-28-02 Initial ++*/ ++ ++#include "../rt_config.h" ++ ++UINT FCSTAB_32[256] = ++{ ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, ++ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, ++ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ++ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, ++ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, ++ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, ++ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ++ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, ++ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, ++ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, ++ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, ++ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, ++ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, ++ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ++ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, ++ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, ++ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, ++ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ++ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, ++ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, ++ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, ++ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, ++ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ++ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, ++ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, ++ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, ++ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ++ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, ++ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, ++ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, ++ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, ++ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, ++ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, ++ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ++ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, ++ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, ++ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, ++ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ++ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, ++ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, ++ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, ++ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, ++ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ++ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ++}; ++ ++/* ++UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ */ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init WEP function. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pKey Pointer to the WEP KEY ++ KeyId WEP Key ID ++ KeyLen the length of WEP KEY ++ pDest Pointer to the destination which Encryption data will store in. ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPInitWepEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN UCHAR KeyLen, ++ IN OUT PUCHAR pDest) ++{ ++ UINT i; ++ UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ ++ pAd->PrivateInfo.FCSCRC32 = PPPINITFCS32; //Init crc32. ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10) && (pAd->OpMode == OPMODE_STA)) ++ { ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, pKey, KeyLen); //INIT SBOX, KEYLEN+3(IV) ++ NdisMoveMemory(pDest, pKey, 3); //Append Init Vector ++ } ++ else ++#endif // CONFIG_STA_SUPPORT // ++ { ++ NdisMoveMemory(WEPKEY + 3, pKey, KeyLen); ++ ++ for(i = 0; i < 3; i++) ++ WEPKEY[i] = RandomByte(pAd); //Call mlme RandomByte() function. ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, KeyLen + 3); //INIT SBOX, KEYLEN+3(IV) ++ ++ NdisMoveMemory(pDest, WEPKEY, 3); //Append Init Vector ++ } ++ *(pDest+3) = (KeyId << 6); //Append KEYID ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Encrypt transimitted data ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pSrc Pointer to the transimitted source data that will be encrypt ++ pDest Pointer to the destination where entryption data will be store in. ++ Len Indicate the length of the source data ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPEncryptData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDest, ++ IN UINT Len) ++{ ++ pAd->PrivateInfo.FCSCRC32 = RTMP_CALC_FCS32(pAd->PrivateInfo.FCSCRC32, pSrc, Len); ++ ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, pSrc, Len); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Decrypt received WEP data ++ ++ Arguments: ++ pAdapter Pointer to our adapter ++ pSrc Pointer to the received data ++ Len the length of the received data ++ ++ Return Value: ++ TRUE Decrypt WEP data success ++ FALSE Decrypt WEP data failed ++ ++ Note: ++ ++ ======================================================================== ++*/ ++BOOLEAN RTMPSoftDecryptWEP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pGroupKey) ++{ ++ UINT trailfcs; ++ UINT crc32; ++ UCHAR KeyIdx; ++ UCHAR WEPKEY[] = { ++ //IV ++ 0x00, 0x11, 0x22, ++ //WEP KEY ++ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC ++ }; ++ UCHAR *pPayload = (UCHAR *)pData + LENGTH_802_11; ++ ULONG payload_len = DataByteCnt - LENGTH_802_11; ++ ++ NdisMoveMemory(WEPKEY, pPayload, 3); //Get WEP IV ++ ++ KeyIdx = (*(pPayload + 3) & 0xc0) >> 6; ++ if (pGroupKey[KeyIdx].KeyLen == 0) ++ return (FALSE); ++ ++ NdisMoveMemory(WEPKEY + 3, pGroupKey[KeyIdx].Key, pGroupKey[KeyIdx].KeyLen); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, WEPKEY, pGroupKey[KeyIdx].KeyLen + 3); ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, pPayload, pPayload + 4, payload_len - 4); ++ NdisMoveMemory(&trailfcs, pPayload + payload_len - 8, 4); ++ crc32 = RTMP_CALC_FCS32(PPPINITFCS32, pPayload, payload_len - 8); //Skip last 4 bytes(FCS). ++ crc32 ^= 0xffffffff; /* complement */ ++ ++ if(crc32 != cpu2le32(trailfcs)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("! WEP Data CRC Error !\n")); //CRC error. ++ return (FALSE); ++ } ++ return (TRUE); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm "ARCFOUR" initialize ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pKey Pointer to the WEP KEY ++ KeyLen Indicate the length fo the WEP KEY ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_INIT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pKey, ++ IN UINT KeyLen) ++{ ++ UCHAR t, u; ++ UINT keyindex; ++ UINT stateindex; ++ PUCHAR state; ++ UINT counter; ++ ++ state = Ctx->STATE; ++ Ctx->X = 0; ++ Ctx->Y = 0; ++ for (counter = 0; counter < 256; counter++) ++ state[counter] = (UCHAR)counter; ++ keyindex = 0; ++ stateindex = 0; ++ for (counter = 0; counter < 256; counter++) ++ { ++ t = state[counter]; ++ stateindex = (stateindex + pKey[keyindex] + t) & 0xff; ++ u = state[stateindex]; ++ state[stateindex] = t; ++ state[counter] = u; ++ if (++keyindex >= KeyLen) ++ keyindex = 0; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get bytes from ARCFOUR CONTEXT (S-BOX) ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ ++ Return Value: ++ UCHAR - the value of the ARCFOUR CONTEXT (S-BOX) ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UCHAR ARCFOUR_BYTE( ++ IN PARCFOURCONTEXT Ctx) ++{ ++ UINT x; ++ UINT y; ++ UCHAR sx, sy; ++ PUCHAR state; ++ ++ state = Ctx->STATE; ++ x = (Ctx->X + 1) & 0xff; ++ sx = state[x]; ++ y = (sx + Ctx->Y) & 0xff; ++ sy = state[y]; ++ Ctx->X = x; ++ Ctx->Y = y; ++ state[y] = sx; ++ state[x] = sy; ++ ++ return(state[(sx + sy) & 0xff]); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Decryption Algorithm ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source data ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_DECRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source dta ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ The Stream Cipher Encryption Algorithm which conform to the special requirement to encrypt GTK. ++ ++ Arguments: ++ Ctx Pointer to ARCFOUR CONTEXT (SBOX) ++ pDest Pointer to the Destination ++ pSrc Pointer to the Source data ++ Len Indicate the length of the Source dta ++ ++ ++ ======================================================================== ++*/ ++ ++VOID WPAARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len) ++{ ++ UINT i; ++ //discard first 256 bytes ++ for (i = 0; i < 256; i++) ++ ARCFOUR_BYTE(Ctx); ++ ++ for (i = 0; i < Len; i++) ++ pDest[i] = pSrc[i] ^ ARCFOUR_BYTE(Ctx); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Calculate a new FCS given the current FCS and the new data. ++ ++ Arguments: ++ Fcs the original FCS value ++ Cp pointer to the data which will be calculate the FCS ++ Len the length of the data ++ ++ Return Value: ++ UINT - FCS 32 bits ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++UINT RTMP_CALC_FCS32( ++ IN UINT Fcs, ++ IN PUCHAR Cp, ++ IN INT Len) ++{ ++ while (Len--) ++ Fcs = (((Fcs) >> 8) ^ FCSTAB_32[((Fcs) ^ (*Cp++)) & 0xff]); ++ ++ return (Fcs); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get last FCS and encrypt it to the destination ++ ++ Arguments: ++ pDest Pointer to the Destination ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPSetICV( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest) ++{ ++ pAd->PrivateInfo.FCSCRC32 ^= 0xffffffff; /* complement */ ++ pAd->PrivateInfo.FCSCRC32 = cpu2le32(pAd->PrivateInfo.FCSCRC32); ++ ++ ARCFOUR_ENCRYPT(&pAd->PrivateInfo.WEPCONTEXT, pDest, (PUCHAR) &pAd->PrivateInfo.FCSCRC32, 4); ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/rtusb_bulk.c +@@ -0,0 +1,1382 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtusb_bulk.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 06-25-2004 created ++ ++*/ ++ ++#include "../rt_config.h" ++// Match total 6 bulkout endpoint to corresponding queue. ++UCHAR EpToQueue[6]={FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_EDCA, FIFO_MGMT}; ++ ++//static BOOLEAN SingleBulkOut = FALSE; ++ ++void RTUSB_FILL_BULK_URB (struct urb *pUrb, ++ struct usb_device *pUsb_Dev, ++ unsigned int bulkpipe, ++ void *pTransferBuf, ++ int BufSize, ++ usb_complete_t Complete, ++ void *pContext) ++{ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ usb_fill_bulk_urb(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, (usb_complete_t)Complete, pContext); ++#else ++ FILL_BULK_URB(pUrb, pUsb_Dev, bulkpipe, pTransferBuf, BufSize, Complete, pContext); ++#endif ++ ++} ++ ++VOID RTUSBInitTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PTX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN usb_complete_t Func) ++{ ++ PURB pUrb; ++ PUCHAR pSrc = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pUrb = pTxContext->pUrb; ++ ASSERT(pUrb); ++ ++ // Store BulkOut PipeId ++ pTxContext->BulkOutPipeId = BulkOutPipeId; ++ ++ if (pTxContext->bAggregatible) ++ { ++ pSrc = &pTxContext->TransferBuffer->Aggregation[2]; ++ } ++ else ++ { ++ pSrc = (PUCHAR) pTxContext->TransferBuffer->field.WirelessPacket; ++ } ++ ++ ++ //Initialize a tx bulk urb ++ RTUSB_FILL_BULK_URB(pUrb, ++ pObj->pUsb_Dev, ++ usb_sndbulkpipe(pObj->pUsb_Dev, pAd->BulkOutEpAddr[BulkOutPipeId]), ++ pSrc, ++ pTxContext->BulkOutSize, ++ Func, ++ pTxContext); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ if (pTxContext->bAggregatible) ++ pUrb->transfer_dma = (pTxContext->data_dma + TX_BUFFER_NORMSIZE + 2); ++ else ++ pUrb->transfer_dma = pTxContext->data_dma; ++ ++ pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++#endif ++ ++} ++ ++VOID RTUSBInitHTTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PHT_TX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN ULONG BulkOutSize, ++ IN usb_complete_t Func) ++{ ++ PURB pUrb; ++ PUCHAR pSrc = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pUrb = pTxContext->pUrb; ++ ASSERT(pUrb); ++ ++ // Store BulkOut PipeId ++ pTxContext->BulkOutPipeId = BulkOutPipeId; ++ ++ pSrc = &pTxContext->TransferBuffer->field.WirelessPacket[pTxContext->NextBulkOutPosition]; ++ ++ ++ //Initialize a tx bulk urb ++ RTUSB_FILL_BULK_URB(pUrb, ++ pObj->pUsb_Dev, ++ usb_sndbulkpipe(pObj->pUsb_Dev, pAd->BulkOutEpAddr[BulkOutPipeId]), ++ pSrc, ++ BulkOutSize, ++ Func, ++ pTxContext); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ pUrb->transfer_dma = (pTxContext->data_dma + pTxContext->NextBulkOutPosition); ++ pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++#endif ++ ++} ++ ++VOID RTUSBInitRxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PRX_CONTEXT pRxContext) ++{ ++ PURB pUrb; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ULONG RX_bulk_size; ++ ++ ++ pUrb = pRxContext->pUrb; ++ ASSERT(pUrb); ++ ++ if ( pAd->BulkInMaxPacketSize == 64) ++ RX_bulk_size = 4096; ++ else ++ RX_bulk_size = MAX_RXBULK_SIZE; ++ ++ //Initialize a rx bulk urb ++ RTUSB_FILL_BULK_URB(pUrb, ++ pObj->pUsb_Dev, ++ usb_rcvbulkpipe(pObj->pUsb_Dev, pAd->BulkInEpAddr), ++ &(pRxContext->TransferBuffer[pAd->NextRxBulkInPosition]), ++ RX_bulk_size - (pAd->NextRxBulkInPosition), ++ (usb_complete_t)RTUSBBulkRxComplete, ++ (void *)pRxContext); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ pUrb->transfer_dma = pRxContext->data_dma + pAd->NextRxBulkInPosition; ++ pUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++#endif ++ ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++#define BULK_OUT_LOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_LOCK((pLock), IrqFlags); ++ ++#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_UNLOCK((pLock), IrqFlags); ++ ++ ++VOID RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UCHAR Index) ++{ ++ ++ PHT_TX_CONTEXT pHTTXContext; ++ PURB pUrb; ++ int ret = 0; ++ PTXINFO_STRUC pTxInfo, pLastTxInfo = NULL; ++ PTXWI_STRUC pTxWI; ++ ULONG TmpBulkEndPos, ThisBulkSize; ++ unsigned long IrqFlags = 0, IrqFlags2 = 0; ++ PUCHAR pWirelessPkt, pAppendant; ++ BOOLEAN bTxQLastRound = FALSE; ++ UCHAR allzero[4]= {0x0,0x0,0x0,0x0}; ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ if ((pAd->BulkOutPending[BulkOutPipeId] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[BulkOutPipeId] = TRUE; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) ++ ) ++ { ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ ++ pHTTXContext = &(pAd->TxContext[BulkOutPipeId]); ++ ++ BULK_OUT_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ if ((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) ++ || ((pHTTXContext->ENextBulkOutPosition-8) == pHTTXContext->CurWritePosition)) ++ { ++ BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ ++ // Clear Data flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId)); ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ ++ // Clear Data flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_FRAG << BulkOutPipeId)); ++ RTUSB_CLEAR_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ ++ //DBGPRINT(RT_DEBUG_TRACE,("BulkOut-B:I=0x%lx, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", in_interrupt(), ++ // pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, ++ // pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ pHTTXContext->NextBulkOutPosition = pHTTXContext->ENextBulkOutPosition; ++ ThisBulkSize = 0; ++ TmpBulkEndPos = pHTTXContext->NextBulkOutPosition; ++ pWirelessPkt = &pHTTXContext->TransferBuffer->field.WirelessPacket[0]; ++ ++ if ((pHTTXContext->bCopySavePad == TRUE)) ++ { ++ if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero,4)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("e1, allzero : %x %x %x %x %x %x %x %x \n", ++ pHTTXContext->SavedPad[0], pHTTXContext->SavedPad[1], pHTTXContext->SavedPad[2],pHTTXContext->SavedPad[3] ++ ,pHTTXContext->SavedPad[4], pHTTXContext->SavedPad[5], pHTTXContext->SavedPad[6],pHTTXContext->SavedPad[7])); ++ } ++ NdisMoveMemory(&pWirelessPkt[TmpBulkEndPos], pHTTXContext->SavedPad, 8); ++ pHTTXContext->bCopySavePad = FALSE; ++ if (pAd->bForcePrintTX == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE,("RTUSBBulkOutDataPacket --> COPY PAD. CurWrite = %ld, NextBulk = %ld. ENextBulk = %ld.\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition)); ++ } ++ ++ do ++ { ++ pTxInfo = (PTXINFO_STRUC)&pWirelessPkt[TmpBulkEndPos]; ++ pTxWI = (PTXWI_STRUC)&pWirelessPkt[TmpBulkEndPos + TXINFO_SIZE]; ++ ++ if (pAd->bForcePrintTX == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkOutDataPacket AMPDU = %d.\n", pTxWI->AMPDU)); ++ ++ // add by Iverson, limit BulkOut size to 4k to pass WMM b mode 2T1R test items ++ //if ((ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) ++ if ((ThisBulkSize != 0) && (pTxWI->PHYMODE == MODE_CCK)) ++ { ++#ifdef INF_AMAZON_SE ++ /*Iverson Add for AMAZON USB (RT2070 && RT3070) to pass WMM A2-T4 ~ A2-T10*/ ++ if(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) ++ { ++ /*Iverson patch for WMM A5-T07 ,WirelessStaToWirelessSta do not bulk out aggregate*/ ++ if(pTxWI->PacketId == 6) ++ { ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ else if (BulkOutPipeId == 1) ++ { ++ /*BK No Limit BulkOut size .*/ ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ else if (((ThisBulkSize&0xffff8000) != 0) || (((ThisBulkSize&0x1000) == 0x1000) && (BulkOutPipeId == 0) )) ++ { ++ /*BE Limit BulkOut size to about 4k bytes.*/ ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ else if (((ThisBulkSize&0xffff8000) != 0) || (((ThisBulkSize&0x1c00) == 0x1c00) && (BulkOutPipeId == 2) )) ++ { ++ /*VI Limit BulkOut size to about 7k bytes.*/ ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ else if (((ThisBulkSize&0xffff8000) != 0) || (((ThisBulkSize&0x2500) == 0x2500) && (BulkOutPipeId == 3) )) ++ { ++ /*VO Limit BulkOut size to about 9k bytes.*/ ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++ else if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x1000) == 0x1000)) ++ { ++ /* Limit BulkOut size to about 4k bytes.*/ ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++#else ++ if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x1000) == 0x1000)) ++ { ++ // Limit BulkOut size to about 4k bytes. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++#endif // INF_AMAZON_SE // ++ ++ else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0) ) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))*/) ++ { ++ // For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. ++ // For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++ // end Iverson ++ else ++ { ++#ifdef INF_AMAZON_SE ++//#ifdef DOT11_N_SUPPORT ++// if(((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000) || ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))) ++// { ++// /* AMAZON_SE: BG mode Disable BulkOut Aggregate, N mode BulkOut Aggregaet size 24K */ ++// pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++// break; ++// } ++// else ++//#endif // DOT11_N_SUPPORT // ++// { ++ if(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && (pTxWI->AMPDU == 0)) ++ { ++ if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0)) || ++ (ThisBulkSize != 0)) ++ { ++ /* AMAZON_SE: RT2070 Disable BulkOut Aggregate when WMM for USB issue */ ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++/* ++ else if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000)) ++ { ++ // Limit BulkOut size to about 24k bytes. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++*/ ++#endif // INF_AMAZON_SE // ++ ++ if (((ThisBulkSize&0xffff8000) != 0) || ((ThisBulkSize&0x6000) == 0x6000)) ++ { // Limit BulkOut size to about 24k bytes. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ ++ else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize&0xfffff800) != 0) ) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0))*/) ++ { // For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. ++ // For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ } ++ ++ if (TmpBulkEndPos == pHTTXContext->CurWritePosition) ++ { ++ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; ++ break; ++ } ++ //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if (pTxInfo->QSEL != FIFO_EDCA) ++ { ++ printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __FUNCTION__, pTxInfo->QSEL); ++ printk("\tCWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad); ++ hex_dump("Wrong QSel Pkt:", (PUCHAR)&pWirelessPkt[TmpBulkEndPos], (pHTTXContext->CurWritePosition - pHTTXContext->NextBulkOutPosition)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ if (pTxInfo->USBDMATxPktLen <= 8) ++ { ++ BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ DBGPRINT(RT_DEBUG_ERROR /*RT_DEBUG_TRACE*/,("e2, USBDMATxPktLen==0, Size=%ld, bCSPad=%d, CWPos=%ld, NBPos=%ld, CWRPos=%ld!\n", ++ pHTTXContext->BulkOutSize, pHTTXContext->bCopySavePad, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->CurWriteRealPos)); ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR /*RT_DEBUG_TRACE*/,("%x %x %x %x %x %x %x %x \n", ++ pHTTXContext->SavedPad[0], pHTTXContext->SavedPad[1], pHTTXContext->SavedPad[2],pHTTXContext->SavedPad[3] ++ ,pHTTXContext->SavedPad[4], pHTTXContext->SavedPad[5], pHTTXContext->SavedPad[6],pHTTXContext->SavedPad[7])); ++ } ++ pAd->bForcePrintTX = TRUE; ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ //DBGPRINT(RT_DEBUG_LOUD,("Out:pTxInfo->USBDMATxPktLen=%d!\n", pTxInfo->USBDMATxPktLen)); ++ return; ++ } ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.OneSecTransmittedByteCount += pTxWI->MPDUtotalByteCount; ++ pAd->RalinkCounters.TransmittedByteCount += pTxWI->MPDUtotalByteCount; ++ ++ pLastTxInfo = pTxInfo; ++ ++ // Make sure we use EDCA QUEUE. ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pTxInfo->QSEL = FIFO_EDCA; //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++#endif // CONFIG_STA_SUPPORT // ++ ThisBulkSize += (pTxInfo->USBDMATxPktLen+4); ++ TmpBulkEndPos += (pTxInfo->USBDMATxPktLen+4); ++ ++ if (TmpBulkEndPos != pHTTXContext->CurWritePosition) ++ pTxInfo->USBDMANextVLD = 1; ++ ++ if (pTxInfo->SwUseLastRound == 1) ++ { ++ if (pHTTXContext->CurWritePosition == 8) ++ pTxInfo->USBDMANextVLD = 0; ++ pTxInfo->SwUseLastRound = 0; ++ ++ bTxQLastRound = TRUE; ++ pHTTXContext->ENextBulkOutPosition = 8; ++ ++ #ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++ #endif // RT_BIG_ENDIAN // ++ ++ break; ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ }while (TRUE); ++ ++ // adjust the pTxInfo->USBDMANextVLD value of last pTxInfo. ++ if (pLastTxInfo) ++ { ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ pLastTxInfo->USBDMANextVLD = 0; ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pLastTxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ } ++ ++ /* ++ We need to copy SavedPad when following condition matched! ++ 1. Not the last round of the TxQueue and ++ 2. any match of following cases: ++ (1). The End Position of this bulk out is reach to the Currenct Write position and ++ the TxInfo and related header already write to the CurWritePosition. ++ =>(ENextBulkOutPosition == CurWritePosition) && (CurWriteRealPos > CurWritePosition) ++ ++ (2). The EndPosition of the bulk out is not reach to the Current Write Position. ++ =>(ENextBulkOutPosition != CurWritePosition) ++ */ ++ if ((bTxQLastRound == FALSE) && ++ (((pHTTXContext->ENextBulkOutPosition == pHTTXContext->CurWritePosition) && (pHTTXContext->CurWriteRealPos > pHTTXContext->CurWritePosition)) || ++ (pHTTXContext->ENextBulkOutPosition != pHTTXContext->CurWritePosition)) ++ ) ++ { ++ NdisMoveMemory(pHTTXContext->SavedPad, &pWirelessPkt[pHTTXContext->ENextBulkOutPosition], 8); ++ pHTTXContext->bCopySavePad = TRUE; ++ if (RTMPEqualMemory(pHTTXContext->SavedPad, allzero,4)) ++ { ++ PUCHAR pBuf = &pHTTXContext->SavedPad[0]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("WARNING-Zero-3:%02x%02x%02x%02x%02x%02x%02x%02x,CWPos=%ld, CWRPos=%ld, bCW=%d, NBPos=%ld, TBPos=%ld, TBSize=%ld\n", ++ pBuf[0], pBuf[1], pBuf[2],pBuf[3],pBuf[4], pBuf[5], pBuf[6],pBuf[7], pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, ++ pHTTXContext->bCurWriting, pHTTXContext->NextBulkOutPosition, TmpBulkEndPos, ThisBulkSize)); ++ ++ pBuf = &pWirelessPkt[pHTTXContext->CurWritePosition]; ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("\tCWPos=%02x%02x%02x%02x%02x%02x%02x%02x\n", pBuf[0], pBuf[1], pBuf[2],pBuf[3],pBuf[4], pBuf[5], pBuf[6],pBuf[7])); ++ } ++ //DBGPRINT(RT_DEBUG_LOUD,("ENPos==CWPos=%ld, CWRPos=%ld, bCSPad=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->bCopySavePad)); ++ } ++ ++ if (pAd->bForcePrintTX == TRUE) ++ DBGPRINT(RT_DEBUG_TRACE,("BulkOut-A:Size=%ld, CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad)); ++ //DBGPRINT(RT_DEBUG_LOUD,("BulkOut-A:Size=%ld, CWPos=%ld, CWRPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, bLRound=%d!\n", ThisBulkSize, pHTTXContext->CurWritePosition, pHTTXContext->CurWriteRealPos, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, bTxQLastRound)); ++ ++ // USB DMA engine requires to pad extra 4 bytes. This pad doesn't count into real bulkoutsize. ++ pAppendant = &pWirelessPkt[TmpBulkEndPos]; ++ NdisZeroMemory(pAppendant, 8); ++ ThisBulkSize += 4; ++ pHTTXContext->LastOne = TRUE; ++ if ((ThisBulkSize % pAd->BulkOutMaxPacketSize) == 0) ++ ThisBulkSize += 4; ++ pHTTXContext->BulkOutSize = ThisBulkSize; ++ ++ pAd->watchDogTxPendingCnt[BulkOutPipeId] = 1; ++ BULK_OUT_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags2); ++ ++ // Init Tx context descriptor ++ RTUSBInitHTTxDesc(pAd, pHTTXContext, BulkOutPipeId, ThisBulkSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); ++ ++ pUrb = pHTTXContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pAd->watchDogTxPendingCnt[BulkOutPipeId] = 0; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ return; ++ } ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pHTTXContext->IRPPending = TRUE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutReq++; ++ ++} ++ ++ ++VOID RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PHT_TX_CONTEXT pHTTXContext; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ UCHAR BulkOutPipeId; ++ ++ ++ pHTTXContext = (PHT_TX_CONTEXT)pUrb->context; ++ pAd = pHTTXContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pHTTXContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ switch (BulkOutPipeId) ++ { ++ case 0: ++ pObj->ac0_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac0_dma_done_task); ++ break; ++ case 1: ++ pObj->ac1_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac1_dma_done_task); ++ break; ++ case 2: ++ pObj->ac2_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac2_dma_done_task); ++ break; ++ case 3: ++ pObj->ac3_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->ac3_dma_done_task); ++ break; ++ case 4: ++ pObj->hcca_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->hcca_dma_done_task); ++ break; ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: NULL frame use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutNullFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ if ((pAd->BulkOutPending[0] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[0] = TRUE; ++ pAd->watchDogTxPendingCnt[0] = 1; ++ pNullContext->IRPPending = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; ++ ++ ++ // Clear Null frame bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pNullContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pNullContext, 0, (usb_complete_t)RTUSBBulkOutNullFrameComplete); ++ ++ pUrb = pNullContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ pNullContext->IRPPending = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutNullFrame: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++} ++ ++// NULL frame use BulkOutPipeId = 0 ++VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pNullContext; ++ NTSTATUS Status; ++ POS_COOKIE pObj; ++ ++ ++ pNullContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pNullContext->pAd; ++ Status = pUrb->status; ++ ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pObj->null_frame_complete_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->null_frame_complete_task); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: MLME use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutMLMEPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PTX_CONTEXT pMLMEContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa; ++ pUrb = pMLMEContext->pUrb; ++ ++ if ((pAd->MgmtRing.TxSwFreeIdx >= MGMT_RING_SIZE) || ++ (pMLMEContext->InUse == FALSE) || ++ (pMLMEContext->bWaitingBulkOut == FALSE)) ++ { ++ ++ ++ // Clear MLME bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ ++ return; ++ } ++ ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ if ((pAd->BulkOutPending[MGMTPIPEIDX] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ return; ++ } ++ ++ pAd->BulkOutPending[MGMTPIPEIDX] = TRUE; ++ pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 1; ++ pMLMEContext->IRPPending = TRUE; ++ pMLMEContext->bWaitingBulkOut = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.TransmittedByteCount += pMLMEContext->BulkOutSize; ++ ++ // Clear MLME bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pMLMEContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pMLMEContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutMLMEPacketComplete); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ //For mgmt urb buffer, because we use sk_buff, so we need to notify the USB controller do dma mapping. ++ pUrb->transfer_dma = 0; ++ pUrb->transfer_flags &= (~URB_NO_TRANSFER_DMA_MAP); ++#endif ++ ++ pUrb = pMLMEContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutMLMEPacket: Submit MLME URB failed %d\n", ret)); ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ pAd->watchDogTxPendingCnt[MGMTPIPEIDX] = 0; ++ pMLMEContext->IRPPending = FALSE; ++ pMLMEContext->bWaitingBulkOut = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[MGMTPIPEIDX], IrqFlags); ++ ++ return; ++ } ++ ++ //DBGPRINT_RAW(RT_DEBUG_INFO, ("<---RTUSBBulkOutMLMEPacket \n")); ++// printk("<---RTUSBBulkOutMLMEPacket,Cpu=%d!, Dma=%d, SwIdx=%d!\n", pAd->MgmtRing.TxCpuIdx, pAd->MgmtRing.TxDmaIdx, pAd->MgmtRing.TxSwFreeIdx); ++} ++ ++ ++VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PTX_CONTEXT pMLMEContext; ++ PRTMP_ADAPTER pAd; ++ NTSTATUS Status; ++ POS_COOKIE pObj; ++ int index; ++ ++ //DBGPRINT_RAW(RT_DEBUG_INFO, ("--->RTUSBBulkOutMLMEPacketComplete\n")); ++ pMLMEContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pMLMEContext->pAd; ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ Status = pUrb->status; ++ index = pMLMEContext->SelfIdx; ++ ++ pObj->mgmt_dma_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->mgmt_dma_done_task); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: PsPoll use BulkOutPipeId = 0 ++ ++ ======================================================================== ++*/ ++VOID RTUSBBulkOutPsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTX_CONTEXT pPsPollContext = &(pAd->PsPollContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ if ((pAd->BulkOutPending[0] == TRUE) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_TX)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ return; ++ } ++ pAd->BulkOutPending[0] = TRUE; ++ pAd->watchDogTxPendingCnt[0] = 1; ++ pPsPollContext->IRPPending = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ ++ // Clear PS-Poll bulk flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR)pPsPollContext->TransferBuffer, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pPsPollContext, MGMTPIPEIDX, (usb_complete_t)RTUSBBulkOutPsPollComplete); ++ ++ pUrb = pPsPollContext->pUrb; ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ pAd->watchDogTxPendingCnt[0] = 0; ++ pPsPollContext->IRPPending = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkOutPsPoll: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++} ++ ++// PS-Poll frame use BulkOutPipeId = 0 ++VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb,struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pPsPollContext; ++ NTSTATUS Status; ++ POS_COOKIE pObj; ++ ++ ++ pPsPollContext= (PTX_CONTEXT)pUrb->context; ++ pAd = pPsPollContext->pAd; ++ Status = pUrb->status; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ pObj->pspoll_frame_complete_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->pspoll_frame_complete_task); ++ ++} ++ ++VOID DoBulkIn(IN RTMP_ADAPTER *pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); ++ if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE) || (pRxContext->InUse == TRUE)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ return; ++ } ++ pRxContext->InUse = TRUE; ++ pRxContext->IRPPending = TRUE; ++ pAd->PendingRx++; ++ pAd->BulkInReq++; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Init Rx context descriptor ++ NdisZeroMemory(pRxContext->TransferBuffer, pRxContext->BulkInOffset); ++ RTUSBInitRxDesc(pAd, pRxContext); ++ ++ pUrb = pRxContext->pUrb; ++ if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { // fail ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pAd->PendingRx--; ++ pAd->BulkInReq--; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSBBulkReceive: Submit Rx URB failed %d\n", ret)); ++ } ++ else ++ { // success ++ ASSERT((pRxContext->InUse == pRxContext->IRPPending)); ++ //printk("BIDone, Pend=%d,BIIdx=%d,BIRIdx=%d!\n", pAd->PendingRx, pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex); ++ } ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ USB_RxPacket initializes a URB and uses the Rx IRP to submit it ++ to USB. It checks if an Rx Descriptor is available and passes the ++ the coresponding buffer to be filled. If no descriptor is available ++ fails the request. When setting the completion routine we pass our ++ Adapter Object as Context. ++ ++ Arguments: ++ ++ Return Value: ++ TRUE found matched tuple cache ++ FALSE no matched found ++ ++ Note: ++ ++ ======================================================================== ++*/ ++#define fRTMP_ADAPTER_NEED_STOP_RX \ ++ (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ ++ fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \ ++ fRTMP_ADAPTER_REMOVE_IN_PROGRESS | fRTMP_ADAPTER_BULKIN_RESET) ++ ++#define fRTMP_ADAPTER_NEED_STOP_HANDLE_RX \ ++ (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ ++ fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_RESET_IN_PROGRESS | \ ++ fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ++ ++VOID RTUSBBulkReceive( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ unsigned long IrqFlags; ++ ++ ++ /* sanity check */ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_HANDLE_RX)) ++ return; ++ ++ while(1) ++ { ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInReadIndex]); ++ if (((pRxContext->InUse == FALSE) && (pRxContext->Readable == TRUE)) && ++ (pRxContext->bRxHandling == FALSE)) ++ { ++ pRxContext->bRxHandling = TRUE; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // read RxContext, Since not ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ STARxDoneInterruptHandle(pAd, TRUE); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Finish to handle this bulkIn buffer. ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->BulkInOffset = 0; ++ pRxContext->Readable = FALSE; ++ pRxContext->bRxHandling = FALSE; ++ pAd->ReadPosition = 0; ++ pAd->TransferBufferLength = 0; ++ INC_RING_INDEX(pAd->NextRxBulkInReadIndex, RX_RING_SIZE); ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ } ++ else ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ break; ++ } ++ } ++ ++ if (!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NEED_STOP_RX))) ++ DoBulkIn(pAd); ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ This routine process Rx Irp and call rx complete function. ++ ++ Arguments: ++ DeviceObject Pointer to the device object for next lower ++ device. DeviceObject passed in here belongs to ++ the next lower driver in the stack because we ++ were invoked via IoCallDriver in USB_RxPacket ++ AND it is not OUR device object ++ Irp Ptr to completed IRP ++ Context Ptr to our Adapter object (context specified ++ in IoSetCompletionRoutine ++ ++ Return Value: ++ Always returns STATUS_MORE_PROCESSING_REQUIRED ++ ++ Note: ++ Always returns STATUS_MORE_PROCESSING_REQUIRED ++ ======================================================================== ++*/ ++VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ // use a receive tasklet to handle received packets; ++ // or sometimes hardware IRQ will be disabled here, so we can not ++ // use spin_lock_bh()/spin_unlock_bh() after IRQ is disabled. :< ++ PRX_CONTEXT pRxContext; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ ++ ++ pRxContext = (PRX_CONTEXT)pUrb->context; ++ pAd = pRxContext->pAd; ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ pObj->rx_done_task.data = (unsigned long)pUrb; ++ tasklet_hi_schedule(&pObj->rx_done_task); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBKickBulkOut( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // BulkIn Reset will reset whole USB PHY. So we need to make sure fRTMP_ADAPTER_BULKIN_RESET not flaged. ++ if (!RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX) ++#ifdef RALINK_ATE ++ && !(ATE_ON(pAd)) ++#endif // RALINK_ATE // ++ ) ++ { ++ // 2. PS-Poll frame is next ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL)) ++ { ++ RTUSBBulkOutPsPoll(pAd); ++ } ++ ++ // 5. Mlme frame is next ++ else if ((RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME)) && ++ (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE)) ++ { ++ RTUSBBulkOutMLMEPacket(pAd, pAd->MgmtRing.TxDmaIdx); ++ } ++ ++ // 6. Data frame normal is next ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 0, pAd->NextBulkOutIndex[0]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_2)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 1, pAd->NextBulkOutIndex[1]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_3)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 2, pAd->NextBulkOutIndex[2]); ++ } ++ } ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_4)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ RTUSBBulkOutDataPacket(pAd, 3, pAd->NextBulkOutIndex[3]); ++ } ++ } ++ //PS packets use HCCA queue when dequeue from PS unicast queue (WiFi WPA2 MA9_DT1 for Marvell B STA) ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NORMAL_5)) ++ { ++ if (((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) || ++ (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ )) ++ { ++ } ++ } ++ ++ // 7. Null frame is the last ++ else if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_NULL)) ++ { ++ if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ RTUSBBulkOutNullFrame(pAd); ++ } ++ } ++ ++ // 8. No data avaliable ++ else ++ { ++ ++ } ++ } ++#ifdef RALINK_ATE ++ /* If the mode is in ATE mode. */ ++ else if((ATE_ON(pAd)) && ++ !RTMP_TEST_FLAG(pAd ,fRTMP_ADAPTER_NEED_STOP_TX))// PETER : watch out ! ++ { ++ if (RTUSB_TEST_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE)) ++ { ++ ATE_RTUSBBulkOutDataPacket(pAd, 0); ++ } ++ } ++#endif // RALINK_ATE // ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Call from Reset action after BulkOut failed. ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCleanUpDataBulkOutQueue( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR Idx; ++ PHT_TX_CONTEXT pTxContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpDataBulkOutQueue\n")); ++ ++ for (Idx = 0; Idx < 4; Idx++) ++ { ++ pTxContext = &pAd->TxContext[Idx]; ++ ++ pTxContext->CurWritePosition = pTxContext->NextBulkOutPosition; ++ pTxContext->LastOne = FALSE; ++ NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]); ++ pAd->BulkOutPending[Idx] = FALSE; ++ NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpDataBulkOutQueue\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCleanUpMLMEBulkOutQueue( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("--->CleanUpMLMEBulkOutQueue\n")); ++ DBGPRINT(RT_DEBUG_TRACE, ("<---CleanUpMLMEBulkOutQueue\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCancelPendingIRPs( ++ IN PRTMP_ADAPTER pAd) ++{ ++ RTUSBCancelPendingBulkInIRP(pAd); ++ RTUSBCancelPendingBulkOutIRP(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ UINT i; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->RTUSBCancelPendingBulkInIRP\n")); ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ pRxContext = &(pAd->RxContext[i]); ++ if(pRxContext->IRPPending == TRUE) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ pRxContext->IRPPending = FALSE; ++ pRxContext->InUse = FALSE; ++ //NdisInterlockedDecrement(&pAd->PendingRx); ++ //pAd->PendingRx--; ++ } ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("<---RTUSBCancelPendingBulkInIRP\n")); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBCancelPendingBulkOutIRP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PHT_TX_CONTEXT pHTTXContext; ++ PTX_CONTEXT pMLMEContext; ++ PTX_CONTEXT pBeaconContext; ++ PTX_CONTEXT pNullContext; ++ PTX_CONTEXT pPsPollContext; ++ PTX_CONTEXT pRTSContext; ++ UINT i, Idx; ++// unsigned int IrqFlags; ++// NDIS_SPIN_LOCK *pLock; ++// BOOLEAN *pPending; ++ ++ ++// pLock = &pAd->BulkOutLock[MGMTPIPEIDX]; ++// pPending = &pAd->BulkOutPending[MGMTPIPEIDX]; ++ ++ for (Idx = 0; Idx < 4; Idx++) ++ { ++ pHTTXContext = &(pAd->TxContext[Idx]); ++ ++ if (pHTTXContext->IRPPending == TRUE) ++ { ++ ++ // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself ++ // remove it from the HeadPendingSendList and NULL out HeadPendingSendList ++ // when the last IRP on the list has been cancelled; that's how we exit this loop ++ // ++ ++ RTUSB_UNLINK_URB(pHTTXContext->pUrb); ++ ++ // Sleep 200 microseconds to give cancellation time to work ++ RTMPusecDelay(200); ++ } ++ ++#ifdef RALINK_ATE ++ pHTTXContext->bCopySavePad = 0; ++ pHTTXContext->CurWritePosition = 0; ++ pHTTXContext->CurWriteRealPos = 0; ++ pHTTXContext->bCurWriting = FALSE; ++ pHTTXContext->NextBulkOutPosition = 0; ++ pHTTXContext->ENextBulkOutPosition = 0; ++#endif // RALINK_ATE // ++ pAd->BulkOutPending[Idx] = FALSE; ++ } ++ ++ //RTMP_IRQ_LOCK(pLock, IrqFlags); ++ for (i = 0; i < MGMT_RING_SIZE; i++) ++ { ++ pMLMEContext = (PTX_CONTEXT)pAd->MgmtRing.Cell[i].AllocVa; ++ if(pMLMEContext && (pMLMEContext->IRPPending == TRUE)) ++ { ++ ++ // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself ++ // remove it from the HeadPendingSendList and NULL out HeadPendingSendList ++ // when the last IRP on the list has been cancelled; that's how we exit this loop ++ // ++ ++ RTUSB_UNLINK_URB(pMLMEContext->pUrb); ++ pMLMEContext->IRPPending = FALSE; ++ ++ // Sleep 200 microsecs to give cancellation time to work ++ RTMPusecDelay(200); ++ } ++ } ++ pAd->BulkOutPending[MGMTPIPEIDX] = FALSE; ++ //RTMP_IRQ_UNLOCK(pLock, IrqFlags); ++ ++ ++ for (i = 0; i < BEACON_RING_SIZE; i++) ++ { ++ pBeaconContext = &(pAd->BeaconContext[i]); ++ ++ if(pBeaconContext->IRPPending == TRUE) ++ { ++ ++ // Get the USB_CONTEXT and cancel it's IRP; the completion routine will itself ++ // remove it from the HeadPendingSendList and NULL out HeadPendingSendList ++ // when the last IRP on the list has been cancelled; that's how we exit this loop ++ // ++ ++ RTUSB_UNLINK_URB(pBeaconContext->pUrb); ++ ++ // Sleep 200 microsecs to give cancellation time to work ++ RTMPusecDelay(200); ++ } ++ } ++ ++ pNullContext = &(pAd->NullContext); ++ if (pNullContext->IRPPending == TRUE) ++ RTUSB_UNLINK_URB(pNullContext->pUrb); ++ ++ pRTSContext = &(pAd->RTSContext); ++ if (pRTSContext->IRPPending == TRUE) ++ RTUSB_UNLINK_URB(pRTSContext->pUrb); ++ ++ pPsPollContext = &(pAd->PsPollContext); ++ if (pPsPollContext->IRPPending == TRUE) ++ RTUSB_UNLINK_URB(pPsPollContext->pUrb); ++ ++ for (Idx = 0; Idx < 4; Idx++) ++ { ++ NdisAcquireSpinLock(&pAd->BulkOutLock[Idx]); ++ pAd->BulkOutPending[Idx] = FALSE; ++ NdisReleaseSpinLock(&pAd->BulkOutLock[Idx]); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/rtusb_data.c +@@ -0,0 +1,218 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtusb_data.c ++ ++ Abstract: ++ Ralink USB driver Tx/Rx functions. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan 03-25-2006 created ++ ++*/ ++#include "../rt_config.h" ++ ++extern UCHAR Phy11BGNextRateUpward[]; // defined in mlme.c ++extern UCHAR EpToQueue[]; ++ ++ ++VOID REPORT_AMSDU_FRAMES_TO_LLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ PNDIS_PACKET pPacket; ++ UINT nMSDU; ++ struct sk_buff *pSkb; ++ ++ nMSDU = 0; ++ /* allocate a rx packet */ ++ pSkb = dev_alloc_skb(RX_BUFFER_AGGRESIZE); ++ pPacket = (PNDIS_PACKET)OSPKT_TO_RTPKT(pSkb); ++ if (pSkb) ++ { ++ ++ /* convert 802.11 to 802.3 packet */ ++ pSkb->dev = get_netdev_from_bssid(pAd, BSS0); ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++ deaggregate_AMSDU_announce(pAd, pPacket, pData, DataSize); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("Can't allocate skb\n")); ++ } ++} ++ ++NDIS_STATUS RTUSBFreeDescriptorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UINT32 NumberRequired) ++{ ++// UCHAR FreeNumber = 0; ++// UINT Index; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ ++ ++ pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->CurWritePosition < pHTTXContext->NextBulkOutPosition) && ((pHTTXContext->CurWritePosition + NumberRequired + LOCAL_TXBUF_SIZE) > pHTTXContext->NextBulkOutPosition)) ++ { ++ ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ else if ((pHTTXContext->CurWritePosition == 8) && (pHTTXContext->NextBulkOutPosition < (NumberRequired + LOCAL_TXBUF_SIZE))) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ else if (pHTTXContext->bCurWriting == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RTUSBFreeD c3 --> QueIdx=%d, CWPos=%ld, NBOutPos=%ld!\n", BulkOutPipeId, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition)); ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << BulkOutPipeId)); ++ } ++ else ++ { ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ ++ return (Status); ++} ++ ++ ++NDIS_STATUS RTUSBFreeDescriptorRelease( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR BulkOutPipeId) ++{ ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ ++ pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ pHTTXContext->bCurWriting = FALSE; ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++ ++BOOLEAN RTUSBNeedQueueBackForAgg( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR BulkOutPipeId) ++{ ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ BOOLEAN needQueBack = FALSE; ++ ++ pHTTXContext = &pAd->TxContext[BulkOutPipeId]; ++ ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ if ((pHTTXContext->IRPPending == TRUE) /*&& (pAd->TxSwQueue[BulkOutPipeId].Number == 0) */) ++ { ++ if ((pHTTXContext->CurWritePosition < pHTTXContext->ENextBulkOutPosition) && ++ (((pHTTXContext->ENextBulkOutPosition+MAX_AGGREGATION_SIZE) < MAX_TXBULK_LIMIT) || (pHTTXContext->CurWritePosition > MAX_AGGREGATION_SIZE))) ++ { ++ needQueBack = TRUE; ++ } ++ else if ((pHTTXContext->CurWritePosition > pHTTXContext->ENextBulkOutPosition) && ++ ((pHTTXContext->ENextBulkOutPosition + MAX_AGGREGATION_SIZE) < pHTTXContext->CurWritePosition)) ++ { ++ needQueBack = TRUE; ++ } ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[BulkOutPipeId], IrqFlags); ++ ++ return needQueBack; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBRejectPendingPackets( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR Index; ++ PQUEUE_ENTRY pEntry; ++ PNDIS_PACKET pPacket; ++ PQUEUE_HEADER pQueue; ++ ++ ++ for (Index = 0; Index < 4; Index++) ++ { ++ NdisAcquireSpinLock(&pAd->TxSwQueueLock[Index]); ++ while (pAd->TxSwQueue[Index].Head != NULL) ++ { ++ pQueue = (PQUEUE_HEADER) &(pAd->TxSwQueue[Index]); ++ pEntry = RemoveHeadQueue(pQueue); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pEntry); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ NdisReleaseSpinLock(&pAd->TxSwQueueLock[Index]); ++ ++ } ++ ++} ++ ++VOID RTMPWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst) ++{ ++ pTxInfo->USBDMATxPktLen = USBDMApktLen; ++ pTxInfo->QSEL = QueueSel; ++ if (QueueSel != FIFO_EDCA) ++ DBGPRINT(RT_DEBUG_TRACE, ("====> QueueSel != FIFO_EDCA<============\n")); ++ pTxInfo->USBDMANextVLD = FALSE; //NextValid; // Need to check with Jan about this. ++ pTxInfo->USBDMATxburst = TxBurst; ++ pTxInfo->WIV = bWiv; ++ pTxInfo->SwUseLastRound = 0; ++ pTxInfo->rsv = 0; ++ pTxInfo->rsv2 = 0; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/rtusb_io.c +@@ -0,0 +1,1908 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtusb_io.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 06-25-2004 created ++*/ ++ ++#include "../rt_config.h" ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: NIC initialization complete ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++NTSTATUS RTUSBFirmwareRun( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x01, ++ 0x8, ++ 0, ++ NULL, ++ 0); ++ ++ return Status; ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write Firmware to NIC. ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBFirmwareWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFwImage, ++ IN ULONG FwLen) ++{ ++ UINT32 MacReg; ++ NTSTATUS Status; ++// ULONG i; ++ USHORT writeLen; ++ ++ Status = RTUSBReadMACRegister(pAd, MAC_CSR0, &MacReg); ++ ++ ++ writeLen = FwLen; ++ RTUSBMultiWrite(pAd, FIRMWARE_IMAGE_BASE, pFwImage, writeLen); ++ ++ Status = RTUSBWriteMACRegister(pAd, 0x7014, 0xffffffff); ++ Status = RTUSBWriteMACRegister(pAd, 0x701c, 0xffffffff); ++ Status = RTUSBFirmwareRun(pAd); ++ ++ RTMPusecDelay(10000); ++ RTUSBWriteMACRegister(pAd,H2M_MAILBOX_CSR,0); ++ AsicSendCommandToMcu(pAd, 0x72, 0x00, 0x00, 0x00);//reset rf by MCU supported by new firmware ++ ++ return Status; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Get current firmware operation mode (Return Value) ++ ++ Arguments: ++ ++ Return Value: ++ 0 or 1 = Downloaded by host driver ++ others = Driver doesn't download firmware ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBFirmwareOpmode( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUINT32 pValue) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x1, ++ 0x11, ++ 0, ++ pValue, ++ 4); ++ return Status; ++} ++NTSTATUS RTUSBVenderReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status; ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("-->RTUSBVenderReset\n")); ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x01, ++ 0x1, ++ 0, ++ NULL, ++ 0); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("<--RTUSBVenderReset\n")); ++ return Status; ++} ++/* ++ ======================================================================== ++ ++ Routine Description: Read various length data from RT2573 ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBMultiRead( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x7, ++ 0, ++ Offset, ++ pData, ++ length); ++ ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write various length data to RT2573 ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBMultiWrite_OneByte( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData) ++{ ++ NTSTATUS Status; ++ ++ // TODO: In 2870, use this funciton carefully cause it's not stable. ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x6, ++ 0, ++ Offset, ++ pData, ++ 1); ++ ++ return Status; ++} ++ ++NTSTATUS RTUSBMultiWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length) ++{ ++ NTSTATUS Status; ++ ++ ++ USHORT index = 0,Value; ++ PUCHAR pSrc = pData; ++ USHORT resude = 0; ++ ++ resude = length % 2; ++ length += resude; ++ do ++ { ++ Value =(USHORT)( *pSrc | (*(pSrc + 1) << 8)); ++ Status = RTUSBSingleWrite(pAd,Offset + index,Value); ++ index +=2; ++ length -= 2; ++ pSrc = pSrc + 2; ++ }while(length > 0); ++ ++ return Status; ++} ++ ++ ++NTSTATUS RTUSBSingleWrite( ++ IN RTMP_ADAPTER *pAd, ++ IN USHORT Offset, ++ IN USHORT Value) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x2, ++ Value, ++ Offset, ++ NULL, ++ 0); ++ ++ return Status; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Read 32-bit MAC register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUINT32 pValue) ++{ ++ NTSTATUS Status; ++ UINT32 localVal; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x7, ++ 0, ++ Offset, ++ &localVal, ++ 4); ++ ++ *pValue = le2cpu32(localVal); ++ ++ ++ if (Status < 0) ++ *pValue = 0xffffffff; ++ ++ return Status; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: Write 32-bit MAC register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN UINT32 Value) ++{ ++ NTSTATUS Status; ++ UINT32 localVal; ++ ++ localVal = Value; ++ ++ Status = RTUSBSingleWrite(pAd, Offset, (USHORT)(localVal & 0xffff)); ++ Status = RTUSBSingleWrite(pAd, Offset + 2, (USHORT)((localVal & 0xffff0000) >> 16)); ++ ++ return Status; ++} ++ ++ ++ ++#if 1 ++/* ++ ======================================================================== ++ ++ Routine Description: Read 8-bit BBP register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN PUCHAR pValue) ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ UINT i = 0; ++ NTSTATUS status; ++ ++ // Verify the busy condition ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); ++ if(status >= 0) ++ { ++ if (!(BbpCsr.field.Busy == BUSY)) ++ break; ++ } ++ printk("RTUSBReadBBPRegister(BBP_CSR_CFG_1):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ // ++ // Read failed then Return Default value. ++ // ++ *pValue = pAd->BbpWriteLatch[Id]; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ // Prepare for write material ++ BbpCsr.word = 0; ++ BbpCsr.field.fRead = 1; ++ BbpCsr.field.Busy = 1; ++ BbpCsr.field.RegNum = Id; ++ RTUSBWriteMACRegister(pAd, BBP_CSR_CFG, BbpCsr.word); ++ ++ i = 0; ++ // Verify the busy condition ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); ++ if (status >= 0) ++ { ++ if (!(BbpCsr.field.Busy == BUSY)) ++ { ++ *pValue = (UCHAR)BbpCsr.field.Value; ++ break; ++ } ++ } ++ printk("RTUSBReadBBPRegister(BBP_CSR_CFG_2):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ // ++ // Read failed then Return Default value. ++ // ++ *pValue = pAd->BbpWriteLatch[Id]; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ return STATUS_SUCCESS; ++} ++#else ++/* ++ ======================================================================== ++ ++ Routine Description: Read 8-bit BBP register via firmware ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN PUCHAR pValue) ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ int i, k; ++ for (i=0; iBbpWriteLatch[Id]; ++ return STATUS_UNSUCCESSFUL; ++ } ++ return STATUS_SUCCESS; ++} ++#endif ++ ++#if 1 ++/* ++ ======================================================================== ++ ++ Routine Description: Write 8-bit BBP register ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN UCHAR Value) ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ UINT i = 0; ++ NTSTATUS status; ++ // Verify the busy condition ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, BBP_CSR_CFG, &BbpCsr.word); ++ if (status >= 0) ++ { ++ if (!(BbpCsr.field.Busy == BUSY)) ++ break; ++ } ++ printk("RTUSBWriteBBPRegister(BBP_CSR_CFG):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ // Prepare for write material ++ BbpCsr.word = 0; ++ BbpCsr.field.fRead = 0; ++ BbpCsr.field.Value = Value; ++ BbpCsr.field.Busy = 1; ++ BbpCsr.field.RegNum = Id; ++ RTUSBWriteMACRegister(pAd, BBP_CSR_CFG, BbpCsr.word); ++ ++ pAd->BbpWriteLatch[Id] = Value; ++ ++ return STATUS_SUCCESS; ++} ++#else ++/* ++ ======================================================================== ++ ++ Routine Description: Write 8-bit BBP register via firmware ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++NTSTATUS RTUSBWriteBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN UCHAR Value) ++ ++{ ++ BBP_CSR_CFG_STRUC BbpCsr; ++ int BusyCnt; ++ for (BusyCnt=0; BusyCntBbpWriteLatch[Id] = Value; ++ break; ++ } ++ if (BusyCnt == MAX_BUSY_COUNT) ++ { ++ DBGPRINT_ERR(("BBP write R%d=0x%x fail\n", Id, BbpCsr.word)); ++ return STATUS_UNSUCCESSFUL; ++ } ++ return STATUS_SUCCESS; ++} ++#endif ++/* ++ ======================================================================== ++ ++ Routine Description: Write RF register through MAC ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 Value) ++{ ++ PHY_CSR4_STRUC PhyCsr4; ++ UINT i = 0; ++ NTSTATUS status; ++ ++ NdisZeroMemory(&PhyCsr4, sizeof(PHY_CSR4_STRUC)); ++ do ++ { ++ status = RTUSBReadMACRegister(pAd, RF_CSR_CFG0, &PhyCsr4.word); ++ if (status >= 0) ++ { ++ if (!(PhyCsr4.field.Busy)) ++ break; ++ } ++ printk("RTUSBWriteRFRegister(RF_CSR_CFG0):retry count=%d!\n", i); ++ i++; ++ } ++ while ((i < RETRY_LIMIT) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))); ++ ++ if ((i == RETRY_LIMIT) || (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Retry count exhausted or device removed!!!\n")); ++ return STATUS_UNSUCCESSFUL; ++ } ++ ++ RTUSBWriteMACRegister(pAd, RF_CSR_CFG0, Value); ++ ++ return STATUS_SUCCESS; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBReadEEPROM( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length) ++{ ++ NTSTATUS Status = STATUS_SUCCESS; ++ ++#ifdef RT30xx ++ if(pAd->bUseEfuse) ++ { ++ Status =eFuseRead(pAd, Offset, pData, length); ++ } ++ else ++#endif // RT30xx // ++ { ++ Status = RTUSB_VendorRequest( ++ pAd, ++ (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK), ++ DEVICE_VENDOR_REQUEST_IN, ++ 0x9, ++ 0, ++ Offset, ++ pData, ++ length); ++ } ++ ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWriteEEPROM( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length) ++{ ++ NTSTATUS Status = STATUS_SUCCESS; ++ ++#ifdef RT30xx ++ if(pAd->bUseEfuse) ++ { ++ Status = eFuseWrite(pAd, Offset, pData, length); ++ } ++ else ++#endif // RT30xx // ++ { ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x8, ++ 0, ++ Offset, ++ pData, ++ length); ++ } ++ ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBPutToSleep( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 value; ++ ++ // Timeout 0x40 x 50us ++ value = (SLEEPCID<<16)+(OWNERMCU<<24)+ (0x40<<8)+1; ++ RTUSBWriteMACRegister(pAd, 0x7010, value); ++ RTUSBWriteMACRegister(pAd, 0x404, 0x30); ++ //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("Sleep Mailbox testvalue %x\n", value)); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSBWakeUp( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status; ++ ++ Status = RTUSB_VendorRequest( ++ pAd, ++ USBD_TRANSFER_DIRECTION_OUT, ++ DEVICE_VENDOR_REQUEST_OUT, ++ 0x01, ++ 0x09, ++ 0, ++ NULL, ++ 0); ++ ++ return Status; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBInitializeCmdQ( ++ IN PCmdQ cmdq) ++{ ++ cmdq->head = NULL; ++ cmdq->tail = NULL; ++ cmdq->size = 0; ++ cmdq->CmdQState = RT2870_THREAD_INITED; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTUSBEnqueueCmdFromNdis( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN BOOLEAN SetInformation, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength) ++{ ++ NDIS_STATUS status; ++ PCmdQElmt cmdqelmt = NULL; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ ++ if (pObj->RTUSBCmdThr_pid < 0) ++ return (NDIS_STATUS_RESOURCES); ++ ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt == NULL)) ++ return (NDIS_STATUS_RESOURCES); ++ ++ cmdqelmt->buffer = NULL; ++ if (pInformationBuffer != NULL) ++ { ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt->buffer, InformationBufferLength); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt->buffer == NULL)) ++ { ++ kfree(cmdqelmt); ++ return (NDIS_STATUS_RESOURCES); ++ } ++ else ++ { ++ NdisMoveMemory(cmdqelmt->buffer, pInformationBuffer, InformationBufferLength); ++ cmdqelmt->bufferlength = InformationBufferLength; ++ } ++ } ++ else ++ cmdqelmt->bufferlength = 0; ++ ++ cmdqelmt->command = Oid; ++ cmdqelmt->CmdFromNdis = TRUE; ++ if (SetInformation == TRUE) ++ cmdqelmt->SetOperation = TRUE; ++ else ++ cmdqelmt->SetOperation = FALSE; ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ if (pAd->CmdQ.CmdQState & RT2870_THREAD_CAN_DO_INSERT) ++ { ++ EnqueueCmd((&pAd->CmdQ), cmdqelmt); ++ status = NDIS_STATUS_SUCCESS; ++ } ++ else ++ { ++ status = NDIS_STATUS_FAILURE; ++ } ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ if (status == NDIS_STATUS_FAILURE) ++ { ++ if (cmdqelmt->buffer) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ RTUSBCMDUp(pAd); ++ ++ ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTUSBEnqueueInternalCmd( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength) ++{ ++ NDIS_STATUS status; ++ PCmdQElmt cmdqelmt = NULL; ++ ++ ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt, sizeof(CmdQElmt)); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt == NULL)) ++ return (NDIS_STATUS_RESOURCES); ++ NdisZeroMemory(cmdqelmt, sizeof(CmdQElmt)); ++ ++ if(InformationBufferLength > 0) ++ { ++ status = RTMPAllocateMemory((PVOID *)&cmdqelmt->buffer, InformationBufferLength); ++ if ((status != NDIS_STATUS_SUCCESS) || (cmdqelmt->buffer == NULL)) ++ { ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ return (NDIS_STATUS_RESOURCES); ++ } ++ else ++ { ++ NdisMoveMemory(cmdqelmt->buffer, pInformationBuffer, InformationBufferLength); ++ cmdqelmt->bufferlength = InformationBufferLength; ++ } ++ } ++ else ++ { ++ cmdqelmt->buffer = NULL; ++ cmdqelmt->bufferlength = 0; ++ } ++ ++ cmdqelmt->command = Oid; ++ cmdqelmt->CmdFromNdis = FALSE; ++ ++ if (cmdqelmt != NULL) ++ { ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ if (pAd->CmdQ.CmdQState & RT2870_THREAD_CAN_DO_INSERT) ++ { ++ EnqueueCmd((&pAd->CmdQ), cmdqelmt); ++ status = NDIS_STATUS_SUCCESS; ++ } ++ else ++ { ++ status = NDIS_STATUS_FAILURE; ++ } ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ if (status == NDIS_STATUS_FAILURE) ++ { ++ if (cmdqelmt->buffer) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ RTUSBCMDUp(pAd); ++ } ++ return(NDIS_STATUS_SUCCESS); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ IRQL = ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTUSBDequeueCmd( ++ IN PCmdQ cmdq, ++ OUT PCmdQElmt *pcmdqelmt) ++{ ++ *pcmdqelmt = cmdq->head; ++ ++ if (*pcmdqelmt != NULL) ++ { ++ cmdq->head = cmdq->head->next; ++ cmdq->size--; ++ if (cmdq->size == 0) ++ cmdq->tail = NULL; ++ } ++} ++ ++/* ++ ======================================================================== ++ usb_control_msg - Builds a control urb, sends it off and waits for completion ++ @dev: pointer to the usb device to send the message to ++ @pipe: endpoint "pipe" to send the message to ++ @request: USB message request value ++ @requesttype: USB message request type value ++ @value: USB message value ++ @index: USB message index value ++ @data: pointer to the data to send ++ @size: length in bytes of the data to send ++ @timeout: time in jiffies to wait for the message to complete before ++ timing out (if 0 the wait is forever) ++ Context: !in_interrupt () ++ ++ This function sends a simple control message to a specified endpoint ++ and waits for the message to complete, or timeout. ++ If successful, it returns the number of bytes transferred, otherwise a negative error number. ++ ++ Don't use this function from within an interrupt context, like a ++ bottom half handler. If you need an asynchronous message, or need to send ++ a message from within interrupt context, use usb_submit_urb() ++ If a thread in your driver uses this call, make sure your disconnect() ++ method can wait for it to complete. Since you don't have a handle on ++ the URB used, you can't cancel the request. ++ ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSB_VendorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TransferFlags, ++ IN UCHAR RequestType, ++ IN UCHAR Request, ++ IN USHORT Value, ++ IN USHORT Index, ++ IN PVOID TransferBuffer, ++ IN UINT32 TransferBufferLength) ++{ ++ int ret; ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("device disconnected\n")); ++ return -1; ++ } ++ else if (in_interrupt()) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("in_interrupt, RTUSB_VendorRequest Request%02x Value%04x Offset%04x\n",Request,Value,Index)); ++ ++ return -1; ++ } ++ else ++ { ++#define MAX_RETRY_COUNT 10 ++ ++ int retryCount = 0; ++ void *tmpBuf = TransferBuffer; ++ ++ // Acquire Control token ++#ifdef INF_AMAZON_SE ++ ret = down_interruptible(&(pAd->UsbVendorReq_semaphore)); ++ if (pAd->UsbVendorReqBuf) ++ { ++ ASSERT(TransferBufferLength UsbVendorReqBuf; ++ NdisZeroMemory(pAd->UsbVendorReqBuf, TransferBufferLength); ++ ++ if (RequestType == DEVICE_VENDOR_REQUEST_OUT) ++ NdisMoveMemory(tmpBuf, TransferBuffer, TransferBufferLength); ++ } ++#endif // INF_AMAZON_SE // ++ do { ++ if( RequestType == DEVICE_VENDOR_REQUEST_OUT) ++ ret=usb_control_msg(pObj->pUsb_Dev, usb_sndctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); ++ else if(RequestType == DEVICE_VENDOR_REQUEST_IN) ++ ret=usb_control_msg(pObj->pUsb_Dev, usb_rcvctrlpipe( pObj->pUsb_Dev, 0 ), Request, RequestType, Value,Index, tmpBuf, TransferBufferLength, CONTROL_TIMEOUT_JIFFIES); ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("vendor request direction is failed\n")); ++ ret = -1; ++ } ++ ++ retryCount++; ++ if (ret < 0) { ++ printk("#\n"); ++ RTMPusecDelay(5000); ++ } ++ } while((ret < 0) && (retryCount < MAX_RETRY_COUNT)); ++ ++#ifdef INF_AMAZON_SE ++ if ((pAd->UsbVendorReqBuf) && (RequestType == DEVICE_VENDOR_REQUEST_IN)) ++ NdisMoveMemory(TransferBuffer, tmpBuf, TransferBufferLength); ++ up(&(pAd->UsbVendorReq_semaphore)); ++#endif // INF_AMAZON_SE // ++ ++ if (ret < 0) { ++// DBGPRINT(RT_DEBUG_ERROR, ("USBVendorRequest failed ret=%d \n",ret)); ++ DBGPRINT(RT_DEBUG_ERROR, ("RTUSB_VendorRequest failed(%d),TxFlags=0x%x, ReqType=%s, Req=0x%x, Index=0x%x\n", ++ ret, TransferFlags, (RequestType == DEVICE_VENDOR_REQUEST_OUT ? "OUT" : "IN"), Request, Index)); ++ if (Request == 0x2) ++ DBGPRINT(RT_DEBUG_ERROR, ("\tRequest Value=0x%04x!\n", Value)); ++ ++ if ((TransferBuffer!= NULL) && (TransferBufferLength > 0)) ++ hex_dump("Failed TransferBuffer value", TransferBuffer, TransferBufferLength); ++ } ++ } ++ return ret; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Creates an IRP to submite an IOCTL_INTERNAL_USB_RESET_PORT ++ synchronously. Callers of this function must be running at ++ PASSIVE LEVEL. ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NTSTATUS RTUSB_ResetDevice( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NTSTATUS Status = TRUE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("--->USB_ResetDevice\n")); ++ //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); ++ return Status; ++} ++ ++VOID CMDHandler( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PCmdQElmt cmdqelmt; ++ PUCHAR pData; ++ NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; ++// ULONG Now = 0; ++ NTSTATUS ntStatus; ++// unsigned long IrqFlags; ++ ++ while (pAd->CmdQ.size > 0) ++ { ++ NdisStatus = NDIS_STATUS_SUCCESS; ++ ++ NdisAcquireSpinLock(&pAd->CmdQLock); ++ RTUSBDequeueCmd(&pAd->CmdQ, &cmdqelmt); ++ NdisReleaseSpinLock(&pAd->CmdQLock); ++ ++ if (cmdqelmt == NULL) ++ break; ++ ++ pData = cmdqelmt->buffer; ++ ++ if(!(RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) ++ { ++ switch (cmdqelmt->command) ++ { ++ case CMDTHREAD_CHECK_GPIO: ++ { ++#ifdef CONFIG_STA_SUPPORT ++ UINT32 data; ++#endif // CONFIG_STA_SUPPORT // ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ ++ ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Read GPIO pin2 as Hardware controlled radio state ++ ++ RTUSBReadMACRegister( pAd, GPIO_CTRL_CFG, &data); ++ ++ if (data & 0x04) ++ { ++ pAd->StaCfg.bHwRadio = TRUE; ++ } ++ else ++ { ++ pAd->StaCfg.bHwRadio = FALSE; ++ } ++ ++ if(pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if(pAd->StaCfg.bRadio == TRUE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("!!! Radio On !!!\n")); ++ ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("!!! Radio Off !!!\n")); ++ ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = HW_RADIO_OFF; ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ break; ++ ++#ifdef CONFIG_STA_SUPPORT ++ case CMDTHREAD_QKERIODIC_EXECUT: ++ { ++ StaQuickResponeForRateUpExec(NULL, pAd, NULL, NULL); ++ } ++ break; ++#endif // CONFIG_STA_SUPPORT // ++ ++ case CMDTHREAD_RESET_BULK_OUT: ++ { ++ UINT32 MACValue; ++ UCHAR Index; ++ int ret=0; ++ PHT_TX_CONTEXT pHTTXContext; ++// RTMP_TX_RING *pTxRing; ++ unsigned long IrqFlags; ++#ifdef RALINK_ATE ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++#endif // RALINK_ATE // ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT(ResetPipeid=0x%0x)===>\n", pAd->bulkResetPipeid)); ++ // All transfers must be aborted or cancelled before attempting to reset the pipe. ++ //RTUSBCancelPendingBulkOutIRP(pAd); ++ // Wait 10ms to let previous packet that are already in HW FIFO to clear. by MAXLEE 12-25-2007 ++ Index = 0; ++ do ++ { ++ RTUSBReadMACRegister(pAd, TXRXQ_PCNT, &MACValue); ++ if ((MACValue & 0xf00000/*0x800000*/) == 0) ++ break; ++ Index++; ++ RTMPusecDelay(10000); ++ }while(Index < 100); ++ MACValue = 0; ++ RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); ++ // To prevent Read Register error, we 2nd check the validity. ++ if ((MACValue & 0xc00000) == 0) ++ RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); ++ // To prevent Read Register error, we 3rd check the validity. ++ if ((MACValue & 0xc00000) == 0) ++ RTUSBReadMACRegister(pAd, USB_DMA_CFG, &MACValue); ++ MACValue |= 0x80000; ++ RTUSBWriteMACRegister(pAd, USB_DMA_CFG, MACValue); ++ ++ // Wait 1ms to prevent next URB to bulkout before HW reset. by MAXLEE 12-25-2007 ++ RTMPusecDelay(1000); ++ ++ MACValue &= (~0x80000); ++ RTUSBWriteMACRegister(pAd, USB_DMA_CFG, MACValue); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tSet 0x2a0 bit19. Clear USB DMA TX path\n")); ++ ++ // Wait 5ms to prevent next URB to bulkout before HW reset. by MAXLEE 12-25-2007 ++ //RTMPusecDelay(5000); ++ ++ if ((pAd->bulkResetPipeid & BULKOUT_MGMT_RESET_FLAG) == BULKOUT_MGMT_RESET_FLAG) ++ { ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ if (pAd->MgmtRing.TxSwFreeIdx < MGMT_RING_SIZE /* pMLMEContext->bWaitingBulkOut == TRUE */) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_MLME); ++ } ++ RTUSBKickBulkOut(pAd); ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tTX MGMT RECOVER Done!\n")); ++ } ++ else ++ { ++ pHTTXContext = &(pAd->TxContext[pAd->bulkResetPipeid]); ++ //NdisAcquireSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); ++ RTMP_INT_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ if ( pAd->BulkOutPending[pAd->bulkResetPipeid] == FALSE) ++ { ++ pAd->BulkOutPending[pAd->bulkResetPipeid] = TRUE; ++ pHTTXContext->IRPPending = TRUE; ++ pAd->watchDogTxPendingCnt[pAd->bulkResetPipeid] = 1; ++ ++ // no matter what, clean the flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ ++ //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); ++ RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++/*-----------------------------------------------------------------------------------------------*/ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ pNullContext->IRPPending = TRUE; ++ // ++ // If driver is still in ATE TXFRAME mode, ++ // keep on transmitting ATE frames. ++ // ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("pAd->ate.Mode == %d\npAd->ContinBulkOut == %d\npAd->BulkOutRemained == %d\n", pAd->ate.Mode, pAd->ContinBulkOut, atomic_read(&pAd->BulkOutRemained))); ++ if((pAd->ate.Mode == ATE_TXFRAME) && ((pAd->ContinBulkOut == TRUE) || (atomic_read(&pAd->BulkOutRemained) > 0))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("After CMDTHREAD_RESET_BULK_OUT, continue to bulk out frames !\n")); ++ ++ // Init Tx context descriptor ++ RTUSBInitTxDesc(pAd, pNullContext, 0/* pAd->bulkResetPipeid */, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); ++ ++ if((ret = RTUSB_SUBMIT_URB(pNullContext->pUrb))!=0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); ++ } ++ ++ pAd->BulkOutReq++; ++ } ++ } ++ else ++#endif // RALINK_ATE // ++/*-----------------------------------------------------------------------------------------------*/ ++ { ++ RTUSBInitHTTxDesc(pAd, pHTTXContext, pAd->bulkResetPipeid, pHTTXContext->BulkOutSize, (usb_complete_t)RTUSBBulkOutDataPacketComplete); ++ ++ if((ret = RTUSB_SUBMIT_URB(pHTTXContext->pUrb))!=0) ++ { ++ RTMP_INT_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ pAd->BulkOutPending[pAd->bulkResetPipeid] = FALSE; ++ pHTTXContext->IRPPending = FALSE; ++ pAd->watchDogTxPendingCnt[pAd->bulkResetPipeid] = 0; ++ RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("CmdThread : CMDTHREAD_RESET_BULK_OUT: Submit Tx URB failed %d\n", ret)); ++ } ++ else ++ { ++ RTMP_IRQ_LOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("\tCMDTHREAD_RESET_BULK_OUT: TxContext[%d]:CWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d, pending=%d!\n", ++ pAd->bulkResetPipeid, pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, ++ pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad, pAd->BulkOutPending[pAd->bulkResetPipeid])); ++ DBGPRINT_RAW(RT_DEBUG_TRACE,("\t\tBulkOut Req=0x%lx, Complete=0x%lx, Other=0x%lx\n", ++ pAd->BulkOutReq, pAd->BulkOutComplete, pAd->BulkOutCompleteOther)); ++ RTMP_IRQ_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("\tCMDTHREAD_RESET_BULK_OUT: Submit Tx DATA URB for failed BulkReq(0x%lx) Done, status=%d!\n", pAd->bulkResetReq[pAd->bulkResetPipeid], pHTTXContext->pUrb->status)); ++ ++ } ++ } ++ } ++ else ++ { ++ //NdisReleaseSpinLock(&pAd->BulkOutLock[pAd->bulkResetPipeid]); ++ //RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("CmdThread : TX DATA RECOVER FAIL for BulkReq(0x%lx) because BulkOutPending[%d] is TRUE!\n", pAd->bulkResetReq[pAd->bulkResetPipeid], pAd->bulkResetPipeid)); ++ if (pAd->bulkResetPipeid == 0) ++ { ++ UCHAR pendingContext = 0; ++ PHT_TX_CONTEXT pHTTXContext = (PHT_TX_CONTEXT)(&pAd->TxContext[pAd->bulkResetPipeid ]); ++ PTX_CONTEXT pMLMEContext = (PTX_CONTEXT)(pAd->MgmtRing.Cell[pAd->MgmtRing.TxDmaIdx].AllocVa); ++ PTX_CONTEXT pNULLContext = (PTX_CONTEXT)(&pAd->PsPollContext); ++ PTX_CONTEXT pPsPollContext = (PTX_CONTEXT)(&pAd->NullContext); ++ ++ if (pHTTXContext->IRPPending) ++ pendingContext |= 1; ++ else if (pMLMEContext->IRPPending) ++ pendingContext |= 2; ++ else if (pNULLContext->IRPPending) ++ pendingContext |= 4; ++ else if (pPsPollContext->IRPPending) ++ pendingContext |= 8; ++ else ++ pendingContext = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("\tTX Occupied by %d!\n", pendingContext)); ++ } ++ ++ // no matter what, clean the flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ ++ RTMP_INT_UNLOCK(&pAd->BulkOutLock[pAd->bulkResetPipeid], IrqFlags); ++ ++ RTUSB_SET_BULK_FLAG(pAd, (fRTUSB_BULK_OUT_DATA_NORMAL << pAd->bulkResetPipeid)); ++ } ++ ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ //RTUSBKickBulkOut(pAd); ++ } ++ ++ } ++ /* ++ // Don't cancel BULKIN. ++ while ((atomic_read(&pAd->PendingRx) > 0) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ if (atomic_read(&pAd->PendingRx) > 0) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkIn IRP Pending!!cancel it!\n")); ++ RTUSBCancelPendingBulkInIRP(pAd); ++ } ++ RTMPusecDelay(100000); ++ } ++ ++ if ((atomic_read(&pAd->PendingRx) == 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) ++ { ++ UCHAR i; ++ RTUSBRxPacket(pAd); ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = 0; // Rx Bulk pointer ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ pRxContext->pAd = pAd; ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ pRxContext->ReorderInUse = FALSE; ++ ++ } ++ RTUSBBulkReceive(pAd); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("RTUSBBulkReceive\n")); ++ }*/ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_OUT<===\n")); ++ break; ++ ++ case CMDTHREAD_RESET_BULK_IN: ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_IN === >\n")); ++ ++ // All transfers must be aborted or cancelled before attempting to reset the pipe. ++ { ++ UINT32 MACValue; ++/*-----------------------------------------------------------------------------------------------*/ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("ATE : BulkIn IRP Pending!!!\n")); ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++ RTMPusecDelay(100000); ++ pAd->PendingRx = 0; ++ } ++ } ++ else ++#endif // RALINK_ATE // ++/*-----------------------------------------------------------------------------------------------*/ ++ { ++ //while ((atomic_read(&pAd->PendingRx) > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ if((pAd->PendingRx > 0) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("BulkIn IRP Pending!!!\n")); ++ RTUSBCancelPendingBulkInIRP(pAd); ++ RTMPusecDelay(100000); ++ pAd->PendingRx = 0; ++ } ++ } ++ ++ // Wait 10ms before reading register. ++ RTMPusecDelay(10000); ++ ntStatus = RTUSBReadMACRegister(pAd, MAC_CSR0, &MACValue); ++ ++ if ((NT_SUCCESS(ntStatus) == TRUE) && ++ (!(RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))))) ++ { ++ UCHAR i; ++ ++ if (RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ break; ++ pAd->NextRxBulkInPosition = pAd->RxContext[pAd->NextRxBulkInIndex].BulkInOffset; ++ DBGPRINT(RT_DEBUG_TRACE, ("BULK_IN_RESET: NBIIdx=0x%x,NBIRIdx=0x%x, BIRPos=0x%lx. BIReq=x%lx, BIComplete=0x%lx, BICFail0x%lx\n", ++ pAd->NextRxBulkInIndex, pAd->NextRxBulkInReadIndex, pAd->NextRxBulkInPosition, pAd->BulkInReq, pAd->BulkInComplete, pAd->BulkInCompleteFail)); ++ for (i = 0; i < RX_RING_SIZE; i++) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("\tRxContext[%d]: IRPPending=%d, InUse=%d, Readable=%d!\n" ++ , i, pAd->RxContext[i].IRPPending, pAd->RxContext[i].InUse, pAd->RxContext[i].Readable)); ++ } ++ /* ++ ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("==========================================\n")); ++ ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = 0; // Rx Bulk pointer ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ pRxContext->pAd = pAd; ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ pRxContext->ReorderInUse = FALSE; ++ ++ }*/ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BULKIN_RESET); ++ for (i = 0; i < pAd->CommonCfg.NumOfBulkInIRP; i++) ++ { ++ //RTUSBBulkReceive(pAd); ++ PRX_CONTEXT pRxContext; ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext = &(pAd->RxContext[pAd->NextRxBulkInIndex]); ++ if ((pAd->PendingRx > 0) || (pRxContext->Readable == TRUE) || (pRxContext->InUse == TRUE)) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ break; ++ } ++ pRxContext->InUse = TRUE; ++ pRxContext->IRPPending = TRUE; ++ pAd->PendingRx++; ++ pAd->BulkInReq++; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++ // Init Rx context descriptor ++ RTUSBInitRxDesc(pAd, pRxContext); ++ pUrb = pRxContext->pUrb; ++ if ((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { // fail ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pAd->PendingRx--; ++ pAd->BulkInReq--; ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ DBGPRINT(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB failed(%d), status=%d\n", ret, pUrb->status)); ++ } ++ else ++ { // success ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CMDTHREAD_RESET_BULK_IN: Submit Rx URB Done, status=%d!\n", pUrb->status)); ++ ASSERT((pRxContext->InUse == pRxContext->IRPPending)); ++ } ++ } ++ ++ } ++ else ++ { ++ // Card must be removed ++ if (NT_SUCCESS(ntStatus) != TRUE) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST); ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Read Register Failed!Card must be removed!!\n\n")); ++ } ++ else ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR, ("CMDTHREAD_RESET_BULK_IN: Cannot do bulk in because flags(0x%lx) on !\n", pAd->Flags)); ++ } ++ } ++ } ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_RESET_BULK_IN <===\n")); ++ break; ++ ++ case CMDTHREAD_SET_ASIC_WCID: ++ { ++ RT_SET_ASIC_WCID SetAsicWcid; ++ USHORT offset; ++ UINT32 MACValue, MACRValue = 0; ++ SetAsicWcid = *((PRT_SET_ASIC_WCID)(pData)); ++ ++ if (SetAsicWcid.WCID >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ offset = MAC_WCID_BASE + ((UCHAR)SetAsicWcid.WCID)*HW_WCID_ENTRY_SIZE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("CmdThread : CMDTHREAD_SET_ASIC_WCID : WCID = %ld, SetTid = %lx, DeleteTid = %lx.\n", SetAsicWcid.WCID, SetAsicWcid.SetTid, SetAsicWcid.DeleteTid)); ++ MACValue = (pAd->MacTab.Content[SetAsicWcid.WCID].Addr[3]<<24)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[2]<<16)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[1]<<8)+(pAd->MacTab.Content[SetAsicWcid.WCID].Addr[0]); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("1-MACValue= %x,\n", MACValue)); ++ RTUSBWriteMACRegister(pAd, offset, MACValue); ++ // Read bitmask ++ RTUSBReadMACRegister(pAd, offset+4, &MACRValue); ++ if ( SetAsicWcid.DeleteTid != 0xffffffff) ++ MACRValue &= (~SetAsicWcid.DeleteTid); ++ if (SetAsicWcid.SetTid != 0xffffffff) ++ MACRValue |= (SetAsicWcid.SetTid); ++ MACRValue &= 0xffff0000; ++ ++ MACValue = (pAd->MacTab.Content[SetAsicWcid.WCID].Addr[5]<<8)+pAd->MacTab.Content[SetAsicWcid.WCID].Addr[4]; ++ MACValue |= MACRValue; ++ RTUSBWriteMACRegister(pAd, offset+4, MACValue); ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-MACValue= %x,\n", MACValue)); ++ } ++ break; ++ ++ case CMDTHREAD_SET_ASIC_WCID_CIPHER: ++ { ++#ifdef CONFIG_STA_SUPPORT ++ RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; ++ USHORT offset; ++ UINT32 MACRValue = 0; ++ SHAREDKEY_MODE_STRUC csr1; ++ SetAsicWcidAttri = *((PRT_SET_ASIC_WCID_ATTRI)(pData)); ++ ++ if (SetAsicWcidAttri.WCID >= MAX_LEN_OF_MAC_TABLE) ++ return; ++ ++ offset = MAC_WCID_ATTRIBUTE_BASE + ((UCHAR)SetAsicWcidAttri.WCID)*HW_WCID_ATTRI_SIZE; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("Cmd : CMDTHREAD_SET_ASIC_WCID_CIPHER : WCID = %ld, Cipher = %lx.\n", SetAsicWcidAttri.WCID, SetAsicWcidAttri.Cipher)); ++ // Read bitmask ++ RTUSBReadMACRegister(pAd, offset, &MACRValue); ++ MACRValue = 0; ++ MACRValue |= (((UCHAR)SetAsicWcidAttri.Cipher) << 1); ++ ++ RTUSBWriteMACRegister(pAd, offset, MACRValue); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-offset = %x , MACValue= %x,\n", offset, MACRValue)); ++ ++ offset = PAIRWISE_IVEIV_TABLE_BASE + ((UCHAR)SetAsicWcidAttri.WCID)*HW_IVEIV_ENTRY_SIZE; ++ MACRValue = 0; ++ if ( (SetAsicWcidAttri.Cipher <= CIPHER_WEP128)) ++ MACRValue |= ( pAd->StaCfg.DefaultKeyId << 30); ++ else ++ MACRValue |= (0x20000000); ++ RTUSBWriteMACRegister(pAd, offset, MACRValue); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("2-offset = %x , MACValue= %x,\n", offset, MACRValue)); ++ ++ // ++ // Update cipher algorithm. WSTA always use BSS0 ++ // ++ // for adhoc mode only ,because wep status slow than add key, when use zero config ++ if (pAd->StaCfg.BssType == BSS_ADHOC ) ++ { ++ offset = MAC_WCID_ATTRIBUTE_BASE; ++ ++ RTUSBReadMACRegister(pAd, offset, &MACRValue); ++ MACRValue &= (~0xe); ++ MACRValue |= (((UCHAR)SetAsicWcidAttri.Cipher) << 1); ++ ++ RTUSBWriteMACRegister(pAd, offset, MACRValue); ++ ++ //Update group key cipher,,because wep status slow than add key, when use zero config ++ RTUSBReadMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), &csr1.word); ++ ++ csr1.field.Bss0Key0CipherAlg = SetAsicWcidAttri.Cipher; ++ csr1.field.Bss0Key1CipherAlg = SetAsicWcidAttri.Cipher; ++ ++ RTUSBWriteMACRegister(pAd, SHARED_KEY_MODE_BASE+4*(0/2), csr1.word); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ break; ++ ++//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> ++ case RT_CMD_SET_KEY_TABLE: //General call for AsicAddPairwiseKeyEntry() ++ { ++ RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; ++ KeyInfo = *((PRT_ADD_PAIRWISE_KEY_ENTRY)(pData)); ++ AsicAddPairwiseKeyEntry(pAd, ++ KeyInfo.MacAddr, ++ (UCHAR)KeyInfo.MacTabMatchWCID, ++ &KeyInfo.CipherKey); ++ } ++ break; ++ case RT_CMD_SET_RX_WCID_TABLE: //General call for RTMPAddWcidAttributeEntry() ++ { ++ PMAC_TABLE_ENTRY pEntry; ++ UCHAR KeyIdx; ++ UCHAR CipherAlg; ++ UCHAR ApIdx; ++ ++ pEntry = (PMAC_TABLE_ENTRY)(pData); ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ KeyIdx = 0; ++ CipherAlg = pEntry->PairwiseKey.CipherAlg; ++ ApIdx = BSS0; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ RTMPAddWcidAttributeEntry( ++ pAd, ++ ApIdx, ++ KeyIdx, ++ CipherAlg, ++ pEntry); ++ } ++ break; ++//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- ++ ++ case CMDTHREAD_SET_CLIENT_MAC_ENTRY: ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ pEntry = (MAC_TABLE_ENTRY *)pData; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)pEntry->Aid); ++ if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) ++ { ++ UINT32 uIV = 0; ++ PUCHAR ptr; ++ ++ ptr = (PUCHAR) &uIV; ++ *(ptr + 3) = (pAd->StaCfg.DefaultKeyId << 6); ++ AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, uIV, 0); ++ AsicUpdateWCIDAttribute(pAd, pEntry->Aid, BSS0, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, FALSE); ++ } ++ else if (pEntry->AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ UINT32 uIV = 0; ++ PUCHAR ptr; ++ ++ ptr = (PUCHAR) &uIV; ++ *(ptr + 3) = (pAd->StaCfg.DefaultKeyId << 6); ++ AsicUpdateWCIDIVEIV(pAd, pEntry->Aid, uIV, 0); ++ AsicUpdateWCIDAttribute(pAd, pEntry->Aid, BSS0, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, FALSE); ++ } ++ else ++ { ++ // ++ // Other case, disable engine. ++ // Don't worry WPA key, we will add WPA Key after 4-Way handshaking. ++ // ++ USHORT offset; ++ offset = MAC_WCID_ATTRIBUTE_BASE + (pEntry->Aid * HW_WCID_ATTRI_SIZE); ++ // RX_PKEY_MODE:0 for no security; RX_KEY_TAB:0 for shared key table; BSS_IDX:0 ++ RTUSBWriteMACRegister(pAd, offset, 0); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ AsicUpdateRxWCIDTable(pAd, pEntry->Aid, pEntry->Addr); ++ printk("UpdateRxWCIDTable(): Aid=%d, Addr=%02x:%02x:%02x:%02x:%02x:%02x!\n", pEntry->Aid, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5]); ++ } ++ break; ++ ++// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet ++ case CMDTHREAD_UPDATE_PROTECT: ++ { ++ AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT), TRUE, 0); ++ } ++ break; ++// end johnli ++ ++ case OID_802_11_ADD_WEP: ++ { ++#ifdef CONFIG_STA_SUPPORT ++ UINT i; ++ UINT32 KeyIdx; ++ PNDIS_802_11_WEP pWepKey; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP \n")); ++ ++ pWepKey = (PNDIS_802_11_WEP)pData; ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ ++ // it is a shared key ++ if ((KeyIdx >= 4) || ((pWepKey->KeyLength != 5) && (pWepKey->KeyLength != 13))) ++ { ++ NdisStatus = NDIS_STATUS_INVALID_DATA; ++ DBGPRINT(RT_DEBUG_ERROR, ("CmdThread::OID_802_11_ADD_WEP, INVALID_DATA!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg; ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ CipherAlg = (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 5)? CIPHER_WEP64 : CIPHER_WEP128; ++ ++ // ++ // Change the WEP cipher to CKIP cipher if CKIP KP on. ++ // Funk UI or Meetinghouse UI will add ckip key from this path. ++ // ++ ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ pAd->MacTab.Content[BSSID_WCID].PairwiseKey.KeyLen = pAd->SharedKey[BSS0][KeyIdx].KeyLen; ++ } ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ UCHAR IVEIV[8]; ++ UINT32 WCIDAttri, Value; ++ USHORT offset, offset2; ++ NdisZeroMemory(IVEIV, 8); ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ // Add BSSID to WCTable. because this is Tx wep key. ++ // WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:1=PAIRWISE KEY, BSSIdx is 0 ++ WCIDAttri = (CipherAlg<<1)|SHAREDKEYTABLE; ++ ++ offset = MAC_WCID_ATTRIBUTE_BASE + (BSSID_WCID* HW_WCID_ATTRI_SIZE); ++ RTUSBWriteMACRegister(pAd, offset, WCIDAttri); ++ // 1. IV/EIV ++ // Specify key index to find shared key. ++ IVEIV[3] = (UCHAR)(KeyIdx<< 6); //WEP Eiv bit off. groupkey index is not 0 ++ offset = PAIRWISE_IVEIV_TABLE_BASE + (BSS0Mcast_WCID * HW_IVEIV_ENTRY_SIZE); ++ offset2 = PAIRWISE_IVEIV_TABLE_BASE + (BSSID_WCID* HW_IVEIV_ENTRY_SIZE); ++ for (i=0; i<8;) ++ { ++ Value = IVEIV[i]; ++ Value += (IVEIV[i+1]<<8); ++ Value += (IVEIV[i+2]<<16); ++ Value += (IVEIV[i+3]<<24); ++ RTUSBWriteMACRegister(pAd, offset+i, Value); ++ RTUSBWriteMACRegister(pAd, offset2+i, Value); ++ i+=4; ++ } ++ ++ // 2. WCID Attribute UDF:3, BSSIdx:3, Alg:3, Keytable:use share key, BSSIdx is 0 ++ WCIDAttri = (pAd->SharedKey[BSS0][KeyIdx].CipherAlg<<1)|SHAREDKEYTABLE; ++ offset = MAC_WCID_ATTRIBUTE_BASE + (BSS0Mcast_WCID* HW_WCID_ATTRI_SIZE); ++ DBGPRINT(RT_DEBUG_TRACE, ("BSS0Mcast_WCID : offset = %x, WCIDAttri = %x\n", offset, WCIDAttri)); ++ RTUSBWriteMACRegister(pAd, offset, WCIDAttri); ++ ++ } ++ AsicAddSharedKeyEntry(pAd, BSS0, (UCHAR)KeyIdx, CipherAlg, pWepKey->KeyMaterial, NULL, NULL); ++ DBGPRINT(RT_DEBUG_TRACE, ("CmdThread::OID_802_11_ADD_WEP (KeyIdx=%d, Len=%d-byte)\n", KeyIdx, pWepKey->KeyLength)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ break; ++ ++ case CMDTHREAD_802_11_COUNTER_MEASURE: ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Control Thread !! ERROR !! Unknown(cmdqelmt->command=0x%x) !! \n", cmdqelmt->command)); ++ break; ++ } ++ } ++ ++ if (cmdqelmt->CmdFromNdis == TRUE) ++ { ++ if (cmdqelmt->buffer != NULL) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ else ++ { ++ if ((cmdqelmt->buffer != NULL) && (cmdqelmt->bufferlength != 0)) ++ NdisFreeMemory(cmdqelmt->buffer, cmdqelmt->bufferlength, 0); ++ { ++ NdisFreeMemory(cmdqelmt, sizeof(CmdQElmt), 0); ++ } ++ } ++ } /* end of while */ ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/common/spectrum.c +@@ -0,0 +1,1876 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ action.c ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ --------- ---------- ---------------------------------------------- ++ Fonchi Wu 2008 created for 802.11h ++ */ ++ ++#include "../rt_config.h" ++#include "../action.h" ++ ++VOID MeasureReqTabInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC); ++ if (pAd->CommonCfg.pMeasureReqTab) ++ NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB)); ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__)); ++ ++ return; ++} ++ ++VOID MeasureReqTabExit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock); ++ ++ if (pAd->CommonCfg.pMeasureReqTab) ++ kfree(pAd->CommonCfg.pMeasureReqTab); ++ pAd->CommonCfg.pMeasureReqTab = NULL; ++ ++ return; ++} ++ ++static PMEASURE_REQ_ENTRY MeasureReqLookUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ UINT HashIdx; ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ++ if (pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ pEntry = pTab->Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if (pEntry->DialogToken == DialogToken) ++ break; ++ else ++ { ++ pPrevEntry = pEntry; ++ pEntry = pEntry->pNext; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ ++ return pEntry; ++} ++ ++static PMEASURE_REQ_ENTRY MeasureReqInsert( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ INT i; ++ ULONG HashIdx; ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry; ++ ULONG Now; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ pEntry = MeasureReqLookUp(pAd, DialogToken); ++ if (pEntry == NULL) ++ { ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry = &pTab->Content[i]; ++ ++ if ((pEntry->Valid == TRUE) ++ && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT))) ++ { ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); ++ pTab->Size--; ++ ++ break; ++ } ++ ++ if (pEntry->Valid == FALSE) ++ break; ++ } ++ ++ if (i < MAX_MEASURE_REQ_TAB_SIZE) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry->lastTime = Now; ++ pEntry->Valid = TRUE; ++ pEntry->DialogToken = DialogToken; ++ pTab->Size++; ++ } ++ else ++ { ++ pEntry = NULL; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__)); ++ } ++ ++ // add this Neighbor entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ if (pTab->Hash[HashIdx] == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pTab->Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ } ++ ++ return pEntry; ++} ++ ++static VOID MeasureReqDelete( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab; ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ return; ++ } ++ ++ // if empty, return ++ if (pTab->Size == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n")); ++ return; ++ } ++ ++ pEntry = MeasureReqLookUp(pAd, DialogToken); ++ if (pEntry != NULL) ++ { ++ PMEASURE_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY)); ++ pTab->Size--; ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); ++ } ++ ++ return; ++} ++ ++VOID TpcReqTabInit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock); ++ ++ pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC); ++ if (pAd->CommonCfg.pTpcReqTab) ++ NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB)); ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__)); ++ ++ return; ++} ++ ++VOID TpcReqTabExit( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock); ++ ++ if (pAd->CommonCfg.pTpcReqTab) ++ kfree(pAd->CommonCfg.pTpcReqTab); ++ pAd->CommonCfg.pTpcReqTab = NULL; ++ ++ return; ++} ++ ++static PTPC_REQ_ENTRY TpcReqLookUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ UINT HashIdx; ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ++ if (pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ ++ HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ pEntry = pTab->Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if (pEntry->DialogToken == DialogToken) ++ break; ++ else ++ { ++ pPrevEntry = pEntry; ++ pEntry = pEntry->pNext; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ ++ return pEntry; ++} ++ ++ ++static PTPC_REQ_ENTRY TpcReqInsert( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ INT i; ++ ULONG HashIdx; ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry; ++ ULONG Now; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return NULL; ++ } ++ ++ pEntry = TpcReqLookUp(pAd, DialogToken); ++ if (pEntry == NULL) ++ { ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry = &pTab->Content[i]; ++ ++ if ((pEntry->Valid == TRUE) ++ && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT))) ++ { ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); ++ pTab->Size--; ++ ++ break; ++ } ++ ++ if (pEntry->Valid == FALSE) ++ break; ++ } ++ ++ if (i < MAX_TPC_REQ_TAB_SIZE) ++ { ++ NdisGetSystemUpTime(&Now); ++ pEntry->lastTime = Now; ++ pEntry->Valid = TRUE; ++ pEntry->DialogToken = DialogToken; ++ pTab->Size++; ++ } ++ else ++ { ++ pEntry = NULL; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__)); ++ } ++ ++ // add this Neighbor entry into HASH table ++ if (pEntry) ++ { ++ HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken); ++ if (pTab->Hash[HashIdx] == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pTab->Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ } ++ ++ return pEntry; ++} ++ ++static VOID TpcReqDelete( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 DialogToken) ++{ ++ PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ ++ if(pTab == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ return; ++ } ++ ++ // if empty, return ++ if (pTab->Size == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n")); ++ return; ++ } ++ ++ pEntry = TpcReqLookUp(pAd, DialogToken); ++ if (pEntry != NULL) ++ { ++ PTPC_REQ_ENTRY pPrevEntry = NULL; ++ ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); ++ PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx]; ++ ++ RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock); ++ // update Hash list ++ do ++ { ++ if (pProbeEntry == pEntry) ++ { ++ if (pPrevEntry == NULL) ++ { ++ pTab->Hash[HashIdx] = pEntry->pNext; ++ } ++ else ++ { ++ pPrevEntry->pNext = pEntry->pNext; ++ } ++ break; ++ } ++ ++ pPrevEntry = pProbeEntry; ++ pProbeEntry = pProbeEntry->pNext; ++ } while (pProbeEntry); ++ ++ NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY)); ++ pTab->Size--; ++ ++ RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Get Current TimeS tamp. ++ ++ Parametrs: ++ ++ Return : Current Time Stamp. ++ ========================================================================== ++ */ ++static UINT64 GetCurrentTimeStamp( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // get current time stamp. ++ return 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Get Current Transmit Power. ++ ++ Parametrs: ++ ++ Return : Current Time Stamp. ++ ========================================================================== ++ */ ++static UINT8 GetCurTxPwr( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 Wcid) ++{ ++ return 16; /* 16 dBm */ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Dialog Token into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Dialog token. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertDialogToken( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 DialogToken) ++{ ++ ULONG TempLen; ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &DialogToken, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert TPC Request IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ static VOID InsertTpcReqIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen) ++{ ++ ULONG TempLen; ++ ULONG Len = 0; ++ UINT8 ElementID = IE_TPC_REQUEST; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert TPC Report IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Transmit Power. ++ 4. Link Margin. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ static VOID InsertTpcReportIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin) ++{ ++ ULONG TempLen; ++ ULONG Len = sizeof(TPC_REPORT_INFO); ++ UINT8 ElementID = IE_TPC_REPORT; ++ TPC_REPORT_INFO TpcReportIE; ++ ++ TpcReportIE.TxPwr = TxPwr; ++ TpcReportIE.LinkMargin = LinkMargin; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, &TpcReportIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Channel Switch Announcement IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. channel switch announcement mode. ++ 4. new selected channel. ++ 5. channel switch announcement count. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertChSwAnnIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewChannel, ++ IN UINT8 ChSwCnt) ++{ ++ ULONG TempLen; ++ ULONG Len = sizeof(CH_SW_ANN_INFO); ++ UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT; ++ CH_SW_ANN_INFO ChSwAnnIE; ++ ++ ChSwAnnIE.ChSwMode = ChSwMode; ++ ChSwAnnIE.Channel = NewChannel; ++ ChSwAnnIE.ChSwCnt = ChSwCnt; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, &ChSwAnnIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Measure Request IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Measure Token. ++ 4. Measure Request Mode. ++ 5. Measure Request Type. ++ 6. Measure Channel. ++ 7. Measure Start time. ++ 8. Measure Duration. ++ ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertMeasureReqIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN PMEASURE_REQ_INFO pMeasureReqIE) ++{ ++ ULONG TempLen; ++ UINT8 Len = sizeof(MEASURE_REQ_INFO); ++ UINT8 ElementID = IE_MEASUREMENT_REQUEST; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, pMeasureReqIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Insert Measure Report IE into frame. ++ ++ Parametrs: ++ 1. frame buffer pointer. ++ 2. frame length. ++ 3. Measure Token. ++ 4. Measure Request Mode. ++ 5. Measure Request Type. ++ 6. Length of Report Infomation ++ 7. Pointer of Report Infomation Buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID InsertMeasureReportIE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN PMEASURE_REPORT_INFO pMeasureReportIE, ++ IN UINT8 ReportLnfoLen, ++ IN PUINT8 pReportInfo) ++{ ++ ULONG TempLen; ++ ULONG Len; ++ UINT8 ElementID = IE_MEASUREMENT_REPORT; ++ ++ Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen; ++ ++ MakeOutgoingFrame(pFrameBuf, &TempLen, ++ 1, &ElementID, ++ 1, &Len, ++ Len, pMeasureReportIE, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ ++ if ((ReportLnfoLen > 0) && (pReportInfo != NULL)) ++ { ++ MakeOutgoingFrame(pFrameBuf + *pFrameLen, &TempLen, ++ ReportLnfoLen, pReportInfo, ++ END_OF_ARGS); ++ ++ *pFrameLen = *pFrameLen + TempLen; ++ } ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 MeasureCh, ++ IN UINT16 MeasureDuration) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ HEADER_802_11 ActHdr; ++ MEASURE_REQ_INFO MeasureReqIE; ++ UINT8 RmReqDailogToken = RandomByte(pAd); ++ UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd); ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken); ++ ++ // prepare Measurement IE. ++ NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO)); ++ MeasureReqIE.Token = RmReqDailogToken; ++ MeasureReqIE.ReqMode.word = MeasureReqMode; ++ MeasureReqIE.ReqType = MeasureReqType; ++ MeasureReqIE.MeasureReq.ChNum = MeasureCh; ++ MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime); ++ MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration); ++ InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 ReportInfoLen, ++ IN PUINT8 pReportInfo) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ HEADER_802_11 ActHdr; ++ MEASURE_REPORT_INFO MeasureRepIE; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // prepare Measurement IE. ++ NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO)); ++ MeasureRepIE.Token = MeasureToken; ++ MeasureRepIE.ReportMode.word = MeasureReqMode; ++ MeasureRepIE.ReportType = MeasureReqType; ++ InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UCHAR DialogToken) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // Insert TPC Request IE. ++ InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP); ++ ++ // fill Dialog Token ++ InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken); ++ ++ // Insert TPC Request IE. ++ InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Channel Switch Announcement action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ 2. Channel switch announcement mode. ++ 2. a New selected channel. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueChSwAnn( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewCh) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen; ++ ++ HEADER_802_11 ActHdr; ++ ++ // build action frame header. ++ MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, ++ pAd->CurrentAddress); ++ ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ return; ++ } ++ NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); ++ FrameLen = sizeof(HEADER_802_11); ++ ++ InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH); ++ ++ InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ return; ++} ++ ++static BOOLEAN DfsRequirementCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT8 Channel) ++{ ++ BOOLEAN Result = FALSE; ++ INT i; ++ ++ do ++ { ++ // check DFS procedure is running. ++ // make sure DFS procedure won't start twice. ++ if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE) ++ { ++ Result = FALSE; ++ break; ++ } ++ ++ // check the new channel carried from Channel Switch Announcemnet is valid. ++ for (i=0; iChannelListNum; i++) ++ { ++ if ((Channel == pAd->ChannelList[i].Channel) ++ &&(pAd->ChannelList[i].RemainingTimeForUse == 0)) ++ { ++ // found radar signal in the channel. the channel can't use at least for 30 minutes. ++ pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec ++ Result = TRUE; ++ break; ++ } ++ } ++ } while(FALSE); ++ ++ return Result; ++} ++ ++VOID NotifyChSwAnnToPeerAPs( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRA, ++ IN PUCHAR pTA, ++ IN UINT8 ChSwMode, ++ IN UINT8 Channel) ++{ ++#ifdef WDS_SUPPORT ++ if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address. ++ { ++ INT i; ++ // info neighbor APs that Radar signal found throgh WDS link. ++ for (i = 0; i < MAX_WDS_ENTRY; i++) ++ { ++ if (ValidWdsEntry(pAd, i)) ++ { ++ PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr; ++ ++ // DA equal to SA. have no necessary orignal AP which found Radar signal. ++ if (MAC_ADDR_EQUAL(pTA, pDA)) ++ continue; ++ ++ // send Channel Switch Action frame to info Neighbro APs. ++ EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel); ++ } ++ } ++ } ++#endif // WDS_SUPPORT // ++} ++ ++static VOID StartDFSProcedure( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN UINT8 ChSwMode) ++{ ++ // start DFS procedure ++ pAd->CommonCfg.Channel = Channel; ++#ifdef DOT11_N_SUPPORT ++ N_ChannelCheck(pAd); ++#endif // DOT11_N_SUPPORT // ++ pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE; ++ pAd->CommonCfg.RadarDetect.CSCount = 0; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Channel Switch Announcement action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Channel switch announcement infomation buffer. ++ ++ ++ Return : None. ++ ========================================================================== ++ */ ++ ++/* ++ Channel Switch Announcement IE. ++ +----+-----+-----------+------------+-----------+ ++ | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt | ++ +----+-----+-----------+------------+-----------+ ++ 1 1 1 1 1 ++*/ ++static BOOLEAN PeerChSwAnnSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PCH_SW_ANN_INFO pChSwAnnInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pChSwAnnInfo == NULL) ++ return result; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_CHANNEL_SWITCH_ANNOUNCEMENT: ++ NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1); ++ ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement request action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Measurement request infomation buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerMeasureReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PMEASURE_REQ_INFO pMeasureReqInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ PUCHAR ptr; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pMeasureReqInfo == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_MEASUREMENT_REQUEST: ++ NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1); ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1); ++ NdisMoveMemory(&MeasureStartTime, ptr + 1, 8); ++ pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime); ++ NdisMoveMemory(&MeasureDuration, ptr + 9, 2); ++ pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration); ++ ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement report action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Measurement report infomation buffer. ++ 4. basic report infomation buffer. ++ ++ Return : None. ++ ========================================================================== ++ */ ++ ++/* ++ Measurement Report IE. ++ +----+-----+-------+-------------+--------------+----------------+ ++ | ID | Len | Token | Report Mode | Measure Type | Measure Report | ++ +----+-----+-------+-------------+--------------+----------------+ ++ 1 1 1 1 1 variable ++ ++ Basic Report. ++ +--------+------------+----------+-----+ ++ | Ch Num | Start Time | Duration | Map | ++ +--------+------------+----------+-----+ ++ 1 8 2 1 ++ ++ Map Field Bit Format. ++ +-----+---------------+---------------------+-------+------------+----------+ ++ | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved | ++ +-----+---------------+---------------------+-------+------------+----------+ ++ 0 1 2 3 4 5-7 ++*/ ++static BOOLEAN PeerMeasureReportSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PMEASURE_REPORT_INFO pMeasureReportInfo, ++ OUT PUINT8 pReportBuf) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ PUCHAR ptr; ++ ++ // skip 802.11 header. ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pMeasureReportInfo == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_MEASUREMENT_REPORT: ++ NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1); ++ NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1); ++ if (pMeasureReportInfo->ReportType == RM_BASIC) ++ { ++ PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->Map, ptr + 11, 1); ++ ++ } ++ else if (pMeasureReportInfo->ReportType == RM_CCA) ++ { ++ PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1); ++ ++ } ++ else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM) ++ { ++ PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf; ++ ptr = eid_ptr->Octet + 3; ++ NdisMoveMemory(&pReport->ChNum, ptr, 1); ++ NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8); ++ NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2); ++ NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8); ++ } ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Request action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Dialog Token. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerTpcReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pDialogToken == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_TPC_REQUEST: ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Report action frame sanity check. ++ ++ Parametrs: ++ 1. MLME message containing the received frame ++ 2. message length. ++ 3. Dialog Token. ++ 4. TPC Report IE. ++ ++ Return : None. ++ ========================================================================== ++ */ ++static BOOLEAN PeerTpcRepSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUINT8 pDialogToken, ++ OUT PTPC_REPORT_INFO pTpcRepInfo) ++{ ++ PFRAME_802_11 Fr = (PFRAME_802_11)pMsg; ++ PUCHAR pFramePtr = Fr->Octet; ++ BOOLEAN result = FALSE; ++ PEID_STRUCT eid_ptr; ++ ++ MsgLen -= sizeof(HEADER_802_11); ++ ++ // skip category and action code. ++ pFramePtr += 2; ++ MsgLen -= 2; ++ ++ if (pDialogToken == NULL) ++ return result; ++ ++ NdisMoveMemory(pDialogToken, pFramePtr, 1); ++ pFramePtr += 1; ++ MsgLen -= 1; ++ ++ eid_ptr = (PEID_STRUCT)pFramePtr; ++ while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen)) ++ { ++ switch(eid_ptr->Eid) ++ { ++ case IE_TPC_REPORT: ++ NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1); ++ NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1); ++ result = TRUE; ++ break; ++ ++ default: ++ break; ++ } ++ eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len); ++ } ++ ++ return result; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Channel Switch Announcement action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerChSwAnnAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ CH_SW_ANN_INFO ChSwAnnInfo; ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR index = 0, Channel = 0, NewChannel = 0; ++ ULONG Bssidx = 0; ++#endif // CONFIG_STA_SUPPORT // ++ ++ NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO)); ++ if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n")); ++ return; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n")); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel)); ++ hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6); ++ ++ Channel = pAd->CommonCfg.Channel; ++ NewChannel = ChSwAnnInfo.Channel; ++ ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) ++ { ++ // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). ++ // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. ++ AsicSwitchChannel(pAd, 1, FALSE); ++ AsicLockChannel(pAd, 1); ++ LinkDown(pAd, FALSE); ++ MlmeQueueInit(&pAd->Mlme.Queue); ++ BssTableInit(&pAd->ScanTab); ++ RTMPusecDelay(1000000); // use delay to prevent STA do reassoc ++ ++ // channel sanity check ++ for (index = 0 ; index < pAd->ChannelListNum; index++) ++ { ++ if (pAd->ChannelList[index].Channel == NewChannel) ++ { ++ pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; ++ pAd->CommonCfg.Channel = NewChannel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); ++ break; ++ } ++ } ++ ++ if (index >= pAd->ChannelListNum) ++ { ++ DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement Request action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerMeasureReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ UINT8 DialogToken; ++ MEASURE_REQ_INFO MeasureReqInfo; ++ MEASURE_REPORT_MODE ReportMode; ++ ++ if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo)) ++ { ++ ReportMode.word = 0; ++ ReportMode.field.Incapable = 1; ++ EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL); ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Measurement Report action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerMeasureReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MEASURE_REPORT_INFO MeasureReportInfo; ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ UINT8 DialogToken; ++ PUINT8 pMeasureReportInfo; ++ ++// if (pAd->CommonCfg.bIEEE80211H != TRUE) ++// return; ++ ++ if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT))); ++ return; ++ } ++ ++ NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO)); ++ NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT)); ++ if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo)) ++ { ++ do { ++ PMEASURE_REQ_ENTRY pEntry = NULL; ++ ++ // Not a autonomous measure report. ++ // check the dialog token field. drop it if the dialog token doesn't match. ++ if ((DialogToken != 0) ++ && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL)) ++ break; ++ ++ if (pEntry != NULL) ++ MeasureReqDelete(pAd, pEntry->DialogToken); ++ ++ if (MeasureReportInfo.ReportType == RM_BASIC) ++ { ++ PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo; ++ if ((pBasicReport->Map.field.Radar) ++ && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE)) ++ { ++ NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum); ++ StartDFSProcedure(pAd, pBasicReport->ChNum, 1); ++ } ++ } ++ } while (FALSE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n")); ++ ++ kfree(pMeasureReportInfo); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Request action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerTpcReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg; ++ PUCHAR pFramePtr = pFr->Octet; ++ UINT8 DialogToken; ++ UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid); ++ UINT8 LinkMargin = 0; ++ CHAR RealRssi; ++ ++ // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The ++ // STA may incorporate rate information and channel conditions, including interference, into its computation ++ // of link margin. ++ ++ RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ++ ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ++ ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ // skip Category and action code. ++ pFramePtr += 2; ++ ++ // Dialog token. ++ NdisMoveMemory(&DialogToken, pFramePtr, 1); ++ ++ LinkMargin = (RealRssi / MIN_RCV_PWR); ++ if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken)) ++ EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin); ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ TPC Report action frame handler. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++static VOID PeerTpcRepAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UINT8 DialogToken; ++ TPC_REPORT_INFO TpcRepInfo; ++ PTPC_REQ_ENTRY pEntry = NULL; ++ ++ NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO)); ++ if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo)) ++ { ++ if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL) ++ { ++ TpcReqDelete(pAd, pEntry->DialogToken); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n", ++ __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); ++ } ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Spectrun action frames Handler such as channel switch annoucement, ++ measurement report, measurement request actions frames. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID PeerSpectrumAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ ++ UCHAR Action = Elem->Msg[LENGTH_802_11+1]; ++ ++ if (pAd->CommonCfg.bIEEE80211H != TRUE) ++ return; ++ ++ switch(Action) ++ { ++ case SPEC_MRQ: ++ // current rt2860 unable do such measure specified in Measurement Request. ++ // reject all measurement request. ++ PeerMeasureReqAction(pAd, Elem); ++ break; ++ ++ case SPEC_MRP: ++ PeerMeasureReportAction(pAd, Elem); ++ break; ++ ++ case SPEC_TPCRQ: ++ PeerTpcReqAction(pAd, Elem); ++ break; ++ ++ case SPEC_TPCRP: ++ PeerTpcRepAction(pAd, Elem); ++ break; ++ ++ case SPEC_CHANNEL_SWITCH: ++{ ++#ifdef DOT11N_DRAFT3 ++ SEC_CHA_OFFSET_IE Secondary; ++ CHA_SWITCH_ANNOUNCE_IE ChannelSwitch; ++ ++ // 802.11h only has Channel Switch Announcement IE. ++ RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE)); ++ ++ // 802.11n D3.03 adds secondary channel offset element in the end. ++ if (Elem->MsgLen == (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE))) ++ { ++ RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE)); ++ } ++ else ++ { ++ Secondary.SecondaryChannelOffset = 0; ++ } ++ ++ if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3)) ++ { ++ ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset); ++ } ++#endif // DOT11N_DRAFT3 // ++} ++ PeerChSwAnnAction(pAd, Elem); ++ break; ++ } ++ ++ return; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Parametrs: ++ ++ Return : None. ++ ========================================================================== ++ */ ++INT Set_MeasureReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT Aid = 1; ++ UINT ArgIdx; ++ PUCHAR thisChar; ++ ++ MEASURE_REQ_MODE MeasureReqMode; ++ UINT8 MeasureReqToken = RandomByte(pAd); ++ UINT8 MeasureReqType = RM_BASIC; ++ UINT8 MeasureCh = 1; ++ ++ ArgIdx = 1; ++ while ((thisChar = strsep((char **)&arg, "-")) != NULL) ++ { ++ switch(ArgIdx) ++ { ++ case 1: // Aid. ++ Aid = simple_strtol(thisChar, 0, 16); ++ break; ++ ++ case 2: // Measurement Request Type. ++ MeasureReqType = simple_strtol(thisChar, 0, 16); ++ if (MeasureReqType > 3) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType)); ++ return TRUE; ++ } ++ break; ++ ++ case 3: // Measurement channel. ++ MeasureCh = simple_strtol(thisChar, 0, 16); ++ break; ++ } ++ ArgIdx++; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh)); ++ if (!VALID_WCID(Aid)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ return TRUE; ++ } ++ ++ MeasureReqMode.word = 0; ++ MeasureReqMode.field.Enable = 1; ++ ++ MeasureReqInsert(pAd, MeasureReqToken); ++ ++ EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr, ++ MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000); ++ ++ return TRUE; ++} ++ ++INT Set_TpcReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT Aid; ++ ++ UINT8 TpcReqToken = RandomByte(pAd); ++ ++ Aid = simple_strtol(arg, 0, 16); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid)); ++ if (!VALID_WCID(Aid)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ return TRUE; ++ } ++ ++ TpcReqInsert(pAd, TpcReqToken); ++ ++ EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken); ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/dfs.h +@@ -0,0 +1,100 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ dfs.h ++ ++ Abstract: ++ Support DFS function. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Fonchi 03-12-2007 created ++*/ ++ ++#define RADAR_PULSE 1 ++#define RADAR_WIDTH 2 ++ ++#define WIDTH_RD_IDLE 0 ++#define WIDTH_RD_CHECK 1 ++ ++ ++VOID BbpRadarDetectionStart( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BbpRadarDetectionStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RadarDetectionStart( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN CTS_Protect, ++ IN UINT8 CTSPeriod); ++ ++VOID RadarDetectionStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RadarDetectPeriodic( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++BOOLEAN RadarChannelCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ch); ++ ++ULONG JapRadarType( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPBbpReadRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPReadRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPCleanRadarDuration( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPrepareRDCTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN ULONG Duration, ++ IN UCHAR RTSRate, ++ IN ULONG CTSBaseAddr, ++ IN UCHAR FrameGap); ++ ++VOID RTMPPrepareRadarDetectParams( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++INT Set_ChMovingTime_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_LongPulseRadarTh_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/firmware.h +@@ -0,0 +1,558 @@ ++/* ++ Copyright (c) 2007, Ralink Technology Corporation ++ All rights reserved. ++ ++ Redistribution. Redistribution and use in binary form, without ++ modification, are permitted provided that the following conditions are ++ met: ++ ++ * Redistributions must reproduce the above copyright notice and the ++ following disclaimer in the documentation and/or other materials ++ provided with the distribution. ++ * Neither the name of Ralink Technology Corporation nor the names of its ++ suppliers may be used to endorse or promote products derived from this ++ software without specific prior written permission. ++ * No reverse engineering, decompilation, or disassembly of this software ++ is permitted. ++ ++ Limited patent license. Ralink Technology Corporation grants a world-wide, ++ royalty-free, non-exclusive license under patents it now or hereafter ++ owns or controls to make, have made, use, import, offer to sell and ++ sell ("Utilize") this software, but solely to the extent that any ++ such patent is necessary to Utilize the software alone, or in ++ combination with an operating system licensed under an approved Open ++ Source license as listed by the Open Source Initiative at ++ http://opensource.org/licenses. The patent license shall not apply to ++ any other combinations which include this software. No hardware per ++ se is licensed hereunder. ++ ++ DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ++ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ++ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ++ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ++ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ++ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS ++ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR ++ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ DAMAGE. ++*/ ++/* AUTO GEN PLEASE DO NOT MODIFY IT */ ++/* AUTO GEN PLEASE DO NOT MODIFY IT */ ++ ++ ++UCHAR FirmwareImage [] = { ++0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x12, 0x67, 0x02, ++0x12, 0x68, 0x02, 0x12, 0x87, 0x02, 0x12, 0x8c, 0x12, 0x12, 0x88, 0x22, 0x02, 0x16, 0x49, 0x02, ++0x17, 0x1f, 0x02, 0x13, 0x77, 0x02, 0x12, 0x8d, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x17, ++0xc1, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40, ++0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4, ++0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4, ++0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01, ++0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xc8, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02, ++0x12, 0x66, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0x9d, 0x10, ++0xb7, 0x31, 0x10, 0xe0, 0x50, 0x11, 0x04, 0x51, 0x11, 0x0d, 0x52, 0x11, 0x0d, 0x53, 0x11, 0x0d, ++0x54, 0x11, 0x4e, 0x55, 0x11, 0x7e, 0x70, 0x11, 0xa9, 0x71, 0x11, 0xd7, 0x72, 0x12, 0x1d, 0x73, ++0x12, 0x3e, 0x80, 0x00, 0x00, 0x12, 0x66, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf, ++0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, ++0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x22, ++0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x12, 0x66, 0x90, 0x70, 0x11, ++0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x12, 0x66, 0x75, 0x4e, 0x03, ++0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47, 0x22, 0x90, 0x04, 0x04, ++0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0, 0xff, 0x74, 0x47, 0x25, 0x57, ++0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef, ++0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, ++0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0xe5, 0x47, ++0x64, 0x07, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0x90, ++0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03, ++0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0xd2, 0x04, 0x22, 0x90, 0x70, ++0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, ++0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, ++0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, ++0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, ++0x91, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, ++0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x10, 0x02, 0xe0, 0xb4, 0x70, 0x1e, 0xa3, 0xe0, ++0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd, 0x90, 0x05, 0x05, 0xe0, 0x54, ++0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe, 0x90, 0x05, 0x08, 0xf0, 0xe4, 0xf5, 0x4e, 0xf5, ++0x4f, 0x75, 0x3a, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, 0x80, ++0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x4b, 0x80, 0x42, 0x90, 0x70, 0x10, ++0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, 0x04, 0x14, 0x74, ++0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70, ++0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0x91, 0x90, ++0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90, ++0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, 0x09, 0xb2, ++0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, ++0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22, 0xc2, 0x42, 0xd3, 0x22, 0x22, 0xc2, 0x4b, 0xc2, ++0x4c, 0xe5, 0x44, 0x12, 0x0a, 0x9d, 0x12, 0xaf, 0x00, 0x13, 0x42, 0x04, 0x13, 0x3e, 0x08, 0x13, ++0x19, 0x10, 0x12, 0xc3, 0x20, 0x12, 0xe3, 0x60, 0x12, 0xf4, 0xa0, 0x00, 0x00, 0x13, 0x44, 0x85, ++0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, 0x02, 0x13, ++0x44, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, 0x0f, 0xf5, ++0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x66, 0x53, 0x43, ++0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, 0x64, 0x06, ++0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, 0x54, 0x0f, ++0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x35, 0xe5, ++0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, 0x06, 0x53, 0x5e, ++0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, 0x42, 0x09, 0xe5, ++0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, 0x06, 0xd2, 0x4b, ++0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, 0xe5, 0x43, 0x54, ++0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, 0xe5, 0x4a, 0xf0, ++0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, 0xe5, 0x42, 0xf0, ++0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, 0x70, 0x03, 0x12, ++0x16, 0x29, 0x12, 0x13, 0x8c, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x90, 0x04, ++0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, 0x24, 0xff, ++0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74, 0x1e, 0xf0, 0xe5, ++0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5, 0x5f, 0x20, 0xe5, ++0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, 0x25, 0x70, 0x05, ++0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, 0x5f, 0x30, ++0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, 0x64, 0x03, ++0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25, 0x70, 0x03, 0x30, ++0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02, 0x15, 0x25, 0xd2, ++0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b, 0xe5, 0x3a, 0x64, ++0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5, ++0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5, ++0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c, ++0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x26, ++0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01, ++0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, ++0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, ++0x26, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f, ++0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, ++0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, ++0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe1, 0x04, ++0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, ++0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x71, 0x92, 0x70, 0x90, 0x10, 0x00, 0xe0, ++0x90, 0x10, 0x2f, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3, 0x94, 0x30, 0x40, 0x14, 0xa2, 0x71, 0x92, ++0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13, 0x54, 0x3f, 0xf5, 0x2e, 0xc2, 0x77, 0xd2, ++0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4c, 0x90, 0x02, 0x29, ++0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, 0x60, 0x23, ++0x24, 0x03, 0x60, 0x03, 0x02, 0x16, 0x18, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0f, 0x80, 0x07, ++0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x06, 0x54, 0xfe, 0xf0, 0x02, 0x16, 0x18, 0x44, 0x01, 0xf0, ++0x02, 0x16, 0x18, 0xe5, 0x46, 0x30, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02, ++0x28, 0xe0, 0x54, 0xfe, 0x4f, 0xf0, 0x02, 0x16, 0x18, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0f, 0xe5, ++0x47, 0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02, 0x16, 0x18, 0xe4, 0xf5, ++0x27, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x2e, ++0x14, 0x60, 0x36, 0x24, 0xfc, 0x60, 0x5f, 0x24, 0xf9, 0x60, 0x1f, 0x24, 0x0e, 0x70, 0x69, 0xe5, ++0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, ++0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x45, 0xa2, 0x47, 0x80, 0x41, 0xe5, 0x46, ++0x30, 0xe2, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, ++0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, ++0x47, 0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, ++0x47, 0xb3, 0x92, 0x39, 0x80, 0x19, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, ++0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, ++0x02, 0x28, 0xe0, 0x54, 0xfc, 0x45, 0x27, 0xf0, 0x90, 0x70, 0x9c, 0xe5, 0x3a, 0xf0, 0xa3, 0xe5, ++0x47, 0xf0, 0x90, 0x70, 0x41, 0xe5, 0x3a, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, ++0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, ++0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x62, 0xc2, 0xaf, 0xe5, 0x51, ++0x14, 0x60, 0x46, 0x14, 0x60, 0x62, 0x24, 0x02, 0x60, 0x03, 0x02, 0x17, 0x03, 0xd2, 0x59, 0x75, ++0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0, 0x20, 0xe7, 0x22, 0x90, 0x04, ++0x34, 0xe0, 0xb4, 0x02, 0x1b, 0xa3, 0xe0, 0xb4, 0x02, 0x16, 0xa3, 0xe0, 0xb4, 0x02, 0x11, 0x7f, ++0x20, 0x12, 0x16, 0x3f, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x80, 0x73, ++0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, 0x80, 0x6a, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, ++0x11, 0x7f, 0x20, 0x12, 0x16, 0x3f, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02, ++0x80, 0x51, 0xe5, 0x50, 0x70, 0x02, 0x80, 0x46, 0x90, 0x02, 0xa3, 0xe0, 0x20, 0xe6, 0x3b, 0x90, ++0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x33, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96, ++0xf0, 0x90, 0x12, 0x04, 0x74, 0x0a, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, ++0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54, 0xf9, 0xf0, 0x75, ++0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, ++0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xad, 0x62, ++0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2, ++0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, ++0x02, 0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70, 0x4c, 0x75, 0x52, ++0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44, ++0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, ++0x03, 0xf0, 0x90, 0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x0c, 0xf0, ++0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, 0x12, 0x17, ++0x8d, 0x80, 0x02, 0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, ++0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, ++0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, ++0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, ++0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10, ++0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10, ++0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90, ++0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90, ++0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01, ++0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x94, 0x3f, ++0xff, 0xff, 0xff, 0x02, 0x10, 0x28, 0x02, 0x10, 0x32, 0x02, 0x10, 0x78, 0x02, 0x12, 0x67, 0x02, ++0x12, 0x68, 0x02, 0x12, 0x87, 0x02, 0x12, 0x8c, 0x12, 0x12, 0x88, 0x22, 0x02, 0x16, 0x49, 0x02, ++0x17, 0x1f, 0x02, 0x13, 0x77, 0x02, 0x12, 0x8d, 0x30, 0x05, 0x06, 0x20, 0x0d, 0x03, 0x12, 0x17, ++0xc1, 0x22, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe3, 0x1b, 0xe5, 0x4c, 0x30, 0xe0, 0x04, 0x7f, 0x40, ++0x80, 0x02, 0x7f, 0x00, 0x90, 0x10, 0x2f, 0xef, 0xf0, 0x90, 0x01, 0x8c, 0x74, 0x08, 0xf0, 0xe4, ++0x90, 0x01, 0xa7, 0xf0, 0x90, 0x01, 0x8c, 0xe0, 0x30, 0xe0, 0x1c, 0x90, 0x01, 0x80, 0xe0, 0xb4, ++0x02, 0x15, 0xa3, 0xe0, 0xb4, 0x01, 0x10, 0x90, 0x01, 0x84, 0xe0, 0xb4, 0x81, 0x09, 0x90, 0x01, ++0x8c, 0x74, 0x01, 0xf0, 0x12, 0x0d, 0xdd, 0x22, 0x90, 0x04, 0x14, 0xe0, 0x20, 0xe7, 0x03, 0x02, ++0x12, 0x66, 0x90, 0x70, 0x12, 0xe0, 0xf5, 0x56, 0x90, 0x04, 0x04, 0xe0, 0x12, 0x0a, 0xb6, 0x10, ++0xb7, 0x31, 0x10, 0xe0, 0x50, 0x11, 0x04, 0x51, 0x11, 0x0d, 0x52, 0x11, 0x0d, 0x53, 0x11, 0x0d, ++0x54, 0x11, 0x4e, 0x55, 0x11, 0x7e, 0x70, 0x11, 0xa9, 0x71, 0x11, 0xd7, 0x72, 0x12, 0x1d, 0x73, ++0x12, 0x3e, 0x80, 0x00, 0x00, 0x12, 0x66, 0x20, 0x02, 0x03, 0x30, 0x03, 0x1d, 0x7d, 0x02, 0xaf, ++0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, ++0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x85, 0x56, 0x41, 0xd2, 0x02, 0x22, ++0x90, 0x70, 0x10, 0xe0, 0x54, 0x7f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x12, 0x66, 0x90, 0x70, 0x11, ++0xe0, 0x64, 0x08, 0x60, 0x08, 0xe0, 0x64, 0x20, 0x60, 0x03, 0x02, 0x12, 0x66, 0x75, 0x4e, 0x03, ++0x75, 0x4f, 0x20, 0x22, 0x90, 0x70, 0x11, 0xe0, 0x24, 0xff, 0x92, 0x47, 0x22, 0x90, 0x04, 0x04, ++0xe0, 0x25, 0xe0, 0x24, 0x5d, 0xf5, 0x57, 0x90, 0x70, 0x10, 0xe0, 0xff, 0x74, 0x47, 0x25, 0x57, ++0xf8, 0xc6, 0xef, 0xc6, 0x90, 0x70, 0x11, 0xe0, 0xff, 0x74, 0x48, 0x25, 0x57, 0xf8, 0xc6, 0xef, ++0xc6, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, ++0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0xe5, 0x47, ++0x64, 0x07, 0x60, 0x0b, 0xe5, 0x47, 0x64, 0x08, 0x60, 0x05, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0x90, ++0x70, 0x11, 0xe0, 0x54, 0x0f, 0xf5, 0x3a, 0xe5, 0x47, 0xb4, 0x09, 0x08, 0xe5, 0x3a, 0xb4, 0x03, ++0x03, 0xe4, 0xf5, 0x46, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0xd2, 0x04, 0x22, 0x90, 0x70, ++0x10, 0xe0, 0xfe, 0x90, 0x70, 0x11, 0xe0, 0xfd, 0xed, 0xf8, 0xe6, 0xf5, 0x57, 0xfd, 0xaf, 0x56, ++0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, ++0xf4, 0x70, 0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x70, 0x10, 0xe0, 0xfe, 0x90, 0x70, ++0x11, 0xe0, 0xfd, 0xed, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xf5, 0x57, 0xfd, 0xaf, 0x56, 0x12, 0x0b, ++0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x70, ++0x03, 0x02, 0x12, 0x66, 0x02, 0x12, 0x5f, 0x90, 0x10, 0x02, 0xe0, 0xb4, 0x70, 0x1e, 0xa3, 0xe0, ++0xb4, 0x30, 0x19, 0x90, 0x05, 0x08, 0xe0, 0x44, 0x01, 0xf0, 0xfd, 0x90, 0x05, 0x05, 0xe0, 0x54, ++0xfb, 0xf0, 0x44, 0x04, 0xf0, 0xed, 0x54, 0xfe, 0x90, 0x05, 0x08, 0xf0, 0xe4, 0xf5, 0x4e, 0xf5, ++0x4f, 0x75, 0x3a, 0xff, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, 0x80, ++0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x4b, 0x80, 0x42, 0x90, 0x70, 0x10, ++0xe0, 0x24, 0xff, 0x92, 0x93, 0xe4, 0xfd, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, 0x04, 0x14, 0x74, ++0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x2a, 0x80, 0x21, 0x90, 0x70, ++0x10, 0xe0, 0x24, 0xff, 0x92, 0x4a, 0xd2, 0x05, 0xad, 0x57, 0xaf, 0x56, 0x12, 0x0b, 0xaa, 0x90, ++0x04, 0x14, 0x74, 0x80, 0xf0, 0xe4, 0x90, 0x70, 0x13, 0xf0, 0xe5, 0x56, 0xf4, 0x60, 0x07, 0x90, ++0x70, 0x25, 0xe0, 0x44, 0x01, 0xf0, 0x22, 0x22, 0xe5, 0x53, 0x70, 0x1a, 0x30, 0x60, 0x09, 0xb2, ++0x4d, 0x30, 0x4d, 0x04, 0x05, 0x46, 0xc2, 0x04, 0xe5, 0x4f, 0x45, 0x4e, 0x60, 0x08, 0xe5, 0x4f, ++0x15, 0x4f, 0x70, 0x02, 0x15, 0x4e, 0x22, 0x22, 0xc2, 0x42, 0xd3, 0x22, 0x22, 0xc2, 0x4b, 0xc2, ++0x4c, 0xe5, 0x44, 0x12, 0x0a, 0xb6, 0x12, 0xaf, 0x00, 0x13, 0x42, 0x04, 0x13, 0x3e, 0x08, 0x13, ++0x19, 0x10, 0x12, 0xc3, 0x20, 0x12, 0xe3, 0x60, 0x12, 0xf4, 0xa0, 0x00, 0x00, 0x13, 0x44, 0x85, ++0x48, 0x43, 0x85, 0x4a, 0x42, 0x85, 0x4c, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x60, 0x03, 0x02, 0x13, ++0x44, 0x80, 0x1b, 0xe5, 0x48, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4a, 0xc4, 0x54, 0x0f, 0xf5, ++0x42, 0xe5, 0x4c, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x66, 0x53, 0x43, ++0x0f, 0x80, 0x61, 0x85, 0x49, 0x43, 0x85, 0x4b, 0x42, 0x85, 0x4d, 0x5e, 0xe5, 0x47, 0x64, 0x06, ++0x70, 0x52, 0x80, 0x1b, 0xe5, 0x49, 0xc4, 0x54, 0x0f, 0xf5, 0x43, 0xe5, 0x4b, 0xc4, 0x54, 0x0f, ++0xf5, 0x42, 0xe5, 0x4d, 0xc4, 0x54, 0x0f, 0xf5, 0x5e, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x35, 0xe5, ++0x43, 0x54, 0x0f, 0x44, 0x10, 0xf5, 0x43, 0x80, 0x2b, 0xe5, 0x47, 0xb4, 0x04, 0x06, 0x53, 0x5e, ++0xfb, 0x75, 0x42, 0x09, 0xe5, 0x47, 0xb4, 0x05, 0x06, 0x43, 0x5e, 0x04, 0x75, 0x42, 0x09, 0xe5, ++0x47, 0xb4, 0x06, 0x10, 0xe5, 0x43, 0x54, 0x0f, 0x44, 0x30, 0xf5, 0x43, 0x80, 0x06, 0xd2, 0x4b, ++0x80, 0x02, 0xd2, 0x4c, 0xe4, 0xf5, 0x25, 0xe5, 0x42, 0xc4, 0x54, 0xf0, 0xff, 0xe5, 0x43, 0x54, ++0x0f, 0x4f, 0xf5, 0x5f, 0x90, 0x70, 0x44, 0xf0, 0xa3, 0xe5, 0x5e, 0xf0, 0xa3, 0xe5, 0x4a, 0xf0, ++0xa3, 0xe5, 0x48, 0xf0, 0xa3, 0xe5, 0x4c, 0xf0, 0xa3, 0xe5, 0x44, 0xf0, 0xa3, 0xe5, 0x42, 0xf0, ++0xa3, 0xe5, 0x43, 0xf0, 0xd2, 0x60, 0x22, 0xe5, 0x47, 0x60, 0x10, 0x24, 0xc0, 0x70, 0x03, 0x12, ++0x16, 0x29, 0x12, 0x13, 0x8c, 0xc2, 0xaf, 0xc2, 0x04, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x90, 0x04, ++0x14, 0xe0, 0x54, 0x0e, 0x60, 0x04, 0xd2, 0x18, 0x80, 0x08, 0xe5, 0x4e, 0x45, 0x4f, 0x24, 0xff, ++0x92, 0x18, 0xd2, 0xaf, 0x90, 0x04, 0x14, 0xe0, 0xa2, 0xe4, 0x92, 0x19, 0x74, 0x1e, 0xf0, 0xe5, ++0x5f, 0x54, 0x0f, 0xf5, 0x2d, 0xe5, 0x25, 0x70, 0x13, 0x30, 0x18, 0x05, 0xe5, 0x5f, 0x20, 0xe5, ++0x0b, 0x30, 0x19, 0x19, 0xe5, 0x5f, 0x54, 0x30, 0xff, 0xbf, 0x30, 0x11, 0xe5, 0x25, 0x70, 0x05, ++0x75, 0x25, 0x0c, 0x80, 0x02, 0x15, 0x25, 0xd2, 0x6c, 0xd2, 0x6d, 0x80, 0x0f, 0xe5, 0x5f, 0x30, ++0xe6, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x04, 0xd2, 0x6c, 0xc2, 0x6d, 0xe5, 0x47, 0x64, 0x03, ++0x70, 0x21, 0x30, 0x4b, 0x06, 0xc2, 0x6c, 0xd2, 0x6d, 0x80, 0x18, 0xe5, 0x25, 0x70, 0x03, 0x30, ++0x4c, 0x11, 0xc2, 0x4c, 0xe5, 0x25, 0x70, 0x05, 0x75, 0x25, 0x07, 0x80, 0x02, 0x15, 0x25, 0xd2, ++0x6c, 0xd2, 0x6d, 0xe5, 0x47, 0xb4, 0x09, 0x14, 0xe5, 0x44, 0x20, 0xe3, 0x0b, 0xe5, 0x3a, 0x64, ++0x02, 0x60, 0x05, 0xe5, 0x3a, 0xb4, 0x03, 0x04, 0xc2, 0x6c, 0xd2, 0x6d, 0x90, 0x70, 0x46, 0xe5, ++0x2d, 0xf0, 0x20, 0x69, 0x07, 0xe5, 0x5e, 0x20, 0xe0, 0x02, 0xb2, 0x68, 0x20, 0x6b, 0x07, 0xe5, ++0x5e, 0x20, 0xe1, 0x02, 0xb2, 0x6a, 0x20, 0x6d, 0x07, 0xe5, 0x5e, 0x20, 0xe2, 0x02, 0xb2, 0x6c, ++0x90, 0x70, 0x47, 0xe5, 0x2d, 0xf0, 0x75, 0x2e, 0x40, 0x20, 0x69, 0x04, 0xa2, 0x68, 0x80, 0x26, ++0x30, 0x68, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe2, 0x04, 0x7f, 0x01, ++0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, 0x02, ++0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x73, 0x92, 0x72, 0x20, 0x6b, 0x04, 0xa2, 0x6a, 0x80, ++0x26, 0x30, 0x6a, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe0, 0x04, 0x7f, ++0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, 0x80, ++0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x75, 0x92, 0x74, 0x20, 0x6d, 0x04, 0xa2, 0x6c, ++0x80, 0x26, 0x30, 0x6c, 0x06, 0xe5, 0x46, 0xa2, 0xe2, 0x80, 0x1d, 0xe5, 0x5e, 0x20, 0xe1, 0x04, ++0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xe5, 0x46, 0x54, 0xf0, 0xfe, 0xbe, 0xf0, 0x04, 0x7e, 0x01, ++0x80, 0x02, 0x7e, 0x00, 0xee, 0x6f, 0x24, 0xff, 0x92, 0x71, 0x92, 0x70, 0x90, 0x10, 0x00, 0xe0, ++0x90, 0x10, 0x2f, 0xf0, 0x90, 0x10, 0x03, 0xe0, 0xc3, 0x94, 0x30, 0x40, 0x14, 0xa2, 0x71, 0x92, ++0x77, 0xa2, 0x70, 0x92, 0x76, 0xe5, 0x2e, 0x13, 0x13, 0x54, 0x3f, 0xf5, 0x2e, 0xc2, 0x77, 0xd2, ++0x76, 0x90, 0x10, 0x2f, 0xe5, 0x2e, 0xf0, 0xe5, 0x47, 0x64, 0x06, 0x70, 0x4c, 0x90, 0x02, 0x29, ++0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x43, 0xc4, 0x54, 0x0f, 0x14, 0x60, 0x14, 0x24, 0xfe, 0x60, 0x23, ++0x24, 0x03, 0x60, 0x03, 0x02, 0x16, 0x18, 0x90, 0x02, 0x28, 0xe0, 0x30, 0x47, 0x0f, 0x80, 0x07, ++0x90, 0x02, 0x28, 0xe0, 0x20, 0x47, 0x06, 0x54, 0xfe, 0xf0, 0x02, 0x16, 0x18, 0x44, 0x01, 0xf0, ++0x02, 0x16, 0x18, 0xe5, 0x46, 0x30, 0xe2, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x02, ++0x28, 0xe0, 0x54, 0xfe, 0x4f, 0xf0, 0x02, 0x16, 0x18, 0xe5, 0x47, 0x64, 0x07, 0x60, 0x0f, 0xe5, ++0x47, 0x64, 0x08, 0x60, 0x09, 0xe5, 0x47, 0x64, 0x09, 0x60, 0x03, 0x02, 0x16, 0x18, 0xe4, 0xf5, ++0x27, 0x90, 0x02, 0x29, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x3a, 0x14, 0x60, 0x2d, 0x14, 0x60, 0x2e, ++0x14, 0x60, 0x36, 0x24, 0xfc, 0x60, 0x5f, 0x24, 0xf9, 0x60, 0x1f, 0x24, 0x0e, 0x70, 0x69, 0xe5, ++0x46, 0x13, 0x13, 0x54, 0x3f, 0x75, 0xf0, 0x03, 0x84, 0xaf, 0xf0, 0x20, 0x47, 0x04, 0x7e, 0x01, ++0x80, 0x02, 0x7e, 0x00, 0xef, 0x6e, 0x24, 0xff, 0x80, 0x45, 0xa2, 0x47, 0x80, 0x41, 0xe5, 0x46, ++0x30, 0xe2, 0x03, 0xd3, 0x80, 0x27, 0xc3, 0x80, 0x24, 0xe5, 0x46, 0x30, 0xe2, 0x0d, 0x54, 0x38, ++0xc3, 0x94, 0x30, 0x50, 0x06, 0x7e, 0x00, 0x7f, 0x01, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x20, ++0x47, 0x04, 0x7d, 0x01, 0x80, 0x02, 0x7d, 0x00, 0xef, 0x6d, 0x4e, 0x24, 0xff, 0x92, 0x38, 0xa2, ++0x47, 0xb3, 0x92, 0x39, 0x80, 0x19, 0xe5, 0x46, 0x30, 0xe2, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, ++0x39, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x80, 0x07, 0xa2, 0x47, 0xb3, 0x92, 0x38, 0x92, 0x39, 0x90, ++0x02, 0x28, 0xe0, 0x54, 0xfc, 0x45, 0x27, 0xf0, 0x90, 0x70, 0x9c, 0xe5, 0x3a, 0xf0, 0xa3, 0xe5, ++0x47, 0xf0, 0x90, 0x70, 0x41, 0xe5, 0x3a, 0xf0, 0x22, 0xe4, 0x90, 0x02, 0x29, 0xf0, 0x30, 0x47, ++0x04, 0xaf, 0x45, 0x80, 0x04, 0xe5, 0x45, 0xf4, 0xff, 0x90, 0x02, 0x28, 0xef, 0xf0, 0x22, 0x8f, ++0x50, 0xd2, 0x59, 0x22, 0x8f, 0x54, 0xd2, 0x58, 0x22, 0xe4, 0xf5, 0x62, 0xc2, 0xaf, 0xe5, 0x51, ++0x14, 0x60, 0x46, 0x14, 0x60, 0x62, 0x24, 0x02, 0x60, 0x03, 0x02, 0x17, 0x03, 0xd2, 0x59, 0x75, ++0x55, 0x01, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0x7f, 0xf0, 0xa3, 0xe0, 0x20, 0xe7, 0x22, 0x90, 0x04, ++0x34, 0xe0, 0xb4, 0x02, 0x1b, 0xa3, 0xe0, 0xb4, 0x02, 0x16, 0xa3, 0xe0, 0xb4, 0x02, 0x11, 0x7f, ++0x20, 0x12, 0x16, 0x3f, 0x90, 0x10, 0x04, 0xe0, 0x54, 0xf3, 0xf0, 0x75, 0x51, 0x01, 0x80, 0x73, ++0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, 0x03, 0x80, 0x6a, 0x90, 0x12, 0x00, 0xe0, 0x54, 0x03, 0x70, ++0x11, 0x7f, 0x20, 0x12, 0x16, 0x3f, 0x90, 0x02, 0xa2, 0xe0, 0x54, 0xbf, 0xf0, 0x75, 0x51, 0x02, ++0x80, 0x51, 0xe5, 0x50, 0x70, 0x02, 0x80, 0x46, 0x90, 0x02, 0xa3, 0xe0, 0x20, 0xe6, 0x3b, 0x90, ++0x04, 0x37, 0xe0, 0x64, 0x22, 0x70, 0x33, 0x90, 0x01, 0x8a, 0x74, 0x7e, 0xf0, 0x90, 0x01, 0x96, ++0xf0, 0x90, 0x12, 0x04, 0x74, 0x0a, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x54, 0xf0, 0xf0, 0xa3, 0xe0, ++0x54, 0xf0, 0xf0, 0xa3, 0xe0, 0x54, 0xfa, 0xf0, 0x90, 0x04, 0x01, 0xe0, 0x54, 0xf9, 0xf0, 0x75, ++0x62, 0x01, 0x75, 0x55, 0x02, 0xe4, 0xf5, 0x51, 0x80, 0x09, 0xe5, 0x50, 0x70, 0x05, 0x75, 0x62, ++0x03, 0xf5, 0x51, 0xe5, 0x62, 0x60, 0x15, 0xc2, 0x01, 0xe4, 0xf5, 0x51, 0xc2, 0x59, 0xad, 0x62, ++0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x62, 0xb4, 0x03, 0x02, 0xd2, 0x03, 0xd2, 0xaf, 0x22, 0xc2, ++0xaf, 0x30, 0x01, 0x12, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xf5, 0x51, 0xc2, 0x59, 0xc2, 0x01, 0x7d, ++0x02, 0xaf, 0x40, 0x12, 0x17, 0x8d, 0xe5, 0x52, 0x14, 0x60, 0x09, 0x04, 0x70, 0x4c, 0x75, 0x52, ++0x01, 0x75, 0x55, 0x03, 0x90, 0x04, 0x01, 0xe0, 0x44, 0x0e, 0xf0, 0x90, 0x13, 0x28, 0xe0, 0x44, ++0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x0f, 0xf0, 0xa3, 0xe0, 0x44, 0x05, 0xf0, 0x90, 0x12, 0x04, 0x74, ++0x03, 0xf0, 0x90, 0x02, 0xa2, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x10, 0x04, 0xe0, 0x44, 0x0c, 0xf0, ++0xe4, 0xf5, 0x52, 0xf5, 0x55, 0x30, 0x02, 0x0b, 0xc2, 0x02, 0x7d, 0x01, 0xaf, 0x41, 0x12, 0x17, ++0x8d, 0x80, 0x02, 0xc2, 0x03, 0xe4, 0x90, 0x01, 0x96, 0xf0, 0xd2, 0xaf, 0x22, 0xef, 0xf4, 0x60, ++0x2d, 0xe4, 0xfe, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xe0, 0xb4, 0xff, ++0x19, 0x74, 0x14, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xef, 0xf0, 0x74, 0x1c, 0x2e, ++0xf5, 0x82, 0xe4, 0x34, 0x70, 0xf5, 0x83, 0xed, 0xf0, 0x22, 0x0e, 0xbe, 0x04, 0xd5, 0x22, 0x22, ++0x22, 0x90, 0x70, 0x2a, 0xe0, 0x30, 0xe1, 0x4d, 0xc2, 0xaf, 0x90, 0x70, 0x28, 0xe0, 0x90, 0x10, ++0x1c, 0xf0, 0x90, 0x70, 0x29, 0xe0, 0x90, 0x10, 0x1d, 0xf0, 0x90, 0x70, 0x2a, 0xe0, 0x90, 0x10, ++0x1e, 0xf0, 0x90, 0x10, 0x1c, 0xe0, 0xf5, 0x62, 0x90, 0x10, 0x1e, 0xe0, 0x20, 0xe1, 0xf3, 0x90, ++0x10, 0x1c, 0xe0, 0x90, 0x70, 0x28, 0xf0, 0x90, 0x10, 0x1d, 0xe0, 0x90, 0x70, 0x29, 0xf0, 0x90, ++0x10, 0x1e, 0xe0, 0x90, 0x70, 0x2a, 0xf0, 0x30, 0x4a, 0x07, 0x90, 0x70, 0x24, 0xe0, 0x44, 0x01, ++0xf0, 0xc2, 0x05, 0xd2, 0xaf, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9b, 0xc0, } ; +--- /dev/null ++++ b/drivers/staging/rt3070/Kconfig +@@ -0,0 +1,6 @@ ++config RT3070 ++ tristate "Ralink 3070 wireless support" ++ depends on USB && X86 && WLAN_80211 ++ ---help--- ++ This is an experimental driver for the Ralink 3070 wireless chip. ++ +--- /dev/null ++++ b/drivers/staging/rt3070/leap.h +@@ -0,0 +1,215 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ leap.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef __LEAP_H__ ++#define __LEAP_H__ ++ ++// Messages for Associate state machine ++#define LEAP_MACHINE_BASE 30 ++ ++#define LEAP_MSG_REQUEST_IDENTITY 31 ++#define LEAP_MSG_REQUEST_LEAP 32 ++#define LEAP_MSG_SUCCESS 33 ++#define LEAP_MSG_FAILED 34 ++#define LEAP_MSG_RESPONSE_LEAP 35 ++#define LEAP_MSG_EAPOLKEY 36 ++#define LEAP_MSG_UNKNOWN 37 ++#define LEAP_MSG 38 ++//! assoc state-machine states ++#define LEAP_IDLE 0 ++#define LEAP_WAIT_IDENTITY_REQUEST 1 ++#define LEAP_WAIT_CHANLLENGE_REQUEST 2 ++#define LEAP_WAIT_SUCCESS 3 ++#define LEAP_WAIT_CHANLLENGE_RESPONSE 4 ++#define LEAP_WAIT_EAPOLKEY 5 ++ ++#define LEAP_REASON_INVALID_AUTH 0x01 ++#define LEAP_REASON_AUTH_TIMEOUT 0x02 ++#define LEAP_REASON_CHALLENGE_FROM_AP_FAILED 0x03 ++#define LEAP_REASON_CHALLENGE_TO_AP_FAILED 0x04 ++ ++#define CISCO_AuthModeLEAP 0x80 ++#define CISCO_AuthModeLEAPNone 0x00 ++#define LEAP_AUTH_TIMEOUT 30000 ++#define LEAP_CHALLENGE_RESPONSE_LENGTH 24 ++#define LEAP_CHALLENGE_REQUEST_LENGTH 8 ++ ++typedef struct _LEAP_EAPOL_HEADER_ { ++ UCHAR Version; ++ UCHAR Type; ++ UCHAR Length[2]; ++} LEAP_EAPOL_HEADER, *PLEAP_EAPOL_HEADER; ++ ++typedef struct _LEAP_EAPOL_PACKET_ { ++ UCHAR Code; ++ UCHAR Identifier; ++ UCHAR Length[2]; ++ UCHAR Type; ++} LEAP_EAPOL_PACKET, *PLEAP_EAPOL_PACKET; ++ ++typedef struct _LEAP_EAP_CONTENTS_ { ++ UCHAR Version; ++ UCHAR Reserved; ++ UCHAR Length; ++} LEAP_EAP_CONTENTS, *PLEAP_EAP_CONTENTS; ++ ++/*** EAPOL key ***/ ++typedef struct _EAPOL_KEY_HEADER_ { ++ UCHAR Type; ++ UCHAR Length[2]; ++ UCHAR Counter[8]; ++ UCHAR IV[16]; ++ UCHAR Index; ++ UCHAR Signature[16]; ++} EAPOL_KEY_HEADER, *PEAPOL_KEY_HEADER; ++ ++BOOLEAN LeapMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT ULONG *MsgType); ++ ++VOID LeapMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr3); ++ ++VOID LeapStartAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapIdentityAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapPeerChallengeAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HashPwd( ++ IN PUCHAR pwd, ++ IN INT pwdlen, ++ OUT PUCHAR hash); ++ ++VOID PeerChallengeResponse( ++ IN PUCHAR szChallenge, ++ IN PUCHAR smbPasswd, ++ OUT PUCHAR szResponse); ++ ++VOID ParityKey( ++ OUT PUCHAR szOut, ++ IN PUCHAR szIn); ++ ++VOID DesKey( ++ OUT ULONG k[16][2], ++ IN PUCHAR key, ++ IN INT decrypt); ++ ++VOID Des( ++ IN ULONG ks[16][2], ++ OUT UCHAR block[8]); ++ ++VOID DesEncrypt( ++ IN PUCHAR szClear, ++ IN PUCHAR szKey, ++ OUT PUCHAR szOut); ++ ++VOID LeapNetworkChallengeAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID LeapNetworkChallengeResponse( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HashpwdHash( ++ IN PUCHAR hash, ++ IN PUCHAR hashhash); ++ ++VOID ProcessSessionKey( ++ OUT PUCHAR SessionKey, ++ IN PUCHAR hash2, ++ IN PUCHAR ChallengeToRadius, ++ IN PUCHAR ChallengeResponseFromRadius, ++ IN PUCHAR ChallengeFromRadius, ++ IN PUCHAR ChallengeResponseToRadius); ++ ++VOID LeapEapolKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID RogueApTableInit( ++ IN ROGUEAP_TABLE *Tab); ++ ++ULONG RogueApTableSearch( ++ IN ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr); ++ ++VOID RogueApEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT ROGUEAP_ENTRY *pRogueAp, ++ IN PUCHAR pAddr, ++ IN UCHAR FaileCode); ++ ++ULONG RogueApTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr, ++ IN UCHAR FaileCode); ++ ++VOID RogueApTableDeleteEntry( ++ IN OUT ROGUEAP_TABLE *Tab, ++ IN PUCHAR pAddr); ++ ++VOID LeapAuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LeapSendRogueAPReport( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN CCKMAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen); ++ ++#endif // __LEAP_H__ +--- /dev/null ++++ b/drivers/staging/rt3070/link_list.h +@@ -0,0 +1,134 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __LINK_LIST_H__ ++#define __LINK_LIST_H__ ++ ++typedef struct _LIST_ENTRY ++{ ++ struct _LIST_ENTRY *pNext; ++} LIST_ENTRY, *PLIST_ENTRY; ++ ++typedef struct _LIST_HEADR ++{ ++ PLIST_ENTRY pHead; ++ PLIST_ENTRY pTail; ++ UCHAR size; ++} LIST_HEADER, *PLIST_HEADER; ++ ++static inline VOID initList( ++ IN PLIST_HEADER pList) ++{ ++ pList->pHead = pList->pTail = NULL; ++ pList->size = 0; ++ return; ++} ++ ++static inline VOID insertTailList( ++ IN PLIST_HEADER pList, ++ IN PLIST_ENTRY pEntry) ++{ ++ pEntry->pNext = NULL; ++ if (pList->pTail) ++ pList->pTail->pNext = pEntry; ++ else ++ pList->pHead = pEntry; ++ pList->pTail = pEntry; ++ pList->size++; ++ ++ return; ++} ++ ++static inline PLIST_ENTRY removeHeadList( ++ IN PLIST_HEADER pList) ++{ ++ PLIST_ENTRY pNext; ++ PLIST_ENTRY pEntry; ++ ++ pEntry = pList->pHead; ++ if (pList->pHead != NULL) ++ { ++ pNext = pList->pHead->pNext; ++ pList->pHead = pNext; ++ if (pNext == NULL) ++ pList->pTail = NULL; ++ pList->size--; ++ } ++ return pEntry; ++} ++ ++static inline int getListSize( ++ IN PLIST_HEADER pList) ++{ ++ return pList->size; ++} ++ ++static inline PLIST_ENTRY delEntryList( ++ IN PLIST_HEADER pList, ++ IN PLIST_ENTRY pEntry) ++{ ++ PLIST_ENTRY pCurEntry; ++ PLIST_ENTRY pPrvEntry; ++ ++ if(pList->pHead == NULL) ++ return NULL; ++ ++ if(pEntry == pList->pHead) ++ { ++ pCurEntry = pList->pHead; ++ pList->pHead = pCurEntry->pNext; ++ ++ if(pList->pHead == NULL) ++ pList->pTail = NULL; ++ ++ pList->size--; ++ return pCurEntry; ++ } ++ ++ pPrvEntry = pList->pHead; ++ pCurEntry = pPrvEntry->pNext; ++ while(pCurEntry != NULL) ++ { ++ if (pEntry == pCurEntry) ++ { ++ pPrvEntry->pNext = pCurEntry->pNext; ++ ++ if(pEntry == pList->pTail) ++ pList->pTail = pPrvEntry; ++ ++ pList->size--; ++ break; ++ } ++ pPrvEntry = pCurEntry; ++ pCurEntry = pPrvEntry->pNext; ++ } ++ ++ return pCurEntry; ++} ++ ++#endif // ___LINK_LIST_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/Makefile +@@ -0,0 +1,47 @@ ++obj-$(CONFIG_RT3070) += rt3070sta.o ++ ++# TODO: all of these should be removed ++EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT ++EXTRA_CFLAGS += -DRT2870 -DRT30xx -DRT3070 ++EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT ++EXTRA_CFLAGS += -DDBG ++EXTRA_CFLAGS += -DDOT11_N_SUPPORT ++EXTRA_CFLAGS += -DWPA_SUPPLICANT_SUPPORT ++EXTRA_CFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT ++ ++rt3070sta-objs := \ ++ common/md5.o \ ++ common/mlme.o \ ++ common/rtmp_wep.o \ ++ common/action.o \ ++ common/cmm_data.o \ ++ common/rtmp_init.o \ ++ common/rtmp_tkip.o \ ++ common/cmm_sync.o \ ++ common/eeprom.o \ ++ common/cmm_sanity.o \ ++ common/cmm_info.o \ ++ common/cmm_wpa.o \ ++ common/dfs.o \ ++ common/spectrum.o \ ++ sta/assoc.o \ ++ sta/aironet.o \ ++ sta/auth.o \ ++ sta/auth_rsp.o \ ++ sta/sync.o \ ++ sta/sanity.o \ ++ sta/rtmp_data.o \ ++ sta/connect.o \ ++ sta/wpa.o \ ++ rt_linux.o \ ++ rt_profile.o \ ++ rt_main_dev.o \ ++ sta_ioctl.o \ ++ common/ba_action.o \ ++ 2870_main_dev.o \ ++ common/2870_rtmp_init.o \ ++ common/rtusb_io.o \ ++ common/rtusb_bulk.o \ ++ common/rtusb_data.o \ ++ common/cmm_data_2870.o ++ +--- /dev/null ++++ b/drivers/staging/rt3070/md4.h +@@ -0,0 +1,42 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __MD4_H__ ++#define __MD4_H__ ++ ++/* MD4 context. */ ++typedef struct _MD4_CTX_ { ++ ULONG state[4]; /* state (ABCD) */ ++ ULONG count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ UCHAR buffer[64]; /* input buffer */ ++} MD4_CTX; ++ ++VOID MD4Init (MD4_CTX *); ++VOID MD4Update (MD4_CTX *, PUCHAR, UINT); ++VOID MD4Final (UCHAR [16], MD4_CTX *); ++ ++#endif //__MD4_H__ +\ No newline at end of file +--- /dev/null ++++ b/drivers/staging/rt3070/md5.h +@@ -0,0 +1,107 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ md5.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ jan 10-28-03 Initial ++ Rita 11-23-04 Modify MD5 and SHA-1 ++*/ ++ ++#ifndef uint8 ++#define uint8 unsigned char ++#endif ++ ++#ifndef uint32 ++#define uint32 unsigned long int ++#endif ++ ++ ++#ifndef __MD5_H__ ++#define __MD5_H__ ++ ++#define MD5_MAC_LEN 16 ++ ++typedef struct _MD5_CTX { ++ UINT32 Buf[4]; // buffers of four states ++ UCHAR Input[64]; // input message ++ UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits ++} MD5_CTX; ++ ++VOID MD5Init(MD5_CTX *pCtx); ++VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); ++VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx); ++VOID MD5Transform(UINT32 Buf[4], UINT32 Mes[16]); ++ ++void md5_mac(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); ++void hmac_md5(u8 *key, size_t key_len, u8 *data, size_t data_len, u8 *mac); ++ ++// ++// SHA context ++// ++typedef struct _SHA_CTX ++{ ++ UINT32 Buf[5]; // buffers of five states ++ UCHAR Input[80]; // input message ++ UINT32 LenInBitCount[2]; // length counter for input message, 0 up to 64 bits ++ ++} SHA_CTX; ++ ++VOID SHAInit(SHA_CTX *pCtx); ++UCHAR SHAUpdate(SHA_CTX *pCtx, UCHAR *pData, UINT32 LenInBytes); ++VOID SHAFinal(SHA_CTX *pCtx, UCHAR Digest[20]); ++VOID SHATransform(UINT32 Buf[5], UINT32 Mes[20]); ++ ++#define SHA_DIGEST_LEN 20 ++#endif // __MD5_H__ ++ ++/******************************************************************************/ ++#ifndef _AES_H ++#define _AES_H ++ ++typedef struct ++{ ++ uint32 erk[64]; /* encryption round keys */ ++ uint32 drk[64]; /* decryption round keys */ ++ int nr; /* number of rounds */ ++} ++aes_context; ++ ++int rtmp_aes_set_key( aes_context *ctx, uint8 *key, int nbits ); ++void rtmp_aes_encrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); ++void rtmp_aes_decrypt( aes_context *ctx, uint8 input[16], uint8 output[16] ); ++ ++void F(char *password, unsigned char *ssid, int ssidlength, int iterations, int count, unsigned char *output); ++int PasswordHash(char *password, unsigned char *ssid, int ssidlength, unsigned char *output); ++ ++#endif /* aes.h */ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/mlme.h +@@ -0,0 +1,1468 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ mlme.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2003-08-28 Created ++ John Chang 2004-09-06 modified for RT2600 ++ ++*/ ++#ifndef __MLME_H__ ++#define __MLME_H__ ++ ++//extern UCHAR BROADCAST_ADDR[]; ++ ++// maximum supported capability information - ++// ESS, IBSS, Privacy, Short Preamble, Spectrum mgmt, Short Slot ++#define SUPPORTED_CAPABILITY_INFO 0x0533 ++ ++#define END_OF_ARGS -1 ++#define LFSR_MASK 0x80000057 ++#define MLME_TASK_EXEC_INTV 100/*200*/ // ++#define LEAD_TIME 5 ++#define MLME_TASK_EXEC_MULTIPLE 10 /*5*/ // MLME_TASK_EXEC_MULTIPLE * MLME_TASK_EXEC_INTV = 1 sec ++#define REORDER_EXEC_INTV 100 // 0.1 sec ++//#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps ++ ++// The definition of Radar detection duration region ++#define CE 0 ++#define FCC 1 ++#define JAP 2 ++#define JAP_W53 3 ++#define JAP_W56 4 ++#define MAX_RD_REGION 5 ++ ++#ifdef NDIS51_MINIPORT ++#define BEACON_LOST_TIME 4000 // 2048 msec = 2 sec ++#else ++#define BEACON_LOST_TIME 4 * OS_HZ // 2048 msec = 2 sec ++#endif ++ ++#define DLS_TIMEOUT 1200 // unit: msec ++#define AUTH_TIMEOUT 300 // unit: msec ++#define ASSOC_TIMEOUT 300 // unit: msec ++#define JOIN_TIMEOUT 2 * OS_HZ // unit: msec ++#define SHORT_CHANNEL_TIME 90 // unit: msec ++#define MIN_CHANNEL_TIME 110 // unit: msec, for dual band scan ++#define MAX_CHANNEL_TIME 140 // unit: msec, for single band scan ++#define FAST_ACTIVE_SCAN_TIME 30 // Active scan waiting for probe response time ++#define CW_MIN_IN_BITS 4 // actual CwMin = 2^CW_MIN_IN_BITS - 1 ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifndef CONFIG_AP_SUPPORT ++#define CW_MAX_IN_BITS 10 // actual CwMax = 2^CW_MAX_IN_BITS - 1 ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++extern UINT32 CW_MAX_IN_BITS; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++// Note: RSSI_TO_DBM_OFFSET has been changed to variable for new RF (2004-0720). ++// SHould not refer to this constant anymore ++//#define RSSI_TO_DBM_OFFSET 120 // for RT2530 RSSI-115 = dBm ++#define RSSI_FOR_MID_TX_POWER -55 // -55 db is considered mid-distance ++#define RSSI_FOR_LOW_TX_POWER -45 // -45 db is considered very short distance and ++ // eligible to use a lower TX power ++#define RSSI_FOR_LOWEST_TX_POWER -30 ++//#define MID_TX_POWER_DELTA 0 // 0 db from full TX power upon mid-distance to AP ++#define LOW_TX_POWER_DELTA 6 // -3 db from full TX power upon very short distance. 1 grade is 0.5 db ++#define LOWEST_TX_POWER_DELTA 16 // -8 db from full TX power upon shortest distance. 1 grade is 0.5 db ++ ++#define RSSI_TRIGGERED_UPON_BELOW_THRESHOLD 0 ++#define RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD 1 ++#define RSSI_THRESHOLD_FOR_ROAMING 25 ++#define RSSI_DELTA 5 ++ ++// Channel Quality Indication ++#define CQI_IS_GOOD(cqi) ((cqi) >= 50) ++//#define CQI_IS_FAIR(cqi) (((cqi) >= 20) && ((cqi) < 50)) ++#define CQI_IS_POOR(cqi) (cqi < 50) //(((cqi) >= 5) && ((cqi) < 20)) ++#define CQI_IS_BAD(cqi) (cqi < 5) ++#define CQI_IS_DEAD(cqi) (cqi == 0) ++ ++// weighting factor to calculate Channel quality, total should be 100% ++#define RSSI_WEIGHTING 50 ++#define TX_WEIGHTING 30 ++#define RX_WEIGHTING 20 ++ ++//#define PEER_KEY_NOT_USED 0 ++//#define PEER_KEY_64_BIT 64 ++//#define PEER_KEY_128_BIT 128 ++ ++//#define PEER_KEY_64BIT_LEN 8 ++//#define PEER_KEY_128BIT_LEN 16 ++ ++#define BSS_NOT_FOUND 0xFFFFFFFF ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define MAX_LEN_OF_MLME_QUEUE 40 //10 ++#endif // CONFIG_STA_SUPPORT // ++ ++#define SCAN_PASSIVE 18 // scan with no probe request, only wait beacon and probe response ++#define SCAN_ACTIVE 19 // scan with probe request, and wait beacon and probe response ++#define SCAN_CISCO_PASSIVE 20 // Single channel passive scan ++#define SCAN_CISCO_ACTIVE 21 // Single channel active scan ++#define SCAN_CISCO_NOISE 22 // Single channel passive scan for noise histogram collection ++#define SCAN_CISCO_CHANNEL_LOAD 23 // Single channel passive scan for channel load collection ++#define FAST_SCAN_ACTIVE 24 // scan with probe request, and wait beacon and probe response ++ ++#ifdef DOT11N_DRAFT3 ++#define SCAN_2040_BSS_COEXIST 26 ++#endif // DOT11N_DRAFT3 // ++ ++//#define BSS_TABLE_EMPTY(x) ((x).BssNr == 0) ++#define MAC_ADDR_IS_GROUP(Addr) (((Addr[0]) & 0x01)) ++#define MAC_ADDR_HASH(Addr) (Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) ++#define MAC_ADDR_HASH_INDEX(Addr) (MAC_ADDR_HASH(Addr) % HASH_TABLE_SIZE) ++#define TID_MAC_HASH(Addr,TID) (TID^Addr[0] ^ Addr[1] ^ Addr[2] ^ Addr[3] ^ Addr[4] ^ Addr[5]) ++#define TID_MAC_HASH_INDEX(Addr,TID) (TID_MAC_HASH(Addr,TID) % HASH_TABLE_SIZE) ++ ++// LED Control ++// assoiation ON. one LED ON. another blinking when TX, OFF when idle ++// no association, both LED off ++#define ASIC_LED_ACT_ON(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00031e46) ++#define ASIC_LED_ACT_OFF(pAd) RTMP_IO_WRITE32(pAd, MAC_CSR14, 0x00001e46) ++ ++// bit definition of the 2-byte pBEACON->Capability field ++#define CAP_IS_ESS_ON(x) (((x) & 0x0001) != 0) ++#define CAP_IS_IBSS_ON(x) (((x) & 0x0002) != 0) ++#define CAP_IS_CF_POLLABLE_ON(x) (((x) & 0x0004) != 0) ++#define CAP_IS_CF_POLL_REQ_ON(x) (((x) & 0x0008) != 0) ++#define CAP_IS_PRIVACY_ON(x) (((x) & 0x0010) != 0) ++#define CAP_IS_SHORT_PREAMBLE_ON(x) (((x) & 0x0020) != 0) ++#define CAP_IS_PBCC_ON(x) (((x) & 0x0040) != 0) ++#define CAP_IS_AGILITY_ON(x) (((x) & 0x0080) != 0) ++#define CAP_IS_SPECTRUM_MGMT(x) (((x) & 0x0100) != 0) // 802.11e d9 ++#define CAP_IS_QOS(x) (((x) & 0x0200) != 0) // 802.11e d9 ++#define CAP_IS_SHORT_SLOT(x) (((x) & 0x0400) != 0) ++#define CAP_IS_APSD(x) (((x) & 0x0800) != 0) // 802.11e d9 ++#define CAP_IS_IMMED_BA(x) (((x) & 0x1000) != 0) // 802.11e d9 ++#define CAP_IS_DSSS_OFDM(x) (((x) & 0x2000) != 0) ++#define CAP_IS_DELAY_BA(x) (((x) & 0x4000) != 0) // 802.11e d9 ++ ++#define CAP_GENERATE(ess,ibss,priv,s_pre,s_slot,spectrum) (((ess) ? 0x0001 : 0x0000) | ((ibss) ? 0x0002 : 0x0000) | ((priv) ? 0x0010 : 0x0000) | ((s_pre) ? 0x0020 : 0x0000) | ((s_slot) ? 0x0400 : 0x0000) | ((spectrum) ? 0x0100 : 0x0000)) ++ ++//#define STA_QOS_CAPABILITY 0 // 1-byte. see 802.11e d9.0 for bit definition ++ ++#define ERP_IS_NON_ERP_PRESENT(x) (((x) & 0x01) != 0) // 802.11g ++#define ERP_IS_USE_PROTECTION(x) (((x) & 0x02) != 0) // 802.11g ++#define ERP_IS_USE_BARKER_PREAMBLE(x) (((x) & 0x04) != 0) // 802.11g ++ ++#define DRS_TX_QUALITY_WORST_BOUND 8// 3 // just test by gary ++#define DRS_PENALTY 8 ++ ++#define BA_NOTUSE 2 ++//BA Policy subfiled value in ADDBA frame ++#define IMMED_BA 1 ++#define DELAY_BA 0 ++ ++// BA Initiator subfield in DELBA frame ++#define ORIGINATOR 1 ++#define RECIPIENT 0 ++ ++// ADDBA Status Code ++#define ADDBA_RESULTCODE_SUCCESS 0 ++#define ADDBA_RESULTCODE_REFUSED 37 ++#define ADDBA_RESULTCODE_INVALID_PARAMETERS 38 ++ ++// DELBA Reason Code ++#define DELBA_REASONCODE_QSTA_LEAVING 36 ++#define DELBA_REASONCODE_END_BA 37 ++#define DELBA_REASONCODE_UNKNOWN_BA 38 ++#define DELBA_REASONCODE_TIMEOUT 39 ++ ++// reset all OneSecTx counters ++#define RESET_ONE_SEC_TX_CNT(__pEntry) \ ++if (((__pEntry)) != NULL) \ ++{ \ ++ (__pEntry)->OneSecTxRetryOkCount = 0; \ ++ (__pEntry)->OneSecTxFailCount = 0; \ ++ (__pEntry)->OneSecTxNoRetryOkCount = 0; \ ++} ++ ++// ++// 802.11 frame formats ++// ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT LSIGTxopProSup:1; ++ USHORT Forty_Mhz_Intolerant:1; ++ USHORT PSMP:1; ++ USHORT CCKmodein40:1; ++ USHORT AMsduSize:1; ++ USHORT DelayedBA:1; //rt2860c not support ++ USHORT RxSTBC:2; ++ USHORT TxSTBC:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT ShortGIfor20:1; ++ USHORT GF:1; //green field ++ USHORT MimoPs:2;//momi power safe ++ USHORT ChannelWidth:1; ++ USHORT AdvCoding:1; ++#else ++ USHORT AdvCoding:1; ++ USHORT ChannelWidth:1; ++ USHORT MimoPs:2;//momi power safe ++ USHORT GF:1; //green field ++ USHORT ShortGIfor20:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT TxSTBC:1; ++ USHORT RxSTBC:2; ++ USHORT DelayedBA:1; //rt2860c not support ++ USHORT AMsduSize:1; // only support as zero ++ USHORT CCKmodein40:1; ++ USHORT PSMP:1; ++ USHORT Forty_Mhz_Intolerant:1; ++ USHORT LSIGTxopProSup:1; ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CAP_INFO, *PHT_CAP_INFO; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:3;//momi power safe ++ UCHAR MpduDensity:3; ++ UCHAR MaxRAmpduFactor:2; ++#else ++ UCHAR MaxRAmpduFactor:2; ++ UCHAR MpduDensity:3; ++ UCHAR rsv:3;//momi power safe ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CAP_PARM, *PHT_CAP_PARM; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++ UCHAR MCSSet[10]; ++ UCHAR SupRate[2]; // unit : 1Mbps ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:3; ++ UCHAR MpduDensity:1; ++ UCHAR TxStream:2; ++ UCHAR TxRxNotEqual:1; ++ UCHAR TxMCSSetDefined:1; ++#else ++ UCHAR TxMCSSetDefined:1; ++ UCHAR TxRxNotEqual:1; ++ UCHAR TxStream:2; ++ UCHAR MpduDensity:1; ++ UCHAR rsv:3; ++#endif // RT_BIG_ENDIAN // ++ UCHAR rsv3[3]; ++} HT_MCS_SET, *PHT_MCS_SET; ++ ++// HT Capability INFO field in HT Cap IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:4; ++ USHORT RDGSupport:1; //reverse Direction Grant support ++ USHORT PlusHTC:1; //+HTC control field support ++ USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. ++ USHORT rsv:5;//momi power safe ++ USHORT TranTime:2; ++ USHORT Pco:1; ++#else ++ USHORT Pco:1; ++ USHORT TranTime:2; ++ USHORT rsv:5;//momi power safe ++ USHORT MCSFeedback:2; //0:no MCS feedback, 2:unsolicited MCS feedback, 3:Full MCS feedback, 1:rsv. ++ USHORT PlusHTC:1; //+HTC control field support ++ USHORT RDGSupport:1; //reverse Direction Grant support ++ USHORT rsv2:4; ++#endif /* RT_BIG_ENDIAN */ ++} EXT_HT_CAP_INFO, *PEXT_HT_CAP_INFO; ++ ++// HT Beamforming field in HT Cap IE . ++typedef struct PACKED _HT_BF_CAP{ ++#ifdef RT_BIG_ENDIAN ++ ULONG rsv:3; ++ ULONG ChanEstimation:2; ++ ULONG CSIRowBFSup:2; ++ ULONG ComSteerBFAntSup:2; ++ ULONG NoComSteerBFAntSup:2; ++ ULONG CSIBFAntSup:2; ++ ULONG MinGrouping:2; ++ ULONG ExpComBF:2; ++ ULONG ExpNoComBF:2; ++ ULONG ExpCSIFbk:2; ++ ULONG ExpComSteerCapable:1; ++ ULONG ExpNoComSteerCapable:1; ++ ULONG ExpCSICapable:1; ++ ULONG Calibration:2; ++ ULONG ImpTxBFCapable:1; ++ ULONG TxNDPCapable:1; ++ ULONG RxNDPCapable:1; ++ ULONG TxSoundCapable:1; ++ ULONG RxSoundCapable:1; ++ ULONG TxBFRecCapable:1; ++#else ++ ULONG TxBFRecCapable:1; ++ ULONG RxSoundCapable:1; ++ ULONG TxSoundCapable:1; ++ ULONG RxNDPCapable:1; ++ ULONG TxNDPCapable:1; ++ ULONG ImpTxBFCapable:1; ++ ULONG Calibration:2; ++ ULONG ExpCSICapable:1; ++ ULONG ExpNoComSteerCapable:1; ++ ULONG ExpComSteerCapable:1; ++ ULONG ExpCSIFbk:2; ++ ULONG ExpNoComBF:2; ++ ULONG ExpComBF:2; ++ ULONG MinGrouping:2; ++ ULONG CSIBFAntSup:2; ++ ULONG NoComSteerBFAntSup:2; ++ ULONG ComSteerBFAntSup:2; ++ ULONG CSIRowBFSup:2; ++ ULONG ChanEstimation:2; ++ ULONG rsv:3; ++#endif // RT_BIG_ENDIAN // ++} HT_BF_CAP, *PHT_BF_CAP; ++ ++// HT antenna selection field in HT Cap IE . ++typedef struct PACKED _HT_AS_CAP{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv:1; ++ UCHAR TxSoundPPDU:1; ++ UCHAR RxASel:1; ++ UCHAR AntIndFbk:1; ++ UCHAR ExpCSIFbk:1; ++ UCHAR AntIndFbkTxASEL:1; ++ UCHAR ExpCSIFbkTxASEL:1; ++ UCHAR AntSelect:1; ++#else ++ UCHAR AntSelect:1; ++ UCHAR ExpCSIFbkTxASEL:1; ++ UCHAR AntIndFbkTxASEL:1; ++ UCHAR ExpCSIFbk:1; ++ UCHAR AntIndFbk:1; ++ UCHAR RxASel:1; ++ UCHAR TxSoundPPDU:1; ++ UCHAR rsv:1; ++#endif // RT_BIG_ENDIAN // ++} HT_AS_CAP, *PHT_AS_CAP; ++ ++// Draft 1.0 set IE length 26, but is extensible.. ++#define SIZE_HT_CAP_IE 26 ++// The structure for HT Capability IE. ++typedef struct PACKED _HT_CAPABILITY_IE{ ++ HT_CAP_INFO HtCapInfo; ++ HT_CAP_PARM HtCapParm; ++// HT_MCS_SET HtMCSSet; ++ UCHAR MCSSet[16]; ++ EXT_HT_CAP_INFO ExtHtCapInfo; ++ HT_BF_CAP TxBFCap; // beamforming cap. rt2860c not support beamforming. ++ HT_AS_CAP ASCap; //antenna selection. ++} HT_CAPABILITY_IE, *PHT_CAPABILITY_IE; ++ ++ ++// 802.11n draft3 related structure definitions. ++// 7.3.2.60 ++#define dot11OBSSScanPassiveDwell 20 // in TU. min amount of time that the STA continously scans each channel when performing an active OBSS scan. ++#define dot11OBSSScanActiveDwell 10 // in TU.min amount of time that the STA continously scans each channel when performing an passive OBSS scan. ++#define dot11BSSWidthTriggerScanInterval 300 // in sec. max interval between scan operations to be performed to detect BSS channel width trigger events. ++#define dot11OBSSScanPassiveTotalPerChannel 200 // in TU. min total amount of time that the STA scans each channel when performing a passive OBSS scan. ++#define dot11OBSSScanActiveTotalPerChannel 20 //in TU. min total amount of time that the STA scans each channel when performing a active OBSS scan ++#define dot11BSSWidthChannelTransactionDelayFactor 5 // min ratio between the delay time in performing a switch from 20MHz BSS to 20/40 BSS operation and the maxima ++ // interval between overlapping BSS scan operations. ++#define dot11BSSScanActivityThreshold 25 // in %%, max total time that a STA may be active on the medium during a period of ++ // (dot11BSSWidthChannelTransactionDelayFactor * dot11BSSWidthTriggerScanInterval) seconds without ++ // being obligated to perform OBSS Scan operations. default is 25(== 0.25%) ++ ++typedef struct PACKED _OVERLAP_BSS_SCAN_IE{ ++ USHORT ScanPassiveDwell; ++ USHORT ScanActiveDwell; ++ USHORT TriggerScanInt; // Trigger scan interval ++ USHORT PassiveTalPerChannel; // passive total per channel ++ USHORT ActiveTalPerChannel; // active total per channel ++ USHORT DelayFactor; // BSS width channel transition delay factor ++ USHORT ScanActThre; // Scan Activity threshold ++}OVERLAP_BSS_SCAN_IE, *POVERLAP_BSS_SCAN_IE; ++ ++ ++// 7.3.2.56. 20/40 Coexistence element used in Element ID = 72 = IE_2040_BSS_COEXIST ++typedef union PACKED _BSS_2040_COEXIST_IE{ ++ struct PACKED { ++ #ifdef RT_BIG_ENDIAN ++ UCHAR rsv:5; ++ UCHAR BSS20WidthReq:1; ++ UCHAR Intolerant40:1; ++ UCHAR InfoReq:1; ++ #else ++ UCHAR InfoReq:1; ++ UCHAR Intolerant40:1; // Inter-BSS. set 1 when prohibits a receiving BSS from operating as a 20/40 Mhz BSS. ++ UCHAR BSS20WidthReq:1; // Intra-BSS set 1 when prohibits a receiving AP from operating its BSS as a 20/40MHz BSS. ++ UCHAR rsv:5; ++#endif // RT_BIG_ENDIAN // ++ } field; ++ UCHAR word; ++} BSS_2040_COEXIST_IE, *PBSS_2040_COEXIST_IE; ++ ++ ++typedef struct _TRIGGER_EVENTA{ ++ BOOLEAN bValid; ++ UCHAR BSSID[6]; ++ UCHAR RegClass; // Regulatory Class ++ USHORT Channel; ++ ULONG CDCounter; // Maintain a seperate count down counter for each Event A. ++} TRIGGER_EVENTA, *PTRIGGER_EVENTA; ++ ++// 20/40 trigger event table ++// If one Event A delete or created, or if Event B is detected or not detected, STA should send 2040BSSCoexistence to AP. ++#define MAX_TRIGGER_EVENT 64 ++typedef struct _TRIGGER_EVENT_TAB{ ++ UCHAR EventANo; ++ TRIGGER_EVENTA EventA[MAX_TRIGGER_EVENT]; ++ ULONG EventBCountDown; // Count down counter for Event B. ++} TRIGGER_EVENT_TAB, *PTRIGGER_EVENT_TAB; ++ ++// 7.3.27 20/40 Bss Coexistence Mgmt capability used in extended capabilities information IE( ID = 127 = IE_EXT_CAPABILITY). ++// This is the first octet and was defined in 802.11n D3.03 and 802.11yD9.0 ++typedef struct PACKED _EXT_CAP_INFO_ELEMENT{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR rsv2:5; ++ UCHAR ExtendChannelSwitch:1; ++ UCHAR rsv:1; ++ UCHAR BssCoexistMgmtSupport:1; ++#else ++ UCHAR BssCoexistMgmtSupport:1; ++ UCHAR rsv:1; ++ UCHAR ExtendChannelSwitch:1; ++ UCHAR rsv2:5; ++#endif // RT_BIG_ENDIAN // ++}EXT_CAP_INFO_ELEMENT, *PEXT_CAP_INFO_ELEMENT; ++ ++ ++// 802.11n 7.3.2.61 ++typedef struct PACKED _BSS_2040_COEXIST_ELEMENT{ ++ UCHAR ElementID; // ID = IE_2040_BSS_COEXIST = 72 ++ UCHAR Len; ++ BSS_2040_COEXIST_IE BssCoexistIe; ++}BSS_2040_COEXIST_ELEMENT, *PBSS_2040_COEXIST_ELEMENT; ++ ++ ++//802.11n 7.3.2.59 ++typedef struct PACKED _BSS_2040_INTOLERANT_CH_REPORT{ ++ UCHAR ElementID; // ID = IE_2040_BSS_INTOLERANT_REPORT = 73 ++ UCHAR Len; ++ UCHAR RegulatoryClass; ++ UCHAR ChList[0]; ++}BSS_2040_INTOLERANT_CH_REPORT, *PBSS_2040_INTOLERANT_CH_REPORT; ++ ++ ++// The structure for channel switch annoucement IE. This is in 802.11n D3.03 ++typedef struct PACKED _CHA_SWITCH_ANNOUNCE_IE{ ++ UCHAR SwitchMode; //channel switch mode ++ UCHAR NewChannel; // ++ UCHAR SwitchCount; // ++} CHA_SWITCH_ANNOUNCE_IE, *PCHA_SWITCH_ANNOUNCE_IE; ++ ++ ++// The structure for channel switch annoucement IE. This is in 802.11n D3.03 ++typedef struct PACKED _SEC_CHA_OFFSET_IE{ ++ UCHAR SecondaryChannelOffset; // 1: Secondary above, 3: Secondary below, 0: no Secondary ++} SEC_CHA_OFFSET_IE, *PSEC_CHA_OFFSET_IE; ++ ++ ++// This structure is extracted from struct RT_HT_CAPABILITY ++typedef struct { ++ BOOLEAN bHtEnable; // If we should use ht rate. ++ BOOLEAN bPreNHt; // If we should use ht rate. ++ //Substract from HT Capability IE ++ UCHAR MCSSet[16]; //only supoort MCS=0-15,32 , ++} RT_HT_PHY_INFO, *PRT_HT_PHY_INFO; ++ ++//This structure substracts ralink supports from all 802.11n-related features. ++//Features not listed here but contained in 802.11n spec are not supported in rt2860. ++typedef struct { ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv:5; ++ USHORT AmsduSize:1; // Max receiving A-MSDU size ++ USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n ++ USHORT RxSTBC:2; // 2 bits ++ USHORT TxSTBC:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT ShortGIfor20:1; ++ USHORT GF:1; //green field ++ USHORT MimoPs:2;//mimo power safe MMPS_ ++ USHORT ChannelWidth:1; ++#else ++ USHORT ChannelWidth:1; ++ USHORT MimoPs:2;//mimo power safe MMPS_ ++ USHORT GF:1; //green field ++ USHORT ShortGIfor20:1; ++ USHORT ShortGIfor40:1; //for40MHz ++ USHORT TxSTBC:1; ++ USHORT RxSTBC:2; // 2 bits ++ USHORT AmsduEnable:1; // Enable to transmit A-MSDU. Suggest disable. We should use A-MPDU to gain best benifit of 802.11n ++ USHORT AmsduSize:1; // Max receiving A-MSDU size ++ USHORT rsv:5; ++#endif ++ ++ //Substract from Addiont HT INFO IE ++#ifdef RT_BIG_ENDIAN ++ UCHAR RecomWidth:1; ++ UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n ++ UCHAR MpduDensity:3; ++ UCHAR MaxRAmpduFactor:2; ++#else ++ UCHAR MaxRAmpduFactor:2; ++ UCHAR MpduDensity:3; ++ UCHAR ExtChanOffset:2; // Please not the difference with following UCHAR NewExtChannelOffset; from 802.11n ++ UCHAR RecomWidth:1; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:11; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv3:1; ++ USHORT NonGfPresent:1; ++ USHORT OperaionMode:2; ++#else ++ USHORT OperaionMode:2; ++ USHORT NonGfPresent:1; ++ USHORT rsv3:1; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv2:11; ++#endif ++ ++ // New Extension Channel Offset IE ++ UCHAR NewExtChannelOffset; ++ // Extension Capability IE = 127 ++ UCHAR BSSCoexist2040; ++} RT_HT_CAPABILITY, *PRT_HT_CAPABILITY; ++ ++// field in Addtional HT Information IE . ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR SerInterGranu:3; ++ UCHAR S_PSMPSup:1; ++ UCHAR RifsMode:1; ++ UCHAR RecomWidth:1; ++ UCHAR ExtChanOffset:2; ++#else ++ UCHAR ExtChanOffset:2; ++ UCHAR RecomWidth:1; ++ UCHAR RifsMode:1; ++ UCHAR S_PSMPSup:1; //Indicate support for scheduled PSMP ++ UCHAR SerInterGranu:3; //service interval granularity ++#endif ++} ADD_HTINFO, *PADD_HTINFO; ++ ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv2:11; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv:1; ++ USHORT NonGfPresent:1; ++ USHORT OperaionMode:2; ++#else ++ USHORT OperaionMode:2; ++ USHORT NonGfPresent:1; ++ USHORT rsv:1; ++ USHORT OBSS_NonHTExist:1; ++ USHORT rsv2:11; ++#endif ++} ADD_HTINFO2, *PADD_HTINFO2; ++ ++ ++// TODO: Need sync with spec about the definition of StbcMcs. In Draft 3.03, it's reserved. ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT rsv:4; ++ USHORT PcoPhase:1; ++ USHORT PcoActive:1; ++ USHORT LsigTxopProt:1; ++ USHORT STBCBeacon:1; ++ USHORT DualCTSProtect:1; ++ USHORT DualBeacon:1; ++ USHORT StbcMcs:6; ++#else ++ USHORT StbcMcs:6; ++ USHORT DualBeacon:1; ++ USHORT DualCTSProtect:1; ++ USHORT STBCBeacon:1; ++ USHORT LsigTxopProt:1; // L-SIG TXOP protection full support ++ USHORT PcoActive:1; ++ USHORT PcoPhase:1; ++ USHORT rsv:4; ++#endif // RT_BIG_ENDIAN // ++} ADD_HTINFO3, *PADD_HTINFO3; ++ ++#define SIZE_ADD_HT_INFO_IE 22 ++typedef struct PACKED{ ++ UCHAR ControlChan; ++ ADD_HTINFO AddHtInfo; ++ ADD_HTINFO2 AddHtInfo2; ++ ADD_HTINFO3 AddHtInfo3; ++ UCHAR MCSSet[16]; // Basic MCS set ++} ADD_HT_INFO_IE, *PADD_HT_INFO_IE; ++ ++typedef struct PACKED{ ++ UCHAR NewExtChanOffset; ++} NEW_EXT_CHAN_IE, *PNEW_EXT_CHAN_IE; ++ ++ ++// 4-byte HTC field. maybe included in any frame except non-QOS data frame. The Order bit must set 1. ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UINT32 RDG:1; //RDG / More PPDU ++ UINT32 ACConstraint:1; //feedback request ++ UINT32 rsv:5; //calibration sequence ++ UINT32 ZLFAnnouce:1; // ZLF announcement ++ UINT32 CSISTEERING:2; //CSI/ STEERING ++ UINT32 FBKReq:2; //feedback request ++ UINT32 CalSeq:2; //calibration sequence ++ UINT32 CalPos:2; // calibration position ++ UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available ++ UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. ++ UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. ++ UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback ++ UINT32 TRQ:1; //sounding request ++ UINT32 MA:1; //management action payload exist in (QoS Null+HTC) ++#else ++ UINT32 MA:1; //management action payload exist in (QoS Null+HTC) ++ UINT32 TRQ:1; //sounding request ++ UINT32 MRQ:1; //MCS feedback. Request for a MCS feedback ++ UINT32 MRSorASI:3; // MRQ Sequence identifier. unchanged during entire procedure. 0x000-0x110. ++ UINT32 MFS:3; //SET to the received value of MRS. 0x111 for unsolicited MFB. ++ UINT32 MFBorASC:7; //Link adaptation feedback containing recommended MCS. 0x7f for no feedback or not available ++ UINT32 CalPos:2; // calibration position ++ UINT32 CalSeq:2; //calibration sequence ++ UINT32 FBKReq:2; //feedback request ++ UINT32 CSISTEERING:2; //CSI/ STEERING ++ UINT32 ZLFAnnouce:1; // ZLF announcement ++ UINT32 rsv:5; //calibration sequence ++ UINT32 ACConstraint:1; //feedback request ++ UINT32 RDG:1; //RDG / More PPDU ++#endif /* !RT_BIG_ENDIAN */ ++} HT_CONTROL, *PHT_CONTROL; ++ ++// 2-byte QOS CONTROL field ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Txop_QueueSize:8; ++ USHORT AMsduPresent:1; ++ USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA ++ USHORT EOSP:1; ++ USHORT TID:4; ++#else ++ USHORT TID:4; ++ USHORT EOSP:1; ++ USHORT AckPolicy:2; //0: normal ACK 1:No ACK 2:scheduled under MTBA/PSMP 3: BA ++ USHORT AMsduPresent:1; ++ USHORT Txop_QueueSize:8; ++#endif /* !RT_BIG_ENDIAN */ ++} QOS_CONTROL, *PQOS_CONTROL; ++ ++// 2-byte Frame control field ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Order:1; // Strict order expected ++ USHORT Wep:1; // Wep data ++ USHORT MoreData:1; // More data bit ++ USHORT PwrMgmt:1; // Power management bit ++ USHORT Retry:1; // Retry status bit ++ USHORT MoreFrag:1; // More fragment bit ++ USHORT FrDs:1; // From DS indication ++ USHORT ToDs:1; // To DS indication ++ USHORT SubType:4; // MSDU subtype ++ USHORT Type:2; // MSDU type ++ USHORT Ver:2; // Protocol version ++#else ++ USHORT Ver:2; // Protocol version ++ USHORT Type:2; // MSDU type ++ USHORT SubType:4; // MSDU subtype ++ USHORT ToDs:1; // To DS indication ++ USHORT FrDs:1; // From DS indication ++ USHORT MoreFrag:1; // More fragment bit ++ USHORT Retry:1; // Retry status bit ++ USHORT PwrMgmt:1; // Power management bit ++ USHORT MoreData:1; // More data bit ++ USHORT Wep:1; // Wep data ++ USHORT Order:1; // Strict order expected ++#endif /* !RT_BIG_ENDIAN */ ++} FRAME_CONTROL, *PFRAME_CONTROL; ++ ++typedef struct PACKED _HEADER_802_11 { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR Addr3[MAC_ADDR_LEN]; ++#ifdef RT_BIG_ENDIAN ++ USHORT Sequence:12; ++ USHORT Frag:4; ++#else ++ USHORT Frag:4; ++ USHORT Sequence:12; ++#endif /* !RT_BIG_ENDIAN */ ++ UCHAR Octet[0]; ++} HEADER_802_11, *PHEADER_802_11; ++ ++typedef struct PACKED _FRAME_802_11 { ++ HEADER_802_11 Hdr; ++ UCHAR Octet[1]; ++} FRAME_802_11, *PFRAME_802_11; ++ ++// QoSNull embedding of management action. When HT Control MA field set to 1. ++typedef struct PACKED _MA_BODY { ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Octet[1]; ++} MA_BODY, *PMA_BODY; ++ ++typedef struct PACKED _HEADER_802_3 { ++ UCHAR DAAddr1[MAC_ADDR_LEN]; ++ UCHAR SAAddr2[MAC_ADDR_LEN]; ++ UCHAR Octet[2]; ++} HEADER_802_3, *PHEADER_802_3; ++////Block ACK related format ++// 2-byte BA Parameter field in DELBA frames to terminate an already set up bA ++typedef struct PACKED{ ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; // value of TC os TS ++ USHORT Initiator:1; // 1: originator 0:recipient ++ USHORT Rsv:11; // always set to 0 ++#else ++ USHORT Rsv:11; // always set to 0 ++ USHORT Initiator:1; // 1: originator 0:recipient ++ USHORT TID:4; // value of TC os TS ++#endif /* !RT_BIG_ENDIAN */ ++} DELBA_PARM, *PDELBA_PARM; ++ ++// 2-byte BA Parameter Set field in ADDBA frames to signal parm for setting up a BA ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT BufSize:10; // number of buffe of size 2304 octetsr ++ USHORT TID:4; // value of TC os TS ++ USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA ++ USHORT AMSDUSupported:1; // 0: not permitted 1: permitted ++#else ++ USHORT AMSDUSupported:1; // 0: not permitted 1: permitted ++ USHORT BAPolicy:1; // 1: immediately BA 0:delayed BA ++ USHORT TID:4; // value of TC os TS ++ USHORT BufSize:10; // number of buffe of size 2304 octetsr ++#endif /* !RT_BIG_ENDIAN */ ++} BA_PARM, *PBA_PARM; ++ ++// 2-byte BA Starting Seq CONTROL field ++typedef union PACKED { ++ struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent ++ USHORT FragNum:4; // always set to 0 ++#else ++ USHORT FragNum:4; // always set to 0 ++ USHORT StartSeq:12; // sequence number of the 1st MSDU for which this BAR is sent ++#endif /* RT_BIG_ENDIAN */ ++ } field; ++ USHORT word; ++} BASEQ_CONTROL, *PBASEQ_CONTROL; ++ ++//BAControl and BARControl are the same ++// 2-byte BA CONTROL field in BA frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; //EWC V1.24 ++ USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK ++#else ++ USHORT ACKPolicy:1; // only related to N-Delayed BA. But not support in RT2860b. 0:NormalACK 1:No ACK ++ USHORT MTID:1; //EWC V1.24 ++ USHORT Compressed:1; ++ USHORT Rsv:9; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} BA_CONTROL, *PBA_CONTROL; ++ ++// 2-byte BAR CONTROL field in BAR frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv1:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ ++ USHORT ACKPolicy:1; ++#else ++ USHORT ACKPolicy:1; // 0:normal ack, 1:no ack. ++ USHORT MTID:1; //if this bit1, use FRAME_MTBA_REQ, if 0, use FRAME_BA_REQ ++ USHORT Compressed:1; ++ USHORT Rsv1:9; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} BAR_CONTROL, *PBAR_CONTROL; ++ ++// BARControl in MTBAR frame ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT NumTID:4; ++ USHORT Rsv1:9; ++ USHORT Compressed:1; ++ USHORT MTID:1; ++ USHORT ACKPolicy:1; ++#else ++ USHORT ACKPolicy:1; ++ USHORT MTID:1; ++ USHORT Compressed:1; ++ USHORT Rsv1:9; ++ USHORT NumTID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} MTBAR_CONTROL, *PMTBAR_CONTROL; ++ ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT TID:4; ++ USHORT Rsv1:12; ++#else ++ USHORT Rsv1:12; ++ USHORT TID:4; ++#endif /* !RT_BIG_ENDIAN */ ++} PER_TID_INFO, *PPER_TID_INFO; ++ ++typedef struct { ++ PER_TID_INFO PerTID; ++ BASEQ_CONTROL BAStartingSeq; ++} EACH_TID, *PEACH_TID; ++ ++ ++typedef struct PACKED _PSPOLL_FRAME { ++ FRAME_CONTROL FC; ++ USHORT Aid; ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR Ta[MAC_ADDR_LEN]; ++} PSPOLL_FRAME, *PPSPOLL_FRAME; ++ ++typedef struct PACKED _RTS_FRAME { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++}RTS_FRAME, *PRTS_FRAME; ++ ++// BAREQ AND MTBAREQ have the same subtype BAR, 802.11n BAR use compressed bitmap. ++typedef struct PACKED _FRAME_BA_REQ { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BARControl; ++ BASEQ_CONTROL BAStartingSeq; ++} FRAME_BA_REQ, *PFRAME_BA_REQ; ++ ++typedef struct PACKED _FRAME_MTBA_REQ { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ MTBAR_CONTROL MTBARControl; ++ PER_TID_INFO PerTIDInfo; ++ BASEQ_CONTROL BAStartingSeq; ++} FRAME_MTBA_REQ, *PFRAME_MTBA_REQ; ++ ++// Compressed format is mandantory in HT STA ++typedef struct PACKED _FRAME_MTBA { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BA_CONTROL BAControl; ++ BASEQ_CONTROL BAStartingSeq; ++ UCHAR BitMap[8]; ++} FRAME_MTBA, *PFRAME_MTBA; ++ ++typedef struct PACKED _FRAME_PSMP_ACTION { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Psmp; // 7.3.1.25 ++} FRAME_PSMP_ACTION, *PFRAME_PSMP_ACTION; ++ ++typedef struct PACKED _FRAME_ACTION_HDR { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++} FRAME_ACTION_HDR, *PFRAME_ACTION_HDR; ++ ++//Action Frame ++//Action Frame Category:Spectrum, Action:Channel Switch. 7.3.2.20 ++typedef struct PACKED _CHAN_SWITCH_ANNOUNCE { ++ UCHAR ElementID; // ID = IE_CHANNEL_SWITCH_ANNOUNCEMENT = 37 ++ UCHAR Len; ++ CHA_SWITCH_ANNOUNCE_IE CSAnnounceIe; ++} CHAN_SWITCH_ANNOUNCE, *PCHAN_SWITCH_ANNOUNCE; ++ ++ ++//802.11n : 7.3.2.20a ++typedef struct PACKED _SECOND_CHAN_OFFSET { ++ UCHAR ElementID; // ID = IE_SECONDARY_CH_OFFSET = 62 ++ UCHAR Len; ++ SEC_CHA_OFFSET_IE SecChOffsetIe; ++} SECOND_CHAN_OFFSET, *PSECOND_CHAN_OFFSET; ++ ++ ++typedef struct PACKED _FRAME_SPETRUM_CS { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ CHAN_SWITCH_ANNOUNCE CSAnnounce; ++ SECOND_CHAN_OFFSET SecondChannel; ++} FRAME_SPETRUM_CS, *PFRAME_SPETRUM_CS; ++ ++ ++typedef struct PACKED _FRAME_ADDBA_REQ { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; // 1 ++ BA_PARM BaParm; // 2 - 10 ++ USHORT TimeOutValue; // 0 - 0 ++ BASEQ_CONTROL BaStartSeq; // 0-0 ++} FRAME_ADDBA_REQ, *PFRAME_ADDBA_REQ; ++ ++typedef struct PACKED _FRAME_ADDBA_RSP { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; ++ USHORT StatusCode; ++ BA_PARM BaParm; //0 - 2 ++ USHORT TimeOutValue; ++} FRAME_ADDBA_RSP, *PFRAME_ADDBA_RSP; ++ ++typedef struct PACKED _FRAME_DELBA_REQ { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ DELBA_PARM DelbaParm; ++ USHORT ReasonCode; ++} FRAME_DELBA_REQ, *PFRAME_DELBA_REQ; ++ ++ ++//7.2.1.7 ++typedef struct PACKED _FRAME_BAR { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BarControl; ++ BASEQ_CONTROL StartingSeq; ++} FRAME_BAR, *PFRAME_BAR; ++ ++//7.2.1.7 ++typedef struct PACKED _FRAME_BA { ++ FRAME_CONTROL FC; ++ USHORT Duration; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BAR_CONTROL BarControl; ++ BASEQ_CONTROL StartingSeq; ++ UCHAR bitmask[8]; ++} FRAME_BA, *PFRAME_BA; ++ ++ ++// Radio Measuement Request Frame Format ++typedef struct PACKED _FRAME_RM_REQ_ACTION { ++ HEADER_802_11 Hdr; ++ UCHAR Category; ++ UCHAR Action; ++ UCHAR Token; ++ USHORT Repetition; ++ UCHAR data[0]; ++} FRAME_RM_REQ_ACTION, *PFRAME_RM_REQ_ACTION; ++ ++typedef struct PACKED { ++ UCHAR ID; ++ UCHAR Length; ++ UCHAR ChannelSwitchMode; ++ UCHAR NewRegClass; ++ UCHAR NewChannelNum; ++ UCHAR ChannelSwitchCount; ++} HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE, *PHT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE; ++ ++ ++// ++// _Limit must be the 2**n - 1 ++// _SEQ1 , _SEQ2 must be within 0 ~ _Limit ++// ++#define SEQ_STEPONE(_SEQ1, _SEQ2, _Limit) ((_SEQ1 == ((_SEQ2+1) & _Limit))) ++#define SEQ_SMALLER(_SEQ1, _SEQ2, _Limit) (((_SEQ1-_SEQ2) & ((_Limit+1)>>1))) ++#define SEQ_LARGER(_SEQ1, _SEQ2, _Limit) ((_SEQ1 != _SEQ2) && !(((_SEQ1-_SEQ2) & ((_Limit+1)>>1)))) ++#define SEQ_WITHIN_WIN(_SEQ1, _SEQ2, _WIN, _Limit) (SEQ_LARGER(_SEQ1, _SEQ2, _Limit) && \ ++ SEQ_SMALLER(_SEQ1, ((_SEQ2+_WIN+1)&_Limit), _Limit)) ++ ++// ++// Contention-free parameter (without ID and Length) ++// ++typedef struct PACKED { ++ BOOLEAN bValid; // 1: variable contains valid value ++ UCHAR CfpCount; ++ UCHAR CfpPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpDurRemaining; ++} CF_PARM, *PCF_PARM; ++ ++typedef struct _CIPHER_SUITE { ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher 1, this one has more secured cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipherAux; // Unicast cipher 2 if AP announce two unicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Group cipher ++ USHORT RsnCapability; // RSN capability from beacon ++ BOOLEAN bMixMode; // Indicate Pair & Group cipher might be different ++} CIPHER_SUITE, *PCIPHER_SUITE; ++ ++// EDCA configuration from AP's BEACON/ProbeRsp ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ BOOLEAN bAdd; // 1: variable contains valid value ++ BOOLEAN bQAck; ++ BOOLEAN bQueueRequest; ++ BOOLEAN bTxopRequest; ++ BOOLEAN bAPSDCapable; ++// BOOLEAN bMoreDataAck; ++ UCHAR EdcaUpdateCount; ++ UCHAR Aifsn[4]; // 0:AC_BK, 1:AC_BE, 2:AC_VI, 3:AC_VO ++ UCHAR Cwmin[4]; ++ UCHAR Cwmax[4]; ++ USHORT Txop[4]; // in unit of 32-us ++ BOOLEAN bACM[4]; // 1: Admission Control of AC_BK is mandattory ++} EDCA_PARM, *PEDCA_PARM; ++ ++// QBSS LOAD information from QAP's BEACON/ProbeRsp ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ USHORT StaNum; ++ UCHAR ChannelUtilization; ++ USHORT RemainingAdmissionControl; // in unit of 32-us ++} QBSS_LOAD_PARM, *PQBSS_LOAD_PARM; ++ ++// QBSS Info field in QSTA's assoc req ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR Rsv2:1; ++ UCHAR MaxSPLength:2; ++ UCHAR Rsv1:1; ++ UCHAR UAPSD_AC_BE:1; ++ UCHAR UAPSD_AC_BK:1; ++ UCHAR UAPSD_AC_VI:1; ++ UCHAR UAPSD_AC_VO:1; ++#else ++ UCHAR UAPSD_AC_VO:1; ++ UCHAR UAPSD_AC_VI:1; ++ UCHAR UAPSD_AC_BK:1; ++ UCHAR UAPSD_AC_BE:1; ++ UCHAR Rsv1:1; ++ UCHAR MaxSPLength:2; ++ UCHAR Rsv2:1; ++#endif /* !RT_BIG_ENDIAN */ ++} QBSS_STA_INFO_PARM, *PQBSS_STA_INFO_PARM; ++ ++// QBSS Info field in QAP's Beacon/ProbeRsp ++typedef struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ UCHAR UAPSD:1; ++ UCHAR Rsv:3; ++ UCHAR ParamSetCount:4; ++#else ++ UCHAR ParamSetCount:4; ++ UCHAR Rsv:3; ++ UCHAR UAPSD:1; ++#endif /* !RT_BIG_ENDIAN */ ++} QBSS_AP_INFO_PARM, *PQBSS_AP_INFO_PARM; ++ ++// QOS Capability reported in QAP's BEACON/ProbeRsp ++// QOS Capability sent out in QSTA's AssociateReq/ReAssociateReq ++typedef struct { ++ BOOLEAN bValid; // 1: variable contains valid value ++ BOOLEAN bQAck; ++ BOOLEAN bQueueRequest; ++ BOOLEAN bTxopRequest; ++// BOOLEAN bMoreDataAck; ++ UCHAR EdcaUpdateCount; ++} QOS_CAPABILITY_PARM, *PQOS_CAPABILITY_PARM; ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef struct { ++ UCHAR IELen; ++ UCHAR IE[MAX_CUSTOM_LEN]; ++} WPA_IE_; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++typedef struct { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR Channel; ++ UCHAR CentralChannel; //Store the wide-band central channel for 40MHz. .used in 40MHz AP. Or this is the same as Channel. ++ UCHAR BssType; ++ USHORT AtimWin; ++ USHORT BeaconPeriod; ++ ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen; ++ HT_CAPABILITY_IE HtCapability; ++ UCHAR HtCapabilityLen; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChanOffset; ++ CHAR Rssi; ++ UCHAR Privacy; // Indicate security function ON/OFF. Don't mess up with auth mode. ++ UCHAR Hidden; ++ ++ USHORT DtimPeriod; ++ USHORT CapabilityInfo; ++ ++ USHORT CfpCount; ++ USHORT CfpPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpDurRemaining; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ ++ ULONG LastBeaconRxTime; // OS's timestamp ++ ++ BOOLEAN bSES; ++ ++ // New for WPA2 ++ CIPHER_SUITE WPA; // AP announced WPA cipher suite ++ CIPHER_SUITE WPA2; // AP announced WPA2 cipher suite ++ ++ // New for microsoft WPA support ++ NDIS_802_11_FIXED_IEs FixIEs; ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeAux; // Addition mode for WPA2 / WPA capable AP ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; // Unicast Encryption Algorithm extract from VAR_IE ++ USHORT VarIELen; // Length of next VIE include EID & Length ++ UCHAR VarIEs[MAX_VIE_LEN]; ++ ++ // CCX Ckip information ++ UCHAR CkipFlag; ++ ++ // CCX 2 TSF ++ UCHAR PTSF[4]; // Parent TSF ++ UCHAR TTSF[8]; // Target TSF ++ ++ // 802.11e d9, and WMM ++ EDCA_PARM EdcaParm; ++ QOS_CAPABILITY_PARM QosCapability; ++ QBSS_LOAD_PARM QbssLoad; ++#ifdef CONFIG_STA_SUPPORT ++ WPA_IE_ WpaIE; ++ WPA_IE_ RsnIE; ++#ifdef EXT_BUILD_CHANNEL_LIST ++ UCHAR CountryString[3]; ++ BOOLEAN bHasCountryIE; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++} BSS_ENTRY, *PBSS_ENTRY; ++ ++typedef struct { ++ UCHAR BssNr; ++ UCHAR BssOverlapNr; ++ BSS_ENTRY BssEntry[MAX_LEN_OF_BSS_TABLE]; ++} BSS_TABLE, *PBSS_TABLE; ++ ++ ++typedef struct _MLME_QUEUE_ELEM { ++ ULONG Machine; ++ ULONG MsgType; ++ ULONG MsgLen; ++ UCHAR Msg[MGMT_DMA_BUFFER_SIZE]; ++ LARGE_INTEGER TimeStamp; ++ UCHAR Rssi0; ++ UCHAR Rssi1; ++ UCHAR Rssi2; ++ UCHAR Signal; ++ UCHAR Channel; ++ UCHAR Wcid; ++ BOOLEAN Occupied; ++#ifdef MLME_EX ++ USHORT Idx; ++#endif // MLME_EX // ++} MLME_QUEUE_ELEM, *PMLME_QUEUE_ELEM; ++ ++typedef struct _MLME_QUEUE { ++ ULONG Num; ++ ULONG Head; ++ ULONG Tail; ++ NDIS_SPIN_LOCK Lock; ++ MLME_QUEUE_ELEM Entry[MAX_LEN_OF_MLME_QUEUE]; ++} MLME_QUEUE, *PMLME_QUEUE; ++ ++typedef VOID (*STATE_MACHINE_FUNC)(VOID *Adaptor, MLME_QUEUE_ELEM *Elem); ++ ++typedef struct _STATE_MACHINE { ++ ULONG Base; ++ ULONG NrState; ++ ULONG NrMsg; ++ ULONG CurrState; ++ STATE_MACHINE_FUNC *TransFunc; ++} STATE_MACHINE, *PSTATE_MACHINE; ++ ++ ++// MLME AUX data structure that hold temporarliy settings during a connection attempt. ++// Once this attemp succeeds, all settings will be copy to pAd->StaActive. ++// A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of ++// several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely ++// separate this under-trial settings away from pAd->StaActive so that once ++// this new attempt failed, driver can auto-recover back to the active settings. ++typedef struct _MLME_AUX { ++ UCHAR BssType; ++ UCHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR AutoReconnectSsid[MAX_LEN_OF_SSID]; ++ UCHAR AutoReconnectSsidLen; ++ USHORT Alg; ++ UCHAR ScanType; ++ UCHAR Channel; ++ UCHAR CentralChannel; ++ USHORT Aid; ++ USHORT CapabilityInfo; ++ USHORT BeaconPeriod; ++ USHORT CfpMaxDuration; ++ USHORT CfpPeriod; ++ USHORT AtimWin; ++ ++ // Copy supported rate from desired AP's beacon. We are trying to match ++ // AP's supported and extended rate settings. ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRateLen; ++ HT_CAPABILITY_IE HtCapability; ++ UCHAR HtCapabilityLen; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR NewExtChannelOffset; ++ //RT_HT_CAPABILITY SupportedHtPhy; ++ ++ // new for QOS ++ QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP ++ EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP ++ QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP ++ ++ // new to keep Ralink specific feature ++ ULONG APRalinkIe; ++ ++ BSS_TABLE SsidBssTab; // AP list for the same SSID ++ BSS_TABLE RoamTab; // AP list eligible for roaming ++ ULONG BssIdx; ++ ULONG RoamIdx; ++ ++ BOOLEAN CurrReqIsFromNdis; ++ ++ RALINK_TIMER_STRUCT BeaconTimer, ScanTimer; ++ RALINK_TIMER_STRUCT AuthTimer; ++ RALINK_TIMER_STRUCT AssocTimer, ReassocTimer, DisassocTimer; ++} MLME_AUX, *PMLME_AUX; ++ ++typedef struct _MLME_ADDBA_REQ_STRUCT{ ++ UCHAR Wcid; // ++ UCHAR pAddr[MAC_ADDR_LEN]; ++ UCHAR BaBufSize; ++ USHORT TimeOutValue; ++ UCHAR TID; ++ UCHAR Token; ++ USHORT BaStartSeq; ++} MLME_ADDBA_REQ_STRUCT, *PMLME_ADDBA_REQ_STRUCT; ++ ++ ++typedef struct _MLME_DELBA_REQ_STRUCT{ ++ UCHAR Wcid; // ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR TID; ++ UCHAR Initiator; ++} MLME_DELBA_REQ_STRUCT, *PMLME_DELBA_REQ_STRUCT; ++ ++// assoc struct is equal to reassoc ++typedef struct _MLME_ASSOC_REQ_STRUCT{ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT CapabilityInfo; ++ USHORT ListenIntv; ++ ULONG Timeout; ++} MLME_ASSOC_REQ_STRUCT, *PMLME_ASSOC_REQ_STRUCT, MLME_REASSOC_REQ_STRUCT, *PMLME_REASSOC_REQ_STRUCT; ++ ++typedef struct _MLME_DISASSOC_REQ_STRUCT{ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Reason; ++} MLME_DISASSOC_REQ_STRUCT, *PMLME_DISASSOC_REQ_STRUCT; ++ ++typedef struct _MLME_AUTH_REQ_STRUCT { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Alg; ++ ULONG Timeout; ++} MLME_AUTH_REQ_STRUCT, *PMLME_AUTH_REQ_STRUCT; ++ ++typedef struct _MLME_DEAUTH_REQ_STRUCT { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Reason; ++} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; ++ ++typedef struct { ++ ULONG BssIdx; ++} MLME_JOIN_REQ_STRUCT; ++ ++typedef struct _MLME_SCAN_REQ_STRUCT { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR BssType; ++ UCHAR ScanType; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++} MLME_SCAN_REQ_STRUCT, *PMLME_SCAN_REQ_STRUCT; ++ ++typedef struct _MLME_START_REQ_STRUCT { ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++} MLME_START_REQ_STRUCT, *PMLME_START_REQ_STRUCT; ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++// structure for DLS ++typedef struct _RT_802_11_DLS { ++ USHORT TimeOut; // Use to time out while slience, unit: second , set by UI ++ USHORT CountDownTimer; // Use to time out while slience,unit: second , used by driver only ++ NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI ++ UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only ++ BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link ++ RALINK_TIMER_STRUCT Timer; // Use to time out while handshake ++ USHORT Sequence; ++ USHORT MacTabMatchWCID; // ASIC ++ BOOLEAN bHTCap; ++ PVOID pAd; ++} RT_802_11_DLS, *PRT_802_11_DLS; ++ ++typedef struct _MLME_DLS_REQ_STRUCT { ++ PRT_802_11_DLS pDLS; ++ USHORT Reason; ++} MLME_DLS_REQ_STRUCT, *PMLME_DLS_REQ_STRUCT; ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct PACKED { ++ UCHAR Eid; ++ UCHAR Len; ++ CHAR Octet[1]; ++} EID_STRUCT,*PEID_STRUCT, BEACON_EID_STRUCT, *PBEACON_EID_STRUCT; ++ ++typedef struct PACKED _RTMP_TX_RATE_SWITCH ++{ ++ UCHAR ItemNo; ++#ifdef RT_BIG_ENDIAN ++ UCHAR Rsv2:2; ++ UCHAR Mode:2; ++ UCHAR Rsv1:1; ++ UCHAR BW:1; ++ UCHAR ShortGI:1; ++ UCHAR STBC:1; ++#else ++ UCHAR STBC:1; ++ UCHAR ShortGI:1; ++ UCHAR BW:1; ++ UCHAR Rsv1:1; ++ UCHAR Mode:2; ++ UCHAR Rsv2:2; ++#endif ++ UCHAR CurrMCS; ++ UCHAR TrainUp; ++ UCHAR TrainDown; ++} RRTMP_TX_RATE_SWITCH, *PRTMP_TX_RATE_SWITCH; ++ ++// ========================== AP mlme.h =============================== ++#define TBTT_PRELOAD_TIME 384 // usec. LomgPreamble + 24-byte at 1Mbps ++#define DEFAULT_DTIM_PERIOD 1 ++ ++// weighting factor to calculate Channel quality, total should be 100% ++//#define RSSI_WEIGHTING 0 ++//#define TX_WEIGHTING 40 ++//#define RX_WEIGHTING 60 ++ ++#define MAC_TABLE_AGEOUT_TIME 300 // unit: sec ++#define MAC_TABLE_ASSOC_TIMEOUT 5 // unit: sec ++#define MAC_TABLE_FULL(Tab) ((Tab).size == MAX_LEN_OF_MAC_TABLE) ++ ++// AP shall drop the sta if contine Tx fail count reach it. ++#define MAC_ENTRY_LIFE_CHECK_CNT 20 // packet cnt. ++ ++// Value domain of pMacEntry->Sst ++typedef enum _Sst { ++ SST_NOT_AUTH, // 0: equivalent to IEEE 802.11/1999 state 1 ++ SST_AUTH, // 1: equivalent to IEEE 802.11/1999 state 2 ++ SST_ASSOC // 2: equivalent to IEEE 802.11/1999 state 3 ++} SST; ++ ++// value domain of pMacEntry->AuthState ++typedef enum _AuthState { ++ AS_NOT_AUTH, ++ AS_AUTH_OPEN, // STA has been authenticated using OPEN SYSTEM ++ AS_AUTH_KEY, // STA has been authenticated using SHARED KEY ++ AS_AUTHENTICATING // STA is waiting for AUTH seq#3 using SHARED KEY ++} AUTH_STATE; ++ ++//for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _ApWpaState { ++ AS_NOTUSE, // 0 ++ AS_DISCONNECT, // 1 ++ AS_DISCONNECTED, // 2 ++ AS_INITIALIZE, // 3 ++ AS_AUTHENTICATION, // 4 ++ AS_AUTHENTICATION2, // 5 ++ AS_INITPMK, // 6 ++ AS_INITPSK, // 7 ++ AS_PTKSTART, // 8 ++ AS_PTKINIT_NEGOTIATING, // 9 ++ AS_PTKINITDONE, // 10 ++ AS_UPDATEKEYS, // 11 ++ AS_INTEGRITY_FAILURE, // 12 ++ AS_KEYUPDATE, // 13 ++} AP_WPA_STATE; ++ ++// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _GTKState { ++ REKEY_NEGOTIATING, ++ REKEY_ESTABLISHED, ++ KEYERROR, ++} GTK_STATE; ++ ++// for-wpa value domain of pMacEntry->WpaState 802.1i D3 p.114 ++typedef enum _WpaGTKState { ++ SETKEYS, ++ SETKEYS_DONE, ++} WPA_GTK_STATE; ++// ====================== end of AP mlme.h ============================ ++ ++ ++#endif // MLME_H__ +--- /dev/null ++++ b/drivers/staging/rt3070/netif_block.h +@@ -0,0 +1,58 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __NET_IF_BLOCK_H__ ++#define __NET_IF_BLOCK_H__ ++ ++//#include ++#include "link_list.h" ++#include "rtmp.h" ++ ++#define FREE_NETIF_POOL_SIZE 32 ++ ++typedef struct _NETIF_ENTRY ++{ ++ struct _NETIF_ENTRY *pNext; ++ PNET_DEV pNetDev; ++} NETIF_ENTRY, *PNETIF_ENTRY; ++ ++void initblockQueueTab( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN blockNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry, ++ IN PNET_DEV pNetDev); ++ ++VOID releaseNetIf( ++ IN PBLOCK_QUEUE_ENTRY pBlockQueueEntry); ++ ++VOID StopNetIfQueue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++#endif // __NET_IF_BLOCK_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/oid.h +@@ -0,0 +1,1142 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ oid.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef _OID_H_ ++#define _OID_H_ ++ ++//#include ++ ++ ++#define TRUE 1 ++#define FALSE 0 ++// ++// IEEE 802.11 Structures and definitions ++// ++#define MAX_TX_POWER_LEVEL 100 /* mW */ ++#define MAX_RSSI_TRIGGER -10 /* dBm */ ++#define MIN_RSSI_TRIGGER -200 /* dBm */ ++#define MAX_FRAG_THRESHOLD 2346 /* byte count */ ++#define MIN_FRAG_THRESHOLD 256 /* byte count */ ++#define MAX_RTS_THRESHOLD 2347 /* byte count */ ++ ++// new types for Media Specific Indications ++// Extension channel offset ++#define EXTCHA_NONE 0 ++#define EXTCHA_ABOVE 0x1 ++#define EXTCHA_BELOW 0x3 ++ ++// BW ++#define BAND_WIDTH_20 0 ++#define BAND_WIDTH_40 1 ++#define BAND_WIDTH_BOTH 2 ++#define BAND_WIDTH_10 3 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. ++// SHORTGI ++#define GAP_INTERVAL_400 1 // only support in HT mode ++#define GAP_INTERVAL_800 0 ++#define GAP_INTERVAL_BOTH 2 ++ ++#define NdisMediaStateConnected 1 ++#define NdisMediaStateDisconnected 0 ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++#define MAC_ADDR_LENGTH 6 ++#define MAX_NUM_OF_CHS 49 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL terminationc ++#define MAX_NUMBER_OF_EVENT 10 // entry # in EVENT table ++#define MAX_NUMBER_OF_MAC 32 // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 ++#define MAX_NUMBER_OF_ACL 64 ++#define MAX_LENGTH_OF_SUPPORT_RATES 12 // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define MAX_NUMBER_OF_DLS_ENTRY 4 ++ ++ ++ ++#ifndef UNDER_CE ++// OID definition, since NDIS 5.0 didn't define these, we need to define for our own ++//#if _WIN32_WINNT<=0x0500 ++ ++#define OID_GEN_MACHINE_NAME 0x0001021A ++ ++#ifdef RALINK_ATE ++#define RT_QUERY_ATE_TXDONE_COUNT 0x0401 ++#endif // RALINK_ATE // ++#define RT_QUERY_SIGNAL_CONTEXT 0x0402 ++#define RT_SET_IAPP_PID 0x0404 ++#define RT_SET_APD_PID 0x0405 ++#define RT_SET_DEL_MAC_ENTRY 0x0406 ++ ++// ++// IEEE 802.11 OIDs ++// ++#define OID_GET_SET_TOGGLE 0x8000 ++ ++#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0103 ++#define OID_802_11_NETWORK_TYPE_IN_USE 0x0104 ++#define OID_802_11_RSSI_TRIGGER 0x0107 ++#define RT_OID_802_11_RSSI 0x0108 //rt2860 only , kathy ++#define RT_OID_802_11_RSSI_1 0x0109 //rt2860 only , kathy ++#define RT_OID_802_11_RSSI_2 0x010A //rt2860 only , kathy ++#define OID_802_11_NUMBER_OF_ANTENNAS 0x010B ++#define OID_802_11_RX_ANTENNA_SELECTED 0x010C ++#define OID_802_11_TX_ANTENNA_SELECTED 0x010D ++#define OID_802_11_SUPPORTED_RATES 0x010E ++#define OID_802_11_ADD_WEP 0x0112 ++#define OID_802_11_REMOVE_WEP 0x0113 ++#define OID_802_11_DISASSOCIATE 0x0114 ++#define OID_802_11_PRIVACY_FILTER 0x0118 ++#define OID_802_11_ASSOCIATION_INFORMATION 0x011E ++#define OID_802_11_TEST 0x011F ++#define RT_OID_802_11_COUNTRY_REGION 0x0507 ++#define OID_802_11_BSSID_LIST_SCAN 0x0508 ++#define OID_802_11_SSID 0x0509 ++#define OID_802_11_BSSID 0x050A ++#define RT_OID_802_11_RADIO 0x050B ++#define RT_OID_802_11_PHY_MODE 0x050C ++#define RT_OID_802_11_STA_CONFIG 0x050D ++#define OID_802_11_DESIRED_RATES 0x050E ++#define RT_OID_802_11_PREAMBLE 0x050F ++#define OID_802_11_WEP_STATUS 0x0510 ++#define OID_802_11_AUTHENTICATION_MODE 0x0511 ++#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 ++#define RT_OID_802_11_RESET_COUNTERS 0x0513 ++#define OID_802_11_RTS_THRESHOLD 0x0514 ++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0515 ++#define OID_802_11_POWER_MODE 0x0516 ++#define OID_802_11_TX_POWER_LEVEL 0x0517 ++#define RT_OID_802_11_ADD_WPA 0x0518 ++#define OID_802_11_REMOVE_KEY 0x0519 ++#define OID_802_11_ADD_KEY 0x0520 ++#define OID_802_11_CONFIGURATION 0x0521 ++#define OID_802_11_TX_PACKET_BURST 0x0522 ++#define RT_OID_802_11_QUERY_NOISE_LEVEL 0x0523 ++#define RT_OID_802_11_EXTRA_INFO 0x0524 ++#ifdef DBG ++#define RT_OID_802_11_HARDWARE_REGISTER 0x0525 ++#endif ++#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS ++#define OID_802_11_DEAUTHENTICATION 0x0526 ++#define OID_802_11_DROP_UNENCRYPTED 0x0527 ++#define OID_802_11_MIC_FAILURE_REPORT_FRAME 0x0528 ++ ++// For 802.1x daemin using to require current driver configuration ++#define OID_802_11_RADIUS_QUERY_SETTING 0x0540 ++ ++#define RT_OID_DEVICE_NAME 0x0607 ++#define RT_OID_VERSION_INFO 0x0608 ++#define OID_802_11_BSSID_LIST 0x0609 ++#define OID_802_3_CURRENT_ADDRESS 0x060A ++#define OID_GEN_MEDIA_CONNECT_STATUS 0x060B ++#define RT_OID_802_11_QUERY_LINK_STATUS 0x060C ++#define OID_802_11_RSSI 0x060D ++#define OID_802_11_STATISTICS 0x060E ++#define OID_GEN_RCV_OK 0x060F ++#define OID_GEN_RCV_NO_BUFFER 0x0610 ++#define RT_OID_802_11_QUERY_EEPROM_VERSION 0x0611 ++#define RT_OID_802_11_QUERY_FIRMWARE_VERSION 0x0612 ++#define RT_OID_802_11_QUERY_LAST_RX_RATE 0x0613 ++#define RT_OID_802_11_TX_POWER_LEVEL_1 0x0614 ++#define RT_OID_802_11_QUERY_PIDVID 0x0615 ++//for WPA_SUPPLICANT_SUPPORT ++#define OID_SET_COUNTERMEASURES 0x0616 ++#define OID_802_11_SET_IEEE8021X 0x0617 ++#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 ++#define OID_802_11_PMKID 0x0620 ++#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 ++#define RT_OID_WE_VERSION_COMPILED 0x0622 ++#define RT_OID_NEW_DRIVER 0x0623 ++ ++ ++//rt2860 , kathy ++#define RT_OID_802_11_SNR_0 0x0630 ++#define RT_OID_802_11_SNR_1 0x0631 ++#define RT_OID_802_11_QUERY_LAST_TX_RATE 0x0632 ++#define RT_OID_802_11_QUERY_HT_PHYMODE 0x0633 ++#define RT_OID_802_11_SET_HT_PHYMODE 0x0634 ++#define OID_802_11_RELOAD_DEFAULTS 0x0635 ++#define RT_OID_802_11_QUERY_APSD_SETTING 0x0636 ++#define RT_OID_802_11_SET_APSD_SETTING 0x0637 ++#define RT_OID_802_11_QUERY_APSD_PSM 0x0638 ++#define RT_OID_802_11_SET_APSD_PSM 0x0639 ++#define RT_OID_802_11_QUERY_DLS 0x063A ++#define RT_OID_802_11_SET_DLS 0x063B ++#define RT_OID_802_11_QUERY_DLS_PARAM 0x063C ++#define RT_OID_802_11_SET_DLS_PARAM 0x063D ++#define RT_OID_802_11_QUERY_WMM 0x063E ++#define RT_OID_802_11_SET_WMM 0x063F ++#define RT_OID_802_11_QUERY_IMME_BA_CAP 0x0640 ++#define RT_OID_802_11_SET_IMME_BA_CAP 0x0641 ++#define RT_OID_802_11_QUERY_BATABLE 0x0642 ++#define RT_OID_802_11_ADD_IMME_BA 0x0643 ++#define RT_OID_802_11_TEAR_IMME_BA 0x0644 ++#define RT_OID_DRIVER_DEVICE_NAME 0x0645 ++#define RT_OID_802_11_QUERY_DAT_HT_PHYMODE 0x0646 ++#define RT_OID_QUERY_MULTIPLE_CARD_SUPPORT 0x0647 ++ ++// Ralink defined OIDs ++// Dennis Lee move to platform specific ++ ++#define RT_OID_802_11_BSSID (OID_GET_SET_TOGGLE | OID_802_11_BSSID) ++#define RT_OID_802_11_SSID (OID_GET_SET_TOGGLE | OID_802_11_SSID) ++#define RT_OID_802_11_INFRASTRUCTURE_MODE (OID_GET_SET_TOGGLE | OID_802_11_INFRASTRUCTURE_MODE) ++#define RT_OID_802_11_ADD_WEP (OID_GET_SET_TOGGLE | OID_802_11_ADD_WEP) ++#define RT_OID_802_11_ADD_KEY (OID_GET_SET_TOGGLE | OID_802_11_ADD_KEY) ++#define RT_OID_802_11_REMOVE_WEP (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_WEP) ++#define RT_OID_802_11_REMOVE_KEY (OID_GET_SET_TOGGLE | OID_802_11_REMOVE_KEY) ++#define RT_OID_802_11_DISASSOCIATE (OID_GET_SET_TOGGLE | OID_802_11_DISASSOCIATE) ++#define RT_OID_802_11_AUTHENTICATION_MODE (OID_GET_SET_TOGGLE | OID_802_11_AUTHENTICATION_MODE) ++#define RT_OID_802_11_PRIVACY_FILTER (OID_GET_SET_TOGGLE | OID_802_11_PRIVACY_FILTER) ++#define RT_OID_802_11_BSSID_LIST_SCAN (OID_GET_SET_TOGGLE | OID_802_11_BSSID_LIST_SCAN) ++#define RT_OID_802_11_WEP_STATUS (OID_GET_SET_TOGGLE | OID_802_11_WEP_STATUS) ++#define RT_OID_802_11_RELOAD_DEFAULTS (OID_GET_SET_TOGGLE | OID_802_11_RELOAD_DEFAULTS) ++#define RT_OID_802_11_NETWORK_TYPE_IN_USE (OID_GET_SET_TOGGLE | OID_802_11_NETWORK_TYPE_IN_USE) ++#define RT_OID_802_11_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | OID_802_11_TX_POWER_LEVEL) ++#define RT_OID_802_11_RSSI_TRIGGER (OID_GET_SET_TOGGLE | OID_802_11_RSSI_TRIGGER) ++#define RT_OID_802_11_FRAGMENTATION_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_FRAGMENTATION_THRESHOLD) ++#define RT_OID_802_11_RTS_THRESHOLD (OID_GET_SET_TOGGLE | OID_802_11_RTS_THRESHOLD) ++#define RT_OID_802_11_RX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_RX_ANTENNA_SELECTED) ++#define RT_OID_802_11_TX_ANTENNA_SELECTED (OID_GET_SET_TOGGLE | OID_802_11_TX_ANTENNA_SELECTED) ++#define RT_OID_802_11_SUPPORTED_RATES (OID_GET_SET_TOGGLE | OID_802_11_SUPPORTED_RATES) ++#define RT_OID_802_11_DESIRED_RATES (OID_GET_SET_TOGGLE | OID_802_11_DESIRED_RATES) ++#define RT_OID_802_11_CONFIGURATION (OID_GET_SET_TOGGLE | OID_802_11_CONFIGURATION) ++#define RT_OID_802_11_POWER_MODE (OID_GET_SET_TOGGLE | OID_802_11_POWER_MODE) ++ ++ ++ ++typedef enum _NDIS_802_11_STATUS_TYPE ++{ ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE; ++ ++typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; ++ ++typedef struct _NDIS_802_11_STATUS_INDICATION ++{ ++ NDIS_802_11_STATUS_TYPE StatusType; ++} NDIS_802_11_STATUS_INDICATION, *PNDIS_802_11_STATUS_INDICATION; ++ ++// mask for authentication/integrity fields ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++ ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_REQUEST ++{ ++ ULONG Length; // Length of structure ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ULONG Flags; ++} NDIS_802_11_AUTHENTICATION_REQUEST, *PNDIS_802_11_AUTHENTICATION_REQUEST; ++ ++//Added new types for PMKID Candidate lists. ++typedef struct _PMKID_CANDIDATE { ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ ULONG Flags; ++} PMKID_CANDIDATE, *PPMKID_CANDIDATE; ++ ++typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST ++{ ++ ULONG Version; // Version of the structure ++ ULONG NumCandidates; // No. of pmkid candidates ++ PMKID_CANDIDATE CandidateList[1]; ++} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; ++ ++//Flags for PMKID Candidate list structure ++#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 ++ ++// Added new types for OFDM 5G and 2.4G ++typedef enum _NDIS_802_11_NETWORK_TYPE ++{ ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM5_N, ++ Ndis802_11OFDM24, ++ Ndis802_11OFDM24_N, ++ Ndis802_11Automode, ++ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound ++} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; ++ ++typedef struct _NDIS_802_11_NETWORK_TYPE_LIST ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_802_11_NETWORK_TYPE NetworkType [1]; ++} NDIS_802_11_NETWORK_TYPE_LIST, *PNDIS_802_11_NETWORK_TYPE_LIST; ++ ++typedef enum _NDIS_802_11_POWER_MODE ++{ ++ Ndis802_11PowerModeCAM, ++ Ndis802_11PowerModeMAX_PSP, ++ Ndis802_11PowerModeFast_PSP, ++ Ndis802_11PowerModeLegacy_PSP, ++ Ndis802_11PowerModeMax // not a real mode, defined as an upper bound ++} NDIS_802_11_POWER_MODE, *PNDIS_802_11_POWER_MODE; ++ ++typedef ULONG NDIS_802_11_TX_POWER_LEVEL; // in milliwatts ++ ++// ++// Received Signal Strength Indication ++// ++typedef LONG NDIS_802_11_RSSI; // in dBm ++ ++typedef struct _NDIS_802_11_CONFIGURATION_FH ++{ ++ ULONG Length; // Length of structure ++ ULONG HopPattern; // As defined by 802.11, MSB set ++ ULONG HopSet; // to one if non-802.11 ++ ULONG DwellTime; // units are Kusec ++} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; ++ ++typedef struct _NDIS_802_11_CONFIGURATION ++{ ++ ULONG Length; // Length of structure ++ ULONG BeaconPeriod; // units are Kusec ++ ULONG ATIMWindow; // units are Kusec ++ ULONG DSConfig; // Frequency, units are kHz ++ NDIS_802_11_CONFIGURATION_FH FHConfig; ++} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; ++ ++typedef struct _NDIS_802_11_STATISTICS ++{ ++ ULONG Length; // Length of structure ++ LARGE_INTEGER TransmittedFragmentCount; ++ LARGE_INTEGER MulticastTransmittedFrameCount; ++ LARGE_INTEGER FailedCount; ++ LARGE_INTEGER RetryCount; ++ LARGE_INTEGER MultipleRetryCount; ++ LARGE_INTEGER RTSSuccessCount; ++ LARGE_INTEGER RTSFailureCount; ++ LARGE_INTEGER ACKFailureCount; ++ LARGE_INTEGER FrameDuplicateCount; ++ LARGE_INTEGER ReceivedFragmentCount; ++ LARGE_INTEGER MulticastReceivedFrameCount; ++ LARGE_INTEGER FCSErrorCount; ++ LARGE_INTEGER TKIPLocalMICFailures; ++ LARGE_INTEGER TKIPRemoteMICErrors; ++ LARGE_INTEGER TKIPICVErrors; ++ LARGE_INTEGER TKIPCounterMeasuresInvoked; ++ LARGE_INTEGER TKIPReplays; ++ LARGE_INTEGER CCMPFormatErrors; ++ LARGE_INTEGER CCMPReplays; ++ LARGE_INTEGER CCMPDecryptErrors; ++ LARGE_INTEGER FourWayHandshakeFailures; ++} NDIS_802_11_STATISTICS, *PNDIS_802_11_STATISTICS; ++ ++typedef ULONG NDIS_802_11_KEY_INDEX; ++typedef ULONGLONG NDIS_802_11_KEY_RSC; ++ ++#define MAX_RADIUS_SRV_NUM 2 // 802.1x failover number ++ ++typedef struct PACKED _RADIUS_SRV_INFO { ++ UINT32 radius_ip; ++ UINT32 radius_port; ++ UCHAR radius_key[64]; ++ UCHAR radius_key_len; ++} RADIUS_SRV_INFO, *PRADIUS_SRV_INFO; ++ ++typedef struct PACKED _RADIUS_KEY_INFO ++{ ++ UCHAR radius_srv_num; ++ RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; ++ UCHAR ieee8021xWEP; // dynamic WEP ++ UCHAR key_index; ++ UCHAR key_length; // length of key in bytes ++ UCHAR key_material[13]; ++} RADIUS_KEY_INFO, *PRADIUS_KEY_INFO; ++ ++// It's used by 802.1x daemon to require relative configuration ++typedef struct PACKED _RADIUS_CONF ++{ ++ UINT32 Length; // Length of this structure ++ UCHAR mbss_num; // indicate multiple BSS number ++ UINT32 own_ip_addr; ++ UINT32 retry_interval; ++ UINT32 session_timeout_interval; ++ UCHAR EAPifname[IFNAMSIZ]; ++ UCHAR EAPifname_len; ++ UCHAR PreAuthifname[IFNAMSIZ]; ++ UCHAR PreAuthifname_len; ++ RADIUS_KEY_INFO RadiusInfo[8/*MAX_MBSSID_NUM*/]; ++} RADIUS_CONF, *PRADIUS_CONF; ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++// Key mapping keys require a BSSID ++typedef struct _NDIS_802_11_KEY ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; ++ UINT KeyLength; // length of key in bytes ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_KEY_RSC KeyRSC; ++ UCHAR KeyMaterial[1]; // variable length depending on above field ++} NDIS_802_11_KEY, *PNDIS_802_11_KEY; ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct _NDIS_802_11_REMOVE_KEY ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; ++ NDIS_802_11_MAC_ADDRESS BSSID; ++} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; ++ ++typedef struct _NDIS_802_11_WEP ++{ ++ UINT Length; // Length of this structure ++ UINT KeyIndex; // 0 is the per-client key, 1-N are the ++ // global keys ++ UINT KeyLength; // length of key in bytes ++ UCHAR KeyMaterial[1];// variable length depending on above field ++} NDIS_802_11_WEP, *PNDIS_802_11_WEP; ++ ++ ++typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE ++{ ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11Monitor, ++ Ndis802_11InfrastructureMax // Not a real value, defined as upper bound ++} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; ++ ++// Add new authentication modes ++typedef enum _NDIS_802_11_AUTHENTICATION_MODE ++{ ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWPA2, ++ Ndis802_11AuthModeWPA2PSK, ++ Ndis802_11AuthModeWPA1WPA2, ++ Ndis802_11AuthModeWPA1PSKWPA2PSK, ++ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound ++} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; ++ ++typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates ++typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates ++ ++typedef struct PACKED _NDIS_802_11_SSID ++{ ++ UINT SsidLength; // length of SSID field below, in bytes; ++ // this can be zero. ++ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field ++} NDIS_802_11_SSID, *PNDIS_802_11_SSID; ++ ++ ++typedef struct PACKED _NDIS_WLAN_BSSID ++{ ++ ULONG Length; // Length of this structure ++ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID ++ UCHAR Reserved[2]; ++ NDIS_802_11_SSID Ssid; // SSID ++ ULONG Privacy; // WEP encryption requirement ++ NDIS_802_11_RSSI Rssi; // receive signal strength in dBm ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES SupportedRates; ++} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; ++ ++typedef struct PACKED _NDIS_802_11_BSSID_LIST ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_WLAN_BSSID Bssid[1]; ++} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; ++ ++// Added Capabilities, IELength and IEs for each BSSID ++typedef struct PACKED _NDIS_WLAN_BSSID_EX ++{ ++ ULONG Length; // Length of this structure ++ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID ++ UCHAR Reserved[2]; ++ NDIS_802_11_SSID Ssid; // SSID ++ UINT Privacy; // WEP encryption requirement ++ NDIS_802_11_RSSI Rssi; // receive signal ++ // strength in dBm ++ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ NDIS_802_11_CONFIGURATION Configuration; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; ++ NDIS_802_11_RATES_EX SupportedRates; ++ ULONG IELength; ++ UCHAR IEs[1]; ++} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; ++ ++typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX ++{ ++ UINT NumberOfItems; // in list below, at least 1 ++ NDIS_WLAN_BSSID_EX Bssid[1]; ++} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; ++ ++typedef struct PACKED _NDIS_802_11_FIXED_IEs ++{ ++ UCHAR Timestamp[8]; ++ USHORT BeaconInterval; ++ USHORT Capabilities; ++} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; ++ ++typedef struct _NDIS_802_11_VARIABLE_IEs ++{ ++ UCHAR ElementID; ++ UCHAR Length; // Number of bytes in data field ++ UCHAR data[1]; ++} NDIS_802_11_VARIABLE_IEs, *PNDIS_802_11_VARIABLE_IEs; ++ ++typedef ULONG NDIS_802_11_FRAGMENTATION_THRESHOLD; ++ ++typedef ULONG NDIS_802_11_RTS_THRESHOLD; ++ ++typedef ULONG NDIS_802_11_ANTENNA; ++ ++typedef enum _NDIS_802_11_PRIVACY_FILTER ++{ ++ Ndis802_11PrivFilterAcceptAll, ++ Ndis802_11PrivFilter8021xWEP ++} NDIS_802_11_PRIVACY_FILTER, *PNDIS_802_11_PRIVACY_FILTER; ++ ++// Added new encryption types ++// Also aliased typedef to new name ++typedef enum _NDIS_802_11_WEP_STATUS ++{ ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent, ++ Ndis802_11Encryption4Enabled, // TKIP or AES mix ++ Ndis802_11Encryption4KeyAbsent, ++} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, ++ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; ++ ++typedef enum _NDIS_802_11_RELOAD_DEFAULTS ++{ ++ Ndis802_11ReloadWEPKeys ++} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++typedef struct _NDIS_802_11_AI_REQFI ++{ ++ USHORT Capabilities; ++ USHORT ListenInterval; ++ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; ++} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; ++ ++typedef struct _NDIS_802_11_AI_RESFI ++{ ++ USHORT Capabilities; ++ USHORT StatusCode; ++ USHORT AssociationId; ++} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; ++ ++typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION ++{ ++ ULONG Length; ++ USHORT AvailableRequestFixedIEs; ++ NDIS_802_11_AI_REQFI RequestFixedIEs; ++ ULONG RequestIELength; ++ ULONG OffsetRequestIEs; ++ USHORT AvailableResponseFixedIEs; ++ NDIS_802_11_AI_RESFI ResponseFixedIEs; ++ ULONG ResponseIELength; ++ ULONG OffsetResponseIEs; ++} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_EVENT ++{ ++ NDIS_802_11_STATUS_INDICATION Status; ++ NDIS_802_11_AUTHENTICATION_REQUEST Request[1]; ++} NDIS_802_11_AUTHENTICATION_EVENT, *PNDIS_802_11_AUTHENTICATION_EVENT; ++ ++/* ++typedef struct _NDIS_802_11_TEST ++{ ++ ULONG Length; ++ ULONG Type; ++ union ++ { ++ NDIS_802_11_AUTHENTICATION_EVENT AuthenticationEvent; ++ NDIS_802_11_RSSI RssiTrigger; ++ }; ++} NDIS_802_11_TEST, *PNDIS_802_11_TEST; ++ */ ++ ++// 802.11 Media stream constraints, associated with OID_802_11_MEDIA_STREAM_MODE ++typedef enum _NDIS_802_11_MEDIA_STREAM_MODE ++{ ++ Ndis802_11MediaStreamOff, ++ Ndis802_11MediaStreamOn, ++} NDIS_802_11_MEDIA_STREAM_MODE, *PNDIS_802_11_MEDIA_STREAM_MODE; ++ ++// PMKID Structures ++typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef struct _BSSID_INFO ++{ ++ NDIS_802_11_MAC_ADDRESS BSSID; ++ NDIS_802_11_PMKID_VALUE PMKID; ++} BSSID_INFO, *PBSSID_INFO; ++ ++typedef struct _NDIS_802_11_PMKID ++{ ++ UINT Length; ++ UINT BSSIDInfoCount; ++ BSSID_INFO BSSIDInfo[1]; ++} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION ++{ ++ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; ++ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; ++} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; ++ ++typedef struct _NDIS_802_11_CAPABILITY ++{ ++ ULONG Length; ++ ULONG Version; ++ ULONG NoOfPMKIDs; ++ ULONG NoOfAuthEncryptPairsSupported; ++ NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; ++} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; ++ ++//#endif //of WIN 2k ++#endif //UNDER_CE ++ ++#if WIRELESS_EXT <= 11 ++#ifndef SIOCDEVPRIVATE ++#define SIOCDEVPRIVATE 0x8BE0 ++#endif ++#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE ++#endif ++ ++#ifdef CONFIG_STA_SUPPORT ++#define RT_PRIV_IOCTL_EXT (SIOCIWFIRSTPRIV + 0x01) // Sync. with AP for wsc upnp daemon ++#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) ++ ++#ifdef DBG ++#define RTPRIV_IOCTL_BBP (SIOCIWFIRSTPRIV + 0x03) ++#define RTPRIV_IOCTL_MAC (SIOCIWFIRSTPRIV + 0x05) ++#define RTPRIV_IOCTL_RF (SIOCIWFIRSTPRIV + 0x13) ++#define RTPRIV_IOCTL_E2P (SIOCIWFIRSTPRIV + 0x07) ++#endif ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++#define RTPRIV_IOCTL_ATE (SIOCIWFIRSTPRIV + 0x08) ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#define RTPRIV_IOCTL_STATISTICS (SIOCIWFIRSTPRIV + 0x09) ++#define RTPRIV_IOCTL_ADD_PMKID_CACHE (SIOCIWFIRSTPRIV + 0x0A) ++#define RTPRIV_IOCTL_RADIUS_DATA (SIOCIWFIRSTPRIV + 0x0C) ++#define RTPRIV_IOCTL_GSITESURVEY (SIOCIWFIRSTPRIV + 0x0D) ++#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) // Sync. with RT61 (for wpa_supplicant) ++#define RTPRIV_IOCTL_GET_MAC_TABLE (SIOCIWFIRSTPRIV + 0x0F) ++ ++#define RTPRIV_IOCTL_SHOW (SIOCIWFIRSTPRIV + 0x11) ++enum { ++ SHOW_CONN_STATUS = 4, ++ SHOW_DRVIER_VERION = 5, ++ SHOW_BA_INFO = 6, ++ SHOW_DESC_INFO = 7, ++#ifdef RT2870 ++ SHOW_RXBULK_INFO = 8, ++ SHOW_TXBULK_INFO = 9, ++#endif // RT2870 // ++ RAIO_OFF = 10, ++ RAIO_ON = 11, ++#ifdef QOS_DLS_SUPPORT ++ SHOW_DLS_ENTRY_INFO = 19, ++#endif // QOS_DLS_SUPPORT // ++ SHOW_CFG_VALUE = 20, ++}; ++ ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++#ifdef SNMP_SUPPORT ++//SNMP ieee 802dot11, kathy , 2008_0220 ++// dot11res(3) ++#define RT_OID_802_11_MANUFACTUREROUI 0x0700 ++#define RT_OID_802_11_MANUFACTURERNAME 0x0701 ++#define RT_OID_802_11_RESOURCETYPEIDNAME 0x0702 ++ ++// dot11smt(1) ++#define RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED 0x0703 ++#define RT_OID_802_11_POWERMANAGEMENTMODE 0x0704 ++#define OID_802_11_WEPDEFAULTKEYVALUE 0x0705 // read , write ++#define OID_802_11_WEPDEFAULTKEYID 0x0706 ++#define RT_OID_802_11_WEPKEYMAPPINGLENGTH 0x0707 ++#define OID_802_11_SHORTRETRYLIMIT 0x0708 ++#define OID_802_11_LONGRETRYLIMIT 0x0709 ++#define RT_OID_802_11_PRODUCTID 0x0710 ++#define RT_OID_802_11_MANUFACTUREID 0x0711 ++ ++// //dot11Phy(4) ++#define OID_802_11_CURRENTCHANNEL 0x0712 ++ ++//dot11mac ++#define RT_OID_802_11_MAC_ADDRESS 0x0713 ++#endif // SNMP_SUPPORT // ++ ++#define OID_802_11_BUILD_CHANNEL_EX 0x0714 ++#define OID_802_11_GET_CH_LIST 0x0715 ++#define OID_802_11_GET_COUNTRY_CODE 0x0716 ++#define OID_802_11_GET_CHANNEL_GEOGRAPHY 0x0717 ++ ++//#define RT_OID_802_11_STATISTICS (OID_GET_SET_TOGGLE | OID_802_11_STATISTICS) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define RT_OID_WSC_SET_PASSPHRASE 0x0740 // passphrase for wpa(2)-psk ++#define RT_OID_WSC_DRIVER_AUTO_CONNECT 0x0741 ++#define RT_OID_WSC_QUERY_DEFAULT_PROFILE 0x0742 ++#define RT_OID_WSC_SET_CONN_BY_PROFILE_INDEX 0x0743 ++#define RT_OID_WSC_SET_ACTION 0x0744 ++#define RT_OID_WSC_SET_SSID 0x0745 ++#define RT_OID_WSC_SET_PIN_CODE 0x0746 ++#define RT_OID_WSC_SET_MODE 0x0747 // PIN or PBC ++#define RT_OID_WSC_SET_CONF_MODE 0x0748 // Enrollee or Registrar ++#define RT_OID_WSC_SET_PROFILE 0x0749 ++#endif // CONFIG_STA_SUPPORT // ++#define RT_OID_802_11_WSC_QUERY_PROFILE 0x0750 ++// for consistency with RT61 ++#define RT_OID_WSC_QUERY_STATUS 0x0751 ++#define RT_OID_WSC_PIN_CODE 0x0752 ++#define RT_OID_WSC_UUID 0x0753 ++#define RT_OID_WSC_SET_SELECTED_REGISTRAR 0x0754 ++#define RT_OID_WSC_EAPMSG 0x0755 ++#define RT_OID_WSC_MANUFACTURER 0x0756 ++#define RT_OID_WSC_MODEL_NAME 0x0757 ++#define RT_OID_WSC_MODEL_NO 0x0758 ++#define RT_OID_WSC_SERIAL_NO 0x0759 ++#define RT_OID_WSC_MAC_ADDRESS 0x0760 ++ ++#ifdef LLTD_SUPPORT ++// for consistency with RT61 ++#define RT_OID_GET_PHY_MODE 0x761 ++#endif // LLTD_SUPPORT // ++ ++#ifdef NINTENDO_AP ++//#define RT_OID_NINTENDO 0x0D010770 ++#define RT_OID_802_11_NINTENDO_GET_TABLE 0x0771 //((RT_OID_NINTENDO + 0x01) & 0xffff) ++#define RT_OID_802_11_NINTENDO_SET_TABLE 0x0772 //((RT_OID_NINTENDO + 0x02) & 0xffff) ++#define RT_OID_802_11_NINTENDO_CAPABLE 0x0773 //((RT_OID_NINTENDO + 0x03) & 0xffff) ++#endif // NINTENDO_AP // ++ ++//Add Paul Chen for Accton ++//#define RT_OID_TX_POWER_LEVEL 0xFF020010 ++//#define RT_OID_SET_TX_POWER_LEVEL (OID_GET_SET_TOGGLE | RT_OID_TX_POWER_LEVEL) ++ ++// New for MeetingHouse Api support ++#define OID_MH_802_1X_SUPPORTED 0xFFEDC100 ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! ++typedef union _HTTRANSMIT_SETTING { ++#ifdef RT_BIG_ENDIAN ++ struct { ++ USHORT MODE:2; // Use definition MODE_xxx. ++// USHORT rsv:3; ++ USHORT TxBF:1; ++ USHORT rsv:2; ++ USHORT STBC:2; //SPACE ++ USHORT ShortGI:1; ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT MCS:7; // MCS ++ } field; ++#else ++ struct { ++ USHORT MCS:7; // MCS ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++// USHORT rsv:3; ++ USHORT rsv:2; ++ USHORT TxBF:1; ++ USHORT MODE:2; // Use definition MODE_xxx. ++ } field; ++#endif ++ USHORT word; ++ } HTTRANSMIT_SETTING, *PHTTRANSMIT_SETTING; ++ ++typedef enum _RT_802_11_PREAMBLE { ++ Rt802_11PreambleLong, ++ Rt802_11PreambleShort, ++ Rt802_11PreambleAuto ++} RT_802_11_PREAMBLE, *PRT_802_11_PREAMBLE; ++ ++// Only for STA, need to sync with AP ++// 2005-03-08 match current RaConfig. ++typedef enum _RT_802_11_PHY_MODE { ++ PHY_11BG_MIXED = 0, ++ PHY_11B, ++ PHY_11A, ++ PHY_11ABG_MIXED, ++ PHY_11G, ++#ifdef DOT11_N_SUPPORT ++ PHY_11ABGN_MIXED, // both band 5 ++ PHY_11N_2_4G, // 11n-only with 2.4G band 6 ++ PHY_11GN_MIXED, // 2.4G band 7 ++ PHY_11AN_MIXED, // 5G band 8 ++ PHY_11BGN_MIXED, // if check 802.11b. 9 ++ PHY_11AGN_MIXED, // if check 802.11b. 10 ++ PHY_11N_5G, // 11n-only with 5G band 11 ++#endif // DOT11_N_SUPPORT // ++} RT_802_11_PHY_MODE; ++ ++// put all proprietery for-query objects here to reduce # of Query_OID ++typedef struct _RT_802_11_LINK_STATUS { ++ ULONG CurrTxRate; // in units of 0.5Mbps ++ ULONG ChannelQuality; // 0..100 % ++ ULONG TxByteCount; // both ok and fail ++ ULONG RxByteCount; // both ok and fail ++ ULONG CentralChannel; // 40MHz central channel number ++} RT_802_11_LINK_STATUS, *PRT_802_11_LINK_STATUS; ++ ++typedef struct _RT_802_11_EVENT_LOG { ++ LARGE_INTEGER SystemTime; // timestammp via NdisGetCurrentSystemTime() ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ USHORT Event; // EVENT_xxx ++} RT_802_11_EVENT_LOG, *PRT_802_11_EVENT_LOG; ++ ++typedef struct _RT_802_11_EVENT_TABLE { ++ ULONG Num; ++ ULONG Rsv; // to align Log[] at LARGE_INEGER boundary ++ RT_802_11_EVENT_LOG Log[MAX_NUMBER_OF_EVENT]; ++} RT_802_11_EVENT_TABLE, PRT_802_11_EVENT_TABLE; ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI. Don't change this definition!!! ++typedef union _MACHTTRANSMIT_SETTING { ++ struct { ++ USHORT MCS:7; // MCS ++ USHORT BW:1; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:3; ++ USHORT MODE:2; // Use definition MODE_xxx. ++ } field; ++ USHORT word; ++ } MACHTTRANSMIT_SETTING, *PMACHTTRANSMIT_SETTING; ++ ++typedef struct _RT_802_11_MAC_ENTRY { ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ UCHAR Aid; ++ UCHAR Psm; // 0:PWR_ACTIVE, 1:PWR_SAVE ++ UCHAR MimoPs; // 0:MMPS_STATIC, 1:MMPS_DYNAMIC, 3:MMPS_Enabled ++ CHAR AvgRssi0; ++ CHAR AvgRssi1; ++ CHAR AvgRssi2; ++ UINT32 ConnectedTime; ++ MACHTTRANSMIT_SETTING TxRate; ++} RT_802_11_MAC_ENTRY, *PRT_802_11_MAC_ENTRY; ++ ++typedef struct _RT_802_11_MAC_TABLE { ++ ULONG Num; ++ RT_802_11_MAC_ENTRY Entry[MAX_NUMBER_OF_MAC]; ++} RT_802_11_MAC_TABLE, *PRT_802_11_MAC_TABLE; ++ ++// structure for query/set hardware register - MAC, BBP, RF register ++typedef struct _RT_802_11_HARDWARE_REGISTER { ++ ULONG HardwareType; // 0:MAC, 1:BBP, 2:RF register, 3:EEPROM ++ ULONG Offset; // Q/S register offset addr ++ ULONG Data; // R/W data buffer ++} RT_802_11_HARDWARE_REGISTER, *PRT_802_11_HARDWARE_REGISTER; ++ ++// structure to tune BBP R17 "RX AGC VGC init" ++//typedef struct _RT_802_11_RX_AGC_VGC_TUNING { ++// UCHAR FalseCcaLowerThreshold; // 0-255, def 10 ++// UCHAR FalseCcaUpperThreshold; // 0-255, def 100 ++// UCHAR VgcDelta; // R17 +-= VgcDelta whenever flase CCA over UpprThreshold ++// // or lower than LowerThresholdupper threshold ++// UCHAR VgcUpperBound; // max value of R17 ++//} RT_802_11_RX_AGC_VGC_TUNING, *PRT_802_11_RX_AGC_VGC_TUNING; ++ ++typedef struct _RT_802_11_AP_CONFIG { ++ ULONG EnableTxBurst; // 0-disable, 1-enable ++ ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate ++ ULONG IsolateInterStaTraffic; // 0-disable, 1-enable isolation ++ ULONG HideSsid; // 0-disable, 1-enable hiding ++ ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF ++ ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time ++ ULONG Rsv1; // must be 0 ++ ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY ++} RT_802_11_AP_CONFIG, *PRT_802_11_AP_CONFIG; ++ ++// structure to query/set STA_CONFIG ++typedef struct _RT_802_11_STA_CONFIG { ++ ULONG EnableTxBurst; // 0-disable, 1-enable ++ ULONG EnableTurboRate; // 0-disable, 1-enable 72/100mbps turbo rate ++ ULONG UseBGProtection; // 0-AUTO, 1-always ON, 2-always OFF ++ ULONG UseShortSlotTime; // 0-no use, 1-use 9-us short slot time when applicable ++ ULONG AdhocMode; // 0-11b rates only (WIFI spec), 1 - b/g mixed, 2 - g only ++ ULONG HwRadioStatus; // 0-OFF, 1-ON, default is 1, Read-Only ++ ULONG Rsv1; // must be 0 ++ ULONG SystemErrorBitmap; // ignore upon SET, return system error upon QUERY ++} RT_802_11_STA_CONFIG, *PRT_802_11_STA_CONFIG; ++ ++// ++// For OID Query or Set about BA structure ++// ++typedef struct _OID_BACAP_STRUC { ++ UCHAR RxBAWinLimit; ++ UCHAR TxBAWinLimit; ++ UCHAR Policy; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid ++ UCHAR MpduDensity; // 0: DELAY_BA 1:IMMED_BA (//BA Policy subfiled value in ADDBA frame) 2:BA-not use. other value invalid ++ UCHAR AmsduEnable; //Enable AMSDU transmisstion ++ UCHAR AmsduSize; // 0:3839, 1:7935 bytes. UINT MSDUSizeToBytes[] = { 3839, 7935}; ++ UCHAR MMPSmode; // MIMO power save more, 0:static, 1:dynamic, 2:rsv, 3:mimo enable ++ BOOLEAN AutoBA; // Auto BA will automatically ++} OID_BACAP_STRUC, *POID_BACAP_STRUC; ++ ++typedef struct _RT_802_11_ACL_ENTRY { ++ UCHAR Addr[MAC_ADDR_LENGTH]; ++ USHORT Rsv; ++} RT_802_11_ACL_ENTRY, *PRT_802_11_ACL_ENTRY; ++ ++typedef struct PACKED _RT_802_11_ACL { ++ ULONG Policy; // 0-disable, 1-positive list, 2-negative list ++ ULONG Num; ++ RT_802_11_ACL_ENTRY Entry[MAX_NUMBER_OF_ACL]; ++} RT_802_11_ACL, *PRT_802_11_ACL; ++ ++typedef struct _RT_802_11_WDS { ++ ULONG Num; ++ NDIS_802_11_MAC_ADDRESS Entry[24/*MAX_NUM_OF_WDS_LINK*/]; ++ ULONG KeyLength; ++ UCHAR KeyMaterial[32]; ++} RT_802_11_WDS, *PRT_802_11_WDS; ++ ++typedef struct _RT_802_11_TX_RATES_ { ++ UCHAR SupRateLen; ++ UCHAR SupRate[MAX_LENGTH_OF_SUPPORT_RATES]; ++ UCHAR ExtRateLen; ++ UCHAR ExtRate[MAX_LENGTH_OF_SUPPORT_RATES]; ++} RT_802_11_TX_RATES, *PRT_802_11_TX_RATES; ++ ++ ++// Definition of extra information code ++#define GENERAL_LINK_UP 0x0 // Link is Up ++#define GENERAL_LINK_DOWN 0x1 // Link is Down ++#define HW_RADIO_OFF 0x2 // Hardware radio off ++#define SW_RADIO_OFF 0x3 // Software radio off ++#define AUTH_FAIL 0x4 // Open authentication fail ++#define AUTH_FAIL_KEYS 0x5 // Shared authentication fail ++#define ASSOC_FAIL 0x6 // Association failed ++#define EAP_MIC_FAILURE 0x7 // Deauthencation because MIC failure ++#define EAP_4WAY_TIMEOUT 0x8 // Deauthencation on 4-way handshake timeout ++#define EAP_GROUP_KEY_TIMEOUT 0x9 // Deauthencation on group key handshake timeout ++#define EAP_SUCCESS 0xa // EAP succeed ++#define DETECT_RADAR_SIGNAL 0xb // Radar signal occur in current channel ++#define EXTRA_INFO_MAX 0xb // Indicate Last OID ++ ++#define EXTRA_INFO_CLEAR 0xffffffff ++ ++// This is OID setting structure. So only GF or MM as Mode. This is valid when our wirelss mode has 802.11n in use. ++typedef struct { ++ RT_802_11_PHY_MODE PhyMode; // ++ UCHAR TransmitNo; ++ UCHAR HtMode; //HTMODE_GF or HTMODE_MM ++ UCHAR ExtOffset; //extension channel above or below ++ UCHAR MCS; ++ UCHAR BW; ++ UCHAR STBC; ++ UCHAR SHORTGI; ++ UCHAR rsv; ++} OID_SET_HT_PHYMODE, *POID_SET_HT_PHYMODE; ++ ++#ifdef NINTENDO_AP ++#define NINTENDO_MAX_ENTRY 16 ++#define NINTENDO_SSID_NAME_LN 8 ++#define NINTENDO_SSID_NAME "NWCUSBAP" ++#define NINTENDO_PROBE_REQ_FLAG_MASK 0x03 ++#define NINTENDO_PROBE_REQ_ON 0x01 ++#define NINTENDO_PROBE_REQ_SIGNAL 0x02 ++#define NINTENDO_PROBE_RSP_ON 0x01 ++#define NINTENDO_SSID_NICKNAME_LN 20 ++ ++#define NINTENDO_WEPKEY_LN 13 ++ ++typedef struct _NINTENDO_SSID ++{ ++ UCHAR NINTENDOFixChar[NINTENDO_SSID_NAME_LN]; ++ UCHAR zero1; ++ UCHAR registe; ++ UCHAR ID; ++ UCHAR zero2; ++ UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; ++} RT_NINTENDO_SSID, *PRT_NINTENDO_SSID; ++ ++typedef struct _NINTENDO_ENTRY ++{ ++ UCHAR NICKname[NINTENDO_SSID_NICKNAME_LN]; ++ UCHAR DS_Addr[ETH_LENGTH_OF_ADDRESS]; ++ UCHAR registe; ++ UCHAR UserSpaceAck; ++} RT_NINTENDO_ENTRY, *PRT_NINTENDO_ENTRY; ++ ++//RTPRIV_IOCTL_NINTENDO_GET_TABLE ++//RTPRIV_IOCTL_NINTENDO_SET_TABLE ++typedef struct _NINTENDO_TABLE ++{ ++ UINT number; ++ RT_NINTENDO_ENTRY entry[NINTENDO_MAX_ENTRY]; ++} RT_NINTENDO_TABLE, *PRT_NINTENDO_TABLE; ++ ++//RTPRIV_IOCTL_NINTENDO_SEED_WEPKEY ++typedef struct _NINTENDO_SEED_WEPKEY ++{ ++ UCHAR seed[NINTENDO_SSID_NICKNAME_LN]; ++ UCHAR wepkey[16];//use 13 for 104 bits wep key ++} RT_NINTENDO_SEED_WEPKEY, *PRT_NINTENDO_SEED_WEPKEY; ++#endif // NINTENDO_AP // ++ ++#ifdef LLTD_SUPPORT ++typedef struct _RT_LLTD_ASSOICATION_ENTRY { ++ UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; ++ unsigned short MOR; // maximum operational rate ++ UCHAR phyMode; ++} RT_LLTD_ASSOICATION_ENTRY, *PRT_LLTD_ASSOICATION_ENTRY; ++ ++typedef struct _RT_LLTD_ASSOICATION_TABLE { ++ unsigned int Num; ++ RT_LLTD_ASSOICATION_ENTRY Entry[MAX_NUMBER_OF_MAC]; ++} RT_LLTD_ASSOICATION_TABLE, *PRT_LLTD_ASSOICATION_TABLE; ++#endif // LLTD_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++//rt2860, kathy 2007-0118 ++// structure for DLS ++typedef struct _RT_802_11_DLS_UI { ++ USHORT TimeOut; // unit: second , set by UI ++ USHORT CountDownTimer; // unit: second , used by driver only ++ NDIS_802_11_MAC_ADDRESS MacAddr; // set by UI ++ UCHAR Status; // 0: none , 1: wait STAkey, 2: finish DLS setup , set by driver only ++ BOOLEAN Valid; // 1: valid , 0: invalid , set by UI, use to setup or tear down DLS link ++} RT_802_11_DLS_UI, *PRT_802_11_DLS_UI; ++ ++typedef struct _RT_802_11_DLS_INFO { ++ RT_802_11_DLS_UI Entry[MAX_NUMBER_OF_DLS_ENTRY]; ++ UCHAR num; ++} RT_802_11_DLS_INFO, *PRT_802_11_DLS_INFO; ++ ++typedef enum _RT_802_11_DLS_MODE { ++ DLS_NONE, ++ DLS_WAIT_KEY, ++ DLS_FINISH ++} RT_802_11_DLS_MODE; ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++#define RT_ASSOC_EVENT_FLAG 0x0101 ++#define RT_DISASSOC_EVENT_FLAG 0x0102 ++#define RT_REQIE_EVENT_FLAG 0x0103 ++#define RT_RESPIE_EVENT_FLAG 0x0104 ++#define RT_ASSOCINFO_EVENT_FLAG 0x0105 ++#define RT_PMKIDCAND_FLAG 0x0106 ++#define RT_INTERFACE_DOWN 0x0107 ++#define RT_INTERFACE_UP 0x0108 ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#define MAX_CUSTOM_LEN 128 ++ ++#ifdef CONFIG_STA_SUPPORT ++typedef enum _RT_802_11_D_CLIENT_MODE ++{ ++ Rt802_11_D_None, ++ Rt802_11_D_Flexible, ++ Rt802_11_D_Strict, ++} RT_802_11_D_CLIENT_MODE, *PRT_802_11_D_CLIENT_MODE; ++#endif // CONFIG_STA_SUPPORT // ++ ++typedef struct _RT_CHANNEL_LIST_INFO ++{ ++ UCHAR ChannelList[MAX_NUM_OF_CHS]; // list all supported channels for site survey ++ UCHAR ChannelListNum; // number of channel in ChannelList[] ++} RT_CHANNEL_LIST_INFO, *PRT_CHANNEL_LIST_INFO; ++ ++// WSC configured credential ++typedef struct _WSC_CREDENTIAL ++{ ++ NDIS_802_11_SSID SSID; // mandatory ++ USHORT AuthType; // mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk ++ USHORT EncrType; // mandatory, 1: none, 2: wep, 4: tkip, 8: aes ++ UCHAR Key[64]; // mandatory, Maximum 64 byte ++ USHORT KeyLength; ++ UCHAR MacAddr[6]; // mandatory, AP MAC address ++ UCHAR KeyIndex; // optional, default is 1 ++ UCHAR Rsvd[3]; // Make alignment ++} WSC_CREDENTIAL, *PWSC_CREDENTIAL; ++ ++// WSC configured profiles ++typedef struct _WSC_PROFILE ++{ ++ UINT ProfileCnt; ++ WSC_CREDENTIAL Profile[8]; // Support up to 8 profiles ++} WSC_PROFILE, *PWSC_PROFILE; ++ ++ ++ ++#endif // _OID_H_ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rt2870.h +@@ -0,0 +1,756 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __RT2870_H__ ++#define __RT2870_H__ ++ ++//usb header files ++#include ++ ++/* rtmp_def.h */ ++// ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define BULKAGGRE_ZISE 100 ++#define RT28XX_DRVDATA_SET(_a) usb_set_intfdata(_a, pAd); ++#define RT28XX_PUT_DEVICE usb_put_dev ++#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso, GFP_ATOMIC) ++#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb, GFP_ATOMIC) ++#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) usb_buffer_alloc(pUsb_Dev, BufSize, GFP_ATOMIC, pDma_addr) ++#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) usb_buffer_free(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) ++#else ++#define BULKAGGRE_ZISE 60 ++#define RT28XX_DRVDATA_SET(_a) ++#define RT28XX_PUT_DEVICE(dev_p) ++#define RTUSB_ALLOC_URB(iso) usb_alloc_urb(iso) ++#define RTUSB_SUBMIT_URB(pUrb) usb_submit_urb(pUrb) ++#define RTUSB_URB_ALLOC_BUFFER(pUsb_Dev, BufSize, pDma_addr) kmalloc(BufSize, GFP_ATOMIC) ++#define RTUSB_URB_FREE_BUFFER(pUsb_Dev, BufSize, pTransferBuf, Dma_addr) kfree(pTransferBuf) ++#endif ++ ++#define RXBULKAGGRE_ZISE 12 ++#define MAX_TXBULK_LIMIT (LOCAL_TXBUF_SIZE*(BULKAGGRE_ZISE-1)) ++#define MAX_TXBULK_SIZE (LOCAL_TXBUF_SIZE*BULKAGGRE_ZISE) ++#define MAX_RXBULK_SIZE (LOCAL_TXBUF_SIZE*RXBULKAGGRE_ZISE) ++#define MAX_MLME_HANDLER_MEMORY 20 ++#define BUFFER_SIZE 2400 //2048 ++#define TX_RING 0xa ++#define PRIO_RING 0xc ++ ++ ++// Flags for Bulkflags control for bulk out data ++// ++#define fRTUSB_BULK_OUT_DATA_NULL 0x00000001 ++#define fRTUSB_BULK_OUT_RTS 0x00000002 ++#define fRTUSB_BULK_OUT_MLME 0x00000004 ++ ++#define fRTUSB_BULK_OUT_DATA_NORMAL 0x00010000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_2 0x00020000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_3 0x00040000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_4 0x00080000 ++#define fRTUSB_BULK_OUT_DATA_NORMAL_5 0x00100000 ++ ++#define fRTUSB_BULK_OUT_PSPOLL 0x00000020 ++#define fRTUSB_BULK_OUT_DATA_FRAG 0x00000040 ++#define fRTUSB_BULK_OUT_DATA_FRAG_2 0x00000080 ++#define fRTUSB_BULK_OUT_DATA_FRAG_3 0x00000100 ++#define fRTUSB_BULK_OUT_DATA_FRAG_4 0x00000200 ++ ++#ifdef RALINK_ATE ++#define fRTUSB_BULK_OUT_DATA_ATE 0x00100000 ++#endif // RALINK_ATE // ++ ++#define RT2870_USB_DEVICES \ ++{ \ ++ {USB_DEVICE(0x148F,0x2770)}, /* Ralink */ \ ++ {USB_DEVICE(0x148F,0x2870)}, /* Ralink */ \ ++ {USB_DEVICE(0x148F,0x3070)}, /* Ralink 3070 */ \ ++ {USB_DEVICE(0x148F,0x3071)}, /* Ralink 3071 */ \ ++ {USB_DEVICE(0x148F,0x3072)}, /* Ralink 3072 */ \ ++ {USB_DEVICE(0x0B05,0x1731)}, /* Asus */ \ ++ {USB_DEVICE(0x0B05,0x1732)}, /* Asus */ \ ++ {USB_DEVICE(0x0B05,0x1742)}, /* Asus */ \ ++ {USB_DEVICE(0x0DF6,0x0017)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x002B)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x002C)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x003E)}, /* Sitecom 3070 */ \ ++ {USB_DEVICE(0x0DF6,0x002D)}, /* Sitecom */ \ ++ {USB_DEVICE(0x0DF6,0x0039)}, /* Sitecom 2770 */ \ ++ {USB_DEVICE(0x14B2,0x3C06)}, /* Conceptronic */ \ ++ {USB_DEVICE(0x14B2,0x3C28)}, /* Conceptronic */ \ ++ {USB_DEVICE(0x2019,0xED06)}, /* Planex Communications, Inc. */ \ ++ {USB_DEVICE(0x2019,0xAB25)}, /* Planex Communications, Inc. RT3070 */ \ ++ {USB_DEVICE(0x07D1,0x3C09)}, /* D-Link */ \ ++ {USB_DEVICE(0x07D1,0x3C11)}, /* D-Link */ \ ++ {USB_DEVICE(0x2001,0x3C09)}, /* D-Link */ \ ++ {USB_DEVICE(0x2001,0x3C0A)}, /* D-Link 3072*/ \ ++ {USB_DEVICE(0x14B2,0x3C07)}, /* AL */ \ ++ {USB_DEVICE(0x14B2,0x3C12)}, /* AL 3070 */ \ ++ {USB_DEVICE(0x050D,0x8053)}, /* Belkin */ \ ++ {USB_DEVICE(0x14B2,0x3C23)}, /* Airlink */ \ ++ {USB_DEVICE(0x14B2,0x3C27)}, /* Airlink */ \ ++ {USB_DEVICE(0x07AA,0x002F)}, /* Corega */ \ ++ {USB_DEVICE(0x07AA,0x003C)}, /* Corega */ \ ++ {USB_DEVICE(0x07AA,0x003F)}, /* Corega */ \ ++ {USB_DEVICE(0x18C5,0x0012)}, /* Corega 3070 */ \ ++ {USB_DEVICE(0x1044,0x800B)}, /* Gigabyte */ \ ++ {USB_DEVICE(0x1044,0x800D)}, /* Gigabyte GN-WB32L 3070 */ \ ++ {USB_DEVICE(0x15A9,0x0006)}, /* Sparklan */ \ ++ {USB_DEVICE(0x083A,0xB522)}, /* SMC */ \ ++ {USB_DEVICE(0x083A,0xA618)}, /* SMC */ \ ++ {USB_DEVICE(0x083A,0x8522)}, /* Arcadyan */ \ ++ {USB_DEVICE(0x083A,0x7512)}, /* Arcadyan 2770 */ \ ++ {USB_DEVICE(0x083A,0x7522)}, /* Arcadyan */ \ ++ {USB_DEVICE(0x083A,0x7511)}, /* Arcadyan 3070 */ \ ++ {USB_DEVICE(0x0CDE,0x0022)}, /* ZCOM */ \ ++ {USB_DEVICE(0x0586,0x3416)}, /* Zyxel */ \ ++ {USB_DEVICE(0x0CDE,0x0025)}, /* Zyxel */ \ ++ {USB_DEVICE(0x1740,0x9701)}, /* EnGenius */ \ ++ {USB_DEVICE(0x1740,0x9702)}, /* EnGenius */ \ ++ {USB_DEVICE(0x1740,0x9703)}, /* EnGenius 3070 */ \ ++ {USB_DEVICE(0x0471,0x200f)}, /* Philips */ \ ++ {USB_DEVICE(0x14B2,0x3C25)}, /* Draytek */ \ ++ {USB_DEVICE(0x13D3,0x3247)}, /* AzureWave */ \ ++ {USB_DEVICE(0x13D3,0x3273)}, /* AzureWave 3070*/ \ ++ {USB_DEVICE(0x083A,0x6618)}, /* Accton */ \ ++ {USB_DEVICE(0x15c5,0x0008)}, /* Amit */ \ ++ {USB_DEVICE(0x0E66,0x0001)}, /* Hawking */ \ ++ {USB_DEVICE(0x0E66,0x0003)}, /* Hawking */ \ ++ {USB_DEVICE(0x129B,0x1828)}, /* Siemens */ \ ++ {USB_DEVICE(0x157E,0x300E)}, /* U-Media */ \ ++ {USB_DEVICE(0x050d,0x805c)}, \ ++ {USB_DEVICE(0x1482,0x3C09)}, /* Abocom*/ \ ++ {USB_DEVICE(0x14B2,0x3C09)}, /* Alpha */ \ ++ {USB_DEVICE(0x04E8,0x2018)}, /* samsung */ \ ++ {USB_DEVICE(0x07B8,0x3070)}, /* AboCom 3070 */ \ ++ {USB_DEVICE(0x07B8,0x3071)}, /* AboCom 3071 */ \ ++ {USB_DEVICE(0x07B8,0x3072)}, /* Abocom 3072 */ \ ++ {USB_DEVICE(0x7392,0x7711)}, /* Edimax 3070 */ \ ++ {USB_DEVICE(0x5A57,0x0280)}, /* Zinwell */ \ ++ {USB_DEVICE(0x5A57,0x0282)}, /* Zinwell */ \ ++ {USB_DEVICE(0x1A32,0x0304)}, /* Quanta 3070 */ \ ++ {USB_DEVICE(0x0789,0x0162)}, /* Logitec 2870 */ \ ++ {USB_DEVICE(0x0789,0x0163)}, /* Logitec 2870 */ \ ++ {USB_DEVICE(0x0789,0x0164)}, /* Logitec 2870 */ \ ++ {USB_DEVICE(0x1EDA,0x2310)}, /* AirTies 3070 */ \ ++ { }/* Terminating entry */ \ ++} ++ ++#define FREE_HTTX_RING(_p, _b, _t) \ ++{ \ ++ if ((_t)->ENextBulkOutPosition == (_t)->CurWritePosition) \ ++ { \ ++ (_t)->bRingEmpty = TRUE; \ ++ } \ ++ /*NdisInterlockedDecrement(&(_p)->TxCount); */\ ++} ++ ++// ++// RXINFO appends at the end of each rx packet. ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _RXINFO_STRUC { ++ UINT32 PlcpSignal:12; ++ UINT32 LastAMSDU:1; ++ UINT32 CipherAlg:1; ++ UINT32 PlcpRssil:1; ++ UINT32 Decrypted:1; ++ UINT32 AMPDU:1; // To be moved ++ UINT32 L2PAD:1; ++ UINT32 RSSI:1; ++ UINT32 HTC:1; ++ UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. ++ UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid ++ UINT32 Crc:1; // 1: CRC error ++ UINT32 MyBss:1; // 1: this frame belongs to the same BSSID ++ UINT32 Bcast:1; // 1: this is a broadcast frame ++ UINT32 Mcast:1; // 1: this is a multicast frame ++ UINT32 U2M:1; // 1: this RX frame is unicast to me ++ UINT32 FRAG:1; ++ UINT32 NULLDATA:1; ++ UINT32 DATA:1; ++ UINT32 BA:1; ++} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; ++#else ++typedef struct PACKED _RXINFO_STRUC { ++ UINT32 BA:1; ++ UINT32 DATA:1; ++ UINT32 NULLDATA:1; ++ UINT32 FRAG:1; ++ UINT32 U2M:1; // 1: this RX frame is unicast to me ++ UINT32 Mcast:1; // 1: this is a multicast frame ++ UINT32 Bcast:1; // 1: this is a broadcast frame ++ UINT32 MyBss:1; // 1: this frame belongs to the same BSSID ++ UINT32 Crc:1; // 1: CRC error ++ UINT32 CipherErr:2; // 0: decryption okay, 1:ICV error, 2:MIC error, 3:KEY not valid ++ UINT32 AMSDU:1; // rx with 802.3 header, not 802.11 header. ++ UINT32 HTC:1; ++ UINT32 RSSI:1; ++ UINT32 L2PAD:1; ++ UINT32 AMPDU:1; // To be moved ++ UINT32 Decrypted:1; ++ UINT32 PlcpRssil:1; ++ UINT32 CipherAlg:1; ++ UINT32 LastAMSDU:1; ++ UINT32 PlcpSignal:12; ++} RXINFO_STRUC, *PRXINFO_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; ++#endif ++ ++ ++// ++// TXINFO ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct _TXINFO_STRUC { ++ // Word 0 ++ UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint ++ UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid ++ UINT32 rsv2:2; // Software use. ++ UINT32 SwUseLastRound:1; // Software use. ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 rsv:8; ++ UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. ++} TXINFO_STRUC, *PTXINFO_STRUC; ++#else ++typedef struct _TXINFO_STRUC { ++ // Word 0 ++ UINT32 USBDMATxPktLen:16; //used ONLY in USB bulk Aggregation, Total byte counts of all sub-frame. ++ UINT32 rsv:8; ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 SwUseLastRound:1; // Software use. ++ UINT32 rsv2:2; // Software use. ++ UINT32 USBDMANextVLD:1; //used ONLY in USB bulk Aggregation, NextValid ++ UINT32 USBDMATxburst:1;//used ONLY in USB bulk Aggre. Force USB DMA transmit frame from current selected endpoint ++} TXINFO_STRUC, *PTXINFO_STRUC; ++#endif ++ ++#define TXINFO_SIZE 4 ++#define RXINFO_SIZE 4 ++#define TXPADDING_SIZE 11 ++ ++// ++// Management ring buffer format ++// ++typedef struct _MGMT_STRUC { ++ BOOLEAN Valid; ++ PUCHAR pBuffer; ++ ULONG Length; ++} MGMT_STRUC, *PMGMT_STRUC; ++ ++ ++/* ----------------- EEPROM Related MACRO ----------------- */ ++#ifdef RT30xx ++#define RT28xx_EEPROM_READ16(pAd, offset, var) \ ++ do { \ ++ RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ ++ if(!pAd->bUseEfuse) \ ++ var = le2cpu16(var); \ ++ }while(0) ++ ++#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ ++ do{ \ ++ USHORT _tmpVar=var; \ ++ if(!pAd->bUseEfuse) \ ++ _tmpVar = cpu2le16(var); \ ++ RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ ++ }while(0) ++#endif // RT30xx // ++#ifndef RT30xx ++#define RT28xx_EEPROM_READ16(pAd, offset, var) \ ++ do { \ ++ RTUSBReadEEPROM(pAd, offset, (PUCHAR)&(var), 2); \ ++ var = le2cpu16(var); \ ++ }while(0) ++ ++#define RT28xx_EEPROM_WRITE16(pAd, offset, var) \ ++ do{ \ ++ USHORT _tmpVar=var; \ ++ _tmpVar = cpu2le16(var); \ ++ RTUSBWriteEEPROM(pAd, offset, (PUCHAR)&(_tmpVar), 2); \ ++ }while(0) ++#endif // RT30xx // ++ ++/* ----------------- TASK/THREAD Related MACRO ----------------- */ ++#define RT28XX_TASK_THREAD_INIT(pAd, Status) \ ++ Status = CreateThreads(net_dev); ++ ++ ++/* ----------------- Frimware Related MACRO ----------------- */ ++#define RT28XX_WRITE_FIRMWARE(_pAd, _pFwImage, _FwLen) \ ++ RTUSBFirmwareWrite(_pAd, _pFwImage, _FwLen) ++ ++/* ----------------- TX Related MACRO ----------------- */ ++#define RT28XX_START_DEQUEUE(pAd, QueIdx, irqFlags) \ ++ { \ ++ RTMP_IRQ_LOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ ++ if (pAd->DeQueueRunning[QueIdx]) \ ++ { \ ++ RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags);\ ++ printk("DeQueueRunning[%d]= TRUE!\n", QueIdx); \ ++ continue; \ ++ } \ ++ else \ ++ { \ ++ pAd->DeQueueRunning[QueIdx] = TRUE; \ ++ RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags);\ ++ } \ ++ } ++#define RT28XX_STOP_DEQUEUE(pAd, QueIdx, irqFlags) \ ++ do{ \ ++ RTMP_IRQ_LOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ ++ pAd->DeQueueRunning[QueIdx] = FALSE; \ ++ RTMP_IRQ_UNLOCK(&pAd->DeQueueLock[QueIdx], irqFlags); \ ++ }while(0) ++ ++ ++#define RT28XX_HAS_ENOUGH_FREE_DESC(pAd, pTxBlk, freeNum, pPacket) \ ++ (RTUSBFreeDescriptorRequest(pAd, pTxBlk->QueIdx, (pTxBlk->TotalFrameLen + GET_OS_PKT_LEN(pPacket))) == NDIS_STATUS_SUCCESS) ++ ++#define RT28XX_RELEASE_DESC_RESOURCE(pAd, QueIdx) \ ++ do{}while(0) ++ ++#define NEED_QUEUE_BACK_FOR_AGG(_pAd, _QueIdx, _freeNum, _TxFrameType) \ ++ ((_TxFrameType == TX_RALINK_FRAME) && (RTUSBNeedQueueBackForAgg(_pAd, _QueIdx))) ++ ++ ++ ++#define fRTMP_ADAPTER_NEED_STOP_TX \ ++ (fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS | \ ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | fRTMP_ADAPTER_BULKOUT_RESET | \ ++ fRTMP_ADAPTER_RADIO_OFF | fRTMP_ADAPTER_REMOVE_IN_PROGRESS) ++ ++ ++#define HAL_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) \ ++ RtmpUSB_WriteSubTxResource(pAd, pTxBlk, bIsLast, pFreeNumber) ++ ++#define HAL_WriteTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) \ ++ RtmpUSB_WriteSingleTxResource(pAd, pTxBlk,bIsLast, pFreeNumber) ++ ++#define HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) \ ++ RtmpUSB_WriteFragTxResource(pAd, pTxBlk, fragNum, pFreeNumber) ++ ++#define HAL_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) \ ++ RtmpUSB_WriteMultiTxResource(pAd, pTxBlk,frameNum, pFreeNumber) ++ ++#define HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, TxIdx) \ ++ RtmpUSB_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, TxIdx) ++ ++#define HAL_LastTxIdx(pAd, QueIdx,TxIdx) \ ++ /*RtmpUSBDataLastTxIdx(pAd, QueIdx,TxIdx)*/ ++ ++#define HAL_KickOutTx(pAd, pTxBlk, QueIdx) \ ++ RtmpUSBDataKickOut(pAd, pTxBlk, QueIdx) ++ ++ ++#define HAL_KickOutMgmtTx(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen) \ ++ RtmpUSBMgmtKickOut(pAd, QueIdx, pPacket, pSrcBufVA, SrcBufLen) ++ ++#define HAL_KickOutNullFrameTx(_pAd, _QueIdx, _pNullFrame, _frameLen) \ ++ RtmpUSBNullFrameKickOut(_pAd, _QueIdx, _pNullFrame, _frameLen) ++ ++#define RTMP_PKT_TAIL_PADDING 11 // 3(max 4 byte padding) + 4 (last packet padding) + 4 (MaxBulkOutsize align padding) ++ ++extern UCHAR EpToQueue[6]; ++ ++ ++#ifdef RT2870 ++#define GET_TXRING_FREENO(_pAd, _QueIdx) (_QueIdx) //(_pAd->TxRing[_QueIdx].TxSwFreeIdx) ++#define GET_MGMTRING_FREENO(_pAd) (_pAd->MgmtRing.TxSwFreeIdx) ++#endif // RT2870 // ++ ++ ++/* ----------------- RX Related MACRO ----------------- */ ++//#define RT28XX_RX_ERROR_CHECK RTMPCheckRxWI ++ ++#define RT28XX_RV_ALL_BUF_END(bBulkReceive) \ ++ /* We return STATUS_MORE_PROCESSING_REQUIRED so that the completion */ \ ++ /* routine (IofCompleteRequest) will stop working on the irp. */ \ ++ if (bBulkReceive == TRUE) RTUSBBulkReceive(pAd); ++ ++ ++/* ----------------- ASIC Related MACRO ----------------- */ ++// reset MAC of a station entry to 0xFFFFFFFFFFFF ++#define RT28XX_STA_ENTRY_MAC_RESET(pAd, Wcid) \ ++ { RT_SET_ASIC_WCID SetAsicWcid; \ ++ SetAsicWcid.WCID = Wcid; \ ++ SetAsicWcid.SetTid = 0xffffffff; \ ++ SetAsicWcid.DeleteTid = 0xffffffff; \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_ASIC_WCID, \ ++ &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); } ++ ++// add this entry into ASIC RX WCID search table ++#define RT28XX_STA_ENTRY_ADD(pAd, pEntry) \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_CLIENT_MAC_ENTRY, \ ++ pEntry, sizeof(MAC_TABLE_ENTRY)); ++ ++// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet ++// Set MAC register value according operation mode ++#define RT28XX_UPDATE_PROTECT(pAd) \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_UPDATE_PROTECT, NULL, 0); ++// end johnli ++ ++// remove Pair-wise key material from ASIC ++// yet implement ++#define RT28XX_STA_ENTRY_KEY_DEL(pAd, BssIdx, Wcid) ++ ++// add Client security information into ASIC WCID table and IVEIV table ++#define RT28XX_STA_SECURITY_INFO_ADD(pAd, apidx, KeyID, pEntry) \ ++ { RT28XX_STA_ENTRY_MAC_RESET(pAd, pEntry->Aid); \ ++ if (pEntry->Aid >= 1) { \ ++ RT_SET_ASIC_WCID_ATTRI SetAsicWcidAttri; \ ++ SetAsicWcidAttri.WCID = pEntry->Aid; \ ++ if ((pEntry->AuthMode <= Ndis802_11AuthModeAutoSwitch) && \ ++ (pEntry->WepStatus == Ndis802_11Encryption1Enabled)) \ ++ { \ ++ SetAsicWcidAttri.Cipher = pAd->SharedKey[apidx][KeyID].CipherAlg; \ ++ } \ ++ else if (pEntry->AuthMode == Ndis802_11AuthModeWPANone) \ ++ { \ ++ SetAsicWcidAttri.Cipher = pAd->SharedKey[apidx][KeyID].CipherAlg; \ ++ } \ ++ else SetAsicWcidAttri.Cipher = 0; \ ++ DBGPRINT(RT_DEBUG_TRACE, ("aid cipher = %ld\n",SetAsicWcidAttri.Cipher)); \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_SET_ASIC_WCID_CIPHER, \ ++ &SetAsicWcidAttri, sizeof(RT_SET_ASIC_WCID_ATTRI)); } } ++ ++// Insert the BA bitmap to ASIC for the Wcid entry ++#define RT28XX_ADD_BA_SESSION_TO_ASIC(_pAd, _Aid, _TID) \ ++ do{ \ ++ RT_SET_ASIC_WCID SetAsicWcid; \ ++ SetAsicWcid.WCID = (_Aid); \ ++ SetAsicWcid.SetTid = (0x10000<<(_TID)); \ ++ SetAsicWcid.DeleteTid = 0xffffffff; \ ++ RTUSBEnqueueInternalCmd((_pAd), CMDTHREAD_SET_ASIC_WCID, &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); \ ++ }while(0) ++ ++// Remove the BA bitmap from ASIC for the Wcid entry ++#define RT28XX_DEL_BA_SESSION_FROM_ASIC(_pAd, _Wcid, _TID) \ ++ do{ \ ++ RT_SET_ASIC_WCID SetAsicWcid; \ ++ SetAsicWcid.WCID = (_Wcid); \ ++ SetAsicWcid.SetTid = (0xffffffff); \ ++ SetAsicWcid.DeleteTid = (0x10000<<(_TID) ); \ ++ RTUSBEnqueueInternalCmd((_pAd), CMDTHREAD_SET_ASIC_WCID, &SetAsicWcid, sizeof(RT_SET_ASIC_WCID)); \ ++ }while(0) ++ ++ ++/* ----------------- PCI/USB Related MACRO ----------------- */ ++#define RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p) \ ++ ((POS_COOKIE)handle)->pUsb_Dev = dev_p; ++ ++// no use ++#define RT28XX_UNMAP() ++#define RT28XX_IRQ_REQUEST(net_dev) ++#define RT28XX_IRQ_RELEASE(net_dev) ++#define RT28XX_IRQ_INIT(pAd) ++#define RT28XX_IRQ_ENABLE(pAd) ++ ++ ++/* ----------------- MLME Related MACRO ----------------- */ ++#define RT28XX_MLME_HANDLER(pAd) RTUSBMlmeUp(pAd) ++ ++#define RT28XX_MLME_PRE_SANITY_CHECK(pAd) \ ++ { if ((pAd->CommonCfg.bHardwareRadio == TRUE) && \ ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && \ ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) { \ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_CHECK_GPIO, NULL, 0); } } ++ ++#define RT28XX_MLME_STA_QUICK_RSP_WAKE_UP(pAd) \ ++ { RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_QKERIODIC_EXECUT, NULL, 0); \ ++ RTUSBMlmeUp(pAd); } ++ ++#define RT28XX_MLME_RESET_STATE_MACHINE(pAd) \ ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_RESET_CONF, 0, NULL); \ ++ RTUSBMlmeUp(pAd); ++ ++#define RT28XX_HANDLE_COUNTER_MEASURE(_pAd, _pEntry) \ ++ { RTUSBEnqueueInternalCmd(_pAd, CMDTHREAD_802_11_COUNTER_MEASURE, _pEntry, sizeof(MAC_TABLE_ENTRY)); \ ++ RTUSBMlmeUp(_pAd); \ ++ } ++ ++ ++/* ----------------- Power Save Related MACRO ----------------- */ ++#define RT28XX_PS_POLL_ENQUEUE(pAd) \ ++ { RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_PSPOLL); \ ++ RTUSBKickBulkOut(pAd); } ++ ++#define RT28xx_CHIP_NAME "RT2870" ++#define USB_CYC_CFG 0x02a4 ++#define NT_SUCCESS(status) (((status) > 0) ? (1):(0)) ++#define InterlockedIncrement atomic_inc ++#define NdisInterlockedIncrement atomic_inc ++#define InterlockedDecrement atomic_dec ++#define NdisInterlockedDecrement atomic_dec ++#define InterlockedExchange atomic_set ++//#define NdisMSendComplete RTMP_SendComplete ++#define NdisMCancelTimer RTMPCancelTimer ++#define NdisAllocMemory(_ptr, _size, _flag) \ ++ do{_ptr = kmalloc((_size),(_flag));}while(0) ++#define NdisFreeMemory(a, b, c) kfree((a)) ++#define NdisMSleep RTMPusecDelay /* unit: microsecond */ ++ ++ ++#define USBD_TRANSFER_DIRECTION_OUT 0 ++#define USBD_TRANSFER_DIRECTION_IN 0 ++#define USBD_SHORT_TRANSFER_OK 0 ++#define PURB purbb_t ++ ++#define RTUSB_FREE_URB(pUrb) usb_free_urb(pUrb) ++ ++//#undef MlmeAllocateMemory ++//#undef MlmeFreeMemory ++ ++typedef struct usb_device * PUSB_DEV; ++ ++/* MACRO for linux usb */ ++typedef struct urb *purbb_t; ++typedef struct usb_ctrlrequest devctrlrequest; ++#define PIRP PVOID ++#define PMDL PVOID ++#define NDIS_OID UINT ++#ifndef USB_ST_NOERROR ++#define USB_ST_NOERROR 0 ++#endif ++ ++// vendor-specific control operations ++#define CONTROL_TIMEOUT_JIFFIES ( (100 * HZ) / 1000) ++#define UNLINK_TIMEOUT_MS 3 ++ ++/* unlink urb */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) ++#define RTUSB_UNLINK_URB(pUrb) usb_kill_urb(pUrb) ++#else ++#define RTUSB_UNLINK_URB(pUrb) usb_unlink_urb(pUrb) ++#endif ++ ++// Prototypes of completion funuc. ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++#define RTUSBBulkOutDataPacketComplete(purb, pt_regs) RTUSBBulkOutDataPacketComplete(purb) ++#define RTUSBBulkOutMLMEPacketComplete(pUrb, pt_regs) RTUSBBulkOutMLMEPacketComplete(pUrb) ++#define RTUSBBulkOutNullFrameComplete(pUrb, pt_regs) RTUSBBulkOutNullFrameComplete(pUrb) ++#define RTUSBBulkOutRTSFrameComplete(pUrb, pt_regs) RTUSBBulkOutRTSFrameComplete(pUrb) ++#define RTUSBBulkOutPsPollComplete(pUrb, pt_regs) RTUSBBulkOutPsPollComplete(pUrb) ++#define RTUSBBulkRxComplete(pUrb, pt_regs) RTUSBBulkRxComplete(pUrb) ++#endif ++ ++ ++VOID RTUSBBulkOutDataPacketComplete(purbb_t purb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutMLMEPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutNullFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutRTSFrameComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkOutPsPollComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++VOID RTUSBBulkRxComplete(purbb_t pUrb, struct pt_regs *pt_regs); ++ ++ ++#define RTUSBMlmeUp(pAd) \ ++{ \ ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ ++ if(pObj->MLMEThr_pid>0) \ ++ up(&(pAd->mlme_semaphore)); \ ++} ++ ++#define RTUSBCMDUp(pAd) \ ++{ \ ++ POS_COOKIE pObj = (POS_COOKIE) pAd->OS_Cookie; \ ++ if(pObj->RTUSBCmdThr_pid>0) \ ++ up(&(pAd->RTUSBCmd_semaphore)); \ ++} ++ ++ ++static inline NDIS_STATUS RTMPAllocateMemory( ++ OUT PVOID *ptr, ++ IN size_t size) ++{ ++ *ptr = kmalloc(size, GFP_ATOMIC); ++ if(*ptr) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_RESOURCES; ++} ++ ++/* rtmp.h */ ++#define BEACON_RING_SIZE 2 ++#define DEVICE_VENDOR_REQUEST_OUT 0x40 ++#define DEVICE_VENDOR_REQUEST_IN 0xc0 ++#define INTERFACE_VENDOR_REQUEST_OUT 0x41 ++#define INTERFACE_VENDOR_REQUEST_IN 0xc1 ++#define MGMTPIPEIDX 0 // EP6 is highest priority ++ ++#define BULKOUT_MGMT_RESET_FLAG 0x80 ++ ++#define RTUSB_SET_BULK_FLAG(_M, _F) ((_M)->BulkFlags |= (_F)) ++#define RTUSB_CLEAR_BULK_FLAG(_M, _F) ((_M)->BulkFlags &= ~(_F)) ++#define RTUSB_TEST_BULK_FLAG(_M, _F) (((_M)->BulkFlags & (_F)) != 0) ++ ++#define EnqueueCmd(cmdq, cmdqelmt) \ ++{ \ ++ if (cmdq->size == 0) \ ++ cmdq->head = cmdqelmt; \ ++ else \ ++ cmdq->tail->next = cmdqelmt; \ ++ cmdq->tail = cmdqelmt; \ ++ cmdqelmt->next = NULL; \ ++ cmdq->size++; \ ++} ++ ++typedef struct _RT_SET_ASIC_WCID { ++ ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG SetTid; // time-based: seconds, packet-based: kilo-packets ++ ULONG DeleteTid; // time-based: seconds, packet-based: kilo-packets ++} RT_SET_ASIC_WCID,*PRT_SET_ASIC_WCID; ++ ++typedef struct _RT_SET_ASIC_WCID_ATTRI { ++ ULONG WCID; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG Cipher; // ASIC Cipher definition ++ UCHAR Addr[ETH_LENGTH_OF_ADDRESS]; ++} RT_SET_ASIC_WCID_ATTRI,*PRT_SET_ASIC_WCID_ATTRI; ++ ++typedef struct _MLME_MEMORY_STRUCT { ++ PVOID AllocVa; //Pointer to the base virtual address of the allocated memory ++ struct _MLME_MEMORY_STRUCT *Next; //Pointer to the next virtual address of the allocated memory ++} MLME_MEMORY_STRUCT, *PMLME_MEMORY_STRUCT; ++ ++typedef struct _MLME_MEMORY_HANDLER { ++ BOOLEAN MemRunning; //The flag of the Mlme memory handler's status ++ UINT MemoryCount; //Total nonpaged system-space memory not size ++ UINT InUseCount; //Nonpaged system-space memory in used counts ++ UINT UnUseCount; //Nonpaged system-space memory available counts ++ INT PendingCount; //Nonpaged system-space memory for free counts ++ PMLME_MEMORY_STRUCT pInUseHead; //Pointer to the first nonpaed memory not used ++ PMLME_MEMORY_STRUCT pInUseTail; //Pointer to the last nonpaged memory not used ++ PMLME_MEMORY_STRUCT pUnUseHead; //Pointer to the first nonpaged memory in used ++ PMLME_MEMORY_STRUCT pUnUseTail; //Pointer to the last nonpaged memory in used ++ PULONG MemFreePending[MAX_MLME_HANDLER_MEMORY]; //an array to keep pending free-memory's pointer (32bits) ++} MLME_MEMORY_HANDLER, *PMLME_MEMORY_HANDLER; ++ ++typedef struct _CmdQElmt { ++ UINT command; ++ PVOID buffer; ++ ULONG bufferlength; ++ BOOLEAN CmdFromNdis; ++ BOOLEAN SetOperation; ++ struct _CmdQElmt *next; ++} CmdQElmt, *PCmdQElmt; ++ ++typedef struct _CmdQ { ++ UINT size; ++ CmdQElmt *head; ++ CmdQElmt *tail; ++ UINT32 CmdQState; ++}CmdQ, *PCmdQ; ++ ++// ++// For WPA SUPPLICANT: WIRELESS EXT support wireless events: v14 or newer ++// ++#if WIRELESS_EXT >= 14 ++//#define WPA_SUPPLICANT_SUPPORT 1 ++#endif ++ ++/* oid.h */ ++// Cipher suite type for mixed mode group cipher, P802.11i-2004 ++typedef enum _RT_802_11_CIPHER_SUITE_TYPE { ++ Cipher_Type_NONE, ++ Cipher_Type_WEP40, ++ Cipher_Type_TKIP, ++ Cipher_Type_RSVD, ++ Cipher_Type_CCMP, ++ Cipher_Type_WEP104 ++} RT_802_11_CIPHER_SUITE_TYPE, *PRT_802_11_CIPHER_SUITE_TYPE; ++ ++//CMDTHREAD_MULTI_READ_MAC ++//CMDTHREAD_MULTI_WRITE_MAC ++//CMDTHREAD_VENDOR_EEPROM_READ ++//CMDTHREAD_VENDOR_EEPROM_WRITE ++typedef struct _CMDHandler_TLV { ++ USHORT Offset; ++ USHORT Length; ++ UCHAR DataFirst; ++} CMDHandler_TLV, *PCMDHandler_TLV; ++ ++// New for MeetingHouse Api support ++#define CMDTHREAD_VENDOR_RESET 0x0D730101 // cmd ++#define CMDTHREAD_VENDOR_UNPLUG 0x0D730102 // cmd ++#define CMDTHREAD_VENDOR_SWITCH_FUNCTION 0x0D730103 // cmd ++#define CMDTHREAD_MULTI_WRITE_MAC 0x0D730107 // cmd ++#define CMDTHREAD_MULTI_READ_MAC 0x0D730108 // cmd ++#define CMDTHREAD_VENDOR_EEPROM_WRITE 0x0D73010A // cmd ++#define CMDTHREAD_VENDOR_EEPROM_READ 0x0D73010B // cmd ++#define CMDTHREAD_VENDOR_ENTER_TESTMODE 0x0D73010C // cmd ++#define CMDTHREAD_VENDOR_EXIT_TESTMODE 0x0D73010D // cmd ++#define CMDTHREAD_VENDOR_WRITE_BBP 0x0D730119 // cmd ++#define CMDTHREAD_VENDOR_READ_BBP 0x0D730118 // cmd ++#define CMDTHREAD_VENDOR_WRITE_RF 0x0D73011A // cmd ++#define CMDTHREAD_VENDOR_FLIP_IQ 0x0D73011D // cmd ++#define CMDTHREAD_RESET_BULK_OUT 0x0D730210 // cmd ++#define CMDTHREAD_RESET_BULK_IN 0x0D730211 // cmd ++#define CMDTHREAD_SET_PSM_BIT_SAVE 0x0D730212 // cmd ++#define CMDTHREAD_SET_RADIO 0x0D730214 // cmd ++#define CMDTHREAD_UPDATE_TX_RATE 0x0D730216 // cmd ++#define CMDTHREAD_802_11_ADD_KEY_WEP 0x0D730218 // cmd ++#define CMDTHREAD_RESET_FROM_ERROR 0x0D73021A // cmd ++#define CMDTHREAD_LINK_DOWN 0x0D73021B // cmd ++#define CMDTHREAD_RESET_FROM_NDIS 0x0D73021C // cmd ++#define CMDTHREAD_CHECK_GPIO 0x0D730215 // cmd ++#define CMDTHREAD_FORCE_WAKE_UP 0x0D730222 // cmd ++#define CMDTHREAD_SET_BW 0x0D730225 // cmd ++#define CMDTHREAD_SET_ASIC_WCID 0x0D730226 // cmd ++#define CMDTHREAD_SET_ASIC_WCID_CIPHER 0x0D730227 // cmd ++#define CMDTHREAD_QKERIODIC_EXECUT 0x0D73023D // cmd ++#define RT_CMD_SET_KEY_TABLE 0x0D730228 // cmd ++#define RT_CMD_SET_RX_WCID_TABLE 0x0D730229 // cmd ++#define CMDTHREAD_SET_CLIENT_MAC_ENTRY 0x0D73023E // cmd ++#define CMDTHREAD_802_11_QUERY_HARDWARE_REGISTER 0x0D710105 // cmd ++#define CMDTHREAD_802_11_SET_PHY_MODE 0x0D79010C // cmd ++#define CMDTHREAD_802_11_SET_STA_CONFIG 0x0D790111 // cmd ++#define CMDTHREAD_802_11_SET_PREAMBLE 0x0D790101 // cmd ++#define CMDTHREAD_802_11_COUNTER_MEASURE 0x0D790102 // cmd ++// add by johnli, fix "in_interrupt" error when call "MacTableDeleteEntry" in Rx tasklet ++#define CMDTHREAD_UPDATE_PROTECT 0x0D790103 // cmd ++// end johnli ++ ++#define WPA1AKMBIT 0x01 ++#define WPA2AKMBIT 0x02 ++#define WPA1PSKAKMBIT 0x04 ++#define WPA2PSKAKMBIT 0x08 ++#define TKIPBIT 0x01 ++#define CCMPBIT 0x02 ++ ++ ++#define RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx) \ ++ RT28xxUsbStaAsicForceWakeup(pAd, bFromTx); ++ ++#define RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp) \ ++ RT28xxUsbStaAsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ ++#define RT28XX_MLME_RADIO_ON(pAd) \ ++ RT28xxUsbMlmeRadioOn(pAd); ++ ++#define RT28XX_MLME_RADIO_OFF(pAd) \ ++ RT28xxUsbMlmeRadioOFF(pAd); ++ ++#endif //__RT2870_H__ +--- /dev/null ++++ b/drivers/staging/rt3070/rt28xx.h +@@ -0,0 +1,2725 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt28xx.h ++ ++ Abstract: ++ RT28xx ASIC related definition & structures ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee Jan-3-2006 created for RT2860c ++*/ ++ ++#ifndef __RT28XX_H__ ++#define __RT28XX_H__ ++ ++ ++// ++// PCI registers - base address 0x0000 ++// ++#define PCI_CFG 0x0000 ++#define PCI_EECTRL 0x0004 ++#define PCI_MCUCTRL 0x0008 ++ ++#define OPT_14 0x114 ++ ++typedef int NTSTATUS; ++#define RETRY_LIMIT 10 ++#define STATUS_SUCCESS 0x00 ++#define STATUS_UNSUCCESSFUL 0x01 ++ ++// ++// SCH/DMA registers - base address 0x0200 ++// ++// INT_SOURCE_CSR: Interrupt source register. Write one to clear corresponding bit ++// ++#define DMA_CSR0 0x200 ++#define INT_SOURCE_CSR 0x200 ++#ifdef RT_BIG_ENDIAN ++typedef union _INT_SOURCE_CSR_STRUC { ++ struct { ++ UINT32 :14; ++ UINT32 TxCoherent:1; ++ UINT32 RxCoherent:1; ++ UINT32 GPTimer:1; ++ UINT32 AutoWakeup:1;//bit14 ++ UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c ++ UINT32 PreTBTT:1; ++ UINT32 TBTTInt:1; ++ UINT32 RxTxCoherent:1; ++ UINT32 MCUCommandINT:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 RxDone:1; ++ UINT32 TxDelayINT:1; //delayed interrupt, not interrupt until several int or time limit hit ++ UINT32 RxDelayINT:1; //dealyed interrupt ++ } field; ++ UINT32 word; ++} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; ++#else ++typedef union _INT_SOURCE_CSR_STRUC { ++ struct { ++ UINT32 RxDelayINT:1; ++ UINT32 TxDelayINT:1; ++ UINT32 RxDone:1; ++ UINT32 Ac0DmaDone:1;//4 ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 HccaDmaDone:1; // bit7 ++ UINT32 MgmtDmaDone:1; ++ UINT32 MCUCommandINT:1;//bit 9 ++ UINT32 RxTxCoherent:1; ++ UINT32 TBTTInt:1; ++ UINT32 PreTBTT:1; ++ UINT32 TXFifoStatusInt:1;//FIFO Statistics is full, sw should read 0x171c ++ UINT32 AutoWakeup:1;//bit14 ++ UINT32 GPTimer:1; ++ UINT32 RxCoherent:1;//bit16 ++ UINT32 TxCoherent:1; ++ UINT32 :14; ++ } field; ++ UINT32 word; ++} INT_SOURCE_CSR_STRUC, *PINT_SOURCE_CSR_STRUC; ++#endif ++ ++// ++// INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF ++// ++#define INT_MASK_CSR 0x204 ++#ifdef RT_BIG_ENDIAN ++typedef union _INT_MASK_CSR_STRUC { ++ struct { ++ UINT32 TxCoherent:1; ++ UINT32 RxCoherent:1; ++ UINT32 :20; ++ UINT32 MCUCommandINT:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 RxDone:1; ++ UINT32 TxDelay:1; ++ UINT32 RXDelay_INT_MSK:1; ++ } field; ++ UINT32 word; ++}INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; ++#else ++typedef union _INT_MASK_CSR_STRUC { ++ struct { ++ UINT32 RXDelay_INT_MSK:1; ++ UINT32 TxDelay:1; ++ UINT32 RxDone:1; ++ UINT32 Ac0DmaDone:1; ++ UINT32 Ac1DmaDone:1; ++ UINT32 Ac2DmaDone:1; ++ UINT32 Ac3DmaDone:1; ++ UINT32 HccaDmaDone:1; ++ UINT32 MgmtDmaDone:1; ++ UINT32 MCUCommandINT:1; ++ UINT32 :20; ++ UINT32 RxCoherent:1; ++ UINT32 TxCoherent:1; ++ } field; ++ UINT32 word; ++} INT_MASK_CSR_STRUC, *PINT_MASK_CSR_STRUC; ++#endif ++#define WPDMA_GLO_CFG 0x208 ++#ifdef RT_BIG_ENDIAN ++typedef union _WPDMA_GLO_CFG_STRUC { ++ struct { ++ UINT32 HDR_SEG_LEN:16; ++ UINT32 RXHdrScater:8; ++ UINT32 BigEndian:1; ++ UINT32 EnTXWriteBackDDONE:1; ++ UINT32 WPDMABurstSIZE:2; ++ UINT32 RxDMABusy:1; ++ UINT32 EnableRxDMA:1; ++ UINT32 TxDMABusy:1; ++ UINT32 EnableTxDMA:1; ++ } field; ++ UINT32 word; ++}WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; ++#else ++typedef union _WPDMA_GLO_CFG_STRUC { ++ struct { ++ UINT32 EnableTxDMA:1; ++ UINT32 TxDMABusy:1; ++ UINT32 EnableRxDMA:1; ++ UINT32 RxDMABusy:1; ++ UINT32 WPDMABurstSIZE:2; ++ UINT32 EnTXWriteBackDDONE:1; ++ UINT32 BigEndian:1; ++ UINT32 RXHdrScater:8; ++ UINT32 HDR_SEG_LEN:16; ++ } field; ++ UINT32 word; ++} WPDMA_GLO_CFG_STRUC, *PWPDMA_GLO_CFG_STRUC; ++#endif ++#define WPDMA_RST_IDX 0x20c ++#ifdef RT_BIG_ENDIAN ++typedef union _WPDMA_RST_IDX_STRUC { ++ struct { ++ UINT32 :15; ++ UINT32 RST_DRX_IDX0:1; ++ UINT32 rsv:10; ++ UINT32 RST_DTX_IDX5:1; ++ UINT32 RST_DTX_IDX4:1; ++ UINT32 RST_DTX_IDX3:1; ++ UINT32 RST_DTX_IDX2:1; ++ UINT32 RST_DTX_IDX1:1; ++ UINT32 RST_DTX_IDX0:1; ++ } field; ++ UINT32 word; ++}WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; ++#else ++typedef union _WPDMA_RST_IDX_STRUC { ++ struct { ++ UINT32 RST_DTX_IDX0:1; ++ UINT32 RST_DTX_IDX1:1; ++ UINT32 RST_DTX_IDX2:1; ++ UINT32 RST_DTX_IDX3:1; ++ UINT32 RST_DTX_IDX4:1; ++ UINT32 RST_DTX_IDX5:1; ++ UINT32 rsv:10; ++ UINT32 RST_DRX_IDX0:1; ++ UINT32 :15; ++ } field; ++ UINT32 word; ++} WPDMA_RST_IDX_STRUC, *PWPDMA_RST_IDX_STRUC; ++#endif ++#define DELAY_INT_CFG 0x0210 ++#ifdef RT_BIG_ENDIAN ++typedef union _DELAY_INT_CFG_STRUC { ++ struct { ++ UINT32 TXDLY_INT_EN:1; ++ UINT32 TXMAX_PINT:7; ++ UINT32 TXMAX_PTIME:8; ++ UINT32 RXDLY_INT_EN:1; ++ UINT32 RXMAX_PINT:7; ++ UINT32 RXMAX_PTIME:8; ++ } field; ++ UINT32 word; ++}DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; ++#else ++typedef union _DELAY_INT_CFG_STRUC { ++ struct { ++ UINT32 RXMAX_PTIME:8; ++ UINT32 RXMAX_PINT:7; ++ UINT32 RXDLY_INT_EN:1; ++ UINT32 TXMAX_PTIME:8; ++ UINT32 TXMAX_PINT:7; ++ UINT32 TXDLY_INT_EN:1; ++ } field; ++ UINT32 word; ++} DELAY_INT_CFG_STRUC, *PDELAY_INT_CFG_STRUC; ++#endif ++#define WMM_AIFSN_CFG 0x0214 ++#ifdef RT_BIG_ENDIAN ++typedef union _AIFSN_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Aifsn3:4; // for AC_VO ++ UINT32 Aifsn2:4; // for AC_VI ++ UINT32 Aifsn1:4; // for AC_BK ++ UINT32 Aifsn0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; ++#else ++typedef union _AIFSN_CSR_STRUC { ++ struct { ++ UINT32 Aifsn0:4; // for AC_BE ++ UINT32 Aifsn1:4; // for AC_BK ++ UINT32 Aifsn2:4; // for AC_VI ++ UINT32 Aifsn3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} AIFSN_CSR_STRUC, *PAIFSN_CSR_STRUC; ++#endif ++// ++// CWMIN_CSR: CWmin for each EDCA AC ++// ++#define WMM_CWMIN_CFG 0x0218 ++#ifdef RT_BIG_ENDIAN ++typedef union _CWMIN_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Cwmin3:4; // for AC_VO ++ UINT32 Cwmin2:4; // for AC_VI ++ UINT32 Cwmin1:4; // for AC_BK ++ UINT32 Cwmin0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; ++#else ++typedef union _CWMIN_CSR_STRUC { ++ struct { ++ UINT32 Cwmin0:4; // for AC_BE ++ UINT32 Cwmin1:4; // for AC_BK ++ UINT32 Cwmin2:4; // for AC_VI ++ UINT32 Cwmin3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} CWMIN_CSR_STRUC, *PCWMIN_CSR_STRUC; ++#endif ++ ++// ++// CWMAX_CSR: CWmin for each EDCA AC ++// ++#define WMM_CWMAX_CFG 0x021c ++#ifdef RT_BIG_ENDIAN ++typedef union _CWMAX_CSR_STRUC { ++ struct { ++ UINT32 Rsv:16; ++ UINT32 Cwmax3:4; // for AC_VO ++ UINT32 Cwmax2:4; // for AC_VI ++ UINT32 Cwmax1:4; // for AC_BK ++ UINT32 Cwmax0:4; // for AC_BE ++ } field; ++ UINT32 word; ++} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; ++#else ++typedef union _CWMAX_CSR_STRUC { ++ struct { ++ UINT32 Cwmax0:4; // for AC_BE ++ UINT32 Cwmax1:4; // for AC_BK ++ UINT32 Cwmax2:4; // for AC_VI ++ UINT32 Cwmax3:4; // for AC_VO ++ UINT32 Rsv:16; ++ } field; ++ UINT32 word; ++} CWMAX_CSR_STRUC, *PCWMAX_CSR_STRUC; ++#endif ++ ++ ++// ++// AC_TXOP_CSR0: AC_BK/AC_BE TXOP register ++// ++#define WMM_TXOP0_CFG 0x0220 ++#ifdef RT_BIG_ENDIAN ++typedef union _AC_TXOP_CSR0_STRUC { ++ struct { ++ USHORT Ac1Txop; // for AC_BE, in unit of 32us ++ USHORT Ac0Txop; // for AC_BK, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; ++#else ++typedef union _AC_TXOP_CSR0_STRUC { ++ struct { ++ USHORT Ac0Txop; // for AC_BK, in unit of 32us ++ USHORT Ac1Txop; // for AC_BE, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR0_STRUC, *PAC_TXOP_CSR0_STRUC; ++#endif ++ ++// ++// AC_TXOP_CSR1: AC_VO/AC_VI TXOP register ++// ++#define WMM_TXOP1_CFG 0x0224 ++#ifdef RT_BIG_ENDIAN ++typedef union _AC_TXOP_CSR1_STRUC { ++ struct { ++ USHORT Ac3Txop; // for AC_VO, in unit of 32us ++ USHORT Ac2Txop; // for AC_VI, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; ++#else ++typedef union _AC_TXOP_CSR1_STRUC { ++ struct { ++ USHORT Ac2Txop; // for AC_VI, in unit of 32us ++ USHORT Ac3Txop; // for AC_VO, in unit of 32us ++ } field; ++ UINT32 word; ++} AC_TXOP_CSR1_STRUC, *PAC_TXOP_CSR1_STRUC; ++#endif ++#define RINGREG_DIFF 0x10 ++#define GPIO_CTRL_CFG 0x0228 //MAC_CSR13 ++#define MCU_CMD_CFG 0x022c ++#define TX_BASE_PTR0 0x0230 //AC_BK base address ++#define TX_MAX_CNT0 0x0234 ++#define TX_CTX_IDX0 0x0238 ++#define TX_DTX_IDX0 0x023c ++#define TX_BASE_PTR1 0x0240 //AC_BE base address ++#define TX_MAX_CNT1 0x0244 ++#define TX_CTX_IDX1 0x0248 ++#define TX_DTX_IDX1 0x024c ++#define TX_BASE_PTR2 0x0250 //AC_VI base address ++#define TX_MAX_CNT2 0x0254 ++#define TX_CTX_IDX2 0x0258 ++#define TX_DTX_IDX2 0x025c ++#define TX_BASE_PTR3 0x0260 //AC_VO base address ++#define TX_MAX_CNT3 0x0264 ++#define TX_CTX_IDX3 0x0268 ++#define TX_DTX_IDX3 0x026c ++#define TX_BASE_PTR4 0x0270 //HCCA base address ++#define TX_MAX_CNT4 0x0274 ++#define TX_CTX_IDX4 0x0278 ++#define TX_DTX_IDX4 0x027c ++#define TX_BASE_PTR5 0x0280 //MGMT base address ++#define TX_MAX_CNT5 0x0284 ++#define TX_CTX_IDX5 0x0288 ++#define TX_DTX_IDX5 0x028c ++#define TX_MGMTMAX_CNT TX_MAX_CNT5 ++#define TX_MGMTCTX_IDX TX_CTX_IDX5 ++#define TX_MGMTDTX_IDX TX_DTX_IDX5 ++#define RX_BASE_PTR 0x0290 //RX base address ++#define RX_MAX_CNT 0x0294 ++#define RX_CRX_IDX 0x0298 ++#define RX_DRX_IDX 0x029c ++#define USB_DMA_CFG 0x02a0 ++#ifdef RT_BIG_ENDIAN ++typedef union _USB_DMA_CFG_STRUC { ++ struct { ++ UINT32 TxBusy:1; //USB DMA TX FSM busy . debug only ++ UINT32 RxBusy:1; //USB DMA RX FSM busy . debug only ++ UINT32 EpoutValid:6; //OUT endpoint data valid. debug only ++ UINT32 TxBulkEn:1; //Enable USB DMA Tx ++ UINT32 RxBulkEn:1; //Enable USB DMA Rx ++ UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation ++ UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. ++ UINT32 TxClear:1; //Clear USB DMA TX path ++ UINT32 rsv:2; ++ UINT32 phyclear:1; //phy watch dog enable. write 1 ++ UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 1024 bytes ++ UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns ++ } field; ++ UINT32 word; ++} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; ++#else ++typedef union _USB_DMA_CFG_STRUC { ++ struct { ++ UINT32 RxBulkAggTOut:8; //Rx Bulk Aggregation TimeOut in unit of 33ns ++ UINT32 RxBulkAggLmt:8; //Rx Bulk Aggregation Limit in unit of 256 bytes ++ UINT32 phyclear:1; //phy watch dog enable. write 1 ++ UINT32 rsv:2; ++ UINT32 TxClear:1; //Clear USB DMA TX path ++ UINT32 TxopHalt:1; //Halt TXOP count down when TX buffer is full. ++ UINT32 RxBulkAggEn:1; //Enable Rx Bulk Aggregation ++ UINT32 RxBulkEn:1; //Enable USB DMA Rx ++ UINT32 TxBulkEn:1; //Enable USB DMA Tx ++ UINT32 EpoutValid:6; //OUT endpoint data valid ++ UINT32 RxBusy:1; //USB DMA RX FSM busy ++ UINT32 TxBusy:1; //USB DMA TX FSM busy ++ } field; ++ UINT32 word; ++} USB_DMA_CFG_STRUC, *PUSB_DMA_CFG_STRUC; ++#endif ++ ++// ++// 3 PBF registers ++// ++// ++// Most are for debug. Driver doesn't touch PBF register. ++#define PBF_SYS_CTRL 0x0400 ++#define PBF_CFG 0x0408 ++#define PBF_MAX_PCNT 0x040C ++#define PBF_CTRL 0x0410 ++#define PBF_INT_STA 0x0414 ++#define PBF_INT_ENA 0x0418 ++#define TXRXQ_PCNT 0x0438 ++#define PBF_DBG 0x043c ++#define PBF_CAP_CTRL 0x0440 ++ ++ ++// eFuse registers ++#define EFUSE_CTRL 0x0580 ++#define EFUSE_DATA0 0x0590 ++#define EFUSE_DATA1 0x0594 ++#define EFUSE_DATA2 0x0598 ++#define EFUSE_DATA3 0x059c ++#define EFUSE_USAGE_MAP_START 0x2d0 ++#define EFUSE_USAGE_MAP_END 0x2fc ++#define EFUSE_TAG 0x2fe ++#define EFUSE_USAGE_MAP_SIZE 45 ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EFUSE_CTRL_STRUC { ++ struct { ++ UINT32 SEL_EFUSE:1; ++ UINT32 EFSROM_KICK:1; ++ UINT32 RESERVED:4; ++ UINT32 EFSROM_AIN:10; ++ UINT32 EFSROM_LDO_ON_TIME:2; ++ UINT32 EFSROM_LDO_OFF_TIME:6; ++ UINT32 EFSROM_MODE:2; ++ UINT32 EFSROM_AOUT:6; ++ } field; ++ UINT32 word; ++} EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; ++#else ++typedef union _EFUSE_CTRL_STRUC { ++ struct { ++ UINT32 EFSROM_AOUT:6; ++ UINT32 EFSROM_MODE:2; ++ UINT32 EFSROM_LDO_OFF_TIME:6; ++ UINT32 EFSROM_LDO_ON_TIME:2; ++ UINT32 EFSROM_AIN:10; ++ UINT32 RESERVED:4; ++ UINT32 EFSROM_KICK:1; ++ UINT32 SEL_EFUSE:1; ++ } field; ++ UINT32 word; ++} EFUSE_CTRL_STRUC, *PEFUSE_CTRL_STRUC; ++#endif // RT_BIG_ENDIAN // ++ ++#define LDO_CFG0 0x05d4 ++#define GPIO_SWITCH 0x05dc ++ ++// ++// 4 MAC registers ++// ++// ++// 4.1 MAC SYSTEM configuration registers (offset:0x1000) ++// ++#define MAC_CSR0 0x1000 ++#ifdef RT_BIG_ENDIAN ++typedef union _ASIC_VER_ID_STRUC { ++ struct { ++ USHORT ASICVer; // version : 2860 ++ USHORT ASICRev; // reversion : 0 ++ } field; ++ UINT32 word; ++} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; ++#else ++typedef union _ASIC_VER_ID_STRUC { ++ struct { ++ USHORT ASICRev; // reversion : 0 ++ USHORT ASICVer; // version : 2860 ++ } field; ++ UINT32 word; ++} ASIC_VER_ID_STRUC, *PASIC_VER_ID_STRUC; ++#endif ++#define MAC_SYS_CTRL 0x1004 //MAC_CSR1 ++#define MAC_ADDR_DW0 0x1008 // MAC ADDR DW0 ++#define MAC_ADDR_DW1 0x100c // MAC ADDR DW1 ++// ++// MAC_CSR2: STA MAC register 0 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_DW0_STRUC { ++ struct { ++ UCHAR Byte3; // MAC address byte 3 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte0; // MAC address byte 0 ++ } field; ++ UINT32 word; ++} MAC_DW0_STRUC, *PMAC_DW0_STRUC; ++#else ++typedef union _MAC_DW0_STRUC { ++ struct { ++ UCHAR Byte0; // MAC address byte 0 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte3; // MAC address byte 3 ++ } field; ++ UINT32 word; ++} MAC_DW0_STRUC, *PMAC_DW0_STRUC; ++#endif ++ ++// ++// MAC_CSR3: STA MAC register 1 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_DW1_STRUC { ++ struct { ++ UCHAR Rsvd1; ++ UCHAR U2MeMask; ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Byte4; // MAC address byte 4 ++ } field; ++ UINT32 word; ++} MAC_DW1_STRUC, *PMAC_DW1_STRUC; ++#else ++typedef union _MAC_DW1_STRUC { ++ struct { ++ UCHAR Byte4; // MAC address byte 4 ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR U2MeMask; ++ UCHAR Rsvd1; ++ } field; ++ UINT32 word; ++} MAC_DW1_STRUC, *PMAC_DW1_STRUC; ++#endif ++ ++#define MAC_BSSID_DW0 0x1010 // MAC BSSID DW0 ++#define MAC_BSSID_DW1 0x1014 // MAC BSSID DW1 ++ ++// ++// MAC_CSR5: BSSID register 1 ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MAC_CSR5_STRUC { ++ struct { ++ USHORT Rsvd:11; ++ USHORT MBssBcnNum:3; ++ USHORT BssIdMode:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID ++ UCHAR Byte5; // BSSID byte 5 ++ UCHAR Byte4; // BSSID byte 4 ++ } field; ++ UINT32 word; ++} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; ++#else ++typedef union _MAC_CSR5_STRUC { ++ struct { ++ UCHAR Byte4; // BSSID byte 4 ++ UCHAR Byte5; // BSSID byte 5 ++ USHORT BssIdMask:2; // 0: one BSSID, 10: 4 BSSID, 01: 2 BSSID , 11: 8BSSID ++ USHORT MBssBcnNum:3; ++ USHORT Rsvd:11; ++ } field; ++ UINT32 word; ++} MAC_CSR5_STRUC, *PMAC_CSR5_STRUC; ++#endif ++ ++#define MAX_LEN_CFG 0x1018 // rt2860b max 16k bytes. bit12:13 Maximum PSDU length (power factor) 0:2^13, 1:2^14, 2:2^15, 3:2^16 ++#define BBP_CSR_CFG 0x101c // ++// ++// BBP_CSR_CFG: BBP serial control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _BBP_CSR_CFG_STRUC { ++ struct { ++ UINT32 :12; ++ UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel ++ UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles ++ UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. ++ UINT32 fRead:1; // 0: Write BBP, 1: Read BBP ++ UINT32 RegNum:8; // Selected BBP register ++ UINT32 Value:8; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; ++#else ++typedef union _BBP_CSR_CFG_STRUC { ++ struct { ++ UINT32 Value:8; // Register value to program into BBP ++ UINT32 RegNum:8; // Selected BBP register ++ UINT32 fRead:1; // 0: Write BBP, 1: Read BBP ++ UINT32 Busy:1; // 1: ASIC is busy execute BBP programming. ++ UINT32 BBP_PAR_DUR:1; // 0: 4 MAC clock cycles 1: 8 MAC clock cycles ++ UINT32 BBP_RW_MODE:1; // 0: use serial mode 1:parallel ++ UINT32 :12; ++ } field; ++ UINT32 word; ++} BBP_CSR_CFG_STRUC, *PBBP_CSR_CFG_STRUC; ++#endif ++#define RF_CSR_CFG0 0x1020 ++// ++// RF_CSR_CFG: RF control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG0_STRUC { ++ struct { ++ UINT32 Busy:1; // 0: idle 1: 8busy ++ UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate ++ UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby ++ UINT32 bitwidth:5; // Selected BBP register ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; ++#else ++typedef union _RF_CSR_CFG0_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 bitwidth:5; // Selected BBP register ++ UINT32 StandbyMode:1; // 0: high when stand by 1: low when standby ++ UINT32 Sel:1; // 0:RF_LE0 activate 1:RF_LE1 activate ++ UINT32 Busy:1; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG0_STRUC, *PRF_CSR_CFG0_STRUC; ++#endif ++#define RF_CSR_CFG1 0x1024 ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG1_STRUC { ++ struct { ++ UINT32 rsv:7; // 0: idle 1: 8busy ++ UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; ++#else ++typedef union _RF_CSR_CFG1_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 RFGap:5; // Gap between BB_CONTROL_RF and RF_LE. 0: 3 system clock cycle (37.5usec) 1: 5 system clock cycle (62.5usec) ++ UINT32 rsv:7; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG1_STRUC, *PRF_CSR_CFG1_STRUC; ++#endif ++#define RF_CSR_CFG2 0x1028 // ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG2_STRUC { ++ struct { ++ UINT32 rsv:8; // 0: idle 1: 8busy ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ } field; ++ UINT32 word; ++} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; ++#else ++typedef union _RF_CSR_CFG2_STRUC { ++ struct { ++ UINT32 RegIdAndContent:24; // Register value to program into BBP ++ UINT32 rsv:8; // 0: idle 1: 8busy ++ } field; ++ UINT32 word; ++} RF_CSR_CFG2_STRUC, *PRF_CSR_CFG2_STRUC; ++#endif ++#define LED_CFG 0x102c // MAC_CSR14 ++#ifdef RT_BIG_ENDIAN ++typedef union _LED_CFG_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high ++ UINT32 YLedMode:2; // yellow Led Mode ++ UINT32 GLedMode:2; // green Led Mode ++ UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on ++ UINT32 rsv:2; ++ UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms ++ UINT32 OffPeriod:8; // blinking off period unit 1ms ++ UINT32 OnPeriod:8; // blinking on period unit 1ms ++ } field; ++ UINT32 word; ++} LED_CFG_STRUC, *PLED_CFG_STRUC; ++#else ++typedef union _LED_CFG_STRUC { ++ struct { ++ UINT32 OnPeriod:8; // blinking on period unit 1ms ++ UINT32 OffPeriod:8; // blinking off period unit 1ms ++ UINT32 SlowBlinkPeriod:6; // slow blinking period. unit:1ms ++ UINT32 rsv:2; ++ UINT32 RLedMode:2; // red Led Mode 0: off1: blinking upon TX2: periodic slow blinking3: always on ++ UINT32 GLedMode:2; // green Led Mode ++ UINT32 YLedMode:2; // yellow Led Mode ++ UINT32 LedPolar:1; // Led Polarity. 0: active low1: active high ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} LED_CFG_STRUC, *PLED_CFG_STRUC; ++#endif ++// ++// 4.2 MAC TIMING configuration registers (offset:0x1100) ++// ++#define XIFS_TIME_CFG 0x1100 // MAC_CSR8 MAC_CSR9 ++#ifdef RT_BIG_ENDIAN ++typedef union _IFS_SLOT_CFG_STRUC { ++ struct { ++ UINT32 rsv:2; ++ UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer ++ UINT32 EIFS:9; // unit 1us ++ UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND ++ UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX ++ UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX ++ } field; ++ UINT32 word; ++} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; ++#else ++typedef union _IFS_SLOT_CFG_STRUC { ++ struct { ++ UINT32 CckmSifsTime:8; // unit 1us. Applied after CCK RX/TX ++ UINT32 OfdmSifsTime:8; // unit 1us. Applied after OFDM RX/TX ++ UINT32 OfdmXifsTime:4; //OFDM SIFS. unit 1us. Applied after OFDM RX when MAC doesn't reference BBP signal BBRXEND ++ UINT32 EIFS:9; // unit 1us ++ UINT32 BBRxendEnable:1; // reference RXEND signal to begin XIFS defer ++ UINT32 rsv:2; ++ } field; ++ UINT32 word; ++} IFS_SLOT_CFG_STRUC, *PIFS_SLOT_CFG_STRUC; ++#endif ++ ++#define BKOFF_SLOT_CFG 0x1104 // mac_csr9 last 8 bits ++#define NAV_TIME_CFG 0x1108 // NAV (MAC_CSR15) ++#define CH_TIME_CFG 0x110C // Count as channel busy ++#define PBF_LIFE_TIMER 0x1110 //TX/RX MPDU timestamp timer (free run)Unit: 1us ++#define BCN_TIME_CFG 0x1114 // TXRX_CSR9 ++ ++#define BCN_OFFSET0 0x042C ++#define BCN_OFFSET1 0x0430 ++ ++// ++// BCN_TIME_CFG : Synchronization control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _BCN_TIME_CFG_STRUC { ++ struct { ++ UINT32 TxTimestampCompensate:8; ++ UINT32 :3; ++ UINT32 bBeaconGen:1; // Enable beacon generator ++ UINT32 bTBTTEnable:1; ++ UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode ++ UINT32 bTsfTicking:1; // Enable TSF auto counting ++ UINT32 BeaconInterval:16; // in unit of 1/16 TU ++ } field; ++ UINT32 word; ++} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; ++#else ++typedef union _BCN_TIME_CFG_STRUC { ++ struct { ++ UINT32 BeaconInterval:16; // in unit of 1/16 TU ++ UINT32 bTsfTicking:1; // Enable TSF auto counting ++ UINT32 TsfSyncMode:2; // Enable TSF sync, 00: disable, 01: infra mode, 10: ad-hoc mode ++ UINT32 bTBTTEnable:1; ++ UINT32 bBeaconGen:1; // Enable beacon generator ++ UINT32 :3; ++ UINT32 TxTimestampCompensate:8; ++ } field; ++ UINT32 word; ++} BCN_TIME_CFG_STRUC, *PBCN_TIME_CFG_STRUC; ++#endif ++#define TBTT_SYNC_CFG 0x1118 // txrx_csr10 ++#define TSF_TIMER_DW0 0x111C // Local TSF timer lsb 32 bits. Read-only ++#define TSF_TIMER_DW1 0x1120 // msb 32 bits. Read-only. ++#define TBTT_TIMER 0x1124 // TImer remains till next TBTT. Read-only. TXRX_CSR14 ++#define INT_TIMER_CFG 0x1128 // ++#define INT_TIMER_EN 0x112c // GP-timer and pre-tbtt Int enable ++#define CH_IDLE_STA 0x1130 // channel idle time ++#define CH_BUSY_STA 0x1134 // channle busy time ++// ++// 4.2 MAC POWER configuration registers (offset:0x1200) ++// ++#define MAC_STATUS_CFG 0x1200 // old MAC_CSR12 ++#define PWR_PIN_CFG 0x1204 // old MAC_CSR12 ++#define AUTO_WAKEUP_CFG 0x1208 // old MAC_CSR10 ++// ++// AUTO_WAKEUP_CFG: Manual power control / status register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _AUTO_WAKEUP_STRUC { ++ struct { ++ UINT32 :16; ++ UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake ++ UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set ++ UINT32 AutoLeadTime:8; ++ } field; ++ UINT32 word; ++} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; ++#else ++typedef union _AUTO_WAKEUP_STRUC { ++ struct { ++ UINT32 AutoLeadTime:8; ++ UINT32 NumofSleepingTbtt:7; // ForceWake has high privilege than PutToSleep when both set ++ UINT32 EnableAutoWakeup:1; // 0:sleep, 1:awake ++ UINT32 :16; ++ } field; ++ UINT32 word; ++} AUTO_WAKEUP_STRUC, *PAUTO_WAKEUP_STRUC; ++#endif ++// ++// 4.3 MAC TX configuration registers (offset:0x1300) ++// ++ ++#define EDCA_AC0_CFG 0x1300 //AC_TXOP_CSR0 0x3474 ++#define EDCA_AC1_CFG 0x1304 ++#define EDCA_AC2_CFG 0x1308 ++#define EDCA_AC3_CFG 0x130c ++#ifdef RT_BIG_ENDIAN ++typedef union _EDCA_AC_CFG_STRUC { ++ struct { ++ UINT32 :12; // ++ UINT32 Cwmax:4; //unit power of 2 ++ UINT32 Cwmin:4; // ++ UINT32 Aifsn:4; // # of slot time ++ UINT32 AcTxop:8; // in unit of 32us ++ } field; ++ UINT32 word; ++} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; ++#else ++typedef union _EDCA_AC_CFG_STRUC { ++ struct { ++ UINT32 AcTxop:8; // in unit of 32us ++ UINT32 Aifsn:4; // # of slot time ++ UINT32 Cwmin:4; // ++ UINT32 Cwmax:4; //unit power of 2 ++ UINT32 :12; // ++ } field; ++ UINT32 word; ++} EDCA_AC_CFG_STRUC, *PEDCA_AC_CFG_STRUC; ++#endif ++ ++#define EDCA_TID_AC_MAP 0x1310 ++#define TX_PWR_CFG_0 0x1314 ++#define TX_PWR_CFG_1 0x1318 ++#define TX_PWR_CFG_2 0x131C ++#define TX_PWR_CFG_3 0x1320 ++#define TX_PWR_CFG_4 0x1324 ++#define TX_PIN_CFG 0x1328 ++#define TX_BAND_CFG 0x132c // 0x1 use upper 20MHz. 0 juse lower 20MHz ++#define TX_SW_CFG0 0x1330 ++#define TX_SW_CFG1 0x1334 ++#define TX_SW_CFG2 0x1338 ++#define TXOP_THRES_CFG 0x133c ++#define TXOP_CTRL_CFG 0x1340 ++#define TX_RTS_CFG 0x1344 ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_RTS_CFG_STRUC { ++ struct { ++ UINT32 rsv:7; ++ UINT32 RtsFbkEn:1; // enable rts rate fallback ++ UINT32 RtsThres:16; // unit:byte ++ UINT32 AutoRtsRetryLimit:8; ++ } field; ++ UINT32 word; ++} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; ++#else ++typedef union _TX_RTS_CFG_STRUC { ++ struct { ++ UINT32 AutoRtsRetryLimit:8; ++ UINT32 RtsThres:16; // unit:byte ++ UINT32 RtsFbkEn:1; // enable rts rate fallback ++ UINT32 rsv:7; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_RTS_CFG_STRUC, *PTX_RTS_CFG_STRUC; ++#endif ++#define TX_TIMEOUT_CFG 0x1348 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_TIMEOUT_CFG_STRUC { ++ struct { ++ UINT32 rsv2:8; ++ UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) ++ UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure ++ UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us ++ UINT32 rsv:4; ++ } field; ++ UINT32 word; ++} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; ++#else ++typedef union _TX_TIMEOUT_CFG_STRUC { ++ struct { ++ UINT32 rsv:4; ++ UINT32 MpduLifeTime:4; // expiration time = 2^(9+MPDU LIFE TIME) us ++ UINT32 RxAckTimeout:8; // unit:slot. Used for TX precedure ++ UINT32 TxopTimeout:8; //TXOP timeout value for TXOP truncation. It is recommended that (SLOT_TIME) > (TX_OP_TIMEOUT) > (RX_ACK_TIMEOUT) ++ UINT32 rsv2:8; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_TIMEOUT_CFG_STRUC, *PTX_TIMEOUT_CFG_STRUC; ++#endif ++#define TX_RTY_CFG 0x134c ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_RTY_CFG_STRUC { ++ struct { ++ UINT32 rsv:1; ++ UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable ++ UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 LongRtyThre:12; // Long retry threshoold ++ UINT32 LongRtyLimit:8; //long retry limit ++ UINT32 ShortRtyLimit:8; // short retry limit ++ ++ } field; ++ UINT32 word; ++} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; ++#else ++typedef union PACKED _TX_RTY_CFG_STRUC { ++ struct { ++ UINT32 ShortRtyLimit:8; // short retry limit ++ UINT32 LongRtyLimit:8; //long retry limit ++ UINT32 LongRtyThre:12; // Long retry threshoold ++ UINT32 NonAggRtyMode:1; // Non-Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 AggRtyMode:1; // Aggregate MPDU retry mode. 0:expired by retry limit, 1: expired by mpdu life timer ++ UINT32 TxautoFBEnable:1; // Tx retry PHY rate auto fallback enable ++ UINT32 rsv:1; // 1: HT non-STBC control frame enable ++ } field; ++ UINT32 word; ++} TX_RTY_CFG_STRUC, *PTX_RTY_CFG_STRUC; ++#endif ++#define TX_LINK_CFG 0x1350 ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_LINK_CFG_STRUC { ++ struct PACKED { ++ UINT32 RemotMFS:8; //remote MCS feedback sequence number ++ UINT32 RemotMFB:8; // remote MCS feedback ++ UINT32 rsv:3; // ++ UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable ++ UINT32 TxRDGEn:1; // RDG TX enable ++ UINT32 TxMRQEn:1; // MCS request TX enable ++ UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) ++ UINT32 MFBEnable:1; // TX apply remote MFB 1:enable ++ UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us ++ } field; ++ UINT32 word; ++} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; ++#else ++typedef union PACKED _TX_LINK_CFG_STRUC { ++ struct PACKED { ++ UINT32 RemoteMFBLifeTime:8; //remote MFB life time. unit : 32us ++ UINT32 MFBEnable:1; // TX apply remote MFB 1:enable ++ UINT32 RemoteUMFSEnable:1; // remote unsolicit MFB enable. 0: not apply remote remote unsolicit (MFS=7) ++ UINT32 TxMRQEn:1; // MCS request TX enable ++ UINT32 TxRDGEn:1; // RDG TX enable ++ UINT32 TxCFAckEn:1; // Piggyback CF-ACK enable ++ UINT32 rsv:3; // ++ UINT32 RemotMFB:8; // remote MCS feedback ++ UINT32 RemotMFS:8; //remote MCS feedback sequence number ++ } field; ++ UINT32 word; ++} TX_LINK_CFG_STRUC, *PTX_LINK_CFG_STRUC; ++#endif ++#define HT_FBK_CFG0 0x1354 ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _HT_FBK_CFG0_STRUC { ++ struct { ++ UINT32 HTMCS7FBK:4; ++ UINT32 HTMCS6FBK:4; ++ UINT32 HTMCS5FBK:4; ++ UINT32 HTMCS4FBK:4; ++ UINT32 HTMCS3FBK:4; ++ UINT32 HTMCS2FBK:4; ++ UINT32 HTMCS1FBK:4; ++ UINT32 HTMCS0FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; ++#else ++typedef union PACKED _HT_FBK_CFG0_STRUC { ++ struct { ++ UINT32 HTMCS0FBK:4; ++ UINT32 HTMCS1FBK:4; ++ UINT32 HTMCS2FBK:4; ++ UINT32 HTMCS3FBK:4; ++ UINT32 HTMCS4FBK:4; ++ UINT32 HTMCS5FBK:4; ++ UINT32 HTMCS6FBK:4; ++ UINT32 HTMCS7FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG0_STRUC, *PHT_FBK_CFG0_STRUC; ++#endif ++#define HT_FBK_CFG1 0x1358 ++#ifdef RT_BIG_ENDIAN ++typedef union _HT_FBK_CFG1_STRUC { ++ struct { ++ UINT32 HTMCS15FBK:4; ++ UINT32 HTMCS14FBK:4; ++ UINT32 HTMCS13FBK:4; ++ UINT32 HTMCS12FBK:4; ++ UINT32 HTMCS11FBK:4; ++ UINT32 HTMCS10FBK:4; ++ UINT32 HTMCS9FBK:4; ++ UINT32 HTMCS8FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; ++#else ++typedef union _HT_FBK_CFG1_STRUC { ++ struct { ++ UINT32 HTMCS8FBK:4; ++ UINT32 HTMCS9FBK:4; ++ UINT32 HTMCS10FBK:4; ++ UINT32 HTMCS11FBK:4; ++ UINT32 HTMCS12FBK:4; ++ UINT32 HTMCS13FBK:4; ++ UINT32 HTMCS14FBK:4; ++ UINT32 HTMCS15FBK:4; ++ } field; ++ UINT32 word; ++} HT_FBK_CFG1_STRUC, *PHT_FBK_CFG1_STRUC; ++#endif ++#define LG_FBK_CFG0 0x135c ++#ifdef RT_BIG_ENDIAN ++typedef union _LG_FBK_CFG0_STRUC { ++ struct { ++ UINT32 OFDMMCS7FBK:4; //initial value is 6 ++ UINT32 OFDMMCS6FBK:4; //initial value is 5 ++ UINT32 OFDMMCS5FBK:4; //initial value is 4 ++ UINT32 OFDMMCS4FBK:4; //initial value is 3 ++ UINT32 OFDMMCS3FBK:4; //initial value is 2 ++ UINT32 OFDMMCS2FBK:4; //initial value is 1 ++ UINT32 OFDMMCS1FBK:4; //initial value is 0 ++ UINT32 OFDMMCS0FBK:4; //initial value is 0 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; ++#else ++typedef union _LG_FBK_CFG0_STRUC { ++ struct { ++ UINT32 OFDMMCS0FBK:4; //initial value is 0 ++ UINT32 OFDMMCS1FBK:4; //initial value is 0 ++ UINT32 OFDMMCS2FBK:4; //initial value is 1 ++ UINT32 OFDMMCS3FBK:4; //initial value is 2 ++ UINT32 OFDMMCS4FBK:4; //initial value is 3 ++ UINT32 OFDMMCS5FBK:4; //initial value is 4 ++ UINT32 OFDMMCS6FBK:4; //initial value is 5 ++ UINT32 OFDMMCS7FBK:4; //initial value is 6 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG0_STRUC, *PLG_FBK_CFG0_STRUC; ++#endif ++#define LG_FBK_CFG1 0x1360 ++#ifdef RT_BIG_ENDIAN ++typedef union _LG_FBK_CFG1_STRUC { ++ struct { ++ UINT32 rsv:16; ++ UINT32 CCKMCS3FBK:4; //initial value is 2 ++ UINT32 CCKMCS2FBK:4; //initial value is 1 ++ UINT32 CCKMCS1FBK:4; //initial value is 0 ++ UINT32 CCKMCS0FBK:4; //initial value is 0 ++ } field; ++ UINT32 word; ++} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; ++#else ++typedef union _LG_FBK_CFG1_STRUC { ++ struct { ++ UINT32 CCKMCS0FBK:4; //initial value is 0 ++ UINT32 CCKMCS1FBK:4; //initial value is 0 ++ UINT32 CCKMCS2FBK:4; //initial value is 1 ++ UINT32 CCKMCS3FBK:4; //initial value is 2 ++ UINT32 rsv:16; ++ } field; ++ UINT32 word; ++} LG_FBK_CFG1_STRUC, *PLG_FBK_CFG1_STRUC; ++#endif ++ ++//======================================================= ++//================ Protection Paramater================================ ++//======================================================= ++#define CCK_PROT_CFG 0x1364 //CCK Protection ++#define ASIC_SHORTNAV 1 ++#define ASIC_LONGNAV 2 ++#define ASIC_RTS 1 ++#define ASIC_CTS 2 ++#ifdef RT_BIG_ENDIAN ++typedef union _PROT_CFG_STRUC { ++ struct { ++ UINT32 rsv:5; ++ UINT32 RTSThEn:1; //RTS threshold enable on CCK TX ++ UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. ++ UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. ++ UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv ++ UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv ++ UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). ++ } field; ++ UINT32 word; ++} PROT_CFG_STRUC, *PPROT_CFG_STRUC; ++#else ++typedef union _PROT_CFG_STRUC { ++ struct { ++ UINT32 ProtectRate:16; //Protection control frame rate for CCK TX(RTS/CTS/CFEnd). ++ UINT32 ProtectCtrl:2; //Protection control frame type for CCK TX. 1:RTS/CTS, 2:CTS-to-self, 0:None, 3:rsv ++ UINT32 ProtectNav:2; //TXOP protection type for CCK TX. 0:None, 1:ShortNAVprotect, 2:LongNAVProtect, 3:rsv ++ UINT32 TxopAllowCck:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowOfdm:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowMM20:1; //CCK TXOP allowance. 0:disallow. ++ UINT32 TxopAllowMM40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF20:1; //CCK TXOP allowance.0:disallow. ++ UINT32 TxopAllowGF40:1; //CCK TXOP allowance.0:disallow. ++ UINT32 RTSThEn:1; //RTS threshold enable on CCK TX ++ UINT32 rsv:5; ++ } field; ++ UINT32 word; ++} PROT_CFG_STRUC, *PPROT_CFG_STRUC; ++#endif ++ ++#define OFDM_PROT_CFG 0x1368 //OFDM Protection ++#define MM20_PROT_CFG 0x136C //MM20 Protection ++#define MM40_PROT_CFG 0x1370 //MM40 Protection ++#define GF20_PROT_CFG 0x1374 //GF20 Protection ++#define GF40_PROT_CFG 0x1378 //GR40 Protection ++#define EXP_CTS_TIME 0x137C // ++#define EXP_ACK_TIME 0x1380 // ++ ++// ++// 4.4 MAC RX configuration registers (offset:0x1400) ++// ++#define RX_FILTR_CFG 0x1400 //TXRX_CSR0 ++#define AUTO_RSP_CFG 0x1404 //TXRX_CSR4 ++// ++// TXRX_CSR4: Auto-Responder/ ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _AUTO_RSP_CFG_STRUC { ++ struct { ++ UINT32 :24; ++ UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame ++ UINT32 DualCTSEn:1; // Power bit value in conrtrol frame ++ UINT32 rsv:1; // Power bit value in conrtrol frame ++ UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble ++ UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode ++ UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode ++ UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble ++ UINT32 AutoResponderEnable:1; ++ } field; ++ UINT32 word; ++} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; ++#else ++typedef union _AUTO_RSP_CFG_STRUC { ++ struct { ++ UINT32 AutoResponderEnable:1; ++ UINT32 BACAckPolicyEnable:1; // 0:long, 1:short preamble ++ UINT32 CTS40MMode:1; // Response CTS 40MHz duplicate mode ++ UINT32 CTS40MRef:1; // Response CTS 40MHz duplicate mode ++ UINT32 AutoResponderPreamble:1; // 0:long, 1:short preamble ++ UINT32 rsv:1; // Power bit value in conrtrol frame ++ UINT32 DualCTSEn:1; // Power bit value in conrtrol frame ++ UINT32 AckCtsPsmBit:1; // Power bit value in conrtrol frame ++ UINT32 :24; ++ } field; ++ UINT32 word; ++} AUTO_RSP_CFG_STRUC, *PAUTO_RSP_CFG_STRUC; ++#endif ++ ++#define LEGACY_BASIC_RATE 0x1408 // TXRX_CSR5 0x3054 ++#define HT_BASIC_RATE 0x140c ++#define HT_CTRL_CFG 0x1410 ++#define SIFS_COST_CFG 0x1414 ++#define RX_PARSER_CFG 0x1418 //Set NAV for all received frames ++ ++// ++// 4.5 MAC Security configuration (offset:0x1500) ++// ++#define TX_SEC_CNT0 0x1500 // ++#define RX_SEC_CNT0 0x1504 // ++#define CCMP_FC_MUTE 0x1508 // ++// ++// 4.6 HCCA/PSMP (offset:0x1600) ++// ++#define TXOP_HLDR_ADDR0 0x1600 ++#define TXOP_HLDR_ADDR1 0x1604 ++#define TXOP_HLDR_ET 0x1608 ++#define QOS_CFPOLL_RA_DW0 0x160c ++#define QOS_CFPOLL_A1_DW1 0x1610 ++#define QOS_CFPOLL_QC 0x1614 ++// ++// 4.7 MAC Statistis registers (offset:0x1700) ++// ++#define RX_STA_CNT0 0x1700 // ++#define RX_STA_CNT1 0x1704 // ++#define RX_STA_CNT2 0x1708 // ++ ++// ++// RX_STA_CNT0_STRUC: RX PLCP error count & RX CRC error count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT0_STRUC { ++ struct { ++ USHORT PhyErr; ++ USHORT CrcErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; ++#else ++typedef union _RX_STA_CNT0_STRUC { ++ struct { ++ USHORT CrcErr; ++ USHORT PhyErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT0_STRUC, *PRX_STA_CNT0_STRUC; ++#endif ++ ++// ++// RX_STA_CNT1_STRUC: RX False CCA count & RX LONG frame count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT1_STRUC { ++ struct { ++ USHORT PlcpErr; ++ USHORT FalseCca; ++ } field; ++ UINT32 word; ++} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; ++#else ++typedef union _RX_STA_CNT1_STRUC { ++ struct { ++ USHORT FalseCca; ++ USHORT PlcpErr; ++ } field; ++ UINT32 word; ++} RX_STA_CNT1_STRUC, *PRX_STA_CNT1_STRUC; ++#endif ++ ++// ++// RX_STA_CNT2_STRUC: ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _RX_STA_CNT2_STRUC { ++ struct { ++ USHORT RxFifoOverflowCount; ++ USHORT RxDupliCount; ++ } field; ++ UINT32 word; ++} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; ++#else ++typedef union _RX_STA_CNT2_STRUC { ++ struct { ++ USHORT RxDupliCount; ++ USHORT RxFifoOverflowCount; ++ } field; ++ UINT32 word; ++} RX_STA_CNT2_STRUC, *PRX_STA_CNT2_STRUC; ++#endif ++#define TX_STA_CNT0 0x170C // ++// ++// STA_CSR3: TX Beacon count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT0_STRUC { ++ struct { ++ USHORT TxBeaconCount; ++ USHORT TxFailCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; ++#else ++typedef union _TX_STA_CNT0_STRUC { ++ struct { ++ USHORT TxFailCount; ++ USHORT TxBeaconCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT0_STRUC, *PTX_STA_CNT0_STRUC; ++#endif ++#define TX_STA_CNT1 0x1710 // ++// ++// TX_STA_CNT1: TX tx count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT1_STRUC { ++ struct { ++ USHORT TxRetransmit; ++ USHORT TxSuccess; ++ } field; ++ UINT32 word; ++} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; ++#else ++typedef union _TX_STA_CNT1_STRUC { ++ struct { ++ USHORT TxSuccess; ++ USHORT TxRetransmit; ++ } field; ++ UINT32 word; ++} TX_STA_CNT1_STRUC, *PTX_STA_CNT1_STRUC; ++#endif ++#define TX_STA_CNT2 0x1714 // ++// ++// TX_STA_CNT2: TX tx count ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_STA_CNT2_STRUC { ++ struct { ++ USHORT TxUnderFlowCount; ++ USHORT TxZeroLenCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; ++#else ++typedef union _TX_STA_CNT2_STRUC { ++ struct { ++ USHORT TxZeroLenCount; ++ USHORT TxUnderFlowCount; ++ } field; ++ UINT32 word; ++} TX_STA_CNT2_STRUC, *PTX_STA_CNT2_STRUC; ++#endif ++#define TX_STA_FIFO 0x1718 // ++// ++// TX_STA_FIFO_STRUC: TX Result for specific PID status fifo register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union PACKED _TX_STA_FIFO_STRUC { ++ struct { ++ UINT32 Reserve:2; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 wcid:8; //wireless client index ++ UINT32 TxAckRequired:1; // ack required ++ UINT32 TxAggre:1; // Tx is aggregated ++ UINT32 TxSuccess:1; // Tx success. whether success or not ++ UINT32 PidType:4; ++ UINT32 bValid:1; // 1:This register contains a valid TX result ++ } field; ++ UINT32 word; ++} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; ++#else ++typedef union PACKED _TX_STA_FIFO_STRUC { ++ struct { ++ UINT32 bValid:1; // 1:This register contains a valid TX result ++ UINT32 PidType:4; ++ UINT32 TxSuccess:1; // Tx No retry success ++ UINT32 TxAggre:1; // Tx Retry Success ++ UINT32 TxAckRequired:1; // Tx fail ++ UINT32 wcid:8; //wireless client index ++// UINT32 SuccessRate:16; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 SuccessRate:13; //include MCS, mode ,shortGI, BW settingSame format as TXWI Word 0 Bit 31-16. ++ UINT32 TxBF:1; ++ UINT32 Reserve:2; ++ } field; ++ UINT32 word; ++} TX_STA_FIFO_STRUC, *PTX_STA_FIFO_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT 0x171c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT_STRUC { ++ struct { ++ USHORT AggTxCount; ++ USHORT NonAggTxCount; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; ++#else ++typedef union _TX_AGG_CNT_STRUC { ++ struct { ++ USHORT NonAggTxCount; ++ USHORT AggTxCount; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT_STRUC, *PTX_AGG_CNT_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT0 0x1720 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT0_STRUC { ++ struct { ++ USHORT AggSize2Count; ++ USHORT AggSize1Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; ++#else ++typedef union _TX_AGG_CNT0_STRUC { ++ struct { ++ USHORT AggSize1Count; ++ USHORT AggSize2Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT0_STRUC, *PTX_AGG_CNT0_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT1 0x1724 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT1_STRUC { ++ struct { ++ USHORT AggSize4Count; ++ USHORT AggSize3Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; ++#else ++typedef union _TX_AGG_CNT1_STRUC { ++ struct { ++ USHORT AggSize3Count; ++ USHORT AggSize4Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT1_STRUC, *PTX_AGG_CNT1_STRUC; ++#endif ++#define TX_AGG_CNT2 0x1728 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT2_STRUC { ++ struct { ++ USHORT AggSize6Count; ++ USHORT AggSize5Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; ++#else ++typedef union _TX_AGG_CNT2_STRUC { ++ struct { ++ USHORT AggSize5Count; ++ USHORT AggSize6Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT2_STRUC, *PTX_AGG_CNT2_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT3 0x172c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT3_STRUC { ++ struct { ++ USHORT AggSize8Count; ++ USHORT AggSize7Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; ++#else ++typedef union _TX_AGG_CNT3_STRUC { ++ struct { ++ USHORT AggSize7Count; ++ USHORT AggSize8Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT3_STRUC, *PTX_AGG_CNT3_STRUC; ++#endif ++// Debug counter ++#define TX_AGG_CNT4 0x1730 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT4_STRUC { ++ struct { ++ USHORT AggSize10Count; ++ USHORT AggSize9Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; ++#else ++typedef union _TX_AGG_CNT4_STRUC { ++ struct { ++ USHORT AggSize9Count; ++ USHORT AggSize10Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT4_STRUC, *PTX_AGG_CNT4_STRUC; ++#endif ++#define TX_AGG_CNT5 0x1734 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT5_STRUC { ++ struct { ++ USHORT AggSize12Count; ++ USHORT AggSize11Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; ++#else ++typedef union _TX_AGG_CNT5_STRUC { ++ struct { ++ USHORT AggSize11Count; ++ USHORT AggSize12Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT5_STRUC, *PTX_AGG_CNT5_STRUC; ++#endif ++#define TX_AGG_CNT6 0x1738 ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT6_STRUC { ++ struct { ++ USHORT AggSize14Count; ++ USHORT AggSize13Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; ++#else ++typedef union _TX_AGG_CNT6_STRUC { ++ struct { ++ USHORT AggSize13Count; ++ USHORT AggSize14Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT6_STRUC, *PTX_AGG_CNT6_STRUC; ++#endif ++#define TX_AGG_CNT7 0x173c ++#ifdef RT_BIG_ENDIAN ++typedef union _TX_AGG_CNT7_STRUC { ++ struct { ++ USHORT AggSize16Count; ++ USHORT AggSize15Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; ++#else ++typedef union _TX_AGG_CNT7_STRUC { ++ struct { ++ USHORT AggSize15Count; ++ USHORT AggSize16Count; ++ } field; ++ UINT32 word; ++} TX_AGG_CNT7_STRUC, *PTX_AGG_CNT7_STRUC; ++#endif ++#define MPDU_DENSITY_CNT 0x1740 ++#ifdef RT_BIG_ENDIAN ++typedef union _MPDU_DEN_CNT_STRUC { ++ struct { ++ USHORT RXZeroDelCount; //RX zero length delimiter count ++ USHORT TXZeroDelCount; //TX zero length delimiter count ++ } field; ++ UINT32 word; ++} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; ++#else ++typedef union _MPDU_DEN_CNT_STRUC { ++ struct { ++ USHORT TXZeroDelCount; //TX zero length delimiter count ++ USHORT RXZeroDelCount; //RX zero length delimiter count ++ } field; ++ UINT32 word; ++} MPDU_DEN_CNT_STRUC, *PMPDU_DEN_CNT_STRUC; ++#endif ++// ++// TXRX control registers - base address 0x3000 ++// ++// rt2860b UNKNOWN reg use R/O Reg Addr 0x77d0 first.. ++#define TXRX_CSR1 0x77d0 ++ ++// ++// Security key table memory, base address = 0x1000 ++// ++#define MAC_WCID_BASE 0x1800 //8-bytes(use only 6-bytes) * 256 entry = ++#define HW_WCID_ENTRY_SIZE 8 ++#define PAIRWISE_KEY_TABLE_BASE 0x4000 // 32-byte * 256-entry = -byte ++#define HW_KEY_ENTRY_SIZE 0x20 ++#define PAIRWISE_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte ++#define MAC_IVEIV_TABLE_BASE 0x6000 // 8-byte * 256-entry = -byte ++#define HW_IVEIV_ENTRY_SIZE 8 ++#define MAC_WCID_ATTRIBUTE_BASE 0x6800 // 4-byte * 256-entry = -byte ++#define HW_WCID_ATTRI_SIZE 4 ++#define WCID_RESERVED 0x6bfc ++#define SHARED_KEY_TABLE_BASE 0x6c00 // 32-byte * 16-entry = 512-byte ++#define SHARED_KEY_MODE_BASE 0x7000 // 32-byte * 16-entry = 512-byte ++#define HW_SHARED_KEY_MODE_SIZE 4 ++#define SHAREDKEYTABLE 0 ++#define PAIRWISEKEYTABLE 1 ++ ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _SHAREDKEY_MODE_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 Bss1Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key0CipherAlg:3; ++ } field; ++ UINT32 word; ++} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; ++#else ++typedef union _SHAREDKEY_MODE_STRUC { ++ struct { ++ UINT32 Bss0Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss0Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss1Key3CipherAlg:3; ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} SHAREDKEY_MODE_STRUC, *PSHAREDKEY_MODE_STRUC; ++#endif ++// 64-entry for pairwise key table ++typedef struct _HW_WCID_ENTRY { // 8-byte per entry ++ UCHAR Address[6]; ++ UCHAR Rsv[2]; ++} HW_WCID_ENTRY, PHW_WCID_ENTRY; ++ ++ ++ ++// ++// Other on-chip shared memory space, base = 0x2000 ++// ++ ++// CIS space - base address = 0x2000 ++#define HW_CIS_BASE 0x2000 ++ ++// Carrier-sense CTS frame base address. It's where mac stores carrier-sense frame for carrier-sense function. ++#define HW_CS_CTS_BASE 0x7700 ++// DFS CTS frame base address. It's where mac stores CTS frame for DFS. ++#define HW_DFS_CTS_BASE 0x7780 ++#define HW_CTS_FRAME_SIZE 0x80 ++ ++// 2004-11-08 john - since NULL frame won't be that long (256 byte). We steal 16 tail bytes ++// to save debugging settings ++#define HW_DEBUG_SETTING_BASE 0x77f0 // 0x77f0~0x77ff total 16 bytes ++#define HW_DEBUG_SETTING_BASE2 0x7770 // 0x77f0~0x77ff total 16 bytes ++ ++// In order to support maximum 8 MBSS and its maximum length is 512 for each beacon ++// Three section discontinue memory segments will be used. ++// 1. The original region for BCN 0~3 ++// 2. Extract memory from FCE table for BCN 4~5 ++// 3. Extract memory from Pair-wise key table for BCN 6~7 ++// It occupied those memory of wcid 238~253 for BCN 6 ++// and wcid 222~237 for BCN 7 ++#define HW_BEACON_MAX_SIZE 0x1000 /* unit: byte */ ++#define HW_BEACON_BASE0 0x7800 ++#define HW_BEACON_BASE1 0x7A00 ++#define HW_BEACON_BASE2 0x7C00 ++#define HW_BEACON_BASE3 0x7E00 ++#define HW_BEACON_BASE4 0x7200 ++#define HW_BEACON_BASE5 0x7400 ++#define HW_BEACON_BASE6 0x5DC0 ++#define HW_BEACON_BASE7 0x5BC0 ++ ++#define HW_BEACON_MAX_COUNT 8 ++#define HW_BEACON_OFFSET 0x0200 ++#define HW_BEACON_CONTENT_LEN (HW_BEACON_OFFSET - TXWI_SIZE) ++ ++// HOST-MCU shared memory - base address = 0x2100 ++#define HOST_CMD_CSR 0x404 ++#define H2M_MAILBOX_CSR 0x7010 ++#define H2M_MAILBOX_CID 0x7014 ++#define H2M_MAILBOX_STATUS 0x701c ++#define H2M_INT_SRC 0x7024 ++#define H2M_BBP_AGENT 0x7028 ++#define M2H_CMD_DONE_CSR 0x000c ++#define MCU_TXOP_ARRAY_BASE 0x000c // TODO: to be provided by Albert ++#define MCU_TXOP_ENTRY_SIZE 32 // TODO: to be provided by Albert ++#define MAX_NUM_OF_TXOP_ENTRY 16 // TODO: must be same with 8051 firmware ++#define MCU_MBOX_VERSION 0x01 // TODO: to be confirmed by Albert ++#define MCU_MBOX_VERSION_OFFSET 5 // TODO: to be provided by Albert ++ ++// ++// Host DMA registers - base address 0x200 . TX0-3=EDCAQid0-3, TX4=HCCA, TX5=MGMT, ++// ++// ++// DMA RING DESCRIPTOR ++// ++#define E2PROM_CSR 0x0004 ++#define IO_CNTL_CSR 0x77d0 ++ ++#ifdef RT2870 ++// 8051 firmware image for usb - use last-half base address = 0x3000 ++#define FIRMWARE_IMAGE_BASE 0x3000 ++#define MAX_FIRMWARE_IMAGE_SIZE 0x1000 // 4kbyte ++#endif // RT2870 // ++ ++// TODO: ????? old RT2560 registers. to keep them or remove them? ++//#define MCAST0 0x0178 // multicast filter register 0 ++//#define MCAST1 0x017c // multicast filter register 1 ++ ++ ++// ================================================================ ++// Tx / Rx / Mgmt ring descriptor definition ++// ================================================================ ++ ++// the following PID values are used to mark outgoing frame type in TXD->PID so that ++// proper TX statistics can be collected based on these categories ++// b3-2 of PID field - ++#define PID_MGMT 0x05 ++#define PID_BEACON 0x0c ++#define PID_DATA_NORMALUCAST 0x02 ++#define PID_DATA_AMPDU 0x04 ++#define PID_DATA_NO_ACK 0x08 ++#define PID_DATA_NOT_NORM_ACK 0x03 ++// value domain of pTxD->HostQId (4-bit: 0~15) ++#define QID_AC_BK 1 // meet ACI definition in 802.11e ++#define QID_AC_BE 0 // meet ACI definition in 802.11e ++#define QID_AC_VI 2 ++#define QID_AC_VO 3 ++#define QID_HCCA 4 ++#define NUM_OF_TX_RING 5 ++#define QID_MGMT 13 ++#define QID_RX 14 ++#define QID_OTHER 15 ++ ++ ++// ------------------------------------------------------ ++// BBP & RF definition ++// ------------------------------------------------------ ++#define BUSY 1 ++#define IDLE 0 ++ ++#define RF_R00 0 ++#define RF_R01 1 ++#define RF_R02 2 ++#define RF_R03 3 ++#define RF_R04 4 ++#define RF_R05 5 ++#define RF_R06 6 ++#define RF_R07 7 ++#define RF_R08 8 ++#define RF_R09 9 ++#define RF_R10 10 ++#define RF_R11 11 ++#define RF_R12 12 ++#define RF_R13 13 ++#define RF_R14 14 ++#define RF_R15 15 ++#define RF_R16 16 ++#define RF_R17 17 ++#define RF_R18 18 ++#define RF_R19 19 ++#define RF_R20 20 ++#define RF_R21 21 ++#define RF_R22 22 ++#define RF_R23 23 ++#define RF_R24 24 ++#define RF_R25 25 ++#define RF_R26 26 ++#define RF_R27 27 ++#define RF_R28 28 ++#define RF_R29 29 ++#define RF_R30 30 ++#define RF_R31 31 ++ ++#define BBP_R0 0 // version ++#define BBP_R1 1 // TSSI ++#define BBP_R2 2 // TX configure ++#define BBP_R3 3 ++#define BBP_R4 4 ++#define BBP_R5 5 ++#define BBP_R6 6 ++#define BBP_R14 14 // RX configure ++#define BBP_R16 16 ++#define BBP_R17 17 // RX sensibility ++#define BBP_R18 18 ++#define BBP_R21 21 ++#define BBP_R22 22 ++#define BBP_R24 24 ++#define BBP_R25 25 ++#define BBP_R31 31 ++#define BBP_R49 49 //TSSI ++#define BBP_R50 50 ++#define BBP_R51 51 ++#define BBP_R52 52 ++#define BBP_R55 55 ++#define BBP_R62 62 // Rx SQ0 Threshold HIGH ++#define BBP_R63 63 ++#define BBP_R64 64 ++#define BBP_R65 65 ++#define BBP_R66 66 ++#define BBP_R67 67 ++#define BBP_R68 68 ++#define BBP_R69 69 ++#define BBP_R70 70 // Rx AGC SQ CCK Xcorr threshold ++#define BBP_R73 73 ++#define BBP_R75 75 ++#define BBP_R77 77 ++#define BBP_R79 79 ++#define BBP_R80 80 ++#define BBP_R81 81 ++#define BBP_R82 82 ++#define BBP_R83 83 ++#define BBP_R84 84 ++#define BBP_R86 86 ++#define BBP_R91 91 ++#define BBP_R92 92 ++#define BBP_R94 94 // Tx Gain Control ++#define BBP_R103 103 ++#define BBP_R105 105 ++#define BBP_R113 113 ++#define BBP_R114 114 ++#define BBP_R115 115 ++#define BBP_R116 116 ++#define BBP_R117 117 ++#define BBP_R118 118 ++#define BBP_R119 119 ++#define BBP_R120 120 ++#define BBP_R121 121 ++#define BBP_R122 122 ++#define BBP_R123 123 ++#ifdef RT30xx ++#define BBP_R138 138 // add by johnli, RF power sequence setup, ADC dynamic on/off control ++#endif // RT30xx // ++ ++ ++#define BBPR94_DEFAULT 0x06 // Add 1 value will gain 1db ++ ++//#define PHY_TR_SWITCH_TIME 5 // usec ++ ++//#define BBP_R17_LOW_SENSIBILITY 0x50 ++//#define BBP_R17_MID_SENSIBILITY 0x41 ++//#define BBP_R17_DYNAMIC_UP_BOUND 0x40 ++#define RSSI_FOR_VERY_LOW_SENSIBILITY -35 ++#define RSSI_FOR_LOW_SENSIBILITY -58 ++#define RSSI_FOR_MID_LOW_SENSIBILITY -80 ++#define RSSI_FOR_MID_SENSIBILITY -90 ++ ++//------------------------------------------------------------------------- ++// EEPROM definition ++//------------------------------------------------------------------------- ++#define EEDO 0x08 ++#define EEDI 0x04 ++#define EECS 0x02 ++#define EESK 0x01 ++#define EERL 0x80 ++ ++#define EEPROM_WRITE_OPCODE 0x05 ++#define EEPROM_READ_OPCODE 0x06 ++#define EEPROM_EWDS_OPCODE 0x10 ++#define EEPROM_EWEN_OPCODE 0x13 ++ ++#define NUM_EEPROM_BBP_PARMS 19 // Include NIC Config 0, 1, CR, TX ALC step, BBPs ++#define NUM_EEPROM_TX_G_PARMS 7 ++#define EEPROM_NIC1_OFFSET 0x34 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_NIC2_OFFSET 0x36 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_BBP_BASE_OFFSET 0xf0 // The address is from NIC config 0, not BBP register ID ++#define EEPROM_G_TX_PWR_OFFSET 0x52 ++#define EEPROM_G_TX2_PWR_OFFSET 0x60 ++#define EEPROM_LED1_OFFSET 0x3c ++#define EEPROM_LED2_OFFSET 0x3e ++#define EEPROM_LED3_OFFSET 0x40 ++#define EEPROM_LNA_OFFSET 0x44 ++#define EEPROM_RSSI_BG_OFFSET 0x46 ++#define EEPROM_RSSI_A_OFFSET 0x4a ++#define EEPROM_DEFINE_MAX_TXPWR 0x4e ++#define EEPROM_TXPOWER_BYRATE_20MHZ_2_4G 0xde // 20MHZ 2.4G tx power. ++#define EEPROM_TXPOWER_BYRATE_40MHZ_2_4G 0xee // 40MHZ 2.4G tx power. ++#define EEPROM_TXPOWER_BYRATE_20MHZ_5G 0xfa // 20MHZ 5G tx power. ++#define EEPROM_TXPOWER_BYRATE_40MHZ_5G 0x10a // 40MHZ 5G tx power. ++#define EEPROM_A_TX_PWR_OFFSET 0x78 ++#define EEPROM_A_TX2_PWR_OFFSET 0xa6 ++//#define EEPROM_Japan_TX_PWR_OFFSET 0x90 // 802.11j ++//#define EEPROM_Japan_TX2_PWR_OFFSET 0xbe ++//#define EEPROM_TSSI_REF_OFFSET 0x54 ++//#define EEPROM_TSSI_DELTA_OFFSET 0x24 ++//#define EEPROM_CCK_TX_PWR_OFFSET 0x62 ++//#define EEPROM_CALIBRATE_OFFSET 0x7c ++#define EEPROM_VERSION_OFFSET 0x02 ++#define EEPROM_FREQ_OFFSET 0x3a ++#define EEPROM_TXPOWER_BYRATE 0xde // 20MHZ power. ++#define EEPROM_TXPOWER_DELTA 0x50 // 20MHZ AND 40 MHZ use different power. This is delta in 40MHZ. ++#define VALID_EEPROM_VERSION 1 ++ ++// PairKeyMode definition ++#define PKMODE_NONE 0 ++#define PKMODE_WEP64 1 ++#define PKMODE_WEP128 2 ++#define PKMODE_TKIP 3 ++#define PKMODE_AES 4 ++#define PKMODE_CKIP64 5 ++#define PKMODE_CKIP128 6 ++#define PKMODE_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table ++ ++// ================================================================================= ++// WCID format ++// ================================================================================= ++//7.1 WCID ENTRY format : 8bytes ++typedef struct _WCID_ENTRY_STRUC { ++ UCHAR RXBABitmap7; // bit0 for TID8, bit7 for TID 15 ++ UCHAR RXBABitmap0; // bit0 for TID0, bit7 for TID 7 ++ UCHAR MAC[6]; // 0 for shared key table. 1 for pairwise key table ++} WCID_ENTRY_STRUC, *PWCID_ENTRY_STRUC; ++ ++//8.1.1 SECURITY KEY format : 8DW ++// 32-byte per entry, total 16-entry for shared key table, 64-entry for pairwise key table ++typedef struct _HW_KEY_ENTRY { // 32-byte per entry ++ UCHAR Key[16]; ++ UCHAR TxMic[8]; ++ UCHAR RxMic[8]; ++} HW_KEY_ENTRY, *PHW_KEY_ENTRY; ++ ++//8.1.2 IV/EIV format : 2DW ++ ++//8.1.3 RX attribute entry format : 1DW ++#ifdef RT_BIG_ENDIAN ++typedef struct _MAC_ATTRIBUTE_STRUC { ++ UINT32 rsv:22; ++ UINT32 RXWIUDF:3; ++ UINT32 BSSIDIdx:3; //multipleBSS index for the WCID ++ UINT32 PairKeyMode:3; ++ UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table ++} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; ++#else ++typedef struct _MAC_ATTRIBUTE_STRUC { ++ UINT32 KeyTab:1; // 0 for shared key table. 1 for pairwise key table ++ UINT32 PairKeyMode:3; ++ UINT32 BSSIDIdx:3; //multipleBSS index for the WCID ++ UINT32 RXWIUDF:3; ++ UINT32 rsv:22; ++} MAC_ATTRIBUTE_STRUC, *PMAC_ATTRIBUTE_STRUC; ++#endif ++ ++ ++// ================================================================================= ++// TX / RX ring descriptor format ++// ================================================================================= ++ ++// the first 24-byte in TXD is called TXINFO and will be DMAed to MAC block through TXFIFO. ++// MAC block use this TXINFO to control the transmission behavior of this frame. ++#define FIFO_MGMT 0 ++#define FIFO_HCCA 1 ++#define FIFO_EDCA 2 ++ ++// ++// TX descriptor format, Tx ring, Mgmt Ring ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _TXD_STRUC { ++ // Word 0 ++ UINT32 SDPtr0; ++ // Word 1 ++ UINT32 DMADONE:1; ++ UINT32 LastSec0:1; ++ UINT32 SDLen0:14; ++ UINT32 Burst:1; ++ UINT32 LastSec1:1; ++ UINT32 SDLen1:14; ++ // Word 2 ++ UINT32 SDPtr1; ++ // Word 3 ++ UINT32 ICO:1; ++ UINT32 UCO:1; ++ UINT32 TCO:1; ++ UINT32 rsv:2; ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 rsv2:24; ++} TXD_STRUC, *PTXD_STRUC; ++#else ++typedef struct PACKED _TXD_STRUC { ++ // Word 0 ++ UINT32 SDPtr0; ++ // Word 1 ++ UINT32 SDLen1:14; ++ UINT32 LastSec1:1; ++ UINT32 Burst:1; ++ UINT32 SDLen0:14; ++ UINT32 LastSec0:1; ++ UINT32 DMADONE:1; ++ //Word2 ++ UINT32 SDPtr1; ++ //Word3 ++ UINT32 rsv2:24; ++ UINT32 WIV:1; // Wireless Info Valid. 1 if Driver already fill WI, o if DMA needs to copy WI to correctposition ++ UINT32 QSEL:2; // select on-chip FIFO ID for 2nd-stage output scheduler.0:MGMT, 1:HCCA 2:EDCA ++ UINT32 rsv:2; ++ UINT32 TCO:1; // ++ UINT32 UCO:1; // ++ UINT32 ICO:1; // ++} TXD_STRUC, *PTXD_STRUC; ++#endif ++ ++ ++// ++// TXD Wireless Information format for Tx ring and Mgmt Ring ++// ++//txop : for txop mode ++// 0:txop for the MPDU frame will be handles by ASIC by register ++// 1/2/3:the MPDU frame is send after PIFS/backoff/SIFS ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _TXWI_STRUC { ++ // Word 0 ++ UINT32 PHYMODE:2; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 rsv2:1; ++// UINT32 rsv2:2; ++ UINT32 Ifs:1; // ++ UINT32 STBC:2; //channel bandwidth 20MHz or 40 MHz ++ UINT32 ShortGI:1; ++ UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz ++ UINT32 MCS:7; ++ ++ UINT32 rsv:6; ++ UINT32 txop:2; //tx back off mode 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. ++ UINT32 MpduDensity:3; ++ UINT32 AMPDU:1; ++ ++ UINT32 TS:1; ++ UINT32 CFACK:1; ++ UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode ++ UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. ++ // Word 1 ++ UINT32 PacketId:4; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 WirelessCliID:8; ++ UINT32 BAWinSize:6; ++ UINT32 NSEQ:1; ++ UINT32 ACK:1; ++ // Word 2 ++ UINT32 IV; ++ // Word 3 ++ UINT32 EIV; ++} TXWI_STRUC, *PTXWI_STRUC; ++#else ++typedef struct PACKED _TXWI_STRUC { ++ // Word 0 ++ UINT32 FRAG:1; // 1 to inform TKIP engine this is a fragment. ++ UINT32 MIMOps:1; // the remote peer is in dynamic MIMO-PS mode ++ UINT32 CFACK:1; ++ UINT32 TS:1; ++ ++ UINT32 AMPDU:1; ++ UINT32 MpduDensity:3; ++ UINT32 txop:2; //FOR "THIS" frame. 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs only when previous frame exchange is successful. ++ UINT32 rsv:6; ++ ++ UINT32 MCS:7; ++ UINT32 BW:1; //channel bandwidth 20MHz or 40 MHz ++ UINT32 ShortGI:1; ++ UINT32 STBC:2; // 1: STBC support MCS =0-7, 2,3 : RESERVE ++ UINT32 Ifs:1; // ++// UINT32 rsv2:2; //channel bandwidth 20MHz or 40 MHz ++ UINT32 rsv2:1; ++ UINT32 TxBF:1; // 3*3 ++ UINT32 PHYMODE:2; ++ // Word 1 ++ UINT32 ACK:1; ++ UINT32 NSEQ:1; ++ UINT32 BAWinSize:6; ++ UINT32 WirelessCliID:8; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 PacketId:4; ++ //Word2 ++ UINT32 IV; ++ //Word3 ++ UINT32 EIV; ++} TXWI_STRUC, *PTXWI_STRUC; ++#endif ++// ++// Rx descriptor format, Rx Ring ++// ++// ++// RXWI wireless information format, in PBF. invisible in driver. ++// ++#ifdef RT_BIG_ENDIAN ++typedef struct PACKED _RXWI_STRUC { ++ // Word 0 ++ UINT32 TID:4; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 UDF:3; ++ UINT32 BSSID:3; ++ UINT32 KeyIndex:2; ++ UINT32 WirelessCliID:8; ++ // Word 1 ++ UINT32 PHYMODE:2; // 1: this RX frame is unicast to me ++ UINT32 rsv:3; ++ UINT32 STBC:2; ++ UINT32 ShortGI:1; ++ UINT32 BW:1; ++ UINT32 MCS:7; ++ UINT32 SEQUENCE:12; ++ UINT32 FRAG:4; ++ // Word 2 ++ UINT32 rsv1:8; ++ UINT32 RSSI2:8; ++ UINT32 RSSI1:8; ++ UINT32 RSSI0:8; ++ // Word 3 ++ UINT32 rsv2:16; ++ UINT32 SNR1:8; ++ UINT32 SNR0:8; ++} RXWI_STRUC, *PRXWI_STRUC; ++#else ++typedef struct PACKED _RXWI_STRUC { ++ // Word 0 ++ UINT32 WirelessCliID:8; ++ UINT32 KeyIndex:2; ++ UINT32 BSSID:3; ++ UINT32 UDF:3; ++ UINT32 MPDUtotalByteCount:12; ++ UINT32 TID:4; ++ // Word 1 ++ UINT32 FRAG:4; ++ UINT32 SEQUENCE:12; ++ UINT32 MCS:7; ++ UINT32 BW:1; ++ UINT32 ShortGI:1; ++ UINT32 STBC:2; ++ UINT32 rsv:3; ++ UINT32 PHYMODE:2; // 1: this RX frame is unicast to me ++ //Word2 ++ UINT32 RSSI0:8; ++ UINT32 RSSI1:8; ++ UINT32 RSSI2:8; ++ UINT32 rsv1:8; ++ //Word3 ++ UINT32 SNR0:8; ++ UINT32 SNR1:8; ++ UINT32 rsv2:16; ++} RXWI_STRUC, *PRXWI_STRUC; ++#endif ++ ++ ++// ================================================================================= ++// HOST-MCU communication data structure ++// ================================================================================= ++ ++// ++// H2M_MAILBOX_CSR: Host-to-MCU Mailbox ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _H2M_MAILBOX_STRUC { ++ struct { ++ UINT32 Owner:8; ++ UINT32 CmdToken:8; // 0xff tells MCU not to report CmdDoneInt after excuting the command ++ UINT32 HighByte:8; ++ UINT32 LowByte:8; ++ } field; ++ UINT32 word; ++} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; ++#else ++typedef union _H2M_MAILBOX_STRUC { ++ struct { ++ UINT32 LowByte:8; ++ UINT32 HighByte:8; ++ UINT32 CmdToken:8; ++ UINT32 Owner:8; ++ } field; ++ UINT32 word; ++} H2M_MAILBOX_STRUC, *PH2M_MAILBOX_STRUC; ++#endif ++ ++// ++// M2H_CMD_DONE_CSR: MCU-to-Host command complete indication ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _M2H_CMD_DONE_STRUC { ++ struct { ++ UINT32 CmdToken3; ++ UINT32 CmdToken2; ++ UINT32 CmdToken1; ++ UINT32 CmdToken0; ++ } field; ++ UINT32 word; ++} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; ++#else ++typedef union _M2H_CMD_DONE_STRUC { ++ struct { ++ UINT32 CmdToken0; ++ UINT32 CmdToken1; ++ UINT32 CmdToken2; ++ UINT32 CmdToken3; ++ } field; ++ UINT32 word; ++} M2H_CMD_DONE_STRUC, *PM2H_CMD_DONE_STRUC; ++#endif ++ ++ ++ ++// ++// MCU_LEDCS: MCU LED Control Setting. ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _MCU_LEDCS_STRUC { ++ struct { ++ UCHAR Polarity:1; ++ UCHAR LedMode:7; ++ } field; ++ UCHAR word; ++} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; ++#else ++typedef union _MCU_LEDCS_STRUC { ++ struct { ++ UCHAR LedMode:7; ++ UCHAR Polarity:1; ++ } field; ++ UCHAR word; ++} MCU_LEDCS_STRUC, *PMCU_LEDCS_STRUC; ++#endif ++// ================================================================================= ++// Register format ++// ================================================================================= ++ ++ ++ ++//NAV_TIME_CFG :NAV ++#ifdef RT_BIG_ENDIAN ++typedef union _NAV_TIME_CFG_STRUC { ++ struct { ++ USHORT rsv:6; ++ USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable ++ USHORT Eifs:9; // in unit of 1-us ++ UCHAR SlotTime; // in unit of 1-us ++ UCHAR Sifs; // in unit of 1-us ++ } field; ++ UINT32 word; ++} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; ++#else ++typedef union _NAV_TIME_CFG_STRUC { ++ struct { ++ UCHAR Sifs; // in unit of 1-us ++ UCHAR SlotTime; // in unit of 1-us ++ USHORT Eifs:9; // in unit of 1-us ++ USHORT ZeroSifs:1; // Applied zero SIFS timer after OFDM RX 0: disable ++ USHORT rsv:6; ++ } field; ++ UINT32 word; ++} NAV_TIME_CFG_STRUC, *PNAV_TIME_CFG_STRUC; ++#endif ++ ++ ++ ++ ++ ++// ++// RX_FILTR_CFG: /RX configuration register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union RX_FILTR_CFG_STRUC { ++ struct { ++ UINT32 :15; ++ UINT32 DropRsvCntlType:1; ++ ++ UINT32 DropBAR:1; // ++ UINT32 DropBA:1; // ++ UINT32 DropPsPoll:1; // Drop Ps-Poll ++ UINT32 DropRts:1; // Drop Ps-Poll ++ ++ UINT32 DropCts:1; // Drop Ps-Poll ++ UINT32 DropAck:1; // Drop Ps-Poll ++ UINT32 DropCFEnd:1; // Drop Ps-Poll ++ UINT32 DropCFEndAck:1; // Drop Ps-Poll ++ ++ UINT32 DropDuplicate:1; // Drop duplicate frame ++ UINT32 DropBcast:1; // Drop broadcast frames ++ UINT32 DropMcast:1; // Drop multicast frames ++ UINT32 DropVerErr:1; // Drop version error frame ++ ++ UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true ++ UINT32 DropNotToMe:1; // Drop not to me unicast frame ++ UINT32 DropPhyErr:1; // Drop physical error ++ UINT32 DropCRCErr:1; // Drop CRC error ++ } field; ++ UINT32 word; ++} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; ++#else ++typedef union _RX_FILTR_CFG_STRUC { ++ struct { ++ UINT32 DropCRCErr:1; // Drop CRC error ++ UINT32 DropPhyErr:1; // Drop physical error ++ UINT32 DropNotToMe:1; // Drop not to me unicast frame ++ UINT32 DropNotMyBSSID:1; // Drop fram ToDs bit is true ++ ++ UINT32 DropVerErr:1; // Drop version error frame ++ UINT32 DropMcast:1; // Drop multicast frames ++ UINT32 DropBcast:1; // Drop broadcast frames ++ UINT32 DropDuplicate:1; // Drop duplicate frame ++ ++ UINT32 DropCFEndAck:1; // Drop Ps-Poll ++ UINT32 DropCFEnd:1; // Drop Ps-Poll ++ UINT32 DropAck:1; // Drop Ps-Poll ++ UINT32 DropCts:1; // Drop Ps-Poll ++ ++ UINT32 DropRts:1; // Drop Ps-Poll ++ UINT32 DropPsPoll:1; // Drop Ps-Poll ++ UINT32 DropBA:1; // ++ UINT32 DropBAR:1; // ++ ++ UINT32 DropRsvCntlType:1; ++ UINT32 :15; ++ } field; ++ UINT32 word; ++} RX_FILTR_CFG_STRUC, *PRX_FILTR_CFG_STRUC; ++#endif ++ ++ ++ ++ ++// ++// PHY_CSR4: RF serial control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _PHY_CSR4_STRUC { ++ struct { ++ UINT32 Busy:1; // 1: ASIC is busy execute RF programming. ++ UINT32 PLL_LD:1; // RF PLL_LD status ++ UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program ++ UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) ++ UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. ++ } field; ++ UINT32 word; ++} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; ++#else ++typedef union _PHY_CSR4_STRUC { ++ struct { ++ UINT32 RFRegValue:24; // Register value (include register id) serial out to RF/IF chip. ++ UINT32 NumberOfBits:5; // Number of bits used in RFRegValue (I:20, RFMD:22) ++ UINT32 IFSelect:1; // 1: select IF to program, 0: select RF to program ++ UINT32 PLL_LD:1; // RF PLL_LD status ++ UINT32 Busy:1; // 1: ASIC is busy execute RF programming. ++ } field; ++ UINT32 word; ++} PHY_CSR4_STRUC, *PPHY_CSR4_STRUC; ++#endif ++ ++ ++// ++// SEC_CSR5: shared key table security mode register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _SEC_CSR5_STRUC { ++ struct { ++ UINT32 :1; ++ UINT32 Bss3Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key0CipherAlg:3; ++ } field; ++ UINT32 word; ++} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; ++#else ++typedef union _SEC_CSR5_STRUC { ++ struct { ++ UINT32 Bss2Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss2Key3CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key0CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key1CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key2CipherAlg:3; ++ UINT32 :1; ++ UINT32 Bss3Key3CipherAlg:3; ++ UINT32 :1; ++ } field; ++ UINT32 word; ++} SEC_CSR5_STRUC, *PSEC_CSR5_STRUC; ++#endif ++ ++ ++// ++// HOST_CMD_CSR: For HOST to interrupt embedded processor ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _HOST_CMD_CSR_STRUC { ++ struct { ++ UINT32 Rsv:24; ++ UINT32 HostCommand:8; ++ } field; ++ UINT32 word; ++} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; ++#else ++typedef union _HOST_CMD_CSR_STRUC { ++ struct { ++ UINT32 HostCommand:8; ++ UINT32 Rsv:24; ++ } field; ++ UINT32 word; ++} HOST_CMD_CSR_STRUC, *PHOST_CMD_CSR_STRUC; ++#endif ++ ++ ++// ++// AIFSN_CSR: AIFSN for each EDCA AC ++// ++ ++ ++ ++// ++// E2PROM_CSR: EEPROM control register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _E2PROM_CSR_STRUC { ++ struct { ++ UINT32 Rsvd:25; ++ UINT32 LoadStatus:1; // 1:loading, 0:done ++ UINT32 Type:1; // 1: 93C46, 0:93C66 ++ UINT32 EepromDO:1; ++ UINT32 EepromDI:1; ++ UINT32 EepromCS:1; ++ UINT32 EepromSK:1; ++ UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. ++ } field; ++ UINT32 word; ++} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; ++#else ++typedef union _E2PROM_CSR_STRUC { ++ struct { ++ UINT32 Reload:1; // Reload EEPROM content, write one to reload, self-cleared. ++ UINT32 EepromSK:1; ++ UINT32 EepromCS:1; ++ UINT32 EepromDI:1; ++ UINT32 EepromDO:1; ++ UINT32 Type:1; // 1: 93C46, 0:93C66 ++ UINT32 LoadStatus:1; // 1:loading, 0:done ++ UINT32 Rsvd:25; ++ } field; ++ UINT32 word; ++} E2PROM_CSR_STRUC, *PE2PROM_CSR_STRUC; ++#endif ++ ++ ++// ------------------------------------------------------------------- ++// E2PROM data layout ++// ------------------------------------------------------------------- ++ ++// ++// EEPROM antenna select format ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_ANTENNA_STRUC { ++ struct { ++ USHORT Rsv:4; ++ USHORT RfIcType:4; // see E2PROM document ++ USHORT TxPath:4; // 1: 1T, 2: 2T ++ USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R ++ } field; ++ USHORT word; ++} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; ++#else ++typedef union _EEPROM_ANTENNA_STRUC { ++ struct { ++ USHORT RxPath:4; // 1: 1R, 2: 2R, 3: 3R ++ USHORT TxPath:4; // 1: 1T, 2: 2T ++ USHORT RfIcType:4; // see E2PROM document ++ USHORT Rsv:4; ++ } field; ++ USHORT word; ++} EEPROM_ANTENNA_STRUC, *PEEPROM_ANTENNA_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_NIC_CINFIG2_STRUC { ++ struct { ++ USHORT DACTestBit:1; // control if driver should patch the DAC issue ++ USHORT Rsv2:3; // must be 0 ++ USHORT AntDiversity:1; // Antenna diversity ++ USHORT Rsv1:1; // must be 0 ++ USHORT BW40MAvailForA:1; // 0:enable, 1:disable ++ USHORT BW40MAvailForG:1; // 0:enable, 1:disable ++ USHORT EnableWPSPBC:1; // WPS PBC Control bit ++ USHORT BW40MSidebandForA:1; ++ USHORT BW40MSidebandForG:1; ++ USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable ++ USHORT ExternalLNAForA:1; // external LNA enable for 5G ++ USHORT ExternalLNAForG:1; // external LNA enable for 2.4G ++ USHORT DynamicTxAgcControl:1; // ++ USHORT HardwareRadioControl:1; // Whether RF is controlled by driver or HW. 1:enable hw control, 0:disable ++ } field; ++ USHORT word; ++} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; ++#else ++typedef union _EEPROM_NIC_CINFIG2_STRUC { ++ struct { ++ USHORT HardwareRadioControl:1; // 1:enable, 0:disable ++ USHORT DynamicTxAgcControl:1; // ++ USHORT ExternalLNAForG:1; // ++ USHORT ExternalLNAForA:1; // external LNA enable for 2.4G ++ USHORT CardbusAcceleration:1; // !!! NOTE: 0 - enable, 1 - disable ++ USHORT BW40MSidebandForG:1; ++ USHORT BW40MSidebandForA:1; ++ USHORT EnableWPSPBC:1; // WPS PBC Control bit ++ USHORT BW40MAvailForG:1; // 0:enable, 1:disable ++ USHORT BW40MAvailForA:1; // 0:enable, 1:disable ++ USHORT Rsv1:1; // must be 0 ++ USHORT AntDiversity:1; // Antenna diversity ++ USHORT Rsv2:3; // must be 0 ++ USHORT DACTestBit:1; // control if driver should patch the DAC issue ++ } field; ++ USHORT word; ++} EEPROM_NIC_CONFIG2_STRUC, *PEEPROM_NIC_CONFIG2_STRUC; ++#endif ++ ++// ++// TX_PWR Value valid range 0xFA(-6) ~ 0x24(36) ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_TX_PWR_STRUC { ++ struct { ++ CHAR Byte1; // High Byte ++ CHAR Byte0; // Low Byte ++ } field; ++ USHORT word; ++} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; ++#else ++typedef union _EEPROM_TX_PWR_STRUC { ++ struct { ++ CHAR Byte0; // Low Byte ++ CHAR Byte1; // High Byte ++ } field; ++ USHORT word; ++} EEPROM_TX_PWR_STRUC, *PEEPROM_TX_PWR_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_VERSION_STRUC { ++ struct { ++ UCHAR Version; // High Byte ++ UCHAR FaeReleaseNumber; // Low Byte ++ } field; ++ USHORT word; ++} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; ++#else ++typedef union _EEPROM_VERSION_STRUC { ++ struct { ++ UCHAR FaeReleaseNumber; // Low Byte ++ UCHAR Version; // High Byte ++ } field; ++ USHORT word; ++} EEPROM_VERSION_STRUC, *PEEPROM_VERSION_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_LED_STRUC { ++ struct { ++ USHORT Rsvd:3; // Reserved ++ USHORT LedMode:5; // Led mode. ++ USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. ++ USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. ++ USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. ++ USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. ++ USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. ++ USHORT PolarityACT:1; // Polarity ACT setting. ++ USHORT PolarityRDY_A:1; // Polarity RDY_A setting. ++ USHORT PolarityRDY_G:1; // Polarity RDY_G setting. ++ } field; ++ USHORT word; ++} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; ++#else ++typedef union _EEPROM_LED_STRUC { ++ struct { ++ USHORT PolarityRDY_G:1; // Polarity RDY_G setting. ++ USHORT PolarityRDY_A:1; // Polarity RDY_A setting. ++ USHORT PolarityACT:1; // Polarity ACT setting. ++ USHORT PolarityGPIO_0:1; // Polarity GPIO#0 setting. ++ USHORT PolarityGPIO_1:1; // Polarity GPIO#1 setting. ++ USHORT PolarityGPIO_2:1; // Polarity GPIO#2 setting. ++ USHORT PolarityGPIO_3:1; // Polarity GPIO#3 setting. ++ USHORT PolarityGPIO_4:1; // Polarity GPIO#4 setting. ++ USHORT LedMode:5; // Led mode. ++ USHORT Rsvd:3; // Reserved ++ } field; ++ USHORT word; ++} EEPROM_LED_STRUC, *PEEPROM_LED_STRUC; ++#endif ++ ++#ifdef RT_BIG_ENDIAN ++typedef union _EEPROM_TXPOWER_DELTA_STRUC { ++ struct { ++ UCHAR TxPowerEnable:1;// Enable ++ UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value ++ UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) ++ } field; ++ UCHAR value; ++} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; ++#else ++typedef union _EEPROM_TXPOWER_DELTA_STRUC { ++ struct { ++ UCHAR DeltaValue:6; // Tx Power dalta value (MAX=4) ++ UCHAR Type:1; // 1: plus the delta value, 0: minus the delta value ++ UCHAR TxPowerEnable:1;// Enable ++ } field; ++ UCHAR value; ++} EEPROM_TXPOWER_DELTA_STRUC, *PEEPROM_TXPOWER_DELTA_STRUC; ++#endif ++ ++// ++// QOS_CSR0: TXOP holder address0 register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _QOS_CSR0_STRUC { ++ struct { ++ UCHAR Byte3; // MAC address byte 3 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte0; // MAC address byte 0 ++ } field; ++ UINT32 word; ++} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; ++#else ++typedef union _QOS_CSR0_STRUC { ++ struct { ++ UCHAR Byte0; // MAC address byte 0 ++ UCHAR Byte1; // MAC address byte 1 ++ UCHAR Byte2; // MAC address byte 2 ++ UCHAR Byte3; // MAC address byte 3 ++ } field; ++ UINT32 word; ++} QOS_CSR0_STRUC, *PQOS_CSR0_STRUC; ++#endif ++ ++// ++// QOS_CSR1: TXOP holder address1 register ++// ++#ifdef RT_BIG_ENDIAN ++typedef union _QOS_CSR1_STRUC { ++ struct { ++ UCHAR Rsvd1; ++ UCHAR Rsvd0; ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Byte4; // MAC address byte 4 ++ } field; ++ UINT32 word; ++} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; ++#else ++typedef union _QOS_CSR1_STRUC { ++ struct { ++ UCHAR Byte4; // MAC address byte 4 ++ UCHAR Byte5; // MAC address byte 5 ++ UCHAR Rsvd0; ++ UCHAR Rsvd1; ++ } field; ++ UINT32 word; ++} QOS_CSR1_STRUC, *PQOS_CSR1_STRUC; ++#endif ++ ++#define RF_CSR_CFG 0x500 ++#ifdef RT_BIG_ENDIAN ++typedef union _RF_CSR_CFG_STRUC { ++ struct { ++ UINT Rsvd1:14; // Reserved ++ UINT RF_CSR_KICK:1; // kick RF register read/write ++ UINT RF_CSR_WR:1; // 0: read 1: write ++ UINT Rsvd2:3; // Reserved ++ UINT TESTCSR_RFACC_REGNUM:5; // RF register ID ++ UINT RF_CSR_DATA:8; // DATA ++ } field; ++ UINT word; ++} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; ++#else ++typedef union _RF_CSR_CFG_STRUC { ++ struct { ++ UINT RF_CSR_DATA:8; // DATA ++ UINT TESTCSR_RFACC_REGNUM:5; // RF register ID ++ UINT Rsvd2:3; // Reserved ++ UINT RF_CSR_WR:1; // 0: read 1: write ++ UINT RF_CSR_KICK:1; // kick RF register read/write ++ UINT Rsvd1:14; // Reserved ++ } field; ++ UINT word; ++} RF_CSR_CFG_STRUC, *PRF_CSR_CFG_STRUC; ++#endif ++ ++#endif // __RT28XX_H__ +--- /dev/null ++++ b/drivers/staging/rt3070/rt_ate.c +@@ -0,0 +1,6506 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++#ifdef UCOS ++INT IoctlResponse(PUCHAR payload, PUCHAR msg, INT len); ++#endif // UCOS // ++ ++#define ATE_BBP_REG_NUM 168 ++UCHAR restore_BBP[ATE_BBP_REG_NUM]={0}; ++ ++#ifdef RALINK_ATE ++UCHAR TemplateFrame[24] = {0x08/* Data type */,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xAA,0xBB,0x12,0x34,0x56,0x00,0x11,0x22,0xAA,0xBB,0xCC,0x00,0x00}; // 802.11 MAC Header, Type:Data, Length:24bytes ++extern RTMP_RF_REGS RF2850RegTable[]; ++extern UCHAR NUM_OF_2850_CHNL; ++ ++#ifdef RT2870 ++extern UCHAR EpToQueue[]; ++extern VOID RTUSBRejectPendingPackets( IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++#ifdef RT30xx ++//2008/07/10:KH adds to support 3070 ATE<-- ++extern FREQUENCY_ITEM FreqItems3020[]; ++extern UCHAR NUM_OF_3020_CHNL; ++//2008/07/10:KH adds to support 3070 ATE--> ++#endif // RT30xx // ++ ++#ifdef UCOS ++extern INT ConsoleResponse(IN PUCHAR buff); ++extern int (*remote_display)(char *); ++#endif // UCOS // ++ ++static CHAR CCKRateTable[] = {0, 1, 2, 3, 8, 9, 10, 11, -1}; /* CCK Mode. */ ++static CHAR OFDMRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; /* OFDM Mode. */ ++static CHAR HTMIXRateTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}; /* HT Mix Mode. */ ++ ++static INT TxDmaBusy( ++ IN PRTMP_ADAPTER pAd); ++ ++static INT RxDmaBusy( ++ IN PRTMP_ADAPTER pAd); ++ ++static VOID RtmpDmaEnable( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Enable); ++ ++static VOID BbpSoftReset( ++ IN PRTMP_ADAPTER pAd); ++ ++static VOID RtmpRfIoWrite( ++ IN PRTMP_ADAPTER pAd); ++ ++static INT ATESetUpFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TxIdx); ++ ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index); ++ ++static INT ATECmdHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++static int CheckMCSValid( ++ IN UCHAR Mode, ++ IN UCHAR Mcs); ++ ++ ++#ifdef RT2870 ++static VOID ATEWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst); ++ ++static VOID ATEWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR MIMOps, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING Transmit); ++ ++#endif // RT2870 // ++ ++static VOID SetJapanFilter( ++ IN PRTMP_ADAPTER pAd); ++ ++/*=========================end of prototype=========================*/ ++ ++ ++#ifdef RT2870 ++static INT TxDmaBusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT result; ++ USB_DMA_CFG_STRUC UsbCfg; ++ ++ RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA ++ if (UsbCfg.field.TxBusy) ++ result = 1; ++ else ++ result = 0; ++ ++ return result; ++} ++ ++static INT RxDmaBusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT result; ++ USB_DMA_CFG_STRUC UsbCfg; ++ ++ RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA ++ if (UsbCfg.field.RxBusy) ++ result = 1; ++ else ++ result = 0; ++ ++ return result; ++} ++ ++static VOID RtmpDmaEnable( ++ IN PRTMP_ADAPTER pAd, ++ IN INT Enable) ++{ ++ BOOLEAN value; ++ ULONG WaitCnt; ++ USB_DMA_CFG_STRUC UsbCfg; ++ ++ value = Enable > 0 ? 1 : 0; ++ ++ // check DMA is in busy mode. ++ WaitCnt = 0; ++ while (TxDmaBusy(pAd) || RxDmaBusy(pAd)) ++ { ++ RTMPusecDelay(10); ++ if (WaitCnt++ > 100) ++ break; ++ } ++ ++ //Why not to clear USB DMA TX path first ??? ++ RTMP_IO_READ32(pAd, USB_DMA_CFG, &UsbCfg.word); // disable DMA ++ UsbCfg.field.TxBulkEn = value; ++ UsbCfg.field.RxBulkEn = value; ++ RTMP_IO_WRITE32(pAd, USB_DMA_CFG, UsbCfg.word); // abort all TX rings ++ RTMPusecDelay(5000); ++ ++ return; ++} ++#endif // RT2870 // ++ ++static VOID BbpSoftReset( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BbpData = 0; ++ ++ // Soft reset, set BBP R21 bit0=1->0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); ++ BbpData |= 0x00000001; //set bit0=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R21, &BbpData); ++ BbpData &= ~(0x00000001); //set bit0=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R21, BbpData); ++ ++ return; ++} ++ ++static VOID RtmpRfIoWrite( ++ IN PRTMP_ADAPTER pAd) ++{ ++ // Set RF value 1's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 2's set R3[bit2] = [1] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 | 0x04)); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ RTMPusecDelay(200); ++ ++ // Set RF value 3's set R3[bit2] = [0] ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAd, (pAd->LatchRfRegs.R3 & (~0x04))); ++ RTMP_RF_IO_WRITE32(pAd, pAd->LatchRfRegs.R4); ++ ++ return; ++} ++ ++static int CheckMCSValid( ++ UCHAR Mode, ++ UCHAR Mcs) ++{ ++ int i; ++ PCHAR pRateTab; ++ ++ switch(Mode) ++ { ++ case 0: ++ pRateTab = CCKRateTable; ++ break; ++ case 1: ++ pRateTab = OFDMRateTable; ++ break; ++ case 2: ++ case 3: ++ pRateTab = HTMIXRateTable; ++ break; ++ default: ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("unrecognizable Tx Mode %d\n", Mode)); ++ return -1; ++ break; ++ } ++ ++ i = 0; ++ while(pRateTab[i] != -1) ++ { ++ if (pRateTab[i] == Mcs) ++ return 0; ++ i++; ++ } ++ ++ return -1; ++} ++ ++#if 1 ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index) ++{ ++ ULONG R; ++ CHAR TxPower; ++ UCHAR Bbp94 = 0; ++ BOOLEAN bPowerReduce = FALSE; ++#ifdef RT30xx ++ UCHAR RFValue; ++#endif // RT30xx // ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power ++ ** are not synchronized. ++ */ ++/* ++ pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; ++ pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; ++*/ ++ return 0; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (TxPower > 31) ++ { ++ // ++ // R3, R4 can't large than 31 (0x24), 31 ~ 36 used by BBP 94 ++ // ++ R = 31; ++ if (TxPower <= 36) ++ Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 ++ // ++ R = 0; ++ if (TxPower >= -6) ++ Bbp94 = BBPR94_DEFAULT + TxPower; ++ } ++ else ++ { ++ // 0 ~ 31 ++ R = (ULONG) TxPower; ++ Bbp94 = BBPR94_DEFAULT; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ } ++ else// 5.5 GHz ++ { ++ if (TxPower > 15) ++ { ++ // ++ // R3, R4 can't large than 15 (0x0F) ++ // ++ R = 15; ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0 ++ // ++ // -1 ~ -7 ++ ASSERT((TxPower >= -7)); ++ R = (ULONG)(TxPower + 7); ++ bPowerReduce = TRUE; ++ } ++ else ++ { ++ // 0 ~ 15 ++ R = (ULONG) TxPower; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R)); ++ } ++//2008/09/10:KH adds to support 3070 ATE TX Power tunning real time<-- ++#ifdef RT30xx ++ if(IS_RT30xx(pAd)) ++ { ++ // Set Tx Power ++ ++ RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); ++ RFValue = (RFValue & 0xE0) | TxPower; ++ RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("3070 or 2070:%s (TxPower=%d, RFValue=%x)\n", __FUNCTION__, TxPower, RFValue)); ++ ++ } ++ else ++#endif // RT30xx // ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ if (index == 0) ++ { ++ R = R << 9; // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = R << 6; // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else// 5.5GHz ++ { ++ if (bPowerReduce == FALSE) ++ { ++ if (index == 0) ++ { ++ R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else ++ { ++ if (index == 0) ++ { ++ R = (R << 10); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ ++ /* Clear bit 9 of R3 to reduce 7dB. */ ++ pAd->LatchRfRegs.R3 = (R & (~(1 << 9))); ++ } ++ else ++ { ++ R = (R << 7); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ ++ /* Clear bit 6 of R4 to reduce 7dB. */ ++ pAd->LatchRfRegs.R4 = (R & (~(1 << 6))); ++ } ++ } ++ } ++ RtmpRfIoWrite(pAd); ++ } ++//2008/09/10:KH adds to support 3070 ATE TX Power tunning real time--> ++ ++ return 0; ++ } ++} ++#else// 1 // ++static INT ATETxPwrHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN char index) ++{ ++ ULONG R; ++ CHAR TxPower; ++ UCHAR Bbp94 = 0; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ // TODO: how to get current TxPower0/1 from pAd->LatchRfRegs ? ++ /* When QA is used for Tx, pAd->ate.TxPower0/1 and real tx power ++ ** are not synchronized. ++ */ ++/* ++ pAd->ate.TxPower0 = pAd->LatchRfRegs.xxx; ++ pAd->ate.TxPower1 = pAd->LatchRfRegs.xxx; ++*/ ++ return 0; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ TxPower = index == 0 ? pAd->ate.TxPower0 : pAd->ate.TxPower1; ++ ++ if (TxPower > 31) ++ { ++ // ++ // R3, R4 can't large than 36 (0x24), 31 ~ 36 used by BBP 94 ++ // ++ R = 31; ++ if (TxPower <= 36) ++ Bbp94 = BBPR94_DEFAULT + (UCHAR)(TxPower - 31); ++ } ++ else if (TxPower < 0) ++ { ++ // ++ // R3, R4 can't less than 0, -1 ~ -6 used by BBP 94 ++ // ++ R = 0; ++ if (TxPower >= -6) ++ Bbp94 = BBPR94_DEFAULT + TxPower; ++ } ++ else ++ { ++ // 0 ~ 31 ++ R = (ULONG) TxPower; ++ Bbp94 = BBPR94_DEFAULT; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if (index == 0) ++ { ++ R = R << 9; // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = R << 6; // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ else ++ { ++ if (index == 0) ++ { ++ R = (R << 10) | (1 << 9); // shift TX power control to correct RF(R3) register bit position ++ R |= (pAd->LatchRfRegs.R3 & 0xffffc1ff); ++ pAd->LatchRfRegs.R3 = R; ++ } ++ else ++ { ++ R = (R << 7) | (1 << 6); // shift TX power control to correct RF(R4) register bit position ++ R |= (pAd->LatchRfRegs.R4 & 0xfffff83f); ++ pAd->LatchRfRegs.R4 = R; ++ } ++ } ++ ++ RtmpRfIoWrite(pAd); ++ ++ return 0; ++ } ++} ++#endif // 1 // ++/* ++ ========================================================================== ++ Description: ++ Set ATE operation mode to ++ 0. ATESTART = Start ATE Mode ++ 1. ATESTOP = Stop ATE Mode ++ 2. TXCONT = Continuous Transmit ++ 3. TXCARR = Transmit Carrier ++ 4. TXFRAME = Transmit Frames ++ 5. RXFRAME = Receive Frames ++#ifdef RALINK_28xx_QA ++ 6. TXSTOP = Stop Any Type of Transmition ++ 7. RXSTOP = Stop Receiving Frames ++#endif // RALINK_28xx_QA // ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++/* */ ++/* */ ++/*=======================End of RT2860=======================*/ ++ ++ ++/*======================Start of RT2870======================*/ ++/* */ ++/* */ ++ ++#ifdef RT2870 ++static INT ATECmdHandler( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UINT32 Value; ++ UCHAR BbpData; ++ UINT32 MacData; ++ UINT i=0, atemode; ++ //NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ++ //PUCHAR pDest; ++ UINT32 temp; ++ ULONG IrqFlags; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> ATECmdHandler()\n")); ++ ATEAsicSwitchChannel(pAd); ++ /* AsicLockChannel() is empty function so far in fact */ ++ AsicLockChannel(pAd, pAd->ate.Channel); ++ ++ RTMPusecDelay(5000); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ /* Enter ATE mode and set Tx/Rx Idle */ ++ if (!strcmp(arg, "ATESTART")) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN Cancelled; ++#endif // CONFIG_STA_SUPPORT // ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: ATESTART\n")); ++ ++ netif_stop_queue(pAd->net_dev); ++ ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode = ATE_START; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable auto responder ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); ++ temp = temp & 0xFFFFFFFE; ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); ++ ++ // read MAC_SYS_CTRL and backup MAC_SYS_CTRL value. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ // clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ // Stop continuous TX production test. ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData);//disable or cancel pending irp first ??? ++ ++ if (atemode & ATE_TXCARR ++#ifdef RT30xx ++ || atemode & ATE_TXCONT ++#endif // RT30xx // ++) ++ { ++#ifdef RT30xx ++ //Hardware Reset BBP ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &temp); ++ temp = temp |0x00000002; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, temp); ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &temp); ++ temp = temp & ~(0x00000002); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, temp); ++ //Restore All BBP Value ++ for(i=0;iMlmeAux.AssocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); ++#endif // CONFIG_STA_SUPPORT // ++ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); /* not used in RT28xx */ ++ RTUSBCleanUpMLMEBulkOutQueue(pAd); ++ ++ // Sometimes kernel will hang on, so we avoid calling MlmeSuspend(). ++// MlmeSuspend(pAd, TRUE); ++ //RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Make sure there are no pending bulk in/out IRPs before we go on. ++/*=========================================================================*/ ++ /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ ++// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ while ((pAd->PendingRx > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++ NdisInterlockedDecrement(&pAd->PendingRx); ++#endif ++ /* delay 0.5 seconds */ ++ RTMPusecDelay(500000); ++ pAd->PendingRx = 0; ++ } ++ /* peter : why don't we have to get BulkOutLock first ? */ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ /* pAd->BulkOutPending[y] will be set to FALSE in RTUSBCancelPendingBulkOutIRP(pAd) */ ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ /* we have enough time delay in RTUSBCancelPendingBulkOutIRP(pAd) ++ ** so this is not necessary ++ */ ++// RTMPusecDelay(500000); ++ } ++ ++ /* pAd->PendingRx is not of type atomic_t anymore in 28xx */ ++// ASSERT(atomic_read(&pAd->PendingRx) == 0); ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++ ++ // reset Rx statistics. ++ pAd->ate.LastSNR0 = 0; ++ pAd->ate.LastSNR1 = 0; ++ pAd->ate.LastRssi0 = 0; ++ pAd->ate.LastRssi1 = 0; ++ pAd->ate.LastRssi2 = 0; ++ pAd->ate.AvgRssi0 = 0; ++ pAd->ate.AvgRssi1 = 0; ++ pAd->ate.AvgRssi2 = 0; ++ pAd->ate.AvgRssi0X8 = 0; ++ pAd->ate.AvgRssi1X8 = 0; ++ pAd->ate.AvgRssi2X8 = 0; ++ pAd->ate.NumOfAvgRssiSample = 0; ++ ++#ifdef RALINK_28xx_QA ++ // Tx frame ++ pAd->ate.bQATxStart = FALSE; ++ pAd->ate.bQARxStart = FALSE; ++ pAd->ate.seq = 0; ++ ++ // counters ++ pAd->ate.U2M = 0; ++ pAd->ate.OtherData = 0; ++ pAd->ate.Beacon = 0; ++ pAd->ate.OtherCount = 0; ++ pAd->ate.TxAc0 = 0; ++ pAd->ate.TxAc1 = 0; ++ pAd->ate.TxAc2 = 0; ++ pAd->ate.TxAc3 = 0; ++ pAd->ate.TxHCCA = 0; ++ pAd->ate.TxMgmt = 0; ++ pAd->ate.RSSI0 = 0; ++ pAd->ate.RSSI1 = 0; ++ pAd->ate.RSSI2 = 0; ++ pAd->ate.SNR0 = 0; ++ pAd->ate.SNR1 = 0; ++ ++ // control ++ pAd->ate.TxDoneCount = 0; ++ pAd->ate.TxStatus = 0; // task Tx status // 0 --> task is idle, 1 --> task is running ++#endif // RALINK_28xx_QA // ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AsicDisableSync(pAd); ++ ++ /* ++ ** If we skip "LinkDown()", we should disable protection ++ ** to prevent from sending out RTS or CTS-to-self. ++ */ ++ ATEDisableAsicProtect(pAd); ++ RTMPStationStop(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ //Clean ATE Bulk in/out counter and continue setup ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ ++ /* NdisAcquireSpinLock()/NdisReleaseSpinLock() need only one argument in RT28xx */ ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = FALSE; ++ pAd->ContinBulkIn = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ } ++ else if (!strcmp(arg, "ATESTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE : ATESTOP ===>\n")); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData);//0820 ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); // recover the MAC_SYS_CTRL register back. ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ /* ++ ** Abort Tx, RX DMA. ++ ** Q : How to do the following I/O if Tx, Rx DMA is aborted ? ++ ** Ans : Bulk endpoints are aborted, while the control endpoint is not. ++ */ ++ RtmpDmaEnable(pAd, 0); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ /* Make sure there are no pending bulk in/out IRPs before we go on. */ ++/*=========================================================================*/ ++// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ while (pAd->PendingRx > 0) ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++// NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++#endif ++ RTMPusecDelay(500000); ++ } ++ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ RTMPusecDelay(500000); ++ } ++ ++// ASSERT(atomic_read(&pAd->PendingRx) == 0); ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++/* Reset Rx RING */ ++/*=========================================================================*/ ++// InterlockedExchange(&pAd->PendingRx, 0); ++ pAd->PendingRx = 0; ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer ++ pAd->NextRxBulkInPosition = 0; ++ for (i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ NdisZeroMemory(pRxContext->TransferBuffer, MAX_RXBULK_SIZE); ++ /* peter : why don't we have to get BulkInLock first ? */ ++ pRxContext->pAd = pAd; ++ pRxContext->pIrp = NULL; ++ /* peter debug ++ */ ++ pRxContext->BulkInOffset = 0; ++ pRxContext->bRxHandling = FALSE; ++ /* peter debug -- */ ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++// pRxContext->ReorderInUse = FALSE; ++// pRxContext->ReadPosOffset = 0; ++ } ++ ++/*=========================================================================*/ ++/* Reset Tx RING */ ++/*=========================================================================*/ ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++/*=========================================================================*/ ++ // Enable auto responder. ++ RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &temp); ++ temp = temp | (0x01); ++ RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, temp); ++ ++/*================================================*/ ++ AsicEnableBssSync(pAd); ++ ++ /* Soft reset BBP.*/ ++ /* In 2870 chipset, ATE_BBP_IO_READ8_BY_REG_ID() == RTMP_BBP_IO_READ8_BY_REG_ID() */ ++ /* Both rt2870ap and rt2870sta use BbpSoftReset(pAd) to do BBP soft reset */ ++ BbpSoftReset(pAd); ++/*================================================*/ ++ { ++#ifdef CONFIG_STA_SUPPORT ++ // Set all state machines back IDLE ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ pAd->Mlme.ActMachine.CurrState = ACT_IDLE; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // ++ // ===> refer to MlmeRestartStateMachine(). ++ // When we entered ATE_START mode, PeriodicTimer was not cancelled. ++ // So we don't have to set it here. ++ // ++ //RTMPSetTimer(pAd, &pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); ++ ++ ASSERT(pAd->CommonCfg.Channel != 0); ++ ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ RTMPStationStart(pAd); ++#endif // CONFIG_STA_SUPPORT // ++ } ++// ++// These two steps have been done when entering ATE_STOP mode. ++// ++ // Clean ATE Bulk in/out counter and continue setup. ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = FALSE; ++ pAd->ContinBulkIn = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ /* Wait 50ms to prevent next URB to bulkout during HW reset. */ ++ /* todo : remove this if not necessary */ ++ NdisMSleep(50000); ++ ++ pAd->ate.Mode = ATE_STOP; ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++/*=========================================================================*/ ++ /* restore RX_FILTR_CFG */ ++#ifdef CONFIG_STA_SUPPORT ++ /* restore RX_FILTR_CFG in order that QA maybe set it to 0x3 */ ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); ++#endif // CONFIG_STA_SUPPORT // ++/*=========================================================================*/ ++ ++ // Enable Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Wait 10ms to wait all of the bulk-in URBs to complete. ++ /* todo : remove this if not necessary */ ++ NdisMSleep(10000); ++ ++ // Everything is ready to start normal Tx/Rx. ++ RTUSBBulkReceive(pAd); ++ netif_start_queue(pAd->net_dev); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATE : ATESTOP \n")); ++ } ++ else if (!strcmp(arg, "TXCARR")) // Tx Carrier ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCARR\n")); ++ pAd->ate.Mode |= ATE_TXCARR; ++ ++#ifdef RT30xx ++ for(i=0;iate.bQATxStart == FALSE) ++ { ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Carrier Test set BBP R22 bit7=1, bit6=1, bit[5~0]=0x01 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ BbpData |= 0x000000C1; //set bit7=1, bit6=1, bit[5~0]=0x01 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1 ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value = Value | 0x00000010; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ } ++ else if (!strcmp(arg, "TXCONT")) // Tx Continue ++ { ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ /* set MAC_SYS_CTRL(0x1004) bit4(Continuous Tx Production Test) ++ and bit2(MAC TX enable) back to zero. */ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData &= 0xFFFFFFEB; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ // set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF7F; //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ ++ /* for TxCont mode. ++ ** Step 1: Send 50 packets first then wait for a moment. ++ ** Step 2: Send more 50 packet then start continue mode. ++ */ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXCONT\n")); ++ ++#ifdef RT30xx ++ for(i=0;iate.Mode |= ATE_TXCONT; ++ pAd->ate.TxCount = 50; ++ pAd->ate.TxDoneCount = 0; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ ++ /* Only needed if we have to send some normal frames. */ ++ SetJapanFilter(pAd); ++ ++ // Setup frame format. ++ ATESetUpFrame(pAd, 0); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#endif // RALINK_28xx_QA // ++ ++ NdisAcquireSpinLock(&pAd->GenericLock);//0820 ++ pAd->ContinBulkOut = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ ++ /* To make sure all the 50 frames have been bulk out before executing step 2 */ ++ while (atomic_read(&pAd->BulkOutRemained) > 0) ++ { ++ RTMPusecDelay(5000); ++ } ++ ++ // Step 2: send more 50 packets then start continue mode. ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Cont. TX set BBP R22 bit7=1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData |= 0x00000080; //set bit7=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ pAd->ate.TxCount = 50; ++ pAd->ate.TxDoneCount = 0; ++ ++ SetJapanFilter(pAd); ++ ++ // Setup frame format. ++ ATESetUpFrame(pAd, 0); ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#endif // RALINK_28xx_QA // ++ ++ NdisAcquireSpinLock(&pAd->GenericLock);//0820 ++ pAd->ContinBulkOut = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ ++#if 1 ++ RTMPusecDelay(500); ++#else ++ while (atomic_read(&pAd->BulkOutRemained) > 0) ++ { ++ RTMPusecDelay(5000); ++ } ++#endif // 1 // ++ ++ // Set MAC_SYS_CTRL(0x1004) Continuous Tx Production Test (bit4) = 1. ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData |= 0x00000010; ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ } ++ else if (!strcmp(arg, "TXFRAME")) // Tx Frames ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXFRAME(Count=0x%08x)\n", pAd->ate.TxCount)); ++ pAd->ate.Mode |= ATE_TXFRAME; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++#ifdef RALINK_28xx_QA ++ // add this for LoopBack mode ++ if (pAd->ate.bQARxStart == FALSE) ++ { ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ } ++ ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pAd->ate.TxStatus = 1; ++ //pAd->ate.Repeat = 0; ++ } ++#else ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++#endif // RALINK_28xx_QA // ++ ++ // Enable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ SetJapanFilter(pAd); ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ pAd->ate.TxDoneCount = 0; ++ ++ // Setup frame format ++ ATESetUpFrame(pAd, 0); ++ ++ // Start Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Check count is continuous or not yet. ++ // ++ // Due to the type mismatch between "pAd->BulkOutRemained"(atomic_t) and "pAd->ate.TxCount"(UINT32) ++ // ++ if (pAd->ate.TxCount == 0) ++ { ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ } ++ else ++ { ++ InterlockedExchange(&pAd->BulkOutRemained, pAd->ate.TxCount); ++ } ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("bulk out count = %d\n", atomic_read(&pAd->BulkOutRemained))); ++ ASSERT((atomic_read(&pAd->BulkOutRemained) >= 0)); ++ ++ if (atomic_read(&pAd->BulkOutRemained) == 0) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packet countinuously\n")); ++ ++ /* In 28xx, NdisAcquireSpinLock() == spin_lock_bh() */ ++ /* NdisAcquireSpinLock only need one argument in 28xx. */ ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = TRUE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ /* In 28xx, BULK_OUT_LOCK() == spin_lock_irqsave() */ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK ++ pAd->BulkOutPending[0] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags);// peter : NdisAcquireSpinLock ==> BULK_OUT_LOCK ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Send packets depend on counter\n")); ++ ++ NdisAcquireSpinLock(&pAd->GenericLock); ++ pAd->ContinBulkOut = FALSE; ++ NdisReleaseSpinLock(&pAd->GenericLock); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[0], IrqFlags); ++ pAd->BulkOutPending[0] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[0], IrqFlags); ++ } ++ ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ ++ // Kick bulk out ++ RTUSBKickBulkOut(pAd); ++ } ++#ifdef RALINK_28xx_QA ++ else if (!strcmp(arg, "TXSTOP")) //Enter ATE mode and set Tx/Rx Idle ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: TXSTOP\n")); ++ ++ atemode = pAd->ate.Mode; ++ pAd->ate.Mode &= ATE_TXSTOP; ++ pAd->ate.bQATxStart = FALSE; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ ++/*=========================================================================*/ ++ if (atemode & ATE_TXCARR) ++ { ++ // No Carrier Test set BBP R22 bit7=0, bit6=0, bit[5~0]=0x0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= 0xFFFFFF00; //clear bit7, bit6, bit[5~0] ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ else if (atemode & ATE_TXCARRSUPP) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ ++ // No Carrier Suppression set BBP R24 bit0=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R24, &BbpData); ++ BbpData &= 0xFFFFFFFE; //clear bit0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R24, BbpData); ++ } ++ else if ((atemode & ATE_TXFRAME) || (atemode == ATE_STOP)) ++ { ++ if (atemode & ATE_TXCONT) ++ { ++ // No Cont. TX set BBP R22 bit7=0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R22, &BbpData); ++ BbpData &= ~(1 << 7); //set bit7=0 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ } ++ } ++ ++/*=========================================================================*/ ++ RTUSBRejectPendingPackets(pAd); ++ RTUSBCleanUpDataBulkOutQueue(pAd); ++ ++ /* not used in RT28xx */ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); ++ /* empty function so far */ ++ RTUSBCleanUpMLMEBulkOutQueue(pAd); ++/*=========================================================================*/ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++/*=========================================================================*/ ++ ++ /* In 28xx, pAd->PendingRx is not of type atomic_t anymore */ ++// while ((atomic_read(&pAd->PendingRx) > 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ /* peter todo : BulkInLock */ ++ while (pAd->PendingRx > 0) ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++// NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++#endif ++ RTMPusecDelay(500000); ++ } ++ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ RTMPusecDelay(500000); ++ } ++ ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++ // Enable Tx, Rx DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ /* task Tx status : 0 --> task is idle, 1 --> task is running */ ++ pAd->ate.TxStatus = 0; ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ ++ // Disable Tx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ MacData &= (0xfffffffb); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ //Clean ATE Bulk in/out counter and continue setup ++ InterlockedExchange(&pAd->BulkOutRemained, 0); ++ ++ pAd->ContinBulkOut = FALSE; ++ } ++ else if (!strcmp(arg, "RXSTOP")) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXSTOP\n")); ++ atemode = pAd->ate.Mode; ++ ++ // Disable Rx ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ pAd->ate.Mode &= ATE_RXSTOP; ++ pAd->ate.bQARxStart = FALSE; ++// pAd->ate.TxDoneCount = pAd->ate.TxCount; ++ ++/*=========================================================================*/ ++ RTUSBRejectPendingPackets(pAd); ++ RTUSBCleanUpDataBulkOutQueue(pAd); ++ ++ /* not used in RT28xx */ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); ++ RTUSBCleanUpMLMEBulkOutQueue(pAd); ++/*=========================================================================*/ ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++/*=========================================================================*/ ++// while ((atomic_read(&pAd->PendingRx) > 0)) ++ while (pAd->PendingRx > 0) ++ { ++#if 1 ++ ATE_RTUSBCancelPendingBulkInIRP(pAd); ++#else ++// NdisInterlockedDecrement(&pAd->PendingRx); ++ pAd->PendingRx--; ++#endif ++ RTMPusecDelay(500000); ++ } ++ ++ while (((pAd->BulkOutPending[0] == TRUE) || ++ (pAd->BulkOutPending[1] == TRUE) || ++ (pAd->BulkOutPending[2] == TRUE) || ++ (pAd->BulkOutPending[3] == TRUE)) && (pAd->BulkFlags != 0)) //pAd->BulkFlags != 0 wait bulk out finish ++ { ++ do ++ { ++ RTUSBCancelPendingBulkOutIRP(pAd); ++ } while (FALSE); ++ ++ RTMPusecDelay(500000); ++ } ++ ++ ASSERT(pAd->PendingRx == 0); ++/*=========================================================================*/ ++ ++ // Soft reset BBP. ++ BbpSoftReset(pAd); ++ pAd->ContinBulkIn = FALSE; ++ } ++#endif // RALINK_28xx_QA // ++ else if (!strcmp(arg, "RXFRAME")) // Rx Frames ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: RXFRAME\n")); ++ ++ // Disable Rx of MAC block ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Default value in BBP R22 is 0x0. ++ BbpData = 0; ++ ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &MacData); ++ // Clean bit4 to stop continuous Tx production test. ++ MacData &= 0xFFFFFFEF; ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R22, BbpData); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, MacData); ++ ++ pAd->ate.Mode |= ATE_RXFRAME; ++ ++ // Abort Tx, RX DMA. ++ RtmpDmaEnable(pAd, 0); ++ ++ // Disable TX of MAC block ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value &= ~(1 << 2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Reset Rx RING. ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ PRX_CONTEXT pRxContext = &(pAd->RxContext[i]); ++ ++ pRxContext->InUse = FALSE; ++ pRxContext->IRPPending = FALSE; ++ pRxContext->Readable = FALSE; ++ ++ // ++ // Get the urb from kernel back to driver. ++ // ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ ++ /* Sleep 200 microsecs to give cancellation time to work. */ ++ NdisMSleep(200); ++ pAd->BulkInReq = 0; ++ ++// InterlockedExchange(&pAd->PendingRx, 0); ++ pAd->PendingRx = 0; ++ pAd->NextRxBulkInReadIndex = 0; // Next Rx Read index ++ pAd->NextRxBulkInIndex = RX_RING_SIZE - 1; // Rx Bulk pointer ++ pAd->NextRxBulkInPosition = 0; ++ } ++ ++ // read to clear counters ++ RTUSBReadMACRegister(pAd, RX_STA_CNT0, &temp); //RX PHY & RX CRC count ++ RTUSBReadMACRegister(pAd, RX_STA_CNT1, &temp); //RX PLCP error count & CCA false alarm count ++ RTUSBReadMACRegister(pAd, RX_STA_CNT2, &temp); //RX FIFO overflow frame count & RX duplicated filtered frame count ++ ++ pAd->ContinBulkIn = TRUE; ++ ++ // Enable Tx, RX DMA. ++ RtmpDmaEnable(pAd, 1); ++ ++ // Enable RX of MAC block ++ RTMP_IO_READ32(pAd, MAC_SYS_CTRL, &Value); ++ Value |= (1 << 3); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, Value); ++ ++ // Kick bulk in ++ RTUSBBulkReceive(pAd); ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATE: Invalid arg!\n")); ++ return FALSE; ++ } ++ RTMPusecDelay(5000); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== ATECmdHandler()\n")); ++ ++ return TRUE; ++} ++#endif // RT2870 // ++ ++INT Set_ATE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (ATECmdHandler(pAd, arg)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Success\n")); ++ ++ ++ return TRUE; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_Proc Failed\n")); ++ return FALSE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR1=DA for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR3=DA for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_DA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr3[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_DA_Proc (DA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr3[0], ++ pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_DA_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR3=SA for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR2=SA for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_SA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr2[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_SA_Proc (SA = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr2[0], ++ pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_SA_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE ADDR2=BSSID for TxFrame(AP : To DS = 0 ; From DS = 1) ++ or ++ Set ATE ADDR1=BSSID for TxFrame(STA : To DS = 1 ; From DS = 0) ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_BSSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *value; ++ INT i; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg, ":"); value; value = rstrtok(NULL, ":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ AtoH(value, &pAd->ate.Addr1[i++], 1); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ if(i != 6) ++ return FALSE; //Invalid ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_BSSID_Proc (BSSID = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAd->ate.Addr1[0], ++ pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5])); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_BSSID_Proc Success\n")); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Channel ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_CHANNEL_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR channel; ++ ++ channel = simple_strtol(arg, 0, 10); ++ ++ if ((channel < 1) || (channel > 216))// to allow A band channel : ((channel < 1) || (channel > 14)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_CHANNEL_Proc::Out of range, it should be in range of 1~14.\n")); ++ return FALSE; ++ } ++ pAd->ate.Channel = channel; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_CHANNEL_Proc (ATE Channel = %d)\n", pAd->ate.Channel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_CHANNEL_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Power0 ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_POWER0_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR TxPower; ++ ++ TxPower = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if ((TxPower > 31) || (TxPower < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ else// 5.5GHz ++ { ++ if ((TxPower > 15) || (TxPower < -7)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER0_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ ++ pAd->ate.TxPower0 = TxPower; ++ ATETxPwrHandler(pAd, 0); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER0_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Power1 ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_POWER1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR TxPower; ++ ++ TxPower = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.Channel <= 14) ++ { ++ if ((TxPower > 31) || (TxPower < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ else ++ { ++ if ((TxPower > 15) || (TxPower < -7)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_POWER1_Proc::Out of range (Value=%d)\n", TxPower)); ++ return FALSE; ++ } ++ } ++ ++ pAd->ate.TxPower1 = TxPower; ++ ATETxPwrHandler(pAd, 1); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_POWER1_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx Antenna ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR value; ++ ++ value = simple_strtol(arg, 0, 10); ++ ++ if ((value > 2) || (value < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_Antenna_Proc::Out of range (Value=%d)\n", value)); ++ return FALSE; ++ } ++ ++ pAd->ate.TxAntennaSel = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_Antenna_Proc (Antenna = %d)\n", pAd->ate.TxAntennaSel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Ralink: Set_ATE_TX_Antenna_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Rx Antenna ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_RX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR value; ++ ++ value = simple_strtol(arg, 0, 10); ++ ++ if ((value > 3) || (value < 0)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_RX_Antenna_Proc::Out of range (Value=%d)\n", value)); ++ return FALSE; ++ } ++ ++ pAd->ate.RxAntennaSel = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_Antenna_Proc (Antenna = %d)\n", pAd->ate.RxAntennaSel)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_Antenna_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE RF frequence offset ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_FREQOFFSET_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR RFFreqOffset; ++ ULONG R4; ++ ++ RFFreqOffset = simple_strtol(arg, 0, 10); ++#ifndef RT30xx ++ if(RFFreqOffset >= 64) ++#endif // RT30xx // ++#ifdef RT30xx ++//2008/08/06: KH modified the limit of offset value from 65 to 95(0x5F) ++ if(RFFreqOffset >= 95) ++#endif // RT30xx // ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_FREQOFFSET_Proc::Out of range, it should be in range of 0~63.\n")); ++ return FALSE; ++ } ++ ++ pAd->ate.RFFreqOffset = RFFreqOffset; ++#ifdef RT30xx ++ if(IS_RT30xx(pAd)) ++ { ++ // Set RF offset ++ UCHAR RFValue; ++ RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); ++ //2008/08/06: KH modified "pAd->RFFreqOffset" to "pAd->ate.RFFreqOffset" ++ RFValue = (RFValue & 0x80) | pAd->ate.RFFreqOffset; ++ RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); ++ } ++ else ++#endif // RT30xx // ++ { ++ ++ R4 = pAd->ate.RFFreqOffset << 15; // shift TX power control to correct RF register bit position ++ R4 |= (pAd->LatchRfRegs.R4 & ((~0x001f8000))); ++ pAd->LatchRfRegs.R4 = R4; ++ ++ RtmpRfIoWrite(pAd); ++ } ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_FREQOFFSET_Proc (RFFreqOffset = %d)\n", pAd->ate.RFFreqOffset)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_FREQOFFSET_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE RF BW ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_BW_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ int i; ++ UCHAR value = 0; ++ UCHAR BBPCurrentBW; ++ ++ BBPCurrentBW = simple_strtol(arg, 0, 10); ++ ++ if(BBPCurrentBW == 0) ++ pAd->ate.TxWI.BW = BW_20; ++ else ++ pAd->ate.TxWI.BW = BW_40; ++ ++ if(pAd->ate.TxWI.BW == BW_20) ++ { ++ if(pAd->ate.Channel <= 14) ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx20MPwrCfgGBand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgGBand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ else ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx20MPwrCfgABand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx20MPwrCfgABand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ ++ //Set BBP R4 bit[4:3]=0:0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value &= (~0x18); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ ++ //Set BBP R66=0x3C ++ value = 0x3C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); ++ //Set BBP R68=0x0B ++ //to improve Rx sensitivity. ++ value = 0x0B; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); ++ //Set BBP R69=0x16 ++ value = 0x16; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); ++ //Set BBP R70=0x08 ++ value = 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); ++ //Set BBP R73=0x11 ++ value = 0x11; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); ++ ++ // If Channel=14, Bandwidth=20M and Mode=CCK, Set BBP R4 bit5=1 ++ // (Japan filter coefficients) ++ // This segment of code will only works when ATETXMODE and ATECHANNEL ++ // were set to MODE_CCK and 14 respectively before ATETXBW is set to 0. ++ //===================================================================== ++ if (pAd->ate.Channel == 14) ++ { ++ int TxMode = pAd->ate.TxWI.PHYMODE; ++ if (TxMode == MODE_CCK) ++ { ++ // when Channel==14 && Mode==CCK && BandWidth==20M, BBP R4 bit5=1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value |= 0x20; //set bit5=1 ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ } ++ } ++ ++ //===================================================================== ++ // If bandwidth != 40M, RF Reg4 bit 21 = 0. ++#ifdef RT30xx ++ // Set BW ++ if(IS_RT30xx(pAd)) ++ RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR) pAd->Mlme.CaliBW20RfR24); ++ else ++#endif // RT30xx // ++ { ++ pAd->LatchRfRegs.R4 &= ~0x00200000; ++ RtmpRfIoWrite(pAd); ++ } ++ ++ } ++ else if(pAd->ate.TxWI.BW == BW_40) ++ { ++ if(pAd->ate.Channel <= 14) ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx40MPwrCfgGBand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgGBand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++ } ++ else ++ { ++ for (i=0; i<5; i++) ++ { ++ if (pAd->Tx40MPwrCfgABand[i] != 0xffffffff) ++ { ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, pAd->Tx40MPwrCfgABand[i]); ++ RTMPusecDelay(5000); ++ } ++ } ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->ate.TxWI.PHYMODE >= MODE_HTMIX) && (pAd->ate.TxWI.MCS == 7)) ++ { ++ value = 0x28; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R67, value); ++ } ++#endif // DOT11_N_SUPPORT // ++ } ++ ++ //Set BBP R4 bit[4:3]=1:0 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &value); ++ value &= (~0x18); ++ value |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, value); ++ ++ //Set BBP R66=0x3C ++ value = 0x3C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, value); ++ //Set BBP R68=0x0C ++ //to improve Rx sensitivity. ++ value = 0x0C; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R68, value); ++ //Set BBP R69=0x1A ++ value = 0x1A; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, value); ++ //Set BBP R70=0x0A ++ value = 0x0A; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, value); ++ //Set BBP R73=0x16 ++ value = 0x16; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, value); ++ ++ // If bandwidth = 40M, set RF Reg4 bit 21 = 1. ++#ifdef RT30xx ++ // Set BW ++ if(IS_RT30xx(pAd)) ++ RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR) pAd->Mlme.CaliBW40RfR24); ++ else ++#endif // RT30xx // ++ { ++ pAd->LatchRfRegs.R4 |= 0x00200000; ++ RtmpRfIoWrite(pAd); ++ } ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_BW_Proc (BBPCurrentBW = %d)\n", pAd->ate.TxWI.BW)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_BW_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame length ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_LENGTH_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxLength = simple_strtol(arg, 0, 10); ++ ++ if((pAd->ate.TxLength < 24) || (pAd->ate.TxLength > (MAX_FRAME_SIZE - 34/* == 2312 */))) ++ { ++ pAd->ate.TxLength = (MAX_FRAME_SIZE - 34/* == 2312 */); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_LENGTH_Proc::Out of range, it should be in range of 24~%d.\n", (MAX_FRAME_SIZE - 34/* == 2312 */))); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_LENGTH_Proc (TxLength = %d)\n", pAd->ate.TxLength)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_LENGTH_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame count ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_COUNT_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxCount = simple_strtol(arg, 0, 10); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_COUNT_Proc (TxCount = %d)\n", pAd->ate.TxCount)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_COUNT_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame MCS ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_MCS_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR MCS; ++ int result; ++ ++ MCS = simple_strtol(arg, 0, 10); ++ result = CheckMCSValid(pAd->ate.TxWI.PHYMODE, MCS); ++ ++ if (result != -1) ++ { ++ pAd->ate.TxWI.MCS = (UCHAR)MCS; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MCS_Proc::Out of range, refer to rate table.\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MCS_Proc (MCS = %d)\n", pAd->ate.TxWI.MCS)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MCS_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame Mode ++ 0: MODE_CCK ++ 1: MODE_OFDM ++ 2: MODE_HTMIX ++ 3: MODE_HTGREENFIELD ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_MODE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxWI.PHYMODE = simple_strtol(arg, 0, 10); ++ ++ if(pAd->ate.TxWI.PHYMODE > 3) ++ { ++ pAd->ate.TxWI.PHYMODE = 0; ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_MODE_Proc::Out of range. it should be in range of 0~3\n")); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("0: CCK, 1: OFDM, 2: HT_MIX, 3: HT_GREEN_FIELD.\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_MODE_Proc (TxMode = %d)\n", pAd->ate.TxWI.PHYMODE)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_MODE_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set ATE Tx frame GI ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_ATE_TX_GI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.TxWI.ShortGI = simple_strtol(arg, 0, 10); ++ ++ if(pAd->ate.TxWI.ShortGI > 1) ++ { ++ pAd->ate.TxWI.ShortGI = 0; ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("Set_ATE_TX_GI_Proc::Out of range\n")); ++ return FALSE; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_TX_GI_Proc (GI = %d)\n", pAd->ate.TxWI.ShortGI)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_TX_GI_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++INT Set_ATE_RX_FER_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ pAd->ate.bRxFer = simple_strtol(arg, 0, 10); ++ ++ if (pAd->ate.bRxFer == 1) ++ { ++ pAd->ate.RxCntPerSec = 0; ++ pAd->ate.RxTotalCnt = 0; ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Set_ATE_RX_FER_Proc (bRxFer = %d)\n", pAd->ate.bRxFer)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("Ralink: Set_ATE_RX_FER_Proc Success\n")); ++ ++ ++ return TRUE; ++} ++ ++INT Set_ATE_Read_RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++#ifdef RT30xx ++//2008/07/10:KH add to support RT30xx ATE<-- ++ if(IS_RT30xx(pAd)) ++ { ++ /* modify by WY for Read RF Reg. error */ ++ UCHAR RFValue; ++ INT index=0; ++ for (index = 0; index < 32; index++) ++ { ++ RT30xxReadRFRegister(pAd, index, (PUCHAR)&RFValue); ++ printk("R%d=%d\n",index,RFValue); ++ } ++ } ++ else ++//2008/07/10:KH add to support RT30xx ATE--> ++#endif // RT30xx // ++ { ++ ate_print(KERN_EMERG "R1 = %lx\n", pAd->LatchRfRegs.R1); ++ ate_print(KERN_EMERG "R2 = %lx\n", pAd->LatchRfRegs.R2); ++ ate_print(KERN_EMERG "R3 = %lx\n", pAd->LatchRfRegs.R3); ++ ate_print(KERN_EMERG "R4 = %lx\n", pAd->LatchRfRegs.R4); ++ } ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++#ifdef RT30xx ++//2008/07/10:KH add to support 3070 ATE<-- ++ if(IS_RT30xx(pAd)) ++ { ++ printk("Warning!! RT30xx Don't Support\n"); ++ return FALSE; ++ ++ } ++ else ++//2008/07/10:KH add to support 3070 ATE--> ++#endif // RT30xx // ++ { ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R1 = value; ++ RtmpRfIoWrite(pAd); ++ } ++ return TRUE; ++ ++} ++ ++INT Set_ATE_Write_RF2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++#ifdef RT30xx ++//2008/07/10:KH add to support 3070 ATE<-- ++ if(IS_RT30xx(pAd)) ++ { ++ printk("Warning!! RT30xx Don't Support\n"); ++ return FALSE; ++ ++ } ++ else ++//2008/07/10:KH add to support 3070 ATE--> ++#endif // RT30xx // ++ { ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R2 = value; ++ RtmpRfIoWrite(pAd); ++ } ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++#ifdef RT30xx ++//2008/07/10:KH add to support 3070 ATE<-- ++ if(IS_RT30xx(pAd)) ++ { ++ printk("Warning!! RT30xx Don't Support\n"); ++ return FALSE; ++ ++ } ++ else ++//2008/07/10:KH add to support 3070 ATE--> ++#endif // RT30xx // ++ { ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R3 = value; ++ RtmpRfIoWrite(pAd); ++ } ++ return TRUE; ++} ++ ++INT Set_ATE_Write_RF4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++#ifdef RT30xx ++//2008/07/10:KH add to support 3070 ATE<-- ++ if(IS_RT30xx(pAd)) ++ { ++ printk("Warning!! RT30xx Don't Support\n"); ++ return FALSE; ++ ++ } ++ else ++//2008/07/10:KH add to support 3070 ATE--> ++#endif // RT30xx // ++ { ++ UINT32 value = simple_strtol(arg, 0, 16); ++ ++ pAd->LatchRfRegs.R4 = value; ++ RtmpRfIoWrite(pAd); ++ } ++ return TRUE; ++} ++#ifdef RT30xx ++//2008/07/10:KH add to support 3070 ATE<-- ++INT SET_ATE_3070RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ UINT32 Reg,RFValue; ++ if(IS_RT30xx(pAd)) ++ { ++ printk("SET_ATE_3070RF_Proc=%s\n",arg); ++ this_char =arg; ++ if ((value = strchr(this_char, ':')) != NULL) ++ *value++ = 0; ++ Reg= simple_strtol(this_char, 0, 16); ++ RFValue= simple_strtol(value, 0, 16); ++ printk("RF Reg[%d]=%d\n",Reg,RFValue); ++ RT30xxWriteRFRegister(pAd, Reg,RFValue); ++ } ++ else ++ printk("Warning!! Only 3070 Support\n"); ++ return TRUE; ++} ++//2008/07/10:KH add to support 3070 ATE--> ++#endif // RT30xx // ++/* ++ ========================================================================== ++ Description: ++ Load and Write EEPROM from a binary file prepared in advance. ++ ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++#ifndef UCOS ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN ret = FALSE; ++ PUCHAR src = EEPROM_BIN_FILE_NAME; ++ struct file *srcf; ++ INT32 retval, orgfsuid, orgfsgid; ++ mm_segment_t orgfs; ++ USHORT WriteEEPROM[(EEPROM_SIZE/2)]; ++ UINT32 FileLength = 0; ++ UINT32 value = simple_strtol(arg, 0, 10); ++ ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value)); ++ ++ if (value > 0) ++ { ++ /* zero the e2p buffer */ ++ NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); ++ ++ /* save uid and gid used for filesystem access. ++ ** set user and group to 0 (root) ++ */ ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ /* as root */ ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ do ++ { ++ /* open the bin file */ ++ srcf = filp_open(src, O_RDONLY, 0); ++ ++ if (IS_ERR(srcf)) ++ { ++ ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src); ++ break; ++ } ++ ++ /* the object must have a read method */ ++ if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) ++ { ++ ate_print("%s - %s does not have a read method\n", __FUNCTION__, src); ++ break; ++ } ++ ++ /* read the firmware from the file *.bin */ ++ FileLength = srcf->f_op->read(srcf, ++ (PUCHAR)WriteEEPROM, ++ EEPROM_SIZE, ++ &srcf->f_pos); ++ ++ if (FileLength != EEPROM_SIZE) ++ { ++ ate_print("%s: error file length (=%d) in e2p.bin\n", ++ __FUNCTION__, FileLength); ++ break; ++ } ++ else ++ { ++ /* write the content of .bin file to EEPROM */ ++ rt_ee_write_all(pAd, WriteEEPROM); ++ ret = TRUE; ++ } ++ break; ++ } while(TRUE); ++ ++ /* close firmware file */ ++ if (IS_ERR(srcf)) ++ { ++ ; ++ } ++ else ++ { ++ retval = filp_close(srcf, NULL); ++ if (retval) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); ++ ++ } ++ } ++ ++ /* restore */ ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ } ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret)); ++ ++ return ret; ++ ++} ++#else ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT WriteEEPROM[(EEPROM_SIZE/2)]; ++ struct iwreq *wrq = (struct iwreq *)arg; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length)); ++ ++ if (wrq->u.data.length != EEPROM_SIZE) ++ { ++ ate_print("%s: error length (=%d) from host\n", ++ __FUNCTION__, wrq->u.data.length); ++ return FALSE; ++ } ++ else/* (wrq->u.data.length == EEPROM_SIZE) */ ++ { ++ /* zero the e2p buffer */ ++ NdisZeroMemory((PUCHAR)WriteEEPROM, EEPROM_SIZE); ++ ++ /* fill the local buffer */ ++ NdisMoveMemory((PUCHAR)WriteEEPROM, wrq->u.data.pointer, wrq->u.data.length); ++ ++ do ++ { ++ /* write the content of .bin file to EEPROM */ ++ rt_ee_write_all(pAd, WriteEEPROM); ++ ++ } while(FALSE); ++ } ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__)); ++ ++ return TRUE; ++ ++} ++#endif // !UCOS // ++ ++INT Set_ATE_Read_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ USHORT buffer[EEPROM_SIZE/2]; ++ USHORT *p; ++ int i; ++ ++ rt_ee_read_all(pAd, (USHORT *)buffer); ++ p = buffer; ++ for (i = 0; i < (EEPROM_SIZE/2); i++) ++ { ++ ate_print("%4.4x ", *p); ++ if (((i+1) % 16) == 0) ++ ate_print("\n"); ++ p++; ++ } ++ return TRUE; ++} ++ ++INT Set_ATE_Show_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print("Mode=%d\n", pAd->ate.Mode); ++ ate_print("TxPower0=%d\n", pAd->ate.TxPower0); ++ ate_print("TxPower1=%d\n", pAd->ate.TxPower1); ++ ate_print("TxAntennaSel=%d\n", pAd->ate.TxAntennaSel); ++ ate_print("RxAntennaSel=%d\n", pAd->ate.RxAntennaSel); ++ ate_print("BBPCurrentBW=%d\n", pAd->ate.TxWI.BW); ++ ate_print("GI=%d\n", pAd->ate.TxWI.ShortGI); ++ ate_print("MCS=%d\n", pAd->ate.TxWI.MCS); ++ ate_print("TxMode=%d\n", pAd->ate.TxWI.PHYMODE); ++ ate_print("Addr1=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr1[0], pAd->ate.Addr1[1], pAd->ate.Addr1[2], pAd->ate.Addr1[3], pAd->ate.Addr1[4], pAd->ate.Addr1[5]); ++ ate_print("Addr2=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr2[0], pAd->ate.Addr2[1], pAd->ate.Addr2[2], pAd->ate.Addr2[3], pAd->ate.Addr2[4], pAd->ate.Addr2[5]); ++ ate_print("Addr3=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ pAd->ate.Addr3[0], pAd->ate.Addr3[1], pAd->ate.Addr3[2], pAd->ate.Addr3[3], pAd->ate.Addr3[4], pAd->ate.Addr3[5]); ++ ate_print("Channel=%d\n", pAd->ate.Channel); ++ ate_print("TxLength=%d\n", pAd->ate.TxLength); ++ ate_print("TxCount=%u\n", pAd->ate.TxCount); ++ ate_print("RFFreqOffset=%d\n", pAd->ate.RFFreqOffset); ++ ate_print(KERN_EMERG "Set_ATE_Show_Proc Success\n"); ++ return TRUE; ++} ++ ++INT Set_ATE_Help_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ate_print("ATE=ATESTART, ATESTOP, TXCONT, TXCARR, TXFRAME, RXFRAME\n"); ++ ate_print("ATEDA\n"); ++ ate_print("ATESA\n"); ++ ate_print("ATEBSSID\n"); ++ ate_print("ATECHANNEL, range:0~14(unless A band !)\n"); ++ ate_print("ATETXPOW0, set power level of antenna 1.\n"); ++ ate_print("ATETXPOW1, set power level of antenna 2.\n"); ++ ate_print("ATETXANT, set TX antenna. 0:all, 1:antenna one, 2:antenna two.\n"); ++ ate_print("ATERXANT, set RX antenna.0:all, 1:antenna one, 2:antenna two, 3:antenna three.\n"); ++ ate_print("ATETXFREQOFFSET, set frequency offset, range 0~63\n"); ++ ate_print("ATETXBW, set BandWidth, 0:20MHz, 1:40MHz.\n"); ++ ate_print("ATETXLEN, set Frame length, range 24~%d\n", (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ ate_print("ATETXCNT, set how many frame going to transmit.\n"); ++ ate_print("ATETXMCS, set MCS, reference to rate table.\n"); ++ ate_print("ATETXMODE, set Mode 0:CCK, 1:OFDM, 2:HT-Mix, 3:GreenField, reference to rate table.\n"); ++ ate_print("ATETXGI, set GI interval, 0:Long, 1:Short\n"); ++ ate_print("ATERXFER, 0:disable Rx Frame error rate. 1:enable Rx Frame error rate.\n"); ++ ate_print("ATERRF, show all RF registers.\n"); ++ ate_print("ATEWRF1, set RF1 register.\n"); ++ ate_print("ATEWRF2, set RF2 register.\n"); ++ ate_print("ATEWRF3, set RF3 register.\n"); ++ ate_print("ATEWRF4, set RF4 register.\n"); ++ ate_print("ATELDE2P, load EEPROM from .bin file.\n"); ++ ate_print("ATERE2P, display all EEPROM content.\n"); ++ ate_print("ATESHOW, display all parameters of ATE.\n"); ++ ate_print("ATEHELP, online help.\n"); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ AsicSwitchChannel() dedicated for ATE. ++ ++ ========================================================================== ++*/ ++VOID ATEAsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 R2 = 0, R3 = DEFAULT_RF_TX_POWER, R4 = 0, Value = 0; ++ CHAR TxPwer = 0, TxPwer2 = 0; ++ UCHAR index, BbpValue = 0, R66 = 0x30; ++ RTMP_RF_REGS *RFRegTable; ++ UCHAR Channel; ++ ++#ifdef RALINK_28xx_QA ++ if ((pAd->ate.bQATxStart == TRUE) || (pAd->ate.bQARxStart == TRUE)) ++ { ++ if (pAd->ate.Channel != pAd->LatchRfRegs.Channel) ++ { ++ pAd->ate.Channel = pAd->LatchRfRegs.Channel; ++ } ++ return; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ Channel = pAd->ate.Channel; ++ ++ // Select antenna ++ AsicAntennaSelect(pAd, Channel); ++ ++ // fill Tx power value ++ TxPwer = pAd->ate.TxPower0; ++ TxPwer2 = pAd->ate.TxPower1; ++#ifdef RT30xx ++//2008/07/10:KH add to support 3070 ATE<-- ++ ++ // The RF programming sequence is difference between 3xxx and 2xxx ++ // The 3070 is 1T1R. Therefore, we don't need to set the number of Tx/Rx path and the only job is to set the parameters of channels. ++ if (IS_RT30xx(pAd) && ((pAd->RfIcType == RFIC_3020) || ++(pAd->RfIcType == RFIC_3021) || (pAd->RfIcType == RFIC_3022) || ++(pAd->RfIcType == RFIC_2020))) ++ { ++ /* modify by WY for Read RF Reg. error */ ++ UCHAR RFValue; ++ ++ for (index = 0; index < NUM_OF_3020_CHNL; index++) ++ { ++ if (Channel == FreqItems3020[index].Channel) ++ { ++ // Programming channel parameters ++ RT30xxWriteRFRegister(pAd, RF_R02, FreqItems3020[index].N); ++ RT30xxWriteRFRegister(pAd, RF_R03, FreqItems3020[index].K); ++ ++ RT30xxReadRFRegister(pAd, RF_R06, (PUCHAR)&RFValue); ++ RFValue = (RFValue & 0xFC) | FreqItems3020[index].R; ++ RT30xxWriteRFRegister(pAd, RF_R06, (UCHAR)RFValue); ++ ++ // Set Tx Power ++ RT30xxReadRFRegister(pAd, RF_R12, (PUCHAR)&RFValue); ++ RFValue = (RFValue & 0xE0) | TxPwer; ++ RT30xxWriteRFRegister(pAd, RF_R12, (UCHAR)RFValue); ++ ++ // Set RF offset ++ RT30xxReadRFRegister(pAd, RF_R23, (PUCHAR)&RFValue); ++ //2008/08/06: KH modified "pAd->RFFreqOffset" to "pAd->ate.RFFreqOffset" ++ RFValue = (RFValue & 0x80) | pAd->ate.RFFreqOffset; ++ RT30xxWriteRFRegister(pAd, RF_R23, (UCHAR)RFValue); ++ ++ // Set BW ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ RFValue = pAd->Mlme.CaliBW40RfR24; ++ //DISABLE_11N_CHECK(pAd); ++ } ++ else ++ { ++ RFValue = pAd->Mlme.CaliBW20RfR24; ++ } ++ RT30xxWriteRFRegister(pAd, RF_R24, (UCHAR)RFValue); ++ ++ // Enable RF tuning ++ RT30xxReadRFRegister(pAd, RF_R07, (PUCHAR)&RFValue); ++ RFValue = RFValue | 0x1; ++ RT30xxWriteRFRegister(pAd, RF_R07, (UCHAR)RFValue); ++ ++ // latch channel for future usage. ++ pAd->LatchRfRegs.Channel = Channel; ++ ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%d, Pwr1=%d, %dT), N=0x%02X, K=0x%02X, R=0x%02X\n", ++ Channel, ++ pAd->RfIcType, ++ TxPwer, ++ TxPwer2, ++ pAd->Antenna.field.TxPath, ++ FreqItems3020[index].N, ++ FreqItems3020[index].K, ++ FreqItems3020[index].R)); ++ } ++ else ++//2008/07/10:KH add to support 3070 ATE--> ++#endif // RT30xx // ++{ ++ RFRegTable = RF2850RegTable; ++ ++ switch (pAd->RfIcType) ++ { ++ /* But only 2850 and 2750 support 5.5GHz band... */ ++ case RFIC_2820: ++ case RFIC_2850: ++ case RFIC_2720: ++ case RFIC_2750: ++ ++ for (index = 0; index < NUM_OF_2850_CHNL; index++) ++ { ++ if (Channel == RFRegTable[index].Channel) ++ { ++ R2 = RFRegTable[index].R2; ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ R2 |= 0x4000; // If TXpath is 1, bit 14 = 1; ++ } ++ ++ if (pAd->Antenna.field.RxPath == 2) ++ { ++ switch (pAd->ate.RxAntennaSel) ++ { ++ case 1: ++ R2 |= 0x20040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x00; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 2: ++ R2 |= 0x10040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x01; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ default: ++ R2 |= 0x40; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ /* Only enable two Antenna to receive. */ ++ BbpValue |= 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ } ++ } ++ else if (pAd->Antenna.field.RxPath == 1) ++ { ++ R2 |= 0x20040; // write 1 to off RxPath ++ } ++ ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ if (pAd->ate.TxAntennaSel == 1) ++ { ++ R2 |= 0x4000; // If TX Antenna select is 1 , bit 14 = 1; Disable Ant 2 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; //11100111B ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ else if (pAd->ate.TxAntennaSel == 2) ++ { ++ R2 |= 0x8000; // If TX Antenna select is 2 , bit 15 = 1; Disable Ant 1 ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; ++ BbpValue |= 0x08; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ else ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &BbpValue); ++ BbpValue &= 0xE7; ++ BbpValue |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, BbpValue); ++ } ++ } ++ if (pAd->Antenna.field.RxPath == 3) ++ { ++ switch (pAd->ate.RxAntennaSel) ++ { ++ case 1: ++ R2 |= 0x20040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x00; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 2: ++ R2 |= 0x10040; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x01; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ case 3: ++ R2 |= 0x30000; ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x02; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ default: ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BbpValue); ++ BbpValue &= 0xE4; ++ BbpValue |= 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BbpValue); ++ break; ++ } ++ } ++ ++ if (Channel > 14) ++ { ++ // initialize R3, R4 ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff); ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15); ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ // 5.5G band power range: 0xF9~0X0F, TX0 Reg3 bit9/TX1 Reg4 bit6="0" means the TX power reduce 7dB ++ // R3 ++ if ((TxPwer >= -7) && (TxPwer < 0)) ++ { ++ TxPwer = (7+TxPwer); ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer=%d \n", TxPwer)); ++ } ++ else ++ { ++ TxPwer = (TxPwer > 0xF) ? (0xF) : (TxPwer); ++ R3 |= (TxPwer << 10) | (1 << 9); ++ } ++ ++ // R4 ++ if ((TxPwer2 >= -7) && (TxPwer2 < 0)) ++ { ++ TxPwer2 = (7+TxPwer2); ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ATEAsicSwitchChannel: TxPwer2=%d \n", TxPwer2)); ++ } ++ else ++ { ++ TxPwer2 = (TxPwer2 > 0xF) ? (0xF) : (TxPwer2); ++ R4 |= (TxPwer2 << 7) | (1 << 6); ++ } ++ } ++ else ++ { ++ R3 = (RFRegTable[index].R3 & 0xffffc1ff) | (TxPwer << 9); // set TX power0 ++ R4 = (RFRegTable[index].R4 & (~0x001f87c0)) | (pAd->ate.RFFreqOffset << 15) | (TxPwer2 <<6);// Set freq offset & TxPwr1 ++ } ++ ++ // Based on BBP current mode before changing RF channel. ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ R4 |=0x200000; ++ } ++ ++ // Update variables ++ pAd->LatchRfRegs.Channel = Channel; ++ pAd->LatchRfRegs.R1 = RFRegTable[index].R1; ++ pAd->LatchRfRegs.R2 = R2; ++ pAd->LatchRfRegs.R3 = R3; ++ pAd->LatchRfRegs.R4 = R4; ++ ++ RtmpRfIoWrite(pAd); ++ ++ break; ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ // Change BBP setting during switch from a->g, g->a ++ if (Channel <= 14) ++ { ++ ULONG TxPinCfg = 0x00050F0A;// 2007.10.09 by Brian : 0x0005050A ==> 0x00050F0A ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ ++ /* For 1T/2R chip only... */ ++ if (pAd->NicConfig2.field.ExternalLNAForG) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x62); ++ } ++ else ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0x84); ++ } ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ if ((BbpValue != 0x00)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); ++ } ++ ++ // 5.5GHz band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x04); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R. ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ else ++ { ++ ULONG TxPinCfg = 0x00050F05;//2007.10.09 by Brian : 0x00050505 ==> 0x00050F05 ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R62, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R63, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R64, (0x37 - GET_LNA_GAIN(pAd))); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R82, 0xF2); ++ ++ // According the Rory's suggestion to solve the middle range issue. ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R86, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ if ((BbpValue != 0x00)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R86, 0x00); ++ } ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R91, &BbpValue); ++ ASSERT((BbpValue == 0x04)); ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R92, &BbpValue); ++ ASSERT((BbpValue == 0x00)); ++ ++ // 5.5GHz band selection PIN, bit1 and bit2 are complement ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Value); ++ Value &= (~0x6); ++ Value |= (0x02); ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Value); ++ ++ // Turn off unused PA or LNA when only 1T or 1R. ++ if (pAd->Antenna.field.TxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFFFF3; ++ } ++ if (pAd->Antenna.field.RxPath == 1) ++ { ++ TxPinCfg &= 0xFFFFF3FF; ++ } ++ ++ RTMP_IO_WRITE32(pAd, TX_PIN_CFG, TxPinCfg); ++ } ++ ++ // R66 should be set according to Channel and use 20MHz when scanning ++ if (Channel <= 14) ++ { ++ // BG band ++ R66 = 0x2E + GET_LNA_GAIN(pAd); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { ++ // 5.5 GHz band ++ if (pAd->ate.TxWI.BW == BW_20) ++ { ++ R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ else ++ { ++ R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); ++ } ++ } ++ ++ // ++ // On 11A, We should delay and wait RF/BBP to be stable ++ // and the appropriate time should be 1000 micro seconds ++ // 2005/06/05 - On 11G, We also need this delay time. Otherwise it's difficult to pass the WHQL. ++ // ++ RTMPusecDelay(1000); ++ ++ if (Channel > 14) ++ { ++ // When 5.5GHz band the LSB of TxPwr will be used to reduced 7dB or not. ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SwitchChannel#%d(RF=%d, Pwr0=%u, Pwr1=%u, %dT) to , R1=0x%08lx, R2=0x%08lx, R3=0x%08lx, R4=0x%08lx\n", ++ Channel, ++ pAd->RfIcType, ++ (R3 & 0x00003e00) >> 9, ++ (R4 & 0x000007c0) >> 6, ++ pAd->Antenna.field.TxPath, ++ pAd->LatchRfRegs.R1, ++ pAd->LatchRfRegs.R2, ++ pAd->LatchRfRegs.R3, ++ pAd->LatchRfRegs.R4)); ++ } ++} ++ ++// ++// In fact, no one will call this routine so far ! ++// ++/* ++ ========================================================================== ++ Description: ++ Gives CCK TX rate 2 more dB TX power. ++ This routine works only in ATE mode. ++ ++ calculate desired Tx power in RF R3.Tx0~5, should consider - ++ 0. if current radio is a noisy environment (pAd->DrsCounters.fNoisyEnvironment) ++ 1. TxPowerPercentage ++ 2. auto calibration based on TSSI feedback ++ 3. extra 2 db for CCK ++ 4. -10 db upon very-short distance (AvgRSSI >= -40db) to AP ++ ++ NOTE: Since this routine requires the value of (pAd->DrsCounters.fNoisyEnvironment), ++ it should be called AFTER MlmeDynamicTxRateSwitching() ++ ========================================================================== ++ */ ++VOID ATEAsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd) ++{ ++ INT i, j; ++ CHAR DeltaPwr = 0; ++ BOOLEAN bAutoTxAgc = FALSE; ++ UCHAR TssiRef, *pTssiMinusBoundary, *pTssiPlusBoundary, TxAgcStep; ++ UCHAR BbpR49 = 0, idx; ++ PCHAR pTxAgcCompensate; ++ ULONG TxPwr[5]; ++ CHAR Value; ++ ++ /* no one calls this procedure so far */ ++ if (pAd->ate.TxWI.BW == BW_40) ++ { ++ if (pAd->ate.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; ++ } ++ } ++ else ++ { ++ if (pAd->ate.Channel > 14) ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; ++ } ++ else ++ { ++ TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; ++ TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; ++ TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; ++ TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; ++ TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; ++ } ++ } ++ ++ // TX power compensation for temperature variation based on TSSI. ++ // Do it per 4 seconds. ++ if (pAd->Mlme.OneSecPeriodicRound % 4 == 0) ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ /* bg channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ TssiRef = pAd->TssiRefG; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryG[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryG[0]; ++ TxAgcStep = pAd->TxAgcStepG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ /* a channel */ ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ TssiRef = pAd->TssiRefA; ++ pTssiMinusBoundary = &pAd->TssiMinusBoundaryA[0]; ++ pTssiPlusBoundary = &pAd->TssiPlusBoundaryA[0]; ++ TxAgcStep = pAd->TxAgcStepA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ { ++ /* BbpR49 is unsigned char */ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R49, &BbpR49); ++ ++ /* (p) TssiPlusBoundaryG[0] = 0 = (m) TssiMinusBoundaryG[0] */ ++ /* compensate: +4 +3 +2 +1 0 -1 -2 -3 -4 * steps */ ++ /* step value is defined in pAd->TxAgcStepG for tx power value */ ++ ++ /* [4]+1+[4] p4 p3 p2 p1 o1 m1 m2 m3 m4 */ ++ /* ex: 0x00 0x15 0x25 0x45 0x88 0xA0 0xB5 0xD0 0xF0 ++ above value are examined in mass factory production */ ++ /* [4] [3] [2] [1] [0] [1] [2] [3] [4] */ ++ ++ /* plus is 0x10 ~ 0x40, minus is 0x60 ~ 0x90 */ ++ /* if value is between p1 ~ o1 or o1 ~ s1, no need to adjust tx power */ ++ /* if value is 0x65, tx power will be -= TxAgcStep*(2-1) */ ++ ++ if (BbpR49 > pTssiMinusBoundary[1]) ++ { ++ // Reading is larger than the reference value. ++ // Check for how large we need to decrease the Tx power. ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 <= pTssiMinusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should decrease, idx = 0 means there is nothing to compensate ++// if (R3 > (ULONG) (TxAgcStep * (idx-1))) ++ *pTxAgcCompensate = -(TxAgcStep * (idx-1)); ++// else ++// *pTxAgcCompensate = -((UCHAR)R3); ++ ++ DeltaPwr += (*pTxAgcCompensate); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("-- Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = -%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else if (BbpR49 < pTssiPlusBoundary[1]) ++ { ++ // Reading is smaller than the reference value ++ // check for how large we need to increase the Tx power ++ for (idx = 1; idx < 5; idx++) ++ { ++ if (BbpR49 >= pTssiPlusBoundary[idx]) // Found the range ++ break; ++ } ++ // The index is the step we should increase, idx = 0 means there is nothing to compensate ++ *pTxAgcCompensate = TxAgcStep * (idx-1); ++ DeltaPwr += (*pTxAgcCompensate); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("++ Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, idx-1)); ++ } ++ else ++ { ++ *pTxAgcCompensate = 0; ++ ATEDBGPRINT(RT_DEBUG_TRACE, (" Tx Power, BBP R1=%x, TssiRef=%x, TxAgcStep=%x, step = +%d\n", ++ BbpR49, TssiRef, TxAgcStep, 0)); ++ } ++ } ++ } ++ else ++ { ++ if (pAd->ate.Channel <= 14) ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcG; ++ pTxAgcCompensate = &pAd->TxAgcCompensateG; ++ } ++ else ++ { ++ bAutoTxAgc = pAd->bAutoTxAgcA; ++ pTxAgcCompensate = &pAd->TxAgcCompensateA; ++ } ++ ++ if (bAutoTxAgc) ++ DeltaPwr += (*pTxAgcCompensate); ++ } ++ ++ /* calculate delta power based on the percentage specified from UI */ ++ // E2PROM setting is calibrated for maximum TX power (i.e. 100%) ++ // We lower TX power here according to the percentage specified from UI ++ if (pAd->CommonCfg.TxPowerPercentage == 0xffffffff) // AUTO TX POWER control ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 90) // 91 ~ 100% & AUTO, treat as 100% in terms of mW ++ ; ++ else if (pAd->CommonCfg.TxPowerPercentage > 60) // 61 ~ 90%, treat as 75% in terms of mW ++ { ++ DeltaPwr -= 1; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 30) // 31 ~ 60%, treat as 50% in terms of mW ++ { ++ DeltaPwr -= 3; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 15) // 16 ~ 30%, treat as 25% in terms of mW ++ { ++ DeltaPwr -= 6; ++ } ++ else if (pAd->CommonCfg.TxPowerPercentage > 9) // 10 ~ 15%, treat as 12.5% in terms of mW ++ { ++ DeltaPwr -= 9; ++ } ++ else // 0 ~ 9 %, treat as MIN(~3%) in terms of mW ++ { ++ DeltaPwr -= 12; ++ } ++ ++ /* reset different new tx power for different TX rate */ ++ for(i=0; i<5; i++) ++ { ++ if (TxPwr[i] != 0xffffffff) ++ { ++ for (j=0; j<8; j++) ++ { ++ Value = (CHAR)((TxPwr[i] >> j*4) & 0x0F); /* 0 ~ 15 */ ++ ++ if ((Value + DeltaPwr) < 0) ++ { ++ Value = 0; /* min */ ++ } ++ else if ((Value + DeltaPwr) > 0xF) ++ { ++ Value = 0xF; /* max */ ++ } ++ else ++ { ++ Value += DeltaPwr; /* temperature compensation */ ++ } ++ ++ /* fill new value to CSR offset */ ++ TxPwr[i] = (TxPwr[i] & ~(0x0000000F << j*4)) | (Value << j*4); ++ } ++ ++ /* write tx power value to CSR */ ++ /* TX_PWR_CFG_0 (8 tx rate) for TX power for OFDM 12M/18M ++ TX power for OFDM 6M/9M ++ TX power for CCK5.5M/11M ++ TX power for CCK1M/2M */ ++ /* TX_PWR_CFG_1 ~ TX_PWR_CFG_4 */ ++ RTMP_IO_WRITE32(pAd, TX_PWR_CFG_0 + i*4, TxPwr[i]); ++ ++ ++ } ++ } ++ ++} ++ ++/* ++ ======================================================================== ++ Routine Description: ++ Write TxWI for ATE mode. ++ ++ Return Value: ++ None ++ ======================================================================== ++*/ ++ ++#ifdef RT2870 ++static VOID ATEWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR MIMOps, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING Transmit) ++{ ++ // ++ // Always use Long preamble before verifiation short preamble functionality works well. ++ // Todo: remove the following line if short preamble functionality works ++ // ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); ++ pTxWI->FRAG= FRAG; ++ pTxWI->TS= InsTimestamp; ++ pTxWI->AMPDU = AMPDU; ++ ++ pTxWI->MIMOps = PWR_ACTIVE; ++ pTxWI->MpduDensity = 4; ++ pTxWI->ACK = Ack; ++ pTxWI->txop = Txopmode; ++ pTxWI->NSEQ = NSeq; ++ pTxWI->BAWinSize = BASize; ++ ++ pTxWI->WirelessCliID = WCID; ++ pTxWI->MPDUtotalByteCount = Length; ++ pTxWI->PacketId = PID; ++ ++ pTxWI->BW = Transmit.field.BW; ++ pTxWI->ShortGI = Transmit.field.ShortGI; ++ pTxWI->STBC= Transmit.field.STBC; ++ ++ pTxWI->MCS = Transmit.field.MCS; ++ pTxWI->PHYMODE= Transmit.field.MODE; ++ ++#ifdef DOT11_N_SUPPORT ++ // ++ // MMPS is 802.11n features. Because TxWI->MCS > 7 must be HT mode, ++ // so need not check if it's HT rate. ++ // ++ if ((MIMOps == MMPS_STATIC) && (pTxWI->MCS > 7)) ++ pTxWI->MCS = 7; ++ ++ if ((MIMOps == MMPS_DYNAMIC) && (pTxWI->MCS > 7)) // SMPS protect 2 spatial. ++ pTxWI->MIMOps = 1; ++#endif // DOT11_N_SUPPORT // ++ ++ pTxWI->CFACK = CfAck; ++ ++ return; ++} ++#endif // RT2870 // ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Disable protection for ATE. ++ ======================================================================== ++*/ ++VOID ATEDisableAsicProtect( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PROT_CFG_STRUC ProtCfg, ProtCfg4; ++ UINT32 Protect[6]; ++ USHORT offset; ++ UCHAR i; ++ UINT32 MacReg = 0; ++ ++ // Config ASIC RTS threshold register ++ RTMP_IO_READ32(pAd, TX_RTS_CFG, &MacReg); ++ MacReg &= 0xFF0000FF; ++ MacReg |= (pAd->CommonCfg.RtsThreshold << 8); ++ RTMP_IO_WRITE32(pAd, TX_RTS_CFG, MacReg); ++ ++ // Initial common protection settings ++ RTMPZeroMemory(Protect, sizeof(Protect)); ++ ProtCfg4.word = 0; ++ ProtCfg.word = 0; ++ ProtCfg.field.TxopAllowGF40 = 1; ++ ProtCfg.field.TxopAllowGF20 = 1; ++ ProtCfg.field.TxopAllowMM40 = 1; ++ ProtCfg.field.TxopAllowMM20 = 1; ++ ProtCfg.field.TxopAllowOfdm = 1; ++ ProtCfg.field.TxopAllowCck = 1; ++ ProtCfg.field.RTSThEn = 1; ++ ProtCfg.field.ProtectNav = ASIC_SHORTNAV; ++ ++ // Handle legacy(B/G) protection ++ ProtCfg.field.ProtectRate = pAd->CommonCfg.RtsRate; ++ ProtCfg.field.ProtectCtrl = 0; ++ Protect[0] = ProtCfg.word; ++ Protect[1] = ProtCfg.word; ++ ++ // NO PROTECT ++ // 1.All STAs in the BSS are 20/40 MHz HT ++ // 2. in ai 20/40MHz BSS ++ // 3. all STAs are 20MHz in a 20MHz BSS ++ // Pure HT. no protection. ++ ++ // MM20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[2] = 0x01744004; ++ ++ // MM40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[3] = 0x03f44084; ++ ++ // CF20_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 010111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4004 (OFDM 24M) ++ Protect[4] = 0x01744004; ++ ++ // CF40_PROT_CFG ++ // Reserved (31:27) ++ // PROT_TXOP(25:20) -- 111111 ++ // PROT_NAV(19:18) -- 01 (Short NAV protection) ++ // PROT_CTRL(17:16) -- 00 (None) ++ // PROT_RATE(15:0) -- 0x4084 (duplicate OFDM 24M) ++ Protect[5] = 0x03f44084; ++ ++ pAd->CommonCfg.IOTestParm.bRTSLongProtOn = FALSE; ++ ++ offset = CCK_PROT_CFG; ++ for (i = 0;i < 6;i++) ++ RTMP_IO_WRITE32(pAd, offset + i*4, Protect[i]); ++ ++} ++ ++#ifdef RT2870 ++/* ++ ======================================================================== ++ Routine Description: ++ Write TxInfo for ATE mode. ++ ++ Return Value: ++ None ++ ======================================================================== ++*/ ++static VOID ATEWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst) ++{ ++ pTxInfo->USBDMATxPktLen = USBDMApktLen; ++ pTxInfo->QSEL = QueueSel; ++ ++ if (QueueSel != FIFO_EDCA) ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("=======> QueueSel != FIFO_EDCA<=======\n")); ++ ++ pTxInfo->USBDMANextVLD = NextValid; ++ pTxInfo->USBDMATxburst = TxBurst; ++ pTxInfo->WIV = bWiv; ++ pTxInfo->SwUseLastRound = 0; ++ pTxInfo->rsv = 0; ++ pTxInfo->rsv2 = 0; ++ ++ return; ++} ++#endif // RT2870 // ++ ++/* There are two ways to convert Rssi */ ++#if 1 ++// ++// The way used with GET_LNA_GAIN(). ++// ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ LNAGain = GET_LNA_GAIN(pAd); ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-12 - RssiOffset - LNAGain - Rssi); ++} ++#else ++// ++// The way originally used in ATE of rt2860ap. ++// ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber) ++{ ++ UCHAR RssiOffset, LNAGain; ++ ++ // Rssi equals to zero should be an invalid value ++ if (Rssi == 0) ++ return -99; ++ ++ if (pAd->LatchRfRegs.Channel > 14) ++ { ++ LNAGain = pAd->ALNAGain; ++ if (RssiNumber == 0) ++ RssiOffset = pAd->ARssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->ARssiOffset1; ++ else ++ RssiOffset = pAd->ARssiOffset2; ++ } ++ else ++ { ++ LNAGain = pAd->BLNAGain; ++ if (RssiNumber == 0) ++ RssiOffset = pAd->BGRssiOffset0; ++ else if (RssiNumber == 1) ++ RssiOffset = pAd->BGRssiOffset1; ++ else ++ RssiOffset = pAd->BGRssiOffset2; ++ } ++ ++ return (-32 - RssiOffset + LNAGain - Rssi); ++} ++#endif /* end of #if 1 */ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Set Japan filter coefficients if needed. ++ Note: ++ This routine should only be called when ++ entering TXFRAME mode or TXCONT mode. ++ ++ ======================================================================== ++*/ ++static VOID SetJapanFilter( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR BbpData = 0; ++ ++ // ++ // If Channel=14 and Bandwidth=20M and Mode=CCK, set BBP R4 bit5=1 ++ // (Japan Tx filter coefficients)when (TXFRAME or TXCONT). ++ // ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BbpData); ++ ++ if ((pAd->ate.TxWI.PHYMODE == MODE_CCK) && (pAd->ate.Channel == 14) && (pAd->ate.TxWI.BW == BW_20)) ++ { ++ BbpData |= 0x20; // turn on ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("SetJapanFilter!!!\n")); ++ } ++ else ++ { ++ BbpData &= 0xdf; // turn off ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("ClearJapanFilter!!!\n")); ++ } ++ ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BbpData); ++} ++ ++VOID ATESampleRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI) ++{ ++ /* There are two ways to collect RSSI. */ ++#if 1 ++ //pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; ++ if (pRxWI->RSSI0 != 0) ++ { ++ pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); ++ pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; ++ pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; ++ } ++ if (pRxWI->RSSI1 != 0) ++ { ++ pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); ++ pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; ++ pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; ++ } ++ if (pRxWI->RSSI2 != 0) ++ { ++ pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); ++ pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; ++ pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; ++ } ++ ++ pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0);// CHAR ==> UCHAR ? ++ pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1);// CHAR ==> UCHAR ? ++ ++ pAd->ate.NumOfAvgRssiSample ++; ++#else ++ pAd->ate.LastSNR0 = (CHAR)(pRxWI->SNR0); ++ pAd->ate.LastSNR1 = (CHAR)(pRxWI->SNR1); ++ pAd->ate.RxCntPerSec++; ++ pAd->ate.LastRssi0 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI0, RSSI_0); ++ pAd->ate.LastRssi1 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI1, RSSI_1); ++ pAd->ate.LastRssi2 = ATEConvertToRssi(pAd, (CHAR) pRxWI->RSSI2, RSSI_2); ++ pAd->ate.AvgRssi0X8 = (pAd->ate.AvgRssi0X8 - pAd->ate.AvgRssi0) + pAd->ate.LastRssi0; ++ pAd->ate.AvgRssi0 = pAd->ate.AvgRssi0X8 >> 3; ++ pAd->ate.AvgRssi1X8 = (pAd->ate.AvgRssi1X8 - pAd->ate.AvgRssi1) + pAd->ate.LastRssi1; ++ pAd->ate.AvgRssi1 = pAd->ate.AvgRssi1X8 >> 3; ++ pAd->ate.AvgRssi2X8 = (pAd->ate.AvgRssi2X8 - pAd->ate.AvgRssi2) + pAd->ate.LastRssi2; ++ pAd->ate.AvgRssi2 = pAd->ate.AvgRssi2X8 >> 3; ++ pAd->ate.NumOfAvgRssiSample ++; ++#endif ++} ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPStationStop( ++ IN PRTMP_ADAPTER pAd) ++{ ++// BOOLEAN Cancelled; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStop\n")); ++ ++ // For rx statistics, we need to keep this timer running. ++// RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStop\n")); ++} ++ ++VOID RTMPStationStart( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Setup Frame format. ++ NOTE: ++ This routine should only be used in ATE mode. ++ ========================================================================== ++ */ ++ ++#ifdef RT2870 ++/*======================Start of RT2870======================*/ ++/* */ ++/* */ ++static INT ATESetUpFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TxIdx) ++{ ++ UINT j; ++ PTX_CONTEXT pNullContext; ++ PUCHAR pDest; ++ HTTRANSMIT_SETTING TxHTPhyMode; ++ PTXWI_STRUC pTxWI; ++ PTXINFO_STRUC pTxInfo; ++ UINT32 TransferBufferLength, OrgBufferLength = 0; ++ UCHAR padLen = 0; ++#ifdef RALINK_28xx_QA ++ PHEADER_802_11 pHeader80211 = NULL; ++#endif // RALINK_28xx_QA // ++ ++ if ((RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) || ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ return -1; ++ } ++ ++ /* We always use QID_AC_BE and FIFO_EDCA in ATE mode. */ ++ ++ pNullContext = &(pAd->NullContext); ++ ASSERT(pNullContext != NULL); ++ ++ if (pNullContext->InUse == FALSE) ++ { ++ // Set the in use bit ++ pNullContext->InUse = TRUE; ++ NdisZeroMemory(&(pAd->NullFrame), sizeof(HEADER_802_11)); ++ ++ // Fill 802.11 header. ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ pHeader80211 = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); ++// pDest = NdisMoveMemory(&(pAd->NullFrame), pAd->ate.Header, pAd->ate.HLen); ++// pHeader80211 = (PHEADER_802_11)pDest; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ // Fill 802.11 header. ++ NdisMoveMemory(&(pAd->NullFrame), TemplateFrame, sizeof(HEADER_802_11)); ++ } ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)&(pAd->NullFrame), DIR_READ, FALSE); ++#endif // RT_BIG_ENDIAN // ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ /* modify sequence number.... */ ++ if (pAd->ate.TxDoneCount == 0) ++ { ++ pAd->ate.seq = pHeader80211->Sequence; ++ } ++ else ++ { ++ pHeader80211->Sequence = ++pAd->ate.seq; ++ } ++ /* We already got all the addr. fields from QA GUI. */ ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->ate.Addr1); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->ate.Addr2); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->ate.Addr3); ++ } ++ ++ RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], TX_BUFFER_NORMSIZE);//??? ++ pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; ++ ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // Avoid to exceed the range of WirelessPacket[]. ++ ASSERT(pAd->ate.TxInfo.USBDMATxPktLen <= (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ NdisMoveMemory(pTxInfo, &(pAd->ate.TxInfo), sizeof(pAd->ate.TxInfo)); ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ // Avoid to exceed the range of WirelessPacket[]. ++ ASSERT(pAd->ate.TxLength <= (MAX_FRAME_SIZE - 34/* == 2312 */)); ++ ++ // pTxInfo->USBDMATxPktLen will be updated to include padding later. ++ ATEWriteTxInfo(pAd, pTxInfo, (USHORT)(TXWI_SIZE + pAd->ate.TxLength), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxInfo->QSEL = FIFO_EDCA; ++ } ++ ++ pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; ++ ++ // Fill TxWI. ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; ++ TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; ++ TxHTPhyMode.field.STBC = pAd->ate.TxWI.STBC; ++ TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; ++ TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; ++ ATEWriteTxWI(pAd, pTxWI, pAd->ate.TxWI.FRAG, pAd->ate.TxWI.TS, pAd->ate.TxWI.AMPDU, pAd->ate.TxWI.ACK, pAd->ate.TxWI.NSEQ, ++ pAd->ate.TxWI.BAWinSize, BSSID_WCID, pAd->ate.TxWI.MPDUtotalByteCount/* include 802.11 header */, pAd->ate.TxWI.PacketId, 0, pAd->ate.TxWI.txop/*IFS_HTTXOP*/, pAd->ate.TxWI.CFACK/*FALSE*/, TxHTPhyMode); ++ } ++ else ++ { ++ TxHTPhyMode.field.BW = pAd->ate.TxWI.BW; ++ TxHTPhyMode.field.ShortGI = pAd->ate.TxWI.ShortGI; ++ TxHTPhyMode.field.STBC = 0; ++ TxHTPhyMode.field.MCS = pAd->ate.TxWI.MCS; ++ TxHTPhyMode.field.MODE = pAd->ate.TxWI.PHYMODE; ++ ++ ATEWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE/* No ack required. */, FALSE, 0, BSSID_WCID, pAd->ate.TxLength, ++ 0, 0, IFS_HTTXOP, FALSE, TxHTPhyMode);// "MMPS_STATIC" instead of "MMPS_DYNAMIC" ??? ++ } ++ ++ RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); ++ ++ pDest = &(pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE+TXWI_SIZE+sizeof(HEADER_802_11)]); ++ ++ // Prepare frame payload ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQATxStart == TRUE) ++ { ++ // copy pattern ++ if ((pAd->ate.PLen != 0)) ++ { ++ for (j = 0; j < pAd->ate.DLen; j+=pAd->ate.PLen) ++ { ++ RTMPMoveMemory(pDest, pAd->ate.Pattern, pAd->ate.PLen); ++ pDest += pAd->ate.PLen; ++ } ++ } ++ TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxWI.MPDUtotalByteCount; ++ } ++ else ++#endif // RALINK_28xx_QA // ++ { ++ for (j = 0; j < (pAd->ate.TxLength - sizeof(HEADER_802_11)); j++) ++ { ++ *pDest = 0xA5; ++ pDest += 1; ++ } ++ TransferBufferLength = TXINFO_SIZE + TXWI_SIZE + pAd->ate.TxLength; ++ } ++ ++#if 1 ++ OrgBufferLength = TransferBufferLength; ++ TransferBufferLength = (TransferBufferLength + 3) & (~3); ++ ++ // Always add 4 extra bytes at every packet. ++ padLen = TransferBufferLength - OrgBufferLength + 4;/* 4 == last packet padding */ ++ ASSERT((padLen <= (RTMP_PKT_TAIL_PADDING - 4/* 4 == MaxBulkOutsize alignment padding */))); ++ ++ /* Now memzero all extra padding bytes. */ ++ NdisZeroMemory(pDest, padLen); ++ pDest += padLen; ++#else ++ if ((TransferBufferLength % 4) == 1) ++ { ++ NdisZeroMemory(pDest, 7); ++ pDest += 7; ++ TransferBufferLength += 3; ++ } ++ else if ((TransferBufferLength % 4) == 2) ++ { ++ NdisZeroMemory(pDest, 6); ++ pDest += 6; ++ TransferBufferLength += 2; ++ } ++ else if ((TransferBufferLength % 4) == 3) ++ { ++ NdisZeroMemory(pDest, 5); ++ pDest += 5; ++ TransferBufferLength += 1; ++ } ++#endif // 1 // ++ ++ // Update pTxInfo->USBDMATxPktLen to include padding. ++ pTxInfo->USBDMATxPktLen = TransferBufferLength - TXINFO_SIZE; ++ ++ TransferBufferLength += 4; ++ ++ // If TransferBufferLength is multiple of 64, add extra 4 bytes again. ++ if ((TransferBufferLength % pAd->BulkOutMaxPacketSize) == 0) ++ { ++ NdisZeroMemory(pDest, 4); ++ TransferBufferLength += 4; ++ } ++ ++ // Fill out frame length information for global Bulk out arbitor ++ pAd->NullContext.BulkOutSize = TransferBufferLength; ++ } ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++ RTMPFrameEndianChange(pAd, (((PUCHAR)pTxInfo)+TXWI_SIZE+TXINFO_SIZE), DIR_WRITE, FALSE); ++ RTMPDescriptorEndianChange((PUCHAR)pTxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++ return 0; ++} ++ ++VOID ATE_RTUSBBulkOutDataPacketComplete(purbb_t pUrb, struct pt_regs *pt_regs) ++{ ++ PRTMP_ADAPTER pAd; ++ PTX_CONTEXT pNullContext; ++ UCHAR BulkOutPipeId; ++ NTSTATUS Status; ++ unsigned long IrqFlags; ++ ULONG OldValue; ++ ++ pNullContext = (PTX_CONTEXT)pUrb->context; ++ pAd = pNullContext->pAd; ++ ++ ++ // Reset Null frame context flags ++ pNullContext->IRPPending = FALSE; ++ pNullContext->InUse = FALSE; ++ Status = pUrb->status; ++ ++ // Store BulkOut PipeId ++ BulkOutPipeId = pNullContext->BulkOutPipeId; ++ pAd->BulkOutDataOneSecCount++; ++ ++ if (Status == USB_ST_NOERROR) ++ { ++#ifdef RALINK_28xx_QA ++ if ((ATE_ON(pAd)) && (pAd->ate.bQATxStart == TRUE)) ++ { ++ if (pAd->ate.QID == BulkOutPipeId) ++ { ++ // Let Rx can have a chance to break in during Tx process, ++ // especially for loopback mode in QA ATE. ++ // To trade off between tx performance and loopback mode integrity. ++ /* Q : Now Rx is handled by tasklet, do we still need this delay ? */ ++ /* Ans : Even tasklet is used, Rx/Tx < 1 if we do not delay for a while right here. */ ++ RTMPusecDelay(500); ++ pAd->ate.TxDoneCount++; ++ pAd->RalinkCounters.KickTxCount++; ++ ASSERT(pAd->ate.QID == 0); ++ pAd->ate.TxAc0++; ++ } ++ } ++#endif // RALINK_28xx_QA // ++ pAd->BulkOutComplete++; ++ ++ pAd->Counters8023.GoodTransmits++; ++ ++ /* Don't worry about the queue is empty or not. This function will check itself. */ ++ RTMPDeQueuePacket(pAd, TRUE, BulkOutPipeId, MAX_TX_PROCESS); ++ ++ /* In 28xx, SendTxWaitQueue ==> TxSwQueue */ ++/* ++ if (pAd->SendTxWaitQueue[BulkOutPipeId].Number > 0) ++ { ++ RTMPDeQueuePacket(pAd, BulkOutPipeId); ++ } ++*/ ++ } ++ else // STATUS_OTHER ++ { ++ pAd->BulkOutCompleteOther++; ++ ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("BulkOutDataPacket Failed STATUS_OTHER = 0x%x . \n", Status)); ++ ATEDBGPRINT(RT_DEBUG_ERROR, (">>BulkOutReq=0x%lx, BulkOutComplete=0x%lx\n", pAd->BulkOutReq, pAd->BulkOutComplete)); ++ ++ if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET))) ++ { ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET); ++ /* In 28xx, RT_OID_USB_RESET_BULK_OUT ==> CMDTHREAD_RESET_BULK_OUT */ ++ RTUSBEnqueueInternalCmd(pAd, CMDTHREAD_RESET_BULK_OUT, NULL, 0); ++ // Check ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ pAd->bulkResetPipeid = BulkOutPipeId; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ } ++ ++ ++ ++ if (atomic_read(&pAd->BulkOutRemained) > 0) ++ { ++ atomic_dec(&pAd->BulkOutRemained); ++ } ++ ++ // 1st - Transmit Success ++ OldValue = pAd->WlanCounters.TransmittedFragmentCount.u.LowPart; ++ pAd->WlanCounters.TransmittedFragmentCount.u.LowPart++; ++ ++ if (pAd->WlanCounters.TransmittedFragmentCount.u.LowPart < OldValue) ++ { ++ pAd->WlanCounters.TransmittedFragmentCount.u.HighPart++; ++ } ++ ++ if(((pAd->ContinBulkOut == TRUE ) ||(atomic_read(&pAd->BulkOutRemained) > 0)) && (pAd->ate.Mode & ATE_TXFRAME)) ++ { ++ RTUSB_SET_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ } ++ else ++ { ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++#ifdef RALINK_28xx_QA ++ pAd->ate.TxStatus = 0; ++#endif // RALINK_28xx_QA // ++ } ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ pAd->BulkOutPending[BulkOutPipeId] = FALSE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ // Always call Bulk routine, even reset bulk. ++ // The protection of rest bulk should be in BulkOut routine. ++ RTUSBKickBulkOut(pAd); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ATE_RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId) ++{ ++ PTX_CONTEXT pNullContext = &(pAd->NullContext); ++ PURB pUrb; ++ int ret = 0; ++ unsigned long IrqFlags; ++ ++ ++ ASSERT(BulkOutPipeId == 0); ++ ++ /* Build up the frame first. */ ++// ATESetUpFrame(pAd, 0); ++ ++ BULK_OUT_LOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ if (pAd->BulkOutPending[BulkOutPipeId] == TRUE) ++ { ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ return; ++ } ++ ++ pAd->BulkOutPending[BulkOutPipeId] = TRUE; ++ BULK_OUT_UNLOCK(&pAd->BulkOutLock[BulkOutPipeId], IrqFlags); ++ ++ // Increase Total transmit byte counter ++ pAd->RalinkCounters.OneSecTransmittedByteCount += pNullContext->BulkOutSize; ++ pAd->RalinkCounters.TransmittedByteCount += pNullContext->BulkOutSize; ++ ++ // Clear ATE frame bulk out flag ++ RTUSB_CLEAR_BULK_FLAG(pAd, fRTUSB_BULK_OUT_DATA_ATE); ++ ++ // Init Tx context descriptor ++ pNullContext->IRPPending = TRUE; ++ RTUSBInitTxDesc(pAd, pNullContext, BulkOutPipeId, (usb_complete_t)ATE_RTUSBBulkOutDataPacketComplete); ++ pUrb = pNullContext->pUrb; ++ ++ if((ret = RTUSB_SUBMIT_URB(pUrb))!=0) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("ATE_RTUSBBulkOutDataPacket: Submit Tx URB failed %d\n", ret)); ++ return; ++ } ++ ++ pAd->BulkOutReq++; ++ return; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ATE_RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PRX_CONTEXT pRxContext; ++ UINT i; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("--->ATE_RTUSBCancelPendingBulkInIRP\n")); ++#if 1 ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ pRxContext = &(pAd->RxContext[i]); ++ if(pRxContext->IRPPending == TRUE) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ pRxContext->IRPPending = FALSE; ++ pRxContext->InUse = FALSE; ++ //NdisInterlockedDecrement(&pAd->PendingRx); ++ //pAd->PendingRx--; ++ } ++ } ++#else ++ for ( i = 0; i < (RX_RING_SIZE); i++) ++ { ++ pRxContext = &(pAd->RxContext[i]); ++ if(atomic_read(&pRxContext->IrpLock) == IRPLOCK_CANCELABLE) ++ { ++ RTUSB_UNLINK_URB(pRxContext->pUrb); ++ } ++ InterlockedExchange(&pRxContext->IrpLock, IRPLOCK_CANCE_START); ++ } ++#endif // 1 // ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<---ATE_RTUSBCancelPendingBulkInIRP\n")); ++ return; ++} ++#endif // RT2870 // ++ ++VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) ++{ ++ USHORT i; ++ USHORT value; ++ ++ for (i = 0 ; i < EEPROM_SIZE/2 ; ) ++ { ++ /* "value" is expecially for some compilers... */ ++ RT28xx_EEPROM_READ16(pAd, i*2, value); ++ Data[i] = value; ++ i++; ++ } ++} ++ ++VOID rt_ee_write_all(PRTMP_ADAPTER pAd, USHORT *Data) ++{ ++ USHORT i; ++ USHORT value; ++ ++ for (i = 0 ; i < EEPROM_SIZE/2 ; ) ++ { ++ /* "value" is expecially for some compilers... */ ++ value = Data[i]; ++ RT28xx_EEPROM_WRITE16(pAd, i*2, value); ++ i ++; ++ } ++} ++#ifdef RALINK_28xx_QA ++VOID ATE_QA_Statistics( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN PHEADER_802_11 pHeader) ++{ ++ // update counter first ++ if (pHeader != NULL) ++ { ++ if (pHeader->FC.Type == BTYPE_DATA) ++ { ++ if (pRxD->U2M) ++ pAd->ate.U2M++; ++ else ++ pAd->ate.OtherData++; ++ } ++ else if (pHeader->FC.Type == BTYPE_MGMT) ++ { ++ if (pHeader->FC.SubType == SUBTYPE_BEACON) ++ pAd->ate.Beacon++; ++ else ++ pAd->ate.OtherCount++; ++ } ++ else if (pHeader->FC.Type == BTYPE_CNTL) ++ { ++ pAd->ate.OtherCount++; ++ } ++ } ++ pAd->ate.RSSI0 = pRxWI->RSSI0; ++ pAd->ate.RSSI1 = pRxWI->RSSI1; ++ pAd->ate.RSSI2 = pRxWI->RSSI2; ++ pAd->ate.SNR0 = pRxWI->SNR0; ++ pAd->ate.SNR1 = pRxWI->SNR1; ++} ++ ++/* command id with Cmd Type == 0x0008(for 28xx)/0x0005(for iNIC) */ ++#define RACFG_CMD_RF_WRITE_ALL 0x0000 ++#define RACFG_CMD_E2PROM_READ16 0x0001 ++#define RACFG_CMD_E2PROM_WRITE16 0x0002 ++#define RACFG_CMD_E2PROM_READ_ALL 0x0003 ++#define RACFG_CMD_E2PROM_WRITE_ALL 0x0004 ++#define RACFG_CMD_IO_READ 0x0005 ++#define RACFG_CMD_IO_WRITE 0x0006 ++#define RACFG_CMD_IO_READ_BULK 0x0007 ++#define RACFG_CMD_BBP_READ8 0x0008 ++#define RACFG_CMD_BBP_WRITE8 0x0009 ++#define RACFG_CMD_BBP_READ_ALL 0x000a ++#define RACFG_CMD_GET_COUNTER 0x000b ++#define RACFG_CMD_CLEAR_COUNTER 0x000c ++ ++#define RACFG_CMD_RSV1 0x000d ++#define RACFG_CMD_RSV2 0x000e ++#define RACFG_CMD_RSV3 0x000f ++ ++#define RACFG_CMD_TX_START 0x0010 ++#define RACFG_CMD_GET_TX_STATUS 0x0011 ++#define RACFG_CMD_TX_STOP 0x0012 ++#define RACFG_CMD_RX_START 0x0013 ++#define RACFG_CMD_RX_STOP 0x0014 ++#define RACFG_CMD_GET_NOISE_LEVEL 0x0015 ++ ++#define RACFG_CMD_ATE_START 0x0080 ++#define RACFG_CMD_ATE_STOP 0x0081 ++ ++#define RACFG_CMD_ATE_START_TX_CARRIER 0x0100 ++#define RACFG_CMD_ATE_START_TX_CONT 0x0101 ++#define RACFG_CMD_ATE_START_TX_FRAME 0x0102 ++#define RACFG_CMD_ATE_SET_BW 0x0103 ++#define RACFG_CMD_ATE_SET_TX_POWER0 0x0104 ++#define RACFG_CMD_ATE_SET_TX_POWER1 0x0105 ++#define RACFG_CMD_ATE_SET_FREQ_OFFSET 0x0106 ++#define RACFG_CMD_ATE_GET_STATISTICS 0x0107 ++#define RACFG_CMD_ATE_RESET_COUNTER 0x0108 ++#define RACFG_CMD_ATE_SEL_TX_ANTENNA 0x0109 ++#define RACFG_CMD_ATE_SEL_RX_ANTENNA 0x010a ++#define RACFG_CMD_ATE_SET_PREAMBLE 0x010b ++#define RACFG_CMD_ATE_SET_CHANNEL 0x010c ++#define RACFG_CMD_ATE_SET_ADDR1 0x010d ++#define RACFG_CMD_ATE_SET_ADDR2 0x010e ++#define RACFG_CMD_ATE_SET_ADDR3 0x010f ++#define RACFG_CMD_ATE_SET_RATE 0x0110 ++#define RACFG_CMD_ATE_SET_TX_FRAME_LEN 0x0111 ++#define RACFG_CMD_ATE_SET_TX_FRAME_COUNT 0x0112 ++#define RACFG_CMD_ATE_START_RX_FRAME 0x0113 ++#define RACFG_CMD_ATE_E2PROM_READ_BULK 0x0114 ++#define RACFG_CMD_ATE_E2PROM_WRITE_BULK 0x0115 ++#define RACFG_CMD_ATE_IO_WRITE_BULK 0x0116 ++#define RACFG_CMD_ATE_BBP_READ_BULK 0x0117 ++#define RACFG_CMD_ATE_BBP_WRITE_BULK 0x0118 ++#define RACFG_CMD_ATE_RF_READ_BULK 0x0119 ++#define RACFG_CMD_ATE_RF_WRITE_BULK 0x011a ++ ++ ++ ++#define A2Hex(_X, _p) \ ++{ \ ++ UCHAR *p; \ ++ _X = 0; \ ++ p = _p; \ ++ while (((*p >= 'a') && (*p <= 'f')) || ((*p >= 'A') && (*p <= 'F')) || ((*p >= '0') && (*p <= '9'))) \ ++ { \ ++ if ((*p >= 'a') && (*p <= 'f')) \ ++ _X = _X * 16 + *p - 87; \ ++ else if ((*p >= 'A') && (*p <= 'F')) \ ++ _X = _X * 16 + *p - 55; \ ++ else if ((*p >= '0') && (*p <= '9')) \ ++ _X = _X * 16 + *p - 48; \ ++ p++; \ ++ } \ ++} ++ ++ ++static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); ++static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len); ++static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len); ++ ++#ifdef UCOS ++int ate_copy_to_user( ++ IN PUCHAR payload, ++ IN PUCHAR msg, ++ IN INT len) ++{ ++ memmove(payload, msg, len); ++ return 0; ++} ++ ++#undef copy_to_user ++#define copy_to_user(x,y,z) ate_copy_to_user((PUCHAR)x, (PUCHAR)y, z) ++#endif // UCOS // ++ ++#define LEN_OF_ARG 16 ++ ++VOID RtmpDoAte( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ unsigned short Command_Id; ++ struct ate_racfghdr *pRaCfg; ++ INT Status = NDIS_STATUS_SUCCESS; ++ ++ ++ ++ if((pRaCfg = kmalloc(sizeof(struct ate_racfghdr), GFP_KERNEL)) == NULL) ++ { ++ Status = -EINVAL; ++ return; ++ } ++ ++ NdisZeroMemory(pRaCfg, sizeof(struct ate_racfghdr)); ++ ++ if (copy_from_user((PUCHAR)pRaCfg, wrq->u.data.pointer, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ kfree(pRaCfg); ++ return; ++ } ++ ++ ++ Command_Id = ntohs(pRaCfg->command_id); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id)); ++ ++ switch (Command_Id) ++ { ++ // We will get this command when QA starts. ++ case RACFG_CMD_ATE_START: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START\n")); ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_ATE_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START is done !\n")); ++ } ++ Set_ATE_Proc(pAdapter, "ATESTART"); ++ } ++ break; ++ ++ // We will get this command either QA is closed or ated is killed by user. ++ case RACFG_CMD_ATE_STOP: ++ { ++#ifndef UCOS ++ INT32 ret; ++#endif // !UCOS // ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_STOP\n")); ++ ++ // Distinguish this command came from QA(via ated) ++ // or ate daemon according to the existence of pid in payload. ++ // No need to prepare feedback if this cmd came directly from ate daemon. ++ pRaCfg->length = ntohs(pRaCfg->length); ++ ++ if (pRaCfg->length == sizeof(pAdapter->ate.AtePid)) ++ { ++ // This command came from QA. ++ // Get the pid of ATE daemon. ++ memcpy((UCHAR *)&pAdapter->ate.AtePid, ++ (&pRaCfg->data[0]) - 2/* == &(pRaCfg->status) */, ++ sizeof(pAdapter->ate.AtePid)); ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_STOP\n")); ++ Status = -EFAULT; ++ } ++ ++ // ++ // kill ATE daemon when leaving ATE mode. ++ // We must kill ATE daemon first before setting ATESTOP, ++ // or Microsoft will report sth. wrong. ++#ifndef UCOS ++ ret = kill_proc(pAdapter->ate.AtePid, SIGTERM, 1); ++ if (ret) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("%s: unable to signal thread\n", pAdapter->net_dev->name)); ++ } ++#endif // !UCOS // ++ } ++ ++#ifdef UCOS ++ // Roger add to avoid error message after close QA ++ if (pAdapter->CSRBaseAddress == RT2860_CSR_ADDR) ++ { ++ ++ // prepare feedback as soon as we can to avoid QA timeout. ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_AP_START\n")); ++ Status = -EFAULT; ++ } ++ } ++#endif // UCOS // ++ ++ // AP might have in ATE_STOP mode due to cmd from QA. ++ if (ATE_ON(pAdapter)) ++ { ++ // Someone has killed ate daemon while QA GUI is still open. ++ Set_ATE_Proc(pAdapter, "ATESTOP"); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_AP_START is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RF_WRITE_ALL: ++ { ++ UINT32 R1, R2, R3, R4; ++ USHORT channel; ++ ++ memcpy(&R1, pRaCfg->data-2, 4); ++ memcpy(&R2, pRaCfg->data+2, 4); ++ memcpy(&R3, pRaCfg->data+6, 4); ++ memcpy(&R4, pRaCfg->data+10, 4); ++ memcpy(&channel, pRaCfg->data+14, 2); ++ ++ pAdapter->LatchRfRegs.R1 = ntohl(R1); ++ pAdapter->LatchRfRegs.R2 = ntohl(R2); ++ pAdapter->LatchRfRegs.R3 = ntohl(R3); ++ pAdapter->LatchRfRegs.R4 = ntohl(R4); ++ pAdapter->LatchRfRegs.Channel = ntohs(channel); ++ ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R1); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R2); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R3); ++ RTMP_RF_IO_WRITE32(pAdapter, pAdapter->LatchRfRegs.R4); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RF_WRITE_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RF_WRITE_ALL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_READ16: ++ { ++ USHORT offset, value, tmp; ++ ++ offset = ntohs(pRaCfg->status); ++ /* "tmp" is expecially for some compilers... */ ++ RT28xx_EEPROM_READ16(pAdapter, offset, tmp); ++ value = tmp; ++ value = htons(value); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("EEPROM Read offset = 0x%04x, value = 0x%04x\n", offset, value)); ++ ++ // prepare feedback ++ pRaCfg->length = htons(4); ++ pRaCfg->status = htons(0); ++ memcpy(pRaCfg->data, &value, 2); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("sizeof(struct ate_racfghdr) = %d\n", sizeof(struct ate_racfghdr))); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ16\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ16 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_WRITE16: ++ { ++ USHORT offset, value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&value, pRaCfg->data, 2); ++ value = ntohs(value); ++ RT28xx_EEPROM_WRITE16(pAdapter, offset, value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE16\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_WRITE16 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_READ_ALL: ++ { ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer, EEPROM_SIZE); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+EEPROM_SIZE); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_READ_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_E2PROM_READ_ALL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_E2PROM_WRITE_ALL: ++ { ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ NdisZeroMemory((UCHAR *)buffer, EEPROM_SIZE); ++ memcpy_exs(pAdapter, (UCHAR *)buffer, (UCHAR *)&pRaCfg->status, EEPROM_SIZE); ++ rt_ee_write_all(pAdapter,(USHORT *)buffer); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_E2PROM_WRITE_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_E2PROM_WRITE_ALL is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_IO_READ: ++ { ++ UINT32 offset; ++ UINT32 value; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract the offset out. ++ offset &= 0x0000FFFF; ++ RTMP_IO_READ32(pAdapter, offset, &value); ++ value = htonl(value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(6); ++ pRaCfg->status = htons(0); ++ memcpy(pRaCfg->data, &value, 4); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_IO_WRITE: ++ { ++ UINT32 offset, value; ++ ++ memcpy(&offset, pRaCfg->data-2, 4); ++ memcpy(&value, pRaCfg->data+2, 4); ++ ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract out the offset. ++ offset &= 0x0000FFFF; ++ value = ntohl(value); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_IO_WRITE: offset = %x, value = %x\n", offset, value)); ++ RTMP_IO_WRITE32(pAdapter, offset, value); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_WRITE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_WRITE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_IO_READ_BULK: ++ { ++ UINT32 offset; ++ USHORT len; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ ++ // We do not need the base address. ++ // So just extract the offset. ++ offset &= 0x0000FFFF; ++ memcpy(&len, pRaCfg->data+2, 2); ++ len = ntohs(len); ++ ++ if (len > 371) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("len is too large, make it smaller\n")); ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(1); ++ break; ++ } ++ ++ RTMP_IO_READ_BULK(pAdapter, pRaCfg->data, (UCHAR *)offset, len*4);// unit in four bytes ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len*4);// unit in four bytes ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_IO_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_IO_READ_BULK is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_BBP_READ8: ++ { ++ USHORT offset; ++ UCHAR value; ++ ++ value = 0; ++ offset = ntohs(pRaCfg->status); ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, offset, &value); ++ } ++ // prepare feedback ++ pRaCfg->length = htons(3); ++ pRaCfg->status = htons(0); ++ pRaCfg->data[0] = value; ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("BBP value = %x\n", value)); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ8\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ8 is done !\n")); ++ } ++ } ++ break; ++ case RACFG_CMD_BBP_WRITE8: ++ { ++ USHORT offset; ++ UCHAR value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&value, pRaCfg->data, 1); ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); ++ } ++ else ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, offset, value); ++ } ++ ++ if ((offset == BBP_R1) || (offset == BBP_R3)) ++ { ++ SyncTxRxConfig(pAdapter, offset, value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_WRITE8\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_WRITE8 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_BBP_READ_ALL: ++ { ++ USHORT j; ++ ++ for (j = 0; j < 137; j++) ++ { ++ pRaCfg->data[j] = 0; ++ ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j]); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+137); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_BBP_READ_ALL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_BBP_READ_ALL is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_ATE_E2PROM_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ if (offset + len <= EEPROM_SIZE) ++ memcpy_exs(pAdapter, pRaCfg->data, (UCHAR *)buffer+offset, len); ++ else ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("exceed EEPROM size\n")); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_E2PROM_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_E2PROM_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT buffer[EEPROM_SIZE/2]; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ rt_ee_read_all(pAdapter,(USHORT *)buffer); ++ memcpy_exs(pAdapter, (UCHAR *)buffer + offset, (UCHAR *)pRaCfg->data + 2, len); ++ rt_ee_write_all(pAdapter,(USHORT *)buffer); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_E2PROM_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_E2PROM_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_IO_WRITE_BULK: ++ { ++ UINT32 offset, i, value; ++ USHORT len; ++ ++ memcpy(&offset, &pRaCfg->status, 4); ++ offset = ntohl(offset); ++ memcpy(&len, pRaCfg->data+2, 2); ++ len = ntohs(len); ++ ++ for (i = 0; i < len; i += 4) ++ { ++ memcpy_exl(pAdapter, (UCHAR *)&value, pRaCfg->data+4+i, 4); ++ printk("Write %x %x\n", offset + i, value); ++ RTMP_IO_WRITE32(pAdapter, (offset +i) & 0xffff, value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_IO_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("RACFG_CMD_ATE_IO_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_BBP_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ pRaCfg->data[j - offset] = 0; ++ ++ if (pAdapter->ate.Mode == ATE_STOP) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ else ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_BBP_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ UCHAR *value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ value = pRaCfg->data + 2 + (j - offset); ++ if (pAdapter->ate.Mode == ATE_STOP) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); ++ } ++ else ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, j, *value); ++ } ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_BBP_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_BBP_WRITE_BULK is done !\n")); ++ } ++ } ++ break; ++ ++#ifdef CONFIG_RALINK_RT3052 ++ case RACFG_CMD_ATE_RF_READ_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ pRaCfg->data[j - offset] = 0; ++ RT30xxReadRFRegister(pAdapter, j, &pRaCfg->data[j - offset]); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2+len); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_READ_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_READ_BULK is done !\n")); ++ } ++ ++ } ++ break; ++ ++ case RACFG_CMD_ATE_RF_WRITE_BULK: ++ { ++ USHORT offset; ++ USHORT len; ++ USHORT j; ++ UCHAR *value; ++ ++ offset = ntohs(pRaCfg->status); ++ memcpy(&len, pRaCfg->data, 2); ++ len = ntohs(len); ++ ++ for (j = offset; j < (offset+len); j++) ++ { ++ value = pRaCfg->data + 2 + (j - offset); ++ RT30xxWriteRFRegister(pAdapter, j, *value); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RF_WRITE_BULK\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RF_WRITE_BULK is done !\n")); ++ } ++ ++ } ++ break; ++#endif ++ ++ ++ case RACFG_CMD_GET_NOISE_LEVEL: ++ { ++ UCHAR channel; ++ INT32 buffer[3][10];/* 3 : RxPath ; 10 : no. of per rssi samples */ ++ ++ channel = (ntohs(pRaCfg->status) & 0x00FF); ++ CalNoiseLevel(pAdapter, channel, buffer); ++ memcpy_exl(pAdapter, (UCHAR *)pRaCfg->data, (UCHAR *)&(buffer[0][0]), (sizeof(INT32)*3*10)); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2 + (sizeof(INT32)*3*10)); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_NOISE_LEVEL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_NOISE_LEVEL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_GET_COUNTER: ++ { ++ memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.U2M, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->ate.OtherData, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->ate.Beacon, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->ate.OtherCount, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->ate.TxAc0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->ate.TxAc1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->ate.TxAc2, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->ate.TxAc3, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->ate.TxHCCA, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->ate.TxMgmt, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&pAdapter->ate.RSSI0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&pAdapter->ate.RSSI1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&pAdapter->ate.RSSI2, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[52], (UCHAR *)&pAdapter->ate.SNR0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[56], (UCHAR *)&pAdapter->ate.SNR1, 4); ++ ++ pRaCfg->length = htons(2+60); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_COUNTER is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_CLEAR_COUNTER: ++ { ++ pAdapter->ate.U2M = 0; ++ pAdapter->ate.OtherData = 0; ++ pAdapter->ate.Beacon = 0; ++ pAdapter->ate.OtherCount = 0; ++ pAdapter->ate.TxAc0 = 0; ++ pAdapter->ate.TxAc1 = 0; ++ pAdapter->ate.TxAc2 = 0; ++ pAdapter->ate.TxAc3 = 0; ++ pAdapter->ate.TxHCCA = 0; ++ pAdapter->ate.TxMgmt = 0; ++ pAdapter->ate.TxDoneCount = 0; ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_CLEAR_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_CLEAR_COUNTER is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_TX_START: ++ { ++ USHORT *p; ++ USHORT err = 1; ++ UCHAR Bbp22Value = 0, Bbp24Value = 0; ++ ++ if ((pAdapter->ate.TxStatus != 0) && (pAdapter->ate.Mode & ATE_TXFRAME)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Ate Tx is already running, to run next Tx, you must stop it first\n")); ++ err = 2; ++ goto TX_START_ERROR; ++ } ++ else if ((pAdapter->ate.TxStatus != 0) && !(pAdapter->ate.Mode & ATE_TXFRAME)) ++ { ++ int i = 0; ++ ++ while ((i++ < 10) && (pAdapter->ate.TxStatus != 0)) ++ { ++ RTMPusecDelay(5000); ++ } ++ ++ // force it to stop ++ pAdapter->ate.TxStatus = 0; ++ pAdapter->ate.TxDoneCount = 0; ++ //pAdapter->ate.Repeat = 0; ++ pAdapter->ate.bQATxStart = FALSE; ++ } ++ ++ // If pRaCfg->length == 0, this "RACFG_CMD_TX_START" is for Carrier test or Carrier Suppression. ++ if (ntohs(pRaCfg->length) != 0) ++ { ++ // Get frame info ++#ifdef RT2870 ++ NdisMoveMemory(&pAdapter->ate.TxInfo, pRaCfg->data - 2, 4); ++#ifdef RT_BIG_ENDIAN ++ RTMPDescriptorEndianChange((PUCHAR) &pAdapter->ate.TxInfo, TYPE_TXINFO); ++#endif // RT_BIG_ENDIAN // ++#endif // RT2870 // ++ ++ NdisMoveMemory(&pAdapter->ate.TxWI, pRaCfg->data + 2, 16); ++#ifdef RT_BIG_ENDIAN ++ RTMPWIEndianChange((PUCHAR)&pAdapter->ate.TxWI, TYPE_TXWI); ++#endif // RT_BIG_ENDIAN // ++ ++ NdisMoveMemory(&pAdapter->ate.TxCount, pRaCfg->data + 18, 4); ++ pAdapter->ate.TxCount = ntohl(pAdapter->ate.TxCount); ++ ++ p = (USHORT *)(&pRaCfg->data[22]); ++ //p = pRaCfg->data + 22; ++ // always use QID_AC_BE ++ pAdapter->ate.QID = 0; ++ p = (USHORT *)(&pRaCfg->data[24]); ++ //p = pRaCfg->data + 24; ++ pAdapter->ate.HLen = ntohs(*p); ++ ++ if (pAdapter->ate.HLen > 32) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.HLen > 32\n")); ++ err = 3; ++ goto TX_START_ERROR; ++ } ++ ++ NdisMoveMemory(&pAdapter->ate.Header, pRaCfg->data + 26, pAdapter->ate.HLen); ++ ++ ++ pAdapter->ate.PLen = ntohs(pRaCfg->length) - (pAdapter->ate.HLen + 28); ++ ++ if (pAdapter->ate.PLen > 32) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("pAdapter->ate.PLen > 32\n")); ++ err = 4; ++ goto TX_START_ERROR; ++ } ++ ++ NdisMoveMemory(&pAdapter->ate.Pattern, pRaCfg->data + 26 + pAdapter->ate.HLen, pAdapter->ate.PLen); ++ pAdapter->ate.DLen = pAdapter->ate.TxWI.MPDUtotalByteCount - pAdapter->ate.HLen; ++ } ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R22, &Bbp22Value); ++ ++ switch (Bbp22Value) ++ { ++ case BBP22_TXFRAME: ++ { ++ if (pAdapter->ate.TxCount == 0) ++ { ++ } ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXFRAME"); ++ } ++ break; ++ ++ case BBP22_TXCONT_OR_CARRSUPP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("BBP22_TXCONT_OR_CARRSUPP\n")); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, 24, &Bbp24Value); ++ ++ switch (Bbp24Value) ++ { ++ case BBP24_TXCONT: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCONT\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXCONT"); ++ } ++ break; ++ ++ case BBP24_CARRSUPP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARRSUPP\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ pAdapter->ate.Mode |= ATE_TXCARRSUPP; ++ } ++ break; ++ ++ default: ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); ++ } ++ break; ++ } ++ } ++ break; ++ ++ case BBP22_TXCARR: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("START TXCARR\n")); ++ pAdapter->ate.bQATxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "TXCARR"); ++ } ++ break; ++ ++ default: ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR,("Unknown Start TX subtype !")); ++ } ++ break; ++ } ++ ++ if (pAdapter->ate.bQATxStart == TRUE) ++ { ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() was failed in case RACFG_CMD_TX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_START is done !\n")); ++ } ++ break; ++ } ++ ++TX_START_ERROR: ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(err); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_TX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("feedback of TX_START_ERROR is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_GET_TX_STATUS: ++ { ++ UINT32 count; ++ ++ // prepare feedback ++ pRaCfg->length = htons(6); ++ pRaCfg->status = htons(0); ++ count = htonl(pAdapter->ate.TxDoneCount); ++ NdisMoveMemory(pRaCfg->data, &count, 4); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_GET_TX_STATUS\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_GET_TX_STATUS is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_TX_STOP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_TX_STOP\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXSTOP"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("copy_to_user() fail in case RACFG_CMD_TX_STOP\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_TX_STOP is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RX_START: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); ++ ++ pAdapter->ate.bQARxStart = TRUE; ++ Set_ATE_Proc(pAdapter, "RXFRAME"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_RX_STOP: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_STOP\n")); ++ ++ Set_ATE_Proc(pAdapter, "RXSTOP"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_STOP\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_STOP is done !\n")); ++ } ++ } ++ break; ++ ++ /* The following cases are for new ATE GUI(not QA). */ ++ /*==================================================*/ ++ case RACFG_CMD_ATE_START_TX_CARRIER: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CARRIER\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXCARR"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CARRIER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CARRIER is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_TX_CONT: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_CONT\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXCONT"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_CONT\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_CONT is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_TX_FRAME: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_START_TX_FRAME\n")); ++ ++ Set_ATE_Proc(pAdapter, "TXFRAME"); ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("wrq->u.data.length = %d\n", wrq->u.data.length)); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_START_TX_FRAME\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_START_TX_FRAME is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_BW: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_BW\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ ++ Set_ATE_TX_BW_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_BW\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_BW is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_POWER0: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER0\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_POWER0_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER0\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER0 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_POWER1: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_POWER1\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_POWER1_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_POWER1\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_POWER1 is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_FREQ_OFFSET: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_FREQOFFSET_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_FREQ_OFFSET\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_FREQ_OFFSET is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_GET_STATISTICS: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_GET_STATISTICS\n")); ++ ++ memcpy_exl(pAdapter, &pRaCfg->data[0], (UCHAR *)&pAdapter->ate.TxDoneCount, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[4], (UCHAR *)&pAdapter->WlanCounters.RetryCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[8], (UCHAR *)&pAdapter->WlanCounters.FailedCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[12], (UCHAR *)&pAdapter->WlanCounters.RTSSuccessCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[16], (UCHAR *)&pAdapter->WlanCounters.RTSFailureCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[20], (UCHAR *)&pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[24], (UCHAR *)&pAdapter->WlanCounters.FCSErrorCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[28], (UCHAR *)&pAdapter->Counters8023.RxNoBuffer, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[32], (UCHAR *)&pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[36], (UCHAR *)&pAdapter->RalinkCounters.OneSecFalseCCACnt, 4); ++ ++ if (pAdapter->ate.RxAntennaSel == 0) ++ { ++ INT32 RSSI0 = 0; ++ INT32 RSSI1 = 0; ++ INT32 RSSI2 = 0; ++ ++ RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); ++ RSSI1 = (INT32)(pAdapter->ate.LastRssi1 - pAdapter->BbpRssiToDbmDelta); ++ RSSI2 = (INT32)(pAdapter->ate.LastRssi2 - pAdapter->BbpRssiToDbmDelta); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[44], (UCHAR *)&RSSI1, 4); ++ memcpy_exl(pAdapter, &pRaCfg->data[48], (UCHAR *)&RSSI2, 4); ++ pRaCfg->length = htons(2+52); ++ } ++ else ++ { ++ INT32 RSSI0 = 0; ++ ++ RSSI0 = (INT32)(pAdapter->ate.LastRssi0 - pAdapter->BbpRssiToDbmDelta); ++ memcpy_exl(pAdapter, &pRaCfg->data[40], (UCHAR *)&RSSI0, 4); ++ pRaCfg->length = htons(2+44); ++ } ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_GET_STATISTICS\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_GET_STATISTICS is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_RESET_COUNTER: ++ { ++ SHORT value = 1; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_RESET_COUNTER\n")); ++ ++ sprintf((PCHAR)str, "%d", value); ++ Set_ResetStatCounter_Proc(pAdapter, str); ++ ++ pAdapter->ate.TxDoneCount = 0; ++ ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_RESET_COUNTER\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_RESET_COUNTER is done !\n")); ++ } ++ } ++ ++ break; ++ ++ case RACFG_CMD_ATE_SEL_TX_ANTENNA: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_Antenna_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_TX_ANTENNA\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_TX_ANTENNA is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SEL_RX_ANTENNA: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_RX_Antenna_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SEL_RX_ANTENNA\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SEL_RX_ANTENNA is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_PREAMBLE: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_PREAMBLE\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_MODE_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_PREAMBLE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_PREAMBLE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_CHANNEL: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_CHANNEL\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_CHANNEL_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_CHANNEL\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_CHANNEL is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR1: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR1\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr1, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR1\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR1 is done !\n (ADDR1 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr1[0], ++ pAdapter->ate.Addr1[1], pAdapter->ate.Addr1[2], pAdapter->ate.Addr1[3], pAdapter->ate.Addr1[4], pAdapter->ate.Addr1[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR2: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR2\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr2, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR2\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR2 is done !\n (ADDR2 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr2[0], ++ pAdapter->ate.Addr2[1], pAdapter->ate.Addr2[2], pAdapter->ate.Addr2[3], pAdapter->ate.Addr2[4], pAdapter->ate.Addr2[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_ADDR3: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_ADDR3\n")); ++ ++ // Addr is an array of UCHAR, ++ // so no need to perform endian swap. ++ memcpy(pAdapter->ate.Addr3, (PUCHAR)(pRaCfg->data - 2), MAC_ADDR_LEN); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_ADDR3\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_ADDR3 is done !\n (ADDR3 = %2X:%2X:%2X:%2X:%2X:%2X)\n", pAdapter->ate.Addr3[0], ++ pAdapter->ate.Addr3[1], pAdapter->ate.Addr3[2], pAdapter->ate.Addr3[3], pAdapter->ate.Addr3[4], pAdapter->ate.Addr3[5])); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_RATE: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_RATE\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_MCS_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_RATE\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_RATE is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_FRAME_LEN: ++ { ++ SHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_LENGTH_Proc(pAdapter, str); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_LEN\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_LEN is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_SET_TX_FRAME_COUNT: ++ { ++ USHORT value = 0; ++ UCHAR str[LEN_OF_ARG]; ++ ++ NdisZeroMemory(str, LEN_OF_ARG); ++ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); ++ ++ memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); ++ value = ntohs(value); ++ { ++ sprintf((PCHAR)str, "%d", value); ++ Set_ATE_TX_COUNT_Proc(pAdapter, str); ++ } ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_ATE_SET_TX_FRAME_COUNT\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_ATE_SET_TX_FRAME_COUNT is done !\n")); ++ } ++ } ++ break; ++ ++ case RACFG_CMD_ATE_START_RX_FRAME: ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE,("RACFG_CMD_RX_START\n")); ++ ++ Set_ATE_Proc(pAdapter, "RXFRAME"); ++ ++ // prepare feedback ++ pRaCfg->length = htons(2); ++ pRaCfg->status = htons(0); ++ wrq->u.data.length = sizeof(pRaCfg->magic_no) + sizeof(pRaCfg->command_type) ++ + sizeof(pRaCfg->command_id) + sizeof(pRaCfg->length) ++ + sizeof(pRaCfg->sequence) + ntohs(pRaCfg->length); ++ ++ if (copy_to_user(wrq->u.data.pointer, pRaCfg, wrq->u.data.length)) ++ { ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("copy_to_user() fail in case RACFG_CMD_RX_START\n")); ++ Status = -EFAULT; ++ } ++ else ++ { ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("RACFG_CMD_RX_START is done !\n")); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ ASSERT(pRaCfg != NULL); ++ if (pRaCfg != NULL) ++ { ++ kfree(pRaCfg); ++ } ++ return; ++} ++ ++VOID BubbleSort(INT32 n, INT32 a[]) ++{ ++ INT32 k, j, temp; ++ ++ for (k = n-1; k>0; k--) ++ { ++ for (j = 0; j a[j+1]) ++ { ++ temp = a[j]; ++ a[j]=a[j+1]; ++ a[j+1]=temp; ++ } ++ } ++ } ++} ++ ++VOID CalNoiseLevel(PRTMP_ADAPTER pAd, UCHAR channel, INT32 RSSI[3][10]) ++{ ++ INT32 RSSI0, RSSI1, RSSI2; ++ CHAR Rssi0Offset, Rssi1Offset, Rssi2Offset; ++ UCHAR BbpR50Rssi0 = 0, BbpR51Rssi1 = 0, BbpR52Rssi2 = 0; ++ UCHAR Org_BBP66value = 0, Org_BBP69value = 0, Org_BBP70value = 0, data = 0; ++ USHORT LNA_Gain = 0; ++ INT32 j = 0; ++ UCHAR Org_Channel = pAd->ate.Channel; ++ USHORT GainValue = 0, OffsetValue = 0; ++ ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &Org_BBP66value); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R69, &Org_BBP69value); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R70, &Org_BBP70value); ++ ++ //********************************************************************** ++ // Read the value of LNA gain and Rssi offset ++ //********************************************************************** ++ RT28xx_EEPROM_READ16(pAd, EEPROM_LNA_OFFSET, GainValue); ++ ++ // for Noise Level ++ if (channel <= 14) ++ { ++ LNA_Gain = GainValue & 0x00FF; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_BG_OFFSET, OffsetValue); ++ Rssi0Offset = OffsetValue & 0x00FF; ++ Rssi1Offset = (OffsetValue & 0xFF00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_BG_OFFSET + 2)/* 0x48 */, OffsetValue); ++ Rssi2Offset = OffsetValue & 0x00FF; ++ } ++ else ++ { ++ LNA_Gain = (GainValue & 0xFF00) >> 8; ++ ++ RT28xx_EEPROM_READ16(pAd, EEPROM_RSSI_A_OFFSET, OffsetValue); ++ Rssi0Offset = OffsetValue & 0x00FF; ++ Rssi1Offset = (OffsetValue & 0xFF00) >> 8; ++ RT28xx_EEPROM_READ16(pAd, (EEPROM_RSSI_A_OFFSET + 2)/* 0x4C */, OffsetValue); ++ Rssi2Offset = OffsetValue & 0x00FF; ++ } ++ //********************************************************************** ++ { ++ pAd->ate.Channel = channel; ++ ATEAsicSwitchChannel(pAd); ++ mdelay(5); ++ ++ data = 0x10; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, data); ++ data = 0x40; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, data); ++ data = 0x40; ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, data); ++ mdelay(5); ++ ++ // Start Rx ++ pAd->ate.bQARxStart = TRUE; ++ Set_ATE_Proc(pAd, "RXFRAME"); ++ ++ mdelay(5); ++ ++ for (j = 0; j < 10; j++) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R50, &BbpR50Rssi0); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R51, &BbpR51Rssi1); ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R52, &BbpR52Rssi2); ++ ++ mdelay(10); ++ ++ // Calculate RSSI 0 ++ if (BbpR50Rssi0 == 0) ++ { ++ RSSI0 = -100; ++ } ++ else ++ { ++ RSSI0 = (INT32)(-12 - BbpR50Rssi0 - LNA_Gain - Rssi0Offset); ++ } ++ RSSI[0][j] = RSSI0; ++ ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ // Calculate RSSI 1 ++ if (BbpR51Rssi1 == 0) ++ { ++ RSSI1 = -100; ++ } ++ else ++ { ++ RSSI1 = (INT32)(-12 - BbpR51Rssi1 - LNA_Gain - Rssi1Offset); ++ } ++ RSSI[1][j] = RSSI1; ++ } ++ ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ // Calculate RSSI 2 ++ if (BbpR52Rssi2 == 0) ++ RSSI2 = -100; ++ else ++ RSSI2 = (INT32)(-12 - BbpR52Rssi2 - LNA_Gain - Rssi2Offset); ++ ++ RSSI[2][j] = RSSI2; ++ } ++ } ++ ++ // Stop Rx ++ Set_ATE_Proc(pAd, "RXSTOP"); ++ ++ mdelay(5); ++ ++ BubbleSort(10, RSSI[0]); // 1R ++ ++ if ( pAd->Antenna.field.RxPath >= 2 ) // 2R ++ { ++ BubbleSort(10, RSSI[1]); ++ } ++ ++ if ( pAd->Antenna.field.RxPath >= 3 ) // 3R ++ { ++ BubbleSort(10, RSSI[2]); ++ } ++ ++ } ++ ++ pAd->ate.Channel = Org_Channel; ++ ATEAsicSwitchChannel(pAd); ++ ++ // Restore original value ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, Org_BBP66value); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, Org_BBP69value); ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, Org_BBP70value); ++ ++ return; ++} ++ ++BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value) ++{ ++ UCHAR tmp = 0, bbp_data = 0; ++ ++ if (ATE_ON(pAd)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, offset, &bbp_data); ++ } ++ ++ /* confirm again */ ++ ASSERT(bbp_data == value); ++ ++ switch(offset) ++ { ++ case BBP_R1: ++ /* Need to sync. tx configuration with legacy ATE. */ ++ tmp = (bbp_data & ((1 << 4) | (1 << 3))/* 0x18 */) >> 3; ++ switch(tmp) ++ { ++ /* The BBP R1 bit[4:3] = 2 :: Both DACs will be used by QA. */ ++ case 2: ++ /* All */ ++ pAd->ate.TxAntennaSel = 0; ++ break; ++ /* The BBP R1 bit[4:3] = 0 :: DAC 0 will be used by QA. */ ++ case 0: ++ /* Antenna one */ ++ pAd->ate.TxAntennaSel = 1; ++ break; ++ /* The BBP R1 bit[4:3] = 1 :: DAC 1 will be used by QA. */ ++ case 1: ++ /* Antenna two */ ++ pAd->ate.TxAntennaSel = 2; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ } ++ break;/* case BBP_R1 */ ++ ++ case BBP_R3: ++ /* Need to sync. rx configuration with legacy ATE. */ ++ tmp = (bbp_data & ((1 << 1) | (1 << 0))/* 0x03 */); ++ switch(tmp) ++ { ++ /* The BBP R3 bit[1:0] = 3 :: All ADCs will be used by QA. */ ++ case 3: ++ /* All */ ++ pAd->ate.RxAntennaSel = 0; ++ break; ++ /* The BBP R3 bit[1:0] = 0 :: ADC 0 will be used by QA, */ ++ /* unless the BBP R3 bit[4:3] = 2 */ ++ case 0: ++ /* Antenna one */ ++ pAd->ate.RxAntennaSel = 1; ++ tmp = ((bbp_data & ((1 << 4) | (1 << 3))/* 0x03 */) >> 3); ++ if (tmp == 2)// 3R ++ { ++ /* Default : All ADCs will be used by QA */ ++ pAd->ate.RxAntennaSel = 0; ++ } ++ break; ++ /* The BBP R3 bit[1:0] = 1 :: ADC 1 will be used by QA. */ ++ case 1: ++ /* Antenna two */ ++ pAd->ate.RxAntennaSel = 2; ++ break; ++ /* The BBP R3 bit[1:0] = 2 :: ADC 2 will be used by QA. */ ++ case 2: ++ /* Antenna three */ ++ pAd->ate.RxAntennaSel = 3; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ } ++ break;/* case BBP_R3 */ ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ return FALSE; ++ ++ } ++ return TRUE; ++} ++ ++static VOID memcpy_exl(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) ++{ ++ ULONG i, Value = 0; ++ ULONG *pDst, *pSrc; ++ UCHAR *p8; ++ ++ p8 = src; ++ pDst = (ULONG *) dst; ++ pSrc = (ULONG *) src; ++ ++ for (i = 0 ; i < (len/4); i++) ++ { ++ /* For alignment issue, we need a variable "Value". */ ++ memmove(&Value, pSrc, 4); ++ Value = htonl(Value); ++ memmove(pDst, &Value, 4); ++ pDst++; ++ pSrc++; ++ } ++ if ((len % 4) != 0) ++ { ++ /* wish that it will never reach here */ ++ memmove(&Value, pSrc, (len % 4)); ++ Value = htonl(Value); ++ memmove(pDst, &Value, (len % 4)); ++ } ++} ++ ++static VOID memcpy_exs(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, ULONG len) ++{ ++ ULONG i; ++ UCHAR *pDst, *pSrc; ++ ++ pDst = dst; ++ pSrc = src; ++ ++ for (i = 0; i < (len/2); i++) ++ { ++ memmove(pDst, pSrc, 2); ++ *((USHORT *)pDst) = htons(*((USHORT *)pDst)); ++ pDst+=2; ++ pSrc+=2; ++ } ++ ++ if ((len % 2) != 0) ++ { ++ memmove(pDst, pSrc, 1); ++ } ++} ++ ++static VOID RTMP_IO_READ_BULK(PRTMP_ADAPTER pAd, UCHAR *dst, UCHAR *src, UINT32 len) ++{ ++ UINT32 i, Value; ++ UINT32 *pDst, *pSrc; ++ ++ pDst = (UINT32 *) dst; ++ pSrc = (UINT32 *) src; ++ ++ for (i = 0 ; i < (len/4); i++) ++ { ++ RTMP_IO_READ32(pAd, (ULONG)pSrc, &Value); ++ Value = htonl(Value); ++ memmove(pDst, &Value, 4); ++ pDst++; ++ pSrc++; ++ } ++ return; ++} ++ ++INT Set_TxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Set_TxStop_Proc\n")); ++ ++ if (Set_ATE_Proc(pAd, "TXSTOP")) ++ { ++ return TRUE; ++} ++ else ++ { ++ return FALSE; ++ } ++} ++ ++INT Set_RxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ATEDBGPRINT(RT_DEBUG_TRACE,("Set_RxStop_Proc\n")); ++ ++ if (Set_ATE_Proc(pAd, "RXSTOP")) ++ { ++ return TRUE; ++} ++ else ++ { ++ return FALSE; ++ } ++} ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rt_ate.h +@@ -0,0 +1,294 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __ATE_H__ ++#define __ATE_H__ ++ ++#ifndef UCOS ++#define ate_print printk ++#define ATEDBGPRINT DBGPRINT ++ ++#ifdef RT2870 ++#define EEPROM_SIZE 0x400 ++#ifdef CONFIG_STA_SUPPORT ++#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2870 // ++#else // !UCOS // ++#define fATE_LOAD_EEPROM 0x0C43 ++#ifdef CONFIG_PRINTK ++extern INT ConsoleResponse(IN PUCHAR buff); ++extern int (*remote_display)(char *); ++extern void puts (const char *s); ++ ++/* specificly defined to redirect and show ate-related messages to host. */ ++/* Try to define ate_print as a macro. */ ++#define ate_print(fmt, args...) \ ++do{ int (*org_remote_display)(char *) = NULL; \ ++ org_remote_display = remote_display;\ ++ /* Save original "remote_display" */\ ++ remote_display = (int (*)(char *))ConsoleResponse; \ ++ printk(fmt, ## args); \ ++ /* Restore the remote_display function pointer */ \ ++ remote_display = org_remote_display; }while(0) ++ ++#define ATEDBGPRINT(Level, Fmt) \ ++{ \ ++ if ((Level) <= RTDebugLevel) \ ++ { \ ++ ate_print Fmt; \ ++ } \ ++} ++#endif // CONFIG_PRINTK // ++#endif // !UCOS // ++ ++#define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) ++ ++/* RT2880_iNIC will define "RT2860". */ ++ ++/* RT2880_iNIC will define RT2860. */ ++ ++#ifdef RT2870 ++#define EEPROM_SIZE 0x400 ++#ifdef CONFIG_STA_SUPPORT ++#define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2870STA/e2p.bin" ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT2870 // ++ ++#ifdef RT2870 ++#define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) ++#define ATE_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) ++ ++#define BULK_OUT_LOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_LOCK((pLock), IrqFlags); ++ ++#define BULK_OUT_UNLOCK(pLock, IrqFlags) \ ++ if(1 /*!(in_interrupt() & 0xffff0000)*/) \ ++ RTMP_IRQ_UNLOCK((pLock), IrqFlags); ++ ++// Prototypes of completion funuc. ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++#define ATE_RTUSBBulkOutDataPacketComplete(purb, pt_regs) ATE_RTUSBBulkOutDataPacketComplete(purb) ++#endif ++ ++VOID ATE_RTUSBBulkOutDataPacketComplete( ++ IN purbb_t purb, ++ OUT struct pt_regs *pt_regs); ++ ++VOID ATE_RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId); ++ ++VOID ATE_RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++#ifdef RT30xx ++#define ATE_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) RTMP_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) ++#define ATE_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTMP_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) ++#endif // RT30xx // ++ ++ ++VOID rt_ee_read_all( ++ IN PRTMP_ADAPTER pAd, ++ OUT USHORT *Data); ++ ++ ++VOID rt_ee_write_all( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT *Data); ++ ++INT Set_ATE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_DA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_SA_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_BSSID_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_CHANNEL_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_POWER0_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_POWER1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_RX_Antenna_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_FREQOFFSET_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_BW_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_LENGTH_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_COUNT_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_MCS_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_MODE_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_TX_GI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_ATE_RX_FER_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Read_RF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF1_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF2_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF3_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Write_RF4_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Load_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Read_E2P_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Show_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ATE_Help_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++VOID ATE_QA_Statistics( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC p28xxRxD, ++ IN PHEADER_802_11 pHeader); ++ ++VOID RtmpDoAte( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID BubbleSort( ++ IN INT32 n, ++ IN INT32 a[]); ++ ++VOID CalNoiseLevel( ++ IN PRTMP_ADAPTER pAdapter, ++ IN UCHAR channel, ++ OUT INT32 buffer[3][10]); ++ ++BOOLEAN SyncTxRxConfig( ++ IN PRTMP_ADAPTER pAdapter, ++ IN USHORT offset, ++ IN UCHAR value); ++ ++INT Set_TxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RxStop_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++VOID ATEAsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ATEAsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ATEDisableAsicProtect( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR ATEConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber); ++ ++VOID ATESampleRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN PRXWI_STRUC pRxWI); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPStationStop( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPStationStart( ++ IN PRTMP_ADAPTER pAd); ++#endif // CONFIG_STA_SUPPORT // ++#endif // __ATE_H__ // +--- /dev/null ++++ b/drivers/staging/rt3070/rt_config.h +@@ -0,0 +1,121 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt_config.h ++ ++ Abstract: ++ Central header file to maintain all include files for all NDIS ++ miniport driver routines. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ ++*/ ++#ifndef __RT_CONFIG_H__ ++#define __RT_CONFIG_H__ ++ ++#include "rtmp_type.h" ++#ifdef UCOS ++#include "includes.h" ++#include ++#include "rt_ucos.h" ++#endif ++ ++#ifdef LINUX ++#include "rt_linux.h" ++#endif ++#include "rtmp_def.h" ++#include "rt28xx.h" ++ ++ ++#ifdef RT2870 ++#include "rt2870.h" ++#endif // RT2870 // ++ ++#include "oid.h" ++#include "mlme.h" ++#include "wpa.h" ++#include "md5.h" ++#include "rtmp.h" ++#include "ap.h" ++#include "dfs.h" ++#include "chlist.h" ++#include "spectrum.h" ++#ifdef MLME_EX ++#include "mlme_ex_def.h" ++#include "mlme_ex.h" ++#endif // MLME_EX // ++ ++#undef AP_WSC_INCLUDED ++#undef STA_WSC_INCLUDED ++#undef WSC_INCLUDED ++ ++ ++#ifdef LEAP_SUPPORT ++#include "leap.h" ++#endif // LEAP_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef BLOCK_NET_IF ++#include "netif_block.h" ++#endif // BLOCK_NET_IF // ++ ++#ifdef IGMP_SNOOP_SUPPORT ++#include "igmp_snoop.h" ++#endif // IGMP_SNOOP_SUPPORT // ++ ++#ifdef RALINK_ATE ++#include "rt_ate.h" ++#endif // RALINK_ATE // ++ ++ ++ ++#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) ++#define WSC_INCLUDED ++#endif ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifndef WPA_SUPPLICANT_SUPPORT ++#error "Build for being controlled by NetworkManager or wext, please set HAS_WPA_SUPPLICANT=y and HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y" ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef IKANOS_VX_1X0 ++#include "vr_ikans.h" ++#endif // IKANOS_VX_1X0 // ++ ++#endif // __RT_CONFIG_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rt_linux.c +@@ -0,0 +1,1063 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++ULONG RTDebugLevel = RT_DEBUG_ERROR; ++ ++BUILD_TIMER_FUNCTION(MlmePeriodicExec); ++//BUILD_TIMER_FUNCTION(MlmeRssiReportExec); ++BUILD_TIMER_FUNCTION(AsicRxAntEvalTimeout); ++BUILD_TIMER_FUNCTION(APSDPeriodicExec); ++BUILD_TIMER_FUNCTION(AsicRfTuningExec); ++#ifdef RT2870 ++BUILD_TIMER_FUNCTION(BeaconUpdateExec); ++#endif // RT2870 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++BUILD_TIMER_FUNCTION(BeaconTimeout); ++BUILD_TIMER_FUNCTION(ScanTimeout); ++BUILD_TIMER_FUNCTION(AuthTimeout); ++BUILD_TIMER_FUNCTION(AssocTimeout); ++BUILD_TIMER_FUNCTION(ReassocTimeout); ++BUILD_TIMER_FUNCTION(DisassocTimeout); ++BUILD_TIMER_FUNCTION(LinkDownExec); ++#ifdef LEAP_SUPPORT ++BUILD_TIMER_FUNCTION(LeapAuthTimeout); ++#endif ++BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); ++BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); ++#ifdef QOS_DLS_SUPPORT ++BUILD_TIMER_FUNCTION(DlsTimeoutAction); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++ ++// for wireless system event message ++char const *pWirelessSysEventText[IW_SYS_EVENT_TYPE_NUM] = { ++ // system status event ++ "had associated successfully", /* IW_ASSOC_EVENT_FLAG */ ++ "had disassociated", /* IW_DISASSOC_EVENT_FLAG */ ++ "had deauthenticated", /* IW_DEAUTH_EVENT_FLAG */ ++ "had been aged-out and disassociated", /* IW_AGEOUT_EVENT_FLAG */ ++ "occurred CounterMeasures attack", /* IW_COUNTER_MEASURES_EVENT_FLAG */ ++ "occurred replay counter different in Key Handshaking", /* IW_REPLAY_COUNTER_DIFF_EVENT_FLAG */ ++ "occurred RSNIE different in Key Handshaking", /* IW_RSNIE_DIFF_EVENT_FLAG */ ++ "occurred MIC different in Key Handshaking", /* IW_MIC_DIFF_EVENT_FLAG */ ++ "occurred ICV error in RX", /* IW_ICV_ERROR_EVENT_FLAG */ ++ "occurred MIC error in RX", /* IW_MIC_ERROR_EVENT_FLAG */ ++ "Group Key Handshaking timeout", /* IW_GROUP_HS_TIMEOUT_EVENT_FLAG */ ++ "Pairwise Key Handshaking timeout", /* IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG */ ++ "RSN IE sanity check failure", /* IW_RSNIE_SANITY_FAIL_EVENT_FLAG */ ++ "set key done in WPA/WPAPSK", /* IW_SET_KEY_DONE_WPA1_EVENT_FLAG */ ++ "set key done in WPA2/WPA2PSK", /* IW_SET_KEY_DONE_WPA2_EVENT_FLAG */ ++ "connects with our wireless client", /* IW_STA_LINKUP_EVENT_FLAG */ ++ "disconnects with our wireless client", /* IW_STA_LINKDOWN_EVENT_FLAG */ ++ "scan completed" /* IW_SCAN_COMPLETED_EVENT_FLAG */ ++ "scan terminate!! Busy!! Enqueue fail!!" /* IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG */ ++ }; ++ ++// for wireless IDS_spoof_attack event message ++char const *pWirelessSpoofEventText[IW_SPOOF_EVENT_TYPE_NUM] = { ++ "detected conflict SSID", /* IW_CONFLICT_SSID_EVENT_FLAG */ ++ "detected spoofed association response", /* IW_SPOOF_ASSOC_RESP_EVENT_FLAG */ ++ "detected spoofed reassociation responses", /* IW_SPOOF_REASSOC_RESP_EVENT_FLAG */ ++ "detected spoofed probe response", /* IW_SPOOF_PROBE_RESP_EVENT_FLAG */ ++ "detected spoofed beacon", /* IW_SPOOF_BEACON_EVENT_FLAG */ ++ "detected spoofed disassociation", /* IW_SPOOF_DISASSOC_EVENT_FLAG */ ++ "detected spoofed authentication", /* IW_SPOOF_AUTH_EVENT_FLAG */ ++ "detected spoofed deauthentication", /* IW_SPOOF_DEAUTH_EVENT_FLAG */ ++ "detected spoofed unknown management frame", /* IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG */ ++ "detected replay attack" /* IW_REPLAY_ATTACK_EVENT_FLAG */ ++ }; ++ ++// for wireless IDS_flooding_attack event message ++char const *pWirelessFloodEventText[IW_FLOOD_EVENT_TYPE_NUM] = { ++ "detected authentication flooding", /* IW_FLOOD_AUTH_EVENT_FLAG */ ++ "detected association request flooding", /* IW_FLOOD_ASSOC_REQ_EVENT_FLAG */ ++ "detected reassociation request flooding", /* IW_FLOOD_REASSOC_REQ_EVENT_FLAG */ ++ "detected probe request flooding", /* IW_FLOOD_PROBE_REQ_EVENT_FLAG */ ++ "detected disassociation flooding", /* IW_FLOOD_DISASSOC_EVENT_FLAG */ ++ "detected deauthentication flooding", /* IW_FLOOD_DEAUTH_EVENT_FLAG */ ++ "detected 802.1x eap-request flooding" /* IW_FLOOD_EAP_REQ_EVENT_FLAG */ ++ }; ++ ++ ++/* timeout -- ms */ ++VOID RTMP_SetPeriodicTimer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ timeout = ((timeout*HZ) / 1000); ++ pTimer->expires = jiffies + timeout; ++ add_timer(pTimer); ++} ++ ++/* convert NdisMInitializeTimer --> RTMP_OS_Init_Timer */ ++VOID RTMP_OS_Init_Timer( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN TIMER_FUNCTION function, ++ IN PVOID data) ++{ ++ init_timer(pTimer); ++ pTimer->data = (unsigned long)data; ++ pTimer->function = function; ++} ++ ++ ++VOID RTMP_OS_Add_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ if (timer_pending(pTimer)) ++ return; ++ ++ timeout = ((timeout*HZ) / 1000); ++ pTimer->expires = jiffies + timeout; ++ add_timer(pTimer); ++} ++ ++VOID RTMP_OS_Mod_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout) ++{ ++ timeout = ((timeout*HZ) / 1000); ++ mod_timer(pTimer, jiffies + timeout); ++} ++ ++VOID RTMP_OS_Del_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ OUT BOOLEAN *pCancelled) ++{ ++ if (timer_pending(pTimer)) ++ { ++ *pCancelled = del_timer_sync(pTimer); ++ } ++ else ++ { ++ *pCancelled = TRUE; ++ } ++ ++} ++ ++VOID RTMP_OS_Release_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_ENTRY pEntry) ++{ ++ //RTMPFreeNdisPacket(pAd, (struct sk_buff *)pEntry); ++} ++ ++// Unify all delay routine by using udelay ++VOID RTMPusecDelay( ++ IN ULONG usec) ++{ ++ ULONG i; ++ ++ for (i = 0; i < (usec / 50); i++) ++ udelay(50); ++ ++ if (usec % 50) ++ udelay(usec % 50); ++} ++ ++void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time) ++{ ++ time->u.LowPart = jiffies; ++} ++ ++// pAd MUST allow to be NULL ++NDIS_STATUS os_alloc_mem( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR *mem, ++ IN ULONG size) ++{ ++ *mem = (PUCHAR) kmalloc(size, GFP_ATOMIC); ++ if (*mem) ++ return (NDIS_STATUS_SUCCESS); ++ else ++ return (NDIS_STATUS_FAILURE); ++} ++ ++// pAd MUST allow to be NULL ++NDIS_STATUS os_free_mem( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mem) ++{ ++ ++ ASSERT(mem); ++ kfree(mem); ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++ ++PNDIS_PACKET RTMP_AllocateFragPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length) ++{ ++ struct sk_buff *pkt; ++ ++ pkt = dev_alloc_skb(Length); ++ ++ if (pkt == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate frag rx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) ++ { ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++PNDIS_PACKET RTMP_AllocateTxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress) ++{ ++ struct sk_buff *pkt; ++ ++ pkt = dev_alloc_skb(Length); ++ ++ if (pkt == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("can't allocate tx %ld size packet\n",Length)); ++ } ++ ++ if (pkt) ++ { ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ *VirtualAddress = (PVOID) pkt->data; ++ } ++ else ++ { ++ *VirtualAddress = (PVOID) NULL; ++ } ++ ++ return (PNDIS_PACKET) pkt; ++} ++ ++ ++VOID build_tx_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pFrame, ++ IN ULONG FrameLen) ++{ ++ ++ struct sk_buff *pTxPkt; ++ ++ ASSERT(pPacket); ++ pTxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ NdisMoveMemory(skb_put(pTxPkt, FrameLen), pFrame, FrameLen); ++} ++ ++VOID RTMPFreeAdapter( ++ IN PRTMP_ADAPTER pAd) ++{ ++ POS_COOKIE os_cookie; ++ int index; ++ ++ os_cookie=(POS_COOKIE)pAd->OS_Cookie; ++ ++ kfree(pAd->BeaconBuf); ++ ++ ++ NdisFreeSpinLock(&pAd->MgmtRingLock); ++ ++ ++ for (index =0 ; index < NUM_OF_TX_RING; index++) ++ { ++ NdisFreeSpinLock(&pAd->TxSwQueueLock[index]); ++ NdisFreeSpinLock(&pAd->DeQueueLock[index]); ++ pAd->DeQueueRunning[index] = FALSE; ++ } ++ ++ NdisFreeSpinLock(&pAd->irq_lock); ++ ++ ++ vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); ++ kfree(os_cookie); ++} ++ ++BOOLEAN OS_Need_Clone_Packet(void) ++{ ++ return (FALSE); ++} ++ ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ clone an input NDIS PACKET to another one. The new internally created NDIS PACKET ++ must have only one NDIS BUFFER ++ return - byte copied. 0 means can't create NDIS PACKET ++ NOTE: internally created NDIS_PACKET should be destroyed by RTMPFreeNdisPacket ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU. ++ *pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet. ++ ++ Return Value: ++ NDIS_STATUS_SUCCESS ++ NDIS_STATUS_FAILURE ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS RTMPCloneNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN pInsAMSDUHdr, ++ IN PNDIS_PACKET pInPacket, ++ OUT PNDIS_PACKET *ppOutPacket) ++{ ++ ++ struct sk_buff *pkt; ++ ++ ASSERT(pInPacket); ++ ASSERT(ppOutPacket); ++ ++ // 1. Allocate a packet ++ pkt = dev_alloc_skb(2048); ++ ++ if (pkt == NULL) ++ { ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ skb_put(pkt, GET_OS_PKT_LEN(pInPacket)); ++ NdisMoveMemory(pkt->data, GET_OS_PKT_DATAPTR(pInPacket), GET_OS_PKT_LEN(pInPacket)); ++ *ppOutPacket = OSPKT_TO_RTPKT(pkt); ++ ++ ++ RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); ++ ++ printk("###Clone###\n"); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++// the allocated NDIS PACKET must be freed via RTMPFreeNdisPacket() ++NDIS_STATUS RTMPAllocateNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ OUT PNDIS_PACKET *ppPacket, ++ IN PUCHAR pHeader, ++ IN UINT HeaderLen, ++ IN PUCHAR pData, ++ IN UINT DataLen) ++{ ++ PNDIS_PACKET pPacket; ++ ASSERT(pData); ++ ASSERT(DataLen); ++ ++ // 1. Allocate a packet ++ pPacket = (PNDIS_PACKET *) dev_alloc_skb(HeaderLen + DataLen + TXPADDING_SIZE); ++ if (pPacket == NULL) ++ { ++ *ppPacket = NULL; ++#ifdef DEBUG ++ printk("RTMPAllocateNdisPacket Fail\n\n"); ++#endif ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ // 2. clone the frame content ++ if (HeaderLen > 0) ++ NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket), pHeader, HeaderLen); ++ if (DataLen > 0) ++ NdisMoveMemory(GET_OS_PKT_DATAPTR(pPacket) + HeaderLen, pData, DataLen); ++ ++ // 3. update length of packet ++ skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen); ++ ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket)); ++ *ppPacket = pPacket; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* ++ ======================================================================== ++ Description: ++ This routine frees a miniport internally allocated NDIS_PACKET and its ++ corresponding NDIS_BUFFER and allocated memory. ++ ======================================================================== ++*/ ++VOID RTMPFreeNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ dev_kfree_skb_any(RTPKT_TO_OSPKT(pPacket)); ++} ++ ++ ++// IRQL = DISPATCH_LEVEL ++// NOTE: we do have an assumption here, that Byte0 and Byte1 always reasid at the same ++// scatter gather buffer ++NDIS_STATUS Sniff2BytesFromNdisBuffer( ++ IN PNDIS_BUFFER pFirstBuffer, ++ IN UCHAR DesiredOffset, ++ OUT PUCHAR pByte0, ++ OUT PUCHAR pByte1) ++{ ++ *pByte0 = *(PUCHAR)(pFirstBuffer + DesiredOffset); ++ *pByte1 = *(PUCHAR)(pFirstBuffer + DesiredOffset + 1); ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++void RTMP_QueryPacketInfo( ++ IN PNDIS_PACKET pPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen) ++{ ++ pPacketInfo->BufferCount = 1; ++ pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); ++ pPacketInfo->PhysicalBufferCount = 1; ++ pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); ++ ++ *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ *pSrcBufLen = GET_OS_PKT_LEN(pPacket); ++} ++ ++void RTMP_QueryNextPacketInfo( ++ IN PNDIS_PACKET *ppPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen) ++{ ++ PNDIS_PACKET pPacket = NULL; ++ ++ if (*ppPacket) ++ pPacket = GET_OS_PKT_NEXT(*ppPacket); ++ ++ if (pPacket) ++ { ++ pPacketInfo->BufferCount = 1; ++ pPacketInfo->pFirstBuffer = GET_OS_PKT_DATAPTR(pPacket); ++ pPacketInfo->PhysicalBufferCount = 1; ++ pPacketInfo->TotalPacketLength = GET_OS_PKT_LEN(pPacket); ++ ++ *pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ *pSrcBufLen = GET_OS_PKT_LEN(pPacket); ++ *ppPacket = GET_OS_PKT_NEXT(pPacket); ++ } ++ else ++ { ++ pPacketInfo->BufferCount = 0; ++ pPacketInfo->pFirstBuffer = NULL; ++ pPacketInfo->PhysicalBufferCount = 0; ++ pPacketInfo->TotalPacketLength = 0; ++ ++ *pSrcBufVA = NULL; ++ *pSrcBufLen = 0; ++ *ppPacket = NULL; ++ } ++} ++ ++// not yet support MBSS ++PNET_DEV get_netdev_from_bssid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR FromWhichBSSID) ++{ ++ PNET_DEV dev_p = NULL; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ dev_p = pAd->net_dev; ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ASSERT(dev_p); ++ return dev_p; /* return one of MBSS */ ++} ++ ++PNDIS_PACKET DuplicatePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *skb; ++ PNDIS_PACKET pRetPacket = NULL; ++ USHORT DataSize; ++ UCHAR *pData; ++ ++ DataSize = (USHORT) GET_OS_PKT_LEN(pPacket); ++ pData = (PUCHAR) GET_OS_PKT_DATAPTR(pPacket); ++ ++ ++ skb = skb_clone(RTPKT_TO_OSPKT(pPacket), MEM_ALLOC_FLAG); ++ if (skb) ++ { ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pRetPacket = OSPKT_TO_RTPKT(skb); ++ } ++ ++ return pRetPacket; ++ ++} ++ ++PNDIS_PACKET duplicate_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *skb; ++ PNDIS_PACKET pPacket = NULL; ++ ++ ++ if ((skb = __dev_alloc_skb(HdrLen + DataSize + 2, MEM_ALLOC_FLAG)) != NULL) ++ { ++ skb_reserve(skb, 2); ++ NdisMoveMemory(skb->tail, pHeader802_3, HdrLen); ++ skb_put(skb, HdrLen); ++ NdisMoveMemory(skb->tail, pData, DataSize); ++ skb_put(skb, DataSize); ++ skb->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pPacket = OSPKT_TO_RTPKT(skb); ++ } ++ ++ return pPacket; ++} ++ ++ ++#define TKIP_TX_MIC_SIZE 8 ++PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ struct sk_buff *skb, *newskb; ++ ++ ++ skb = RTPKT_TO_OSPKT(pPacket); ++ if (skb_tailroom(skb) < TKIP_TX_MIC_SIZE) ++ { ++ // alloc a new skb and copy the packet ++ newskb = skb_copy_expand(skb, skb_headroom(skb), TKIP_TX_MIC_SIZE, GFP_ATOMIC); ++ dev_kfree_skb_any(skb); ++ if (newskb == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Extend Tx.MIC for packet failed!, dropping packet!\n")); ++ return NULL; ++ } ++ skb = newskb; ++ } ++ ++ return OSPKT_TO_RTPKT(skb); ++} ++ ++ ++ ++ ++PNDIS_PACKET ClonePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize) ++{ ++ struct sk_buff *pRxPkt; ++ struct sk_buff *pClonedPkt; ++ ++ ASSERT(pPacket); ++ pRxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++ // clone the packet ++ pClonedPkt = skb_clone(pRxPkt, MEM_ALLOC_FLAG); ++ ++ if (pClonedPkt) ++ { ++ // set the correct dataptr and data len ++ pClonedPkt->dev = pRxPkt->dev; ++ pClonedPkt->data = pData; ++ pClonedPkt->len = DataSize; ++ pClonedPkt->tail = pClonedPkt->data + pClonedPkt->len; ++ ASSERT(DataSize < 1530); ++ } ++ return pClonedPkt; ++} ++ ++// ++// change OS packet DataPtr and DataLen ++// ++void update_os_packet_info( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *pOSPkt; ++ ++ ASSERT(pRxBlk->pRxPacket); ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pOSPkt->data = pRxBlk->pData; ++ pOSPkt->len = pRxBlk->DataSize; ++ pOSPkt->tail = pOSPkt->data + pOSPkt->len; ++} ++ ++ ++void wlan_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN PUCHAR pHeader802_3, ++ IN UCHAR FromWhichBSSID) ++{ ++ struct sk_buff *pOSPkt; ++ ++ ASSERT(pRxBlk->pRxPacket); ++ ASSERT(pHeader802_3); ++ ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ ++ pOSPkt->dev = get_netdev_from_bssid(pAd, FromWhichBSSID); ++ pOSPkt->data = pRxBlk->pData; ++ pOSPkt->len = pRxBlk->DataSize; ++ pOSPkt->tail = pOSPkt->data + pOSPkt->len; ++ ++ // ++ // copy 802.3 header ++ // ++ // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(skb_push(pOSPkt, LENGTH_802_3), pHeader802_3, LENGTH_802_3); ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ ++void announce_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ ++ struct sk_buff *pRxPkt; ++ ++ ASSERT(pPacket); ++ ++ pRxPkt = RTPKT_TO_OSPKT(pPacket); ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ /* Push up the protocol stack */ ++#ifdef IKANOS_VX_1X0 ++ IKANOS_DataFrameRx(pAd, pRxPkt->dev, pRxPkt, pRxPkt->len); ++#else ++ pRxPkt->protocol = eth_type_trans(pRxPkt, pRxPkt->dev); ++ ++//#ifdef CONFIG_5VT_ENHANCE ++// *(int*)(pRxPkt->cb) = BRIDGE_TAG; ++//#endif ++ netif_rx(pRxPkt); ++#endif // IKANOS_VX_1X0 // ++} ++ ++ ++PRTMP_SCATTER_GATHER_LIST ++rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg) ++{ ++ sg->NumberOfElements = 1; ++ sg->Elements[0].Address = GET_OS_PKT_DATAPTR(pPacket); ++ sg->Elements[0].Length = GET_OS_PKT_LEN(pPacket); ++ return (sg); ++} ++ ++void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen) ++{ ++ unsigned char *pt; ++ int x; ++ ++ if (RTDebugLevel < RT_DEBUG_TRACE) ++ return; ++ ++ pt = pSrcBufVA; ++ printk("%s: %p, len = %d\n",str, pSrcBufVA, SrcBufLen); ++ for (x=0; x= 15 ++ ++ union iwreq_data wrqu; ++ PUCHAR pBuf = NULL, pBufPtr = NULL; ++ USHORT event, type, BufLen; ++ UCHAR event_table_len = 0; ++ ++ type = Event_flag & 0xFF00; ++ event = Event_flag & 0x00FF; ++ ++ switch (type) ++ { ++ case IW_SYS_EVENT_FLAG_START: ++ event_table_len = IW_SYS_EVENT_TYPE_NUM; ++ break; ++ ++ case IW_SPOOF_EVENT_FLAG_START: ++ event_table_len = IW_SPOOF_EVENT_TYPE_NUM; ++ break; ++ ++ case IW_FLOOD_EVENT_FLAG_START: ++ event_table_len = IW_FLOOD_EVENT_TYPE_NUM; ++ break; ++ } ++ ++ if (event_table_len == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type)); ++ return; ++ } ++ ++ if (event >= event_table_len) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event)); ++ return; ++ } ++ ++ //Allocate memory and copy the msg. ++ if((pBuf = kmalloc(IW_CUSTOM_MAX_LEN, GFP_ATOMIC)) != NULL) ++ { ++ //Prepare the payload ++ memset(pBuf, 0, IW_CUSTOM_MAX_LEN); ++ ++ pBufPtr = pBuf; ++ ++ if (pAddr) ++ pBufPtr += sprintf(pBufPtr, "(RT2860) STA(%02x:%02x:%02x:%02x:%02x:%02x) ", PRINT_MAC(pAddr)); ++ else if (BssIdx < MAX_MBSSID_NUM) ++ pBufPtr += sprintf(pBufPtr, "(RT2860) BSS(ra%d) ", BssIdx); ++ else ++ pBufPtr += sprintf(pBufPtr, "(RT2860) "); ++ ++ if (type == IW_SYS_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s", pWirelessSysEventText[event]); ++ else if (type == IW_SPOOF_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s (RSSI=%d)", pWirelessSpoofEventText[event], Rssi); ++ else if (type == IW_FLOOD_EVENT_FLAG_START) ++ pBufPtr += sprintf(pBufPtr, "%s", pWirelessFloodEventText[event]); ++ else ++ pBufPtr += sprintf(pBufPtr, "%s", "unknown event"); ++ ++ pBufPtr[pBufPtr - pBuf] = '\0'; ++ BufLen = pBufPtr - pBuf; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = Event_flag; ++ wrqu.data.length = BufLen; ++ ++ //send wireless event ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf); ++ ++ //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf)); ++ ++ kfree(pBuf); ++ } ++ else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__)); ++#else ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__)); ++#endif /* WIRELESS_EXT >= 15 */ ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++void send_monitor_packets( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ struct sk_buff *pOSPkt; ++ wlan_ng_prism2_header *ph; ++ int rate_index = 0; ++ USHORT header_len = 0; ++ UCHAR temp_header[40] = {0}; ++ ++ u_int32_t ralinkrate[256] = {2,4,11,22, 12,18,24,36,48,72,96, 108, 109, 110, 111, 112, 13, 26, 39, 52,78,104, 117, 130, 26, 52, 78,104, 156, 208, 234, 260, 27, 54,81,108,162, 216, 243, 270, // Last 38 ++ 54, 108, 162, 216, 324, 432, 486, 540, 14, 29, 43, 57, 87, 115, 130, 144, 29, 59,87,115, 173, 230,260, 288, 30, 60,90,120,180,240,270,300,60,120,180,240,360,480,540,600, 0,1,2,3,4,5,6,7,8,9,10, ++ 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80}; ++ ++ ++ ASSERT(pRxBlk->pRxPacket); ++ if (pRxBlk->DataSize < 10) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize)); ++ goto err_free_sk_buff; ++ } ++ ++ if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); ++ goto err_free_sk_buff; ++ } ++ ++ pOSPkt = RTPKT_TO_OSPKT(pRxBlk->pRxPacket); ++ pOSPkt->dev = get_netdev_from_bssid(pAd, BSS0); ++ if (pRxBlk->pHeader->FC.Type == BTYPE_DATA) ++ { ++ pRxBlk->DataSize -= LENGTH_802_11; ++ if ((pRxBlk->pHeader->FC.ToDs == 1) && ++ (pRxBlk->pHeader->FC.FrDs == 1)) ++ header_len = LENGTH_802_11_WITH_ADDR4; ++ else ++ header_len = LENGTH_802_11; ++ ++ // QOS ++ if (pRxBlk->pHeader->FC.SubType & 0x08) ++ { ++ header_len += 2; ++ // Data skip QOS contorl field ++ pRxBlk->DataSize -=2; ++ } ++ ++ // Order bit: A-Ralink or HTC+ ++ if (pRxBlk->pHeader->FC.Order) ++ { ++ header_len += 4; ++ // Data skip HTC contorl field ++ pRxBlk->DataSize -= 4; ++ } ++ ++ // Copy Header ++ if (header_len <= 40) ++ NdisMoveMemory(temp_header, pRxBlk->pData, header_len); ++ ++ // skip HW padding ++ if (pRxBlk->RxD.L2PAD) ++ pRxBlk->pData += (header_len + 2); ++ else ++ pRxBlk->pData += header_len; ++ } //end if ++ ++ ++ if (pRxBlk->DataSize < pOSPkt->len) { ++ skb_trim(pOSPkt,pRxBlk->DataSize); ++ } else { ++ skb_put(pOSPkt,(pRxBlk->DataSize - pOSPkt->len)); ++ } //end if ++ ++ if ((pRxBlk->pData - pOSPkt->data) > 0) { ++ skb_put(pOSPkt,(pRxBlk->pData - pOSPkt->data)); ++ skb_pull(pOSPkt,(pRxBlk->pData - pOSPkt->data)); ++ } //end if ++ ++ if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) { ++ if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__)); ++ goto err_free_sk_buff; ++ } //end if ++ } //end if ++ ++ if (header_len > 0) ++ NdisMoveMemory(skb_push(pOSPkt, header_len), temp_header, header_len); ++ ++ ph = (wlan_ng_prism2_header *) skb_push(pOSPkt, sizeof(wlan_ng_prism2_header)); ++ NdisZeroMemory(ph, sizeof(wlan_ng_prism2_header)); ++ ++ ph->msgcode = DIDmsg_lnxind_wlansniffrm; ++ ph->msglen = sizeof(wlan_ng_prism2_header); ++ strcpy(ph->devname, pAd->net_dev->name); ++ ++ ph->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; ++ ph->hosttime.status = 0; ++ ph->hosttime.len = 4; ++ ph->hosttime.data = jiffies; ++ ++ ph->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; ++ ph->mactime.status = 0; ++ ph->mactime.len = 0; ++ ph->mactime.data = 0; ++ ++ ph->istx.did = DIDmsg_lnxind_wlansniffrm_istx; ++ ph->istx.status = 0; ++ ph->istx.len = 0; ++ ph->istx.data = 0; ++ ++ ph->channel.did = DIDmsg_lnxind_wlansniffrm_channel; ++ ph->channel.status = 0; ++ ph->channel.len = 4; ++ ++ ph->channel.data = (u_int32_t)pAd->CommonCfg.Channel; ++ ++ ph->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; ++ ph->rssi.status = 0; ++ ph->rssi.len = 4; ++ ph->rssi.data = (u_int32_t)RTMPMaxRssi(pAd, ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI0, RSSI_0), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI1, RSSI_1), ConvertToRssi(pAd, pRxBlk->pRxWI->RSSI2, RSSI_2));; ++ ++ ph->signal.did = DIDmsg_lnxind_wlansniffrm_signal; ++ ph->signal.status = 0; ++ ph->signal.len = 4; ++ ph->signal.data = 0; //rssi + noise; ++ ++ ph->noise.did = DIDmsg_lnxind_wlansniffrm_noise; ++ ph->noise.status = 0; ++ ph->noise.len = 4; ++ ph->noise.data = 0; ++ ++#ifdef DOT11_N_SUPPORT ++ if (pRxBlk->pRxWI->PHYMODE >= MODE_HTMIX) ++ { ++ rate_index = 16 + ((UCHAR)pRxBlk->pRxWI->BW *16) + ((UCHAR)pRxBlk->pRxWI->ShortGI *32) + ((UCHAR)pRxBlk->pRxWI->MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pRxBlk->pRxWI->PHYMODE == MODE_OFDM) ++ rate_index = (UCHAR)(pRxBlk->pRxWI->MCS) + 4; ++ else ++ rate_index = (UCHAR)(pRxBlk->pRxWI->MCS); ++ if (rate_index < 0) ++ rate_index = 0; ++ if (rate_index > 255) ++ rate_index = 255; ++ ++ ph->rate.did = DIDmsg_lnxind_wlansniffrm_rate; ++ ph->rate.status = 0; ++ ph->rate.len = 4; ++ ph->rate.data = ralinkrate[rate_index]; ++ ++ ph->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; ++ ph->frmlen.status = 0; ++ ph->frmlen.len = 4; ++ ph->frmlen.data = (u_int32_t)pRxBlk->DataSize; ++ ++ ++ pOSPkt->pkt_type = PACKET_OTHERHOST; ++ pOSPkt->protocol = eth_type_trans(pOSPkt, pOSPkt->dev); ++ pOSPkt->ip_summed = CHECKSUM_NONE; ++ netif_rx(pOSPkt); ++ ++ return; ++ ++err_free_sk_buff: ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) ++{ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ daemonize(pThreadName /*"%s",pAd->net_dev->name*/); ++ ++ allow_signal(SIGTERM); ++ allow_signal(SIGKILL); ++ current->flags |= PF_NOFREEZE; ++#else ++ unsigned long flags; ++ ++ daemonize(); ++ reparent_to_init(); ++ strcpy(current->comm, pThreadName); ++ ++ siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); ++ ++ /* Allow interception of SIGKILL only ++ * Don't allow other signals to interrupt the transmission */ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) ++ spin_lock_irqsave(¤t->sigmask_lock, flags); ++ flush_signals(current); ++ recalc_sigpending(current); ++ spin_unlock_irqrestore(¤t->sigmask_lock, flags); ++#endif ++#endif ++ ++ /* signal that we've started the thread */ ++ complete(pNotify); ++ ++} ++ ++void RTMP_IndicateMediaState( ++ IN PRTMP_ADAPTER pAd) ++{ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ else ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rt_linux.h +@@ -0,0 +1,887 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++/***********************************************************************/ ++/* */ ++/* Program: rt_linux.c */ ++/* Created: 4/21/2006 1:17:38 PM */ ++/* Author: Wu Xi-Kun */ ++/* Comments: `description` */ ++/* */ ++/*---------------------------------------------------------------------*/ ++/* */ ++/* History: */ ++/* Revision 1.1 4/21/2006 1:17:38 PM xsikun */ ++/* Initial revision */ ++/* */ ++/***********************************************************************/ ++ ++#include "rtmp_type.h" ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++ ++// load firmware ++#define __KERNEL_SYSCALLS__ ++#include ++#include ++ ++ ++#define MEM_ALLOC_FLAG (GFP_ATOMIC) //(GFP_DMA | GFP_ATOMIC) ++ ++#ifndef IFNAMSIZ ++#define IFNAMSIZ 16 ++#endif ++ ++//#define CONFIG_CKIP_SUPPORT ++ ++#undef __inline ++#define __inline static inline ++ ++typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_dev); ++ ++// add by kathy ++ ++#ifdef CONFIG_STA_SUPPORT ++ ++#ifdef RT2870 ++#define STA_PROFILE_PATH "/etc/Wireless/RT2870STA/RT2870STA.dat" ++#define STA_RT2870_IMAGE_FILE_NAME "/etc/Wireless/RT2870STA/rt2870.bin" ++#define STA_NIC_DEVICE_NAME "RT2870STA" ++#define STA_DRIVER_VERSION "2.0.1.0" ++#ifdef MULTIPLE_CARD_SUPPORT ++#define CARD_INFO_PATH "/etc/Wireless/RT2870STA/RT2870STACard.dat" ++#endif // MULTIPLE_CARD_SUPPORT // ++#endif // RT2870 // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ ++#define RTMP_TIME_AFTER(a,b) \ ++ (typecheck(unsigned long, (unsigned long)a) && \ ++ typecheck(unsigned long, (unsigned long)b) && \ ++ ((long)(b) - (long)(a) < 0)) ++ ++#define RTMP_TIME_AFTER_EQ(a,b) \ ++ (typecheck(unsigned long, (unsigned long)a) && \ ++ typecheck(unsigned long, (unsigned long)b) && \ ++ ((long)(a) - (long)(b) >= 0)) ++#define RTMP_TIME_BEFORE(a,b) RTMP_TIME_AFTER_EQ(b,a) ++#else ++#define RTMP_TIME_AFTER(a,b) time_after(a, b) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#define RT_MOD_INC_USE_COUNT() \ ++ if (!try_module_get(THIS_MODULE)) \ ++ { \ ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \ ++ return -1; \ ++ } ++ ++#define RT_MOD_DEC_USE_COUNT() module_put(THIS_MODULE); ++#else ++#define RT_MOD_INC_USE_COUNT() MOD_INC_USE_COUNT; ++#define RT_MOD_DEC_USE_COUNT() MOD_DEC_USE_COUNT; ++#endif ++ ++#define OS_HZ HZ ++ ++#define ETH_LENGTH_OF_ADDRESS 6 ++ ++#define IN ++#define OUT ++ ++#define NDIS_STATUS INT ++#define NDIS_STATUS_SUCCESS 0x00 ++#define NDIS_STATUS_FAILURE 0x01 ++#define NDIS_STATUS_INVALID_DATA 0x02 ++#define NDIS_STATUS_RESOURCES 0x03 ++ ++#define MIN_NET_DEVICE_FOR_AID 0x00 //0x00~0x3f ++#define MIN_NET_DEVICE_FOR_MBSSID 0x00 //0x00,0x10,0x20,0x30 ++#define MIN_NET_DEVICE_FOR_WDS 0x10 //0x40,0x50,0x60,0x70 ++#define MIN_NET_DEVICE_FOR_APCLI 0x20 ++#define MIN_NET_DEVICE_FOR_MESH 0x30 ++#ifdef CONFIG_STA_SUPPORT ++#define MIN_NET_DEVICE_FOR_DLS 0x40 ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define NDIS_PACKET_TYPE_DIRECTED 0 ++#define NDIS_PACKET_TYPE_MULTICAST 1 ++#define NDIS_PACKET_TYPE_BROADCAST 2 ++#define NDIS_PACKET_TYPE_ALL_MULTICAST 3 ++#endif // CONFIG_STA_SUPPORT // ++ ++struct os_lock { ++ spinlock_t lock; ++ unsigned long flags; ++}; ++ ++ ++struct os_cookie { ++ ++#ifdef RT2870 ++ struct usb_device *pUsb_Dev; ++ ++ struct pid * MLMEThr_pid; ++ struct pid * RTUSBCmdThr_pid; ++ struct pid * TimerQThr_pid; ++#endif // RT2870 // ++ ++ struct tasklet_struct rx_done_task; ++ struct tasklet_struct mgmt_dma_done_task; ++ struct tasklet_struct ac0_dma_done_task; ++ struct tasklet_struct ac1_dma_done_task; ++ struct tasklet_struct ac2_dma_done_task; ++ struct tasklet_struct ac3_dma_done_task; ++ struct tasklet_struct hcca_dma_done_task; ++ struct tasklet_struct tbtt_task; ++#ifdef RT2870 ++ struct tasklet_struct null_frame_complete_task; ++ struct tasklet_struct rts_frame_complete_task; ++ struct tasklet_struct pspoll_frame_complete_task; ++#endif // RT2870 // ++ ++ ++ unsigned long apd_pid; //802.1x daemon pid ++ INT ioctl_if_type; ++ INT ioctl_if; ++}; ++ ++typedef struct _VIRTUAL_ADAPTER ++{ ++ struct net_device *RtmpDev; ++ struct net_device *VirtualDev; ++} VIRTUAL_ADAPTER, PVIRTUAL_ADAPTER; ++ ++#undef ASSERT ++#define ASSERT(x) \ ++{ \ ++ if (!(x)) \ ++ { \ ++ printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__); \ ++ } \ ++} ++ ++typedef struct os_cookie * POS_COOKIE; ++typedef struct pci_dev * PPCI_DEV; ++typedef struct net_device * PNET_DEV; ++typedef void * PNDIS_PACKET; ++typedef char NDIS_PACKET; ++typedef PNDIS_PACKET * PPNDIS_PACKET; ++typedef dma_addr_t NDIS_PHYSICAL_ADDRESS; ++typedef dma_addr_t * PNDIS_PHYSICAL_ADDRESS; ++//typedef struct timer_list RALINK_TIMER_STRUCT; ++//typedef struct timer_list * PRALINK_TIMER_STRUCT; ++//typedef struct os_lock NDIS_SPIN_LOCK; ++typedef spinlock_t NDIS_SPIN_LOCK; ++typedef struct timer_list NDIS_MINIPORT_TIMER; ++typedef void * NDIS_HANDLE; ++typedef char * PNDIS_BUFFER; ++ ++ ++ ++void hex_dump(char *str, unsigned char *pSrcBufVA, unsigned int SrcBufLen); ++ ++dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, int sd_idx, int direction); ++void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, int direction); ++ ++ ++//////////////////////////////////////// ++// MOVE TO rtmp.h ? ++///////////////////////////////////////// ++#define PKTSRC_NDIS 0x7f ++#define PKTSRC_DRIVER 0x0f ++#define PRINT_MAC(addr) \ ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ++ ++ ++#define RT2860_PCI_DEVICE_ID 0x0601 ++ ++#ifdef RT2870 ++#define PCI_MAP_SINGLE(_handle, _ptr, _size, _dir) (ULONG)0 ++ ++#define PCI_UNMAP_SINGLE(_handle, _ptr, _size, _dir) ++#endif // RT2870 // ++ ++ ++#define BEACON_FRAME_DMA_CACHE_WBACK(_ptr, _size) \ ++ dma_cache_wback(_ptr, _size) ++ ++ ++////////////////////////////////////////// ++// ++////////////////////////////////////////// ++ ++ ++#define NdisMIndicateStatus(_w, _x, _y, _z) ++ ++ ++typedef struct timer_list RTMP_OS_TIMER; ++ ++#ifdef RT2870 ++/* ----------------- Timer Related MARCO ---------------*/ ++// In RT2870, we have a lot of timer functions and will read/write register, it's ++// not allowed in Linux USB sub-system to do it ( because of sleep issue when submit ++// to ctrl pipe). So we need a wrapper function to take care it. ++ ++typedef VOID (*RT2870_TIMER_HANDLE)( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // RT2870 // ++ ++ ++typedef struct _RALINK_TIMER_STRUCT { ++ RTMP_OS_TIMER TimerObj; // Ndis Timer object ++ BOOLEAN Valid; // Set to True when call RTMPInitTimer ++ BOOLEAN State; // True if timer cancelled ++ BOOLEAN PeriodicType; // True if timer is periodic timer ++ BOOLEAN Repeat; // True if periodic timer ++ ULONG TimerValue; // Timer value in milliseconds ++ ULONG cookie; // os specific object ++#ifdef RT2870 ++ RT2870_TIMER_HANDLE handle; ++ void *pAd; ++#endif // RT2870 // ++} RALINK_TIMER_STRUCT, *PRALINK_TIMER_STRUCT; ++ ++ ++#ifdef RT2870 ++ ++typedef enum _RT2870_KERNEL_THREAD_STATUS_ ++{ ++ RT2870_THREAD_UNKNOWN = 0, ++ RT2870_THREAD_INITED = 1, ++ RT2870_THREAD_RUNNING = 2, ++ RT2870_THREAD_STOPED = 4, ++}RT2870_KERNEL_THREAD_STATUS; ++ ++#define RT2870_THREAD_CAN_DO_INSERT (RT2870_THREAD_INITED |RT2870_THREAD_RUNNING) ++ ++typedef struct _RT2870_TIMER_ENTRY_ ++{ ++ RALINK_TIMER_STRUCT *pRaTimer; ++ struct _RT2870_TIMER_ENTRY_ *pNext; ++}RT2870_TIMER_ENTRY; ++ ++ ++#define TIMER_QUEUE_SIZE_MAX 128 ++typedef struct _RT2870_TIMER_QUEUE_ ++{ ++ unsigned int status; ++ //wait_queue_head_t timerWaitQ; ++ //atomic_t count; ++ UCHAR *pTimerQPoll; ++ RT2870_TIMER_ENTRY *pQPollFreeList; ++ RT2870_TIMER_ENTRY *pQHead; ++ RT2870_TIMER_ENTRY *pQTail; ++}RT2870_TIMER_QUEUE; ++#endif // RT2870 // ++ ++ ++//#define DBG 1 ++ ++// ++// MACRO for debugging information ++// ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++ ++#define DBGPRINT_RAW(Level, Fmt) \ ++{ \ ++ if (Level <= RTDebugLevel) \ ++ { \ ++ printk Fmt; \ ++ } \ ++} ++ ++#define DBGPRINT(Level, Fmt) DBGPRINT_RAW(Level, Fmt) ++ ++ ++#define DBGPRINT_ERR(Fmt) \ ++{ \ ++ printk("ERROR!!! "); \ ++ printk Fmt; \ ++} ++ ++#define DBGPRINT_S(Status, Fmt) \ ++{ \ ++ printk Fmt; \ ++} ++ ++ ++#else ++#define DBGPRINT(Level, Fmt) ++#define DBGPRINT_RAW(Level, Fmt) ++#define DBGPRINT_S(Status, Fmt) ++#define DBGPRINT_ERR(Fmt) ++#endif ++ ++ ++// ++// spin_lock enhanced for Nested spin lock ++// ++#define NdisAllocateSpinLock(__lock) \ ++{ \ ++ spin_lock_init((spinlock_t *)(__lock)); \ ++} ++ ++#define NdisFreeSpinLock(lock) \ ++{ \ ++} ++ ++ ++#define RTMP_SEM_LOCK(__lock) \ ++{ \ ++ spin_lock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#define RTMP_SEM_UNLOCK(__lock) \ ++{ \ ++ spin_unlock_bh((spinlock_t *)(__lock)); \ ++} ++ ++// sample, use semaphore lock to replace IRQ lock, 2007/11/15 ++#define RTMP_IRQ_LOCK(__lock, __irqflags) \ ++{ \ ++ __irqflags = 0; \ ++ spin_lock_bh((spinlock_t *)(__lock)); \ ++ pAd->irq_disabled |= 1; \ ++} ++ ++#define RTMP_IRQ_UNLOCK(__lock, __irqflag) \ ++{ \ ++ pAd->irq_disabled &= 0; \ ++ spin_unlock_bh((spinlock_t *)(__lock)); \ ++} ++ ++#define RTMP_INT_LOCK(__lock, __irqflags) \ ++{ \ ++ spin_lock_irqsave((spinlock_t *)__lock, __irqflags); \ ++} ++ ++#define RTMP_INT_UNLOCK(__lock, __irqflag) \ ++{ \ ++ spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ ++} ++ ++#ifdef RT2870 ++#define RTMP_IO_READ32(_A, _R, _pV) \ ++ RTUSBReadMACRegister(_A, _R, _pV) ++ ++#define RTMP_IO_READ8(_A, _R, _pV) \ ++{ \ ++} ++ ++#define RTMP_IO_WRITE32(_A, _R, _V) \ ++ RTUSBWriteMACRegister(_A, _R, _V) ++ ++ ++#define RTMP_IO_WRITE8(_A, _R, _V) \ ++{ \ ++ USHORT _Val = _V; \ ++ RTUSBSingleWrite(_A, _R, _Val); \ ++} ++ ++ ++#define RTMP_IO_WRITE16(_A, _R, _V) \ ++{ \ ++ RTUSBSingleWrite(_A, _R, _V); \ ++} ++#endif // RT2870 // ++ ++#ifndef wait_event_interruptible_timeout ++#define __wait_event_interruptible_timeout(wq, condition, ret) \ ++do { \ ++ wait_queue_t __wait; \ ++ init_waitqueue_entry(&__wait, current); \ ++ add_wait_queue(&wq, &__wait); \ ++ for (;;) { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (!signal_pending(current)) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ continue; \ ++ } \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ current->state = TASK_RUNNING; \ ++ remove_wait_queue(&wq, &__wait); \ ++} while (0) ++ ++#define wait_event_interruptible_timeout(wq, condition, timeout) \ ++({ \ ++ long __ret = timeout; \ ++ if (!(condition)) \ ++ __wait_event_interruptible_timeout(wq, condition, __ret); \ ++ __ret; \ ++}) ++#endif ++#define ONE_TICK 1 ++#define OS_WAIT(_time) \ ++{ int _i; \ ++ long _loop = ((_time)/(1000/OS_HZ)) > 0 ? ((_time)/(1000/OS_HZ)) : 1;\ ++ wait_queue_head_t _wait; \ ++ init_waitqueue_head(&_wait); \ ++ for (_i=0; _i<(_loop); _i++) \ ++ wait_event_interruptible_timeout(_wait, 0, ONE_TICK); } ++ ++ ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++typedef void (*TIMER_FUNCTION)(unsigned long); ++ ++#define COPY_MAC_ADDR(Addr1, Addr2) memcpy((Addr1), (Addr2), MAC_ADDR_LEN) ++ ++#define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) ++#define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) ++ ++ ++#ifdef RT2870 ++#define BUILD_TIMER_FUNCTION(_func) \ ++void linux_##_func(unsigned long data) \ ++{ \ ++ PRALINK_TIMER_STRUCT _pTimer = (PRALINK_TIMER_STRUCT)data; \ ++ RT2870_TIMER_ENTRY *_pQNode; \ ++ RTMP_ADAPTER *_pAd; \ ++ \ ++ _pTimer->handle = _func; \ ++ _pAd = (RTMP_ADAPTER *)_pTimer->pAd; \ ++ _pQNode = RT2870_TimerQ_Insert(_pAd, _pTimer); \ ++ if ((_pQNode == NULL) && (_pAd->TimerQ.status & RT2870_THREAD_CAN_DO_INSERT)) \ ++ RTMP_OS_Add_Timer(&_pTimer->TimerObj, HZ); \ ++} ++#endif // RT2870 // ++ ++ ++#define DECLARE_TIMER_FUNCTION(_func) \ ++void linux_##_func(unsigned long data) ++ ++#define GET_TIMER_FUNCTION(_func) \ ++ linux_##_func ++ ++DECLARE_TIMER_FUNCTION(MlmePeriodicExec); ++DECLARE_TIMER_FUNCTION(MlmeRssiReportExec); ++DECLARE_TIMER_FUNCTION(AsicRxAntEvalTimeout); ++DECLARE_TIMER_FUNCTION(APSDPeriodicExec); ++DECLARE_TIMER_FUNCTION(AsicRfTuningExec); ++#ifdef RT2870 ++DECLARE_TIMER_FUNCTION(BeaconUpdateExec); ++#endif // RT2870 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++DECLARE_TIMER_FUNCTION(BeaconTimeout); ++DECLARE_TIMER_FUNCTION(ScanTimeout); ++DECLARE_TIMER_FUNCTION(AuthTimeout); ++DECLARE_TIMER_FUNCTION(AssocTimeout); ++DECLARE_TIMER_FUNCTION(ReassocTimeout); ++DECLARE_TIMER_FUNCTION(DisassocTimeout); ++DECLARE_TIMER_FUNCTION(LinkDownExec); ++#ifdef LEAP_SUPPORT ++DECLARE_TIMER_FUNCTION(LeapAuthTimeout); ++#endif ++DECLARE_TIMER_FUNCTION(StaQuickResponeForRateUpExec); ++DECLARE_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); ++DECLARE_TIMER_FUNCTION(PsPollWakeExec); ++DECLARE_TIMER_FUNCTION(RadioOnExec); ++ ++#ifdef QOS_DLS_SUPPORT ++DECLARE_TIMER_FUNCTION(DlsTimeoutAction); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#undef AP_WSC_INCLUDED ++#undef STA_WSC_INCLUDED ++#undef WSC_INCLUDED ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) ++#define WSC_INCLUDED ++#endif ++ ++ ++ ++void RTMP_GetCurrentSystemTime(LARGE_INTEGER *time); ++ ++ ++/* ++ * packet helper ++ * - convert internal rt packet to os packet or ++ * os packet to rt packet ++ */ ++#define RTPKT_TO_OSPKT(_p) ((struct sk_buff *)(_p)) ++#define OSPKT_TO_RTPKT(_p) ((PNDIS_PACKET)(_p)) ++ ++#define GET_OS_PKT_DATAPTR(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->data) ++ ++#define GET_OS_PKT_LEN(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->len) ++ ++#define GET_OS_PKT_DATATAIL(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->tail) ++ ++#define GET_OS_PKT_HEAD(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->head) ++ ++#define GET_OS_PKT_END(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->end) ++ ++#define GET_OS_PKT_NETDEV(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->dev) ++ ++#define GET_OS_PKT_TYPE(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)) ++ ++#define GET_OS_PKT_NEXT(_pkt) \ ++ (RTPKT_TO_OSPKT(_pkt)->next) ++ ++ ++#define OS_NTOHS(_Val) \ ++ (ntohs(_Val)) ++#define OS_HTONS(_Val) \ ++ (htons(_Val)) ++#define OS_NTOHL(_Val) \ ++ (ntohl(_Val)) ++#define OS_HTONL(_Val) \ ++ (htonl(_Val)) ++ ++/* statistics counter */ ++#define STATS_INC_RX_PACKETS(_pAd, _dev) ++#define STATS_INC_TX_PACKETS(_pAd, _dev) ++ ++#define STATS_INC_RX_BYTESS(_pAd, _dev, len) ++#define STATS_INC_TX_BYTESS(_pAd, _dev, len) ++ ++#define STATS_INC_RX_ERRORS(_pAd, _dev) ++#define STATS_INC_TX_ERRORS(_pAd, _dev) ++ ++#define STATS_INC_RX_DROPPED(_pAd, _dev) ++#define STATS_INC_TX_DROPPED(_pAd, _dev) ++ ++ ++#define CB_OFF 10 ++ ++ ++// check DDK NDIS_PACKET data structure and find out only MiniportReservedEx[0..7] can be used by our driver without ++// ambiguity. Fields after pPacket->MiniportReservedEx[8] may be used by other wrapper layer thus crashes the driver ++// ++//#define RTMP_GET_PACKET_MR(_p) (RTPKT_TO_OSPKT(_p)) ++ ++// User Priority ++#define RTMP_SET_PACKET_UP(_p, _prio) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0] = _prio) ++#define RTMP_GET_PACKET_UP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+0]) ++ ++// Fragment # ++#define RTMP_SET_PACKET_FRAGMENTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1] = _num) ++#define RTMP_GET_PACKET_FRAGMENTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+1]) ++ ++// 0x0 ~0x7f: TX to AP's own BSS which has the specified AID. if AID>127, set bit 7 in RTMP_SET_PACKET_EMACTAB too. ++//(this value also as MAC(on-chip WCID) table index) ++// 0x80~0xff: TX to a WDS link. b0~6: WDS index ++#define RTMP_SET_PACKET_WCID(_p, _wdsidx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2] = _wdsidx) ++#define RTMP_GET_PACKET_WCID(_p) ((UCHAR)(RTPKT_TO_OSPKT(_p)->cb[CB_OFF+2])) ++ ++// 0xff: PKTSRC_NDIS, others: local TX buffer index. This value affects how to a packet ++#define RTMP_SET_PACKET_SOURCE(_p, _pktsrc) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3] = _pktsrc) ++#define RTMP_GET_PACKET_SOURCE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+3]) ++ ++// RTS/CTS-to-self protection method ++#define RTMP_SET_PACKET_RTS(_p, _num) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4] = _num) ++#define RTMP_GET_PACKET_RTS(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+4]) ++// see RTMP_S(G)ET_PACKET_EMACTAB ++ ++// TX rate index ++#define RTMP_SET_PACKET_TXRATE(_p, _rate) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5] = _rate) ++#define RTMP_GET_PACKET_TXRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+5]) ++ ++// From which Interface ++#define RTMP_SET_PACKET_IF(_p, _ifdx) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6] = _ifdx) ++#define RTMP_GET_PACKET_IF(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+6]) ++#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) RTMP_SET_PACKET_IF((_p), (_bss)) ++#define RTMP_SET_PACKET_NET_DEVICE_WDS(_p, _bss) RTMP_SET_PACKET_IF((_p), ((_bss) + MIN_NET_DEVICE_FOR_WDS)) ++#define RTMP_SET_PACKET_NET_DEVICE_APCLI(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_APCLI)) ++#define RTMP_SET_PACKET_NET_DEVICE_MESH(_p, _idx) RTMP_SET_PACKET_IF((_p), ((_idx) + MIN_NET_DEVICE_FOR_MESH)) ++#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) RTMP_GET_PACKET_IF((_p)) ++#define RTMP_GET_PACKET_NET_DEVICE(_p) RTMP_GET_PACKET_IF((_p)) ++ ++#define RTMP_SET_PACKET_MOREDATA(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7] = _morebit) ++#define RTMP_GET_PACKET_MOREDATA(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+7]) ++ ++//#define RTMP_SET_PACKET_NET_DEVICE_MBSSID(_p, _bss) (RTPKT_TO_OSPKT(_p)->cb[8] = _bss) ++//#define RTMP_GET_PACKET_NET_DEVICE_MBSSID(_p) (RTPKT_TO_OSPKT(_p)->cb[8]) ++ ++// ++// Sepcific Pakcet Type definition ++// ++#define RTMP_PACKET_SPECIFIC_CB_OFFSET 11 ++ ++#define RTMP_PACKET_SPECIFIC_DHCP 0x01 ++#define RTMP_PACKET_SPECIFIC_EAPOL 0x02 ++#define RTMP_PACKET_SPECIFIC_IPV4 0x04 ++#define RTMP_PACKET_SPECIFIC_WAI 0x08 ++#define RTMP_PACKET_SPECIFIC_VLAN 0x10 ++#define RTMP_PACKET_SPECIFIC_LLCSNAP 0x20 ++ ++//Specific ++#define RTMP_SET_PACKET_SPECIFIC(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] = _flg) ++ ++//DHCP ++#define RTMP_SET_PACKET_DHCP(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_DHCP); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_DHCP); \ ++ }while(0) ++#define RTMP_GET_PACKET_DHCP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_DHCP) ++ ++//EAPOL ++#define RTMP_SET_PACKET_EAPOL(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_EAPOL); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_EAPOL); \ ++ }while(0) ++#define RTMP_GET_PACKET_EAPOL(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_EAPOL) ++ ++//WAI ++#define RTMP_SET_PACKET_WAI(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_WAI); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_WAI); \ ++ }while(0) ++#define RTMP_GET_PACKET_WAI(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_WAI) ++ ++#define RTMP_GET_PACKET_LOWRATE(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & (RTMP_PACKET_SPECIFIC_EAPOL | RTMP_PACKET_SPECIFIC_DHCP | RTMP_PACKET_SPECIFIC_WAI)) ++ ++//VLAN ++#define RTMP_SET_PACKET_VLAN(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_VLAN); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_VLAN); \ ++ }while(0) ++#define RTMP_GET_PACKET_VLAN(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_VLAN) ++ ++//LLC/SNAP ++#define RTMP_SET_PACKET_LLCSNAP(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_LLCSNAP); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_LLCSNAP); \ ++ }while(0) ++ ++#define RTMP_GET_PACKET_LLCSNAP(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_LLCSNAP) ++ ++// IP ++#define RTMP_SET_PACKET_IPV4(_p, _flg) \ ++ do{ \ ++ if (_flg) \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) |= (RTMP_PACKET_SPECIFIC_IPV4); \ ++ else \ ++ (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11]) &= (!RTMP_PACKET_SPECIFIC_IPV4); \ ++ }while(0) ++ ++#define RTMP_GET_PACKET_IPV4(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+11] & RTMP_PACKET_SPECIFIC_IPV4) ++ ++// If this flag is set, it indicates that this EAPoL frame MUST be clear. ++#define RTMP_SET_PACKET_CLEAR_EAP_FRAME(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12] = _flg) ++#define RTMP_GET_PACKET_CLEAR_EAP_FRAME(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+12]) ++ ++#define RTMP_SET_PACKET_5VT(_p, _flg) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22] = _flg) ++#define RTMP_GET_PACKET_5VT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+22]) ++ ++ ++#ifdef INF_AMAZON_SE ++/*Iverson patch for WMM A5-T07 ,WirelessStaToWirelessSta do not bulk out aggregate */ ++#define RTMP_SET_PACKET_NOBULKOUT(_p, _morebit) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+23] = _morebit) ++#define RTMP_GET_PACKET_NOBULKOUT(_p) (RTPKT_TO_OSPKT(_p)->cb[CB_OFF+23]) ++#endif // INF_AMAZON_SE // ++ ++ ++ ++#ifdef CONFIG_5VT_ENHANCE ++#define BRIDGE_TAG 0x35564252 // depends on 5VT define in br_input.c ++#endif ++ ++ ++#define NDIS_SET_PACKET_STATUS(_p, _status) ++ ++ ++#define GET_SG_LIST_FROM_PACKET(_p, _sc) \ ++ rt_get_sg_list_from_packet(_p, _sc) ++ ++#define NdisMoveMemory(Destination, Source, Length) memmove(Destination, Source, Length) ++#define NdisZeroMemory(Destination, Length) memset(Destination, 0, Length) ++#define NdisFillMemory(Destination, Length, Fill) memset(Destination, Fill, Length) ++#define NdisEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) ++#define RTMPEqualMemory(Source1, Source2, Length) (!memcmp(Source1, Source2, Length)) ++ ++ ++#define RTMP_INC_REF(_A) 0 ++#define RTMP_DEC_REF(_A) 0 ++#define RTMP_GET_REF(_A) 0 ++ ++ ++ ++/* ++ * ULONG ++ * RTMP_GetPhysicalAddressLow( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ */ ++#define RTMP_GetPhysicalAddressLow(PhysicalAddress) (PhysicalAddress) ++ ++/* ++ * ULONG ++ * RTMP_GetPhysicalAddressHigh( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ */ ++#define RTMP_GetPhysicalAddressHigh(PhysicalAddress) (0) ++ ++/* ++ * VOID ++ * RTMP_SetPhysicalAddressLow( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, ++ * IN ULONG Value); ++ */ ++#define RTMP_SetPhysicalAddressLow(PhysicalAddress, Value) \ ++ PhysicalAddress = Value; ++ ++/* ++ * VOID ++ * RTMP_SetPhysicalAddressHigh( ++ * IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, ++ * IN ULONG Value); ++ */ ++#define RTMP_SetPhysicalAddressHigh(PhysicalAddress, Value) ++ ++ ++//CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); ++#define QUEUE_ENTRY_TO_PACKET(pEntry) \ ++ (PNDIS_PACKET)(pEntry) ++ ++#define PACKET_TO_QUEUE_ENTRY(pPacket) \ ++ (PQUEUE_ENTRY)(pPacket) ++ ++ ++#ifndef CONTAINING_RECORD ++#define CONTAINING_RECORD(address, type, field) \ ++((type *)((PCHAR)(address) - offsetof(type, field))) ++#endif ++ ++ ++#define RELEASE_NDIS_PACKET(_pAd, _pPacket, _Status) \ ++{ \ ++ RTMPFreeNdisPacket(_pAd, _pPacket); \ ++} ++ ++ ++#define SWITCH_PhyAB(_pAA, _pBB) \ ++{ \ ++ ULONG AABasePaHigh; \ ++ ULONG AABasePaLow; \ ++ ULONG BBBasePaHigh; \ ++ ULONG BBBasePaLow; \ ++ BBBasePaHigh = RTMP_GetPhysicalAddressHigh(_pBB); \ ++ BBBasePaLow = RTMP_GetPhysicalAddressLow(_pBB); \ ++ AABasePaHigh = RTMP_GetPhysicalAddressHigh(_pAA); \ ++ AABasePaLow = RTMP_GetPhysicalAddressLow(_pAA); \ ++ RTMP_SetPhysicalAddressHigh(_pAA, BBBasePaHigh); \ ++ RTMP_SetPhysicalAddressLow(_pAA, BBBasePaLow); \ ++ RTMP_SetPhysicalAddressHigh(_pBB, AABasePaHigh); \ ++ RTMP_SetPhysicalAddressLow(_pBB, AABasePaLow); \ ++} ++ ++ ++#define NdisWriteErrorLogEntry(_a, _b, _c, _d) ++#define NdisMAllocateMapRegisters(_a, _b, _c, _d, _e) NDIS_STATUS_SUCCESS ++ ++ ++#define NdisAcquireSpinLock RTMP_SEM_LOCK ++#define NdisReleaseSpinLock RTMP_SEM_UNLOCK ++ ++static inline void NdisGetSystemUpTime(ULONG *time) ++{ ++ *time = jiffies; ++} ++ ++//pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); ++#define QUEUE_ENTRY_TO_PKT(pEntry) \ ++ ((PNDIS_PACKET) (pEntry)) ++ ++int rt28xx_packet_xmit(struct sk_buff *skb); ++ ++ ++ ++void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); ++ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rt_main_dev.c +@@ -0,0 +1,1800 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rt_main_dev.c ++ ++ Abstract: ++ Create and register network interface. ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Sample Mar/21/07 Merge RT2870 and RT2860 drivers. ++*/ ++ ++#include "rt_config.h" ++ ++#define FORTY_MHZ_INTOLERANT_INTERVAL (60*1000) // 1 min ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// record whether the card in the card list is used in the card file ++UINT8 MC_CardUsed[MAX_NUM_OF_MULTIPLE_CARD]; ++// record used card mac address in the card list ++static UINT8 MC_CardMac[MAX_NUM_OF_MULTIPLE_CARD][6]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++UINT32 CW_MAX_IN_BITS; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++/*---------------------------------------------------------------------*/ ++/* Private Variables Used */ ++/*---------------------------------------------------------------------*/ ++//static RALINK_TIMER_STRUCT PeriodicTimer; ++ ++char *mac = ""; // default 00:00:00:00:00:00 ++char *hostname = ""; // default CMPC ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) ++MODULE_PARM (mac, "s"); ++#else ++module_param (mac, charp, 0); ++#endif ++MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); ++ ++ ++/*---------------------------------------------------------------------*/ ++/* Prototypes of Functions Used */ ++/*---------------------------------------------------------------------*/ ++#ifdef DOT11_N_SUPPORT ++extern BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); ++extern void ba_reordering_resource_release(PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); ++ ++ ++// public function prototype ++INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, ++ IN UINT argc, OUT PRTMP_ADAPTER *ppAd); ++ ++// private function prototype ++static int rt28xx_init(IN struct net_device *net_dev); ++INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev); ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++struct net_device *alloc_netdev( ++ int sizeof_priv, ++ const char *mask, ++ void (*setup)(struct net_device *)); ++#endif // LINUX_VERSION_CODE // ++ ++static void CfgInitHook(PRTMP_ADAPTER pAd); ++//static BOOLEAN RT28XXAvailRANameAssign(IN CHAR *name_p); ++ ++#ifdef CONFIG_STA_SUPPORT ++extern const struct iw_handler_def rt28xx_iw_handler_def; ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++extern const struct iw_handler_def rt28xx_ap_iw_handler_def; ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev); ++#endif ++ ++struct net_device_stats *RT28xx_get_ether_stats( ++ IN struct net_device *net_dev); ++ ++/* ++======================================================================== ++Routine Description: ++ Close raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int MainVirtualIF_close(IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ netif_carrier_off(pAd->net_dev); ++ netif_stop_queue(pAd->net_dev); ++ ++ ++ ++ VIRTUAL_IF_DOWN(pAd); ++ ++ RT_MOD_DEC_USE_COUNT(); ++ ++ return 0; // close ok ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Open raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int MainVirtualIF_open(IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ if (VIRTUAL_IF_UP(pAd) != 0) ++ return -1; ++ ++ // increase MODULE use count ++ RT_MOD_INC_USE_COUNT(); ++ ++ netif_start_queue(net_dev); ++ netif_carrier_on(net_dev); ++ netif_wake_queue(net_dev); ++ ++ return 0; ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Close raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++ 1. if open fail, kernel will not call the close function. ++ 2. Free memory for ++ (1) Mlme Memory Handler: MlmeHalt() ++ (2) TX & RX: RTMPFreeTxRxRingMemory() ++ (3) BA Reordering: ba_reordering_resource_release() ++======================================================================== ++*/ ++int rt28xx_close(IN PNET_DEV dev) ++{ ++ struct net_device * net_dev = (struct net_device *)dev; ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; ++ BOOLEAN Cancelled = FALSE; ++ UINT32 i = 0; ++#ifdef RT2870 ++ DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); ++ DECLARE_WAITQUEUE(wait, current); ++ ++ //RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); ++#endif // RT2870 // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("===> rt28xx_close\n")); ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ return 0; // close ok ++ ++ ++#ifdef WDS_SUPPORT ++ WdsDown(pAd); ++#endif // WDS_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ // If dirver doesn't wake up firmware here, ++ // NICLoadFirmware will hang forever when interface is up again. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AsicForceWakeup(pAd, TRUE); ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ // send DLS-TEAR_DOWN message, ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ UCHAR i; ++ ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ RT28XX_MLME_HANDLER(pAd); ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ if (INFRA_ON(pAd) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))) ++ { ++ MLME_DISASSOC_REQ_STRUCT DisReq; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ COPY_MAC_ADDR(DisReq.Addr, pAd->CommonCfg.Bssid); ++ DisReq.Reason = REASON_DEAUTH_STA_LEAVING; ++ ++ MsgElem->Machine = ASSOC_STATE_MACHINE; ++ MsgElem->MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAd->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, MsgElem); ++ kfree(MsgElem); ++ ++ RTMPusecDelay(1000); ++ } ++ ++#ifdef RT2870 ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); ++#endif // RT2870 // ++ ++#ifdef CCX_SUPPORT ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &Cancelled); ++#endif ++ ++ RTMPCancelTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, &Cancelled); ++ RTMPCancelTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, &Cancelled); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ // send wireless event to wpa_supplicant for infroming interface down. ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_INTERFACE_DOWN; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ MlmeRadioOff(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ ++ for (i = 0 ; i < NUM_OF_TX_RING; i++) ++ { ++ while (pAd->DeQueueRunning[i] == TRUE) ++ { ++ printk("Waiting for TxQueue[%d] done..........\n", i); ++ RTMPusecDelay(1000); ++ } ++ } ++ ++#ifdef RT2870 ++ // ensure there are no more active urbs. ++ add_wait_queue (&unlink_wakeup, &wait); ++ pAd->wait = &unlink_wakeup; ++ ++ // maybe wait for deletions to finish. ++ i = 0; ++ //while((i < 25) && atomic_read(&pAd->PendingRx) > 0) ++ while(i < 25) ++ { ++ unsigned long IrqFlags; ++ ++ RTMP_IRQ_LOCK(&pAd->BulkInLock, IrqFlags); ++ if (pAd->PendingRx == 0) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ break; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->BulkInLock, IrqFlags); ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) ++ msleep(UNLINK_TIMEOUT_MS); //Time in millisecond ++#else ++ RTMPusecDelay(UNLINK_TIMEOUT_MS*1000); //Time in microsecond ++#endif ++ i++; ++ } ++ pAd->wait = NULL; ++ remove_wait_queue (&unlink_wakeup, &wait); ++#endif // RT2870 // ++ ++ //RTUSBCleanUpMLMEWaitQueue(pAd); /*not used in RT28xx*/ ++ ++ ++#ifdef RT2870 ++ // We need clear timerQ related structure before exits of the timer thread. ++ RT2870_TimerQ_Exit(pAd); ++ // Close kernel threads or tasklets ++ RT28xxThreadTerminate(pAd); ++#endif // RT2870 // ++ ++ // Stop Mlme state machine ++ MlmeHalt(pAd); ++ ++ // Close kernel threads or tasklets ++ kill_thread_task(pAd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ MacTableReset(pAd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ MeasureReqTabExit(pAd); ++ TpcReqTabExit(pAd); ++ ++ ++ ++ ++ // Free Ring or USB buffers ++ RTMPFreeTxRxRingMemory(pAd); ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ ++#ifdef DOT11_N_SUPPORT ++ // Free BA reorder resource ++ ba_reordering_resource_release(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef RT2870 ++#ifdef INF_AMAZON_SE ++ if (pAd->UsbVendorReqBuf) ++ os_free_mem(pAd, pAd->UsbVendorReqBuf); ++#endif // INF_AMAZON_SE // ++#endif // RT2870 // ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_START_UP); ++ ++ return 0; // close ok ++} /* End of rt28xx_close */ ++ ++static int rt28xx_init(IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; ++ UINT index; ++ UCHAR TmpPhy; ++// ULONG Value=0; ++ NDIS_STATUS Status; ++// OID_SET_HT_PHYMODE SetHT; ++// WPDMA_GLO_CFG_STRUC GloCfg; ++ UINT32 MacCsr0 = 0; ++ UINT32 MacValue = 0; ++ ++#ifdef RT2870 ++#ifdef INF_AMAZON_SE ++ init_MUTEX(&(pAd->UsbVendorReq_semaphore)); ++ os_alloc_mem(pAd, (PUCHAR)&pAd->UsbVendorReqBuf, MAX_PARAM_BUFFER_SIZE - 1); ++ if (pAd->UsbVendorReqBuf == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Allocate vendor request temp buffer failed!\n")); ++ goto err0; ++ } ++#endif // INF_AMAZON_SE // ++#endif // RT2870 // ++ ++#ifdef DOT11_N_SUPPORT ++ // Allocate BA Reordering memory ++ ba_reordering_resource_init(pAd, MAX_REORDERING_MPDU_NUM); ++#endif // DOT11_N_SUPPORT // ++ ++ // Make sure MAC gets ready. ++ index = 0; ++ do ++ { ++ RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0); ++ pAd->MACVersion = MacCsr0; ++ ++ if ((pAd->MACVersion != 0x00) && (pAd->MACVersion != 0xFFFFFFFF)) ++ break; ++ ++ RTMPusecDelay(10); ++ } while (index++ < 100); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MAC_CSR0 [ Ver:Rev=0x%08x]\n", pAd->MACVersion)); ++/*Iverson patch PCIE L1 issue */ ++ ++ // Disable DMA ++ RT28XXDMADisable(pAd); ++ ++ ++ // Load 8051 firmware ++ Status = NICLoadFirmware(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICLoadFirmware failed, Status[=0x%08x]\n", Status)); ++ goto err1; ++ } ++ ++ NICLoadRateSwitchingParams(pAd); ++ ++ // Disable interrupts here which is as soon as possible ++ // This statement should never be true. We might consider to remove it later ++ ++ Status = RTMPAllocTxRxRingMemory(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("RTMPAllocDMAMemory failed, Status[=0x%08x]\n", Status)); ++ goto err1; ++ } ++ ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ ++ // initialize MLME ++ // ++ ++ Status = MlmeInit(pAd); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("MlmeInit failed, Status[=0x%08x]\n", Status)); ++ goto err2; ++ } ++ ++ // Initialize pAd->StaCfg, pAd->ApCfg, pAd->CommonCfg to manufacture default ++ // ++ UserCfgInit(pAd); ++ ++#ifdef RT2870 ++ // We need init timerQ related structure before create the timer thread. ++ RT2870_TimerQ_Init(pAd); ++#endif // RT2870 // ++ ++ RT28XX_TASK_THREAD_INIT(pAd, Status); ++ if (Status != NDIS_STATUS_SUCCESS) ++ goto err1; ++ ++// COPY_MAC_ADDR(pAd->ApCfg.MBSSID[apidx].Bssid, netif->hwaddr); ++// pAd->bForcePrintTX = TRUE; ++ ++ CfgInitHook(pAd); ++ ++ ++#ifdef BLOCK_NET_IF ++ initblockQueueTab(pAd); ++#endif // BLOCK_NET_IF // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisAllocateSpinLock(&pAd->MacTabLock); ++#endif // CONFIG_STA_SUPPORT // ++ ++ MeasureReqTabInit(pAd); ++ TpcReqTabInit(pAd); ++ ++ // ++ // Init the hardware, we need to init asic before read registry, otherwise mac register will be reset ++ // ++ Status = NICInitializeAdapter(pAd, TRUE); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICInitializeAdapter failed, Status[=0x%08x]\n", Status)); ++ if (Status != NDIS_STATUS_SUCCESS) ++ goto err3; ++ } ++ ++ // Read parameters from Config File ++ Status = RTMPReadParametersHook(pAd); ++ ++ printk("1. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ if (Status != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT_ERR(("NICReadRegParameters failed, Status[=0x%08x]\n",Status)); ++ goto err4; ++ } ++ ++#ifdef RT2870 ++ pAd->CommonCfg.bMultipleIRP = FALSE; ++ ++ if (pAd->CommonCfg.bMultipleIRP) ++ pAd->CommonCfg.NumOfBulkInIRP = RX_RING_SIZE; ++ else ++ pAd->CommonCfg.NumOfBulkInIRP = 1; ++#endif // RT2870 // ++ ++ ++ //Init Ba Capability parameters. ++// RT28XX_BA_INIT(pAd); ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.DesiredHtPhy.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++ pAd->CommonCfg.DesiredHtPhy.AmsduEnable = (USHORT)pAd->CommonCfg.BACapability.field.AmsduEnable; ++ pAd->CommonCfg.DesiredHtPhy.AmsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.DesiredHtPhy.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ // UPdata to HT IE ++ pAd->CommonCfg.HtCapability.HtCapInfo.MimoPs = (USHORT)pAd->CommonCfg.BACapability.field.MMPSmode; ++ pAd->CommonCfg.HtCapability.HtCapInfo.AMsduSize = (USHORT)pAd->CommonCfg.BACapability.field.AmsduSize; ++ pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity = (UCHAR)pAd->CommonCfg.BACapability.field.MpduDensity; ++#endif // DOT11_N_SUPPORT // ++ ++ // after reading Registry, we now know if in AP mode or STA mode ++ ++ // Load 8051 firmware; crash when FW image not existent ++ // Status = NICLoadFirmware(pAd); ++ // if (Status != NDIS_STATUS_SUCCESS) ++ // break; ++ ++ printk("2. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ ++ // We should read EEPROM for all cases. rt2860b ++ NICReadEEPROMParameters(pAd, mac); ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ printk("3. Phy Mode = %d\n", pAd->CommonCfg.PhyMode); ++ ++ NICInitAsicFromEEPROM(pAd); //rt2860b ++ ++ // Set PHY to appropriate mode ++ TmpPhy = pAd->CommonCfg.PhyMode; ++ pAd->CommonCfg.PhyMode = 0xff; ++ RTMPSetPhyMode(pAd, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ // No valid channels. ++ if (pAd->ChannelListNum == 0) ++ { ++ printk("Wrong configuration. No valid channel found. Check \"ContryCode\" and \"ChannelGeography\" setting.\n"); ++ goto err4; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ printk("MCS Set = %02x %02x %02x %02x %02x\n", pAd->CommonCfg.HtCapability.MCSSet[0], ++ pAd->CommonCfg.HtCapability.MCSSet[1], pAd->CommonCfg.HtCapability.MCSSet[2], ++ pAd->CommonCfg.HtCapability.MCSSet[3], pAd->CommonCfg.HtCapability.MCSSet[4]); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef RT30xx ++ //Init RT30xx RFRegisters after read RFIC type from EEPROM ++ NICInitRT30xxRFRegisters(pAd); ++#endif // RT30xx // ++ ++// APInitialize(pAd); ++ ++#ifdef IKANOS_VX_1X0 ++ VR_IKANOS_FP_Init(pAd->ApCfg.BssidNum, pAd->PermanentAddress); ++#endif // IKANOS_VX_1X0 // ++ ++ // ++ // Initialize RF register to default value ++ // ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ if (pAd && (Status != NDIS_STATUS_SUCCESS)) ++ { ++ // ++ // Undo everything if it failed ++ // ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++// NdisMDeregisterInterrupt(&pAd->Interrupt); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); ++ } ++// RTMPFreeAdapter(pAd); // we will free it in disconnect() ++ } ++ else if (pAd) ++ { ++ // Microsoft HCT require driver send a disconnect event after driver initialization. ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++// pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event B!\n")); ++ ++ ++#ifdef RT2870 ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_REMOVE_IN_PROGRESS); ++ ++ // ++ // Support multiple BulkIn IRP, ++ // the value on pAd->CommonCfg.NumOfBulkInIRP may be large than 1. ++ // ++ for(index=0; indexCommonCfg.NumOfBulkInIRP; index++) ++ { ++ RTUSBBulkReceive(pAd); ++ DBGPRINT(RT_DEBUG_TRACE, ("RTUSBBulkReceive!\n" )); ++ } ++#endif // RT2870 // ++ }// end of else ++ ++ ++ DBGPRINT_S(Status, ("<==== RTMPInitialize, Status=%x\n", Status)); ++ ++ return TRUE; ++ ++ ++err4: ++err3: ++ MlmeHalt(pAd); ++err2: ++ RTMPFreeTxRxRingMemory(pAd); ++// RTMPFreeAdapter(pAd); ++err1: ++ ++#ifdef DOT11_N_SUPPORT ++ os_free_mem(pAd, pAd->mpdu_blk_pool.mem); // free BA pool ++#endif // DOT11_N_SUPPORT // ++ RT28XX_IRQ_RELEASE(net_dev); ++ ++ // shall not set priv to NULL here because the priv didn't been free yet. ++ //net_dev->ml_priv = 0; ++#ifdef INF_AMAZON_SE ++err0: ++#endif // INF_AMAZON_SE // ++ printk("!!! %s Initialized fail !!!\n", RT28xx_CHIP_NAME); ++ return FALSE; ++} /* End of rt28xx_init */ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Open raxx interface. ++ ++Arguments: ++ *net_dev the raxx interface pointer ++ ++Return Value: ++ 0 Open OK ++ otherwise Open Fail ++ ++Note: ++======================================================================== ++*/ ++int rt28xx_open(IN PNET_DEV dev) ++{ ++ struct net_device * net_dev = (struct net_device *)dev; ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; ++ int retval = 0; ++ POS_COOKIE pObj; ++ ++ ++ // Sanity check for pAd ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->ml_priv will be NULL in 2rd open */ ++ return -1; ++ } ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ CW_MAX_IN_BITS = 6; ++ } ++ else if (pAd->OpMode == OPMODE_STA) ++ { ++ CW_MAX_IN_BITS = 10; ++ } ++ ++#if WIRELESS_EXT >= 12 ++ if (net_dev->ml_priv_flags == INT_MAIN) ++ { ++ if (pAd->OpMode == OPMODE_AP) ++ net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_ap_iw_handler_def; ++ else if (pAd->OpMode == OPMODE_STA) ++ net_dev->wireless_handlers = (struct iw_handler_def *) &rt28xx_iw_handler_def; ++ } ++#endif // WIRELESS_EXT >= 12 // ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Init ++ pObj = (POS_COOKIE)pAd->OS_Cookie; ++ ++ // reset Adapter flags ++ RTMP_CLEAR_FLAGS(pAd); ++ ++ // Request interrupt service routine for PCI device ++ // register the interrupt routine with the os ++ RT28XX_IRQ_REQUEST(net_dev); ++ ++ ++ // Init BssTab & ChannelInfo tabbles for auto channel select. ++ ++ ++ // Chip & other init ++ if (rt28xx_init(net_dev) == FALSE) ++ goto err; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ NdisZeroMemory(pAd->StaCfg.dev_name, 16); ++ NdisMoveMemory(pAd->StaCfg.dev_name, net_dev->name, strlen(net_dev->name)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Set up the Mac address ++ NdisMoveMemory(net_dev->dev_addr, (void *) pAd->CurrentAddress, 6); ++ ++ // Init IRQ parameters ++ RT28XX_IRQ_INIT(pAd); ++ ++ // Various AP function init ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ // send wireless event to wpa_supplicant for infroming interface down. ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_INTERFACE_UP; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Enable Interrupt ++ RT28XX_IRQ_ENABLE(pAd); ++ ++ // Now Enable RxTx ++ RTMPEnableRxTx(pAd); ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP); ++ ++ { ++ UINT32 reg = 0; ++ RTMP_IO_READ32(pAd, 0x1300, ®); // clear garbage interrupts ++ printk("0x1300 = %08x\n", reg); ++ } ++ ++ { ++// u32 reg; ++// u8 byte; ++// u16 tmp; ++ ++// RTMP_IO_READ32(pAd, XIFS_TIME_CFG, ®); ++ ++// tmp = 0x0805; ++// reg = (reg & 0xffff0000) | tmp; ++// RTMP_IO_WRITE32(pAd, XIFS_TIME_CFG, reg); ++ ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ return (retval); ++ ++err: ++ return (-1); ++} /* End of rt28xx_open */ ++ ++ ++/* Must not be called for mdev and apdev */ ++static NDIS_STATUS rt_ieee80211_if_setup(struct net_device *dev, PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS Status; ++ INT i=0; ++ CHAR slot_name[IFNAMSIZ]; ++ struct net_device *device; ++ ++ ++ //ether_setup(dev); ++ dev->hard_start_xmit = rt28xx_send_packets; ++ ++#ifdef IKANOS_VX_1X0 ++ dev->hard_start_xmit = IKANOS_DataFramesTx; ++#endif // IKANOS_VX_1X0 // ++ ++// dev->set_multicast_list = ieee80211_set_multicast_list; ++// dev->change_mtu = ieee80211_change_mtu; ++#ifdef CONFIG_STA_SUPPORT ++#if WIRELESS_EXT >= 12 ++ if (pAd->OpMode == OPMODE_STA) ++ { ++ dev->wireless_handlers = &rt28xx_iw_handler_def; ++ } ++#endif //WIRELESS_EXT >= 12 ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++#if WIRELESS_EXT >= 12 ++ if (pAd->OpMode == OPMODE_AP) ++ { ++ dev->wireless_handlers = &rt28xx_ap_iw_handler_def; ++ } ++#endif //WIRELESS_EXT >= 12 ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++#if WIRELESS_EXT < 21 ++ dev->get_wireless_stats = rt28xx_get_wireless_stats; ++#endif ++ dev->get_stats = RT28xx_get_ether_stats; ++ dev->open = MainVirtualIF_open; //rt28xx_open; ++ dev->stop = MainVirtualIF_close; //rt28xx_close; ++// dev->uninit = ieee80211_if_reinit; ++// dev->destructor = ieee80211_if_free; ++ dev->priv_flags = INT_MAIN; ++ dev->do_ioctl = rt28xx_ioctl; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++ dev->validate_addr = NULL; ++#endif ++ // find available device name ++ for (i = 0; i < 8; i++) ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if (pAd->MC_RowID >= 0) ++ sprintf(slot_name, "ra%02d_%d", pAd->MC_RowID, i); ++ else ++#endif // MULTIPLE_CARD_SUPPORT // ++ sprintf(slot_name, "ra%d", i); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ device = dev_get_by_name(dev_net(dev), slot_name); ++#else ++ device = dev_get_by_name(dev->nd_net, slot_name); ++#endif ++#else ++ device = dev_get_by_name(slot_name); ++#endif ++ if (device != NULL) dev_put(device); ++#else ++ for (device = dev_base; device != NULL; device = device->next) ++ { ++ if (strncmp(device->name, slot_name, 4) == 0) ++ break; ++ } ++#endif ++ if(device == NULL) ++ break; ++ } ++ ++ if(i == 8) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("No available slot name\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++#ifdef MULTIPLE_CARD_SUPPORT ++ if (pAd->MC_RowID >= 0) ++ sprintf(dev->name, "ra%02d_%d", pAd->MC_RowID, i); ++ else ++#endif // MULTIPLE_CARD_SUPPORT // ++ sprintf(dev->name, "ra%d", i); ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ ++ return Status; ++ ++} ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++/* ++======================================================================== ++Routine Description: ++ Get card profile path. ++ ++Arguments: ++ pAd ++ ++Return Value: ++ TRUE - Find a card profile ++ FALSE - use default profile ++ ++Note: ++======================================================================== ++*/ ++extern INT RTMPGetKeyParameter( ++ IN PCHAR key, ++ OUT PCHAR dest, ++ IN INT destsize, ++ IN PCHAR buffer); ++ ++BOOLEAN RTMP_CardInfoRead( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define MC_SELECT_CARDID 0 /* use CARD ID (0 ~ 31) to identify different cards */ ++#define MC_SELECT_MAC 1 /* use CARD MAC to identify different cards */ ++#define MC_SELECT_CARDTYPE 2 /* use CARD type (abgn or bgn) to identify different cards */ ++ ++#define LETTER_CASE_TRANSLATE(txt_p, card_id) \ ++ { UINT32 _len; char _char; \ ++ for(_len=0; _lenfsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid = current->fsgid = 0; ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ // get RF IC type ++ RTMP_IO_READ32(pAd, E2PROM_CSR, &data); ++ ++ if ((data & 0x30) == 0) ++ pAd->EEPROMAddressNum = 6; // 93C46 ++ else if ((data & 0x30) == 0x10) ++ pAd->EEPROMAddressNum = 8; // 93C66 ++ else ++ pAd->EEPROMAddressNum = 8; // 93C86 ++ ++ //antenna.word = RTMP_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET); ++ RT28xx_EEPROM_READ16(pAd, EEPROM_NIC1_OFFSET, antenna.word); ++ ++ if ((antenna.field.RfIcType == RFIC_2850) || ++ (antenna.field.RfIcType == RFIC_2750)) ++ { ++ /* ABGN card */ ++ strcpy(RFIC_word, "abgn"); ++ } ++ else ++ { ++ /* BGN card */ ++ strcpy(RFIC_word, "bgn"); ++ } ++ ++ // get MAC address ++ //addr01 = RTMP_EEPROM_READ16(pAd, 0x04); ++ //addr23 = RTMP_EEPROM_READ16(pAd, 0x06); ++ //addr45 = RTMP_EEPROM_READ16(pAd, 0x08); ++ RT28xx_EEPROM_READ16(pAd, 0x04, addr01); ++ RT28xx_EEPROM_READ16(pAd, 0x06, addr23); ++ RT28xx_EEPROM_READ16(pAd, 0x08, addr45); ++ ++ mac[0] = (UCHAR)(addr01 & 0xff); ++ mac[1] = (UCHAR)(addr01 >> 8); ++ mac[2] = (UCHAR)(addr23 & 0xff); ++ mac[3] = (UCHAR)(addr23 >> 8); ++ mac[4] = (UCHAR)(addr45 & 0xff); ++ mac[5] = (UCHAR)(addr45 >> 8); ++ ++ // open card information file ++ srcf = filp_open(CARD_INFO_PATH, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ /* card information file does not exist */ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("--> Error %ld opening %s\n", -PTR_ERR(srcf), CARD_INFO_PATH)); ++ return FALSE; ++ } ++ ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ /* card information file exists so reading the card information */ ++ memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); ++ retval = srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); ++ if (retval < 0) ++ { ++ /* read fail */ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("--> Read %s error %d\n", CARD_INFO_PATH, -retval)); ++ } ++ else ++ { ++ /* get card selection method */ ++ memset(tmpbuf, 0x00, MAX_PARAM_BUFFER_SIZE); ++ card_select_method = MC_SELECT_CARDTYPE; // default ++ ++ if (RTMPGetKeyParameter("SELECT", tmpbuf, 256, buffer)) ++ { ++ if (strcmp(tmpbuf, "CARDID") == 0) ++ card_select_method = MC_SELECT_CARDID; ++ else if (strcmp(tmpbuf, "MAC") == 0) ++ card_select_method = MC_SELECT_MAC; ++ else if (strcmp(tmpbuf, "CARDTYPE") == 0) ++ card_select_method = MC_SELECT_CARDTYPE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("MC> Card Selection = %d\n", card_select_method)); ++ ++ // init ++ card_free_id = -1; ++ card_nouse_id = -1; ++ card_same_mac_id = -1; ++ card_match_id = -1; ++ ++ // search current card information records ++ for(card_index=0; ++ card_index Free = %d, Same = %d, NOUSE = %d\n", ++ card_free_id, card_same_mac_id, card_nouse_id)); ++ ++ if ((card_same_mac_id >= 0) && ++ ((card_select_method == MC_SELECT_CARDID) || ++ (card_select_method == MC_SELECT_CARDTYPE))) ++ { ++ // same MAC entry is found ++ card_match_id = card_same_mac_id; ++ ++ if (card_select_method == MC_SELECT_CARDTYPE) ++ { ++ // for CARDTYPE ++ sprintf(card_id_buf, "%02dCARDTYPE%s", ++ card_match_id, RFIC_word); ++ ++ if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) ++ { ++ // we found the card ID ++ LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); ++ } ++ } ++ } ++ else ++ { ++ // the card is 1st plug-in, try to find the match card profile ++ switch(card_select_method) ++ { ++ case MC_SELECT_CARDID: // CARDID ++ default: ++ if (card_free_id >= 0) ++ card_match_id = card_free_id; ++ else ++ card_match_id = card_nouse_id; ++ break; ++ ++ case MC_SELECT_MAC: // MAC ++ sprintf(card_id_buf, "MAC%02x:%02x:%02x:%02x:%02x:%02x", ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ ++ /* try to find the key word in the card file */ ++ if ((start_ptr=rtstrstruncasecmp(buffer, card_id_buf)) != NULL) ++ { ++ LETTER_CASE_TRANSLATE(start_ptr, card_id_buf); ++ ++ /* get the row ID (2 ASCII characters) */ ++ start_ptr -= 2; ++ card_id_buf[0] = *(start_ptr); ++ card_id_buf[1] = *(start_ptr+1); ++ card_id_buf[2] = 0x00; ++ ++ card_match_id = simple_strtol(card_id_buf, 0, 10); ++ } ++ break; ++ ++ case MC_SELECT_CARDTYPE: // CARDTYPE ++ card_nouse_id = -1; ++ ++ for(card_index=0; ++ card_index= 0) ++ { ++ // make up search keyword ++ switch(card_select_method) ++ { ++ case MC_SELECT_CARDID: // CARDID ++ sprintf(card_id_buf, "%02dCARDID", card_match_id); ++ break; ++ ++ case MC_SELECT_MAC: // MAC ++ sprintf(card_id_buf, ++ "%02dmac%02x:%02x:%02x:%02x:%02x:%02x", ++ card_match_id, ++ mac[0], mac[1], mac[2], ++ mac[3], mac[4], mac[5]); ++ break; ++ ++ case MC_SELECT_CARDTYPE: // CARDTYPE ++ default: ++ sprintf(card_id_buf, "%02dcardtype%s", ++ card_match_id, RFIC_word); ++ break; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Search Keyword = %s\n", card_id_buf)); ++ ++ // read card file path ++ if (RTMPGetKeyParameter(card_id_buf, tmpbuf, 256, buffer)) ++ { ++ if (strlen(tmpbuf) < sizeof(pAd->MC_FileName)) ++ { ++ // backup card information ++ pAd->MC_RowID = card_match_id; /* base 0 */ ++ MC_CardUsed[card_match_id] = 1; ++ memcpy(MC_CardMac[card_match_id], mac, sizeof(mac)); ++ ++ // backup card file path ++ NdisMoveMemory(pAd->MC_FileName, tmpbuf , strlen(tmpbuf)); ++ pAd->MC_FileName[strlen(tmpbuf)] = '\0'; ++ flg_match_ok = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("Card Profile Name = %s\n", pAd->MC_FileName)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("Card Profile Name length too large!\n")); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("Can not find search key word in card.dat!\n")); ++ } ++ ++ if ((flg_match_ok != TRUE) && ++ (card_match_id < MAX_NUM_OF_MULTIPLE_CARD)) ++ { ++ MC_CardUsed[card_match_id] = 0; ++ memset(MC_CardMac[card_match_id], 0, sizeof(mac)); ++ } ++ } // if (card_match_id >= 0) ++ } ++ } ++ ++ // close file ++ retval = filp_close(srcf, NULL); ++ set_fs(orgfs); ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++ kfree(buffer); ++ kfree(tmpbuf); ++ return flg_match_ok; ++} ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Probe RT28XX chipset. ++ ++Arguments: ++ _dev_p Point to the PCI or USB device ++ _dev_id_p Point to the PCI or USB device ID ++ ++Return Value: ++ 0 Probe OK ++ -ENODEV Probe Fail ++ ++Note: ++======================================================================== ++*/ ++INT __devinit rt28xx_probe( ++ IN void *_dev_p, ++ IN void *_dev_id_p, ++ IN UINT argc, ++ OUT PRTMP_ADAPTER *ppAd) ++{ ++ struct net_device *net_dev; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; ++ INT status; ++ PVOID handle; ++#ifdef RT2870 ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* kernel 2.4 series */ ++ struct usb_device *dev_p = (struct usb_device *)_dev_p; ++#else ++ struct usb_interface *intf = (struct usb_interface *)_dev_p; ++ struct usb_device *dev_p = interface_to_usbdev(intf); ++ ++ dev_p = usb_get_dev(dev_p); ++#endif // LINUX_VERSION_CODE // ++#endif // RT2870 // ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Check chipset vendor/product ID ++// if (RT28XXChipsetCheck(_dev_p) == FALSE) ++// goto err_out; ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++ net_dev = alloc_netdev(sizeof(PRTMP_ADAPTER), "eth%d", ether_setup); ++#else ++ net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); ++#endif ++ if (net_dev == NULL) ++ { ++ printk("alloc_netdev failed\n"); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++ module_put(THIS_MODULE); ++#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++#else ++ MOD_DEC_USE_COUNT; ++#endif ++ goto err_out; ++ } ++ ++// sample ++// if (rt_ieee80211_if_setup(net_dev) != NDIS_STATUS_SUCCESS) ++// goto err_out; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(net_dev); ++#endif ++ ++ netif_stop_queue(net_dev); ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++/* for supporting Network Manager */ ++/* Set the sysfs physical device reference for the network logical device ++ * if set prior to registration will cause a symlink during initialization. ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) ++ SET_NETDEV_DEV(net_dev, &(dev_p->dev)); ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ // Allocate RTMP_ADAPTER miniport adapter structure ++ handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); ++ RT28XX_HANDLE_DEV_ASSIGN(handle, dev_p); ++ ++ status = RTMPAllocAdapterBlock(handle, &pAd); ++ if (status != NDIS_STATUS_SUCCESS) ++ goto err_out_free_netdev; ++ ++ net_dev->ml_priv = (PVOID)pAd; ++ pAd->net_dev = net_dev; // must be before RT28XXNetDevInit() ++ ++ RT28XXNetDevInit(_dev_p, net_dev, pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAd->StaCfg.OriDevType = net_dev->type; ++#endif // CONFIG_STA_SUPPORT // ++ ++ // Find and assign a free interface name, raxx ++// RT28XXAvailRANameAssign(net_dev->name); ++ ++ // Post config ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ if (RT28XXProbePostConfig(_dev_p, pAd, argc) == FALSE) ++ goto err_out_unmap; ++#else ++ if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) ++ goto err_out_unmap; ++#endif // LINUX_VERSION_CODE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ pAd->OpMode = OPMODE_STA; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++ // find its profile path ++ pAd->MC_RowID = -1; // use default profile path ++ RTMP_CardInfoRead(pAd); ++ ++ if (pAd->MC_RowID == -1) ++#ifdef CONFIG_STA_SUPPORT ++ strcpy(pAd->MC_FileName, STA_PROFILE_PATH); ++#endif // CONFIG_STA_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ++ ("MC> ROW = %d, PATH = %s\n", pAd->MC_RowID, pAd->MC_FileName)); ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ // sample move ++ if (rt_ieee80211_if_setup(net_dev, pAd) != NDIS_STATUS_SUCCESS) ++ goto err_out_unmap; ++ ++ // Register this device ++ status = register_netdev(net_dev); ++ if (status) ++ goto err_out_unmap; ++ ++ // Set driver data ++ RT28XX_DRVDATA_SET(_dev_p); ++ ++ ++ ++ *ppAd = pAd; ++ return 0; // probe ok ++ ++ ++ /* --------------------------- ERROR HANDLE --------------------------- */ ++err_out_unmap: ++ RTMPFreeAdapter(pAd); ++ RT28XX_UNMAP(); ++ ++err_out_free_netdev: ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ++ free_netdev(net_dev); ++#else ++ kfree(net_dev); ++#endif ++ ++err_out: ++ RT28XX_PUT_DEVICE(dev_p); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++ return (LONG)NULL; ++#else ++ return -ENODEV; /* probe fail */ ++#endif // LINUX_VERSION_CODE // ++} /* End of rt28xx_probe */ ++ ++ ++/* ++======================================================================== ++Routine Description: ++ The entry point for Linux kernel sent packet to our driver. ++ ++Arguments: ++ sk_buff *skb the pointer refer to a sk_buffer. ++ ++Return Value: ++ 0 ++ ++Note: ++ This function is the entry point of Tx Path for Os delivery packet to ++ our driver. You only can put OS-depened & STA/AP common handle procedures ++ in here. ++======================================================================== ++*/ ++int rt28xx_packet_xmit(struct sk_buff *skb) ++{ ++ struct net_device *net_dev = skb->dev; ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; ++ int status = 0; ++ PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; ++ ++ /* RT2870STA does this in RTMPSendPackets() */ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_RESOURCES); ++ return 0; ++ } ++#endif // RALINK_ATE // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ // Drop send request since we are in monitor mode ++ if (MONITOR_ON(pAd)) ++ { ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ goto done; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ // EapolStart size is 18 ++ if (skb->len < 14) ++ { ++ //printk("bad packet size: %d\n", pkt->len); ++ hex_dump("bad packet", skb->data, skb->len); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ goto done; ++ } ++ ++ RTMP_SET_PACKET_5VT(pPacket, 0); ++// MiniportMMRequest(pAd, pkt->data, pkt->len); ++#ifdef CONFIG_5VT_ENHANCE ++ if (*(int*)(skb->cb) == BRIDGE_TAG) { ++ RTMP_SET_PACKET_5VT(pPacket, 1); ++ } ++#endif ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ++ STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1); ++ } ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ status = 0; ++done: ++ ++ return status; ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ Send a packet to WLAN. ++ ++Arguments: ++ skb_p points to our adapter ++ dev_p which WLAN network interface ++ ++Return Value: ++ 0: transmit successfully ++ otherwise: transmit fail ++ ++Note: ++======================================================================== ++*/ ++INT rt28xx_send_packets( ++ IN struct sk_buff *skb_p, ++ IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; ++ ++ if (!(net_dev->flags & IFF_UP)) ++ { ++ RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); ++ return 0; ++ } ++ ++ NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15); ++ RTMP_SET_PACKET_NET_DEVICE_MBSSID(skb_p, MAIN_MBSSID); ++ ++ return rt28xx_packet_xmit(skb_p); ++} /* End of MBSS_VirtualIF_PacketSend */ ++ ++ ++ ++ ++#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 ++//static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, void (*setup)(struct net_device *)) //sample ++struct net_device *alloc_netdev( ++ int sizeof_priv, ++ const char *mask, ++ void (*setup)(struct net_device *)) ++{ ++ struct net_device *dev; ++ INT alloc_size; ++ ++ ++ /* ensure 32-byte alignment of the private area */ ++ alloc_size = sizeof (*dev) + sizeof_priv + 31; ++ ++ dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); ++ if (dev == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ++ ("alloc_netdev: Unable to allocate device memory.\n")); ++ return NULL; ++ } ++ ++ memset(dev, 0, alloc_size); ++ ++ if (sizeof_priv) ++ dev->ml_priv = (void *) (((long)(dev + 1) + 31) & ~31); ++ ++ setup(dev); ++ strcpy(dev->name, mask); ++ ++ return dev; ++} ++#endif // LINUX_VERSION_CODE // ++ ++ ++void CfgInitHook(PRTMP_ADAPTER pAd) ++{ ++ pAd->bBroadComHT = TRUE; ++} /* End of CfgInitHook */ ++ ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev) ++{ ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt28xx_get_wireless_stats --->\n")); ++ ++ pAd->iw_stats.status = 0; // Status - device dependent for now ++ ++ // link quality ++ pAd->iw_stats.qual.qual = ((pAd->Mlme.ChannelQuality * 12)/10 + 10); ++ if(pAd->iw_stats.qual.qual > 100) ++ pAd->iw_stats.qual.qual = 100; ++ ++#ifdef CONFIG_STA_SUPPORT ++ if (pAd->OpMode == OPMODE_STA) ++ pAd->iw_stats.qual.level = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); ++#endif // CONFIG_STA_SUPPORT // ++ ++ pAd->iw_stats.qual.noise = pAd->BbpWriteLatch[66]; // noise level (dBm) ++ ++ pAd->iw_stats.qual.noise += 256 - 143; ++ pAd->iw_stats.qual.updated = 1; // Flags to know if updated ++#ifdef IW_QUAL_DBM ++ pAd->iw_stats.qual.updated |= IW_QUAL_DBM; // Level + Noise are dBm ++#endif // IW_QUAL_DBM // ++ ++ pAd->iw_stats.discard.nwid = 0; // Rx : Wrong nwid/essid ++ pAd->iw_stats.miss.beacon = 0; // Missed beacons/superframe ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- rt28xx_get_wireless_stats\n")); ++ return &pAd->iw_stats; ++} /* End of rt28xx_get_wireless_stats */ ++#endif // WIRELESS_EXT // ++ ++ ++ ++void tbtt_tasklet(unsigned long data) ++{ ++#define MAX_TX_IN_TBTT (16) ++ ++} ++ ++INT rt28xx_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ INT ret = 0; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->ml_priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->ml_priv; ++ pAd = pVirtualAd->RtmpDev->ml_priv; ++ } ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->ml_priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ ret = rt28xx_sta_ioctl(net_dev, rq, cmd); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ return ret; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ return ethernet statistics counter ++ ++ Arguments: ++ net_dev Pointer to net_device ++ ++ Return Value: ++ net_device_stats* ++ ++ Note: ++ ++ ======================================================================== ++*/ ++struct net_device_stats *RT28xx_get_ether_stats( ++ IN struct net_device *net_dev) ++{ ++ RTMP_ADAPTER *pAd = NULL; ++ ++ if (net_dev) ++ pAd = net_dev->ml_priv; ++ ++ if (pAd) ++ { ++ ++ pAd->stats.rx_packets = pAd->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pAd->stats.tx_packets = pAd->WlanCounters.TransmittedFragmentCount.QuadPart; ++ ++ pAd->stats.rx_bytes = pAd->RalinkCounters.ReceivedByteCount; ++ pAd->stats.tx_bytes = pAd->RalinkCounters.TransmittedByteCount; ++ ++ pAd->stats.rx_errors = pAd->Counters8023.RxErrors; ++ pAd->stats.tx_errors = pAd->Counters8023.TxErrors; ++ ++ pAd->stats.rx_dropped = 0; ++ pAd->stats.tx_dropped = 0; ++ ++ pAd->stats.multicast = pAd->WlanCounters.MulticastReceivedFrameCount.QuadPart; // multicast packets received ++ pAd->stats.collisions = pAd->Counters8023.OneCollision + pAd->Counters8023.MoreCollisions; // Collision packets ++ ++ pAd->stats.rx_length_errors = 0; ++ pAd->stats.rx_over_errors = pAd->Counters8023.RxNoBuffer; // receiver ring buff overflow ++ pAd->stats.rx_crc_errors = 0;//pAd->WlanCounters.FCSErrorCount; // recved pkt with crc error ++ pAd->stats.rx_frame_errors = pAd->Counters8023.RcvAlignmentErrors; // recv'd frame alignment error ++ pAd->stats.rx_fifo_errors = pAd->Counters8023.RxNoBuffer; // recv'r fifo overrun ++ pAd->stats.rx_missed_errors = 0; // receiver missed packet ++ ++ // detailed tx_errors ++ pAd->stats.tx_aborted_errors = 0; ++ pAd->stats.tx_carrier_errors = 0; ++ pAd->stats.tx_fifo_errors = 0; ++ pAd->stats.tx_heartbeat_errors = 0; ++ pAd->stats.tx_window_errors = 0; ++ ++ // for cslip etc ++ pAd->stats.rx_compressed = 0; ++ pAd->stats.tx_compressed = 0; ++ ++ return &pAd->stats; ++ } ++ else ++ return NULL; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rtmp_ckipmic.h +@@ -0,0 +1,113 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_ckipmic.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++#ifndef __RTMP_CKIPMIC_H__ ++#define __RTMP_CKIPMIC_H__ ++ ++typedef struct _MIC_CONTEXT { ++ /* --- MMH context */ ++ UCHAR CK[16]; /* the key */ ++ UCHAR coefficient[16]; /* current aes counter mode coefficients */ ++ ULONGLONG accum; /* accumulated mic, reduced to u32 in final() */ ++ UINT position; /* current position (byte offset) in message */ ++ UCHAR part[4]; /* for conversion of message to u32 for mmh */ ++} MIC_CONTEXT, *PMIC_CONTEXT; ++ ++VOID CKIP_key_permute( ++ OUT UCHAR *PK, /* output permuted key */ ++ IN UCHAR *CK, /* input CKIP key */ ++ IN UCHAR toDsFromDs, /* input toDs/FromDs bits */ ++ IN UCHAR *piv); /* input pointer to IV */ ++ ++VOID RTMPCkipMicInit( ++ IN PMIC_CONTEXT pContext, ++ IN PUCHAR CK); ++ ++VOID RTMPMicUpdate( ++ IN PMIC_CONTEXT pContext, ++ IN PUCHAR pOctets, ++ IN INT len); ++ ++ULONG RTMPMicGetCoefficient( ++ IN PMIC_CONTEXT pContext); ++ ++VOID xor_128( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++UCHAR RTMPCkipSbox( ++ IN UCHAR a); ++ ++VOID xor_32( ++ IN PUCHAR a, ++ IN PUCHAR b, ++ OUT PUCHAR out); ++ ++VOID next_key( ++ IN PUCHAR key, ++ IN INT round); ++ ++VOID byte_sub( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID shift_row( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID mix_column( ++ IN PUCHAR in, ++ OUT PUCHAR out); ++ ++VOID RTMPAesEncrypt( ++ IN PUCHAR key, ++ IN PUCHAR data, ++ IN PUCHAR ciphertext); ++ ++VOID RTMPMicFinal( ++ IN PMIC_CONTEXT pContext, ++ OUT UCHAR digest[4]); ++ ++VOID RTMPCkipInsertCMIC( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pMIC, ++ IN PUCHAR p80211hdr, ++ IN PNDIS_PACKET pPacket, ++ IN PCIPHER_KEY pKey, ++ IN PUCHAR mic_snap); ++ ++#endif //__RTMP_CKIPMIC_H__ +--- /dev/null ++++ b/drivers/staging/rt3070/rtmp_def.h +@@ -0,0 +1,1559 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_def.h ++ ++ Abstract: ++ Miniport related definition header ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 08-01-2002 created ++ John Chang 08-05-2003 add definition for 11g & other drafts ++*/ ++#ifndef __RTMP_DEF_H__ ++#define __RTMP_DEF_H__ ++ ++#include "oid.h" ++ ++#undef AP_WSC_INCLUDED ++#undef STA_WSC_INCLUDED ++#undef WSC_INCLUDED ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) ++#define WSC_INCLUDED ++#endif ++// ++// Debug information verbosity: lower values indicate higher urgency ++// ++#define RT_DEBUG_OFF 0 ++#define RT_DEBUG_ERROR 1 ++#define RT_DEBUG_WARN 2 ++#define RT_DEBUG_TRACE 3 ++#define RT_DEBUG_INFO 4 ++#define RT_DEBUG_LOUD 5 ++ ++#define NIC_TAG ((ULONG)'0682') ++#define NIC_DBG_STRING ("**RT28xx**") ++ ++#ifdef SNMP_SUPPORT ++// for snmp ++// to get manufacturer OUI, kathy, 2008_0220 ++#define ManufacturerOUI_LEN 3 ++#define ManufacturerNAME ("Ralink Technology Company.") ++#define ResourceTypeIdName ("Ralink_ID") ++#endif ++ ++ ++//#define PACKED ++ ++#define RALINK_2883_VERSION ((UINT32)0x28830300) ++#define RALINK_2880E_VERSION ((UINT32)0x28720200) ++#define RALINK_3070_VERSION ((UINT32)0x30700200) ++ ++// ++// NDIS version in use by the NIC driver. ++// The high byte is the major version. The low byte is the minor version. ++// ++#ifdef NDIS51_MINIPORT ++#define NIC_DRIVER_VERSION 0x0501 ++#else ++#define NIC_DRIVER_VERSION 0x0500 ++#endif ++ ++// ++// NDIS media type, current is ethernet, change if native wireless supported ++// ++#define NIC_MEDIA_TYPE NdisMedium802_3 ++#define NIC_PCI_HDR_LENGTH 0xe2 ++#define NIC_MAX_PACKET_SIZE 2304 ++#define NIC_HEADER_SIZE 14 ++#define MAX_MAP_REGISTERS_NEEDED 32 ++#define MIN_MAP_REGISTERS_NEEDED 2 //Todo: should consider fragment issue. ++ ++// ++// interface type, we use PCI ++// ++#define NIC_INTERFACE_TYPE NdisInterfacePci ++#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive ++ ++// ++// buffer size passed in NdisMQueryAdapterResources ++// We should only need three adapter resources (IO, interrupt and memory), ++// Some devices get extra resources, so have room for 10 resources ++// UF_SIZE (sizeof(NDIS_RESOURCE_LIST) + (10*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))) ++ ++ ++#define NIC_RESOURCE_B// ++// IO space length ++// ++#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC) ++ ++#define MAX_RX_PKT_LEN 1520 ++ ++// ++// Entry number for each DMA descriptor ring ++// ++ ++ ++#ifdef RT2870 ++#define TX_RING_SIZE 8 // 1 ++#define PRIO_RING_SIZE 8 ++#define MGMT_RING_SIZE 32 // PRIO_RING_SIZE ++#define RX_RING_SIZE 8 ++#define MAX_TX_PROCESS 4 ++#define LOCAL_TXBUF_SIZE 2048 ++#endif // RT2870 // ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++// MC: Multple Cards ++#define MAX_NUM_OF_MULTIPLE_CARD 32 ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++#define MAX_RX_PROCESS 128 //64 //32 ++#define NUM_OF_LOCAL_TXBUF 2 ++#define TXD_SIZE 16 ++#define TXWI_SIZE 16 ++#define RXD_SIZE 16 ++#define RXWI_SIZE 16 ++// TXINFO_SIZE + TXWI_SIZE + 802.11 Header Size + AMSDU sub frame header ++#define TX_DMA_1ST_BUFFER_SIZE 96 // only the 1st physical buffer is pre-allocated ++#define MGMT_DMA_BUFFER_SIZE 1536 //2048 ++#define RX_BUFFER_AGGRESIZE 3840 //3904 //3968 //4096 //2048 //4096 ++#define RX_BUFFER_NORMSIZE 3840 //3904 //3968 //4096 //2048 //4096 ++#define TX_BUFFER_NORMSIZE RX_BUFFER_NORMSIZE ++#define MAX_FRAME_SIZE 2346 // Maximum 802.11 frame size ++#define MAX_AGGREGATION_SIZE 3840 //3904 //3968 //4096 ++#define MAX_NUM_OF_TUPLE_CACHE 2 ++#define MAX_MCAST_LIST_SIZE 32 ++#define MAX_LEN_OF_VENDOR_DESC 64 ++//#define MAX_SIZE_OF_MCAST_PSQ (NUM_OF_LOCAL_TXBUF >> 2) // AP won't spend more than 1/4 of total buffers on M/BCAST PSQ ++#define MAX_SIZE_OF_MCAST_PSQ 32 ++ ++#define MAX_RX_PROCESS_CNT (RX_RING_SIZE) ++ ++ ++#define MAX_PACKETS_IN_QUEUE (512) //(512) // to pass WMM A5-WPAPSK ++#define MAX_PACKETS_IN_MCAST_PS_QUEUE 32 ++#define MAX_PACKETS_IN_PS_QUEUE 128 //32 ++#define WMM_NUM_OF_AC 4 /* AC0, AC1, AC2, and AC3 */ ++ ++ ++//2008/09/11:KH add to support efuse<-- ++#define MAX_EEPROM_BIN_FILE_SIZE 1024 ++//2008/09/11:KH add to support efuse--> ++ ++// RxFilter ++#define STANORMAL 0x17f97 ++#define APNORMAL 0x15f97 ++// ++// RTMP_ADAPTER flags ++// ++#define fRTMP_ADAPTER_MAP_REGISTER 0x00000001 ++#define fRTMP_ADAPTER_INTERRUPT_IN_USE 0x00000002 ++#define fRTMP_ADAPTER_HARDWARE_ERROR 0x00000004 ++#define fRTMP_ADAPTER_SCATTER_GATHER 0x00000008 ++#define fRTMP_ADAPTER_SEND_PACKET_ERROR 0x00000010 ++#define fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS 0x00000020 ++#define fRTMP_ADAPTER_HALT_IN_PROGRESS 0x00000040 ++#define fRTMP_ADAPTER_RESET_IN_PROGRESS 0x00000080 ++#define fRTMP_ADAPTER_NIC_NOT_EXIST 0x00000100 ++#define fRTMP_ADAPTER_TX_RING_ALLOCATED 0x00000200 ++#define fRTMP_ADAPTER_REMOVE_IN_PROGRESS 0x00000400 ++#define fRTMP_ADAPTER_MIMORATE_INUSED 0x00000800 ++#define fRTMP_ADAPTER_RX_RING_ALLOCATED 0x00001000 ++#define fRTMP_ADAPTER_INTERRUPT_ACTIVE 0x00002000 ++#define fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS 0x00004000 ++#define fRTMP_ADAPTER_REASSOC_IN_PROGRESS 0x00008000 ++#define fRTMP_ADAPTER_MEDIA_STATE_PENDING 0x00010000 ++#define fRTMP_ADAPTER_RADIO_OFF 0x00020000 ++#define fRTMP_ADAPTER_BULKOUT_RESET 0x00040000 ++#define fRTMP_ADAPTER_BULKIN_RESET 0x00080000 ++#define fRTMP_ADAPTER_RDG_ACTIVE 0x00100000 ++#define fRTMP_ADAPTER_DYNAMIC_BE_TXOP_ACTIVE 0x00200000 ++#define fRTMP_ADAPTER_SCAN_2040 0x04000000 ++#define fRTMP_ADAPTER_RADIO_MEASUREMENT 0x08000000 ++ ++#define fRTMP_ADAPTER_START_UP 0x10000000 //Devive already initialized and enabled Tx/Rx. ++#define fRTMP_ADAPTER_MEDIA_STATE_CHANGE 0x20000000 ++#define fRTMP_ADAPTER_IDLE_RADIO_OFF 0x40000000 ++ ++// Lock bit for accessing different ring buffers ++//#define fRTMP_ADAPTER_TX_RING_BUSY 0x80000000 ++//#define fRTMP_ADAPTER_MGMT_RING_BUSY 0x40000000 ++//#define fRTMP_ADAPTER_ATIM_RING_BUSY 0x20000000 ++//#define fRTMP_ADAPTER_RX_RING_BUSY 0x10000000 ++ ++// Lock bit for accessing different queue ++//#define fRTMP_ADAPTER_TX_QUEUE_BUSY 0x08000000 ++//#define fRTMP_ADAPTER_MGMT_QUEUE_BUSY 0x04000000 ++ ++// ++// STA operation status flags ++// ++#define fOP_STATUS_INFRA_ON 0x00000001 ++#define fOP_STATUS_ADHOC_ON 0x00000002 ++#define fOP_STATUS_BG_PROTECTION_INUSED 0x00000004 ++#define fOP_STATUS_SHORT_SLOT_INUSED 0x00000008 ++#define fOP_STATUS_SHORT_PREAMBLE_INUSED 0x00000010 ++#define fOP_STATUS_RECEIVE_DTIM 0x00000020 ++//#define fOP_STATUS_TX_RATE_SWITCH_ENABLED 0x00000040 ++#define fOP_STATUS_MEDIA_STATE_CONNECTED 0x00000080 ++#define fOP_STATUS_WMM_INUSED 0x00000100 ++#define fOP_STATUS_AGGREGATION_INUSED 0x00000200 ++#define fOP_STATUS_DOZE 0x00000400 // debug purpose ++#define fOP_STATUS_PIGGYBACK_INUSED 0x00000800 // piggy-back, and aggregation ++#define fOP_STATUS_APSD_INUSED 0x00001000 ++#define fOP_STATUS_TX_AMSDU_INUSED 0x00002000 ++#define fOP_STATUS_MAX_RETRY_ENABLED 0x00004000 ++#define fOP_STATUS_WAKEUP_NOW 0x00008000 ++#define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 ++ ++#ifdef DOT11N_DRAFT3 ++#define fOP_STATUS_SCAN_2040 0x00040000 ++#endif // DOT11N_DRAFT3 // ++ ++#define CCKSETPROTECT 0x1 ++#define OFDMSETPROTECT 0x2 ++#define MM20SETPROTECT 0x4 ++#define MM40SETPROTECT 0x8 ++#define GF20SETPROTECT 0x10 ++#define GR40SETPROTECT 0x20 ++#define ALLN_SETPROTECT (GR40SETPROTECT | GF20SETPROTECT | MM40SETPROTECT | MM20SETPROTECT) ++ ++// ++// AP's client table operation status flags ++// ++#define fCLIENT_STATUS_WMM_CAPABLE 0x00000001 // CLIENT can parse QOS DATA frame ++#define fCLIENT_STATUS_AGGREGATION_CAPABLE 0x00000002 // CLIENT can receive Ralink's proprietary TX aggregation frame ++#define fCLIENT_STATUS_PIGGYBACK_CAPABLE 0x00000004 // CLIENT support piggy-back ++#define fCLIENT_STATUS_AMSDU_INUSED 0x00000008 ++#define fCLIENT_STATUS_SGI20_CAPABLE 0x00000010 ++#define fCLIENT_STATUS_SGI40_CAPABLE 0x00000020 ++#define fCLIENT_STATUS_TxSTBC_CAPABLE 0x00000040 ++#define fCLIENT_STATUS_RxSTBC_CAPABLE 0x00000080 ++#define fCLIENT_STATUS_HTC_CAPABLE 0x00000100 ++#define fCLIENT_STATUS_RDG_CAPABLE 0x00000200 ++#define fCLIENT_STATUS_MCSFEEDBACK_CAPABLE 0x00000400 ++#define fCLIENT_STATUS_APSD_CAPABLE 0x00000800 /* UAPSD STATION */ ++ ++#ifdef DOT11N_DRAFT3 ++#define fCLIENT_STATUS_BSSCOEXIST_CAPABLE 0x00001000 ++#endif // DOT11N_DRAFT3 // ++ ++#define fCLIENT_STATUS_RALINK_CHIPSET 0x00100000 ++// ++// STA configuration flags ++// ++//#define fSTA_CFG_ENABLE_TX_BURST 0x00000001 ++ ++// 802.11n Operating Mode Definition. 0-3 also used in ASICUPdateProtect switch case ++#define HT_NO_PROTECT 0 ++#define HT_LEGACY_PROTECT 1 ++#define HT_40_PROTECT 2 ++#define HT_2040_PROTECT 3 ++#define HT_RTSCTS_6M 7 ++//following is our own definition in order to turn on our ASIC protection register in INFRASTRUCTURE. ++#define HT_ATHEROS 8 ++#define HT_FORCERTSCTS 9 // Force turn on RTS/CTS first. then go to evaluate if this force RTS is necessary. ++ ++// ++// RX Packet Filter control flags. Apply on pAd->PacketFilter ++// ++#define fRX_FILTER_ACCEPT_DIRECT NDIS_PACKET_TYPE_DIRECTED ++#define fRX_FILTER_ACCEPT_MULTICAST NDIS_PACKET_TYPE_MULTICAST ++#define fRX_FILTER_ACCEPT_BROADCAST NDIS_PACKET_TYPE_BROADCAST ++#define fRX_FILTER_ACCEPT_ALL_MULTICAST NDIS_PACKET_TYPE_ALL_MULTICAST ++ ++// ++// Error code section ++// ++// NDIS_ERROR_CODE_ADAPTER_NOT_FOUND ++#define ERRLOG_READ_PCI_SLOT_FAILED 0x00000101L ++#define ERRLOG_WRITE_PCI_SLOT_FAILED 0x00000102L ++#define ERRLOG_VENDOR_DEVICE_NOMATCH 0x00000103L ++ ++// NDIS_ERROR_CODE_ADAPTER_DISABLED ++#define ERRLOG_BUS_MASTER_DISABLED 0x00000201L ++ ++// NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION ++#define ERRLOG_INVALID_SPEED_DUPLEX 0x00000301L ++#define ERRLOG_SET_SECONDARY_FAILED 0x00000302L ++ ++// NDIS_ERROR_CODE_OUT_OF_RESOURCES ++#define ERRLOG_OUT_OF_MEMORY 0x00000401L ++#define ERRLOG_OUT_OF_SHARED_MEMORY 0x00000402L ++#define ERRLOG_OUT_OF_MAP_REGISTERS 0x00000403L ++#define ERRLOG_OUT_OF_BUFFER_POOL 0x00000404L ++#define ERRLOG_OUT_OF_NDIS_BUFFER 0x00000405L ++#define ERRLOG_OUT_OF_PACKET_POOL 0x00000406L ++#define ERRLOG_OUT_OF_NDIS_PACKET 0x00000407L ++#define ERRLOG_OUT_OF_LOOKASIDE_MEMORY 0x00000408L ++ ++// NDIS_ERROR_CODE_HARDWARE_FAILURE ++#define ERRLOG_SELFTEST_FAILED 0x00000501L ++#define ERRLOG_INITIALIZE_ADAPTER 0x00000502L ++#define ERRLOG_REMOVE_MINIPORT 0x00000503L ++ ++// NDIS_ERROR_CODE_RESOURCE_CONFLICT ++#define ERRLOG_MAP_IO_SPACE 0x00000601L ++#define ERRLOG_QUERY_ADAPTER_RESOURCES 0x00000602L ++#define ERRLOG_NO_IO_RESOURCE 0x00000603L ++#define ERRLOG_NO_INTERRUPT_RESOURCE 0x00000604L ++#define ERRLOG_NO_MEMORY_RESOURCE 0x00000605L ++ ++ ++// WDS definition ++#define MAX_WDS_ENTRY 4 ++#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table ++ ++#define WDS_DISABLE_MODE 0 ++#define WDS_RESTRICT_MODE 1 ++#define WDS_BRIDGE_MODE 2 ++#define WDS_REPEATER_MODE 3 ++#define WDS_LAZY_MODE 4 ++ ++ ++#define MAX_MESH_NUM 0 ++ ++#define MAX_APCLI_NUM 0 ++ ++#define MAX_MBSSID_NUM 1 ++#ifdef MBSS_SUPPORT ++#undef MAX_MBSSID_NUM ++#define MAX_MBSSID_NUM (8 - MAX_MESH_NUM - MAX_APCLI_NUM) ++#endif // MBSS_SUPPORT // ++ ++/* sanity check for apidx */ ++#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ ++ { if (apidx > MAX_MBSSID_NUM) { \ ++ printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \ ++ apidx = MAIN_MBSSID; } } ++ ++#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE ) ++ ++#define MAIN_MBSSID 0 ++#define FIRST_MBSSID 1 ++ ++ ++#define MAX_BEACON_SIZE 512 ++// If the MAX_MBSSID_NUM is larger than 6, ++// it shall reserve some WCID space(wcid 222~253) for beacon frames. ++// - these wcid 238~253 are reserved for beacon#6(ra6). ++// - these wcid 222~237 are reserved for beacon#7(ra7). ++#if defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 8) ++#define HW_RESERVED_WCID 222 ++#elif defined(MAX_MBSSID_NUM) && (MAX_MBSSID_NUM == 7) ++#define HW_RESERVED_WCID 238 ++#else ++#define HW_RESERVED_WCID 255 ++#endif ++ ++// Then dedicate wcid of DFS and Carrier-Sense. ++#define DFS_CTS_WCID (HW_RESERVED_WCID - 1) ++#define CS_CTS_WCID (HW_RESERVED_WCID - 2) ++#define LAST_SPECIFIC_WCID (HW_RESERVED_WCID - 2) ++ ++// If MAX_MBSSID_NUM is 8, the maximum available wcid for the associated STA is 211. ++// If MAX_MBSSID_NUM is 7, the maximum available wcid for the associated STA is 228. ++#define MAX_AVAILABLE_CLIENT_WCID (LAST_SPECIFIC_WCID - MAX_MBSSID_NUM - 1) ++ ++// TX need WCID to find Cipher Key ++// these wcid 212 ~ 219 are reserved for bc/mc packets if MAX_MBSSID_NUM is 8. ++#define GET_GroupKey_WCID(__wcid, __bssidx) \ ++ { \ ++ __wcid = LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM) + __bssidx; \ ++ } ++ ++#define IsGroupKeyWCID(__wcid) (((__wcid) < LAST_SPECIFIC_WCID) && ((__wcid) >= (LAST_SPECIFIC_WCID - (MAX_MBSSID_NUM)))) ++ ++ ++// definition to support multiple BSSID ++#define BSS0 0 ++#define BSS1 1 ++#define BSS2 2 ++#define BSS3 3 ++#define BSS4 4 ++#define BSS5 5 ++#define BSS6 6 ++#define BSS7 7 ++ ++ ++//============================================================ ++// Length definitions ++#define PEER_KEY_NO 2 ++#define MAC_ADDR_LEN 6 ++#define TIMESTAMP_LEN 8 ++#define MAX_LEN_OF_SUPPORTED_RATES MAX_LENGTH_OF_SUPPORT_RATES // 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 ++#define MAX_LEN_OF_KEY 32 // 32 octets == 256 bits, Redefine for WPA ++#define MAX_NUM_OF_CHANNELS MAX_NUM_OF_CHS // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination ++#define MAX_NUM_OF_11JCHANNELS 20 // 14 channels @2.4G + 12@UNII + 4 @MMAC + 11 @HiperLAN2 + 7 @Japan + 1 as NULL termination ++#define MAX_LEN_OF_SSID 32 ++#define CIPHER_TEXT_LEN 128 ++#define HASH_TABLE_SIZE 256 ++#define MAX_VIE_LEN 1024 // New for WPA cipher suite variable IE sizes. ++#define MAX_SUPPORT_MCS 32 ++ ++//============================================================ ++// ASIC WCID Table definition. ++//============================================================ ++#define BSSID_WCID 1 // in infra mode, always put bssid with this WCID ++#define MCAST_WCID 0x0 ++#define BSS0Mcast_WCID 0x0 ++#define BSS1Mcast_WCID 0xf8 ++#define BSS2Mcast_WCID 0xf9 ++#define BSS3Mcast_WCID 0xfa ++#define BSS4Mcast_WCID 0xfb ++#define BSS5Mcast_WCID 0xfc ++#define BSS6Mcast_WCID 0xfd ++#define BSS7Mcast_WCID 0xfe ++#define RESERVED_WCID 0xff ++ ++#define MAX_NUM_OF_ACL_LIST MAX_NUMBER_OF_ACL ++ ++#define MAX_LEN_OF_MAC_TABLE MAX_NUMBER_OF_MAC // if MAX_MBSSID_NUM is 8, this value can't be larger than 211 ++ ++#if MAX_LEN_OF_MAC_TABLE>MAX_AVAILABLE_CLIENT_WCID ++#error MAX_LEN_OF_MAC_TABLE can not be larger than MAX_AVAILABLE_CLIENT_WCID!!!! ++#endif ++ ++#define MAX_NUM_OF_WDS_LINK_PERBSSID 3 ++#define MAX_NUM_OF_WDS_LINK (MAX_NUM_OF_WDS_LINK_PERBSSID*MAX_MBSSID_NUM) ++#define MAX_NUM_OF_EVENT MAX_NUMBER_OF_EVENT ++#define WDS_LINK_START_WCID (MAX_LEN_OF_MAC_TABLE-1) ++ ++#define NUM_OF_TID 8 ++#define MAX_AID_BA 4 ++#define MAX_LEN_OF_BA_REC_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) //Block ACK recipient ++#define MAX_LEN_OF_BA_ORI_TABLE ((NUM_OF_TID * MAX_LEN_OF_MAC_TABLE)/2)// (NUM_OF_TID*MAX_AID_BA + 32) // Block ACK originator ++#define MAX_LEN_OF_BSS_TABLE 64 ++#define MAX_REORDERING_MPDU_NUM 512 ++ ++// key related definitions ++#define SHARE_KEY_NUM 4 ++#define MAX_LEN_OF_SHARE_KEY 16 // byte count ++#define MAX_LEN_OF_PEER_KEY 16 // byte count ++#define PAIRWISE_KEY_NUM 64 // in MAC ASIC pairwise key table ++#define GROUP_KEY_NUM 4 ++#define PMK_LEN 32 ++#define WDS_PAIRWISE_KEY_OFFSET 60 // WDS links uses pairwise key#60 ~ 63 in ASIC pairwise key table ++#define PMKID_NO 4 // Number of PMKID saved supported ++#define MAX_LEN_OF_MLME_BUFFER 2048 ++ ++// power status related definitions ++#define PWR_ACTIVE 0 ++#define PWR_SAVE 1 ++#define PWR_MMPS 2 //MIMO power save ++//#define PWR_UNKNOWN 2 ++ ++// Auth and Assoc mode related definitions ++#define AUTH_MODE_OPEN 0x00 ++#define AUTH_MODE_KEY 0x01 ++//#define AUTH_MODE_AUTO_SWITCH 0x03 ++//#define AUTH_MODE_DEAUTH 0x04 ++//#define AUTH_MODE_UPLAYER 0x05 // reserved for 802.11i use ++ ++// BSS Type definitions ++#define BSS_ADHOC 0 // = Ndis802_11IBSS ++#define BSS_INFRA 1 // = Ndis802_11Infrastructure ++#define BSS_ANY 2 // = Ndis802_11AutoUnknown ++#define BSS_MONITOR 3 // = Ndis802_11Monitor ++ ++ ++// Reason code definitions ++#define REASON_RESERVED 0 ++#define REASON_UNSPECIFY 1 ++#define REASON_NO_LONGER_VALID 2 ++#define REASON_DEAUTH_STA_LEAVING 3 ++#define REASON_DISASSOC_INACTIVE 4 ++#define REASON_DISASSPC_AP_UNABLE 5 ++#define REASON_CLS2ERR 6 ++#define REASON_CLS3ERR 7 ++#define REASON_DISASSOC_STA_LEAVING 8 ++#define REASON_STA_REQ_ASSOC_NOT_AUTH 9 ++#define REASON_INVALID_IE 13 ++#define REASON_MIC_FAILURE 14 ++#define REASON_4_WAY_TIMEOUT 15 ++#define REASON_GROUP_KEY_HS_TIMEOUT 16 ++#define REASON_IE_DIFFERENT 17 ++#define REASON_MCIPHER_NOT_VALID 18 ++#define REASON_UCIPHER_NOT_VALID 19 ++#define REASON_AKMP_NOT_VALID 20 ++#define REASON_UNSUPPORT_RSNE_VER 21 ++#define REASON_INVALID_RSNE_CAP 22 ++#define REASON_8021X_AUTH_FAIL 23 ++#define REASON_CIPHER_SUITE_REJECTED 24 ++#define REASON_DECLINED 37 ++ ++#define REASON_QOS_UNSPECIFY 32 ++#define REASON_QOS_LACK_BANDWIDTH 33 ++#define REASON_POOR_CHANNEL_CONDITION 34 ++#define REASON_QOS_OUTSIDE_TXOP_LIMITION 35 ++#define REASON_QOS_QSTA_LEAVING_QBSS 36 ++#define REASON_QOS_UNWANTED_MECHANISM 37 ++#define REASON_QOS_MECH_SETUP_REQUIRED 38 ++#define REASON_QOS_REQUEST_TIMEOUT 39 ++#define REASON_QOS_CIPHER_NOT_SUPPORT 45 ++ ++// Status code definitions ++#define MLME_SUCCESS 0 ++#define MLME_UNSPECIFY_FAIL 1 ++#define MLME_CANNOT_SUPPORT_CAP 10 ++#define MLME_REASSOC_DENY_ASSOC_EXIST 11 ++#define MLME_ASSOC_DENY_OUT_SCOPE 12 ++#define MLME_ALG_NOT_SUPPORT 13 ++#define MLME_SEQ_NR_OUT_OF_SEQUENCE 14 ++#define MLME_REJ_CHALLENGE_FAILURE 15 ++#define MLME_REJ_TIMEOUT 16 ++#define MLME_ASSOC_REJ_UNABLE_HANDLE_STA 17 ++#define MLME_ASSOC_REJ_DATA_RATE 18 ++ ++#define MLME_ASSOC_REJ_NO_EXT_RATE 22 ++#define MLME_ASSOC_REJ_NO_EXT_RATE_PBCC 23 ++#define MLME_ASSOC_REJ_NO_CCK_OFDM 24 ++ ++#define MLME_QOS_UNSPECIFY 32 ++#define MLME_REQUEST_DECLINED 37 ++#define MLME_REQUEST_WITH_INVALID_PARAM 38 ++#define MLME_DLS_NOT_ALLOW_IN_QBSS 48 ++#define MLME_DEST_STA_NOT_IN_QBSS 49 ++#define MLME_DEST_STA_IS_NOT_A_QSTA 50 ++ ++#define MLME_INVALID_FORMAT 0x51 ++#define MLME_FAIL_NO_RESOURCE 0x52 ++#define MLME_STATE_MACHINE_REJECT 0x53 ++#define MLME_MAC_TABLE_FAIL 0x54 ++ ++// IE code ++#define IE_SSID 0 ++#define IE_SUPP_RATES 1 ++#define IE_FH_PARM 2 ++#define IE_DS_PARM 3 ++#define IE_CF_PARM 4 ++#define IE_TIM 5 ++#define IE_IBSS_PARM 6 ++#define IE_COUNTRY 7 // 802.11d ++#define IE_802_11D_REQUEST 10 // 802.11d ++#define IE_QBSS_LOAD 11 // 802.11e d9 ++#define IE_EDCA_PARAMETER 12 // 802.11e d9 ++#define IE_TSPEC 13 // 802.11e d9 ++#define IE_TCLAS 14 // 802.11e d9 ++#define IE_SCHEDULE 15 // 802.11e d9 ++#define IE_CHALLENGE_TEXT 16 ++#define IE_POWER_CONSTRAINT 32 // 802.11h d3.3 ++#define IE_POWER_CAPABILITY 33 // 802.11h d3.3 ++#define IE_TPC_REQUEST 34 // 802.11h d3.3 ++#define IE_TPC_REPORT 35 // 802.11h d3.3 ++#define IE_SUPP_CHANNELS 36 // 802.11h d3.3 ++#define IE_CHANNEL_SWITCH_ANNOUNCEMENT 37 // 802.11h d3.3 ++#define IE_MEASUREMENT_REQUEST 38 // 802.11h d3.3 ++#define IE_MEASUREMENT_REPORT 39 // 802.11h d3.3 ++#define IE_QUIET 40 // 802.11h d3.3 ++#define IE_IBSS_DFS 41 // 802.11h d3.3 ++#define IE_ERP 42 // 802.11g ++#define IE_TS_DELAY 43 // 802.11e d9 ++#define IE_TCLAS_PROCESSING 44 // 802.11e d9 ++#define IE_QOS_CAPABILITY 46 // 802.11e d6 ++#define IE_HT_CAP 45 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD ++#define IE_AP_CHANNEL_REPORT 51 // 802.11k d6 ++#define IE_HT_CAP2 52 // 802.11n d1. HT CAPABILITY. ELEMENT ID TBD ++#define IE_RSN 48 // 802.11i d3.0 ++#define IE_WPA2 48 // WPA2 ++#define IE_EXT_SUPP_RATES 50 // 802.11g ++#define IE_SUPP_REG_CLASS 59 // 802.11y. Supported regulatory classes. ++#define IE_EXT_CHANNEL_SWITCH_ANNOUNCEMENT 60 // 802.11n ++#define IE_ADD_HT 61 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD ++#define IE_ADD_HT2 53 // 802.11n d1. ADDITIONAL HT CAPABILITY. ELEMENT ID TBD ++ ++ ++// For 802.11n D3.03 ++//#define IE_NEW_EXT_CHA_OFFSET 62 // 802.11n d1. New extension channel offset elemet ++#define IE_SECONDARY_CH_OFFSET 62 // 802.11n D3.03 Secondary Channel Offset element ++#define IE_WAPI 68 // WAPI information element ++#define IE_2040_BSS_COEXIST 72 // 802.11n D3.0.3 ++#define IE_2040_BSS_INTOLERANT_REPORT 73 // 802.11n D3.03 ++#define IE_OVERLAPBSS_SCAN_PARM 74 // 802.11n D3.03 ++#define IE_EXT_CAPABILITY 127 // 802.11n D3.03 ++ ++ ++#define IE_WPA 221 // WPA ++#define IE_VENDOR_SPECIFIC 221 // Wifi WMM (WME) ++ ++#define OUI_BROADCOM_HT 51 // ++#define OUI_BROADCOM_HTADD 52 // ++#define OUI_PREN_HT_CAP 51 // ++#define OUI_PREN_ADD_HT 52 // ++ ++// CCX information ++#define IE_AIRONET_CKIP 133 // CCX1.0 ID 85H for CKIP ++#define IE_AP_TX_POWER 150 // CCX 2.0 for AP transmit power ++#define IE_MEASUREMENT_CAPABILITY 221 // CCX 2.0 ++#define IE_CCX_V2 221 ++#define IE_AIRONET_IPADDRESS 149 // CCX ID 95H for IP Address ++#define IE_AIRONET_CCKMREASSOC 156 // CCX ID 9CH for CCKM Reassociation Request element ++#define CKIP_NEGOTIATION_LENGTH 30 ++#define AIRONET_IPADDRESS_LENGTH 10 ++#define AIRONET_CCKMREASSOC_LENGTH 24 ++ ++// ======================================================== ++// MLME state machine definition ++// ======================================================== ++ ++// STA MLME state mahcines ++#define ASSOC_STATE_MACHINE 1 ++#define AUTH_STATE_MACHINE 2 ++#define AUTH_RSP_STATE_MACHINE 3 ++#define SYNC_STATE_MACHINE 4 ++#define MLME_CNTL_STATE_MACHINE 5 ++#define WPA_PSK_STATE_MACHINE 6 ++#define LEAP_STATE_MACHINE 7 ++#define AIRONET_STATE_MACHINE 8 ++#define ACTION_STATE_MACHINE 9 ++ ++// AP MLME state machines ++#define AP_ASSOC_STATE_MACHINE 11 ++#define AP_AUTH_STATE_MACHINE 12 ++#define AP_AUTH_RSP_STATE_MACHINE 13 ++#define AP_SYNC_STATE_MACHINE 14 ++#define AP_CNTL_STATE_MACHINE 15 ++#define AP_WPA_STATE_MACHINE 16 ++ ++#define WSC_STATE_MACHINE 17 ++#define WSC_UPNP_STATE_MACHINE 18 ++ ++ ++ ++#ifdef QOS_DLS_SUPPORT ++#define DLS_STATE_MACHINE 26 ++#endif // QOS_DLS_SUPPORT // ++ ++// ++// STA's CONTROL/CONNECT state machine: states, events, total function # ++// ++#define CNTL_IDLE 0 ++#define CNTL_WAIT_DISASSOC 1 ++#define CNTL_WAIT_JOIN 2 ++#define CNTL_WAIT_REASSOC 3 ++#define CNTL_WAIT_START 4 ++#define CNTL_WAIT_AUTH 5 ++#define CNTL_WAIT_ASSOC 6 ++#define CNTL_WAIT_AUTH2 7 ++#define CNTL_WAIT_OID_LIST_SCAN 8 ++#define CNTL_WAIT_OID_DISASSOC 9 ++#ifdef RT2870 ++#define CNTL_WAIT_SCAN_FOR_CONNECT 10 ++#endif // RT2870 // ++ ++#define MT2_ASSOC_CONF 34 ++#define MT2_AUTH_CONF 35 ++#define MT2_DEAUTH_CONF 36 ++#define MT2_DISASSOC_CONF 37 ++#define MT2_REASSOC_CONF 38 ++#define MT2_PWR_MGMT_CONF 39 ++#define MT2_JOIN_CONF 40 ++#define MT2_SCAN_CONF 41 ++#define MT2_START_CONF 42 ++#define MT2_GET_CONF 43 ++#define MT2_SET_CONF 44 ++#define MT2_RESET_CONF 45 ++#define MT2_MLME_ROAMING_REQ 52 ++ ++#define CNTL_FUNC_SIZE 1 ++ ++// ++// STA's ASSOC state machine: states, events, total function # ++// ++#define ASSOC_IDLE 0 ++#define ASSOC_WAIT_RSP 1 ++#define REASSOC_WAIT_RSP 2 ++#define DISASSOC_WAIT_RSP 3 ++#define MAX_ASSOC_STATE 4 ++ ++#define ASSOC_MACHINE_BASE 0 ++#define MT2_MLME_ASSOC_REQ 0 ++#define MT2_MLME_REASSOC_REQ 1 ++#define MT2_MLME_DISASSOC_REQ 2 ++#define MT2_PEER_DISASSOC_REQ 3 ++#define MT2_PEER_ASSOC_REQ 4 ++#define MT2_PEER_ASSOC_RSP 5 ++#define MT2_PEER_REASSOC_REQ 6 ++#define MT2_PEER_REASSOC_RSP 7 ++#define MT2_DISASSOC_TIMEOUT 8 ++#define MT2_ASSOC_TIMEOUT 9 ++#define MT2_REASSOC_TIMEOUT 10 ++#define MAX_ASSOC_MSG 11 ++ ++#define ASSOC_FUNC_SIZE (MAX_ASSOC_STATE * MAX_ASSOC_MSG) ++ ++// ++// ACT state machine: states, events, total function # ++// ++#define ACT_IDLE 0 ++#define MAX_ACT_STATE 1 ++ ++#define ACT_MACHINE_BASE 0 ++ ++//Those PEER_xx_CATE number is based on real Categary value in IEEE spec. Please don'es modify it by your self. ++//Category ++#define MT2_PEER_SPECTRUM_CATE 0 ++#define MT2_PEER_QOS_CATE 1 ++#define MT2_PEER_DLS_CATE 2 ++#define MT2_PEER_BA_CATE 3 ++#define MT2_PEER_PUBLIC_CATE 4 ++#define MT2_PEER_RM_CATE 5 ++#define MT2_PEER_HT_CATE 7 // 7.4.7 ++#define MAX_PEER_CATE_MSG 7 ++#define MT2_MLME_ADD_BA_CATE 8 ++#define MT2_MLME_ORI_DELBA_CATE 9 ++#define MT2_MLME_REC_DELBA_CATE 10 ++#define MT2_MLME_QOS_CATE 11 ++#define MT2_MLME_DLS_CATE 12 ++#define MT2_ACT_INVALID 13 ++#define MAX_ACT_MSG 14 ++ ++//Category field ++#define CATEGORY_SPECTRUM 0 ++#define CATEGORY_QOS 1 ++#define CATEGORY_DLS 2 ++#define CATEGORY_BA 3 ++#define CATEGORY_PUBLIC 4 ++#define CATEGORY_RM 5 ++#define CATEGORY_HT 7 ++ ++ ++// DLS Action frame definition ++#define ACTION_DLS_REQUEST 0 ++#define ACTION_DLS_RESPONSE 1 ++#define ACTION_DLS_TEARDOWN 2 ++ ++//Spectrum Action field value 802.11h 7.4.1 ++#define SPEC_MRQ 0 // Request ++#define SPEC_MRP 1 //Report ++#define SPEC_TPCRQ 2 ++#define SPEC_TPCRP 3 ++#define SPEC_CHANNEL_SWITCH 4 ++ ++ ++//BA Action field value ++#define ADDBA_REQ 0 ++#define ADDBA_RESP 1 ++#define DELBA 2 ++ ++//Public's Action field value in Public Category. Some in 802.11y and some in 11n ++#define ACTION_BSS_2040_COEXIST 0 // 11n ++#define ACTION_DSE_ENABLEMENT 1 // 11y D9.0 ++#define ACTION_DSE_DEENABLEMENT 2 // 11y D9.0 ++#define ACTION_DSE_REG_LOCATION_ANNOUNCE 3 // 11y D9.0 ++#define ACTION_EXT_CH_SWITCH_ANNOUNCE 4 // 11y D9.0 ++#define ACTION_DSE_MEASUREMENT_REQ 5 // 11y D9.0 ++#define ACTION_DSE_MEASUREMENT_REPORT 6 // 11y D9.0 ++#define ACTION_MEASUREMENT_PILOT_ACTION 7 // 11y D9.0 ++#define ACTION_DSE_POWER_CONSTRAINT 8 // 11y D9.0 ++ ++ ++//HT Action field value ++#define NOTIFY_BW_ACTION 0 ++#define SMPS_ACTION 1 ++#define PSMP_ACTION 2 ++#define SETPCO_ACTION 3 ++#define MIMO_CHA_MEASURE_ACTION 4 ++#define MIMO_N_BEACONFORM 5 ++#define MIMO_BEACONFORM 6 ++#define ANTENNA_SELECT 7 ++#define HT_INFO_EXCHANGE 8 ++ ++#define ACT_FUNC_SIZE (MAX_ACT_STATE * MAX_ACT_MSG) ++// ++// STA's AUTHENTICATION state machine: states, evvents, total function # ++// ++#define AUTH_REQ_IDLE 0 ++#define AUTH_WAIT_SEQ2 1 ++#define AUTH_WAIT_SEQ4 2 ++#define MAX_AUTH_STATE 3 ++ ++#define AUTH_MACHINE_BASE 0 ++#define MT2_MLME_AUTH_REQ 0 ++#define MT2_PEER_AUTH_EVEN 1 ++#define MT2_AUTH_TIMEOUT 2 ++#define MAX_AUTH_MSG 3 ++ ++#define AUTH_FUNC_SIZE (MAX_AUTH_STATE * MAX_AUTH_MSG) ++ ++// ++// STA's AUTH_RSP state machine: states, events, total function # ++// ++#define AUTH_RSP_IDLE 0 ++#define AUTH_RSP_WAIT_CHAL 1 ++#define MAX_AUTH_RSP_STATE 2 ++ ++#define AUTH_RSP_MACHINE_BASE 0 ++#define MT2_AUTH_CHALLENGE_TIMEOUT 0 ++#define MT2_PEER_AUTH_ODD 1 ++#define MT2_PEER_DEAUTH 2 ++#define MAX_AUTH_RSP_MSG 3 ++ ++#define AUTH_RSP_FUNC_SIZE (MAX_AUTH_RSP_STATE * MAX_AUTH_RSP_MSG) ++ ++// ++// STA's SYNC state machine: states, events, total function # ++// ++#define SYNC_IDLE 0 // merge NO_BSS,IBSS_IDLE,IBSS_ACTIVE and BSS in to 1 state ++#define JOIN_WAIT_BEACON 1 ++#define SCAN_LISTEN 2 ++#define MAX_SYNC_STATE 3 ++ ++#define SYNC_MACHINE_BASE 0 ++#define MT2_MLME_SCAN_REQ 0 ++#define MT2_MLME_JOIN_REQ 1 ++#define MT2_MLME_START_REQ 2 ++#define MT2_PEER_BEACON 3 ++#define MT2_PEER_PROBE_RSP 4 ++#define MT2_PEER_ATIM 5 ++#define MT2_SCAN_TIMEOUT 6 ++#define MT2_BEACON_TIMEOUT 7 ++#define MT2_ATIM_TIMEOUT 8 ++#define MT2_PEER_PROBE_REQ 9 ++#define MAX_SYNC_MSG 10 ++ ++#define SYNC_FUNC_SIZE (MAX_SYNC_STATE * MAX_SYNC_MSG) ++ ++//Messages for the DLS state machine ++#define DLS_IDLE 0 ++#define MAX_DLS_STATE 1 ++ ++#define DLS_MACHINE_BASE 0 ++#define MT2_MLME_DLS_REQ 0 ++#define MT2_PEER_DLS_REQ 1 ++#define MT2_PEER_DLS_RSP 2 ++#define MT2_MLME_DLS_TEAR_DOWN 3 ++#define MT2_PEER_DLS_TEAR_DOWN 4 ++#define MAX_DLS_MSG 5 ++ ++#define DLS_FUNC_SIZE (MAX_DLS_STATE * MAX_DLS_MSG) ++ ++// ++// STA's WPA-PSK State machine: states, events, total function # ++// ++#define WPA_PSK_IDLE 0 ++#define MAX_WPA_PSK_STATE 1 ++ ++#define WPA_MACHINE_BASE 0 ++#define MT2_EAPPacket 0 ++#define MT2_EAPOLStart 1 ++#define MT2_EAPOLLogoff 2 ++#define MT2_EAPOLKey 3 ++#define MT2_EAPOLASFAlert 4 ++#define MAX_WPA_PSK_MSG 5 ++ ++#define WPA_PSK_FUNC_SIZE (MAX_WPA_PSK_STATE * MAX_WPA_PSK_MSG) ++ ++// ++// STA's CISCO-AIRONET State machine: states, events, total function # ++// ++#define AIRONET_IDLE 0 ++#define AIRONET_SCANNING 1 ++#define MAX_AIRONET_STATE 2 ++ ++#define AIRONET_MACHINE_BASE 0 ++#define MT2_AIRONET_MSG 0 ++#define MT2_AIRONET_SCAN_REQ 1 ++#define MT2_AIRONET_SCAN_DONE 2 ++#define MAX_AIRONET_MSG 3 ++ ++#define AIRONET_FUNC_SIZE (MAX_AIRONET_STATE * MAX_AIRONET_MSG) ++ ++// ++// WSC State machine: states, events, total function # ++// ++ ++// ++// AP's CONTROL/CONNECT state machine: states, events, total function # ++// ++#define AP_CNTL_FUNC_SIZE 1 ++ ++// ++// AP's ASSOC state machine: states, events, total function # ++// ++#define AP_ASSOC_IDLE 0 ++#define AP_MAX_ASSOC_STATE 1 ++ ++#define AP_ASSOC_MACHINE_BASE 0 ++#define APMT2_MLME_DISASSOC_REQ 0 ++#define APMT2_PEER_DISASSOC_REQ 1 ++#define APMT2_PEER_ASSOC_REQ 2 ++#define APMT2_PEER_REASSOC_REQ 3 ++#define APMT2_CLS3ERR 4 ++#define AP_MAX_ASSOC_MSG 5 ++ ++#define AP_ASSOC_FUNC_SIZE (AP_MAX_ASSOC_STATE * AP_MAX_ASSOC_MSG) ++ ++// ++// AP's AUTHENTICATION state machine: states, events, total function # ++// ++#define AP_AUTH_REQ_IDLE 0 ++#define AP_MAX_AUTH_STATE 1 ++ ++#define AP_AUTH_MACHINE_BASE 0 ++#define APMT2_MLME_DEAUTH_REQ 0 ++#define APMT2_CLS2ERR 1 ++#define AP_MAX_AUTH_MSG 2 ++ ++#define AP_AUTH_FUNC_SIZE (AP_MAX_AUTH_STATE * AP_MAX_AUTH_MSG) ++ ++// ++// AP's AUTH-RSP state machine: states, events, total function # ++// ++#define AP_AUTH_RSP_IDLE 0 ++#define AP_MAX_AUTH_RSP_STATE 1 ++ ++#define AP_AUTH_RSP_MACHINE_BASE 0 ++#define APMT2_AUTH_CHALLENGE_TIMEOUT 0 ++#define APMT2_PEER_AUTH_ODD 1 ++#define APMT2_PEER_DEAUTH 2 ++#define AP_MAX_AUTH_RSP_MSG 3 ++ ++#define AP_AUTH_RSP_FUNC_SIZE (AP_MAX_AUTH_RSP_STATE * AP_MAX_AUTH_RSP_MSG) ++ ++// ++// AP's SYNC state machine: states, events, total function # ++// ++#define AP_SYNC_IDLE 0 ++#define AP_SCAN_LISTEN 1 ++#define AP_MAX_SYNC_STATE 2 ++ ++#define AP_SYNC_MACHINE_BASE 0 ++#define APMT2_PEER_PROBE_REQ 0 ++#define APMT2_PEER_BEACON 1 ++#define APMT2_MLME_SCAN_REQ 2 ++#define APMT2_PEER_PROBE_RSP 3 ++#define APMT2_SCAN_TIMEOUT 4 ++#define APMT2_MLME_SCAN_CNCL 5 ++#define AP_MAX_SYNC_MSG 6 ++ ++#define AP_SYNC_FUNC_SIZE (AP_MAX_SYNC_STATE * AP_MAX_SYNC_MSG) ++ ++// ++// AP's WPA state machine: states, events, total function # ++// ++#define AP_WPA_PTK 0 ++#define AP_MAX_WPA_PTK_STATE 1 ++ ++#define AP_WPA_MACHINE_BASE 0 ++#define APMT2_EAPPacket 0 ++#define APMT2_EAPOLStart 1 ++#define APMT2_EAPOLLogoff 2 ++#define APMT2_EAPOLKey 3 ++#define APMT2_EAPOLASFAlert 4 ++#define AP_MAX_WPA_MSG 5 ++ ++#define AP_WPA_FUNC_SIZE (AP_MAX_WPA_PTK_STATE * AP_MAX_WPA_MSG) ++ ++ ++ ++// ============================================================================= ++ ++// value domain of 802.11 header FC.Tyte, which is b3..b2 of the 1st-byte of MAC header ++#define BTYPE_MGMT 0 ++#define BTYPE_CNTL 1 ++#define BTYPE_DATA 2 ++ ++// value domain of 802.11 MGMT frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_ASSOC_REQ 0 ++#define SUBTYPE_ASSOC_RSP 1 ++#define SUBTYPE_REASSOC_REQ 2 ++#define SUBTYPE_REASSOC_RSP 3 ++#define SUBTYPE_PROBE_REQ 4 ++#define SUBTYPE_PROBE_RSP 5 ++#define SUBTYPE_BEACON 8 ++#define SUBTYPE_ATIM 9 ++#define SUBTYPE_DISASSOC 10 ++#define SUBTYPE_AUTH 11 ++#define SUBTYPE_DEAUTH 12 ++#define SUBTYPE_ACTION 13 ++#define SUBTYPE_ACTION_NO_ACK 14 ++ ++// value domain of 802.11 CNTL frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_WRAPPER 7 ++#define SUBTYPE_BLOCK_ACK_REQ 8 ++#define SUBTYPE_BLOCK_ACK 9 ++#define SUBTYPE_PS_POLL 10 ++#define SUBTYPE_RTS 11 ++#define SUBTYPE_CTS 12 ++#define SUBTYPE_ACK 13 ++#define SUBTYPE_CFEND 14 ++#define SUBTYPE_CFEND_CFACK 15 ++ ++// value domain of 802.11 DATA frame's FC.subtype, which is b7..4 of the 1st-byte of MAC header ++#define SUBTYPE_DATA 0 ++#define SUBTYPE_DATA_CFACK 1 ++#define SUBTYPE_DATA_CFPOLL 2 ++#define SUBTYPE_DATA_CFACK_CFPOLL 3 ++#define SUBTYPE_NULL_FUNC 4 ++#define SUBTYPE_CFACK 5 ++#define SUBTYPE_CFPOLL 6 ++#define SUBTYPE_CFACK_CFPOLL 7 ++#define SUBTYPE_QDATA 8 ++#define SUBTYPE_QDATA_CFACK 9 ++#define SUBTYPE_QDATA_CFPOLL 10 ++#define SUBTYPE_QDATA_CFACK_CFPOLL 11 ++#define SUBTYPE_QOS_NULL 12 ++#define SUBTYPE_QOS_CFACK 13 ++#define SUBTYPE_QOS_CFPOLL 14 ++#define SUBTYPE_QOS_CFACK_CFPOLL 15 ++ ++// ACK policy of QOS Control field bit 6:5 ++#define NORMAL_ACK 0x00 // b6:5 = 00 ++#define NO_ACK 0x20 // b6:5 = 01 ++#define NO_EXPLICIT_ACK 0x40 // b6:5 = 10 ++#define BLOCK_ACK 0x60 // b6:5 = 11 ++ ++// ++// rtmp_data.c use these definition ++// ++#define LENGTH_802_11 24 ++#define LENGTH_802_11_AND_H 30 ++#define LENGTH_802_11_CRC_H 34 ++#define LENGTH_802_11_CRC 28 ++#define LENGTH_802_11_WITH_ADDR4 30 ++#define LENGTH_802_3 14 ++#define LENGTH_802_3_TYPE 2 ++#define LENGTH_802_1_H 8 ++#define LENGTH_EAPOL_H 4 ++#define LENGTH_WMMQOS_H 2 ++#define LENGTH_CRC 4 ++#define MAX_SEQ_NUMBER 0x0fff ++#define LENGTH_802_3_NO_TYPE 12 ++#define LENGTH_802_1Q 4 /* VLAN related */ ++ ++// STA_CSR4.field.TxResult ++#define TX_RESULT_SUCCESS 0 ++#define TX_RESULT_ZERO_LENGTH 1 ++#define TX_RESULT_UNDER_RUN 2 ++#define TX_RESULT_OHY_ERROR 4 ++#define TX_RESULT_RETRY_FAIL 6 ++ ++// All PHY rate summary in TXD ++// Preamble MODE in TxD ++#define MODE_CCK 0 ++#define MODE_OFDM 1 ++#ifdef DOT11_N_SUPPORT ++#define MODE_HTMIX 2 ++#define MODE_HTGREENFIELD 3 ++#endif // DOT11_N_SUPPORT // ++// MCS for CCK. BW.SGI.STBC are reserved ++#define MCS_LONGP_RATE_1 0 // long preamble CCK 1Mbps ++#define MCS_LONGP_RATE_2 1 // long preamble CCK 1Mbps ++#define MCS_LONGP_RATE_5_5 2 ++#define MCS_LONGP_RATE_11 3 ++#define MCS_SHORTP_RATE_1 4 // long preamble CCK 1Mbps. short is forbidden in 1Mbps ++#define MCS_SHORTP_RATE_2 5 // short preamble CCK 2Mbps ++#define MCS_SHORTP_RATE_5_5 6 ++#define MCS_SHORTP_RATE_11 7 ++// To send duplicate legacy OFDM. set BW=BW_40. SGI.STBC are reserved ++#define MCS_RATE_6 0 // legacy OFDM ++#define MCS_RATE_9 1 // OFDM ++#define MCS_RATE_12 2 // OFDM ++#define MCS_RATE_18 3 // OFDM ++#define MCS_RATE_24 4 // OFDM ++#define MCS_RATE_36 5 // OFDM ++#define MCS_RATE_48 6 // OFDM ++#define MCS_RATE_54 7 // OFDM ++// HT ++#define MCS_0 0 // 1S ++#define MCS_1 1 ++#define MCS_2 2 ++#define MCS_3 3 ++#define MCS_4 4 ++#define MCS_5 5 ++#define MCS_6 6 ++#define MCS_7 7 ++#define MCS_8 8 // 2S ++#define MCS_9 9 ++#define MCS_10 10 ++#define MCS_11 11 ++#define MCS_12 12 ++#define MCS_13 13 ++#define MCS_14 14 ++#define MCS_15 15 ++#define MCS_16 16 // 3*3 ++#define MCS_17 17 ++#define MCS_18 18 ++#define MCS_19 19 ++#define MCS_20 20 ++#define MCS_21 21 ++#define MCS_22 22 ++#define MCS_23 23 ++#define MCS_32 32 ++#define MCS_AUTO 33 ++ ++#ifdef DOT11_N_SUPPORT ++// OID_HTPHYMODE ++// MODE ++#define HTMODE_MM 0 ++#define HTMODE_GF 1 ++#endif // DOT11_N_SUPPORT // ++ ++// Fixed Tx MODE - HT, CCK or OFDM ++#define FIXED_TXMODE_HT 0 ++#define FIXED_TXMODE_CCK 1 ++#define FIXED_TXMODE_OFDM 2 ++// BW ++#define BW_20 BAND_WIDTH_20 ++#define BW_40 BAND_WIDTH_40 ++#define BW_BOTH BAND_WIDTH_BOTH ++#define BW_10 BAND_WIDTH_10 // 802.11j has 10MHz. This definition is for internal usage. doesn't fill in the IE or other field. ++ ++#ifdef DOT11_N_SUPPORT ++// SHORTGI ++#define GI_400 GAP_INTERVAL_400 // only support in HT mode ++#define GI_BOTH GAP_INTERVAL_BOTH ++#endif // DOT11_N_SUPPORT // ++#define GI_800 GAP_INTERVAL_800 ++// STBC ++#define STBC_NONE 0 ++#ifdef DOT11_N_SUPPORT ++#define STBC_USE 1 // limited use in rt2860b phy ++#define RXSTBC_ONE 1 // rx support of one spatial stream ++#define RXSTBC_TWO 2 // rx support of 1 and 2 spatial stream ++#define RXSTBC_THR 3 // rx support of 1~3 spatial stream ++// MCS FEEDBACK ++#define MCSFBK_NONE 0 // not support mcs feedback / ++#define MCSFBK_RSV 1 // reserved ++#define MCSFBK_UNSOLICIT 2 // only support unsolict mcs feedback ++#define MCSFBK_MRQ 3 // response to both MRQ and unsolict mcs feedback ++ ++// MIMO power safe ++#define MMPS_STATIC 0 ++#define MMPS_DYNAMIC 1 ++#define MMPS_RSV 2 ++#define MMPS_ENABLE 3 ++ ++ ++// A-MSDU size ++#define AMSDU_0 0 ++#define AMSDU_1 1 ++ ++#endif // DOT11_N_SUPPORT // ++ ++// MCS use 7 bits ++#define TXRATEMIMO 0x80 ++#define TXRATEMCS 0x7F ++#define TXRATEOFDM 0x7F ++#define RATE_1 0 ++#define RATE_2 1 ++#define RATE_5_5 2 ++#define RATE_11 3 ++#define RATE_6 4 // OFDM ++#define RATE_9 5 // OFDM ++#define RATE_12 6 // OFDM ++#define RATE_18 7 // OFDM ++#define RATE_24 8 // OFDM ++#define RATE_36 9 // OFDM ++#define RATE_48 10 // OFDM ++#define RATE_54 11 // OFDM ++#define RATE_FIRST_OFDM_RATE RATE_6 ++#define RATE_LAST_OFDM_RATE RATE_54 ++#define RATE_6_5 12 // HT mix ++#define RATE_13 13 // HT mix ++#define RATE_19_5 14 // HT mix ++#define RATE_26 15 // HT mix ++#define RATE_39 16 // HT mix ++#define RATE_52 17 // HT mix ++#define RATE_58_5 18 // HT mix ++#define RATE_65 19 // HT mix ++#define RATE_78 20 // HT mix ++#define RATE_104 21 // HT mix ++#define RATE_117 22 // HT mix ++#define RATE_130 23 // HT mix ++//#define RATE_AUTO_SWITCH 255 // for StaCfg.FixedTxRate only ++#define HTRATE_0 12 ++#define RATE_FIRST_MM_RATE HTRATE_0 ++#define RATE_FIRST_HT_RATE HTRATE_0 ++#define RATE_LAST_HT_RATE HTRATE_0 ++ ++// pTxWI->txop ++#define IFS_HTTXOP 0 // The txop will be handles by ASIC. ++#define IFS_PIFS 1 ++#define IFS_SIFS 2 ++#define IFS_BACKOFF 3 ++ ++// pTxD->RetryMode ++#define LONG_RETRY 1 ++#define SHORT_RETRY 0 ++ ++// Country Region definition ++#define REGION_MINIMUM_BG_BAND 0 ++#define REGION_0_BG_BAND 0 // 1-11 ++#define REGION_1_BG_BAND 1 // 1-13 ++#define REGION_2_BG_BAND 2 // 10-11 ++#define REGION_3_BG_BAND 3 // 10-13 ++#define REGION_4_BG_BAND 4 // 14 ++#define REGION_5_BG_BAND 5 // 1-14 ++#define REGION_6_BG_BAND 6 // 3-9 ++#define REGION_7_BG_BAND 7 // 5-13 ++#define REGION_31_BG_BAND 31 // 5-13 ++#define REGION_MAXIMUM_BG_BAND 7 ++ ++#define REGION_MINIMUM_A_BAND 0 ++#define REGION_0_A_BAND 0 // 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165 ++#define REGION_1_A_BAND 1 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 ++#define REGION_2_A_BAND 2 // 36, 40, 44, 48, 52, 56, 60, 64 ++#define REGION_3_A_BAND 3 // 52, 56, 60, 64, 149, 153, 157, 161 ++#define REGION_4_A_BAND 4 // 149, 153, 157, 161, 165 ++#define REGION_5_A_BAND 5 // 149, 153, 157, 161 ++#define REGION_6_A_BAND 6 // 36, 40, 44, 48 ++#define REGION_7_A_BAND 7 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 ++#define REGION_8_A_BAND 8 // 52, 56, 60, 64 ++#define REGION_9_A_BAND 9 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165 ++#define REGION_10_A_BAND 10 // 36, 40, 44, 48, 149, 153, 157, 161, 165 ++#define REGION_11_A_BAND 11 // 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 149, 153, 157, 161 ++#define REGION_MAXIMUM_A_BAND 11 ++ ++// pTxD->CipherAlg ++#define CIPHER_NONE 0 ++#define CIPHER_WEP64 1 ++#define CIPHER_WEP128 2 ++#define CIPHER_TKIP 3 ++#define CIPHER_AES 4 ++#define CIPHER_CKIP64 5 ++#define CIPHER_CKIP128 6 ++#define CIPHER_TKIP_NO_MIC 7 // MIC appended by driver: not a valid value in hardware key table ++#define CIPHER_SMS4 8 ++ ++// value domain of pAd->RfIcType ++#define RFIC_2820 1 // 2.4G 2T3R ++#define RFIC_2850 2 // 2.4G/5G 2T3R ++#define RFIC_2720 3 // 2.4G 1T2R ++#define RFIC_2750 4 // 2.4G/5G 1T2R ++#define RFIC_3020 5 // 2.4G 1T1R ++#define RFIC_2020 6 // 2.4G B/G ++#define RFIC_3021 7 // 2.4G 1T2R ++#define RFIC_3022 8 // 2.4G 2T2R ++ ++// LED Status. ++#define LED_LINK_DOWN 0 ++#define LED_LINK_UP 1 ++#define LED_RADIO_OFF 2 ++#define LED_RADIO_ON 3 ++#define LED_HALT 4 ++#define LED_WPS 5 ++#define LED_ON_SITE_SURVEY 6 ++#define LED_POWER_UP 7 ++ ++// value domain of pAd->LedCntl.LedMode and E2PROM ++#define LED_MODE_DEFAULT 0 ++#define LED_MODE_TWO_LED 1 ++#define LED_MODE_SIGNAL_STREGTH 8 // EEPROM define =8 ++ ++// RC4 init value, used fro WEP & TKIP ++#define PPPINITFCS32 0xffffffff /* Initial FCS value */ ++ ++// value domain of pAd->StaCfg.PortSecured. 802.1X controlled port definition ++#define WPA_802_1X_PORT_SECURED 1 ++#define WPA_802_1X_PORT_NOT_SECURED 2 ++ ++#define PAIRWISE_KEY 1 ++#define GROUP_KEY 2 ++ ++//definition of DRS ++#define MAX_STEP_OF_TX_RATE_SWITCH 32 ++ ++ ++// pre-allocated free NDIS PACKET/BUFFER poll for internal usage ++#define MAX_NUM_OF_FREE_NDIS_PACKET 128 ++ ++//Block ACK ++#define MAX_TX_REORDERBUF 64 ++#define MAX_RX_REORDERBUF 64 ++#define DEFAULT_TX_TIMEOUT 30 ++#define DEFAULT_RX_TIMEOUT 30 ++ ++// definition of Recipient or Originator ++#define I_RECIPIENT TRUE ++#define I_ORIGINATOR FALSE ++ ++#define DEFAULT_BBP_TX_POWER 0 ++#define DEFAULT_RF_TX_POWER 5 ++ ++#define MAX_INI_BUFFER_SIZE 4096 ++#define MAX_PARAM_BUFFER_SIZE (2048) // enough for ACL (18*64) ++ //18 : the length of Mac address acceptable format "01:02:03:04:05:06;") ++ //64 : MAX_NUM_OF_ACL_LIST ++// definition of pAd->OpMode ++#define OPMODE_STA 0 ++#define OPMODE_AP 1 ++//#define OPMODE_L3_BRG 2 // as AP and STA at the same time ++ ++#ifdef RT_BIG_ENDIAN ++#define DIR_READ 0 ++#define DIR_WRITE 1 ++#define TYPE_TXD 0 ++#define TYPE_RXD 1 ++#define TYPE_TXINFO 0 ++#define TYPE_RXINFO 1 ++#define TYPE_TXWI 0 ++#define TYPE_RXWI 1 ++#endif ++ ++// ========================= AP rtmp_def.h =========================== ++// value domain for pAd->EventTab.Log[].Event ++#define EVENT_RESET_ACCESS_POINT 0 // Log = "hh:mm:ss Restart Access Point" ++#define EVENT_ASSOCIATED 1 // Log = "hh:mm:ss STA 00:01:02:03:04:05 associated" ++#define EVENT_DISASSOCIATED 2 // Log = "hh:mm:ss STA 00:01:02:03:04:05 left this BSS" ++#define EVENT_AGED_OUT 3 // Log = "hh:mm:ss STA 00:01:02:03:04:05 was aged-out and removed from this BSS" ++#define EVENT_COUNTER_M 4 ++#define EVENT_INVALID_PSK 5 ++#define EVENT_MAX_EVENT_TYPE 6 ++// ==== end of AP rtmp_def.h ============ ++ ++// definition RSSI Number ++#define RSSI_0 0 ++#define RSSI_1 1 ++#define RSSI_2 2 ++ ++// definition of radar detection ++#define RD_NORMAL_MODE 0 // Not found radar signal ++#define RD_SWITCHING_MODE 1 // Found radar signal, and doing channel switch ++#define RD_SILENCE_MODE 2 // After channel switch, need to be silence a while to ensure radar not found ++ ++//Driver defined cid for mapping status and command. ++#define SLEEPCID 0x11 ++#define WAKECID 0x22 ++#define QUERYPOWERCID 0x33 ++#define OWNERMCU 0x1 ++#define OWNERCPU 0x0 ++ ++// MBSSID definition ++#define ENTRY_NOT_FOUND 0xFF ++ ++ ++/* After Linux 2.6.9, ++ * VLAN module use Private (from user) interface flags (netdevice->priv_flags). ++ * #define IFF_802_1Q_VLAN 0x1 -- 802.1Q VLAN device. in if.h ++ * ref to ip_sabotage_out() [ out->priv_flags & IFF_802_1Q_VLAN ] in br_netfilter.c ++ * ++ * For this reason, we MUST use EVEN value in priv_flags ++ */ ++#define INT_MAIN 0x0100 ++#define INT_MBSSID 0x0200 ++#define INT_WDS 0x0300 ++#define INT_APCLI 0x0400 ++#define INT_MESH 0x0500 ++ ++// Use bitmap to allow coexist of ATE_TXFRAME and ATE_RXFRAME(i.e.,to support LoopBack mode) ++#ifdef RALINK_ATE ++#define ATE_START 0x00 // Start ATE ++#define ATE_STOP 0x80 // Stop ATE ++#define ATE_TXCONT 0x05 // Continuous Transmit ++#define ATE_TXCARR 0x09 // Transmit Carrier ++#define ATE_TXCARRSUPP 0x11 // Transmit Carrier Suppression ++#define ATE_TXFRAME 0x01 // Transmit Frames ++#define ATE_RXFRAME 0x02 // Receive Frames ++#ifdef RALINK_28xx_QA ++#define ATE_TXSTOP 0xe2 // Stop Transmition(i.e., TXCONT, TXCARR, TXCARRSUPP, and TXFRAME) ++#define ATE_RXSTOP 0xfd // Stop receiving Frames ++#define BBP22_TXFRAME 0x00 // Transmit Frames ++#define BBP22_TXCONT_OR_CARRSUPP 0x80 // Continuous Transmit or Carrier Suppression ++#define BBP22_TXCARR 0xc1 // Transmit Carrier ++#define BBP24_TXCONT 0x00 // Continuous Transmit ++#define BBP24_CARRSUPP 0x01 // Carrier Suppression ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++// WEP Key TYPE ++#define WEP_HEXADECIMAL_TYPE 0 ++#define WEP_ASCII_TYPE 1 ++ ++ ++ ++// WIRELESS EVENTS definition ++/* Max number of char in custom event, refer to wireless_tools.28/wireless.20.h */ ++#define IW_CUSTOM_MAX_LEN 255 /* In bytes */ ++ ++// For system event - start ++#define IW_SYS_EVENT_FLAG_START 0x0200 ++#define IW_ASSOC_EVENT_FLAG 0x0200 ++#define IW_DISASSOC_EVENT_FLAG 0x0201 ++#define IW_DEAUTH_EVENT_FLAG 0x0202 ++#define IW_AGEOUT_EVENT_FLAG 0x0203 ++#define IW_COUNTER_MEASURES_EVENT_FLAG 0x0204 ++#define IW_REPLAY_COUNTER_DIFF_EVENT_FLAG 0x0205 ++#define IW_RSNIE_DIFF_EVENT_FLAG 0x0206 ++#define IW_MIC_DIFF_EVENT_FLAG 0x0207 ++#define IW_ICV_ERROR_EVENT_FLAG 0x0208 ++#define IW_MIC_ERROR_EVENT_FLAG 0x0209 ++#define IW_GROUP_HS_TIMEOUT_EVENT_FLAG 0x020A ++#define IW_PAIRWISE_HS_TIMEOUT_EVENT_FLAG 0x020B ++#define IW_RSNIE_SANITY_FAIL_EVENT_FLAG 0x020C ++#define IW_SET_KEY_DONE_WPA1_EVENT_FLAG 0x020D ++#define IW_SET_KEY_DONE_WPA2_EVENT_FLAG 0x020E ++#define IW_STA_LINKUP_EVENT_FLAG 0x020F ++#define IW_STA_LINKDOWN_EVENT_FLAG 0x0210 ++#define IW_SCAN_COMPLETED_EVENT_FLAG 0x0211 ++#define IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG 0x0212 ++// if add new system event flag, please upadte the IW_SYS_EVENT_FLAG_END ++#define IW_SYS_EVENT_FLAG_END 0x0212 ++#define IW_SYS_EVENT_TYPE_NUM (IW_SYS_EVENT_FLAG_END - IW_SYS_EVENT_FLAG_START + 1) ++// For system event - end ++ ++// For spoof attack event - start ++#define IW_SPOOF_EVENT_FLAG_START 0x0300 ++#define IW_CONFLICT_SSID_EVENT_FLAG 0x0300 ++#define IW_SPOOF_ASSOC_RESP_EVENT_FLAG 0x0301 ++#define IW_SPOOF_REASSOC_RESP_EVENT_FLAG 0x0302 ++#define IW_SPOOF_PROBE_RESP_EVENT_FLAG 0x0303 ++#define IW_SPOOF_BEACON_EVENT_FLAG 0x0304 ++#define IW_SPOOF_DISASSOC_EVENT_FLAG 0x0305 ++#define IW_SPOOF_AUTH_EVENT_FLAG 0x0306 ++#define IW_SPOOF_DEAUTH_EVENT_FLAG 0x0307 ++#define IW_SPOOF_UNKNOWN_MGMT_EVENT_FLAG 0x0308 ++#define IW_REPLAY_ATTACK_EVENT_FLAG 0x0309 ++// if add new spoof attack event flag, please upadte the IW_SPOOF_EVENT_FLAG_END ++#define IW_SPOOF_EVENT_FLAG_END 0x0309 ++#define IW_SPOOF_EVENT_TYPE_NUM (IW_SPOOF_EVENT_FLAG_END - IW_SPOOF_EVENT_FLAG_START + 1) ++// For spoof attack event - end ++ ++// For flooding attack event - start ++#define IW_FLOOD_EVENT_FLAG_START 0x0400 ++#define IW_FLOOD_AUTH_EVENT_FLAG 0x0400 ++#define IW_FLOOD_ASSOC_REQ_EVENT_FLAG 0x0401 ++#define IW_FLOOD_REASSOC_REQ_EVENT_FLAG 0x0402 ++#define IW_FLOOD_PROBE_REQ_EVENT_FLAG 0x0403 ++#define IW_FLOOD_DISASSOC_EVENT_FLAG 0x0404 ++#define IW_FLOOD_DEAUTH_EVENT_FLAG 0x0405 ++#define IW_FLOOD_EAP_REQ_EVENT_FLAG 0x0406 ++// if add new flooding attack event flag, please upadte the IW_FLOOD_EVENT_FLAG_END ++#define IW_FLOOD_EVENT_FLAG_END 0x0406 ++#define IW_FLOOD_EVENT_TYPE_NUM (IW_FLOOD_EVENT_FLAG_END - IW_FLOOD_EVENT_FLAG_START + 1) ++// For flooding attack - end ++ ++// End - WIRELESS EVENTS definition ++ ++#ifdef CONFIG_STA_SUPPORT ++// definition for DLS, kathy ++#define MAX_NUM_OF_INIT_DLS_ENTRY 1 ++#define MAX_NUM_OF_DLS_ENTRY MAX_NUMBER_OF_DLS_ENTRY ++ ++//Block ACK , rt2860, kathy ++#define MAX_TX_REORDERBUF 64 ++#define MAX_RX_REORDERBUF 64 ++#define DEFAULT_TX_TIMEOUT 30 ++#define DEFAULT_RX_TIMEOUT 30 ++#ifndef CONFIG_AP_SUPPORT ++#define MAX_BARECI_SESSION 8 ++#endif ++ ++#ifndef IW_ESSID_MAX_SIZE ++/* Maximum size of the ESSID and pAd->nickname strings */ ++#define IW_ESSID_MAX_SIZE 32 ++#endif ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef MCAST_RATE_SPECIFIC ++#define MCAST_DISABLE 0 ++#define MCAST_CCK 1 ++#define MCAST_OFDM 2 ++#define MCAST_HTMIX 3 ++#endif // MCAST_RATE_SPECIFIC // ++ ++// For AsicRadioOff/AsicRadioOn function ++#define DOT11POWERSAVE 0 ++#define GUIRADIO_OFF 1 ++#define RTMP_HALT 2 ++#define GUI_IDLE_POWER_SAVE 3 ++// -- ++ ++ ++// definition for WpaSupport flag ++#define WPA_SUPPLICANT_DISABLE 0 ++#define WPA_SUPPLICANT_ENABLE 1 ++#define WPA_SUPPLICANT_ENABLE_WITH_WEB_UI 2 ++ ++// Endian byte swapping codes ++#define SWAP16(x) \ ++ ((UINT16)( \ ++ (((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \ ++ (((UINT16)(x) & (UINT16) 0xff00U) >> 8) )) ++ ++#define SWAP32(x) \ ++ ((UINT32)( \ ++ (((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \ ++ (((UINT32)(x) & (UINT32) 0x0000ff00UL) << 8) | \ ++ (((UINT32)(x) & (UINT32) 0x00ff0000UL) >> 8) | \ ++ (((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) )) ++ ++#define SWAP64(x) \ ++ ((UINT64)( \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) << 8) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >> 8) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \ ++ (UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) )) ++ ++#ifdef RT_BIG_ENDIAN ++ ++#define cpu2le64(x) SWAP64((x)) ++#define le2cpu64(x) SWAP64((x)) ++#define cpu2le32(x) SWAP32((x)) ++#define le2cpu32(x) SWAP32((x)) ++#define cpu2le16(x) SWAP16((x)) ++#define le2cpu16(x) SWAP16((x)) ++#define cpu2be64(x) ((UINT64)(x)) ++#define be2cpu64(x) ((UINT64)(x)) ++#define cpu2be32(x) ((UINT32)(x)) ++#define be2cpu32(x) ((UINT32)(x)) ++#define cpu2be16(x) ((UINT16)(x)) ++#define be2cpu16(x) ((UINT16)(x)) ++ ++#else // Little_Endian ++ ++#define cpu2le64(x) ((UINT64)(x)) ++#define le2cpu64(x) ((UINT64)(x)) ++#define cpu2le32(x) ((UINT32)(x)) ++#define le2cpu32(x) ((UINT32)(x)) ++#define cpu2le16(x) ((UINT16)(x)) ++#define le2cpu16(x) ((UINT16)(x)) ++#define cpu2be64(x) SWAP64((x)) ++#define be2cpu64(x) SWAP64((x)) ++#define cpu2be32(x) SWAP32((x)) ++#define be2cpu32(x) SWAP32((x)) ++#define cpu2be16(x) SWAP16((x)) ++#define be2cpu16(x) SWAP16((x)) ++ ++#endif // RT_BIG_ENDIAN ++ ++#endif // __RTMP_DEF_H__ ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rtmp.h +@@ -0,0 +1,7728 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp.h ++ ++ Abstract: ++ Miniport generic portion header file ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 2002-08-01 created ++ James Tan 2002-09-06 modified (Revise NTCRegTable) ++ John Chang 2004-09-06 modified for RT2600 ++*/ ++#ifndef __RTMP_H__ ++#define __RTMP_H__ ++ ++#include "link_list.h" ++#include "spectrum_def.h" ++ ++#ifdef MLME_EX ++#include "mlme_ex_def.h" ++#endif // MLME_EX // ++ ++#ifdef CONFIG_STA_SUPPORT ++#include "aironet.h" ++#endif // CONFIG_STA_SUPPORT // ++ ++#undef AP_WSC_INCLUDED ++#undef STA_WSC_INCLUDED ++#undef WSC_INCLUDED ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++#if defined(AP_WSC_INCLUDED) || defined(STA_WSC_INCLUDED) ++#define WSC_INCLUDED ++#endif ++ ++ ++ ++ ++ ++//#define DBG 1 ++ ++//#define DBG_DIAGNOSE 1 ++ ++#if defined(CONFIG_AP_SUPPORT) && defined(CONFIG_STA_SUPPORT) ++#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) if(_pAd->OpMode == OPMODE_AP) ++#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) if(_pAd->OpMode == OPMODE_STA) ++#else ++#define IF_DEV_CONFIG_OPMODE_ON_AP(_pAd) ++#define IF_DEV_CONFIG_OPMODE_ON_STA(_pAd) ++#endif ++ ++#define VIRTUAL_IF_INC(__pAd) ((__pAd)->VirtualIfCnt++) ++#define VIRTUAL_IF_DEC(__pAd) ((__pAd)->VirtualIfCnt--) ++#define VIRTUAL_IF_NUM(__pAd) ((__pAd)->VirtualIfCnt) ++ ++#ifdef RT2870 ++//////////////////////////////////////////////////////////////////////////// ++// The TX_BUFFER structure forms the transmitted USB packet to the device ++//////////////////////////////////////////////////////////////////////////// ++typedef struct __TX_BUFFER{ ++ union { ++ UCHAR WirelessPacket[TX_BUFFER_NORMSIZE]; ++ HEADER_802_11 NullFrame; ++ PSPOLL_FRAME PsPollPacket; ++ RTS_FRAME RTSFrame; ++ }field; ++ UCHAR Aggregation[4]; //Buffer for save Aggregation size. ++} TX_BUFFER, *PTX_BUFFER; ++ ++typedef struct __HTTX_BUFFER{ ++ union { ++ UCHAR WirelessPacket[MAX_TXBULK_SIZE]; ++ HEADER_802_11 NullFrame; ++ PSPOLL_FRAME PsPollPacket; ++ RTS_FRAME RTSFrame; ++ }field; ++ UCHAR Aggregation[4]; //Buffer for save Aggregation size. ++} HTTX_BUFFER, *PHTTX_BUFFER; ++ ++ ++// used to track driver-generated write irps ++typedef struct _TX_CONTEXT ++{ ++ PVOID pAd; //Initialized in MiniportInitialize ++ PURB pUrb; //Initialized in MiniportInitialize ++ PIRP pIrp; //used to cancel pending bulk out. ++ //Initialized in MiniportInitialize ++ PTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize ++ ULONG BulkOutSize; ++ UCHAR BulkOutPipeId; ++ UCHAR SelfIdx; ++ BOOLEAN InUse; ++ BOOLEAN bWaitingBulkOut; // at least one packet is in this TxContext, ready for making IRP anytime. ++ BOOLEAN bFullForBulkOut; // all tx buffer are full , so waiting for tx bulkout. ++ BOOLEAN IRPPending; ++ BOOLEAN LastOne; ++ BOOLEAN bAggregatible; ++ UCHAR Header_802_3[LENGTH_802_3]; ++ UCHAR Rsv[2]; ++ ULONG DataOffset; ++ UINT TxRate; ++ dma_addr_t data_dma; // urb dma on linux ++ ++} TX_CONTEXT, *PTX_CONTEXT, **PPTX_CONTEXT; ++ ++ ++// used to track driver-generated write irps ++typedef struct _HT_TX_CONTEXT ++{ ++ PVOID pAd; //Initialized in MiniportInitialize ++ PURB pUrb; //Initialized in MiniportInitialize ++ PIRP pIrp; //used to cancel pending bulk out. ++ //Initialized in MiniportInitialize ++ PHTTX_BUFFER TransferBuffer; //Initialized in MiniportInitialize ++ ULONG BulkOutSize; // Indicate the total bulk-out size in bytes in one bulk-transmission ++ UCHAR BulkOutPipeId; ++ BOOLEAN IRPPending; ++ BOOLEAN LastOne; ++ BOOLEAN bCurWriting; ++ BOOLEAN bRingEmpty; ++ BOOLEAN bCopySavePad; ++ UCHAR SavedPad[8]; ++ UCHAR Header_802_3[LENGTH_802_3]; ++ ULONG CurWritePosition; // Indicate the buffer offset which packet will be inserted start from. ++ ULONG CurWriteRealPos; // Indicate the buffer offset which packet now are writing to. ++ ULONG NextBulkOutPosition; // Indicate the buffer start offset of a bulk-transmission ++ ULONG ENextBulkOutPosition; // Indicate the buffer end offset of a bulk-transmission ++ UINT TxRate; ++ dma_addr_t data_dma; // urb dma on linux ++} HT_TX_CONTEXT, *PHT_TX_CONTEXT, **PPHT_TX_CONTEXT; ++ ++ ++// ++// Structure to keep track of receive packets and buffers to indicate ++// receive data to the protocol. ++// ++typedef struct _RX_CONTEXT ++{ ++ PUCHAR TransferBuffer; ++ PVOID pAd; ++ PIRP pIrp;//used to cancel pending bulk in. ++ PURB pUrb; ++ //These 2 Boolean shouldn't both be 1 at the same time. ++ ULONG BulkInOffset; // number of packets waiting for reordering . ++// BOOLEAN ReorderInUse; // At least one packet in this buffer are in reordering buffer and wait for receive indication ++ BOOLEAN bRxHandling; // Notify this packet is being process now. ++ BOOLEAN InUse; // USB Hardware Occupied. Wait for USB HW to put packet. ++ BOOLEAN Readable; // Receive Complete back. OK for driver to indicate receiving packet. ++ BOOLEAN IRPPending; // TODO: To be removed ++ atomic_t IrpLock; ++ NDIS_SPIN_LOCK RxContextLock; ++ dma_addr_t data_dma; // urb dma on linux ++} RX_CONTEXT, *PRX_CONTEXT; ++#endif // RT2870 // ++ ++ ++// ++// NDIS Version definitions ++// ++#ifdef NDIS50_MINIPORT ++#define RTMP_NDIS_MAJOR_VERSION 5 ++#define RTMP_NDIS_MINOR_VERSION 0 ++#endif ++ ++#ifdef NDIS51_MINIPORT ++#define RTMP_NDIS_MAJOR_VERSION 5 ++#define RTMP_NDIS_MINOR_VERSION 1 ++#endif ++ ++extern char NIC_VENDOR_DESC[]; ++extern int NIC_VENDOR_DESC_LEN; ++ ++extern unsigned char SNAP_AIRONET[]; ++extern unsigned char CipherSuiteCiscoCCKM[]; ++extern unsigned char CipherSuiteCiscoCCKMLen; ++extern unsigned char CipherSuiteCiscoCCKM24[]; ++extern unsigned char CipherSuiteCiscoCCKM24Len; ++extern unsigned char CipherSuiteCCXTkip[]; ++extern unsigned char CipherSuiteCCXTkipLen; ++extern unsigned char CISCO_OUI[]; ++extern UCHAR BaSizeArray[4]; ++ ++extern UCHAR BROADCAST_ADDR[MAC_ADDR_LEN]; ++extern UCHAR MULTICAST_ADDR[MAC_ADDR_LEN]; ++extern UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN]; ++extern ULONG BIT32[32]; ++extern UCHAR BIT8[8]; ++extern char* CipherName[]; ++extern char* MCSToMbps[]; ++extern UCHAR RxwiMCSToOfdmRate[12]; ++extern UCHAR SNAP_802_1H[6]; ++extern UCHAR SNAP_BRIDGE_TUNNEL[6]; ++extern UCHAR SNAP_AIRONET[8]; ++extern UCHAR CKIP_LLC_SNAP[8]; ++extern UCHAR EAPOL_LLC_SNAP[8]; ++extern UCHAR EAPOL[2]; ++extern UCHAR IPX[2]; ++extern UCHAR APPLE_TALK[2]; ++extern UCHAR RateIdToPlcpSignal[12]; // see IEEE802.11a-1999 p.14 ++extern UCHAR OfdmRateToRxwiMCS[]; ++extern UCHAR OfdmSignalToRateId[16] ; ++extern UCHAR default_cwmin[4]; ++extern UCHAR default_cwmax[4]; ++extern UCHAR default_sta_aifsn[4]; ++extern UCHAR MapUserPriorityToAccessCategory[8]; ++ ++extern USHORT RateUpPER[]; ++extern USHORT RateDownPER[]; ++extern UCHAR Phy11BNextRateDownward[]; ++extern UCHAR Phy11BNextRateUpward[]; ++extern UCHAR Phy11BGNextRateDownward[]; ++extern UCHAR Phy11BGNextRateUpward[]; ++extern UCHAR Phy11ANextRateDownward[]; ++extern UCHAR Phy11ANextRateUpward[]; ++extern CHAR RssiSafeLevelForTxRate[]; ++extern UCHAR RateIdToMbps[]; ++extern USHORT RateIdTo500Kbps[]; ++ ++extern UCHAR CipherSuiteWpaNoneTkip[]; ++extern UCHAR CipherSuiteWpaNoneTkipLen; ++ ++extern UCHAR CipherSuiteWpaNoneAes[]; ++extern UCHAR CipherSuiteWpaNoneAesLen; ++ ++extern UCHAR SsidIe; ++extern UCHAR SupRateIe; ++extern UCHAR ExtRateIe; ++ ++#ifdef DOT11_N_SUPPORT ++extern UCHAR HtCapIe; ++extern UCHAR AddHtInfoIe; ++extern UCHAR NewExtChanIe; ++#ifdef DOT11N_DRAFT3 ++extern UCHAR ExtHtCapIe; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++extern UCHAR ErpIe; ++extern UCHAR DsIe; ++extern UCHAR TimIe; ++extern UCHAR WpaIe; ++extern UCHAR Wpa2Ie; ++extern UCHAR IbssIe; ++extern UCHAR Ccx2Ie; ++extern UCHAR WapiIe; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WAPI_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR Ccx2IeInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR PowerConstraintIE[]; ++ ++ ++extern UCHAR RateSwitchTable[]; ++extern UCHAR RateSwitchTable11B[]; ++extern UCHAR RateSwitchTable11G[]; ++extern UCHAR RateSwitchTable11BG[]; ++ ++#ifdef DOT11_N_SUPPORT ++extern UCHAR RateSwitchTable11BGN1S[]; ++extern UCHAR RateSwitchTable11BGN2S[]; ++extern UCHAR RateSwitchTable11BGN2SForABand[]; ++extern UCHAR RateSwitchTable11N1S[]; ++extern UCHAR RateSwitchTable11N2S[]; ++extern UCHAR RateSwitchTable11N2SForABand[]; ++ ++#ifdef CONFIG_STA_SUPPORT ++extern UCHAR PRE_N_HT_OUI[]; ++#endif // CONFIG_STA_SUPPORT // ++#endif // DOT11_N_SUPPORT // ++ ++#define MAXSEQ (0xFFF) ++ ++#ifdef RALINK_ATE ++typedef struct _ATE_INFO { ++ UCHAR Mode; ++ CHAR TxPower0; ++ CHAR TxPower1; ++ CHAR TxAntennaSel; ++ CHAR RxAntennaSel; ++ TXWI_STRUC TxWI; // TXWI ++ USHORT QID; ++ UCHAR Addr1[MAC_ADDR_LEN]; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR Addr3[MAC_ADDR_LEN]; ++ UCHAR Channel; ++ UINT32 TxLength; ++ UINT32 TxCount; ++ UINT32 TxDoneCount; // Tx DMA Done ++ UINT32 RFFreqOffset; ++ BOOLEAN bRxFer; ++ BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. ++ BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. ++ UINT32 RxTotalCnt; ++ UINT32 RxCntPerSec; ++ ++ CHAR LastSNR0; // last received SNR ++ CHAR LastSNR1; // last received SNR for 2nd antenna ++ CHAR LastRssi0; // last received RSSI ++ CHAR LastRssi1; // last received RSSI for 2nd antenna ++ CHAR LastRssi2; // last received RSSI for 3rd antenna ++ CHAR AvgRssi0; // last 8 frames' average RSSI ++ CHAR AvgRssi1; // last 8 frames' average RSSI ++ CHAR AvgRssi2; // last 8 frames' average RSSI ++ SHORT AvgRssi0X8; // sum of last 8 frames' RSSI ++ SHORT AvgRssi1X8; // sum of last 8 frames' RSSI ++ SHORT AvgRssi2X8; // sum of last 8 frames' RSSI ++ ++ UINT32 NumOfAvgRssiSample; ++ ++#ifdef RALINK_28xx_QA ++ // Tx frame ++#ifdef RT2870 ++ /* not used in RT2860 */ ++ TXINFO_STRUC TxInfo; // TxInfo ++#endif // RT2870 // ++ USHORT HLen; // Header Length ++ USHORT PLen; // Pattern Length ++ UCHAR Header[32]; // Header buffer ++ UCHAR Pattern[32]; // Pattern buffer ++ USHORT DLen; // Data Length ++ USHORT seq; ++ UINT32 CID; ++ pid_t AtePid; ++ // counters ++ UINT32 U2M; ++ UINT32 OtherData; ++ UINT32 Beacon; ++ UINT32 OtherCount; ++ UINT32 TxAc0; ++ UINT32 TxAc1; ++ UINT32 TxAc2; ++ UINT32 TxAc3; ++ UINT32 TxHCCA; ++ UINT32 TxMgmt; ++ UINT32 RSSI0; ++ UINT32 RSSI1; ++ UINT32 RSSI2; ++ UINT32 SNR0; ++ UINT32 SNR1; ++ // control ++ //UINT32 Repeat; // Tx Cpu count ++ UCHAR TxStatus; // task Tx status // 0 --> task is idle, 1 --> task is running ++#endif // RALINK_28xx_QA // ++} ATE_INFO, *PATE_INFO; ++ ++#ifdef RALINK_28xx_QA ++struct ate_racfghdr { ++ UINT32 magic_no; ++ USHORT command_type; ++ USHORT command_id; ++ USHORT length; ++ USHORT sequence; ++ USHORT status; ++ UCHAR data[2046]; ++} __attribute__((packed)); ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++struct reordering_mpdu ++{ ++ struct reordering_mpdu *next; ++ PNDIS_PACKET pPacket; /* coverted to 802.3 frame */ ++ int Sequence; /* sequence number of MPDU */ ++ BOOLEAN bAMSDU; ++}; ++ ++struct reordering_list ++{ ++ struct reordering_mpdu *next; ++ int qlen; ++}; ++ ++struct reordering_mpdu_pool ++{ ++ PVOID mem; ++ NDIS_SPIN_LOCK lock; ++ struct reordering_list freelist; ++}; ++#endif // DOT11_N_SUPPORT // ++ ++typedef struct _RSSI_SAMPLE { ++ CHAR LastRssi0; // last received RSSI ++ CHAR LastRssi1; // last received RSSI ++ CHAR LastRssi2; // last received RSSI ++ CHAR AvgRssi0; ++ CHAR AvgRssi1; ++ CHAR AvgRssi2; ++ SHORT AvgRssi0X8; ++ SHORT AvgRssi1X8; ++ SHORT AvgRssi2X8; ++} RSSI_SAMPLE; ++ ++// ++// Queue structure and macros ++// ++typedef struct _QUEUE_ENTRY { ++ struct _QUEUE_ENTRY *Next; ++} QUEUE_ENTRY, *PQUEUE_ENTRY; ++ ++// Queue structure ++typedef struct _QUEUE_HEADER { ++ PQUEUE_ENTRY Head; ++ PQUEUE_ENTRY Tail; ++ ULONG Number; ++} QUEUE_HEADER, *PQUEUE_HEADER; ++ ++#define InitializeQueueHeader(QueueHeader) \ ++{ \ ++ (QueueHeader)->Head = (QueueHeader)->Tail = NULL; \ ++ (QueueHeader)->Number = 0; \ ++} ++ ++#define RemoveHeadQueue(QueueHeader) \ ++(QueueHeader)->Head; \ ++{ \ ++ PQUEUE_ENTRY pNext; \ ++ if ((QueueHeader)->Head != NULL) \ ++ { \ ++ pNext = (QueueHeader)->Head->Next; \ ++ (QueueHeader)->Head = pNext; \ ++ if (pNext == NULL) \ ++ (QueueHeader)->Tail = NULL; \ ++ (QueueHeader)->Number--; \ ++ } \ ++} ++ ++#define InsertHeadQueue(QueueHeader, QueueEntry) \ ++{ \ ++ ((PQUEUE_ENTRY)QueueEntry)->Next = (QueueHeader)->Head; \ ++ (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ ++ if ((QueueHeader)->Tail == NULL) \ ++ (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Number++; \ ++} ++ ++#define InsertTailQueue(QueueHeader, QueueEntry) \ ++{ \ ++ ((PQUEUE_ENTRY)QueueEntry)->Next = NULL; \ ++ if ((QueueHeader)->Tail) \ ++ (QueueHeader)->Tail->Next = (PQUEUE_ENTRY)(QueueEntry); \ ++ else \ ++ (QueueHeader)->Head = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Tail = (PQUEUE_ENTRY)(QueueEntry); \ ++ (QueueHeader)->Number++; \ ++} ++ ++// ++// Macros for flag and ref count operations ++// ++#define RTMP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) ++#define RTMP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) ++#define RTMP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) ++#define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) ++#define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) ++ ++#define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) ++#define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) ++#define OPSTATUS_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.OpStatusFlags & (_F)) != 0) ++ ++#define CLIENT_STATUS_SET_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags |= (_F)) ++#define CLIENT_STATUS_CLEAR_FLAG(_pEntry,_F) ((_pEntry)->ClientStatusFlags &= ~(_F)) ++#define CLIENT_STATUS_TEST_FLAG(_pEntry,_F) (((_pEntry)->ClientStatusFlags & (_F)) != 0) ++ ++#define RX_FILTER_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter |= (_F)) ++#define RX_FILTER_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.PacketFilter &= ~(_F)) ++#define RX_FILTER_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.PacketFilter & (_F)) != 0) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define STA_NO_SECURITY_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) ++#define STA_WEP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) ++#define STA_TKIP_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++#define STA_AES_ON(_p) (_p->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ ++#define STA_TGN_WIFI_ON(_p) (_p->StaCfg.bTGnWifiTest == TRUE) ++#endif // CONFIG_STA_SUPPORT // ++ ++#define CKIP_KP_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x10) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) ++#define CKIP_CMIC_ON(_p) ((((_p)->StaCfg.CkipFlag) & 0x08) && ((_p)->StaCfg.bCkipCmicOn == TRUE)) ++ ++ ++#define INC_RING_INDEX(_idx, _RingSize) \ ++{ \ ++ (_idx) = (_idx+1) % (_RingSize); \ ++} ++ ++// We will have a cost down version which mac version is 0x3090xxxx ++#define IS_RT3090(_pAd) ((((_pAd)->MACVersion & 0xffff0000) == 0x30710000) || (((_pAd)->MACVersion & 0xffff0000) == 0x30900000)) ++ ++#define IS_RT3070(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30700000) ++#define IS_RT3071(_pAd) (((_pAd)->MACVersion & 0xffff0000) == 0x30710000) ++#define IS_RT2070(_pAd) (((_pAd)->RfIcType == RFIC_2020) || ((_pAd)->EFuseTag == 0x27)) ++ ++#define IS_RT30xx(_pAd) (((_pAd)->MACVersion & 0xfff00000) == 0x30700000) ++ ++#define RING_PACKET_INIT(_TxRing, _idx) \ ++{ \ ++ _TxRing->Cell[_idx].pNdisPacket = NULL; \ ++ _TxRing->Cell[_idx].pNextNdisPacket = NULL; \ ++} ++ ++#define TXDT_INIT(_TxD) \ ++{ \ ++ NdisZeroMemory(_TxD, TXD_SIZE); \ ++ _TxD->DMADONE = 1; \ ++} ++ ++//Set last data segment ++#define RING_SET_LASTDS(_TxD, _IsSD0) \ ++{ \ ++ if (_IsSD0) {_TxD->LastSec0 = 1;} \ ++ else {_TxD->LastSec1 = 1;} \ ++} ++ ++// Increase TxTsc value for next transmission ++// TODO: ++// When i==6, means TSC has done one full cycle, do re-keying stuff follow specs ++// Should send a special event microsoft defined to request re-key ++#define INC_TX_TSC(_tsc) \ ++{ \ ++ int i=0; \ ++ while (++_tsc[i] == 0x0) \ ++ { \ ++ i++; \ ++ if (i == 6) \ ++ break; \ ++ } \ ++} ++ ++#ifdef DOT11_N_SUPPORT ++// StaActive.SupportedHtPhy.MCSSet is copied from AP beacon. Don't need to update here. ++#define COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ ++{ \ ++ _pAd->StaActive.SupportedHtPhy.ChannelWidth = _pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth; \ ++ _pAd->StaActive.SupportedHtPhy.MimoPs = _pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs; \ ++ _pAd->StaActive.SupportedHtPhy.GF = _pAd->MlmeAux.HtCapability.HtCapInfo.GF; \ ++ _pAd->StaActive.SupportedHtPhy.ShortGIfor20 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20; \ ++ _pAd->StaActive.SupportedHtPhy.ShortGIfor40 = _pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40; \ ++ _pAd->StaActive.SupportedHtPhy.TxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC; \ ++ _pAd->StaActive.SupportedHtPhy.RxSTBC = _pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC; \ ++ _pAd->StaActive.SupportedHtPhy.ExtChanOffset = _pAd->MlmeAux.AddHtInfo.AddHtInfo.ExtChanOffset; \ ++ _pAd->StaActive.SupportedHtPhy.RecomWidth = _pAd->MlmeAux.AddHtInfo.AddHtInfo.RecomWidth; \ ++ _pAd->StaActive.SupportedHtPhy.OperaionMode = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode; \ ++ _pAd->StaActive.SupportedHtPhy.NonGfPresent = _pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent; \ ++ NdisMoveMemory((_pAd)->MacTab.Content[BSSID_WCID].HTCapability.MCSSet, (_pAd)->StaActive.SupportedPhyInfo.MCSSet, sizeof(UCHAR) * 16);\ ++} ++ ++#define COPY_AP_HTSETTINGS_FROM_BEACON(_pAd, _pHtCapability) \ ++{ \ ++ _pAd->MacTab.Content[BSSID_WCID].AMsduSize = (UCHAR)(_pHtCapability->HtCapInfo.AMsduSize); \ ++ _pAd->MacTab.Content[BSSID_WCID].MmpsMode= (UCHAR)(_pHtCapability->HtCapInfo.MimoPs); \ ++ _pAd->MacTab.Content[BSSID_WCID].MaxRAmpduFactor = (UCHAR)(_pHtCapability->HtCapParm.MaxRAmpduFactor); \ ++} ++#endif // DOT11_N_SUPPORT // ++ ++// ++// MACRO for 32-bit PCI register read / write ++// ++// Usage : RTMP_IO_READ32( ++// PRTMP_ADAPTER pAd, ++// ULONG Register_Offset, ++// PULONG pValue) ++// ++// RTMP_IO_WRITE32( ++// PRTMP_ADAPTER pAd, ++// ULONG Register_Offset, ++// ULONG Value) ++// ++ ++// ++// BBP & RF are using indirect access. Before write any value into it. ++// We have to make sure there is no outstanding command pending via checking busy bit. ++// ++#define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register ++// ++ ++#ifdef RT2870 ++#define RTMP_RF_IO_WRITE32(_A, _V) RTUSBWriteRFRegister(_A, _V) ++#define RTMP_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) ++#define RTMP_BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) ++ ++#define BBP_IO_WRITE8_BY_REG_ID(_A, _I, _V) RTUSBWriteBBPRegister(_A, _I, _V) ++#define BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) RTUSBReadBBPRegister(_A, _I, _pV) ++#endif // RT2870 // ++ ++#ifdef RT30xx ++#define RTMP_RF_IO_READ8_BY_REG_ID(_A, _I, _pV) RT30xxReadRFRegister(_A, _I, _pV) ++#define RTMP_RF_IO_WRITE8_BY_REG_ID(_A, _I, _V) RT30xxWriteRFRegister(_A, _I, _V) ++#endif // RT30xx // ++ ++#define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ ++ switch (ch) \ ++ { \ ++ case 1: khz = 2412000; break; \ ++ case 2: khz = 2417000; break; \ ++ case 3: khz = 2422000; break; \ ++ case 4: khz = 2427000; break; \ ++ case 5: khz = 2432000; break; \ ++ case 6: khz = 2437000; break; \ ++ case 7: khz = 2442000; break; \ ++ case 8: khz = 2447000; break; \ ++ case 9: khz = 2452000; break; \ ++ case 10: khz = 2457000; break; \ ++ case 11: khz = 2462000; break; \ ++ case 12: khz = 2467000; break; \ ++ case 13: khz = 2472000; break; \ ++ case 14: khz = 2484000; break; \ ++ case 36: /* UNII */ khz = 5180000; break; \ ++ case 40: /* UNII */ khz = 5200000; break; \ ++ case 44: /* UNII */ khz = 5220000; break; \ ++ case 48: /* UNII */ khz = 5240000; break; \ ++ case 52: /* UNII */ khz = 5260000; break; \ ++ case 56: /* UNII */ khz = 5280000; break; \ ++ case 60: /* UNII */ khz = 5300000; break; \ ++ case 64: /* UNII */ khz = 5320000; break; \ ++ case 149: /* UNII */ khz = 5745000; break; \ ++ case 153: /* UNII */ khz = 5765000; break; \ ++ case 157: /* UNII */ khz = 5785000; break; \ ++ case 161: /* UNII */ khz = 5805000; break; \ ++ case 165: /* UNII */ khz = 5825000; break; \ ++ case 100: /* HiperLAN2 */ khz = 5500000; break; \ ++ case 104: /* HiperLAN2 */ khz = 5520000; break; \ ++ case 108: /* HiperLAN2 */ khz = 5540000; break; \ ++ case 112: /* HiperLAN2 */ khz = 5560000; break; \ ++ case 116: /* HiperLAN2 */ khz = 5580000; break; \ ++ case 120: /* HiperLAN2 */ khz = 5600000; break; \ ++ case 124: /* HiperLAN2 */ khz = 5620000; break; \ ++ case 128: /* HiperLAN2 */ khz = 5640000; break; \ ++ case 132: /* HiperLAN2 */ khz = 5660000; break; \ ++ case 136: /* HiperLAN2 */ khz = 5680000; break; \ ++ case 140: /* HiperLAN2 */ khz = 5700000; break; \ ++ case 34: /* Japan MMAC */ khz = 5170000; break; \ ++ case 38: /* Japan MMAC */ khz = 5190000; break; \ ++ case 42: /* Japan MMAC */ khz = 5210000; break; \ ++ case 46: /* Japan MMAC */ khz = 5230000; break; \ ++ case 184: /* Japan */ khz = 4920000; break; \ ++ case 188: /* Japan */ khz = 4940000; break; \ ++ case 192: /* Japan */ khz = 4960000; break; \ ++ case 196: /* Japan */ khz = 4980000; break; \ ++ case 208: /* Japan, means J08 */ khz = 5040000; break; \ ++ case 212: /* Japan, means J12 */ khz = 5060000; break; \ ++ case 216: /* Japan, means J16 */ khz = 5080000; break; \ ++ default: khz = 2412000; break; \ ++ } \ ++ } ++ ++#define MAP_KHZ_TO_CHANNEL_ID(khz, ch) { \ ++ switch (khz) \ ++ { \ ++ case 2412000: ch = 1; break; \ ++ case 2417000: ch = 2; break; \ ++ case 2422000: ch = 3; break; \ ++ case 2427000: ch = 4; break; \ ++ case 2432000: ch = 5; break; \ ++ case 2437000: ch = 6; break; \ ++ case 2442000: ch = 7; break; \ ++ case 2447000: ch = 8; break; \ ++ case 2452000: ch = 9; break; \ ++ case 2457000: ch = 10; break; \ ++ case 2462000: ch = 11; break; \ ++ case 2467000: ch = 12; break; \ ++ case 2472000: ch = 13; break; \ ++ case 2484000: ch = 14; break; \ ++ case 5180000: ch = 36; /* UNII */ break; \ ++ case 5200000: ch = 40; /* UNII */ break; \ ++ case 5220000: ch = 44; /* UNII */ break; \ ++ case 5240000: ch = 48; /* UNII */ break; \ ++ case 5260000: ch = 52; /* UNII */ break; \ ++ case 5280000: ch = 56; /* UNII */ break; \ ++ case 5300000: ch = 60; /* UNII */ break; \ ++ case 5320000: ch = 64; /* UNII */ break; \ ++ case 5745000: ch = 149; /* UNII */ break; \ ++ case 5765000: ch = 153; /* UNII */ break; \ ++ case 5785000: ch = 157; /* UNII */ break; \ ++ case 5805000: ch = 161; /* UNII */ break; \ ++ case 5825000: ch = 165; /* UNII */ break; \ ++ case 5500000: ch = 100; /* HiperLAN2 */ break; \ ++ case 5520000: ch = 104; /* HiperLAN2 */ break; \ ++ case 5540000: ch = 108; /* HiperLAN2 */ break; \ ++ case 5560000: ch = 112; /* HiperLAN2 */ break; \ ++ case 5580000: ch = 116; /* HiperLAN2 */ break; \ ++ case 5600000: ch = 120; /* HiperLAN2 */ break; \ ++ case 5620000: ch = 124; /* HiperLAN2 */ break; \ ++ case 5640000: ch = 128; /* HiperLAN2 */ break; \ ++ case 5660000: ch = 132; /* HiperLAN2 */ break; \ ++ case 5680000: ch = 136; /* HiperLAN2 */ break; \ ++ case 5700000: ch = 140; /* HiperLAN2 */ break; \ ++ case 5170000: ch = 34; /* Japan MMAC */ break; \ ++ case 5190000: ch = 38; /* Japan MMAC */ break; \ ++ case 5210000: ch = 42; /* Japan MMAC */ break; \ ++ case 5230000: ch = 46; /* Japan MMAC */ break; \ ++ case 4920000: ch = 184; /* Japan */ break; \ ++ case 4940000: ch = 188; /* Japan */ break; \ ++ case 4960000: ch = 192; /* Japan */ break; \ ++ case 4980000: ch = 196; /* Japan */ break; \ ++ case 5040000: ch = 208; /* Japan, means J08 */ break; \ ++ case 5060000: ch = 212; /* Japan, means J12 */ break; \ ++ case 5080000: ch = 216; /* Japan, means J16 */ break; \ ++ default: ch = 1; break; \ ++ } \ ++ } ++ ++// ++// Common fragment list structure - Identical to the scatter gather frag list structure ++// ++//#define RTMP_SCATTER_GATHER_ELEMENT SCATTER_GATHER_ELEMENT ++//#define PRTMP_SCATTER_GATHER_ELEMENT PSCATTER_GATHER_ELEMENT ++#define NIC_MAX_PHYS_BUF_COUNT 8 ++ ++typedef struct _RTMP_SCATTER_GATHER_ELEMENT { ++ PVOID Address; ++ ULONG Length; ++ PULONG Reserved; ++} RTMP_SCATTER_GATHER_ELEMENT, *PRTMP_SCATTER_GATHER_ELEMENT; ++ ++ ++typedef struct _RTMP_SCATTER_GATHER_LIST { ++ ULONG NumberOfElements; ++ PULONG Reserved; ++ RTMP_SCATTER_GATHER_ELEMENT Elements[NIC_MAX_PHYS_BUF_COUNT]; ++} RTMP_SCATTER_GATHER_LIST, *PRTMP_SCATTER_GATHER_LIST; ++ ++// ++// Some utility macros ++// ++#ifndef min ++#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) ++#endif ++ ++#ifndef max ++#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) ++#endif ++ ++#define GET_LNA_GAIN(_pAd) ((_pAd->LatchRfRegs.Channel <= 14) ? (_pAd->BLNAGain) : ((_pAd->LatchRfRegs.Channel <= 64) ? (_pAd->ALNAGain0) : ((_pAd->LatchRfRegs.Channel <= 128) ? (_pAd->ALNAGain1) : (_pAd->ALNAGain2)))) ++ ++#define INC_COUNTER64(Val) (Val.QuadPart++) ++ ++#define INFRA_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_INFRA_ON)) ++#define ADHOC_ON(_p) (OPSTATUS_TEST_FLAG(_p, fOP_STATUS_ADHOC_ON)) ++#define MONITOR_ON(_p) (((_p)->StaCfg.BssType) == BSS_MONITOR) ++#define IDLE_ON(_p) (!INFRA_ON(_p) && !ADHOC_ON(_p)) ++ ++// Check LEAP & CCKM flags ++#define LEAP_ON(_p) (((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) ++#define LEAP_CCKM_ON(_p) ((((_p)->StaCfg.LeapAuthMode) == CISCO_AuthModeLEAP) && ((_p)->StaCfg.LeapAuthInfo.CCKM == TRUE)) ++ ++// if orginal Ethernet frame contains no LLC/SNAP, then an extra LLC/SNAP encap is required ++#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(_pBufVA, _pExtraLlcSnapEncap) \ ++{ \ ++ if (((*(_pBufVA + 12) << 8) + *(_pBufVA + 13)) > 1500) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_802_1H; \ ++ if (NdisEqualMemory(IPX, _pBufVA + 12, 2) || \ ++ NdisEqualMemory(APPLE_TALK, _pBufVA + 12, 2)) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ _pExtraLlcSnapEncap = NULL; \ ++ } \ ++} ++ ++// New Define for new Tx Path. ++#define EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(_pBufVA, _pExtraLlcSnapEncap) \ ++{ \ ++ if (((*(_pBufVA) << 8) + *(_pBufVA + 1)) > 1500) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_802_1H; \ ++ if (NdisEqualMemory(IPX, _pBufVA, 2) || \ ++ NdisEqualMemory(APPLE_TALK, _pBufVA, 2)) \ ++ { \ ++ _pExtraLlcSnapEncap = SNAP_BRIDGE_TUNNEL; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ _pExtraLlcSnapEncap = NULL; \ ++ } \ ++} ++ ++ ++#define MAKE_802_3_HEADER(_p, _pMac1, _pMac2, _pType) \ ++{ \ ++ NdisMoveMemory(_p, _pMac1, MAC_ADDR_LEN); \ ++ NdisMoveMemory((_p + MAC_ADDR_LEN), _pMac2, MAC_ADDR_LEN); \ ++ NdisMoveMemory((_p + MAC_ADDR_LEN * 2), _pType, LENGTH_802_3_TYPE); \ ++} ++ ++// if pData has no LLC/SNAP (neither RFC1042 nor Bridge tunnel), keep it that way. ++// else if the received frame is LLC/SNAP-encaped IPX or APPLETALK, preserve the LLC/SNAP field ++// else remove the LLC/SNAP field from the result Ethernet frame ++// Patch for WHQL only, which did not turn on Netbios but use IPX within its payload ++// Note: ++// _pData & _DataSize may be altered (remove 8-byte LLC/SNAP) by this MACRO ++// _pRemovedLLCSNAP: pointer to removed LLC/SNAP; NULL is not removed ++#define CONVERT_TO_802_3(_p8023hdr, _pDA, _pSA, _pData, _DataSize, _pRemovedLLCSNAP) \ ++{ \ ++ char LLC_Len[2]; \ ++ \ ++ _pRemovedLLCSNAP = NULL; \ ++ if (NdisEqualMemory(SNAP_802_1H, _pData, 6) || \ ++ NdisEqualMemory(SNAP_BRIDGE_TUNNEL, _pData, 6)) \ ++ { \ ++ PUCHAR pProto = _pData + 6; \ ++ \ ++ if ((NdisEqualMemory(IPX, pProto, 2) || NdisEqualMemory(APPLE_TALK, pProto, 2)) && \ ++ NdisEqualMemory(SNAP_802_1H, _pData, 6)) \ ++ { \ ++ LLC_Len[0] = (UCHAR)(_DataSize / 256); \ ++ LLC_Len[1] = (UCHAR)(_DataSize % 256); \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ ++ } \ ++ else \ ++ { \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, pProto); \ ++ _pRemovedLLCSNAP = _pData; \ ++ _DataSize -= LENGTH_802_1_H; \ ++ _pData += LENGTH_802_1_H; \ ++ } \ ++ } \ ++ else \ ++ { \ ++ LLC_Len[0] = (UCHAR)(_DataSize / 256); \ ++ LLC_Len[1] = (UCHAR)(_DataSize % 256); \ ++ MAKE_802_3_HEADER(_p8023hdr, _pDA, _pSA, LLC_Len); \ ++ } \ ++} ++ ++#define SWITCH_AB( _pAA, _pBB) \ ++{ \ ++ PVOID pCC; \ ++ pCC = _pBB; \ ++ _pBB = _pAA; \ ++ _pAA = pCC; \ ++} ++ ++// Enqueue this frame to MLME engine ++// We need to enqueue the whole frame because MLME need to pass data type ++// information from 802.11 header ++#ifdef RT2870 ++#define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ ++{ \ ++ UINT32 High32TSF=0, Low32TSF=0; \ ++ MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ ++} ++#endif // RT2870 // ++ ++#ifdef RT30xx ++//Need to collect each ant's rssi concurrently ++//rssi1 is report to pair2 Ant and rss2 is reprot to pair1 Ant when 4 Ant ++#define COLLECT_RX_ANTENNA_AVERAGE_RSSI(_pAd, _rssi1, _rssi2) \ ++{ \ ++ SHORT AvgRssi; \ ++ UCHAR UsedAnt; \ ++ if (_pAd->RxAnt.EvaluatePeriod == 0) \ ++ { \ ++ UsedAnt = _pAd->RxAnt.Pair1PrimaryRxAnt; \ ++ AvgRssi = _pAd->RxAnt.Pair1AvgRssi[UsedAnt]; \ ++ if (AvgRssi < 0) \ ++ AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi1; \ ++ else \ ++ AvgRssi = _rssi1 << 3; \ ++ _pAd->RxAnt.Pair1AvgRssi[UsedAnt] = AvgRssi; \ ++ } \ ++ else \ ++ { \ ++ UsedAnt = _pAd->RxAnt.Pair1SecondaryRxAnt; \ ++ AvgRssi = _pAd->RxAnt.Pair1AvgRssi[UsedAnt]; \ ++ if ((AvgRssi < 0) && (_pAd->RxAnt.FirstPktArrivedWhenEvaluate)) \ ++ AvgRssi = AvgRssi - (AvgRssi >> 3) + _rssi1; \ ++ else \ ++ { \ ++ _pAd->RxAnt.FirstPktArrivedWhenEvaluate = TRUE; \ ++ AvgRssi = _rssi1 << 3; \ ++ } \ ++ _pAd->RxAnt.Pair1AvgRssi[UsedAnt] = AvgRssi; \ ++ _pAd->RxAnt.RcvPktNumWhenEvaluate++; \ ++ } \ ++} ++#endif // RT30xx // ++ ++ ++#define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ ++ NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) ++ ++#define MAC_ADDR_EQUAL(pAddr1,pAddr2) RTMPEqualMemory((PVOID)(pAddr1), (PVOID)(pAddr2), MAC_ADDR_LEN) ++#define SSID_EQUAL(ssid1, len1, ssid2, len2) ((len1==len2) && (RTMPEqualMemory(ssid1, ssid2, len1))) ++ ++// ++// Check if it is Japan W53(ch52,56,60,64) channel. ++// ++#define JapanChannelCheck(channel) ((channel == 52) || (channel == 56) || (channel == 60) || (channel == 64)) ++ ++#ifdef CONFIG_STA_SUPPORT ++#define STA_PORT_SECURED(_pAd) \ ++{ \ ++ _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ ++ NdisAcquireSpinLock(&_pAd->MacTabLock); \ ++ _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ ++ NdisReleaseSpinLock(&_pAd->MacTabLock); \ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++// ++// Register set pair for initialzation register set definition ++// ++typedef struct _RTMP_REG_PAIR ++{ ++ ULONG Register; ++ ULONG Value; ++} RTMP_REG_PAIR, *PRTMP_REG_PAIR; ++ ++typedef struct _REG_PAIR ++{ ++ UCHAR Register; ++ UCHAR Value; ++} REG_PAIR, *PREG_PAIR; ++ ++// ++// Register set pair for initialzation register set definition ++// ++typedef struct _RTMP_RF_REGS ++{ ++ UCHAR Channel; ++ ULONG R1; ++ ULONG R2; ++ ULONG R3; ++ ULONG R4; ++} RTMP_RF_REGS, *PRTMP_RF_REGS; ++ ++typedef struct _FREQUENCY_ITEM { ++ UCHAR Channel; ++ UCHAR N; ++ UCHAR R; ++ UCHAR K; ++} FREQUENCY_ITEM, *PFREQUENCY_ITEM; ++ ++// ++// Data buffer for DMA operation, the buffer must be contiguous physical memory ++// Both DMA to / from CPU use the same structure. ++// ++typedef struct _RTMP_DMABUF ++{ ++ ULONG AllocSize; ++ PVOID AllocVa; // TxBuf virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address ++} RTMP_DMABUF, *PRTMP_DMABUF; ++ ++ ++typedef union _HEADER_802_11_SEQ{ ++#ifdef RT_BIG_ENDIAN ++ struct { ++ USHORT Sequence:12; ++ USHORT Frag:4; ++ } field; ++#else ++ struct { ++ USHORT Frag:4; ++ USHORT Sequence:12; ++ } field; ++#endif ++ USHORT value; ++} HEADER_802_11_SEQ, *PHEADER_802_11_SEQ; ++ ++// ++// Data buffer for DMA operation, the buffer must be contiguous physical memory ++// Both DMA to / from CPU use the same structure. ++// ++typedef struct _RTMP_REORDERBUF ++{ ++ BOOLEAN IsFull; ++ PVOID AllocVa; // TxBuf virtual address ++ UCHAR Header802_3[14]; ++ HEADER_802_11_SEQ Sequence; //support compressed bitmap BA, so no consider fragment in BA ++ UCHAR DataOffset; ++ USHORT Datasize; ++ ULONG AllocSize; ++#ifdef RT2870 ++ PUCHAR AllocPa; ++#endif // RT2870 // ++} RTMP_REORDERBUF, *PRTMP_REORDERBUF; ++ ++// ++// Control block (Descriptor) for all ring descriptor DMA operation, buffer must be ++// contiguous physical memory. NDIS_PACKET stored the binding Rx packet descriptor ++// which won't be released, driver has to wait until upper layer return the packet ++// before giveing up this rx ring descriptor to ASIC. NDIS_BUFFER is assocaited pair ++// to describe the packet buffer. For Tx, NDIS_PACKET stored the tx packet descriptor ++// which driver should ACK upper layer when the tx is physically done or failed. ++// ++typedef struct _RTMP_DMACB ++{ ++ ULONG AllocSize; // Control block size ++ PVOID AllocVa; // Control block virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address ++ PNDIS_PACKET pNdisPacket; ++ PNDIS_PACKET pNextNdisPacket; ++ ++ RTMP_DMABUF DmaBuf; // Associated DMA buffer structure ++} RTMP_DMACB, *PRTMP_DMACB; ++ ++typedef struct _RTMP_TX_BUF ++{ ++ PQUEUE_ENTRY Next; ++ UCHAR Index; ++ ULONG AllocSize; // Control block size ++ PVOID AllocVa; // Control block virtual address ++ NDIS_PHYSICAL_ADDRESS AllocPa; // Control block physical address ++} RTMP_TXBUF, *PRTMP_TXBUF; ++ ++typedef struct _RTMP_RX_BUF ++{ ++ BOOLEAN InUse; ++ ULONG ByBaRecIndex; ++ RTMP_REORDERBUF MAP_RXBuf[MAX_RX_REORDERBUF]; ++} RTMP_RXBUF, *PRTMP_RXBUF; ++typedef struct _RTMP_TX_RING ++{ ++ RTMP_DMACB Cell[TX_RING_SIZE]; ++ UINT32 TxCpuIdx; ++ UINT32 TxDmaIdx; ++ UINT32 TxSwFreeIdx; // software next free tx index ++} RTMP_TX_RING, *PRTMP_TX_RING; ++ ++typedef struct _RTMP_RX_RING ++{ ++ RTMP_DMACB Cell[RX_RING_SIZE]; ++ UINT32 RxCpuIdx; ++ UINT32 RxDmaIdx; ++ INT32 RxSwReadIdx; // software next read index ++} RTMP_RX_RING, *PRTMP_RX_RING; ++ ++typedef struct _RTMP_MGMT_RING ++{ ++ RTMP_DMACB Cell[MGMT_RING_SIZE]; ++ UINT32 TxCpuIdx; ++ UINT32 TxDmaIdx; ++ UINT32 TxSwFreeIdx; // software next free tx index ++} RTMP_MGMT_RING, *PRTMP_MGMT_RING; ++ ++// ++// Statistic counter structure ++// ++typedef struct _COUNTER_802_3 ++{ ++ // General Stats ++ ULONG GoodTransmits; ++ ULONG GoodReceives; ++ ULONG TxErrors; ++ ULONG RxErrors; ++ ULONG RxNoBuffer; ++ ++ // Ethernet Stats ++ ULONG RcvAlignmentErrors; ++ ULONG OneCollision; ++ ULONG MoreCollisions; ++ ++} COUNTER_802_3, *PCOUNTER_802_3; ++ ++typedef struct _COUNTER_802_11 { ++ ULONG Length; ++ LARGE_INTEGER LastTransmittedFragmentCount; ++ LARGE_INTEGER TransmittedFragmentCount; ++ LARGE_INTEGER MulticastTransmittedFrameCount; ++ LARGE_INTEGER FailedCount; ++ LARGE_INTEGER RetryCount; ++ LARGE_INTEGER MultipleRetryCount; ++ LARGE_INTEGER RTSSuccessCount; ++ LARGE_INTEGER RTSFailureCount; ++ LARGE_INTEGER ACKFailureCount; ++ LARGE_INTEGER FrameDuplicateCount; ++ LARGE_INTEGER ReceivedFragmentCount; ++ LARGE_INTEGER MulticastReceivedFrameCount; ++ LARGE_INTEGER FCSErrorCount; ++} COUNTER_802_11, *PCOUNTER_802_11; ++ ++typedef struct _COUNTER_RALINK { ++ ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput ++ ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput ++ ULONG BeenDisassociatedCount; ++ ULONG BadCQIAutoRecoveryCount; ++ ULONG PoorCQIRoamingCount; ++ ULONG MgmtRingFullCount; ++ ULONG RxCountSinceLastNULL; ++ ULONG RxCount; ++ ULONG RxRingErrCount; ++ ULONG KickTxCount; ++ ULONG TxRingErrCount; ++ LARGE_INTEGER RealFcsErrCount; ++ ULONG PendingNdisPacketCount; ++ ++ ULONG OneSecOsTxCount[NUM_OF_TX_RING]; ++ ULONG OneSecDmaDoneCount[NUM_OF_TX_RING]; ++ UINT32 OneSecTxDoneCount; ++ ULONG OneSecRxCount; ++ UINT32 OneSecTxAggregationCount; ++ UINT32 OneSecRxAggregationCount; ++ ++ UINT32 OneSecFrameDuplicateCount; ++ ++#ifdef RT2870 ++ ULONG OneSecTransmittedByteCount; // both successful and failure, used to calculate TX throughput ++#endif // RT2870 // ++ ++ UINT32 OneSecTxNoRetryOkCount; ++ UINT32 OneSecTxRetryOkCount; ++ UINT32 OneSecTxFailCount; ++ UINT32 OneSecFalseCCACnt; // CCA error count, for debug purpose, might move to global counter ++ UINT32 OneSecRxOkCnt; // RX without error ++ UINT32 OneSecRxOkDataCnt; // unicast-to-me DATA frame count ++ UINT32 OneSecRxFcsErrCnt; // CRC error ++ UINT32 OneSecBeaconSentCnt; ++ UINT32 LastOneSecTotalTxCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount ++ UINT32 LastOneSecRxOkDataCnt; // OneSecRxOkDataCnt ++ ULONG DuplicateRcv; ++ ULONG TxAggCount; ++ ULONG TxNonAggCount; ++ ULONG TxAgg1MPDUCount; ++ ULONG TxAgg2MPDUCount; ++ ULONG TxAgg3MPDUCount; ++ ULONG TxAgg4MPDUCount; ++ ULONG TxAgg5MPDUCount; ++ ULONG TxAgg6MPDUCount; ++ ULONG TxAgg7MPDUCount; ++ ULONG TxAgg8MPDUCount; ++ ULONG TxAgg9MPDUCount; ++ ULONG TxAgg10MPDUCount; ++ ULONG TxAgg11MPDUCount; ++ ULONG TxAgg12MPDUCount; ++ ULONG TxAgg13MPDUCount; ++ ULONG TxAgg14MPDUCount; ++ ULONG TxAgg15MPDUCount; ++ ULONG TxAgg16MPDUCount; ++ ++ LARGE_INTEGER TransmittedOctetsInAMSDU; ++ LARGE_INTEGER TransmittedAMSDUCount; ++ LARGE_INTEGER ReceivedOctesInAMSDUCount; ++ LARGE_INTEGER ReceivedAMSDUCount; ++ LARGE_INTEGER TransmittedAMPDUCount; ++ LARGE_INTEGER TransmittedMPDUsInAMPDUCount; ++ LARGE_INTEGER TransmittedOctetsInAMPDUCount; ++ LARGE_INTEGER MPDUInReceivedAMPDUCount; ++} COUNTER_RALINK, *PCOUNTER_RALINK; ++ ++typedef struct _PID_COUNTER { ++ ULONG TxAckRequiredCount; // CRC error ++ ULONG TxAggreCount; ++ ULONG TxSuccessCount; // OneSecTxNoRetryOkCount + OneSecTxRetryOkCount + OneSecTxFailCount ++ ULONG LastSuccessRate; ++} PID_COUNTER, *PPID_COUNTER; ++ ++typedef struct _COUNTER_DRS { ++ // to record the each TX rate's quality. 0 is best, the bigger the worse. ++ USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++ ULONG CurrTxRateStableTime; // # of second in current TX rate ++ BOOLEAN fNoisyEnvironment; ++ BOOLEAN fLastSecAccordingRSSI; ++ UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down ++ UCHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction ++ ULONG LastTxOkCount; ++} COUNTER_DRS, *PCOUNTER_DRS; ++ ++// ++// Arcfour Structure Added by PaulWu ++// ++typedef struct _ARCFOUR ++{ ++ UINT X; ++ UINT Y; ++ UCHAR STATE[256]; ++} ARCFOURCONTEXT, *PARCFOURCONTEXT; ++ ++// MIMO Tx parameter, ShortGI, MCS, STBC, etc. these are fields in TXWI too. just copy to TXWI. ++typedef struct _RECEIVE_SETTING { ++#ifdef RT_BIG_ENDIAN ++ USHORT MIMO:1; ++ USHORT OFDM:1; ++ USHORT rsv:3; ++ USHORT STBC:2; //SPACE ++ USHORT ShortGI:1; ++ USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz ++ USHORT NumOfRX:2; // MIMO. WE HAVE 3R ++#else ++ USHORT NumOfRX:2; // MIMO. WE HAVE 3R ++ USHORT Mode:2; //channel bandwidth 20MHz or 40 MHz ++ USHORT ShortGI:1; ++ USHORT STBC:2; //SPACE ++ USHORT rsv:3; ++ USHORT OFDM:1; ++ USHORT MIMO:1; ++#endif ++ } RECEIVE_SETTING, *PRECEIVE_SETTING; ++ ++// Shared key data structure ++typedef struct _WEP_KEY { ++ UCHAR KeyLen; // Key length for each key, 0: entry is invalid ++ UCHAR Key[MAX_LEN_OF_KEY]; // right now we implement 4 keys, 128 bits max ++} WEP_KEY, *PWEP_KEY; ++ ++typedef struct _CIPHER_KEY { ++ UCHAR Key[16]; // right now we implement 4 keys, 128 bits max ++ UCHAR RxMic[8]; // make alignment ++ UCHAR TxMic[8]; ++ UCHAR TxTsc[6]; // 48bit TSC value ++ UCHAR RxTsc[6]; // 48bit TSC value ++ UCHAR CipherAlg; // 0-none, 1:WEP64, 2:WEP128, 3:TKIP, 4:AES, 5:CKIP64, 6:CKIP128 ++ UCHAR KeyLen; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR BssId[6]; ++#endif // CONFIG_STA_SUPPORT // ++ // Key length for each key, 0: entry is invalid ++ UCHAR Type; // Indicate Pairwise/Group when reporting MIC error ++} CIPHER_KEY, *PCIPHER_KEY; ++ ++typedef struct _BBP_TUNING_STRUCT { ++ BOOLEAN Enable; ++ UCHAR FalseCcaCountUpperBound; // 100 per sec ++ UCHAR FalseCcaCountLowerBound; // 10 per sec ++ UCHAR R17LowerBound; // specified in E2PROM ++ UCHAR R17UpperBound; // 0x68 according to David Tung ++ UCHAR CurrentR17Value; ++} BBP_TUNING, *PBBP_TUNING; ++ ++typedef struct _SOFT_RX_ANT_DIVERSITY_STRUCT { ++ UCHAR EvaluatePeriod; // 0:not evalute status, 1: evaluate status, 2: switching status ++ UCHAR EvaluateStableCnt; ++ UCHAR Pair1PrimaryRxAnt; // 0:Ant-E1, 1:Ant-E2 ++ UCHAR Pair1SecondaryRxAnt; // 0:Ant-E1, 1:Ant-E2 ++ UCHAR Pair2PrimaryRxAnt; // 0:Ant-E3, 1:Ant-E4 ++ UCHAR Pair2SecondaryRxAnt; // 0:Ant-E3, 1:Ant-E4 ++ SHORT Pair1AvgRssi[2]; // AvgRssi[0]:E1, AvgRssi[1]:E2 ++ SHORT Pair2AvgRssi[2]; // AvgRssi[0]:E3, AvgRssi[1]:E4 ++ SHORT Pair1LastAvgRssi; // ++ SHORT Pair2LastAvgRssi; // ++ ULONG RcvPktNumWhenEvaluate; ++ BOOLEAN FirstPktArrivedWhenEvaluate; ++ RALINK_TIMER_STRUCT RxAntDiversityTimer; ++} SOFT_RX_ANT_DIVERSITY, *PSOFT_RX_ANT_DIVERSITY; ++ ++typedef struct _LEAP_AUTH_INFO { ++ BOOLEAN Enabled; //Ture: Enable LEAP Authentication ++ BOOLEAN CCKM; //Ture: Use Fast Reauthentication with CCKM ++ UCHAR Reserve[2]; ++ UCHAR UserName[256]; //LEAP, User name ++ ULONG UserNameLen; ++ UCHAR Password[256]; //LEAP, User Password ++ ULONG PasswordLen; ++} LEAP_AUTH_INFO, *PLEAP_AUTH_INFO; ++ ++typedef struct { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR ErrorCode[2]; //00 01-Invalid authentication type ++ //00 02-Authentication timeout ++ //00 03-Challenge from AP failed ++ //00 04-Challenge to AP failed ++ BOOLEAN Reported; ++} ROGUEAP_ENTRY, *PROGUEAP_ENTRY; ++ ++typedef struct { ++ UCHAR RogueApNr; ++ ROGUEAP_ENTRY RogueApEntry[MAX_LEN_OF_BSS_TABLE]; ++} ROGUEAP_TABLE, *PROGUEAP_TABLE; ++ ++typedef struct { ++ BOOLEAN Enable; ++ UCHAR Delta; ++ BOOLEAN PlusSign; ++} CCK_TX_POWER_CALIBRATE, *PCCK_TX_POWER_CALIBRATE; ++ ++// ++// Receive Tuple Cache Format ++// ++typedef struct _TUPLE_CACHE { ++ BOOLEAN Valid; ++ UCHAR MacAddress[MAC_ADDR_LEN]; ++ USHORT Sequence; ++ USHORT Frag; ++} TUPLE_CACHE, *PTUPLE_CACHE; ++ ++// ++// Fragment Frame structure ++// ++typedef struct _FRAGMENT_FRAME { ++ PNDIS_PACKET pFragPacket; ++ ULONG RxSize; ++ USHORT Sequence; ++ USHORT LastFrag; ++ ULONG Flags; // Some extra frame information. bit 0: LLC presented ++} FRAGMENT_FRAME, *PFRAGMENT_FRAME; ++ ++ ++// ++// Packet information for NdisQueryPacket ++// ++typedef struct _PACKET_INFO { ++ UINT PhysicalBufferCount; // Physical breaks of buffer descripor chained ++ UINT BufferCount ; // Number of Buffer descriptor chained ++ UINT TotalPacketLength ; // Self explained ++ PNDIS_BUFFER pFirstBuffer; // Pointer to first buffer descriptor ++} PACKET_INFO, *PPACKET_INFO; ++ ++// ++// Tkip Key structure which RC4 key & MIC calculation ++// ++typedef struct _TKIP_KEY_INFO { ++ UINT nBytesInM; // # bytes in M for MICKEY ++ ULONG IV16; ++ ULONG IV32; ++ ULONG K0; // for MICKEY Low ++ ULONG K1; // for MICKEY Hig ++ ULONG L; // Current state for MICKEY ++ ULONG R; // Current state for MICKEY ++ ULONG M; // Message accumulator for MICKEY ++ UCHAR RC4KEY[16]; ++ UCHAR MIC[8]; ++} TKIP_KEY_INFO, *PTKIP_KEY_INFO; ++ ++// ++// Private / Misc data, counters for driver internal use ++// ++typedef struct __PRIVATE_STRUC { ++ UINT SystemResetCnt; // System reset counter ++ UINT TxRingFullCnt; // Tx ring full occurrance number ++ UINT PhyRxErrCnt; // PHY Rx error count, for debug purpose, might move to global counter ++ // Variables for WEP encryption / decryption in rtmp_wep.c ++ UINT FCSCRC32; ++ ARCFOURCONTEXT WEPCONTEXT; ++ // Tkip stuff ++ TKIP_KEY_INFO Tx; ++ TKIP_KEY_INFO Rx; ++} PRIVATE_STRUC, *PPRIVATE_STRUC; ++ ++// structure to tune BBP R66 (BBP TUNING) ++typedef struct _BBP_R66_TUNING { ++ BOOLEAN bEnable; ++ USHORT FalseCcaLowerThreshold; // default 100 ++ USHORT FalseCcaUpperThreshold; // default 512 ++ UCHAR R66Delta; ++ UCHAR R66CurrentValue; ++ BOOLEAN R66LowerUpperSelect; //Before LinkUp, Used LowerBound or UpperBound as R66 value. ++} BBP_R66_TUNING, *PBBP_R66_TUNING; ++ ++// structure to store channel TX power ++typedef struct _CHANNEL_TX_POWER { ++ USHORT RemainingTimeForUse; //unit: sec ++ UCHAR Channel; ++#ifdef DOT11N_DRAFT3 ++ BOOLEAN bEffectedChannel; // For BW 40 operating in 2.4GHz , the "effected channel" is the channel that is covered in 40Mhz. ++#endif // DOT11N_DRAFT3 // ++ CHAR Power; ++ CHAR Power2; ++ UCHAR MaxTxPwr; ++ UCHAR DfsReq; ++} CHANNEL_TX_POWER, *PCHANNEL_TX_POWER; ++ ++// structure to store 802.11j channel TX power ++typedef struct _CHANNEL_11J_TX_POWER { ++ UCHAR Channel; ++ UCHAR BW; // BW_10 or BW_20 ++ CHAR Power; ++ CHAR Power2; ++ USHORT RemainingTimeForUse; //unit: sec ++} CHANNEL_11J_TX_POWER, *PCHANNEL_11J_TX_POWER; ++ ++typedef enum _ABGBAND_STATE_ { ++ UNKNOWN_BAND, ++ BG_BAND, ++ A_BAND, ++} ABGBAND_STATE; ++ ++typedef struct _MLME_STRUCT { ++#ifdef CONFIG_STA_SUPPORT ++ // STA state machines ++ STATE_MACHINE CntlMachine; ++ STATE_MACHINE AssocMachine; ++ STATE_MACHINE AuthMachine; ++ STATE_MACHINE AuthRspMachine; ++ STATE_MACHINE SyncMachine; ++ STATE_MACHINE WpaPskMachine; ++ STATE_MACHINE LeapMachine; ++ STATE_MACHINE AironetMachine; ++ STATE_MACHINE_FUNC AssocFunc[ASSOC_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AuthFunc[AUTH_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AuthRspFunc[AUTH_RSP_FUNC_SIZE]; ++ STATE_MACHINE_FUNC SyncFunc[SYNC_FUNC_SIZE]; ++ STATE_MACHINE_FUNC WpaPskFunc[WPA_PSK_FUNC_SIZE]; ++ STATE_MACHINE_FUNC AironetFunc[AIRONET_FUNC_SIZE]; ++#endif // CONFIG_STA_SUPPORT // ++ STATE_MACHINE_FUNC ActFunc[ACT_FUNC_SIZE]; ++ // Action ++ STATE_MACHINE ActMachine; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ STATE_MACHINE DlsMachine; ++ STATE_MACHINE_FUNC DlsFunc[DLS_FUNC_SIZE]; ++#endif // QOS_DLS_SUPPORT // ++ ++ ++ ++ ++ ULONG ChannelQuality; // 0..100, Channel Quality Indication for Roaming ++ ULONG Now32; // latch the value of NdisGetSystemUpTime() ++ ULONG LastSendNULLpsmTime; ++ ++ BOOLEAN bRunning; ++ NDIS_SPIN_LOCK TaskLock; ++ MLME_QUEUE Queue; ++ ++ UINT ShiftReg; ++ ++ RALINK_TIMER_STRUCT PeriodicTimer; ++ RALINK_TIMER_STRUCT APSDPeriodicTimer; ++ RALINK_TIMER_STRUCT LinkDownTimer; ++ RALINK_TIMER_STRUCT LinkUpTimer; ++ ULONG PeriodicRound; ++ ULONG OneSecPeriodicRound; ++ ++ UCHAR RealRxPath; ++ BOOLEAN bLowThroughput; ++ BOOLEAN bEnableAutoAntennaCheck; ++ RALINK_TIMER_STRUCT RxAntEvalTimer; ++ ++#ifdef RT30xx ++ UCHAR CaliBW40RfR24; ++ UCHAR CaliBW20RfR24; ++#endif // RT30xx // ++ ++} MLME_STRUCT, *PMLME_STRUCT; ++ ++// structure for radar detection and channel switch ++typedef struct _RADAR_DETECT_STRUCT { ++ //BOOLEAN IEEE80211H; // 0: disable, 1: enable IEEE802.11h ++ UCHAR CSCount; //Channel switch counter ++ UCHAR CSPeriod; //Channel switch period (beacon count) ++ UCHAR RDCount; //Radar detection counter ++ UCHAR RDMode; //Radar Detection mode ++ UCHAR RDDurRegion; //Radar detection duration region ++ UCHAR BBPR16; ++ UCHAR BBPR17; ++ UCHAR BBPR18; ++ UCHAR BBPR21; ++ UCHAR BBPR22; ++ UCHAR BBPR64; ++ ULONG InServiceMonitorCount; // unit: sec ++ UINT8 DfsSessionTime; ++ BOOLEAN bFastDfs; ++ UINT8 ChMovingTime; ++ UINT8 LongPulseRadarTh; ++} RADAR_DETECT_STRUCT, *PRADAR_DETECT_STRUCT; ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++typedef enum CD_STATE_n ++{ ++ CD_NORMAL, ++ CD_SILENCE, ++ CD_MAX_STATE ++} CD_STATE; ++ ++typedef struct CARRIER_DETECTION_s ++{ ++ BOOLEAN Enable; ++ UINT8 CDSessionTime; ++ UINT8 CDPeriod; ++ CD_STATE CD_State; ++} CARRIER_DETECTION, *PCARRIER_DETECTION; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++typedef enum _REC_BLOCKACK_STATUS ++{ ++ Recipient_NONE=0, ++ Recipient_USED, ++ Recipient_HandleRes, ++ Recipient_Accept ++} REC_BLOCKACK_STATUS, *PREC_BLOCKACK_STATUS; ++ ++typedef enum _ORI_BLOCKACK_STATUS ++{ ++ Originator_NONE=0, ++ Originator_USED, ++ Originator_WaitRes, ++ Originator_Done ++} ORI_BLOCKACK_STATUS, *PORI_BLOCKACK_STATUS; ++ ++#ifdef DOT11_N_SUPPORT ++typedef struct _BA_ORI_ENTRY{ ++ UCHAR Wcid; ++ UCHAR TID; ++ UCHAR BAWinSize; ++ UCHAR Token; ++// Sequence is to fill every outgoing QoS DATA frame's sequence field in 802.11 header. ++ USHORT Sequence; ++ USHORT TimeOutValue; ++ ORI_BLOCKACK_STATUS ORI_BA_Status; ++ RALINK_TIMER_STRUCT ORIBATimer; ++ PVOID pAdapter; ++} BA_ORI_ENTRY, *PBA_ORI_ENTRY; ++ ++typedef struct _BA_REC_ENTRY { ++ UCHAR Wcid; ++ UCHAR TID; ++ UCHAR BAWinSize; // 7.3.1.14. each buffer is capable of holding a max AMSDU or MSDU. ++ //UCHAR NumOfRxPkt; ++ //UCHAR Curindidx; // the head in the RX reordering buffer ++ USHORT LastIndSeq; ++// USHORT LastIndSeqAtTimer; ++ USHORT TimeOutValue; ++ RALINK_TIMER_STRUCT RECBATimer; ++ ULONG LastIndSeqAtTimer; ++ ULONG nDropPacket; ++ ULONG rcvSeq; ++ REC_BLOCKACK_STATUS REC_BA_Status; ++// UCHAR RxBufIdxUsed; ++ // corresponding virtual address for RX reordering packet storage. ++ //RTMP_REORDERDMABUF MAP_RXBuf[MAX_RX_REORDERBUF]; ++ NDIS_SPIN_LOCK RxReRingLock; // Rx Ring spinlock ++// struct _BA_REC_ENTRY *pNext; ++ PVOID pAdapter; ++ struct reordering_list list; ++} BA_REC_ENTRY, *PBA_REC_ENTRY; ++ ++ ++typedef struct { ++ ULONG numAsRecipient; // I am recipient of numAsRecipient clients. These client are in the BARecEntry[] ++ ULONG numAsOriginator; // I am originator of numAsOriginator clients. These clients are in the BAOriEntry[] ++ BA_ORI_ENTRY BAOriEntry[MAX_LEN_OF_BA_ORI_TABLE]; ++ BA_REC_ENTRY BARecEntry[MAX_LEN_OF_BA_REC_TABLE]; ++} BA_TABLE, *PBA_TABLE; ++ ++//For QureyBATableOID use; ++typedef struct PACKED _OID_BA_REC_ENTRY{ ++ UCHAR MACAddr[MAC_ADDR_LEN]; ++ UCHAR BaBitmap; // if (BaBitmap&(1<> 3) + 1) /* /8 + 1 */ ++#define WLAN_CT_TIM_BCMC_OFFSET 0 /* unit: 32B */ ++ ++/* clear bcmc TIM bit */ ++#define WLAN_MR_TIM_BCMC_CLEAR(apidx) \ ++ pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] &= ~BIT8[0]; ++ ++/* set bcmc TIM bit */ ++#define WLAN_MR_TIM_BCMC_SET(apidx) \ ++ pAd->ApCfg.MBSSID[apidx].TimBitmaps[WLAN_CT_TIM_BCMC_OFFSET] |= BIT8[0]; ++ ++/* clear a station PS TIM bit */ ++#define WLAN_MR_TIM_BIT_CLEAR(ad_p, apidx, wcid) \ ++ { UCHAR tim_offset = wcid >> 3; \ ++ UCHAR bit_offset = wcid & 0x7; \ ++ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] &= (~BIT8[bit_offset]); } ++ ++/* set a station PS TIM bit */ ++#define WLAN_MR_TIM_BIT_SET(ad_p, apidx, wcid) \ ++ { UCHAR tim_offset = wcid >> 3; \ ++ UCHAR bit_offset = wcid & 0x7; \ ++ ad_p->ApCfg.MBSSID[apidx].TimBitmaps[tim_offset] |= BIT8[bit_offset]; } ++ ++#ifdef RT2870 ++#define BEACON_BITMAP_MASK 0xff ++typedef struct _BEACON_SYNC_STRUCT_ ++{ ++ UCHAR BeaconBuf[HW_BEACON_MAX_COUNT][HW_BEACON_OFFSET]; ++ UCHAR BeaconTxWI[HW_BEACON_MAX_COUNT][TXWI_SIZE]; ++ ULONG TimIELocationInBeacon[HW_BEACON_MAX_COUNT]; ++ ULONG CapabilityInfoLocationInBeacon[HW_BEACON_MAX_COUNT]; ++ BOOLEAN EnableBeacon; // trigger to enable beacon transmission. ++ UCHAR BeaconBitMap; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. ++ UCHAR DtimBitOn; // NOTE: If the MAX_MBSSID_NUM is larger than 8, this parameter need to change. ++}BEACON_SYNC_STRUCT; ++#endif // RT2870 // ++ ++typedef struct _MULTISSID_STRUCT { ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ USHORT CapabilityInfo; ++ ++ PNET_DEV MSSIDDev; ++ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++ WPA_MIX_PAIR_CIPHER WpaMixPairCipher; ++ ++ ULONG TxCount; ++ ULONG RxCount; ++ ULONG ReceivedByteCount; ++ ULONG TransmittedByteCount; ++ ULONG RxErrorCount; ++ ULONG RxDropCount; ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. this is for reading registry setting only. not useful. ++ BOOLEAN bAutoTxRateSwitch; ++ ++ //CIPHER_KEY SharedKey[SHARE_KEY_NUM]; // ref pAd->SharedKey[BSS][4] ++ UCHAR DefaultKeyId; ++ ++ UCHAR TxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11, ... ++ UCHAR DesiredRates[MAX_LEN_OF_SUPPORTED_RATES];// OID_802_11_DESIRED_RATES ++ UCHAR DesiredRatesIndex; ++ UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ ++// ULONG TimBitmap; // bit0 for broadcast, 1 for AID1, 2 for AID2, ...so on ++// ULONG TimBitmap2; // b0 for AID32, b1 for AID33, ... and so on ++ UCHAR TimBitmaps[WLAN_MAX_NUM_OF_TIM]; ++ ++ // WPA ++ UCHAR GMK[32]; ++ UCHAR PMK[32]; ++ UCHAR GTK[32]; ++ BOOLEAN IEEE8021X; ++ BOOLEAN PreAuth; ++ UCHAR GNonce[32]; ++ UCHAR PortSecured; ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; ++ UCHAR BANClass3Data; ++ ULONG IsolateInterStaTraffic; ++ ++ UCHAR RSNIE_Len[2]; ++ UCHAR RSN_IE[2][MAX_LEN_OF_RSNIE]; ++ ++ ++ UCHAR TimIELocationInBeacon; ++ UCHAR CapabilityInfoLocationInBeacon; ++ // outgoing BEACON frame buffer and corresponding TXWI ++ // PTXWI_STRUC BeaconTxWI; // ++ CHAR BeaconBuf[MAX_BEACON_SIZE]; // NOTE: BeaconBuf should be 4-byte aligned ++ ++ BOOLEAN bHideSsid; ++ UINT16 StationKeepAliveTime; // unit: second ++ ++ USHORT VLAN_VID; ++ USHORT VLAN_Priority; ++ ++ RT_802_11_ACL AccessControlList; ++ ++ // EDCA Qos ++ BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM ++ BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS ++ ++ UCHAR DlsPTK[64]; // Due to windows dirver count on meetinghouse to handle 4-way shake ++ ++ // For 802.1x daemon setting per BSS ++ UCHAR radius_srv_num; ++ RADIUS_SRV_INFO radius_srv_info[MAX_RADIUS_SRV_NUM]; ++ ++#ifdef RTL865X_SOC ++ unsigned int mylinkid; ++#endif ++ ++ ++ UINT32 RcvdConflictSsidCount; ++ UINT32 RcvdSpoofedAssocRespCount; ++ UINT32 RcvdSpoofedReassocRespCount; ++ UINT32 RcvdSpoofedProbeRespCount; ++ UINT32 RcvdSpoofedBeaconCount; ++ UINT32 RcvdSpoofedDisassocCount; ++ UINT32 RcvdSpoofedAuthCount; ++ UINT32 RcvdSpoofedDeauthCount; ++ UINT32 RcvdSpoofedUnknownMgmtCount; ++ UINT32 RcvdReplayAttackCount; ++ ++ CHAR RssiOfRcvdConflictSsid; ++ CHAR RssiOfRcvdSpoofedAssocResp; ++ CHAR RssiOfRcvdSpoofedReassocResp; ++ CHAR RssiOfRcvdSpoofedProbeResp; ++ CHAR RssiOfRcvdSpoofedBeacon; ++ CHAR RssiOfRcvdSpoofedDisassoc; ++ CHAR RssiOfRcvdSpoofedAuth; ++ CHAR RssiOfRcvdSpoofedDeauth; ++ CHAR RssiOfRcvdSpoofedUnknownMgmt; ++ CHAR RssiOfRcvdReplayAttack; ++ ++ BOOLEAN bBcnSntReq; ++ UCHAR BcnBufIdx; ++} MULTISSID_STRUCT, *PMULTISSID_STRUCT; ++ ++ ++ ++#ifdef DOT11N_DRAFT3 ++typedef enum _BSS2040COEXIST_FLAG{ ++ BSS_2040_COEXIST_DISABLE = 0, ++ BSS_2040_COEXIST_TIMER_FIRED = 1, ++ BSS_2040_COEXIST_INFO_SYNC = 2, ++ BSS_2040_COEXIST_INFO_NOTIFY = 4, ++}BSS2040COEXIST_FLAG; ++#endif // DOT11N_DRAFT3 // ++ ++// configuration common to OPMODE_AP as well as OPMODE_STA ++typedef struct _COMMON_CONFIG { ++ ++ BOOLEAN bCountryFlag; ++ UCHAR CountryCode[3]; ++ UCHAR Geography; ++ UCHAR CountryRegion; // Enum of country region, 0:FCC, 1:IC, 2:ETSI, 3:SPAIN, 4:France, 5:MKK, 6:MKK1, 7:Israel ++ UCHAR CountryRegionForABand; // Enum of country region for A band ++ UCHAR PhyMode; // PHY_11A, PHY_11B, PHY_11BG_MIXED, PHY_ABG_MIXED ++ USHORT Dsifs; // in units of usec ++ ULONG PacketFilter; // Packet filter for receiving ++ ++ CHAR Ssid[MAX_LEN_OF_SSID]; // NOT NULL-terminated ++ UCHAR SsidLen; // the actual ssid length in used ++ UCHAR LastSsidLen; // the actual ssid length in used ++ CHAR LastSsid[MAX_LEN_OF_SSID]; // NOT NULL-terminated ++ UCHAR LastBssid[MAC_ADDR_LEN]; ++ ++ UCHAR Bssid[MAC_ADDR_LEN]; ++ USHORT BeaconPeriod; ++ UCHAR Channel; ++ UCHAR CentralChannel; // Central Channel when using 40MHz is indicating. not real channel. ++ ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen; ++ UCHAR DesireRate[MAX_LEN_OF_SUPPORTED_RATES]; // OID_802_11_DESIRED_RATES ++ UCHAR MaxDesiredRate; ++ UCHAR ExpectedACKRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ ++ ULONG BasicRateBitmap; // backup basic ratebitmap ++ ++ BOOLEAN bAPSDCapable; ++ BOOLEAN bInServicePeriod; ++ BOOLEAN bAPSDAC_BE; ++ BOOLEAN bAPSDAC_BK; ++ BOOLEAN bAPSDAC_VI; ++ BOOLEAN bAPSDAC_VO; ++ BOOLEAN bNeedSendTriggerFrame; ++ BOOLEAN bAPSDForcePowerSave; // Force power save mode, should only use in APSD-STAUT ++ ULONG TriggerTimerCount; ++ UCHAR MaxSPLength; ++ UCHAR BBPCurrentBW; // BW_10, BW_20, BW_40 ++ // move to MULTISSID_STRUCT for MBSS ++ //HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ REG_TRANSMIT_SETTING RegTransmitSetting; //registry transmit setting. this is for reading registry setting only. not useful. ++ //UCHAR FixedTxMode; // Fixed Tx Mode (CCK, OFDM), for HT fixed tx mode (GF, MIX) , refer to RegTransmitSetting.field.HTMode ++ UCHAR TxRate; // Same value to fill in TXD. TxRate is 6-bit ++ UCHAR MaxTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ UCHAR TxRateIndex; // Tx rate index in RateSwitchTable ++ UCHAR TxRateTableSize; // Valid Tx rate table size in RateSwitchTable ++ //BOOLEAN bAutoTxRateSwitch; ++ UCHAR MinTxRate; // RATE_1, RATE_2, RATE_5_5, RATE_11 ++ UCHAR RtsRate; // RATE_xxx ++ HTTRANSMIT_SETTING MlmeTransmit; // MGMT frame PHY rate setting when operatin at Ht rate. ++ UCHAR MlmeRate; // RATE_xxx, used to send MLME frames ++ UCHAR BasicMlmeRate; // Default Rate for sending MLME frames ++ ++ USHORT RtsThreshold; // in unit of BYTE ++ USHORT FragmentThreshold; // in unit of BYTE ++ ++ UCHAR TxPower; // in unit of mW ++ ULONG TxPowerPercentage; // 0~100 % ++ ULONG TxPowerDefault; // keep for TxPowerPercentage ++ ++#ifdef DOT11_N_SUPPORT ++ BACAP_STRUC BACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 ++ BACAP_STRUC REGBACapability; // NO USE = 0XFF ; IMMED_BA =1 ; DELAY_BA=0 ++#endif // DOT11_N_SUPPORT // ++ IOT_STRUC IOTestParm; // 802.11n InterOpbility Test Parameter; ++ ULONG TxPreamble; // Rt802_11PreambleLong, Rt802_11PreambleShort, Rt802_11PreambleAuto ++ BOOLEAN bUseZeroToDisableFragment; // Microsoft use 0 as disable ++ ULONG UseBGProtection; // 0: auto, 1: always use, 2: always not use ++ BOOLEAN bUseShortSlotTime; // 0: disable, 1 - use short slot (9us) ++ BOOLEAN bEnableTxBurst; // 1: enble TX PACKET BURST, 0: disable TX PACKET BURST ++ BOOLEAN bAggregationCapable; // 1: enable TX aggregation when the peer supports it ++ BOOLEAN bPiggyBackCapable; // 1: enable TX piggy-back according MAC's version ++ BOOLEAN bIEEE80211H; // 1: enable IEEE802.11h spec. ++ ULONG DisableOLBCDetect; // 0: enable OLBC detect; 1 disable OLBC detect ++ ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bRdg; ++#endif // DOT11_N_SUPPORT // ++ BOOLEAN bWmmCapable; // 0:disable WMM, 1:enable WMM ++ QOS_CAPABILITY_PARM APQosCapability; // QOS capability of the current associated AP ++ EDCA_PARM APEdcaParm; // EDCA parameters of the current associated AP ++ QBSS_LOAD_PARM APQbssLoad; // QBSS load of the current associated AP ++ UCHAR AckPolicy[4]; // ACK policy of the specified AC. see ACK_xxx ++#ifdef CONFIG_STA_SUPPORT ++ BOOLEAN bDLSCapable; // 0:disable DLS, 1:enable DLS ++#endif // CONFIG_STA_SUPPORT // ++ // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular ++ // BOOLEAN control, either ON or OFF. These flags should always be accessed via ++ // OPSTATUS_TEST_FLAG(), OPSTATUS_SET_FLAG(), OP_STATUS_CLEAR_FLAG() macros. ++ // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition ++ ULONG OpStatusFlags; ++ ++ BOOLEAN NdisRadioStateOff; //For HCT 12.0, set this flag to TRUE instead of called MlmeRadioOff. ++ ABGBAND_STATE BandState; // For setting BBP used on B/G or A mode. ++ BOOLEAN bRxAntDiversity; // 0:disable, 1:enable Software Rx Antenna Diversity. ++ ++ // IEEE802.11H--DFS. ++ RADAR_DETECT_STRUCT RadarDetect; ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++ CARRIER_DETECTION CarrierDetect; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ UCHAR BASize; // USer desired BAWindowSize. Should not exceed our max capability ++ //RT_HT_CAPABILITY SupportedHtPhy; ++ RT_HT_CAPABILITY DesiredHtPhy; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHTInfo; // Useful as AP. ++ //This IE is used with channel switch announcement element when changing to a new 40MHz. ++ //This IE is included in channel switch ammouncement frames 7.4.1.5, beacons, probe Rsp. ++ NEW_EXT_CHAN_IE NewExtChanOffset; //7.3.2.20A, 1 if extension channel is above the control channel, 3 if below, 0 if not present ++ ++#ifdef DOT11N_DRAFT3 ++ UCHAR Bss2040CoexistFlag; // bit 0: bBssCoexistTimerRunning, bit 1: NeedSyncAddHtInfo. ++ RALINK_TIMER_STRUCT Bss2040CoexistTimer; ++ ++ //This IE is used for 20/40 BSS Coexistence. ++ BSS_2040_COEXIST_IE BSS2040CoexistInfo; ++ // ====== 11n D3.0 =======================> ++ USHORT Dot11OBssScanPassiveDwell; // Unit : TU. 5~1000 ++ USHORT Dot11OBssScanActiveDwell; // Unit : TU. 10~1000 ++ USHORT Dot11BssWidthTriggerScanInt; // Unit : Second ++ USHORT Dot11OBssScanPassiveTotalPerChannel; // Unit : TU. 200~10000 ++ USHORT Dot11OBssScanActiveTotalPerChannel; // Unit : TU. 20~10000 ++ USHORT Dot11BssWidthChanTranDelayFactor; ++ USHORT Dot11OBssScanActivityThre; // Unit : percentage ++ ++ ULONG Dot11BssWidthChanTranDelay; // multiple of (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) ++ ULONG CountDownCtr; // CountDown Counter from (Dot11BssWidthTriggerScanInt * Dot11BssWidthChanTranDelayFactor) ++ ++ NDIS_SPIN_LOCK TriggerEventTabLock; ++ BSS_2040_COEXIST_IE LastBSSCoexist2040; ++ BSS_2040_COEXIST_IE BSSCoexist2040; ++ TRIGGER_EVENT_TAB TriggerEventTab; ++ UCHAR ChannelListIdx; ++ // <====== 11n D3.0 ======================= ++ BOOLEAN bOverlapScanning; ++#endif // DOT11N_DRAFT3 // ++ ++ BOOLEAN bHTProtect; ++ BOOLEAN bMIMOPSEnable; ++ BOOLEAN bBADecline; ++ BOOLEAN bDisableReordering; ++ BOOLEAN bForty_Mhz_Intolerant; ++ BOOLEAN bExtChannelSwitchAnnouncement; ++ BOOLEAN bRcvBSSWidthTriggerEvents; ++ ULONG LastRcvBSSWidthTriggerEventsTime; ++ ++ UCHAR TxBASize; ++#endif // DOT11_N_SUPPORT // ++ ++ // Enable wireless event ++ BOOLEAN bWirelessEvent; ++ BOOLEAN bWiFiTest; // Enable this parameter for WiFi test ++ ++ // Tx & Rx Stream number selection ++ UCHAR TxStream; ++ UCHAR RxStream; ++ ++ // transmit phy mode, trasmit rate for Multicast. ++#ifdef MCAST_RATE_SPECIFIC ++ UCHAR McastTransmitMcs; ++ UCHAR McastTransmitPhyMode; ++#endif // MCAST_RATE_SPECIFIC // ++ ++ BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled ++ ++#ifdef RT2870 ++ BOOLEAN bMultipleIRP; // Multiple Bulk IN flag ++ UCHAR NumOfBulkInIRP; // if bMultipleIRP == TRUE, NumOfBulkInIRP will be 4 otherwise be 1 ++ RT_HT_CAPABILITY SupportedHtPhy; ++ ULONG MaxPktOneTxBulk; ++ UCHAR TxBulkFactor; ++ UCHAR RxBulkFactor; ++ ++ BEACON_SYNC_STRUCT *pBeaconSync; ++ RALINK_TIMER_STRUCT BeaconUpdateTimer; ++ UINT32 BeaconAdjust; ++ UINT32 BeaconFactor; ++ UINT32 BeaconRemain; ++#endif // RT2870 // ++ ++ ++ NDIS_SPIN_LOCK MeasureReqTabLock; ++ PMEASURE_REQ_TAB pMeasureReqTab; ++ ++ NDIS_SPIN_LOCK TpcReqTabLock; ++ PTPC_REQ_TAB pTpcReqTab; ++ ++ // transmit phy mode, trasmit rate for Multicast. ++#ifdef MCAST_RATE_SPECIFIC ++ HTTRANSMIT_SETTING MCastPhyMode; ++#endif // MCAST_RATE_SPECIFIC // ++ ++#ifdef SINGLE_SKU ++ UINT16 DefineMaxTxPwr; ++#endif // SINGLE_SKU // ++ ++ ++} COMMON_CONFIG, *PCOMMON_CONFIG; ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++// STA configuration and status ++typedef struct _STA_ADMIN_CONFIG { ++ // GROUP 1 - ++ // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe ++ // the user intended configuration, but not necessary fully equal to the final ++ // settings in ACTIVE BSS after negotiation/compromize with the BSS holder (either ++ // AP or IBSS holder). ++ // Once initialized, user configuration can only be changed via OID_xxx ++ UCHAR BssType; // BSS_INFRA or BSS_ADHOC ++ USHORT AtimWin; // used when starting a new IBSS ++ ++ // GROUP 2 - ++ // User configuration loaded from Registry, E2PROM or OID_xxx. These settings describe ++ // the user intended configuration, and should be always applied to the final ++ // settings in ACTIVE BSS without compromising with the BSS holder. ++ // Once initialized, user configuration can only be changed via OID_xxx ++ UCHAR RssiTrigger; ++ UCHAR RssiTriggerMode; // RSSI_TRIGGERED_UPON_BELOW_THRESHOLD or RSSI_TRIGGERED_UPON_EXCCEED_THRESHOLD ++ USHORT DefaultListenCount; // default listen count; ++ ULONG WindowsPowerMode; // Power mode for AC power ++ ULONG WindowsBatteryPowerMode; // Power mode for battery if exists ++ BOOLEAN bWindowsACCAMEnable; // Enable CAM power mode when AC on ++ BOOLEAN bAutoReconnect; // Set to TRUE when setting OID_802_11_SSID with no matching BSSID ++ ULONG WindowsPowerProfile; // Windows power profile, for NDIS5.1 PnP ++ ++ // MIB:ieee802dot11.dot11smt(1).dot11StationConfigTable(1) ++ USHORT Psm; // power management mode (PWR_ACTIVE|PWR_SAVE) ++ USHORT DisassocReason; ++ UCHAR DisassocSta[MAC_ADDR_LEN]; ++ USHORT DeauthReason; ++ UCHAR DeauthSta[MAC_ADDR_LEN]; ++ USHORT AuthFailReason; ++ UCHAR AuthFailSta[MAC_ADDR_LEN]; ++ ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_WEP_STATUS OrigWepStatus; // Original wep status set from OID ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ NDIS_802_11_WEP_STATUS GroupKeyWepStatus; ++ ++ UCHAR PMK[32]; // WPA PSK mode PMK ++ UCHAR PTK[64]; // WPA PSK mode PTK ++ UCHAR GTK[32]; // GTK from authenticator ++ BSSID_INFO SavedPMK[PMKID_NO]; ++ UINT SavedPMKNum; // Saved PMKID number ++ ++ UCHAR DefaultKeyId; ++ ++ ++ // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED ++ UCHAR PortSecured; ++ ++ // For WPA countermeasures ++ ULONG LastMicErrorTime; // record last MIC error time ++ ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). ++ BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. ++ // For WPA-PSK supplicant state ++ WPA_STATE WpaState; // Default is SS_NOTUSE and handled by microsoft 802.1x ++ UCHAR ReplayCounter[8]; ++ UCHAR ANonce[32]; // ANonce for WPA-PSK from aurhenticator ++ UCHAR SNonce[32]; // SNonce for WPA-PSK ++ ++ UCHAR LastSNR0; // last received BEACON's SNR ++ UCHAR LastSNR1; // last received BEACON's SNR for 2nd antenna ++ RSSI_SAMPLE RssiSample; ++ ULONG NumOfAvgRssiSample; ++ ++ ULONG LastBeaconRxTime; // OS's timestamp of the last BEACON RX time ++ ULONG Last11bBeaconRxTime; // OS's timestamp of the last 11B BEACON RX time ++ ULONG Last11gBeaconRxTime; // OS's timestamp of the last 11G BEACON RX time ++ ULONG Last20NBeaconRxTime; // OS's timestamp of the last 20MHz N BEACON RX time ++ ++ ULONG LastScanTime; // Record last scan time for issue BSSID_SCAN_LIST ++ ULONG ScanCnt; // Scan counts since most recent SSID, BSSID, SCAN OID request ++ BOOLEAN bSwRadio; // Software controlled Radio On/Off, TRUE: On ++ BOOLEAN bHwRadio; // Hardware controlled Radio On/Off, TRUE: On ++ BOOLEAN bRadio; // Radio state, And of Sw & Hw radio state ++ BOOLEAN bHardwareRadio; // Hardware controlled Radio enabled ++ BOOLEAN bShowHiddenSSID; // Show all known SSID in SSID list get operation ++ ++ //BOOLEAN AdhocBOnlyJoined; // Indicate Adhoc B Join. ++ //BOOLEAN AdhocBGJoined; // Indicate Adhoc B/G Join. ++ //BOOLEAN Adhoc20NJoined; // Indicate Adhoc 20MHz N Join. ++ ++ // New for WPA, windows want us to to keep association information and ++ // Fixed IEs from last association response ++ NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo; ++ USHORT ReqVarIELen; // Length of next VIE include EID & Length ++ UCHAR ReqVarIEs[MAX_VIE_LEN]; // The content saved here should be little-endian format. ++ USHORT ResVarIELen; // Length of next VIE include EID & Length ++ UCHAR ResVarIEs[MAX_VIE_LEN]; ++ ++ UCHAR RSNIE_Len; ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be little-endian format. ++ ++ // New variables used for CCX 1.0 ++ BOOLEAN bCkipOn; ++ BOOLEAN bCkipCmicOn; ++ UCHAR CkipFlag; ++ UCHAR GIV[3]; //for CCX iv ++ UCHAR RxSEQ[4]; ++ UCHAR TxSEQ[4]; ++ UCHAR CKIPMIC[4]; ++ UCHAR LeapAuthMode; ++ LEAP_AUTH_INFO LeapAuthInfo; ++ UCHAR HashPwd[16]; ++ UCHAR NetworkChallenge[8]; ++ UCHAR NetworkChallengeResponse[24]; ++ UCHAR PeerChallenge[8]; ++ ++ UCHAR PeerChallengeResponse[24]; ++ UCHAR SessionKey[16]; //Network session keys (NSK) ++ RALINK_TIMER_STRUCT LeapAuthTimer; ++ ROGUEAP_TABLE RogueApTab; //Cisco CCX1 Rogue AP Detection ++ ++ // New control flags for CCX ++ CCX_CONTROL CCXControl; // Master administration state ++ BOOLEAN CCXEnable; // Actual CCX state ++ UCHAR CCXScanChannel; // Selected channel for CCX beacon request ++ USHORT CCXScanTime; // Time out to wait for beacon and probe response ++ UCHAR CCXReqType; // Current processing CCX request type ++ BSS_TABLE CCXBssTab; // BSS Table ++ UCHAR FrameReportBuf[2048]; // Buffer for creating frame report ++ USHORT FrameReportLen; // Current Frame report length ++ ULONG CLBusyBytes; // Save the total bytes received durning channel load scan time ++ USHORT RPIDensity[8]; // Array for RPI density collection ++ // Start address of each BSS table within FrameReportBuf ++ // It's important to update the RxPower of the corresponding Bss ++ USHORT BssReportOffset[MAX_LEN_OF_BSS_TABLE]; ++ USHORT BeaconToken; // Token for beacon report ++ ULONG LastBssIndex; // Most current reported Bss index ++ RM_REQUEST_ACTION MeasurementRequest[16]; // Saved measurement request ++ UCHAR RMReqCnt; // Number of measurement request saved. ++ UCHAR CurrentRMReqIdx; // Number of measurement request saved. ++ BOOLEAN ParallelReq; // Parallel measurement, only one request performed, ++ // It must be the same channel with maximum duration ++ USHORT ParallelDuration; // Maximum duration for parallel measurement ++ UCHAR ParallelChannel; // Only one channel with parallel measurement ++ USHORT IAPPToken; // IAPP dialog token ++ UCHAR CCXQosECWMin; // Cisco QOS ECWMin for AC 0 ++ UCHAR CCXQosECWMax; // Cisco QOS ECWMax for AC 0 ++ // Hack for channel load and noise histogram parameters ++ UCHAR NHFactor; // Parameter for Noise histogram ++ UCHAR CLFactor; // Parameter for channel load ++ ++ UCHAR KRK[16]; //Key Refresh Key. ++ UCHAR BTK[32]; //Base Transient Key ++ BOOLEAN CCKMLinkUpFlag; ++ ULONG CCKMRN; //(Re)Association request number. ++ LARGE_INTEGER CCKMBeaconAtJoinTimeStamp; //TSF timer for Re-assocaite to the new AP ++ UCHAR AironetCellPowerLimit; //in dBm ++ UCHAR AironetIPAddress[4]; //eg. 192.168.1.1 ++ BOOLEAN CCXAdjacentAPReportFlag; //flag for determining report Assoc Lost time ++ CHAR CCXAdjacentAPSsid[MAX_LEN_OF_SSID]; //Adjacent AP's SSID report ++ UCHAR CCXAdjacentAPSsidLen; // the actual ssid length in used ++ UCHAR CCXAdjacentAPBssid[MAC_ADDR_LEN]; //Adjacent AP's BSSID report ++ USHORT CCXAdjacentAPChannel; ++ ULONG CCXAdjacentAPLinkDownTime; //for Spec S32. ++ ++ RALINK_TIMER_STRUCT StaQuickResponeForRateUpTimer; ++ BOOLEAN StaQuickResponeForRateUpTimerRunning; ++ ++ UCHAR DtimCount; // 0.. DtimPeriod-1 ++ UCHAR DtimPeriod; // default = 3 ++ ++#ifdef QOS_DLS_SUPPORT ++ RT_802_11_DLS DLSEntry[MAX_NUM_OF_DLS_ENTRY]; ++ UCHAR DlsReplayCounter[8]; ++#endif // QOS_DLS_SUPPORT // ++ //////////////////////////////////////////////////////////////////////////////////////// ++ // This is only for WHQL test. ++ BOOLEAN WhqlTest; ++ //////////////////////////////////////////////////////////////////////////////////////// ++ ++ RALINK_TIMER_STRUCT WpaDisassocAndBlockAssocTimer; ++ // Fast Roaming ++ BOOLEAN bFastRoaming; // 0:disable fast roaming, 1:enable fast roaming ++ CHAR dBmToRoam; // the condition to roam when receiving Rssi less than this value. It's negative value. ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ BOOLEAN IEEE8021X; ++ BOOLEAN IEEE8021x_required_keys; ++ CIPHER_KEY DesireSharedKey[4]; // Record user desired WEP keys ++ UCHAR DesireSharedKeyId; ++ ++ // 0: driver ignores wpa_supplicant ++ // 1: wpa_supplicant initiates scanning and AP selection ++ // 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters ++ UCHAR WpaSupplicantUP; ++ UCHAR WpaSupplicantScanCount; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ CHAR dev_name[16]; ++ USHORT OriDevType; ++ ++ BOOLEAN bTGnWifiTest; ++ BOOLEAN bScanReqIsFromWebUI; ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ UCHAR IEEE80211dClientMode; ++ UCHAR StaOriCountryCode[3]; ++ UCHAR StaOriGeography; ++#endif // EXT_BUILD_CHANNEL_LIST // ++} STA_ADMIN_CONFIG, *PSTA_ADMIN_CONFIG; ++ ++// This data structure keep the current active BSS/IBSS's configuration that this STA ++// had agreed upon joining the network. Which means these parameters are usually decided ++// by the BSS/IBSS creator instead of user configuration. Data in this data structurre ++// is valid only when either ADHOC_ON(pAd) or INFRA_ON(pAd) is TRUE. ++// Normally, after SCAN or failed roaming attempts, we need to recover back to ++// the current active settings. ++typedef struct _STA_ACTIVE_CONFIG { ++ USHORT Aid; ++ USHORT AtimWin; // in kusec; IBSS parameter set element ++ USHORT CapabilityInfo; ++ USHORT CfpMaxDuration; ++ USHORT CfpPeriod; ++ ++ // Copy supported rate from desired AP's beacon. We are trying to match ++ // AP's supported and extended rate settings. ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen; ++ UCHAR ExtRateLen; ++ // Copy supported ht from desired AP's beacon. We are trying to match ++ RT_HT_PHY_INFO SupportedPhyInfo; ++ RT_HT_CAPABILITY SupportedHtPhy; ++} STA_ACTIVE_CONFIG, *PSTA_ACTIVE_CONFIG; ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef RT2870 ++typedef struct RT_ADD_PAIRWISE_KEY_ENTRY { ++ NDIS_802_11_MAC_ADDRESS MacAddr; ++ USHORT MacTabMatchWCID; // ASIC ++ CIPHER_KEY CipherKey; ++} RT_ADD_PAIRWISE_KEY_ENTRY,*PRT_ADD_PAIRWISE_KEY_ENTRY; ++#endif // RT2870 // ++ ++// ----------- start of AP -------------------------- ++// AUTH-RSP State Machine Aux data structure ++typedef struct _AP_MLME_AUX { ++ UCHAR Addr[MAC_ADDR_LEN]; ++ USHORT Alg; ++ CHAR Challenge[CIPHER_TEXT_LEN]; ++} AP_MLME_AUX, *PAP_MLME_AUX; ++ ++// structure to define WPA Group Key Rekey Interval ++typedef struct PACKED _RT_802_11_WPA_REKEY { ++ ULONG ReKeyMethod; // mechanism for rekeying: 0:disable, 1: time-based, 2: packet-based ++ ULONG ReKeyInterval; // time-based: seconds, packet-based: kilo-packets ++} RT_WPA_REKEY,*PRT_WPA_REKEY, RT_802_11_WPA_REKEY, *PRT_802_11_WPA_REKEY; ++ ++typedef struct _MAC_TABLE_ENTRY { ++ //Choose 1 from ValidAsWDS and ValidAsCLI to validize. ++ BOOLEAN ValidAsCLI; // Sta mode, set this TRUE after Linkup,too. ++ BOOLEAN ValidAsWDS; // This is WDS Entry. only for AP mode. ++ BOOLEAN ValidAsApCli; //This is a AP-Client entry, only for AP mode which enable AP-Client functions. ++ BOOLEAN ValidAsMesh; ++ BOOLEAN ValidAsDls; // This is DLS Entry. only for STA mode. ++ BOOLEAN isCached; ++ BOOLEAN bIAmBadAtheros; ++ ++ UCHAR EnqueueEapolStartTimerRunning; // Enqueue EAPoL-Start for triggering EAP SM ++ //jan for wpa ++ // record which entry revoke MIC Failure , if it leaves the BSS itself, AP won't update aMICFailTime MIB ++ UCHAR CMTimerRunning; ++ UCHAR apidx; // MBSS number ++ UCHAR RSNIE_Len; ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; ++ UCHAR ANonce[LEN_KEY_DESC_NONCE]; ++ UCHAR R_Counter[LEN_KEY_DESC_REPLAY]; ++ UCHAR PTK[64]; ++ UCHAR ReTryCounter; ++ RALINK_TIMER_STRUCT RetryTimer; ++ RALINK_TIMER_STRUCT EnqueueStartForPSKTimer; // A timer which enqueue EAPoL-Start for triggering PSK SM ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ AP_WPA_STATE WpaState; ++ GTK_STATE GTKState; ++ USHORT PortSecured; ++ NDIS_802_11_PRIVACY_FILTER PrivacyFilter; // PrivacyFilter enum for 802.1X ++ CIPHER_KEY PairwiseKey; ++ PVOID pAd; ++ INT PMKID_CacheIdx; ++ UCHAR PMKID[LEN_PMKID]; ++ ++ ++ UCHAR Addr[MAC_ADDR_LEN]; ++ UCHAR PsMode; ++ SST Sst; ++ AUTH_STATE AuthState; // for SHARED KEY authentication state machine used only ++ BOOLEAN IsReassocSta; // Indicate whether this is a reassociation procedure ++ USHORT Aid; ++ USHORT CapabilityInfo; ++ UCHAR LastRssi; ++ ULONG NoDataIdleCount; ++ UINT16 StationKeepAliveCount; // unit: second ++ ULONG PsQIdleCount; ++ QUEUE_HEADER PsQueue; ++ ++ UINT32 StaConnectTime; // the live time of this station since associated with AP ++ ++ ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN bSendBAR; ++ USHORT NoBADataCountDown; ++ ++ UINT32 CachedBuf[16]; // UINT (4 bytes) for alignment ++ UINT TxBFCount; // 3*3 ++#endif // DOT11_N_SUPPORT // ++ UINT FIFOCount; ++ UINT DebugFIFOCount; ++ UINT DebugTxCount; ++ BOOLEAN bDlsInit; ++ ++ ++//==================================================== ++//WDS entry needs these ++// rt2860 add this. if ValidAsWDS==TRUE, MatchWDSTabIdx is the index in WdsTab.MacTab ++ UINT MatchWDSTabIdx; ++ UCHAR MaxSupportedRate; ++ UCHAR CurrTxRate; ++ UCHAR CurrTxRateIndex; ++ // to record the each TX rate's quality. 0 is best, the bigger the worse. ++ USHORT TxQuality[MAX_STEP_OF_TX_RATE_SWITCH]; ++// USHORT OneSecTxOkCount; ++ UINT32 OneSecTxNoRetryOkCount; ++ UINT32 OneSecTxRetryOkCount; ++ UINT32 OneSecTxFailCount; ++ UINT32 ContinueTxFailCnt; ++ UINT32 CurrTxRateStableTime; // # of second in current TX rate ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++//==================================================== ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++ UINT MatchDlsEntryIdx; // indicate the index in pAd->StaCfg.DLSEntry ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++ BOOLEAN fNoisyEnvironment; ++ BOOLEAN fLastSecAccordingRSSI; ++ UCHAR LastSecTxRateChangeAction; // 0: no change, 1:rate UP, 2:rate down ++ CHAR LastTimeTxRateChangeAction; //Keep last time value of LastSecTxRateChangeAction ++ ULONG LastTxOkCount; ++ UCHAR PER[MAX_STEP_OF_TX_RATE_SWITCH]; ++ ++ // a bitmap of BOOLEAN flags. each bit represent an operation status of a particular ++ // BOOLEAN control, either ON or OFF. These flags should always be accessed via ++ // CLIENT_STATUS_TEST_FLAG(), CLIENT_STATUS_SET_FLAG(), CLIENT_STATUS_CLEAR_FLAG() macros. ++ // see fOP_STATUS_xxx in RTMP_DEF.C for detail bit definition. fCLIENT_STATUS_AMSDU_INUSED ++ ULONG ClientStatusFlags; ++ ++ // TODO: Shall we move that to DOT11_N_SUPPORT??? ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode;// For transmit phy setting in TXWI. ++ ++#ifdef DOT11_N_SUPPORT ++ // HT EWC MIMO-N used parameters ++ USHORT RXBAbitmap; // fill to on-chip RXWI_BA_BITMASK in 8.1.3RX attribute entry format ++ USHORT TXBAbitmap; // This bitmap as originator, only keep in software used to mark AMPDU bit in TXWI ++ USHORT TXAutoBAbitmap; ++ USHORT BADeclineBitmap; ++ USHORT BARecWcidArray[NUM_OF_TID]; // The mapping wcid of recipient session. if RXBAbitmap bit is masked ++ USHORT BAOriWcidArray[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked ++ USHORT BAOriSequence[NUM_OF_TID]; // The mapping wcid of originator session. if TXBAbitmap bit is masked ++ ++ // 802.11n features. ++ UCHAR MpduDensity; ++ UCHAR MaxRAmpduFactor; ++ UCHAR AMsduSize; ++ UCHAR MmpsMode; // MIMO power save more. ++ ++ HT_CAPABILITY_IE HTCapability; ++ ++#ifdef DOT11N_DRAFT3 ++ UCHAR BSS2040CoexistenceMgmtSupport; ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ BOOLEAN bAutoTxRateSwitch; ++ ++ UCHAR RateLen; ++ struct _MAC_TABLE_ENTRY *pNext; ++ USHORT TxSeq[NUM_OF_TID]; ++ USHORT NonQosDataSeq; ++ ++ RSSI_SAMPLE RssiSample; ++ ++ UINT32 TXMCSExpected[16]; ++ UINT32 TXMCSSuccessful[16]; ++ UINT32 TXMCSFailed[16]; ++ UINT32 TXMCSAutoFallBack[16][16]; ++ ++#ifdef CONFIG_STA_SUPPORT ++ ULONG LastBeaconRxTime; ++#endif // CONFIG_STA_SUPPORT // ++} MAC_TABLE_ENTRY, *PMAC_TABLE_ENTRY; ++ ++typedef struct _MAC_TABLE { ++ USHORT Size; ++ MAC_TABLE_ENTRY *Hash[HASH_TABLE_SIZE]; ++ MAC_TABLE_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; ++ QUEUE_HEADER McastPsQueue; ++ ULONG PsQIdleCount; ++ BOOLEAN fAnyStationInPsm; ++ BOOLEAN fAnyStationBadAtheros; // Check if any Station is atheros 802.11n Chip. We need to use RTS/CTS with Atheros 802,.11n chip. ++ BOOLEAN fAnyTxOPForceDisable; // Check if it is necessary to disable BE TxOP ++ BOOLEAN fAllStationAsRalink; // Check if all stations are ralink-chipset ++#ifdef DOT11_N_SUPPORT ++ BOOLEAN fAnyStationIsLegacy; // Check if I use legacy rate to transmit to my BSS Station/ ++ BOOLEAN fAnyStationNonGF; // Check if any Station can't support GF. ++ BOOLEAN fAnyStation20Only; // Check if any Station can't support GF. ++ BOOLEAN fAnyStationMIMOPSDynamic; // Check if any Station is MIMO Dynamic ++ BOOLEAN fAnyBASession; // Check if there is BA session. Force turn on RTS/CTS ++#endif // DOT11_N_SUPPORT // ++} MAC_TABLE, *PMAC_TABLE; ++ ++#ifdef DOT11_N_SUPPORT ++#define IS_HT_STA(_pMacEntry) \ ++ (_pMacEntry->MaxHTPhyMode.field.MODE >= MODE_HTMIX) ++ ++#define IS_HT_RATE(_pMacEntry) \ ++ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++ ++#define PEER_IS_HT_RATE(_pMacEntry) \ ++ (_pMacEntry->HTPhyMode.field.MODE >= MODE_HTMIX) ++#endif // DOT11_N_SUPPORT // ++ ++typedef struct _WDS_ENTRY { ++ BOOLEAN Valid; ++ UCHAR Addr[MAC_ADDR_LEN]; ++ ULONG NoDataIdleCount; ++ struct _WDS_ENTRY *pNext; ++} WDS_ENTRY, *PWDS_ENTRY; ++ ++typedef struct _WDS_TABLE_ENTRY { ++ USHORT Size; ++ UCHAR WdsAddr[MAC_ADDR_LEN]; ++ WDS_ENTRY *Hash[HASH_TABLE_SIZE]; ++ WDS_ENTRY Content[MAX_LEN_OF_MAC_TABLE]; ++ UCHAR MaxSupportedRate; ++ UCHAR CurrTxRate; ++ USHORT TxQuality[MAX_LEN_OF_SUPPORTED_RATES]; ++ USHORT OneSecTxOkCount; ++ USHORT OneSecTxRetryOkCount; ++ USHORT OneSecTxFailCount; ++ ULONG CurrTxRateStableTime; // # of second in current TX rate ++ UCHAR TxRateUpPenalty; // extra # of second penalty due to last unstable condition ++} WDS_TABLE_ENTRY, *PWDS_TABLE_ENTRY; ++ ++typedef struct _RT_802_11_WDS_ENTRY { ++ PNET_DEV dev; ++ UCHAR Valid; ++ UCHAR PhyMode; ++ UCHAR PeerWdsAddr[MAC_ADDR_LEN]; ++ UCHAR MacTabMatchWCID; // ASIC ++ NDIS_802_11_WEP_STATUS WepStatus; ++ UCHAR KeyIdx; ++ CIPHER_KEY WdsKey; ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. ++} RT_802_11_WDS_ENTRY, *PRT_802_11_WDS_ENTRY; ++ ++typedef struct _WDS_TABLE { ++ UCHAR Mode; ++ ULONG Size; ++ RT_802_11_WDS_ENTRY WdsEntry[MAX_WDS_ENTRY]; ++} WDS_TABLE, *PWDS_TABLE; ++ ++typedef struct _APCLI_STRUCT { ++ PNET_DEV dev; ++#ifdef RTL865X_SOC ++ unsigned int mylinkid; ++#endif ++ BOOLEAN Enable; // Set it as 1 if the apcli interface was configured to "1" or by iwpriv cmd "ApCliEnable" ++ BOOLEAN Valid; // Set it as 1 if the apcli interface associated success to remote AP. ++ UCHAR MacTabWCID; //WCID value, which point to the entry of ASIC Mac table. ++ UCHAR SsidLen; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ ++ UCHAR CfgSsidLen; ++ CHAR CfgSsid[MAX_LEN_OF_SSID]; ++ UCHAR CfgApCliBssid[ETH_LENGTH_OF_ADDRESS]; ++ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS]; ++ ++ ULONG ApCliRcvBeaconTime; ++ ++ ULONG CtrlCurrState; ++ ULONG SyncCurrState; ++ ULONG AuthCurrState; ++ ULONG AssocCurrState; ++ ULONG WpaPskCurrState; ++ ++ USHORT AuthReqCnt; ++ USHORT AssocReqCnt; ++ ++ ULONG ClientStatusFlags; ++ UCHAR MpduDensity; ++ ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; // This should match to whatever microsoft defined ++ NDIS_802_11_WEP_STATUS WepStatus; ++ ++ // Add to support different cipher suite for WPA2/WPA mode ++ NDIS_802_11_ENCRYPTION_STATUS GroupCipher; // Multicast cipher suite ++ NDIS_802_11_ENCRYPTION_STATUS PairCipher; // Unicast cipher suite ++ BOOLEAN bMixCipher; // Indicate current Pair & Group use different cipher suites ++ USHORT RsnCapability; ++ ++ UCHAR PSK[100]; // reserve PSK key material ++ UCHAR PSKLen; ++ UCHAR PMK[32]; // WPA PSK mode PMK ++ //UCHAR PTK[64]; // WPA PSK mode PTK ++ UCHAR GTK[32]; // GTK from authenticator ++ ++ //CIPHER_KEY PairwiseKey; ++ CIPHER_KEY SharedKey[SHARE_KEY_NUM]; ++ UCHAR DefaultKeyId; ++ ++ // WPA 802.1x port control, WPA_802_1X_PORT_SECURED, WPA_802_1X_PORT_NOT_SECURED ++ //UCHAR PortSecured; ++ ++ // store RSN_IE built by driver ++ UCHAR RSN_IE[MAX_LEN_OF_RSNIE]; // The content saved here should be convert to little-endian format. ++ UCHAR RSNIE_Len; ++ ++ // For WPA countermeasures ++ ULONG LastMicErrorTime; // record last MIC error time ++ //ULONG MicErrCnt; // Should be 0, 1, 2, then reset to zero (after disassoiciation). ++ BOOLEAN bBlockAssoc; // Block associate attempt for 60 seconds after counter measure occurred. ++ ++ // For WPA-PSK supplicant state ++ //WPA_STATE WpaState; // Default is SS_NOTUSE ++ //UCHAR ReplayCounter[8]; ++ //UCHAR ANonce[32]; // ANonce for WPA-PSK from authenticator ++ UCHAR SNonce[32]; // SNonce for WPA-PSK ++ UCHAR GNonce[32]; // GNonce for WPA-PSK from authenticator ++ ++ HTTRANSMIT_SETTING HTPhyMode, MaxHTPhyMode, MinHTPhyMode; ++ RT_HT_PHY_INFO DesiredHtPhyInfo; ++ BOOLEAN bAutoTxRateSwitch; ++ DESIRED_TRANSMIT_SETTING DesiredTransmitSetting; // Desired transmit setting. ++} APCLI_STRUCT, *PAPCLI_STRUCT; ++ ++// ----------- end of AP ---------------------------- ++ ++#ifdef BLOCK_NET_IF ++typedef struct _BLOCK_QUEUE_ENTRY ++{ ++ BOOLEAN SwTxQueueBlockFlag; ++ LIST_HEADER NetIfList; ++} BLOCK_QUEUE_ENTRY, *PBLOCK_QUEUE_ENTRY; ++#endif // BLOCK_NET_IF // ++ ++ ++struct wificonf ++{ ++ BOOLEAN bShortGI; ++ BOOLEAN bGreenField; ++}; ++ ++ ++ ++ ++typedef struct _INF_PCI_CONFIG ++{ ++ PUCHAR CSRBaseAddress; // PCI MMIO Base Address, all access will use ++}INF_PCI_CONFIG; ++ ++typedef struct _INF_USB_CONFIG ++{ ++ UINT BulkInEpAddr; // bulk-in endpoint address ++ UINT BulkOutEpAddr[6]; // bulk-out endpoint address ++ ++}INF_USB_CONFIG; ++ ++#ifdef IKANOS_VX_1X0 ++ typedef void (*IkanosWlanTxCbFuncP)(void *, void *); ++ ++ struct IKANOS_TX_INFO ++ { ++ struct net_device *netdev; ++ IkanosWlanTxCbFuncP *fp; ++ }; ++#endif // IKANOS_VX_1X0 // ++ ++#ifdef NINTENDO_AP ++typedef struct _NINDO_CTRL_BLOCK { ++ ++ RT_NINTENDO_TABLE DS_TABLE; ++ ++#ifdef CHIP25XX ++ spinlock_t NINTENDO_TABLE_Lock; ++#else ++ NDIS_SPIN_LOCK NINTENDO_TABLE_Lock; ++#endif // CHIP25XX // ++ ++ UCHAR NINTENDO_UP_BUFFER[512]; ++ UCHAR Local_KeyIdx; ++ CIPHER_KEY Local_SharedKey; ++ UCHAR Local_bHideSsid; ++ UCHAR Local_AuthMode; ++ UCHAR Local_WepStatus; ++ USHORT Local_CapabilityInfo; ++} NINDO_CTRL_BLOCK; ++#endif // NINTENDO_AP // ++ ++ ++#ifdef DBG_DIAGNOSE ++#define DIAGNOSE_TIME 10 // 10 sec ++typedef struct _RtmpDiagStrcut_ ++{ // Diagnosis Related element ++ unsigned char inited; ++ unsigned char qIdx; ++ unsigned char ArrayStartIdx; ++ unsigned char ArrayCurIdx; ++ // Tx Related Count ++ USHORT TxDataCnt[DIAGNOSE_TIME]; ++ USHORT TxFailCnt[DIAGNOSE_TIME]; ++// USHORT TxDescCnt[DIAGNOSE_TIME][16]; // TxDesc queue length in scale of 0~14, >=15 ++ USHORT TxDescCnt[DIAGNOSE_TIME][24]; // 3*3 // TxDesc queue length in scale of 0~14, >=15 ++// USHORT TxMcsCnt[DIAGNOSE_TIME][16]; // TxDate MCS Count in range from 0 to 15, step in 1. ++ USHORT TxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 ++ USHORT TxSWQueCnt[DIAGNOSE_TIME][9]; // TxSwQueue length in scale of 0, 1, 2, 3, 4, 5, 6, 7, >=8 ++ ++ USHORT TxAggCnt[DIAGNOSE_TIME]; ++ USHORT TxNonAggCnt[DIAGNOSE_TIME]; ++// USHORT TxAMPDUCnt[DIAGNOSE_TIME][16]; // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. ++ USHORT TxAMPDUCnt[DIAGNOSE_TIME][24]; // 3*3 // 10 sec, TxDMA APMDU Aggregation count in range from 0 to 15, in setp of 1. ++ USHORT TxRalinkCnt[DIAGNOSE_TIME]; // TxRalink Aggregation Count in 1 sec scale. ++ USHORT TxAMSDUCnt[DIAGNOSE_TIME]; // TxAMSUD Aggregation Count in 1 sec scale. ++ ++ // Rx Related Count ++ USHORT RxDataCnt[DIAGNOSE_TIME]; // Rx Total Data count. ++ USHORT RxCrcErrCnt[DIAGNOSE_TIME]; ++// USHORT RxMcsCnt[DIAGNOSE_TIME][16]; // Rx MCS Count in range from 0 to 15, step in 1. ++ USHORT RxMcsCnt[DIAGNOSE_TIME][24]; // 3*3 ++}RtmpDiagStruct; ++#endif // DBG_DIAGNOSE // ++ ++ ++// ++// The miniport adapter structure ++// ++typedef struct _RTMP_ADAPTER ++{ ++ PVOID OS_Cookie; // save specific structure relative to OS ++ PNET_DEV net_dev; ++ ULONG VirtualIfCnt; ++ ++ ++ ++ NDIS_SPIN_LOCK irq_lock; ++ UCHAR irq_disabled; ++ ++#ifdef RT2870 ++/*****************************************************************************************/ ++/* USB related parameters */ ++/*****************************************************************************************/ ++ struct usb_config_descriptor *config; ++ UINT BulkInEpAddr; // bulk-in endpoint address ++ UINT BulkOutEpAddr[6]; // bulk-out endpoint address ++ ++ UINT NumberOfPipes; ++ USHORT BulkOutMaxPacketSize; ++ USHORT BulkInMaxPacketSize; ++ ++ //======Control Flags ++ LONG PendingIoCount; ++ ULONG BulkFlags; ++ BOOLEAN bUsbTxBulkAggre; // Flags for bulk out data priority ++ ++ ++ //======Timer Thread ++ RT2870_TIMER_QUEUE TimerQ; ++ NDIS_SPIN_LOCK TimerQLock; ++ ++ ++ //======Cmd Thread ++ CmdQ CmdQ; ++ NDIS_SPIN_LOCK CmdQLock; // CmdQLock spinlock ++ ++ BOOLEAN TimerFunc_kill; ++ BOOLEAN mlme_kill; ++ ++ ++ //======Semaphores (event) ++ struct semaphore mlme_semaphore; /* to sleep thread on */ ++ struct semaphore RTUSBCmd_semaphore; /* to sleep thread on */ ++ struct semaphore RTUSBTimer_semaphore; ++#ifdef INF_AMAZON_SE ++ struct semaphore UsbVendorReq_semaphore; ++ PVOID UsbVendorReqBuf; ++#endif // INF_AMAZON_SE // ++ struct completion TimerQComplete; ++ struct completion mlmeComplete; ++ struct completion CmdQComplete; ++ wait_queue_head_t *wait; ++ ++ //======Lock for 2870 ATE ++#ifdef RALINK_ATE ++ NDIS_SPIN_LOCK GenericLock; // ATE Tx/Rx generic spinlock ++#endif // RALINK_ATE // ++ ++#endif // RT2870 // ++ ++ ++/*****************************************************************************************/ ++ /* Both PCI/USB related parameters */ ++/*****************************************************************************************/ ++ ++ ++/*****************************************************************************************/ ++/* Tx related parameters */ ++/*****************************************************************************************/ ++ BOOLEAN DeQueueRunning[NUM_OF_TX_RING]; // for ensuring RTUSBDeQueuePacket get call once ++ NDIS_SPIN_LOCK DeQueueLock[NUM_OF_TX_RING]; ++ ++#ifdef RT2870 ++ // Data related context and AC specified, 4 AC supported ++ NDIS_SPIN_LOCK BulkOutLock[6]; // BulkOut spinlock for 4 ACs ++ NDIS_SPIN_LOCK MLMEBulkOutLock; // MLME BulkOut lock ++ ++ HT_TX_CONTEXT TxContext[NUM_OF_TX_RING]; ++ NDIS_SPIN_LOCK TxContextQueueLock[NUM_OF_TX_RING]; // TxContextQueue spinlock ++ ++ // 4 sets of Bulk Out index and pending flag ++ UCHAR NextBulkOutIndex[4]; // only used for 4 EDCA bulkout pipe ++ ++ BOOLEAN BulkOutPending[6]; // used for total 6 bulkout pipe ++ UCHAR bulkResetPipeid; ++ BOOLEAN MgmtBulkPending; ++ ULONG bulkResetReq[6]; ++#endif // RT2870 // ++ ++ // resource for software backlog queues ++ QUEUE_HEADER TxSwQueue[NUM_OF_TX_RING]; // 4 AC + 1 HCCA ++ NDIS_SPIN_LOCK TxSwQueueLock[NUM_OF_TX_RING]; // TxSwQueue spinlock ++ ++ RTMP_DMABUF MgmtDescRing; // Shared memory for MGMT descriptors ++ RTMP_MGMT_RING MgmtRing; ++ NDIS_SPIN_LOCK MgmtRingLock; // Prio Ring spinlock ++ ++ ++/*****************************************************************************************/ ++/* Rx related parameters */ ++/*****************************************************************************************/ ++ ++ ++#ifdef RT2870 ++ RX_CONTEXT RxContext[RX_RING_SIZE]; // 1 for redundant multiple IRP bulk in. ++ NDIS_SPIN_LOCK BulkInLock; // BulkIn spinlock for 4 ACs ++ UCHAR PendingRx; // The Maxima pending Rx value should be RX_RING_SIZE. ++ UCHAR NextRxBulkInIndex; // Indicate the current RxContext Index which hold by Host controller. ++ UCHAR NextRxBulkInReadIndex; // Indicate the current RxContext Index which driver can read & process it. ++ ULONG NextRxBulkInPosition; // Want to contatenate 2 URB buffer while 1st is bulkin failed URB. This Position is 1st URB TransferLength. ++ ULONG TransferBufferLength; // current length of the packet buffer ++ ULONG ReadPosition; // current read position in a packet buffer ++#endif // RT2870 // ++ ++ ++/*****************************************************************************************/ ++/* ASIC related parameters */ ++/*****************************************************************************************/ ++ UINT32 MACVersion; // MAC version. Record rt2860C(0x28600100) or rt2860D (0x28600101).. ++ ++ // --------------------------- ++ // E2PROM ++ // --------------------------- ++ ULONG EepromVersion; // byte 0: version, byte 1: revision, byte 2~3: unused ++ UCHAR EEPROMAddressNum; // 93c46=6 93c66=8 ++ USHORT EEPROMDefaultValue[NUM_EEPROM_BBP_PARMS]; ++ BOOLEAN EepromAccess; ++ UCHAR EFuseTag; ++ ULONG FirmwareVersion; // byte 0: Minor version, byte 1: Major version, otherwise unused. ++ ++ // --------------------------- ++ // BBP Control ++ // --------------------------- ++ UCHAR BbpWriteLatch[140]; // record last BBP register value written via BBP_IO_WRITE/BBP_IO_WRITE_VY_REG_ID ++ UCHAR BbpRssiToDbmDelta; ++ BBP_R66_TUNING BbpTuning; ++ ++ // ---------------------------- ++ // RFIC control ++ // ---------------------------- ++ UCHAR RfIcType; // RFIC_xxx ++ ULONG RfFreqOffset; // Frequency offset for channel switching ++ RTMP_RF_REGS LatchRfRegs; // latch th latest RF programming value since RF IC doesn't support READ ++ ++ EEPROM_ANTENNA_STRUC Antenna; // Since ANtenna definition is different for a & g. We need to save it for future reference. ++ EEPROM_NIC_CONFIG2_STRUC NicConfig2; ++ ++ // This soft Rx Antenna Diversity mechanism is used only when user set ++ // RX Antenna = DIVERSITY ON ++ SOFT_RX_ANT_DIVERSITY RxAnt; ++ ++ UCHAR RFProgSeq; ++ CHANNEL_TX_POWER TxPower[MAX_NUM_OF_CHANNELS]; // Store Tx power value for all channels. ++ CHANNEL_TX_POWER ChannelList[MAX_NUM_OF_CHANNELS]; // list all supported channels for site survey ++ CHANNEL_11J_TX_POWER TxPower11J[MAX_NUM_OF_11JCHANNELS]; // 802.11j channel and bw ++ CHANNEL_11J_TX_POWER ChannelList11J[MAX_NUM_OF_11JCHANNELS]; // list all supported channels for site survey ++ ++ UCHAR ChannelListNum; // number of channel in ChannelList[] ++ UCHAR Bbp94; ++ BOOLEAN BbpForCCK; ++ ULONG Tx20MPwrCfgABand[5]; ++ ULONG Tx20MPwrCfgGBand[5]; ++ ULONG Tx40MPwrCfgABand[5]; ++ ULONG Tx40MPwrCfgGBand[5]; ++ ++ BOOLEAN bAutoTxAgcA; // Enable driver auto Tx Agc control ++ UCHAR TssiRefA; // Store Tssi reference value as 25 temperature. ++ UCHAR TssiPlusBoundaryA[5]; // Tssi boundary for increase Tx power to compensate. ++ UCHAR TssiMinusBoundaryA[5]; // Tssi boundary for decrease Tx power to compensate. ++ UCHAR TxAgcStepA; // Store Tx TSSI delta increment / decrement value ++ CHAR TxAgcCompensateA; // Store the compensation (TxAgcStep * (idx-1)) ++ ++ BOOLEAN bAutoTxAgcG; // Enable driver auto Tx Agc control ++ UCHAR TssiRefG; // Store Tssi reference value as 25 temperature. ++ UCHAR TssiPlusBoundaryG[5]; // Tssi boundary for increase Tx power to compensate. ++ UCHAR TssiMinusBoundaryG[5]; // Tssi boundary for decrease Tx power to compensate. ++ UCHAR TxAgcStepG; // Store Tx TSSI delta increment / decrement value ++ CHAR TxAgcCompensateG; // Store the compensation (TxAgcStep * (idx-1)) ++ ++ //+++For RT2870, the parameteres is start from BGRssiOffset1 ~ BGRssiOffset3 ++ CHAR BGRssiOffset0; // Store B/G RSSI#0 Offset value on EEPROM 0x46h ++ CHAR BGRssiOffset1; // Store B/G RSSI#1 Offset value ++ CHAR BGRssiOffset2; // Store B/G RSSI#2 Offset value ++ //--- ++ ++ //+++For RT2870, the parameteres is start from ARssiOffset1 ~ ARssiOffset3 ++ CHAR ARssiOffset0; // Store A RSSI#0 Offset value on EEPROM 0x4Ah ++ CHAR ARssiOffset1; // Store A RSSI#1 Offset value ++ CHAR ARssiOffset2; // Store A RSSI#2 Offset value ++ //--- ++ ++ CHAR BLNAGain; // Store B/G external LNA#0 value on EEPROM 0x44h ++ CHAR ALNAGain0; // Store A external LNA#0 value for ch36~64 ++ CHAR ALNAGain1; // Store A external LNA#1 value for ch100~128 ++ CHAR ALNAGain2; // Store A external LNA#2 value for ch132~165 ++ ++ // ---------------------------- ++ // LED control ++ // ---------------------------- ++ MCU_LEDCS_STRUC LedCntl; ++ USHORT Led1; // read from EEPROM 0x3c ++ USHORT Led2; // EEPROM 0x3e ++ USHORT Led3; // EEPROM 0x40 ++ UCHAR LedIndicatorStregth; ++ UCHAR RssiSingalstrengthOffet; ++ BOOLEAN bLedOnScanning; ++ UCHAR LedStatus; ++ ++/*****************************************************************************************/ ++/* 802.11 related parameters */ ++/*****************************************************************************************/ ++ // outgoing BEACON frame buffer and corresponding TXD ++ TXWI_STRUC BeaconTxWI; ++ PUCHAR BeaconBuf; ++ USHORT BeaconOffset[HW_BEACON_MAX_COUNT]; ++ ++ // pre-build PS-POLL and NULL frame upon link up. for efficiency purpose. ++ PSPOLL_FRAME PsPollFrame; ++ HEADER_802_11 NullFrame; ++ ++#ifdef RT2870 ++ TX_CONTEXT BeaconContext[BEACON_RING_SIZE]; ++ TX_CONTEXT NullContext; ++ TX_CONTEXT PsPollContext; ++ TX_CONTEXT RTSContext; ++#endif // RT2870 // ++ ++ ++ ++//=========AP=========== ++ ++ ++//=======STA=========== ++#ifdef CONFIG_STA_SUPPORT ++/* Modified by Wu Xi-Kun 4/21/2006 */ ++ // ----------------------------------------------- ++ // STA specific configuration & operation status ++ // used only when pAd->OpMode == OPMODE_STA ++ // ----------------------------------------------- ++ STA_ADMIN_CONFIG StaCfg; // user desired settings ++ STA_ACTIVE_CONFIG StaActive; // valid only when ADHOC_ON(pAd) || INFRA_ON(pAd) ++ CHAR nickname[IW_ESSID_MAX_SIZE+1]; // nickname, only used in the iwconfig i/f ++ NDIS_MEDIA_STATE PreMediaState; ++#endif // CONFIG_STA_SUPPORT // ++ ++//=======Common=========== ++ // OP mode: either AP or STA ++ UCHAR OpMode; // OPMODE_STA, OPMODE_AP ++ ++ NDIS_MEDIA_STATE IndicateMediaState; // Base on Indication state, default is NdisMediaStateDisConnected ++ ++ ++ // MAT related parameters ++ ++ // configuration: read from Registry & E2PROM ++ BOOLEAN bLocalAdminMAC; // Use user changed MAC ++ UCHAR PermanentAddress[MAC_ADDR_LEN]; // Factory default MAC address ++ UCHAR CurrentAddress[MAC_ADDR_LEN]; // User changed MAC address ++ ++ // ------------------------------------------------------ ++ // common configuration to both OPMODE_STA and OPMODE_AP ++ // ------------------------------------------------------ ++ COMMON_CONFIG CommonCfg; ++ MLME_STRUCT Mlme; ++ ++ // AP needs those vaiables for site survey feature. ++ MLME_AUX MlmeAux; // temporary settings used during MLME state machine ++ BSS_TABLE ScanTab; // store the latest SCAN result ++ ++ //About MacTab, the sta driver will use #0 and #1 for multicast and AP. ++ MAC_TABLE MacTab; // ASIC on-chip WCID entry table. At TX, ASIC always use key according to this on-chip table. ++ NDIS_SPIN_LOCK MacTabLock; ++ ++#ifdef DOT11_N_SUPPORT ++ BA_TABLE BATable; ++#endif // DOT11_N_SUPPORT // ++ NDIS_SPIN_LOCK BATabLock; ++ RALINK_TIMER_STRUCT RECBATimer; ++ ++ // encryption/decryption KEY tables ++ CIPHER_KEY SharedKey[MAX_MBSSID_NUM][4]; // STA always use SharedKey[BSS0][0..3] ++ ++ // RX re-assembly buffer for fragmentation ++ FRAGMENT_FRAME FragFrame; // Frame storage for fragment frame ++ ++ // various Counters ++ COUNTER_802_3 Counters8023; // 802.3 counters ++ COUNTER_802_11 WlanCounters; // 802.11 MIB counters ++ COUNTER_RALINK RalinkCounters; // Ralink propriety counters ++ COUNTER_DRS DrsCounters; // counters for Dynamic TX Rate Switching ++ PRIVATE_STRUC PrivateInfo; // Private information & counters ++ ++ // flags, see fRTMP_ADAPTER_xxx flags ++ ULONG Flags; // Represent current device status ++ ++ // current TX sequence # ++ USHORT Sequence; ++ ++#ifdef UNDER_CE ++ NDIS_HANDLE hGiISR; ++#endif ++ ++ ++ // Control disconnect / connect event generation ++ //+++Didn't used anymore ++ ULONG LinkDownTime; ++ //--- ++ ULONG LastRxRate; ++ ULONG LastTxRate; ++ //+++Used only for Station ++ BOOLEAN bConfigChanged; // Config Change flag for the same SSID setting ++ //--- ++ ++ ULONG ExtraInfo; // Extra information for displaying status ++ ULONG SystemErrorBitmap; // b0: E2PROM version error ++ ++ //+++Didn't used anymore ++ ULONG MacIcVersion; // MAC/BBP serial interface issue solved after ver.D ++ //--- ++ ++ // --------------------------- ++ // System event log ++ // --------------------------- ++ RT_802_11_EVENT_TABLE EventTab; ++ ++ ++ BOOLEAN HTCEnable; ++ ++ /*****************************************************************************************/ ++ /* Statistic related parameters */ ++ /*****************************************************************************************/ ++#ifdef RT2870 ++ ULONG BulkOutDataOneSecCount; ++ ULONG BulkInDataOneSecCount; ++ ULONG BulkLastOneSecCount; // BulkOutDataOneSecCount + BulkInDataOneSecCount ++ ULONG watchDogRxCnt; ++ ULONG watchDogRxOverFlowCnt; ++ ULONG watchDogTxPendingCnt[NUM_OF_TX_RING]; ++#endif // RT2870 // ++ ++ BOOLEAN bUpdateBcnCntDone; ++ ULONG watchDogMacDeadlock; // prevent MAC/BBP into deadlock condition ++ // ---------------------------- ++ // DEBUG paramerts ++ // ---------------------------- ++ //ULONG DebugSetting[4]; ++ BOOLEAN bBanAllBaSetup; ++ BOOLEAN bPromiscuous; ++ ++ // ---------------------------- ++ // rt2860c emulation-use Parameters ++ // ---------------------------- ++ ULONG rtsaccu[30]; ++ ULONG ctsaccu[30]; ++ ULONG cfendaccu[30]; ++ ULONG bacontent[16]; ++ ULONG rxint[RX_RING_SIZE+1]; ++ UCHAR rcvba[60]; ++ BOOLEAN bLinkAdapt; ++ BOOLEAN bForcePrintTX; ++ BOOLEAN bForcePrintRX; ++ BOOLEAN bDisablescanning; //defined in RT2870 USB ++ BOOLEAN bStaFifoTest; ++ BOOLEAN bProtectionTest; ++ BOOLEAN bHCCATest; ++ BOOLEAN bGenOneHCCA; ++ BOOLEAN bBroadComHT; ++ //+++Following add from RT2870 USB. ++ ULONG BulkOutReq; ++ ULONG BulkOutComplete; ++ ULONG BulkOutCompleteOther; ++ ULONG BulkOutCompleteCancel; // seems not use now? ++ ULONG BulkInReq; ++ ULONG BulkInComplete; ++ ULONG BulkInCompleteFail; ++ //--- ++ ++ struct wificonf WIFItestbed; ++ ++#ifdef RALINK_ATE ++ ATE_INFO ate; ++#ifdef RT2870 ++ BOOLEAN ContinBulkOut; //ATE bulk out control ++ BOOLEAN ContinBulkIn; //ATE bulk in control ++ atomic_t BulkOutRemained; ++ atomic_t BulkInRemained; ++#endif // RT2870 // ++#endif // RALINK_ATE // ++ ++#ifdef DOT11_N_SUPPORT ++ struct reordering_mpdu_pool mpdu_blk_pool; ++#endif // DOT11_N_SUPPORT // ++ ++ ULONG OneSecondnonBEpackets; // record non BE packets per second ++ ++#if WIRELESS_EXT >= 12 ++ struct iw_statistics iw_stats; ++#endif ++ ++ struct net_device_stats stats; ++ ++#ifdef BLOCK_NET_IF ++ BLOCK_QUEUE_ENTRY blockQueueTab[NUM_OF_TX_RING]; ++#endif // BLOCK_NET_IF // ++ ++ ++ ++#ifdef MULTIPLE_CARD_SUPPORT ++ INT32 MC_RowID; ++ UCHAR MC_FileName[256]; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ ULONG TbttTickCount; ++#ifdef PCI_MSI_SUPPORT ++ BOOLEAN HaveMsi; ++#endif // PCI_MSI_SUPPORT // ++ ++ ++ UCHAR is_on; ++ ++#define TIME_BASE (1000000/OS_HZ) ++#define TIME_ONE_SECOND (1000000/TIME_BASE) ++ UCHAR flg_be_adjust; ++ ULONG be_adjust_last_time; ++ ++#ifdef NINTENDO_AP ++ NINDO_CTRL_BLOCK nindo_ctrl_block; ++#endif // NINTENDO_AP // ++ ++ ++#ifdef IKANOS_VX_1X0 ++ struct IKANOS_TX_INFO IkanosTxInfo; ++ struct IKANOS_TX_INFO IkanosRxInfo[MAX_MBSSID_NUM + MAX_WDS_ENTRY + MAX_APCLI_NUM + MAX_MESH_NUM]; ++#endif // IKANOS_VX_1X0 // ++ ++ ++#ifdef DBG_DIAGNOSE ++ RtmpDiagStruct DiagStruct; ++#endif // DBG_DIAGNOSE // ++ ++ ++ UINT8 PM_FlgSuspend; ++ ++#ifdef RT30xx ++//======efuse ++ BOOLEAN bUseEfuse; ++ BOOLEAN bEEPROMFile; ++#endif // RT30xx // ++ ++} RTMP_ADAPTER, *PRTMP_ADAPTER; ++ ++// ++// Cisco IAPP format ++// ++typedef struct _CISCO_IAPP_CONTENT_ ++{ ++ USHORT Length; //IAPP Length ++ UCHAR MessageType; //IAPP type ++ UCHAR FunctionCode; //IAPP function type ++ UCHAR DestinaionMAC[MAC_ADDR_LEN]; ++ UCHAR SourceMAC[MAC_ADDR_LEN]; ++ USHORT Tag; //Tag(element IE) - Adjacent AP report ++ USHORT TagLength; //Length of element not including 4 byte header ++ UCHAR OUI[4]; //0x00, 0x40, 0x96, 0x00 ++ UCHAR PreviousAP[MAC_ADDR_LEN]; //MAC Address of access point ++ USHORT Channel; ++ USHORT SsidLen; ++ UCHAR Ssid[MAX_LEN_OF_SSID]; ++ USHORT Seconds; //Seconds that the client has been disassociated. ++} CISCO_IAPP_CONTENT, *PCISCO_IAPP_CONTENT; ++ ++#define DELAYINTMASK 0x0003fffb ++#define INTMASK 0x0003fffb ++#define IndMask 0x0003fffc ++#define RxINT 0x00000005 // Delayed Rx or indivi rx ++#define TxDataInt 0x000000fa // Delayed Tx or indivi tx ++#define TxMgmtInt 0x00000102 // Delayed Tx or indivi tx ++#define TxCoherent 0x00020000 // tx coherent ++#define RxCoherent 0x00010000 // rx coherent ++#define McuCommand 0x00000200 // mcu ++#define PreTBTTInt 0x00001000 // Pre-TBTT interrupt ++#define TBTTInt 0x00000800 // TBTT interrupt ++#define GPTimeOutInt 0x00008000 // GPtimeout interrupt ++#define AutoWakeupInt 0x00004000 // AutoWakeupInt interrupt ++#define FifoStaFullInt 0x00002000 // fifo statistics full interrupt ++ ++ ++typedef struct _RX_BLK_ ++{ ++// RXD_STRUC RxD; // sample ++ RT28XX_RXD_STRUC RxD; ++ PRXWI_STRUC pRxWI; ++ PHEADER_802_11 pHeader; ++ PNDIS_PACKET pRxPacket; ++ UCHAR *pData; ++ USHORT DataSize; ++ USHORT Flags; ++ UCHAR UserPriority; // for calculate TKIP MIC using ++} RX_BLK; ++ ++ ++#define RX_BLK_SET_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags |= _flag) ++#define RX_BLK_TEST_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags & _flag) ++#define RX_BLK_CLEAR_FLAG(_pRxBlk, _flag) (_pRxBlk->Flags &= ~(_flag)) ++ ++ ++#define fRX_WDS 0x0001 ++#define fRX_AMSDU 0x0002 ++#define fRX_ARALINK 0x0004 ++#define fRX_HTC 0x0008 ++#define fRX_PAD 0x0010 ++#define fRX_AMPDU 0x0020 ++#define fRX_QOS 0x0040 ++#define fRX_INFRA 0x0080 ++#define fRX_EAP 0x0100 ++#define fRX_MESH 0x0200 ++#define fRX_APCLI 0x0400 ++#define fRX_DLS 0x0800 ++#define fRX_WPI 0x1000 ++ ++#define LENGTH_AMSDU_SUBFRAMEHEAD 14 ++#define LENGTH_ARALINK_SUBFRAMEHEAD 14 ++#define LENGTH_ARALINK_HEADER_FIELD 2 ++ ++#define TX_UNKOWN_FRAME 0x00 ++#define TX_MCAST_FRAME 0x01 ++#define TX_LEGACY_FRAME 0x02 ++#define TX_AMPDU_FRAME 0x04 ++#define TX_AMSDU_FRAME 0x08 ++#define TX_RALINK_FRAME 0x10 ++#define TX_FRAG_FRAME 0x20 ++ ++ ++// Currently the sizeof(TX_BLK) is 148 bytes. ++typedef struct _TX_BLK_ ++{ ++ UCHAR QueIdx; ++ UCHAR TxFrameType; // Indicate the Transmission type of the all frames in one batch ++ UCHAR TotalFrameNum; // Total frame number want to send-out in one batch ++ USHORT TotalFragNum; // Total frame fragments required in one batch ++ USHORT TotalFrameLen; // Total length of all frames want to send-out in one batch ++ ++ QUEUE_HEADER TxPacketList; ++ MAC_TABLE_ENTRY *pMacEntry; // NULL: packet with 802.11 RA field is multicast/broadcast address ++ HTTRANSMIT_SETTING *pTransmit; ++ ++ // Following structure used for the characteristics of a specific packet. ++ PNDIS_PACKET pPacket; ++ PUCHAR pSrcBufHeader; // Reference to the head of sk_buff->data ++ PUCHAR pSrcBufData; // Reference to the sk_buff->data, will changed depends on hanlding progresss ++ UINT SrcBufLen; // Length of packet payload which not including Layer 2 header ++ PUCHAR pExtraLlcSnapEncap; // NULL means no extra LLC/SNAP is required ++ UCHAR HeaderBuf[80]; // TempBuffer for TX_INFO + TX_WI + 802.11 Header + padding + AMSDU SubHeader + LLC/SNAP ++ UCHAR MpduHeaderLen; // 802.11 header length NOT including the padding ++ UCHAR HdrPadLen; // recording Header Padding Length; ++ UCHAR apidx; // The interface associated to this packet ++ UCHAR Wcid; // The MAC entry associated to this packet ++ UCHAR UserPriority; // priority class of packet ++ UCHAR FrameGap; // what kind of IFS this packet use ++ UCHAR MpduReqNum; // number of fragments of this frame ++ UCHAR TxRate; // TODO: Obsoleted? Should change to MCS? ++ UCHAR CipherAlg; // cipher alogrithm ++ PCIPHER_KEY pKey; ++ ++ ++ ++ USHORT Flags; //See following definitions for detail. ++ ++ //YOU SHOULD NOT TOUCH IT! Following parameters are used for hardware-depended layer. ++ ULONG Priv; // Hardware specific value saved in here. ++} TX_BLK, *PTX_BLK; ++ ++ ++#define fTX_bRtsRequired 0x0001 // Indicate if need send RTS frame for protection. Not used in RT2860/RT2870. ++#define fTX_bAckRequired 0x0002 // the packet need ack response ++#define fTX_bPiggyBack 0x0004 // Legacy device use Piggback or not ++#define fTX_bHTRate 0x0008 // allow to use HT rate ++//#define fTX_bForceLowRate 0x0010 // force to use Low Rate ++#define fTX_bForceNonQoS 0x0010 // force to transmit frame without WMM-QoS in HT mode ++#define fTX_bAllowFrag 0x0020 // allow to fragment the packet, A-MPDU, A-MSDU, A-Ralink is not allowed to fragment ++#define fTX_bMoreData 0x0040 // there are more data packets in PowerSave Queue ++#define fTX_bWMM 0x0080 // QOS Data ++ ++#define fTX_bClearEAPFrame 0x0100 ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++#define TX_BLK_ASSIGN_FLAG(_pTxBlk, _flag, value) \ ++ do { \ ++ if (value) \ ++ (_pTxBlk->Flags |= _flag) \ ++ else \ ++ (_pTxBlk->Flags &= ~(_flag)) \ ++ }while(0) ++ ++#define TX_BLK_SET_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags |= _flag) ++#define TX_BLK_TEST_FLAG(_pTxBlk, _flag) (((_pTxBlk->Flags & _flag) == _flag) ? 1 : 0) ++#define TX_BLK_CLEAR_FLAG(_pTxBlk, _flag) (_pTxBlk->Flags &= ~(_flag)) ++ ++ ++ ++ ++ ++//------------------------------------------------------------------------------------------ ++ ++ ++ ++#ifdef RT_BIG_ENDIAN ++static inline VOID WriteBackToDescriptor( ++ IN PUCHAR Dest, ++ IN PUCHAR Src, ++ IN BOOLEAN DoEncrypt, ++ IN ULONG DescriptorType) ++{ ++ UINT32 *p1, *p2; ++ ++ p1 = ((UINT32 *)Dest); ++ p2 = ((UINT32 *)Src); ++ ++ *p1 = *p2; ++ *(p1+2) = *(p2+2); ++ *(p1+3) = *(p2+3); ++ *(p1+1) = *(p2+1); // Word 1; this must be written back last ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of Tx/Rx descriptor . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to Tx/Rx descriptor ++ DescriptorType Direction of the frame ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update descriptor ++ ======================================================================== ++*/ ++static inline VOID RTMPWIEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType) ++{ ++ int size; ++ int i; ++ ++ size = ((DescriptorType == TYPE_TXWI) ? TXWI_SIZE : RXWI_SIZE); ++ ++ if(DescriptorType == TYPE_TXWI) ++ { ++ *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); // Byte 0~3 ++ *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData+4))); // Byte 4~7 ++ } ++ else ++ { ++ for(i=0; i < size/4 ; i++) ++ *(((UINT32 *)pData) +i) = SWAP32(*(((UINT32 *)pData)+i)); ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of Tx/Rx descriptor . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to Tx/Rx descriptor ++ DescriptorType Direction of the frame ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update descriptor ++ ======================================================================== ++*/ ++ ++#ifdef RT2870 ++static inline VOID RTMPDescriptorEndianChange( ++ IN PUCHAR pData, ++ IN ULONG DescriptorType) ++{ ++ *((UINT32 *)(pData)) = SWAP32(*((UINT32 *)(pData))); ++} ++#endif // RT2870 // ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Endian conversion of all kinds of 802.11 frames . ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Pointer to the 802.11 frame structure ++ Dir Direction of the frame ++ FromRxDoneInt Caller is from RxDone interrupt ++ ++ Return Value: ++ None ++ ++ Note: ++ Call this function when read or update buffer data ++ ======================================================================== ++*/ ++static inline VOID RTMPFrameEndianChange( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG Dir, ++ IN BOOLEAN FromRxDoneInt) ++{ ++ PHEADER_802_11 pFrame; ++ PUCHAR pMacHdr; ++ ++ // swab 16 bit fields - Frame Control field ++ if(Dir == DIR_READ) ++ { ++ *(USHORT *)pData = SWAP16(*(USHORT *)pData); ++ } ++ ++ pFrame = (PHEADER_802_11) pData; ++ pMacHdr = (PUCHAR) pFrame; ++ ++ // swab 16 bit fields - Duration/ID field ++ *(USHORT *)(pMacHdr + 2) = SWAP16(*(USHORT *)(pMacHdr + 2)); ++ ++ // swab 16 bit fields - Sequence Control field ++ *(USHORT *)(pMacHdr + 22) = SWAP16(*(USHORT *)(pMacHdr + 22)); ++ ++ if(pFrame->FC.Type == BTYPE_MGMT) ++ { ++ switch(pFrame->FC.SubType) ++ { ++ case SUBTYPE_ASSOC_REQ: ++ case SUBTYPE_REASSOC_REQ: ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Listen Interval field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_ASSOC_RSP: ++ case SUBTYPE_REASSOC_RSP: ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Status Code field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - AID field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_AUTH: ++ // If from APHandleRxDoneInterrupt routine, it is still a encrypt format. ++ // The convertion is delayed to RTMPHandleDecryptionDoneInterrupt. ++ if(!FromRxDoneInt && pFrame->FC.Wep == 1) ++ break; ++ else ++ { ++ // swab 16 bit fields - Auth Alg No. field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Auth Seq No. field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - Status Code field ++ pMacHdr += 2; ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ } ++ break; ++ ++ case SUBTYPE_BEACON: ++ case SUBTYPE_PROBE_RSP: ++ // swab 16 bit fields - BeaconInterval field ++ pMacHdr += (sizeof(HEADER_802_11) + TIMESTAMP_LEN); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ ++ // swab 16 bit fields - CapabilityInfo field ++ pMacHdr += sizeof(USHORT); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ ++ case SUBTYPE_DEAUTH: ++ case SUBTYPE_DISASSOC: ++ // swab 16 bit fields - Reason code field ++ pMacHdr += sizeof(HEADER_802_11); ++ *(USHORT *)pMacHdr = SWAP16(*(USHORT *)pMacHdr); ++ break; ++ } ++ } ++ else if( pFrame->FC.Type == BTYPE_DATA ) ++ { ++ } ++ else if(pFrame->FC.Type == BTYPE_CNTL) ++ { ++ switch(pFrame->FC.SubType) ++ { ++ case SUBTYPE_BLOCK_ACK_REQ: ++ { ++ PFRAME_BA_REQ pBAReq = (PFRAME_BA_REQ)pFrame; ++ *(USHORT *)(&pBAReq->BARControl) = SWAP16(*(USHORT *)(&pBAReq->BARControl)); ++ pBAReq->BAStartingSeq.word = SWAP16(pBAReq->BAStartingSeq.word); ++ } ++ break; ++ case SUBTYPE_BLOCK_ACK: ++ // For Block Ack packet, the HT_CONTROL field is in the same offset with Addr3 ++ *(UINT32 *)(&pFrame->Addr3[0]) = SWAP32(*(UINT32 *)(&pFrame->Addr3[0])); ++ break; ++ ++ case SUBTYPE_ACK: ++ //For ACK packet, the HT_CONTROL field is in the same offset with Addr2 ++ *(UINT32 *)(&pFrame->Addr2[0])= SWAP32(*(UINT32 *)(&pFrame->Addr2[0])); ++ break; ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("Invalid Frame Type!!!\n")); ++ } ++ ++ // swab 16 bit fields - Frame Control ++ if(Dir == DIR_WRITE) ++ { ++ *(USHORT *)pData = SWAP16(*(USHORT *)pData); ++ } ++} ++#endif // RT_BIG_ENDIAN // ++ ++ ++static inline VOID ConvertMulticastIP2MAC( ++ IN PUCHAR pIpAddr, ++ IN PUCHAR *ppMacAddr, ++ IN UINT16 ProtoType) ++{ ++ if (pIpAddr == NULL) ++ return; ++ ++ if (ppMacAddr == NULL || *ppMacAddr == NULL) ++ return; ++ ++ switch (ProtoType) ++ { ++ case ETH_P_IPV6: ++// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); ++ *(*ppMacAddr) = 0x33; ++ *(*ppMacAddr + 1) = 0x33; ++ *(*ppMacAddr + 2) = pIpAddr[12]; ++ *(*ppMacAddr + 3) = pIpAddr[13]; ++ *(*ppMacAddr + 4) = pIpAddr[14]; ++ *(*ppMacAddr + 5) = pIpAddr[15]; ++ break; ++ ++ case ETH_P_IP: ++ default: ++// memset(*ppMacAddr, 0, ETH_LENGTH_OF_ADDRESS); ++ *(*ppMacAddr) = 0x01; ++ *(*ppMacAddr + 1) = 0x00; ++ *(*ppMacAddr + 2) = 0x5e; ++ *(*ppMacAddr + 3) = pIpAddr[1] & 0x7f; ++ *(*ppMacAddr + 4) = pIpAddr[2]; ++ *(*ppMacAddr + 5) = pIpAddr[3]; ++ break; ++ } ++ ++ return; ++} ++ ++BOOLEAN RTMPCheckForHang( ++ IN NDIS_HANDLE MiniportAdapterContext ++ ); ++ ++VOID RTMPHalt( ++ IN NDIS_HANDLE MiniportAdapterContext ++ ); ++ ++// ++// Private routines in rtmp_init.c ++// ++NDIS_STATUS RTMPAllocAdapterBlock( ++ IN PVOID handle, ++ OUT PRTMP_ADAPTER *ppAdapter ++ ); ++ ++NDIS_STATUS RTMPAllocTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++NDIS_STATUS RTMPFindAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ); ++ ++NDIS_STATUS RTMPReadParametersHook( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++VOID RTMPFreeAdapter( ++ IN PRTMP_ADAPTER pAd ++ ); ++ ++NDIS_STATUS NICReadRegParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_HANDLE WrapperConfigurationContext ++ ); ++ ++#ifdef RT30xx ++VOID NICInitRT30xxRFRegisters( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT30xx // ++ ++VOID NICReadEEPROMParameters( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mac_addr); ++ ++VOID NICInitAsicFromEEPROM( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICInitTxRxRingAndBacklogQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICInitializeAdapter( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset); ++ ++NDIS_STATUS NICInitializeAsic( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bHardReset); ++ ++VOID NICIssueReset( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPRingCleanUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType); ++ ++VOID RxTest( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS DbgSendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++VOID UserCfgInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICResetFromError( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICEraseFirmware( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICLoadFirmware( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS NICLoadRateSwitchingParams( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN NICCheckForHang( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICUpdateFifoStaCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NICUpdateRawCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG RTMPNotAllZero( ++ IN PVOID pSrc1, ++ IN ULONG Length); ++ ++VOID RTMPZeroMemory( ++ IN PVOID pSrc, ++ IN ULONG Length); ++ ++ULONG RTMPCompareMemory( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ IN ULONG Length); ++ ++VOID RTMPMoveMemory( ++ OUT PVOID pDest, ++ IN PVOID pSrc, ++ IN ULONG Length); ++ ++VOID AtoH( ++ char *src, ++ UCHAR *dest, ++ int destlen); ++ ++UCHAR BtoH( ++ char ch); ++ ++VOID RTMPPatchMacBbpBug( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPPatchCardBus( ++ IN PRTMP_ADAPTER pAdapter); ++ ++VOID RTMPPatchRalinkCardBus( ++ IN PRTMP_ADAPTER pAdapter, ++ IN ULONG Bus); ++ ++ULONG RTMPReadCBConfig( ++ IN ULONG Bus, ++ IN ULONG Slot, ++ IN ULONG Func, ++ IN ULONG Offset); ++ ++VOID RTMPWriteCBConfig( ++ IN ULONG Bus, ++ IN ULONG Slot, ++ IN ULONG Func, ++ IN ULONG Offset, ++ IN ULONG Value); ++ ++VOID RTMPInitTimer( ++ IN PRTMP_ADAPTER pAd, ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN PVOID pTimerFunc, ++ IN PVOID pData, ++ IN BOOLEAN Repeat); ++ ++VOID RTMPSetTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value); ++ ++ ++VOID RTMPModTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ IN ULONG Value); ++ ++VOID RTMPCancelTimer( ++ IN PRALINK_TIMER_STRUCT pTimer, ++ OUT BOOLEAN *pCancelled); ++ ++VOID RTMPSetLED( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Status); ++ ++VOID RTMPSetSignalLED( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_802_11_RSSI Dbm); ++ ++VOID RTMPEnableRxTx( ++ IN PRTMP_ADAPTER pAd); ++ ++// ++// prototype in action.c ++// ++VOID ActionStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeADDBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDELBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeInvalidAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerAddBAReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAddBARspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDelBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBAAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // DOT11_N_SUPPORT // ++ ++VOID SendPSMPAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Psmp); ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID SendBSS2040CoexistMgmtAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx, ++ IN UCHAR InfoReq); ++ ++VOID SendNotifyBWActionFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR apidx); ++ ++BOOLEAN ChannelSwitchSanityCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR NewChannel, ++ IN UCHAR Secondary); ++ ++VOID ChannelSwitchAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR Channel, ++ IN UCHAR Secondary); ++ ++ULONG BuildIntolerantChannelRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest); ++ ++VOID Update2040CoexistFrameAndNotify( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha); ++ ++VOID Send2040CoexistAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN BOOLEAN bAddIntolerantCha); ++#endif // DOT11N_DRAFT3 // ++ ++VOID PeerRMAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID StaPublicAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Bss2040Coexist); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++VOID PeerBSSTranAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef DOT11_N_SUPPORT ++VOID PeerHTAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // DOT11_N_SUPPORT // ++ ++VOID PeerQOSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef QOS_DLS_SUPPORT ++VOID PeerDLSAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // QOS_DLS_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++VOID DlsParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, ++ IN PRT_802_11_DLS pDls, ++ IN USHORT reason); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID RECBATimerTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID ORIBATimerTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID SendRefreshBAR( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++#endif // DOT11_N_SUPPORT // ++ ++VOID ActHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN PUCHAR Addr1, ++ IN PUCHAR Addr2, ++ IN PUCHAR Addr3); ++ ++VOID BarHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PFRAME_BAR pCntlBar, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA); ++ ++VOID InsertActField( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pFrameBuf, ++ OUT PULONG pFrameLen, ++ IN UINT8 Category, ++ IN UINT8 ActCode); ++ ++BOOLEAN QosBADataParse( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bAMSDU, ++ IN PUCHAR p8023Header, ++ IN UCHAR WCID, ++ IN UCHAR TID, ++ IN USHORT Sequence, ++ IN UCHAR DataOffset, ++ IN USHORT Datasize, ++ IN UINT CurRxIndex); ++ ++#ifdef DOT11_N_SUPPORT ++BOOLEAN CntlEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG MsgLen, ++ IN PFRAME_BA_REQ pMsg); ++ ++VOID BaAutoManSwitch( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11_N_SUPPORT // ++ ++VOID HTIOTCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BatRecIdx); ++ ++// ++// Private routines in rtmp_data.c ++// ++BOOLEAN RTMPHandleRxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleTxDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPHandleTxRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd, ++ IN INT_SOURCE_CSR_STRUC TxRingBitmap); ++ ++VOID RTMPHandleMgmtRingDmaDoneInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandlePreTBTTInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++void RTMPHandleTwakeupInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPHandleRxCoherentInterrupt( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN TxFrameIsAggregatible( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pPrevAddr1, ++ IN PUCHAR p8023hdr); ++ ++BOOLEAN PeerIsAggreOn( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG TxRate, ++ IN PMAC_TABLE_ENTRY pMacEntry); ++ ++NDIS_STATUS Sniff2BytesFromNdisBuffer( ++ IN PNDIS_BUFFER pFirstBuffer, ++ IN UCHAR DesiredOffset, ++ OUT PUCHAR pByte0, ++ OUT PUCHAR pByte1); ++ ++NDIS_STATUS STASendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++VOID STASendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets); ++ ++VOID RTMPDeQueuePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bIntContext, ++ IN UCHAR QueIdx, ++ IN UCHAR Max_Tx_Packets); ++ ++NDIS_STATUS RTMPHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR QueIdx, ++ OUT PULONG pFreeTXDLeft); ++ ++NDIS_STATUS STAHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++VOID STARxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++NDIS_STATUS RTMPFreeTXDRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RingType, ++ IN UCHAR NumberRequired, ++ IN PUCHAR FreeNumberIs); ++ ++NDIS_STATUS MlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++NDIS_STATUS MlmeHardTransmitMgmtRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++NDIS_STATUS MlmeHardTransmitTxRing( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket); ++ ++USHORT RTMPCalcDuration( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Rate, ++ IN ULONG Size); ++ ++VOID RTMPWriteTxWI( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXWI_STRUC pTxWI, ++ IN BOOLEAN FRAG, ++ IN BOOLEAN CFACK, ++ IN BOOLEAN InsTimestamp, ++ IN BOOLEAN AMPDU, ++ IN BOOLEAN Ack, ++ IN BOOLEAN NSeq, // HW new a sequence. ++ IN UCHAR BASize, ++ IN UCHAR WCID, ++ IN ULONG Length, ++ IN UCHAR PID, ++ IN UCHAR TID, ++ IN UCHAR TxRate, ++ IN UCHAR Txopmode, ++ IN BOOLEAN CfAck, ++ IN HTTRANSMIT_SETTING *pTransmit); ++ ++ ++VOID RTMPWriteTxWI_Data( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk); ++ ++ ++VOID RTMPWriteTxWI_Cache( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PTXWI_STRUC pTxWI, ++ IN TX_BLK *pTxBlk); ++ ++VOID RTMPWriteTxDescriptor( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXD_STRUC pTxD, ++ IN BOOLEAN bWIV, ++ IN UCHAR QSEL); ++ ++VOID RTMPSuspendMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPResumeMsduTransmission( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS MiniportMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length); ++ ++NDIS_STATUS MiniportDataMMRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN PUCHAR pData, ++ IN UINT Length); ++ ++VOID RTMPSendNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull); ++ ++VOID RTMPSendDisassociationFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSendRTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN unsigned int NextMpduSize, ++ IN UCHAR TxRate, ++ IN UCHAR RTSRate, ++ IN USHORT AckDuration, ++ IN UCHAR QueIdx, ++ IN UCHAR FrameGap); ++ ++ ++NDIS_STATUS RTMPApplyPacketFilter( ++ IN PRTMP_ADAPTER pAd, ++ IN PRT28XX_RXD_STRUC pRxD, ++ IN PHEADER_802_11 pHeader); ++ ++PQUEUE_HEADER RTMPCheckTxSwQueue( ++ IN PRTMP_ADAPTER pAd, ++ OUT UCHAR *QueIdx); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPReportMicError( ++ IN PRTMP_ADAPTER pAd, ++ IN PCIPHER_KEY pWpaKey); ++ ++VOID WpaMicFailureReportFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaDisassocApAndBlockAssoc( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++#endif // CONFIG_STA_SUPPORT // ++ ++NDIS_STATUS RTMPCloneNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN pInsAMSDUHdr, ++ IN PNDIS_PACKET pInPacket, ++ OUT PNDIS_PACKET *ppOutPacket); ++ ++NDIS_STATUS RTMPAllocateNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET *pPacket, ++ IN PUCHAR pHeader, ++ IN UINT HeaderLen, ++ IN PUCHAR pData, ++ IN UINT DataLen); ++ ++VOID RTMPFreeNdisPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++BOOLEAN RTMPFreeTXDUponTxDmaDone( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx); ++ ++BOOLEAN RTMPCheckDHCPFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++BOOLEAN RTMPCheckEtherType( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++VOID RTMPCckBbpTuning( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT TxRate); ++ ++// ++// Private routines in rtmp_wep.c ++// ++VOID RTMPInitWepEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN UCHAR KeyId, ++ IN UCHAR KeyLen, ++ IN PUCHAR pDest); ++ ++VOID RTMPEncryptData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDest, ++ IN UINT Len); ++ ++BOOLEAN RTMPDecryptData( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR pSrc, ++ IN UINT Len, ++ IN UINT idx); ++ ++BOOLEAN RTMPSoftDecryptWEP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pGroupKey); ++ ++VOID RTMPSetICV( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDest); ++ ++VOID ARCFOUR_INIT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pKey, ++ IN UINT KeyLen); ++ ++UCHAR ARCFOUR_BYTE( ++ IN PARCFOURCONTEXT Ctx); ++ ++VOID ARCFOUR_DECRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++VOID ARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++VOID WPAARCFOUR_ENCRYPT( ++ IN PARCFOURCONTEXT Ctx, ++ IN PUCHAR pDest, ++ IN PUCHAR pSrc, ++ IN UINT Len); ++ ++UINT RTMP_CALC_FCS32( ++ IN UINT Fcs, ++ IN PUCHAR Cp, ++ IN INT Len); ++ ++// ++// MLME routines ++// ++ ++// Asic/RF/BBP related functions ++ ++VOID AsicAdjustTxPower( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicUpdateProtect( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT OperaionMode, ++ IN UCHAR SetMask, ++ IN BOOLEAN bDisableBGProtect, ++ IN BOOLEAN bNonGFExist); ++ ++VOID AsicSwitchChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel, ++ IN BOOLEAN bScan); ++ ++VOID AsicLockChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel) ; ++ ++VOID AsicAntennaSelect( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++VOID AsicAntennaSetting( ++ IN PRTMP_ADAPTER pAd, ++ IN ABGBAND_STATE BandState); ++ ++VOID AsicRfTuningExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID AsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp); ++ ++VOID AsicForceSleep( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx); ++#endif // CONFIG_STA_SUPPORT // ++ ++VOID AsicSetBssid( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid); ++ ++VOID AsicSetMcastWC( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDelWcidTab( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid); ++ ++VOID AsicEnableRDG( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDisableRDG( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicDisableSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicEnableBssSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicEnableIbssSync( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicSetEdcaParm( ++ IN PRTMP_ADAPTER pAd, ++ IN PEDCA_PARM pEdcaParm); ++ ++VOID AsicSetSlotTime( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUseShortSlotTime); ++ ++VOID AsicAddSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN PUCHAR pKey, ++ IN PUCHAR pTxMic, ++ IN PUCHAR pRxMic); ++ ++VOID AsicRemoveSharedKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx); ++ ++VOID AsicUpdateWCIDAttribute( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bUsePairewiseKeyTable); ++ ++VOID AsicUpdateWCIDIVEIV( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN ULONG uIV, ++ IN ULONG uEIV); ++ ++VOID AsicUpdateRxWCIDTable( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN PUCHAR pAddr); ++ ++VOID AsicAddKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT WCID, ++ IN UCHAR BssIndex, ++ IN UCHAR KeyIdx, ++ IN PCIPHER_KEY pCipherKey, ++ IN BOOLEAN bUsePairewiseKeyTable, ++ IN BOOLEAN bTxKey); ++ ++VOID AsicAddPairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UCHAR WCID, ++ IN CIPHER_KEY *pCipherKey); ++ ++VOID AsicRemovePairwiseKeyEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR Wcid); ++ ++BOOLEAN AsicSendCommandToMcu( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Command, ++ IN UCHAR Token, ++ IN UCHAR Arg0, ++ IN UCHAR Arg1); ++ ++ ++VOID MacAddrRandomBssid( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR pAddr); ++ ++VOID MgtMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR SubType, ++ IN UCHAR ToDs, ++ IN PUCHAR pDA, ++ IN PUCHAR pBssid); ++ ++VOID MlmeRadioOff( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeRadioOn( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++VOID BssTableInit( ++ IN BSS_TABLE *Tab); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInit( ++ IN PRTMP_ADAPTER pAd, ++ IN BA_TABLE *Tab); ++#endif // DOT11_N_SUPPORT // ++ ++ULONG BssTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel); ++ ++ULONG BssSsidTableSearch( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR pBssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel); ++ ++ULONG BssTableSearchWithSSID( ++ IN BSS_TABLE *Tab, ++ IN PUCHAR Bssid, ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen, ++ IN UCHAR Channel); ++ ++VOID BssTableDeleteEntry( ++ IN OUT PBSS_TABLE pTab, ++ IN PUCHAR pBssid, ++ IN UCHAR Channel); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableDeleteORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_ORI_ENTRY *pBAORIEntry); ++ ++VOID BATableDeleteRECEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN BA_REC_ENTRY *pBARECEntry); ++ ++VOID BATableTearORIEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR TID, ++ IN UCHAR Wcid, ++ IN BOOLEAN bForceDelete, ++ IN BOOLEAN ALL); ++ ++VOID BATableTearRECEntry( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR TID, ++ IN UCHAR WCID, ++ IN BOOLEAN ALL); ++#endif // DOT11_N_SUPPORT // ++ ++VOID BssEntrySet( ++ IN PRTMP_ADAPTER pAd, ++ OUT PBSS_ENTRY pBss, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN PCF_PARM CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++ULONG BssTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT PBSS_TABLE pTab, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN USHORT BeaconPeriod, ++ IN CF_PARM *CfParm, ++ IN USHORT AtimWin, ++ IN USHORT CapabilityInfo, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR AddHtInfoLen, ++ IN UCHAR NewExtChanOffset, ++ IN UCHAR Channel, ++ IN CHAR Rssi, ++ IN LARGE_INTEGER TimeStamp, ++ IN UCHAR CkipFlag, ++ IN PEDCA_PARM pEdcaParm, ++ IN PQOS_CAPABILITY_PARM pQosCapability, ++ IN PQBSS_LOAD_PARM pQbssLoad, ++ IN USHORT LengthVIE, ++ IN PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++#ifdef DOT11_N_SUPPORT ++VOID BATableInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Aid, ++ IN USHORT TimeOutValue, ++ IN USHORT StartingSeq, ++ IN UCHAR TID, ++ IN UCHAR BAWinSize, ++ IN UCHAR OriginatorStatus, ++ IN BOOLEAN IsRecipient); ++ ++#ifdef DOT11N_DRAFT3 ++VOID Bss2040CoexistTimeOut( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++ ++VOID TriEventInit( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG TriEventTableSetEntry( ++ IN PRTMP_ADAPTER pAd, ++ OUT TRIGGER_EVENT_TAB *Tab, ++ IN PUCHAR pBssid, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN UCHAR RegClass, ++ IN UCHAR ChannelNo); ++ ++VOID TriEventCounterMaintenance( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++VOID BssTableSsidSort( ++ IN PRTMP_ADAPTER pAd, ++ OUT BSS_TABLE *OutTab, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen); ++ ++VOID BssTableSortByRssi( ++ IN OUT BSS_TABLE *OutTab); ++ ++VOID BssCipherParse( ++ IN OUT PBSS_ENTRY pBss); ++ ++NDIS_STATUS MlmeQueueInit( ++ IN MLME_QUEUE *Queue); ++ ++VOID MlmeQueueDestroy( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MlmeEnqueue( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Machine, ++ IN ULONG MsgType, ++ IN ULONG MsgLen, ++ IN VOID *Msg); ++ ++BOOLEAN MlmeEnqueueForRecv( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid, ++ IN ULONG TimeStampHigh, ++ IN ULONG TimeStampLow, ++ IN UCHAR Rssi0, ++ IN UCHAR Rssi1, ++ IN UCHAR Rssi2, ++ IN ULONG MsgLen, ++ IN PVOID Msg, ++ IN UCHAR Signal); ++ ++ ++BOOLEAN MlmeDequeue( ++ IN MLME_QUEUE *Queue, ++ OUT MLME_QUEUE_ELEM **Elem); ++ ++VOID MlmeRestartStateMachine( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeQueueEmpty( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MlmeQueueFull( ++ IN MLME_QUEUE *Queue); ++ ++BOOLEAN MsgTypeSubst( ++ IN PRTMP_ADAPTER pAd, ++ IN PFRAME_802_11 pFrame, ++ OUT INT *Machine, ++ OUT INT *MsgType); ++ ++VOID StateMachineInit( ++ IN STATE_MACHINE *Sm, ++ IN STATE_MACHINE_FUNC Trans[], ++ IN ULONG StNr, ++ IN ULONG MsgNr, ++ IN STATE_MACHINE_FUNC DefFunc, ++ IN ULONG InitState, ++ IN ULONG Base); ++ ++VOID StateMachineSetAction( ++ IN STATE_MACHINE *S, ++ IN ULONG St, ++ ULONG Msg, ++ IN STATE_MACHINE_FUNC F); ++ ++VOID StateMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Drop( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID ReassocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID AssocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID DisassocTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++//---------------------------------------------- ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAssocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerReassocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDisassocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID DisassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AssocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ReassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Cls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID SwitchBetweenWepAndCkip( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID InvalidStateWhenAssoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenReassoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenDisassociate( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef RT2870 ++VOID MlmeCntlConfirm( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG MsgType, ++ IN USHORT Msg); ++#endif // RT2870 // ++ ++VOID ComposePsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ComposeNullFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AssocPostProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr2, ++ IN USHORT CapabilityInfo, ++ IN USHORT Aid, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN PEDCA_PARM pEdcaParm, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID AuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID AuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID MlmeAuthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthRspAtSeq2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthRspAtSeq4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AuthTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Cls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr); ++ ++VOID MlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenAuth( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++//============================================= ++ ++VOID AuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]); ++ ++VOID PeerDeauthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT Reason, ++ IN USHORT Status); ++ ++// ++// Private routines in dls.c ++// ++ ++#ifdef CONFIG_STA_SUPPORT ++#ifdef QOS_DLS_SUPPORT ++void DlsStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID RTMPCheckDLSTimeOut( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPRcvFrameDLSCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN ULONG Len, ++ IN PRT28XX_RXD_STRUC pRxD); ++ ++INT RTMPCheckDLSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++NDIS_STATUS RTMPSendSTAKeyRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++NDIS_STATUS RTMPSendSTAKeyHandShake( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++VOID DlsTimeoutAction( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN MlmeDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PRT_802_11_DLS *pDLS, ++ OUT PUSHORT pReason); ++ ++INT Set_DlsEntryInfo_Display_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++MAC_TABLE_ENTRY *MacTableInsertDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UINT DlsEntryIdx); ++ ++BOOLEAN MacTableDeleteDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr); ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount); ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR wcid, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount); ++ ++INT Set_DlsAddEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_DlsTearDownEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // QOS_DLS_SUPPORT // ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef QOS_DLS_SUPPORT ++BOOLEAN PeerDlsReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pDlsTimeout, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDlsRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT UCHAR *pRatesLen, ++ OUT UCHAR Rates[], ++ OUT UCHAR *pHtCapabilityLen, ++ OUT HT_CAPABILITY_IE *pHtCapability); ++ ++BOOLEAN PeerDlsTearDownSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pDA, ++ OUT PUCHAR pSA, ++ OUT USHORT *pReason); ++#endif // QOS_DLS_SUPPORT // ++ ++//======================================== ++ ++VOID SyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID BeaconTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID ScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenJoin( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID InvalidStateWhenStart( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID EnqueueProbeRequest( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN ScanRunning( ++ IN PRTMP_ADAPTER pAd); ++//========================================= ++ ++VOID MlmeCntlInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID MlmeCntlMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlIdleProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlOidScanProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlOidSsidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlOidRTBssidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlMlmeRoamingProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem); ++ ++VOID CntlWaitDisassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitJoinProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitReassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitStartProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAuthProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAuthProc2( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CntlWaitAssocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++#ifdef QOS_DLS_SUPPORT ++VOID CntlOidDLSSetupProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++#endif // QOS_DLS_SUPPORT // ++ ++VOID LinkUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssType); ++ ++VOID LinkDown( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN IsReqFromAP); ++ ++VOID IterateOnBssTab( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID IterateOnBssTab2( ++ IN PRTMP_ADAPTER pAd);; ++ ++VOID JoinParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, ++ IN ULONG BssIdx); ++ ++VOID AssocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_ASSOC_REQ_STRUCT *AssocReq, ++ IN PUCHAR pAddr, ++ IN USHORT CapabilityInfo, ++ IN ULONG Timeout, ++ IN USHORT ListenIntv); ++ ++VOID ScanParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN UCHAR ScanType); ++ ++VOID DisassocParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DISASSOC_REQ_STRUCT *DisassocReq, ++ IN PUCHAR pAddr, ++ IN USHORT Reason); ++ ++VOID StartParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_START_REQ_STRUCT *StartReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen); ++ ++VOID AuthParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, ++ IN PUCHAR pAddr, ++ IN USHORT Alg); ++ ++VOID EnqueuePsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EnqueueBeaconFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeJoinReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID MlmeStartReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID BeaconTimeoutAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeaconAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ScanNextChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++ULONG MakeIbssBeacon( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID CCXAdjacentAPReport( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeScanReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT UCHAR *BssType, ++ OUT CHAR ssid[], ++ OUT UCHAR *SsidLen, ++ OUT UCHAR *ScanType); ++ ++BOOLEAN PeerBeaconAndProbeRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgChannel, ++ OUT PUCHAR pAddr2, ++ OUT PUCHAR pBssid, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen, ++ OUT UCHAR *pBssType, ++ OUT USHORT *pBeaconPeriod, ++ OUT UCHAR *pChannel, ++ OUT UCHAR *pNewChannel, ++ OUT LARGE_INTEGER *pTimestamp, ++ OUT CF_PARM *pCfParm, ++ OUT USHORT *pAtimWin, ++ OUT USHORT *pCapabilityInfo, ++ OUT UCHAR *pErp, ++ OUT UCHAR *pDtimCount, ++ OUT UCHAR *pDtimPeriod, ++ OUT UCHAR *pBcastFlag, ++ OUT UCHAR *pMessageToMe, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT UCHAR *pCkipFlag, ++ OUT UCHAR *pAironetCellPowerLimit, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT PQBSS_LOAD_PARM pQbssLoad, ++ OUT PQOS_CAPABILITY_PARM pQosCapability, ++ OUT ULONG *pRalinkIe, ++ OUT UCHAR *pHtCapabilityLen, ++#ifdef CONFIG_STA_SUPPORT ++ OUT UCHAR *pPreNHtCapabilityLen, ++#endif // CONFIG_STA_SUPPORT // ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT UCHAR *AddHtInfoLen, ++ OUT ADD_HT_INFO_IE *AddHtInfo, ++ OUT UCHAR *NewExtChannel, ++ OUT USHORT *LengthVIE, ++ OUT PNDIS_802_11_VARIABLE_IEs pVIE); ++ ++BOOLEAN PeerAddBAReqActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2); ++ ++BOOLEAN PeerAddBARspActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen); ++ ++BOOLEAN PeerDelBAActionSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN VOID *pMsg, ++ IN ULONG MsgLen); ++ ++BOOLEAN MlmeAssocReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pApAddr, ++ OUT USHORT *CapabilityInfo, ++ OUT ULONG *Timeout, ++ OUT USHORT *ListenIntv); ++ ++BOOLEAN MlmeAuthReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT ULONG *Timeout, ++ OUT USHORT *Alg); ++ ++BOOLEAN MlmeStartReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT CHAR Ssid[], ++ OUT UCHAR *Ssidlen); ++ ++BOOLEAN PeerAuthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr, ++ OUT USHORT *Alg, ++ OUT USHORT *Seq, ++ OUT USHORT *Status, ++ OUT CHAR ChlgText[]); ++ ++BOOLEAN PeerAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT USHORT *pAid, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ OUT UCHAR *pHtCapabilityLen, ++ OUT UCHAR *pAddHtInfoLen, ++ OUT UCHAR *pNewExtChannelOffset, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT UCHAR *pCkipFlag); ++ ++BOOLEAN PeerDisassocSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerWpaMessageSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN PEAPOL_PACKET pMsg, ++ IN ULONG MsgLen, ++ IN UCHAR MsgType, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN PeerDeauthSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *Reason); ++ ++BOOLEAN PeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen); ++ ++BOOLEAN GetTimBit( ++ IN CHAR *Ptr, ++ IN USHORT Aid, ++ OUT UCHAR *TimLen, ++ OUT UCHAR *BcastFlag, ++ OUT UCHAR *DtimCount, ++ OUT UCHAR *DtimPeriod, ++ OUT UCHAR *MessageToMe); ++ ++UCHAR ChannelSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel); ++ ++NDIS_802_11_NETWORK_TYPE NetworkTypeInUseSanity( ++ IN PBSS_ENTRY pBss); ++ ++BOOLEAN MlmeDelBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen); ++ ++BOOLEAN MlmeAddBAReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2); ++ ++ULONG MakeOutgoingFrame( ++ OUT CHAR *Buffer, ++ OUT ULONG *Length, ...); ++ ++VOID LfsrInit( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Seed); ++ ++UCHAR RandomByte( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicUpdateAutoFallBackTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pTxRate); ++ ++VOID MlmePeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LinkDownExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID LinkUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID STAMlmePeriodicExec( ++ PRTMP_ADAPTER pAd); ++ ++VOID MlmeAutoScan( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeAutoReconnectLastSSID( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN MlmeValidateSSID( ++ IN PUCHAR pSsid, ++ IN UCHAR SsidLen); ++ ++VOID MlmeCheckForRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32); ++ ++VOID MlmeCheckForFastRoaming( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now); ++ ++VOID MlmeDynamicTxRateSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeSetTxRate( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PRTMP_TX_RATE_SWITCH pTxRate); ++ ++VOID MlmeSelectTxRateTable( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR *ppTable, ++ IN PUCHAR pTableSize, ++ IN PUCHAR pInitTxRateIdx); ++ ++VOID MlmeCalculateChannelQuality( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now); ++ ++VOID MlmeCheckPsmChange( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Now32); ++ ++VOID MlmeSetPsmBit( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm); ++ ++VOID MlmeSetTxPreamble( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TxPreamble); ++ ++VOID UpdateBasicRateBitmap( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeUpdateTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bLinkUp, ++ IN UCHAR apidx); ++ ++#ifdef DOT11_N_SUPPORT ++VOID MlmeUpdateHtTxRates( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx); ++#endif // DOT11_N_SUPPORT // ++ ++VOID RTMPCheckRates( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT UCHAR SupRate[], ++ IN OUT UCHAR *SupRateLen); ++ ++#ifdef CONFIG_STA_SUPPORT ++BOOLEAN RTMPCheckChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR CentralChannel, ++ IN UCHAR Channel); ++#endif // CONFIG_STA_SUPPORT // ++ ++BOOLEAN RTMPCheckHt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN OUT HT_CAPABILITY_IE *pHtCapability, ++ IN OUT ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID StaQuickResponeForRateUpExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID AsicBbpTuning1( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicBbpTuning2( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPUpdateMlmeRate( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR RTMPMaxRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi0, ++ IN CHAR Rssi1, ++ IN CHAR Rssi2); ++ ++VOID AsicSetRxAnt( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Ant); ++ ++VOID AsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicRxAntEvalTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID APSDPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++ ++UCHAR RTMPStaFixedTxMode( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry); ++ ++VOID RTMPUpdateLegacyTxSetting( ++ UCHAR fixed_tx_mode, ++ PMAC_TABLE_ENTRY pEntry); ++ ++BOOLEAN RTMPAutoRateSwitchCheck( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS MlmeInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeHandler( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeHalt( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeResetRalinkCounters( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BuildChannelList( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR FirstChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR NextChannel( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR channel); ++ ++VOID ChangeToCellPowerLimit( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR AironetCellPowerLimit); ++ ++VOID RaiseClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x); ++ ++VOID LowerClock( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 *x); ++ ++USHORT ShiftInBits( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ShiftOutBits( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT data, ++ IN USHORT count); ++ ++VOID EEpromCleanup( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EWDS( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID EWEN( ++ IN PRTMP_ADAPTER pAd); ++ ++USHORT RTMP_EEPROM_READ16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset); ++ ++VOID RTMP_EEPROM_WRITE16( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Data); ++ ++// ++// Prototypes of function definition in rtmp_tkip.c ++// ++VOID RTMPInitTkipEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pTKey, ++ IN UCHAR KeyId, ++ IN PUCHAR pTA, ++ IN PUCHAR pMICKey, ++ IN PUCHAR pTSC, ++ OUT PULONG pIV16, ++ OUT PULONG pIV32); ++ ++VOID RTMPInitMICEngine( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKey, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN UCHAR UserPriority, ++ IN PUCHAR pMICKey); ++ ++BOOLEAN RTMPTkipCompareMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UCHAR UserPriority, ++ IN UINT Len); ++ ++VOID RTMPCalculateMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pEncap, ++ IN PCIPHER_KEY pKey, ++ IN UCHAR apidx); ++ ++BOOLEAN RTMPTkipCompareMICValueWithLLC( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pLLC, ++ IN PUCHAR pSrc, ++ IN PUCHAR pDA, ++ IN PUCHAR pSA, ++ IN PUCHAR pMICKey, ++ IN UINT Len); ++ ++VOID RTMPTkipAppendByte( ++ IN PTKIP_KEY_INFO pTkip, ++ IN UCHAR uChar); ++ ++VOID RTMPTkipAppend( ++ IN PTKIP_KEY_INFO pTkip, ++ IN PUCHAR pSrc, ++ IN UINT nBytes); ++ ++VOID RTMPTkipGetMIC( ++ IN PTKIP_KEY_INFO pTkip); ++ ++BOOLEAN RTMPSoftDecryptTKIP( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN UCHAR UserPriority, ++ IN PCIPHER_KEY pWpaKey); ++ ++BOOLEAN RTMPSoftDecryptAES( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataByteCnt, ++ IN PCIPHER_KEY pWpaKey); ++ ++// ++// Prototypes of function definition in cmm_info.c ++// ++NDIS_STATUS RTMPWPARemoveKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++VOID RTMPWPARemoveAllKeys( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN RTMPCheckStrPrintAble( ++ IN CHAR *pInPutStr, ++ IN UCHAR strLen); ++ ++VOID RTMPSetPhyMode( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG phymode); ++ ++VOID RTMPUpdateHTIE( ++ IN RT_HT_CAPABILITY *pRtHt, ++ IN UCHAR *pMcsSet, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo); ++ ++VOID RTMPAddWcidAttributeEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssIdx, ++ IN UCHAR KeyIdx, ++ IN UCHAR CipherAlg, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++CHAR *GetEncryptType( ++ CHAR enc); ++ ++CHAR *GetAuthMode( ++ CHAR auth); ++ ++VOID RTMPIoctlGetSiteSurvey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlGetMacTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIndicateWPA2Status( ++ IN PRTMP_ADAPTER pAdapter); ++ ++VOID RTMPOPModeSwitching( ++ IN PRTMP_ADAPTER pAd); ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID RTMPAddBSSIDCipher( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Aid, ++ IN PNDIS_802_11_KEY pKey, ++ IN UCHAR CipherAlg); ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++VOID RTMPSetHT( ++ IN PRTMP_ADAPTER pAd, ++ IN OID_SET_HT_PHYMODE *pHTPhyMode); ++ ++VOID RTMPSetIndividualHT( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR apidx); ++#endif // DOT11_N_SUPPORT // ++ ++VOID RTMPSendWirelessEvent( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Event_flag, ++ IN PUCHAR pAddr, ++ IN UCHAR BssIdx, ++ IN CHAR Rssi); ++ ++VOID NICUpdateCntlCounters( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN UCHAR SubType, ++ IN PRXWI_STRUC pRxWI); ++// ++// prototype in wpa.c ++// ++BOOLEAN WpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType); ++ ++VOID WpaPskStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID WpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaPairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaPairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaGroupMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID WpaMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr1); ++ ++VOID Wpa2PairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID Wpa2PairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++BOOLEAN ParseKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR bPairewise); ++ ++VOID RTMPToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN is4wayFrame); ++ ++VOID HMAC_SHA1( ++ IN UCHAR *text, ++ IN UINT text_len, ++ IN UCHAR *key, ++ IN UINT key_len, ++ IN UCHAR *digest); ++ ++VOID PRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *prefix, ++ IN INT prefix_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len); ++ ++VOID CCKMPRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len); ++ ++VOID WpaCountPTK( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *PMK, ++ IN UCHAR *ANonce, ++ IN UCHAR *AA, ++ IN UCHAR *SNonce, ++ IN UCHAR *SA, ++ OUT UCHAR *output, ++ IN UINT len); ++ ++VOID GenRandom( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR *macAddr, ++ OUT UCHAR *random); ++ ++// ++// prototype in aironet.c ++// ++VOID AironetStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]); ++ ++VOID AironetMsgAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID AironetRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ChannelLoadRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID NoiseHistRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID BeaconRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID ChannelLoadReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID NoiseHistReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetFinalReportAction( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID BeaconReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID AironetAddBeaconReport( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Index, ++ IN PMLME_QUEUE_ELEM pElem); ++ ++VOID AironetCreateBeaconReportFromBssTable( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID DBGPRINT_TX_RING( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx); ++ ++VOID DBGPRINT_RX_RING( ++ IN PRTMP_ADAPTER pAd); ++ ++CHAR ConvertToRssi( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR Rssi, ++ IN UCHAR RssiNumber); ++ ++ ++#ifdef DOT11N_DRAFT3 ++VOID BuildEffectedChannelList( ++ IN PRTMP_ADAPTER pAd); ++#endif // DOT11N_DRAFT3 // ++ ++ ++VOID APAsicEvaluateRxAnt( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++VOID APAsicRxAntEvalTimeout( ++ IN PRTMP_ADAPTER pAd); ++ ++// ++// function prototype in cmm_wpa.c ++// ++BOOLEAN RTMPCheckWPAframe( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN PUCHAR pData, ++ IN ULONG DataByteCount, ++ IN UCHAR FromWhichBSSID); ++ ++VOID AES_GTK_KEY_UNWRAP( ++ IN UCHAR *key, ++ OUT UCHAR *plaintext, ++ IN UCHAR c_len, ++ IN UCHAR *ciphertext); ++ ++BOOLEAN RTMPCheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ IN MAC_TABLE_ENTRY *pEntry, ++ OUT UCHAR *Offset); ++ ++BOOLEAN RTMPParseEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR GroupKeyIndex, ++ IN UCHAR MsgType, ++ IN BOOLEAN bWPA2, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID ConstructEapolMsg( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerAuthMode, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR MyGroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN UCHAR *ReplayCounter, ++ IN UCHAR *KeyNonce, ++ IN UCHAR *TxRSC, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_Len, ++ OUT PEAPOL_PACKET pMsg); ++ ++VOID CalculateMIC( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR *PTK, ++ OUT PEAPOL_PACKET pMsg); ++ ++NDIS_STATUS RTMPSoftDecryptBroadCastData( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN NDIS_802_11_ENCRYPTION_STATUS GroupCipher, ++ IN PCIPHER_KEY pShard_key); ++ ++VOID ConstructEapolKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR PeerAuthMode, ++ IN UCHAR PeerWepStatus, ++ IN UCHAR GroupKeyWepStatus, ++ IN UCHAR MsgType, ++ IN UCHAR DefaultKeyIdx, ++ IN BOOLEAN bWPA2Capable, ++ IN UCHAR *PTK, ++ IN UCHAR *GTK, ++ IN UCHAR *RSNIE, ++ IN UCHAR RSNIE_LEN, ++ OUT PEAPOL_PACKET pMsg); ++ ++VOID RTMPMakeRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT AuthMode, ++ IN UINT WepStatus, ++ IN UCHAR apidx); ++ ++// ++// function prototype in ap_wpa.c ++// ++ ++BOOLEAN APWpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType) ; ++ ++MAC_TABLE_ENTRY *PACInquiry( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Wcid); ++ ++BOOLEAN RTMPCheckMcast( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN RTMPCheckUcast( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++BOOLEAN RTMPCheckAUTH( ++ IN PRTMP_ADAPTER pAd, ++ IN PEID_STRUCT eid_ptr, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID WPAStart4WayHS( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN ULONG TimeInterval); ++ ++VOID WPAStart2WayGroupHS( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID APWpaEAPPacketAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLStartAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLLogoffAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID APWpaEAPOLASFAlertAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID HandleCounterMeasure( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++VOID PeerPairMsg2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerPairMsg4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID CMTimerExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID WPARetryExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID EnqueueStartForPSKExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID RTMPHandleSTAKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++VOID PeerGroupMsg2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN VOID *Msg, ++ IN UINT MsgLen); ++ ++VOID PairDisAssocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN USHORT Reason); ++ ++VOID MlmeDeAuthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN USHORT Reason); ++ ++VOID GREKEYPeriodicExec( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3); ++ ++VOID CountGTK( ++ IN UCHAR *PMK, ++ IN UCHAR *GNonce, ++ IN UCHAR *AA, ++ OUT UCHAR *output, ++ IN UINT len); ++ ++VOID GetSmall( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ OUT PUCHAR out, ++ IN ULONG Length); ++ ++VOID GetLarge( ++ IN PVOID pSrc1, ++ IN PVOID pSrc2, ++ OUT PUCHAR out, ++ IN ULONG Length); ++ ++VOID APGenRandom( ++ IN PRTMP_ADAPTER pAd, ++ OUT UCHAR *random); ++ ++VOID AES_GTK_KEY_WRAP( ++ IN UCHAR *key, ++ IN UCHAR *plaintext, ++ IN UCHAR p_len, ++ OUT UCHAR *ciphertext); ++ ++VOID WpaSend( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR pPacket, ++ IN ULONG Len); ++ ++VOID APToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN bClearFrame); ++ ++VOID RTMPAddPMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN PUCHAR pAddr, ++ IN UCHAR *PMKID, ++ IN UCHAR *PMK); ++ ++INT RTMPSearchPMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN PUCHAR pAddr); ++ ++VOID RTMPDeletePMKIDCache( ++ IN PRTMP_ADAPTER pAd, ++ IN INT apidx, ++ IN INT idx); ++ ++VOID RTMPMaintainPMKIDCache( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSendTriggerFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuffer, ++ IN ULONG Length, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull); ++ ++#ifdef RT30xx ++VOID RTMPFilterCalibration( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT30xx // ++ ++ ++//typedef void (*TIMER_FUNCTION)(unsigned long); ++ ++ ++/* timeout -- ms */ ++VOID RTMP_SetPeriodicTimer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++VOID RTMP_OS_Init_Timer( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN TIMER_FUNCTION function, ++ IN PVOID data); ++ ++VOID RTMP_OS_Add_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++VOID RTMP_OS_Mod_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ IN unsigned long timeout); ++ ++ ++VOID RTMP_OS_Del_Timer( ++ IN NDIS_MINIPORT_TIMER *pTimer, ++ OUT BOOLEAN *pCancelled); ++ ++ ++VOID RTMP_OS_Release_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PQUEUE_ENTRY pEntry); ++ ++VOID RTMPusecDelay( ++ IN ULONG usec); ++ ++NDIS_STATUS os_alloc_mem( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUCHAR *mem, ++ IN ULONG size); ++ ++NDIS_STATUS os_free_mem( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR mem); ++ ++ ++void RTMP_AllocateSharedMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++VOID RTMPFreeTxRxRingMemory( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS AdapterBlockAllocateMemory( ++ IN PVOID handle, ++ OUT PVOID *ppAd); ++ ++void RTMP_AllocateTxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateFirstTxBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT Index, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateMgmtDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++void RTMP_AllocateRxDescMemory( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++PNDIS_PACKET RTMP_AllocateRxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress, ++ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress); ++ ++PNDIS_PACKET RTMP_AllocateTxPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length, ++ IN BOOLEAN Cached, ++ OUT PVOID *VirtualAddress); ++ ++PNDIS_PACKET RTMP_AllocateFragPacketBuffer( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Length); ++ ++void RTMP_QueryPacketInfo( ++ IN PNDIS_PACKET pPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen); ++ ++void RTMP_QueryNextPacketInfo( ++ IN PNDIS_PACKET *ppPacket, ++ OUT PACKET_INFO *pPacketInfo, ++ OUT PUCHAR *pSrcBufVA, ++ OUT UINT *pSrcBufLen); ++ ++ ++BOOLEAN RTMP_FillTxBlkInfo( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk); ++ ++ ++PRTMP_SCATTER_GATHER_LIST ++rt_get_sg_list_from_packet(PNDIS_PACKET pPacket, RTMP_SCATTER_GATHER_LIST *sg); ++ ++ ++ void announce_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++UINT BA_Reorder_AMSDU_Annnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket); ++ ++ ++UINT Handle_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++void convert_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR p8023hdr, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNET_DEV get_netdev_from_bssid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET duplicate_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET duplicate_pkt_with_TKIP_MIC( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pOldPkt); ++ ++PNDIS_PACKET duplicate_pkt_with_VLAN( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ IN UCHAR FromWhichBSSID); ++ ++PNDIS_PACKET duplicate_pkt_with_WPI( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UINT32 ext_head_len, ++ IN UINT32 ext_tail_len); ++ ++UCHAR VLAN_8023_Header_Copy( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ OUT PUCHAR pData, ++ IN UCHAR FromWhichBSSID); ++ ++#ifdef DOT11_N_SUPPORT ++void ba_flush_reordering_timeout_mpdus( ++ IN PRTMP_ADAPTER pAd, ++ IN PBA_REC_ENTRY pBAEntry, ++ IN ULONG Now32); ++ ++ ++VOID BAOriSessionSetUp( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN UCHAR TID, ++ IN USHORT TimeOut, ++ IN ULONG DelayTime, ++ IN BOOLEAN isForced); ++ ++VOID BASessionTearDownALL( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid); ++#endif // DOT11_N_SUPPORT // ++ ++BOOLEAN OS_Need_Clone_Packet(void); ++ ++ ++VOID build_tx_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pFrame, ++ IN ULONG FrameLen); ++ ++ ++VOID BAOriSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive, ++ IN BOOLEAN bForceSend); ++ ++VOID BARecSessionTearDown( ++ IN OUT PRTMP_ADAPTER pAd, ++ IN UCHAR Wcid, ++ IN UCHAR TID, ++ IN BOOLEAN bPassive); ++ ++BOOLEAN ba_reordering_resource_init(PRTMP_ADAPTER pAd, int num); ++void ba_reordering_resource_release(PRTMP_ADAPTER pAd); ++ ++ULONG AutoChBssInsertEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pBssid, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR ChannelNo, ++ IN CHAR Rssi); ++ ++void AutoChBssTableInit( ++ IN PRTMP_ADAPTER pAd); ++ ++void ChannelInfoInit( ++ IN PRTMP_ADAPTER pAd); ++ ++void AutoChBssTableDestroy( ++ IN PRTMP_ADAPTER pAd); ++ ++void ChannelInfoDestroy( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR New_ApAutoSelectChannel( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++#ifdef NINTENDO_AP ++VOID InitNINTENDO_TABLE( ++ IN PRTMP_ADAPTER pAd); ++ ++UCHAR CheckNINTENDO_TABLE( ++ IN PRTMP_ADAPTER pAd, ++ PCHAR pDS_Ssid, ++ UCHAR DS_SsidLen, ++ PUCHAR pDS_Addr); ++ ++UCHAR DelNINTENDO_ENTRY( ++ IN PRTMP_ADAPTER pAd, ++ UCHAR * pDS_Addr); ++ ++VOID RTMPIoctlNintendoCapable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlNintendoGetTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlNintendoSetTable( ++ IN PRTMP_ADAPTER pAd, ++ IN struct iwreq *wrq); ++ ++#endif // NINTENDO_AP // ++ ++BOOLEAN rtstrmactohex( ++ IN char *s1, ++ IN char *s2); ++ ++BOOLEAN rtstrcasecmp( ++ IN char *s1, ++ IN char *s2); ++ ++char *rtstrstruncasecmp( ++ IN char *s1, ++ IN char *s2); ++ ++char *rtstrstr( ++ IN const char * s1, ++ IN const char * s2); ++ ++char *rstrtok( ++ IN char * s, ++ IN const char * ct); ++ ++int rtinet_aton( ++ const char *cp, ++ unsigned int *addr); ++ ++////////// common ioctl functions ////////// ++INT Set_DriverVersion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_CountryRegion_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_CountryRegionABand_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_WirelessMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_Channel_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ShortSlot_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxPower_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BGProtection_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxPreamble_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_RTSThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_FragThreshold_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TxBurst_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef AGGREGATION_SUPPORT ++INT Set_PktAggregate_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_IEEE80211H_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef DBG ++INT Set_Debug_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Show_DescInfo_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ResetStatCounter_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_BASetup_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BADecline_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BAOriTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_BARecTearDown_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtBw_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMcs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtGi_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtOpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtStbc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtHtc_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtExtcha_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMpduDensity_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtBaWinSize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtRdg_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtLinkAdapt_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtAmsdu_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtAutoBa_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtProtect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMimoPs_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_ForceShortGI_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_ForceGF_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT SetCommonHT( ++ IN PRTMP_ADAPTER pAd); ++ ++INT Set_SendPSMPAction_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_HtMIMOPSmode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++ ++INT Set_HtTxBASize_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++//Dls , kathy ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA); ++ ++#ifdef DOT11_N_SUPPORT ++//Block ACK ++VOID QueryBATABLE( ++ IN PRTMP_ADAPTER pAd, ++ OUT PQUERYBA_TABLE pBAT); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT WpaCheckEapCode( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFrame, ++ IN USHORT FrameLen, ++ IN USHORT OffSet); ++ ++VOID WpaSendMicFailureToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUnicast); ++ ++VOID SendAssocIEsToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++int wext_notify_event_assoc( ++ IN RTMP_ADAPTER *pAd); ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ ++#ifdef DOT11_N_SUPPORT ++VOID Handle_BSS_Width_Trigger_Events( ++ IN PRTMP_ADAPTER pAd); ++ ++void build_ext_channel_switch_ie( ++ IN PRTMP_ADAPTER pAd, ++ IN HT_EXT_CHANNEL_SWITCH_ANNOUNCEMENT_IE *pIE); ++#endif // DOT11_N_SUPPORT // ++ ++ ++BOOLEAN APRxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN STARxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN argc); ++ ++#ifdef DOT11_N_SUPPORT ++// AMPDU packet indication ++VOID Indicate_AMPDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++// AMSDU packet indication ++VOID Indicate_AMSDU_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++#endif // DOT11_N_SUPPORT // ++ ++// Normal legacy Rx packet indication ++VOID Indicate_Legacy_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Indicate_EAPOL_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++void update_os_packet_info( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++void wlan_802_11_to_802_3_packet( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN PUCHAR pHeader802_3, ++ IN UCHAR FromWhichBSSID); ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++// remove LLC and get 802_3 Header ++#define RTMP_802_11_REMOVE_LLC_AND_CONVERT_TO_802_3(_pRxBlk, _pHeader802_3) \ ++{ \ ++ PUCHAR _pRemovedLLCSNAP = NULL, _pDA, _pSA; \ ++ \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_MESH)) \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr3; \ ++ _pSA = (PUCHAR)_pRxBlk->pHeader + sizeof(HEADER_802_11); \ ++ } \ ++ else \ ++ { \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_INFRA)) \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr1; \ ++ if (RX_BLK_TEST_FLAG(_pRxBlk, fRX_DLS)) \ ++ _pSA = _pRxBlk->pHeader->Addr2; \ ++ else \ ++ _pSA = _pRxBlk->pHeader->Addr3; \ ++ } \ ++ else \ ++ { \ ++ _pDA = _pRxBlk->pHeader->Addr1; \ ++ _pSA = _pRxBlk->pHeader->Addr2; \ ++ } \ ++ } \ ++ \ ++ CONVERT_TO_802_3(_pHeader802_3, _pDA, _pSA, _pRxBlk->pData, \ ++ _pRxBlk->DataSize, _pRemovedLLCSNAP); \ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++BOOLEAN APFowardWirelessStaToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN ULONG FromWhichBSSID); ++ ++VOID Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Sta_Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++#define ANNOUNCE_OR_FORWARD_802_3_PACKET(_pAd, _pPacket, _FromWhichBSS)\ ++ Sta_Announce_or_Forward_802_3_Packet(_pAd, _pPacket, _FromWhichBSS); ++ //announce_802_3_packet(_pAd, _pPacket); ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++PNDIS_PACKET DuplicatePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID); ++ ++ ++PNDIS_PACKET ClonePacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++ ++// Normal, AMPDU or AMSDU ++VOID CmmRxnonRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID CmmRxRalinkFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID); ++ ++VOID Update_Rssi_Sample( ++ IN PRTMP_ADAPTER pAd, ++ IN RSSI_SAMPLE *pRssi, ++ IN PRXWI_STRUC pRxWI); ++ ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending); ++ ++PNDIS_PACKET RTMPDeFragmentDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk); ++ ++//////////////////////////////////////// ++ ++ ++ ++ ++ ++#ifdef SNMP_SUPPORT ++//for snmp , kathy ++typedef struct _DefaultKeyIdxValue ++{ ++ UCHAR KeyIdx; ++ UCHAR Value[16]; ++} DefaultKeyIdxValue, *PDefaultKeyIdxValue; ++#endif ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++enum { ++ DIDmsg_lnxind_wlansniffrm = 0x00000044, ++ DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, ++ DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, ++ DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, ++ DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, ++ DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, ++ DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, ++ DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, ++ DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, ++ DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, ++ DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 ++}; ++enum { ++ P80211ENUM_msgitem_status_no_value = 0x00 ++}; ++enum { ++ P80211ENUM_truth_false = 0x00, ++ P80211ENUM_truth_true = 0x01 ++}; ++ ++/* Definition from madwifi */ ++typedef struct { ++ UINT32 did; ++ UINT16 status; ++ UINT16 len; ++ UINT32 data; ++} p80211item_uint32_t; ++ ++typedef struct { ++ UINT32 msgcode; ++ UINT32 msglen; ++#define WLAN_DEVNAMELEN_MAX 16 ++ UINT8 devname[WLAN_DEVNAMELEN_MAX]; ++ p80211item_uint32_t hosttime; ++ p80211item_uint32_t mactime; ++ p80211item_uint32_t channel; ++ p80211item_uint32_t rssi; ++ p80211item_uint32_t sq; ++ p80211item_uint32_t signal; ++ p80211item_uint32_t noise; ++ p80211item_uint32_t rate; ++ p80211item_uint32_t istx; ++ p80211item_uint32_t frmlen; ++} wlan_ng_prism2_header; ++ ++/* The radio capture header precedes the 802.11 header. */ ++typedef struct PACKED _ieee80211_radiotap_header { ++ UINT8 it_version; /* Version 0. Only increases ++ * for drastic changes, ++ * introduction of compatible ++ * new fields does not count. ++ */ ++ UINT8 it_pad; ++ UINT16 it_len; /* length of the whole ++ * header in bytes, including ++ * it_version, it_pad, ++ * it_len, and data fields. ++ */ ++ UINT32 it_present; /* A bitmap telling which ++ * fields are present. Set bit 31 ++ * (0x80000000) to extend the ++ * bitmap by another 32 bits. ++ * Additional extensions are made ++ * by setting bit 31. ++ */ ++}ieee80211_radiotap_header ; ++ ++enum ieee80211_radiotap_type { ++ IEEE80211_RADIOTAP_TSFT = 0, ++ IEEE80211_RADIOTAP_FLAGS = 1, ++ IEEE80211_RADIOTAP_RATE = 2, ++ IEEE80211_RADIOTAP_CHANNEL = 3, ++ IEEE80211_RADIOTAP_FHSS = 4, ++ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, ++ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, ++ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, ++ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, ++ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, ++ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, ++ IEEE80211_RADIOTAP_ANTENNA = 11, ++ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, ++ IEEE80211_RADIOTAP_DB_ANTNOISE = 13 ++}; ++ ++#define WLAN_RADIOTAP_PRESENT ( \ ++ (1 << IEEE80211_RADIOTAP_TSFT) | \ ++ (1 << IEEE80211_RADIOTAP_FLAGS) | \ ++ (1 << IEEE80211_RADIOTAP_RATE) | \ ++ 0) ++ ++typedef struct _wlan_radiotap_header { ++ ieee80211_radiotap_header wt_ihdr; ++ INT64 wt_tsft; ++ UINT8 wt_flags; ++ UINT8 wt_rate; ++} wlan_radiotap_header; ++/* Definition from madwifi */ ++ ++void send_monitor_packets( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk); ++ ++#if WIRELESS_EXT >= 12 ++// This function will be called when query /proc ++struct iw_statistics *rt28xx_get_wireless_stats( ++ IN struct net_device *net_dev); ++#endif ++ ++VOID RTMPSetDesiredRates( ++ IN PRTMP_ADAPTER pAdapter, ++ IN LONG Rates); ++#endif // CONFIG_STA_SUPPORT // ++ ++INT Set_FixedTxMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++INT Set_OpMode_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ ++static inline char* GetPhyMode( ++ int Mode) ++{ ++ switch(Mode) ++ { ++ case MODE_CCK: ++ return "CCK"; ++ ++ case MODE_OFDM: ++ return "OFDM"; ++#ifdef DOT11_N_SUPPORT ++ case MODE_HTMIX: ++ return "HTMIX"; ++ ++ case MODE_HTGREENFIELD: ++ return "GREEN"; ++#endif // DOT11_N_SUPPORT // ++ default: ++ return "N/A"; ++ } ++} ++ ++ ++static inline char* GetBW( ++ int BW) ++{ ++ switch(BW) ++ { ++ case BW_10: ++ return "10M"; ++ ++ case BW_20: ++ return "20M"; ++#ifdef DOT11_N_SUPPORT ++ case BW_40: ++ return "40M"; ++#endif // DOT11_N_SUPPORT // ++ default: ++ return "N/A"; ++ } ++} ++ ++ ++VOID RT28xxThreadTerminate( ++ IN RTMP_ADAPTER *pAd); ++ ++BOOLEAN RT28XXChipsetCheck( ++ IN void *_dev_p); ++ ++BOOLEAN RT28XXNetDevInit( ++ IN void *_dev_p, ++ IN struct net_device *net_dev, ++ IN RTMP_ADAPTER *pAd); ++ ++BOOLEAN RT28XXProbePostConfig( ++ IN void *_dev_p, ++ IN RTMP_ADAPTER *pAd, ++ IN INT32 argc); ++ ++VOID RT28XXDMADisable( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT28XXDMAEnable( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT28xx_UpdateBeaconToAsic( ++ IN RTMP_ADAPTER * pAd, ++ IN INT apidx, ++ IN ULONG BeaconLen, ++ IN ULONG UpdatePos); ++ ++INT rt28xx_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd); ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd); ++#endif // CONFIG_STA_SUPPORT // ++ ++BOOLEAN RT28XXSecurityKeyAdd( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG apidx, ++ IN ULONG KeyIdx, ++ IN MAC_TABLE_ENTRY *pEntry); ++ ++//////////////////////////////////////// ++PNDIS_PACKET GetPacketFromRxRing( ++ IN PRTMP_ADAPTER pAd, ++ OUT PRT28XX_RXD_STRUC pSaveRxD, ++ OUT BOOLEAN *pbReschedule, ++ IN OUT UINT32 *pRxPending); ++ ++ ++void kill_thread_task(PRTMP_ADAPTER pAd); ++ ++void tbtt_tasklet(unsigned long data); ++ ++ ++VOID AsicTurnOffRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++VOID AsicTurnOnRFClk( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Channel); ++ ++#ifdef RT30xx ++NTSTATUS RT30xxWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN UCHAR Value); ++ ++NTSTATUS RT30xxReadRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR RegID, ++ IN PUCHAR pValue); ++ ++//2008/09/11:KH add to support efuse<-- ++UCHAR eFuseReadRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ OUT USHORT* pData); ++ ++VOID eFuseReadPhysical( ++ IN PRTMP_ADAPTER pAd, ++ IN PUSHORT lpInBuffer, ++ IN ULONG nInBufferSize, ++ OUT PUSHORT lpOutBuffer, ++ IN ULONG nOutBufferSize ++); ++ ++NTSTATUS eFuseRead( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT Length); ++ ++VOID eFusePhysicalWriteRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ OUT USHORT* pData); ++ ++NTSTATUS eFuseWriteRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ IN USHORT* pData); ++ ++VOID eFuseWritePhysical( ++ IN PRTMP_ADAPTER pAd, ++ PUSHORT lpInBuffer, ++ ULONG nInBufferSize, ++ PUCHAR lpOutBuffer, ++ ULONG nOutBufferSize ++); ++ ++NTSTATUS eFuseWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length); ++ ++INT set_eFuseGetFreeBlockCount_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT set_eFusedump_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT set_eFuseLoadFromBin_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++NTSTATUS eFuseWriteRegistersFromBin( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ IN USHORT* pData); ++ ++VOID eFusePhysicalReadRegisters( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN USHORT Length, ++ OUT USHORT* pData); ++ ++NDIS_STATUS NICLoadEEPROM( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN bNeedLoadEEPROM( ++ IN PRTMP_ADAPTER pAd); ++//2008/09/11:KH add to support efuse--> ++#endif // RT30xx // ++ ++#ifdef RT30xx ++// add by johnli, RF power sequence setup ++VOID RT30xxLoadRFNormalModeSetup( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RT30xxLoadRFSleepModeSetup( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RT30xxReverseRFSleepModeSetup( ++ IN PRTMP_ADAPTER pAd); ++// end johnli ++#endif // RT30xx // ++ ++#ifdef RT2870 ++// ++// Function Prototype in rtusb_bulk.c ++// ++VOID RTUSBInitTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PTX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN usb_complete_t Func); ++ ++VOID RTUSBInitHTTxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PHT_TX_CONTEXT pTxContext, ++ IN UCHAR BulkOutPipeId, ++ IN ULONG BulkOutSize, ++ IN usb_complete_t Func); ++ ++VOID RTUSBInitRxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PRX_CONTEXT pRxContext); ++ ++VOID RTUSBCleanUpDataBulkOutQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCancelPendingBulkOutIRP( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkOutDataPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UCHAR Index); ++ ++VOID RTUSBBulkOutNullFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkOutRTSFrame( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCancelPendingBulkInIRP( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCancelPendingIRPs( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkOutMLMEPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index); ++ ++VOID RTUSBBulkOutPsPoll( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBCleanUpMLMEBulkOutQueue( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBKickBulkOut( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBBulkReceive( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID DoBulkIn( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RTUSBInitRxDesc( ++ IN PRTMP_ADAPTER pAd, ++ IN PRX_CONTEXT pRxContext); ++ ++VOID RTUSBBulkRxHandle( ++ IN unsigned long data); ++ ++// ++// Function Prototype in rtusb_io.c ++// ++NTSTATUS RTUSBMultiRead( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length); ++ ++NTSTATUS RTUSBMultiWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length); ++ ++NTSTATUS RTUSBMultiWrite_OneByte( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData); ++ ++NTSTATUS RTUSBReadBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN PUCHAR pValue); ++ ++NTSTATUS RTUSBWriteBBPRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Id, ++ IN UCHAR Value); ++ ++NTSTATUS RTUSBWriteRFRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 Value); ++ ++NTSTATUS RTUSB_VendorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UINT32 TransferFlags, ++ IN UCHAR ReservedBits, ++ IN UCHAR Request, ++ IN USHORT Value, ++ IN USHORT Index, ++ IN PVOID TransferBuffer, ++ IN UINT32 TransferBufferLength); ++ ++NTSTATUS RTUSBReadEEPROM( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUCHAR pData, ++ IN USHORT length); ++ ++NTSTATUS RTUSBWriteEEPROM( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN PUCHAR pData, ++ IN USHORT length); ++ ++VOID RTUSBPutToSleep( ++ IN PRTMP_ADAPTER pAd); ++ ++NTSTATUS RTUSBWakeUp( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTUSBInitializeCmdQ( ++ IN PCmdQ cmdq); ++ ++NDIS_STATUS RTUSBEnqueueCmdFromNdis( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN BOOLEAN SetInformation, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength); ++ ++NDIS_STATUS RTUSBEnqueueInternalCmd( ++ IN PRTMP_ADAPTER pAd, ++ IN NDIS_OID Oid, ++ IN PVOID pInformationBuffer, ++ IN UINT32 InformationBufferLength); ++ ++VOID RTUSBDequeueCmd( ++ IN PCmdQ cmdq, ++ OUT PCmdQElmt *pcmdqelmt); ++ ++INT RTUSBCmdThread( ++ IN OUT PVOID Context); ++ ++INT TimerQThread( ++ IN OUT PVOID Context); ++ ++RT2870_TIMER_ENTRY *RT2870_TimerQ_Insert( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer); ++ ++BOOLEAN RT2870_TimerQ_Remove( ++ IN RTMP_ADAPTER *pAd, ++ IN RALINK_TIMER_STRUCT *pTimer); ++ ++void RT2870_TimerQ_Exit( ++ IN RTMP_ADAPTER *pAd); ++ ++void RT2870_TimerQ_Init( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_BssBeaconExit( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_BssBeaconStop( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_BssBeaconStart( ++ IN RTMP_ADAPTER * pAd); ++ ++VOID RT2870_BssBeaconInit( ++ IN RTMP_ADAPTER *pAd); ++ ++VOID RT2870_WatchDog( ++ IN RTMP_ADAPTER *pAd); ++ ++NTSTATUS RTUSBWriteMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ IN UINT32 Value); ++ ++NTSTATUS RTUSBReadMACRegister( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT Offset, ++ OUT PUINT32 pValue); ++ ++NTSTATUS RTUSBSingleWrite( ++ IN RTMP_ADAPTER *pAd, ++ IN USHORT Offset, ++ IN USHORT Value); ++ ++NTSTATUS RTUSBFirmwareRun( ++ IN PRTMP_ADAPTER pAd); ++ ++NTSTATUS RTUSBFirmwareWrite( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFwImage, ++ IN ULONG FwLen); ++ ++NTSTATUS RTUSBFirmwareOpmode( ++ IN PRTMP_ADAPTER pAd, ++ OUT PUINT32 pValue); ++ ++NTSTATUS RTUSBVenderReset( ++ IN PRTMP_ADAPTER pAd); ++ ++NDIS_STATUS RTUSBSetHardWareRegister( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PVOID pBuf); ++ ++NDIS_STATUS RTUSBQueryHardWareRegister( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PVOID pBuf); ++ ++VOID CMDHandler( ++ IN PRTMP_ADAPTER pAd); ++ ++ ++NDIS_STATUS CreateThreads( ++ IN struct net_device *net_dev ); ++ ++ ++VOID MacTableInitialize( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MlmeSetPsm( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT psm); ++ ++NDIS_STATUS RTMPWPAAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++VOID AsicRxAntEvalAction( ++ IN PRTMP_ADAPTER pAd); ++ ++void append_pkt( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN ULONG DataSize, ++ OUT PNDIS_PACKET *ppPacket); ++ ++UINT deaggregate_AMSDU_announce( ++ IN PRTMP_ADAPTER pAd, ++ PNDIS_PACKET pPacket, ++ IN PUCHAR pData, ++ IN ULONG DataSize); ++ ++NDIS_STATUS RTMPCheckRxError( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN PRXWI_STRUC pRxWI, ++ IN PRT28XX_RXD_STRUC pRxINFO); ++ ++ ++VOID RTUSBMlmeHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN PMGMT_STRUC pMgmt); ++ ++INT MlmeThread( ++ IN PVOID Context); ++ ++// ++// Function Prototype in rtusb_data.c ++// ++NDIS_STATUS RTUSBFreeDescriptorRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BulkOutPipeId, ++ IN UINT32 NumberRequired); ++ ++ ++BOOLEAN RTUSBNeedQueueBackForAgg( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR BulkOutPipeId); ++ ++ ++VOID RTMPWriteTxInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PTXINFO_STRUC pTxInfo, ++ IN USHORT USBDMApktLen, ++ IN BOOLEAN bWiv, ++ IN UCHAR QueueSel, ++ IN UCHAR NextValid, ++ IN UCHAR TxBurst); ++ ++// ++// Function Prototype in cmm_data_2870.c ++// ++USHORT RtmpUSB_WriteSubTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpUSB_WriteSingleTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN BOOLEAN bIsLast, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpUSB_WriteFragTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR fragNum, ++ OUT USHORT *FreeNumber); ++ ++USHORT RtmpUSB_WriteMultiTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR frameNum, ++ OUT USHORT *FreeNumber); ++ ++VOID RtmpUSB_FinalWriteTxResource( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN USHORT totalMPDUSize, ++ IN USHORT TxIdx); ++ ++VOID RtmpUSBDataLastTxIdx( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN USHORT TxIdx); ++ ++VOID RtmpUSBDataKickOut( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx); ++ ++ ++int RtmpUSBMgmtKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN PNDIS_PACKET pPacket, ++ IN PUCHAR pSrcBufVA, ++ IN UINT SrcBufLen); ++ ++VOID RtmpUSBNullFrameKickOut( ++ IN RTMP_ADAPTER *pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR *pNullFrame, ++ IN UINT32 frameLen); ++ ++VOID RT28xxUsbStaAsicForceWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bFromTx); ++ ++VOID RT28xxUsbStaAsicSleepThenAutoWakeup( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT TbttNumToNextWakeUp); ++ ++VOID RT28xxUsbMlmeRadioOn( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RT28xxUsbMlmeRadioOFF( ++ IN PRTMP_ADAPTER pAd); ++#endif // RT2870 // ++ ++//////////////////////////////////////// ++ ++VOID QBSS_LoadInit( ++ IN RTMP_ADAPTER *pAd); ++ ++UINT32 QBSS_LoadElementAppend( ++ IN RTMP_ADAPTER *pAd, ++ OUT UINT8 *buf_p); ++ ++VOID QBSS_LoadUpdate( ++ IN RTMP_ADAPTER *pAd); ++ ++/////////////////////////////////////// ++INT RTMPShowCfgValue( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pName, ++ IN PUCHAR pBuf); ++ ++PCHAR RTMPGetRalinkAuthModeStr( ++ IN NDIS_802_11_AUTHENTICATION_MODE authMode); ++ ++PCHAR RTMPGetRalinkEncryModeStr( ++ IN USHORT encryMode); ++////////////////////////////////////// ++ ++#ifdef CONFIG_STA_SUPPORT ++VOID AsicStaBbpTuning( ++ IN PRTMP_ADAPTER pAd); ++ ++BOOLEAN StaAddMacTableEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN USHORT CapabilityInfo); ++#endif // CONFIG_STA_SUPPORT // ++ ++void RTMP_IndicateMediaState( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID ReSyncBeaconTime( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID RTMPSetAGCInitValue( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BandWidth); ++ ++int rt28xx_close(IN PNET_DEV dev); ++int rt28xx_open(IN PNET_DEV dev); ++ ++__inline INT VIRTUAL_IF_UP(PRTMP_ADAPTER pAd) ++{ ++extern VOID MeshMakeBeacon(IN PRTMP_ADAPTER pAd, IN UCHAR idx); ++extern VOID MeshUpdateBeaconFrame(IN PRTMP_ADAPTER pAd, IN UCHAR idx); ++ ++ if (VIRTUAL_IF_NUM(pAd) == 0) ++ { ++ if (rt28xx_open(pAd->net_dev) != 0) ++ return -1; ++ } ++ else ++ { ++ } ++ VIRTUAL_IF_INC(pAd); ++ return 0; ++} ++ ++__inline VOID VIRTUAL_IF_DOWN(PRTMP_ADAPTER pAd) ++{ ++ VIRTUAL_IF_DEC(pAd); ++ if (VIRTUAL_IF_NUM(pAd) == 0) ++ rt28xx_close(pAd->net_dev); ++ return; ++} ++ ++ ++#endif // __RTMP_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rtmp_type.h +@@ -0,0 +1,95 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_type.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++ Paul Lin 1-2-2004 ++*/ ++#ifndef __RTMP_TYPE_H__ ++#define __RTMP_TYPE_H__ ++ ++ ++#define PACKED __attribute__ ((packed)) ++ ++// Put platform dependent declaration here ++// For example, linux type definition ++typedef unsigned char UINT8; ++typedef unsigned short UINT16; ++typedef unsigned int UINT32; ++typedef unsigned long long UINT64; ++typedef int INT32; ++typedef long long INT64; ++ ++typedef unsigned char * PUINT8; ++typedef unsigned short * PUINT16; ++typedef unsigned int * PUINT32; ++typedef unsigned long long * PUINT64; ++typedef int * PINT32; ++typedef long long * PINT64; ++ ++typedef signed char CHAR; ++typedef signed short SHORT; ++typedef signed int INT; ++typedef signed long LONG; ++typedef signed long long LONGLONG; ++ ++ ++typedef unsigned char UCHAR; ++typedef unsigned short USHORT; ++typedef unsigned int UINT; ++typedef unsigned long ULONG; ++typedef unsigned long long ULONGLONG; ++ ++typedef unsigned char BOOLEAN; ++typedef void VOID; ++ ++typedef VOID * PVOID; ++typedef CHAR * PCHAR; ++typedef UCHAR * PUCHAR; ++typedef USHORT * PUSHORT; ++typedef LONG * PLONG; ++typedef ULONG * PULONG; ++typedef UINT * PUINT; ++ ++typedef unsigned int NDIS_MEDIA_STATE; ++ ++typedef union _LARGE_INTEGER { ++ struct { ++ UINT LowPart; ++ INT32 HighPart; ++ } u; ++ INT64 QuadPart; ++} LARGE_INTEGER; ++ ++#endif // __RTMP_TYPE_H__ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/rt_profile.c +@@ -0,0 +1,2041 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#include "rt_config.h" ++ ++#ifdef DOT11_N_SUPPORT ++static void HTParametersHook( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR *pValueStr, ++ IN CHAR *pInput); ++#endif // DOT11_N_SUPPORT // ++ ++#define ETH_MAC_ADDR_STR_LEN 17 // in format of xx:xx:xx:xx:xx:xx ++ ++// We assume the s1 is a sting, s2 is a memory space with 6 bytes. and content of s1 will be changed. ++BOOLEAN rtstrmactohex(char *s1, char *s2) ++{ ++ int i = 0; ++ char *ptokS = s1, *ptokE = s1; ++ ++ if (strlen(s1) != ETH_MAC_ADDR_STR_LEN) ++ return FALSE; ++ ++ while((*ptokS) != '\0') ++ { ++ if((ptokE = strchr(ptokS, ':')) != NULL) ++ *ptokE++ = '\0'; ++ if ((strlen(ptokS) != 2) || (!isxdigit(*ptokS)) || (!isxdigit(*(ptokS+1)))) ++ break; // fail ++ AtoH(ptokS, &s2[i++], 1); ++ ptokS = ptokE; ++ if (i == 6) ++ break; // parsing finished ++ } ++ ++ return ( i == 6 ? TRUE : FALSE); ++ ++} ++ ++ ++// we assume the s1 and s2 both are strings. ++BOOLEAN rtstrcasecmp(char *s1, char *s2) ++{ ++ char *p1 = s1, *p2 = s2; ++ ++ if (strlen(s1) != strlen(s2)) ++ return FALSE; ++ ++ while(*p1 != '\0') ++ { ++ if((*p1 != *p2) && ((*p1 ^ *p2) != 0x20)) ++ return FALSE; ++ p1++; ++ p2++; ++ } ++ ++ return TRUE; ++} ++ ++// we assume the s1 (buffer) and s2 (key) both are strings. ++char * rtstrstruncasecmp(char * s1, char * s2) ++{ ++ INT l1, l2, i; ++ char temp1, temp2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *) s1; ++ ++ l1 = strlen(s1); ++ ++ while (l1 >= l2) ++ { ++ l1--; ++ ++ for(i=0; i= l2) ++ { ++ l1--; ++ if (!memcmp(s1,s2,l2)) ++ return (char *) s1; ++ s1++; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * rstrtok - Split a string into tokens ++ * @s: The string to be searched ++ * @ct: The characters to search for ++ * * WARNING: strtok is deprecated, use strsep instead. However strsep is not compatible with old architecture. ++ */ ++char * __rstrtok; ++char * rstrtok(char * s,const char * ct) ++{ ++ char *sbegin, *send; ++ ++ sbegin = s ? s : __rstrtok; ++ if (!sbegin) ++ { ++ return NULL; ++ } ++ ++ sbegin += strspn(sbegin,ct); ++ if (*sbegin == '\0') ++ { ++ __rstrtok = NULL; ++ return( NULL ); ++ } ++ ++ send = strpbrk( sbegin, ct); ++ if (send && *send != '\0') ++ *send++ = '\0'; ++ ++ __rstrtok = send; ++ ++ return (sbegin); ++} ++ ++/** ++ * delimitcnt - return the count of a given delimiter in a given string. ++ * @s: The string to be searched. ++ * @ct: The delimiter to search for. ++ * Notice : We suppose the delimiter is a single-char string(for example : ";"). ++ */ ++INT delimitcnt(char * s,const char * ct) ++{ ++ INT count = 0; ++ /* point to the beginning of the line */ ++ const char *token = s; ++ ++ for ( ;; ) ++ { ++ token = strpbrk(token, ct); /* search for delimiters */ ++ ++ if ( token == NULL ) ++ { ++ /* advanced to the terminating null character */ ++ break; ++ } ++ /* skip the delimiter */ ++ ++token; ++ ++ /* ++ * Print the found text: use len with %.*s to specify field width. ++ */ ++ ++ /* accumulate delimiter count */ ++ ++count; ++ } ++ return count; ++} ++ ++/* ++ * converts the Internet host address from the standard numbers-and-dots notation ++ * into binary data. ++ * returns nonzero if the address is valid, zero if not. ++ */ ++int rtinet_aton(const char *cp, unsigned int *addr) ++{ ++ unsigned int val; ++ int base, n; ++ char c; ++ unsigned int parts[4]; ++ unsigned int *pp = parts; ++ ++ for (;;) ++ { ++ /* ++ * Collect number up to ``.''. ++ * Values are specified as for C: ++ * 0x=hex, 0=octal, other=decimal. ++ */ ++ val = 0; ++ base = 10; ++ if (*cp == '0') ++ { ++ if (*++cp == 'x' || *cp == 'X') ++ base = 16, cp++; ++ else ++ base = 8; ++ } ++ while ((c = *cp) != '\0') ++ { ++ if (isdigit((unsigned char) c)) ++ { ++ val = (val * base) + (c - '0'); ++ cp++; ++ continue; ++ } ++ if (base == 16 && isxdigit((unsigned char) c)) ++ { ++ val = (val << 4) + ++ (c + 10 - (islower((unsigned char) c) ? 'a' : 'A')); ++ cp++; ++ continue; ++ } ++ break; ++ } ++ if (*cp == '.') ++ { ++ /* ++ * Internet format: a.b.c.d a.b.c (with c treated as 16-bits) ++ * a.b (with b treated as 24 bits) ++ */ ++ if (pp >= parts + 3 || val > 0xff) ++ return 0; ++ *pp++ = val, cp++; ++ } ++ else ++ break; ++ } ++ ++ /* ++ * Check for trailing junk. ++ */ ++ while (*cp) ++ if (!isspace((unsigned char) *cp++)) ++ return 0; ++ ++ /* ++ * Concoct the address according to the number of parts specified. ++ */ ++ n = pp - parts + 1; ++ switch (n) ++ { ++ ++ case 1: /* a -- 32 bits */ ++ break; ++ ++ case 2: /* a.b -- 8.24 bits */ ++ if (val > 0xffffff) ++ return 0; ++ val |= parts[0] << 24; ++ break; ++ ++ case 3: /* a.b.c -- 8.8.16 bits */ ++ if (val > 0xffff) ++ return 0; ++ val |= (parts[0] << 24) | (parts[1] << 16); ++ break; ++ ++ case 4: /* a.b.c.d -- 8.8.8.8 bits */ ++ if (val > 0xff) ++ return 0; ++ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); ++ break; ++ } ++ ++ *addr = htonl(val); ++ return 1; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Find key section for Get key parameter. ++ ++ Arguments: ++ buffer Pointer to the buffer to start find the key section ++ section the key of the secion to be find ++ ++ Return Value: ++ NULL Fail ++ Others Success ++ ======================================================================== ++*/ ++PUCHAR RTMPFindSection( ++ IN PCHAR buffer) ++{ ++ CHAR temp_buf[32]; ++ PUCHAR ptr; ++ ++ strcpy(temp_buf, "Default"); ++ ++ if((ptr = rtstrstr(buffer, temp_buf)) != NULL) ++ return (ptr+strlen("\n")); ++ else ++ return NULL; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Get key parameter. ++ ++ Arguments: ++ key Pointer to key string ++ dest Pointer to destination ++ destsize The datasize of the destination ++ buffer Pointer to the buffer to start find the key ++ ++ Return Value: ++ TRUE Success ++ FALSE Fail ++ ++ Note: ++ This routine get the value with the matched key (case case-sensitive) ++ ======================================================================== ++*/ ++INT RTMPGetKeyParameter( ++ IN PCHAR key, ++ OUT PCHAR dest, ++ IN INT destsize, ++ IN PCHAR buffer) ++{ ++ UCHAR *temp_buf1 = NULL; ++ UCHAR *temp_buf2 = NULL; ++ CHAR *start_ptr; ++ CHAR *end_ptr; ++ CHAR *ptr; ++ CHAR *offset = 0; ++ INT len; ++ ++ //temp_buf1 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ os_alloc_mem(NULL, &temp_buf1, MAX_PARAM_BUFFER_SIZE); ++ ++ if(temp_buf1 == NULL) ++ return (FALSE); ++ ++ //temp_buf2 = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ os_alloc_mem(NULL, &temp_buf2, MAX_PARAM_BUFFER_SIZE); ++ if(temp_buf2 == NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ return (FALSE); ++ } ++ ++ //find section ++ if((offset = RTMPFindSection(buffer)) == NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ os_free_mem(NULL, temp_buf2); ++ return (FALSE); ++ } ++ ++ strcpy(temp_buf1, "\n"); ++ strcat(temp_buf1, key); ++ strcat(temp_buf1, "="); ++ ++ //search key ++ if((start_ptr=rtstrstr(offset, temp_buf1))==NULL) ++ { ++ os_free_mem(NULL, temp_buf1); ++ os_free_mem(NULL, temp_buf2); ++ return (FALSE); ++ } ++ ++ start_ptr+=strlen("\n"); ++ if((end_ptr=rtstrstr(start_ptr, "\n"))==NULL) ++ end_ptr=start_ptr+strlen(start_ptr); ++ ++ if (end_ptrSharedKey[i][idx].KeyLen = KeyLen / 2; ++ AtoH(keybuff, pAd->SharedKey[i][idx].Key, KeyLen / 2); ++ if (KeyLen == 10) ++ CipherAlg = CIPHER_WEP64; ++ else ++ CipherAlg = CIPHER_WEP128; ++ pAd->SharedKey[i][idx].CipherAlg = CipherAlg; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("I/F(ra%d) Key%dStr=%s and type=%s\n", i, idx+1, keybuff, (KeyType == 0) ? "Hex":"Ascii")); ++ return 1; ++ } ++ else ++ {//Invalid key length ++ DBGPRINT(RT_DEBUG_ERROR, ("I/F(ra%d) Key%dStr is Invalid key length! KeyLen = %ld!\n", i, idx+1, KeyLen)); ++ return 0; ++ } ++ } ++} ++static void rtmp_read_key_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) ++{ ++ char tok_str[16]; ++ PUCHAR macptr; ++ INT i = 0, idx; ++ ULONG KeyType[MAX_MBSSID_NUM]; ++ ULONG KeyIdx; ++ ++ NdisZeroMemory(KeyType, MAX_MBSSID_NUM); ++ ++ //DefaultKeyID ++ if(RTMPGetKeyParameter("DefaultKeyID", tmpbuf, 25, buffer)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ KeyIdx = simple_strtol(tmpbuf, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1); ++ else ++ pAd->StaCfg.DefaultKeyId = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyID(0~3)=%d\n", pAd->StaCfg.DefaultKeyId)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ for (idx = 0; idx < 4; idx++) ++ { ++ sprintf(tok_str, "Key%dType", idx + 1); ++ //Key1Type ++ if (RTMPGetKeyParameter(tok_str, tmpbuf, 128, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ KeyType[i] = simple_strtol(macptr, 0, 10); ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ sprintf(tok_str, "Key%dStr", idx + 1); ++ if (RTMPGetCriticalParameter(tok_str, tmpbuf, 128, buffer)) ++ { ++ rtmp_parse_key_buffer_from_file(pAd, tmpbuf, KeyType[BSS0], BSS0, idx); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ } ++} ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++static void rtmp_read_sta_wmm_parms_from_file(IN PRTMP_ADAPTER pAd, char *tmpbuf, char *buffer) ++{ ++ PUCHAR macptr; ++ INT i=0; ++ BOOLEAN bWmmEnable = FALSE; ++ ++ //WmmCapable ++ if(RTMPGetKeyParameter("WmmCapable", tmpbuf, 32, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ { ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ bWmmEnable = TRUE; ++ } ++ else //Disable ++ { ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WmmCapable=%d\n", pAd->CommonCfg.bWmmCapable)); ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ //DLSCapable ++ if(RTMPGetKeyParameter("DLSCapable", tmpbuf, 32, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ { ++ pAd->CommonCfg.bDLSCapable = TRUE; ++ } ++ else //Disable ++ { ++ pAd->CommonCfg.bDLSCapable = FALSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("bDLSCapable=%d\n", pAd->CommonCfg.bDLSCapable)); ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ //AckPolicy for AC_BK, AC_BE, AC_VI, AC_VO ++ if(RTMPGetKeyParameter("AckPolicy", tmpbuf, 32, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ pAd->CommonCfg.AckPolicy[i] = (UCHAR)simple_strtol(macptr, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AckPolicy[%d]=%d\n", i, pAd->CommonCfg.AckPolicy[i])); ++ } ++ } ++ ++ if (bWmmEnable) ++ { ++ //APSDCapable ++ if(RTMPGetKeyParameter("APSDCapable", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bAPSDCapable = TRUE; ++ else ++ pAd->CommonCfg.bAPSDCapable = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("APSDCapable=%d\n", pAd->CommonCfg.bAPSDCapable)); ++ } ++ ++ //APSDAC for AC_BE, AC_BK, AC_VI, AC_VO ++ if(RTMPGetKeyParameter("APSDAC", tmpbuf, 32, buffer)) ++ { ++ BOOLEAN apsd_ac[4]; ++ ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ apsd_ac[i] = (BOOLEAN)simple_strtol(macptr, 0, 10); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("APSDAC%d %d\n", i, apsd_ac[i])); ++ } ++ ++ pAd->CommonCfg.bAPSDAC_BE = apsd_ac[0]; ++ pAd->CommonCfg.bAPSDAC_BK = apsd_ac[1]; ++ pAd->CommonCfg.bAPSDAC_VI = apsd_ac[2]; ++ pAd->CommonCfg.bAPSDAC_VO = apsd_ac[3]; ++ } ++ } ++ ++} ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++NDIS_STATUS RTMPReadParametersHook( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PUCHAR src = NULL; ++ struct file *srcf; ++ INT retval, orgfsuid, orgfsgid; ++ mm_segment_t orgfs; ++ CHAR *buffer; ++ CHAR *tmpbuf; ++ ULONG RtsThresh; ++ ULONG FragThresh; ++#ifdef CONFIG_STA_SUPPORT ++ UCHAR keyMaterial[40]; ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++ PUCHAR macptr; ++ INT i = 0; ++ ++ buffer = kmalloc(MAX_INI_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ if(buffer == NULL) ++ return NDIS_STATUS_FAILURE; ++ ++ tmpbuf = kmalloc(MAX_PARAM_BUFFER_SIZE, MEM_ALLOC_FLAG); ++ if(tmpbuf == NULL) ++ { ++ kfree(buffer); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ src = STA_PROFILE_PATH; ++#endif // CONFIG_STA_SUPPORT // ++#ifdef MULTIPLE_CARD_SUPPORT ++ src = pAd->MC_FileName; ++#endif // MULTIPLE_CARD_SUPPORT // ++ ++ // Save uid and gid used for filesystem access. ++ // Set user and group to 0 (root) ++#if 0 ++ orgfsuid = current->fsuid; ++ orgfsgid = current->fsgid; ++ current->fsuid=current->fsgid = 0; ++#endif ++ orgfs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ if (src && *src) ++ { ++ srcf = filp_open(src, O_RDONLY, 0); ++ if (IS_ERR(srcf)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("--> Error %ld opening %s\n", -PTR_ERR(srcf),src)); ++ } ++ else ++ { ++ // The object must have a read method ++ if (srcf->f_op && srcf->f_op->read) ++ { ++ memset(buffer, 0x00, MAX_INI_BUFFER_SIZE); ++ retval=srcf->f_op->read(srcf, buffer, MAX_INI_BUFFER_SIZE, &srcf->f_pos); ++ if (retval < 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Read %s error %d\n", src, -retval)); ++ } ++ else ++ { ++ // set file parameter to portcfg ++ //CountryRegion ++ if(RTMPGetKeyParameter("CountryRegion", tmpbuf, 25, buffer)) ++ { ++ pAd->CommonCfg.CountryRegion = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryRegion=%d\n", pAd->CommonCfg.CountryRegion)); ++ } ++ //CountryRegionABand ++ if(RTMPGetKeyParameter("CountryRegionABand", tmpbuf, 25, buffer)) ++ { ++ pAd->CommonCfg.CountryRegionForABand= (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryRegionABand=%d\n", pAd->CommonCfg.CountryRegionForABand)); ++ } ++ //CountryCode ++ if(RTMPGetKeyParameter("CountryCode", tmpbuf, 25, buffer)) ++ { ++ NdisMoveMemory(pAd->CommonCfg.CountryCode, tmpbuf , 2); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ NdisMoveMemory(pAd->StaCfg.StaOriCountryCode, tmpbuf , 2); ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ if (strlen(pAd->CommonCfg.CountryCode) != 0) ++ { ++ pAd->CommonCfg.bCountryFlag = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("CountryCode=%s\n", pAd->CommonCfg.CountryCode)); ++ } ++ //ChannelGeography ++ if(RTMPGetKeyParameter("ChannelGeography", tmpbuf, 25, buffer)) ++ { ++ UCHAR Geography = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ if (Geography <= BOTH) ++ { ++ pAd->CommonCfg.Geography = Geography; ++ pAd->CommonCfg.CountryCode[2] = ++ (pAd->CommonCfg.Geography == BOTH) ? ' ' : ((pAd->CommonCfg.Geography == IDOR) ? 'I' : 'O'); ++#ifdef CONFIG_STA_SUPPORT ++#ifdef EXT_BUILD_CHANNEL_LIST ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->StaCfg.StaOriGeography = pAd->CommonCfg.Geography; ++#endif // EXT_BUILD_CHANNEL_LIST // ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelGeography=%d\n", pAd->CommonCfg.Geography)); ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.Geography = BOTH; ++ pAd->CommonCfg.CountryCode[2] = ' '; ++ } ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //SSID ++ if (RTMPGetCriticalParameter("SSID", tmpbuf, 256, buffer)) ++ { ++ if (strlen(tmpbuf) <= 32) ++ { ++ pAd->CommonCfg.SsidLen = (UCHAR) strlen(tmpbuf); ++ NdisZeroMemory(pAd->CommonCfg.Ssid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->CommonCfg.Ssid, tmpbuf, pAd->CommonCfg.SsidLen); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->CommonCfg.SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, tmpbuf, pAd->MlmeAux.AutoReconnectSsidLen); ++ pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //NetworkType ++ if (RTMPGetKeyParameter("NetworkType", tmpbuf, 25, buffer)) ++ { ++ pAd->bConfigChanged = TRUE; ++ if (strcmp(tmpbuf, "Adhoc") == 0) ++ pAd->StaCfg.BssType = BSS_ADHOC; ++ else //Default Infrastructure mode ++ pAd->StaCfg.BssType = BSS_INFRA; ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ //Channel ++ if(RTMPGetKeyParameter("Channel", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.Channel = (UCHAR) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("Channel=%d\n", pAd->CommonCfg.Channel)); ++ } ++ //WirelessMode ++ if(RTMPGetKeyParameter("WirelessMode", tmpbuf, 10, buffer)) ++ { ++ int value = 0, maxPhyMode = PHY_11G; ++ ++#ifdef DOT11_N_SUPPORT ++ maxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ value = simple_strtol(tmpbuf, 0, 10); ++ ++ if (value <= maxPhyMode) ++ { ++ pAd->CommonCfg.PhyMode = value; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("PhyMode=%d\n", pAd->CommonCfg.PhyMode)); ++ } ++ //BasicRate ++ if(RTMPGetKeyParameter("BasicRate", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.BasicRateBitmap = (ULONG) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("BasicRate=%ld\n", pAd->CommonCfg.BasicRateBitmap)); ++ } ++ //BeaconPeriod ++ if(RTMPGetKeyParameter("BeaconPeriod", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.BeaconPeriod = (USHORT) simple_strtol(tmpbuf, 0, 10); ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconPeriod=%d\n", pAd->CommonCfg.BeaconPeriod)); ++ } ++ //TxPower ++ if(RTMPGetKeyParameter("TxPower", tmpbuf, 10, buffer)) ++ { ++ pAd->CommonCfg.TxPowerPercentage = (ULONG) simple_strtol(tmpbuf, 0, 10); ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ pAd->CommonCfg.TxPowerDefault = pAd->CommonCfg.TxPowerPercentage; ++#endif // CONFIG_STA_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPower=%ld\n", pAd->CommonCfg.TxPowerPercentage)); ++ } ++ //BGProtection ++ if(RTMPGetKeyParameter("BGProtection", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //Always On ++ pAd->CommonCfg.UseBGProtection = 1; ++ break; ++ case 2: //Always OFF ++ pAd->CommonCfg.UseBGProtection = 2; ++ break; ++ case 0: //AUTO ++ default: ++ pAd->CommonCfg.UseBGProtection = 0; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("BGProtection=%ld\n", pAd->CommonCfg.UseBGProtection)); ++ } ++ //OLBCDetection ++ if(RTMPGetKeyParameter("DisableOLBC", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //disable OLBC Detection ++ pAd->CommonCfg.DisableOLBCDetect = 1; ++ break; ++ case 0: //enable OLBC Detection ++ pAd->CommonCfg.DisableOLBCDetect = 0; ++ break; ++ default: ++ pAd->CommonCfg.DisableOLBCDetect= 0; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("OLBCDetection=%ld\n", pAd->CommonCfg.DisableOLBCDetect)); ++ } ++ //TxPreamble ++ if(RTMPGetKeyParameter("TxPreamble", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case Rt802_11PreambleShort: ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleShort; ++ break; ++ case Rt802_11PreambleLong: ++ default: ++ pAd->CommonCfg.TxPreamble = Rt802_11PreambleLong; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("TxPreamble=%ld\n", pAd->CommonCfg.TxPreamble)); ++ } ++ //RTSThreshold ++ if(RTMPGetKeyParameter("RTSThreshold", tmpbuf, 10, buffer)) ++ { ++ RtsThresh = simple_strtol(tmpbuf, 0, 10); ++ if( (RtsThresh >= 1) && (RtsThresh <= MAX_RTS_THRESHOLD) ) ++ pAd->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ else ++ pAd->CommonCfg.RtsThreshold = MAX_RTS_THRESHOLD; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTSThreshold=%d\n", pAd->CommonCfg.RtsThreshold)); ++ } ++ //FragThreshold ++ if(RTMPGetKeyParameter("FragThreshold", tmpbuf, 10, buffer)) ++ { ++ FragThresh = simple_strtol(tmpbuf, 0, 10); ++ pAd->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { //illegal FragThresh so we set it to default ++ pAd->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAd->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else if (FragThresh % 2 == 1) ++ { ++ // The length of each fragment shall always be an even number of octets, except for the last fragment ++ // of an MSDU or MMPDU, which may be either an even or an odd number of octets. ++ pAd->CommonCfg.FragmentThreshold = (USHORT)(FragThresh - 1); ++ } ++ else ++ { ++ pAd->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ //pAd->CommonCfg.AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; ++ DBGPRINT(RT_DEBUG_TRACE, ("FragThreshold=%d\n", pAd->CommonCfg.FragmentThreshold)); ++ } ++ //TxBurst ++ if(RTMPGetKeyParameter("TxBurst", tmpbuf, 10, buffer)) ++ { ++//#ifdef WIFI_TEST ++// pAd->CommonCfg.bEnableTxBurst = FALSE; ++//#else ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bEnableTxBurst = TRUE; ++ else //Disable ++ pAd->CommonCfg.bEnableTxBurst = FALSE; ++//#endif ++ DBGPRINT(RT_DEBUG_TRACE, ("TxBurst=%d\n", pAd->CommonCfg.bEnableTxBurst)); ++ } ++ ++#ifdef AGGREGATION_SUPPORT ++ //PktAggregate ++ if(RTMPGetKeyParameter("PktAggregate", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bAggregationCapable = TRUE; ++ else //Disable ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++#ifdef PIGGYBACK_SUPPORT ++ pAd->CommonCfg.bPiggyBackCapable = pAd->CommonCfg.bAggregationCapable; ++#endif // PIGGYBACK_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("PktAggregate=%d\n", pAd->CommonCfg.bAggregationCapable)); ++ } ++#else ++ pAd->CommonCfg.bAggregationCapable = FALSE; ++ pAd->CommonCfg.bPiggyBackCapable = FALSE; ++#endif // AGGREGATION_SUPPORT // ++ ++ // WmmCapable ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ rtmp_read_sta_wmm_parms_from_file(pAd, tmpbuf, buffer); ++#endif // CONFIG_STA_SUPPORT // ++ ++ //ShortSlot ++ if(RTMPGetKeyParameter("ShortSlot", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bUseShortSlotTime = TRUE; ++ else //Disable ++ pAd->CommonCfg.bUseShortSlotTime = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortSlot=%d\n", pAd->CommonCfg.bUseShortSlotTime)); ++ } ++ //IEEE80211H ++ if(RTMPGetKeyParameter("IEEE80211H", tmpbuf, 10, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ if(simple_strtol(macptr, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bIEEE80211H = TRUE; ++ else //Disable ++ pAd->CommonCfg.bIEEE80211H = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IEEE80211H=%d\n", pAd->CommonCfg.bIEEE80211H)); ++ } ++ } ++ //CSPeriod ++ if(RTMPGetKeyParameter("CSPeriod", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.RadarDetect.CSPeriod = simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.RadarDetect.CSPeriod = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CSPeriod=%d\n", pAd->CommonCfg.RadarDetect.CSPeriod)); ++ } ++ ++ //RDRegion ++ if(RTMPGetKeyParameter("RDRegion", tmpbuf, 128, buffer)) ++ { ++ if ((strncmp(tmpbuf, "JAP_W53", 7) == 0) || (strncmp(tmpbuf, "jap_w53", 7) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W53; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 15; ++ } ++ else if ((strncmp(tmpbuf, "JAP_W56", 7) == 0) || (strncmp(tmpbuf, "jap_w56", 7) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP_W56; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ else if ((strncmp(tmpbuf, "JAP", 3) == 0) || (strncmp(tmpbuf, "jap", 3) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = JAP; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; ++ } ++ else if ((strncmp(tmpbuf, "FCC", 3) == 0) || (strncmp(tmpbuf, "fcc", 3) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = FCC; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 5; ++ } ++ else if ((strncmp(tmpbuf, "CE", 2) == 0) || (strncmp(tmpbuf, "ce", 2) == 0)) ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ else ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RDRegion=%d\n", pAd->CommonCfg.RadarDetect.RDDurRegion)); ++ } ++ else ++ { ++ pAd->CommonCfg.RadarDetect.RDDurRegion = CE; ++ pAd->CommonCfg.RadarDetect.DfsSessionTime = 13; ++ } ++ ++ //WirelessEvent ++ if(RTMPGetKeyParameter("WirelessEvent", tmpbuf, 10, buffer)) ++ { ++#if WIRELESS_EXT >= 15 ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.bWirelessEvent = simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.bWirelessEvent = 0; // disable ++#else ++ pAd->CommonCfg.bWirelessEvent = 0; // disable ++#endif ++ DBGPRINT(RT_DEBUG_TRACE, ("WirelessEvent=%d\n", pAd->CommonCfg.bWirelessEvent)); ++ } ++ if(RTMPGetKeyParameter("WiFiTest", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) != 0) ++ pAd->CommonCfg.bWiFiTest= simple_strtol(tmpbuf, 0, 10); ++ else ++ pAd->CommonCfg.bWiFiTest = 0; // disable ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WiFiTest=%d\n", pAd->CommonCfg.bWiFiTest)); ++ } ++ //AuthMode ++ if(RTMPGetKeyParameter("AuthMode", tmpbuf, 128, buffer)) ++ { ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((strcmp(tmpbuf, "WEPAUTO") == 0) || (strcmp(tmpbuf, "wepauto") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(tmpbuf, "SHARED") == 0) || (strcmp(tmpbuf, "shared") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(tmpbuf, "WPAPSK") == 0) || (strcmp(tmpbuf, "wpapsk") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(tmpbuf, "WPANONE") == 0) || (strcmp(tmpbuf, "wpanone") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(tmpbuf, "WPA2PSK") == 0) || (strcmp(tmpbuf, "wpa2psk") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(tmpbuf, "WPA") == 0) || (strcmp(tmpbuf, "wpa") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(tmpbuf, "WPA2") == 0) || (strcmp(tmpbuf, "wpa2") == 0)) ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ pAd->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ //EncrypType ++ if(RTMPGetKeyParameter("EncrypType", tmpbuf, 128, buffer)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((strcmp(tmpbuf, "WEP") == 0) || (strcmp(tmpbuf, "wep") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ else if ((strcmp(tmpbuf, "TKIP") == 0) || (strcmp(tmpbuf, "tkip") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ else if ((strcmp(tmpbuf, "AES") == 0) || (strcmp(tmpbuf, "aes") == 0)) ++ pAd->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ else ++ pAd->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ ++ // Update all wepstatus related ++ pAd->StaCfg.PairCipher = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus; ++ pAd->StaCfg.bMixCipher = FALSE; ++ ++ //RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if(RTMPGetCriticalParameter("WPAPSK", tmpbuf, 512, buffer)) ++ { ++ int err=0; ++ ++ tmpbuf[strlen(tmpbuf)] = '\0'; // make STA can process .$^& for WPAPSK input ++ ++ if ((pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAd->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ { ++ err = 1; ++ } ++ else if ((strlen(tmpbuf) >= 8) && (strlen(tmpbuf) < 64)) ++ { ++ PasswordHash((char *)tmpbuf, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, keyMaterial); ++ NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else if (strlen(tmpbuf) == 64) ++ { ++ AtoH(tmpbuf, keyMaterial, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, keyMaterial, 32); ++ } ++ else ++ { ++ err = 1; ++ DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__)); ++ } ++ ++ if (err == 0) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ // Start STA supplicant state machine ++ pAd->StaCfg.WpaState = SS_START; ++ } ++ else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ /* ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ */ ++ pAd->StaCfg.WpaState = SS_NOTUSE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ //DefaultKeyID, KeyType, KeyStr ++ rtmp_read_key_parms_from_file(pAd, tmpbuf, buffer); ++ ++ ++ //HSCounter ++ /*if(RTMPGetKeyParameter("HSCounter", tmpbuf, 10, buffer)) ++ { ++ switch (simple_strtol(tmpbuf, 0, 10)) ++ { ++ case 1: //Enable ++ pAd->CommonCfg.bEnableHSCounter = TRUE; ++ break; ++ case 0: //Disable ++ default: ++ pAd->CommonCfg.bEnableHSCounter = FALSE; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, "HSCounter=%d\n", pAd->CommonCfg.bEnableHSCounter); ++ }*/ ++ ++#ifdef DOT11_N_SUPPORT ++ HTParametersHook(pAd, tmpbuf, buffer); ++#endif // DOT11_N_SUPPORT // ++ ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++ //CarrierDetect ++ if(RTMPGetKeyParameter("CarrierDetect", tmpbuf, 128, buffer)) ++ { ++ if ((strncmp(tmpbuf, "0", 1) == 0)) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else if ((strncmp(tmpbuf, "1", 1) == 0)) ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CarrierDetect.Enable=%d\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ } ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ //PSMode ++ if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) ++ { ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(tmpbuf, "MAX_PSP") == 0) || (strcmp(tmpbuf, "max_psp") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsm(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAd->StaCfg.DefaultListenCount = 5; ++ } ++ else if ((strcmp(tmpbuf, "Fast_PSP") == 0) || (strcmp(tmpbuf, "fast_psp") == 0) ++ || (strcmp(tmpbuf, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsmBit(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAd->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(tmpbuf, "Legacy_PSP") == 0) || (strcmp(tmpbuf, "legacy_psp") == 0) ++ || (strcmp(tmpbuf, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ // MlmeSetPsmBit(pAd, PWR_SAVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAd->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM); ++ if (pAd->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("PSMode=%ld\n", pAd->StaCfg.WindowsPowerMode)); ++ } ++ } ++ // FastRoaming ++ if (RTMPGetKeyParameter("FastRoaming", tmpbuf, 32, buffer)) ++ { ++ if (simple_strtol(tmpbuf, 0, 10) == 0) ++ pAd->StaCfg.bFastRoaming = FALSE; ++ else ++ pAd->StaCfg.bFastRoaming = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FastRoaming=%d\n", pAd->StaCfg.bFastRoaming)); ++ } ++ // RoamThreshold ++ if (RTMPGetKeyParameter("RoamThreshold", tmpbuf, 32, buffer)) ++ { ++ long lInfo = simple_strtol(tmpbuf, 0, 10); ++ ++ if (lInfo > 90 || lInfo < 60) ++ pAd->StaCfg.dBmToRoam = -70; ++ else ++ pAd->StaCfg.dBmToRoam = (CHAR)(-1)*lInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RoamThreshold=%d dBm\n", pAd->StaCfg.dBmToRoam)); ++ } ++ ++ if(RTMPGetKeyParameter("TGnWifiTest", tmpbuf, 10, buffer)) ++ { ++ if(simple_strtol(tmpbuf, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("TGnWifiTest=%d\n", pAd->StaCfg.bTGnWifiTest)); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ ++ ++#ifdef RT30xx ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if(RTMPGetKeyParameter("AntDiversity", tmpbuf, 10, buffer)) ++ { ++ for (i = 0, macptr = rstrtok(tmpbuf,";"); macptr; macptr = rstrtok(NULL,";"), i++) ++ { ++ if(simple_strtol(macptr, 0, 10) != 0) //Enable ++ pAd->CommonCfg.bRxAntDiversity = TRUE; ++ else //Disable ++ pAd->CommonCfg.bRxAntDiversity = FALSE; ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("AntDiversity=%d\n", pAd->CommonCfg.bRxAntDiversity)); ++ } ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++#endif // RT30xx // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> %s does not have a write method\n", src)); ++ } ++ ++ retval=filp_close(srcf,NULL); ++ ++ if (retval) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("--> Error %d closing %s\n", -retval, src)); ++ } ++ } ++ } ++ ++ set_fs(orgfs); ++#if 0 ++ current->fsuid = orgfsuid; ++ current->fsgid = orgfsgid; ++#endif ++ ++ kfree(buffer); ++ kfree(tmpbuf); ++ ++ return (NDIS_STATUS_SUCCESS); ++} ++ ++#ifdef DOT11_N_SUPPORT ++static void HTParametersHook( ++ IN PRTMP_ADAPTER pAd, ++ IN CHAR *pValueStr, ++ IN CHAR *pInput) ++{ ++ ++ INT Value; ++ ++ if (RTMPGetKeyParameter("HT_PROTECT", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bHTProtect = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bHTProtect = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Protection = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ if (RTMPGetKeyParameter("HT_MIMOPSEnable", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bMIMOPSEnable = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bMIMOPSEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPSEnable = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ ++ if (RTMPGetKeyParameter("HT_MIMOPSMode", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value > MMPS_ENABLE) ++ { ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ } ++ else ++ { ++ //TODO: add mimo power saving mechanism ++ pAd->CommonCfg.BACapability.field.MMPSmode = MMPS_ENABLE; ++ //pAd->CommonCfg.BACapability.field.MMPSmode = Value; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MIMOPS Mode = %d\n", Value)); ++ } ++ ++ if (RTMPGetKeyParameter("HT_BADecline", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bBADecline = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bBADecline = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Decline = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ ++ if (RTMPGetKeyParameter("HT_DisableReordering", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bDisableReordering = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bDisableReordering = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: DisableReordering = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ if (RTMPGetKeyParameter("HT_AutoBA", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = FALSE; ++ pAd->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AutoBA = TRUE; ++ pAd->CommonCfg.BACapability.field.Policy = IMMED_BA; ++ } ++ pAd->CommonCfg.REGBACapability.field.AutoBA = pAd->CommonCfg.BACapability.field.AutoBA; ++ pAd->CommonCfg.REGBACapability.field.Policy = pAd->CommonCfg.BACapability.field.Policy; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Auto BA = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // Tx_+HTC frame ++ if (RTMPGetKeyParameter("HT_HTC", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->HTCEnable = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx +HTC frame = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // Enable HT Link Adaptation Control ++ if (RTMPGetKeyParameter("HT_LinkAdapt", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->bLinkAdapt = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->bLinkAdapt = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Link Adaptation Control = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); ++ } ++ ++ // Reverse Direction Mechanism ++ if (RTMPGetKeyParameter("HT_RDG", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bRdg = FALSE; ++ } ++ else ++ { ++ pAd->HTCEnable = TRUE; ++ pAd->CommonCfg.bRdg = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: RDG = %s\n", (Value==0) ? "Disable" : "Enable(+HTC)")); ++ } ++ ++ ++ ++ ++ // Tx A-MSUD ? ++ if (RTMPGetKeyParameter("HT_AMSDU", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.BACapability.field.AmsduEnable = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.AmsduEnable = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx A-MSDU = %s\n", (Value==0) ? "Disable" : "Enable")); ++ } ++ ++ // MPDU Density ++ if (RTMPGetKeyParameter("HT_MpduDensity", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value <=7 && Value >= 0) ++ { ++ pAd->CommonCfg.BACapability.field.MpduDensity = Value; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d\n", Value)); ++ } ++ else ++ { ++ pAd->CommonCfg.BACapability.field.MpduDensity = 4; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MPDU Density = %d (Default)\n", 4)); ++ } ++ } ++ ++ // Max Rx BA Window Size ++ if (RTMPGetKeyParameter("HT_BAWinSize", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value >=1 && Value <= 64) ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = Value; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = Value; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = %d\n", Value)); ++ } ++ else ++ { ++ pAd->CommonCfg.REGBACapability.field.RxBAWinLimit = 64; ++ pAd->CommonCfg.BACapability.field.RxBAWinLimit = 64; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: BA Windw Size = 64 (Defualt)\n")); ++ } ++ ++ } ++ ++ // Guard Interval ++ if (RTMPGetKeyParameter("HT_GI", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == GI_400) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_400; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.ShortGI = GI_800; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Guard Interval = %s\n", (Value==GI_400) ? "400" : "800" )); ++ } ++ ++ // HT Operation Mode : Mixed Mode , Green Field ++ if (RTMPGetKeyParameter("HT_OpMode", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == HTMODE_GF) ++ { ++ ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_GF; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.HTMODE = HTMODE_MM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Operate Mode = %s\n", (Value==HTMODE_GF) ? "Green Field" : "Mixed Mode" )); ++ } ++ ++ // Fixed Tx mode : CCK, OFDM ++ if (RTMPGetKeyParameter("FixedTxMode", pValueStr, 25, pInput)) ++ { ++ UCHAR fix_tx_mode; ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ fix_tx_mode = FIXED_TXMODE_HT; ++ ++ if (strcmp(pValueStr, "OFDM") == 0 || strcmp(pValueStr, "ofdm") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_OFDM; ++ } ++ else if (strcmp(pValueStr, "CCK") == 0 || strcmp(pValueStr, "cck") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_CCK; ++ } ++ else if (strcmp(pValueStr, "HT") == 0 || strcmp(pValueStr, "ht") == 0) ++ { ++ fix_tx_mode = FIXED_TXMODE_HT; ++ } ++ else ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ // 1 : CCK ++ // 2 : OFDM ++ // otherwise : HT ++ if (Value == FIXED_TXMODE_CCK || Value == FIXED_TXMODE_OFDM) ++ fix_tx_mode = Value; ++ else ++ fix_tx_mode = FIXED_TXMODE_HT; ++ } ++ ++ pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode = fix_tx_mode; ++ DBGPRINT(RT_DEBUG_TRACE, ("Fixed Tx Mode = %d\n", fix_tx_mode)); ++ ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ ++ // Channel Width ++ if (RTMPGetKeyParameter("HT_BW", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == BW_40) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; ++ } ++ ++#ifdef MCAST_RATE_SPECIFIC ++ pAd->CommonCfg.MCastPhyMode.field.BW = pAd->CommonCfg.RegTransmitSetting.field.BW; ++#endif // MCAST_RATE_SPECIFIC // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Channel Width = %s\n", (Value==BW_40) ? "40 MHz" : "20 MHz" )); ++ } ++ ++ if (RTMPGetKeyParameter("HT_EXTCHA", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++ if (Value == 0) ++ { ++ ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_BELOW; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.EXTCHA = EXTCHA_ABOVE; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Ext Channel = %s\n", (Value==0) ? "BELOW" : "ABOVE" )); ++ } ++ ++ // MSC ++ if (RTMPGetKeyParameter("HT_MCS", pValueStr, 50, pInput)) ++ { ++ ++#ifdef CONFIG_STA_SUPPORT ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ ++// if ((Value >= 0 && Value <= 15) || (Value == 32)) ++ if ((Value >= 0 && Value <= 23) || (Value == 32)) // 3*3 ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = Value; ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = %d\n", pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: MCS = AUTO\n")); ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ } ++ ++ // STBC ++ if (RTMPGetKeyParameter("HT_STBC", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == STBC_USE) ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_USE; ++ } ++ else ++ { ++ pAd->CommonCfg.RegTransmitSetting.field.STBC = STBC_NONE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: STBC = %d\n", pAd->CommonCfg.RegTransmitSetting.field.STBC)); ++ } ++ ++ // 40_Mhz_Intolerant ++ if (RTMPGetKeyParameter("HT_40MHZ_INTOLERANT", pValueStr, 25, pInput)) ++ { ++ Value = simple_strtol(pValueStr, 0, 10); ++ if (Value == 0) ++ { ++ pAd->CommonCfg.bForty_Mhz_Intolerant = FALSE; ++ } ++ else ++ { ++ pAd->CommonCfg.bForty_Mhz_Intolerant = TRUE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: 40MHZ INTOLERANT = %d\n", pAd->CommonCfg.bForty_Mhz_Intolerant)); ++ } ++ //HT_TxStream ++ if(RTMPGetKeyParameter("HT_TxStream", pValueStr, 10, pInput)) ++ { ++ switch (simple_strtol(pValueStr, 0, 10)) ++ { ++ case 1: ++ pAd->CommonCfg.TxStream = 1; ++ break; ++ case 2: ++ pAd->CommonCfg.TxStream = 2; ++ break; ++ case 3: // 3*3 ++ default: ++ pAd->CommonCfg.TxStream = 3; ++ ++ if (pAd->MACVersion < RALINK_2883_VERSION) ++ pAd->CommonCfg.TxStream = 2; // only 2 tx streams for RT2860 series ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Tx Stream = %d\n", pAd->CommonCfg.TxStream)); ++ } ++ //HT_RxStream ++ if(RTMPGetKeyParameter("HT_RxStream", pValueStr, 10, pInput)) ++ { ++ switch (simple_strtol(pValueStr, 0, 10)) ++ { ++ case 1: ++ pAd->CommonCfg.RxStream = 1; ++ break; ++ case 2: ++ pAd->CommonCfg.RxStream = 2; ++ break; ++ case 3: ++ default: ++ pAd->CommonCfg.RxStream = 3; ++ ++ if (pAd->MACVersion < RALINK_2883_VERSION) ++ pAd->CommonCfg.RxStream = 2; // only 2 rx streams for RT2860 series ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("HT: Rx Stream = %d\n", pAd->CommonCfg.RxStream)); ++ } ++ ++} ++#endif // DOT11_N_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/spectrum_def.h +@@ -0,0 +1,95 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ spectrum_def.h ++ ++ Abstract: ++ Handle association related requests either from WSTA or from local MLME ++ ++ Revision History: ++ Who When What ++ --------- ---------- ---------------------------------------------- ++ Fonchi Wu 2008 created for 802.11h ++ */ ++ ++#ifndef __SPECTRUM_DEF_H__ ++#define __SPECTRUM_DEF_H__ ++ ++#define MAX_MEASURE_REQ_TAB_SIZE 3 ++#define MAX_HASH_MEASURE_REQ_TAB_SIZE MAX_MEASURE_REQ_TAB_SIZE ++ ++#define MAX_TPC_REQ_TAB_SIZE 3 ++#define MAX_HASH_TPC_REQ_TAB_SIZE MAX_TPC_REQ_TAB_SIZE ++ ++#define MIN_RCV_PWR 100 /* Negative value ((dBm) */ ++ ++#define RM_TPC_REQ 0 ++#define RM_MEASURE_REQ 1 ++ ++#define RM_BASIC 0 ++#define RM_CCA 1 ++#define RM_RPI_HISTOGRAM 2 ++ ++#define TPC_REQ_AGE_OUT 500 /* ms */ ++#define MQ_REQ_AGE_OUT 500 /* ms */ ++ ++#define TPC_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_HASH_TPC_REQ_TAB_SIZE) ++#define MQ_DIALOGTOKEN_HASH_INDEX(_DialogToken) ((_DialogToken) % MAX_MEASURE_REQ_TAB_SIZE) ++ ++typedef struct _MEASURE_REQ_ENTRY ++{ ++ struct _MEASURE_REQ_ENTRY *pNext; ++ ULONG lastTime; ++ BOOLEAN Valid; ++ UINT8 DialogToken; ++ UINT8 MeasureDialogToken[3]; // 0:basic measure, 1: CCA measure, 2: RPI_Histogram measure. ++} MEASURE_REQ_ENTRY, *PMEASURE_REQ_ENTRY; ++ ++typedef struct _MEASURE_REQ_TAB ++{ ++ UCHAR Size; ++ PMEASURE_REQ_ENTRY Hash[MAX_HASH_MEASURE_REQ_TAB_SIZE]; ++ MEASURE_REQ_ENTRY Content[MAX_MEASURE_REQ_TAB_SIZE]; ++} MEASURE_REQ_TAB, *PMEASURE_REQ_TAB; ++ ++typedef struct _TPC_REQ_ENTRY ++{ ++ struct _TPC_REQ_ENTRY *pNext; ++ ULONG lastTime; ++ BOOLEAN Valid; ++ UINT8 DialogToken; ++} TPC_REQ_ENTRY, *PTPC_REQ_ENTRY; ++ ++typedef struct _TPC_REQ_TAB ++{ ++ UCHAR Size; ++ PTPC_REQ_ENTRY Hash[MAX_HASH_TPC_REQ_TAB_SIZE]; ++ TPC_REQ_ENTRY Content[MAX_TPC_REQ_TAB_SIZE]; ++} TPC_REQ_TAB, *PTPC_REQ_TAB; ++ ++#endif // __SPECTRUM_DEF_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/spectrum.h +@@ -0,0 +1,322 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ */ ++ ++#ifndef __SPECTRUM_H__ ++#define __SPECTRUM_H__ ++ ++#include "rtmp_type.h" ++#include "spectrum_def.h" ++ ++typedef struct PACKED _TPC_REPORT_INFO ++{ ++ UINT8 TxPwr; ++ UINT8 LinkMargin; ++} TPC_REPORT_INFO, *PTPC_REPORT_INFO; ++ ++typedef struct PACKED _CH_SW_ANN_INFO ++{ ++ UINT8 ChSwMode; ++ UINT8 Channel; ++ UINT8 ChSwCnt; ++} CH_SW_ANN_INFO, *PCH_SW_ANN_INFO; ++ ++typedef union PACKED _MEASURE_REQ_MODE ++{ ++#ifdef RT_BIG_ENDIAN ++ struct PACKED ++ { ++ UINT8 Rev1:4; ++ UINT8 Report:1; ++ UINT8 Request:1; ++ UINT8 Enable:1; ++ UINT8 Rev0:1; ++ } field; ++#else ++ struct PACKED ++ { ++ UINT8 Rev0:1; ++ UINT8 Enable:1; ++ UINT8 Request:1; ++ UINT8 Report:1; ++ UINT8 Rev1:4; ++ } field; ++#endif // RT_BIG_ENDIAN // ++ UINT8 word; ++} MEASURE_REQ_MODE, *PMEASURE_REQ_MODE; ++ ++typedef struct PACKED _MEASURE_REQ ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++} MEASURE_REQ, *PMEASURE_REQ; ++ ++typedef struct PACKED _MEASURE_REQ_INFO ++{ ++ UINT8 Token; ++ MEASURE_REQ_MODE ReqMode; ++ UINT8 ReqType; ++ MEASURE_REQ MeasureReq; ++} MEASURE_REQ_INFO, *PMEASURE_REQ_INFO; ++ ++typedef union PACKED _MEASURE_BASIC_REPORT_MAP ++{ ++#ifdef RT_BIG_ENDIAN ++ struct PACKED ++ { ++ UINT8 Rev:3; ++ UINT8 Unmeasure:1; ++ UINT8 Radar:1; ++ UINT8 UnidentifiedSignal:1; ++ UINT8 OfdmPreamble:1; ++ UINT8 BSS:1; ++ } field; ++#else ++ struct PACKED ++ { ++ UINT8 BSS:1; ++ UINT8 OfdmPreamble:1; ++ UINT8 UnidentifiedSignal:1; ++ UINT8 Radar:1; ++ UINT8 Unmeasure:1; ++ UINT8 Rev:3; ++ } field; ++#endif // RT_BIG_ENDIAN // ++ UINT8 word; ++} MEASURE_BASIC_REPORT_MAP, *PMEASURE_BASIC_REPORT_MAP; ++ ++typedef struct PACKED _MEASURE_BASIC_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ MEASURE_BASIC_REPORT_MAP Map; ++} MEASURE_BASIC_REPORT, *PMEASURE_BASIC_REPORT; ++ ++typedef struct PACKED _MEASURE_CCA_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ UINT8 CCA_Busy_Fraction; ++} MEASURE_CCA_REPORT, *PMEASURE_CCA_REPORT; ++ ++typedef struct PACKED _MEASURE_RPI_REPORT ++{ ++ UINT8 ChNum; ++ UINT64 MeasureStartTime; ++ UINT16 MeasureDuration; ++ UINT8 RPI_Density[8]; ++} MEASURE_RPI_REPORT, *PMEASURE_RPI_REPORT; ++ ++typedef union PACKED _MEASURE_REPORT_MODE ++{ ++ struct PACKED ++ { ++#ifdef RT_BIG_ENDIAN ++ UINT8 Rev:5; ++ UINT8 Refused:1; ++ UINT8 Incapable:1; ++ UINT8 Late:1; ++#else ++ UINT8 Late:1; ++ UINT8 Incapable:1; ++ UINT8 Refused:1; ++ UINT8 Rev:5; ++#endif // RT_BIG_ENDIAN // ++ } field; ++ UINT8 word; ++} MEASURE_REPORT_MODE, *PMEASURE_REPORT_MODE; ++ ++typedef struct PACKED _MEASURE_REPORT_INFO ++{ ++ UINT8 Token; ++ MEASURE_REPORT_MODE ReportMode; ++ UINT8 ReportType; ++ UINT8 Octect[0]; ++} MEASURE_REPORT_INFO, *PMEASURE_REPORT_INFO; ++ ++typedef struct PACKED _QUIET_INFO ++{ ++ UINT8 QuietCnt; ++ UINT8 QuietPeriod; ++ UINT8 QuietDuration; ++ UINT8 QuietOffset; ++} QUIET_INFO, *PQUIET_INFO; ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 MeasureCh, ++ IN UINT16 MeasureDuration); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Measurement report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueMeasurementRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 MeasureToken, ++ IN UINT8 MeasureReqMode, ++ IN UINT8 MeasureReqType, ++ IN UINT8 ReportInfoLen, ++ IN PUINT8 pReportInfo); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Request action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCReq( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UCHAR DialogToken); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare TPC Report action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueTPCRep( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 DialogToken, ++ IN UINT8 TxPwr, ++ IN UINT8 LinkMargin); ++ ++/* ++ ========================================================================== ++ Description: ++ Prepare Channel Switch Announcement action frame and enqueue it into ++ management queue waiting for transmition. ++ ++ Parametrs: ++ 1. the destination mac address of the frame. ++ 2. Channel switch announcement mode. ++ 2. a New selected channel. ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID EnqueueChSwAnn( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN UINT8 ChSwMode, ++ IN UINT8 NewCh); ++ ++/* ++ ========================================================================== ++ Description: ++ Spectrun action frames Handler such as channel switch annoucement, ++ measurement report, measurement request actions frames. ++ ++ Parametrs: ++ Elme - MLME message containing the received frame ++ ++ Return : None. ++ ========================================================================== ++ */ ++VOID PeerSpectrumAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem); ++ ++/* ++ ========================================================================== ++ Description: ++ ++ Parametrs: ++ ++ Return : None. ++ ========================================================================== ++ */ ++INT Set_MeasureReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++INT Set_TpcReq_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++ ++VOID MeasureReqTabInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID MeasureReqTabExit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID TpcReqTabInit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID TpcReqTabExit( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID NotifyChSwAnnToPeerAPs( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pRA, ++ IN PUCHAR pTA, ++ IN UINT8 ChSwMode, ++ IN UINT8 Channel); ++#endif // __SPECTRUM_H__ // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/aironet.c +@@ -0,0 +1,1312 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ aironet.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Paul Lin 04-06-15 Initial ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ========================================================================== ++ */ ++VOID AironetStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE); ++ StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction); ++ StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction); ++ StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This is state machine function. ++ When receiving EAPOL packets which is for 802.1x key management. ++ Use both in WPA, and WPAPSK case. ++ In this function, further dispatch to different functions according to the received packet. 3 categories are : ++ 1. normal 4-way pairwisekey and 2-way groupkey handshake ++ 2. MIC error (Countermeasures attack) report packet from STA. ++ 3. Request for pairwise/group key update from STA ++ Return: ++ ========================================================================== ++*/ ++VOID AironetMsgAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Length; ++ UCHAR Index, i; ++ PUCHAR pData; ++ PAIRONET_RM_REQUEST_FRAME pRMReq; ++ PRM_REQUEST_ACTION pReqElem; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n")); ++ ++ // 0. Get Aironet IAPP header first ++ pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11]; ++ pData = (PUCHAR) &Elem->Msg[LENGTH_802_11]; ++ ++ // 1. Change endian format form network to little endian ++ Length = be2cpu16(pRMReq->IAPP.Length); ++ ++ // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled ++ if (pAd->StaCfg.CCXEnable != TRUE) ++ return; ++ ++ // 2.1 Radio measurement must be on ++ if (pAd->StaCfg.CCXControl.field.RMEnable != 1) ++ return; ++ ++ // 2.2. Debug print all bit information ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay)); ++ DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset)); ++ ++ // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension ++ if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n")); ++ return; ++ } ++ ++ // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request. ++ // Since we are acting as client only, we will disregards reply subtype. ++ if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n")); ++ return; ++ } ++ ++ // 5. Verify Destination MAC and Source MAC, both should be all zeros. ++ if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n")); ++ return; ++ } ++ ++ if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n")); ++ return; ++ } ++ ++ // 6. Reinit all report related fields ++ NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048); ++ NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE); ++ NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4); ++ ++ // 7. Point to the start of first element report element ++ pAd->StaCfg.FrameReportLen = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER); ++ DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); ++ pAd->StaCfg.LastBssIndex = 0xff; ++ pAd->StaCfg.RMReqCnt = 0; ++ pAd->StaCfg.ParallelReq = FALSE; ++ pAd->StaCfg.ParallelDuration = 0; ++ pAd->StaCfg.ParallelChannel = 0; ++ pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; ++ pAd->StaCfg.CurrentRMReqIdx = 0; ++ pAd->StaCfg.CLBusyBytes = 0; ++ // Reset the statistics ++ for (i = 0; i < 8; i++) ++ pAd->StaCfg.RPIDensity[i] = 0; ++ ++ Index = 0; ++ ++ // 8. Save dialog token for report ++ pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token; ++ ++ // Save Activation delay & measurement offset, Not really needed ++ ++ // 9. Point to the first request element ++ pData += sizeof(AIRONET_RM_REQUEST_FRAME); ++ // Length should exclude the CISCO Aironet SNAP header ++ Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H); ++ ++ // 10. Start Parsing the Measurement elements. ++ // Be careful about multiple MR elements within one frames. ++ while (Length > 0) ++ { ++ pReqElem = (PRM_REQUEST_ACTION) pData; ++ switch (pReqElem->ReqElem.Eid) ++ { ++ case IE_MEASUREMENT_REQUEST: ++ // From the example, it seems we only need to support one request in one frame ++ // There is no multiple request in one frame. ++ // Besides, looks like we need to take care the measurement request only. ++ // The measurement request is always 4 bytes. ++ ++ // Start parsing this type of request. ++ // 0. Eid is IE_MEASUREMENT_REQUEST ++ // 1. Length didn't include Eid and Length field, it always be 8. ++ // 2. Measurement Token, we nned to save it for the corresponding report. ++ // 3. Measurement Mode, Although there are definitions, but we din't see value other than ++ // 0 from test specs examples. ++ // 4. Measurement Type, this is what we need to do. ++ switch (pReqElem->ReqElem.Type) ++ { ++ case MSRN_TYPE_CHANNEL_LOAD_REQ: ++ case MSRN_TYPE_NOISE_HIST_REQ: ++ case MSRN_TYPE_BEACON_REQ: ++ // Check the Enable non-serving channel measurement control ++ if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0) ++ { ++ // Check channel before enqueue the action ++ if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) ++ break; ++ } ++ else ++ { ++ // If off channel measurement, check the TU duration limit ++ if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel) ++ if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit) ++ break; ++ } ++ ++ // Save requests and execute actions later ++ NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION)); ++ Index += 1; ++ break; ++ ++ case MSRN_TYPE_FRAME_REQ: ++ // Since it's option, we will support later ++ // FrameRequestAction(pAd, pData); ++ break; ++ ++ default: ++ break; ++ } ++ ++ // Point to next Measurement request ++ pData += sizeof(RM_REQUEST_ACTION); ++ Length -= sizeof(RM_REQUEST_ACTION); ++ break; ++ ++ // We accept request only, all others are dropped ++ case IE_MEASUREMENT_REPORT: ++ case IE_AP_TX_POWER: ++ case IE_MEASUREMENT_CAPABILITY: ++ default: ++ return; ++ } ++ } ++ ++ // 11. Update some flags and index ++ pAd->StaCfg.RMReqCnt = Index; ++ ++ if (Index) ++ { ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRM_REQUEST_ACTION pReq; ++ ++ // 1. Point to next request element ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ // 2. Parse measurement type and call appropriate functions ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) ++ // Beacon measurement request ++ BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else ++ // Unknown. Do nothing and return, this should never happen ++ return; ++ ++ // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one ++ if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt) ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1]; ++ // Check for parallel bit ++ if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel)) ++ { ++ // Update parallel mode request information ++ pAd->StaCfg.ParallelReq = TRUE; ++ pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ? ++ (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime)); ++ } ++ } ++ ++ // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used ++ RT28XX_MLME_HANDLER(pAd); ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare channel load report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ChannelLoadRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32]; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ // Passive scan Mode ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer;; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_CHANNEL_LOAD_REQ; ++ pAd->StaCfg.CLBusyBytes = 0; ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); ++ ++ // Set channel load measurement flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare noise histogram report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NoiseHistRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32], i; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ // Passive scan Mode ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_NOISE_HIST_REQ; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ // Reset the statistics ++ for (i = 0; i < 8; i++) ++ pAd->StaCfg.RPIDensity[i] = 0; ++ ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010); ++ ++ // Set channel load measurement flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare Beacon report action, special scan operation added ++ to support ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pData Start from element ID ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID BeaconRequestAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PRM_REQUEST_ACTION pReq; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ PHEADER_802_11 pNullFrame; ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ UCHAR ZeroSsid[32]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n")); ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index]; ++ NdisZeroMemory(ZeroSsid, 32); ++ ++ // Prepare for special scan request ++ // The scan definition is different with our Active, Passive scan definition. ++ // For CCX2, Active means send out probe request with broadcast BSSID. ++ // Passive means no probe request sent, only listen to the beacons. ++ // The channel scanned is fixed as specified, no need to scan all channels. ++ // The scan wait time is specified in the request too. ++ if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE) ++ { ++ // Passive scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n")); ++ ++ // Control state machine is not idle, reject the request ++ if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0)) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ } ++ else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE) ++ { ++ // Active scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n")); ++ ++ // Control state machine is not idle, reject the request ++ if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ return; ++ ++ // Fill out stuff for scan request ++ ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ ++ // Reset some internal control flags to make sure this scan works. ++ BssTableInit(&pAd->StaCfg.CCXBssTab); ++ pAd->StaCfg.ScanCnt = 0; ++ pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel; ++ pAd->StaCfg.CCXScanTime = pReq->Measurement.Duration; ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_BEACON_REQ; ++ DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration)); ++ ++ // If it's non serving channel scan, send out a null frame with PSM bit on. ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ { ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ pNullFrame = (PHEADER_802_11) pOutBuffer; ++ // Make the power save Null frame with PSM bit on ++ MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pNullFrame->Duration = 0; ++ pNullFrame->FC.Type = BTYPE_DATA; ++ pNullFrame->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n")); ++ RTMPusecDelay(5000); ++ } ++ ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ } ++ else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE) ++ { ++ // Beacon report Mode, report all the APS in current bss table ++ DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n")); ++ ++ // Copy current BSS table to CCX table, we can omit this step later on. ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE)); ++ ++ // Create beacon report from Bss table ++ AironetCreateBeaconReportFromBssTable(pAd); ++ ++ // Set state to scanning ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING; ++ ++ // Enqueue report request ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++ else ++ { ++ // Wrong scan Mode ++ DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n")); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRM_REQUEST_ACTION pReq; ++ ULONG Now32; ++ ++ NdisGetSystemUpTime(&Now32); ++ pAd->StaCfg.LastBeaconRxTime = Now32; ++ ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n")); ++ ++ // 1. Parse measurement type and call appropriate functions ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ) ++ // Beacon measurement request ++ BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else ++ // Unknown. Do nothing and return ++ ; ++ ++ // 2. Point to the correct index of action element, start from 0 ++ pAd->StaCfg.CurrentRMReqIdx++; ++ ++ // 3. Check for parallel actions ++ if (pAd->StaCfg.ParallelReq == TRUE) ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ // Process next action right away ++ if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ) ++ // Channel Load measurement request ++ ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ) ++ // Noise Histogram measurement request ++ NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx); ++ ++ pAd->StaCfg.ParallelReq = FALSE; ++ pAd->StaCfg.CurrentRMReqIdx++; ++ } ++ ++ if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt) ++ { ++ // 4. There is no more unprocessed measurement request, go for transmit this report ++ AironetFinalReportAction(pAd); ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ } ++ else ++ { ++ pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx]; ++ ++ if (pReq->Measurement.Channel != pAd->CommonCfg.Channel) ++ { ++ RTMPusecDelay(100000); ++ } ++ ++ // 5. There are more requests to be measure ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetFinalReportAction( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PUCHAR pDest; ++ PAIRONET_IAPP_HEADER pIAPP; ++ PHEADER_802_11 pHeader; ++ UCHAR AckRate = RATE_2; ++ USHORT AckDuration = 0; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n")); ++ ++ // 0. Set up the frame pointer, Frame was inited at the end of message action ++ pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11]; ++ ++ // 1. Update report IAPP fields ++ pIAPP = (PAIRONET_IAPP_HEADER) pDest; ++ ++ // 2. Copy Cisco SNAP header ++ NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H); ++ ++ // 3. network order for this 16bit length ++ pIAPP->Length = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H); ++ ++ // 3.1 sanity check the report length, ignore it if there is nothing to report ++ if (be2cpu16(pIAPP->Length) <= 18) ++ return; ++ ++ // 4. Type must be 0x32 ++ pIAPP->Type = AIRONET_IAPP_TYPE; ++ ++ // 5. SubType for report must be 0x81 ++ pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT; ++ ++ // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function ++ // We will do it again here. We can use BSSID instead ++ COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid); ++ ++ // 7. SA is the client reporting which must be our MAC ++ COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress); ++ ++ // 8. Copy the saved dialog token ++ pIAPP->Token = pAd->StaCfg.IAPPToken; ++ ++ // 9. Make the Report frame 802.11 header ++ // Reuse function in wpa.c ++ pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf; ++ pAd->Sequence ++; ++ WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid); ++ ++ // ACK size is 14 include CRC, and its rate is based on real time information ++ AckRate = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate]; ++ AckDuration = RTMPCalcDuration(pAd, AckRate, 14); ++ pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration; ++ ++ // Use MLME enqueue method ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything. ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf, ++ END_OF_ARGS); ++ ++ // 11. Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID ChannelLoadReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PCHANNEL_LOAD_REPORT pLoad; ++ PUCHAR pDest; ++ UCHAR CCABusyFraction; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n")); ++ ++ // Disable Rx with promiscuous reception, make it back to normal ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ ++ // 0. Setup pointer for processing beacon & probe response ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ ++ // 1. Fill Measurement report element field. ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ // Fixed Length at 9, not include Eid and length fields ++ pReport->Length = 9; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_CHANNEL_LOAD_REQ; ++ ++ // 2. Fill channel report measurement data ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pLoad = (PCHANNEL_LOAD_REPORT) pDest; ++ pLoad->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; ++ pLoad->Spare = 0; ++ pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; ++ ++ // 3. Calculate the CCA Busy Fraction ++ // (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed ++ // = (Bytes + ACK) / 12 / duration ++ // 9 is the good value for pAd->StaCfg.CLFactor ++ // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration); ++ CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration); ++ if (CCABusyFraction < 10) ++ CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1; ++ ++ pLoad->CCABusy = CCABusyFraction; ++ DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); ++ pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen)); ++ ++ // 4. Clear channel load measurement flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ // 5. reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID NoiseHistReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PNOISE_HIST_REPORT pNoise; ++ PUCHAR pDest; ++ UCHAR i,NoiseCnt; ++ USHORT TotalRPICnt, TotalRPISum; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n")); ++ ++ // 0. Disable Rx with promiscuous reception, make it back to normal ++ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification. ++ // 1. Setup pointer for processing beacon & probe response ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ ++ // 2. Fill Measurement report element field. ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ // Fixed Length at 16, not include Eid and length fields ++ pReport->Length = 16; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_NOISE_HIST_REQ; ++ ++ // 3. Fill noise histogram report measurement data ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pNoise = (PNOISE_HIST_REPORT) pDest; ++ pNoise->Channel = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel; ++ pNoise->Spare = 0; ++ pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration; ++ // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU ++ // We estimate 4000 normal packets received durning 10 seconds test. ++ // Adjust it if required. ++ // 3 is a good value for pAd->StaCfg.NHFactor ++ // TotalRPICnt = pNoise->Duration * 3 / 10; ++ TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10; ++ TotalRPISum = 0; ++ ++ for (i = 0; i < 8; i++) ++ { ++ TotalRPISum += pAd->StaCfg.RPIDensity[i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i])); ++ } ++ ++ // Double check if the counter is larger than our expectation. ++ // We will replace it with the total number plus a fraction. ++ if (TotalRPISum > TotalRPICnt) ++ TotalRPICnt = TotalRPISum + pNoise->Duration / 20; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt)); ++ ++ // 5. Initialize noise count for the total summation of 0xff ++ NoiseCnt = 0; ++ for (i = 1; i < 8; i++) ++ { ++ pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt); ++ if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0)) ++ pNoise->Density[i]++; ++ NoiseCnt += pNoise->Density[i]; ++ DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d] = 0x%02x\n", i, pNoise->Density[i])); ++ } ++ ++ // 6. RPI[0] represents the rest of counts ++ pNoise->Density[0] = 0xff - NoiseCnt; ++ DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0] = 0x%02x\n", pNoise->Density[0])); ++ ++ pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT)); ++ ++ // 7. Clear channel load measurement flag ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT); ++ ++ // 8. reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Prepare Beacon report action, ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID BeaconReportAction( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR Index) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n")); ++ ++ // Looks like we don't have anything thing need to do here. ++ // All measurement report already finished in AddBeaconReport ++ // The length is in the FrameReportLen ++ ++ // reset Beacon index for next beacon request ++ pAd->StaCfg.LastBssIndex = 0xff; ++ ++ // reset to idle state ++ pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Index Current BSSID in CCXBsstab entry index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetAddBeaconReport( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG Index, ++ IN PMLME_QUEUE_ELEM pElem) ++{ ++ PVOID pMsg; ++ PUCHAR pSrc, pDest; ++ UCHAR ReqIdx; ++ ULONG MsgLen; ++ USHORT Length; ++ PFRAME_802_11 pFrame; ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PEID_STRUCT pEid; ++ PBEACON_REPORT pBeaconReport; ++ PBSS_ENTRY pBss; ++ ++ // 0. Setup pointer for processing beacon & probe response ++ pMsg = pElem->Msg; ++ MsgLen = pElem->MsgLen; ++ pFrame = (PFRAME_802_11) pMsg; ++ pSrc = pFrame->Octet; // Start from AP TSF ++ pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; ++ ReqIdx = pAd->StaCfg.CurrentRMReqIdx; ++ ++ // 1 Check the Index, if we already create this entry, only update the average RSSI ++ if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff)) ++ { ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]]; ++ // Point to bss report information ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ ++ // Update Rx power, in dBm ++ // Get the original RSSI readback from BBP ++ pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta; ++ // Average the Rssi reading ++ pBeaconReport->RxPower = (pBeaconReport->RxPower + pBss->Rssi) / 2; ++ // Get to dBm format ++ pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", ++ pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], ++ pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index])); ++ ++ // Update other information here ++ ++ // Done ++ return; ++ } ++ ++ // 2. Update reported Index ++ pAd->StaCfg.LastBssIndex = Index; ++ ++ // 3. Setup the buffer address for copying this BSSID into reporting frame ++ // The offset should start after 802.11 header and report frame header. ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ ++ // 4. Save the start offset of each Bss in report frame ++ pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen; ++ ++ // 5. Fill Measurement report fields ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ pReport->Length = 0; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_BEACON_REQ; ++ Length = sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ ++ // 6. Start thebeacon report format ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ pDest += sizeof(BEACON_REPORT); ++ Length += sizeof(BEACON_REPORT); ++ ++ // 7. Copy Channel number ++ pBeaconReport->Channel = pBss->Channel; ++ pBeaconReport->Spare = 0; ++ pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; ++ pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); ++ // 8. Rx power, in dBm ++ pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ", ++ pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], ++ pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256)); ++ DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen)); ++ ++ pBeaconReport->BeaconInterval = pBss->BeaconPeriod; ++ COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3); ++ NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4); ++ NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4); ++ ++ // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo ++ pSrc += (TIMESTAMP_LEN + 2); ++ pBeaconReport->CapabilityInfo = *(USHORT *)pSrc; ++ ++ // 10. Point to start of element ID ++ pSrc += 2; ++ pEid = (PEID_STRUCT) pSrc; ++ ++ // 11. Start process all variable Eid oayload and add the appropriate to the frame report ++ while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen)) ++ { ++ // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate, ++ // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set, ++ // TIM (report first 4 bytes only, radio measurement capability ++ switch (pEid->Eid) ++ { ++ case IE_SSID: ++ case IE_SUPP_RATES: ++ case IE_FH_PARM: ++ case IE_DS_PARM: ++ case IE_CF_PARM: ++ case IE_IBSS_PARM: ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ break; ++ ++ case IE_MEASUREMENT_CAPABILITY: ++ // Since this IE is duplicated with WPA security IE, we has to do sanity check before ++ // recognize it. ++ // 1. It also has fixed 6 bytes IE length. ++ if (pEid->Len != 6) ++ break; ++ // 2. Check the Cisco Aironet OUI ++ if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3)) ++ { ++ // Matched, this is what we want ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ } ++ break; ++ ++ case IE_TIM: ++ if (pEid->Len > 4) ++ { ++ // May truncate and report the first 4 bytes only, with the eid & len, total should be 6 ++ NdisMoveMemory(pDest, pEid, 6); ++ pDest += 6; ++ Length += 6; ++ } ++ else ++ { ++ NdisMoveMemory(pDest, pEid, pEid->Len + 2); ++ pDest += (pEid->Len + 2); ++ Length += (pEid->Len + 2); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ // 12. Move to next element ID ++ pSrc += (2 + pEid->Len); ++ pEid = (PEID_STRUCT) pSrc; ++ } ++ ++ // 13. Update the length in the header, not include EID and length ++ pReport->Length = Length - 4; ++ ++ // 14. Update the frame report buffer data length ++ pAd->StaCfg.FrameReportLen += Length; ++ DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen)); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ ++ Arguments: ++ Index Current BSSID in CCXBsstab entry index ++ ++ Return Value: ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID AironetCreateBeaconReportFromBssTable( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PMEASUREMENT_REPORT_ELEMENT pReport; ++ PBEACON_REPORT pBeaconReport; ++ UCHAR Index, ReqIdx; ++ USHORT Length; ++ PUCHAR pDest; ++ PBSS_ENTRY pBss; ++ ++ // 0. setup base pointer ++ ReqIdx = pAd->StaCfg.CurrentRMReqIdx; ++ ++ for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++) ++ { ++ // 1. Setup the buffer address for copying this BSSID into reporting frame ++ // The offset should start after 802.11 header and report frame header. ++ pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen]; ++ pBss = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index]; ++ Length = 0; ++ ++ // 2. Fill Measurement report fields ++ pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest; ++ pReport->Eid = IE_MEASUREMENT_REPORT; ++ pReport->Length = 0; ++ pReport->Token = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token; ++ pReport->Mode = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode; ++ pReport->Type = MSRN_TYPE_BEACON_REQ; ++ Length = sizeof(MEASUREMENT_REPORT_ELEMENT); ++ pDest += sizeof(MEASUREMENT_REPORT_ELEMENT); ++ ++ // 3. Start the beacon report format ++ pBeaconReport = (PBEACON_REPORT) pDest; ++ pDest += sizeof(BEACON_REPORT); ++ Length += sizeof(BEACON_REPORT); ++ ++ // 4. Copy Channel number ++ pBeaconReport->Channel = pBss->Channel; ++ pBeaconReport->Spare = 0; ++ pBeaconReport->Duration = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration; ++ pBeaconReport->PhyType = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS); ++ pBeaconReport->RxPower = pBss->Rssi - pAd->BbpRssiToDbmDelta; ++ pBeaconReport->BeaconInterval = pBss->BeaconPeriod; ++ pBeaconReport->CapabilityInfo = pBss->CapabilityInfo; ++ COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid); ++ NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4); ++ NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8); ++ ++ // 5. Create SSID ++ *pDest++ = 0x00; ++ *pDest++ = pBss->SsidLen; ++ NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen); ++ pDest += pBss->SsidLen; ++ Length += (2 + pBss->SsidLen); ++ ++ // 6. Create SupportRates ++ *pDest++ = 0x01; ++ *pDest++ = pBss->SupRateLen; ++ NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen); ++ pDest += pBss->SupRateLen; ++ Length += (2 + pBss->SupRateLen); ++ ++ // 7. DS Parameter ++ *pDest++ = 0x03; ++ *pDest++ = 1; ++ *pDest++ = pBss->Channel; ++ Length += 3; ++ ++ // 8. IBSS parameter if presents ++ if (pBss->BssType == BSS_ADHOC) ++ { ++ *pDest++ = 0x06; ++ *pDest++ = 2; ++ *(PUSHORT) pDest = pBss->AtimWin; ++ pDest += 2; ++ Length += 4; ++ } ++ ++ // 9. Update length field, not include EID and length ++ pReport->Length = Length - 4; ++ ++ // 10. Update total frame size ++ pAd->StaCfg.FrameReportLen += Length; ++ } ++} +--- /dev/null ++++ b/drivers/staging/rt3070/sta/assoc.c +@@ -0,0 +1,2060 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ assoc.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-9-3 porting from RT2500 ++*/ ++#include "../rt_config.h" ++ ++UCHAR CipherWpaTemplate[] = { ++ 0xdd, // WPA IE ++ 0x16, // Length ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x01 // authentication ++ }; ++ ++UCHAR CipherWpa2Template[] = { ++ 0x30, // RSN IE ++ 0x14, // Length ++ 0x01, 0x00, // Version ++ 0x00, 0x0f, 0xac, 0x02, // group cipher, TKIP ++ 0x01, 0x00, // number of pairwise ++ 0x00, 0x0f, 0xac, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x0f, 0xac, 0x02, // authentication ++ 0x00, 0x00, // RSN capability ++ }; ++ ++UCHAR Ccx2IeInfo[] = { 0x00, 0x40, 0x96, 0x03, 0x02}; ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE); ++ ++ // first column ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction); ++ StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ ++ // second column ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); ++ // ++ // Patch 3Com AP MOde:3CRWE454G72 ++ // We send Assoc request frame to this AP, it always send Reassoc Rsp not Associate Rsp. ++ // ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction); ++ StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction); ++ ++ // third column ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); ++ // ++ // Patch, AP doesn't send Reassociate Rsp frame to Station. ++ // ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction); ++ StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction); ++ ++ // fourth column ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction); ++ StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction); ++ ++ // initialize the timer ++ RTMPInitTimer(pAd, &pAd->MlmeAux.AssocTimer, GET_TIMER_FUNCTION(AssocTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.ReassocTimer, GET_TIMER_FUNCTION(ReassocTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.DisassocTimer, GET_TIMER_FUNCTION(DisassocTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Association timeout procedure. After association timeout, this function ++ will be called and it will put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Reassociation timeout procedure. After reassociation timeout, this ++ function will be called and put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ReassocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Disassociation timeout procedure. After disassociation timeout, this ++ function will be called and put a message into the MLME queue ++ Parameters: ++ Standard timer parameters ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID DisassocTimeout(IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ mlme assoc req handling procedure ++ Parameters: ++ Adapter - Adapter pointer ++ Elem - MLME Queue Element ++ Pre: ++ the station has been authenticated and the following information is stored in the config ++ -# SSID ++ -# supported rates and their length ++ -# listen interval (Adapter->StaCfg.default_listen_count) ++ -# Transmit power (Adapter->StaCfg.tx_power) ++ Post : ++ -# An association request frame is generated and sent to the air ++ -# Association timer starts ++ -# Association state -> ASSOC_WAIT_RSP ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeAssocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR ApAddr[6]; ++ HEADER_802_11 AssocHdr; ++ UCHAR Ccx2Len = 5; ++ UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ USHORT ListenIntv; ++ ULONG Timeout; ++ USHORT CapabilityInfo; ++ BOOLEAN TimerCancelled; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ ULONG tmp; ++ USHORT VarIesOffset; ++ UCHAR CkipFlag; ++ UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; ++ UCHAR AironetCkipIe = IE_AIRONET_CKIP; ++ UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; ++ UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; ++ UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; ++ UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; ++ USHORT Status; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block Assoc request durning WPA block period!\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ // check sanity first ++ else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); ++ ++ // Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() allocate memory failed \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ // Add by James 03/06/27 ++ pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ // Association don't need to report MAC address ++ pAd->StaCfg.AssocInfo.AvailableRequestFixedIEs = ++ NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL; ++ pAd->StaCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo; ++ pAd->StaCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv; ++ // Only reassociate need this ++ //COPY_MAC_ADDR(pAd->StaCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, ApAddr); ++ pAd->StaCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ ++ NdisZeroMemory(pAd->StaCfg.ReqVarIEs, MAX_VIE_LEN); ++ // First add SSID ++ VarIesOffset = 0; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SsidLen, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ VarIesOffset += pAd->MlmeAux.SsidLen; ++ ++ // Second add Supported rates ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SupRateIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SupRateLen, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.SupRate, pAd->MlmeAux.SupRateLen); ++ VarIesOffset += pAd->MlmeAux.SupRateLen; ++ // End Add by James ++ ++ if ((pAd->CommonCfg.Channel > 14) && ++ (pAd->CommonCfg.bIEEE80211H == TRUE)) ++ CapabilityInfo |= 0x0100; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send ASSOC request...\n")); ++ MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, ApAddr, ApAddr); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AssocHdr, ++ 2, &CapabilityInfo, ++ 2, &ListenIntv, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) ++ { ++ HtLen = SIZE_HT_CAP_IE + 4; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisZeroMemory(&HtCapabilityTmp, sizeof(HT_CAPABILITY_IE)); ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->MlmeAux.HtCapability, pAd->MlmeAux.HtCapabilityLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen,&HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION ++ // Case I: (Aggregation + Piggy-Back) ++ // 1. user enable aggregation, AND ++ // 2. Mac support piggy-back ++ // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON ++ // Case II: (Aggregation) ++ // 1. user enable aggregation, AND ++ // 2. AP annouces it's AGGREGATION-capable in BEACON ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ } ++ else ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x06, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ ++ if (pAd->MlmeAux.APEdcaParm.bValid) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) ++ { ++ QBSS_STA_INFO_PARM QosInfo; ++ ++ NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); ++ QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; ++ QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; ++ QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; ++ QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; ++ QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; ++ WmeIe[8] |= *(PUCHAR)&QosInfo; ++ } ++ else ++ { ++ // The Parameter Set Count is set to ¡§0¡¨ in the association request frames ++ // WmeIe[8] |= (pAd->MlmeAux.APEdcaParm.EdcaUpdateCount & 0x0f); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 9, &WmeIe[0], ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // ++ // Let WPA(#221) Element ID on the end of this association frame. ++ // Otherwise some AP will fail on parsing Element ID and set status fail on Assoc Rsp. ++ // For example: Put Vendor Specific IE on the front of WPA IE. ++ // This happens on AP (Model No:Linksys WRK54G) ++ // ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ++ ) ++ ) ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ { ++ RSNIe = IE_WPA2; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP != 1) ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ ++ // Check for WPA PMK cache list ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ++ { ++ INT idx; ++ BOOLEAN FoundPMK = FALSE; ++ // Search chched PMKID, append it if existed ++ for (idx = 0; idx < PMKID_NO; idx++) ++ { ++ if (NdisEqualMemory(ApAddr, &pAd->StaCfg.SavedPMK[idx].BSSID, 6)) ++ { ++ FoundPMK = TRUE; ++ break; ++ } ++ } ++ ++ if (FoundPMK) ++ { ++ // Set PMK number ++ *(PUSHORT) &pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len] = 1; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len + 2], &pAd->StaCfg.SavedPMK[idx].PMKID, 16); ++ pAd->StaCfg.RSNIE_Len += 18; ++ } ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == 1) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ } ++ else ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ } ++ ++ FrameLen += tmp; ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP != 1) ++#endif ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ // Append Variable IE ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); ++ VarIesOffset += 1; ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->StaCfg.RSNIE_Len, 1); ++ VarIesOffset += 1; ++ } ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ VarIesOffset += pAd->StaCfg.RSNIE_Len; ++ ++ // Set Variable IEs Length ++ pAd->StaCfg.ReqVarIELen = VarIesOffset; ++ } ++ ++ // We have update that at PeerBeaconAtJoinRequest() ++ CkipFlag = pAd->StaCfg.CkipFlag; ++ if (CkipFlag != 0) ++ { ++ NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); ++ CkipNegotiationBuffer[2] = 0x66; ++ // Make it try KP & MIC, since we have to follow the result from AssocRsp ++ CkipNegotiationBuffer[8] = 0x18; ++ CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; ++ CkipFlag = 0x18; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCkipIe, ++ 1, &AironetCkipLen, ++ AironetCkipLen, CkipNegotiationBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // Add CCX v2 request if CCX2 admin state is on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ { ++ ++ // ++ // Add AironetIPAddressIE for Cisco CCX 2.X ++ // Add CCX Version ++ // ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetIPAddressIE, ++ 1, &AironetIPAddressLen, ++ AironetIPAddressLen, AironetIPAddressBuffer, ++ 1, &Ccx2Ie, ++ 1, &Ccx2Len, ++ Ccx2Len, Ccx2IeInfo, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // ++ // Add CipherSuite CCKM or LeapTkip if setting. ++ // ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCiscoCCKMLen, CipherSuiteCiscoCCKM, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // Third add RSN ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); //Save CipherSuite ++ VarIesOffset += CipherSuiteCiscoCCKMLen; ++ } ++ else if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCCXTkipLen, CipherSuiteCCXTkip, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // Third add RSN ++ NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, CipherSuiteCCXTkip, CipherSuiteCCXTkipLen); ++ VarIesOffset += CipherSuiteCCXTkipLen; ++ } ++#endif // LEAP_SUPPORT // ++ ++ // Add by James 03/06/27 ++ // Set Variable IEs Length ++ pAd->StaCfg.ReqVarIELen = VarIesOffset; ++ pAd->StaCfg.AssocInfo.RequestIELength = VarIesOffset; ++ ++ // OffsetResponseIEs follow ReqVarIE ++ pAd->StaCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->StaCfg.ReqVarIELen; ++ // End Add by James ++ } ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AssocTimer, Timeout); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ mlme reassoc req handling procedure ++ Parameters: ++ Elem - ++ Pre: ++ -# SSID (Adapter->StaCfg.ssid[]) ++ -# BSSID (AP address, Adapter->StaCfg.bssid) ++ -# Supported rates (Adapter->StaCfg.supported_rates[]) ++ -# Supported rates length (Adapter->StaCfg.supported_rates_len) ++ -# Tx power (Adapter->StaCfg.tx_power) ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeReassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR ApAddr[6]; ++ HEADER_802_11 ReassocHdr; ++ UCHAR Ccx2Len = 5; ++ UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ USHORT CapabilityInfo, ListenIntv; ++ ULONG Timeout; ++ ULONG FrameLen = 0; ++ BOOLEAN TimerCancelled; ++ NDIS_STATUS NStatus; ++ ULONG tmp; ++ PUCHAR pOutBuffer = NULL; ++//CCX 2.X ++#ifdef LEAP_SUPPORT ++ UCHAR CkipFlag; ++ UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH]; ++ UCHAR AironetCkipIe = IE_AIRONET_CKIP; ++ UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH; ++ UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS; ++ UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH; ++ UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00}; ++ UCHAR AironetCCKMReassocIE = IE_AIRONET_CCKMREASSOC; ++ UCHAR AironetCCKMReassocLen = AIRONET_CCKMREASSOC_LENGTH; ++ UCHAR AironetCCKMReassocBuffer[AIRONET_CCKMREASSOC_LENGTH]; ++ UCHAR AironetOUI[] = {0x00, 0x40, 0x96, 0x00}; ++ UCHAR MICMN[16]; ++ UCHAR CalcMicBuffer[80]; ++ ULONG CalcMicBufferLen = 0; ++#endif // LEAP_SUPPORT // ++ USHORT Status; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block ReAssoc request durning WPA block period!\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ // the parameters are the same as the association ++ else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv)) ++ { ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() allocate memory failed \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr); ++ ++ // make frame, use bssid as the AP address?? ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send RE-ASSOC request...\n")); ++ MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, ApAddr, ApAddr); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &ReassocHdr, ++ 2, &CapabilityInfo, ++ 2, &ListenIntv, ++ MAC_ADDR_LEN, ApAddr, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ if (pAd->MlmeAux.APEdcaParm.bValid) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable) ++ { ++ QBSS_STA_INFO_PARM QosInfo; ++ ++ NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM)); ++ QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE; ++ QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK; ++ QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI; ++ QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO; ++ QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength; ++ WmeIe[8] |= *(PUCHAR)&QosInfo; ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 9, &WmeIe[0], ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // HT ++ if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE) ++ { ++ HtLen = SIZE_HT_CAP_IE + 4; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 1, &HtLen, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &pAd->MlmeAux.HtCapabilityLen, ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION ++ // Case I: (Aggregation + Piggy-Back) ++ // 1. user enable aggregation, AND ++ // 2. Mac support piggy-back ++ // 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON ++ // Case II: (Aggregation) ++ // 1. user enable aggregation, AND ++ // 2. AP annouces it's AGGREGATION-capable in BEACON ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++ } ++ else ++ { ++ ULONG TmpLen; ++ UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x04, 0x00, 0x00, 0x00}; ++ MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen, ++ 9, RalinkIe, ++ END_OF_ARGS); ++ FrameLen += TmpLen; ++ } ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ CkipFlag = pAd->StaCfg.CkipFlag; // We have update that at PeerBeaconAtJoinRequest() ++ if (CkipFlag != 0) ++ { ++ NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH); ++ CkipNegotiationBuffer[2] = 0x66; ++ // Make it try KP & MIC, since we have to follow the result from AssocRsp ++ CkipNegotiationBuffer[8] = 0x18; ++ CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCkipIe, ++ 1, &AironetCkipLen, ++ AironetCkipLen, CkipNegotiationBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetIPAddressIE, ++ 1, &AironetIPAddressLen, ++ AironetIPAddressLen, AironetIPAddressBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ // ++ // The RN is incremented before each reassociation request. ++ // ++ pAd->StaCfg.CCKMRN++; ++ // ++ // Calculate MIC = hmac-md5(krk, STA-ID|BSSID|RSNIE|TSF|RN); ++ // ++ COPY_MAC_ADDR(CalcMicBuffer, pAd->CurrentAddress); ++ CalcMicBufferLen = MAC_ADDR_LEN; ++ COPY_MAC_ADDR(CalcMicBuffer + CalcMicBufferLen, pAd->MlmeAux.Bssid); ++ CalcMicBufferLen += MAC_ADDR_LEN; ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, CipherSuiteCiscoCCKM, CipherSuiteCiscoCCKMLen); ++ CalcMicBufferLen += CipherSuiteCiscoCCKMLen; ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR) &pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp)); ++ CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMBeaconAtJoinTimeStamp); ++ NdisMoveMemory(CalcMicBuffer + CalcMicBufferLen, (PUCHAR)&pAd->StaCfg.CCKMRN, sizeof(pAd->StaCfg.CCKMRN)); ++ CalcMicBufferLen += sizeof(pAd->StaCfg.CCKMRN); ++ hmac_md5(pAd->StaCfg.KRK, LEN_EAP_MICK, CalcMicBuffer, CalcMicBufferLen, MICMN); ++ ++ // ++ // fill up CCKM reassociation request element ++ // ++ NdisMoveMemory(AironetCCKMReassocBuffer, AironetOUI, 4); ++ NdisMoveMemory(AironetCCKMReassocBuffer + 4, (PUCHAR)&pAd->StaCfg.CCKMBeaconAtJoinTimeStamp, 8); ++ NdisMoveMemory(AironetCCKMReassocBuffer + 12, (PUCHAR) &pAd->StaCfg.CCKMRN, 4); ++ NdisMoveMemory(AironetCCKMReassocBuffer +16, MICMN, 8); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &AironetCCKMReassocIE, ++ 1, &AironetCCKMReassocLen, ++ AironetCCKMReassocLen, AironetCCKMReassocBuffer, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ CipherSuiteCiscoCCKMLen,CipherSuiteCiscoCCKM, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++#endif // LEAP_SUPPORT // ++ ++ // Add CCX v2 request if CCX2 admin state is on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ { ++ // ++ // Add CCX Version ++ // ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &Ccx2Ie, ++ 1, &Ccx2Len, ++ Ccx2Len, Ccx2IeInfo, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.ReassocTimer, Timeout); /* in mSec */ ++ pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Upper layer issues disassoc request ++ Parameters: ++ Elem - ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDisassocReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PMLME_DISASSOC_REQ_STRUCT pDisassocReq; ++ HEADER_802_11 DisassocHdr; ++ PHEADER_802_11 pDisassocHdr; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ NDIS_STATUS NStatus; ++ BOOLEAN TimerCancelled; ++ ULONG Timeout = 0; ++ USHORT Status; ++ ++#ifdef QOS_DLS_SUPPORT ++ // send DLS-TEAR_DOWN message, ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ UCHAR i; ++ ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ } ++ } ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // skip sanity check ++ pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - MlmeDisassocReqAction() allocate memory failed\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++ return; ++ } ++ ++ ++ ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &TimerCancelled); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send DISASSOC request[BSSID::%02x:%02x:%02x:%02x:%02x:%02x (Reason=%d)\n", ++ pDisassocReq->Addr[0], pDisassocReq->Addr[1], pDisassocReq->Addr[2], ++ pDisassocReq->Addr[3], pDisassocReq->Addr[4], pDisassocReq->Addr[5], pDisassocReq->Reason)); ++ MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pDisassocReq->Addr, pDisassocReq->Addr); // patch peap ttls switching issue ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DisassocHdr, ++ 2, &pDisassocReq->Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ // To patch Instance and Buffalo(N) AP ++ // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine ++ // Therefore, we send both of them. ++ pDisassocHdr = (PHEADER_802_11)pOutBuffer; ++ pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING; ++ COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr); ++ ++ RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */ ++ pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends assoc rsp back ++ Parameters: ++ Elme - MLME message containing the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAssocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo, Status, Aid; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ BOOLEAN TimerCancelled; ++ UCHAR CkipFlag; ++ EDCA_PARM EdcaParm; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, ++ &HtCapability,&AddHtInfo, &HtCapabilityLen,&AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) ++ { ++ // The frame is for me ? ++ if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status)); ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++#endif // DOT11_N_SUPPORT // ++ RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled); ++ if(Status == MLME_SUCCESS) ++ { ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR idx; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (idx=0; idxMacTab.Content[BSSID_WCID], MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo); ++ ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ if (CkipFlag & 0x18) ++ { ++ NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); ++ pAd->StaCfg.GIV[0] = RandomByte(pAd); ++ pAd->StaCfg.GIV[1] = RandomByte(pAd); ++ pAd->StaCfg.GIV[2] = RandomByte(pAd); ++ pAd->StaCfg.bCkipOn = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); ++ } ++ } ++ else ++ { ++ // Faile on Association, we need to check the status code ++ // Is that a Rogue AP? ++#ifdef LEAP_SUPPORT ++ if ((pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) && (Status == MLME_ALG_NOT_SUPPORT)) ++ { //Possibly Rogue AP ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, pAd->MlmeAux.Bssid, LEAP_REASON_INVALID_AUTH); ++ } ++#endif // LEAP_SUPPORT // ++ } ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerAssocRspAction() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends reassoc rsp ++ Parametrs: ++ Elem - MLME message cntaining the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerReassocRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo; ++ USHORT Status; ++ USHORT Aid; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen; ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ UCHAR CkipFlag; ++ BOOLEAN TimerCancelled; ++ EDCA_PARM EdcaParm; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen, ++ &HtCapability, &AddHtInfo, &HtCapabilityLen, &AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag)) ++ { ++ if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) // The frame is for me ? ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status)); ++ RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled); ++ ++ if(Status == MLME_SUCCESS) ++ { ++ // go to procedure listed on page 376 ++ AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ } ++ ++ // ++ // Cisco Leap CCKM supported Re-association. ++ // ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ if (CCKMAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen) == TRUE) ++ { ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ if (CkipFlag & 0x18) ++ { ++ NdisZeroMemory(pAd->StaCfg.TxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.RxSEQ, 4); ++ NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4); ++ pAd->StaCfg.GIV[0] = RandomByte(pAd); ++ pAd->StaCfg.GIV[1] = RandomByte(pAd); ++ pAd->StaCfg.GIV[2] = RandomByte(pAd); ++ pAd->StaCfg.bCkipOn = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, (" pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag)); ++ } ++ ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - CCKMAssocRspSanity() sanity check fail\n")); ++ } ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ // CkipFlag is no use for reassociate ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerReassocRspAction() sanity check fail\n")); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ procedures on IEEE 802.11/1999 p.376 ++ Parametrs: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocPostProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr2, ++ IN USHORT CapabilityInfo, ++ IN USHORT Aid, ++ IN UCHAR SupRate[], ++ IN UCHAR SupRateLen, ++ IN UCHAR ExtRate[], ++ IN UCHAR ExtRateLen, ++ IN PEDCA_PARM pEdcaParm, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN ADD_HT_INFO_IE *pAddHtInfo) // AP might use this additional ht info IE ++{ ++ ULONG Idx; ++ ++ pAd->MlmeAux.BssType = BSS_INFRA; ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2); ++ pAd->MlmeAux.Aid = Aid; ++ pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; ++#ifdef DOT11_N_SUPPORT ++ // Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on. ++ if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE)) ++ { ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->Aifsn[0] = 3; ++ pEdcaParm->Aifsn[1] = 7; ++ pEdcaParm->Aifsn[2] = 2; ++ pEdcaParm->Aifsn[3] = 2; ++ ++ pEdcaParm->Cwmin[0] = 4; ++ pEdcaParm->Cwmin[1] = 4; ++ pEdcaParm->Cwmin[2] = 3; ++ pEdcaParm->Cwmin[3] = 2; ++ ++ pEdcaParm->Cwmax[0] = 10; ++ pEdcaParm->Cwmax[1] = 10; ++ pEdcaParm->Cwmax[2] = 4; ++ pEdcaParm->Cwmax[3] = 3; ++ ++ pEdcaParm->Txop[0] = 0; ++ pEdcaParm->Txop[1] = 0; ++ pEdcaParm->Txop[2] = 96; ++ pEdcaParm->Txop[3] = 48; ++ ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM)); ++ ++ // filter out un-supported rates ++ pAd->MlmeAux.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ ++ // filter out un-supported rates ++ pAd->MlmeAux.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++ ++#ifdef DOT11_N_SUPPORT ++ if (HtCapabilityLen > 0) ++ { ++ RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> AP.AMsduSize = %d. ClientStatusFlags = 0x%lx \n", pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n", ++ pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize)); ++#endif // DOT11_N_SUPPORT // ++ ++ // Set New WPA information ++ Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel); ++ if (Idx == BSS_NOT_FOUND) ++ { ++ DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n")); ++ } ++ else ++ { ++ // Init variable ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0; ++ NdisZeroMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, MAX_LEN_OF_RSNIE); ++ ++ // Store appropriate RSN_IE for WPA SM negotiation later ++ if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAd->ScanTab.BssEntry[Idx].VarIELen != 0)) ++ { ++ PUCHAR pVIE; ++ USHORT len; ++ PEID_STRUCT pEid; ++ ++ pVIE = pAd->ScanTab.BssEntry[Idx].VarIEs; ++ len = pAd->ScanTab.BssEntry[Idx].VarIELen; ++ ++ while (len > 0) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // For WPA/WPAPSK ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) ++ && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA SM negotiation \n")); ++ } ++ // For WPA2/WPA2PSK ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) ++ && (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2)); ++ pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA2 SM negotiation \n")); ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ } ++ ++ if (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> no RSN_IE \n")); ++ } ++ else ++ { ++ hex_dump("RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ left part of IEEE 802.11/1999 p.374 ++ Parameters: ++ Elem - MLME message containing the received frame ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDisassocAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Reason; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction()\n")); ++ if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() Reason = %d\n", Reason)); ++ if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, Addr2)) ++ { ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ // Cisco_LEAP has start a timer ++ // We should cancel it if using LEAP ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); ++ //Check is it mach the LEAP Authentication failed as possible a Rogue AP ++ //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Association. ++ if ((pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE) && (pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); ++ } ++ } ++#endif // LEAP_SUPPORT // ++ // ++ // Get Current System time and Turn on AdjacentAPReport ++ // ++ NdisGetSystemUpTime(&pAd->StaCfg.CCXAdjacentAPLinkDownTime); ++ pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; ++ LinkDown(pAd, TRUE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() sanity check fail\n")); ++ } ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after assoc timeout ++ Parameters: ++ Elme - ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AssocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - AssocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after reassoc timeout ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ReassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - ReassocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ what the state machine will do after disassoc timeout ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID DisassocTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - DisassocTimeoutAction\n")); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenAssoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenAssoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenReassoc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenReassoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status); ++} ++ ++VOID InvalidStateWhenDisassociate( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenDisassoc(state=%ld), reset ASSOC state machine\n", ++ pAd->Mlme.AssocMachine.CurrState)); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ right part of IEEE 802.11/1999 page 374 ++ Note: ++ This event should never cause ASSOC state machine perform state ++ transition, and has no relationship with CNTL machine. So we separate ++ this routine as a service outside of ASSOC state transition table. ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID Cls3errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr) ++{ ++ HEADER_802_11 DisassocHdr; ++ PHEADER_802_11 pDisassocHdr; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ NDIS_STATUS NStatus; ++ USHORT Reason = REASON_CLS3ERR; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Class 3 Error, Send DISASSOC frame\n")); ++ MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, pAd->CommonCfg.Bssid); // patch peap ttls switching issue ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DisassocHdr, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ // To patch Instance and Buffalo(N) AP ++ // Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine ++ // Therefore, we send both of them. ++ pDisassocHdr = (PHEADER_802_11)pOutBuffer; ++ pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH; ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DisassocReason = REASON_CLS3ERR; ++ COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pAddr); ++} ++ ++ /* ++ ========================================================================== ++ Description: ++ Switch between WEP and CKIP upon new association up. ++ Parameters: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID SwitchBetweenWepAndCkip( ++ IN PRTMP_ADAPTER pAd) ++{ ++ int i; ++ SHAREDKEY_MODE_STRUC csr1; ++ ++ // if KP is required. change the CipherAlg in hardware shard key table from WEP ++ // to CKIP. else remain as WEP ++ if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10)) ++ { ++ // modify hardware key table so that MAC use correct algorithm to decrypt RX ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); ++ if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP128; ++ ++ if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP64) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP64; ++ else if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP128) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP128; ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); ++ ++ // modify software key table so that driver can specify correct algorithm in TXD upon TX ++ for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_WEP64) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP64; ++ else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP128) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP128; ++ } ++ } ++ ++ // else if KP NOT inused. change the CipherAlg in hardware shard key table from CKIP ++ // to WEP. ++ else ++ { ++ // modify hardware key table so that MAC use correct algorithm to decrypt RX ++ RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word); ++ if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key0CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key1CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key2CipherAlg = CIPHER_WEP128; ++ ++ if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP64) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_WEP64; ++ else if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP128) ++ csr1.field.Bss0Key3CipherAlg = CIPHER_WEP128; ++ ++ // modify software key table so that driver can specify correct algorithm in TXD upon TX ++ for (i=0; iSharedKey[BSS0][i].CipherAlg == CIPHER_CKIP64) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP64; ++ else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP128) ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP128; ++ } ++ ++ // ++ // On WPA-NONE, must update CipherAlg. ++ // Because the OID_802_11_WEP_STATUS was been set after OID_802_11_ADD_KEY ++ // and CipherAlg will be CIPHER_NONE by Windows ZeroConfig. ++ // So we need to update CipherAlg after connect. ++ // ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ for (i = 0; i < SHARE_KEY_NUM; i++) ++ { ++ if (pAd->SharedKey[BSS0][i].KeyLen != 0) ++ { ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_TKIP; ++ } ++ else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_AES; ++ } ++ } ++ else ++ { ++ pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE; ++ } ++ } ++ ++ csr1.field.Bss0Key0CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ csr1.field.Bss0Key1CipherAlg = pAd->SharedKey[BSS0][1].CipherAlg; ++ csr1.field.Bss0Key2CipherAlg = pAd->SharedKey[BSS0][2].CipherAlg; ++ csr1.field.Bss0Key3CipherAlg = pAd->SharedKey[BSS0][3].CipherAlg; ++ } ++ RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg])); ++ } ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++VOID SendAssocIEsToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd) ++{ ++ union iwreq_data wrqu; ++ unsigned char custom[IW_CUSTOM_MAX] = {0}; ++ ++ if ((pAd->StaCfg.ReqVarIELen + 17) <= IW_CUSTOM_MAX) ++ { ++ sprintf(custom, "ASSOCINFO_ReqIEs="); ++ NdisMoveMemory(custom+17, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = pAd->StaCfg.ReqVarIELen + 17; ++ wrqu.data.flags = RT_REQIE_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOCINFO_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen + 17 > MAX_CUSTOM_LEN\n")); ++ ++ return; ++} ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++int wext_notify_event_assoc( ++ IN RTMP_ADAPTER *pAd) ++{ ++ union iwreq_data wrqu; ++ char custom[IW_CUSTOM_MAX] = {0}; ++ ++#if WIRELESS_EXT > 17 ++ if (pAd->StaCfg.ReqVarIELen <= IW_CUSTOM_MAX) ++ { ++ wrqu.data.length = pAd->StaCfg.ReqVarIELen; ++ memcpy(custom, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen); ++ wireless_send_event(pAd->net_dev, IWEVASSOCREQIE, &wrqu, custom); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen > MAX_CUSTOM_LEN\n")); ++#else ++ if (((pAd->StaCfg.ReqVarIELen*2) + 17) <= IW_CUSTOM_MAX) ++ { ++ UCHAR idx; ++ wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17; ++ sprintf(custom, "ASSOCINFO(ReqIEs="); ++ for (idx=0; idxStaCfg.ReqVarIELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAd->StaCfg.ReqVarIEs[idx]); ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("(pAd->StaCfg.ReqVarIELen*2) + 17 > MAX_CUSTOM_LEN\n")); ++#endif ++ ++ return 0; ++ ++} ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ ++BOOLEAN StaAddMacTableEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PMAC_TABLE_ENTRY pEntry, ++ IN UCHAR MaxSupportedRateIn500Kbps, ++ IN HT_CAPABILITY_IE *pHtCapability, ++ IN UCHAR HtCapabilityLen, ++ IN USHORT CapabilityInfo) ++{ ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ if (ADHOC_ON(pAd)) ++ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11G) && (MaxSupportedRate < RATE_FIRST_OFDM_RATE)) ++ return FALSE; ++ ++#ifdef DOT11_N_SUPPORT ++ // 11n only ++ if (((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))&& (HtCapabilityLen == 0)) ++ return FALSE; ++#endif // DOT11_N_SUPPORT // ++ ++ if (!pEntry) ++ return FALSE; ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ if (pEntry) ++ { ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ if ((MaxSupportedRate < RATE_FIRST_OFDM_RATE) || ++ (pAd->CommonCfg.PhyMode == PHY_11B)) ++ { ++ pEntry->RateLen = 4; ++ if (MaxSupportedRate >= RATE_FIRST_OFDM_RATE) ++ MaxSupportedRate = RATE_11; ++ } ++ else ++ pEntry->RateLen = 12; ++ ++ pEntry->MaxHTPhyMode.word = 0; ++ pEntry->MinHTPhyMode.word = 0; ++ pEntry->HTPhyMode.word = 0; ++ pEntry->MaxSupportedRate = MaxSupportedRate; ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ pEntry->CapabilityInfo = CapabilityInfo; ++ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE); ++ CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR i; ++ ++ if (ADHOC_ON(pAd)) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ if ((pHtCapability->HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((pHtCapability->HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(pHtCapability->HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(pHtCapability->HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // 3*3 ++ if (pAd->MACVersion >= RALINK_2883_VERSION && pAd->MACVersion < RALINK_3070_VERSION) ++ pEntry->MaxHTPhyMode.field.TxBF = pAd->CommonCfg.RegTransmitSetting.field.TxBF; ++ ++ // find max fixed rate ++ for (i=23; i>=0; i--) // 3*3 ++ { ++ j = i/8; ++ bitmask = (1<<(i-(j*8))); ++ if ((pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j] & bitmask) && (pHtCapability->MCSSet[j] & bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = i; ++ break; ++ } ++ if (i==0) ++ break; ++ } ++ ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE)) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED); ++ if (pHtCapability->HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (pHtCapability->HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (pHtCapability->HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (pHtCapability->HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (pHtCapability->ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (pHtCapability->ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ } ++ else ++ { ++ pAd->MacTab.fAnyStationIsLegacy = TRUE; ++ } ++ ++ NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE)); ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ ++ // Set asic auto fall back ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ // If the legacy mode is set, overwrite the transmit setting of this entry. ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ ++ pEntry->PortSecured = WPA_802_1X_PORT_SECURED; ++ pEntry->Sst = SST_ASSOC; ++ pEntry->AuthState = AS_AUTH_OPEN; ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ union iwreq_data wrqu; ++ ++ SendAssocIEsToWpaSupplicant(pAd); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_ASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ wext_notify_event_assoc(pAd); ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ return TRUE; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/auth.c +@@ -0,0 +1,475 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ auth.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-9-3 porting from RT2500 ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ authenticate state machine init, including state transition and timer init ++ Parameters: ++ Sm - pointer to the auth state machine ++ Note: ++ The state machine looks like this ++ ++ AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4 ++ MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth ++ MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action ++ MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++ ++void AuthStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE); ++ ++ // the first column ++ StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction); ++ ++ // the second column ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); ++ ++ // the third column ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action); ++ StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction); ++ ++ RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ function to be executed at timer thread when auth timer expires ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n")); ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) ++ return; ++ ++ // send a de-auth to reset AP's state machine (Patch AP-Dir635) ++ if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2) ++ Cls2errAction(pAd, pAd->MlmeAux.Bssid); ++ ++ ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeAuthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr[6]; ++ USHORT Alg, Seq, Status; ++ ULONG Timeout; ++ HEADER_802_11 AuthHdr; ++ BOOLEAN TimerCancelled; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ ++ // Block all authentication request durning WPA block period ++ if (pAd->StaCfg.bBlockAssoc == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg)) ++ { ++ // reset timer ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr); ++ pAd->MlmeAux.Alg = Alg; ++ Seq = 1; ++ Status = MLME_SUCCESS; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg)); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg)); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&AuthHdr, ++ 2, &Alg, ++ 2, &Seq, ++ 2, &Status, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2; ++ } ++ else ++ { ++ DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAuthRspAtSeq2Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Seq, Status, RemoteStatus, Alg; ++ UCHAR ChlgText[CIPHER_TEXT_LEN]; ++ UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8]; ++ UCHAR Element[2]; ++ HEADER_802_11 AuthHdr; ++ BOOLEAN TimerCancelled; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Status2; ++ ++ if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) ++ { ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status)); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ ++ if (Status == MLME_SUCCESS) ++ { ++ // Authentication Mode "LEAP" has allow for CCX 1.X ++ if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen) ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ { ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++#ifdef LEAP_SUPPORT ++ pAd->Mlme.LeapMachine.CurrState = LEAP_IDLE; ++#endif // LEAP_SUPPORT // ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ else ++ { ++ // 2. shared key, need to be challenged ++ Seq++; ++ RemoteStatus = MLME_SUCCESS; ++ ++ // Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if(NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status2 = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2); ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n")); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid); ++ AuthHdr.FC.Wep = 1; ++ // Encrypt challenge text & auth information ++ RTMPInitWepEngine( ++ pAd, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen, ++ CyperChlgText); ++ ++ Alg = cpu2le16(*(USHORT *)&Alg); ++ Seq = cpu2le16(*(USHORT *)&Seq); ++ RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus); ++ ++ RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2); ++ RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2); ++ RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2); ++ Element[0] = 16; ++ Element[1] = 128; ++ RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2); ++ RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128); ++ RTMPSetICV(pAd, CyperChlgText + 140); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AuthHdr, ++ CIPHER_TEXT_LEN + 16, CyperChlgText, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4; ++ } ++ } ++ else ++ { ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ //Invalid Authentication possible rogue AP ++ //Add this Ap to Rogue AP. ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_INVALID_AUTH); ++ } ++#endif // LEAP_SUPPORT // ++ pAd->StaCfg.AuthFailReason = Status; ++ COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerAuthRspAtSeq4Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Alg, Seq, Status; ++ CHAR ChlgText[CIPHER_TEXT_LEN]; ++ BOOLEAN TimerCancelled; ++ ++ if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText)) ++ { ++ if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n")); ++ RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled); ++ ++ if (Status != MLME_SUCCESS) ++ { ++ pAd->StaCfg.AuthFailReason = Status; ++ COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2); ++ } ++ ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n")); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDeauthReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ HEADER_802_11 DeauthHdr; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Status; ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_FAIL_NO_RESOURCE; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); ++ return; ++ } ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason)); ++ MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DeauthHdr, ++ 2, &pInfo->Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DeauthReason = pInfo->Reason; ++ COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status); ++ ++ // send wireless event - for deauthentication ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n")); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID InvalidStateWhenAuth( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState)); ++ pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Some STA/AP ++ Note: ++ This action should never trigger AUTH state transition, therefore we ++ separate it from AUTH state machine, and make it as a standalone service ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID Cls2errAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr) ++{ ++ HEADER_802_11 DeauthHdr; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT Reason = REASON_CLS2ERR; ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n")); ++ MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11),&DeauthHdr, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ pAd->StaCfg.DeauthReason = Reason; ++ COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr); ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/auth_rsp.c +@@ -0,0 +1,167 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ auth_rsp.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-10-1 copy from RT2560 ++*/ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ authentication state machine init procedure ++ Parameters: ++ Sm - the state machine ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++VOID AuthRspStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN PSTATE_MACHINE Sm, ++ IN STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE); ++ ++ // column 1 ++ StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); ++ ++ // column 2 ++ StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction); ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID PeerAuthSimpleRspGenAndSend( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHdr80211, ++ IN USHORT Alg, ++ IN USHORT Seq, ++ IN USHORT Reason, ++ IN USHORT Status) ++{ ++ HEADER_802_11 AuthHdr; ++ ULONG FrameLen = 0; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ++ if (Reason != MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Peer AUTH fail...\n")); ++ return; ++ } ++ ++ //Get an unused nonpaged memory ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send AUTH response (seq#2)...\n")); ++ MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, pHdr80211->Addr2, pAd->MlmeAux.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &AuthHdr, ++ 2, &Alg, ++ 2, &Seq, ++ 2, &Reason, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID PeerDeauthAction( ++ IN PRTMP_ADAPTER pAd, ++ IN PMLME_QUEUE_ELEM Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ USHORT Reason; ++ ++ if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason)) ++ { ++ if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(Addr2, pAd->CommonCfg.Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason)); ++ ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++ ++ // send wireless event - for deauthentication ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ LinkDown(pAd, TRUE); ++ ++ // Authentication Mode Cisco_LEAP has start a timer ++ // We should cancel it if using LEAP ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ RTMPCancelTimer(&pAd->StaCfg.LeapAuthTimer, &TimerCancelled); ++ //Check is it mach the LEAP Authentication failed as possible a Rogue AP ++ //on it's PortSecured not equal to WPA_802_1X_PORT_SECURED while process the Authenticaton. ++ if ((pAd->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED) && (pAd->Mlme.LeapMachine.CurrState != LEAP_IDLE)) ++ { ++ RogueApTableSetEntry(pAd, &pAd->StaCfg.RogueApTab, Addr2, LEAP_REASON_AUTH_TIMEOUT); ++ } ++ } ++#endif // LEAP_SUPPORT // ++ } ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - PeerDeauthAction() sanity check fail\n")); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/connect.c +@@ -0,0 +1,2857 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ connect.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John 2004-08-08 Major modification from RT2560 ++*/ ++#include "../rt_config.h" ++ ++UCHAR CipherSuiteWpaNoneTkip[] = { ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x00 // authentication ++ }; ++UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteWpaNoneAes[] = { ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x04, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x04, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x00 // authentication ++ }; ++UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR)); ++ ++// The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS, ++// or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS ++// All settings successfuly negotiated furing MLME state machines become final settings ++// and are copied to pAd->StaActive ++#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \ ++{ \ ++ (_pAd)->CommonCfg.SsidLen = (_pAd)->MlmeAux.SsidLen; \ ++ NdisMoveMemory((_pAd)->CommonCfg.Ssid, (_pAd)->MlmeAux.Ssid, (_pAd)->MlmeAux.SsidLen); \ ++ COPY_MAC_ADDR((_pAd)->CommonCfg.Bssid, (_pAd)->MlmeAux.Bssid); \ ++ (_pAd)->CommonCfg.Channel = (_pAd)->MlmeAux.Channel; \ ++ (_pAd)->CommonCfg.CentralChannel = (_pAd)->MlmeAux.CentralChannel; \ ++ (_pAd)->StaActive.Aid = (_pAd)->MlmeAux.Aid; \ ++ (_pAd)->StaActive.AtimWin = (_pAd)->MlmeAux.AtimWin; \ ++ (_pAd)->StaActive.CapabilityInfo = (_pAd)->MlmeAux.CapabilityInfo; \ ++ (_pAd)->CommonCfg.BeaconPeriod = (_pAd)->MlmeAux.BeaconPeriod; \ ++ (_pAd)->StaActive.CfpMaxDuration = (_pAd)->MlmeAux.CfpMaxDuration; \ ++ (_pAd)->StaActive.CfpPeriod = (_pAd)->MlmeAux.CfpPeriod; \ ++ (_pAd)->StaActive.SupRateLen = (_pAd)->MlmeAux.SupRateLen; \ ++ NdisMoveMemory((_pAd)->StaActive.SupRate, (_pAd)->MlmeAux.SupRate, (_pAd)->MlmeAux.SupRateLen);\ ++ (_pAd)->StaActive.ExtRateLen = (_pAd)->MlmeAux.ExtRateLen; \ ++ NdisMoveMemory((_pAd)->StaActive.ExtRate, (_pAd)->MlmeAux.ExtRate, (_pAd)->MlmeAux.ExtRateLen);\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APEdcaParm, &(_pAd)->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APQosCapability, &(_pAd)->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));\ ++ NdisMoveMemory(&(_pAd)->CommonCfg.APQbssLoad, &(_pAd)->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));\ ++ COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].Addr, (_pAd)->MlmeAux.Bssid); \ ++ (_pAd)->MacTab.Content[BSSID_WCID].Aid = (_pAd)->MlmeAux.Aid; \ ++ (_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = (_pAd)->StaCfg.PairCipher;\ ++ COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.BssId, (_pAd)->MlmeAux.Bssid);\ ++ (_pAd)->MacTab.Content[BSSID_WCID].RateLen = (_pAd)->StaActive.SupRateLen + (_pAd)->StaActive.ExtRateLen;\ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++*/ ++VOID MlmeCntlInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ // Control state machine differs from other state machines, the interface ++ // follows the standard interface ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID MlmeCntlMachinePerformAction( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ switch(pAd->Mlme.CntlMachine.CurrState) ++ { ++ case CNTL_IDLE: ++ { ++ CntlIdleProc(pAd, Elem); ++ } ++ break; ++ case CNTL_WAIT_DISASSOC: ++ CntlWaitDisassocProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_JOIN: ++ CntlWaitJoinProc(pAd, Elem); ++ break; ++ ++ // CNTL_WAIT_REASSOC is the only state in CNTL machine that does ++ // not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)". ++ // Therefore not protected by NDIS's "only one outstanding OID request" ++ // rule. Which means NDIS may SET OID in the middle of ROAMing attempts. ++ // Current approach is to block new SET request at RTMPSetInformation() ++ // when CntlMachine.CurrState is not CNTL_IDLE ++ case CNTL_WAIT_REASSOC: ++ CntlWaitReassocProc(pAd, Elem); ++ break; ++ ++ case CNTL_WAIT_START: ++ CntlWaitStartProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_AUTH: ++ CntlWaitAuthProc(pAd, Elem); ++ break; ++ case CNTL_WAIT_AUTH2: ++ CntlWaitAuthProc2(pAd, Elem); ++ break; ++ case CNTL_WAIT_ASSOC: ++ CntlWaitAssocProc(pAd, Elem); ++ break; ++ ++ case CNTL_WAIT_OID_LIST_SCAN: ++ if(Elem->MsgType == MT2_SCAN_CONF) ++ { ++ // Resume TxRing after SCANING complete. We hope the out-of-service time ++ // won't be too long to let upper layer time-out the waiting frames ++ RTMPResumeMsduTransmission(pAd); ++ if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) ++ { ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ ++ // ++ // Set LED status to previous status. ++ // ++ if (pAd->bLedOnScanning) ++ { ++ pAd->bLedOnScanning = FALSE; ++ RTMPSetLED(pAd, pAd->LedStatus); ++ } ++#ifdef DOT11N_DRAFT3 ++ // AP sent a 2040Coexistence mgmt frame, then station perform a scan, and then send back the respone. ++ if (pAd->CommonCfg.BSSCoexist2040.field.InfoReq == 1) ++ { ++ Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); ++ } ++#endif // DOT11N_DRAFT3 // ++ } ++ break; ++ ++ case CNTL_WAIT_OID_DISASSOC: ++ if (Elem->MsgType == MT2_DISASSOC_CONF) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++ break; ++#ifdef RT2870 ++ // ++ // This state is for that we want to connect to an AP but ++ // it didn't find on BSS List table. So we need to scan the air first, ++ // after that we can try to connect to the desired AP if available. ++ // ++ case CNTL_WAIT_SCAN_FOR_CONNECT: ++ if(Elem->MsgType == MT2_SCAN_CONF) ++ { ++ // Resume TxRing after SCANING complete. We hope the out-of-service time ++ // won't be too long to let upper layer time-out the waiting frames ++ RTMPResumeMsduTransmission(pAd); ++#ifdef CCX_SUPPORT ++ if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) ++ { ++ // Cisco scan request is finished, prepare beacon report ++ MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL); ++ } ++#endif // CCX_SUPPORT // ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ ++ // ++ // Check if we can connect to. ++ // ++ BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ if (pAd->MlmeAux.SsidBssTab.BssNr > 0) ++ { ++ MlmeAutoReconnectLastSSID(pAd); ++ } ++ } ++ break; ++#endif // RT2870 // ++ default: ++ DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType)); ++ break; ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlIdleProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ return; ++ ++ switch(Elem->MsgType) ++ { ++ case OID_802_11_SSID: ++ CntlOidSsidProc(pAd, Elem); ++ break; ++ ++ case OID_802_11_BSSID: ++ CntlOidRTBssidProc(pAd,Elem); ++ break; ++ ++ case OID_802_11_BSSID_LIST_SCAN: ++ CntlOidScanProc(pAd,Elem); ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAd->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); ++ } ++ break; ++ ++ case MT2_MLME_ROAMING_REQ: ++ CntlMlmeRoamingProc(pAd, Elem); ++ break; ++ ++ case OID_802_11_MIC_FAILURE_REPORT_FRAME: ++ WpaMicFailureReportFrame(pAd, Elem); ++ break; ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS_PARAM: ++ CntlOidDLSSetupProc(pAd, Elem); ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType)); ++ break; ++ } ++} ++ ++VOID CntlOidScanProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ULONG BssIdx = BSS_NOT_FOUND; ++ BSS_ENTRY CurrBss; ++ ++#ifdef RALINK_ATE ++/* Disable scanning when ATE is running. */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ ++ // record current BSS if network is connected. ++ // 2003-2-13 do not include current IBSS if this is the only STA in this IBSS. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ BssIdx = BssSsidTableSearch(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->CommonCfg.Channel); ++ if (BssIdx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(&CurrBss, &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); ++ } ++ } ++ ++ // clean up previous SCAN result, add current BSS back to table if any ++ BssTableInit(&pAd->ScanTab); ++ if (BssIdx != BSS_NOT_FOUND) ++ { ++ // DDK Note: If the NIC is associated with a particular BSSID and SSID ++ // that are not contained in the list of BSSIDs generated by this scan, the ++ // BSSID description of the currently associated BSSID and SSID should be ++ // appended to the list of BSSIDs in the NIC's database. ++ // To ensure this, we append this BSS as the first entry in SCAN result ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY)); ++ pAd->ScanTab.BssNr = 1; ++ } ++ ++ ScanParmFill(pAd, &ScanReq, "", 0, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, ++ sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Before calling this routine, user desired SSID should already been ++ recorded in CommonCfg.Ssid[] ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidSsidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem) ++{ ++ PNDIS_802_11_SSID pOidSsid = (NDIS_802_11_SSID *)Elem->Msg; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ULONG Now; ++ ++ // Step 1. record the desired user settings to MlmeAux ++ NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength); ++ pAd->MlmeAux.SsidLen = (UCHAR)pOidSsid->SsidLength; ++ NdisZeroMemory(pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ pAd->MlmeAux.BssType = pAd->StaCfg.BssType; ++ ++ ++ // ++ // Update Reconnect Ssid, that user desired to connect. ++ // ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; ++ ++ // step 2. find all matching BSS in the lastest SCAN result (inBssTab) ++ // & log them into MlmeAux.SsidBssTab for later-on iteration. Sort by RSSI order ++ BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - %d BSS of %d BSS match the desire (%d)SSID - %s\n", ++ pAd->MlmeAux.SsidBssTab.BssNr, pAd->ScanTab.BssNr, pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid)); ++ NdisGetSystemUpTime(&Now); ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ (pAd->CommonCfg.SsidLen == pAd->MlmeAux.SsidBssTab.BssEntry[0].SsidLen) && ++ NdisEqualMemory(pAd->CommonCfg.Ssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Ssid, pAd->CommonCfg.SsidLen) && ++ MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Bssid)) ++ { ++ // Case 1. already connected with an AP who has the desired SSID ++ // with highest RSSI ++ ++ // Add checking Mode "LEAP" for CCX 1.0 ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ // case 1.1 For WPA, WPA-PSK, if the 1x port is not secured, we have to redo ++ // connection process ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else if (pAd->bConfigChanged == TRUE) ++ { ++ // case 1.2 Important Config has changed, we have to reconnect to the same AP ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP Because config changed...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ // case 1.3. already connected to the SSID with highest RSSI. ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - already with this BSSID. ignore this SET_SSID request\n")); ++ // ++ // (HCT 12.1) 1c_wlan_mediaevents required ++ // media connect events are indicated when associating with the same AP ++ // ++ if (INFRA_ON(pAd)) ++ { ++ // ++ // Since MediaState already is NdisMediaStateConnected ++ // We just indicate the connect event again to meet the WHQL required. ++ // ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up ++ } ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ } ++ else if (INFRA_ON(pAd)) ++ { ++ // ++ // For RT61 ++ // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) ++ // RT61 may lost SSID, and not connect to NDTEST_WEP_AP2 and will connect to NDTEST_WEP_AP2 by Autoreconnect ++ // But media status is connected, so the SSID not report correctly. ++ // ++ if (!SSID_EQUAL(pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen)) ++ { ++ // ++ // Different SSID means not Roaming case, so we let LinkDown() to Indicate a disconnect event. ++ // ++ pAd->MlmeAux.CurrReqIsFromNdis = TRUE; ++ } ++ // case 2. active INFRA association existent ++ // roaming is done within miniport driver, nothing to do with configuration ++ // utility. so upon a new SET(OID_802_11_SSID) is received, we just ++ // disassociate with the current associated AP, ++ // then perform a new association with this new SSID, no matter the ++ // new/old SSID are the same or not. ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ if (ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - drop current ADHOC\n")); ++ LinkDown(pAd, FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); ++ } ++ ++ if ((pAd->MlmeAux.SsidBssTab.BssNr == 0) && ++ (pAd->StaCfg.bAutoReconnect == TRUE) && ++ (pAd->MlmeAux.BssType == BSS_INFRA) && ++ (MlmeValidateSSID(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen) == TRUE) ++ ) ++ { ++ MLME_SCAN_REQ_STRUCT ScanReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - No matching BSS, start a new scan\n")); ++ ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, BSS_ANY, SCAN_ACTIVE); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; ++ // Reset Missed scan number ++ pAd->StaCfg.LastScanTime = Now; ++ } ++ else ++ { ++ pAd->MlmeAux.BssIdx = 0; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidRTBssidProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM * Elem) ++{ ++ ULONG BssIdx; ++ PUCHAR pOidBssid = (PUCHAR)Elem->Msg; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ MLME_JOIN_REQ_STRUCT JoinReq; ++ ++#ifdef RALINK_ATE ++/* No need to perform this routine when ATE is running. */ ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ // record user desired settings ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid); ++ pAd->MlmeAux.BssType = pAd->StaCfg.BssType; ++ ++ // ++ // Update Reconnect Ssid, that user desired to connect. ++ // ++ NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID); ++ pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen; ++ NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ ++ // find the desired BSS in the latest SCAN result table ++ BssIdx = BssTableSearch(&pAd->ScanTab, pOidBssid, pAd->MlmeAux.Channel); ++ if (BssIdx == BSS_NOT_FOUND) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ return; ++ } ++ ++ // copy the matched BSS entry from ScanTab to MlmeAux.SsidBssTab. Why? ++ // Because we need this entry to become the JOIN target in later on SYNC state machine ++ pAd->MlmeAux.BssIdx = 0; ++ pAd->MlmeAux.SsidBssTab.BssNr = 1; ++ NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY)); ++ ++ //pAd->MlmeAux.AutoReconnectSsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; ++ //NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->ScanTab.BssEntry[BssIdx].SsidLen); ++ ++ // Add SSID into MlmeAux for site surey joining hidden SSID ++ //pAd->MlmeAux.SsidLen = pAd->ScanTab.BssEntry[BssIdx].SsidLen; ++ //NdisMoveMemory(pAd->MlmeAux.Ssid, pAd->ScanTab.BssEntry[BssIdx].Ssid, pAd->MlmeAux.SsidLen); ++ ++ // 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP ++ // we just follow normal procedure. The reason of user doing this may because he/she changed ++ // AP to another channel, but we still received BEACON from it thus don't claim Link Down. ++ // Since user knows he's changed AP channel, he'll re-connect again. By skipping the following ++ // checking, we'll disassociate then re-do normal association with this AP at the new channel. ++ // 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do ++ // connection when setting the same BSSID. ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && ++ MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pOidBssid)) ++ { ++ // already connected to the same BSSID, go back to idle state directly ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ } ++ else ++ { ++ if (INFRA_ON(pAd)) ++ { ++ // disassoc from current AP first ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - disassociate with current AP ...\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, ++ sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ } ++ else ++ { ++ if (ADHOC_ON(pAd)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n")); ++ LinkDown(pAd, FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event C!\n")); ++ } ++ ++ // Change the wepstatus to original wepstatus ++ pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; ++ ++ // Check cipher suite, AP must have more secured cipher than station setting ++ // Set the Pairwise and Group cipher to match the intended AP setting ++ // We can only connect to AP with less secured cipher setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher; ++ else if (pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher; ++ else if (pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ ++ // RSN capability ++ pAd->StaCfg.RsnCapability = pAd->ScanTab.BssEntry[BssIdx].WPA2.RsnCapability; ++ } ++ ++ // Set Mix cipher flag ++ pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; ++ if (pAd->StaCfg.bMixCipher == TRUE) ++ { ++ // If mix cipher, re-build RSNIE ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ } ++ // No active association, join the BSS immediately ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pOidBssid[0],pOidBssid[1],pOidBssid[2],pOidBssid[3],pOidBssid[4],pOidBssid[5])); ++ ++ JoinParmFill(pAd, &JoinReq, pAd->MlmeAux.BssIdx); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; ++ } ++ } ++} ++ ++// Roaming is the only external request triggering CNTL state machine ++// despite of other "SET OID" operation. All "SET OID" related oerations ++// happen in sequence, because no other SET OID will be sent to this device ++// until the the previous SET operation is complete (successful o failed). ++// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"? ++// or been corrupted by other "SET OID"? ++// ++// IRQL = DISPATCH_LEVEL ++VOID CntlMlmeRoamingProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ // TODO: ++ // AP in different channel may show lower RSSI than actual value?? ++ // should we add a weighting factor to compensate it? ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - Roaming in MlmeAux.RoamTab...\n")); ++ ++ NdisMoveMemory(&pAd->MlmeAux.SsidBssTab, &pAd->MlmeAux.RoamTab, sizeof(pAd->MlmeAux.RoamTab)); ++ pAd->MlmeAux.SsidBssTab.BssNr = pAd->MlmeAux.RoamTab.BssNr; ++ ++ BssTableSortByRssi(&pAd->MlmeAux.SsidBssTab); ++ pAd->MlmeAux.BssIdx = 0; ++ IterateOnBssTab(pAd); ++} ++ ++#ifdef QOS_DLS_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlOidDLSSetupProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PRT_802_11_DLS pDLS = (PRT_802_11_DLS)Elem->Msg; ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ INT i; ++ USHORT reason = REASON_UNSPECIFY; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - (OID set %02x:%02x:%02x:%02x:%02x:%02x with Valid=%d, Status=%d, TimeOut=%d, CountDownTimer=%d)\n", ++ pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5], ++ pDLS->Valid, pDLS->Status, pDLS->TimeOut, pDLS->CountDownTimer)); ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ // DLS will not be supported when Adhoc mode ++ if (INFRA_ON(pAd)) ++ { ++ for (i = 0; i < MAX_NUM_OF_DLS_ENTRY; i++) ++ { ++ if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ (pDLS->TimeOut == pAd->StaCfg.DLSEntry[i].TimeOut) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 1. Same setting, just drop it ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - setting unchanged\n")); ++ break; ++ } ++ else if (!pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 2. Disable DLS link case, just tear down DLS link ++ reason = REASON_QOS_UNWANTED_MECHANISM; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - start tear down procedure\n")); ++ break; ++ } ++ else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && !pAd->StaCfg.DLSEntry[i].Valid) ++ { ++ // 3. Enable case, start DLS setup procedure ++ NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); ++ ++ //Update countdown timer ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS setup case\n")); ++ break; ++ } ++ else if ((i < MAX_NUM_OF_DLS_ENTRY) && pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && !MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 4. update mac case, tear down old DLS and setup new DLS ++ reason = REASON_QOS_UNWANTED_MECHANISM; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ NdisMoveMemory(&pAd->StaCfg.DLSEntry[i], pDLS, sizeof(RT_802_11_DLS_UI)); ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS tear down and restart case\n")); ++ break; ++ } ++ else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr) && (pAd->StaCfg.DLSEntry[i].TimeOut != pDLS->TimeOut)) ++ { ++ // 5. update timeout case, start DLS setup procedure (no tear down) ++ pAd->StaCfg.DLSEntry[i].TimeOut = pDLS->TimeOut; ++ //Update countdown timer ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS update timeout case\n")); ++ break; ++ } ++ else if (pDLS->Valid && pAd->StaCfg.DLSEntry[i].Valid && ++ (pAd->StaCfg.DLSEntry[i].Status != DLS_FINISH) && MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ // 6. re-setup case, start DLS setup procedure (no tear down) ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_REQ, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ DBGPRINT(RT_DEBUG_TRACE,("CNTL - DLS retry setup procedure\n")); ++ break; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN,("CNTL - DLS not changed in entry - %d - Valid=%d, Status=%d, TimeOut=%d\n", ++ i, pAd->StaCfg.DLSEntry[i].Valid, pAd->StaCfg.DLSEntry[i].Status, pAd->StaCfg.DLSEntry[i].TimeOut)); ++ } ++ } ++ } ++} ++#endif // QOS_DLS_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitDisassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ MLME_START_REQ_STRUCT StartReq; ++ ++ if (Elem->MsgType == MT2_DISASSOC_CONF) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Dis-associate successful\n")); ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ LinkDown(pAd, FALSE); ++ ++ // case 1. no matching BSS, and user wants ADHOC, so we just start a new one ++ if ((pAd->MlmeAux.SsidBssTab.BssNr==0) && (pAd->StaCfg.BssType == BSS_ADHOC)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ // case 2. try each matched BSS ++ else ++ { ++ pAd->MlmeAux.BssIdx = 0; ++ ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitJoinProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_JOIN_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ // 1. joined an IBSS, we are pretty much done here ++ if (pAd->MlmeAux.BssType == BSS_ADHOC) ++ { ++ // ++ // 5G bands rules of Japan: ++ // Ad hoc must be disabled in W53(ch52,56,60,64) channels. ++ // ++ if ( (pAd->CommonCfg.bIEEE80211H == 1) && ++ RadarChannelCheck(pAd, pAd->CommonCfg.Channel) ++ ) ++ { ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Join adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); ++ return; ++ } ++ ++ LinkUp(pAd, BSS_ADHOC); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - join the IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ } ++ // 2. joined a new INFRA network, start from authentication ++ else ++ { ++#ifdef LEAP_SUPPORT ++ // Add AuthMode "LEAP" for CCX 1.X ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); ++ } ++ else ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ } ++ } ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH; ++ } ++ } ++ else ++ { ++ // 3. failed, try next BSS ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitStartProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Result; ++ ++ if (Elem->MsgType == MT2_START_CONF) ++ { ++ NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); ++ if (Result == MLME_SUCCESS) ++ { ++ // ++ // 5G bands rules of Japan: ++ // Ad hoc must be disabled in W53(ch52,56,60,64) channels. ++ // ++ if ( (pAd->CommonCfg.bIEEE80211H == 1) && ++ RadarChannelCheck(pAd, pAd->CommonCfg.Channel) ++ ) ++ { ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel)); ++ return; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ N_ChannelCheck(pAd); ++ SetCommonHT(pAd); ++ NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &pAd->CommonCfg.AddHTInfo, sizeof(ADD_HT_INFO_IE)); ++ RTMPCheckHt(pAd, BSSID_WCID, &pAd->CommonCfg.HtCapability, &pAd->CommonCfg.AddHTInfo); ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ NdisZeroMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], 16); ++ NdisMoveMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], &pAd->CommonCfg.HtCapability.MCSSet[0], 16); ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ ++ if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) ++ { ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) ++ { ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ } ++ LinkUp(pAd, BSS_ADHOC); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ // Before send beacon, driver need do radar detection ++ if ((pAd->CommonCfg.Channel > 14 ) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE; ++ pAd->CommonCfg.RadarDetect.RDCount = 0; ++#ifdef DFS_SUPPORT ++ BbpRadarDetectionStart(pAd); ++#endif // DFS_SUPPORT // ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n", ++ pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5])); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Start IBSS fail. BUG!!!!!\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAuthProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_ASSOC_REQ_STRUCT AssocReq; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_AUTH_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); ++ AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ ++#ifdef LEAP_SUPPORT ++ // ++ // Cisco Leap CCKM supported Re-association. ++ // ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ { ++ //if CCKM is turn on , that's mean Fast Reauthentication ++ //Use CCKM Reassociation instead of normal association for Fast Roaming. ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; ++ } ++ } ++ else ++ { ++ // This fail may because of the AP already keep us in its MAC table without ++ // ageing-out. The previous authentication attempt must have let it remove us. ++ // so try Authentication again may help. For D-Link DWL-900AP+ compatibility. ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n")); ++#ifdef LEAP_SUPPORT ++ //Add AuthMode "LEAP" for CCX 1.X ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, CISCO_AuthModeLEAP); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch)) ++ { ++ // either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared); ++ } ++ else ++ { ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ } ++ } ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAuthProc2( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ MLME_ASSOC_REQ_STRUCT AssocReq; ++ MLME_AUTH_REQ_STRUCT AuthReq; ++ ++ if (Elem->MsgType == MT2_AUTH_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n")); ++ AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ, ++ sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC; ++ } ++ else ++ { ++#ifdef LEAP_SUPPORT ++ // Process LEAP first, since it use different control variable ++ // We don't want to affect other poven operation ++ if (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++ { ++ // LEAP Auth not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - *LEAP* AUTH FAIL, give up; try next BSS\n")); ++ DBGPRINT(RT_DEBUG_TRACE, ("Total match BSSID [=%d]\n", pAd->MlmeAux.SsidBssTab.BssNr)); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ else ++#endif // LEAP_SUPPORT // ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) && ++ (pAd->MlmeAux.Alg == Ndis802_11AuthModeShared)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try OPEN system...\n")); ++ AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen); ++ MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ, ++ sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2; ++ } ++ else ++ { ++ // not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, give up; try next BSS\n")); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //??????? ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitAssocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Reason; ++ ++ if (Elem->MsgType == MT2_ASSOC_CONF) ++ { ++ NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT)); ++ if (Reason == MLME_SUCCESS) ++ { ++ LinkUp(pAd, BSS_INFRA); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association successful on BSS #%ld\n",pAd->MlmeAux.BssIdx)); ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++ else ++ { ++ // not success, try next BSS ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association fails on BSS #%ld\n",pAd->MlmeAux.BssIdx)); ++ pAd->MlmeAux.BssIdx++; ++ IterateOnBssTab(pAd); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID CntlWaitReassocProc( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Result; ++ ++ if (Elem->MsgType == MT2_REASSOC_CONF) ++ { ++ NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT)); ++ if (Result == MLME_SUCCESS) ++ { ++ // ++ // NDIS requires a new Link UP indication but no Link Down for RE-ASSOC ++ // ++ LinkUp(pAd, BSS_INFRA); ++ ++ // send wireless event - for association ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ ++#ifdef LEAP_SUPPORT ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ STA_PORT_SECURED(pAd); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++#endif // LEAP_SUPPORT // ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); ++ } ++ else ++ { ++ // reassoc failed, try to pick next BSS in the BSS Table ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition fails on BSS #%ld\n", pAd->MlmeAux.RoamIdx)); ++ pAd->MlmeAux.RoamIdx++; ++ IterateOnBssTab2(pAd); ++ } ++ } ++} ++ ++ ++VOID AdhocTurnOnQos( ++ IN PRTMP_ADAPTER pAd) ++{ ++#define AC0_DEF_TXOP 0 ++#define AC1_DEF_TXOP 0 ++#define AC2_DEF_TXOP 94 ++#define AC3_DEF_TXOP 47 ++ ++ // Turn on QOs if use HT rate. ++ if (pAd->CommonCfg.APEdcaParm.bValid == FALSE) ++ { ++ pAd->CommonCfg.APEdcaParm.bValid = TRUE; ++ pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3; ++ pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7; ++ pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1; ++ pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3; ++ pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2; ++ ++ pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10; ++ pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6; ++ pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4; ++ pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3; ++ ++ pAd->CommonCfg.APEdcaParm.Txop[0] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[1] = 0; ++ pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP; ++ pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP; ++ } ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID LinkUp( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR BssType) ++{ ++ ULONG Now; ++ UINT32 Data; ++ BOOLEAN Cancelled; ++ UCHAR Value = 0, idx; ++ MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; ++ ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ ++ // ++ // ASSOC - DisassocTimeoutAction ++ // CNTL - Dis-associate successful ++ // !!! LINK DOWN !!! ++ // [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: ) ++ // ++ // To prevent DisassocTimeoutAction to call Link down after we link up, ++ // cancel the DisassocTimer no matter what it start or not. ++ // ++ RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); ++ ++ COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++ ++#ifdef DOT11_N_SUPPORT ++ COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd); ++#endif // DOT11_N_SUPPORT // ++ // It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS ++ // is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place ++ // to examine if cipher algorithm switching is required. ++ //rt2860b. Don't know why need this ++ SwitchBetweenWepAndCkip(pAd); ++ ++ ++ if (BssType == BSS_ADHOC) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE)) ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2; ++ } ++ else if ((pAd->CommonCfg.Channel > 2) && ++ (pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) && ++ (pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW)) ++ { ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ // No carrier detection when adhoc ++ // CarrierDetectionStop(pAd); ++ pAd->CommonCfg.CarrierDetect.CD_State = CD_NORMAL; ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ AdhocTurnOnQos(pAd); ++#endif // DOT11_N_SUPPORT // ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" )); ++ } ++ else ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!Infra LINK UP !!! \n" )); ++ } ++ ++ // 3*3 ++ // reset Tx beamforming bit ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x01); ++ Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++#ifdef DOT11_N_SUPPORT ++ // Change to AP channel ++ if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! 20MHz LINK UP !!! \n" )); ++ } ++ ++ RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW); ++ // ++ // Save BBP_R66 value, it will be used in RTUSBResumeMsduTransmission ++ // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n", ++ BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel)); ++ ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity)); ++#endif // DOT11_N_SUPPORT // ++ ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ ++ AsicSetSlotTime(pAd, TRUE); ++ AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm); ++ ++ // Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit ++ AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE)) ++ { ++ // Update HT protectionfor based on AP's operating mode. ++ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); ++ } ++ else ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS)); ++ ++ NdisGetSystemUpTime(&Now); ++ pAd->StaCfg.LastBeaconRxTime = Now; // last RX timestamp ++ ++ if ((pAd->CommonCfg.TxPreamble != Rt802_11PreambleLong) && ++ CAP_IS_SHORT_PREAMBLE_ON(pAd->StaActive.CapabilityInfo)) ++ { ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleShort); ++ } ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ ++ if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE) ++ { ++#ifdef DFS_SUPPORT ++ RadarDetectionStop(pAd); ++#endif // DFS_SUPPORT // ++ } ++ pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE; ++ ++ if (BssType == BSS_ADHOC) ++ { ++ MakeIbssBeacon(pAd); ++ if ((pAd->CommonCfg.Channel > 14) ++ && (pAd->CommonCfg.bIEEE80211H == 1) ++ && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) ++ { ++ ; //Do nothing ++ } ++ else ++ { ++ AsicEnableIbssSync(pAd); ++ } ++ ++ // In ad hoc mode, use MAC table from index 1. ++ // p.s ASIC use all 0xff as termination of WCID table search.To prevent it's 0xff-ff-ff-ff-ff-ff, Write 0 here. ++ RTMP_IO_WRITE32(pAd, MAC_WCID_BASE, 0x00); ++ RTMP_IO_WRITE32(pAd, 0x1808, 0x00); ++ ++ // If WEP is enabled, add key material and cipherAlg into Asic ++ // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) ++ ++ if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ ++ for (idx=0; idx < SHARE_KEY_NUM; idx++) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][idx].Key; ++ ++ if (pAd->SharedKey[BSS0][idx].KeyLen > 0) ++ { ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ if (idx == pAd->StaCfg.DefaultKeyId) ++ { ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ } ++ } ++ ++ ++ } ++ } ++ // If WPANone is enabled, add key material and cipherAlg into Asic ++ // Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000) ++ else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAd->StaCfg.DefaultKeyId = 0; // always be zero ++ ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK); ++ ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Unknow Cipher (=%d), set Cipher to AES\n", pAd->StaCfg.PairCipher)); ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ } ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, NULL); ++ ++ } ++ ++ } ++ else // BSS_INFRA ++ { ++ // Check the new SSID with last SSID ++ while (Cancelled == TRUE) ++ { ++ if (pAd->CommonCfg.LastSsidLen == pAd->CommonCfg.SsidLen) ++ { ++ if (RTMPCompareMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen) == 0) ++ { ++ // Link to the old one no linkdown is required. ++ break; ++ } ++ } ++ // Send link down event before set to link up ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event AA!\n")); ++ break; ++ } ++ ++ // ++ // On WPA mode, Remove All Keys if not connect to the last BSSID ++ // Key will be set after 4-way handshake. ++ // ++ if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ ULONG IV; ++ ++ // Remove all WPA keys ++ RTMPWPARemoveAllKeys(pAd); ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ ++ // Fixed connection failed with Range Maximizer - 515 AP (Marvell Chip) when security is WPAPSK/TKIP ++ // If IV related values are too large in GroupMsg2, AP would ignore this message. ++ IV = 0; ++ IV |= (pAd->StaCfg.DefaultKeyId << 30); ++ AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); ++ } ++ // NOTE: ++ // the decision of using "short slot time" or not may change dynamically due to ++ // new STA association to the AP. so we have to decide that upon parsing BEACON, not here ++ ++ // NOTE: ++ // the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically ++ // due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here ++ ++ ComposePsPoll(pAd); ++ ComposeNullFrame(pAd); ++ ++ AsicEnableBssSync(pAd); ++ ++ // Add BSSID to WCID search table ++ AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid); ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ // add this BSSID entry into HASH table ++ { ++ UCHAR HashIdx; ++ ++ //pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ HashIdx = MAC_ADDR_HASH_INDEX(pAd->CommonCfg.Bssid); ++ if (pAd->MacTab.Hash[HashIdx] == NULL) ++ { ++ pAd->MacTab.Hash[HashIdx] = pEntry; ++ } ++ else ++ { ++ pCurrEntry = pAd->MacTab.Hash[HashIdx]; ++ while (pCurrEntry->pNext != NULL) ++ pCurrEntry = pCurrEntry->pNext; ++ pCurrEntry->pNext = pEntry; ++ } ++ } ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ ++ // If WEP is enabled, add paiewise and shared key ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (((pAd->StaCfg.WpaSupplicantUP)&& ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&& ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) || ++ ((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&& ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled))) ++#else ++ if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ ++ for (idx=0; idx < SHARE_KEY_NUM; idx++) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][idx].Key; ++ ++ if (pAd->SharedKey[BSS0][idx].KeyLen > 0) ++ { ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL); ++ ++ if (idx == pAd->StaCfg.DefaultKeyId) ++ { ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL); ++ ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry); ++ } ++ } ++ } ++ } ++ ++ // only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode ++ // should wait until at least 2 active nodes in this BSSID. ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ // For GUI ++ ++ if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ { ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ RTMP_IndicateMediaState(pAd); ++ } ++ // -- ++ ++ // Add BSSID in my MAC Table. ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ RTMPMoveMemory(pAd->MacTab.Content[BSSID_WCID].Addr, pAd->CommonCfg.Bssid, MAC_ADDR_LEN); ++ pAd->MacTab.Content[BSSID_WCID].Aid = BSSID_WCID; ++ pAd->MacTab.Content[BSSID_WCID].pAd = pAd; ++ pAd->MacTab.Content[BSSID_WCID].ValidAsCLI = TRUE; //Although this is bssid..still set ValidAsCl ++ pAd->MacTab.Size = 1; // infra mode always set MACtab size =1. ++ pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC; ++ pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC; ++ pAd->MacTab.Content[BSSID_WCID].AuthMode = pAd->StaCfg.AuthMode; ++ pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! ClientStatusFlags=%lx)\n", ++ pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++ ++ MlmeUpdateTxRates(pAd, TRUE, BSS0); ++#ifdef DOT11_N_SUPPORT ++ MlmeUpdateHtTxRates(pAd, BSS0); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable)); ++#endif // DOT11_N_SUPPORT // ++ ++ // ++ // Report Adjacent AP report. ++ // ++#ifdef LEAP_SUPPORT ++ CCXAdjacentAPReport(pAd); ++#endif // LEAP_SUPPORT // ++ ++ if (pAd->CommonCfg.bAggregationCapable) ++ { ++ if ((pAd->CommonCfg.bPiggyBackCapable) && (pAd->MlmeAux.APRalinkIe & 0x00000003) == 3) ++ { ++ ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ RTMPSetPiggyBack(pAd, TRUE); ++ DBGPRINT(RT_DEBUG_TRACE, ("Turn on Piggy-Back\n")); ++ } ++ else if (pAd->MlmeAux.APRalinkIe & 0x00000001) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ } ++ } ++ ++ if (pAd->MlmeAux.APRalinkIe != 0x0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE)) ++ { ++ AsicEnableRDG(pAd); ++ } ++#endif // DOT11_N_SUPPORT // ++ OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); ++ CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); ++ } ++ else ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET); ++ CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET); ++ } ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags)); ++#endif // DOT11_N_SUPPORT // ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_LINK_UP); ++ ++ pAd->Mlme.PeriodicRound = 0; ++ pAd->Mlme.OneSecPeriodicRound = 0; ++ pAd->bConfigChanged = FALSE; // Reset config flag ++ pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up ++ ++ // Set asic auto fall back ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, &pAd->MacTab.Content[BSSID_WCID], &pTable, &TableSize, &pAd->CommonCfg.TxRateIndex); ++ AsicUpdateAutoFallBackTable(pAd, pTable); ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ pEntry->MaxHTPhyMode.word = pAd->StaCfg.HTPhyMode.word; ++ if (pAd->StaCfg.bAutoTxRateSwitch == FALSE) ++ { ++ pEntry->bAutoTxRateSwitch = FALSE; ++#ifdef DOT11_N_SUPPORT ++ if (pEntry->HTPhyMode.field.MCS == 32) ++ pEntry->HTPhyMode.field.ShortGI = GI_800; ++ ++ if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32)) ++ pEntry->HTPhyMode.field.STBC = STBC_NONE; ++#endif // DOT11_N_SUPPORT // ++ // If the legacy mode is set, overwrite the transmit setting of this entry. ++ if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM) ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ else ++ pEntry->bAutoTxRateSwitch = TRUE; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ // Let Link Status Page display first initial rate. ++ pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); ++ // Select DAC according to HT or Legacy ++ if (pAd->StaActive.SupportedPhyInfo.MCSSet[0] != 0x00) ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); ++ Value &= (~0x18); ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ Value |= 0x10; ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); ++ } ++ else ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) ++ { ++ } ++ else if (pEntry->MaxRAmpduFactor == 0) ++ { ++ // If HT AP doesn't support MaxRAmpduFactor = 1, we need to set max PSDU to 0. ++ // Because our Init value is 1 at MACRegTable. ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ // Patch for Marvel AP to gain high throughput ++ // Need to set as following, ++ // 1. Set txop in register-EDCA_AC0_CFG as 0x60 ++ // 2. Set EnTXWriteBackDDONE in register-WPDMA_GLO_CFG as zero ++ // 3. PBF_MAX_PCNT as 0x1F3FBF9F ++ // 4. kick per two packets when dequeue ++ // ++ // Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable ++ // ++ // if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is. ++#ifdef DOT11_N_SUPPORT ++// if ((!IS_RT30xx(pAd)) && ++ if (!((pAd->CommonCfg.RxStream == 1)&&(pAd->CommonCfg.TxStream == 1)) && ++ (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)) ++ || ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)))) ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n")); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (pAd->CommonCfg.bEnableTxBurst) ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ Data |= 0x60; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = TRUE; ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3FBF9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 2\n")); ++ } ++ else ++ { ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data); ++ Data &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data); ++ ++ RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F); ++ DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n")); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // Re-check to turn on TX burst or not. ++ if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd)))) ++ { ++ pAd->CommonCfg.IOTestParm.bNextDisableRxBA = TRUE; ++ if (pAd->CommonCfg.bEnableTxBurst) ++ { ++ UINT32 MACValue = 0; ++ // Force disable TXOP value in this case. The same action in MLMEUpdateProtect too. ++ // I didn't change PBF_MAX_PCNT setting. ++ RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &MACValue); ++ MACValue &= 0xFFFFFF00; ++ RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, MACValue); ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; ++ } ++ } ++ else ++ { ++ pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE; ++ COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!pAd->bNextDisableRxBA= %d \n", pAd->CommonCfg.IOTestParm.bNextDisableRxBA)); ++ // BSSID add in one MAC entry too. Because in Tx, ASIC need to check Cipher and IV/EIV, BAbitmap ++ // Pther information in MACTab.Content[BSSID_WCID] is not necessary for driver. ++ // Note: As STA, The MACTab.Content[BSSID_WCID]. PairwiseKey and Shared Key for BSS0 are the same. ++ ++ if (pAd->StaCfg.WepStatus <= Ndis802_11WEPDisabled) ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll; ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pEntry->PortSecured = pAd->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ // ++ // Patch Atheros AP TX will breakdown issue. ++ // AP Model: DLink DWL-8200AP ++ // ++ if (INFRA_ON(pAd) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && STA_TKIP_ON(pAd)) ++ { ++ RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x01); ++ } ++ else ++ { ++ RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x00); ++ } ++ ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if ((pAd->CommonCfg.BACapability.field.b2040CoexistScanSup) && (pAd->CommonCfg.Channel <= 11)) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SCAN_2040); ++ BuildEffectedChannelList(pAd); ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++} ++ ++/* ++ ========================================================================== ++ ++ Routine Description: ++ Disconnect current BSSID ++ ++ Arguments: ++ pAd - Pointer to our adapter ++ IsReqFromAP - Request from AP ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ We need more information to know it's this requst from AP. ++ If yes! we need to do extra handling, for example, remove the WPA key. ++ Otherwise on 4-way handshaking will faied, since the WPA key didn't be ++ remove while auto reconnect. ++ Disconnect request from AP, it means we will start afresh 4-way handshaking ++ on WPA mode. ++ ++ ========================================================================== ++*/ ++VOID LinkDown( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN IsReqFromAP) ++{ ++ UCHAR i, ByteValue = 0; ++ ++ // Do nothing if monitor mode is on ++ if (MONITOR_ON(pAd)) ++ return; ++ ++#ifdef RALINK_ATE ++ // Nothing to do in ATE mode. ++ if (ATE_ON(pAd)) ++ return; ++#endif // RALINK_ATE // ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); ++ ++ if (ADHOC_ON(pAd)) // Adhoc mode link down ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MacTab.Size=%d !!!\n", pAd->MacTab.Size)); ++ } ++ else // Infra structure mode ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n")); ++ ++#ifdef QOS_DLS_SUPPORT ++ // DLS tear down frame must be sent before link down ++ // send DLS-TEAR_DOWN message ++ if (pAd->CommonCfg.bDLSCapable) ++ { ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ RTMPSendDLSTearDownFrame(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ // Saved last SSID for linkup comparison ++ pAd->CommonCfg.LastSsidLen = pAd->CommonCfg.SsidLen; ++ NdisMoveMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen); ++ COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid); ++ if (pAd->MlmeAux.CurrReqIsFromNdis == TRUE) ++ { ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event A!\n")); ++ pAd->MlmeAux.CurrReqIsFromNdis = FALSE; ++ } ++ else ++ { ++ // ++ // If disassociation request is from NDIS, then we don't need to delete BSSID from entry. ++ // Otherwise lost beacon or receive De-Authentication from AP, ++ // then we should delete BSSID from BssTable. ++ // If we don't delete from entry, roaming will fail. ++ // ++ BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel); ++ } ++ ++ // restore back to - ++ // 1. long slot (20 us) or short slot (9 us) time ++ // 2. turn on/off RTS/CTS and/or CTS-to-self protection ++ // 3. short preamble ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ ++ if (pAd->StaCfg.CCXAdjacentAPReportFlag == TRUE) ++ { ++ // ++ // Record current AP's information. ++ // for later used reporting Adjacent AP report. ++ // ++ pAd->StaCfg.CCXAdjacentAPChannel = pAd->CommonCfg.Channel; ++ pAd->StaCfg.CCXAdjacentAPSsidLen = pAd->CommonCfg.SsidLen; ++ NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen); ++ COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid); ++ } ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // Country IE of the AP will be evaluated and will be used. ++ if (pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) ++ { ++ NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pAd->StaCfg.StaOriCountryCode[0], 2); ++ pAd->CommonCfg.Geography = pAd->StaCfg.StaOriGeography; ++ BuildChannelListEx(pAd); ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ } ++ ++ for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) ++ MacTableDeleteEntry(pAd, pAd->MacTab.Content[i].Aid, pAd->MacTab.Content[i].Addr); ++ } ++ ++ pAd->StaCfg.CCXQosECWMin = 4; ++ pAd->StaCfg.CCXQosECWMax = 10; ++ ++ AsicSetSlotTime(pAd, TRUE); //FALSE); ++ AsicSetEdcaParm(pAd, NULL); ++ ++ // Set LED ++ RTMPSetLED(pAd, LED_LINK_DOWN); ++ pAd->LedIndicatorStregth = 0xF0; ++ RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. ++ ++ AsicDisableSync(pAd); ++ ++ pAd->Mlme.PeriodicRound = 0; ++ pAd->Mlme.OneSecPeriodicRound = 0; ++ ++ if (pAd->StaCfg.BssType == BSS_INFRA) ++ { ++ // Remove StaCfg Information after link down ++ NdisZeroMemory(pAd->CommonCfg.Bssid, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->CommonCfg.Ssid, MAX_LEN_OF_SSID); ++ pAd->CommonCfg.SsidLen = 0; ++ } ++#ifdef DOT11_N_SUPPORT ++ NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE)); ++ NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ pAd->MlmeAux.HtCapabilityLen = 0; ++ pAd->MlmeAux.NewExtChannelOffset = 0xff; ++#endif // DOT11_N_SUPPORT // ++ ++ // Reset WPA-PSK state. Only reset when supplicant enabled ++ if (pAd->StaCfg.WpaState != SS_NOTUSE) ++ { ++ pAd->StaCfg.WpaState = SS_START; ++ // Clear Replay counter ++ NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); ++ ++#ifdef QOS_DLS_SUPPORT ++ if (pAd->CommonCfg.bDLSCapable) ++ NdisZeroMemory(pAd->StaCfg.DlsReplayCounter, 8); ++#endif // QOS_DLS_SUPPORT // ++ } ++ ++ ++ // ++ // if link down come from AP, we need to remove all WPA keys on WPA mode. ++ // otherwise will cause 4-way handshaking failed, since the WPA key not empty. ++ // ++ if ((IsReqFromAP) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ // Remove all WPA keys ++ RTMPWPARemoveAllKeys(pAd); ++ } ++ ++ // 802.1x port control ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Prevent clear PortSecured here with static WEP ++ // NetworkManger set security policy first then set SSID to connect AP. ++ if (pAd->StaCfg.WpaSupplicantUP && ++ (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) && ++ (pAd->StaCfg.IEEE8021X == FALSE)) ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP; ++ } ++ ++ NdisAcquireSpinLock(&pAd->MacTabLock); ++ pAd->MacTab.Content[BSSID_WCID].PortSecured = pAd->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAd->MacTabLock); ++ ++ pAd->StaCfg.MicErrCnt = 0; ++ ++ // Turn off Ckip control flag ++ pAd->StaCfg.bCkipOn = FALSE; ++ pAd->StaCfg.CCXEnable = FALSE; ++ ++ pAd->IndicateMediaState = NdisMediaStateDisconnected; ++ // Update extra information to link is up ++ pAd->ExtraInfo = GENERAL_LINK_DOWN; ++ ++ //pAd->StaCfg.AdhocBOnlyJoined = FALSE; ++ //pAd->StaCfg.AdhocBGJoined = FALSE; ++ //pAd->StaCfg.Adhoc20NJoined = FALSE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ ++ // Reset the Current AP's IP address ++ NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4); ++#ifdef RT2870 ++ pAd->bUsbTxBulkAggre = FALSE; ++#endif // RT2870 // ++ ++ // Clean association information ++ NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); ++ pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); ++ pAd->StaCfg.ReqVarIELen = 0; ++ pAd->StaCfg.ResVarIELen = 0; ++ ++ // ++ // Reset RSSI value after link down ++ // ++ pAd->StaCfg.RssiSample.AvgRssi0 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi0X8 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi1 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi1X8 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi2 = 0; ++ pAd->StaCfg.RssiSample.AvgRssi2X8 = 0; ++ ++ // Restore MlmeRate ++ pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate; ++ pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate; ++ ++#ifdef DOT11_N_SUPPORT ++ // ++ // After Link down, reset piggy-back setting in ASIC. Disable RDG. ++ // ++ if (pAd->CommonCfg.BBPCurrentBW == BW_40) ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &ByteValue); ++ ByteValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue); ++ } ++#endif // DOT11_N_SUPPORT // ++ // Reset DAC ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue); ++ ByteValue &= (~0x18); ++ if (pAd->Antenna.field.TxPath == 2) ++ { ++ ByteValue |= 0x10; ++ } ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, ByteValue); ++ ++ RTMPSetPiggyBack(pAd,FALSE); ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED); ++ ++#ifdef DOT11_N_SUPPORT ++ pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word; ++#endif // DOT11_N_SUPPORT // ++ ++ // Restore all settings in the following. ++ AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE); ++ AsicDisableRDG(pAd); ++ pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE; ++ pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE; ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SCAN_2040); ++ pAd->CommonCfg.BSSCoexist2040.word = 0; ++ TriEventInit(pAd); ++ for (i = 0; i < (pAd->ChannelListNum - 1); i++) ++ { ++ pAd->ChannelList[i].bEffectedChannel = FALSE; ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++ RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#ifndef NATIVE_WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) { ++ union iwreq_data wrqu; ++ //send disassociate event to wpa_supplicant ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.flags = RT_DISASSOC_EVENT_FLAG; ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++ { ++ union iwreq_data wrqu; ++ memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); ++ wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); ++ } ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef RT30xx ++ if (IS_RT3090(pAd)) ++ { ++ UINT32 macdata; ++ // disable MMPS BBP control register ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &ByteValue); ++ ByteValue &= ~(0x04); //bit 2 ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, ByteValue); ++ ++ // disable MMPS MAC control register ++ RTMP_IO_READ32(pAd, 0x1210, &macdata); ++ macdata &= ~(0x09); //bit 0, 3 ++ RTMP_IO_WRITE32(pAd, 0x1210, macdata); ++ } ++#endif // RT30xx // ++ ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID IterateOnBssTab( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_START_REQ_STRUCT StartReq; ++ MLME_JOIN_REQ_STRUCT JoinReq; ++ ULONG BssIdx; ++ ++ // Change the wepstatus to original wepstatus ++ pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus; ++ pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus; ++ ++ BssIdx = pAd->MlmeAux.BssIdx; ++ if (BssIdx < pAd->MlmeAux.SsidBssTab.BssNr) ++ { ++ // Check cipher suite, AP must have more secured cipher than station setting ++ // Set the Pairwise and Group cipher to match the intended AP setting ++ // We can only connect to AP with less secured cipher setting ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher; ++ else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.GroupCipher; ++ ++ if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher; ++ else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled) ++ pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux; ++ else // There is no PairCipher Aux, downgrade our capability to TKIP ++ pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ ++ // RSN capability ++ pAd->StaCfg.RsnCapability = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.RsnCapability; ++ } ++ ++ // Set Mix cipher flag ++ pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE; ++ if (pAd->StaCfg.bMixCipher == TRUE) ++ { ++ // If mix cipher, re-build RSNIE ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.SsidBssTab.BssNr)); ++ JoinParmFill(pAd, &JoinReq, BssIdx); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), ++ &JoinReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN; ++ } ++ else if (pAd->StaCfg.BssType == BSS_ADHOC) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid)); ++ StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; ++ } ++ else // no more BSS ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All roaming failed, stay @ ch #%d\n", pAd->CommonCfg.Channel)); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++} ++ ++// for re-association only ++// IRQL = DISPATCH_LEVEL ++VOID IterateOnBssTab2( ++ IN PRTMP_ADAPTER pAd) ++{ ++ MLME_REASSOC_REQ_STRUCT ReassocReq; ++ ULONG BssIdx; ++ BSS_ENTRY *pBss; ++ ++ BssIdx = pAd->MlmeAux.RoamIdx; ++ pBss = &pAd->MlmeAux.RoamTab.BssEntry[BssIdx]; ++ ++ if (BssIdx < pAd->MlmeAux.RoamTab.BssNr) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.RoamTab.BssNr)); ++ ++ AsicSwitchChannel(pAd, pBss->Channel, FALSE); ++ AsicLockChannel(pAd, pBss->Channel); ++ ++ // reassociate message has the same structure as associate message ++ AssocParmFill(pAd, &ReassocReq, pBss->Bssid, pBss->CapabilityInfo, ++ ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ, ++ sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC; ++ } ++ else // no more BSS ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All fast roaming failed, back to ch #%d\n",pAd->CommonCfg.Channel)); ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID JoinParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_JOIN_REQ_STRUCT *JoinReq, ++ IN ULONG BssIdx) ++{ ++ JoinReq->BssIdx = BssIdx; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID ScanParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_SCAN_REQ_STRUCT *ScanReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen, ++ IN UCHAR BssType, ++ IN UCHAR ScanType) ++{ ++ NdisZeroMemory(ScanReq->Ssid, MAX_LEN_OF_SSID); ++ ScanReq->SsidLen = SsidLen; ++ NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen); ++ ScanReq->BssType = BssType; ++ ScanReq->ScanType = ScanType; ++} ++ ++#ifdef QOS_DLS_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID DlsParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_DLS_REQ_STRUCT *pDlsReq, ++ IN PRT_802_11_DLS pDls, ++ IN USHORT reason) ++{ ++ pDlsReq->pDLS = pDls; ++ pDlsReq->Reason = reason; ++} ++#endif // QOS_DLS_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID StartParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_START_REQ_STRUCT *StartReq, ++ IN CHAR Ssid[], ++ IN UCHAR SsidLen) ++{ ++ ASSERT(SsidLen <= MAX_LEN_OF_SSID); ++ NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen); ++ StartReq->SsidLen = SsidLen; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++VOID AuthParmFill( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT MLME_AUTH_REQ_STRUCT *AuthReq, ++ IN PUCHAR pAddr, ++ IN USHORT Alg) ++{ ++ COPY_MAC_ADDR(AuthReq->Addr, pAddr); ++ AuthReq->Alg = Alg; ++ AuthReq->Timeout = AUTH_TIMEOUT; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++ ++ ++#ifdef RT2870 ++ ++VOID MlmeCntlConfirm( ++ IN PRTMP_ADAPTER pAd, ++ IN ULONG MsgType, ++ IN USHORT Msg) ++{ ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg); ++} ++ ++VOID ComposePsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTXINFO_STRUC pTxInfo; ++ PTXWI_STRUC pTxWI; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("ComposePsPoll\n")); ++ NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++ ++ pAd->PsPollFrame.FC.PwrMgmt = 0; ++ pAd->PsPollFrame.FC.Type = BTYPE_CNTL; ++ pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL; ++ pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000; ++ COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress); ++ ++ RTMPZeroMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0], 100); ++ pTxInfo = (PTXINFO_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0]; ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(PSPOLL_FRAME)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxWI = (PTXWI_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(PSPOLL_FRAME)), ++ 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ RTMPMoveMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++ // Append 4 extra zero bytes. ++ pAd->PsPollContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(PSPOLL_FRAME) + 4; ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID ComposeNullFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++ PTXINFO_STRUC pTxInfo; ++ PTXWI_STRUC pTxWI; ++ ++ NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11)); ++ pAd->NullFrame.FC.Type = BTYPE_DATA; ++ pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC; ++ pAd->NullFrame.FC.ToDs = 1; ++ COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); ++ RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], 100); ++ pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0]; ++ RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE); ++ pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE]; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)), ++ 0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11)); ++ pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4; ++} ++#endif // RT2870 // ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Pre-build a BEACON frame in the shared memory ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++*/ ++ULONG MakeIbssBeacon( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR DsLen = 1, IbssLen = 2; ++ UCHAR LocalErpIe[3] = {IE_ERP, 1, 0x04}; ++ HEADER_802_11 BcnHdr; ++ USHORT CapabilityInfo; ++ LARGE_INTEGER FakeTimestamp; ++ ULONG FrameLen = 0; ++ PTXWI_STRUC pTxWI = &pAd->BeaconTxWI; ++ CHAR *pBeaconFrame = pAd->BeaconBuf; ++ BOOLEAN Privacy; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen = 0; ++ UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR ExtRateLen = 0; ++ UCHAR RSNIe = IE_WPA; ++ ++ if ((pAd->CommonCfg.PhyMode == PHY_11B) && (pAd->CommonCfg.Channel <= 14)) ++ { ++ SupRate[0] = 0x82; // 1 mbps ++ SupRate[1] = 0x84; // 2 mbps ++ SupRate[2] = 0x8b; // 5.5 mbps ++ SupRate[3] = 0x96; // 11 mbps ++ SupRateLen = 4; ++ ExtRateLen = 0; ++ } ++ else if (pAd->CommonCfg.Channel > 14) ++ { ++ SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate ++ SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ SupRateLen = 8; ++ ExtRateLen = 0; ++ ++ // ++ // Also Update MlmeRate & RtsRate for G only & A only ++ // ++ pAd->CommonCfg.MlmeRate = RATE_6; ++ pAd->CommonCfg.RtsRate = RATE_6; ++ pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; ++ pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; ++ pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; ++ } ++ else ++ { ++ SupRate[0] = 0x82; // 1 mbps ++ SupRate[1] = 0x84; // 2 mbps ++ SupRate[2] = 0x8b; // 5.5 mbps ++ SupRate[3] = 0x96; // 11 mbps ++ SupRateLen = 4; ++ ++ ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps, ++ ExtRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps ++ ExtRate[2] = 0x18; // 12 mbps, in units of 0.5 Mbps, ++ ExtRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps ++ ExtRate[4] = 0x30; // 24 mbps, in units of 0.5 Mbps, ++ ExtRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps ++ ExtRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps ++ ExtRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps ++ ExtRateLen = 8; ++ } ++ ++ pAd->StaActive.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->StaActive.SupRate, SupRate, SupRateLen); ++ pAd->StaActive.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, ExtRateLen); ++ ++ // compose IBSS beacon frame ++ MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR, pAd->CommonCfg.Bssid); ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); ++ ++ MakeOutgoingFrame(pBeaconFrame, &FrameLen, ++ sizeof(HEADER_802_11), &BcnHdr, ++ TIMESTAMP_LEN, &FakeTimestamp, ++ 2, &pAd->CommonCfg.BeaconPeriod, ++ 2, &CapabilityInfo, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &SupRateLen, ++ SupRateLen, SupRate, ++ 1, &DsIe, ++ 1, &DsLen, ++ 1, &pAd->CommonCfg.Channel, ++ 1, &IbssIe, ++ 1, &IbssLen, ++ 2, &pAd->StaActive.AtimWin, ++ END_OF_ARGS); ++ ++ // add ERP_IE and EXT_RAE IE of in 802.11g ++ if (ExtRateLen) ++ { ++ ULONG tmp; ++ ++ MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, ++ 3, LocalErpIe, ++ 1, &ExtRateIe, ++ 1, &ExtRateLen, ++ ExtRateLen, ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // If adhoc secruity is set for WPA-None, append the cipher suite IE ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ ULONG tmp; ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ ++ MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ ULONG TmpLen; ++ UCHAR HtLen, HtLen1; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++ ADD_HT_INFO_IE addHTInfoTmp; ++ USHORT b2lTmp, b2lTmp2; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(pAd->CommonCfg.HtCapability); ++ HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ 1, &AddHtInfoIe, ++ 1, &HtLen1, ++ HtLen1, &pAd->CommonCfg.AddHTInfo, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ NdisMoveMemory(&addHTInfoTmp, &pAd->CommonCfg.AddHTInfo, HtLen1); ++ *(USHORT *)(&addHTInfoTmp.AddHtInfo2) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo2)); ++ *(USHORT *)(&addHTInfoTmp.AddHtInfo3) = SWAP16(*(USHORT *)(&addHTInfoTmp.AddHtInfo3)); ++ ++ MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ 1, &AddHtInfoIe, ++ 1, &HtLen1, ++ HtLen1, &addHTInfoTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ //beacon use reserved WCID 0xff ++ if (pAd->CommonCfg.Channel > 14) ++ { ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, ++ PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit); ++ } ++ else ++ { ++ // Set to use 1Mbps for Adhoc beacon. ++ HTTRANSMIT_SETTING Transmit; ++ Transmit.word = 0; ++ RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen, ++ PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit); ++ } ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, pBeaconFrame, DIR_WRITE, FALSE); ++ RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI); ++#endif ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n", ++ FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode)); ++ return FrameLen; ++} ++ ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/dls.c +@@ -0,0 +1,2170 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ dls.c ++ ++ Abstract: ++ Handle WMM-DLS state machine ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 02-14-2006 ++ Arvin Tai 06-03-2008 Modified for RT28xx ++ */ ++ ++#include "../rt_config.h" ++ ++/* ++ ========================================================================== ++ Description: ++ dls state machine init, including state transition and timer init ++ Parameters: ++ Sm - pointer to the dls state machine ++ Note: ++ The state machine looks like this ++ ++ DLS_IDLE ++ MT2_MLME_DLS_REQUEST MlmeDlsReqAction ++ MT2_PEER_DLS_REQUEST PeerDlsReqAction ++ MT2_PEER_DLS_RESPONSE PeerDlsRspAction ++ MT2_MLME_DLS_TEARDOWN MlmeTearDownAction ++ MT2_PEER_DLS_TEARDOWN PeerTearDownAction ++ ++ IRQL = PASSIVE_LEVEL ++ ++ ========================================================================== ++ */ ++void DlsStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ UCHAR i; ++ ++ StateMachineInit(Sm, (STATE_MACHINE_FUNC*)Trans, MAX_DLS_STATE, MAX_DLS_MSG, (STATE_MACHINE_FUNC)Drop, DLS_IDLE, DLS_MACHINE_BASE); ++ ++ // the first column ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_REQ, (STATE_MACHINE_FUNC)MlmeDlsReqAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_REQ, (STATE_MACHINE_FUNC)PeerDlsReqAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_RSP, (STATE_MACHINE_FUNC)PeerDlsRspAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_MLME_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)MlmeDlsTearDownAction); ++ StateMachineSetAction(Sm, DLS_IDLE, MT2_PEER_DLS_TEAR_DOWN, (STATE_MACHINE_FUNC)PeerDlsTearDownAction); ++ ++ for (i=0; iStaCfg.DLSEntry[i].pAd = pAd; ++ RTMPInitTimer(pAd, &pAd->StaCfg.DLSEntry[i].Timer, GET_TIMER_FUNCTION(DlsTimeoutAction), pAd, FALSE); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ HEADER_802_11 DlsReqHdr; ++ PRT_802_11_DLS pDLS = NULL; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_REQUEST; ++ ULONG tmp; ++ USHORT reason; ++ ULONG Timeout; ++ BOOLEAN TimerCancelled; ++ ++ if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &reason)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsReqAction() \n")); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsReqAction() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsReqHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsReqHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, &pDLS->MacAddr, ++ 6, pAd->CurrentAddress, ++ 2, &pAd->StaActive.CapabilityInfo, ++ 2, &pDLS->TimeOut, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR HtLen; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(HT_CAPABILITY_IE); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen = FrameLen + tmp; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ Timeout = DLS_TIMEOUT; ++ RTMPSetTimer(&pDLS->Timer, Timeout); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ USHORT StatusCode = MLME_SUCCESS; ++ HEADER_802_11 DlsRspHdr; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_RESPONSE; ++ ULONG tmp; ++ USHORT CapabilityInfo; ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT DLSTimeOut; ++ SHORT i; ++ ULONG Timeout; ++ BOOLEAN TimerCancelled; ++ PRT_802_11_DLS pDLS = NULL; ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR SupportedRatesLen; ++ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR HtCapabilityLen; ++ HT_CAPABILITY_IE HtCapability; ++ ++ if (!PeerDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &DLSTimeOut, ++ &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) ++ return; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (i = 0; i < SupportedRatesLen; i++) ++ { ++ if (MaxSupportedRateIn500Kbps < (SupportedRates[i] & 0x7f)) ++ MaxSupportedRateIn500Kbps = SupportedRates[i] & 0x7f; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() from %02x:%02x:%02x:%02x:%02x:%02x\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() allocate memory failed \n")); ++ return; ++ } ++ ++ if (!INFRA_ON(pAd)) ++ { ++ StatusCode = MLME_REQUEST_DECLINED; ++ } ++ else if (!pAd->CommonCfg.bWmmCapable) ++ { ++ StatusCode = MLME_DEST_STA_IS_NOT_A_QSTA; ++ } ++ else if (!pAd->CommonCfg.bDLSCapable) ++ { ++ StatusCode = MLME_REQUEST_DECLINED; ++ } ++ else ++ { ++ // find table to update parameters ++ for (i = (MAX_NUM_OF_DLS_ENTRY-1); i >= 0; i--) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ } ++ ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ pDLS = &pAd->StaCfg.DLSEntry[i]; ++ break; ++ } ++ } ++ ++ // can not find in table, create a new one ++ if (i < 0) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() can not find same entry \n")); ++ for (i=(MAX_NUM_OF_DLS_ENTRY - 1); i >= MAX_NUM_OF_INIT_DLS_ENTRY; i--) ++ { ++ if (!pAd->StaCfg.DLSEntry[i].Valid) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ } ++ ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ pAd->StaCfg.DLSEntry[i].Valid = TRUE; ++ pAd->StaCfg.DLSEntry[i].TimeOut = DLSTimeOut; ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = DLSTimeOut; ++ NdisMoveMemory(pAd->StaCfg.DLSEntry[i].MacAddr, SA, MAC_ADDR_LEN); ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ pDLS = &pAd->StaCfg.DLSEntry[i]; ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ ++ printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ break; ++ } ++ } ++ } ++ StatusCode = MLME_SUCCESS; ++ ++ // can not find in table, create a new one ++ if (i < 0) ++ { ++ StatusCode = MLME_QOS_UNSPECIFY; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsReqAction() DLSEntry table full(only can support %d DLS session) \n", MAX_NUM_OF_DLS_ENTRY - MAX_NUM_OF_INIT_DLS_ENTRY)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsReqAction() use entry(%d) %02x:%02x:%02x:%02x:%02x:%02x\n", ++ i, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ } ++ ++ ActHeaderInit(pAd, &DlsRspHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsRspHdr, ++ 1, &Category, ++ 1, &Action, ++ 2, &StatusCode, ++ 6, SA, ++ 6, pAd->CurrentAddress, ++ 2, &pAd->StaActive.CapabilityInfo, ++ 1, &SupRateIe, ++ 1, &pAd->MlmeAux.SupRateLen, ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate, ++ END_OF_ARGS); ++ ++ if (pAd->MlmeAux.ExtRateLen != 0) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &ExtRateIe, ++ 1, &pAd->MlmeAux.ExtRateLen, ++ pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR HtLen; ++ ++#ifdef RT_BIG_ENDIAN ++ HT_CAPABILITY_IE HtCapabilityTmp; ++#endif ++ ++ // add HT Capability IE ++ HtLen = sizeof(HT_CAPABILITY_IE); ++#ifndef RT_BIG_ENDIAN ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &pAd->CommonCfg.HtCapability, ++ END_OF_ARGS); ++#else ++ NdisMoveMemory(&HtCapabilityTmp, &pAd->CommonCfg.HtCapability, HtLen); ++ *(USHORT *)(&HtCapabilityTmp.HtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.HtCapInfo)); ++ *(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo) = SWAP16(*(USHORT *)(&HtCapabilityTmp.ExtHtCapInfo)); ++ ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ HtLen, &HtCapabilityTmp, ++ END_OF_ARGS); ++#endif ++ FrameLen = FrameLen + tmp; ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (pDLS && (pDLS->Status != DLS_FINISH)) ++ { ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ Timeout = DLS_TIMEOUT; ++ RTMPSetTimer(&pDLS->Timer, Timeout); ++ } ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsRspHdr, ++ 1, &Category, ++ 1, &Action, ++ 2, &StatusCode, ++ 6, SA, ++ 6, pAd->CurrentAddress, ++ END_OF_ARGS); ++ } ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsRspAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT CapabilityInfo; ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT StatusCode; ++ SHORT i; ++ BOOLEAN TimerCancelled; ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR SupportedRatesLen; ++ UCHAR SupportedRates[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR HtCapabilityLen; ++ HT_CAPABILITY_IE HtCapability; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (!INFRA_ON(pAd)) ++ return; ++ ++ if (!PeerDlsRspSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &CapabilityInfo, &StatusCode, ++ &SupportedRatesLen, &SupportedRates[0], &HtCapabilityLen, &HtCapability)) ++ return; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); ++ } ++ else ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); ++ } ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ ++ //initialize seq no for DLS frames. ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ } ++ else ++ { ++ // DLS setup procedure failed. ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); ++ } ++ } ++ } ++ ++ if (i >= MAX_NUM_OF_INIT_DLS_ENTRY) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() update timeout value \n")); ++ for (i=(MAX_NUM_OF_DLS_ENTRY-1); i>=MAX_NUM_OF_INIT_DLS_ENTRY; i--) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (StatusCode == MLME_SUCCESS) ++ { ++ MAC_TABLE_ENTRY *pEntry; ++ UCHAR MaxSupportedRate = RATE_11; ++ ++ pEntry = MacTableInsertDlsEntry(pAd, SA, i); ++ ++ switch (MaxSupportedRateIn500Kbps) ++ { ++ case 108: MaxSupportedRate = RATE_54; break; ++ case 96: MaxSupportedRate = RATE_48; break; ++ case 72: MaxSupportedRate = RATE_36; break; ++ case 48: MaxSupportedRate = RATE_24; break; ++ case 36: MaxSupportedRate = RATE_18; break; ++ case 24: MaxSupportedRate = RATE_12; break; ++ case 18: MaxSupportedRate = RATE_9; break; ++ case 12: MaxSupportedRate = RATE_6; break; ++ case 22: MaxSupportedRate = RATE_11; break; ++ case 11: MaxSupportedRate = RATE_5_5; break; ++ case 4: MaxSupportedRate = RATE_2; break; ++ case 2: MaxSupportedRate = RATE_1; break; ++ default: MaxSupportedRate = RATE_11; break; ++ } ++ ++ pEntry->MaxSupportedRate = min(pAd->CommonCfg.MaxTxRate, MaxSupportedRate); ++ ++ if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->MinHTPhyMode.field.MODE = MODE_CCK; ++ pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ pEntry->HTPhyMode.field.MODE = MODE_CCK; ++ pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->MinHTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ pEntry->HTPhyMode.field.MODE = MODE_OFDM; ++ pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate]; ++ } ++ ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MinHTPhyMode.field.BW = BW_20; ++ ++#ifdef DOT11_N_SUPPORT ++ pEntry->HTCapability.MCSSet[0] = 0; ++ pEntry->HTCapability.MCSSet[1] = 0; ++ ++ // If this Entry supports 802.11n, upgrade to HT rate. ++ if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ UCHAR j, bitmask; //k,bitmask; ++ CHAR ii; ++ ++ if ((HtCapability.HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD; ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pAd->MacTab.fAnyStationNonGF = TRUE; ++ pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1; ++ } ++ ++ if ((HtCapability.HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth)) ++ { ++ pEntry->MaxHTPhyMode.field.BW= BW_40; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(HtCapability.HtCapInfo.ShortGIfor40)); ++ } ++ else ++ { ++ pEntry->MaxHTPhyMode.field.BW = BW_20; ++ pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(HtCapability.HtCapInfo.ShortGIfor20)); ++ pAd->MacTab.fAnyStation20Only = TRUE; ++ } ++ ++ // find max fixed rate ++ for (ii=15; ii>=0; ii--) ++ { ++ j = ii/8; ++ bitmask = (1<<(ii-(j*8))); ++ if ( (pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j]&bitmask) && (HtCapability.MCSSet[j]&bitmask)) ++ { ++ pEntry->MaxHTPhyMode.field.MCS = ii; ++ break; ++ } ++ if (ii==0) ++ break; ++ } ++ ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO) ++ { ++ printk("@@@ pAd->CommonCfg.RegTransmitSetting.field.MCS = %d\n", ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS); ++ if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32) ++ { ++ // Fix MCS as HT Duplicated Mode ++ pEntry->MaxHTPhyMode.field.BW = 1; ++ pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX; ++ pEntry->MaxHTPhyMode.field.STBC = 0; ++ pEntry->MaxHTPhyMode.field.ShortGI = 0; ++ pEntry->MaxHTPhyMode.field.MCS = 32; ++ } ++ else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS) ++ { ++ // STA supports fixed MCS ++ pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ } ++ } ++ ++ pEntry->MaxHTPhyMode.field.STBC = (HtCapability.HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC)); ++ pEntry->MpduDensity = HtCapability.HtCapParm.MpduDensity; ++ pEntry->MaxRAmpduFactor = HtCapability.HtCapParm.MaxRAmpduFactor; ++ pEntry->MmpsMode = (UCHAR)HtCapability.HtCapInfo.MimoPs; ++ pEntry->AMsduSize = (UCHAR)HtCapability.HtCapInfo.AMsduSize; ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ ++ if (HtCapability.HtCapInfo.ShortGIfor20) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE); ++ if (HtCapability.HtCapInfo.ShortGIfor40) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE); ++ if (HtCapability.HtCapInfo.TxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE); ++ if (HtCapability.HtCapInfo.RxSTBC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.PlusHTC) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE); ++ if (pAd->CommonCfg.bRdg && HtCapability.ExtHtCapInfo.RDGSupport) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE); ++ if (HtCapability.ExtHtCapInfo.MCSFeedback == 0x03) ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE); ++ ++ NdisMoveMemory(&pEntry->HTCapability, &HtCapability, sizeof(HT_CAPABILITY_IE)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word; ++ pEntry->CurrTxRate = pEntry->MaxSupportedRate; ++ CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE); ++ ++ if (pAd->StaCfg.bAutoTxRateSwitch == TRUE) ++ { ++ PUCHAR pTable; ++ UCHAR TableSize = 0; ++ ++ MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex); ++ pEntry->bAutoTxRateSwitch = TRUE; ++ } ++ else ++ { ++ pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; ++ pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; ++ pEntry->bAutoTxRateSwitch = FALSE; ++ ++ RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry); ++ } ++ pEntry->RateLen = SupportedRatesLen; ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyRequest(pAd, pAd->StaCfg.DLSEntry[i].MacAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed when call RTMPSendSTAKeyRequest \n")); ++ } ++ else ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_WAIT_KEY; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - waiting for STAKey handshake procedure\n")); ++ } ++ } ++ else ++ { ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsRspAction() from %02x:%02x:%02x:%02x:%02x:%02x Succeed with WEP or no security\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5])); ++ } ++ pAd->StaCfg.DLSEntry[i].Sequence = 0; ++ if (HtCapabilityLen != 0) ++ pAd->StaCfg.DLSEntry[i].bHTCap = TRUE; ++ else ++ pAd->StaCfg.DLSEntry[i].bHTCap = FALSE; ++ } ++ else ++ { ++ // DLS setup procedure failed. ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - PeerDlsRspAction failed with StatusCode=%d \n", StatusCode)); ++ } ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID MlmeDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_TEARDOWN; ++ USHORT ReasonCode = REASON_QOS_UNSPECIFY; ++ HEADER_802_11 DlsTearDownHdr; ++ PRT_802_11_DLS pDLS; ++ BOOLEAN TimerCancelled; ++ UCHAR i; ++ ++ if(!MlmeDlsReqSanity(pAd, Elem->Msg, Elem->MsgLen, &pDLS, &ReasonCode)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - MlmeDlsTearDownAction() with ReasonCode=%d \n", ReasonCode)); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("DLS - MlmeDlsTearDownAction() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ ++ // Build basic frame first ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsTearDownHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, &pDLS->MacAddr, ++ 6, pAd->CurrentAddress, ++ 2, &ReasonCode, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPCancelTimer(&pDLS->Timer, &TimerCancelled); ++ ++ // Remove key in local dls table entry ++ for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // clear peer dls table entry ++ for (i = MAX_NUM_OF_INIT_DLS_ENTRY; i < MAX_NUM_OF_DLS_ENTRY; i++) ++ { ++ if (MAC_ADDR_EQUAL(pDLS->MacAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerDlsTearDownAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR DA[MAC_ADDR_LEN], SA[MAC_ADDR_LEN]; ++ USHORT ReasonCode; ++ UINT i; ++ BOOLEAN TimerCancelled; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (!INFRA_ON(pAd)) ++ return; ++ ++ if (!PeerDlsTearDownSanity(pAd, Elem->Msg, Elem->MsgLen, DA, SA, &ReasonCode)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - PeerDlsTearDownAction() from %02x:%02x:%02x:%02x:%02x:%02x with ReasonCode=%d\n", SA[0], SA[1], SA[2], SA[3], SA[4], SA[5], ReasonCode)); ++ ++ // clear local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // clear peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(SA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ //AsicDelWcidTab(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ //AsicRemovePairwiseKeyEntry(pAd, BSS0, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID); ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID RTMPCheckDLSTimeOut( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG i; ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_UNSPECIFY; ++ ++ if (! pAd->CommonCfg.bDLSCapable) ++ return; ++ ++ if (! INFRA_ON(pAd)) ++ return; ++ ++ // If timeout value is equaled to zero, it means always not be timeout. ++ ++ // update local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer --; ++ ++ if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ } ++ } ++ ++ // update peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && (pAd->StaCfg.DLSEntry[i].TimeOut != 0)) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer --; ++ ++ if (pAd->StaCfg.DLSEntry[i].CountDownTimer == 0) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN RTMPRcvFrameDLSCheck( ++ IN PRTMP_ADAPTER pAd, ++ IN PHEADER_802_11 pHeader, ++ IN ULONG Len, ++ IN PRT28XX_RXD_STRUC pRxD) ++{ ++ ULONG i; ++ BOOLEAN bFindEntry = FALSE; ++ BOOLEAN bSTAKeyFrame = FALSE; ++ PEAPOL_PACKET pEap; ++ PUCHAR pProto, pAddr = NULL; ++ PUCHAR pSTAKey = NULL; ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR digest[80]; ++ UCHAR DlsPTK[80]; ++ UCHAR temp[64]; ++ BOOLEAN TimerCancelled; ++ CIPHER_KEY PairwiseKey; ++ ++ ++ if (! pAd->CommonCfg.bDLSCapable) ++ return bSTAKeyFrame; ++ ++ if (! INFRA_ON(pAd)) ++ return bSTAKeyFrame; ++ ++ if (! (pHeader->FC.SubType & 0x08)) ++ return bSTAKeyFrame; ++ ++ if (Len < LENGTH_802_11 + 6 + 2 + 2) ++ return bSTAKeyFrame; ++ ++ pProto = (PUCHAR)pHeader + LENGTH_802_11 + 2 + 6; // QOS Control field , 0xAA 0xAA 0xAA 0x00 0x00 0x00 ++ pAddr = pHeader->Addr2; ++ ++ // L2PAD bit on will pad 2 bytes at LLC ++ if (pRxD->L2PAD) ++ { ++ pProto += 2; ++ } ++ ++ if (RTMPEqualMemory(EAPOL, pProto, 2) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ pEap = (PEAPOL_PACKET) (pProto + 2); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff Len=%ld, DataLen=%d, KeyMic=%d, Install=%d, KeyAck=%d, Secure=%d, EKD_DL=%d, Error=%d, Request=%d\n", Len, ++ (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16), ++ pEap->KeyDesc.KeyInfo.KeyMic, ++ pEap->KeyDesc.KeyInfo.Install, ++ pEap->KeyDesc.KeyInfo.KeyAck, ++ pEap->KeyDesc.KeyInfo.Secure, ++ pEap->KeyDesc.KeyInfo.EKD_DL, ++ pEap->KeyDesc.KeyInfo.Error, ++ pEap->KeyDesc.KeyInfo.Request)); ++ ++ if ((Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE + 16)) && pEap->KeyDesc.KeyInfo.KeyMic ++ && pEap->KeyDesc.KeyInfo.Install && pEap->KeyDesc.KeyInfo.KeyAck && pEap->KeyDesc.KeyInfo.Secure ++ && pEap->KeyDesc.KeyInfo.EKD_DL && !pEap->KeyDesc.KeyInfo.Error && !pEap->KeyDesc.KeyInfo.Request) ++ { ++ // First validate replay counter, only accept message with larger replay counter ++ // Let equal pass, some AP start with all zero replay counter ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ if ((RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pEap->KeyDesc.ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ return bSTAKeyFrame; ++ ++ //RTMPMoveMemory(pAd->StaCfg.ReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter (%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", ++ pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], ++ pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], ++ pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); ++ ++ // put these code segment to get the replay counter ++ if (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) ++ return bSTAKeyFrame; ++ ++ // Check MIC value ++ // Save the MIC and replace with zero ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ NdisMoveMemory(OldMic, pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pEap->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1((PUCHAR) pEap, pEap->Body_Len[1] + 4, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(DlsPTK, LEN_EAP_MICK, (PUCHAR) pEap, pEap->Body_Len[1] + 4, Mic); ++ } ++ ++ if (!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("MIC Different in Msg1 of STAKey handshake! \n")); ++ return bSTAKeyFrame; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("MIC VALID in Msg1 of STAKey handshake! \n")); ++#if 1 ++ if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0C) ++ && (pEap->KeyDesc.KeyData[4] == 0x43) && (pEap->KeyDesc.KeyData[5] == 0x02)) ++ { ++ pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) ++ pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%ld, KeyDataLen=%d\n", ++ pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); ++ ++ bSTAKeyFrame = TRUE; ++ } ++#else ++ if ((pEap->KeyDesc.KeyData[0] == 0xDD) && (pEap->KeyDesc.KeyData[2] == 0x00) && (pEap->KeyDesc.KeyData[3] == 0x0F) ++ && (pEap->KeyDesc.KeyData[4] == 0xAC) && (pEap->KeyDesc.KeyData[5] == 0x02)) ++ { ++ pAddr = pEap->KeyDesc.KeyData + 8; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2) ++ pSTAKey = pEap->KeyDesc.KeyData + 14; // Tpe(1), Len(1), OUI(3), DataType(1), Reserved(2), STAKey_Mac_Addr(6) ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 from %02x:%02x:%02x:%02x:%02x:%02x Len=%d, KeyDataLen=%d\n", ++ pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5], Len, pEap->KeyDesc.KeyData[1])); ++ ++ bSTAKeyFrame = TRUE; ++ } ++#endif ++ ++ } ++ else if (Len >= (LENGTH_802_11 + 6 + 2 + 2 + sizeof(EAPOL_PACKET) - MAX_LEN_OF_RSNIE)) ++ { ++ RTMPMoveMemory(pAd->StaCfg.DlsReplayCounter, pEap->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Sniff replay counter 2(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x) Len=%ld, KeyDataLen=%d\n", ++ pAd->StaCfg.ReplayCounter[0], pAd->StaCfg.ReplayCounter[1], pAd->StaCfg.ReplayCounter[2], ++ pAd->StaCfg.ReplayCounter[3], pAd->StaCfg.ReplayCounter[4], pAd->StaCfg.ReplayCounter[5], ++ pAd->StaCfg.ReplayCounter[6], pAd->StaCfg.ReplayCounter[7], Len, pEap->KeyDesc.KeyData[1])); ++ ++ } ++ } ++ ++ // If timeout value is equaled to zero, it means always not be timeout. ++ // update local dls table entry ++ for (i= 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (bSTAKeyFrame) ++ { ++ PMAC_TABLE_ENTRY pEntry; ++ ++ // STAKey frame, add pairwise key table ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ ++ PairwiseKey.KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); ++ NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); ++ ++ PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; ++ ++ pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ // Add Pair-wise key to Asic ++#ifdef RT2870 ++//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> ++ { ++ RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; ++ COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); ++ KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; ++ NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); ++ } ++ { ++ PMAC_TABLE_ENTRY pDLSEntry; ++ pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); ++ } ++//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- ++#endif // RT2870 // ++ NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); ++ ++ RTMPSendSTAKeyHandShake(pAd, pAd->StaCfg.DLSEntry[i].MacAddr); ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Initiator side)\n")); ++ } ++ else ++ { ++ // Data frame, update timeout value ++ if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ } ++ } ++ ++ bFindEntry = TRUE; ++ } ++ } ++ ++ // update peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && MAC_ADDR_EQUAL(pAddr, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ if (bSTAKeyFrame) ++ { ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ // STAKey frame, add pairwise key table, and send STAkey Msg-2 ++ pAd->StaCfg.DLSEntry[i].Status = DLS_FINISH; ++ RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &TimerCancelled); ++ ++ PairwiseKey.KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(PairwiseKey.Key, &pSTAKey[0], LEN_TKIP_EK); ++ NdisMoveMemory(PairwiseKey.TxMic, &pSTAKey[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(PairwiseKey.RxMic, &pSTAKey[24], LEN_TKIP_TXMICK); ++ ++ PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg; ++ ++ pEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast ++ //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); ++ // Add Pair-wise key to Asic ++#ifdef RT2870 ++//Benson modified for USB interface, avoid in interrupt when write key, 20080724 --> ++ { ++ RT_ADD_PAIRWISE_KEY_ENTRY KeyInfo; ++ COPY_MAC_ADDR(KeyInfo.MacAddr,pAd->StaCfg.DLSEntry[i].MacAddr); ++ KeyInfo.MacTabMatchWCID=pAd->StaCfg.DLSEntry[i].MacTabMatchWCID; ++ NdisMoveMemory(&KeyInfo.CipherKey, &PairwiseKey,sizeof(CIPHER_KEY)); ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_KEY_TABLE, &KeyInfo, sizeof(RT_ADD_PAIRWISE_KEY_ENTRY)); ++ } ++ { ++ PMAC_TABLE_ENTRY pDLSEntry; ++ pDLSEntry = DlsEntryTableLookup(pAd, pAd->StaCfg.DLSEntry[i].MacAddr, TRUE); ++ pDLSEntry->PairwiseKey.CipherAlg=PairwiseKey.CipherAlg; ++ RTUSBEnqueueInternalCmd(pAd, RT_CMD_SET_RX_WCID_TABLE, pDLSEntry, sizeof(MAC_TABLE_ENTRY)); ++ } ++//Benson modified for USB interface, avoid in interrupt when write key, 20080724 <-- ++#endif // RT2870 // ++ NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); ++ ++ // If support WPA or WPA2, start STAKey hand shake, ++ // If failed hand shake, just tear down peer DLS ++ if (RTMPSendSTAKeyHandShake(pAd, pAddr) != NDIS_STATUS_SUCCESS) ++ { ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason = REASON_QOS_CIPHER_NOT_SUPPORT; ++ ++ pAd->StaCfg.DLSEntry[i].Valid = FALSE; ++ pAd->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, &pAd->StaCfg.DLSEntry[i], reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - Finish STAKey handshake procedure (Peer side)\n")); ++ } ++ } ++ else ++ { ++ // Data frame, update timeout value ++ if (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ { ++ pAd->StaCfg.DLSEntry[i].CountDownTimer = pAd->StaCfg.DLSEntry[i].TimeOut; ++ } ++ } ++ ++ bFindEntry = TRUE; ++ } ++ } ++ ++ ++ return bSTAKeyFrame; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check if the frame can be sent through DLS direct link interface ++ ++ Arguments: ++ pAd Pointer to adapter ++ ++ Return Value: ++ DLS entry index ++ ++ Note: ++ ++ ======================================================================== ++*/ ++INT RTMPCheckDLSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ INT rval = -1; ++ INT i; ++ ++ if (!pAd->CommonCfg.bDLSCapable) ++ return rval; ++ ++ if (!INFRA_ON(pAd)) ++ return rval; ++ ++ do{ ++ // check local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ rval = i; ++ break; ++ } ++ } ++ ++ // check peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) && ++ MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ rval = i; ++ break; ++ } ++ } ++ } while (FALSE); ++ ++ return rval; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID RTMPSendDLSTearDownFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ HEADER_802_11 DlsTearDownHdr; ++ ULONG FrameLen = 0; ++ USHORT Reason = REASON_QOS_QSTA_LEAVING_QBSS; ++ UCHAR Category = CATEGORY_DLS; ++ UCHAR Action = ACTION_DLS_TEARDOWN; ++ UCHAR i = 0; ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame \n")); ++ ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("ASSOC - RTMPSendDLSTearDownFrame() allocate memory failed \n")); ++ return; ++ } ++ ++ ActHeaderInit(pAd, &DlsTearDownHdr, pAd->CommonCfg.Bssid, pAd->CurrentAddress, pAd->CommonCfg.Bssid); ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &DlsTearDownHdr, ++ 1, &Category, ++ 1, &Action, ++ 6, pDA, ++ 6, pAd->CurrentAddress, ++ 2, &Reason, ++ END_OF_ARGS); ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ // Remove key in local dls table entry ++ for (i = 0; i < MAX_NUM_OF_INIT_DLS_ENTRY; i++) ++ { ++ if (pAd->StaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // Remove key in peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH) ++ && MAC_ADDR_EQUAL(pDA, pAd->StaCfg.DLSEntry[i].MacAddr)) ++ { ++ MacTableDeleteDlsEntry(pAd, pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, pAd->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Send DLS TearDown Frame and remove key in (i=%d) \n", i)); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++NDIS_STATUS RTMPSendSTAKeyRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ UCHAR Header802_3[14]; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ UCHAR digest[80]; ++ PUCHAR pOutBuffer = NULL; ++ PNDIS_PACKET pNdisPacket; ++ UCHAR temp[64]; ++ UCHAR DlsPTK[80]; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyRequest() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); ++ ++ pAd->Sequence ++; ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE andPeer MAC address ++ ++ // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ ++ // Key descriptor version ++ Packet.KeyDesc.KeyInfo.KeyDescVer = ++ (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ Packet.KeyDesc.KeyInfo.Request = 1; ++ ++ Packet.KeyDesc.KeyDataLen[1] = 12; ++ ++ // use our own OUI to distinguish proprietary with standard. ++ Packet.KeyDesc.KeyData[0] = 0xDD; ++ Packet.KeyDesc.KeyData[1] = 0x0A; ++ Packet.KeyDesc.KeyData[2] = 0x00; ++ Packet.KeyDesc.KeyData[3] = 0x0C; ++ Packet.KeyDesc.KeyData[4] = 0x43; ++ Packet.KeyDesc.KeyData[5] = 0x03; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); ++ ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Allocate buffer for transmitting message ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return NStatus; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ // calculate MIC ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ NdisZeroMemory(digest, sizeof(digest)); ++ HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(Header802_3), Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); ++ STASendPacket(pAd, pNdisPacket); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyRequest- Send STAKey request (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); ++ ++ return NStatus; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++NDIS_STATUS RTMPSendSTAKeyHandShake( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA) ++{ ++ UCHAR Header802_3[14]; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ UCHAR digest[80]; ++ PUCHAR pOutBuffer = NULL; ++ PNDIS_PACKET pNdisPacket; ++ UCHAR temp[64]; ++ UCHAR DlsPTK[80]; // Due to dirver can not get PTK, use proprietary PTK ++ ++ DBGPRINT(RT_DEBUG_TRACE,("DLS - RTMPSendSTAKeyHandShake() to %02x:%02x:%02x:%02x:%02x:%02x\n", pDA[0], pDA[1], pDA[2], pDA[3], pDA[4], pDA[5])); ++ ++ pAd->Sequence ++; ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + 6 + MAC_ADDR_LEN; // data field contain KDE and Peer MAC address ++ ++ // STAKey Message is as EAPOL-Key(1,1,0,0,G/0,0,0, MIC, 0,Peer MAC KDE) ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ ++ // Key descriptor version ++ Packet.KeyDesc.KeyInfo.KeyDescVer = ++ (((pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) || (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)) ? (DESC_TYPE_AES) : (DESC_TYPE_TKIP)); ++ ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ Packet.KeyDesc.KeyDataLen[1] = 12; ++ ++ // use our own OUI to distinguish proprietary with standard. ++ Packet.KeyDesc.KeyData[0] = 0xDD; ++ Packet.KeyDesc.KeyData[1] = 0x0A; ++ Packet.KeyDesc.KeyData[2] = 0x00; ++ Packet.KeyDesc.KeyData[3] = 0x0C; ++ Packet.KeyDesc.KeyData[4] = 0x43; ++ Packet.KeyDesc.KeyData[5] = 0x03; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[6], pDA, MAC_ADDR_LEN); ++ ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.DlsReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Allocate buffer for transmitting message ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return NStatus; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // use proprietary PTK ++ NdisZeroMemory(temp, 64); ++ NdisMoveMemory(temp, "IEEE802.11 WIRELESS ACCESS POINT", 32); ++ WpaCountPTK(pAd, temp, temp, pAd->CommonCfg.Bssid, temp, pAd->CurrentAddress, DlsPTK, LEN_PTK); ++ ++ // calculate MIC ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ NdisZeroMemory(digest, sizeof(digest)); ++ HMAC_SHA1(pOutBuffer, FrameLen, DlsPTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ hmac_md5(DlsPTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ } ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(Header802_3), Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ NStatus = RTMPAllocateNdisPacket(pAd, &pNdisPacket, NULL, 0, pOutBuffer, FrameLen); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ RTMP_SET_PACKET_WCID(pNdisPacket, BSSID_WCID); ++ STASendPacket(pAd, pNdisPacket); ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ } ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPSendSTAKeyHandShake- Send STAKey Message-2 (NStatus=%x, FrameLen=%ld)\n", NStatus, FrameLen)); ++ ++ return NStatus; ++} ++ ++VOID DlsTimeoutAction( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ MLME_DLS_REQ_STRUCT MlmeDlsReq; ++ USHORT reason; ++ PRT_802_11_DLS pDLS = (PRT_802_11_DLS)FunctionContext; ++ PRTMP_ADAPTER pAd = pDLS->pAd; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("DlsTimeout - Tear down DLS links (%02x:%02x:%02x:%02x:%02x:%02x)\n", ++ pDLS->MacAddr[0], pDLS->MacAddr[1], pDLS->MacAddr[2], pDLS->MacAddr[3], pDLS->MacAddr[4], pDLS->MacAddr[5])); ++ ++ if ((pDLS) && (pDLS->Valid)) ++ { ++ reason = REASON_QOS_REQUEST_TIMEOUT; ++ pDLS->Valid = FALSE; ++ pDLS->Status = DLS_NONE; ++ DlsParmFill(pAd, &MlmeDlsReq, pDLS, reason); ++ MlmeEnqueue(pAd, DLS_STATE_MACHINE, MT2_MLME_DLS_TEAR_DOWN, sizeof(MLME_DLS_REQ_STRUCT), &MlmeDlsReq); ++ RT28XX_MLME_HANDLER(pAd); ++ } ++} ++ ++/* ++================================================================ ++Description : because DLS and CLI share the same WCID table in ASIC. ++Mesh entry also insert to pAd->MacTab.content[]. Such is marked as ValidAsDls = TRUE. ++Also fills the pairwise key. ++Because front MAX_AID_BA entries have direct mapping to BAEntry, which is only used as CLI. So we insert Dls ++from index MAX_AID_BA. ++================================================================ ++*/ ++MAC_TABLE_ENTRY *MacTableInsertDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN UINT DlsEntryIdx) ++{ ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableInsertDlsEntry\n")); ++ // if FULL, return ++ if (pAd->MacTab.Size >= MAX_LEN_OF_MAC_TABLE) ++ return NULL; ++ ++ do ++ { ++ if((pEntry = DlsEntryTableLookup(pAd, pAddr, TRUE)) != NULL) ++ break; ++ ++ // allocate one MAC entry ++ pEntry = MacTableInsertEntry(pAd, pAddr, DlsEntryIdx + MIN_NET_DEVICE_FOR_DLS, TRUE); ++ if (pEntry) ++ { ++ pAd->StaCfg.DLSEntry[DlsEntryIdx].MacTabMatchWCID = pEntry->Aid; ++ pEntry->MatchDlsEntryIdx = DlsEntryIdx; ++ pEntry->AuthMode = pAd->StaCfg.AuthMode; ++ pEntry->WepStatus = pAd->StaCfg.WepStatus; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacTableInsertDlsEntry - allocate entry #%d, Total= %d\n",pEntry->Aid, pAd->MacTab.Size)); ++ ++ // If legacy WEP is used, set pair-wise cipherAlg into WCID attribute table for this entry ++ if ((pEntry->ValidAsDls) && (pEntry->WepStatus == Ndis802_11WEPEnabled)) ++ { ++ UCHAR KeyIdx = 0; ++ UCHAR CipherAlg = 0; ++ ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pEntry); ++ } ++ ++ break; ++ } ++ } while(FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableInsertDlsEntry\n")); ++ ++ return pEntry; ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ Delete all Mesh Entry in pAd->MacTab ++ ========================================================================== ++ */ ++BOOLEAN MacTableDeleteDlsEntry( ++ IN PRTMP_ADAPTER pAd, ++ IN USHORT wcid, ++ IN PUCHAR pAddr) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> MacTableDeleteDlsEntry\n")); ++ ++ if (!VALID_WCID(wcid)) ++ return FALSE; ++ ++ MacTableDeleteEntry(pAd, wcid, pAddr); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==== MacTableDeleteDlsEntry\n")); ++ ++ return TRUE; ++} ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookup( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount) ++{ ++ ULONG HashIdx; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ ++ RTMP_SEM_LOCK(&pAd->MacTabLock); ++ HashIdx = MAC_ADDR_HASH_INDEX(pAddr); ++ pEntry = pAd->MacTab.Hash[HashIdx]; ++ ++ while (pEntry) ++ { ++ if ((pEntry->ValidAsDls == TRUE) ++ && MAC_ADDR_EQUAL(pEntry->Addr, pAddr)) ++ { ++ if(bResetIdelCount) ++ pEntry->NoDataIdleCount = 0; ++ break; ++ } ++ else ++ pEntry = pEntry->pNext; ++ } ++ ++ RTMP_SEM_UNLOCK(&pAd->MacTabLock); ++ return pEntry; ++} ++ ++MAC_TABLE_ENTRY *DlsEntryTableLookupByWcid( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR wcid, ++ IN PUCHAR pAddr, ++ IN BOOLEAN bResetIdelCount) ++{ ++ ULONG DLsIndex; ++ PMAC_TABLE_ENTRY pCurEntry = NULL; ++ PMAC_TABLE_ENTRY pEntry = NULL; ++ ++ if (!VALID_WCID(wcid)) ++ return NULL; ++ ++ RTMP_SEM_LOCK(&pAd->MacTabLock); ++ ++ do ++ { ++ pCurEntry = &pAd->MacTab.Content[wcid]; ++ ++ DLsIndex = 0xff; ++ if ((pCurEntry) && (pCurEntry->ValidAsDls== TRUE)) ++ { ++ DLsIndex = pCurEntry->MatchDlsEntryIdx; ++ } ++ ++ if (DLsIndex == 0xff) ++ break; ++ ++ if (MAC_ADDR_EQUAL(pCurEntry->Addr, pAddr)) ++ { ++ if(bResetIdelCount) ++ pCurEntry->NoDataIdleCount = 0; ++ pEntry = pCurEntry; ++ break; ++ } ++ } while(FALSE); ++ ++ RTMP_SEM_UNLOCK(&pAd->MacTabLock); ++ ++ return pEntry; ++} ++ ++INT Set_DlsEntryInfo_Display_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ INT i; ++ ++ printk("\n%-19s%-8s\n", "MAC", "TIMEOUT\n"); ++ for (i=0; iStaCfg.DLSEntry[i].Valid) && (pAd->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ printk("%02x:%02x:%02x:%02x:%02x:%02x ", ++ pAd->StaCfg.DLSEntry[i].MacAddr[0], pAd->StaCfg.DLSEntry[i].MacAddr[1], pAd->StaCfg.DLSEntry[i].MacAddr[2], ++ pAd->StaCfg.DLSEntry[i].MacAddr[3], pAd->StaCfg.DLSEntry[i].MacAddr[4], pAd->StaCfg.DLSEntry[i].MacAddr[5]); ++ printk("%-8d\n", pAd->StaCfg.DLSEntry[i].TimeOut); ++ } ++ } ++ ++ return TRUE; ++} ++ ++INT Set_DlsAddEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR mac[MAC_ADDR_LEN]; ++ USHORT Timeout; ++ char *token, sepValue[] = ":", DASH = '-'; ++ INT i; ++ RT_802_11_DLS Dls; ++ ++ if(strlen(arg) < 19) //Mac address acceptable format 01:02:03:04:05:06 length 17 plus the "-" and timeout value in decimal format. ++ return FALSE; ++ ++ token = strchr(arg, DASH); ++ if ((token != NULL) && (strlen(token)>1)) ++ { ++ Timeout = simple_strtol((token+1), 0, 10); ++ ++ *token = '\0'; ++ for (i = 0, token = rstrtok(arg, &sepValue[0]); token; token = rstrtok(NULL, &sepValue[0]), i++) ++ { ++ if((strlen(token) != 2) || (!isxdigit(*token)) || (!isxdigit(*(token+1)))) ++ return FALSE; ++ AtoH(token, (PUCHAR)(&mac[i]), 1); ++ } ++ if(i != 6) ++ return FALSE; ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x-%d", mac[0], mac[1], ++ mac[2], mac[3], mac[4], mac[5], (int)Timeout); ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ Dls.TimeOut = Timeout; ++ COPY_MAC_ADDR(Dls.MacAddr, mac); ++ Dls.Valid = 1; ++ ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++ ++} ++ ++INT Set_DlsTearDownEntry_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ UCHAR macAddr[MAC_ADDR_LEN]; ++ CHAR *value; ++ INT i; ++ RT_802_11_DLS Dls; ++ ++ if(strlen(arg) != 17) //Mac address acceptable format 01:02:03:04:05:06 length 17 ++ return FALSE; ++ ++ for (i=0, value = rstrtok(arg,":"); value; value = rstrtok(NULL,":")) ++ { ++ if((strlen(value) != 2) || (!isxdigit(*value)) || (!isxdigit(*(value+1))) ) ++ return FALSE; //Invalid ++ ++ AtoH(value, &macAddr[i++], 2); ++ } ++ ++ printk("\n%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], ++ macAddr[2], macAddr[3], macAddr[4], macAddr[5]); ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ COPY_MAC_ADDR(Dls.MacAddr, macAddr); ++ Dls.Valid = 0; ++ ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta_ioctl.c +@@ -0,0 +1,7203 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sta_ioctl.c ++ ++ Abstract: ++ IOCTL related subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Rory Chen 01-03-2003 created ++ Rory Chen 02-14-2005 modify to support RT61 ++*/ ++ ++#include "rt_config.h" ++ ++#ifdef DBG ++extern ULONG RTDebugLevel; ++#endif ++ ++#define NR_WEP_KEYS 4 ++#define WEP_SMALL_KEY_LEN (40/8) ++#define WEP_LARGE_KEY_LEN (104/8) ++ ++#define GROUP_KEY_NO 4 ++ ++extern UCHAR CipherWpa2Template[]; ++extern UCHAR CipherWpaPskTkip[]; ++extern UCHAR CipherWpaPskTkipLen; ++ ++typedef struct PACKED _RT_VERSION_INFO{ ++ UCHAR DriverVersionW; ++ UCHAR DriverVersionX; ++ UCHAR DriverVersionY; ++ UCHAR DriverVersionZ; ++ UINT DriverBuildYear; ++ UINT DriverBuildMonth; ++ UINT DriverBuildDay; ++} RT_VERSION_INFO, *PRT_VERSION_INFO; ++ ++struct iw_priv_args privtab[] = { ++{ RTPRIV_IOCTL_SET, ++ IW_PRIV_TYPE_CHAR | 1024, 0, ++ "set"}, ++ ++{ RTPRIV_IOCTL_SHOW, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++{ RTPRIV_IOCTL_SHOW, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ ""}, ++/* --- sub-ioctls definitions --- */ ++ { SHOW_CONN_STATUS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "connStatus" }, ++ { SHOW_DRVIER_VERION, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "driverVer" }, ++ { SHOW_BA_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "bainfo" }, ++ { SHOW_DESC_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "descinfo" }, ++ { RAIO_OFF, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_off" }, ++ { RAIO_ON, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "radio_on" }, ++#ifdef QOS_DLS_SUPPORT ++ { SHOW_DLS_ENTRY_INFO, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "dlsentryinfo" }, ++#endif // QOS_DLS_SUPPORT // ++ { SHOW_CFG_VALUE, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "show" }, ++/* --- sub-ioctls relations --- */ ++ ++#ifdef DBG ++{ RTPRIV_IOCTL_BBP, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "bbp"}, ++{ RTPRIV_IOCTL_MAC, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "mac"}, ++#ifdef RT30xx ++{ RTPRIV_IOCTL_RF, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "rf"}, ++#endif // RT30xx // ++{ RTPRIV_IOCTL_E2P, ++ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, ++ "e2p"}, ++#endif /* DBG */ ++ ++{ RTPRIV_IOCTL_STATISTICS, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ++ "stat"}, ++{ RTPRIV_IOCTL_GSITESURVEY, ++ 0, IW_PRIV_TYPE_CHAR | 1024, ++ "get_site_survey"}, ++ ++ ++}; ++ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WMM_SUPPORT ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif ++ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++ ++#ifdef RT30xx ++VOID RTMPIoctlRF( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq); ++#endif // RT30xx // ++#endif // DBG // ++ ++ ++NDIS_STATUS RTMPWPANoneAddKeyProc( ++ IN PRTMP_ADAPTER pAd, ++ IN PVOID pBuf); ++ ++INT Set_FragTest_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef DOT11_N_SUPPORT ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // DOT11_N_SUPPORT // ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg); ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg); ++#endif // CARRIER_DETECTION_SUPPORT // ++ ++static struct { ++ CHAR *name; ++ INT (*set_proc)(PRTMP_ADAPTER pAdapter, PUCHAR arg); ++} *PRTMP_PRIVATE_SET_PROC, RTMP_PRIVATE_SUPPORT_PROC[] = { ++ {"DriverVersion", Set_DriverVersion_Proc}, ++ {"CountryRegion", Set_CountryRegion_Proc}, ++ {"CountryRegionABand", Set_CountryRegionABand_Proc}, ++ {"SSID", Set_SSID_Proc}, ++ {"WirelessMode", Set_WirelessMode_Proc}, ++ {"TxBurst", Set_TxBurst_Proc}, ++ {"TxPreamble", Set_TxPreamble_Proc}, ++ {"TxPower", Set_TxPower_Proc}, ++ {"Channel", Set_Channel_Proc}, ++ {"BGProtection", Set_BGProtection_Proc}, ++ {"RTSThreshold", Set_RTSThreshold_Proc}, ++ {"FragThreshold", Set_FragThreshold_Proc}, ++#ifdef DOT11_N_SUPPORT ++ {"HtBw", Set_HtBw_Proc}, ++ {"HtMcs", Set_HtMcs_Proc}, ++ {"HtGi", Set_HtGi_Proc}, ++ {"HtOpMode", Set_HtOpMode_Proc}, ++ {"HtExtcha", Set_HtExtcha_Proc}, ++ {"HtMpduDensity", Set_HtMpduDensity_Proc}, ++ {"HtBaWinSize", Set_HtBaWinSize_Proc}, ++ {"HtRdg", Set_HtRdg_Proc}, ++ {"HtAmsdu", Set_HtAmsdu_Proc}, ++ {"HtAutoBa", Set_HtAutoBa_Proc}, ++ {"HtBaDecline", Set_BADecline_Proc}, ++ {"HtProtect", Set_HtProtect_Proc}, ++ {"HtMimoPs", Set_HtMimoPs_Proc}, ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef AGGREGATION_SUPPORT ++ {"PktAggregate", Set_PktAggregate_Proc}, ++#endif ++ ++#ifdef WMM_SUPPORT ++ {"WmmCapable", Set_WmmCapable_Proc}, ++#endif ++ {"IEEE80211H", Set_IEEE80211H_Proc}, ++ {"NetworkType", Set_NetworkType_Proc}, ++ {"AuthMode", Set_AuthMode_Proc}, ++ {"EncrypType", Set_EncrypType_Proc}, ++ {"DefaultKeyID", Set_DefaultKeyID_Proc}, ++ {"Key1", Set_Key1_Proc}, ++ {"Key2", Set_Key2_Proc}, ++ {"Key3", Set_Key3_Proc}, ++ {"Key4", Set_Key4_Proc}, ++ {"WPAPSK", Set_WPAPSK_Proc}, ++ {"ResetCounter", Set_ResetStatCounter_Proc}, ++ {"PSMode", Set_PSMode_Proc}, ++#ifdef DBG ++ {"Debug", Set_Debug_Proc}, ++#endif ++ ++#ifdef RALINK_ATE ++ {"ATE", Set_ATE_Proc}, ++ {"ATEDA", Set_ATE_DA_Proc}, ++ {"ATESA", Set_ATE_SA_Proc}, ++ {"ATEBSSID", Set_ATE_BSSID_Proc}, ++ {"ATECHANNEL", Set_ATE_CHANNEL_Proc}, ++ {"ATETXPOW0", Set_ATE_TX_POWER0_Proc}, ++ {"ATETXPOW1", Set_ATE_TX_POWER1_Proc}, ++ {"ATETXANT", Set_ATE_TX_Antenna_Proc}, ++ {"ATERXANT", Set_ATE_RX_Antenna_Proc}, ++ {"ATETXFREQOFFSET", Set_ATE_TX_FREQOFFSET_Proc}, ++ {"ATETXBW", Set_ATE_TX_BW_Proc}, ++ {"ATETXLEN", Set_ATE_TX_LENGTH_Proc}, ++ {"ATETXCNT", Set_ATE_TX_COUNT_Proc}, ++ {"ATETXMCS", Set_ATE_TX_MCS_Proc}, ++ {"ATETXMODE", Set_ATE_TX_MODE_Proc}, ++ {"ATETXGI", Set_ATE_TX_GI_Proc}, ++ {"ATERXFER", Set_ATE_RX_FER_Proc}, ++ {"ATERRF", Set_ATE_Read_RF_Proc}, ++ {"ATEWRF1", Set_ATE_Write_RF1_Proc}, ++ {"ATEWRF2", Set_ATE_Write_RF2_Proc}, ++ {"ATEWRF3", Set_ATE_Write_RF3_Proc}, ++ {"ATEWRF4", Set_ATE_Write_RF4_Proc}, ++ {"ATELDE2P", Set_ATE_Load_E2P_Proc}, ++ {"ATERE2P", Set_ATE_Read_E2P_Proc}, ++ {"ATESHOW", Set_ATE_Show_Proc}, ++ {"ATEHELP", Set_ATE_Help_Proc}, ++ ++#ifdef RALINK_28xx_QA ++ {"TxStop", Set_TxStop_Proc}, ++ {"RxStop", Set_RxStop_Proc}, ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ {"WpaSupport", Set_Wpa_Support}, ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++ {"FixedTxMode", Set_FixedTxMode_Proc}, ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ {"OpMode", Set_OpMode_Proc}, ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++#ifdef DOT11_N_SUPPORT ++ {"TGnWifiTest", Set_TGnWifiTest_Proc}, ++ {"ForceGF", Set_ForceGF_Proc}, ++#endif // DOT11_N_SUPPORT // ++#ifdef QOS_DLS_SUPPORT ++ {"DlsAddEntry", Set_DlsAddEntry_Proc}, ++ {"DlsTearDownEntry", Set_DlsTearDownEntry_Proc}, ++#endif // QOS_DLS_SUPPORT // ++ {"LongRetry", Set_LongRetryLimit_Proc}, ++ {"ShortRetry", Set_ShortRetryLimit_Proc}, ++#ifdef EXT_BUILD_CHANNEL_LIST ++ {"11dClientMode", Set_Ieee80211dClientMode_Proc}, ++#endif // EXT_BUILD_CHANNEL_LIST // ++#ifdef CARRIER_DETECTION_SUPPORT ++ {"CarrierDetect", Set_CarrierDetect_Proc}, ++#endif // CARRIER_DETECTION_SUPPORT // ++//2008/09/11:KH add to support efuse<-- ++#ifdef RT30xx ++ {"efuseFreeNumber", set_eFuseGetFreeBlockCount_Proc}, ++ {"efuseDump", set_eFusedump_Proc}, ++ {"efuseLoadFromBin", set_eFuseLoadFromBin_Proc}, ++#endif // RT30xx // ++//2008/09/11:KH add to support efuse--> ++ {NULL,} ++}; ++ ++ ++VOID RTMPAddKey( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_802_11_KEY pKey) ++{ ++ ULONG KeyIdx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ NdisZeroMemory(pAd->StaCfg.PMK, 32); ++ NdisMoveMemory(pAd->StaCfg.PMK, pKey->KeyMaterial, pKey->KeyLength); ++ goto end; ++ } ++ // Update PTK ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, pAd->SharedKey[BSS0][0].Key, LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, pAd->SharedKey[BSS0][0].RxMic, LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, pAd->SharedKey[BSS0][0].TxMic, LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else ++ { ++ // Update GTK ++ pAd->StaCfg.DefaultKeyId = (pKey->KeyIndex & 0xFF); ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKey->KeyMaterial, LEN_TKIP_EK); ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pKey->KeyMaterial + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, pKey->KeyMaterial + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ } ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ } ++ } ++ else // dynamic WEP from wpa_supplicant ++ { ++ UCHAR CipherAlg; ++ PUCHAR Key; ++ ++ if(pKey->KeyLength == 32) ++ goto end; ++ ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ ++ if (KeyIdx < 4) ++ { ++ // it is a default shared key, for Pairwise key setting ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ pEntry = MacTableLookup(pAd, pKey->BSSID); ++ ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey: Set Pair-wise Key\n")); ++ ++ // set key material and key length ++ pEntry->PairwiseKey.KeyLen = (UCHAR)pKey->KeyLength; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // set Cipher type ++ if (pKey->KeyLength == 5) ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP64; ++ else ++ pEntry->PairwiseKey.CipherAlg = CIPHER_WEP128; ++ ++ // Add Pair-wise key to Asic ++ AsicAddPairwiseKeyEntry( ++ pAd, ++ pEntry->Addr, ++ (UCHAR)pEntry->Aid, ++ &pEntry->PairwiseKey); ++ ++ // update WCID attribute table and IVEIV table for this entry ++ RTMPAddWcidAttributeEntry( ++ pAd, ++ BSS0, ++ KeyIdx, // The value may be not zero ++ pEntry->PairwiseKey.CipherAlg, ++ pEntry); ++ ++ } ++ } ++ else ++ { ++ // Default key for tx (shared key) ++ pAd->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ ++ // set key material and key length ++ pAd->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(pAd->SharedKey[BSS0][KeyIdx].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ ++ // Set Ciper type ++ if (pKey->KeyLength == 5) ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP64; ++ else ++ pAd->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_WEP128; ++ ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ Key = pAd->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAd, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAd, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ } ++ } ++ } ++end: ++ return; ++} ++ ++char * rtstrchr(const char * s, int c) ++{ ++ for(; *s != (char) c; ++s) ++ if (*s == '\0') ++ return NULL; ++ return (char *) s; ++} ++ ++/* ++This is required for LinEX2004/kernel2.6.7 to provide iwlist scanning function ++*/ ++ ++int ++rt_ioctl_giwname(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++// PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++#ifdef RT2870 ++ strncpy(name, "RT2870 Wireless", IFNAMSIZ); ++#endif // RT2870 // ++ return 0; ++} ++ ++int rt_ioctl_siwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ int chan = -1; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ ++ if (freq->e > 1) ++ return -EINVAL; ++ ++ if((freq->e == 0) && (freq->m <= 1000)) ++ chan = freq->m; // Setting by channel number ++ else ++ MAP_KHZ_TO_CHANNEL_ID( (freq->m /100) , chan); // Setting by frequency - search the table , like 2.412G, 2.422G, ++ ++ if (ChannelSanity(pAdapter, chan) == TRUE) ++ { ++ pAdapter->CommonCfg.Channel = chan; ++ DBGPRINT(RT_DEBUG_ERROR, ("==>rt_ioctl_siwfreq::SIOCSIWFREQ[cmd=0x%x] (Channel=%d)\n", SIOCSIWFREQ, pAdapter->CommonCfg.Channel)); ++ } ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++int rt_ioctl_giwfreq(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter; ++ UCHAR ch; ++ ULONG m; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->ml_priv; ++ } ++ else ++ { ++ pVirtualAd = dev->ml_priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; ++ } ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->ml_priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ ch = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("==>rt_ioctl_giwfreq %d\n", ch)); ++ ++ MAP_CHANNEL_ID_TO_KHZ(ch, m); ++ freq->m = m * 100; ++ freq->e = 1; ++ return 0; ++} ++ ++int rt_ioctl_siwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (*mode) ++ { ++ case IW_MODE_ADHOC: ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ break; ++ case IW_MODE_INFRA: ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ break; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ case IW_MODE_MONITOR: ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ break; ++#endif ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); ++ return -EINVAL; ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ if (ADHOC_ON(pAdapter)) ++ *mode = IW_MODE_ADHOC; ++ else if (INFRA_ON(pAdapter)) ++ *mode = IW_MODE_INFRA; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ else if (MONITOR_ON(pAdapter)) ++ { ++ *mode = IW_MODE_MONITOR; ++ } ++#endif ++ else ++ *mode = IW_MODE_AUTO; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("==>rt_ioctl_giwmode(mode=%d)\n", *mode)); ++ return 0; ++} ++ ++int rt_ioctl_siwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwsens(struct net_device *dev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ return 0; ++} ++ ++int rt_ioctl_giwrange(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ struct iw_range *range = (struct iw_range *) extra; ++ u16 val; ++ int i; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===>rt_ioctl_giwrange\n")); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_DBM; ++ ++ if (INFRA_ON(pAdapter)||ADHOC_ON(pAdapter)) ++ { ++ range->min_pmp = 1 * 1024; ++ range->max_pmp = 65535 * 1024; ++ range->min_pmt = 1 * 1024; ++ range->max_pmt = 1000 * 1024; ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_TIMEOUT; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | ++ IW_POWER_UNICAST_R | IW_POWER_ALL_R; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 14; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = pAdapter->ChannelListNum; ++ ++ val = 0; ++ for (i = 1; i <= range->num_channels; i++) ++ { ++ u32 m; ++ range->freq[val].i = pAdapter->ChannelList[i-1].Channel; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ChannelList[i-1].Channel, m); ++ range->freq[val].m = m * 100; /* HZ */ ++ ++ range->freq[val].e = 1; ++ val++; ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ range->num_frequency = val; ++ ++ range->max_qual.qual = 100; /* what is correct max? This was not ++ * documented exactly. At least ++ * 69 has been observed. */ ++ range->max_qual.level = 0; /* dB */ ++ range->max_qual.noise = 0; /* dB */ ++ ++ /* What would be suitable values for "average/typical" qual? */ ++ range->avg_qual.qual = 20; ++ range->avg_qual.level = -60; ++ range->avg_qual.noise = -95; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = NR_WEP_KEYS; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++#if WIRELESS_EXT > 17 ++ /* IW_ENC_CAPA_* bit field */ ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++#endif ++ ++ return 0; ++} ++ ++int rt_ioctl_siwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ memset(Bssid, 0, MAC_ADDR_LEN); ++ memcpy(Bssid, ap_addr->sa_data, MAC_ADDR_LEN); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCSIWAP %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ ++ return 0; ++} ++ ++int rt_ioctl_giwap(struct net_device *dev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->CommonCfg.Bssid, ETH_ALEN); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, &pAdapter->MlmeAux.Bssid, ETH_ALEN); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIWAP(=EMPTY)\n")); ++ return -ENOTCONN; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Units are in db above the noise floor. That means the ++ * rssi values reported in the tx/rx descriptors in the ++ * driver are the SNR expressed in db. ++ * ++ * If you assume that the noise floor is -95, which is an ++ * excellent assumption 99.5 % of the time, then you can ++ * derive the absolute signal level (i.e. -95 + rssi). ++ * There are some other slight factors to take into account ++ * depending on whether the rssi measurement is from 11b, ++ * 11g, or 11a. These differences are at most 2db and ++ * can be documented. ++ * ++ * NB: various calculations are based on the orinoco/wavelan ++ * drivers for compatibility ++ */ ++static void set_quality(PRTMP_ADAPTER pAdapter, ++ struct iw_quality *iq, ++ signed char rssi) ++{ ++ __u8 ChannelQuality; ++ ++ // Normalize Rssi ++ if (rssi >= -50) ++ ChannelQuality = 100; ++ else if (rssi >= -80) // between -50 ~ -80dbm ++ ChannelQuality = (__u8)(24 + ((rssi + 80) * 26)/10); ++ else if (rssi >= -90) // between -80 ~ -90dbm ++ ChannelQuality = (__u8)((rssi + 90) * 26)/10; ++ else ++ ChannelQuality = 0; ++ ++ iq->qual = (__u8)ChannelQuality; ++ ++ iq->level = (__u8)(rssi); ++ iq->noise = (pAdapter->BbpWriteLatch[66] > pAdapter->BbpTuning.FalseCcaUpperThreshold) ? ((__u8)pAdapter->BbpTuning.FalseCcaUpperThreshold) : ((__u8) pAdapter->BbpWriteLatch[66]); // noise level (dBm) ++ iq->noise += 256 - 143; ++ iq->updated = pAdapter->iw_stats.qual.updated; ++} ++ ++int rt_ioctl_iwaplist(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ struct sockaddr addr[IW_MAX_AP]; ++ struct iw_quality qual[IW_MAX_AP]; ++ int i; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ data->length = 0; ++ return 0; ++ //return -ENETDOWN; ++ } ++ ++ for (i = 0; i = pAdapter->ScanTab.BssNr) ++ break; ++ addr[i].sa_family = ARPHRD_ETHER; ++ memcpy(addr[i].sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ set_quality(pAdapter, &qual[i], pAdapter->ScanTab.BssEntry[i].Rssi); ++ } ++ data->length = i; ++ memcpy(extra, &addr, i*sizeof(addr[0])); ++ data->flags = 1; /* signal quality present (sort of) */ ++ memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); ++ ++ return 0; ++} ++ ++#ifdef SIOCGIWSCAN ++int rt_ioctl_siwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ ULONG Now; ++ int Status = NDIS_STATUS_SUCCESS; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ return -EINVAL; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount++; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return 0; ++ do{ ++ Now = jiffies; ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if ((pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) && ++ (pAdapter->StaCfg.WpaSupplicantScanCount > 3)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! WpaSupplicantScanCount > 3\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ RT28XX_MLME_HANDLER(pAdapter); ++ }while(0); ++ return 0; ++} ++ ++int rt_ioctl_giwscan(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ int i=0; ++ char *current_ev = extra, *previous_ev = extra; ++ char *end_buf; ++ char *current_val, custom[MAX_CUSTOM_LEN] = {0}; ++#ifndef IWEVGENIE ++ char idx; ++#endif // IWEVGENIE // ++ struct iw_event iwe; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ return -EAGAIN; ++ } ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ pAdapter->StaCfg.WpaSupplicantScanCount = 0; ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ if (pAdapter->ScanTab.BssNr == 0) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++#if WIRELESS_EXT >= 17 ++ if (data->length > 0) ++ end_buf = extra + data->length; ++ else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#else ++ end_buf = extra + IW_SCAN_MAX_DATA; ++#endif ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ if (current_ev >= end_buf) ++ { ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //MAC address ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, &pAdapter->ScanTab.BssEntry[i].Bssid, ETH_ALEN); ++ ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ /* ++ Protocol: ++ it will show scanned AP's WirelessMode . ++ it might be ++ 802.11a ++ 802.11a/n ++ 802.11g/n ++ 802.11b/g/n ++ 802.11g ++ 802.11b/g ++ */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWNAME; ++ ++ ++ { ++ PBSS_ENTRY pBssEntry=&pAdapter->ScanTab.BssEntry[i]; ++ BOOLEAN isGonly=FALSE; ++ int rateCnt=0; ++ ++ if (pBssEntry->Channel>14) ++ { ++ if (pBssEntry->HtCapabilityLen!=0) ++ strcpy(iwe.u.name,"802.11a/n"); ++ else ++ strcpy(iwe.u.name,"802.11a"); ++ } ++ else ++ { ++ /* ++ if one of non B mode rate is set supported rate . it mean G only. ++ */ ++ for (rateCnt=0;rateCntSupRateLen;rateCnt++) ++ { ++ /* ++ 6Mbps(140) 9Mbps(146) and >=12Mbps(152) are supported rate , it mean G only. ++ */ ++ if (pBssEntry->SupRate[rateCnt]==140 || pBssEntry->SupRate[rateCnt]==146 || pBssEntry->SupRate[rateCnt]>=152) ++ isGonly=TRUE; ++ } ++ ++ for (rateCnt=0;rateCntExtRateLen;rateCnt++) ++ { ++ if (pBssEntry->ExtRate[rateCnt]==140 || pBssEntry->ExtRate[rateCnt]==146 || pBssEntry->ExtRate[rateCnt]>=152) ++ isGonly=TRUE; ++ } ++ ++ ++ if (pBssEntry->HtCapabilityLen!=0) ++ { ++ if (isGonly==TRUE) ++ strcpy(iwe.u.name,"802.11g/n"); ++ else ++ strcpy(iwe.u.name,"802.11b/g/n"); ++ } ++ else ++ { ++ if (isGonly==TRUE) ++ strcpy(iwe.u.name,"802.11g"); ++ else ++ { ++ if (pBssEntry->SupRateLen==4 && pBssEntry->ExtRateLen==0) ++ strcpy(iwe.u.name,"802.11b"); ++ else ++ strcpy(iwe.u.name,"802.11b/g"); ++ } ++ } ++ } ++ } ++ ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //ESSID ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ iwe.u.data.flags = 1; ++ ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pAdapter->ScanTab.BssEntry[i].Ssid); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Network Type ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11IBSS) ++ { ++ iwe.u.mode = IW_MODE_ADHOC; ++ } ++ else if (pAdapter->ScanTab.BssEntry[i].BssType == Ndis802_11Infrastructure) ++ { ++ iwe.u.mode = IW_MODE_INFRA; ++ } ++ else ++ { ++ iwe.u.mode = IW_MODE_AUTO; ++ } ++ iwe.len = IW_EV_UINT_LEN; ++ ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Channel and Frequency ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ else ++ iwe.u.freq.m = pAdapter->ScanTab.BssEntry[i].Channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++ ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Add quality statistics ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.level = 0; ++ iwe.u.qual.noise = 0; ++ set_quality(pAdapter, &iwe.u.qual, pAdapter->ScanTab.BssEntry[i].Rssi); ++ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Encyption key ++ //================================ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (CAP_IS_PRIVACY_ON (pAdapter->ScanTab.BssEntry[i].CapabilityInfo )) ++ iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_point(info, current_ev, end_buf,&iwe, (char *)pAdapter->SharedKey[BSS0][(iwe.u.data.flags & IW_ENCODE_INDEX)-1].Key); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ ++ //Bit Rate ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].SupRateLen) ++ { ++ UCHAR tmpRate = pAdapter->ScanTab.BssEntry[i].SupRate[pAdapter->ScanTab.BssEntry[i].SupRateLen-1]; ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWRATE; ++ current_val = current_ev + IW_EV_LCP_LEN; ++ if (tmpRate == 0x82) ++ iwe.u.bitrate.value = 1 * 1000000; ++ else if (tmpRate == 0x84) ++ iwe.u.bitrate.value = 2 * 1000000; ++ else if (tmpRate == 0x8B) ++ iwe.u.bitrate.value = 5.5 * 1000000; ++ else if (tmpRate == 0x96) ++ iwe.u.bitrate.value = 11 * 1000000; ++ else ++ iwe.u.bitrate.value = (tmpRate/2) * 1000000; ++ ++ iwe.u.bitrate.disabled = 0; ++ current_val = iwe_stream_add_value(info, current_ev, ++ current_val, end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ ++ if((current_val-current_ev)>IW_EV_LCP_LEN) ++ current_ev = current_val; ++ else ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++#ifdef IWEVGENIE ++ //WPA IE ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].WpaIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].WpaIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; ++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ memset(&iwe, 0, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ memcpy(custom, &(pAdapter->ScanTab.BssEntry[i].RsnIE.IE[0]), ++ pAdapter->ScanTab.BssEntry[i].RsnIE.IELen); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; ++ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#else ++ //WPA IE ++ //================================ ++ if (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].WpaIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "wpa_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].WpaIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].WpaIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++ ++ //WPA2 IE ++ if (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen > 0) ++ { ++ NdisZeroMemory(&iwe, sizeof(iwe)); ++ memset(&custom[0], 0, MAX_CUSTOM_LEN); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = (pAdapter->ScanTab.BssEntry[i].RsnIE.IELen * 2) + 7; ++ NdisMoveMemory(custom, "rsn_ie=", 7); ++ for (idx = 0; idx < pAdapter->ScanTab.BssEntry[i].RsnIE.IELen; idx++) ++ sprintf(custom, "%s%02x", custom, pAdapter->ScanTab.BssEntry[i].RsnIE.IE[idx]); ++ previous_ev = current_ev; ++ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); ++ if (current_ev == previous_ev) ++#if WIRELESS_EXT >= 17 ++ return -E2BIG; ++#else ++ break; ++#endif ++ } ++#endif // IWEVGENIE // ++ } ++ ++ data->length = current_ev - extra; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ DBGPRINT(RT_DEBUG_ERROR ,("===>rt_ioctl_giwscan. %d(%d) BSS returned, data->length = %d\n",i , pAdapter->ScanTab.BssNr, data->length)); ++ return 0; ++} ++#endif ++ ++int rt_ioctl_siwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->flags) ++ { ++ PCHAR pSsidString = NULL; ++ ++ // Includes null character. ++ if (data->length > (IW_ESSID_MAX_SIZE + 1)) ++ return -E2BIG; ++ ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, essid, data->length); ++ if (Set_SSID_Proc(pAdapter, pSsidString) == FALSE) ++ return -EINVAL; ++ } ++ else ++ return -ENOMEM; ++ } ++ else ++ { ++ // ANY ssid ++ if (Set_SSID_Proc(pAdapter, "") == FALSE) ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int rt_ioctl_giwessid(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *essid) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ data->flags = 1; ++ if (MONITOR_ON(pAdapter)) ++ { ++ data->length = 0; ++ return 0; ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is connected\n")); ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#ifdef RT2870 ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // Add for RT2870 ++ else if (pAdapter->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_DISABLE) ++ { ++ data->length = pAdapter->CommonCfg.SsidLen; ++ memcpy(essid, pAdapter->CommonCfg.Ssid, pAdapter->CommonCfg.SsidLen); ++ } ++#endif // WPA_SUPPLICANT_SUPPORT // ++#endif // RT2870 // ++ else ++ {//the ANY ssid was specified ++ data->length = 0; ++ DBGPRINT(RT_DEBUG_TRACE ,("MediaState is not connected, ess\n")); ++ } ++ ++ return 0; ++ ++} ++ ++int rt_ioctl_siwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (data->length > IW_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(pAdapter->nickname, 0, IW_ESSID_MAX_SIZE + 1); ++ memcpy(pAdapter->nickname, nickname, data->length); ++ ++ ++ return 0; ++} ++ ++int rt_ioctl_giwnickn(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *nickname) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ if (data->length > strlen(pAdapter->nickname) + 1) ++ data->length = strlen(pAdapter->nickname) + 1; ++ if (data->length > 0) { ++ memcpy(nickname, pAdapter->nickname, data->length-1); ++ nickname[data->length-1] = '\0'; ++ } ++ return 0; ++} ++ ++int rt_ioctl_siwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (rts->disabled) ++ val = MAX_RTS_THRESHOLD; ++ else if (rts->value < 0 || rts->value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ else if (rts->value == 0) ++ val = MAX_RTS_THRESHOLD; ++ else ++ val = rts->value; ++ ++ if (val != pAdapter->CommonCfg.RtsThreshold) ++ pAdapter->CommonCfg.RtsThreshold = val; ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrts(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ rts->value = pAdapter->CommonCfg.RtsThreshold; ++ rts->disabled = (rts->value == MAX_RTS_THRESHOLD); ++ rts->fixed = 1; ++ ++ return 0; ++} ++ ++int rt_ioctl_siwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ u16 val; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (frag->disabled) ++ val = MAX_FRAG_THRESHOLD; ++ else if (frag->value >= MIN_FRAG_THRESHOLD || frag->value <= MAX_FRAG_THRESHOLD) ++ val = __cpu_to_le16(frag->value & ~0x1); /* even numbers only */ ++ else if (frag->value == 0) ++ val = MAX_FRAG_THRESHOLD; ++ else ++ return -EINVAL; ++ ++ pAdapter->CommonCfg.FragmentThreshold = val; ++ return 0; ++} ++ ++int rt_ioctl_giwfrag(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ frag->value = pAdapter->CommonCfg.FragmentThreshold; ++ frag->disabled = (frag->value == MAX_FRAG_THRESHOLD); ++ frag->fixed = 1; ++ ++ return 0; ++} ++ ++#define MAX_WEP_KEY_SIZE 13 ++#define MIN_WEP_KEY_SIZE 5 ++int rt_ioctl_siwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((erq->length == 0) && ++ (erq->flags & IW_ENCODE_DISABLED)) ++ { ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ goto done; ++ } ++ else if (erq->flags & IW_ENCODE_RESTRICTED || erq->flags & IW_ENCODE_OPEN) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ if (erq->flags & IW_ENCODE_RESTRICTED) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ } ++ ++ if (erq->length > 0) ++ { ++ int keyIdx = (erq->flags & IW_ENCODE_INDEX) - 1; ++ /* Check the size of the key */ ++ if (erq->length > MAX_WEP_KEY_SIZE) ++ { ++ return -EINVAL; ++ } ++ /* Check key index */ ++ if ((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::Wrong keyIdx=%d! Using default key instead (%d)\n", ++ keyIdx, pAdapter->StaCfg.DefaultKeyId)); ++ ++ //Using default key ++ keyIdx = pAdapter->StaCfg.DefaultKeyId; ++ } ++ else ++ { ++ pAdapter->StaCfg.DefaultKeyId=keyIdx; ++ } ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ ++ if (erq->length == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (erq->length == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ /* Disable the key */ ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ ++ /* Check if the key is not marked as invalid */ ++ if(!(erq->flags & IW_ENCODE_NOKEY)) ++ { ++ /* Copy the key in the driver */ ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, extra, erq->length); ++ } ++ } ++ else ++ { ++ /* Do we want to just set the transmit key index ? */ ++ int index = (erq->flags & IW_ENCODE_INDEX) - 1; ++ if ((index >= 0) && (index < 4)) ++ { ++ pAdapter->StaCfg.DefaultKeyId = index; ++ } ++ else ++ /* Don't complain if only change the mode */ ++ if(!erq->flags & IW_ENCODE_MODE) ++ { ++ return -EINVAL; ++ } ++ } ++ ++done: ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::erq->flags=%x\n",erq->flags)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::AuthMode=%x\n",pAdapter->StaCfg.AuthMode)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::DefaultKeyId=%x, KeyLen = %d\n",pAdapter->StaCfg.DefaultKeyId , pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen)); ++ DBGPRINT(RT_DEBUG_TRACE ,("==>rt_ioctl_siwencode::WepStatus=%x\n",pAdapter->StaCfg.WepStatus)); ++ return 0; ++} ++ ++int ++rt_ioctl_giwencode(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *erq, char *key) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ int kid; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ kid = erq->flags & IW_ENCODE_INDEX; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_giwencode %d\n", erq->flags & IW_ENCODE_INDEX)); ++ ++ if (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ++ { ++ erq->length = 0; ++ erq->flags = IW_ENCODE_DISABLED; ++ } ++ else if ((kid > 0) && (kid <=4)) ++ { ++ // copy wep key ++ erq->flags = kid ; /* NB: base 1 */ ++ if (erq->length > pAdapter->SharedKey[BSS0][kid-1].KeyLen) ++ erq->length = pAdapter->SharedKey[BSS0][kid-1].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][kid-1].Key, erq->length); ++ //if ((kid == pAdapter->PortCfg.DefaultKeyId)) ++ //erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ ++ } ++ else if (kid == 0) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->length = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ memcpy(key, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, erq->length); ++ // copy default key ID ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; /* XXX */ ++ else ++ erq->flags |= IW_ENCODE_OPEN; /* XXX */ ++ erq->flags = pAdapter->StaCfg.DefaultKeyId + 1; /* NB: base 1 */ ++ erq->flags |= IW_ENCODE_ENABLED; /* XXX */ ++ } ++ ++ return 0; ++ ++} ++ ++static int ++rt_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, ++ void *w, char *extra) ++{ ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAdapter; ++ POS_COOKIE pObj; ++ char *this_char = extra; ++ char *value; ++ int Status=0; ++ ++ if (dev->priv_flags == INT_MAIN) ++ { ++ pAdapter = dev->ml_priv; ++ } ++ else ++ { ++ pVirtualAd = dev->ml_priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; ++ } ++ pObj = (POS_COOKIE) pAdapter->OS_Cookie; ++ ++ if (pAdapter == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->ml_priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (!*this_char) ++ return -EINVAL; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value) ++ return -EINVAL; ++ ++ // reject setting nothing besides ANY ssid(ssidLen=0) ++ if (!*value && (strcmp(this_char, "SSID") != 0)) ++ return -EINVAL; ++ ++ for (PRTMP_PRIVATE_SET_PROC = RTMP_PRIVATE_SUPPORT_PROC; PRTMP_PRIVATE_SET_PROC->name; PRTMP_PRIVATE_SET_PROC++) ++ { ++ if (strcmp(this_char, PRTMP_PRIVATE_SET_PROC->name) == 0) ++ { ++ if(!PRTMP_PRIVATE_SET_PROC->set_proc(pAdapter, value)) ++ { //FALSE:Set private failed then return Invalid argument ++ Status = -EINVAL; ++ } ++ break; //Exit for loop. ++ } ++ } ++ ++ if(PRTMP_PRIVATE_SET_PROC->name == NULL) ++ { //Not found argument ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_setparam:: (iwpriv) Not Support Set Command [%s=%s]\n", this_char, value)); ++ } ++ ++ return Status; ++} ++ ++ ++static int ++rt_private_get_statistics(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n\n"); ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ //sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->ate.TxDoneCount); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "Tx success = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx success without retry = %ld\n", (ULONG)pAd->WlanCounters.TransmittedFragmentCount.QuadPart - (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ } ++ sprintf(extra+strlen(extra), "Tx success after retry = %ld\n", (ULONG)pAd->WlanCounters.RetryCount.QuadPart); ++ sprintf(extra+strlen(extra), "Tx fail to Rcv ACK after retry = %ld\n", (ULONG)pAd->WlanCounters.FailedCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Success Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSSuccessCount.QuadPart); ++ sprintf(extra+strlen(extra), "RTS Fail Rcv CTS = %ld\n", (ULONG)pAd->WlanCounters.RTSFailureCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "Rx success = %ld\n", (ULONG)pAd->WlanCounters.ReceivedFragmentCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx with CRC = %ld\n", (ULONG)pAd->WlanCounters.FCSErrorCount.QuadPart); ++ sprintf(extra+strlen(extra), "Rx drop due to out of resource = %ld\n", (ULONG)pAd->Counters8023.RxNoBuffer); ++ sprintf(extra+strlen(extra), "Rx duplicate frame = %ld\n", (ULONG)pAd->WlanCounters.FrameDuplicateCount.QuadPart); ++ ++ sprintf(extra+strlen(extra), "False CCA (one second) = %ld\n", (ULONG)pAd->RalinkCounters.OneSecFalseCCACnt); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ if (pAd->ate.RxAntennaSel == 0) ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->ate.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->ate.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++ else ++ { ++ sprintf(extra+strlen(extra), "RSSI = %ld\n", (LONG)(pAd->ate.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ } ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ sprintf(extra+strlen(extra), "RSSI-A = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi0 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-B (if available) = %ld\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi1 - pAd->BbpRssiToDbmDelta)); ++ sprintf(extra+strlen(extra), "RSSI-C (if available) = %ld\n\n", (LONG)(pAd->StaCfg.RssiSample.LastRssi2 - pAd->BbpRssiToDbmDelta)); ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ sprintf(extra+strlen(extra), "WpaSupplicantUP = %d\n\n", pAd->StaCfg.WpaSupplicantUP); ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("<== rt_private_get_statistics, wrq->length = %d\n", wrq->length)); ++ ++ return Status; ++} ++ ++#ifdef DOT11_N_SUPPORT ++void getBaInfo( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pOutBuf) ++{ ++ INT i, j; ++ BA_ORI_ENTRY *pOriBAEntry; ++ BA_REC_ENTRY *pRecBAEntry; ++ ++ for (i=0; iMacTab.Content[i]; ++ if (((pEntry->ValidAsCLI || pEntry->ValidAsApCli) && (pEntry->Sst == SST_ASSOC)) ++ || (pEntry->ValidAsWDS) || (pEntry->ValidAsMesh)) ++ { ++ sprintf(pOutBuf, "%s\n%02X:%02X:%02X:%02X:%02X:%02X (Aid = %d) (AP) -\n", ++ pOutBuf, ++ pEntry->Addr[0], pEntry->Addr[1], pEntry->Addr[2], ++ pEntry->Addr[3], pEntry->Addr[4], pEntry->Addr[5], pEntry->Aid); ++ ++ sprintf(pOutBuf, "%s[Recipient]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BARecWcidArray[j] != 0) ++ { ++ pRecBAEntry =&pAd->BATable.BARecEntry[pEntry->BARecWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, LastIndSeq=%d, ReorderingPkts=%d\n", pOutBuf, j, pRecBAEntry->BAWinSize, pRecBAEntry->LastIndSeq, pRecBAEntry->list.qlen); ++ } ++ } ++ sprintf(pOutBuf, "%s\n", pOutBuf); ++ ++ sprintf(pOutBuf, "%s[Originator]\n", pOutBuf); ++ for (j=0; j < NUM_OF_TID; j++) ++ { ++ if (pEntry->BAOriWcidArray[j] != 0) ++ { ++ pOriBAEntry =&pAd->BATable.BAOriEntry[pEntry->BAOriWcidArray[j]]; ++ sprintf(pOutBuf, "%sTID=%d, BAWinSize=%d, StartSeq=%d, CurTxSeq=%d\n", pOutBuf, j, pOriBAEntry->BAWinSize, pOriBAEntry->Sequence, pEntry->TxSeq[j]); ++ } ++ } ++ sprintf(pOutBuf, "%s\n\n", pOutBuf); ++ } ++ if (strlen(pOutBuf) > (IW_PRIV_SIZE_MASK - 30)) ++ break; ++ } ++ ++ return; ++} ++#endif // DOT11_N_SUPPORT // ++ ++static int ++rt_private_show(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++{ ++ INT Status = 0; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ PRTMP_ADAPTER pAd; ++ POS_COOKIE pObj; ++ u32 subcmd = wrq->flags; ++ ++ if (dev->priv_flags == INT_MAIN) ++ pAd = dev->ml_priv; ++ else ++ { ++ pVirtualAd = dev->ml_priv; ++ pAd = pVirtualAd->RtmpDev->ml_priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->ml_priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ if (extra == NULL) ++ { ++ wrq->length = 0; ++ return -EIO; ++ } ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ { ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(subcmd) ++ { ++ ++ case SHOW_CONN_STATUS: ++ if (MONITOR_ON(pAd)) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAd->CommonCfg.RegTransmitSetting.field.BW) ++ sprintf(extra, "Monitor Mode(CentralChannel %d)\n", pAd->CommonCfg.CentralChannel); ++ else ++#endif // DOT11_N_SUPPORT // ++ sprintf(extra, "Monitor Mode(Channel %d)\n", pAd->CommonCfg.Channel); ++ } ++ else ++ { ++ if (pAd->IndicateMediaState == NdisMediaStateConnected) ++ { ++ if (INFRA_ON(pAd)) ++ { ++ sprintf(extra, "Connected(AP: %s[%02X:%02X:%02X:%02X:%02X:%02X])\n", ++ pAd->CommonCfg.Ssid, ++ pAd->CommonCfg.Bssid[0], ++ pAd->CommonCfg.Bssid[1], ++ pAd->CommonCfg.Bssid[2], ++ pAd->CommonCfg.Bssid[3], ++ pAd->CommonCfg.Bssid[4], ++ pAd->CommonCfg.Bssid[5]); ++ DBGPRINT(RT_DEBUG_TRACE ,("Ssid=%s ,Ssidlen = %d\n",pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)); ++ } ++ else if (ADHOC_ON(pAd)) ++ sprintf(extra, "Connected\n"); ++ } ++ else ++ { ++ sprintf(extra, "Disconnected\n"); ++ DBGPRINT(RT_DEBUG_TRACE ,("ConnStatus is not connected\n")); ++ } ++ } ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case SHOW_DRVIER_VERION: ++ sprintf(extra, "Driver version-%s, %s %s\n", STA_DRIVER_VERSION, __DATE__, __TIME__ ); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#ifdef DOT11_N_SUPPORT ++ case SHOW_BA_INFO: ++ getBaInfo(pAd, extra); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SHOW_DESC_INFO: ++ { ++ Show_DescInfo_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++ case RAIO_OFF: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = FALSE; ++ if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ MlmeRadioOff(pAd); ++ // Update extra information ++ pAd->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ sprintf(extra, "Radio Off\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ case RAIO_ON: ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ sprintf(extra, "Scanning\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ } ++ pAd->StaCfg.bSwRadio = TRUE; ++ //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) ++ { ++ pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAd); ++ // Update extra information ++ pAd->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ } ++ sprintf(extra, "Radio On\n"); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case SHOW_DLS_ENTRY_INFO: ++ { ++ Set_DlsEntryInfo_Display_Proc(pAd, NULL); ++ wrq->length = 0; // 1: size of '\0' ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ ++ case SHOW_CFG_VALUE: ++ { ++ Status = RTMPShowCfgValue(pAd, wrq->pointer, extra); ++ if (Status == 0) ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ } ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); ++ break; ++ } ++ ++ return Status; ++} ++ ++#ifdef SIOCSIWMLME ++int rt_ioctl_siwmlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; ++ MLME_QUEUE_ELEM MsgElem; ++ MLME_DISASSOC_REQ_STRUCT DisAssocReq; ++ MLME_DEAUTH_REQ_STRUCT DeAuthReq; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); ++ ++ if (pMlme == NULL) ++ return -EINVAL; ++ ++ switch(pMlme->cmd) ++ { ++#ifdef IW_MLME_DEAUTH ++ case IW_MLME_DEAUTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); ++ DeAuthReq.Reason = pMlme->reason_code; ++ MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DeAuthReq, sizeof(MLME_DEAUTH_REQ_STRUCT)); ++ MlmeDeauthReqAction(pAd, &MsgElem); ++ if (INFRA_ON(pAd)) ++ { ++ LinkDown(pAd, FALSE); ++ pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ break; ++#endif // IW_MLME_DEAUTH // ++#ifdef IW_MLME_DISASSOC ++ case IW_MLME_DISASSOC: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); ++ COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); ++ DisAssocReq.Reason = pMlme->reason_code; ++ ++ MsgElem.Machine = ASSOC_STATE_MACHINE; ++ MsgElem.MsgType = MT2_MLME_DISASSOC_REQ; ++ MsgElem.MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT); ++ NdisMoveMemory(MsgElem.Msg, &DisAssocReq, sizeof(MLME_DISASSOC_REQ_STRUCT)); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC; ++ MlmeDisassocReqAction(pAd, &MsgElem); ++ break; ++#endif // IW_MLME_DISASSOC // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); ++ break; ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWMLME // ++ ++#if WIRELESS_EXT > 17 ++int rt_ioctl_siwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ if (param->value == IW_AUTH_WPA_VERSION_WPA) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ } ++ else if (param->value == IW_AUTH_WPA_VERSION_WPA2) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ if (param->value == IW_AUTH_CIPHER_NONE) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_WEP40 || ++ param->value == IW_AUTH_CIPHER_WEP104) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_TKIP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if (param->value == IW_AUTH_CIPHER_CCMP) ++ { ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_KEY_MGMT: ++ if (param->value == IW_AUTH_KEY_MGMT_802_1X) ++ { ++ if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ pAdapter->StaCfg.IEEE8021X = FALSE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else ++ // WEP 1x ++ pAdapter->StaCfg.IEEE8021X = TRUE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ } ++ else if (param->value == 0) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ /*if (param->value == 0) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ }*/ ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ if (param->value != 0) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ if (param->value & IW_AUTH_ALG_SHARED_KEY) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ } ++ else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) ++ { ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ } ++ else ++ return -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); ++ break; ++ default: ++ return -EOPNOTSUPP; ++} ++ ++ return 0; ++} ++ ++int rt_ioctl_giwauth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ struct iw_param *param = &wrqu->param; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_DROP_UNENCRYPTED: ++ param->value = (pAdapter->StaCfg.WepStatus == Ndis802_11WEPDisabled) ? 0 : 1; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ param->value = (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeShared) ? IW_AUTH_ALG_SHARED_KEY : IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ ++ case IW_AUTH_WPA_ENABLED: ++ param->value = (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ? 1 : 0; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_giwauth::param->value = %d!\n", param->value)); ++ return 0; ++} ++ ++void fnSetCipherKey( ++ IN PRTMP_ADAPTER pAdapter, ++ IN INT keyIdx, ++ IN UCHAR CipherAlg, ++ IN BOOLEAN bGTK, ++ IN struct iw_encode_ext *ext) ++{ ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].TxMic, ext->key + LEN_TKIP_EK, LEN_TKIP_TXMICK); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].RxMic, ext->key + LEN_TKIP_EK + LEN_TKIP_TXMICK, LEN_TKIP_RXMICK); ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CipherAlg; ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ pAdapter->SharedKey[BSS0][keyIdx].Key, ++ pAdapter->SharedKey[BSS0][keyIdx].TxMic, ++ pAdapter->SharedKey[BSS0][keyIdx].RxMic); ++ ++ if (bGTK) ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ NULL); ++ else ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAdapter, ++ BSS0, ++ keyIdx, ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, ++ &pAdapter->MacTab.Content[BSSID_WCID]); ++} ++ ++int rt_ioctl_siwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++ { ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int keyIdx, alg = ext->alg; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if (encoding->flags & IW_ENCODE_DISABLED) ++ { ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ // set BSSID wcid entry of the Pair-wise Key table as no-security mode ++ AsicRemovePairwiseKeyEntry(pAdapter, BSS0, BSSID_WCID); ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); ++ NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); ++ } ++ else ++ { ++ // Get Key Index and convet to our own defined key index ++ keyIdx = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ if((keyIdx < 0) || (keyIdx >= NR_WEP_KEYS)) ++ return -EINVAL; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ pAdapter->StaCfg.DefaultKeyId = keyIdx; ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); ++ } ++ ++ switch (alg) { ++ case IW_ENCODE_ALG_NONE: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); ++ break; ++ case IW_ENCODE_ALG_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); ++ if (ext->key_len == MAX_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP128; ++ } ++ else if (ext->key_len == MIN_WEP_KEY_SIZE) ++ { ++ pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MIN_WEP_KEY_SIZE; ++ pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_WEP64; ++ } ++ else ++ return -EINVAL; ++ ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); ++ if (ext->key_len == 32) ++ { ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ { ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_TKIP, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ } ++ else ++ return -EINVAL; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, FALSE, ext); ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA2) ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ else if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ++ { ++ fnSetCipherKey(pAdapter, keyIdx, CIPHER_AES, TRUE, ext); ++ ++ // set 802.1x port control ++ //pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAdapter); ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++rt_ioctl_giwencodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ PCHAR pKey = NULL; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int idx, max_key_len; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_giwencodeext\n")); ++ ++ max_key_len = encoding->length - sizeof(*ext); ++ if (max_key_len < 0) ++ return -EINVAL; ++ ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) ++ { ++ if (idx < 1 || idx > 4) ++ return -EINVAL; ++ idx--; ++ ++ if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)) ++ { ++ if (idx != pAd->StaCfg.DefaultKeyId) ++ { ++ ext->key_len = 0; ++ return 0; ++ } ++ } ++ } ++ else ++ idx = pAd->StaCfg.DefaultKeyId; ++ ++ encoding->flags = idx + 1; ++ memset(ext, 0, sizeof(*ext)); ++ ++ ext->key_len = 0; ++ switch(pAd->StaCfg.WepStatus) { ++ case Ndis802_11WEPDisabled: ++ ext->alg = IW_ENCODE_ALG_NONE; ++ encoding->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11WEPEnabled: ++ ext->alg = IW_ENCODE_ALG_WEP; ++ if (pAd->SharedKey[BSS0][idx].KeyLen > max_key_len) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = pAd->SharedKey[BSS0][idx].KeyLen; ++ pKey = &(pAd->SharedKey[BSS0][idx].Key[0]); ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ++ ext->alg = IW_ENCODE_ALG_TKIP; ++ else ++ ext->alg = IW_ENCODE_ALG_CCMP; ++ ++ if (max_key_len < 32) ++ return -E2BIG; ++ else ++ { ++ ext->key_len = 32; ++ pKey = &pAd->StaCfg.PMK[0]; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (ext->key_len && pKey) ++ { ++ encoding->flags |= IW_ENCODE_ENABLED; ++ memcpy(ext->key, pKey, ext->key_len); ++ } ++ ++ return 0; ++} ++ ++#ifdef SIOCSIWGENIE ++int rt_ioctl_siwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ ++ if (wrqu->data.length > MAX_LEN_OF_RSNIE || ++ (wrqu->data.length && extra == NULL)) ++ return -EINVAL; ++ ++ if (wrqu->data.length) ++ { ++ pAd->StaCfg.RSNIE_Len = wrqu->data.length; ++ NdisMoveMemory(&pAd->StaCfg.RSN_IE[0], extra, pAd->StaCfg.RSNIE_Len); ++ } ++ else ++ { ++ pAd->StaCfg.RSNIE_Len = 0; ++ NdisZeroMemory(&pAd->StaCfg.RSN_IE[0], MAX_LEN_OF_RSNIE); ++ } ++ ++ return 0; ++} ++#endif // SIOCSIWGENIE // ++ ++int rt_ioctl_giwgenie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ ++ if ((pAd->StaCfg.RSNIE_Len == 0) || ++ (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) ++ { ++ wrqu->data.length = 0; ++ return 0; ++ } ++ ++#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT ++#ifdef SIOCSIWGENIE ++ if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) ++ { ++ if (wrqu->data.length < pAd->StaCfg.RSNIE_Len) ++ return -E2BIG; ++ ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ else ++#endif // SIOCSIWGENIE // ++#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // ++ { ++ UCHAR RSNIe = IE_WPA; ++ ++ if (wrqu->data.length < (pAd->StaCfg.RSNIE_Len + 2)) // ID, Len ++ return -E2BIG; ++ wrqu->data.length = pAd->StaCfg.RSNIE_Len + 2; ++ ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)) ++ RSNIe = IE_RSN; ++ ++ extra[0] = (char)RSNIe; ++ extra[1] = pAd->StaCfg.RSNIE_Len; ++ memcpy(extra+2, &pAd->StaCfg.RSN_IE[0], pAd->StaCfg.RSNIE_Len); ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_siwpmksa(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, ++ char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; ++ INT CachedIdx = 0, idx = 0; ++ ++ if (pPmksa == NULL) ++ return -EINVAL; ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("===> rt_ioctl_siwpmksa\n")); ++ switch(pPmksa->cmd) ++ { ++ case IW_PMKSA_FLUSH: ++ NdisZeroMemory(pAd->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_FLUSH\n")); ++ break; ++ case IW_PMKSA_REMOVE: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ { ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN); ++ NdisZeroMemory(pAd->StaCfg.SavedPMK[CachedIdx].PMKID, 16); ++ for (idx = CachedIdx; idx < (pAd->StaCfg.SavedPMKNum - 1); idx++) ++ { ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].BSSID[0], &pAd->StaCfg.SavedPMK[idx+1].BSSID[0], MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[idx].PMKID[0], &pAd->StaCfg.SavedPMK[idx+1].PMKID[0], 16); ++ } ++ pAd->StaCfg.SavedPMKNum--; ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_REMOVE\n")); ++ break; ++ case IW_PMKSA_ADD: ++ for (CachedIdx = 0; CachedIdx < pAd->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pPmksa->bssid.sa_data, pAd->StaCfg.SavedPMK[CachedIdx].BSSID, MAC_ADDR_LEN)) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ pAd->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pPmksa->bssid.sa_data[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].BSSID[0], pPmksa->bssid.sa_data, MAC_ADDR_LEN); ++ NdisMoveMemory(&pAd->StaCfg.SavedPMK[CachedIdx].PMKID[0], pPmksa->pmkid, 16); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - IW_PMKSA_ADD\n")); ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE ,("rt_ioctl_siwpmksa - Unknow Command!!\n")); ++ break; ++ } ++ ++ return 0; ++} ++#endif // #if WIRELESS_EXT > 17 ++ ++#ifdef DBG ++static int ++rt_private_ioctl_bbp(struct net_device *dev, struct iw_request_info *info, ++ struct iw_point *wrq, char *extra) ++ { ++ CHAR *this_char; ++ CHAR *value = NULL; ++ UCHAR regBBP = 0; ++// CHAR arg[255]={0}; ++ UINT32 bbpId; ++ UINT32 bbpValue; ++ BOOLEAN bIsPrintAllBBP = FALSE; ++ INT Status = 0; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; ++ ++ ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ ++ if (wrq->length > 1) //No parameters. ++ { ++ sprintf(extra, "\n"); ++ ++ //Parsing Read or Write ++ this_char = wrq->pointer; ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s\n", this_char)); ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ DBGPRINT(RT_DEBUG_TRACE, ("this_char=%s, value=%s\n", this_char, value)); ++ if (sscanf(this_char, "%d", &(bbpId)) == 1) ++ { ++#ifndef RT30xx ++ if (bbpId <= 136) ++#endif // RT30xx // ++#ifdef RT30xx ++ if (bbpId <= 138) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control ++#endif // RT30xx // ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Write ++ if ((sscanf(this_char, "%d", &(bbpId)) == 1) && (sscanf(value, "%x", &(bbpValue)) == 1)) ++ { ++#ifndef RT30xx ++ if (bbpId <= 136) ++#endif // RT30xx // ++#ifdef RT30xx ++ if (bbpId <= 138) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control ++#endif // RT30xx // ++ { ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, bbpId, bbpValue); ++ //Read it back for showing ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X\n", bbpId, bbpId*2, regBBP); ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("msg=%s\n", extra)); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all bbp ++ bIsPrintAllBBP = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ bIsPrintAllBBP = TRUE; ++ ++next: ++ if (bIsPrintAllBBP) ++ { ++ memset(extra, 0x00, IW_PRIV_SIZE_MASK); ++ sprintf(extra, "\n"); ++#ifndef RT30xx ++ for (bbpId = 0; bbpId <= 136; bbpId++) ++#endif // RT30xx // ++#ifdef RT30xx ++ for (bbpId = 0; bbpId <= 138; bbpId++) // edit by johnli, RF power sequence setup, add BBP R138 for ADC dynamic on/off control ++#endif // RT30xx // ++ { ++ if (strlen(extra) >= (IW_PRIV_SIZE_MASK - 10)) ++ break; ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++/* ++ sprintf(extra+strlen(extra), "R%02d[0x%02X]:%02X ", bbpId, bbpId*2, regBBP); ++ if (bbpId%5 == 4) ++ sprintf(extra+strlen(extra), "\n"); ++*/ ++ sprintf(extra+strlen(extra), "%03d = %02X\n", bbpId, regBBP); // edit by johnli, change display format ++ } ++ ++ wrq->length = strlen(extra) + 1; // 1: size of '\0' ++ DBGPRINT(RT_DEBUG_TRACE, ("wrq->length = %d\n", wrq->length)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==rt_private_ioctl_bbp\n\n")); ++ ++ return Status; ++} ++#endif // DBG // ++ ++int rt_ioctl_siwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(rate = %d, fixed = %d)\n", rate, fixed)); ++ /* rate = -1 => auto rate ++ rate = X, fixed = 1 => (fixed rate X) ++ */ ++ if (rate == -1) ++ { ++ //Auto Rate ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++ pAd->StaCfg.bAutoTxRateSwitch = TRUE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, -1); ++ ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ else ++ { ++ if (fixed) ++ { ++ pAd->StaCfg.bAutoTxRateSwitch = FALSE; ++ if ((pAd->CommonCfg.PhyMode <= PHY_11G) || ++ (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM)) ++ RTMPSetDesiredRates(pAd, rate); ++ else ++ { ++ pAd->StaCfg.DesiredTransmitSetting.field.MCS = MCS_AUTO; ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAd); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("rt_ioctl_siwrate::(HtMcs=%d)\n",pAd->StaCfg.DesiredTransmitSetting.field.MCS)); ++ } ++ else ++ { ++ // TODO: rate = X, fixed = 0 => (rates <= X) ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ return 0; ++} ++ ++int rt_ioctl_giwrate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ PRTMP_ADAPTER pAd = dev->ml_priv; ++ int rate_index = 0, rate_count = 0; ++ HTTRANSMIT_SETTING ht_setting; ++ __s32 ralinkrate[] = ++ {2, 4, 11, 22, // CCK ++ 12, 18, 24, 36, 48, 72, 96, 108, // OFDM ++ 13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, 260, // 20MHz, 800ns GI, MCS: 0 ~ 15 ++ 39, 78, 117, 156, 234, 312, 351, 390, // 20MHz, 800ns GI, MCS: 16 ~ 23 ++ 27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, 540, // 40MHz, 800ns GI, MCS: 0 ~ 15 ++ 81, 162, 243, 324, 486, 648, 729, 810, // 40MHz, 800ns GI, MCS: 16 ~ 23 ++ 14, 29, 43, 57, 87, 115, 130, 144, 29, 59, 87, 115, 173, 230, 260, 288, // 20MHz, 400ns GI, MCS: 0 ~ 15 ++ 43, 87, 130, 173, 260, 317, 390, 433, // 20MHz, 400ns GI, MCS: 16 ~ 23 ++ 30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, 600, // 40MHz, 400ns GI, MCS: 0 ~ 15 ++ 90, 180, 270, 360, 540, 720, 810, 900}; // 40MHz, 400ns GI, MCS: 16 ~ 23 ++ ++ rate_count = sizeof(ralinkrate)/sizeof(__s32); ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ ++ if ((pAd->StaCfg.bAutoTxRateSwitch == FALSE) && ++ (INFRA_ON(pAd)) && ++ ((pAd->CommonCfg.PhyMode <= PHY_11G) || (pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE <= MODE_OFDM))) ++ ht_setting.word = pAd->StaCfg.HTPhyMode.word; ++ else ++ ht_setting.word = pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ ++#ifdef DOT11_N_SUPPORT ++ if (ht_setting.field.MODE >= MODE_HTMIX) ++ { ++// rate_index = 12 + ((UCHAR)ht_setting.field.BW *16) + ((UCHAR)ht_setting.field.ShortGI *32) + ((UCHAR)ht_setting.field.MCS); ++ rate_index = 12 + ((UCHAR)ht_setting.field.BW *24) + ((UCHAR)ht_setting.field.ShortGI *48) + ((UCHAR)ht_setting.field.MCS); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ if (ht_setting.field.MODE == MODE_OFDM) ++ rate_index = (UCHAR)(ht_setting.field.MCS) + 4; ++ else if (ht_setting.field.MODE == MODE_CCK) ++ rate_index = (UCHAR)(ht_setting.field.MCS); ++ ++ if (rate_index < 0) ++ rate_index = 0; ++ ++ if (rate_index > rate_count) ++ rate_index = rate_count; ++ ++ wrqu->bitrate.value = ralinkrate[rate_index] * 500000; ++ wrqu->bitrate.disabled = 0; ++ ++ return 0; ++} ++ ++static const iw_handler rt_handler[] = ++{ ++ (iw_handler) NULL, /* SIOCSIWCOMMIT */ ++ (iw_handler) rt_ioctl_giwname, /* SIOCGIWNAME */ ++ (iw_handler) NULL, /* SIOCSIWNWID */ ++ (iw_handler) NULL, /* SIOCGIWNWID */ ++ (iw_handler) rt_ioctl_siwfreq, /* SIOCSIWFREQ */ ++ (iw_handler) rt_ioctl_giwfreq, /* SIOCGIWFREQ */ ++ (iw_handler) rt_ioctl_siwmode, /* SIOCSIWMODE */ ++ (iw_handler) rt_ioctl_giwmode, /* SIOCGIWMODE */ ++ (iw_handler) NULL, /* SIOCSIWSENS */ ++ (iw_handler) NULL, /* SIOCGIWSENS */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ ++ (iw_handler) rt_ioctl_giwrange, /* SIOCGIWRANGE */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ ++ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ ++ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ ++ (iw_handler) rt28xx_get_wireless_stats /* kernel code */, /* SIOCGIWSTATS */ ++ (iw_handler) NULL, /* SIOCSIWSPY */ ++ (iw_handler) NULL, /* SIOCGIWSPY */ ++ (iw_handler) NULL, /* SIOCSIWTHRSPY */ ++ (iw_handler) NULL, /* SIOCGIWTHRSPY */ ++ (iw_handler) rt_ioctl_siwap, /* SIOCSIWAP */ ++ (iw_handler) rt_ioctl_giwap, /* SIOCGIWAP */ ++#ifdef SIOCSIWMLME ++ (iw_handler) rt_ioctl_siwmlme, /* SIOCSIWMLME */ ++#else ++ (iw_handler) NULL, /* SIOCSIWMLME */ ++#endif // SIOCSIWMLME // ++ (iw_handler) rt_ioctl_iwaplist, /* SIOCGIWAPLIST */ ++#ifdef SIOCGIWSCAN ++ (iw_handler) rt_ioctl_siwscan, /* SIOCSIWSCAN */ ++ (iw_handler) rt_ioctl_giwscan, /* SIOCGIWSCAN */ ++#else ++ (iw_handler) NULL, /* SIOCSIWSCAN */ ++ (iw_handler) NULL, /* SIOCGIWSCAN */ ++#endif /* SIOCGIWSCAN */ ++ (iw_handler) rt_ioctl_siwessid, /* SIOCSIWESSID */ ++ (iw_handler) rt_ioctl_giwessid, /* SIOCGIWESSID */ ++ (iw_handler) rt_ioctl_siwnickn, /* SIOCSIWNICKN */ ++ (iw_handler) rt_ioctl_giwnickn, /* SIOCGIWNICKN */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) rt_ioctl_siwrate, /* SIOCSIWRATE */ ++ (iw_handler) rt_ioctl_giwrate, /* SIOCGIWRATE */ ++ (iw_handler) rt_ioctl_siwrts, /* SIOCSIWRTS */ ++ (iw_handler) rt_ioctl_giwrts, /* SIOCGIWRTS */ ++ (iw_handler) rt_ioctl_siwfrag, /* SIOCSIWFRAG */ ++ (iw_handler) rt_ioctl_giwfrag, /* SIOCGIWFRAG */ ++ (iw_handler) NULL, /* SIOCSIWTXPOW */ ++ (iw_handler) NULL, /* SIOCGIWTXPOW */ ++ (iw_handler) NULL, /* SIOCSIWRETRY */ ++ (iw_handler) NULL, /* SIOCGIWRETRY */ ++ (iw_handler) rt_ioctl_siwencode, /* SIOCSIWENCODE */ ++ (iw_handler) rt_ioctl_giwencode, /* SIOCGIWENCODE */ ++ (iw_handler) NULL, /* SIOCSIWPOWER */ ++ (iw_handler) NULL, /* SIOCGIWPOWER */ ++ (iw_handler) NULL, /* -- hole -- */ ++ (iw_handler) NULL, /* -- hole -- */ ++#if WIRELESS_EXT > 17 ++ (iw_handler) rt_ioctl_siwgenie, /* SIOCSIWGENIE */ ++ (iw_handler) rt_ioctl_giwgenie, /* SIOCGIWGENIE */ ++ (iw_handler) rt_ioctl_siwauth, /* SIOCSIWAUTH */ ++ (iw_handler) rt_ioctl_giwauth, /* SIOCGIWAUTH */ ++ (iw_handler) rt_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ ++ (iw_handler) rt_ioctl_giwencodeext, /* SIOCGIWENCODEEXT */ ++ (iw_handler) rt_ioctl_siwpmksa, /* SIOCSIWPMKSA */ ++#endif ++}; ++ ++static const iw_handler rt_priv_handlers[] = { ++ (iw_handler) NULL, /* + 0x00 */ ++ (iw_handler) NULL, /* + 0x01 */ ++#ifndef CONFIG_AP_SUPPORT ++ (iw_handler) rt_ioctl_setparam, /* + 0x02 */ ++#else ++ (iw_handler) NULL, /* + 0x02 */ ++#endif // CONFIG_AP_SUPPORT // ++#ifdef DBG ++ (iw_handler) rt_private_ioctl_bbp, /* + 0x03 */ ++#else ++ (iw_handler) NULL, /* + 0x03 */ ++#endif ++ (iw_handler) NULL, /* + 0x04 */ ++ (iw_handler) NULL, /* + 0x05 */ ++ (iw_handler) NULL, /* + 0x06 */ ++ (iw_handler) NULL, /* + 0x07 */ ++ (iw_handler) NULL, /* + 0x08 */ ++ (iw_handler) rt_private_get_statistics, /* + 0x09 */ ++ (iw_handler) NULL, /* + 0x0A */ ++ (iw_handler) NULL, /* + 0x0B */ ++ (iw_handler) NULL, /* + 0x0C */ ++ (iw_handler) NULL, /* + 0x0D */ ++ (iw_handler) NULL, /* + 0x0E */ ++ (iw_handler) NULL, /* + 0x0F */ ++ (iw_handler) NULL, /* + 0x10 */ ++ (iw_handler) rt_private_show, /* + 0x11 */ ++ (iw_handler) NULL, /* + 0x12 */ ++ (iw_handler) NULL, /* + 0x13 */ ++ (iw_handler) NULL, /* + 0x15 */ ++ (iw_handler) NULL, /* + 0x17 */ ++ (iw_handler) NULL, /* + 0x18 */ ++}; ++ ++const struct iw_handler_def rt28xx_iw_handler_def = ++{ ++#define N(a) (sizeof (a) / sizeof (a[0])) ++ .standard = (iw_handler *) rt_handler, ++ .num_standard = sizeof(rt_handler) / sizeof(iw_handler), ++ .private = (iw_handler *) rt_priv_handlers, ++ .num_private = N(rt_priv_handlers), ++ .private_args = (struct iw_priv_args *) privtab, ++ .num_private_args = N(privtab), ++#if IW_HANDLER_VERSION >= 7 ++ .get_wireless_stats = rt28xx_get_wireless_stats, ++#endif ++}; ++ ++INT RTMPSetInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_MAC_ADDRESS Bssid; ++ RT_802_11_PHY_MODE PhyMode; ++ RT_802_11_STA_CONFIG StaConfig; ++ NDIS_802_11_RATES aryRates; ++ RT_802_11_PREAMBLE Preamble; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode = Ndis802_11AuthModeMax; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ PNDIS_802_11_KEY pKey = NULL; ++ PNDIS_802_11_WEP pWepKey =NULL; ++ PNDIS_802_11_REMOVE_KEY pRemoveKey = NULL; ++ NDIS_802_11_CONFIGURATION Config, *pConfig = NULL; ++ NDIS_802_11_NETWORK_TYPE NetType; ++ ULONG Now; ++ UINT KeyIdx = 0; ++ INT Status = NDIS_STATUS_SUCCESS, MaxPhyMode = PHY_11G; ++ ULONG PowerTemp; ++ BOOLEAN RadioState; ++ BOOLEAN StateMachineTouched = FALSE; ++#ifdef DOT11_N_SUPPORT ++ OID_SET_HT_PHYMODE HT_PhyMode; //11n ,kathy ++#endif // DOT11_N_SUPPORT // ++#ifdef WPA_SUPPLICANT_SUPPORT ++ PNDIS_802_11_PMKID pPmkId = NULL; ++ BOOLEAN IEEE8021xState = FALSE; ++ BOOLEAN IEEE8021x_required_keys = FALSE; ++ UCHAR wpa_supplicant_enable = 0; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef SNMP_SUPPORT ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR ctmp; ++#endif // SNMP_SUPPORT // ++ ++ ++#ifdef DOT11_N_SUPPORT ++ MaxPhyMode = PHY_11N_5G; ++#endif // DOT11_N_SUPPORT // ++ ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-->RTMPSetInformation(), 0x%08x\n", cmd&0x7FFF)); ++ switch(cmd & 0x7FFF) { ++ case RT_OID_802_11_COUNTRY_REGION: ++ if (wrq->u.data.length < sizeof(UCHAR)) ++ Status = -EINVAL; ++ // Only avaliable when EEPROM not programming ++ else if (!(pAdapter->CommonCfg.CountryRegion & 0x80) && !(pAdapter->CommonCfg.CountryRegionForABand & 0x80)) ++ { ++ ULONG Country; ++ UCHAR TmpPhy; ++ ++ Status = copy_from_user(&Country, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.CountryRegion = (UCHAR)(Country & 0x000000FF); ++ pAdapter->CommonCfg.CountryRegionForABand = (UCHAR)((Country >> 8) & 0x000000FF); ++ TmpPhy = pAdapter->CommonCfg.PhyMode; ++ pAdapter->CommonCfg.PhyMode = 0xff; ++ // Build all corresponding channel information ++ RTMPSetPhyMode(pAdapter, TmpPhy); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_COUNTRY_REGION (A:%d B/G:%d)\n", pAdapter->CommonCfg.CountryRegionForABand, ++ pAdapter->CommonCfg.CountryRegion)); ++ } ++ break; ++ case OID_802_11_BSSID_LIST_SCAN: ++ #ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ Now = jiffies; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID_LIST_SCAN, TxCnt = %d \n", pAdapter->RalinkCounters.LastOneSecTotalTxCount)); ++ ++ if (MONITOR_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is in Monitor Mode now !!!\n")); ++ break; ++ } ++ ++ //Benson add 20080527, when radio off, sta don't need to scan ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_RADIO_OFF)) ++ break; ++ ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Driver is scanning now !!!\n")); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ } ++ ++ if (pAdapter->RalinkCounters.LastOneSecTotalTxCount > 100) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ if ((OPSTATUS_TEST_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED)) && ++ ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) && ++ (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! Link UP, Port Not Secured! ignore this set::OID_802_11_BSSID_LIST_SCAN\n")); ++ Status = NDIS_STATUS_SUCCESS; ++ pAdapter->StaCfg.ScanCnt = 99; // Prevent auto scan triggered by this OID ++ break; ++ } ++ ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ pAdapter->StaCfg.LastScanTime = Now; ++ ++ pAdapter->StaCfg.bScanReqIsFromWebUI = TRUE; ++ RTMP_SET_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID_LIST_SCAN, ++ 0, ++ NULL); ++ ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ break; ++ case OID_802_11_SSID: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_SSID)) ++ Status = -EINVAL; ++ else ++ { ++ PCHAR pSsidString = NULL; ++ Status = copy_from_user(&Ssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SSID (Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ if (Ssid.SsidLength > MAX_LEN_OF_SSID) ++ Status = -EINVAL; ++ else ++ { ++ if (Ssid.SsidLength == 0) ++ { ++ Set_SSID_Proc(pAdapter, ""); ++ } ++ else ++ { ++ pSsidString = (CHAR *) kmalloc(MAX_LEN_OF_SSID+1, MEM_ALLOC_FLAG); ++ if (pSsidString) ++ { ++ NdisZeroMemory(pSsidString, MAX_LEN_OF_SSID+1); ++ NdisMoveMemory(pSsidString, Ssid.Ssid, Ssid.SsidLength); ++ Set_SSID_Proc(pAdapter, pSsidString); ++ kfree(pSsidString); ++ } ++ else ++ Status = -ENOMEM; ++ } ++ } ++ } ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ if (wrq->u.data.length != sizeof(NDIS_802_11_MAC_ADDRESS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Bssid, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // tell CNTL state machine to call NdisMSetInformationComplete() after completing ++ // this request, because this request is initiated by NDIS. ++ pAdapter->MlmeAux.CurrReqIsFromNdis = FALSE; ++ ++ // Prevent to connect AP again in STAMlmePeriodicExec ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ ++ // Reset allowed scan retries ++ pAdapter->StaCfg.ScanCnt = 0; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_BSSID, ++ sizeof(NDIS_802_11_MAC_ADDRESS), ++ (VOID *)&Bssid); ++ Status = NDIS_STATUS_SUCCESS; ++ StateMachineTouched = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ } ++ break; ++ case RT_OID_802_11_RADIO: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RadioState, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RADIO (=%d)\n", RadioState)); ++ if (pAdapter->StaCfg.bSwRadio != RadioState) ++ { ++ pAdapter->StaCfg.bSwRadio = RadioState; ++ if (pAdapter->StaCfg.bRadio != (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio)) ++ { ++ pAdapter->StaCfg.bRadio = (pAdapter->StaCfg.bHwRadio && pAdapter->StaCfg.bSwRadio); ++ if (pAdapter->StaCfg.bRadio == TRUE) ++ { ++ MlmeRadioOn(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = EXTRA_INFO_CLEAR; ++ } ++ else ++ { ++ MlmeRadioOff(pAdapter); ++ // Update extra information ++ pAdapter->ExtraInfo = SW_RADIO_OFF; ++ } ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PHY_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PhyMode <= MaxPhyMode) ++ { ++ RTMPSetPhyMode(pAdapter, PhyMode); ++#ifdef DOT11_N_SUPPORT ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PHY_MODE (=%d)\n", PhyMode)); ++ } ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ if (wrq->u.data.length != sizeof(RT_802_11_STA_CONFIG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&StaConfig, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bEnableTxBurst = StaConfig.EnableTxBurst; ++ pAdapter->CommonCfg.UseBGProtection = StaConfig.UseBGProtection; ++ pAdapter->CommonCfg.bUseShortSlotTime = 1; // 2003-10-30 always SHORT SLOT capable ++ if ((pAdapter->CommonCfg.PhyMode != StaConfig.AdhocMode) && ++ (StaConfig.AdhocMode <= MaxPhyMode)) ++ { ++ // allow dynamic change of "USE OFDM rate or not" in ADHOC mode ++ // if setting changed, need to reset current TX rate as well as BEACON frame format ++ pAdapter->CommonCfg.PhyMode = StaConfig.AdhocMode; ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ { ++ RTMPSetPhyMode(pAdapter, PhyMode); ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ MakeIbssBeacon(pAdapter); // re-build BEACON frame ++ AsicEnableIbssSync(pAdapter); // copy to on-chip memory ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_STA_CONFIG (Burst=%d, Protection=%ld,ShortSlot=%d\n", ++ pAdapter->CommonCfg.bEnableTxBurst, ++ pAdapter->CommonCfg.UseBGProtection, ++ pAdapter->CommonCfg.bUseShortSlotTime)); ++ } ++ break; ++ case OID_802_11_DESIRED_RATES: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RATES)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&aryRates, wrq->u.data.pointer, wrq->u.data.length); ++ NdisZeroMemory(pAdapter->CommonCfg.DesireRate, MAX_LEN_OF_SUPPORTED_RATES); ++ NdisMoveMemory(pAdapter->CommonCfg.DesireRate, &aryRates, sizeof(NDIS_802_11_RATES)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DESIRED_RATES (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)\n", ++ pAdapter->CommonCfg.DesireRate[0],pAdapter->CommonCfg.DesireRate[1], ++ pAdapter->CommonCfg.DesireRate[2],pAdapter->CommonCfg.DesireRate[3], ++ pAdapter->CommonCfg.DesireRate[4],pAdapter->CommonCfg.DesireRate[5], ++ pAdapter->CommonCfg.DesireRate[6],pAdapter->CommonCfg.DesireRate[7] )); ++ // Changing DesiredRate may affect the MAX TX rate we used to TX frames out ++ MlmeUpdateTxRates(pAdapter, FALSE, 0); ++ } ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ if (wrq->u.data.length != sizeof(RT_802_11_PREAMBLE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Preamble, wrq->u.data.pointer, wrq->u.data.length); ++ if (Preamble == Rt802_11PreambleShort) ++ { ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleShort); ++ } ++ else if ((Preamble == Rt802_11PreambleLong) || (Preamble == Rt802_11PreambleAuto)) ++ { ++ // if user wants AUTO, initialize to LONG here, then change according to AP's ++ // capability upon association. ++ pAdapter->CommonCfg.TxPreamble = Preamble; ++ MlmeSetTxPreamble(pAdapter, Rt802_11PreambleLong); ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_PREAMBLE (=%d)\n", Preamble)); ++ } ++ break; ++ case OID_802_11_WEP_STATUS: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_WEP_STATUS)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&WepStatus, wrq->u.data.pointer, wrq->u.data.length); ++ // Since TKIP, AES, WEP are all supported. It should not have any invalid setting ++ if (WepStatus <= Ndis802_11Encryption3KeyAbsent) ++ { ++ if (pAdapter->StaCfg.WepStatus != WepStatus) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.WepStatus = WepStatus; ++ pAdapter->StaCfg.OrigWepStatus = WepStatus; ++ pAdapter->StaCfg.PairCipher = WepStatus; ++ pAdapter->StaCfg.GroupCipher = WepStatus; ++ } ++ else ++ { ++ Status = -EINVAL; ++ break; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEP_STATUS (=%d)\n",WepStatus)); ++ } ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_AUTHENTICATION_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&AuthMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (AuthMode > Ndis802_11AuthModeMax) ++ { ++ Status = -EINVAL; ++ break; ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode != AuthMode) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ pAdapter->StaCfg.AuthMode = AuthMode; ++ } ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_AUTHENTICATION_MODE (=%d) \n",pAdapter->StaCfg.AuthMode)); ++ } ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&BssType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (BssType == Ndis802_11IBSS) ++ Set_NetworkType_Proc(pAdapter, "Adhoc"); ++ else if (BssType == Ndis802_11Infrastructure) ++ Set_NetworkType_Proc(pAdapter, "Infra"); ++ else if (BssType == Ndis802_11Monitor) ++ Set_NetworkType_Proc(pAdapter, "Monitor"); ++ else ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_INFRASTRUCTURE_MODE (unknown)\n")); ++ } ++ } ++ break; ++ case OID_802_11_REMOVE_WEP: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_WEP\n")); ++ if (wrq->u.data.length != sizeof(NDIS_802_11_KEY_INDEX)) ++ { ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = *(NDIS_802_11_KEY_INDEX *) wrq->u.data.pointer; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx >= 4){ ++ Status = -EINVAL; ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ } ++ } ++ } ++ break; ++ case RT_OID_802_11_RESET_COUNTERS: ++ NdisZeroMemory(&pAdapter->WlanCounters, sizeof(COUNTER_802_11)); ++ NdisZeroMemory(&pAdapter->Counters8023, sizeof(COUNTER_802_3)); ++ NdisZeroMemory(&pAdapter->RalinkCounters, sizeof(COUNTER_RALINK)); ++ pAdapter->Counters8023.RxNoBuffer = 0; ++ pAdapter->Counters8023.GoodReceives = 0; ++ pAdapter->Counters8023.RxNoBuffer = 0; ++#ifdef RT2870 ++ pAdapter->BulkOutComplete = 0; ++ pAdapter->BulkOutCompleteOther= 0; ++ pAdapter->BulkOutCompleteCancel = 0; ++ pAdapter->BulkOutReq = 0; ++ pAdapter->BulkInReq= 0; ++ pAdapter->BulkInComplete = 0; ++ pAdapter->BulkInCompleteFail = 0; ++#endif // RT2870 // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_RESET_COUNTERS \n")); ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_RTS_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&RtsThresh, wrq->u.data.pointer, wrq->u.data.length); ++ if (RtsThresh > MAX_RTS_THRESHOLD) ++ Status = -EINVAL; ++ else ++ pAdapter->CommonCfg.RtsThreshold = (USHORT)RtsThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_RTS_THRESHOLD (=%ld)\n",RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_FRAGMENTATION_THRESHOLD)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&FragThresh, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = FALSE; ++ if (FragThresh > MAX_FRAG_THRESHOLD || FragThresh < MIN_FRAG_THRESHOLD) ++ { ++ if (FragThresh == 0) ++ { ++ pAdapter->CommonCfg.FragmentThreshold = MAX_FRAG_THRESHOLD; ++ pAdapter->CommonCfg.bUseZeroToDisableFragment = TRUE; ++ } ++ else ++ Status = -EINVAL; ++ } ++ else ++ pAdapter->CommonCfg.FragmentThreshold = (USHORT)FragThresh; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_FRAGMENTATION_THRESHOLD (=%ld) \n",FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_POWER_MODE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerMode, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerMode == Ndis802_11PowerModeCAM) ++ Set_PSMode_Proc(pAdapter, "CAM"); ++ else if (PowerMode == Ndis802_11PowerModeMAX_PSP) ++ Set_PSMode_Proc(pAdapter, "Max_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeFast_PSP) ++ Set_PSMode_Proc(pAdapter, "Fast_PSP"); ++ else if (PowerMode == Ndis802_11PowerModeLegacy_PSP) ++ Set_PSMode_Proc(pAdapter, "Legacy_PSP"); ++ else ++ Status = -EINVAL; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_POWER_MODE (=%d)\n",PowerMode)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ if (wrq->u.data.length < sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&PowerTemp, wrq->u.data.pointer, wrq->u.data.length); ++ if (PowerTemp > 100) ++ PowerTemp = 0xffffffff; // AUTO ++ pAdapter->CommonCfg.TxPowerDefault = PowerTemp; //keep current setting. ++ pAdapter->CommonCfg.TxPowerPercentage = pAdapter->CommonCfg.TxPowerDefault; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ } ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_NETWORK_TYPE)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&NetType, wrq->u.data.pointer, wrq->u.data.length); ++ ++ if (NetType == Ndis802_11DS) ++ RTMPSetPhyMode(pAdapter, PHY_11B); ++ else if (NetType == Ndis802_11OFDM24) ++ RTMPSetPhyMode(pAdapter, PHY_11BG_MIXED); ++ else if (NetType == Ndis802_11OFDM5) ++ RTMPSetPhyMode(pAdapter, PHY_11A); ++ else ++ Status = -EINVAL; ++#ifdef DOT11_N_SUPPORT ++ if (Status == NDIS_STATUS_SUCCESS) ++ SetCommonHT(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_NETWORK_TYPE_IN_USE (=%d)\n",NetType)); ++ } ++ break; ++ // For WPA PSK PMK key ++ case RT_OID_802_11_ADD_WPA: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!!\n")); ++ } ++ else ++ { ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ) ++ { ++ Status = -EOPNOTSUPP; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA, Failed!! [AuthMode != WPAPSK/WPA2PSK/WPANONE]\n")); ++ } ++ else if ((pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) || ++ (pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ) // Only for WPA PSK mode ++ { ++ NdisMoveMemory(pAdapter->StaCfg.PMK, &pKey->KeyMaterial, pKey->KeyLength); ++ // Use RaConfig as PSK agent. ++ // Start STA supplicant state machine ++ if (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ pAdapter->StaCfg.WpaState = SS_START; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ else ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_WPA (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_REMOVE_KEY: ++ pRemoveKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pRemoveKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ ++ Status = copy_from_user(pRemoveKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pRemoveKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!\n")); ++ } ++ else ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ { ++ RTMPWPARemoveKeyProc(pAdapter, pRemoveKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Remove WPA Key!!\n")); ++ } ++ else ++ { ++ KeyIdx = pRemoveKey->KeyIndex; ++ ++ if (KeyIdx & 0x80000000) ++ { ++ // Should never set default bit when remove key ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(Should never set default bit when remove key)\n")); ++ } ++ else ++ { ++ KeyIdx = KeyIdx & 0x0fffffff; ++ if (KeyIdx > 3) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY, Failed!!(KeyId[%d] out of range)\n", KeyIdx)); ++ } ++ else ++ { ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = 0; ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CIPHER_NONE; ++ AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)KeyIdx); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_REMOVE_KEY (id=0x%x, Len=%d-byte)\n", pRemoveKey->KeyIndex, pRemoveKey->Length)); ++ } ++ } ++ } ++ } ++ kfree(pRemoveKey); ++ break; ++ // New for WPA ++ case OID_802_11_ADD_KEY: ++ pKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ if(pKey == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY, Failed!!\n")); ++ } ++ else ++ { ++ RTMPAddKey(pAdapter, pKey); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_KEY (id=0x%x, Len=%d-byte)\n", pKey->KeyIndex, pKey->KeyLength)); ++ } ++ kfree(pKey); ++ break; ++ case OID_802_11_CONFIGURATION: ++ if (wrq->u.data.length != sizeof(NDIS_802_11_CONFIGURATION)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&Config, wrq->u.data.pointer, wrq->u.data.length); ++ pConfig = &Config; ++ ++ if ((pConfig->BeaconPeriod >= 20) && (pConfig->BeaconPeriod <=400)) ++ pAdapter->CommonCfg.BeaconPeriod = (USHORT) pConfig->BeaconPeriod; ++ ++ pAdapter->StaActive.AtimWin = (USHORT) pConfig->ATIMWindow; ++ MAP_KHZ_TO_CHANNEL_ID(pConfig->DSConfig, pAdapter->CommonCfg.Channel); ++ // ++ // Save the channel on MlmeAux for CntlOidRTBssidProc used. ++ // ++ pAdapter->MlmeAux.Channel = pAdapter->CommonCfg.Channel; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CONFIGURATION (BeacnPeriod=%ld,AtimW=%ld,Ch=%d)\n", ++ pConfig->BeaconPeriod, pConfig->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ } ++ break; ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_HT_PHYMODE: ++ if (wrq->u.data.length != sizeof(OID_SET_HT_PHYMODE)) ++ Status = -EINVAL; ++ else ++ { ++ POID_SET_HT_PHYMODE pHTPhyMode = &HT_PhyMode; ++ ++ Status = copy_from_user(&HT_PhyMode, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::pHTPhyMode (PhyMode = %d,TransmitNo = %d, HtMode = %d, ExtOffset = %d , MCS = %d, BW = %d, STBC = %d, SHORTGI = %d) \n", ++ pHTPhyMode->PhyMode, pHTPhyMode->TransmitNo,pHTPhyMode->HtMode,pHTPhyMode->ExtOffset, ++ pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->SHORTGI)); ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ RTMPSetHT(pAdapter, pHTPhyMode); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_HT_PHYMODE(MCS=%d,BW=%d,SGI=%d,STBC=%d)\n", ++ pAdapter->StaCfg.HTPhyMode.field.MCS, pAdapter->StaCfg.HTPhyMode.field.BW, pAdapter->StaCfg.HTPhyMode.field.ShortGI, ++ pAdapter->StaCfg.HTPhyMode.field.STBC)); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case RT_OID_802_11_SET_APSD_SETTING: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ ULONG apsd ; ++ Status = copy_from_user(&apsd, wrq->u.data.pointer, wrq->u.data.length); ++ ++ /*------------------------------------------------------------------- ++ |B31~B7 | B6~B5 | B4 | B3 | B2 | B1 | B0 | ++ --------------------------------------------------------------------- ++ | Rsvd | Max SP Len | AC_VO | AC_VI | AC_BK | AC_BE | APSD Capable | ++ ---------------------------------------------------------------------*/ ++ pAdapter->CommonCfg.bAPSDCapable = (apsd & 0x00000001) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BE = ((apsd & 0x00000002) >> 1) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_BK = ((apsd & 0x00000004) >> 2) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VI = ((apsd & 0x00000008) >> 3) ? TRUE : FALSE; ++ pAdapter->CommonCfg.bAPSDAC_VO = ((apsd & 0x00000010) >> 4) ? TRUE : FALSE; ++ pAdapter->CommonCfg.MaxSPLength = (UCHAR)((apsd & 0x00000060) >> 5); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_SETTING (apsd=0x%lx, APSDCap=%d, [BE,BK,VI,VO]=[%d/%d/%d/%d], MaxSPLen=%d)\n", apsd, pAdapter->CommonCfg.bAPSDCapable, ++ pAdapter->CommonCfg.bAPSDAC_BE, pAdapter->CommonCfg.bAPSDAC_BK, pAdapter->CommonCfg.bAPSDAC_VI, pAdapter->CommonCfg.bAPSDAC_VO, pAdapter->CommonCfg.MaxSPLength)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_APSD_PSM: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ // Driver needs to notify AP when PSM changes ++ Status = copy_from_user(&pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.pointer, wrq->u.data.length); ++ if (pAdapter->CommonCfg.bAPSDForcePowerSave != pAdapter->StaCfg.Psm) ++ { ++ MlmeSetPsmBit(pAdapter, pAdapter->CommonCfg.bAPSDForcePowerSave); ++ RTMPSendNullFrame(pAdapter, pAdapter->CommonCfg.TxRate, TRUE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_APSD_PSM (bAPSDForcePowerSave:%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ } ++ break; ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_SET_DLS: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ BOOLEAN oldvalue = pAdapter->CommonCfg.bDLSCapable; ++ Status = copy_from_user(&pAdapter->CommonCfg.bDLSCapable, wrq->u.data.pointer, wrq->u.data.length); ++ if (oldvalue && !pAdapter->CommonCfg.bDLSCapable) ++ { ++ int i; ++ // tear down local dls table entry ++ for (i=0; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ ++ // tear down peer dls table entry ++ for (i=MAX_NUM_OF_INIT_DLS_ENTRY; iStaCfg.DLSEntry[i].Valid && (pAdapter->StaCfg.DLSEntry[i].Status == DLS_FINISH)) ++ { ++ pAdapter->StaCfg.DLSEntry[i].Status = DLS_NONE; ++ pAdapter->StaCfg.DLSEntry[i].Valid = FALSE; ++ RTMPSendDLSTearDownFrame(pAdapter, pAdapter->StaCfg.DLSEntry[i].MacAddr); ++ } ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS (=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ } ++ break; ++ ++ case RT_OID_802_11_SET_DLS_PARAM: ++ if (wrq->u.data.length != sizeof(RT_802_11_DLS_UI)) ++ Status = -EINVAL; ++ else ++ { ++ RT_802_11_DLS Dls; ++ ++ NdisZeroMemory(&Dls, sizeof(RT_802_11_DLS)); ++ RTMPMoveMemory(&Dls, wrq->u.data.pointer, sizeof(RT_802_11_DLS_UI)); ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ RT_OID_802_11_SET_DLS_PARAM, ++ sizeof(RT_802_11_DLS), ++ &Dls); ++ DBGPRINT(RT_DEBUG_TRACE,("Set::RT_OID_802_11_SET_DLS_PARAM \n")); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ case RT_OID_802_11_SET_WMM: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&pAdapter->CommonCfg.bWmmCapable, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_SET_WMM (=%d) \n", pAdapter->CommonCfg.bWmmCapable)); ++ } ++ break; ++ ++ case OID_802_11_DISASSOCIATE: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ break; ++ } ++#endif // RALINK_ATE // ++ // ++ // Set NdisRadioStateOff to TRUE, instead of called MlmeRadioOff. ++ // Later on, NDIS_802_11_BSSID_LIST_EX->NumberOfItems should be 0 ++ // when query OID_802_11_BSSID_LIST. ++ // ++ // TRUE: NumberOfItems will set to 0. ++ // FALSE: NumberOfItems no change. ++ // ++ pAdapter->CommonCfg.NdisRadioStateOff = TRUE; ++ // Set to immediately send the media disconnect event ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DISASSOCIATE \n")); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_DISASSOCIATE, ++ 0, ++ NULL); ++ ++ StateMachineTouched = TRUE; ++ } ++ break; ++ ++#ifdef DOT11_N_SUPPORT ++ case RT_OID_802_11_SET_IMME_BA_CAP: ++ if (wrq->u.data.length != sizeof(OID_BACAP_STRUC)) ++ Status = -EINVAL; ++ else ++ { ++ OID_BACAP_STRUC Orde ; ++ Status = copy_from_user(&Orde, wrq->u.data.pointer, wrq->u.data.length); ++ if (Orde.Policy > BA_NOTUSE) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ } ++ else if (Orde.Policy == BA_NOTUSE) ++ { ++ pAdapter->CommonCfg.BACapability.field.Policy = BA_NOTUSE; ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs= Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ } ++ else ++ { ++ pAdapter->CommonCfg.BACapability.field.AutoBA = Orde.AutoBA; ++ pAdapter->CommonCfg.BACapability.field.Policy = IMMED_BA; // we only support immediate BA. ++ pAdapter->CommonCfg.BACapability.field.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.MpduDensity = Orde.MpduDensity; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable = Orde.AmsduEnable; ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize= Orde.AmsduSize; ++ pAdapter->CommonCfg.DesiredHtPhy.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.BACapability.field.MMPSmode = Orde.MMPSmode; ++ ++ // UPdata to HT IE ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.MimoPs = Orde.MMPSmode; ++ pAdapter->CommonCfg.HtCapability.HtCapInfo.AMsduSize = Orde.AmsduSize; ++ pAdapter->CommonCfg.HtCapability.HtCapParm.MpduDensity = Orde.MpduDensity; ++ ++ if (pAdapter->CommonCfg.BACapability.field.RxBAWinLimit > MAX_RX_REORDERBUF) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = MAX_RX_REORDERBUF; ++ ++ } ++ ++ pAdapter->CommonCfg.REGBACapability.word = pAdapter->CommonCfg.BACapability.word; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(Orde.AutoBA = %d) (Policy=%d)(ReBAWinLimit=%d)(TxBAWinLimit=%d)(AutoMode=%d)\n",Orde.AutoBA, pAdapter->CommonCfg.BACapability.field.Policy, ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit,pAdapter->CommonCfg.BACapability.field.TxBAWinLimit, pAdapter->CommonCfg.BACapability.field.AutoBA)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::(MimoPs = %d)(AmsduEnable = %d) (AmsduSize=%d)(MpduDensity=%d)\n",pAdapter->CommonCfg.DesiredHtPhy.MimoPs, pAdapter->CommonCfg.DesiredHtPhy.AmsduEnable, ++ pAdapter->CommonCfg.DesiredHtPhy.AmsduSize, pAdapter->CommonCfg.DesiredHtPhy.MpduDensity)); ++ } ++ ++ break; ++ case RT_OID_802_11_ADD_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, (" Set :: RT_OID_802_11_ADD_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ UCHAR index; ++ OID_ADD_BA_ENTRY BA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ Status = copy_from_user(&BA, wrq->u.data.pointer, wrq->u.data.length); ++ if (BA.TID > 15) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ else ++ { ++ //BATableInsertEntry ++ //As ad-hoc mode, BA pair is not limited to only BSSID. so add via OID. ++ index = BA.TID; ++ // in ad hoc mode, when adding BA pair, we should insert this entry into MACEntry too ++ pEntry = MacTableLookup(pAdapter, BA.MACAddr); ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("RT_OID_802_11_ADD_IMME_BA. break on no connection.----:%x:%x\n", BA.MACAddr[4], BA.MACAddr[5])); ++ break; ++ } ++ if (BA.IsRecipient == FALSE) ++ { ++ if (pEntry->bIAmBadAtheros == TRUE) ++ pAdapter->CommonCfg.BACapability.field.RxBAWinLimit = 0x10; ++ ++ BAOriSessionSetUp(pAdapter, pEntry, index, 0, 100, TRUE); ++ } ++ else ++ { ++ //BATableInsertEntry(pAdapter, pEntry->Aid, BA.MACAddr, 0, 0xffff, BA.TID, BA.nMSDU, BA.IsRecipient); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_802_11_ADD_IMME_BA. Rec = %d. Mac = %x:%x:%x:%x:%x:%x . \n", ++ BA.IsRecipient, BA.MACAddr[0], BA.MACAddr[1], BA.MACAddr[2], BA.MACAddr[2] ++ , BA.MACAddr[4], BA.MACAddr[5])); ++ } ++ } ++ break; ++ ++ case RT_OID_802_11_TEAR_IMME_BA: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA \n")); ++ if (wrq->u.data.length != sizeof(OID_ADD_BA_ENTRY)) ++ Status = -EINVAL; ++ else ++ { ++ POID_ADD_BA_ENTRY pBA; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ pBA = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if (pBA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA kmalloc() can't allocate enough memory\n")); ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = copy_from_user(pBA, wrq->u.data.pointer, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: RT_OID_802_11_TEAR_IMME_BA(TID=%d, bAllTid=%d)\n", pBA->TID, pBA->bAllTid)); ++ ++ if (!pBA->bAllTid && (pBA->TID > NUM_OF_TID)) ++ { ++ Status = NDIS_STATUS_INVALID_DATA; ++ break; ++ } ++ ++ if (pBA->IsRecipient == FALSE) ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->IsRecipient == FALSE\n")); ++ if (pEntry) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, (" pBA->pEntry\n")); ++ BAOriSessionTearDown(pAdapter, pEntry->Aid, pBA->TID, FALSE, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAdapter, pBA->MACAddr); ++ if (pEntry) ++ { ++ BARecSessionTearDown( pAdapter, (UCHAR)pEntry->Aid, pBA->TID, TRUE); ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("Set :: Not found pEntry \n")); ++ } ++ kfree(pBA); ++ } ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ ++ // For WPA_SUPPLICANT to set static wep key ++ case OID_802_11_ADD_WEP: ++ pWepKey = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pWepKey == NULL) ++ { ++ Status = -ENOMEM; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed!!\n")); ++ break; ++ } ++ Status = copy_from_user(pWepKey, wrq->u.data.pointer, wrq->u.data.length); ++ if (Status) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (length mismatch)!!\n")); ++ } ++ else ++ { ++ KeyIdx = pWepKey->KeyIndex & 0x0fffffff; ++ // KeyIdx must be 0 ~ 3 ++ if (KeyIdx > 4) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, Failed (KeyIdx must be smaller than 4)!!\n")); ++ } ++ else ++ { ++ UCHAR CipherAlg = 0; ++ PUCHAR Key; ++ ++ // set key material and key length ++ NdisZeroMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, 16); ++ pAdapter->SharedKey[BSS0][KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->SharedKey[BSS0][KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ ++ switch(pWepKey->KeyLength) ++ { ++ case 5: ++ CipherAlg = CIPHER_WEP64; ++ break; ++ case 13: ++ CipherAlg = CIPHER_WEP128; ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP, only support CIPHER_WEP64(len:5) & CIPHER_WEP128(len:13)!!\n")); ++ Status = -EINVAL; ++ break; ++ } ++ pAdapter->SharedKey[BSS0][KeyIdx].CipherAlg = CipherAlg; ++ ++ // Default key for tx (shared key) ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++#ifdef WPA_SUPPLICANT_SUPPORT ++ // set key material and key length ++ NdisZeroMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, 16); ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].KeyLen = (UCHAR) pWepKey->KeyLength; ++ NdisMoveMemory(pAdapter->StaCfg.DesireSharedKey[KeyIdx].Key, &pWepKey->KeyMaterial, pWepKey->KeyLength); ++ pAdapter->StaCfg.DesireSharedKeyId = KeyIdx; ++ pAdapter->StaCfg.DesireSharedKey[KeyIdx].CipherAlg = CipherAlg; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ++#endif // WPA_SUPPLICANT_SUPPORT ++ { ++ Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; ++ ++ // Set key material and cipherAlg to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ if (pWepKey->KeyIndex & 0x80000000) ++ { ++ PMAC_TABLE_ENTRY pEntry = &pAdapter->MacTab.Content[BSSID_WCID]; ++ // Assign group key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ // Assign pairwise key info ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, pEntry); ++ } ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_ADD_WEP (id=0x%x, Len=%d-byte), %s\n", pWepKey->KeyIndex, pWepKey->KeyLength, (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ? "Port Secured":"Port NOT Secured")); ++ } ++ } ++ kfree(pWepKey); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case OID_SET_COUNTERMEASURES: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.bBlockAssoc = TRUE; ++ else ++ // WPA MIC error should block association attempt for 60 seconds ++ pAdapter->StaCfg.bBlockAssoc = FALSE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_SET_COUNTERMEASURES bBlockAssoc=%s\n", pAdapter->StaCfg.bBlockAssoc ? "TRUE":"FALSE")); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&wpa_supplicant_enable, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.WpaSupplicantUP = wpa_supplicant_enable; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ } ++ break; ++ case OID_802_11_DEAUTHENTICATION: ++ if (wrq->u.data.length != sizeof(MLME_DEAUTH_REQ_STRUCT)) ++ Status = -EINVAL; ++ else ++ { ++ MLME_DEAUTH_REQ_STRUCT *pInfo; ++ MLME_QUEUE_ELEM *MsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG); ++ ++ pInfo = (MLME_DEAUTH_REQ_STRUCT *) MsgElem->Msg; ++ Status = copy_from_user(pInfo, wrq->u.data.pointer, wrq->u.data.length); ++ MlmeDeauthReqAction(pAdapter, MsgElem); ++ kfree(MsgElem); ++ ++ if (INFRA_ON(pAdapter)) ++ { ++ LinkDown(pAdapter, FALSE); ++ pAdapter->Mlme.AssocMachine.CurrState = ASSOC_IDLE; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DEAUTHENTICATION (Reason=%d)\n", pInfo->Reason)); ++ } ++ break; ++ case OID_802_11_DROP_UNENCRYPTED: ++ if (wrq->u.data.length != sizeof(int)) ++ Status = -EINVAL; ++ else ++ { ++ int enabled = 0; ++ Status = copy_from_user(&enabled, wrq->u.data.pointer, wrq->u.data.length); ++ if (enabled == 1) ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ else ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ NdisAcquireSpinLock(&pAdapter->MacTabLock); ++ pAdapter->MacTab.Content[BSSID_WCID].PortSecured = pAdapter->StaCfg.PortSecured; ++ NdisReleaseSpinLock(&pAdapter->MacTabLock); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_DROP_UNENCRYPTED (=%d)\n", enabled)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021xState, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021X = IEEE8021xState; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X (=%d)\n", IEEE8021xState)); ++ } ++ break; ++ case OID_802_11_SET_IEEE8021X_REQUIRE_KEY: ++ if (wrq->u.data.length != sizeof(BOOLEAN)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&IEEE8021x_required_keys, wrq->u.data.pointer, wrq->u.data.length); ++ pAdapter->StaCfg.IEEE8021x_required_keys = IEEE8021x_required_keys; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SET_IEEE8021X_REQUIRE_KEY (%d)\n", IEEE8021x_required_keys)); ++ } ++ break; ++ case OID_802_11_PMKID: ++ pPmkId = kmalloc(wrq->u.data.length, MEM_ALLOC_FLAG); ++ ++ if(pPmkId == NULL) { ++ Status = -ENOMEM; ++ break; ++ } ++ Status = copy_from_user(pPmkId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ // check the PMKID information ++ if (pPmkId->BSSIDInfoCount == 0) ++ NdisZeroMemory(pAdapter->StaCfg.SavedPMK, sizeof(BSSID_INFO)*PMKID_NO); ++ else ++ { ++ PBSSID_INFO pBssIdInfo; ++ UINT BssIdx; ++ UINT CachedIdx; ++ ++ for (BssIdx = 0; BssIdx < pPmkId->BSSIDInfoCount; BssIdx++) ++ { ++ // point to the indexed BSSID_INFO structure ++ pBssIdInfo = (PBSSID_INFO) ((PUCHAR) pPmkId + 2 * sizeof(UINT) + BssIdx * sizeof(BSSID_INFO)); ++ // Find the entry in the saved data base. ++ for (CachedIdx = 0; CachedIdx < pAdapter->StaCfg.SavedPMKNum; CachedIdx++) ++ { ++ // compare the BSSID ++ if (NdisEqualMemory(pBssIdInfo->BSSID, pAdapter->StaCfg.SavedPMK[CachedIdx].BSSID, sizeof(NDIS_802_11_MAC_ADDRESS))) ++ break; ++ } ++ ++ // Found, replace it ++ if (CachedIdx < PMKID_NO) ++ { ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ pAdapter->StaCfg.SavedPMKNum++; ++ } ++ // Not found, replace the last one ++ else ++ { ++ // Randomly replace one ++ CachedIdx = (pBssIdInfo->BSSID[5] % PMKID_NO); ++ DBGPRINT(RT_DEBUG_OFF, ("Update OID_802_11_PMKID, idx = %d\n", CachedIdx)); ++ NdisMoveMemory(&pAdapter->StaCfg.SavedPMK[CachedIdx], pBssIdInfo, sizeof(BSSID_INFO)); ++ } ++ } ++ } ++ if(pPmkId) ++ kfree(pPmkId); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ ++ ++#ifdef SNMP_SUPPORT ++ case OID_802_11_SHORTRETRYLIMIT: ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ShortRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_SHORTRETRYLIMIT (tx_rty_cfg.field.ShortRetryLimit=%d, ShortRetryLimit=%ld)\n", tx_rty_cfg.field.ShortRtyLimit, ShortRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT \n")); ++ if (wrq->u.data.length != sizeof(ULONG)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&LongRetryLimit, wrq->u.data.pointer, wrq->u.data.length); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_LONGRETRYLIMIT (tx_rty_cfg.field.LongRetryLimit= %d,LongRetryLimit=%ld)\n", tx_rty_cfg.field.LongRtyLimit, LongRetryLimit)); ++ } ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE\n")); ++ pKey = kmalloc(wrq->u.data.length, GFP_KERNEL); ++ Status = copy_from_user(pKey, wrq->u.data.pointer, wrq->u.data.length); ++ //pKey = &WepKey; ++ ++ if ( pKey->Length != wrq->u.data.length) ++ { ++ Status = -EINVAL; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYVALUE, Failed!!\n")); ++ } ++ KeyIdx = pKey->KeyIndex & 0x0fffffff; ++ DBGPRINT(RT_DEBUG_TRACE,("pKey->KeyIndex =%d, pKey->KeyLength=%d\n", pKey->KeyIndex, pKey->KeyLength)); ++ ++ // it is a shared key ++ if (KeyIdx > 4) ++ Status = -EINVAL; ++ else ++ { ++ pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen = (UCHAR) pKey->KeyLength; ++ NdisMoveMemory(&pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, &pKey->KeyMaterial, pKey->KeyLength); ++ if (pKey->KeyIndex & 0x80000000) ++ { ++ // Default key for tx (shared key) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) KeyIdx; ++ } ++ //RestartAPIsRequired = TRUE; ++ } ++ break; ++ ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_WEPDEFAULTKEYID \n")); ++ ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ Status = copy_from_user(&pAdapter->StaCfg.DefaultKeyId, wrq->u.data.pointer, wrq->u.data.length); ++ ++ break; ++ ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::OID_802_11_CURRENTCHANNEL \n")); ++ if (wrq->u.data.length != sizeof(UCHAR)) ++ Status = -EINVAL; ++ else ++ { ++ Status = copy_from_user(&ctmp, wrq->u.data.pointer, wrq->u.data.length); ++ sprintf(&ctmp,"%d", ctmp); ++ Set_Channel_Proc(pAdapter, &ctmp); ++ } ++ break; ++#endif ++ ++ ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Set::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ ++ return Status; ++} ++ ++INT RTMPQueryInformation( ++ IN PRTMP_ADAPTER pAdapter, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ NDIS_802_11_BSSID_LIST_EX *pBssidList = NULL; ++ PNDIS_WLAN_BSSID_EX pBss; ++ NDIS_802_11_SSID Ssid; ++ NDIS_802_11_CONFIGURATION *pConfiguration = NULL; ++ RT_802_11_LINK_STATUS *pLinkStatus = NULL; ++ RT_802_11_STA_CONFIG *pStaConfig = NULL; ++ NDIS_802_11_STATISTICS *pStatistics = NULL; ++ NDIS_802_11_RTS_THRESHOLD RtsThresh; ++ NDIS_802_11_FRAGMENTATION_THRESHOLD FragThresh; ++ NDIS_802_11_POWER_MODE PowerMode; ++ NDIS_802_11_NETWORK_INFRASTRUCTURE BssType; ++ RT_802_11_PREAMBLE PreamType; ++ NDIS_802_11_AUTHENTICATION_MODE AuthMode; ++ NDIS_802_11_WEP_STATUS WepStatus; ++ NDIS_MEDIA_STATE MediaState; ++ ULONG BssBufSize, ulInfo=0, NetworkTypeList[4], apsd = 0; ++ USHORT BssLen = 0; ++ PUCHAR pBuf = NULL, pPtr; ++ INT Status = NDIS_STATUS_SUCCESS; ++ UINT we_version_compiled; ++ UCHAR i, Padding = 0; ++ BOOLEAN RadioState; ++ UCHAR driverVersion[8]; ++ OID_SET_HT_PHYMODE *pHTPhyMode = NULL; ++ ++ ++#ifdef SNMP_SUPPORT ++ //for snmp, kathy ++ DefaultKeyIdxValue *pKeyIdxValue; ++ INT valueLen; ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ ULONG ShortRetryLimit, LongRetryLimit; ++ UCHAR tmp[64]; ++#endif //SNMP ++ ++ switch(cmd) ++ { ++ case RT_OID_DEVICE_NAME: ++ wrq->u.data.length = sizeof(STA_NIC_DEVICE_NAME); ++ Status = copy_to_user(wrq->u.data.pointer, STA_NIC_DEVICE_NAME, wrq->u.data.length); ++ break; ++ case RT_OID_VERSION_INFO: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_VERSION_INFO \n")); ++ wrq->u.data.length = 8*sizeof(UCHAR); ++ sprintf(&driverVersion[0], "%s", STA_DRIVER_VERSION); ++ driverVersion[7] = '\0'; ++ if (copy_to_user(wrq->u.data.pointer, &driverVersion, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#ifdef RALINK_ATE ++ case RT_QUERY_ATE_TXDONE_COUNT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_QUERY_ATE_TXDONE_COUNT \n")); ++ wrq->u.data.length = sizeof(UINT32); ++ if (copy_to_user(wrq->u.data.pointer, &pAdapter->ate.TxDoneCount, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++#endif // RALINK_ATE // ++ case OID_802_11_BSSID_LIST: ++ if (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ { ++ /* ++ * Still scanning, indicate the caller should try again. ++ */ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (Still scanning)\n")); ++ return -EAGAIN; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID_LIST (%d BSS returned)\n",pAdapter->ScanTab.BssNr)); ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ // Claculate total buffer size required ++ BssBufSize = sizeof(ULONG); ++ ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ // Align pointer to 4 bytes boundary. ++ //Padding = 4 - (pAdapter->ScanTab.BssEntry[i].VarIELen & 0x0003); ++ //if (Padding == 4) ++ // Padding = 0; ++ BssBufSize += (sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ } ++ ++ // For safety issue, we add 256 bytes just in case ++ BssBufSize += 256; ++ // Allocate the same size as passed from higher layer ++ pBuf = kmalloc(BssBufSize, MEM_ALLOC_FLAG); ++ if(pBuf == NULL) ++ { ++ Status = -ENOMEM; ++ break; ++ } ++ // Init 802_11_BSSID_LIST_EX structure ++ NdisZeroMemory(pBuf, BssBufSize); ++ pBssidList = (PNDIS_802_11_BSSID_LIST_EX) pBuf; ++ pBssidList->NumberOfItems = pAdapter->ScanTab.BssNr; ++ ++ // Calculate total buffer length ++ BssLen = 4; // Consist of NumberOfItems ++ // Point to start of NDIS_WLAN_BSSID_EX ++ // pPtr = pBuf + sizeof(ULONG); ++ pPtr = (PUCHAR) &pBssidList->Bssid[0]; ++ for (i = 0; i < pAdapter->ScanTab.BssNr; i++) ++ { ++ pBss = (PNDIS_WLAN_BSSID_EX) pPtr; ++ NdisMoveMemory(&pBss->MacAddress, &pAdapter->ScanTab.BssEntry[i].Bssid, MAC_ADDR_LEN); ++ if ((pAdapter->ScanTab.BssEntry[i].Hidden == 1) && (pAdapter->StaCfg.bShowHiddenSSID == FALSE)) ++ { ++ // ++ // We must return this SSID during 4way handshaking, otherwise Aegis will failed to parse WPA infomation ++ // and then failed to send EAPOl farame. ++ // ++ if ((pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAdapter->StaCfg.PortSecured != WPA_802_1X_PORT_SECURED)) ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ else ++ pBss->Ssid.SsidLength = 0; ++ } ++ else ++ { ++ pBss->Ssid.SsidLength = pAdapter->ScanTab.BssEntry[i].SsidLen; ++ NdisMoveMemory(pBss->Ssid.Ssid, pAdapter->ScanTab.BssEntry[i].Ssid, pAdapter->ScanTab.BssEntry[i].SsidLen); ++ } ++ pBss->Privacy = pAdapter->ScanTab.BssEntry[i].Privacy; ++ pBss->Rssi = pAdapter->ScanTab.BssEntry[i].Rssi - pAdapter->BbpRssiToDbmDelta; ++ pBss->NetworkTypeInUse = NetworkTypeInUseSanity(&pAdapter->ScanTab.BssEntry[i]); ++ pBss->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pBss->Configuration.BeaconPeriod = pAdapter->ScanTab.BssEntry[i].BeaconPeriod; ++ pBss->Configuration.ATIMWindow = pAdapter->ScanTab.BssEntry[i].AtimWin; ++ ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->ScanTab.BssEntry[i].Channel, pBss->Configuration.DSConfig); ++ ++ if (pAdapter->ScanTab.BssEntry[i].BssType == BSS_INFRA) ++ pBss->InfrastructureMode = Ndis802_11Infrastructure; ++ else ++ pBss->InfrastructureMode = Ndis802_11IBSS; ++ ++ NdisMoveMemory(pBss->SupportedRates, pAdapter->ScanTab.BssEntry[i].SupRate, pAdapter->ScanTab.BssEntry[i].SupRateLen); ++ NdisMoveMemory(pBss->SupportedRates + pAdapter->ScanTab.BssEntry[i].SupRateLen, ++ pAdapter->ScanTab.BssEntry[i].ExtRate, ++ pAdapter->ScanTab.BssEntry[i].ExtRateLen); ++ ++ if (pAdapter->ScanTab.BssEntry[i].VarIELen == 0) ++ { ++ pBss->IELength = sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ } ++ else ++ { ++ pBss->IELength = (ULONG)(sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr = pPtr + sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs); ++ NdisMoveMemory(pBss->IEs, &pAdapter->ScanTab.BssEntry[i].FixIEs, sizeof(NDIS_802_11_FIXED_IEs)); ++ NdisMoveMemory(pBss->IEs + sizeof(NDIS_802_11_FIXED_IEs), pAdapter->ScanTab.BssEntry[i].VarIEs, pAdapter->ScanTab.BssEntry[i].VarIELen); ++ pPtr += pAdapter->ScanTab.BssEntry[i].VarIELen; ++ } ++ pBss->Length = (ULONG)(sizeof(NDIS_WLAN_BSSID_EX) - 1 + sizeof(NDIS_802_11_FIXED_IEs) + pAdapter->ScanTab.BssEntry[i].VarIELen + Padding); ++ ++#if WIRELESS_EXT < 17 ++ if ((BssLen + pBss->Length) < wrq->u.data.length) ++ BssLen += pBss->Length; ++ else ++ { ++ pBssidList->NumberOfItems = i; ++ break; ++ } ++#else ++ BssLen += pBss->Length; ++#endif ++ } ++ ++#if WIRELESS_EXT < 17 ++ wrq->u.data.length = BssLen; ++#else ++ if (BssLen > wrq->u.data.length) ++ { ++ kfree(pBssidList); ++ return -E2BIG; ++ } ++ else ++ wrq->u.data.length = BssLen; ++#endif ++ Status = copy_to_user(wrq->u.data.pointer, pBssidList, BssLen); ++ kfree(pBssidList); ++ break; ++ case OID_802_3_CURRENT_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ case OID_GEN_MEDIA_CONNECT_STATUS: ++ if (pAdapter->IndicateMediaState == NdisMediaStateConnected) ++ MediaState = NdisMediaStateConnected; ++ else ++ MediaState = NdisMediaStateDisconnected; ++ ++ wrq->u.data.length = sizeof(NDIS_MEDIA_STATE); ++ Status = copy_to_user(wrq->u.data.pointer, &MediaState, wrq->u.data.length); ++ break; ++ case OID_802_11_BSSID: ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now\n")); ++ Status = NDIS_STATUS_RESOURCES; ++ break; ++ } ++#endif // RALINK_ATE // ++ if (INFRA_ON(pAdapter) || ADHOC_ON(pAdapter)) ++ { ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Bssid, sizeof(NDIS_802_11_MAC_ADDRESS)); ++ ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BSSID(=EMPTY)\n")); ++ Status = -ENOTCONN; ++ } ++ break; ++ case OID_802_11_SSID: ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ NdisZeroMemory(Ssid.Ssid, MAX_LEN_OF_SSID); ++ Ssid.SsidLength = pAdapter->CommonCfg.SsidLen; ++ memcpy(Ssid.Ssid, pAdapter->CommonCfg.Ssid, Ssid.SsidLength); ++ wrq->u.data.length = sizeof(NDIS_802_11_SSID); ++ Status = copy_to_user(wrq->u.data.pointer, &Ssid, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SSID (Len=%d, ssid=%s)\n", Ssid.SsidLength,Ssid.Ssid)); ++ break; ++ case RT_OID_802_11_QUERY_LINK_STATUS: ++ pLinkStatus = (RT_802_11_LINK_STATUS *) kmalloc(sizeof(RT_802_11_LINK_STATUS), MEM_ALLOC_FLAG); ++ if (pLinkStatus) ++ { ++ pLinkStatus->CurrTxRate = RateIdTo500Kbps[pAdapter->CommonCfg.TxRate]; // unit : 500 kbps ++ pLinkStatus->ChannelQuality = pAdapter->Mlme.ChannelQuality; ++ pLinkStatus->RxByteCount = pAdapter->RalinkCounters.ReceivedByteCount; ++ pLinkStatus->TxByteCount = pAdapter->RalinkCounters.TransmittedByteCount; ++ pLinkStatus->CentralChannel = pAdapter->CommonCfg.CentralChannel; ++ wrq->u.data.length = sizeof(RT_802_11_LINK_STATUS); ++ Status = copy_to_user(wrq->u.data.pointer, pLinkStatus, wrq->u.data.length); ++ kfree(pLinkStatus); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS\n")); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LINK_STATUS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_CONFIGURATION: ++ pConfiguration = (NDIS_802_11_CONFIGURATION *) kmalloc(sizeof(NDIS_802_11_CONFIGURATION), MEM_ALLOC_FLAG); ++ if (pConfiguration) ++ { ++ pConfiguration->Length = sizeof(NDIS_802_11_CONFIGURATION); ++ pConfiguration->BeaconPeriod = pAdapter->CommonCfg.BeaconPeriod; ++ pConfiguration->ATIMWindow = pAdapter->StaActive.AtimWin; ++ MAP_CHANNEL_ID_TO_KHZ(pAdapter->CommonCfg.Channel, pConfiguration->DSConfig); ++ wrq->u.data.length = sizeof(NDIS_802_11_CONFIGURATION); ++ Status = copy_to_user(wrq->u.data.pointer, pConfiguration, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(BeaconPeriod=%ld,AtimW=%ld,Channel=%d) \n", ++ pConfiguration->BeaconPeriod, pConfiguration->ATIMWindow, pAdapter->CommonCfg.Channel)); ++ kfree(pConfiguration); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CONFIGURATION(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_SNR_0: ++ if ((pAdapter->StaCfg.LastSNR0 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR0) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_SNR_0(0x=%lx)\n", ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ break; ++ case RT_OID_802_11_SNR_1: ++ if ((pAdapter->Antenna.field.RxPath > 1) && ++ (pAdapter->StaCfg.LastSNR1 > 0)) ++ { ++ ulInfo = ((0xeb - pAdapter->StaCfg.LastSNR1) * 3) / 16 ; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(0x=%lx)\n",ulInfo)); ++ } ++ else ++ Status = -EFAULT; ++ DBGPRINT(RT_DEBUG_TRACE,("Query::RT_OID_802_11_SNR_1(pAdapter->StaCfg.LastSNR1=%d)\n",pAdapter->StaCfg.LastSNR1)); ++ break; ++ case OID_802_11_RSSI_TRIGGER: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0 - pAdapter->BbpRssiToDbmDelta; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RSSI_TRIGGER(=%ld)\n", ulInfo)); ++ break; ++ case OID_802_11_RSSI: ++ case RT_OID_802_11_RSSI: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi0; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_1: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi1; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_RSSI_2: ++ ulInfo = pAdapter->StaCfg.RssiSample.LastRssi2; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_802_11_STATISTICS: ++ pStatistics = (NDIS_802_11_STATISTICS *) kmalloc(sizeof(NDIS_802_11_STATISTICS), MEM_ALLOC_FLAG); ++ if (pStatistics) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS \n")); ++ // add the most up-to-date h/w raw counters into software counters ++ NICUpdateRawCounters(pAdapter); ++ ++ // Sanity check for calculation of sucessful count ++ if (pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart < pAdapter->WlanCounters.RetryCount.QuadPart) ++ pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ ++ pStatistics->TransmittedFragmentCount.QuadPart = pAdapter->WlanCounters.TransmittedFragmentCount.QuadPart; ++ pStatistics->MulticastTransmittedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastTransmittedFrameCount.QuadPart; ++ pStatistics->FailedCount.QuadPart = pAdapter->WlanCounters.FailedCount.QuadPart; ++ pStatistics->RetryCount.QuadPart = pAdapter->WlanCounters.RetryCount.QuadPart; ++ pStatistics->MultipleRetryCount.QuadPart = pAdapter->WlanCounters.MultipleRetryCount.QuadPart; ++ pStatistics->RTSSuccessCount.QuadPart = pAdapter->WlanCounters.RTSSuccessCount.QuadPart; ++ pStatistics->RTSFailureCount.QuadPart = pAdapter->WlanCounters.RTSFailureCount.QuadPart; ++ pStatistics->ACKFailureCount.QuadPart = pAdapter->WlanCounters.ACKFailureCount.QuadPart; ++ pStatistics->FrameDuplicateCount.QuadPart = pAdapter->WlanCounters.FrameDuplicateCount.QuadPart; ++ pStatistics->ReceivedFragmentCount.QuadPart = pAdapter->WlanCounters.ReceivedFragmentCount.QuadPart; ++ pStatistics->MulticastReceivedFrameCount.QuadPart = pAdapter->WlanCounters.MulticastReceivedFrameCount.QuadPart; ++#ifdef DBG ++ pStatistics->FCSErrorCount = pAdapter->RalinkCounters.RealFcsErrCount; ++#else ++ pStatistics->FCSErrorCount.QuadPart = pAdapter->WlanCounters.FCSErrorCount.QuadPart; ++ pStatistics->FrameDuplicateCount.u.LowPart = pAdapter->WlanCounters.FrameDuplicateCount.u.LowPart / 100; ++#endif ++ wrq->u.data.length = sizeof(NDIS_802_11_STATISTICS); ++ Status = copy_to_user(wrq->u.data.pointer, pStatistics, wrq->u.data.length); ++ kfree(pStatistics); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_STATISTICS(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_GEN_RCV_OK: ++ ulInfo = pAdapter->Counters8023.GoodReceives; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case OID_GEN_RCV_NO_BUFFER: ++ ulInfo = pAdapter->Counters8023.RxNoBuffer; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_PHY_MODE: ++ ulInfo = (ULONG)pAdapter->CommonCfg.PhyMode; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PHY_MODE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_STA_CONFIG: ++ pStaConfig = (RT_802_11_STA_CONFIG *) kmalloc(sizeof(RT_802_11_STA_CONFIG), MEM_ALLOC_FLAG); ++ if (pStaConfig) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG\n")); ++ pStaConfig->EnableTxBurst = pAdapter->CommonCfg.bEnableTxBurst; ++ pStaConfig->EnableTurboRate = 0; ++ pStaConfig->UseBGProtection = pAdapter->CommonCfg.UseBGProtection; ++ pStaConfig->UseShortSlotTime = pAdapter->CommonCfg.bUseShortSlotTime; ++ //pStaConfig->AdhocMode = pAdapter->StaCfg.AdhocMode; ++ pStaConfig->HwRadioStatus = (pAdapter->StaCfg.bHwRadio == TRUE) ? 1 : 0; ++ pStaConfig->Rsv1 = 0; ++ pStaConfig->SystemErrorBitmap = pAdapter->SystemErrorBitmap; ++ wrq->u.data.length = sizeof(RT_802_11_STA_CONFIG); ++ Status = copy_to_user(wrq->u.data.pointer, pStaConfig, wrq->u.data.length); ++ kfree(pStaConfig); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case OID_802_11_RTS_THRESHOLD: ++ RtsThresh = pAdapter->CommonCfg.RtsThreshold; ++ wrq->u.data.length = sizeof(RtsThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &RtsThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_RTS_THRESHOLD(=%ld)\n", RtsThresh)); ++ break; ++ case OID_802_11_FRAGMENTATION_THRESHOLD: ++ FragThresh = pAdapter->CommonCfg.FragmentThreshold; ++ if (pAdapter->CommonCfg.bUseZeroToDisableFragment == TRUE) ++ FragThresh = 0; ++ wrq->u.data.length = sizeof(FragThresh); ++ Status = copy_to_user(wrq->u.data.pointer, &FragThresh, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_FRAGMENTATION_THRESHOLD(=%ld)\n", FragThresh)); ++ break; ++ case OID_802_11_POWER_MODE: ++ PowerMode = pAdapter->StaCfg.WindowsPowerMode; ++ wrq->u.data.length = sizeof(PowerMode); ++ Status = copy_to_user(wrq->u.data.pointer, &PowerMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_POWER_MODE(=%d)\n", PowerMode)); ++ break; ++ case RT_OID_802_11_RADIO: ++ RadioState = (BOOLEAN) pAdapter->StaCfg.bSwRadio; ++ wrq->u.data.length = sizeof(RadioState); ++ Status = copy_to_user(wrq->u.data.pointer, &RadioState, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_RADIO (=%d)\n", RadioState)); ++ break; ++ case OID_802_11_INFRASTRUCTURE_MODE: ++ if (pAdapter->StaCfg.BssType == BSS_ADHOC) ++ BssType = Ndis802_11IBSS; ++ else if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ BssType = Ndis802_11Infrastructure; ++ else if (pAdapter->StaCfg.BssType == BSS_MONITOR) ++ BssType = Ndis802_11Monitor; ++ else ++ BssType = Ndis802_11AutoUnknown; ++ ++ wrq->u.data.length = sizeof(BssType); ++ Status = copy_to_user(wrq->u.data.pointer, &BssType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_INFRASTRUCTURE_MODE(=%d)\n", BssType)); ++ break; ++ case RT_OID_802_11_PREAMBLE: ++ PreamType = pAdapter->CommonCfg.TxPreamble; ++ wrq->u.data.length = sizeof(PreamType); ++ Status = copy_to_user(wrq->u.data.pointer, &PreamType, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PREAMBLE(=%d)\n", PreamType)); ++ break; ++ case OID_802_11_AUTHENTICATION_MODE: ++ AuthMode = pAdapter->StaCfg.AuthMode; ++ wrq->u.data.length = sizeof(AuthMode); ++ Status = copy_to_user(wrq->u.data.pointer, &AuthMode, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_AUTHENTICATION_MODE(=%d)\n", AuthMode)); ++ break; ++ case OID_802_11_WEP_STATUS: ++ WepStatus = pAdapter->StaCfg.WepStatus; ++ wrq->u.data.length = sizeof(WepStatus); ++ Status = copy_to_user(wrq->u.data.pointer, &WepStatus, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEP_STATUS(=%d)\n", WepStatus)); ++ break; ++ case OID_802_11_TX_POWER_LEVEL: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPower, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_TX_POWER_LEVEL %x\n",pAdapter->CommonCfg.TxPower)); ++ break; ++ case RT_OID_802_11_TX_POWER_LEVEL_1: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.TxPowerPercentage, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_TX_POWER_LEVEL_1 (=%ld)\n", pAdapter->CommonCfg.TxPowerPercentage)); ++ break; ++ case OID_802_11_NETWORK_TYPES_SUPPORTED: ++ if ((pAdapter->RfIcType == RFIC_2850) || (pAdapter->RfIcType == RFIC_2750)) ++ { ++ NetworkTypeList[0] = 3; // NumberOfItems = 3 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ NetworkTypeList[3] = Ndis802_11OFDM5; // NetworkType[3] = 11a ++ wrq->u.data.length = 16; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ else ++ { ++ NetworkTypeList[0] = 2; // NumberOfItems = 2 ++ NetworkTypeList[1] = Ndis802_11DS; // NetworkType[1] = 11b ++ NetworkTypeList[2] = Ndis802_11OFDM24; // NetworkType[2] = 11g ++ wrq->u.data.length = 12; ++ Status = copy_to_user(wrq->u.data.pointer, &NetworkTypeList[0], wrq->u.data.length); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_NETWORK_TYPES_SUPPORTED\n")); ++ break; ++ case OID_802_11_NETWORK_TYPE_IN_USE: ++ wrq->u.data.length = sizeof(ULONG); ++ if (pAdapter->CommonCfg.PhyMode == PHY_11A) ++ ulInfo = Ndis802_11OFDM5; ++ else if ((pAdapter->CommonCfg.PhyMode == PHY_11BG_MIXED) || (pAdapter->CommonCfg.PhyMode == PHY_11G)) ++ ulInfo = Ndis802_11OFDM24; ++ else ++ ulInfo = Ndis802_11DS; ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_LAST_RX_RATE: ++ ulInfo = (ULONG)pAdapter->LastRxRate; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_RX_RATE (=%ld)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_LAST_TX_RATE: ++ //ulInfo = (ULONG)pAdapter->LastTxRate; ++ ulInfo = (ULONG)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word; ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_LAST_TX_RATE (=%lx)\n", ulInfo)); ++ break; ++ case RT_OID_802_11_QUERY_EEPROM_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->EepromVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_FIRMWARE_VERSION: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->FirmwareVersion, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_NOISE_LEVEL: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->BbpWriteLatch[66], wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_NOISE_LEVEL (=%d)\n", pAdapter->BbpWriteLatch[66])); ++ break; ++ case RT_OID_802_11_EXTRA_INFO: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->ExtraInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_EXTRA_INFO (=%ld)\n", pAdapter->ExtraInfo)); ++ break; ++ case RT_OID_WE_VERSION_COMPILED: ++ wrq->u.data.length = sizeof(UINT); ++ we_version_compiled = WIRELESS_EXT; ++ Status = copy_to_user(wrq->u.data.pointer, &we_version_compiled, wrq->u.data.length); ++ break; ++ case RT_OID_802_11_QUERY_APSD_SETTING: ++ apsd = (pAdapter->CommonCfg.bAPSDCapable | (pAdapter->CommonCfg.bAPSDAC_BE << 1) | (pAdapter->CommonCfg.bAPSDAC_BK << 2) ++ | (pAdapter->CommonCfg.bAPSDAC_VI << 3) | (pAdapter->CommonCfg.bAPSDAC_VO << 4) | (pAdapter->CommonCfg.MaxSPLength << 5)); ++ ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &apsd, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_SETTING (=0x%lx,APSDCap=%d,AC_BE=%d,AC_BK=%d,AC_VI=%d,AC_VO=%d,MAXSPLen=%d)\n", ++ apsd,pAdapter->CommonCfg.bAPSDCapable,pAdapter->CommonCfg.bAPSDAC_BE,pAdapter->CommonCfg.bAPSDAC_BK,pAdapter->CommonCfg.bAPSDAC_VI,pAdapter->CommonCfg.bAPSDAC_VO,pAdapter->CommonCfg.MaxSPLength)); ++ break; ++ case RT_OID_802_11_QUERY_APSD_PSM: ++ wrq->u.data.length = sizeof(ULONG); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bAPSDForcePowerSave, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_APSD_PSM (=%d)\n", pAdapter->CommonCfg.bAPSDForcePowerSave)); ++ break; ++ case RT_OID_802_11_QUERY_WMM: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bWmmCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_WMM (=%d)\n", pAdapter->CommonCfg.bWmmCapable)); ++ break; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ case RT_OID_NEW_DRIVER: ++ { ++ UCHAR enabled = 1; ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &enabled, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_NEW_DRIVER (=%d)\n", enabled)); ++ } ++ break; ++ case RT_OID_WPA_SUPPLICANT_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.WpaSupplicantUP, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_WPA_SUPPLICANT_SUPPORT (=%d)\n", pAdapter->StaCfg.WpaSupplicantUP)); ++ break; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++ case RT_OID_DRIVER_DEVICE_NAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_DRIVER_DEVICE_NAME \n")); ++ wrq->u.data.length = 16; ++ if (copy_to_user(wrq->u.data.pointer, pAdapter->StaCfg.dev_name, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC; ++ ++ pHTPhyMode->ExtOffset = ((pAdapter->CommonCfg.CentralChannel < pAdapter->CommonCfg.Channel) ? (EXTCHA_BELOW) : (EXTCHA_ABOVE)); ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_COUNTRY_REGION: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_COUNTRY_REGION \n")); ++ wrq->u.data.length = sizeof(ulInfo); ++ ulInfo = pAdapter->CommonCfg.CountryRegionForABand; ++ ulInfo = (ulInfo << 8)|(pAdapter->CommonCfg.CountryRegion); ++ if (copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_802_11_QUERY_DAT_HT_PHYMODE: ++ pHTPhyMode = (OID_SET_HT_PHYMODE *) kmalloc(sizeof(OID_SET_HT_PHYMODE), MEM_ALLOC_FLAG); ++ if (pHTPhyMode) ++ { ++ pHTPhyMode->PhyMode = pAdapter->CommonCfg.PhyMode; ++ pHTPhyMode->HtMode = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.HTMODE; ++ pHTPhyMode->BW = (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.BW; ++ pHTPhyMode->MCS= (UCHAR)pAdapter->StaCfg.DesiredTransmitSetting.field.MCS; ++ pHTPhyMode->SHORTGI= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.ShortGI; ++ pHTPhyMode->STBC= (UCHAR)pAdapter->CommonCfg.RegTransmitSetting.field.STBC; ++ ++ wrq->u.data.length = sizeof(OID_SET_HT_PHYMODE); ++ if (copy_to_user(wrq->u.data.pointer, pHTPhyMode, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_HT_PHYMODE (PhyMode = %d, MCS =%d, BW = %d, STBC = %d, ExtOffset=%d)\n", ++ pHTPhyMode->HtMode, pHTPhyMode->MCS, pHTPhyMode->BW, pHTPhyMode->STBC, pHTPhyMode->ExtOffset)); ++ DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (.word = %x )\n", pAdapter->MacTab.Content[BSSID_WCID].HTPhyMode.word)); ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_STA_CONFIG(kmalloc failed)\n")); ++ Status = -EFAULT; ++ } ++ break; ++ case RT_OID_QUERY_MULTIPLE_CARD_SUPPORT: ++ wrq->u.data.length = sizeof(UCHAR); ++ i = 0; ++#ifdef MULTIPLE_CARD_SUPPORT ++ i = 1; ++#endif // MULTIPLE_CARD_SUPPORT // ++ if (copy_to_user(wrq->u.data.pointer, &i, wrq->u.data.length)) ++ { ++ Status = -EFAULT; ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_QUERY_MULTIPLE_CARD_SUPPORT(=%d) \n", i)); ++ break; ++#ifdef SNMP_SUPPORT ++ case RT_OID_802_11_MAC_ADDRESS: ++ wrq->u.data.length = MAC_ADDR_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREROUI: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREROUI \n")); ++ wrq->u.data.length = ManufacturerOUI_LEN; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CurrentAddress, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTURERNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTURERNAME \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_RESOURCETYPEIDNAME: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_RESOURCETYPEIDNAME \n")); ++ wrq->u.data.length = strlen(ResourceTypeIdName); ++ Status = copy_to_user(wrq->u.data.pointer, ResourceTypeIdName, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRIVACYOPTIONIMPLEMENTED \n")); ++ ulInfo = 1; // 1 is support wep else 2 is not support. ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_POWERMANAGEMENTMODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_POWERMANAGEMENTMODE \n")); ++ if (pAdapter->StaCfg.Psm == PSMP_ACTION) ++ ulInfo = 1; // 1 is power active else 2 is power save. ++ else ++ ulInfo = 2; ++ ++ wrq->u.data.length = sizeof(ulInfo); ++ Status = copy_to_user(wrq->u.data.pointer, &ulInfo, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYVALUE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_WEPDEFAULTKEYVALUE \n")); ++ //KeyIdxValue.KeyIdx = pAd->PortCfg.MBSSID[pAd->IoctlIF].DefaultKeyId; ++ pKeyIdxValue = wrq->u.data.pointer; ++ DBGPRINT(RT_DEBUG_TRACE,("KeyIdxValue.KeyIdx = %d, \n",pKeyIdxValue->KeyIdx)); ++ valueLen = pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen; ++ NdisMoveMemory(pKeyIdxValue->Value, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].Key, ++ valueLen); ++ pKeyIdxValue->Value[valueLen]='\0'; ++ ++ wrq->u.data.length = sizeof(DefaultKeyIdxValue); ++ ++ Status = copy_to_user(wrq->u.data.pointer, pKeyIdxValue, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE,("DefaultKeyId = %d, total len = %d, str len=%d, KeyValue= %02x %02x %02x %02x \n", pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length, pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ pAdapter->SharedKey[BSS0][0].Key[0], ++ pAdapter->SharedKey[BSS0][1].Key[0], ++ pAdapter->SharedKey[BSS0][2].Key[0], ++ pAdapter->SharedKey[BSS0][3].Key[0])); ++ break; ++ ++ case OID_802_11_WEPDEFAULTKEYID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPDEFAULTKEYID \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->StaCfg.DefaultKeyId, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("DefaultKeyId =%d \n", pAdapter->StaCfg.DefaultKeyId)); ++ break; ++ ++ case RT_OID_802_11_WEPKEYMAPPINGLENGTH: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_WEPKEYMAPPINGLENGTH \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ Status = copy_to_user(wrq->u.data.pointer, ++ &pAdapter->SharedKey[BSS0][pAdapter->StaCfg.DefaultKeyId].KeyLen, ++ wrq->u.data.length); ++ break; ++ ++ case OID_802_11_SHORTRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_SHORTRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ ShortRetryLimit = tx_rty_cfg.field.ShortRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("ShortRetryLimit =%ld, tx_rty_cfg.field.ShortRetryLimit=%d\n", ShortRetryLimit, tx_rty_cfg.field.ShortRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &ShortRetryLimit, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_LONGRETRYLIMIT: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_LONGRETRYLIMIT \n")); ++ wrq->u.data.length = sizeof(ULONG); ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ LongRetryLimit = tx_rty_cfg.field.LongRtyLimit; ++ DBGPRINT(RT_DEBUG_TRACE, ("LongRetryLimit =%ld, tx_rty_cfg.field.LongRtyLimit=%d\n", LongRetryLimit, tx_rty_cfg.field.LongRtyLimit)); ++ Status = copy_to_user(wrq->u.data.pointer, &LongRetryLimit, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_PRODUCTID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); ++ ++#ifdef RT2870 ++ sprintf(tmp, "%04x %04x\n", ((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idVendor ,((POS_COOKIE)pAdapter->OS_Cookie)->pUsb_Dev->descriptor.idProduct); ++ ++#endif // RT2870 // ++ wrq->u.data.length = strlen(tmp); ++ Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); ++ break; ++ ++ case RT_OID_802_11_MANUFACTUREID: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_MANUFACTUREID \n")); ++ wrq->u.data.length = strlen(ManufacturerNAME); ++ Status = copy_to_user(wrq->u.data.pointer, ManufacturerNAME, wrq->u.data.length); ++ break; ++ ++ case OID_802_11_CURRENTCHANNEL: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_CURRENTCHANNEL \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++ DBGPRINT(RT_DEBUG_TRACE, ("sizeof UCHAR=%d, channel=%d \n", sizeof(UCHAR), pAdapter->CommonCfg.Channel)); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Channel, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++#endif //SNMP_SUPPORT ++ ++ case OID_802_11_BUILD_CHANNEL_EX: ++ { ++ UCHAR value; ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_BUILD_CHANNEL_EX \n")); ++ wrq->u.data.length = sizeof(UCHAR); ++#ifdef EXT_BUILD_CHANNEL_LIST ++ DBGPRINT(RT_DEBUG_TRACE, ("Support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 1; ++#else ++ DBGPRINT(RT_DEBUG_TRACE, ("Doesn't support EXT_BUILD_CHANNEL_LIST.\n")); ++ value = 0; ++#endif // EXT_BUILD_CHANNEL_LIST // ++ Status = copy_to_user(wrq->u.data.pointer, &value, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ } ++ break; ++ ++ case OID_802_11_GET_CH_LIST: ++ { ++ PRT_CHANNEL_LIST_INFO pChListBuf; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CH_LIST \n")); ++ if (pAdapter->ChannelListNum == 0) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf = (RT_CHANNEL_LIST_INFO *) kmalloc(sizeof(RT_CHANNEL_LIST_INFO), MEM_ALLOC_FLAG); ++ if (pChListBuf == NULL) ++ { ++ wrq->u.data.length = 0; ++ break; ++ } ++ ++ pChListBuf->ChannelListNum = pAdapter->ChannelListNum; ++ for (i = 0; i < pChListBuf->ChannelListNum; i++) ++ pChListBuf->ChannelList[i] = pAdapter->ChannelList[i].Channel; ++ ++ wrq->u.data.length = sizeof(RT_CHANNEL_LIST_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pChListBuf, sizeof(RT_CHANNEL_LIST_INFO)); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ ++ if (pChListBuf) ++ kfree(pChListBuf); ++ } ++ break; ++ ++ case OID_802_11_GET_COUNTRY_CODE: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_COUNTRY_CODE \n")); ++ wrq->u.data.length = 2; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.CountryCode, 2); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ case OID_802_11_GET_CHANNEL_GEOGRAPHY: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::OID_802_11_GET_CHANNEL_GEOGRAPHY \n")); ++ wrq->u.data.length = 1; ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.Geography, 1); ++ DBGPRINT(RT_DEBUG_TRACE, ("Status=%d\n", Status)); ++ break; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ case RT_OID_802_11_QUERY_DLS: ++ wrq->u.data.length = sizeof(BOOLEAN); ++ Status = copy_to_user(wrq->u.data.pointer, &pAdapter->CommonCfg.bDLSCapable, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS(=%d)\n", pAdapter->CommonCfg.bDLSCapable)); ++ break; ++ ++ case RT_OID_802_11_QUERY_DLS_PARAM: ++ { ++ PRT_802_11_DLS_INFO pDlsInfo = kmalloc(sizeof(RT_802_11_DLS_INFO), GFP_ATOMIC); ++ if (pDlsInfo == NULL) ++ break; ++ ++ for (i=0; iEntry[i], &pAdapter->StaCfg.DLSEntry[i], sizeof(RT_802_11_DLS_UI)); ++ } ++ ++ pDlsInfo->num = MAX_NUM_OF_DLS_ENTRY; ++ wrq->u.data.length = sizeof(RT_802_11_DLS_INFO); ++ Status = copy_to_user(wrq->u.data.pointer, pDlsInfo, wrq->u.data.length); ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_QUERY_DLS_PARAM\n")); ++ ++ if (pDlsInfo) ++ kfree(pDlsInfo); ++ } ++ break; ++#endif // QOS_DLS_SUPPORT // ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("Query::unknown IOCTL's subcmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ return Status; ++} ++ ++INT rt28xx_sta_ioctl( ++ IN struct net_device *net_dev, ++ IN OUT struct ifreq *rq, ++ IN INT cmd) ++{ ++ POS_COOKIE pObj; ++ VIRTUAL_ADAPTER *pVirtualAd = NULL; ++ RTMP_ADAPTER *pAd = NULL; ++ struct iwreq *wrq = (struct iwreq *) rq; ++ BOOLEAN StateMachineTouched = FALSE; ++ INT Status = NDIS_STATUS_SUCCESS; ++ USHORT subcmd; ++ ++ if (net_dev->priv_flags == INT_MAIN) ++ { ++ pAd = net_dev->ml_priv; ++ } ++ else ++ { ++ pVirtualAd = net_dev->ml_priv; ++ pAd = pVirtualAd->RtmpDev->ml_priv; ++ } ++ pObj = (POS_COOKIE) pAd->OS_Cookie; ++ ++ if (pAd == NULL) ++ { ++ /* if 1st open fail, pAd will be free; ++ So the net_dev->ml_priv will be NULL in 2rd open */ ++ return -ENETDOWN; ++ } ++ ++ //check if the interface is down ++ if(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) ++ { ++#ifdef CONFIG_APSTA_MIXED_SUPPORT ++ if (wrq->u.data.pointer == NULL) ++ { ++ return Status; ++ } ++ ++ if (strstr(wrq->u.data.pointer, "OpMode") == NULL) ++#endif // CONFIG_APSTA_MIXED_SUPPORT // ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("INFO::Network is down!\n")); ++ return -ENETDOWN; ++ } ++ } ++ ++ { // determine this ioctl command is comming from which interface. ++ pObj->ioctl_if_type = INT_MAIN; ++ pObj->ioctl_if = MAIN_MBSSID; ++ } ++ ++ switch(cmd) ++ { ++#ifdef RALINK_ATE ++#ifdef RALINK_28xx_QA ++ case RTPRIV_IOCTL_ATE: ++ { ++ RtmpDoAte(pAd, wrq); ++ } ++ break; ++#endif // RALINK_28xx_QA // ++#endif // RALINK_ATE // ++ case SIOCGIFHWADDR: ++ DBGPRINT(RT_DEBUG_TRACE, ("IOCTL::SIOCGIFHWADDR\n")); ++ memcpy(wrq->u.name, pAd->CurrentAddress, ETH_ALEN); ++ break; ++ case SIOCGIWNAME: ++ { ++ char *name=&wrq->u.name[0]; ++ rt_ioctl_giwname(net_dev, NULL, name, NULL); ++ break; ++ } ++ case SIOCGIWESSID: //Get ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_giwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWESSID: //Set ESSID ++ { ++ struct iw_point *essid=&wrq->u.essid; ++ rt_ioctl_siwessid(net_dev, NULL, essid, essid->pointer); ++ break; ++ } ++ case SIOCSIWNWID: // set network id (the cell) ++ case SIOCGIWNWID: // get network id ++ Status = -EOPNOTSUPP; ++ break; ++ case SIOCSIWFREQ: //set channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_siwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCGIWFREQ: // get channel/frequency (Hz) ++ { ++ struct iw_freq *freq=&wrq->u.freq; ++ rt_ioctl_giwfreq(net_dev, NULL, freq, NULL); ++ break; ++ } ++ case SIOCSIWNICKN: //set node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_siwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWNICKN: //get node name/nickname ++ { ++ struct iw_point *data=&wrq->u.data; ++ rt_ioctl_giwnickn(net_dev, NULL, data, NULL); ++ break; ++ } ++ case SIOCGIWRATE: //get default bit rate (bps) ++ rt_ioctl_giwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCSIWRATE: //set default bit rate (bps) ++ rt_ioctl_siwrate(net_dev, NULL, &wrq->u, NULL); ++ break; ++ case SIOCGIWRTS: // get RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_giwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCSIWRTS: //set RTS/CTS threshold (bytes) ++ { ++ struct iw_param *rts=&wrq->u.rts; ++ rt_ioctl_siwrts(net_dev, NULL, rts, NULL); ++ break; ++ } ++ case SIOCGIWFRAG: //get fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_giwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCSIWFRAG: //set fragmentation thr (bytes) ++ { ++ struct iw_param *frag=&wrq->u.frag; ++ rt_ioctl_siwfrag(net_dev, NULL, frag, NULL); ++ break; ++ } ++ case SIOCGIWENCODE: //get encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_giwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCSIWENCODE: //set encoding token & mode ++ { ++ struct iw_point *erq=&wrq->u.encoding; ++ if(erq->pointer) ++ rt_ioctl_siwencode(net_dev, NULL, erq, erq->pointer); ++ break; ++ } ++ case SIOCGIWAP: //get access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_giwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCSIWAP: //set access point MAC addresses ++ { ++ struct sockaddr *ap_addr=&wrq->u.ap_addr; ++ rt_ioctl_siwap(net_dev, NULL, ap_addr, ap_addr->sa_data); ++ break; ++ } ++ case SIOCGIWMODE: //get operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_giwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCSIWMODE: //set operation mode ++ { ++ __u32 *mode=&wrq->u.mode; ++ rt_ioctl_siwmode(net_dev, NULL, mode, NULL); ++ break; ++ } ++ case SIOCGIWSENS: //get sensitivity (dBm) ++ case SIOCSIWSENS: //set sensitivity (dBm) ++ case SIOCGIWPOWER: //get Power Management settings ++ case SIOCSIWPOWER: //set Power Management settings ++ case SIOCGIWTXPOW: //get transmit power (dBm) ++ case SIOCSIWTXPOW: //set transmit power (dBm) ++ case SIOCGIWRANGE: //Get range of parameters ++ case SIOCGIWRETRY: //get retry limits and lifetime ++ case SIOCSIWRETRY: //set retry limits and lifetime ++ Status = -EOPNOTSUPP; ++ break; ++ case RT_PRIV_IOCTL: ++ case RT_PRIV_IOCTL_EXT: ++ subcmd = wrq->u.data.flags; ++ if( subcmd & OID_GET_SET_TOGGLE) ++ Status = RTMPSetInformation(pAd, rq, subcmd); ++ else ++ Status = RTMPQueryInformation(pAd, rq, subcmd); ++ break; ++ case SIOCGIWPRIV: ++ if (wrq->u.data.pointer) ++ { ++ if ( access_ok(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)) != TRUE) ++ break; ++ wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); ++ if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) ++ Status = -EFAULT; ++ } ++ break; ++ case RTPRIV_IOCTL_SET: ++ if(access_ok(VERIFY_READ, wrq->u.data.pointer, wrq->u.data.length) != TRUE) ++ break; ++ rt_ioctl_setparam(net_dev, NULL, NULL, wrq->u.data.pointer); ++ break; ++ case RTPRIV_IOCTL_GSITESURVEY: ++ RTMPIoctlGetSiteSurvey(pAd, wrq); ++ break; ++#ifdef DBG ++ case RTPRIV_IOCTL_MAC: ++ RTMPIoctlMAC(pAd, wrq); ++ break; ++ case RTPRIV_IOCTL_E2P: ++ RTMPIoctlE2PROM(pAd, wrq); ++ break; ++#ifdef RT30xx ++ case RTPRIV_IOCTL_RF: ++ RTMPIoctlRF(pAd, wrq); ++ break; ++#endif // RT30xx // ++#endif // DBG // ++ case SIOCETHTOOL: ++ break; ++ default: ++ DBGPRINT(RT_DEBUG_ERROR, ("IOCTL::unknown IOCTL's cmd = 0x%08x\n", cmd)); ++ Status = -EOPNOTSUPP; ++ break; ++ } ++ ++ if(StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAd); ++ ++ return Status; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set SSID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_SSID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ NDIS_802_11_SSID Ssid, *pSsid=NULL; ++ BOOLEAN StateMachineTouched = FALSE; ++ int success = TRUE; ++ ++ if( strlen(arg) <= MAX_LEN_OF_SSID) ++ { ++ NdisZeroMemory(&Ssid, sizeof(NDIS_802_11_SSID)); ++ if (strlen(arg) != 0) ++ { ++ NdisMoveMemory(Ssid.Ssid, arg, strlen(arg)); ++ Ssid.SsidLength = strlen(arg); ++ } ++ else //ANY ssid ++ { ++ Ssid.SsidLength = 0; ++ memcpy(Ssid.Ssid, "", 0); ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ pAdapter->StaCfg.WepStatus = Ndis802_11EncryptionDisabled; ++ } ++ pSsid = &Ssid; ++ ++ if (pAdapter->Mlme.CntlMachine.CurrState != CNTL_IDLE) ++ { ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!! MLME busy, reset MLME state machine !!!\n")); ++ } ++ ++ pAdapter->MlmeAux.CurrReqIsFromNdis = TRUE; ++ pAdapter->StaCfg.bScanReqIsFromWebUI = FALSE; ++ pAdapter->bConfigChanged = TRUE; ++ ++ MlmeEnqueue(pAdapter, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_SSID, ++ sizeof(NDIS_802_11_SSID), ++ (VOID *)pSsid); ++ ++ StateMachineTouched = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_SSID_Proc::(Len=%d,Ssid=%s)\n", Ssid.SsidLength, Ssid.Ssid)); ++ } ++ else ++ success = FALSE; ++ ++ if (StateMachineTouched) // Upper layer sent a MLME-related operations ++ RT28XX_MLME_HANDLER(pAdapter); ++ ++ return success; ++} ++ ++#ifdef WMM_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WmmCapable Enable or Disable ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WmmCapable_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ BOOLEAN bWmmCapable; ++ ++ bWmmCapable = simple_strtol(arg, 0, 10); ++ ++ if ((bWmmCapable == 1) ++#ifdef RT2870 ++ && (pAd->NumberOfPipes >= 5) ++#endif // RT2870 // ++ ) ++ pAd->CommonCfg.bWmmCapable = TRUE; ++ else if (bWmmCapable == 0) ++ pAd->CommonCfg.bWmmCapable = FALSE; ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WmmCapable_Proc::(bWmmCapable=%d)\n", ++ pAd->CommonCfg.bWmmCapable)); ++ ++ return TRUE; ++} ++#endif // WMM_SUPPORT // ++ ++/* ++ ========================================================================== ++ Description: ++ Set Network Type(Infrastructure/Adhoc mode) ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_NetworkType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UINT32 Value = 0; ++ ++ if (strcmp(arg, "Adhoc") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_ADHOC) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (INFRA_ON(pAdapter)) ++ { ++ //BOOLEAN Cancelled; ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event BB!\n")); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_ADHOC; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(AD-HOC)\n")); ++ } ++ else if (strcmp(arg, "Infra") == 0) ++ { ++ if (pAdapter->StaCfg.BssType != BSS_INFRA) ++ { ++ // Config has changed ++ pAdapter->bConfigChanged = TRUE; ++ if (MONITOR_ON(pAdapter)) ++ { ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, STANORMAL); ++ RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ Value &= (~0x80); ++ RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ pAdapter->StaCfg.bAutoReconnect = TRUE; ++ LinkDown(pAdapter, FALSE); ++ } ++ if (ADHOC_ON(pAdapter)) ++ { ++ // Set the AutoReconnectSsid to prevent it reconnect to old SSID ++ // Since calling this indicate user don't want to connect to that SSID anymore. ++ pAdapter->MlmeAux.AutoReconnectSsidLen= 32; ++ NdisZeroMemory(pAdapter->MlmeAux.AutoReconnectSsid, pAdapter->MlmeAux.AutoReconnectSsidLen); ++ ++ LinkDown(pAdapter, FALSE); ++ } ++ } ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ pAdapter->net_dev->type = pAdapter->StaCfg.OriDevType; ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(INFRA)\n")); ++ ++ pAdapter->StaCfg.BssType = BSS_INFRA; ++ } ++ else if (strcmp(arg, "Monitor") == 0) ++ { ++ UCHAR bbpValue = 0; ++ BCN_TIME_CFG_STRUC csr; ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_INFRA_ON); ++ OPSTATUS_CLEAR_FLAG(pAdapter, fOP_STATUS_ADHOC_ON); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ // disable all periodic state machine ++ pAdapter->StaCfg.bAutoReconnect = FALSE; ++ // reset all mlme state machine ++ RT28XX_MLME_RESET_STATE_MACHINE(pAdapter); ++ DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_MEDIA_STATE_CONNECTED \n")); ++ if (pAdapter->CommonCfg.CentralChannel == 0) ++ { ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode == PHY_11AN_MIXED) ++ pAdapter->CommonCfg.CentralChannel = 36; ++ else ++#endif // DOT11_N_SUPPORT // ++ pAdapter->CommonCfg.CentralChannel = 6; ++ } ++#ifdef DOT11_N_SUPPORT ++ else ++ N_ChannelCheck(pAdapter); ++#endif // DOT11_N_SUPPORT // ++ ++#ifdef DOT11_N_SUPPORT ++ if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_ABOVE) ++ { ++ // 40MHz ,control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel + 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else if (pAdapter->CommonCfg.PhyMode >= PHY_11ABGN_MIXED && ++ pAdapter->CommonCfg.RegTransmitSetting.field.BW == BW_40 && ++ pAdapter->CommonCfg.RegTransmitSetting.field.EXTCHA == EXTCHA_BELOW) ++ { ++ // 40MHz ,control channel at upper ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ bbpValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_40; ++ RTMP_IO_READ32(pAdapter, TX_BAND_CFG, &Value); ++ Value |= 0x1; ++ RTMP_IO_WRITE32(pAdapter, TX_BAND_CFG, Value); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R3, &bbpValue); ++ bbpValue |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R3, bbpValue); ++ pAdapter->CommonCfg.CentralChannel = pAdapter->CommonCfg.Channel - 2; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.CentralChannel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_40 ,control_channel(%d), CentralChannel(%d) \n", ++ pAdapter->CommonCfg.Channel, ++ pAdapter->CommonCfg.CentralChannel)); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // 20MHz ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAdapter, BBP_R4, &bbpValue); ++ bbpValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R4, bbpValue); ++ pAdapter->CommonCfg.BBPCurrentBW = BW_20; ++ AsicSwitchChannel(pAdapter, pAdapter->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAdapter, pAdapter->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("BW_20, Channel(%d)\n", pAdapter->CommonCfg.Channel)); ++ } ++ // Enable Rx with promiscuous reception ++ RTMP_IO_WRITE32(pAdapter, RX_FILTR_CFG, 0x3); ++ // ASIC supporsts sniffer function with replacing RSSI with timestamp. ++ //RTMP_IO_READ32(pAdapter, MAC_SYS_CTRL, &Value); ++ //Value |= (0x80); ++ //RTMP_IO_WRITE32(pAdapter, MAC_SYS_CTRL, Value); ++ // disable sync ++ RTMP_IO_READ32(pAdapter, BCN_TIME_CFG, &csr.word); ++ csr.field.bBeaconGen = 0; ++ csr.field.bTBTTEnable = 0; ++ csr.field.TsfSyncMode = 0; ++ RTMP_IO_WRITE32(pAdapter, BCN_TIME_CFG, csr.word); ++ ++ pAdapter->StaCfg.BssType = BSS_MONITOR; ++ pAdapter->net_dev->type = ARPHRD_IEEE80211_PRISM; //ARPHRD_IEEE80211; // IEEE80211 ++ DBGPRINT(RT_DEBUG_TRACE, ("===>Set_NetworkType_Proc::(MONITOR)\n")); ++ } ++ ++ // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_NetworkType_Proc::(NetworkType=%d)\n", pAdapter->StaCfg.BssType)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Authentication mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_AuthMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "WEPAUTO") == 0) || (strcmp(arg, "wepauto") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeAutoSwitch; ++ else if ((strcmp(arg, "OPEN") == 0) || (strcmp(arg, "open") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeOpen; ++ else if ((strcmp(arg, "SHARED") == 0) || (strcmp(arg, "shared") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeShared; ++ else if ((strcmp(arg, "WPAPSK") == 0) || (strcmp(arg, "wpapsk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPAPSK; ++ else if ((strcmp(arg, "WPANONE") == 0) || (strcmp(arg, "wpanone") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPANone; ++ else if ((strcmp(arg, "WPA2PSK") == 0) || (strcmp(arg, "wpa2psk") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ((strcmp(arg, "WPA") == 0) || (strcmp(arg, "wpa") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA; ++ else if ((strcmp(arg, "WPA2") == 0) || (strcmp(arg, "wpa2") == 0)) ++ pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_AuthMode_Proc::(AuthMode=%d)\n", pAdapter->StaCfg.AuthMode)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Encryption Type ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_EncrypType_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if ((strcmp(arg, "NONE") == 0) || (strcmp(arg, "none") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled; ++ } ++ else if ((strcmp(arg, "WEP") == 0) || (strcmp(arg, "wep") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11WEPEnabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11WEPEnabled; ++ } ++ else if ((strcmp(arg, "TKIP") == 0) || (strcmp(arg, "tkip") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption2Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption2Enabled; ++ } ++ else if ((strcmp(arg, "AES") == 0) || (strcmp(arg, "aes") == 0)) ++ { ++ if (pAdapter->StaCfg.AuthMode < Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ pAdapter->StaCfg.WepStatus = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; ++ pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; ++ } ++ else ++ return FALSE; ++ ++ pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_EncrypType_Proc::(EncrypType=%d)\n", pAdapter->StaCfg.WepStatus)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Default Key ID ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_DefaultKeyID_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ ULONG KeyIdx; ++ ++ KeyIdx = simple_strtol(arg, 0, 10); ++ if((KeyIdx >= 1 ) && (KeyIdx <= 4)) ++ pAdapter->StaCfg.DefaultKeyId = (UCHAR) (KeyIdx - 1 ); ++ else ++ return FALSE; //Invalid argument ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_DefaultKeyID_Proc::(DefaultKeyID=%d)\n", pAdapter->StaCfg.DefaultKeyId)); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY1 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key1_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][0].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][0].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][0].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::(Key1=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key1_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ ++ pAdapter->SharedKey[BSS0][0].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 0, ++ pAdapter->SharedKey[BSS0][0].CipherAlg, ++ pAdapter->SharedKey[BSS0][0].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ ++ Description: ++ Set WEP KEY2 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key2_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][1].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][1].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][1].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::(Key2=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key2_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][1].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 1, ++ pAdapter->SharedKey[BSS0][1].CipherAlg, ++ pAdapter->SharedKey[BSS0][1].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY3 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key3_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][2].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Ascii)\n", arg)); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][2].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][2].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::(Key3=%s and type=Hex)\n", arg)); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key3_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][2].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 2, ++ pAdapter->SharedKey[BSS0][2].CipherAlg, ++ pAdapter->SharedKey[BSS0][2].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++/* ++ ========================================================================== ++ Description: ++ Set WEP KEY4 ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Key4_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ int KeyLen; ++ int i; ++ UCHAR CipherAlg=CIPHER_WEP64; ++ ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ return TRUE; // do nothing ++ ++ KeyLen = strlen(arg); ++ ++ switch (KeyLen) ++ { ++ case 5: //wep 40 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 10: //wep 40 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP64; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ case 13: //wep 104 Ascii type ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen; ++ memcpy(pAdapter->SharedKey[BSS0][3].Key, arg, KeyLen); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Ascii")); ++ break; ++ case 26: //wep 104 Hex type ++ for(i=0; i < KeyLen; i++) ++ { ++ if( !isxdigit(*(arg+i)) ) ++ return FALSE; //Not Hex value; ++ } ++ pAdapter->SharedKey[BSS0][3].KeyLen = KeyLen / 2 ; ++ AtoH(arg, pAdapter->SharedKey[BSS0][3].Key, KeyLen / 2); ++ CipherAlg = CIPHER_WEP128; ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::(Key4=%s and type=%s)\n", arg, "Hex")); ++ break; ++ default: //Invalid argument ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Key4_Proc::Invalid argument (=%s)\n", arg)); ++ return FALSE; ++ } ++ pAdapter->SharedKey[BSS0][3].CipherAlg = CipherAlg; ++ ++ // Set keys (into ASIC) ++ if (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) ++ ; // not support ++ else // Old WEP stuff ++ { ++ AsicAddSharedKeyEntry(pAdapter, ++ 0, ++ 3, ++ pAdapter->SharedKey[BSS0][3].CipherAlg, ++ pAdapter->SharedKey[BSS0][3].Key, ++ NULL, ++ NULL); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set WPA PSK key ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_WPAPSK_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ UCHAR keyMaterial[40]; ++ ++ if ((pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPAPSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPA2PSK) && ++ (pAdapter->StaCfg.AuthMode != Ndis802_11AuthModeWPANone) ++ ) ++ return TRUE; // do nothing ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_WPAPSK_Proc::(WPAPSK=%s)\n", arg)); ++ ++ NdisZeroMemory(keyMaterial, 40); ++ ++ if ((strlen(arg) < 8) || (strlen(arg) > 64)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("Set failed!!(WPAPSK=%s), WPAPSK key-string required 8 ~ 64 characters \n", arg)); ++ return FALSE; ++ } ++ ++ if (strlen(arg) == 64) ++ { ++ AtoH(arg, keyMaterial, 32); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ ++ } ++ else ++ { ++ PasswordHash((char *)arg, pAdapter->MlmeAux.Ssid, pAdapter->MlmeAux.SsidLen, keyMaterial); ++ NdisMoveMemory(pAdapter->StaCfg.PMK, keyMaterial, 32); ++ } ++ ++ ++ ++ if(pAdapter->StaCfg.BssType == BSS_ADHOC && ++ pAdapter->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ pAdapter->StaCfg.WpaState = SS_NOTUSE; ++ } ++ else ++ { ++ // Start STA supplicant state machine ++ pAdapter->StaCfg.WpaState = SS_START; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Set Power Saving mode ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_PSMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (pAdapter->StaCfg.BssType == BSS_INFRA) ++ { ++ if ((strcmp(arg, "Max_PSP") == 0) || ++ (strcmp(arg, "max_psp") == 0) || ++ (strcmp(arg, "MAX_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP; ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ pAdapter->StaCfg.DefaultListenCount = 5; ++ ++ } ++ else if ((strcmp(arg, "Fast_PSP") == 0) || ++ (strcmp(arg, "fast_psp") == 0) || ++ (strcmp(arg, "FAST_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else if ((strcmp(arg, "Legacy_PSP") == 0) || ++ (strcmp(arg, "legacy_psp") == 0) || ++ (strcmp(arg, "LEGACY_PSP") == 0)) ++ { ++ // do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange() ++ // to exclude certain situations. ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP; ++ pAdapter->StaCfg.DefaultListenCount = 3; ++ } ++ else ++ { ++ //Default Ndis802_11PowerModeCAM ++ // clear PSM bit immediately ++ MlmeSetPsmBit(pAdapter, PWR_ACTIVE); ++ OPSTATUS_SET_FLAG(pAdapter, fOP_STATUS_RECEIVE_DTIM); ++ if (pAdapter->StaCfg.bWindowsACCAMEnable == FALSE) ++ pAdapter->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM; ++ pAdapter->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_PSMode_Proc::(PSMode=%ld)\n", pAdapter->StaCfg.WindowsPowerMode)); ++ } ++ else ++ return FALSE; ++ ++ ++ return TRUE; ++} ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++/* ++ ========================================================================== ++ Description: ++ Set WpaSupport flag. ++ Value: ++ 0: Driver ignore wpa_supplicant. ++ 1: wpa_supplicant initiates scanning and AP selection. ++ 2: driver takes care of scanning, AP selection, and IEEE 802.11 association parameters. ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++*/ ++INT Set_Wpa_Support( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ ++ if ( simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ else if ( simple_strtol(arg, 0, 10) == 1) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE; ++ else if ( simple_strtol(arg, 0, 10) == 2) ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_ENABLE_WITH_WEB_UI; ++ else ++ pAd->StaCfg.WpaSupplicantUP = WPA_SUPPLICANT_DISABLE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Wpa_Support::(WpaSupplicantUP=%d)\n", pAd->StaCfg.WpaSupplicantUP)); ++ ++ return TRUE; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++#ifdef DBG ++/* ++ ========================================================================== ++ Description: ++ Read / Write MAC ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 mac 0 ==> read MAC where Addr=0x0 ++ 2.) iwpriv ra0 mac 0=12 ==> write MAC where Addr=0x0, value=12 ++ ========================================================================== ++*/ ++VOID RTMPIoctlMAC( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ ULONG macAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ UINT32 macValue = 0; ++ INT Status; ++ BOOLEAN bIsPrintAllMAC = FALSE; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // Mac Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ if (macAddr < 0xFFFF) ++ { ++ RTMP_IO_READ32(pAdapter, macAddr, &macValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%lx, MacValue=%x\n", macAddr, macValue)); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr , macValue); ++ } ++ else ++ {//Invalid parametes, so default printk all mac ++ bIsPrintAllMAC = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[8-k+j] = temp2[j]; ++ } ++ ++ while(k < 8) ++ temp2[7-k++]='0'; ++ temp2[8]='\0'; ++ ++ { ++ AtoH(this_char, temp, 2); ++ macAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 4); ++ macValue = *temp*256*256*256 + temp[1]*256*256 + temp[2]*256 + temp[3]; ++ ++ // debug mode ++ if (macAddr == (HW_DEBUG_SETTING_BASE + 4)) ++ { ++ // 0x2bf4: byte0 non-zero: enable R17 tuning, 0: disable R17 tuning ++ if (macValue & 0x000000ff) ++ { ++ pAdapter->BbpTuning.bEnable = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,("turn on R17 tuning\n")); ++ } ++ else ++ { ++ UCHAR R66; ++ pAdapter->BbpTuning.bEnable = FALSE; ++ R66 = 0x26 + GET_LNA_GAIN(pAdapter); ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ } ++ else ++#endif // RALINK_ATE // ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAdapter, BBP_R66, (0x26 + GET_LNA_GAIN(pAdapter))); ++ DBGPRINT(RT_DEBUG_TRACE,("turn off R17 tuning, restore to 0x%02x\n", R66)); ++ } ++ return; ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("MacAddr=%02lx, MacValue=0x%x\n", macAddr, macValue)); ++ ++ RTMP_IO_WRITE32(pAdapter, macAddr, macValue); ++ sprintf(msg+strlen(msg), "[0x%08lX]:%08X ", macAddr, macValue); ++ } ++ } ++ } ++ else ++ bIsPrintAllMAC = TRUE; ++next: ++ if (bIsPrintAllMAC) ++ { ++ struct file *file_w; ++ PCHAR fileName = "MacDump.txt"; ++ mm_segment_t orig_fs; ++ ++ orig_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ // open file ++ file_w = filp_open(fileName, O_WRONLY|O_CREAT, 0); ++ if (IS_ERR(file_w)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("-->2) %s: Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(file_w), fileName)); ++ } ++ else ++ { ++ if (file_w->f_op && file_w->f_op->write) ++ { ++ file_w->f_pos = 0; ++ macAddr = 0x1000; ++ ++ while (macAddr <= 0x1800) ++ { ++ RTMP_IO_READ32(pAdapter, macAddr, &macValue); ++ sprintf(msg, "%08lx = %08X\n", macAddr, macValue); ++ ++ // write data to file ++ file_w->f_op->write(file_w, msg, strlen(msg), &file_w->f_pos); ++ ++ printk("%s", msg); ++ macAddr += 4; ++ } ++ sprintf(msg, "\nDump all MAC values to %s\n", fileName); ++ } ++ filp_close(file_w, NULL); ++ } ++ set_fs(orig_fs); ++ } ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlMAC\n\n")); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Read / Write E2PROM ++ Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 e2p 0 ==> read E2PROM where Addr=0x0 ++ 2.) iwpriv ra0 e2p 0=1234 ==> write E2PROM where Addr=0x0, value=1234 ++ ========================================================================== ++*/ ++VOID RTMPIoctlE2PROM( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ INT j = 0, k = 0; ++ CHAR msg[1024]; ++ CHAR arg[255]; ++ USHORT eepAddr = 0; ++ UCHAR temp[16], temp2[16]; ++ USHORT eepValue; ++ int Status; ++ BOOLEAN bIsPrintAllE2P = FALSE; ++ ++ ++ memset(msg, 0x00, 1024); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ ++ ++ if (!*this_char) ++ goto next; ++ ++ if ((value = rtstrchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ ++ // Sanity check ++ if(strlen(this_char) > 4) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ ++ // E2PROM addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ if(strlen(this_char) == 4) ++ { ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ if (eepAddr < 0xFFFF) ++ { ++ RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%04X]:0x%04X ", eepAddr , eepValue); ++ } ++ else ++ {//Invalid parametes, so default printk all bbp ++ bIsPrintAllE2P = TRUE; ++ goto next; ++ } ++ } ++ } ++ else ++ { //Write ++ memcpy(&temp2, value, strlen(value)); ++ temp2[strlen(value)] = '\0'; ++ ++ // Sanity check ++ if((strlen(this_char) > 4) || strlen(temp2) > 8) ++ goto next; ++ ++ j = strlen(this_char); ++ while(j-- > 0) ++ { ++ if(this_char[j] > 'f' || this_char[j] < '0') ++ return; ++ } ++ j = strlen(temp2); ++ while(j-- > 0) ++ { ++ if(temp2[j] > 'f' || temp2[j] < '0') ++ return; ++ } ++ ++ //MAC Addr ++ k = j = strlen(this_char); ++ while(j-- > 0) ++ { ++ this_char[4-k+j] = this_char[j]; ++ } ++ ++ while(k < 4) ++ this_char[3-k++]='0'; ++ this_char[4]='\0'; ++ ++ //MAC value ++ k = j = strlen(temp2); ++ while(j-- > 0) ++ { ++ temp2[4-k+j] = temp2[j]; ++ } ++ ++ while(k < 4) ++ temp2[3-k++]='0'; ++ temp2[4]='\0'; ++ ++ AtoH(this_char, temp, 2); ++ eepAddr = *temp*256 + temp[1]; ++ ++ AtoH(temp2, temp, 2); ++ eepValue = *temp*256 + temp[1]; ++ ++ RT28xx_EEPROM_WRITE16(pAdapter, eepAddr, eepValue); ++ sprintf(msg+strlen(msg), "[0x%02X]:%02X ", eepAddr, eepValue); ++ } ++ } ++ else ++ bIsPrintAllE2P = TRUE; ++next: ++ if (bIsPrintAllE2P) ++ { ++ struct file *file_w; ++ PCHAR fileName = "EEPROMDump.txt"; ++ mm_segment_t orig_fs; ++ ++ orig_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ // open file ++ file_w = filp_open(fileName, O_WRONLY|O_CREAT, 0); ++ if (IS_ERR(file_w)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("-->2) %s: Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(file_w), fileName)); ++ } ++ else ++ { ++ if (file_w->f_op && file_w->f_op->write) ++ { ++ file_w->f_pos = 0; ++ eepAddr = 0x00; ++ ++ while (eepAddr <= 0xFE) ++ { ++ RT28xx_EEPROM_READ16(pAdapter, eepAddr, eepValue); ++ sprintf(msg, "%08x = %04x\n", eepAddr , eepValue); ++ ++ // write data to file ++ file_w->f_op->write(file_w, msg, strlen(msg), &file_w->f_pos); ++ ++ printk("%s", msg); ++ eepAddr += 2; ++ } ++ sprintf(msg, "\nDump all EEPROM values to %s\n", fileName); ++ } ++ filp_close(file_w, NULL); ++ } ++ set_fs(orig_fs); ++ } ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlE2PROM\n")); ++} ++#ifdef RT30xx ++/* ++ ========================================================================== ++ Description: ++ Read / Write RF register ++Arguments: ++ pAdapter Pointer to our adapter ++ wrq Pointer to the ioctl argument ++ ++ Return Value: ++ None ++ ++ Note: ++ Usage: ++ 1.) iwpriv ra0 rf ==> read all RF registers ++ 2.) iwpriv ra0 rf 1 ==> read RF where RegID=1 ++ 3.) iwpriv ra0 rf 1=10 ==> write RF R1=0x10 ++ ========================================================================== ++*/ ++VOID RTMPIoctlRF( ++ IN PRTMP_ADAPTER pAdapter, ++ IN struct iwreq *wrq) ++{ ++ CHAR *this_char; ++ CHAR *value; ++ UCHAR regRF = 0; ++ CHAR msg[2048]; ++ CHAR arg[255]; ++ INT rfId; ++ LONG rfValue; ++ int Status; ++ BOOLEAN bIsPrintAllRF = FALSE; ++ ++ ++ memset(msg, 0x00, 2048); ++ if (wrq->u.data.length > 1) //No parameters. ++ { ++ Status = copy_from_user(arg, wrq->u.data.pointer, (wrq->u.data.length > 255) ? 255 : wrq->u.data.length); ++ sprintf(msg, "\n"); ++ ++ //Parsing Read or Write ++ this_char = arg; ++ if (!*this_char) ++ goto next; ++ ++ if ((value = strchr(this_char, '=')) != NULL) ++ *value++ = 0; ++ ++ if (!value || !*value) ++ { //Read ++ if (sscanf(this_char, "%d", &(rfId)) == 1) ++ { ++ if (rfId <= 31) ++ { ++ // In RT2860 ATE mode, we do not load 8051 firmware. ++ //We must access RF directly. ++ // For RT2870 ATE mode, ATE_RF_IO_WRITE8(/READ8)_BY_REG_ID are redefined. ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); ++ } ++ else ++#endif // RALINK_ATE // ++ // according to Andy, Gary, David require. ++ // the command rf shall read rf register directly for dubug. ++ // BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ RT30xxReadRFRegister(pAdapter, rfId, ®RF); ++ ++ sprintf(msg+strlen(msg), "R%02d[0x%02x]:%02X ", rfId, rfId*2, regRF); ++ } ++ else ++ {//Invalid parametes, so default printk all RF ++ bIsPrintAllRF = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all RF ++ bIsPrintAllRF = TRUE; ++ goto next; ++ } ++ } ++ else ++ { //Write ++ if ((sscanf(this_char, "%d", &(rfId)) == 1) && (sscanf(value, "%lx", &(rfValue)) == 1)) ++ { ++ if (rfId <= 31) ++ { ++ // In RT2860 ATE mode, we do not load 8051 firmware. ++ // We should access RF registers directly. ++ // For RT2870 ATE mode, ATE_RF_IO_WRITE8/READ8_BY_REG_ID are redefined. ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); ++ ATE_RF_IO_WRITE8_BY_REG_ID(pAdapter, (UCHAR)rfId,(UCHAR) rfValue); ++ //Read it back for showing ++ ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); ++ sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X\n", rfId, rfId*2, regRF); ++ } ++ else ++#endif // RALINK_ATE // ++ { ++ // according to Andy, Gary, David require. ++ // the command RF shall read/write RF register directly for dubug. ++ //BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ //BBP_IO_WRITE8_BY_REG_ID(pAdapter, (UCHAR)bbpId,(UCHAR) bbpValue); ++ RT30xxReadRFRegister(pAdapter, rfId, ®RF); ++ RT30xxWriteRFRegister(pAdapter, (UCHAR)rfId,(UCHAR) rfValue); ++ //Read it back for showing ++ //BBP_IO_READ8_BY_REG_ID(pAdapter, bbpId, ®BBP); ++ RT30xxReadRFRegister(pAdapter, rfId, ®RF); ++ sprintf(msg+strlen(msg), "R%02d[0x%02X]:%02X\n", rfId, rfId*2, regRF); ++ } ++ } ++ else ++ {//Invalid parametes, so default printk all RF ++ bIsPrintAllRF = TRUE; ++ } ++ } ++ else ++ { //Invalid parametes, so default printk all RF ++ bIsPrintAllRF = TRUE; ++ } ++ } ++ } ++ else ++ bIsPrintAllRF = TRUE; ++next: ++ if (bIsPrintAllRF) ++ { ++ memset(msg, 0x00, 2048); ++ sprintf(msg, "\n"); ++ for (rfId = 0; rfId <= 31; rfId++) ++ { ++ // In RT2860 ATE mode, we do not load 8051 firmware. ++ // We should access RF registers directly. ++ // For RT2870 ATE mode, ATE_RF_IO_WRITE8/READ8_BY_REG_ID are redefined. ++#ifdef RALINK_ATE ++ if (ATE_ON(pAdapter)) ++ { ++ ATE_RF_IO_READ8_BY_REG_ID(pAdapter, rfId, ®RF); ++ } ++ else ++#endif // RALINK_ATE // ++ ++ // according to Andy, Gary, David require. ++ // the command RF shall read/write RF register directly for dubug. ++ RT30xxReadRFRegister(pAdapter, rfId, ®RF); ++ sprintf(msg+strlen(msg), "%03d = %02X\n", rfId, regRF); ++ } ++ // Copy the information into the user buffer ++ DBGPRINT(RT_DEBUG_TRACE, ("strlen(msg)=%d\n", (UINT32)strlen(msg))); ++ wrq->u.data.length = strlen(msg); ++ if (copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); ++ } ++ } ++ else ++ { ++ if(strlen(msg) == 1) ++ sprintf(msg+strlen(msg), "===>Error command format!"); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("copy to user [msg=%s]\n", msg)); ++ // Copy the information into the user buffer ++ DBGPRINT(RT_DEBUG_TRACE, ("strlen(msg) =%d\n", (UINT32)strlen(msg))); ++ ++ // Copy the information into the user buffer ++ wrq->u.data.length = strlen(msg); ++ Status = copy_to_user(wrq->u.data.pointer, msg, wrq->u.data.length); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<==RTMPIoctlRF\n\n")); ++} ++#endif // RT30xx // ++#endif // DBG // ++ ++ ++ ++ ++INT Set_TGnWifiTest_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->StaCfg.bTGnWifiTest = FALSE; ++ else ++ pAd->StaCfg.bTGnWifiTest = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_TGnWifiTest_Proc::(bTGnWifiTest=%d)\n", pAd->StaCfg.bTGnWifiTest)); ++ return TRUE; ++} ++ ++INT Set_LongRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR LongRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.LongRtyLimit = LongRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_LongRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++INT Set_ShortRetryLimit_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ TX_RTY_CFG_STRUC tx_rty_cfg; ++ UCHAR ShortRetryLimit = (UCHAR)simple_strtol(arg, 0, 10); ++ ++ RTMP_IO_READ32(pAdapter, TX_RTY_CFG, &tx_rty_cfg.word); ++ tx_rty_cfg.field.ShortRtyLimit = ShortRetryLimit; ++ RTMP_IO_WRITE32(pAdapter, TX_RTY_CFG, tx_rty_cfg.word); ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_ShortRetryLimit_Proc::(tx_rty_cfg=0x%x)\n", tx_rty_cfg.word)); ++ return TRUE; ++} ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++INT Set_Ieee80211dClientMode_Proc( ++ IN PRTMP_ADAPTER pAdapter, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_None; ++ else if (simple_strtol(arg, 0, 10) == 1) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Flexible; ++ else if (simple_strtol(arg, 0, 10) == 2) ++ pAdapter->StaCfg.IEEE80211dClientMode = Rt802_11_D_Strict; ++ else ++ return FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Set_Ieee802dMode_Proc::(IEEEE0211dMode=%d)\n", pAdapter->StaCfg.IEEE80211dClientMode)); ++ return TRUE; ++} ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++#ifdef CARRIER_DETECTION_SUPPORT ++INT Set_CarrierDetect_Proc( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR arg) ++{ ++ if (simple_strtol(arg, 0, 10) == 0) ++ pAd->CommonCfg.CarrierDetect.Enable = FALSE; ++ else ++ pAd->CommonCfg.CarrierDetect.Enable = TRUE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("IF Set_CarrierDetect_Proc::(CarrierDetect.Enable=%d)\n", pAd->CommonCfg.CarrierDetect.Enable)); ++ return TRUE; ++} ++#endif // CARRIER_DETECTION_SUPPORT // ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/rtmp_data.c +@@ -0,0 +1,2637 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ rtmp_data.c ++ ++ Abstract: ++ Data path subroutines ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Aug/17/04 major modification for RT2561/2661 ++ Jan Lee Mar/17/06 major modification for RT2860 New Ring Design ++*/ ++#include "../rt_config.h" ++ ++ ++ ++VOID STARxEAPOLFrameIndicate( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ UCHAR *pTmpBuf; ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ // All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon) ++ // TBD : process fragmented EAPol frames ++ { ++ // In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable ++ if ( pAd->StaCfg.IEEE8021X == TRUE && ++ (EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H))) ++ { ++ PUCHAR Key; ++ UCHAR CipherAlg; ++ int idx = 0; ++ ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n")); ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ if (pAd->StaCfg.IEEE8021x_required_keys == FALSE) ++ { ++ idx = pAd->StaCfg.DesireSharedKeyId; ++ CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg; ++ Key = pAd->StaCfg.DesireSharedKey[idx].Key; ++ ++ if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) ++ { ++#ifdef RT2870 ++ union ++ { ++ char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1]; ++ NDIS_802_11_WEP keyinfo; ++ } WepKey; ++ int len; ++ ++ ++ NdisZeroMemory(&WepKey, sizeof(WepKey)); ++ len =pAd->StaCfg.DesireSharedKey[idx].KeyLen; ++ ++ NdisMoveMemory(WepKey.keyinfo.KeyMaterial, ++ pAd->StaCfg.DesireSharedKey[idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].KeyLen); ++ ++ WepKey.keyinfo.KeyIndex = 0x80000000 + idx; ++ WepKey.keyinfo.KeyLength = len; ++ pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ // need to enqueue cmd to thread ++ RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1); ++#endif // RT2870 // ++ // For Preventing ShardKey Table is cleared by remove key procedure. ++ pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; ++ pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; ++ NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].Key, ++ pAd->StaCfg.DesireSharedKey[idx].KeyLen); ++ } ++ } ++ } ++ ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ // Special DATA frame that has to pass to MLME ++ // 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process ++ // 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process ++ { ++ pTmpBuf = pRxBlk->pData - LENGTH_802_11; ++ NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11); ++ REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize)); ++ } ++ } ++ ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ ++} ++ ++VOID STARxDataFrameAnnounce( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk, ++ IN UCHAR FromWhichBSSID) ++{ ++ ++ // non-EAP frame ++ if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID)) ++ { ++ ++ { ++ // drop all non-EAP DATA frame before ++ // this client's Port-Access-Control is secured ++ if (pRxBlk->pHeader->FC.Wep) ++ { ++ // unsupported cipher suite ++ if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ else ++ { ++ // encryption in-use but receive a non-EAPOL clear text frame, drop it ++ if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ } ++ RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP); ++ if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK)) ++ { ++ // Normal legacy, AMPDU or AMSDU ++ CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID); ++ ++ } ++ else ++ { ++ // ARALINK ++ CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ } ++#ifdef QOS_DLS_SUPPORT ++ RX_BLK_CLEAR_FLAG(pRxBlk, fRX_DLS); ++#endif // QOS_DLS_SUPPORT // ++ } ++ else ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_EAP); ++#ifdef DOT11_N_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0)) ++ { ++ Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // Determin the destination of the EAP frame ++ // to WPA state machine or upper layer ++ STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ } ++ } ++} ++ ++ ++// For TKIP frame, calculate the MIC value ++BOOLEAN STACheckTkipMICValue( ++ IN PRTMP_ADAPTER pAd, ++ IN MAC_TABLE_ENTRY *pEntry, ++ IN RX_BLK *pRxBlk) ++{ ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ UCHAR *pData = pRxBlk->pData; ++ USHORT DataSize = pRxBlk->DataSize; ++ UCHAR UserPriority = pRxBlk->UserPriority; ++ PCIPHER_KEY pWpaKey; ++ UCHAR *pDA, *pSA; ++ ++ pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex]; ++ ++ pDA = pHeader->Addr1; ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA)) ++ { ++ pSA = pHeader->Addr3; ++ } ++ else ++ { ++ pSA = pHeader->Addr2; ++ } ++ ++ if (RTMPTkipCompareMICValue(pAd, ++ pData, ++ pDA, ++ pSA, ++ pWpaKey->RxMic, ++ UserPriority, ++ DataSize) == FALSE) ++ { ++ DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n")); ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++ if (pAd->StaCfg.WpaSupplicantUP) ++ { ++ WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE); ++ } ++ else ++#endif // WPA_SUPPLICANT_SUPPORT // ++ { ++ RTMPReportMicError(pAd, pWpaKey); ++ } ++ ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++// ++// All Rx routines use RX_BLK structure to hande rx events ++// It is very important to build pRxBlk attributes ++// 1. pHeader pointer to 802.11 Header ++// 2. pData pointer to payload including LLC (just skip Header) ++// 3. set payload size including LLC to DataSize ++// 4. set some flags with RX_BLK_SET_FLAG() ++// ++VOID STAHandleRxDataFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ BOOLEAN bFragment = FALSE; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ UCHAR FromWhichBSSID = BSS0; ++ UCHAR UserPriority = 0; ++ ++ { ++ // before LINK UP, all DATA frames are rejected ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++#ifdef QOS_DLS_SUPPORT ++ //if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) ++ if (RTMPRcvFrameDLSCheck(pAd, pHeader, pRxWI->MPDUtotalByteCount, pRxD)) ++ { ++ return; ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // Drop not my BSS frames ++ if (pRxD->MyBss == 0) ++ { ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ ++ pAd->RalinkCounters.RxCountSinceLastNULL++; ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08)) ++ { ++ UCHAR *pData; ++ DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n")); ++ ++ // Qos bit 4 ++ pData = (PUCHAR)pHeader + LENGTH_802_11; ++ if ((*pData >> 4) & 0x01) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n")); ++ pAd->CommonCfg.bInServicePeriod = FALSE; ++ ++ // Force driver to fall into sleep mode when rcv EOSP frame ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ USHORT TbttNumToNextWakeUp; ++ USHORT NextDtim = pAd->StaCfg.DtimPeriod; ++ ULONG Now; ++ ++ NdisGetSystemUpTime(&Now); ++ NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod; ++ ++ TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) ++ TbttNumToNextWakeUp = NextDtim; ++ ++ MlmeSetPsmBit(pAd, PWR_SAVE); ++ // if WMM-APSD is failed, try to disable following line ++ AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ } ++ } ++ ++ if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n")); ++ } ++ } ++ ++ // Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame ++ if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // Drop not my BSS frame (we can not only check the MyBss bit in RxD) ++#ifdef QOS_DLS_SUPPORT ++ if (!pAd->CommonCfg.bDLSCapable) ++ { ++#endif // QOS_DLS_SUPPORT // ++ if (INFRA_ON(pAd)) ++ { ++ // Infrastructure mode, check address 2 for BSSID ++ if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6)) ++ { ++ // Receive frame not my BSSID ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++ else // Ad-Hoc mode or Not associated ++ { ++ // Ad-Hoc mode, check address 3 for BSSID ++ if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6)) ++ { ++ // Receive frame not my BSSID ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ } ++#ifdef QOS_DLS_SUPPORT ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ // ++ // find pEntry ++ // ++ if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE) ++ { ++ pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; ++ } ++ else ++ { ++ // 1. release packet if infra mode ++ // 2. new a pEntry if ad-hoc mode ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // infra or ad-hoc ++ if (INFRA_ON(pAd)) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA); ++#ifdef QOS_DLS_SUPPORT ++ if ((pHeader->FC.FrDs == 0) && (pHeader->FC.ToDs == 0)) ++ RX_BLK_SET_FLAG(pRxBlk, fRX_DLS); ++ else ++#endif // QOS_DLS_SUPPORT // ++ ASSERT(pRxWI->WirelessCliID == BSSID_WCID); ++ } ++ ++ // check Atheros Client ++ if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry )) ++ { ++ pEntry->bIAmBadAtheros = TRUE; ++ pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE; ++ pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE; ++ if (!STA_AES_ON(pAd)) ++ { ++ AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE); ++ } ++ } ++ } ++ ++ pRxBlk->pData = (UCHAR *)pHeader; ++ ++ // ++ // update RxBlk->pData, DataSize ++ // 802.11 Header, QOS, HTC, Hw Padding ++ // ++ ++ // 1. skip 802.11 HEADER ++ { ++ pRxBlk->pData += LENGTH_802_11; ++ pRxBlk->DataSize -= LENGTH_802_11; ++ } ++ ++ // 2. QOS ++ if (pHeader->FC.SubType & 0x08) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_QOS); ++ UserPriority = *(pRxBlk->pData) & 0x0f; ++ // bit 7 in QoS Control field signals the HT A-MSDU format ++ if ((*pRxBlk->pData) & 0x80) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU); ++ } ++ ++ // skip QOS contorl field ++ pRxBlk->pData += 2; ++ pRxBlk->DataSize -=2; ++ } ++ pRxBlk->UserPriority = UserPriority; ++ ++ // 3. Order bit: A-Ralink or HTC+ ++ if (pHeader->FC.Order) ++ { ++#ifdef AGGREGATION_SUPPORT ++ if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK); ++ } ++ else ++#endif ++ { ++#ifdef DOT11_N_SUPPORT ++ RX_BLK_SET_FLAG(pRxBlk, fRX_HTC); ++ // skip HTC contorl field ++ pRxBlk->pData += 4; ++ pRxBlk->DataSize -= 4; ++#endif // DOT11_N_SUPPORT // ++ } ++ } ++ ++ // 4. skip HW padding ++ if (pRxD->L2PAD) ++ { ++ // just move pData pointer ++ // because DataSize excluding HW padding ++ RX_BLK_SET_FLAG(pRxBlk, fRX_PAD); ++ pRxBlk->pData += 2; ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ if (pRxD->BA) ++ { ++ RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ ++ // ++ // Case I Process Broadcast & Multicast data frame ++ // ++ if (pRxD->Bcast || pRxD->Mcast) ++ { ++ INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount); ++ ++ // Drop Mcast/Bcast frame with fragment bit on ++ if (pHeader->FC.MoreFrag) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ // Filter out Bcast frame which AP relayed for us ++ if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress)) ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ else if (pRxD->U2M) ++ { ++ pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ; ++ ++ ++#ifdef QOS_DLS_SUPPORT ++ if (RX_BLK_TEST_FLAG(pRxBlk, fRX_DLS)) ++ { ++ MAC_TABLE_ENTRY *pDlsEntry = NULL; ++ ++ pDlsEntry = DlsEntryTableLookupByWcid(pAd, pRxWI->WirelessCliID, pHeader->Addr2, TRUE); ++ if(pDlsEntry) ++ Update_Rssi_Sample(pAd, &pDlsEntry->RssiSample, pRxWI); ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ if (ADHOC_ON(pAd)) ++ { ++ pEntry = MacTableLookup(pAd, pHeader->Addr2); ++ if (pEntry) ++ Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI); ++ } ++ ++ ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); ++ ++ pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); ++ pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); ++ ++ pAd->RalinkCounters.OneSecRxOkDataCnt++; ++ ++ ++ if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0))) ++ { ++ // re-assemble the fragmented packets ++ // return complete frame (pRxPacket) or NULL ++ bFragment = TRUE; ++ pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk); ++ } ++ ++ if (pRxPacket) ++ { ++ pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID]; ++ ++ // process complete frame ++ if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled)) ++ { ++ // Minus MIC length ++ pRxBlk->DataSize -= 8; ++ ++ // For TKIP frame, calculate the MIC value ++ if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE) ++ { ++ return; ++ } ++ } ++ ++ STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID); ++ return; ++ } ++ else ++ { ++ // just return ++ // because RTMPDeFragmentDataFrame() will release rx packet, ++ // if packet is fragmented ++ return; ++ } ++ } ++ ++ ASSERT(0); ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++} ++ ++VOID STAHandleRxMgmtFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++ PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD); ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ ++ do ++ { ++ ++ // We should collect RSSI not only U2M data but also my beacon ++ if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)) ++ && (pAd->RxAnt.EvaluatePeriod == 0)) ++ { ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI); ++ ++ pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0); ++ pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1); ++ } ++ ++#ifdef RT30xx ++ // collect rssi information for antenna diversity ++ if (pAd->NicConfig2.field.AntDiversity) ++ { ++ if ((pRxD->U2M) || ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)))) ++ { ++ COLLECT_RX_ANTENNA_AVERAGE_RSSI(pAd, ConvertToRssi(pAd, (UCHAR)pRxWI->RSSI0, RSSI_0), 0); //Note: RSSI2 not used on RT73 ++ pAd->StaCfg.NumOfAvgRssiSample ++; ++ } ++ } ++#endif // RT30xx // ++ ++ // First check the size, it MUST not exceed the mlme queue size ++ if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE) ++ { ++ DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount)); ++ break; ++ } ++ ++ REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount, ++ pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal); ++ } while (FALSE); ++ ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); ++} ++ ++VOID STAHandleRxControlFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN RX_BLK *pRxBlk) ++{ ++#ifdef DOT11_N_SUPPORT ++ PRXWI_STRUC pRxWI = pRxBlk->pRxWI; ++#endif // DOT11_N_SUPPORT // ++ PHEADER_802_11 pHeader = pRxBlk->pHeader; ++ PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket; ++ ++ switch (pHeader->FC.SubType) ++ { ++ case SUBTYPE_BLOCK_ACK_REQ: ++#ifdef DOT11_N_SUPPORT ++ { ++ CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader); ++ } ++ break; ++#endif // DOT11_N_SUPPORT // ++ case SUBTYPE_BLOCK_ACK: ++ case SUBTYPE_ACK: ++ default: ++ break; ++ } ++ ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process RxDone interrupt, running in DPC level ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ This routine has to maintain Rx ring read pointer. ++ Need to consider QOS DATA format when converting to 802.3 ++ ======================================================================== ++*/ ++BOOLEAN STARxDoneInterruptHandle( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN argc) ++{ ++ NDIS_STATUS Status; ++ UINT32 RxProcessed, RxPending; ++ BOOLEAN bReschedule = FALSE; ++ RT28XX_RXD_STRUC *pRxD; ++ UCHAR *pData; ++ PRXWI_STRUC pRxWI; ++ PNDIS_PACKET pRxPacket; ++ PHEADER_802_11 pHeader; ++ RX_BLK RxCell; ++ ++ RxProcessed = RxPending = 0; ++ ++ // process whole rx ring ++ while (1) ++ { ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF | ++ fRTMP_ADAPTER_RESET_IN_PROGRESS | ++ fRTMP_ADAPTER_HALT_IN_PROGRESS | ++ fRTMP_ADAPTER_NIC_NOT_EXIST) || ++ !RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP)) ++ { ++ break; ++ } ++ ++ ++ RxProcessed ++; // test ++ ++ // 1. allocate a new data packet into rx ring to replace received packet ++ // then processing the received packet ++ // 2. the callee must take charge of release of packet ++ // 3. As far as driver is concerned , ++ // the rx packet must ++ // a. be indicated to upper layer or ++ // b. be released if it is discarded ++ pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending); ++ if (pRxPacket == NULL) ++ { ++ // no more packet to process ++ break; ++ } ++ ++ // get rx ring descriptor ++ pRxD = &(RxCell.RxD); ++ // get rx data buffer ++ pData = GET_OS_PKT_DATAPTR(pRxPacket); ++ pRxWI = (PRXWI_STRUC) pData; ++ pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ; ++ ++#ifdef RT_BIG_ENDIAN ++ RTMPFrameEndianChange(pAd, (PUCHAR)pHeader, DIR_READ, TRUE); ++ RTMPWIEndianChange((PUCHAR)pRxWI, TYPE_RXWI); ++#endif ++ ++ // build RxCell ++ RxCell.pRxWI = pRxWI; ++ RxCell.pHeader = pHeader; ++ RxCell.pRxPacket = pRxPacket; ++ RxCell.pData = (UCHAR *) pHeader; ++ RxCell.DataSize = pRxWI->MPDUtotalByteCount; ++ RxCell.Flags = 0; ++ ++ // Increase Total receive byte counter after real data received no mater any error or not ++ pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount; ++ pAd->RalinkCounters.RxCount ++; ++ ++ INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount); ++ ++ if (pRxWI->MPDUtotalByteCount < 14) ++ Status = NDIS_STATUS_FAILURE; ++ ++ if (MONITOR_ON(pAd)) ++ { ++ send_monitor_packets(pAd, &RxCell); ++ break; ++ } ++ /* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ pAd->ate.RxCntPerSec++; ++ ATESampleRssi(pAd, pRxWI); ++#ifdef RALINK_28xx_QA ++ if (pAd->ate.bQARxStart == TRUE) ++ { ++ /* (*pRxD) has been swapped in GetPacketFromRxRing() */ ++ ATE_QA_Statistics(pAd, pRxWI, pRxD, pHeader); ++ } ++#endif // RALINK_28xx_QA // ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS); ++ continue; ++ } ++#endif // RALINK_ATE // ++ ++ // Check for all RxD errors ++ Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD); ++ ++ // Handle the received frame ++ if (Status == NDIS_STATUS_SUCCESS) ++ { ++ switch (pHeader->FC.Type) ++ { ++ // CASE I, receive a DATA frame ++ case BTYPE_DATA: ++ { ++ // process DATA frame ++ STAHandleRxDataFrame(pAd, &RxCell); ++ } ++ break; ++ // CASE II, receive a MGMT frame ++ case BTYPE_MGMT: ++ { ++ STAHandleRxMgmtFrame(pAd, &RxCell); ++ } ++ break; ++ // CASE III. receive a CNTL frame ++ case BTYPE_CNTL: ++ { ++ STAHandleRxControlFrame(pAd, &RxCell); ++ } ++ break; ++ // discard other type ++ default: ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ break; ++ } ++ } ++ else ++ { ++ pAd->Counters8023.RxErrors++; ++ // discard this frame ++ RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE); ++ } ++ } ++ ++ return bReschedule; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Arguments: ++ pAd Pointer to our adapter ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ======================================================================== ++*/ ++VOID RTMPHandleTwakeupInterrupt( ++ IN PRTMP_ADAPTER pAd) ++{ ++ AsicForceWakeup(pAd, FALSE); ++} ++ ++/* ++======================================================================== ++Routine Description: ++ Early checking and OS-depened parsing for Tx packet send to our STA driver. ++ ++Arguments: ++ NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd. ++ PPNDIS_PACKET ppPacketArray The packet array need to do transmission. ++ UINT NumberOfPackets Number of packet in packet array. ++ ++Return Value: ++ NONE ++ ++Note: ++ This function do early checking and classification for send-out packet. ++ You only can put OS-depened & STA related code in here. ++======================================================================== ++*/ ++VOID STASendPackets( ++ IN NDIS_HANDLE MiniportAdapterContext, ++ IN PPNDIS_PACKET ppPacketArray, ++ IN UINT NumberOfPackets) ++{ ++ UINT Index; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext; ++ PNDIS_PACKET pPacket; ++ BOOLEAN allowToSend = FALSE; ++ ++ ++ for (Index = 0; Index < NumberOfPackets; Index++) ++ { ++ pPacket = ppPacketArray[Index]; ++ ++ do ++ { ++ ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) ++ { ++ // Drop send request since hardware is in reset state ++ break; ++ } ++ else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd)) ++ { ++ // Drop send request since there are no physical connection yet ++ break; ++ } ++ else ++ { ++ // Record that orignal packet source is from NDIS layer,so that ++ // later on driver knows how to release this NDIS PACKET ++#ifdef QOS_DLS_SUPPORT ++ MAC_TABLE_ENTRY *pEntry; ++ PUCHAR pSrcBufVA = GET_OS_PKT_DATAPTR(pPacket); ++ ++ pEntry = MacTableLookup(pAd, pSrcBufVA); ++ if (pEntry && (pEntry->ValidAsDls == TRUE)) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, pEntry->Aid); ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode ++ RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); ++ NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING); ++ pAd->RalinkCounters.PendingNdisPacketCount++; ++ ++ allowToSend = TRUE; ++ } ++ } while(FALSE); ++ ++ if (allowToSend == TRUE) ++ STASendPacket(pAd, pPacket); ++ else ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ ++ // Dequeue outgoing frames from TxSwQueue[] and process it ++ RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS); ++ ++} ++ ++ ++/* ++======================================================================== ++Routine Description: ++ This routine is used to do packet parsing and classification for Tx packet ++ to STA device, and it will en-queue packets to our TxSwQueue depends on AC ++ class. ++ ++Arguments: ++ pAd Pointer to our adapter ++ pPacket Pointer to send packet ++ ++Return Value: ++ NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue. ++ NDIS_STATUS_FAILURE If failed to do en-queue. ++ ++Note: ++ You only can put OS-indepened & STA related code in here. ++======================================================================== ++*/ ++NDIS_STATUS STASendPacket( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket) ++{ ++ PACKET_INFO PacketInfo; ++ PUCHAR pSrcBufVA; ++ UINT SrcBufLen; ++ UINT AllowFragSize; ++ UCHAR NumberOfFrag; ++// UCHAR RTSRequired; ++ UCHAR QueIdx, UserPriority; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ unsigned int IrqFlags; ++ UCHAR FlgIsIP = 0; ++ UCHAR Rate; ++ ++ // Prepare packet information structure for buffer descriptor ++ // chained within a single NDIS packet. ++ RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen); ++ ++ if (pSrcBufVA == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen)); ++ // Resourece is low, system did not allocate virtual address ++ // return NDIS_STATUS_FAILURE directly to upper layer ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ ++ if (SrcBufLen < 14) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++ // In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry. ++ // Note multicast packets in adhoc also use BSSID_WCID index. ++ { ++ if(INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ USHORT tmpWcid; ++ ++ tmpWcid = RTMP_GET_PACKET_WCID(pPacket); ++ if (VALID_WCID(tmpWcid) && ++ (pAd->MacTab.Content[tmpWcid].ValidAsDls== TRUE)) ++ { ++ pEntry = &pAd->MacTab.Content[tmpWcid]; ++ Rate = pAd->MacTab.Content[tmpWcid].CurrTxRate; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID); ++ Rate = pAd->CommonCfg.TxRate; ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ if (*pSrcBufVA & 0x01) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID); ++ pEntry = &pAd->MacTab.Content[MCAST_WCID]; ++ } ++ else ++ { ++ pEntry = MacTableLookup(pAd, pSrcBufVA); ++ } ++ Rate = pAd->CommonCfg.TxRate; ++ } ++ } ++ ++ if (!pEntry) ++ { ++ DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA))); ++ // Resourece is low, system did not allocate virtual address ++ // return NDIS_STATUS_FAILURE directly to upper layer ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ if (ADHOC_ON(pAd) ++ ) ++ { ++ RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid); ++ } ++ ++ // ++ // Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags. ++ // Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL). ++ RTMPCheckEtherType(pAd, pPacket); ++ ++ ++ ++ // ++ // WPA 802.1x secured port control - drop all non-802.1x frame before port secured ++ // ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef WPA_SUPPLICANT_SUPPORT ++ || (pAd->StaCfg.IEEE8021X == TRUE) ++#endif // WPA_SUPPLICANT_SUPPORT // ++#ifdef LEAP_SUPPORT ++ || (pAd->StaCfg.LeapAuthMode == CISCO_AuthModeLEAP) ++#endif // LEAP_SUPPORT // ++ ) ++ && ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2)) ++ && (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE) ++ ) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n")); ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ ++ return (NDIS_STATUS_FAILURE); ++ } ++ ++ ++ // STEP 1. Decide number of fragments required to deliver this MSDU. ++ // The estimation here is not very accurate because difficult to ++ // take encryption overhead into consideration here. The result ++ // "NumberOfFrag" is then just used to pre-check if enough free ++ // TXD are available to hold this MSDU. ++ ++ ++ if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast ++ NumberOfFrag = 1; ++ else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)) ++ NumberOfFrag = 1; // Aggregation overwhelms fragmentation ++ else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED)) ++ NumberOfFrag = 1; // Aggregation overwhelms fragmentation ++#ifdef DOT11_N_SUPPORT ++ else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD)) ++ NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation ++#endif // DOT11_N_SUPPORT // ++ else ++ { ++ // The calculated "NumberOfFrag" is a rough estimation because of various ++ // encryption/encapsulation overhead not taken into consideration. This number is just ++ // used to make sure enough free TXD are available before fragmentation takes place. ++ // In case the actual required number of fragments of an NDIS packet ++ // excceeds "NumberOfFrag"caculated here and not enough free TXD available, the ++ // last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of ++ // resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should ++ // rarely happen and the penalty is just like a TX RETRY fail. Affordable. ++ ++ AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC; ++ NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1; ++ // To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size ++ if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0) ++ { ++ NumberOfFrag--; ++ } ++ } ++ ++ // Save fragment number to Ndis packet reserved field ++ RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag); ++ ++ ++ // STEP 2. Check the requirement of RTS: ++ // If multiple fragment required, RTS is required only for the first fragment ++ // if the fragment size large than RTS threshold ++ // For RT28xx, Let ASIC send RTS/CTS ++ RTMP_SET_PACKET_RTS(pPacket, 0); ++ RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate); ++ ++ // ++ // STEP 3. Traffic classification. outcome = ++ // ++ UserPriority = 0; ++ QueIdx = QID_AC_BE; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE)) ++ { ++ USHORT Protocol; ++ UCHAR LlcSnapLen = 0, Byte0, Byte1; ++ do ++ { ++ // get Ethernet protocol field ++ Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]); ++ if (Protocol <= 1500) ++ { ++ // get Ethernet protocol field from LLC/SNAP ++ if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) ++ break; ++ ++ Protocol = (USHORT)((Byte0 << 8) + Byte1); ++ LlcSnapLen = 8; ++ } ++ ++ // always AC_BE for non-IP packet ++ if (Protocol != 0x0800) ++ break; ++ ++ // get IP header ++ if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS) ++ break; ++ ++ // return AC_BE if packet is not IPv4 ++ if ((Byte0 & 0xf0) != 0x40) ++ break; ++ ++ FlgIsIP = 1; ++ UserPriority = (Byte1 & 0xe0) >> 5; ++ QueIdx = MapUserPriorityToAccessCategory[UserPriority]; ++ ++ // TODO: have to check ACM bit. apply TSPEC if ACM is ON ++ // TODO: downgrade UP & QueIdx before passing ACM ++ if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx]) ++ { ++ UserPriority = 0; ++ QueIdx = QID_AC_BE; ++ } ++ } while (FALSE); ++ } ++ ++ RTMP_SET_PACKET_UP(pPacket, UserPriority); ++ ++ ++ ++ // Make sure SendTxWait queue resource won't be used by other threads ++ RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); ++ if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE) ++ { ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++#ifdef BLOCK_NET_IF ++ StopNetIfQueue(pAd, QueIdx, pPacket); ++#endif // BLOCK_NET_IF // ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ ++ return NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket)); ++ } ++ RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&& ++ IS_HT_STA(pEntry)) ++ { ++ //PMAC_TABLE_ENTRY pMacEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ if (((pEntry->TXBAbitmap & (1<BADeclineBitmap & (1<PortSecured == WPA_802_1X_PORT_SECURED) ++ // For IOT compatibility, if ++ // 1. It is Ralink chip or ++ // 2. It is OPEN or AES mode, ++ // then BA session can be bulit. ++ && ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) || ++ (pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled)) ++ ) ++ { ++ BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE); ++ } ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed ++ return NDIS_STATUS_SUCCESS; ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ This subroutine will scan through releative ring descriptor to find ++ out avaliable free ring descriptor and compare with request size. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ QueIdx Selected TX Ring ++ ++ Return Value: ++ NDIS_STATUS_FAILURE Not enough free descriptor ++ NDIS_STATUS_SUCCESS Enough free descriptor ++ ++ IRQL = PASSIVE_LEVEL ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++ ++#ifdef RT2870 ++/* ++ Actually, this function used to check if the TxHardware Queue still has frame need to send. ++ If no frame need to send, go to sleep, else, still wake up. ++*/ ++NDIS_STATUS RTMPFreeTXDRequest( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR QueIdx, ++ IN UCHAR NumberRequired, ++ IN PUCHAR FreeNumberIs) ++{ ++ //ULONG FreeNumber = 0; ++ NDIS_STATUS Status = NDIS_STATUS_FAILURE; ++ unsigned long IrqFlags; ++ HT_TX_CONTEXT *pHTTXContext; ++ ++ switch (QueIdx) ++ { ++ case QID_AC_BK: ++ case QID_AC_BE: ++ case QID_AC_VI: ++ case QID_AC_VO: ++ case QID_HCCA: ++ { ++ pHTTXContext = &pAd->TxContext[QueIdx]; ++ RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) || ++ (pHTTXContext->IRPPending == TRUE)) ++ { ++ Status = NDIS_STATUS_FAILURE; ++ } ++ else ++ { ++ Status = NDIS_STATUS_SUCCESS; ++ } ++ RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags); ++ } ++ break; ++ ++ case QID_MGMT: ++ if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE) ++ Status = NDIS_STATUS_FAILURE; ++ else ++ Status = NDIS_STATUS_SUCCESS; ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx)); ++ break; ++ } ++ ++ return (Status); ++ ++} ++#endif // RT2870 // ++ ++ ++VOID RTMPSendDisassociationFrame( ++ IN PRTMP_ADAPTER pAd) ++{ ++} ++ ++VOID RTMPSendNullFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN UCHAR TxRate, ++ IN BOOLEAN bQosNull) ++{ ++ UCHAR NullFrame[48]; ++ ULONG Length; ++ PHEADER_802_11 pHeader_802_11; ++ ++ ++#ifdef RALINK_ATE ++ if(ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ // WPA 802.1x secured port control ++ if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || ++ (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++#ifdef WPA_SUPPLICANT_SUPPORT ++ || (pAd->StaCfg.IEEE8021X == TRUE) ++#endif ++ ) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ { ++ return; ++ } ++ ++ NdisZeroMemory(NullFrame, 48); ++ Length = sizeof(HEADER_802_11); ++ ++ pHeader_802_11 = (PHEADER_802_11) NullFrame; ++ ++ pHeader_802_11->FC.Type = BTYPE_DATA; ++ pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC; ++ pHeader_802_11->FC.ToDs = 1; ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ { ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ } ++ else ++ { ++ pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0; ++ } ++ pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14); ++ ++ pAd->Sequence++; ++ pHeader_802_11->Sequence = pAd->Sequence; ++ ++ // Prepare QosNull function frame ++ if (bQosNull) ++ { ++ pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL; ++ ++ // copy QOS control bytes ++ NullFrame[Length] = 0; ++ NullFrame[Length+1] = 0; ++ Length += 2;// if pad with 2 bytes for alignment, APSD will fail ++ } ++ ++ HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length); ++ ++} ++ ++// IRQL = DISPATCH_LEVEL ++VOID RTMPSendRTSFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pDA, ++ IN unsigned int NextMpduSize, ++ IN UCHAR TxRate, ++ IN UCHAR RTSRate, ++ IN USHORT AckDuration, ++ IN UCHAR QueIdx, ++ IN UCHAR FrameGap) ++{ ++} ++ ++ ++ ++// -------------------------------------------------------- ++// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM ++// Find the WPA key, either Group or Pairwise Key ++// LEAP + TKIP also use WPA key. ++// -------------------------------------------------------- ++// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst ++// In Cisco CCX 2.0 Leap Authentication ++// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey ++// Instead of the SharedKey, SharedKey Length may be Zero. ++VOID STAFindCipherAlgorithm( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet ++ UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm ++ UCHAR KeyIdx = 0xff; ++ PUCHAR pSrcBufVA; ++ PCIPHER_KEY pKey = NULL; ++ ++ pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket); ++ ++ { ++ // Select Cipher ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) ++ Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast ++ else ++ Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast ++ ++ if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) ++ { ++ ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128); ++ ++ // 4-way handshaking frame must be clear ++ if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) && ++ (pAd->SharedKey[BSS0][0].KeyLen)) ++ { ++ CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ KeyIdx = 0; ++ } ++ } ++ else if (Cipher == Ndis802_11Encryption1Enabled) ++ { ++#ifdef LEAP_SUPPORT ++ if (pAd->StaCfg.CkipFlag & 0x10) // Cisco CKIP KP is on ++ { ++ if (LEAP_CCKM_ON(pAd)) ++ { ++ if (((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))) ++ KeyIdx = 1; ++ else ++ KeyIdx = 0; ++ } ++ else ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ else if (pAd->StaCfg.CkipFlag & 0x08) // only CKIP CMIC ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ else if (LEAP_CCKM_ON(pAd)) ++ { ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) ++ KeyIdx = 1; ++ else ++ KeyIdx = 0; ++ } ++ else // standard WEP64 or WEP128 ++#endif // LEAP_SUPPORT // ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ else if ((Cipher == Ndis802_11Encryption2Enabled) || ++ (Cipher == Ndis802_11Encryption3Enabled)) ++ { ++ if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ else if (pAd->SharedKey[BSS0][0].KeyLen) ++ KeyIdx = 0; ++ else ++ KeyIdx = pAd->StaCfg.DefaultKeyId; ++ } ++ ++ if (KeyIdx == 0xff) ++ CipherAlg = CIPHER_NONE; ++ else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0)) ++ CipherAlg = CIPHER_NONE; ++#ifdef WPA_SUPPLICANT_SUPPORT ++ else if ( pAd->StaCfg.WpaSupplicantUP && ++ (Cipher == Ndis802_11Encryption1Enabled) && ++ (pAd->StaCfg.IEEE8021X == TRUE) && ++ (pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED)) ++ CipherAlg = CIPHER_NONE; ++#endif // WPA_SUPPLICANT_SUPPORT // ++ else ++ { ++ //Header_802_11.FC.Wep = 1; ++ CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg; ++ pKey = &pAd->SharedKey[BSS0][KeyIdx]; ++ } ++ } ++ ++ pTxBlk->CipherAlg = CipherAlg; ++ pTxBlk->pKey = pKey; ++} ++ ++ ++VOID STABuildCommon802_11Header( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ ++ HEADER_802_11 *pHeader_802_11; ++#ifdef QOS_DLS_SUPPORT ++ BOOLEAN bDLSFrame = FALSE; ++ INT DlsEntryIndex = 0; ++#endif // QOS_DLS_SUPPORT // ++ ++ // ++ // MAKE A COMMON 802.11 HEADER ++ // ++ ++ // normal wlan header size : 24 octets ++ pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); ++ ++ pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ ++ NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11)); ++ ++ pHeader_802_11->FC.FrDs = 0; ++ pHeader_802_11->FC.Type = BTYPE_DATA; ++ pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA); ++ ++#ifdef QOS_DLS_SUPPORT ++ if (INFRA_ON(pAd)) ++ { ++ // Check if the frame can be sent through DLS direct link interface ++ // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) ++ DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); ++ if (DlsEntryIndex >= 0) ++ bDLSFrame = TRUE; ++ else ++ bDLSFrame = FALSE; ++ } ++#endif // QOS_DLS_SUPPORT // ++ ++ if (pTxBlk->pMacEntry) ++ { ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS)) ++ { ++ pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq; ++ pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ; ++ } ++ else ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ pHeader_802_11->Sequence = pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence; ++ pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence = (pAd->StaCfg.DLSEntry[DlsEntryIndex].Sequence+1) & MAXSEQ; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]; ++ pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; ++ } ++ } ++ } ++ else ++ { ++ pHeader_802_11->Sequence = pAd->Sequence; ++ pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence ++ } ++ ++ pHeader_802_11->Frag = 0; ++ ++ pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); ++ ++ { ++ if (INFRA_ON(pAd)) ++ { ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ pHeader_802_11->FC.ToDs = 0; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader); ++ pHeader_802_11->FC.ToDs = 1; ++ } ++ } ++ else if (ADHOC_ON(pAd)) ++ { ++ COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid); ++ pHeader_802_11->FC.ToDs = 0; ++ } ++ } ++ ++ if (pTxBlk->CipherAlg != CIPHER_NONE) ++ pHeader_802_11->FC.Wep = 1; ++ ++ // ----------------------------------------------------------------- ++ // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. ++ // ----------------------------------------------------------------- ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ pHeader_802_11->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++} ++ ++#ifdef DOT11_N_SUPPORT ++VOID STABuildCache802_11Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR *pHeader) ++{ ++ MAC_TABLE_ENTRY *pMacEntry; ++ PHEADER_802_11 pHeader80211; ++ ++ pHeader80211 = (PHEADER_802_11)pHeader; ++ pMacEntry = pTxBlk->pMacEntry; ++ ++ // ++ // Update the cached 802.11 HEADER ++ // ++ ++ // normal wlan header size : 24 octets ++ pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11); ++ ++ // More Bit ++ pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData); ++ ++ // Sequence ++ pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority]; ++ pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ; ++ ++ { ++ // Check if the frame can be sent through DLS direct link interface ++ // If packet can be sent through DLS, then force aggregation disable. (Hard to determine peer STA's capability) ++#ifdef QOS_DLS_SUPPORT ++ BOOLEAN bDLSFrame = FALSE; ++ INT DlsEntryIndex = 0; ++ ++ DlsEntryIndex = RTMPCheckDLSFrame(pAd, pTxBlk->pSrcBufHeader); ++ if (DlsEntryIndex >= 0) ++ bDLSFrame = TRUE; ++ else ++ bDLSFrame = FALSE; ++#endif // QOS_DLS_SUPPORT // ++ ++ // The addr3 of normal packet send from DS is Dest Mac address. ++#ifdef QOS_DLS_SUPPORT ++ if (bDLSFrame) ++ { ++ COPY_MAC_ADDR(pHeader80211->Addr1, pTxBlk->pSrcBufHeader); ++ COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); ++ pHeader80211->FC.ToDs = 0; ++ } ++ else ++#endif // QOS_DLS_SUPPORT // ++ if (ADHOC_ON(pAd)) ++ COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid); ++ else ++ COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader); ++ } ++ ++ // ----------------------------------------------------------------- ++ // STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later. ++ // ----------------------------------------------------------------- ++ if (pAd->CommonCfg.bAPSDForcePowerSave) ++ pHeader80211->FC.PwrMgmt = PWR_SAVE; ++ else ++ pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE); ++} ++#endif // DOT11_N_SUPPORT // ++ ++static inline PUCHAR STA_Build_ARalink_Frame_Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ HEADER_802_11 *pHeader_802_11; ++ PNDIS_PACKET pNextPacket; ++ UINT32 nextBufLen; ++ PQUEUE_ENTRY pQEntry; ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // steal "order" bit to mark "aggregation" ++ pHeader_802_11->FC.Order = 1; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // padding at front of LLC header. LLC header should at 4-bytes aligment. ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ // For RA Aggregation, ++ // put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format ++ pQEntry = pTxBlk->TxPacketList.Head; ++ pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry); ++ nextBufLen = GET_OS_PKT_LEN(pNextPacket); ++ if (RTMP_GET_PACKET_VLAN(pNextPacket)) ++ nextBufLen -= LENGTH_802_1Q; ++ ++ *pHeaderBufPtr = (UCHAR)nextBufLen & 0xff; ++ *(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8); ++ ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ return pHeaderBufPtr; ++ ++} ++ ++#ifdef DOT11_N_SUPPORT ++static inline PUCHAR STA_Build_AMSDU_Frame_Header( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr;//, pSaveBufPtr; ++ HEADER_802_11 *pHeader_802_11; ++ ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ // ++ // A-MSDU packet ++ // ++ *pHeaderBufPtr |= 0x80; ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ //pSaveBufPtr = pHeaderBufPtr; ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ // @@@ MpduHeaderLen excluding padding @@@ ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ return pHeaderBufPtr; ++ ++} ++ ++ ++VOID STA_AMPDU_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ MAC_TABLE_ENTRY *pMacEntry; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ASSERT(pTxBlk); ++ ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ pMacEntry = pTxBlk->pMacEntry; ++ if (pMacEntry->isCached) ++ { ++ // NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!! ++ NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11)); ++ pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]); ++ STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr); ++ } ++ else ++ { ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ } ++ ++ ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ ++ // ++ // build HTC+ ++ // HTC control filed following QoS field ++ // ++ if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE)) ++ { ++ if (pMacEntry->isCached == FALSE) ++ { ++ // mark HTC bit ++ pHeader_802_11->FC.Order = 1; ++ ++ NdisZeroMemory(pHeaderBufPtr, 4); ++ *(pHeaderBufPtr+3) |= 0x80; ++ } ++ pHeaderBufPtr += 4; ++ pTxBlk->MpduHeaderLen += 4; ++ } ++ ++ //pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE; ++ ASSERT(pTxBlk->MpduHeaderLen >= 24); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ // @@@ MpduHeaderLen excluding padding @@@ ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ { ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ } ++ ++ if (pMacEntry->isCached) ++ { ++ RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ } ++ else ++ { ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf)); ++ NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]))); ++ pMacEntry->isCached = TRUE; ++ } ++ ++ // calculate Transmitted AMPDU count and ByteCount ++ { ++ pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++; ++ pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen; ++ } ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ } ++ ++} ++ ++ ++VOID STA_AMSDU_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding. ++ USHORT totalMPDUSize=0; ++ UCHAR *subFrameHeader; ++ UCHAR padding = 0; ++ USHORT FirstTx = 0, LastTxIdx = 0; ++ BOOLEAN bVLANPkt; ++ int frameNum = 0; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ ASSERT((pTxBlk->TxPacketList.Number > 1)); ++ ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ if (frameNum == 0) ++ { ++ pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk); ++ ++ // NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled. ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ } ++ else ++ { ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; ++ padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen); ++ NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD); ++ pHeaderBufPtr += padding; ++ pTxBlk->MpduHeaderLen = padding; ++ } ++ ++ // ++ // A-MSDU subframe ++ // DA(6)+SA(6)+Length(2) + LLC/SNAP Encap ++ // ++ subFrameHeader = pHeaderBufPtr; ++ subFramePayloadLen = pTxBlk->SrcBufLen; ++ ++ NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12); ++ ++ ++ pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD; ++ pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD; ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ ++ subFramePayloadLen = pTxBlk->SrcBufLen; ++ ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ subFramePayloadLen += LENGTH_802_1_H; ++ } ++ ++ // update subFrame Length field ++ subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8; ++ subFrameHeader[13] = subFramePayloadLen & 0xFF; ++ ++ totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++ if (frameNum ==0) ++ FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ else ++ LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ ++ frameNum++; ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // calculate Transmitted AMSDU Count and ByteCount ++ { ++ pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++; ++ pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize; ++ } ++ ++ } ++ ++ HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); ++ HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++#endif // DOT11_N_SUPPORT // ++ ++VOID STA_Legacy_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ASSERT(pTxBlk); ++ ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ if (pTxBlk->TxFrameType == TX_MCAST_FRAME) ++ { ++ INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount); ++ } ++ ++ if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket)) ++ TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired); ++ else ++ TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired); ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate) ++ pTxBlk->TxRate = pAd->CommonCfg.MinTxRate; ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr; ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // The remaining content of MPDU header should locate at 4-octets aligment ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ { ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ // ++ // if original Ethernet frame contains no LLC/SNAP, ++ // then an extra LLC/SNAP encap is required ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ UCHAR vlan_size; ++ ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // skip vlan tag ++ vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ } ++ ++ // ++ // prepare for TXWI ++ // use Wcid as Key Index ++ // ++ ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ ++ HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++ ++ ++VOID STA_ARalink_Frame_Tx( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ USHORT totalMPDUSize=0; ++ USHORT FirstTx, LastTxIdx; ++ int frameNum = 0; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ ASSERT((pTxBlk->TxPacketList.Number== 2)); ++ ++ ++ FirstTx = LastTxIdx = 0; // Is it ok init they as 0? ++ while(pTxBlk->TxPacketList.Head) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ continue; ++ } ++ ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ if (frameNum == 0) ++ { // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header ++ ++ pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk); ++ ++ // It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount ++ // will be updated after final frame was handled. ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap); ++ ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ } ++ else ++ { // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0. ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[0]; ++ pTxBlk->MpduHeaderLen = 0; ++ ++ // A-Ralink sub-sequent frame header is the same as 802.3 header. ++ // DA(6)+SA(6)+FrameType(2) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12); ++ pHeaderBufPtr += 12; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD; ++ } ++ ++ totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen; ++ ++ //FreeNumber = GET_TXRING_FREENO(pAd, QueIdx); ++ if (frameNum ==0) ++ FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ else ++ LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber); ++ ++ frameNum++; ++ ++ pAd->RalinkCounters.OneSecTxAggregationCount++; ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ } ++ ++ HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx); ++ HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ ++} ++ ++ ++VOID STA_Fragment_Frame_Tx( ++ IN RTMP_ADAPTER *pAd, ++ IN TX_BLK *pTxBlk) ++{ ++ HEADER_802_11 *pHeader_802_11; ++ PUCHAR pHeaderBufPtr; ++ USHORT FreeNumber; ++ UCHAR fragNum = 0; ++ PACKET_INFO PacketInfo; ++ USHORT EncryptionOverhead = 0; ++ UINT32 FreeMpduSize, SrcRemainingBytes; ++ USHORT AckDuration; ++ UINT NextMpduSize; ++ BOOLEAN bVLANPkt; ++ PQUEUE_ENTRY pQEntry; ++ ++ ++ ASSERT(pTxBlk); ++ ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE) ++ { ++ RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE); ++ return; ++ } ++ ++ ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag)); ++ bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE); ++ ++ STAFindCipherAlgorithm(pAd, pTxBlk); ++ STABuildCommon802_11Header(pAd, pTxBlk); ++ ++ if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ { ++ pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket); ++ if (pTxBlk->pPacket == NULL) ++ return; ++ RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen); ++ } ++ ++ // skip 802.3 header ++ pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3; ++ pTxBlk->SrcBufLen -= LENGTH_802_3; ++ ++ ++ // skip vlan tag ++ if (bVLANPkt) ++ { ++ pTxBlk->pSrcBufData += LENGTH_802_1Q; ++ pTxBlk->SrcBufLen -= LENGTH_802_1Q; ++ } ++ ++ pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]; ++ pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr; ++ ++ ++ // skip common header ++ pHeaderBufPtr += pTxBlk->MpduHeaderLen; ++ ++ if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ++ { ++ // ++ // build QOS Control bytes ++ // ++ *pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F); ++ ++ *(pHeaderBufPtr+1) = 0; ++ pHeaderBufPtr +=2; ++ pTxBlk->MpduHeaderLen += 2; ++ } ++ ++ // ++ // padding at front of LLC header ++ // LLC header should locate at 4-octets aligment ++ // ++ pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr; ++ pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4); ++ pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen); ++ ++ ++ ++ // ++ // Insert LLC-SNAP encapsulation - 8 octets ++ // ++ // ++ // if original Ethernet frame contains no LLC/SNAP, ++ // then an extra LLC/SNAP encap is required ++ // ++ EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap); ++ if (pTxBlk->pExtraLlcSnapEncap) ++ { ++ UCHAR vlan_size; ++ ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6); ++ pHeaderBufPtr += 6; ++ // skip vlan tag ++ vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0; ++ // get 2 octets (TypeofLen) ++ NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2); ++ pHeaderBufPtr += 2; ++ pTxBlk->MpduHeaderLen += LENGTH_802_1_H; ++ } ++ ++ ++ // If TKIP is used and fragmentation is required. Driver has to ++ // append TKIP MIC at tail of the scatter buffer ++ // MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC ++ if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ { ++ ++ // NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust ++ // to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress. ++ NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8); ++ //skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8); ++ pTxBlk->SrcBufLen += 8; ++ pTxBlk->TotalFrameLen += 8; ++ pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC; ++ } ++ ++ // ++ // calcuate the overhead bytes that encryption algorithm may add. This ++ // affects the calculate of "duration" field ++ // ++ if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128)) ++ EncryptionOverhead = 8; //WEP: IV[4] + ICV[4]; ++ else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC) ++ EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength ++ else if (pTxBlk->CipherAlg == CIPHER_TKIP) ++ EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8] ++ else if (pTxBlk->CipherAlg == CIPHER_AES) ++ EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8] ++ else ++ EncryptionOverhead = 0; ++ ++ // decide how much time an ACK/CTS frame will consume in the air ++ AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14); ++ ++ // Init the total payload length of this frame. ++ SrcRemainingBytes = pTxBlk->SrcBufLen; ++ ++ pTxBlk->TotalFragNum = 0xff; ++ ++ do { ++ ++ FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC; ++ ++ FreeMpduSize -= pTxBlk->MpduHeaderLen; ++ ++ if (SrcRemainingBytes <= FreeMpduSize) ++ { // this is the last or only fragment ++ ++ pTxBlk->SrcBufLen = SrcRemainingBytes; ++ ++ pHeader_802_11->FC.MoreFrag = 0; ++ pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration; ++ ++ // Indicate the lower layer that this's the last fragment. ++ pTxBlk->TotalFragNum = fragNum; ++ } ++ else ++ { // more fragment is required ++ ++ pTxBlk->SrcBufLen = FreeMpduSize; ++ ++ NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold)); ++ pHeader_802_11->FC.MoreFrag = 1; ++ pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead); ++ } ++ ++ if (fragNum == 0) ++ pTxBlk->FrameGap = IFS_HTTXOP; ++ else ++ pTxBlk->FrameGap = IFS_SIFS; ++ ++ RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk); ++ ++ HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber); ++ ++ pAd->RalinkCounters.KickTxCount++; ++ pAd->RalinkCounters.OneSecTxDoneCount++; ++ ++ // Update the frame number, remaining size of the NDIS packet payload. ++ ++ // space for 802.11 header. ++ if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap) ++ pTxBlk->MpduHeaderLen -= LENGTH_802_1_H; ++ ++ fragNum++; ++ SrcRemainingBytes -= pTxBlk->SrcBufLen; ++ pTxBlk->pSrcBufData += pTxBlk->SrcBufLen; ++ ++ pHeader_802_11->Frag++; // increase Frag # ++ ++ }while(SrcRemainingBytes > 0); ++ ++ // ++ // Kick out Tx ++ // ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++} ++ ++ ++#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \ ++ while(_pTxBlk->TxPacketList.Head) \ ++ { \ ++ _pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \ ++ RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \ ++ } ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware encryption before really ++ sent out to air. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to outgoing Ndis frame ++ NumberOfFrag Number of fragment required ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++NDIS_STATUS STAHardTransmit( ++ IN PRTMP_ADAPTER pAd, ++ IN TX_BLK *pTxBlk, ++ IN UCHAR QueIdx) ++{ ++ NDIS_PACKET *pPacket; ++ PQUEUE_ENTRY pQEntry; ++ ++ // --------------------------------------------- ++ // STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION. ++ // --------------------------------------------- ++ // ++ ASSERT(pTxBlk->TxPacketList.Number); ++ if (pTxBlk->TxPacketList.Head == NULL) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number)); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head); ++ ++ // ------------------------------------------------------------------ ++ // STEP 1. WAKE UP PHY ++ // outgoing frame always wakeup PHY to prevent frame lost and ++ // turn off PSM bit to improve performance ++ // ------------------------------------------------------------------ ++ // not to change PSM bit, just send this frame out? ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); ++ AsicForceWakeup(pAd, TRUE); ++ } ++ ++ // It should not change PSM bit, when APSD turn on. ++ if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE)) ++ || (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket)) ++ || (RTMP_GET_PACKET_WAI(pTxBlk->pPacket))) ++ { ++ if ((pAd->StaCfg.Psm == PWR_SAVE) && ++ (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP)) ++ MlmeSetPsmBit(pAd, PWR_ACTIVE); ++ } ++ ++ switch (pTxBlk->TxFrameType) ++ { ++#ifdef DOT11_N_SUPPORT ++ case TX_AMPDU_FRAME: ++ STA_AMPDU_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_AMSDU_FRAME: ++ STA_AMSDU_Frame_Tx(pAd, pTxBlk); ++ break; ++#endif // DOT11_N_SUPPORT // ++ case TX_LEGACY_FRAME: ++ STA_Legacy_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_MCAST_FRAME: ++ STA_Legacy_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_RALINK_FRAME: ++ STA_ARalink_Frame_Tx(pAd, pTxBlk); ++ break; ++ case TX_FRAG_FRAME: ++ STA_Fragment_Frame_Tx(pAd, pTxBlk); ++ break; ++ default: ++ { ++ // It should not happened! ++ DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n")); ++ while(pTxBlk->TxPacketList.Number) ++ { ++ pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList); ++ pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry); ++ if (pPacket) ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++ } ++ break; ++ } ++ ++ return (NDIS_STATUS_SUCCESS); ++ ++} ++ ++ULONG HashBytesPolynomial(UCHAR *value, unsigned int len) ++{ ++ unsigned char *word = value; ++ unsigned int ret = 0; ++ unsigned int i; ++ ++ for(i=0; i < len; i++) ++ { ++ int mod = i % 32; ++ ret ^=(unsigned int) (word[i]) << mod; ++ ret ^=(unsigned int) (word[i]) >> (32 - mod); ++ } ++ return ret; ++} ++ ++VOID Sta_Announce_or_Forward_802_3_Packet( ++ IN PRTMP_ADAPTER pAd, ++ IN PNDIS_PACKET pPacket, ++ IN UCHAR FromWhichBSSID) ++{ ++ if (TRUE ++ ) ++ { ++ announce_802_3_packet(pAd, pPacket); ++ } ++ else ++ { ++ // release packet ++ RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE); ++ } ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/sanity.c +@@ -0,0 +1,420 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sanity.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 add WMM support ++*/ ++#include "../rt_config.h" ++ ++extern UCHAR CISCO_OUI[]; ++ ++extern UCHAR WPA_OUI[]; ++extern UCHAR RSN_OUI[]; ++extern UCHAR WME_INFO_ELEM[]; ++extern UCHAR WME_PARM_ELEM[]; ++extern UCHAR Ccx2QosInfo[]; ++extern UCHAR RALINK_OUI[]; ++extern UCHAR BROADCOM_OUI[]; ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ========================================================================== ++ */ ++BOOLEAN MlmeStartReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen) ++{ ++ MLME_START_REQ_STRUCT *Info; ++ ++ Info = (MLME_START_REQ_STRUCT *)(Msg); ++ ++ if (Info->SsidLen > MAX_LEN_OF_SSID) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqSanity fail - wrong SSID length\n")); ++ return FALSE; ++ } ++ ++ *pSsidLen = Info->SsidLen; ++ NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen); ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerAssocRspSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *pMsg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT USHORT *pCapabilityInfo, ++ OUT USHORT *pStatus, ++ OUT USHORT *pAid, ++ OUT UCHAR SupRate[], ++ OUT UCHAR *pSupRateLen, ++ OUT UCHAR ExtRate[], ++ OUT UCHAR *pExtRateLen, ++ OUT HT_CAPABILITY_IE *pHtCapability, ++ OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE ++ OUT UCHAR *pHtCapabilityLen, ++ OUT UCHAR *pAddHtInfoLen, ++ OUT UCHAR *pNewExtChannelOffset, ++ OUT PEDCA_PARM pEdcaParm, ++ OUT UCHAR *pCkipFlag) ++{ ++ CHAR IeType, *Ptr; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg; ++ PEID_STRUCT pEid; ++ ULONG Length = 0; ++ ++ *pNewExtChannelOffset = 0xff; ++ *pHtCapabilityLen = 0; ++ *pAddHtInfoLen = 0; ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ Ptr = pFrame->Octet; ++ Length += LENGTH_802_11; ++ ++ NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2); ++ Length += 2; ++ NdisMoveMemory(pStatus, &pFrame->Octet[2], 2); ++ Length += 2; ++ *pCkipFlag = 0; ++ *pExtRateLen = 0; ++ pEdcaParm->bValid = FALSE; ++ ++ if (*pStatus != MLME_SUCCESS) ++ return TRUE; ++ ++ NdisMoveMemory(pAid, &pFrame->Octet[4], 2); ++ Length += 2; ++ ++ // Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform ++ *pAid = (*pAid) & 0x3fff; // AID is low 14-bit ++ ++ // -- get supported rates from payload and advance the pointer ++ IeType = pFrame->Octet[6]; ++ *pSupRateLen = pFrame->Octet[7]; ++ if ((IeType != IE_SUPP_RATES) || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity fail - wrong SupportedRates IE\n")); ++ return FALSE; ++ } ++ else ++ NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen); ++ ++ Length = Length + 2 + *pSupRateLen; ++ ++ // many AP implement proprietary IEs in non-standard order, we'd better ++ // tolerate mis-ordered IEs to get best compatibility ++ pEid = (PEID_STRUCT) &pFrame->Octet[8 + (*pSupRateLen)]; ++ ++ // get variable fields from payload and advance the pointer ++ while ((Length + 2 + pEid->Len) <= MsgLen) ++ { ++ switch (pEid->Eid) ++ { ++ case IE_EXT_SUPP_RATES: ++ if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES) ++ { ++ NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len); ++ *pExtRateLen = pEid->Len; ++ } ++ break; ++ ++ case IE_HT_CAP: ++ case IE_HT_CAP2: ++ if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!! ++ { ++ NdisMoveMemory(pHtCapability, pEid->Octet, SIZE_HT_CAP_IE); ++ ++ *(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo)); ++ *(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo)); ++ ++ *pHtCapabilityLen = SIZE_HT_CAP_IE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_HT_CAP. \n")); ++ } ++ ++ break; ++#ifdef DOT11_N_SUPPORT ++ case IE_ADD_HT: ++ case IE_ADD_HT2: ++ if (pEid->Len >= sizeof(ADD_HT_INFO_IE)) ++ { ++ // This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only ++ // copy first sizeof(ADD_HT_INFO_IE) ++ NdisMoveMemory(pAddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE)); ++ ++ *(USHORT *)(&pAddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo2)); ++ *(USHORT *)(&pAddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo3)); ++ ++ *pAddHtInfoLen = SIZE_ADD_HT_INFO_IE; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_ADD_HT. \n")); ++ } ++ ++ break; ++ case IE_SECONDARY_CH_OFFSET: ++ if (pEid->Len == 1) ++ { ++ *pNewExtChannelOffset = pEid->Octet[0]; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n")); ++ } ++#endif // DOT11_N_SUPPORT // ++ break; ++ case IE_AIRONET_CKIP: ++ // 0. Check Aironet IE length, it must be larger or equal to 28 ++ // Cisco's AP VxWork version(will not be supported) used this IE length as 28 ++ // Cisco's AP IOS version used this IE length as 30 ++ if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2)) ++ break; ++ ++ // 1. Copy CKIP flag byte to buffer for process ++ *pCkipFlag = *(pEid->Octet + 8); ++ break; ++ ++ case IE_AIRONET_IPADDRESS: ++ if (pEid->Len != 0x0A) ++ break; ++ ++ // Get Cisco Aironet IP information ++ if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1) ++ NdisMoveMemory(pAd->StaCfg.AironetIPAddress, pEid->Octet + 4, 4); ++ break; ++ ++ // CCX2, WMM use the same IE value ++ // case IE_CCX_V2: ++ case IE_VENDOR_SPECIFIC: ++ // handle WME PARAMTER ELEMENT ++ if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24)) ++ { ++ PUCHAR ptr; ++ int i; ++ ++ // parsing EDCA parameters ++ pEdcaParm->bValid = TRUE; ++ pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10; ++ pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20; ++ pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40; ++ //pEdcaParm->bMoreDataAck = FALSE; // pEid->Octet[0] & 0x80; ++ pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f; ++ pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0; ++ ptr = &pEid->Octet[8]; ++ for (i=0; i<4; i++) ++ { ++ UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX ++ pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM ++ pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN ++ pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin ++ pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax ++ pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us ++ ptr += 4; // point to next AC ++ } ++ } ++ ++ // handle CCX IE ++ else ++ { ++ // 0. Check the size and CCX admin control ++ if (pAd->StaCfg.CCXControl.field.Enable == 0) ++ break; ++ if (pEid->Len != 5) ++ break; ++ ++ // Turn CCX2 if matched ++ if (NdisEqualMemory(pEid->Octet, Ccx2IeInfo, 5) == 1) ++ pAd->StaCfg.CCXEnable = TRUE; ++ break; ++ } ++ break; ++ ++ default: ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity - ignore unrecognized EID = %d\n", pEid->Eid)); ++ break; ++ } ++ ++ Length = Length + 2 + pEid->Len; ++ pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); ++ } ++ ++ // Force CCX2 enable to TRUE for those AP didn't replay CCX v2 IE, we still force it to be on ++ if (pAd->StaCfg.CCXControl.field.Enable == 1) ++ pAd->StaCfg.CCXEnable = TRUE; ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME message sanity check ++ Return: ++ TRUE if all parameters are OK, FALSE otherwise ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN PeerProbeReqSanity( ++ IN PRTMP_ADAPTER pAd, ++ IN VOID *Msg, ++ IN ULONG MsgLen, ++ OUT PUCHAR pAddr2, ++ OUT CHAR Ssid[], ++ OUT UCHAR *pSsidLen) ++{ ++ UCHAR Idx; ++ UCHAR RateLen; ++ CHAR IeType; ++ PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; ++ ++ COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2); ++ ++ if ((pFrame->Octet[0] != IE_SSID) || (pFrame->Octet[1] > MAX_LEN_OF_SSID)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",pFrame->Octet[0],pFrame->Octet[1])); ++ return FALSE; ++ } ++ ++ *pSsidLen = pFrame->Octet[1]; ++ NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen); ++ ++ Idx = *pSsidLen + 2; ++ ++ // -- get supported rates from payload and advance the pointer ++ IeType = pFrame->Octet[Idx]; ++ RateLen = pFrame->Octet[Idx + 1]; ++ if (IeType != IE_SUPP_RATES) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",pFrame->Octet[Idx],pFrame->Octet[Idx+1])); ++ return FALSE; ++ } ++ else ++ { ++ if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8)) ++ return (FALSE); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++BOOLEAN GetTimBit( ++ IN CHAR *Ptr, ++ IN USHORT Aid, ++ OUT UCHAR *TimLen, ++ OUT UCHAR *BcastFlag, ++ OUT UCHAR *DtimCount, ++ OUT UCHAR *DtimPeriod, ++ OUT UCHAR *MessageToMe) ++{ ++ UCHAR BitCntl, N1, N2, MyByte, MyBit; ++ CHAR *IdxPtr; ++ ++ IdxPtr = Ptr; ++ ++ IdxPtr ++; ++ *TimLen = *IdxPtr; ++ ++ // get DTIM Count from TIM element ++ IdxPtr ++; ++ *DtimCount = *IdxPtr; ++ ++ // get DTIM Period from TIM element ++ IdxPtr++; ++ *DtimPeriod = *IdxPtr; ++ ++ // get Bitmap Control from TIM element ++ IdxPtr++; ++ BitCntl = *IdxPtr; ++ ++ if ((*DtimCount == 0) && (BitCntl & 0x01)) ++ *BcastFlag = TRUE; ++ else ++ *BcastFlag = FALSE; ++ ++ // Parse Partial Virtual Bitmap from TIM element ++ N1 = BitCntl & 0xfe; // N1 is the first bitmap byte# ++ N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte# ++ ++ if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3))) ++ *MessageToMe = FALSE; ++ else ++ { ++ MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream ++ MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0); ++ ++ IdxPtr += (MyByte + 1); ++ ++ //if (*IdxPtr) ++ // DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr)); ++ ++ if (*IdxPtr & (0x01 << MyBit)) ++ *MessageToMe = TRUE; ++ else ++ *MessageToMe = FALSE; ++ } ++ ++ return TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/sync.c +@@ -0,0 +1,1755 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ sync.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ John Chang 2004-09-01 modified for rt2561/2661 ++ Jan Lee 2006-08-01 modified for rt2860 for 802.11n ++*/ ++#include "../rt_config.h" ++ ++#define ADHOC_ENTRY_BEACON_LOST_TIME (2*OS_HZ) // 2 sec ++ ++/* ++ ========================================================================== ++ Description: ++ The sync state machine, ++ Parameters: ++ Sm - pointer to the state machine ++ Note: ++ the state machine looks like the following ++ ++ ========================================================================== ++ */ ++VOID SyncStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *Sm, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(Sm, Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE); ++ ++ // column 1 ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon); ++ StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction); ++ ++ //column 2 ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction); ++ StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction); ++ ++ // column 3 ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction); ++ StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction); ++ ++ // timer init ++ RTMPInitTimer(pAd, &pAd->MlmeAux.BeaconTimer, GET_TIMER_FUNCTION(BeaconTimeout), pAd, FALSE); ++ RTMPInitTimer(pAd, &pAd->MlmeAux.ScanTimer, GET_TIMER_FUNCTION(ScanTimeout), pAd, FALSE); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Beacon timeout handler, executed in timer thread ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID BeaconTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ DBGPRINT(RT_DEBUG_TRACE,("SYNC - BeaconTimeout\n")); ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++#ifdef DOT11_N_SUPPORT ++ if ((pAd->CommonCfg.BBPCurrentBW == BW_40) ++ ) ++ { ++ UCHAR BBPValue = 0; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ BBPValue |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL); ++ RT28XX_MLME_HANDLER(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan timeout handler, executed in timer thread ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID ScanTimeout( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; ++ ++ ++ // Do nothing if the driver is starting halt state. ++ // This might happen when timer already been fired before cancel timer with mlmehalt ++ if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) ++ return; ++ ++ if (MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL)) ++ { ++ RT28XX_MLME_HANDLER(pAd); ++ } ++ else ++ { ++ // To prevent SyncMachine.CurrState is SCAN_LISTEN forever. ++ pAd->MlmeAux.Channel = 0; ++ ScanNextChannel(pAd); ++ if (pAd->CommonCfg.bWirelessEvent) ++ { ++ RTMPSendWirelessEvent(pAd, IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ } ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME SCAN req state machine procedure ++ ========================================================================== ++ */ ++VOID MlmeScanReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType, BBPValue = 0; ++ BOOLEAN TimerCancelled; ++ ULONG Now; ++ USHORT Status; ++ PHEADER_802_11 pHdr80211; ++ PUCHAR pOutBuffer = NULL; ++ NDIS_STATUS NStatus; ++ ++ // Check the total scan tries for one single OID command ++ // If this is the CCX 2.0 Case, skip that! ++ if ( !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeScanReqAction before Startup\n")); ++ return; ++ } ++ ++ // Increase the scan retry counters. ++ pAd->StaCfg.ScanCnt++; ++ ++ ++ // first check the parameter sanity ++ if (MlmeScanReqSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ &BssType, ++ Ssid, ++ &SsidLen, ++ &ScanType)) ++ { ++ ++ // Check for channel load and noise hist request ++ // Suspend MSDU only at scan request, not the last two mentioned ++ if ((ScanType == SCAN_CISCO_NOISE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD)) ++ { ++ if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel) ++ RTMPSuspendMsduTransmission(pAd); // Suspend MSDU transmission here ++ } ++ else ++ { ++ // Suspend MSDU transmission here ++ RTMPSuspendMsduTransmission(pAd); ++ } ++ ++ // ++ // To prevent data lost. ++ // Send an NULL data with turned PSM bit on to current associated AP before SCAN progress. ++ // And should send an NULL data with turned PSM bit off to AP, when scan progress done ++ // ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd))) ++ { ++ NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ pHdr80211 = (PHEADER_802_11) pOutBuffer; ++ MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid); ++ pHdr80211->Duration = 0; ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.PwrMgmt = PWR_SAVE; ++ ++ // Send using priority queue ++ MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11)); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame for off channel RM\n")); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ RTMPusecDelay(5000); ++ } ++ } ++ ++ NdisGetSystemUpTime(&Now); ++ pAd->StaCfg.LastScanTime = Now; ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ ++ // record desired BSS parameters ++ pAd->MlmeAux.BssType = BssType; ++ pAd->MlmeAux.ScanType = ScanType; ++ pAd->MlmeAux.SsidLen = SsidLen; ++ NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ ++ // start from the first channel ++ pAd->MlmeAux.Channel = FirstChannel(pAd); ++ ++ // Change the scan channel when dealing with CCX beacon report ++ if ((ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_ACTIVE) || ++ (ScanType == SCAN_CISCO_CHANNEL_LOAD) || (ScanType == SCAN_CISCO_NOISE)) ++ pAd->MlmeAux.Channel = pAd->StaCfg.CCXScanChannel; ++ ++ // Let BBP register at 20MHz to do scan ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ++ ScanNextChannel(pAd); ++ } ++ else ++ { ++ DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME JOIN req state machine procedure ++ ========================================================================== ++ */ ++VOID MlmeJoinReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR BBPValue = 0; ++ BSS_ENTRY *pBss; ++ BOOLEAN TimerCancelled; ++ HEADER_802_11 Hdr80211; ++ NDIS_STATUS NStatus; ++ ULONG FrameLen = 0; ++ PUCHAR pOutBuffer = NULL; ++ PUCHAR pSupRate = NULL; ++ UCHAR SupRateLen; ++ PUCHAR pExtRate = NULL; ++ UCHAR ExtRateLen; ++ UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C}; ++ UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR); ++ MLME_JOIN_REQ_STRUCT *pInfo = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); ++ ++ ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ pBss = &pAd->MlmeAux.SsidBssTab.BssEntry[pInfo->BssIdx]; ++ ++ // record the desired SSID & BSSID we're waiting for ++ COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pBss->Bssid); ++ ++ // If AP's SSID is not hidden, it is OK for updating ssid to MlmeAux again. ++ if (pBss->Hidden == 0) ++ { ++ NdisMoveMemory(pAd->MlmeAux.Ssid, pBss->Ssid, pBss->SsidLen); ++ pAd->MlmeAux.SsidLen = pBss->SsidLen; ++ } ++ ++ pAd->MlmeAux.BssType = pBss->BssType; ++ pAd->MlmeAux.Channel = pBss->Channel; ++ pAd->MlmeAux.CentralChannel = pBss->CentralChannel; ++ ++#ifdef EXT_BUILD_CHANNEL_LIST ++ // Country IE of the AP will be evaluated and will be used. ++ if ((pAd->StaCfg.IEEE80211dClientMode != Rt802_11_D_None) && ++ (pBss->bHasCountryIE == TRUE)) ++ { ++ NdisMoveMemory(&pAd->CommonCfg.CountryCode[0], &pBss->CountryString[0], 2); ++ if (pBss->CountryString[2] == 'I') ++ pAd->CommonCfg.Geography = IDOR; ++ else if (pBss->CountryString[2] == 'O') ++ pAd->CommonCfg.Geography = ODOR; ++ else ++ pAd->CommonCfg.Geography = BOTH; ++ BuildChannelListEx(pAd); ++ } ++#endif // EXT_BUILD_CHANNEL_LIST // ++ ++ // Let BBP register at 20MHz to do scan ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue); ++ BBPValue &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n")); ++ ++ // switch channel and waiting for beacon timer ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ RTMPSetTimer(&pAd->MlmeAux.BeaconTimer, JOIN_TIMEOUT); ++ ++ do ++ { ++ if (((pAd->CommonCfg.bIEEE80211H == 1) && ++ (pAd->MlmeAux.Channel > 14) && ++ RadarChannelCheck(pAd, pAd->MlmeAux.Channel)) ++#ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier ++ || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) ++#endif // CARRIER_DETECTION_SUPPORT // ++ ) ++ { ++ // ++ // We can't send any Probe request frame to meet 802.11h. ++ // ++ if (pBss->Hidden == 0) ++ break; ++ } ++ ++ // ++ // send probe request ++ // ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); ++ if (NStatus == NDIS_STATUS_SUCCESS) ++ { ++ if (pAd->MlmeAux.Channel <= 14) ++ { ++ pSupRate = pAd->CommonCfg.SupRate; ++ SupRateLen = pAd->CommonCfg.SupRateLen; ++ pExtRate = pAd->CommonCfg.ExtRate; ++ ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ } ++ else ++ { ++ // ++ // Overwrite Support Rate, CCK rate are not allowed ++ // ++ pSupRate = ASupRate; ++ SupRateLen = ASupRateLen; ++ ExtRateLen = 0; ++ } ++ ++ if (pAd->MlmeAux.BssType == BSS_INFRA) ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, pAd->MlmeAux.Bssid, pAd->MlmeAux.Bssid); ++ else ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &pAd->MlmeAux.SsidLen, ++ pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid, ++ 1, &SupRateIe, ++ 1, &SupRateLen, ++ SupRateLen, pSupRate, ++ END_OF_ARGS); ++ ++ if (ExtRateLen) ++ { ++ ULONG Tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp, ++ 1, &ExtRateIe, ++ 1, &ExtRateLen, ++ ExtRateLen, pExtRate, ++ END_OF_ARGS); ++ FrameLen += Tmp; ++ } ++ ++ ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } while (FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Switch to ch %d, Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5])); ++ ++ pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ MLME START Request state machine procedure, starting an IBSS ++ ========================================================================== ++ */ ++VOID MlmeStartReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen; ++ BOOLEAN TimerCancelled; ++ ++ // New for WPA security suites ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ LARGE_INTEGER TimeStamp; ++ BOOLEAN Privacy; ++ USHORT Status; ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ TimeStamp.u.LowPart = 0; ++ TimeStamp.u.HighPart = 0; ++ ++ if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen)) ++ { ++ // reset all the timers ++ RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ // ++ // Start a new IBSS. All IBSS parameters are decided now.... ++ // ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - Start a new IBSS. All IBSS parameters are decided now.... \n")); ++ pAd->MlmeAux.BssType = BSS_ADHOC; ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ pAd->MlmeAux.SsidLen = SsidLen; ++ ++ // generate a radom number as BSSID ++ MacAddrRandomBssid(pAd, pAd->MlmeAux.Bssid); ++ DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - generate a radom number as BSSID \n")); ++ ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ pAd->MlmeAux.CapabilityInfo = CAP_GENERATE(0,1,Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 1, 0); ++ pAd->MlmeAux.BeaconPeriod = pAd->CommonCfg.BeaconPeriod; ++ pAd->MlmeAux.AtimWin = pAd->StaCfg.AtimWin; ++ pAd->MlmeAux.Channel = pAd->CommonCfg.Channel; ++ ++ pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; ++ pAd->MlmeAux.CentralChannel = pAd->CommonCfg.CentralChannel; ++ ++ pAd->MlmeAux.SupRateLen= pAd->CommonCfg.SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo); ++ pAd->MlmeAux.HtCapabilityLen = sizeof(HT_CAPABILITY_IE); ++ // Not turn pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE here. ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n")); ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ pAd->MlmeAux.HtCapabilityLen = 0; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ } ++ // temporarily not support QOS in IBSS ++ NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ ++ AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->MlmeAux.Channel); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeStartReqAction(ch= %d,sup rates= %d, ext rates=%d)\n", ++ pAd->MlmeAux.Channel, pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++ } ++ else ++ { ++ DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_INVALID_FORMAT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++ } ++} ++ ++/* ++ ========================================================================== ++ Description: ++ peer sends beacon back when scanning ++ ========================================================================== ++ */ ++VOID PeerBeaconAtScanAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, NewChannel, ++ SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe; ++ CF_PARM CfParm; ++ USHORT BeaconPeriod, AtimWin, CapabilityInfo; ++ PFRAME_802_11 pFrame; ++ LARGE_INTEGER TimeStamp; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ USHORT LenVIE; ++ UCHAR CkipFlag; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ ULONG RalinkIe; ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ ++ // NdisFillMemory(Ssid, MAX_LEN_OF_SSID, 0x00); ++ pFrame = (PFRAME_802_11) Elem->Msg; ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++#ifdef DOT11_N_SUPPORT ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++#endif // DOT11_N_SUPPORT // ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &CfParm, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ ULONG Idx; ++ CHAR Rssi = 0; ++ ++ Idx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Idx != BSS_NOT_FOUND) ++ Rssi = pAd->ScanTab.BssEntry[Idx].Rssi; ++ ++ Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ ++#ifdef DOT11_N_SUPPORT ++ if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) ++ HtCapabilityLen = SIZE_HT_CAP_IE; ++#endif // DOT11_N_SUPPORT // ++ if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel)) ++ { ++ Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen,ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++ if (Idx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(pAd->StaCfg.CCXBssTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ if (pAd->StaCfg.CCXReqType == MSRN_TYPE_BEACON_REQ) ++ AironetAddBeaconReport(pAd, Idx, Elem); ++ } ++ } ++ else ++ { ++ Idx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++ if (pAd->ChannelList[pAd->CommonCfg.ChannelListIdx].bEffectedChannel == TRUE) ++ { ++ UCHAR RegClass; ++ PeerBeaconAndProbeRspSanity2(pAd, Elem->Msg, Elem->MsgLen, &RegClass); ++ TriEventTableSetEntry(pAd, &pAd->CommonCfg.TriggerEventTab, Bssid, &HtCapability, HtCapabilityLen, RegClass, Channel); ++ } ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ if (Idx != BSS_NOT_FOUND) ++ { ++ NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ } ++ } ++ } ++ // sanity check fail, ignored ++} ++ ++/* ++ ========================================================================== ++ Description: ++ When waiting joining the (I)BSS, beacon received from external ++ ========================================================================== ++ */ ++VOID PeerBeaconAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, MessageToMe, ++ DtimCount, DtimPeriod, BcastFlag, NewChannel; ++ LARGE_INTEGER TimeStamp; ++ USHORT BeaconPeriod, AtimWin, CapabilityInfo; ++ CF_PARM Cf; ++ BOOLEAN TimerCancelled; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ UCHAR CkipFlag; ++ USHORT LenVIE; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ USHORT Status; ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ ULONG RalinkIe; ++ ULONG Idx; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++#ifdef DOT11_N_SUPPORT ++ UCHAR CentralChannel; ++#endif // DOT11_N_SUPPORT // ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &Cf, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ // Disqualify 11b only adhoc when we are in 11g only adhoc mode ++ if ((BssType == BSS_ADHOC) && (pAd->CommonCfg.PhyMode == PHY_11G) && ((SupRateLen+ExtRateLen)< 12)) ++ return; ++ ++ // BEACON from desired BSS/IBSS found. We should be able to decide most ++ // BSS parameters here. ++ // Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION? ++ // Do we need to receover back all parameters belonging to previous BSS? ++ // A. Should be not. There's no back-door recover to previous AP. It still need ++ // a new JOIN-AUTH-ASSOC sequence. ++ if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - receive desired BEACON at JoinWaitBeacon... Channel = %d\n", Channel)); ++ RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled); ++ ++ // Update RSSI to prevent No signal display when cards first initialized ++ pAd->StaCfg.RssiSample.LastRssi0 = ConvertToRssi(pAd, Elem->Rssi0, RSSI_0); ++ pAd->StaCfg.RssiSample.LastRssi1 = ConvertToRssi(pAd, Elem->Rssi1, RSSI_1); ++ pAd->StaCfg.RssiSample.LastRssi2 = ConvertToRssi(pAd, Elem->Rssi2, RSSI_2); ++ pAd->StaCfg.RssiSample.AvgRssi0 = pAd->StaCfg.RssiSample.LastRssi0; ++ pAd->StaCfg.RssiSample.AvgRssi0X8 = pAd->StaCfg.RssiSample.AvgRssi0 << 3; ++ pAd->StaCfg.RssiSample.AvgRssi1 = pAd->StaCfg.RssiSample.LastRssi1; ++ pAd->StaCfg.RssiSample.AvgRssi1X8 = pAd->StaCfg.RssiSample.AvgRssi1 << 3; ++ pAd->StaCfg.RssiSample.AvgRssi2 = pAd->StaCfg.RssiSample.LastRssi2; ++ pAd->StaCfg.RssiSample.AvgRssi2X8 = pAd->StaCfg.RssiSample.AvgRssi2 << 3; ++ ++ // ++ // We need to check if SSID only set to any, then we can record the current SSID. ++ // Otherwise will cause hidden SSID association failed. ++ // ++ if (pAd->MlmeAux.SsidLen == 0) ++ { ++ NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen); ++ pAd->MlmeAux.SsidLen = SsidLen; ++ } ++ else ++ { ++ Idx = BssSsidTableSearch(&pAd->ScanTab, Bssid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Channel); ++ ++ if (Idx != BSS_NOT_FOUND) ++ { ++ // ++ // Multiple SSID case, used correct CapabilityInfo ++ // ++ CapabilityInfo = pAd->ScanTab.BssEntry[Idx].CapabilityInfo; ++ } ++ } ++ NdisMoveMemory(pAd->MlmeAux.Bssid, Bssid, MAC_ADDR_LEN); ++ pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO; ++ pAd->MlmeAux.BssType = BssType; ++ pAd->MlmeAux.BeaconPeriod = BeaconPeriod; ++ pAd->MlmeAux.Channel = Channel; ++ pAd->MlmeAux.AtimWin = AtimWin; ++ pAd->MlmeAux.CfpPeriod = Cf.CfpPeriod; ++ pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration; ++ pAd->MlmeAux.APRalinkIe = RalinkIe; ++ ++ // Copy AP's supported rate to MlmeAux for creating assoication request ++ // Also filter out not supported rate ++ pAd->MlmeAux.SupRateLen = SupRateLen; ++ NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen); ++ pAd->MlmeAux.ExtRateLen = ExtRateLen; ++ NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen); ++ RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen); ++ ++ NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16); ++#ifdef DOT11_N_SUPPORT ++ pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; ++ pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen; ++ ++ // filter out un-supported ht rates ++ if (((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)) ++ { ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ ++ // StaActive.SupportedHtPhy.MCSSet stores Peer AP's 11n Rx capability ++ NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16); ++ pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset; ++ pAd->MlmeAux.HtCapabilityLen = SIZE_HT_CAP_IE; ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE; ++ if (PreNHtCapabilityLen > 0) ++ pAd->StaActive.SupportedPhyInfo.bPreNHt = TRUE; ++ RTMPCheckHt(pAd, BSSID_WCID, &HtCapability, &AddHtInfo); ++ // Copy AP Parameter to StaActive. This is also in LinkUp. ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction! (MpduDensity=%d, MaxRAmpduFactor=%d, BW=%d)\n", ++ pAd->StaActive.SupportedHtPhy.MpduDensity, pAd->StaActive.SupportedHtPhy.MaxRAmpduFactor, HtCapability.HtCapInfo.ChannelWidth)); ++ ++ if (AddHtInfoLen > 0) ++ { ++ CentralChannel = AddHtInfo.ControlChan; ++ // Check again the Bandwidth capability of this AP. ++ if ((AddHtInfo.ControlChan > 2)&& (AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ CentralChannel = AddHtInfo.ControlChan - 2; ++ } ++ else if ((AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ CentralChannel = AddHtInfo.ControlChan + 2; ++ } ++ ++ // Check Error . ++ if (pAd->MlmeAux.CentralChannel != CentralChannel) ++ DBGPRINT(RT_DEBUG_ERROR, ("PeerBeaconAtJoinAction HT===>Beacon Central Channel = %d, Control Channel = %d. Mlmeaux CentralChannel = %d\n", CentralChannel, AddHtInfo.ControlChan, pAd->MlmeAux.CentralChannel)); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction HT===>Central Channel = %d, Control Channel = %d, .\n", CentralChannel, AddHtInfo.ControlChan)); ++ ++ } ++ ++ } ++ else ++#endif // DOT11_N_SUPPORT // ++ { ++ // To prevent error, let legacy AP must have same CentralChannel and Channel. ++ if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0)) ++ pAd->MlmeAux.CentralChannel = pAd->MlmeAux.Channel; ++ ++ pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE; ++ RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE); ++ RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE); ++ } ++ ++ RTMPUpdateMlmeRate(pAd); ++ ++ // copy QOS related information ++ if ((pAd->CommonCfg.bWmmCapable) ++#ifdef DOT11_N_SUPPORT ++ || (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++#endif // DOT11_N_SUPPORT // ++ ) ++ { ++ NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM)); ++ NdisMoveMemory(&pAd->MlmeAux.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisMoveMemory(&pAd->MlmeAux.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ else ++ { ++ NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n", ++ pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen)); ++ ++#ifdef LEAP_SUPPORT ++ // Update CkipFlag ++ pAd->StaCfg.CkipFlag = CkipFlag; ++ ++ // Keep TimeStamp for Re-Association used. ++ if (LEAP_CCKM_ON(pAd) && (pAd->StaCfg.CCKMLinkUpFlag == TRUE)) ++ pAd->StaCfg.CCKMBeaconAtJoinTimeStamp = TimeStamp; ++#endif // LEAP_SUPPORT // ++ ++ if (AironetCellPowerLimit != 0xFF) ++ { ++ //We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power ++ ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); ++ } ++ else //Used the default TX Power Percentage. ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_SUCCESS; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++ } ++ // not to me BEACON, ignored ++ } ++ // sanity check fail, ignore this frame ++} ++ ++/* ++ ========================================================================== ++ Description: ++ receive BEACON from peer ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID PeerBeacon( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN]; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ CF_PARM CfParm; ++ UCHAR SsidLen, MessageToMe=0, BssType, Channel, NewChannel, index=0; ++ UCHAR DtimCount=0, DtimPeriod=0, BcastFlag=0; ++ USHORT CapabilityInfo, AtimWin, BeaconPeriod; ++ LARGE_INTEGER TimeStamp; ++ USHORT TbttNumToNextWakeUp; ++ UCHAR Erp; ++ UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES]; ++ UCHAR SupRateLen, ExtRateLen; ++ UCHAR CkipFlag; ++ USHORT LenVIE; ++ UCHAR AironetCellPowerLimit; ++ EDCA_PARM EdcaParm; ++ QBSS_LOAD_PARM QbssLoad; ++ QOS_CAPABILITY_PARM QosCapability; ++ ULONG RalinkIe; ++ // New for WPA security suites ++ UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5 ++ NDIS_802_11_VARIABLE_IEs *pVIE = NULL; ++ HT_CAPABILITY_IE HtCapability; ++ ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE ++ UCHAR HtCapabilityLen, PreNHtCapabilityLen; ++ UCHAR AddHtInfoLen; ++ UCHAR NewExtChannelOffset = 0xff; ++ ++ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ if (!(INFRA_ON(pAd) || ADHOC_ON(pAd) ++ )) ++ return; ++ ++ // Init Variable IE structure ++ pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE; ++ pVIE->Length = 0; ++ RTMPZeroMemory(&HtCapability, sizeof(HtCapability)); ++ RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE)); ++ ++ if (PeerBeaconAndProbeRspSanity(pAd, ++ Elem->Msg, ++ Elem->MsgLen, ++ Elem->Channel, ++ Addr2, ++ Bssid, ++ Ssid, ++ &SsidLen, ++ &BssType, ++ &BeaconPeriod, ++ &Channel, ++ &NewChannel, ++ &TimeStamp, ++ &CfParm, ++ &AtimWin, ++ &CapabilityInfo, ++ &Erp, ++ &DtimCount, ++ &DtimPeriod, ++ &BcastFlag, ++ &MessageToMe, ++ SupRate, ++ &SupRateLen, ++ ExtRate, ++ &ExtRateLen, ++ &CkipFlag, ++ &AironetCellPowerLimit, ++ &EdcaParm, ++ &QbssLoad, ++ &QosCapability, ++ &RalinkIe, ++ &HtCapabilityLen, ++ &PreNHtCapabilityLen, ++ &HtCapability, ++ &AddHtInfoLen, ++ &AddHtInfo, ++ &NewExtChannelOffset, ++ &LenVIE, ++ pVIE)) ++ { ++ BOOLEAN is_my_bssid, is_my_ssid; ++ ULONG Bssidx, Now; ++ BSS_ENTRY *pBss; ++ CHAR RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2)); ++ ++ is_my_bssid = MAC_ADDR_EQUAL(Bssid, pAd->CommonCfg.Bssid)? TRUE : FALSE; ++ is_my_ssid = SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)? TRUE:FALSE; ++ ++ ++ // ignore BEACON not for my SSID ++ if ((! is_my_ssid) && (! is_my_bssid)) ++ return; ++ ++ // It means STA waits disassoc completely from this AP, ignores this beacon. ++ if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC) ++ return; ++ ++#ifdef DOT11_N_SUPPORT ++ // Copy Control channel for this BSSID. ++ if (AddHtInfoLen != 0) ++ Channel = AddHtInfo.ControlChan; ++ ++ if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) ++ HtCapabilityLen = SIZE_HT_CAP_IE; ++#endif // DOT11_N_SUPPORT // ++ ++ // ++ // Housekeeping "SsidBssTab" table for later-on ROAMing usage. ++ // ++ Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ // discover new AP of this network, create BSS entry ++ Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, ++ &HtCapability, &AddHtInfo,HtCapabilityLen,AddHtInfoLen,NewExtChannelOffset, Channel, ++ RealRssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability, ++ &QbssLoad, LenVIE, pVIE); ++ if (Bssidx == BSS_NOT_FOUND) // return if BSS table full ++ return; ++ ++ NdisMoveMemory(pAd->ScanTab.BssEntry[Bssidx].PTSF, &Elem->Msg[24], 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4); ++ NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4); ++ ++ ++ ++ } ++ ++ if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel)) ++ { ++ // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection). ++ // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results. ++ AsicSwitchChannel(pAd, 1, FALSE); ++ AsicLockChannel(pAd, 1); ++ LinkDown(pAd, FALSE); ++ MlmeQueueInit(&pAd->Mlme.Queue); ++ BssTableInit(&pAd->ScanTab); ++ RTMPusecDelay(1000000); // use delay to prevent STA do reassoc ++ ++ // channel sanity check ++ for (index = 0 ; index < pAd->ChannelListNum; index++) ++ { ++ if (pAd->ChannelList[index].Channel == NewChannel) ++ { ++ pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel; ++ pAd->CommonCfg.Channel = NewChannel; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ DBGPRINT(RT_DEBUG_TRACE, ("PeerBeacon - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel)); ++ break; ++ } ++ } ++ ++ if (index >= pAd->ChannelListNum) ++ { ++ DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum)); ++ } ++ } ++ ++ // if the ssid matched & bssid unmatched, we should select the bssid with large value. ++ // This might happened when two STA start at the same time ++ if ((! is_my_bssid) && ADHOC_ON(pAd)) ++ { ++ INT i; ++ ++ // Add the safeguard against the mismatch of adhoc wep status ++ if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Not matched wep status %d %d\n", pAd->StaCfg.WepStatus, pAd->ScanTab.BssEntry[Bssidx].WepStatus)); ++ DBGPRINT(RT_DEBUG_TRACE, ("bssid=%s\n", pAd->ScanTab.BssEntry[Bssidx].Bssid)); ++ return; ++ } ++ ++ // collapse into the ADHOC network which has bigger BSSID value. ++ for (i = 0; i < 6; i++) ++ { ++ if (Bssid[i] > pAd->CommonCfg.Bssid[i]) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - merge to the IBSS with bigger BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", ++ Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5])); ++ AsicDisableSync(pAd); ++ COPY_MAC_ADDR(pAd->CommonCfg.Bssid, Bssid); ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ MakeIbssBeacon(pAd); // re-build BEACON frame ++ AsicEnableIbssSync(pAd); // copy BEACON frame to on-chip memory ++ is_my_bssid = TRUE; ++ break; ++ } ++ else if (Bssid[i] < pAd->CommonCfg.Bssid[i]) ++ break; ++ } ++ } ++ ++ ++ NdisGetSystemUpTime(&Now); ++ pBss = &pAd->ScanTab.BssEntry[Bssidx]; ++ pBss->Rssi = RealRssi; // lastest RSSI ++ pBss->LastBeaconRxTime = Now; // last RX timestamp ++ ++ // ++ // BEACON from my BSSID - either IBSS or INFRA network ++ // ++ if (is_my_bssid) ++ { ++ RXWI_STRUC RxWI; ++ ++ pAd->StaCfg.DtimCount = DtimCount; ++ pAd->StaCfg.DtimPeriod = DtimPeriod; ++ pAd->StaCfg.LastBeaconRxTime = Now; ++ ++ ++ RxWI.RSSI0 = Elem->Rssi0; ++ RxWI.RSSI1 = Elem->Rssi1; ++ RxWI.RSSI2 = Elem->Rssi2; ++ ++ Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, &RxWI); ++ if (AironetCellPowerLimit != 0xFF) ++ { ++ // ++ // We get the Cisco (ccx) "TxPower Limit" required ++ // Changed to appropriate TxPower Limit for Ciso Compatible Extensions ++ // ++ ChangeToCellPowerLimit(pAd, AironetCellPowerLimit); ++ } ++ else ++ { ++ // ++ // AironetCellPowerLimit equal to 0xFF means the Cisco (ccx) "TxPower Limit" not exist. ++ // Used the default TX Power Percentage, that set from UI. ++ // ++ pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault; ++ } ++ ++ if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo))) ++ { ++ UCHAR MaxSupportedRateIn500Kbps = 0; ++ UCHAR idx; ++ MAC_TABLE_ENTRY *pEntry; ++ ++ // supported rates array may not be sorted. sort it and find the maximum rate ++ for (idx=0; idxWcid == RESERVED_WCID)) || ++ (pEntry && ((pEntry->LastBeaconRxTime + ADHOC_ENTRY_BEACON_LOST_TIME) < Now))) ++ { ++ if (pEntry == NULL) ++ // Another adhoc joining, add to our MAC table. ++ pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE); ++ ++ if (StaAddMacTableEntry(pAd, pEntry, MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo) == FALSE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("ADHOC - Add Entry failed.\n")); ++ return; ++ } ++ ++ if (pEntry && ++ (Elem->Wcid == RESERVED_WCID)) ++ { ++ idx = pAd->StaCfg.DefaultKeyId; ++ RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry); ++ } ++ } ++ ++ if (pEntry && pEntry->ValidAsCLI) ++ pEntry->LastBeaconRxTime = Now; ++ ++ // At least another peer in this IBSS, declare MediaState as CONNECTED ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED); ++ ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ RTMP_IndicateMediaState(pAd); ++ pAd->ExtraInfo = GENERAL_LINK_UP; ++ AsicSetBssid(pAd, pAd->CommonCfg.Bssid); ++ ++ // 2003/03/12 - john ++ // Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that ++ // "site survey" result should always include the current connected network. ++ // ++ Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel); ++ if (Bssidx == BSS_NOT_FOUND) ++ { ++ Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod, ++ &CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability, ++ &AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0, ++ &EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE); ++ } ++ DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n")); ++ } ++ } ++ ++ if (INFRA_ON(pAd)) ++ { ++ BOOLEAN bUseShortSlot, bUseBGProtection; ++ ++ // decide to use/change to - ++ // 1. long slot (20 us) or short slot (9 us) time ++ // 2. turn on/off RTS/CTS and/or CTS-to-self protection ++ // 3. short preamble ++ ++ //bUseShortSlot = pAd->CommonCfg.bUseShortSlotTime && CAP_IS_SHORT_SLOT(CapabilityInfo); ++ bUseShortSlot = CAP_IS_SHORT_SLOT(CapabilityInfo); ++ if (bUseShortSlot != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED)) ++ AsicSetSlotTime(pAd, bUseShortSlot); ++ ++ bUseBGProtection = (pAd->CommonCfg.UseBGProtection == 1) || // always use ++ ((pAd->CommonCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp)); ++ ++ if (pAd->CommonCfg.Channel > 14) // always no BG protection in A-band. falsely happened when switching A/G band to a dual-band AP ++ bUseBGProtection = FALSE; ++ ++ if (bUseBGProtection != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED)) ++ { ++ if (bUseBGProtection) ++ { ++ OPSTATUS_SET_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),FALSE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); ++ } ++ else ++ { ++ OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED); ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),TRUE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)); ++ } ++ ++ DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection)); ++ } ++ ++#ifdef DOT11_N_SUPPORT ++ // check Ht protection mode. and adhere to the Non-GF device indication by AP. ++ if ((AddHtInfoLen != 0) && ++ ((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) || ++ (AddHtInfo.AddHtInfo2.NonGfPresent != pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent))) ++ { ++ pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent = AddHtInfo.AddHtInfo2.NonGfPresent; ++ pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode = AddHtInfo.AddHtInfo2.OperaionMode; ++ if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1) ++ { ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE); ++ } ++ else ++ AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode)); ++ } ++#endif // DOT11_N_SUPPORT // ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) && ++ ERP_IS_USE_BARKER_PREAMBLE(Erp)) ++ { ++ MlmeSetTxPreamble(pAd, Rt802_11PreambleLong); ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP forced to use LONG preamble\n")); ++ } ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && ++ (EdcaParm.bValid == TRUE) && ++ (EdcaParm.EdcaUpdateCount != pAd->CommonCfg.APEdcaParm.EdcaUpdateCount)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP change EDCA parameters(from %d to %d)\n", ++ pAd->CommonCfg.APEdcaParm.EdcaUpdateCount, ++ EdcaParm.EdcaUpdateCount)); ++ AsicSetEdcaParm(pAd, &EdcaParm); ++ } ++ ++ // copy QOS related information ++ NdisMoveMemory(&pAd->CommonCfg.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM)); ++ NdisMoveMemory(&pAd->CommonCfg.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM)); ++ } ++ ++ // only INFRASTRUCTURE mode support power-saving feature ++ if ((INFRA_ON(pAd) && (pAd->StaCfg.Psm == PWR_SAVE)) || (pAd->CommonCfg.bAPSDForcePowerSave)) ++ { ++ UCHAR FreeNumber; ++ // 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL ++ // 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE ++ // 3. we have outgoing frames in TxRing or MgmtRing, better stay AWAKE ++ // 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE ++ // 5. otherwise, put PHY back to sleep to save battery. ++ if (MessageToMe) ++ { ++ if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && ++ pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) ++ { ++ pAd->CommonCfg.bNeedSendTriggerFrame = TRUE; ++ } ++ else ++ RT28XX_PS_POLL_ENQUEUE(pAd); ++ } ++ else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) ++ { ++ } ++ else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_BE].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_VI].Number != 0) || ++ (pAd->TxSwQueue[QID_AC_VO].Number != 0) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_BK, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_BE, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_VI, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_AC_VO, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) || ++ (RTMPFreeTXDRequest(pAd, QID_MGMT, MGMT_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS)) ++ { ++ // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme ++ // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? ++ } ++ else ++ { ++ USHORT NextDtim = DtimCount; ++ ++ if (NextDtim == 0) ++ NextDtim = DtimPeriod; ++ ++ TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount; ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim)) ++ TbttNumToNextWakeUp = NextDtim; ++ ++ if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ { ++ AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ } ++ } ++ } ++ } ++ // not my BSSID, ignore it ++ } ++ // sanity check fail, ignore this frame ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Receive PROBE REQ from remote peer when operating in IBSS mode ++ ========================================================================== ++ */ ++VOID PeerProbeReqAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ UCHAR Addr2[MAC_ADDR_LEN]; ++ CHAR Ssid[MAX_LEN_OF_SSID]; ++ UCHAR SsidLen; ++#ifdef DOT11_N_SUPPORT ++ UCHAR HtLen, AddHtLen, NewExtLen; ++#endif // DOT11_N_SUPPORT // ++ HEADER_802_11 ProbeRspHdr; ++ NDIS_STATUS NStatus; ++ PUCHAR pOutBuffer = NULL; ++ ULONG FrameLen = 0; ++ LARGE_INTEGER FakeTimestamp; ++ UCHAR DsLen = 1, IbssLen = 2; ++ UCHAR LocalErpIe[3] = {IE_ERP, 1, 0}; ++ BOOLEAN Privacy; ++ USHORT CapabilityInfo; ++ UCHAR RSNIe = IE_WPA; ++ ++ if (! ADHOC_ON(pAd)) ++ return; ++ ++ if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, Ssid, &SsidLen)) ++ { ++ if ((SsidLen == 0) || SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) ++ { ++ // allocate and send out ProbeRsp frame ++ NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NStatus != NDIS_STATUS_SUCCESS) ++ return; ++ ++ //pAd->StaCfg.AtimWin = 0; // ?????? ++ ++ Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) || ++ (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled); ++ CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &ProbeRspHdr, ++ TIMESTAMP_LEN, &FakeTimestamp, ++ 2, &pAd->CommonCfg.BeaconPeriod, ++ 2, &CapabilityInfo, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->StaActive.SupRateLen, ++ pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, ++ 1, &DsIe, ++ 1, &DsLen, ++ 1, &pAd->CommonCfg.Channel, ++ 1, &IbssIe, ++ 1, &IbssLen, ++ 2, &pAd->StaActive.AtimWin, ++ END_OF_ARGS); ++ ++ if (pAd->StaActive.ExtRateLen) ++ { ++ ULONG tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 3, LocalErpIe, ++ 1, &ExtRateIe, ++ 1, &pAd->StaActive.ExtRateLen, ++ pAd->StaActive.ExtRateLen, &pAd->StaActive.ExtRate, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++ ++ // If adhoc secruity is set for WPA-None, append the cipher suite IE ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone) ++ { ++ ULONG tmp; ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, ++ 1, &RSNIe, ++ 1, &pAd->StaCfg.RSNIE_Len, ++ pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, ++ END_OF_ARGS); ++ FrameLen += tmp; ++ } ++#ifdef DOT11_N_SUPPORT ++ if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) ++ { ++ ULONG TmpLen; ++ UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33}; ++ HtLen = sizeof(pAd->CommonCfg.HtCapability); ++ AddHtLen = sizeof(pAd->CommonCfg.AddHTInfo); ++ NewExtLen = 1; ++ //New extension channel offset IE is included in Beacon, Probe Rsp or channel Switch Announcement Frame ++ if (pAd->bBroadComHT == TRUE) ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &WpaIe, ++ 4, &BROADCOM[0], ++ pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability, ++ END_OF_ARGS); ++ } ++ else ++ { ++ MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen, ++ 1, &HtCapIe, ++ 1, &HtLen, ++ sizeof(HT_CAPABILITY_IE), &pAd->CommonCfg.HtCapability, ++ 1, &AddHtInfoIe, ++ 1, &AddHtLen, ++ sizeof(ADD_HT_INFO_IE), &pAd->CommonCfg.AddHTInfo, ++ 1, &NewExtChanIe, ++ 1, &NewExtLen, ++ sizeof(NEW_EXT_CHAN_IE), &pAd->CommonCfg.NewExtChanOffset, ++ END_OF_ARGS); ++ } ++ FrameLen += TmpLen; ++ } ++#endif // DOT11_N_SUPPORT // ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ } ++} ++ ++VOID BeaconTimeoutAtJoinAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BeaconTimeoutAtJoinAction\n")); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_REJ_TIMEOUT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ Scan timeout procedure. basically add channel index by 1 and rescan ++ ========================================================================== ++ */ ++VOID ScanTimeoutAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ pAd->MlmeAux.Channel = NextChannel(pAd, pAd->MlmeAux.Channel); ++ ++ // Only one channel scanned for CISCO beacon request ++ if ((pAd->MlmeAux.ScanType == SCAN_CISCO_ACTIVE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_PASSIVE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_NOISE) || ++ (pAd->MlmeAux.ScanType == SCAN_CISCO_CHANNEL_LOAD)) ++ pAd->MlmeAux.Channel = 0; ++ ++ // this routine will stop if pAd->MlmeAux.Channel == 0 ++ ScanNextChannel(pAd); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenScan( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("AYNC - InvalidStateWhenScan(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenJoin( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenJoin(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID InvalidStateWhenStart( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ USHORT Status; ++ DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenStart(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState)); ++ pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; ++ Status = MLME_STATE_MACHINE_REJECT; ++ MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ ++ IRQL = DISPATCH_LEVEL ++ ++ ========================================================================== ++ */ ++VOID EnqueuePsPoll( ++ IN PRTMP_ADAPTER pAd) ++{ ++#ifdef RALINK_ATE ++ if (ATE_ON(pAd)) ++ { ++ return; ++ } ++#endif // RALINK_ATE // ++ ++ ++ if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP) ++ pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE; ++ MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME)); ++} ++ ++ ++/* ++ ========================================================================== ++ Description: ++ ========================================================================== ++ */ ++VOID EnqueueProbeRequest( ++ IN PRTMP_ADAPTER pAd) ++{ ++ NDIS_STATUS NState; ++ PUCHAR pOutBuffer; ++ ULONG FrameLen = 0; ++ HEADER_802_11 Hdr80211; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("force out a ProbeRequest ...\n")); ++ ++ NState = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory ++ if (NState == NDIS_STATUS_SUCCESS) ++ { ++ MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR); ++ ++ // this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ sizeof(HEADER_802_11), &Hdr80211, ++ 1, &SsidIe, ++ 1, &pAd->CommonCfg.SsidLen, ++ pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid, ++ 1, &SupRateIe, ++ 1, &pAd->StaActive.SupRateLen, ++ pAd->StaActive.SupRateLen, pAd->StaActive.SupRate, ++ END_OF_ARGS); ++ MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); ++ MlmeFreeMemory(pAd, pOutBuffer); ++ } ++ ++} ++ ++#ifdef DOT11_N_SUPPORT ++#ifdef DOT11N_DRAFT3 ++VOID BuildEffectedChannelList( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR EChannel[11]; ++ UCHAR i, j, k; ++ UCHAR UpperChannel = 0, LowerChannel = 0; ++ ++ RTMPZeroMemory(EChannel, 11); ++ i = 0; ++ // Find upper channel and lower channel. ++ if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) ++ { ++ UpperChannel = pAd->CommonCfg.Channel; ++ LowerChannel = pAd->CommonCfg.CentralChannel; ++ } ++ else if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) ++ { ++ UpperChannel = pAd->CommonCfg.CentralChannel; ++ LowerChannel = pAd->CommonCfg.Channel; ++ } ++ else ++ { ++ return; ++ } ++ ++ // Record channels that is below lower channel.. ++ if (LowerChannel > 1) ++ { ++ EChannel[0] = LowerChannel - 1; ++ i = 1; ++ if (LowerChannel > 2) ++ { ++ EChannel[1] = LowerChannel - 2; ++ i = 2; ++ if (LowerChannel > 3) ++ { ++ EChannel[2] = LowerChannel - 3; ++ i = 3; ++ } ++ } ++ } ++ // Record channels that is between lower channel and upper channel. ++ for (k = LowerChannel;k < UpperChannel;k++) ++ { ++ EChannel[i] = k; ++ i++; ++ } ++ // Record channels that is above upper channel.. ++ if (LowerChannel < 11) ++ { ++ EChannel[i] = UpperChannel + 1; ++ i++; ++ if (LowerChannel < 10) ++ { ++ EChannel[i] = LowerChannel + 2; ++ i++; ++ if (LowerChannel < 9) ++ { ++ EChannel[i] = LowerChannel + 3; ++ i++; ++ } ++ } ++ } ++ // ++ for (j = 0;j < i;j++) ++ { ++ for (k = 0;k < pAd->ChannelListNum;k++) ++ { ++ if (pAd->ChannelList[k].Channel == EChannel[j]) ++ { ++ pAd->ChannelList[k].bEffectedChannel = TRUE; ++ DBGPRINT(RT_DEBUG_TRACE,(" EffectedChannel( =%d)\n", EChannel[j])); ++ break; ++ } ++ } ++ } ++} ++#endif // DOT11N_DRAFT3 // ++#endif // DOT11_N_SUPPORT // ++ ++BOOLEAN ScanRunning( ++ IN PRTMP_ADAPTER pAd) ++{ ++ return (pAd->Mlme.SyncMachine.CurrState == SCAN_LISTEN) ? TRUE : FALSE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/sta/wpa.c +@@ -0,0 +1,2099 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.c ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Jan Lee 03-07-22 Initial ++ Paul Lin 03-11-28 Modify for supplicant ++*/ ++#include "../rt_config.h" ++ ++#define WPARSNIE 0xdd ++#define WPA2RSNIE 0x30 ++ ++//extern UCHAR BIT8[]; ++UCHAR CipherWpaPskTkip[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x02 // authentication ++ }; ++UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); ++ ++UCHAR CipherWpaPskAes[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x04, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x04, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x02 // authentication ++ }; ++UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCiscoCCKM[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x40, 0x96, 0x01, // Multicast ++ 0x01, 0x00, // Number of uicast ++ 0x00, 0x40, 0x96, 0x01, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x40, 0x96, 0x00 // Authentication ++ }; ++UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCiscoCCKM24[] = { ++ 0xDD, 0x18, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x40, 0x96, 0x01, // Multicast ++ 0x01, 0x00, // Number of uicast ++ 0x00, 0x40, 0x96, 0x01, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x40, 0x96, 0x00, ++ 0x28, 0x00// Authentication ++ }; ++ ++UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR)); ++ ++UCHAR CipherSuiteCCXTkip[] = { ++ 0xDD, 0x16, // RSN IE ++ 0x00, 0x50, 0xf2, 0x01, // oui ++ 0x01, 0x00, // Version ++ 0x00, 0x50, 0xf2, 0x02, // Multicast ++ 0x01, 0x00, // Number of unicast ++ 0x00, 0x50, 0xf2, 0x02, // unicast ++ 0x01, 0x00, // number of authentication method ++ 0x00, 0x50, 0xf2, 0x01 // authentication ++ }; ++UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR)); ++ ++UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; ++UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; ++ ++UCHAR EAPOL_FRAME[] = {0x88, 0x8E}; ++ ++BOOLEAN CheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ OUT UCHAR *Offset); ++ ++void inc_byte_array(UCHAR *counter, int len); ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Classify WPA EAP message type ++ ++ Arguments: ++ EAPType Value of EAP message type ++ MsgType Internal Message definition for MLME state machine ++ ++ Return Value: ++ TRUE Found appropriate message type ++ FALSE No appropriate message type ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ All these constants are defined in wpa.h ++ For supplicant, there is only EAPOL Key message avaliable ++ ++ ======================================================================== ++*/ ++BOOLEAN WpaMsgTypeSubst( ++ IN UCHAR EAPType, ++ OUT INT *MsgType) ++{ ++ switch (EAPType) ++ { ++ case EAPPacket: ++ *MsgType = MT2_EAPPacket; ++ break; ++ case EAPOLStart: ++ *MsgType = MT2_EAPOLStart; ++ break; ++ case EAPOLLogoff: ++ *MsgType = MT2_EAPOLLogoff; ++ break; ++ case EAPOLKey: ++ *MsgType = MT2_EAPOLKey; ++ break; ++ case EAPOLASFAlert: ++ *MsgType = MT2_EAPOLASFAlert; ++ break; ++ default: ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/* ++ ========================================================================== ++ Description: ++ association state machine init, including state transition and timer init ++ Parameters: ++ S - pointer to the association state machine ++ ========================================================================== ++ */ ++VOID WpaPskStateMachineInit( ++ IN PRTMP_ADAPTER pAd, ++ IN STATE_MACHINE *S, ++ OUT STATE_MACHINE_FUNC Trans[]) ++{ ++ StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); ++ StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); ++} ++ ++/* ++ ========================================================================== ++ Description: ++ This is state machine function. ++ When receiving EAPOL packets which is for 802.1x key management. ++ Use both in WPA, and WPAPSK case. ++ In this function, further dispatch to different functions according to the received packet. 3 categories are : ++ 1. normal 4-way pairwisekey and 2-way groupkey handshake ++ 2. MIC error (Countermeasures attack) report packet from STA. ++ 3. Request for pairwise/group key update from STA ++ Return: ++ ========================================================================== ++*/ ++VOID WpaEAPOLKeyAction( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ INT MsgType = EAPOL_MSG_INVALID; ++ PKEY_DESCRIPTER pKeyDesc; ++ PHEADER_802_11 pHeader; //red ++ UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; ++ UCHAR EapolVr; ++ KEY_INFO peerKeyInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n")); ++ ++ // Get 802.11 header first ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Get EAPoL-Key Descriptor ++ pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo)); ++ ++ ++ // 1. Check EAPOL frame version and type ++ EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H]; ++ ++ if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC))) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n")); ++ return; ++ } ++ ++ // First validate replay counter, only accept message with larger replay counter ++ // Let equal pass, some AP start with all zero replay counter ++ NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); ++ ++ if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && ++ (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n")); ++ return; ++ } ++ ++ // Process WPA2PSK frame ++ if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.EKD_DL == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 0) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); ++ } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.EKD_DL == 1) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_3; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); ++ } else if((peerKeyInfo.KeyType == GROUPKEY) && ++ (peerKeyInfo.EKD_DL == 1) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_GROUP_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); ++ } ++ ++ // We will assume link is up (assoc suceess and port not secured). ++ // All state has to be able to process message from previous state ++ switch(pAd->StaCfg.WpaState) ++ { ++ case SS_START: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ break; ++ ++ case SS_WAIT_MSG_3: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ Wpa2PairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ break; ++ ++ case SS_WAIT_GROUP: // When doing group key exchange ++ case SS_FINISH: // This happened when update group key ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ Wpa2PairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ Wpa2PairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ else if(MsgType == EAPOL_GROUP_MSG_1) ++ { ++ WpaGroupMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ // Process WPAPSK Frame ++ // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant ++ else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ { ++ if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.KeyIndex == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 0) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); ++ } ++ else if((peerKeyInfo.KeyType == PAIRWISEKEY) && ++ (peerKeyInfo.KeyIndex == 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 0) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_PAIR_MSG_3; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); ++ } ++ else if((peerKeyInfo.KeyType == GROUPKEY) && ++ (peerKeyInfo.KeyIndex != 0) && ++ (peerKeyInfo.KeyAck == 1) && ++ (peerKeyInfo.KeyMic == 1) && ++ (peerKeyInfo.Secure == 1) && ++ (peerKeyInfo.Error == 0) && ++ (peerKeyInfo.Request == 0)) ++ { ++ MsgType = EAPOL_GROUP_MSG_1; ++ DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); ++ } ++ ++ // We will assume link is up (assoc suceess and port not secured). ++ // All state has to be able to process message from previous state ++ switch(pAd->StaCfg.WpaState) ++ { ++ case SS_START: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ break; ++ ++ case SS_WAIT_MSG_3: ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ WpaPairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ } ++ break; ++ ++ case SS_WAIT_GROUP: // When doing group key exchange ++ case SS_FINISH: // This happened when update group key ++ if(MsgType == EAPOL_PAIR_MSG_1) ++ { ++ WpaPairMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_MSG_3; ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ } ++ else if(MsgType == EAPOL_PAIR_MSG_3) ++ { ++ WpaPairMsg3Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_WAIT_GROUP; ++ // Reset port secured variable ++ pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; ++ } ++ else if(MsgType == EAPOL_GROUP_MSG_1) ++ { ++ WpaGroupMsg1Action(pAd, Elem); ++ pAd->StaCfg.WpaState = SS_FINISH; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Pairwise key 4-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaPairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PHEADER_802_11 pHeader; ++ UCHAR *mpool, *PTK, *digest; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ PEAPOL_PACKET pMsg1; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n")); ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); ++ ++ if (mpool == NULL) ++ return; ++ ++ // PTK Len = 80. ++ PTK = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(PTK + 80, 4); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 1 from authenticator ++ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ // 1. Save Replay counter, it will use to verify message 3 and construct message 2 ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Save ANonce ++ NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Generate random SNonce ++ GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); ++ ++ // Calc PTK(ANonce, SNonce) ++ WpaCountPTK(pAd, ++ pAd->StaCfg.PMK, ++ pAd->StaCfg.ANonce, ++ pAd->CommonCfg.Bssid, ++ pAd->StaCfg.SNonce, ++ pAd->CurrentAddress, ++ PTK, ++ LEN_PTK); ++ ++ // Save key to PTK entry ++ NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Message 2 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ // ++ // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ // 1. Key descriptor version and appropriate RSN IE ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ // fill in Data Material and its length ++ Packet.KeyDesc.KeyData[0] = IE_WPA; ++ Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; ++ Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; ++ ++ // Update Key length ++ Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; ++ // 2. Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // 3. KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ //Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ ++ // 4. Fill SNonce ++ NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); ++ ++ // 5. Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE) ++ // Out buffer for transmitting message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, mpool); ++ return; ++ } ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // 6. Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ ++ HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring and send Msg 2 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n")); ++} ++ ++VOID Wpa2PairMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PHEADER_802_11 pHeader; ++ UCHAR *mpool, *PTK, *digest; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ PEAPOL_PACKET pMsg1; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n")); ++ ++ // allocate memory pool ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); ++ ++ if (mpool == NULL) ++ return; ++ ++ // PTK Len = 80. ++ PTK = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(PTK + 80, 4); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 1 from authenticator ++ pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ // 1. Save Replay counter, it will use to verify message 3 and construct message 2 ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Save ANonce ++ NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); ++ ++ // Generate random SNonce ++ GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); ++ ++ if(pMsg1->KeyDesc.KeyDataLen[1] > 0 ) ++ { ++ // cached PMKID ++ } ++ ++ // Calc PTK(ANonce, SNonce) ++ WpaCountPTK(pAd, ++ pAd->StaCfg.PMK, ++ pAd->StaCfg.ANonce, ++ pAd->CommonCfg.Bssid, ++ pAd->StaCfg.SNonce, ++ pAd->CurrentAddress, ++ PTK, ++ LEN_PTK); ++ ++ // Save key to PTK entry ++ NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message 2 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ // ++ // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ ++ // 1. Key descriptor version and appropriate RSN IE ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ // fill in Data Material and its length ++ Packet.KeyDesc.KeyData[0] = IE_WPA2; ++ Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; ++ Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; ++ NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; ++ ++ // 2. Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // 3. KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = 0; ++ Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; ++ ++ // 4. Fill SNonce ++ NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); ++ ++ // 5. Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) ++ // Out buffer for transmitting message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // 6. Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ ++ // Make Transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, pOutBuffer); ++ os_free_mem(pAd, mpool); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n")); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Pairwise key 4-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaPairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PHEADER_802_11 pHeader; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pMsg3; ++ UCHAR Mic[16], OldMic[16]; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ UCHAR skip_offset; ++ KEY_INFO peerKeyInfo; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n")); ++ ++ // Record 802.11 header & the received EAPOL packet Msg3 ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ ++ // 1. Verify cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) ++ { ++ return; ++ } ++ else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ return; ++ } ++ ++ // Verify RSN IE ++ //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) ++ if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n")); ++ hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); ++ hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n")); ++ ++ ++ // 2. Check MIC value ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ UCHAR digest[80]; ++ ++ HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else // TKIP ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ ++ // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ return; ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 4. Double check ANonce ++ if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) ++ return; ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Message 4 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) ++ // ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; ++ ++ // Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS ++ // Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3 ++ Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting message 4 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ return; ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ UCHAR digest[80]; ++ ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ // Update PTK ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ // Make transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // Copy frame to Tx ring and Send Message 4 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n")); ++} ++ ++VOID Wpa2PairMsg3Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PHEADER_802_11 pHeader; ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pMsg3; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR *mpool, *KEYDATA, *digest; ++ UCHAR Key[32]; ++ MAC_TABLE_ENTRY *pEntry = NULL; ++ KEY_INFO peerKeyInfo; ++ ++ // allocate memory ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); ++ ++ if(mpool == NULL) ++ return; ++ ++ // KEYDATA Len = 512. ++ KEYDATA = (UCHAR *) ROUND_UP(mpool, 4); ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n")); ++ ++ pHeader = (PHEADER_802_11) Elem->Msg; ++ ++ // Process message 3 frame. ++ pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ // 1. Verify cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // 2. Check MIC value ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); ++ ++ // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 4. Double check ANonce ++ if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Obtain GTK ++ // 5. Decrypt GTK from Key Data ++ DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // Decrypt AES GTK ++ AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData); ++ } ++ else // TKIP ++ { ++ INT i; ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); ++ } ++ ++ if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update GTK to ASIC ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero message 4 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) ++ // ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; ++ ++ // Key Type PeerKey ++ Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting message 4 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ // Update PTK ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ ++ // Decide its ChiperAlg ++ if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; ++ else ++ pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; ++ ++ // Update these related information to MAC_TABLE_ENTRY ++ pEntry = &pAd->MacTab.Content[BSSID_WCID]; ++ NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); ++ NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); ++ NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); ++ pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; ++ ++ // Update pairwise key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pAd->SharedKey[BSS0][0].Key, ++ pAd->SharedKey[BSS0][0].TxMic, ++ pAd->SharedKey[BSS0][0].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ 0, ++ pAd->SharedKey[BSS0][0].CipherAlg, ++ pEntry); ++ ++ // Make Transmitting frame ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // Copy frame to Tx ring and Send Message 4 to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ ++ // send wireless event - for set key done WPA2 ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0); ++ ++ DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n")); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process Group key 2-way handshaking ++ ++ Arguments: ++ pAd Pointer to our adapter ++ Elem Message body ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaGroupMsg1Action( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++ ++{ ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ PEAPOL_PACKET pGroup; ++ UCHAR *mpool, *digest, *KEYDATA; ++ UCHAR Mic[16], OldMic[16]; ++ UCHAR GTK[32], Key[32]; ++ KEY_INFO peerKeyInfo; ++ ++ // allocate memory ++ os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); ++ ++ if(mpool == NULL) ++ return; ++ ++ // digest Len = 80. ++ digest = (UCHAR *) ROUND_UP(mpool, 4); ++ // KEYDATA Len = 512. ++ KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n")); ++ ++ // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) ++ pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; ++ ++ NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); ++ NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO)); ++ ++ *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); ++ ++ // 0. Check cipher type match ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // 1. Verify Replay counter ++ // Check Replay Counter, it has to be larger than last one. No need to be exact one larger ++ if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Update new replay counter ++ NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // 2. Verify MIC is valid ++ // Save the MIC and replace with zero ++ NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); ++ ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic); ++ } ++ ++ if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n")); ++ MlmeFreeMemory(pAd, (PUCHAR)mpool); ++ return; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n")); ++ ++ ++ // 3. Decrypt GTK from Key Data ++ if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // Decrypt AES GTK ++ AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData); ++ } ++ else // TKIP ++ { ++ INT i; ++ ++ // Decrypt TKIP GTK ++ // Construct 32 bytes RC4 Key ++ NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16); ++ NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ++ ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); ++ //discard first 256 bytes ++ for(i = 0; i < 256; i++) ++ ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); ++ // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ++ ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]); ++ } ++ ++ // Process decrypted key data material ++ // Parse keyData to handle KDE format for WPA2PSK ++ if (peerKeyInfo.EKD_DL) ++ { ++ if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0)) ++ { ++ os_free_mem(pAd, (PUCHAR)mpool); ++ return; ++ } ++ } ++ else // WPAPSK ++ { ++ // set key material, TxMic and RxMic for WPAPSK ++ NdisMoveMemory(GTK, KEYDATA, 32); ++ NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32); ++ pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex; ++ ++ // Prepare pair-wise key information into shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, >K[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, >K[24], LEN_TKIP_TXMICK); ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); ++ } ++ ++ // Update group key information to ASIC Shared Key Table ++ AsicAddSharedKeyEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); ++ ++ // Update ASIC WCID attribute table and IVEIV table ++ RTMPAddWcidAttributeEntry(pAd, ++ BSS0, ++ pAd->StaCfg.DefaultKeyId, ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, ++ NULL); ++ ++ // set 802.1x port control ++ //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; ++ STA_PORT_SECURED(pAd); ++ ++ // Indicate Connected for GUI ++ pAd->IndicateMediaState = NdisMediaStateConnected; ++ ++ // init header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ // Zero Group message 1 body ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field ++ ++ // ++ // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) ++ // ++ if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ++ { ++ Packet.KeyDesc.Type = WPA2_KEY_DESC; ++ } ++ else ++ { ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ } ++ ++ // Key descriptor version and appropriate RSN IE ++ Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; ++ ++ // Update Key Length ++ Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0]; ++ Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1]; ++ ++ // Key Index as G-Msg 1 ++ if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ++ Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex; ++ ++ // Key Type Group key ++ Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY; ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Secure bit ++ Packet.KeyDesc.KeyInfo.Secure = 1; ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ // Key Replay count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ ++ // Out buffer for transmitting group message 2 ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ MlmeFreeMemory(pAd, (PUCHAR)mpool); ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ // AES ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ ++ // 5. Copy frame to Tx ring and prepare for encryption ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); ++ ++ // 6 Free allocated memory ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ os_free_mem(pAd, (PUCHAR)mpool); ++ ++ // send wireless event - for set key done WPA2 ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n")); ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Init WPA MAC header ++ ++ Arguments: ++ pAd Pointer to our adapter ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID WpaMacHeaderInit( ++ IN PRTMP_ADAPTER pAd, ++ IN OUT PHEADER_802_11 pHdr80211, ++ IN UCHAR wep, ++ IN PUCHAR pAddr1) ++{ ++ NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); ++ pHdr80211->FC.Type = BTYPE_DATA; ++ pHdr80211->FC.ToDs = 1; ++ if (wep == 1) ++ pHdr80211->FC.Wep = 1; ++ ++ // Addr1: BSSID, Addr2: SA, Addr3: DA ++ COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1); ++ COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); ++ COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid); ++ pHdr80211->Sequence = pAd->Sequence; ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Copy frame from waiting queue into relative ring buffer and set ++ appropriate ASIC register to kick hardware encryption before really ++ sent out to air. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ PNDIS_PACKET Pointer to outgoing Ndis frame ++ NumberOfFrag Number of fragment required ++ ++ Return Value: ++ None ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPToWirelessSta( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pHeader802_3, ++ IN UINT HdrLen, ++ IN PUCHAR pData, ++ IN UINT DataLen, ++ IN BOOLEAN is4wayFrame) ++ ++{ ++ NDIS_STATUS Status; ++ PNDIS_PACKET pPacket; ++ UCHAR Index; ++ ++ do ++ { ++ // 1. build a NDIS packet and call RTMPSendPacket(); ++ // be careful about how/when to release this internal allocated NDIS PACKET buffer ++ Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen); ++ if (Status != NDIS_STATUS_SUCCESS) ++ break; ++ ++ if (is4wayFrame) ++ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1); ++ else ++ RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0); ++ ++ // 2. send out the packet ++ Status = STASendPacket(pAd, pPacket); ++ if(Status == NDIS_STATUS_SUCCESS) ++ { ++ // Dequeue one frame from TxSwQueue0..3 queue and process it ++ // There are three place calling dequeue for TX ring. ++ // 1. Here, right after queueing the frame. ++ // 2. At the end of TxRingTxDone service routine. ++ // 3. Upon NDIS call RTMPSendPackets ++ if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) ++ { ++ for(Index = 0; Index < 5; Index ++) ++ if(pAd->TxSwQueue[Index].Number > 0) ++ RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS); ++ } ++ } ++ } while(FALSE); ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Check Sanity RSN IE form AP ++ ++ Arguments: ++ ++ Return Value: ++ ++ ++ ======================================================================== ++*/ ++BOOLEAN CheckRSNIE( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pData, ++ IN UCHAR DataLen, ++ OUT UCHAR *Offset) ++{ ++ PUCHAR pVIE; ++ UCHAR len; ++ PEID_STRUCT pEid; ++ BOOLEAN result = FALSE; ++ ++ pVIE = pData; ++ len = DataLen; ++ *Offset = 0; ++ ++ while (len > sizeof(RSNIE2)) ++ { ++ pEid = (PEID_STRUCT) pVIE; ++ // WPA RSN IE ++ if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && ++ (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && ++ (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ // WPA2 RSN IE ++ else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) ++ { ++ if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) && ++ (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && ++ (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); ++ result = TRUE; ++ } ++ ++ *Offset += (pEid->Len + 2); ++ } ++ else ++ { ++ break; ++ } ++ ++ pVIE += (pEid->Len + 2); ++ len -= (pEid->Len + 2); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset)); ++ ++ return result; ++ ++} ++ ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. ++ GTK is encaptulated in KDE format at p.83 802.11i D10 ++ ++ Arguments: ++ ++ Return Value: ++ ++ Note: ++ 802.11i D10 ++ ++ ======================================================================== ++*/ ++BOOLEAN ParseKeyData( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pKeyData, ++ IN UCHAR KeyDataLen, ++ IN UCHAR bPairewise) ++{ ++ PKDE_ENCAP pKDE = NULL; ++ PUCHAR pMyKeyData = pKeyData; ++ UCHAR KeyDataLength = KeyDataLen; ++ UCHAR GTKLEN; ++ UCHAR skip_offset; ++ ++ // Verify The RSN IE contained in Pairewise-Msg 3 and skip it ++ if (bPairewise) ++ { ++ // Check RSN IE whether it is WPA2/WPA2PSK ++ if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n")); ++ hex_dump("Get KEYDATA :", pKeyData, KeyDataLen); ++ return FALSE; ++ } ++ else ++ { ++ // skip RSN IE ++ pMyKeyData += skip_offset; ++ KeyDataLength -= skip_offset; ++ ++ //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); ++ ++ // Parse EKD format ++ if (KeyDataLength >= 8) ++ { ++ pKDE = (PKDE_ENCAP) pMyKeyData; ++ } ++ else ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n")); ++ return FALSE; ++ } ++ ++ ++ // Sanity check - shared key index should not be 0 ++ if (pKDE->GTKEncap.Kid == 0) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n")); ++ return FALSE; ++ } ++ ++ // Sanity check - KED length ++ if (KeyDataLength < (pKDE->Len + 2)) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); ++ return FALSE; ++ } ++ ++ // Get GTK length - refer to IEEE 802.11i-2004 p.82 ++ GTKLEN = pKDE->Len -6; ++ ++ if (GTKLEN < LEN_AES_KEY) ++ { ++ DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); ++ return FALSE; ++ } ++ else ++ DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN)); ++ ++ // Update GTK ++ // set key material, TxMic and RxMic for WPAPSK ++ NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32); ++ pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid; ++ ++ // Update shared key table ++ NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK); ++ NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK); ++ ++ // Update Shared Key CipherAlg ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; ++ if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ ++ return TRUE; ++ ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Cisco CCKM PRF function ++ ++ Arguments: ++ key Cisco Base Transient Key (BTK) ++ key_len The key length of the BTK ++ data Ruquest Number(RN) + BSSID ++ data_len The length of the data ++ output Store for PTK(Pairwise transient keys) ++ len The length of the output ++ Return Value: ++ None ++ ++ Note: ++ 802.1i Annex F.9 ++ ++ ======================================================================== ++*/ ++VOID CCKMPRF( ++ IN UCHAR *key, ++ IN INT key_len, ++ IN UCHAR *data, ++ IN INT data_len, ++ OUT UCHAR *output, ++ IN INT len) ++{ ++ INT i; ++ UCHAR input[1024]; ++ INT currentindex = 0; ++ INT total_len; ++ ++ NdisMoveMemory(input, data, data_len); ++ total_len = data_len; ++ input[total_len] = 0; ++ total_len++; ++ for (i = 0; i < (len + 19) / 20; i++) ++ { ++ HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); ++ currentindex += 20; ++ input[total_len - 1]++; ++ } ++} ++ ++/* ++ ======================================================================== ++ ++ Routine Description: ++ Process MIC error indication and record MIC error timer. ++ ++ Arguments: ++ pAd Pointer to our adapter ++ pWpaKey Pointer to the WPA key structure ++ ++ Return Value: ++ None ++ ++ IRQL = DISPATCH_LEVEL ++ ++ Note: ++ ++ ======================================================================== ++*/ ++VOID RTMPReportMicError( ++ IN PRTMP_ADAPTER pAd, ++ IN PCIPHER_KEY pWpaKey) ++{ ++ ULONG Now; ++ UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0); ++ ++ // Record Last MIC error time and count ++ Now = jiffies; ++ if (pAd->StaCfg.MicErrCnt == 0) ++ { ++ pAd->StaCfg.MicErrCnt++; ++ pAd->StaCfg.LastMicErrorTime = Now; ++ NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); ++ } ++ else if (pAd->StaCfg.MicErrCnt == 1) ++ { ++ if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) ++ { ++ // Update Last MIC error time, this did not violate two MIC errors within 60 seconds ++ pAd->StaCfg.LastMicErrorTime = Now; ++ } ++ else ++ { ++ ++ if (pAd->CommonCfg.bWirelessEvent) ++ RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); ++ ++ pAd->StaCfg.LastMicErrorTime = Now; ++ // Violate MIC error counts, MIC countermeasures kicks in ++ pAd->StaCfg.MicErrCnt++; ++ // We shall block all reception ++ // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame ++ // ++ // No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets ++ // if pAd->StaCfg.MicErrCnt greater than 2. ++ // ++ // RTMPRingCleanUp(pAd, QID_AC_BK); ++ // RTMPRingCleanUp(pAd, QID_AC_BE); ++ // RTMPRingCleanUp(pAd, QID_AC_VI); ++ // RTMPRingCleanUp(pAd, QID_AC_VO); ++ // RTMPRingCleanUp(pAd, QID_HCCA); ++ } ++ } ++ else ++ { ++ // MIC error count >= 2 ++ // This should not happen ++ ; ++ } ++ MlmeEnqueue(pAd, ++ MLME_CNTL_STATE_MACHINE, ++ OID_802_11_MIC_FAILURE_REPORT_FRAME, ++ 1, ++ &unicastKey); ++ ++ if (pAd->StaCfg.MicErrCnt == 2) ++ { ++ RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); ++ } ++} ++ ++ ++#ifdef WPA_SUPPLICANT_SUPPORT ++#define LENGTH_EAP_H 4 ++// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). ++INT WpaCheckEapCode( ++ IN PRTMP_ADAPTER pAd, ++ IN PUCHAR pFrame, ++ IN USHORT FrameLen, ++ IN USHORT OffSet) ++{ ++ ++ PUCHAR pData; ++ INT result = 0; ++ ++ if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H ) ++ return result; ++ ++ pData = pFrame + OffSet; // skip offset bytes ++ ++ if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type ++ { ++ result = *(pData+4); // EAP header - Code ++ } ++ ++ return result; ++} ++ ++VOID WpaSendMicFailureToWpaSupplicant( ++ IN PRTMP_ADAPTER pAd, ++ IN BOOLEAN bUnicast) ++{ ++ union iwreq_data wrqu; ++ char custom[IW_CUSTOM_MAX] = {0}; ++ ++ sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); ++ if (bUnicast) ++ sprintf(custom, "%s unicast", custom); ++ wrqu.data.length = strlen(custom); ++ wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); ++ ++ return; ++} ++#endif // WPA_SUPPLICANT_SUPPORT // ++ ++VOID WpaMicFailureReportFrame( ++ IN PRTMP_ADAPTER pAd, ++ IN MLME_QUEUE_ELEM *Elem) ++{ ++ PUCHAR pOutBuffer = NULL; ++ UCHAR Header802_3[14]; ++ ULONG FrameLen = 0; ++ EAPOL_PACKET Packet; ++ UCHAR Mic[16]; ++ BOOLEAN bUnicast; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); ++ ++ bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE); ++ pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); ++ ++ // init 802.3 header and Fill Packet ++ MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); ++ ++ NdisZeroMemory(&Packet, sizeof(Packet)); ++ Packet.ProVer = EAPOL_VER; ++ Packet.ProType = EAPOLKey; ++ ++ Packet.KeyDesc.Type = WPA1_KEY_DESC; ++ ++ // Request field presented ++ Packet.KeyDesc.KeyInfo.Request = 1; ++ ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 2; ++ } ++ else // TKIP ++ { ++ Packet.KeyDesc.KeyInfo.KeyDescVer = 1; ++ } ++ ++ Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); ++ ++ // KeyMic field presented ++ Packet.KeyDesc.KeyInfo.KeyMic = 1; ++ ++ // Error field presented ++ Packet.KeyDesc.KeyInfo.Error = 1; ++ ++ // Update packet length after decide Key data payload ++ Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; ++ ++ // Key Replay Count ++ NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); ++ inc_byte_array(pAd->StaCfg.ReplayCounter, 8); ++ ++ // Convert to little-endian format. ++ *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); ++ ++ ++ MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory ++ if(pOutBuffer == NULL) ++ { ++ return; ++ } ++ ++ // Prepare EAPOL frame for MIC calculation ++ // Be careful, only EAPOL frame is counted for MIC calculation ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // Prepare and Fill MIC value ++ NdisZeroMemory(Mic, sizeof(Mic)); ++ if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) ++ { // AES ++ UCHAR digest[20] = {0}; ++ HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); ++ NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); ++ } ++ else ++ { // TKIP ++ hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); ++ } ++ NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); ++ ++ MakeOutgoingFrame(pOutBuffer, &FrameLen, ++ LENGTH_802_3, &Header802_3, ++ Packet.Body_Len[1] + 4, &Packet, ++ END_OF_ARGS); ++ ++ // opy frame to Tx ring and send MIC failure report frame to authenticator ++ RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); ++ ++ MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); ++} ++ ++/** from wpa_supplicant ++ * inc_byte_array - Increment arbitrary length byte array by one ++ * @counter: Pointer to byte array ++ * @len: Length of the counter in bytes ++ * ++ * This function increments the last byte of the counter by one and continues ++ * rolling over to more significant bytes if the byte was incremented from ++ * 0xff to 0x00. ++ */ ++void inc_byte_array(UCHAR *counter, int len) ++{ ++ int pos = len - 1; ++ while (pos >= 0) { ++ counter[pos]++; ++ if (counter[pos] != 0) ++ break; ++ pos--; ++ } ++} ++ ++VOID WpaDisassocApAndBlockAssoc( ++ IN PVOID SystemSpecific1, ++ IN PVOID FunctionContext, ++ IN PVOID SystemSpecific2, ++ IN PVOID SystemSpecific3) ++{ ++ RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext; ++ MLME_DISASSOC_REQ_STRUCT DisassocReq; ++ ++ // disassoc from current AP first ++ DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); ++ DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); ++ MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); ++ ++ pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; ++ pAd->StaCfg.bBlockAssoc = TRUE; ++} ++ +--- /dev/null ++++ b/drivers/staging/rt3070/wpa.h +@@ -0,0 +1,356 @@ ++/* ++ ************************************************************************* ++ * Ralink Tech Inc. ++ * 5F., No.36, Taiyuan St., Jhubei City, ++ * Hsinchu County 302, ++ * Taiwan, R.O.C. ++ * ++ * (c) Copyright 2002-2007, Ralink Technology, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, * ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of * ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ++ * GNU General Public License for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License * ++ * along with this program; if not, write to the * ++ * Free Software Foundation, Inc., * ++ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ++ * * ++ ************************************************************************* ++ ++ Module Name: ++ wpa.h ++ ++ Abstract: ++ ++ Revision History: ++ Who When What ++ -------- ---------- ---------------------------------------------- ++ Name Date Modification logs ++*/ ++ ++#ifndef __WPA_H__ ++#define __WPA_H__ ++ ++// EAPOL Key descripter frame format related length ++#define LEN_KEY_DESC_NONCE 32 ++#define LEN_KEY_DESC_IV 16 ++#define LEN_KEY_DESC_RSC 8 ++#define LEN_KEY_DESC_ID 8 ++#define LEN_KEY_DESC_REPLAY 8 ++#define LEN_KEY_DESC_MIC 16 ++ ++// The length is the EAPoL-Key frame except key data field. ++// Please refer to 802.11i-2004 ,Figure 43u in p.78 ++#define LEN_EAPOL_KEY_MSG (sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE) ++ ++// EAP Code Type. ++#define EAP_CODE_REQUEST 1 ++#define EAP_CODE_RESPONSE 2 ++#define EAP_CODE_SUCCESS 3 ++#define EAP_CODE_FAILURE 4 ++ ++// EAPOL frame Protocol Version ++#define EAPOL_VER 1 ++#define EAPOL_VER2 2 ++ ++// EAPOL-KEY Descriptor Type ++#define WPA1_KEY_DESC 0xfe ++#define WPA2_KEY_DESC 0x02 ++ ++// Key Descriptor Version of Key Information ++#define DESC_TYPE_TKIP 1 ++#define DESC_TYPE_AES 2 ++#define DESC_TYPE_MESH 3 ++ ++#define LEN_MSG1_2WAY 0x7f ++#define MAX_LEN_OF_EAP_HS 256 ++ ++#define LEN_MASTER_KEY 32 ++ ++// EAPOL EK, MK ++#define LEN_EAP_EK 16 ++#define LEN_EAP_MICK 16 ++#define LEN_EAP_KEY ((LEN_EAP_EK)+(LEN_EAP_MICK)) ++// TKIP key related ++#define LEN_PMKID 16 ++#define LEN_TKIP_EK 16 ++#define LEN_TKIP_RXMICK 8 ++#define LEN_TKIP_TXMICK 8 ++#define LEN_AES_EK 16 ++#define LEN_AES_KEY LEN_AES_EK ++#define LEN_TKIP_KEY ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) ++#define TKIP_AP_TXMICK_OFFSET ((LEN_EAP_KEY)+(LEN_TKIP_EK)) ++#define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) ++#define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) ++#define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) ++ ++// RSN IE Length definition ++#define MAX_LEN_OF_RSNIE 90 ++#define MIN_LEN_OF_RSNIE 8 ++ ++//EAP Packet Type ++#define EAPPacket 0 ++#define EAPOLStart 1 ++#define EAPOLLogoff 2 ++#define EAPOLKey 3 ++#define EAPOLASFAlert 4 ++#define EAPTtypeMax 5 ++ ++#define EAPOL_MSG_INVALID 0 ++#define EAPOL_PAIR_MSG_1 1 ++#define EAPOL_PAIR_MSG_2 2 ++#define EAPOL_PAIR_MSG_3 3 ++#define EAPOL_PAIR_MSG_4 4 ++#define EAPOL_GROUP_MSG_1 5 ++#define EAPOL_GROUP_MSG_2 6 ++ ++#define PAIRWISEKEY 1 ++#define GROUPKEY 0 ++ ++// Retry timer counter initial value ++#define PEER_MSG1_RETRY_TIMER_CTR 0 ++#define PEER_MSG3_RETRY_TIMER_CTR 10 ++#define GROUP_MSG1_RETRY_TIMER_CTR 20 ++ ++ ++#define EAPOL_START_DISABLE 0 ++#define EAPOL_START_PSK 1 ++#define EAPOL_START_1X 2 ++ ++#define MIX_CIPHER_WPA_TKIP_ON(x) (((x) & 0x08) != 0) ++#define MIX_CIPHER_WPA_AES_ON(x) (((x) & 0x04) != 0) ++#define MIX_CIPHER_WPA2_TKIP_ON(x) (((x) & 0x02) != 0) ++#define MIX_CIPHER_WPA2_AES_ON(x) (((x) & 0x01) != 0) ++ ++#define ROUND_UP(__x, __y) \ ++ (((ULONG)((__x)+((__y)-1))) & ((ULONG)~((__y)-1))) ++ ++#define ADD_ONE_To_64BIT_VAR(_V) \ ++{ \ ++ UCHAR cnt = LEN_KEY_DESC_REPLAY; \ ++ do \ ++ { \ ++ cnt--; \ ++ _V[cnt]++; \ ++ if (cnt == 0) \ ++ break; \ ++ }while (_V[cnt] == 0); \ ++} ++ ++#define IS_WPA_CAPABILITY(a) (((a) >= Ndis802_11AuthModeWPA) && ((a) <= Ndis802_11AuthModeWPA1PSKWPA2PSK)) ++ ++// EAPOL Key Information definition within Key descriptor format ++typedef struct PACKED _KEY_INFO ++{ ++#ifdef RT_BIG_ENDIAN ++ UCHAR KeyAck:1; ++ UCHAR Install:1; ++ UCHAR KeyIndex:2; ++ UCHAR KeyType:1; ++ UCHAR KeyDescVer:3; ++ UCHAR Rsvd:3; ++ UCHAR EKD_DL:1; // EKD for AP; DL for STA ++ UCHAR Request:1; ++ UCHAR Error:1; ++ UCHAR Secure:1; ++ UCHAR KeyMic:1; ++#else ++ UCHAR KeyMic:1; ++ UCHAR Secure:1; ++ UCHAR Error:1; ++ UCHAR Request:1; ++ UCHAR EKD_DL:1; // EKD for AP; DL for STA ++ UCHAR Rsvd:3; ++ UCHAR KeyDescVer:3; ++ UCHAR KeyType:1; ++ UCHAR KeyIndex:2; ++ UCHAR Install:1; ++ UCHAR KeyAck:1; ++#endif ++} KEY_INFO, *PKEY_INFO; ++ ++// EAPOL Key descriptor format ++typedef struct PACKED _KEY_DESCRIPTER ++{ ++ UCHAR Type; ++ KEY_INFO KeyInfo; ++ UCHAR KeyLength[2]; ++ UCHAR ReplayCounter[LEN_KEY_DESC_REPLAY]; ++ UCHAR KeyNonce[LEN_KEY_DESC_NONCE]; ++ UCHAR KeyIv[LEN_KEY_DESC_IV]; ++ UCHAR KeyRsc[LEN_KEY_DESC_RSC]; ++ UCHAR KeyId[LEN_KEY_DESC_ID]; ++ UCHAR KeyMic[LEN_KEY_DESC_MIC]; ++ UCHAR KeyDataLen[2]; ++ UCHAR KeyData[MAX_LEN_OF_RSNIE]; ++} KEY_DESCRIPTER, *PKEY_DESCRIPTER; ++ ++typedef struct PACKED _EAPOL_PACKET ++{ ++ UCHAR ProVer; ++ UCHAR ProType; ++ UCHAR Body_Len[2]; ++ KEY_DESCRIPTER KeyDesc; ++} EAPOL_PACKET, *PEAPOL_PACKET; ++ ++//802.11i D10 page 83 ++typedef struct PACKED _GTK_ENCAP ++{ ++#ifndef RT_BIG_ENDIAN ++ UCHAR Kid:2; ++ UCHAR tx:1; ++ UCHAR rsv:5; ++ UCHAR rsv1; ++#else ++ UCHAR rsv:5; ++ UCHAR tx:1; ++ UCHAR Kid:2; ++ UCHAR rsv1; ++#endif ++ UCHAR GTK[TKIP_GTK_LENGTH]; ++} GTK_ENCAP, *PGTK_ENCAP; ++ ++typedef struct PACKED _KDE_ENCAP ++{ ++ UCHAR Type; ++ UCHAR Len; ++ UCHAR OUI[3]; ++ UCHAR DataType; ++ GTK_ENCAP GTKEncap; ++} KDE_ENCAP, *PKDE_ENCAP; ++ ++// For WPA1 ++typedef struct PACKED _RSNIE { ++ UCHAR oui[4]; ++ USHORT version; ++ UCHAR mcast[4]; ++ USHORT ucount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }ucast[1]; ++} RSNIE, *PRSNIE; ++ ++// For WPA2 ++typedef struct PACKED _RSNIE2 { ++ USHORT version; ++ UCHAR mcast[4]; ++ USHORT ucount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }ucast[1]; ++} RSNIE2, *PRSNIE2; ++ ++// AKM Suite ++typedef struct PACKED _RSNIE_AUTH { ++ USHORT acount; ++ struct PACKED { ++ UCHAR oui[4]; ++ }auth[1]; ++} RSNIE_AUTH,*PRSNIE_AUTH; ++ ++typedef union PACKED _RSN_CAPABILITIES { ++ struct PACKED { ++#ifdef RT_BIG_ENDIAN ++ USHORT Rsvd:10; ++ USHORT GTKSA_R_Counter:2; ++ USHORT PTKSA_R_Counter:2; ++ USHORT No_Pairwise:1; ++ USHORT PreAuth:1; ++#else ++ USHORT PreAuth:1; ++ USHORT No_Pairwise:1; ++ USHORT PTKSA_R_Counter:2; ++ USHORT GTKSA_R_Counter:2; ++ USHORT Rsvd:10; ++#endif ++ } field; ++ USHORT word; ++} RSN_CAPABILITIES, *PRSN_CAPABILITIES; ++ ++typedef struct PACKED _EAP_HDR { ++ UCHAR ProVer; ++ UCHAR ProType; ++ UCHAR Body_Len[2]; ++ UCHAR code; ++ UCHAR identifier; ++ UCHAR length[2]; // including code and identifier, followed by length-2 octets of data ++} EAP_HDR, *PEAP_HDR; ++ ++// For supplicant state machine states. 802.11i Draft 4.1, p. 97 ++// We simplified it ++typedef enum _WpaState ++{ ++ SS_NOTUSE, // 0 ++ SS_START, // 1 ++ SS_WAIT_MSG_3, // 2 ++ SS_WAIT_GROUP, // 3 ++ SS_FINISH, // 4 ++ SS_KEYUPDATE, // 5 ++} WPA_STATE; ++ ++// ++// The definition of the cipher combination ++// ++// bit3 bit2 bit1 bit0 ++// +------------+------------+ ++// | WPA | WPA2 | ++// +------+-----+------+-----+ ++// | TKIP | AES | TKIP | AES | ++// | 0 | 1 | 1 | 0 | -> 0x06 ++// | 0 | 1 | 1 | 1 | -> 0x07 ++// | 1 | 0 | 0 | 1 | -> 0x09 ++// | 1 | 0 | 1 | 1 | -> 0x0B ++// | 1 | 1 | 0 | 1 | -> 0x0D ++// | 1 | 1 | 1 | 0 | -> 0x0E ++// | 1 | 1 | 1 | 1 | -> 0x0F ++// +------+-----+------+-----+ ++// ++typedef enum _WpaMixPairCipher ++{ ++ MIX_CIPHER_NOTUSE = 0x00, ++ WPA_NONE_WPA2_TKIPAES = 0x03, // WPA2-TKIPAES ++ WPA_AES_WPA2_TKIP = 0x06, ++ WPA_AES_WPA2_TKIPAES = 0x07, ++ WPA_TKIP_WPA2_AES = 0x09, ++ WPA_TKIP_WPA2_TKIPAES = 0x0B, ++ WPA_TKIPAES_WPA2_NONE = 0x0C, // WPA-TKIPAES ++ WPA_TKIPAES_WPA2_AES = 0x0D, ++ WPA_TKIPAES_WPA2_TKIP = 0x0E, ++ WPA_TKIPAES_WPA2_TKIPAES = 0x0F, ++} WPA_MIX_PAIR_CIPHER; ++ ++typedef struct PACKED _RSN_IE_HEADER_STRUCT { ++ UCHAR Eid; ++ UCHAR Length; ++ USHORT Version; // Little endian format ++} RSN_IE_HEADER_STRUCT, *PRSN_IE_HEADER_STRUCT; ++ ++// Cipher suite selector types ++typedef struct PACKED _CIPHER_SUITE_STRUCT { ++ UCHAR Oui[3]; ++ UCHAR Type; ++} CIPHER_SUITE_STRUCT, *PCIPHER_SUITE_STRUCT; ++ ++// Authentication and Key Management suite selector ++typedef struct PACKED _AKM_SUITE_STRUCT { ++ UCHAR Oui[3]; ++ UCHAR Type; ++} AKM_SUITE_STRUCT, *PAKM_SUITE_STRUCT; ++ ++// RSN capability ++typedef struct PACKED _RSN_CAPABILITY { ++ USHORT Rsv:10; ++ USHORT GTKSAReplayCnt:2; ++ USHORT PTKSAReplayCnt:2; ++ USHORT NoPairwise:1; ++ USHORT PreAuth:1; ++} RSN_CAPABILITY, *PRSN_CAPABILITY; ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rtl8187se-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rtl8187se-driver.patch new file mode 100644 index 000000000..ee0f947b7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-rtl8187se-driver.patch @@ -0,0 +1,36633 @@ +From a2c94c94994d49114faad8439d7e5c90cae47cae Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 4 Dec 2008 20:01:41 -0800 +Subject: Staging: add rtl8187se driver +Patch-mainline: 2.6.29 + +From: Greg Kroah-Hartman + +This is a driver for the Ralink 8187 "SE" wireless PCI devices +in some netbook computers (MSI Wind, and others). It includes +its own copy of the ieee80211 stack, but it is compiled into +the driver to prevend duplicate symbol issues. + +This version comes from Ralink with no authorship, but it is based +on an old version of the rtl8180 driver from Andrea Merello. It was +hacked up a bit to get it to build properly within the kernel tree and +to properly handle the merged wireless stack within the driver. + +Cc: Andrea Merello +Cc: linux-wireless +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/rtl8187se/Kconfig | 5 + drivers/staging/rtl8187se/Makefile | 55 + drivers/staging/rtl8187se/dot11d.h | 101 + drivers/staging/rtl8187se/ieee80211.h | 1755 +++ + drivers/staging/rtl8187se/ieee80211/dot11d.c | 246 + drivers/staging/rtl8187se/ieee80211/dot11d.h | 102 + drivers/staging/rtl8187se/ieee80211/ieee80211.h | 1755 +++ + drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c | 265 + drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h | 86 + drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c | 533 + + drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c | 1001 + + drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c | 394 + drivers/staging/rtl8187se/ieee80211/ieee80211_module.c | 299 + drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c | 1971 +++ + drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c | 4029 +++++++ + drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c | 602 + + drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c | 828 + + drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c | 884 + + drivers/staging/rtl8187se/ieee80211/internal.h | 115 + drivers/staging/rtl8187se/ieee80211/rtl_crypto.h | 399 + drivers/staging/rtl8187se/ieee80211_crypt.h | 86 + drivers/staging/rtl8187se/r8180.h | 761 + + drivers/staging/rtl8187se/r8180_93cx6.c | 146 + drivers/staging/rtl8187se/r8180_93cx6.h | 59 + drivers/staging/rtl8187se/r8180_core.c | 6828 +++++++++++++ + drivers/staging/rtl8187se/r8180_dm.c | 1725 +++ + drivers/staging/rtl8187se/r8180_dm.h | 41 + drivers/staging/rtl8187se/r8180_gct.c | 296 + drivers/staging/rtl8187se/r8180_gct.h | 25 + drivers/staging/rtl8187se/r8180_hw.h | 956 + + drivers/staging/rtl8187se/r8180_max2820.c | 240 + drivers/staging/rtl8187se/r8180_max2820.h | 21 + drivers/staging/rtl8187se/r8180_pm.c | 90 + drivers/staging/rtl8187se/r8180_pm.h | 28 + drivers/staging/rtl8187se/r8180_rtl8225.c | 933 + + drivers/staging/rtl8187se/r8180_rtl8225.h | 44 + drivers/staging/rtl8187se/r8180_rtl8225z2.c | 1587 +++ + drivers/staging/rtl8187se/r8180_rtl8255.c | 1838 +++ + drivers/staging/rtl8187se/r8180_rtl8255.h | 19 + drivers/staging/rtl8187se/r8180_sa2400.c | 233 + drivers/staging/rtl8187se/r8180_sa2400.h | 26 + drivers/staging/rtl8187se/r8180_wx.c | 1644 +++ + drivers/staging/rtl8187se/r8180_wx.h | 21 + drivers/staging/rtl8187se/r8185b_init.c | 3342 ++++++ + 46 files changed, 36417 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -51,4 +51,6 @@ source "drivers/staging/rt2860/Kconfig" + + source "drivers/staging/benet/Kconfig" + ++source "drivers/staging/rtl8187se/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -17,3 +17,4 @@ obj-$(CONFIG_AGNX) += agnx/ + obj-$(CONFIG_OTUS) += otus/ + obj-$(CONFIG_RT2860) += rt2860/ + obj-$(CONFIG_BENET) += benet/ ++obj-$(CONFIG_RTL8187SE) += rtl8187se/ +--- /dev/null ++++ b/drivers/staging/rtl8187se/dot11d.h +@@ -0,0 +1,101 @@ ++#ifndef __INC_DOT11D_H ++#define __INC_DOT11D_H ++ ++#include "ieee80211.h" ++ ++//#define ENABLE_DOT11D ++ ++//#define DOT11D_MAX_CHNL_NUM 83 ++ ++typedef struct _CHNL_TXPOWER_TRIPLE { ++ u8 FirstChnl; ++ u8 NumChnls; ++ u8 MaxTxPowerInDbm; ++}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; ++ ++typedef enum _DOT11D_STATE { ++ DOT11D_STATE_NONE = 0, ++ DOT11D_STATE_LEARNED, ++ DOT11D_STATE_DONE, ++}DOT11D_STATE; ++ ++typedef struct _RT_DOT11D_INFO { ++ //DECLARE_RT_OBJECT(RT_DOT11D_INFO); ++ ++ bool bEnabled; // dot11MultiDomainCapabilityEnabled ++ ++ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. ++ u8 CountryIeBuf[MAX_IE_LEN]; ++ u8 CountryIeSrcAddr[6]; // Source AP of the country IE. ++ u8 CountryIeWatchdog; ++ ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) ++ //u8 ChnlListLen; // #Bytes valid in ChnlList[]. ++ //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; ++ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; ++ ++ DOT11D_STATE State; ++}RT_DOT11D_INFO, *PRT_DOT11D_INFO; ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) ++#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) ++ ++#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled ++#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) ++ ++#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++ ++#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ ++ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ ++ FALSE : \ ++ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) ++ ++#define CIE_WATCHDOG_TH 1 ++#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog ++#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 ++#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) ++ ++#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) ++ ++ ++void ++Dot11d_Init( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_Reset( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_UpdateCountryIe( ++ struct ieee80211_device *dev, ++ u8 * pTaddr, ++ u16 CoutryIeLen, ++ u8 * pCoutryIe ++ ); ++ ++u8 ++DOT11D_GetMaxTxPwrInDbm( ++ struct ieee80211_device *dev, ++ u8 Channel ++ ); ++ ++void ++DOT11D_ScanComplete( ++ struct ieee80211_device * dev ++ ); ++ ++int IsLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++ ++int ToLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++ ++#endif // #ifndef __INC_DOT11D_H +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211_crypt.h +@@ -0,0 +1,86 @@ ++/* ++ * Original code based on Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++/* ++ * This file defines the interface to the ieee80211 crypto module. ++ */ ++#ifndef IEEE80211_CRYPT_H ++#define IEEE80211_CRYPT_H ++ ++#include ++ ++struct ieee80211_crypto_ops { ++ const char *name; ++ ++ /* init new crypto context (e.g., allocate private data space, ++ * select IV, etc.); returns NULL on failure or pointer to allocated ++ * private data on success */ ++ void * (*init)(int keyidx); ++ ++ /* deinitialize crypto context and free allocated private data */ ++ void (*deinit)(void *priv); ++ ++ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return ++ * value from decrypt_mpdu is passed as the keyidx value for ++ * decrypt_msdu. skb must have enough head and tail room for the ++ * encryption; if not, error will be returned; these functions are ++ * called for all MPDUs (i.e., fragments). ++ */ ++ int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ ++ /* These functions are called for full MSDUs, i.e. full frames. ++ * These can be NULL if full MSDU operations are not needed. */ ++ int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, ++ void *priv); ++ ++ int (*set_key)(void *key, int len, u8 *seq, void *priv); ++ int (*get_key)(void *key, int len, u8 *seq, void *priv); ++ ++ /* procfs handler for printing out key information and possible ++ * statistics */ ++ char * (*print_stats)(char *p, void *priv); ++ ++ /* maximum number of bytes added by encryption; encrypt buf is ++ * allocated with extra_prefix_len bytes, copy of in_buf, and ++ * extra_postfix_len; encrypt need not use all this space, but ++ * the result must start at the beginning of the buffer and correct ++ * length must be returned */ ++ int extra_prefix_len, extra_postfix_len; ++ ++ struct module *owner; ++}; ++ ++struct ieee80211_crypt_data { ++ struct list_head list; /* delayed deletion list */ ++ struct ieee80211_crypto_ops *ops; ++ void *priv; ++ atomic_t refcnt; ++}; ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); ++void ieee80211_crypt_deinit_handler(unsigned long); ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c +@@ -0,0 +1,246 @@ ++#ifdef ENABLE_DOT11D ++//----------------------------------------------------------------------------- ++// File: ++// Dot11d.c ++// ++// Description: ++// Implement 802.11d. ++// ++//----------------------------------------------------------------------------- ++ ++#include "dot11d.h" ++ ++void ++Dot11d_Init(struct ieee80211_device *ieee) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); ++ ++ pDot11dInfo->bEnabled = 0; ++ ++ pDot11dInfo->State = DOT11D_STATE_NONE; ++ pDot11dInfo->CountryIeLen = 0; ++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); ++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); ++ RESET_CIE_WATCHDOG(ieee); ++ ++ printk("Dot11d_Init()\n"); ++} ++ ++// ++// Description: ++// Reset to the state as we are just entering a regulatory domain. ++// ++void ++Dot11d_Reset(struct ieee80211_device *ieee) ++{ ++ u32 i; ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); ++ ++ // Clear old channel map ++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); ++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); ++ // Set new channel map ++ for (i=1; i<=11; i++) { ++ (pDot11dInfo->channel_map)[i] = 1; ++ } ++ for (i=12; i<=14; i++) { ++ (pDot11dInfo->channel_map)[i] = 2; ++ } ++ ++ pDot11dInfo->State = DOT11D_STATE_NONE; ++ pDot11dInfo->CountryIeLen = 0; ++ RESET_CIE_WATCHDOG(ieee); ++ ++ //printk("Dot11d_Reset()\n"); ++} ++ ++// ++// Description: ++// Update country IE from Beacon or Probe Resopnse ++// and configure PHY for operation in the regulatory domain. ++// ++// TODO: ++// Configure Tx power. ++// ++// Assumption: ++// 1. IS_DOT11D_ENABLE() is TRUE. ++// 2. Input IE is an valid one. ++// ++void ++Dot11d_UpdateCountryIe( ++ struct ieee80211_device *dev, ++ u8 * pTaddr, ++ u16 CoutryIeLen, ++ u8 * pCoutryIe ++ ) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ u8 i, j, NumTriples, MaxChnlNum; ++ PCHNL_TXPOWER_TRIPLE pTriple; ++ ++ if((CoutryIeLen - 3)%3 != 0) ++ { ++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); ++ Dot11d_Reset(dev); ++ return; ++ } ++ ++ memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); ++ memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); ++ MaxChnlNum = 0; ++ NumTriples = (CoutryIeLen - 3) / 3; // skip 3-byte country string. ++ pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3); ++ for(i = 0; i < NumTriples; i++) ++ { ++ if(MaxChnlNum >= pTriple->FirstChnl) ++ { // It is not in a monotonically increasing order, so stop processing. ++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); ++ Dot11d_Reset(dev); ++ return; ++ } ++ if(MAX_CHANNEL_NUMBER < (pTriple->FirstChnl + pTriple->NumChnls)) ++ { // It is not a valid set of channel id, so stop processing. ++ printk("Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n"); ++ Dot11d_Reset(dev); ++ return; ++ } ++ ++ for(j = 0 ; j < pTriple->NumChnls; j++) ++ { ++ pDot11dInfo->channel_map[pTriple->FirstChnl + j] = 1; ++ pDot11dInfo->MaxTxPwrDbmList[pTriple->FirstChnl + j] = pTriple->MaxTxPowerInDbm; ++ MaxChnlNum = pTriple->FirstChnl + j; ++ } ++ ++ pTriple = (PCHNL_TXPOWER_TRIPLE)((u8*)pTriple + 3); ++ } ++#if 1 ++ //printk("Dot11d_UpdateCountryIe(): Channel List:\n"); ++ printk("Channel List:"); ++ for(i=1; i<= MAX_CHANNEL_NUMBER; i++) ++ if(pDot11dInfo->channel_map[i] > 0) ++ printk(" %d", i); ++ printk("\n"); ++#endif ++ ++ UPDATE_CIE_SRC(dev, pTaddr); ++ ++ pDot11dInfo->CountryIeLen = CoutryIeLen; ++ memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe,CoutryIeLen); ++ pDot11dInfo->State = DOT11D_STATE_LEARNED; ++} ++ ++void dump_chnl_map(u8 * channel_map) ++{ ++ int i; ++ printk("Channel List:"); ++ for(i=1; i<= MAX_CHANNEL_NUMBER; i++) ++ if(channel_map[i] > 0) ++ printk(" %d(%d)", i, channel_map[i]); ++ printk("\n"); ++} ++ ++u8 ++DOT11D_GetMaxTxPwrInDbm( ++ struct ieee80211_device *dev, ++ u8 Channel ++ ) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ u8 MaxTxPwrInDbm = 255; ++ ++ if(MAX_CHANNEL_NUMBER < Channel) ++ { ++ printk("DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); ++ return MaxTxPwrInDbm; ++ } ++ if(pDot11dInfo->channel_map[Channel]) ++ { ++ MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; ++ } ++ ++ return MaxTxPwrInDbm; ++} ++ ++ ++void ++DOT11D_ScanComplete( ++ struct ieee80211_device * dev ++ ) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ ++ switch(pDot11dInfo->State) ++ { ++ case DOT11D_STATE_LEARNED: ++ pDot11dInfo->State = DOT11D_STATE_DONE; ++ break; ++ ++ case DOT11D_STATE_DONE: ++ if( GET_CIE_WATCHDOG(dev) == 0 ) ++ { // Reset country IE if previous one is gone. ++ Dot11d_Reset(dev); ++ } ++ break; ++ case DOT11D_STATE_NONE: ++ break; ++ } ++} ++ ++int IsLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ ++ if(MAX_CHANNEL_NUMBER < channel) ++ { ++ printk("IsLegalChannel(): Invalid Channel\n"); ++ return 0; ++ } ++ if(pDot11dInfo->channel_map[channel] > 0) ++ return 1; ++ return 0; ++} ++ ++int ToLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++) ++{ ++ PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); ++ u8 default_chn = 0; ++ u32 i = 0; ++ ++ for (i=1; i<= MAX_CHANNEL_NUMBER; i++) ++ { ++ if(pDot11dInfo->channel_map[i] > 0) ++ { ++ default_chn = i; ++ break; ++ } ++ } ++ ++ if(MAX_CHANNEL_NUMBER < channel) ++ { ++ printk("IsLegalChannel(): Invalid Channel\n"); ++ return default_chn; ++ } ++ ++ if(pDot11dInfo->channel_map[channel] > 0) ++ return channel; ++ ++ return default_chn; ++} ++ ++#if 0 ++EXPORT_SYMBOL(Dot11d_Init); ++EXPORT_SYMBOL(Dot11d_Reset); ++EXPORT_SYMBOL(Dot11d_UpdateCountryIe); ++EXPORT_SYMBOL(DOT11D_GetMaxTxPwrInDbm); ++EXPORT_SYMBOL(DOT11D_ScanComplete); ++EXPORT_SYMBOL(IsLegalChannel); ++EXPORT_SYMBOL(ToLegalChannel); ++#endif ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/dot11d.h +@@ -0,0 +1,102 @@ ++#ifndef __INC_DOT11D_H ++#define __INC_DOT11D_H ++ ++#include "ieee80211.h" ++ ++//#define ENABLE_DOT11D ++ ++//#define DOT11D_MAX_CHNL_NUM 83 ++ ++typedef struct _CHNL_TXPOWER_TRIPLE { ++ u8 FirstChnl; ++ u8 NumChnls; ++ u8 MaxTxPowerInDbm; ++}CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; ++ ++typedef enum _DOT11D_STATE { ++ DOT11D_STATE_NONE = 0, ++ DOT11D_STATE_LEARNED, ++ DOT11D_STATE_DONE, ++}DOT11D_STATE; ++ ++typedef struct _RT_DOT11D_INFO { ++ //DECLARE_RT_OBJECT(RT_DOT11D_INFO); ++ ++ bool bEnabled; // dot11MultiDomainCapabilityEnabled ++ ++ u16 CountryIeLen; // > 0 if CountryIeBuf[] contains valid country information element. ++ u8 CountryIeBuf[MAX_IE_LEN]; ++ u8 CountryIeSrcAddr[6]; // Source AP of the country IE. ++ u8 CountryIeWatchdog; ++ ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; //!!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) ++ //u8 ChnlListLen; // #Bytes valid in ChnlList[]. ++ //u8 ChnlList[DOT11D_MAX_CHNL_NUM]; ++ u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; ++ ++ DOT11D_STATE State; ++}RT_DOT11D_INFO, *PRT_DOT11D_INFO; ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) ++#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) ++ ++#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled ++#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) ++ ++#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) ++ ++#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ ++ (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ ++ FALSE : \ ++ (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) ++ ++#define CIE_WATCHDOG_TH 1 ++#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog ++#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 ++#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) ++ ++#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) ++ ++ ++void ++Dot11d_Init( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_Reset( ++ struct ieee80211_device *dev ++ ); ++ ++void ++Dot11d_UpdateCountryIe( ++ struct ieee80211_device *dev, ++ u8 * pTaddr, ++ u16 CoutryIeLen, ++ u8 * pCoutryIe ++ ); ++ ++u8 ++DOT11D_GetMaxTxPwrInDbm( ++ struct ieee80211_device *dev, ++ u8 Channel ++ ); ++ ++void ++DOT11D_ScanComplete( ++ struct ieee80211_device * dev ++ ); ++ ++int IsLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++ ++int ToLegalChannel( ++ struct ieee80211_device * dev, ++ u8 channel ++); ++ ++void dump_chnl_map(u8 * channel_map); ++#endif // #ifndef __INC_DOT11D_H +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211.h +@@ -0,0 +1,1755 @@ ++/* ++ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 ++ * remains copyright by the original authors ++ * ++ * Portions of the merged code are based on Host AP (software wireless ++ * LAN access point) driver for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * Modified for Realtek's wi-fi cards by Andrea Merello ++ * ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++#ifndef IEEE80211_H ++#define IEEE80211_H ++#include /* ETH_ALEN */ ++#include /* ARRAY_SIZE */ ++#include ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) ++#include ++#endif ++ ++/* ++#ifndef bool ++#define bool int ++#endif ++ ++#ifndef true ++#define true 1 ++#endif ++ ++#ifndef false ++#define false 0 ++#endif ++*/ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#ifndef bool ++typedef enum{false = 0, true} bool; ++#endif ++#endif ++//#ifdef JOHN_HWSEC ++#define KEY_TYPE_NA 0x0 ++#define KEY_TYPE_WEP40 0x1 ++#define KEY_TYPE_TKIP 0x2 ++#define KEY_TYPE_CCMP 0x4 ++#define KEY_TYPE_WEP104 0x5 ++//#endif ++ ++ ++#define aSifsTime 10 ++ ++#define MGMT_QUEUE_NUM 5 ++ ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++//It should consistent with the driver_XXX.c ++// David, 2006.9.26 ++#define IEEE_PARAM_WPAX_SELECT 7 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_PROTO_WPA 1 ++#define IEEE_PROTO_RSN 2 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_WPAX_USEGROUP 0 ++#define IEEE_WPAX_WEP40 1 ++#define IEEE_WPAX_TKIP 2 ++#define IEEE_WPAX_WRAP 3 ++#define IEEE_WPAX_CCMP 4 ++#define IEEE_WPAX_WEP104 5 ++ ++#define IEEE_KEY_MGMT_IEEE8021X 1 ++#define IEEE_KEY_MGMT_PSK 2 ++ ++ ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) ++#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rtl ++#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rtl ++#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rtl ++//////////////////////////////// ++// added for kernel conflict under FC5 ++#define ieee80211_wx_get_name ieee80211_wx_get_name_rtl ++#define free_ieee80211 free_ieee80211_rtl ++#define alloc_ieee80211 alloc_ieee80211_rtl ++/////////////////////////////// ++#endif ++//error in ubuntu2.6.22,so add these ++#define ieee80211_wake_queue ieee80211_wake_queue_rtl ++#define ieee80211_stop_queue ieee80211_stop_queue_rtl ++ ++#define ieee80211_rx ieee80211_rx_rtl ++ ++#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rtl ++#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rtl ++#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rtl ++#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rtl ++#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rtl ++#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rtl ++ ++#define ieee80211_txb_free ieee80211_txb_free_rtl ++#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rtl ++#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rtl ++#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rtl ++#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rtl ++#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rtl ++#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rtl ++#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rtl ++#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rtl ++#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rtl ++#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rtl ++#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rtl ++#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rtl ++#define ieee80211_wx_set_power ieee80211_wx_set_power_rtl ++#define ieee80211_wx_get_power ieee80211_wx_get_power_rtl ++#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rtl ++#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rtl ++#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rtl ++#define ieee80211_start_protocol ieee80211_start_protocol_rtl ++#define ieee80211_stop_protocol ieee80211_stop_protocol_rtl ++#define ieee80211_rx_mgt ieee80211_rx_mgt_rtl ++ ++#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rtl ++//by amy for ps ++#define notify_wx_assoc_event notify_wx_assoc_event_rtl ++#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rtl ++#define ieee80211_disassociate ieee80211_disassociate_rtl ++#define ieee80211_start_scan ieee80211_start_scan_rtl ++//by amy for ps ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ ++ } u; ++}ieee_param; ++ ++ ++#if WIRELESS_EXT < 17 ++#define IW_QUAL_QUAL_INVALID 0x10 ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#define IW_QUAL_QUAL_UPDATED 0x1 ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#endif ++ ++// linux under 2.6.9 release may not support it, so modify it for common use ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) ++#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) ++static inline unsigned long msleep_interruptible_rtl(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++ return timeout; ++} ++#else ++#define MSECS(t) msecs_to_jiffies(t) ++#define msleep_interruptible_rtl msleep_interruptible ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++ ++ ++#define IEEE80211_HLEN 30 ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++ ++/* this is stolen and modified from the madwifi driver*/ ++#define IEEE80211_FC0_TYPE_MASK 0x0c ++#define IEEE80211_FC0_TYPE_DATA 0x08 ++#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 ++#define IEEE80211_FC0_SUBTYPE_QOS 0x80 ++ ++#define IEEE80211_QOS_HAS_SEQ(fc) \ ++ (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ ++ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num[17]; ++ u16 frag_num[17]; ++ unsigned long packet_time[17]; ++ struct list_head list; ++}; ++ ++struct ieee80211_hdr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_QOS { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u16 QOS_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr_QOS { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u16 QOS_ctl; ++} __attribute__ ((packed)); ++ ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++static const char *eap_types[] = { ++ [EAP_PACKET] = "EAP-Packet", ++ [EAPOL_START] = "EAPOL-Start", ++ [EAPOL_LOGOFF] = "EAPOL-Logoff", ++ [EAPOL_KEY] = "EAPOL-Key", ++ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" ++}; ++ ++static inline const char *eap_get_type(int type) ++{ ++ return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; ++} ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++/* Frame control field constants */ ++#define IEEE80211_FCTL_VERS 0x0002 ++#define IEEE80211_FCTL_FTYPE 0x000c ++#define IEEE80211_FCTL_STYPE 0x00f0 ++#define IEEE80211_FCTL_TODS 0x0100 ++#define IEEE80211_FCTL_FROMDS 0x0200 ++#define IEEE80211_FCTL_DSTODS 0x0300 //added by david ++#define IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define IEEE80211_FCTL_RETRY 0x0800 ++#define IEEE80211_FCTL_PM 0x1000 ++#define IEEE80211_FCTL_MOREDATA 0x2000 ++#define IEEE80211_FCTL_WEP 0x4000 ++#define IEEE80211_FCTL_ORDER 0x8000 ++ ++#define IEEE80211_FTYPE_MGMT 0x0000 ++#define IEEE80211_FTYPE_CTL 0x0004 ++#define IEEE80211_FTYPE_DATA 0x0008 ++ ++/* management */ ++#define IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define IEEE80211_STYPE_BEACON 0x0080 ++#define IEEE80211_STYPE_ATIM 0x0090 ++#define IEEE80211_STYPE_DISASSOC 0x00A0 ++#define IEEE80211_STYPE_AUTH 0x00B0 ++#define IEEE80211_STYPE_DEAUTH 0x00C0 ++#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 ++ ++/* control */ ++#define IEEE80211_STYPE_PSPOLL 0x00A0 ++#define IEEE80211_STYPE_RTS 0x00B0 ++#define IEEE80211_STYPE_CTS 0x00C0 ++#define IEEE80211_STYPE_ACK 0x00D0 ++#define IEEE80211_STYPE_CFEND 0x00E0 ++#define IEEE80211_STYPE_CFENDACK 0x00F0 ++ ++/* data */ ++#define IEEE80211_STYPE_DATA 0x0000 ++#define IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define IEEE80211_STYPE_NULLFUNC 0x0040 ++#define IEEE80211_STYPE_CFACK 0x0050 ++#define IEEE80211_STYPE_CFPOLL 0x0060 ++#define IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 ++#define IEEE80211_STYPE_QOS_NULL 0x00C0 ++ ++ ++#define IEEE80211_SCTL_FRAG 0x000F ++#define IEEE80211_SCTL_SEQ 0xFFF0 ++ ++ ++/* debug macros */ ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++extern u32 ieee80211_debug_level; ++#define IEEE80211_DEBUG(level, fmt, args...) \ ++do { if (ieee80211_debug_level & (level)) \ ++ printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ ++ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) ++#else ++#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) ++#endif /* CONFIG_IEEE80211_DEBUG */ ++ ++/* ++ * To use the debug system; ++ * ++ * If you are defining a new debug classification, simply add it to the #define ++ * list here in the form of: ++ * ++ * #define IEEE80211_DL_xxxx VALUE ++ * ++ * shifting value to the left one bit from the previous entry. xxxx should be ++ * the name of the classification (for example, WEP) ++ * ++ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your ++ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want ++ * to send output to that classification. ++ * ++ * To add your debug level to the list of levels seen when you perform ++ * ++ * % cat /proc/net/ipw/debug_level ++ * ++ * you simply need to add your entry to the ipw_debug_levels array. ++ * ++ * If you do not see debug_level in /proc/net/ipw then you do not have ++ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration ++ * ++ */ ++ ++#define IEEE80211_DL_INFO (1<<0) ++#define IEEE80211_DL_WX (1<<1) ++#define IEEE80211_DL_SCAN (1<<2) ++#define IEEE80211_DL_STATE (1<<3) ++#define IEEE80211_DL_MGMT (1<<4) ++#define IEEE80211_DL_FRAG (1<<5) ++#define IEEE80211_DL_EAP (1<<6) ++#define IEEE80211_DL_DROP (1<<7) ++ ++#define IEEE80211_DL_TX (1<<8) ++#define IEEE80211_DL_RX (1<<9) ++ ++#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) ++#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) ++#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) ++ ++#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) ++#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) ++//#define IEEE_DEBUG_SCAN IEEE80211_WARNING ++#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) ++#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) ++#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) ++#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) ++#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) ++#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) ++#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) ++#include ++#include ++#include /* ARPHRD_ETHER */ ++ ++#ifndef WIRELESS_SPY ++#define WIRELESS_SPY // enable iwspy support ++#endif ++#include // new driver API ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++} __attribute__ ((packed)); ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) ++ ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++ ++/* Status codes */ ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 ++/* 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++ ++/* Reason codes */ ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 ++ ++ ++/* Information Element IDs */ ++#define WLAN_EID_SSID 0 ++#define WLAN_EID_SUPP_RATES 1 ++#define WLAN_EID_FH_PARAMS 2 ++#define WLAN_EID_DS_PARAMS 3 ++#define WLAN_EID_CF_PARAMS 4 ++#define WLAN_EID_TIM 5 ++#define WLAN_EID_IBSS_PARAMS 6 ++#define WLAN_EID_CHALLENGE 16 ++#define WLAN_EID_RSN 48 ++#define WLAN_EID_GENERIC 221 ++ ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++ ++ ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++ u32 mac_time[2]; ++ u8 signalstrength; ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u16 rate; /* in 100 kbps */ ++ u8 received_channel; ++ u8 control; ++ u8 mask; ++ u8 freq; ++ u16 len; ++ u8 nic_type; ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ unsigned long first_frag_time; ++ unsigned int seq; ++ unsigned int last_frag; ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ unsigned int tx_unicast_frames; ++ unsigned int tx_multicast_frames; ++ unsigned int tx_fragments; ++ unsigned int tx_unicast_octets; ++ unsigned int tx_multicast_octets; ++ unsigned int tx_deferred_transmissions; ++ unsigned int tx_single_retry_frames; ++ unsigned int tx_multiple_retry_frames; ++ unsigned int tx_retry_limit_exceeded; ++ unsigned int tx_discards; ++ unsigned int rx_unicast_frames; ++ unsigned int rx_multicast_frames; ++ unsigned int rx_fragments; ++ unsigned int rx_unicast_octets; ++ unsigned int rx_multicast_octets; ++ unsigned int rx_fcs_errors; ++ unsigned int rx_discards_no_buffer; ++ unsigned int tx_discards_wrong_sa; ++ unsigned int rx_discards_undecryptable; ++ unsigned int rx_message_in_msg_fragments; ++ unsigned int rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_softmac_stats{ ++ unsigned int rx_ass_ok; ++ unsigned int rx_ass_err; ++ unsigned int rx_probe_rq; ++ unsigned int tx_probe_rs; ++ unsigned int tx_beacons; ++ unsigned int rx_auth_rq; ++ unsigned int rx_auth_rs_ok; ++ unsigned int rx_auth_rs_err; ++ unsigned int tx_auth_rq; ++ unsigned int no_auth_rs; ++ unsigned int no_ass_rs; ++ unsigned int tx_ass_rq; ++ unsigned int rx_ass_rq; ++ unsigned int tx_probe_rq; ++ unsigned int reassoc; ++ unsigned int swtxstop; ++ unsigned int swtxawake; ++}; ++ ++struct ieee80211_device; ++ ++#include "ieee80211_crypt.h" ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++ ++#define WEP_KEY_LEN_MODIF 32 ++ ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][WEP_KEY_LEN_MODIF]; ++ u8 level; ++ u16 flags; ++} __attribute__ ((packed)); ++ ++ ++/* ++ ++ 802.11 data frame from AP ++ ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++ ++Total: 28-2340 bytes ++ ++*/ ++ ++struct ieee80211_header_data { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[6]; ++ u8 addr2[6]; ++ u8 addr3[6]; ++ u16 seq_ctrl; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++/* Management Frame Information Element Types */ ++#define MFIE_TYPE_SSID 0 ++#define MFIE_TYPE_RATES 1 ++#define MFIE_TYPE_FH_SET 2 ++#define MFIE_TYPE_DS_SET 3 ++#define MFIE_TYPE_CF_SET 4 ++#define MFIE_TYPE_TIM 5 ++#define MFIE_TYPE_IBSS_SET 6 ++#define MFIE_TYPE_COUNTRY 7 //+YJ,080625 ++#define MFIE_TYPE_CHALLENGE 16 ++#define MFIE_TYPE_ERP 42 ++#define MFIE_TYPE_RSN 48 ++#define MFIE_TYPE_RATES_EX 50 ++#define MFIE_TYPE_GENERIC 221 ++ ++#ifdef ENABLE_DOT11D ++typedef enum ++{ ++ COUNTRY_CODE_FCC = 0, ++ COUNTRY_CODE_IC = 1, ++ COUNTRY_CODE_ETSI = 2, ++ COUNTRY_CODE_SPAIN = 3, ++ COUNTRY_CODE_FRANCE = 4, ++ COUNTRY_CODE_MKK = 5, ++ COUNTRY_CODE_MKK1 = 6, ++ COUNTRY_CODE_ISRAEL = 7, ++ COUNTRY_CODE_TELEC = 8, ++ COUNTRY_CODE_GLOBAL_DOMAIN = 9, ++ COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10 ++}country_code_type_t; ++#endif ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __attribute__ ((packed)); ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __attribute__ ((packed)); ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __attribute__ ((packed)); ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 10 ++ ++struct ieee80211_authentication { ++ struct ieee80211_header_data header; ++ u16 algorithm; ++ u16 transaction; ++ u16 status; ++ //struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++ ++struct ieee80211_probe_response { ++ struct ieee80211_header_data header; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 capability; ++ struct ieee80211_info_element info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_request { ++ struct ieee80211_header_data header; ++ /*struct ieee80211_info_element info_element;*/ ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 listen_interval; ++ //u8 current_ap[ETH_ALEN]; ++ struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_response_frame { ++ struct ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 status; ++ u16 aid; ++ struct ieee80211_info_element info_element; /* supported rates */ ++} __attribute__ ((packed)); ++ ++struct ieee80211_disassoc_frame{ ++ struct ieee80211_hdr_3addr header; ++ u16 reasoncode; ++}__attribute__ ((packed)); ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u16 reserved; ++ u16 frag_size; ++ u16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++struct ieee80211_wmm_ac_param { ++ u8 ac_aci_acm_aifsn; ++ u8 ac_ecwmin_ecwmax; ++ u16 ac_txop_limit; ++}; ++ ++struct ieee80211_wmm_ts_info { ++ u8 ac_dir_tid; ++ u8 ac_up_psb; ++ u8 reserved; ++} __attribute__ ((packed)); ++ ++struct ieee80211_wmm_tspec_elem { ++ struct ieee80211_wmm_ts_info ts_info; ++ u16 norm_msdu_size; ++ u16 max_msdu_size; ++ u32 min_serv_inter; ++ u32 max_serv_inter; ++ u32 inact_inter; ++ u32 suspen_inter; ++ u32 serv_start_time; ++ u32 min_data_rate; ++ u32 mean_data_rate; ++ u32 peak_data_rate; ++ u32 max_burst_size; ++ u32 delay_bound; ++ u32 min_phy_rate; ++ u16 surp_band_allow; ++ u16 medium_time; ++}__attribute__((packed)); ++ ++enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; ++#define MAX_SP_Len (WMM_all_frame << 4) ++#define IEEE80211_QOS_TID 0x0f ++#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++//#define MAX_CHANNEL_NUMBER 161 ++#define MAX_CHANNEL_NUMBER 165 //YJ,modified,080625 ++#define MAX_IE_LEN 0xFF //+YJ,080625 ++ ++typedef struct _CHANNEL_LIST{ ++ u8 Channel[MAX_CHANNEL_NUMBER + 1]; ++ u8 Len; ++}CHANNEL_LIST, *PCHANNEL_LIST; ++ ++#define IEEE80211_SOFTMAC_SCAN_TIME 100//400 ++//(HZ / 2) ++//by amy for ps ++#define IEEE80211_WATCH_DOG_TIME 2000 ++//by amy for ps ++//by amy for antenna ++#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m ++//by amy for antenna ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN 64 ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++#define IEEE80211_PS_ENABLE IEEE80211_DTIM_VALID ++//added by David for QoS 2006/6/30 ++//#define WMM_Hang_8187 ++#ifdef WMM_Hang_8187 ++#undef WMM_Hang_8187 ++#endif ++ ++#define WME_AC_BE 0x00 ++#define WME_AC_BK 0x01 ++#define WME_AC_VI 0x02 ++#define WME_AC_VO 0x03 ++#define WME_ACI_MASK 0x03 ++#define WME_AIFSN_MASK 0x03 ++#define WME_AC_PRAM_LEN 16 ++ ++//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP ++//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) ++#define UP2AC(up) ( \ ++ ((up) < 1) ? WME_AC_BE : \ ++ ((up) < 3) ? WME_AC_BK : \ ++ ((up) < 4) ? WME_AC_BE : \ ++ ((up) < 6) ? WME_AC_VI : \ ++ WME_AC_VO) ++//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue ++#define AC2UP(_ac) ( \ ++ ((_ac) == WME_AC_VO) ? 6 : \ ++ ((_ac) == WME_AC_VI) ? 5 : \ ++ ((_ac) == WME_AC_BK) ? 1 : \ ++ 0) ++ ++#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ ++struct ether_header { ++ u8 ether_dhost[ETHER_ADDR_LEN]; ++ u8 ether_shost[ETHER_ADDR_LEN]; ++ u16 ether_type; ++} __attribute__((packed)); ++ ++#ifndef ETHERTYPE_PAE ++#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ ++#endif ++#ifndef ETHERTYPE_IP ++#define ETHERTYPE_IP 0x0800 /* IP protocol */ ++#endif ++ ++struct ieee80211_network { ++ /* These entries are used to identify a unique network */ ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ /* Ensure null-terminated for any debug msgs */ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++ ++ /* These are network statistics */ ++ struct ieee80211_rx_stats stats; ++ u16 capability; ++ u8 rates[MAX_RATES_LENGTH]; ++ u8 rates_len; ++ u8 rates_ex[MAX_RATES_EX_LENGTH]; ++ u8 rates_ex_len; ++ unsigned long last_scanned; ++ u8 mode; ++ u8 flags; ++ u32 last_associate; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ size_t wpa_ie_len; ++ u8 rsn_ie[MAX_WPA_IE_LEN]; ++ size_t rsn_ie_len; ++ u8 dtim_period; ++ u8 dtim_data; ++ u32 last_dtim_sta_time[2]; ++ struct list_head list; ++ //appeded for QoS ++ u8 wmm_info; ++ struct ieee80211_wmm_ac_param wmm_param[4]; ++ u8 QoS_Enable; ++ u8 SignalStrength; ++//by amy 080312 ++ u8 HighestOperaRate; ++//by amy 080312 ++#ifdef THOMAS_TURBO ++ u8 Turbo_Enable;//enable turbo mode, added by thomas ++#endif ++#ifdef ENABLE_DOT11D ++ u16 CountryIeLen; ++ u8 CountryIeBuf[MAX_IE_LEN]; ++#endif ++}; ++ ++enum ieee80211_state { ++ ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++ ++}; ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++ ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) ++extern inline int is_multicast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) ++extern inline int is_broadcast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++#endif ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++ ++typedef struct tx_pending_t{ ++ int frag; ++ struct ieee80211_txb *txb; ++}tx_pending_t; ++ ++ ++struct ieee80211_device { ++ struct net_device *dev; ++ ++ /* Bookkeeping structures */ ++ struct net_device_stats stats; ++ struct ieee80211_stats ieee_stats; ++ struct ieee80211_softmac_stats softmac_stats; ++ ++ /* Probe / Beacon management */ ++ struct list_head network_free_list; ++ struct list_head network_list; ++ struct ieee80211_network *networks; ++ int scans; ++ int scan_age; ++ ++ int iw_mode; /* operating mode (IW_MODE_*) */ ++ ++ spinlock_t lock; ++ spinlock_t wpax_suitlist_lock; ++ ++ int tx_headroom; /* Set to size of any additional room needed at front ++ * of allocated Tx SKBs */ ++ u32 config; ++ ++ /* WEP and other encryption related settings at the device level */ ++ int open_wep; /* Set to 1 to allow unencrypted frames */ ++ ++ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on ++ * WEP key changes */ ++ ++ /* If the host performs {en,de}cryption, then set to 1 */ ++ int host_encrypt; ++ int host_decrypt; ++ int ieee802_1x; /* is IEEE 802.1X used */ ++ ++ /* WPA data */ ++ int wpa_enabled; ++ int drop_unencrypted; ++ int tkip_countermeasures; ++ int privacy_invoked; ++ size_t wpa_ie_len; ++ u8 *wpa_ie; ++ ++ u8 ap_mac_addr[6]; ++ u16 pairwise_key_type; ++ u16 broadcast_key_type; ++ ++ struct list_head crypt_deinit_list; ++ struct ieee80211_crypt_data *crypt[WEP_KEYS]; ++ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ ++ struct timer_list crypt_deinit_timer; ++ ++ int bcrx_sta_key; /* use individual keys to override default keys even ++ * with RX of broad/multicast frames */ ++ ++ /* Fragmentation structures */ ++ // each streaming contain a entry ++ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; ++ unsigned int frag_next_idx[17]; ++ u16 fts; /* Fragmentation Threshold */ ++ ++ /* This stores infos for the current network. ++ * Either the network we are associated in INFRASTRUCTURE ++ * or the network that we are creating in MASTER mode. ++ * ad-hoc is a mixture ;-). ++ * Note that in infrastructure mode, even when not associated, ++ * fields bssid and essid may be valid (if wpa_set and essid_set ++ * are true) as thy carry the value set by the user via iwconfig ++ */ ++ struct ieee80211_network current_network; ++ ++ ++ enum ieee80211_state state; ++ ++ int short_slot; ++ int mode; /* A, B, G */ ++ int modulation; /* CCK, OFDM */ ++ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ ++ int abg_true; /* ABG flag */ ++ ++ /* used for forcing the ibss workqueue to terminate ++ * without wait for the syncro scan to terminate ++ */ ++ short sync_scan_hurryup; ++ ++#ifdef ENABLE_DOT11D ++ void * pDot11dInfo; ++ bool bGlobalDomain; ++ ++ // For Liteon Ch12~13 passive scan ++ u8 MinPassiveChnlNum; ++ u8 IbssStartChnl; ++#else ++ /* map of allowed channels. 0 is dummy */ ++ // FIXME: remeber to default to a basic channel plan depending of the PHY type ++ int channel_map[MAX_CHANNEL_NUMBER+1]; ++#endif ++ ++ int rate; /* current rate */ ++ int basic_rate; ++ //FIXME: pleace callback, see if redundant with softmac_features ++ short active_scan; ++ ++ /* this contains flags for selectively enable softmac support */ ++ u16 softmac_features; ++ ++ /* if the sequence control field is not filled by HW */ ++ u16 seq_ctrl[5]; ++ ++ /* association procedure transaction sequence number */ ++ u16 associate_seq; ++ ++ /* AID for RTXed association responses */ ++ u16 assoc_id; ++ ++ /* power save mode related*/ ++ short ps; ++ short sta_sleep; ++ int ps_timeout; ++ struct tasklet_struct ps_task; ++ u32 ps_th; ++ u32 ps_tl; ++ ++ short raw_tx; ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ short queue_stop; ++ short scanning; ++ short proto_started; ++ ++ struct semaphore wx_sem; ++ struct semaphore scan_sem; ++ ++ spinlock_t mgmt_tx_lock; ++ spinlock_t beacon_lock; ++ ++ short beacon_txing; ++ ++ short wap_set; ++ short ssid_set; ++ ++ u8 wpax_type_set; //{added by David, 2006.9.28} ++ u32 wpax_type_notify; //{added by David, 2006.9.26} ++ ++ /* QoS related flag */ ++ char init_wmmparam_flag; ++ ++ /* for discarding duplicated packets in IBSS */ ++ struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; ++ ++ /* for discarding duplicated packets in BSS */ ++ u16 last_rxseq_num[17]; /* rx seq previous per-tid */ ++ u16 last_rxfrag_num[17];/* tx frag previous per-tid */ ++ unsigned long last_packet_time[17]; ++ ++ /* for PS mode */ ++ unsigned long last_rx_ps_time; ++ ++ /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ ++ struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; ++ int mgmt_queue_head; ++ int mgmt_queue_tail; ++ ++ ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ struct tx_pending_t tx_pending; ++ ++ /* used if IEEE_SOFTMAC_ASSOCIATE is set */ ++ struct timer_list associate_timer; ++ ++ /* used if IEEE_SOFTMAC_BEACONS is set */ ++ struct timer_list beacon_timer; ++ ++ struct work_struct associate_complete_wq; ++// struct work_struct associate_retry_wq; ++ struct work_struct associate_procedure_wq; ++// struct work_struct softmac_scan_wq; ++ struct work_struct wx_sync_scan_wq; ++ struct work_struct wmm_param_update_wq; ++ struct work_struct ps_request_tx_ack_wq;//for ps ++// struct work_struct hw_wakeup_wq; ++// struct work_struct hw_sleep_wq; ++// struct work_struct watch_dog_wq; ++ bool bInactivePs; ++ bool actscanning; ++ bool beinretry; ++ u16 ListenInterval; ++ unsigned long NumRxDataInPeriod; //YJ,add,080828 ++ unsigned long NumRxBcnInPeriod; //YJ,add,080828 ++ unsigned long NumRxOkTotal; ++ unsigned long NumRxUnicast;//YJ,add,080828,for keep alive ++ bool bHwRadioOff; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct delayed_work softmac_scan_wq; ++ struct delayed_work associate_retry_wq; ++ struct delayed_work hw_wakeup_wq; ++ struct delayed_work hw_sleep_wq;//+by amy 080324 ++ struct delayed_work watch_dog_wq; ++ struct delayed_work sw_antenna_wq; ++ struct delayed_work start_ibss_wq; ++//by amy for rate adaptive 080312 ++ struct delayed_work rate_adapter_wq; ++//by amy for rate adaptive ++ struct delayed_work hw_dig_wq; ++ struct delayed_work tx_pw_wq; ++ ++//Added for RF power on power off by lizhaoming 080512 ++ struct delayed_work GPIOChangeRFWorkItem; ++#else ++ ++ struct work_struct start_ibss_wq; ++ struct work_struct softmac_scan_wq; ++ struct work_struct associate_retry_wq; ++ struct work_struct hw_wakeup_wq; ++ struct work_struct hw_sleep_wq; ++ struct work_struct watch_dog_wq; ++ struct work_struct sw_antenna_wq; ++//by amy for rate adaptive 080312 ++ struct work_struct rate_adapter_wq; ++//by amy for rate adaptive ++ struct work_struct hw_dig_wq; ++ struct work_struct tx_pw_wq; ++ ++//Added for RF power on power off by lizhaoming 080512 ++ struct work_struct GPIOChangeRFWorkItem; ++#endif ++ struct workqueue_struct *wq; ++ ++ /* Callback functions */ ++ void (*set_security)(struct net_device *dev, ++ struct ieee80211_security *sec); ++ ++ /* Used to TX data frame by using txb structs. ++ * this is not used if in the softmac_features ++ * is set the flag IEEE_SOFTMAC_TX_QUEUE ++ */ ++ int (*hard_start_xmit)(struct ieee80211_txb *txb, ++ struct net_device *dev); ++ ++ int (*reset_port)(struct net_device *dev); ++ ++ /* Softmac-generated frames (mamagement) are TXed via this ++ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is ++ * not set. As some cards may have different HW queues that ++ * one might want to use for data and management frames ++ * the option to have two callbacks might be useful. ++ * This fucntion can't sleep. ++ */ ++ int (*softmac_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* used instead of hard_start_xmit (not softmac_hard_start_xmit) ++ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data ++ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set ++ * then also management frames are sent via this callback. ++ * This function can't sleep. ++ */ ++ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev,int rate); ++ ++ /* stops the HW queue for DATA frames. Useful to avoid ++ * waste time to TX data frame when we are reassociating ++ * This function can sleep. ++ */ ++ void (*data_hard_stop)(struct net_device *dev); ++ ++ /* OK this is complementar to data_poll_hard_stop */ ++ void (*data_hard_resume)(struct net_device *dev); ++ ++ /* ask to the driver to retune the radio . ++ * This function can sleep. the driver should ensure ++ * the radio has been swithced before return. ++ */ ++ void (*set_chan)(struct net_device *dev,short ch); ++ ++ /* These are not used if the ieee stack takes care of ++ * scanning (IEEE_SOFTMAC_SCAN feature set). ++ * In this case only the set_chan is used. ++ * ++ * The syncro version is similar to the start_scan but ++ * does not return until all channels has been scanned. ++ * this is called in user context and should sleep, ++ * it is called in a work_queue when swithcing to ad-hoc mode ++ * or in behalf of iwlist scan when the card is associated ++ * and root user ask for a scan. ++ * the fucntion stop_scan should stop both the syncro and ++ * background scanning and can sleep. ++ * The fucntion start_scan should initiate the background ++ * scanning and can't sleep. ++ */ ++ void (*scan_syncro)(struct net_device *dev); ++ void (*start_scan)(struct net_device *dev); ++ void (*stop_scan)(struct net_device *dev); ++ ++ /* indicate the driver that the link state is changed ++ * for example it may indicate the card is associated now. ++ * Driver might be interested in this to apply RX filter ++ * rules or simply light the LINK led ++ */ ++ void (*link_change)(struct net_device *dev); ++ ++ /* these two function indicates to the HW when to start ++ * and stop to send beacons. This is used when the ++ * IEEE_SOFTMAC_BEACONS is not set. For now the ++ * stop_send_bacons is NOT guaranteed to be called only ++ * after start_send_beacons. ++ */ ++ void (*start_send_beacons) (struct net_device *dev); ++ void (*stop_send_beacons) (struct net_device *dev); ++ ++ /* power save mode related */ ++ void (*sta_wake_up) (struct net_device *dev); ++ void (*ps_request_tx_ack) (struct net_device *dev); ++ void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); ++ short (*ps_is_queue_empty) (struct net_device *dev); ++ ++ /* QoS related */ ++ //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param); ++ //void (*wmm_param_update) (struct ieee80211_device *ieee); ++ ++ /* This must be the last item so that it points to the data ++ * allocated beyond this structure by alloc_ieee80211 */ ++ u8 priv[0]; ++}; ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++/* Generate a 802.11 header */ ++ ++/* Uses the channel change callback directly ++ * instead of [start/stop] scan callbacks ++ */ ++#define IEEE_SOFTMAC_SCAN (1<<2) ++ ++/* Perform authentication and association handshake */ ++#define IEEE_SOFTMAC_ASSOCIATE (1<<3) ++ ++/* Generate probe requests */ ++#define IEEE_SOFTMAC_PROBERQ (1<<4) ++ ++/* Generate respones to probe requests */ ++#define IEEE_SOFTMAC_PROBERS (1<<5) ++ ++/* The ieee802.11 stack will manages the netif queue ++ * wake/stop for the driver, taking care of 802.11 ++ * fragmentation. See softmac.c for details. */ ++#define IEEE_SOFTMAC_TX_QUEUE (1<<7) ++ ++/* Uses only the softmac_data_hard_start_xmit ++ * even for TX management frames. ++ */ ++#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) ++ ++/* Generate beacons. The stack will enqueue beacons ++ * to the card ++ */ ++#define IEEE_SOFTMAC_BEACONS (1<<6) ++ ++ ++ ++static inline void *ieee80211_priv(struct net_device *dev) ++{ ++ return ((struct ieee80211_device *)netdev_priv(dev))->priv; ++} ++ ++extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) ++{ ++ /* ++ * It is possible for both access points and our device to support ++ * combinations of modes, so as long as there is one valid combination ++ * of ap/device supported modes, then return success ++ * ++ */ ++ if ((mode & IEEE_A) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_52GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_G) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_B) && ++ (ieee->modulation & IEEE80211_CCK_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ return 0; ++} ++ ++extern inline int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = 24; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case IEEE80211_FTYPE_DATA: ++ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) ++ hdrlen = 30; /* Addr4 */ ++ if(IEEE80211_QOS_HAS_SEQ(fc)) ++ hdrlen += 2; /* QOS ctrl*/ ++ break; ++ case IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case IEEE80211_STYPE_CTS: ++ case IEEE80211_STYPE_ACK: ++ hdrlen = 10; ++ break; ++ default: ++ hdrlen = 16; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++ ++ ++/* ieee80211.c */ ++extern void free_ieee80211(struct net_device *dev); ++extern struct net_device *alloc_ieee80211(int sizeof_priv); ++ ++extern int ieee80211_set_encryption(struct ieee80211_device *ieee); ++ ++/* ieee80211_tx.c */ ++ ++extern int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len); ++ ++extern int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev); ++extern void ieee80211_txb_free(struct ieee80211_txb *); ++ ++ ++/* ieee80211_rx.c */ ++extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats); ++extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header, ++ struct ieee80211_rx_stats *stats); ++ ++/* ieee80211_wx.c */ ++extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra); ++int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); ++/* ieee80211_softmac.c */ ++extern short ieee80211_is_54g(struct ieee80211_network net); ++extern short ieee80211_is_shortslot(struct ieee80211_network net); ++extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype); ++extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); ++ ++extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); ++extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_ibss(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_init(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_free(struct ieee80211_device *ieee); ++extern void ieee80211_associate_abort(struct ieee80211_device *ieee); ++extern void ieee80211_disassociate(struct ieee80211_device *ieee); ++extern void ieee80211_stop_scan(struct ieee80211_device *ieee); ++extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); ++extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_reset_queue(struct ieee80211_device *ieee); ++extern void ieee80211_wake_queue(struct ieee80211_device *ieee); ++extern void ieee80211_stop_queue(struct ieee80211_device *ieee); ++extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); ++extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); ++extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn); ++extern void ieee80211_start_scan(struct ieee80211_device *ieee); ++ ++//Add for RF power on power off by lizhaoming 080512 ++extern void SendDisassociation(struct ieee80211_device *ieee, ++ u8* asSta, ++ u8 asRsn); ++ ++/* ieee80211_crypt_ccmp&tkip&wep.c */ ++extern void ieee80211_tkip_null(void); ++extern void ieee80211_wep_null(void); ++extern void ieee80211_ccmp_null(void); ++/* ieee80211_softmac_wx.c */ ++ ++extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *ext); ++ ++extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra); ++ ++extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); ++ ++extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); ++#else ++ extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#endif ++//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++ ++extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee); ++ ++extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr); ++ ++extern const long ieee80211_wlan_frequencies[]; ++ ++extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) ++{ ++ ieee->scans++; ++} ++ ++extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) ++{ ++ return ieee->scans; ++} ++ ++static inline const char *escape_essid(const char *essid, u8 essid_len) { ++ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; ++ const char *s = essid; ++ char *d = escaped; ++ ++ if (ieee80211_is_empty_essid(essid, essid_len)) { ++ memcpy(escaped, "", sizeof("")); ++ return escaped; ++ } ++ ++ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); ++ while (essid_len--) { ++ if (*s == '\0') { ++ *d++ = '\\'; ++ *d++ = '0'; ++ s++; ++ } else { ++ *d++ = *s++; ++ } ++ } ++ *d = '\0'; ++ return escaped; ++} ++#endif /* IEEE80211_H */ +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c +@@ -0,0 +1,265 @@ ++/* ++ * Host AP crypto routines ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Portions Copyright (C) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ * ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE ++#endif ++ ++#include "ieee80211.h" ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("HostAP crypto"); ++MODULE_LICENSE("GPL"); ++ ++struct ieee80211_crypto_alg { ++ struct list_head list; ++ struct ieee80211_crypto_ops *ops; ++}; ++ ++ ++struct ieee80211_crypto { ++ struct list_head algs; ++ spinlock_t lock; ++}; ++ ++static struct ieee80211_crypto *hcrypt; ++ ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, ++ int force) ++{ ++ struct list_head *ptr, *n; ++ struct ieee80211_crypt_data *entry; ++ ++ for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; ++ ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { ++ entry = list_entry(ptr, struct ieee80211_crypt_data, list); ++ ++ if (atomic_read(&entry->refcnt) != 0 && !force) ++ continue; ++ ++ list_del(ptr); ++ ++ if (entry->ops) { ++ entry->ops->deinit(entry->priv); ++ module_put(entry->ops->owner); ++ } ++ kfree(entry); ++ } ++} ++ ++void ieee80211_crypt_deinit_handler(unsigned long data) ++{ ++ struct ieee80211_device *ieee = (struct ieee80211_device *)data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ieee80211_crypt_deinit_entries(ieee, 0); ++ if (!list_empty(&ieee->crypt_deinit_list)) { ++ printk(KERN_DEBUG "%s: entries remaining in delayed crypt " ++ "deletion list\n", ieee->dev->name); ++ ieee->crypt_deinit_timer.expires = jiffies + HZ; ++ add_timer(&ieee->crypt_deinit_timer); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt) ++{ ++ struct ieee80211_crypt_data *tmp; ++ unsigned long flags; ++ ++ if (*crypt == NULL) ++ return; ++ ++ tmp = *crypt; ++ *crypt = NULL; ++ ++ /* must not run ops->deinit() while there may be pending encrypt or ++ * decrypt operations. Use a list of delayed deinits to avoid needing ++ * locking. */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ list_add(&tmp->list, &ieee->crypt_deinit_list); ++ if (!timer_pending(&ieee->crypt_deinit_timer)) { ++ ieee->crypt_deinit_timer.expires = jiffies + HZ; ++ add_timer(&ieee->crypt_deinit_timer); ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) ++{ ++ unsigned long flags; ++ struct ieee80211_crypto_alg *alg; ++ ++ if (hcrypt == NULL) ++ return -1; ++ ++ alg = kmalloc(sizeof(*alg), GFP_KERNEL); ++ if (alg == NULL) ++ return -ENOMEM; ++ ++ memset(alg, 0, sizeof(*alg)); ++ alg->ops = ops; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ list_add(&alg->list, &hcrypt->algs); ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", ++ ops->name); ++ ++ return 0; ++} ++ ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) ++{ ++ unsigned long flags; ++ struct list_head *ptr; ++ struct ieee80211_crypto_alg *del_alg = NULL; ++ ++ if (hcrypt == NULL) ++ return -1; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ if (alg->ops == ops) { ++ list_del(&alg->list); ++ del_alg = alg; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ if (del_alg) { ++ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " ++ "'%s'\n", ops->name); ++ kfree(del_alg); ++ } ++ ++ return del_alg ? 0 : -1; ++} ++ ++ ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name) ++{ ++ unsigned long flags; ++ struct list_head *ptr; ++ struct ieee80211_crypto_alg *found_alg = NULL; ++ ++ if (hcrypt == NULL) ++ return NULL; ++ ++ spin_lock_irqsave(&hcrypt->lock, flags); ++ for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ if (strcmp(alg->ops->name, name) == 0) { ++ found_alg = alg; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&hcrypt->lock, flags); ++ ++ if (found_alg) ++ return found_alg->ops; ++ else ++ return NULL; ++} ++ ++ ++static void * ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } ++static void ieee80211_crypt_null_deinit(void *priv) {} ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_null = { ++ .name = "NULL", ++ .init = ieee80211_crypt_null_init, ++ .deinit = ieee80211_crypt_null_deinit, ++ .encrypt_mpdu = NULL, ++ .decrypt_mpdu = NULL, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = NULL, ++ .get_key = NULL, ++ .extra_prefix_len = 0, ++ .extra_postfix_len = 0, ++ .owner = THIS_MODULE, ++}; ++ ++ ++int ieee80211_crypto_init(void) ++{ ++ int ret = -ENOMEM; ++ ++ hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); ++ if (!hcrypt) ++ goto out; ++ ++ memset(hcrypt, 0, sizeof(*hcrypt)); ++ INIT_LIST_HEAD(&hcrypt->algs); ++ spin_lock_init(&hcrypt->lock); ++ ++ ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); ++ if (ret < 0) { ++ kfree(hcrypt); ++ hcrypt = NULL; ++ } ++out: ++ return ret; ++} ++ ++ ++void ieee80211_crypto_deinit(void) ++{ ++ struct list_head *ptr, *n; ++ ++ if (hcrypt == NULL) ++ return; ++ ++ for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; ++ ptr = n, n = ptr->next) { ++ struct ieee80211_crypto_alg *alg = ++ (struct ieee80211_crypto_alg *) ptr; ++ list_del(ptr); ++ printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " ++ "'%s' (deinit)\n", alg->ops->name); ++ kfree(alg); ++ } ++ ++ kfree(hcrypt); ++} ++ ++#if 0 ++EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); ++EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); ++EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); ++ ++EXPORT_SYMBOL(ieee80211_register_crypto_ops); ++EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); ++EXPORT_SYMBOL(ieee80211_get_crypto_ops); ++#endif ++ ++//module_init(ieee80211_crypto_init); ++//module_exit(ieee80211_crypto_deinit); +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c +@@ -0,0 +1,533 @@ ++/* ++ * Host AP crypt: host-based CCMP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2003-2004, Jouni Malinen ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include ++#else ++ #include ++#endif ++ ++//#include ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: CCMP"); ++MODULE_LICENSE("GPL"); ++ ++#ifdef OPENSUSE_SLED ++#ifndef IN_OPENSUSE_SLED ++#define IN_OPENSUSE_SLED 1 ++#endif ++#endif ++ ++#define AES_BLOCK_LEN 16 ++#define CCMP_HDR_LEN 8 ++#define CCMP_MIC_LEN 8 ++#define CCMP_TK_LEN 16 ++#define CCMP_PN_LEN 6 ++ ++struct ieee80211_ccmp_data { ++ u8 key[CCMP_TK_LEN]; ++ int key_set; ++ ++ u8 tx_pn[CCMP_PN_LEN]; ++ u8 rx_pn[CCMP_PN_LEN]; ++ ++ u32 dot11RSNAStatsCCMPFormatErrors; ++ u32 dot11RSNAStatsCCMPReplays; ++ u32 dot11RSNAStatsCCMPDecryptErrors; ++ ++ int key_idx; ++ ++ struct crypto_tfm *tfm; ++ ++ /* scratch buffers for virt_to_page() (crypto API) */ ++ u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], ++ tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; ++ u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; ++}; ++ ++void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, ++ const u8 pt[16], u8 ct[16]) ++{ ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) ++ crypto_cipher_encrypt_one((void *)tfm, ct, pt); ++ #else ++ struct scatterlist src, dst; ++ ++ src.page = virt_to_page(pt); ++ src.offset = offset_in_page(pt); ++ src.length = AES_BLOCK_LEN; ++ ++ dst.page = virt_to_page(ct); ++ dst.offset = offset_in_page(ct); ++ dst.length = AES_BLOCK_LEN; ++ ++ crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); ++ #endif ++} ++ ++static void * ieee80211_ccmp_init(int key_idx) ++{ ++ struct ieee80211_ccmp_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = key_idx; ++ ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) ++ priv->tfm = crypto_alloc_tfm("aes", 0); ++ if (priv->tfm == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " ++ "crypto API aes\n"); ++ goto fail; ++ } ++ #else ++ priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " ++ "crypto API aes\n"); ++ priv->tfm = NULL; ++ goto fail; ++ } ++ #endif ++ return priv; ++ ++fail: ++ if (priv) { ++ if (priv->tfm) ++ //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) ++ crypto_free_tfm(priv->tfm); ++ #else ++ crypto_free_cipher((void *)priv->tfm); ++ #endif ++ kfree(priv); ++ } ++ ++ return NULL; ++} ++ ++ ++static void ieee80211_ccmp_deinit(void *priv) ++{ ++ struct ieee80211_ccmp_data *_priv = priv; ++ if (_priv && _priv->tfm) ++ //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) ++ crypto_free_tfm(_priv->tfm); ++ #else ++ crypto_free_cipher((void *)_priv->tfm); ++ #endif ++ kfree(priv); ++} ++ ++ ++static inline void xor_block(u8 *b, u8 *a, size_t len) ++{ ++ int i; ++ for (i = 0; i < len; i++) ++ b[i] ^= a[i]; ++} ++ ++#ifndef JOHN_CCMP ++static void ccmp_init_blocks(struct crypto_tfm *tfm, ++ struct ieee80211_hdr *hdr, ++ u8 *pn, size_t dlen, u8 *b0, u8 *auth, ++ u8 *s0) ++{ ++ u8 *pos, qc = 0; ++ size_t aad_len; ++ u16 fc; ++ int a4_included, qc_included; ++ u8 aad[2 * AES_BLOCK_LEN]; ++ ++ fc = le16_to_cpu(hdr->frame_ctl); ++ a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); ++ /* ++ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && ++ (WLAN_FC_GET_STYPE(fc) & 0x08)); ++ */ ++ // fixed by David :2006.9.6 ++ qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && ++ (WLAN_FC_GET_STYPE(fc) & 0x80)); ++ aad_len = 22; ++ if (a4_included) ++ aad_len += 6; ++ if (qc_included) { ++ pos = (u8 *) &hdr->addr4; ++ if (a4_included) ++ pos += 6; ++ qc = *pos & 0x0f; ++ aad_len += 2; ++ } ++ /* CCM Initial Block: ++ * Flag (Include authentication header, M=3 (8-octet MIC), ++ * L=1 (2-octet Dlen)) ++ * Nonce: 0x00 | A2 | PN ++ * Dlen */ ++ b0[0] = 0x59; ++ b0[1] = qc; ++ memcpy(b0 + 2, hdr->addr2, ETH_ALEN); ++ memcpy(b0 + 8, pn, CCMP_PN_LEN); ++ b0[14] = (dlen >> 8) & 0xff; ++ b0[15] = dlen & 0xff; ++ ++ /* AAD: ++ * FC with bits 4..6 and 11..13 masked to zero; 14 is always one ++ * A1 | A2 | A3 ++ * SC with bits 4..15 (seq#) masked to zero ++ * A4 (if present) ++ * QC (if present) ++ */ ++ pos = (u8 *) hdr; ++ aad[0] = 0; /* aad_len >> 8 */ ++ aad[1] = aad_len & 0xff; ++ aad[2] = pos[0] & 0x8f; ++ aad[3] = pos[1] & 0xc7; ++ memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); ++ pos = (u8 *) &hdr->seq_ctl; ++ aad[22] = pos[0] & 0x0f; ++ aad[23] = 0; /* all bits masked */ ++ memset(aad + 24, 0, 8); ++ if (a4_included) ++ memcpy(aad + 24, hdr->addr4, ETH_ALEN); ++ if (qc_included) { ++ aad[a4_included ? 30 : 24] = qc; ++ /* rest of QC masked */ ++ } ++ ++ /* Start with the first block and AAD */ ++ ieee80211_ccmp_aes_encrypt(tfm, b0, auth); ++ xor_block(auth, aad, AES_BLOCK_LEN); ++ ieee80211_ccmp_aes_encrypt(tfm, auth, auth); ++ xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); ++ ieee80211_ccmp_aes_encrypt(tfm, auth, auth); ++ b0[0] &= 0x07; ++ b0[14] = b0[15] = 0; ++ ieee80211_ccmp_aes_encrypt(tfm, b0, s0); ++} ++#endif ++ ++static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_ccmp_data *key = priv; ++ int data_len, i; ++ u8 *pos; ++ struct ieee80211_hdr *hdr; ++#ifndef JOHN_CCMP ++ int blocks, last, len; ++ u8 *mic; ++ u8 *b0 = key->tx_b0; ++ u8 *b = key->tx_b; ++ u8 *e = key->tx_e; ++ u8 *s0 = key->tx_s0; ++#endif ++ if (skb_headroom(skb) < CCMP_HDR_LEN || ++ skb_tailroom(skb) < CCMP_MIC_LEN || ++ skb->len < hdr_len) ++ return -1; ++ ++ data_len = skb->len - hdr_len; ++ pos = skb_push(skb, CCMP_HDR_LEN); ++ memmove(pos, pos + CCMP_HDR_LEN, hdr_len); ++ pos += hdr_len; ++// mic = skb_put(skb, CCMP_MIC_LEN); ++ ++ i = CCMP_PN_LEN - 1; ++ while (i >= 0) { ++ key->tx_pn[i]++; ++ if (key->tx_pn[i] != 0) ++ break; ++ i--; ++ } ++ ++ *pos++ = key->tx_pn[5]; ++ *pos++ = key->tx_pn[4]; ++ *pos++ = 0; ++ *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; ++ *pos++ = key->tx_pn[3]; ++ *pos++ = key->tx_pn[2]; ++ *pos++ = key->tx_pn[1]; ++ *pos++ = key->tx_pn[0]; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#ifndef JOHN_CCMP ++ //mic is moved to here by john ++ mic = skb_put(skb, CCMP_MIC_LEN); ++ ++ ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); ++ ++ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; ++ last = data_len % AES_BLOCK_LEN; ++ ++ for (i = 1; i <= blocks; i++) { ++ len = (i == blocks && last) ? last : AES_BLOCK_LEN; ++ /* Authentication */ ++ xor_block(b, pos, len); ++ ieee80211_ccmp_aes_encrypt(key->tfm, b, b); ++ /* Encryption, with counter */ ++ b0[14] = (i >> 8) & 0xff; ++ b0[15] = i & 0xff; ++ ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); ++ xor_block(pos, e, len); ++ pos += len; ++ } ++ ++ for (i = 0; i < CCMP_MIC_LEN; i++) ++ mic[i] = b[i] ^ s0[i]; ++#endif ++ return 0; ++} ++ ++ ++static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_ccmp_data *key = priv; ++ u8 keyidx, *pos; ++ struct ieee80211_hdr *hdr; ++ u8 pn[6]; ++#ifndef JOHN_CCMP ++ size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; ++ u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; ++ u8 *b0 = key->rx_b0; ++ u8 *b = key->rx_b; ++ u8 *a = key->rx_a; ++ int i, blocks, last, len; ++#endif ++ if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { ++ key->dot11RSNAStatsCCMPFormatErrors++; ++ return -1; ++ } ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ pos = skb->data + hdr_len; ++ keyidx = pos[3]; ++ if (!(keyidx & (1 << 5))) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: received packet without ExtIV" ++ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ key->dot11RSNAStatsCCMPFormatErrors++; ++ return -2; ++ } ++ keyidx >>= 6; ++ if (key->key_idx != keyidx) { ++ printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " ++ "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); ++ return -6; ++ } ++ if (!key->key_set) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT ++ " with keyid=%d that does not have a configured" ++ " key\n", MAC_ARG(hdr->addr2), keyidx); ++ } ++ return -3; ++ } ++ ++ pn[0] = pos[7]; ++ pn[1] = pos[6]; ++ pn[2] = pos[5]; ++ pn[3] = pos[4]; ++ pn[4] = pos[1]; ++ pn[5] = pos[0]; ++ pos += 8; ++ ++ if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT ++ " previous PN %02x%02x%02x%02x%02x%02x " ++ "received PN %02x%02x%02x%02x%02x%02x\n", ++ MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), ++ MAC_ARG(pn)); ++ } ++ key->dot11RSNAStatsCCMPReplays++; ++ return -4; ++ } ++ ++#ifndef JOHN_CCMP ++ ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); ++ xor_block(mic, b, CCMP_MIC_LEN); ++ ++ blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; ++ last = data_len % AES_BLOCK_LEN; ++ ++ for (i = 1; i <= blocks; i++) { ++ len = (i == blocks && last) ? last : AES_BLOCK_LEN; ++ /* Decrypt, with counter */ ++ b0[14] = (i >> 8) & 0xff; ++ b0[15] = i & 0xff; ++ ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); ++ xor_block(pos, b, len); ++ /* Authentication */ ++ xor_block(a, pos, len); ++ ieee80211_ccmp_aes_encrypt(key->tfm, a, a); ++ pos += len; ++ } ++ ++ if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "CCMP: decrypt failed: STA=" ++ MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ key->dot11RSNAStatsCCMPDecryptErrors++; ++ return -5; ++ } ++ ++ memcpy(key->rx_pn, pn, CCMP_PN_LEN); ++ ++#endif ++ /* Remove hdr and MIC */ ++ memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); ++ skb_pull(skb, CCMP_HDR_LEN); ++ skb_trim(skb, skb->len - CCMP_MIC_LEN); ++ ++ return keyidx; ++} ++ ++ ++static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_ccmp_data *data = priv; ++ int keyidx; ++ struct crypto_tfm *tfm = data->tfm; ++ ++ keyidx = data->key_idx; ++ memset(data, 0, sizeof(*data)); ++ data->key_idx = keyidx; ++ data->tfm = tfm; ++ if (len == CCMP_TK_LEN) { ++ memcpy(data->key, key, CCMP_TK_LEN); ++ data->key_set = 1; ++ if (seq) { ++ data->rx_pn[0] = seq[5]; ++ data->rx_pn[1] = seq[4]; ++ data->rx_pn[2] = seq[3]; ++ data->rx_pn[3] = seq[2]; ++ data->rx_pn[4] = seq[1]; ++ data->rx_pn[5] = seq[0]; ++ } ++ crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN); ++ } else if (len == 0) ++ data->key_set = 0; ++ else ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_ccmp_data *data = priv; ++ ++ if (len < CCMP_TK_LEN) ++ return -1; ++ ++ if (!data->key_set) ++ return 0; ++ memcpy(key, data->key, CCMP_TK_LEN); ++ ++ if (seq) { ++ seq[0] = data->tx_pn[5]; ++ seq[1] = data->tx_pn[4]; ++ seq[2] = data->tx_pn[3]; ++ seq[3] = data->tx_pn[2]; ++ seq[4] = data->tx_pn[1]; ++ seq[5] = data->tx_pn[0]; ++ } ++ ++ return CCMP_TK_LEN; ++} ++ ++ ++static char * ieee80211_ccmp_print_stats(char *p, void *priv) ++{ ++ struct ieee80211_ccmp_data *ccmp = priv; ++ p += sprintf(p, "key[%d] alg=CCMP key_set=%d " ++ "tx_pn=%02x%02x%02x%02x%02x%02x " ++ "rx_pn=%02x%02x%02x%02x%02x%02x " ++ "format_errors=%d replays=%d decrypt_errors=%d\n", ++ ccmp->key_idx, ccmp->key_set, ++ MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), ++ ccmp->dot11RSNAStatsCCMPFormatErrors, ++ ccmp->dot11RSNAStatsCCMPReplays, ++ ccmp->dot11RSNAStatsCCMPDecryptErrors); ++ ++ return p; ++} ++ ++void ieee80211_ccmp_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { ++ .name = "CCMP", ++ .init = ieee80211_ccmp_init, ++ .deinit = ieee80211_ccmp_deinit, ++ .encrypt_mpdu = ieee80211_ccmp_encrypt, ++ .decrypt_mpdu = ieee80211_ccmp_decrypt, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = ieee80211_ccmp_set_key, ++ .get_key = ieee80211_ccmp_get_key, ++ .print_stats = ieee80211_ccmp_print_stats, ++ .extra_prefix_len = CCMP_HDR_LEN, ++ .extra_postfix_len = CCMP_MIC_LEN, ++ .owner = THIS_MODULE, ++}; ++ ++ ++int ieee80211_crypto_ccmp_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); ++} ++ ++ ++void ieee80211_crypto_ccmp_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); ++} ++ ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_ccmp_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_ccmp_null); ++#endif ++#endif ++ ++//module_init(ieee80211_crypto_ccmp_init); ++//module_exit(ieee80211_crypto_ccmp_exit); +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h +@@ -0,0 +1,86 @@ ++/* ++ * Original code based on Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++/* ++ * This file defines the interface to the ieee80211 crypto module. ++ */ ++#ifndef IEEE80211_CRYPT_H ++#define IEEE80211_CRYPT_H ++ ++#include ++ ++struct ieee80211_crypto_ops { ++ const char *name; ++ ++ /* init new crypto context (e.g., allocate private data space, ++ * select IV, etc.); returns NULL on failure or pointer to allocated ++ * private data on success */ ++ void * (*init)(int keyidx); ++ ++ /* deinitialize crypto context and free allocated private data */ ++ void (*deinit)(void *priv); ++ ++ /* encrypt/decrypt return < 0 on error or >= 0 on success. The return ++ * value from decrypt_mpdu is passed as the keyidx value for ++ * decrypt_msdu. skb must have enough head and tail room for the ++ * encryption; if not, error will be returned; these functions are ++ * called for all MPDUs (i.e., fragments). ++ */ ++ int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ ++ /* These functions are called for full MSDUs, i.e. full frames. ++ * These can be NULL if full MSDU operations are not needed. */ ++ int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); ++ int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, ++ void *priv); ++ ++ int (*set_key)(void *key, int len, u8 *seq, void *priv); ++ int (*get_key)(void *key, int len, u8 *seq, void *priv); ++ ++ /* procfs handler for printing out key information and possible ++ * statistics */ ++ char * (*print_stats)(char *p, void *priv); ++ ++ /* maximum number of bytes added by encryption; encrypt buf is ++ * allocated with extra_prefix_len bytes, copy of in_buf, and ++ * extra_postfix_len; encrypt need not use all this space, but ++ * the result must start at the beginning of the buffer and correct ++ * length must be returned */ ++ int extra_prefix_len, extra_postfix_len; ++ ++ struct module *owner; ++}; ++ ++struct ieee80211_crypt_data { ++ struct list_head list; /* delayed deletion list */ ++ struct ieee80211_crypto_ops *ops; ++ void *priv; ++ atomic_t refcnt; ++}; ++ ++int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); ++int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); ++struct ieee80211_crypto_ops * ieee80211_get_crypto_ops(const char *name); ++void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); ++void ieee80211_crypt_deinit_handler(unsigned long); ++void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, ++ struct ieee80211_crypt_data **crypt); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c +@@ -0,0 +1,1001 @@ ++/* ++ * Host AP crypt: host-based TKIP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2003-2004, Jouni Malinen ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++//#include ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++ #include ++#else ++ #include ++#endif ++ ++#include ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: TKIP"); ++MODULE_LICENSE("GPL"); ++ ++#ifdef OPENSUSE_SLED ++#ifndef IN_OPENSUSE_SLED ++#define IN_OPENSUSE_SLED 1 ++#endif ++#endif ++ ++struct ieee80211_tkip_data { ++#define TKIP_KEY_LEN 32 ++ u8 key[TKIP_KEY_LEN]; ++ int key_set; ++ ++ u32 tx_iv32; ++ u16 tx_iv16; ++ u16 tx_ttak[5]; ++ int tx_phase1_done; ++ ++ u32 rx_iv32; ++ u16 rx_iv16; ++ u16 rx_ttak[5]; ++ int rx_phase1_done; ++ u32 rx_iv32_new; ++ u16 rx_iv16_new; ++ ++ u32 dot11RSNAStatsTKIPReplays; ++ u32 dot11RSNAStatsTKIPICVErrors; ++ u32 dot11RSNAStatsTKIPLocalMICFailures; ++ ++ int key_idx; ++ ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) ++ struct crypto_blkcipher *rx_tfm_arc4; ++ struct crypto_hash *rx_tfm_michael; ++ struct crypto_blkcipher *tx_tfm_arc4; ++ struct crypto_hash *tx_tfm_michael; ++ #endif ++ ++ struct crypto_tfm *tfm_arc4; ++ struct crypto_tfm *tfm_michael; ++ ++ /* scratch buffers for virt_to_page() (crypto API) */ ++ u8 rx_hdr[16], tx_hdr[16]; ++}; ++ ++static void * ieee80211_tkip_init(int key_idx) ++{ ++ struct ieee80211_tkip_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = key_idx; ++ ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); ++ if (priv->tfm_arc4 == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ ++ priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); ++ if (priv->tfm_michael == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ goto fail; ++ } ++ ++ #else ++ priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm_arc4)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ priv->tx_tfm_arc4 = NULL; ++ goto fail; ++ } ++ ++ priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm_michael)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ priv->tx_tfm_michael = NULL; ++ goto fail; ++ } ++ ++ priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm_arc4)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API arc4\n"); ++ priv->rx_tfm_arc4 = NULL; ++ goto fail; ++ } ++ ++ priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, ++ CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm_michael)) { ++ printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " ++ "crypto API michael_mic\n"); ++ priv->rx_tfm_michael = NULL; ++ goto fail; ++ } ++ #endif ++ return priv; ++ ++fail: ++ if (priv) { ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ if (priv->tfm_michael) ++ crypto_free_tfm(priv->tfm_michael); ++ if (priv->tfm_arc4) ++ crypto_free_tfm(priv->tfm_arc4); ++ #else ++ if (priv->tx_tfm_michael) ++ crypto_free_hash(priv->tx_tfm_michael); ++ if (priv->tx_tfm_arc4) ++ crypto_free_blkcipher(priv->tx_tfm_arc4); ++ if (priv->rx_tfm_michael) ++ crypto_free_hash(priv->rx_tfm_michael); ++ if (priv->rx_tfm_arc4) ++ crypto_free_blkcipher(priv->rx_tfm_arc4); ++ #endif ++ kfree(priv); ++ } ++ ++ return NULL; ++} ++ ++ ++static void ieee80211_tkip_deinit(void *priv) ++{ ++ struct ieee80211_tkip_data *_priv = priv; ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ if (_priv && _priv->tfm_michael) ++ crypto_free_tfm(_priv->tfm_michael); ++ if (_priv && _priv->tfm_arc4) ++ crypto_free_tfm(_priv->tfm_arc4); ++ #else ++ if (_priv) { ++ if (_priv->tx_tfm_michael) ++ crypto_free_hash(_priv->tx_tfm_michael); ++ if (_priv->tx_tfm_arc4) ++ crypto_free_blkcipher(_priv->tx_tfm_arc4); ++ if (_priv->rx_tfm_michael) ++ crypto_free_hash(_priv->rx_tfm_michael); ++ if (_priv->rx_tfm_arc4) ++ crypto_free_blkcipher(_priv->rx_tfm_arc4); ++ } ++ #endif ++ kfree(priv); ++} ++ ++ ++static inline u16 RotR1(u16 val) ++{ ++ return (val >> 1) | (val << 15); ++} ++ ++ ++static inline u8 Lo8(u16 val) ++{ ++ return val & 0xff; ++} ++ ++ ++static inline u8 Hi8(u16 val) ++{ ++ return val >> 8; ++} ++ ++ ++static inline u16 Lo16(u32 val) ++{ ++ return val & 0xffff; ++} ++ ++ ++static inline u16 Hi16(u32 val) ++{ ++ return val >> 16; ++} ++ ++ ++static inline u16 Mk16(u8 hi, u8 lo) ++{ ++ return lo | (((u16) hi) << 8); ++} ++ ++ ++static inline u16 Mk16_le(u16 *v) ++{ ++ return le16_to_cpu(*v); ++} ++ ++ ++static const u16 Sbox[256] = ++{ ++ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, ++ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, ++ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, ++ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, ++ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, ++ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, ++ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, ++ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, ++ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, ++ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, ++ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, ++ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, ++ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, ++ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, ++ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, ++ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, ++ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, ++ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, ++ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, ++ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, ++ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, ++ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, ++ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, ++ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, ++ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, ++ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, ++ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, ++ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, ++ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, ++ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, ++ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, ++ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, ++}; ++ ++ ++static inline u16 _S_(u16 v) ++{ ++ u16 t = Sbox[Hi8(v)]; ++ return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); ++} ++ ++#ifndef JOHN_TKIP ++#define PHASE1_LOOP_COUNT 8 ++ ++static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) ++{ ++ int i, j; ++ ++ /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ ++ TTAK[0] = Lo16(IV32); ++ TTAK[1] = Hi16(IV32); ++ TTAK[2] = Mk16(TA[1], TA[0]); ++ TTAK[3] = Mk16(TA[3], TA[2]); ++ TTAK[4] = Mk16(TA[5], TA[4]); ++ ++ for (i = 0; i < PHASE1_LOOP_COUNT; i++) { ++ j = 2 * (i & 1); ++ TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); ++ TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); ++ TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); ++ TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); ++ TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; ++ } ++} ++ ++ ++static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, ++ u16 IV16) ++{ ++ /* Make temporary area overlap WEP seed so that the final copy can be ++ * avoided on little endian hosts. */ ++ u16 *PPK = (u16 *) &WEPSeed[4]; ++ ++ /* Step 1 - make copy of TTAK and bring in TSC */ ++ PPK[0] = TTAK[0]; ++ PPK[1] = TTAK[1]; ++ PPK[2] = TTAK[2]; ++ PPK[3] = TTAK[3]; ++ PPK[4] = TTAK[4]; ++ PPK[5] = TTAK[4] + IV16; ++ ++ /* Step 2 - 96-bit bijective mixing using S-box */ ++ PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); ++ PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); ++ PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); ++ PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); ++ PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); ++ PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); ++ ++ PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); ++ PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); ++ PPK[2] += RotR1(PPK[1]); ++ PPK[3] += RotR1(PPK[2]); ++ PPK[4] += RotR1(PPK[3]); ++ PPK[5] += RotR1(PPK[4]); ++ ++ /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value ++ * WEPSeed[0..2] is transmitted as WEP IV */ ++ WEPSeed[0] = Hi8(IV16); ++ WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; ++ WEPSeed[2] = Lo8(IV16); ++ WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); ++ ++#ifdef __BIG_ENDIAN ++ { ++ int i; ++ for (i = 0; i < 6; i++) ++ PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); ++ } ++#endif ++} ++#endif ++static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; ++ #endif ++ int len; ++ u8 *pos; ++ struct ieee80211_hdr *hdr; ++#ifndef JOHN_TKIP ++ u8 rc4key[16],*icv; ++ u32 crc; ++ struct scatterlist sg; ++#endif ++ int ret; ++ ++ ret = 0; ++ if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || ++ skb->len < hdr_len) ++ return -1; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#if 0 ++printk("@@ tkey\n"); ++printk("%x|", ((u32*)tkey->key)[0]); ++printk("%x|", ((u32*)tkey->key)[1]); ++printk("%x|", ((u32*)tkey->key)[2]); ++printk("%x|", ((u32*)tkey->key)[3]); ++printk("%x|", ((u32*)tkey->key)[4]); ++printk("%x|", ((u32*)tkey->key)[5]); ++printk("%x|", ((u32*)tkey->key)[6]); ++printk("%x\n", ((u32*)tkey->key)[7]); ++#endif ++ ++#ifndef JOHN_TKIP ++ if (!tkey->tx_phase1_done) { ++ tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, ++ tkey->tx_iv32); ++ tkey->tx_phase1_done = 1; ++ } ++ tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); ++ ++#else ++ tkey->tx_phase1_done = 1; ++#endif /*JOHN_TKIP*/ ++ ++ len = skb->len - hdr_len; ++ pos = skb_push(skb, 8); ++ memmove(pos, pos + 8, hdr_len); ++ pos += hdr_len; ++ ++#ifdef JOHN_TKIP ++ *pos++ = Hi8(tkey->tx_iv16); ++ *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; ++ *pos++ = Lo8(tkey->tx_iv16); ++#else ++ *pos++ = rc4key[0]; ++ *pos++ = rc4key[1]; ++ *pos++ = rc4key[2]; ++#endif ++ *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; ++ *pos++ = tkey->tx_iv32 & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 8) & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 16) & 0xff; ++ *pos++ = (tkey->tx_iv32 >> 24) & 0xff; ++#ifndef JOHN_TKIP ++ icv = skb_put(skb, 4); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, len); ++#else ++ crc = ~ether_crc_le(len, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); ++ #else ++ crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ #else ++ sg_init_one(&sg, pos, len+4); ++ #endif ++ ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); ++ #endif ++#endif ++ tkey->tx_iv16++; ++ if (tkey->tx_iv16 == 0) { ++ tkey->tx_phase1_done = 0; ++ tkey->tx_iv32++; ++ } ++#ifndef JOHN_TKIP ++ #if((LINUX_VERSION_CODE = KERNEL_VERSION(2,6,21)) ||(IN_OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4}; ++ #endif ++ u8 keyidx, *pos; ++ u32 iv32; ++ u16 iv16; ++ struct ieee80211_hdr *hdr; ++#ifndef JOHN_TKIP ++ u8 icv[4]; ++ u32 crc; ++ struct scatterlist sg; ++ u8 rc4key[16]; ++ int plen; ++#endif ++ if (skb->len < hdr_len + 8 + 4) ++ return -1; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ pos = skb->data + hdr_len; ++ keyidx = pos[3]; ++ if (!(keyidx & (1 << 5))) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: received packet without ExtIV" ++ " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ return -2; ++ } ++ keyidx >>= 6; ++ if (tkey->key_idx != keyidx) { ++ printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " ++ "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); ++ return -6; ++ } ++ if (!tkey->key_set) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT ++ " with keyid=%d that does not have a configured" ++ " key\n", MAC_ARG(hdr->addr2), keyidx); ++ } ++ return -3; ++ } ++ iv16 = (pos[0] << 8) | pos[2]; ++ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); ++ pos += 8; ++#ifndef JOHN_TKIP ++ ++ if (iv32 < tkey->rx_iv32 || ++ (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT ++ " previous TSC %08x%04x received TSC " ++ "%08x%04x\n", MAC_ARG(hdr->addr2), ++ tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); ++ } ++ tkey->dot11RSNAStatsTKIPReplays++; ++ return -4; ++ } ++ ++ if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { ++ tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); ++ tkey->rx_phase1_done = 1; ++ } ++ tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); ++ ++ plen = skb->len - hdr_len - 12; ++ #if((LINUX_VERSION_CODE tfm_arc4, rc4key, 16); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); ++ #else ++ crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); ++ #if(LINUX_VERSION_CODE addr2)); ++ } ++ return -7; ++ } ++ #endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, plen); ++#else ++ crc = ~ether_crc_le(plen, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ if (memcmp(icv, pos + plen, 4) != 0) { ++ if (iv32 != tkey->rx_iv32) { ++ /* Previously cached Phase1 result was already lost, so ++ * it needs to be recalculated for the next packet. */ ++ tkey->rx_phase1_done = 0; ++ } ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "TKIP: ICV error detected: STA=" ++ MAC_FMT "\n", MAC_ARG(hdr->addr2)); ++ } ++ tkey->dot11RSNAStatsTKIPICVErrors++; ++ return -5; ++ } ++ ++#endif /* JOHN_TKIP */ ++ ++ /* Update real counters only after Michael MIC verification has ++ * completed */ ++ tkey->rx_iv32_new = iv32; ++ tkey->rx_iv16_new = iv16; ++ ++ /* Remove IV and ICV */ ++ memmove(skb->data + 8, skb->data, hdr_len); ++ skb_pull(skb, 8); ++ skb_trim(skb, skb->len - 4); ++ ++//john's test ++#ifdef JOHN_DUMP ++if( ((u16*)skb->data)[0] & 0x4000){ ++ printk("@@ rx decrypted skb->data"); ++ int i; ++ for(i=0;ilen;i++){ ++ if( (i%24)==0 ) printk("\n"); ++ printk("%2x ", ((u8*)skb->data)[i]); ++ } ++ printk("\n"); ++} ++#endif /*JOHN_DUMP*/ ++ return keyidx; ++} ++ ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) && (!IN_OPENSUSE_SLED)) ++static int michael_mic(struct ieee80211_tkip_data *tkey, u8 *key, u8 *hdr, ++ u8 *data, size_t data_len, u8 *mic) ++{ ++ struct scatterlist sg[2]; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct hash_desc desc; ++ int ret=0; ++#endif ++ if (tkey->tfm_michael == NULL) { ++ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); ++ return -1; ++ } ++ sg[0].page = virt_to_page(hdr); ++ sg[0].offset = offset_in_page(hdr); ++ sg[0].length = 16; ++ ++ sg[1].page = virt_to_page(data); ++ sg[1].offset = offset_in_page(data); ++ sg[1].length = data_len; ++ ++ //crypto_digest_init(tkey->tfm_michael); ++ //crypto_digest_setkey(tkey->tfm_michael, key, 8); ++ //crypto_digest_update(tkey->tfm_michael, sg, 2); ++ //crypto_digest_final(tkey->tfm_michael, mic); ++ ++ //return 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ crypto_digest_init(tkey->tfm_michael); ++ crypto_digest_setkey(tkey->tfm_michael, key, 8); ++ crypto_digest_update(tkey->tfm_michael, sg, 2); ++ crypto_digest_final(tkey->tfm_michael, mic); ++ ++ return 0; ++#else ++if (crypto_hash_setkey(tkey->tfm_michael, key, 8)) ++ return -1; ++ ++// return 0; ++ desc.tfm = tkey->tfm_michael; ++ desc.flags = 0; ++ ret = crypto_hash_digest(&desc, sg, data_len + 16, mic); ++ return ret; ++#endif ++} ++#else ++static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, ++ u8 * data, size_t data_len, u8 * mic) ++{ ++ struct hash_desc desc; ++ struct scatterlist sg[2]; ++ ++ if (tfm_michael == NULL) { ++ printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); ++ return -1; ++ } ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg[0].page = virt_to_page(hdr); ++ sg[0].offset = offset_in_page(hdr); ++ sg[0].length = 16; ++ sg[1].page = virt_to_page(data); ++ sg[1].offset = offset_in_page(data); ++ sg[1].length = data_len; ++ #else ++ sg_init_table(sg, 2); ++ sg_set_buf(&sg[0], hdr, 16); ++ sg_set_buf(&sg[1], data, data_len); ++ #endif ++ ++ if (crypto_hash_setkey(tfm_michael, key, 8)) ++ return -1; ++ ++ desc.tfm = tfm_michael; ++ desc.flags = 0; ++ return crypto_hash_digest(&desc, sg, data_len + 16, mic); ++} ++#endif ++ ++ ++ ++static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) ++{ ++ struct ieee80211_hdr *hdr11; ++ ++ hdr11 = (struct ieee80211_hdr *) skb->data; ++ switch (le16_to_cpu(hdr11->frame_ctl) & ++ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { ++ case IEEE80211_FCTL_TODS: ++ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ ++ break; ++ case IEEE80211_FCTL_FROMDS: ++ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ ++ break; ++ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: ++ memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ ++ break; ++ case 0: ++ memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ ++ memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ ++ break; ++ } ++ ++ hdr[12] = 0; /* priority */ ++ ++ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ ++} ++ ++ ++static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 *pos; ++ struct ieee80211_hdr *hdr; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { ++ printk(KERN_DEBUG "Invalid packet for Michael MIC add " ++ "(tailroom=%d hdr_len=%d skb->len=%d)\n", ++ skb_tailroom(skb), hdr_len, skb->len); ++ return -1; ++ } ++ ++ michael_mic_hdr(skb, tkey->tx_hdr); ++ ++ // { david, 2006.9.1 ++ // fix the wpa process with wmm enabled. ++ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { ++ tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; ++ } ++ // } ++ pos = skb_put(skb, 8); ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) ++ #else ++ if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) ++ #endif ++ return -1; ++ ++ return 0; ++} ++ ++ ++#if WIRELESS_EXT >= 18 ++static void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr *hdr, ++ int keyidx) ++{ ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure ev; ++ ++ /* TODO: needed parameters: count, keyid, key type, TSC */ ++ memset(&ev, 0, sizeof(ev)); ++ ev.flags = keyidx & IW_MICFAILURE_KEY_ID; ++ if (hdr->addr1[0] & 0x01) ++ ev.flags |= IW_MICFAILURE_GROUP; ++ else ++ ev.flags |= IW_MICFAILURE_PAIRWISE; ++ ev.src_addr.sa_family = ARPHRD_ETHER; ++ memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(ev); ++ wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); ++} ++#elif WIRELESS_EXT >= 15 ++static void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr *hdr, ++ int keyidx) ++{ ++ union iwreq_data wrqu; ++ char buf[128]; ++ ++ /* TODO: needed parameters: count, keyid, key type, TSC */ ++ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" ++ MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", ++ MAC_ARG(hdr->addr2)); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = strlen(buf); ++ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); ++} ++#else /* WIRELESS_EXT >= 15 */ ++static inline void ieee80211_michael_mic_failure(struct net_device *dev, ++ struct ieee80211_hdr *hdr, ++ int keyidx) ++{ ++} ++#endif /* WIRELESS_EXT >= 15 */ ++ ++ ++static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, ++ int hdr_len, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ u8 mic[8]; ++ struct ieee80211_hdr *hdr; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ if (!tkey->key_set) ++ return -1; ++ ++ michael_mic_hdr(skb, tkey->rx_hdr); ++ // { david, 2006.9.1 ++ // fix the wpa process with wmm enabled. ++ if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) { ++ tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; ++ } ++ // } ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) ++ #else ++ if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, ++ skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) ++ #endif ++ return -1; ++ if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { ++ struct ieee80211_hdr *hdr; ++ hdr = (struct ieee80211_hdr *) skb->data; ++ printk(KERN_DEBUG "%s: Michael MIC verification failed for " ++ "MSDU from " MAC_FMT " keyidx=%d\n", ++ skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), ++ keyidx); ++ if (skb->dev) ++ ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); ++ tkey->dot11RSNAStatsTKIPLocalMICFailures++; ++ return -1; ++ } ++ ++ /* Update TSC counters for RX now that the packet verification has ++ * completed. */ ++ tkey->rx_iv32 = tkey->rx_iv32_new; ++ tkey->rx_iv16 = tkey->rx_iv16_new; ++ ++ skb_trim(skb, skb->len - 8); ++ ++ return 0; ++} ++ ++ ++static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ int keyidx; ++ #if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ struct crypto_tfm *tfm = tkey->tfm_michael; ++ struct crypto_tfm *tfm2 = tkey->tfm_arc4; ++ #else ++ struct crypto_hash *tfm = tkey->tx_tfm_michael; ++ struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; ++ struct crypto_hash *tfm3 = tkey->rx_tfm_michael; ++ struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; ++ #endif ++ ++ keyidx = tkey->key_idx; ++ memset(tkey, 0, sizeof(*tkey)); ++ tkey->key_idx = keyidx; ++ ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ tkey->tfm_michael = tfm; ++ tkey->tfm_arc4 = tfm2; ++ #else ++ tkey->tx_tfm_michael = tfm; ++ tkey->tx_tfm_arc4 = tfm2; ++ tkey->rx_tfm_michael = tfm3; ++ tkey->rx_tfm_arc4 = tfm4; ++ #endif ++ ++ if (len == TKIP_KEY_LEN) { ++ memcpy(tkey->key, key, TKIP_KEY_LEN); ++ tkey->key_set = 1; ++ tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ ++ if (seq) { ++ tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | ++ (seq[3] << 8) | seq[2]; ++ tkey->rx_iv16 = (seq[1] << 8) | seq[0]; ++ } ++ } else if (len == 0) ++ tkey->key_set = 0; ++ else ++ return -1; ++ ++ return 0; ++} ++ ++ ++static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct ieee80211_tkip_data *tkey = priv; ++ ++ if (len < TKIP_KEY_LEN) ++ return -1; ++ ++ if (!tkey->key_set) ++ return 0; ++ memcpy(key, tkey->key, TKIP_KEY_LEN); ++ ++ if (seq) { ++ /* Return the sequence number of the last transmitted frame. */ ++ u16 iv16 = tkey->tx_iv16; ++ u32 iv32 = tkey->tx_iv32; ++ if (iv16 == 0) ++ iv32--; ++ iv16--; ++ seq[0] = tkey->tx_iv16; ++ seq[1] = tkey->tx_iv16 >> 8; ++ seq[2] = tkey->tx_iv32; ++ seq[3] = tkey->tx_iv32 >> 8; ++ seq[4] = tkey->tx_iv32 >> 16; ++ seq[5] = tkey->tx_iv32 >> 24; ++ } ++ ++ return TKIP_KEY_LEN; ++} ++ ++ ++static char * ieee80211_tkip_print_stats(char *p, void *priv) ++{ ++ struct ieee80211_tkip_data *tkip = priv; ++ p += sprintf(p, "key[%d] alg=TKIP key_set=%d " ++ "tx_pn=%02x%02x%02x%02x%02x%02x " ++ "rx_pn=%02x%02x%02x%02x%02x%02x " ++ "replays=%d icv_errors=%d local_mic_failures=%d\n", ++ tkip->key_idx, tkip->key_set, ++ (tkip->tx_iv32 >> 24) & 0xff, ++ (tkip->tx_iv32 >> 16) & 0xff, ++ (tkip->tx_iv32 >> 8) & 0xff, ++ tkip->tx_iv32 & 0xff, ++ (tkip->tx_iv16 >> 8) & 0xff, ++ tkip->tx_iv16 & 0xff, ++ (tkip->rx_iv32 >> 24) & 0xff, ++ (tkip->rx_iv32 >> 16) & 0xff, ++ (tkip->rx_iv32 >> 8) & 0xff, ++ tkip->rx_iv32 & 0xff, ++ (tkip->rx_iv16 >> 8) & 0xff, ++ tkip->rx_iv16 & 0xff, ++ tkip->dot11RSNAStatsTKIPReplays, ++ tkip->dot11RSNAStatsTKIPICVErrors, ++ tkip->dot11RSNAStatsTKIPLocalMICFailures); ++ return p; ++} ++ ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { ++ .name = "TKIP", ++ .init = ieee80211_tkip_init, ++ .deinit = ieee80211_tkip_deinit, ++ .encrypt_mpdu = ieee80211_tkip_encrypt, ++ .decrypt_mpdu = ieee80211_tkip_decrypt, ++ .encrypt_msdu = ieee80211_michael_mic_add, ++ .decrypt_msdu = ieee80211_michael_mic_verify, ++ .set_key = ieee80211_tkip_set_key, ++ .get_key = ieee80211_tkip_get_key, ++ .print_stats = ieee80211_tkip_print_stats, ++ .extra_prefix_len = 4 + 4, /* IV + ExtIV */ ++ .extra_postfix_len = 8 + 4, /* MIC + ICV */ ++ .owner = THIS_MODULE, ++}; ++ ++ ++int ieee80211_crypto_tkip_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); ++} ++ ++ ++void ieee80211_crypto_tkip_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); ++} ++ ++ ++void ieee80211_tkip_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++ ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_tkip_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_tkip_null); ++#endif ++#endif ++ ++ ++//module_init(ieee80211_crypto_tkip_init); ++//module_exit(ieee80211_crypto_tkip_exit); +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c +@@ -0,0 +1,394 @@ ++/* ++ * Host AP crypt: host-based WEP encryption implementation for Host AP driver ++ * ++ * Copyright (c) 2002-2004, Jouni Malinen ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) ++#include "rtl_crypto.h" ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ #include ++#else ++ #include ++#endif ++//#include ++#include ++ ++MODULE_AUTHOR("Jouni Malinen"); ++MODULE_DESCRIPTION("Host AP crypt: WEP"); ++MODULE_LICENSE("GPL"); ++ ++#ifdef OPENSUSE_SLED ++#ifndef IN_OPENSUSE_SLED ++#define IN_OPENSUSE_SLED 1 ++#endif ++#endif ++ ++ ++struct prism2_wep_data { ++ u32 iv; ++#define WEP_KEY_LEN 13 ++ u8 key[WEP_KEY_LEN + 1]; ++ u8 key_len; ++ u8 key_idx; ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ struct crypto_tfm *tfm; ++ #else ++ struct crypto_blkcipher *tx_tfm; ++ struct crypto_blkcipher *rx_tfm; ++ #endif ++}; ++ ++ ++static void * prism2_wep_init(int keyidx) ++{ ++ struct prism2_wep_data *priv; ++ ++ priv = kmalloc(sizeof(*priv), GFP_ATOMIC); ++ if (priv == NULL) ++ goto fail; ++ memset(priv, 0, sizeof(*priv)); ++ priv->key_idx = keyidx; ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ priv->tfm = crypto_alloc_tfm("arc4", 0); ++ if (priv->tfm == NULL) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ goto fail; ++ } ++ #else ++ priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->tx_tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ priv->tx_tfm = NULL; ++ goto fail; ++ } ++ priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); ++ if (IS_ERR(priv->rx_tfm)) { ++ printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " ++ "crypto API arc4\n"); ++ priv->rx_tfm = NULL; ++ goto fail; ++ } ++ #endif ++ ++ /* start WEP IV from a random value */ ++ get_random_bytes(&priv->iv, 4); ++ ++ return priv; ++ ++fail: ++ //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ if (priv) { ++ if (priv->tfm) ++ crypto_free_tfm(priv->tfm); ++ kfree(priv); ++ } ++ #else ++ if (priv) { ++ if (priv->tx_tfm) ++ crypto_free_blkcipher(priv->tx_tfm); ++ if (priv->rx_tfm) ++ crypto_free_blkcipher(priv->rx_tfm); ++ kfree(priv); ++ } ++ #endif ++ return NULL; ++} ++ ++ ++static void prism2_wep_deinit(void *priv) ++{ ++ struct prism2_wep_data *_priv = priv; ++ //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ if (_priv && _priv->tfm) ++ crypto_free_tfm(_priv->tfm); ++ #else ++ if (_priv) { ++ if (_priv->tx_tfm) ++ crypto_free_blkcipher(_priv->tx_tfm); ++ if (_priv->rx_tfm) ++ crypto_free_blkcipher(_priv->rx_tfm); ++ } ++ #endif ++ kfree(priv); ++} ++ ++ ++/* Perform WEP encryption on given skb that has at least 4 bytes of headroom ++ * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, ++ * so the payload length increases with 8 bytes. ++ * ++ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) ++ */ ++static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++//#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = wep->tx_tfm}; ++#endif ++ u32 klen, len; ++ u8 key[WEP_KEY_LEN + 3]; ++ u8 *pos; ++#ifndef JOHN_HWSEC ++ u32 crc; ++ u8 *icv; ++ struct scatterlist sg; ++#endif ++ if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || ++ skb->len < hdr_len) ++ return -1; ++ ++ len = skb->len - hdr_len; ++ pos = skb_push(skb, 4); ++ memmove(pos, pos + 4, hdr_len); ++ pos += hdr_len; ++ ++ klen = 3 + wep->key_len; ++ ++ wep->iv++; ++ ++ /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key ++ * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) ++ * can be used to speedup attacks, so avoid using them. */ ++ if ((wep->iv & 0xff00) == 0xff00) { ++ u8 B = (wep->iv >> 16) & 0xff; ++ if (B >= 3 && B < klen) ++ wep->iv += 0x0100; ++ } ++ ++ /* Prepend 24-bit IV to RC4 key and TX frame */ ++ *pos++ = key[0] = (wep->iv >> 16) & 0xff; ++ *pos++ = key[1] = (wep->iv >> 8) & 0xff; ++ *pos++ = key[2] = wep->iv & 0xff; ++ *pos++ = wep->key_idx << 6; ++ ++ /* Copy rest of the WEP key (the secret part) */ ++ memcpy(key + 3, wep->key, wep->key_len); ++ ++#ifndef JOHN_HWSEC ++ /* Append little-endian CRC32 and encrypt it to produce ICV */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, len); ++#else ++ crc = ~ether_crc_le(len, pos); ++#endif ++ icv = skb_put(skb, 4); ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++ //#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++ #if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ crypto_cipher_setkey(wep->tfm, key, klen); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); ++ ++ return 0; ++ #else ++ crypto_blkcipher_setkey(wep->tx_tfm, key, klen); ++ #if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = len + 4; ++ #else ++ sg_init_one(&sg, pos, len+4); ++ #endif ++ return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); ++ #endif ++#endif /* JOHN_HWSEC */ ++ return 0; ++} ++ ++ ++/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of ++ * the frame: IV (4 bytes), encrypted payload (including SNAP header), ++ * ICV (4 bytes). len includes both IV and ICV. ++ * ++ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on ++ * failure. If frame is OK, IV and ICV will be removed. ++ */ ++static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ //#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++ #if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))||(IN_OPENSUSE_SLED)) ++ struct blkcipher_desc desc = {.tfm = wep->rx_tfm}; ++ #endif ++ u32 klen, plen; ++ u8 key[WEP_KEY_LEN + 3]; ++ u8 keyidx, *pos; ++#ifndef JOHN_HWSEC ++ u32 crc; ++ u8 icv[4]; ++ struct scatterlist sg; ++#endif ++ if (skb->len < hdr_len + 8) ++ return -1; ++ ++ pos = skb->data + hdr_len; ++ key[0] = *pos++; ++ key[1] = *pos++; ++ key[2] = *pos++; ++ keyidx = *pos++ >> 6; ++ if (keyidx != wep->key_idx) ++ return -1; ++ ++ klen = 3 + wep->key_len; ++ ++ /* Copy rest of the WEP key (the secret part) */ ++ memcpy(key + 3, wep->key, wep->key_len); ++ ++ /* Apply RC4 to data and compute CRC32 over decrypted data */ ++ plen = skb->len - hdr_len - 8; ++#ifndef JOHN_HWSEC ++//#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)) ++#if((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))&&(!IN_OPENSUSE_SLED)) ++ crypto_cipher_setkey(wep->tfm, key, klen); ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); ++#else ++ crypto_blkcipher_setkey(wep->rx_tfm, key, klen); ++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) ++ sg.page = virt_to_page(pos); ++ sg.offset = offset_in_page(pos); ++ sg.length = plen + 4; ++ #else ++ sg_init_one(&sg, pos, plen+4); ++ #endif ++ if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) ++ return -7; ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++ crc = ~crc32_le(~0, pos, plen); ++#else ++ crc = ~ether_crc_le(plen, pos); ++#endif ++ icv[0] = crc; ++ icv[1] = crc >> 8; ++ icv[2] = crc >> 16; ++ icv[3] = crc >> 24; ++ ++ if (memcmp(icv, pos + plen, 4) != 0) { ++ /* ICV mismatch - drop frame */ ++ return -2; ++ } ++#endif /* JOHN_HWSEC */ ++ ++ /* Remove IV and ICV */ ++ memmove(skb->data + 4, skb->data, hdr_len); ++ skb_pull(skb, 4); ++ skb_trim(skb, skb->len - 4); ++ return 0; ++} ++ ++ ++static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ ++ if (len < 0 || len > WEP_KEY_LEN) ++ return -1; ++ ++ memcpy(wep->key, key, len); ++ wep->key_len = len; ++ ++ return 0; ++} ++ ++ ++static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ ++ if (len < wep->key_len) ++ return -1; ++ ++ memcpy(key, wep->key, wep->key_len); ++ ++ return wep->key_len; ++} ++ ++ ++static char * prism2_wep_print_stats(char *p, void *priv) ++{ ++ struct prism2_wep_data *wep = priv; ++ p += sprintf(p, "key[%d] alg=WEP len=%d\n", ++ wep->key_idx, wep->key_len); ++ return p; ++} ++ ++ ++static struct ieee80211_crypto_ops ieee80211_crypt_wep = { ++ .name = "WEP", ++ .init = prism2_wep_init, ++ .deinit = prism2_wep_deinit, ++ .encrypt_mpdu = prism2_wep_encrypt, ++ .decrypt_mpdu = prism2_wep_decrypt, ++ .encrypt_msdu = NULL, ++ .decrypt_msdu = NULL, ++ .set_key = prism2_wep_set_key, ++ .get_key = prism2_wep_get_key, ++ .print_stats = prism2_wep_print_stats, ++ .extra_prefix_len = 4, /* IV */ ++ .extra_postfix_len = 4, /* ICV */ ++ .owner = THIS_MODULE, ++}; ++ ++ ++int ieee80211_crypto_wep_init(void) ++{ ++ return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); ++} ++ ++ ++void ieee80211_crypto_wep_exit(void) ++{ ++ ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); ++} ++ ++ ++void ieee80211_wep_null(void) ++{ ++// printk("============>%s()\n", __FUNCTION__); ++ return; ++} ++#if 0 ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++EXPORT_SYMBOL(ieee80211_wep_null); ++#else ++EXPORT_SYMBOL_NOVERS(ieee80211_wep_null); ++#endif ++#endif ++//module_init(ieee80211_crypto_wep_init); ++//module_exit(ieee80211_crypto_wep_exit); +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h +@@ -0,0 +1,1755 @@ ++/* ++ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 ++ * remains copyright by the original authors ++ * ++ * Portions of the merged code are based on Host AP (software wireless ++ * LAN access point) driver for Intersil Prism2/2.5/3. ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * ++ * Adaption to a generic IEEE 802.11 stack by James Ketrenos ++ * ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * Modified for Realtek's wi-fi cards by Andrea Merello ++ * ++ * ++ * 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. See README and COPYING for ++ * more details. ++ */ ++#ifndef IEEE80211_H ++#define IEEE80211_H ++#include /* ETH_ALEN */ ++#include /* ARRAY_SIZE */ ++#include ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) ++#include ++#endif ++ ++/* ++#ifndef bool ++#define bool int ++#endif ++ ++#ifndef true ++#define true 1 ++#endif ++ ++#ifndef false ++#define false 0 ++#endif ++*/ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) ++#ifndef bool ++typedef enum{false = 0, true} bool; ++#endif ++#endif ++//#ifdef JOHN_HWSEC ++#define KEY_TYPE_NA 0x0 ++#define KEY_TYPE_WEP40 0x1 ++#define KEY_TYPE_TKIP 0x2 ++#define KEY_TYPE_CCMP 0x4 ++#define KEY_TYPE_WEP104 0x5 ++//#endif ++ ++ ++#define aSifsTime 10 ++ ++#define MGMT_QUEUE_NUM 5 ++ ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++//It should consistent with the driver_XXX.c ++// David, 2006.9.26 ++#define IEEE_PARAM_WPAX_SELECT 7 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_PROTO_WPA 1 ++#define IEEE_PROTO_RSN 2 ++//Added for notify the encryption type selection ++// David, 2006.9.26 ++#define IEEE_WPAX_USEGROUP 0 ++#define IEEE_WPAX_WEP40 1 ++#define IEEE_WPAX_TKIP 2 ++#define IEEE_WPAX_WRAP 3 ++#define IEEE_WPAX_CCMP 4 ++#define IEEE_WPAX_WEP104 5 ++ ++#define IEEE_KEY_MGMT_IEEE8021X 1 ++#define IEEE_KEY_MGMT_PSK 2 ++ ++ ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) ++#define ieee80211_wx_get_scan ieee80211_wx_get_scan_rtl ++#define ieee80211_wx_set_encode ieee80211_wx_set_encode_rtl ++#define ieee80211_wx_get_encode ieee80211_wx_get_encode_rtl ++//////////////////////////////// ++// added for kernel conflict under FC5 ++#define ieee80211_wx_get_name ieee80211_wx_get_name_rtl ++#define free_ieee80211 free_ieee80211_rtl ++#define alloc_ieee80211 alloc_ieee80211_rtl ++/////////////////////////////// ++#endif ++//error in ubuntu2.6.22,so add these ++#define ieee80211_wake_queue ieee80211_wake_queue_rtl ++#define ieee80211_stop_queue ieee80211_stop_queue_rtl ++ ++#define ieee80211_rx ieee80211_rx_rtl ++ ++#define ieee80211_register_crypto_ops ieee80211_register_crypto_ops_rtl ++#define ieee80211_unregister_crypto_ops ieee80211_unregister_crypto_ops_rtl ++#define ieee80211_get_crypto_ops ieee80211_get_crypto_ops_rtl ++#define ieee80211_crypt_deinit_entries ieee80211_crypt_deinit_entries_rtl ++#define ieee80211_crypt_deinit_handler ieee80211_crypt_deinit_handler_rtl ++#define ieee80211_crypt_delayed_deinit ieee80211_crypt_delayed_deinit_rtl ++ ++#define ieee80211_txb_free ieee80211_txb_free_rtl ++#define ieee80211_wx_get_essid ieee80211_wx_get_essid_rtl ++#define ieee80211_wx_set_essid ieee80211_wx_set_essid_rtl ++#define ieee80211_wx_set_rate ieee80211_wx_set_rate_rtl ++#define ieee80211_wx_get_rate ieee80211_wx_get_rate_rtl ++#define ieee80211_wx_set_wap ieee80211_wx_set_wap_rtl ++#define ieee80211_wx_get_wap ieee80211_wx_get_wap_rtl ++#define ieee80211_wx_set_mode ieee80211_wx_set_mode_rtl ++#define ieee80211_wx_get_mode ieee80211_wx_get_mode_rtl ++#define ieee80211_wx_set_scan ieee80211_wx_set_scan_rtl ++#define ieee80211_wx_get_freq ieee80211_wx_get_freq_rtl ++#define ieee80211_wx_set_freq ieee80211_wx_set_freq_rtl ++#define ieee80211_wx_set_rawtx ieee80211_wx_set_rawtx_rtl ++#define ieee80211_wx_set_power ieee80211_wx_set_power_rtl ++#define ieee80211_wx_get_power ieee80211_wx_get_power_rtl ++#define ieee80211_wlan_frequencies ieee80211_wlan_frequencies_rtl ++#define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rtl ++#define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rtl ++#define ieee80211_start_protocol ieee80211_start_protocol_rtl ++#define ieee80211_stop_protocol ieee80211_stop_protocol_rtl ++#define ieee80211_rx_mgt ieee80211_rx_mgt_rtl ++ ++#define ieee80211_wx_set_auth ieee80211_wx_set_auth_rtl ++//by amy for ps ++#define notify_wx_assoc_event notify_wx_assoc_event_rtl ++#define ieee80211_stop_send_beacons ieee80211_stop_send_beacons_rtl ++#define ieee80211_disassociate ieee80211_disassociate_rtl ++#define ieee80211_start_scan ieee80211_start_scan_rtl ++//by amy for ps ++typedef struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct{ ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++ ++ } u; ++}ieee_param; ++ ++ ++#if WIRELESS_EXT < 17 ++#define IW_QUAL_QUAL_INVALID 0x10 ++#define IW_QUAL_LEVEL_INVALID 0x20 ++#define IW_QUAL_NOISE_INVALID 0x40 ++#define IW_QUAL_QUAL_UPDATED 0x1 ++#define IW_QUAL_LEVEL_UPDATED 0x2 ++#define IW_QUAL_NOISE_UPDATED 0x4 ++#endif ++ ++// linux under 2.6.9 release may not support it, so modify it for common use ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) ++#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ) ++static inline unsigned long msleep_interruptible_rtl(unsigned int msecs) ++{ ++ unsigned long timeout = MSECS(msecs) + 1; ++ ++ while (timeout) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = schedule_timeout(timeout); ++ } ++ return timeout; ++} ++#else ++#define MSECS(t) msecs_to_jiffies(t) ++#define msleep_interruptible_rtl msleep_interruptible ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++ ++ ++#define IEEE80211_HLEN 30 ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++ ++/* this is stolen and modified from the madwifi driver*/ ++#define IEEE80211_FC0_TYPE_MASK 0x0c ++#define IEEE80211_FC0_TYPE_DATA 0x08 ++#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 ++#define IEEE80211_FC0_SUBTYPE_QOS 0x80 ++ ++#define IEEE80211_QOS_HAS_SEQ(fc) \ ++ (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ ++ (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num[17]; ++ u16 frag_num[17]; ++ unsigned long packet_time[17]; ++ struct list_head list; ++}; ++ ++struct ieee80211_hdr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_QOS { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u16 QOS_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++} __attribute__ ((packed)); ++ ++struct ieee80211_hdr_3addr_QOS { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u16 QOS_ctl; ++} __attribute__ ((packed)); ++ ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++static const char *eap_types[] = { ++ [EAP_PACKET] = "EAP-Packet", ++ [EAPOL_START] = "EAPOL-Start", ++ [EAPOL_LOGOFF] = "EAPOL-Logoff", ++ [EAPOL_KEY] = "EAPOL-Key", ++ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" ++}; ++ ++static inline const char *eap_get_type(int type) ++{ ++ return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; ++} ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __attribute__ ((packed)); ++ ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++/* Frame control field constants */ ++#define IEEE80211_FCTL_VERS 0x0002 ++#define IEEE80211_FCTL_FTYPE 0x000c ++#define IEEE80211_FCTL_STYPE 0x00f0 ++#define IEEE80211_FCTL_TODS 0x0100 ++#define IEEE80211_FCTL_FROMDS 0x0200 ++#define IEEE80211_FCTL_DSTODS 0x0300 //added by david ++#define IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define IEEE80211_FCTL_RETRY 0x0800 ++#define IEEE80211_FCTL_PM 0x1000 ++#define IEEE80211_FCTL_MOREDATA 0x2000 ++#define IEEE80211_FCTL_WEP 0x4000 ++#define IEEE80211_FCTL_ORDER 0x8000 ++ ++#define IEEE80211_FTYPE_MGMT 0x0000 ++#define IEEE80211_FTYPE_CTL 0x0004 ++#define IEEE80211_FTYPE_DATA 0x0008 ++ ++/* management */ ++#define IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define IEEE80211_STYPE_BEACON 0x0080 ++#define IEEE80211_STYPE_ATIM 0x0090 ++#define IEEE80211_STYPE_DISASSOC 0x00A0 ++#define IEEE80211_STYPE_AUTH 0x00B0 ++#define IEEE80211_STYPE_DEAUTH 0x00C0 ++#define IEEE80211_STYPE_MANAGE_ACT 0x00D0 ++ ++/* control */ ++#define IEEE80211_STYPE_PSPOLL 0x00A0 ++#define IEEE80211_STYPE_RTS 0x00B0 ++#define IEEE80211_STYPE_CTS 0x00C0 ++#define IEEE80211_STYPE_ACK 0x00D0 ++#define IEEE80211_STYPE_CFEND 0x00E0 ++#define IEEE80211_STYPE_CFENDACK 0x00F0 ++ ++/* data */ ++#define IEEE80211_STYPE_DATA 0x0000 ++#define IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define IEEE80211_STYPE_NULLFUNC 0x0040 ++#define IEEE80211_STYPE_CFACK 0x0050 ++#define IEEE80211_STYPE_CFPOLL 0x0060 ++#define IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define IEEE80211_STYPE_QOS_DATA 0x0080 //added for WMM 2006/8/2 ++#define IEEE80211_STYPE_QOS_NULL 0x00C0 ++ ++ ++#define IEEE80211_SCTL_FRAG 0x000F ++#define IEEE80211_SCTL_SEQ 0xFFF0 ++ ++ ++/* debug macros */ ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++extern u32 ieee80211_debug_level; ++#define IEEE80211_DEBUG(level, fmt, args...) \ ++do { if (ieee80211_debug_level & (level)) \ ++ printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ ++ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) ++#else ++#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) ++#endif /* CONFIG_IEEE80211_DEBUG */ ++ ++/* ++ * To use the debug system; ++ * ++ * If you are defining a new debug classification, simply add it to the #define ++ * list here in the form of: ++ * ++ * #define IEEE80211_DL_xxxx VALUE ++ * ++ * shifting value to the left one bit from the previous entry. xxxx should be ++ * the name of the classification (for example, WEP) ++ * ++ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your ++ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want ++ * to send output to that classification. ++ * ++ * To add your debug level to the list of levels seen when you perform ++ * ++ * % cat /proc/net/ipw/debug_level ++ * ++ * you simply need to add your entry to the ipw_debug_levels array. ++ * ++ * If you do not see debug_level in /proc/net/ipw then you do not have ++ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration ++ * ++ */ ++ ++#define IEEE80211_DL_INFO (1<<0) ++#define IEEE80211_DL_WX (1<<1) ++#define IEEE80211_DL_SCAN (1<<2) ++#define IEEE80211_DL_STATE (1<<3) ++#define IEEE80211_DL_MGMT (1<<4) ++#define IEEE80211_DL_FRAG (1<<5) ++#define IEEE80211_DL_EAP (1<<6) ++#define IEEE80211_DL_DROP (1<<7) ++ ++#define IEEE80211_DL_TX (1<<8) ++#define IEEE80211_DL_RX (1<<9) ++ ++#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) ++#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) ++#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) ++ ++#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) ++#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) ++//#define IEEE_DEBUG_SCAN IEEE80211_WARNING ++#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) ++#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) ++#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) ++#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) ++#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) ++#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) ++#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) ++#include ++#include ++#include /* ARPHRD_ETHER */ ++ ++#ifndef WIRELESS_SPY ++#define WIRELESS_SPY // enable iwspy support ++#endif ++#include // new driver API ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++struct ieee80211_snap_hdr { ++ ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++ ++} __attribute__ ((packed)); ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) ++ ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++ ++/* Status codes */ ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 ++/* 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++ ++/* Reason codes */ ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 ++ ++ ++/* Information Element IDs */ ++#define WLAN_EID_SSID 0 ++#define WLAN_EID_SUPP_RATES 1 ++#define WLAN_EID_FH_PARAMS 2 ++#define WLAN_EID_DS_PARAMS 3 ++#define WLAN_EID_CF_PARAMS 4 ++#define WLAN_EID_TIM 5 ++#define WLAN_EID_IBSS_PARAMS 6 ++#define WLAN_EID_CHALLENGE 16 ++#define WLAN_EID_RSN 48 ++#define WLAN_EID_GENERIC 221 ++ ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++ ++ ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++ u32 mac_time[2]; ++ u8 signalstrength; ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u16 rate; /* in 100 kbps */ ++ u8 received_channel; ++ u8 control; ++ u8 mask; ++ u8 freq; ++ u16 len; ++ u8 nic_type; ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ unsigned long first_frag_time; ++ unsigned int seq; ++ unsigned int last_frag; ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ unsigned int tx_unicast_frames; ++ unsigned int tx_multicast_frames; ++ unsigned int tx_fragments; ++ unsigned int tx_unicast_octets; ++ unsigned int tx_multicast_octets; ++ unsigned int tx_deferred_transmissions; ++ unsigned int tx_single_retry_frames; ++ unsigned int tx_multiple_retry_frames; ++ unsigned int tx_retry_limit_exceeded; ++ unsigned int tx_discards; ++ unsigned int rx_unicast_frames; ++ unsigned int rx_multicast_frames; ++ unsigned int rx_fragments; ++ unsigned int rx_unicast_octets; ++ unsigned int rx_multicast_octets; ++ unsigned int rx_fcs_errors; ++ unsigned int rx_discards_no_buffer; ++ unsigned int tx_discards_wrong_sa; ++ unsigned int rx_discards_undecryptable; ++ unsigned int rx_message_in_msg_fragments; ++ unsigned int rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_softmac_stats{ ++ unsigned int rx_ass_ok; ++ unsigned int rx_ass_err; ++ unsigned int rx_probe_rq; ++ unsigned int tx_probe_rs; ++ unsigned int tx_beacons; ++ unsigned int rx_auth_rq; ++ unsigned int rx_auth_rs_ok; ++ unsigned int rx_auth_rs_err; ++ unsigned int tx_auth_rq; ++ unsigned int no_auth_rs; ++ unsigned int no_ass_rs; ++ unsigned int tx_ass_rq; ++ unsigned int rx_ass_rq; ++ unsigned int tx_probe_rq; ++ unsigned int reassoc; ++ unsigned int swtxstop; ++ unsigned int swtxawake; ++}; ++ ++struct ieee80211_device; ++ ++#include "ieee80211_crypt.h" ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++ ++#define WEP_KEY_LEN_MODIF 32 ++ ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][WEP_KEY_LEN_MODIF]; ++ u8 level; ++ u16 flags; ++} __attribute__ ((packed)); ++ ++ ++/* ++ ++ 802.11 data frame from AP ++ ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++ ++Total: 28-2340 bytes ++ ++*/ ++ ++struct ieee80211_header_data { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[6]; ++ u8 addr2[6]; ++ u8 addr3[6]; ++ u16 seq_ctrl; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++/* Management Frame Information Element Types */ ++#define MFIE_TYPE_SSID 0 ++#define MFIE_TYPE_RATES 1 ++#define MFIE_TYPE_FH_SET 2 ++#define MFIE_TYPE_DS_SET 3 ++#define MFIE_TYPE_CF_SET 4 ++#define MFIE_TYPE_TIM 5 ++#define MFIE_TYPE_IBSS_SET 6 ++#define MFIE_TYPE_COUNTRY 7 //+YJ,080625 ++#define MFIE_TYPE_CHALLENGE 16 ++#define MFIE_TYPE_ERP 42 ++#define MFIE_TYPE_RSN 48 ++#define MFIE_TYPE_RATES_EX 50 ++#define MFIE_TYPE_GENERIC 221 ++ ++#ifdef ENABLE_DOT11D ++typedef enum ++{ ++ COUNTRY_CODE_FCC = 0, ++ COUNTRY_CODE_IC = 1, ++ COUNTRY_CODE_ETSI = 2, ++ COUNTRY_CODE_SPAIN = 3, ++ COUNTRY_CODE_FRANCE = 4, ++ COUNTRY_CODE_MKK = 5, ++ COUNTRY_CODE_MKK1 = 6, ++ COUNTRY_CODE_ISRAEL = 7, ++ COUNTRY_CODE_TELEC = 8, ++ COUNTRY_CODE_GLOBAL_DOMAIN = 9, ++ COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10 ++}country_code_type_t; ++#endif ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __attribute__ ((packed)); ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __attribute__ ((packed)); ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __attribute__ ((packed)); ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 10 ++ ++struct ieee80211_authentication { ++ struct ieee80211_header_data header; ++ u16 algorithm; ++ u16 transaction; ++ u16 status; ++ //struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++ ++struct ieee80211_probe_response { ++ struct ieee80211_header_data header; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 capability; ++ struct ieee80211_info_element info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_probe_request { ++ struct ieee80211_header_data header; ++ /*struct ieee80211_info_element info_element;*/ ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_request_frame { ++ struct ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 listen_interval; ++ //u8 current_ap[ETH_ALEN]; ++ struct ieee80211_info_element_hdr info_element; ++} __attribute__ ((packed)); ++ ++struct ieee80211_assoc_response_frame { ++ struct ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 status; ++ u16 aid; ++ struct ieee80211_info_element info_element; /* supported rates */ ++} __attribute__ ((packed)); ++ ++struct ieee80211_disassoc_frame{ ++ struct ieee80211_hdr_3addr header; ++ u16 reasoncode; ++}__attribute__ ((packed)); ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u16 reserved; ++ u16 frag_size; ++ u16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++struct ieee80211_wmm_ac_param { ++ u8 ac_aci_acm_aifsn; ++ u8 ac_ecwmin_ecwmax; ++ u16 ac_txop_limit; ++}; ++ ++struct ieee80211_wmm_ts_info { ++ u8 ac_dir_tid; ++ u8 ac_up_psb; ++ u8 reserved; ++} __attribute__ ((packed)); ++ ++struct ieee80211_wmm_tspec_elem { ++ struct ieee80211_wmm_ts_info ts_info; ++ u16 norm_msdu_size; ++ u16 max_msdu_size; ++ u32 min_serv_inter; ++ u32 max_serv_inter; ++ u32 inact_inter; ++ u32 suspen_inter; ++ u32 serv_start_time; ++ u32 min_data_rate; ++ u32 mean_data_rate; ++ u32 peak_data_rate; ++ u32 max_burst_size; ++ u32 delay_bound; ++ u32 min_phy_rate; ++ u16 surp_band_allow; ++ u16 medium_time; ++}__attribute__((packed)); ++ ++enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; ++#define MAX_SP_Len (WMM_all_frame << 4) ++#define IEEE80211_QOS_TID 0x0f ++#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++//#define MAX_CHANNEL_NUMBER 161 ++#define MAX_CHANNEL_NUMBER 165 //YJ,modified,080625 ++#define MAX_IE_LEN 0xFF //+YJ,080625 ++ ++typedef struct _CHANNEL_LIST{ ++ u8 Channel[MAX_CHANNEL_NUMBER + 1]; ++ u8 Len; ++}CHANNEL_LIST, *PCHANNEL_LIST; ++ ++#define IEEE80211_SOFTMAC_SCAN_TIME 100//400 ++//(HZ / 2) ++//by amy for ps ++#define IEEE80211_WATCH_DOG_TIME 2000 ++//by amy for ps ++//by amy for antenna ++#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m ++//by amy for antenna ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN 64 ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++#define IEEE80211_PS_ENABLE IEEE80211_DTIM_VALID ++//added by David for QoS 2006/6/30 ++//#define WMM_Hang_8187 ++#ifdef WMM_Hang_8187 ++#undef WMM_Hang_8187 ++#endif ++ ++#define WME_AC_BE 0x00 ++#define WME_AC_BK 0x01 ++#define WME_AC_VI 0x02 ++#define WME_AC_VO 0x03 ++#define WME_ACI_MASK 0x03 ++#define WME_AIFSN_MASK 0x03 ++#define WME_AC_PRAM_LEN 16 ++ ++//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP ++//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) ++#define UP2AC(up) ( \ ++ ((up) < 1) ? WME_AC_BE : \ ++ ((up) < 3) ? WME_AC_BK : \ ++ ((up) < 4) ? WME_AC_BE : \ ++ ((up) < 6) ? WME_AC_VI : \ ++ WME_AC_VO) ++//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue ++#define AC2UP(_ac) ( \ ++ ((_ac) == WME_AC_VO) ? 6 : \ ++ ((_ac) == WME_AC_VI) ? 5 : \ ++ ((_ac) == WME_AC_BK) ? 1 : \ ++ 0) ++ ++#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ ++struct ether_header { ++ u8 ether_dhost[ETHER_ADDR_LEN]; ++ u8 ether_shost[ETHER_ADDR_LEN]; ++ u16 ether_type; ++} __attribute__((packed)); ++ ++#ifndef ETHERTYPE_PAE ++#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ ++#endif ++#ifndef ETHERTYPE_IP ++#define ETHERTYPE_IP 0x0800 /* IP protocol */ ++#endif ++ ++struct ieee80211_network { ++ /* These entries are used to identify a unique network */ ++ u8 bssid[ETH_ALEN]; ++ u8 channel; ++ /* Ensure null-terminated for any debug msgs */ ++ u8 ssid[IW_ESSID_MAX_SIZE + 1]; ++ u8 ssid_len; ++ ++ /* These are network statistics */ ++ struct ieee80211_rx_stats stats; ++ u16 capability; ++ u8 rates[MAX_RATES_LENGTH]; ++ u8 rates_len; ++ u8 rates_ex[MAX_RATES_EX_LENGTH]; ++ u8 rates_ex_len; ++ unsigned long last_scanned; ++ u8 mode; ++ u8 flags; ++ u32 last_associate; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 listen_interval; ++ u16 atim_window; ++ u8 wpa_ie[MAX_WPA_IE_LEN]; ++ size_t wpa_ie_len; ++ u8 rsn_ie[MAX_WPA_IE_LEN]; ++ size_t rsn_ie_len; ++ u8 dtim_period; ++ u8 dtim_data; ++ u32 last_dtim_sta_time[2]; ++ struct list_head list; ++ //appeded for QoS ++ u8 wmm_info; ++ struct ieee80211_wmm_ac_param wmm_param[4]; ++ u8 QoS_Enable; ++ u8 SignalStrength; ++//by amy 080312 ++ u8 HighestOperaRate; ++//by amy 080312 ++#ifdef THOMAS_TURBO ++ u8 Turbo_Enable;//enable turbo mode, added by thomas ++#endif ++#ifdef ENABLE_DOT11D ++ u16 CountryIeLen; ++ u8 CountryIeBuf[MAX_IE_LEN]; ++#endif ++}; ++ ++enum ieee80211_state { ++ ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++ ++}; ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] ++ ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)) ++extern inline int is_multicast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++#endif ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)) ++extern inline int is_broadcast_ether_addr(const u8 *addr) ++{ ++ return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); ++} ++#endif ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++ ++typedef struct tx_pending_t{ ++ int frag; ++ struct ieee80211_txb *txb; ++}tx_pending_t; ++ ++ ++struct ieee80211_device { ++ struct net_device *dev; ++ ++ /* Bookkeeping structures */ ++ struct net_device_stats stats; ++ struct ieee80211_stats ieee_stats; ++ struct ieee80211_softmac_stats softmac_stats; ++ ++ /* Probe / Beacon management */ ++ struct list_head network_free_list; ++ struct list_head network_list; ++ struct ieee80211_network *networks; ++ int scans; ++ int scan_age; ++ ++ int iw_mode; /* operating mode (IW_MODE_*) */ ++ ++ spinlock_t lock; ++ spinlock_t wpax_suitlist_lock; ++ ++ int tx_headroom; /* Set to size of any additional room needed at front ++ * of allocated Tx SKBs */ ++ u32 config; ++ ++ /* WEP and other encryption related settings at the device level */ ++ int open_wep; /* Set to 1 to allow unencrypted frames */ ++ ++ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on ++ * WEP key changes */ ++ ++ /* If the host performs {en,de}cryption, then set to 1 */ ++ int host_encrypt; ++ int host_decrypt; ++ int ieee802_1x; /* is IEEE 802.1X used */ ++ ++ /* WPA data */ ++ int wpa_enabled; ++ int drop_unencrypted; ++ int tkip_countermeasures; ++ int privacy_invoked; ++ size_t wpa_ie_len; ++ u8 *wpa_ie; ++ ++ u8 ap_mac_addr[6]; ++ u16 pairwise_key_type; ++ u16 broadcast_key_type; ++ ++ struct list_head crypt_deinit_list; ++ struct ieee80211_crypt_data *crypt[WEP_KEYS]; ++ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ ++ struct timer_list crypt_deinit_timer; ++ ++ int bcrx_sta_key; /* use individual keys to override default keys even ++ * with RX of broad/multicast frames */ ++ ++ /* Fragmentation structures */ ++ // each streaming contain a entry ++ struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; ++ unsigned int frag_next_idx[17]; ++ u16 fts; /* Fragmentation Threshold */ ++ ++ /* This stores infos for the current network. ++ * Either the network we are associated in INFRASTRUCTURE ++ * or the network that we are creating in MASTER mode. ++ * ad-hoc is a mixture ;-). ++ * Note that in infrastructure mode, even when not associated, ++ * fields bssid and essid may be valid (if wpa_set and essid_set ++ * are true) as thy carry the value set by the user via iwconfig ++ */ ++ struct ieee80211_network current_network; ++ ++ ++ enum ieee80211_state state; ++ ++ int short_slot; ++ int mode; /* A, B, G */ ++ int modulation; /* CCK, OFDM */ ++ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ ++ int abg_true; /* ABG flag */ ++ ++ /* used for forcing the ibss workqueue to terminate ++ * without wait for the syncro scan to terminate ++ */ ++ short sync_scan_hurryup; ++ ++#ifdef ENABLE_DOT11D ++ void * pDot11dInfo; ++ bool bGlobalDomain; ++ ++ // For Liteon Ch12~13 passive scan ++ u8 MinPassiveChnlNum; ++ u8 IbssStartChnl; ++#else ++ /* map of allowed channels. 0 is dummy */ ++ // FIXME: remeber to default to a basic channel plan depending of the PHY type ++ int channel_map[MAX_CHANNEL_NUMBER+1]; ++#endif ++ ++ int rate; /* current rate */ ++ int basic_rate; ++ //FIXME: pleace callback, see if redundant with softmac_features ++ short active_scan; ++ ++ /* this contains flags for selectively enable softmac support */ ++ u16 softmac_features; ++ ++ /* if the sequence control field is not filled by HW */ ++ u16 seq_ctrl[5]; ++ ++ /* association procedure transaction sequence number */ ++ u16 associate_seq; ++ ++ /* AID for RTXed association responses */ ++ u16 assoc_id; ++ ++ /* power save mode related*/ ++ short ps; ++ short sta_sleep; ++ int ps_timeout; ++ struct tasklet_struct ps_task; ++ u32 ps_th; ++ u32 ps_tl; ++ ++ short raw_tx; ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ short queue_stop; ++ short scanning; ++ short proto_started; ++ ++ struct semaphore wx_sem; ++ struct semaphore scan_sem; ++ ++ spinlock_t mgmt_tx_lock; ++ spinlock_t beacon_lock; ++ ++ short beacon_txing; ++ ++ short wap_set; ++ short ssid_set; ++ ++ u8 wpax_type_set; //{added by David, 2006.9.28} ++ u32 wpax_type_notify; //{added by David, 2006.9.26} ++ ++ /* QoS related flag */ ++ char init_wmmparam_flag; ++ ++ /* for discarding duplicated packets in IBSS */ ++ struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; ++ ++ /* for discarding duplicated packets in BSS */ ++ u16 last_rxseq_num[17]; /* rx seq previous per-tid */ ++ u16 last_rxfrag_num[17];/* tx frag previous per-tid */ ++ unsigned long last_packet_time[17]; ++ ++ /* for PS mode */ ++ unsigned long last_rx_ps_time; ++ ++ /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ ++ struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; ++ int mgmt_queue_head; ++ int mgmt_queue_tail; ++ ++ ++ /* used if IEEE_SOFTMAC_TX_QUEUE is set */ ++ struct tx_pending_t tx_pending; ++ ++ /* used if IEEE_SOFTMAC_ASSOCIATE is set */ ++ struct timer_list associate_timer; ++ ++ /* used if IEEE_SOFTMAC_BEACONS is set */ ++ struct timer_list beacon_timer; ++ ++ struct work_struct associate_complete_wq; ++// struct work_struct associate_retry_wq; ++ struct work_struct associate_procedure_wq; ++// struct work_struct softmac_scan_wq; ++ struct work_struct wx_sync_scan_wq; ++ struct work_struct wmm_param_update_wq; ++ struct work_struct ps_request_tx_ack_wq;//for ps ++// struct work_struct hw_wakeup_wq; ++// struct work_struct hw_sleep_wq; ++// struct work_struct watch_dog_wq; ++ bool bInactivePs; ++ bool actscanning; ++ bool beinretry; ++ u16 ListenInterval; ++ unsigned long NumRxDataInPeriod; //YJ,add,080828 ++ unsigned long NumRxBcnInPeriod; //YJ,add,080828 ++ unsigned long NumRxOkTotal; ++ unsigned long NumRxUnicast;//YJ,add,080828,for keep alive ++ bool bHwRadioOff; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++ struct delayed_work softmac_scan_wq; ++ struct delayed_work associate_retry_wq; ++ struct delayed_work hw_wakeup_wq; ++ struct delayed_work hw_sleep_wq;//+by amy 080324 ++ struct delayed_work watch_dog_wq; ++ struct delayed_work sw_antenna_wq; ++ struct delayed_work start_ibss_wq; ++//by amy for rate adaptive 080312 ++ struct delayed_work rate_adapter_wq; ++//by amy for rate adaptive ++ struct delayed_work hw_dig_wq; ++ struct delayed_work tx_pw_wq; ++ ++//Added for RF power on power off by lizhaoming 080512 ++ struct delayed_work GPIOChangeRFWorkItem; ++#else ++ ++ struct work_struct start_ibss_wq; ++ struct work_struct softmac_scan_wq; ++ struct work_struct associate_retry_wq; ++ struct work_struct hw_wakeup_wq; ++ struct work_struct hw_sleep_wq; ++ struct work_struct watch_dog_wq; ++ struct work_struct sw_antenna_wq; ++//by amy for rate adaptive 080312 ++ struct work_struct rate_adapter_wq; ++//by amy for rate adaptive ++ struct work_struct hw_dig_wq; ++ struct work_struct tx_pw_wq; ++ ++//Added for RF power on power off by lizhaoming 080512 ++ struct work_struct GPIOChangeRFWorkItem; ++#endif ++ struct workqueue_struct *wq; ++ ++ /* Callback functions */ ++ void (*set_security)(struct net_device *dev, ++ struct ieee80211_security *sec); ++ ++ /* Used to TX data frame by using txb structs. ++ * this is not used if in the softmac_features ++ * is set the flag IEEE_SOFTMAC_TX_QUEUE ++ */ ++ int (*hard_start_xmit)(struct ieee80211_txb *txb, ++ struct net_device *dev); ++ ++ int (*reset_port)(struct net_device *dev); ++ ++ /* Softmac-generated frames (mamagement) are TXed via this ++ * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is ++ * not set. As some cards may have different HW queues that ++ * one might want to use for data and management frames ++ * the option to have two callbacks might be useful. ++ * This fucntion can't sleep. ++ */ ++ int (*softmac_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev); ++ ++ /* used instead of hard_start_xmit (not softmac_hard_start_xmit) ++ * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data ++ * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set ++ * then also management frames are sent via this callback. ++ * This function can't sleep. ++ */ ++ void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, ++ struct net_device *dev,int rate); ++ ++ /* stops the HW queue for DATA frames. Useful to avoid ++ * waste time to TX data frame when we are reassociating ++ * This function can sleep. ++ */ ++ void (*data_hard_stop)(struct net_device *dev); ++ ++ /* OK this is complementar to data_poll_hard_stop */ ++ void (*data_hard_resume)(struct net_device *dev); ++ ++ /* ask to the driver to retune the radio . ++ * This function can sleep. the driver should ensure ++ * the radio has been swithced before return. ++ */ ++ void (*set_chan)(struct net_device *dev,short ch); ++ ++ /* These are not used if the ieee stack takes care of ++ * scanning (IEEE_SOFTMAC_SCAN feature set). ++ * In this case only the set_chan is used. ++ * ++ * The syncro version is similar to the start_scan but ++ * does not return until all channels has been scanned. ++ * this is called in user context and should sleep, ++ * it is called in a work_queue when swithcing to ad-hoc mode ++ * or in behalf of iwlist scan when the card is associated ++ * and root user ask for a scan. ++ * the fucntion stop_scan should stop both the syncro and ++ * background scanning and can sleep. ++ * The fucntion start_scan should initiate the background ++ * scanning and can't sleep. ++ */ ++ void (*scan_syncro)(struct net_device *dev); ++ void (*start_scan)(struct net_device *dev); ++ void (*stop_scan)(struct net_device *dev); ++ ++ /* indicate the driver that the link state is changed ++ * for example it may indicate the card is associated now. ++ * Driver might be interested in this to apply RX filter ++ * rules or simply light the LINK led ++ */ ++ void (*link_change)(struct net_device *dev); ++ ++ /* these two function indicates to the HW when to start ++ * and stop to send beacons. This is used when the ++ * IEEE_SOFTMAC_BEACONS is not set. For now the ++ * stop_send_bacons is NOT guaranteed to be called only ++ * after start_send_beacons. ++ */ ++ void (*start_send_beacons) (struct net_device *dev); ++ void (*stop_send_beacons) (struct net_device *dev); ++ ++ /* power save mode related */ ++ void (*sta_wake_up) (struct net_device *dev); ++ void (*ps_request_tx_ack) (struct net_device *dev); ++ void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); ++ short (*ps_is_queue_empty) (struct net_device *dev); ++ ++ /* QoS related */ ++ //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param); ++ //void (*wmm_param_update) (struct ieee80211_device *ieee); ++ ++ /* This must be the last item so that it points to the data ++ * allocated beyond this structure by alloc_ieee80211 */ ++ u8 priv[0]; ++}; ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++/* Generate a 802.11 header */ ++ ++/* Uses the channel change callback directly ++ * instead of [start/stop] scan callbacks ++ */ ++#define IEEE_SOFTMAC_SCAN (1<<2) ++ ++/* Perform authentication and association handshake */ ++#define IEEE_SOFTMAC_ASSOCIATE (1<<3) ++ ++/* Generate probe requests */ ++#define IEEE_SOFTMAC_PROBERQ (1<<4) ++ ++/* Generate respones to probe requests */ ++#define IEEE_SOFTMAC_PROBERS (1<<5) ++ ++/* The ieee802.11 stack will manages the netif queue ++ * wake/stop for the driver, taking care of 802.11 ++ * fragmentation. See softmac.c for details. */ ++#define IEEE_SOFTMAC_TX_QUEUE (1<<7) ++ ++/* Uses only the softmac_data_hard_start_xmit ++ * even for TX management frames. ++ */ ++#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) ++ ++/* Generate beacons. The stack will enqueue beacons ++ * to the card ++ */ ++#define IEEE_SOFTMAC_BEACONS (1<<6) ++ ++ ++ ++static inline void *ieee80211_priv(struct net_device *dev) ++{ ++ return ((struct ieee80211_device *)netdev_priv(dev))->priv; ++} ++ ++extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) ++{ ++ /* ++ * It is possible for both access points and our device to support ++ * combinations of modes, so as long as there is one valid combination ++ * of ap/device supported modes, then return success ++ * ++ */ ++ if ((mode & IEEE_A) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_52GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_G) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ if ((mode & IEEE_B) && ++ (ieee->modulation & IEEE80211_CCK_MODULATION) && ++ (ieee->freq_band & IEEE80211_24GHZ_BAND)) ++ return 1; ++ ++ return 0; ++} ++ ++extern inline int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = 24; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case IEEE80211_FTYPE_DATA: ++ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) ++ hdrlen = 30; /* Addr4 */ ++ if(IEEE80211_QOS_HAS_SEQ(fc)) ++ hdrlen += 2; /* QOS ctrl*/ ++ break; ++ case IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case IEEE80211_STYPE_CTS: ++ case IEEE80211_STYPE_ACK: ++ hdrlen = 10; ++ break; ++ default: ++ hdrlen = 16; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++ ++ ++/* ieee80211.c */ ++extern void free_ieee80211(struct net_device *dev); ++extern struct net_device *alloc_ieee80211(int sizeof_priv); ++ ++extern int ieee80211_set_encryption(struct ieee80211_device *ieee); ++ ++/* ieee80211_tx.c */ ++ ++extern int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len); ++ ++extern int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev); ++extern void ieee80211_txb_free(struct ieee80211_txb *); ++ ++ ++/* ieee80211_rx.c */ ++extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats); ++extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header, ++ struct ieee80211_rx_stats *stats); ++ ++/* ieee80211_wx.c */ ++extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key); ++extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data* wrqu, char *extra); ++int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra); ++int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); ++/* ieee80211_softmac.c */ ++extern short ieee80211_is_54g(struct ieee80211_network net); ++extern short ieee80211_is_shortslot(struct ieee80211_network net); ++extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype); ++extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net); ++ ++extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee); ++extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); ++extern void ieee80211_start_ibss(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_init(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_free(struct ieee80211_device *ieee); ++extern void ieee80211_associate_abort(struct ieee80211_device *ieee); ++extern void ieee80211_disassociate(struct ieee80211_device *ieee); ++extern void ieee80211_stop_scan(struct ieee80211_device *ieee); ++extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); ++extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); ++extern void ieee80211_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); ++extern void ieee80211_reset_queue(struct ieee80211_device *ieee); ++extern void ieee80211_wake_queue(struct ieee80211_device *ieee); ++extern void ieee80211_stop_queue(struct ieee80211_device *ieee); ++extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); ++extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); ++extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); ++extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p); ++extern void notify_wx_assoc_event(struct ieee80211_device *ieee); ++extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); ++extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn); ++extern void ieee80211_start_scan(struct ieee80211_device *ieee); ++ ++//Add for RF power on power off by lizhaoming 080512 ++extern void SendDisassociation(struct ieee80211_device *ieee, ++ u8* asSta, ++ u8 asRsn); ++ ++/* ieee80211_crypt_ccmp&tkip&wep.c */ ++extern void ieee80211_tkip_null(void); ++extern void ieee80211_wep_null(void); ++extern void ieee80211_ccmp_null(void); ++/* ieee80211_softmac_wx.c */ ++ ++extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *ext); ++ ++extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra); ++ ++extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b); ++ ++extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++ ++extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); ++#else ++ extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++#endif ++//extern void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee); ++ ++extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++extern void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee); ++ ++extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr); ++ ++extern const long ieee80211_wlan_frequencies[]; ++ ++extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) ++{ ++ ieee->scans++; ++} ++ ++extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) ++{ ++ return ieee->scans; ++} ++ ++static inline const char *escape_essid(const char *essid, u8 essid_len) { ++ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; ++ const char *s = essid; ++ char *d = escaped; ++ ++ if (ieee80211_is_empty_essid(essid, essid_len)) { ++ memcpy(escaped, "", sizeof("")); ++ return escaped; ++ } ++ ++ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); ++ while (essid_len--) { ++ if (*s == '\0') { ++ *d++ = '\\'; ++ *d++ = '0'; ++ s++; ++ } else { ++ *d++ = *s++; ++ } ++ } ++ *d = '\0'; ++ return escaped; ++} ++#endif /* IEEE80211_H */ +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c +@@ -0,0 +1,299 @@ ++/******************************************************************************* ++ ++ Copyright(c) 2004 Intel Corporation. All rights reserved. ++ ++ Portions of this file are based on the WEP enablement code provided by the ++ Host AP project hostap-drivers v0.1.3 ++ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ ++ Copyright (c) 2002-2003, Jouni Malinen ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., 59 ++ Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++MODULE_DESCRIPTION("802.11 data/management/control stack"); ++MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation "); ++MODULE_LICENSE("GPL"); ++ ++#define DRV_NAME "ieee80211" ++ ++static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) ++{ ++ if (ieee->networks) ++ return 0; ++ ++ ieee->networks = kmalloc( ++ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), ++ GFP_KERNEL); ++ if (!ieee->networks) { ++ printk(KERN_WARNING "%s: Out of memory allocating beacons\n", ++ ieee->dev->name); ++ return -ENOMEM; ++ } ++ ++ memset(ieee->networks, 0, ++ MAX_NETWORK_COUNT * sizeof(struct ieee80211_network)); ++ ++ return 0; ++} ++ ++static inline void ieee80211_networks_free(struct ieee80211_device *ieee) ++{ ++ if (!ieee->networks) ++ return; ++ kfree(ieee->networks); ++ ieee->networks = NULL; ++} ++ ++static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) ++{ ++ int i; ++ ++ INIT_LIST_HEAD(&ieee->network_free_list); ++ INIT_LIST_HEAD(&ieee->network_list); ++ for (i = 0; i < MAX_NETWORK_COUNT; i++) ++ list_add_tail(&ieee->networks[i].list, &ieee->network_free_list); ++} ++ ++ ++struct net_device *alloc_ieee80211(int sizeof_priv) ++{ ++ struct ieee80211_device *ieee; ++ struct net_device *dev; ++ int i,err; ++ ++ IEEE80211_DEBUG_INFO("Initializing...\n"); ++ ++ dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); ++ if (!dev) { ++ IEEE80211_ERROR("Unable to network device.\n"); ++ goto failed; ++ } ++ ieee = netdev_priv(dev); ++ dev->hard_start_xmit = ieee80211_xmit; ++ ++ ieee->dev = dev; ++ ++ err = ieee80211_networks_allocate(ieee); ++ if (err) { ++ IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", ++ err); ++ goto failed; ++ } ++ ieee80211_networks_initialize(ieee); ++ ++ /* Default fragmentation threshold is maximum payload size */ ++ ieee->fts = DEFAULT_FTS; ++ ieee->scan_age = DEFAULT_MAX_SCAN_AGE; ++ ieee->open_wep = 1; ++ ++ /* Default to enabling full open WEP with host based encrypt/decrypt */ ++ ieee->host_encrypt = 1; ++ ieee->host_decrypt = 1; ++ ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ ++ ++ INIT_LIST_HEAD(&ieee->crypt_deinit_list); ++ init_timer(&ieee->crypt_deinit_timer); ++ ieee->crypt_deinit_timer.data = (unsigned long)ieee; ++ ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; ++ ++ spin_lock_init(&ieee->lock); ++ spin_lock_init(&ieee->wpax_suitlist_lock); ++ ++ ieee->wpax_type_set = 0; ++ ieee->wpa_enabled = 0; ++ ieee->tkip_countermeasures = 0; ++ ieee->drop_unencrypted = 0; ++ ieee->privacy_invoked = 0; ++ ieee->ieee802_1x = 1; ++ ieee->raw_tx = 0; ++ ++ ieee80211_softmac_init(ieee); ++ ++ for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) ++ INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); ++ ++ for (i = 0; i < 17; i++) { ++ ieee->last_rxseq_num[i] = -1; ++ ieee->last_rxfrag_num[i] = -1; ++ ieee->last_packet_time[i] = 0; ++ } ++//These function were added to load crypte module autoly ++ ieee80211_tkip_null(); ++ ieee80211_wep_null(); ++ ieee80211_ccmp_null(); ++ return dev; ++ ++ failed: ++ if (dev) ++ free_netdev(dev); ++ return NULL; ++} ++ ++ ++void free_ieee80211(struct net_device *dev) ++{ ++ struct ieee80211_device *ieee = netdev_priv(dev); ++ ++ int i; ++ struct list_head *p, *q; ++ ++ ++ ieee80211_softmac_free(ieee); ++ del_timer_sync(&ieee->crypt_deinit_timer); ++ ieee80211_crypt_deinit_entries(ieee, 1); ++ ++ for (i = 0; i < WEP_KEYS; i++) { ++ struct ieee80211_crypt_data *crypt = ieee->crypt[i]; ++ if (crypt) { ++ if (crypt->ops) { ++ crypt->ops->deinit(crypt->priv); ++ module_put(crypt->ops->owner); ++ } ++ kfree(crypt); ++ ieee->crypt[i] = NULL; ++ } ++ } ++ ++ ieee80211_networks_free(ieee); ++ ++ for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) { ++ list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) { ++ kfree(list_entry(p, struct ieee_ibss_seq, list)); ++ list_del(p); ++ } ++ } ++ ++ ++ free_netdev(dev); ++} ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ ++static int debug = 0; ++u32 ieee80211_debug_level = 0; ++struct proc_dir_entry *ieee80211_proc = NULL; ++ ++static int show_debug_level(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); ++} ++ ++static int store_debug_level(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char buf[] = "0x00000000"; ++ unsigned long len = min(sizeof(buf) - 1, (u32)count); ++ char *p = (char *)buf; ++ unsigned long val; ++ ++ if (copy_from_user(buf, buffer, len)) ++ return count; ++ buf[len] = 0; ++ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { ++ p++; ++ if (p[0] == 'x' || p[0] == 'X') ++ p++; ++ val = simple_strtoul(p, &p, 16); ++ } else ++ val = simple_strtoul(p, &p, 10); ++ if (p == buf) ++ printk(KERN_INFO DRV_NAME ++ ": %s is not in hex or decimal form.\n", buf); ++ else ++ ieee80211_debug_level = val; ++ ++ return strnlen(buf, count); ++} ++ ++static int __init ieee80211_init(void) ++{ ++ struct proc_dir_entry *e; ++ ++ ieee80211_debug_level = debug; ++ ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net); ++ if (ieee80211_proc == NULL) { ++ IEEE80211_ERROR("Unable to create " DRV_NAME ++ " proc directory\n"); ++ return -EIO; ++ } ++ e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, ++ ieee80211_proc); ++ if (!e) { ++ remove_proc_entry(DRV_NAME, proc_net); ++ ieee80211_proc = NULL; ++ return -EIO; ++ } ++ e->read_proc = show_debug_level; ++ e->write_proc = store_debug_level; ++ e->data = NULL; ++ ++ return 0; ++} ++ ++static void __exit ieee80211_exit(void) ++{ ++ if (ieee80211_proc) { ++ remove_proc_entry("debug_level", ieee80211_proc); ++ remove_proc_entry(DRV_NAME, proc_net); ++ ieee80211_proc = NULL; ++ } ++} ++ ++#include ++module_param(debug, int, 0444); ++MODULE_PARM_DESC(debug, "debug output mask"); ++ ++ ++module_exit(ieee80211_exit); ++module_init(ieee80211_init); ++#endif ++ ++#if 0 ++EXPORT_SYMBOL(alloc_ieee80211); ++EXPORT_SYMBOL(free_ieee80211); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c +@@ -0,0 +1,1971 @@ ++/* ++ * Original code based Host AP (software wireless LAN access point) driver ++ * for Intersil Prism2/2.5/3 - hostap.o module, common routines ++ * ++ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ * ++ * Copyright (c) 2002-2003, Jouni Malinen ++ * Copyright (c) 2004, Intel Corporation ++ * ++ * 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. See README and COPYING for ++ * more details. ++ ****************************************************************************** ++ ++ Few modifications for Realtek's Wi-Fi drivers by ++ Andrea Merello ++ ++ A special thanks goes to Realtek for their support ! ++ ++******************************************************************************/ ++ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, ++ struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats) ++{ ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ ++ skb->dev = ieee->dev; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++ skb_reset_mac_header(skb); ++#else ++ skb->mac.raw = skb->data; ++#endif ++ skb_pull(skb, ieee80211_get_hdrlen(fc)); ++ skb->pkt_type = PACKET_OTHERHOST; ++ skb->protocol = __constant_htons(ETH_P_80211_RAW); ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ netif_rx(skb); ++} ++ ++ ++/* Called only as a tasklet (software IRQ) */ ++static struct ieee80211_frag_entry * ++ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq, ++ unsigned int frag, u8 tid,u8 *src, u8 *dst) ++{ ++ struct ieee80211_frag_entry *entry; ++ int i; ++ ++ for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { ++ entry = &ieee->frag_cache[tid][i]; ++ if (entry->skb != NULL && ++ time_after(jiffies, entry->first_frag_time + 2 * HZ)) { ++ IEEE80211_DEBUG_FRAG( ++ "expiring fragment cache entry " ++ "seq=%u last_frag=%u\n", ++ entry->seq, entry->last_frag); ++ dev_kfree_skb_any(entry->skb); ++ entry->skb = NULL; ++ } ++ ++ if (entry->skb != NULL && entry->seq == seq && ++ (entry->last_frag + 1 == frag || frag == -1) && ++ memcmp(entry->src_addr, src, ETH_ALEN) == 0 && ++ memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) ++ return entry; ++ } ++ ++ return NULL; ++} ++ ++/* Called only as a tasklet (software IRQ) */ ++static struct sk_buff * ++ieee80211_frag_cache_get(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *hdr) ++{ ++ struct sk_buff *skb = NULL; ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ u16 sc = le16_to_cpu(hdr->seq_ctl); ++ unsigned int frag = WLAN_GET_SEQ_FRAG(sc); ++ unsigned int seq = WLAN_GET_SEQ_SEQ(sc); ++ struct ieee80211_frag_entry *entry; ++ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; ++ struct ieee80211_hdr_QOS *hdr_4addr_QoS; ++ u8 tid; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; ++ } ++ else ++#endif ++ if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { ++ tid = 0; ++ } ++ ++ if (frag == 0) { ++ /* Reserve enough space to fit maximum frame length */ ++ skb = dev_alloc_skb(ieee->dev->mtu + ++ sizeof(struct ieee80211_hdr) + ++ 8 /* LLC */ + ++ 2 /* alignment */ + ++ 8 /* WEP */ + ++ ETH_ALEN /* WDS */ + ++ (IEEE80211_QOS_HAS_SEQ(fc)?2:0) /* QOS Control */); ++ if (skb == NULL) ++ return NULL; ++ ++ entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; ++ ieee->frag_next_idx[tid]++; ++ if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN) ++ ieee->frag_next_idx[tid] = 0; ++ ++ if (entry->skb != NULL) ++ dev_kfree_skb_any(entry->skb); ++ ++ entry->first_frag_time = jiffies; ++ entry->seq = seq; ++ entry->last_frag = frag; ++ entry->skb = skb; ++ memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); ++ memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); ++ } else { ++ /* received a fragment of a frame for which the head fragment ++ * should have already been received */ ++ entry = ieee80211_frag_cache_find(ieee, seq, frag, tid,hdr->addr2, ++ hdr->addr1); ++ if (entry != NULL) { ++ entry->last_frag = frag; ++ skb = entry->skb; ++ } ++ } ++ ++ return skb; ++} ++ ++ ++/* Called only as a tasklet (software IRQ) */ ++static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *hdr) ++{ ++ u16 fc = le16_to_cpu(hdr->frame_ctl); ++ u16 sc = le16_to_cpu(hdr->seq_ctl); ++ unsigned int seq = WLAN_GET_SEQ_SEQ(sc); ++ struct ieee80211_frag_entry *entry; ++ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; ++ struct ieee80211_hdr_QOS *hdr_4addr_QoS; ++ u8 tid; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ tid = (hdr->addr2[ETH_ALEN-2] ^ hdr->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; ++ } ++ else ++#endif ++ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if (IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS *)hdr; ++ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { ++ tid = 0; ++ } ++ ++ entry = ieee80211_frag_cache_find(ieee, seq, -1, tid,hdr->addr2, ++ hdr->addr1); ++ ++ if (entry == NULL) { ++ IEEE80211_DEBUG_FRAG( ++ "could not invalidate fragment cache " ++ "entry (seq=%u)\n", seq); ++ return -1; ++ } ++ ++ entry->skb = NULL; ++ return 0; ++} ++ ++ ++ ++/* ieee80211_rx_frame_mgtmt ++ * ++ * Responsible for handling management control frames ++ * ++ * Called by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype) ++{ ++ struct ieee80211_hdr *hdr; ++ ++ // cheat the the hdr type ++ hdr = (struct ieee80211_hdr *)skb->data; ++ ++ /* On the struct stats definition there is written that ++ * this is not mandatory.... but seems that the probe ++ * response parser uses it ++ */ ++ rx_stats->len = skb->len; ++ ieee80211_rx_mgt(ieee,(struct ieee80211_hdr *)skb->data,rx_stats); ++ ++ if((ieee->state == IEEE80211_LINKED)&&(memcmp(hdr->addr3,ieee->current_network.bssid,ETH_ALEN))) { ++ dev_kfree_skb_any(skb); ++ return 0; ++ } ++ ++ ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype); ++ ++ dev_kfree_skb_any(skb); ++ ++ return 0; ++ ++ #ifdef NOT_YET ++ if (ieee->iw_mode == IW_MODE_MASTER) { ++ printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", ++ ieee->dev->name); ++ return 0; ++/* ++ hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) ++ skb->data);*/ ++ } ++ ++ if (ieee->hostapd && type == IEEE80211_TYPE_MGMT) { ++ if (stype == WLAN_FC_STYPE_BEACON && ++ ieee->iw_mode == IW_MODE_MASTER) { ++ struct sk_buff *skb2; ++ /* Process beacon frames also in kernel driver to ++ * update STA(AP) table statistics */ ++ skb2 = skb_clone(skb, GFP_ATOMIC); ++ if (skb2) ++ hostap_rx(skb2->dev, skb2, rx_stats); ++ } ++ ++ /* send management frames to the user space daemon for ++ * processing */ ++ ieee->apdevstats.rx_packets++; ++ ieee->apdevstats.rx_bytes += skb->len; ++ prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); ++ return 0; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MASTER) { ++ if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { ++ printk(KERN_DEBUG "%s: unknown management frame " ++ "(type=0x%02x, stype=0x%02x) dropped\n", ++ skb->dev->name, type, stype); ++ return -1; ++ } ++ ++ hostap_rx(skb->dev, skb, rx_stats); ++ return 0; ++ } ++ ++ printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " ++ "received in non-Host AP mode\n", skb->dev->name); ++ return -1; ++ #endif ++} ++ ++ ++ ++/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ ++/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ ++static unsigned char rfc1042_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ++/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ ++static unsigned char bridge_tunnel_header[] = ++{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; ++/* No encapsulation header if EtherType < 0x600 (=length) */ ++ ++/* Called by ieee80211_rx_frame_decrypt */ ++static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, ++ struct sk_buff *skb, size_t hdrlen) ++{ ++ struct net_device *dev = ieee->dev; ++ u16 fc, ethertype; ++ struct ieee80211_hdr *hdr; ++ u8 *pos; ++ ++ if (skb->len < 24) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ ++ /* check that the frame is unicast frame to us */ ++ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_TODS && ++ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && ++ memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { ++ /* ToDS frame with own addr BSSID and DA */ ++ } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_FROMDS && ++ memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { ++ /* FromDS frame with own addr as DA */ ++ } else ++ return 0; ++ ++ if (skb->len < 24 + 8) ++ return 0; ++ ++ /* check for port access entity Ethernet type */ ++// pos = skb->data + 24; ++ pos = skb->data + hdrlen; ++ ethertype = (pos[6] << 8) | pos[7]; ++ if (ethertype == ETH_P_PAE) ++ return 1; ++ ++ return 0; ++} ++ ++/* Called only as a tasklet (software IRQ), by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, ++ struct ieee80211_crypt_data *crypt) ++{ ++ struct ieee80211_hdr *hdr; ++ int res, hdrlen; ++ ++ if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) ++ { ++ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); ++ } ++ else ++#endif ++ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); ++ ++#ifdef CONFIG_IEEE80211_CRYPT_TKIP ++ if (ieee->tkip_countermeasures && ++ strcmp(crypt->ops->name, "TKIP") == 0) { ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ++ "received packet from " MAC_FMT "\n", ++ ieee->dev->name, MAC_ARG(hdr->addr2)); ++ } ++ return -1; ++ } ++#endif ++ ++ atomic_inc(&crypt->refcnt); ++ res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ IEEE80211_DEBUG_DROP( ++ "decryption failed (SA=" MAC_FMT ++ ") res=%d\n", MAC_ARG(hdr->addr2), res); ++ if (res == -2) ++ IEEE80211_DEBUG_DROP("Decryption failed ICV " ++ "mismatch (key %d)\n", ++ skb->data[hdrlen + 3] >> 6); ++ ieee->ieee_stats.rx_discards_undecryptable++; ++ return -1; ++ } ++ ++ return res; ++} ++ ++ ++/* Called only as a tasklet (software IRQ), by ieee80211_rx */ ++static inline int ++ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device* ieee, struct sk_buff *skb, ++ int keyidx, struct ieee80211_crypt_data *crypt) ++{ ++ struct ieee80211_hdr *hdr; ++ int res, hdrlen; ++ ++ if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) ++ return 0; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) ++ { ++ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); ++ } ++ else ++#endif ++ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); ++ ++ atomic_inc(&crypt->refcnt); ++ res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" ++ " (SA=" MAC_FMT " keyidx=%d)\n", ++ ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/* this function is stolen from ipw2200 driver*/ ++#define IEEE_PACKET_RETRY_TIME (5*HZ) ++static int is_duplicate_packet(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header) ++{ ++ u16 fc = le16_to_cpu(header->frame_ctl); ++ u16 sc = le16_to_cpu(header->seq_ctl); ++ u16 seq = WLAN_GET_SEQ_SEQ(sc); ++ u16 frag = WLAN_GET_SEQ_FRAG(sc); ++ u16 *last_seq, *last_frag; ++ unsigned long *last_time; ++ struct ieee80211_hdr_3addr_QOS *hdr_3addr_QoS; ++ struct ieee80211_hdr_QOS *hdr_4addr_QoS; ++ u8 tid; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ tid = (header->addr2[ETH_ALEN-2] ^ header->addr2[ETH_ALEN-1]) & IEEE80211_QOS_TID; ++ } ++ else ++#endif ++ //TO2DS and QoS ++ if(((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS)&&IEEE80211_QOS_HAS_SEQ(fc)) { ++ hdr_4addr_QoS = (struct ieee80211_hdr_QOS *)header; ++ tid = le16_to_cpu(hdr_4addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else if(IEEE80211_QOS_HAS_SEQ(fc)) { //QoS ++ hdr_3addr_QoS = (struct ieee80211_hdr_3addr_QOS*)header; ++ tid = le16_to_cpu(hdr_3addr_QoS->QOS_ctl) & IEEE80211_QOS_TID; ++ tid = UP2AC(tid); ++ tid ++; ++ } else { // no QoS ++ tid = 0; ++ } ++ switch (ieee->iw_mode) { ++ case IW_MODE_ADHOC: ++ { ++ struct list_head *p; ++ struct ieee_ibss_seq *entry = NULL; ++ u8 *mac = header->addr2; ++ int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; ++ //for (pos = (head)->next; pos != (head); pos = pos->next) ++ __list_for_each(p, &ieee->ibss_mac_hash[index]) { ++ entry = list_entry(p, struct ieee_ibss_seq, list); ++ if (!memcmp(entry->mac, mac, ETH_ALEN)) ++ break; ++ } ++ // if (memcmp(entry->mac, mac, ETH_ALEN)){ ++ if (p == &ieee->ibss_mac_hash[index]) { ++ entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); ++ if (!entry) { ++ printk(KERN_WARNING "Cannot malloc new mac entry\n"); ++ return 0; ++ } ++ memcpy(entry->mac, mac, ETH_ALEN); ++ entry->seq_num[tid] = seq; ++ entry->frag_num[tid] = frag; ++ entry->packet_time[tid] = jiffies; ++ list_add(&entry->list, &ieee->ibss_mac_hash[index]); ++ return 0; ++ } ++ last_seq = &entry->seq_num[tid]; ++ last_frag = &entry->frag_num[tid]; ++ last_time = &entry->packet_time[tid]; ++ break; ++ } ++ ++ case IW_MODE_INFRA: ++ last_seq = &ieee->last_rxseq_num[tid]; ++ last_frag = &ieee->last_rxfrag_num[tid]; ++ last_time = &ieee->last_packet_time[tid]; ++ ++ break; ++ default: ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ { ++ last_seq = &ieee->last_rxseq_num[tid]; ++ last_frag = &ieee->last_rxfrag_num[tid]; ++ last_time = &ieee->last_packet_time[tid]; ++ break; ++ } ++ else ++#endif ++ return 0; ++ } ++ ++// if(tid != 0) { ++// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl); ++// } ++ if ((*last_seq == seq) && ++ time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { ++ if (*last_frag == frag){ ++ //printk(KERN_WARNING "[1] go drop!\n"); ++ goto drop; ++ ++ } ++ if (*last_frag + 1 != frag) ++ /* out-of-order fragment */ ++ //printk(KERN_WARNING "[2] go drop!\n"); ++ goto drop; ++ } else ++ *last_seq = seq; ++ ++ *last_frag = frag; ++ *last_time = jiffies; ++ return 0; ++ ++drop: ++// BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); ++// printk("DUP\n"); ++ ++ return 1; ++} ++ ++ ++/* All received frames are sent to this function. @skb contains the frame in ++ * IEEE 802.11 format, i.e., in the format it was sent over air. ++ * This function is called only as a tasklet (software IRQ). */ ++int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats) ++{ ++ struct net_device *dev = ieee->dev; ++ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct ieee80211_hdr *hdr; ++ //struct ieee80211_hdr_3addr_QOS *hdr; ++ ++ size_t hdrlen; ++ u16 fc, type, stype, sc; ++ struct net_device_stats *stats; ++ unsigned int frag; ++ u8 *payload; ++ u16 ethertype; ++#ifdef NOT_YET ++ struct net_device *wds = NULL; ++ struct sk_buff *skb2 = NULL; ++ struct net_device *wds = NULL; ++ int frame_authorized = 0; ++ int from_assoc_ap = 0; ++ void *sta = NULL; ++#endif ++// u16 QOS_ctl = 0; ++ u8 dst[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++ u8 bssid[ETH_ALEN]; ++ struct ieee80211_crypt_data *crypt = NULL; ++ int keyidx = 0; ++ ++ //Added for mesh by Lawrence. ++#ifdef _RTL8187_EXT_PATCH_ ++ u8 status; ++ u32 flags; ++#endif ++ // cheat the the hdr type ++ hdr = (struct ieee80211_hdr *)skb->data; ++ stats = &ieee->stats; ++ ++ if (skb->len < 10) { ++ printk(KERN_INFO "%s: SKB length < 10\n", ++ dev->name); ++ goto rx_dropped; ++ } ++ ++ fc = le16_to_cpu(hdr->frame_ctl); ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ sc = le16_to_cpu(hdr->seq_ctl); ++ ++ frag = WLAN_GET_SEQ_FRAG(sc); ++ ++//YJ,add,080828,for keep alive ++ if((fc & IEEE80211_FCTL_TODS) != IEEE80211_FCTL_TODS) ++ { ++ if(!memcmp(hdr->addr1,dev->dev_addr, ETH_ALEN)) ++ { ++ ieee->NumRxUnicast++; ++ } ++ } ++ else ++ { ++ if(!memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) ++ { ++ ieee->NumRxUnicast++; ++ } ++ } ++//YJ,add,080828,for keep alive,end ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_rx_frame_get_hdrlen)) ++ { ++ hdrlen = ieee->ext_patch_ieee80211_rx_frame_get_hdrlen(ieee, skb); ++ if(skb->len < hdrlen) ++ goto rx_dropped; ++ } ++ else ++#endif ++ hdrlen = ieee80211_get_hdrlen(fc); ++ ++#ifdef NOT_YET ++#if WIRELESS_EXT > 15 ++ /* Put this code here so that we avoid duplicating it in all ++ * Rx paths. - Jean II */ ++#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ ++ /* If spy monitoring on */ ++ if (iface->spy_data.spy_number > 0) { ++ struct iw_quality wstats; ++ wstats.level = rx_stats->signal; ++ wstats.noise = rx_stats->noise; ++ wstats.updated = 6; /* No qual value */ ++ /* Update spy records */ ++ wireless_spy_update(dev, hdr->addr2, &wstats); ++ } ++#endif /* IW_WIRELESS_SPY */ ++#endif /* WIRELESS_EXT > 15 */ ++ hostap_update_rx_stats(local->ap, hdr, rx_stats); ++#endif ++ ++#if WIRELESS_EXT > 15 ++ if (ieee->iw_mode == IW_MODE_MONITOR) { ++ ieee80211_monitor_rx(ieee, skb, rx_stats); ++ stats->rx_packets++; ++ stats->rx_bytes += skb->len; ++ return 1; ++ } ++#endif ++ if (ieee->host_decrypt) { ++ int idx = 0; ++ if (skb->len >= hdrlen + 3) ++ idx = skb->data[hdrlen + 3] >> 6; ++ crypt = ieee->crypt[idx]; ++#ifdef NOT_YET ++ sta = NULL; ++ ++ /* Use station specific key to override default keys if the ++ * receiver address is a unicast address ("individual RA"). If ++ * bcrx_sta_key parameter is set, station specific key is used ++ * even with broad/multicast targets (this is against IEEE ++ * 802.11, but makes it easier to use different keys with ++ * stations that do not support WEP key mapping). */ ++ ++ if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) ++ (void) hostap_handle_sta_crypto(local, hdr, &crypt, ++ &sta); ++#endif ++ ++ /* allow NULL decrypt to indicate an station specific override ++ * for default encryption */ ++ if (crypt && (crypt->ops == NULL || ++ crypt->ops->decrypt_mpdu == NULL)) ++ crypt = NULL; ++ ++ if (!crypt && (fc & IEEE80211_FCTL_WEP)) { ++ /* This seems to be triggered by some (multicast?) ++ * frames from other than current BSS, so just drop the ++ * frames silently instead of filling system log with ++ * these reports. */ ++ IEEE80211_DEBUG_DROP("Decryption failed (not set)" ++ " (SA=" MAC_FMT ")\n", ++ MAC_ARG(hdr->addr2)); ++ ieee->ieee_stats.rx_discards_undecryptable++; ++ goto rx_dropped; ++ } ++ } ++ ++ if (skb->len < IEEE80211_DATA_HDR3_LEN) ++ goto rx_dropped; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_update_expire ) ++ ieee->ext_patch_ieee80211_rx_mgt_update_expire( ieee, skb ); ++#endif ++ ++ // if QoS enabled, should check the sequence for each of the AC ++ if (is_duplicate_packet(ieee, hdr)) ++ goto rx_dropped; ++ ++ ++ if (type == IEEE80211_FTYPE_MGMT) { ++ ++ #if 0 ++ if ( stype == IEEE80211_STYPE_AUTH && ++ fc & IEEE80211_FCTL_WEP && ieee->host_decrypt && ++ (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) ++ { ++ printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " ++ "from " MAC_FMT "\n", dev->name, ++ MAC_ARG(hdr->addr2)); ++ /* TODO: could inform hostapd about this so that it ++ * could send auth failure report */ ++ goto rx_dropped; ++ } ++ #endif ++ ++ ++ if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) ++ goto rx_dropped; ++ else ++ goto rx_exit; ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_on_rx) ++ { ++ if(ieee->ext_patch_ieee80211_rx_on_rx(ieee, skb, rx_stats, type, stype)==0) ++ { ++ goto rx_exit; ++ } ++ } ++#endif ++ ++ /* Data frame - extract src/dst addresses */ ++ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { ++ case IEEE80211_FCTL_FROMDS: ++ memcpy(dst, hdr->addr1, ETH_ALEN); ++ memcpy(src, hdr->addr3, ETH_ALEN); ++ memcpy(bssid,hdr->addr2,ETH_ALEN); ++ break; ++ case IEEE80211_FCTL_TODS: ++ memcpy(dst, hdr->addr3, ETH_ALEN); ++ memcpy(src, hdr->addr2, ETH_ALEN); ++ memcpy(bssid,hdr->addr1,ETH_ALEN); ++ break; ++ case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: ++ if (skb->len < IEEE80211_DATA_HDR4_LEN) ++ goto rx_dropped; ++ memcpy(dst, hdr->addr3, ETH_ALEN); ++ memcpy(src, hdr->addr4, ETH_ALEN); ++ memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); ++ break; ++ case 0: ++ memcpy(dst, hdr->addr1, ETH_ALEN); ++ memcpy(src, hdr->addr2, ETH_ALEN); ++ memcpy(bssid,hdr->addr3,ETH_ALEN); ++ break; ++ } ++ ++#ifdef NOT_YET ++ if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) ++ goto rx_dropped; ++ if (wds) { ++ skb->dev = dev = wds; ++ stats = hostap_get_stats(dev); ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ++ (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS && ++ ieee->stadev && ++ memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { ++ /* Frame from BSSID of the AP for which we are a client */ ++ skb->dev = dev = ieee->stadev; ++ stats = hostap_get_stats(dev); ++ from_assoc_ap = 1; ++ } ++#endif ++ ++ dev->last_rx = jiffies; ++ ++#ifdef NOT_YET ++ if ((ieee->iw_mode == IW_MODE_MASTER || ++ ieee->iw_mode == IW_MODE_REPEAT) && ++ !from_assoc_ap) { ++ switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, ++ wds != NULL)) { ++ case AP_RX_CONTINUE_NOT_AUTHORIZED: ++ frame_authorized = 0; ++ break; ++ case AP_RX_CONTINUE: ++ frame_authorized = 1; ++ break; ++ case AP_RX_DROP: ++ goto rx_dropped; ++ case AP_RX_EXIT: ++ goto rx_exit; ++ } ++ } ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_is_valid_framectl) ++ { ++ if(ieee->ext_patch_ieee80211_rx_is_valid_framectl(ieee, fc, type, stype)==0) ++ goto rx_dropped; ++ } ++ else ++#endif ++ /* Nullfunc frames may have PS-bit set, so they must be passed to ++ * hostap_handle_sta_rx() before being dropped here. */ ++ if (stype != IEEE80211_STYPE_DATA && ++ stype != IEEE80211_STYPE_DATA_CFACK && ++ stype != IEEE80211_STYPE_DATA_CFPOLL && ++ stype != IEEE80211_STYPE_DATA_CFACKPOLL&& ++ stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4 ++ ) { ++ if (stype != IEEE80211_STYPE_NULLFUNC) ++ IEEE80211_DEBUG_DROP( ++ "RX: dropped data frame " ++ "with no data (type=0x%02x, " ++ "subtype=0x%02x, len=%d)\n", ++ type, stype, skb->len); ++ goto rx_dropped; ++ } ++ if(memcmp(bssid,ieee->current_network.bssid,ETH_ALEN)) { ++ goto rx_dropped; ++ } ++ ++ ieee->NumRxDataInPeriod++; ++ ieee->NumRxOkTotal++; ++ /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ ++ ++ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) ++ goto rx_dropped; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ++ /* skb: hdr + (possibly fragmented) plaintext payload */ ++ // PR: FIXME: hostap has additional conditions in the "if" below: ++ // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { ++ int flen; ++ struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); ++ IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); ++ ++ if (!frag_skb) { ++ IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, ++ "Rx cannot get skb from fragment " ++ "cache (morefrag=%d seq=%u frag=%u)\n", ++ (fc & IEEE80211_FCTL_MOREFRAGS) != 0, ++ WLAN_GET_SEQ_SEQ(sc), frag); ++ goto rx_dropped; ++ } ++ flen = skb->len; ++ if (frag != 0) ++ flen -= hdrlen; ++ ++ if (frag_skb->tail + flen > frag_skb->end) { ++ printk(KERN_WARNING "%s: host decrypted and " ++ "reassembled frame did not fit skb\n", ++ dev->name); ++ ieee80211_frag_cache_invalidate(ieee, hdr); ++ goto rx_dropped; ++ } ++ ++ if (frag == 0) { ++ /* copy first fragment (including full headers) into ++ * beginning of the fragment cache skb */ ++ memcpy(skb_put(frag_skb, flen), skb->data, flen); ++ } else { ++ /* append frame payload to the end of the fragment ++ * cache skb */ ++ memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, ++ flen); ++ } ++ dev_kfree_skb_any(skb); ++ skb = NULL; ++ ++ if (fc & IEEE80211_FCTL_MOREFRAGS) { ++ /* more fragments expected - leave the skb in fragment ++ * cache for now; it will be delivered to upper layers ++ * after all fragments have been received */ ++ goto rx_exit; ++ } ++ ++ /* this was the last fragment and the frame will be ++ * delivered, so remove skb from fragment cache */ ++ skb = frag_skb; ++ hdr = (struct ieee80211_hdr *) skb->data; ++ ieee80211_frag_cache_invalidate(ieee, hdr); ++ } ++ ++ /* skb: hdr + (possible reassembled) full MSDU payload; possibly still ++ * encrypted/authenticated */ ++ if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && ++ ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) ++ goto rx_dropped; ++ ++ hdr = (struct ieee80211_hdr *) skb->data; ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) { ++ if (/*ieee->ieee802_1x &&*/ ++ ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ /* pass unencrypted EAPOL frames even if encryption is ++ * configured */ ++ struct eapol *eap = (struct eapol *)(skb->data + ++ 24); ++ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++#endif ++ } else { ++ IEEE80211_DEBUG_DROP( ++ "encryption configured, but RX " ++ "frame not encrypted (SA=" MAC_FMT ")\n", ++ MAC_ARG(hdr->addr2)); ++ goto rx_dropped; ++ } ++ } ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && ++ ieee80211_is_eapol_frame(ieee, skb)) { ++ struct eapol *eap = (struct eapol *)(skb->data + ++ 24); ++ IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++ } ++#endif ++ ++ if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep && ++ !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ IEEE80211_DEBUG_DROP( ++ "dropped unencrypted RX data " ++ "frame from " MAC_FMT ++ " (drop_unencrypted=1)\n", ++ MAC_ARG(hdr->addr2)); ++ goto rx_dropped; ++ } ++/* ++ if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { ++ printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n"); ++ } ++*/ ++ /* skb: hdr + (possible reassembled) full plaintext payload */ ++ payload = skb->data + hdrlen; ++ ethertype = (payload[6] << 8) | payload[7]; ++ ++#ifdef NOT_YET ++ /* If IEEE 802.1X is used, check whether the port is authorized to send ++ * the received frame. */ ++ if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) { ++ if (ethertype == ETH_P_PAE) { ++ printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", ++ dev->name); ++ if (ieee->hostapd && ieee->apdev) { ++ /* Send IEEE 802.1X frames to the user ++ * space daemon for processing */ ++ prism2_rx_80211(ieee->apdev, skb, rx_stats, ++ PRISM2_RX_MGMT); ++ ieee->apdevstats.rx_packets++; ++ ieee->apdevstats.rx_bytes += skb->len; ++ goto rx_exit; ++ } ++ } else if (!frame_authorized) { ++ printk(KERN_DEBUG "%s: dropped frame from " ++ "unauthorized port (IEEE 802.1X): " ++ "ethertype=0x%04x\n", ++ dev->name, ethertype); ++ goto rx_dropped; ++ } ++ } ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_process_dataframe) ++ { ++ //Added for mesh rx interrupt. ++ //spin_lock_irqsave(&ieee->lock,flags); ++ status = ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats); ++ //spin_unlock_irqrestore(&ieee->lock,flags); ++ ++ if(status) ++// if(ieee->ext_patch_ieee80211_rx_process_dataframe(ieee, skb, rx_stats)) ++ goto rx_exit; ++ else ++ goto rx_dropped; ++ } ++#endif ++ ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ if (skb->len - hdrlen >= 8 && ++ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && ++ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ++ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and ++ * replace EtherType */ ++ skb_pull(skb, hdrlen + SNAP_SIZE); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ skb_pull(skb, hdrlen); ++ len = htons(skb->len); ++ memcpy(skb_push(skb, 2), &len, 2); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } ++ ++#ifdef NOT_YET ++ if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == ++ IEEE80211_FCTL_TODS) && ++ skb->len >= ETH_HLEN + ETH_ALEN) { ++ /* Non-standard frame: get addr4 from its bogus location after ++ * the payload */ ++ memcpy(skb->data + ETH_ALEN, ++ skb->data + skb->len - ETH_ALEN, ETH_ALEN); ++ skb_trim(skb, skb->len - ETH_ALEN); ++ } ++#endif ++ ++ stats->rx_packets++; ++ stats->rx_bytes += skb->len; ++ ++#ifdef NOT_YET ++ if (ieee->iw_mode == IW_MODE_MASTER && !wds && ++ ieee->ap->bridge_packets) { ++ if (dst[0] & 0x01) { ++ /* copy multicast frame both to the higher layers and ++ * to the wireless media */ ++ ieee->ap->bridged_multicast++; ++ skb2 = skb_clone(skb, GFP_ATOMIC); ++ if (skb2 == NULL) ++ printk(KERN_DEBUG "%s: skb_clone failed for " ++ "multicast frame\n", dev->name); ++ } else if (hostap_is_sta_assoc(ieee->ap, dst)) { ++ /* send frame directly to the associated STA using ++ * wireless media and not passing to higher layers */ ++ ieee->ap->bridged_unicast++; ++ skb2 = skb; ++ skb = NULL; ++ } ++ } ++ ++ if (skb2 != NULL) { ++ /* send to wireless media */ ++ skb2->protocol = __constant_htons(ETH_P_802_3); ++ skb2->mac.raw = skb2->nh.raw = skb2->data; ++ /* skb2->nh.raw = skb2->data + ETH_HLEN; */ ++ skb2->dev = dev; ++ dev_queue_xmit(skb2); ++ } ++ ++#endif ++ if (skb) { ++ skb->protocol = eth_type_trans(skb, dev); ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ skb->dev = dev; ++ skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ ++ ieee->last_rx_ps_time = jiffies; ++ netif_rx(skb); ++ } ++ ++ rx_exit: ++#ifdef NOT_YET ++ if (sta) ++ hostap_handle_sta_release(sta); ++#endif ++ return 1; ++ ++ rx_dropped: ++ stats->rx_dropped++; ++ ++ /* Returning 0 indicates to caller that we have not handled the SKB-- ++ * so it is still allocated and can be used again by underlying ++ * hardware as a DMA target */ ++ return 0; ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++int ieee_ext_skb_p80211_to_ether(struct sk_buff *skb, int hdrlen, u8 *dst, u8 *src) ++{ ++ u8 *payload; ++ u16 ethertype; ++ ++ /* skb: hdr + (possible reassembled) full plaintext payload */ ++ payload = skb->data + hdrlen; ++ ethertype = (payload[6] << 8) | payload[7]; ++ ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ if (skb->len - hdrlen >= 8 && ++ ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && ++ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ++ memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and ++ * replace EtherType */ ++ skb_pull(skb, hdrlen + SNAP_SIZE); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } else { ++ u16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ skb_pull(skb, hdrlen); ++ len = htons(skb->len); ++ memcpy(skb_push(skb, 2), &len, 2); ++ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); ++ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); ++ } ++ ++ return 1; ++} ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ++#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 ++ ++static inline int ieee80211_is_ofdm_rate(u8 rate) ++{ ++ switch (rate & ~IEEE80211_BASIC_RATE_MASK) { ++ case IEEE80211_OFDM_RATE_6MB: ++ case IEEE80211_OFDM_RATE_9MB: ++ case IEEE80211_OFDM_RATE_12MB: ++ case IEEE80211_OFDM_RATE_18MB: ++ case IEEE80211_OFDM_RATE_24MB: ++ case IEEE80211_OFDM_RATE_36MB: ++ case IEEE80211_OFDM_RATE_48MB: ++ case IEEE80211_OFDM_RATE_54MB: ++ return 1; ++ } ++ return 0; ++} ++ ++static inline int ieee80211_SignalStrengthTranslate( ++ int CurrSS ++ ) ++{ ++ int RetSS; ++ ++ // Step 1. Scale mapping. ++ if(CurrSS >= 71 && CurrSS <= 100) ++ { ++ RetSS = 90 + ((CurrSS - 70) / 3); ++ } ++ else if(CurrSS >= 41 && CurrSS <= 70) ++ { ++ RetSS = 78 + ((CurrSS - 40) / 3); ++ } ++ else if(CurrSS >= 31 && CurrSS <= 40) ++ { ++ RetSS = 66 + (CurrSS - 30); ++ } ++ else if(CurrSS >= 21 && CurrSS <= 30) ++ { ++ RetSS = 54 + (CurrSS - 20); ++ } ++ else if(CurrSS >= 5 && CurrSS <= 20) ++ { ++ RetSS = 42 + (((CurrSS - 5) * 2) / 3); ++ } ++ else if(CurrSS == 4) ++ { ++ RetSS = 36; ++ } ++ else if(CurrSS == 3) ++ { ++ RetSS = 27; ++ } ++ else if(CurrSS == 2) ++ { ++ RetSS = 18; ++ } ++ else if(CurrSS == 1) ++ { ++ RetSS = 9; ++ } ++ else ++ { ++ RetSS = CurrSS; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ // Step 2. Smoothing. ++ ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ return RetSS; ++} ++ ++#ifdef ENABLE_DOT11D ++static inline void ieee80211_extract_country_ie( ++ struct ieee80211_device *ieee, ++ struct ieee80211_info_element *info_element, ++ struct ieee80211_network *network, ++ u8 * addr2 ++) ++{ ++#if 0 ++ u32 i = 0; ++ u8 * p = (u8*)info_element->data; ++ printk("-----------------------\n"); ++ printk("%s Country IE:", network->ssid); ++ for(i=0; ilen; i++) ++ printk("\t%2.2x", *(p+i)); ++ printk("\n-----------------------\n"); ++#endif ++ if(IS_DOT11D_ENABLE(ieee)) ++ { ++ if(info_element->len!= 0) ++ { ++ memcpy(network->CountryIeBuf, info_element->data, info_element->len); ++ network->CountryIeLen = info_element->len; ++ ++ if(!IS_COUNTRY_IE_VALID(ieee)) ++ { ++ Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); ++ } ++ } ++ ++ // ++ // 070305, rcnjko: I update country IE watch dog here because ++ // some AP (e.g. Cisco 1242) don't include country IE in their ++ // probe response frame. ++ // ++ if(IS_EQUAL_CIE_SRC(ieee, addr2) ) ++ { ++ UPDATE_CIE_WATCHDOG(ieee); ++ } ++ } ++ ++} ++#endif ++ ++int ++ieee80211_TranslateToDbm( ++ unsigned char SignalStrengthIndex // 0-100 index. ++ ) ++{ ++ unsigned char SignalPower; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ SignalPower = (int)SignalStrengthIndex * 7 / 10; ++ SignalPower -= 95; ++ ++ return SignalPower; ++} ++inline int ieee80211_network_init( ++ struct ieee80211_device *ieee, ++ struct ieee80211_probe_response *beacon, ++ struct ieee80211_network *network, ++ struct ieee80211_rx_stats *stats) ++{ ++#ifdef CONFIG_IEEE80211_DEBUG ++ char rates_str[64]; ++ char *p; ++#endif ++ struct ieee80211_info_element *info_element; ++ u16 left; ++ u8 i; ++ short offset; ++ u8 curRate = 0,hOpRate = 0,curRate_ex = 0; ++ ++ /* Pull out fixed field data */ ++ memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); ++ network->capability = beacon->capability; ++ network->last_scanned = jiffies; ++ network->time_stamp[0] = beacon->time_stamp[0]; ++ network->time_stamp[1] = beacon->time_stamp[1]; ++ network->beacon_interval = beacon->beacon_interval; ++ /* Where to pull this? beacon->listen_interval;*/ ++ network->listen_interval = 0x0A; ++ network->rates_len = network->rates_ex_len = 0; ++ network->last_associate = 0; ++ network->ssid_len = 0; ++ network->flags = 0; ++ network->atim_window = 0; ++ network->QoS_Enable = 0; ++//by amy 080312 ++ network->HighestOperaRate = 0; ++//by amy 080312 ++#ifdef THOMAS_TURBO ++ network->Turbo_Enable = 0; ++#endif ++#ifdef ENABLE_DOT11D ++ network->CountryIeLen = 0; ++ memset(network->CountryIeBuf, 0, MAX_IE_LEN); ++#endif ++ ++ if (stats->freq == IEEE80211_52GHZ_BAND) { ++ /* for A band (No DS info) */ ++ network->channel = stats->received_channel; ++ } else ++ network->flags |= NETWORK_HAS_CCK; ++ ++ network->wpa_ie_len = 0; ++ network->rsn_ie_len = 0; ++ ++ info_element = &beacon->info_element; ++ left = stats->len - ((void *)info_element - (void *)beacon); ++ while (left >= sizeof(struct ieee80211_info_element_hdr)) { ++ if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { ++ IEEE80211_DEBUG_SCAN("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%d left=%d.\n", ++ info_element->len + sizeof(struct ieee80211_info_element), ++ left); ++ return 1; ++ } ++ ++ switch (info_element->id) { ++ case MFIE_TYPE_SSID: ++ if (ieee80211_is_empty_essid(info_element->data, ++ info_element->len)) { ++ network->flags |= NETWORK_EMPTY_ESSID; ++ break; ++ } ++ ++ network->ssid_len = min(info_element->len, ++ (u8)IW_ESSID_MAX_SIZE); ++ memcpy(network->ssid, info_element->data, network->ssid_len); ++ if (network->ssid_len < IW_ESSID_MAX_SIZE) ++ memset(network->ssid + network->ssid_len, 0, ++ IW_ESSID_MAX_SIZE - network->ssid_len); ++ ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n", ++ network->ssid, network->ssid_len); ++ break; ++ ++ case MFIE_TYPE_RATES: ++#ifdef CONFIG_IEEE80211_DEBUG ++ p = rates_str; ++#endif ++ network->rates_len = min(info_element->len, MAX_RATES_LENGTH); ++ for (i = 0; i < network->rates_len; i++) { ++ network->rates[i] = info_element->data[i]; ++ curRate = network->rates[i] & 0x7f; ++ if( hOpRate < curRate ) ++ hOpRate = curRate; ++#ifdef CONFIG_IEEE80211_DEBUG ++ p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); ++#endif ++ if (ieee80211_is_ofdm_rate(info_element->data[i])) { ++ network->flags |= NETWORK_HAS_OFDM; ++ if (info_element->data[i] & ++ IEEE80211_BASIC_RATE_MASK) ++ network->flags &= ++ ~NETWORK_HAS_CCK; ++ } ++ } ++ ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n", ++ rates_str, network->rates_len); ++ break; ++ ++ case MFIE_TYPE_RATES_EX: ++#ifdef CONFIG_IEEE80211_DEBUG ++ p = rates_str; ++#endif ++ network->rates_ex_len = min(info_element->len, MAX_RATES_EX_LENGTH); ++ for (i = 0; i < network->rates_ex_len; i++) { ++ network->rates_ex[i] = info_element->data[i]; ++ curRate_ex = network->rates_ex[i] & 0x7f; ++ if( hOpRate < curRate_ex ) ++ hOpRate = curRate_ex; ++#ifdef CONFIG_IEEE80211_DEBUG ++ p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); ++#endif ++ if (ieee80211_is_ofdm_rate(info_element->data[i])) { ++ network->flags |= NETWORK_HAS_OFDM; ++ if (info_element->data[i] & ++ IEEE80211_BASIC_RATE_MASK) ++ network->flags &= ++ ~NETWORK_HAS_CCK; ++ } ++ } ++ ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n", ++ rates_str, network->rates_ex_len); ++ break; ++ ++ case MFIE_TYPE_DS_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n", ++ info_element->data[0]); ++ if (stats->freq == IEEE80211_24GHZ_BAND) ++ network->channel = info_element->data[0]; ++ break; ++ ++ case MFIE_TYPE_FH_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_CF_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_TIM: ++ ++ if(info_element->len < 4) ++ break; ++ ++ network->dtim_period = info_element->data[1]; ++ ++ if(ieee->state != IEEE80211_LINKED) ++ break; ++#if 0 ++ network->last_dtim_sta_time[0] = stats->mac_time[0]; ++#else ++ network->last_dtim_sta_time[0] = jiffies; ++#endif ++ network->last_dtim_sta_time[1] = stats->mac_time[1]; ++ ++ network->dtim_data = IEEE80211_DTIM_VALID; ++ ++ if(info_element->data[0] != 0) ++ break; ++ ++ if(info_element->data[2] & 1) ++ network->dtim_data |= IEEE80211_DTIM_MBCAST; ++ ++ offset = (info_element->data[2] >> 1)*2; ++ ++ //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id); ++ ++ /* add and modified for ps 2008.1.22 */ ++ if(ieee->assoc_id < 8*offset || ++ ieee->assoc_id > 8*(offset + info_element->len -3)) { ++ break; ++ } ++ ++ offset = (ieee->assoc_id/8) - offset;// + ((aid % 8)? 0 : 1) ; ++ ++ // printk("offset:%x data:%x, ucast:%d\n", offset, ++ // info_element->data[3+offset] , ++ // info_element->data[3+offset] & (1<<(ieee->assoc_id%8))); ++ ++ if(info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) { ++ network->dtim_data |= IEEE80211_DTIM_UCAST; ++ } ++ break; ++ ++ case MFIE_TYPE_IBSS_SET: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_CHALLENGE: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n"); ++ break; ++ ++ case MFIE_TYPE_GENERIC: ++ //nic is 87B ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", ++ info_element->len); ++ if (info_element->len >= 4 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x01) { ++ network->wpa_ie_len = min(info_element->len + 2, ++ MAX_WPA_IE_LEN); ++ memcpy(network->wpa_ie, info_element, ++ network->wpa_ie_len); ++ } ++ ++#ifdef THOMAS_TURBO ++ if (info_element->len == 7 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0xe0 && ++ info_element->data[2] == 0x4c && ++ info_element->data[3] == 0x01 && ++ info_element->data[4] == 0x02) { ++ network->Turbo_Enable = 1; ++ } ++#endif ++ if (1 == stats->nic_type) {//nic 87 ++ break; ++ } ++ ++ if (info_element->len >= 5 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x02 && ++ info_element->data[4] == 0x00) { ++ //printk(KERN_WARNING "wmm info updated: %x\n", info_element->data[6]); ++ //WMM Information Element ++ network->wmm_info = info_element->data[6]; ++ network->QoS_Enable = 1; ++ } ++ ++ if (info_element->len >= 8 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x02 && ++ info_element->data[4] == 0x01) { ++ // Not care about version at present. ++ //WMM Information Element ++ //printk(KERN_WARNING "wmm info¶m updated: %x\n", info_element->data[6]); ++ network->wmm_info = info_element->data[6]; ++ //WMM Parameter Element ++ memcpy(network->wmm_param, (u8 *)(info_element->data + 8),(info_element->len - 8)); ++ network->QoS_Enable = 1; ++ } ++ break; ++ ++ case MFIE_TYPE_RSN: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n", ++ info_element->len); ++ network->rsn_ie_len = min(info_element->len + 2, ++ MAX_WPA_IE_LEN); ++ memcpy(network->rsn_ie, info_element, ++ network->rsn_ie_len); ++ break; ++#ifdef ENABLE_DOT11D ++ case MFIE_TYPE_COUNTRY: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", ++ info_element->len); ++// printk("=====>Receive <%s> Country IE\n",network->ssid); ++ ieee80211_extract_country_ie(ieee, info_element, network, beacon->header.addr2); ++ break; ++#endif ++ default: ++ IEEE80211_DEBUG_SCAN("unsupported IE %d\n", ++ info_element->id); ++ break; ++ } ++ ++ left -= sizeof(struct ieee80211_info_element_hdr) + ++ info_element->len; ++ info_element = (struct ieee80211_info_element *) ++ &info_element->data[info_element->len]; ++ } ++//by amy 080312 ++ network->HighestOperaRate = hOpRate; ++//by amy 080312 ++ network->mode = 0; ++ if (stats->freq == IEEE80211_52GHZ_BAND) ++ network->mode = IEEE_A; ++ else { ++ if (network->flags & NETWORK_HAS_OFDM) ++ network->mode |= IEEE_G; ++ if (network->flags & NETWORK_HAS_CCK) ++ network->mode |= IEEE_B; ++ } ++ ++ if (network->mode == 0) { ++ IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " ++ "network.\n", ++ escape_essid(network->ssid, ++ network->ssid_len), ++ MAC_ARG(network->bssid)); ++ return 1; ++ } ++ ++ if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) ++ network->flags |= NETWORK_EMPTY_ESSID; ++#if 0 ++ stats->signal = ieee80211_SignalStrengthTranslate(stats->signal); ++#endif ++ stats->signal = ieee80211_TranslateToDbm(stats->signalstrength); ++ //stats->noise = stats->signal - stats->noise; ++ stats->noise = ieee80211_TranslateToDbm(100 - stats->signalstrength) - 25; ++ memcpy(&network->stats, stats, sizeof(network->stats)); ++ ++ return 0; ++} ++ ++static inline int is_same_network(struct ieee80211_network *src, ++ struct ieee80211_network *dst, ++ struct ieee80211_device * ieee) ++{ ++ /* A network is only a duplicate if the channel, BSSID, ESSID ++ * and the capability field (in particular IBSS and BSS) all match. ++ * We treat all with the same BSSID and channel ++ * as one network */ ++ return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap ++ //((src->ssid_len == dst->ssid_len) && ++ (src->channel == dst->channel) && ++ !memcmp(src->bssid, dst->bssid, ETH_ALEN) && ++ (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap ++ //!memcmp(src->ssid, dst->ssid, src->ssid_len) && ++ ((src->capability & WLAN_CAPABILITY_IBSS) == ++ (dst->capability & WLAN_CAPABILITY_IBSS)) && ++ ((src->capability & WLAN_CAPABILITY_BSS) == ++ (dst->capability & WLAN_CAPABILITY_BSS))); ++} ++ ++inline void update_network(struct ieee80211_network *dst, ++ struct ieee80211_network *src) ++{ ++ unsigned char quality = src->stats.signalstrength; ++ unsigned char signal = 0; ++ unsigned char noise = 0; ++ if(dst->stats.signalstrength > 0) { ++ quality = (dst->stats.signalstrength * 5 + src->stats.signalstrength + 5)/6; ++ } ++ signal = ieee80211_TranslateToDbm(quality); ++ //noise = signal - src->stats.noise; ++ if(dst->stats.noise > 0) ++ noise = (dst->stats.noise * 5 + src->stats.noise)/6; ++ //if(strcmp(dst->ssid, "linksys_lzm000") == 0) ++// printk("ssid:%s, quality:%d, signal:%d\n", dst->ssid, quality, signal); ++ memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); ++ dst->stats.signalstrength = quality; ++ dst->stats.signal = signal; ++// printk("==================>stats.signal is %d\n",dst->stats.signal); ++ dst->stats.noise = noise; ++ ++ ++ dst->capability = src->capability; ++ memcpy(dst->rates, src->rates, src->rates_len); ++ dst->rates_len = src->rates_len; ++ memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); ++ dst->rates_ex_len = src->rates_ex_len; ++ dst->HighestOperaRate= src->HighestOperaRate; ++ //printk("==========>in %s: src->ssid is %s,chan is %d\n",__FUNCTION__,src->ssid,src->channel); ++ ++ //YJ,add,080819,for hidden ap ++ if(src->ssid_len > 0) ++ { ++ //if(src->ssid_len == 13) ++ // printk("=====================>>>>>>>> Dst ssid: %s Src ssid: %s\n", dst->ssid, src->ssid); ++ memset(dst->ssid, 0, dst->ssid_len); ++ dst->ssid_len = src->ssid_len; ++ memcpy(dst->ssid, src->ssid, src->ssid_len); ++ } ++ //YJ,add,080819,for hidden ap,end ++ ++ dst->channel = src->channel; ++ dst->mode = src->mode; ++ dst->flags = src->flags; ++ dst->time_stamp[0] = src->time_stamp[0]; ++ dst->time_stamp[1] = src->time_stamp[1]; ++ ++ dst->beacon_interval = src->beacon_interval; ++ dst->listen_interval = src->listen_interval; ++ dst->atim_window = src->atim_window; ++ dst->dtim_period = src->dtim_period; ++ dst->dtim_data = src->dtim_data; ++ dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0]; ++ dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1]; ++// printk("update:%s, dtim_period:%x, dtim_data:%x\n", src->ssid, src->dtim_period, src->dtim_data); ++ memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); ++ dst->wpa_ie_len = src->wpa_ie_len; ++ memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); ++ dst->rsn_ie_len = src->rsn_ie_len; ++ ++ dst->last_scanned = jiffies; ++ /* dst->last_associate is not overwritten */ ++// disable QoS process now, added by David 2006/7/25 ++#if 1 ++ dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame. ++/* ++ if((dst->wmm_info^src->wmm_info)&0x0f) {//Param Set Count change, update Parameter ++ memcpy(dst->wmm_param, src->wmm_param, IEEE80211_AC_PRAM_LEN); ++ } ++*/ ++ if(src->wmm_param[0].ac_aci_acm_aifsn|| \ ++ src->wmm_param[1].ac_aci_acm_aifsn|| \ ++ src->wmm_param[2].ac_aci_acm_aifsn|| \ ++ src->wmm_param[1].ac_aci_acm_aifsn) { ++ memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); ++ } ++ dst->QoS_Enable = src->QoS_Enable; ++#else ++ dst->QoS_Enable = 1;//for Rtl8187 simulation ++#endif ++ dst->SignalStrength = src->SignalStrength; ++#ifdef THOMAS_TURBO ++ dst->Turbo_Enable = src->Turbo_Enable; ++#endif ++#ifdef ENABLE_DOT11D ++ dst->CountryIeLen = src->CountryIeLen; ++ memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); ++#endif ++} ++ ++ ++inline void ieee80211_process_probe_response( ++ struct ieee80211_device *ieee, ++ struct ieee80211_probe_response *beacon, ++ struct ieee80211_rx_stats *stats) ++{ ++ struct ieee80211_network network; ++ struct ieee80211_network *target; ++ struct ieee80211_network *oldest = NULL; ++#ifdef CONFIG_IEEE80211_DEBUG ++ struct ieee80211_info_element *info_element = &beacon->info_element; ++#endif ++ unsigned long flags; ++ short renew; ++ u8 wmm_info; ++ u8 is_beacon = (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON)? 1:0; //YJ,add,080819,for hidden ap ++ ++ memset(&network, 0, sizeof(struct ieee80211_network)); ++//rz ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_process_probe_response_1) { ++ ieee->ext_patch_ieee80211_process_probe_response_1(ieee, beacon, stats); ++ return; ++ } ++#endif ++ ++ IEEE80211_DEBUG_SCAN( ++ "'%s' (" MAC_FMT "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", ++ escape_essid(info_element->data, info_element->len), ++ MAC_ARG(beacon->header.addr3), ++ (beacon->capability & (1<<0xf)) ? '1' : '0', ++ (beacon->capability & (1<<0xe)) ? '1' : '0', ++ (beacon->capability & (1<<0xd)) ? '1' : '0', ++ (beacon->capability & (1<<0xc)) ? '1' : '0', ++ (beacon->capability & (1<<0xb)) ? '1' : '0', ++ (beacon->capability & (1<<0xa)) ? '1' : '0', ++ (beacon->capability & (1<<0x9)) ? '1' : '0', ++ (beacon->capability & (1<<0x8)) ? '1' : '0', ++ (beacon->capability & (1<<0x7)) ? '1' : '0', ++ (beacon->capability & (1<<0x6)) ? '1' : '0', ++ (beacon->capability & (1<<0x5)) ? '1' : '0', ++ (beacon->capability & (1<<0x4)) ? '1' : '0', ++ (beacon->capability & (1<<0x3)) ? '1' : '0', ++ (beacon->capability & (1<<0x2)) ? '1' : '0', ++ (beacon->capability & (1<<0x1)) ? '1' : '0', ++ (beacon->capability & (1<<0x0)) ? '1' : '0'); ++#if 0 ++ if(strcmp(escape_essid(beacon->info_element.data, beacon->info_element.len), "rtl_softap") == 0) ++ { ++ if(WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON) ++ { ++ u32 i = 0, len = stats->len; ++ u8 * p = (u8*)beacon; ++ printk("-----------------------\n"); ++ printk("rtl_softap Beacon:"); ++ for(i=0; idata, ++ info_element->len), ++ MAC_ARG(beacon->header.addr3), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++ return; ++ } ++ ++#ifdef ENABLE_DOT11D ++ // For Asus EeePc request, ++ // (1) if wireless adapter receive get any 802.11d country code in AP beacon, ++ // wireless adapter should follow the country code. ++ // (2) If there is no any country code in beacon, ++ // then wireless adapter should do active scan from ch1~11 and ++ // passive scan from ch12~14 ++ if(ieee->bGlobalDomain) ++ { ++ if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) ++ { ++ // Case 1: Country code ++ if(IS_COUNTRY_IE_VALID(ieee) ) ++ { ++ if( !IsLegalChannel(ieee, network.channel) ) ++ { ++ printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ // Case 2: No any country code. ++ else ++ { ++ // Filter over channel ch12~14 ++ if(network.channel > 11) ++ { ++ printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); ++ return; ++ } ++ } ++ } ++ else ++ { ++ // Case 1: Country code ++ if(IS_COUNTRY_IE_VALID(ieee) ) ++ { ++ if( !IsLegalChannel(ieee, network.channel) ) ++ { ++ printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n",network.channel); ++ return; ++ } ++ } ++ // Case 2: No any country code. ++ else ++ { ++ // Filter over channel ch12~14 ++ if(network.channel > 14) ++ { ++ printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n",network.channel); ++ return; ++ } ++ } ++ } ++ } ++#endif ++ /* The network parsed correctly -- so now we scan our known networks ++ * to see if we can find it in our list. ++ * ++ * NOTE: This search is definitely not optimized. Once its doing ++ * the "right thing" we'll optimize it for efficiency if ++ * necessary */ ++ ++ /* Search for this entry in the list and update it if it is ++ * already there. */ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(is_same_network(&ieee->current_network, &network, ieee)) { ++ wmm_info = ieee->current_network.wmm_info; ++ //YJ,add,080819,for hidden ap ++ if(is_beacon == 0) ++ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); ++ else if(ieee->state == IEEE80211_LINKED) ++ ieee->NumRxBcnInPeriod++; ++ //YJ,add,080819,for hidden ap,end ++ //printk("====>network.ssid=%s cur_ssid=%s\n", network.ssid, ieee->current_network.ssid); ++ update_network(&ieee->current_network, &network); ++ } ++ ++ list_for_each_entry(target, &ieee->network_list, list) { ++ if (is_same_network(target, &network, ieee)) ++ break; ++ if ((oldest == NULL) || ++ (target->last_scanned < oldest->last_scanned)) ++ oldest = target; ++ } ++ ++ /* If we didn't find a match, then get a new network slot to initialize ++ * with this beacon's information */ ++ if (&target->list == &ieee->network_list) { ++ if (list_empty(&ieee->network_free_list)) { ++ /* If there are no more slots, expire the oldest */ ++ list_del(&oldest->list); ++ target = oldest; ++ IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " ++ "network list.\n", ++ escape_essid(target->ssid, ++ target->ssid_len), ++ MAC_ARG(target->bssid)); ++ } else { ++ /* Otherwise just pull from the free list */ ++ target = list_entry(ieee->network_free_list.next, ++ struct ieee80211_network, list); ++ list_del(ieee->network_free_list.next); ++ } ++ ++ ++#ifdef CONFIG_IEEE80211_DEBUG ++ IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(network.ssid, ++ network.ssid_len), ++ MAC_ARG(network.bssid), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ network.ext_entry = target->ext_entry; ++#endif ++ memcpy(target, &network, sizeof(*target)); ++ list_add_tail(&target->list, &ieee->network_list); ++ if(ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) ++ ieee80211_softmac_new_net(ieee,&network); ++ } else { ++ IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", ++ escape_essid(target->ssid, ++ target->ssid_len), ++ MAC_ARG(target->bssid), ++ WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == ++ IEEE80211_STYPE_PROBE_RESP ? ++ "PROBE RESPONSE" : "BEACON"); ++ ++ /* we have an entry and we are going to update it. But this entry may ++ * be already expired. In this case we do the same as we found a new ++ * net and call the new_net handler ++ */ ++ renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); ++ //YJ,add,080819,for hidden ap ++ if(is_beacon == 0) ++ network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); ++ //if(strncmp(network.ssid, "linksys-c",9) == 0) ++ // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); ++ if(((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ ++ && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ ++ ||((ieee->current_network.ssid_len == network.ssid_len)&&(strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0)&&(ieee->state == IEEE80211_NOLINK)))) ++ renew = 1; ++ //YJ,add,080819,for hidden ap,end ++ update_network(target, &network); ++ if(renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) ++ ieee80211_softmac_new_net(ieee,&network); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++void ieee80211_rx_mgt(struct ieee80211_device *ieee, ++ struct ieee80211_hdr *header, ++ struct ieee80211_rx_stats *stats) ++{ ++ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { ++ ++ case IEEE80211_STYPE_BEACON: ++ IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Beacon\n"); ++ ieee80211_process_probe_response( ++ ieee, (struct ieee80211_probe_response *)header, stats); ++ break; ++ ++ case IEEE80211_STYPE_PROBE_RESP: ++ IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Probe response\n"); ++ ieee80211_process_probe_response( ++ ieee, (struct ieee80211_probe_response *)header, stats); ++ break; ++//rz ++#ifdef _RTL8187_EXT_PATCH_ ++ case IEEE80211_STYPE_PROBE_REQ: ++ IEEE80211_DEBUG_MGMT("received PROBE REQUEST (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ IEEE80211_DEBUG_SCAN("Probe request\n"); ++ /// ++ if( ieee->iw_mode == ieee->iw_ext_mode && ieee->ext_patch_ieee80211_rx_mgt_on_probe_req ) ++ ieee->ext_patch_ieee80211_rx_mgt_on_probe_req( ieee, (struct ieee80211_probe_request *)header, stats); ++ break; ++#endif // _RTL8187_EXT_PATCH_ ++ ++ } ++} ++ ++#if 0 ++EXPORT_SYMBOL(ieee80211_rx_mgt); ++EXPORT_SYMBOL(ieee80211_rx); ++EXPORT_SYMBOL(ieee80211_network_init); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee_ext_skb_p80211_to_ether); ++#endif ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +@@ -0,0 +1,4029 @@ ++/* IEEE 802.11 SoftMAC layer ++ * Copyright (c) 2005 Andrea Merello ++ * ++ * Mostly extracted from the rtl8180-sa2400 driver for the ++ * in-kernel generic ieee802.11 stack. ++ * ++ * Few lines might be stolen from other part of the ieee80211 ++ * stack. Copyright who own it's copyright ++ * ++ * WPA code stolen from the ipw2200 driver. ++ * Copyright who own it's copyright. ++ * ++ * released under the GPL ++ */ ++ ++ ++#include "ieee80211.h" ++ ++#include ++#include ++#include ++#include ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++u8 rsn_authen_cipher_suite[16][4] = { ++ {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved ++ {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default ++ {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default} ++ {0x00,0x0F,0xAC,0x03}, //WRAP-historical ++ {0x00,0x0F,0xAC,0x04}, //CCMP ++ {0x00,0x0F,0xAC,0x05}, //WEP-104 ++}; ++ ++short ieee80211_is_54g(struct ieee80211_network net) ++{ ++ return ((net.rates_ex_len > 0) || (net.rates_len > 4)); ++} ++ ++short ieee80211_is_shortslot(struct ieee80211_network net) ++{ ++ return (net.capability & WLAN_CAPABILITY_SHORT_SLOT); ++} ++ ++/* returns the total length needed for pleacing the RATE MFIE ++ * tag and the EXTENDED RATE MFIE tag if needed. ++ * It encludes two bytes per tag for the tag itself and its len ++ */ ++unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) ++{ ++ unsigned int rate_len = 0; ++ ++ if (ieee->modulation & IEEE80211_CCK_MODULATION) ++ rate_len = IEEE80211_CCK_RATE_LEN + 2; ++ ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION) ++ ++ rate_len += IEEE80211_OFDM_RATE_LEN + 2; ++ ++ return rate_len; ++} ++ ++/* pleace the MFIE rate, tag to the memory (double) poined. ++ * Then it updates the pointer so that ++ * it points after the new MFIE tag added. ++ */ ++void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p) ++{ ++ u8 *tag = *tag_p; ++ ++ if (ieee->modulation & IEEE80211_CCK_MODULATION){ ++ *tag++ = MFIE_TYPE_RATES; ++ *tag++ = 4; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; ++ } ++ ++ /* We may add an option for custom rates that specific HW might support */ ++ *tag_p = tag; ++} ++ ++void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p) ++{ ++ u8 *tag = *tag_p; ++ ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ++ *tag++ = MFIE_TYPE_RATES_EX; ++ *tag++ = 8; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; ++ *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; ++ ++ } ++ ++ /* We may add an option for custom rates that specific HW might support */ ++ *tag_p = tag; ++} ++ ++ ++void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) { ++ u8 *tag = *tag_p; ++ ++ *tag++ = MFIE_TYPE_GENERIC; //0 ++ *tag++ = 7; ++ *tag++ = 0x00; ++ *tag++ = 0x50; ++ *tag++ = 0xf2; ++ *tag++ = 0x02;//5 ++ *tag++ = 0x00; ++ *tag++ = 0x01; ++#ifdef SUPPORT_USPD ++ if(ieee->current_network.wmm_info & 0x80) { ++ *tag++ = 0x0f|MAX_SP_Len; ++ } else { ++ *tag++ = MAX_SP_Len; ++ } ++#else ++ *tag++ = MAX_SP_Len; ++#endif ++ *tag_p = tag; ++} ++ ++#ifdef THOMAS_TURBO ++void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) { ++ u8 *tag = *tag_p; ++ ++ *tag++ = MFIE_TYPE_GENERIC; //0 ++ *tag++ = 7; ++ *tag++ = 0x00; ++ *tag++ = 0xe0; ++ *tag++ = 0x4c; ++ *tag++ = 0x01;//5 ++ *tag++ = 0x02; ++ *tag++ = 0x11; ++ *tag++ = 0x00; ++ ++ *tag_p = tag; ++ printk(KERN_ALERT "This is enable turbo mode IE process\n"); ++} ++#endif ++ ++void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ int nh; ++ nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM; ++ ++/* ++ * if the queue is full but we have newer frames then ++ * just overwrites the oldest. ++ * ++ * if (nh == ieee->mgmt_queue_tail) ++ * return -1; ++ */ ++ ieee->mgmt_queue_head = nh; ++ ieee->mgmt_queue_ring[nh] = skb; ++ ++ //return 0; ++} ++ ++struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *ret; ++ ++ if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head) ++ return NULL; ++ ++ ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; ++ ++ ieee->mgmt_queue_tail = ++ (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; ++ ++ return ret; ++} ++ ++void init_mgmt_queue(struct ieee80211_device *ieee) ++{ ++ ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; ++} ++ ++ ++void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); ++ ++inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; ++ struct ieee80211_hdr_3addr *header= ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ /* called with 2nd param 0, no mgmt lock required */ ++ ieee80211_sta_wakeup(ieee,0); ++ ++ if(single){ ++ if(ieee->queue_stop){ ++ ++ enqueue_mgmt(ieee,skb); ++ }else{ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ ieee->dev->trans_start = jiffies; ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ }else{ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ ieee->dev->trans_start = jiffies; ++ ieee->softmac_hard_start_xmit(skb,ieee->dev); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); ++ } ++} ++ ++ ++inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee) ++{ ++ ++ short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; ++ struct ieee80211_hdr_3addr *header = ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ ++ if(single){ ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ ieee->dev->trans_start = jiffies; ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ ++ }else{ ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ /* avoid watchdog triggers */ ++ ieee->dev->trans_start = jiffies; ++ ieee->softmac_hard_start_xmit(skb,ieee->dev); ++ ++ } ++// dev_kfree_skb_any(skb);//edit by thomas ++} ++//by amy for power save ++inline struct sk_buff *ieee80211_disassociate_skb( ++ struct ieee80211_network *beacon, ++ struct ieee80211_device *ieee, ++ u8 asRsn) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_disassoc_frame *disass; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc_frame)); ++ if (!skb) ++ return NULL; ++ ++ disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame)); ++ disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); ++ disass->header.duration_id = 0; ++ ++ memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); ++ ++ disass->reasoncode = asRsn; ++ return skb; ++} ++void ++SendDisassociation( ++ struct ieee80211_device *ieee, ++ u8* asSta, ++ u8 asRsn ++) ++{ ++ struct ieee80211_network *beacon = &ieee->current_network; ++ struct sk_buff *skb; ++ skb = ieee80211_disassociate_skb(beacon,ieee,asRsn); ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++//by amy for power save ++inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) ++{ ++ unsigned int len,rate_len; ++ u8 *tag; ++ struct sk_buff *skb; ++ struct ieee80211_probe_request *req; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ short extMore = 0; ++ if(ieee->ext_patch_ieee80211_probe_req_1) ++ extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee); ++#endif ++ ++ len = ieee->current_network.ssid_len; ++ ++ rate_len = ieee80211_MFIE_rate_len(ieee); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(!extMore) ++#endif ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len); ++#ifdef _RTL8187_EXT_PATCH_ ++ else ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len+128); // MESHID + CAP ++#endif ++ ++ if (!skb) ++ return NULL; ++ ++ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); ++ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); ++ req->header.duration_id = 0; //FIXME: is this OK ? ++ ++ memset(req->header.addr1, 0xff, ETH_ALEN); ++ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memset(req->header.addr3, 0xff, ETH_ALEN); ++ ++ tag = (u8 *) skb_put(skb,len+2+rate_len); ++ ++ *tag++ = MFIE_TYPE_SSID; ++ *tag++ = len; ++ memcpy(tag, ieee->current_network.ssid, len); ++ tag += len; ++ ieee80211_MFIE_Brate(ieee,&tag); ++ ieee80211_MFIE_Grate(ieee,&tag); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(extMore) ++ ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag); ++#endif ++ return skb; ++} ++ ++struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); ++ ++//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++//void ext_ieee80211_send_beacon_wq(struct work_struct *work) ++//{ ++// struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_send_beacon_wq); ++//#else ++void ext_ieee80211_send_beacon_wq(struct ieee80211_device *ieee) ++{ ++//#endif ++ ++ struct sk_buff *skb; ++ ++ //unsigned long flags; ++ ++ skb = ieee80211_get_beacon_(ieee); ++ ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_beacons++; ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ ++ ++ //printk(KERN_WARNING "[1] beacon sending!\n"); ++ ieee->beacon_timer.expires = jiffies + ++ (MSECS( ieee->current_network.beacon_interval -5)); ++ ++ //spin_lock_irqsave(&ieee->beacon_lock,flags); ++ if(ieee->beacon_txing) ++ add_timer(&ieee->beacon_timer); ++ //spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++void ieee80211_send_beacon(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ ++ //unsigned long flags; ++ ++ skb = ieee80211_get_beacon_(ieee); ++ ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_beacons++; ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ ++ //printk(KERN_WARNING "[1] beacon sending!\n"); ++ ieee->beacon_timer.expires = jiffies + ++ (MSECS( ieee->current_network.beacon_interval -5)); ++ ++ //spin_lock_irqsave(&ieee->beacon_lock,flags); ++ if(ieee->beacon_txing) ++ add_timer(&ieee->beacon_timer); ++ //spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++ ++void ieee80211_send_beacon_cb(unsigned long _ieee) ++{ ++ struct ieee80211_device *ieee = ++ (struct ieee80211_device *) _ieee; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock, flags); ++ ieee80211_send_beacon(ieee); ++ spin_unlock_irqrestore(&ieee->beacon_lock, flags); ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ ++inline struct sk_buff *ieee80211_probe_req_with_SSID(struct ieee80211_device *ieee, char *ssid, int len_ssid) ++{ ++ unsigned int len,rate_len; ++ u8 *tag; ++ struct sk_buff *skb; ++ struct ieee80211_probe_request *req; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ short extMore = 0; ++ if(ieee->ext_patch_ieee80211_probe_req_1) ++ extMore = ieee->ext_patch_ieee80211_probe_req_1(ieee); ++#endif ++ ++ len = len_ssid; ++ ++ rate_len = ieee80211_MFIE_rate_len(ieee); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(!extMore) ++#endif ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len); ++#ifdef _RTL8187_EXT_PATCH_ ++ else ++ skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + ++ 2 + len + rate_len+128); // MESHID + CAP ++#endif ++ ++ if (!skb) ++ return NULL; ++ ++ req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request)); ++ req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); ++ req->header.duration_id = 0; //FIXME: is this OK ? ++ ++ memset(req->header.addr1, 0xff, ETH_ALEN); ++ memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memset(req->header.addr3, 0xff, ETH_ALEN); ++ ++ tag = (u8 *) skb_put(skb,len+2+rate_len); ++ ++ *tag++ = MFIE_TYPE_SSID; ++ *tag++ = len; ++ if(len) ++ { ++ memcpy(tag, ssid, len); ++ tag += len; ++ } ++ ++ ieee80211_MFIE_Brate(ieee,&tag); ++ ieee80211_MFIE_Grate(ieee,&tag); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(extMore) ++ ieee->ext_patch_ieee80211_probe_req_2(ieee, skb, tag); ++#endif ++ return skb; ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ++void ieee80211_send_probe(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ skb = ieee80211_probe_req_with_SSID(ieee, NULL, 0); ++ else ++#endif ++ skb = ieee80211_probe_req(ieee); ++ if (skb){ ++ softmac_mgmt_xmit(skb, ieee); ++ ieee->softmac_stats.tx_probe_rq++; ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++void ieee80211_send_probe_requests(struct ieee80211_device *ieee) ++{ ++ if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){ ++ ieee80211_send_probe(ieee); ++ ieee80211_send_probe(ieee); ++ } ++} ++ ++/* this performs syncro scan blocking the caller until all channels ++ * in the allowed channel map has been checked. ++ */ ++void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) ++{ ++ short ch = 0; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++ down(&ieee->scan_sem); ++// printk("==================> Sync scan\n"); ++// dump_chnl_map(channel_map); ++ ++ while(1) ++ { ++ ++ do{ ++ ch++; ++ if (ch > MAX_CHANNEL_NUMBER) ++ goto out; /* scan completed */ ++ ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ch]); ++#else ++ }while(!ieee->channel_map[ch]); ++#endif ++ /* this fuction can be called in two situations ++ * 1- We have switched to ad-hoc mode and we are ++ * performing a complete syncro scan before conclude ++ * there are no interesting cell and to create a ++ * new one. In this case the link state is ++ * IEEE80211_NOLINK until we found an interesting cell. ++ * If so the ieee8021_new_net, called by the RX path ++ * will set the state to IEEE80211_LINKED, so we stop ++ * scanning ++ * 2- We are linked and the root uses run iwlist scan. ++ * So we switch to IEEE80211_LINKED_SCANNING to remember ++ * that we are still logically linked (not interested in ++ * new network events, despite for updating the net list, ++ * but we are temporarly 'unlinked' as the driver shall ++ * not filter RX frames and the channel is changing. ++ * So the only situation in witch are interested is to check ++ * if the state become LINKED because of the #1 situation ++ */ ++ ++ if (ieee->state == IEEE80211_LINKED) ++ goto out; ++ ++ ieee->set_chan(ieee->dev, ch); ++// printk("=====>channel=%d ",ch); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ch] == 1) ++#endif ++ { ++// printk("====send probe request\n"); ++ ieee80211_send_probe_requests(ieee); ++ } ++ /* this prevent excessive time wait when we ++ * need to wait for a syncro scan to end.. ++ */ ++ if (ieee->sync_scan_hurryup) ++ goto out; ++ ++ ++ msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); ++ ++ } ++out: ++ ieee->sync_scan_hurryup = 0; ++ up(&ieee->scan_sem); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++} ++ ++void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee) ++{ ++ int ch; ++ unsigned int watch_dog = 0; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++ down(&ieee->scan_sem); ++ ch = ieee->current_network.channel; ++// if(ieee->sync_scan_hurryup) ++// { ++ ++// printk("stop scan sync\n"); ++// goto out; ++// } ++// printk("=======hh===============>ips scan\n"); ++ while(1) ++ { ++ /* this fuction can be called in two situations ++ * 1- We have switched to ad-hoc mode and we are ++ * performing a complete syncro scan before conclude ++ * there are no interesting cell and to create a ++ * new one. In this case the link state is ++ * IEEE80211_NOLINK until we found an interesting cell. ++ * If so the ieee8021_new_net, called by the RX path ++ * will set the state to IEEE80211_LINKED, so we stop ++ * scanning ++ * 2- We are linked and the root uses run iwlist scan. ++ * So we switch to IEEE80211_LINKED_SCANNING to remember ++ * that we are still logically linked (not interested in ++ * new network events, despite for updating the net list, ++ * but we are temporarly 'unlinked' as the driver shall ++ * not filter RX frames and the channel is changing. ++ * So the only situation in witch are interested is to check ++ * if the state become LINKED because of the #1 situation ++ */ ++ if (ieee->state == IEEE80211_LINKED) ++ { ++ goto out; ++ } ++#ifdef ENABLE_DOT11D ++ if(channel_map[ieee->current_network.channel] > 0) ++#endif ++ { ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++// printk("======>channel=%d ",ieee->current_network.channel); ++ } ++#ifdef ENABLE_DOT11D ++ if(channel_map[ieee->current_network.channel] == 1) ++#endif ++ { ++// printk("====send probe request\n"); ++ ieee80211_send_probe_requests(ieee); ++ } ++ /* this prevent excessive time wait when we ++ * need to wait for a syncro scan to end.. ++ */ ++// if (ieee->sync_scan_hurryup) ++// goto out; ++ ++ msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); ++ ++ do{ ++ if (watch_dog++ >= MAX_CHANNEL_NUMBER) ++ // if (++watch_dog >= 15);//MAX_CHANNEL_NUMBER) //YJ,modified,080630 ++ goto out; /* scan completed */ ++ ++ ieee->current_network.channel = (ieee->current_network.channel + 1)%MAX_CHANNEL_NUMBER; ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ieee->current_network.channel]); ++#else ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ } ++out: ++ //ieee->sync_scan_hurryup = 0; ++ //ieee->set_chan(ieee->dev, ch); ++ //ieee->current_network.channel = ch; ++ ieee->actscanning = false; ++ up(&ieee->scan_sem); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++} ++ ++ ++#if 0 ++/* called both by wq with ieee->lock held */ ++void ieee80211_softmac_scan(struct ieee80211_device *ieee) ++{ ++ short watchdog = 0; ++ ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (watchdog++ > MAX_CHANNEL_NUMBER) ++ return; /* no good chans */ ++ ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++ ++ ++ schedule_work(&ieee->softmac_scan_wq); ++} ++#endif ++#ifdef ENABLE_IPS ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_softmac_scan_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); ++#else ++void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ static short watchdog = 0; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++// printk("ieee80211_softmac_scan_wq ENABLE_IPS\n"); ++// printk("in %s\n",__FUNCTION__); ++ down(&ieee->scan_sem); ++ ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (watchdog++ > MAX_CHANNEL_NUMBER) ++ goto out; /* no good chans */ ++ ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ieee->current_network.channel]); ++#else ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ ++ //printk("current_network.channel:%d\n", ieee->current_network.channel); ++ if (ieee->scanning == 0 ) ++ { ++ printk("error out, scanning = 0\n"); ++ goto out; ++ } ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ieee->current_network.channel] == 1) ++#endif ++ ieee80211_send_probe_requests(ieee); ++ ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); ++ up(&ieee->scan_sem); ++ return; ++out: ++ ieee->actscanning = false; ++ watchdog = 0; ++ ieee->scanning = 0; ++ up(&ieee->scan_sem); ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++ return; ++} ++#else ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_softmac_scan_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, softmac_scan_wq); ++#else ++void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ++ short watchdog = 0; ++#ifdef ENABLE_DOT11D ++ u8 channel_map[MAX_CHANNEL_NUMBER+1]; ++ memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); ++#endif ++// printk("enter scan wq,watchdog is %d\n",watchdog); ++ down(&ieee->scan_sem); ++ ++ do{ ++ ieee->current_network.channel = ++ (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; ++ if (watchdog++ > MAX_CHANNEL_NUMBER) ++ goto out; /* no good chans */ ++ ++#ifdef ENABLE_DOT11D ++ }while(!channel_map[ieee->current_network.channel]); ++#else ++ }while(!ieee->channel_map[ieee->current_network.channel]); ++#endif ++ ++// printk("current_network.channel:%d\n", ieee->current_network.channel); ++ if (ieee->scanning == 0 ) ++ { ++ printk("error out, scanning = 0\n"); ++ goto out; ++ } ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++#ifdef ENABLE_DOT11D ++ if(channel_map[ieee->current_network.channel] == 1) ++#endif ++ ieee80211_send_probe_requests(ieee); ++ ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); ++out: ++ up(&ieee->scan_sem); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ DOT11D_ScanComplete(ieee); ++#endif ++} ++ ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ++void ieee80211_softmac_scan_cb(unsigned long _dev) ++{ ++ unsigned long flags; ++ struct ieee80211_device *ieee = (struct ieee80211_device *)_dev; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ieee80211_softmac_scan(ieee); ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++#endif ++ ++ ++void ieee80211_beacons_start(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock,flags); ++ ++ ieee->beacon_txing = 1; ++ ieee80211_send_beacon(ieee); ++ ++ spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++} ++ ++void ieee80211_beacons_stop(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->beacon_lock,flags); ++ ++ ieee->beacon_txing = 0; ++ del_timer_sync(&ieee->beacon_timer); ++ ++ spin_unlock_irqrestore(&ieee->beacon_lock,flags); ++ ++} ++ ++ ++void ieee80211_stop_send_beacons(struct ieee80211_device *ieee) ++{ ++ if(ieee->stop_send_beacons) ++ ieee->stop_send_beacons(ieee->dev); ++ if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) ++ ieee80211_beacons_stop(ieee); ++} ++ ++ ++void ieee80211_start_send_beacons(struct ieee80211_device *ieee) ++{ ++ if(ieee->start_send_beacons) ++ ieee->start_send_beacons(ieee->dev); ++ if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS) ++ ieee80211_beacons_start(ieee); ++} ++ ++ ++void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) ++{ ++// unsigned long flags; ++ ++ //ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->scan_sem); ++// spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->scanning == 1){ ++ ieee->scanning = 0; ++ //del_timer_sync(&ieee->scan_timer); ++ cancel_delayed_work(&ieee->softmac_scan_wq); ++ } ++ ++// spin_unlock_irqrestore(&ieee->lock, flags); ++ up(&ieee->scan_sem); ++} ++ ++void ieee80211_stop_scan(struct ieee80211_device *ieee) ++{ ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ++ ieee80211_softmac_stop_scan(ieee); ++ else ++ ieee->stop_scan(ieee->dev); ++} ++ ++/* called with ieee->lock held */ ++void ieee80211_start_scan(struct ieee80211_device *ieee) ++{ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee) ) ++ { ++ if(IS_COUNTRY_IE_VALID(ieee)) ++ { ++ RESET_CIE_WATCHDOG(ieee); ++ } ++ } ++#endif ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ ++ if (ieee->scanning == 0) ++ { ++ ieee->scanning = 1; ++ //ieee80211_softmac_scan(ieee); ++ // queue_work(ieee->wq, &ieee->softmac_scan_wq); ++ //care this,1203,2007,by lawrence ++#if 1 ++ queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq,0); ++#endif ++ } ++ }else ++ ieee->start_scan(ieee->dev); ++ ++} ++ ++/* called with wx_sem held */ ++void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) ++{ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee) ) ++ { ++ if(IS_COUNTRY_IE_VALID(ieee)) ++ { ++ RESET_CIE_WATCHDOG(ieee); ++ } ++ } ++#endif ++ ieee->sync_scan_hurryup = 0; ++ ++ if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) ++ ieee80211_softmac_scan_syncro(ieee); ++ else ++ ieee->scan_syncro(ieee->dev); ++ ++} ++ ++inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon, ++ struct ieee80211_device *ieee, int challengelen) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_authentication *auth; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_authentication) + challengelen); ++ ++ if (!skb) return NULL; ++ ++ auth = (struct ieee80211_authentication *) ++ skb_put(skb, sizeof(struct ieee80211_authentication)); ++ ++ auth->header.frame_ctl = IEEE80211_STYPE_AUTH; ++ if (challengelen) auth->header.frame_ctl |= IEEE80211_FCTL_WEP; ++ ++ auth->header.duration_id = 0x013a; //FIXME ++ ++ memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); ++ ++ auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ ++ auth->transaction = cpu_to_le16(ieee->associate_seq); ++ ieee->associate_seq++; ++ ++ auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); ++ ++ return skb; ++ ++} ++ ++static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest) ++{ ++ u8 *tag; ++ int beacon_size; ++ struct ieee80211_probe_response *beacon_buf; ++ struct sk_buff *skb; ++ int encrypt; ++ int atim_len,erp_len; ++ struct ieee80211_crypt_data* crypt; ++ ++ char *ssid = ieee->current_network.ssid; ++ int ssid_len = ieee->current_network.ssid_len; ++ int rate_len = ieee->current_network.rates_len+2; ++ int rate_ex_len = ieee->current_network.rates_ex_len; ++ int wpa_ie_len = ieee->wpa_ie_len; ++ if(rate_ex_len > 0) rate_ex_len+=2; ++ ++ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) ++ atim_len = 4; ++ else ++ atim_len = 0; ++ ++ if(ieee80211_is_54g(ieee->current_network)) ++ erp_len = 3; ++ else ++ erp_len = 0; ++ ++ beacon_size = sizeof(struct ieee80211_probe_response)+ ++ ssid_len ++ +3 //channel ++ +rate_len ++ +rate_ex_len ++ +atim_len ++ +wpa_ie_len ++ +erp_len; ++ ++ skb = dev_alloc_skb(beacon_size); ++ ++ if (!skb) ++ return NULL; ++ ++ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size); ++ ++ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); ++ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ beacon_buf->header.duration_id = 0; //FIXME ++ beacon_buf->beacon_interval = ++ cpu_to_le16(ieee->current_network.beacon_interval); ++ beacon_buf->capability = ++ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); ++ ++ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ++ ((0 == strcmp(crypt->ops->name, "WEP")) || wpa_ie_len); ++ ++ if (encrypt) ++ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ ++ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); ++ ++ beacon_buf->info_element.id = MFIE_TYPE_SSID; ++ beacon_buf->info_element.len = ssid_len; ++ ++ tag = (u8*) beacon_buf->info_element.data; ++ ++ memcpy(tag, ssid, ssid_len); ++ ++ tag += ssid_len; ++ ++ *(tag++) = MFIE_TYPE_RATES; ++ *(tag++) = rate_len-2; ++ memcpy(tag,ieee->current_network.rates,rate_len-2); ++ tag+=rate_len-2; ++ ++ *(tag++) = MFIE_TYPE_DS_SET; ++ *(tag++) = 1; ++ *(tag++) = ieee->current_network.channel; ++ ++ if(atim_len){ ++ *(tag++) = MFIE_TYPE_IBSS_SET; ++ *(tag++) = 2; ++ *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); ++ tag+=2; ++ } ++ ++ if(erp_len){ ++ *(tag++) = MFIE_TYPE_ERP; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ } ++ ++ if(rate_ex_len){ ++ *(tag++) = MFIE_TYPE_RATES_EX; ++ *(tag++) = rate_ex_len-2; ++ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); ++ tag+=rate_ex_len-2; ++ } ++ ++ if (wpa_ie_len) ++ { ++ if (ieee->iw_mode == IW_MODE_ADHOC) ++ {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07 ++ memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); ++ } ++ ++ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); ++ } ++ ++ skb->dev = ieee->dev; ++ return skb; ++} ++#ifdef _RTL8187_EXT_PATCH_ ++struct sk_buff* ieee80211_ext_probe_resp_by_net(struct ieee80211_device *ieee, u8 *dest, struct ieee80211_network *net) ++{ ++ u8 *tag; ++ int beacon_size; ++ struct ieee80211_probe_response *beacon_buf; ++ struct sk_buff *skb; ++ int encrypt; ++ int atim_len,erp_len; ++ struct ieee80211_crypt_data* crypt; ++ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ int wpa_ie_len = ieee->wpa_ie_len; ++ char *ssid = net->ssid; ++ int ssid_len = net->ssid_len; ++ ++ int rate_len = ieee->current_network.rates_len+2; ++ int rate_ex_len = ieee->current_network.rates_ex_len; ++ if(rate_ex_len > 0) rate_ex_len+=2; ++ ++ if( ieee->meshScanMode&4) ++ ieee->current_network.channel = ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee); ++ if( ieee->meshScanMode&6) ++ { ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->ext_stop_scan_wq); ++#else ++ schedule_task(&ieee->ext_stop_scan_wq); ++#endif ++ } ++ if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS) // use current_network here ++ atim_len = 4; ++ else ++ atim_len = 0; ++ ++ if(ieee80211_is_54g(*net)) ++ erp_len = 3; ++ else ++ erp_len = 0; ++ ++ beacon_size = sizeof(struct ieee80211_probe_response)+ ++ ssid_len ++ +3 //channel ++ +rate_len ++ +rate_ex_len ++ +atim_len ++ +erp_len; ++//b ++ skb = dev_alloc_skb(beacon_size+196); ++ ++ if (!skb) ++ return NULL; ++ ++ beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, beacon_size); ++ ++ memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); ++ memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ beacon_buf->header.duration_id = 0; //FIXME ++ ++ beacon_buf->beacon_interval = ++ cpu_to_le16(ieee->current_network.beacon_interval); // use current_network here ++ beacon_buf->capability = ++ cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); ++ ++ if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) ++ cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT)); ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ ++ encrypt = ieee->host_encrypt && crypt && crypt->ops && ++ ((0 == strcmp(crypt->ops->name, "WEP"))||wpa_ie_len); ++ ++ if (encrypt) ++ beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ ++ beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); ++ ++ beacon_buf->info_element.id = MFIE_TYPE_SSID; ++ beacon_buf->info_element.len = ssid_len; ++ ++ tag = (u8*) beacon_buf->info_element.data; ++ ++ // brocad cast / probe rsp ++ if(memcmp(dest, broadcast_addr, ETH_ALEN )) ++ memcpy(tag, ssid, ssid_len); ++ else ++ ssid_len=0; ++ ++ tag += ssid_len; ++ ++//get_bssrate_set(priv, _SUPPORTEDRATES_IE_, &pbssrate, &bssrate_len); ++//pbuf = set_ie(pbuf, _SUPPORTEDRATES_IE_, bssrate_len, pbssrate, &frlen); ++ ++ *(tag++) = MFIE_TYPE_RATES; ++ *(tag++) = rate_len-2; ++ memcpy(tag,ieee->current_network.rates,rate_len-2); ++ tag+=rate_len-2; ++ ++ *(tag++) = MFIE_TYPE_DS_SET; ++ *(tag++) = 1; ++ *(tag++) = ieee->current_network.channel; // use current_network here ++ ++ ++ if(atim_len){ ++ *(tag++) = MFIE_TYPE_IBSS_SET; ++ *(tag++) = 2; ++ *((u16*)(tag)) = cpu_to_le16(ieee->current_network.atim_window); // use current_network here ++ tag+=2; ++ } ++ ++ if(erp_len){ ++ *(tag++) = MFIE_TYPE_ERP; ++ *(tag++) = 1; ++ *(tag++) = 0; ++ } ++ ++ if(rate_ex_len){ ++ *(tag++) = MFIE_TYPE_RATES_EX; ++ *(tag++) = rate_ex_len-2; ++ memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); ++ tag+=rate_ex_len-2; ++ } ++ if (wpa_ie_len) ++ memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); ++ ++ skb->dev = ieee->dev; ++ return skb; ++} ++#endif // _RTL8187_EXT_PATCH_ ++ ++struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) ++{ ++ struct sk_buff *skb; ++ u8* tag; ++ ++ struct ieee80211_crypt_data* crypt; ++ struct ieee80211_assoc_response_frame *assoc; ++ short encrypt; ++ ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; ++ ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ assoc = (struct ieee80211_assoc_response_frame *) ++ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); ++ ++ assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); ++ memcpy(assoc->header.addr1, dest,ETH_ALEN); ++ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? ++ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); ++ ++ ++ if(ieee->short_slot) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++ if (ieee->host_encrypt) ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ else crypt = NULL; ++ ++ encrypt = ( crypt && crypt->ops); ++ ++ if (encrypt) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ assoc->status = 0; ++ assoc->aid = cpu_to_le16(ieee->assoc_id); ++ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; ++ else ieee->assoc_id++; ++ ++ tag = (u8*) skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ return skb; ++} ++ ++struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_authentication *auth; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_authentication)+1); ++ ++ if (!skb) ++ return NULL; ++ ++ skb->len = sizeof(struct ieee80211_authentication); ++ ++ auth = (struct ieee80211_authentication *)skb->data; ++ ++ auth->status = cpu_to_le16(status); ++ auth->transaction = cpu_to_le16(2); ++ auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ memcpy(auth->header.addr3, dest, ETH_ALEN); ++#else ++ memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++#endif ++ memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(auth->header.addr1, dest, ETH_ALEN); ++ auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); ++ return skb; ++ ++ ++} ++ ++struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr* hdr; ++ ++ skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr)); ++ ++ if (!skb) ++ return NULL; ++ ++ hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr)); ++ ++ memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); ++ memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); ++ ++ hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | ++ IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | ++ (pwr ? IEEE80211_FCTL_PM:0)); ++ ++ return skb; ++ ++ ++} ++ ++ ++void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest) ++{ ++ struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest); ++ ++ if (buf){ ++ softmac_mgmt_xmit(buf, ieee); ++ dev_kfree_skb_any(buf);//edit by thomas ++ } ++} ++ ++ ++void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest) ++{ ++ struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest); ++ ++ if (buf){ ++ softmac_mgmt_xmit(buf, ieee); ++ dev_kfree_skb_any(buf);//edit by thomas ++ } ++} ++ ++ ++void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest) ++{ ++ ++ struct sk_buff *buf = ieee80211_probe_resp(ieee, dest); ++ ++ if (buf) { ++ softmac_mgmt_xmit(buf, ieee); ++ dev_kfree_skb_any(buf);//edit by thomas ++ } ++} ++ ++ ++inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ //unsigned long flags; ++ ++ struct ieee80211_assoc_request_frame *hdr; ++ u8 *tag; ++ //short info_addr = 0; ++ //int i; ++ //u16 suite_count = 0; ++ //u8 suit_select = 0; ++ unsigned int wpa_len = beacon->wpa_ie_len; ++ //struct net_device *dev = ieee->dev; ++ //union iwreq_data wrqu; ++ //u8 *buff; ++ //u8 *p; ++#if 1 ++ // for testing purpose ++ unsigned int rsn_len = beacon->rsn_ie_len; ++#else ++ unsigned int rsn_len = beacon->rsn_ie_len - 4; ++#endif ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ unsigned int wmm_info_len = beacon->QoS_Enable?9:0; ++#ifdef THOMAS_TURBO ++ unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; ++#endif ++ ++ u8 encry_proto = ieee->wpax_type_notify & 0xff; ++ //u8 pairwise_type = (ieee->wpax_type_notify >> 8) & 0xff; ++ //u8 authen_type = (ieee->wpax_type_notify >> 16) & 0xff; ++ ++ int len = 0; ++ ++ //[0] Notify type of encryption: WPA/WPA2 ++ //[1] pair wise type ++ //[2] authen type ++ if(ieee->wpax_type_set) { ++ if (IEEE_PROTO_WPA == encry_proto) { ++ rsn_len = 0; ++ } else if (IEEE_PROTO_RSN == encry_proto) { ++ wpa_len = 0; ++ } ++ } ++#ifdef THOMAS_TURBO ++ len = sizeof(struct ieee80211_assoc_request_frame)+ ++ + beacon->ssid_len//essid tagged val ++ + rate_len//rates tagged val ++ + wpa_len ++ + rsn_len ++ + wmm_info_len ++ + turbo_info_len; ++#else ++ len = sizeof(struct ieee80211_assoc_request_frame)+ ++ + beacon->ssid_len//essid tagged val ++ + rate_len//rates tagged val ++ + wpa_len ++ + rsn_len ++ + wmm_info_len; ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ skb = dev_alloc_skb(len+256); // stanley ++ else ++#endif ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ hdr = (struct ieee80211_assoc_request_frame *) ++ skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); ++ ++ ++ hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; ++ hdr->header.duration_id= 37; //FIXME ++ memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); ++ memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); ++ memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John ++ ++ hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS); ++ if (beacon->capability & WLAN_CAPABILITY_PRIVACY ) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); ++ ++ if(ieee->short_slot) ++ hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_1) ++ ieee->ext_patch_ieee80211_association_req_1(hdr); ++#endif ++ ++ hdr->listen_interval = 0xa; //FIXME ++ ++ hdr->info_element.id = MFIE_TYPE_SSID; ++ ++ hdr->info_element.len = beacon->ssid_len; ++ tag = skb_put(skb, beacon->ssid_len); ++ memcpy(tag, beacon->ssid, beacon->ssid_len); ++ ++ tag = skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ //add rsn==0 condition for ap's mix security mode(wpa+wpa2), john2007.8.9 ++ //choose AES encryption as default algorithm while using mixed mode ++#if 0 ++ if(rsn_len == 0){ ++ ++ tag = skb_put(skb,wpa_len); ++ ++ if(wpa_len) { ++ ++ ++ //{add by david. 2006.8.31 ++ //fix linksys compatibility bug ++ //} ++ if(wpa_len > 24) {//22+2, mean include the capability ++ beacon->wpa_ie[wpa_len - 2] = 0; ++ } ++ //multicast cipher OUI ++ if( beacon->wpa_ie[11]==0x2 ){ //0x0050f202 is the oui of tkip ++ ieee->broadcast_key_type = KEY_TYPE_TKIP; ++ } ++ else if( beacon->wpa_ie[11]==0x4 ){//0x0050f204 is the oui of ccmp ++ ieee->broadcast_key_type = KEY_TYPE_CCMP; ++ } ++ //unicast cipher OUI ++ if( beacon->wpa_ie[14]==0 ++ && beacon->wpa_ie[15]==0x50 ++ && beacon->wpa_ie[16]==0xf2 ++ && beacon->wpa_ie[17]==0x2 ){ //0x0050f202 is the oui of tkip ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ } ++ ++ else if( beacon->wpa_ie[14]==0 ++ && beacon->wpa_ie[15]==0x50 ++ && beacon->wpa_ie[16]==0xf2 ++ && beacon->wpa_ie[17]==0x4 ){//0x0050f204 is the oui of ccmp ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ } ++ //indicate the wpa_ie content to WPA_SUPPLICANT ++ buff = kmalloc(IW_CUSTOM_MAX, GFP_ATOMIC); ++ memset(buff, 0, IW_CUSTOM_MAX); ++ p=buff; ++ p += sprintf(p, "ASSOCINFO(ReqIEs="); ++ for(i=0;iwpa_ie[i]); ++ } ++ p += sprintf(p, ")"); ++ memset(&wrqu, 0, sizeof(wrqu) ); ++ wrqu.data.length = p - buff; ++ ++ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buff); ++ memcpy(tag,beacon->wpa_ie,wpa_len); ++ } ++ ++ } ++ ++ if(rsn_len > 22) { ++ ++ if( beacon->rsn_ie[4]==0x0 && ++ beacon->rsn_ie[5]==0xf && ++ beacon->rsn_ie[6]==0xac){ ++ ++ switch(beacon->rsn_ie[7]){ ++ case 0x1: ++ ieee->broadcast_key_type = KEY_TYPE_WEP40; ++ break; ++ case 0x2: ++ ieee->broadcast_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->broadcast_key_type = KEY_TYPE_CCMP; ++ break; ++ case 0x5: ++ ieee->broadcast_key_type = KEY_TYPE_WEP104; ++ break; ++ default: ++ printk("fault suite type in RSN broadcast key\n"); ++ break; ++ } ++ } ++ ++ if( beacon->rsn_ie[10]==0x0 && ++ beacon->rsn_ie[11]==0xf && ++ beacon->rsn_ie[12]==0xac){ ++ if(beacon->rsn_ie[8]==1){//not mixed mode ++ switch(beacon->rsn_ie[13]){ ++ case 0x2: ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ break; ++ default: ++ printk("fault suite type in RSN pairwise key\n"); ++ break; ++ } ++ } ++ else if(beacon->rsn_ie[8]==2){//mixed mode ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ } ++ } ++ ++ ++ ++ tag = skb_put(skb,22); ++ memcpy(tag,(beacon->rsn_ie + info_addr),8); ++ tag[1] = 20; ++ tag += 8; ++ info_addr += 8; ++ ++ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); ++ for (i = 0; i < 2; i++) { ++ tag[0] = 1; ++ tag[1] = 0; ++ tag += 2; ++ suite_count = beacon->rsn_ie[info_addr] + \ ++ (beacon->rsn_ie[info_addr + 1] << 8); ++ info_addr += 2; ++ if(1 == suite_count) { ++ memcpy(tag,(beacon->rsn_ie + info_addr),4); ++ info_addr += 4; ++ } else { ++ // if the wpax_type_notify has been set by the application, ++ // just use it, otherwise just use the default one. ++ if(ieee->wpax_type_set) { ++ suit_select = ((0 == i) ? pairwise_type:authen_type)&0x0f ; ++ memcpy(tag,rsn_authen_cipher_suite[suit_select],4); ++ } else { ++ //default set as ccmp, or none authentication ++ if(i == 0) { ++ memcpy(tag,rsn_authen_cipher_suite[4],4); ++ } else { ++ memcpy(tag,rsn_authen_cipher_suite[2],4); ++ } ++ ++ } ++ ++ info_addr += (suite_count * 4); ++ } ++ tag += 4; ++ } ++ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); ++ ++ tag[0] = 0; ++ tag[1] = beacon->rsn_ie[info_addr+1]; ++ ++ } else { ++ tag = skb_put(skb,rsn_len); ++ if(rsn_len) { ++ ++ ++ if( beacon->rsn_ie[4]==0x0 && ++ beacon->rsn_ie[5]==0xf && ++ beacon->rsn_ie[6]==0xac){ ++ switch(beacon->rsn_ie[7]){ ++ case 0x1: ++ ieee->broadcast_key_type = KEY_TYPE_WEP40; ++ break; ++ case 0x2: ++ ieee->broadcast_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->broadcast_key_type = KEY_TYPE_CCMP; ++ break; ++ case 0x5: ++ ieee->broadcast_key_type = KEY_TYPE_WEP104; ++ break; ++ default: ++ printk("fault suite type in RSN broadcast key\n"); ++ break; ++ } ++ } ++ if( beacon->rsn_ie[10]==0x0 && ++ beacon->rsn_ie[11]==0xf && ++ beacon->rsn_ie[12]==0xac){ ++ if(beacon->rsn_ie[8]==1){//not mixed mode ++ switch(beacon->rsn_ie[13]){ ++ case 0x2: ++ ieee->pairwise_key_type = KEY_TYPE_TKIP; ++ break; ++ case 0x4: ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ break; ++ default: ++ printk("fault suite type in RSN pairwise key\n"); ++ break; ++ } ++ ++ } ++ else if(beacon->rsn_ie[8]==2){//mixed mode ++ ieee->pairwise_key_type = KEY_TYPE_CCMP; ++ } ++ } ++ ++ ++ beacon->rsn_ie[rsn_len - 2] = 0; ++ memcpy(tag,beacon->rsn_ie,rsn_len); ++ } ++ } ++#else ++ tag = skb_put(skb,ieee->wpa_ie_len); ++ memcpy(tag,ieee->wpa_ie,ieee->wpa_ie_len); ++#endif ++ tag = skb_put(skb,wmm_info_len); ++ if(wmm_info_len) { ++ ieee80211_WMM_Info(ieee, &tag); ++ } ++#ifdef THOMAS_TURBO ++ tag = skb_put(skb,turbo_info_len); ++ if(turbo_info_len) { ++ ieee80211_TURBO_Info(ieee, &tag); ++ } ++#endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_association_req_2) ++ ieee->ext_patch_ieee80211_association_req_2(ieee, beacon, skb); ++#endif ++ ++ return skb; ++} ++ ++void ieee80211_associate_abort(struct ieee80211_device *ieee) ++{ ++ ++ unsigned long flags; ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ ieee->associate_seq++; ++ ++ /* don't scan, and avoid to have the RX path possibily ++ * try again to associate. Even do not react to AUTH or ++ * ASSOC response. Just wait for the retry wq to be scheduled. ++ * Here we will check if there are good nets to associate ++ * with, so we retry or just get back to NO_LINK and scanning ++ */ ++ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){ ++ IEEE80211_DEBUG_MGMT("Authentication failed\n"); ++ ieee->softmac_stats.no_auth_rs++; ++ }else{ ++ IEEE80211_DEBUG_MGMT("Association failed\n"); ++ ieee->softmac_stats.no_ass_rs++; ++ } ++ ++ ieee->state = IEEE80211_ASSOCIATING_RETRY; ++ ++ queue_delayed_work(ieee->wq, &ieee->associate_retry_wq,IEEE80211_SOFTMAC_ASSOC_RETRY_TIME); ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++void ieee80211_associate_abort_cb(unsigned long dev) ++{ ++ ieee80211_associate_abort((struct ieee80211_device *) dev); ++} ++ ++ ++void ieee80211_associate_step1(struct ieee80211_device *ieee) ++{ ++ struct ieee80211_network *beacon = &ieee->current_network; ++ struct sk_buff *skb; ++ ++ IEEE80211_DEBUG_MGMT("Stopping scan\n"); ++ ieee->softmac_stats.tx_auth_rq++; ++ skb=ieee80211_authentication_req(beacon, ieee, 0); ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->iw_mode == ieee->iw_ext_mode ) { ++ if(skb) ++ softmac_mgmt_xmit(skb, ieee); ++ return; ++ }else ++#endif ++ if (!skb){ ++ ++ ieee80211_associate_abort(ieee); ++ } ++ else{ ++ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ; ++ IEEE80211_DEBUG_MGMT("Sending authentication request\n"); ++ //printk("---Sending authentication request\n"); ++ softmac_mgmt_xmit(skb, ieee); ++ //BUGON when you try to add_timer twice, using mod_timer may be better, john0709 ++ if(!timer_pending(&ieee->associate_timer)){ ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ //If call dev_kfree_skb_any,a warning will ocur.... ++ //KERNEL: assertion (!atomic_read(&skb->users)) failed at net/core/dev.c (1708) ++ //So ... 1204 by lawrence. ++ //printk("\nIn %s,line %d call kfree skb.",__FUNCTION__,__LINE__); ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) ++{ ++ u8 *c; ++ struct sk_buff *skb; ++ struct ieee80211_network *beacon = &ieee->current_network; ++// int hlen = sizeof(struct ieee80211_authentication); ++ del_timer_sync(&ieee->associate_timer); ++ ieee->associate_seq++; ++ ieee->softmac_stats.tx_auth_rq++; ++ ++ skb = ieee80211_authentication_req(beacon, ieee, chlen+2); ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ c = skb_put(skb, chlen+2); ++ *(c++) = MFIE_TYPE_CHALLENGE; ++ *(c++) = chlen; ++ memcpy(c, challenge, chlen); ++ ++ IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n"); ++ ++ ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr )); ++ ++ softmac_mgmt_xmit(skb, ieee); ++ if (!timer_pending(&ieee->associate_timer)){ ++ //printk("=========>add timer again, to crash\n"); ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ kfree(challenge); ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ ++// based on ieee80211_assoc_resp ++struct sk_buff* ieee80211_assoc_resp_by_net(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type) ++{ ++ struct sk_buff *skb; ++ u8* tag; ++ ++ struct ieee80211_crypt_data* crypt; ++ struct ieee80211_assoc_response_frame *assoc; ++ short encrypt; ++ ++ unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); ++ int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; ++ ++ if(ieee->iw_mode == ieee->iw_ext_mode) ++ skb = dev_alloc_skb(len+256); // stanley ++ else ++ skb = dev_alloc_skb(len); ++ ++ if (!skb) ++ return NULL; ++ ++ assoc = (struct ieee80211_assoc_response_frame *) ++ skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); ++ ++ assoc->header.frame_ctl = cpu_to_le16(pkt_type); ++ ++ memcpy(assoc->header.addr1, dest,ETH_ALEN); ++ memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); ++ memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); ++ assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? ++ WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); ++ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_1) ++ ieee->ext_patch_ieee80211_assoc_resp_by_net_1(assoc); ++ ++ if(ieee->short_slot) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); ++ ++ if (ieee->host_encrypt) ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ else crypt = NULL; ++ ++ encrypt = ( crypt && crypt->ops); ++ ++ if (encrypt) ++ assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); ++ ++ assoc->status = 0; ++ assoc->aid = cpu_to_le16(ieee->assoc_id); ++ if (ieee->assoc_id == 0x2007) ieee->assoc_id=0; ++ else ieee->assoc_id++; ++ ++ assoc->info_element.id = 230; // Stanley, an unused id (just a hot fix) ++ assoc->info_element.len = 0; ++ ++ tag = (u8*) skb_put(skb, rate_len); ++ ++ ieee80211_MFIE_Brate(ieee, &tag); ++ ieee80211_MFIE_Grate(ieee, &tag); ++ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_assoc_resp_by_net_2) ++ ieee->ext_patch_ieee80211_assoc_resp_by_net_2(ieee, pstat, pkt_type, skb); ++ ++ return skb; ++} ++ ++// based on ieee80211_resp_to_assoc_rq ++void ieee80211_ext_issue_assoc_rsp(struct ieee80211_device *ieee, u8 *dest, unsigned short status, struct ieee80211_network *pstat, int pkt_type) ++{ ++ struct sk_buff *buf = ieee80211_assoc_resp_by_net(ieee, dest, status, pstat, pkt_type); ++ ++ if (buf) ++ softmac_mgmt_xmit(buf, ieee); ++} ++ ++// based on ieee80211_associate_step2 ++void ieee80211_ext_issue_assoc_req(struct ieee80211_device *ieee, struct ieee80211_network *pstat) ++{ ++ ++ struct sk_buff* skb; ++ ++ // printk("@@@@@ ieee80211_ext_issue_assoc_req on channel: %d\n", ieee->current_network.channel); ++ ++ ieee->softmac_stats.tx_ass_rq++; ++ skb=ieee80211_association_req(pstat, ieee); ++ if (skb) ++ softmac_mgmt_xmit(skb, ieee); ++} ++ ++void ieee80211_ext_issue_disassoc(struct ieee80211_device *ieee, struct ieee80211_network *pstat, int reason, unsigned char extReason) ++{ ++ // do nothing ++ // printk("@@@@@ ieee80211_ext_issue_disassoc\n"); ++ return; ++} ++#endif // _RTL8187_EXT_PATCH_ ++ ++void ieee80211_associate_step2(struct ieee80211_device *ieee) ++{ ++ struct sk_buff* skb; ++ struct ieee80211_network *beacon = &ieee->current_network; ++ ++ del_timer_sync(&ieee->associate_timer); ++ ++ IEEE80211_DEBUG_MGMT("Sending association request\n"); ++ ieee->softmac_stats.tx_ass_rq++; ++ skb=ieee80211_association_req(beacon, ieee); ++ if (!skb) ++ ieee80211_associate_abort(ieee); ++ else{ ++ softmac_mgmt_xmit(skb, ieee); ++ if (!timer_pending(&ieee->associate_timer)){ ++ ieee->associate_timer.expires = jiffies + (HZ / 2); ++ add_timer(&ieee->associate_timer); ++ } ++ //dev_kfree_skb_any(skb);//edit by thomas ++ } ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_complete_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq); ++#else ++void ieee80211_associate_complete_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ printk(KERN_INFO "Associated successfully\n"); ++ if(ieee80211_is_54g(ieee->current_network) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION)){ ++ ++ ieee->rate = 540; ++ printk(KERN_INFO"Using G rates\n"); ++ }else{ ++ ieee->rate = 110; ++ printk(KERN_INFO"Using B rates\n"); ++ } ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ netif_carrier_on(ieee->dev); ++} ++ ++void ieee80211_associate_complete(struct ieee80211_device *ieee) ++{ ++ int i; ++ del_timer_sync(&ieee->associate_timer); ++ ++ for(i = 0; i < 6; i++) { ++ //ieee->seq_ctrl[i] = 0; ++ } ++ ieee->state = IEEE80211_LINKED; ++ IEEE80211_DEBUG_MGMT("Successfully associated\n"); ++ ++ queue_work(ieee->wq, &ieee->associate_complete_wq); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_procedure_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); ++#else ++void ieee80211_associate_procedure_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_scan(ieee); ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ ieee->associate_seq = 1; ++ ieee80211_associate_step1(ieee); ++ ++ up(&ieee->wx_sem); ++} ++#ifdef _RTL8187_EXT_PATCH_ ++// based on ieee80211_associate_procedure_wq ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void ieee80211_ext_stop_scan_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, ext_stop_scan_wq); ++#else ++void ieee80211_ext_stop_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ if (ieee->scanning == 0) ++ { ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel ++ && ( ieee->current_network.channel == ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee) ) ) ++ return; ++ } ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ ++ // printk("@@@@@@@@@@ ieee80211_ext_stop_scan_wq\n"); ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_scan(ieee); ++ ++ // set channel ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel) ++ ieee->set_chan(ieee->dev, ieee->ext_patch_ieee80211_ext_stop_scan_wq_set_channel(ieee)); ++ else ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ // ++ up(&ieee->wx_sem); ++} ++ ++ ++void ieee80211_ext_send_11s_beacon(struct ieee80211_device *ieee) ++{ ++ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->ext_send_beacon_wq); ++ #else ++ schedule_task(&ieee->ext_send_beacon_wq); ++ #endif ++ ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net) ++{ ++ u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; ++ int tmp_ssid_len = 0; ++ ++ short apset,ssidset,ssidbroad,apmatch,ssidmatch; ++ ++ /* we are interested in new new only if we are not associated ++ * and we are not associating / authenticating ++ */ ++ if (ieee->state != IEEE80211_NOLINK) ++ return; ++ ++ if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS)) ++ return; ++ ++ if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) ++ return; ++ ++ ++ if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){ ++ /* if the user specified the AP MAC, we need also the essid ++ * This could be obtained by beacons or, if the network does not ++ * broadcast it, it can be put manually. ++ */ ++ apset = ieee->wap_set;//(memcmp(ieee->current_network.bssid, zero,ETH_ALEN)!=0 ); ++ ssidset = ieee->ssid_set;//ieee->current_network.ssid[0] != '\0'; ++ ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0'); ++ apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0); ++ ++ if(ieee->current_network.ssid_len != net->ssid_len) ++ ssidmatch = 0; ++ else ++ ssidmatch = (0==strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); ++ ++ //printk("cur: %s, %d, net:%s, %d\n", ieee->current_network.ssid, ieee->current_network.ssid_len, net->ssid, net->ssid_len); ++ //printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch); ++ ++ if ( /* if the user set the AP check if match. ++ * if the network does not broadcast essid we check the user supplyed ANY essid ++ * if the network does broadcast and the user does not set essid it is OK ++ * if the network does broadcast and the user did set essid chech if essid match ++ */ ++ ( apset && apmatch && ++ ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || ++ /* if the ap is not set, check that the user set the bssid ++ * and the network does bradcast and that those two bssid matches ++ */ ++ (!apset && ssidset && ssidbroad && ssidmatch) ++ ){ ++ ++ ++ /* if the essid is hidden replace it with the ++ * essid provided by the user. ++ */ ++ if (!ssidbroad){ ++ strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); ++ tmp_ssid_len = ieee->current_network.ssid_len; ++ } ++ memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network)); ++ ++ if (!ssidbroad){ ++ strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); ++ ieee->current_network.ssid_len = tmp_ssid_len; ++ } ++ printk(KERN_INFO"Linking with %s: channel is %d\n",ieee->current_network.ssid,ieee->current_network.channel); ++ ++ if (ieee->iw_mode == IW_MODE_INFRA){ ++ ieee->state = IEEE80211_ASSOCIATING; ++ ieee->beinretry = false; ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++ }else{ ++ if(ieee80211_is_54g(ieee->current_network) && ++ (ieee->modulation & IEEE80211_OFDM_MODULATION)){ ++ ieee->rate = 540; ++ printk(KERN_INFO"Using G rates\n"); ++ }else{ ++ ieee->rate = 110; ++ printk(KERN_INFO"Using B rates\n"); ++ } ++ ieee->state = IEEE80211_LINKED; ++ ieee->beinretry = false; ++ } ++ ++ } ++ } ++ ++} ++ ++void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ struct ieee80211_network *target; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ list_for_each_entry(target, &ieee->network_list, list) { ++ ++ /* if the state become different that NOLINK means ++ * we had found what we are searching for ++ */ ++ ++ if (ieee->state != IEEE80211_NOLINK) ++ break; ++ ++ if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) ++ ieee80211_softmac_new_net(ieee, target); ++ } ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++ ++static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen) ++{ ++ struct ieee80211_authentication *a; ++ u8 *t; ++ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len); ++ return 0xcafe; ++ } ++ *challenge = NULL; ++ a = (struct ieee80211_authentication*) skb->data; ++ if(skb->len > (sizeof(struct ieee80211_authentication) +3)){ ++ t = skb->data + sizeof(struct ieee80211_authentication); ++ ++ if(*(t++) == MFIE_TYPE_CHALLENGE){ ++ *chlen = *(t++); ++ *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC); ++ memcpy(*challenge, t, *chlen); ++ } ++ } ++ ++ return cpu_to_le16(a->status); ++ ++} ++ ++ ++int auth_rq_parse(struct sk_buff *skb,u8* dest) ++{ ++ struct ieee80211_authentication *a; ++ ++ if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len); ++ return -1; ++ } ++ a = (struct ieee80211_authentication*) skb->data; ++ ++ memcpy(dest,a->header.addr2, ETH_ALEN); ++ ++ if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) ++ return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; ++ ++ return WLAN_STATUS_SUCCESS; ++} ++ ++static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src) ++{ ++ u8 *tag; ++ u8 *skbend; ++ u8 *ssid=NULL; ++ u8 ssidlen = 0; ++ ++ struct ieee80211_hdr_3addr *header = ++ (struct ieee80211_hdr_3addr *) skb->data; ++ ++ if (skb->len < sizeof (struct ieee80211_hdr_3addr )) ++ return -1; /* corrupted */ ++ ++ memcpy(src,header->addr2, ETH_ALEN); ++ ++ skbend = (u8*)skb->data + skb->len; ++ ++ tag = skb->data + sizeof (struct ieee80211_hdr_3addr ); ++ ++ while (tag+1 < skbend){ ++ if (*tag == 0){ ++ ssid = tag+2; ++ ssidlen = *(tag+1); ++ break; ++ } ++ tag++; /* point to the len field */ ++ tag = tag + *(tag); /* point to the last data byte of the tag */ ++ tag++; /* point to the next tag */ ++ } ++ ++ //IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src)); ++ if (ssidlen == 0) return 1; ++ ++ if (!ssid) return 1; /* ssid not found in tagged param */ ++ return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); ++ ++} ++ ++int assoc_rq_parse(struct sk_buff *skb,u8* dest) ++{ ++ struct ieee80211_assoc_request_frame *a; ++ ++ if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) - ++ sizeof(struct ieee80211_info_element))) { ++ ++ IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len); ++ return -1; ++ } ++ ++ a = (struct ieee80211_assoc_request_frame*) skb->data; ++ ++ memcpy(dest,a->header.addr2,ETH_ALEN); ++ ++ return 0; ++} ++ ++static inline u16 assoc_parse(struct sk_buff *skb, int *aid) ++{ ++ struct ieee80211_assoc_response_frame *a; ++ if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){ ++ IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); ++ return 0xcafe; ++ } ++ ++ a = (struct ieee80211_assoc_response_frame*) skb->data; ++ *aid = le16_to_cpu(a->aid) & 0x3fff; ++ return le16_to_cpu(a->status); ++} ++ ++static inline void ++ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ u8 dest[ETH_ALEN]; ++ ++ //IEEE80211DMESG("Rx probe"); ++ ieee->softmac_stats.rx_probe_rq++; ++ //DMESG("Dest is "MACSTR, MAC2STR(dest)); ++ if (probe_rq_parse(ieee, skb, dest)){ ++ //IEEE80211DMESG("Was for me!"); ++ ieee->softmac_stats.tx_probe_rs++; ++ ieee80211_resp_to_probe(ieee, dest); ++ } ++} ++ ++inline void ++ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ u8 dest[ETH_ALEN]; ++ int status; ++ //IEEE80211DMESG("Rx probe"); ++ ieee->softmac_stats.rx_auth_rq++; ++ ++ if ((status = auth_rq_parse(skb, dest))!= -1){ ++ ieee80211_resp_to_auth(ieee, status, dest); ++ } ++ //DMESG("Dest is "MACSTR, MAC2STR(dest)); ++ ++} ++ ++ inline void ++ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb) ++{ ++ ++ u8 dest[ETH_ALEN]; ++ //unsigned long flags; ++ ++ ieee->softmac_stats.rx_ass_rq++; ++ if (assoc_rq_parse(skb,dest) != -1){ ++ ieee80211_resp_to_assoc_rq(ieee, dest); ++ } ++ ++ printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest)); ++ //FIXME ++ #if 0 ++ spin_lock_irqsave(&ieee->lock,flags); ++ add_associate(ieee,dest); ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ #endif ++} ++ ++ ++ ++void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr) ++{ ++ ++ struct sk_buff *buf = ieee80211_null_func(ieee, pwr); ++ ++ if (buf) ++ softmac_ps_mgmt_xmit(buf, ieee); ++ ++} ++ ++ ++short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l) ++{ ++#if 0 ++ int timeout = ieee->ps_timeout; ++#else ++ int timeout = 0; ++#endif ++ u8 dtim; ++ /*if(ieee->ps == IEEE80211_PS_DISABLED || ++ ieee->iw_mode != IW_MODE_INFRA || ++ ieee->state != IEEE80211_LINKED) ++ ++ return 0; ++ */ ++ dtim = ieee->current_network.dtim_data; ++ //printk("DTIM\n"); ++ ++ if(!(dtim & IEEE80211_DTIM_VALID)) ++ return 0; ++ else ++ timeout = ieee->current_network.beacon_interval; ++ ++ //printk("VALID\n"); ++ ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID; ++ ++ if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps)) ++ return 2; ++ ++ if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))) ++ return 0; ++ ++ if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))) ++ return 0; ++ ++ if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) && ++ (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) ++ return 0; ++#if 0 ++ if(time_l){ ++ *time_l = ieee->current_network.last_dtim_sta_time[0] ++ + (ieee->current_network.beacon_interval ++ * ieee->current_network.dtim_period) * 1000; ++ } ++#else ++ if(time_l){ ++ *time_l = ieee->current_network.last_dtim_sta_time[0] ++ + MSECS((ieee->current_network.beacon_interval)); ++ //* ieee->current_network.dtim_period)); ++ //printk("beacon_interval:%x, dtim_period:%x, totol to Msecs:%x, HZ:%x\n", ieee->current_network.beacon_interval, ieee->current_network.dtim_period, MSECS(((ieee->current_network.beacon_interval * ieee->current_network.dtim_period))), HZ); ++ } ++ ++#endif ++ if(time_h){ ++ *time_h = ieee->current_network.last_dtim_sta_time[1]; ++ if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) ++ *time_h += 1; ++ } ++ ++ return 1; ++ ++ ++} ++ ++inline void ieee80211_sta_ps(struct ieee80211_device *ieee) ++{ ++ ++ u32 th,tl; ++ short sleep; ++ ++ unsigned long flags,flags2; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if((ieee->ps == IEEE80211_PS_DISABLED || ++ ++ ieee->iw_mode != IW_MODE_INFRA || ++ ieee->state != IEEE80211_LINKED)){ ++ ++ //#warning CHECK_LOCK_HERE ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ ieee80211_sta_wakeup(ieee, 1); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ ++ sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl); ++// printk("===>%s,%d[2 wake, 1 sleep, 0 do nothing], ieee->sta_sleep = %d\n",__FUNCTION__, sleep,ieee->sta_sleep); ++ /* 2 wake, 1 sleep, 0 do nothing */ ++ if(sleep == 0) ++ goto out; ++ ++ if(sleep == 1){ ++ ++ if(ieee->sta_sleep == 1) ++ ieee->enter_sleep_state(ieee->dev,th,tl); ++ ++ else if(ieee->sta_sleep == 0){ ++ // printk("send null 1\n"); ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ if(ieee->ps_is_queue_empty(ieee->dev)){ ++ ++ ++ ieee->sta_sleep = 2; ++ ++ ieee->ps_request_tx_ack(ieee->dev); ++ ++ ieee80211_sta_ps_send_null_frame(ieee,1); ++ ++ ieee->ps_th = th; ++ ieee->ps_tl = tl; ++ } ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ ++ } ++ ++ ++ }else if(sleep == 2){ ++//#warning CHECK_LOCK_HERE ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ++ // printk("send wakeup packet\n"); ++ ieee80211_sta_wakeup(ieee,1); ++ ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ ++out: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++} ++ ++void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl) ++{ ++ if(ieee->sta_sleep == 0){ ++ if(nl){ ++ // printk("Warning: driver is probably failing to report TX ps error\n"); ++ ieee->ps_request_tx_ack(ieee->dev); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ } ++ return; ++ ++ } ++ ++ if(ieee->sta_sleep == 1) ++ ieee->sta_wake_up(ieee->dev); ++ ++ ieee->sta_sleep = 0; ++ ++ if(nl){ ++ ieee->ps_request_tx_ack(ieee->dev); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ } ++} ++ ++void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success) ++{ ++ unsigned long flags,flags2; ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ if(ieee->sta_sleep == 2){ ++ /* Null frame with PS bit set */ ++ if(success){ ++ ++ // printk("==================> %s::enter sleep state\n",__FUNCTION__); ++ ieee->sta_sleep = 1; ++ ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl); ++ } ++ /* if the card report not success we can't be sure the AP ++ * has not RXed so we can't assume the AP believe us awake ++ */ ++ } ++ /* 21112005 - tx again null without PS bit if lost */ ++ else { ++ ++ if((ieee->sta_sleep == 0) && !success){ ++ spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); ++ ieee80211_sta_ps_send_null_frame(ieee, 0); ++ spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++inline int ++ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ++ struct ieee80211_rx_stats *rx_stats, u16 type, ++ u16 stype) ++{ ++ struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data; ++ u16 errcode; ++ u8* challenge=NULL; ++ int chlen=0; ++ int aid=0; ++ struct ieee80211_assoc_response_frame *assoc_resp; ++ struct ieee80211_info_element *info_element; ++ ++ if(!ieee->proto_started) ++ return 0; ++ ++ if(ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && ++ ieee->iw_mode == IW_MODE_INFRA && ++ ieee->state == IEEE80211_LINKED)) ++ ++ tasklet_schedule(&ieee->ps_task); ++ ++ if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && ++ WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) ++ ieee->last_rx_ps_time = jiffies; ++ ++ switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { ++ ++ case IEEE80211_STYPE_ASSOC_RESP: ++ case IEEE80211_STYPE_REASSOC_RESP: ++ ++ IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", ++ WLAN_FC_GET_STYPE(header->frame_ctl)); ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ if (0 == (errcode=assoc_parse(skb, &aid))){ ++ u16 left; ++ ++ ieee->state=IEEE80211_LINKED; ++ ieee->assoc_id = aid; ++ ieee->softmac_stats.rx_ass_ok++; ++ ++ //printk(KERN_WARNING "nic_type = %s", (rx_stats->nic_type == 1)?"rtl8187":"rtl8187B"); ++ if(1 == rx_stats->nic_type) //card type is 8187 ++ { ++ goto associate_complete; ++ } ++ assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data; ++ info_element = &assoc_resp->info_element; ++ left = skb->len - ((void*)info_element - (void*)assoc_resp); ++ ++ while (left >= sizeof(struct ieee80211_info_element_hdr)) { ++ if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { ++ printk(KERN_WARNING "[re]associate reeponse error!"); ++ return 1; ++ } ++ switch (info_element->id) { ++ case MFIE_TYPE_GENERIC: ++ IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len); ++ if (info_element->len >= 8 && ++ info_element->data[0] == 0x00 && ++ info_element->data[1] == 0x50 && ++ info_element->data[2] == 0xf2 && ++ info_element->data[3] == 0x02 && ++ info_element->data[4] == 0x01) { ++ // Not care about version at present. ++ //WMM Parameter Element ++ memcpy(ieee->current_network.wmm_param,(u8*)(info_element->data\ ++ + 8),(info_element->len - 8)); ++ ++ if (((ieee->current_network.wmm_info^info_element->data[6])& \ ++ 0x0f)||(!ieee->init_wmmparam_flag)) { ++ //refresh paramete element for current network ++ // update the register parameter for hardware ++ ieee->init_wmmparam_flag = 1; ++ queue_work(ieee->wq, &ieee->wmm_param_update_wq); ++ ++ } ++ //update info_element for current network ++ ieee->current_network.wmm_info = info_element->data[6]; ++ } ++ break; ++ default: ++ //nothing to do at present!!! ++ break; ++ } ++ ++ left -= sizeof(struct ieee80211_info_element_hdr) + ++ info_element->len; ++ info_element = (struct ieee80211_info_element *) ++ &info_element->data[info_element->len]; ++ } ++ if(!ieee->init_wmmparam_flag) //legacy AP, reset the AC_xx_param register ++ { ++ queue_work(ieee->wq,&ieee->wmm_param_update_wq); ++ ieee->init_wmmparam_flag = 1;//indicate AC_xx_param upated since last associate ++ } ++associate_complete: ++ ieee80211_associate_complete(ieee); ++ }else{ ++ ieee->softmac_stats.rx_ass_err++; ++ IEEE80211_DEBUG_MGMT( ++ "Association response status code 0x%x\n", ++ errcode); ++ ieee80211_associate_abort(ieee); ++ } ++ } ++#ifdef _RTL8187_EXT_PATCH_ ++ else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp) ++ { ++ ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_rsp(ieee, skb); ++ } ++#endif ++ break; ++ ++ case IEEE80211_STYPE_ASSOC_REQ: ++ case IEEE80211_STYPE_REASSOC_REQ: ++ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ ieee->iw_mode == IW_MODE_MASTER) ++ ++ ieee80211_rx_assoc_rq(ieee, skb); ++#ifdef _RTL8187_EXT_PATCH_ ++ else if ((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req) ++ { ++ ieee->ext_patch_ieee80211_rx_frame_softmac_on_assoc_req(ieee, skb); ++ } ++#endif ++ break; ++ ++ case IEEE80211_STYPE_AUTH: ++ ++#ifdef _RTL8187_EXT_PATCH_ ++printk("IEEE80211_STYPE_AUTH\n"); ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth) ++ if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_auth(ieee, skb, rx_stats) ); ++#endif ++ if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){ ++ if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING && ++ ieee->iw_mode == IW_MODE_INFRA){ ++ ++ IEEE80211_DEBUG_MGMT("Received authentication response"); ++ ++ if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){ ++ if(ieee->open_wep || !challenge){ ++ ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED; ++ ieee->softmac_stats.rx_auth_rs_ok++; ++ ++ ieee80211_associate_step2(ieee); ++ }else{ ++ ieee80211_auth_challenge(ieee, challenge, chlen); ++ } ++ }else{ ++ ieee->softmac_stats.rx_auth_rs_err++; ++ IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); ++ ieee80211_associate_abort(ieee); ++ } ++ ++ }else if (ieee->iw_mode == IW_MODE_MASTER){ ++ ieee80211_rx_auth_rq(ieee, skb); ++ } ++ } ++ break; ++ ++ case IEEE80211_STYPE_PROBE_REQ: ++ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && ++ ((ieee->iw_mode == IW_MODE_ADHOC || ++ ieee->iw_mode == IW_MODE_MASTER) && ++ ieee->state == IEEE80211_LINKED)) ++ ++ ieee80211_rx_probe_rq(ieee, skb); ++ break; ++ ++ case IEEE80211_STYPE_DISASSOC: ++ case IEEE80211_STYPE_DEAUTH: ++#ifdef _RTL8187_EXT_PATCH_ ++printk("IEEE80211_STYPE_DEAUTH\n"); ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth) ++ if( ieee->ext_patch_ieee80211_rx_frame_softmac_on_deauth(ieee, skb, rx_stats) ) ; ++#endif ++ /* FIXME for now repeat all the association procedure ++ * both for disassociation and deauthentication ++ */ ++ if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && ++ (ieee->state == IEEE80211_LINKED) && ++ (ieee->iw_mode == IW_MODE_INFRA) && ++ (!memcmp(header->addr2,ieee->current_network.bssid,ETH_ALEN))){ ++ ieee->state = IEEE80211_ASSOCIATING; ++ ieee->softmac_stats.reassoc++; ++ ++ //notify_wx_assoc_event(ieee); //YJ,del,080828, do not notify os here ++ queue_work(ieee->wq, &ieee->associate_procedure_wq); ++ } ++ ++ break; ++ ++ default: ++ return -1; ++ break; ++ } ++ ++ //dev_kfree_skb_any(skb); ++ return 0; ++} ++ ++ ++ ++/* following are for a simplier TX queue management. ++ * Instead of using netif_[stop/wake]_queue the driver ++ * will uses these two function (plus a reset one), that ++ * will internally uses the kernel netif_* and takes ++ * care of the ieee802.11 fragmentation. ++ * So the driver receives a fragment per time and might ++ * call the stop function when it want without take care ++ * to have enought room to TX an entire packet. ++ * This might be useful if each fragment need it's own ++ * descriptor, thus just keep a total free memory > than ++ * the max fragmentation treshold is not enought.. If the ++ * ieee802.11 stack passed a TXB struct then you needed ++ * to keep N free descriptors where ++ * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD ++ * In this way you need just one and the 802.11 stack ++ * will take care of buffering fragments and pass them to ++ * to the driver later, when it wakes the queue. ++ */ ++ ++void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee) ++{ ++ ++ ++ unsigned long flags; ++ int i; ++#ifdef _RTL8187_EXT_PATCH_ ++ int rate = ieee->rate; ++#endif ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ #if 0 ++ if(ieee->queue_stop){ ++ IEEE80211DMESG("EE: IEEE hard_start_xmit invoked when kernel queue should be stopped"); ++ netif_stop_queue(ieee->dev); ++ ieee->ieee_stats.swtxstop++; ++ //dev_kfree_skb_any(skb); ++ err = 1; ++ goto exit; ++ } ++ ++ ieee->stats.tx_bytes+=skb->len; ++ ++ ++ txb=ieee80211_skb_to_txb(ieee,skb); ++ ++ ++ if(txb==NULL){ ++ IEEE80211DMESG("WW: IEEE stack failed to provide txb"); ++ //dev_kfree_skb_any(skb); ++ err = 1; ++ goto exit; ++ } ++ #endif ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_ieee80211_softmac_xmit_get_rate && txb->nr_frags) ++ { ++ rate = ieee->ext_patch_ieee80211_softmac_xmit_get_rate(ieee, txb->fragments[0]); ++ } ++#endif ++ /* called with 2nd parm 0, no tx mgmt lock required */ ++ ieee80211_sta_wakeup(ieee,0); ++ ++ for(i = 0; i < txb->nr_frags; i++) { ++ ++ if (ieee->queue_stop){ ++ ieee->tx_pending.txb = txb; ++ ieee->tx_pending.frag = i; ++ goto exit; ++ }else{ ++ ieee->softmac_data_hard_start_xmit( ++ txb->fragments[i], ++#ifdef _RTL8187_EXT_PATCH_ ++ ieee->dev, rate); ++#else ++ ieee->dev,ieee->rate); ++#endif ++ //(i+1)nr_frags); ++ ieee->stats.tx_packets++; ++ ieee->stats.tx_bytes += txb->fragments[i]->len; ++ ieee->dev->trans_start = jiffies; ++ } ++ } ++ ++ ieee80211_txb_free(txb); ++ ++ exit: ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++/* called with ieee->lock acquired */ ++void ieee80211_resume_tx(struct ieee80211_device *ieee) ++{ ++ int i; ++ for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { ++ ++ if (ieee->queue_stop){ ++ ieee->tx_pending.frag = i; ++ return; ++ }else{ ++ ++ ieee->softmac_data_hard_start_xmit( ++ ieee->tx_pending.txb->fragments[i], ++ ieee->dev,ieee->rate); ++ //(i+1)tx_pending.txb->nr_frags); ++ ieee->stats.tx_packets++; ++ ieee->dev->trans_start = jiffies; ++ } ++ } ++ ++ ++ ieee80211_txb_free(ieee->tx_pending.txb); ++ ieee->tx_pending.txb = NULL; ++} ++ ++ ++void ieee80211_reset_queue(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ init_mgmt_queue(ieee); ++ if (ieee->tx_pending.txb){ ++ ieee80211_txb_free(ieee->tx_pending.txb); ++ ieee->tx_pending.txb = NULL; ++ } ++ ieee->queue_stop = 0; ++ spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++void ieee80211_wake_queue(struct ieee80211_device *ieee) ++{ ++ ++ unsigned long flags; ++ struct sk_buff *skb; ++ struct ieee80211_hdr_3addr *header; ++ ++ spin_lock_irqsave(&ieee->lock,flags); ++ if (! ieee->queue_stop) goto exit; ++ ++ ieee->queue_stop = 0; ++ ++ if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){ ++ while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){ ++ ++ header = (struct ieee80211_hdr_3addr *) skb->data; ++ ++ header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ //printk(KERN_ALERT "ieee80211_wake_queue \n"); ++ ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); ++ dev_kfree_skb_any(skb);//edit by thomas ++ } ++ } ++ if (!ieee->queue_stop && ieee->tx_pending.txb) ++ ieee80211_resume_tx(ieee); ++ ++ if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){ ++ ieee->softmac_stats.swtxawake++; ++ netif_wake_queue(ieee->dev); ++ } ++ ++exit : ++ spin_unlock_irqrestore(&ieee->lock,flags); ++} ++ ++ ++void ieee80211_stop_queue(struct ieee80211_device *ieee) ++{ ++ //unsigned long flags; ++ //spin_lock_irqsave(&ieee->lock,flags); ++ ++ if (! netif_queue_stopped(ieee->dev)){ ++ netif_stop_queue(ieee->dev); ++ ieee->softmac_stats.swtxstop++; ++ } ++ ieee->queue_stop = 1; ++ //spin_unlock_irqrestore(&ieee->lock,flags); ++ ++} ++ ++ ++inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) ++{ ++ ++ get_random_bytes(ieee->current_network.bssid, ETH_ALEN); ++ ++ /* an IBSS cell address must have the two less significant ++ * bits of the first byte = 2 ++ */ ++ ieee->current_network.bssid[0] &= ~0x01; ++ ieee->current_network.bssid[0] |= 0x02; ++} ++ ++/* called in user context only */ ++void ieee80211_start_master_bss(struct ieee80211_device *ieee) ++{ ++ ieee->assoc_id = 1; ++ ++ if (ieee->current_network.ssid_len == 0){ ++ strncpy(ieee->current_network.ssid, ++ IEEE80211_DEFAULT_TX_ESSID, ++ IW_ESSID_MAX_SIZE); ++ ++ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); ++ ieee->ssid_set = 1; ++ } ++ ++ memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); ++ ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->state = IEEE80211_LINKED; ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++} ++ ++void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) ++{ ++ if(ieee->raw_tx){ ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_start_ibss_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); ++#else ++void ieee80211_start_ibss_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ ++ /* iwconfig mode ad-hoc will schedule this and return ++ * on the other hand this will block further iwconfig SET ++ * operations because of the wx_sem hold. ++ * Anyway some most set operations set a flag to speed-up ++ * (abort) this wq (when syncro scanning) before sleeping ++ * on the semaphore ++ */ ++ ++ down(&ieee->wx_sem); ++ ++ ++ if (ieee->current_network.ssid_len == 0){ ++ strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID); ++ ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); ++ ieee->ssid_set = 1; ++ } ++ ++ /* check if we have this cell in our network list */ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++#ifdef ENABLE_DOT11D ++ if(ieee->state == IEEE80211_NOLINK) ++ ieee->current_network.channel = 10; ++#endif ++ /* if not then the state is not linked. Maybe the user swithced to ++ * ad-hoc mode just after being in monitor mode, or just after ++ * being very few time in managed mode (so the card have had no ++ * time to scan all the chans..) or we have just run up the iface ++ * after setting ad-hoc mode. So we have to give another try.. ++ * Here, in ibss mode, should be safe to do this without extra care ++ * (in bss mode we had to make sure no-one tryed to associate when ++ * we had just checked the ieee->state and we was going to start the ++ * scan) beacause in ibss mode the ieee80211_new_net function, when ++ * finds a good net, just set the ieee->state to IEEE80211_LINKED, ++ * so, at worst, we waste a bit of time to initiate an unneeded syncro ++ * scan, that will stop at the first round because it sees the state ++ * associated. ++ */ ++ if (ieee->state == IEEE80211_NOLINK) ++ ieee80211_start_scan_syncro(ieee); ++ ++ /* the network definitively is not here.. create a new cell */ ++ if (ieee->state == IEEE80211_NOLINK){ ++ printk("creating new IBSS cell\n"); ++ if(!ieee->wap_set) ++ ieee80211_randomize_cell(ieee); ++ ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ ++ ieee->current_network.rates_len = 4; ++ ++ ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; ++ ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; ++ ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; ++ ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; ++ ++ }else ++ ieee->current_network.rates_len = 0; ++ ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ieee->current_network.rates_ex_len = 8; ++ ++ ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; ++ ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; ++ ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; ++ ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; ++ ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; ++ ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; ++ ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; ++ ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; ++ ++ ieee->rate = 540; ++ }else{ ++ ieee->current_network.rates_ex_len = 0; ++ ieee->rate = 110; ++ } ++ ++ // By default, WMM function will be disabled in IBSS mode ++ ieee->current_network.QoS_Enable = 0; ++ ++ ieee->current_network.atim_window = 0; ++ ieee->current_network.capability = WLAN_CAPABILITY_IBSS; ++ if(ieee->short_slot) ++ ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT; ++ ++ } ++ ++ ieee->state = IEEE80211_LINKED; ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ieee->link_change(ieee->dev); ++ ++ notify_wx_assoc_event(ieee); ++ ++ ieee80211_start_send_beacons(ieee); ++ printk(KERN_WARNING "after sending beacon packet!\n"); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ ++ up(&ieee->wx_sem); ++} ++inline void ieee80211_start_ibss(struct ieee80211_device *ieee) ++{ ++ queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 100); ++} ++ ++/* this is called only in user context, with wx_sem held */ ++void ieee80211_start_bss(struct ieee80211_device *ieee) ++{ ++ unsigned long flags; ++#ifdef ENABLE_DOT11D ++ // ++ // Ref: 802.11d 11.1.3.3 ++ // STA shall not start a BSS unless properly formed Beacon frame including a Country IE. ++ // ++ if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) ++ { ++ if(! ieee->bGlobalDomain) ++ { ++ return; ++ } ++ } ++#endif ++ /* check if we have already found the net we ++ * are interested in (if any). ++ * if not (we are disassociated and we are not ++ * in associating / authenticating phase) start the background scanning. ++ */ ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ /* ensure no-one start an associating process (thus setting ++ * the ieee->state to ieee80211_ASSOCIATING) while we ++ * have just cheked it and we are going to enable scan. ++ * The ieee80211_new_net function is always called with ++ * lock held (from both ieee80211_softmac_check_all_nets and ++ * the rx path), so we cannot be in the middle of such function ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++//#ifdef ENABLE_IPS ++// printk("start bss ENABLE_IPS\n"); ++//#else ++ if (ieee->state == IEEE80211_NOLINK){ ++ ieee->actscanning = true; ++ ieee80211_start_scan(ieee); ++ } ++//#endif ++ spin_unlock_irqrestore(&ieee->lock, flags); ++} ++ ++/* called only in userspace context */ ++void ieee80211_disassociate(struct ieee80211_device *ieee) ++{ ++ netif_carrier_off(ieee->dev); ++ ++ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) ++ ieee80211_reset_queue(ieee); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(ieee)) ++ Dot11d_Reset(ieee); ++#endif ++ ieee->state = IEEE80211_NOLINK; ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void ieee80211_associate_retry_wq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); ++#else ++void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) ++{ ++#endif ++ unsigned long flags; ++ down(&ieee->wx_sem); ++ if(!ieee->proto_started) ++ goto exit; ++ if(ieee->state != IEEE80211_ASSOCIATING_RETRY) ++ goto exit; ++ /* until we do not set the state to IEEE80211_NOLINK ++ * there are no possibility to have someone else trying ++ * to start an association procdure (we get here with ++ * ieee->state = IEEE80211_ASSOCIATING). ++ * When we set the state to IEEE80211_NOLINK it is possible ++ * that the RX path run an attempt to associate, but ++ * both ieee80211_softmac_check_all_nets and the ++ * RX path works with ieee->lock held so there are no ++ * problems. If we are still disassociated then start a scan. ++ * the lock here is necessary to ensure no one try to start ++ * an association procedure when we have just checked the ++ * state and we are going to start the scan. ++ */ ++ ieee->state = IEEE80211_NOLINK; ++ ieee->beinretry = true; ++ ieee80211_softmac_check_all_nets(ieee); ++ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(ieee->state == IEEE80211_NOLINK){ ++ ieee->beinretry = false; ++ ieee->actscanning = true; ++ ieee80211_start_scan(ieee); ++ } ++ //YJ,add,080828, notify os here ++ if(ieee->state == IEEE80211_NOLINK) ++ { ++ notify_wx_assoc_event(ieee); ++ } ++ //YJ,add,080828,end ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++exit: ++ up(&ieee->wx_sem); ++} ++ ++struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) ++{ ++ u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; ++ ++ struct sk_buff *skb = NULL; ++ struct ieee80211_probe_response *b; ++ ++//rz ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) && ieee->ext_patch_get_beacon_get_probersp ) ++ skb = ieee->ext_patch_get_beacon_get_probersp(ieee, broadcast_addr, &(ieee->current_network)); ++ else ++ skb = ieee80211_probe_resp(ieee, broadcast_addr); ++#else ++ skb = ieee80211_probe_resp(ieee, broadcast_addr); ++#endif ++// ++ if (!skb) ++ return NULL; ++ ++ b = (struct ieee80211_probe_response *) skb->data; ++ b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); ++ ++ return skb; ++ ++} ++ ++struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) ++{ ++ struct sk_buff *skb; ++ struct ieee80211_probe_response *b; ++ ++ skb = ieee80211_get_beacon_(ieee); ++ if(!skb) ++ return NULL; ++ ++ b = (struct ieee80211_probe_response *) skb->data; ++ b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); ++ ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ return skb; ++} ++ ++void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) ++{ ++ ieee->sync_scan_hurryup = 1; ++ down(&ieee->wx_sem); ++ ieee80211_stop_protocol(ieee); ++ up(&ieee->wx_sem); ++} ++ ++ ++void ieee80211_stop_protocol(struct ieee80211_device *ieee) ++{ ++ if (!ieee->proto_started) ++ return; ++ ++ ieee->proto_started = 0; ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ if(ieee->ext_patch_ieee80211_stop_protocol) ++ ieee->ext_patch_ieee80211_stop_protocol(ieee); ++//if call queue_delayed_work,can call this,or do nothing.. ++//edit by lawrence,20071118 ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++// cancel_delayed_work(&ieee->ext_stop_scan_wq); ++// cancel_delayed_work(&ieee->ext_send_beacon_wq); ++#endif ++#endif // _RTL8187_EXT_PATCH_ ++ ++ ieee80211_stop_send_beacons(ieee); ++ if((ieee->iw_mode == IW_MODE_INFRA)&&(ieee->state == IEEE80211_LINKED)) { ++ SendDisassociation(ieee,NULL,WLAN_REASON_DISASSOC_STA_HAS_LEFT); ++ } ++ del_timer_sync(&ieee->associate_timer); ++ cancel_delayed_work(&ieee->associate_retry_wq); ++ cancel_delayed_work(&ieee->start_ibss_wq); ++ ieee80211_stop_scan(ieee); ++ ++ ieee80211_disassociate(ieee); ++} ++ ++void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) ++{ ++ ieee->sync_scan_hurryup = 0; ++ down(&ieee->wx_sem); ++ ieee80211_start_protocol(ieee); ++ up(&ieee->wx_sem); ++} ++ ++void ieee80211_start_protocol(struct ieee80211_device *ieee) ++{ ++ short ch = 0; ++ int i = 0; ++ ++ if (ieee->proto_started) ++ return; ++ ++ ieee->proto_started = 1; ++ ++ if (ieee->current_network.channel == 0){ ++ do{ ++ ch++; ++ if (ch > MAX_CHANNEL_NUMBER) ++ return; /* no channel found */ ++ ++#ifdef ENABLE_DOT11D ++ }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]); ++#else ++ }while(!ieee->channel_map[ch]); ++#endif ++ ++ ieee->current_network.channel = ch; ++ } ++ ++ if (ieee->current_network.beacon_interval == 0) ++ ieee->current_network.beacon_interval = 100; ++ ieee->set_chan(ieee->dev,ieee->current_network.channel); ++ ++ for(i = 0; i < 17; i++) { ++ ieee->last_rxseq_num[i] = -1; ++ ieee->last_rxfrag_num[i] = -1; ++ ieee->last_packet_time[i] = 0; ++ } ++ ++ ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers. ++ ++ ++ /* if the user set the MAC of the ad-hoc cell and then ++ * switch to managed mode, shall we make sure that association ++ * attempts does not fail just because the user provide the essid ++ * and the nic is still checking for the AP MAC ?? ++ */ ++ switch (ieee->iw_mode) { ++ case IW_MODE_AUTO: ++ ieee->iw_mode = IW_MODE_INFRA; ++ //not set break here intentionly ++ case IW_MODE_INFRA: ++ ieee80211_start_bss(ieee); ++ break; ++ ++ case IW_MODE_ADHOC: ++ ieee80211_start_ibss(ieee); ++ break; ++ ++ case IW_MODE_MASTER: ++ ieee80211_start_master_bss(ieee); ++ break; ++ ++ case IW_MODE_MONITOR: ++ ieee80211_start_monitor_mode(ieee); ++ break; ++ ++ default: ++#ifdef _RTL8187_EXT_PATCH_ ++ if((ieee->iw_mode == ieee->iw_ext_mode) &&\ ++ ieee->ext_patch_ieee80211_start_protocol &&\ ++ ieee->ext_patch_ieee80211_start_protocol(ieee)) { ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) ++ queue_work(ieee->wq, &ieee->ext_stop_scan_wq); ++#endif ++ // By default, WMM function will be disabled in ++ // EXTENSION mode ++ ieee->current_network.QoS_Enable = 0; ++ ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ ieee->current_network.rates_len = 4; ++ ieee->current_network.rates[0] = \ ++ IEEE80211_BASIC_RATE_MASK | \ ++ IEEE80211_CCK_RATE_1MB; ++ ieee->current_network.rates[1] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_CCK_RATE_2MB; ++ ieee->current_network.rates[2] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_CCK_RATE_5MB; ++ ieee->current_network.rates[3] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_CCK_RATE_11MB; ++ }else ++ ieee->current_network.rates_len = 0; ++ ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION){ ++ ieee->current_network.rates_ex_len = 8; ++ ieee->current_network.rates_ex[0] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_6MB; ++ ieee->current_network.rates_ex[1] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_9MB; ++ ieee->current_network.rates_ex[2] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_12MB; ++ ieee->current_network.rates_ex[3] = \ ++ IEEE80211_BASIC_RATE_MASK | \ ++ IEEE80211_OFDM_RATE_18MB; ++ ieee->current_network.rates_ex[4] =\ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_24MB; ++ ieee->current_network.rates_ex[5] =\ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_36MB; ++ ieee->current_network.rates_ex[6] = \ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_48MB; ++ ieee->current_network.rates_ex[7] =\ ++ IEEE80211_BASIC_RATE_MASK |\ ++ IEEE80211_OFDM_RATE_54MB; ++ ieee->rate = 540; ++ }else{ ++ ieee->current_network.rates_ex_len = 0; ++ ieee->rate = 110; ++ } ++ ++ /* ++ spin_lock_irqsave(&ieee->lock, flags); ++ if (ieee->state == IEEE80211_NOLINK) ++ ieee80211_start_scan(ieee); ++ // ieee->set_chan(ieee->dev, 8); ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ */ ++ memcpy(ieee->current_network.bssid, ieee->dev->dev_addr,\ ++ ETH_ALEN); ++ ieee->link_change(ieee->dev); ++ notify_wx_assoc_event(ieee); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } else { ++ ieee->iw_mode = IW_MODE_INFRA; ++ ieee80211_start_bss(ieee); ++ } ++#else ++ ieee->iw_mode = IW_MODE_INFRA; ++ ieee80211_start_bss(ieee); ++ ++#endif ++ break; ++ } ++} ++ ++ ++#define DRV_NAME "Ieee80211" ++void ieee80211_softmac_init(struct ieee80211_device *ieee) ++{ ++ int i; ++ memset(&ieee->current_network, 0, sizeof(struct ieee80211_network)); ++ ++ ieee->state = IEEE80211_NOLINK; ++ ieee->sync_scan_hurryup = 0; ++ for(i = 0; i < 5; i++) { ++ ieee->seq_ctrl[i] = 0; ++ } ++ ++ ieee->assoc_id = 0; ++ ieee->queue_stop = 0; ++ ieee->scanning = 0; ++ ieee->softmac_features = 0; //so IEEE2100-like driver are happy ++ ieee->wap_set = 0; ++ ieee->ssid_set = 0; ++ ieee->proto_started = 0; ++ ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE; ++ ieee->rate = 3; ++//#ifdef ENABLE_LPS ++ ieee->ps = IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST; ++//#else ++// ieee->ps = IEEE80211_PS_DISABLED; ++//#endif ++ ieee->sta_sleep = 0; ++//by amy ++ ieee->bInactivePs = false; ++ ieee->actscanning = false; ++ ieee->ListenInterval = 2; ++ ieee->NumRxDataInPeriod = 0; //YJ,add,080828 ++ ieee->NumRxBcnInPeriod = 0; //YJ,add,080828 ++ ieee->NumRxOkTotal = 0;//+by amy 080312 ++ ieee->NumRxUnicast = 0;//YJ,add,080828,for keep alive ++ ieee->beinretry = false; ++ ieee->bHwRadioOff = false; ++//by amy ++#ifdef _RTL8187_EXT_PATCH_ ++ ieee->iw_ext_mode = 999; ++#endif ++ ++ init_mgmt_queue(ieee); ++#if 0 ++ init_timer(&ieee->scan_timer); ++ ieee->scan_timer.data = (unsigned long)ieee; ++ ieee->scan_timer.function = ieee80211_softmac_scan_cb; ++#endif ++ ieee->tx_pending.txb = NULL; ++ ++ init_timer(&ieee->associate_timer); ++ ieee->associate_timer.data = (unsigned long)ieee; ++ ieee->associate_timer.function = ieee80211_associate_abort_cb; ++ ++ init_timer(&ieee->beacon_timer); ++ ieee->beacon_timer.data = (unsigned long) ieee; ++ ieee->beacon_timer.function = ieee80211_send_beacon_cb; ++ ++#ifdef PF_SYNCTHREAD ++ ieee->wq = create_workqueue(DRV_NAME,0); ++#else ++ ieee->wq = create_workqueue(DRV_NAME); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)//added by lawrence,070702 ++ INIT_DELAYED_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq); ++ INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq); ++ INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq); ++ INIT_DELAYED_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq); ++ INIT_DELAYED_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq); ++ INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq); ++// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq); ++//added by lawrence,20071118 ++#ifdef _RTL8187_EXT_PATCH_ ++ INIT_WORK(&ieee->ext_stop_scan_wq,(void*) ieee80211_ext_stop_scan_wq); ++ //INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ieee80211_beacons_start,ieee); ++ INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ext_ieee80211_send_beacon_wq); ++#endif //_RTL8187_EXT_PATCH_ ++#else ++ INIT_WORK(&ieee->start_ibss_wq,(void*) ieee80211_start_ibss_wq,ieee); ++ INIT_WORK(&ieee->associate_retry_wq,(void*) ieee80211_associate_retry_wq,ieee); ++ INIT_WORK(&ieee->associate_complete_wq,(void*) ieee80211_associate_complete_wq,ieee); ++ INIT_WORK(&ieee->associate_procedure_wq,(void*) ieee80211_associate_procedure_wq,ieee); ++ INIT_WORK(&ieee->softmac_scan_wq,(void*) ieee80211_softmac_scan_wq,ieee); ++ INIT_WORK(&ieee->wx_sync_scan_wq,(void*) ieee80211_wx_sync_scan_wq,ieee); ++// INIT_WORK(&ieee->watch_dog_wq,(void*) ieee80211_watch_dog_wq,ieee); ++#ifdef _RTL8187_EXT_PATCH_ ++ INIT_WORK(&ieee->ext_stop_scan_wq,(void*) ieee80211_ext_stop_scan_wq,ieee); ++ //INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ieee80211_beacons_start,ieee); ++ INIT_WORK(&ieee->ext_send_beacon_wq,(void*) ext_ieee80211_send_beacon_wq,ieee); ++#endif ++#endif ++ sema_init(&ieee->wx_sem, 1); ++ sema_init(&ieee->scan_sem, 1); ++ ++ spin_lock_init(&ieee->mgmt_tx_lock); ++ spin_lock_init(&ieee->beacon_lock); ++ ++ tasklet_init(&ieee->ps_task, ++ (void(*)(unsigned long)) ieee80211_sta_ps, ++ (unsigned long)ieee); ++#ifdef ENABLE_DOT11D ++ ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); ++#endif ++} ++ ++void ieee80211_softmac_free(struct ieee80211_device *ieee) ++{ ++ down(&ieee->wx_sem); ++ ++ del_timer_sync(&ieee->associate_timer); ++ cancel_delayed_work(&ieee->associate_retry_wq); ++ ++ ++ //add for RF power on power of by lizhaoming 080512 ++ cancel_delayed_work(&ieee->GPIOChangeRFWorkItem); ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ cancel_delayed_work(&ieee->ext_stop_scan_wq); ++ cancel_delayed_work(&ieee->ext_send_beacon_wq); ++#endif ++ destroy_workqueue(ieee->wq); ++#ifdef ENABLE_DOT11D ++ if(NULL != ieee->pDot11dInfo) ++ kfree(ieee->pDot11dInfo); ++#endif ++ up(&ieee->wx_sem); ++} ++ ++/******************************************************** ++ * Start of WPA code. * ++ * this is stolen from the ipw2200 driver * ++ ********************************************************/ ++ ++ ++static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value) ++{ ++ /* This is called when wpa_supplicant loads and closes the driver ++ * interface. */ ++ printk("%s WPA\n",value ? "enabling" : "disabling"); ++ ieee->wpa_enabled = value; ++ return 0; ++} ++ ++ ++void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len) ++{ ++ /* make sure WPA is enabled */ ++ ieee80211_wpa_enable(ieee, 1); ++ ++ ieee80211_disassociate(ieee); ++} ++ ++ ++static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason) ++{ ++ ++ int ret = 0; ++ ++ switch (command) { ++ case IEEE_MLME_STA_DEAUTH: ++ // silently ignore ++ break; ++ ++ case IEEE_MLME_STA_DISASSOC: ++ ieee80211_disassociate(ieee); ++ break; ++ ++ default: ++ printk("Unknown MLME request: %d\n", command); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++ ++static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee, ++ struct ieee_param *param, int plen) ++{ ++ u8 *buf; ++ ++ if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || ++ (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) ++ return -EINVAL; ++ ++ if (param->u.wpa_ie.len) { ++ buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = buf; ++ ieee->wpa_ie_len = param->u.wpa_ie.len; ++ } else { ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = NULL; ++ ieee->wpa_ie_len = 0; ++ } ++ ++ ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); ++ return 0; ++} ++ ++#define AUTH_ALG_OPEN_SYSTEM 0x1 ++#define AUTH_ALG_SHARED_KEY 0x2 ++ ++static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value) ++{ ++ ++ struct ieee80211_security sec = { ++ .flags = SEC_AUTH_MODE, ++ }; ++ int ret = 0; ++ ++ if (value & AUTH_ALG_SHARED_KEY) { ++ sec.auth_mode = WLAN_AUTH_SHARED_KEY; ++ ieee->open_wep = 0; ++ } else { ++ sec.auth_mode = WLAN_AUTH_OPEN; ++ ieee->open_wep = 1; ++ } ++ ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ else ++ ret = -EOPNOTSUPP; ++ ++ return ret; ++} ++ ++static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value) ++{ ++ int ret=0; ++ unsigned long flags; ++ ++ switch (name) { ++ case IEEE_PARAM_WPA_ENABLED: ++ ret = ieee80211_wpa_enable(ieee, value); ++ break; ++ ++ case IEEE_PARAM_TKIP_COUNTERMEASURES: ++ ieee->tkip_countermeasures=value; ++ break; ++ ++ case IEEE_PARAM_DROP_UNENCRYPTED: { ++ /* HACK: ++ * ++ * wpa_supplicant calls set_wpa_enabled when the driver ++ * is loaded and unloaded, regardless of if WPA is being ++ * used. No other calls are made which can be used to ++ * determine if encryption will be used or not prior to ++ * association being expected. If encryption is not being ++ * used, drop_unencrypted is set to false, else true -- we ++ * can use this to determine if the CAP_PRIVACY_ON bit should ++ * be set. ++ */ ++ struct ieee80211_security sec = { ++ .flags = SEC_ENABLED, ++ .enabled = value, ++ }; ++ ieee->drop_unencrypted = value; ++ /* We only change SEC_LEVEL for open mode. Others ++ * are set by ipw_wpa_set_encryption. ++ */ ++ if (!value) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_0; ++ } ++ else { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ break; ++ } ++ ++ case IEEE_PARAM_PRIVACY_INVOKED: ++ ieee->privacy_invoked=value; ++ break; ++ ++ case IEEE_PARAM_AUTH_ALGS: ++ ret = ieee80211_wpa_set_auth_algs(ieee, value); ++ break; ++ ++ case IEEE_PARAM_IEEE_802_1X: ++ ieee->ieee802_1x=value; ++ break; ++ case IEEE_PARAM_WPAX_SELECT: ++ // added for WPA2 mixed mode ++ //printk(KERN_WARNING "------------------------>wpax value = %x\n", value); ++ spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); ++ ieee->wpax_type_set = 1; ++ ieee->wpax_type_notify = value; ++ spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); ++ break; ++ ++ default: ++ printk("Unknown WPA param: %d\n",name); ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++/* implementation borrowed from hostap driver */ ++ ++static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, ++ struct ieee_param *param, int param_len) ++{ ++ int ret = 0; ++ ++ struct ieee80211_crypto_ops *ops; ++ struct ieee80211_crypt_data **crypt; ++ ++ struct ieee80211_security sec = { ++ .flags = 0, ++ }; ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len != ++ (int) ((char *) param->u.crypt.key - (char *) param) + ++ param->u.crypt.key_len) { ++ printk("Len mismatch %d, %d\n", param_len, ++ param->u.crypt.key_len); ++ return -EINVAL; ++ } ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { ++ if (param->u.crypt.idx >= WEP_KEYS) ++ return -EINVAL; ++ crypt = &ieee->crypt[param->u.crypt.idx]; ++ } else { ++ return -EINVAL; ++ } ++ ++ if (strcmp(param->u.crypt.alg, "none") == 0) { ++ if (crypt) { ++ sec.enabled = 0; ++ // FIXME FIXME ++ //sec.encrypt = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_ENABLED | SEC_LEVEL; ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } ++ goto done; ++ } ++ sec.enabled = 1; ++// FIXME FIXME ++// sec.encrypt = 1; ++ sec.flags |= SEC_ENABLED; ++ ++ /* IPW HW cannot build TKIP MIC, host decryption still needed. */ ++ if (!(ieee->host_encrypt || ieee->host_decrypt) && ++ strcmp(param->u.crypt.alg, "TKIP")) ++ goto skip_host_crypt; ++ ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { ++ request_module("ieee80211_crypt_wep"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { ++ request_module("ieee80211_crypt_tkip"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { ++ request_module("ieee80211_crypt_ccmp"); ++ ops = ieee80211_get_crypto_ops(param->u.crypt.alg); ++ } ++ if (ops == NULL) { ++ printk("unknown crypto alg '%s'\n", param->u.crypt.alg); ++ param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ if (*crypt == NULL || (*crypt)->ops != ops) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ new_crypt = (struct ieee80211_crypt_data *) ++ kmalloc(sizeof(*new_crypt), GFP_KERNEL); ++ if (new_crypt == NULL) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); ++ new_crypt->ops = ops; ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++ new_crypt->priv = ++ new_crypt->ops->init(param->u.crypt.idx); ++ ++ if (new_crypt->priv == NULL) { ++ kfree(new_crypt); ++ param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ *crypt = new_crypt; ++ } ++ ++ if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && ++ (*crypt)->ops->set_key(param->u.crypt.key, ++ param->u.crypt.key_len, param->u.crypt.seq, ++ (*crypt)->priv) < 0) { ++ printk("key setting failed\n"); ++ param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ skip_host_crypt: ++ if (param->u.crypt.set_tx) { ++ ieee->tx_keyidx = param->u.crypt.idx; ++ sec.active_key = param->u.crypt.idx; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } else ++ sec.flags &= ~SEC_ACTIVE_KEY; ++ ++ if (param->u.crypt.alg != NULL) { ++ memcpy(sec.keys[param->u.crypt.idx], ++ param->u.crypt.key, ++ param->u.crypt.key_len); ++ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; ++ sec.flags |= (1 << param->u.crypt.idx); ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_2; ++ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_3; ++ } ++ } ++ done: ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ ++ /* Do not reset port if card is in Managed mode since resetting will ++ * generate new IEEE 802.11 authentication which may end up in looping ++ * with IEEE 802.1X. If your hardware requires a reset after WEP ++ * configuration (for example... Prism2), implement the reset_port in ++ * the callbacks structures used to initialize the 802.11 stack. */ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ++ ieee->reset_port(ieee->dev)) { ++ printk("reset_port failed\n"); ++ param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p) ++{ ++ struct ieee_param *param; ++ int ret=0; ++ ++ down(&ieee->wx_sem); ++ //IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); ++ ++ if (p->length < sizeof(struct ieee_param) || !p->pointer){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); ++ if (param == NULL){ ++ ret = -ENOMEM; ++ goto out; ++ } ++ if (copy_from_user(param, p->pointer, p->length)) { ++ kfree(param); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ switch (param->cmd) { ++ ++ case IEEE_CMD_SET_WPA_PARAM: ++ ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name, ++ param->u.wpa_param.value); ++ break; ++ ++ case IEEE_CMD_SET_WPA_IE: ++ ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length); ++ break; ++ ++ case IEEE_CMD_SET_ENCRYPTION: ++ ret = ieee80211_wpa_set_encryption(ieee, param, p->length); ++ break; ++ ++ case IEEE_CMD_MLME: ++ ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command, ++ param->u.mlme.reason_code); ++ break; ++ ++ default: ++ printk("Unknown WPA supplicant request: %d\n",param->cmd); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ++ ret = -EFAULT; ++ ++ kfree(param); ++out: ++ up(&ieee->wx_sem); ++ ++ return ret; ++} ++ ++void notify_wx_assoc_event(struct ieee80211_device *ieee) ++{ ++ union iwreq_data wrqu; ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ if (ieee->state == IEEE80211_LINKED) ++ memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); ++ else ++ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); ++} ++ ++ ++#if 0 ++EXPORT_SYMBOL(ieee80211_get_beacon); ++EXPORT_SYMBOL(ieee80211_wake_queue); ++EXPORT_SYMBOL(ieee80211_stop_queue); ++EXPORT_SYMBOL(ieee80211_reset_queue); ++EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); ++EXPORT_SYMBOL(ieee80211_softmac_start_protocol); ++EXPORT_SYMBOL(ieee80211_is_shortslot); ++EXPORT_SYMBOL(ieee80211_is_54g); ++EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl); ++EXPORT_SYMBOL(ieee80211_ps_tx_ack); ++EXPORT_SYMBOL(ieee80211_start_protocol); ++EXPORT_SYMBOL(ieee80211_stop_protocol); ++EXPORT_SYMBOL(notify_wx_assoc_event); ++EXPORT_SYMBOL(ieee80211_stop_send_beacons); ++EXPORT_SYMBOL(SendDisassociation); ++EXPORT_SYMBOL(ieee80211_disassociate); ++EXPORT_SYMBOL(ieee80211_start_scan); ++EXPORT_SYMBOL(ieee80211_softmac_ips_scan_syncro); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee80211_ext_issue_assoc_req); ++EXPORT_SYMBOL(ieee80211_ext_issue_disassoc); ++EXPORT_SYMBOL(ieee80211_ext_issue_assoc_rsp); ++EXPORT_SYMBOL(softmac_mgmt_xmit); ++EXPORT_SYMBOL(ieee80211_ext_probe_resp_by_net); ++EXPORT_SYMBOL(ieee80211_start_scan); ++EXPORT_SYMBOL(ieee80211_stop_scan); ++EXPORT_SYMBOL(ieee80211_ext_send_11s_beacon); ++EXPORT_SYMBOL(ieee80211_rx_auth_rq); ++EXPORT_SYMBOL(ieee80211_associate_step1); ++#endif // _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee80211_sta_ps_send_null_frame); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c +@@ -0,0 +1,602 @@ ++/* IEEE 802.11 SoftMAC layer ++ * Copyright (c) 2005 Andrea Merello ++ * ++ * Mostly extracted from the rtl8180-sa2400 driver for the ++ * in-kernel generic ieee802.11 stack. ++ * ++ * Some pieces of code might be stolen from ipw2100 driver ++ * copyright of who own it's copyright ;-) ++ * ++ * PS wx handler mostly stolen from hostap, copyright who ++ * own it's copyright ;-) ++ * ++ * released under the GPL ++ */ ++ ++ ++#include "ieee80211.h" ++ ++/* FIXME: add A freqs */ ++ ++const long ieee80211_wlan_frequencies[] = { ++ 2412, 2417, 2422, 2427, ++ 2432, 2437, 2442, 2447, ++ 2452, 2457, 2462, 2467, ++ 2472, 2484 ++}; ++ ++ ++int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct iw_freq *fwrq = & wrqu->freq; ++// printk("in %s\n",__FUNCTION__); ++ down(&ieee->wx_sem); ++ ++ if(ieee->iw_mode == IW_MODE_INFRA){ ++ ret = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ /* if setting by freq convert to channel */ ++ if (fwrq->e == 1) { ++ if ((fwrq->m >= (int) 2.412e8 && ++ fwrq->m <= (int) 2.487e8)) { ++ int f = fwrq->m / 100000; ++ int c = 0; ++ ++ while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) ++ c++; ++ ++ /* hack to fall through */ ++ fwrq->e = 0; ++ fwrq->m = c + 1; ++ } ++ } ++ ++ if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ ++ ret = -EOPNOTSUPP; ++ goto out; ++ ++ }else { /* Set the channel */ ++ ++ ++ ieee->current_network.channel = fwrq->m; ++ ieee->set_chan(ieee->dev, ieee->current_network.channel); ++ ++ if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) ++ if(ieee->state == IEEE80211_LINKED){ ++ ++ ieee80211_stop_send_beacons(ieee); ++ ieee80211_start_send_beacons(ieee); ++ } ++ } ++ ++ ret = 0; ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ ++int ieee80211_wx_get_freq(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct iw_freq *fwrq = & wrqu->freq; ++ ++ if (ieee->current_network.channel == 0) ++ return -1; ++ ++ fwrq->m = ieee->current_network.channel; ++ fwrq->e = 0; ++ ++ return 0; ++} ++ ++int ieee80211_wx_get_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ unsigned long flags; ++ ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ /* We want avoid to give to the user inconsistent infos*/ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->state != IEEE80211_LINKED && ++ ieee->state != IEEE80211_LINKED_SCANNING && ++ ieee->wap_set == 0) ++ ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ else ++ memcpy(wrqu->ap_addr.sa_data, ++ ieee->current_network.bssid, ETH_ALEN); ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ return 0; ++} ++ ++ ++int ieee80211_wx_set_wap(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ ++ int ret = 0; ++ u8 zero[] = {0,0,0,0,0,0}; ++ unsigned long flags; ++ ++ short ifup = ieee->proto_started;//dev->flags & IFF_UP; ++ struct sockaddr *temp = (struct sockaddr *)awrq; ++ ++ //printk("=======Set WAP:"); ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ /* use ifconfig hw ether */ ++ if (ieee->iw_mode == IW_MODE_MASTER){ ++ ret = -1; ++ goto out; ++ } ++ ++ if (temp->sa_family != ARPHRD_ETHER){ ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (ifup) ++ ieee80211_stop_protocol(ieee); ++ ++ /* just to avoid to give inconsistent infos in the ++ * get wx method. not really needed otherwise ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); ++ ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; ++ //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]); ++ ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ if (ifup) ++ ieee80211_start_protocol(ieee); ++ ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b) ++{ ++ int len,ret = 0; ++ unsigned long flags; ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ /* We want avoid to give to the user inconsistent infos*/ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (ieee->current_network.ssid[0] == '\0' || ++ ieee->current_network.ssid_len == 0){ ++ ret = -1; ++ goto out; ++ } ++ ++ if (ieee->state != IEEE80211_LINKED && ++ ieee->state != IEEE80211_LINKED_SCANNING && ++ ieee->ssid_set == 0){ ++ ret = -1; ++ goto out; ++ } ++ len = ieee->current_network.ssid_len; ++ wrqu->essid.length = len; ++ strncpy(b,ieee->current_network.ssid,len); ++ wrqu->essid.flags = 1; ++ ++out: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ return ret; ++ ++} ++ ++int ieee80211_wx_set_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ u32 target_rate = wrqu->bitrate.value; ++ ++ //added by lizhaoming for auto mode ++ if(target_rate == -1){ ++ ieee->rate = 110; ++ } else { ++ ieee->rate = target_rate/100000; ++ } ++ //FIXME: we might want to limit rate also in management protocols. ++ return 0; ++} ++ ++ ++ ++int ieee80211_wx_get_rate(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ wrqu->bitrate.value = ieee->rate * 100000; ++ ++ return 0; ++} ++ ++int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ ++ if (wrqu->mode == ieee->iw_mode) ++ goto out; ++ ++ if (wrqu->mode == IW_MODE_MONITOR){ ++ ++ ieee->dev->type = ARPHRD_IEEE80211; ++ }else{ ++ ieee->dev->type = ARPHRD_ETHER; ++ } ++ ++ if (!ieee->proto_started){ ++ ieee->iw_mode = wrqu->mode; ++ }else{ ++ ieee80211_stop_protocol(ieee); ++ ieee->iw_mode = wrqu->mode; ++ ieee80211_start_protocol(ieee); ++ } ++ ++out: ++ up(&ieee->wx_sem); ++ return 0; ++} ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++void ieee80211_wx_sync_scan_wq(struct work_struct *work) ++{ ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); ++#else ++void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) ++{ ++#endif ++//void ieee80211_wx_sync_scan_wq(struct ieee80211_device *ieee) ++//{ ++ short chan; ++ ++ chan = ieee->current_network.channel; ++ ++ netif_carrier_off(ieee->dev); ++ ++ if (ieee->data_hard_stop) ++ ieee->data_hard_stop(ieee->dev); ++ ++ ieee80211_stop_send_beacons(ieee); ++ ++ ieee->state = IEEE80211_LINKED_SCANNING; ++ ieee->link_change(ieee->dev); ++ ++ ieee80211_start_scan_syncro(ieee); ++ ++ ieee->set_chan(ieee->dev, chan); ++ ++ ieee->state = IEEE80211_LINKED; ++ ieee->link_change(ieee->dev); ++ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) ++ ieee80211_start_send_beacons(ieee); ++ ++ netif_carrier_on(ieee->dev); ++ ++ //YJ,add,080828, In prevent of lossing ping packet during scanning ++ //ieee80211_sta_ps_send_null_frame(ieee, false); ++ //YJ,add,080828,end ++ ++ up(&ieee->wx_sem); ++ ++} ++ ++int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret = 0; ++ ++ down(&ieee->wx_sem); ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){ ++ ret = -1; ++ goto out; ++ } ++ //YJ,add,080828 ++ //In prevent of lossing ping packet during scanning ++ //ieee80211_sta_ps_send_null_frame(ieee, true); ++ //YJ,add,080828,end ++ ++ if ( ieee->state == IEEE80211_LINKED){ ++ queue_work(ieee->wq, &ieee->wx_sync_scan_wq); ++ /* intentionally forget to up sem */ ++ return 0; ++ } ++ ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++int ieee80211_wx_set_essid(struct ieee80211_device *ieee, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int ret=0,len; ++ short proto_started; ++ unsigned long flags; ++ ++ ieee->sync_scan_hurryup = 1; ++ ++ down(&ieee->wx_sem); ++ ++ proto_started = ieee->proto_started; ++ ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE){ ++ ret= -E2BIG; ++ goto out; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_MONITOR){ ++ ret= -1; ++ goto out; ++ } ++ ++ if(proto_started) ++ ieee80211_stop_protocol(ieee); ++ ++ /* this is just to be sure that the GET wx callback ++ * has consisten infos. not needed otherwise ++ */ ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if (wrqu->essid.flags && wrqu->essid.length) { ++//YJ,modified,080819 ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE; ++#else ++ len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE; ++#endif ++ memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819 ++ strncpy(ieee->current_network.ssid, extra, len); ++ ieee->current_network.ssid_len = len; ++ ieee->ssid_set = 1; ++//YJ,modified,080819,end ++ ++ //YJ,add,080819,for hidden ap ++ if(len == 0){ ++ memset(ieee->current_network.bssid, 0, ETH_ALEN); ++ ieee->current_network.capability = 0; ++ } ++ //YJ,add,080819,for hidden ap,end ++ } ++ else{ ++ ieee->ssid_set = 0; ++ ieee->current_network.ssid[0] = '\0'; ++ ieee->current_network.ssid_len = 0; ++ } ++ //printk("==========set essid %s!\n",ieee->current_network.ssid); ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ ++ if (proto_started) ++ ieee80211_start_protocol(ieee); ++out: ++ up(&ieee->wx_sem); ++ return ret; ++} ++ ++ int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ wrqu->mode = ieee->iw_mode; ++ return 0; ++} ++ ++ int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ int *parms = (int *)extra; ++ int enable = (parms[0] > 0); ++ short prev = ieee->raw_tx; ++ ++ down(&ieee->wx_sem); ++ ++ if(enable) ++ ieee->raw_tx = 1; ++ else ++ ieee->raw_tx = 0; ++ ++ printk(KERN_INFO"raw TX is %s\n", ++ ieee->raw_tx ? "enabled" : "disabled"); ++ ++ if(ieee->iw_mode == IW_MODE_MONITOR) ++ { ++ if(prev == 0 && ieee->raw_tx){ ++ if (ieee->data_hard_resume) ++ ieee->data_hard_resume(ieee->dev); ++ ++ netif_carrier_on(ieee->dev); ++ } ++ ++ if(prev && ieee->raw_tx == 1) ++ netif_carrier_off(ieee->dev); ++ } ++ ++ up(&ieee->wx_sem); ++ ++ return 0; ++} ++ ++int ieee80211_wx_get_name(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ strcpy(wrqu->name, "802.11"); ++ if(ieee->modulation & IEEE80211_CCK_MODULATION){ ++ strcat(wrqu->name, "b"); ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(wrqu->name, "/g"); ++ }else if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(wrqu->name, "g"); ++ ++ if((ieee->state == IEEE80211_LINKED) || ++ (ieee->state == IEEE80211_LINKED_SCANNING)) ++ strcat(wrqu->name," linked"); ++ else if(ieee->state != IEEE80211_NOLINK) ++ strcat(wrqu->name," link.."); ++ ++ ++ return 0; ++} ++ ++ ++/* this is mostly stolen from hostap */ ++int ieee80211_wx_set_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++ if( ++ (!ieee->sta_wake_up) || ++ (!ieee->ps_request_tx_ack) || ++ (!ieee->enter_sleep_state) || ++ (!ieee->ps_is_queue_empty)){ ++ ++ printk("ERROR. PS mode is tryied to be use but\ ++driver missed a callback\n\n"); ++ ++ return -1; ++ } ++ ++ down(&ieee->wx_sem); ++ ++ if (wrqu->power.disabled){ ++ ieee->ps = IEEE80211_PS_DISABLED; ++ ++ goto exit; ++ } ++ switch (wrqu->power.flags & IW_POWER_MODE) { ++ case IW_POWER_UNICAST_R: ++ ieee->ps = IEEE80211_PS_UNICAST; ++ ++ break; ++ case IW_POWER_ALL_R: ++ ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; ++ break; ++ ++ case IW_POWER_ON: ++ ieee->ps = IEEE80211_PS_DISABLED; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (wrqu->power.flags & IW_POWER_TIMEOUT) { ++ ++ ieee->ps_timeout = wrqu->power.value / 1000; ++ printk("Timeout %d\n",ieee->ps_timeout); ++ } ++ ++ if (wrqu->power.flags & IW_POWER_PERIOD) { ++ ++ ret = -EOPNOTSUPP; ++ goto exit; ++ //wrq->value / 1024; ++ ++ } ++exit: ++ up(&ieee->wx_sem); ++ return ret; ++ ++} ++ ++/* this is stolen from hostap */ ++int ieee80211_wx_get_power(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret =0; ++ ++ down(&ieee->wx_sem); ++ ++ if(ieee->ps == IEEE80211_PS_DISABLED){ ++ wrqu->power.disabled = 1; ++ goto exit; ++ } ++ ++ wrqu->power.disabled = 0; ++ ++// if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { ++ wrqu->power.flags = IW_POWER_TIMEOUT; ++ wrqu->power.value = ieee->ps_timeout * 1000; ++// } else { ++// ret = -EOPNOTSUPP; ++// goto exit; ++ //wrqu->power.flags = IW_POWER_PERIOD; ++ //wrqu->power.value = ieee->current_network.dtim_period * ++ // ieee->current_network.beacon_interval * 1024; ++// } ++ ++ ++ if (ieee->ps & IEEE80211_PS_MBCAST) ++ wrqu->power.flags |= IW_POWER_ALL_R; ++ else ++ wrqu->power.flags |= IW_POWER_UNICAST_R; ++ ++exit: ++ up(&ieee->wx_sem); ++ return ret; ++ ++} ++ ++#if 0 ++EXPORT_SYMBOL(ieee80211_wx_get_essid); ++EXPORT_SYMBOL(ieee80211_wx_set_essid); ++EXPORT_SYMBOL(ieee80211_wx_set_rate); ++EXPORT_SYMBOL(ieee80211_wx_get_rate); ++EXPORT_SYMBOL(ieee80211_wx_set_wap); ++EXPORT_SYMBOL(ieee80211_wx_get_wap); ++EXPORT_SYMBOL(ieee80211_wx_set_mode); ++EXPORT_SYMBOL(ieee80211_wx_get_mode); ++EXPORT_SYMBOL(ieee80211_wx_set_scan); ++EXPORT_SYMBOL(ieee80211_wx_get_freq); ++EXPORT_SYMBOL(ieee80211_wx_set_freq); ++EXPORT_SYMBOL(ieee80211_wx_set_rawtx); ++EXPORT_SYMBOL(ieee80211_wx_get_name); ++EXPORT_SYMBOL(ieee80211_wx_set_power); ++EXPORT_SYMBOL(ieee80211_wx_get_power); ++EXPORT_SYMBOL(ieee80211_wlan_frequencies); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +@@ -0,0 +1,828 @@ ++/****************************************************************************** ++ ++ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., 59 ++ Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++****************************************************************************** ++ ++ Few modifications for Realtek's Wi-Fi drivers by ++ Andrea Merello ++ ++ A special thanks goes to Realtek for their support ! ++ ++******************************************************************************/ ++ ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++ ++ ++/* ++ ++ ++802.11 Data Frame ++ ++ ++802.11 frame_contorl for data frames - 2 bytes ++ ,-----------------------------------------------------------------------------------------. ++bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | ++ |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| ++val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | ++ |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| ++desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | ++ | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | ++ '-----------------------------------------------------------------------------------------' ++ /\ ++ | ++802.11 Data Frame | ++ ,--------- 'ctrl' expands to >-----------' ++ | ++ ,--'---,-------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `--------------------------------------------------| |------' ++Total: 28 non-data bytes `----.----' ++ | ++ .- 'Frame data' expands to <---------------------------' ++ | ++ V ++ ,---------------------------------------------------. ++Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | ++ |------|------|---------|----------|------|---------| ++Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | ++ | DSAP | SSAP | | | | Packet | ++ | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | ++ `-----------------------------------------| | ++Total: 8 non-data bytes `----.----' ++ | ++ .- 'IP Packet' expands, if WEP enabled, to <--' ++ | ++ V ++ ,-----------------------. ++Bytes | 4 | 0-2296 | 4 | ++ |-----|-----------|-----| ++Desc. | IV | Encrypted | ICV | ++ | | IP Packet | | ++ `-----------------------' ++Total: 8 non-data bytes ++ ++ ++802.3 Ethernet Data Frame ++ ++ ,-----------------------------------------. ++Bytes | 6 | 6 | 2 | Variable | 4 | ++ |-------|-------|------|-----------|------| ++Desc. | Dest. | Source| Type | IP Packet | fcs | ++ | MAC | MAC | | | | ++ `-----------------------------------------' ++Total: 18 non-data bytes ++ ++In the event that fragmentation is required, the incoming payload is split into ++N parts of size ieee->fts. The first fragment contains the SNAP header and the ++remaining packets are just data. ++ ++If encryption is enabled, each fragment payload size is reduced by enough space ++to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) ++So if you have 1500 bytes of payload with ieee->fts set to 500 without ++encryption it will take 3 frames. With WEP it will take 4 frames as the ++payload of each frame is reduced to 492 bytes. ++ ++* SKB visualization ++* ++* ,- skb->data ++* | ++* | ETHERNET HEADER ,-<-- PAYLOAD ++* | | 14 bytes from skb->data ++* | 2 bytes for Type --> ,T. | (sizeof ethhdr) ++* | | | | ++* |,-Dest.--. ,--Src.---. | | | ++* | 6 bytes| | 6 bytes | | | | ++* v | | | | | | ++* 0 | v 1 | v | v 2 ++* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ++* ^ | ^ | ^ | ++* | | | | | | ++* | | | | `T' <---- 2 bytes for Type ++* | | | | ++* | | '---SNAP--' <-------- 6 bytes for SNAP ++* | | ++* `-IV--' <-------------------- 4 bytes for IV (WEP) ++* ++* SNAP HEADER ++* ++*/ ++ ++static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; ++static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; ++ ++static inline int ieee80211_put_snap(u8 *data, u16 h_proto) ++{ ++ struct ieee80211_snap_hdr *snap; ++ u8 *oui; ++ ++ snap = (struct ieee80211_snap_hdr *)data; ++ snap->dsap = 0xaa; ++ snap->ssap = 0xaa; ++ snap->ctrl = 0x03; ++ ++ if (h_proto == 0x8137 || h_proto == 0x80f3) ++ oui = P802_1H_OUI; ++ else ++ oui = RFC1042_OUI; ++ snap->oui[0] = oui[0]; ++ snap->oui[1] = oui[1]; ++ snap->oui[2] = oui[2]; ++ ++ *(u16 *)(data + SNAP_SIZE) = htons(h_proto); ++ ++ return SNAP_SIZE + sizeof(u16); ++} ++ ++int ieee80211_encrypt_fragment( ++ struct ieee80211_device *ieee, ++ struct sk_buff *frag, ++ int hdr_len) ++{ ++ struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; ++ int res; ++ ++ /*added to care about null crypt condition, to solve that system hangs when shared keys error*/ ++ if (!crypt || !crypt->ops) ++ return -1; ++ ++#ifdef CONFIG_IEEE80211_CRYPT_TKIP ++ struct ieee80211_hdr *header; ++ ++ if (ieee->tkip_countermeasures && ++ crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { ++ header = (struct ieee80211_hdr *) frag->data; ++ if (net_ratelimit()) { ++ printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " ++ "TX packet to " MAC_FMT "\n", ++ ieee->dev->name, MAC_ARG(header->addr1)); ++ } ++ return -1; ++ } ++#endif ++ /* To encrypt, frame format is: ++ * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ ++ ++ // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. ++ /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so ++ * call both MSDU and MPDU encryption functions from here. */ ++ atomic_inc(&crypt->refcnt); ++ res = 0; ++ if (crypt->ops->encrypt_msdu) ++ res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); ++ if (res == 0 && crypt->ops->encrypt_mpdu) ++ res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); ++ ++ atomic_dec(&crypt->refcnt); ++ if (res < 0) { ++ printk(KERN_INFO "%s: Encryption failed: len=%d.\n", ++ ieee->dev->name, frag->len); ++ ieee->ieee_stats.tx_discards++; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++void ieee80211_txb_free(struct ieee80211_txb *txb) { ++ int i; ++ if (unlikely(!txb)) ++ return; ++ for (i = 0; i < txb->nr_frags; i++) ++ if (txb->fragments[i]) ++ dev_kfree_skb_any(txb->fragments[i]); ++ kfree(txb); ++} ++ ++struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, ++ int gfp_mask) ++{ ++ struct ieee80211_txb *txb; ++ int i; ++ txb = kmalloc( ++ sizeof(struct ieee80211_txb) + (sizeof(u8*) * nr_frags), ++ gfp_mask); ++ if (!txb) ++ return NULL; ++ ++ memset(txb, 0, sizeof(struct ieee80211_txb)); ++ txb->nr_frags = nr_frags; ++ txb->frag_size = txb_size; ++ ++ for (i = 0; i < nr_frags; i++) { ++ txb->fragments[i] = dev_alloc_skb(txb_size); ++ if (unlikely(!txb->fragments[i])) { ++ i--; ++ break; ++ } ++ } ++ if (unlikely(i != nr_frags)) { ++ while (i >= 0) ++ dev_kfree_skb_any(txb->fragments[i--]); ++ kfree(txb); ++ return NULL; ++ } ++ return txb; ++} ++ ++// Classify the to-be send data packet ++// Need to acquire the sent queue index. ++static int ++ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) ++{ ++ struct ether_header *eh = (struct ether_header*)skb->data; ++ unsigned int wme_UP = 0; ++ ++ if(!network->QoS_Enable) { ++ skb->priority = 0; ++ return(wme_UP); ++ } ++ ++ if(eh->ether_type == __constant_htons(ETHERTYPE_IP)) { ++ const struct iphdr *ih = (struct iphdr*)(skb->data + \ ++ sizeof(struct ether_header)); ++ wme_UP = (ih->tos >> 5)&0x07; ++ } else if (vlan_tx_tag_present(skb)) {//vtag packet ++#ifndef VLAN_PRI_SHIFT ++#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ ++#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ ++#endif ++ u32 tag = vlan_tx_tag_get(skb); ++ wme_UP = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; ++ } else if(ETH_P_PAE == ntohs(((struct ethhdr *)skb->data)->h_proto)) { ++ //printk(KERN_WARNING "type = normal packet\n"); ++ wme_UP = 7; ++ } ++ ++ skb->priority = wme_UP; ++ return(wme_UP); ++} ++ ++#ifdef _RTL8187_EXT_PATCH_ ++// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held ++struct ieee80211_txb *ieee80211_ext_alloc_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addr *frag_hdr; ++ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; ++ int ether_type; ++ int bytes, QOS_ctl; ++ struct sk_buff *skb_frag; ++ ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ /* Determine fragmentation size based on destination (multicast ++ * and broadcast are not fragmented) */ ++ // if (is_multicast_ether_addr(dest) || ++ // is_broadcast_ether_addr(dest)) { ++ if (is_multicast_ether_addr(header->addr1) || ++ is_broadcast_ether_addr(header->addr1)) { ++ frag_size = MAX_FRAG_THRESHOLD; ++ QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ //printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size); ++ frag_size = ieee->fts;//default:392 ++ QOS_ctl = 0; ++ } ++ ++ if(isQoS) { ++ QOS_ctl |= skb->priority; //set in the ieee80211_classify ++ *pQOS_ctl = cpu_to_le16(QOS_ctl); ++ } ++ //printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl); ++ /* Determine amount of payload per fragment. Regardless of if ++ * this stack is providing the full 802.11 header, one will ++ * eventually be affixed to this fragment -- so we must account for ++ * it when determining the amount of payload space. */ ++ //bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0)); ++ bytes_per_frag = frag_size - hdr_len; ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ bytes_per_frag -= IEEE80211_FCS_LEN; ++ ++ /* Each fragment may need to have room for encryptiong pre/postfix */ ++ if (isEncrypt) ++ bytes_per_frag -= crypt->ops->extra_prefix_len + ++ crypt->ops->extra_postfix_len; ++ ++ /* Number of fragments is the total bytes_per_frag / ++ * payload_per_fragment */ ++ nr_frags = bytes / bytes_per_frag; ++ bytes_last_frag = bytes % bytes_per_frag; ++ if (bytes_last_frag) ++ nr_frags++; ++ else ++ bytes_last_frag = bytes_per_frag; ++ ++ /* When we allocate the TXB we allocate enough space for the reserve ++ * and full fragment bytes (bytes_per_frag doesn't include prefix, ++ * postfix, header, FCS, etc.) */ ++ txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ return NULL; ++ } ++ txb->encrypted = isEncrypt; ++ txb->payload_size = bytes; ++ ++ for (i = 0; i < nr_frags; i++) { ++ skb_frag = txb->fragments[i]; ++ skb_frag->priority = UP2AC(skb->priority); ++ if (isEncrypt) ++ skb_reserve(skb_frag, crypt->ops->extra_prefix_len); ++ ++ frag_hdr = (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); ++ memcpy(frag_hdr, (void *)header, hdr_len); ++ ++ /* If this is not the last fragment, then add the MOREFRAGS ++ * bit to the frame control */ ++ if (i != nr_frags - 1) { ++ frag_hdr->frame_ctl = cpu_to_le16( ++ header->frame_ctl | IEEE80211_FCTL_MOREFRAGS); ++ bytes = bytes_per_frag; ++ ++ } else { ++ /* The last fragment takes the remaining length */ ++ bytes = bytes_last_frag; ++ } ++ ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); ++ //frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i); ++ // ++ ++ /* Put a SNAP header on the first fragment */ ++ if (i == 0) { ++ ieee80211_put_snap( ++ skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ether_type); ++ bytes -= SNAP_SIZE + sizeof(u16); ++ } ++ ++ memcpy(skb_put(skb_frag, bytes), skb->data, bytes); ++ ++ /* Advance the SKB... */ ++ skb_pull(skb, bytes); ++ ++ /* Encryption routine will move the header forward in order ++ * to insert the IV between the header and the payload */ ++ if (isEncrypt) ++ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ skb_put(skb_frag, 4); ++ } ++ // Advance sequence number in data frame. ++ //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ // stanley, just for debug ++/* ++{ ++ int j=0; ++ for(j=0;jfragments[j]; ++ printk("send(%d): ", j); ++ for (i=0;ilen;i++) ++ printk("%02X ", skb->data[i]&0xff); ++ printk("\n"); ++ } ++} ++*/ ++ ++ return txb; ++} ++ ++ ++// based on part of ieee80211_xmit. Mainly allocate txb. ieee->lock is held ++// Assume no encryption, no FCS computing ++struct ieee80211_txb *ieee80211_ext_reuse_txb(struct sk_buff *skb, struct net_device *dev, struct ieee80211_hdr_3addr *header, int hdr_len, u8 isQoS, u16 *pQOS_ctl, int isEncrypt, struct ieee80211_crypt_data* crypt) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) ++ struct ieee80211_device *ieee = netdev_priv(dev); ++#else ++ struct ieee80211_device *ieee = (struct ieee80211_device *)dev->priv; ++#endif ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addr *frag_hdr; ++ int ether_type; ++ int bytes, QOS_ctl; ++ ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ if (is_multicast_ether_addr(header->addr1) || ++ is_broadcast_ether_addr(header->addr1)) { ++ QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ QOS_ctl = 0; ++ } ++ ++ if(isQoS) { ++ QOS_ctl |= skb->priority; //set in the ieee80211_classify ++ *pQOS_ctl = cpu_to_le16(QOS_ctl); ++ } ++ ++ txb = kmalloc( sizeof(struct ieee80211_txb) + sizeof(u8*), GFP_ATOMIC ); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ return NULL; ++ } ++ ++ txb->nr_frags = 1; ++ txb->frag_size = bytes; ++ txb->encrypted = isEncrypt; ++ txb->payload_size = bytes; ++ ++ txb->fragments[0] = skb; ++ ieee80211_put_snap( ++ skb_push(skb, SNAP_SIZE + sizeof(u16)), ether_type); ++ frag_hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, hdr_len); ++ memcpy(frag_hdr, (void *)header, hdr_len); ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | 0); ++ skb->priority = UP2AC(skb->priority); ++ ++ // Advance sequence number in data frame. ++ //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ ++ return txb; ++} ++ ++#endif // _RTL8187_EXT_PATCH_ ++ ++/* SKBs are added to the ieee->tx_queue. */ ++int ieee80211_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct ieee80211_device *ieee = netdev_priv(dev); ++ struct ieee80211_txb *txb = NULL; ++ struct ieee80211_hdr_3addr_QOS *frag_hdr; ++ int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; ++ unsigned long flags; ++ struct net_device_stats *stats = &ieee->stats; ++ int ether_type, encrypt; ++ int bytes, fc, QOS_ctl, hdr_len; ++ struct sk_buff *skb_frag; ++ //struct ieee80211_hdr header = { /* Ensure zero initialized */ ++ // .duration_id = 0, ++ // .seq_ctl = 0 ++ //}; ++ struct ieee80211_hdr_3addr_QOS header = { /* Ensure zero initialized */ ++ .duration_id = 0, ++ .seq_ctl = 0, ++ .QOS_ctl = 0 ++ }; ++ u8 dest[ETH_ALEN], src[ETH_ALEN]; ++ ++ struct ieee80211_crypt_data* crypt; ++ ++ //printk(KERN_WARNING "upper layer packet!\n"); ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ /* If there is no driver handler to take the TXB, dont' bother ++ * creating it... */ ++ if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))|| ++ ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { ++ printk(KERN_WARNING "%s: No xmit handler.\n", ++ ieee->dev->name); ++ goto success; ++ } ++ ++ ieee80211_classify(skb,&ieee->current_network); ++ if(likely(ieee->raw_tx == 0)){ ++ ++ if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { ++ printk(KERN_WARNING "%s: skb too small (%d).\n", ++ ieee->dev->name, skb->len); ++ goto success; ++ } ++ ++ ++#ifdef _RTL8187_EXT_PATCH_ ++ // note, skb->priority which was set by ieee80211_classify, and used by physical tx ++ if((ieee->iw_mode == ieee->iw_ext_mode) && (ieee->ext_patch_ieee80211_xmit)) ++ { ++ txb = ieee->ext_patch_ieee80211_xmit(skb, dev); ++ goto success; ++ } ++#endif ++ ++ ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); ++ ++ crypt = ieee->crypt[ieee->tx_keyidx]; ++ ++ encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && ++ ieee->host_encrypt && crypt && crypt->ops; ++ ++ if (!encrypt && ieee->ieee802_1x && ++ ieee->drop_unencrypted && ether_type != ETH_P_PAE) { ++ stats->tx_dropped++; ++ goto success; ++ } ++ ++ #ifdef CONFIG_IEEE80211_DEBUG ++ if (crypt && !encrypt && ether_type == ETH_P_PAE) { ++ struct eapol *eap = (struct eapol *)(skb->data + ++ sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16)); ++ IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", ++ eap_get_type(eap->type)); ++ } ++ #endif ++ ++ /* Save source and destination addresses */ ++ memcpy(&dest, skb->data, ETH_ALEN); ++ memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ /* Advance the SKB to the start of the payload */ ++ skb_pull(skb, sizeof(struct ethhdr)); ++ ++ /* Determine total amount of storage required for TXB packets */ ++ bytes = skb->len + SNAP_SIZE + sizeof(u16); ++ ++ if(ieee->current_network.QoS_Enable) { ++ if (encrypt) ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA | ++ IEEE80211_FCTL_WEP; ++ else ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA; ++ ++ } else { ++ if (encrypt) ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | ++ IEEE80211_FCTL_WEP; ++ else ++ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; ++ } ++ ++ if (ieee->iw_mode == IW_MODE_INFRA) { ++ fc |= IEEE80211_FCTL_TODS; ++ /* To DS: Addr1 = BSSID, Addr2 = SA, ++ Addr3 = DA */ ++ memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN); ++ memcpy(&header.addr2, &src, ETH_ALEN); ++ memcpy(&header.addr3, &dest, ETH_ALEN); ++ } else if (ieee->iw_mode == IW_MODE_ADHOC) { ++ /* not From/To DS: Addr1 = DA, Addr2 = SA, ++ Addr3 = BSSID */ ++ memcpy(&header.addr1, dest, ETH_ALEN); ++ memcpy(&header.addr2, src, ETH_ALEN); ++ memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN); ++ } ++ // printk(KERN_WARNING "essid MAC address is "MAC_FMT, MAC_ARG(&header.addr1)); ++ header.frame_ctl = cpu_to_le16(fc); ++ //hdr_len = IEEE80211_3ADDR_LEN; ++ ++ /* Determine fragmentation size based on destination (multicast ++ * and broadcast are not fragmented) */ ++// if (is_multicast_ether_addr(dest) || ++// is_broadcast_ether_addr(dest)) { ++ if (is_multicast_ether_addr(header.addr1) || ++ is_broadcast_ether_addr(header.addr1)) { ++ frag_size = MAX_FRAG_THRESHOLD; ++ QOS_ctl = QOS_CTL_NOTCONTAIN_ACK; ++ } ++ else { ++ //printk(KERN_WARNING "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&frag_size = %d\n", frag_size); ++ frag_size = ieee->fts;//default:392 ++ QOS_ctl = 0; ++ } ++ ++ if (ieee->current_network.QoS_Enable) { ++ hdr_len = IEEE80211_3ADDR_LEN + 2; ++ QOS_ctl |= skb->priority; //set in the ieee80211_classify ++ header.QOS_ctl = cpu_to_le16(QOS_ctl); ++ } else { ++ hdr_len = IEEE80211_3ADDR_LEN; ++ } ++ //printk(KERN_WARNING "header size = %d, QOS_ctl = %x\n", hdr_len,QOS_ctl); ++ /* Determine amount of payload per fragment. Regardless of if ++ * this stack is providing the full 802.11 header, one will ++ * eventually be affixed to this fragment -- so we must account for ++ * it when determining the amount of payload space. */ ++ //bytes_per_frag = frag_size - (IEEE80211_3ADDR_LEN + (ieee->current_network->QoS_Enable ? 2:0)); ++ bytes_per_frag = frag_size - hdr_len; ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ bytes_per_frag -= IEEE80211_FCS_LEN; ++ ++ /* Each fragment may need to have room for encryptiong pre/postfix */ ++ if (encrypt) ++ bytes_per_frag -= crypt->ops->extra_prefix_len + ++ crypt->ops->extra_postfix_len; ++ ++ /* Number of fragments is the total bytes_per_frag / ++ * payload_per_fragment */ ++ nr_frags = bytes / bytes_per_frag; ++ bytes_last_frag = bytes % bytes_per_frag; ++ if (bytes_last_frag) ++ nr_frags++; ++ else ++ bytes_last_frag = bytes_per_frag; ++ ++ /* When we allocate the TXB we allocate enough space for the reserve ++ * and full fragment bytes (bytes_per_frag doesn't include prefix, ++ * postfix, header, FCS, etc.) */ ++ txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); ++ if (unlikely(!txb)) { ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ goto failed; ++ } ++ txb->encrypted = encrypt; ++ txb->payload_size = bytes; ++ ++ for (i = 0; i < nr_frags; i++) { ++ skb_frag = txb->fragments[i]; ++ skb_frag->priority = UP2AC(skb->priority); ++ if (encrypt) ++ skb_reserve(skb_frag, crypt->ops->extra_prefix_len); ++ ++ frag_hdr = (struct ieee80211_hdr_3addr_QOS *)skb_put(skb_frag, hdr_len); ++ memcpy(frag_hdr, &header, hdr_len); ++ ++ /* If this is not the last fragment, then add the MOREFRAGS ++ * bit to the frame control */ ++ if (i != nr_frags - 1) { ++ frag_hdr->frame_ctl = cpu_to_le16( ++ fc | IEEE80211_FCTL_MOREFRAGS); ++ bytes = bytes_per_frag; ++ ++ } else { ++ /* The last fragment takes the remaining length */ ++ bytes = bytes_last_frag; ++ } ++ if(ieee->current_network.QoS_Enable) { ++ // add 1 only indicate to corresponding seq number control 2006/7/12 ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i); ++ //printk(KERN_WARNING "skb->priority = %d,", skb->priority); ++ //printk(KERN_WARNING "type:%d: seq = %d\n",UP2AC(skb->priority),ieee->seq_ctrl[UP2AC(skb->priority)+1]); ++ } else { ++ frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4 | i); ++ } ++ //frag_hdr->seq_ctl = cpu_to_le16(ieee->seq_ctrl<<4 | i); ++ // ++ ++ /* Put a SNAP header on the first fragment */ ++ if (i == 0) { ++ ieee80211_put_snap( ++ skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), ++ ether_type); ++ bytes -= SNAP_SIZE + sizeof(u16); ++ } ++ ++ memcpy(skb_put(skb_frag, bytes), skb->data, bytes); ++ ++ /* Advance the SKB... */ ++ skb_pull(skb, bytes); ++ ++ /* Encryption routine will move the header forward in order ++ * to insert the IV between the header and the payload */ ++ if (encrypt) ++ ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); ++ if (ieee->config & ++ (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) ++ skb_put(skb_frag, 4); ++ } ++ // Advance sequence number in data frame. ++ //printk(KERN_WARNING "QoS Enalbed? %s\n", ieee->current_network.QoS_Enable?"Y":"N"); ++ if (ieee->current_network.QoS_Enable) { ++ if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) ++ ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; ++ else ++ ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; ++ } else { ++ if (ieee->seq_ctrl[0] == 0xFFF) ++ ieee->seq_ctrl[0] = 0; ++ else ++ ieee->seq_ctrl[0]++; ++ } ++ //--- ++ }else{ ++ if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) { ++ printk(KERN_WARNING "%s: skb too small (%d).\n", ++ ieee->dev->name, skb->len); ++ goto success; ++ } ++ ++ txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC); ++ if(!txb){ ++ printk(KERN_WARNING "%s: Could not allocate TXB\n", ++ ieee->dev->name); ++ goto failed; ++ } ++ ++ txb->encrypted = 0; ++ txb->payload_size = skb->len; ++ memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len); ++ } ++ ++ success: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++#ifdef _RTL8187_EXT_PATCH_ ++ // Sometimes, extension mode can reuse skb (by txb->fragments[0]) ++ if( ! ((ieee->iw_mode == ieee->iw_ext_mode) && txb && (txb->fragments[0] == skb)) ) ++#endif ++ dev_kfree_skb_any(skb); ++ if (txb) { ++ if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE){ ++ ieee80211_softmac_xmit(txb, ieee); ++ }else{ ++ if ((*ieee->hard_start_xmit)(txb, dev) == 0) { ++ stats->tx_packets++; ++ stats->tx_bytes += txb->payload_size; ++ return 0; ++ } ++ ieee80211_txb_free(txb); ++ } ++ } ++ ++ return 0; ++ ++ failed: ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ netif_stop_queue(dev); ++ stats->tx_errors++; ++ return 1; ++ ++} ++ ++#if 0 ++EXPORT_SYMBOL(ieee80211_txb_free); ++#ifdef _RTL8187_EXT_PATCH_ ++EXPORT_SYMBOL(ieee80211_alloc_txb); ++EXPORT_SYMBOL(ieee80211_ext_alloc_txb); ++EXPORT_SYMBOL(ieee80211_ext_reuse_txb); ++#endif // _RTL8187_EXT_PATCH_ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c +@@ -0,0 +1,884 @@ ++/****************************************************************************** ++ ++ Copyright(c) 2004 Intel Corporation. All rights reserved. ++ ++ Portions of this file are based on the WEP enablement code provided by the ++ Host AP project hostap-drivers v0.1.3 ++ Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen ++ ++ Copyright (c) 2002-2003, Jouni Malinen ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but WITHOUT ++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ more details. ++ ++ You should have received a copy of the GNU General Public License along with ++ this program; if not, write to the Free Software Foundation, Inc., 59 ++ Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++******************************************************************************/ ++#include ++#include ++#include ++#include ++ ++#include "ieee80211.h" ++static const char *ieee80211_modes[] = { ++ "?", "a", "b", "ab", "g", "ag", "bg", "abg" ++}; ++ ++#ifdef FEDORACORE_9 ++#define IN_FEDORACORE_9 1 ++#else ++#define IN_FEDORACORE_9 0 ++#endif ++ ++#define MAX_CUSTOM_LEN 64 ++static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee, ++ char *start, char *stop, ++ struct ieee80211_network *network, ++ struct iw_request_info *info) ++{ ++ char custom[MAX_CUSTOM_LEN]; ++ char *p; ++ struct iw_event iwe; ++ int i, j; ++ u8 max_rate, rate; ++ ++ /* First entry *MUST* be the AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); ++#endif ++ ++ /* Remaining entries will be displayed in the order we provide them */ ++ ++ /* Add the ESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ //YJ,modified,080903,for hidden ap ++ //if (network->flags & NETWORK_EMPTY_ESSID) { ++ if (network->ssid_len == 0) { ++ //YJ,modified,080903,end ++ iwe.u.data.length = sizeof(""); ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, ""); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, ""); ++#endif ++ } else { ++ iwe.u.data.length = min(network->ssid_len, (u8)32); ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, network->ssid); ++#endif ++ } ++ //printk("ESSID: %s\n",network->ssid); ++ /* Add the protocol name */ ++ iwe.cmd = SIOCGIWNAME; ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]); ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); ++#endif ++ ++ /* Add mode */ ++ iwe.cmd = SIOCGIWMODE; ++ if (network->capability & ++ (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { ++ if (network->capability & WLAN_CAPABILITY_BSS) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); ++#endif ++ } ++ ++ /* Add frequency/channel */ ++ iwe.cmd = SIOCGIWFREQ; ++/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); ++ iwe.u.freq.e = 3; */ ++ iwe.u.freq.m = network->channel; ++ iwe.u.freq.e = 0; ++ iwe.u.freq.i = 0; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); ++#endif ++ ++ /* Add encryption capability */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (network->capability & WLAN_CAPABILITY_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, network->ssid); ++#endif ++ ++ /* Add basic and extended rates */ ++ max_rate = 0; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); ++ for (i = 0, j = 0; i < network->rates_len; ) { ++ if (j < network->rates_ex_len && ++ ((network->rates_ex[j] & 0x7F) < ++ (network->rates[i] & 0x7F))) ++ rate = network->rates_ex[j++] & 0x7F; ++ else ++ rate = network->rates[i++] & 0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ } ++ for (; j < network->rates_ex_len; j++) { ++ rate = network->rates_ex[j] & 0x7F; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ if (rate > max_rate) ++ max_rate = rate; ++ } ++ ++ iwe.cmd = SIOCGIWRATE; ++ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; ++ iwe.u.bitrate.value = max_rate * 500000; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN); ++#endif ++ ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ ++ /* Add quality statistics */ ++ /* TODO: Fix these values... */ ++ if (network->stats.signal == 0 || network->stats.rssi == 0) ++ printk("========>signal:%d, rssi:%d\n", network->stats.signal, network->stats.rssi); ++ iwe.cmd = IWEVQUAL; ++// printk("SIGNAL: %d,RSSI: %d,NOISE: %d\n",network->stats.signal,network->stats.rssi,network->stats.noise); ++ iwe.u.qual.qual = network->stats.signalstrength; ++ iwe.u.qual.level = network->stats.signal; ++ iwe.u.qual.noise = network->stats.noise; ++ iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; ++ if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) ++ iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; ++ if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) ++ iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; ++ if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) ++ iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; ++ iwe.u.qual.updated = 7; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); ++#else ++ start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); ++#endif ++ ++ iwe.cmd = IWEVCUSTOM; ++ p = custom; ++ ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ ++#if 0 ++ if (ieee->wpa_enabled && network->wpa_ie_len){ ++ char buf[MAX_WPA_IE_LEN * 2 + 30]; ++ // printk("WPA IE\n"); ++ u8 *p = buf; ++ p += sprintf(p, "wpa_ie="); ++ for (i = 0; i < network->wpa_ie_len; i++) { ++ p += sprintf(p, "%02x", network->wpa_ie[i]); ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ ++ if (ieee->wpa_enabled && network->rsn_ie_len){ ++ char buf[MAX_WPA_IE_LEN * 2 + 30]; ++ ++ u8 *p = buf; ++ p += sprintf(p, "rsn_ie="); ++ for (i = 0; i < network->rsn_ie_len; i++) { ++ p += sprintf(p, "%02x", network->rsn_ie[i]); ++ } ++ ++ ++#else ++ memset(&iwe, 0, sizeof(iwe)); ++ if (network->wpa_ie_len) { ++ // printk("wpa_ie_len:%d\n", network->wpa_ie_len); ++ char buf[MAX_WPA_IE_LEN]; ++ memcpy(buf, network->wpa_ie, network->wpa_ie_len); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = network->wpa_ie_len; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ if (network->rsn_ie_len) { ++ // printk("=====>rsn_ie_len:\n", network->rsn_ie_len); ++ #if 0 ++ { ++ int i; ++ for (i=0; irsn_ie_len; i++); ++ printk("%2x ", network->rsn_ie[i]); ++ printk("\n"); ++ } ++ #endif ++ char buf[MAX_WPA_IE_LEN]; ++ memcpy(buf, network->rsn_ie, network->rsn_ie_len); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = network->rsn_ie_len; ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, buf); ++#endif ++ } ++ ++#endif ++ ++ /* Add EXTRA: Age to display seconds since last beacon/probe response ++ * for given network. */ ++ iwe.cmd = IWEVCUSTOM; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); ++ iwe.u.data.length = p - custom; ++ if (iwe.u.data.length) ++#if((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))||IN_FEDORACORE_9) ++ start = iwe_stream_add_point(info, start, stop, &iwe, custom); ++#else ++ start = iwe_stream_add_point(start, stop, &iwe, custom); ++#endif ++ ++ return start; ++} ++ ++int ieee80211_wx_get_scan(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ieee80211_network *network; ++ unsigned long flags; ++ int err = 0; ++ char *ev = extra; ++ char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA; ++ //char *stop = ev + IW_SCAN_MAX_DATA; ++ int i = 0; ++ ++ IEEE80211_DEBUG_WX("Getting scan\n"); ++ down(&ieee->wx_sem); ++ spin_lock_irqsave(&ieee->lock, flags); ++ ++ if(!ieee->bHwRadioOff) ++ { ++ list_for_each_entry(network, &ieee->network_list, list) { ++ i++; ++ ++ if((stop-ev)<200) ++ { ++ err = -E2BIG; ++ break; ++ } ++ if (ieee->scan_age == 0 || ++ time_after(network->last_scanned + ieee->scan_age, jiffies)) ++ { ++ ev = rtl818x_translate_scan(ieee, ev, stop, network, info); ++ } ++ else ++ IEEE80211_DEBUG_SCAN( ++ "Not showing network '%s (" ++ MAC_FMT ")' due to age (%lums).\n", ++ escape_essid(network->ssid, ++ network->ssid_len), ++ MAC_ARG(network->bssid), ++ (jiffies - network->last_scanned) / (HZ / 100)); ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flags); ++ up(&ieee->wx_sem); ++ wrqu->data.length = ev - extra; ++ wrqu->data.flags = 0; ++ IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); ++ ++ return err; ++} ++ ++int ieee80211_wx_set_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ struct iw_point *erq = &(wrqu->encoding); ++ struct net_device *dev = ieee->dev; ++ struct ieee80211_security sec = { ++ .flags = 0 ++ }; ++ int i, key, key_provided, len; ++ struct ieee80211_crypt_data **crypt; ++ ++ IEEE80211_DEBUG_WX("SET_ENCODE\n"); ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ key_provided = 1; ++ } else { ++ key_provided = 0; ++ key = ieee->tx_keyidx; ++ } ++ ++ IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? ++ "provided" : "default"); ++ ++ crypt = &ieee->crypt[key]; ++ ++ if (erq->flags & IW_ENCODE_DISABLED) { ++ if (key_provided && *crypt) { ++ IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", ++ key); ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } else ++ IEEE80211_DEBUG_WX("Disabling encryption.\n"); ++ ++ /* Check all the keys to see if any are still configured, ++ * and if no key index was provided, de-init them all */ ++ for (i = 0; i < WEP_KEYS; i++) { ++ if (ieee->crypt[i] != NULL) { ++ if (key_provided) ++ break; ++ ieee80211_crypt_delayed_deinit( ++ ieee, &ieee->crypt[i]); ++ } ++ } ++ ++ if (i == WEP_KEYS) { ++ sec.enabled = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_ENABLED | SEC_LEVEL; ++ } ++ ++ goto done; ++ } ++ ++ ++ ++ sec.enabled = 1; ++ sec.flags |= SEC_ENABLED; ++ ++ if (*crypt != NULL && (*crypt)->ops != NULL && ++ strcmp((*crypt)->ops->name, "WEP") != 0) { ++ /* changing to use WEP; deinit previously used algorithm ++ * on this key */ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ } ++ ++ if (*crypt == NULL) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ /* take WEP into use */ ++ new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), ++ GFP_KERNEL); ++ if (new_crypt == NULL) ++ return -ENOMEM; ++ memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); ++ new_crypt->ops = ieee80211_get_crypto_ops("WEP"); ++ if (!new_crypt->ops) { ++ request_module("ieee80211_crypt_wep"); ++ new_crypt->ops = ieee80211_get_crypto_ops("WEP"); ++ } ++ ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++ new_crypt->priv = new_crypt->ops->init(key); ++ ++ if (!new_crypt->ops || !new_crypt->priv) { ++ kfree(new_crypt); ++ new_crypt = NULL; ++ ++ printk(KERN_WARNING "%s: could not initialize WEP: " ++ "load module ieee80211_crypt_wep\n", ++ dev->name); ++ return -EOPNOTSUPP; ++ } ++ *crypt = new_crypt; ++ } ++ ++ /* If a new key was provided, set it up */ ++ if (erq->length > 0) { ++ len = erq->length <= 5 ? 5 : 13; ++ memcpy(sec.keys[key], keybuf, erq->length); ++ if (len > erq->length) ++ memset(sec.keys[key] + erq->length, 0, ++ len - erq->length); ++ IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", ++ key, escape_essid(sec.keys[key], len), ++ erq->length, len); ++ sec.key_sizes[key] = len; ++ (*crypt)->ops->set_key(sec.keys[key], len, NULL, ++ (*crypt)->priv); ++ sec.flags |= (1 << key); ++ /* This ensures a key will be activated if no key is ++ * explicitely set */ ++ if (key == sec.active_key) ++ sec.flags |= SEC_ACTIVE_KEY; ++ ieee->tx_keyidx = key;//by wb 080312 ++ } else { ++ len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, ++ NULL, (*crypt)->priv); ++ if (len == 0) { ++ /* Set a default key of all 0 */ ++ IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", ++ key); ++ memset(sec.keys[key], 0, 13); ++ (*crypt)->ops->set_key(sec.keys[key], 13, NULL, ++ (*crypt)->priv); ++ sec.key_sizes[key] = 13; ++ sec.flags |= (1 << key); ++ } ++ ++ /* No key data - just set the default TX key index */ ++ if (key_provided) { ++ IEEE80211_DEBUG_WX( ++ "Setting key %d to default Tx key.\n", key); ++ ieee->tx_keyidx = key; ++ sec.active_key = key; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } ++ } ++ ++ done: ++ ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); ++ sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; ++ sec.flags |= SEC_AUTH_MODE; ++ IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? ++ "OPEN" : "SHARED KEY"); ++ ++ /* For now we just support WEP, so only set that security level... ++ * TODO: When WPA is added this is one place that needs to change */ ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ ++ ++ if (ieee->set_security) ++ ieee->set_security(dev, &sec); ++ ++ /* Do not reset port if card is in Managed mode since resetting will ++ * generate new IEEE 802.11 authentication which may end up in looping ++ * with IEEE 802.1X. If your hardware requires a reset after WEP ++ * configuration (for example... Prism2), implement the reset_port in ++ * the callbacks structures used to initialize the 802.11 stack. */ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ieee->reset_port(dev)) { ++ printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int ieee80211_wx_get_encode(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ struct iw_point *erq = &(wrqu->encoding); ++ int len, key; ++ struct ieee80211_crypt_data *crypt; ++ ++ IEEE80211_DEBUG_WX("GET_ENCODE\n"); ++ ++ if(ieee->iw_mode == IW_MODE_MONITOR) ++ return -1; ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ } else ++ key = ieee->tx_keyidx; ++ ++ crypt = ieee->crypt[key]; ++ erq->flags = key + 1; ++ ++ if (crypt == NULL || crypt->ops == NULL) { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ return 0; ++ } ++ ++ if (strcmp(crypt->ops->name, "WEP") != 0) { ++ /* only WEP is supported with wireless extensions, so just ++ * report that encryption is used */ ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_ENABLED; ++ return 0; ++ } ++ ++ len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); ++ erq->length = (len >= 0 ? len : 0); ++ ++ erq->flags |= IW_ENCODE_ENABLED; ++ ++ if (ieee->open_wep) ++ erq->flags |= IW_ENCODE_OPEN; ++ else ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ ++ return 0; ++} ++ ++int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct net_device *dev = ieee->dev; ++ struct iw_point *encoding = &wrqu->encoding; ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ int i, idx, ret = 0; ++ int group_key = 0; ++ const char *alg, *module; ++ struct ieee80211_crypto_ops *ops; ++ struct ieee80211_crypt_data **crypt; ++ ++ struct ieee80211_security sec = { ++ .flags = 0, ++ }; ++ //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg); ++ idx = encoding->flags & IW_ENCODE_INDEX; ++ if (idx) { ++ if (idx < 1 || idx > WEP_KEYS) ++ return -EINVAL; ++ idx--; ++ } else ++ idx = ieee->tx_keyidx; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ crypt = &ieee->crypt[idx]; ++ group_key = 1; ++ } else { ++ /* some Cisco APs use idx>0 for unicast in dynamic WEP */ ++ //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg); ++ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) ++ return -EINVAL; ++ if (ieee->iw_mode == IW_MODE_INFRA) ++ crypt = &ieee->crypt[idx]; ++ else ++ return -EINVAL; ++ } ++ ++ sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT; ++ if ((encoding->flags & IW_ENCODE_DISABLED) || ++ ext->alg == IW_ENCODE_ALG_NONE) { ++ if (*crypt) ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ for (i = 0; i < WEP_KEYS; i++) ++ if (ieee->crypt[i] != NULL) ++ break; ++ ++ if (i == WEP_KEYS) { ++ sec.enabled = 0; ++ // sec.encrypt = 0; ++ sec.level = SEC_LEVEL_0; ++ sec.flags |= SEC_LEVEL; ++ } ++ //printk("disabled: flag:%x\n", encoding->flags); ++ goto done; ++ } ++ ++ sec.enabled = 1; ++ // sec.encrypt = 1; ++#if 0 ++ if (group_key ? !ieee->host_mc_decrypt : ++ !(ieee->host_encrypt || ieee->host_decrypt || ++ ieee->host_encrypt_msdu)) ++ goto skip_host_crypt; ++#endif ++ switch (ext->alg) { ++ case IW_ENCODE_ALG_WEP: ++ alg = "WEP"; ++ module = "ieee80211_crypt_wep"; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ alg = "TKIP"; ++ module = "ieee80211_crypt_tkip"; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ alg = "CCMP"; ++ module = "ieee80211_crypt_ccmp"; ++ break; ++ default: ++ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", ++ dev->name, ext->alg); ++ ret = -EINVAL; ++ goto done; ++ } ++// printk("8-09-08-9=====>%s, alg name:%s\n",__FUNCTION__, alg); ++ ++ ops = ieee80211_get_crypto_ops(alg); ++ if (ops == NULL) { ++ request_module(module); ++ ops = ieee80211_get_crypto_ops(alg); ++ } ++ if (ops == NULL) { ++ IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", ++ dev->name, ext->alg); ++ printk("========>unknown crypto alg %d\n", ext->alg); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ if (*crypt == NULL || (*crypt)->ops != ops) { ++ struct ieee80211_crypt_data *new_crypt; ++ ++ ieee80211_crypt_delayed_deinit(ieee, crypt); ++ ++ new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); ++ if (new_crypt == NULL) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ new_crypt->ops = ops; ++ if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) ++ new_crypt->priv = new_crypt->ops->init(idx); ++ if (new_crypt->priv == NULL) { ++ kfree(new_crypt); ++ ret = -EINVAL; ++ goto done; ++ } ++ *crypt = new_crypt; ++ ++ } ++ ++ if (ext->key_len > 0 && (*crypt)->ops->set_key && ++ (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, ++ (*crypt)->priv) < 0) { ++ IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); ++ printk("key setting failed\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++#if 1 ++ //skip_host_crypt: ++ //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { ++ ieee->tx_keyidx = idx; ++ sec.active_key = idx; ++ sec.flags |= SEC_ACTIVE_KEY; ++ } ++ ++ if (ext->alg != IW_ENCODE_ALG_NONE) { ++ memcpy(sec.keys[idx], ext->key, ext->key_len); ++ sec.key_sizes[idx] = ext->key_len; ++ sec.flags |= (1 << idx); ++ if (ext->alg == IW_ENCODE_ALG_WEP) { ++ // sec.encode_alg[idx] = SEC_ALG_WEP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_1; ++ } else if (ext->alg == IW_ENCODE_ALG_TKIP) { ++ // sec.encode_alg[idx] = SEC_ALG_TKIP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_2; ++ } else if (ext->alg == IW_ENCODE_ALG_CCMP) { ++ // sec.encode_alg[idx] = SEC_ALG_CCMP; ++ sec.flags |= SEC_LEVEL; ++ sec.level = SEC_LEVEL_3; ++ } ++ /* Don't set sec level for group keys. */ ++ if (group_key) ++ sec.flags &= ~SEC_LEVEL; ++ } ++#endif ++done: ++ if (ieee->set_security) ++ ieee->set_security(ieee->dev, &sec); ++ ++ if (ieee->reset_on_keychange && ++ ieee->iw_mode != IW_MODE_INFRA && ++ ieee->reset_port && ieee->reset_port(dev)) { ++ IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_mlme *mlme = (struct iw_mlme *) extra; ++// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __FUNCTION__, mlme->cmd); ++#if 1 ++ switch (mlme->cmd) { ++ case IW_MLME_DEAUTH: ++ case IW_MLME_DISASSOC: ++ // printk("disassoc now\n"); ++ ieee80211_disassociate(ieee); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++#endif ++ return 0; ++} ++ ++int ieee80211_wx_set_auth(struct ieee80211_device *ieee, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra) ++{ ++/* ++ struct ieee80211_security sec = { ++ .flags = SEC_AUTH_MODE, ++ } ++*/ ++ //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value); ++ switch (data->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ /*need to support wpa2 here*/ ++ //printk("wpa version:%x\n", data->value); ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ case IW_AUTH_CIPHER_GROUP: ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * * Host AP driver does not use these parameters and allows ++ * * wpa_supplicant to control them internally. ++ * */ ++ break; ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ ieee->tkip_countermeasures = data->value; ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ ieee->drop_unencrypted = data->value; ++ break; ++ ++ case IW_AUTH_80211_AUTH_ALG: ++ ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0; ++ //printk("open_wep:%d\n", ieee->open_wep); ++ break; ++ ++#if 1 ++ case IW_AUTH_WPA_ENABLED: ++ ieee->wpa_enabled = (data->value)?1:0; ++ //printk("enalbe wpa:%d\n", ieee->wpa_enabled); ++ break; ++ ++#endif ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ ieee->ieee802_1x = data->value; ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ ieee->privacy_invoked = data->value; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++#if 1 ++int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) ++{ ++#if 0 ++ printk("====>%s()\n", __FUNCTION__); ++ { ++ int i; ++ for (i=0; iMAX_WPA_IE_LEN || (len && ie == NULL)) ++ { ++ printk("return error out, len:%d\n", len); ++ return -EINVAL; ++ } ++ ++ if (len) ++ { ++ if (len != ie[1]+2){ ++ printk("len:%d, ie:%d\n", len, ie[1]); ++ return -EINVAL; ++ } ++ buf = kmalloc(len, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ memcpy(buf, ie, len); ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = buf; ++ ieee->wpa_ie_len = len; ++ } ++ else{ ++ if (ieee->wpa_ie) ++ kfree(ieee->wpa_ie); ++ ieee->wpa_ie = NULL; ++ ieee->wpa_ie_len = 0; ++ } ++// printk("<=====out %s()\n", __FUNCTION__); ++ ++ return 0; ++ ++} ++#endif ++ ++#if 0 ++EXPORT_SYMBOL(ieee80211_wx_set_gen_ie); ++EXPORT_SYMBOL(ieee80211_wx_set_mlme); ++EXPORT_SYMBOL(ieee80211_wx_set_auth); ++EXPORT_SYMBOL(ieee80211_wx_set_encode_ext); ++EXPORT_SYMBOL(ieee80211_wx_get_scan); ++EXPORT_SYMBOL(ieee80211_wx_set_encode); ++EXPORT_SYMBOL(ieee80211_wx_get_encode); ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/internal.h +@@ -0,0 +1,115 @@ ++/* ++ * Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris ++ * ++ * 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. ++ * ++ */ ++#ifndef _CRYPTO_INTERNAL_H ++#define _CRYPTO_INTERNAL_H ++ ++ ++//#include ++#include "rtl_crypto.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)) ++#define list_for_each_entry(pos, head, member) \ ++ for (pos = list_entry((head)->next, typeof(*pos), member), \ ++ prefetch(pos->member.next); \ ++ &pos->member != (head); \ ++ pos = list_entry(pos->member.next, typeof(*pos), member), \ ++ prefetch(pos->member.next)) ++ ++static inline void cond_resched(void) ++{ ++ if (need_resched()) { ++ set_current_state(TASK_RUNNING); ++ schedule(); ++ } ++} ++#endif ++ ++extern enum km_type crypto_km_types[]; ++ ++static inline enum km_type crypto_kmap_type(int out) ++{ ++ return crypto_km_types[(in_softirq() ? 2 : 0) + out]; ++} ++ ++static inline void *crypto_kmap(struct page *page, int out) ++{ ++ return kmap_atomic(page, crypto_kmap_type(out)); ++} ++ ++static inline void crypto_kunmap(void *vaddr, int out) ++{ ++ kunmap_atomic(vaddr, crypto_kmap_type(out)); ++} ++ ++static inline void crypto_yield(struct crypto_tfm *tfm) ++{ ++ if (!in_softirq()) ++ cond_resched(); ++} ++ ++static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) ++{ ++ return (void *)&tfm[1]; ++} ++ ++struct crypto_alg *crypto_alg_lookup(const char *name); ++ ++#ifdef CONFIG_KMOD ++void crypto_alg_autoload(const char *name); ++struct crypto_alg *crypto_alg_mod_lookup(const char *name); ++#else ++static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) ++{ ++ return crypto_alg_lookup(name); ++} ++#endif ++ ++#ifdef CONFIG_CRYPTO_HMAC ++int crypto_alloc_hmac_block(struct crypto_tfm *tfm); ++void crypto_free_hmac_block(struct crypto_tfm *tfm); ++#else ++static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm) ++{ ++ return 0; ++} ++ ++static inline void crypto_free_hmac_block(struct crypto_tfm *tfm) ++{ } ++#endif ++ ++#ifdef CONFIG_PROC_FS ++void __init crypto_init_proc(void); ++#else ++static inline void crypto_init_proc(void) ++{ } ++#endif ++ ++int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); ++int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); ++int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); ++ ++int crypto_init_digest_ops(struct crypto_tfm *tfm); ++int crypto_init_cipher_ops(struct crypto_tfm *tfm); ++int crypto_init_compress_ops(struct crypto_tfm *tfm); ++ ++void crypto_exit_digest_ops(struct crypto_tfm *tfm); ++void crypto_exit_cipher_ops(struct crypto_tfm *tfm); ++void crypto_exit_compress_ops(struct crypto_tfm *tfm); ++ ++#endif /* _CRYPTO_INTERNAL_H */ ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/ieee80211/rtl_crypto.h +@@ -0,0 +1,399 @@ ++/* ++ * Scatterlist Cryptographic API. ++ * ++ * Copyright (c) 2002 James Morris ++ * Copyright (c) 2002 David S. Miller (davem@redhat.com) ++ * ++ * Portions derived from Cryptoapi, by Alexander Kjeldaas ++ * and Nettle, by Niels M鰈ler. ++ * ++ * 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. ++ * ++ */ ++#ifndef _LINUX_CRYPTO_H ++#define _LINUX_CRYPTO_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define crypto_register_alg crypto_register_alg_rtl ++#define crypto_unregister_alg crypto_unregister_alg_rtl ++#define crypto_alloc_tfm crypto_alloc_tfm_rtl ++#define crypto_free_tfm crypto_free_tfm_rtl ++#define crypto_alg_available crypto_alg_available_rtl ++ ++/* ++ * Algorithm masks and types. ++ */ ++#define CRYPTO_ALG_TYPE_MASK 0x000000ff ++#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 ++#define CRYPTO_ALG_TYPE_DIGEST 0x00000002 ++#define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 ++ ++/* ++ * Transform masks and values (for crt_flags). ++ */ ++#define CRYPTO_TFM_MODE_MASK 0x000000ff ++#define CRYPTO_TFM_REQ_MASK 0x000fff00 ++#define CRYPTO_TFM_RES_MASK 0xfff00000 ++ ++#define CRYPTO_TFM_MODE_ECB 0x00000001 ++#define CRYPTO_TFM_MODE_CBC 0x00000002 ++#define CRYPTO_TFM_MODE_CFB 0x00000004 ++#define CRYPTO_TFM_MODE_CTR 0x00000008 ++ ++#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 ++#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 ++#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 ++#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 ++#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 ++#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 ++ ++/* ++ * Miscellaneous stuff. ++ */ ++#define CRYPTO_UNSPEC 0 ++#define CRYPTO_MAX_ALG_NAME 64 ++ ++struct scatterlist; ++ ++/* ++ * Algorithms: modular crypto algorithm implementations, managed ++ * via crypto_register_alg() and crypto_unregister_alg(). ++ */ ++struct cipher_alg { ++ unsigned int cia_min_keysize; ++ unsigned int cia_max_keysize; ++ int (*cia_setkey)(void *ctx, const u8 *key, ++ unsigned int keylen, u32 *flags); ++ void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src); ++ void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src); ++}; ++ ++struct digest_alg { ++ unsigned int dia_digestsize; ++ void (*dia_init)(void *ctx); ++ void (*dia_update)(void *ctx, const u8 *data, unsigned int len); ++ void (*dia_final)(void *ctx, u8 *out); ++ int (*dia_setkey)(void *ctx, const u8 *key, ++ unsigned int keylen, u32 *flags); ++}; ++ ++struct compress_alg { ++ int (*coa_init)(void *ctx); ++ void (*coa_exit)(void *ctx); ++ int (*coa_compress)(void *ctx, const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++ int (*coa_decompress)(void *ctx, const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++}; ++ ++#define cra_cipher cra_u.cipher ++#define cra_digest cra_u.digest ++#define cra_compress cra_u.compress ++ ++struct crypto_alg { ++ struct list_head cra_list; ++ u32 cra_flags; ++ unsigned int cra_blocksize; ++ unsigned int cra_ctxsize; ++ const char cra_name[CRYPTO_MAX_ALG_NAME]; ++ ++ union { ++ struct cipher_alg cipher; ++ struct digest_alg digest; ++ struct compress_alg compress; ++ } cra_u; ++ ++ struct module *cra_module; ++}; ++ ++/* ++ * Algorithm registration interface. ++ */ ++int crypto_register_alg(struct crypto_alg *alg); ++int crypto_unregister_alg(struct crypto_alg *alg); ++ ++/* ++ * Algorithm query interface. ++ */ ++int crypto_alg_available(const char *name, u32 flags); ++ ++/* ++ * Transforms: user-instantiated objects which encapsulate algorithms ++ * and core processing logic. Managed via crypto_alloc_tfm() and ++ * crypto_free_tfm(), as well as the various helpers below. ++ */ ++struct crypto_tfm; ++ ++struct cipher_tfm { ++ void *cit_iv; ++ unsigned int cit_ivsize; ++ u32 cit_mode; ++ int (*cit_setkey)(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen); ++ int (*cit_encrypt)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes); ++ int (*cit_encrypt_iv)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv); ++ int (*cit_decrypt)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes); ++ int (*cit_decrypt_iv)(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv); ++ void (*cit_xor_block)(u8 *dst, const u8 *src); ++}; ++ ++struct digest_tfm { ++ void (*dit_init)(struct crypto_tfm *tfm); ++ void (*dit_update)(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg); ++ void (*dit_final)(struct crypto_tfm *tfm, u8 *out); ++ void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, ++ unsigned int nsg, u8 *out); ++ int (*dit_setkey)(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen); ++#ifdef CONFIG_CRYPTO_HMAC ++ void *dit_hmac_block; ++#endif ++}; ++ ++struct compress_tfm { ++ int (*cot_compress)(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++ int (*cot_decompress)(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen); ++}; ++ ++#define crt_cipher crt_u.cipher ++#define crt_digest crt_u.digest ++#define crt_compress crt_u.compress ++ ++struct crypto_tfm { ++ ++ u32 crt_flags; ++ ++ union { ++ struct cipher_tfm cipher; ++ struct digest_tfm digest; ++ struct compress_tfm compress; ++ } crt_u; ++ ++ struct crypto_alg *__crt_alg; ++}; ++ ++/* ++ * Transform user interface. ++ */ ++ ++/* ++ * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm. ++ * If that fails and the kernel supports dynamically loadable modules, it ++ * will then attempt to load a module of the same name or alias. A refcount ++ * is grabbed on the algorithm which is then associated with the new transform. ++ * ++ * crypto_free_tfm() frees up the transform and any associated resources, ++ * then drops the refcount on the associated algorithm. ++ */ ++struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags); ++void crypto_free_tfm(struct crypto_tfm *tfm); ++ ++/* ++ * Transform helpers which query the underlying algorithm. ++ */ ++static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_name; ++} ++ ++static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ ++ if (alg->cra_module) ++ return alg->cra_module->name; ++ else ++ return NULL; ++} ++ ++static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; ++} ++ ++static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->__crt_alg->cra_cipher.cia_min_keysize; ++} ++ ++static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->__crt_alg->cra_cipher.cia_max_keysize; ++} ++ ++static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_ivsize; ++} ++ ++static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) ++{ ++ return tfm->__crt_alg->cra_blocksize; ++} ++ ++static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ return tfm->__crt_alg->cra_digest.dia_digestsize; ++} ++ ++/* ++ * API wrappers. ++ */ ++static inline void crypto_digest_init(struct crypto_tfm *tfm) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_init(tfm); ++} ++ ++static inline void crypto_digest_update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, ++ unsigned int nsg) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_update(tfm, sg, nsg); ++} ++ ++static inline void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_final(tfm, out); ++} ++ ++static inline void crypto_digest_digest(struct crypto_tfm *tfm, ++ struct scatterlist *sg, ++ unsigned int nsg, u8 *out) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ tfm->crt_digest.dit_digest(tfm, sg, nsg, out); ++} ++ ++static inline int crypto_digest_setkey(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); ++ if (tfm->crt_digest.dit_setkey == NULL) ++ return -ENOSYS; ++ return tfm->crt_digest.dit_setkey(tfm, key, keylen); ++} ++ ++static inline int crypto_cipher_setkey(struct crypto_tfm *tfm, ++ const u8 *key, unsigned int keylen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_setkey(tfm, key, keylen); ++} ++ ++static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); ++} ++ ++static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); ++ return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); ++} ++ ++static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); ++} ++ ++static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, ++ struct scatterlist *dst, ++ struct scatterlist *src, ++ unsigned int nbytes, u8 *iv) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB); ++ return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); ++} ++ ++static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int len) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ memcpy(tfm->crt_cipher.cit_iv, src, len); ++} ++ ++static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, ++ u8 *dst, unsigned int len) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); ++ memcpy(dst, tfm->crt_cipher.cit_iv, len); ++} ++ ++static inline int crypto_comp_compress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); ++ return tfm->crt_compress.cot_compress(tfm, src, slen, dst, dlen); ++} ++ ++static inline int crypto_comp_decompress(struct crypto_tfm *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen) ++{ ++ BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_COMPRESS); ++ return tfm->crt_compress.cot_decompress(tfm, src, slen, dst, dlen); ++} ++ ++/* ++ * HMAC support. ++ */ ++#ifdef CONFIG_CRYPTO_HMAC ++void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen); ++void crypto_hmac_update(struct crypto_tfm *tfm, ++ struct scatterlist *sg, unsigned int nsg); ++void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ++ unsigned int *keylen, u8 *out); ++void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen, ++ struct scatterlist *sg, unsigned int nsg, u8 *out); ++#endif /* CONFIG_CRYPTO_HMAC */ ++ ++#endif /* _LINUX_CRYPTO_H */ ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/Kconfig +@@ -0,0 +1,5 @@ ++config RTL8187SE ++ tristate "RealTek RTL8187SE Wireless LAN NIC driver" ++ depends on PCI ++ default N ++ ---help--- +--- /dev/null ++++ b/drivers/staging/rtl8187se/Makefile +@@ -0,0 +1,55 @@ ++ ++#EXTRA_CFLAGS += -DCONFIG_IEEE80211_NOWEP=y ++#EXTRA_CFLAGS += -DCONFIG_RTL8180_IOMAP ++#EXTRA_CFLAGS += -std=gnu89 ++#EXTRA_CFLAGS += -O2 ++#CC = gcc ++EXTRA_CFLAGS += -DTHOMAS_TURBO ++#CFLAGS += -DCONFIG_RTL8185B ++#CFLAGS += -DCONFIG_RTL818x_S ++ ++#added for EeePC testing ++EXTRA_CFLAGS += -DENABLE_IPS ++EXTRA_CFLAGS += -DSW_ANTE ++EXTRA_CFLAGS += -DTX_TRACK ++EXTRA_CFLAGS += -DHIGH_POWER ++EXTRA_CFLAGS += -DSW_DIG ++EXTRA_CFLAGS += -DRATE_ADAPT ++EXTRA_CFLAGS += -DCONFIG_RTL8180_PM ++ ++#+YJ,080626 ++EXTRA_CFLAGS += -DENABLE_DOT11D ++ ++#enable it for legacy power save, disable it for leisure power save ++EXTRA_CFLAGS += -DENABLE_LPS ++ ++ ++#EXTRA_CFLAGS += -mhard-float -DCONFIG_FORCE_HARD_FLOAT=y ++ ++rtl8187se-objs := \ ++ r8180_core.o \ ++ r8180_sa2400.o \ ++ r8180_93cx6.o \ ++ r8180_wx.o \ ++ r8180_max2820.o \ ++ r8180_gct.o \ ++ r8180_rtl8225.o \ ++ r8180_rtl8255.o \ ++ r8180_rtl8225z2.o \ ++ r8185b_init.o \ ++ r8180_dm.o \ ++ r8180_pm.o \ ++ ieee80211/dot11d.o \ ++ ieee80211/ieee80211_softmac.o \ ++ ieee80211/ieee80211_rx.o \ ++ ieee80211/ieee80211_tx.o \ ++ ieee80211/ieee80211_wx.o \ ++ ieee80211/ieee80211_module.o \ ++ ieee80211/ieee80211_softmac_wx.o \ ++ ieee80211/ieee80211_crypt.o \ ++ ieee80211/ieee80211_crypt_tkip.o \ ++ ieee80211/ieee80211_crypt_ccmp.o \ ++ ieee80211/ieee80211_crypt_wep.o ++ ++obj-$(CONFIG_RTL8187SE) += rtl8187se.o ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_93cx6.c +@@ -0,0 +1,146 @@ ++/* ++ This files contains card eeprom (93c46 or 93c56) programming routines, ++ memory is addressed by 16 bits words. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#include "r8180_93cx6.h" ++ ++void eprom_cs(struct net_device *dev, short bit) ++{ ++ if(bit) ++ write_nic_byte(dev, EPROM_CMD, ++ (1<epromtype==EPROM_93c56){ ++ addr_str[7]=addr & 1; ++ addr_str[6]=addr & (1<<1); ++ addr_str[5]=addr & (1<<2); ++ addr_str[4]=addr & (1<<3); ++ addr_str[3]=addr & (1<<4); ++ addr_str[2]=addr & (1<<5); ++ addr_str[1]=addr & (1<<6); ++ addr_str[0]=addr & (1<<7); ++ addr_len=8; ++ }else{ ++ addr_str[5]=addr & 1; ++ addr_str[4]=addr & (1<<1); ++ addr_str[3]=addr & (1<<2); ++ addr_str[2]=addr & (1<<3); ++ addr_str[1]=addr & (1<<4); ++ addr_str[0]=addr & (1<<5); ++ addr_len=6; ++ } ++ eprom_cs(dev, 1); ++ eprom_ck_cycle(dev); ++ eprom_send_bits_string(dev, read_cmd, 3); ++ eprom_send_bits_string(dev, addr_str, addr_len); ++ ++ //keep chip pin D to low state while reading. ++ //I'm unsure if it is necessary, but anyway shouldn't hurt ++ eprom_w(dev, 0); ++ ++ for(i=0;i<16;i++){ ++ //eeprom needs a clk cycle between writing opcode&adr ++ //and reading data. (eeprom outs a dummy 0) ++ eprom_ck_cycle(dev); ++ ret |= (eprom_r(dev)<<(15-i)); ++ } ++ ++ eprom_cs(dev, 0); ++ eprom_ck_cycle(dev); ++ ++ //disable EPROM programming ++ write_nic_byte(dev, EPROM_CMD, ++ (EPROM_CMD_NORMAL< ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++/*This files contains card eeprom (93c46 or 93c56) programming routines*/ ++/*memory is addressed by WORDS*/ ++ ++#include "r8180.h" ++#include "r8180_hw.h" ++ ++#define EPROM_DELAY 10 ++ ++#define EPROM_ANAPARAM_ADDRLWORD 0xd ++#define EPROM_ANAPARAM_ADDRHWORD 0xe ++ ++#define RFCHIPID 0x6 ++#define RFCHIPID_INTERSIL 1 ++#define RFCHIPID_RFMD 2 ++#define RFCHIPID_PHILIPS 3 ++#define RFCHIPID_MAXIM 4 ++#define RFCHIPID_GCT 5 ++#define RFCHIPID_RTL8225 9 ++#ifdef CONFIG_RTL8185B ++#define RF_ZEBRA2 11 ++#define EPROM_TXPW_BASE 0x05 ++#define RF_ZEBRA4 12 ++#endif ++#define RFCHIPID_RTL8255 0xa ++#define RF_PARAM 0x19 ++#define RF_PARAM_DIGPHY_SHIFT 0 ++#define RF_PARAM_ANTBDEFAULT_SHIFT 1 ++#define RF_PARAM_CARRIERSENSE_SHIFT 2 ++#define RF_PARAM_CARRIERSENSE_MASK (3<<2) ++#define ENERGY_TRESHOLD 0x17 ++#define EPROM_VERSION 0x1E ++#define MAC_ADR 0x7 ++ ++#define CIS 0x18 ++ ++#define EPROM_TXPW_OFDM_CH1_2 0x20 ++ ++//#define EPROM_TXPW_CH1_2 0x10 ++#define EPROM_TXPW_CH1_2 0x30 ++#define EPROM_TXPW_CH3_4 0x11 ++#define EPROM_TXPW_CH5_6 0x12 ++#define EPROM_TXPW_CH7_8 0x13 ++#define EPROM_TXPW_CH9_10 0x14 ++#define EPROM_TXPW_CH11_12 0x15 ++#define EPROM_TXPW_CH13_14 0x16 ++ ++u32 eprom_read(struct net_device *dev,u32 addr); //reads a 16 bits word +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_core.c +@@ -0,0 +1,6828 @@ ++/* ++ This is part of rtl818x pci OpenSource driver - v 0.1 ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public License) ++ ++ Parts of this driver are based on the GPL part of the official ++ Realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ Parts of BB/RF code are derived from David Young rtl8180 netbsd driver. ++ ++ RSSI calc function from 'The Deuce' ++ ++ Some ideas borrowed from the 8139too.c driver included in linux kernel. ++ ++ We (I?) want to thanks the Authors of those projecs and also the ++ Ndiswrapper's project Authors. ++ ++ A big big thanks goes also to Realtek corp. for their help in my attempt to ++ add RTL8185 and RTL8225 support, and to David Young also. ++*/ ++ ++#if 0 ++double __floatsidf (int i) { return i; } ++unsigned int __fixunsdfsi (double d) { return d; } ++double __adddf3(double a, double b) { return a+b; } ++double __addsf3(float a, float b) { return a+b; } ++double __subdf3(double a, double b) { return a-b; } ++double __extendsfdf2(float a) {return a;} ++#endif ++ ++ ++#undef DEBUG_TX_DESC2 ++#undef RX_DONT_PASS_UL ++#undef DEBUG_EPROM ++#undef DEBUG_RX_VERBOSE ++#undef DUMMY_RX ++#undef DEBUG_ZERO_RX ++#undef DEBUG_RX_SKB ++#undef DEBUG_TX_FRAG ++#undef DEBUG_RX_FRAG ++#undef DEBUG_TX_FILLDESC ++#undef DEBUG_TX ++#undef DEBUG_IRQ ++#undef DEBUG_RX ++#undef DEBUG_RXALLOC ++#undef DEBUG_REGISTERS ++#undef DEBUG_RING ++#undef DEBUG_IRQ_TASKLET ++#undef DEBUG_TX_ALLOC ++#undef DEBUG_TX_DESC ++ ++//#define DEBUG_TX ++//#define DEBUG_TX_DESC2 ++//#define DEBUG_RX ++//#define DEBUG_RX_SKB ++ ++//#define CONFIG_RTL8180_IO_MAP ++#include ++//#include ++//#include ++#include "r8180_hw.h" ++#include "r8180.h" ++#include "r8180_sa2400.h" /* PHILIPS Radio frontend */ ++#include "r8180_max2820.h" /* MAXIM Radio frontend */ ++#include "r8180_gct.h" /* GCT Radio frontend */ ++#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ ++#include "r8180_rtl8255.h" /* RTL8255 Radio frontend */ ++#include "r8180_93cx6.h" /* Card EEPROM */ ++#include "r8180_wx.h" ++#include "r8180_dm.h" ++ ++#ifdef CONFIG_RTL8180_PM ++#include "r8180_pm.h" ++#endif ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++#ifdef CONFIG_RTL8185B ++//#define CONFIG_RTL8180_IO_MAP ++#endif ++ ++#ifndef PCI_VENDOR_ID_BELKIN ++ #define PCI_VENDOR_ID_BELKIN 0x1799 ++#endif ++#ifndef PCI_VENDOR_ID_DLINK ++ #define PCI_VENDOR_ID_DLINK 0x1186 ++#endif ++ ++static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = { ++ { ++ .vendor = PCI_VENDOR_ID_REALTEK, ++// .device = 0x8180, ++ .device = 0x8199, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = 0, ++ }, ++#if 0 ++ { ++ .vendor = PCI_VENDOR_ID_BELKIN, ++ .device = 0x6001, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = 1, ++ }, ++ { /* Belkin F5D6020 v3 */ ++ .vendor = PCI_VENDOR_ID_BELKIN, ++ .device = 0x6020, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = 2, ++ }, ++ { /* D-Link DWL-610 */ ++ .vendor = PCI_VENDOR_ID_DLINK, ++ .device = 0x3300, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = 3, ++ }, ++ { ++ .vendor = PCI_VENDOR_ID_REALTEK, ++ .device = 0x8185, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .driver_data = 4, ++ }, ++#endif ++ { ++ .vendor = 0, ++ .device = 0, ++ .subvendor = 0, ++ .subdevice = 0, ++ .driver_data = 0, ++ } ++}; ++ ++ ++static char* ifname = "wlan%d"; ++static int hwseqnum = 0; ++//static char* ifname = "ath%d"; ++static int hwwep = 0; ++static int channels = 0x3fff; ++ ++#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 ) ++#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5]) ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl); ++MODULE_AUTHOR("Andrea Merello "); ++MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards"); ++ ++ ++ ++/* ++MODULE_PARM(ifname, "s"); ++MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); ++ ++MODULE_PARM(hwseqnum,"i"); ++MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); ++ ++MODULE_PARM(hwwep,"i"); ++MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); ++ ++MODULE_PARM(channels,"i"); ++MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); ++*/ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) ++module_param(ifname, charp, S_IRUGO|S_IWUSR ); ++module_param(hwseqnum,int, S_IRUGO|S_IWUSR); ++module_param(hwwep,int, S_IRUGO|S_IWUSR); ++module_param(channels,int, S_IRUGO|S_IWUSR); ++#else ++MODULE_PARM(ifname, "s"); ++MODULE_PARM(hwseqnum,"i"); ++MODULE_PARM(hwwep,"i"); ++MODULE_PARM(channels,"i"); ++#endif ++ ++MODULE_PARM_DESC(devname," Net interface name, wlan%d=default"); ++//MODULE_PARM_DESC(devname," Net interface name, ath%d=default"); ++MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default"); ++MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards"); ++MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI"); ++ ++ ++static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id); ++ ++static void __devexit rtl8180_pci_remove(struct pci_dev *pdev); ++ ++static void rtl8180_shutdown (struct pci_dev *pdev) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++ dev->stop(dev); ++ pci_disable_device(pdev); ++} ++ ++static struct pci_driver rtl8180_pci_driver = { ++ .name = RTL8180_MODULE_NAME, /* Driver name */ ++ .id_table = rtl8180_pci_id_tbl, /* PCI_ID table */ ++ .probe = rtl8180_pci_probe, /* probe fn */ ++ .remove = __devexit_p(rtl8180_pci_remove),/* remove fn */ ++#ifdef CONFIG_RTL8180_PM ++ .suspend = rtl8180_suspend, /* PM suspend fn */ ++ .resume = rtl8180_resume, /* PM resume fn */ ++#else ++ .suspend = NULL, /* PM suspend fn */ ++ .resume = NULL, /* PM resume fn */ ++#endif ++ .shutdown = rtl8180_shutdown, ++}; ++ ++ ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ ++u8 read_nic_byte(struct net_device *dev, int x) ++{ ++ return 0xff&inb(dev->base_addr +x); ++} ++ ++u32 read_nic_dword(struct net_device *dev, int x) ++{ ++ return inl(dev->base_addr +x); ++} ++ ++u16 read_nic_word(struct net_device *dev, int x) ++{ ++ return inw(dev->base_addr +x); ++} ++ ++void write_nic_byte(struct net_device *dev, int x,u8 y) ++{ ++ outb(y&0xff,dev->base_addr +x); ++} ++ ++void write_nic_word(struct net_device *dev, int x,u16 y) ++{ ++ outw(y,dev->base_addr +x); ++} ++ ++void write_nic_dword(struct net_device *dev, int x,u32 y) ++{ ++ outl(y,dev->base_addr +x); ++} ++ ++#else /* RTL_IO_MAP */ ++ ++u8 read_nic_byte(struct net_device *dev, int x) ++{ ++ return 0xff&readb((u8*)dev->mem_start +x); ++} ++ ++u32 read_nic_dword(struct net_device *dev, int x) ++{ ++ return readl((u8*)dev->mem_start +x); ++} ++ ++u16 read_nic_word(struct net_device *dev, int x) ++{ ++ return readw((u8*)dev->mem_start +x); ++} ++ ++void write_nic_byte(struct net_device *dev, int x,u8 y) ++{ ++ writeb(y,(u8*)dev->mem_start +x); ++ udelay(20); ++} ++ ++void write_nic_dword(struct net_device *dev, int x,u32 y) ++{ ++ writel(y,(u8*)dev->mem_start +x); ++ udelay(20); ++} ++ ++void write_nic_word(struct net_device *dev, int x,u16 y) ++{ ++ writew(y,(u8*)dev->mem_start +x); ++ udelay(20); ++} ++ ++#endif /* RTL_IO_MAP */ ++ ++ ++ ++ ++ ++inline void force_pci_posting(struct net_device *dev) ++{ ++ read_nic_byte(dev,EPROM_CMD); ++#ifndef CONFIG_RTL8180_IO_MAP ++ mb(); ++#endif ++} ++ ++ ++irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs); ++void set_nic_rxring(struct net_device *dev); ++void set_nic_txring(struct net_device *dev); ++static struct net_device_stats *rtl8180_stats(struct net_device *dev); ++void rtl8180_commit(struct net_device *dev); ++void rtl8180_start_tx_beacon(struct net_device *dev); ++ ++/**************************************************************************** ++ -----------------------------PROCFS STUFF------------------------- ++*****************************************************************************/ ++ ++static struct proc_dir_entry *rtl8180_proc = NULL; ++ ++static int proc_get_registers(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++// struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ int i,n; ++ ++ int max=0xff; ++ ++ /* This dump the current register page */ ++ for(n=0;n<=max;) ++ { ++ //printk( "\nD: %2x> ", n); ++ len += snprintf(page + len, count - len, ++ "\nD: %2x > ",n); ++ ++ for(i=0;i<16 && n<=max;i++,n++) ++ len += snprintf(page + len, count - len, ++ "%2x ",read_nic_byte(dev,n)); ++ ++ // printk("%2x ",read_nic_byte(dev,n)); ++ } ++ len += snprintf(page + len, count - len,"\n"); ++ ++ ++ ++ *eof = 1; ++ return len; ++ ++} ++ ++int get_curr_tx_free_desc(struct net_device *dev, int priority); ++ ++static int proc_get_stats_hw(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ //struct net_device *dev = data; ++ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++#ifdef CONFIG_RTL8185B ++ ++#else ++ len += snprintf(page + len, count - len, ++ "NIC int: %lu\n" ++ "Total int: %lu\n" ++ "--------------------\n" ++ "LP avail desc %d\n" ++ "NP avail desc %d\n" ++ "--------------------\n" ++ "LP phys dma addr %x\n" ++ "LP NIC ptr %x\n" ++ "LP virt 32base %x\n" ++ "LP virt 32tail %x\n" ++ "--------------------\n" ++ "NP phys dma addr %x\n" ++ "NP NIC ptr %x\n" ++ "NP virt 32base %x\n" ++ "NP virt 32tail %x\n" ++ "--------------------\n" ++ "BP phys dma addr %x\n" ++ "BP NIC ptr %x\n" ++ "BP virt 32base %x\n" ++ "BP virt 32tail %x\n", ++ priv->stats.ints, ++ priv->stats.shints, ++ get_curr_tx_free_desc(dev,LOW_PRIORITY), ++ get_curr_tx_free_desc(dev,NORM_PRIORITY), ++ (u32)priv->txvipringdma, ++ read_nic_dword(dev,TLPDA), ++ (u32)priv->txvipring, ++ (u32)priv->txvipringtail, ++ (u32)priv->txvopringdma, ++ read_nic_dword(dev,TNPDA), ++ (u32)priv->txvopring, ++ (u32)priv->txvopringtail, ++ (u32)priv->txbeaconringdma, ++ read_nic_dword(dev,TBDA), ++ (u32)priv->txbeaconring, ++ (u32)priv->txbeaconringtail); ++#endif ++ *eof = 1; ++ return len; ++} ++ ++ ++static int proc_get_stats_rx(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ /* "RX descriptor not available: %lu\n" ++ "RX incomplete (missing last descriptor): %lu\n" ++ "RX not data: %lu\n" ++ //"RX descriptor pointer reset: %lu\n" ++ "RX descriptor pointer lost: %lu\n" ++ //"RX pointer workaround: %lu\n" ++ "RX error int: %lu\n" ++ "RX fifo overflow: %lu\n" ++ "RX int: %lu\n" ++ "RX packet: %lu\n" ++ "RX bytes: %lu\n" ++ "RX DMA fail: %lu\n", ++ priv->stats.rxrdu, ++ priv->stats.rxnolast, ++ priv->stats.rxnodata, ++ //priv->stats.rxreset, ++ priv->stats.rxnopointer, ++ //priv->stats.rxwrkaround, ++ priv->stats.rxerr, ++ priv->stats.rxoverflow, ++ priv->stats.rxint, ++ priv->ieee80211->stats.rx_packets, ++ priv->ieee80211->stats.rx_bytes, ++ priv->stats.rxdmafail */ ++ "RX OK: %lu\n" ++ "RX Retry: %lu\n" ++ "RX CRC Error(0-500): %lu\n" ++ "RX CRC Error(500-1000): %lu\n" ++ "RX CRC Error(>1000): %lu\n" ++ "RX ICV Error: %lu\n", ++ priv->stats.rxint, ++ priv->stats.rxerr, ++ priv->stats.rxcrcerrmin, ++ priv->stats.rxcrcerrmid, ++ priv->stats.rxcrcerrmax, ++ priv->stats.rxicverr ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++#if 0 ++static int proc_get_stats_ieee(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, ++ "TXed association requests: %u\n" ++ "TXed authentication requests: %u\n" ++ "RXed successful association response: %u\n" ++ "RXed failed association response: %u\n" ++ "RXed successful authentication response: %u\n" ++ "RXed failed authentication response: %u\n" ++ "Association requests without response: %u\n" ++ "Authentication requests without response: %u\n" ++ "TX probe response: %u\n" ++ "RX probe request: %u\n" ++ "TX probe request: %lu\n" ++ "RX authentication requests: %lu\n" ++ "RX association requests: %lu\n" ++ "Reassociations: %lu\n", ++ priv->ieee80211->ieee_stats.tx_ass, ++ priv->ieee80211->ieee_stats.tx_aut, ++ priv->ieee80211->ieee_stats.rx_ass_ok, ++ priv->ieee80211->ieee_stats.rx_ass_err, ++ priv->ieee80211->ieee_stats.rx_aut_ok, ++ priv->ieee80211->ieee_stats.rx_aut_err, ++ priv->ieee80211->ieee_stats.ass_noresp, ++ priv->ieee80211->ieee_stats.aut_noresp, ++ priv->ieee80211->ieee_stats.tx_probe, ++ priv->ieee80211->ieee_stats.rx_probe, ++ priv->ieee80211->ieee_stats.tx_probe_rq, ++ priv->ieee80211->ieee_stats.rx_auth_rq, ++ priv->ieee80211->ieee_stats.rx_assoc_rq, ++ priv->ieee80211->ieee_stats.reassoc); ++ ++ *eof = 1; ++ return len; ++} ++#endif ++#if 0 ++static int proc_get_stats_ap(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct mac_htable_t *list; ++ int i; ++ int len = 0; ++ ++ if(priv->ieee80211->iw_mode != IW_MODE_MASTER){ ++ len += snprintf(page + len, count - len, ++ "Card is not acting as AP...\n" ++ ); ++ }else{ ++ len += snprintf(page + len, count - len, ++ "List of associated STA:\n" ++ ); ++ ++ for(i=0;iieee80211->assoc_htable[i]; list!=NULL; list = list->next){ ++ len += snprintf(page + len, count - len, ++ MACSTR"\n",MAC2STR(list->adr)); ++ } ++ ++ } ++ *eof = 1; ++ return len; ++} ++#endif ++ ++static int proc_get_stats_tx(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ int len = 0; ++ unsigned long totalOK; ++ ++ totalOK=priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint; ++ len += snprintf(page + len, count - len, ++ /* "TX normal priority ok int: %lu\n" ++ "TX normal priority error int: %lu\n" ++ "TX high priority ok int: %lu\n" ++ "TX high priority failed error int: %lu\n" ++ "TX low priority ok int: %lu\n" ++ "TX low priority failed error int: %lu\n" ++ "TX bytes: %lu\n" ++ "TX packets: %lu\n" ++ "TX queue resume: %lu\n" ++ "TX queue stopped?: %d\n" ++ "TX fifo overflow: %lu\n" ++ //"SW TX stop: %lu\n" ++ //"SW TX wake: %lu\n" ++ "TX beacon: %lu\n" ++ "TX beacon aborted: %lu\n", ++ priv->stats.txnpokint, ++ priv->stats.txnperr, ++ priv->stats.txhpokint, ++ priv->stats.txhperr, ++ priv->stats.txlpokint, ++ priv->stats.txlperr, ++ priv->ieee80211->stats.tx_bytes, ++ priv->ieee80211->stats.tx_packets, ++ priv->stats.txresumed, ++ netif_queue_stopped(dev), ++ priv->stats.txoverflow, ++ //priv->ieee80211->ieee_stats.swtxstop, ++ //priv->ieee80211->ieee_stats.swtxawake, ++ priv->stats.txbeacon, ++ priv->stats.txbeaconerr */ ++ "TX OK: %lu\n" ++ "TX Error: %lu\n" ++ "TX Retry: %lu\n" ++ "TX beacon OK: %lu\n" ++ "TX beacon error: %lu\n", ++ totalOK, ++ priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr, ++ priv->stats.txretry, ++ priv->stats.txbeacon, ++ priv->stats.txbeaconerr ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++#if WIRELESS_EXT < 17 ++static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return &priv->wstats; ++} ++#endif ++void rtl8180_proc_module_init(void) ++{ ++ DMESG("Initializing proc filesystem"); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, proc_net); ++#else ++ rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, init_net.proc_net); ++#endif ++} ++ ++ ++void rtl8180_proc_module_remove(void) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ remove_proc_entry(RTL8180_MODULE_NAME, proc_net); ++#else ++ remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net); ++#endif ++} ++ ++ ++void rtl8180_proc_remove_one(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ if (priv->dir_dev) { ++ remove_proc_entry("stats-hw", priv->dir_dev); ++ remove_proc_entry("stats-tx", priv->dir_dev); ++ remove_proc_entry("stats-rx", priv->dir_dev); ++// remove_proc_entry("stats-ieee", priv->dir_dev); ++// remove_proc_entry("stats-ap", priv->dir_dev); ++ remove_proc_entry("registers", priv->dir_dev); ++ remove_proc_entry(dev->name, rtl8180_proc); ++ priv->dir_dev = NULL; ++ } ++} ++ ++ ++void rtl8180_proc_init_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *e; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->dir_dev = create_proc_entry(dev->name, ++ S_IFDIR | S_IRUGO | S_IXUGO, ++ rtl8180_proc); ++ if (!priv->dir_dev) { ++ DMESGE("Unable to initialize /proc/net/rtl8180/%s\n", ++ dev->name); ++ return; ++ } ++ ++ e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_hw, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8180/%s/stats-hw\n", ++ dev->name); ++ } ++ ++ e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_rx, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8180/%s/stats-rx\n", ++ dev->name); ++ } ++ ++ ++ e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_tx, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8180/%s/stats-tx\n", ++ dev->name); ++ } ++ #if 0 ++ e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_ieee, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8180/%s/stats-ieee\n", ++ dev->name); ++ } ++ #endif ++ #if 0 ++ e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_stats_ap, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8180/%s/stats-ap\n", ++ dev->name); ++ } ++ #endif ++ ++ e = create_proc_read_entry("registers", S_IFREG | S_IRUGO, ++ priv->dir_dev, proc_get_registers, dev); ++ ++ if (!e) { ++ DMESGE("Unable to initialize " ++ "/proc/net/rtl8180/%s/registers\n", ++ dev->name); ++ } ++} ++/**************************************************************************** ++ -----------------------------MISC STUFF------------------------- ++*****************************************************************************/ ++/* ++ FIXME: check if we can use some standard already-existent ++ data type+functions in kernel ++*/ ++ ++short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma, ++ struct buffer **bufferhead) ++{ ++#ifdef DEBUG_RING ++ DMESG("adding buffer to TX/RX struct"); ++#endif ++ ++ struct buffer *tmp; ++ ++ if(! *buffer){ ++ ++ *buffer = kmalloc(sizeof(struct buffer),GFP_KERNEL); ++ ++ if (*buffer == NULL) { ++ DMESGE("Failed to kmalloc head of TX/RX struct"); ++ return -1; ++ } ++ (*buffer)->next=*buffer; ++ (*buffer)->buf=buf; ++ (*buffer)->dma=dma; ++ if(bufferhead !=NULL) ++ (*bufferhead) = (*buffer); ++ return 0; ++ } ++ tmp=*buffer; ++ ++ while(tmp->next!=(*buffer)) tmp=tmp->next; ++ if ((tmp->next= kmalloc(sizeof(struct buffer),GFP_KERNEL)) == NULL){ ++ DMESGE("Failed to kmalloc TX/RX struct"); ++ return -1; ++ } ++ tmp->next->buf=buf; ++ tmp->next->dma=dma; ++ tmp->next->next=*buffer; ++ ++ return 0; ++} ++ ++ ++void buffer_free(struct net_device *dev,struct buffer **buffer,int len,short ++consistent) ++{ ++ ++ struct buffer *tmp,*next; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct pci_dev *pdev=priv->pdev; ++ //int i; ++ ++ if(! *buffer) return; ++ ++ /*for(tmp=*buffer; tmp->next != *buffer; tmp=tmp->next) ++ ++ */ ++ tmp=*buffer; ++ do{ ++ next=tmp->next; ++ if(consistent){ ++ pci_free_consistent(pdev,len, ++ tmp->buf,tmp->dma); ++ }else{ ++ pci_unmap_single(pdev, tmp->dma, ++ len,PCI_DMA_FROMDEVICE); ++ kfree(tmp->buf); ++ } ++ kfree(tmp); ++ tmp = next; ++ } ++ while(next != *buffer); ++ ++ *buffer=NULL; ++} ++ ++ ++void print_buffer(u32 *buffer, int len) ++{ ++ int i; ++ u8 *buf =(u8*)buffer; ++ ++ printk("ASCII BUFFER DUMP (len: %x):\n",len); ++ ++ for(i=0;itxmapringhead; ++ tail = priv->txmapringtail; ++ break; ++ case BK_PRIORITY: ++ head = priv->txbkpringhead; ++ tail = priv->txbkpringtail; ++ break; ++ case BE_PRIORITY: ++ head = priv->txbepringhead; ++ tail = priv->txbepringtail; ++ break; ++ case VI_PRIORITY: ++ head = priv->txvipringhead; ++ tail = priv->txvipringtail; ++ break; ++ case VO_PRIORITY: ++ head = priv->txvopringhead; ++ tail = priv->txvopringtail; ++ break; ++ case HI_PRIORITY: ++ head = priv->txhpringhead; ++ tail = priv->txhpringtail; ++ break; ++ default: ++ return -1; ++ } ++ ++ //DMESG("%x %x", head, tail); ++ ++ /* FIXME FIXME FIXME FIXME */ ++ ++#if 0 ++ if( head <= tail ) return priv->txringcount-1 - (tail - head)/8; ++ return (head - tail)/8/4; ++#else ++ if( head <= tail ) ++ ret = priv->txringcount - (tail - head)/8; ++ else ++ ret = (head - tail)/8; ++ ++ if(ret > priv->txringcount ) DMESG("BUG"); ++ return ret; ++#endif ++} ++ ++ ++short check_nic_enought_desc(struct net_device *dev, int priority) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = netdev_priv(dev); ++ ++ int requiredbyte, required; ++ requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data); ++ ++ if(ieee->current_network.QoS_Enable) { ++ requiredbyte += 2; ++ }; ++ ++ required = requiredbyte / (priv->txbuffsize-4); ++ if (requiredbyte % priv->txbuffsize) required++; ++ /* for now we keep two free descriptor as a safety boundary ++ * between the tail and the head ++ */ ++ ++ return (required+2 < get_curr_tx_free_desc(dev,priority)); ++} ++ ++ ++/* This function is only for debuging purpose */ ++void check_tx_ring(struct net_device *dev, int pri) ++{ ++ static int maxlog =3; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32* tmp; ++ struct buffer *buf; ++ int i; ++ int nic; ++ u32* tail; ++ u32* head; ++ u32* begin; ++ u32 nicbegin; ++ struct buffer* buffer; ++ ++ maxlog --; ++ if (maxlog <0 ) return; ++ ++ switch(pri) { ++ case MANAGE_PRIORITY: ++ tail = priv->txmapringtail; ++ begin = priv->txmapring; ++ head = priv->txmapringhead; ++ nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR); ++ buffer = priv->txmapbufs; ++ nicbegin = priv->txmapringdma; ++ break; ++ ++ ++ case BK_PRIORITY: ++ tail = priv->txbkpringtail; ++ begin = priv->txbkpring; ++ head = priv->txbkpringhead; ++ nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR); ++ buffer = priv->txbkpbufs; ++ nicbegin = priv->txbkpringdma; ++ break; ++ ++ case BE_PRIORITY: ++ tail = priv->txbepringtail; ++ begin = priv->txbepring; ++ head = priv->txbepringhead; ++ nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR); ++ buffer = priv->txbepbufs; ++ nicbegin = priv->txbepringdma; ++ break; ++ ++ case VI_PRIORITY: ++ tail = priv->txvipringtail; ++ begin = priv->txvipring; ++ head = priv->txvipringhead; ++ nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR); ++ buffer = priv->txvipbufs; ++ nicbegin = priv->txvipringdma; ++ break; ++ ++ ++ case VO_PRIORITY: ++ tail = priv->txvopringtail; ++ begin = priv->txvopring; ++ head = priv->txvopringhead; ++ nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR); ++ buffer = priv->txvopbufs; ++ nicbegin = priv->txvopringdma; ++ break; ++ ++ case HI_PRIORITY: ++ tail = priv->txhpringtail; ++ begin = priv->txhpring; ++ head = priv->txhpringhead; ++ nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR); ++ buffer = priv->txhpbufs; ++ nicbegin = priv->txhpringdma; ++ break; ++ ++ default: ++ return ; ++ break; ++ } ++ ++ if(!priv->txvopbufs) ++ DMESGE ("NIC TX ack, but TX queue corrupted!"); ++ else{ ++ ++ for(i=0,buf=buffer, tmp=begin; ++ tmptxringcount)*8; ++ tmp+=8,buf=buf->next,i++) ++ ++ DMESG("BUF%d %s %x %s. Next : %x",i, ++ *tmp & (1<<31) ? "filled" : "empty", ++ *(buf->buf), ++ *tmp & (1<<15)? "ok": "err", *(tmp+4)); ++ } ++ ++ DMESG("nic at %d", ++ (nic-nicbegin) / 8 /4); ++ DMESG("tail at %d", ((int)tail - (int)begin) /8 /4); ++ DMESG("head at %d", ((int)head - (int)begin) /8 /4); ++ DMESG("check free desc returns %d", check_nic_enought_desc(dev,pri)); ++ DMESG("free desc is %d\n", get_curr_tx_free_desc(dev,pri)); ++ //rtl8180_reset(dev); ++ return; ++} ++ ++ ++ ++/* this function is only for debugging purpose */ ++void check_rxbuf(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32* tmp; ++ struct buffer *buf; ++ u8 rx_desc_size; ++ ++#ifdef CONFIG_RTL8185B ++ rx_desc_size = 8; ++#else ++ rx_desc_size = 4; ++#endif ++ ++ if(!priv->rxbuffer) ++ DMESGE ("NIC RX ack, but RX queue corrupted!"); ++ ++ else{ ++ ++ for(buf=priv->rxbuffer, tmp=priv->rxring; ++ tmp < priv->rxring+(priv->rxringcount)*rx_desc_size; ++ tmp+=rx_desc_size, buf=buf->next) ++ ++ DMESG("BUF %s %x", ++ *tmp & (1<<31) ? "empty" : "filled", ++ *(buf->buf)); ++ } ++ ++ return; ++} ++ ++ ++void dump_eprom(struct net_device *dev) ++{ ++ int i; ++ for(i=0; i<63; i++) ++ DMESG("EEPROM addr %x : %x", i, eprom_read(dev,i)); ++} ++ ++ ++void rtl8180_dump_reg(struct net_device *dev) ++{ ++ int i; ++ int n; ++ int max=0xff; ++ ++ DMESG("Dumping NIC register map"); ++ ++ for(n=0;n<=max;) ++ { ++ printk( "\nD: %2x> ", n); ++ for(i=0;i<16 && n<=max;i++,n++) ++ printk("%2x ",read_nic_byte(dev,n)); ++ } ++ printk("\n"); ++} ++ ++ ++void fix_tx_fifo(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 *tmp; ++ int i; ++#ifdef DEBUG_TX_ALLOC ++ DMESG("FIXING TX FIFOs"); ++#endif ++ for (tmp=priv->txmapring, i=0; ++ i < priv->txringcount; ++ tmp+=8, i++){ ++ *tmp = *tmp &~ (1<<31); ++ } ++ ++ for (tmp=priv->txbkpring, i=0; ++ i < priv->txringcount; ++ tmp+=8, i++) { ++ *tmp = *tmp &~ (1<<31); ++ } ++ ++ for (tmp=priv->txbepring, i=0; ++ i < priv->txringcount; ++ tmp+=8, i++){ ++ *tmp = *tmp &~ (1<<31); ++ } ++ for (tmp=priv->txvipring, i=0; ++ i < priv->txringcount; ++ tmp+=8, i++) { ++ *tmp = *tmp &~ (1<<31); ++ } ++ ++ for (tmp=priv->txvopring, i=0; ++ i < priv->txringcount; ++ tmp+=8, i++){ ++ *tmp = *tmp &~ (1<<31); ++ } ++ ++ for (tmp=priv->txhpring, i=0; ++ i < priv->txringcount; ++ tmp+=8,i++){ ++ *tmp = *tmp &~ (1<<31); ++ } ++ ++ for (tmp=priv->txbeaconring, i=0; ++ i < priv->txbeaconcount; ++ tmp+=8, i++){ ++ *tmp = *tmp &~ (1<<31); ++ } ++#ifdef DEBUG_TX_ALLOC ++ DMESG("TX FIFOs FIXED"); ++#endif ++ priv->txmapringtail = priv->txmapring; ++ priv->txmapringhead = priv->txmapring; ++ priv->txmapbufstail = priv->txmapbufs; ++ ++ priv->txbkpringtail = priv->txbkpring; ++ priv->txbkpringhead = priv->txbkpring; ++ priv->txbkpbufstail = priv->txbkpbufs; ++ ++ priv->txbepringtail = priv->txbepring; ++ priv->txbepringhead = priv->txbepring; ++ priv->txbepbufstail = priv->txbepbufs; ++ ++ priv->txvipringtail = priv->txvipring; ++ priv->txvipringhead = priv->txvipring; ++ priv->txvipbufstail = priv->txvipbufs; ++ ++ priv->txvopringtail = priv->txvopring; ++ priv->txvopringhead = priv->txvopring; ++ priv->txvopbufstail = priv->txvopbufs; ++ ++ priv->txhpringtail = priv->txhpring; ++ priv->txhpringhead = priv->txhpring; ++ priv->txhpbufstail = priv->txhpbufs; ++ ++ priv->txbeaconringtail = priv->txbeaconring; ++ priv->txbeaconbufstail = priv->txbeaconbufs; ++ set_nic_txring(dev); ++ ++ ieee80211_reset_queue(priv->ieee80211); ++ priv->ack_tx_to_ieee = 0; ++} ++ ++ ++void fix_rx_fifo(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 *tmp; ++ struct buffer *rxbuf; ++ u8 rx_desc_size; ++ ++#ifdef CONFIG_RTL8185B ++ rx_desc_size = 8; // 4*8 = 32 bytes ++#else ++ rx_desc_size = 4; ++#endif ++ ++#ifdef DEBUG_RXALLOC ++ DMESG("FIXING RX FIFO"); ++ check_rxbuf(dev); ++#endif ++ ++ for (tmp=priv->rxring, rxbuf=priv->rxbufferhead; ++ (tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size); ++ tmp+=rx_desc_size,rxbuf=rxbuf->next){ ++ *(tmp+2) = rxbuf->dma; ++ *tmp=*tmp &~ 0xfff; ++ *tmp=*tmp | priv->rxbuffersize; ++ *tmp |= (1<<31); ++ } ++ ++#ifdef DEBUG_RXALLOC ++ DMESG("RX FIFO FIXED"); ++ check_rxbuf(dev); ++#endif ++ ++ priv->rxringtail=priv->rxring; ++ priv->rxbuffer=priv->rxbufferhead; ++ priv->rx_skb_complete=1; ++ set_nic_rxring(dev); ++} ++ ++ ++/**************************************************************************** ++ ------------------------------HW STUFF--------------------------- ++*****************************************************************************/ ++ ++unsigned char QUALITY_MAP[] = { ++ 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61, ++ 0x61, 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5d, 0x5c, ++ 0x5b, 0x5a, 0x59, 0x57, 0x56, 0x54, 0x52, 0x4f, ++ 0x4c, 0x49, 0x45, 0x41, 0x3c, 0x37, 0x31, 0x29, ++ 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, ++ 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e, ++ 0x1d, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x19, ++ 0x18, 0x17, 0x16, 0x15, 0x14, 0x12, 0x11, 0x0f, ++ 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x01, 0x00 ++}; ++ ++unsigned char STRENGTH_MAP[] = { ++ 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, ++ 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50, ++ 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f, ++ 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b, ++ 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, ++ 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13, ++ 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f, ++ 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, ++ 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07, ++ 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x00 ++}; ++ ++void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual){ ++ //void Mlme_UpdateRssiSQ(struct net_device *dev, u8 *rssi, u8 *qual){ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 temp; ++ u32 temp2; ++ u32 temp3; ++ u32 lsb; ++ u32 q; ++ u32 orig_qual; ++ u8 _rssi; ++ ++ q = *qual; ++ orig_qual = *qual; ++ _rssi = 0; // avoid gcc complains.. ++ ++ if (q <= 0x4e) { ++ temp = QUALITY_MAP[q]; ++ } else { ++ if( q & 0x80 ) { ++ temp = 0x32; ++ } else { ++ temp = 1; ++ } ++ } ++ ++ *qual = temp; ++ temp2 = *rssi; ++ ++ switch(priv->rf_chip){ ++ case RFCHIPID_RFMD: ++ lsb = temp2 & 1; ++ temp2 &= 0x7e; ++ if ( !lsb || !(temp2 <= 0x3c) ) { ++ temp2 = 0x64; ++ } else { ++ temp2 = 100 * temp2 / 0x3c; ++ } ++ *rssi = temp2 & 0xff; ++ _rssi = temp2 & 0xff; ++ break; ++ case RFCHIPID_INTERSIL: ++ lsb = temp2; ++ temp2 &= 0xfffffffe; ++ temp2 *= 251; ++ temp3 = temp2; ++ temp2 <<= 6; ++ temp3 += temp2; ++ temp3 <<= 1; ++ temp2 = 0x4950df; ++ temp2 -= temp3; ++ lsb &= 1; ++ if ( temp2 <= 0x3e0000 ) { ++ if ( temp2 < 0xffef0000 ) ++ temp2 = 0xffef0000; ++ } else { ++ temp2 = 0x3e0000; ++ } ++ if ( !lsb ) { ++ temp2 -= 0xf0000; ++ } else { ++ temp2 += 0xf0000; ++ } ++ ++ temp3 = 0x4d0000; ++ temp3 -= temp2; ++ temp3 *= 100; ++ temp3 = temp3 / 0x6d; ++ temp3 >>= 0x10; ++ _rssi = temp3 & 0xff; ++ *rssi = temp3 & 0xff; ++ break; ++ case RFCHIPID_GCT: ++ lsb = temp2 & 1; ++ temp2 &= 0x7e; ++ if ( ! lsb || !(temp2 <= 0x3c) ){ ++ temp2 = 0x64; ++ } else { ++ temp2 = (100 * temp2) / 0x3c; ++ } ++ *rssi = temp2 & 0xff; ++ _rssi = temp2 & 0xff; ++ break; ++ case RFCHIPID_PHILIPS: ++ if( orig_qual <= 0x4e ){ ++ _rssi = STRENGTH_MAP[orig_qual]; ++ *rssi = _rssi; ++ } else { ++ orig_qual -= 0x80; ++ if ( !orig_qual ){ ++ _rssi = 1; ++ *rssi = 1; ++ } else { ++ _rssi = 0x32; ++ *rssi = 0x32; ++ } ++ } ++ break; ++ ++ /* case 4 */ ++ case RFCHIPID_MAXIM: ++ lsb = temp2 & 1; ++ temp2 &= 0x7e; ++ temp2 >>= 1; ++ temp2 += 0x42; ++ if( lsb != 0 ){ ++ temp2 += 0xa; ++ } ++ *rssi = temp2 & 0xff; ++ _rssi = temp2 & 0xff; ++ break; ++ } ++ ++ if ( _rssi < 0x64 ){ ++ if ( _rssi == 0 ) { ++ *rssi = 1; ++ } ++ } else { ++ *rssi = 0x64; ++ } ++ ++ return; ++} ++ ++ ++void rtl8180_irq_enable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ priv->irq_enabled = 1; ++/* ++ write_nic_word(dev,INTA_MASK,INTA_RXOK | INTA_RXDESCERR | INTA_RXOVERFLOW |\ ++ INTA_TXOVERFLOW | INTA_HIPRIORITYDESCERR | INTA_HIPRIORITYDESCOK |\ ++ INTA_NORMPRIORITYDESCERR | INTA_NORMPRIORITYDESCOK |\ ++ INTA_LOWPRIORITYDESCERR | INTA_LOWPRIORITYDESCOK | INTA_TIMEOUT); ++*/ ++ write_nic_word(dev,INTA_MASK, priv->irq_mask); ++} ++ ++ ++void rtl8180_irq_disable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++#ifdef CONFIG_RTL8185B ++ write_nic_dword(dev,IMR,0); ++#else ++ write_nic_word(dev,INTA_MASK,0); ++#endif ++ force_pci_posting(dev); ++ priv->irq_enabled = 0; ++} ++ ++ ++void rtl8180_set_mode(struct net_device *dev,int mode) ++{ ++ u8 ecmd; ++ ecmd=read_nic_byte(dev, EPROM_CMD); ++ ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK; ++ ecmd=ecmd | (mode<ieee80211->state == IEEE80211_LINKED) ++ { ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ msr |= (MSR_LINK_ADHOC<ieee80211->iw_mode == IW_MODE_MASTER) ++ msr |= (MSR_LINK_MASTER<ieee80211->iw_mode == IW_MODE_INFRA) ++ msr |= (MSR_LINK_MANAGED< 14) || (ch < 1)) ++ { ++ printk("In %s: Invalid chnanel %d\n", __FUNCTION__, ch); ++ return; ++ } ++ ++ priv->chan=ch; ++ //printk("in %s:channel is %d\n",__FUNCTION__,ch); ++ priv->rf_set_chan(dev,priv->chan); ++ ++} ++ ++ ++void rtl8180_rx_enable(struct net_device *dev) ++{ ++ u8 cmd; ++ u32 rxconf; ++ /* for now we accept data, management & ctl frame*/ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rxconf=read_nic_dword(dev,RX_CONF); ++ rxconf = rxconf &~ MAC_FILTER_MASK; ++ rxconf = rxconf | (1<flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ ++ dev->flags & IFF_PROMISC){ ++ rxconf = rxconf | (1<card_8185 == 0) ++ rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MASTER){ ++ rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MONITOR){ ++ rxconf = rxconf | (1<crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) ++ rxconf = rxconf | (1<card_8185){ ++ rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; ++ rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<card_8185) ++ rxconf = rxconf | RCR_ONLYERLPKT; ++ ++ rxconf = rxconf &~ RCR_CS_MASK; ++ if(!priv->card_8185) ++ rxconf |= (priv->rcr_csense<txlpringdma,read_nic_dword(dev,TLPDA)); ++ ++ write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma); ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma); ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma); ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma); ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma); ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma); ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ ++ write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma); ++} ++ ++ ++void rtl8180_conttx_enable(struct net_device *dev) ++{ ++ u32 txconf; ++ txconf = read_nic_dword(dev,TX_CONF); ++ txconf = txconf &~ TX_LOOPBACK_MASK; ++ txconf = txconf | (TX_LOOPBACK_CONTINUE <card_8185){ ++ ++ ++ byte = read_nic_byte(dev,CW_CONF); ++ byte &= ~(1<card_8185){ ++ ++ txconf = txconf &~ (1<retry_data<retry_rts<card_8185){ ++ if(priv->hw_plcp_len) ++ txconf = txconf &~ TCR_PLCP_LEN; ++ else ++ txconf = txconf | TCR_PLCP_LEN; ++ }else{ ++ txconf = txconf &~ TCR_SAT; ++ } ++ txconf = txconf &~ TCR_MXDMA_MASK; ++ txconf = txconf | (TCR_MXDMA_2048<ieee80211->hw_wep) ++// txconf=txconf &~ (1<dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ */ ++} ++ ++ ++void rtl8180_beacon_tx_enable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++#ifdef CONFIG_RTL8185B ++ priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ); ++ write_nic_byte(dev,TPPollStop, priv->dma_poll_mask); ++#else ++ priv->dma_poll_mask &=~(1<dma_poll_mask); ++#endif ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++ ++ ++void rtl8180_beacon_tx_disable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++#ifdef CONFIG_RTL8185B ++ priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ; ++ write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); ++#else ++ priv->dma_poll_mask |= (1<dma_poll_mask); ++#endif ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ ++} ++ ++ ++void rtl8180_rtx_disable(struct net_device *dev) ++{ ++ u8 cmd; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ cmd=read_nic_byte(dev,CMD); ++ write_nic_byte(dev, CMD, cmd &~ \ ++ ((1<rx_skb_complete) ++ dev_kfree_skb_any(priv->rx_skb); ++} ++ ++#if 0 ++int alloc_tx_beacon_desc_ring(struct net_device *dev, int count) ++{ ++ int i; ++ u32 *tmp; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ priv->txbeaconring = (u32*)pci_alloc_consistent(priv->pdev, ++ sizeof(u32)*8*count, ++ &priv->txbeaconringdma); ++ if (!priv->txbeaconring) return -1; ++ for (tmp=priv->txbeaconring,i=0;itxbeaconringdma+((i+1)*8*4); ++ else ++ *(tmp+4) = (u32)priv->txbeaconringdma; ++ ++ tmp=tmp+8; ++ } ++ return 0; ++} ++#endif ++ ++short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count, ++ int addr) ++{ ++ int i; ++ u32 *desc; ++ u32 *tmp; ++ dma_addr_t dma_desc, dma_tmp; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct pci_dev *pdev = priv->pdev; ++ void *buf; ++ ++ if((bufsize & 0xfff) != bufsize) { ++ DMESGE ("TX buffer allocation too large"); ++ return 0; ++ } ++ desc = (u32*)pci_alloc_consistent(pdev, ++ sizeof(u32)*8*count+256, &dma_desc); ++ if(desc==NULL) return -1; ++ if(dma_desc & 0xff){ ++ ++ /* ++ * descriptor's buffer must be 256 byte aligned ++ * we shouldn't be here, since we set DMA mask ! ++ */ ++ DMESGW("Fixing TX alignment"); ++ desc = (u32*)((u8*)desc + 256); ++#if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR)) ++ desc = (u32*)((u64)desc &~ 0xff); ++ dma_desc = (dma_addr_t)((u8*)dma_desc + 256); ++ dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff); ++#else ++ desc = (u32*)((u32)desc &~ 0xff); ++ dma_desc = (dma_addr_t)((u8*)dma_desc + 256); ++ dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff); ++#endif ++ } ++ tmp=desc; ++ for (i=0;itxnpbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer NP"); ++ return -ENOMEM; ++ } ++ break; ++ ++ case TX_LOWPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txlpbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer LP"); ++ return -ENOMEM; ++ } ++ break; ++ ++ case TX_HIGHPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer HP"); ++ return -ENOMEM; ++ } ++ break; ++#else ++ case TX_MANAGEPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txmapbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer NP"); ++ return -ENOMEM; ++ } ++ break; ++ ++ case TX_BKPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txbkpbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer LP"); ++ return -ENOMEM; ++ } ++ break; ++ case TX_BEPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txbepbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer NP"); ++ return -ENOMEM; ++ } ++ break; ++ ++ case TX_VIPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txvipbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer LP"); ++ return -ENOMEM; ++ } ++ break; ++ case TX_VOPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txvopbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer NP"); ++ return -ENOMEM; ++ } ++ break; ++#endif ++ case TX_HIGHPRIORITY_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer HP"); ++ return -ENOMEM; ++ } ++ break; ++ case TX_BEACON_RING_ADDR: ++ if(-1 == buffer_add(&(priv->txbeaconbufs),buf,dma_tmp,NULL)){ ++ DMESGE("Unable to allocate mem for buffer BP"); ++ return -ENOMEM; ++ } ++ break; ++ } ++ *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv ++ *(tmp+2) = (u32)dma_tmp; ++ *(tmp+3) = bufsize; ++ ++ if(i+1txmapringdma=dma_desc; ++ priv->txmapring=desc; ++ break; ++ ++ case TX_BKPRIORITY_RING_ADDR: ++ priv->txbkpringdma=dma_desc; ++ priv->txbkpring=desc; ++ break; ++ ++ case TX_BEPRIORITY_RING_ADDR: ++ priv->txbepringdma=dma_desc; ++ priv->txbepring=desc; ++ break; ++ ++ case TX_VIPRIORITY_RING_ADDR: ++ priv->txvipringdma=dma_desc; ++ priv->txvipring=desc; ++ break; ++ ++ case TX_VOPRIORITY_RING_ADDR: ++ priv->txvopringdma=dma_desc; ++ priv->txvopring=desc; ++ break; ++ ++ case TX_HIGHPRIORITY_RING_ADDR: ++ priv->txhpringdma=dma_desc; ++ priv->txhpring=desc; ++ break; ++ ++ case TX_BEACON_RING_ADDR: ++ priv->txbeaconringdma=dma_desc; ++ priv->txbeaconring=desc; ++ break; ++ ++ } ++ ++#ifdef DEBUG_TX ++ DMESG("Tx dma physical address: %x",dma_desc); ++#endif ++ ++ return 0; ++} ++ ++ ++void free_tx_desc_rings(struct net_device *dev) ++{ ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct pci_dev *pdev=priv->pdev; ++ int count = priv->txringcount; ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txmapring, priv->txmapringdma); ++ buffer_free(dev,&(priv->txmapbufs),priv->txbuffsize,1); ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txbkpring, priv->txbkpringdma); ++ buffer_free(dev,&(priv->txbkpbufs),priv->txbuffsize,1); ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txbepring, priv->txbepringdma); ++ buffer_free(dev,&(priv->txbepbufs),priv->txbuffsize,1); ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txvipring, priv->txvipringdma); ++ buffer_free(dev,&(priv->txvipbufs),priv->txbuffsize,1); ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txvopring, priv->txvopringdma); ++ buffer_free(dev,&(priv->txvopbufs),priv->txbuffsize,1); ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txhpring, priv->txhpringdma); ++ buffer_free(dev,&(priv->txhpbufs),priv->txbuffsize,1); ++ ++ count = priv->txbeaconcount; ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txbeaconring, priv->txbeaconringdma); ++ buffer_free(dev,&(priv->txbeaconbufs),priv->txbuffsize,1); ++} ++ ++#if 0 ++void free_beacon_desc_ring(struct net_device *dev,int count) ++{ ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct pci_dev *pdev=priv->pdev; ++ ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->txbeaconring, priv->txbeaconringdma); ++ ++ if (priv->beacon_buf) ++ pci_free_consistent(priv->pdev, ++ priv->master_beaconsize,priv->beacon_buf,priv->beacondmabuf); ++ ++} ++#endif ++void free_rx_desc_ring(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct pci_dev *pdev = priv->pdev; ++ ++ int count = priv->rxringcount; ++ ++#ifdef CONFIG_RTL8185B ++ pci_free_consistent(pdev, sizeof(u32)*8*count+256, ++ priv->rxring, priv->rxringdma); ++#else ++ pci_free_consistent(pdev, sizeof(u32)*4*count+256, ++ priv->rxring, priv->rxringdma); ++#endif ++ ++ buffer_free(dev,&(priv->rxbuffer),priv->rxbuffersize,0); ++} ++ ++ ++short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) ++{ ++ int i; ++ u32 *desc; ++ u32 *tmp; ++ dma_addr_t dma_desc,dma_tmp; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct pci_dev *pdev=priv->pdev; ++ void *buf; ++ u8 rx_desc_size; ++ ++#ifdef CONFIG_RTL8185B ++ rx_desc_size = 8; // 4*8 = 32 bytes ++#else ++ rx_desc_size = 4; ++#endif ++ ++ if((bufsize & 0xfff) != bufsize){ ++ DMESGE ("RX buffer allocation too large"); ++ return -1; ++ } ++ ++ desc = (u32*)pci_alloc_consistent(pdev,sizeof(u32)*rx_desc_size*count+256, ++ &dma_desc); ++ ++ if(dma_desc & 0xff){ ++ ++ /* ++ * descriptor's buffer must be 256 byte aligned ++ * should never happen since we specify the DMA mask ++ */ ++ ++ DMESGW("Fixing RX alignment"); ++ desc = (u32*)((u8*)desc + 256); ++#if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR)) ++ desc = (u32*)((u64)desc &~ 0xff); ++ dma_desc = (dma_addr_t)((u8*)dma_desc + 256); ++ dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff); ++#else ++ desc = (u32*)((u32)desc &~ 0xff); ++ dma_desc = (dma_addr_t)((u8*)dma_desc + 256); ++ dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff); ++#endif ++ } ++ ++ priv->rxring=desc; ++ priv->rxringdma=dma_desc; ++ tmp=desc; ++ ++ for (i=0;irxbuffer), buf,dma_tmp, ++ &(priv->rxbufferhead))){ ++ DMESGE("Unable to allocate mem RX buf"); ++ return -1; ++ } ++ *tmp = 0; //zero pads the header of the descriptor ++ *tmp = *tmp |( bufsize&0xfff); ++ *(tmp+2) = (u32)dma_tmp; ++ *tmp = *tmp |(1<<31); // descriptor void, owned by the NIC ++ ++#ifdef DEBUG_RXALLOC ++ DMESG("Alloc %x size buffer, DMA mem @ %x, virtual mem @ %x", ++ (u32)(bufsize&0xfff), (u32)dma_tmp, (u32)buf); ++#endif ++ ++ tmp=tmp+rx_desc_size; ++ } ++ ++ *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); // this is the last descriptor ++ ++ ++#ifdef DEBUG_RXALLOC ++ DMESG("RX DMA physical address: %x",dma_desc); ++#endif ++ ++ return 0; ++} ++ ++ ++void set_nic_rxring(struct net_device *dev) ++{ ++ u8 pgreg; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ //rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ ++ pgreg=read_nic_byte(dev, PGSELECT); ++ write_nic_byte(dev, PGSELECT, pgreg &~ (1<rxringdma); ++} ++ ++ ++void rtl8180_reset(struct net_device *dev) ++{ ++ //u32 txconf = 0x80e00707; //FIXME: Make me understandable ++ u8 cr; ++ ++ //write_nic_dword(dev,TX_CONF,txconf); ++ ++ rtl8180_irq_disable(dev); ++ ++ cr=read_nic_byte(dev,CMD); ++ cr = cr & 2; ++ cr = cr | (1<12) return 10; ++ return rtl_rate[rate]; ++} ++inline u8 rtl8180_IsWirelessBMode(u16 rate) ++{ ++ if( ((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220) ) ++ return 1; ++ else return 0; ++} ++u16 N_DBPSOfRate(u16 DataRate); ++u16 ComputeTxTime( ++ u16 FrameLength, ++ u16 DataRate, ++ u8 bManagementFrame, ++ u8 bShortPreamble ++) ++{ ++ u16 FrameTime; ++ u16 N_DBPS; ++ u16 Ceiling; ++ ++ if( rtl8180_IsWirelessBMode(DataRate) ) ++ { ++ if( bManagementFrame || !bShortPreamble || DataRate == 10 ) ++ { // long preamble ++ FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10))); ++ } ++ else ++ { // Short preamble ++ FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10))); ++ } ++ if( ( FrameLength*8 % (DataRate/10) ) != 0 ) //Get the Ceilling ++ FrameTime ++; ++ } else { //802.11g DSSS-OFDM PLCP length field calculation. ++ N_DBPS = N_DBPSOfRate(DataRate); ++ Ceiling = (16 + 8*FrameLength + 6) / N_DBPS ++ + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0); ++ FrameTime = (u16)(16 + 4 + 4*Ceiling + 6); ++ } ++ return FrameTime; ++} ++u16 N_DBPSOfRate(u16 DataRate) ++{ ++ u16 N_DBPS = 24; ++ ++ switch(DataRate) ++ { ++ case 60: ++ N_DBPS = 24; ++ break; ++ ++ case 90: ++ N_DBPS = 36; ++ break; ++ ++ case 120: ++ N_DBPS = 48; ++ break; ++ ++ case 180: ++ N_DBPS = 72; ++ break; ++ ++ case 240: ++ N_DBPS = 96; ++ break; ++ ++ case 360: ++ N_DBPS = 144; ++ break; ++ ++ case 480: ++ N_DBPS = 192; ++ break; ++ ++ case 540: ++ N_DBPS = 216; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return N_DBPS; ++} ++ ++//{by amy 080312 ++// ++// Description: ++// For Netgear case, they want good-looking singal strength. ++// 2004.12.05, by rcnjko. ++// ++long ++NetgearSignalStrengthTranslate( ++ long LastSS, ++ long CurrSS ++ ) ++{ ++ long RetSS; ++ ++ // Step 1. Scale mapping. ++ if(CurrSS >= 71 && CurrSS <= 100) ++ { ++ RetSS = 90 + ((CurrSS - 70) / 3); ++ } ++ else if(CurrSS >= 41 && CurrSS <= 70) ++ { ++ RetSS = 78 + ((CurrSS - 40) / 3); ++ } ++ else if(CurrSS >= 31 && CurrSS <= 40) ++ { ++ RetSS = 66 + (CurrSS - 30); ++ } ++ else if(CurrSS >= 21 && CurrSS <= 30) ++ { ++ RetSS = 54 + (CurrSS - 20); ++ } ++ else if(CurrSS >= 5 && CurrSS <= 20) ++ { ++ RetSS = 42 + (((CurrSS - 5) * 2) / 3); ++ } ++ else if(CurrSS == 4) ++ { ++ RetSS = 36; ++ } ++ else if(CurrSS == 3) ++ { ++ RetSS = 27; ++ } ++ else if(CurrSS == 2) ++ { ++ RetSS = 18; ++ } ++ else if(CurrSS == 1) ++ { ++ RetSS = 9; ++ } ++ else ++ { ++ RetSS = CurrSS; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ // Step 2. Smoothing. ++ if(LastSS > 0) ++ { ++ RetSS = ((LastSS * 5) + (RetSS)+ 5) / 6; ++ } ++ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); ++ ++ return RetSS; ++} ++// ++// Description: ++// Translate 0-100 signal strength index into dBm. ++// ++long ++TranslateToDbm8185( ++ u8 SignalStrengthIndex // 0-100 index. ++ ) ++{ ++ long SignalPower; // in dBm. ++ ++ // Translate to dBm (x=0.5y-95). ++ SignalPower = (long)((SignalStrengthIndex + 1) >> 1); ++ SignalPower -= 95; ++ ++ return SignalPower; ++} ++// ++// Description: ++// Perform signal smoothing for dynamic mechanism. ++// This is different with PerformSignalSmoothing8185 in smoothing fomula. ++// No dramatic adjustion is apply because dynamic mechanism need some degree ++// of correctness. Ported from 8187B. ++// 2007-02-26, by Bruce. ++// ++void ++PerformUndecoratedSignalSmoothing8185( ++ struct r8180_priv *priv, ++ bool bCckRate ++ ) ++{ ++ ++ ++ // Determin the current packet is CCK rate. ++ priv->bCurCCKPkt = bCckRate; ++ ++ if(priv->UndecoratedSmoothedSS >= 0) ++ { ++ priv->UndecoratedSmoothedSS = ( (priv->UndecoratedSmoothedSS * 5) + (priv->SignalStrength * 10) ) / 6; ++ } ++ else ++ { ++ priv->UndecoratedSmoothedSS = priv->SignalStrength * 10; ++ } ++ ++ priv->UndercorateSmoothedRxPower = ( (priv->UndercorateSmoothedRxPower * 50) + (priv->RxPower* 11)) / 60; ++ ++// printk("Sommthing SignalSterngth (%d) => UndecoratedSmoothedSS (%d)\n", priv->SignalStrength, priv->UndecoratedSmoothedSS); ++// printk("Sommthing RxPower (%d) => UndecoratedRxPower (%d)\n", priv->RxPower, priv->UndercorateSmoothedRxPower); ++ ++ //if(priv->CurCCKRSSI >= 0 && bCckRate) ++ if(bCckRate) ++ { ++ priv->CurCCKRSSI = priv->RSSI; ++ } ++ else ++ { ++ priv->CurCCKRSSI = 0; ++ } ++ ++ // Boundary checking. ++ // TODO: The overflow condition does happen, if we want to fix, ++ // we shall recalculate thresholds first. ++ if(priv->UndecoratedSmoothedSS > 100) ++ { ++// printk("UndecoratedSmoothedSS(%d) overflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength); ++ } ++ if(priv->UndecoratedSmoothedSS < 0) ++ { ++// printk("UndecoratedSmoothedSS(%d) underflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength); ++ } ++ ++} ++ ++//by amy 080312} ++ ++/* This is rough RX isr handling routine*/ ++void rtl8180_rx(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct sk_buff *tmp_skb; ++ ++ //struct sk_buff *skb; ++ short first,last; ++ u32 len; ++ int lastlen; ++ unsigned char quality, signal; ++ u8 rate; ++ //u32 *prism_hdr; ++ u32 *tmp,*tmp2; ++ u8 rx_desc_size; ++ u8 padding; ++ //u32 count=0; ++ char rxpower = 0; ++ u32 RXAGC = 0; ++ long RxAGC_dBm = 0; ++ u8 LNA=0, BB=0; ++ u8 LNA_gain[4]={02, 17, 29, 39}; ++ u8 Antenna = 0; ++ struct ieee80211_hdr *hdr;//by amy ++ u16 fc,type; ++ u8 bHwError = 0,bCRC = 0,bICV = 0; ++ //bHwError = 0; ++ //bCRC = 0; ++ //bICV = 0; ++ bool bCckRate = false; ++ u8 RSSI = 0; ++ long SignalStrengthIndex = 0;//+by amy 080312 ++// u8 SignalStrength = 0; ++ struct ieee80211_rx_stats stats = { ++ .signal = 0, ++ .noise = -98, ++ .rate = 0, ++ // .mac_time = jiffies, ++ .freq = IEEE80211_24GHZ_BAND, ++ }; ++ ++#ifdef CONFIG_RTL8185B ++ stats.nic_type = NIC_8185B; ++ rx_desc_size = 8; ++ ++#else ++ stats.nic_type = NIC_8185; ++ rx_desc_size = 4; ++#endif ++ //printk("receive frame!%d\n",count++); ++ //if (!priv->rxbuffer) DMESG ("EE: NIC RX ack, but RX queue corrupted!"); ++ //else { ++ ++ if ((*(priv->rxringtail)) & (1<<31)) { ++ ++ /* we have got an RX int, but the descriptor ++ * we are pointing is empty*/ ++ ++ priv->stats.rxnodata++; ++ priv->ieee80211->stats.rx_errors++; ++ ++ /* if (! *(priv->rxring) & (1<<31)) { ++ ++ priv->stats.rxreset++; ++ priv->rxringtail=priv->rxring; ++ priv->rxbuffer=priv->rxbufferhead; ++ ++ }else{*/ ++ ++ #if 0 ++ /* Maybe it is possible that the NIC has skipped some descriptors or ++ * it has reset its internal pointer to the beginning of the ring ++ * we search for the first filled descriptor in the ring, or we break ++ * putting again the pointer in the old location if we do not found any. ++ * This is quite dangerous, what does happen if the nic writes ++ * two descriptor (say A and B) when we have just checked the descriptor ++ * A and we are going to check the descriptor B..This might happen if the ++ * interrupt was dummy, there was not really filled descriptors and ++ * the NIC didn't lose pointer ++ */ ++ ++ //priv->stats.rxwrkaround++; ++ ++ tmp = priv->rxringtail; ++ while (*(priv->rxringtail) & (1<<31)){ ++ ++ priv->rxringtail+=4; ++ ++ if(priv->rxringtail >= ++ (priv->rxring)+(priv->rxringcount )*4) ++ priv->rxringtail=priv->rxring; ++ ++ priv->rxbuffer=(priv->rxbuffer->next); ++ ++ if(priv->rxringtail == tmp ){ ++ //DMESG("EE: Could not find RX pointer"); ++ priv->stats.rxnopointer++; ++ break; ++ } ++ } ++ #else ++ ++ tmp2 = NULL; ++ tmp = priv->rxringtail; ++ do{ ++ if(tmp == priv->rxring) ++ //tmp = priv->rxring + (priv->rxringcount )*rx_desc_size; xiong-2006-11-15 ++ tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size; ++ else ++ tmp -= rx_desc_size; ++ ++ if(! (*tmp & (1<<31))) ++ tmp2 = tmp; ++ }while(tmp != priv->rxring); ++ ++ if(tmp2) priv->rxringtail = tmp2; ++ #endif ++ //} ++ } ++ ++ /* while there are filled descriptors */ ++ while(!(*(priv->rxringtail) & (1<<31))){ ++ if(*(priv->rxringtail) & (1<<26)) ++ DMESGW("RX buffer overflow"); ++ if(*(priv->rxringtail) & (1<<12)) ++ priv->stats.rxicverr++; ++ ++ if(*(priv->rxringtail) & (1<<27)){ ++ priv->stats.rxdmafail++; ++ //DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); ++ goto drop; ++ } ++ ++ pci_dma_sync_single_for_cpu(priv->pdev, ++ priv->rxbuffer->dma, ++ priv->rxbuffersize * \ ++ sizeof(u8), ++ PCI_DMA_FROMDEVICE); ++ ++ first = *(priv->rxringtail) & (1<<29) ? 1:0; ++ if(first) priv->rx_prevlen=0; ++ ++ last = *(priv->rxringtail) & (1<<28) ? 1:0; ++ if(last){ ++ lastlen=((*priv->rxringtail) &0xfff); ++ ++ /* if the last descriptor (that should ++ * tell us the total packet len) tell ++ * us something less than the descriptors ++ * len we had until now, then there is some ++ * problem.. ++ * workaround to prevent kernel panic ++ */ ++ if(lastlen < priv->rx_prevlen) ++ len=0; ++ else ++ len=lastlen-priv->rx_prevlen; ++ ++ if(*(priv->rxringtail) & (1<<13)) { ++//lastlen=((*priv->rxringtail) &0xfff); ++ if ((*(priv->rxringtail) & 0xfff) <500) ++ priv->stats.rxcrcerrmin++; ++ else if ((*(priv->rxringtail) & 0x0fff) >1000) ++ priv->stats.rxcrcerrmax++; ++ else ++ priv->stats.rxcrcerrmid++; ++ ++ } ++ ++ }else{ ++ len = priv->rxbuffersize; ++ } ++ ++#ifdef CONFIG_RTL8185B ++ if(first && last) { ++ padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; ++ }else if(first) { ++ padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; ++ if(padding) { ++ len -= 2; ++ } ++ }else { ++ padding = 0; ++ } ++#ifdef CONFIG_RTL818X_S ++ padding = 0; ++#endif ++#endif ++ priv->rx_prevlen+=len; ++ ++ if(priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100){ ++ /* HW is probably passing several buggy frames ++ * without FD or LD flag set. ++ * Throw this garbage away to prevent skb ++ * memory exausting ++ */ ++ if(!priv->rx_skb_complete) ++ dev_kfree_skb_any(priv->rx_skb); ++ priv->rx_skb_complete = 1; ++ } ++ ++#ifdef DEBUG_RX_FRAG ++ DMESG("Iteration.. len %x",len); ++ if(first) DMESG ("First descriptor"); ++ if(last) DMESG("Last descriptor"); ++ ++#endif ++#ifdef DEBUG_RX_VERBOSE ++ print_buffer( priv->rxbuffer->buf, len); ++#endif ++ ++#ifdef CONFIG_RTL8185B ++ signal=(unsigned char)(((*(priv->rxringtail+3))& (0x00ff0000))>>16); ++ signal=(signal&0xfe)>>1; // Modify by hikaru 6.6 ++ ++ quality=(unsigned char)((*(priv->rxringtail+3)) & (0xff)); ++ ++ stats.mac_time[0] = *(priv->rxringtail+1); ++ stats.mac_time[1] = *(priv->rxringtail+2); ++ rxpower =((char)(((*(priv->rxringtail+4))& (0x00ff0000))>>16))/2 - 42; ++ RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>> 8)) & (0x7f); ++ ++#else ++ signal=((*(priv->rxringtail+1))& (0xff0000))>>16; ++ signal=(signal&0xfe)>>1; // Modify by hikaru 6.6 ++ ++ quality=((*(priv->rxringtail+1)) & (0xff)); ++ ++ stats.mac_time[0] = *(priv->rxringtail+2); ++ stats.mac_time[1] = *(priv->rxringtail+3); ++#endif ++ rate=((*(priv->rxringtail)) & ++ ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20; ++ ++ stats.rate = rtl8180_rate2rate(rate); ++ //DMESG("%d",rate); ++ Antenna = (((*(priv->rxringtail +3))& (0x00008000)) == 0 )? 0:1 ; ++// printk("in rtl8180_rx():Antenna is %d\n",Antenna); ++//by amy for antenna ++ if(!rtl8180_IsWirelessBMode(stats.rate)) ++ { // OFDM rate. ++ ++ RxAGC_dBm = rxpower+1; //bias ++ } ++ else ++ { // CCK rate. ++ RxAGC_dBm = signal;//bit 0 discard ++ ++ LNA = (u8) (RxAGC_dBm & 0x60 ) >> 5 ; //bit 6~ bit 5 ++ BB = (u8) (RxAGC_dBm & 0x1F); // bit 4 ~ bit 0 ++ ++ RxAGC_dBm = -( LNA_gain[LNA] + (BB *2) ); //Pin_11b=-(LNA_gain+BB_gain) (dBm) ++ ++ RxAGC_dBm +=4; //bias ++ } ++ ++ if(RxAGC_dBm & 0x80) //absolute value ++ RXAGC= ~(RxAGC_dBm)+1; ++ bCckRate = rtl8180_IsWirelessBMode(stats.rate); ++ // Translate RXAGC into 1-100. ++ if(!rtl8180_IsWirelessBMode(stats.rate)) ++ { // OFDM rate. ++ if(RXAGC>90) ++ RXAGC=90; ++ else if(RXAGC<25) ++ RXAGC=25; ++ RXAGC=(90-RXAGC)*100/65; ++ } ++ else ++ { // CCK rate. ++ if(RXAGC>95) ++ RXAGC=95; ++ else if(RXAGC<30) ++ RXAGC=30; ++ RXAGC=(95-RXAGC)*100/65; ++ } ++ priv->SignalStrength = (u8)RXAGC; ++ priv->RecvSignalPower = RxAGC_dBm ; // It can use directly by SD3 CMLin ++ priv->RxPower = rxpower; ++ priv->RSSI = RSSI; ++//{by amy 080312 ++ // SQ translation formular is provided by SD3 DZ. 2006.06.27, by rcnjko. ++ if(quality >= 127) ++ quality = 1;//0; //0 will cause epc to show signal zero , walk aroud now; ++ else if(quality < 27) ++ quality = 100; ++ else ++ quality = 127 - quality; ++ priv->SignalQuality = quality; ++ if(!priv->card_8185) ++ printk("check your card type\n"); ++ ++ stats.signal = (u8)quality;//priv->wstats.qual.level = priv->SignalStrength; ++ stats.signalstrength = RXAGC; ++ if(stats.signalstrength > 100) ++ stats.signalstrength = 100; ++ stats.signalstrength = (stats.signalstrength * 70)/100 + 30; ++ // printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); ++ stats.rssi = priv->wstats.qual.qual = priv->SignalQuality; ++ stats.noise = priv->wstats.qual.noise = 100 - priv ->wstats.qual.qual; ++//by amy 080312} ++ bHwError = (((*(priv->rxringtail))& (0x00000fff)) == 4080)| (((*(priv->rxringtail))& (0x04000000)) != 0 ) ++ | (((*(priv->rxringtail))& (0x08000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x10000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x20000000)) != 0 ); ++ bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13; ++ bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12; ++ hdr = (struct ieee80211_hdr *)priv->rxbuffer->buf; ++ fc = le16_to_cpu(hdr->frame_ctl); ++ type = WLAN_FC_GET_TYPE(fc); ++ ++ if((IEEE80211_FTYPE_CTL != type) && ++ (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3)) ++ && (!bHwError) && (!bCRC)&& (!bICV)) ++ { ++//by amy 080312 ++ // Perform signal smoothing for dynamic mechanism on demand. ++ // This is different with PerformSignalSmoothing8185 in smoothing fomula. ++ // No dramatic adjustion is apply because dynamic mechanism need some degree ++ // of correctness. 2007.01.23, by shien chang. ++ PerformUndecoratedSignalSmoothing8185(priv,bCckRate); ++ // ++ // For good-looking singal strength. ++ // ++ SignalStrengthIndex = NetgearSignalStrengthTranslate( ++ priv->LastSignalStrengthInPercent, ++ priv->SignalStrength); ++ ++ priv->LastSignalStrengthInPercent = SignalStrengthIndex; ++ priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex); ++ // ++ // We need more correct power of received packets and the "SignalStrength" of RxStats is beautified, ++ // so we record the correct power here. ++ // ++ priv->Stats_SignalQuality =(long) (priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6; ++ priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower -1) / 6; ++ ++ // Figure out which antenna that received the lasted packet. ++ priv->LastRxPktAntenna = Antenna ? 1 : 0; // 0: aux, 1: main. ++//by amy 080312 ++ SwAntennaDiversityRxOk8185(dev, priv->SignalStrength); ++ } ++ ++//by amy for antenna ++ ++ ++ ++ ++ ++ ++#ifndef DUMMY_RX ++ if(first){ ++ if(!priv->rx_skb_complete){ ++ /* seems that HW sometimes fails to reiceve and ++ doesn't provide the last descriptor */ ++#ifdef DEBUG_RX_SKB ++ DMESG("going to free incomplete skb"); ++#endif ++ dev_kfree_skb_any(priv->rx_skb); ++ priv->stats.rxnolast++; ++#ifdef DEBUG_RX_SKB ++ DMESG("free incomplete skb OK"); ++#endif ++ } ++ /* support for prism header has been originally added by Christian */ ++ if(priv->prism_hdr && priv->ieee80211->iw_mode == IW_MODE_MONITOR){ ++ ++#if 0 ++ priv->rx_skb = dev_alloc_skb(len+2+PRISM_HDR_SIZE); ++ if(! priv->rx_skb) goto drop; ++ ++ prism_hdr = (u32*) skb_put(priv->rx_skb,PRISM_HDR_SIZE); ++ prism_hdr[0]=htonl(0x80211001); //version ++ prism_hdr[1]=htonl(0x40); //length ++ prism_hdr[2]=htonl(stats.mac_time[1]); //mactime (HIGH) ++ prism_hdr[3]=htonl(stats.mac_time[0]); //mactime (LOW) ++ rdtsc(prism_hdr[5], prism_hdr[4]); //hostime (LOW+HIGH) ++ prism_hdr[4]=htonl(prism_hdr[4]); //Byte-Order aendern ++ prism_hdr[5]=htonl(prism_hdr[5]); //Byte-Order aendern ++ prism_hdr[6]=0x00; //phytype ++ prism_hdr[7]=htonl(priv->chan); //channel ++ prism_hdr[8]=htonl(stats.rate); //datarate ++ prism_hdr[9]=0x00; //antenna ++ prism_hdr[10]=0x00; //priority ++ prism_hdr[11]=0x00; //ssi_type ++ prism_hdr[12]=htonl(stats.signal); //ssi_signal ++ prism_hdr[13]=htonl(stats.noise); //ssi_noise ++ prism_hdr[14]=0x00; //preamble ++ prism_hdr[15]=0x00; //encoding ++ ++#endif ++ }else{ ++ priv->rx_skb = dev_alloc_skb(len+2); ++ if( !priv->rx_skb) goto drop; ++#ifdef DEBUG_RX_SKB ++ DMESG("Alloc initial skb %x",len+2); ++#endif ++ } ++ ++ priv->rx_skb_complete=0; ++ priv->rx_skb->dev=dev; ++ }else{ ++ /* if we are here we should have already RXed ++ * the first frame. ++ * If we get here and the skb is not allocated then ++ * we have just throw out garbage (skb not allocated) ++ * and we are still rxing garbage.... ++ */ ++ if(!priv->rx_skb_complete){ ++ ++ tmp_skb= dev_alloc_skb(priv->rx_skb->len +len+2); ++ ++ if(!tmp_skb) goto drop; ++ ++ tmp_skb->dev=dev; ++#ifdef DEBUG_RX_SKB ++ DMESG("Realloc skb %x",len+2); ++#endif ++ ++#ifdef DEBUG_RX_SKB ++ DMESG("going copy prev frag %x",priv->rx_skb->len); ++#endif ++ memcpy(skb_put(tmp_skb,priv->rx_skb->len), ++ priv->rx_skb->data, ++ priv->rx_skb->len); ++#ifdef DEBUG_RX_SKB ++ DMESG("skb copy prev frag complete"); ++#endif ++ ++ dev_kfree_skb_any(priv->rx_skb); ++#ifdef DEBUG_RX_SKB ++ DMESG("prev skb free ok"); ++#endif ++ ++ priv->rx_skb=tmp_skb; ++ } ++ } ++#ifdef DEBUG_RX_SKB ++ DMESG("going to copy current payload %x",len); ++#endif ++ if(!priv->rx_skb_complete) { ++#ifdef CONFIG_RTL8185B ++ if(padding) { ++ memcpy(skb_put(priv->rx_skb,len), ++ (((unsigned char *)priv->rxbuffer->buf) + 2),len); ++ } else { ++#endif ++ memcpy(skb_put(priv->rx_skb,len), ++ priv->rxbuffer->buf,len); ++#ifdef CONFIG_RTL8185B ++ } ++#endif ++ } ++#ifdef DEBUG_RX_SKB ++ DMESG("current fragment skb copy complete"); ++#endif ++ ++ if(last && !priv->rx_skb_complete){ ++ ++#ifdef DEBUG_RX_SKB ++ DMESG("Got last fragment"); ++#endif ++ ++ if(priv->rx_skb->len > 4) ++ skb_trim(priv->rx_skb,priv->rx_skb->len-4); ++#ifdef DEBUG_RX_SKB ++ DMESG("yanked out crc, passing to the upper layer"); ++#endif ++ ++#ifndef RX_DONT_PASS_UL ++ if(!ieee80211_rx(priv->ieee80211, ++ priv->rx_skb, &stats)){ ++#ifdef DEBUG_RX ++ DMESGW("Packet not consumed"); ++#endif ++#endif // RX_DONT_PASS_UL ++ ++ dev_kfree_skb_any(priv->rx_skb); ++#ifndef RX_DONT_PASS_UL ++ } ++#endif ++#ifdef DEBUG_RX ++ else{ ++ DMESG("Rcv frag"); ++ } ++#endif ++ priv->rx_skb_complete=1; ++ } ++ ++#endif //DUMMY_RX ++ ++ pci_dma_sync_single_for_device(priv->pdev, ++ priv->rxbuffer->dma, ++ priv->rxbuffersize * \ ++ sizeof(u8), ++ PCI_DMA_FROMDEVICE); ++ ++ ++drop: // this is used when we have not enought mem ++ ++ /* restore the descriptor */ ++ *(priv->rxringtail+2)=priv->rxbuffer->dma; ++ *(priv->rxringtail)=*(priv->rxringtail) &~ 0xfff; ++ *(priv->rxringtail)= ++ *(priv->rxringtail) | priv->rxbuffersize; ++ ++ *(priv->rxringtail)= ++ *(priv->rxringtail) | (1<<31); ++ //^empty descriptor ++ ++ //wmb(); ++ ++#ifdef DEBUG_RX ++ DMESG("Current descriptor: %x",(u32)priv->rxringtail); ++#endif ++ //unsigned long flags; ++ //spin_lock_irqsave(&priv->irq_lock,flags); ++ ++ priv->rxringtail+=rx_desc_size; ++ if(priv->rxringtail >= ++ (priv->rxring)+(priv->rxringcount )*rx_desc_size) ++ priv->rxringtail=priv->rxring; ++ ++ //spin_unlock_irqrestore(&priv->irq_lock,flags); ++ ++ ++ priv->rxbuffer=(priv->rxbuffer->next); ++ ++ } ++ ++ ++ ++// if(get_curr_tx_free_desc(dev,priority)) ++// ieee80211_sta_ps_sleep(priv->ieee80211, &tmp, &tmp2); ++ ++ ++ ++} ++ ++ ++void rtl8180_dma_kick(struct net_device *dev, int priority) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++/* ++ ++ switch(priority){ ++ ++ case LOW_PRIORITY: ++ ++ write_nic_byte(dev,TX_DMA_POLLING, ++ (1<< TX_DMA_POLLING_LOWPRIORITY_SHIFT) | ++ priv->dma_poll_mask); ++ break; ++ ++ case NORM_PRIORITY: ++ ++ write_nic_byte(dev,TX_DMA_POLLING, ++ (1<< TX_DMA_POLLING_NORMPRIORITY_SHIFT) | ++ priv->dma_poll_mask); ++ break; ++ ++ case HI_PRIORITY: ++ ++ write_nic_byte(dev,TX_DMA_POLLING, ++ (1<< TX_DMA_POLLING_HIPRIORITY_SHIFT) | ++ priv->dma_poll_mask); ++ break; ++ ++ } ++*/ ++ write_nic_byte(dev, TX_DMA_POLLING, ++ (1 << (priority + 1)) | priv->dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ ++ force_pci_posting(dev); ++} ++ ++#if 0 ++void rtl8180_tx_queues_stop(struct net_device *dev) ++{ ++ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u8 dma_poll_mask = (1<dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ; ++ write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); ++#else ++ priv->dma_poll_mask |= (1<dma_poll_mask); ++#endif ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++ ++ ++void rtl8180_data_hard_resume(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++#ifdef CONFIG_RTL8185B ++ priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ); ++ write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask); ++#else ++ priv->dma_poll_mask &= ~(1<dma_poll_mask); ++#endif ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++} ++ ++ ++/* this function TX data frames when the ieee80211 stack requires this. ++ * It checks also if we need to stop the ieee tx queue, eventually do it ++ */ ++void rtl8180_hard_data_xmit(struct sk_buff *skb,struct net_device *dev, int ++rate) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ int mode; ++ struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; ++ short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS; ++ unsigned long flags; ++ int priority; ++ //static int count = 0; ++ ++ mode = priv->ieee80211->iw_mode; ++ ++ rate = ieeerate2rtlrate(rate); ++ /* ++ * This function doesn't require lock because we make ++ * sure it's called with the tx_lock already acquired. ++ * this come from the kernel's hard_xmit callback (trought ++ * the ieee stack, or from the try_wake_queue (again trought ++ * the ieee stack. ++ */ ++#ifdef CONFIG_RTL8185B ++ priority = AC2Q(skb->priority); ++#else ++ priority = LOW_PRIORITY; ++#endif ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ { ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ return; ++ } ++ ++ //printk(KERN_WARNING "priority = %d@%d\n", priority, count++); ++ if (!check_nic_enought_desc(dev, priority)){ ++ //DMESG("Error: no descriptor left by previous TX (avail %d) ", ++ // get_curr_tx_free_desc(dev, priority)); ++ DMESGW("Error: no descriptor left by previous TX (avail %d) ", ++ get_curr_tx_free_desc(dev, priority)); ++ //printk(KERN_WARNING "==============================================================> \n"); ++ ieee80211_stop_queue(priv->ieee80211); ++ } ++ rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate); ++ if (!check_nic_enought_desc(dev, priority)) ++ ieee80211_stop_queue(priv->ieee80211); ++ ++ //dev_kfree_skb_any(skb); ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++} ++ ++/* This is a rough attempt to TX a frame ++ * This is called by the ieee 80211 stack to TX management frames. ++ * If the ring is full packet are dropped (for data frame the queue ++ * is stopped before this can happen). For this reason it is better ++ * if the descriptors are larger than the largest management frame ++ * we intend to TX: i'm unsure what the HW does if it will not found ++ * the last fragment of a frame because it has been dropped... ++ * Since queues for Management and Data frames are different we ++ * might use a different lock than tx_lock (for example mgmt_tx_lock) ++ */ ++/* these function may loops if invoked with 0 descriptors or 0 len buffer*/ ++int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ unsigned long flags; ++ ++ int priority; ++ ++#ifdef CONFIG_RTL8185B ++ priority = MANAGE_PRIORITY; ++#else ++ priority = NORM_PRIORITY; ++#endif ++ ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ { ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ dev_kfree_skb_any(skb); ++ return 0; ++ } ++ ++ rtl8180_tx(dev, skb->data, skb->len, priority, ++ 0, 0,ieeerate2rtlrate(priv->ieee80211->basic_rate)); ++ ++ priv->ieee80211->stats.tx_bytes+=skb->len; ++ priv->ieee80211->stats.tx_packets++; ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ dev_kfree_skb_any(skb); ++ return 0; ++} ++ ++// longpre 144+48 shortpre 72+24 ++u16 rtl8180_len2duration(u32 len, short rate,short* ext) ++{ ++ u16 duration; ++ u16 drift; ++ *ext=0; ++ ++ switch(rate){ ++ case 0://1mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0x2; ++ drift = ((len+4)<<4) % 0x2; ++ if(drift ==0 ) break; ++ duration++; ++ break; ++ ++ case 1://2mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0x4; ++ drift = ((len+4)<<4) % 0x4; ++ if(drift ==0 ) break; ++ duration++; ++ break; ++ ++ case 2: //5.5mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0xb; ++ drift = ((len+4)<<4) % 0xb; ++ if(drift ==0 ) ++ break; ++ duration++; ++ break; ++ ++ default: ++ case 3://11mbps ++ *ext=0; ++ duration = ((len+4)<<4) /0x16; ++ drift = ((len+4)<<4) % 0x16; ++ if(drift ==0 ) ++ break; ++ duration++; ++ if(drift > 6) ++ break; ++ *ext=1; ++ break; ++ } ++ ++ return duration; ++} ++ ++ ++void rtl8180_prepare_beacon(struct net_device *dev) ++{ ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ struct sk_buff *skb; ++ ++ u16 word = read_nic_word(dev, BcnItv); ++ word &= ~BcnItv_BcnItv; // clear Bcn_Itv ++ word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval);//0x64; ++ write_nic_word(dev, BcnItv, word); ++ ++ ++ skb = ieee80211_get_beacon(priv->ieee80211); ++ if(skb){ ++ rtl8180_tx(dev,skb->data,skb->len,BEACON_PRIORITY, ++ 0,0,ieeerate2rtlrate(priv->ieee80211->basic_rate)); ++ dev_kfree_skb_any(skb); ++ } ++ #if 0 ++ //DMESG("size %x",len); ++ if(*tail & (1<<31)){ ++ ++ //DMESG("No more beacon TX desc"); ++ return ; ++ ++ } ++ //while(! *tail & (1<<31)){ ++ *tail= 0; // zeroes header ++ ++ *tail = *tail| (1<<29) ; //fist segment of the packet ++ *tail = (*tail) | (1<<28); // last segment ++ // *tail = *tail | (1<<18); // this is a beacon frame ++ *(tail+3)=*(tail+3) &~ 0xfff; ++ *(tail+3)=*(tail+3) | len; // buffer lenght ++ *tail = *tail |len; ++ // zeroes the second 32-bits dword of the descriptor ++ *(tail+1)= 0; ++ *tail = *tail | (rate << 24); ++ ++ duration = rtl8180_len2duration(len,rate,&ext); ++ ++ *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16); ++ ++ *tail = *tail | (1<<31); ++ //^ descriptor ready to be txed ++ if((tail - begin)/8 == priv->txbeaconcount-1) ++ tail=begin; ++ else ++ tail=tail+8; ++ //} ++#endif ++} ++ ++/* This function do the real dirty work: it enqueues a TX command ++ * descriptor in the ring buffer, copyes the frame in a TX buffer ++ * and kicks the NIC to ensure it does the DMA transfer. ++ */ ++short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, ++ short morefrag, short descfrag, int rate) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 *tail,*temp_tail; ++ u32 *begin; ++ u32 *buf; ++ int i; ++ int remain; ++ int buflen; ++ int count; ++ //u16 AckCtsTime; ++ //u16 FrameTime; ++ u16 duration; ++ short ext; ++ struct buffer* buflist; ++ //unsigned long flags; ++#ifdef CONFIG_RTL8185B ++ struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf; ++ u8 dest[ETH_ALEN]; ++ u8 bUseShortPreamble = 0; ++ u8 bCTSEnable = 0; ++ u8 bRTSEnable = 0; ++ //u16 RTSRate = 22; ++ //u8 RetryLimit = 0; ++ u16 Duration = 0; ++ u16 RtsDur = 0; ++ u16 ThisFrameTime = 0; ++ u16 TxDescDuration = 0; ++ u8 ownbit_flag = false; //added by david woo for sync Tx, 2007.12.14 ++#endif ++ ++ switch(priority) { ++ case MANAGE_PRIORITY: ++ tail=priv->txmapringtail; ++ begin=priv->txmapring; ++ buflist = priv->txmapbufstail; ++ count = priv->txringcount; ++ break; ++ ++ case BK_PRIORITY: ++ tail=priv->txbkpringtail; ++ begin=priv->txbkpring; ++ buflist = priv->txbkpbufstail; ++ count = priv->txringcount; ++ break; ++ ++ case BE_PRIORITY: ++ tail=priv->txbepringtail; ++ begin=priv->txbepring; ++ buflist = priv->txbepbufstail; ++ count = priv->txringcount; ++ break; ++ ++ case VI_PRIORITY: ++ tail=priv->txvipringtail; ++ begin=priv->txvipring; ++ buflist = priv->txvipbufstail; ++ count = priv->txringcount; ++ break; ++ ++ case VO_PRIORITY: ++ tail=priv->txvopringtail; ++ begin=priv->txvopring; ++ buflist = priv->txvopbufstail; ++ count = priv->txringcount; ++ break; ++ ++ case HI_PRIORITY: ++ tail=priv->txhpringtail; ++ begin=priv->txhpring; ++ buflist = priv->txhpbufstail; ++ count = priv->txringcount; ++ break; ++ ++ case BEACON_PRIORITY: ++ tail=priv->txbeaconringtail; ++ begin=priv->txbeaconring; ++ buflist = priv->txbeaconbufstail; ++ count = priv->txbeaconcount; ++ break; ++ ++ default: ++ return -1; ++ break; ++ } ++ ++ //printk("in rtl8180_tx(): rate is %d\n",priv->ieee80211->rate); ++#if 1 ++ memcpy(&dest, frag_hdr->addr1, ETH_ALEN); ++ if (is_multicast_ether_addr(dest) || ++ is_broadcast_ether_addr(dest)) ++ { ++ Duration = 0; ++ RtsDur = 0; ++ bRTSEnable = 0; ++ bCTSEnable = 0; ++ ++ ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); ++ TxDescDuration = ThisFrameTime; ++ } else {// Unicast packet ++ //u8 AckRate; ++ u16 AckTime; ++ ++ //YJ,add,080828,for Keep alive ++ priv->NumTxUnicast++; ++ ++ // Figure out ACK rate according to BSS basic rate and Tx rate, 2006.03.08 by rcnjko. ++ //AckRate = ComputeAckRate( pMgntInfo->mBrates, (u1Byte)(pTcb->DataRate) ); ++ // Figure out ACK time according to the AckRate and assume long preamble is used on receiver, 2006.03.08, by rcnjko. ++ //AckTime = ComputeTxTime( sAckCtsLng/8, AckRate, FALSE, FALSE); ++ //For simplicity, just use the 1M basic rate ++ //AckTime = ComputeTxTime(14, 540,0, 0); // AckCTSLng = 14 use 1M bps send ++ AckTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send ++ //AckTime = ComputeTxTime(14, 2,false, false); // AckCTSLng = 14 use 1M bps send ++ ++ if ( ((len + sCrcLng) > priv->rts) && priv->rts ) ++ { // RTS/CTS. ++ u16 RtsTime, CtsTime; ++ //u16 CtsRate; ++ bRTSEnable = 1; ++ bCTSEnable = 0; ++ ++ // Rate and time required for RTS. ++ RtsTime = ComputeTxTime( sAckCtsLng/8,priv->ieee80211->basic_rate, 0, 0); ++ // Rate and time required for CTS. ++ CtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send ++ ++ // Figure out time required to transmit this frame. ++ ThisFrameTime = ComputeTxTime(len + sCrcLng, ++ rtl8180_rate2rate(rate), ++ 0, ++ bUseShortPreamble); ++ ++ // RTS-CTS-ThisFrame-ACK. ++ RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime; ++ ++ TxDescDuration = RtsTime + RtsDur; ++ } ++ else {// Normal case. ++ bCTSEnable = 0; ++ bRTSEnable = 0; ++ RtsDur = 0; ++ ++ ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble); ++ TxDescDuration = ThisFrameTime + aSifsTime + AckTime; ++ } ++ ++ if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment ++ // ThisFrame-ACK. ++ Duration = aSifsTime + AckTime; ++ } else { // One or more fragments remained. ++ u16 NextFragTime; ++ NextFragTime = ComputeTxTime( len + sCrcLng, //pretend following packet length equal current packet ++ rtl8180_rate2rate(rate), ++ 0, ++ bUseShortPreamble ); ++ ++ //ThisFrag-ACk-NextFrag-ACK. ++ Duration = NextFragTime + 3*aSifsTime + 2*AckTime; ++ } ++ ++ } // End of Unicast packet ++ ++ frag_hdr->duration_id = Duration; ++#endif ++ ++ buflen=priv->txbuffsize; ++ remain=len; ++ temp_tail = tail; ++//printk("================================>buflen = %d, remain = %d!\n", buflen,remain); ++ while(remain!=0){ ++#ifdef DEBUG_TX_FRAG ++ DMESG("TX iteration"); ++#endif ++#ifdef DEBUG_TX ++ DMESG("TX: filling descriptor %x",(u32)tail); ++#endif ++ mb(); ++ if(!buflist){ ++ DMESGE("TX buffer error, cannot TX frames. pri %d.", priority); ++ //spin_unlock_irqrestore(&priv->tx_lock,flags); ++ return -1; ++ } ++ buf=buflist->buf; ++ ++ if( (*tail & (1<<31)) && (priority != BEACON_PRIORITY)){ ++ ++ DMESGW("No more TX desc, returning %x of %x", ++ remain,len); ++ priv->stats.txrdu++; ++#ifdef DEBUG_TX_DESC ++ check_tx_ring(dev,priority); ++ // netif_stop_queue(dev); ++ // netif_carrier_off(dev); ++#endif ++ // spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ return remain; ++ ++ } ++ ++ *tail= 0; // zeroes header ++ *(tail+1) = 0; ++ *(tail+3) = 0; ++ *(tail+5) = 0; ++ *(tail+6) = 0; ++ *(tail+7) = 0; ++ ++ if(priv->card_8185){ ++ //FIXME: this should be triggered by HW encryption parameters. ++ *tail |= (1<<15); //no encrypt ++// *tail |= (1<<30); //raise int when completed ++ } ++ // *tail = *tail | (1<<16); ++ if(remain==len && !descfrag) { ++ ownbit_flag = false; //added by david woo,2007.12.14 ++#ifdef DEBUG_TX_FRAG ++ DMESG("First descriptor"); ++#endif ++ *tail = *tail| (1<<29) ; //fist segment of the packet ++ *tail = *tail |(len); ++ } else { ++ ownbit_flag = true; ++ } ++ ++ for(i=0;i0;i++,remain--){ ++ ((u8*)buf)[i]=txbuf[i]; //copy data into descriptor pointed DMAble buffer ++ if(remain == 4 && i+4 >= buflen) break; ++ /* ensure the last desc has at least 4 bytes payload */ ++ ++ } ++ txbuf = txbuf + i; ++ *(tail+3)=*(tail+3) &~ 0xfff; ++ *(tail+3)=*(tail+3) | i; // buffer lenght ++ // Use short preamble or not ++ if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE) ++ if (priv->plcp_preamble_mode==1 && rate!=0) // short mode now, not long! ++ // *tail |= (1<<16); // enable short preamble mode. ++ ++#ifdef CONFIG_RTL8185B ++ if(bCTSEnable) { ++ *tail |= (1<<18); ++ } ++ ++ if(bRTSEnable) //rts enable ++ { ++ *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19);//RTS RATE ++ *tail |= (1<<23);//rts enable ++ *(tail+1) |=(RtsDur&0xffff);//RTS Duration ++ } ++ *(tail+3) |= ((TxDescDuration&0xffff)<<16); //DURATION ++// *(tail+3) |= (0xe6<<16); ++ *(tail+5) |= (11<<8);//(priv->retry_data<<8); //retry lim ; ++#else ++ //Use RTS or not ++#ifdef CONFIG_RTL8187B ++ if ( (len>priv->rts) && priv->rts && priority!=MANAGE_PRIORITY){ ++#else ++ if ( (len>priv->rts) && priv->rts && priority==LOW_PRIORITY){ ++#endif ++ *tail |= (1<<23); //enalbe RTS function ++ *tail |= (0<<19); //use 1M bps send RTS packet ++ AckCtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send ++ FrameTime = ComputeTxTime(len + 4, rtl8180_rate2rate(rate), 0, *tail&(1<<16)); ++ // RTS/CTS time is calculate as follow ++ duration = FrameTime + 3*10 + 2*AckCtsTime; //10us is the SifsTime; ++ *(tail+1) |= duration; //Need to edit here! ----hikaru ++ }else{ ++ *(tail+1)= 0; // zeroes the second 32-bits dword of the descriptor ++ } ++#endif ++ ++ *tail = *tail | ((rate&0xf) << 24); ++ //DMESG("rate %d",rate); ++ ++ if(priv->card_8185){ ++ ++ #if 0 ++ *(tail+5)&= ~(1<<24); /* tx ant 0 */ ++ ++ *(tail+5) &= ~(1<<23); /* random tx agc 23-16 */ ++ *(tail+5) |= (1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16); ++ ++ *(tail+5) &= ++~((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)); ++ *(tail+5) |= (7<<8); // Max retry limit ++ ++ *(tail+5) &= ~((1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0)); ++ *(tail+5) |= (8<<4); // Max contention window ++ *(tail+6) |= 4; // Min contention window ++ #endif ++ // *(tail+5) = 0; ++ } ++ ++ /* hw_plcp_len is not used for rtl8180 chip */ ++ /* FIXME */ ++ if(priv->card_8185 == 0 || !priv->hw_plcp_len){ ++ ++ duration = rtl8180_len2duration(len, ++ rate,&ext); ++ ++ ++#ifdef DEBUG_TX ++ DMESG("PLCP duration %d",duration ); ++ //DMESG("drift %d",drift); ++ DMESG("extension %s", (ext==1) ? "on":"off"); ++#endif ++ *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16); ++ if(ext) *(tail+1) = *(tail+1) |(1<<31); //plcp length extension ++ } ++ ++ if(morefrag) *tail = (*tail) | (1<<17); // more fragment ++ if(!remain) *tail = (*tail) | (1<<28); // last segment of frame ++ ++#ifdef DEBUG_TX_FRAG ++ if(!remain)DMESG("Last descriptor"); ++ if(morefrag)DMESG("More frag"); ++#endif ++ *(tail+5) = *(tail+5)|(2<<27); ++ *(tail+7) = *(tail+7)|(1<<4); ++ ++ wmb(); ++ if(ownbit_flag) ++ { ++ *tail = *tail | (1<<31); // descriptor ready to be txed ++ } ++ ++#ifdef DEBUG_TX_DESC2 ++ printk("tx desc is:\n"); ++ DMESG("%8x %8x %8x %8x %8x %8x %8x %8x", tail[0], tail[1], tail[2], tail[3], ++ tail[4], tail[5], tail[6], tail[7]); ++#endif ++ ++ if((tail - begin)/8 == count-1) ++ tail=begin; ++ ++ else ++ tail=tail+8; ++ ++ buflist=buflist->next; ++ ++ mb(); ++ ++ switch(priority) { ++ case MANAGE_PRIORITY: ++ priv->txmapringtail=tail; ++ priv->txmapbufstail=buflist; ++ break; ++ ++ case BK_PRIORITY: ++ priv->txbkpringtail=tail; ++ priv->txbkpbufstail=buflist; ++ break; ++ ++ case BE_PRIORITY: ++ priv->txbepringtail=tail; ++ priv->txbepbufstail=buflist; ++ break; ++ ++ case VI_PRIORITY: ++ priv->txvipringtail=tail; ++ priv->txvipbufstail=buflist; ++ break; ++ ++ case VO_PRIORITY: ++ priv->txvopringtail=tail; ++ priv->txvopbufstail=buflist; ++ break; ++ ++ case HI_PRIORITY: ++ priv->txhpringtail=tail; ++ priv->txhpbufstail = buflist; ++ break; ++ ++ case BEACON_PRIORITY: ++ /* the HW seems to be happy with the 1st ++ * descriptor filled and the 2nd empty... ++ * So always update descriptor 1 and never ++ * touch 2nd ++ */ ++ // priv->txbeaconringtail=tail; ++ // priv->txbeaconbufstail=buflist; ++ ++ break; ++ ++ } ++ ++ //rtl8180_dma_kick(dev,priority); ++ } ++ *temp_tail = *temp_tail | (1<<31); // descriptor ready to be txed ++ rtl8180_dma_kick(dev,priority); ++ //spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ return 0; ++ ++} ++ ++ ++void rtl8180_irq_rx_tasklet(struct r8180_priv * priv); ++ ++ ++void rtl8180_link_change(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 beacon_interval; ++ ++ struct ieee80211_network *net = &priv->ieee80211->current_network; ++// rtl8180_adapter_start(dev); ++ rtl8180_update_msr(dev); ++ ++ ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ ++ write_nic_dword(dev,BSSID,((u32*)net->bssid)[0]); ++ write_nic_word(dev,BSSID+4,((u16*)net->bssid)[2]); ++ ++ ++ beacon_interval = read_nic_dword(dev,BEACON_INTERVAL); ++ beacon_interval &= ~ BEACON_INTERVAL_MASK; ++ beacon_interval |= net->beacon_interval; ++ write_nic_dword(dev, BEACON_INTERVAL, beacon_interval); ++ ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ ++ ++ /* ++ u16 atim = read_nic_dword(dev,ATIM); ++ u16 = u16 &~ ATIM_MASK; ++ u16 = u16 | beacon->atim; ++ */ ++#if 0 ++ if (net->capability & WLAN_CAPABILITY_PRIVACY) { ++ if (priv->hw_wep) { ++ DMESG("Enabling hardware WEP support"); ++ rtl8180_set_hw_wep(dev); ++ priv->ieee80211->host_encrypt=0; ++ priv->ieee80211->host_decrypt=0; ++ } ++#ifndef CONFIG_IEEE80211_NOWEP ++ else { ++ priv->ieee80211->host_encrypt=1; ++ priv->ieee80211->host_decrypt=1; ++ } ++#endif ++ } ++#ifndef CONFIG_IEEE80211_NOWEP ++ else{ ++ priv->ieee80211->host_encrypt=0; ++ priv->ieee80211->host_decrypt=0; ++ } ++#endif ++#endif ++ ++ ++ if(priv->card_8185) ++ rtl8180_set_chan(dev, priv->chan); ++ ++ ++} ++ ++void rtl8180_rq_tx_ack(struct net_device *dev){ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++// printk("====================>%s\n",__FUNCTION__); ++ write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)|CONFIG4_PWRMGT); ++ priv->ack_tx_to_ieee = 1; ++} ++ ++short rtl8180_is_tx_queue_empty(struct net_device *dev){ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32* d; ++ ++ for (d = priv->txmapring; ++ d < priv->txmapring + priv->txringcount;d+=8) ++ if(*d & (1<<31)) return 0; ++ ++ for (d = priv->txbkpring; ++ d < priv->txbkpring + priv->txringcount;d+=8) ++ if(*d & (1<<31)) return 0; ++ ++ for (d = priv->txbepring; ++ d < priv->txbepring + priv->txringcount;d+=8) ++ if(*d & (1<<31)) return 0; ++ ++ for (d = priv->txvipring; ++ d < priv->txvipring + priv->txringcount;d+=8) ++ if(*d & (1<<31)) return 0; ++ ++ for (d = priv->txvopring; ++ d < priv->txvopring + priv->txringcount;d+=8) ++ if(*d & (1<<31)) return 0; ++ ++ for (d = priv->txhpring; ++ d < priv->txhpring + priv->txringcount;d+=8) ++ if(*d & (1<<31)) return 0; ++ return 1; ++} ++/* FIXME FIXME 5msecs is random */ ++#define HW_WAKE_DELAY 5 ++ ++void rtl8180_hw_wakeup(struct net_device *dev) ++{ ++ unsigned long flags; ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ spin_lock_irqsave(&priv->ps_lock,flags); ++ //DMESG("Waken up!"); ++ write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)&~CONFIG4_PWRMGT); ++ ++ if(priv->rf_wakeup) ++ priv->rf_wakeup(dev); ++// mdelay(HW_WAKE_DELAY); ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++} ++ ++void rtl8180_hw_sleep_down(struct net_device *dev) ++{ ++ unsigned long flags; ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ spin_lock_irqsave(&priv->ps_lock,flags); ++ //DMESG("Sleep!"); ++ ++ if(priv->rf_sleep) ++ priv->rf_sleep(dev); ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++} ++ ++ ++void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ u32 rb = jiffies; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->ps_lock,flags); ++ ++ /* Writing HW register with 0 equals to disable ++ * the timer, that is not really what we want ++ */ ++ tl -= MSECS(4+16+7); ++ ++ //if(tl == 0) tl = 1; ++ ++ /* FIXME HACK FIXME HACK */ ++// force_pci_posting(dev); ++ //mdelay(1); ++ ++// rb = read_nic_dword(dev, TSFTR); ++ ++ /* If the interval in witch we are requested to sleep is too ++ * short then give up and remain awake ++ */ ++ if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME)) ++ ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) { ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++ printk("too short to sleep\n"); ++ return; ++ } ++ ++// write_nic_dword(dev, TimerInt, tl); ++// rb = read_nic_dword(dev, TSFTR); ++ { ++ u32 tmp = (tl>rb)?(tl-rb):(rb-tl); ++ // if (tlDozePeriodInPast2Sec += jiffies_to_msecs(tmp); ++ ++ queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb ++ } ++ /* if we suspect the TimerInt is gone beyond tl ++ * while setting it, then give up ++ */ ++#if 1 ++ if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))|| ++ ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) { ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++ return; ++ } ++#endif ++// if(priv->rf_sleep) ++// priv->rf_sleep(dev); ++ ++ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq); ++ spin_unlock_irqrestore(&priv->ps_lock,flags); ++} ++ ++ ++//void rtl8180_wmm_param_update(struct net_device *dev,u8 *ac_param) ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_wmm_param_update(struct work_struct * work) ++{ ++ struct ieee80211_device * ieee = container_of(work, struct ieee80211_device,wmm_param_update_wq); ++ //struct r8180_priv *priv = (struct r8180_priv*)(ieee->priv); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_wmm_param_update(struct ieee80211_device *ieee) ++{ ++ struct net_device *dev = ieee->dev; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ u8 *ac_param = (u8 *)(ieee->current_network.wmm_param); ++ u8 mode = ieee->current_network.mode; ++ AC_CODING eACI; ++ AC_PARAM AcParam; ++ PAC_PARAM pAcParam; ++ u8 i; ++ ++#ifndef CONFIG_RTL8185B ++ //for legacy 8185 keep the PARAM unchange. ++ return; ++#else ++ if(!ieee->current_network.QoS_Enable){ ++ //legacy ac_xx_param update ++ AcParam.longData = 0; ++ AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. ++ AcParam.f.AciAifsn.f.ACM = 0; ++ AcParam.f.Ecw.f.ECWmin = 3; // Follow 802.11 CWmin. ++ AcParam.f.Ecw.f.ECWmax = 7; // Follow 802.11 CWmax. ++ AcParam.f.TXOPLimit = 0; ++ for(eACI = 0; eACI < AC_MAX; eACI++){ ++ AcParam.f.AciAifsn.f.ACI = (u8)eACI; ++ { ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ pAcParam = (PAC_PARAM)(&AcParam); ++ // Retrive paramters to udpate. ++ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN *(((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; ++ u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<f.Ecw.f.ECWmax))<f.Ecw.f.ECWmin))<f.AciAifsn.f.ACI; ++ //Mode G/A: slotTimeTimer = 9; Mode B: 20 ++ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime; ++ u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | ++ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); ++ ++ switch(eACI){ ++ case AC1_BK: ++ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); ++ break; ++ ++ case AC0_BE: ++ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); ++ break; ++ ++ case AC2_VI: ++ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); ++ break; ++ ++ case AC3_VO: ++ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); ++ break; ++ ++ default: ++ printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI); ++ break; ++ } ++ } ++ ac_param += (sizeof(AC_PARAM)); ++ } ++#endif ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_tx_irq_wq(struct work_struct *work); ++#else ++void rtl8180_tx_irq_wq(struct net_device *dev); ++#endif ++ ++ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_restart_wq(struct work_struct *work); ++//void rtl8180_rq_tx_ack(struct work_struct *work); ++#else ++ void rtl8180_restart_wq(struct net_device *dev); ++//void rtl8180_rq_tx_ack(struct net_device *dev); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_watch_dog_wq(struct work_struct *work); ++#else ++void rtl8180_watch_dog_wq(struct net_device *dev); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_wakeup_wq(struct work_struct *work); ++#else ++void rtl8180_hw_wakeup_wq(struct net_device *dev); ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_sleep_wq(struct work_struct *work); ++#else ++void rtl8180_hw_sleep_wq(struct net_device *dev); ++#endif ++ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_sw_antenna_wq(struct work_struct *work); ++#else ++void rtl8180_sw_antenna_wq(struct net_device *dev); ++#endif ++ void rtl8180_watch_dog(struct net_device *dev); ++void watch_dog_adaptive(unsigned long data) ++{ ++ struct r8180_priv* priv = ieee80211_priv((struct net_device *)data); ++// DMESG("---->watch_dog_adaptive()\n"); ++ if(!priv->up) ++ { ++ DMESG("<----watch_dog_adaptive():driver is not up!\n"); ++ return; ++ } ++ ++ // queue_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq); ++//{by amy 080312 ++#if 1 ++ // Tx High Power Mechanism. ++#ifdef HIGH_POWER ++ if(CheckHighPower((struct net_device *)data)) ++ { ++ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq); ++ } ++#endif ++ ++#ifdef CONFIG_RTL818X_S ++ // Tx Power Tracking on 87SE. ++#ifdef TX_TRACK ++ //if( priv->bTxPowerTrack ) //lzm mod 080826 ++ if( CheckTxPwrTracking((struct net_device *)data)); ++ TxPwrTracking87SE((struct net_device *)data); ++#endif ++#endif ++ ++ // Perform DIG immediately. ++#ifdef SW_DIG ++ if(CheckDig((struct net_device *)data) == true) ++ { ++ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq); ++ } ++#endif ++#endif ++//by amy 080312} ++ rtl8180_watch_dog((struct net_device *)data); ++ ++ ++ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem); ++ ++ priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME); ++ add_timer(&priv->watch_dog_timer); ++// DMESG("<----watch_dog_adaptive()\n"); ++} ++ ++#ifdef ENABLE_DOT11D ++ ++static CHANNEL_LIST ChannelPlan[] = { ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC ++ {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI. ++ {{14,36,40,44,48,52,56,60,64},9}, //MKK ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} //world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 ++}; ++ ++static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee) ++{ ++ int i; ++ ++ //lzm add 080826 ++ ieee->MinPassiveChnlNum=MAX_CHANNEL_NUMBER+1; ++ ieee->IbssStartChnl=0; ++ ++ switch (channel_plan) ++ { ++ case COUNTRY_CODE_FCC: ++ case COUNTRY_CODE_IC: ++ case COUNTRY_CODE_ETSI: ++ case COUNTRY_CODE_SPAIN: ++ case COUNTRY_CODE_FRANCE: ++ case COUNTRY_CODE_MKK: ++ case COUNTRY_CODE_MKK1: ++ case COUNTRY_CODE_ISRAEL: ++ case COUNTRY_CODE_TELEC: ++ { ++ Dot11d_Init(ieee); ++ ieee->bGlobalDomain = false; ++ if (ChannelPlan[channel_plan].Len != 0){ ++ // Clear old channel map ++ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); ++ // Set new channel map ++ for (i=0;ichannel_map[ChannelPlan[channel_plan].Channel[i]] = 1; ++ } ++ } ++ break; ++ } ++ case COUNTRY_CODE_GLOBAL_DOMAIN: ++ { ++ GET_DOT11D_INFO(ieee)->bEnabled = 0; ++ Dot11d_Reset(ieee); ++ ieee->bGlobalDomain = true; ++ break; ++ } ++ case COUNTRY_CODE_WORLD_WIDE_13_INDEX://lzm add 080826 ++ { ++ ieee->MinPassiveChnlNum=12; ++ ieee->IbssStartChnl= 10; ++ break; ++ } ++ default: ++ { ++ Dot11d_Init(ieee); ++ ieee->bGlobalDomain = false; ++ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); ++ for (i=1;i<=14;i++) ++ { ++ GET_DOT11D_INFO(ieee)->channel_map[i] = 1; ++ } ++ break; ++ } ++ } ++} ++#endif ++ ++//Add for RF power on power off by lizhaoming 080512 ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void GPIOChangeRFWorkItemCallBack(struct work_struct *work); ++#else ++void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee); ++#endif ++ ++//YJ,add,080828 ++static void rtl8180_statistics_init(struct Stats *pstats) ++{ ++ memset(pstats, 0, sizeof(struct Stats)); ++} ++static void rtl8180_link_detect_init(plink_detect_t plink_detect) ++{ ++ memset(plink_detect, 0, sizeof(link_detect_t)); ++ plink_detect->SlotNum = DEFAULT_SLOT_NUM; ++} ++//YJ,add,080828,end ++ ++short rtl8180_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 word; ++ u16 version; ++ u8 hw_version; ++ //u8 config3; ++ u32 usValue; ++ u16 tmpu16; ++ int i, j; ++ ++#ifdef ENABLE_DOT11D ++#if 0 ++ for(i=0;i<0xFF;i++) { ++ if(i%16 == 0) ++ printk("\n[%x]: ", i/16); ++ printk("\t%4.4x", eprom_read(dev,i)); ++ } ++#endif ++ priv->channel_plan = eprom_read(dev, EEPROM_COUNTRY_CODE>>1) & 0xFF; ++ if(priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN){ ++ printk("rtl8180_init:Error channel plan! Set to default.\n"); ++ priv->channel_plan = 0; ++ } ++ //priv->channel_plan = 9; //Global Domain ++ ++ DMESG("Channel plan is %d\n",priv->channel_plan); ++ rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211); ++#else ++ int ch; ++ //Set Default Channel Plan ++ if(!channels){ ++ DMESG("No channels, aborting"); ++ return -1; ++ } ++ ch=channels; ++ priv->channel_plan = 0;//hikaru ++ // set channels 1..14 allowed in given locale ++ for (i=1; i<=14; i++) { ++ (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01); ++ ch >>= 1; ++ } ++#endif ++ ++ //memcpy(priv->stats,0,sizeof(struct Stats)); ++ ++ //FIXME: these constants are placed in a bad pleace. ++ priv->txbuffsize = 2048;//1024; ++ priv->txringcount = 32;//32; ++ priv->rxbuffersize = 2048;//1024; ++ priv->rxringcount = 64;//32; ++ priv->txbeaconcount = 2; ++ priv->rx_skb_complete = 1; ++ //priv->txnp_pending.ispending=0; ++ /* ^^ the SKB does not containt a partial RXed ++ * packet (is empty) ++ */ ++ ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ priv->RegThreeWireMode = HW_THREE_WIRE_SI; ++#else ++ priv->RegThreeWireMode = SW_THREE_WIRE; ++#endif ++#endif ++ ++//Add for RF power on power off by lizhaoming 080512 ++ priv->RFChangeInProgress = false; ++ priv->SetRFPowerStateInProgress = false; ++ priv->RFProgType = 0; ++ priv->bInHctTest = false; ++ ++ priv->irq_enabled=0; ++ ++//YJ,modified,080828 ++#if 0 ++ priv->stats.rxdmafail=0; ++ priv->stats.txrdu=0; ++ priv->stats.rxrdu=0; ++ priv->stats.rxnolast=0; ++ priv->stats.rxnodata=0; ++ //priv->stats.rxreset=0; ++ //priv->stats.rxwrkaround=0; ++ priv->stats.rxnopointer=0; ++ priv->stats.txnperr=0; ++ priv->stats.txresumed=0; ++ priv->stats.rxerr=0; ++ priv->stats.rxoverflow=0; ++ priv->stats.rxint=0; ++ priv->stats.txnpokint=0; ++ priv->stats.txhpokint=0; ++ priv->stats.txhperr=0; ++ priv->stats.ints=0; ++ priv->stats.shints=0; ++ priv->stats.txoverflow=0; ++ priv->stats.txbeacon=0; ++ priv->stats.txbeaconerr=0; ++ priv->stats.txlperr=0; ++ priv->stats.txlpokint=0; ++ priv->stats.txretry=0;//tony 20060601 ++ priv->stats.rxcrcerrmin=0; ++ priv->stats.rxcrcerrmid=0; ++ priv->stats.rxcrcerrmax=0; ++ priv->stats.rxicverr=0; ++#else ++ rtl8180_statistics_init(&priv->stats); ++ rtl8180_link_detect_init(&priv->link_detect); ++#endif ++//YJ,modified,080828,end ++ ++ ++ priv->ack_tx_to_ieee = 0; ++ priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; ++ priv->ieee80211->iw_mode = IW_MODE_INFRA; ++ priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | ++ IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | ++ IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; ++ priv->ieee80211->active_scan = 1; ++ priv->ieee80211->rate = 110; //11 mbps ++ priv->ieee80211->modulation = IEEE80211_CCK_MODULATION; ++ priv->ieee80211->host_encrypt = 1; ++ priv->ieee80211->host_decrypt = 1; ++ priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup; ++ priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack; ++ priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep; ++ priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty; ++ ++ priv->hw_wep = hwwep; ++ priv->prism_hdr=0; ++ priv->dev=dev; ++ priv->retry_rts = DEFAULT_RETRY_RTS; ++ priv->retry_data = DEFAULT_RETRY_DATA; ++ priv->RFChangeInProgress = false; ++ priv->SetRFPowerStateInProgress = false; ++ priv->RFProgType = 0; ++ priv->bInHctTest = false; ++ priv->bInactivePs = true;//false; ++ priv->ieee80211->bInactivePs = priv->bInactivePs; ++ priv->bSwRfProcessing = false; ++ priv->eRFPowerState = eRfOff; ++ priv->RfOffReason = 0; ++ priv->LedStrategy = SW_LED_MODE0; ++ //priv->NumRxOkInPeriod = 0; //YJ,del,080828 ++ //priv->NumTxOkInPeriod = 0; //YJ,del,080828 ++ priv->TxPollingTimes = 0;//lzm add 080826 ++ priv->bLeisurePs = true; ++ priv->dot11PowerSaveMode = eActive; ++//by amy for antenna ++ priv->AdMinCheckPeriod = 5; ++ priv->AdMaxCheckPeriod = 10; ++// Lower signal strength threshold to fit the HW participation in antenna diversity. +by amy 080312 ++ priv->AdMaxRxSsThreshold = 30;//60->30 ++ priv->AdRxSsThreshold = 20;//50->20 ++ priv->AdCheckPeriod = priv->AdMinCheckPeriod; ++ priv->AdTickCount = 0; ++ priv->AdRxSignalStrength = -1; ++ priv->RegSwAntennaDiversityMechanism = 0; ++ priv->RegDefaultAntenna = 0; ++ priv->SignalStrength = 0; ++ priv->AdRxOkCnt = 0; ++ priv->CurrAntennaIndex = 0; ++ priv->AdRxSsBeforeSwitched = 0; ++ init_timer(&priv->SwAntennaDiversityTimer); ++ priv->SwAntennaDiversityTimer.data = (unsigned long)dev; ++ priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback; ++//by amy for antenna ++//{by amy 080312 ++ priv->bDigMechanism = 1; ++ priv->InitialGain = 6; ++ priv->bXtalCalibration = false; ++ priv->XtalCal_Xin = 0; ++ priv->XtalCal_Xout = 0; ++ priv->bTxPowerTrack = false; ++ priv->ThermalMeter = 0; ++ priv->FalseAlarmRegValue = 0; ++ priv->RegDigOfdmFaUpTh = 0xc; // Upper threhold of OFDM false alarm, which is used in DIG. ++ priv->DIG_NumberFallbackVote = 0; ++ priv->DIG_NumberUpgradeVote = 0; ++ priv->LastSignalStrengthInPercent = 0; ++ priv->Stats_SignalStrength = 0; ++ priv->LastRxPktAntenna = 0; ++ priv->SignalQuality = 0; // in 0-100 index. ++ priv->Stats_SignalQuality = 0; ++ priv->RecvSignalPower = 0; // in dBm. ++ priv->Stats_RecvSignalPower = 0; ++ priv->AdMainAntennaRxOkCnt = 0; ++ priv->AdAuxAntennaRxOkCnt = 0; ++ priv->bHWAdSwitched = false; ++ priv->bRegHighPowerMechanism = true; ++ priv->RegHiPwrUpperTh = 77; ++ priv->RegHiPwrLowerTh = 75; ++ priv->RegRSSIHiPwrUpperTh = 70; ++ priv->RegRSSIHiPwrLowerTh = 20; ++ priv->bCurCCKPkt = false; ++ priv->UndecoratedSmoothedSS = -1; ++ priv->bToUpdateTxPwr = false; ++ priv->CurCCKRSSI = 0; ++ priv->RxPower = 0; ++ priv->RSSI = 0; ++ //YJ,add,080828 ++ priv->NumTxOkTotal = 0; ++ priv->NumTxUnicast = 0; ++ priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL; ++ priv->PowerProfile = POWER_PROFILE_AC; ++ //YJ,add,080828,end ++//by amy for rate adaptive ++ priv->CurrRetryCnt=0; ++ priv->LastRetryCnt=0; ++ priv->LastTxokCnt=0; ++ priv->LastRxokCnt=0; ++ priv->LastRetryRate=0; ++ priv->bTryuping=0; ++ priv->CurrTxRate=0; ++ priv->CurrRetryRate=0; ++ priv->TryupingCount=0; ++ priv->TryupingCountNoData=0; ++ priv->TryDownCountLowData=0; ++ priv->LastTxOKBytes=0; ++ priv->LastFailTxRate=0; ++ priv->LastFailTxRateSS=0; ++ priv->FailTxRateCount=0; ++ priv->LastTxThroughput=0; ++ priv->NumTxOkBytesTotal=0; ++ priv->ForcedDataRate = 0; ++ priv->RegBModeGainStage = 1; ++ ++//by amy for rate adaptive ++//by amy 080312} ++ priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0; ++ spin_lock_init(&priv->irq_lock); ++ spin_lock_init(&priv->irq_th_lock); ++ spin_lock_init(&priv->tx_lock); ++ spin_lock_init(&priv->ps_lock); ++ spin_lock_init(&priv->rf_ps_lock); ++ sema_init(&priv->wx_sem,1); ++ sema_init(&priv->rf_state,1); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++ INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq); ++ INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq); ++ INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq); ++ INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq); ++ //INIT_DELAYED_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq); ++ //INIT_DELAYED_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq); ++ INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update); ++ INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter);//+by amy 080312 ++ INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq);//+by amy 080312 ++ INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq);//+by amy 080312 ++ ++ //add for RF power on power off by lizhaoming 080512 ++ INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack); ++#else ++ INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev); ++ INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq,dev); ++ //INIT_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq,dev); ++ INIT_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq,dev); ++ INIT_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq,dev); ++ //INIT_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq,dev); ++ INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update,priv->ieee80211); ++ INIT_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter,dev);//+by amy 080312 ++ INIT_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq,dev);//+by amy 080312 ++ INIT_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq,dev);//+by amy 080312 ++ ++ //add for RF power on power off by lizhaoming 080512 ++ INIT_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack, priv->ieee80211); ++#endif ++ //INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev); ++ ++ tasklet_init(&priv->irq_rx_tasklet, ++ (void(*)(unsigned long)) rtl8180_irq_rx_tasklet, ++ (unsigned long)priv); ++//by amy ++ init_timer(&priv->watch_dog_timer); ++ priv->watch_dog_timer.data = (unsigned long)dev; ++ priv->watch_dog_timer.function = watch_dog_adaptive; ++//by amy ++ ++//{by amy 080312 ++//by amy for rate adaptive ++ init_timer(&priv->rateadapter_timer); ++ priv->rateadapter_timer.data = (unsigned long)dev; ++ priv->rateadapter_timer.function = timer_rate_adaptive; ++ priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD; ++ priv->bEnhanceTxPwr=false; ++//by amy for rate adaptive ++//by amy 080312} ++ //priv->ieee80211->func = ++ // kmalloc(sizeof(struct ieee80211_helper_functions),GFP_KERNEL); ++ //memset(priv->ieee80211->func, 0, ++ // sizeof(struct ieee80211_helper_functions)); ++ ++ priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit; ++ priv->ieee80211->set_chan = rtl8180_set_chan; ++ priv->ieee80211->link_change = rtl8180_link_change; ++ priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit; ++ priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop; ++ priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume; ++ ++ priv->ieee80211->init_wmmparam_flag = 0; ++ ++ priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon; ++ priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable; ++ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; ++ ++#ifdef CONFIG_RTL8185B ++ priv->MWIEnable = 0; ++ ++ priv->ShortRetryLimit = 7; ++ priv->LongRetryLimit = 7; ++ priv->EarlyRxThreshold = 7; ++ ++ priv->CSMethod = (0x01 << 29); ++ ++ priv->TransmitConfig = ++ 1<ShortRetryLimit<LongRetryLimit<ReceiveConfig = ++#ifdef CONFIG_RTL818X_S ++#else ++ priv->CSMethod | ++#endif ++// RCR_ENMARP | ++ RCR_AMF | RCR_ADF | //accept management/data ++ RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko. ++ RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC ++ //RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet ++ (7<EarlyRxThreshold<EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0); ++ ++ priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER | ++ IMR_THPDER | IMR_THPDOK | ++ IMR_TVODER | IMR_TVODOK | ++ IMR_TVIDER | IMR_TVIDOK | ++ IMR_TBEDER | IMR_TBEDOK | ++ IMR_TBKDER | IMR_TBKDOK | ++ IMR_RDU | // To handle the defragmentation not enough Rx descriptors case. Annie, 2006-03-27. ++ IMR_RER | IMR_ROK | ++ IMR_RQoSOK; // ROK and RQoSOK are mutually exclusive, so, we must handle RQoSOK interrupt to receive QoS frames, 2005.12.09, by rcnjko. ++ ++ priv->InitialGain = 6; ++#endif ++ ++ hw_version =( read_nic_dword(dev, TCR) & TCR_HWVERID_MASK)>>TCR_HWVERID_SHIFT; ++ ++ switch (hw_version){ ++#ifdef CONFIG_RTL8185B ++ case HW_VERID_R8185B_B: ++#ifdef CONFIG_RTL818X_S ++ priv->card_8185 = VERSION_8187S_C; ++ DMESG("MAC controller is a RTL8187SE b/g"); ++ priv->phy_ver = 2; ++ break; ++#else ++ DMESG("MAC controller is a RTL8185B b/g"); ++ priv->card_8185 = 3; ++ priv->phy_ver = 2; ++ break; ++#endif ++#endif ++ case HW_VERID_R8185_ABC: ++ DMESG("MAC controller is a RTL8185 b/g"); ++ priv->card_8185 = 1; ++ /* you should not find a card with 8225 PHY ver < C*/ ++ priv->phy_ver = 2; ++ break; ++ ++ case HW_VERID_R8185_D: ++ DMESG("MAC controller is a RTL8185 b/g (V. D)"); ++ priv->card_8185 = 2; ++ /* you should not find a card with 8225 PHY ver < C*/ ++ priv->phy_ver = 2; ++ break; ++ ++ case HW_VERID_R8180_ABCD: ++ DMESG("MAC controller is a RTL8180"); ++ priv->card_8185 = 0; ++ break; ++ ++ case HW_VERID_R8180_F: ++ DMESG("MAC controller is a RTL8180 (v. F)"); ++ priv->card_8185 = 0; ++ break; ++ ++ default: ++ DMESGW("MAC chip not recognized: version %x. Assuming RTL8180",hw_version); ++ priv->card_8185 = 0; ++ break; ++ } ++ ++ if(priv->card_8185){ ++ priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION; ++ priv->ieee80211->short_slot = 1; ++ } ++ /* you should not found any 8185 Ver B Card */ ++ priv->card_8185_Bversion = 0; ++ ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ // just for sync 85 ++ priv->card_type = PCI; ++ DMESG("This is a PCI NIC"); ++#else ++ config3 = read_nic_byte(dev, CONFIG3); ++ if(config3 & 0x8){ ++ priv->card_type = CARDBUS; ++ DMESG("This is a CARDBUS NIC"); ++ } ++ else if( config3 & 0x4){ ++ priv->card_type = MINIPCI; ++ DMESG("This is a MINI-PCI NIC"); ++ }else{ ++ priv->card_type = PCI; ++ DMESG("This is a PCI NIC"); ++ } ++#endif ++#endif ++ priv->enable_gpio0 = 0; ++ ++//by amy for antenna ++#ifdef CONFIG_RTL8185B ++ usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET); ++ DMESG("usValue is 0x%x\n",usValue); ++#ifdef CONFIG_RTL818X_S ++ //3Read AntennaDiversity ++ // SW Antenna Diversity. ++ if( (usValue & EEPROM_SW_AD_MASK) != EEPROM_SW_AD_ENABLE ) ++ { ++ priv->EEPROMSwAntennaDiversity = false; ++ //printk("EEPROM Disable SW Antenna Diversity\n"); ++ } ++ else ++ { ++ priv->EEPROMSwAntennaDiversity = true; ++ //printk("EEPROM Enable SW Antenna Diversity\n"); ++ } ++ // Default Antenna to use. ++ if( (usValue & EEPROM_DEF_ANT_MASK) != EEPROM_DEF_ANT_1 ) ++ { ++ priv->EEPROMDefaultAntenna1 = false; ++ //printk("EEPROM Default Antenna 0\n"); ++ } ++ else ++ { ++ priv->EEPROMDefaultAntenna1 = true; ++ //printk("EEPROM Default Antenna 1\n"); ++ } ++ ++ // ++ // Antenna diversity mechanism. Added by Roger, 2007.11.05. ++ // ++ if( priv->RegSwAntennaDiversityMechanism == 0 ) // Auto ++ {// 0: default from EEPROM. ++ priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity; ++ } ++ else ++ {// 1:disable antenna diversity, 2: enable antenna diversity. ++ priv->bSwAntennaDiverity = ((priv->RegSwAntennaDiversityMechanism == 1)? false : true); ++ } ++ //printk("bSwAntennaDiverity = %d\n", priv->bSwAntennaDiverity); ++ ++ ++ // ++ // Default antenna settings. Added by Roger, 2007.11.05. ++ // ++ if( priv->RegDefaultAntenna == 0) ++ {// 0: default from EEPROM. ++ priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1; ++ } ++ else ++ {// 1: main, 2: aux. ++ priv->bDefaultAntenna1 = ((priv->RegDefaultAntenna== 2) ? true : false); ++ } ++ //printk("bDefaultAntenna1 = %d\n", priv->bDefaultAntenna1); ++#endif ++#endif ++//by amy for antenna ++ /* rtl8185 can calc plcp len in HW.*/ ++ priv->hw_plcp_len = 1; ++ ++ priv->plcp_preamble_mode = 2; ++ /*the eeprom type is stored in RCR register bit #6 */ ++ if (RCR_9356SEL & read_nic_dword(dev, RCR)){ ++ priv->epromtype=EPROM_93c56; ++ //DMESG("Reported EEPROM chip is a 93c56 (2Kbit)"); ++ }else{ ++ priv->epromtype=EPROM_93c46; ++ //DMESG("Reported EEPROM chip is a 93c46 (1Kbit)"); ++ } ++ ++ dev->get_stats = rtl8180_stats; ++ ++ dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff; ++ dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8; ++ dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff; ++ dev->dev_addr[3]=(eprom_read(dev,MAC_ADR+1) & 0xff00)>>8; ++ dev->dev_addr[4]=eprom_read(dev,MAC_ADR+2) & 0xff; ++ dev->dev_addr[5]=(eprom_read(dev,MAC_ADR+2) & 0xff00)>>8; ++ //DMESG("Card MAC address is "MAC_FMT, MAC_ARG(dev->dev_addr)); ++ ++ ++ for(i=1,j=0; i<14; i+=2,j++){ ++ ++ word = eprom_read(dev,EPROM_TXPW_CH1_2 + j); ++ priv->chtxpwr[i]=word & 0xff; ++ priv->chtxpwr[i+1]=(word & 0xff00)>>8; ++#ifdef DEBUG_EPROM ++ DMESG("tx word %x:%x",j,word); ++ DMESG("ch %d pwr %x",i,priv->chtxpwr[i]); ++ DMESG("ch %d pwr %x",i+1,priv->chtxpwr[i+1]); ++#endif ++ } ++ if(priv->card_8185){ ++ for(i=1,j=0; i<14; i+=2,j++){ ++ ++ word = eprom_read(dev,EPROM_TXPW_OFDM_CH1_2 + j); ++ priv->chtxpwr_ofdm[i]=word & 0xff; ++ priv->chtxpwr_ofdm[i+1]=(word & 0xff00)>>8; ++#ifdef DEBUG_EPROM ++ DMESG("ofdm tx word %x:%x",j,word); ++ DMESG("ofdm ch %d pwr %x",i,priv->chtxpwr_ofdm[i]); ++ DMESG("ofdm ch %d pwr %x",i+1,priv->chtxpwr_ofdm[i+1]); ++#endif ++ } ++ } ++//{by amy 080312 ++ //3Read crystal calibtration and thermal meter indication on 87SE. ++ ++ // By SD3 SY's request. Added by Roger, 2007.12.11. ++ ++ tmpu16 = eprom_read(dev, EEPROM_RSV>>1); ++ ++ //printk("ReadAdapterInfo8185(): EEPROM_RSV(%04x)\n", tmpu16); ++ ++ // Crystal calibration for Xin and Xout resp. ++ priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK; // 0~7.5pF ++ priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK)>>4; // 0~7.5pF ++ if((tmpu16 & EEPROM_XTAL_CAL_ENABLE)>>12) ++ priv->bXtalCalibration = true; ++ ++ // Thermal meter reference indication. ++ priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK)>>8); ++ if((tmpu16 & EEPROM_THERMAL_METER_ENABLE)>>13) ++ priv->bTxPowerTrack = true; ++ ++//by amy 080312} ++#ifdef CONFIG_RTL8185B ++ word = eprom_read(dev,EPROM_TXPW_BASE); ++ priv->cck_txpwr_base = word & 0xf; ++ priv->ofdm_txpwr_base = (word>>4) & 0xf; ++#endif ++ ++ version = eprom_read(dev,EPROM_VERSION); ++ DMESG("EEPROM version %x",version); ++ if( (!priv->card_8185) && version < 0x0101){ ++ DMESG ("EEPROM version too old, assuming defaults"); ++ DMESG ("If you see this message *plase* send your \ ++DMESG output to andreamrl@tiscali.it THANKS"); ++ priv->digphy=1; ++ priv->antb=0; ++ priv->diversity=1; ++ priv->cs_treshold=0xc; ++ priv->rcr_csense=1; ++ priv->rf_chip=RFCHIPID_PHILIPS; ++ }else{ ++ if(!priv->card_8185){ ++ u8 rfparam = eprom_read(dev,RF_PARAM); ++ DMESG("RfParam: %x",rfparam); ++ ++ priv->digphy = rfparam & (1<antb = rfparam & (1<rcr_csense = (rfparam & RF_PARAM_CARRIERSENSE_MASK) >> ++ RF_PARAM_CARRIERSENSE_SHIFT; ++ ++ priv->diversity = ++ (read_nic_byte(dev,CONFIG2)&(1<rcr_csense = 3; ++ } ++ ++ priv->cs_treshold = (eprom_read(dev,ENERGY_TRESHOLD)&0xff00) >>8; ++ ++ priv->rf_chip = 0xff & eprom_read(dev,RFCHIPID); ++ } ++ ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ priv->rf_chip = RF_ZEBRA4; ++ priv->rf_sleep = rtl8225z4_rf_sleep; ++ priv->rf_wakeup = rtl8225z4_rf_wakeup; ++#else ++ priv->rf_chip = RF_ZEBRA2; ++#endif ++ //DMESG("Card reports RF frontend Realtek 8225z2"); ++ //DMESGW("This driver has EXPERIMENTAL support for this chipset."); ++ //DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!"); ++ ++ priv->rf_close = rtl8225z2_rf_close; ++ priv->rf_init = rtl8225z2_rf_init; ++ priv->rf_set_chan = rtl8225z2_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ //priv->rf_sleep = rtl8225_rf_sleep; ++ //priv->rf_wakeup = rtl8225_rf_wakeup; ++ ++#else ++ /* check RF frontend chipset */ ++ switch (priv->rf_chip) { ++ ++ case RFCHIPID_RTL8225: ++ ++ if(priv->card_8185){ ++ DMESG("Card reports RF frontend Realtek 8225"); ++ DMESGW("This driver has EXPERIMENTAL support for this chipset."); ++ DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); ++ ++ priv->rf_close = rtl8225_rf_close; ++ priv->rf_init = rtl8225_rf_init; ++ priv->rf_set_chan = rtl8225_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ priv->rf_sleep = rtl8225_rf_sleep; ++ priv->rf_wakeup = rtl8225_rf_wakeup; ++ ++ }else{ ++ DMESGW("Detected RTL8225 radio on a card recognized as RTL8180"); ++ DMESGW("This could not be... something went wrong...."); ++ return -ENODEV; ++ } ++ break; ++ ++ case RFCHIPID_RTL8255: ++ if(priv->card_8185){ ++ DMESG("Card reports RF frontend Realtek 8255"); ++ DMESGW("This driver has EXPERIMENTAL support for this chipset."); ++ DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); ++ ++ priv->rf_close = rtl8255_rf_close; ++ priv->rf_init = rtl8255_rf_init; ++ priv->rf_set_chan = rtl8255_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ priv->rf_sleep = NULL; ++ priv->rf_wakeup = NULL; ++ ++ }else{ ++ DMESGW("Detected RTL8255 radio on a card recognized as RTL8180"); ++ DMESGW("This could not be... something went wrong...."); ++ return -ENODEV; ++ } ++ break; ++ ++ ++ case RFCHIPID_INTERSIL: ++ DMESGW("Card reports RF frontend by Intersil."); ++ DMESGW("This driver has NO support for this chipset."); ++ return -ENODEV; ++ break; ++ ++ case RFCHIPID_RFMD: ++ DMESGW("Card reports RF frontend by RFMD."); ++ DMESGW("This driver has NO support for this chipset."); ++ return -ENODEV; ++ break; ++ ++ case RFCHIPID_GCT: ++ DMESGW("Card reports RF frontend by GCT."); ++ DMESGW("This driver has EXPERIMENTAL support for this chipset."); ++ DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); ++ priv->rf_close = gct_rf_close; ++ priv->rf_init = gct_rf_init; ++ priv->rf_set_chan = gct_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ priv->rf_sleep = NULL; ++ priv->rf_wakeup = NULL; ++ break; ++ ++ case RFCHIPID_MAXIM: ++ DMESGW("Card reports RF frontend by MAXIM."); ++ DMESGW("This driver has EXPERIMENTAL support for this chipset."); ++ DMESGW("use it with care and at your own risk and"); ++ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it"); ++ priv->rf_close = maxim_rf_close; ++ priv->rf_init = maxim_rf_init; ++ priv->rf_set_chan = maxim_rf_set_chan; ++ priv->rf_set_sens = NULL; ++ priv->rf_sleep = NULL; ++ priv->rf_wakeup = NULL; ++ break; ++ ++ case RFCHIPID_PHILIPS: ++ DMESG("Card reports RF frontend by Philips."); ++ DMESG("OK! Philips SA2400 radio chipset is supported."); ++ priv->rf_close = sa2400_rf_close; ++ priv->rf_init = sa2400_rf_init; ++ priv->rf_set_chan = sa2400_rf_set_chan; ++ priv->rf_set_sens = sa2400_rf_set_sens; ++ priv->sens = SA2400_RF_DEF_SENS; /* default sensitivity */ ++ priv->max_sens = SA2400_RF_MAX_SENS; /* maximum sensitivity */ ++ priv->rf_sleep = NULL; ++ priv->rf_wakeup = NULL; ++ ++ if(priv->digphy){ ++ DMESGW("Digital PHY found"); ++ DMESGW("Philips DIGITAL PHY is untested! *Please*\ ++ report success/failure to "); ++ }else{ ++ DMESG ("Analog PHY found"); ++ } ++ ++ break; ++ ++ default: ++ DMESGW("Unknown RF module %x",priv->rf_chip); ++ DMESGW("Exiting..."); ++ return -1; ++ ++ } ++#endif ++ ++ ++ if(!priv->card_8185){ ++ if(priv->antb) ++ DMESG ("Antenna B is default antenna"); ++ else ++ DMESG ("Antenna A is default antenna"); ++ ++ if(priv->diversity) ++ DMESG ("Antenna diversity is enabled"); ++ else ++ DMESG("Antenna diversity is disabled"); ++ ++ DMESG("Carrier sense %d",priv->rcr_csense); ++ } ++ ++ if (0!=alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, ++ TX_MANAGEPRIORITY_RING_ADDR)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, ++ TX_BKPRIORITY_RING_ADDR)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, ++ TX_BEPRIORITY_RING_ADDR)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, ++ TX_VIPRIORITY_RING_ADDR)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, ++ TX_VOPRIORITY_RING_ADDR)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, ++ TX_HIGHPRIORITY_RING_ADDR)) ++ return -ENOMEM; ++ ++ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount, ++ TX_BEACON_RING_ADDR)) ++ return -ENOMEM; ++ ++ ++ //priv->beacon_buf=NULL; ++ ++ if(!priv->card_8185){ ++ ++ if(read_nic_byte(dev, CONFIG0) & (1<irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)){ ++#else ++ if(request_irq(dev->irq, (void *)rtl8180_interrupt, SA_SHIRQ, dev->name, dev)){ ++#endif ++ DMESGE("Error allocating IRQ %d",dev->irq); ++ return -1; ++ }else{ ++ priv->irq=dev->irq; ++ DMESG("IRQ %d",dev->irq); ++ } ++ ++#ifdef DEBUG_EPROM ++ dump_eprom(dev); ++#endif ++ ++ return 0; ++ ++} ++ ++ ++void rtl8180_no_hw_wep(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(!priv->card_8185) ++ { ++ u8 security; ++ ++ security = read_nic_byte(dev, SECURITY); ++ security &=~(1<ieee80211->hw_wep=0; ++} ++ ++ ++void rtl8180_set_hw_wep(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 pgreg; ++ u8 security; ++ u32 key0_word4; ++ ++ pgreg=read_nic_byte(dev, PGSELECT); ++ write_nic_byte(dev, PGSELECT, pgreg &~ (1<key0[3]& 0xff; ++ write_nic_dword(dev,KEY0,(priv->key0[0])); ++ write_nic_dword(dev,KEY0+4,(priv->key0[1])); ++ write_nic_dword(dev,KEY0+4+4,(priv->key0[2])); ++ write_nic_dword(dev,KEY0+4+4+4,(key0_word4)); ++ ++ /* ++ TX_CONF,read_nic_dword(dev,TX_CONF) &~(1<ieee80211->hw_wep=1; ++} ++ ++ ++void rtl8185_rf_pins_enable(struct net_device *dev) ++{ ++// u16 tmp; ++// tmp = read_nic_word(dev, RFPinsEnable); ++ write_nic_word(dev, RFPinsEnable, 0x1fff);// | tmp); ++// write_nic_word(dev, RFPinsEnable,7 | tmp); ++} ++ ++ ++void rtl8185_set_anaparam2(struct net_device *dev, u32 a) ++{ ++ u8 conf3; ++ ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ ++ conf3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, conf3 | (1<> 24)); ++ write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); ++ write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); ++ write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff) )); ++#endif ++ /* this is ok to fail when we write AGC table. check for AGC table might be ++ * done by masking with 0x7f instead of 0xff ++ */ ++ //if(phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data,adr); ++} ++ ++ ++inline void write_phy_ofdm (struct net_device *dev, u8 adr, u32 data) ++{ ++ data = data & 0xff; ++ rtl8185_write_phy(dev, adr, data); ++} ++ ++ ++void write_phy_cck (struct net_device *dev, u8 adr, u32 data) ++{ ++ data = data & 0xff; ++ rtl8185_write_phy(dev, adr, data | 0x10000); ++} ++ ++ ++/* 70*3 = 210 ms ++ * I hope this is enougth ++ */ ++#define MAX_PHY 70 ++void write_phy(struct net_device *dev, u8 adr, u8 data) ++{ ++ u32 phy; ++ int i; ++ ++ phy = 0xff0000; ++ phy |= adr; ++ phy |= 0x80; /* this should enable writing */ ++ phy |= (data<<8); ++ ++ //PHY_ADR, PHY_R and PHY_W are contig and treated as one dword ++ write_nic_dword(dev,PHY_ADR, phy); ++ ++ phy= 0xffff00; ++ phy |= adr; ++ ++ write_nic_dword(dev,PHY_ADR, phy); ++ for(i=0;i> 16; ++ if(phy == data){ //SUCCESS! ++ force_pci_posting(dev); ++ mdelay(3); //random value ++#ifdef DEBUG_BB ++ DMESG("Phy wr %x,%x",adr,data); ++#endif ++ return; ++ }else{ ++ force_pci_posting(dev); ++ mdelay(3); //random value ++ } ++ } ++ DMESGW ("Phy writing %x %x failed!", adr,data); ++} ++ ++void rtl8185_set_rate(struct net_device *dev) ++{ ++ int i; ++ u16 word; ++ int basic_rate,min_rr_rate,max_rr_rate; ++ ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ //if (ieee80211_is_54g(priv->ieee80211->current_network) && ++// priv->ieee80211->state == IEEE80211_LINKED){ ++ basic_rate = ieeerate2rtlrate(240); ++ min_rr_rate = ieeerate2rtlrate(60); ++ max_rr_rate = ieeerate2rtlrate(240); ++ ++// ++// }else{ ++// basic_rate = ieeerate2rtlrate(20); ++// min_rr_rate = ieeerate2rtlrate(10); ++// max_rr_rate = ieeerate2rtlrate(110); ++// } ++ ++ write_nic_byte(dev, RESP_RATE, ++ max_rr_rate<irq_mask = 0xafff; ++// priv->irq_mask = 0x4fcf; ++ ++ /* enable beacon timeout, beacon TX ok and err ++ * LP tx ok and err, HP TX ok and err, NP TX ok and err, ++ * RX ok and ERR, and GP timer */ ++ priv->irq_mask = 0x6fcf; ++ ++ priv->dma_poll_mask = 0; ++ ++ rtl8180_beacon_tx_disable(dev); ++ ++ if(priv->card_type == CARDBUS ){ ++ config3=read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev,CONFIG3,config3 | CONFIG3_FuncRegEn); ++ write_nic_word(dev,FEMR, FEMR_INTR | FEMR_WKUP | FEMR_GWAKE | ++ read_nic_word(dev, FEMR)); ++ } ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); ++ write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ ++ rtl8180_update_msr(dev); ++ ++ if(!priv->card_8185){ ++ anaparam = eprom_read(dev,EPROM_ANAPARAM_ADDRLWORD); ++ anaparam |= eprom_read(dev,EPROM_ANAPARAM_ADDRHWORD)<<16; ++ ++ rtl8180_set_anaparam(dev,anaparam); ++ } ++ /* These might be unnecessary since we do in rx_enable / tx_enable */ ++ fix_rx_fifo(dev); ++ fix_tx_fifo(dev); ++ /*set_nic_rxring(dev); ++ set_nic_txring(dev);*/ ++ ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ ++ /* ++ The following is very strange. seems to be that 1 means test mode, ++ but we need to acknolwledges the nic when a packet is ready ++ altought we set it to 0 ++ */ ++ ++ write_nic_byte(dev, ++ CONFIG2, read_nic_byte(dev,CONFIG2) &~\ ++ (1<card_8185) ++ write_nic_byte(dev, ++ CONFIG2, read_nic_byte(dev,CONFIG2)|(1<<4)); ++ ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ ++ write_nic_dword(dev,INT_TIMEOUT,0); ++#ifdef DEBUG_REGISTERS ++ rtl8180_dump_reg(dev); ++#endif ++ ++ if(!priv->card_8185) ++ { ++ /* ++ experimental - this might be needed to calibrate AGC, ++ anyway it shouldn't hurt ++ */ ++ write_nic_byte(dev, CONFIG5, ++ read_nic_byte(dev, CONFIG5) | (1<card_8185){ ++ rtl8185_set_rate(dev); ++ write_nic_byte(dev, RATE_FALLBACK, 0x81); ++ // write_nic_byte(dev, 0xdf, 0x15); ++ }else{ ++ word = read_nic_word(dev, BRSR); ++ word &= ~BRSR_MBR; ++ word &= ~BRSR_BPLCP; ++ word |= ieeerate2rtlrate(priv->ieee80211->basic_rate); ++//by amy ++ word |= 0x0f; ++//by amy ++ write_nic_word(dev, BRSR, word); ++ } ++ ++ ++ if(priv->card_8185){ ++ write_nic_byte(dev, GP_ENABLE,read_nic_byte(dev, GP_ENABLE) & ~(1<<6)); ++ ++ //FIXME cfg 3 ClkRun enable - isn't it ReadOnly ? ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_byte(dev,CONFIG3, read_nic_byte(dev, CONFIG3) ++|(1<rf_init(dev); ++ ++ if(priv->rf_set_sens != NULL) ++ priv->rf_set_sens(dev,priv->sens); ++ rtl8180_irq_enable(dev); ++ ++ netif_start_queue(dev); ++ /*DMESG ("lfree %d",get_curr_tx_free_desc(dev,LOW_PRIORITY)); ++ ++ DMESG ("nfree %d",get_curr_tx_free_desc(dev,NORM_PRIORITY)); ++ ++ DMESG ("hfree %d",get_curr_tx_free_desc(dev,HI_PRIORITY)); ++ if(check_nic_enought_desc(dev,NORM_PRIORITY)) DMESG("NORM OK"); ++ if(check_nic_enought_desc(dev,HI_PRIORITY)) DMESG("HI OK"); ++ if(check_nic_enought_desc(dev,LOW_PRIORITY)) DMESG("LOW OK");*/ ++} ++ ++ ++ ++/* this configures registers for beacon tx and enables it via ++ * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might ++ * be used to stop beacon transmission ++ */ ++void rtl8180_start_tx_beacon(struct net_device *dev) ++{ ++// struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u16 word; ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ ++ DMESG("Enabling beacon TX"); ++ //write_nic_byte(dev, 0x42,0xe6);// TCR ++// set_nic_txring(dev); ++// fix_tx_fifo(dev); ++ rtl8180_prepare_beacon(dev); ++ rtl8180_irq_disable(dev); ++ rtl8180_beacon_tx_enable(dev); ++#if 0 ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ //write_nic_byte(dev,0x9d,0x20); //DMA Poll ++ //write_nic_word(dev,0x7a,0); ++ //write_nic_word(dev,0x7a,0x8000); ++ ++#if 0 ++ word = read_nic_word(dev, BcnItv); ++ word &= ~BcnItv_BcnItv; // clear Bcn_Itv ++ word |= priv->ieee80211->current_network.beacon_interval;//0x64; ++ write_nic_word(dev, BcnItv, word); ++#endif ++#endif ++ word = read_nic_word(dev, AtimWnd) &~ AtimWnd_AtimWnd; ++ write_nic_word(dev, AtimWnd,word);// word |= ++//priv->ieee80211->current_network.atim_window); ++ ++ word = read_nic_word(dev, BintrItv); ++ word &= ~BintrItv_BintrItv; ++ word |= 1000;/*priv->ieee80211->current_network.beacon_interval * ++ ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); ++ // FIXME: check if correct ^^ worked with 0x3e8; ++ */ ++ write_nic_word(dev, BintrItv, word); ++ ++ ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ ++// rtl8180_beacon_tx_enable(dev); ++#ifdef CONFIG_RTL8185B ++ rtl8185b_irq_enable(dev); ++#else ++ rtl8180_irq_enable(dev); ++#endif ++ /* VV !!!!!!!!!! VV*/ ++ /* ++ rtl8180_set_mode(dev,EPROM_CMD_CONFIG); ++ write_nic_byte(dev,0x9d,0x00); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++*/ ++// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA)); ++ ++} ++ ++ ++ ++/*************************************************************************** ++ -------------------------------NET STUFF--------------------------- ++***************************************************************************/ ++static struct net_device_stats *rtl8180_stats(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return &priv->ieee80211->stats; ++} ++// ++// Change current and default preamble mode. ++// 2005.01.06, by rcnjko. ++// ++bool ++MgntActSet_802_11_PowerSaveMode( ++ struct r8180_priv *priv, ++ RT_PS_MODE rtPsMode ++) ++{ ++ ++ // Currently, we do not change power save mode on IBSS mode. ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ { ++ return false; ++ } ++ ++ // ++ // If we make HW to fill up the PwrMgt bit for us, ++ // some AP will not response to our mgnt frames with PwrMgt bit set, ++ // e.g. cannot associate the AP. ++ // So I commented out it. 2005.02.16, by rcnjko. ++ // ++// // Change device's power save mode. ++// Adapter->HalFunc.SetPSModeHandler( Adapter, rtPsMode ); ++ ++ // Update power save mode configured. ++// priv->dot11PowerSaveMode = rtPsMode; ++ priv->ieee80211->ps = rtPsMode; ++ // Determine ListenInterval. ++#if 0 ++ if(priv->dot11PowerSaveMode == eMaxPs) ++ { ++ priv->ieee80211->ListenInterval = 10; ++ } ++ else ++ { ++ priv->ieee80211->ListenInterval = 2; ++ } ++#endif ++ return true; ++} ++ ++//================================================================================ ++// Leisure Power Save in linked state. ++//================================================================================ ++ ++// ++// Description: ++// Enter the leisure power save mode. ++// ++void ++LeisurePSEnter( ++ struct r8180_priv *priv ++ ) ++{ ++ if (priv->bLeisurePs) ++ { ++ if (priv->ieee80211->ps == IEEE80211_PS_DISABLED) ++ { ++ //printk("----Enter PS\n"); ++ MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);//IEEE80211_PS_ENABLE ++ } ++ } ++} ++ ++ ++// ++// Description: ++// Leave the leisure power save mode. ++// ++void ++LeisurePSLeave( ++ struct r8180_priv *priv ++ ) ++{ ++ if (priv->bLeisurePs) ++ { ++ if (priv->ieee80211->ps != IEEE80211_PS_DISABLED) ++ { ++ //printk("----Leave PS\n"); ++ MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED); ++ } ++ } ++} ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_wakeup_wq (struct work_struct *work) ++{ ++// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); ++// struct ieee80211_device * ieee = (struct ieee80211_device*) ++// container_of(work, struct ieee80211_device, watch_dog_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_hw_wakeup_wq(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ ++// printk("dev is %d\n",dev); ++// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__); ++ rtl8180_hw_wakeup(dev); ++ ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_sleep_wq (struct work_struct *work) ++{ ++// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); ++// struct ieee80211_device * ieee = (struct ieee80211_device*) ++// container_of(work, struct ieee80211_device, watch_dog_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_hw_sleep_wq(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ ++ rtl8180_hw_sleep_down(dev); ++} ++ ++//YJ,add,080828,for KeepAlive ++static void MgntLinkKeepAlive(struct r8180_priv *priv ) ++{ ++ if (priv->keepAliveLevel == 0) ++ return; ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED) ++ { ++ // ++ // Keep-Alive. ++ // ++ //printk("LastTx:%d Tx:%d LastRx:%d Rx:%ld Idle:%d\n",priv->link_detect.LastNumTxUnicast,priv->NumTxUnicast, priv->link_detect.LastNumRxUnicast, priv->ieee80211->NumRxUnicast, priv->link_detect.IdleCount); ++ ++ if ( (priv->keepAliveLevel== 2) || ++ (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast && ++ priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast ) ++ ) ++ { ++ priv->link_detect.IdleCount++; ++ ++ // ++ // Send a Keep-Alive packet packet to AP if we had been idle for a while. ++ // ++ if(priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1) ) ++ { ++ priv->link_detect.IdleCount = 0; ++ ieee80211_sta_ps_send_null_frame(priv->ieee80211, false); ++ } ++ } ++ else ++ { ++ priv->link_detect.IdleCount = 0; ++ } ++ priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast; ++ priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast; ++ } ++} ++//YJ,add,080828,for KeepAlive,end ++ ++static u8 read_acadapter_file(char *filename); ++void rtl8180_watch_dog(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ bool bEnterPS = false; ++ bool bBusyTraffic = false; ++ u32 TotalRxNum = 0; ++ u16 SlotIndex = 0; ++ u16 i = 0; ++#ifdef ENABLE_IPS ++ if(priv->ieee80211->actscanning == false){ ++ if((priv->ieee80211->iw_mode != IW_MODE_ADHOC) && (priv->ieee80211->state == IEEE80211_NOLINK) && (priv->ieee80211->beinretry == false) && (priv->eRFPowerState == eRfOn)){ ++ IPSEnter(dev); ++ } ++ } ++#endif ++ //YJ,add,080828,for link state check ++ if((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)){ ++ SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum; ++ priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod; ++ for( i=0; ilink_detect.SlotNum; i++ ) ++ TotalRxNum+= priv->link_detect.RxFrameNum[i]; ++ //printk("&&&&&=== TotalRxNum = %d\n", TotalRxNum); ++ if(TotalRxNum == 0){ ++ priv->ieee80211->state = IEEE80211_ASSOCIATING; ++ queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq); ++ } ++ } ++ ++ //YJ,add,080828,for KeepAlive ++ MgntLinkKeepAlive(priv); ++ ++ //YJ,add,080828,for LPS ++#ifdef ENABLE_LPS ++ if(priv->PowerProfile == POWER_PROFILE_BATTERY ) ++ { ++ //Turn on LeisurePS on battery power ++ //printk("!!!!!On battery power\n"); ++ priv->bLeisurePs = true; ++ } ++ else if(priv->PowerProfile == POWER_PROFILE_AC ) ++ { ++ // Turn off LeisurePS on AC power ++ //printk("----On AC power\n"); ++ LeisurePSLeave(priv); ++ priv->bLeisurePs= false; ++ } ++#endif ++ ++#if 0 ++#ifndef ENABLE_LPS ++ if(priv->ieee80211->state == IEEE80211_LINKED){ ++ if( priv->NumRxOkInPeriod> 666 || ++ priv->NumTxOkInPeriod > 666 ) { ++ bBusyTraffic = true; ++ } ++ if((priv->ieee80211->NumRxData + priv->NumTxOkInPeriod)<8) { ++ bEnterPS= true; ++ } ++ if(bEnterPS) { ++ LeisurePSEnter(priv); ++ } ++ else { ++ LeisurePSLeave(priv); ++ } ++ } ++ else { ++ LeisurePSLeave(priv); ++ } ++#endif ++ priv->NumRxOkInPeriod = 0; ++ priv->NumTxOkInPeriod = 0; ++ priv->ieee80211->NumRxData = 0; ++#else ++#ifdef ENABLE_LPS ++ if(priv->ieee80211->state == IEEE80211_LINKED){ ++ priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod; ++ //printk("TxOk=%d RxOk=%d\n", priv->link_detect.NumTxOkInPeriod, priv->link_detect.NumRxOkInPeriod); ++ if( priv->link_detect.NumRxOkInPeriod> 666 || ++ priv->link_detect.NumTxOkInPeriod> 666 ) { ++ bBusyTraffic = true; ++ } ++ if(((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8) ++ || (priv->link_detect.NumRxOkInPeriod > 2)) { ++ bEnterPS= false; ++ } ++ else { ++ bEnterPS= true; ++ } ++ ++ if(bEnterPS) { ++ LeisurePSEnter(priv); ++ } ++ else { ++ LeisurePSLeave(priv); ++ } ++ } ++ else{ ++ LeisurePSLeave(priv); ++ } ++#endif ++ priv->link_detect.bBusyTraffic = bBusyTraffic; ++ priv->link_detect.NumRxOkInPeriod = 0; ++ priv->link_detect.NumTxOkInPeriod = 0; ++ priv->ieee80211->NumRxDataInPeriod = 0; ++ priv->ieee80211->NumRxBcnInPeriod = 0; ++#endif ++} ++int _rtl8180_up(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //int i; ++ ++ priv->up=1; ++ ++ DMESG("Bringing up iface"); ++#ifdef CONFIG_RTL8185B ++ rtl8185b_adapter_start(dev); ++ rtl8185b_rx_enable(dev); ++ rtl8185b_tx_enable(dev); ++#else ++ rtl8180_adapter_start(dev); ++ rtl8180_rx_enable(dev); ++ rtl8180_tx_enable(dev); ++#endif ++#ifdef ENABLE_IPS ++ if(priv->bInactivePs){ ++ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC) ++ IPSLeave(dev); ++ } ++#endif ++//by amy 080312 ++#ifdef RATE_ADAPT ++ timer_rate_adaptive((unsigned long)dev); ++#endif ++//by amy 080312 ++ watch_dog_adaptive((unsigned long)dev); ++#ifdef SW_ANTE ++ if(priv->bSwAntennaDiverity) ++ SwAntennaDiversityTimerCallback(dev); ++#endif ++// IPSEnter(dev); ++ ieee80211_softmac_start_protocol(priv->ieee80211); ++ ++//Add for RF power on power off by lizhaoming 080512 ++// priv->eRFPowerState = eRfOn; ++// printk("\n--------Start queue_work:GPIOChangeRFWorkItem"); ++// queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->GPIOChangeRFWorkItem,1000); ++ ++ return 0; ++} ++ ++ ++int rtl8180_open(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ down(&priv->wx_sem); ++ ret = rtl8180_up(dev); ++ up(&priv->wx_sem); ++ return ret; ++ ++} ++ ++ ++int rtl8180_up(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 1) return -1; ++ ++ return _rtl8180_up(dev); ++} ++ ++ ++int rtl8180_close(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ down(&priv->wx_sem); ++ ret = rtl8180_down(dev); ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++int rtl8180_down(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 0) return -1; ++ ++ priv->up=0; ++ ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ /* FIXME */ ++ if (!netif_queue_stopped(dev)) ++ netif_stop_queue(dev); ++ rtl8180_rtx_disable(dev); ++ rtl8180_irq_disable(dev); ++ del_timer_sync(&priv->watch_dog_timer); ++ //cancel_delayed_work(&priv->ieee80211->watch_dog_wq); ++//{by amy 080312 ++ del_timer_sync(&priv->rateadapter_timer); ++ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); ++//by amy 080312} ++ cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_dig_wq); ++ cancel_delayed_work(&priv->ieee80211->tx_pw_wq); ++ del_timer_sync(&priv->SwAntennaDiversityTimer); ++ SetZebraRFPowerState8185(dev,eRfOff); ++ //ieee80211_softmac_stop_protocol(priv->ieee80211); ++ memset(&(priv->ieee80211->current_network),0,sizeof(struct ieee80211_network)); ++ priv->ieee80211->state = IEEE80211_NOLINK; ++ return 0; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_restart_wq(struct work_struct *work) ++{ ++ struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); ++ struct net_device *dev = priv->dev; ++#else ++void rtl8180_restart_wq(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ down(&priv->wx_sem); ++ ++ rtl8180_commit(dev); ++ ++ up(&priv->wx_sem); ++} ++ ++void rtl8180_restart(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //rtl8180_commit(dev); ++ schedule_work(&priv->reset_wq); ++ //DMESG("TXTIMEOUT"); ++} ++ ++ ++void rtl8180_commit(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (priv->up == 0) return ; ++//+by amy 080312 ++ del_timer_sync(&priv->watch_dog_timer); ++ //cancel_delayed_work(&priv->ieee80211->watch_dog_wq); ++//{by amy 080312 ++//by amy for rate adaptive ++ del_timer_sync(&priv->rateadapter_timer); ++ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); ++//by amy for rate adaptive ++//by amy 080312} ++ cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); ++ cancel_delayed_work(&priv->ieee80211->hw_dig_wq); ++ cancel_delayed_work(&priv->ieee80211->tx_pw_wq); ++ del_timer_sync(&priv->SwAntennaDiversityTimer); ++ ieee80211_softmac_stop_protocol(priv->ieee80211); ++ rtl8180_irq_disable(dev); ++ rtl8180_rtx_disable(dev); ++ _rtl8180_up(dev); ++} ++ ++ ++static void r8180_set_multicast(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ short promisc; ++ ++ //down(&priv->wx_sem); ++ ++ promisc = (dev->flags & IFF_PROMISC) ? 1:0; ++ ++ if (promisc != priv->promisc) ++ rtl8180_restart(dev); ++ ++ priv->promisc = promisc; ++ ++ //up(&priv->wx_sem); ++} ++ ++#if 0 ++/* this is called by the kernel when it needs to TX a 802.3 encapsulated frame*/ ++int rtl8180_8023_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ ret = ieee80211_r8180_8023_hardstartxmit(skb,priv->ieee80211); ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ return ret; ++} ++#endif ++ ++int r8180_set_mac_adr(struct net_device *dev, void *mac) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct sockaddr *addr = mac; ++ ++ down(&priv->wx_sem); ++ ++ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_MASTER) ++ memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN); ++ ++ if (priv->up) { ++ rtl8180_down(dev); ++ rtl8180_up(dev); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++/* based on ipw2200 driver */ ++int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ struct iwreq *wrq = (struct iwreq *) rq; ++ int ret=-1; ++ switch (cmd) { ++ case RTL_IOCTL_WPA_SUPPLICANT: ++ ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); ++ return ret; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++ ++ ++/**************************************************************************** ++ -----------------------------PCI STUFF--------------------------- ++*****************************************************************************/ ++ ++ ++static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ unsigned long ioaddr = 0; ++ struct net_device *dev = NULL; ++ struct r8180_priv *priv= NULL; ++ //u8 *ptr; ++ u8 unit = 0; ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ unsigned long pio_start, pio_len, pio_flags; ++#else ++ unsigned long pmem_start, pmem_len, pmem_flags; ++#endif //end #ifdef RTL_IO_MAP ++ ++ DMESG("Configuring chip resources"); ++ ++ if( pci_enable_device (pdev) ){ ++ DMESG("Failed to enable PCI device"); ++ return -EIO; ++ } ++ ++ pci_set_master(pdev); ++ //pci_set_wmi(pdev); ++ pci_set_dma_mask(pdev, 0xffffff00ULL); ++ pci_set_consistent_dma_mask(pdev,0xffffff00ULL); ++ dev = alloc_ieee80211(sizeof(struct r8180_priv)); ++ if (!dev) ++ return -ENOMEM; ++ priv = ieee80211_priv(dev); ++ priv->ieee80211 = netdev_priv(dev); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++ SET_MODULE_OWNER(dev); ++#endif ++ pci_set_drvdata(pdev, dev); ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ ++ priv = ieee80211_priv(dev); ++// memset(priv,0,sizeof(struct r8180_priv)); ++ priv->pdev=pdev; ++ ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ ++ pio_start = (unsigned long)pci_resource_start (pdev, 0); ++ pio_len = (unsigned long)pci_resource_len (pdev, 0); ++ pio_flags = (unsigned long)pci_resource_flags (pdev, 0); ++ ++ if (!(pio_flags & IORESOURCE_IO)) { ++ DMESG("region #0 not a PIO resource, aborting"); ++ goto fail; ++ } ++ ++ //DMESG("IO space @ 0x%08lx", pio_start ); ++ if( ! request_region( pio_start, pio_len, RTL8180_MODULE_NAME ) ){ ++ DMESG("request_region failed!"); ++ goto fail; ++ } ++ ++ ioaddr = pio_start; ++ dev->base_addr = ioaddr; // device I/O address ++ ++#else ++ ++ pmem_start = pci_resource_start(pdev, 1); ++ pmem_len = pci_resource_len(pdev, 1); ++ pmem_flags = pci_resource_flags (pdev, 1); ++ ++ if (!(pmem_flags & IORESOURCE_MEM)) { ++ DMESG("region #1 not a MMIO resource, aborting"); ++ goto fail; ++ } ++ ++ //DMESG("Memory mapped space @ 0x%08lx ", pmem_start); ++ if( ! request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) { ++ DMESG("request_mem_region failed!"); ++ goto fail; ++ } ++ ++ ++ ioaddr = (unsigned long)ioremap_nocache( pmem_start, pmem_len); ++ if( ioaddr == (unsigned long)NULL ){ ++ DMESG("ioremap failed!"); ++ // release_mem_region( pmem_start, pmem_len ); ++ goto fail1; ++ } ++ ++ dev->mem_start = ioaddr; // shared mem start ++ dev->mem_end = ioaddr + pci_resource_len(pdev, 0); // shared mem end ++ ++#endif //end #ifdef RTL_IO_MAP ++ ++#ifdef CONFIG_RTL8185B ++ //pci_read_config_byte(pdev, 0x05, ptr); ++ //pci_write_config_byte(pdev, 0x05, (*ptr) & (~0x04)); ++ pci_read_config_byte(pdev, 0x05, &unit); ++ pci_write_config_byte(pdev, 0x05, unit & (~0x04)); ++#endif ++ ++ dev->irq = pdev->irq; ++ priv->irq = 0; ++ ++ dev->open = rtl8180_open; ++ dev->stop = rtl8180_close; ++ //dev->hard_start_xmit = ieee80211_xmit; ++ dev->tx_timeout = rtl8180_restart; ++ dev->wireless_handlers = &r8180_wx_handlers_def; ++ dev->do_ioctl = rtl8180_ioctl; ++ dev->set_multicast_list = r8180_set_multicast; ++ dev->set_mac_address = r8180_set_mac_adr; ++ ++#if WIRELESS_EXT >= 12 ++#if WIRELESS_EXT < 17 ++ dev->get_wireless_stats = r8180_get_wireless_stats; ++#endif ++ dev->wireless_handlers = (struct iw_handler_def *) &r8180_wx_handlers_def; ++#endif ++ ++ dev->type=ARPHRD_ETHER; ++ dev->watchdog_timeo = HZ*3; //added by david woo, 2007.12.13 ++ ++ if (dev_alloc_name(dev, ifname) < 0){ ++ DMESG("Oops: devname already taken! Trying wlan%%d...\n"); ++ ifname = "wlan%d"; ++ // ifname = "ath%d"; ++ dev_alloc_name(dev, ifname); ++ } ++ ++ ++ if(rtl8180_init(dev)!=0){ ++ DMESG("Initialization failed"); ++ goto fail1; ++ } ++ ++ netif_carrier_off(dev); ++ ++ register_netdev(dev); ++ ++ rtl8180_proc_init_one(dev); ++ ++ DMESG("Driver probe completed\n"); ++ return 0; ++ ++fail1: ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ ++ if( dev->base_addr != 0 ){ ++ ++ release_region(dev->base_addr, ++ pci_resource_len(pdev, 0) ); ++ } ++#else ++ if( dev->mem_start != (unsigned long)NULL ){ ++ iounmap( (void *)dev->mem_start ); ++ release_mem_region( pci_resource_start(pdev, 1), ++ pci_resource_len(pdev, 1) ); ++ } ++#endif //end #ifdef RTL_IO_MAP ++ ++ ++fail: ++ if(dev){ ++ ++ if (priv->irq) { ++ free_irq(dev->irq, dev); ++ dev->irq=0; ++ } ++ free_ieee80211(dev); ++ } ++ ++ pci_disable_device(pdev); ++ ++ DMESG("wlan driver load failed\n"); ++ pci_set_drvdata(pdev, NULL); ++ return -ENODEV; ++ ++} ++ ++ ++static void __devexit rtl8180_pci_remove(struct pci_dev *pdev) ++{ ++ struct r8180_priv *priv; ++ struct net_device *dev = pci_get_drvdata(pdev); ++ if(dev){ ++ ++ unregister_netdev(dev); ++ ++ priv=ieee80211_priv(dev); ++ ++ rtl8180_proc_remove_one(dev); ++ rtl8180_down(dev); ++ priv->rf_close(dev); ++ rtl8180_reset(dev); ++ //rtl8180_rtx_disable(dev); ++ //rtl8180_irq_disable(dev); ++ mdelay(10); ++ //write_nic_word(dev,INTA,read_nic_word(dev,INTA)); ++ //force_pci_posting(dev); ++ //mdelay(10); ++ ++ if(priv->irq){ ++ ++ DMESG("Freeing irq %d",dev->irq); ++ free_irq(dev->irq, dev); ++ priv->irq=0; ++ ++ } ++ ++ free_rx_desc_ring(dev); ++ free_tx_desc_rings(dev); ++ // free_beacon_desc_ring(dev,priv->txbeaconcount); ++ ++#ifdef CONFIG_RTL8180_IO_MAP ++ ++ if( dev->base_addr != 0 ){ ++ ++ release_region(dev->base_addr, ++ pci_resource_len(pdev, 0) ); ++ } ++#else ++ if( dev->mem_start != (unsigned long)NULL ){ ++ iounmap( (void *)dev->mem_start ); ++ release_mem_region( pci_resource_start(pdev, 1), ++ pci_resource_len(pdev, 1) ); ++ } ++#endif /*end #ifdef RTL_IO_MAP*/ ++ ++ free_ieee80211(dev); ++ } ++ pci_disable_device(pdev); ++ ++ DMESG("wlan driver removed\n"); ++} ++ ++ ++/* fun with the built-in ieee80211 stack... */ ++extern int ieee80211_crypto_init(void); ++extern void ieee80211_crypto_deinit(void); ++extern int ieee80211_crypto_tkip_init(void); ++extern void ieee80211_crypto_tkip_exit(void); ++extern int ieee80211_crypto_ccmp_init(void); ++extern void ieee80211_crypto_ccmp_exit(void); ++extern int ieee80211_crypto_wep_init(void); ++extern void ieee80211_crypto_wep_exit(void); ++ ++static int __init rtl8180_pci_module_init(void) ++{ ++ int ret; ++ ++ ret = ieee80211_crypto_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_init() failed %d\n", ret); ++ return ret; ++ } ++ ret = ieee80211_crypto_tkip_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_tkip_init() failed %d\n", ret); ++ return ret; ++ } ++ ret = ieee80211_crypto_ccmp_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_ccmp_init() failed %d\n", ret); ++ return ret; ++ } ++ ret = ieee80211_crypto_wep_init(); ++ if (ret) { ++ printk(KERN_ERR "ieee80211_crypto_wep_init() failed %d\n", ret); ++ return ret; ++ } ++ ++ printk(KERN_INFO "\nLinux kernel driver for RTL8180 \ ++/ RTL8185 based WLAN cards\n"); ++ printk(KERN_INFO "Copyright (c) 2004-2005, Andrea Merello\n"); ++ DMESG("Initializing module"); ++ DMESG("Wireless extensions version %d", WIRELESS_EXT); ++ rtl8180_proc_module_init(); ++ ++#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) ++ if(0!=pci_module_init(&rtl8180_pci_driver)) ++#else ++ if(0!=pci_register_driver(&rtl8180_pci_driver)) ++#endif ++ //if(0!=pci_module_init(&rtl8180_pci_driver)) ++ { ++ DMESG("No device found"); ++ /*pci_unregister_driver (&rtl8180_pci_driver);*/ ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++ ++static void __exit rtl8180_pci_module_exit(void) ++{ ++ pci_unregister_driver (&rtl8180_pci_driver); ++ rtl8180_proc_module_remove(); ++ ieee80211_crypto_deinit(); ++ ieee80211_crypto_tkip_exit(); ++ ieee80211_crypto_ccmp_exit(); ++ ieee80211_crypto_wep_exit(); ++ DMESG("Exiting"); ++} ++ ++ ++void rtl8180_try_wake_queue(struct net_device *dev, int pri) ++{ ++ unsigned long flags; ++ short enough_desc; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ spin_lock_irqsave(&priv->tx_lock,flags); ++ enough_desc = check_nic_enought_desc(dev,pri); ++ spin_unlock_irqrestore(&priv->tx_lock,flags); ++ ++ if(enough_desc) ++ ieee80211_wake_queue(priv->ieee80211); ++} ++ ++/***************************************************************************** ++ -----------------------------IRQ STUFF--------------------------- ++******************************************************************************/ ++ ++void rtl8180_tx_isr(struct net_device *dev, int pri,short error) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ u32 *tail; //tail virtual addr ++ u32 *head; //head virtual addr ++ u32 *begin;//start of ring virtual addr ++ u32 *nicv; //nic pointer virtual addr ++// u32 *txdv; //packet just TXed ++ u32 nic; //nic pointer physical addr ++ u32 nicbegin;// start of ring physical addr ++// short txed; ++ unsigned long flag; ++ /* physical addr are ok on 32 bits since we set DMA mask*/ ++ ++ int offs; ++ int j,i; ++ int hd; ++ if (error) priv->stats.txretry++; //tony 20060601 ++ spin_lock_irqsave(&priv->tx_lock,flag); ++ switch(pri) { ++ case MANAGE_PRIORITY: ++ tail = priv->txmapringtail; ++ begin = priv->txmapring; ++ head = priv->txmapringhead; ++ nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR); ++ nicbegin = priv->txmapringdma; ++ break; ++ ++ case BK_PRIORITY: ++ tail = priv->txbkpringtail; ++ begin = priv->txbkpring; ++ head = priv->txbkpringhead; ++ nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR); ++ nicbegin = priv->txbkpringdma; ++ break; ++ ++ case BE_PRIORITY: ++ tail = priv->txbepringtail; ++ begin = priv->txbepring; ++ head = priv->txbepringhead; ++ nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR); ++ nicbegin = priv->txbepringdma; ++ break; ++ ++ case VI_PRIORITY: ++ tail = priv->txvipringtail; ++ begin = priv->txvipring; ++ head = priv->txvipringhead; ++ nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR); ++ nicbegin = priv->txvipringdma; ++ break; ++ ++ case VO_PRIORITY: ++ tail = priv->txvopringtail; ++ begin = priv->txvopring; ++ head = priv->txvopringhead; ++ nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR); ++ nicbegin = priv->txvopringdma; ++ break; ++ ++ case HI_PRIORITY: ++ tail = priv->txhpringtail; ++ begin = priv->txhpring; ++ head = priv->txhpringhead; ++ nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR); ++ nicbegin = priv->txhpringdma; ++ break; ++ ++ default: ++ spin_unlock_irqrestore(&priv->tx_lock,flag); ++ return ; ++ } ++/* DMESG("%x %s %x %x",((int)nic & 0xfff)/8/4, ++ *(priv->txnpring + ((int)nic&0xfff)/4/8) & (1<<31) ? "filled" : "empty", ++ (priv->txnpringtail - priv->txnpring)/8,(priv->txnpringhead - ++priv->txnpring)/8); ++*/ ++ //nicv = (u32*) ((nic - nicbegin) + (int)begin); ++ nicv = (u32*) ((nic - nicbegin) + (u8*)begin); ++ if((head <= tail && (nicv > tail || nicv < head)) || ++ (head > tail && (nicv > tail && nicv < head))){ ++ ++ DMESGW("nic has lost pointer"); ++#ifdef DEBUG_TX_DESC ++ //check_tx_ring(dev,NORM_PRIORITY); ++ check_tx_ring(dev,pri); ++#endif ++ spin_unlock_irqrestore(&priv->tx_lock,flag); ++ rtl8180_restart(dev); ++ return; ++ } ++ ++ /* we check all the descriptors between the head and the nic, ++ * but not the currenly pointed by the nic (the next to be txed) ++ * and the previous of the pointed (might be in process ??) ++ */ ++ //if (head == nic) return; ++ //DMESG("%x %x",head,nic); ++ offs = (nic - nicbegin); ++ //DMESG("%x %x %x",nic ,(u32)nicbegin, (int)nic -nicbegin); ++ ++ offs = offs / 8 /4; ++ ++ hd = (head - begin) /8; ++ ++ if(offs >= hd) ++ j = offs - hd; ++ else ++ j = offs + (priv->txringcount -1 -hd); ++ // j= priv->txringcount -1- (hd - offs); ++ ++ j-=2; ++ if(j<0) j=0; ++ ++ ++ for(i=0;iCurrRetryCnt += (u16)((*head) & (0x000000ff)); ++#if 1 ++ if(!error) ++ { ++ priv->NumTxOkTotal++; ++// printk("NumTxOkTotal is %d\n",priv->NumTxOkTotal++); ++ } ++#endif ++ // printk("in function %s:curr_retry_count is %d\n",__FUNCTION__,((*head) & (0x000000ff))); ++ } ++ if(!error){ ++ priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff); ++ } ++// printk("in function %s:curr_txokbyte_count is %d\n",__FUNCTION__,(*(head+3)) & (0x00000fff)); ++ *head = *head &~ (1<<31); ++ ++ if((head - begin)/8 == priv->txringcount-1) ++ head=begin; ++ ++ else ++ head+=8; ++ } ++#if 0 ++ if(nicv == begin) ++ txdv = begin + (priv->txringcount -1)*8; ++ else ++ txdv = nicv - 8; ++ ++ txed = !(txdv[0] &(1<<31)); ++ ++ if(txed){ ++ if(!(txdv[0] & (1<<15))) error = 1; ++ //if(!(txdv[0] & (1<<30))) error = 1; ++ if(error)DMESG("%x",txdv[0]); ++ } ++#endif ++ //DMESG("%x",txdv[0]); ++ /* the head has been moved to the last certainly TXed ++ * (or at least processed by the nic) packet. ++ * The driver take forcefully owning of all these packets ++ * If the packet previous of the nic pointer has been ++ * processed this doesn't matter: it will be checked ++ * here at the next round. Anyway if no more packet are ++ * TXed no memory leak occour at all. ++ */ ++ ++ switch(pri) { ++ case MANAGE_PRIORITY: ++ priv->txmapringhead = head; ++ //printk("1==========================================> priority check!\n"); ++ if(priv->ack_tx_to_ieee){ ++ // try to implement power-save mode 2008.1.22 ++ // printk("2==========================================> priority check!\n"); ++#if 1 ++ if(rtl8180_is_tx_queue_empty(dev)){ ++ // printk("tx queue empty, after send null sleep packet, try to sleep !\n"); ++ priv->ack_tx_to_ieee = 0; ++ ieee80211_ps_tx_ack(priv->ieee80211,!error); ++ } ++#endif ++ } ++ break; ++ ++ case BK_PRIORITY: ++ priv->txbkpringhead = head; ++ break; ++ ++ case BE_PRIORITY: ++ priv->txbepringhead = head; ++ break; ++ ++ case VI_PRIORITY: ++ priv->txvipringhead = head; ++ break; ++ ++ case VO_PRIORITY: ++ priv->txvopringhead = head; ++ break; ++ ++ case HI_PRIORITY: ++ priv->txhpringhead = head; ++ break; ++ } ++ ++ /*DMESG("%x %x %x", (priv->txnpringhead - priv->txnpring) /8 , ++ (priv->txnpringtail - priv->txnpring) /8, ++ offs ); ++ */ ++ ++ spin_unlock_irqrestore(&priv->tx_lock,flag); ++ ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_tx_irq_wq(struct work_struct *work) ++{ ++ //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device * ieee = (struct ieee80211_device*) ++ container_of(dwork, struct ieee80211_device, watch_dog_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_tx_irq_wq(struct net_device *dev) ++{ ++ //struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ rtl8180_tx_isr(dev,MANAGE_PRIORITY,0); ++} ++irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs) ++{ ++ struct net_device *dev = (struct net_device *) netdev; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ unsigned long flags; ++ u32 inta; ++ ++ /* We should return IRQ_NONE, but for now let me keep this */ ++ if(priv->irq_enabled == 0) return IRQ_HANDLED; ++ ++ spin_lock_irqsave(&priv->irq_th_lock,flags); ++ ++#ifdef CONFIG_RTL8185B ++ //ISR: 4bytes ++ inta = read_nic_dword(dev, ISR);// & priv->IntrMask; ++ write_nic_dword(dev,ISR,inta); // reset int situation ++#else ++ inta = read_nic_word(dev,INTA) & priv->irq_mask; ++ write_nic_word(dev,INTA,inta); // reset int situation ++#endif ++ ++ priv->stats.shints++; ++ ++ //DMESG("Enter interrupt, ISR value = 0x%08x", inta); ++ ++ if(!inta){ ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ return IRQ_HANDLED; ++ /* ++ most probably we can safely return IRQ_NONE, ++ but for now is better to avoid problems ++ */ ++ } ++ ++ if(inta == 0xffff){ ++ /* HW disappared */ ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ return IRQ_HANDLED; ++ } ++ ++ priv->stats.ints++; ++#ifdef DEBUG_IRQ ++ DMESG("NIC irq %x",inta); ++#endif ++ //priv->irqpending = inta; ++ ++ ++ if(!netif_running(dev)) { ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ return IRQ_HANDLED; ++ } ++ ++ if(inta & ISR_TimeOut){ ++ write_nic_dword(dev, TimerInt, 0); ++ //DMESG("=================>waking up"); ++// rtl8180_hw_wakeup(dev); ++ } ++ ++ if(inta & ISR_TBDOK){ ++ priv->stats.txbeacon++; ++ } ++ ++ if(inta & ISR_TBDER){ ++ priv->stats.txbeaconerr++; ++ } ++ ++ if(inta & IMR_TMGDOK ) { ++// priv->NumTxOkTotal++; ++ rtl8180_tx_isr(dev,MANAGE_PRIORITY,0); ++// schedule_work(&priv->tx_irq_wq); ++ ++ } ++ ++ if(inta & ISR_THPDER){ ++#ifdef DEBUG_TX ++ DMESG ("TX high priority ERR"); ++#endif ++ priv->stats.txhperr++; ++ rtl8180_tx_isr(dev,HI_PRIORITY,1); ++ priv->ieee80211->stats.tx_errors++; ++ } ++ ++ if(inta & ISR_THPDOK){ //High priority tx ok ++#ifdef DEBUG_TX ++ DMESG ("TX high priority OK"); ++#endif ++// priv->NumTxOkTotal++; ++ //priv->NumTxOkInPeriod++; //YJ,del,080828 ++ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 ++ priv->stats.txhpokint++; ++ rtl8180_tx_isr(dev,HI_PRIORITY,0); ++ } ++ ++ if(inta & ISR_RER) { ++ priv->stats.rxerr++; ++#ifdef DEBUG_RX ++ DMESGW("RX error int"); ++#endif ++ } ++#ifdef CONFIG_RTL8185B ++ if(inta & ISR_TBKDER){ //corresponding to BK_PRIORITY ++ priv->stats.txbkperr++; ++ priv->ieee80211->stats.tx_errors++; ++#ifdef DEBUG_TX ++ DMESGW("TX bkp error int"); ++#endif ++ //tasklet_schedule(&priv->irq_tx_tasklet); ++ rtl8180_tx_isr(dev,BK_PRIORITY,1); ++ rtl8180_try_wake_queue(dev, BE_PRIORITY); ++ } ++ ++ if(inta & ISR_TBEDER){ //corresponding to BE_PRIORITY ++ priv->stats.txbeperr++; ++ priv->ieee80211->stats.tx_errors++; ++#ifdef DEBUG_TX ++ DMESGW("TX bep error int"); ++#endif ++ rtl8180_tx_isr(dev,BE_PRIORITY,1); ++ //tasklet_schedule(&priv->irq_tx_tasklet); ++ rtl8180_try_wake_queue(dev, BE_PRIORITY); ++ } ++#endif ++ if(inta & ISR_TNPDER){ //corresponding to VO_PRIORITY ++ priv->stats.txnperr++; ++ priv->ieee80211->stats.tx_errors++; ++#ifdef DEBUG_TX ++ DMESGW("TX np error int"); ++#endif ++ //tasklet_schedule(&priv->irq_tx_tasklet); ++ rtl8180_tx_isr(dev,NORM_PRIORITY,1); ++#ifdef CONFIG_RTL8185B ++ rtl8180_try_wake_queue(dev, NORM_PRIORITY); ++#endif ++ } ++ ++ if(inta & ISR_TLPDER){ //corresponding to VI_PRIORITY ++ priv->stats.txlperr++; ++ priv->ieee80211->stats.tx_errors++; ++#ifdef DEBUG_TX ++ DMESGW("TX lp error int"); ++#endif ++ rtl8180_tx_isr(dev,LOW_PRIORITY,1); ++ //tasklet_schedule(&priv->irq_tx_tasklet); ++ rtl8180_try_wake_queue(dev, LOW_PRIORITY); ++ } ++ ++ if(inta & ISR_ROK){ ++#ifdef DEBUG_RX ++ DMESG("Frame arrived !"); ++#endif ++ //priv->NumRxOkInPeriod++; //YJ,del,080828 ++ priv->stats.rxint++; ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ } ++ ++ if(inta & ISR_RQoSOK ){ ++#ifdef DEBUG_RX ++ DMESG("QoS Frame arrived !"); ++#endif ++ //priv->NumRxOkInPeriod++; //YJ,del,080828 ++ priv->stats.rxint++; ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ } ++ if(inta & ISR_BcnInt) { ++ //DMESG("Preparing Beacons"); ++ rtl8180_prepare_beacon(dev); ++ } ++ ++ if(inta & ISR_RDU){ ++//#ifdef DEBUG_RX ++ DMESGW("No RX descriptor available"); ++ priv->stats.rxrdu++; ++//#endif ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ /*queue_work(priv->workqueue ,&priv->restart_work);*/ ++ ++ } ++ if(inta & ISR_RXFOVW){ ++#ifdef DEBUG_RX ++ DMESGW("RX fifo overflow"); ++#endif ++ priv->stats.rxoverflow++; ++ tasklet_schedule(&priv->irq_rx_tasklet); ++ //queue_work(priv->workqueue ,&priv->restart_work); ++ } ++ ++ if(inta & ISR_TXFOVW) priv->stats.txoverflow++; ++ ++ if(inta & ISR_TNPDOK){ //Normal priority tx ok ++#ifdef DEBUG_TX ++ DMESG ("TX normal priority OK"); ++#endif ++// priv->NumTxOkTotal++; ++ //priv->NumTxOkInPeriod++; //YJ,del,080828 ++ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 ++ // priv->ieee80211->stats.tx_packets++; ++ priv->stats.txnpokint++; ++ rtl8180_tx_isr(dev,NORM_PRIORITY,0); ++ } ++ ++ if(inta & ISR_TLPDOK){ //Low priority tx ok ++#ifdef DEBUG_TX ++ DMESG ("TX low priority OK"); ++#endif ++// priv->NumTxOkTotal++; ++ //priv->NumTxOkInPeriod++; //YJ,del,080828 ++ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 ++ // priv->ieee80211->stats.tx_packets++; ++ priv->stats.txlpokint++; ++ rtl8180_tx_isr(dev,LOW_PRIORITY,0); ++ rtl8180_try_wake_queue(dev, LOW_PRIORITY); ++ } ++ ++#ifdef CONFIG_RTL8185B ++ if(inta & ISR_TBKDOK){ //corresponding to BK_PRIORITY ++ priv->stats.txbkpokint++; ++#ifdef DEBUG_TX ++ DMESGW("TX bk priority ok"); ++#endif ++// priv->NumTxOkTotal++; ++ //priv->NumTxOkInPeriod++; //YJ,del,080828 ++ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 ++ rtl8180_tx_isr(dev,BK_PRIORITY,0); ++ rtl8180_try_wake_queue(dev, BE_PRIORITY); ++ } ++ ++ if(inta & ISR_TBEDOK){ //corresponding to BE_PRIORITY ++ priv->stats.txbeperr++; ++#ifdef DEBUG_TX ++ DMESGW("TX be priority ok"); ++#endif ++// priv->NumTxOkTotal++; ++ //priv->NumTxOkInPeriod++; //YJ,del,080828 ++ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828 ++ rtl8180_tx_isr(dev,BE_PRIORITY,0); ++ rtl8180_try_wake_queue(dev, BE_PRIORITY); ++ } ++#endif ++ force_pci_posting(dev); ++ spin_unlock_irqrestore(&priv->irq_th_lock,flags); ++ ++ return IRQ_HANDLED; ++} ++ ++ ++void rtl8180_irq_rx_tasklet(struct r8180_priv* priv) ++{ ++// unsigned long flags; ++ ++/* spin_lock_irqsave(&priv->irq_lock, flags); ++ priv->irq_mask &=~IMR_ROK; ++ priv->irq_mask &=~IMR_RDU; ++ ++ rtl8180_irq_enable(priv->dev); ++ spin_unlock_irqrestore(&priv->irq_lock, flags); ++*/ ++ rtl8180_rx(priv->dev); ++ ++/* spin_lock_irqsave(&priv->irq_lock, flags); ++ priv->irq_mask |= IMR_ROK; ++ priv->irq_mask |= IMR_RDU; ++ rtl8180_irq_enable(priv->dev); ++ spin_unlock_irqrestore(&priv->irq_lock, flags); ++*/ ++} ++ ++/**************************************************************************** ++lizhaoming--------------------------- RF power on/power off ----------------- ++*****************************************************************************/ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void GPIOChangeRFWorkItemCallBack(struct work_struct *work) ++{ ++ //struct delayed_work *dwork = container_of(work, struct delayed_work, work); ++ struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work); ++ struct net_device *dev = ieee->dev; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#else ++void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee) ++{ ++ struct net_device *dev = ieee->dev; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ ++ //u16 tmp2byte; ++ u8 btPSR; ++ u8 btConfig0; ++ RT_RF_POWER_STATE eRfPowerStateToSet; ++ bool bActuallySet=false; ++ ++ char *argv[3]; ++ static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh"; ++ static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL}; ++ static int readf_count = 0; ++ //printk("============>%s in \n", __func__); ++ ++#ifdef ENABLE_LPS ++ if(readf_count % 10 == 0) ++ priv->PowerProfile = read_acadapter_file("/proc/acpi/ac_adapter/AC0/state"); ++ ++ readf_count = (readf_count+1)%0xffff; ++#endif ++#if 0 ++ if(priv->up == 0)//driver stopped ++ { ++ printk("\nDo nothing..."); ++ goto out; ++ } ++ else ++#endif ++ { ++ // We should turn off LED before polling FF51[4]. ++ ++ //Turn off LED. ++ btPSR = read_nic_byte(dev, PSR); ++ write_nic_byte(dev, PSR, (btPSR & ~BIT3)); ++ ++ //It need to delay 4us suggested by Jong, 2008-01-16 ++ udelay(4); ++ ++ //HW radio On/Off according to the value of FF51[4](config0) ++ btConfig0 = btPSR = read_nic_byte(dev, CONFIG0); ++ ++ //Turn on LED. ++ write_nic_byte(dev, PSR, btPSR| BIT3); ++ ++ eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff; ++ ++ if((priv->ieee80211->bHwRadioOff == true) && (eRfPowerStateToSet == eRfOn)) ++ { ++ priv->ieee80211->bHwRadioOff = false; ++ bActuallySet = true; ++ } ++ else if((priv->ieee80211->bHwRadioOff == false) && (eRfPowerStateToSet == eRfOff)) ++ { ++ priv->ieee80211->bHwRadioOff = true; ++ bActuallySet = true; ++ } ++ ++ if(bActuallySet) ++ { ++ MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); ++ ++ /* To update the UI status for Power status changed */ ++ if(priv->ieee80211->bHwRadioOff == true) ++ argv[1] = "RFOFF"; ++ else{ ++ //if(!priv->RfOffReason) ++ argv[1] = "RFON"; ++ //else ++ // argv[1] = "RFOFF"; ++ } ++ argv[0] = RadioPowerPath; ++ argv[2] = NULL; ++ ++ call_usermodehelper(RadioPowerPath,argv,envp,1); ++ } ++ ++ } ++ ++} ++ ++static u8 read_acadapter_file(char *filename) ++{ ++//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)) ++#if 0 ++ int fd; ++ char buf[1]; ++ char ret[50]; ++ int i = 0; ++ int n = 0; ++ mm_segment_t old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ fd = sys_open(filename, O_RDONLY, 0); ++ if (fd >= 0) { ++ while (sys_read(fd, buf, 1) == 1) ++ { ++ i++; ++ if(i>10) ++ { ++ if(buf[0]!=' ') ++ { ++ ret[n]=buf[0]; ++ n++; ++ } ++ } ++ } ++ sys_close(fd); ++ } ++ ret[n]='\0'; ++// printk("%s \n", ret); ++ set_fs(old_fs); ++ ++ if(strncmp(ret, "off-line",8) == 0) ++ { ++ return 1; ++ } ++#endif ++ return 0; ++} ++ ++/*************************************************************************** ++ ------------------- module init / exit stubs ---------------- ++****************************************************************************/ ++module_init(rtl8180_pci_module_init); ++module_exit(rtl8180_pci_module_exit); ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_dm.c +@@ -0,0 +1,1725 @@ ++//#include "r8180.h" ++#include "r8180_dm.h" ++#include "r8180_hw.h" ++#include "r8180_93cx6.h" ++//{by amy 080312 ++ ++// ++// Description: ++// Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. ++// ++//+by amy 080312 ++#define RATE_ADAPTIVE_TIMER_PERIOD 300 ++ ++bool CheckHighPower(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ if(!priv->bRegHighPowerMechanism) ++ { ++ return false; ++ } ++ ++ if(ieee->state == IEEE80211_LINKED_SCANNING) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++// ++// Description: ++// Update Tx power level if necessary. ++// See also DoRxHighPower() and SetTxPowerLevel8185() for reference. ++// ++// Note: ++// The reason why we udpate Tx power level here instead of DoRxHighPower() ++// is the number of IO to change Tx power is much more than chane TR switch ++// and they are related to OFDM and MAC registers. ++// So, we don't want to update it so frequently in per-Rx packet base. ++// ++void ++DoTxHighPower( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 HiPwrUpperTh = 0; ++ u16 HiPwrLowerTh = 0; ++ u8 RSSIHiPwrUpperTh; ++ u8 RSSIHiPwrLowerTh; ++ u8 u1bTmp; ++ char OfdmTxPwrIdx, CckTxPwrIdx; ++ ++ //printk("----> DoTxHighPower()\n"); ++ ++ HiPwrUpperTh = priv->RegHiPwrUpperTh; ++ HiPwrLowerTh = priv->RegHiPwrLowerTh; ++ ++ HiPwrUpperTh = HiPwrUpperTh * 10; ++ HiPwrLowerTh = HiPwrLowerTh * 10; ++ RSSIHiPwrUpperTh = priv->RegRSSIHiPwrUpperTh; ++ RSSIHiPwrLowerTh = priv->RegRSSIHiPwrLowerTh; ++ ++ //lzm add 080826 ++ OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel]; ++ CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel]; ++ ++ // printk("DoTxHighPower() - UndecoratedSmoothedSS:%d, CurCCKRSSI = %d , bCurCCKPkt= %d \n", priv->UndecoratedSmoothedSS, priv->CurCCKRSSI, priv->bCurCCKPkt ); ++ ++ if((priv->UndecoratedSmoothedSS > HiPwrUpperTh) || ++ (priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh))) ++ { ++ // Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah ++ ++ // printk("=====>DoTxHighPower() - High Power - UndecoratedSmoothedSS:%d, HiPwrUpperTh = %d \n", priv->UndecoratedSmoothedSS, HiPwrUpperTh ); ++ priv->bToUpdateTxPwr = true; ++ u1bTmp= read_nic_byte(dev, CCK_TXAGC); ++ ++ // If it never enter High Power. ++ if( CckTxPwrIdx == u1bTmp) ++ { ++ u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0; // 8dbm ++ write_nic_byte(dev, CCK_TXAGC, u1bTmp); ++ ++ u1bTmp= read_nic_byte(dev, OFDM_TXAGC); ++ u1bTmp = (u1bTmp > 16) ? (u1bTmp -16): 0; // 8dbm ++ write_nic_byte(dev, OFDM_TXAGC, u1bTmp); ++ } ++ ++ } ++ else if((priv->UndecoratedSmoothedSS < HiPwrLowerTh) && ++ (!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh)) ++ { ++ // printk("DoTxHighPower() - lower Power - UndecoratedSmoothedSS:%d, HiPwrUpperTh = %d \n", priv->UndecoratedSmoothedSS, HiPwrLowerTh ); ++ if(priv->bToUpdateTxPwr) ++ { ++ priv->bToUpdateTxPwr = false; ++ //SD3 required. ++ u1bTmp= read_nic_byte(dev, CCK_TXAGC); ++ if(u1bTmp < CckTxPwrIdx) ++ { ++ //u1bTmp = ((u1bTmp+16) > 35) ? 35: (u1bTmp+16); // 8dbm ++ //write_nic_byte(dev, CCK_TXAGC, u1bTmp); ++ write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx); ++ } ++ ++ u1bTmp= read_nic_byte(dev, OFDM_TXAGC); ++ if(u1bTmp < OfdmTxPwrIdx) ++ { ++ //u1bTmp = ((u1bTmp+16) > 35) ? 35: (u1bTmp+16); // 8dbm ++ //write_nic_byte(dev, OFDM_TXAGC, u1bTmp); ++ write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); ++ } ++ } ++ } ++ ++ //printk("<---- DoTxHighPower()\n"); ++} ++ ++ ++// ++// Description: ++// Callback function of UpdateTxPowerWorkItem. ++// Because of some event happend, e.g. CCX TPC, High Power Mechanism, ++// We update Tx power of current channel again. ++// ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_tx_pw_wq (struct work_struct *work) ++{ ++// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); ++// struct ieee80211_device * ieee = (struct ieee80211_device*) ++// container_of(work, struct ieee80211_device, watch_dog_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,tx_pw_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_tx_pw_wq(struct net_device *dev) ++{ ++ // struct r8180_priv *priv = ieee80211_priv(dev); ++#endif ++ ++// printk("----> UpdateTxPowerWorkItemCallback()\n"); ++ ++ DoTxHighPower(dev); ++ ++// printk("<---- UpdateTxPowerWorkItemCallback()\n"); ++} ++ ++ ++// ++// Description: ++// Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise. ++// ++bool ++CheckDig( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ if(!priv->bDigMechanism) ++ return false; ++ ++ if(ieee->state != IEEE80211_LINKED) ++ return false; ++ ++ //if(priv->CurrentOperaRate < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01. ++ if((priv->ieee80211->rate/5) < 36) // Schedule Dig under all OFDM rates. By Bruce, 2007-06-01. ++ return false; ++ return true; ++} ++// ++// Description: ++// Implementation of DIG for Zebra and Zebra2. ++// ++void ++DIG_Zebra( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 CCKFalseAlarm, OFDMFalseAlarm; ++ u16 OfdmFA1, OfdmFA2; ++ int InitialGainStep = 7; // The number of initial gain stages. ++ int LowestGainStage = 4; // The capable lowest stage of performing dig workitem. ++ u32 AwakePeriodIn2Sec=0; ++ ++ //printk("---------> DIG_Zebra()\n"); ++ ++ CCKFalseAlarm = (u16)(priv->FalseAlarmRegValue & 0x0000ffff); ++ OFDMFalseAlarm = (u16)((priv->FalseAlarmRegValue >> 16) & 0x0000ffff); ++ OfdmFA1 = 0x15; ++ OfdmFA2 = ((u16)(priv->RegDigOfdmFaUpTh)) << 8; ++ ++// printk("DIG**********CCK False Alarm: %#X \n",CCKFalseAlarm); ++// printk("DIG**********OFDM False Alarm: %#X \n",OFDMFalseAlarm); ++ ++ // The number of initial gain steps is different, by Bruce, 2007-04-13. ++ if (priv->InitialGain == 0 ) //autoDIG ++ { // Advised from SD3 DZ ++ priv->InitialGain = 4; // In 87B, m74dBm means State 4 (m82dBm) ++ } ++ //if(pHalData->VersionID != VERSION_8187B_B) ++ { // Advised from SD3 DZ ++ OfdmFA1 = 0x20; ++ } ++ ++#if 1 //lzm reserved 080826 ++ AwakePeriodIn2Sec = (2000-priv ->DozePeriodInPast2Sec); ++ //printk("&&& DozePeriod=%d AwakePeriod=%d\n", priv->DozePeriodInPast2Sec, AwakePeriodIn2Sec); ++ priv ->DozePeriodInPast2Sec=0; ++ ++ if(AwakePeriodIn2Sec) ++ { ++ //RT_TRACE(COMP_DIG, DBG_TRACE, ("DIG: AwakePeriodIn2Sec(%d) - FATh(0x%X , 0x%X) ->",AwakePeriodIn2Sec, OfdmFA1, OfdmFA2)); ++ // adjuest DIG threshold. ++ OfdmFA1 = (u16)((OfdmFA1*AwakePeriodIn2Sec) / 2000) ; ++ OfdmFA2 = (u16)((OfdmFA2*AwakePeriodIn2Sec) / 2000) ; ++ //RT_TRACE(COMP_DIG, DBG_TRACE, ("( 0x%X , 0x%X)\n", OfdmFA1, OfdmFA2)); ++ } ++ else ++ { ++ ;//RT_TRACE(COMP_DIG, DBG_WARNING, ("ERROR!! AwakePeriodIn2Sec should not be ZERO!!\n")); ++ } ++#endif ++ ++ InitialGainStep = 8; ++ LowestGainStage = priv->RegBModeGainStage; // Lowest gain stage. ++ ++ if (OFDMFalseAlarm > OfdmFA1) ++ { ++ if (OFDMFalseAlarm > OfdmFA2) ++ { ++ priv->DIG_NumberFallbackVote++; ++ if (priv->DIG_NumberFallbackVote >1) ++ { ++ //serious OFDM False Alarm, need fallback ++ if (priv->InitialGain < InitialGainStep) ++ { ++ priv->InitialGainBackUp= priv->InitialGain; ++ ++ priv->InitialGain = (priv->InitialGain + 1); ++// printk("DIG**********OFDM False Alarm: %#X, OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2); ++// printk("DIG+++++++ fallback OFDM:%d \n", priv->InitialGain); ++ UpdateInitialGain(dev); ++ } ++ priv->DIG_NumberFallbackVote = 0; ++ priv->DIG_NumberUpgradeVote=0; ++ } ++ } ++ else ++ { ++ if (priv->DIG_NumberFallbackVote) ++ priv->DIG_NumberFallbackVote--; ++ } ++ priv->DIG_NumberUpgradeVote=0; ++ } ++ else ++ { ++ if (priv->DIG_NumberFallbackVote) ++ priv->DIG_NumberFallbackVote--; ++ priv->DIG_NumberUpgradeVote++; ++ ++ if (priv->DIG_NumberUpgradeVote>9) ++ { ++ if (priv->InitialGain > LowestGainStage) // In 87B, m78dBm means State 4 (m864dBm) ++ { ++ priv->InitialGainBackUp= priv->InitialGain; ++ ++ priv->InitialGain = (priv->InitialGain - 1); ++// printk("DIG**********OFDM False Alarm: %#X, OfdmFA1: %#X, OfdmFA2: %#X\n", OFDMFalseAlarm, OfdmFA1, OfdmFA2); ++// printk("DIG--------- Upgrade OFDM:%d \n", priv->InitialGain); ++ UpdateInitialGain(dev); ++ } ++ priv->DIG_NumberFallbackVote = 0; ++ priv->DIG_NumberUpgradeVote=0; ++ } ++ } ++ ++// printk("DIG+++++++ OFDM:%d\n", priv->InitialGain); ++ //printk("<--------- DIG_Zebra()\n"); ++} ++ ++// ++// Description: ++// Dispatch DIG implementation according to RF. ++// ++void ++DynamicInitGain( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: // [AnnieWorkaround] For Zebra2, 2005-08-01. ++ case RF_ZEBRA4: ++ DIG_Zebra( dev ); ++ break; ++ ++ default: ++ printk("DynamicInitGain(): unknown RFChipID(%d) !!!\n", priv->rf_chip); ++ break; ++ } ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_dig_wq (struct work_struct *work) ++{ ++// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); ++// struct ieee80211_device * ieee = (struct ieee80211_device*) ++// container_of(work, struct ieee80211_device, watch_dog_wq); ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_dig_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_hw_dig_wq(struct net_device *dev) ++{ ++ ++#endif ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ // Read CCK and OFDM False Alarm. ++ priv->FalseAlarmRegValue = read_nic_dword(dev, CCK_FALSE_ALARM); ++ ++ ++ // Adjust Initial Gain dynamically. ++ DynamicInitGain(dev); ++ ++} ++ ++int ++IncludedInSupportedRates( ++ struct r8180_priv *priv, ++ u8 TxRate ) ++{ ++ u8 rate_len; ++ u8 rate_ex_len; ++ u8 RateMask = 0x7F; ++ u8 idx; ++ unsigned short Found = 0; ++ u8 NaiveTxRate = TxRate&RateMask; ++ ++ rate_len = priv->ieee80211->current_network.rates_len; ++ rate_ex_len = priv->ieee80211->current_network.rates_ex_len; ++ for( idx=0; idx< rate_len; idx++ ) ++ { ++ if( (priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate ) ++ { ++ Found = 1; ++ goto found_rate; ++ } ++ } ++ for( idx=0; idx< rate_ex_len; idx++ ) ++ { ++ if( (priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate ) ++ { ++ Found = 1; ++ goto found_rate; ++ } ++ } ++ return Found; ++ found_rate: ++ return Found; ++} ++ ++// ++// Description: ++// Get the Tx rate one degree up form the input rate in the supported rates. ++// Return the upgrade rate if it is successed, otherwise return the input rate. ++// By Bruce, 2007-06-05. ++// ++u8 ++GetUpgradeTxRate( ++ struct net_device *dev, ++ u8 rate ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 UpRate; ++ ++ // Upgrade 1 degree. ++ switch(rate) ++ { ++ case 108: // Up to 54Mbps. ++ UpRate = 108; ++ break; ++ ++ case 96: // Up to 54Mbps. ++ UpRate = 108; ++ break; ++ ++ case 72: // Up to 48Mbps. ++ UpRate = 96; ++ break; ++ ++ case 48: // Up to 36Mbps. ++ UpRate = 72; ++ break; ++ ++ case 36: // Up to 24Mbps. ++ UpRate = 48; ++ break; ++ ++ case 22: // Up to 18Mbps. ++ UpRate = 36; ++ break; ++ ++ case 11: // Up to 11Mbps. ++ UpRate = 22; ++ break; ++ ++ case 4: // Up to 5.5Mbps. ++ UpRate = 11; ++ break; ++ ++ case 2: // Up to 2Mbps. ++ UpRate = 4; ++ break; ++ ++ default: ++ printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); ++ return rate; ++ } ++ // Check if the rate is valid. ++ if(IncludedInSupportedRates(priv, UpRate)) ++ { ++// printk("GetUpgradeTxRate(): GetUpgrade Tx rate(%d) from %d !\n", UpRate, priv->CurrentOperaRate); ++ return UpRate; ++ } ++ else ++ { ++ //printk("GetUpgradeTxRate(): Tx rate (%d) is not in supported rates\n", UpRate); ++ return rate; ++ } ++ return rate; ++} ++// ++// Description: ++// Get the Tx rate one degree down form the input rate in the supported rates. ++// Return the degrade rate if it is successed, otherwise return the input rate. ++// By Bruce, 2007-06-05. ++// ++u8 ++GetDegradeTxRate( ++ struct net_device *dev, ++ u8 rate ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 DownRate; ++ ++ // Upgrade 1 degree. ++ switch(rate) ++ { ++ case 108: // Down to 48Mbps. ++ DownRate = 96; ++ break; ++ ++ case 96: // Down to 36Mbps. ++ DownRate = 72; ++ break; ++ ++ case 72: // Down to 24Mbps. ++ DownRate = 48; ++ break; ++ ++ case 48: // Down to 18Mbps. ++ DownRate = 36; ++ break; ++ ++ case 36: // Down to 11Mbps. ++ DownRate = 22; ++ break; ++ ++ case 22: // Down to 5.5Mbps. ++ DownRate = 11; ++ break; ++ ++ case 11: // Down to 2Mbps. ++ DownRate = 4; ++ break; ++ ++ case 4: // Down to 1Mbps. ++ DownRate = 2; ++ break; ++ ++ case 2: // Down to 1Mbps. ++ DownRate = 2; ++ break; ++ ++ default: ++ printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); ++ return rate; ++ } ++ // Check if the rate is valid. ++ if(IncludedInSupportedRates(priv, DownRate)) ++ { ++// printk("GetDegradeTxRate(): GetDegrade Tx rate(%d) from %d!\n", DownRate, priv->CurrentOperaRate); ++ return DownRate; ++ } ++ else ++ { ++ //printk("GetDegradeTxRate(): Tx rate (%d) is not in supported rates\n", DownRate); ++ return rate; ++ } ++ return rate; ++} ++// ++// Helper function to determine if specified data rate is ++// CCK rate. ++// 2005.01.25, by rcnjko. ++// ++bool ++MgntIsCckRate( ++ u16 rate ++ ) ++{ ++ bool bReturn = false; ++ ++ if((rate <= 22) && (rate != 12) && (rate != 18)) ++ { ++ bReturn = true; ++ } ++ ++ return bReturn; ++} ++#ifdef CONFIG_RTL818X_S ++// ++// Description: ++// Tx Power tracking mechanism routine on 87SE. ++// Created by Roger, 2007.12.11. ++// ++void ++TxPwrTracking87SE( ++ struct net_device *dev ++) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u8 tmpu1Byte, CurrentThermal, Idx; ++ char CckTxPwrIdx, OfdmTxPwrIdx; ++ //u32 u4bRfReg; ++ ++ tmpu1Byte = read_nic_byte(dev, EN_LPF_CAL); ++ CurrentThermal = (tmpu1Byte & 0xf0)>>4; //[ 7:4]: thermal meter indication. ++ CurrentThermal = (CurrentThermal>0x0c)? 0x0c:CurrentThermal;//lzm add 080826 ++ ++ //printk("TxPwrTracking87SE(): CurrentThermal(%d)\n", CurrentThermal); ++ ++ if( CurrentThermal != priv->ThermalMeter) ++ { ++// printk("TxPwrTracking87SE(): Thermal meter changed!!!\n"); ++ ++ // Update Tx Power level on each channel. ++ for(Idx = 1; Idx<15; Idx++) ++ { ++ CckTxPwrIdx = priv->chtxpwr[Idx]; ++ OfdmTxPwrIdx = priv->chtxpwr_ofdm[Idx]; ++ ++ if( CurrentThermal > priv->ThermalMeter ) ++ { // higher thermal meter. ++ CckTxPwrIdx += (CurrentThermal - priv->ThermalMeter)*2; ++ OfdmTxPwrIdx += (CurrentThermal - priv->ThermalMeter)*2; ++ ++ if(CckTxPwrIdx >35) ++ CckTxPwrIdx = 35; // Force TxPower to maximal index. ++ if(OfdmTxPwrIdx >35) ++ OfdmTxPwrIdx = 35; ++ } ++ else ++ { // lower thermal meter. ++ CckTxPwrIdx -= (priv->ThermalMeter - CurrentThermal)*2; ++ OfdmTxPwrIdx -= (priv->ThermalMeter - CurrentThermal)*2; ++ ++ if(CckTxPwrIdx <0) ++ CckTxPwrIdx = 0; ++ if(OfdmTxPwrIdx <0) ++ OfdmTxPwrIdx = 0; ++ } ++ ++ // Update TxPower level on CCK and OFDM resp. ++ priv->chtxpwr[Idx] = CckTxPwrIdx; ++ priv->chtxpwr_ofdm[Idx] = OfdmTxPwrIdx; ++ } ++ ++ // Update TxPower level immediately. ++ rtl8225z2_SetTXPowerLevel(dev, priv->ieee80211->current_network.channel); ++ } ++ priv->ThermalMeter = CurrentThermal; ++} ++void ++StaRateAdaptive87SE( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ unsigned long CurrTxokCnt; ++ u16 CurrRetryCnt; ++ u16 CurrRetryRate; ++ //u16 i,idx; ++ unsigned long CurrRxokCnt; ++ bool bTryUp = false; ++ bool bTryDown = false; ++ u8 TryUpTh = 1; ++ u8 TryDownTh = 2; ++ u32 TxThroughput; ++ long CurrSignalStrength; ++ bool bUpdateInitialGain = false; ++ u8 u1bOfdm=0, u1bCck = 0; ++ char OfdmTxPwrIdx, CckTxPwrIdx; ++ ++ priv->RateAdaptivePeriod= RATE_ADAPTIVE_TIMER_PERIOD; ++ ++ ++ CurrRetryCnt = priv->CurrRetryCnt; ++ CurrTxokCnt = priv->NumTxOkTotal - priv->LastTxokCnt; ++ CurrRxokCnt = priv->ieee80211->NumRxOkTotal - priv->LastRxokCnt; ++ CurrSignalStrength = priv->Stats_RecvSignalPower; ++ TxThroughput = (u32)(priv->NumTxOkBytesTotal - priv->LastTxOKBytes); ++ priv->LastTxOKBytes = priv->NumTxOkBytesTotal; ++ priv->CurrentOperaRate = priv->ieee80211->rate/5; ++ //printk("priv->CurrentOperaRate is %d\n",priv->CurrentOperaRate); ++ //2 Compute retry ratio. ++ if (CurrTxokCnt>0) ++ { ++ CurrRetryRate = (u16)(CurrRetryCnt*100/CurrTxokCnt); ++ } ++ else ++ { // It may be serious retry. To distinguish serious retry or no packets modified by Bruce ++ CurrRetryRate = (u16)(CurrRetryCnt*100/1); ++ } ++ ++ ++ // ++ // Added by Roger, 2007.01.02. ++ // For debug information. ++ // ++ //printk("\n(1) pHalData->LastRetryRate: %d \n",priv->LastRetryRate); ++ //printk("(2) RetryCnt = %d \n", CurrRetryCnt); ++ //printk("(3) TxokCnt = %d \n", CurrTxokCnt); ++ //printk("(4) CurrRetryRate = %d \n", CurrRetryRate); ++ //printk("(5) CurrSignalStrength = %d \n",CurrSignalStrength); ++ //printk("(6) TxThroughput is %d\n",TxThroughput); ++ //printk("priv->NumTxOkBytesTotal is %d\n",priv->NumTxOkBytesTotal); ++ ++ priv->LastRetryCnt = priv->CurrRetryCnt; ++ priv->LastTxokCnt = priv->NumTxOkTotal; ++ priv->LastRxokCnt = priv->ieee80211->NumRxOkTotal; ++ priv->CurrRetryCnt = 0; ++ ++ //2No Tx packets, return to init_rate or not? ++ if (CurrRetryRate==0 && CurrTxokCnt == 0) ++ { ++ // ++ //After 9 (30*300ms) seconds in this condition, we try to raise rate. ++ // ++ priv->TryupingCountNoData++; ++ ++// printk("No Tx packets, TryupingCountNoData(%d)\n", priv->TryupingCountNoData); ++ //[TRC Dell Lab] Extend raised period from 4.5sec to 9sec, Isaiah 2008-02-15 18:00 ++ if (priv->TryupingCountNoData>30) ++ { ++ priv->TryupingCountNoData = 0; ++ priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); ++ // Reset Fail Record ++ priv->LastFailTxRate = 0; ++ priv->LastFailTxRateSS = -200; ++ priv->FailTxRateCount = 0; ++ } ++ goto SetInitialGain; ++ } ++ else ++ { ++ priv->TryupingCountNoData=0; //Reset trying up times. ++ } ++ ++ ++ // ++ // For Netgear case, I comment out the following signal strength estimation, ++ // which can results in lower rate to transmit when sample is NOT enough (e.g. PING request). ++ // 2007.04.09, by Roger. ++ // ++ ++ // ++ // Restructure rate adaptive as the following main stages: ++ // (1) Add retry threshold in 54M upgrading condition with signal strength. ++ // (2) Add the mechanism to degrade to CCK rate according to signal strength ++ // and retry rate. ++ // (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated ++ // situation, Initial Gain Update is upon on DIG mechanism except CCK rate. ++ // (4) Add the mehanism of trying to upgrade tx rate. ++ // (5) Record the information of upping tx rate to avoid trying upping tx rate constantly. ++ // By Bruce, 2007-06-05. ++ // ++ // ++ ++ // 11Mbps or 36Mbps ++ // Check more times in these rate(key rates). ++ // ++ if(priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72) ++ { ++ TryUpTh += 9; ++ } ++ // ++ // Let these rates down more difficult. ++ // ++ if(MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36) ++ { ++ TryDownTh += 1; ++ } ++ ++ //1 Adjust Rate. ++ if (priv->bTryuping == true) ++ { ++ //2 For Test Upgrading mechanism ++ // Note: ++ // Sometimes the throughput is upon on the capability bwtween the AP and NIC, ++ // thus the low data rate does not improve the performance. ++ // We randomly upgrade the data rate and check if the retry rate is improved. ++ ++ // Upgrading rate did not improve the retry rate, fallback to the original rate. ++ if ( (CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput) ++ { ++ //Not necessary raising rate, fall back rate. ++ bTryDown = true; ++ //printk("case1-1: Not necessary raising rate, fall back rate....\n"); ++ //printk("case1-1: pMgntInfo->CurrentOperaRate =%d, TxThroughput = %d, LastThroughput = %d\n", ++ // priv->CurrentOperaRate, TxThroughput, priv->LastTxThroughput); ++ } ++ else ++ { ++ priv->bTryuping = false; ++ } ++ } ++ else if (CurrSignalStrength > -47 && (CurrRetryRate < 50)) ++ { ++ //2For High Power ++ // ++ // Added by Roger, 2007.04.09. ++ // Return to highest data rate, if signal strength is good enough. ++ // SignalStrength threshold(-50dbm) is for RTL8186. ++ // Revise SignalStrength threshold to -51dbm. ++ // ++ // Also need to check retry rate for safety, by Bruce, 2007-06-05. ++ if(priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate ) ++ { ++ bTryUp = true; ++ // Upgrade Tx Rate directly. ++ priv->TryupingCount += TryUpTh; ++ } ++// printk("case2: StaRateAdaptive87SE: Power(%d) is high enough!!. \n", CurrSignalStrength); ++ ++ } ++ else if(CurrTxokCnt > 9 && CurrTxokCnt< 100 && CurrRetryRate >= 600) ++ { ++ //2 For Serious Retry ++ // ++ // Traffic is not busy but our Tx retry is serious. ++ // ++ bTryDown = true; ++ // Let Rate Mechanism to degrade tx rate directly. ++ priv->TryDownCountLowData += TryDownTh; ++// printk("case3: RA: Tx Retry is serious. Degrade Tx Rate to %d directly...\n", priv->CurrentOperaRate); ++ } ++ else if ( priv->CurrentOperaRate == 108 ) ++ { ++ //2For 54Mbps ++ // Air Link ++ if ( (CurrRetryRate>26)&&(priv->LastRetryRate>25)) ++// if ( (CurrRetryRate>40)&&(priv->LastRetryRate>39)) ++ { ++ //Down to rate 48Mbps. ++ bTryDown = true; ++ } ++ // Cable Link ++ else if ( (CurrRetryRate>17)&&(priv->LastRetryRate>16) && (CurrSignalStrength > -72)) ++// else if ( (CurrRetryRate>17)&&(priv->LastRetryRate>16) && (CurrSignalStrength > -72)) ++ { ++ //Down to rate 48Mbps. ++ bTryDown = true; ++ } ++ ++ if(bTryDown && (CurrSignalStrength < -75)) //cable link ++ { ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ //printk("case4---54M \n"); ++ ++ } ++ else if ( priv->CurrentOperaRate == 96 ) ++ { ++ //2For 48Mbps ++ //Air Link ++ if ( ((CurrRetryRate>48) && (priv->LastRetryRate>47))) ++// if ( ((CurrRetryRate>65) && (priv->LastRetryRate>64))) ++ ++ { ++ //Down to rate 36Mbps. ++ bTryDown = true; ++ } ++ //Cable Link ++ else if ( ((CurrRetryRate>21) && (priv->LastRetryRate>20)) && (CurrSignalStrength > -74)) ++ { ++ //Down to rate 36Mbps. ++ bTryDown = true; ++ } ++ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 )) ++// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 )) ++ { ++ bTryDown = true; ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ else if ( (CurrRetryRate<8) && (priv->LastRetryRate<8) ) //TO DO: need to consider (RSSI) ++// else if ( (CurrRetryRate<28) && (priv->LastRetryRate<8) ) ++ { ++ bTryUp = true; ++ } ++ ++ if(bTryDown && (CurrSignalStrength < -75)) ++ { ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ //printk("case5---48M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 72 ) ++ { ++ //2For 36Mbps ++ if ( (CurrRetryRate>43) && (priv->LastRetryRate>41)) ++// if ( (CurrRetryRate>60) && (priv->LastRetryRate>59)) ++ { ++ //Down to rate 24Mbps. ++ bTryDown = true; ++ } ++ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 )) ++// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 )) ++ { ++ bTryDown = true; ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ else if ( (CurrRetryRate<15) && (priv->LastRetryRate<16)) //TO DO: need to consider (RSSI) ++// else if ( (CurrRetryRate<35) && (priv->LastRetryRate<36)) ++ { ++ bTryUp = true; ++ } ++ ++ if(bTryDown && (CurrSignalStrength < -80)) ++ { ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ //printk("case6---36M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 48 ) ++ { ++ //2For 24Mbps ++ // Air Link ++ if ( ((CurrRetryRate>63) && (priv->LastRetryRate>62))) ++// if ( ((CurrRetryRate>83) && (priv->LastRetryRate>82))) ++ { ++ //Down to rate 18Mbps. ++ bTryDown = true; ++ } ++ //Cable Link ++ else if ( ((CurrRetryRate>33) && (priv->LastRetryRate>32)) && (CurrSignalStrength > -82) ) ++// else if ( ((CurrRetryRate>50) && (priv->LastRetryRate>49)) && (CurrSignalStrength > -82) ) ++ { ++ //Down to rate 18Mbps. ++ bTryDown = true; ++ } ++ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 )) ++// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 )) ++ ++ { ++ bTryDown = true; ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ else if ( (CurrRetryRate<20) && (priv->LastRetryRate<21)) //TO DO: need to consider (RSSI) ++// else if ( (CurrRetryRate<40) && (priv->LastRetryRate<41)) ++ { ++ bTryUp = true; ++ } ++ ++ if(bTryDown && (CurrSignalStrength < -82)) ++ { ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ //printk("case7---24M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 36 ) ++ { ++ //2For 18Mbps ++ // original (109, 109) ++ //[TRC Dell Lab] (90, 91), Isaiah 2008-02-18 23:24 ++ // (85, 86), Isaiah 2008-02-18 24:00 ++ if ( ((CurrRetryRate>85) && (priv->LastRetryRate>86))) ++// if ( ((CurrRetryRate>115) && (priv->LastRetryRate>116))) ++ { ++ //Down to rate 11Mbps. ++ bTryDown = true; ++ } ++ //[TRC Dell Lab] Isaiah 2008-02-18 23:24 ++ else if((CurrRetryRate> (priv->LastRetryRate + 50 )) && (priv->FailTxRateCount >2 )) ++// else if((CurrRetryRate> (priv->LastRetryRate + 70 )) && (priv->FailTxRateCount >2 )) ++ { ++ bTryDown = true; ++ priv->TryDownCountLowData += TryDownTh; ++ } ++ else if ( (CurrRetryRate<22) && (priv->LastRetryRate<23)) //TO DO: need to consider (RSSI) ++// else if ( (CurrRetryRate<42) && (priv->LastRetryRate<43)) ++ { ++ bTryUp = true; ++ } ++ //printk("case8---18M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 22 ) ++ { ++ //2For 11Mbps ++ if (CurrRetryRate>95) ++// if (CurrRetryRate>155) ++ { ++ bTryDown = true; ++ } ++ else if ( (CurrRetryRate<29) && (priv->LastRetryRate <30) )//TO DO: need to consider (RSSI) ++// else if ( (CurrRetryRate<49) && (priv->LastRetryRate <50) ) ++ { ++ bTryUp = true; ++ } ++ //printk("case9---11M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 11 ) ++ { ++ //2For 5.5Mbps ++ if (CurrRetryRate>149) ++// if (CurrRetryRate>189) ++ { ++ bTryDown = true; ++ } ++ else if ( (CurrRetryRate<60) && (priv->LastRetryRate < 65)) ++// else if ( (CurrRetryRate<80) && (priv->LastRetryRate < 85)) ++ ++ { ++ bTryUp = true; ++ } ++ //printk("case10---5.5M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 4 ) ++ { ++ //2For 2 Mbps ++ if((CurrRetryRate>99) && (priv->LastRetryRate>99)) ++// if((CurrRetryRate>199) && (priv->LastRetryRate>199)) ++ { ++ bTryDown = true; ++ } ++ else if ( (CurrRetryRate < 65) && (priv->LastRetryRate < 70)) ++// else if ( (CurrRetryRate < 85) && (priv->LastRetryRate < 90)) ++ { ++ bTryUp = true; ++ } ++ //printk("case11---2M \n"); ++ } ++ else if ( priv->CurrentOperaRate == 2 ) ++ { ++ //2For 1 Mbps ++ if( (CurrRetryRate<70) && (priv->LastRetryRate<75)) ++// if( (CurrRetryRate<90) && (priv->LastRetryRate<95)) ++ { ++ bTryUp = true; ++ } ++ //printk("case12---1M \n"); ++ } ++ ++ if(bTryUp && bTryDown) ++ printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n"); ++ ++ //1 Test Upgrading Tx Rate ++ // Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC. ++ // To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate. ++ if(!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0) ++ && priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2) ++ { ++ if(jiffies% (CurrRetryRate + 101) == 0) ++ { ++ bTryUp = true; ++ priv->bTryuping = true; ++ //printk("StaRateAdaptive87SE(): Randomly try upgrading...\n"); ++ } ++ } ++ ++ //1 Rate Mechanism ++ if(bTryUp) ++ { ++ priv->TryupingCount++; ++ priv->TryDownCountLowData = 0; ++ ++ { ++// printk("UP: pHalData->TryupingCount = %d\n", priv->TryupingCount); ++// printk("UP: TryUpTh(%d)+ (FailTxRateCount(%d))^2 =%d\n", ++// TryUpTh, priv->FailTxRateCount, (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount) ); ++// printk("UP: pHalData->bTryuping=%d\n", priv->bTryuping); ++ ++ } ++ ++ // ++ // Check more times if we need to upgrade indeed. ++ // Because the largest value of pHalData->TryupingCount is 0xFFFF and ++ // the largest value of pHalData->FailTxRateCount is 0x14, ++ // this condition will be satisfied at most every 2 min. ++ // ++ ++ if((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) || ++ (CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping) ++ { ++ priv->TryupingCount = 0; ++ // ++ // When transfering from CCK to OFDM, DIG is an important issue. ++ // ++ if(priv->CurrentOperaRate == 22) ++ bUpdateInitialGain = true; ++ ++ // The difference in throughput between 48Mbps and 36Mbps is 8M. ++ // So, we must be carefully in this rate scale. Isaiah 2008-02-15. ++ // ++ if( ((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) && ++ (priv->FailTxRateCount > 2) ) ++ priv->RateAdaptivePeriod= (RATE_ADAPTIVE_TIMER_PERIOD/2); ++ ++ // (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold. ++ // (2)If the signal strength is increased, it may be able to upgrade. ++ ++ priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); ++// printk("StaRateAdaptive87SE(): Upgrade Tx Rate to %d\n", priv->CurrentOperaRate); ++ ++ //[TRC Dell Lab] Bypass 12/9/6, Isaiah 2008-02-18 20:00 ++ if(priv->CurrentOperaRate ==36) ++ { ++ priv->bUpdateARFR=true; ++ write_nic_word(dev, ARFR, 0x0F8F); //bypass 12/9/6 ++// printk("UP: ARFR=0xF8F\n"); ++ } ++ else if(priv->bUpdateARFR) ++ { ++ priv->bUpdateARFR=false; ++ write_nic_word(dev, ARFR, 0x0FFF); //set 1M ~ 54Mbps. ++// printk("UP: ARFR=0xFFF\n"); ++ } ++ ++ // Update Fail Tx rate and count. ++ if(priv->LastFailTxRate != priv->CurrentOperaRate) ++ { ++ priv->LastFailTxRate = priv->CurrentOperaRate; ++ priv->FailTxRateCount = 0; ++ priv->LastFailTxRateSS = -200; // Set lowest power. ++ } ++ } ++ } ++ else ++ { ++ if(priv->TryupingCount > 0) ++ priv->TryupingCount --; ++ } ++ ++ if(bTryDown) ++ { ++ priv->TryDownCountLowData++; ++ priv->TryupingCount = 0; ++ { ++// printk("DN: pHalData->TryDownCountLowData = %d\n",priv->TryDownCountLowData); ++// printk("DN: TryDownTh =%d\n", TryDownTh); ++// printk("DN: pHalData->bTryuping=%d\n", priv->bTryuping); ++ } ++ ++ //Check if Tx rate can be degraded or Test trying upgrading should fallback. ++ if(priv->TryDownCountLowData > TryDownTh || priv->bTryuping) ++ { ++ priv->TryDownCountLowData = 0; ++ priv->bTryuping = false; ++ // Update fail information. ++ if(priv->LastFailTxRate == priv->CurrentOperaRate) ++ { ++ priv->FailTxRateCount ++; ++ // Record the Tx fail rate signal strength. ++ if(CurrSignalStrength > priv->LastFailTxRateSS) ++ { ++ priv->LastFailTxRateSS = CurrSignalStrength; ++ } ++ } ++ else ++ { ++ priv->LastFailTxRate = priv->CurrentOperaRate; ++ priv->FailTxRateCount = 1; ++ priv->LastFailTxRateSS = CurrSignalStrength; ++ } ++ priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate); ++ ++ // Reduce chariot training time at weak signal strength situation. SD3 ED demand. ++ //[TRC Dell Lab] Revise Signal Threshold from -75 to -80 , Isaiah 2008-02-18 20:00 ++ if( (CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72 )) ++ { ++ priv->CurrentOperaRate = 72; ++// printk("DN: weak signal strength (%d), degrade to 36Mbps\n", CurrSignalStrength); ++ } ++ ++ //[TRC Dell Lab] Bypass 12/9/6, Isaiah 2008-02-18 20:00 ++ if(priv->CurrentOperaRate ==36) ++ { ++ priv->bUpdateARFR=true; ++ write_nic_word(dev, ARFR, 0x0F8F); //bypass 12/9/6 ++// printk("DN: ARFR=0xF8F\n"); ++ } ++ else if(priv->bUpdateARFR) ++ { ++ priv->bUpdateARFR=false; ++ write_nic_word(dev, ARFR, 0x0FFF); //set 1M ~ 54Mbps. ++// printk("DN: ARFR=0xFFF\n"); ++ } ++ ++ // ++ // When it is CCK rate, it may need to update initial gain to receive lower power packets. ++ // ++ if(MgntIsCckRate(priv->CurrentOperaRate)) ++ { ++ bUpdateInitialGain = true; ++ } ++// printk("StaRateAdaptive87SE(): Degrade Tx Rate to %d\n", priv->CurrentOperaRate); ++ } ++ } ++ else ++ { ++ if(priv->TryDownCountLowData > 0) ++ priv->TryDownCountLowData --; ++ } ++ ++ // Keep the Tx fail rate count to equal to 0x15 at most. ++ // Reduce the fail count at least to 10 sec if tx rate is tending stable. ++ if(priv->FailTxRateCount >= 0x15 || ++ (!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6)) ++ { ++ priv->FailTxRateCount --; ++ } ++ ++ ++ OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel]; ++ CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel]; ++ ++ //[TRC Dell Lab] Mac0x9e increase 2 level in 36M~18M situation, Isaiah 2008-02-18 24:00 ++ if((priv->CurrentOperaRate < 96) &&(priv->CurrentOperaRate > 22)) ++ { ++ u1bCck = read_nic_byte(dev, CCK_TXAGC); ++ u1bOfdm = read_nic_byte(dev, OFDM_TXAGC); ++ ++ // case 1: Never enter High power ++ if(u1bCck == CckTxPwrIdx ) ++ { ++ if(u1bOfdm != (OfdmTxPwrIdx+2) ) ++ { ++ priv->bEnhanceTxPwr= true; ++ u1bOfdm = ((u1bOfdm+2) > 35) ? 35: (u1bOfdm+2); ++ write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); ++// printk("Enhance OFDM_TXAGC : +++++ u1bOfdm= 0x%x\n", u1bOfdm); ++ } ++ } ++ // case 2: enter high power ++ else if(u1bCck < CckTxPwrIdx) ++ { ++ if(!priv->bEnhanceTxPwr) ++ { ++ priv->bEnhanceTxPwr= true; ++ u1bOfdm = ((u1bOfdm+2) > 35) ? 35: (u1bOfdm+2); ++ write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); ++ //RT_TRACE(COMP_RATE, DBG_TRACE, ("Enhance OFDM_TXAGC(2) : +++++ u1bOfdm= 0x%x\n", u1bOfdm)); ++ } ++ } ++ } ++ else if(priv->bEnhanceTxPwr) //54/48/11/5.5/2/1 ++ { ++ u1bCck = read_nic_byte(dev, CCK_TXAGC); ++ u1bOfdm = read_nic_byte(dev, OFDM_TXAGC); ++ ++ // case 1: Never enter High power ++ if(u1bCck == CckTxPwrIdx ) ++ { ++ priv->bEnhanceTxPwr= false; ++ write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); ++ //printk("Recover OFDM_TXAGC : ===== u1bOfdm= 0x%x\n", OfdmTxPwrIdx); ++ } ++ // case 2: enter high power ++ else if(u1bCck < CckTxPwrIdx) ++ { ++ priv->bEnhanceTxPwr= false; ++ u1bOfdm = ((u1bOfdm-2) > 0) ? (u1bOfdm-2): 0; ++ write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); ++ //RT_TRACE(COMP_RATE, DBG_TRACE, ("Recover OFDM_TXAGC(2): ===== u1bOfdm= 0x%x\n", u1bOfdm)); ++ ++ } ++ } ++ ++ // ++ // We need update initial gain when we set tx rate "from OFDM to CCK" or ++ // "from CCK to OFDM". ++ // ++SetInitialGain: ++ if(bUpdateInitialGain) ++ { ++ if(MgntIsCckRate(priv->CurrentOperaRate)) // CCK ++ { ++ if(priv->InitialGain > priv->RegBModeGainStage) ++ { ++ priv->InitialGainBackUp= priv->InitialGain; ++ ++ if(CurrSignalStrength < -85) // Low power, OFDM [0x17] = 26. ++ { ++ //SD3 SYs suggest that CurrSignalStrength < -65, ofdm 0x17=26. ++ priv->InitialGain = priv->RegBModeGainStage; ++ } ++ else if(priv->InitialGain > priv->RegBModeGainStage + 1) ++ { ++ priv->InitialGain -= 2; ++ } ++ else ++ { ++ priv->InitialGain --; ++ } ++ printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate); ++ UpdateInitialGain(dev); ++ } ++ } ++ else // OFDM ++ { ++ if(priv->InitialGain < 4) ++ { ++ priv->InitialGainBackUp= priv->InitialGain; ++ ++ priv->InitialGain ++; ++ printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n",priv->InitialGain, priv->CurrentOperaRate); ++ UpdateInitialGain(dev); ++ } ++ } ++ } ++ ++ //Record the related info ++ priv->LastRetryRate = CurrRetryRate; ++ priv->LastTxThroughput = TxThroughput; ++ priv->ieee80211->rate = priv->CurrentOperaRate * 5; ++} ++ ++#endif ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_rate_adapter(struct work_struct * work) ++{ ++ struct delayed_work *dwork = container_of(work,struct delayed_work,work); ++ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,rate_adapter_wq); ++ struct net_device *dev = ieee->dev; ++#else ++void rtl8180_rate_adapter(struct net_device *dev) ++{ ++ ++#endif ++ //struct r8180_priv *priv = ieee80211_priv(dev); ++// DMESG("---->rtl8180_rate_adapter"); ++ StaRateAdaptive87SE(dev); ++// DMESG("<----rtl8180_rate_adapter"); ++} ++void timer_rate_adaptive(unsigned long data) ++{ ++ struct r8180_priv* priv = ieee80211_priv((struct net_device *)data); ++ //DMESG("---->timer_rate_adaptive()\n"); ++ if(!priv->up) ++ { ++// DMESG("<----timer_rate_adaptive():driver is not up!\n"); ++ return; ++ } ++ if((priv->ieee80211->iw_mode != IW_MODE_MASTER) ++ && (priv->ieee80211->state == IEEE80211_LINKED) && ++ (priv->ForcedDataRate == 0) ) ++ { ++// DMESG("timer_rate_adaptive():schedule rate_adapter_wq\n"); ++#ifdef CONFIG_RTL818X_S ++ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->rate_adapter_wq); ++// StaRateAdaptive87SE((struct net_device *)data); ++#endif ++ } ++ priv->rateadapter_timer.expires = jiffies + MSECS(priv->RateAdaptivePeriod); ++ add_timer(&priv->rateadapter_timer); ++ //DMESG("<----timer_rate_adaptive()\n"); ++} ++//by amy 080312} ++void ++SwAntennaDiversityRxOk8185( ++ struct net_device *dev, ++ u8 SignalStrength ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++// printk("+SwAntennaDiversityRxOk8185: RxSs: %d\n", SignalStrength); ++ ++ priv->AdRxOkCnt++; ++ ++ if( priv->AdRxSignalStrength != -1) ++ { ++ priv->AdRxSignalStrength = ((priv->AdRxSignalStrength*7) + (SignalStrength*3)) / 10; ++ } ++ else ++ { // Initialization case. ++ priv->AdRxSignalStrength = SignalStrength; ++ } ++//{+by amy 080312 ++ if( priv->LastRxPktAntenna ) //Main antenna. ++ priv->AdMainAntennaRxOkCnt++; ++ else // Aux antenna. ++ priv->AdAuxAntennaRxOkCnt++; ++//+by amy 080312 ++// printk("-SwAntennaDiversityRxOk8185: AdRxOkCnt: %d AdRxSignalStrength: %d\n", priv->AdRxOkCnt, priv->AdRxSignalStrength); ++} ++// ++// Description: ++// Change Antenna Switch. ++// ++bool ++SetAntenna8185( ++ struct net_device *dev, ++ u8 u1bAntennaIndex ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bAntennaSwitched = false; ++ ++// printk("+SetAntenna8185(): Antenna is switching to: %d \n", u1bAntennaIndex); ++ ++ switch(u1bAntennaIndex) ++ { ++ case 0: ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ // Mac register, main antenna ++ write_nic_byte(dev, ANTSEL, 0x03); ++ //base band ++ write_phy_cck(dev,0x11, 0x9b); // Config CCK RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x5c); // Config OFDM RX antenna. ++ ++#else ++ // Mac register, main antenna ++ write_nic_byte(dev, ANTSEL, 0x03); ++ //base band ++ write_phy_cck(dev, 0x10, 0x9b); // Config CCK RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x5c); // Config OFDM RX antenna. ++#endif ++#endif ++ ++ bAntennaSwitched = true; ++ break; ++ ++ default: ++ printk("SetAntenna8185: unkown RFChipID(%d)\n", priv->rf_chip); ++ break; ++ } ++ break; ++ ++ case 1: ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ // Mac register, aux antenna ++ write_nic_byte(dev, ANTSEL, 0x00); ++ //base band ++ write_phy_cck(dev, 0x11, 0xbb); // Config CCK RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x54); // Config OFDM RX antenna. ++#else ++ // Mac register, aux antenna ++ write_nic_byte(dev, ANTSEL, 0x00); ++ //base band ++ write_phy_cck(dev, 0x10, 0xbb); // Config CCK RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x54); // Config OFDM RX antenna. ++#endif ++#endif ++ ++ bAntennaSwitched = true; ++ break; ++ ++ default: ++ printk("SetAntenna8185: unkown RFChipID(%d)\n", priv->rf_chip); ++ break; ++ } ++ break; ++ ++ default: ++ printk("SetAntenna8185: unkown u1bAntennaIndex(%d)\n", u1bAntennaIndex); ++ break; ++ } ++ ++ if(bAntennaSwitched) ++ { ++ priv->CurrAntennaIndex = u1bAntennaIndex; ++ } ++ ++// printk("-SetAntenna8185(): return (%#X)\n", bAntennaSwitched); ++ ++ return bAntennaSwitched; ++} ++// ++// Description: ++// Toggle Antenna switch. ++// ++bool ++SwitchAntenna( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ bool bResult; ++ ++ if(priv->CurrAntennaIndex == 0) ++ { ++#if 0//lzm del 080826 ++//by amy 080312 ++#ifdef CONFIG_RTL818X_S ++ if(priv->bSwAntennaDiverity) ++ bResult = SetAntennaConfig87SE(dev, 1, true); ++ else ++#endif ++#endif ++ bResult = SetAntenna8185(dev, 1); ++//by amy 080312 ++// printk("SwitchAntenna(): switching to antenna 1 ......\n"); ++// bResult = SetAntenna8185(dev, 1);//-by amy 080312 ++ } ++ else ++ { ++#if 0//lzm del 080826 ++//by amy 080312 ++#ifdef CONFIG_RTL818X_S ++ if(priv->bSwAntennaDiverity) ++ bResult = SetAntennaConfig87SE(dev, 0, true); ++ else ++#endif ++#endif ++ bResult = SetAntenna8185(dev, 0); ++//by amy 080312 ++// printk("SwitchAntenna(): switching to antenna 0 ......\n"); ++// bResult = SetAntenna8185(dev, 0);//-by amy 080312 ++ } ++ ++ return bResult; ++} ++// ++// Description: ++// Engine of SW Antenna Diversity mechanism. ++// Since 8187 has no Tx part information, ++// this implementation is only dependend on Rx part information. ++// ++// 2006.04.17, by rcnjko. ++// ++void ++SwAntennaDiversity( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bSwCheckSS=false; ++// printk("+SwAntennaDiversity(): CurrAntennaIndex: %d\n", priv->CurrAntennaIndex); ++// printk("AdTickCount is %d\n",priv->AdTickCount); ++//by amy 080312 ++ if(bSwCheckSS) ++ { ++ priv->AdTickCount++; ++ ++ printk("(1) AdTickCount: %d, AdCheckPeriod: %d\n", ++ priv->AdTickCount, priv->AdCheckPeriod); ++ printk("(2) AdRxSignalStrength: %ld, AdRxSsThreshold: %ld\n", ++ priv->AdRxSignalStrength, priv->AdRxSsThreshold); ++ } ++// priv->AdTickCount++;//-by amy 080312 ++ ++ // Case 1. No Link. ++ if(priv->ieee80211->state != IEEE80211_LINKED) ++ { ++ // printk("SwAntennaDiversity(): Case 1. No Link.\n"); ++ ++ priv->bAdSwitchedChecking = false; ++ // I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko.. ++ SwitchAntenna(dev); ++ } ++ // Case 2. Linked but no packet received. ++ else if(priv->AdRxOkCnt == 0) ++ { ++ // printk("SwAntennaDiversity(): Case 2. Linked but no packet received.\n"); ++ ++ priv->bAdSwitchedChecking = false; ++ SwitchAntenna(dev); ++ } ++ // Case 3. Evaluate last antenna switch action and undo it if necessary. ++ else if(priv->bAdSwitchedChecking == true) ++ { ++ // printk("SwAntennaDiversity(): Case 3. Evaluate last antenna switch action.\n"); ++ ++ priv->bAdSwitchedChecking = false; ++ ++ // Adjust Rx signal strength threashold. ++ priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2; ++ ++ priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? ++ priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold; ++ if(priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched) ++ { // Rx signal strength is not improved after we swtiched antenna. => Swich back. ++// printk("SwAntennaDiversity(): Rx Signal Strength is not improved, CurrRxSs: %d, LastRxSs: %d\n", ++// priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched); ++//by amy 080312 ++ // Increase Antenna Diversity checking period due to bad decision. ++ priv->AdCheckPeriod *= 2; ++//by amy 080312 ++ // Increase Antenna Diversity checking period. ++ if(priv->AdCheckPeriod > priv->AdMaxCheckPeriod) ++ priv->AdCheckPeriod = priv->AdMaxCheckPeriod; ++ ++ // Wrong deceision => switch back. ++ SwitchAntenna(dev); ++ } ++ else ++ { // Rx Signal Strength is improved. ++// printk("SwAntennaDiversity(): Rx Signal Strength is improved, CurrRxSs: %d, LastRxSs: %d\n", ++// priv->AdRxSignalStrength, priv->AdRxSsBeforeSwitched); ++ ++ // Reset Antenna Diversity checking period to its min value. ++ priv->AdCheckPeriod = priv->AdMinCheckPeriod; ++ } ++ ++// printk("SwAntennaDiversity(): AdRxSsThreshold: %d, AdCheckPeriod: %d\n", ++// priv->AdRxSsThreshold, priv->AdCheckPeriod); ++ } ++ // Case 4. Evaluate if we shall switch antenna now. ++ // Cause Table Speed is very fast in TRC Dell Lab, we check it every time. ++ else// if(priv->AdTickCount >= priv->AdCheckPeriod)//-by amy 080312 ++ { ++// printk("SwAntennaDiversity(): Case 4. Evaluate if we shall switch antenna now.\n"); ++ ++ priv->AdTickCount = 0; ++ ++ // ++ // We evaluate RxOk counts for each antenna first and than ++ // evaluate signal strength. ++ // The following operation can overcome the disability of CCA on both two antennas ++ // When signal strength was extremely low or high. ++ // 2008.01.30. ++ // ++ ++ // ++ // Evaluate RxOk count from each antenna if we shall switch default antenna now. ++ // Added by Roger, 2008.02.21. ++//{by amy 080312 ++ if((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt) ++ && (priv->CurrAntennaIndex == 0)) ++ { // We set Main antenna as default but RxOk count was less than Aux ones. ++ ++ // printk("SwAntennaDiversity(): Main antenna RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n", ++ // priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt); ++ ++ // Switch to Aux antenna. ++ SwitchAntenna(dev); ++ priv->bHWAdSwitched = true; ++ } ++ else if((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt) ++ && (priv->CurrAntennaIndex == 1)) ++ { // We set Aux antenna as default but RxOk count was less than Main ones. ++ ++ // printk("SwAntennaDiversity(): Aux antenna RxOK is poor, AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n", ++ // priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt); ++ ++ // Switch to Main antenna. ++ SwitchAntenna(dev); ++ priv->bHWAdSwitched = true; ++ } ++ else ++ {// Default antenna is better. ++ ++ // printk("SwAntennaDiversity(): Default antenna is better., AdMainAntennaRxOkCnt: %d, AdAuxAntennaRxOkCnt: %d\n", ++ // priv->AdMainAntennaRxOkCnt, priv->AdAuxAntennaRxOkCnt); ++ ++ // Still need to check current signal strength. ++ priv->bHWAdSwitched = false; ++ } ++ // ++ // We evaluate Rx signal strength ONLY when default antenna ++ // didn't changed by HW evaluation. ++ // 2008.02.27. ++ // ++ // [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05 ++ // For example, Throughput of aux is better than main antenna(about 10M v.s 2M), ++ // but AdRxSignalStrength is less than main. ++ // Our guess is that main antenna have lower throughput and get many change ++ // to receive more CCK packets(ex.Beacon) which have stronger SignalStrength. ++ // ++ if( (!priv->bHWAdSwitched) && (bSwCheckSS)) ++ { ++//by amy 080312} ++ // Evaluate Rx signal strength if we shall switch antenna now. ++ if(priv->AdRxSignalStrength < priv->AdRxSsThreshold) ++ { // Rx signal strength is weak => Switch Antenna. ++// printk("SwAntennaDiversity(): Rx Signal Strength is weak, CurrRxSs: %d, RxSsThreshold: %d\n", ++// priv->AdRxSignalStrength, priv->AdRxSsThreshold); ++ ++ priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength; ++ priv->bAdSwitchedChecking = true; ++ ++ SwitchAntenna(dev); ++ } ++ else ++ { // Rx signal strength is OK. ++// printk("SwAntennaDiversity(): Rx Signal Strength is OK, CurrRxSs: %d, RxSsThreshold: %d\n", ++// priv->AdRxSignalStrength, priv->AdRxSsThreshold); ++ ++ priv->bAdSwitchedChecking = false; ++ // Increase Rx signal strength threashold if necessary. ++ if( (priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && // Signal is much stronger than current threshold ++ priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) // Current threhold is not yet reach upper limit. ++ { ++ priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2; ++ priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? ++ priv->AdMaxRxSsThreshold: priv->AdRxSsThreshold;//+by amy 080312 ++ } ++ ++ // Reduce Antenna Diversity checking period if possible. ++ if( priv->AdCheckPeriod > priv->AdMinCheckPeriod ) ++ { ++ priv->AdCheckPeriod /= 2; ++ } ++ } ++ } ++ } ++//by amy 080312 ++ // Reset antenna diversity Rx related statistics. ++ priv->AdRxOkCnt = 0; ++ priv->AdMainAntennaRxOkCnt = 0; ++ priv->AdAuxAntennaRxOkCnt = 0; ++//by amy 080312 ++ ++// priv->AdRxOkCnt = 0;//-by amy 080312 ++ ++// printk("-SwAntennaDiversity()\n"); ++} ++ ++// ++// Description: ++// Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise. ++// ++bool ++CheckTxPwrTracking( struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ if(!priv->bTxPowerTrack) ++ { ++ return false; ++ } ++ ++//lzm reserved 080826 ++ //if(priv->bScanInProgress) ++ //{ ++ // return false; ++ //} ++ ++ //if 87SE is in High Power , don't do Tx Power Tracking. asked by SD3 ED. 2008-08-08 Isaiah ++ if(priv->bToUpdateTxPwr) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++ ++// ++// Description: ++// Timer callback function of SW Antenna Diversity. ++// ++void ++SwAntennaDiversityTimerCallback( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ ++ //printk("+SwAntennaDiversityTimerCallback()\n"); ++ ++ // ++ // We do NOT need to switch antenna while RF is off. ++ // 2007.05.09, added by Roger. ++ // ++ rtState = priv->eRFPowerState; ++ do{ ++ if (rtState == eRfOff) ++ { ++// printk("SwAntennaDiversityTimer - RF is OFF.\n"); ++ break; ++ } ++ else if (rtState == eRfSleep) ++ { ++ // Don't access BB/RF under Disable PLL situation. ++ //RT_TRACE((COMP_RF|COMP_ANTENNA), DBG_LOUD, ("SwAntennaDiversityTimerCallback(): RF is Sleep => skip it\n")); ++ break; ++ } ++ SwAntennaDiversity(dev); ++ ++ }while(false); ++ ++ if(priv->up) ++ { ++ priv->SwAntennaDiversityTimer.expires = jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD); ++ add_timer(&priv->SwAntennaDiversityTimer); ++ } ++ ++ //printk("-SwAntennaDiversityTimerCallback()\n"); ++} ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_dm.h +@@ -0,0 +1,41 @@ ++#ifndef R8180_DM_H ++#define R8180_DM_H ++ ++#include "r8180.h" ++//#include "r8180_hw.h" ++//#include "r8180_93cx6.h" ++void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength); ++bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex); ++bool SwitchAntenna( struct net_device *dev); ++void SwAntennaDiversity(struct net_device *dev ); ++void SwAntennaDiversityTimerCallback(struct net_device *dev); ++bool CheckDig(struct net_device *dev); ++bool CheckHighPower(struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_hw_dig_wq (struct work_struct *work); ++#else ++void rtl8180_hw_dig_wq(struct net_device *dev); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) ++void rtl8180_tx_pw_wq (struct work_struct *work); ++#else ++void rtl8180_tx_pw_wq(struct net_device *dev); ++#endif ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_rate_adapter(struct work_struct * work); ++ ++#else ++void rtl8180_rate_adapter(struct net_device *dev); ++ ++#endif ++void TxPwrTracking87SE(struct net_device *dev); ++bool CheckTxPwrTracking(struct net_device *dev); ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_rate_adapter(struct work_struct * work); ++#else ++void rtl8180_rate_adapter(struct net_device *dev); ++#endif ++void timer_rate_adaptive(unsigned long data); ++ ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_gct.c +@@ -0,0 +1,296 @@ ++/* ++ This files contains GCT radio frontend programming routines. ++ ++ This is part of rtl8180 OpenSource driver ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ Code from Rtw8180 NetBSD driver by David Young has been really useful to ++ understand some things and gets some ideas ++ ++ Code from rtl8181 project has been useful to me to understand some things. ++ ++ Some code from 'Deuce' work ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++ ++#include "r8180.h" ++#include "r8180_hw.h" ++#include "r8180_gct.h" ++ ++ ++//#define DEBUG_GCT ++ ++/* the following experiment are just experiments. ++ * this means if you enable them you can have every kind ++ * of result, included damage the RF chip, so don't ++ * touch them if you don't know what you are doing. ++ * In any case, if you do it, do at your own risk ++ */ ++ ++//#define GCT_EXPERIMENT1 //improve RX sensivity ++ ++//#define GCT_EXPERIMENT2 ++ ++//#define GCT_EXPERIMENT3 //iprove a bit RX signal quality ? ++ ++//#define GCT_EXPERIMENT4 //maybe solve some brokeness with experiment1 ? ++ ++//#define GCT_EXPERIMENT5 ++ ++//#define GCT_EXPERIMENT6 //not good ++ ++ ++u32 gct_chan[] = { ++ 0x0, //dummy channel 0 ++ 0x0, //1 ++ 0x1, //2 ++ 0x2, //3 ++ 0x3, //4 ++ 0x4, //5 ++ 0x5, //6 ++ 0x6, //7 ++ 0x7, //8 ++ 0x8, //9 ++ 0x9, //10 ++ 0xa, //11 ++ 0xb, //12 ++ 0xc, //13 ++ 0xd, //14 ++}; ++ ++int gct_encode[16] = { ++ 0, 8, 4, 0xC, ++ 2, 0xA, 6, 0xE, ++ 1, 9, 5, 0xD, ++ 3, 0xB, 7, 0xF ++}; ++ ++void gct_rf_stabilize(struct net_device *dev) ++{ ++ force_pci_posting(dev); ++ mdelay(3); //for now use a great value.. we may optimize in future ++} ++ ++ ++void write_gct(struct net_device *dev, u8 adr, u32 data) ++{ ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 phy_config; ++ ++ phy_config = gct_encode[(data & 0xf00) >> 8]; ++ phy_config |= gct_encode[(data & 0xf0) >> 4 ] << 4; ++ phy_config |= gct_encode[(data & 0xf) ] << 8; ++ phy_config |= gct_encode[(adr >> 1) & 0xf ] << 12; ++ phy_config |= (adr & 1 ) << 16; ++ phy_config |= gct_encode[(data & 0xf000)>>12] << 24; ++ ++ phy_config |= 0x90000000; // MAC will bang bits to the chip ++ ++ ++ write_nic_dword(dev,PHY_CONFIG,phy_config); ++#ifdef DEBUG_GCT ++ DMESG("Writing GCT: %x (adr %x)",phy_config,adr); ++#endif ++ gct_rf_stabilize(dev); ++} ++ ++ ++ ++void gct_write_phy_antenna(struct net_device *dev,short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 ant; ++ ++ ant = GCT_ANTENNA; ++ if(priv->antb) /*default antenna is antenna B */ ++ ant |= BB_ANTENNA_B; ++ if(ch == 14) ++ ant |= BB_ANTATTEN_CHAN14; ++ write_phy(dev,0x10,ant); ++ //DMESG("BB antenna %x ",ant); ++} ++ ++ ++void gct_rf_set_chan(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 txpw = 0xff & priv->chtxpwr[ch]; ++ u32 chan = gct_chan[ch]; ++ ++ //write_phy(dev,3,txpw); ++#ifdef DEBUG_GCT ++ DMESG("Gct set channel"); ++#endif ++ /* set TX power */ ++ write_gct(dev,0x15,0); ++ write_gct(dev,6, txpw); ++ write_gct(dev,0x15, 0x10); ++ write_gct(dev,0x15,0); ++ ++ /*set frequency*/ ++ write_gct(dev,7, 0); ++ write_gct(dev,0xB, chan); ++ write_gct(dev,7, 0x1000); ++ ++#ifdef DEBUG_GCT ++ DMESG("Gct set channel > write phy antenna"); ++#endif ++ ++ ++ gct_write_phy_antenna(dev,ch); ++ ++} ++ ++ ++void gct_rf_close(struct net_device *dev) ++{ ++ u32 anaparam; ++ ++ anaparam = read_nic_dword(dev,ANAPARAM); ++ anaparam &= 0x000fffff; ++ anaparam |= 0x3f900000; ++ rtl8180_set_anaparam(dev, anaparam); ++ ++ write_gct(dev, 0x7, 0); ++ write_gct(dev, 0x1f, 0x45); ++ write_gct(dev, 0x1f, 0x5); ++ write_gct(dev, 0x0, 0x8e4); ++} ++ ++ ++void gct_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //u32 anaparam; ++ ++ ++ write_nic_byte(dev,PHY_DELAY,0x6); //this is general ++ write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general ++ ++ //DMESG("%x", read_nic_dword(dev,ANAPARAM)); ++ /* we should set anaparm here*/ ++ //rtl8180_set_anaparam(dev,anaparam); ++ ++ write_gct(dev,0x1f,0); ++ write_gct(dev,0x1f,0); ++ write_gct(dev,0x1f,0x40); ++ write_gct(dev,0x1f,0x60); ++ write_gct(dev,0x1f,0x61); ++ write_gct(dev,0x1f,0x61); ++ write_gct(dev,0x0,0xae4); ++ write_gct(dev,0x1f,0x1); ++ write_gct(dev,0x1f,0x41); ++ write_gct(dev,0x1f,0x61); ++ write_gct(dev,0x1,0x1a23); ++ write_gct(dev,0x2,0x4971); ++ write_gct(dev,0x3,0x41de); ++ write_gct(dev,0x4,0x2d80); ++#ifdef GCT_EXPERIMENT1 ++ //write_gct(dev,0x5,0x6810); // from zydas driver. sens+ but quite slow ++ //write_gct(dev,0x5,0x681f); //good+ (somewhat stable, better sens, performance decent) ++ write_gct(dev,0x5,0x685f); //good performances, not sure sens is really so beeter ++ //write_gct(dev,0x5,0x687f); //good performances, maybe sens is not improved ++ //write_gct(dev,0x5,0x689f); //like above ++ //write_gct(dev,0x5,0x685e); //bad ++ //write_gct(dev,0x5,0x68ff); //good+ (somewhat stable, better sens(?), performance decent) ++ //write_gct(dev,0x5,0x68f0); //bad ++ //write_gct(dev,0x5,0x6cff); //sens+ but not so good ++ //write_gct(dev,0x5,0x6dff); //sens+,apparentely very good but broken ++ //write_gct(dev,0x5,0x65ff); //sens+,good ++ //write_gct(dev,0x5,0x78ff); //sens + but almost broken ++ //write_gct(dev,0x5,0x7810); //- //snes + but broken ++ //write_gct(dev,0x5,0x781f); //-- //sens + ++ //write_gct(dev,0x5,0x78f0); //low sens ++#else ++ write_gct(dev,0x5,0x61ff); //best performance but weak sensitivity ++#endif ++#ifdef GCT_EXPERIMENT2 ++ write_gct(dev,0x6,0xe); ++#else ++ write_gct(dev,0x6,0x0); ++#endif ++ write_gct(dev,0x7,0x0); ++ write_gct(dev,0x8,0x7533); ++ write_gct(dev,0x9,0xc401); ++ write_gct(dev,0xa,0x0); ++ write_gct(dev,0xc,0x1c7); ++ write_gct(dev,0xd,0x29d3); ++ write_gct(dev,0xe,0x2e8); ++ write_gct(dev,0x10,0x192); ++#ifdef GCT_EXPERIMENT3 ++ write_gct(dev,0x11,0x246); ++#else ++ write_gct(dev,0x11,0x248); ++#endif ++ write_gct(dev,0x12,0x0); ++ write_gct(dev,0x13,0x20c4); ++#ifdef GCT_EXPERIMENT4 ++ write_gct(dev,0x14,0xf488); ++#else ++ write_gct(dev,0x14,0xf4fc); ++#endif ++#ifdef GCT_EXPERIMENT5 ++ write_gct(dev,0x15,0xb152); ++#else ++ write_gct(dev,0x15,0x0); ++#endif ++#ifdef GCT_EXPERIMENT6 ++ write_gct(dev,0x1e,0x1); ++#endif ++ write_gct(dev,0x16,0x1500); ++ ++ write_gct(dev,0x7,0x1000); ++ /*write_gct(dev,0x15,0x0); ++ write_gct(dev,0x6,0x15); ++ write_gct(dev,0x15,0x8); ++ write_gct(dev,0x15,0x0); ++*/ ++ write_phy(dev,0,0xa8); ++ ++/* write_gct(dev,0x15,0x0); ++ write_gct(dev,0x6,0x12); ++ write_gct(dev,0x15,0x8); ++ write_gct(dev,0x15,0x0); ++*/ ++ write_phy(dev,3,0x0); ++ write_phy(dev,4,0xc0); /* lna det*/ ++ write_phy(dev,5,0x90); ++ write_phy(dev,6,0x1e); ++ write_phy(dev,7,0x64); ++ ++#ifdef DEBUG_GCT ++ DMESG("Gct init> write phy antenna"); ++#endif ++ ++ gct_write_phy_antenna(dev,priv->chan); ++ ++ write_phy(dev,0x11,0x88); ++ if(!priv->diversity) ++ write_phy(dev,0x12,0xc0); ++ else ++ write_phy(dev,0x12,0x40); ++ ++ write_phy(dev,0x13,0x90 | priv->cs_treshold ); ++ ++ write_phy(dev,0x19,0x0); ++ write_phy(dev,0x1a,0xa0); ++ write_phy(dev,0x1b,0x44); ++ ++#ifdef DEBUG_GCT ++ DMESG("Gct init > set channel2"); ++#endif ++ ++ gct_rf_set_chan(dev,priv->chan); ++} +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_gct.h +@@ -0,0 +1,25 @@ ++/* ++ This is part of rtl8180 OpenSource driver - v 0.20 ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++#define GCT_ANTENNA 0xA3 ++ ++ ++// we use the untouched eeprom value- cross your finger ;-) ++#define GCT_ANAPARAM_PWR1_ON ?? ++#define GCT_ANAPARAM_PWR0_ON ?? ++ ++ ++ ++void gct_rf_init(struct net_device *dev); ++void gct_rf_set_chan(struct net_device *dev,short ch); ++ ++void gct_rf_close(struct net_device *dev); +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180.h +@@ -0,0 +1,761 @@ ++/* ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++#ifndef R8180H ++#define R8180H ++ ++ ++#define RTL8180_MODULE_NAME "rtl8180" ++#define DMESG(x,a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a) ++#define DMESGW(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a) ++#define DMESGE(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a) ++ ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include //for rtnl_lock() ++#include ++#include ++#include // Necessary because we use the proc fs ++#include ++#include "ieee80211.h" ++#include ++//#include ++ ++#define EPROM_93c46 0 ++#define EPROM_93c56 1 ++ ++#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 ++ ++#define DEFAULT_FRAG_THRESHOLD 2342U ++#define MIN_FRAG_THRESHOLD 256U ++//#define MAX_FRAG_THRESHOLD 2342U ++#define DEFAULT_RTS_THRESHOLD 2342U ++#define MIN_RTS_THRESHOLD 0U ++#define MAX_RTS_THRESHOLD 2342U ++#define DEFAULT_BEACONINTERVAL 0x64U ++#define DEFAULT_BEACON_ESSID "Rtl8180" ++ ++#define DEFAULT_SSID "" ++#define DEFAULT_RETRY_RTS 7 ++#define DEFAULT_RETRY_DATA 7 ++#define PRISM_HDR_SIZE 64 ++ ++#ifdef CONFIG_RTL8185B ++ ++#define MGNT_QUEUE 0 ++#define BK_QUEUE 1 ++#define BE_QUEUE 2 ++#define VI_QUEUE 3 ++#define VO_QUEUE 4 ++#define HIGH_QUEUE 5 ++#define BEACON_QUEUE 6 ++ ++#define LOW_QUEUE BE_QUEUE ++#define NORMAL_QUEUE MGNT_QUEUE ++ ++#define aSifsTime 10 ++ ++#define sCrcLng 4 ++#define sAckCtsLng 112 // bits in ACK and CTS frames ++//+by amy 080312 ++#define RATE_ADAPTIVE_TIMER_PERIOD 300 ++ ++typedef enum _WIRELESS_MODE { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_A = 0x01, ++ WIRELESS_MODE_B = 0x02, ++ WIRELESS_MODE_G = 0x04, ++ WIRELESS_MODE_AUTO = 0x08, ++} WIRELESS_MODE; ++ ++typedef enum _VERSION_8185{ ++ // RTL8185 ++ VERSION_8185_UNKNOWN, ++ VERSION_8185_C, // C-cut ++ VERSION_8185_D, // D-cut ++ // RTL8185B ++ VERSION_8185B_B, // B-cut ++ VERSION_8185B_D, // D-cut ++ VERSION_8185B_E, // E-cut ++ //RTL8187S-PCIE ++ VERSION_8187S_B, // B-cut ++ VERSION_8187S_C, // C-cut ++ VERSION_8187S_D, // D-cut ++ ++}VERSION_8185,*PVERSION_8185; ++typedef struct ChnlAccessSetting { ++ u16 SIFS_Timer; ++ u16 DIFS_Timer; ++ u16 SlotTimeTimer; ++ u16 EIFS_Timer; ++ u16 CWminIndex; ++ u16 CWmaxIndex; ++}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING; ++ ++typedef enum{ ++ NIC_8185 = 1, ++ NIC_8185B ++ } nic_t; ++ ++typedef u32 AC_CODING; ++#define AC0_BE 0 // ACI: 0x00 // Best Effort ++#define AC1_BK 1 // ACI: 0x01 // Background ++#define AC2_VI 2 // ACI: 0x10 // Video ++#define AC3_VO 3 // ACI: 0x11 // Voice ++#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. ++ ++// ++// ECWmin/ECWmax field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. ++// ++typedef union _ECW{ ++ u8 charData; ++ struct ++ { ++ u8 ECWmin:4; ++ u8 ECWmax:4; ++ }f; // Field ++}ECW, *PECW; ++ ++// ++// ACI/AIFSN Field. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _ACI_AIFSN{ ++ u8 charData; ++ ++ struct ++ { ++ u8 AIFSN:4; ++ u8 ACM:1; ++ u8 ACI:2; ++ u8 Reserved:1; ++ }f; // Field ++}ACI_AIFSN, *PACI_AIFSN; ++ ++// ++// AC Parameters Record Format. ++// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. ++// ++typedef union _AC_PARAM{ ++ u32 longData; ++ u8 charData[4]; ++ ++ struct ++ { ++ ACI_AIFSN AciAifsn; ++ ECW Ecw; ++ u16 TXOPLimit; ++ }f; // Field ++}AC_PARAM, *PAC_PARAM; ++ ++/* it is a wrong definition. -xiong-2006-11-17 ++typedef struct ThreeWireReg { ++ u16 longData; ++ struct { ++ u8 enableB; ++ u8 data; ++ u8 clk; ++ u8 read_write; ++ } struc; ++} ThreeWireReg; ++*/ ++ ++typedef union _ThreeWire{ ++ struct _ThreeWireStruc{ ++ u16 data:1; ++ u16 clk:1; ++ u16 enableB:1; ++ u16 read_write:1; ++ u16 resv1:12; ++// u2Byte resv2:14; ++// u2Byte ThreeWireEnable:1; ++// u2Byte resv3:1; ++ }struc; ++ u16 longData; ++}ThreeWireReg; ++ ++#endif ++ ++typedef struct buffer ++{ ++ struct buffer *next; ++ u32 *buf; ++ dma_addr_t dma; ++} buffer; ++ ++//YJ,modified,080828 ++typedef struct Stats ++{ ++ unsigned long txrdu; ++ unsigned long rxrdu; ++ unsigned long rxnolast; ++ unsigned long rxnodata; ++// unsigned long rxreset; ++// unsigned long rxwrkaround; ++ unsigned long rxnopointer; ++ unsigned long txnperr; ++ unsigned long txresumed; ++ unsigned long rxerr; ++ unsigned long rxoverflow; ++ unsigned long rxint; ++ unsigned long txbkpokint; ++ unsigned long txbepoking; ++ unsigned long txbkperr; ++ unsigned long txbeperr; ++ unsigned long txnpokint; ++ unsigned long txhpokint; ++ unsigned long txhperr; ++ unsigned long ints; ++ unsigned long shints; ++ unsigned long txoverflow; ++ unsigned long rxdmafail; ++ unsigned long txbeacon; ++ unsigned long txbeaconerr; ++ unsigned long txlpokint; ++ unsigned long txlperr; ++ unsigned long txretry;//retry number tony 20060601 ++ unsigned long rxcrcerrmin;//crc error (0-500) ++ unsigned long rxcrcerrmid;//crc error (500-1000) ++ unsigned long rxcrcerrmax;//crc error (>1000) ++ unsigned long rxicverr;//ICV error ++} Stats; ++ ++#define MAX_LD_SLOT_NUM 10 ++#define KEEP_ALIVE_INTERVAL 20 // in seconds. ++#define CHECK_FOR_HANG_PERIOD 2 //be equal to watchdog check time ++#define DEFAULT_KEEP_ALIVE_LEVEL 1 ++#define DEFAULT_SLOT_NUM 2 ++#define POWER_PROFILE_AC 0 ++#define POWER_PROFILE_BATTERY 1 ++ ++typedef struct _link_detect_t ++{ ++ u32 RxFrameNum[MAX_LD_SLOT_NUM]; // number of Rx Frame / CheckForHang_period to determine link status ++ u16 SlotNum; // number of CheckForHang period to determine link status, default is 2 ++ u16 SlotIndex; ++ ++ u32 NumTxOkInPeriod; //number of packet transmitted during CheckForHang ++ u32 NumRxOkInPeriod; //number of packet received during CheckForHang ++ ++ u8 IdleCount; // (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) ++ u32 LastNumTxUnicast; ++ u32 LastNumRxUnicast; ++ ++ bool bBusyTraffic; //when it is set to 1, UI cann't scan at will. ++}link_detect_t, *plink_detect_t; ++ ++//YJ,modified,080828,end ++ ++//by amy for led ++//================================================================================ ++// LED customization. ++//================================================================================ ++ ++typedef enum _LED_STRATEGY_8185{ ++ SW_LED_MODE0, // ++ SW_LED_MODE1, // ++ HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes) ++}LED_STRATEGY_8185, *PLED_STRATEGY_8185; ++//by amy for led ++//by amy for power save ++typedef enum _LED_CTL_MODE{ ++ LED_CTL_POWER_ON = 1, ++ LED_CTL_LINK = 2, ++ LED_CTL_NO_LINK = 3, ++ LED_CTL_TX = 4, ++ LED_CTL_RX = 5, ++ LED_CTL_SITE_SURVEY = 6, ++ LED_CTL_POWER_OFF = 7 ++}LED_CTL_MODE; ++ ++typedef enum _RT_RF_POWER_STATE ++{ ++ eRfOn, ++ eRfSleep, ++ eRfOff ++}RT_RF_POWER_STATE; ++ ++enum _ReasonCode{ ++ unspec_reason = 0x1, ++ auth_not_valid = 0x2, ++ deauth_lv_ss = 0x3, ++ inactivity = 0x4, ++ ap_overload = 0x5, ++ class2_err = 0x6, ++ class3_err = 0x7, ++ disas_lv_ss = 0x8, ++ asoc_not_auth = 0x9, ++ ++ //----MIC_CHECK ++ mic_failure = 0xe, ++ //----END MIC_CHECK ++ ++ // Reason code defined in 802.11i D10.0 p.28. ++ invalid_IE = 0x0d, ++ four_way_tmout = 0x0f, ++ two_way_tmout = 0x10, ++ IE_dismatch = 0x11, ++ invalid_Gcipher = 0x12, ++ invalid_Pcipher = 0x13, ++ invalid_AKMP = 0x14, ++ unsup_RSNIEver = 0x15, ++ invalid_RSNIE = 0x16, ++ auth_802_1x_fail= 0x17, ++ ciper_reject = 0x18, ++ ++ // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. ++ QoS_unspec = 0x20, // 32 ++ QAP_bandwidth = 0x21, // 33 ++ poor_condition = 0x22, // 34 ++ no_facility = 0x23, // 35 ++ // Where is 36??? ++ req_declined = 0x25, // 37 ++ invalid_param = 0x26, // 38 ++ req_not_honored= 0x27, // 39 ++ TS_not_created = 0x2F, // 47 ++ DL_not_allowed = 0x30, // 48 ++ dest_not_exist = 0x31, // 49 ++ dest_not_QSTA = 0x32, // 50 ++}; ++typedef enum _RT_PS_MODE ++{ ++ eActive, // Active/Continuous access. ++ eMaxPs, // Max power save mode. ++ eFastPs // Fast power save mode. ++}RT_PS_MODE; ++//by amy for power save ++typedef struct r8180_priv ++{ ++ struct pci_dev *pdev; ++ ++ short epromtype; ++ int irq; ++ struct ieee80211_device *ieee80211; ++ ++ short card_8185; /* O: rtl8180, 1:rtl8185 V B/C, 2:rtl8185 V D, 3:rtl8185B */ ++ short card_8185_Bversion; /* if TCR reports card V B/C this discriminates */ ++ short phy_ver; /* meaningful for rtl8225 1:A 2:B 3:C */ ++ short enable_gpio0; ++ enum card_type {PCI,MINIPCI,CARDBUS,USB/*rtl8187*/}card_type; ++ short hw_plcp_len; ++ short plcp_preamble_mode; // 0:auto 1:short 2:long ++ ++ spinlock_t irq_lock; ++ spinlock_t irq_th_lock; ++ spinlock_t tx_lock; ++ spinlock_t ps_lock; ++ spinlock_t rf_ps_lock; ++ ++ u16 irq_mask; ++ short irq_enabled; ++ struct net_device *dev; ++ short chan; ++ short sens; ++ short max_sens; ++ u8 chtxpwr[15]; //channels from 1 to 14, 0 not used ++ u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used ++ //u8 challow[15]; //channels from 1 to 14, 0 not used ++ u8 channel_plan; // it's the channel plan index ++ short up; ++ short crcmon; //if 1 allow bad crc frame reception in monitor mode ++ short prism_hdr; ++ ++ struct timer_list scan_timer; ++ /*short scanpending; ++ short stopscan;*/ ++ spinlock_t scan_lock; ++ u8 active_probe; ++ //u8 active_scan_num; ++ struct semaphore wx_sem; ++ struct semaphore rf_state; ++ short hw_wep; ++ ++ short digphy; ++ short antb; ++ short diversity; ++ u8 cs_treshold; ++ short rcr_csense; ++ short rf_chip; ++ u32 key0[4]; ++ short (*rf_set_sens)(struct net_device *dev,short sens); ++ void (*rf_set_chan)(struct net_device *dev,short ch); ++ void (*rf_close)(struct net_device *dev); ++ void (*rf_init)(struct net_device *dev); ++ void (*rf_sleep)(struct net_device *dev); ++ void (*rf_wakeup)(struct net_device *dev); ++ //short rate; ++ short promisc; ++ /*stats*/ ++ struct Stats stats; ++ struct _link_detect_t link_detect; //YJ,add,080828 ++ struct iw_statistics wstats; ++ struct proc_dir_entry *dir_dev; ++ ++ /*RX stuff*/ ++ u32 *rxring; ++ u32 *rxringtail; ++ dma_addr_t rxringdma; ++ struct buffer *rxbuffer; ++ struct buffer *rxbufferhead; ++ int rxringcount; ++ u16 rxbuffersize; ++ ++ struct sk_buff *rx_skb; ++ ++ short rx_skb_complete; ++ ++ u32 rx_prevlen; ++ ++ /*TX stuff*/ ++/* ++ u32 *txlpring; ++ u32 *txhpring; ++ u32 *txnpring; ++ dma_addr_t txlpringdma; ++ dma_addr_t txhpringdma; ++ dma_addr_t txnpringdma; ++ u32 *txlpringtail; ++ u32 *txhpringtail; ++ u32 *txnpringtail; ++ u32 *txlpringhead; ++ u32 *txhpringhead; ++ u32 *txnpringhead; ++ struct buffer *txlpbufs; ++ struct buffer *txhpbufs; ++ struct buffer *txnpbufs; ++ struct buffer *txlpbufstail; ++ struct buffer *txhpbufstail; ++ struct buffer *txnpbufstail; ++*/ ++ u32 *txmapring; ++ u32 *txbkpring; ++ u32 *txbepring; ++ u32 *txvipring; ++ u32 *txvopring; ++ u32 *txhpring; ++ dma_addr_t txmapringdma; ++ dma_addr_t txbkpringdma; ++ dma_addr_t txbepringdma; ++ dma_addr_t txvipringdma; ++ dma_addr_t txvopringdma; ++ dma_addr_t txhpringdma; ++ u32 *txmapringtail; ++ u32 *txbkpringtail; ++ u32 *txbepringtail; ++ u32 *txvipringtail; ++ u32 *txvopringtail; ++ u32 *txhpringtail; ++ u32 *txmapringhead; ++ u32 *txbkpringhead; ++ u32 *txbepringhead; ++ u32 *txvipringhead; ++ u32 *txvopringhead; ++ u32 *txhpringhead; ++ struct buffer *txmapbufs; ++ struct buffer *txbkpbufs; ++ struct buffer *txbepbufs; ++ struct buffer *txvipbufs; ++ struct buffer *txvopbufs; ++ struct buffer *txhpbufs; ++ struct buffer *txmapbufstail; ++ struct buffer *txbkpbufstail; ++ struct buffer *txbepbufstail; ++ struct buffer *txvipbufstail; ++ struct buffer *txvopbufstail; ++ struct buffer *txhpbufstail; ++ ++ int txringcount; ++ int txbuffsize; ++ //struct tx_pendingbuf txnp_pending; ++ //struct tasklet_struct irq_tx_tasklet; ++ struct tasklet_struct irq_rx_tasklet; ++ u8 dma_poll_mask; ++ //short tx_suspend; ++ ++ /* adhoc/master mode stuff */ ++ u32 *txbeaconringtail; ++ dma_addr_t txbeaconringdma; ++ u32 *txbeaconring; ++ int txbeaconcount; ++ struct buffer *txbeaconbufs; ++ struct buffer *txbeaconbufstail; ++ //char *master_essid; ++ //u16 master_beaconinterval; ++ //u32 master_beaconsize; ++ //u16 beacon_interval; ++ ++ u8 retry_data; ++ u8 retry_rts; ++ u16 rts; ++ ++//add for RF power on power off by lizhaoming 080512 ++ u8 RegThreeWireMode; // See "Three wire mode" defined above, 2006.05.31, by rcnjko. ++ ++//by amy for led ++ LED_STRATEGY_8185 LedStrategy; ++//by amy for led ++ ++//by amy for power save ++ struct timer_list watch_dog_timer; ++ bool bInactivePs; ++ bool bSwRfProcessing; ++ RT_RF_POWER_STATE eInactivePowerState; ++ RT_RF_POWER_STATE eRFPowerState; ++ u32 RfOffReason; ++ bool RFChangeInProgress; ++ bool bInHctTest; ++ bool SetRFPowerStateInProgress; ++ u8 RFProgType; ++ bool bLeisurePs; ++ RT_PS_MODE dot11PowerSaveMode; ++ //u32 NumRxOkInPeriod; //YJ,del,080828 ++ //u32 NumTxOkInPeriod; //YJ,del,080828 ++ u8 TxPollingTimes; ++ ++ bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake untill receive data or timeout. ++ u8 WaitBufDataBcnCount; ++ u8 WaitBufDataTimeOut; ++ ++//by amy for power save ++//by amy for antenna ++ u8 EEPROMSwAntennaDiversity; ++ bool EEPROMDefaultAntenna1; ++ u8 RegSwAntennaDiversityMechanism; ++ bool bSwAntennaDiverity; ++ u8 RegDefaultAntenna; ++ bool bDefaultAntenna1; ++ u8 SignalStrength; ++ long Stats_SignalStrength; ++ long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average. ++ u8 SignalQuality; // in 0-100 index. ++ long Stats_SignalQuality; ++ long RecvSignalPower; // in dBm. ++ long Stats_RecvSignalPower; ++ u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25. ++ u32 AdRxOkCnt; ++ long AdRxSignalStrength; ++ u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx). ++ u8 AdTickCount; // Times of SwAntennaDiversityTimer happened. ++ u8 AdCheckPeriod; // # of period SwAntennaDiversityTimer to check Rx signal strength for SW Antenna Diversity. ++ u8 AdMinCheckPeriod; // Min value of AdCheckPeriod. ++ u8 AdMaxCheckPeriod; // Max value of AdCheckPeriod. ++ long AdRxSsThreshold; // Signal strength threshold to switch antenna. ++ long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold. ++ bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna. ++ long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna. ++ struct timer_list SwAntennaDiversityTimer; ++//by amy for antenna ++//{by amy 080312 ++// ++ // Crystal calibration. ++ // Added by Roger, 2007.12.11. ++ // ++ bool bXtalCalibration; // Crystal calibration. ++ u8 XtalCal_Xin; // Crystal calibration for Xin. 0~7.5pF ++ u8 XtalCal_Xout; // Crystal calibration for Xout. 0~7.5pF ++ // ++ // Tx power tracking with thermal meter indication. ++ // Added by Roger, 2007.12.11. ++ // ++ bool bTxPowerTrack; // Tx Power tracking. ++ u8 ThermalMeter; // Thermal meter reference indication. ++ // ++ // Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, 2007-02-14. ++ // ++ bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow. ++ bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko. ++ u32 FalseAlarmRegValue; ++ u8 RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG. ++ u8 DIG_NumberFallbackVote; ++ u8 DIG_NumberUpgradeVote; ++ // For HW antenna diversity, added by Roger, 2008.01.30. ++ u32 AdMainAntennaRxOkCnt; // Main antenna Rx OK count. ++ u32 AdAuxAntennaRxOkCnt; // Aux antenna Rx OK count. ++ bool bHWAdSwitched; // TRUE if we has switched default antenna by HW evaluation. ++ // RF High Power upper/lower threshold. ++ u8 RegHiPwrUpperTh; ++ u8 RegHiPwrLowerTh; ++ // RF RSSI High Power upper/lower Threshold. ++ u8 RegRSSIHiPwrUpperTh; ++ u8 RegRSSIHiPwrLowerTh; ++ // Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, by Bruce, 2007-04-12. ++ u8 CurCCKRSSI; ++ bool bCurCCKPkt; ++ // ++ // High Power Mechanism. Added by amy, 080312. ++ // ++ bool bToUpdateTxPwr; ++ long UndecoratedSmoothedSS; ++ long UndercorateSmoothedRxPower; ++ u8 RSSI; ++ char RxPower; ++ u8 InitialGain; ++ //For adjust Dig Threshhold during Legacy/Leisure Power Save Mode ++ u32 DozePeriodInPast2Sec; ++ // Don't access BB/RF under disable PLL situation. ++ u8 InitialGainBackUp; ++ u8 RegBModeGainStage; ++//by amy for rate adaptive ++ struct timer_list rateadapter_timer; ++ u32 RateAdaptivePeriod; ++ bool bEnhanceTxPwr; ++ bool bUpdateARFR; ++ int ForcedDataRate; // Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.) ++ u32 NumTxUnicast; //YJ,add,080828,for keep alive ++ u8 keepAliveLevel; //YJ,add,080828,for KeepAlive ++ unsigned long NumTxOkTotal; ++ u16 LastRetryCnt; ++ u16 LastRetryRate; ++ unsigned long LastTxokCnt; ++ unsigned long LastRxokCnt; ++ u16 CurrRetryCnt; ++ unsigned long LastTxOKBytes; ++ unsigned long NumTxOkBytesTotal; ++ u8 LastFailTxRate; ++ long LastFailTxRateSS; ++ u8 FailTxRateCount; ++ u32 LastTxThroughput; ++ //for up rate ++ unsigned short bTryuping; ++ u8 CurrTxRate; //the rate before up ++ u16 CurrRetryRate; ++ u16 TryupingCount; ++ u8 TryDownCountLowData; ++ u8 TryupingCountNoData; ++ ++ u8 CurrentOperaRate; ++//by amy for rate adaptive ++//by amy 080312} ++// short wq_hurryup; ++// struct workqueue_struct *workqueue; ++ struct work_struct reset_wq; ++ struct work_struct watch_dog_wq; ++ struct work_struct tx_irq_wq; ++ short ack_tx_to_ieee; ++ ++ u8 PowerProfile; ++#ifdef CONFIG_RTL8185B ++ u32 CSMethod; ++ u8 cck_txpwr_base; ++ u8 ofdm_txpwr_base; ++ u8 dma_poll_stop_mask; ++ ++ //u8 RegThreeWireMode; ++ u8 MWIEnable; ++ u16 ShortRetryLimit; ++ u16 LongRetryLimit; ++ u16 EarlyRxThreshold; ++ u32 TransmitConfig; ++ u32 ReceiveConfig; ++ u32 IntrMask; ++ ++ struct ChnlAccessSetting ChannelAccessSetting; ++#endif ++}r8180_priv; ++ ++#define MANAGE_PRIORITY 0 ++#define BK_PRIORITY 1 ++#define BE_PRIORITY 2 ++#define VI_PRIORITY 3 ++#define VO_PRIORITY 4 ++#define HI_PRIORITY 5 ++#define BEACON_PRIORITY 6 ++ ++#define LOW_PRIORITY VI_PRIORITY ++#define NORM_PRIORITY VO_PRIORITY ++//AC2Queue mapping ++#define AC2Q(_ac) (((_ac) == WME_AC_VO) ? VO_PRIORITY : \ ++ ((_ac) == WME_AC_VI) ? VI_PRIORITY : \ ++ ((_ac) == WME_AC_BK) ? BK_PRIORITY : \ ++ BE_PRIORITY) ++ ++short rtl8180_tx(struct net_device *dev,u8* skbuf, int len,int priority, ++ short morefrag,short fragdesc,int rate); ++ ++u8 read_nic_byte(struct net_device *dev, int x); ++u32 read_nic_dword(struct net_device *dev, int x); ++u16 read_nic_word(struct net_device *dev, int x) ; ++void write_nic_byte(struct net_device *dev, int x,u8 y); ++void write_nic_word(struct net_device *dev, int x,u16 y); ++void write_nic_dword(struct net_device *dev, int x,u32 y); ++void force_pci_posting(struct net_device *dev); ++ ++void rtl8180_rtx_disable(struct net_device *); ++void rtl8180_rx_enable(struct net_device *); ++void rtl8180_tx_enable(struct net_device *); ++void rtl8180_start_scanning(struct net_device *dev); ++void rtl8180_start_scanning_s(struct net_device *dev); ++void rtl8180_stop_scanning(struct net_device *dev); ++void rtl8180_disassociate(struct net_device *dev); ++//void fix_rx_fifo(struct net_device *dev); ++void rtl8180_set_anaparam(struct net_device *dev,u32 a); ++void rtl8185_set_anaparam2(struct net_device *dev,u32 a); ++void rtl8180_set_hw_wep(struct net_device *dev); ++void rtl8180_no_hw_wep(struct net_device *dev); ++void rtl8180_update_msr(struct net_device *dev); ++//void rtl8180_BSS_create(struct net_device *dev); ++void rtl8180_beacon_tx_disable(struct net_device *dev); ++void rtl8180_beacon_rx_disable(struct net_device *dev); ++void rtl8180_conttx_enable(struct net_device *dev); ++void rtl8180_conttx_disable(struct net_device *dev); ++int rtl8180_down(struct net_device *dev); ++int rtl8180_up(struct net_device *dev); ++void rtl8180_commit(struct net_device *dev); ++void rtl8180_set_chan(struct net_device *dev,short ch); ++void rtl8180_set_master_essid(struct net_device *dev,char *essid); ++void rtl8180_update_beacon_security(struct net_device *dev); ++void write_phy(struct net_device *dev, u8 adr, u8 data); ++void write_phy_cck(struct net_device *dev, u8 adr, u32 data); ++void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data); ++void rtl8185_tx_antenna(struct net_device *dev, u8 ant); ++void rtl8185_rf_pins_enable(struct net_device *dev); ++void IBSS_randomize_cell(struct net_device *dev); ++void IPSEnter(struct net_device *dev); ++void IPSLeave(struct net_device *dev); ++int get_curr_tx_free_desc(struct net_device *dev, int priority); ++void UpdateInitialGain(struct net_device *dev); ++bool SetAntennaConfig87SE(struct net_device *dev, u8 DefaultAnt, bool bAntDiversity); ++ ++//#ifdef CONFIG_RTL8185B ++void rtl8185b_adapter_start(struct net_device *dev); ++void rtl8185b_rx_enable(struct net_device *dev); ++void rtl8185b_tx_enable(struct net_device *dev); ++void rtl8180_reset(struct net_device *dev); ++void rtl8185b_irq_enable(struct net_device *dev); ++void fix_rx_fifo(struct net_device *dev); ++void fix_tx_fifo(struct net_device *dev); ++void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch); ++#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20) ++void rtl8180_rate_adapter(struct work_struct * work); ++#else ++void rtl8180_rate_adapter(struct net_device *dev); ++#endif ++//#endif ++bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource); ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_hw.h +@@ -0,0 +1,956 @@ ++/* ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official Realtek driver. ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ Parts of this driver are based on the Intel Pro Wireless ++ 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects ++ and the Ndiswrapper project Authors. ++*/ ++ ++/* Mariusz Matuszek added full registers definition with Realtek's name */ ++ ++/* this file contains register definitions for the rtl8180 MAC controller */ ++#ifndef R8180_HW ++#define R8180_HW ++ ++#define CONFIG_RTL8185B //support for rtl8185B, xiong-2006-11-15 ++#define CONFIG_RTL818X_S ++ ++#define BIT0 0x00000001 ++#define BIT1 0x00000002 ++#define BIT2 0x00000004 ++#define BIT3 0x00000008 ++#define BIT4 0x00000010 ++#define BIT5 0x00000020 ++#define BIT6 0x00000040 ++#define BIT7 0x00000080 ++#define BIT8 0x00000100 ++#define BIT9 0x00000200 ++#define BIT10 0x00000400 ++#define BIT11 0x00000800 ++#define BIT12 0x00001000 ++#define BIT13 0x00002000 ++#define BIT14 0x00004000 ++#define BIT15 0x00008000 ++#define BIT16 0x00010000 ++#define BIT17 0x00020000 ++#define BIT18 0x00040000 ++#define BIT19 0x00080000 ++#define BIT20 0x00100000 ++#define BIT21 0x00200000 ++#define BIT22 0x00400000 ++#define BIT23 0x00800000 ++#define BIT24 0x01000000 ++#define BIT25 0x02000000 ++#define BIT26 0x04000000 ++#define BIT27 0x08000000 ++#define BIT28 0x10000000 ++#define BIT29 0x20000000 ++#define BIT30 0x40000000 ++#define BIT31 0x80000000 ++ ++#define MAX_SLEEP_TIME (10000) ++#define MIN_SLEEP_TIME (50) ++ ++#define BB_ANTATTEN_CHAN14 0x0c ++#define BB_ANTENNA_B 0x40 ++ ++#define BB_HOST_BANG (1<<30) ++#define BB_HOST_BANG_EN (1<<2) ++#define BB_HOST_BANG_CLK (1<<1) ++#define BB_HOST_BANG_DATA 1 ++ ++#define ANAPARAM_TXDACOFF_SHIFT 27 ++#define ANAPARAM_PWR0_MASK ((1<<30)|(1<<29)|(1<<28)) ++#define ANAPARAM_PWR0_SHIFT 28 ++#define ANAPARAM_PWR1_MASK ((1<<26)|(1<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<21)|(1<<20)) ++#define ANAPARAM_PWR1_SHIFT 20 ++ ++#define MAC0 0 ++#define MAC1 1 ++#define MAC2 2 ++#define MAC3 3 ++#define MAC4 4 ++#define MAC5 5 ++#define CMD 0x37 ++#define CMD_RST_SHIFT 4 ++#define CMD_RESERVED_MASK ((1<<1) | (1<<5) | (1<<6) | (1<<7)) ++#define CMD_RX_ENABLE_SHIFT 3 ++#define CMD_TX_ENABLE_SHIFT 2 ++ ++#define EPROM_CMD 0x50 ++#define EPROM_CMD_RESERVED_MASK ((1<<5)|(1<<4)) ++#define EPROM_CMD_OPERATING_MODE_SHIFT 6 ++#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) ++#define EPROM_CMD_CONFIG 0x3 ++#define EPROM_CMD_NORMAL 0 ++#define EPROM_CMD_LOAD 1 ++#define EPROM_CMD_PROGRAM 2 ++#define EPROM_CS_SHIFT 3 ++#define EPROM_CK_SHIFT 2 ++#define EPROM_W_SHIFT 1 ++#define EPROM_R_SHIFT 0 ++#define CONFIG2_DMA_POLLING_MODE_SHIFT 3 ++#define INTA 0x3e ++#define INTA_TXOVERFLOW (1<<15) ++#define INTA_TIMEOUT (1<<14) ++#define INTA_BEACONTIMEOUT (1<<13) ++#define INTA_ATIM (1<<12) ++#define INTA_BEACONDESCERR (1<<11) ++#define INTA_BEACONDESCOK (1<<10) ++#define INTA_HIPRIORITYDESCERR (1<<9) ++#define INTA_HIPRIORITYDESCOK (1<<8) ++#define INTA_NORMPRIORITYDESCERR (1<<7) ++#define INTA_NORMPRIORITYDESCOK (1<<6) ++#define INTA_RXOVERFLOW (1<<5) ++#define INTA_RXDESCERR (1<<4) ++#define INTA_LOWPRIORITYDESCERR (1<<3) ++#define INTA_LOWPRIORITYDESCOK (1<<2) ++#define INTA_RXCRCERR (1<<1) ++#define INTA_RXOK (1) ++#define INTA_MASK 0x3c ++#define RXRING_ADDR 0xe4 // page 0 ++#define PGSELECT 0x5e ++#define PGSELECT_PG_SHIFT 0 ++#define RX_CONF 0x44 ++#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ ++(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) ++#define RX_CHECK_BSSID_SHIFT 23 ++#define ACCEPT_PWR_FRAME_SHIFT 22 ++#define ACCEPT_MNG_FRAME_SHIFT 20 ++#define ACCEPT_CTL_FRAME_SHIFT 19 ++#define ACCEPT_DATA_FRAME_SHIFT 18 ++#define ACCEPT_ICVERR_FRAME_SHIFT 12 ++#define ACCEPT_CRCERR_FRAME_SHIFT 5 ++#define ACCEPT_BCAST_FRAME_SHIFT 3 ++#define ACCEPT_MCAST_FRAME_SHIFT 2 ++#define ACCEPT_ALLMAC_FRAME_SHIFT 0 ++#define ACCEPT_NICMAC_FRAME_SHIFT 1 ++#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) ++#define RX_FIFO_THRESHOLD_SHIFT 13 ++#define RX_FIFO_THRESHOLD_128 3 ++#define RX_FIFO_THRESHOLD_256 4 ++#define RX_FIFO_THRESHOLD_512 5 ++#define RX_FIFO_THRESHOLD_1024 6 ++#define RX_FIFO_THRESHOLD_NONE 7 ++#define RX_AUTORESETPHY_SHIFT 28 ++#define EPROM_TYPE_SHIFT 6 ++#define TX_CONF 0x40 ++#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30 ++#define TX_LOOPBACK_SHIFT 17 ++#define TX_LOOPBACK_MAC 1 ++#define TX_LOOPBACK_BASEBAND 2 ++#define TX_LOOPBACK_NONE 0 ++#define TX_LOOPBACK_CONTINUE 3 ++#define TX_LOOPBACK_MASK ((1<<17)|(1<<18)) ++#define TX_DPRETRY_SHIFT 0 ++#define R8180_MAX_RETRY 255 ++#define TX_RTSRETRY_SHIFT 8 ++#define TX_NOICV_SHIFT 19 ++#define TX_NOCRC_SHIFT 16 ++#define TX_DMA_POLLING 0xd9 ++#define TX_DMA_POLLING_BEACON_SHIFT 7 ++#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6 ++#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5 ++#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4 ++#define TX_DMA_STOP_BEACON_SHIFT 3 ++#define TX_DMA_STOP_HIPRIORITY_SHIFT 2 ++#define TX_DMA_STOP_NORMPRIORITY_SHIFT 1 ++#define TX_DMA_STOP_LOWPRIORITY_SHIFT 0 ++#define TX_MANAGEPRIORITY_RING_ADDR 0x0C ++#define TX_BKPRIORITY_RING_ADDR 0x10 ++#define TX_BEPRIORITY_RING_ADDR 0x14 ++#define TX_VIPRIORITY_RING_ADDR 0x20 ++#define TX_VOPRIORITY_RING_ADDR 0x24 ++#define TX_HIGHPRIORITY_RING_ADDR 0x28 ++//AC_VI and Low priority share the sane queue ++#define TX_LOWPRIORITY_RING_ADDR TX_VIPRIORITY_RING_ADDR ++//AC_VO and Norm priority share the same queue ++#define TX_NORMPRIORITY_RING_ADDR TX_VOPRIORITY_RING_ADDR ++ ++#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) ++#define MAX_RX_DMA_2048 7 ++#define MAX_RX_DMA_1024 6 ++#define MAX_RX_DMA_SHIFT 10 ++#define INT_TIMEOUT 0x48 ++#define CONFIG3_CLKRUN_SHIFT 2 ++#define CONFIG3_ANAPARAM_W_SHIFT 6 ++#define ANAPARAM 0x54 ++#define BEACON_INTERVAL 0x70 ++#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \ ++(1<<6)|(1<<7)|(1<<8)|(1<<9)) ++#define ATIM_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)| \ ++(1<<8)|(1<<9)) ++#define ATIM 0x72 ++#define EPROM_CS_SHIFT 3 ++#define EPROM_CK_SHIFT 2 ++#define PHY_DELAY 0x78 ++#define PHY_CONFIG 0x80 ++#define PHY_ADR 0x7c ++#define PHY_READ 0x7e ++#define CARRIER_SENSE_COUNTER 0x79 //byte ++#define SECURITY 0x5f //1209 this is sth wrong ++#define SECURITY_WEP_TX_ENABLE_SHIFT 1 ++#define SECURITY_WEP_RX_ENABLE_SHIFT 0 ++#define SECURITY_ENCRYP_104 1 ++#define SECURITY_ENCRYP_SHIFT 4 ++#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5)) ++#define KEY0 0x90 //1209 this is sth wrong ++#define CONFIG2_ANTENNA_SHIFT 6 ++#define TX_BEACON_RING_ADDR 0x4c ++#define CONFIG0_WEP40_SHIFT 7 ++#define CONFIG0_WEP104_SHIFT 6 ++#define AGCRESET_SHIFT 5 ++ ++ ++ ++/* ++ * Operational registers offsets in PCI (I/O) space. ++ * RealTek names are used. ++ */ ++ ++#define IDR0 0x0000 ++#define IDR1 0x0001 ++#define IDR2 0x0002 ++#define IDR3 0x0003 ++#define IDR4 0x0004 ++#define IDR5 0x0005 ++ ++/* 0x0006 - 0x0007 - reserved */ ++ ++#define MAR0 0x0008 ++#define MAR1 0x0009 ++#define MAR2 0x000A ++#define MAR3 0x000B ++#define MAR4 0x000C ++#define MAR5 0x000D ++#define MAR6 0x000E ++#define MAR7 0x000F ++ ++/* 0x0010 - 0x0017 - reserved */ ++ ++#define TSFTR 0x0018 ++#define TSFTR_END 0x001F ++ ++#define TLPDA 0x0020 ++#define TLPDA_END 0x0023 ++#define TNPDA 0x0024 ++#define TNPDA_END 0x0027 ++#define THPDA 0x0028 ++#define THPDA_END 0x002B ++ ++#define BSSID 0x002E ++#define BSSID_END 0x0033 ++ ++#define CR 0x0037 ++ ++#ifdef CONFIG_RTL8185B ++#define RF_SW_CONFIG 0x8 // store data which is transmitted to RF for driver ++#define RF_SW_CFG_SI BIT1 ++#define PIFS 0x2C // PCF InterFrame Spacing Timer Setting. ++#define EIFS 0x2D // Extended InterFrame Space Timer, in unit of 4 us. ++ ++#define BRSR 0x34 // Basic rate set ++ ++#define IMR 0x006C ++#define ISR 0x003C ++#else ++#define BRSR 0x002C ++#define BRSR_END 0x002D ++ ++/* 0x0034 - 0x0034 - reserved */ ++#define EIFS 0x0035 ++ ++#define IMR 0x003C ++#define IMR_END 0x003D ++#define ISR 0x003E ++#define ISR_END 0x003F ++#endif ++ ++#define TCR 0x0040 ++#define TCR_END 0x0043 ++ ++#define RCR 0x0044 ++#define RCR_END 0x0047 ++ ++#define TimerInt 0x0048 ++#define TimerInt_END 0x004B ++ ++#define TBDA 0x004C ++#define TBDA_END 0x004F ++ ++#define CR9346 0x0050 ++ ++#define CONFIG0 0x0051 ++#define CONFIG1 0x0052 ++#define CONFIG2 0x0053 ++ ++#define ANA_PARM 0x0054 ++#define ANA_PARM_END 0x0x0057 ++ ++#define MSR 0x0058 ++ ++#define CONFIG3 0x0059 ++#define CONFIG4 0x005A ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ // SD3 szuyitasi: Mac0x57= CC -> B0 Mac0x60= D1 -> C6 ++ // Mac0x60 = 0x000004C6 power save parameters ++ #define ANAPARM_ASIC_ON 0xB0054D00 ++ #define ANAPARM2_ASIC_ON 0x000004C6 ++ ++ #define ANAPARM_ON ANAPARM_ASIC_ON ++ #define ANAPARM2_ON ANAPARM2_ASIC_ON ++#else ++ // SD3 CMLin: ++ #define ANAPARM_ASIC_ON 0x45090658 ++ #define ANAPARM2_ASIC_ON 0x727f3f52 ++ ++ #define ANAPARM_ON ANAPARM_ASIC_ON ++ #define ANAPARM2_ON ANAPARM2_ASIC_ON ++#endif ++#endif ++ ++#define TESTR 0x005B ++ ++/* 0x005C - 0x005D - reserved */ ++ ++#define PSR 0x005E ++ ++/* 0x0060 - 0x006F - reserved */ ++ ++#define BcnItv 0x0070 ++#define BcnItv_END 0x0071 ++ ++#define AtimWnd 0x0072 ++#define AtimWnd_END 0x0073 ++ ++#define BintrItv 0x0074 ++#define BintrItv_END 0x0075 ++ ++#define AtimtrItv 0x0076 ++#define AtimtrItv_END 0x0077 ++ ++#define PhyDelay 0x0078 ++ ++#define CRCount 0x0079 ++ ++/* 0x007A - 0x007B - reserved */ ++ ++#define PhyAddr 0x007C ++#define PhyDataW 0x007D ++#define PhyDataR 0x007E ++ ++#define PhyCFG 0x0080 ++#define PhyCFG_END 0x0083 ++ ++/* following are for rtl8185 */ ++#define RFPinsOutput 0x80 ++#define RFPinsEnable 0x82 ++#define RF_TIMING 0x8c ++#define RFPinsSelect 0x84 ++#define ANAPARAM2 0x60 ++#define RF_PARA 0x88 ++#define RFPinsInput 0x86 ++#define GP_ENABLE 0x90 ++#define GPIO 0x91 ++#define SW_CONTROL_GPIO 0x400 ++#define TX_ANTENNA 0x9f ++#define TX_GAIN_OFDM 0x9e ++#define TX_GAIN_CCK 0x9d ++#define WPA_CONFIG 0xb0 ++#define TX_AGC_CTL 0x9c ++#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0 ++#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1 ++#define TX_AGC_CTL_FEEDBACK_ANT 2 ++#define RESP_RATE 0x34 ++#define SIFS 0xb4 ++#define DIFS 0xb5 ++ ++#define SLOT 0xb6 ++#define CW_CONF 0xbc ++#define CW_CONF_PERPACKET_RETRY_SHIFT 1 ++#define CW_CONF_PERPACKET_CW_SHIFT 0 ++#define CW_VAL 0xbd ++#define MAX_RESP_RATE_SHIFT 4 ++#define MIN_RESP_RATE_SHIFT 0 ++#define RATE_FALLBACK 0xbe ++/* ++ * 0x0084 - 0x00D3 is selected to page 1 when PSEn bit (bit0, PSR) ++ * is set to 1 ++ */ ++ ++#define Wakeup0 0x0084 ++#define Wakeup0_END 0x008B ++ ++#define Wakeup1 0x008C ++#define Wakeup1_END 0x0093 ++ ++#define Wakeup2LD 0x0094 ++#define Wakeup2LD_END 0x009B ++#define Wakeup2HD 0x009C ++#define Wakeup2HD_END 0x00A3 ++ ++#define Wakeup3LD 0x00A4 ++#define Wakeup3LD_END 0x00AB ++#define Wakeup3HD 0x00AC ++#define Wakeup3HD_END 0x00B3 ++ ++#define Wakeup4LD 0x00B4 ++#define Wakeup4LD_END 0x00BB ++#define Wakeup4HD 0x00BC ++#define Wakeup4HD_END 0x00C3 ++ ++#define CRC0 0x00C4 ++#define CRC0_END 0x00C5 ++#define CRC1 0x00C6 ++#define CRC1_END 0x00C7 ++#define CRC2 0x00C8 ++#define CRC2_END 0x00C9 ++#define CRC3 0x00CA ++#define CRC3_END 0x00CB ++#define CRC4 0x00CC ++#define CRC4_END 0x00CD ++ ++/* 0x00CE - 0x00D3 - reserved */ ++ ++ ++ ++/* ++ * 0x0084 - 0x00D3 is selected to page 0 when PSEn bit (bit0, PSR) ++ * is set to 0 ++ */ ++ ++/* 0x0084 - 0x008F - reserved */ ++ ++#define DK0 0x0090 ++#define DK0_END 0x009F ++#define DK1 0x00A0 ++#define DK1_END 0x00AF ++#define DK2 0x00B0 ++#define DK2_END 0x00BF ++#define DK3 0x00C0 ++#define DK3_END 0x00CF ++ ++/* 0x00D0 - 0x00D3 - reserved */ ++ ++ ++ ++ ++ ++/* 0x00D4 - 0x00D7 - reserved */ ++ ++#define CONFIG5 0x00D8 ++ ++#define TPPoll 0x00D9 ++ ++/* 0x00DA - 0x00DB - reserved */ ++ ++#ifdef CONFIG_RTL818X_S ++#define PHYPR 0xDA //0xDA - 0x0B PHY Parameter Register. ++#endif ++ ++#define CWR 0x00DC ++#define CWR_END 0x00DD ++ ++#define RetryCTR 0x00DE ++ ++/* 0x00DF - 0x00E3 - reserved */ ++ ++#define RDSAR 0x00E4 ++#define RDSAR_END 0x00E7 ++ ++/* 0x00E8 - 0x00EF - reserved */ ++#ifdef CONFIG_RTL818X_S ++#define LED_CONTROL 0xED ++#endif ++ ++#define FER 0x00F0 ++#define FER_END 0x00F3 ++ ++#ifdef CONFIG_RTL8185B ++#define FEMR 0x1D4 // Function Event Mask register ++#else ++#define FEMR 0x00F4 ++#define FEMR_END 0x00F7 ++#endif ++ ++#define FPSR 0x00F8 ++#define FPSR_END 0x00FB ++ ++#define FFER 0x00FC ++#define FFER_END 0x00FF ++ ++ ++ ++/* ++ * Bitmasks for specific register functions. ++ * Names are derived from the register name and function name. ++ * ++ * _[] ++ * ++ * this leads to some awkward names... ++ */ ++ ++#define BRSR_BPLCP ((1<< 8)) ++#define BRSR_MBR ((1<< 1)|(1<< 0)) ++#define BRSR_MBR_8185 ((1<< 11)|(1<< 10)|(1<< 9)|(1<< 8)|(1<< 7)|(1<< 6)|(1<< 5)|(1<< 4)|(1<< 3)|(1<< 2)|(1<< 1)|(1<< 0)) ++#define BRSR_MBR0 ((1<< 0)) ++#define BRSR_MBR1 ((1<< 1)) ++ ++#define CR_RST ((1<< 4)) ++#define CR_RE ((1<< 3)) ++#define CR_TE ((1<< 2)) ++#define CR_MulRW ((1<< 0)) ++ ++#ifdef CONFIG_RTL8185B ++#define IMR_Dot11hInt ((1<< 25)) // 802.11h Measurement Interrupt ++#define IMR_BcnDmaInt ((1<< 24)) // Beacon DMA Interrupt // What differenct between BcnDmaInt and BcnInt??? ++#define IMR_WakeInt ((1<< 23)) // Wake Up Interrupt ++#define IMR_TXFOVW ((1<< 22)) // Tx FIFO Overflow Interrupt ++#define IMR_TimeOut1 ((1<< 21)) // Time Out Interrupt 1 ++#define IMR_BcnInt ((1<< 20)) // Beacon Time out Interrupt ++#define IMR_ATIMInt ((1<< 19)) // ATIM Time Out Interrupt ++#define IMR_TBDER ((1<< 18)) // Tx Beacon Descriptor Error Interrupt ++#define IMR_TBDOK ((1<< 17)) // Tx Beacon Descriptor OK Interrupt ++#define IMR_THPDER ((1<< 16)) // Tx High Priority Descriptor Error Interrupt ++#define IMR_THPDOK ((1<< 15)) // Tx High Priority Descriptor OK Interrupt ++#define IMR_TVODER ((1<< 14)) // Tx AC_VO Descriptor Error Interrupt ++#define IMR_TVODOK ((1<< 13)) // Tx AC_VO Descriptor OK Interrupt ++#define IMR_FOVW ((1<< 12)) // Rx FIFO Overflow Interrupt ++#define IMR_RDU ((1<< 11)) // Rx Descriptor Unavailable Interrupt ++#define IMR_TVIDER ((1<< 10)) // Tx AC_VI Descriptor Error Interrupt ++#define IMR_TVIDOK ((1<< 9)) // Tx AC_VI Descriptor OK Interrupt ++#define IMR_RER ((1<< 8)) // Rx Error Interrupt ++#define IMR_ROK ((1<< 7)) // Receive OK Interrupt ++#define IMR_TBEDER ((1<< 6)) // Tx AC_BE Descriptor Error Interrupt ++#define IMR_TBEDOK ((1<< 5)) // Tx AC_BE Descriptor OK Interrupt ++#define IMR_TBKDER ((1<< 4)) // Tx AC_BK Descriptor Error Interrupt ++#define IMR_TBKDOK ((1<< 3)) // Tx AC_BK Descriptor OK Interrupt ++#define IMR_RQoSOK ((1<< 2)) // Rx QoS OK Interrupt ++#define IMR_TimeOut2 ((1<< 1)) // Time Out Interrupt 2 ++#define IMR_TimeOut3 ((1<< 0)) // Time Out Interrupt 3 ++#define IMR_TMGDOK ((1<<30)) ++#define ISR_Dot11hInt ((1<< 25)) // 802.11h Measurement Interrupt ++#define ISR_BcnDmaInt ((1<< 24)) // Beacon DMA Interrupt // What differenct between BcnDmaInt and BcnInt??? ++#define ISR_WakeInt ((1<< 23)) // Wake Up Interrupt ++#define ISR_TXFOVW ((1<< 22)) // Tx FIFO Overflow Interrupt ++#define ISR_TimeOut1 ((1<< 21)) // Time Out Interrupt 1 ++#define ISR_BcnInt ((1<< 20)) // Beacon Time out Interrupt ++#define ISR_ATIMInt ((1<< 19)) // ATIM Time Out Interrupt ++#define ISR_TBDER ((1<< 18)) // Tx Beacon Descriptor Error Interrupt ++#define ISR_TBDOK ((1<< 17)) // Tx Beacon Descriptor OK Interrupt ++#define ISR_THPDER ((1<< 16)) // Tx High Priority Descriptor Error Interrupt ++#define ISR_THPDOK ((1<< 15)) // Tx High Priority Descriptor OK Interrupt ++#define ISR_TVODER ((1<< 14)) // Tx AC_VO Descriptor Error Interrupt ++#define ISR_TVODOK ((1<< 13)) // Tx AC_VO Descriptor OK Interrupt ++#define ISR_FOVW ((1<< 12)) // Rx FIFO Overflow Interrupt ++#define ISR_RDU ((1<< 11)) // Rx Descriptor Unavailable Interrupt ++#define ISR_TVIDER ((1<< 10)) // Tx AC_VI Descriptor Error Interrupt ++#define ISR_TVIDOK ((1<< 9)) // Tx AC_VI Descriptor OK Interrupt ++#define ISR_RER ((1<< 8)) // Rx Error Interrupt ++#define ISR_ROK ((1<< 7)) // Receive OK Interrupt ++#define ISR_TBEDER ((1<< 6)) // Tx AC_BE Descriptor Error Interrupt ++#define ISR_TBEDOK ((1<< 5)) // Tx AC_BE Descriptor OK Interrupt ++#define ISR_TBKDER ((1<< 4)) // Tx AC_BK Descriptor Error Interrupt ++#define ISR_TBKDOK ((1<< 3)) // Tx AC_BK Descriptor OK Interrupt ++#define ISR_RQoSOK ((1<< 2)) // Rx QoS OK Interrupt ++#define ISR_TimeOut2 ((1<< 1)) // Time Out Interrupt 2 ++#define ISR_TimeOut3 ((1<< 0)) // Time Out Interrupt 3 ++ ++//these definition is used for Tx/Rx test temporarily ++#define ISR_TLPDER ISR_TVIDER ++#define ISR_TLPDOK ISR_TVIDOK ++#define ISR_TNPDER ISR_TVODER ++#define ISR_TNPDOK ISR_TVODOK ++#define ISR_TimeOut ISR_TimeOut1 ++#define ISR_RXFOVW ISR_FOVW ++ ++#else ++#define IMR_TXFOVW ((1<<15)) ++#define IMR_TimeOut ((1<<14)) ++#define IMR_BcnInt ((1<<13)) ++#define IMR_ATIMInt ((1<<12)) ++#define IMR_TBDER ((1<<11)) ++#define IMR_TBDOK ((1<<10)) ++#define IMR_THPDER ((1<< 9)) ++#define IMR_THPDOK ((1<< 8)) ++#define IMR_TNPDER ((1<< 7)) ++#define IMR_TNPDOK ((1<< 6)) ++#define IMR_RXFOVW ((1<< 5)) ++#define IMR_RDU ((1<< 4)) ++#define IMR_TLPDER ((1<< 3)) ++#define IMR_TLPDOK ((1<< 2)) ++#define IMR_RER ((1<< 1)) ++#define IMR_ROK ((1<< 0)) ++ ++#define ISR_TXFOVW ((1<<15)) ++#define ISR_TimeOut ((1<<14)) ++#define ISR_BcnInt ((1<<13)) ++#define ISR_ATIMInt ((1<<12)) ++#define ISR_TBDER ((1<<11)) ++#define ISR_TBDOK ((1<<10)) ++#define ISR_THPDER ((1<< 9)) ++#define ISR_THPDOK ((1<< 8)) ++#define ISR_TNPDER ((1<< 7)) ++#define ISR_TNPDOK ((1<< 6)) ++#define ISR_RXFOVW ((1<< 5)) ++#define ISR_RDU ((1<< 4)) ++#define ISR_TLPDER ((1<< 3)) ++#define ISR_TLPDOK ((1<< 2)) ++#define ISR_RER ((1<< 1)) ++#define ISR_ROK ((1<< 0)) ++#endif ++ ++#define HW_VERID_R8180_F 3 ++#define HW_VERID_R8180_ABCD 2 ++#define HW_VERID_R8185_ABC 4 ++#define HW_VERID_R8185_D 5 ++#ifdef CONFIG_RTL8185B ++#define HW_VERID_R8185B_B 6 ++#endif ++ ++#define TCR_CWMIN ((1<<31)) ++#define TCR_SWSEQ ((1<<30)) ++#define TCR_HWVERID_MASK ((1<<27)|(1<<26)|(1<<25)) ++#define TCR_HWVERID_SHIFT 25 ++#define TCR_SAT ((1<<24)) ++#define TCR_PLCP_LEN TCR_SAT // rtl8180 ++#define TCR_MXDMA_MASK ((1<<23)|(1<<22)|(1<<21)) ++#define TCR_MXDMA_1024 6 ++#define TCR_MXDMA_2048 7 ++#define TCR_MXDMA_SHIFT 21 ++#define TCR_DISCW ((1<<20)) ++#define TCR_ICV ((1<<19)) ++#define TCR_LBK ((1<<18)|(1<<17)) ++#define TCR_LBK1 ((1<<18)) ++#define TCR_LBK0 ((1<<17)) ++#define TCR_CRC ((1<<16)) ++#define TCR_DPRETRY_MASK ((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)) ++#define TCR_RTSRETRY_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)) ++#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 //rtl8185 ++ ++#define RCR_ONLYERLPKT ((1<<31)) ++#define RCR_CS_SHIFT 29 ++#define RCR_CS_MASK ((1<<30) | (1<<29)) ++#define RCR_ENMARP ((1<<28)) ++#define RCR_CBSSID ((1<<23)) ++#define RCR_APWRMGT ((1<<22)) ++#define RCR_ADD3 ((1<<21)) ++#define RCR_AMF ((1<<20)) ++#define RCR_ACF ((1<<19)) ++#define RCR_ADF ((1<<18)) ++#define RCR_RXFTH ((1<<15)|(1<<14)|(1<<13)) ++#define RCR_RXFTH2 ((1<<15)) ++#define RCR_RXFTH1 ((1<<14)) ++#define RCR_RXFTH0 ((1<<13)) ++#define RCR_AICV ((1<<12)) ++#define RCR_MXDMA ((1<<10)|(1<< 9)|(1<< 8)) ++#define RCR_MXDMA2 ((1<<10)) ++#define RCR_MXDMA1 ((1<< 9)) ++#define RCR_MXDMA0 ((1<< 8)) ++#define RCR_9356SEL ((1<< 6)) ++#define RCR_ACRC32 ((1<< 5)) ++#define RCR_AB ((1<< 3)) ++#define RCR_AM ((1<< 2)) ++#define RCR_APM ((1<< 1)) ++#define RCR_AAP ((1<< 0)) ++ ++#define CR9346_EEM ((1<<7)|(1<<6)) ++#define CR9346_EEM1 ((1<<7)) ++#define CR9346_EEM0 ((1<<6)) ++#define CR9346_EECS ((1<<3)) ++#define CR9346_EESK ((1<<2)) ++#define CR9346_EED1 ((1<<1)) ++#define CR9346_EED0 ((1<<0)) ++ ++#define CONFIG0_WEP104 ((1<<6)) ++#define CONFIG0_LEDGPO_En ((1<<4)) ++#define CONFIG0_Aux_Status ((1<<3)) ++#define CONFIG0_GL ((1<<1)|(1<<0)) ++#define CONFIG0_GL1 ((1<<1)) ++#define CONFIG0_GL0 ((1<<0)) ++ ++#define CONFIG1_LEDS ((1<<7)|(1<<6)) ++#define CONFIG1_LEDS1 ((1<<7)) ++#define CONFIG1_LEDS0 ((1<<6)) ++#define CONFIG1_LWACT ((1<<4)) ++#define CONFIG1_MEMMAP ((1<<3)) ++#define CONFIG1_IOMAP ((1<<2)) ++#define CONFIG1_VPD ((1<<1)) ++#define CONFIG1_PMEn ((1<<0)) ++ ++#define CONFIG2_LCK ((1<<7)) ++#define CONFIG2_ANT ((1<<6)) ++#define CONFIG2_DPS ((1<<3)) ++#define CONFIG2_PAPE_sign ((1<<2)) ++#define CONFIG2_PAPE_time ((1<<1)|(1<<0)) ++#define CONFIG2_PAPE_time1 ((1<<1)) ++#define CONFIG2_PAPE_time0 ((1<<0)) ++ ++#define CONFIG3_GNTSel ((1<<7)) ++#define CONFIG3_PARM_En ((1<<6)) ++#define CONFIG3_Magic ((1<<5)) ++#define CONFIG3_CardB_En ((1<<3)) ++#define CONFIG3_CLKRUN_En ((1<<2)) ++#define CONFIG3_FuncRegEn ((1<<1)) ++#define CONFIG3_FBtbEn ((1<<0)) ++ ++#define CONFIG4_VCOPDN ((1<<7)) ++#define CONFIG4_PWROFF ((1<<6)) ++#define CONFIG4_PWRMGT ((1<<5)) ++#define CONFIG4_LWPME ((1<<4)) ++#define CONFIG4_LWPTN ((1<<2)) ++#define CONFIG4_RFTYPE ((1<<1)|(1<<0)) ++#define CONFIG4_RFTYPE1 ((1<<1)) ++#define CONFIG4_RFTYPE0 ((1<<0)) ++ ++#define CONFIG5_TX_FIFO_OK ((1<<7)) ++#define CONFIG5_RX_FIFO_OK ((1<<6)) ++#define CONFIG5_CALON ((1<<5)) ++#define CONFIG5_EACPI ((1<<2)) ++#define CONFIG5_LANWake ((1<<1)) ++#define CONFIG5_PME_STS ((1<<0)) ++ ++#define MSR_LINK_MASK ((1<<2)|(1<<3)) ++#define MSR_LINK_MANAGED 2 ++#define MSR_LINK_NONE 0 ++#define MSR_LINK_SHIFT 2 ++#define MSR_LINK_ADHOC 1 ++#define MSR_LINK_MASTER 3 ++ ++#define PSR_GPO ((1<<7)) ++#define PSR_GPI ((1<<6)) ++#define PSR_LEDGPO1 ((1<<5)) ++#define PSR_LEDGPO0 ((1<<4)) ++#define PSR_UWF ((1<<1)) ++#define PSR_PSEn ((1<<0)) ++ ++#define SCR_KM ((1<<5)|(1<<4)) ++#define SCR_KM1 ((1<<5)) ++#define SCR_KM0 ((1<<4)) ++#define SCR_TXSECON ((1<<1)) ++#define SCR_RXSECON ((1<<0)) ++ ++#define BcnItv_BcnItv (0x01FF) ++ ++#define AtimWnd_AtimWnd (0x01FF) ++ ++#define BintrItv_BintrItv (0x01FF) ++ ++#define AtimtrItv_AtimtrItv (0x01FF) ++ ++#define PhyDelay_PhyDelay ((1<<2)|(1<<1)|(1<<0)) ++ ++#define TPPoll_BQ ((1<<7)) ++#define TPPoll_HPQ ((1<<6)) ++#define TPPoll_NPQ ((1<<5)) ++#define TPPoll_LPQ ((1<<4)) ++#define TPPoll_SBQ ((1<<3)) ++#define TPPoll_SHPQ ((1<<2)) ++#define TPPoll_SNPQ ((1<<1)) ++#define TPPoll_SLPQ ((1<<0)) ++ ++#define CWR_CW (0x01FF) ++ ++#define FER_INTR ((1<<15)) ++#define FER_GWAKE ((1<< 4)) ++ ++#define FEMR_INTR ((1<<15)) ++#define FEMR_WKUP ((1<<14)) ++#define FEMR_GWAKE ((1<< 4)) ++ ++#define FPSR_INTR ((1<<15)) ++#define FPSR_GWAKE ((1<< 4)) ++ ++#define FFER_INTR ((1<<15)) ++#define FFER_GWAKE ((1<< 4)) ++ ++#ifdef CONFIG_RTL8185B ++// Three wire mode. ++#define SW_THREE_WIRE 0 ++#define HW_THREE_WIRE 2 ++//RTL8187S by amy ++#define HW_THREE_WIRE_PI 5 ++#define HW_THREE_WIRE_SI 6 ++//by amy ++#define TCR_LRL_OFFSET 0 ++#define TCR_SRL_OFFSET 8 ++#define TCR_MXDMA_OFFSET 21 ++#define TCR_DISReqQsize_OFFSET 28 ++#define TCR_DurProcMode_OFFSET 30 ++ ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ ++#define TMGDS 0x0C // Tx Management Descriptor Address ++#define TBKDS 0x10 // Tx AC_BK Descriptor Address ++#define TBEDS 0x14 // Tx AC_BE Descriptor Address ++#define TLPDS 0x20 // Tx AC_VI Descriptor Address ++#define TNPDS 0x24 // Tx AC_VO Descriptor Address ++#define THPDS 0x28 // Tx Hign Priority Descriptor Address ++ ++#define TBDS 0x4c // Beacon descriptor queue start address ++ ++#define RDSA 0xE4 // Receive descriptor queue start address ++ ++#define AckTimeOutReg 0x79 // ACK timeout register, in unit of 4 us. ++ ++#define RFTiming 0x8C ++ ++#define TPPollStop 0x93 ++ ++#define TXAGC_CTL 0x9C // TX_AGC_CONTROL (0x9C seems be removed at 8185B, see p37). ++#define CCK_TXAGC 0x9D ++#define OFDM_TXAGC 0x9E ++#define ANTSEL 0x9F ++ ++#define ACM_CONTROL 0x00BF // ACM Control Registe ++ ++#define RTL8185B_VER_REG 0xE1 ++ ++#define IntMig 0xE2 // Interrupt Migration (0xE2 ~ 0xE3) ++ ++#define TID_AC_MAP 0xE8 // TID to AC Mapping Register ++ ++#define ANAPARAM3 0xEE // How to use it? ++ ++#define AC_VO_PARAM 0xF0 // AC_VO Parameters Record ++#define AC_VI_PARAM 0xF4 // AC_VI Parameters Record ++#define AC_BE_PARAM 0xF8 // AC_BE Parameters Record ++#define AC_BK_PARAM 0xFC // AC_BK Parameters Record ++ ++#ifdef CONFIG_RTL818X_S ++#define BcnTimingAdjust 0x16A // Beacon Timing Adjust Register. ++#define GPIOCtrl 0x16B // GPIO Control Register. ++#define PSByGC 0x180 // 0x180 - 0x183 Power Saving by Gated Clock. ++#endif ++#define ARFR 0x1E0 // Auto Rate Fallback Register (0x1e0 ~ 0x1e2) ++ ++#define RFSW_CTRL 0x272 // 0x272-0x273. ++#define SW_3W_DB0 0x274 // Software 3-wire data buffer bit 31~0. ++#define SW_3W_DB1 0x278 // Software 3-wire data buffer bit 63~32. ++#define SW_3W_CMD0 0x27C // Software 3-wire Control/Status Register. ++#define SW_3W_CMD1 0x27D // Software 3-wire Control/Status Register. ++ ++#ifdef CONFIG_RTL818X_S ++#define PI_DATA_READ 0X360 // 0x360 - 0x361 Parallel Interface Data Register. ++#define SI_DATA_READ 0x362 // 0x362 - 0x363 Serial Interface Data Register. ++#endif ++ ++//---------------------------------------------------------------------------- ++// 8185B TPPoll bits (offset 0xd9, 1 byte) ++//---------------------------------------------------------------------------- ++#define TPPOLL_BQ (0x01 << 7) ++#define TPPOLL_HPQ (0x01 << 6) ++#define TPPOLL_AC_VOQ (0x01 << 5) ++#define TPPOLL_AC_VIQ (0x01 << 4) ++#define TPPOLL_AC_BEQ (0x01 << 3) ++#define TPPOLL_AC_BKQ (0x01 << 2) ++#define TPPOLL_AC_MGQ (0x01 << 1) ++ ++//---------------------------------------------------------------------------- ++// 8185B TPPollStop bits (offset 0x93, 1 byte) ++//---------------------------------------------------------------------------- ++#define TPPOLLSTOP_BQ (0x01 << 7) ++#define TPPOLLSTOP_HPQ (0x01 << 6) ++#define TPPOLLSTOP_AC_VOQ (0x01 << 5) ++#define TPPOLLSTOP_AC_VIQ (0x01 << 4) ++#define TPPOLLSTOP_AC_BEQ (0x01 << 3) ++#define TPPOLLSTOP_AC_BKQ (0x01 << 2) ++#define TPPOLLSTOP_AC_MGQ (0x01 << 1) ++ ++ ++#define MSR_LINK_ENEDCA (1<<4) ++ ++//---------------------------------------------------------------------------- ++// 8187B AC_XX_PARAM bits ++//---------------------------------------------------------------------------- ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ ++//---------------------------------------------------------------------------- ++// 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte) ++//---------------------------------------------------------------------------- ++#define VOQ_ACM_EN (0x01 << 7) //BIT7 ++#define VIQ_ACM_EN (0x01 << 6) //BIT6 ++#define BEQ_ACM_EN (0x01 << 5) //BIT5 ++#define ACM_HW_EN (0x01 << 4) //BIT4 ++#define TXOPSEL (0x01 << 3) //BIT3 ++#define VOQ_ACM_CTL (0x01 << 2) //BIT2 // Set to 1 when AC_VO used time reaches or exceeds the admitted time ++#define VIQ_ACM_CTL (0x01 << 1) //BIT1 // Set to 1 when AC_VI used time reaches or exceeds the admitted time ++#define BEQ_ACM_CTL (0x01 << 0) //BIT0 // Set to 1 when AC_BE used time reaches or exceeds the admitted time ++ ++ ++//---------------------------------------------------------------------------- ++// 8185B SW_3W_CMD bits (Offset 0x27C-0x27D, 16bit) ++//---------------------------------------------------------------------------- ++#define SW_3W_CMD0_HOLD ((1<< 7)) ++#define SW_3W_CMD1_RE ((1<< 0)) // BIT8 ++#define SW_3W_CMD1_WE ((1<< 1)) // BIT9 ++#define SW_3W_CMD1_DONE ((1<< 2)) // BIT10 ++ ++#define BB_HOST_BANG_RW (1<<3) ++ ++//---------------------------------------------------------------------------- ++// 8185B RATE_FALLBACK_CTL bits (Offset 0xBE, 8bit) ++//---------------------------------------------------------------------------- ++#define RATE_FALLBACK_CTL_ENABLE ((1<< 7)) ++#define RATE_FALLBACK_CTL_ENABLE_RTSCTS ((1<< 6)) ++// Auto rate fallback per 2^n retry. ++#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00 ++#define RATE_FALLBACK_CTL_AUTO_STEP1 0x01 ++#define RATE_FALLBACK_CTL_AUTO_STEP2 0x02 ++#define RATE_FALLBACK_CTL_AUTO_STEP3 0x03 ++ ++ ++#define RTL8225z2_ANAPARAM_OFF 0x55480658 ++#define RTL8225z2_ANAPARAM2_OFF 0x72003f70 ++//by amy for power save ++#define RF_CHANGE_BY_SW BIT31 ++#define RF_CHANGE_BY_HW BIT30 ++#define RF_CHANGE_BY_PS BIT29 ++#define RF_CHANGE_BY_IPS BIT28 ++//by amy for power save ++//by amy for antenna ++#define EEPROM_SW_REVD_OFFSET 0x3f ++// BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable. ++#define EEPROM_SW_AD_MASK 0x0300 ++#define EEPROM_SW_AD_ENABLE 0x0100 ++ ++// BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. ++#define EEPROM_DEF_ANT_MASK 0x0C00 ++#define EEPROM_DEF_ANT_1 0x0400 ++//by amy for antenna ++//{by amy 080312 ++//0x7C, 0x7D Crystal calibration and Tx Power tracking mechanism. Added by Roger. 2007.12.10. ++#define EEPROM_RSV 0x7C ++#define EEPROM_XTAL_CAL_MASK 0x00FF // 0x7C[7:0], Crystal calibration mask. ++#define EEPROM_XTAL_CAL_XOUT_MASK 0x0F // 0x7C[3:0], Crystal calibration for Xout. ++#define EEPROM_XTAL_CAL_XIN_MASK 0xF0 // 0x7C[7:4], Crystal calibration for Xin. ++#define EEPROM_THERMAL_METER_MASK 0x0F00 // 0x7D[3:0], Thermal meter reference level. ++#define EEPROM_XTAL_CAL_ENABLE 0x1000 // 0x7D[4], Crystal calibration enabled/disabled BIT. ++#define EEPROM_THERMAL_METER_ENABLE 0x2000 // 0x7D[5], Thermal meter enabled/disabled BIT. ++#define EEPROM_CID_RSVD1 0x3F ++#define EN_LPF_CAL 0x238 // Enable LPF Calibration. ++#define PWR_METER_EN BIT1 ++// where are false alarm counters in 8185B? ++#define CCK_FALSE_ALARM 0xD0 ++#define OFDM_FALSE_ALARM 0xD2 ++//by amy 080312} ++ ++//YJ,add for Country IE, 080630 ++#define EEPROM_COUNTRY_CODE 0x2E ++//YJ,add,080630,end ++#endif ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_max2820.c +@@ -0,0 +1,240 @@ ++/* ++ This files contains MAXIM MAX2820 radio frontend programming routines. ++ ++ This is part of rtl8180 OpenSource driver ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ NetBSD rtl8180 driver from Dave Young has been really useful to ++ understand how to program the MAXIM radio. Thanks a lot!!! ++ ++ 'The Deuce' tested this and fixed some bugs. ++ ++ Code from rtl8181 project has been useful to me to understand some things. ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++ ++#include "r8180.h" ++#include "r8180_hw.h" ++#include "r8180_max2820.h" ++ ++ ++//#define DEBUG_MAXIM ++ ++u32 maxim_chan[] = { ++ 0, //dummy channel 0 ++ 12, //1 ++ 17, //2 ++ 22, //3 ++ 27, //4 ++ 32, //5 ++ 37, //6 ++ 42, //7 ++ 47, //8 ++ 52, //9 ++ 57, //10 ++ 62, //11 ++ 67, //12 ++ 72, //13 ++ 84, //14 ++}; ++ ++#if 0 ++/* maxim expects 4 bit address MSF, then 12 bit data MSF*/ ++void write_maxim(struct net_device *dev,u8 adr, u32 data) ++{ ++ ++ int shift; ++ short bit; ++ u16 word; ++ ++ adr = adr &0xf; ++ word = (u16)data & 0xfff; ++ word |= (adr<<12); ++ /*write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | BB_HOST_BANG_EN); ++ read_nic_dword(dev,PHY_CONFIG); ++ mdelay(1); ++ ++ write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | BB_HOST_BANG_EN | BB_HOST_BANG_CLK); ++ read_nic_dword(dev,PHY_CONFIG); ++ mdelay(1); ++ */ ++ ++ /* MAX2820 will sample data on rising edge of clock */ ++ for(shift = 15;shift >=0; shift--){ ++ bit = word>>shift & 1; ++ ++ write_nic_dword(dev,PHY_CONFIG,BB_HOST_BANG | (bit<> 4) & 0xff; ++#ifdef DEBUG_MAXIM ++ DMESG("write_maxim: %08x", temp); ++#endif ++ write_nic_dword(dev, PHY_CONFIG, temp); ++ force_pci_posting(dev); ++ mdelay(1); ++} ++ ++ ++void maxim_write_phy_antenna(struct net_device *dev,short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 ant; ++ ++ ant = MAXIM_ANTENNA; ++ if(priv->antb) /*default antenna is antenna B */ ++ ant |= BB_ANTENNA_B; ++ if(ch == 14) ++ ant |= BB_ANTATTEN_CHAN14; ++ write_phy(dev,0x10,ant); ++ //DMESG("BB antenna %x ",ant); ++} ++ ++ ++void maxim_rf_set_chan(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 txpw = 0xff & priv->chtxpwr[ch]; ++ u32 chan = maxim_chan[ch]; ++ ++ /*While philips SA2400 drive the PA bias ++ *seems that for MAXIM we delegate this ++ *to the BB ++ */ ++ ++ //write_maxim(dev,5,txpw); ++ write_phy(dev,3,txpw); ++ ++ maxim_write_phy_antenna(dev,ch); ++ write_maxim(dev,3,chan); ++} ++ ++ ++void maxim_rf_close(struct net_device *dev) ++{ ++ write_phy(dev, 3, 0x8); ++ write_maxim(dev, 1, 0); ++} ++ ++ ++void maxim_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 anaparam; ++ ++ write_nic_byte(dev,PHY_DELAY,0x6); //this is general ++ write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general ++ ++ /*these are maxim specific*/ ++ anaparam = read_nic_dword(dev,ANAPARAM); ++ anaparam = anaparam &~ (ANAPARAM_TXDACOFF_SHIFT); ++ anaparam = anaparam &~ANAPARAM_PWR1_MASK; ++ anaparam = anaparam &~ANAPARAM_PWR0_MASK; ++ anaparam |= (MAXIM_ANAPARAM_PWR1_ON<chan); ++ ++ write_maxim(dev,4, 0x313); /* rx register*/ ++ ++ /* PA is driven directly by the BB, we keep the MAXIM bias ++ * at the highest value in the boubt tha pleacing it to lower ++ * values may introduce some further attenuation somewhere.. ++ */ ++ ++ write_maxim(dev,5, 0xf); ++ ++ ++ /*baseband configuration*/ ++ write_phy(dev,0,0x88); //sys1 ++ write_phy(dev,3,0x8); //txagc ++ write_phy(dev,4,0xf8); // lnadet ++ write_phy(dev,5,0x90); // ifagcinit ++ write_phy(dev,6,0x1a); // ifagclimit ++ write_phy(dev,7,0x64); // ifagcdet ++ ++ /*Should be done something more here??*/ ++ ++ maxim_write_phy_antenna(dev,priv->chan); ++ ++ write_phy(dev,0x11,0x88); //trl ++ if(priv->diversity) ++ write_phy(dev,0x12,0xc7); ++ else ++ write_phy(dev,0x12,0x47); ++ ++ write_phy(dev,0x13,0x9b); ++ ++ write_phy(dev,0x19,0x0); //CHESTLIM ++ write_phy(dev,0x1a,0x9f); //CHSQLIM ++ ++ maxim_rf_set_chan(dev,priv->chan); ++} +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_max2820.h +@@ -0,0 +1,21 @@ ++/* ++ This is part of rtl8180 OpenSource driver ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++#define MAXIM_ANTENNA 0xb3 ++#define MAXIM_ANAPARAM_PWR1_ON 0x8 ++#define MAXIM_ANAPARAM_PWR0_ON 0x0 ++ ++ ++void maxim_rf_init(struct net_device *dev); ++void maxim_rf_set_chan(struct net_device *dev,short ch); ++ ++void maxim_rf_close(struct net_device *dev); +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_pm.c +@@ -0,0 +1,90 @@ ++/* ++ Power management interface routines. ++ Written by Mariusz Matuszek. ++ This code is currently just a placeholder for later work and ++ does not do anything useful. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++*/ ++ ++#ifdef CONFIG_RTL8180_PM ++ ++ ++#include "r8180_hw.h" ++#include "r8180_pm.h" ++#include "r8180.h" ++ ++int rtl8180_save_state (struct pci_dev *dev, u32 state) ++{ ++ printk(KERN_NOTICE "r8180 save state call (state %u).\n", state); ++ return(-EAGAIN); ++} ++ ++int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if (!netif_running(dev)) ++ goto out_pci_suspend; ++ ++ dev->stop(dev); ++ ++ netif_device_detach(dev); ++ ++out_pci_suspend: ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev,pci_choose_state(pdev,state)); ++ return 0; ++} ++ ++int rtl8180_resume (struct pci_dev *pdev) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ int err; ++ u32 val; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ ++ err = pci_enable_device(pdev); ++ if(err) { ++ printk(KERN_ERR "%s: pci_enable_device failed on resume\n", ++ dev->name); ++ ++ return err; ++ } ++ pci_restore_state(pdev); ++ /* ++ * Suspend/Resume resets the PCI configuration space, so we have to ++ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries ++ * from interfering with C3 CPU state. pci_restore_state won't help ++ * here since it only restores the first 64 bytes pci config header. ++ */ ++ pci_read_config_dword(pdev, 0x40, &val); ++ if ((val & 0x0000ff00) != 0) ++ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ++ ++ if(!netif_running(dev)) ++ goto out; ++ ++ dev->open(dev); ++ netif_device_attach(dev); ++out: ++ return 0; ++} ++ ++ ++int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable) ++{ ++ printk(KERN_NOTICE "r8180 enable wake call (state %u, enable %d).\n", ++ state, enable); ++ return(-EAGAIN); ++} ++ ++ ++ ++#endif //CONFIG_RTL8180_PM +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_pm.h +@@ -0,0 +1,28 @@ ++/* ++ Power management interface routines. ++ Written by Mariusz Matuszek. ++ This code is currently just a placeholder for later work and ++ does not do anything useful. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++*/ ++ ++#ifdef CONFIG_RTL8180_PM ++ ++#ifndef R8180_PM_H ++#define R8180_PM_H ++ ++#include ++#include ++ ++int rtl8180_save_state (struct pci_dev *dev, u32 state); ++int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state); ++int rtl8180_resume (struct pci_dev *pdev); ++int rtl8180_enable_wake (struct pci_dev *dev, u32 state, int enable); ++ ++#endif //R8180_PM_H ++ ++#endif // CONFIG_RTL8180_PM +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_rtl8225.c +@@ -0,0 +1,933 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello ++ ++ This files contains programming code for the rtl8225 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++ ++ ++#include "r8180_hw.h" ++#include "r8180_rtl8225.h" ++ ++ ++u8 rtl8225_gain[]={ ++ 0x23,0x88,0x7c,0xa5,// -82dbm ++ 0x23,0x88,0x7c,0xb5,// -82dbm ++ 0x23,0x88,0x7c,0xc5,// -82dbm ++ 0x33,0x80,0x79,0xc5,// -78dbm ++ 0x43,0x78,0x76,0xc5,// -74dbm ++ 0x53,0x60,0x73,0xc5,// -70dbm ++ 0x63,0x58,0x70,0xc5,// -66dbm ++}; ++ ++#if 0 ++u8 rtl8225_init_gain[]={ ++ //0x00,0x00,0x00,0x00,//0x00,0x00,0x00,0x00, ++ 0x33,0x80,0x6c,0xc5,//0x00,0x49,0x06,0xb5,//Gain = 0 ~ -78dbm ++ 0x43,0x78,0x69,0xc5,//0x00,0x45,0x06,0xb1,//Gain = 1 ~ -74dbm ++ 0x53,0x60,0x66,0xc5,//0x00,0x41,0x06,0xab,//Gain = 2 ~ -70dbm ++ 0x63,0x58,0x63,0xc5,//0x00,0x3d,0x06,0xa5,//Gain = 3 ~ -66dbm ++ 0x73,0x50,0x62,0xc5,//0x00,0x39,0x06,0xa1,//Gain = 4 ~ -62dbm ++ 0x83,0x43,0x61,0xc5,//0x00,0x35,0x06,0x9b,//Gain = 5 ~ -58dbm ++ 0x93,0x38,0x5a,0xc5,//0x00,0x31,0x06,0x99,//Gain = 6 ~ -54dbm ++}; ++#endif ++#ifdef CONFIG_RTL818X_S ++u32 rtl8225_chan[] ={ ++ 0, ++ 0x0080, //ch1 ++ 0x0100, //ch2 ++ 0x0180, //ch3 ++ 0x0200, //ch4 ++ 0x0280, ++ 0x0300, ++ 0x0380, ++ 0x0400, ++ 0x0480, ++ 0x0500, ++ 0x0580, ++ 0x0600, ++ 0x0680, ++ 0x074A, //ch14 ++}; ++#else ++u32 rtl8225_chan[] = { ++ 0, //dummy channel 0 ++ 0x085c, //1 ++ 0x08dc, //2 ++ 0x095c, //3 ++ 0x09dc, //4 ++ 0x0a5c, //5 ++ 0x0adc, //6 ++ 0x0b5c, //7 ++ 0x0bdc, //8 ++ 0x0c5c, //9 ++ 0x0cdc, //10 ++ 0x0d5c, //11 ++ 0x0ddc, //12 ++ 0x0e5c, //13 ++ //0x0f5c, //14 ++ 0x0f72, // 14 ++}; ++#endif ++ ++u16 rtl8225bcd_rxgain[]={ ++ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, ++ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, ++ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, ++ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, ++ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, ++ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, ++ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, ++ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, ++ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, ++ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, ++ 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, ++ 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb ++ ++}; ++ ++ ++#if 0 ++u16 rtl8225bc_rxgain[]={ ++ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, ++ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, ++ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, ++ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, ++ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, ++ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, ++ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, ++ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, ++ 0x0794, 0x0795, 0x0798, 0x0799, 0x039a, 0x039b, 0x039c, 0x039d, ++ 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, ++ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, ++ 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb ++ ++}; ++ ++ ++u16 rtl8225a_rxgain[]={ ++ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, ++ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, ++ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, ++ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, ++ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, ++ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, ++ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, ++ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, ++ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, ++ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, ++ 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, ++ 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad, 0x07ad ++}; ++#endif ++ ++u8 rtl8225_agc[]={ ++ 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96, ++ 0x95,0x94,0x93,0x92,0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86, ++ 0x85,0x84,0x83,0x82,0x81,0x80,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36, ++ 0x35,0x34,0x33,0x32,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26, ++ 0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16, ++ 0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06, ++ 0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++}; ++ ++ ++u8 rtl8225_tx_gain_cck_ofdm[]={ ++ 0x02,0x06,0x0e,0x1e,0x3e,0x7e ++}; ++ ++ ++u8 rtl8225_tx_power_ofdm[]={ ++ 0x80,0x90,0xa2,0xb5,0xcb,0xe4 ++}; ++ ++ ++u8 rtl8225_tx_power_cck_ch14[]={ ++ 0x18,0x17,0x15,0x0c,0x00,0x00,0x00,0x00, ++ 0x1b,0x1a,0x17,0x0e,0x00,0x00,0x00,0x00, ++ 0x1f,0x1e,0x1a,0x0f,0x00,0x00,0x00,0x00, ++ 0x22,0x21,0x1d,0x11,0x00,0x00,0x00,0x00, ++ 0x26,0x25,0x21,0x13,0x00,0x00,0x00,0x00, ++ 0x2b,0x2a,0x25,0x15,0x00,0x00,0x00,0x00 ++}; ++ ++ ++u8 rtl8225_tx_power_cck[]={ ++ 0x18,0x17,0x15,0x11,0x0c,0x08,0x04,0x02, ++ 0x1b,0x1a,0x17,0x13,0x0e,0x09,0x04,0x02, ++ 0x1f,0x1e,0x1a,0x15,0x10,0x0a,0x05,0x02, ++ 0x22,0x21,0x1d,0x18,0x11,0x0b,0x06,0x02, ++ 0x26,0x25,0x21,0x1b,0x14,0x0d,0x06,0x03, ++ 0x2b,0x2a,0x25,0x1e,0x16,0x0e,0x07,0x03 ++}; ++ ++ ++void rtl8225_set_gain(struct net_device *dev, short gain) ++{ ++ write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); ++ write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); ++ write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); ++ write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); ++} ++#if 0 ++ ++void rtl8225_set_gain(struct net_device *dev, short gain) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ ++ if(priv->card_8185 == 2) ++ write_phy_ofdm(dev, 0x21, 0x27); ++ else ++ write_phy_ofdm(dev, 0x21, 0x37); ++ ++ write_phy_ofdm(dev, 0x25, 0x20); ++ write_phy_ofdm(dev, 0x11, 0x6); ++ ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ write_phy_ofdm(dev, 0x27, 0x8); ++ else ++ write_phy_ofdm(dev, 0x27, 0x88); ++ ++ write_phy_ofdm(dev, 0x14, 0); ++ write_phy_ofdm(dev, 0x16, 0); ++ write_phy_ofdm(dev, 0x15, 0x40); ++ write_phy_ofdm(dev, 0x17, 0x40); ++ ++ write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); ++ write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); ++ write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); ++ write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); ++ //rtl8225_set_gain_usb(dev, gain); ++} ++#endif ++ ++ ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data) ++{ ++ int i; ++ u16 out,select; ++ u8 bit; ++ u32 bangdata = (data << 4) | (adr & 0xf); ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ out = read_nic_word(dev, RFPinsOutput) & 0xfff3; ++ ++ write_nic_word(dev,RFPinsEnable, ++ (read_nic_word(dev,RFPinsEnable) | 0x7)); ++ ++ select = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsSelect, select | 0x7 | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); ++ ++ force_pci_posting(dev); ++ udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, out); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ ++ for(i=15; i>=0;i--){ ++ ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ i--; ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ } ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | ++ ((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN)); ++ ++ write_nic_word(dev, RFPinsSelect, select | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ if(priv->card_type == USB) ++ mdelay(2); ++ else ++ rtl8185_rf_pins_enable(dev); ++} ++ ++void rtl8225_rf_close(struct net_device *dev) ++{ ++ write_rtl8225(dev, 0x4, 0x1f); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); ++} ++ ++void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ int GainIdx; ++ int GainSetting; ++ int i; ++ u8 power; ++ u8 *cck_power_table; ++ u8 max_cck_power_level; ++ u8 max_ofdm_power_level; ++ u8 min_ofdm_power_level; ++ u8 cck_power_level = 0xff & priv->chtxpwr[ch]; ++ u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch]; ++ ++ if(priv->card_type == USB){ ++ max_cck_power_level = 11; ++ max_ofdm_power_level = 25; // 12 -> 25 ++ min_ofdm_power_level = 10; ++ }else{ ++ max_cck_power_level = 35; ++ max_ofdm_power_level = 35; ++ min_ofdm_power_level = 0; ++ } ++ /* CCK power setting */ ++ if(cck_power_level > max_cck_power_level) ++ cck_power_level = max_cck_power_level; ++ GainIdx=cck_power_level % 6; ++ GainSetting=cck_power_level / 6; ++ ++ if(ch == 14) ++ cck_power_table = rtl8225_tx_power_cck_ch14; ++ else ++ cck_power_table = rtl8225_tx_power_cck; ++ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion ){ ++ /*Ver B*/ ++// write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]); ++// }else{ ++ /*Ver C - D */ ++ write_nic_byte(dev, TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1); ++// } ++ ++ for(i=0;i<8;i++){ ++ ++ power = cck_power_table[GainIdx * 8 + i]; ++ write_phy_cck(dev, 0x44 + i, power); ++ } ++ ++ /* FIXME Is this delay really needeed ? */ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ /* OFDM power setting */ ++// Old: ++// if(ofdm_power_level > max_ofdm_power_level) ++// ofdm_power_level = 35; ++// ofdm_power_level += min_ofdm_power_level; ++// Latest: ++ if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) ++ ofdm_power_level = max_ofdm_power_level; ++ else ++ ofdm_power_level += min_ofdm_power_level; ++ if(ofdm_power_level > 35) ++ ofdm_power_level = 35; ++// ++ ++ GainIdx=ofdm_power_level % 6; ++ GainSetting=ofdm_power_level / 6; ++#if 1 ++// if(priv->card_type == USB){ ++ rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON); ++ ++ write_phy_ofdm(dev,2,0x42); ++ write_phy_ofdm(dev,6,0); ++ write_phy_ofdm(dev,8,0); ++// } ++#endif ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion){ ++// /*Ver B*/ ++// write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]); ++// }else{ ++ /*Ver C - D */ ++ write_nic_byte(dev, TX_GAIN_OFDM, rtl8225_tx_gain_cck_ofdm[GainSetting]>>1); ++// } ++ ++ ++ power = rtl8225_tx_power_ofdm[GainIdx]; ++ ++ write_phy_ofdm(dev, 0x5, power); ++ write_phy_ofdm(dev, 0x7, power); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ //write_nic_byte(dev, TX_AGC_CONTROL,4); ++} ++#if 0 ++/* switch between mode B and G */ ++void rtl8225_set_mode(struct net_device *dev, short modeb) ++{ ++ write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40)); ++ write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40)); ++} ++#endif ++void rtl8225_rf_set_chan(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ short gset = (priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_54g(priv->ieee80211->current_network)) || ++ priv->ieee80211->iw_mode == IW_MODE_MONITOR; ++ ++ rtl8225_SetTXPowerLevel(dev, ch); ++ ++ write_rtl8225(dev, 0x7, rtl8225_chan[ch]); ++ ++ force_pci_posting(dev); ++ mdelay(10); ++ ++ // A mode sifs 0x44, difs 34-14, slot 9, eifs 23, cwm 3, cwM 7, ctstoself 0x10 ++ if(gset){ ++ write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22 ++ write_nic_byte(dev,DIFS,0x14); //DIFS: 20 ++ //write_nic_byte(dev,DIFS,20); //DIFS: 20 ++ }else{ ++ write_nic_byte(dev,SIFS,0x44);// SIFS: 0x22 ++ write_nic_byte(dev,DIFS,50 - 14); //DIFS: 36 ++ } ++ if(priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_shortslot(priv->ieee80211->current_network)) ++ write_nic_byte(dev,SLOT,0x9); //SLOT: 9 ++ ++ else ++ write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14) ++ ++ ++ if(gset){ ++ write_nic_byte(dev,EIFS,81);//91 - 20); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37 ++ //DMESG("using G net params"); ++ }else{ ++ write_nic_byte(dev,EIFS,81); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37 ++ //DMESG("using B net params"); ++ } ++ ++ ++} ++ ++void rtl8225_host_pci_init(struct net_device *dev) ++{ ++ write_nic_word(dev, RFPinsOutput, 0x480); ++ ++ rtl8185_rf_pins_enable(dev); ++ ++ //if(priv->card_8185 == 2 && priv->enable_gpio0 ) /* version D */ ++ //write_nic_word(dev, RFPinsSelect, 0x88); ++ //else ++ write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); /* 0x488 | SW_CONTROL_GPIO */ ++ ++ write_nic_byte(dev, GP_ENABLE, 0); ++ ++ force_pci_posting(dev); ++ mdelay(200); ++ ++ write_nic_word(dev, GP_ENABLE, 0xff & (~(1<<6))); /* bit 6 is for RF on/off detection */ ++ ++ ++} ++ ++void rtl8225_host_usb_init(struct net_device *dev) ++{ ++ #if 0 ++ write_nic_byte(dev,RFPinsSelect+1,0); ++ ++ write_nic_byte(dev,GPIO,0); ++ ++ write_nic_byte_E(dev,0x53,read_nic_byte_E(dev,0x53) | (1<<7)); ++ ++ write_nic_byte(dev,RFPinsSelect+1,4); ++ ++ write_nic_byte(dev,GPIO,0x20); ++ ++ write_nic_byte(dev,GP_ENABLE,0); ++ ++ ++ /* Config BB & RF */ ++ write_nic_word(dev, RFPinsOutput, 0x80); ++ ++ write_nic_word(dev, RFPinsSelect, 0x80); ++ ++ write_nic_word(dev, RFPinsEnable, 0x80); ++ ++ ++ mdelay(100); ++ ++ mdelay(1000); ++#endif ++ ++} ++ ++void rtl8225_rf_sleep(struct net_device *dev) ++{ ++ write_rtl8225(dev,0x4,0xdff); ++ force_pci_posting(dev); ++ mdelay(1); ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_SLEEP); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_SLEEP); ++ force_pci_posting(dev); ++} ++ ++void rtl8225_rf_wakeup(struct net_device *dev) ++{ ++ write_rtl8225(dev,0x4,0x9ff); ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ force_pci_posting(dev); ++} ++ ++void rtl8225_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int i; ++ short channel = 1; ++ u16 brsr; ++ ++ priv->chan = channel; ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ ++ ++ if(priv->card_type == USB) ++ rtl8225_host_usb_init(dev); ++ else ++ rtl8225_host_pci_init(dev); ++ ++ write_nic_dword(dev, RF_TIMING, 0x000a8008); ++ ++ brsr = read_nic_word(dev, BRSR); ++ ++ write_nic_word(dev, BRSR, 0xffff); ++ ++ #if 0 ++ if(priv->card_8185 == 1){/* version C or B */ ++ if(priv->card_8185_Bversion) /* version B*/ ++ write_nic_dword(dev, RF_PARA, 0x44); ++ else /* version C */ ++ write_nic_dword(dev, RF_PARA, 0x100044); ++ }else{ /* version D */ ++ if(priv->enable_gpio0) ++ write_nic_dword(dev, RF_PARA, 0x20100044); ++ else /* also USB */ ++ write_nic_dword(dev, RF_PARA, 0x100044); ++ } ++ #endif ++ ++ write_nic_dword(dev, RF_PARA, 0x100044); ++ ++ #if 1 //0->1 ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_byte(dev, CONFIG3, 0x44); ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ #endif ++ ++ if(priv->card_type == USB){ ++ rtl8185_rf_pins_enable(dev); ++ ++ mdelay(1000); ++ } ++ ++ write_rtl8225(dev, 0x0, 0x67); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0x1, 0xfe0); mdelay(1); ++ ++ write_rtl8225(dev, 0x2, 0x44d); mdelay(1); ++ ++ write_rtl8225(dev, 0x3, 0x441); mdelay(1); ++ ++ if(priv->card_type == USB) ++ write_rtl8225(dev, 0x4, 0x486); ++ else ++ write_rtl8225(dev, 0x4, 0x8be); ++ ++ mdelay(1); ++ ++ ++ #if 0 ++ }else if(priv->phy_ver == 1){ ++ /* version A */ ++ write_rtl8225(dev, 0x5, 0xbc0 + 2); ++ }else{ ++ #endif ++ /* version B & C */ ++ ++ if(priv->card_type == USB) ++ write_rtl8225(dev, 0x5, 0xbc0); ++ else if(priv->card_type == MINIPCI) ++ write_rtl8225(dev, 0x5, 0xbc0 + 3 +(6<<3)); ++ else ++ write_rtl8225(dev, 0x5, 0xbc0 + (6<<3)); ++ ++ mdelay(1); ++// } ++ ++ write_rtl8225(dev, 0x6, 0xae6); mdelay(1); ++ ++ write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1); ++ ++ write_rtl8225(dev, 0x8, 0x1f); mdelay(1); ++ ++ write_rtl8225(dev, 0x9, 0x334); mdelay(1); ++ ++ write_rtl8225(dev, 0xa, 0xfd4); mdelay(1); ++ ++ write_rtl8225(dev, 0xb, 0x391); mdelay(1); ++ ++ write_rtl8225(dev, 0xc, 0x50); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0xd, 0x6db); mdelay(1); ++ ++ write_rtl8225(dev, 0xe, 0x29); mdelay(1); ++ ++ write_rtl8225(dev, 0xf, 0x914); ++ ++ if(priv->card_type == USB){ ++ //force_pci_posting(dev); ++ mdelay(100); ++ } ++ ++ write_rtl8225(dev, 0x2, 0xc4d); ++ ++ if(priv->card_type == USB){ ++ // force_pci_posting(dev); ++ mdelay(200); ++ ++ write_rtl8225(dev, 0x2, 0x44d); ++ ++ // force_pci_posting(dev); ++ mdelay(100); ++ ++ }//End of if(priv->card_type == USB) ++ /* FIXME!! rtl8187 we have to check if calibrarion ++ * is successful and eventually cal. again (repeat ++ * the two write on reg 2) ++ */ ++ force_pci_posting(dev); ++ ++ mdelay(100); //200 for 8187 ++ ++ //if(priv->card_type != USB) /* maybe not needed even for 8185 */ ++// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++ ++ write_rtl8225(dev, 0x0, 0x127); ++ ++ for(i=0;i<95;i++){ ++ write_rtl8225(dev, 0x1, (u8)(i+1)); ++ ++ #if 0 ++ if(priv->phy_ver == 1) ++ /* version A */ ++ write_rtl8225(dev, 0x2, rtl8225a_rxgain[i]); ++ else ++ #endif ++ /* version B & C & D*/ ++ ++ write_rtl8225(dev, 0x2, rtl8225bcd_rxgain[i]); ++ } ++ ++ write_rtl8225(dev, 0x0, 0x27); ++ ++ ++// //if(priv->card_type != USB){ ++// write_rtl8225(dev, 0x2, 0x44d); ++// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++// write_rtl8225(dev, 0x2, 0x47d); ++// ++// force_pci_posting(dev); ++// mdelay(100); ++// ++// write_rtl8225(dev, 0x2, 0x44d); ++// //} ++ ++ write_rtl8225(dev, 0x0, 0x22f); ++ ++ if(priv->card_type != USB) ++ rtl8185_rf_pins_enable(dev); ++ ++ for(i=0;i<128;i++){ ++ write_phy_ofdm(dev, 0xb, rtl8225_agc[i]); ++ ++ mdelay(1); ++ write_phy_ofdm(dev, 0xa, (u8)i+ 0x80); ++ ++ mdelay(1); ++ } ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ write_phy_ofdm(dev, 0x0, 0x1); mdelay(1); ++ write_phy_ofdm(dev, 0x1, 0x2); mdelay(1); ++ write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1); ++ write_phy_ofdm(dev, 0x3, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x4, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x5, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x6, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x7, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x8, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1); ++ ++ #if 0 ++ if(priv->card_type == USB){ ++ write_phy_ofdm(dev, 0xa, 0x9); ++ }else{ ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion){ ++ /* Ver B ++ * maybe later version can accept this also? ++ */ ++ write_phy_ofdm(dev, 0xa, 0x6); ++ write_phy_ofdm(dev, 0x18, 0x6f); ++ }else{ ++ #endif ++ /* ver C & D */ ++ write_phy_ofdm(dev, 0xa, 0x9); mdelay(1); ++ ++ //write_phy_ofdm(dev, 0x18, 0xef); ++ // } ++ //} ++ write_phy_ofdm(dev, 0xb, 0x80); mdelay(1); ++ ++ write_phy_ofdm(dev, 0xc, 0x1);mdelay(1); ++ ++ ++ //if(priv->card_type != USB) ++ //write_phy_ofdm(dev, 0xd, 0x33); // <> ++ ++ write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1); ++ ++ ++ #if 0 ++ if(priv->card_8185 == 1){ ++ if(priv->card_8185_Bversion) ++ write_phy_ofdm(dev, 0xf, 0x20);/*ver B*/ ++ else ++ write_phy_ofdm(dev, 0xf, 0x28);/*ver C*/ ++ }else{ ++ #endif ++ write_phy_ofdm(dev, 0xf, 0x38);mdelay(1); ++/*ver D & 8187*/ ++// } ++ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++// write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/ ++// else ++ write_phy_ofdm(dev, 0x10, 0x84);mdelay(1); ++/*ver C & D & 8187*/ ++ ++ write_phy_ofdm(dev, 0x11, 0x06);mdelay(1); ++/*agc resp time 700*/ ++ ++ ++// if(priv->card_8185 == 2){ ++ /* Ver D & 8187*/ ++ write_phy_ofdm(dev, 0x12, 0x20);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x13, 0x20);mdelay(1); ++ ++#if 0 ++ }else{ ++ /* Ver B & C*/ ++ write_phy_ofdm(dev, 0x12, 0x0); ++ write_phy_ofdm(dev, 0x13, 0x0); ++ } ++#endif ++ write_phy_ofdm(dev, 0x14, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x16, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); ++ ++// if (priv->card_type == USB) ++// write_phy_ofdm(dev, 0x18, 0xef); ++ ++ write_phy_ofdm(dev, 0x18, 0xef);mdelay(1); ++ ++ ++ write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); ++ write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); ++ ++// if (priv->card_type != USB){ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++// write_phy_ofdm(dev, 0x1b, 0x66); /* Ver B */ ++// else ++ write_phy_ofdm(dev, 0x1b, 0x76);mdelay(1); ++ /* Ver C & D */ //FIXME:MAYBE not needed ++// } ++ ++ write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1); ++ ++#if 0 ++ if(priv->card_8185 == 1){ ++ if(priv->card_8185_Bversion){ ++ /*ver B*/ ++ write_phy_ofdm(dev, 0x1e, 0x95); ++ write_phy_ofdm(dev, 0x1f, 0x55); ++ }else{ ++ /*ver C*/ ++ write_phy_ofdm(dev, 0x1e, 0x90); ++ write_phy_ofdm(dev, 0x1f, 0x34); ++ ++ } ++ }else{ ++#endif ++ /*ver D & 8187*/ ++ write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); ++ ++// } ++ ++ write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x21, 0x27);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x22, 0x16);mdelay(1); ++ ++// if(priv->card_type != USB) ++ //write_phy_ofdm(dev, 0x23, 0x43); //FIXME maybe not needed // <> ++ ++ write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0x25, 0x20); mdelay(1); ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); ++#if 0 ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ write_phy_ofdm(dev, 0x27, 0x08); /* Ver B. might work also fo ver C&D ?*/ ++ else ++#endif ++ write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); ++/* Ver C & D & 8187*/ ++ ++ // <> Set init. gain to m74dBm. ++ write_phy_ofdm(dev, 0x0d, 0x43); mdelay(1); ++ write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1); ++ write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1); ++ write_phy_ofdm(dev, 0x23, 0x78); mdelay(1); ++ ++ //if(priv->card_type == USB); ++ // rtl8225_set_gain_usb(dev, 1); /* FIXME this '2' is random */ ++ ++ write_phy_cck(dev, 0x0, 0x98); mdelay(1); ++ write_phy_cck(dev, 0x3, 0x20); mdelay(1); ++ write_phy_cck(dev, 0x4, 0x7e); mdelay(1); ++ write_phy_cck(dev, 0x5, 0x12); mdelay(1); ++ write_phy_cck(dev, 0x6, 0xfc); mdelay(1); ++#if 0 ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ write_phy_cck(dev, 0x7, 0xd8); /* Ver B */ ++ else ++#endif ++ write_phy_cck(dev, 0x7, 0x78);mdelay(1); ++ /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x8, 0x2e);mdelay(1); ++ ++ write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1); ++ write_phy_cck(dev, 0x11, 0x88); mdelay(1); ++ write_phy_cck(dev, 0x12, 0x47); mdelay(1); ++#if 0 ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ write_phy_cck(dev, 0x13, 0x98); /* Ver B */ ++ else ++#endif ++ write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x19, 0x0); ++ write_phy_cck(dev, 0x1a, 0xa0); ++ write_phy_cck(dev, 0x1b, 0x8); ++ write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ ++ ++ write_phy_cck(dev, 0x41, 0x8d);mdelay(1); ++ ++ ++ write_phy_cck(dev, 0x42, 0x15); mdelay(1); ++ write_phy_cck(dev, 0x43, 0x18); mdelay(1); ++ write_phy_cck(dev, 0x44, 0x1f); mdelay(1); ++ write_phy_cck(dev, 0x45, 0x1e); mdelay(1); ++ write_phy_cck(dev, 0x46, 0x1a); mdelay(1); ++ write_phy_cck(dev, 0x47, 0x15); mdelay(1); ++ write_phy_cck(dev, 0x48, 0x10); mdelay(1); ++ write_phy_cck(dev, 0x49, 0xa); mdelay(1); ++ write_phy_cck(dev, 0x4a, 0x5); mdelay(1); ++ write_phy_cck(dev, 0x4b, 0x2); mdelay(1); ++ write_phy_cck(dev, 0x4c, 0x5);mdelay(1); ++ ++ ++ write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); ++ ++ ++ ++// <> ++// // TESTR 0xb 8187 ++// write_phy_cck(dev, 0x10, 0x93);// & 0xfb); ++// ++// //if(priv->card_type != USB){ ++// write_phy_ofdm(dev, 0x2, 0x62); ++// write_phy_ofdm(dev, 0x6, 0x0); ++// write_phy_ofdm(dev, 0x8, 0x0); ++// //} ++ ++ rtl8225_SetTXPowerLevel(dev, channel); ++ ++ write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */ ++ ++ rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */ ++ ++ /* switch to high-speed 3-wire ++ * last digit. 2 for both cck and ofdm ++ */ ++ if(priv->card_type == USB) ++ write_nic_dword(dev, 0x94, 0x3dc00002); ++ else{ ++ write_nic_dword(dev, 0x94, 0x15c00002); ++ rtl8185_rf_pins_enable(dev); ++ } ++ ++// if(priv->card_type != USB) ++// rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <> ++// rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <> ++// ++// /* make sure is waken up! */ ++// write_rtl8225(dev,0x4, 0x9ff); ++// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ ++ rtl8225_rf_set_chan(dev, priv->chan); ++ ++ write_nic_word(dev,BRSR,brsr); ++ ++} +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_rtl8225.h +@@ -0,0 +1,44 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello ++ ++ This files contains programming code for the rtl8225 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#include "r8180.h" ++ ++#define RTL8225_ANAPARAM_ON 0xa0000b59 ++#define RTL8225_ANAPARAM_OFF 0xa00beb59 ++#define RTL8225_ANAPARAM2_OFF 0x840dec11 ++#define RTL8225_ANAPARAM2_ON 0x860dec11 ++#define RTL8225_ANAPARAM_SLEEP 0xa00bab59 ++#define RTL8225_ANAPARAM2_SLEEP 0x840dec11 ++ ++#ifdef CONFIG_RTL8185B ++void rtl8225z2_rf_init(struct net_device *dev); ++void rtl8225z2_rf_set_chan(struct net_device *dev,short ch); ++void rtl8225z2_rf_close(struct net_device *dev); ++ ++void rtl8225_host_pci_init(struct net_device *dev); ++void rtl8225_host_usb_init(struct net_device *dev); ++ ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data); ++void RF_WriteReg(struct net_device *dev, u8 offset, u32 data); ++u32 RF_ReadReg(struct net_device *dev, u8 offset); ++#endif ++void rtl8225_rf_init(struct net_device *dev); ++void rtl8225_rf_set_chan(struct net_device *dev,short ch); ++void rtl8225_rf_close(struct net_device *dev); ++void rtl8225_rf_sleep(struct net_device *dev); ++void rtl8225_rf_wakeup(struct net_device *dev); ++void rtl8180_set_mode(struct net_device *dev,int mode); ++void rtl8180_set_mode(struct net_device *dev,int mode); ++bool SetZebraRFPowerState8185(struct net_device *dev,RT_RF_POWER_STATE eRFPowerState); ++void rtl8225z4_rf_sleep(struct net_device *dev); ++void rtl8225z4_rf_wakeup(struct net_device *dev); ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c +@@ -0,0 +1,1587 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello ++ ++ This files contains programming code for the rtl8225 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#include "r8180_hw.h" ++#include "r8180_rtl8225.h" ++#include "r8180_93cx6.h" ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++#ifdef CONFIG_RTL8185B ++ ++extern u8 rtl8225_agc[]; ++ ++extern u32 rtl8225_chan[]; ++ ++//2005.11.16 ++u8 rtl8225z2_threshold[]={ ++ 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd, ++}; ++ ++// 0xd 0x19 0x1b 0x21 ++u8 rtl8225z2_gain_bg[]={ ++ 0x23, 0x15, 0xa5, // -82-1dbm ++ 0x23, 0x15, 0xb5, // -82-2dbm ++ 0x23, 0x15, 0xc5, // -82-3dbm ++ 0x33, 0x15, 0xc5, // -78dbm ++ 0x43, 0x15, 0xc5, // -74dbm ++ 0x53, 0x15, 0xc5, // -70dbm ++ 0x63, 0x15, 0xc5, // -66dbm ++}; ++ ++u8 rtl8225z2_gain_a[]={ ++ 0x13,0x27,0x5a,//,0x37,// -82dbm ++ 0x23,0x23,0x58,//,0x37,// -82dbm ++ 0x33,0x1f,0x56,//,0x37,// -82dbm ++ 0x43,0x1b,0x54,//,0x37,// -78dbm ++ 0x53,0x17,0x51,//,0x37,// -74dbm ++ 0x63,0x24,0x4f,//,0x37,// -70dbm ++ 0x73,0x0f,0x4c,//,0x37,// -66dbm ++}; ++#if 0 ++u32 rtl8225_chan[] = { ++ 0, //dummy channel 0 ++ 0x085c, //1 ++ 0x08dc, //2 ++ 0x095c, //3 ++ 0x09dc, //4 ++ 0x0a5c, //5 ++ 0x0adc, //6 ++ 0x0b5c, //7 ++ 0x0bdc, //8 ++ 0x0c5c, //9 ++ 0x0cdc, //10 ++ 0x0d5c, //11 ++ 0x0ddc, //12 ++ 0x0e5c, //13 ++ //0x0f5c, //14 ++ 0x0f72, // 14 ++}; ++#endif ++ ++//- ++u16 rtl8225z2_rxgain[]={ ++ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, ++ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, ++ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, ++ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, ++ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, ++ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, ++ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, ++ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, ++ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, ++ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, ++ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, ++ 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb ++ ++}; ++ ++//2005.11.16, ++u8 ZEBRA2_CCK_OFDM_GAIN_SETTING[]={ ++ 0x00,0x01,0x02,0x03,0x04,0x05, ++ 0x06,0x07,0x08,0x09,0x0a,0x0b, ++ 0x0c,0x0d,0x0e,0x0f,0x10,0x11, ++ 0x12,0x13,0x14,0x15,0x16,0x17, ++ 0x18,0x19,0x1a,0x1b,0x1c,0x1d, ++ 0x1e,0x1f,0x20,0x21,0x22,0x23, ++}; ++ ++#if 0 ++//- ++u8 rtl8225_agc[]={ ++ 0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,0x97,0x96, ++ 0x95,0x94,0x93,0x92,0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,0x87,0x86, ++ 0x85,0x84,0x83,0x82,0x81,0x80,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37,0x36, ++ 0x35,0x34,0x33,0x32,0x31,0x30,0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26, ++ 0x25,0x24,0x23,0x22,0x21,0x20,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16, ++ 0x15,0x14,0x13,0x12,0x11,0x10,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06, ++ 0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++}; ++#endif ++/* ++ from 0 to 0x23 ++u8 rtl8225_tx_gain_cck_ofdm[]={ ++ 0x02,0x06,0x0e,0x1e,0x3e,0x7e ++}; ++*/ ++ ++//- ++u8 rtl8225z2_tx_power_ofdm[]={ ++ 0x42,0x00,0x40,0x00,0x40 ++}; ++ ++ ++//- ++u8 rtl8225z2_tx_power_cck_ch14[]={ ++ 0x36,0x35,0x2e,0x1b,0x00,0x00,0x00,0x00 ++}; ++ ++ ++//- ++u8 rtl8225z2_tx_power_cck[]={ ++ 0x36,0x35,0x2e,0x25,0x1c,0x12,0x09,0x04 ++}; ++ ++ ++void rtl8225z2_set_gain(struct net_device *dev, short gain) ++{ ++ u8* rtl8225_gain; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ u8 mode = priv->ieee80211->mode; ++ ++ if(mode == IEEE_B || mode == IEEE_G) ++ rtl8225_gain = rtl8225z2_gain_bg; ++ else ++ rtl8225_gain = rtl8225z2_gain_a; ++ ++ //write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 3]); ++ //write_phy_ofdm(dev, 0x19, rtl8225_gain[gain * 3 + 1]); ++ //write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 2]); ++ //2005.11.17, by ch-hsu ++ write_phy_ofdm(dev, 0x0b, rtl8225_gain[gain * 3]); ++ write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 1]); ++ write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 3 + 2]); ++ write_phy_ofdm(dev, 0x21, 0x37); ++ ++} ++ ++#if 0 ++ ++void rtl8225_set_gain(struct net_device *dev, short gain) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ ++ if(priv->card_8185 == 2) ++ write_phy_ofdm(dev, 0x21, 0x27); ++ else ++ write_phy_ofdm(dev, 0x21, 0x37); ++ ++ write_phy_ofdm(dev, 0x25, 0x20); ++ write_phy_ofdm(dev, 0x11, 0x6); ++ ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ write_phy_ofdm(dev, 0x27, 0x8); ++ else ++ write_phy_ofdm(dev, 0x27, 0x88); ++ ++ write_phy_ofdm(dev, 0x14, 0); ++ write_phy_ofdm(dev, 0x16, 0); ++ write_phy_ofdm(dev, 0x15, 0x40); ++ write_phy_ofdm(dev, 0x17, 0x40); ++ ++ write_phy_ofdm(dev, 0x0d, rtl8225_gain[gain * 4]); ++ write_phy_ofdm(dev, 0x23, rtl8225_gain[gain * 4 + 1]); ++ write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 4 + 2]); ++ write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 4 + 3]); ++ //rtl8225_set_gain_usb(dev, gain); ++} ++#endif ++ ++u32 read_rtl8225(struct net_device *dev, u8 adr) ++{ ++ u32 data2Write = ((u32)(adr & 0x1f)) << 27; ++ u32 dataRead; ++ u32 mask; ++ u16 oval,oval2,oval3,tmp; ++// ThreeWireReg twreg; ++// ThreeWireReg tdata; ++ int i; ++ short bit, rw; ++ ++ u8 wLength = 6; ++ u8 rLength = 12; ++ u8 low2high = 0; ++ ++ oval = read_nic_word(dev, RFPinsOutput); ++ oval2 = read_nic_word(dev, RFPinsEnable); ++ oval3 = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsEnable, (oval2|0xf)); ++ write_nic_word(dev, RFPinsSelect, (oval3|0xf)); ++ ++ dataRead = 0; ++ ++ oval &= ~0xf; ++ ++ write_nic_word(dev, RFPinsOutput, oval | BB_HOST_BANG_EN ); udelay(4); ++ ++ write_nic_word(dev, RFPinsOutput, oval ); udelay(5); ++ ++ rw = 0; ++ ++ mask = (low2high) ? 0x01 : (((u32)0x01)<<(32-1)); ++ for(i = 0; i < wLength/2; i++) ++ { ++ bit = ((data2Write&mask) != 0) ? 1 : 0; ++ write_nic_word(dev, RFPinsOutput, bit|oval | rw); udelay(1); ++ ++ write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); ++ write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); ++ ++ mask = (low2high) ? (mask<<1): (mask>>1); ++ ++ if(i == 2) ++ { ++ rw = BB_HOST_BANG_RW; ++ write_nic_word(dev, RFPinsOutput, bit|oval | BB_HOST_BANG_CLK | rw); udelay(2); ++ write_nic_word(dev, RFPinsOutput, bit|oval | rw); udelay(2); ++ break; ++ } ++ ++ bit = ((data2Write&mask) != 0) ? 1: 0; ++ ++ write_nic_word(dev, RFPinsOutput, oval|bit|rw| BB_HOST_BANG_CLK); udelay(2); ++ write_nic_word(dev, RFPinsOutput, oval|bit|rw| BB_HOST_BANG_CLK); udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, oval| bit |rw); udelay(1); ++ ++ mask = (low2high) ? (mask<<1) : (mask>>1); ++ } ++ ++ //twreg.struc.clk = 0; ++ //twreg.struc.data = 0; ++ write_nic_word(dev, RFPinsOutput, rw|oval); udelay(2); ++ mask = (low2high) ? 0x01 : (((u32)0x01) << (12-1)); ++ ++ // We must set data pin to HW controled, otherwise RF can't driver it and ++ // value RF register won't be able to read back properly. 2006.06.13, by rcnjko. ++ write_nic_word(dev, RFPinsEnable, (oval2 & (~0x01))); ++ ++ for(i = 0; i < rLength; i++) ++ { ++ write_nic_word(dev, RFPinsOutput, rw|oval); udelay(1); ++ ++ write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); ++ write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); ++ write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); udelay(2); ++ tmp = read_nic_word(dev, RFPinsInput); ++ ++ dataRead |= (tmp & BB_HOST_BANG_CLK ? mask : 0); ++ ++ write_nic_word(dev, RFPinsOutput, (rw|oval)); udelay(2); ++ ++ mask = (low2high) ? (mask<<1) : (mask>>1); ++ } ++ ++ write_nic_word(dev, RFPinsOutput, BB_HOST_BANG_EN|BB_HOST_BANG_RW|oval); udelay(2); ++ ++ write_nic_word(dev, RFPinsEnable, oval2); ++ write_nic_word(dev, RFPinsSelect, oval3); // Set To SW Switch ++ write_nic_word(dev, RFPinsOutput, 0x3a0); ++ ++ return dataRead; ++ ++} ++#if 0 ++void write_rtl8225(struct net_device *dev, u8 adr, u16 data) ++{ ++ int i; ++ u16 out,select; ++ u8 bit; ++ u32 bangdata = (data << 4) | (adr & 0xf); ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ out = read_nic_word(dev, RFPinsOutput) & 0xfff3; ++ ++ write_nic_word(dev,RFPinsEnable, ++ (read_nic_word(dev,RFPinsEnable) | 0x7)); ++ ++ select = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsSelect, select | 0x7 | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); ++ ++ force_pci_posting(dev); ++ udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, out); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ ++ for(i=15; i>=0;i--){ ++ ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ i--; ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ ++ } ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | ++ ((priv->card_type == USB) ? 4 : BB_HOST_BANG_EN)); ++ ++ write_nic_word(dev, RFPinsSelect, select | ++ ((priv->card_type == USB) ? 0 : SW_CONTROL_GPIO)); ++ ++ if(priv->card_type == USB) ++ mdelay(2); ++ else ++ rtl8185_rf_pins_enable(dev); ++} ++ ++#endif ++short rtl8225_is_V_z2(struct net_device *dev) ++{ ++ short vz2 = 1; ++ //int i; ++ /* sw to reg pg 1 */ ++ //write_rtl8225(dev, 0, 0x1b7); ++ //write_rtl8225(dev, 0, 0x0b7); ++ ++ /* reg 8 pg 1 = 23*/ ++ //printk(KERN_WARNING "RF Rigisters:\n"); ++#if 0 ++ for(i = 0; i <= 0xf; i++) ++ printk(KERN_WARNING "%08x,", read_rtl8225(dev, i)); ++ //printk(KERN_WARNING "reg[9]@pg1 = 0x%x\n", read_rtl8225(dev, 0x0F)); ++ ++// printk(KERN_WARNING "RF:\n"); ++#endif ++ if( read_rtl8225(dev, 8) != 0x588) ++ vz2 = 0; ++ ++ else /* reg 9 pg 1 = 24 */ ++ if( read_rtl8225(dev, 9) != 0x700) ++ vz2 = 0; ++ ++ /* sw back to pg 0 */ ++ write_rtl8225(dev, 0, 0xb7); ++ ++ return vz2; ++ ++} ++ ++#if 0 ++void rtl8225_rf_close(struct net_device *dev) ++{ ++ write_rtl8225(dev, 0x4, 0x1f); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); ++ rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); ++} ++#endif ++#if 0 ++short rtl8225_rf_set_sens(struct net_device *dev, short sens) ++{ ++ if (sens <0 || sens > 6) return -1; ++ ++ if(sens > 4) ++ write_rtl8225(dev, 0x0c, 0x850); ++ else ++ write_rtl8225(dev, 0x0c, 0x50); ++ ++ sens= 6-sens; ++ rtl8225_set_gain(dev, sens); ++ ++ write_phy_cck(dev, 0x41, rtl8225_threshold[sens]); ++ return 0; ++ ++} ++#endif ++ ++ ++void rtl8225z2_rf_close(struct net_device *dev) ++{ ++ RF_WriteReg(dev, 0x4, 0x1f); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ rtl8180_set_anaparam(dev, RTL8225z2_ANAPARAM_OFF); ++ rtl8185_set_anaparam2(dev, RTL8225z2_ANAPARAM2_OFF); ++} ++ ++#ifdef ENABLE_DOT11D ++// ++// Description: ++// Map dBm into Tx power index according to ++// current HW model, for example, RF and PA, and ++// current wireless mode. ++// ++s8 ++DbmToTxPwrIdx( ++ struct r8180_priv *priv, ++ WIRELESS_MODE WirelessMode, ++ s32 PowerInDbm ++ ) ++{ ++ bool bUseDefault = true; ++ s8 TxPwrIdx = 0; ++ ++#ifdef CONFIG_RTL818X_S ++ // ++ // 071011, SD3 SY: ++ // OFDM Power in dBm = Index * 0.5 + 0 ++ // CCK Power in dBm = Index * 0.25 + 13 ++ // ++ if(priv->card_8185 >= VERSION_8187S_B) ++ { ++ s32 tmp = 0; ++ ++ if(WirelessMode == WIRELESS_MODE_G) ++ { ++ bUseDefault = false; ++ tmp = (2 * PowerInDbm); ++ ++ if(tmp < 0) ++ TxPwrIdx = 0; ++ else if(tmp > 40) // 40 means 20 dBm. ++ TxPwrIdx = 40; ++ else ++ TxPwrIdx = (s8)tmp; ++ } ++ else if(WirelessMode == WIRELESS_MODE_B) ++ { ++ bUseDefault = false; ++ tmp = (4 * PowerInDbm) - 52; ++ ++ if(tmp < 0) ++ TxPwrIdx = 0; ++ else if(tmp > 28) // 28 means 20 dBm. ++ TxPwrIdx = 28; ++ else ++ TxPwrIdx = (s8)tmp; ++ } ++ } ++#endif ++ ++ // ++ // TRUE if we want to use a default implementation. ++ // We shall set it to FALSE when we have exact translation formular ++ // for target IC. 070622, by rcnjko. ++ // ++ if(bUseDefault) ++ { ++ if(PowerInDbm < 0) ++ TxPwrIdx = 0; ++ else if(PowerInDbm > 35) ++ TxPwrIdx = 35; ++ else ++ TxPwrIdx = (u8)PowerInDbm; ++ } ++ ++ return TxPwrIdx; ++} ++#endif ++ ++void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++// int GainIdx; ++// int GainSetting; ++ //int i; ++ //u8 power; ++ //u8 *cck_power_table; ++ u8 max_cck_power_level; ++ //u8 min_cck_power_level; ++ u8 max_ofdm_power_level; ++ u8 min_ofdm_power_level; ++// u8 cck_power_level = 0xff & priv->chtxpwr[ch];//-by amy 080312 ++// u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch];//-by amy 080312 ++ char cck_power_level = (char)(0xff & priv->chtxpwr[ch]);//+by amy 080312 ++ char ofdm_power_level = (char)(0xff & priv->chtxpwr_ofdm[ch]);//+by amy 080312 ++#if 0 ++ // ++ // CCX 2 S31, AP control of client transmit power: ++ // 1. We shall not exceed Cell Power Limit as possible as we can. ++ // 2. Tolerance is +/- 5dB. ++ // 3. 802.11h Power Contraint takes higher precedence over CCX Cell Power Limit. ++ // ++ // TODO: ++ // 1. 802.11h power contraint ++ // ++ // 071011, by rcnjko. ++ // ++ if( priv->OpMode == RT_OP_MODE_INFRASTRUCTURE && ++ priv->bWithCcxCellPwr && ++ ch == priv->dot11CurrentChannelNumber) ++ { ++ u8 CckCellPwrIdx = DbmToTxPwrIdx(dev, WIRELESS_MODE_B, pMgntInfo->CcxCellPwr); ++ u8 OfdmCellPwrIdx = DbmToTxPwrIdx(dev, WIRELESS_MODE_G, pMgntInfo->CcxCellPwr); ++ ++ printk("CCX Cell Limit: %d dBm => CCK Tx power index : %d, OFDM Tx power index: %d\n", ++ priv->CcxCellPwr, CckCellPwrIdx, OfdmCellPwrIdx); ++ printk("EEPROM channel(%d) => CCK Tx power index: %d, OFDM Tx power index: %d\n", ++ channel, CckTxPwrIdx, OfdmTxPwrIdx); ++ ++ if(cck_power_level > CckCellPwrIdx) ++ cck_power_level = CckCellPwrIdx; ++ if(ofdm_power_level > OfdmCellPwrIdx) ++ ofdm_power_level = OfdmCellPwrIdx; ++ ++ printk("Altered CCK Tx power index : %d, OFDM Tx power index: %d\n", ++ CckTxPwrIdx, OfdmTxPwrIdx); ++ } ++#endif ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(priv->ieee80211) && ++ IS_DOT11D_STATE_DONE(priv->ieee80211) ) ++ { ++ //PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(priv->ieee80211); ++ u8 MaxTxPwrInDbm = DOT11D_GetMaxTxPwrInDbm(priv->ieee80211, ch); ++ u8 CckMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_B, MaxTxPwrInDbm); ++ u8 OfdmMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_G, MaxTxPwrInDbm); ++ ++ //printk("Max Tx Power dBm (%d) => CCK Tx power index : %d, OFDM Tx power index: %d\n", MaxTxPwrInDbm, CckMaxPwrIdx, OfdmMaxPwrIdx); ++ ++ //printk("EEPROM channel(%d) => CCK Tx power index: %d, OFDM Tx power index: %d\n", ++ // ch, cck_power_level, ofdm_power_level); ++ ++ if(cck_power_level > CckMaxPwrIdx) ++ cck_power_level = CckMaxPwrIdx; ++ if(ofdm_power_level > OfdmMaxPwrIdx) ++ ofdm_power_level = OfdmMaxPwrIdx; ++ } ++ ++ //priv->CurrentCckTxPwrIdx = cck_power_level; ++ //priv->CurrentOfdmTxPwrIdx = ofdm_power_level; ++#endif ++ ++ max_cck_power_level = 15; ++ max_ofdm_power_level = 25; // 12 -> 25 ++ min_ofdm_power_level = 10; ++ ++#ifdef CONFIG_RTL8185B ++#ifdef CONFIG_RTL818X_S ++ ++ if(cck_power_level > 35) ++ { ++ cck_power_level = 35; ++ } ++ // ++ // Set up CCK TXAGC. suggested by SD3 SY. ++ // ++ write_nic_byte(dev, CCK_TXAGC, (ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)cck_power_level]) ); ++ //printk("CCK TX power is %x\n", (ZEBRA2_CCK_OFDM_GAIN_SETTING[cck_power_level])); ++ force_pci_posting(dev); ++ mdelay(1); ++#else ++ ++ /* CCK power setting */ ++ if(cck_power_level > max_cck_power_level) ++ cck_power_level = max_cck_power_level; ++ ++ cck_power_level += priv->cck_txpwr_base; ++ ++ if(cck_power_level > 35) ++ cck_power_level = 35; ++ ++ if(ch == 14) ++ cck_power_table = rtl8225z2_tx_power_cck_ch14; ++ else ++ cck_power_table = rtl8225z2_tx_power_cck; ++ ++ ++ for(i=0;i<8;i++){ ++ ++ power = cck_power_table[i]; ++ write_phy_cck(dev, 0x44 + i, power); ++ } ++ ++ //write_nic_byte(dev, TX_GAIN_CCK, power); ++ //2005.11.17, ++ write_nic_byte(dev, CCK_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)cck_power_level]); ++ ++ force_pci_posting(dev); ++ mdelay(1); ++#endif ++#endif ++ /* OFDM power setting */ ++// Old: ++// if(ofdm_power_level > max_ofdm_power_level) ++// ofdm_power_level = 35; ++// ofdm_power_level += min_ofdm_power_level; ++// Latest: ++/* if(ofdm_power_level > (max_ofdm_power_level - min_ofdm_power_level)) ++ ofdm_power_level = max_ofdm_power_level; ++ else ++ ofdm_power_level += min_ofdm_power_level; ++ ++ ofdm_power_level += priv->ofdm_txpwr_base; ++*/ ++ if(ofdm_power_level > 35) ++ ofdm_power_level = 35; ++ ++// rtl8185_set_anaparam2(dev,RTL8225_ANAPARAM2_ON); ++ ++ //rtl8185_set_anaparam2(dev, ANAPARM2_ASIC_ON); ++ ++ if (priv->up == 0) { ++ //must add these for rtl8185B down, xiong-2006-11-21 ++ write_phy_ofdm(dev,2,0x42); ++ write_phy_ofdm(dev,5,0); ++ write_phy_ofdm(dev,6,0x40); ++ write_phy_ofdm(dev,7,0); ++ write_phy_ofdm(dev,8,0x40); ++ } ++ ++ //write_nic_byte(dev, TX_GAIN_OFDM, ofdm_power_level); ++ //2005.11.17, ++#ifdef CONFIG_RTL818X_S ++ write_nic_byte(dev, OFDM_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)ofdm_power_level]); ++#else ++ write_nic_byte(dev, OFDM_TXAGC, ZEBRA2_CCK_OFDM_GAIN_SETTING[(u8)ofdm_power_level]*2); ++#endif ++ if(ofdm_power_level<=11) ++ { ++// write_nic_dword(dev,PHY_ADR,0x00005c87); ++// write_nic_dword(dev,PHY_ADR,0x00005c89); ++ write_phy_ofdm(dev,0x07,0x5c); ++ write_phy_ofdm(dev,0x09,0x5c); ++ } ++ if(ofdm_power_level<=17) ++ { ++// write_nic_dword(dev,PHY_ADR,0x00005487); ++// write_nic_dword(dev,PHY_ADR,0x00005489); ++ write_phy_ofdm(dev,0x07,0x54); ++ write_phy_ofdm(dev,0x09,0x54); ++ } ++ else ++ { ++// write_nic_dword(dev,PHY_ADR,0x00005087); ++// write_nic_dword(dev,PHY_ADR,0x00005089); ++ write_phy_ofdm(dev,0x07,0x50); ++ write_phy_ofdm(dev,0x09,0x50); ++ } ++ force_pci_posting(dev); ++ mdelay(1); ++ ++} ++#if 0 ++/* switch between mode B and G */ ++void rtl8225_set_mode(struct net_device *dev, short modeb) ++{ ++ write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40)); ++ write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40)); ++} ++#endif ++ ++void rtl8225z2_rf_set_chan(struct net_device *dev, short ch) ++{ ++/* ++ short gset = (priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_54g(priv->ieee80211->current_network)) || ++ priv->ieee80211->iw_mode == IW_MODE_MONITOR; ++*/ ++ rtl8225z2_SetTXPowerLevel(dev, ch); ++ ++ RF_WriteReg(dev, 0x7, rtl8225_chan[ch]); ++ ++ //YJ,add,080828, if set channel failed, write again ++ if((RF_ReadReg(dev, 0x7) & 0x0F80) != rtl8225_chan[ch]) ++ { ++ RF_WriteReg(dev, 0x7, rtl8225_chan[ch]); ++ } ++ ++ mdelay(1); ++ ++ force_pci_posting(dev); ++ mdelay(10); ++//deleted by David : 2006/8/9 ++#if 0 ++ write_nic_byte(dev,SIFS,0x22);// SIFS: 0x22 ++ ++ if(gset) ++ write_nic_byte(dev,DIFS,20); //DIFS: 20 ++ else ++ write_nic_byte(dev,DIFS,0x24); //DIFS: 36 ++ ++ if(priv->ieee80211->state == IEEE80211_LINKED && ++ ieee80211_is_shortslot(priv->ieee80211->current_network)) ++ write_nic_byte(dev,SLOT,0x9); //SLOT: 9 ++ ++ else ++ write_nic_byte(dev,SLOT,0x14); //SLOT: 20 (0x14) ++ ++ ++ if(gset){ ++ write_nic_byte(dev,EIFS,91 - 20); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0x73); //CW VALUE: 0x37 ++ //DMESG("using G net params"); ++ }else{ ++ write_nic_byte(dev,EIFS,91 - 0x24); // EIFS: 91 (0x5B) ++ write_nic_byte(dev,CW_VAL,0xa5); //CW VALUE: 0x37 ++ //DMESG("using B net params"); ++ } ++#endif ++ ++} ++#if 0 ++void rtl8225_host_pci_init(struct net_device *dev) ++{ ++ write_nic_word(dev, RFPinsOutput, 0x480); ++ ++ rtl8185_rf_pins_enable(dev); ++ ++ //if(priv->card_8185 == 2 && priv->enable_gpio0 ) /* version D */ ++ //write_nic_word(dev, RFPinsSelect, 0x88); ++ //else ++ write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); /* 0x488 | SW_CONTROL_GPIO */ ++ ++ write_nic_byte(dev, GP_ENABLE, 0); ++ ++ force_pci_posting(dev); ++ mdelay(200); ++ ++ write_nic_word(dev, GP_ENABLE, 0xff & (~(1<<6))); /* bit 6 is for RF on/off detection */ ++ ++ ++} ++ ++void rtl8225_host_usb_init(struct net_device *dev) ++{ ++ write_nic_byte(dev,RFPinsSelect+1,0); ++ ++ write_nic_byte(dev,GPIO,0); ++ ++ write_nic_byte_E(dev,0x53,read_nic_byte_E(dev,0x53) | (1<<7)); ++ ++ write_nic_byte(dev,RFPinsSelect+1,4); ++ ++ write_nic_byte(dev,GPIO,0x20); ++ ++ write_nic_byte(dev,GP_ENABLE,0); ++ ++ ++ /* Config BB & RF */ ++ write_nic_word(dev, RFPinsOutput, 0x80); ++ ++ write_nic_word(dev, RFPinsSelect, 0x80); ++ ++ write_nic_word(dev, RFPinsEnable, 0x80); ++ ++ ++ mdelay(100); ++ ++ mdelay(1000); ++ ++} ++#endif ++void rtl8225z2_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int i; ++ short channel = 1; ++ u16 brsr; ++ u32 data,addr; ++ ++ priv->chan = channel; ++ ++// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++ ++ ++ if(priv->card_type == USB) ++ rtl8225_host_usb_init(dev); ++ else ++ rtl8225_host_pci_init(dev); ++ ++ write_nic_dword(dev, RF_TIMING, 0x000a8008); ++ ++ brsr = read_nic_word(dev, BRSR); ++ ++ write_nic_word(dev, BRSR, 0xffff); ++ ++ ++ write_nic_dword(dev, RF_PARA, 0x100044); ++ ++ #if 1 //0->1 ++ rtl8180_set_mode(dev, EPROM_CMD_CONFIG); ++ write_nic_byte(dev, CONFIG3, 0x44); ++ rtl8180_set_mode(dev, EPROM_CMD_NORMAL); ++ #endif ++ ++ ++ rtl8185_rf_pins_enable(dev); ++ ++// mdelay(1000); ++ ++ write_rtl8225(dev, 0x0, 0x2bf); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0x1, 0xee0); mdelay(1); ++ ++ write_rtl8225(dev, 0x2, 0x44d); mdelay(1); ++ ++ write_rtl8225(dev, 0x3, 0x441); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0x4, 0x8c3);mdelay(1); ++ ++ ++ ++ write_rtl8225(dev, 0x5, 0xc72);mdelay(1); ++// } ++ ++ write_rtl8225(dev, 0x6, 0xe6); mdelay(1); ++ ++ write_rtl8225(dev, 0x7, ((priv->card_type == USB)? 0x82a : rtl8225_chan[channel])); mdelay(1); ++ ++ write_rtl8225(dev, 0x8, 0x3f); mdelay(1); ++ ++ write_rtl8225(dev, 0x9, 0x335); mdelay(1); ++ ++ write_rtl8225(dev, 0xa, 0x9d4); mdelay(1); ++ ++ write_rtl8225(dev, 0xb, 0x7bb); mdelay(1); ++ ++ write_rtl8225(dev, 0xc, 0x850); mdelay(1); ++ ++ ++ write_rtl8225(dev, 0xd, 0xcdf); mdelay(1); ++ ++ write_rtl8225(dev, 0xe, 0x2b); mdelay(1); ++ ++ write_rtl8225(dev, 0xf, 0x114); ++ ++ ++ mdelay(100); ++ ++ ++ //if(priv->card_type != USB) /* maybe not needed even for 8185 */ ++// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++ ++ write_rtl8225(dev, 0x0, 0x1b7); ++ ++ for(i=0;i<95;i++){ ++ write_rtl8225(dev, 0x1, (u8)(i+1)); ++ ++ #if 0 ++ if(priv->phy_ver == 1) ++ /* version A */ ++ write_rtl8225(dev, 0x2, rtl8225a_rxgain[i]); ++ else ++ #endif ++ /* version B & C & D*/ ++ ++ write_rtl8225(dev, 0x2, rtl8225z2_rxgain[i]); ++ } ++ write_rtl8225(dev, 0x3, 0x80); ++ write_rtl8225(dev, 0x5, 0x4); ++ ++ write_rtl8225(dev, 0x0, 0xb7); ++ ++ write_rtl8225(dev, 0x2, 0xc4d); ++ ++ if(priv->card_type == USB){ ++ // force_pci_posting(dev); ++ mdelay(200); ++ ++ write_rtl8225(dev, 0x2, 0x44d); ++ ++ // force_pci_posting(dev); ++ mdelay(100); ++ ++ }//End of if(priv->card_type == USB) ++ /* FIXME!! rtl8187 we have to check if calibrarion ++ * is successful and eventually cal. again (repeat ++ * the two write on reg 2) ++ */ ++ // Check for calibration status, 2005.11.17, ++ data = read_rtl8225(dev, 6); ++ if (!(data&0x00000080)) ++ { ++ write_rtl8225(dev, 0x02, 0x0c4d); ++ force_pci_posting(dev); mdelay(200); ++ write_rtl8225(dev, 0x02, 0x044d); ++ force_pci_posting(dev); mdelay(100); ++ data = read_rtl8225(dev, 6); ++ if (!(data&0x00000080)) ++ { ++ DMESGW("RF Calibration Failed!!!!\n"); ++ } ++ } ++ //force_pci_posting(dev); ++ ++ mdelay(200); //200 for 8187 ++ ++ ++// //if(priv->card_type != USB){ ++// write_rtl8225(dev, 0x2, 0x44d); ++// write_rtl8225(dev, 0x7, rtl8225_chan[channel]); ++// write_rtl8225(dev, 0x2, 0x47d); ++// ++// force_pci_posting(dev); ++// mdelay(100); ++// ++// write_rtl8225(dev, 0x2, 0x44d); ++// //} ++ ++ write_rtl8225(dev, 0x0, 0x2bf); ++ ++ if(priv->card_type != USB) ++ rtl8185_rf_pins_enable(dev); ++ //set up ZEBRA AGC table, 2005.11.17, ++ for(i=0;i<128;i++){ ++ data = rtl8225_agc[i]; ++ ++ addr = i + 0x80; //enable writing AGC table ++ write_phy_ofdm(dev, 0xb, data); ++ ++ mdelay(1); ++ write_phy_ofdm(dev, 0xa, addr); ++ ++ mdelay(1); ++ } ++#if 0 ++ for(i=0;i<128;i++){ ++ write_phy_ofdm(dev, 0xb, rtl8225_agc[i]); ++ ++ mdelay(1); ++ write_phy_ofdm(dev, 0xa, (u8)i+ 0x80); ++ ++ mdelay(1); ++ } ++#endif ++ ++ force_pci_posting(dev); ++ mdelay(1); ++ ++ write_phy_ofdm(dev, 0x0, 0x1); mdelay(1); ++ write_phy_ofdm(dev, 0x1, 0x2); mdelay(1); ++ write_phy_ofdm(dev, 0x2, ((priv->card_type == USB)? 0x42 : 0x62)); mdelay(1); ++ write_phy_ofdm(dev, 0x3, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x4, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x5, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x6, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x7, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x8, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x9, 0xfe); mdelay(1); ++ ++ write_phy_ofdm(dev, 0xa, 0x8); mdelay(1); ++ ++ //write_phy_ofdm(dev, 0x18, 0xef); ++ // } ++ //} ++ write_phy_ofdm(dev, 0xb, 0x80); mdelay(1); ++ ++ write_phy_ofdm(dev, 0xc, 0x1);mdelay(1); ++ ++ ++ //if(priv->card_type != USB) ++ write_phy_ofdm(dev, 0xd, 0x43); ++ ++ write_phy_ofdm(dev, 0xe, 0xd3);mdelay(1); ++ ++ ++ #if 0 ++ if(priv->card_8185 == 1){ ++ if(priv->card_8185_Bversion) ++ write_phy_ofdm(dev, 0xf, 0x20);/*ver B*/ ++ else ++ write_phy_ofdm(dev, 0xf, 0x28);/*ver C*/ ++ }else{ ++ #endif ++ write_phy_ofdm(dev, 0xf, 0x38);mdelay(1); ++/*ver D & 8187*/ ++// } ++ ++// if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++// write_phy_ofdm(dev, 0x10, 0x04);/*ver B*/ ++// else ++ write_phy_ofdm(dev, 0x10, 0x84);mdelay(1); ++/*ver C & D & 8187*/ ++ ++ write_phy_ofdm(dev, 0x11, 0x07);mdelay(1); ++/*agc resp time 700*/ ++ ++ ++// if(priv->card_8185 == 2){ ++ /* Ver D & 8187*/ ++ write_phy_ofdm(dev, 0x12, 0x20);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x13, 0x20);mdelay(1); ++ ++#if 0 ++ }else{ ++ /* Ver B & C*/ ++ write_phy_ofdm(dev, 0x12, 0x0); ++ write_phy_ofdm(dev, 0x13, 0x0); ++ } ++#endif ++ write_phy_ofdm(dev, 0x14, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); ++ write_phy_ofdm(dev, 0x16, 0x0); mdelay(1); ++ write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); ++ ++// if (priv->card_type == USB) ++// write_phy_ofdm(dev, 0x18, 0xef); ++ ++ write_phy_ofdm(dev, 0x18, 0xef);mdelay(1); ++ ++ ++ write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); ++ write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); ++ write_phy_ofdm(dev, 0x1b, 0x15);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1c, 0x4);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1d, 0xc5);mdelay(1); //2005.11.17, ++ ++ write_phy_ofdm(dev, 0x1e, 0x95);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); ++ ++// } ++ ++ write_phy_ofdm(dev, 0x20, 0x1f);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x21, 0x17);mdelay(1); ++ ++ write_phy_ofdm(dev, 0x22, 0x16);mdelay(1); ++ ++// if(priv->card_type != USB) ++ write_phy_ofdm(dev, 0x23, 0x80);mdelay(1); //FIXME maybe not needed // <> ++ ++ write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0x25, 0x00); mdelay(1); ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); ++ ++ write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); ++ ++ ++ // <> Set init. gain to m74dBm. ++ ++ rtl8225z2_set_gain(dev,4); ++ ++ write_phy_cck(dev, 0x0, 0x98); mdelay(1); ++ write_phy_cck(dev, 0x3, 0x20); mdelay(1); ++ write_phy_cck(dev, 0x4, 0x7e); mdelay(1); ++ write_phy_cck(dev, 0x5, 0x12); mdelay(1); ++ write_phy_cck(dev, 0x6, 0xfc); mdelay(1); ++ ++ write_phy_cck(dev, 0x7, 0x78);mdelay(1); ++ /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x8, 0x2e);mdelay(1); ++ ++ write_phy_cck(dev, 0x10, ((priv->card_type == USB) ? 0x9b: 0x93)); mdelay(1); ++ write_phy_cck(dev, 0x11, 0x88); mdelay(1); ++ write_phy_cck(dev, 0x12, 0x47); mdelay(1); ++#if 0 ++ if(priv->card_8185 == 1 && priv->card_8185_Bversion) ++ write_phy_cck(dev, 0x13, 0x98); /* Ver B */ ++ else ++#endif ++ write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x19, 0x0); ++ write_phy_cck(dev, 0x1a, 0xa0); ++ write_phy_cck(dev, 0x1b, 0x8); ++ write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ ++ ++ write_phy_cck(dev, 0x41, 0x8d);mdelay(1); ++ ++ ++ write_phy_cck(dev, 0x42, 0x15); mdelay(1); ++ write_phy_cck(dev, 0x43, 0x18); mdelay(1); ++ ++ ++ write_phy_cck(dev, 0x44, 0x36); mdelay(1); ++ write_phy_cck(dev, 0x45, 0x35); mdelay(1); ++ write_phy_cck(dev, 0x46, 0x2e); mdelay(1); ++ write_phy_cck(dev, 0x47, 0x25); mdelay(1); ++ write_phy_cck(dev, 0x48, 0x1c); mdelay(1); ++ write_phy_cck(dev, 0x49, 0x12); mdelay(1); ++ write_phy_cck(dev, 0x4a, 0x9); mdelay(1); ++ write_phy_cck(dev, 0x4b, 0x4); mdelay(1); ++ write_phy_cck(dev, 0x4c, 0x5);mdelay(1); ++ ++ ++ write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); ++ ++ ++ ++// <> ++// // TESTR 0xb 8187 ++// write_phy_cck(dev, 0x10, 0x93);// & 0xfb); ++// ++// //if(priv->card_type != USB){ ++// write_phy_ofdm(dev, 0x2, 0x62); ++// write_phy_ofdm(dev, 0x6, 0x0); ++// write_phy_ofdm(dev, 0x8, 0x0); ++// //} ++ ++ rtl8225z2_SetTXPowerLevel(dev, channel); ++#ifdef CONFIG_RTL818X_S ++ write_phy_cck(dev, 0x11, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ ++#else ++ write_phy_cck(dev, 0x10, 0x9b); mdelay(1); /* Rx ant A, 0xdb for B */ ++#endif ++ write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* Rx ant A, 0x10 for B */ ++ ++ rtl8185_tx_antenna(dev, 0x3); /* TX ant A, 0x0 for B */ ++ ++ /* switch to high-speed 3-wire ++ * last digit. 2 for both cck and ofdm ++ */ ++ if(priv->card_type == USB) ++ write_nic_dword(dev, 0x94, 0x3dc00002); ++ else{ ++ write_nic_dword(dev, 0x94, 0x15c00002); ++ rtl8185_rf_pins_enable(dev); ++ } ++ ++// if(priv->card_type != USB) ++// rtl8225_set_gain(dev, 4); /* FIXME this '1' is random */ // <> ++// rtl8225_set_mode(dev, 1); /* FIXME start in B mode */ // <> ++// ++// /* make sure is waken up! */ ++// write_rtl8225(dev,0x4, 0x9ff); ++// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_ON); ++// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_ON); ++ ++ rtl8225_rf_set_chan(dev, priv->chan); ++ ++ //write_nic_word(dev,BRSR,brsr); ++ ++ //rtl8225z2_rf_set_mode(dev); ++} ++ ++void rtl8225z2_rf_set_mode(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->mode == IEEE_A) ++ { ++ write_rtl8225(dev, 0x5, 0x1865); ++ write_nic_dword(dev, RF_PARA, 0x10084); ++ write_nic_dword(dev, RF_TIMING, 0xa8008); ++ write_phy_ofdm(dev, 0x0, 0x0); ++ write_phy_ofdm(dev, 0xa, 0x6); ++ write_phy_ofdm(dev, 0xb, 0x99); ++ write_phy_ofdm(dev, 0xf, 0x20); ++ write_phy_ofdm(dev, 0x11, 0x7); ++ ++ rtl8225z2_set_gain(dev,4); ++ ++ write_phy_ofdm(dev,0x15, 0x40); ++ write_phy_ofdm(dev,0x17, 0x40); ++ ++ write_nic_dword(dev, 0x94,0x10000000); ++ }else{ ++ ++ write_rtl8225(dev, 0x5, 0x1864); ++ write_nic_dword(dev, RF_PARA, 0x10044); ++ write_nic_dword(dev, RF_TIMING, 0xa8008); ++ write_phy_ofdm(dev, 0x0, 0x1); ++ write_phy_ofdm(dev, 0xa, 0x6); ++ write_phy_ofdm(dev, 0xb, 0x99); ++ write_phy_ofdm(dev, 0xf, 0x20); ++ write_phy_ofdm(dev, 0x11, 0x7); ++ ++ rtl8225z2_set_gain(dev,4); ++ ++ write_phy_ofdm(dev,0x15, 0x40); ++ write_phy_ofdm(dev,0x17, 0x40); ++ ++ write_nic_dword(dev, 0x94,0x04000002); ++ } ++} ++ ++//lzm mod 080826 ++//#define MAX_DOZE_WAITING_TIMES_85B 64 ++//#define MAX_POLLING_24F_TIMES_87SE 5 ++#define MAX_DOZE_WAITING_TIMES_85B 20 ++#define MAX_POLLING_24F_TIMES_87SE 10 ++#define LPS_MAX_SLEEP_WAITING_TIMES_87SE 5 ++ ++bool ++SetZebraRFPowerState8185( ++ struct net_device *dev, ++ RT_RF_POWER_STATE eRFPowerState ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 btCR9346, btConfig3; ++ bool bActionAllowed= true, bTurnOffBB = true;//lzm mod 080826 ++ //u32 DWordContent; ++ u8 u1bTmp; ++ int i; ++ //u16 u2bTFPC = 0; ++ bool bResult = true; ++ u8 QueueID; ++ ++ if(priv->SetRFPowerStateInProgress == true) ++ return false; ++ ++ priv->SetRFPowerStateInProgress = true; ++ ++ // enable EEM0 and EEM1 in 9346CR ++ btCR9346 = read_nic_byte(dev, CR9346); ++ write_nic_byte(dev, CR9346, (btCR9346|0xC0) ); ++ // enable PARM_En in Config3 ++ btConfig3 = read_nic_byte(dev, CONFIG3); ++ write_nic_byte(dev, CONFIG3, (btConfig3|CONFIG3_PARM_En) ); ++ ++ switch( priv->rf_chip ) ++ { ++ case RF_ZEBRA2: ++ switch( eRFPowerState ) ++ { ++ case eRfOn: ++ RF_WriteReg(dev,0x4,0x9FF); ++ ++ write_nic_dword(dev, ANAPARAM, ANAPARM_ON); ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_ON); ++ ++ write_nic_byte(dev, CONFIG4, priv->RFProgType); ++ ++ //Follow 87B, Isaiah 2007-04-27 ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5|BIT6))) );// 070124 SD1 Alex: turn on CCK and OFDM. ++ break; ++ ++ case eRfSleep: ++ break; ++ ++ case eRfOff: ++ break; ++ ++ default: ++ bResult = false; ++ break; ++ } ++ break; ++ ++ case RF_ZEBRA4: ++ switch( eRFPowerState ) ++ { ++ case eRfOn: ++ //printk("===================================power on@jiffies:%d\n",jiffies); ++ write_nic_word(dev, 0x37C, 0x00EC); ++ ++ //turn on AFE ++ write_nic_byte(dev, 0x54, 0x00); ++ write_nic_byte(dev, 0x62, 0x00); ++ ++ //lzm mod 080826 ++ //turn on RF ++ //RF_WriteReg(dev, 0x0, 0x009f); //mdelay(1); ++ //RF_WriteReg(dev, 0x4, 0x0972); //mdelay(1); ++ RF_WriteReg(dev, 0x0, 0x009f); udelay(500); ++ RF_WriteReg(dev, 0x4, 0x0972); udelay(500); ++ //turn on RF again, suggested by SD3 stevenl. ++ RF_WriteReg(dev, 0x0, 0x009f); udelay(500); ++ RF_WriteReg(dev, 0x4, 0x0972); udelay(500); ++ ++ //turn on BB ++// write_nic_dword(dev, PhyAddr, 0x4090); //ofdm 10=00 ++// write_nic_dword(dev, PhyAddr, 0x4092); //ofdm 12=00 ++ write_phy_ofdm(dev,0x10,0x40); ++ write_phy_ofdm(dev,0x12,0x40); ++ //Avoid power down at init time. ++ write_nic_byte(dev, CONFIG4, priv->RFProgType); ++ ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5|BIT6))) ); ++ ++ break; ++ ++ case eRfSleep: ++ // Make sure BusyQueue is empty befor turn off RFE pwoer. ++ //printk("===================================power sleep@jiffies:%d\n",jiffies); ++ ++ for(QueueID = 0, i = 0; QueueID < 6; ) ++ { ++ if(get_curr_tx_free_desc(dev,QueueID) == priv->txringcount) ++ { ++ QueueID++; ++ continue; ++ } ++#if 0 //reserved amy ++ else if(priv->NdisAdapter.CurrentPowerState != NdisDeviceStateD0) ++ { ++ RT_TRACE(COMP_POWER, DBG_LOUD, ("eRfSleep: %d times TcbBusyQueue[%d] !=0 but lower power state!\n", (pMgntInfo->TxPollingTimes+1), QueueID)); ++ break; ++ } ++#endif ++ else//lzm mod 080826 ++ { ++ priv->TxPollingTimes ++; ++ if(priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) ++ { ++ //RT_TRACE(COMP_POWER, DBG_WARNING, ("\n\n\n SetZebraRFPowerState8185B():eRfSleep: %d times TcbBusyQueue[%d] != 0 !!!\n\n\n", LPS_MAX_SLEEP_WAITING_TIMES_87SE, QueueID)); ++ bActionAllowed=false; ++ break; ++ } ++ else ++ { ++ udelay(10); // Windows may delay 3~16ms actually. ++ //RT_TRACE(COMP_POWER, DBG_LOUD, ("eRfSleep: %d times TcbBusyQueue[%d] !=0 before doze!\n", (pMgntInfo->TxPollingTimes), QueueID)); ++ } ++ } ++ ++ //lzm del 080826 ++ //if(i >= MAX_DOZE_WAITING_TIMES_85B) ++ //{ ++ //printk("\n\n\n SetZebraRFPowerState8185B(): %d times BusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_85B, QueueID); ++ //break; ++ //} ++ } ++ ++ if(bActionAllowed)//lzm add 080826 ++ { ++ //turn off BB RXIQ matrix to cut off rx signal ++// write_nic_dword(dev, PhyAddr, 0x0090); //ofdm 10=00 ++// write_nic_dword(dev, PhyAddr, 0x0092); //ofdm 12=00 ++ write_phy_ofdm(dev,0x10,0x00); ++ write_phy_ofdm(dev,0x12,0x00); ++ //turn off RF ++ RF_WriteReg(dev, 0x4, 0x0000); //mdelay(1); ++ RF_WriteReg(dev, 0x0, 0x0000); //mdelay(1); ++ //turn off AFE except PLL ++ write_nic_byte(dev, 0x62, 0xff); ++ write_nic_byte(dev, 0x54, 0xec); ++// mdelay(10); ++ ++#if 1 ++ mdelay(1); ++ { ++ int i = 0; ++ while (true) ++ { ++ u8 tmp24F = read_nic_byte(dev, 0x24f); ++ if ((tmp24F == 0x01) || (tmp24F == 0x09)) ++ { ++ bTurnOffBB = true; ++ break; ++ } ++ else//lzm mod 080826 ++ { ++ udelay(10); ++ i++; ++ priv->TxPollingTimes++; ++ ++ if(priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) ++ { ++ //RT_TRACE(COMP_POWER, DBG_WARNING, ("\n\n\n SetZebraRFPowerState8185B(): eRfOff: %d times Rx Mac0x24F=0x%x !!!\n\n\n", i, u1bTmp24F)); ++ bTurnOffBB=false; ++ break; ++ } ++ else ++ { ++ udelay(10);// Windows may delay 3~16ms actually. ++ //RT_TRACE(COMP_POWER, DBG_LOUD,("(%d)eRfSleep- u1bTmp24F= 0x%X\n", i, u1bTmp24F)); ++ ++ } ++ } ++ ++ //lzm del 080826 ++ //if (i > MAX_POLLING_24F_TIMES_87SE) ++ // break; ++ } ++ } ++#endif ++ if (bTurnOffBB)//lzm mod 080826 ++ { ++ //turn off BB ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6)); ++ ++ //turn off AFE PLL ++ //write_nic_byte(dev, 0x54, 0xec); ++ //write_nic_word(dev, 0x37C, 0x00ec); ++ write_nic_byte(dev, 0x54, 0xFC); //[ECS] FC-> EC->FC, asked by SD3 Stevenl ++ write_nic_word(dev, 0x37C, 0x00FC);//[ECS] FC-> EC->FC, asked by SD3 Stevenl ++ } ++ } ++ break; ++ ++ case eRfOff: ++ // Make sure BusyQueue is empty befor turn off RFE pwoer. ++ //printk("===================================power off@jiffies:%d\n",jiffies); ++ for(QueueID = 0, i = 0; QueueID < 6; ) ++ { ++ if(get_curr_tx_free_desc(dev,QueueID) == priv->txringcount) ++ { ++ QueueID++; ++ continue; ++ } ++#if 0 ++ else if(Adapter->NdisAdapter.CurrentPowerState != NdisDeviceStateD0) ++ { ++ RT_TRACE(COMP_POWER, DBG_LOUD, ("%d times TcbBusyQueue[%d] !=0 but lower power state!\n", (i+1), QueueID)); ++ break; ++ } ++#endif ++ else ++ { ++ udelay(10); ++ i++; ++ } ++ ++ if(i >= MAX_DOZE_WAITING_TIMES_85B) ++ { ++ //printk("\n\n\n SetZebraRFPowerState8185B(): %d times BusyQueue[%d] != 0 !!!\n\n\n", MAX_DOZE_WAITING_TIMES_85B, QueueID); ++ break; ++ } ++ } ++ ++ //turn off BB RXIQ matrix to cut off rx signal ++// write_nic_dword(dev, PhyAddr, 0x0090); //ofdm 10=00 ++// write_nic_dword(dev, PhyAddr, 0x0092); //ofdm 12=00 ++ write_phy_ofdm(dev,0x10,0x00); ++ write_phy_ofdm(dev,0x12,0x00); ++ //turn off RF ++ RF_WriteReg(dev, 0x4, 0x0000); //mdelay(1); ++ RF_WriteReg(dev, 0x0, 0x0000); //mdelay(1); ++ //turn off AFE except PLL ++ write_nic_byte(dev, 0x62, 0xff); ++ write_nic_byte(dev, 0x54, 0xec); ++// mdelay(10); ++#if 1 ++ mdelay(1); ++ { ++ int i = 0; ++ while (true) ++ { ++ u8 tmp24F = read_nic_byte(dev, 0x24f); ++ if ((tmp24F == 0x01) || (tmp24F == 0x09)) ++ { ++ bTurnOffBB = true; ++ break; ++ } ++ else ++ { ++ bTurnOffBB = false; ++ udelay(10); ++ i++; ++ } ++ if (i > MAX_POLLING_24F_TIMES_87SE) ++ break; ++ } ++ } ++#endif ++ if (bTurnOffBB)//lzm mod 080826 ++ { ++ ++ //turn off BB ++ u1bTmp = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1bTmp|BIT5|BIT6)); ++ //turn off AFE PLL (80M) ++ //write_nic_byte(dev, 0x54, 0xec); ++ //write_nic_word(dev, 0x37C, 0x00ec); ++ write_nic_byte(dev, 0x54, 0xFC); //[ECS] FC-> EC->FC, asked by SD3 Stevenl ++ write_nic_word(dev, 0x37C, 0x00FC); //[ECS] FC-> EC->FC, asked by SD3 Stevenl ++ } ++ ++ break; ++ ++ default: ++ bResult = false; ++ printk("SetZebraRFPowerState8185(): unknow state to set: 0x%X!!!\n", eRFPowerState); ++ break; ++ } ++ break; ++ } ++ ++ // disable PARM_En in Config3 ++ btConfig3 &= ~(CONFIG3_PARM_En); ++ write_nic_byte(dev, CONFIG3, btConfig3); ++ // disable EEM0 and EEM1 in 9346CR ++ btCR9346 &= ~(0xC0); ++ write_nic_byte(dev, CR9346, btCR9346); ++ ++ if(bResult && bActionAllowed)//lzm mod 080826 ++ { ++ // Update current RF state variable. ++ priv->eRFPowerState = eRFPowerState; ++#if 0 ++ switch(priv->eRFPowerState) ++ { ++ case eRfOff: ++ // ++ //If Rf off reason is from IPS, Led should blink with no link, by Maddest 071015 ++ // ++ if(priv->RfOffReason==RF_CHANGE_BY_IPS ) ++ { ++ Adapter->HalFunc.LedControlHandler(Adapter,LED_CTL_NO_LINK); ++ } ++ else ++ { ++ // Turn off LED if RF is not ON. ++ Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_POWER_OFF); ++ } ++ break; ++ ++ case eRfOn: ++ // Turn on RF we are still linked, which might happen when ++ // we quickly turn off and on HW RF. 2006.05.12, by rcnjko. ++ if( pMgntInfo->bMediaConnect == TRUE ) ++ { ++ Adapter->HalFunc.LedControlHandler(Adapter, LED_CTL_LINK); ++ } ++ break; ++ ++ default: ++ // do nothing. ++ break; ++ } ++#endif ++ ++ } ++ ++ priv->SetRFPowerStateInProgress = false; ++ ++ return (bResult && bActionAllowed) ; ++} ++void rtl8225z4_rf_sleep(struct net_device *dev) ++{ ++ // ++ // Turn off RF power. ++ // ++ //printk("=========>%s()\n", __FUNCTION__); ++ MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS); ++ //mdelay(2); //FIXME ++} ++void rtl8225z4_rf_wakeup(struct net_device *dev) ++{ ++ // ++ // Turn on RF power. ++ // ++ //printk("=========>%s()\n", __FUNCTION__); ++ MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS); ++} ++#endif ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_rtl8255.c +@@ -0,0 +1,1838 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello ++ ++ This files contains programming code for the rtl8255 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#define BAND_A 1 ++#define BAND_BG 2 ++ ++#include "r8180.h" ++#include "r8180_hw.h" ++#include "r8180_rtl8255.h" ++ ++u32 rtl8255_chan[] = { ++ 0, //dummy channel 0 ++ 0x13, //1 ++ 0x115, //2 ++ 0x217, //3 ++ 0x219, //4 ++ 0x31b, //5 ++ 0x41d, //6 ++ 0x41f, //7 ++ 0x621, //8 ++ 0x623, //9 ++ 0x625, //10 ++ 0x627, //11 ++ 0x829, //12 ++ 0x82b, //13 ++ 0x92f, // 14 ++}; ++ ++static short rtl8255_gain_2G[]={ ++ 0x33, 0x17, 0x7c, 0xc5,//-78 ++ 0x43, 0x17, 0x7a, 0xc5,//-74 ++ 0x53, 0x17, 0x78, 0xc5,//-70 ++ 0x63, 0x17, 0x76, 0xc5,//-66 ++}; ++ ++ ++static short rtl8255_agc[]={ ++ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, ++ ++ 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, ++ 0x6, 0x6, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, ++ 0xb, 0xb, 0xc, 0xc, 0xd, 0xd, 0xe, 0xe, 0xf, 0xf, ++ ++ 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, ++ 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, ++ 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, ++ 0x1f, 0x1f, ++ ++ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, ++ 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, ++ 0x2a, 0x2a, ++ ++ 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, ++ 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, ++ 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, ++ 0x2a, 0x2a, 0x2a, 0x2a ++ ++}; ++ ++void rtl8255_set_gain(struct net_device *dev, short gain) ++{ ++ ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ write_phy_ofdm(dev, 0x0d, rtl8255_gain_2G[gain * 4]); ++ write_phy_ofdm(dev, 0x23, rtl8255_gain_2G[gain * 4 + 1]); ++ write_phy_ofdm(dev, 0x1b, rtl8255_gain_2G[gain * 4 + 2]); ++ write_phy_ofdm(dev, 0x1d, rtl8255_gain_2G[gain * 4 + 3]); ++ //rtl8225_set_gain_usb(dev, gain); ++} ++ ++void write_rtl8255_reg0c(struct net_device *dev, u32 d1, u32 d2, u32 d3, u32 d4, ++u32 d5, u32 d6, u32 d7, u32 d8, u32 d9, u32 d10) ++{ ++ int i,j; ++ u16 out,select; ++ u8 bit; ++ u32 bangdata; ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ write_nic_word(dev,RFPinsEnable, ++ (read_nic_word(dev,RFPinsEnable) | 0x7)); ++ ++ select = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsSelect, select | 0x7 | SW_CONTROL_GPIO); ++ ++ out = read_nic_word(dev, RFPinsOutput) & 0xfff3; ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); ++ ++ force_pci_posting(dev); ++ udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, out); ++ ++ force_pci_posting(dev); ++ udelay(2); ++ ++ for(j=0;j<10;j++) ++ { ++ switch(j) ++ { ++ case 9: ++ bangdata = d10 | 0x0c; ++ break; ++ case 8: ++ bangdata = d9; ++ break; ++ case 7: ++ bangdata = d8; ++ break; ++ case 6: ++ bangdata = d7; ++ break; ++ case 5: ++ bangdata = d6; ++ break; ++ case 4: ++ bangdata = d5; ++ break; ++ case 3: ++ bangdata = d4; ++ break; ++ case 2: ++ bangdata = d3; ++ break; ++ case 1: ++ bangdata = d2; ++ break; ++ case 0: ++ bangdata = d1; ++ break; ++ default: ++ bangdata=0xbadc0de; /* avoid gcc complaints */ ++ break; ++ } ++ ++ for(i=31; i>=0;i--){ ++ ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ force_pci_posting(dev); ++ udelay(1); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ force_pci_posting(dev); ++ udelay(1); ++ // write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ i--; ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ force_pci_posting(dev); ++ udelay(1); ++ // write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ force_pci_posting(dev); ++ udelay(1); ++ } ++ } ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ force_pci_posting(dev); ++ udelay(10); ++ ++// write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ write_nic_word(dev, RFPinsSelect, select | SW_CONTROL_GPIO); ++// rtl8185_rf_pins_enable(dev); ++ ++} ++ ++void write_rtl8255(struct net_device *dev, u8 adr, u16 data) ++{ ++ int i; ++ u16 out,select; ++ u8 bit; ++ u32 bangdata = (data << 4) | (adr & 0xf); ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ out = read_nic_word(dev, RFPinsOutput) & 0xfff3; ++ ++ write_nic_word(dev,RFPinsEnable, ++ (read_nic_word(dev,RFPinsEnable) | 0x7)); ++ ++ select = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsSelect, select | 0x7 | SW_CONTROL_GPIO); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN );//| 0x1fff); ++ ++ force_pci_posting(dev); ++ udelay(2); ++ ++ write_nic_word(dev, RFPinsOutput, out); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ ++ for(i=15; i>=0;i--){ ++ ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ i--; ++ bit = (bangdata & (1<> i; ++ ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); ++ write_nic_word(dev, RFPinsOutput, bit | out); ++ } ++ ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ ++ force_pci_posting(dev); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); ++ write_nic_word(dev, RFPinsSelect, select | SW_CONTROL_GPIO); ++ ++ rtl8185_rf_pins_enable(dev); ++} ++ ++void rtl8255_rf_close(struct net_device *dev) ++{ ++ ++// rtl8180_set_anaparam(dev, RTL8225_ANAPARAM_OFF); ++// rtl8185_set_anaparam2(dev, RTL8225_ANAPARAM2_OFF); ++} ++ ++void rtl8255_SetTXPowerLevel(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ u8 cck_power_level = 0xff & priv->chtxpwr[ch]; ++ u8 ofdm_power_level = 0xff & priv->chtxpwr_ofdm[ch]; ++ write_nic_byte(dev, TX_GAIN_OFDM, ofdm_power_level); ++ write_nic_byte(dev, TX_GAIN_CCK, cck_power_level); ++ force_pci_posting(dev); ++ mdelay(1); ++ //write_nic_byte(dev, TX_AGC_CONTROL,4); ++} ++#if 0 ++/* switch between mode B and G */ ++void rtl8255_set_mode(struct net_device *dev, short modeb) ++{ ++ write_phy_ofdm(dev, 0x15, (modeb ? 0x0 : 0x40)); ++ write_phy_ofdm(dev, 0x17, (modeb ? 0x0 : 0x40)); ++} ++#endif ++ ++void rtl8255_rf_set_chan(struct net_device *dev, short ch) ++{ ++ //write_rtl8225(dev, 0x7, rtl8225_chan[1]); ++ write_rtl8255(dev, 0x5, 0x65); ++ write_rtl8255(dev, 0x6, rtl8255_chan[ch]); ++ write_rtl8255(dev, 0x7, 0x7c); ++ write_rtl8255(dev, 0x8, 0x6); ++ ++ ++ force_pci_posting(dev); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++// rtl8225_set_mode_B(dev); ++ ++ rtl8255_SetTXPowerLevel(dev, ch); ++ /* FIXME FIXME FIXME */ ++ ++ #if 0 ++ write_nic_byte(dev,DIFS,0xe); //DIFS ++ write_nic_byte(dev,SLOT,0x14); //SLOT ++ write_nic_byte(dev,EIFS,0x5b); // EIFS ++ //write_nic_byte(dev,0xbc,0); //CW CONFIG ++ write_nic_byte(dev,0xbd,0xa4); //CW VALUE ++ //write_nic_byte(dev,TX_AGC_CONTROL,4); ++ //write_nic_byte(dev, 0x9d,7); ++//Apr 20 13:25:03 localhost kernel: w8. 409d<-7 // CCK AGC ++ /*write_nic_word(dev,0x84,0x488); ++ write_nic_byte(dev,0x91,0x3e); ++ write_nic_byte(dev,0x90,0x30); ++ write_nic_word(dev,0x84,0x488); ++ write_nic_byte(dev,0x91,0x3e); ++ write_nic_byte(dev,0x90,0x20); ++ */ ++ //mdelay(100); ++ #endif ++} ++ ++void rtl8255_init_BGband(struct net_device *dev) ++{ ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804187cf, 0x40000027, ++ 0x92402ac0, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc00); ++ write_rtl8255(dev, 0x4, 0xe00); ++ write_rtl8255(dev, 0x4, 0xc00); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x800); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa00); ++ write_rtl8255(dev, 0x4, 0x800); ++ write_rtl8255(dev, 0x4, 0x400); ++ write_rtl8255(dev, 0x3, 0x26); ++ write_rtl8255(dev, 0x2, 0x27); ++ write_rtl8255(dev, 0x4, 0x600); ++ write_rtl8255(dev, 0x4, 0x400); ++ write_rtl8255(dev, 0x4, 0x400); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x600); ++ write_rtl8255(dev, 0x4, 0x400); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804187ce, 0x80000027, ++ 0x92402ac0, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc01); ++ write_rtl8255(dev, 0x4, 0xe01); ++ write_rtl8255(dev, 0x4, 0xc01); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x801); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa01); ++ write_rtl8255(dev, 0x4, 0x801); ++ write_rtl8255(dev, 0x4, 0x401); ++ write_rtl8255(dev, 0x3, 0x26); ++ write_rtl8255(dev, 0x2, 0x27); ++ write_rtl8255(dev, 0x4, 0x601); ++ write_rtl8255(dev, 0x4, 0x401); ++ write_rtl8255(dev, 0x4, 0x401); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x601); ++ write_rtl8255(dev, 0x4, 0x401); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80418bdf, 0x40000027, ++ 0x92402ac4, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc02); ++ write_rtl8255(dev, 0x4, 0xe02); ++ write_rtl8255(dev, 0x4, 0xc02); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x802); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa02); ++ write_rtl8255(dev, 0x4, 0x802); ++ write_rtl8255(dev, 0x4, 0x402); ++ write_rtl8255(dev, 0x3, 0x26); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x602); ++ write_rtl8255(dev, 0x4, 0x402); ++ write_rtl8255(dev, 0x4, 0x402); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x602); ++ write_rtl8255(dev, 0x4, 0x402); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80418bbf, 0x40000027, ++ 0x92402ac4, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc03); ++ write_rtl8255(dev, 0x4, 0xe03); ++ write_rtl8255(dev, 0x4, 0xc03); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x803); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa03); ++ write_rtl8255(dev, 0x4, 0x803); ++ write_rtl8255(dev, 0x4, 0x403); ++ write_rtl8255(dev, 0x3, 0x26); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x603); ++ write_rtl8255(dev, 0x4, 0x403); ++ write_rtl8255(dev, 0x4, 0x403); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x603); ++ write_rtl8255(dev, 0x4, 0x403); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80418b9f, 0x40000027, ++ 0x92402ac8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc04); ++ write_rtl8255(dev, 0x4, 0xe04); ++ write_rtl8255(dev, 0x4, 0xc04); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x804); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa04); ++ write_rtl8255(dev, 0x4, 0x804); ++ write_rtl8255(dev, 0x4, 0x404); ++ write_rtl8255(dev, 0x3, 0x26); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x604); ++ write_rtl8255(dev, 0x4, 0x404); ++ write_rtl8255(dev, 0x4, 0x404); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x604); ++ write_rtl8255(dev, 0x4, 0x404); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804183df, 0x40000027, ++ 0x92402ac8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc05); ++ write_rtl8255(dev, 0x4, 0xe05); ++ write_rtl8255(dev, 0x4, 0xc05); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x805); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa05); ++ write_rtl8255(dev, 0x4, 0x805); ++ write_rtl8255(dev, 0x4, 0x405); ++ write_rtl8255(dev, 0x3, 0x26); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x605); ++ write_rtl8255(dev, 0x4, 0x405); ++ write_rtl8255(dev, 0x4, 0x405); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x605); ++ write_rtl8255(dev, 0x4, 0x405); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804183cf, 0x27, ++ 0x92402acc, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc06); ++ write_rtl8255(dev, 0x4, 0xe06); ++ write_rtl8255(dev, 0x4, 0xc06); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x806); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa06); ++ write_rtl8255(dev, 0x4, 0x806); ++ write_rtl8255(dev, 0x4, 0x406); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x606); ++ write_rtl8255(dev, 0x4, 0x406); ++ write_rtl8255(dev, 0x4, 0x406); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x606); ++ write_rtl8255(dev, 0x4, 0x406); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804183af, 0x27, ++ 0x92402acc, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc07); ++ write_rtl8255(dev, 0x4, 0xe07); ++ write_rtl8255(dev, 0x4, 0xc07); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x807); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa07); ++ write_rtl8255(dev, 0x4, 0x807); ++ write_rtl8255(dev, 0x4, 0x407); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x607); ++ write_rtl8255(dev, 0x4, 0x407); ++ write_rtl8255(dev, 0x4, 0x407); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x607); ++ write_rtl8255(dev, 0x4, 0x407); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804083d7, 0x40000027, ++ 0x92402ad0, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc08); ++ write_rtl8255(dev, 0x4, 0xe08); ++ write_rtl8255(dev, 0x4, 0xc08); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x808); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa08); ++ write_rtl8255(dev, 0x4, 0x808); ++ write_rtl8255(dev, 0x4, 0x408); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x608); ++ write_rtl8255(dev, 0x4, 0x408); ++ write_rtl8255(dev, 0x4, 0x408); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x608); ++ write_rtl8255(dev, 0x4, 0x408); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804083c7, 0x27, ++ 0x92402ad0, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc09); ++ write_rtl8255(dev, 0x4, 0xe09); ++ write_rtl8255(dev, 0x4, 0xc09); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x809); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa09); ++ write_rtl8255(dev, 0x4, 0x809); ++ write_rtl8255(dev, 0x4, 0x409); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x609); ++ write_rtl8255(dev, 0x4, 0x409); ++ write_rtl8255(dev, 0x4, 0x409); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x609); ++ write_rtl8255(dev, 0x4, 0x409); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043d7, 0x40000027, ++ 0x92402ad4, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc0a); ++ write_rtl8255(dev, 0x4, 0xe0a); ++ write_rtl8255(dev, 0x4, 0xc0a); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x80a); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa0a); ++ write_rtl8255(dev, 0x4, 0x80a); ++ write_rtl8255(dev, 0x4, 0x40a); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x60a); ++ write_rtl8255(dev, 0x4, 0x40a); ++ write_rtl8255(dev, 0x4, 0x40a); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x60a); ++ write_rtl8255(dev, 0x4, 0x40a); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043d7, 0x40000027, ++ 0x92402ad4, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc0b); ++ write_rtl8255(dev, 0x4, 0xe0b); ++ write_rtl8255(dev, 0x4, 0xc0b); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x80b); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa0b); ++ write_rtl8255(dev, 0x4, 0x80b); ++ write_rtl8255(dev, 0x4, 0x40b); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x60b); ++ write_rtl8255(dev, 0x4, 0x40b); ++ write_rtl8255(dev, 0x4, 0x40b); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x60b); ++ write_rtl8255(dev, 0x4, 0x40b); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043c7, 0x27, ++ 0x92402ad8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc0c); ++ write_rtl8255(dev, 0x4, 0xe0c); ++ write_rtl8255(dev, 0x4, 0xc0c); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x80c); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa0c); ++ write_rtl8255(dev, 0x4, 0x80c); ++ write_rtl8255(dev, 0x4, 0x40c); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x60c); ++ write_rtl8255(dev, 0x4, 0x40c); ++ write_rtl8255(dev, 0x4, 0x40c); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x60c); ++ write_rtl8255(dev, 0x4, 0x40c); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804043a7, 0x27, ++ 0x92402ad8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc0d); ++ write_rtl8255(dev, 0x4, 0xe0d); ++ write_rtl8255(dev, 0x4, 0xc0d); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x80d); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa0d); ++ write_rtl8255(dev, 0x4, 0x80d); ++ write_rtl8255(dev, 0x4, 0x40d); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x60d); ++ write_rtl8255(dev, 0x4, 0x40d); ++ write_rtl8255(dev, 0x4, 0x40d); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x60d); ++ write_rtl8255(dev, 0x4, 0x40d); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404387, 0x27, ++ 0x92402aa8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc0e); ++ write_rtl8255(dev, 0x4, 0xe0e); ++ write_rtl8255(dev, 0x4, 0xc0e); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x80e); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa0e); ++ write_rtl8255(dev, 0x4, 0x80e); ++ write_rtl8255(dev, 0x4, 0x40e); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x60e); ++ write_rtl8255(dev, 0x4, 0x40e); ++ write_rtl8255(dev, 0x4, 0x40e); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x60e); ++ write_rtl8255(dev, 0x4, 0x40e); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804041c7, 0x27, ++ 0x92402aa8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc0f); ++ write_rtl8255(dev, 0x4, 0xe0f); ++ write_rtl8255(dev, 0x4, 0xc0f); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x80f); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa0f); ++ write_rtl8255(dev, 0x4, 0x80f); ++ write_rtl8255(dev, 0x4, 0x40f); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x60f); ++ write_rtl8255(dev, 0x4, 0x40f); ++ write_rtl8255(dev, 0x4, 0x40f); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x60f); ++ write_rtl8255(dev, 0x4, 0x40f); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x804041a7, 0x27, ++ 0x92402aac, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc10); ++ write_rtl8255(dev, 0x4, 0xe10); ++ write_rtl8255(dev, 0x4, 0xc10); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x810); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa10); ++ write_rtl8255(dev, 0x4, 0x810); ++ write_rtl8255(dev, 0x4, 0x410); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x610); ++ write_rtl8255(dev, 0x4, 0x410); ++ write_rtl8255(dev, 0x4, 0x410); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x610); ++ write_rtl8255(dev, 0x4, 0x410); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404187, 0x27, ++ 0x92402aac, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc11); ++ write_rtl8255(dev, 0x4, 0xe11); ++ write_rtl8255(dev, 0x4, 0xc11); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x811); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa11); ++ write_rtl8255(dev, 0x4, 0x811); ++ write_rtl8255(dev, 0x4, 0x411); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x611); ++ write_rtl8255(dev, 0x4, 0x411); ++ write_rtl8255(dev, 0x4, 0x411); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x611); ++ write_rtl8255(dev, 0x4, 0x411); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404186, 0x80000027, ++ 0x92402ab0, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc12); ++ write_rtl8255(dev, 0x4, 0xe12); ++ write_rtl8255(dev, 0x4, 0xc12); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x812); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa12); ++ write_rtl8255(dev, 0x4, 0x812); ++ write_rtl8255(dev, 0x4, 0x412); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x612); ++ write_rtl8255(dev, 0x4, 0x412); ++ write_rtl8255(dev, 0x4, 0x412); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x612); ++ write_rtl8255(dev, 0x4, 0x412); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404186, 0x27, ++ 0x92402ab0, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc13); ++ write_rtl8255(dev, 0x4, 0xe13); ++ write_rtl8255(dev, 0x4, 0xc13); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x813); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa13); ++ write_rtl8255(dev, 0x4, 0x813); ++ write_rtl8255(dev, 0x4, 0x413); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x613); ++ write_rtl8255(dev, 0x4, 0x413); ++ write_rtl8255(dev, 0x4, 0x413); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x613); ++ write_rtl8255(dev, 0x4, 0x413); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404146, 0x27, ++ 0x92402ab4, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc14); ++ write_rtl8255(dev, 0x4, 0xe14); ++ write_rtl8255(dev, 0x4, 0xc14); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x814); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa14); ++ write_rtl8255(dev, 0x4, 0x814); ++ write_rtl8255(dev, 0x4, 0x414); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x614); ++ write_rtl8255(dev, 0x4, 0x414); ++ write_rtl8255(dev, 0x4, 0x414); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x614); ++ write_rtl8255(dev, 0x4, 0x414); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404126, 0x27, ++ 0x92402ab4, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc15); ++ write_rtl8255(dev, 0x4, 0xe15); ++ write_rtl8255(dev, 0x4, 0xc15); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x815); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa15); ++ write_rtl8255(dev, 0x4, 0x815); ++ write_rtl8255(dev, 0x4, 0x415); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x615); ++ write_rtl8255(dev, 0x4, 0x415); ++ write_rtl8255(dev, 0x4, 0x415); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x615); ++ write_rtl8255(dev, 0x4, 0x415); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404106, 0x27, ++ 0x92402ab8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc16); ++ write_rtl8255(dev, 0x4, 0xe16); ++ write_rtl8255(dev, 0x4, 0xc16); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x816); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa16); ++ write_rtl8255(dev, 0x4, 0x816); ++ write_rtl8255(dev, 0x4, 0x416); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x616); ++ write_rtl8255(dev, 0x4, 0x416); ++ write_rtl8255(dev, 0x4, 0x416); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x616); ++ write_rtl8255(dev, 0x4, 0x416); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404105, 0x27, ++ 0x92402ab8, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc17); ++ write_rtl8255(dev, 0x4, 0xe17); ++ write_rtl8255(dev, 0x4, 0xc17); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x817); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa17); ++ write_rtl8255(dev, 0x4, 0x817); ++ write_rtl8255(dev, 0x4, 0x417); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x617); ++ write_rtl8255(dev, 0x4, 0x417); ++ write_rtl8255(dev, 0x4, 0x417); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x617); ++ write_rtl8255(dev, 0x4, 0x417); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404104, 0x80000027, ++ 0x92402a88, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc18); ++ write_rtl8255(dev, 0x4, 0xe18); ++ write_rtl8255(dev, 0x4, 0xc18); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x818); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa18); ++ write_rtl8255(dev, 0x4, 0x818); ++ write_rtl8255(dev, 0x4, 0x418); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x618); ++ write_rtl8255(dev, 0x4, 0x418); ++ write_rtl8255(dev, 0x4, 0x418); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x618); ++ write_rtl8255(dev, 0x4, 0x418); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404104, 0x27, ++ 0x92402a88, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc19); ++ write_rtl8255(dev, 0x4, 0xe19); ++ write_rtl8255(dev, 0x4, 0xc19); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x819); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa19); ++ write_rtl8255(dev, 0x4, 0x819); ++ write_rtl8255(dev, 0x4, 0x419); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x619); ++ write_rtl8255(dev, 0x4, 0x419); ++ write_rtl8255(dev, 0x4, 0x419); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x619); ++ write_rtl8255(dev, 0x4, 0x419); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404044, 0x27, ++ 0x92402a8c, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc1a); ++ write_rtl8255(dev, 0x4, 0xe1a); ++ write_rtl8255(dev, 0x4, 0xc1a); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x81a); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa1a); ++ write_rtl8255(dev, 0x4, 0x81a); ++ write_rtl8255(dev, 0x4, 0x41a); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x61a); ++ write_rtl8255(dev, 0x4, 0x41a); ++ write_rtl8255(dev, 0x4, 0x41a); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x61a); ++ write_rtl8255(dev, 0x4, 0x41a); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404024, 0x27, ++ 0x92402a8c, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc1b); ++ write_rtl8255(dev, 0x4, 0xe1b); ++ write_rtl8255(dev, 0x4, 0xc1b); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x81b); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa1b); ++ write_rtl8255(dev, 0x4, 0x81b); ++ write_rtl8255(dev, 0x4, 0x41b); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x61b); ++ write_rtl8255(dev, 0x4, 0x41b); ++ write_rtl8255(dev, 0x4, 0x41b); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x61b); ++ write_rtl8255(dev, 0x4, 0x41b); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404004, 0x27, ++ 0x92402a90, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc1c); ++ write_rtl8255(dev, 0x4, 0xe1c); ++ write_rtl8255(dev, 0x4, 0xc1c); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x81c); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa1c); ++ write_rtl8255(dev, 0x4, 0x81c); ++ write_rtl8255(dev, 0x4, 0x41c); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x61c); ++ write_rtl8255(dev, 0x4, 0x41c); ++ write_rtl8255(dev, 0x4, 0x41c); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x61c); ++ write_rtl8255(dev, 0x4, 0x41c); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404001, 0x27, ++ 0x92402a90, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc1d); ++ write_rtl8255(dev, 0x4, 0xe1d); ++ write_rtl8255(dev, 0x4, 0xc1d); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x81d); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa1d); ++ write_rtl8255(dev, 0x4, 0x81d); ++ write_rtl8255(dev, 0x4, 0x41d); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x61d); ++ write_rtl8255(dev, 0x4, 0x41d); ++ write_rtl8255(dev, 0x4, 0x41d); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x61d); ++ write_rtl8255(dev, 0x4, 0x41d); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a94, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc1e); ++ write_rtl8255(dev, 0x4, 0xe1e); ++ write_rtl8255(dev, 0x4, 0xc1e); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x81e); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa1e); ++ write_rtl8255(dev, 0x4, 0x81e); ++ write_rtl8255(dev, 0x4, 0x41e); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x61e); ++ write_rtl8255(dev, 0x4, 0x41e); ++ write_rtl8255(dev, 0x4, 0x41e); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x61e); ++ write_rtl8255(dev, 0x4, 0x41e); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x27, ++ 0x92402a94, 0xf0009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc1f); ++ write_rtl8255(dev, 0x4, 0xe1f); ++ write_rtl8255(dev, 0x4, 0xc1f); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x81f); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa1f); ++ write_rtl8255(dev, 0x4, 0x81f); ++ write_rtl8255(dev, 0x4, 0x41f); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x61f); ++ write_rtl8255(dev, 0x4, 0x41f); ++ write_rtl8255(dev, 0x4, 0x41f); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x61f); ++ write_rtl8255(dev, 0x4, 0x41f); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404020, 0x80000027, ++ 0x92402a98, 0xf8009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc20); ++ write_rtl8255(dev, 0x4, 0xe20); ++ write_rtl8255(dev, 0x4, 0xc20); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x820); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa20); ++ write_rtl8255(dev, 0x4, 0x820); ++ write_rtl8255(dev, 0x4, 0x420); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x620); ++ write_rtl8255(dev, 0x4, 0x420); ++ write_rtl8255(dev, 0x4, 0x420); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x620); ++ write_rtl8255(dev, 0x4, 0x420); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404020, 0x27, ++ 0x92402a98, 0xf8009, 0x28000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc21); ++ write_rtl8255(dev, 0x4, 0xe21); ++ write_rtl8255(dev, 0x4, 0xc21); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x821); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa21); ++ write_rtl8255(dev, 0x4, 0x821); ++ write_rtl8255(dev, 0x4, 0x421); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x621); ++ write_rtl8255(dev, 0x4, 0x421); ++ write_rtl8255(dev, 0x4, 0x421); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x621); ++ write_rtl8255(dev, 0x4, 0x421); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a68, 0xf0009, 0x10028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc22); ++ write_rtl8255(dev, 0x4, 0xe22); ++ write_rtl8255(dev, 0x4, 0xc22); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x822); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa22); ++ write_rtl8255(dev, 0x4, 0x822); ++ write_rtl8255(dev, 0x4, 0x422); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x622); ++ write_rtl8255(dev, 0x4, 0x422); ++ write_rtl8255(dev, 0x4, 0x422); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x622); ++ write_rtl8255(dev, 0x4, 0x422); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0x80000027, ++ 0x92402a68, 0xf0009, 0x20028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc23); ++ write_rtl8255(dev, 0x4, 0xe23); ++ write_rtl8255(dev, 0x4, 0xc23); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x823); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa23); ++ write_rtl8255(dev, 0x4, 0x823); ++ write_rtl8255(dev, 0x4, 0x423); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x623); ++ write_rtl8255(dev, 0x4, 0x423); ++ write_rtl8255(dev, 0x4, 0x423); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x623); ++ write_rtl8255(dev, 0x4, 0x423); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0x80000027, ++ 0x92402a6c, 0xf0009, 0x30028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc24); ++ write_rtl8255(dev, 0x4, 0xe24); ++ write_rtl8255(dev, 0x4, 0xc24); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x824); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa24); ++ write_rtl8255(dev, 0x4, 0x824); ++ write_rtl8255(dev, 0x4, 0x424); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x624); ++ write_rtl8255(dev, 0x4, 0x424); ++ write_rtl8255(dev, 0x4, 0x424); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x624); ++ write_rtl8255(dev, 0x4, 0x424); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0x80000027, ++ 0x92402a6c, 0xf0009, 0x40028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc25); ++ write_rtl8255(dev, 0x4, 0xe25); ++ write_rtl8255(dev, 0x4, 0xc25); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x825); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa25); ++ write_rtl8255(dev, 0x4, 0x825); ++ write_rtl8255(dev, 0x4, 0x425); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x625); ++ write_rtl8255(dev, 0x4, 0x425); ++ write_rtl8255(dev, 0x4, 0x425); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x625); ++ write_rtl8255(dev, 0x4, 0x425); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a70, 0xf0009, 0x60028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc26); ++ write_rtl8255(dev, 0x4, 0xe26); ++ write_rtl8255(dev, 0x4, 0xc26); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x826); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa26); ++ write_rtl8255(dev, 0x4, 0x826); ++ write_rtl8255(dev, 0x4, 0x426); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x626); ++ write_rtl8255(dev, 0x4, 0x426); ++ write_rtl8255(dev, 0x4, 0x426); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x626); ++ write_rtl8255(dev, 0x4, 0x426); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404031, 0x40000027, ++ 0x92402a70, 0xf0011, 0x60028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc27); ++ write_rtl8255(dev, 0x4, 0xe27); ++ write_rtl8255(dev, 0x4, 0xc27); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x827); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa27); ++ write_rtl8255(dev, 0x4, 0x827); ++ write_rtl8255(dev, 0x4, 0x427); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x627); ++ write_rtl8255(dev, 0x4, 0x427); ++ write_rtl8255(dev, 0x4, 0x427); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x627); ++ write_rtl8255(dev, 0x4, 0x427); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404011, 0x40000027, ++ 0x92402a74, 0xf0011, 0x60028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc28); ++ write_rtl8255(dev, 0x4, 0xe28); ++ write_rtl8255(dev, 0x4, 0xc28); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x828); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa28); ++ write_rtl8255(dev, 0x4, 0x828); ++ write_rtl8255(dev, 0x4, 0x428); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x628); ++ write_rtl8255(dev, 0x4, 0x428); ++ write_rtl8255(dev, 0x4, 0x428); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x628); ++ write_rtl8255(dev, 0x4, 0x428); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404010, 0xc0000027, ++ 0x92402a74, 0xf0011, 0x60028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc29); ++ write_rtl8255(dev, 0x4, 0xe29); ++ write_rtl8255(dev, 0x4, 0xc29); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x829); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa29); ++ write_rtl8255(dev, 0x4, 0x829); ++ write_rtl8255(dev, 0x4, 0x429); ++ write_rtl8255(dev, 0x3, 0x25); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x629); ++ write_rtl8255(dev, 0x4, 0x429); ++ write_rtl8255(dev, 0x4, 0x429); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x629); ++ write_rtl8255(dev, 0x4, 0x429); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a78, 0xf0011, 0x60028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc2a); ++ write_rtl8255(dev, 0x4, 0xe2a); ++ write_rtl8255(dev, 0x4, 0xc2a); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x82a); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa2a); ++ write_rtl8255(dev, 0x4, 0x82a); ++ write_rtl8255(dev, 0x4, 0x42a); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x62a); ++ write_rtl8255(dev, 0x4, 0x42a); ++ write_rtl8255(dev, 0x4, 0x42a); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x62a); ++ write_rtl8255(dev, 0x4, 0x42a); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a78, 0xf0011, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc2b); ++ write_rtl8255(dev, 0x4, 0xe2b); ++ write_rtl8255(dev, 0x4, 0xc2b); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x82b); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa2b); ++ write_rtl8255(dev, 0x4, 0x82b); ++ write_rtl8255(dev, 0x4, 0x42b); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x62b); ++ write_rtl8255(dev, 0x4, 0x42b); ++ write_rtl8255(dev, 0x4, 0x42b); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x62b); ++ write_rtl8255(dev, 0x4, 0x42b); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a48, 0xf0019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc2c); ++ write_rtl8255(dev, 0x4, 0xe2c); ++ write_rtl8255(dev, 0x4, 0xc2c); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x82c); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa2c); ++ write_rtl8255(dev, 0x4, 0x82c); ++ write_rtl8255(dev, 0x4, 0x42c); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x62c); ++ write_rtl8255(dev, 0x4, 0x42c); ++ write_rtl8255(dev, 0x4, 0x42c); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x62c); ++ write_rtl8255(dev, 0x4, 0x42c); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a48, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc2d); ++ write_rtl8255(dev, 0x4, 0xe2d); ++ write_rtl8255(dev, 0x4, 0xc2d); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x82d); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa2d); ++ write_rtl8255(dev, 0x4, 0x82d); ++ write_rtl8255(dev, 0x4, 0x42d); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x62d); ++ write_rtl8255(dev, 0x4, 0x42d); ++ write_rtl8255(dev, 0x4, 0x42d); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x62d); ++ write_rtl8255(dev, 0x4, 0x42d); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a4c, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc2e); ++ write_rtl8255(dev, 0x4, 0xe2e); ++ write_rtl8255(dev, 0x4, 0xc2e); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x82e); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa2e); ++ write_rtl8255(dev, 0x4, 0x82e); ++ write_rtl8255(dev, 0x4, 0x42e); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x62e); ++ write_rtl8255(dev, 0x4, 0x42e); ++ write_rtl8255(dev, 0x4, 0x42e); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x62e); ++ write_rtl8255(dev, 0x4, 0x42e); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a4c, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc2f); ++ write_rtl8255(dev, 0x4, 0xe2f); ++ write_rtl8255(dev, 0x4, 0xc2f); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x82f); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa2f); ++ write_rtl8255(dev, 0x4, 0x82f); ++ write_rtl8255(dev, 0x4, 0x42f); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x62f); ++ write_rtl8255(dev, 0x4, 0x42f); ++ write_rtl8255(dev, 0x4, 0x42f); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x62f); ++ write_rtl8255(dev, 0x4, 0x42f); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a50, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc30); ++ write_rtl8255(dev, 0x4, 0xe30); ++ write_rtl8255(dev, 0x4, 0xc30); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x830); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa30); ++ write_rtl8255(dev, 0x4, 0x830); ++ write_rtl8255(dev, 0x4, 0x430); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x630); ++ write_rtl8255(dev, 0x4, 0x430); ++ write_rtl8255(dev, 0x4, 0x430); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x630); ++ write_rtl8255(dev, 0x4, 0x430); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a50, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc31); ++ write_rtl8255(dev, 0x4, 0xe31); ++ write_rtl8255(dev, 0x4, 0xc31); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x831); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa31); ++ write_rtl8255(dev, 0x4, 0x831); ++ write_rtl8255(dev, 0x4, 0x431); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x631); ++ write_rtl8255(dev, 0x4, 0x431); ++ write_rtl8255(dev, 0x4, 0x431); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x631); ++ write_rtl8255(dev, 0x4, 0x431); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a54, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc32); ++ write_rtl8255(dev, 0x4, 0xe32); ++ write_rtl8255(dev, 0x4, 0xc32); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x832); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa32); ++ write_rtl8255(dev, 0x4, 0x832); ++ write_rtl8255(dev, 0x4, 0x432); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x632); ++ write_rtl8255(dev, 0x4, 0x432); ++ write_rtl8255(dev, 0x4, 0x432); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x632); ++ write_rtl8255(dev, 0x4, 0x432); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a54, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc33); ++ write_rtl8255(dev, 0x4, 0xe33); ++ write_rtl8255(dev, 0x4, 0xc33); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x833); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa33); ++ write_rtl8255(dev, 0x4, 0x833); ++ write_rtl8255(dev, 0x4, 0x433); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x633); ++ write_rtl8255(dev, 0x4, 0x433); ++ write_rtl8255(dev, 0x4, 0x433); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x633); ++ write_rtl8255(dev, 0x4, 0x433); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a58, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc34); ++ write_rtl8255(dev, 0x4, 0xe34); ++ write_rtl8255(dev, 0x4, 0xc34); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x834); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa34); ++ write_rtl8255(dev, 0x4, 0x834); ++ write_rtl8255(dev, 0x4, 0x434); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x634); ++ write_rtl8255(dev, 0x4, 0x434); ++ write_rtl8255(dev, 0x4, 0x434); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x634); ++ write_rtl8255(dev, 0x4, 0x434); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a58, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc35); ++ write_rtl8255(dev, 0x4, 0xe35); ++ write_rtl8255(dev, 0x4, 0xc35); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x835); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa35); ++ write_rtl8255(dev, 0x4, 0x835); ++ write_rtl8255(dev, 0x4, 0x435); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x4, 0x635); ++ write_rtl8255(dev, 0x4, 0x435); ++ write_rtl8255(dev, 0x4, 0x435); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x635); ++ write_rtl8255(dev, 0x4, 0x435); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a24, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc36); ++ write_rtl8255(dev, 0x4, 0xe36); ++ write_rtl8255(dev, 0x4, 0xc36); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x836); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa36); ++ write_rtl8255(dev, 0x4, 0x836); ++ write_rtl8255(dev, 0x4, 0x436); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x25); ++ write_rtl8255(dev, 0x4, 0x636); ++ write_rtl8255(dev, 0x4, 0x436); ++ write_rtl8255(dev, 0x4, 0x436); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x636); ++ write_rtl8255(dev, 0x4, 0x436); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a24, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc37); ++ write_rtl8255(dev, 0x4, 0xe37); ++ write_rtl8255(dev, 0x4, 0xc37); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x837); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa37); ++ write_rtl8255(dev, 0x4, 0x837); ++ write_rtl8255(dev, 0x4, 0x437); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x25); ++ write_rtl8255(dev, 0x4, 0x637); ++ write_rtl8255(dev, 0x4, 0x437); ++ write_rtl8255(dev, 0x4, 0x437); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x637); ++ write_rtl8255(dev, 0x4, 0x437); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a28, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc38); ++ write_rtl8255(dev, 0x4, 0xe38); ++ write_rtl8255(dev, 0x4, 0xc38); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x838); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa38); ++ write_rtl8255(dev, 0x4, 0x838); ++ write_rtl8255(dev, 0x4, 0x438); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x25); ++ write_rtl8255(dev, 0x4, 0x638); ++ write_rtl8255(dev, 0x4, 0x438); ++ write_rtl8255(dev, 0x4, 0x438); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x638); ++ write_rtl8255(dev, 0x4, 0x438); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a28, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc39); ++ write_rtl8255(dev, 0x4, 0xe39); ++ write_rtl8255(dev, 0x4, 0xc39); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x839); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa39); ++ write_rtl8255(dev, 0x4, 0x839); ++ write_rtl8255(dev, 0x4, 0x439); ++ write_rtl8255(dev, 0x3, 0x24); ++ write_rtl8255(dev, 0x2, 0x25); ++ write_rtl8255(dev, 0x4, 0x639); ++ write_rtl8255(dev, 0x4, 0x439); ++ write_rtl8255(dev, 0x4, 0x439); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x639); ++ write_rtl8255(dev, 0x4, 0x439); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc3a); ++ write_rtl8255(dev, 0x4, 0xe3a); ++ write_rtl8255(dev, 0x4, 0xc3a); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x83a); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa3a); ++ write_rtl8255(dev, 0x4, 0x83a); ++ write_rtl8255(dev, 0x4, 0x43a); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0x63a); ++ write_rtl8255(dev, 0x4, 0x43a); ++ write_rtl8255(dev, 0x4, 0x43a); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x63a); ++ write_rtl8255(dev, 0x4, 0x43a); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc3b); ++ write_rtl8255(dev, 0x4, 0xe3b); ++ write_rtl8255(dev, 0x4, 0xc3b); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x83b); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa3b); ++ write_rtl8255(dev, 0x4, 0x83b); ++ write_rtl8255(dev, 0x4, 0x43b); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0x63b); ++ write_rtl8255(dev, 0x4, 0x43b); ++ write_rtl8255(dev, 0x4, 0x43b); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x63b); ++ write_rtl8255(dev, 0x4, 0x43b); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc3c); ++ write_rtl8255(dev, 0x4, 0xe3c); ++ write_rtl8255(dev, 0x4, 0xc3c); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x83c); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa3c); ++ write_rtl8255(dev, 0x4, 0x83c); ++ write_rtl8255(dev, 0x4, 0x43c); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0x63c); ++ write_rtl8255(dev, 0x4, 0x43c); ++ write_rtl8255(dev, 0x4, 0x43c); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x63c); ++ write_rtl8255(dev, 0x4, 0x43c); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc3d); ++ write_rtl8255(dev, 0x4, 0xe3d); ++ write_rtl8255(dev, 0x4, 0xc3d); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x83d); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa3d); ++ write_rtl8255(dev, 0x4, 0x83d); ++ write_rtl8255(dev, 0x4, 0x43d); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0x63d); ++ write_rtl8255(dev, 0x4, 0x43d); ++ write_rtl8255(dev, 0x4, 0x43d); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x63d); ++ write_rtl8255(dev, 0x4, 0x43d); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a00, 0xf8019, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc3e); ++ write_rtl8255(dev, 0x4, 0xe3e); ++ write_rtl8255(dev, 0x4, 0xc3e); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x83e); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa3e); ++ write_rtl8255(dev, 0x4, 0x83e); ++ write_rtl8255(dev, 0x4, 0x43e); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0x63e); ++ write_rtl8255(dev, 0x4, 0x43e); ++ write_rtl8255(dev, 0x4, 0x43e); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x63e); ++ write_rtl8255(dev, 0x4, 0x43e); ++ write_rtl8255_reg0c(dev, 0x1554, 0xa800403b, 0xf6d44278, 0x80404000, 0x80000027, ++ 0x92402a00, 0xf8011, 0x70028000, 0xc00, 0x0); ++ write_rtl8255(dev, 0x1, 0x807); ++ write_rtl8255(dev, 0x4, 0xc3f); ++ write_rtl8255(dev, 0x4, 0xe3f); ++ write_rtl8255(dev, 0x4, 0xc3f); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255(dev, 0x4, 0x83f); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0xa3f); ++ write_rtl8255(dev, 0x4, 0x83f); ++ write_rtl8255(dev, 0x4, 0x43f); ++ write_rtl8255(dev, 0x3, 0x0); ++ write_rtl8255(dev, 0x2, 0x0); ++ write_rtl8255(dev, 0x4, 0x63f); ++ write_rtl8255(dev, 0x4, 0x43f); ++ write_rtl8255(dev, 0x4, 0x43f); ++ write_rtl8255(dev, 0x3, 0x100); ++ write_rtl8255(dev, 0x4, 0x63f); ++ write_rtl8255(dev, 0x4, 0x43f); ++ write_rtl8255(dev, 0x4, 0x0); ++ write_rtl8255(dev, 0x1, 0x0); ++ write_rtl8255_reg0c(dev, 0x3539, 0x70000c03, 0xfef46178, 0x408000, 0x403307, ++ 0x924f80c0, 0xf955c, 0x8400, 0x429200, 0x1ce20); ++ write_rtl8255(dev, 0x1, 0x1c7); ++ write_rtl8255(dev, 0x2, 0x26); ++ write_rtl8255(dev, 0x3, 0x27); ++ write_rtl8255(dev, 0x1, 0x47); ++ write_rtl8255(dev, 0x4, 0x98c); ++ write_rtl8255(dev, 0x5, 0x65); ++ write_rtl8255(dev, 0x6, 0x13); ++ write_rtl8255(dev, 0x7, 0x7c); ++ write_rtl8255(dev, 0x8, 0x6); ++ write_rtl8255(dev, 0x8, 0x7); ++ write_rtl8255(dev, 0x8, 0x6); ++ write_rtl8255(dev, 0x9, 0xce2); ++ write_rtl8255(dev, 0xb, 0x1c5); ++ write_rtl8255(dev, 0xd, 0xd7f); ++ write_rtl8255(dev, 0xe, 0x369); ++ write_rtl8255(dev, 0xa, 0xd56); ++ write_rtl8255(dev, 0xa, 0xd57); ++ mdelay(20); ++ write_rtl8255(dev, 0xd, 0xd7e); ++ ++} ++ ++ ++void rtl8255_set_band_param(struct net_device *dev, short band) ++{ ++ if(band != BAND_A){ ++ write_nic_dword(dev, 0x94, 0x3dc00002); ++ write_nic_dword(dev, 0x88, 0x00100040); ++ ++ write_phy_cck(dev, 0x13, 0xd0); ++ ++ write_phy_cck(dev, 0x41, 0x9d); ++ write_nic_dword(dev, 0x8c, 0x00082205); ++ write_nic_byte(dev, 0xb4, 0x66); ++ } ++} ++ ++void rtl8255_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int i; ++ u16 brsr; ++// short channel /*= priv->chan*/ = 1; ++ priv->chan = 1; ++ ++ write_nic_word(dev, RFPinsOutput, 0x80); ++ write_nic_word(dev, RFPinsSelect, 0x80 | SW_CONTROL_GPIO); ++ write_nic_word(dev, RFPinsEnable, 0x80); ++ write_nic_word(dev, RFPinsSelect, SW_CONTROL_GPIO); ++ ++ write_nic_dword(dev, RF_TIMING, 0x000f800f); ++ ++ brsr = read_nic_word(dev, BRSR); ++ ++ write_nic_word(dev, 0x2c, 0xffff); ++ ++ ++ rtl8180_set_anaparam(dev, RTL8255_ANAPARAM_ON); ++ rtl8185_set_anaparam2(dev, RTL8255_ANAPARAM2_ON); ++ ++ write_nic_dword(dev, 0x94, 0x11c00002); ++ ++ write_nic_dword(dev, RF_PARA, 0x100040); ++ ++ rtl8185_rf_pins_enable(dev); ++ ++ rtl8255_init_BGband(dev); ++ rtl8255_set_band_param(dev,BAND_BG); ++ ++ write_phy_cck(dev, 0x0, 0x98); ++ write_phy_cck(dev, 0x3, 0x20); ++ write_phy_cck(dev, 0x4, 0x2e); ++ write_phy_cck(dev, 0x5, 0x12); ++ write_phy_cck(dev, 0x6, 0xfc); ++ write_phy_cck(dev, 0x7, 0xd8); ++ write_phy_cck(dev, 0x8, 0x2e); ++ write_phy_cck(dev, 0x10, 0xd3); ++ write_phy_cck(dev, 0x11, 0x88); ++ write_phy_cck(dev, 0x12, 0x47); ++ write_phy_cck(dev, 0x13, 0xd0); /* Ver C & D & 8187*/ ++ ++ write_phy_cck(dev, 0x19, 0x0); ++ write_phy_cck(dev, 0x1a, 0xa0); ++ write_phy_cck(dev, 0x1b, 0x8); ++ write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ ++ write_phy_cck(dev, 0x41, 0x9d); /* Energy Threshold */ ++ //write_phy_cck(dev, 0x42, 0x0); ++ write_phy_cck(dev, 0x43, 0x8); ++ ++ write_nic_byte(dev, TESTR,0x8); ++ ++ for(i=0;i<128;i++){ ++ write_phy_ofdm(dev, 0x4b, rtl8255_agc[i]); ++ write_phy_ofdm(dev, 0x4a, (u8)i+ 0x80); ++ } ++ ++ ++ write_phy_ofdm(dev, 0x0, 0x1); ++ write_phy_ofdm(dev, 0x1, 0x2); ++ write_phy_ofdm(dev, 0x2, 0x43); ++ write_phy_ofdm(dev, 0x3, 0x0); ++ write_phy_ofdm(dev, 0x4, 0x0); ++ write_phy_ofdm(dev, 0x5, 0x0); ++ write_phy_ofdm(dev, 0x6, 0x40); ++ write_phy_ofdm(dev, 0x7, 0x0); ++ write_phy_ofdm(dev, 0x8, 0x40); ++ write_phy_ofdm(dev, 0x9, 0xfe); ++ write_phy_ofdm(dev, 0xa, 0x9); ++ write_phy_ofdm(dev, 0xb, 0x80); ++ write_phy_ofdm(dev, 0xc, 0x1); ++ write_phy_ofdm(dev, 0xd, 0x43); ++ write_phy_ofdm(dev, 0xe, 0xd3); ++ write_phy_ofdm(dev, 0xf, 0x38); ++ write_phy_ofdm(dev, 0x10, 0x4); ++ write_phy_ofdm(dev, 0x11, 0x06);/*agc resp time 700*/ ++ write_phy_ofdm(dev, 0x12, 0x20); ++ write_phy_ofdm(dev, 0x13, 0x20); ++ write_phy_ofdm(dev, 0x14, 0x0); ++ write_phy_ofdm(dev, 0x15, 0x40); ++ write_phy_ofdm(dev, 0x16, 0x0); ++ write_phy_ofdm(dev, 0x17, 0x40); ++ write_phy_ofdm(dev, 0x18, 0xef); ++ write_phy_ofdm(dev, 0x19, 0x25); ++ write_phy_ofdm(dev, 0x1a, 0x20); ++ write_phy_ofdm(dev, 0x1b, 0x7a); ++ write_phy_ofdm(dev, 0x1c, 0x84); ++ write_phy_ofdm(dev, 0x1e, 0x95); ++ write_phy_ofdm(dev, 0x1f, 0x75); ++ write_phy_ofdm(dev, 0x20, 0x1f); ++ write_phy_ofdm(dev, 0x21, 0x17); ++ write_phy_ofdm(dev, 0x22, 0x16); ++ write_phy_ofdm(dev, 0x23, 0x70); //FIXME maybe not needed ++ write_phy_ofdm(dev, 0x24, 0x70); ++ write_phy_ofdm(dev, 0x25, 0x0); ++ write_phy_ofdm(dev, 0x26, 0x10); ++ write_phy_ofdm(dev, 0x27, 0x88); ++ ++ ++ write_nic_dword(dev, 0x94, 0x3dc00002); //BAND DEPEND. ++// write_nic_dword(dev, 0x94, 0x15c00002); //BAND DEPEND. ++ ++ write_phy_cck(dev, 0x4, 0x18); ++ write_phy_cck(dev, 0x43, 0x18); ++ write_phy_cck(dev, 0x6, 0xdc); ++ write_phy_cck(dev, 0x44, 0x2b); ++ write_phy_cck(dev, 0x45, 0x2b); ++ write_phy_cck(dev, 0x46, 0x25); ++ write_phy_cck(dev, 0x47, 0x15); ++ write_phy_cck(dev, 0x48, 0x0); ++ write_phy_cck(dev, 0x49, 0x0); ++ write_phy_cck(dev, 0x4a, 0x0); ++ write_phy_cck(dev, 0x4b, 0x0); ++// write_phy_cck(dev, 0x4c, 0x5); ++#if 0 ++ write_phy_cck(dev, 0x41, 0x9d); /* Energy Threshold */ ++ // TESTR 0xb 8187 ++ write_phy_cck(dev, 0x10, 0x93);// & 0xfb); ++#endif ++ //rtl8255_set_gain(dev, 1); /* FIXME this '1' is random */ ++ ++ rtl8255_SetTXPowerLevel(dev, priv->chan); ++ ++ write_phy_cck(dev, 0x10, 0x93 |0x4); /* Rx ant B, 0xd3 for A */ ++ write_phy_ofdm(dev, 0x26, 0x90); /* Rx ant B, 0x10 for A */ ++ ++ rtl8185_tx_antenna(dev, 0x3); /* TX ant B, 0x0 for A*/ ++ /* make sure is waken up! */ ++ rtl8180_set_anaparam(dev, RTL8255_ANAPARAM_ON); ++ rtl8185_set_anaparam2(dev, RTL8255_ANAPARAM2_ON); ++ ++ rtl8255_set_band_param(dev,BAND_BG); ++ ++ write_phy_cck(dev, 0x41, 0x9d); ++ ++ rtl8255_set_gain(dev, 4); ++ //rtl8255_set_energy_threshold(dev); ++ write_phy_cck(dev, 0x41, 0x9d); ++ rtl8255_rf_set_chan(dev, priv->chan); ++ ++ write_nic_word(dev, BRSR, brsr); ++} ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_rtl8255.h +@@ -0,0 +1,19 @@ ++/* ++ This is part of the rtl8180-sa2400 driver ++ released under the GPL (See file COPYING for details). ++ Copyright (c) 2005 Andrea Merello ++ ++ This files contains programming code for the rtl8255 ++ radio frontend. ++ ++ *Many* thanks to Realtek Corp. for their great support! ++ ++*/ ++ ++#define RTL8255_ANAPARAM_ON 0xa0000b59 ++#define RTL8255_ANAPARAM2_ON 0x840cf311 ++ ++ ++void rtl8255_rf_init(struct net_device *dev); ++void rtl8255_rf_set_chan(struct net_device *dev,short ch); ++void rtl8255_rf_close(struct net_device *dev); +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_sa2400.c +@@ -0,0 +1,233 @@ ++/* ++ This files contains PHILIPS SA2400 radio frontend programming routines. ++ ++ This is part of rtl8180 OpenSource driver ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the ++ official realtek driver ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ Code at http://che.ojctech.com/~dyoung/rtw/ has been useful to me to ++ understand some things. ++ ++ Code from rtl8181 project has been useful to me to understand some things. ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++ ++#include "r8180.h" ++#include "r8180_hw.h" ++#include "r8180_sa2400.h" ++ ++ ++//#define DEBUG_SA2400 ++ ++u32 sa2400_chan[] = { ++ 0x0, //dummy channel 0 ++ 0x00096c, //1 ++ 0x080970, //2 ++ 0x100974, //3 ++ 0x180978, //4 ++ 0x000980, //5 ++ 0x080984, //6 ++ 0x100988, //7 ++ 0x18098c, //8 ++ 0x000994, //9 ++ 0x080998, //10 ++ 0x10099c, //11 ++ 0x1809a0, //12 ++ 0x0009a8, //13 ++ 0x0009b4, //14 ++}; ++ ++ ++void rf_stabilize(struct net_device *dev) ++{ ++ force_pci_posting(dev); ++ mdelay(3); //for now use a great value.. we may optimize in future ++} ++ ++ ++void write_sa2400(struct net_device *dev,u8 adr, u32 data) ++{ ++// struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 phy_config; ++ ++ // philips sa2400 expects 24 bits data ++ ++ /*if(adr == 4 && priv->digphy){ ++ phy_config=0x60000000; ++ }else{ ++ phy_config=0xb0000000; ++ }*/ ++ ++ phy_config = 0xb0000000; // MAC will bang bits to the sa2400 ++ ++ phy_config |= (((u32)(adr&0xf))<< 24); ++ phy_config |= (data & 0xffffff); ++ write_nic_dword(dev,PHY_CONFIG,phy_config); ++#ifdef DEBUG_SA2400 ++ DMESG("Writing sa2400: %x (adr %x)",phy_config,adr); ++#endif ++ rf_stabilize(dev); ++} ++ ++ ++ ++void sa2400_write_phy_antenna(struct net_device *dev,short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 ant; ++ ++ ant = SA2400_ANTENNA; ++ if(priv->antb) /*default antenna is antenna B */ ++ ant |= BB_ANTENNA_B; ++ if(ch == 14) ++ ant |= BB_ANTATTEN_CHAN14; ++ write_phy(dev,0x10,ant); ++ //DMESG("BB antenna %x ",ant); ++} ++ ++ ++/* from the rtl8181 embedded driver */ ++short sa2400_rf_set_sens(struct net_device *dev, short sens) ++{ ++ u8 finetune = 0; ++ if ((sens > 85) || (sens < 54)) return -1; ++ ++ write_sa2400(dev,5,0x1dfb | (sens-54) << 15 |(finetune<<20)); // AGC 0xc9dfb ++ ++ return 0; ++} ++ ++ ++void sa2400_rf_set_chan(struct net_device *dev, short ch) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 txpw = 0xff & priv->chtxpwr[ch]; ++ u32 chan = sa2400_chan[ch]; ++ ++ write_sa2400(dev,7,txpw); ++ //write_phy(dev,0x10,0xd1); ++ sa2400_write_phy_antenna(dev,ch); ++ write_sa2400(dev,0,chan); ++ write_sa2400(dev,1,0xbb50); ++ write_sa2400(dev,2,0x80); ++ write_sa2400(dev,3,0); ++} ++ ++ ++void sa2400_rf_close(struct net_device *dev) ++{ ++ write_sa2400(dev, 4, 0); ++} ++ ++ ++void sa2400_rf_init(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u32 anaparam; ++ u8 firdac; ++ ++ write_nic_byte(dev,PHY_DELAY,0x6); //this is general ++ write_nic_byte(dev,CARRIER_SENSE_COUNTER,0x4c); //this is general ++ ++ /*these are philips sa2400 specific*/ ++ anaparam = read_nic_dword(dev,ANAPARAM); ++ anaparam = anaparam &~ (1<digphy){ ++ anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON<digphy) ? (1<chan]); ++ write_sa2400(dev,1,0xbb50); ++ write_sa2400(dev,2,0x80); ++ write_sa2400(dev,3,0); ++ write_sa2400(dev,4,0x19340 | firdac); ++ write_sa2400(dev,5,0xc9dfb); // AGC ++ write_sa2400(dev,4,0x19348 | firdac); //calibrates VCO ++ ++ if(priv->digphy) ++ write_sa2400(dev,4,0x1938c); /*???*/ ++ ++ write_sa2400(dev,4,0x19340 | firdac); ++ ++ write_sa2400(dev,0,sa2400_chan[priv->chan]); ++ write_sa2400(dev,1,0xbb50); ++ write_sa2400(dev,2,0x80); ++ write_sa2400(dev,3,0); ++ write_sa2400(dev,4,0x19344 | firdac); //calibrates filter ++ ++ /* new from rtl8180 embedded driver (rtl8181 project) */ ++ write_sa2400(dev,6,0x13ff | (1<<23)); // MANRX ++ write_sa2400(dev,8,0); //VCO ++ ++ if(!priv->digphy) ++ { ++ rtl8180_set_anaparam(dev, anaparam | \ ++ (1<chan); ++ ++ write_phy(dev,0x11,0x80); ++ if(priv->diversity) ++ write_phy(dev,0x12,0xc7); ++ else ++ write_phy(dev,0x12,0x47); ++ ++ write_phy(dev,0x13,0x90 | priv->cs_treshold ); ++ ++ write_phy(dev,0x19,0x0); ++ write_phy(dev,0x1a,0xa0); ++ ++ sa2400_rf_set_chan(dev,priv->chan); ++} +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_sa2400.h +@@ -0,0 +1,26 @@ ++/* ++ This is part of rtl8180 OpenSource driver - v 0.7 ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++#define SA2400_ANTENNA 0x91 ++#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 ++#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 ++#define SA2400_ANAPARAM_PWR0_ON 0x3 ++ ++#define SA2400_RF_MAX_SENS 85 ++#define SA2400_RF_DEF_SENS 80 ++ ++#define SA2400_REG4_FIRDAC_SHIFT 7 ++ ++void sa2400_rf_init(struct net_device *dev); ++void sa2400_rf_set_chan(struct net_device *dev,short ch); ++short sa2400_rf_set_sens(struct net_device *dev,short sens); ++void sa2400_rf_close(struct net_device *dev); +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_wx.c +@@ -0,0 +1,1644 @@ ++/* ++ This file contains wireless extension handlers. ++ ++ This is part of rtl8180 OpenSource driver. ++ Copyright (C) Andrea Merello 2004-2005 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part ++ of the official realtek driver. ++ ++ Parts of this driver are based on the rtl8180 driver skeleton ++ from Patric Schenke & Andres Salomon. ++ ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. ++ ++ We want to tanks the Authors of those projects and the Ndiswrapper ++ project Authors. ++*/ ++ ++ ++#include "r8180.h" ++#include "r8180_hw.h" ++#include "r8180_sa2400.h" ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++//#define RATE_COUNT 4 ++u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000, ++ 6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000}; ++ ++#define RATE_COUNT (sizeof(rtl8180_rates)/sizeof(rtl8180_rates[0])) ++ ++static CHANNEL_LIST DefaultChannelPlan[] = { ++// {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //Default channel plan ++ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC ++ {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI. ++ {{14,36,40,44,48,52,56,60,64},9}, //MKK ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1 ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel. ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC ++ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14} //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 ++}; ++static int r8180_wx_get_freq(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_freq(priv->ieee80211, a, wrqu, b); ++} ++ ++ ++int r8180_wx_set_key(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct iw_point *erq = &(wrqu->encoding); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ if (erq->flags & IW_ENCODE_DISABLED) { ++ } ++ ++ ++/* i = erq->flags & IW_ENCODE_INDEX; ++ if (i < 1 || i > 4) ++*/ ++ ++ if (erq->length > 0) { ++ ++ //int len = erq->length <= 5 ? 5 : 13; ++ ++ u32* tkey= (u32*) key; ++ priv->key0[0] = tkey[0]; ++ priv->key0[1] = tkey[1]; ++ priv->key0[2] = tkey[2]; ++ priv->key0[3] = tkey[3] &0xff; ++ DMESG("Setting wep key to %x %x %x %x", ++ tkey[0],tkey[1],tkey[2],tkey[3]); ++ rtl8180_set_hw_wep(dev); ++ } ++ return 0; ++} ++ ++ ++static int r8180_wx_set_beaconinterval(struct net_device *dev, struct iw_request_info *aa, ++ union iwreq_data *wrqu, char *b) ++{ ++ int *parms = (int *)b; ++ int bi = parms[0]; ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ DMESG("setting beacon interval to %x",bi); ++ ++ priv->ieee80211->current_network.beacon_interval=bi; ++ rtl8180_commit(dev); ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++ ++ ++static int r8180_wx_get_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_mode(priv->ieee80211,a,wrqu,b); ++} ++ ++ ++ ++static int r8180_wx_get_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_rate(priv->ieee80211,info,wrqu,extra); ++} ++ ++ ++ ++static int r8180_wx_set_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++static int r8180_wx_set_crcmon(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int *parms = (int *)extra; ++ int enable = (parms[0] > 0); ++ short prev = priv->crcmon; ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ if(enable) ++ priv->crcmon=1; ++ else ++ priv->crcmon=0; ++ ++ DMESG("bad CRC in monitor mode are %s", ++ priv->crcmon ? "accepted" : "rejected"); ++ ++ if(prev != priv->crcmon && priv->up){ ++ rtl8180_down(dev); ++ rtl8180_up(dev); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_set_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++#ifdef ENABLE_IPS ++// printk("set mode ENABLE_IPS\n"); ++ if(priv->bInactivePs){ ++ if(wrqu->mode == IW_MODE_ADHOC) ++ IPSLeave(dev); ++ } ++#endif ++ ret = ieee80211_wx_set_mode(priv->ieee80211,a,wrqu,b); ++ ++ //rtl8180_commit(dev); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++//YJ,add,080819,for hidden ap ++struct iw_range_with_scan_capa ++{ ++ /* Informative stuff (to choose between different interface) */ ++ __u32 throughput; /* To give an idea... */ ++ /* In theory this value should be the maximum benchmarked ++ * TCP/IP throughput, because with most of these devices the ++ * bit rate is meaningless (overhead an co) to estimate how ++ * fast the connection will go and pick the fastest one. ++ * I suggest people to play with Netperf or any benchmark... ++ */ ++ ++ /* NWID (or domain id) */ ++ __u32 min_nwid; /* Minimal NWID we are able to set */ ++ __u32 max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++ __u16 old_num_channels; ++ __u8 old_num_frequency; ++ ++ /* Scan capabilities */ ++ __u8 scan_capa; ++}; ++//YJ,add,080819,for hidden ap ++ ++ ++static int rtl8180_wx_get_range(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *)extra; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u16 val; ++ int i; ++ //struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range; //YJ,add,080819,for hidden ap ++ ++ wrqu->data.length = sizeof(*range); ++ memset(range, 0, sizeof(*range)); ++ ++ /* Let's try to keep this struct in the same order as in ++ * linux/include/wireless.h ++ */ ++ ++ /* TODO: See what values we can set, and remove the ones we can't ++ * set, or fill them with some default data. ++ */ ++ ++ /* ~5 Mb/s real (802.11b) */ ++ range->throughput = 5 * 1000 * 1000; ++ ++ // TODO: Not used in 802.11b? ++// range->min_nwid; /* Minimal NWID we are able to set */ ++ // TODO: Not used in 802.11b? ++// range->max_nwid; /* Maximal NWID we are able to set */ ++ ++ /* Old Frequency (backward compat - moved lower ) */ ++// range->old_num_channels; ++// range->old_num_frequency; ++// range->old_freq[6]; /* Filler to keep "version" at the same offset */ ++ if(priv->rf_set_sens != NULL) ++ range->sensitivity = priv->max_sens; /* signal level threshold range */ ++ ++ range->max_qual.qual = 100; ++ /* TODO: Find real max RSSI and stick here */ ++ range->max_qual.level = 0; ++ range->max_qual.noise = -98; ++ range->max_qual.updated = 7; /* Updated all three */ ++ ++ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ ++ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ ++ range->avg_qual.level = 20 + -98; ++ range->avg_qual.noise = 0; ++ range->avg_qual.updated = 7; /* Updated all three */ ++ ++ range->num_bitrates = RATE_COUNT; ++ ++ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) { ++ range->bitrate[i] = rtl8180_rates[i]; ++ } ++ ++ range->min_frag = MIN_FRAG_THRESHOLD; ++ range->max_frag = MAX_FRAG_THRESHOLD; ++ ++ range->pm_capa = 0; ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 16; ++ ++// range->retry_capa; /* What retry options are supported */ ++// range->retry_flags; /* How to decode max/min retry limit */ ++// range->r_time_flags; /* How to decode max/min retry life */ ++// range->min_retry; /* Minimal number of retries */ ++// range->max_retry; /* Maximal number of retries */ ++// range->min_r_time; /* Minimal retry lifetime */ ++// range->max_r_time; /* Maximal retry lifetime */ ++ ++ range->num_channels = 14; ++ ++ for (i = 0, val = 0; i < 14; i++) { ++ ++ // Include only legal frequencies for some countries ++#ifdef ENABLE_DOT11D ++ if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { ++#else ++ if ((priv->ieee80211->channel_map)[i+1]) { ++#endif ++ range->freq[val].i = i + 1; ++ range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } else { ++ // FIXME: do we need to set anything for channels ++ // we don't use ? ++ } ++ ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ ++ range->num_frequency = val; ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++ ++ //tmp->scan_capa = 0x01; //YJ,add,080819,for hidden ap ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ struct ieee80211_device* ieee = priv->ieee80211; ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++//YJ,add,080819, for hidden ap ++ //printk("==*&*&*&==>%s in\n", __func__); ++ //printk("=*&*&*&*===>flag:%x, %x\n", wrqu->data.flags, IW_SCAN_THIS_ESSID); ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) ++ { ++ struct iw_scan_req* req = (struct iw_scan_req*)b; ++ if (req->essid_len) ++ { ++ //printk("==**&*&*&**===>scan set ssid:%s\n", req->essid); ++ ieee->current_network.ssid_len = req->essid_len; ++ memcpy(ieee->current_network.ssid, req->essid, req->essid_len); ++ //printk("=====>network ssid:%s\n", ieee->current_network.ssid); ++ } ++ } ++//YJ,add,080819, for hidden ap, end ++ ++ down(&priv->wx_sem); ++ if(priv->up){ ++#ifdef ENABLE_IPS ++// printk("set scan ENABLE_IPS\n"); ++ priv->ieee80211->actscanning = true; ++ if(priv->bInactivePs && (priv->ieee80211->state != IEEE80211_LINKED)){ ++ IPSLeave(dev); ++// down(&priv->ieee80211->wx_sem); ++ ++// if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || !(priv->ieee80211->proto_started)){ ++// ret = -1; ++// up(&priv->ieee80211->wx_sem); ++// up(&priv->wx_sem); ++// return ret; ++// } ++ ++ // queue_work(priv->ieee80211->wq, &priv->ieee80211->wx_sync_scan_wq); ++ //printk("start scan============================>\n"); ++ ieee80211_softmac_ips_scan_syncro(priv->ieee80211); ++//ieee80211_start_scan(priv->ieee80211); ++ /* intentionally forget to up sem */ ++// up(&priv->ieee80211->wx_sem); ++ ret = 0; ++ } ++ else ++#endif ++ { ++ //YJ,add,080828, prevent scan in BusyTraffic ++ //FIXME: Need to consider last scan time ++ if ((priv->link_detect.bBusyTraffic) && (true)) ++ { ++ ret = 0; ++ printk("Now traffic is busy, please try later!\n"); ++ } ++ else ++ //YJ,add,080828, prevent scan in BusyTraffic,end ++ ret = ieee80211_wx_set_scan(priv->ieee80211,a,wrqu,b); ++ } ++ } ++ else ++ ret = -1; ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++static int r8180_wx_get_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ if(priv->up) ++ ret = ieee80211_wx_get_scan(priv->ieee80211,a,wrqu,b); ++ else ++ ret = -1; ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++static int r8180_wx_set_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ int ret; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++#ifdef ENABLE_IPS ++ //printk("set essid ENABLE_IPS\n"); ++ if(priv->bInactivePs) ++ IPSLeave(dev); ++#endif ++// printk("haha:set essid %s essid_len = %d essid_flgs = %d\n",b, wrqu->essid.length, wrqu->essid.flags); ++ ++ ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++static int r8180_wx_get_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++ ++static int r8180_wx_set_freq(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++static int r8180_wx_get_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra); ++} ++ ++static int r8180_wx_set_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ if (wrqu->frag.disabled) ++ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; ++ else { ++ if (wrqu->frag.value < MIN_FRAG_THRESHOLD || ++ wrqu->frag.value > MAX_FRAG_THRESHOLD) ++ return -EINVAL; ++ ++ priv->ieee80211->fts = wrqu->frag.value & ~0x1; ++ } ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_get_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ wrqu->frag.value = priv->ieee80211->fts; ++ wrqu->frag.fixed = 0; /* no auto select */ ++ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); ++ ++ return 0; ++} ++ ++ ++static int r8180_wx_set_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra); ++ ++ up(&priv->wx_sem); ++ return ret; ++ ++} ++ ++ ++static int r8180_wx_get_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_wap(priv->ieee80211,info,wrqu,extra); ++} ++ ++ ++static int r8180_wx_set_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ ++ down(&priv->wx_sem); ++ ++ if(priv->hw_wep) ret = r8180_wx_set_key(dev,info,wrqu,key); ++ else{ ++ DMESG("Setting SW wep key"); ++ ret = ieee80211_wx_set_encode(priv->ieee80211,info,wrqu,key); ++ } ++ ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++ ++static int r8180_wx_get_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *key) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key); ++} ++ ++ ++static int r8180_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union ++ iwreq_data *wrqu, char *p){ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int *parms=(int*)p; ++ int mode=parms[0]; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ priv->ieee80211->active_scan = mode; ++ ++ return 1; ++} ++ ++ ++/* added by christian */ ++/* ++static int r8180_wx_set_monitor_type(struct net_device *dev, struct iw_request_info *aa, union ++ iwreq_data *wrqu, char *p){ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int *parms=(int*)p; ++ int mode=parms[0]; ++ ++ if(priv->ieee80211->iw_mode != IW_MODE_MONITOR) return -1; ++ priv->prism_hdr = mode; ++ if(!mode)dev->type=ARPHRD_IEEE80211; ++ else dev->type=ARPHRD_IEEE80211_PRISM; ++ DMESG("using %s RX encap", mode ? "AVS":"80211"); ++ return 0; ++ ++} ++*/ ++//of r8180_wx_set_monitor_type ++/* end added christian */ ++ ++static int r8180_wx_set_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int err = 0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ if (wrqu->retry.flags & IW_RETRY_LIFETIME || ++ wrqu->retry.disabled){ ++ err = -EINVAL; ++ goto exit; ++ } ++ if (!(wrqu->retry.flags & IW_RETRY_LIMIT)){ ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if(wrqu->retry.value > R8180_MAX_RETRY){ ++ err= -EINVAL; ++ goto exit; ++ } ++ if (wrqu->retry.flags & IW_RETRY_MAX) { ++ priv->retry_rts = wrqu->retry.value; ++ DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value); ++ ++ }else { ++ priv->retry_data = wrqu->retry.value; ++ DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value); ++ } ++ ++ /* FIXME ! ++ * We might try to write directly the TX config register ++ * or to restart just the (R)TX process. ++ * I'm unsure if whole reset is really needed ++ */ ++ ++ rtl8180_commit(dev); ++ /* ++ if(priv->up){ ++ rtl8180_rtx_disable(dev); ++ rtl8180_rx_enable(dev); ++ rtl8180_tx_enable(dev); ++ ++ } ++ */ ++exit: ++ up(&priv->wx_sem); ++ ++ return err; ++} ++ ++static int r8180_wx_get_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ wrqu->retry.disabled = 0; /* can't be disabled */ ++ ++ if ((wrqu->retry.flags & IW_RETRY_TYPE) == ++ IW_RETRY_LIFETIME) ++ return -EINVAL; ++ ++ if (wrqu->retry.flags & IW_RETRY_MAX) { ++ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX; ++ wrqu->retry.value = priv->retry_rts; ++ } else { ++ wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN; ++ wrqu->retry.value = priv->retry_data; ++ } ++ //DMESG("returning %d",wrqu->retry.value); ++ ++ ++ return 0; ++} ++ ++static int r8180_wx_get_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ if(priv->rf_set_sens == NULL) ++ return -1; /* we have not this support for this radio */ ++ wrqu->sens.value = priv->sens; ++ return 0; ++} ++ ++ ++static int r8180_wx_set_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ short err = 0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ //DMESG("attempt to set sensivity to %ddb",wrqu->sens.value); ++ if(priv->rf_set_sens == NULL) { ++ err= -1; /* we have not this support for this radio */ ++ goto exit; ++ } ++ if(priv->rf_set_sens(dev, wrqu->sens.value) == 0) ++ priv->sens = wrqu->sens.value; ++ else ++ err= -EINVAL; ++ ++exit: ++ up(&priv->wx_sem); ++ ++ return err; ++} ++ ++ ++static int r8180_wx_set_rawtx(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++ ++static int r8180_wx_get_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_get_power(priv->ieee80211, info, wrqu, extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++static int r8180_wx_set_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ printk("=>>>>>>>>>>=============================>set power:%d,%d!\n",wrqu->power.disabled, wrqu->power.flags); ++ if (wrqu->power.disabled==0) { ++ wrqu->power.flags|=IW_POWER_ALL_R; ++ wrqu->power.flags|=IW_POWER_TIMEOUT; ++ wrqu->power.value =1000; ++ } ++ ++ ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++ ++static int r8180_wx_set_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ if (wrqu->rts.disabled) ++ priv->rts = DEFAULT_RTS_THRESHOLD; ++ else { ++ if (wrqu->rts.value < MIN_RTS_THRESHOLD || ++ wrqu->rts.value > MAX_RTS_THRESHOLD) ++ return -EINVAL; ++ ++ priv->rts = wrqu->rts.value; ++ } ++ ++ return 0; ++} ++static int r8180_wx_get_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ ++ wrqu->rts.value = priv->rts; ++ wrqu->rts.fixed = 0; /* no auto select */ ++ wrqu->rts.disabled = (wrqu->rts.value == 0); ++ ++ return 0; ++} ++static int dummy(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu,char *b) ++{ ++ return -1; ++} ++ ++/* ++static int r8180_wx_get_psmode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee; ++ int ret = 0; ++ ++ ++ ++ down(&priv->wx_sem); ++ ++ if(priv) { ++ ieee = priv->ieee80211; ++ if(ieee->ps == IEEE80211_PS_DISABLED) { ++ *((unsigned int *)extra) = IEEE80211_PS_DISABLED; ++ goto exit; ++ } ++ *((unsigned int *)extra) = IW_POWER_TIMEOUT; ++ if (ieee->ps & IEEE80211_PS_MBCAST) ++ *((unsigned int *)extra) |= IW_POWER_ALL_R; ++ else ++ *((unsigned int *)extra) |= IW_POWER_UNICAST_R; ++ } else ++ ret = -1; ++exit: ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++static int r8180_wx_set_psmode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //struct ieee80211_device *ieee; ++ int ret = 0; ++ ++ ++ ++ down(&priv->wx_sem); ++ ++ ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++ ++} ++*/ ++ ++static int r8180_wx_get_iwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee; ++ int ret = 0; ++ ++ ++ ++ down(&priv->wx_sem); ++ ++ ieee = priv->ieee80211; ++ ++ strcpy(extra, "802.11"); ++ if(ieee->modulation & IEEE80211_CCK_MODULATION) { ++ strcat(extra, "b"); ++ if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(extra, "/g"); ++ } else if(ieee->modulation & IEEE80211_OFDM_MODULATION) ++ strcat(extra, "g"); ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++static int r8180_wx_set_iwmode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ int *param = (int *)extra; ++ int ret = 0; ++ int modulation = 0, mode = 0; ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ++ if (*param == 1) { ++ modulation |= IEEE80211_CCK_MODULATION; ++ mode = IEEE_B; ++ printk(KERN_INFO "B mode!\n"); ++ } else if (*param == 2) { ++ modulation |= IEEE80211_OFDM_MODULATION; ++ mode = IEEE_G; ++ printk(KERN_INFO "G mode!\n"); ++ } else if (*param == 3) { ++ modulation |= IEEE80211_CCK_MODULATION; ++ modulation |= IEEE80211_OFDM_MODULATION; ++ mode = IEEE_B|IEEE_G; ++ printk(KERN_INFO "B/G mode!\n"); ++ } ++ ++ if(ieee->proto_started) { ++ ieee80211_stop_protocol(ieee); ++ ieee->mode = mode; ++ ieee->modulation = modulation; ++ ieee80211_start_protocol(ieee); ++ } else { ++ ieee->mode = mode; ++ ieee->modulation = modulation; ++// ieee80211_start_protocol(ieee); ++ } ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++static int r8180_wx_get_preamble(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ ++ down(&priv->wx_sem); ++ ++ ++ ++ *extra = (char) priv->plcp_preamble_mode; // 0:auto 1:short 2:long ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++static int r8180_wx_set_preamble(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret = 0; ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ if (*extra<0||*extra>2) ++ ret = -1; ++ else ++ priv->plcp_preamble_mode = *((short *)extra) ; ++ ++ ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++static int r8180_wx_get_siglevel(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //struct ieee80211_network *network = &(priv->ieee80211->current_network); ++ int ret = 0; ++ ++ ++ ++ down(&priv->wx_sem); ++ // Modify by hikaru 6.5 ++ *((int *)extra) = priv->wstats.qual.level;//for interface test ,it should be the priv->wstats.qual.level; ++ ++ ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++static int r8180_wx_get_sigqual(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //struct ieee80211_network *network = &(priv->ieee80211->current_network); ++ int ret = 0; ++ ++ ++ ++ down(&priv->wx_sem); ++ // Modify by hikaru 6.5 ++ *((int *)extra) = priv->wstats.qual.qual;//for interface test ,it should be the priv->wstats.qual.qual; ++ ++ ++ ++ up(&priv->wx_sem); ++ ++ return ret; ++} ++static int r8180_wx_reset_stats(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv =ieee80211_priv(dev); ++ down(&priv->wx_sem); ++ ++ priv->stats.txrdu = 0; ++ priv->stats.rxrdu = 0; ++ priv->stats.rxnolast = 0; ++ priv->stats.rxnodata = 0; ++ priv->stats.rxnopointer = 0; ++ priv->stats.txnperr = 0; ++ priv->stats.txresumed = 0; ++ priv->stats.rxerr = 0; ++ priv->stats.rxoverflow = 0; ++ priv->stats.rxint = 0; ++ ++ priv->stats.txnpokint = 0; ++ priv->stats.txhpokint = 0; ++ priv->stats.txhperr = 0; ++ priv->stats.ints = 0; ++ priv->stats.shints = 0; ++ priv->stats.txoverflow = 0; ++ priv->stats.rxdmafail = 0; ++ priv->stats.txbeacon = 0; ++ priv->stats.txbeaconerr = 0; ++ priv->stats.txlpokint = 0; ++ priv->stats.txlperr = 0; ++ priv->stats.txretry =0;//20060601 ++ priv->stats.rxcrcerrmin=0; ++ priv->stats.rxcrcerrmid=0; ++ priv->stats.rxcrcerrmax=0; ++ priv->stats.rxicverr=0; ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++ ++} ++static int r8180_wx_radio_on(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv =ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ ++ down(&priv->wx_sem); ++ priv->rf_wakeup(dev); ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++ ++} ++ ++static int r8180_wx_radio_off(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv =ieee80211_priv(dev); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ ++ down(&priv->wx_sem); ++ priv->rf_sleep(dev); ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++ ++} ++static int r8180_wx_get_channelplan(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ ++ down(&priv->wx_sem); ++ *extra = priv->channel_plan; ++ ++ ++ ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++static int r8180_wx_set_channelplan(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //struct ieee80211_device *ieee = netdev_priv(dev); ++ int *val = (int *)extra; ++ int i; ++ printk("-----in fun %s\n", __FUNCTION__); ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ //unsigned long flags; ++ down(&priv->wx_sem); ++ if (DefaultChannelPlan[*val].Len != 0){ ++ priv ->channel_plan = *val; ++ // Clear old channel map ++ for (i=1;i<=MAX_CHANNEL_NUMBER;i++) ++ { ++#ifdef ENABLE_DOT11D ++ GET_DOT11D_INFO(priv->ieee80211)->channel_map[i] = 0; ++#else ++ priv->ieee80211->channel_map[i] = 0; ++#endif ++ } ++ // Set new channel map ++ for (i=1;i<=DefaultChannelPlan[*val].Len;i++) ++ { ++#ifdef ENABLE_DOT11D ++ GET_DOT11D_INFO(priv->ieee80211)->channel_map[DefaultChannelPlan[*val].Channel[i-1]] = 1; ++#else ++ priv->ieee80211->channel_map[DefaultChannelPlan[*val].Channel[i-1]] = 1; ++#endif ++ } ++ } ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++static int r8180_wx_get_version(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //struct ieee80211_device *ieee; ++ ++ down(&priv->wx_sem); ++ strcpy(extra, "1020.0808"); ++ up(&priv->wx_sem); ++ ++ return 0; ++} ++ ++//added by amy 080818 ++//receive datarate from user typing valid rate is from 2 to 108 (1 - 54M), if input 0, return to normal rate adaptive. ++static int r8180_wx_set_forcerate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ u8 forcerate = *extra; ++ ++ down(&priv->wx_sem); ++ ++ printk("==============>%s(): forcerate is %d\n",__FUNCTION__,forcerate); ++ if((forcerate == 2) || (forcerate == 4) || (forcerate == 11) || (forcerate == 22) || (forcerate == 12) || ++ (forcerate == 18) || (forcerate == 24) || (forcerate == 36) || (forcerate == 48) || (forcerate == 72) || ++ (forcerate == 96) || (forcerate == 108)) ++ { ++ priv->ForcedDataRate = 1; ++ priv->ieee80211->rate = forcerate * 5; ++ } ++ else if(forcerate == 0) ++ { ++ priv->ForcedDataRate = 0; ++ printk("OK! return rate adaptive\n"); ++ } ++ else ++ printk("ERR: wrong rate\n"); ++ up(&priv->wx_sem); ++ return 0; ++} ++ ++static int r8180_wx_set_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ //printk("===>%s()\n", __FUNCTION__); ++ ++ int ret=0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra); ++ up(&priv->wx_sem); ++ return ret; ++ ++} ++static int r8180_wx_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_param *data, char *extra) ++{ ++ //printk("====>%s()\n", __FUNCTION__); ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ int ret=0; ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++ ret = ieee80211_wx_set_auth(priv->ieee80211, info, data, extra); ++ up(&priv->wx_sem); ++ return ret; ++} ++ ++static int r8180_wx_set_mlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ //printk("====>%s()\n", __FUNCTION__); ++ ++ int ret=0; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ ++ down(&priv->wx_sem); ++#if 1 ++ ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); ++#endif ++ up(&priv->wx_sem); ++ return ret; ++} ++static int r8180_wx_set_gen_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++// printk("====>%s(), len:%d\n", __FUNCTION__, data->length); ++ int ret=0; ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ ++ ++ if(priv->ieee80211->bHwRadioOff) ++ return 0; ++ ++ down(&priv->wx_sem); ++#if 1 ++ ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->length); ++#endif ++ up(&priv->wx_sem); ++ //printk("<======%s(), ret:%d\n", __FUNCTION__, ret); ++ return ret; ++ ++ ++} ++static iw_handler r8180_wx_handlers[] = ++{ ++ NULL, /* SIOCSIWCOMMIT */ ++ r8180_wx_get_name, /* SIOCGIWNAME */ ++ dummy, /* SIOCSIWNWID */ ++ dummy, /* SIOCGIWNWID */ ++ r8180_wx_set_freq, /* SIOCSIWFREQ */ ++ r8180_wx_get_freq, /* SIOCGIWFREQ */ ++ r8180_wx_set_mode, /* SIOCSIWMODE */ ++ r8180_wx_get_mode, /* SIOCGIWMODE */ ++ r8180_wx_set_sens, /* SIOCSIWSENS */ ++ r8180_wx_get_sens, /* SIOCGIWSENS */ ++ NULL, /* SIOCSIWRANGE */ ++ rtl8180_wx_get_range, /* SIOCGIWRANGE */ ++ NULL, /* SIOCSIWPRIV */ ++ NULL, /* SIOCGIWPRIV */ ++ NULL, /* SIOCSIWSTATS */ ++ NULL, /* SIOCGIWSTATS */ ++ dummy, /* SIOCSIWSPY */ ++ dummy, /* SIOCGIWSPY */ ++ NULL, /* SIOCGIWTHRSPY */ ++ NULL, /* SIOCWIWTHRSPY */ ++ r8180_wx_set_wap, /* SIOCSIWAP */ ++ r8180_wx_get_wap, /* SIOCGIWAP */ ++ r8180_wx_set_mlme, /* SIOCSIWMLME*/ ++ dummy, /* SIOCGIWAPLIST -- depricated */ ++ r8180_wx_set_scan, /* SIOCSIWSCAN */ ++ r8180_wx_get_scan, /* SIOCGIWSCAN */ ++ r8180_wx_set_essid, /* SIOCSIWESSID */ ++ r8180_wx_get_essid, /* SIOCGIWESSID */ ++ dummy, /* SIOCSIWNICKN */ ++ dummy, /* SIOCGIWNICKN */ ++ NULL, /* -- hole -- */ ++ NULL, /* -- hole -- */ ++ r8180_wx_set_rate, /* SIOCSIWRATE */ ++ r8180_wx_get_rate, /* SIOCGIWRATE */ ++ r8180_wx_set_rts, /* SIOCSIWRTS */ ++ r8180_wx_get_rts, /* SIOCGIWRTS */ ++ r8180_wx_set_frag, /* SIOCSIWFRAG */ ++ r8180_wx_get_frag, /* SIOCGIWFRAG */ ++ dummy, /* SIOCSIWTXPOW */ ++ dummy, /* SIOCGIWTXPOW */ ++ r8180_wx_set_retry, /* SIOCSIWRETRY */ ++ r8180_wx_get_retry, /* SIOCGIWRETRY */ ++ r8180_wx_set_enc, /* SIOCSIWENCODE */ ++ r8180_wx_get_enc, /* SIOCGIWENCODE */ ++ r8180_wx_set_power, /* SIOCSIWPOWER */ ++ r8180_wx_get_power, /* SIOCGIWPOWER */ ++ NULL, /*---hole---*/ ++ NULL, /*---hole---*/ ++ r8180_wx_set_gen_ie, /* SIOCSIWGENIE */ ++ NULL, /* SIOCSIWGENIE */ ++ r8180_wx_set_auth, /* SIOCSIWAUTH */ ++ NULL, /* SIOCSIWAUTH */ ++ r8180_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ ++ NULL, /* SIOCSIWENCODEEXT */ ++ NULL, /* SIOCSIWPMKSA */ ++ NULL, /*---hole---*/ ++}; ++ ++ ++static const struct iw_priv_args r8180_private_args[] = { ++ { ++ SIOCIWFIRSTPRIV + 0x0, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" ++ }, ++ { SIOCIWFIRSTPRIV + 0x1, ++ 0, 0, "dummy" ++ ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x2, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beaconint" ++ }, ++ { SIOCIWFIRSTPRIV + 0x3, ++ 0, 0, "dummy" ++ ++ }, ++ /* added by christian */ ++ //{ ++ // SIOCIWFIRSTPRIV + 0x2, ++ // IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prismhdr" ++ //}, ++ /* end added by christian */ ++ { ++ SIOCIWFIRSTPRIV + 0x4, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" ++ ++ }, ++ { SIOCIWFIRSTPRIV + 0x5, ++ 0, 0, "dummy" ++ ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x6, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" ++ ++ }, ++ { SIOCIWFIRSTPRIV + 0x7, ++ 0, 0, "dummy" ++ ++ }, ++// { ++// SIOCIWFIRSTPRIV + 0x5, ++// 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpsmode" ++// }, ++// { ++// SIOCIWFIRSTPRIV + 0x6, ++// IW_PRIV_SIZE_FIXED, 0, "setpsmode" ++// }, ++//set/get mode have been realized in public handlers ++ ++ { ++ SIOCIWFIRSTPRIV + 0x8, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setiwmode" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x9, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 32, "getiwmode" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xA, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpreamble" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xB, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpreamble" ++ }, ++ { SIOCIWFIRSTPRIV + 0xC, ++ 0, 0, "dummy" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xD, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getrssi" ++ }, ++ { SIOCIWFIRSTPRIV + 0xE, ++ 0, 0, "dummy" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xF, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getlinkqual" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x10, ++ 0, 0, "resetstats" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x11, ++ 0,0, "dummy" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x12, ++ 0, 0, "radioon" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x13, ++ 0, 0, "radiooff" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x14, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setchannel" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x15, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x16, ++ 0,0, "dummy" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x17, ++ 0,IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 32, "getversion" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x18, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setrate" ++ }, ++}; ++ ++ ++static iw_handler r8180_private_handler[] = { ++ r8180_wx_set_crcmon, /*SIOCIWSECONDPRIV*/ ++ dummy, ++ r8180_wx_set_beaconinterval, ++ dummy, ++ //r8180_wx_set_monitor_type, ++ r8180_wx_set_scan_type, ++ dummy, ++ r8180_wx_set_rawtx, ++ dummy, ++ r8180_wx_set_iwmode, ++ r8180_wx_get_iwmode, ++ r8180_wx_set_preamble, ++ r8180_wx_get_preamble, ++ dummy, ++ r8180_wx_get_siglevel, ++ dummy, ++ r8180_wx_get_sigqual, ++ r8180_wx_reset_stats, ++ dummy,//r8180_wx_get_stats ++ r8180_wx_radio_on, ++ r8180_wx_radio_off, ++ r8180_wx_set_channelplan, ++ r8180_wx_get_channelplan, ++ dummy, ++ r8180_wx_get_version, ++ r8180_wx_set_forcerate, ++}; ++ ++#if WIRELESS_EXT >= 17 ++static inline int is_same_network(struct ieee80211_network *src, ++ struct ieee80211_network *dst, ++ struct ieee80211_device *ieee) ++{ ++ /* A network is only a duplicate if the channel, BSSID, ESSID ++ * and the capability field (in particular IBSS and BSS) all match. ++ * We treat all with the same BSSID and channel ++ * as one network */ ++ return (((src->ssid_len == dst->ssid_len)||(ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod, 080819,for hidden ap ++ //((src->ssid_len == dst->ssid_len) && ++ (src->channel == dst->channel) && ++ !memcmp(src->bssid, dst->bssid, ETH_ALEN) && ++ (!memcmp(src->ssid, dst->ssid, src->ssid_len)||(ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod, 080819,for hidden ap ++ //!memcmp(src->ssid, dst->ssid, src->ssid_len) && ++ ((src->capability & WLAN_CAPABILITY_IBSS) == ++ (dst->capability & WLAN_CAPABILITY_IBSS)) && ++ ((src->capability & WLAN_CAPABILITY_BSS) == ++ (dst->capability & WLAN_CAPABILITY_BSS))); ++} ++ ++//WB modefied to show signal to GUI on 18-01-2008 ++static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device* ieee = priv->ieee80211; ++ struct iw_statistics* wstats = &priv->wstats; ++ //struct ieee80211_network* target = NULL; ++ int tmp_level = 0; ++ int tmp_qual = 0; ++ int tmp_noise = 0; ++ //unsigned long flag; ++ ++ if (ieee->state < IEEE80211_LINKED) ++ { ++ wstats->qual.qual = 0; ++ wstats->qual.level = 0; ++ wstats->qual.noise = 0; ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++ return wstats; ++ } ++#if 0 ++ spin_lock_irqsave(&ieee->lock, flag); ++ list_for_each_entry(target, &ieee->network_list, list) ++ { ++ if (is_same_network(target, &ieee->current_network, ieee)) ++ { ++ printk("it's same network:%s\n", target->ssid); ++#if 0 ++ if (!tmp_level) ++ { ++ tmp_level = target->stats.signalstrength; ++ tmp_qual = target->stats.signal; ++ } ++ else ++ { ++ ++ tmp_level = (15*tmp_level + target->stats.signalstrength)/16; ++ tmp_qual = (15*tmp_qual + target->stats.signal)/16; ++ } ++#else ++ tmp_level = target->stats.signal; ++ tmp_qual = target->stats.signalstrength; ++ tmp_noise = target->stats.noise; ++ printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); ++#endif ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&ieee->lock, flag); ++#endif ++ tmp_level = (&ieee->current_network)->stats.signal; ++ tmp_qual = (&ieee->current_network)->stats.signalstrength; ++ tmp_noise = (&ieee->current_network)->stats.noise; ++ //printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); ++ ++// printk("level:%d\n", tmp_level); ++ wstats->qual.level = tmp_level; ++ wstats->qual.qual = tmp_qual; ++ wstats->qual.noise = tmp_noise; ++ wstats->qual.updated = IW_QUAL_ALL_UPDATED| IW_QUAL_DBM; ++ return wstats; ++} ++#endif ++ ++ ++struct iw_handler_def r8180_wx_handlers_def={ ++ .standard = r8180_wx_handlers, ++ .num_standard = sizeof(r8180_wx_handlers) / sizeof(iw_handler), ++ .private = r8180_private_handler, ++ .num_private = sizeof(r8180_private_handler) / sizeof(iw_handler), ++ .num_private_args = sizeof(r8180_private_args) / sizeof(struct iw_priv_args), ++#if WIRELESS_EXT >= 17 ++ .get_wireless_stats = r8180_get_wireless_stats, ++#endif ++ .private_args = (struct iw_priv_args *)r8180_private_args, ++}; ++ ++ +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8180_wx.h +@@ -0,0 +1,21 @@ ++/* ++ This is part of rtl8180 OpenSource driver - v 0.3 ++ Copyright (C) Andrea Merello 2004 ++ Released under the terms of GPL (General Public Licence) ++ ++ Parts of this driver are based on the GPL part of the official realtek driver ++ Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon ++ Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver ++ ++ We want to tanks the Authors of such projects and the Ndiswrapper project Authors. ++*/ ++ ++/* this file (will) contains wireless extension handlers*/ ++ ++#ifndef R8180_WX_H ++#define R8180_WX_H ++#include ++#include "ieee80211.h" ++extern struct iw_handler_def r8180_wx_handlers_def; ++ ++#endif +--- /dev/null ++++ b/drivers/staging/rtl8187se/r8185b_init.c +@@ -0,0 +1,3342 @@ ++/*++ ++Copyright (c) Realtek Semiconductor Corp. All rights reserved. ++ ++Module Name: ++ r8185b_init.c ++ ++Abstract: ++ Hardware Initialization and Hardware IO for RTL8185B ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2006-11-15 Xiong Created ++ ++Notes: ++ This file is ported from RTL8185B Windows driver. ++ ++ ++--*/ ++ ++/*--------------------------Include File------------------------------------*/ ++#include ++#include "r8180_hw.h" ++#include "r8180.h" ++#include "r8180_sa2400.h" /* PHILIPS Radio frontend */ ++#include "r8180_max2820.h" /* MAXIM Radio frontend */ ++#include "r8180_gct.h" /* GCT Radio frontend */ ++#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ ++#include "r8180_rtl8255.h" /* RTL8255 Radio frontend */ ++#include "r8180_93cx6.h" /* Card EEPROM */ ++#include "r8180_wx.h" ++ ++#ifdef CONFIG_RTL8180_PM ++#include "r8180_pm.h" ++#endif ++ ++#ifdef ENABLE_DOT11D ++#include "dot11d.h" ++#endif ++ ++#ifdef CONFIG_RTL8185B ++ ++//#define CONFIG_RTL8180_IO_MAP ++ ++#define TC_3W_POLL_MAX_TRY_CNT 5 ++#ifdef CONFIG_RTL818X_S ++static u8 MAC_REG_TABLE[][2]={ ++ //PAGA 0: ++ // 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() ++ // 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). ++ // 0x1F0~0x1F8 set in MacConfig_85BASIC() ++ {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42}, ++ {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03}, ++ {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03}, ++ {0x94, 0x0F}, {0x95, 0x32}, ++ {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00}, ++ {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, ++ {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, ++ {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, ++ {0xff, 0x00}, ++ ++ //PAGE 1: ++ // For Flextronics system Logo PCIHCT failure: ++ // 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 ++ {0x5e, 0x01}, ++ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24}, ++ {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF}, ++ {0x82, 0xFF}, {0x83, 0x03}, ++ {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, //lzm add 080826 ++ {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22},//lzm add 080826 ++ {0xe2, 0x00}, ++ ++ ++ //PAGE 2: ++ {0x5e, 0x02}, ++ {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5}, ++ {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff}, ++ {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08}, ++ {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f}, ++ {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f}, ++ {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff}, ++ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00}, ++ ++ //PAGA 0: ++ {0x5e, 0x00},{0x9f, 0x03} ++ }; ++ ++ ++static u8 ZEBRA_AGC[]={ ++ 0, ++ 0x7E,0x7E,0x7E,0x7E,0x7D,0x7C,0x7B,0x7A,0x79,0x78,0x77,0x76,0x75,0x74,0x73,0x72, ++ 0x71,0x70,0x6F,0x6E,0x6D,0x6C,0x6B,0x6A,0x69,0x68,0x67,0x66,0x65,0x64,0x63,0x62, ++ 0x48,0x47,0x46,0x45,0x44,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x08,0x07, ++ 0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, ++ 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x10,0x11,0x12,0x13,0x15,0x16, ++ 0x17,0x17,0x18,0x18,0x19,0x1a,0x1a,0x1b,0x1b,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e, ++ 0x1f,0x1f,0x1f,0x20,0x20,0x20,0x20,0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x24, ++ 0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F,0x2F ++ }; ++ ++static u32 ZEBRA_RF_RX_GAIN_TABLE[]={ ++ 0x0096,0x0076,0x0056,0x0036,0x0016,0x01f6,0x01d6,0x01b6, ++ 0x0196,0x0176,0x00F7,0x00D7,0x00B7,0x0097,0x0077,0x0057, ++ 0x0037,0x00FB,0x00DB,0x00BB,0x00FF,0x00E3,0x00C3,0x00A3, ++ 0x0083,0x0063,0x0043,0x0023,0x0003,0x01E3,0x01C3,0x01A3, ++ 0x0183,0x0163,0x0143,0x0123,0x0103 ++ }; ++ ++static u8 OFDM_CONFIG[]={ ++ // OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX ++ // OFDM reg0x3C[4]=1'b1: Enable RX power saving mode ++ // ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test ++ ++ // 0x00 ++ 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50, ++ 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, ++ // 0x10 ++ 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26, ++ 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB, ++ // 0x20 ++ 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00, ++ 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00, ++ // 0x30 ++ 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e, ++ 0xD8, 0x3C, 0x7B, 0x10, 0x10 ++ }; ++#else ++ static u8 MAC_REG_TABLE[][2]={ ++ //PAGA 0: ++ {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, ++ {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, ++ {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, ++ {0xff, 0x00}, ++ ++ //PAGE 1: ++ {0x5e, 0x01}, ++ {0x58, 0x4b}, {0x59, 0x00}, {0x5a, 0x4b}, {0x5b, 0x00}, {0x60, 0x4b}, ++ {0x61, 0x09}, {0x62, 0x4b}, {0x63, 0x09}, {0xce, 0x0f}, {0xcf, 0x00}, ++ {0xe0, 0xff}, {0xe1, 0x0f}, {0xe2, 0x00}, {0xf0, 0x4e}, {0xf1, 0x01}, ++ {0xf2, 0x02}, {0xf3, 0x03}, {0xf4, 0x04}, {0xf5, 0x05}, {0xf6, 0x06}, ++ {0xf7, 0x07}, {0xf8, 0x08}, ++ ++ ++ //PAGE 2: ++ {0x5e, 0x02}, ++ {0x0c, 0x04}, {0x21, 0x61}, {0x22, 0x68}, {0x23, 0x6f}, {0x24, 0x76}, ++ {0x25, 0x7d}, {0x26, 0x84}, {0x27, 0x8d}, {0x4d, 0x08}, {0x4e, 0x00}, ++ {0x50, 0x05}, {0x51, 0xf5}, {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0x1f}, ++ {0x55, 0x23}, {0x56, 0x45}, {0x57, 0x67}, {0x58, 0x08}, {0x59, 0x08}, ++ {0x5a, 0x08}, {0x5b, 0x08}, {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, ++ {0x63, 0x08}, {0x64, 0xcf}, {0x72, 0x56}, {0x73, 0x9a}, ++ ++ //PAGA 0: ++ {0x5e, 0x00}, ++ {0x34, 0xff}, {0x35, 0x0f}, {0x5b, 0x40}, {0x84, 0x88}, {0x85, 0x24}, ++ {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x07}, {0x8d, 0x00}, {0x94, 0x1b}, ++ {0x95, 0x12}, {0x96, 0x00}, {0x97, 0x06}, {0x9d, 0x1a}, {0x9f, 0x10}, ++ {0xb4, 0x22}, {0xbe, 0x80}, {0xdb, 0x00}, {0xee, 0x00}, {0x5b, 0x42}, ++ {0x91, 0x03}, ++ ++ //PAGE 2: ++ {0x5e, 0x02}, ++ {0x4c, 0x03}, ++ ++ //PAGE 0: ++ {0x5e, 0x00}, ++ ++ //PAGE 3: ++ {0x5e, 0x03}, ++ {0x9f, 0x00}, ++ ++ //PAGE 0: ++ {0x5e, 0x00}, ++ {0x8c, 0x01}, {0x8d, 0x10},{0x8e, 0x08}, {0x8f, 0x00} ++ }; ++ ++ ++static u8 ZEBRA_AGC[]={ ++ 0, ++ 0x5e,0x5e,0x5e,0x5e,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4d,0x4b,0x49,0x47, ++ 0x45,0x43,0x41,0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2d,0x2b,0x29,0x27, ++ 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0d,0x0b,0x09,0x07, ++ 0x05,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, ++ 0x19,0x19,0x19,0x019,0x19,0x19,0x19,0x19,0x19,0x19,0x1e,0x1f,0x20,0x21,0x21,0x22, ++ 0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x27,0x27,0x28,0x28,0x28,0x29,0x2a,0x2a,0x2b, ++ 0x2b,0x2b,0x2c,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2f,0x30,0x31,0x31,0x31,0x31, ++ 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31 ++ }; ++ ++static u32 ZEBRA_RF_RX_GAIN_TABLE[]={ ++ 0, ++ 0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0408,0x0409, ++ 0x040a,0x040b,0x0502,0x0503,0x0504,0x0505,0x0540,0x0541, ++ 0x0542,0x0543,0x0544,0x0545,0x0580,0x0581,0x0582,0x0583, ++ 0x0584,0x0585,0x0588,0x0589,0x058a,0x058b,0x0643,0x0644, ++ 0x0645,0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0688, ++ 0x0689,0x068a,0x068b,0x068c,0x0742,0x0743,0x0744,0x0745, ++ 0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0788,0x0789, ++ 0x078a,0x078b,0x078c,0x078d,0x0790,0x0791,0x0792,0x0793, ++ 0x0794,0x0795,0x0798,0x0799,0x079a,0x079b,0x079c,0x079d, ++ 0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a8,0x07a9, ++ 0x03aa,0x03ab,0x03ac,0x03ad,0x03b0,0x03b1,0x03b2,0x03b3, ++ 0x03b4,0x03b5,0x03b8,0x03b9,0x03ba,0x03bb,0x03bb ++}; ++ ++// 2006.07.13, SD3 szuyitasi: ++// OFDM.0x03=0x0C (original is 0x0F) ++// Use the new SD3 given param, by shien chang, 2006.07.14 ++static u8 OFDM_CONFIG[]={ ++ 0x10, 0x0d, 0x01, 0x0C, 0x14, 0xfb, 0x0f, 0x60, 0x00, 0x60, ++ 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, ++ 0x00, 0x00, 0xa8, 0x46, 0xb2, 0x33, 0x07, 0xa5, 0x6f, 0x55, ++ 0xc8, 0xb3, 0x0a, 0xe1, 0x1c, 0x8a, 0xb6, 0x83, 0x34, 0x0f, ++ 0x4f, 0x23, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, 0xc0, 0xc1, ++ 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, 0x6d, 0x3c, 0xff, 0x07 ++}; ++#endif ++ ++/*--------------------------------------------------------------- ++ * Hardware IO ++ * the code is ported from Windows source code ++ ----------------------------------------------------------------*/ ++ ++void ++PlatformIOWrite1Byte( ++ struct net_device *dev, ++ u32 offset, ++ u8 data ++ ) ++{ ++#ifndef CONFIG_RTL8180_IO_MAP ++ write_nic_byte(dev, offset, data); ++ read_nic_byte(dev, offset); // To make sure write operation is completed, 2005.11.09, by rcnjko. ++ ++#else // Port IO ++ u32 Page = (offset >> 8); ++ ++ switch(Page) ++ { ++ case 0: // Page 0 ++ write_nic_byte(dev, offset, data); ++ break; ++ ++ case 1: // Page 1 ++ case 2: // Page 2 ++ case 3: // Page 3 ++ { ++ u8 psr = read_nic_byte(dev, PSR); ++ ++ write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. ++ write_nic_byte(dev, (offset & 0xff), data); ++ write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. ++ } ++ break; ++ ++ default: ++ // Illegal page number. ++ DMESGE("PlatformIOWrite1Byte(): illegal page number: %d, offset: %#X", Page, offset); ++ break; ++ } ++#endif ++} ++ ++void ++PlatformIOWrite2Byte( ++ struct net_device *dev, ++ u32 offset, ++ u16 data ++ ) ++{ ++#ifndef CONFIG_RTL8180_IO_MAP ++ write_nic_word(dev, offset, data); ++ read_nic_word(dev, offset); // To make sure write operation is completed, 2005.11.09, by rcnjko. ++ ++ ++#else // Port IO ++ u32 Page = (offset >> 8); ++ ++ switch(Page) ++ { ++ case 0: // Page 0 ++ write_nic_word(dev, offset, data); ++ break; ++ ++ case 1: // Page 1 ++ case 2: // Page 2 ++ case 3: // Page 3 ++ { ++ u8 psr = read_nic_byte(dev, PSR); ++ ++ write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. ++ write_nic_word(dev, (offset & 0xff), data); ++ write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. ++ } ++ break; ++ ++ default: ++ // Illegal page number. ++ DMESGE("PlatformIOWrite2Byte(): illegal page number: %d, offset: %#X", Page, offset); ++ break; ++ } ++#endif ++} ++u8 PlatformIORead1Byte(struct net_device *dev, u32 offset); ++ ++void ++PlatformIOWrite4Byte( ++ struct net_device *dev, ++ u32 offset, ++ u32 data ++ ) ++{ ++#ifndef CONFIG_RTL8180_IO_MAP ++//{by amy 080312 ++if (offset == PhyAddr) ++ {//For Base Band configuration. ++ unsigned char cmdByte; ++ unsigned long dataBytes; ++ unsigned char idx; ++ u8 u1bTmp; ++ ++ cmdByte = (u8)(data & 0x000000ff); ++ dataBytes = data>>8; ++ ++ // ++ // 071010, rcnjko: ++ // The critical section is only BB read/write race condition. ++ // Assumption: ++ // 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for ++ // acquiring the spinlock in such context. ++ // 2. PlatformIOWrite4Byte() MUST NOT be recursive. ++ // ++// NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); ++ ++ for(idx = 0; idx < 30; idx++) ++ { // Make sure command bit is clear before access it. ++ u1bTmp = PlatformIORead1Byte(dev, PhyAddr); ++ if((u1bTmp & BIT7) == 0) ++ break; ++ else ++ mdelay(10); ++ } ++ ++ for(idx=0; idx < 3; idx++) ++ { ++ PlatformIOWrite1Byte(dev,offset+1+idx,((u8*)&dataBytes)[idx] ); ++ } ++ write_nic_byte(dev, offset, cmdByte); ++ ++// NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); ++ } ++//by amy 080312} ++ else{ ++ write_nic_dword(dev, offset, data); ++ read_nic_dword(dev, offset); // To make sure write operation is completed, 2005.11.09, by rcnjko. ++ } ++#else // Port IO ++ u32 Page = (offset >> 8); ++ ++ switch(Page) ++ { ++ case 0: // Page 0 ++ write_nic_word(dev, offset, data); ++ break; ++ ++ case 1: // Page 1 ++ case 2: // Page 2 ++ case 3: // Page 3 ++ { ++ u8 psr = read_nic_byte(dev, PSR); ++ ++ write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. ++ write_nic_dword(dev, (offset & 0xff), data); ++ write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. ++ } ++ break; ++ ++ default: ++ // Illegal page number. ++ DMESGE("PlatformIOWrite4Byte(): illegal page number: %d, offset: %#X", Page, offset); ++ break; ++ } ++#endif ++} ++ ++u8 ++PlatformIORead1Byte( ++ struct net_device *dev, ++ u32 offset ++ ) ++{ ++ u8 data = 0; ++ ++#ifndef CONFIG_RTL8180_IO_MAP ++ data = read_nic_byte(dev, offset); ++ ++#else // Port IO ++ u32 Page = (offset >> 8); ++ ++ switch(Page) ++ { ++ case 0: // Page 0 ++ data = read_nic_byte(dev, offset); ++ break; ++ ++ case 1: // Page 1 ++ case 2: // Page 2 ++ case 3: // Page 3 ++ { ++ u8 psr = read_nic_byte(dev, PSR); ++ ++ write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. ++ data = read_nic_byte(dev, (offset & 0xff)); ++ write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. ++ } ++ break; ++ ++ default: ++ // Illegal page number. ++ DMESGE("PlatformIORead1Byte(): illegal page number: %d, offset: %#X", Page, offset); ++ break; ++ } ++#endif ++ ++ return data; ++} ++ ++u16 ++PlatformIORead2Byte( ++ struct net_device *dev, ++ u32 offset ++ ) ++{ ++ u16 data = 0; ++ ++#ifndef CONFIG_RTL8180_IO_MAP ++ data = read_nic_word(dev, offset); ++ ++#else // Port IO ++ u32 Page = (offset >> 8); ++ ++ switch(Page) ++ { ++ case 0: // Page 0 ++ data = read_nic_word(dev, offset); ++ break; ++ ++ case 1: // Page 1 ++ case 2: // Page 2 ++ case 3: // Page 3 ++ { ++ u8 psr = read_nic_byte(dev, PSR); ++ ++ write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. ++ data = read_nic_word(dev, (offset & 0xff)); ++ write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. ++ } ++ break; ++ ++ default: ++ // Illegal page number. ++ DMESGE("PlatformIORead2Byte(): illegal page number: %d, offset: %#X", Page, offset); ++ break; ++ } ++#endif ++ ++ return data; ++} ++ ++u32 ++PlatformIORead4Byte( ++ struct net_device *dev, ++ u32 offset ++ ) ++{ ++ u32 data = 0; ++ ++#ifndef CONFIG_RTL8180_IO_MAP ++ data = read_nic_dword(dev, offset); ++ ++#else // Port IO ++ u32 Page = (offset >> 8); ++ ++ switch(Page) ++ { ++ case 0: // Page 0 ++ data = read_nic_dword(dev, offset); ++ break; ++ ++ case 1: // Page 1 ++ case 2: // Page 2 ++ case 3: // Page 3 ++ { ++ u8 psr = read_nic_byte(dev, PSR); ++ ++ write_nic_byte(dev, PSR, ((psr & 0xfc) | (u8)Page)); // Switch to page N. ++ data = read_nic_dword(dev, (offset & 0xff)); ++ write_nic_byte(dev, PSR, (psr & 0xfc)); // Switch to page 0. ++ } ++ break; ++ ++ default: ++ // Illegal page number. ++ DMESGE("PlatformIORead4Byte(): illegal page number: %d, offset: %#X\n", Page, offset); ++ break; ++ } ++#endif ++ ++ return data; ++} ++ ++void ++SetOutputEnableOfRfPins( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ switch(priv->rf_chip) ++ { ++ case RFCHIPID_RTL8225: ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++ write_nic_word(dev, RFPinsEnable, 0x1bff); ++ //write_nic_word(dev, RFPinsEnable, 0x1fff); ++ break; ++ } ++} ++ ++void ++ZEBRA_RFSerialWrite( ++ struct net_device *dev, ++ u32 data2Write, ++ u8 totalLength, ++ u8 low2high ++ ) ++{ ++ ThreeWireReg twreg; ++ int i; ++ u16 oval,oval2,oval3; ++ u32 mask; ++ u16 UshortBuffer; ++ ++ u8 u1bTmp; ++#ifdef CONFIG_RTL818X_S ++ // RTL8187S HSSI Read/Write Function ++ u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); ++ u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI) ++ write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); ++#endif ++ UshortBuffer = read_nic_word(dev, RFPinsOutput); ++ oval = UshortBuffer & 0xfff8; // We shall clear bit0, 1, 2 first, 2005.10.28, by rcnjko. ++ ++ oval2 = read_nic_word(dev, RFPinsEnable); ++ oval3 = read_nic_word(dev, RFPinsSelect); ++ ++ // 3-wire should be controled by HW when we finish SW 3-wire programming. 2005.08.10, by rcnjko. ++ oval3 &= 0xfff8; ++ ++ write_nic_word(dev, RFPinsEnable, (oval2|0x0007)); // Set To Output Enable ++ write_nic_word(dev, RFPinsSelect, (oval3|0x0007)); // Set To SW Switch ++ udelay(10); ++ ++ // Add this to avoid hardware and software 3-wire conflict. ++ // 2005.03.01, by rcnjko. ++ twreg.longData = 0; ++ twreg.struc.enableB = 1; ++ write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); // Set SI_EN (RFLE) ++ udelay(2); ++ twreg.struc.enableB = 0; ++ write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); // Clear SI_EN (RFLE) ++ udelay(10); ++ ++ mask = (low2high)?0x01:((u32)0x01<<(totalLength-1)); ++ ++ for(i=0; i>1); ++ twreg.struc.data = ((data2Write&mask)!=0) ? 1 : 0; ++ write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); ++ write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); ++ twreg.struc.clk = 0; ++ write_nic_word(dev, RFPinsOutput, (twreg.longData|oval)); ++ mask = (low2high)?(mask<<1):(mask>>1); ++ } ++ ++ twreg.struc.enableB = 1; ++ twreg.struc.clk = 0; ++ twreg.struc.data = 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); ++ udelay(10); ++ ++ write_nic_word(dev, RFPinsOutput, oval|0x0004); ++ write_nic_word(dev, RFPinsSelect, oval3|0x0000); ++ ++ SetOutputEnableOfRfPins(dev); ++} ++//by amy ++ ++ ++int ++HwHSSIThreeWire( ++ struct net_device *dev, ++ u8 *pDataBuf, ++ u8 nDataBufBitCnt, ++ int bSI, ++ int bWrite ++ ) ++{ ++ int bResult = 1; ++ u8 TryCnt; ++ u8 u1bTmp; ++ ++ do ++ { ++ // Check if WE and RE are cleared. ++ for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) ++ { ++ u1bTmp = read_nic_byte(dev, SW_3W_CMD1); ++ if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 ) ++ { ++ break; ++ } ++ udelay(10); ++ } ++ if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) ++ panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp); ++ ++ // RTL8187S HSSI Read/Write Function ++ u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); ++ ++ if(bSI) ++ { ++ u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI) ++ }else ++ { ++ u1bTmp &= ~RF_SW_CFG_SI; //reg08[1]=0 Parallel Interface(PI) ++ } ++ ++ write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); ++ ++ if(bSI) ++ { ++ // jong: HW SI read must set reg84[3]=0. ++ u1bTmp = read_nic_byte(dev, RFPinsSelect); ++ u1bTmp &= ~BIT3; ++ write_nic_byte(dev, RFPinsSelect, u1bTmp ); ++ } ++ // Fill up data buffer for write operation. ++ ++ if(bWrite) ++ { ++ if(nDataBufBitCnt == 16) ++ { ++ write_nic_word(dev, SW_3W_DB0, *((u16*)pDataBuf)); ++ } ++ else if(nDataBufBitCnt == 64) // RTL8187S shouldn't enter this case ++ { ++ write_nic_dword(dev, SW_3W_DB0, *((u32*)pDataBuf)); ++ write_nic_dword(dev, SW_3W_DB1, *((u32*)(pDataBuf + 4))); ++ } ++ else ++ { ++ int idx; ++ int ByteCnt = nDataBufBitCnt / 8; ++ //printk("%d\n",nDataBufBitCnt); ++ if ((nDataBufBitCnt % 8) != 0) ++ panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", ++ nDataBufBitCnt); ++ ++ if (nDataBufBitCnt > 64) ++ panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", ++ nDataBufBitCnt); ++ ++ for(idx = 0; idx < ByteCnt; idx++) ++ { ++ write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx)); ++ } ++ } ++ } ++ else //read ++ { ++ if(bSI) ++ { ++ // SI - reg274[3:0] : RF register's Address ++ write_nic_word(dev, SW_3W_DB0, *((u16*)pDataBuf) ); ++ } ++ else ++ { ++ // PI - reg274[15:12] : RF register's Address ++ write_nic_word(dev, SW_3W_DB0, (*((u16*)pDataBuf)) << 12); ++ } ++ } ++ ++ // Set up command: WE or RE. ++ if(bWrite) ++ { ++ write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_WE); ++ } ++ else ++ { ++ write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_RE); ++ } ++ ++ // Check if DONE is set. ++ for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) ++ { ++ u1bTmp = read_nic_byte(dev, SW_3W_CMD1); ++ if( (u1bTmp & SW_3W_CMD1_DONE) != 0 ) ++ { ++ break; ++ } ++ udelay(10); ++ } ++ ++ write_nic_byte(dev, SW_3W_CMD1, 0); ++ ++ // Read back data for read operation. ++ if(bWrite == 0) ++ { ++ if(bSI) ++ { ++ //Serial Interface : reg363_362[11:0] ++ *((u16*)pDataBuf) = read_nic_word(dev, SI_DATA_READ) ; ++ } ++ else ++ { ++ //Parallel Interface : reg361_360[11:0] ++ *((u16*)pDataBuf) = read_nic_word(dev, PI_DATA_READ); ++ } ++ ++ *((u16*)pDataBuf) &= 0x0FFF; ++ } ++ ++ }while(0); ++ ++ return bResult; ++} ++//by amy ++ ++int ++HwThreeWire( ++ struct net_device *dev, ++ u8 *pDataBuf, ++ u8 nDataBufBitCnt, ++ int bHold, ++ int bWrite ++ ) ++{ ++ int bResult = 1; ++ u8 TryCnt; ++ u8 u1bTmp; ++ ++ do ++ { ++ // Check if WE and RE are cleared. ++ for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) ++ { ++ u1bTmp = read_nic_byte(dev, SW_3W_CMD1); ++ if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 ) ++ { ++ break; ++ } ++ udelay(10); ++ } ++ if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) ++ panic("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", u1bTmp); ++ ++ // Fill up data buffer for write operation. ++ if(nDataBufBitCnt == 16) ++ { ++ write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf)); ++ } ++ else if(nDataBufBitCnt == 64) ++ { ++ write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf)); ++ write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4))); ++ } ++ else ++ { ++ int idx; ++ int ByteCnt = nDataBufBitCnt / 8; ++ ++ if ((nDataBufBitCnt % 8) != 0) ++ panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", ++ nDataBufBitCnt); ++ ++ if (nDataBufBitCnt > 64) ++ panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", ++ nDataBufBitCnt); ++ ++ for(idx = 0; idx < ByteCnt; idx++) ++ { ++ write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx)); ++ } ++ } ++ ++ // Fill up length field. ++ u1bTmp = (u8)(nDataBufBitCnt - 1); // Number of bits - 1. ++ if(bHold) ++ u1bTmp |= SW_3W_CMD0_HOLD; ++ write_nic_byte(dev, SW_3W_CMD0, u1bTmp); ++ ++ // Set up command: WE or RE. ++ if(bWrite) ++ { ++ write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_WE); ++ } ++ else ++ { ++ write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_RE); ++ } ++ ++ // Check if WE and RE are cleared and DONE is set. ++ for(TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) ++ { ++ u1bTmp = read_nic_byte(dev, SW_3W_CMD1); ++ if( (u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0 && ++ (u1bTmp & SW_3W_CMD1_DONE) != 0 ) ++ { ++ break; ++ } ++ udelay(10); ++ } ++ if(TryCnt == TC_3W_POLL_MAX_TRY_CNT) ++ { ++ //RT_ASSERT(TryCnt != TC_3W_POLL_MAX_TRY_CNT, ++ // ("HwThreeWire(): CmdReg: %#X RE|WE bits are not clear or DONE is not set!!\n", u1bTmp)); ++ // Workaround suggested by wcchu: clear WE here. 2006.07.07, by rcnjko. ++ write_nic_byte(dev, SW_3W_CMD1, 0); ++ } ++ ++ // Read back data for read operation. ++ // I am not sure if this is correct output format of a read operation. ++ if(bWrite == 0) ++ { ++ if(nDataBufBitCnt == 16) ++ { ++ *((u16 *)pDataBuf) = read_nic_word(dev, SW_3W_DB0); ++ } ++ else if(nDataBufBitCnt == 64) ++ { ++ *((u32 *)pDataBuf) = read_nic_dword(dev, SW_3W_DB0); ++ *((u32 *)(pDataBuf + 4)) = read_nic_dword(dev, SW_3W_DB1); ++ } ++ else ++ { ++ int idx; ++ int ByteCnt = nDataBufBitCnt / 8; ++ ++ if ((nDataBufBitCnt % 8) != 0) ++ panic("HwThreeWire(): nDataBufBitCnt(%d) should be multiple of 8!!!\n", ++ nDataBufBitCnt); ++ ++ if (nDataBufBitCnt > 64) ++ panic("HwThreeWire(): nDataBufBitCnt(%d) should <= 64!!!\n", ++ nDataBufBitCnt); ++ ++ for(idx = 0; idx < ByteCnt; idx++) ++ { ++ *(pDataBuf+idx) = read_nic_byte(dev, (SW_3W_DB0+idx)); ++ } ++ } ++ } ++ ++ }while(0); ++ ++ return bResult; ++} ++ ++ ++void ++RF_WriteReg( ++ struct net_device *dev, ++ u8 offset, ++ u32 data ++ ) ++{ ++ //RFReg reg; ++ u32 data2Write; ++ u8 len; ++ u8 low2high; ++ //u32 RF_Read = 0; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ ++ switch(priv->rf_chip) ++ { ++ case RFCHIPID_RTL8225: ++ case RF_ZEBRA2: // Annie 2006-05-12. ++ case RF_ZEBRA4: //by amy ++ switch(priv->RegThreeWireMode) ++ { ++ case SW_THREE_WIRE: ++ { // Perform SW 3-wire programming by driver. ++ data2Write = (data << 4) | (u32)(offset & 0x0f); ++ len = 16; ++ low2high = 0; ++ ZEBRA_RFSerialWrite(dev, data2Write, len, low2high); ++ } ++ break; ++ ++ case HW_THREE_WIRE: ++ { // Pure HW 3-wire. ++ data2Write = (data << 4) | (u32)(offset & 0x0f); ++ len = 16; ++ HwThreeWire( ++ dev, ++ (u8 *)(&data2Write), // pDataBuf, ++ len, // nDataBufBitCnt, ++ 0, // bHold, ++ 1); // bWrite ++ } ++ break; ++ #ifdef CONFIG_RTL818X_S ++ case HW_THREE_WIRE_PI: //Parallel Interface ++ { // Pure HW 3-wire. ++ data2Write = (data << 4) | (u32)(offset & 0x0f); ++ len = 16; ++ HwHSSIThreeWire( ++ dev, ++ (u8*)(&data2Write), // pDataBuf, ++ len, // nDataBufBitCnt, ++ 0, // bSI ++ 1); // bWrite ++ ++ //printk("33333\n"); ++ } ++ break; ++ ++ case HW_THREE_WIRE_SI: //Serial Interface ++ { // Pure HW 3-wire. ++ data2Write = (data << 4) | (u32)(offset & 0x0f); ++ len = 16; ++// printk(" enter ZEBRA_RFSerialWrite\n "); ++// low2high = 0; ++// ZEBRA_RFSerialWrite(dev, data2Write, len, low2high); ++ ++ HwHSSIThreeWire( ++ dev, ++ (u8*)(&data2Write), // pDataBuf, ++ len, // nDataBufBitCnt, ++ 1, // bSI ++ 1); // bWrite ++ ++// printk(" exit ZEBRA_RFSerialWrite\n "); ++ } ++ break; ++ #endif ++ ++ ++ default: ++ DMESGE("RF_WriteReg(): invalid RegThreeWireMode(%d) !!!", priv->RegThreeWireMode); ++ break; ++ } ++ break; ++ ++ default: ++ DMESGE("RF_WriteReg(): unknown RFChipID: %#X", priv->rf_chip); ++ break; ++ } ++} ++ ++ ++void ++ZEBRA_RFSerialRead( ++ struct net_device *dev, ++ u32 data2Write, ++ u8 wLength, ++ u32 *data2Read, ++ u8 rLength, ++ u8 low2high ++ ) ++{ ++ ThreeWireReg twreg; ++ int i; ++ u16 oval,oval2,oval3,tmp, wReg80; ++ u32 mask; ++ u8 u1bTmp; ++ ThreeWireReg tdata; ++ //PHAL_DATA_8187 pHalData = GetHalData8187(pAdapter); ++#ifdef CONFIG_RTL818X_S ++ { // RTL8187S HSSI Read/Write Function ++ u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); ++ u1bTmp |= RF_SW_CFG_SI; //reg08[1]=1 Serial Interface(SI) ++ write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); ++ } ++#endif ++ ++ wReg80 = oval = read_nic_word(dev, RFPinsOutput); ++ oval2 = read_nic_word(dev, RFPinsEnable); ++ oval3 = read_nic_word(dev, RFPinsSelect); ++ ++ write_nic_word(dev, RFPinsEnable, oval2|0xf); ++ write_nic_word(dev, RFPinsSelect, oval3|0xf); ++ ++ *data2Read = 0; ++ ++ // We must clear BIT0-3 here, otherwise, ++ // SW_Enalbe will be true when we first call ZEBRA_RFSerialRead() after 8187MPVC open, ++ // which will cause the value read become 0. 2005.04.11, by rcnjko. ++ oval &= ~0xf; ++ ++ // Avoid collision with hardware three-wire. ++ twreg.longData = 0; ++ twreg.struc.enableB = 1; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(4); ++ ++ twreg.longData = 0; ++ twreg.struc.enableB = 0; ++ twreg.struc.clk = 0; ++ twreg.struc.read_write = 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(5); ++ ++ mask = (low2high) ? 0x01 : ((u32)0x01<<(32-1)); ++ for(i = 0; i < wLength/2; i++) ++ { ++ twreg.struc.data = ((data2Write&mask) != 0) ? 1 : 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1); ++ twreg.struc.clk = 1; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ ++ mask = (low2high) ? (mask<<1): (mask>>1); ++ ++ if(i == 2) ++ { ++ // Commented out by Jackie, 2004.08.26. We must comment out the following two lines for we cannot pull down VCOPDN during RF Serail Read. ++ //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, 0xe); // turn off data enable ++ //PlatformEFIOWrite2Byte(pAdapter, RFPinsSelect, 0xe); ++ ++ twreg.struc.read_write=1; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ twreg.struc.clk = 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ break; ++ } ++ twreg.struc.data = ((data2Write&mask) != 0) ? 1: 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ ++ twreg.struc.clk = 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1); ++ ++ mask = (low2high) ? (mask<<1) : (mask>>1); ++ } ++ ++ twreg.struc.clk = 0; ++ twreg.struc.data = 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ mask = (low2high) ? 0x01 : ((u32)0x01 << (12-1)); ++ ++ // ++ // 061016, by rcnjko: ++ // We must set data pin to HW controled, otherwise RF can't driver it and ++ // value RF register won't be able to read back properly. ++ // ++ write_nic_word(dev, RFPinsEnable, ( ((oval2|0x0E) & (~0x01))) ); ++ ++ for(i = 0; i < rLength; i++) ++ { ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(1); ++ twreg.struc.clk = 1; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ tmp = read_nic_word(dev, RFPinsInput); ++ tdata.longData = tmp; ++ *data2Read |= tdata.struc.clk ? mask : 0; ++ ++ twreg.struc.clk = 0; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ ++ mask = (low2high) ? (mask<<1) : (mask>>1); ++ } ++ twreg.struc.enableB = 1; ++ twreg.struc.clk = 0; ++ twreg.struc.data = 0; ++ twreg.struc.read_write = 1; ++ write_nic_word(dev, RFPinsOutput, twreg.longData|oval); udelay(2); ++ ++ //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, oval2|0x8); // Set To Output Enable ++ write_nic_word(dev, RFPinsEnable, oval2); // Set To Output Enable, We cannot enable BIT3 here, otherwise, we will failed to switch channel. 2005.04.12. ++ //PlatformEFIOWrite2Byte(pAdapter, RFPinsEnable, 0x1bff); ++ write_nic_word(dev, RFPinsSelect, oval3); // Set To SW Switch ++ //PlatformEFIOWrite2Byte(pAdapter, RFPinsSelect, 0x0488); ++ write_nic_word(dev, RFPinsOutput, 0x3a0); ++ //PlatformEFIOWrite2Byte(pAdapter, RFPinsOutput, 0x0480); ++} ++ ++ ++u32 ++RF_ReadReg( ++ struct net_device *dev, ++ u8 offset ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 data2Write; ++ u8 wlen; ++ u8 rlen; ++ u8 low2high; ++ u32 dataRead; ++ ++ switch(priv->rf_chip) ++ { ++ case RFCHIPID_RTL8225: ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++ switch(priv->RegThreeWireMode) ++ { ++#ifdef CONFIG_RTL818X_S ++ case HW_THREE_WIRE_PI: // For 87S Parallel Interface. ++ { ++ data2Write = ((u32)(offset&0x0f)); ++ wlen=16; ++ HwHSSIThreeWire( ++ dev, ++ (u8*)(&data2Write), // pDataBuf, ++ wlen, // nDataBufBitCnt, ++ 0, // bSI ++ 0); // bWrite ++ dataRead= data2Write; ++ } ++ break; ++ ++ case HW_THREE_WIRE_SI: // For 87S Serial Interface. ++ { ++ data2Write = ((u32)(offset&0x0f)) ; ++ wlen=16; ++ HwHSSIThreeWire( ++ dev, ++ (u8*)(&data2Write), // pDataBuf, ++ wlen, // nDataBufBitCnt, ++ 1, // bSI ++ 0 // bWrite ++ ); ++ dataRead= data2Write; ++ } ++ break; ++ ++#endif ++ // Perform SW 3-wire programming by driver. ++ default: ++ { ++ data2Write = ((u32)(offset&0x1f)) << 27; // For Zebra E-cut. 2005.04.11, by rcnjko. ++ wlen = 6; ++ rlen = 12; ++ low2high = 0; ++ ZEBRA_RFSerialRead(dev, data2Write, wlen,&dataRead,rlen, low2high); ++ } ++ break; ++ } ++ break; ++ default: ++ dataRead = 0; ++ break; ++ } ++ ++ return dataRead; ++} ++ ++ ++// by Owen on 04/07/14 for writing BB register successfully ++void ++WriteBBPortUchar( ++ struct net_device *dev, ++ u32 Data ++ ) ++{ ++ //u8 TimeoutCounter; ++ u8 RegisterContent; ++ u8 UCharData; ++ ++ UCharData = (u8)((Data & 0x0000ff00) >> 8); ++ PlatformIOWrite4Byte(dev, PhyAddr, Data); ++ //for(TimeoutCounter = 10; TimeoutCounter > 0; TimeoutCounter--) ++ { ++ PlatformIOWrite4Byte(dev, PhyAddr, Data & 0xffffff7f); ++ RegisterContent = PlatformIORead1Byte(dev, PhyDataR); ++ //if(UCharData == RegisterContent) ++ // break; ++ } ++} ++ ++u8 ++ReadBBPortUchar( ++ struct net_device *dev, ++ u32 addr ++ ) ++{ ++ //u8 TimeoutCounter; ++ u8 RegisterContent; ++ ++ PlatformIOWrite4Byte(dev, PhyAddr, addr & 0xffffff7f); ++ RegisterContent = PlatformIORead1Byte(dev, PhyDataR); ++ ++ return RegisterContent; ++} ++//{by amy 080312 ++#ifdef CONFIG_RTL818X_S ++// ++// Description: ++// Perform Antenna settings with antenna diversity on 87SE. ++// Created by Roger, 2008.01.25. ++// ++bool ++SetAntennaConfig87SE( ++ struct net_device *dev, ++ u8 DefaultAnt, // 0: Main, 1: Aux. ++ bool bAntDiversity // 1:Enable, 0: Disable. ++) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bAntennaSwitched = true; ++ ++ //printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", DefaultAnt, bAntDiversity); ++ ++ // Threshold for antenna diversity. ++ write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 ++ ++ if( bAntDiversity ) // Enable Antenna Diversity. ++ { ++ if( DefaultAnt == 1 ) // aux antenna ++ { ++ // Mac register, aux antenna ++ write_nic_byte(dev, ANTSEL, 0x00); ++ ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb ++ write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 ++ ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0D, 0x54); // Reg0d : 54 ++ write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 ++ } ++ else // use main antenna ++ { ++ // Mac register, main antenna ++ write_nic_byte(dev, ANTSEL, 0x03); ++ //base band ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b ++ write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 ++ ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x5c); // Reg0d : 5c ++ write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 ++ } ++ } ++ else // Disable Antenna Diversity. ++ { ++ if( DefaultAnt == 1 ) // aux Antenna ++ { ++ // Mac register, aux antenna ++ write_nic_byte(dev, ANTSEL, 0x00); ++ ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb ++ write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 ++ ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0D, 0x54); // Reg0d : 54 ++ write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 ++ } ++ else // main Antenna ++ { ++ // Mac register, main antenna ++ write_nic_byte(dev, ANTSEL, 0x03); ++ ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b ++ write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 ++ ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0D, 0x5c); // Reg0d : 5c ++ write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 ++ } ++ } ++ priv->CurrAntennaIndex = DefaultAnt; // Update default settings. ++ return bAntennaSwitched; ++} ++#endif ++//by amy 080312 ++/*--------------------------------------------------------------- ++ * Hardware Initialization. ++ * the code is ported from Windows source code ++ ----------------------------------------------------------------*/ ++ ++void ++ZEBRA_Config_85BASIC_HardCode( ++ struct net_device *dev ++ ) ++{ ++ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 i; ++ u32 addr,data; ++ u32 u4bRegOffset, u4bRegValue, u4bRF23, u4bRF24; ++ u8 u1b24E; ++ ++#ifdef CONFIG_RTL818X_S ++ ++ //============================================================================= ++ // 87S_PCIE :: RADIOCFG.TXT ++ //============================================================================= ++ ++ ++ // Page1 : reg16-reg30 ++ RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); // switch to page1 ++ u4bRF23= RF_ReadReg(dev, 0x08); mdelay(1); ++ u4bRF24= RF_ReadReg(dev, 0x09); mdelay(1); ++ ++ if (u4bRF23==0x818 && u4bRF24==0x70C && priv->card_8185 == VERSION_8187S_C) ++ priv->card_8185 = VERSION_8187S_D; ++ ++ // Page0 : reg0-reg15 ++ ++// RF_WriteReg(dev, 0x00, 0x003f); mdelay(1);//1 ++ RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);// 1 ++ ++ RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1); ++ ++// RF_WriteReg(dev, 0x02, 0x004c); mdelay(1);//2 ++ RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);// 2 ++ ++// RF_WriteReg(dev, 0x03, 0x0000); mdelay(1);//3 ++ RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);// 3 ++ ++ RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); ++ RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); ++ RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1); ++ RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1); ++ RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1); ++ RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1); ++ RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1); ++ RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1); ++ RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1); ++ RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); ++ RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1); ++ RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1); ++ ++ ++ // Page1 : reg16-reg30 ++ RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); ++ ++ RF_WriteReg(dev, 0x03, 0x0806); mdelay(1); ++ ++ if(priv->card_8185 < VERSION_8187S_C) ++ { ++ RF_WriteReg(dev, 0x04, 0x03f7); mdelay(1); ++ RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); ++ RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); ++ } ++ else ++ { ++ RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1); ++ RF_WriteReg(dev, 0x05, 0x059b); mdelay(1); ++ RF_WriteReg(dev, 0x06, 0x0081); mdelay(1); ++ } ++ ++ ++ RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1); ++// Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl. ++// RF_WriteReg(dev, 0x08, 0x0597); mdelay(1); ++// RF_WriteReg(dev, 0x09, 0x050a); mdelay(1); ++ RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); ++ RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1); ++ ++ if(priv->card_8185 == VERSION_8187S_D) ++ { ++ RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); ++ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); ++ RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); // RX LO buffer ++ } ++ else ++ { ++ RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); ++ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); ++ RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); // RX LO buffer ++ } ++ ++ RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); ++ ++// RF_WriteReg(dev, 0x00, 0x017f); mdelay(1);//6 ++ RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1);// 6 ++ ++ RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1); ++ RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1); ++ for(i=0;i<=36;i++) ++ { ++ RF_WriteReg(dev, 0x01, i); mdelay(1); ++ RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); ++ //DbgPrint("RF - 0x%x = 0x%x", i, ZEBRA_RF_RX_GAIN_TABLE[i]); ++ } ++ ++ RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /// 203, 343 ++ //RF_WriteReg(dev, 0x06, 0x0300); mdelay(1); // 400 ++ RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); // 400 ++ ++ RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); // switch to reg16-reg30, and HSSI disable 137 ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++// RF_WriteReg(dev, 0x0c, 0x09be); mdelay(1); // 7 ++ //RF_WriteReg(dev, 0x0c, 0x07be); mdelay(1); ++ //mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); // Z4 synthesizer loop filter setting, 392 ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); // switch to reg0-reg15, and HSSI disable ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); // CBC on, Tx Rx disable, High gain ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); // Z4 setted channel 1 ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); // LC calibration ++ mdelay(200); // Deay 200 ms. //0xfd ++ mdelay(10); // Deay 10 ms. //0xfd ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); // switch to reg16-reg30 137, and HSSI disable 137 ++ mdelay(10); // Deay 10 ms. //0xfd ++ ++ RF_WriteReg(dev, 0x07, 0x0000); mdelay(1); ++ RF_WriteReg(dev, 0x07, 0x0180); mdelay(1); ++ RF_WriteReg(dev, 0x07, 0x0220); mdelay(1); ++ RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1); ++ ++ // DAC calibration off 20070702 ++ RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); ++ RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); ++//{by amy 080312 ++ // For crystal calibration, added by Roger, 2007.12.11. ++ if( priv->bXtalCalibration ) // reg 30. ++ { // enable crystal calibration. ++ // RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0]. ++ // (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0 ++ // (3)RF signal on/off when calibration[13], default: on, set BIT13=0. ++ // So we should minus 4 BITs offset. ++ RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5)|(priv->XtalCal_Xout<<1)|BIT11|BIT9); mdelay(1); ++ printk("ZEBRA_Config_85BASIC_HardCode(): (%02x)\n", ++ (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11| BIT9); ++ } ++ else ++ { // using default value. Xin=6, Xout=6. ++ RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); ++ } ++//by amy 080312 ++// RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); //-by amy 080312 ++ ++ RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); // switch to reg0-reg15, and HSSI enable ++// RF_WriteReg(dev, 0x0d, 0x009f); mdelay(1); // Rx BB start calibration, 00c//-edward ++ RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); // Rx BB start calibration, 00c//+edward ++ RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); // temperature meter off ++ RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); // Rx mode ++ mdelay(10); // Deay 10 ms. //0xfe ++ mdelay(10); // Deay 10 ms. //0xfe ++ mdelay(10); // Deay 10 ms. //0xfe ++ RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); // Rx mode//+edward ++ RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); // Rx mode//+edward ++ RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); // Rx mode//+edward ++ ++#if 0//-edward ++ RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); ++ RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); ++ RF_WriteReg(dev, 0x00, 0x009F); mdelay(1); ++#endif ++ RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); // Rx mode//+edward ++ RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); // Rx mode//+edward ++ //power save parameters. ++ u1b24E = read_nic_byte(dev, 0x24E); ++ write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6)))); ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // CCKCONF.TXT ++ //============================================================================= ++ ++ /* [POWER SAVE] Power Saving Parameters by jong. 2007-11-27 ++ CCK reg0x00[7]=1'b1 :power saving for TX (default) ++ CCK reg0x00[6]=1'b1: power saving for RX (default) ++ CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation. ++ CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1 ++ CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0 ++ */ ++#if 0 ++ write_nic_dword(dev, PHY_ADR, 0x0100c880); ++ write_nic_dword(dev, PHY_ADR, 0x01001c86); ++ write_nic_dword(dev, PHY_ADR, 0x01007890); ++ write_nic_dword(dev, PHY_ADR, 0x0100d0ae); ++ write_nic_dword(dev, PHY_ADR, 0x010006af); ++ write_nic_dword(dev, PHY_ADR, 0x01004681); ++#endif ++ write_phy_cck(dev,0x00,0xc8); ++ write_phy_cck(dev,0x06,0x1c); ++ write_phy_cck(dev,0x10,0x78); ++ write_phy_cck(dev,0x2e,0xd0); ++ write_phy_cck(dev,0x2f,0x06); ++ write_phy_cck(dev,0x01,0x46); ++ ++ // power control ++ write_nic_byte(dev, CCK_TXAGC, 0x10); ++ write_nic_byte(dev, OFDM_TXAGC, 0x1B); ++ write_nic_byte(dev, ANTSEL, 0x03); ++#else ++ //============================================================================= ++ // RADIOCFG.TXT ++ //============================================================================= ++ ++ RF_WriteReg(dev, 0x00, 0x00b7); mdelay(1); ++ RF_WriteReg(dev, 0x01, 0x0ee0); mdelay(1); ++ RF_WriteReg(dev, 0x02, 0x044d); mdelay(1); ++ RF_WriteReg(dev, 0x03, 0x0441); mdelay(1); ++ RF_WriteReg(dev, 0x04, 0x08c3); mdelay(1); ++ RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); ++ RF_WriteReg(dev, 0x06, 0x00e6); mdelay(1); ++ RF_WriteReg(dev, 0x07, 0x082a); mdelay(1); ++ RF_WriteReg(dev, 0x08, 0x003f); mdelay(1); ++ RF_WriteReg(dev, 0x09, 0x0335); mdelay(1); ++ RF_WriteReg(dev, 0x0a, 0x09d4); mdelay(1); ++ RF_WriteReg(dev, 0x0b, 0x07bb); mdelay(1); ++ RF_WriteReg(dev, 0x0c, 0x0850); mdelay(1); ++ RF_WriteReg(dev, 0x0d, 0x0cdf); mdelay(1); ++ RF_WriteReg(dev, 0x0e, 0x002b); mdelay(1); ++ RF_WriteReg(dev, 0x0f, 0x0114); mdelay(1); ++ ++ RF_WriteReg(dev, 0x00, 0x01b7); mdelay(1); ++ ++ ++ for(i=1;i<=95;i++) ++ { ++ RF_WriteReg(dev, 0x01, i); mdelay(1); ++ RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); ++ //DbgPrint("RF - 0x%x = 0x%x", i, ZEBRA_RF_RX_GAIN_TABLE[i]); ++ } ++ ++ RF_WriteReg(dev, 0x03, 0x0080); mdelay(1); // write reg 18 ++ RF_WriteReg(dev, 0x05, 0x0004); mdelay(1); // write reg 20 ++ RF_WriteReg(dev, 0x00, 0x00b7); mdelay(1); // switch to reg0-reg15 ++ //0xfd ++ //0xfd ++ //0xfd ++ RF_WriteReg(dev, 0x02, 0x0c4d); mdelay(1); ++ mdelay(100); // Deay 100 ms. //0xfe ++ mdelay(100); // Deay 100 ms. //0xfe ++ RF_WriteReg(dev, 0x02, 0x044d); mdelay(1); ++ RF_WriteReg(dev, 0x00, 0x02bf); mdelay(1); //0x002f disable 6us corner change, 06f--> enable ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // CCKCONF.TXT ++ //============================================================================= ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // Follow WMAC RTL8225_Config() ++ //============================================================================= ++ ++ // power control ++ write_nic_byte(dev, CCK_TXAGC, 0x03); ++ write_nic_byte(dev, OFDM_TXAGC, 0x07); ++ write_nic_byte(dev, ANTSEL, 0x03); ++ ++ //============================================================================= ++ ++ // OFDM BBP setup ++// SetOutputEnableOfRfPins(dev);//by amy ++#endif ++ ++ ++ ++ //============================================================================= ++ // AGC.txt ++ //============================================================================= ++ ++// PlatformIOWrite4Byte( dev, PhyAddr, 0x00001280); // Annie, 2006-05-05 ++ write_phy_ofdm(dev, 0x00, 0x12); ++ //WriteBBPortUchar(dev, 0x00001280); ++ ++ for (i=0; i<128; i++) ++ { ++ //DbgPrint("AGC - [%x+1] = 0x%x\n", i, ZEBRA_AGC[i+1]); ++ ++ data = ZEBRA_AGC[i+1]; ++ data = data << 8; ++ data = data | 0x0000008F; ++ ++ addr = i + 0x80; //enable writing AGC table ++ addr = addr << 8; ++ addr = addr | 0x0000008E; ++ ++ WriteBBPortUchar(dev, data); ++ WriteBBPortUchar(dev, addr); ++ WriteBBPortUchar(dev, 0x0000008E); ++ } ++ ++ PlatformIOWrite4Byte( dev, PhyAddr, 0x00001080); // Annie, 2006-05-05 ++ //WriteBBPortUchar(dev, 0x00001080); ++ ++ //============================================================================= ++ ++ //============================================================================= ++ // OFDMCONF.TXT ++ //============================================================================= ++ ++ for(i=0; i<60; i++) ++ { ++ u4bRegOffset=i; ++ u4bRegValue=OFDM_CONFIG[i]; ++ ++ //DbgPrint("OFDM - 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue); ++ ++ WriteBBPortUchar(dev, ++ (0x00000080 | ++ (u4bRegOffset & 0x7f) | ++ ((u4bRegValue & 0xff) << 8))); ++ } ++ ++ //============================================================================= ++//by amy for antenna ++ //============================================================================= ++//{by amy 080312 ++#ifdef CONFIG_RTL818X_S ++ // Config Sw/Hw Combinational Antenna Diversity. Added by Roger, 2008.02.26. ++ SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, priv->bSwAntennaDiverity); ++#endif ++//by amy 080312} ++#if 0 ++ // Config Sw/Hw Antenna Diversity ++ if( priv->bSwAntennaDiverity ) // Use SW+Hw Antenna Diversity ++ { ++ if( priv->bDefaultAntenna1 == true ) // aux antenna ++ { ++ // Mac register, aux antenna ++ write_nic_byte(dev, ANTSEL, 0x00); ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb ++ write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 ++ write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x54); // Reg0d : 54 ++ write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 ++ } ++ else // main antenna ++ { ++ // Mac register, main antenna ++ write_nic_byte(dev, ANTSEL, 0x03); ++ //base band ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b ++ write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 ++ write_phy_cck(dev, 0x01, 0xc7); // Reg01 : c7 ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x5c); // Reg0d : 5c ++ write_phy_ofdm(dev, 0x18, 0xb2); // Reg18 : b2 ++ } ++ } ++ else // Disable Antenna Diversity ++ { ++ if( priv->bDefaultAntenna1 == true ) // aux Antenna ++ { ++ // Mac register, aux antenna ++ write_nic_byte(dev, ANTSEL, 0x00); ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0xbb); // Reg11 : bb ++ write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 ++ write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x54); // Reg0d : 54 ++ write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 ++ } ++ else // main Antenna ++ { ++ // Mac register, main antenna ++ write_nic_byte(dev, ANTSEL, 0x03); ++ // Config CCK RX antenna. ++ write_phy_cck(dev, 0x11, 0x9b); // Reg11 : 9b ++ write_phy_cck(dev, 0x0c, 0x09); // Reg0c : 09 ++ write_phy_cck(dev, 0x01, 0x47); // Reg01 : 47 ++ // Config OFDM RX antenna. ++ write_phy_ofdm(dev, 0x0d, 0x5c); // Reg0d : 5c ++ write_phy_ofdm(dev, 0x18, 0x32); // Reg18 : 32 ++ } ++ } ++#endif ++//by amy for antenna ++} ++ ++ ++void ++UpdateInitialGain( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ //unsigned char* IGTable; ++ //u8 DIG_CurrentInitialGain = 4; ++ //unsigned char u1Tmp; ++ ++ //lzm add 080826 ++ if(priv->eRFPowerState != eRfOn) ++ { ++ //Don't access BB/RF under disable PLL situation. ++ //RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n")); ++ // Back to the original state ++ priv->InitialGain= priv->InitialGainBackUp; ++ return; ++ } ++ ++ switch(priv->rf_chip) ++ { ++#if 0 ++ case RF_ZEBRA2: ++ // Dynamic set initial gain, by shien chang, 2006.07.14 ++ switch(priv->InitialGain) ++ { ++ case 1: //m861dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 1: -82 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0x86a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfa85); mdelay(1); ++ break; ++ ++ case 2: //m862dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 2: -82 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0x86a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); ++ break; ++ ++ case 3: //m863dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 3: -82 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0x96a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); ++ break; ++ ++ case 4: //m864dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 4: -78 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); ++ break; ++ ++ case 5: //m82dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 5: -74 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x3697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); ++ break; ++ ++ case 6: //m78dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 6: -70 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x4697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); ++ break; ++ ++ case 7: //m74dBm ++ DMESG("RTL8185B + 8225 Initial Gain State 7: -66 dBm \n"); ++ write_nic_dword(dev, PhyAddr, 0x5697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xa6a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfb85); mdelay(1); ++ break; ++ ++ default: //MP ++ DMESG("RTL8185B + 8225 Initial Gain State 1: -82 dBm (default)\n"); ++ write_nic_dword(dev, PhyAddr, 0x2697); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0x86a4); mdelay(1); ++ write_nic_dword(dev, PhyAddr, 0xfa85); mdelay(1); ++ break; ++ } ++ break; ++#endif ++ case RF_ZEBRA4: ++ // Dynamic set initial gain, follow 87B ++ switch(priv->InitialGain) ++ { ++ case 1: //m861dBm ++ //DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); ++ break; ++ ++ case 2: //m862dBm ++ //DMESG("RTL8187 + 8225 Initial Gain State 2: -82 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x36); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); ++ break; ++ ++ case 3: //m863dBm ++ //DMESG("RTL8187 + 8225 Initial Gain State 3: -82 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x36); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); ++ break; ++ ++ case 4: //m864dBm ++ //DMESG("RTL8187 + 8225 Initial Gain State 4: -78 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); ++ break; ++ ++ case 5: //m82dBm ++ //DMESG("RTL8187 + 8225 Initial Gain State 5: -74 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x46); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x96); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); ++ break; ++ ++ case 6: //m78dBm ++ //DMESG ("RTL8187 + 8225 Initial Gain State 6: -70 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x56); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x96); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); ++ break; ++ ++ case 7: //m74dBm ++ //DMESG("RTL8187 + 8225 Initial Gain State 7: -66 dBm \n"); ++ write_phy_ofdm(dev, 0x17, 0x56); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0xa6); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); ++ break; ++ ++ case 8: ++ //DMESG("RTL8187 + 8225 Initial Gain State 8:\n"); ++ write_phy_ofdm(dev, 0x17, 0x66); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0xb6); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); ++ break; ++ ++ ++ default: //MP ++ //DMESG("RTL8187 + 8225 Initial Gain State 1: -82 dBm (default)\n"); ++ write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); ++ write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); ++ write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); ++ break; ++ } ++ break; ++ ++ ++ default: ++ DMESG("UpdateInitialGain(): unknown RFChipID: %#X\n", priv->rf_chip); ++ break; ++ } ++} ++#ifdef CONFIG_RTL818X_S ++// ++// Description: ++// Tx Power tracking mechanism routine on 87SE. ++// Created by Roger, 2007.12.11. ++// ++void ++InitTxPwrTracking87SE( ++ struct net_device *dev ++) ++{ ++ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u32 u4bRfReg; ++ ++ u4bRfReg = RF_ReadReg(dev, 0x02); ++ ++ // Enable Thermal meter indication. ++ //printk("InitTxPwrTracking87SE(): Enable thermal meter indication, Write RF[0x02] = %#x", u4bRfReg|PWR_METER_EN); ++ RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1); ++} ++ ++#endif ++void ++PhyConfig8185( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ write_nic_dword(dev, RCR, priv->ReceiveConfig); ++ priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03; ++ // RF config ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++ ZEBRA_Config_85BASIC_HardCode( dev); ++ break; ++ } ++//{by amy 080312 ++#ifdef CONFIG_RTL818X_S ++ // Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06. ++ if(priv->bDigMechanism) ++ { ++ if(priv->InitialGain == 0) ++ priv->InitialGain = 4; ++ //printk("PhyConfig8185(): DIG is enabled, set default initial gain index to %d\n", priv->InitialGain); ++ } ++ ++ // ++ // Enable thermal meter indication to implement TxPower tracking on 87SE. ++ // We initialize thermal meter here to avoid unsuccessful configuration. ++ // Added by Roger, 2007.12.11. ++ // ++ if(priv->bTxPowerTrack) ++ InitTxPwrTracking87SE(dev); ++ ++#endif ++//by amy 080312} ++ priv->InitialGainBackUp= priv->InitialGain; ++ UpdateInitialGain(dev); ++ ++ return; ++} ++ ++ ++ ++ ++void ++HwConfigureRTL8185( ++ struct net_device *dev ++ ) ++{ ++ //RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. ++// u8 bUNIVERSAL_CONTROL_RL = 1; ++ u8 bUNIVERSAL_CONTROL_RL = 0; ++ ++ u8 bUNIVERSAL_CONTROL_AGC = 1; ++ u8 bUNIVERSAL_CONTROL_ANT = 1; ++ u8 bAUTO_RATE_FALLBACK_CTL = 1; ++ u8 val8; ++ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ //struct ieee80211_device *ieee = priv->ieee80211; ++ //if(IS_WIRELESS_MODE_A(dev) || IS_WIRELESS_MODE_G(dev)) ++//{by amy 080312 if((ieee->mode == IEEE_G)||(ieee->mode == IEEE_A)) ++// { ++// write_nic_word(dev, BRSR, 0xffff); ++// } ++// else ++// { ++// write_nic_word(dev, BRSR, 0x000f); ++// } ++//by amy 080312} ++ write_nic_word(dev, BRSR, 0x0fff); ++ // Retry limit ++ val8 = read_nic_byte(dev, CW_CONF); ++ ++ if(bUNIVERSAL_CONTROL_RL) ++ val8 = val8 & 0xfd; ++ else ++ val8 = val8 | 0x02; ++ ++ write_nic_byte(dev, CW_CONF, val8); ++ ++ // Tx AGC ++ val8 = read_nic_byte(dev, TXAGC_CTL); ++ if(bUNIVERSAL_CONTROL_AGC) ++ { ++ write_nic_byte(dev, CCK_TXAGC, 128); ++ write_nic_byte(dev, OFDM_TXAGC, 128); ++ val8 = val8 & 0xfe; ++ } ++ else ++ { ++ val8 = val8 | 0x01 ; ++ } ++ ++ ++ write_nic_byte(dev, TXAGC_CTL, val8); ++ ++ // Tx Antenna including Feedback control ++ val8 = read_nic_byte(dev, TXAGC_CTL ); ++ ++ if(bUNIVERSAL_CONTROL_ANT) ++ { ++ write_nic_byte(dev, ANTSEL, 0x00); ++ val8 = val8 & 0xfd; ++ } ++ else ++ { ++ val8 = val8 & (val8|0x02); //xiong-2006-11-15 ++ } ++ ++ write_nic_byte(dev, TXAGC_CTL, val8); ++ ++ // Auto Rate fallback control ++ val8 = read_nic_byte(dev, RATE_FALLBACK); ++ val8 &= 0x7c; ++ if( bAUTO_RATE_FALLBACK_CTL ) ++ { ++ val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1; ++ ++ // We shall set up the ARFR according to user's setting. ++ //write_nic_word(dev, ARFR, 0x0fff); // set 1M ~ 54M ++//by amy ++#if 0 ++ PlatformIOWrite2Byte(dev, ARFR, 0x0fff); // set 1M ~ 54M ++#endif ++#ifdef CONFIG_RTL818X_S ++ // Aadded by Roger, 2007.11.15. ++ PlatformIOWrite2Byte(dev, ARFR, 0x0fff); //set 1M ~ 54Mbps. ++#else ++ PlatformIOWrite2Byte(dev, ARFR, 0x0c00); //set 48Mbps, 54Mbps. ++ // By SD3 szuyi's request. by Roger, 2007.03.26. ++#endif ++//by amy ++ } ++ else ++ { ++ } ++ write_nic_byte(dev, RATE_FALLBACK, val8); ++} ++ ++ ++ ++static void ++MacConfig_85BASIC_HardCode( ++ struct net_device *dev) ++{ ++ //============================================================================ ++ // MACREG.TXT ++ //============================================================================ ++ int nLinesRead = 0; ++ ++ u32 u4bRegOffset, u4bRegValue,u4bPageIndex = 0; ++ int i; ++ ++ nLinesRead=sizeof(MAC_REG_TABLE)/2; ++ ++ for(i = 0; i < nLinesRead; i++) //nLinesRead=101 ++ { ++ u4bRegOffset=MAC_REG_TABLE[i][0]; ++ u4bRegValue=MAC_REG_TABLE[i][1]; ++ ++ if(u4bRegOffset == 0x5e) ++ { ++ u4bPageIndex = u4bRegValue; ++ } ++ else ++ { ++ u4bRegOffset |= (u4bPageIndex << 8); ++ } ++ //DbgPrint("MAC - 0x%x = 0x%x\n", u4bRegOffset, u4bRegValue); ++ write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue); ++ } ++ //============================================================================ ++} ++ ++ ++ ++static void ++MacConfig_85BASIC( ++ struct net_device *dev) ++{ ++ ++ u8 u1DA; ++ MacConfig_85BASIC_HardCode(dev); ++ ++ //============================================================================ ++ ++ // Follow TID_AC_MAP of WMac. ++ write_nic_word(dev, TID_AC_MAP, 0xfa50); ++ ++ // Interrupt Migration, Jong suggested we use set 0x0000 first, 2005.12.14, by rcnjko. ++ write_nic_word(dev, IntMig, 0x0000); ++ ++ // Prevent TPC to cause CRC error. Added by Annie, 2006-06-10. ++ PlatformIOWrite4Byte(dev, 0x1F0, 0x00000000); ++ PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000); ++ PlatformIOWrite1Byte(dev, 0x1F8, 0x00); ++ ++ // Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. ++ //PlatformIOWrite4Byte(dev, RFTiming, 0x00004001); ++//by amy ++#if 0 ++ write_nic_dword(dev, RFTiming, 0x00004001); ++#endif ++#ifdef CONFIG_RTL818X_S ++ // power save parameter based on "87SE power save parameters 20071127.doc", as follow. ++ ++ //Enable DA10 TX power saving ++ u1DA = read_nic_byte(dev, PHYPR); ++ write_nic_byte(dev, PHYPR, (u1DA | BIT2) ); ++ ++ //POWER: ++ write_nic_word(dev, 0x360, 0x1000); ++ write_nic_word(dev, 0x362, 0x1000); ++ ++ // AFE. ++ write_nic_word(dev, 0x370, 0x0560); ++ write_nic_word(dev, 0x372, 0x0560); ++ write_nic_word(dev, 0x374, 0x0DA4); ++ write_nic_word(dev, 0x376, 0x0DA4); ++ write_nic_word(dev, 0x378, 0x0560); ++ write_nic_word(dev, 0x37A, 0x0560); ++ write_nic_word(dev, 0x37C, 0x00EC); ++// write_nic_word(dev, 0x37E, 0x00FE);//-edward ++ write_nic_word(dev, 0x37E, 0x00EC);//+edward ++#else ++ write_nic_dword(dev, RFTiming, 0x00004003); ++#endif ++ write_nic_byte(dev, 0x24E,0x01); ++//by amy ++ ++} ++ ++ ++ ++ ++u8 ++GetSupportedWirelessMode8185( ++ struct net_device *dev ++) ++{ ++ u8 btSupportedWirelessMode = 0; ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++ btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G); ++ break; ++ default: ++ btSupportedWirelessMode = WIRELESS_MODE_B; ++ break; ++ } ++ ++ return btSupportedWirelessMode; ++} ++ ++void ++ActUpdateChannelAccessSetting( ++ struct net_device *dev, ++ WIRELESS_MODE WirelessMode, ++ PCHANNEL_ACCESS_SETTING ChnlAccessSetting ++ ) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ AC_CODING eACI; ++ AC_PARAM AcParam; ++ //PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos; ++ u8 bFollowLegacySetting = 0; ++ u8 u1bAIFS; ++ ++ // ++ // ++ // TODO: We still don't know how to set up these registers, just follow WMAC to ++ // verify 8185B FPAG. ++ // ++ // ++ // Jong said CWmin/CWmax register are not functional in 8185B, ++ // so we shall fill channel access realted register into AC parameter registers, ++ // even in nQBss. ++ // ++ ChnlAccessSetting->SIFS_Timer = 0x22; // Suggested by Jong, 2005.12.08. ++ ChnlAccessSetting->DIFS_Timer = 0x1C; // 2006.06.02, by rcnjko. ++ ChnlAccessSetting->SlotTimeTimer = 9; // 2006.06.02, by rcnjko. ++ ChnlAccessSetting->EIFS_Timer = 0x5B; // Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. ++ ChnlAccessSetting->CWminIndex = 3; // 2006.06.02, by rcnjko. ++ ChnlAccessSetting->CWmaxIndex = 7; // 2006.06.02, by rcnjko. ++ ++ write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer); ++ //Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_SLOT_TIME, &ChnlAccessSetting->SlotTimeTimer ); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. ++ write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); // Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. ++ ++ u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer ); ++ ++ //write_nic_byte(dev, AC_VO_PARAM, u1bAIFS); ++ //write_nic_byte(dev, AC_VI_PARAM, u1bAIFS); ++ //write_nic_byte(dev, AC_BE_PARAM, u1bAIFS); ++ //write_nic_byte(dev, AC_BK_PARAM, u1bAIFS); ++ ++ write_nic_byte(dev, EIFS, ChnlAccessSetting->EIFS_Timer); ++ ++ write_nic_byte(dev, AckTimeOutReg, 0x5B); // Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. ++ ++#ifdef TODO ++ // Update ECWmin/ECWmax, AIFS, TXOP Limit of each AC to the value defined by SPEC. ++ if( pStaQos->CurrentQosMode > QOS_DISABLE ) ++ { // QoS mode. ++ if(pStaQos->QBssWirelessMode == WirelessMode) ++ { ++ // Follow AC Parameters of the QBSS. ++ for(eACI = 0; eACI < AC_MAX; eACI++) ++ { ++ Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, (pu1Byte)(&(pStaQos->WMMParamEle.AcParam[eACI])) ); ++ } ++ } ++ else ++ { ++ // Follow Default WMM AC Parameters. ++ bFollowLegacySetting = 1; ++ } ++ } ++ else ++#endif ++ { // Legacy 802.11. ++ bFollowLegacySetting = 1; ++ ++ } ++ ++ // this setting is copied from rtl8187B. xiong-2006-11-13 ++ if(bFollowLegacySetting) ++ { ++ ++ ++ // ++ // Follow 802.11 seeting to AC parameter, all AC shall use the same parameter. ++ // 2005.12.01, by rcnjko. ++ // ++ AcParam.longData = 0; ++ AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS. ++ AcParam.f.AciAifsn.f.ACM = 0; ++ AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; // Follow 802.11 CWmin. ++ AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; // Follow 802.11 CWmax. ++ AcParam.f.TXOPLimit = 0; ++ ++ //lzm reserved 080826 ++#if 1 ++#ifdef THOMAS_TURBO ++ // For turbo mode setting. port from 87B by Isaiah 2008-08-01 ++ if( ieee->current_network.Turbo_Enable == 1 ) ++ AcParam.f.TXOPLimit = 0x01FF; ++#endif ++ // For 87SE with Intel 4965 Ad-Hoc mode have poor throughput (19MB) ++ if (ieee->iw_mode == IW_MODE_ADHOC) ++ AcParam.f.TXOPLimit = 0x0020; ++#endif ++ ++ for(eACI = 0; eACI < AC_MAX; eACI++) ++ { ++ AcParam.f.AciAifsn.f.ACI = (u8)eACI; ++ { ++ PAC_PARAM pAcParam = (PAC_PARAM)(&AcParam); ++ AC_CODING eACI; ++ u8 u1bAIFS; ++ u32 u4bAcParam; ++ ++ // Retrive paramters to udpate. ++ eACI = pAcParam->f.AciAifsn.f.ACI; ++ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime; ++ u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | ++ (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | ++ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); ++ ++ switch(eACI) ++ { ++ case AC1_BK: ++ //write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); ++ break; ++ ++ case AC0_BE: ++ //write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); ++ break; ++ ++ case AC2_VI: ++ //write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); ++ break; ++ ++ case AC3_VO: ++ //write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); ++ break; ++ ++ default: ++ DMESGW( "SetHwReg8185(): invalid ACI: %d !\n", eACI); ++ break; ++ } ++ ++ // Cehck ACM bit. ++ // If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. ++ //write_nic_byte(dev, ACM_CONTROL, pAcParam->f.AciAifsn); ++ { ++ PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn); ++ AC_CODING eACI = pAciAifsn->f.ACI; ++ ++ //modified Joseph ++ //for 8187B AsynIORead issue ++#ifdef TODO ++ u8 AcmCtrl = pHalData->AcmControl; ++#else ++ u8 AcmCtrl = 0; ++#endif ++ if( pAciAifsn->f.ACM ) ++ { // ACM bit is 1. ++ switch(eACI) ++ { ++ case AC0_BE: ++ AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); // or 0x21 ++ break; ++ ++ case AC2_VI: ++ AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); // or 0x42 ++ break; ++ ++ case AC3_VO: ++ AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); // or 0x84 ++ break; ++ ++ default: ++ DMESGW("SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set failed: eACI is %d\n", eACI ); ++ break; ++ } ++ } ++ else ++ { // ACM bit is 0. ++ switch(eACI) ++ { ++ case AC0_BE: ++ AcmCtrl &= ( (~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0xDE ++ break; ++ ++ case AC2_VI: ++ AcmCtrl &= ( (~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0xBD ++ break; ++ ++ case AC3_VO: ++ AcmCtrl &= ( (~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN) ); // and 0x7B ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ //printk(KERN_WARNING "SetHwReg8185(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl); ++ ++#ifdef TO_DO ++ pHalData->AcmControl = AcmCtrl; ++#endif ++ //write_nic_byte(dev, ACM_CONTROL, AcmCtrl); ++ write_nic_byte(dev, ACM_CONTROL, 0); ++ } ++ } ++ } ++ ++ ++ } ++} ++ ++void ++ActSetWirelessMode8185( ++ struct net_device *dev, ++ u8 btWirelessMode ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); ++ u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev); ++ ++ if( (btWirelessMode & btSupportedWirelessMode) == 0 ) ++ { // Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. ++ DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n", ++ btWirelessMode, btSupportedWirelessMode); ++ return; ++ } ++ ++ // 1. Assign wireless mode to swtich if necessary. ++ if (btWirelessMode == WIRELESS_MODE_AUTO) ++ { ++ if((btSupportedWirelessMode & WIRELESS_MODE_A)) ++ { ++ btWirelessMode = WIRELESS_MODE_A; ++ } ++ else if((btSupportedWirelessMode & WIRELESS_MODE_G)) ++ { ++ btWirelessMode = WIRELESS_MODE_G; ++ } ++ else if((btSupportedWirelessMode & WIRELESS_MODE_B)) ++ { ++ btWirelessMode = WIRELESS_MODE_B; ++ } ++ else ++ { ++ DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n", ++ btSupportedWirelessMode); ++ btWirelessMode = WIRELESS_MODE_B; ++ } ++ } ++ ++ ++ // 2. Swtich band: RF or BB specific actions, ++ // for example, refresh tables in omc8255, or change initial gain if necessary. ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++ { ++ // Nothing to do for Zebra to switch band. ++ // Update current wireless mode if we swtich to specified band successfully. ++ ieee->mode = (WIRELESS_MODE)btWirelessMode; ++ } ++ break; ++ ++ default: ++ DMESGW("ActSetWirelessMode8185(): unsupported RF: 0x%X !!!\n", priv->rf_chip); ++ break; ++ } ++ ++ // 3. Change related setting. ++ if( ieee->mode == WIRELESS_MODE_A ){ ++ DMESG("WIRELESS_MODE_A\n"); ++ } ++ else if( ieee->mode == WIRELESS_MODE_B ){ ++ DMESG("WIRELESS_MODE_B\n"); ++ } ++ else if( ieee->mode == WIRELESS_MODE_G ){ ++ DMESG("WIRELESS_MODE_G\n"); ++ } ++ ++ ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting); ++} ++ ++void rtl8185b_irq_enable(struct net_device *dev) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++ priv->irq_enabled = 1; ++ write_nic_dword(dev, IMR, priv->IntrMask); ++} ++//by amy for power save ++void ++DrvIFIndicateDisassociation( ++ struct net_device *dev, ++ u16 reason ++ ) ++{ ++ //printk("==> DrvIFIndicateDisassociation()\n"); ++ ++ // nothing is needed after disassociation request. ++ ++ //printk("<== DrvIFIndicateDisassociation()\n"); ++} ++void ++MgntDisconnectIBSS( ++ struct net_device *dev ++) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u8 i; ++ ++ //printk("XXXXXXXXXX MgntDisconnect IBSS\n"); ++ ++ DrvIFIndicateDisassociation(dev, unspec_reason); ++ ++// PlatformZeroMemory( pMgntInfo->Bssid, 6 ); ++ for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x55; ++ ++ priv->ieee80211->state = IEEE80211_NOLINK; ++ ++ //Stop Beacon. ++ ++ // Vista add a Adhoc profile, HW radio off untill OID_DOT11_RESET_REQUEST ++ // Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck. ++ // Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send. ++ ++ // Disable Beacon Queue Own bit, suggested by jong ++// Adapter->HalFunc.SetTxDescOWNHandler(Adapter, BEACON_QUEUE, 0, 0); ++ ieee80211_stop_send_beacons(priv->ieee80211); ++ ++ priv->ieee80211->link_change(dev); ++ notify_wx_assoc_event(priv->ieee80211); ++ ++ // Stop SW Beacon.Use hw beacon so do not need to do so.by amy ++#if 0 ++ if(pMgntInfo->bEnableSwBeaconTimer) ++ { ++ // SwBeaconTimer will stop if pMgntInfo->mIbss==FALSE, see SwBeaconCallback() for details. ++// comment out by haich, 2007.10.01 ++//#if DEV_BUS_TYPE==USB_INTERFACE ++ PlatformCancelTimer( Adapter, &pMgntInfo->SwBeaconTimer); ++//#endif ++ } ++#endif ++ ++// MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE ); ++ ++} ++void ++MlmeDisassociateRequest( ++ struct net_device *dev, ++ u8* asSta, ++ u8 asRsn ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ u8 i; ++ ++ SendDisassociation(priv->ieee80211, asSta, asRsn ); ++ ++ if( memcmp(priv->ieee80211->current_network.bssid, asSta, 6 ) == 0 ){ ++ //ShuChen TODO: change media status. ++ //ShuChen TODO: What to do when disassociate. ++ DrvIFIndicateDisassociation(dev, unspec_reason); ++ ++ ++ // pMgntInfo->AsocTimestamp = 0; ++ for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x22; ++// pMgntInfo->mBrates.Length = 0; ++// Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_BASIC_RATE, (pu1Byte)(&pMgntInfo->mBrates) ); ++ ++ ieee80211_disassociate(priv->ieee80211); ++ ++ ++ } ++ ++} ++ ++void ++MgntDisconnectAP( ++ struct net_device *dev, ++ u8 asRsn ++) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ ++// ++// Commented out by rcnjko, 2005.01.27: ++// I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE(). ++// ++// //2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success ++// SecClearAllKeys(Adapter); ++ ++ // In WPA WPA2 need to Clear all key ... because new key will set after new handshaking. ++#ifdef TODO ++ if( pMgntInfo->SecurityInfo.AuthMode > RT_802_11AuthModeAutoSwitch || ++ (pMgntInfo->bAPSuportCCKM && pMgntInfo->bCCX8021xenable) ) // In CCKM mode will Clear key ++ { ++ SecClearAllKeys(Adapter); ++ RT_TRACE(COMP_SEC, DBG_LOUD,("======>CCKM clear key...")) ++ } ++#endif ++ // 2004.10.11, by rcnjko. ++ //MlmeDisassociateRequest( Adapter, pMgntInfo->Bssid, disas_lv_ss ); ++ MlmeDisassociateRequest( dev, priv->ieee80211->current_network.bssid, asRsn ); ++ ++ priv->ieee80211->state = IEEE80211_NOLINK; ++// pMgntInfo->AsocTimestamp = 0; ++} ++bool ++MgntDisconnect( ++ struct net_device *dev, ++ u8 asRsn ++) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ // ++ // Schedule an workitem to wake up for ps mode, 070109, by rcnjko. ++ // ++#ifdef TODO ++ if(pMgntInfo->mPss != eAwake) ++ { ++ // ++ // Using AwkaeTimer to prevent mismatch ps state. ++ // In the timer the state will be changed according to the RF is being awoke or not. By Bruce, 2007-10-31. ++ // ++ // PlatformScheduleWorkItem( &(pMgntInfo->AwakeWorkItem) ); ++ PlatformSetTimer( Adapter, &(pMgntInfo->AwakeTimer), 0 ); ++ } ++#endif ++ ++ // Indication of disassociation event. ++ //DrvIFIndicateDisassociation(Adapter, asRsn); ++#ifdef ENABLE_DOT11D ++ if(IS_DOT11D_ENABLE(priv->ieee80211)) ++ Dot11d_Reset(priv->ieee80211); ++#endif ++ // In adhoc mode, update beacon frame. ++ if( priv->ieee80211->state == IEEE80211_LINKED ) ++ { ++ if( priv->ieee80211->iw_mode == IW_MODE_ADHOC ) ++ { ++// RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> MgntDisconnectIBSS\n")); ++ //printk("MgntDisconnect() ===> MgntDisconnectIBSS\n"); ++ MgntDisconnectIBSS(dev); ++ } ++ if( priv->ieee80211->iw_mode == IW_MODE_INFRA ) ++ { ++ // We clear key here instead of MgntDisconnectAP() because that ++ // MgntActSet_802_11_DISASSOCIATE() is an interface called by OS, ++ // e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is ++ // used to handle disassociation related things to AP, e.g. send Disassoc ++ // frame to AP. 2005.01.27, by rcnjko. ++// SecClearAllKeys(Adapter); ++ ++// RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> MgntDisconnectAP\n")); ++ //printk("MgntDisconnect() ===> MgntDisconnectAP\n"); ++ MgntDisconnectAP(dev, asRsn); ++ } ++ ++ // Inidicate Disconnect, 2005.02.23, by rcnjko. ++// MgntIndicateMediaStatus( Adapter, RT_MEDIA_DISCONNECT, GENERAL_INDICATE); ++ } ++ ++ return true; ++} ++// ++// Description: ++// Chang RF Power State. ++// Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE. ++// ++// Assumption: ++// PASSIVE LEVEL. ++// ++bool ++SetRFPowerState( ++ struct net_device *dev, ++ RT_RF_POWER_STATE eRFPowerState ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bResult = false; ++ ++// printk("---------> SetRFPowerState(): eRFPowerState(%d)\n", eRFPowerState); ++ if(eRFPowerState == priv->eRFPowerState) ++ { ++// printk("<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState); ++ return bResult; ++ } ++ ++ switch(priv->rf_chip) ++ { ++ case RF_ZEBRA2: ++ case RF_ZEBRA4: ++ bResult = SetZebraRFPowerState8185(dev, eRFPowerState); ++ break; ++ ++ default: ++ printk("SetRFPowerState8185(): unknown RFChipID: 0x%X!!!\n", priv->rf_chip); ++ break;; ++} ++// printk("<--------- SetRFPowerState(): bResult(%d)\n", bResult); ++ ++ return bResult; ++} ++void ++HalEnableRx8185Dummy( ++ struct net_device *dev ++ ) ++{ ++} ++void ++HalDisableRx8185Dummy( ++ struct net_device *dev ++ ) ++{ ++} ++ ++bool ++MgntActSet_RF_State( ++ struct net_device *dev, ++ RT_RF_POWER_STATE StateToSet, ++ u32 ChangeSource ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ bool bActionAllowed = false; ++ bool bConnectBySSID = false; ++ RT_RF_POWER_STATE rtState; ++ u16 RFWaitCounter = 0; ++ unsigned long flag; ++// printk("===>MgntActSet_RF_State(): StateToSet(%d), ChangeSource(0x%x)\n",StateToSet, ChangeSource); ++ // ++ // Prevent the race condition of RF state change. By Bruce, 2007-11-28. ++ // Only one thread can change the RF state at one time, and others should wait to be executed. ++ // ++#if 1 ++ while(true) ++ { ++// down(&priv->rf_state); ++ spin_lock_irqsave(&priv->rf_ps_lock,flag); ++ if(priv->RFChangeInProgress) ++ { ++// printk("====================>haha111111111\n"); ++// up(&priv->rf_state); ++// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", StateToSet)); ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ // Set RF after the previous action is done. ++ while(priv->RFChangeInProgress) ++ { ++ RFWaitCounter ++; ++// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", RFWaitCounter)); ++ udelay(1000); // 1 ms ++ ++ // Wait too long, return FALSE to avoid to be stuck here. ++ if(RFWaitCounter > 1000) // 1sec ++ { ++// RT_ASSERT(FALSE, ("MgntActSet_RF_State(): Wait too logn to set RF\n")); ++ printk("MgntActSet_RF_State(): Wait too long to set RF\n"); ++ // TODO: Reset RF state? ++ return false; ++ } ++ } ++ } ++ else ++ { ++// printk("========================>haha2\n"); ++ priv->RFChangeInProgress = true; ++// up(&priv->rf_state); ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++ break; ++ } ++ } ++#endif ++ rtState = priv->eRFPowerState; ++ ++ ++ switch(StateToSet) ++ { ++ case eRfOn: ++ // ++ // Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or ++ // the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02. ++ // ++ priv->RfOffReason &= (~ChangeSource); ++ ++ if(! priv->RfOffReason) ++ { ++ priv->RfOffReason = 0; ++ bActionAllowed = true; ++ ++ if(rtState == eRfOff && ChangeSource >=RF_CHANGE_BY_HW && !priv->bInHctTest) ++ { ++ bConnectBySSID = true; ++ } ++ } ++ else ++// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", pMgntInfo->RfOffReason, ChangeSource)); ++ ; ++ break; ++ ++ case eRfOff: ++ // 070125, rcnjko: we always keep connected in AP mode. ++ ++ if (priv->RfOffReason > RF_CHANGE_BY_IPS) ++ { ++ // ++ // 060808, Annie: ++ // Disconnect to current BSS when radio off. Asked by QuanTa. ++ // ++ ++ // ++ // Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(), ++ // because we do NOT need to set ssid to dummy ones. ++ // Revised by Roger, 2007.12.04. ++ // ++ MgntDisconnect( dev, disas_lv_ss ); ++ ++ // Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. ++ // 2007.05.28, by shien chang. ++// PlatformZeroMemory( pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC ); ++// pMgntInfo->NumBssDesc = 0; ++// PlatformZeroMemory( pMgntInfo->bssDesc4Query, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC ); ++// pMgntInfo->NumBssDesc4Query = 0; ++ } ++ ++ ++ ++ priv->RfOffReason |= ChangeSource; ++ bActionAllowed = true; ++ break; ++ ++ case eRfSleep: ++ priv->RfOffReason |= ChangeSource; ++ bActionAllowed = true; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if(bActionAllowed) ++ { ++// RT_TRACE(COMP_RF, DBG_LOUD, ("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, pMgntInfo->RfOffReason)); ++ // Config HW to the specified mode. ++// printk("MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->RfOffReason); ++ SetRFPowerState(dev, StateToSet); ++ ++ // Turn on RF. ++ if(StateToSet == eRfOn) ++ { ++ HalEnableRx8185Dummy(dev); ++ if(bConnectBySSID) ++ { ++ // by amy not supported ++// MgntActSet_802_11_SSID(Adapter, Adapter->MgntInfo.Ssid.Octet, Adapter->MgntInfo.Ssid.Length, TRUE ); ++ } ++ } ++ // Turn off RF. ++ else if(StateToSet == eRfOff) ++ { ++ HalDisableRx8185Dummy(dev); ++ } ++ } ++ else ++ { ++ // printk("MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", StateToSet, ChangeSource, priv->RfOffReason); ++ } ++ ++ // Release RF spinlock ++// down(&priv->rf_state); ++ spin_lock_irqsave(&priv->rf_ps_lock,flag); ++ priv->RFChangeInProgress = false; ++// up(&priv->rf_state); ++ spin_unlock_irqrestore(&priv->rf_ps_lock,flag); ++// printk("<===MgntActSet_RF_State()\n"); ++ return bActionAllowed; ++} ++void ++InactivePowerSave( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ //u8 index = 0; ++ ++ // ++ // This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem ++ // is really scheduled. ++ // The old code, sets this flag before scheduling the IPS workitem and however, at the same time the ++ // previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing ++ // blocks the IPS procedure of switching RF. ++ // By Bruce, 2007-12-25. ++ // ++ priv->bSwRfProcessing = true; ++ ++ MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS); ++ ++ // ++ // To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20. ++ // ++#if 0 ++ while( index < 4 ) ++ { ++ if( ( pMgntInfo->SecurityInfo.PairwiseEncAlgorithm == WEP104_Encryption ) || ++ (pMgntInfo->SecurityInfo.PairwiseEncAlgorithm == WEP40_Encryption) ) ++ { ++ if( pMgntInfo->SecurityInfo.KeyLen[index] != 0) ++ pAdapter->HalFunc.SetKeyHandler(pAdapter, index, 0, FALSE, pMgntInfo->SecurityInfo.PairwiseEncAlgorithm, TRUE, FALSE); ++ ++ } ++ index++; ++ } ++#endif ++ priv->bSwRfProcessing = false; ++} ++ ++// ++// Description: ++// Enter the inactive power save mode. RF will be off ++// 2007.08.17, by shien chang. ++// ++void ++IPSEnter( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ //printk("==============================>enter IPS\n"); ++ if (priv->bInactivePs) ++ { ++ rtState = priv->eRFPowerState; ++ ++ // ++ // Added by Bruce, 2007-12-25. ++ // Do not enter IPS in the following conditions: ++ // (1) RF is already OFF or Sleep ++ // (2) bSwRfProcessing (indicates the IPS is still under going) ++ // (3) Connectted (only disconnected can trigger IPS) ++ // (4) IBSS (send Beacon) ++ // (5) AP mode (send Beacon) ++ // ++ if (rtState == eRfOn && !priv->bSwRfProcessing ++ && (priv->ieee80211->state != IEEE80211_LINKED )) ++ { ++ // printk("IPSEnter(): Turn off RF.\n"); ++ priv->eInactivePowerState = eRfOff; ++ InactivePowerSave(dev); ++ } ++ } ++// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState); ++} ++void ++IPSLeave( ++ struct net_device *dev ++ ) ++{ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++ RT_RF_POWER_STATE rtState; ++ //printk("===================================>leave IPS\n"); ++ if (priv->bInactivePs) ++ { ++ rtState = priv->eRFPowerState; ++ if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) ++ { ++// printk("IPSLeave(): Turn on RF.\n"); ++ priv->eInactivePowerState = eRfOn; ++ InactivePowerSave(dev); ++ } ++ } ++// printk("priv->eRFPowerState is %d\n",priv->eRFPowerState); ++} ++//by amy for power save ++void rtl8185b_adapter_start(struct net_device *dev) ++{ ++ struct r8180_priv *priv = ieee80211_priv(dev); ++ struct ieee80211_device *ieee = priv->ieee80211; ++ ++ u8 SupportedWirelessMode; ++ u8 InitWirelessMode; ++ u8 bInvalidWirelessMode = 0; ++ //int i; ++ u8 tmpu8; ++ //u8 u1tmp,u2tmp; ++ u8 btCR9346; ++ u8 TmpU1b; ++ u8 btPSR; ++ ++ //rtl8180_rtx_disable(dev); ++//{by amy 080312 ++ write_nic_byte(dev,0x24e, (BIT5|BIT6|BIT0)); ++//by amy 080312} ++ rtl8180_reset(dev); ++ ++ priv->dma_poll_mask = 0; ++ priv->dma_poll_stop_mask = 0; ++ ++ //rtl8180_beacon_tx_disable(dev); ++ ++ HwConfigureRTL8185(dev); ++ ++ write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]); ++ write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff ); ++ ++ write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); // default network type to 'No Link' ++ ++ //write_nic_byte(dev, BRSR, 0x0); // Set BRSR= 1M ++ ++ write_nic_word(dev, BcnItv, 100); ++ write_nic_word(dev, AtimWnd, 2); ++ ++ //PlatformEFIOWrite2Byte(dev, FEMR, 0xFFFF); ++ PlatformIOWrite2Byte(dev, FEMR, 0xFFFF); ++ ++ write_nic_byte(dev, WPA_CONFIG, 0); ++ ++ MacConfig_85BASIC(dev); ++ ++ // Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. ++ // BT_DEMO_BOARD type ++ PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a); ++//by amy ++//#ifdef CONFIG_RTL818X_S ++ // for jong required ++// PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x9a56); ++//#endif ++//by amy ++ //BT_QA_BOARD ++ //PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x9a56); ++ ++ //----------------------------------------------------------------------------- ++ // Set up PHY related. ++ //----------------------------------------------------------------------------- ++ // Enable Config3.PARAM_En to revise AnaaParm. ++ write_nic_byte(dev, CR9346, 0xc0); // enable config register write ++//by amy ++ tmpu8 = read_nic_byte(dev, CONFIG3); ++#ifdef CONFIG_RTL818X_S ++ write_nic_byte(dev, CONFIG3, (tmpu8 |CONFIG3_PARM_En) ); ++#else ++ write_nic_byte(dev, CONFIG3, (tmpu8 |CONFIG3_PARM_En | CONFIG3_CLKRUN_En) ); ++#endif ++//by amy ++ // Turn on Analog power. ++ // Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON); ++ write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON); ++//by amy ++#ifdef CONFIG_RTL818X_S ++ write_nic_word(dev, ANAPARAM3, 0x0010); ++#else ++ write_nic_byte(dev, ANAPARAM3, 0x00); ++#endif ++//by amy ++ ++ write_nic_byte(dev, CONFIG3, tmpu8); ++ write_nic_byte(dev, CR9346, 0x00); ++//{by amy 080312 for led ++ // enable EEM0 and EEM1 in 9346CR ++ btCR9346 = read_nic_byte(dev, CR9346); ++ write_nic_byte(dev, CR9346, (btCR9346|0xC0) ); ++ ++ // B cut use LED1 to control HW RF on/off ++ TmpU1b = read_nic_byte(dev, CONFIG5); ++ TmpU1b = TmpU1b & ~BIT3; ++ write_nic_byte(dev,CONFIG5, TmpU1b); ++ ++ // disable EEM0 and EEM1 in 9346CR ++ btCR9346 &= ~(0xC0); ++ write_nic_byte(dev, CR9346, btCR9346); ++ ++ //Enable Led (suggested by Jong) ++ // B-cut RF Radio on/off 5e[3]=0 ++ btPSR = read_nic_byte(dev, PSR); ++ write_nic_byte(dev, PSR, (btPSR | BIT3)); ++//by amy 080312 for led} ++ // setup initial timing for RFE. ++ write_nic_word(dev, RFPinsOutput, 0x0480); ++ SetOutputEnableOfRfPins(dev); ++ write_nic_word(dev, RFPinsSelect, 0x2488); ++ ++ // PHY config. ++ PhyConfig8185(dev); ++ ++ // We assume RegWirelessMode has already been initialized before, ++ // however, we has to validate the wireless mode here and provide a reasonble ++ // initialized value if necessary. 2005.01.13, by rcnjko. ++ SupportedWirelessMode = GetSupportedWirelessMode8185(dev); ++ if( (ieee->mode != WIRELESS_MODE_B) && ++ (ieee->mode != WIRELESS_MODE_G) && ++ (ieee->mode != WIRELESS_MODE_A) && ++ (ieee->mode != WIRELESS_MODE_AUTO)) ++ { // It should be one of B, G, A, or AUTO. ++ bInvalidWirelessMode = 1; ++ } ++ else ++ { // One of B, G, A, or AUTO. ++ // Check if the wireless mode is supported by RF. ++ if( (ieee->mode != WIRELESS_MODE_AUTO) && ++ (ieee->mode & SupportedWirelessMode) == 0 ) ++ { ++ bInvalidWirelessMode = 1; ++ } ++ } ++ ++ if(bInvalidWirelessMode || ieee->mode==WIRELESS_MODE_AUTO) ++ { // Auto or other invalid value. ++ // Assigne a wireless mode to initialize. ++ if((SupportedWirelessMode & WIRELESS_MODE_A)) ++ { ++ InitWirelessMode = WIRELESS_MODE_A; ++ } ++ else if((SupportedWirelessMode & WIRELESS_MODE_G)) ++ { ++ InitWirelessMode = WIRELESS_MODE_G; ++ } ++ else if((SupportedWirelessMode & WIRELESS_MODE_B)) ++ { ++ InitWirelessMode = WIRELESS_MODE_B; ++ } ++ else ++ { ++ DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", ++ SupportedWirelessMode); ++ InitWirelessMode = WIRELESS_MODE_B; ++ } ++ ++ // Initialize RegWirelessMode if it is not a valid one. ++ if(bInvalidWirelessMode) ++ { ++ ieee->mode = (WIRELESS_MODE)InitWirelessMode; ++ } ++ } ++ else ++ { // One of B, G, A. ++ InitWirelessMode = ieee->mode; ++ } ++//by amy for power save ++#ifdef ENABLE_IPS ++// printk("initialize ENABLE_IPS\n"); ++ priv->eRFPowerState = eRfOff; ++ priv->RfOffReason = 0; ++ { ++ // u32 tmp2; ++ // u32 tmp = jiffies; ++ MgntActSet_RF_State(dev, eRfOn, 0); ++ // tmp2 = jiffies; ++ // printk("rf on cost jiffies:%lx\n", (tmp2-tmp)*1000/HZ); ++ } ++// DrvIFIndicateCurrentPhyStatus(priv); ++ // ++ // If inactive power mode is enabled, disable rf while in disconnected state. ++ // 2007.07.16, by shien chang. ++ // ++ if (priv->bInactivePs) ++ { ++ // u32 tmp2; ++ // u32 tmp = jiffies; ++ MgntActSet_RF_State(dev,eRfOff, RF_CHANGE_BY_IPS); ++ // tmp2 = jiffies; ++ // printk("rf off cost jiffies:%lx\n", (tmp2-tmp)*1000/HZ); ++ ++ } ++#endif ++// IPSEnter(dev); ++//by amy for power save ++#ifdef TODO ++ // Turn off RF if necessary. 2005.08.23, by rcnjko. ++ // We shall turn off RF after setting CMDR, otherwise, ++ // RF will be turnned on after we enable MAC Tx/Rx. ++ if(Adapter->MgntInfo.RegRfOff == TRUE) ++ { ++ SetRFPowerState8185(Adapter, RF_OFF); ++ } ++ else ++ { ++ SetRFPowerState8185(Adapter, RF_ON); ++ } ++#endif ++ ++/* //these is equal with above TODO. ++ write_nic_byte(dev, CR9346, 0xc0); // enable config register write ++ write_nic_byte(dev, CONFIG3, read_nic_byte(dev, CONFIG3) | CONFIG3_PARM_En); ++ RF_WriteReg(dev, 0x4, 0x9FF); ++ write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON); ++ write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON); ++ write_nic_byte(dev, CONFIG3, (read_nic_byte(dev, CONFIG3)&(~CONFIG3_PARM_En))); ++ write_nic_byte(dev, CR9346, 0x00); ++*/ ++ ++ ActSetWirelessMode8185(dev, (u8)(InitWirelessMode)); ++ ++ //----------------------------------------------------------------------------- ++ ++ rtl8185b_irq_enable(dev); ++ ++ netif_start_queue(dev); ++ ++ } ++ ++ ++void rtl8185b_rx_enable(struct net_device *dev) ++{ ++ u8 cmd; ++ //u32 rxconf; ++ /* for now we accept data, management & ctl frame*/ ++ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); ++#if 0 ++ rxconf=read_nic_dword(dev,RX_CONF); ++ rxconf = rxconf &~ MAC_FILTER_MASK; ++ rxconf = rxconf | (1<flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ ++ dev->flags & IFF_PROMISC){ ++ rxconf = rxconf | (1<card_8185 == 0) ++ rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MASTER){ ++ rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MONITOR){ ++ rxconf = rxconf | (1<crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) ++ rxconf = rxconf | (1<card_8185){ ++ rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK; ++ rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<card_8185) ++ rxconf = rxconf | RCR_ONLYERLPKT; ++ ++ rxconf = rxconf &~ RCR_CS_MASK; ++ if(!priv->card_8185) ++ rxconf |= (priv->rcr_csense<flags & IFF_PROMISC) DMESG ("NIC in promisc mode"); ++ ++ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \ ++ dev->flags & IFF_PROMISC){ ++ priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM); ++ priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP; ++ } ++ ++ /*if(priv->ieee80211->iw_mode == IW_MODE_MASTER){ ++ rxconf = rxconf | (1<ieee80211->iw_mode == IW_MODE_MONITOR){ ++ priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACF | RCR_APWRMGT | RCR_AICV; ++ } ++ ++ if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) ++ priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACRC32; ++ ++ write_nic_dword(dev, RCR, priv->ReceiveConfig); ++ ++ fix_rx_fifo(dev); ++ ++#ifdef DEBUG_RX ++ DMESG("rxconf: %x %x",priv->ReceiveConfig ,read_nic_dword(dev,RCR)); ++#endif ++ cmd=read_nic_byte(dev,CMD); ++ write_nic_byte(dev,CMD,cmd | (1<card_8185){ ++ ++ ++ byte = read_nic_byte(dev,CW_CONF); ++ byte &= ~(1<card_8185){ ++ ++ txconf = txconf &~ (1<retry_data<retry_rts<card_8185){ ++ if(priv->hw_plcp_len) ++ txconf = txconf &~ TCR_PLCP_LEN; ++ else ++ txconf = txconf | TCR_PLCP_LEN; ++ }else{ ++ txconf = txconf &~ TCR_SAT; ++ } ++ txconf = txconf &~ TCR_MXDMA_MASK; ++ txconf = txconf | (TCR_MXDMA_2048<ieee80211->hw_wep) ++// txconf=txconf &~ (1<TransmitConfig); ++ byte = read_nic_byte(dev, MSR); ++ byte |= MSR_LINK_ENEDCA; ++ write_nic_byte(dev, MSR, byte); ++ ++ fix_tx_fifo(dev); ++ ++#ifdef DEBUG_TX ++ DMESG("txconf: %x %x",priv->TransmitConfig,read_nic_dword(dev,TCR)); ++#endif ++ ++ cmd=read_nic_byte(dev,CMD); ++ write_nic_byte(dev,CMD,cmd | (1<dma_poll_mask); ++ rtl8180_set_mode(dev,EPROM_CMD_NORMAL); ++ */ ++} ++ ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-add-serverengines-benet-10gb-ethernet-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-serverengines-benet-10gb-ethernet-driver.patch new file mode 100644 index 000000000..78550f977 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-add-serverengines-benet-10gb-ethernet-driver.patch @@ -0,0 +1,12439 @@ +From 225bdeadbbf71d061cf69bc924f92e8c01540001 Mon Sep 17 00:00:00 2001 +From: Subbu Seetharaman +Date: Sun, 2 Nov 2008 08:09:57 -0500 +Subject: Staging: Add ServerEngines benet 10Gb ethernet driver +Patch-mainline: 2.6.29 + +From: Subbu Seetharaman + +Signed-off-by: Jeff Garzik +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/benet/Kconfig | 7 + drivers/staging/benet/MAINTAINERS | 6 + drivers/staging/benet/Makefile | 14 + drivers/staging/benet/TODO | 7 + drivers/staging/benet/asyncmesg.h | 98 ++ + drivers/staging/benet/be_cm.h | 134 ++ + drivers/staging/benet/be_common.h | 53 + + drivers/staging/benet/be_ethtool.c | 348 +++++++ + drivers/staging/benet/be_init.c | 1381 ++++++++++++++++++++++++++++++ + drivers/staging/benet/be_int.c | 872 ++++++++++++++++++ + drivers/staging/benet/be_netif.c | 706 +++++++++++++++ + drivers/staging/benet/benet.h | 429 +++++++++ + drivers/staging/benet/bestatus.h | 103 ++ + drivers/staging/benet/cev.h | 243 +++++ + drivers/staging/benet/cq.c | 211 ++++ + drivers/staging/benet/descriptors.h | 71 + + drivers/staging/benet/doorbells.h | 179 +++ + drivers/staging/benet/ep.h | 66 + + drivers/staging/benet/eq.c | 299 ++++++ + drivers/staging/benet/eth.c | 1273 +++++++++++++++++++++++++++ + drivers/staging/benet/etx_context.h | 55 + + drivers/staging/benet/funcobj.c | 565 ++++++++++++ + drivers/staging/benet/fwcmd_common.h | 222 ++++ + drivers/staging/benet/fwcmd_common_bmap.h | 717 +++++++++++++++ + drivers/staging/benet/fwcmd_eth_bmap.h | 280 ++++++ + drivers/staging/benet/fwcmd_hdr_bmap.h | 54 + + drivers/staging/benet/fwcmd_mcc.h | 94 ++ + drivers/staging/benet/fwcmd_opcodes.h | 244 +++++ + drivers/staging/benet/fwcmd_types_bmap.h | 29 + drivers/staging/benet/host_struct.h | 182 +++ + drivers/staging/benet/hwlib.h | 829 ++++++++++++++++++ + drivers/staging/benet/mpu.c | 1364 +++++++++++++++++++++++++++++ + drivers/staging/benet/mpu.h | 74 + + drivers/staging/benet/mpu_context.h | 46 + drivers/staging/benet/pcicfg.h | 825 +++++++++++++++++ + drivers/staging/benet/post_codes.h | 111 ++ + drivers/staging/benet/regmap.h | 68 + + 39 files changed, 12262 insertions(+) + +--- /dev/null ++++ b/drivers/staging/benet/asyncmesg.h +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __asyncmesg_amap_h__ ++#define __asyncmesg_amap_h__ ++#include "fwcmd_common.h" ++ ++/* --- ASYNC_EVENT_CODES --- */ ++#define ASYNC_EVENT_CODE_LINK_STATE (1) ++#define ASYNC_EVENT_CODE_ISCSI (2) ++ ++/* --- ASYNC_LINK_STATES --- */ ++#define ASYNC_EVENT_LINK_DOWN (0) /* Link Down on a port */ ++#define ASYNC_EVENT_LINK_UP (1) /* Link Up on a port */ ++ ++/* ++ * The last 4 bytes of the async events have this common format. It allows ++ * the driver to distinguish [link]MCC_CQ_ENTRY[/link] structs from ++ * asynchronous events. Both arrive on the same completion queue. This ++ * structure also contains the common fields used to decode the async event. ++ */ ++struct BE_ASYNC_EVENT_TRAILER_AMAP { ++ u8 rsvd0[8]; /* DWORD 0 */ ++ u8 event_code[8]; /* DWORD 0 */ ++ u8 event_type[8]; /* DWORD 0 */ ++ u8 rsvd1[6]; /* DWORD 0 */ ++ u8 async_event; /* DWORD 0 */ ++ u8 valid; /* DWORD 0 */ ++} __packed; ++struct ASYNC_EVENT_TRAILER_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * Applicable in Initiator, Target and NIC modes. ++ * A link state async event is seen by all device drivers as soon they ++ * create an MCC ring. Thereafter, anytime the link status changes the ++ * drivers will receive a link state async event. Notifications continue to ++ * be sent until a driver destroys its MCC ring. A link down event is ++ * reported when either port loses link. A link up event is reported ++ * when either port regains link. When BE's failover mechanism is enabled, a ++ * link down on the active port causes traffic to be diverted to the standby ++ * port by the BE's ARM firmware (assuming the standby port has link). In ++ * this case, the standy port assumes the active status. Note: when link is ++ * restored on the failed port, traffic continues on the currently active ++ * port. The ARM firmware does not attempt to 'fail back' traffic to ++ * the restored port. ++ */ ++#if 0 ++struct BE_ASYNC_EVENT_LINK_STATE_AMAP { ++ struct BE_UEXACT8_AMAP port0_link_status; ++ struct BE_UEXACT8_AMAP port1_link_status; ++ struct BE_UEXACT8_AMAP active_port; ++ u8 rsvd0[8]; /* DWORD 0 */ ++ struct BE_UEXACT8_AMAP port0_duplex; ++ struct BE_UEXACT8_AMAP port0_speed; ++ struct BE_UEXACT8_AMAP port1_duplex; ++ struct BE_UEXACT8_AMAP port1_speed; ++ struct BE_UEXACT8_AMAP port0_fault; ++ struct BE_UEXACT8_AMAP port1_fault; ++ u8 rsvd1[2][8]; /* DWORD 2 */ ++ struct BE_ASYNC_EVENT_TRAILER_AMAP trailer; ++} __packed; ++#endif ++struct BE_ASYNC_EVENT_LINK_STATE_AMAP { ++ u8 port0_link_status[8]; ++ u8 port1_link_status[8]; ++ u8 active_port[8]; ++ u8 rsvd0[8]; /* DWORD 0 */ ++ u8 port0_duplex[8]; ++ u8 port0_speed[8]; ++ u8 port1_duplex[8]; ++ u8 port1_speed[8]; ++ u8 port0_fault[8]; ++ u8 port1_fault[8]; ++ u8 rsvd1[2][8]; /* DWORD 2 */ ++ struct BE_ASYNC_EVENT_TRAILER_AMAP trailer; ++} __packed; ++struct ASYNC_EVENT_LINK_STATE_AMAP { ++ u32 dw[4]; ++}; ++#endif /* __asyncmesg_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/be_cm.h +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __be_cm_amap_h__ ++#define __be_cm_amap_h__ ++#include "be_common.h" ++#include "etx_context.h" ++#include "mpu_context.h" ++ ++/* ++ * --- CEV_WATERMARK_ENUM --- ++ * CQ/EQ Watermark Encodings. Encoded as number of free entries in ++ * Queue when Watermark is reached. ++ */ ++#define CEV_WMARK_0 (0) /* Watermark when Queue full */ ++#define CEV_WMARK_16 (1) /* Watermark at 16 free entries */ ++#define CEV_WMARK_32 (2) /* Watermark at 32 free entries */ ++#define CEV_WMARK_48 (3) /* Watermark at 48 free entries */ ++#define CEV_WMARK_64 (4) /* Watermark at 64 free entries */ ++#define CEV_WMARK_80 (5) /* Watermark at 80 free entries */ ++#define CEV_WMARK_96 (6) /* Watermark at 96 free entries */ ++#define CEV_WMARK_112 (7) /* Watermark at 112 free entries */ ++#define CEV_WMARK_128 (8) /* Watermark at 128 free entries */ ++#define CEV_WMARK_144 (9) /* Watermark at 144 free entries */ ++#define CEV_WMARK_160 (10) /* Watermark at 160 free entries */ ++#define CEV_WMARK_176 (11) /* Watermark at 176 free entries */ ++#define CEV_WMARK_192 (12) /* Watermark at 192 free entries */ ++#define CEV_WMARK_208 (13) /* Watermark at 208 free entries */ ++#define CEV_WMARK_224 (14) /* Watermark at 224 free entries */ ++#define CEV_WMARK_240 (15) /* Watermark at 240 free entries */ ++ ++/* ++ * --- CQ_CNT_ENUM --- ++ * Completion Queue Count Encodings. ++ */ ++#define CEV_CQ_CNT_256 (0) /* CQ has 256 entries */ ++#define CEV_CQ_CNT_512 (1) /* CQ has 512 entries */ ++#define CEV_CQ_CNT_1024 (2) /* CQ has 1024 entries */ ++ ++/* ++ * --- EQ_CNT_ENUM --- ++ * Event Queue Count Encodings. ++ */ ++#define CEV_EQ_CNT_256 (0) /* EQ has 256 entries (16-byte EQEs only) */ ++#define CEV_EQ_CNT_512 (1) /* EQ has 512 entries (16-byte EQEs only) */ ++#define CEV_EQ_CNT_1024 (2) /* EQ has 1024 entries (4-byte or */ ++ /* 16-byte EQEs only) */ ++#define CEV_EQ_CNT_2048 (3) /* EQ has 2048 entries (4-byte or */ ++ /* 16-byte EQEs only) */ ++#define CEV_EQ_CNT_4096 (4) /* EQ has 4096 entries (4-byte EQEs only) */ ++ ++/* ++ * --- EQ_SIZE_ENUM --- ++ * Event Queue Entry Size Encoding. ++ */ ++#define CEV_EQ_SIZE_4 (0) /* EQE is 4 bytes */ ++#define CEV_EQ_SIZE_16 (1) /* EQE is 16 bytes */ ++ ++/* ++ * Completion Queue Context Table Entry. Contains the state of a CQ. ++ * Located in RAM within the CEV block. ++ */ ++struct BE_CQ_CONTEXT_AMAP { ++ u8 Cidx[11]; /* DWORD 0 */ ++ u8 Watermark[4]; /* DWORD 0 */ ++ u8 NoDelay; /* DWORD 0 */ ++ u8 EPIdx[11]; /* DWORD 0 */ ++ u8 Count[2]; /* DWORD 0 */ ++ u8 valid; /* DWORD 0 */ ++ u8 SolEvent; /* DWORD 0 */ ++ u8 Eventable; /* DWORD 0 */ ++ u8 Pidx[11]; /* DWORD 1 */ ++ u8 PD[10]; /* DWORD 1 */ ++ u8 EQID[7]; /* DWORD 1 */ ++ u8 Func; /* DWORD 1 */ ++ u8 WME; /* DWORD 1 */ ++ u8 Stalled; /* DWORD 1 */ ++ u8 Armed; /* DWORD 1 */ ++} __packed; ++struct CQ_CONTEXT_AMAP { ++ u32 dw[2]; ++}; ++ ++/* ++ * Event Queue Context Table Entry. Contains the state of an EQ. ++ * Located in RAM in the CEV block. ++ */ ++struct BE_EQ_CONTEXT_AMAP { ++ u8 Cidx[13]; /* DWORD 0 */ ++ u8 rsvd0[2]; /* DWORD 0 */ ++ u8 Func; /* DWORD 0 */ ++ u8 EPIdx[13]; /* DWORD 0 */ ++ u8 valid; /* DWORD 0 */ ++ u8 rsvd1; /* DWORD 0 */ ++ u8 Size; /* DWORD 0 */ ++ u8 Pidx[13]; /* DWORD 1 */ ++ u8 rsvd2[3]; /* DWORD 1 */ ++ u8 PD[10]; /* DWORD 1 */ ++ u8 Count[3]; /* DWORD 1 */ ++ u8 SolEvent; /* DWORD 1 */ ++ u8 Stalled; /* DWORD 1 */ ++ u8 Armed; /* DWORD 1 */ ++ u8 Watermark[4]; /* DWORD 2 */ ++ u8 WME; /* DWORD 2 */ ++ u8 rsvd3[3]; /* DWORD 2 */ ++ u8 EventVect[6]; /* DWORD 2 */ ++ u8 rsvd4[2]; /* DWORD 2 */ ++ u8 Delay[8]; /* DWORD 2 */ ++ u8 rsvd5[6]; /* DWORD 2 */ ++ u8 TMR; /* DWORD 2 */ ++ u8 rsvd6; /* DWORD 2 */ ++ u8 rsvd7[32]; /* DWORD 3 */ ++} __packed; ++struct EQ_CONTEXT_AMAP { ++ u32 dw[4]; ++}; ++ ++#endif /* __be_cm_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/be_common.h +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __be_common_amap_h__ ++#define __be_common_amap_h__ ++ ++/* Physical Address. */ ++struct BE_PHYS_ADDR_AMAP { ++ u8 lo[32]; /* DWORD 0 */ ++ u8 hi[32]; /* DWORD 1 */ ++} __packed; ++struct PHYS_ADDR_AMAP { ++ u32 dw[2]; ++}; ++ ++/* Virtual Address. */ ++struct BE_VIRT_ADDR_AMAP { ++ u8 lo[32]; /* DWORD 0 */ ++ u8 hi[32]; /* DWORD 1 */ ++} __packed; ++struct VIRT_ADDR_AMAP { ++ u32 dw[2]; ++}; ++ ++/* Scatter gather element. */ ++struct BE_SGE_AMAP { ++ u8 addr_hi[32]; /* DWORD 0 */ ++ u8 addr_lo[32]; /* DWORD 1 */ ++ u8 rsvd0[32]; /* DWORD 2 */ ++ u8 len[16]; /* DWORD 3 */ ++ u8 rsvd1[16]; /* DWORD 3 */ ++} __packed; ++struct SGE_AMAP { ++ u32 dw[4]; ++}; ++ ++#endif /* __be_common_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/be_ethtool.c +@@ -0,0 +1,348 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * be_ethtool.c ++ * ++ * This file contains various functions that ethtool can use ++ * to talk to the driver and the BE H/W. ++ */ ++ ++#include "benet.h" ++ ++#include ++ ++static const char benet_gstrings_stats[][ETH_GSTRING_LEN] = { ++/* net_device_stats */ ++ "rx_packets", ++ "tx_packets", ++ "rx_bytes", ++ "tx_bytes", ++ "rx_errors", ++ "tx_errors", ++ "rx_dropped", ++ "tx_dropped", ++ "multicast", ++ "collisions", ++ "rx_length_errors", ++ "rx_over_errors", ++ "rx_crc_errors", ++ "rx_frame_errors", ++ "rx_fifo_errors", ++ "rx_missed_errors", ++ "tx_aborted_errors", ++ "tx_carrier_errors", ++ "tx_fifo_errors", ++ "tx_heartbeat_errors", ++ "tx_window_errors", ++ "rx_compressed", ++ "tc_compressed", ++/* BE driver Stats */ ++ "bes_tx_reqs", ++ "bes_tx_fails", ++ "bes_fwd_reqs", ++ "bes_tx_wrbs", ++ "bes_interrupts", ++ "bes_events", ++ "bes_tx_events", ++ "bes_rx_events", ++ "bes_tx_compl", ++ "bes_rx_compl", ++ "bes_ethrx_post_fail", ++ "bes_802_3_dropped_frames", ++ "bes_802_3_malformed_frames", ++ "bes_rx_misc_pkts", ++ "bes_eth_tx_rate", ++ "bes_eth_rx_rate", ++ "Num Packets collected", ++ "Num Times Flushed", ++}; ++ ++#define NET_DEV_STATS_LEN \ ++ (sizeof(struct net_device_stats)/sizeof(unsigned long)) ++ ++#define BENET_STATS_LEN ARRAY_SIZE(benet_gstrings_stats) ++ ++static void ++be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ ++ strncpy(drvinfo->driver, be_driver_name, 32); ++ strncpy(drvinfo->version, be_drvr_ver, 32); ++ strncpy(drvinfo->fw_version, be_fw_ver, 32); ++ strcpy(drvinfo->bus_info, pci_name(adapter->pdev)); ++ drvinfo->testinfo_len = 0; ++ drvinfo->regdump_len = 0; ++ drvinfo->eedump_len = 0; ++} ++ ++static int ++be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ ++ coalesce->rx_max_coalesced_frames = adapter->max_rx_coal; ++ ++ coalesce->rx_coalesce_usecs = adapter->cur_eqd; ++ coalesce->rx_coalesce_usecs_high = adapter->max_eqd; ++ coalesce->rx_coalesce_usecs_low = adapter->min_eqd; ++ ++ coalesce->tx_coalesce_usecs = adapter->cur_eqd; ++ coalesce->tx_coalesce_usecs_high = adapter->max_eqd; ++ coalesce->tx_coalesce_usecs_low = adapter->min_eqd; ++ ++ coalesce->use_adaptive_rx_coalesce = adapter->enable_aic; ++ coalesce->use_adaptive_tx_coalesce = adapter->enable_aic; ++ ++ return 0; ++} ++ ++/* ++ * This routine is used to set interrup coalescing delay *as well as* ++ * the number of pkts to coalesce for LRO. ++ */ ++static int ++be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ struct be_eq_object *eq_objectp; ++ u32 max, min, cur; ++ int status; ++ ++ adapter->max_rx_coal = coalesce->rx_max_coalesced_frames; ++ if (adapter->max_rx_coal >= BE_LRO_MAX_PKTS) ++ adapter->max_rx_coal = BE_LRO_MAX_PKTS; ++ ++ if (adapter->enable_aic == 0 && ++ coalesce->use_adaptive_rx_coalesce == 1) { ++ /* if AIC is being turned on now, start with an EQD of 0 */ ++ adapter->cur_eqd = 0; ++ } ++ adapter->enable_aic = coalesce->use_adaptive_rx_coalesce; ++ ++ /* round off to nearest multiple of 8 */ ++ max = (((coalesce->rx_coalesce_usecs_high + 4) >> 3) << 3); ++ min = (((coalesce->rx_coalesce_usecs_low + 4) >> 3) << 3); ++ cur = (((coalesce->rx_coalesce_usecs + 4) >> 3) << 3); ++ ++ if (adapter->enable_aic) { ++ /* accept low and high if AIC is enabled */ ++ if (max > MAX_EQD) ++ max = MAX_EQD; ++ if (min > max) ++ min = max; ++ adapter->max_eqd = max; ++ adapter->min_eqd = min; ++ if (adapter->cur_eqd > max) ++ adapter->cur_eqd = max; ++ if (adapter->cur_eqd < min) ++ adapter->cur_eqd = min; ++ } else { ++ /* accept specified coalesce_usecs only if AIC is disabled */ ++ if (cur > MAX_EQD) ++ cur = MAX_EQD; ++ eq_objectp = &pnob->event_q_obj; ++ status = ++ be_eq_modify_delay(&pnob->fn_obj, 1, &eq_objectp, &cur, ++ NULL, NULL, NULL); ++ if (status == BE_SUCCESS) ++ adapter->cur_eqd = cur; ++ } ++ return 0; ++} ++ ++static u32 be_get_rx_csum(struct net_device *netdev) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ return adapter->rx_csum; ++} ++ ++static int be_set_rx_csum(struct net_device *netdev, uint32_t data) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ ++ if (data) ++ adapter->rx_csum = 1; ++ else ++ adapter->rx_csum = 0; ++ ++ return 0; ++} ++ ++static void ++be_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) ++{ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ memcpy(data, *benet_gstrings_stats, ++ sizeof(benet_gstrings_stats)); ++ break; ++ } ++} ++ ++static int be_get_stats_count(struct net_device *netdev) ++{ ++ return BENET_STATS_LEN; ++} ++ ++static void ++be_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, uint64_t *data) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ int i; ++ ++ benet_get_stats(netdev); ++ ++ for (i = 0; i <= NET_DEV_STATS_LEN; i++) ++ data[i] = ((unsigned long *)&adapter->benet_stats)[i]; ++ ++ data[i] = adapter->be_stat.bes_tx_reqs; ++ data[i++] = adapter->be_stat.bes_tx_fails; ++ data[i++] = adapter->be_stat.bes_fwd_reqs; ++ data[i++] = adapter->be_stat.bes_tx_wrbs; ++ ++ data[i++] = adapter->be_stat.bes_ints; ++ data[i++] = adapter->be_stat.bes_events; ++ data[i++] = adapter->be_stat.bes_tx_events; ++ data[i++] = adapter->be_stat.bes_rx_events; ++ data[i++] = adapter->be_stat.bes_tx_compl; ++ data[i++] = adapter->be_stat.bes_rx_compl; ++ data[i++] = adapter->be_stat.bes_ethrx_post_fail; ++ data[i++] = adapter->be_stat.bes_802_3_dropped_frames; ++ data[i++] = adapter->be_stat.bes_802_3_malformed_frames; ++ data[i++] = adapter->be_stat.bes_rx_misc_pkts; ++ data[i++] = adapter->be_stat.bes_eth_tx_rate; ++ data[i++] = adapter->be_stat.bes_eth_rx_rate; ++ data[i++] = adapter->be_stat.bes_rx_coal; ++ data[i++] = adapter->be_stat.bes_rx_flush; ++ ++} ++ ++static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ++{ ++ ecmd->speed = SPEED_10000; ++ ecmd->duplex = DUPLEX_FULL; ++ ecmd->autoneg = AUTONEG_DISABLE; ++ return 0; ++} ++ ++/* Get the Ring parameters from the pnob */ ++static void ++be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ ++ /* Pre Set Maxims */ ++ ring->rx_max_pending = pnob->rx_q_len; ++ ring->rx_mini_max_pending = ring->rx_mini_max_pending; ++ ring->rx_jumbo_max_pending = ring->rx_jumbo_max_pending; ++ ring->tx_max_pending = pnob->tx_q_len; ++ ++ /* Current hardware Settings */ ++ ring->rx_pending = atomic_read(&pnob->rx_q_posted); ++ ring->rx_mini_pending = ring->rx_mini_pending; ++ ring->rx_jumbo_pending = ring->rx_jumbo_pending; ++ ring->tx_pending = atomic_read(&pnob->tx_q_used); ++ ++} ++ ++static void ++be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ bool rxfc, txfc; ++ int status; ++ ++ status = be_eth_get_flow_control(&pnob->fn_obj, &txfc, &rxfc); ++ if (status != BE_SUCCESS) { ++ dev_info(&netdev->dev, "Unable to get pause frame settings\n"); ++ /* return defaults */ ++ ecmd->rx_pause = 1; ++ ecmd->tx_pause = 0; ++ ecmd->autoneg = AUTONEG_ENABLE; ++ return; ++ } ++ ++ if (txfc == true) ++ ecmd->tx_pause = 1; ++ else ++ ecmd->tx_pause = 0; ++ ++ if (rxfc == true) ++ ecmd->rx_pause = 1; ++ else ++ ecmd->rx_pause = 0; ++ ++ ecmd->autoneg = AUTONEG_ENABLE; ++} ++ ++static int ++be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ bool txfc, rxfc; ++ int status; ++ ++ if (ecmd->autoneg != AUTONEG_ENABLE) ++ return -EINVAL; ++ ++ if (ecmd->tx_pause) ++ txfc = true; ++ else ++ txfc = false; ++ ++ if (ecmd->rx_pause) ++ rxfc = true; ++ else ++ rxfc = false; ++ ++ status = be_eth_set_flow_control(&pnob->fn_obj, txfc, rxfc); ++ if (status != BE_SUCCESS) { ++ dev_info(&netdev->dev, "Unable to set pause frame settings\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++struct ethtool_ops be_ethtool_ops = { ++ .get_settings = be_get_settings, ++ .get_drvinfo = be_get_drvinfo, ++ .get_link = ethtool_op_get_link, ++ .get_coalesce = be_get_coalesce, ++ .set_coalesce = be_set_coalesce, ++ .get_ringparam = be_get_ringparam, ++ .get_pauseparam = be_get_pauseparam, ++ .set_pauseparam = be_set_pauseparam, ++ .get_rx_csum = be_get_rx_csum, ++ .set_rx_csum = be_set_rx_csum, ++ .get_tx_csum = ethtool_op_get_tx_csum, ++ .set_tx_csum = ethtool_op_set_tx_csum, ++ .get_sg = ethtool_op_get_sg, ++ .set_sg = ethtool_op_set_sg, ++ .get_tso = ethtool_op_get_tso, ++ .set_tso = ethtool_op_set_tso, ++ .get_strings = be_get_strings, ++ .get_stats_count = be_get_stats_count, ++ .get_ethtool_stats = be_get_ethtool_stats, ++}; +--- /dev/null ++++ b/drivers/staging/benet/be_init.c +@@ -0,0 +1,1381 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include ++#include "benet.h" ++ ++#define DRVR_VERSION "1.0.728" ++ ++static const struct pci_device_id be_device_id_table[] = { ++ {PCI_DEVICE(0x19a2, 0x0201)}, ++ {0} ++}; ++ ++MODULE_DEVICE_TABLE(pci, be_device_id_table); ++ ++MODULE_VERSION(DRVR_VERSION); ++ ++#define DRV_DESCRIPTION "ServerEngines BladeEngine Network Driver Version " ++ ++MODULE_DESCRIPTION(DRV_DESCRIPTION DRVR_VERSION); ++MODULE_AUTHOR("ServerEngines"); ++MODULE_LICENSE("GPL"); ++ ++static unsigned int msix = 1; ++module_param(msix, uint, S_IRUGO); ++MODULE_PARM_DESC(msix, "Use MSI-x interrupts"); ++ ++static unsigned int rxbuf_size = 2048; /* Default RX frag size */ ++module_param(rxbuf_size, uint, S_IRUGO); ++MODULE_PARM_DESC(rxbuf_size, "Size of buffers to hold Rx data"); ++ ++const char be_drvr_ver[] = DRVR_VERSION; ++char be_fw_ver[32]; /* F/W version filled in by be_probe */ ++char be_driver_name[] = "benet"; ++ ++/* ++ * Number of entries in each queue. ++ */ ++#define EVENT_Q_LEN 1024 ++#define ETH_TXQ_LEN 2048 ++#define ETH_TXCQ_LEN 1024 ++#define ETH_RXQ_LEN 1024 /* Does not support any other value */ ++#define ETH_UC_RXCQ_LEN 1024 ++#define ETH_BC_RXCQ_LEN 256 ++#define MCC_Q_LEN 64 /* total size not to exceed 8 pages */ ++#define MCC_CQ_LEN 256 ++ ++/* Bit mask describing events of interest to be traced */ ++unsigned int trace_level; ++ ++static int ++init_pci_be_function(struct be_adapter *adapter, struct pci_dev *pdev) ++{ ++ u64 pa; ++ ++ /* CSR */ ++ pa = pci_resource_start(pdev, 2); ++ adapter->csr_va = ioremap_nocache(pa, pci_resource_len(pdev, 2)); ++ if (adapter->csr_va == NULL) ++ return -ENOMEM; ++ ++ /* Door Bell */ ++ pa = pci_resource_start(pdev, 4); ++ adapter->db_va = ioremap_nocache(pa, (128 * 1024)); ++ if (adapter->db_va == NULL) { ++ iounmap(adapter->csr_va); ++ return -ENOMEM; ++ } ++ ++ /* PCI */ ++ pa = pci_resource_start(pdev, 1); ++ adapter->pci_va = ioremap_nocache(pa, pci_resource_len(pdev, 1)); ++ if (adapter->pci_va == NULL) { ++ iounmap(adapter->csr_va); ++ iounmap(adapter->db_va); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++/* ++ This function enables the interrupt corresponding to the Event ++ queue ID for the given NetObject ++*/ ++void be_enable_eq_intr(struct be_net_object *pnob) ++{ ++ struct CQ_DB_AMAP cqdb; ++ cqdb.dw[0] = 0; ++ AMAP_SET_BITS_PTR(CQ_DB, event, &cqdb, 1); ++ AMAP_SET_BITS_PTR(CQ_DB, rearm, &cqdb, 1); ++ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &cqdb, 0); ++ AMAP_SET_BITS_PTR(CQ_DB, qid, &cqdb, pnob->event_q_id); ++ PD_WRITE(&pnob->fn_obj, cq_db, cqdb.dw[0]); ++} ++ ++/* ++ This function disables the interrupt corresponding to the Event ++ queue ID for the given NetObject ++*/ ++void be_disable_eq_intr(struct be_net_object *pnob) ++{ ++ struct CQ_DB_AMAP cqdb; ++ cqdb.dw[0] = 0; ++ AMAP_SET_BITS_PTR(CQ_DB, event, &cqdb, 1); ++ AMAP_SET_BITS_PTR(CQ_DB, rearm, &cqdb, 0); ++ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &cqdb, 0); ++ AMAP_SET_BITS_PTR(CQ_DB, qid, &cqdb, pnob->event_q_id); ++ PD_WRITE(&pnob->fn_obj, cq_db, cqdb.dw[0]); ++} ++ ++/* ++ This function enables the interrupt from the network function ++ of the BladeEngine. Use the function be_disable_eq_intr() ++ to enable the interrupt from the event queue of only one specific ++ NetObject ++*/ ++void be_enable_intr(struct be_net_object *pnob) ++{ ++ struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP ctrl; ++ u32 host_intr; ++ ++ ctrl.dw[0] = PCICFG1_READ(&pnob->fn_obj, host_timer_int_ctrl); ++ host_intr = AMAP_GET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR, ++ hostintr, ctrl.dw); ++ if (!host_intr) { ++ AMAP_SET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR, ++ hostintr, ctrl.dw, 1); ++ PCICFG1_WRITE(&pnob->fn_obj, host_timer_int_ctrl, ++ ctrl.dw[0]); ++ } ++} ++ ++/* ++ This function disables the interrupt from the network function of ++ the BladeEngine. Use the function be_disable_eq_intr() to ++ disable the interrupt from the event queue of only one specific NetObject ++*/ ++void be_disable_intr(struct be_net_object *pnob) ++{ ++ ++ struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP ctrl; ++ u32 host_intr; ++ ctrl.dw[0] = PCICFG1_READ(&pnob->fn_obj, host_timer_int_ctrl); ++ host_intr = AMAP_GET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR, ++ hostintr, ctrl.dw); ++ if (host_intr) { ++ AMAP_SET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR, hostintr, ++ ctrl.dw, 0); ++ PCICFG1_WRITE(&pnob->fn_obj, host_timer_int_ctrl, ++ ctrl.dw[0]); ++ } ++} ++ ++static int be_enable_msix(struct be_adapter *adapter) ++{ ++ int i, ret; ++ ++ if (!msix) ++ return -1; ++ ++ for (i = 0; i < BE_MAX_REQ_MSIX_VECTORS; i++) ++ adapter->msix_entries[i].entry = i; ++ ++ ret = pci_enable_msix(adapter->pdev, adapter->msix_entries, ++ BE_MAX_REQ_MSIX_VECTORS); ++ ++ if (ret == 0) ++ adapter->msix_enabled = 1; ++ return ret; ++} ++ ++static int be_register_isr(struct be_adapter *adapter, ++ struct be_net_object *pnob) ++{ ++ struct net_device *netdev = pnob->netdev; ++ int intx = 0, r; ++ ++ netdev->irq = adapter->pdev->irq; ++ r = be_enable_msix(adapter); ++ ++ if (r == 0) { ++ r = request_irq(adapter->msix_entries[0].vector, ++ be_int, IRQF_SHARED, netdev->name, netdev); ++ if (r) { ++ printk(KERN_WARNING ++ "MSIX Request IRQ failed - Errno %d\n", r); ++ intx = 1; ++ pci_disable_msix(adapter->pdev); ++ adapter->msix_enabled = 0; ++ } ++ } else { ++ intx = 1; ++ } ++ ++ if (intx) { ++ r = request_irq(netdev->irq, be_int, IRQF_SHARED, ++ netdev->name, netdev); ++ if (r) { ++ printk(KERN_WARNING ++ "INTx Request IRQ failed - Errno %d\n", r); ++ return -1; ++ } ++ } ++ adapter->isr_registered = 1; ++ return 0; ++} ++ ++static void be_unregister_isr(struct be_adapter *adapter) ++{ ++ struct net_device *netdev = adapter->netdevp; ++ if (adapter->isr_registered) { ++ if (adapter->msix_enabled) { ++ free_irq(adapter->msix_entries[0].vector, netdev); ++ pci_disable_msix(adapter->pdev); ++ adapter->msix_enabled = 0; ++ } else { ++ free_irq(netdev->irq, netdev); ++ } ++ adapter->isr_registered = 0; ++ } ++} ++ ++/* ++ This function processes the Flush Completions that are issued by the ++ ARM F/W, when a Recv Ring is destroyed. A flush completion is ++ identified when a Rx COmpl descriptor has the tcpcksum and udpcksum ++ set and the pktsize is 32. These completions are received on the ++ Rx Completion Queue. ++*/ ++static u32 be_process_rx_flush_cmpl(struct be_net_object *pnob) ++{ ++ struct ETH_RX_COMPL_AMAP *rxcp; ++ unsigned int i = 0; ++ while ((rxcp = be_get_rx_cmpl(pnob)) != NULL) { ++ be_notify_cmpl(pnob, 1, pnob->rx_cq_id, 1); ++ i++; ++ } ++ return i; ++} ++ ++static void be_tx_q_clean(struct be_net_object *pnob) ++{ ++ while (atomic_read(&pnob->tx_q_used)) ++ process_one_tx_compl(pnob, tx_compl_lastwrb_idx_get(pnob)); ++} ++ ++static void be_rx_q_clean(struct be_net_object *pnob) ++{ ++ if (pnob->rx_ctxt) { ++ int i; ++ struct be_rx_page_info *rx_page_info; ++ for (i = 0; i < pnob->rx_q_len; i++) { ++ rx_page_info = &(pnob->rx_page_info[i]); ++ if (!pnob->rx_pg_shared || rx_page_info->page_offset) { ++ pci_unmap_page(pnob->adapter->pdev, ++ pci_unmap_addr(rx_page_info, bus), ++ pnob->rx_buf_size, ++ PCI_DMA_FROMDEVICE); ++ } ++ if (rx_page_info->page) ++ put_page(rx_page_info->page); ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ } ++ pnob->rx_pg_info_hd = 0; ++ } ++} ++ ++static void be_destroy_netobj(struct be_net_object *pnob) ++{ ++ int status; ++ ++ if (pnob->tx_q_created) { ++ status = be_eth_sq_destroy(&pnob->tx_q_obj); ++ pnob->tx_q_created = 0; ++ } ++ ++ if (pnob->rx_q_created) { ++ status = be_eth_rq_destroy(&pnob->rx_q_obj); ++ if (status != 0) { ++ status = be_eth_rq_destroy_options(&pnob->rx_q_obj, 0, ++ NULL, NULL); ++ BUG_ON(status); ++ } ++ pnob->rx_q_created = 0; ++ } ++ ++ be_process_rx_flush_cmpl(pnob); ++ ++ if (pnob->tx_cq_created) { ++ status = be_cq_destroy(&pnob->tx_cq_obj); ++ pnob->tx_cq_created = 0; ++ } ++ ++ if (pnob->rx_cq_created) { ++ status = be_cq_destroy(&pnob->rx_cq_obj); ++ pnob->rx_cq_created = 0; ++ } ++ ++ if (pnob->mcc_q_created) { ++ status = be_mcc_ring_destroy(&pnob->mcc_q_obj); ++ pnob->mcc_q_created = 0; ++ } ++ if (pnob->mcc_cq_created) { ++ status = be_cq_destroy(&pnob->mcc_cq_obj); ++ pnob->mcc_cq_created = 0; ++ } ++ ++ if (pnob->event_q_created) { ++ status = be_eq_destroy(&pnob->event_q_obj); ++ pnob->event_q_created = 0; ++ } ++ be_function_cleanup(&pnob->fn_obj); ++} ++ ++/* ++ * free all resources associated with a pnob ++ * Called at the time of module cleanup as well a any error during ++ * module init. Some resources may be partially allocated in a NetObj. ++ */ ++static void netobject_cleanup(struct be_adapter *adapter, ++ struct be_net_object *pnob) ++{ ++ struct net_device *netdev = adapter->netdevp; ++ ++ if (netif_running(netdev)) { ++ netif_stop_queue(netdev); ++ be_wait_nic_tx_cmplx_cmpl(pnob); ++ be_disable_eq_intr(pnob); ++ } ++ ++ be_unregister_isr(adapter); ++ ++ if (adapter->tasklet_started) { ++ tasklet_kill(&(adapter->sts_handler)); ++ adapter->tasklet_started = 0; ++ } ++ if (pnob->fn_obj_created) ++ be_disable_intr(pnob); ++ ++ if (adapter->dev_state != BE_DEV_STATE_NONE) ++ unregister_netdev(netdev); ++ ++ if (pnob->fn_obj_created) ++ be_destroy_netobj(pnob); ++ ++ adapter->net_obj = NULL; ++ adapter->netdevp = NULL; ++ ++ be_rx_q_clean(pnob); ++ if (pnob->rx_ctxt) { ++ kfree(pnob->rx_page_info); ++ kfree(pnob->rx_ctxt); ++ } ++ ++ be_tx_q_clean(pnob); ++ kfree(pnob->tx_ctxt); ++ ++ if (pnob->mcc_q) ++ pci_free_consistent(adapter->pdev, pnob->mcc_q_size, ++ pnob->mcc_q, pnob->mcc_q_bus); ++ ++ if (pnob->mcc_wrb_ctxt) ++ free_pages((unsigned long)pnob->mcc_wrb_ctxt, ++ get_order(pnob->mcc_wrb_ctxt_size)); ++ ++ if (pnob->mcc_cq) ++ pci_free_consistent(adapter->pdev, pnob->mcc_cq_size, ++ pnob->mcc_cq, pnob->mcc_cq_bus); ++ ++ if (pnob->event_q) ++ pci_free_consistent(adapter->pdev, pnob->event_q_size, ++ pnob->event_q, pnob->event_q_bus); ++ ++ if (pnob->tx_cq) ++ pci_free_consistent(adapter->pdev, pnob->tx_cq_size, ++ pnob->tx_cq, pnob->tx_cq_bus); ++ ++ if (pnob->tx_q) ++ pci_free_consistent(adapter->pdev, pnob->tx_q_size, ++ pnob->tx_q, pnob->tx_q_bus); ++ ++ if (pnob->rx_q) ++ pci_free_consistent(adapter->pdev, pnob->rx_q_size, ++ pnob->rx_q, pnob->rx_q_bus); ++ ++ if (pnob->rx_cq) ++ pci_free_consistent(adapter->pdev, pnob->rx_cq_size, ++ pnob->rx_cq, pnob->rx_cq_bus); ++ ++ ++ if (pnob->mb_ptr) ++ pci_free_consistent(adapter->pdev, pnob->mb_size, pnob->mb_ptr, ++ pnob->mb_bus); ++ ++ free_netdev(netdev); ++} ++ ++ ++static int be_nob_ring_alloc(struct be_adapter *adapter, ++ struct be_net_object *pnob) ++{ ++ u32 size; ++ ++ /* Mail box rd; mailbox pointer needs to be 16 byte aligned */ ++ pnob->mb_size = sizeof(struct MCC_MAILBOX_AMAP) + 16; ++ pnob->mb_ptr = pci_alloc_consistent(adapter->pdev, pnob->mb_size, ++ &pnob->mb_bus); ++ if (!pnob->mb_bus) ++ return -1; ++ memset(pnob->mb_ptr, 0, pnob->mb_size); ++ pnob->mb_rd.va = PTR_ALIGN(pnob->mb_ptr, 16); ++ pnob->mb_rd.pa = PTR_ALIGN(pnob->mb_bus, 16); ++ pnob->mb_rd.length = sizeof(struct MCC_MAILBOX_AMAP); ++ /* ++ * Event queue ++ */ ++ pnob->event_q_len = EVENT_Q_LEN; ++ pnob->event_q_size = pnob->event_q_len * sizeof(struct EQ_ENTRY_AMAP); ++ pnob->event_q = pci_alloc_consistent(adapter->pdev, pnob->event_q_size, ++ &pnob->event_q_bus); ++ if (!pnob->event_q_bus) ++ return -1; ++ memset(pnob->event_q, 0, pnob->event_q_size); ++ /* ++ * Eth TX queue ++ */ ++ pnob->tx_q_len = ETH_TXQ_LEN; ++ pnob->tx_q_port = 0; ++ pnob->tx_q_size = pnob->tx_q_len * sizeof(struct ETH_WRB_AMAP); ++ pnob->tx_q = pci_alloc_consistent(adapter->pdev, pnob->tx_q_size, ++ &pnob->tx_q_bus); ++ if (!pnob->tx_q_bus) ++ return -1; ++ memset(pnob->tx_q, 0, pnob->tx_q_size); ++ /* ++ * Eth TX Compl queue ++ */ ++ pnob->txcq_len = ETH_TXCQ_LEN; ++ pnob->tx_cq_size = pnob->txcq_len * sizeof(struct ETH_TX_COMPL_AMAP); ++ pnob->tx_cq = pci_alloc_consistent(adapter->pdev, pnob->tx_cq_size, ++ &pnob->tx_cq_bus); ++ if (!pnob->tx_cq_bus) ++ return -1; ++ memset(pnob->tx_cq, 0, pnob->tx_cq_size); ++ /* ++ * Eth RX queue ++ */ ++ pnob->rx_q_len = ETH_RXQ_LEN; ++ pnob->rx_q_size = pnob->rx_q_len * sizeof(struct ETH_RX_D_AMAP); ++ pnob->rx_q = pci_alloc_consistent(adapter->pdev, pnob->rx_q_size, ++ &pnob->rx_q_bus); ++ if (!pnob->rx_q_bus) ++ return -1; ++ memset(pnob->rx_q, 0, pnob->rx_q_size); ++ /* ++ * Eth Unicast RX Compl queue ++ */ ++ pnob->rx_cq_len = ETH_UC_RXCQ_LEN; ++ pnob->rx_cq_size = pnob->rx_cq_len * ++ sizeof(struct ETH_RX_COMPL_AMAP); ++ pnob->rx_cq = pci_alloc_consistent(adapter->pdev, pnob->rx_cq_size, ++ &pnob->rx_cq_bus); ++ if (!pnob->rx_cq_bus) ++ return -1; ++ memset(pnob->rx_cq, 0, pnob->rx_cq_size); ++ ++ /* TX resources */ ++ size = pnob->tx_q_len * sizeof(void **); ++ pnob->tx_ctxt = kzalloc(size, GFP_KERNEL); ++ if (pnob->tx_ctxt == NULL) ++ return -1; ++ ++ /* RX resources */ ++ size = pnob->rx_q_len * sizeof(void *); ++ pnob->rx_ctxt = kzalloc(size, GFP_KERNEL); ++ if (pnob->rx_ctxt == NULL) ++ return -1; ++ ++ size = (pnob->rx_q_len * sizeof(struct be_rx_page_info)); ++ pnob->rx_page_info = kzalloc(size, GFP_KERNEL); ++ if (pnob->rx_page_info == NULL) ++ return -1; ++ ++ adapter->eth_statsp = kzalloc(sizeof(struct FWCMD_ETH_GET_STATISTICS), ++ GFP_KERNEL); ++ if (adapter->eth_statsp == NULL) ++ return -1; ++ pnob->rx_buf_size = rxbuf_size; ++ return 0; ++} ++ ++/* ++ This function initializes the be_net_object for subsequent ++ network operations. ++ ++ Before calling this function, the driver must have allocated ++ space for the NetObject structure, initialized the structure, ++ allocated DMAable memory for all the network queues that form ++ part of the NetObject and populated the start address (virtual) ++ and number of entries allocated for each queue in the NetObject structure. ++ ++ The driver must also have allocated memory to hold the ++ mailbox structure (MCC_MAILBOX) and post the physical address, ++ virtual addresses and the size of the mailbox memory in the ++ NetObj.mb_rd. This structure is used by BECLIB for ++ initial communication with the embedded MCC processor. BECLIB ++ uses the mailbox until MCC rings are created for more efficient ++ communication with the MCC processor. ++ ++ If the driver wants to create multiple network interface for more ++ than one protection domain, it can call be_create_netobj() ++ multiple times once for each protection domain. A Maximum of ++ 32 protection domains are supported. ++ ++*/ ++static int ++be_create_netobj(struct be_net_object *pnob, u8 __iomem *csr_va, ++ u8 __iomem *db_va, u8 __iomem *pci_va) ++{ ++ int status = 0; ++ bool eventable = false, tx_no_delay = false, rx_no_delay = false; ++ struct be_eq_object *eq_objectp = NULL; ++ struct be_function_object *pfob = &pnob->fn_obj; ++ struct ring_desc rd; ++ u32 set_rxbuf_size; ++ u32 tx_cmpl_wm = CEV_WMARK_96; /* 0xffffffff to disable */ ++ u32 rx_cmpl_wm = CEV_WMARK_160; /* 0xffffffff to disable */ ++ u32 eq_delay = 0; /* delay in 8usec units. 0xffffffff to disable */ ++ ++ memset(&rd, 0, sizeof(struct ring_desc)); ++ ++ status = be_function_object_create(csr_va, db_va, pci_va, ++ BE_FUNCTION_TYPE_NETWORK, &pnob->mb_rd, pfob); ++ if (status != BE_SUCCESS) ++ return status; ++ pnob->fn_obj_created = true; ++ ++ if (tx_cmpl_wm == 0xffffffff) ++ tx_no_delay = true; ++ if (rx_cmpl_wm == 0xffffffff) ++ rx_no_delay = true; ++ /* ++ * now create the necessary rings ++ * Event Queue first. ++ */ ++ if (pnob->event_q_len) { ++ rd.va = pnob->event_q; ++ rd.pa = pnob->event_q_bus; ++ rd.length = pnob->event_q_size; ++ ++ status = be_eq_create(pfob, &rd, 4, pnob->event_q_len, ++ (u32) -1, /* CEV_WMARK_* or -1 */ ++ eq_delay, /* in 8us units, or -1 */ ++ &pnob->event_q_obj); ++ if (status != BE_SUCCESS) ++ goto error_ret; ++ pnob->event_q_id = pnob->event_q_obj.eq_id; ++ pnob->event_q_created = 1; ++ eventable = true; ++ eq_objectp = &pnob->event_q_obj; ++ } ++ /* ++ * Now Eth Tx Compl. queue. ++ */ ++ if (pnob->txcq_len) { ++ rd.va = pnob->tx_cq; ++ rd.pa = pnob->tx_cq_bus; ++ rd.length = pnob->tx_cq_size; ++ ++ status = be_cq_create(pfob, &rd, ++ pnob->txcq_len * sizeof(struct ETH_TX_COMPL_AMAP), ++ false, /* solicted events, */ ++ tx_no_delay, /* nodelay */ ++ tx_cmpl_wm, /* Watermark encodings */ ++ eq_objectp, &pnob->tx_cq_obj); ++ if (status != BE_SUCCESS) ++ goto error_ret; ++ ++ pnob->tx_cq_id = pnob->tx_cq_obj.cq_id; ++ pnob->tx_cq_created = 1; ++ } ++ /* ++ * Eth Tx queue ++ */ ++ if (pnob->tx_q_len) { ++ struct be_eth_sq_parameters ex_params = { 0 }; ++ u32 type; ++ ++ if (pnob->tx_q_port) { ++ /* TXQ to be bound to a specific port */ ++ type = BE_ETH_TX_RING_TYPE_BOUND; ++ ex_params.port = pnob->tx_q_port - 1; ++ } else ++ type = BE_ETH_TX_RING_TYPE_STANDARD; ++ ++ rd.va = pnob->tx_q; ++ rd.pa = pnob->tx_q_bus; ++ rd.length = pnob->tx_q_size; ++ ++ status = be_eth_sq_create_ex(pfob, &rd, ++ pnob->tx_q_len * sizeof(struct ETH_WRB_AMAP), ++ type, 2, &pnob->tx_cq_obj, ++ &ex_params, &pnob->tx_q_obj); ++ ++ if (status != BE_SUCCESS) ++ goto error_ret; ++ ++ pnob->tx_q_id = pnob->tx_q_obj.bid; ++ pnob->tx_q_created = 1; ++ } ++ /* ++ * Now Eth Rx compl. queue. Always needed. ++ */ ++ rd.va = pnob->rx_cq; ++ rd.pa = pnob->rx_cq_bus; ++ rd.length = pnob->rx_cq_size; ++ ++ status = be_cq_create(pfob, &rd, ++ pnob->rx_cq_len * sizeof(struct ETH_RX_COMPL_AMAP), ++ false, /* solicted events, */ ++ rx_no_delay, /* nodelay */ ++ rx_cmpl_wm, /* Watermark encodings */ ++ eq_objectp, &pnob->rx_cq_obj); ++ if (status != BE_SUCCESS) ++ goto error_ret; ++ ++ pnob->rx_cq_id = pnob->rx_cq_obj.cq_id; ++ pnob->rx_cq_created = 1; ++ ++ status = be_eth_rq_set_frag_size(pfob, pnob->rx_buf_size, ++ (u32 *) &set_rxbuf_size); ++ if (status != BE_SUCCESS) { ++ be_eth_rq_get_frag_size(pfob, (u32 *) &pnob->rx_buf_size); ++ if ((pnob->rx_buf_size != 2048) && (pnob->rx_buf_size != 4096) ++ && (pnob->rx_buf_size != 8192)) ++ goto error_ret; ++ } else { ++ if (pnob->rx_buf_size != set_rxbuf_size) ++ pnob->rx_buf_size = set_rxbuf_size; ++ } ++ /* ++ * Eth RX queue. be_eth_rq_create() always assumes 2 pages size ++ */ ++ rd.va = pnob->rx_q; ++ rd.pa = pnob->rx_q_bus; ++ rd.length = pnob->rx_q_size; ++ ++ status = be_eth_rq_create(pfob, &rd, &pnob->rx_cq_obj, ++ &pnob->rx_cq_obj, &pnob->rx_q_obj); ++ ++ if (status != BE_SUCCESS) ++ goto error_ret; ++ ++ pnob->rx_q_id = pnob->rx_q_obj.rid; ++ pnob->rx_q_created = 1; ++ ++ return BE_SUCCESS; /* All required queues created. */ ++ ++error_ret: ++ be_destroy_netobj(pnob); ++ return status; ++} ++ ++static int be_nob_ring_init(struct be_adapter *adapter, ++ struct be_net_object *pnob) ++{ ++ int status; ++ ++ pnob->event_q_tl = 0; ++ ++ pnob->tx_q_hd = 0; ++ pnob->tx_q_tl = 0; ++ ++ pnob->tx_cq_tl = 0; ++ ++ pnob->rx_cq_tl = 0; ++ ++ memset(pnob->event_q, 0, pnob->event_q_size); ++ memset(pnob->tx_cq, 0, pnob->tx_cq_size); ++ memset(pnob->tx_ctxt, 0, pnob->tx_q_len * sizeof(void **)); ++ memset(pnob->rx_ctxt, 0, pnob->rx_q_len * sizeof(void *)); ++ pnob->rx_pg_info_hd = 0; ++ pnob->rx_q_hd = 0; ++ atomic_set(&pnob->rx_q_posted, 0); ++ ++ status = be_create_netobj(pnob, adapter->csr_va, adapter->db_va, ++ adapter->pci_va); ++ if (status != BE_SUCCESS) ++ return -1; ++ ++ be_post_eth_rx_buffs(pnob); ++ return 0; ++} ++ ++/* This function handles async callback for link status */ ++static void ++be_link_status_async_callback(void *context, u32 event_code, void *event) ++{ ++ struct ASYNC_EVENT_LINK_STATE_AMAP *link_status = event; ++ struct be_adapter *adapter = context; ++ bool link_enable = false; ++ struct be_net_object *pnob; ++ struct ASYNC_EVENT_TRAILER_AMAP *async_trailer; ++ struct net_device *netdev; ++ u32 async_event_code, async_event_type, active_port; ++ u32 port0_link_status, port1_link_status, port0_duplex, port1_duplex; ++ u32 port0_speed, port1_speed; ++ ++ if (event_code != ASYNC_EVENT_CODE_LINK_STATE) { ++ /* Not our event to handle */ ++ return; ++ } ++ async_trailer = (struct ASYNC_EVENT_TRAILER_AMAP *) ++ ((u8 *) event + sizeof(struct MCC_CQ_ENTRY_AMAP) - ++ sizeof(struct ASYNC_EVENT_TRAILER_AMAP)); ++ ++ async_event_code = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, event_code, ++ async_trailer); ++ BUG_ON(async_event_code != ASYNC_EVENT_CODE_LINK_STATE); ++ ++ pnob = adapter->net_obj; ++ netdev = pnob->netdev; ++ ++ /* Determine if this event is a switch VLD or a physical link event */ ++ async_event_type = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, event_type, ++ async_trailer); ++ active_port = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ active_port, link_status); ++ port0_link_status = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ port0_link_status, link_status); ++ port1_link_status = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ port1_link_status, link_status); ++ port0_duplex = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ port0_duplex, link_status); ++ port1_duplex = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ port1_duplex, link_status); ++ port0_speed = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ port0_speed, link_status); ++ port1_speed = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE, ++ port1_speed, link_status); ++ if (async_event_type == NTWK_LINK_TYPE_VIRTUAL) { ++ adapter->be_stat.bes_link_change_virtual++; ++ if (adapter->be_link_sts->active_port != active_port) { ++ dev_notice(&netdev->dev, ++ "Active port changed due to VLD on switch\n"); ++ } else { ++ dev_notice(&netdev->dev, "Link status update\n"); ++ } ++ ++ } else { ++ adapter->be_stat.bes_link_change_physical++; ++ if (adapter->be_link_sts->active_port != active_port) { ++ dev_notice(&netdev->dev, ++ "Active port changed due to port link" ++ " status change\n"); ++ } else { ++ dev_notice(&netdev->dev, "Link status update\n"); ++ } ++ } ++ ++ memset(adapter->be_link_sts, 0, sizeof(adapter->be_link_sts)); ++ ++ if ((port0_link_status == ASYNC_EVENT_LINK_UP) || ++ (port1_link_status == ASYNC_EVENT_LINK_UP)) { ++ if ((adapter->port0_link_sts == BE_PORT_LINK_DOWN) && ++ (adapter->port1_link_sts == BE_PORT_LINK_DOWN)) { ++ /* Earlier both the ports are down So link is up */ ++ link_enable = true; ++ } ++ ++ if (port0_link_status == ASYNC_EVENT_LINK_UP) { ++ adapter->port0_link_sts = BE_PORT_LINK_UP; ++ adapter->be_link_sts->mac0_duplex = port0_duplex; ++ adapter->be_link_sts->mac0_speed = port0_speed; ++ if (active_port == NTWK_PORT_A) ++ adapter->be_link_sts->active_port = 0; ++ } else ++ adapter->port0_link_sts = BE_PORT_LINK_DOWN; ++ ++ if (port1_link_status == ASYNC_EVENT_LINK_UP) { ++ adapter->port1_link_sts = BE_PORT_LINK_UP; ++ adapter->be_link_sts->mac1_duplex = port1_duplex; ++ adapter->be_link_sts->mac1_speed = port1_speed; ++ if (active_port == NTWK_PORT_B) ++ adapter->be_link_sts->active_port = 1; ++ } else ++ adapter->port1_link_sts = BE_PORT_LINK_DOWN; ++ ++ printk(KERN_INFO "Link Properties for %s:\n", netdev->name); ++ dev_info(&netdev->dev, "Link Properties:\n"); ++ be_print_link_info(adapter->be_link_sts); ++ ++ if (!link_enable) ++ return; ++ /* ++ * Both ports were down previously, but atleast one of ++ * them has come up if this netdevice's carrier is not up, ++ * then indicate to stack ++ */ ++ if (!netif_carrier_ok(netdev)) { ++ netif_start_queue(netdev); ++ netif_carrier_on(netdev); ++ } ++ return; ++ } ++ ++ /* Now both the ports are down. Tell the stack about it */ ++ dev_info(&netdev->dev, "Both ports are down\n"); ++ adapter->port0_link_sts = BE_PORT_LINK_DOWN; ++ adapter->port1_link_sts = BE_PORT_LINK_DOWN; ++ if (netif_carrier_ok(netdev)) { ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ } ++ return; ++} ++ ++static int be_mcc_create(struct be_adapter *adapter) ++{ ++ struct be_net_object *pnob; ++ ++ pnob = adapter->net_obj; ++ /* ++ * Create the MCC ring so that all further communication with ++ * MCC can go thru the ring. we do this at the end since ++ * we do not want to be dealing with interrupts until the ++ * initialization is complete. ++ */ ++ pnob->mcc_q_len = MCC_Q_LEN; ++ pnob->mcc_q_size = pnob->mcc_q_len * sizeof(struct MCC_WRB_AMAP); ++ pnob->mcc_q = pci_alloc_consistent(adapter->pdev, pnob->mcc_q_size, ++ &pnob->mcc_q_bus); ++ if (!pnob->mcc_q_bus) ++ return -1; ++ /* ++ * space for MCC WRB context ++ */ ++ pnob->mcc_wrb_ctxtLen = MCC_Q_LEN; ++ pnob->mcc_wrb_ctxt_size = pnob->mcc_wrb_ctxtLen * ++ sizeof(struct be_mcc_wrb_context); ++ pnob->mcc_wrb_ctxt = (void *)__get_free_pages(GFP_KERNEL, ++ get_order(pnob->mcc_wrb_ctxt_size)); ++ if (pnob->mcc_wrb_ctxt == NULL) ++ return -1; ++ /* ++ * Space for MCC compl. ring ++ */ ++ pnob->mcc_cq_len = MCC_CQ_LEN; ++ pnob->mcc_cq_size = pnob->mcc_cq_len * sizeof(struct MCC_CQ_ENTRY_AMAP); ++ pnob->mcc_cq = pci_alloc_consistent(adapter->pdev, pnob->mcc_cq_size, ++ &pnob->mcc_cq_bus); ++ if (!pnob->mcc_cq_bus) ++ return -1; ++ return 0; ++} ++ ++/* ++ This function creates the MCC request and completion ring required ++ for communicating with the ARM processor. The caller must have ++ allocated required amount of memory for the MCC ring and MCC ++ completion ring and posted the virtual address and number of ++ entries in the corresponding members (mcc_q and mcc_cq) in the ++ NetObject struture. ++ ++ When this call is completed, all further communication with ++ ARM will switch from mailbox to this ring. ++ ++ pnob - Pointer to the NetObject structure. This NetObject should ++ have been created using a previous call to be_create_netobj() ++*/ ++int be_create_mcc_rings(struct be_net_object *pnob) ++{ ++ int status = 0; ++ struct ring_desc rd; ++ struct be_function_object *pfob = &pnob->fn_obj; ++ ++ memset(&rd, 0, sizeof(struct ring_desc)); ++ if (pnob->mcc_cq_len) { ++ rd.va = pnob->mcc_cq; ++ rd.pa = pnob->mcc_cq_bus; ++ rd.length = pnob->mcc_cq_size; ++ ++ status = be_cq_create(pfob, &rd, ++ pnob->mcc_cq_len * sizeof(struct MCC_CQ_ENTRY_AMAP), ++ false, /* solicted events, */ ++ true, /* nodelay */ ++ 0, /* 0 Watermark since Nodelay is true */ ++ &pnob->event_q_obj, ++ &pnob->mcc_cq_obj); ++ ++ if (status != BE_SUCCESS) ++ return status; ++ ++ pnob->mcc_cq_id = pnob->mcc_cq_obj.cq_id; ++ pnob->mcc_cq_created = 1; ++ } ++ if (pnob->mcc_q_len) { ++ rd.va = pnob->mcc_q; ++ rd.pa = pnob->mcc_q_bus; ++ rd.length = pnob->mcc_q_size; ++ ++ status = be_mcc_ring_create(pfob, &rd, ++ pnob->mcc_q_len * sizeof(struct MCC_WRB_AMAP), ++ pnob->mcc_wrb_ctxt, pnob->mcc_wrb_ctxtLen, ++ &pnob->mcc_cq_obj, &pnob->mcc_q_obj); ++ ++ if (status != BE_SUCCESS) ++ return status; ++ ++ pnob->mcc_q_created = 1; ++ } ++ return BE_SUCCESS; ++} ++ ++static int be_mcc_init(struct be_adapter *adapter) ++{ ++ u32 r; ++ struct be_net_object *pnob; ++ ++ pnob = adapter->net_obj; ++ memset(pnob->mcc_q, 0, pnob->mcc_q_size); ++ pnob->mcc_q_hd = 0; ++ ++ memset(pnob->mcc_wrb_ctxt, 0, pnob->mcc_wrb_ctxt_size); ++ ++ memset(pnob->mcc_cq, 0, pnob->mcc_cq_size); ++ pnob->mcc_cq_tl = 0; ++ ++ r = be_create_mcc_rings(adapter->net_obj); ++ if (r != BE_SUCCESS) ++ return -1; ++ ++ return 0; ++} ++ ++static void be_remove(struct pci_dev *pdev) ++{ ++ struct be_net_object *pnob; ++ struct be_adapter *adapter; ++ ++ adapter = pci_get_drvdata(pdev); ++ if (!adapter) ++ return; ++ ++ pci_set_drvdata(pdev, NULL); ++ pnob = (struct be_net_object *)adapter->net_obj; ++ ++ flush_scheduled_work(); ++ ++ if (pnob) { ++ /* Unregister async callback function for link status updates */ ++ if (pnob->mcc_q_created) ++ be_mcc_add_async_event_callback(&pnob->mcc_q_obj, ++ NULL, NULL); ++ netobject_cleanup(adapter, pnob); ++ } ++ ++ if (adapter->csr_va) ++ iounmap(adapter->csr_va); ++ if (adapter->db_va) ++ iounmap(adapter->db_va); ++ if (adapter->pci_va) ++ iounmap(adapter->pci_va); ++ ++ pci_release_regions(adapter->pdev); ++ pci_disable_device(adapter->pdev); ++ ++ kfree(adapter->be_link_sts); ++ kfree(adapter->eth_statsp); ++ ++ if (adapter->timer_ctxt.get_stats_timer.function) ++ del_timer_sync(&adapter->timer_ctxt.get_stats_timer); ++ kfree(adapter); ++} ++ ++/* ++ * This function is called by the PCI sub-system when it finds a PCI ++ * device with dev/vendor IDs that match with one of our devices. ++ * All of the driver initialization is done in this function. ++ */ ++static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) ++{ ++ int status = 0; ++ struct be_adapter *adapter; ++ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD get_fwv; ++ struct be_net_object *pnob; ++ struct net_device *netdev; ++ ++ status = pci_enable_device(pdev); ++ if (status) ++ goto error; ++ ++ status = pci_request_regions(pdev, be_driver_name); ++ if (status) ++ goto error_pci_req; ++ ++ pci_set_master(pdev); ++ adapter = kzalloc(sizeof(struct be_adapter), GFP_KERNEL); ++ if (adapter == NULL) { ++ status = -ENOMEM; ++ goto error_adapter; ++ } ++ adapter->dev_state = BE_DEV_STATE_NONE; ++ adapter->pdev = pdev; ++ pci_set_drvdata(pdev, adapter); ++ ++ adapter->enable_aic = 1; ++ adapter->max_eqd = MAX_EQD; ++ adapter->min_eqd = 0; ++ adapter->cur_eqd = 0; ++ ++ status = pci_set_dma_mask(pdev, DMA_64BIT_MASK); ++ if (!status) { ++ adapter->dma_64bit_cap = true; ++ } else { ++ adapter->dma_64bit_cap = false; ++ status = pci_set_dma_mask(pdev, DMA_32BIT_MASK); ++ if (status != 0) { ++ printk(KERN_ERR "Could not set PCI DMA Mask\n"); ++ goto cleanup; ++ } ++ } ++ ++ status = init_pci_be_function(adapter, pdev); ++ if (status != 0) { ++ printk(KERN_ERR "Failed to map PCI BARS\n"); ++ status = -ENOMEM; ++ goto cleanup; ++ } ++ ++ be_trace_set_level(DL_ALWAYS | DL_ERR); ++ ++ adapter->be_link_sts = kmalloc(sizeof(struct BE_LINK_STATUS), ++ GFP_KERNEL); ++ if (adapter->be_link_sts == NULL) { ++ printk(KERN_ERR "Memory allocation for link status " ++ "buffer failed\n"); ++ goto cleanup; ++ } ++ spin_lock_init(&adapter->txq_lock); ++ ++ netdev = alloc_etherdev(sizeof(struct be_net_object)); ++ if (netdev == NULL) { ++ status = -ENOMEM; ++ goto cleanup; ++ } ++ pnob = netdev->priv; ++ adapter->net_obj = pnob; ++ adapter->netdevp = netdev; ++ pnob->adapter = adapter; ++ pnob->netdev = netdev; ++ ++ status = be_nob_ring_alloc(adapter, pnob); ++ if (status != 0) ++ goto cleanup; ++ ++ status = be_nob_ring_init(adapter, pnob); ++ if (status != 0) ++ goto cleanup; ++ ++ be_rxf_mac_address_read_write(&pnob->fn_obj, false, false, false, ++ false, false, netdev->dev_addr, NULL, NULL); ++ ++ netdev->init = &benet_init; ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ ++ SET_NETDEV_DEV(netdev, &(adapter->pdev->dev)); ++ ++ netif_napi_add(netdev, &pnob->napi, be_poll, 64); ++ ++ /* if the rx_frag size if 2K, one page is shared as two RX frags */ ++ pnob->rx_pg_shared = (pnob->rx_buf_size <= PAGE_SIZE / 2)? true : false; ++ if (pnob->rx_buf_size != rxbuf_size) { ++ printk(KERN_WARNING ++ "Could not set Rx buffer size to %d. Using %d\n", ++ rxbuf_size, pnob->rx_buf_size); ++ rxbuf_size = pnob->rx_buf_size; ++ } ++ ++ tasklet_init(&(adapter->sts_handler), be_process_intr, ++ (unsigned long)adapter); ++ adapter->tasklet_started = 1; ++ spin_lock_init(&(adapter->int_lock)); ++ ++ status = be_register_isr(adapter, pnob); ++ if (status != 0) ++ goto cleanup; ++ ++ adapter->rx_csum = 1; ++ adapter->max_rx_coal = BE_LRO_MAX_PKTS; ++ ++ memset(&get_fwv, 0, ++ sizeof(struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD)); ++ printk(KERN_INFO "BladeEngine Driver version:%s. " ++ "Copyright ServerEngines, Corporation 2005 - 2008\n", ++ be_drvr_ver); ++ status = be_function_get_fw_version(&pnob->fn_obj, &get_fwv, NULL, ++ NULL); ++ if (status == BE_SUCCESS) { ++ strncpy(be_fw_ver, get_fwv.firmware_version_string, 32); ++ printk(KERN_INFO "BladeEngine Firmware Version:%s\n", ++ get_fwv.firmware_version_string); ++ } else { ++ printk(KERN_WARNING "Unable to get BE Firmware Version\n"); ++ } ++ ++ sema_init(&adapter->get_eth_stat_sem, 0); ++ init_timer(&adapter->timer_ctxt.get_stats_timer); ++ atomic_set(&adapter->timer_ctxt.get_stat_flag, 0); ++ adapter->timer_ctxt.get_stats_timer.function = ++ &be_get_stats_timer_handler; ++ ++ status = be_mcc_create(adapter); ++ if (status < 0) ++ goto cleanup; ++ status = be_mcc_init(adapter); ++ if (status < 0) ++ goto cleanup; ++ ++ ++ status = be_mcc_add_async_event_callback(&adapter->net_obj->mcc_q_obj, ++ be_link_status_async_callback, (void *)adapter); ++ if (status != BE_SUCCESS) { ++ printk(KERN_WARNING "add_async_event_callback failed"); ++ printk(KERN_WARNING ++ "Link status changes may not be reflected\n"); ++ } ++ ++ status = register_netdev(netdev); ++ if (status != 0) ++ goto cleanup; ++ be_update_link_status(adapter); ++ adapter->dev_state = BE_DEV_STATE_INIT; ++ return 0; ++ ++cleanup: ++ be_remove(pdev); ++ return status; ++error_adapter: ++ pci_release_regions(pdev); ++error_pci_req: ++ pci_disable_device(pdev); ++error: ++ printk(KERN_ERR "BladeEngine initalization failed\n"); ++ return status; ++} ++ ++/* ++ * Get the current link status and print the status on console ++ */ ++void be_update_link_status(struct be_adapter *adapter) ++{ ++ int status; ++ struct be_net_object *pnob = adapter->net_obj; ++ ++ status = be_rxf_link_status(&pnob->fn_obj, adapter->be_link_sts, NULL, ++ NULL, NULL); ++ if (status == BE_SUCCESS) { ++ if (adapter->be_link_sts->mac0_speed && ++ adapter->be_link_sts->mac0_duplex) ++ adapter->port0_link_sts = BE_PORT_LINK_UP; ++ else ++ adapter->port0_link_sts = BE_PORT_LINK_DOWN; ++ ++ if (adapter->be_link_sts->mac1_speed && ++ adapter->be_link_sts->mac1_duplex) ++ adapter->port1_link_sts = BE_PORT_LINK_UP; ++ else ++ adapter->port1_link_sts = BE_PORT_LINK_DOWN; ++ ++ dev_info(&pnob->netdev->dev, "Link Properties:\n"); ++ be_print_link_info(adapter->be_link_sts); ++ return; ++ } ++ dev_info(&pnob->netdev->dev, "Could not get link status\n"); ++ return; ++} ++ ++ ++#ifdef CONFIG_PM ++static void ++be_pm_cleanup(struct be_adapter *adapter, ++ struct be_net_object *pnob, struct net_device *netdev) ++{ ++ netif_carrier_off(netdev); ++ netif_stop_queue(netdev); ++ ++ be_wait_nic_tx_cmplx_cmpl(pnob); ++ be_disable_eq_intr(pnob); ++ ++ if (adapter->tasklet_started) { ++ tasklet_kill(&adapter->sts_handler); ++ adapter->tasklet_started = 0; ++ } ++ ++ be_unregister_isr(adapter); ++ be_disable_intr(pnob); ++ ++ be_tx_q_clean(pnob); ++ be_rx_q_clean(pnob); ++ ++ be_destroy_netobj(pnob); ++} ++ ++static int be_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct be_adapter *adapter = pci_get_drvdata(pdev); ++ struct net_device *netdev = adapter->netdevp; ++ struct be_net_object *pnob = (struct be_net_object *)netdev->priv; ++ ++ adapter->dev_pm_state = adapter->dev_state; ++ adapter->dev_state = BE_DEV_STATE_SUSPEND; ++ ++ netif_device_detach(netdev); ++ if (netif_running(netdev)) ++ be_pm_cleanup(adapter, pnob, netdev); ++ ++ pci_enable_wake(pdev, 3, 1); ++ pci_enable_wake(pdev, 4, 1); /* D3 Cold = 4 */ ++ pci_save_state(pdev); ++ pci_disable_device(pdev); ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); ++ return 0; ++} ++ ++static void be_up(struct be_adapter *adapter) ++{ ++ struct be_net_object *pnob = adapter->net_obj; ++ ++ if (pnob->num_vlans != 0) ++ be_rxf_vlan_config(&pnob->fn_obj, false, pnob->num_vlans, ++ pnob->vlan_tag, NULL, NULL, NULL); ++ ++} ++ ++static int be_resume(struct pci_dev *pdev) ++{ ++ int status = 0; ++ struct be_adapter *adapter = pci_get_drvdata(pdev); ++ struct net_device *netdev = adapter->netdevp; ++ struct be_net_object *pnob = (struct be_net_object *)netdev->priv; ++ ++ netif_device_detach(netdev); ++ ++ status = pci_enable_device(pdev); ++ if (status) ++ return status; ++ ++ pci_set_power_state(pdev, 0); ++ pci_restore_state(pdev); ++ pci_enable_wake(pdev, 3, 0); ++ pci_enable_wake(pdev, 4, 0); /* 4 is D3 cold */ ++ ++ netif_carrier_on(netdev); ++ netif_start_queue(netdev); ++ ++ if (netif_running(netdev)) { ++ be_rxf_mac_address_read_write(&pnob->fn_obj, false, false, ++ false, true, false, netdev->dev_addr, NULL, NULL); ++ ++ status = be_nob_ring_init(adapter, pnob); ++ if (status < 0) ++ return status; ++ ++ tasklet_init(&(adapter->sts_handler), be_process_intr, ++ (unsigned long)adapter); ++ adapter->tasklet_started = 1; ++ ++ if (be_register_isr(adapter, pnob) != 0) { ++ printk(KERN_ERR "be_register_isr failed\n"); ++ return status; ++ } ++ ++ ++ status = be_mcc_init(adapter); ++ if (status < 0) { ++ printk(KERN_ERR "be_mcc_init failed\n"); ++ return status; ++ } ++ be_update_link_status(adapter); ++ /* ++ * Register async call back function to handle link ++ * status updates ++ */ ++ status = be_mcc_add_async_event_callback( ++ &adapter->net_obj->mcc_q_obj, ++ be_link_status_async_callback, (void *)adapter); ++ if (status != BE_SUCCESS) { ++ printk(KERN_WARNING "add_async_event_callback failed"); ++ printk(KERN_WARNING ++ "Link status changes may not be reflected\n"); ++ } ++ be_enable_intr(pnob); ++ be_enable_eq_intr(pnob); ++ be_up(adapter); ++ } ++ netif_device_attach(netdev); ++ adapter->dev_state = adapter->dev_pm_state; ++ return 0; ++ ++} ++ ++#endif ++ ++/* Wait until no more pending transmits */ ++void be_wait_nic_tx_cmplx_cmpl(struct be_net_object *pnob) ++{ ++ int i; ++ ++ /* Wait for 20us * 50000 (= 1s) and no more */ ++ i = 0; ++ while ((pnob->tx_q_tl != pnob->tx_q_hd) && (i < 50000)) { ++ ++i; ++ udelay(20); ++ } ++ ++ /* Check for no more pending transmits */ ++ if (i >= 50000) { ++ printk(KERN_WARNING ++ "Did not receive completions for all TX requests\n"); ++ } ++} ++ ++static struct pci_driver be_driver = { ++ .name = be_driver_name, ++ .id_table = be_device_id_table, ++ .probe = be_probe, ++#ifdef CONFIG_PM ++ .suspend = be_suspend, ++ .resume = be_resume, ++#endif ++ .remove = be_remove ++}; ++ ++/* ++ * Module init entry point. Registers our our device and return. ++ * Our probe will be called if the device is found. ++ */ ++static int __init be_init_module(void) ++{ ++ int ret; ++ ++ if (rxbuf_size != 8192 && rxbuf_size != 4096 && rxbuf_size != 2048) { ++ printk(KERN_WARNING ++ "Unsupported receive buffer size (%d) requested\n", ++ rxbuf_size); ++ printk(KERN_WARNING ++ "Must be 2048, 4096 or 8192. Defaulting to 2048\n"); ++ rxbuf_size = 2048; ++ } ++ ++ ret = pci_register_driver(&be_driver); ++ ++ return ret; ++} ++ ++module_init(be_init_module); ++ ++/* ++ * be_exit_module - Driver Exit Cleanup Routine ++ */ ++static void __exit be_exit_module(void) ++{ ++ pci_unregister_driver(&be_driver); ++} ++ ++module_exit(be_exit_module); +--- /dev/null ++++ b/drivers/staging/benet/be_int.c +@@ -0,0 +1,872 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include ++#include ++ ++#include "benet.h" ++ ++/* number of bytes of RX frame that are copied to skb->data */ ++#define BE_HDR_LEN 64 ++ ++#define NETIF_RX(skb) netif_receive_skb(skb) ++#define VLAN_ACCEL_RX(skb, pnob, vt) \ ++ vlan_hwaccel_rx(skb, pnob->vlan_grp, vt) ++ ++/* ++ This function notifies BladeEngine of the number of completion ++ entries processed from the specified completion queue by writing ++ the number of popped entries to the door bell. ++ ++ pnob - Pointer to the NetObject structure ++ n - Number of completion entries processed ++ cq_id - Queue ID of the completion queue for which notification ++ is being done. ++ re_arm - 1 - rearm the completion ring to generate an event. ++ - 0 - dont rearm the completion ring to generate an event ++*/ ++void be_notify_cmpl(struct be_net_object *pnob, int n, int cq_id, int re_arm) ++{ ++ struct CQ_DB_AMAP cqdb; ++ ++ cqdb.dw[0] = 0; ++ AMAP_SET_BITS_PTR(CQ_DB, qid, &cqdb, cq_id); ++ AMAP_SET_BITS_PTR(CQ_DB, rearm, &cqdb, re_arm); ++ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &cqdb, n); ++ PD_WRITE(&pnob->fn_obj, cq_db, cqdb.dw[0]); ++} ++ ++/* ++ * adds additional receive frags indicated by BE starting from given ++ * frag index (fi) to specified skb's frag list ++ */ ++static void ++add_skb_frags(struct be_net_object *pnob, struct sk_buff *skb, ++ u32 nresid, u32 fi) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ u32 sk_frag_idx, n; ++ struct be_rx_page_info *rx_page_info; ++ u32 frag_sz = pnob->rx_buf_size; ++ ++ sk_frag_idx = skb_shinfo(skb)->nr_frags; ++ while (nresid) { ++ index_inc(&fi, pnob->rx_q_len); ++ ++ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi]; ++ pnob->rx_ctxt[fi] = NULL; ++ if ((rx_page_info->page_offset) || ++ (pnob->rx_pg_shared == false)) { ++ pci_unmap_page(adapter->pdev, ++ pci_unmap_addr(rx_page_info, bus), ++ frag_sz, PCI_DMA_FROMDEVICE); ++ } ++ ++ n = min(nresid, frag_sz); ++ skb_shinfo(skb)->frags[sk_frag_idx].page = rx_page_info->page; ++ skb_shinfo(skb)->frags[sk_frag_idx].page_offset ++ = rx_page_info->page_offset; ++ skb_shinfo(skb)->frags[sk_frag_idx].size = n; ++ ++ sk_frag_idx++; ++ skb->len += n; ++ skb->data_len += n; ++ skb_shinfo(skb)->nr_frags++; ++ nresid -= n; ++ ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ atomic_dec(&pnob->rx_q_posted); ++ } ++} ++ ++/* ++ * This function processes incoming nic packets over various Rx queues. ++ * This function takes the adapter, the current Rx status descriptor ++ * entry and the Rx completion queue ID as argument. ++ */ ++static inline int process_nic_rx_completion(struct be_net_object *pnob, ++ struct ETH_RX_COMPL_AMAP *rxcp) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ struct sk_buff *skb; ++ int udpcksm, tcpcksm; ++ int n; ++ u32 nresid, fi; ++ u32 frag_sz = pnob->rx_buf_size; ++ u8 *va; ++ struct be_rx_page_info *rx_page_info; ++ u32 numfrags, vtp, vtm, vlan_tag, pktsize; ++ ++ fi = AMAP_GET_BITS_PTR(ETH_RX_COMPL, fragndx, rxcp); ++ BUG_ON(fi >= (int)pnob->rx_q_len); ++ BUG_ON(fi < 0); ++ ++ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi]; ++ BUG_ON(!rx_page_info->page); ++ pnob->rx_ctxt[fi] = NULL; ++ ++ /* ++ * If one page is used per fragment or if this is the second half of ++ * of the page, unmap the page here ++ */ ++ if ((rx_page_info->page_offset) || (pnob->rx_pg_shared == false)) { ++ pci_unmap_page(adapter->pdev, ++ pci_unmap_addr(rx_page_info, bus), frag_sz, ++ PCI_DMA_FROMDEVICE); ++ } ++ ++ atomic_dec(&pnob->rx_q_posted); ++ udpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, udpcksm, rxcp); ++ tcpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, tcpcksm, rxcp); ++ pktsize = AMAP_GET_BITS_PTR(ETH_RX_COMPL, pktsize, rxcp); ++ /* ++ * get rid of RX flush completions first. ++ */ ++ if ((tcpcksm) && (udpcksm) && (pktsize == 32)) { ++ put_page(rx_page_info->page); ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ return 0; ++ } ++ skb = netdev_alloc_skb(pnob->netdev, BE_HDR_LEN + NET_IP_ALIGN); ++ if (skb == NULL) { ++ dev_info(&pnob->netdev->dev, "alloc_skb() failed\n"); ++ put_page(rx_page_info->page); ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ goto free_frags; ++ } ++ skb_reserve(skb, NET_IP_ALIGN); ++ ++ skb->dev = pnob->netdev; ++ ++ n = min(pktsize, frag_sz); ++ ++ va = page_address(rx_page_info->page) + rx_page_info->page_offset; ++ prefetch(va); ++ ++ skb->len = skb->data_len = n; ++ if (n <= BE_HDR_LEN) { ++ memcpy(skb->data, va, n); ++ put_page(rx_page_info->page); ++ skb->data_len -= n; ++ skb->tail += n; ++ } else { ++ ++ /* Setup the SKB with page buffer information */ ++ skb_shinfo(skb)->frags[0].page = rx_page_info->page; ++ skb_shinfo(skb)->nr_frags++; ++ ++ /* Copy the header into the skb_data */ ++ memcpy(skb->data, va, BE_HDR_LEN); ++ skb_shinfo(skb)->frags[0].page_offset = ++ rx_page_info->page_offset + BE_HDR_LEN; ++ skb_shinfo(skb)->frags[0].size = n - BE_HDR_LEN; ++ skb->data_len -= BE_HDR_LEN; ++ skb->tail += BE_HDR_LEN; ++ } ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ nresid = pktsize - n; ++ ++ skb->protocol = eth_type_trans(skb, pnob->netdev); ++ ++ if ((tcpcksm || udpcksm) && adapter->rx_csum) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ /* ++ * if we have more bytes left, the frame has been ++ * given to us in multiple fragments. This happens ++ * with Jumbo frames. Add the remaining fragments to ++ * skb->frags[] array. ++ */ ++ if (nresid) ++ add_skb_frags(pnob, skb, nresid, fi); ++ ++ /* update the the true size of the skb. */ ++ skb->truesize = skb->len + sizeof(struct sk_buff); ++ ++ /* ++ * If a 802.3 frame or 802.2 LLC frame ++ * (i.e) contains length field in MAC Hdr ++ * and frame len is greater than 64 bytes ++ */ ++ if (((skb->protocol == ntohs(ETH_P_802_2)) || ++ (skb->protocol == ntohs(ETH_P_802_3))) ++ && (pktsize > BE_HDR_LEN)) { ++ /* ++ * If the length given in Mac Hdr is less than frame size ++ * Erraneous frame, Drop it ++ */ ++ if ((ntohs(*(u16 *) (va + 12)) + ETH_HLEN) < pktsize) { ++ /* Increment Non Ether type II frames dropped */ ++ adapter->be_stat.bes_802_3_dropped_frames++; ++ ++ kfree_skb(skb); ++ return 0; ++ } ++ /* ++ * else if the length given in Mac Hdr is greater than ++ * frame size, should not be seeing this sort of frames ++ * dump the pkt and pass to stack ++ */ ++ else if ((ntohs(*(u16 *) (va + 12)) + ETH_HLEN) > pktsize) { ++ /* Increment Non Ether type II frames malformed */ ++ adapter->be_stat.bes_802_3_malformed_frames++; ++ } ++ } ++ ++ vtp = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtp, rxcp); ++ vtm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtm, rxcp); ++ if (vtp && vtm) { ++ /* Vlan tag present in pkt and BE found ++ * that the tag matched an entry in VLAN table ++ */ ++ if (!pnob->vlan_grp || pnob->num_vlans == 0) { ++ /* But we have no VLANs configured. ++ * This should never happen. Drop the packet. ++ */ ++ dev_info(&pnob->netdev->dev, ++ "BladeEngine: Unexpected vlan tagged packet\n"); ++ kfree_skb(skb); ++ return 0; ++ } ++ /* pass the VLAN packet to stack */ ++ vlan_tag = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vlan_tag, rxcp); ++ VLAN_ACCEL_RX(skb, pnob, be16_to_cpu(vlan_tag)); ++ ++ } else { ++ NETIF_RX(skb); ++ } ++ return 0; ++ ++free_frags: ++ /* free all frags associated with the current rxcp */ ++ numfrags = AMAP_GET_BITS_PTR(ETH_RX_COMPL, numfrags, rxcp); ++ while (numfrags-- > 1) { ++ index_inc(&fi, pnob->rx_q_len); ++ ++ rx_page_info = (struct be_rx_page_info *) ++ pnob->rx_ctxt[fi]; ++ pnob->rx_ctxt[fi] = (void *)NULL; ++ if (rx_page_info->page_offset || !pnob->rx_pg_shared) { ++ pci_unmap_page(adapter->pdev, ++ pci_unmap_addr(rx_page_info, bus), ++ frag_sz, PCI_DMA_FROMDEVICE); ++ } ++ ++ put_page(rx_page_info->page); ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ atomic_dec(&pnob->rx_q_posted); ++ } ++ return -ENOMEM; ++} ++ ++static void process_nic_rx_completion_lro(struct be_net_object *pnob, ++ struct ETH_RX_COMPL_AMAP *rxcp) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME]; ++ unsigned int udpcksm, tcpcksm; ++ u32 numfrags, vlanf, vtm, vlan_tag, nresid; ++ u16 vlant; ++ unsigned int fi, idx, n; ++ struct be_rx_page_info *rx_page_info; ++ u32 frag_sz = pnob->rx_buf_size, pktsize; ++ bool rx_coal = (adapter->max_rx_coal <= 1) ? 0 : 1; ++ u8 err, *va; ++ __wsum csum = 0; ++ ++ if (AMAP_GET_BITS_PTR(ETH_RX_COMPL, ipsec, rxcp)) { ++ /* Drop the pkt and move to the next completion. */ ++ adapter->be_stat.bes_rx_misc_pkts++; ++ return; ++ } ++ err = AMAP_GET_BITS_PTR(ETH_RX_COMPL, err, rxcp); ++ if (err || !rx_coal) { ++ /* We won't coalesce Rx pkts if the err bit set. ++ * take the path of normal completion processing */ ++ process_nic_rx_completion(pnob, rxcp); ++ return; ++ } ++ ++ fi = AMAP_GET_BITS_PTR(ETH_RX_COMPL, fragndx, rxcp); ++ BUG_ON(fi >= (int)pnob->rx_q_len); ++ BUG_ON(fi < 0); ++ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi]; ++ BUG_ON(!rx_page_info->page); ++ pnob->rx_ctxt[fi] = (void *)NULL; ++ /* If one page is used per fragment or if this is the ++ * second half of the page, unmap the page here ++ */ ++ if (rx_page_info->page_offset || !pnob->rx_pg_shared) { ++ pci_unmap_page(adapter->pdev, ++ pci_unmap_addr(rx_page_info, bus), ++ frag_sz, PCI_DMA_FROMDEVICE); ++ } ++ ++ numfrags = AMAP_GET_BITS_PTR(ETH_RX_COMPL, numfrags, rxcp); ++ udpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, udpcksm, rxcp); ++ tcpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, tcpcksm, rxcp); ++ vlan_tag = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vlan_tag, rxcp); ++ vlant = be16_to_cpu(vlan_tag); ++ vlanf = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtp, rxcp); ++ vtm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtm, rxcp); ++ pktsize = AMAP_GET_BITS_PTR(ETH_RX_COMPL, pktsize, rxcp); ++ ++ atomic_dec(&pnob->rx_q_posted); ++ ++ if (tcpcksm && udpcksm && pktsize == 32) { ++ /* flush completion entries */ ++ put_page(rx_page_info->page); ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ return; ++ } ++ /* Only one of udpcksum and tcpcksum can be set */ ++ BUG_ON(udpcksm && tcpcksm); ++ ++ /* jumbo frames could come in multiple fragments */ ++ BUG_ON(numfrags != ((pktsize + (frag_sz - 1)) / frag_sz)); ++ n = min(pktsize, frag_sz); ++ nresid = pktsize - n; /* will be useful for jumbo pkts */ ++ idx = 0; ++ ++ va = page_address(rx_page_info->page) + rx_page_info->page_offset; ++ prefetch(va); ++ rx_frags[idx].page = rx_page_info->page; ++ rx_frags[idx].page_offset = (rx_page_info->page_offset); ++ rx_frags[idx].size = n; ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ ++ /* If we got multiple fragments, we have more data. */ ++ while (nresid) { ++ idx++; ++ index_inc(&fi, pnob->rx_q_len); ++ ++ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi]; ++ pnob->rx_ctxt[fi] = (void *)NULL; ++ if (rx_page_info->page_offset || !pnob->rx_pg_shared) { ++ pci_unmap_page(adapter->pdev, ++ pci_unmap_addr(rx_page_info, bus), ++ frag_sz, PCI_DMA_FROMDEVICE); ++ } ++ ++ n = min(nresid, frag_sz); ++ rx_frags[idx].page = rx_page_info->page; ++ rx_frags[idx].page_offset = (rx_page_info->page_offset); ++ rx_frags[idx].size = n; ++ ++ nresid -= n; ++ memset(rx_page_info, 0, sizeof(struct be_rx_page_info)); ++ atomic_dec(&pnob->rx_q_posted); ++ } ++ ++ if (likely(!(vlanf && vtm))) { ++ lro_receive_frags(&pnob->lro_mgr, rx_frags, ++ pktsize, pktsize, ++ (void *)(unsigned long)csum, csum); ++ } else { ++ /* Vlan tag present in pkt and BE found ++ * that the tag matched an entry in VLAN table ++ */ ++ if (unlikely(!pnob->vlan_grp || pnob->num_vlans == 0)) { ++ /* But we have no VLANs configured. ++ * This should never happen. Drop the packet. ++ */ ++ dev_info(&pnob->netdev->dev, ++ "BladeEngine: Unexpected vlan tagged packet\n"); ++ return; ++ } ++ /* pass the VLAN packet to stack */ ++ lro_vlan_hwaccel_receive_frags(&pnob->lro_mgr, ++ rx_frags, pktsize, pktsize, ++ pnob->vlan_grp, vlant, ++ (void *)(unsigned long)csum, ++ csum); ++ } ++ ++ adapter->be_stat.bes_rx_coal++; ++} ++ ++struct ETH_RX_COMPL_AMAP *be_get_rx_cmpl(struct be_net_object *pnob) ++{ ++ struct ETH_RX_COMPL_AMAP *rxcp = &pnob->rx_cq[pnob->rx_cq_tl]; ++ u32 valid, ct; ++ ++ valid = AMAP_GET_BITS_PTR(ETH_RX_COMPL, valid, rxcp); ++ if (valid == 0) ++ return NULL; ++ ++ ct = AMAP_GET_BITS_PTR(ETH_RX_COMPL, ct, rxcp); ++ if (ct != 0) { ++ /* Invalid chute #. treat as error */ ++ AMAP_SET_BITS_PTR(ETH_RX_COMPL, err, rxcp, 1); ++ } ++ ++ be_adv_rxcq_tl(pnob); ++ AMAP_SET_BITS_PTR(ETH_RX_COMPL, valid, rxcp, 0); ++ return rxcp; ++} ++ ++static void update_rx_rate(struct be_adapter *adapter) ++{ ++ /* update the rate once in two seconds */ ++ if ((jiffies - adapter->eth_rx_jiffies) > 2 * (HZ)) { ++ u32 r; ++ r = adapter->eth_rx_bytes / ++ ((jiffies - adapter->eth_rx_jiffies) / (HZ)); ++ r = (r / 1000000); /* MB/Sec */ ++ ++ /* Mega Bits/Sec */ ++ adapter->be_stat.bes_eth_rx_rate = (r * 8); ++ adapter->eth_rx_jiffies = jiffies; ++ adapter->eth_rx_bytes = 0; ++ } ++} ++ ++static int process_rx_completions(struct be_net_object *pnob, int max_work) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ struct ETH_RX_COMPL_AMAP *rxcp; ++ u32 nc = 0; ++ unsigned int pktsize; ++ ++ while (max_work && (rxcp = be_get_rx_cmpl(pnob))) { ++ prefetch(rxcp); ++ pktsize = AMAP_GET_BITS_PTR(ETH_RX_COMPL, pktsize, rxcp); ++ process_nic_rx_completion_lro(pnob, rxcp); ++ adapter->eth_rx_bytes += pktsize; ++ update_rx_rate(adapter); ++ nc++; ++ max_work--; ++ adapter->be_stat.bes_rx_compl++; ++ } ++ if (likely(adapter->max_rx_coal > 1)) { ++ adapter->be_stat.bes_rx_flush++; ++ lro_flush_all(&pnob->lro_mgr); ++ } ++ ++ /* Refill the queue */ ++ if (atomic_read(&pnob->rx_q_posted) < 900) ++ be_post_eth_rx_buffs(pnob); ++ ++ return nc; ++} ++ ++static struct ETH_TX_COMPL_AMAP *be_get_tx_cmpl(struct be_net_object *pnob) ++{ ++ struct ETH_TX_COMPL_AMAP *txcp = &pnob->tx_cq[pnob->tx_cq_tl]; ++ u32 valid; ++ ++ valid = AMAP_GET_BITS_PTR(ETH_TX_COMPL, valid, txcp); ++ if (valid == 0) ++ return NULL; ++ ++ AMAP_SET_BITS_PTR(ETH_TX_COMPL, valid, txcp, 0); ++ be_adv_txcq_tl(pnob); ++ return txcp; ++ ++} ++ ++void process_one_tx_compl(struct be_net_object *pnob, u32 end_idx) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ int cur_index, tx_wrbs_completed = 0; ++ struct sk_buff *skb; ++ u64 busaddr, pa, pa_lo, pa_hi; ++ struct ETH_WRB_AMAP *wrb; ++ u32 frag_len, last_index, j; ++ ++ last_index = tx_compl_lastwrb_idx_get(pnob); ++ BUG_ON(last_index != end_idx); ++ pnob->tx_ctxt[pnob->tx_q_tl] = NULL; ++ do { ++ cur_index = pnob->tx_q_tl; ++ wrb = &pnob->tx_q[cur_index]; ++ pa_hi = AMAP_GET_BITS_PTR(ETH_WRB, frag_pa_hi, wrb); ++ pa_lo = AMAP_GET_BITS_PTR(ETH_WRB, frag_pa_lo, wrb); ++ frag_len = AMAP_GET_BITS_PTR(ETH_WRB, frag_len, wrb); ++ busaddr = (pa_hi << 32) | pa_lo; ++ if (busaddr != 0) { ++ pa = le64_to_cpu(busaddr); ++ pci_unmap_single(adapter->pdev, pa, ++ frag_len, PCI_DMA_TODEVICE); ++ } ++ if (cur_index == last_index) { ++ skb = (struct sk_buff *)pnob->tx_ctxt[cur_index]; ++ BUG_ON(!skb); ++ for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) { ++ struct skb_frag_struct *frag; ++ frag = &skb_shinfo(skb)->frags[j]; ++ pci_unmap_page(adapter->pdev, ++ (ulong) frag->page, frag->size, ++ PCI_DMA_TODEVICE); ++ } ++ kfree_skb(skb); ++ pnob->tx_ctxt[cur_index] = NULL; ++ } else { ++ BUG_ON(pnob->tx_ctxt[cur_index]); ++ } ++ tx_wrbs_completed++; ++ be_adv_txq_tl(pnob); ++ } while (cur_index != last_index); ++ atomic_sub(tx_wrbs_completed, &pnob->tx_q_used); ++} ++ ++/* there is no need to take an SMP lock here since currently ++ * we have only one instance of the tasklet that does completion ++ * processing. ++ */ ++static void process_nic_tx_completions(struct be_net_object *pnob) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ struct ETH_TX_COMPL_AMAP *txcp; ++ struct net_device *netdev = pnob->netdev; ++ u32 end_idx, num_processed = 0; ++ ++ adapter->be_stat.bes_tx_events++; ++ ++ while ((txcp = be_get_tx_cmpl(pnob))) { ++ end_idx = AMAP_GET_BITS_PTR(ETH_TX_COMPL, wrb_index, txcp); ++ process_one_tx_compl(pnob, end_idx); ++ num_processed++; ++ adapter->be_stat.bes_tx_compl++; ++ } ++ be_notify_cmpl(pnob, num_processed, pnob->tx_cq_id, 1); ++ /* ++ * We got Tx completions and have usable WRBs. ++ * If the netdev's queue has been stopped ++ * because we had run out of WRBs, wake it now. ++ */ ++ spin_lock(&adapter->txq_lock); ++ if (netif_queue_stopped(netdev) ++ && atomic_read(&pnob->tx_q_used) < pnob->tx_q_len / 2) { ++ netif_wake_queue(netdev); ++ } ++ spin_unlock(&adapter->txq_lock); ++} ++ ++static u32 post_rx_buffs(struct be_net_object *pnob, struct list_head *rxbl) ++{ ++ u32 nposted = 0; ++ struct ETH_RX_D_AMAP *rxd = NULL; ++ struct be_recv_buffer *rxbp; ++ void **rx_ctxp; ++ struct RQ_DB_AMAP rqdb; ++ ++ rx_ctxp = pnob->rx_ctxt; ++ ++ while (!list_empty(rxbl) && ++ (rx_ctxp[pnob->rx_q_hd] == NULL) && nposted < 255) { ++ ++ rxbp = list_first_entry(rxbl, struct be_recv_buffer, rxb_list); ++ list_del(&rxbp->rxb_list); ++ rxd = pnob->rx_q + pnob->rx_q_hd; ++ AMAP_SET_BITS_PTR(ETH_RX_D, fragpa_lo, rxd, rxbp->rxb_pa_lo); ++ AMAP_SET_BITS_PTR(ETH_RX_D, fragpa_hi, rxd, rxbp->rxb_pa_hi); ++ ++ rx_ctxp[pnob->rx_q_hd] = rxbp->rxb_ctxt; ++ be_adv_rxq_hd(pnob); ++ nposted++; ++ } ++ ++ if (nposted) { ++ /* Now press the door bell to notify BladeEngine. */ ++ rqdb.dw[0] = 0; ++ AMAP_SET_BITS_PTR(RQ_DB, numPosted, &rqdb, nposted); ++ AMAP_SET_BITS_PTR(RQ_DB, rq, &rqdb, pnob->rx_q_id); ++ PD_WRITE(&pnob->fn_obj, erx_rq_db, rqdb.dw[0]); ++ } ++ atomic_add(nposted, &pnob->rx_q_posted); ++ return nposted; ++} ++ ++void be_post_eth_rx_buffs(struct be_net_object *pnob) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ u32 num_bufs, r; ++ u64 busaddr = 0, tmp_pa; ++ u32 max_bufs, pg_hd; ++ u32 frag_size; ++ struct be_recv_buffer *rxbp; ++ struct list_head rxbl; ++ struct be_rx_page_info *rx_page_info; ++ struct page *page = NULL; ++ u32 page_order = 0; ++ gfp_t alloc_flags = GFP_ATOMIC; ++ ++ BUG_ON(!adapter); ++ ++ max_bufs = 64; /* should be even # <= 255. */ ++ ++ frag_size = pnob->rx_buf_size; ++ page_order = get_order(frag_size); ++ ++ if (frag_size == 8192) ++ alloc_flags |= (gfp_t) __GFP_COMP; ++ /* ++ * Form a linked list of RECV_BUFFFER structure to be be posted. ++ * We will post even number of buffer so that pages can be ++ * shared. ++ */ ++ INIT_LIST_HEAD(&rxbl); ++ ++ for (num_bufs = 0; num_bufs < max_bufs; ++num_bufs) { ++ ++ rxbp = &pnob->eth_rx_bufs[num_bufs]; ++ pg_hd = pnob->rx_pg_info_hd; ++ rx_page_info = &pnob->rx_page_info[pg_hd]; ++ ++ if (!page) { ++ /* ++ * before we allocate a page make sure that we ++ * have space in the RX queue to post the buffer. ++ * We check for two vacant slots since with ++ * 2K frags, we will need two slots. ++ */ ++ if ((pnob->rx_ctxt[(pnob->rx_q_hd + num_bufs) & ++ (pnob->rx_q_len - 1)] != NULL) ++ || (pnob->rx_ctxt[(pnob->rx_q_hd + num_bufs + 1) % ++ pnob->rx_q_len] != NULL)) { ++ break; ++ } ++ page = alloc_pages(alloc_flags, page_order); ++ if (unlikely(page == NULL)) { ++ adapter->be_stat.bes_ethrx_post_fail++; ++ pnob->rxbuf_post_fail++; ++ break; ++ } ++ pnob->rxbuf_post_fail = 0; ++ busaddr = pci_map_page(adapter->pdev, page, 0, ++ frag_size, PCI_DMA_FROMDEVICE); ++ rx_page_info->page_offset = 0; ++ rx_page_info->page = page; ++ /* ++ * If we are sharing a page among two skbs, ++ * alloc a new one on the next iteration ++ */ ++ if (pnob->rx_pg_shared == false) ++ page = NULL; ++ } else { ++ get_page(page); ++ rx_page_info->page_offset += frag_size; ++ rx_page_info->page = page; ++ /* ++ * We are finished with the alloced page, ++ * Alloc a new one on the next iteration ++ */ ++ page = NULL; ++ } ++ rxbp->rxb_ctxt = (void *)rx_page_info; ++ index_inc(&pnob->rx_pg_info_hd, pnob->rx_q_len); ++ ++ pci_unmap_addr_set(rx_page_info, bus, busaddr); ++ tmp_pa = busaddr + rx_page_info->page_offset; ++ rxbp->rxb_pa_lo = (tmp_pa & 0xFFFFFFFF); ++ rxbp->rxb_pa_hi = (tmp_pa >> 32); ++ rxbp->rxb_len = frag_size; ++ list_add_tail(&rxbp->rxb_list, &rxbl); ++ } /* End of for */ ++ ++ r = post_rx_buffs(pnob, &rxbl); ++ BUG_ON(r != num_bufs); ++ return; ++} ++ ++/* ++ * Interrupt service for network function. We just schedule the ++ * tasklet which does all completion processing. ++ */ ++irqreturn_t be_int(int irq, void *dev) ++{ ++ struct net_device *netdev = dev; ++ struct be_net_object *pnob = (struct be_net_object *)(netdev->priv); ++ struct be_adapter *adapter = pnob->adapter; ++ u32 isr; ++ ++ isr = CSR_READ(&pnob->fn_obj, cev.isr1); ++ if (unlikely(!isr)) ++ return IRQ_NONE; ++ ++ spin_lock(&adapter->int_lock); ++ adapter->isr |= isr; ++ spin_unlock(&adapter->int_lock); ++ ++ adapter->be_stat.bes_ints++; ++ ++ tasklet_schedule(&adapter->sts_handler); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * Poll function called by NAPI with a work budget. ++ * We process as many UC. BC and MC receive completions ++ * as the budget allows and return the actual number of ++ * RX ststutses processed. ++ */ ++int be_poll(struct napi_struct *napi, int budget) ++{ ++ struct be_net_object *pnob = container_of(napi, struct be_net_object, napi); ++ u32 work_done; ++ ++ pnob->adapter->be_stat.bes_polls++; ++ work_done = process_rx_completions(pnob, budget); ++ BUG_ON(work_done > budget); ++ ++ /* All consumed */ ++ if (work_done < budget) { ++ netif_rx_complete(pnob->netdev, napi); ++ /* enable intr */ ++ be_notify_cmpl(pnob, work_done, pnob->rx_cq_id, 1); ++ } else { ++ /* More to be consumed; continue with interrupts disabled */ ++ be_notify_cmpl(pnob, work_done, pnob->rx_cq_id, 0); ++ } ++ return work_done; ++} ++ ++static struct EQ_ENTRY_AMAP *get_event(struct be_net_object *pnob) ++{ ++ struct EQ_ENTRY_AMAP *eqp = &(pnob->event_q[pnob->event_q_tl]); ++ if (!AMAP_GET_BITS_PTR(EQ_ENTRY, Valid, eqp)) ++ return NULL; ++ be_adv_eq_tl(pnob); ++ return eqp; ++} ++ ++/* ++ * Processes all valid events in the event ring associated with given ++ * NetObject. Also, notifies BE the number of events processed. ++ */ ++static inline u32 process_events(struct be_net_object *pnob) ++{ ++ struct be_adapter *adapter = pnob->adapter; ++ struct EQ_ENTRY_AMAP *eqp; ++ u32 rid, num_events = 0; ++ struct net_device *netdev = pnob->netdev; ++ ++ while ((eqp = get_event(pnob)) != NULL) { ++ adapter->be_stat.bes_events++; ++ rid = AMAP_GET_BITS_PTR(EQ_ENTRY, ResourceID, eqp); ++ if (rid == pnob->rx_cq_id) { ++ adapter->be_stat.bes_rx_events++; ++ netif_rx_schedule(netdev, &pnob->napi); ++ } else if (rid == pnob->tx_cq_id) { ++ process_nic_tx_completions(pnob); ++ } else if (rid == pnob->mcc_cq_id) { ++ be_mcc_process_cq(&pnob->mcc_q_obj, 1); ++ } else { ++ dev_info(&netdev->dev, ++ "Invalid EQ ResourceID %d\n", rid); ++ } ++ AMAP_SET_BITS_PTR(EQ_ENTRY, Valid, eqp, 0); ++ AMAP_SET_BITS_PTR(EQ_ENTRY, ResourceID, eqp, 0); ++ num_events++; ++ } ++ return num_events; ++} ++ ++static void update_eqd(struct be_adapter *adapter, struct be_net_object *pnob) ++{ ++ int status; ++ struct be_eq_object *eq_objectp; ++ ++ /* update once a second */ ++ if ((jiffies - adapter->ips_jiffies) > 1 * (HZ)) { ++ /* One second elapsed since last update */ ++ u32 r, new_eqd = -1; ++ r = adapter->be_stat.bes_ints - adapter->be_stat.bes_prev_ints; ++ r = r / ((jiffies - adapter->ips_jiffies) / (HZ)); ++ adapter->be_stat.bes_ips = r; ++ adapter->ips_jiffies = jiffies; ++ adapter->be_stat.bes_prev_ints = adapter->be_stat.bes_ints; ++ if (r > IPS_HI_WM && adapter->cur_eqd < adapter->max_eqd) ++ new_eqd = (adapter->cur_eqd + 8); ++ if (r < IPS_LO_WM && adapter->cur_eqd > adapter->min_eqd) ++ new_eqd = (adapter->cur_eqd - 8); ++ if (adapter->enable_aic && new_eqd != -1) { ++ eq_objectp = &pnob->event_q_obj; ++ status = be_eq_modify_delay(&pnob->fn_obj, 1, ++ &eq_objectp, &new_eqd, NULL, ++ NULL, NULL); ++ if (status == BE_SUCCESS) ++ adapter->cur_eqd = new_eqd; ++ } ++ } ++} ++ ++/* ++ This function notifies BladeEngine of how many events were processed ++ from the event queue by ringing the corresponding door bell and ++ optionally re-arms the event queue. ++ n - number of events processed ++ re_arm - 1 - re-arm the EQ, 0 - do not re-arm the EQ ++ ++*/ ++static void be_notify_event(struct be_net_object *pnob, int n, int re_arm) ++{ ++ struct CQ_DB_AMAP eqdb; ++ eqdb.dw[0] = 0; ++ ++ AMAP_SET_BITS_PTR(CQ_DB, qid, &eqdb, pnob->event_q_id); ++ AMAP_SET_BITS_PTR(CQ_DB, rearm, &eqdb, re_arm); ++ AMAP_SET_BITS_PTR(CQ_DB, event, &eqdb, 1); ++ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &eqdb, n); ++ /* ++ * Under some situations we see an interrupt and no valid ++ * EQ entry. To keep going, we need to ring the DB even if ++ * numPOsted is 0. ++ */ ++ PD_WRITE(&pnob->fn_obj, cq_db, eqdb.dw[0]); ++ return; ++} ++ ++/* ++ * Called from the tasklet scheduled by ISR. All real interrupt processing ++ * is done here. ++ */ ++void be_process_intr(unsigned long context) ++{ ++ struct be_adapter *adapter = (struct be_adapter *)context; ++ struct be_net_object *pnob = adapter->net_obj; ++ u32 isr, n; ++ ulong flags = 0; ++ ++ isr = adapter->isr; ++ ++ /* ++ * we create only one NIC event queue in Linux. Event is ++ * expected only in the first event queue ++ */ ++ BUG_ON(isr & 0xfffffffe); ++ if ((isr & 1) == 0) ++ return; /* not our interrupt */ ++ n = process_events(pnob); ++ /* ++ * Clear the event bit. adapter->isr is set by ++ * hard interrupt. Prevent race with lock. ++ */ ++ spin_lock_irqsave(&adapter->int_lock, flags); ++ adapter->isr &= ~1; ++ spin_unlock_irqrestore(&adapter->int_lock, flags); ++ be_notify_event(pnob, n, 1); ++ /* ++ * If previous allocation attempts had failed and ++ * BE has used up all posted buffers, post RX buffers here ++ */ ++ if (pnob->rxbuf_post_fail && atomic_read(&pnob->rx_q_posted) == 0) ++ be_post_eth_rx_buffs(pnob); ++ update_eqd(adapter, pnob); ++ return; ++} +--- /dev/null ++++ b/drivers/staging/benet/benet.h +@@ -0,0 +1,429 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#ifndef _BENET_H_ ++#define _BENET_H_ ++ ++#include ++#include ++#include ++#include "hwlib.h" ++ ++#define _SA_MODULE_NAME "net-driver" ++ ++#define VLAN_VALID_BIT 0x8000 ++#define BE_NUM_VLAN_SUPPORTED 32 ++#define BE_PORT_LINK_DOWN 0000 ++#define BE_PORT_LINK_UP 0001 ++#define BE_MAX_TX_FRAG_COUNT (30) ++ ++/* Flag bits for send operation */ ++#define IPCS (1 << 0) /* Enable IP checksum offload */ ++#define UDPCS (1 << 1) /* Enable UDP checksum offload */ ++#define TCPCS (1 << 2) /* Enable TCP checksum offload */ ++#define LSO (1 << 3) /* Enable Large Segment offload */ ++#define ETHVLAN (1 << 4) /* Enable VLAN insert */ ++#define ETHEVENT (1 << 5) /* Generate event on completion */ ++#define ETHCOMPLETE (1 << 6) /* Generate completion when done */ ++#define IPSEC (1 << 7) /* Enable IPSEC */ ++#define FORWARD (1 << 8) /* Send the packet in forwarding path */ ++#define FIN (1 << 9) /* Issue FIN segment */ ++ ++#define BE_MAX_MTU 8974 ++ ++#define BE_MAX_LRO_DESCRIPTORS 8 ++#define BE_LRO_MAX_PKTS 64 ++#define BE_MAX_FRAGS_PER_FRAME 6 ++ ++extern const char be_drvr_ver[]; ++extern char be_fw_ver[]; ++extern char be_driver_name[]; ++ ++extern struct ethtool_ops be_ethtool_ops; ++ ++#define BE_DEV_STATE_NONE 0 ++#define BE_DEV_STATE_INIT 1 ++#define BE_DEV_STATE_OPEN 2 ++#define BE_DEV_STATE_SUSPEND 3 ++ ++/* This structure is used to describe physical fragments to use ++ * for DMAing data from NIC. ++ */ ++struct be_recv_buffer { ++ struct list_head rxb_list; /* for maintaining a linked list */ ++ void *rxb_va; /* buffer virtual address */ ++ u32 rxb_pa_lo; /* low part of physical address */ ++ u32 rxb_pa_hi; /* high part of physical address */ ++ u32 rxb_len; /* length of recv buffer */ ++ void *rxb_ctxt; /* context for OSM driver to use */ ++}; ++ ++/* ++ * fragment list to describe scattered data. ++ */ ++struct be_tx_frag_list { ++ u32 txb_len; /* Size of this fragment */ ++ u32 txb_pa_lo; /* Lower 32 bits of 64 bit physical addr */ ++ u32 txb_pa_hi; /* Higher 32 bits of 64 bit physical addr */ ++}; ++ ++struct be_rx_page_info { ++ struct page *page; ++ dma_addr_t bus; ++ u16 page_offset; ++}; ++ ++/* ++ * This structure is the main tracking structure for a NIC interface. ++ */ ++struct be_net_object { ++ /* MCC Ring - used to send fwcmds to embedded ARM processor */ ++ struct MCC_WRB_AMAP *mcc_q; /* VA of the start of the ring */ ++ u32 mcc_q_len; /* # of WRB entries in this ring */ ++ u32 mcc_q_size; ++ u32 mcc_q_hd; /* MCC ring head */ ++ u8 mcc_q_created; /* flag to help cleanup */ ++ struct be_mcc_object mcc_q_obj; /* BECLIB's MCC ring Object */ ++ dma_addr_t mcc_q_bus; /* DMA'ble bus address */ ++ ++ /* MCC Completion Ring - FW responses to fwcmds sent from MCC ring */ ++ struct MCC_CQ_ENTRY_AMAP *mcc_cq; /* VA of the start of the ring */ ++ u32 mcc_cq_len; /* # of compl. entries in this ring */ ++ u32 mcc_cq_size; ++ u32 mcc_cq_tl; /* compl. ring tail */ ++ u8 mcc_cq_created; /* flag to help cleanup */ ++ struct be_cq_object mcc_cq_obj; /* BECLIB's MCC compl. ring object */ ++ u32 mcc_cq_id; /* MCC ring ID */ ++ dma_addr_t mcc_cq_bus; /* DMA'ble bus address */ ++ ++ struct ring_desc mb_rd; /* RD for MCC_MAIL_BOX */ ++ void *mb_ptr; /* mailbox ptr to be freed */ ++ dma_addr_t mb_bus; /* DMA'ble bus address */ ++ u32 mb_size; ++ ++ /* BEClib uses an array of context objects to track outstanding ++ * requests to the MCC. We need allocate the same number of ++ * conext entries as the number of entries in the MCC WRB ring ++ */ ++ u32 mcc_wrb_ctxt_size; ++ void *mcc_wrb_ctxt; /* pointer to the context area */ ++ u32 mcc_wrb_ctxtLen; /* Number of entries in the context */ ++ /* ++ * NIC send request ring - used for xmitting raw ether frames. ++ */ ++ struct ETH_WRB_AMAP *tx_q; /* VA of the start of the ring */ ++ u32 tx_q_len; /* # if entries in the send ring */ ++ u32 tx_q_size; ++ u32 tx_q_hd; /* Head index. Next req. goes here */ ++ u32 tx_q_tl; /* Tail indx. oldest outstanding req. */ ++ u8 tx_q_created; /* flag to help cleanup */ ++ struct be_ethsq_object tx_q_obj;/* BECLIB's send Q handle */ ++ dma_addr_t tx_q_bus; /* DMA'ble bus address */ ++ u32 tx_q_id; /* send queue ring ID */ ++ u32 tx_q_port; /* 0 no binding, 1 port A, 2 port B */ ++ atomic_t tx_q_used; /* # of WRBs used */ ++ /* ptr to an array in which we store context info for each send req. */ ++ void **tx_ctxt; ++ /* ++ * NIC Send compl. ring - completion status for all NIC frames xmitted. ++ */ ++ struct ETH_TX_COMPL_AMAP *tx_cq;/* VA of start of the ring */ ++ u32 txcq_len; /* # of entries in the ring */ ++ u32 tx_cq_size; ++ /* ++ * index into compl ring where the host expects next completion entry ++ */ ++ u32 tx_cq_tl; ++ u32 tx_cq_id; /* completion queue id */ ++ u8 tx_cq_created; /* flag to help cleanup */ ++ struct be_cq_object tx_cq_obj; ++ dma_addr_t tx_cq_bus; /* DMA'ble bus address */ ++ /* ++ * Event Queue - all completion entries post events here. ++ */ ++ struct EQ_ENTRY_AMAP *event_q; /* VA of start of event queue */ ++ u32 event_q_len; /* # of entries */ ++ u32 event_q_size; ++ u32 event_q_tl; /* Tail of the event queue */ ++ u32 event_q_id; /* Event queue ID */ ++ u8 event_q_created; /* flag to help cleanup */ ++ struct be_eq_object event_q_obj; /* Queue handle */ ++ dma_addr_t event_q_bus; /* DMA'ble bus address */ ++ /* ++ * NIC receive queue - Data buffers to be used for receiving unicast, ++ * broadcast and multi-cast frames are posted here. ++ */ ++ struct ETH_RX_D_AMAP *rx_q; /* VA of start of the queue */ ++ u32 rx_q_len; /* # of entries */ ++ u32 rx_q_size; ++ u32 rx_q_hd; /* Head of the queue */ ++ atomic_t rx_q_posted; /* number of posted buffers */ ++ u32 rx_q_id; /* queue ID */ ++ u8 rx_q_created; /* flag to help cleanup */ ++ struct be_ethrq_object rx_q_obj; /* NIC RX queue handle */ ++ dma_addr_t rx_q_bus; /* DMA'ble bus address */ ++ /* ++ * Pointer to an array of opaque context object for use by OSM driver ++ */ ++ void **rx_ctxt; ++ /* ++ * NIC unicast RX completion queue - all unicast ether frame completion ++ * statuses from BE come here. ++ */ ++ struct ETH_RX_COMPL_AMAP *rx_cq; /* VA of start of the queue */ ++ u32 rx_cq_len; /* # of entries */ ++ u32 rx_cq_size; ++ u32 rx_cq_tl; /* Tail of the queue */ ++ u32 rx_cq_id; /* queue ID */ ++ u8 rx_cq_created; /* flag to help cleanup */ ++ struct be_cq_object rx_cq_obj; /* queue handle */ ++ dma_addr_t rx_cq_bus; /* DMA'ble bus address */ ++ struct be_function_object fn_obj; /* function object */ ++ bool fn_obj_created; ++ u32 rx_buf_size; /* Size of the RX buffers */ ++ ++ struct net_device *netdev; ++ struct be_recv_buffer eth_rx_bufs[256]; /* to pass Rx buffer ++ addresses */ ++ struct be_adapter *adapter; /* Pointer to OSM adapter */ ++ u32 devno; /* OSM, network dev no. */ ++ u32 use_port; /* Current active port */ ++ struct be_rx_page_info *rx_page_info; /* Array of Rx buf pages */ ++ u32 rx_pg_info_hd; /* Head of queue */ ++ int rxbuf_post_fail; /* RxBuff posting fail count */ ++ bool rx_pg_shared; /* Is an allocsted page shared as two frags ? */ ++ struct vlan_group *vlan_grp; ++ u32 num_vlans; /* Number of vlans in BE's filter */ ++ u16 vlan_tag[BE_NUM_VLAN_SUPPORTED]; /* vlans currently configured */ ++ struct napi_struct napi; ++ struct net_lro_mgr lro_mgr; ++ struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS]; ++}; ++ ++#define NET_FH(np) (&(np)->fn_obj) ++ ++/* ++ * BE driver statistics. ++ */ ++struct be_drvr_stat { ++ u32 bes_tx_reqs; /* number of TX requests initiated */ ++ u32 bes_tx_fails; /* number of TX requests that failed */ ++ u32 bes_fwd_reqs; /* number of send reqs through forwarding i/f */ ++ u32 bes_tx_wrbs; /* number of tx WRBs used */ ++ ++ u32 bes_ints; /* number of interrupts */ ++ u32 bes_polls; /* number of times NAPI called poll function */ ++ u32 bes_events; /* total evet entries processed */ ++ u32 bes_tx_events; /* number of tx completion events */ ++ u32 bes_rx_events; /* number of ucast rx completion events */ ++ u32 bes_tx_compl; /* number of tx completion entries processed */ ++ u32 bes_rx_compl; /* number of rx completion entries ++ processed */ ++ u32 bes_ethrx_post_fail; /* number of ethrx buffer alloc ++ failures */ ++ /* ++ * number of non ether type II frames dropped where ++ * frame len > length field of Mac Hdr ++ */ ++ u32 bes_802_3_dropped_frames; ++ /* ++ * number of non ether type II frames malformed where ++ * in frame len < length field of Mac Hdr ++ */ ++ u32 bes_802_3_malformed_frames; ++ u32 bes_ips; /* interrupts / sec */ ++ u32 bes_prev_ints; /* bes_ints at last IPS calculation */ ++ u16 bes_eth_tx_rate; /* ETH TX rate - Mb/sec */ ++ u16 bes_eth_rx_rate; /* ETH RX rate - Mb/sec */ ++ u32 bes_rx_coal; /* Num pkts coalasced */ ++ u32 bes_rx_flush; /* Num times coalasced */ ++ u32 bes_link_change_physical; /*Num of times physical link changed */ ++ u32 bes_link_change_virtual; /*Num of times virtual link changed */ ++ u32 bes_rx_misc_pkts; /* Misc pkts received */ ++}; ++ ++/* Maximum interrupt delay (in microseconds) allowed */ ++#define MAX_EQD 120 ++ ++/* ++ * timer to prevent system shutdown hang for ever if h/w stops responding ++ */ ++struct be_timer_ctxt { ++ atomic_t get_stat_flag; ++ struct timer_list get_stats_timer; ++ unsigned long get_stat_sem_addr; ++} ; ++ ++/* This structure is the main BladeEngine driver context. */ ++struct be_adapter { ++ struct net_device *netdevp; ++ struct be_drvr_stat be_stat; ++ struct net_device_stats benet_stats; ++ ++ /* PCI BAR mapped addresses */ ++ u8 __iomem *csr_va; /* CSR */ ++ u8 __iomem *db_va; /* Door Bell */ ++ u8 __iomem *pci_va; /* PCI Config */ ++ ++ struct tasklet_struct sts_handler; ++ struct timer_list cq_timer; ++ spinlock_t int_lock; ++ ++ struct FWCMD_ETH_GET_STATISTICS *eth_statsp; ++ /* ++ * This will enable the use of ethtool to enable or disable ++ * Checksum on Rx pkts to be obeyed or disobeyed. ++ * If this is true = 1, then whatever is the checksum on the ++ * Received pkt as per BE, it will be given to the stack. ++ * Else the stack will re calculate it. ++ */ ++ bool rx_csum; ++ /* ++ * This will enable the use of ethtool to enable or disable ++ * Coalese on Rx pkts to be obeyed or disobeyed. ++ * If this is grater than 0 and less than 16 then coalascing ++ * is enabled else it is disabled ++ */ ++ u32 max_rx_coal; ++ struct pci_dev *pdev; /* Pointer to OS's PCI dvice */ ++ ++ spinlock_t txq_lock; ++ ++ u32 isr; /* copy of Intr status reg. */ ++ ++ u32 port0_link_sts; /* Port 0 link status */ ++ u32 port1_link_sts; /* port 1 list status */ ++ struct BE_LINK_STATUS *be_link_sts; ++ ++ /* pointer to the first netobject of this adapter */ ++ struct be_net_object *net_obj; ++ ++ /* Flags to indicate what to clean up */ ++ bool tasklet_started; ++ bool isr_registered; ++ /* ++ * adaptive interrupt coalescing (AIC) related ++ */ ++ bool enable_aic; /* 1 if AIC is enabled */ ++ u16 min_eqd; /* minimum EQ delay in usec */ ++ u16 max_eqd; /* minimum EQ delay in usec */ ++ u16 cur_eqd; /* current EQ delay in usec */ ++ /* ++ * book keeping for interrupt / sec and TX/RX rate calculation ++ */ ++ ulong ips_jiffies; /* jiffies at last IPS calc */ ++ u32 eth_tx_bytes; ++ ulong eth_tx_jiffies; ++ u32 eth_rx_bytes; ++ ulong eth_rx_jiffies; ++ ++ struct semaphore get_eth_stat_sem; ++ ++ /* timer ctxt to prevent shutdown hanging due to un-responsive BE */ ++ struct be_timer_ctxt timer_ctxt; ++ ++#define BE_MAX_MSIX_VECTORS 32 ++#define BE_MAX_REQ_MSIX_VECTORS 1 /* only one EQ in Linux driver */ ++ struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; ++ bool msix_enabled; ++ bool dma_64bit_cap; /* the Device DAC capable or not */ ++ u8 dev_state; /* The current state of the device */ ++ u8 dev_pm_state; /* The State of device before going to suspend */ ++}; ++ ++/* ++ * Every second we look at the ints/sec and adjust eq_delay ++ * between adapter->min_eqd and adapter->max_eqd to keep the ints/sec between ++ * IPS_HI_WM and IPS_LO_WM. ++ */ ++#define IPS_HI_WM 18000 ++#define IPS_LO_WM 8000 ++ ++ ++static inline void index_adv(u32 *index, u32 val, u32 limit) ++{ ++ BUG_ON(limit & (limit-1)); ++ *index = (*index + val) & (limit - 1); ++} ++ ++static inline void index_inc(u32 *index, u32 limit) ++{ ++ BUG_ON(limit & (limit-1)); ++ *index = (*index + 1) & (limit - 1); ++} ++ ++static inline void be_adv_eq_tl(struct be_net_object *pnob) ++{ ++ index_inc(&pnob->event_q_tl, pnob->event_q_len); ++} ++ ++static inline void be_adv_txq_hd(struct be_net_object *pnob) ++{ ++ index_inc(&pnob->tx_q_hd, pnob->tx_q_len); ++} ++ ++static inline void be_adv_txq_tl(struct be_net_object *pnob) ++{ ++ index_inc(&pnob->tx_q_tl, pnob->tx_q_len); ++} ++ ++static inline void be_adv_txcq_tl(struct be_net_object *pnob) ++{ ++ index_inc(&pnob->tx_cq_tl, pnob->txcq_len); ++} ++ ++static inline void be_adv_rxq_hd(struct be_net_object *pnob) ++{ ++ index_inc(&pnob->rx_q_hd, pnob->rx_q_len); ++} ++ ++static inline void be_adv_rxcq_tl(struct be_net_object *pnob) ++{ ++ index_inc(&pnob->rx_cq_tl, pnob->rx_cq_len); ++} ++ ++static inline u32 tx_compl_lastwrb_idx_get(struct be_net_object *pnob) ++{ ++ return (pnob->tx_q_tl + *(u32 *)&pnob->tx_ctxt[pnob->tx_q_tl] - 1) ++ & (pnob->tx_q_len - 1); ++} ++ ++int benet_init(struct net_device *); ++int be_ethtool_ioctl(struct net_device *, struct ifreq *); ++struct net_device_stats *benet_get_stats(struct net_device *); ++void be_process_intr(unsigned long context); ++irqreturn_t be_int(int irq, void *dev); ++void be_post_eth_rx_buffs(struct be_net_object *); ++void be_get_stat_cb(void *, int, struct MCC_WRB_AMAP *); ++void be_get_stats_timer_handler(unsigned long); ++void be_wait_nic_tx_cmplx_cmpl(struct be_net_object *); ++void be_print_link_info(struct BE_LINK_STATUS *); ++void be_update_link_status(struct be_adapter *); ++void be_init_procfs(struct be_adapter *); ++void be_cleanup_procfs(struct be_adapter *); ++int be_poll(struct napi_struct *, int); ++struct ETH_RX_COMPL_AMAP *be_get_rx_cmpl(struct be_net_object *); ++void be_notify_cmpl(struct be_net_object *, int, int, int); ++void be_enable_intr(struct be_net_object *); ++void be_enable_eq_intr(struct be_net_object *); ++void be_disable_intr(struct be_net_object *); ++void be_disable_eq_intr(struct be_net_object *); ++int be_set_uc_mac_adr(struct be_net_object *, u8, u8, u8, ++ u8 *, mcc_wrb_cqe_callback, void *); ++int be_get_flow_ctl(struct be_function_object *pFnObj, bool *, bool *); ++void process_one_tx_compl(struct be_net_object *pnob, u32 end_idx); ++ ++#endif /* _BENET_H_ */ +--- /dev/null ++++ b/drivers/staging/benet/be_netif.c +@@ -0,0 +1,706 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * be_netif.c ++ * ++ * This file contains various entry points of drivers seen by tcp/ip stack. ++ */ ++ ++#include ++#include ++#include "benet.h" ++#include ++#include ++ ++/* Strings to print Link properties */ ++static const char *link_speed[] = { ++ "Invalid link Speed Value", ++ "10 Mbps", ++ "100 Mbps", ++ "1 Gbps", ++ "10 Gbps" ++}; ++ ++static const char *link_duplex[] = { ++ "Invalid Duplex Value", ++ "Half Duplex", ++ "Full Duplex" ++}; ++ ++static const char *link_state[] = { ++ "", ++ "(active)" ++}; ++ ++void be_print_link_info(struct BE_LINK_STATUS *lnk_status) ++{ ++ u16 si, di, ai; ++ ++ /* Port 0 */ ++ if (lnk_status->mac0_speed && lnk_status->mac0_duplex) { ++ /* Port is up and running */ ++ si = (lnk_status->mac0_speed < 5) ? lnk_status->mac0_speed : 0; ++ di = (lnk_status->mac0_duplex < 3) ? ++ lnk_status->mac0_duplex : 0; ++ ai = (lnk_status->active_port == 0) ? 1 : 0; ++ printk(KERN_INFO "PortNo. 0: Speed - %s %s %s\n", ++ link_speed[si], link_duplex[di], link_state[ai]); ++ } else ++ printk(KERN_INFO "PortNo. 0: Down\n"); ++ ++ /* Port 1 */ ++ if (lnk_status->mac1_speed && lnk_status->mac1_duplex) { ++ /* Port is up and running */ ++ si = (lnk_status->mac1_speed < 5) ? lnk_status->mac1_speed : 0; ++ di = (lnk_status->mac1_duplex < 3) ? ++ lnk_status->mac1_duplex : 0; ++ ai = (lnk_status->active_port == 0) ? 1 : 0; ++ printk(KERN_INFO "PortNo. 1: Speed - %s %s %s\n", ++ link_speed[si], link_duplex[di], link_state[ai]); ++ } else ++ printk(KERN_INFO "PortNo. 1: Down\n"); ++ ++ return; ++} ++ ++static int ++be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, ++ void **ip_hdr, void **tcpudp_hdr, ++ u64 *hdr_flags, void *priv) ++{ ++ struct ethhdr *eh; ++ struct vlan_ethhdr *veh; ++ struct iphdr *iph; ++ u8 *va = page_address(frag->page) + frag->page_offset; ++ unsigned long ll_hlen; ++ ++ /* find the mac header, abort if not IPv4 */ ++ ++ prefetch(va); ++ eh = (struct ethhdr *)va; ++ *mac_hdr = eh; ++ ll_hlen = ETH_HLEN; ++ if (eh->h_proto != htons(ETH_P_IP)) { ++ if (eh->h_proto == htons(ETH_P_8021Q)) { ++ veh = (struct vlan_ethhdr *)va; ++ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP)) ++ return -1; ++ ++ ll_hlen += VLAN_HLEN; ++ ++ } else { ++ return -1; ++ } ++ } ++ *hdr_flags = LRO_IPV4; ++ ++ iph = (struct iphdr *)(va + ll_hlen); ++ *ip_hdr = iph; ++ if (iph->protocol != IPPROTO_TCP) ++ return -1; ++ *hdr_flags |= LRO_TCP; ++ *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); ++ ++ return 0; ++} ++ ++static int benet_open(struct net_device *netdev) ++{ ++ struct be_net_object *pnob = (struct be_net_object *)netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ struct net_lro_mgr *lro_mgr; ++ ++ if (adapter->dev_state < BE_DEV_STATE_INIT) ++ return -EAGAIN; ++ ++ lro_mgr = &pnob->lro_mgr; ++ lro_mgr->dev = netdev; ++ ++ lro_mgr->features = LRO_F_NAPI; ++ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; ++ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; ++ lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS; ++ lro_mgr->lro_arr = pnob->lro_desc; ++ lro_mgr->get_frag_header = be_get_frag_header; ++ lro_mgr->max_aggr = adapter->max_rx_coal; ++ lro_mgr->frag_align_pad = 2; ++ if (lro_mgr->max_aggr > MAX_SKB_FRAGS) ++ lro_mgr->max_aggr = MAX_SKB_FRAGS; ++ ++ adapter->max_rx_coal = BE_LRO_MAX_PKTS; ++ ++ be_update_link_status(adapter); ++ ++ /* ++ * Set carrier on only if Physical Link up ++ * Either of the port link status up signifies this ++ */ ++ if ((adapter->port0_link_sts == BE_PORT_LINK_UP) || ++ (adapter->port1_link_sts == BE_PORT_LINK_UP)) { ++ netif_start_queue(netdev); ++ netif_carrier_on(netdev); ++ } ++ ++ adapter->dev_state = BE_DEV_STATE_OPEN; ++ napi_enable(&pnob->napi); ++ be_enable_intr(pnob); ++ be_enable_eq_intr(pnob); ++ /* ++ * RX completion queue may be in dis-armed state. Arm it. ++ */ ++ be_notify_cmpl(pnob, 0, pnob->rx_cq_id, 1); ++ ++ return 0; ++} ++ ++static int benet_close(struct net_device *netdev) ++{ ++ struct be_net_object *pnob = (struct be_net_object *)netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ ++ netif_stop_queue(netdev); ++ synchronize_irq(netdev->irq); ++ ++ be_wait_nic_tx_cmplx_cmpl(pnob); ++ adapter->dev_state = BE_DEV_STATE_INIT; ++ netif_carrier_off(netdev); ++ ++ adapter->port0_link_sts = BE_PORT_LINK_DOWN; ++ adapter->port1_link_sts = BE_PORT_LINK_DOWN; ++ be_disable_intr(pnob); ++ be_disable_eq_intr(pnob); ++ napi_disable(&pnob->napi); ++ ++ return 0; ++} ++ ++/* ++ * Setting a Mac Address for BE ++ * Takes netdev and a void pointer as arguments. ++ * The pointer holds the new addres to be used. ++ */ ++static int benet_set_mac_addr(struct net_device *netdev, void *p) ++{ ++ struct sockaddr *addr = p; ++ struct be_net_object *pnob; ++ ++ pnob = (struct be_net_object *)netdev->priv; ++ ++ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); ++ be_rxf_mac_address_read_write(&pnob->fn_obj, 0, 0, false, true, false, ++ netdev->dev_addr, NULL, NULL); ++ /* ++ * Since we are doing Active-Passive failover, both ++ * ports should have matching MAC addresses everytime. ++ */ ++ be_rxf_mac_address_read_write(&pnob->fn_obj, 1, 0, false, true, false, ++ netdev->dev_addr, NULL, NULL); ++ ++ return 0; ++} ++ ++void be_get_stats_timer_handler(unsigned long context) ++{ ++ struct be_timer_ctxt *ctxt = (struct be_timer_ctxt *)context; ++ ++ if (atomic_read(&ctxt->get_stat_flag)) { ++ atomic_dec(&ctxt->get_stat_flag); ++ up((void *)ctxt->get_stat_sem_addr); ++ } ++ del_timer(&ctxt->get_stats_timer); ++ return; ++} ++ ++void be_get_stat_cb(void *context, int status, ++ struct MCC_WRB_AMAP *optional_wrb) ++{ ++ struct be_timer_ctxt *ctxt = (struct be_timer_ctxt *)context; ++ /* ++ * just up the semaphore if the get_stat_flag ++ * reads 1. so that the waiter can continue. ++ * If it is 0, then it was handled by the timer handler. ++ */ ++ del_timer(&ctxt->get_stats_timer); ++ if (atomic_read(&ctxt->get_stat_flag)) { ++ atomic_dec(&ctxt->get_stat_flag); ++ up((void *)ctxt->get_stat_sem_addr); ++ } ++} ++ ++struct net_device_stats *benet_get_stats(struct net_device *dev) ++{ ++ struct be_net_object *pnob = dev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ u64 pa; ++ struct be_timer_ctxt *ctxt = &adapter->timer_ctxt; ++ ++ if (adapter->dev_state != BE_DEV_STATE_OPEN) { ++ /* Return previously read stats */ ++ return &(adapter->benet_stats); ++ } ++ /* Get Physical Addr */ ++ pa = pci_map_single(adapter->pdev, adapter->eth_statsp, ++ sizeof(struct FWCMD_ETH_GET_STATISTICS), ++ PCI_DMA_FROMDEVICE); ++ ctxt->get_stat_sem_addr = (unsigned long)&adapter->get_eth_stat_sem; ++ atomic_inc(&ctxt->get_stat_flag); ++ ++ be_rxf_query_eth_statistics(&pnob->fn_obj, adapter->eth_statsp, ++ cpu_to_le64(pa), be_get_stat_cb, ctxt, ++ NULL); ++ ++ ctxt->get_stats_timer.data = (unsigned long)ctxt; ++ mod_timer(&ctxt->get_stats_timer, (jiffies + (HZ * 2))); ++ down((void *)ctxt->get_stat_sem_addr); /* callback will unblock us */ ++ ++ /* Adding port0 and port1 stats. */ ++ adapter->benet_stats.rx_packets = ++ adapter->eth_statsp->params.response.p0recvdtotalframes + ++ adapter->eth_statsp->params.response.p1recvdtotalframes; ++ adapter->benet_stats.tx_packets = ++ adapter->eth_statsp->params.response.p0xmitunicastframes + ++ adapter->eth_statsp->params.response.p1xmitunicastframes; ++ adapter->benet_stats.tx_bytes = ++ adapter->eth_statsp->params.response.p0xmitbyteslsd + ++ adapter->eth_statsp->params.response.p1xmitbyteslsd; ++ adapter->benet_stats.rx_errors = ++ adapter->eth_statsp->params.response.p0crcerrors + ++ adapter->eth_statsp->params.response.p1crcerrors; ++ adapter->benet_stats.rx_errors += ++ adapter->eth_statsp->params.response.p0alignmentsymerrs + ++ adapter->eth_statsp->params.response.p1alignmentsymerrs; ++ adapter->benet_stats.rx_errors += ++ adapter->eth_statsp->params.response.p0inrangelenerrors + ++ adapter->eth_statsp->params.response.p1inrangelenerrors; ++ adapter->benet_stats.rx_bytes = ++ adapter->eth_statsp->params.response.p0recvdtotalbytesLSD + ++ adapter->eth_statsp->params.response.p1recvdtotalbytesLSD; ++ adapter->benet_stats.rx_crc_errors = ++ adapter->eth_statsp->params.response.p0crcerrors + ++ adapter->eth_statsp->params.response.p1crcerrors; ++ ++ adapter->benet_stats.tx_packets += ++ adapter->eth_statsp->params.response.p0xmitmulticastframes + ++ adapter->eth_statsp->params.response.p1xmitmulticastframes; ++ adapter->benet_stats.tx_packets += ++ adapter->eth_statsp->params.response.p0xmitbroadcastframes + ++ adapter->eth_statsp->params.response.p1xmitbroadcastframes; ++ adapter->benet_stats.tx_errors = 0; ++ ++ adapter->benet_stats.multicast = ++ adapter->eth_statsp->params.response.p0xmitmulticastframes + ++ adapter->eth_statsp->params.response.p1xmitmulticastframes; ++ ++ adapter->benet_stats.rx_fifo_errors = ++ adapter->eth_statsp->params.response.p0rxfifooverflowdropped + ++ adapter->eth_statsp->params.response.p1rxfifooverflowdropped; ++ adapter->benet_stats.rx_frame_errors = ++ adapter->eth_statsp->params.response.p0alignmentsymerrs + ++ adapter->eth_statsp->params.response.p1alignmentsymerrs; ++ adapter->benet_stats.rx_length_errors = ++ adapter->eth_statsp->params.response.p0inrangelenerrors + ++ adapter->eth_statsp->params.response.p1inrangelenerrors; ++ adapter->benet_stats.rx_length_errors += ++ adapter->eth_statsp->params.response.p0outrangeerrors + ++ adapter->eth_statsp->params.response.p1outrangeerrors; ++ adapter->benet_stats.rx_length_errors += ++ adapter->eth_statsp->params.response.p0frametoolongerrors + ++ adapter->eth_statsp->params.response.p1frametoolongerrors; ++ ++ pci_unmap_single(adapter->pdev, (ulong) adapter->eth_statsp, ++ sizeof(struct FWCMD_ETH_GET_STATISTICS), ++ PCI_DMA_FROMDEVICE); ++ return &(adapter->benet_stats); ++ ++} ++ ++static void be_start_tx(struct be_net_object *pnob, u32 nposted) ++{ ++#define CSR_ETH_MAX_SQPOSTS 255 ++ struct SQ_DB_AMAP sqdb; ++ ++ sqdb.dw[0] = 0; ++ ++ AMAP_SET_BITS_PTR(SQ_DB, cid, &sqdb, pnob->tx_q_id); ++ while (nposted) { ++ if (nposted > CSR_ETH_MAX_SQPOSTS) { ++ AMAP_SET_BITS_PTR(SQ_DB, numPosted, &sqdb, ++ CSR_ETH_MAX_SQPOSTS); ++ nposted -= CSR_ETH_MAX_SQPOSTS; ++ } else { ++ AMAP_SET_BITS_PTR(SQ_DB, numPosted, &sqdb, nposted); ++ nposted = 0; ++ } ++ PD_WRITE(&pnob->fn_obj, etx_sq_db, sqdb.dw[0]); ++ } ++ ++ return; ++} ++ ++static void update_tx_rate(struct be_adapter *adapter) ++{ ++ /* update the rate once in two seconds */ ++ if ((jiffies - adapter->eth_tx_jiffies) > 2 * (HZ)) { ++ u32 r; ++ r = adapter->eth_tx_bytes / ++ ((jiffies - adapter->eth_tx_jiffies) / (HZ)); ++ r = (r / 1000000); /* M bytes/s */ ++ adapter->be_stat.bes_eth_tx_rate = (r * 8); /* M bits/s */ ++ adapter->eth_tx_jiffies = jiffies; ++ adapter->eth_tx_bytes = 0; ++ } ++} ++ ++static int wrb_cnt_in_skb(struct sk_buff *skb) ++{ ++ int cnt = 0; ++ while (skb) { ++ if (skb->len > skb->data_len) ++ cnt++; ++ cnt += skb_shinfo(skb)->nr_frags; ++ skb = skb_shinfo(skb)->frag_list; ++ } ++ BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT); ++ return cnt; ++} ++ ++static void wrb_fill(struct ETH_WRB_AMAP *wrb, u64 addr, int len) ++{ ++ AMAP_SET_BITS_PTR(ETH_WRB, frag_pa_hi, wrb, addr >> 32); ++ AMAP_SET_BITS_PTR(ETH_WRB, frag_pa_lo, wrb, addr & 0xFFFFFFFF); ++ AMAP_SET_BITS_PTR(ETH_WRB, frag_len, wrb, len); ++} ++ ++static void wrb_fill_extra(struct ETH_WRB_AMAP *wrb, struct sk_buff *skb, ++ struct be_net_object *pnob) ++{ ++ wrb->dw[2] = wrb->dw[3] = 0; ++ AMAP_SET_BITS_PTR(ETH_WRB, crc, wrb, 1); ++ if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) { ++ AMAP_SET_BITS_PTR(ETH_WRB, lso, wrb, 1); ++ AMAP_SET_BITS_PTR(ETH_WRB, lso_mss, wrb, ++ skb_shinfo(skb)->gso_size); ++ } else if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ u8 proto = ((struct iphdr *)ip_hdr(skb))->protocol; ++ if (proto == IPPROTO_TCP) ++ AMAP_SET_BITS_PTR(ETH_WRB, tcpcs, wrb, 1); ++ else if (proto == IPPROTO_UDP) ++ AMAP_SET_BITS_PTR(ETH_WRB, udpcs, wrb, 1); ++ } ++ if (pnob->vlan_grp && vlan_tx_tag_present(skb)) { ++ AMAP_SET_BITS_PTR(ETH_WRB, vlan, wrb, 1); ++ AMAP_SET_BITS_PTR(ETH_WRB, vlan_tag, wrb, vlan_tx_tag_get(skb)); ++ } ++} ++ ++static inline void wrb_copy_extra(struct ETH_WRB_AMAP *to, ++ struct ETH_WRB_AMAP *from) ++{ ++ ++ to->dw[2] = from->dw[2]; ++ to->dw[3] = from->dw[3]; ++} ++ ++/* Returns the actual count of wrbs used including a possible dummy */ ++static int copy_skb_to_txq(struct be_net_object *pnob, struct sk_buff *skb, ++ u32 wrb_cnt, u32 *copied) ++{ ++ u64 busaddr; ++ struct ETH_WRB_AMAP *wrb = NULL, *first = NULL; ++ u32 i; ++ bool dummy = true; ++ struct pci_dev *pdev = pnob->adapter->pdev; ++ ++ if (wrb_cnt & 1) ++ wrb_cnt++; ++ else ++ dummy = false; ++ ++ atomic_add(wrb_cnt, &pnob->tx_q_used); ++ ++ while (skb) { ++ if (skb->len > skb->data_len) { ++ int len = skb->len - skb->data_len; ++ busaddr = pci_map_single(pdev, skb->data, len, ++ PCI_DMA_TODEVICE); ++ busaddr = cpu_to_le64(busaddr); ++ wrb = &pnob->tx_q[pnob->tx_q_hd]; ++ if (first == NULL) { ++ wrb_fill_extra(wrb, skb, pnob); ++ first = wrb; ++ } else { ++ wrb_copy_extra(wrb, first); ++ } ++ wrb_fill(wrb, busaddr, len); ++ be_adv_txq_hd(pnob); ++ *copied += len; ++ } ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ struct skb_frag_struct *frag = ++ &skb_shinfo(skb)->frags[i]; ++ busaddr = pci_map_page(pdev, frag->page, ++ frag->page_offset, frag->size, ++ PCI_DMA_TODEVICE); ++ busaddr = cpu_to_le64(busaddr); ++ wrb = &pnob->tx_q[pnob->tx_q_hd]; ++ if (first == NULL) { ++ wrb_fill_extra(wrb, skb, pnob); ++ first = wrb; ++ } else { ++ wrb_copy_extra(wrb, first); ++ } ++ wrb_fill(wrb, busaddr, frag->size); ++ be_adv_txq_hd(pnob); ++ *copied += frag->size; ++ } ++ skb = skb_shinfo(skb)->frag_list; ++ } ++ ++ if (dummy) { ++ wrb = &pnob->tx_q[pnob->tx_q_hd]; ++ BUG_ON(first == NULL); ++ wrb_copy_extra(wrb, first); ++ wrb_fill(wrb, 0, 0); ++ be_adv_txq_hd(pnob); ++ } ++ AMAP_SET_BITS_PTR(ETH_WRB, complete, wrb, 1); ++ AMAP_SET_BITS_PTR(ETH_WRB, last, wrb, 1); ++ return wrb_cnt; ++} ++ ++/* For each skb transmitted, tx_ctxt stores the num of wrbs in the ++ * start index and skb pointer in the end index ++ */ ++static inline void be_tx_wrb_info_remember(struct be_net_object *pnob, ++ struct sk_buff *skb, int wrb_cnt, ++ u32 start) ++{ ++ *(u32 *) (&pnob->tx_ctxt[start]) = wrb_cnt; ++ index_adv(&start, wrb_cnt - 1, pnob->tx_q_len); ++ pnob->tx_ctxt[start] = skb; ++} ++ ++static int benet_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ u32 wrb_cnt, copied = 0; ++ u32 start = pnob->tx_q_hd; ++ ++ adapter->be_stat.bes_tx_reqs++; ++ ++ wrb_cnt = wrb_cnt_in_skb(skb); ++ spin_lock_bh(&adapter->txq_lock); ++ if ((pnob->tx_q_len - 2 - atomic_read(&pnob->tx_q_used)) <= wrb_cnt) { ++ netif_stop_queue(pnob->netdev); ++ spin_unlock_bh(&adapter->txq_lock); ++ adapter->be_stat.bes_tx_fails++; ++ return NETDEV_TX_BUSY; ++ } ++ spin_unlock_bh(&adapter->txq_lock); ++ ++ wrb_cnt = copy_skb_to_txq(pnob, skb, wrb_cnt, &copied); ++ be_tx_wrb_info_remember(pnob, skb, wrb_cnt, start); ++ ++ be_start_tx(pnob, wrb_cnt); ++ ++ adapter->eth_tx_bytes += copied; ++ adapter->be_stat.bes_tx_wrbs += wrb_cnt; ++ update_tx_rate(adapter); ++ netdev->trans_start = jiffies; ++ ++ return NETDEV_TX_OK; ++} ++ ++/* ++ * This is the driver entry point to change the mtu of the device ++ * Returns 0 for success and errno for failure. ++ */ ++static int benet_change_mtu(struct net_device *netdev, int new_mtu) ++{ ++ /* ++ * BE supports jumbo frame size upto 9000 bytes including the link layer ++ * header. Considering the different variants of frame formats possible ++ * like VLAN, SNAP/LLC, the maximum possible value for MTU is 8974 bytes ++ */ ++ ++ if (new_mtu < (ETH_ZLEN + ETH_FCS_LEN) || (new_mtu > BE_MAX_MTU)) { ++ dev_info(&netdev->dev, "Invalid MTU requested. " ++ "Must be between %d and %d bytes\n", ++ (ETH_ZLEN + ETH_FCS_LEN), BE_MAX_MTU); ++ return -EINVAL; ++ } ++ dev_info(&netdev->dev, "MTU changed from %d to %d\n", ++ netdev->mtu, new_mtu); ++ netdev->mtu = new_mtu; ++ return 0; ++} ++ ++/* ++ * This is the driver entry point to register a vlan with the device ++ */ ++static void benet_vlan_register(struct net_device *netdev, ++ struct vlan_group *grp) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ ++ be_disable_eq_intr(pnob); ++ pnob->vlan_grp = grp; ++ pnob->num_vlans = 0; ++ be_enable_eq_intr(pnob); ++} ++ ++/* ++ * This is the driver entry point to add a vlan vlan_id ++ * with the device netdev ++ */ ++static void benet_vlan_add_vid(struct net_device *netdev, u16 vlan_id) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ ++ if (pnob->num_vlans == (BE_NUM_VLAN_SUPPORTED - 1)) { ++ /* no way to return an error */ ++ dev_info(&netdev->dev, ++ "BladeEngine: Cannot configure more than %d Vlans\n", ++ BE_NUM_VLAN_SUPPORTED); ++ return; ++ } ++ /* The new vlan tag will be in the slot indicated by num_vlans. */ ++ pnob->vlan_tag[pnob->num_vlans++] = vlan_id; ++ be_rxf_vlan_config(&pnob->fn_obj, false, pnob->num_vlans, ++ pnob->vlan_tag, NULL, NULL, NULL); ++} ++ ++/* ++ * This is the driver entry point to remove a vlan vlan_id ++ * with the device netdev ++ */ ++static void benet_vlan_rem_vid(struct net_device *netdev, u16 vlan_id) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ ++ u32 i, value; ++ ++ /* ++ * In Blade Engine, we support 32 vlan tag filters across both ports. ++ * To program a vlan tag, the RXF_RTPR_CSR register is used. ++ * Each 32-bit value of RXF_RTDR_CSR can address 2 vlan tag entries. ++ * The Vlan table is of depth 16. thus we support 32 tags. ++ */ ++ ++ value = vlan_id | VLAN_VALID_BIT; ++ for (i = 0; i < BE_NUM_VLAN_SUPPORTED; i++) { ++ if (pnob->vlan_tag[i] == vlan_id) ++ break; ++ } ++ ++ if (i == BE_NUM_VLAN_SUPPORTED) ++ return; ++ /* Now compact the vlan tag array by removing hole created. */ ++ while ((i + 1) < BE_NUM_VLAN_SUPPORTED) { ++ pnob->vlan_tag[i] = pnob->vlan_tag[i + 1]; ++ i++; ++ } ++ if ((i + 1) == BE_NUM_VLAN_SUPPORTED) ++ pnob->vlan_tag[i] = (u16) 0x0; ++ pnob->num_vlans--; ++ be_rxf_vlan_config(&pnob->fn_obj, false, pnob->num_vlans, ++ pnob->vlan_tag, NULL, NULL, NULL); ++} ++ ++/* ++ * This function is called to program multicast ++ * address in the multicast filter of the ASIC. ++ */ ++static void be_set_multicast_filter(struct net_device *netdev) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct dev_mc_list *mc_ptr; ++ u8 mac_addr[32][ETH_ALEN]; ++ int i; ++ ++ if (netdev->flags & IFF_ALLMULTI) { ++ /* set BE in Multicast promiscuous */ ++ be_rxf_multicast_config(&pnob->fn_obj, true, 0, NULL, NULL, ++ NULL, NULL); ++ return; ++ } ++ ++ for (mc_ptr = netdev->mc_list, i = 0; mc_ptr; ++ mc_ptr = mc_ptr->next, i++) { ++ memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN); ++ } ++ ++ /* reset the promiscuous mode also. */ ++ be_rxf_multicast_config(&pnob->fn_obj, false, i, ++ &mac_addr[0][0], NULL, NULL, NULL); ++} ++ ++/* ++ * This is the driver entry point to set multicast list ++ * with the device netdev. This function will be used to ++ * set promiscuous mode or multicast promiscuous mode ++ * or multicast mode.... ++ */ ++static void benet_set_multicast_list(struct net_device *netdev) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ ++ if (netdev->flags & IFF_PROMISC) { ++ be_rxf_promiscuous(&pnob->fn_obj, 1, 1, NULL, NULL, NULL); ++ } else { ++ be_rxf_promiscuous(&pnob->fn_obj, 0, 0, NULL, NULL, NULL); ++ be_set_multicast_filter(netdev); ++ } ++} ++ ++int benet_init(struct net_device *netdev) ++{ ++ struct be_net_object *pnob = netdev->priv; ++ struct be_adapter *adapter = pnob->adapter; ++ ++ ether_setup(netdev); ++ ++ netdev->open = &benet_open; ++ netdev->stop = &benet_close; ++ netdev->hard_start_xmit = &benet_xmit; ++ ++ netdev->get_stats = &benet_get_stats; ++ ++ netdev->set_multicast_list = &benet_set_multicast_list; ++ ++ netdev->change_mtu = &benet_change_mtu; ++ netdev->set_mac_address = &benet_set_mac_addr; ++ ++ netdev->vlan_rx_register = benet_vlan_register; ++ netdev->vlan_rx_add_vid = benet_vlan_add_vid; ++ netdev->vlan_rx_kill_vid = benet_vlan_rem_vid; ++ ++ netdev->features = ++ NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | ++ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM; ++ ++ netdev->flags |= IFF_MULTICAST; ++ ++ /* If device is DAC Capable, set the HIGHDMA flag for netdevice. */ ++ if (adapter->dma_64bit_cap) ++ netdev->features |= NETIF_F_HIGHDMA; ++ ++ SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); ++ return 0; ++} +--- /dev/null ++++ b/drivers/staging/benet/bestatus.h +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#ifndef _BESTATUS_H_ ++#define _BESTATUS_H_ ++ ++#define BE_SUCCESS (0x00000000L) ++/* ++ * MessageId: BE_PENDING ++ * The BladeEngine Driver call succeeded, and pended operation. ++ */ ++#define BE_PENDING (0x20070001L) ++#define BE_STATUS_PENDING (BE_PENDING) ++/* ++ * MessageId: BE_NOT_OK ++ * An error occurred. ++ */ ++#define BE_NOT_OK (0xE0070002L) ++/* ++ * MessageId: BE_STATUS_SYSTEM_RESOURCES ++ * Insufficient host system resources exist to complete the API. ++ */ ++#define BE_STATUS_SYSTEM_RESOURCES (0xE0070003L) ++/* ++ * MessageId: BE_STATUS_CHIP_RESOURCES ++ * Insufficient chip resources exist to complete the API. ++ */ ++#define BE_STATUS_CHIP_RESOURCES (0xE0070004L) ++/* ++ * MessageId: BE_STATUS_NO_RESOURCE ++ * Insufficient resources to complete request. ++ */ ++#define BE_STATUS_NO_RESOURCE (0xE0070005L) ++/* ++ * MessageId: BE_STATUS_BUSY ++ * Resource is currently busy. ++ */ ++#define BE_STATUS_BUSY (0xE0070006L) ++/* ++ * MessageId: BE_STATUS_INVALID_PARAMETER ++ * Invalid Parameter in request. ++ */ ++#define BE_STATUS_INVALID_PARAMETER (0xE0000007L) ++/* ++ * MessageId: BE_STATUS_NOT_SUPPORTED ++ * Requested operation is not supported. ++ */ ++#define BE_STATUS_NOT_SUPPORTED (0xE000000DL) ++ ++/* ++ * *************************************************************************** ++ * E T H E R N E T S T A T U S ++ * *************************************************************************** ++ */ ++ ++/* ++ * MessageId: BE_ETH_TX_ERROR ++ * The Ethernet device driver failed to transmit a packet. ++ */ ++#define BE_ETH_TX_ERROR (0xE0070101L) ++ ++/* ++ * *************************************************************************** ++ * S H A R E D S T A T U S ++ * *************************************************************************** ++ */ ++ ++/* ++ * MessageId: BE_STATUS_VBD_INVALID_VERSION ++ * The device driver is not compatible with this version of the VBD. ++ */ ++#define BE_STATUS_INVALID_VERSION (0xE0070402L) ++/* ++ * MessageId: BE_STATUS_DOMAIN_DENIED ++ * The operation failed to complete due to insufficient access ++ * rights for the requesting domain. ++ */ ++#define BE_STATUS_DOMAIN_DENIED (0xE0070403L) ++/* ++ * MessageId: BE_STATUS_TCP_NOT_STARTED ++ * The embedded TCP/IP stack has not been started. ++ */ ++#define BE_STATUS_TCP_NOT_STARTED (0xE0070409L) ++/* ++ * MessageId: BE_STATUS_NO_MCC_WRB ++ * No free MCC WRB are available for posting the request. ++ */ ++#define BE_STATUS_NO_MCC_WRB (0xE0070414L) ++ ++#endif /* _BESTATUS_ */ +--- /dev/null ++++ b/drivers/staging/benet/cev.h +@@ -0,0 +1,243 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __cev_amap_h__ ++#define __cev_amap_h__ ++#include "ep.h" ++ ++/* ++ * Host Interrupt Status Register 0. The first of four application ++ * interrupt status registers. This register contains the interrupts ++ * for Event Queues EQ0 through EQ31. ++ */ ++struct BE_CEV_ISR0_CSR_AMAP { ++ u8 interrupt0; /* DWORD 0 */ ++ u8 interrupt1; /* DWORD 0 */ ++ u8 interrupt2; /* DWORD 0 */ ++ u8 interrupt3; /* DWORD 0 */ ++ u8 interrupt4; /* DWORD 0 */ ++ u8 interrupt5; /* DWORD 0 */ ++ u8 interrupt6; /* DWORD 0 */ ++ u8 interrupt7; /* DWORD 0 */ ++ u8 interrupt8; /* DWORD 0 */ ++ u8 interrupt9; /* DWORD 0 */ ++ u8 interrupt10; /* DWORD 0 */ ++ u8 interrupt11; /* DWORD 0 */ ++ u8 interrupt12; /* DWORD 0 */ ++ u8 interrupt13; /* DWORD 0 */ ++ u8 interrupt14; /* DWORD 0 */ ++ u8 interrupt15; /* DWORD 0 */ ++ u8 interrupt16; /* DWORD 0 */ ++ u8 interrupt17; /* DWORD 0 */ ++ u8 interrupt18; /* DWORD 0 */ ++ u8 interrupt19; /* DWORD 0 */ ++ u8 interrupt20; /* DWORD 0 */ ++ u8 interrupt21; /* DWORD 0 */ ++ u8 interrupt22; /* DWORD 0 */ ++ u8 interrupt23; /* DWORD 0 */ ++ u8 interrupt24; /* DWORD 0 */ ++ u8 interrupt25; /* DWORD 0 */ ++ u8 interrupt26; /* DWORD 0 */ ++ u8 interrupt27; /* DWORD 0 */ ++ u8 interrupt28; /* DWORD 0 */ ++ u8 interrupt29; /* DWORD 0 */ ++ u8 interrupt30; /* DWORD 0 */ ++ u8 interrupt31; /* DWORD 0 */ ++} __packed; ++struct CEV_ISR0_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * Host Interrupt Status Register 1. The second of four application ++ * interrupt status registers. This register contains the interrupts ++ * for Event Queues EQ32 through EQ63. ++ */ ++struct BE_CEV_ISR1_CSR_AMAP { ++ u8 interrupt32; /* DWORD 0 */ ++ u8 interrupt33; /* DWORD 0 */ ++ u8 interrupt34; /* DWORD 0 */ ++ u8 interrupt35; /* DWORD 0 */ ++ u8 interrupt36; /* DWORD 0 */ ++ u8 interrupt37; /* DWORD 0 */ ++ u8 interrupt38; /* DWORD 0 */ ++ u8 interrupt39; /* DWORD 0 */ ++ u8 interrupt40; /* DWORD 0 */ ++ u8 interrupt41; /* DWORD 0 */ ++ u8 interrupt42; /* DWORD 0 */ ++ u8 interrupt43; /* DWORD 0 */ ++ u8 interrupt44; /* DWORD 0 */ ++ u8 interrupt45; /* DWORD 0 */ ++ u8 interrupt46; /* DWORD 0 */ ++ u8 interrupt47; /* DWORD 0 */ ++ u8 interrupt48; /* DWORD 0 */ ++ u8 interrupt49; /* DWORD 0 */ ++ u8 interrupt50; /* DWORD 0 */ ++ u8 interrupt51; /* DWORD 0 */ ++ u8 interrupt52; /* DWORD 0 */ ++ u8 interrupt53; /* DWORD 0 */ ++ u8 interrupt54; /* DWORD 0 */ ++ u8 interrupt55; /* DWORD 0 */ ++ u8 interrupt56; /* DWORD 0 */ ++ u8 interrupt57; /* DWORD 0 */ ++ u8 interrupt58; /* DWORD 0 */ ++ u8 interrupt59; /* DWORD 0 */ ++ u8 interrupt60; /* DWORD 0 */ ++ u8 interrupt61; /* DWORD 0 */ ++ u8 interrupt62; /* DWORD 0 */ ++ u8 interrupt63; /* DWORD 0 */ ++} __packed; ++struct CEV_ISR1_CSR_AMAP { ++ u32 dw[1]; ++}; ++/* ++ * Host Interrupt Status Register 2. The third of four application ++ * interrupt status registers. This register contains the interrupts ++ * for Event Queues EQ64 through EQ95. ++ */ ++struct BE_CEV_ISR2_CSR_AMAP { ++ u8 interrupt64; /* DWORD 0 */ ++ u8 interrupt65; /* DWORD 0 */ ++ u8 interrupt66; /* DWORD 0 */ ++ u8 interrupt67; /* DWORD 0 */ ++ u8 interrupt68; /* DWORD 0 */ ++ u8 interrupt69; /* DWORD 0 */ ++ u8 interrupt70; /* DWORD 0 */ ++ u8 interrupt71; /* DWORD 0 */ ++ u8 interrupt72; /* DWORD 0 */ ++ u8 interrupt73; /* DWORD 0 */ ++ u8 interrupt74; /* DWORD 0 */ ++ u8 interrupt75; /* DWORD 0 */ ++ u8 interrupt76; /* DWORD 0 */ ++ u8 interrupt77; /* DWORD 0 */ ++ u8 interrupt78; /* DWORD 0 */ ++ u8 interrupt79; /* DWORD 0 */ ++ u8 interrupt80; /* DWORD 0 */ ++ u8 interrupt81; /* DWORD 0 */ ++ u8 interrupt82; /* DWORD 0 */ ++ u8 interrupt83; /* DWORD 0 */ ++ u8 interrupt84; /* DWORD 0 */ ++ u8 interrupt85; /* DWORD 0 */ ++ u8 interrupt86; /* DWORD 0 */ ++ u8 interrupt87; /* DWORD 0 */ ++ u8 interrupt88; /* DWORD 0 */ ++ u8 interrupt89; /* DWORD 0 */ ++ u8 interrupt90; /* DWORD 0 */ ++ u8 interrupt91; /* DWORD 0 */ ++ u8 interrupt92; /* DWORD 0 */ ++ u8 interrupt93; /* DWORD 0 */ ++ u8 interrupt94; /* DWORD 0 */ ++ u8 interrupt95; /* DWORD 0 */ ++} __packed; ++struct CEV_ISR2_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * Host Interrupt Status Register 3. The fourth of four application ++ * interrupt status registers. This register contains the interrupts ++ * for Event Queues EQ96 through EQ127. ++ */ ++struct BE_CEV_ISR3_CSR_AMAP { ++ u8 interrupt96; /* DWORD 0 */ ++ u8 interrupt97; /* DWORD 0 */ ++ u8 interrupt98; /* DWORD 0 */ ++ u8 interrupt99; /* DWORD 0 */ ++ u8 interrupt100; /* DWORD 0 */ ++ u8 interrupt101; /* DWORD 0 */ ++ u8 interrupt102; /* DWORD 0 */ ++ u8 interrupt103; /* DWORD 0 */ ++ u8 interrupt104; /* DWORD 0 */ ++ u8 interrupt105; /* DWORD 0 */ ++ u8 interrupt106; /* DWORD 0 */ ++ u8 interrupt107; /* DWORD 0 */ ++ u8 interrupt108; /* DWORD 0 */ ++ u8 interrupt109; /* DWORD 0 */ ++ u8 interrupt110; /* DWORD 0 */ ++ u8 interrupt111; /* DWORD 0 */ ++ u8 interrupt112; /* DWORD 0 */ ++ u8 interrupt113; /* DWORD 0 */ ++ u8 interrupt114; /* DWORD 0 */ ++ u8 interrupt115; /* DWORD 0 */ ++ u8 interrupt116; /* DWORD 0 */ ++ u8 interrupt117; /* DWORD 0 */ ++ u8 interrupt118; /* DWORD 0 */ ++ u8 interrupt119; /* DWORD 0 */ ++ u8 interrupt120; /* DWORD 0 */ ++ u8 interrupt121; /* DWORD 0 */ ++ u8 interrupt122; /* DWORD 0 */ ++ u8 interrupt123; /* DWORD 0 */ ++ u8 interrupt124; /* DWORD 0 */ ++ u8 interrupt125; /* DWORD 0 */ ++ u8 interrupt126; /* DWORD 0 */ ++ u8 interrupt127; /* DWORD 0 */ ++} __packed; ++struct CEV_ISR3_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Completions and Events block Registers. */ ++struct BE_CEV_CSRMAP_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[32]; /* DWORD 1 */ ++ u8 rsvd2[32]; /* DWORD 2 */ ++ u8 rsvd3[32]; /* DWORD 3 */ ++ struct BE_CEV_ISR0_CSR_AMAP isr0; ++ struct BE_CEV_ISR1_CSR_AMAP isr1; ++ struct BE_CEV_ISR2_CSR_AMAP isr2; ++ struct BE_CEV_ISR3_CSR_AMAP isr3; ++ u8 rsvd4[32]; /* DWORD 8 */ ++ u8 rsvd5[32]; /* DWORD 9 */ ++ u8 rsvd6[32]; /* DWORD 10 */ ++ u8 rsvd7[32]; /* DWORD 11 */ ++ u8 rsvd8[32]; /* DWORD 12 */ ++ u8 rsvd9[32]; /* DWORD 13 */ ++ u8 rsvd10[32]; /* DWORD 14 */ ++ u8 rsvd11[32]; /* DWORD 15 */ ++ u8 rsvd12[32]; /* DWORD 16 */ ++ u8 rsvd13[32]; /* DWORD 17 */ ++ u8 rsvd14[32]; /* DWORD 18 */ ++ u8 rsvd15[32]; /* DWORD 19 */ ++ u8 rsvd16[32]; /* DWORD 20 */ ++ u8 rsvd17[32]; /* DWORD 21 */ ++ u8 rsvd18[32]; /* DWORD 22 */ ++ u8 rsvd19[32]; /* DWORD 23 */ ++ u8 rsvd20[32]; /* DWORD 24 */ ++ u8 rsvd21[32]; /* DWORD 25 */ ++ u8 rsvd22[32]; /* DWORD 26 */ ++ u8 rsvd23[32]; /* DWORD 27 */ ++ u8 rsvd24[32]; /* DWORD 28 */ ++ u8 rsvd25[32]; /* DWORD 29 */ ++ u8 rsvd26[32]; /* DWORD 30 */ ++ u8 rsvd27[32]; /* DWORD 31 */ ++ u8 rsvd28[32]; /* DWORD 32 */ ++ u8 rsvd29[32]; /* DWORD 33 */ ++ u8 rsvd30[192]; /* DWORD 34 */ ++ u8 rsvd31[192]; /* DWORD 40 */ ++ u8 rsvd32[160]; /* DWORD 46 */ ++ u8 rsvd33[160]; /* DWORD 51 */ ++ u8 rsvd34[160]; /* DWORD 56 */ ++ u8 rsvd35[96]; /* DWORD 61 */ ++ u8 rsvd36[192][32]; /* DWORD 64 */ ++} __packed; ++struct CEV_CSRMAP_AMAP { ++ u32 dw[256]; ++}; ++ ++#endif /* __cev_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/cq.c +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include "hwlib.h" ++#include "bestatus.h" ++ ++/* ++ * Completion Queue Objects ++ */ ++/* ++ *============================================================================ ++ * P U B L I C R O U T I N E S ++ *============================================================================ ++ */ ++ ++/* ++ This routine creates a completion queue based on the client completion ++ queue configuration information. ++ ++ ++ FunctionObject - Handle to a function object ++ CqBaseVa - Base VA for a the CQ ring ++ NumEntries - CEV_CQ_CNT_* values ++ solEventEnable - 0 = All CQEs can generate Events if CQ is eventable ++ 1 = only CQEs with solicited bit set are eventable ++ eventable - Eventable CQ, generates interrupts. ++ nodelay - 1 = Force interrupt, relevent if CQ eventable. ++ Interrupt is asserted immediately after EQE ++ write is confirmed, regardless of EQ Timer ++ or watermark settings. ++ wme - Enable watermark based coalescing ++ wmThresh - High watermark(CQ fullness at which event ++ or interrupt should be asserted). These are the ++ CEV_WATERMARK encoded values. ++ EqObject - EQ Handle to assign to this CQ ++ ppCqObject - Internal CQ Handle returned. ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful error code is ++ returned. ++ ++ IRQL < DISPATCH_LEVEL ++ ++*/ ++int be_cq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 length, bool solicited_eventable, ++ bool no_delay, u32 wm_thresh, ++ struct be_eq_object *eq_object, struct be_cq_object *cq_object) ++{ ++ int status = BE_SUCCESS; ++ u32 num_entries_encoding; ++ u32 num_entries = length / sizeof(struct MCC_CQ_ENTRY_AMAP); ++ struct FWCMD_COMMON_CQ_CREATE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ u32 n; ++ unsigned long irql; ++ ++ ASSERT(rd); ++ ASSERT(cq_object); ++ ASSERT(length % sizeof(struct MCC_CQ_ENTRY_AMAP) == 0); ++ ++ switch (num_entries) { ++ case 256: ++ num_entries_encoding = CEV_CQ_CNT_256; ++ break; ++ case 512: ++ num_entries_encoding = CEV_CQ_CNT_512; ++ break; ++ case 1024: ++ num_entries_encoding = CEV_CQ_CNT_1024; ++ break; ++ default: ++ ASSERT(0); ++ return BE_STATUS_INVALID_PARAMETER; ++ } ++ ++ /* ++ * All cq entries all the same size. Use iSCSI version ++ * as a test for the proper rd length. ++ */ ++ memset(cq_object, 0, sizeof(*cq_object)); ++ ++ atomic_set(&cq_object->ref_count, 0); ++ cq_object->parent_function = pfob; ++ cq_object->eq_object = eq_object; ++ cq_object->num_entries = num_entries; ++ /* save for MCC cq processing */ ++ cq_object->va = rd->va; ++ ++ /* map into UT. */ ++ length = num_entries * sizeof(struct MCC_CQ_ENTRY_AMAP); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ ASSERT(wrb); ++ TRACE(DL_ERR, "No free MCC WRBs in create EQ."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_CQ_CREATE); ++ ++ fwcmd->params.request.num_pages = PAGES_SPANNED(OFFSET_IN_PAGE(rd->va), ++ length); ++ ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, valid, &fwcmd->params.request.context, 1); ++ n = pfob->pci_function_number; ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, Func, &fwcmd->params.request.context, n); ++ ++ n = (eq_object != NULL); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, Eventable, ++ &fwcmd->params.request.context, n); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, Armed, &fwcmd->params.request.context, 1); ++ ++ n = eq_object ? eq_object->eq_id : 0; ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, EQID, &fwcmd->params.request.context, n); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, Count, ++ &fwcmd->params.request.context, num_entries_encoding); ++ ++ n = 0; /* Protection Domain is always 0 in Linux driver */ ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, PD, &fwcmd->params.request.context, n); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, NoDelay, ++ &fwcmd->params.request.context, no_delay); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, SolEvent, ++ &fwcmd->params.request.context, solicited_eventable); ++ ++ n = (wm_thresh != 0xFFFFFFFF); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, WME, &fwcmd->params.request.context, n); ++ ++ n = (n ? wm_thresh : 0); ++ AMAP_SET_BITS_PTR(CQ_CONTEXT, Watermark, ++ &fwcmd->params.request.context, n); ++ /* Create a page list for the FWCMD. */ ++ be_rd_to_pa_list(rd, fwcmd->params.request.pages, ++ ARRAY_SIZE(fwcmd->params.request.pages)); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "MCC to create CQ failed."); ++ goto Error; ++ } ++ /* Remember the CQ id. */ ++ cq_object->cq_id = fwcmd->params.response.cq_id; ++ ++ /* insert this cq into eq_object reference */ ++ if (eq_object) { ++ atomic_inc(&eq_object->ref_count); ++ list_add_tail(&cq_object->cqlist_for_eq, ++ &eq_object->cq_list_head); ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ ++ Deferences the given object. Once the object's reference count drops to ++ zero, the object is destroyed and all resources that are held by this object ++ are released. The on-chip context is also destroyed along with the queue ++ ID, and any mappings made into the UT. ++ ++ cq_object - CQ handle returned from cq_object_create. ++ ++ returns the current reference count on the object ++ ++ IRQL: IRQL < DISPATCH_LEVEL ++*/ ++int be_cq_destroy(struct be_cq_object *cq_object) ++{ ++ int status = 0; ++ ++ /* Nothing should reference this CQ at this point. */ ++ ASSERT(atomic_read(&cq_object->ref_count) == 0); ++ ++ /* Send fwcmd to destroy the CQ. */ ++ status = be_function_ring_destroy(cq_object->parent_function, ++ cq_object->cq_id, FWCMD_RING_TYPE_CQ, ++ NULL, NULL, NULL, NULL); ++ ASSERT(status == 0); ++ ++ /* Remove reference if this is an eventable CQ. */ ++ if (cq_object->eq_object) { ++ atomic_dec(&cq_object->eq_object->ref_count); ++ list_del(&cq_object->cqlist_for_eq); ++ } ++ return BE_SUCCESS; ++} ++ +--- /dev/null ++++ b/drivers/staging/benet/descriptors.h +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __descriptors_amap_h__ ++#define __descriptors_amap_h__ ++ ++/* ++ * --- IPC_NODE_ID_ENUM --- ++ * IPC processor id values ++ */ ++#define TPOST_NODE_ID (0) /* TPOST ID */ ++#define TPRE_NODE_ID (1) /* TPRE ID */ ++#define TXULP0_NODE_ID (2) /* TXULP0 ID */ ++#define TXULP1_NODE_ID (3) /* TXULP1 ID */ ++#define TXULP2_NODE_ID (4) /* TXULP2 ID */ ++#define RXULP0_NODE_ID (5) /* RXULP0 ID */ ++#define RXULP1_NODE_ID (6) /* RXULP1 ID */ ++#define RXULP2_NODE_ID (7) /* RXULP2 ID */ ++#define MPU_NODE_ID (15) /* MPU ID */ ++ ++/* ++ * --- MAC_ID_ENUM --- ++ * Meaning of the mac_id field in rxpp_eth_d ++ */ ++#define PORT0_HOST_MAC0 (0) /* PD 0, Port 0, host networking, MAC 0. */ ++#define PORT0_HOST_MAC1 (1) /* PD 0, Port 0, host networking, MAC 1. */ ++#define PORT0_STORAGE_MAC0 (2) /* PD 0, Port 0, host storage, MAC 0. */ ++#define PORT0_STORAGE_MAC1 (3) /* PD 0, Port 0, host storage, MAC 1. */ ++#define PORT1_HOST_MAC0 (4) /* PD 0, Port 1 host networking, MAC 0. */ ++#define PORT1_HOST_MAC1 (5) /* PD 0, Port 1 host networking, MAC 1. */ ++#define PORT1_STORAGE_MAC0 (6) /* PD 0, Port 1 host storage, MAC 0. */ ++#define PORT1_STORAGE_MAC1 (7) /* PD 0, Port 1 host storage, MAC 1. */ ++#define FIRST_VM_MAC (8) /* PD 1 MAC. Protection domains have IDs */ ++ /* from 0x8-0x26, one per PD. */ ++#define LAST_VM_MAC (38) /* PD 31 MAC. */ ++#define MGMT_MAC (39) /* Management port MAC. */ ++#define MARBLE_MAC0 (59) /* Used for flushing function 0 receive */ ++ /* ++ * queues before re-using a torn-down ++ * receive ring. the DA = ++ * 00-00-00-00-00-00, and the MSB of the ++ * SA = 00 ++ */ ++#define MARBLE_MAC1 (60) /* Used for flushing function 1 receive */ ++ /* ++ * queues before re-using a torn-down ++ * receive ring. the DA = ++ * 00-00-00-00-00-00, and the MSB of the ++ * SA != 00 ++ */ ++#define NULL_MAC (61) /* Promiscuous mode, indicates no match */ ++#define MCAST_MAC (62) /* Multicast match. */ ++#define BCAST_MATCH (63) /* Broadcast match. */ ++ ++#endif /* __descriptors_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/doorbells.h +@@ -0,0 +1,179 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __doorbells_amap_h__ ++#define __doorbells_amap_h__ ++ ++/* The TX/RDMA send queue doorbell. */ ++struct BE_SQ_DB_AMAP { ++ u8 cid[11]; /* DWORD 0 */ ++ u8 rsvd0[5]; /* DWORD 0 */ ++ u8 numPosted[14]; /* DWORD 0 */ ++ u8 rsvd1[2]; /* DWORD 0 */ ++} __packed; ++struct SQ_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* The receive queue doorbell. */ ++struct BE_RQ_DB_AMAP { ++ u8 rq[10]; /* DWORD 0 */ ++ u8 rsvd0[13]; /* DWORD 0 */ ++ u8 Invalidate; /* DWORD 0 */ ++ u8 numPosted[8]; /* DWORD 0 */ ++} __packed; ++struct RQ_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * The CQ/EQ doorbell. Software MUST set reserved fields in this ++ * descriptor to zero, otherwise (CEV) hardware will not execute the ++ * doorbell (flagging a bad_db_qid error instead). ++ */ ++struct BE_CQ_DB_AMAP { ++ u8 qid[10]; /* DWORD 0 */ ++ u8 rsvd0[4]; /* DWORD 0 */ ++ u8 rearm; /* DWORD 0 */ ++ u8 event; /* DWORD 0 */ ++ u8 num_popped[13]; /* DWORD 0 */ ++ u8 rsvd1[3]; /* DWORD 0 */ ++} __packed; ++struct CQ_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_TPM_RQ_DB_AMAP { ++ u8 qid[10]; /* DWORD 0 */ ++ u8 rsvd0[6]; /* DWORD 0 */ ++ u8 numPosted[11]; /* DWORD 0 */ ++ u8 mss_cnt[5]; /* DWORD 0 */ ++} __packed; ++struct TPM_RQ_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * Post WRB Queue Doorbell Register used by the host Storage stack ++ * to notify the controller of a posted Work Request Block ++ */ ++struct BE_WRB_POST_DB_AMAP { ++ u8 wrb_cid[10]; /* DWORD 0 */ ++ u8 rsvd0[6]; /* DWORD 0 */ ++ u8 wrb_index[8]; /* DWORD 0 */ ++ u8 numberPosted[8]; /* DWORD 0 */ ++} __packed; ++struct WRB_POST_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * Update Default PDU Queue Doorbell Register used to communicate ++ * to the controller that the driver has stopped processing the queue ++ * and where in the queue it stopped, this is ++ * a CQ Entry Type. Used by storage driver. ++ */ ++struct BE_DEFAULT_PDU_DB_AMAP { ++ u8 qid[10]; /* DWORD 0 */ ++ u8 rsvd0[4]; /* DWORD 0 */ ++ u8 rearm; /* DWORD 0 */ ++ u8 event; /* DWORD 0 */ ++ u8 cqproc[14]; /* DWORD 0 */ ++ u8 rsvd1[2]; /* DWORD 0 */ ++} __packed; ++struct DEFAULT_PDU_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Management Command and Controller default fragment ring */ ++struct BE_MCC_DB_AMAP { ++ u8 rid[11]; /* DWORD 0 */ ++ u8 rsvd0[5]; /* DWORD 0 */ ++ u8 numPosted[14]; /* DWORD 0 */ ++ u8 rsvd1[2]; /* DWORD 0 */ ++} __packed; ++struct MCC_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * Used for bootstrapping the Host interface. This register is ++ * used for driver communication with the MPU when no MCC Rings exist. ++ * The software must write this register twice to post any MCC ++ * command. First, it writes the register with hi=1 and the upper bits of ++ * the physical address for the MCC_MAILBOX structure. Software must poll ++ * the ready bit until this is acknowledged. Then, sotware writes the ++ * register with hi=0 with the lower bits in the address. It must ++ * poll the ready bit until the MCC command is complete. Upon completion, ++ * the MCC_MAILBOX will contain a valid completion queue entry. ++ */ ++struct BE_MPU_MAILBOX_DB_AMAP { ++ u8 ready; /* DWORD 0 */ ++ u8 hi; /* DWORD 0 */ ++ u8 address[30]; /* DWORD 0 */ ++} __packed; ++struct MPU_MAILBOX_DB_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * This is the protection domain doorbell register map. Note that ++ * while this map shows doorbells for all Blade Engine supported ++ * protocols, not all of these may be valid in a given function or ++ * protection domain. It is the responsibility of the application ++ * accessing the doorbells to know which are valid. Each doorbell ++ * occupies 32 bytes of space, but unless otherwise specified, ++ * only the first 4 bytes should be written. There are 32 instances ++ * of these doorbells for the host and 31 virtual machines respectively. ++ * The host and VMs will only map the doorbell pages belonging to its ++ * protection domain. It will not be able to touch the doorbells for ++ * another VM. The doorbells are the only registers directly accessible ++ * by a virtual machine. Similarly, there are 511 additional ++ * doorbells for RDMA protection domains. PD 0 for RDMA shares ++ * the same physical protection domain doorbell page as ETH/iSCSI. ++ * ++ */ ++struct BE_PROTECTION_DOMAIN_DBMAP_AMAP { ++ u8 rsvd0[512]; /* DWORD 0 */ ++ struct BE_SQ_DB_AMAP rdma_sq_db; ++ u8 rsvd1[7][32]; /* DWORD 17 */ ++ struct BE_WRB_POST_DB_AMAP iscsi_wrb_post_db; ++ u8 rsvd2[7][32]; /* DWORD 25 */ ++ struct BE_SQ_DB_AMAP etx_sq_db; ++ u8 rsvd3[7][32]; /* DWORD 33 */ ++ struct BE_RQ_DB_AMAP rdma_rq_db; ++ u8 rsvd4[7][32]; /* DWORD 41 */ ++ struct BE_DEFAULT_PDU_DB_AMAP iscsi_default_pdu_db; ++ u8 rsvd5[7][32]; /* DWORD 49 */ ++ struct BE_TPM_RQ_DB_AMAP tpm_rq_db; ++ u8 rsvd6[7][32]; /* DWORD 57 */ ++ struct BE_RQ_DB_AMAP erx_rq_db; ++ u8 rsvd7[7][32]; /* DWORD 65 */ ++ struct BE_CQ_DB_AMAP cq_db; ++ u8 rsvd8[7][32]; /* DWORD 73 */ ++ struct BE_MCC_DB_AMAP mpu_mcc_db; ++ u8 rsvd9[7][32]; /* DWORD 81 */ ++ struct BE_MPU_MAILBOX_DB_AMAP mcc_bootstrap_db; ++ u8 rsvd10[935][32]; /* DWORD 89 */ ++} __packed; ++struct PROTECTION_DOMAIN_DBMAP_AMAP { ++ u32 dw[1024]; ++}; ++ ++#endif /* __doorbells_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/ep.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __ep_amap_h__ ++#define __ep_amap_h__ ++ ++/* General Control and Status Register. */ ++struct BE_EP_CONTROL_CSR_AMAP { ++ u8 m0_RxPbuf; /* DWORD 0 */ ++ u8 m1_RxPbuf; /* DWORD 0 */ ++ u8 m2_RxPbuf; /* DWORD 0 */ ++ u8 ff_en; /* DWORD 0 */ ++ u8 rsvd0[27]; /* DWORD 0 */ ++ u8 CPU_reset; /* DWORD 0 */ ++} __packed; ++struct EP_CONTROL_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Semaphore Register. */ ++struct BE_EP_SEMAPHORE_CSR_AMAP { ++ u8 value[32]; /* DWORD 0 */ ++} __packed; ++struct EP_SEMAPHORE_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Embedded Processor Specific Registers. */ ++struct BE_EP_CSRMAP_AMAP { ++ struct BE_EP_CONTROL_CSR_AMAP ep_control; ++ u8 rsvd0[32]; /* DWORD 1 */ ++ u8 rsvd1[32]; /* DWORD 2 */ ++ u8 rsvd2[32]; /* DWORD 3 */ ++ u8 rsvd3[32]; /* DWORD 4 */ ++ u8 rsvd4[32]; /* DWORD 5 */ ++ u8 rsvd5[8][128]; /* DWORD 6 */ ++ u8 rsvd6[32]; /* DWORD 38 */ ++ u8 rsvd7[32]; /* DWORD 39 */ ++ u8 rsvd8[32]; /* DWORD 40 */ ++ u8 rsvd9[32]; /* DWORD 41 */ ++ u8 rsvd10[32]; /* DWORD 42 */ ++ struct BE_EP_SEMAPHORE_CSR_AMAP ep_semaphore; ++ u8 rsvd11[32]; /* DWORD 44 */ ++ u8 rsvd12[19][32]; /* DWORD 45 */ ++} __packed; ++struct EP_CSRMAP_AMAP { ++ u32 dw[64]; ++}; ++ ++#endif /* __ep_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/eq.c +@@ -0,0 +1,299 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include "hwlib.h" ++#include "bestatus.h" ++/* ++ This routine creates an event queue based on the client completion ++ queue configuration information. ++ ++ FunctionObject - Handle to a function object ++ EqBaseVa - Base VA for a the EQ ring ++ SizeEncoding - The encoded size for the EQ entries. This value is ++ either CEV_EQ_SIZE_4 or CEV_EQ_SIZE_16 ++ NumEntries - CEV_CQ_CNT_* values. ++ Watermark - Enables watermark based coalescing. This parameter ++ must be of the type CEV_WMARK_* if watermarks ++ are enabled. If watermarks to to be disabled ++ this value should be-1. ++ TimerDelay - If a timer delay is enabled this value should be the ++ time of the delay in 8 microsecond units. If ++ delays are not used this parameter should be ++ set to -1. ++ ppEqObject - Internal EQ Handle returned. ++ ++ Returns BE_SUCCESS if successfull,, otherwise a useful error code ++ is returned. ++ ++ IRQL < DISPATCH_LEVEL ++*/ ++int ++be_eq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 eqe_size, u32 num_entries, ++ u32 watermark, /* CEV_WMARK_* or -1 */ ++ u32 timer_delay, /* in 8us units, or -1 */ ++ struct be_eq_object *eq_object) ++{ ++ int status = BE_SUCCESS; ++ u32 num_entries_encoding, eqe_size_encoding, length; ++ struct FWCMD_COMMON_EQ_CREATE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ u32 n; ++ unsigned long irql; ++ ++ ASSERT(rd); ++ ASSERT(eq_object); ++ ++ switch (num_entries) { ++ case 256: ++ num_entries_encoding = CEV_EQ_CNT_256; ++ break; ++ case 512: ++ num_entries_encoding = CEV_EQ_CNT_512; ++ break; ++ case 1024: ++ num_entries_encoding = CEV_EQ_CNT_1024; ++ break; ++ case 2048: ++ num_entries_encoding = CEV_EQ_CNT_2048; ++ break; ++ case 4096: ++ num_entries_encoding = CEV_EQ_CNT_4096; ++ break; ++ default: ++ ASSERT(0); ++ return BE_STATUS_INVALID_PARAMETER; ++ } ++ ++ switch (eqe_size) { ++ case 4: ++ eqe_size_encoding = CEV_EQ_SIZE_4; ++ break; ++ case 16: ++ eqe_size_encoding = CEV_EQ_SIZE_16; ++ break; ++ default: ++ ASSERT(0); ++ return BE_STATUS_INVALID_PARAMETER; ++ } ++ ++ if ((eqe_size == 4 && num_entries < 1024) || ++ (eqe_size == 16 && num_entries == 4096)) { ++ TRACE(DL_ERR, "Bad EQ size. eqe_size:%d num_entries:%d", ++ eqe_size, num_entries); ++ ASSERT(0); ++ return BE_STATUS_INVALID_PARAMETER; ++ } ++ ++ memset(eq_object, 0, sizeof(*eq_object)); ++ ++ atomic_set(&eq_object->ref_count, 0); ++ eq_object->parent_function = pfob; ++ eq_object->eq_id = 0xFFFFFFFF; ++ ++ INIT_LIST_HEAD(&eq_object->cq_list_head); ++ ++ length = num_entries * eqe_size; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ ASSERT(wrb); ++ TRACE(DL_ERR, "No free MCC WRBs in create EQ."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_EQ_CREATE); ++ ++ fwcmd->params.request.num_pages = PAGES_SPANNED(OFFSET_IN_PAGE(rd->va), ++ length); ++ n = pfob->pci_function_number; ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, Func, &fwcmd->params.request.context, n); ++ ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, valid, &fwcmd->params.request.context, 1); ++ ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, Size, ++ &fwcmd->params.request.context, eqe_size_encoding); ++ ++ n = 0; /* Protection Domain is always 0 in Linux driver */ ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, PD, &fwcmd->params.request.context, n); ++ ++ /* Let the caller ARM the EQ with the doorbell. */ ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, Armed, &fwcmd->params.request.context, 0); ++ ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, Count, &fwcmd->params.request.context, ++ num_entries_encoding); ++ ++ n = pfob->pci_function_number * 32; ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, EventVect, ++ &fwcmd->params.request.context, n); ++ if (watermark != -1) { ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, WME, ++ &fwcmd->params.request.context, 1); ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, Watermark, ++ &fwcmd->params.request.context, watermark); ++ ASSERT(watermark <= CEV_WMARK_240); ++ } else ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, WME, ++ &fwcmd->params.request.context, 0); ++ if (timer_delay != -1) { ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, TMR, ++ &fwcmd->params.request.context, 1); ++ ++ ASSERT(timer_delay <= 250); /* max value according to EAS */ ++ timer_delay = min(timer_delay, (u32)250); ++ ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, Delay, ++ &fwcmd->params.request.context, timer_delay); ++ } else { ++ AMAP_SET_BITS_PTR(EQ_CONTEXT, TMR, ++ &fwcmd->params.request.context, 0); ++ } ++ /* Create a page list for the FWCMD. */ ++ be_rd_to_pa_list(rd, fwcmd->params.request.pages, ++ ARRAY_SIZE(fwcmd->params.request.pages)); ++ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "MCC to create EQ failed."); ++ goto Error; ++ } ++ /* Get the EQ id. The MPU allocates the IDs. */ ++ eq_object->eq_id = fwcmd->params.response.eq_id; ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ Deferences the given object. Once the object's reference count drops to ++ zero, the object is destroyed and all resources that are held by this ++ object are released. The on-chip context is also destroyed along with ++ the queue ID, and any mappings made into the UT. ++ ++ eq_object - EQ handle returned from eq_object_create. ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful error code ++ is returned. ++ ++ IRQL: IRQL < DISPATCH_LEVEL ++*/ ++int be_eq_destroy(struct be_eq_object *eq_object) ++{ ++ int status = 0; ++ ++ ASSERT(atomic_read(&eq_object->ref_count) == 0); ++ /* no CQs should reference this EQ now */ ++ ASSERT(list_empty(&eq_object->cq_list_head)); ++ ++ /* Send fwcmd to destroy the EQ. */ ++ status = be_function_ring_destroy(eq_object->parent_function, ++ eq_object->eq_id, FWCMD_RING_TYPE_EQ, ++ NULL, NULL, NULL, NULL); ++ ASSERT(status == 0); ++ ++ return BE_SUCCESS; ++} ++/* ++ *--------------------------------------------------------------------------- ++ * Function: be_eq_modify_delay ++ * Changes the EQ delay for a group of EQs. ++ * num_eq - The number of EQs in the eq_array to adjust. ++ * This also is the number of delay values in ++ * the eq_delay_array. ++ * eq_array - Array of struct be_eq_object pointers to adjust. ++ * eq_delay_array - Array of "num_eq" timer delays in units ++ * of microseconds. The be_eq_query_delay_range ++ * fwcmd returns the resolution and range of ++ * legal EQ delays. ++ * cb - ++ * cb_context - ++ * q_ctxt - Optional. Pointer to a previously allocated ++ * struct. If the MCC WRB ring is full, this ++ * structure is used to queue the operation. It ++ * will be posted to the MCC ring when space ++ * becomes available. All queued commands will ++ * be posted to the ring in the order they are ++ * received. It is always valid to pass a pointer to ++ * a generic be_generic_q_cntxt. However, ++ * the specific context structs ++ * are generally smaller than the generic struct. ++ * return pend_status - BE_SUCCESS (0) on success. ++ * BE_PENDING (postive value) if the FWCMD ++ * completion is pending. Negative error code on failure. ++ *------------------------------------------------------------------------- ++ */ ++int ++be_eq_modify_delay(struct be_function_object *pfob, ++ u32 num_eq, struct be_eq_object **eq_array, ++ u32 *eq_delay_array, mcc_wrb_cqe_callback cb, ++ void *cb_context, struct be_eq_modify_delay_q_ctxt *q_ctxt) ++{ ++ struct FWCMD_COMMON_MODIFY_EQ_DELAY *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ struct be_generic_q_ctxt *gen_ctxt = NULL; ++ u32 i; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ gen_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ gen_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_MODIFY_EQ_DELAY); ++ ++ ASSERT(num_eq > 0); ++ ASSERT(num_eq <= ARRAY_SIZE(fwcmd->params.request.delay)); ++ fwcmd->params.request.num_eq = num_eq; ++ for (i = 0; i < num_eq; i++) { ++ fwcmd->params.request.delay[i].eq_id = eq_array[i]->eq_id; ++ fwcmd->params.request.delay[i].delay_in_microseconds = ++ eq_delay_array[i]; ++ } ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, gen_ctxt, ++ cb, cb_context, NULL, NULL, fwcmd, NULL); ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ +--- /dev/null ++++ b/drivers/staging/benet/eth.c +@@ -0,0 +1,1273 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include ++#include "hwlib.h" ++#include "bestatus.h" ++ ++/* ++ *--------------------------------------------------------- ++ * Function: be_eth_sq_create_ex ++ * Creates an ethernet send ring - extended version with ++ * additional parameters. ++ * pfob - ++ * rd - ring address ++ * length_in_bytes - ++ * type - The type of ring to create. ++ * ulp - The requested ULP number for the ring. ++ * This should be zero based, i.e. 0,1,2. This must ++ * be valid NIC ULP based on the firmware config. ++ * All doorbells for this ring must be sent to ++ * this ULP. The first network ring allocated for ++ * each ULP are higher performance than subsequent rings. ++ * cq_object - cq object for completions ++ * ex_parameters - Additional parameters (that may increase in ++ * future revisions). These parameters are only used ++ * for certain ring types -- see ++ * struct be_eth_sq_parameters for details. ++ * eth_sq - ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *--------------------------------------------------------- ++ */ ++int ++be_eth_sq_create_ex(struct be_function_object *pfob, struct ring_desc *rd, ++ u32 length, u32 type, u32 ulp, struct be_cq_object *cq_object, ++ struct be_eth_sq_parameters *ex_parameters, ++ struct be_ethsq_object *eth_sq) ++{ ++ struct FWCMD_COMMON_ETH_TX_CREATE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ u32 n; ++ unsigned long irql; ++ ++ ASSERT(rd); ++ ASSERT(eth_sq); ++ ASSERT(ex_parameters); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ memset(eth_sq, 0, sizeof(*eth_sq)); ++ ++ eth_sq->parent_function = pfob; ++ eth_sq->bid = 0xFFFFFFFF; ++ eth_sq->cq_object = cq_object; ++ ++ /* Translate hwlib interface to arm interface. */ ++ switch (type) { ++ case BE_ETH_TX_RING_TYPE_FORWARDING: ++ type = ETH_TX_RING_TYPE_FORWARDING; ++ break; ++ case BE_ETH_TX_RING_TYPE_STANDARD: ++ type = ETH_TX_RING_TYPE_STANDARD; ++ break; ++ case BE_ETH_TX_RING_TYPE_BOUND: ++ ASSERT(ex_parameters->port < 2); ++ type = ETH_TX_RING_TYPE_BOUND; ++ break; ++ default: ++ TRACE(DL_ERR, "Invalid eth tx ring type:%d", type); ++ return BE_NOT_OK; ++ break; ++ } ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ ASSERT(wrb); ++ TRACE(DL_ERR, "No free MCC WRBs in create EQ."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ /* NIC must be supported by the current config. */ ++ ASSERT(pfob->fw_config.nic_ulp_mask); ++ ++ /* ++ * The ulp parameter must select a valid NIC ULP ++ * for the current config. ++ */ ++ ASSERT((1 << ulp) & pfob->fw_config.nic_ulp_mask); ++ ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_TX_CREATE); ++ fwcmd->header.request.port_number = ex_parameters->port; ++ ++ AMAP_SET_BITS_PTR(ETX_CONTEXT, pd_id, ++ &fwcmd->params.request.context, 0); ++ ++ n = be_ring_length_to_encoding(length, sizeof(struct ETH_WRB_AMAP)); ++ AMAP_SET_BITS_PTR(ETX_CONTEXT, tx_ring_size, ++ &fwcmd->params.request.context, n); ++ ++ AMAP_SET_BITS_PTR(ETX_CONTEXT, cq_id_send, ++ &fwcmd->params.request.context, cq_object->cq_id); ++ ++ n = pfob->pci_function_number; ++ AMAP_SET_BITS_PTR(ETX_CONTEXT, func, &fwcmd->params.request.context, n); ++ ++ fwcmd->params.request.type = type; ++ fwcmd->params.request.ulp_num = (1 << ulp); ++ fwcmd->params.request.num_pages = DIV_ROUND_UP(length, PAGE_SIZE); ++ ASSERT(PAGES_SPANNED(rd->va, rd->length) >= ++ fwcmd->params.request.num_pages); ++ ++ /* Create a page list for the FWCMD. */ ++ be_rd_to_pa_list(rd, fwcmd->params.request.pages, ++ ARRAY_SIZE(fwcmd->params.request.pages)); ++ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "MCC to create etx queue failed."); ++ goto Error; ++ } ++ /* save the butler ID */ ++ eth_sq->bid = fwcmd->params.response.cid; ++ ++ /* add a reference to the corresponding CQ */ ++ atomic_inc(&cq_object->ref_count); ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++ ++/* ++ This routine destroys an ethernet send queue ++ ++ EthSq - EthSq Handle returned from EthSqCreate ++ ++ This function always return BE_SUCCESS. ++ ++ This function frees memory allocated by EthSqCreate for the EthSq Object. ++ ++*/ ++int be_eth_sq_destroy(struct be_ethsq_object *eth_sq) ++{ ++ int status = 0; ++ ++ /* Send fwcmd to destroy the queue. */ ++ status = be_function_ring_destroy(eth_sq->parent_function, eth_sq->bid, ++ FWCMD_RING_TYPE_ETH_TX, NULL, NULL, NULL, NULL); ++ ASSERT(status == 0); ++ ++ /* Derefence any associated CQs. */ ++ atomic_dec(ð_sq->cq_object->ref_count); ++ return status; ++} ++/* ++ This routine attempts to set the transmit flow control parameters. ++ ++ FunctionObject - Handle to a function object ++ ++ txfc_enable - transmit flow control enable - true for ++ enable, false for disable ++ ++ rxfc_enable - receive flow control enable - true for ++ enable, false for disable ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int error ++ code is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++ ++ This function always fails in non-privileged machine context. ++*/ ++int ++be_eth_set_flow_control(struct be_function_object *pfob, ++ bool txfc_enable, bool rxfc_enable) ++{ ++ struct FWCMD_COMMON_SET_FLOW_CONTROL *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FLOW_CONTROL); ++ ++ fwcmd->params.request.rx_flow_control = rxfc_enable; ++ fwcmd->params.request.tx_flow_control = txfc_enable; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) { ++ TRACE(DL_ERR, "set flow control fwcmd failed."); ++ goto error; ++ } ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine attempts to get the transmit flow control parameters. ++ ++ pfob - Handle to a function object ++ ++ txfc_enable - transmit flow control enable - true for ++ enable, false for disable ++ ++ rxfc_enable - receive flow control enable - true for enable, ++ false for disable ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int error code ++ is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++ ++ This function always fails in non-privileged machine context. ++*/ ++int ++be_eth_get_flow_control(struct be_function_object *pfob, ++ bool *txfc_enable, bool *rxfc_enable) ++{ ++ struct FWCMD_COMMON_GET_FLOW_CONTROL *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_FLOW_CONTROL); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) { ++ TRACE(DL_ERR, "get flow control fwcmd failed."); ++ goto error; ++ } ++ ++ *txfc_enable = fwcmd->params.response.tx_flow_control; ++ *rxfc_enable = fwcmd->params.response.rx_flow_control; ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ *--------------------------------------------------------- ++ * Function: be_eth_set_qos ++ * This function sets the ethernet transmit Quality of Service (QoS) ++ * characteristics of BladeEngine for the domain. All ethernet ++ * transmit rings of the domain will evenly share the bandwidth. ++ * The exeception to sharing is the host primary (super) ethernet ++ * transmit ring as well as the host ethernet forwarding ring ++ * for missed offload data. ++ * pfob - ++ * max_bps - the maximum bits per second in units of ++ * 10 Mbps (valid 0-100) ++ * max_pps - the maximum packets per second in units ++ * of 1 Kpps (0 indicates no limit) ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *--------------------------------------------------------- ++ */ ++int ++be_eth_set_qos(struct be_function_object *pfob, u32 max_bps, u32 max_pps) ++{ ++ struct FWCMD_COMMON_SET_QOS *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_QOS); ++ ++ /* Set fields in fwcmd */ ++ fwcmd->params.request.max_bits_per_second_NIC = max_bps; ++ fwcmd->params.request.max_packets_per_second_NIC = max_pps; ++ fwcmd->params.request.valid_flags = QOS_BITS_NIC | QOS_PKTS_NIC; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) ++ TRACE(DL_ERR, "network set qos fwcmd failed."); ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ *--------------------------------------------------------- ++ * Function: be_eth_get_qos ++ * This function retrieves the ethernet transmit Quality of Service (QoS) ++ * characteristics for the domain. ++ * max_bps - the maximum bits per second in units of ++ * 10 Mbps (valid 0-100) ++ * max_pps - the maximum packets per second in units of ++ * 1 Kpps (0 indicates no limit) ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *--------------------------------------------------------- ++ */ ++int ++be_eth_get_qos(struct be_function_object *pfob, u32 *max_bps, u32 *max_pps) ++{ ++ struct FWCMD_COMMON_GET_QOS *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_QOS); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) { ++ TRACE(DL_ERR, "network get qos fwcmd failed."); ++ goto error; ++ } ++ ++ *max_bps = fwcmd->params.response.max_bits_per_second_NIC; ++ *max_pps = fwcmd->params.response.max_packets_per_second_NIC; ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ *--------------------------------------------------------- ++ * Function: be_eth_set_frame_size ++ * This function sets the ethernet maximum frame size. The previous ++ * values are returned. ++ * pfob - ++ * tx_frame_size - maximum transmit frame size in bytes ++ * rx_frame_size - maximum receive frame size in bytes ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *--------------------------------------------------------- ++ */ ++int ++be_eth_set_frame_size(struct be_function_object *pfob, ++ u32 *tx_frame_size, u32 *rx_frame_size) ++{ ++ struct FWCMD_COMMON_SET_FRAME_SIZE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FRAME_SIZE); ++ fwcmd->params.request.max_tx_frame_size = *tx_frame_size; ++ fwcmd->params.request.max_rx_frame_size = *rx_frame_size; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) { ++ TRACE(DL_ERR, "network set frame size fwcmd failed."); ++ goto error; ++ } ++ ++ *tx_frame_size = fwcmd->params.response.chip_max_tx_frame_size; ++ *rx_frame_size = fwcmd->params.response.chip_max_rx_frame_size; ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++ ++/* ++ This routine creates a Ethernet receive ring. ++ ++ pfob - handle to a function object ++ rq_base_va - base VA for the default receive ring. this must be ++ exactly 8K in length and continguous physical memory. ++ cq_object - handle to a previously created CQ to be associated ++ with the RQ. ++ pp_eth_rq - pointer to an opqaue handle where an eth ++ receive object is returned. ++ Returns BE_SUCCESS if successfull, , otherwise a useful ++ int error code is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++ this function allocates a struct be_ethrq_object *object. ++ there must be no more than 1 of these per function object, unless the ++ function object supports RSS (is networking and on the host). ++ the rq_base_va must point to a buffer of exactly 8K. ++ the erx::host_cqid (or host_stor_cqid) register and erx::ring_page registers ++ will be updated as appropriate on return ++*/ ++int ++be_eth_rq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, struct be_cq_object *cq_object, ++ struct be_cq_object *bcmc_cq_object, ++ struct be_ethrq_object *eth_rq) ++{ ++ int status = 0; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ struct FWCMD_COMMON_ETH_RX_CREATE *fwcmd = NULL; ++ unsigned long irql; ++ ++ /* MPU will set the */ ++ ASSERT(rd); ++ ASSERT(eth_rq); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ eth_rq->parent_function = pfob; ++ eth_rq->cq_object = cq_object; ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_RX_CREATE); ++ ++ fwcmd->params.request.num_pages = 2; /* required length */ ++ fwcmd->params.request.cq_id = cq_object->cq_id; ++ ++ if (bcmc_cq_object) ++ fwcmd->params.request.bcmc_cq_id = bcmc_cq_object->cq_id; ++ else ++ fwcmd->params.request.bcmc_cq_id = 0xFFFF; ++ ++ /* Create a page list for the FWCMD. */ ++ be_rd_to_pa_list(rd, fwcmd->params.request.pages, ++ ARRAY_SIZE(fwcmd->params.request.pages)); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "fwcmd to map eth rxq frags failed."); ++ goto Error; ++ } ++ /* Save the ring ID for cleanup. */ ++ eth_rq->rid = fwcmd->params.response.id; ++ ++ atomic_inc(&cq_object->ref_count); ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine destroys an Ethernet receive queue ++ ++ eth_rq - ethernet receive queue handle returned from eth_rq_create ++ ++ Returns BE_SUCCESS on success and an appropriate int on failure. ++ ++ This function frees resourcs allocated by EthRqCreate. ++ The erx::host_cqid (or host_stor_cqid) register and erx::ring_page ++ registers will be updated as appropriate on return ++ IRQL: < DISPATCH_LEVEL ++*/ ++ ++static void be_eth_rq_destroy_internal_cb(void *context, int status, ++ struct MCC_WRB_AMAP *wrb) ++{ ++ struct be_ethrq_object *eth_rq = (struct be_ethrq_object *) context; ++ ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "Destroy eth rq failed in internal callback.\n"); ++ } else { ++ /* Dereference any CQs associated with this queue. */ ++ atomic_dec(ð_rq->cq_object->ref_count); ++ } ++ ++ return; ++} ++ ++int be_eth_rq_destroy(struct be_ethrq_object *eth_rq) ++{ ++ int status = BE_SUCCESS; ++ ++ /* Send fwcmd to destroy the RQ. */ ++ status = be_function_ring_destroy(eth_rq->parent_function, ++ eth_rq->rid, FWCMD_RING_TYPE_ETH_RX, NULL, NULL, ++ be_eth_rq_destroy_internal_cb, eth_rq); ++ ++ return status; ++} ++ ++/* ++ *--------------------------------------------------------------------------- ++ * Function: be_eth_rq_destroy_options ++ * Destroys an ethernet receive ring with finer granularity options ++ * than the standard be_eth_rq_destroy() API function. ++ * eth_rq - ++ * flush - Set to 1 to flush the ring, set to 0 to bypass the flush ++ * cb - Callback function on completion ++ * cb_context - Callback context ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *---------------------------------------------------------------------------- ++ */ ++int ++be_eth_rq_destroy_options(struct be_ethrq_object *eth_rq, bool flush, ++ mcc_wrb_cqe_callback cb, void *cb_context) ++{ ++ struct FWCMD_COMMON_RING_DESTROY *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = BE_SUCCESS; ++ struct be_function_object *pfob = NULL; ++ unsigned long irql; ++ ++ pfob = eth_rq->parent_function; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ TRACE(DL_INFO, "Destroy eth_rq ring id:%d, flush:%d", eth_rq->rid, ++ flush); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ ASSERT(wrb); ++ TRACE(DL_ERR, "No free MCC WRBs in destroy eth_rq ring."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_RING_DESTROY); ++ ++ fwcmd->params.request.id = eth_rq->rid; ++ fwcmd->params.request.ring_type = FWCMD_RING_TYPE_ETH_RX; ++ fwcmd->params.request.bypass_flush = ((0 == flush) ? 1 : 0); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, cb_context, ++ be_eth_rq_destroy_internal_cb, eth_rq, fwcmd, NULL); ++ ++ if (status != BE_SUCCESS && status != BE_PENDING) { ++ TRACE(DL_ERR, "eth_rq ring destroy failed. id:%d, flush:%d", ++ eth_rq->rid, flush); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine queries the frag size for erx. ++ ++ pfob - handle to a function object ++ ++ frag_size_bytes - erx frag size in bytes that is/was set. ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int error ++ code is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++ ++*/ ++int ++be_eth_rq_get_frag_size(struct be_function_object *pfob, u32 *frag_size_bytes) ++{ ++ struct FWCMD_ETH_GET_RX_FRAG_SIZE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ ASSERT(frag_size_bytes); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ return BE_STATUS_NO_MCC_WRB; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_GET_RX_FRAG_SIZE); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) { ++ TRACE(DL_ERR, "get frag size fwcmd failed."); ++ goto error; ++ } ++ ++ *frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2; ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine attempts to set the frag size for erx. If the frag size is ++ already set, the attempt fails and the current frag size is returned. ++ ++ pfob - Handle to a function object ++ ++ frag_size - Erx frag size in bytes that is/was set. ++ ++ current_frag_size_bytes - Pointer to location where currrent frag ++ is to be rturned ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int error ++ code is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++ ++ This function always fails in non-privileged machine context. ++*/ ++int ++be_eth_rq_set_frag_size(struct be_function_object *pfob, ++ u32 frag_size, u32 *frag_size_bytes) ++{ ++ struct FWCMD_ETH_SET_RX_FRAG_SIZE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ ASSERT(frag_size_bytes); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_SET_RX_FRAG_SIZE); ++ ++ ASSERT(frag_size >= 128 && frag_size <= 16 * 1024); ++ ++ /* This is the log2 of the fragsize. This is not the exact ++ * ERX encoding. */ ++ fwcmd->params.request.new_fragsize_log2 = __ilog2_u32(frag_size); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ ++ if (status != 0) { ++ TRACE(DL_ERR, "set frag size fwcmd failed."); ++ goto error; ++ } ++ ++ *frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2; ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++ ++/* ++ This routine gets or sets a mac address for a domain ++ given the port and mac. ++ ++ FunctionObject - Function object handle. ++ port1 - Set to TRUE if this function will set/get the Port 1 ++ address. Only the host may set this to TRUE. ++ mac1 - Set to TRUE if this function will set/get the ++ MAC 1 address. Only the host may set this to TRUE. ++ write - Set to TRUE if this function should write the mac address. ++ mac_address - Buffer of the mac address to read or write. ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++*/ ++int be_rxf_mac_address_read_write(struct be_function_object *pfob, ++ bool port1, /* VM must always set to false */ ++ bool mac1, /* VM must always set to false */ ++ bool mgmt, bool write, ++ bool permanent, u8 *mac_address, ++ mcc_wrb_cqe_callback cb, /* optional */ ++ void *cb_context) /* optional */ ++{ ++ int status = BE_SUCCESS; ++ union { ++ struct FWCMD_COMMON_NTWK_MAC_QUERY *query; ++ struct FWCMD_COMMON_NTWK_MAC_SET *set; ++ } fwcmd = {NULL}; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ u32 type = 0; ++ unsigned long irql; ++ struct be_mcc_wrb_response_copy rc; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ ASSERT(mac_address); ++ ++ ASSERT(port1 == false); ++ ASSERT(mac1 == false); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ ++ if (mgmt) { ++ type = MAC_ADDRESS_TYPE_MANAGEMENT; ++ } else { ++ if (pfob->type == BE_FUNCTION_TYPE_NETWORK) ++ type = MAC_ADDRESS_TYPE_NETWORK; ++ else ++ type = MAC_ADDRESS_TYPE_STORAGE; ++ } ++ ++ if (write) { ++ /* Prepares an embedded fwcmd, including ++ * request/response sizes. ++ */ ++ fwcmd.set = BE_PREPARE_EMBEDDED_FWCMD(pfob, ++ wrb, COMMON_NTWK_MAC_SET); ++ ++ fwcmd.set->params.request.invalidate = 0; ++ fwcmd.set->params.request.mac1 = (mac1 ? 1 : 0); ++ fwcmd.set->params.request.port = (port1 ? 1 : 0); ++ fwcmd.set->params.request.type = type; ++ ++ /* Copy the mac address to set. */ ++ fwcmd.set->params.request.mac.SizeOfStructure = ++ sizeof(fwcmd.set->params.request.mac); ++ memcpy(fwcmd.set->params.request.mac.MACAddress, ++ mac_address, ETH_ALEN); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, ++ cb, cb_context, NULL, NULL, fwcmd.set, NULL); ++ ++ } else { ++ ++ /* ++ * Prepares an embedded fwcmd, including ++ * request/response sizes. ++ */ ++ fwcmd.query = BE_PREPARE_EMBEDDED_FWCMD(pfob, ++ wrb, COMMON_NTWK_MAC_QUERY); ++ ++ fwcmd.query->params.request.mac1 = (mac1 ? 1 : 0); ++ fwcmd.query->params.request.port = (port1 ? 1 : 0); ++ fwcmd.query->params.request.type = type; ++ fwcmd.query->params.request.permanent = permanent; ++ ++ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_MAC_QUERY, ++ params.response.mac.MACAddress); ++ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_MAC_QUERY, ++ params.response.mac.MACAddress); ++ rc.va = mac_address; ++ /* Post the f/w command (with a copy for the response) */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, ++ cb_context, NULL, NULL, fwcmd.query, &rc); ++ } ++ ++ if (status < 0) { ++ TRACE(DL_ERR, "mac set/query failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine writes data to context memory. ++ ++ pfob - Function object handle. ++ mac_table - Set to the 128-bit multicast address hash table. ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++*/ ++ ++int be_rxf_multicast_config(struct be_function_object *pfob, ++ bool promiscuous, u32 num, u8 *mac_table, ++ mcc_wrb_cqe_callback cb, /* optional */ ++ void *cb_context, ++ struct be_multicast_q_ctxt *q_ctxt) ++{ ++ int status = BE_SUCCESS; ++ struct FWCMD_COMMON_NTWK_MULTICAST_SET *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ struct be_generic_q_ctxt *generic_ctxt = NULL; ++ unsigned long irql; ++ ++ ASSERT(num <= ARRAY_SIZE(fwcmd->params.request.mac)); ++ ++ if (num > ARRAY_SIZE(fwcmd->params.request.mac)) { ++ TRACE(DL_ERR, "Too many multicast addresses. BE supports %d.", ++ (int) ARRAY_SIZE(fwcmd->params.request.mac)); ++ return BE_NOT_OK; ++ } ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ generic_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_MULTICAST_SET); ++ ++ fwcmd->params.request.promiscuous = promiscuous; ++ if (!promiscuous) { ++ fwcmd->params.request.num_mac = num; ++ if (num > 0) { ++ ASSERT(mac_table); ++ memcpy(fwcmd->params.request.mac, ++ mac_table, ETH_ALEN * num); ++ } ++ } ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt, ++ cb, cb_context, NULL, NULL, fwcmd, NULL); ++ if (status < 0) { ++ TRACE(DL_ERR, "multicast fwcmd failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine adds or removes a vlan tag from the rxf table. ++ ++ FunctionObject - Function object handle. ++ VLanTag - VLan tag to add or remove. ++ Add - Set to TRUE if this will add a vlan tag ++ ++ Returns BE_SUCCESS if successfull, otherwise a useful int is returned. ++ ++ IRQL: < DISPATCH_LEVEL ++*/ ++int be_rxf_vlan_config(struct be_function_object *pfob, ++ bool promiscuous, u32 num, u16 *vlan_tag_array, ++ mcc_wrb_cqe_callback cb, /* optional */ ++ void *cb_context, ++ struct be_vlan_q_ctxt *q_ctxt) /* optional */ ++{ ++ int status = BE_SUCCESS; ++ struct FWCMD_COMMON_NTWK_VLAN_CONFIG *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ struct be_generic_q_ctxt *generic_ctxt = NULL; ++ unsigned long irql; ++ ++ if (num > ARRAY_SIZE(fwcmd->params.request.vlan_tag)) { ++ TRACE(DL_ERR, "Too many VLAN tags."); ++ return BE_NOT_OK; ++ } ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ generic_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_VLAN_CONFIG); ++ ++ fwcmd->params.request.promiscuous = promiscuous; ++ if (!promiscuous) { ++ fwcmd->params.request.num_vlan = num; ++ ++ if (num > 0) { ++ ASSERT(vlan_tag_array); ++ memcpy(fwcmd->params.request.vlan_tag, vlan_tag_array, ++ num * sizeof(vlan_tag_array[0])); ++ } ++ } ++ ++ /* Post the commadn */ ++ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt, ++ cb, cb_context, NULL, NULL, fwcmd, NULL); ++ if (status < 0) { ++ TRACE(DL_ERR, "vlan fwcmd failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++ ++int be_rxf_link_status(struct be_function_object *pfob, ++ struct BE_LINK_STATUS *link_status, ++ mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_link_status_q_ctxt *q_ctxt) ++{ ++ struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ struct be_generic_q_ctxt *generic_ctxt = NULL; ++ unsigned long irql; ++ struct be_mcc_wrb_response_copy rc; ++ ++ ASSERT(link_status); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ generic_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ++ COMMON_NTWK_LINK_STATUS_QUERY); ++ ++ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY, ++ params.response); ++ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY, ++ params.response); ++ rc.va = link_status; ++ /* Post or queue the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt, ++ cb, cb_context, NULL, NULL, fwcmd, &rc); ++ ++ if (status < 0) { ++ TRACE(DL_ERR, "link status fwcmd failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++int ++be_rxf_query_eth_statistics(struct be_function_object *pfob, ++ struct FWCMD_ETH_GET_STATISTICS *va_for_fwcmd, ++ u64 pa_for_fwcmd, mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_nonembedded_q_ctxt *q_ctxt) ++{ ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ struct be_generic_q_ctxt *generic_ctxt = NULL; ++ unsigned long irql; ++ ++ ASSERT(va_for_fwcmd); ++ ASSERT(pa_for_fwcmd); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ generic_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ ++ TRACE(DL_INFO, "Query eth stats. fwcmd va:%p pa:0x%08x_%08x", ++ va_for_fwcmd, upper_32_bits(pa_for_fwcmd), (u32)pa_for_fwcmd); ++ ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ va_for_fwcmd = BE_PREPARE_NONEMBEDDED_FWCMD(pfob, wrb, ++ va_for_fwcmd, pa_for_fwcmd, ETH_GET_STATISTICS); ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt, ++ cb, cb_context, NULL, NULL, va_for_fwcmd, NULL); ++ if (status < 0) { ++ TRACE(DL_ERR, "eth stats fwcmd failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++int ++be_rxf_promiscuous(struct be_function_object *pfob, ++ bool enable_port0, bool enable_port1, ++ mcc_wrb_cqe_callback cb, void *cb_context, ++ struct be_promiscuous_q_ctxt *q_ctxt) ++{ ++ struct FWCMD_ETH_PROMISCUOUS *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ struct be_generic_q_ctxt *generic_ctxt = NULL; ++ unsigned long irql; ++ ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ generic_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_PROMISCUOUS); ++ ++ fwcmd->params.request.port0_promiscuous = enable_port0; ++ fwcmd->params.request.port1_promiscuous = enable_port1; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt, ++ cb, cb_context, NULL, NULL, fwcmd, NULL); ++ ++ if (status < 0) { ++ TRACE(DL_ERR, "promiscuous fwcmd failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++ ++/* ++ *------------------------------------------------------------------------- ++ * Function: be_rxf_filter_config ++ * Configures BladeEngine ethernet receive filter settings. ++ * pfob - ++ * settings - Pointer to the requested filter settings. ++ * The response from BladeEngine will be placed back ++ * in this structure. ++ * cb - optional ++ * cb_context - optional ++ * q_ctxt - Optional. Pointer to a previously allocated struct. ++ * If the MCC WRB ring is full, this structure is ++ * used to queue the operation. It will be posted ++ * to the MCC ring when space becomes available. All ++ * queued commands will be posted to the ring in ++ * the order they are received. It is always valid ++ * to pass a pointer to a generic ++ * be_generic_q_ctxt. However, the specific ++ * context structs are generally smaller than ++ * the generic struct. ++ * return pend_status - BE_SUCCESS (0) on success. ++ * BE_PENDING (postive value) if the FWCMD ++ * completion is pending. Negative error code on failure. ++ *--------------------------------------------------------------------------- ++ */ ++int ++be_rxf_filter_config(struct be_function_object *pfob, ++ struct NTWK_RX_FILTER_SETTINGS *settings, ++ mcc_wrb_cqe_callback cb, void *cb_context, ++ struct be_rxf_filter_q_ctxt *q_ctxt) ++{ ++ struct FWCMD_COMMON_NTWK_RX_FILTER *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ struct be_generic_q_ctxt *generic_ctxt = NULL; ++ unsigned long irql; ++ struct be_mcc_wrb_response_copy rc; ++ ++ ASSERT(settings); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ ++ if (!wrb) { ++ if (q_ctxt && cb) { ++ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt; ++ generic_ctxt->context.bytes = sizeof(*q_ctxt); ++ } else { ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_RX_FILTER); ++ memcpy(&fwcmd->params.request, settings, sizeof(*settings)); ++ ++ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_RX_FILTER, ++ params.response); ++ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_RX_FILTER, ++ params.response); ++ rc.va = settings; ++ /* Post or queue the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt, ++ cb, cb_context, NULL, NULL, fwcmd, &rc); ++ ++ if (status < 0) { ++ TRACE(DL_ERR, "RXF/ERX filter config fwcmd failed."); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} +--- /dev/null ++++ b/drivers/staging/benet/etx_context.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __etx_context_amap_h__ ++#define __etx_context_amap_h__ ++ ++/* ETX ring context structure. */ ++struct BE_ETX_CONTEXT_AMAP { ++ u8 tx_cidx[11]; /* DWORD 0 */ ++ u8 rsvd0[5]; /* DWORD 0 */ ++ u8 rsvd1[16]; /* DWORD 0 */ ++ u8 tx_pidx[11]; /* DWORD 1 */ ++ u8 rsvd2; /* DWORD 1 */ ++ u8 tx_ring_size[4]; /* DWORD 1 */ ++ u8 pd_id[5]; /* DWORD 1 */ ++ u8 pd_id_not_valid; /* DWORD 1 */ ++ u8 cq_id_send[10]; /* DWORD 1 */ ++ u8 rsvd3[32]; /* DWORD 2 */ ++ u8 rsvd4[32]; /* DWORD 3 */ ++ u8 cur_bytes[32]; /* DWORD 4 */ ++ u8 max_bytes[32]; /* DWORD 5 */ ++ u8 time_stamp[32]; /* DWORD 6 */ ++ u8 rsvd5[11]; /* DWORD 7 */ ++ u8 func; /* DWORD 7 */ ++ u8 rsvd6[20]; /* DWORD 7 */ ++ u8 cur_txd_count[32]; /* DWORD 8 */ ++ u8 max_txd_count[32]; /* DWORD 9 */ ++ u8 rsvd7[32]; /* DWORD 10 */ ++ u8 rsvd8[32]; /* DWORD 11 */ ++ u8 rsvd9[32]; /* DWORD 12 */ ++ u8 rsvd10[32]; /* DWORD 13 */ ++ u8 rsvd11[32]; /* DWORD 14 */ ++ u8 rsvd12[32]; /* DWORD 15 */ ++} __packed; ++struct ETX_CONTEXT_AMAP { ++ u32 dw[16]; ++}; ++ ++#endif /* __etx_context_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/funcobj.c +@@ -0,0 +1,565 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include "hwlib.h" ++#include "bestatus.h" ++ ++ ++int ++be_function_internal_query_firmware_config(struct be_function_object *pfob, ++ struct BE_FIRMWARE_CONFIG *config) ++{ ++ struct FWCMD_COMMON_FIRMWARE_CONFIG *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ struct be_mcc_wrb_response_copy rc; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_FIRMWARE_CONFIG); ++ ++ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_FIRMWARE_CONFIG, ++ params.response); ++ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_FIRMWARE_CONFIG, ++ params.response); ++ rc.va = config; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, ++ NULL, NULL, NULL, fwcmd, &rc); ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This allocates and initializes a function object based on the information ++ provided by upper layer drivers. ++ ++ Returns BE_SUCCESS on success and an appropriate int on failure. ++ ++ A function object represents a single BladeEngine (logical) PCI function. ++ That is a function object either represents ++ the networking side of BladeEngine or the iSCSI side of BladeEngine. ++ ++ This routine will also detect and create an appropriate PD object for the ++ PCI function as needed. ++*/ ++int ++be_function_object_create(u8 __iomem *csr_va, u8 __iomem *db_va, ++ u8 __iomem *pci_va, u32 function_type, ++ struct ring_desc *mailbox, struct be_function_object *pfob) ++{ ++ int status; ++ ++ ASSERT(pfob); /* not a magic assert */ ++ ASSERT(function_type <= 2); ++ ++ TRACE(DL_INFO, "Create function object. type:%s object:0x%p", ++ (function_type == BE_FUNCTION_TYPE_ISCSI ? "iSCSI" : ++ (function_type == BE_FUNCTION_TYPE_NETWORK ? "Network" : ++ "Arm")), pfob); ++ ++ memset(pfob, 0, sizeof(*pfob)); ++ ++ pfob->type = function_type; ++ pfob->csr_va = csr_va; ++ pfob->db_va = db_va; ++ pfob->pci_va = pci_va; ++ ++ spin_lock_init(&pfob->cq_lock); ++ spin_lock_init(&pfob->post_lock); ++ spin_lock_init(&pfob->mcc_context_lock); ++ ++ ++ pfob->pci_function_number = 1; ++ ++ ++ pfob->emulate = false; ++ TRACE(DL_NOTE, "Non-emulation mode"); ++ status = be_drive_POST(pfob); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "BladeEngine POST failed."); ++ goto error; ++ } ++ ++ /* Initialize the mailbox */ ++ status = be_mpu_init_mailbox(pfob, mailbox); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "Failed to initialize mailbox."); ++ goto error; ++ } ++ /* ++ * Cache the firmware config for ASSERTs in hwclib and later ++ * driver queries. ++ */ ++ status = be_function_internal_query_firmware_config(pfob, ++ &pfob->fw_config); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "Failed to query firmware config."); ++ goto error; ++ } ++ ++error: ++ if (status != BE_SUCCESS) { ++ /* No cleanup necessary */ ++ TRACE(DL_ERR, "Failed to create function."); ++ memset(pfob, 0, sizeof(*pfob)); ++ } ++ return status; ++} ++ ++/* ++ This routine drops the reference count on a given function object. Once ++ the reference count falls to zero, the function object is destroyed and all ++ resources held are freed. ++ ++ FunctionObject - The function object to drop the reference to. ++*/ ++int be_function_object_destroy(struct be_function_object *pfob) ++{ ++ TRACE(DL_INFO, "Destroy pfob. Object:0x%p", ++ pfob); ++ ++ ++ ASSERT(pfob->mcc == NULL); ++ ++ return BE_SUCCESS; ++} ++ ++int be_function_cleanup(struct be_function_object *pfob) ++{ ++ int status = 0; ++ u32 isr; ++ u32 host_intr; ++ struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP ctrl; ++ ++ ++ if (pfob->type == BE_FUNCTION_TYPE_NETWORK) { ++ status = be_rxf_multicast_config(pfob, false, 0, ++ NULL, NULL, NULL, NULL); ++ ASSERT(status == BE_SUCCESS); ++ } ++ /* VLAN */ ++ status = be_rxf_vlan_config(pfob, false, 0, NULL, NULL, NULL, NULL); ++ ASSERT(status == BE_SUCCESS); ++ /* ++ * MCC Queue -- Switches to mailbox mode. May want to destroy ++ * all but the MCC CQ before this call if polling CQ is much better ++ * performance than polling mailbox register. ++ */ ++ if (pfob->mcc) ++ status = be_mcc_ring_destroy(pfob->mcc); ++ /* ++ * If interrupts are disabled, clear any CEV interrupt assertions that ++ * fired after we stopped processing EQs. ++ */ ++ ctrl.dw[0] = PCICFG1_READ(pfob, host_timer_int_ctrl); ++ host_intr = AMAP_GET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR, ++ hostintr, ctrl.dw); ++ if (!host_intr) ++ if (pfob->type == BE_FUNCTION_TYPE_NETWORK) ++ isr = CSR_READ(pfob, cev.isr1); ++ else ++ isr = CSR_READ(pfob, cev.isr0); ++ else ++ /* This should never happen... */ ++ TRACE(DL_ERR, "function_cleanup called with interrupt enabled"); ++ /* Function object destroy */ ++ status = be_function_object_destroy(pfob); ++ ASSERT(status == BE_SUCCESS); ++ ++ return status; ++} ++ ++ ++void * ++be_function_prepare_embedded_fwcmd(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, u32 payld_len, u32 request_length, ++ u32 response_length, u32 opcode, u32 subsystem) ++{ ++ struct FWCMD_REQUEST_HEADER *header = NULL; ++ u32 n; ++ ++ ASSERT(wrb); ++ ++ n = offsetof(struct BE_MCC_WRB_AMAP, payload)/8; ++ AMAP_SET_BITS_PTR(MCC_WRB, embedded, wrb, 1); ++ AMAP_SET_BITS_PTR(MCC_WRB, payload_length, wrb, min(payld_len, n)); ++ header = (struct FWCMD_REQUEST_HEADER *)((u8 *)wrb + n); ++ ++ header->timeout = 0; ++ header->domain = 0; ++ header->request_length = max(request_length, response_length); ++ header->opcode = opcode; ++ header->subsystem = subsystem; ++ ++ return header; ++} ++ ++void * ++be_function_prepare_nonembedded_fwcmd(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, ++ void *fwcmd_va, u64 fwcmd_pa, ++ u32 payld_len, ++ u32 request_length, ++ u32 response_length, ++ u32 opcode, u32 subsystem) ++{ ++ struct FWCMD_REQUEST_HEADER *header = NULL; ++ u32 n; ++ struct MCC_WRB_PAYLOAD_AMAP *plp; ++ ++ ASSERT(wrb); ++ ASSERT(fwcmd_va); ++ ++ header = (struct FWCMD_REQUEST_HEADER *) fwcmd_va; ++ ++ AMAP_SET_BITS_PTR(MCC_WRB, embedded, wrb, 0); ++ AMAP_SET_BITS_PTR(MCC_WRB, payload_length, wrb, payld_len); ++ ++ /* ++ * Assume one fragment. The caller may override the SGL by ++ * rewriting the 0th length and adding more entries. They ++ * will also need to update the sge_count. ++ */ ++ AMAP_SET_BITS_PTR(MCC_WRB, sge_count, wrb, 1); ++ ++ n = offsetof(struct BE_MCC_WRB_AMAP, payload)/8; ++ plp = (struct MCC_WRB_PAYLOAD_AMAP *)((u8 *)wrb + n); ++ AMAP_SET_BITS_PTR(MCC_WRB_PAYLOAD, sgl[0].length, plp, payld_len); ++ AMAP_SET_BITS_PTR(MCC_WRB_PAYLOAD, sgl[0].pa_lo, plp, (u32)fwcmd_pa); ++ AMAP_SET_BITS_PTR(MCC_WRB_PAYLOAD, sgl[0].pa_hi, plp, ++ upper_32_bits(fwcmd_pa)); ++ ++ header->timeout = 0; ++ header->domain = 0; ++ header->request_length = max(request_length, response_length); ++ header->opcode = opcode; ++ header->subsystem = subsystem; ++ ++ return header; ++} ++ ++struct MCC_WRB_AMAP * ++be_function_peek_mcc_wrb(struct be_function_object *pfob) ++{ ++ struct MCC_WRB_AMAP *wrb = NULL; ++ u32 offset; ++ ++ if (pfob->mcc) ++ wrb = _be_mpu_peek_ring_wrb(pfob->mcc, false); ++ else { ++ offset = offsetof(struct BE_MCC_MAILBOX_AMAP, wrb)/8; ++ wrb = (struct MCC_WRB_AMAP *) ((u8 *) pfob->mailbox.va + ++ offset); ++ } ++ ++ if (wrb) ++ memset(wrb, 0, sizeof(struct MCC_WRB_AMAP)); ++ ++ return wrb; ++} ++ ++#if defined(BE_DEBUG) ++void be_function_debug_print_wrb(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, void *optional_fwcmd_va, ++ struct be_mcc_wrb_context *wrb_context) ++{ ++ ++ struct FWCMD_REQUEST_HEADER *header = NULL; ++ u8 embedded; ++ u32 n; ++ ++ embedded = AMAP_GET_BITS_PTR(MCC_WRB, embedded, wrb); ++ ++ if (embedded) { ++ n = offsetof(struct BE_MCC_WRB_AMAP, payload)/8; ++ header = (struct FWCMD_REQUEST_HEADER *)((u8 *)wrb + n); ++ } else { ++ header = (struct FWCMD_REQUEST_HEADER *) optional_fwcmd_va; ++ } ++ ++ /* Save the completed count before posting for a debug assert. */ ++ ++ if (header) { ++ wrb_context->opcode = header->opcode; ++ wrb_context->subsystem = header->subsystem; ++ ++ } else { ++ wrb_context->opcode = 0; ++ wrb_context->subsystem = 0; ++ } ++} ++#else ++#define be_function_debug_print_wrb(a_, b_, c_, d_) ++#endif ++ ++int ++be_function_post_mcc_wrb(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, ++ struct be_generic_q_ctxt *q_ctxt, ++ mcc_wrb_cqe_callback cb, void *cb_context, ++ mcc_wrb_cqe_callback internal_cb, ++ void *internal_cb_context, void *optional_fwcmd_va, ++ struct be_mcc_wrb_response_copy *rc) ++{ ++ int status; ++ struct be_mcc_wrb_context *wrb_context = NULL; ++ u64 *p; ++ ++ if (q_ctxt) { ++ /* Initialize context. */ ++ q_ctxt->context.internal_cb = internal_cb; ++ q_ctxt->context.internal_cb_context = internal_cb_context; ++ q_ctxt->context.cb = cb; ++ q_ctxt->context.cb_context = cb_context; ++ if (rc) { ++ q_ctxt->context.copy.length = rc->length; ++ q_ctxt->context.copy.fwcmd_offset = rc->fwcmd_offset; ++ q_ctxt->context.copy.va = rc->va; ++ } else ++ q_ctxt->context.copy.length = 0; ++ ++ q_ctxt->context.optional_fwcmd_va = optional_fwcmd_va; ++ ++ /* Queue this request */ ++ status = be_function_queue_mcc_wrb(pfob, q_ctxt); ++ ++ goto Error; ++ } ++ /* ++ * Allocate a WRB context struct to hold the callback pointers, ++ * status, etc. This is required if commands complete out of order. ++ */ ++ wrb_context = _be_mcc_allocate_wrb_context(pfob); ++ if (!wrb_context) { ++ TRACE(DL_WARN, "Failed to allocate MCC WRB context."); ++ status = BE_STATUS_SYSTEM_RESOURCES; ++ goto Error; ++ } ++ /* Initialize context. */ ++ memset(wrb_context, 0, sizeof(*wrb_context)); ++ wrb_context->internal_cb = internal_cb; ++ wrb_context->internal_cb_context = internal_cb_context; ++ wrb_context->cb = cb; ++ wrb_context->cb_context = cb_context; ++ if (rc) { ++ wrb_context->copy.length = rc->length; ++ wrb_context->copy.fwcmd_offset = rc->fwcmd_offset; ++ wrb_context->copy.va = rc->va; ++ } else ++ wrb_context->copy.length = 0; ++ wrb_context->wrb = wrb; ++ ++ /* ++ * Copy the context pointer into the WRB opaque tag field. ++ * Verify assumption of 64-bit tag with a compile time assert. ++ */ ++ p = (u64 *) ((u8 *)wrb + offsetof(struct BE_MCC_WRB_AMAP, tag)/8); ++ *p = (u64)(size_t)wrb_context; ++ ++ /* Print info about this FWCMD for debug builds. */ ++ be_function_debug_print_wrb(pfob, wrb, optional_fwcmd_va, wrb_context); ++ ++ /* ++ * issue the WRB to the MPU as appropriate ++ */ ++ if (pfob->mcc) { ++ /* ++ * we're in WRB mode, pass to the mcc layer ++ */ ++ status = _be_mpu_post_wrb_ring(pfob->mcc, wrb, wrb_context); ++ } else { ++ /* ++ * we're in mailbox mode ++ */ ++ status = _be_mpu_post_wrb_mailbox(pfob, wrb, wrb_context); ++ ++ /* mailbox mode always completes synchronously */ ++ ASSERT(status != BE_STATUS_PENDING); ++ } ++ ++Error: ++ ++ return status; ++} ++ ++int ++be_function_ring_destroy(struct be_function_object *pfob, ++ u32 id, u32 ring_type, mcc_wrb_cqe_callback cb, ++ void *cb_context, mcc_wrb_cqe_callback internal_cb, ++ void *internal_cb_context) ++{ ++ ++ struct FWCMD_COMMON_RING_DESTROY *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ int status = 0; ++ unsigned long irql; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ TRACE(DL_INFO, "Destroy ring id:%d type:%d", id, ring_type); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ ASSERT(wrb); ++ TRACE(DL_ERR, "No free MCC WRBs in destroy ring."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_RING_DESTROY); ++ ++ fwcmd->params.request.id = id; ++ fwcmd->params.request.ring_type = ring_type; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, cb_context, ++ internal_cb, internal_cb_context, fwcmd, NULL); ++ if (status != BE_SUCCESS && status != BE_PENDING) { ++ TRACE(DL_ERR, "Ring destroy fwcmd failed. id:%d ring_type:%d", ++ id, ring_type); ++ goto Error; ++ } ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++void ++be_rd_to_pa_list(struct ring_desc *rd, struct PHYS_ADDR *pa_list, u32 max_num) ++{ ++ u32 num_pages = PAGES_SPANNED(rd->va, rd->length); ++ u32 i = 0; ++ u64 pa = rd->pa; ++ __le64 lepa; ++ ++ ASSERT(pa_list); ++ ASSERT(pa); ++ ++ for (i = 0; i < min(num_pages, max_num); i++) { ++ lepa = cpu_to_le64(pa); ++ pa_list[i].lo = (u32)lepa; ++ pa_list[i].hi = upper_32_bits(lepa); ++ pa += PAGE_SIZE; ++ } ++} ++ ++ ++ ++/*----------------------------------------------------------------------------- ++ * Function: be_function_get_fw_version ++ * Retrieves the firmware version on the adpater. If the callback is ++ * NULL this call executes synchronously. If the callback is not NULL, ++ * the returned status will be BE_PENDING if the command was issued ++ * successfully. ++ * pfob - ++ * fwv - Pointer to response buffer if callback is NULL. ++ * cb - Callback function invoked when the FWCMD completes. ++ * cb_context - Passed to the callback function. ++ * return pend_status - BE_SUCCESS (0) on success. ++ * BE_PENDING (postive value) if the FWCMD ++ * completion is pending. Negative error code on failure. ++ *--------------------------------------------------------------------------- ++ */ ++int ++be_function_get_fw_version(struct be_function_object *pfob, ++ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD *fwv, ++ mcc_wrb_cqe_callback cb, void *cb_context) ++{ ++ int status = BE_SUCCESS; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ struct FWCMD_COMMON_GET_FW_VERSION *fwcmd = NULL; ++ unsigned long irql; ++ struct be_mcc_wrb_response_copy rc; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ TRACE(DL_ERR, "MCC wrb peek failed."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto Error; ++ } ++ ++ if (!cb && !fwv) { ++ TRACE(DL_ERR, "callback and response buffer NULL!"); ++ status = BE_NOT_OK; ++ goto Error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_FW_VERSION); ++ ++ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_GET_FW_VERSION, ++ params.response); ++ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_GET_FW_VERSION, ++ params.response); ++ rc.va = fwv; ++ ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, ++ cb_context, NULL, NULL, fwcmd, &rc); ++ ++Error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++int ++be_function_queue_mcc_wrb(struct be_function_object *pfob, ++ struct be_generic_q_ctxt *q_ctxt) ++{ ++ int status; ++ ++ ASSERT(q_ctxt); ++ ++ /* ++ * issue the WRB to the MPU as appropriate ++ */ ++ if (pfob->mcc) { ++ ++ /* We're in ring mode. Queue this item. */ ++ pfob->mcc->backlog_length++; ++ list_add_tail(&q_ctxt->context.list, &pfob->mcc->backlog); ++ status = BE_PENDING; ++ } else { ++ status = BE_NOT_OK; ++ } ++ return status; ++} ++ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_common_bmap.h +@@ -0,0 +1,717 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_common_bmap_h__ ++#define __fwcmd_common_bmap_h__ ++#include "fwcmd_types_bmap.h" ++#include "fwcmd_hdr_bmap.h" ++ ++#if defined(__BIG_ENDIAN) ++ /* Physical Address. */ ++struct PHYS_ADDR { ++ union { ++ struct { ++ u32 lo; /* DWORD 0 */ ++ u32 hi; /* DWORD 1 */ ++ } __packed; /* unnamed struct */ ++ u32 dw[2]; /* dword union */ ++ }; /* unnamed union */ ++} __packed ; ++ ++ ++#else ++ /* Physical Address. */ ++struct PHYS_ADDR { ++ union { ++ struct { ++ u32 lo; /* DWORD 0 */ ++ u32 hi; /* DWORD 1 */ ++ } __packed; /* unnamed struct */ ++ u32 dw[2]; /* dword union */ ++ }; /* unnamed union */ ++} __packed ; ++ ++struct BE_LINK_STATUS { ++ u8 mac0_duplex; ++ u8 mac0_speed; ++ u8 mac1_duplex; ++ u8 mac1_speed; ++ u8 mgmt_mac_duplex; ++ u8 mgmt_mac_speed; ++ u8 active_port; ++ u8 rsvd0; ++ u8 mac0_fault; ++ u8 mac1_fault; ++ u16 rsvd1; ++} __packed; ++#endif ++ ++struct FWCMD_COMMON_ANON_170_REQUEST { ++ u32 rsvd0; ++} __packed; ++ ++union LINK_STATUS_QUERY_PARAMS { ++ struct BE_LINK_STATUS response; ++ struct FWCMD_COMMON_ANON_170_REQUEST request; ++} __packed; ++ ++/* ++ * Queries the the link status for all ports. The valid values below ++ * DO NOT indicate that a particular duplex or speed is supported by ++ * BladeEngine. These enumerations simply list all possible duplexes ++ * and speeds for any port. Consult BladeEngine product documentation ++ * for the supported parameters. ++ */ ++struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY { ++ union FWCMD_HEADER header; ++ union LINK_STATUS_QUERY_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_171_REQUEST { ++ u8 type; ++ u8 port; ++ u8 mac1; ++ u8 permanent; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_172_RESPONSE { ++ struct MAC_ADDRESS_FORMAT mac; ++} __packed; ++ ++union NTWK_MAC_QUERY_PARAMS { ++ struct FWCMD_COMMON_ANON_171_REQUEST request; ++ struct FWCMD_COMMON_ANON_172_RESPONSE response; ++} __packed; ++ ++/* Queries one MAC address. */ ++struct FWCMD_COMMON_NTWK_MAC_QUERY { ++ union FWCMD_HEADER header; ++ union NTWK_MAC_QUERY_PARAMS params; ++} __packed; ++ ++struct MAC_SET_PARAMS_IN { ++ u8 type; ++ u8 port; ++ u8 mac1; ++ u8 invalidate; ++ struct MAC_ADDRESS_FORMAT mac; ++} __packed; ++ ++struct MAC_SET_PARAMS_OUT { ++ u32 rsvd0; ++} __packed; ++ ++union MAC_SET_PARAMS { ++ struct MAC_SET_PARAMS_IN request; ++ struct MAC_SET_PARAMS_OUT response; ++} __packed; ++ ++/* Sets a MAC address. */ ++struct FWCMD_COMMON_NTWK_MAC_SET { ++ union FWCMD_HEADER header; ++ union MAC_SET_PARAMS params; ++} __packed; ++ ++/* MAC address list. */ ++struct NTWK_MULTICAST_MAC_LIST { ++ u8 byte[6]; ++} __packed; ++ ++struct FWCMD_COMMON_NTWK_MULTICAST_SET_REQUEST_PAYLOAD { ++ u16 num_mac; ++ u8 promiscuous; ++ u8 rsvd0; ++ struct NTWK_MULTICAST_MAC_LIST mac[32]; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_174_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_173_PARAMS { ++ struct FWCMD_COMMON_NTWK_MULTICAST_SET_REQUEST_PAYLOAD request; ++ struct FWCMD_COMMON_ANON_174_RESPONSE response; ++} __packed; ++ ++/* ++ * Sets multicast address hash. The MPU will merge the MAC address lists ++ * from all clients, including the networking and storage functions. ++ * This command may fail if the final merged list of MAC addresses exceeds ++ * 32 entries. ++ */ ++struct FWCMD_COMMON_NTWK_MULTICAST_SET { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_173_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_NTWK_VLAN_CONFIG_REQUEST_PAYLOAD { ++ u16 num_vlan; ++ u8 promiscuous; ++ u8 rsvd0; ++ u16 vlan_tag[32]; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_176_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_175_PARAMS { ++ struct FWCMD_COMMON_NTWK_VLAN_CONFIG_REQUEST_PAYLOAD request; ++ struct FWCMD_COMMON_ANON_176_RESPONSE response; ++} __packed; ++ ++/* ++ * Sets VLAN tag filter. The MPU will merge the VLAN tag list from all ++ * clients, including the networking and storage functions. This command ++ * may fail if the final vlan_tag array (from all functions) is longer ++ * than 32 entries. ++ */ ++struct FWCMD_COMMON_NTWK_VLAN_CONFIG { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_175_PARAMS params; ++} __packed; ++ ++struct RING_DESTROY_REQUEST { ++ u16 ring_type; ++ u16 id; ++ u8 bypass_flush; ++ u8 rsvd0; ++ u16 rsvd1; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_190_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_189_PARAMS { ++ struct RING_DESTROY_REQUEST request; ++ struct FWCMD_COMMON_ANON_190_RESPONSE response; ++} __packed; ++/* ++ * Command for destroying any ring. The connection(s) using the ring should ++ * be quiesced before destroying the ring. ++ */ ++struct FWCMD_COMMON_RING_DESTROY { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_189_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_192_REQUEST { ++ u16 num_pages; ++ u16 rsvd0; ++ struct CQ_CONTEXT_AMAP context; ++ struct PHYS_ADDR pages[4]; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_193_RESPONSE { ++ u16 cq_id; ++} __packed ; ++ ++union FWCMD_COMMON_ANON_191_PARAMS { ++ struct FWCMD_COMMON_ANON_192_REQUEST request; ++ struct FWCMD_COMMON_ANON_193_RESPONSE response; ++} __packed ; ++ ++/* ++ * Command for creating a completion queue. A Completion Queue must span ++ * at least 1 page and at most 4 pages. Each completion queue entry ++ * is 16 bytes regardless of CQ entry format. Thus the ring must be ++ * at least 256 entries deep (corresponding to 1 page) and can be at ++ * most 1024 entries deep (corresponding to 4 pages). The number of ++ * pages posted must contain the CQ ring size as encoded in the context. ++ * ++ */ ++struct FWCMD_COMMON_CQ_CREATE { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_191_PARAMS params; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_198_REQUEST { ++ u16 num_pages; ++ u16 rsvd0; ++ struct EQ_CONTEXT_AMAP context; ++ struct PHYS_ADDR pages[8]; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_199_RESPONSE { ++ u16 eq_id; ++} __packed ; ++ ++union FWCMD_COMMON_ANON_197_PARAMS { ++ struct FWCMD_COMMON_ANON_198_REQUEST request; ++ struct FWCMD_COMMON_ANON_199_RESPONSE response; ++} __packed ; ++ ++/* ++ * Command for creating a event queue. An Event Queue must span at least ++ * 1 page and at most 8 pages. The number of pages posted must contain ++ * the EQ ring. The ring is defined by the size of the EQ entries (encoded ++ * in the context) and the number of EQ entries (also encoded in the ++ * context). ++ */ ++struct FWCMD_COMMON_EQ_CREATE { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_197_PARAMS params; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_201_REQUEST { ++ u16 cq_id; ++ u16 bcmc_cq_id; ++ u16 num_pages; ++ u16 rsvd0; ++ struct PHYS_ADDR pages[2]; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_202_RESPONSE { ++ u16 id; ++} __packed; ++ ++union FWCMD_COMMON_ANON_200_PARAMS { ++ struct FWCMD_COMMON_ANON_201_REQUEST request; ++ struct FWCMD_COMMON_ANON_202_RESPONSE response; ++} __packed; ++ ++/* ++ * Command for creating Ethernet receive ring. An ERX ring contains ETH_RX_D ++ * entries (8 bytes each). An ERX ring must be 1024 entries deep ++ * (corresponding to 2 pages). ++ */ ++struct FWCMD_COMMON_ETH_RX_CREATE { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_200_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_204_REQUEST { ++ u16 num_pages; ++ u8 ulp_num; ++ u8 type; ++ struct ETX_CONTEXT_AMAP context; ++ struct PHYS_ADDR pages[8]; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_205_RESPONSE { ++ u16 cid; ++ u8 ulp_num; ++ u8 rsvd0; ++} __packed ; ++ ++union FWCMD_COMMON_ANON_203_PARAMS { ++ struct FWCMD_COMMON_ANON_204_REQUEST request; ++ struct FWCMD_COMMON_ANON_205_RESPONSE response; ++} __packed ; ++ ++/* ++ * Command for creating an Ethernet transmit ring. An ETX ring contains ++ * ETH_WRB entries (16 bytes each). An ETX ring must be at least 256 ++ * entries deep (corresponding to 1 page) and at most 2k entries deep ++ * (corresponding to 8 pages). ++ */ ++struct FWCMD_COMMON_ETH_TX_CREATE { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_203_PARAMS params; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_222_REQUEST { ++ u16 num_pages; ++ u16 rsvd0; ++ struct MCC_RING_CONTEXT_AMAP context; ++ struct PHYS_ADDR pages[8]; ++} __packed ; ++ ++struct FWCMD_COMMON_ANON_223_RESPONSE { ++ u16 id; ++} __packed ; ++ ++union FWCMD_COMMON_ANON_221_PARAMS { ++ struct FWCMD_COMMON_ANON_222_REQUEST request; ++ struct FWCMD_COMMON_ANON_223_RESPONSE response; ++} __packed ; ++ ++/* ++ * Command for creating the MCC ring. An MCC ring must be at least 16 ++ * entries deep (corresponding to 1 page) and at most 128 entries deep ++ * (corresponding to 8 pages). ++ */ ++struct FWCMD_COMMON_MCC_CREATE { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_221_PARAMS params; ++} __packed ; ++ ++struct GET_QOS_IN { ++ u32 qos_params_rsvd; ++} __packed; ++ ++struct GET_QOS_OUT { ++ u32 max_bits_per_second_NIC; ++ u32 max_packets_per_second_NIC; ++ u32 max_ios_per_second_iSCSI; ++ u32 max_bytes_per_second_iSCSI; ++ u16 domain_VLAN_tag; ++ u16 fabric_domain_ID; ++ u32 qos_params_oem[4]; ++} __packed; ++ ++union GET_QOS_PARAMS { ++ struct GET_QOS_IN request; ++ struct GET_QOS_OUT response; ++} __packed; ++ ++/* QOS/Bandwidth settings per domain. Applicable only in VMs. */ ++struct FWCMD_COMMON_GET_QOS { ++ union FWCMD_HEADER header; ++ union GET_QOS_PARAMS params; ++} __packed; ++ ++struct SET_QOS_IN { ++ u32 valid_flags; ++ u32 max_bits_per_second_NIC; ++ u32 max_packets_per_second_NIC; ++ u32 max_ios_per_second_iSCSI; ++ u32 max_bytes_per_second_iSCSI; ++ u16 domain_VLAN_tag; ++ u16 fabric_domain_ID; ++ u32 qos_params_oem[4]; ++} __packed; ++ ++struct SET_QOS_OUT { ++ u32 qos_params_rsvd; ++} __packed; ++ ++union SET_QOS_PARAMS { ++ struct SET_QOS_IN request; ++ struct SET_QOS_OUT response; ++} __packed; ++ ++/* QOS/Bandwidth settings per domain. Applicable only in VMs. */ ++struct FWCMD_COMMON_SET_QOS { ++ union FWCMD_HEADER header; ++ union SET_QOS_PARAMS params; ++} __packed; ++ ++struct SET_FRAME_SIZE_IN { ++ u32 max_tx_frame_size; ++ u32 max_rx_frame_size; ++} __packed; ++ ++struct SET_FRAME_SIZE_OUT { ++ u32 chip_max_tx_frame_size; ++ u32 chip_max_rx_frame_size; ++} __packed; ++ ++union SET_FRAME_SIZE_PARAMS { ++ struct SET_FRAME_SIZE_IN request; ++ struct SET_FRAME_SIZE_OUT response; ++} __packed; ++ ++/* Set frame size command. Only host domain may issue this command. */ ++struct FWCMD_COMMON_SET_FRAME_SIZE { ++ union FWCMD_HEADER header; ++ union SET_FRAME_SIZE_PARAMS params; ++} __packed; ++ ++struct FORCE_FAILOVER_IN { ++ u32 move_to_port; ++ u32 failover_config; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_231_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_230_PARAMS { ++ struct FORCE_FAILOVER_IN request; ++ struct FWCMD_COMMON_ANON_231_RESPONSE response; ++} __packed; ++ ++/* ++ * Use this command to control failover in BladeEngine. It may be used ++ * to failback to a restored port or to forcibly move traffic from ++ * one port to another. It may also be used to enable or disable the ++ * automatic failover feature. This command can only be issued by domain ++ * 0. ++ */ ++struct FWCMD_COMMON_FORCE_FAILOVER { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_230_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_240_REQUEST { ++ u64 context; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_241_RESPONSE { ++ u64 context; ++} __packed; ++ ++union FWCMD_COMMON_ANON_239_PARAMS { ++ struct FWCMD_COMMON_ANON_240_REQUEST request; ++ struct FWCMD_COMMON_ANON_241_RESPONSE response; ++} __packed; ++ ++/* ++ * This command can be used by clients as a no-operation request. Typical ++ * uses for drivers are as a heartbeat mechanism, or deferred processing ++ * catalyst. The ARM will always complete this command with a good completion. ++ * The 64-bit parameter is not touched by the ARM processor. ++ */ ++struct FWCMD_COMMON_NOP { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_239_PARAMS params; ++} __packed; ++ ++struct NTWK_RX_FILTER_SETTINGS { ++ u8 promiscuous; ++ u8 ip_cksum; ++ u8 tcp_cksum; ++ u8 udp_cksum; ++ u8 pass_err; ++ u8 pass_ckerr; ++ u8 strip_crc; ++ u8 mcast_en; ++ u8 bcast_en; ++ u8 mcast_promiscuous_en; ++ u8 unicast_en; ++ u8 vlan_promiscuous; ++} __packed; ++ ++union FWCMD_COMMON_ANON_242_PARAMS { ++ struct NTWK_RX_FILTER_SETTINGS request; ++ struct NTWK_RX_FILTER_SETTINGS response; ++} __packed; ++ ++/* ++ * This command is used to modify the ethernet receive filter configuration. ++ * Only domain 0 network function drivers may issue this command. The ++ * applied configuration is returned in the response payload. Note: ++ * Some receive packet filter settings are global on BladeEngine and ++ * can affect both the storage and network function clients that the ++ * BladeEngine hardware and firmware serve. Additionaly, depending ++ * on the revision of BladeEngine, some ethernet receive filter settings ++ * are dependent on others. If a dependency exists between settings ++ * for the BladeEngine revision, and the command request settings do ++ * not meet the dependency requirement, the invalid settings will not ++ * be applied despite the comand succeeding. For example: a driver may ++ * request to enable broadcast packets, but not enable multicast packets. ++ * On early revisions of BladeEngine, there may be no distinction between ++ * broadcast and multicast filters, so broadcast could not be enabled ++ * without enabling multicast. In this scenario, the comand would still ++ * succeed, but the response payload would indicate the previously ++ * configured broadcast and multicast setting. ++ */ ++struct FWCMD_COMMON_NTWK_RX_FILTER { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_242_PARAMS params; ++} __packed; ++ ++ ++struct FWCMD_COMMON_ANON_244_REQUEST { ++ u32 rsvd0; ++} __packed; ++ ++struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD { ++ u8 firmware_version_string[32]; ++ u8 fw_on_flash_version_string[32]; ++} __packed; ++ ++union FWCMD_COMMON_ANON_243_PARAMS { ++ struct FWCMD_COMMON_ANON_244_REQUEST request; ++ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD response; ++} __packed; ++ ++/* This comand retrieves the firmware version. */ ++struct FWCMD_COMMON_GET_FW_VERSION { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_243_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_246_REQUEST { ++ u16 tx_flow_control; ++ u16 rx_flow_control; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_247_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_245_PARAMS { ++ struct FWCMD_COMMON_ANON_246_REQUEST request; ++ struct FWCMD_COMMON_ANON_247_RESPONSE response; ++} __packed; ++ ++/* ++ * This comand is used to program BladeEngine flow control behavior. ++ * Only the host networking driver is allowed to use this comand. ++ */ ++struct FWCMD_COMMON_SET_FLOW_CONTROL { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_245_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_249_REQUEST { ++ u32 rsvd0; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_250_RESPONSE { ++ u16 tx_flow_control; ++ u16 rx_flow_control; ++} __packed; ++ ++union FWCMD_COMMON_ANON_248_PARAMS { ++ struct FWCMD_COMMON_ANON_249_REQUEST request; ++ struct FWCMD_COMMON_ANON_250_RESPONSE response; ++} __packed; ++ ++/* This comand is used to read BladeEngine flow control settings. */ ++struct FWCMD_COMMON_GET_FLOW_CONTROL { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_248_PARAMS params; ++} __packed; ++ ++struct EQ_DELAY_PARAMS { ++ u32 eq_id; ++ u32 delay_in_microseconds; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_257_REQUEST { ++ u32 num_eq; ++ u32 rsvd0; ++ struct EQ_DELAY_PARAMS delay[16]; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_258_RESPONSE { ++ u32 delay_resolution_in_microseconds; ++ u32 delay_max_in_microseconds; ++} __packed; ++ ++union MODIFY_EQ_DELAY_PARAMS { ++ struct FWCMD_COMMON_ANON_257_REQUEST request; ++ struct FWCMD_COMMON_ANON_258_RESPONSE response; ++} __packed; ++ ++/* This comand changes the EQ delay for a given set of EQs. */ ++struct FWCMD_COMMON_MODIFY_EQ_DELAY { ++ union FWCMD_HEADER header; ++ union MODIFY_EQ_DELAY_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_260_REQUEST { ++ u32 rsvd0; ++} __packed; ++ ++struct BE_FIRMWARE_CONFIG { ++ u16 be_config_number; ++ u16 asic_revision; ++ u32 nic_ulp_mask; ++ u32 tulp_mask; ++ u32 iscsi_ulp_mask; ++ u32 rdma_ulp_mask; ++ u32 rsvd0[4]; ++ u32 eth_tx_id_start; ++ u32 eth_tx_id_count; ++ u32 eth_rx_id_start; ++ u32 eth_rx_id_count; ++ u32 tpm_wrbq_id_start; ++ u32 tpm_wrbq_id_count; ++ u32 tpm_defq_id_start; ++ u32 tpm_defq_id_count; ++ u32 iscsi_wrbq_id_start; ++ u32 iscsi_wrbq_id_count; ++ u32 iscsi_defq_id_start; ++ u32 iscsi_defq_id_count; ++ u32 rdma_qp_id_start; ++ u32 rdma_qp_id_count; ++ u32 rsvd1[8]; ++} __packed; ++ ++union FWCMD_COMMON_ANON_259_PARAMS { ++ struct FWCMD_COMMON_ANON_260_REQUEST request; ++ struct BE_FIRMWARE_CONFIG response; ++} __packed; ++ ++/* ++ * This comand queries the current firmware configuration parameters. ++ * The static configuration type is defined by be_config_number. This ++ * differentiates different BladeEngine builds, such as iSCSI Initiator ++ * versus iSCSI Target. For a given static configuration, the Upper ++ * Layer Protocol (ULP) processors may be reconfigured to support different ++ * protocols. Each ULP processor supports one or more protocols. The ++ * masks indicate which processors are configured for each protocol. ++ * For a given static configuration, the number of TCP connections ++ * supported for each protocol may vary. The *_id_start and *_id_count ++ * variables define a linear range of IDs that are available for each ++ * supported protocol. The *_id_count may be used by the driver to allocate ++ * the appropriate number of connection resources. The *_id_start may ++ * be used to map the arbitrary range of IDs to a zero-based range ++ * of indices. ++ */ ++struct FWCMD_COMMON_FIRMWARE_CONFIG { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_259_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_PORT_EQUALIZATION_PARAMS { ++ u32 emph_lev_sel_port0; ++ u32 emph_lev_sel_port1; ++ u8 xaui_vo_sel; ++ u8 xaui_state; ++ u16 rsvd0; ++ u32 xaui_eq_vector; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_262_REQUEST { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_261_PARAMS { ++ struct FWCMD_COMMON_ANON_262_REQUEST request; ++ struct FWCMD_COMMON_PORT_EQUALIZATION_PARAMS response; ++} __packed; ++ ++/* ++ * This comand can be used to read XAUI equalization parameters. The ++ * ARM firmware applies default equalization parameters during initialization. ++ * These parameters may be customer-specific when derived from the ++ * SEEPROM. See SEEPROM_DATA for equalization specific fields. ++ */ ++struct FWCMD_COMMON_GET_PORT_EQUALIZATION { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_261_PARAMS params; ++} __packed; ++ ++struct FWCMD_COMMON_ANON_264_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_COMMON_ANON_263_PARAMS { ++ struct FWCMD_COMMON_PORT_EQUALIZATION_PARAMS request; ++ struct FWCMD_COMMON_ANON_264_RESPONSE response; ++} __packed; ++ ++/* ++ * This comand can be used to set XAUI equalization parameters. The ARM ++ * firmware applies default equalization parameters during initialization. ++ * These parameters may be customer-specific when derived from the ++ * SEEPROM. See SEEPROM_DATA for equalization specific fields. ++ */ ++struct FWCMD_COMMON_SET_PORT_EQUALIZATION { ++ union FWCMD_HEADER header; ++ union FWCMD_COMMON_ANON_263_PARAMS params; ++} __packed; ++ ++#endif /* __fwcmd_common_bmap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_common.h +@@ -0,0 +1,222 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_common_amap_h__ ++#define __fwcmd_common_amap_h__ ++#include "host_struct.h" ++ ++/* --- PHY_LINK_DUPLEX_ENUM --- */ ++#define PHY_LINK_DUPLEX_NONE (0) ++#define PHY_LINK_DUPLEX_HALF (1) ++#define PHY_LINK_DUPLEX_FULL (2) ++ ++/* --- PHY_LINK_SPEED_ENUM --- */ ++#define PHY_LINK_SPEED_ZERO (0) /* No link. */ ++#define PHY_LINK_SPEED_10MBPS (1) /* 10 Mbps */ ++#define PHY_LINK_SPEED_100MBPS (2) /* 100 Mbps */ ++#define PHY_LINK_SPEED_1GBPS (3) /* 1 Gbps */ ++#define PHY_LINK_SPEED_10GBPS (4) /* 10 Gbps */ ++ ++/* --- PHY_LINK_FAULT_ENUM --- */ ++#define PHY_LINK_FAULT_NONE (0) /* No fault status ++ available or detected */ ++#define PHY_LINK_FAULT_LOCAL (1) /* Local fault detected */ ++#define PHY_LINK_FAULT_REMOTE (2) /* Remote fault detected */ ++ ++/* --- BE_ULP_MASK --- */ ++#define BE_ULP0_MASK (1) ++#define BE_ULP1_MASK (2) ++#define BE_ULP2_MASK (4) ++ ++/* --- NTWK_ACTIVE_PORT --- */ ++#define NTWK_PORT_A (0) /* Port A is currently active */ ++#define NTWK_PORT_B (1) /* Port B is currently active */ ++#define NTWK_NO_ACTIVE_PORT (15) /* Both ports have lost link */ ++ ++/* --- NTWK_LINK_TYPE --- */ ++#define NTWK_LINK_TYPE_PHYSICAL (0) /* link up/down event ++ applies to BladeEngine's ++ Physical Ports ++ */ ++#define NTWK_LINK_TYPE_VIRTUAL (1) /* Virtual link up/down event ++ reported by BladeExchange. ++ This applies only when the ++ VLD feature is enabled ++ */ ++ ++/* ++ * --- FWCMD_MAC_TYPE_ENUM --- ++ * This enum defines the types of MAC addresses in the RXF MAC Address Table. ++ */ ++#define MAC_ADDRESS_TYPE_STORAGE (0) /* Storage MAC Address */ ++#define MAC_ADDRESS_TYPE_NETWORK (1) /* Network MAC Address */ ++#define MAC_ADDRESS_TYPE_PD (2) /* Protection Domain MAC Addr */ ++#define MAC_ADDRESS_TYPE_MANAGEMENT (3) /* Managment MAC Address */ ++ ++ ++/* --- FWCMD_RING_TYPE_ENUM --- */ ++#define FWCMD_RING_TYPE_ETH_RX (1) /* Ring created with */ ++ /* FWCMD_COMMON_ETH_RX_CREATE. */ ++#define FWCMD_RING_TYPE_ETH_TX (2) /* Ring created with */ ++ /* FWCMD_COMMON_ETH_TX_CREATE. */ ++#define FWCMD_RING_TYPE_ISCSI_WRBQ (3) /* Ring created with */ ++ /* FWCMD_COMMON_ISCSI_WRBQ_CREATE. */ ++#define FWCMD_RING_TYPE_ISCSI_DEFQ (4) /* Ring created with */ ++ /* FWCMD_COMMON_ISCSI_DEFQ_CREATE. */ ++#define FWCMD_RING_TYPE_TPM_WRBQ (5) /* Ring created with */ ++ /* FWCMD_COMMON_TPM_WRBQ_CREATE. */ ++#define FWCMD_RING_TYPE_TPM_DEFQ (6) /* Ring created with */ ++ /* FWCMD_COMMONTPM_TDEFQ_CREATE. */ ++#define FWCMD_RING_TYPE_TPM_RQ (7) /* Ring created with */ ++ /* FWCMD_COMMON_TPM_RQ_CREATE. */ ++#define FWCMD_RING_TYPE_MCC (8) /* Ring created with */ ++ /* FWCMD_COMMON_MCC_CREATE. */ ++#define FWCMD_RING_TYPE_CQ (9) /* Ring created with */ ++ /* FWCMD_COMMON_CQ_CREATE. */ ++#define FWCMD_RING_TYPE_EQ (10) /* Ring created with */ ++ /* FWCMD_COMMON_EQ_CREATE. */ ++#define FWCMD_RING_TYPE_QP (11) /* Ring created with */ ++ /* FWCMD_RDMA_QP_CREATE. */ ++ ++ ++/* --- ETH_TX_RING_TYPE_ENUM --- */ ++#define ETH_TX_RING_TYPE_FORWARDING (1) /* Ethernet ring for ++ forwarding packets */ ++#define ETH_TX_RING_TYPE_STANDARD (2) /* Ethernet ring for sending ++ network packets. */ ++#define ETH_TX_RING_TYPE_BOUND (3) /* Ethernet ring bound to the ++ port specified in the command ++ header.port_number field. ++ Rings of this type are ++ NOT subject to the ++ failover logic implemented ++ in the BladeEngine. ++ */ ++ ++/* --- FWCMD_COMMON_QOS_TYPE_ENUM --- */ ++#define QOS_BITS_NIC (1) /* max_bits_per_second_NIC */ ++ /* field is valid. */ ++#define QOS_PKTS_NIC (2) /* max_packets_per_second_NIC */ ++ /* field is valid. */ ++#define QOS_IOPS_ISCSI (4) /* max_ios_per_second_iSCSI */ ++ /*field is valid. */ ++#define QOS_VLAN_TAG (8) /* domain_VLAN_tag field ++ is valid. */ ++#define QOS_FABRIC_ID (16) /* fabric_domain_ID field ++ is valid. */ ++#define QOS_OEM_PARAMS (32) /* qos_params_oem field ++ is valid. */ ++#define QOS_TPUT_ISCSI (64) /* max_bytes_per_second_iSCSI ++ field is valid. */ ++ ++ ++/* ++ * --- FAILOVER_CONFIG_ENUM --- ++ * Failover configuration setting used in FWCMD_COMMON_FORCE_FAILOVER ++ */ ++#define FAILOVER_CONFIG_NO_CHANGE (0) /* No change to automatic */ ++ /* port failover setting. */ ++#define FAILOVER_CONFIG_ON (1) /* Automatic port failover ++ on link down is enabled. */ ++#define FAILOVER_CONFIG_OFF (2) /* Automatic port failover ++ on link down is disabled. */ ++ ++/* ++ * --- FAILOVER_PORT_ENUM --- ++ * Failover port setting used in FWCMD_COMMON_FORCE_FAILOVER ++ */ ++#define FAILOVER_PORT_A (0) /* Selects port A. */ ++#define FAILOVER_PORT_B (1) /* Selects port B. */ ++#define FAILOVER_PORT_NONE (15) /* No port change requested. */ ++ ++ ++/* ++ * --- MGMT_FLASHROM_OPCODE --- ++ * Flash ROM operation code ++ */ ++#define MGMT_FLASHROM_OPCODE_FLASH (1) /* Commit downloaded data ++ to Flash ROM */ ++#define MGMT_FLASHROM_OPCODE_SAVE (2) /* Save downloaded data to ++ ARM's DDR - do not flash */ ++#define MGMT_FLASHROM_OPCODE_CLEAR (3) /* Erase specified component ++ from FlashROM */ ++#define MGMT_FLASHROM_OPCODE_REPORT (4) /* Read specified component ++ from Flash ROM */ ++#define MGMT_FLASHROM_OPCODE_IMAGE_INFO (5) /* Returns size of a ++ component */ ++ ++/* ++ * --- MGMT_FLASHROM_OPTYPE --- ++ * Flash ROM operation type ++ */ ++#define MGMT_FLASHROM_OPTYPE_CODE_FIRMWARE (0) /* Includes ARM firmware, ++ IPSec (optional) and EP ++ firmware */ ++#define MGMT_FLASHROM_OPTYPE_CODE_REDBOOT (1) ++#define MGMT_FLASHROM_OPTYPE_CODE_BIOS (2) ++#define MGMT_FLASHROM_OPTYPE_CODE_PXE_BIOS (3) ++#define MGMT_FLASHROM_OPTYPE_CODE_CTRLS (4) ++#define MGMT_FLASHROM_OPTYPE_CFG_IPSEC (5) ++#define MGMT_FLASHROM_OPTYPE_CFG_INI (6) ++#define MGMT_FLASHROM_OPTYPE_ROM_OFFSET_SPECIFIED (7) ++ ++/* ++ * --- FLASHROM_TYPE --- ++ * Flash ROM manufacturers supported in the f/w ++ */ ++#define INTEL (0) ++#define SPANSION (1) ++#define MICRON (2) ++ ++/* --- DDR_CAS_TYPE --- */ ++#define CAS_3 (0) ++#define CAS_4 (1) ++#define CAS_5 (2) ++ ++/* --- DDR_SIZE_TYPE --- */ ++#define SIZE_256MB (0) ++#define SIZE_512MB (1) ++ ++/* --- DDR_MODE_TYPE --- */ ++#define DDR_NO_ECC (0) ++#define DDR_ECC (1) ++ ++/* --- INTERFACE_10GB_TYPE --- */ ++#define CX4_TYPE (0) ++#define XFP_TYPE (1) ++ ++/* --- BE_CHIP_MAX_MTU --- */ ++#define CHIP_MAX_MTU (9000) ++ ++/* --- XAUI_STATE_ENUM --- */ ++#define XAUI_STATE_ENABLE (0) /* This MUST be the default ++ value for all requests ++ which set/change ++ equalization parameter. */ ++#define XAUI_STATE_DISABLE (255) /* The XAUI for both ports ++ may be disabled for EMI ++ tests. There is no ++ provision for turning off ++ individual ports. ++ */ ++/* --- BE_ASIC_REVISION --- */ ++#define BE_ASIC_REV_A0 (1) ++#define BE_ASIC_REV_A1 (2) ++ ++#endif /* __fwcmd_common_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_eth_bmap.h +@@ -0,0 +1,280 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_eth_bmap_h__ ++#define __fwcmd_eth_bmap_h__ ++#include "fwcmd_hdr_bmap.h" ++#include "fwcmd_types_bmap.h" ++ ++struct MIB_ETH_STATISTICS_PARAMS_IN { ++ u32 rsvd0; ++} __packed; ++ ++struct BE_RXF_STATS { ++ u32 p0recvdtotalbytesLSD; /* DWORD 0 */ ++ u32 p0recvdtotalbytesMSD; /* DWORD 1 */ ++ u32 p0recvdtotalframes; /* DWORD 2 */ ++ u32 p0recvdunicastframes; /* DWORD 3 */ ++ u32 p0recvdmulticastframes; /* DWORD 4 */ ++ u32 p0recvdbroadcastframes; /* DWORD 5 */ ++ u32 p0crcerrors; /* DWORD 6 */ ++ u32 p0alignmentsymerrs; /* DWORD 7 */ ++ u32 p0pauseframesrecvd; /* DWORD 8 */ ++ u32 p0controlframesrecvd; /* DWORD 9 */ ++ u32 p0inrangelenerrors; /* DWORD 10 */ ++ u32 p0outrangeerrors; /* DWORD 11 */ ++ u32 p0frametoolongerrors; /* DWORD 12 */ ++ u32 p0droppedaddressmatch; /* DWORD 13 */ ++ u32 p0droppedvlanmismatch; /* DWORD 14 */ ++ u32 p0ipdroppedtoosmall; /* DWORD 15 */ ++ u32 p0ipdroppedtooshort; /* DWORD 16 */ ++ u32 p0ipdroppedhdrtoosmall; /* DWORD 17 */ ++ u32 p0tcpdroppedlen; /* DWORD 18 */ ++ u32 p0droppedrunt; /* DWORD 19 */ ++ u32 p0recvd64; /* DWORD 20 */ ++ u32 p0recvd65_127; /* DWORD 21 */ ++ u32 p0recvd128_256; /* DWORD 22 */ ++ u32 p0recvd256_511; /* DWORD 23 */ ++ u32 p0recvd512_1023; /* DWORD 24 */ ++ u32 p0recvd1518_1522; /* DWORD 25 */ ++ u32 p0recvd1522_2047; /* DWORD 26 */ ++ u32 p0recvd2048_4095; /* DWORD 27 */ ++ u32 p0recvd4096_8191; /* DWORD 28 */ ++ u32 p0recvd8192_9216; /* DWORD 29 */ ++ u32 p0rcvdipcksmerrs; /* DWORD 30 */ ++ u32 p0recvdtcpcksmerrs; /* DWORD 31 */ ++ u32 p0recvdudpcksmerrs; /* DWORD 32 */ ++ u32 p0recvdnonrsspackets; /* DWORD 33 */ ++ u32 p0recvdippackets; /* DWORD 34 */ ++ u32 p0recvdchute1packets; /* DWORD 35 */ ++ u32 p0recvdchute2packets; /* DWORD 36 */ ++ u32 p0recvdchute3packets; /* DWORD 37 */ ++ u32 p0recvdipsecpackets; /* DWORD 38 */ ++ u32 p0recvdmanagementpackets; /* DWORD 39 */ ++ u32 p0xmitbyteslsd; /* DWORD 40 */ ++ u32 p0xmitbytesmsd; /* DWORD 41 */ ++ u32 p0xmitunicastframes; /* DWORD 42 */ ++ u32 p0xmitmulticastframes; /* DWORD 43 */ ++ u32 p0xmitbroadcastframes; /* DWORD 44 */ ++ u32 p0xmitpauseframes; /* DWORD 45 */ ++ u32 p0xmitcontrolframes; /* DWORD 46 */ ++ u32 p0xmit64; /* DWORD 47 */ ++ u32 p0xmit65_127; /* DWORD 48 */ ++ u32 p0xmit128_256; /* DWORD 49 */ ++ u32 p0xmit256_511; /* DWORD 50 */ ++ u32 p0xmit512_1023; /* DWORD 51 */ ++ u32 p0xmit1518_1522; /* DWORD 52 */ ++ u32 p0xmit1522_2047; /* DWORD 53 */ ++ u32 p0xmit2048_4095; /* DWORD 54 */ ++ u32 p0xmit4096_8191; /* DWORD 55 */ ++ u32 p0xmit8192_9216; /* DWORD 56 */ ++ u32 p0rxfifooverflowdropped; /* DWORD 57 */ ++ u32 p0ipseclookupfaileddropped; /* DWORD 58 */ ++ u32 p1recvdtotalbytesLSD; /* DWORD 59 */ ++ u32 p1recvdtotalbytesMSD; /* DWORD 60 */ ++ u32 p1recvdtotalframes; /* DWORD 61 */ ++ u32 p1recvdunicastframes; /* DWORD 62 */ ++ u32 p1recvdmulticastframes; /* DWORD 63 */ ++ u32 p1recvdbroadcastframes; /* DWORD 64 */ ++ u32 p1crcerrors; /* DWORD 65 */ ++ u32 p1alignmentsymerrs; /* DWORD 66 */ ++ u32 p1pauseframesrecvd; /* DWORD 67 */ ++ u32 p1controlframesrecvd; /* DWORD 68 */ ++ u32 p1inrangelenerrors; /* DWORD 69 */ ++ u32 p1outrangeerrors; /* DWORD 70 */ ++ u32 p1frametoolongerrors; /* DWORD 71 */ ++ u32 p1droppedaddressmatch; /* DWORD 72 */ ++ u32 p1droppedvlanmismatch; /* DWORD 73 */ ++ u32 p1ipdroppedtoosmall; /* DWORD 74 */ ++ u32 p1ipdroppedtooshort; /* DWORD 75 */ ++ u32 p1ipdroppedhdrtoosmall; /* DWORD 76 */ ++ u32 p1tcpdroppedlen; /* DWORD 77 */ ++ u32 p1droppedrunt; /* DWORD 78 */ ++ u32 p1recvd64; /* DWORD 79 */ ++ u32 p1recvd65_127; /* DWORD 80 */ ++ u32 p1recvd128_256; /* DWORD 81 */ ++ u32 p1recvd256_511; /* DWORD 82 */ ++ u32 p1recvd512_1023; /* DWORD 83 */ ++ u32 p1recvd1518_1522; /* DWORD 84 */ ++ u32 p1recvd1522_2047; /* DWORD 85 */ ++ u32 p1recvd2048_4095; /* DWORD 86 */ ++ u32 p1recvd4096_8191; /* DWORD 87 */ ++ u32 p1recvd8192_9216; /* DWORD 88 */ ++ u32 p1rcvdipcksmerrs; /* DWORD 89 */ ++ u32 p1recvdtcpcksmerrs; /* DWORD 90 */ ++ u32 p1recvdudpcksmerrs; /* DWORD 91 */ ++ u32 p1recvdnonrsspackets; /* DWORD 92 */ ++ u32 p1recvdippackets; /* DWORD 93 */ ++ u32 p1recvdchute1packets; /* DWORD 94 */ ++ u32 p1recvdchute2packets; /* DWORD 95 */ ++ u32 p1recvdchute3packets; /* DWORD 96 */ ++ u32 p1recvdipsecpackets; /* DWORD 97 */ ++ u32 p1recvdmanagementpackets; /* DWORD 98 */ ++ u32 p1xmitbyteslsd; /* DWORD 99 */ ++ u32 p1xmitbytesmsd; /* DWORD 100 */ ++ u32 p1xmitunicastframes; /* DWORD 101 */ ++ u32 p1xmitmulticastframes; /* DWORD 102 */ ++ u32 p1xmitbroadcastframes; /* DWORD 103 */ ++ u32 p1xmitpauseframes; /* DWORD 104 */ ++ u32 p1xmitcontrolframes; /* DWORD 105 */ ++ u32 p1xmit64; /* DWORD 106 */ ++ u32 p1xmit65_127; /* DWORD 107 */ ++ u32 p1xmit128_256; /* DWORD 108 */ ++ u32 p1xmit256_511; /* DWORD 109 */ ++ u32 p1xmit512_1023; /* DWORD 110 */ ++ u32 p1xmit1518_1522; /* DWORD 111 */ ++ u32 p1xmit1522_2047; /* DWORD 112 */ ++ u32 p1xmit2048_4095; /* DWORD 113 */ ++ u32 p1xmit4096_8191; /* DWORD 114 */ ++ u32 p1xmit8192_9216; /* DWORD 115 */ ++ u32 p1rxfifooverflowdropped; /* DWORD 116 */ ++ u32 p1ipseclookupfaileddropped; /* DWORD 117 */ ++ u32 pxdroppednopbuf; /* DWORD 118 */ ++ u32 pxdroppednotxpb; /* DWORD 119 */ ++ u32 pxdroppednoipsecbuf; /* DWORD 120 */ ++ u32 pxdroppednoerxdescr; /* DWORD 121 */ ++ u32 pxdroppednotpredescr; /* DWORD 122 */ ++ u32 pxrecvdmanagementportpackets; /* DWORD 123 */ ++ u32 pxrecvdmanagementportbytes; /* DWORD 124 */ ++ u32 pxrecvdmanagementportpauseframes; /* DWORD 125 */ ++ u32 pxrecvdmanagementporterrors; /* DWORD 126 */ ++ u32 pxxmitmanagementportpackets; /* DWORD 127 */ ++ u32 pxxmitmanagementportbytes; /* DWORD 128 */ ++ u32 pxxmitmanagementportpause; /* DWORD 129 */ ++ u32 pxxmitmanagementportrxfifooverflow; /* DWORD 130 */ ++ u32 pxrecvdipsecipcksmerrs; /* DWORD 131 */ ++ u32 pxrecvdtcpsecipcksmerrs; /* DWORD 132 */ ++ u32 pxrecvdudpsecipcksmerrs; /* DWORD 133 */ ++ u32 pxipsecrunt; /* DWORD 134 */ ++ u32 pxipsecaddressmismatchdropped; /* DWORD 135 */ ++ u32 pxipsecrxfifooverflowdropped; /* DWORD 136 */ ++ u32 pxipsecframestoolong; /* DWORD 137 */ ++ u32 pxipsectotalipframes; /* DWORD 138 */ ++ u32 pxipseciptoosmall; /* DWORD 139 */ ++ u32 pxipseciptooshort; /* DWORD 140 */ ++ u32 pxipseciphdrtoosmall; /* DWORD 141 */ ++ u32 pxipsectcphdrbad; /* DWORD 142 */ ++ u32 pxrecvdipsecchute1; /* DWORD 143 */ ++ u32 pxrecvdipsecchute2; /* DWORD 144 */ ++ u32 pxrecvdipsecchute3; /* DWORD 145 */ ++ u32 pxdropped7frags; /* DWORD 146 */ ++ u32 pxdroppedfrags; /* DWORD 147 */ ++ u32 pxdroppedinvalidfragring; /* DWORD 148 */ ++ u32 pxnumforwardedpackets; /* DWORD 149 */ ++} __packed; ++ ++union MIB_ETH_STATISTICS_PARAMS { ++ struct MIB_ETH_STATISTICS_PARAMS_IN request; ++ struct BE_RXF_STATS response; ++} __packed; ++ ++/* ++ * Query ethernet statistics. All domains may issue this command. The ++ * host domain drivers may optionally reset internal statistic counters ++ * with a query. ++ */ ++struct FWCMD_ETH_GET_STATISTICS { ++ union FWCMD_HEADER header; ++ union MIB_ETH_STATISTICS_PARAMS params; ++} __packed; ++ ++ ++struct FWCMD_ETH_ANON_175_REQUEST { ++ u8 port0_promiscuous; ++ u8 port1_promiscuous; ++ u16 rsvd0; ++} __packed; ++ ++struct FWCMD_ETH_ANON_176_RESPONSE { ++ u32 rsvd0; ++} __packed; ++ ++union FWCMD_ETH_ANON_174_PARAMS { ++ struct FWCMD_ETH_ANON_175_REQUEST request; ++ struct FWCMD_ETH_ANON_176_RESPONSE response; ++} __packed; ++ ++/* Enables/Disables promiscuous ethernet receive mode. */ ++struct FWCMD_ETH_PROMISCUOUS { ++ union FWCMD_HEADER header; ++ union FWCMD_ETH_ANON_174_PARAMS params; ++} __packed; ++ ++struct FWCMD_ETH_ANON_178_REQUEST { ++ u32 new_fragsize_log2; ++} __packed; ++ ++struct FWCMD_ETH_ANON_179_RESPONSE { ++ u32 actual_fragsize_log2; ++} __packed; ++ ++union FWCMD_ETH_ANON_177_PARAMS { ++ struct FWCMD_ETH_ANON_178_REQUEST request; ++ struct FWCMD_ETH_ANON_179_RESPONSE response; ++} __packed; ++ ++/* ++ * Sets the Ethernet RX fragment size. Only host (domain 0) networking ++ * drivers may issue this command. This call will fail for non-host ++ * protection domains. In this situation the MCC CQ status will indicate ++ * a failure due to insufficient priviledges. The response should be ++ * ignored, and the driver should use the FWCMD_ETH_GET_FRAG_SIZE to ++ * query the existing ethernet receive fragment size. It must use this ++ * fragment size for all fragments in the ethernet receive ring. If ++ * the command succeeds, the driver must use the frag size indicated ++ * in the command response since the requested frag size may not be applied ++ * until the next reboot. When the requested fragsize matches the response ++ * fragsize, this indicates the request was applied immediately. ++ */ ++struct FWCMD_ETH_SET_RX_FRAG_SIZE { ++ union FWCMD_HEADER header; ++ union FWCMD_ETH_ANON_177_PARAMS params; ++} __packed; ++ ++struct FWCMD_ETH_ANON_181_REQUEST { ++ u32 rsvd0; ++} __packed; ++ ++struct FWCMD_ETH_ANON_182_RESPONSE { ++ u32 actual_fragsize_log2; ++} __packed; ++ ++union FWCMD_ETH_ANON_180_PARAMS { ++ struct FWCMD_ETH_ANON_181_REQUEST request; ++ struct FWCMD_ETH_ANON_182_RESPONSE response; ++} __packed; ++ ++/* ++ * Queries the Ethernet RX fragment size. All domains may issue this ++ * command. The driver should call this command to determine the minimum ++ * required fragment size for the ethernet RX ring buffers. Drivers ++ * may choose to use a larger size for each fragment buffer, but BladeEngine ++ * will use up to the configured minimum required fragsize in each ethernet ++ * receive fragment buffer. For example, if the ethernet receive fragment ++ * size is configured to 4kB, and a driver uses 8kB fragments, a 6kB ++ * ethernet packet received by BladeEngine will be split accross two ++ * of the driver's receive framgents (4kB in one fragment buffer, and ++ * 2kB in the subsequent fragment buffer). ++ */ ++struct FWCMD_ETH_GET_RX_FRAG_SIZE { ++ union FWCMD_HEADER header; ++ union FWCMD_ETH_ANON_180_PARAMS params; ++} __packed; ++ ++#endif /* __fwcmd_eth_bmap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_hdr_bmap.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_hdr_bmap_h__ ++#define __fwcmd_hdr_bmap_h__ ++ ++struct FWCMD_REQUEST_HEADER { ++ u8 opcode; ++ u8 subsystem; ++ u8 port_number; ++ u8 domain; ++ u32 timeout; ++ u32 request_length; ++ u32 rsvd0; ++} __packed; ++ ++struct FWCMD_RESPONSE_HEADER { ++ u8 opcode; ++ u8 subsystem; ++ u8 rsvd0; ++ u8 domain; ++ u8 status; ++ u8 additional_status; ++ u16 rsvd1; ++ u32 response_length; ++ u32 actual_response_length; ++} __packed; ++ ++/* ++ * The firmware/driver overwrites the input FWCMD_REQUEST_HEADER with ++ * the output FWCMD_RESPONSE_HEADER. ++ */ ++union FWCMD_HEADER { ++ struct FWCMD_REQUEST_HEADER request; ++ struct FWCMD_RESPONSE_HEADER response; ++} __packed; ++ ++#endif /* __fwcmd_hdr_bmap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_mcc.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_mcc_amap_h__ ++#define __fwcmd_mcc_amap_h__ ++#include "fwcmd_opcodes.h" ++/* ++ * Where applicable, a WRB, may contain a list of Scatter-gather elements. ++ * Each element supports a 64 bit address and a 32bit length field. ++ */ ++struct BE_MCC_SGE_AMAP { ++ u8 pa_lo[32]; /* DWORD 0 */ ++ u8 pa_hi[32]; /* DWORD 1 */ ++ u8 length[32]; /* DWORD 2 */ ++} __packed; ++struct MCC_SGE_AMAP { ++ u32 dw[3]; ++}; ++/* ++ * The design of an MCC_SGE allows up to 19 elements to be embedded ++ * in a WRB, supporting 64KB data transfers (assuming a 4KB page size). ++ */ ++struct BE_MCC_WRB_PAYLOAD_AMAP { ++ union { ++ struct BE_MCC_SGE_AMAP sgl[19]; ++ u8 embedded[59][32]; /* DWORD 0 */ ++ }; ++} __packed; ++struct MCC_WRB_PAYLOAD_AMAP { ++ u32 dw[59]; ++}; ++ ++/* ++ * This is the structure of the MCC Command WRB for commands ++ * sent to the Management Processing Unit (MPU). See section ++ * for usage in embedded and non-embedded modes. ++ */ ++struct BE_MCC_WRB_AMAP { ++ u8 embedded; /* DWORD 0 */ ++ u8 rsvd0[2]; /* DWORD 0 */ ++ u8 sge_count[5]; /* DWORD 0 */ ++ u8 rsvd1[16]; /* DWORD 0 */ ++ u8 special[8]; /* DWORD 0 */ ++ u8 payload_length[32]; /* DWORD 1 */ ++ u8 tag[2][32]; /* DWORD 2 */ ++ u8 rsvd2[32]; /* DWORD 4 */ ++ struct BE_MCC_WRB_PAYLOAD_AMAP payload; ++} __packed; ++struct MCC_WRB_AMAP { ++ u32 dw[64]; ++}; ++ ++/* This is the structure of the MCC Completion queue entry */ ++struct BE_MCC_CQ_ENTRY_AMAP { ++ u8 completion_status[16]; /* DWORD 0 */ ++ u8 extended_status[16]; /* DWORD 0 */ ++ u8 mcc_tag[2][32]; /* DWORD 1 */ ++ u8 rsvd0[27]; /* DWORD 3 */ ++ u8 consumed; /* DWORD 3 */ ++ u8 completed; /* DWORD 3 */ ++ u8 hpi_buffer_completion; /* DWORD 3 */ ++ u8 async_event; /* DWORD 3 */ ++ u8 valid; /* DWORD 3 */ ++} __packed; ++struct MCC_CQ_ENTRY_AMAP { ++ u32 dw[4]; ++}; ++ ++/* Mailbox structures used by the MPU during bootstrap */ ++struct BE_MCC_MAILBOX_AMAP { ++ struct BE_MCC_WRB_AMAP wrb; ++ struct BE_MCC_CQ_ENTRY_AMAP cq; ++} __packed; ++struct MCC_MAILBOX_AMAP { ++ u32 dw[68]; ++}; ++ ++#endif /* __fwcmd_mcc_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_opcodes.h +@@ -0,0 +1,244 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_opcodes_amap_h__ ++#define __fwcmd_opcodes_amap_h__ ++ ++/* ++ * --- FWCMD_SUBSYSTEMS --- ++ * The commands are grouped into the following subsystems. The subsystem ++ * code along with the opcode uniquely identify a particular fwcmd. ++ */ ++#define FWCMD_SUBSYSTEM_RSVD (0) /* This subsystem is reserved. It is */ ++ /* never used. */ ++#define FWCMD_SUBSYSTEM_COMMON (1) /* CMDs in this group are common to ++ * all subsystems. See ++ * COMMON_SUBSYSTEM_OPCODES for opcodes ++ * and Common Host Configuration CMDs ++ * for the FWCMD descriptions. ++ */ ++#define FWCMD_SUBSYSTEM_COMMON_ISCSI (2) /* CMDs in this group are */ ++ /* ++ * common to Initiator and Target. See ++ * COMMON_ISCSI_SUBSYSTEM_OPCODES and ++ * Common iSCSI Initiator and Target ++ * CMDs for the command descriptions. ++ */ ++#define FWCMD_SUBSYSTEM_ETH (3) /* This subsystem is used to ++ execute Ethernet commands. */ ++ ++#define FWCMD_SUBSYSTEM_TPM (4) /* This subsystem is used ++ to execute TPM commands. */ ++#define FWCMD_SUBSYSTEM_PXE_UNDI (5) /* This subsystem is used ++ * to execute PXE ++ * and UNDI specific commands. ++ */ ++ ++#define FWCMD_SUBSYSTEM_ISCSI_INI (6) /* This subsystem is used to ++ execute ISCSI Initiator ++ specific commands. ++ */ ++#define FWCMD_SUBSYSTEM_ISCSI_TGT (7) /* This subsystem is used ++ to execute iSCSI Target ++ specific commands.between ++ PTL and ARM firmware. ++ */ ++#define FWCMD_SUBSYSTEM_MILI_PTL (8) /* This subsystem is used to ++ execute iSCSI Target specific ++ commands.between MILI ++ and PTL. */ ++#define FWCMD_SUBSYSTEM_MILI_TMD (9) /* This subsystem is used to ++ execute iSCSI Target specific ++ commands between MILI ++ and TMD. */ ++#define FWCMD_SUBSYSTEM_PROXY (11) /* This subsystem is used ++ to execute proxied commands ++ within the host at the ++ explicit request of a ++ non priviledged domain. ++ This 'subsystem' is entirely ++ virtual from the controller ++ and firmware perspective as ++ it is implemented in host ++ drivers. ++ */ ++ ++/* ++ * --- COMMON_SUBSYSTEM_OPCODES --- ++ * These opcodes are common to both networking and storage PCI ++ * functions. They are used to reserve resources and configure ++ * BladeEngine. These opcodes all use the FWCMD_SUBSYSTEM_COMMON ++ * subsystem code. ++ */ ++#define OPCODE_COMMON_NTWK_MAC_QUERY (1) ++#define SUBSYSTEM_COMMON_NTWK_MAC_QUERY (1) ++#define SUBSYSTEM_COMMON_NTWK_MAC_SET (1) ++#define SUBSYSTEM_COMMON_NTWK_MULTICAST_SET (1) ++#define SUBSYSTEM_COMMON_NTWK_VLAN_CONFIG (1) ++#define SUBSYSTEM_COMMON_NTWK_LINK_STATUS_QUERY (1) ++#define SUBSYSTEM_COMMON_READ_FLASHROM (1) ++#define SUBSYSTEM_COMMON_WRITE_FLASHROM (1) ++#define SUBSYSTEM_COMMON_QUERY_MAX_FWCMD_BUFFER_SIZE (1) ++#define SUBSYSTEM_COMMON_ADD_PAGE_TABLES (1) ++#define SUBSYSTEM_COMMON_REMOVE_PAGE_TABLES (1) ++#define SUBSYSTEM_COMMON_RING_DESTROY (1) ++#define SUBSYSTEM_COMMON_CQ_CREATE (1) ++#define SUBSYSTEM_COMMON_EQ_CREATE (1) ++#define SUBSYSTEM_COMMON_ETH_RX_CREATE (1) ++#define SUBSYSTEM_COMMON_ETH_TX_CREATE (1) ++#define SUBSYSTEM_COMMON_ISCSI_DEFQ_CREATE (1) ++#define SUBSYSTEM_COMMON_ISCSI_WRBQ_CREATE (1) ++#define SUBSYSTEM_COMMON_MCC_CREATE (1) ++#define SUBSYSTEM_COMMON_JELL_CONFIG (1) ++#define SUBSYSTEM_COMMON_FORCE_FAILOVER (1) ++#define SUBSYSTEM_COMMON_ADD_TEMPLATE_HEADER_BUFFERS (1) ++#define SUBSYSTEM_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS (1) ++#define SUBSYSTEM_COMMON_POST_ZERO_BUFFER (1) ++#define SUBSYSTEM_COMMON_GET_QOS (1) ++#define SUBSYSTEM_COMMON_SET_QOS (1) ++#define SUBSYSTEM_COMMON_TCP_GET_STATISTICS (1) ++#define SUBSYSTEM_COMMON_SEEPROM_READ (1) ++#define SUBSYSTEM_COMMON_TCP_STATE_QUERY (1) ++#define SUBSYSTEM_COMMON_GET_CNTL_ATTRIBUTES (1) ++#define SUBSYSTEM_COMMON_NOP (1) ++#define SUBSYSTEM_COMMON_NTWK_RX_FILTER (1) ++#define SUBSYSTEM_COMMON_GET_FW_VERSION (1) ++#define SUBSYSTEM_COMMON_SET_FLOW_CONTROL (1) ++#define SUBSYSTEM_COMMON_GET_FLOW_CONTROL (1) ++#define SUBSYSTEM_COMMON_SET_TCP_PARAMETERS (1) ++#define SUBSYSTEM_COMMON_SET_FRAME_SIZE (1) ++#define SUBSYSTEM_COMMON_GET_FAT (1) ++#define SUBSYSTEM_COMMON_MODIFY_EQ_DELAY (1) ++#define SUBSYSTEM_COMMON_FIRMWARE_CONFIG (1) ++#define SUBSYSTEM_COMMON_ENABLE_DISABLE_DOMAINS (1) ++#define SUBSYSTEM_COMMON_GET_DOMAIN_CONFIG (1) ++#define SUBSYSTEM_COMMON_SET_VLD_CONFIG (1) ++#define SUBSYSTEM_COMMON_GET_VLD_CONFIG (1) ++#define SUBSYSTEM_COMMON_GET_PORT_EQUALIZATION (1) ++#define SUBSYSTEM_COMMON_SET_PORT_EQUALIZATION (1) ++#define SUBSYSTEM_COMMON_RED_CONFIG (1) ++#define OPCODE_COMMON_NTWK_MAC_SET (2) ++#define OPCODE_COMMON_NTWK_MULTICAST_SET (3) ++#define OPCODE_COMMON_NTWK_VLAN_CONFIG (4) ++#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY (5) ++#define OPCODE_COMMON_READ_FLASHROM (6) ++#define OPCODE_COMMON_WRITE_FLASHROM (7) ++#define OPCODE_COMMON_QUERY_MAX_FWCMD_BUFFER_SIZE (8) ++#define OPCODE_COMMON_ADD_PAGE_TABLES (9) ++#define OPCODE_COMMON_REMOVE_PAGE_TABLES (10) ++#define OPCODE_COMMON_RING_DESTROY (11) ++#define OPCODE_COMMON_CQ_CREATE (12) ++#define OPCODE_COMMON_EQ_CREATE (13) ++#define OPCODE_COMMON_ETH_RX_CREATE (14) ++#define OPCODE_COMMON_ETH_TX_CREATE (15) ++#define OPCODE_COMMON_NET_RESERVED0 (16) /* Reserved */ ++#define OPCODE_COMMON_NET_RESERVED1 (17) /* Reserved */ ++#define OPCODE_COMMON_NET_RESERVED2 (18) /* Reserved */ ++#define OPCODE_COMMON_ISCSI_DEFQ_CREATE (19) ++#define OPCODE_COMMON_ISCSI_WRBQ_CREATE (20) ++#define OPCODE_COMMON_MCC_CREATE (21) ++#define OPCODE_COMMON_JELL_CONFIG (22) ++#define OPCODE_COMMON_FORCE_FAILOVER (23) ++#define OPCODE_COMMON_ADD_TEMPLATE_HEADER_BUFFERS (24) ++#define OPCODE_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS (25) ++#define OPCODE_COMMON_POST_ZERO_BUFFER (26) ++#define OPCODE_COMMON_GET_QOS (27) ++#define OPCODE_COMMON_SET_QOS (28) ++#define OPCODE_COMMON_TCP_GET_STATISTICS (29) ++#define OPCODE_COMMON_SEEPROM_READ (30) ++#define OPCODE_COMMON_TCP_STATE_QUERY (31) ++#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES (32) ++#define OPCODE_COMMON_NOP (33) ++#define OPCODE_COMMON_NTWK_RX_FILTER (34) ++#define OPCODE_COMMON_GET_FW_VERSION (35) ++#define OPCODE_COMMON_SET_FLOW_CONTROL (36) ++#define OPCODE_COMMON_GET_FLOW_CONTROL (37) ++#define OPCODE_COMMON_SET_TCP_PARAMETERS (38) ++#define OPCODE_COMMON_SET_FRAME_SIZE (39) ++#define OPCODE_COMMON_GET_FAT (40) ++#define OPCODE_COMMON_MODIFY_EQ_DELAY (41) ++#define OPCODE_COMMON_FIRMWARE_CONFIG (42) ++#define OPCODE_COMMON_ENABLE_DISABLE_DOMAINS (43) ++#define OPCODE_COMMON_GET_DOMAIN_CONFIG (44) ++#define OPCODE_COMMON_SET_VLD_CONFIG (45) ++#define OPCODE_COMMON_GET_VLD_CONFIG (46) ++#define OPCODE_COMMON_GET_PORT_EQUALIZATION (47) ++#define OPCODE_COMMON_SET_PORT_EQUALIZATION (48) ++#define OPCODE_COMMON_RED_CONFIG (49) ++ ++ ++ ++/* ++ * --- ETH_SUBSYSTEM_OPCODES --- ++ * These opcodes are used for configuring the Ethernet interfaces. These ++ * opcodes all use the FWCMD_SUBSYSTEM_ETH subsystem code. ++ */ ++#define OPCODE_ETH_RSS_CONFIG (1) ++#define OPCODE_ETH_ACPI_CONFIG (2) ++#define SUBSYSTEM_ETH_RSS_CONFIG (3) ++#define SUBSYSTEM_ETH_ACPI_CONFIG (3) ++#define OPCODE_ETH_PROMISCUOUS (3) ++#define SUBSYSTEM_ETH_PROMISCUOUS (3) ++#define SUBSYSTEM_ETH_GET_STATISTICS (3) ++#define SUBSYSTEM_ETH_GET_RX_FRAG_SIZE (3) ++#define SUBSYSTEM_ETH_SET_RX_FRAG_SIZE (3) ++#define OPCODE_ETH_GET_STATISTICS (4) ++#define OPCODE_ETH_GET_RX_FRAG_SIZE (5) ++#define OPCODE_ETH_SET_RX_FRAG_SIZE (6) ++ ++ ++ ++ ++ ++/* ++ * --- MCC_STATUS_CODE --- ++ * These are the global status codes used by all subsystems ++ */ ++#define MCC_STATUS_SUCCESS (0) /* Indicates a successful ++ completion of the command */ ++#define MCC_STATUS_INSUFFICIENT_PRIVILEGES (1) /* The client does not have ++ sufficient privileges to ++ execute the command */ ++#define MCC_STATUS_INVALID_PARAMETER (2) /* A parameter in the command ++ was invalid. The extended ++ status contains the index ++ of the parameter */ ++#define MCC_STATUS_INSUFFICIENT_RESOURCES (3) /* There are insufficient ++ chip resources to execute ++ the command */ ++#define MCC_STATUS_QUEUE_FLUSHING (4) /* The command is completing ++ because the queue was ++ getting flushed */ ++#define MCC_STATUS_DMA_FAILED (5) /* The command is completing ++ with a DMA error */ ++ ++/* ++ * --- MGMT_ERROR_CODES --- ++ * Error Codes returned in the status field of the FWCMD response header ++ */ ++#define MGMT_STATUS_SUCCESS (0) /* The FWCMD completed ++ without errors */ ++#define MGMT_STATUS_FAILED (1) /* Error status in the Status ++ field of the ++ struct FWCMD_RESPONSE_HEADER */ ++#define MGMT_STATUS_ILLEGAL_REQUEST (2) /* Invalid FWCMD opcode */ ++#define MGMT_STATUS_ILLEGAL_FIELD (3) /* Invalid parameter in ++ the FWCMD payload */ ++ ++#endif /* __fwcmd_opcodes_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/fwcmd_types_bmap.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __fwcmd_types_bmap_h__ ++#define __fwcmd_types_bmap_h__ ++ ++/* MAC address format */ ++struct MAC_ADDRESS_FORMAT { ++ u16 SizeOfStructure; ++ u8 MACAddress[6]; ++} __packed; ++ ++#endif /* __fwcmd_types_bmap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/host_struct.h +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __host_struct_amap_h__ ++#define __host_struct_amap_h__ ++#include "be_cm.h" ++#include "be_common.h" ++#include "descriptors.h" ++ ++/* --- EQ_COMPLETION_MAJOR_CODE_ENUM --- */ ++#define EQ_MAJOR_CODE_COMPLETION (0) /* Completion event on a */ ++ /* qcompletion ueue. */ ++#define EQ_MAJOR_CODE_ETH (1) /* Affiliated Ethernet Event. */ ++#define EQ_MAJOR_CODE_RESERVED (2) /* Reserved */ ++#define EQ_MAJOR_CODE_RDMA (3) /* Affiliated RDMA Event. */ ++#define EQ_MAJOR_CODE_ISCSI (4) /* Affiliated ISCSI Event */ ++#define EQ_MAJOR_CODE_UNAFFILIATED (5) /* Unaffiliated Event */ ++ ++/* --- EQ_COMPLETION_MINOR_CODE_ENUM --- */ ++#define EQ_MINOR_CODE_COMPLETION (0) /* Completion event on a */ ++ /* completion queue. */ ++#define EQ_MINOR_CODE_OTHER (1) /* Other Event (TBD). */ ++ ++/* Queue Entry Definition for all 4 byte event queue types. */ ++struct BE_EQ_ENTRY_AMAP { ++ u8 Valid; /* DWORD 0 */ ++ u8 MajorCode[3]; /* DWORD 0 */ ++ u8 MinorCode[12]; /* DWORD 0 */ ++ u8 ResourceID[16]; /* DWORD 0 */ ++} __packed; ++struct EQ_ENTRY_AMAP { ++ u32 dw[1]; ++}; ++ ++/* ++ * --- ETH_EVENT_CODE --- ++ * These codes are returned by the MPU when one of these events has occurred, ++ * and the event is configured to report to an Event Queue when an event ++ * is detected. ++ */ ++#define ETH_EQ_LINK_STATUS (0) /* Link status change event */ ++ /* detected. */ ++#define ETH_EQ_WATERMARK (1) /* watermark event detected. */ ++#define ETH_EQ_MAGIC_PKT (2) /* magic pkt event detected. */ ++#define ETH_EQ_ACPI_PKT0 (3) /* ACPI interesting packet */ ++ /* detected. */ ++#define ETH_EQ_ACPI_PKT1 (3) /* ACPI interesting packet */ ++ /* detected. */ ++#define ETH_EQ_ACPI_PKT2 (3) /* ACPI interesting packet */ ++ /* detected. */ ++#define ETH_EQ_ACPI_PKT3 (3) /* ACPI interesting packet */ ++ /* detected. */ ++ ++/* ++ * --- ETH_TX_COMPL_STATUS_ENUM --- ++ * Status codes contained in Ethernet TX completion descriptors. ++ */ ++#define ETH_COMP_VALID (0) ++#define ETH_COMP_ERROR (1) ++#define ETH_COMP_INVALID (15) ++ ++/* ++ * --- ETH_TX_COMPL_PORT_ENUM --- ++ * Port indicator contained in Ethernet TX completion descriptors. ++ */ ++#define ETH_COMP_PORT0 (0) ++#define ETH_COMP_PORT1 (1) ++#define ETH_COMP_MGMT (2) ++ ++/* ++ * --- ETH_TX_COMPL_CT_ENUM --- ++ * Completion type indicator contained in Ethernet TX completion descriptors. ++ */ ++#define ETH_COMP_ETH (0) ++ ++/* ++ * Work request block that the driver issues to the chip for ++ * Ethernet transmissions. All control fields must be valid in each WRB for ++ * a message. The controller, as specified by the flags, optionally writes ++ * an entry to the Completion Ring and generate an event. ++ */ ++struct BE_ETH_WRB_AMAP { ++ u8 frag_pa_hi[32]; /* DWORD 0 */ ++ u8 frag_pa_lo[32]; /* DWORD 1 */ ++ u8 complete; /* DWORD 2 */ ++ u8 event; /* DWORD 2 */ ++ u8 crc; /* DWORD 2 */ ++ u8 forward; /* DWORD 2 */ ++ u8 ipsec; /* DWORD 2 */ ++ u8 mgmt; /* DWORD 2 */ ++ u8 ipcs; /* DWORD 2 */ ++ u8 udpcs; /* DWORD 2 */ ++ u8 tcpcs; /* DWORD 2 */ ++ u8 lso; /* DWORD 2 */ ++ u8 last; /* DWORD 2 */ ++ u8 vlan; /* DWORD 2 */ ++ u8 dbg[3]; /* DWORD 2 */ ++ u8 hash_val[3]; /* DWORD 2 */ ++ u8 lso_mss[14]; /* DWORD 2 */ ++ u8 frag_len[16]; /* DWORD 3 */ ++ u8 vlan_tag[16]; /* DWORD 3 */ ++} __packed; ++struct ETH_WRB_AMAP { ++ u32 dw[4]; ++}; ++ ++/* This is an Ethernet transmit completion descriptor */ ++struct BE_ETH_TX_COMPL_AMAP { ++ u8 user_bytes[16]; /* DWORD 0 */ ++ u8 nwh_bytes[8]; /* DWORD 0 */ ++ u8 lso; /* DWORD 0 */ ++ u8 rsvd0[7]; /* DWORD 0 */ ++ u8 wrb_index[16]; /* DWORD 1 */ ++ u8 ct[2]; /* DWORD 1 */ ++ u8 port[2]; /* DWORD 1 */ ++ u8 rsvd1[8]; /* DWORD 1 */ ++ u8 status[4]; /* DWORD 1 */ ++ u8 rsvd2[16]; /* DWORD 2 */ ++ u8 ringid[11]; /* DWORD 2 */ ++ u8 hash_val[4]; /* DWORD 2 */ ++ u8 valid; /* DWORD 2 */ ++ u8 rsvd3[32]; /* DWORD 3 */ ++} __packed; ++struct ETH_TX_COMPL_AMAP { ++ u32 dw[4]; ++}; ++ ++/* Ethernet Receive Buffer descriptor */ ++struct BE_ETH_RX_D_AMAP { ++ u8 fragpa_hi[32]; /* DWORD 0 */ ++ u8 fragpa_lo[32]; /* DWORD 1 */ ++} __packed; ++struct ETH_RX_D_AMAP { ++ u32 dw[2]; ++}; ++ ++/* This is an Ethernet Receive Completion Descriptor */ ++struct BE_ETH_RX_COMPL_AMAP { ++ u8 vlan_tag[16]; /* DWORD 0 */ ++ u8 pktsize[14]; /* DWORD 0 */ ++ u8 port; /* DWORD 0 */ ++ u8 rsvd0; /* DWORD 0 */ ++ u8 err; /* DWORD 1 */ ++ u8 rsshp; /* DWORD 1 */ ++ u8 ipf; /* DWORD 1 */ ++ u8 tcpf; /* DWORD 1 */ ++ u8 udpf; /* DWORD 1 */ ++ u8 ipcksm; /* DWORD 1 */ ++ u8 tcpcksm; /* DWORD 1 */ ++ u8 udpcksm; /* DWORD 1 */ ++ u8 macdst[6]; /* DWORD 1 */ ++ u8 vtp; /* DWORD 1 */ ++ u8 vtm; /* DWORD 1 */ ++ u8 fragndx[10]; /* DWORD 1 */ ++ u8 ct[2]; /* DWORD 1 */ ++ u8 ipsec; /* DWORD 1 */ ++ u8 numfrags[3]; /* DWORD 1 */ ++ u8 rsvd1[31]; /* DWORD 2 */ ++ u8 valid; /* DWORD 2 */ ++ u8 rsshash[32]; /* DWORD 3 */ ++} __packed; ++struct ETH_RX_COMPL_AMAP { ++ u32 dw[4]; ++}; ++ ++#endif /* __host_struct_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/hwlib.h +@@ -0,0 +1,829 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#ifndef __hwlib_h__ ++#define __hwlib_h__ ++ ++#include ++#include ++#include ++#include ++ ++#include "regmap.h" /* srcgen array map output */ ++ ++#include "asyncmesg.h" ++#include "fwcmd_opcodes.h" ++#include "post_codes.h" ++#include "fwcmd_mcc.h" ++ ++#include "fwcmd_types_bmap.h" ++#include "fwcmd_common_bmap.h" ++#include "fwcmd_eth_bmap.h" ++#include "bestatus.h" ++/* ++ * ++ * Macros for reading/writing a protection domain or CSR registers ++ * in BladeEngine. ++ */ ++#define PD_READ(fo, field) ioread32((fo)->db_va + \ ++ offsetof(struct BE_PROTECTION_DOMAIN_DBMAP_AMAP, field)/8) ++ ++#define PD_WRITE(fo, field, val) iowrite32(val, (fo)->db_va + \ ++ offsetof(struct BE_PROTECTION_DOMAIN_DBMAP_AMAP, field)/8) ++ ++#define CSR_READ(fo, field) ioread32((fo)->csr_va + \ ++ offsetof(struct BE_BLADE_ENGINE_CSRMAP_AMAP, field)/8) ++ ++#define CSR_WRITE(fo, field, val) iowrite32(val, (fo)->csr_va + \ ++ offsetof(struct BE_BLADE_ENGINE_CSRMAP_AMAP, field)/8) ++ ++#define PCICFG0_READ(fo, field) ioread32((fo)->pci_va + \ ++ offsetof(struct BE_PCICFG0_CSRMAP_AMAP, field)/8) ++ ++#define PCICFG0_WRITE(fo, field, val) iowrite32(val, (fo)->pci_va + \ ++ offsetof(struct BE_PCICFG0_CSRMAP_AMAP, field)/8) ++ ++#define PCICFG1_READ(fo, field) ioread32((fo)->pci_va + \ ++ offsetof(struct BE_PCICFG1_CSRMAP_AMAP, field)/8) ++ ++#define PCICFG1_WRITE(fo, field, val) iowrite32(val, (fo)->pci_va + \ ++ offsetof(struct BE_PCICFG1_CSRMAP_AMAP, field)/8) ++ ++#ifdef BE_DEBUG ++#define ASSERT(c) BUG_ON(!(c)); ++#else ++#define ASSERT(c) ++#endif ++ ++/* debug levels */ ++enum BE_DEBUG_LEVELS { ++ DL_ALWAYS = 0, /* cannot be masked */ ++ DL_ERR = 0x1, /* errors that should never happen */ ++ DL_WARN = 0x2, /* something questionable. ++ recoverable errors */ ++ DL_NOTE = 0x4, /* infrequent, important debug info */ ++ DL_INFO = 0x8, /* debug information */ ++ DL_VERBOSE = 0x10, /* detailed info, such as buffer traces */ ++ BE_DL_MIN_VALUE = 0x1, /* this is the min value used */ ++ BE_DL_MAX_VALUE = 0x80 /* this is the higheset value used */ ++} ; ++ ++extern unsigned int trace_level; ++ ++#define TRACE(lm, fmt, args...) { \ ++ if (trace_level & lm) { \ ++ printk(KERN_NOTICE "BE: %s:%d \n" fmt, \ ++ __FILE__ , __LINE__ , ## args); \ ++ } \ ++ } ++ ++static inline unsigned int be_trace_set_level(unsigned int level) ++{ ++ unsigned int old_level = trace_level; ++ trace_level = level; ++ return old_level; ++} ++ ++#define be_trace_get_level() trace_level ++/* ++ * Returns number of pages spanned by the size of data ++ * starting at the given address. ++ */ ++#define PAGES_SPANNED(_address, _size) \ ++ ((u32)((((size_t)(_address) & (PAGE_SIZE - 1)) + \ ++ (_size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)) ++/* Byte offset into the page corresponding to given address */ ++#define OFFSET_IN_PAGE(_addr_) ((size_t)(_addr_) & (PAGE_SIZE-1)) ++ ++/* ++ * circular subtract. ++ * Returns a - b assuming a circular number system, where a and b are ++ * in range (0, maxValue-1). If a==b, zero is returned so the ++ * highest value possible with this subtraction is maxValue-1. ++ */ ++static inline u32 be_subc(u32 a, u32 b, u32 max) ++{ ++ ASSERT(a <= max && b <= max); ++ ASSERT(max > 0); ++ return (a >= b ? (a - b) : (max - b + a)); ++} ++ ++static inline u32 be_addc(u32 a, u32 b, u32 max) ++{ ++ ASSERT(a < max); ++ ASSERT(max > 0); ++ return ((max - a > b) ? (a + b) : (b + a - max)); ++} ++ ++/* descriptor for a physically contiguous memory used for ring */ ++struct ring_desc { ++ u32 length; /* length in bytes */ ++ void *va; /* virtual address */ ++ u64 pa; /* bus address */ ++} ; ++ ++/* ++ * This structure stores information about a ring shared between hardware ++ * and software. Each ring is allocated by the driver in the uncached ++ * extension and mapped into BladeEngine's unified table. ++ */ ++struct mp_ring { ++ u32 pages; /* queue size in pages */ ++ u32 id; /* queue id assigned by beklib */ ++ u32 num; /* number of elements in queue */ ++ u32 cidx; /* consumer index */ ++ u32 pidx; /* producer index -- not used by most rings */ ++ u32 itemSize; /* size in bytes of one object */ ++ ++ void *va; /* The virtual address of the ring. ++ This should be last to allow 32 & 64 ++ bit debugger extensions to work. */ ++} ; ++ ++/*----------- amap bit filed get / set macros and functions -----*/ ++/* ++ * Structures defined in the map header files (under fw/amap/) with names ++ * in the format BE__AMAP are pseudo structures with members ++ * of type u8. These structures are templates that are used in ++ * conjuntion with the structures with names in the format ++ * _AMAP to calculate the bit masks and bit offsets to get or set ++ * bit fields in structures. The structures _AMAP are arrays ++ * of 32 bits words and have the correct size. The following macros ++ * provide convenient ways to get and set the various members ++ * in the structures without using strucctures with bit fields. ++ * Always use the macros AMAP_GET_BITS_PTR and AMAP_SET_BITS_PTR ++ * macros to extract and set various members. ++ */ ++ ++/* ++ * Returns the a bit mask for the register that is NOT shifted into location. ++ * That means return values always look like: 0x1, 0xFF, 0x7FF, etc... ++ */ ++static inline u32 amap_mask(u32 bit_size) ++{ ++ return (bit_size == 32 ? 0xFFFFFFFF : (1 << bit_size) - 1); ++} ++ ++#define AMAP_BIT_MASK(_struct_, field) \ ++ amap_mask(AMAP_BIT_SIZE(_struct_, field)) ++ ++/* ++ * non-optimized set bits function. First clears the bits and then assigns them. ++ * This does not require knowledge of the particular DWORD you are setting. ++ * e.g. AMAP_SET_BITS_PTR (struct, field1, &contextMemory, 123); ++ */ ++static inline void ++amap_set(void *ptr, u32 dw_offset, u32 mask, u32 offset, u32 value) ++{ ++ u32 *dw = (u32 *)ptr; ++ *(dw + dw_offset) &= ~(mask << offset); ++ *(dw + dw_offset) |= (mask & value) << offset; ++} ++ ++#define AMAP_SET_BITS_PTR(_struct_, field, _structPtr_, val) \ ++ amap_set(_structPtr_, AMAP_WORD_OFFSET(_struct_, field), \ ++ AMAP_BIT_MASK(_struct_, field), AMAP_BIT_OFFSET(_struct_, field), val) ++ ++/* ++ * Non-optimized routine that gets the bits without knowing the correct DWORD. ++ * e.g. fieldValue = AMAP_GET_BITS_PTR (struct, field1, &contextMemory); ++ */ ++static inline u32 ++amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset) ++{ ++ u32 *dw = (u32 *)ptr; ++ return mask & (*(dw + dw_offset) >> offset); ++} ++#define AMAP_GET_BITS_PTR(_struct_, field, _structPtr_) \ ++ amap_get(_structPtr_, AMAP_WORD_OFFSET(_struct_, field), \ ++ AMAP_BIT_MASK(_struct_, field), AMAP_BIT_OFFSET(_struct_, field)) ++ ++/* Returns 0-31 representing bit offset within a DWORD of a bitfield. */ ++#define AMAP_BIT_OFFSET(_struct_, field) \ ++ (offsetof(struct BE_ ## _struct_ ## _AMAP, field) % 32) ++ ++/* Returns 0-n representing DWORD offset of bitfield within the structure. */ ++#define AMAP_WORD_OFFSET(_struct_, field) \ ++ (offsetof(struct BE_ ## _struct_ ## _AMAP, field)/32) ++ ++/* Returns size of bitfield in bits. */ ++#define AMAP_BIT_SIZE(_struct_, field) \ ++ sizeof(((struct BE_ ## _struct_ ## _AMAP*)0)->field) ++ ++struct be_mcc_wrb_response_copy { ++ u16 length; /* bytes in response */ ++ u16 fwcmd_offset; /* offset within the wrb of the response */ ++ void *va; /* user's va to copy response into */ ++ ++} ; ++typedef void (*mcc_wrb_cqe_callback) (void *context, int status, ++ struct MCC_WRB_AMAP *optional_wrb); ++struct be_mcc_wrb_context { ++ ++ mcc_wrb_cqe_callback internal_cb; /* Function to call on ++ completion */ ++ void *internal_cb_context; /* Parameter to pass ++ to completion function */ ++ ++ mcc_wrb_cqe_callback cb; /* Function to call on completion */ ++ void *cb_context; /* Parameter to pass to completion function */ ++ ++ int *users_final_status; /* pointer to a local ++ variable for synchronous ++ commands */ ++ struct MCC_WRB_AMAP *wrb; /* pointer to original wrb for embedded ++ commands only */ ++ struct list_head next; /* links context structs together in ++ free list */ ++ ++ struct be_mcc_wrb_response_copy copy; /* Optional parameters to copy ++ embedded response to user's va */ ++ ++#if defined(BE_DEBUG) ++ u16 subsystem, opcode; /* Track this FWCMD for debug builds. */ ++ struct MCC_WRB_AMAP *ring_wrb; ++ u32 consumed_count; ++#endif ++} ; ++ ++/* ++ Represents a function object for network or storage. This ++ is used to manage per-function resources like MCC CQs, etc. ++*/ ++struct be_function_object { ++ ++ u32 magic; /*!< magic for detecting memory corruption. */ ++ ++ /* PCI BAR mapped addresses */ ++ u8 __iomem *csr_va; /* CSR */ ++ u8 __iomem *db_va; /* Door Bell */ ++ u8 __iomem *pci_va; /* PCI config space */ ++ u32 emulate; /* if set, MPU is not available. ++ Emulate everything. */ ++ u32 pend_queue_driving; /* if set, drive the queued WRBs ++ after releasing the WRB lock */ ++ ++ spinlock_t post_lock; /* lock for verifying one thread posting wrbs */ ++ spinlock_t cq_lock; /* lock for verifying one thread ++ processing cq */ ++ spinlock_t mcc_context_lock; /* lock for protecting mcc ++ context free list */ ++ unsigned long post_irq; ++ unsigned long cq_irq; ++ ++ u32 type; ++ u32 pci_function_number; ++ ++ struct be_mcc_object *mcc; /* mcc rings. */ ++ ++ struct { ++ struct MCC_MAILBOX_AMAP *va; /* VA to the mailbox */ ++ u64 pa; /* PA to the mailbox */ ++ u32 length; /* byte length of mailbox */ ++ ++ /* One default context struct used for posting at ++ * least one MCC_WRB ++ */ ++ struct be_mcc_wrb_context default_context; ++ bool default_context_allocated; ++ } mailbox; ++ ++ struct { ++ ++ /* Wake on lans configured. */ ++ u32 wol_bitmask; /* bits 0,1,2,3 are set if ++ corresponding index is enabled */ ++ } config; ++ ++ ++ struct BE_FIRMWARE_CONFIG fw_config; ++} ; ++ ++/* ++ Represents an Event Queue ++*/ ++struct be_eq_object { ++ u32 magic; ++ atomic_t ref_count; ++ ++ struct be_function_object *parent_function; ++ ++ struct list_head eq_list; ++ struct list_head cq_list_head; ++ ++ u32 eq_id; ++ void *cb_context; ++ ++} ; ++ ++/* ++ Manages a completion queue ++*/ ++struct be_cq_object { ++ u32 magic; ++ atomic_t ref_count; ++ ++ struct be_function_object *parent_function; ++ struct be_eq_object *eq_object; ++ ++ struct list_head cq_list; ++ struct list_head cqlist_for_eq; ++ ++ void *va; ++ u32 num_entries; ++ ++ void *cb_context; ++ ++ u32 cq_id; ++ ++} ; ++ ++/* ++ Manages an ethernet send queue ++*/ ++struct be_ethsq_object { ++ u32 magic; ++ ++ struct list_head list; ++ ++ struct be_function_object *parent_function; ++ struct be_cq_object *cq_object; ++ u32 bid; ++ ++} ; ++ ++/* ++@brief ++ Manages an ethernet receive queue ++*/ ++struct be_ethrq_object { ++ u32 magic; ++ struct list_head list; ++ struct be_function_object *parent_function; ++ u32 rid; ++ struct be_cq_object *cq_object; ++ struct be_cq_object *rss_cq_object[4]; ++ ++} ; ++ ++/* ++ Manages an MCC ++*/ ++typedef void (*mcc_async_event_callback) (void *context, u32 event_code, ++ void *event); ++struct be_mcc_object { ++ u32 magic; ++ ++ struct be_function_object *parent_function; ++ struct list_head mcc_list; ++ ++ struct be_cq_object *cq_object; ++ ++ /* Async event callback for MCC CQ. */ ++ mcc_async_event_callback async_cb; ++ void *async_context; ++ ++ struct { ++ struct be_mcc_wrb_context *base; ++ u32 num; ++ struct list_head list_head; ++ } wrb_context; ++ ++ struct { ++ struct ring_desc *rd; ++ struct mp_ring ring; ++ } sq; ++ ++ struct { ++ struct mp_ring ring; ++ } cq; ++ ++ u32 processing; /* flag indicating that one thread ++ is processing CQ */ ++ u32 rearm; /* doorbell rearm setting to make ++ sure the active processing thread */ ++ /* rearms the CQ if any of the threads requested it. */ ++ ++ struct list_head backlog; ++ u32 backlog_length; ++ u32 driving_backlog; ++ u32 consumed_index; ++ ++} ; ++ ++ ++/* Queue context header -- the required software information for ++ * queueing a WRB. ++ */ ++struct be_queue_driver_context { ++ mcc_wrb_cqe_callback internal_cb; /* Function to call on ++ completion */ ++ void *internal_cb_context; /* Parameter to pass ++ to completion function */ ++ ++ mcc_wrb_cqe_callback cb; /* Function to call on completion */ ++ void *cb_context; /* Parameter to pass to completion function */ ++ ++ struct be_mcc_wrb_response_copy copy; /* Optional parameters to copy ++ embedded response to user's va */ ++ void *optional_fwcmd_va; ++ struct list_head list; ++ u32 bytes; ++} ; ++ ++/* ++ * Common MCC WRB header that all commands require. ++ */ ++struct be_mcc_wrb_header { ++ u8 rsvd[offsetof(struct BE_MCC_WRB_AMAP, payload)/8]; ++} ; ++ ++/* ++ * All non embedded commands supported by hwlib functions only allow ++ * 1 SGE. This queue context handles them all. ++ */ ++struct be_nonembedded_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct MCC_SGE_AMAP sge[1]; ++} ; ++ ++/* ++ * ------------------------------------------------------------------------ ++ * This section contains the specific queue struct for each command. ++ * The user could always provide a be_generic_q_ctxt but this is a ++ * rather large struct. By using the specific struct, memory consumption ++ * can be reduced. ++ * ------------------------------------------------------------------------ ++ */ ++ ++struct be_link_status_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY fwcmd; ++} ; ++ ++struct be_multicast_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_COMMON_NTWK_MULTICAST_SET fwcmd; ++} ; ++ ++ ++struct be_vlan_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_COMMON_NTWK_VLAN_CONFIG fwcmd; ++} ; ++ ++struct be_promiscuous_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_ETH_PROMISCUOUS fwcmd; ++} ; ++ ++struct be_force_failover_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_COMMON_FORCE_FAILOVER fwcmd; ++} ; ++ ++ ++struct be_rxf_filter_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_COMMON_NTWK_RX_FILTER fwcmd; ++} ; ++ ++struct be_eq_modify_delay_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct FWCMD_COMMON_MODIFY_EQ_DELAY fwcmd; ++} ; ++ ++/* ++ * The generic context is the largest size that would be required. ++ * It is the software context plus an entire WRB. ++ */ ++struct be_generic_q_ctxt { ++ struct be_queue_driver_context context; ++ struct be_mcc_wrb_header wrb_header; ++ struct MCC_WRB_PAYLOAD_AMAP payload; ++} ; ++ ++/* ++ * Types for the BE_QUEUE_CONTEXT object. ++ */ ++#define BE_QUEUE_INVALID (0) ++#define BE_QUEUE_LINK_STATUS (0xA006) ++#define BE_QUEUE_ETH_STATS (0xA007) ++#define BE_QUEUE_TPM_STATS (0xA008) ++#define BE_QUEUE_TCP_STATS (0xA009) ++#define BE_QUEUE_MULTICAST (0xA00A) ++#define BE_QUEUE_VLAN (0xA00B) ++#define BE_QUEUE_RSS (0xA00C) ++#define BE_QUEUE_FORCE_FAILOVER (0xA00D) ++#define BE_QUEUE_PROMISCUOUS (0xA00E) ++#define BE_QUEUE_WAKE_ON_LAN (0xA00F) ++#define BE_QUEUE_NOP (0xA010) ++ ++/* --- BE_FUNCTION_ENUM --- */ ++#define BE_FUNCTION_TYPE_ISCSI (0) ++#define BE_FUNCTION_TYPE_NETWORK (1) ++#define BE_FUNCTION_TYPE_ARM (2) ++ ++/* --- BE_ETH_TX_RING_TYPE_ENUM --- */ ++#define BE_ETH_TX_RING_TYPE_FORWARDING (1) /* Ether ring for forwarding */ ++#define BE_ETH_TX_RING_TYPE_STANDARD (2) /* Ether ring for sending */ ++ /* network packets. */ ++#define BE_ETH_TX_RING_TYPE_BOUND (3) /* Ethernet ring for sending */ ++ /* network packets, bound */ ++ /* to a physical port. */ ++/* ++ * ---------------------------------------------------------------------- ++ * API MACROS ++ * ---------------------------------------------------------------------- ++ */ ++#define BE_FWCMD_NAME(_short_name_) struct FWCMD_##_short_name_ ++#define BE_OPCODE_NAME(_short_name_) OPCODE_##_short_name_ ++#define BE_SUBSYSTEM_NAME(_short_name_) SUBSYSTEM_##_short_name_ ++ ++ ++#define BE_PREPARE_EMBEDDED_FWCMD(_pfob_, _wrb_, _short_name_) \ ++ ((BE_FWCMD_NAME(_short_name_) *) \ ++ be_function_prepare_embedded_fwcmd(_pfob_, _wrb_, \ ++ sizeof(BE_FWCMD_NAME(_short_name_)), \ ++ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.request), \ ++ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.response), \ ++ BE_OPCODE_NAME(_short_name_), \ ++ BE_SUBSYSTEM_NAME(_short_name_))); ++ ++#define BE_PREPARE_NONEMBEDDED_FWCMD(_pfob_, _wrb_, _iva_, _ipa_, _short_name_)\ ++ ((BE_FWCMD_NAME(_short_name_) *) \ ++ be_function_prepare_nonembedded_fwcmd(_pfob_, _wrb_, (_iva_), (_ipa_), \ ++ sizeof(BE_FWCMD_NAME(_short_name_)), \ ++ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.request), \ ++ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.response), \ ++ BE_OPCODE_NAME(_short_name_), \ ++ BE_SUBSYSTEM_NAME(_short_name_))); ++ ++int be_function_object_create(u8 __iomem *csr_va, u8 __iomem *db_va, ++ u8 __iomem *pci_va, u32 function_type, struct ring_desc *mailbox_rd, ++ struct be_function_object *pfob); ++ ++int be_function_object_destroy(struct be_function_object *pfob); ++int be_function_cleanup(struct be_function_object *pfob); ++ ++ ++int be_function_get_fw_version(struct be_function_object *pfob, ++ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD *fw_version, ++ mcc_wrb_cqe_callback cb, void *cb_context); ++ ++ ++int be_eq_modify_delay(struct be_function_object *pfob, ++ u32 num_eq, struct be_eq_object **eq_array, ++ u32 *eq_delay_array, mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_eq_modify_delay_q_ctxt *q_ctxt); ++ ++ ++ ++int be_eq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 eqe_size, u32 num_entries, ++ u32 watermark, u32 timer_delay, struct be_eq_object *eq_object); ++ ++int be_eq_destroy(struct be_eq_object *eq); ++ ++int be_cq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 length, ++ bool solicited_eventable, bool no_delay, ++ u32 wm_thresh, struct be_eq_object *eq_object, ++ struct be_cq_object *cq_object); ++ ++int be_cq_destroy(struct be_cq_object *cq); ++ ++int be_mcc_ring_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 length, ++ struct be_mcc_wrb_context *context_array, ++ u32 num_context_entries, ++ struct be_cq_object *cq, struct be_mcc_object *mcc); ++int be_mcc_ring_destroy(struct be_mcc_object *mcc_object); ++ ++int be_mcc_process_cq(struct be_mcc_object *mcc_object, bool rearm); ++ ++int be_mcc_add_async_event_callback(struct be_mcc_object *mcc_object, ++ mcc_async_event_callback cb, void *cb_context); ++ ++int be_pci_soft_reset(struct be_function_object *pfob); ++ ++ ++int be_drive_POST(struct be_function_object *pfob); ++ ++ ++int be_eth_sq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 length_in_bytes, ++ u32 type, u32 ulp, struct be_cq_object *cq_object, ++ struct be_ethsq_object *eth_sq); ++ ++struct be_eth_sq_parameters { ++ u32 port; ++ u32 rsvd0[2]; ++} ; ++ ++int be_eth_sq_create_ex(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 length_in_bytes, ++ u32 type, u32 ulp, struct be_cq_object *cq_object, ++ struct be_eth_sq_parameters *ex_parameters, ++ struct be_ethsq_object *eth_sq); ++int be_eth_sq_destroy(struct be_ethsq_object *eth_sq); ++ ++int be_eth_set_flow_control(struct be_function_object *pfob, ++ bool txfc_enable, bool rxfc_enable); ++ ++int be_eth_get_flow_control(struct be_function_object *pfob, ++ bool *txfc_enable, bool *rxfc_enable); ++int be_eth_set_qos(struct be_function_object *pfob, u32 max_bps, u32 max_pps); ++ ++int be_eth_get_qos(struct be_function_object *pfob, u32 *max_bps, u32 *max_pps); ++ ++int be_eth_set_frame_size(struct be_function_object *pfob, ++ u32 *tx_frame_size, u32 *rx_frame_size); ++ ++int be_eth_rq_create(struct be_function_object *pfob, ++ struct ring_desc *rd, struct be_cq_object *cq_object, ++ struct be_cq_object *bcmc_cq_object, ++ struct be_ethrq_object *eth_rq); ++ ++int be_eth_rq_destroy(struct be_ethrq_object *eth_rq); ++ ++int be_eth_rq_destroy_options(struct be_ethrq_object *eth_rq, bool flush, ++ mcc_wrb_cqe_callback cb, void *cb_context); ++int be_eth_rq_set_frag_size(struct be_function_object *pfob, ++ u32 new_frag_size_bytes, u32 *actual_frag_size_bytes); ++int be_eth_rq_get_frag_size(struct be_function_object *pfob, ++ u32 *frag_size_bytes); ++ ++void *be_function_prepare_embedded_fwcmd(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, ++ u32 payload_length, u32 request_length, ++ u32 response_length, u32 opcode, u32 subsystem); ++void *be_function_prepare_nonembedded_fwcmd(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, void *fwcmd_header_va, u64 fwcmd_header_pa, ++ u32 payload_length, u32 request_length, u32 response_length, ++ u32 opcode, u32 subsystem); ++ ++ ++struct MCC_WRB_AMAP * ++be_function_peek_mcc_wrb(struct be_function_object *pfob); ++ ++int be_rxf_mac_address_read_write(struct be_function_object *pfob, ++ bool port1, bool mac1, bool mgmt, ++ bool write, bool permanent, u8 *mac_address, ++ mcc_wrb_cqe_callback cb, ++ void *cb_context); ++ ++int be_rxf_multicast_config(struct be_function_object *pfob, ++ bool promiscuous, u32 num, u8 *mac_table, ++ mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_multicast_q_ctxt *q_ctxt); ++ ++int be_rxf_vlan_config(struct be_function_object *pfob, ++ bool promiscuous, u32 num, u16 *vlan_tag_array, ++ mcc_wrb_cqe_callback cb, void *cb_context, ++ struct be_vlan_q_ctxt *q_ctxt); ++ ++ ++int be_rxf_link_status(struct be_function_object *pfob, ++ struct BE_LINK_STATUS *link_status, ++ mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_link_status_q_ctxt *q_ctxt); ++ ++ ++int be_rxf_query_eth_statistics(struct be_function_object *pfob, ++ struct FWCMD_ETH_GET_STATISTICS *va_for_fwcmd, ++ u64 pa_for_fwcmd, mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_nonembedded_q_ctxt *q_ctxt); ++ ++int be_rxf_promiscuous(struct be_function_object *pfob, ++ bool enable_port0, bool enable_port1, ++ mcc_wrb_cqe_callback cb, void *cb_context, ++ struct be_promiscuous_q_ctxt *q_ctxt); ++ ++ ++int be_rxf_filter_config(struct be_function_object *pfob, ++ struct NTWK_RX_FILTER_SETTINGS *settings, ++ mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ struct be_rxf_filter_q_ctxt *q_ctxt); ++ ++/* ++ * ------------------------------------------------------ ++ * internal functions used by hwlib ++ * ------------------------------------------------------ ++ */ ++ ++ ++int be_function_ring_destroy(struct be_function_object *pfob, ++ u32 id, u32 ring_type, mcc_wrb_cqe_callback cb, ++ void *cb_context, ++ mcc_wrb_cqe_callback internal_cb, ++ void *internal_callback_context); ++ ++int be_function_post_mcc_wrb(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, ++ struct be_generic_q_ctxt *q_ctxt, ++ mcc_wrb_cqe_callback cb, void *cb_context, ++ mcc_wrb_cqe_callback internal_cb, ++ void *internal_cb_context, void *optional_fwcmd_va, ++ struct be_mcc_wrb_response_copy *response_copy); ++ ++int be_function_queue_mcc_wrb(struct be_function_object *pfob, ++ struct be_generic_q_ctxt *q_ctxt); ++ ++/* ++ * ------------------------------------------------------ ++ * MCC QUEUE ++ * ------------------------------------------------------ ++ */ ++ ++int be_mpu_init_mailbox(struct be_function_object *pfob, struct ring_desc *rd); ++ ++ ++struct MCC_WRB_AMAP * ++_be_mpu_peek_ring_wrb(struct be_mcc_object *mcc, bool driving_queue); ++ ++struct be_mcc_wrb_context * ++_be_mcc_allocate_wrb_context(struct be_function_object *pfob); ++ ++void _be_mcc_free_wrb_context(struct be_function_object *pfob, ++ struct be_mcc_wrb_context *context); ++ ++int _be_mpu_post_wrb_mailbox(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, struct be_mcc_wrb_context *wrb_context); ++ ++int _be_mpu_post_wrb_ring(struct be_mcc_object *mcc, ++ struct MCC_WRB_AMAP *wrb, struct be_mcc_wrb_context *wrb_context); ++ ++void be_drive_mcc_wrb_queue(struct be_mcc_object *mcc); ++ ++ ++/* ++ * ------------------------------------------------------ ++ * Ring Sizes ++ * ------------------------------------------------------ ++ */ ++static inline u32 be_ring_encoding_to_length(u32 encoding, u32 object_size) ++{ ++ ++ ASSERT(encoding != 1); /* 1 is rsvd */ ++ ASSERT(encoding < 16); ++ ASSERT(object_size > 0); ++ ++ if (encoding == 0) /* 32k deep */ ++ encoding = 16; ++ ++ return (1 << (encoding - 1)) * object_size; ++} ++ ++static inline ++u32 be_ring_length_to_encoding(u32 length_in_bytes, u32 object_size) ++{ ++ ++ u32 count, encoding; ++ ++ ASSERT(object_size > 0); ++ ASSERT(length_in_bytes % object_size == 0); ++ ++ count = length_in_bytes / object_size; ++ ++ ASSERT(count > 1); ++ ASSERT(count <= 32 * 1024); ++ ASSERT(length_in_bytes <= 8 * PAGE_SIZE); /* max ring size in UT */ ++ ++ encoding = __ilog2_u32(count) + 1; ++ ++ if (encoding == 16) ++ encoding = 0; /* 32k deep */ ++ ++ return encoding; ++} ++ ++void be_rd_to_pa_list(struct ring_desc *rd, struct PHYS_ADDR *pa_list, ++ u32 max_num); ++#endif /* __hwlib_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/Kconfig +@@ -0,0 +1,7 @@ ++config BENET ++ tristate "ServerEngines 10Gb NIC - BladeEngine" ++ depends on PCI && INET ++ select INET_LRO ++ help ++ This driver implements the NIC functionality for ServerEngines ++ 10Gb network adapter BladeEngine (EC 3210). +--- /dev/null ++++ b/drivers/staging/benet/MAINTAINERS +@@ -0,0 +1,6 @@ ++SERVER ENGINES 10Gbe NIC - BLADE-ENGINE ++P: Subbu Seetharaman ++M: subbus@serverengines.com ++L: netdev@vger.kernel.org ++W: http://www.serverengines.com ++S: Supported +--- /dev/null ++++ b/drivers/staging/benet/Makefile +@@ -0,0 +1,14 @@ ++# ++# Makefile to build the network driver for ServerEngine's BladeEngine ++# ++obj-$(CONFIG_BENET) += benet.o ++ ++benet-y := be_init.o \ ++ be_int.o \ ++ be_netif.o \ ++ be_ethtool.o \ ++ funcobj.o \ ++ cq.o \ ++ eq.o \ ++ mpu.o \ ++ eth.o +--- /dev/null ++++ b/drivers/staging/benet/mpu.c +@@ -0,0 +1,1364 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++#include ++#include "hwlib.h" ++#include "bestatus.h" ++ ++static ++inline void mp_ring_create(struct mp_ring *ring, u32 num, u32 size, void *va) ++{ ++ ASSERT(ring); ++ memset(ring, 0, sizeof(struct mp_ring)); ++ ring->num = num; ++ ring->pages = DIV_ROUND_UP(num * size, PAGE_SIZE); ++ ring->itemSize = size; ++ ring->va = va; ++} ++ ++/* ++ * ----------------------------------------------------------------------- ++ * Interface for 2 index rings. i.e. consumer/producer rings ++ * -------------------------------------------------------------------------- ++ */ ++ ++/* Returns number items pending on ring. */ ++static inline u32 mp_ring_num_pending(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ if (ring->num == 0) ++ return 0; ++ return be_subc(ring->pidx, ring->cidx, ring->num); ++} ++ ++/* Returns number items free on ring. */ ++static inline u32 mp_ring_num_empty(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ return ring->num - 1 - mp_ring_num_pending(ring); ++} ++ ++/* Consume 1 item */ ++static inline void mp_ring_consume(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ ASSERT(ring->pidx != ring->cidx); ++ ++ ring->cidx = be_addc(ring->cidx, 1, ring->num); ++} ++ ++/* Produce 1 item */ ++static inline void mp_ring_produce(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ ring->pidx = be_addc(ring->pidx, 1, ring->num); ++} ++ ++/* Consume count items */ ++static inline void mp_ring_consume_multiple(struct mp_ring *ring, u32 count) ++{ ++ ASSERT(ring); ++ ASSERT(mp_ring_num_pending(ring) >= count); ++ ring->cidx = be_addc(ring->cidx, count, ring->num); ++} ++ ++static inline void *mp_ring_item(struct mp_ring *ring, u32 index) ++{ ++ ASSERT(ring); ++ ASSERT(index < ring->num); ++ ASSERT(ring->itemSize > 0); ++ return (u8 *) ring->va + index * ring->itemSize; ++} ++ ++/* Ptr to produce item */ ++static inline void *mp_ring_producer_ptr(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ return mp_ring_item(ring, ring->pidx); ++} ++ ++/* ++ * Returns a pointer to the current location in the ring. ++ * This is used for rings with 1 index. ++ */ ++static inline void *mp_ring_current(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ ASSERT(ring->pidx == 0); /* not used */ ++ ++ return mp_ring_item(ring, ring->cidx); ++} ++ ++/* ++ * Increment index for rings with only 1 index. ++ * This is used for rings with 1 index. ++ */ ++static inline void *mp_ring_next(struct mp_ring *ring) ++{ ++ ASSERT(ring); ++ ASSERT(ring->num > 0); ++ ASSERT(ring->pidx == 0); /* not used */ ++ ++ ring->cidx = be_addc(ring->cidx, 1, ring->num); ++ return mp_ring_current(ring); ++} ++ ++/* ++ This routine waits for a previously posted mailbox WRB to be completed. ++ Specifically it waits for the mailbox to say that it's ready to accept ++ more data by setting the LSB of the mailbox pd register to 1. ++ ++ pcontroller - The function object to post this data to ++ ++ IRQL < DISPATCH_LEVEL ++*/ ++static void be_mcc_mailbox_wait(struct be_function_object *pfob) ++{ ++ struct MPU_MAILBOX_DB_AMAP mailbox_db; ++ u32 i = 0; ++ u32 ready; ++ ++ if (pfob->emulate) { ++ /* No waiting for mailbox in emulated mode. */ ++ return; ++ } ++ ++ mailbox_db.dw[0] = PD_READ(pfob, mcc_bootstrap_db); ++ ready = AMAP_GET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db); ++ ++ while (ready == false) { ++ if ((++i & 0x3FFFF) == 0) { ++ TRACE(DL_WARN, "Waiting for mailbox ready - %dk polls", ++ i / 1000); ++ } ++ udelay(1); ++ mailbox_db.dw[0] = PD_READ(pfob, mcc_bootstrap_db); ++ ready = AMAP_GET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db); ++ } ++} ++ ++/* ++ This routine tells the MCC mailbox that there is data to processed ++ in the mailbox. It does this by setting the physical address for the ++ mailbox location and clearing the LSB. This routine returns immediately ++ and does not wait for the WRB to be processed. ++ ++ pcontroller - The function object to post this data to ++ ++ IRQL < DISPATCH_LEVEL ++ ++*/ ++static void be_mcc_mailbox_notify(struct be_function_object *pfob) ++{ ++ struct MPU_MAILBOX_DB_AMAP mailbox_db; ++ u32 pa; ++ ++ ASSERT(pfob->mailbox.pa); ++ ASSERT(pfob->mailbox.va); ++ ++ /* If emulated, do not ring the mailbox */ ++ if (pfob->emulate) { ++ TRACE(DL_WARN, "MPU disabled. Skipping mailbox notify."); ++ return; ++ } ++ ++ /* form the higher bits in the address */ ++ mailbox_db.dw[0] = 0; /* init */ ++ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, hi, &mailbox_db, 1); ++ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db, 0); ++ ++ /* bits 34 to 63 */ ++ pa = (u32) (pfob->mailbox.pa >> 34); ++ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, address, &mailbox_db, pa); ++ ++ /* Wait for the MPU to be ready */ ++ be_mcc_mailbox_wait(pfob); ++ ++ /* Ring doorbell 1st time */ ++ PD_WRITE(pfob, mcc_bootstrap_db, mailbox_db.dw[0]); ++ ++ /* Wait for 1st write to be acknowledged. */ ++ be_mcc_mailbox_wait(pfob); ++ ++ /* lower bits 30 bits from 4th bit (bits 4 to 33)*/ ++ pa = (u32) (pfob->mailbox.pa >> 4) & 0x3FFFFFFF; ++ ++ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, hi, &mailbox_db, 0); ++ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db, 0); ++ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, address, &mailbox_db, pa); ++ ++ /* Ring doorbell 2nd time */ ++ PD_WRITE(pfob, mcc_bootstrap_db, mailbox_db.dw[0]); ++} ++ ++/* ++ This routine tells the MCC mailbox that there is data to processed ++ in the mailbox. It does this by setting the physical address for the ++ mailbox location and clearing the LSB. This routine spins until the ++ MPU writes a 1 into the LSB indicating that the data has been received ++ and is ready to be processed. ++ ++ pcontroller - The function object to post this data to ++ ++ IRQL < DISPATCH_LEVEL ++*/ ++static void ++be_mcc_mailbox_notify_and_wait(struct be_function_object *pfob) ++{ ++ /* ++ * Notify it ++ */ ++ be_mcc_mailbox_notify(pfob); ++ /* ++ * Now wait for completion of WRB ++ */ ++ be_mcc_mailbox_wait(pfob); ++} ++ ++void ++be_mcc_process_cqe(struct be_function_object *pfob, ++ struct MCC_CQ_ENTRY_AMAP *cqe) ++{ ++ struct be_mcc_wrb_context *wrb_context = NULL; ++ u32 offset, status; ++ u8 *p; ++ ++ ASSERT(cqe); ++ /* ++ * A command completed. Commands complete out-of-order. ++ * Determine which command completed from the TAG. ++ */ ++ offset = offsetof(struct BE_MCC_CQ_ENTRY_AMAP, mcc_tag)/8; ++ p = (u8 *) cqe + offset; ++ wrb_context = (struct be_mcc_wrb_context *)(void *)(size_t)(*(u64 *)p); ++ ASSERT(wrb_context); ++ ++ /* ++ * Perform a response copy if requested. ++ * Only copy data if the FWCMD is successful. ++ */ ++ status = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, completion_status, cqe); ++ if (status == MGMT_STATUS_SUCCESS && wrb_context->copy.length > 0) { ++ ASSERT(wrb_context->wrb); ++ ASSERT(wrb_context->copy.va); ++ p = (u8 *)wrb_context->wrb + ++ offsetof(struct BE_MCC_WRB_AMAP, payload)/8; ++ memcpy(wrb_context->copy.va, ++ (u8 *)p + wrb_context->copy.fwcmd_offset, ++ wrb_context->copy.length); ++ } ++ ++ if (status) ++ status = BE_NOT_OK; ++ /* internal callback */ ++ if (wrb_context->internal_cb) { ++ wrb_context->internal_cb(wrb_context->internal_cb_context, ++ status, wrb_context->wrb); ++ } ++ ++ /* callback */ ++ if (wrb_context->cb) { ++ wrb_context->cb(wrb_context->cb_context, ++ status, wrb_context->wrb); ++ } ++ /* Free the context structure */ ++ _be_mcc_free_wrb_context(pfob, wrb_context); ++} ++ ++void be_drive_mcc_wrb_queue(struct be_mcc_object *mcc) ++{ ++ struct be_function_object *pfob = NULL; ++ int status = BE_PENDING; ++ struct be_generic_q_ctxt *q_ctxt; ++ struct MCC_WRB_AMAP *wrb; ++ struct MCC_WRB_AMAP *queue_wrb; ++ u32 length, payload_length, sge_count, embedded; ++ unsigned long irql; ++ ++ BUILD_BUG_ON((sizeof(struct be_generic_q_ctxt) < ++ sizeof(struct be_queue_driver_context) + ++ sizeof(struct MCC_WRB_AMAP))); ++ pfob = mcc->parent_function; ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ if (mcc->driving_backlog) { ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return; ++ } ++ /* Acquire the flag to limit 1 thread to redrive posts. */ ++ mcc->driving_backlog = 1; ++ ++ while (!list_empty(&mcc->backlog)) { ++ wrb = _be_mpu_peek_ring_wrb(mcc, true); /* Driving the queue */ ++ if (!wrb) ++ break; /* No space in the ring yet. */ ++ /* Get the next queued entry to process. */ ++ q_ctxt = list_first_entry(&mcc->backlog, ++ struct be_generic_q_ctxt, context.list); ++ list_del(&q_ctxt->context.list); ++ pfob->mcc->backlog_length--; ++ /* ++ * Compute the required length of the WRB. ++ * Since the queue element may be smaller than ++ * the complete WRB, copy only the required number of bytes. ++ */ ++ queue_wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header; ++ embedded = AMAP_GET_BITS_PTR(MCC_WRB, embedded, queue_wrb); ++ if (embedded) { ++ payload_length = AMAP_GET_BITS_PTR(MCC_WRB, ++ payload_length, queue_wrb); ++ length = sizeof(struct be_mcc_wrb_header) + ++ payload_length; ++ } else { ++ sge_count = AMAP_GET_BITS_PTR(MCC_WRB, sge_count, ++ queue_wrb); ++ ASSERT(sge_count == 1); /* only 1 frag. */ ++ length = sizeof(struct be_mcc_wrb_header) + ++ sge_count * sizeof(struct MCC_SGE_AMAP); ++ } ++ ++ /* ++ * Truncate the length based on the size of the ++ * queue element. Some elements that have output parameters ++ * can be smaller than the payload_length field would ++ * indicate. We really only need to copy the request ++ * parameters, not the response. ++ */ ++ length = min(length, (u32) (q_ctxt->context.bytes - ++ offsetof(struct be_generic_q_ctxt, wrb_header))); ++ ++ /* Copy the queue element WRB into the ring. */ ++ memcpy(wrb, &q_ctxt->wrb_header, length); ++ ++ /* Post the wrb. This should not fail assuming we have ++ * enough context structs. */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, ++ q_ctxt->context.cb, q_ctxt->context.cb_context, ++ q_ctxt->context.internal_cb, ++ q_ctxt->context.internal_cb_context, ++ q_ctxt->context.optional_fwcmd_va, ++ &q_ctxt->context.copy); ++ ++ if (status == BE_SUCCESS) { ++ /* ++ * Synchronous completion. Since it was queued, ++ * we will invoke the callback. ++ * To the user, this is an asynchronous request. ++ */ ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ ++ ASSERT(q_ctxt->context.cb); ++ ++ q_ctxt->context.cb( ++ q_ctxt->context.cb_context, ++ BE_SUCCESS, NULL); ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ } else if (status != BE_PENDING) { ++ /* ++ * Another resource failed. Should never happen ++ * if we have sufficient MCC_WRB_CONTEXT structs. ++ * Return to head of the queue. ++ */ ++ TRACE(DL_WARN, "Failed to post a queued WRB. 0x%x", ++ status); ++ list_add(&q_ctxt->context.list, &mcc->backlog); ++ pfob->mcc->backlog_length++; ++ break; ++ } ++ } ++ ++ /* Free the flag to limit 1 thread to redrive posts. */ ++ mcc->driving_backlog = 0; ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++} ++ ++/* This function asserts that the WRB was consumed in order. */ ++#ifdef BE_DEBUG ++u32 be_mcc_wrb_consumed_in_order(struct be_mcc_object *mcc, ++ struct MCC_CQ_ENTRY_AMAP *cqe) ++{ ++ struct be_mcc_wrb_context *wrb_context = NULL; ++ u32 wrb_index; ++ u32 wrb_consumed_in_order; ++ u32 offset; ++ u8 *p; ++ ++ ASSERT(cqe); ++ /* ++ * A command completed. Commands complete out-of-order. ++ * Determine which command completed from the TAG. ++ */ ++ offset = offsetof(struct BE_MCC_CQ_ENTRY_AMAP, mcc_tag)/8; ++ p = (u8 *) cqe + offset; ++ wrb_context = (struct be_mcc_wrb_context *)(void *)(size_t)(*(u64 *)p); ++ ++ ASSERT(wrb_context); ++ ++ wrb_index = (u32) (((u64)(size_t)wrb_context->ring_wrb - ++ (u64)(size_t)mcc->sq.ring.va) / sizeof(struct MCC_WRB_AMAP)); ++ ++ ASSERT(wrb_index < mcc->sq.ring.num); ++ ++ wrb_consumed_in_order = (u32) (wrb_index == mcc->consumed_index); ++ mcc->consumed_index = be_addc(mcc->consumed_index, 1, mcc->sq.ring.num); ++ return wrb_consumed_in_order; ++} ++#endif ++ ++int be_mcc_process_cq(struct be_mcc_object *mcc, bool rearm) ++{ ++ struct be_function_object *pfob = NULL; ++ struct MCC_CQ_ENTRY_AMAP *cqe; ++ struct CQ_DB_AMAP db; ++ struct mp_ring *cq_ring = &mcc->cq.ring; ++ struct mp_ring *mp_ring = &mcc->sq.ring; ++ u32 num_processed = 0; ++ u32 consumed = 0, valid, completed, cqe_consumed, async_event; ++ ++ pfob = mcc->parent_function; ++ ++ spin_lock_irqsave(&pfob->cq_lock, pfob->cq_irq); ++ ++ /* ++ * Verify that only one thread is processing the CQ at once. ++ * We cannot hold the lock while processing the CQ due to ++ * the callbacks into the OS. Therefore, this flag is used ++ * to control it. If any of the threads want to ++ * rearm the CQ, we need to honor that. ++ */ ++ if (mcc->processing != 0) { ++ mcc->rearm = mcc->rearm || rearm; ++ goto Error; ++ } else { ++ mcc->processing = 1; /* lock processing for this thread. */ ++ mcc->rearm = rearm; /* set our rearm setting */ ++ } ++ ++ spin_unlock_irqrestore(&pfob->cq_lock, pfob->cq_irq); ++ ++ cqe = mp_ring_current(cq_ring); ++ valid = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, valid, cqe); ++ while (valid) { ++ ++ if (num_processed >= 8) { ++ /* coalesce doorbells, but free space in cq ++ * ring while processing. */ ++ db.dw[0] = 0; /* clear */ ++ AMAP_SET_BITS_PTR(CQ_DB, qid, &db, cq_ring->id); ++ AMAP_SET_BITS_PTR(CQ_DB, rearm, &db, false); ++ AMAP_SET_BITS_PTR(CQ_DB, event, &db, false); ++ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &db, ++ num_processed); ++ num_processed = 0; ++ ++ PD_WRITE(pfob, cq_db, db.dw[0]); ++ } ++ ++ async_event = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, async_event, cqe); ++ if (async_event) { ++ /* This is an asynchronous event. */ ++ struct ASYNC_EVENT_TRAILER_AMAP *async_trailer = ++ (struct ASYNC_EVENT_TRAILER_AMAP *) ++ ((u8 *) cqe + sizeof(struct MCC_CQ_ENTRY_AMAP) - ++ sizeof(struct ASYNC_EVENT_TRAILER_AMAP)); ++ u32 event_code; ++ async_event = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, ++ async_event, async_trailer); ++ ASSERT(async_event == 1); ++ ++ ++ valid = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, ++ valid, async_trailer); ++ ASSERT(valid == 1); ++ ++ /* Call the async event handler if it is installed. */ ++ if (mcc->async_cb) { ++ event_code = ++ AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, ++ event_code, async_trailer); ++ mcc->async_cb(mcc->async_context, ++ (u32) event_code, (void *) cqe); ++ } ++ ++ } else { ++ /* This is a completion entry. */ ++ ++ /* No vm forwarding in this driver. */ ++ ++ cqe_consumed = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, ++ consumed, cqe); ++ if (cqe_consumed) { ++ /* ++ * A command on the MCC ring was consumed. ++ * Update the consumer index. ++ * These occur in order. ++ */ ++ ASSERT(be_mcc_wrb_consumed_in_order(mcc, cqe)); ++ consumed++; ++ } ++ ++ completed = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, ++ completed, cqe); ++ if (completed) { ++ /* A command completed. Use tag to ++ * determine which command. */ ++ be_mcc_process_cqe(pfob, cqe); ++ } ++ } ++ ++ /* Reset the CQE */ ++ AMAP_SET_BITS_PTR(MCC_CQ_ENTRY, valid, cqe, false); ++ num_processed++; ++ ++ /* Update our tracking for the CQ ring. */ ++ cqe = mp_ring_next(cq_ring); ++ valid = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, valid, cqe); ++ } ++ ++ TRACE(DL_INFO, "num_processed:0x%x, and consumed:0x%x", ++ num_processed, consumed); ++ /* ++ * Grab the CQ lock to synchronize the "rearm" setting for ++ * the doorbell, and for clearing the "processing" flag. ++ */ ++ spin_lock_irqsave(&pfob->cq_lock, pfob->cq_irq); ++ ++ /* ++ * Rearm the cq. This is done based on the global mcc->rearm ++ * flag which combines the rearm parameter from the current ++ * call to process_cq and any other threads ++ * that tried to process the CQ while this one was active. ++ * This handles the situation where a sync. fwcmd was processing ++ * the CQ while the interrupt/dpc tries to process it. ++ * The sync process gets to continue -- but it is now ++ * responsible for the rearming. ++ */ ++ if (num_processed > 0 || mcc->rearm == true) { ++ db.dw[0] = 0; /* clear */ ++ AMAP_SET_BITS_PTR(CQ_DB, qid, &db, cq_ring->id); ++ AMAP_SET_BITS_PTR(CQ_DB, rearm, &db, mcc->rearm); ++ AMAP_SET_BITS_PTR(CQ_DB, event, &db, false); ++ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &db, num_processed); ++ ++ PD_WRITE(pfob, cq_db, db.dw[0]); ++ } ++ /* ++ * Update the consumer index after ringing the CQ doorbell. ++ * We don't want another thread to post more WRBs before we ++ * have CQ space available. ++ */ ++ mp_ring_consume_multiple(mp_ring, consumed); ++ ++ /* Clear the processing flag. */ ++ mcc->processing = 0; ++ ++Error: ++ spin_unlock_irqrestore(&pfob->cq_lock, pfob->cq_irq); ++ /* ++ * Use the local variable to detect if the current thread ++ * holds the WRB post lock. If rearm is false, this is ++ * either a synchronous command, or the upper layer driver is polling ++ * from a thread. We do not drive the queue from that ++ * context since the driver may hold the ++ * wrb post lock already. ++ */ ++ if (rearm) ++ be_drive_mcc_wrb_queue(mcc); ++ else ++ pfob->pend_queue_driving = 1; ++ ++ return BE_SUCCESS; ++} ++ ++/* ++ *============================================================================ ++ * P U B L I C R O U T I N E S ++ *============================================================================ ++ */ ++ ++/* ++ This routine creates an MCC object. This object contains an MCC send queue ++ and a CQ private to the MCC. ++ ++ pcontroller - Handle to a function object ++ ++ EqObject - EQ object that will be used to dispatch this MCC ++ ++ ppMccObject - Pointer to an internal Mcc Object returned. ++ ++ Returns BE_SUCCESS if successfull,, otherwise a useful error code ++ is returned. ++ ++ IRQL < DISPATCH_LEVEL ++ ++*/ ++int ++be_mcc_ring_create(struct be_function_object *pfob, ++ struct ring_desc *rd, u32 length, ++ struct be_mcc_wrb_context *context_array, ++ u32 num_context_entries, ++ struct be_cq_object *cq, struct be_mcc_object *mcc) ++{ ++ int status = 0; ++ ++ struct FWCMD_COMMON_MCC_CREATE *fwcmd = NULL; ++ struct MCC_WRB_AMAP *wrb = NULL; ++ u32 num_entries_encoded, n, i; ++ void *va = NULL; ++ unsigned long irql; ++ ++ if (length < sizeof(struct MCC_WRB_AMAP) * 2) { ++ TRACE(DL_ERR, "Invalid MCC ring length:%d", length); ++ return BE_NOT_OK; ++ } ++ /* ++ * Reduce the actual ring size to be less than the number ++ * of context entries. This ensures that we run out of ++ * ring WRBs first so the queuing works correctly. We never ++ * queue based on context structs. ++ */ ++ if (num_context_entries + 1 < ++ length / sizeof(struct MCC_WRB_AMAP) - 1) { ++ ++ u32 max_length = ++ (num_context_entries + 2) * sizeof(struct MCC_WRB_AMAP); ++ ++ if (is_power_of_2(max_length)) ++ length = __roundup_pow_of_two(max_length+1) / 2; ++ else ++ length = __roundup_pow_of_two(max_length) / 2; ++ ++ ASSERT(length <= max_length); ++ ++ TRACE(DL_WARN, ++ "MCC ring length reduced based on context entries." ++ " length:%d wrbs:%d context_entries:%d", length, ++ (int) (length / sizeof(struct MCC_WRB_AMAP)), ++ num_context_entries); ++ } ++ ++ spin_lock_irqsave(&pfob->post_lock, irql); ++ ++ num_entries_encoded = ++ be_ring_length_to_encoding(length, sizeof(struct MCC_WRB_AMAP)); ++ ++ /* Init MCC object. */ ++ memset(mcc, 0, sizeof(*mcc)); ++ mcc->parent_function = pfob; ++ mcc->cq_object = cq; ++ ++ INIT_LIST_HEAD(&mcc->backlog); ++ ++ wrb = be_function_peek_mcc_wrb(pfob); ++ if (!wrb) { ++ ASSERT(wrb); ++ TRACE(DL_ERR, "No free MCC WRBs in create EQ."); ++ status = BE_STATUS_NO_MCC_WRB; ++ goto error; ++ } ++ /* Prepares an embedded fwcmd, including request/response sizes. */ ++ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_MCC_CREATE); ++ ++ fwcmd->params.request.num_pages = DIV_ROUND_UP(length, PAGE_SIZE); ++ /* ++ * Program MCC ring context ++ */ ++ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, pdid, ++ &fwcmd->params.request.context, 0); ++ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, invalid, ++ &fwcmd->params.request.context, false); ++ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, ring_size, ++ &fwcmd->params.request.context, num_entries_encoded); ++ ++ n = cq->cq_id; ++ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, ++ cq_id, &fwcmd->params.request.context, n); ++ be_rd_to_pa_list(rd, fwcmd->params.request.pages, ++ ARRAY_SIZE(fwcmd->params.request.pages)); ++ /* Post the f/w command */ ++ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL, ++ NULL, NULL, fwcmd, NULL); ++ if (status != BE_SUCCESS) { ++ TRACE(DL_ERR, "MCC to create CQ failed."); ++ goto error; ++ } ++ /* ++ * Create a linked list of context structures ++ */ ++ mcc->wrb_context.base = context_array; ++ mcc->wrb_context.num = num_context_entries; ++ INIT_LIST_HEAD(&mcc->wrb_context.list_head); ++ memset(context_array, 0, ++ sizeof(struct be_mcc_wrb_context) * num_context_entries); ++ for (i = 0; i < mcc->wrb_context.num; i++) { ++ list_add_tail(&context_array[i].next, ++ &mcc->wrb_context.list_head); ++ } ++ ++ /* ++ * ++ * Create an mcc_ring for tracking WRB hw ring ++ */ ++ va = rd->va; ++ ASSERT(va); ++ mp_ring_create(&mcc->sq.ring, length / sizeof(struct MCC_WRB_AMAP), ++ sizeof(struct MCC_WRB_AMAP), va); ++ mcc->sq.ring.id = fwcmd->params.response.id; ++ /* ++ * Init a mcc_ring for tracking the MCC CQ. ++ */ ++ ASSERT(cq->va); ++ mp_ring_create(&mcc->cq.ring, cq->num_entries, ++ sizeof(struct MCC_CQ_ENTRY_AMAP), cq->va); ++ mcc->cq.ring.id = cq->cq_id; ++ ++ /* Force zeroing of CQ. */ ++ memset(cq->va, 0, cq->num_entries * sizeof(struct MCC_CQ_ENTRY_AMAP)); ++ ++ /* Initialize debug index. */ ++ mcc->consumed_index = 0; ++ ++ atomic_inc(&cq->ref_count); ++ pfob->mcc = mcc; ++ ++ TRACE(DL_INFO, "MCC ring created. id:%d bytes:%d cq_id:%d cq_entries:%d" ++ " num_context:%d", mcc->sq.ring.id, length, ++ cq->cq_id, cq->num_entries, num_context_entries); ++ ++error: ++ spin_unlock_irqrestore(&pfob->post_lock, irql); ++ if (pfob->pend_queue_driving && pfob->mcc) { ++ pfob->pend_queue_driving = 0; ++ be_drive_mcc_wrb_queue(pfob->mcc); ++ } ++ return status; ++} ++ ++/* ++ This routine destroys an MCC send queue ++ ++ MccObject - Internal Mcc Object to be destroyed. ++ ++ Returns BE_SUCCESS if successfull, otherwise an error code is returned. ++ ++ IRQL < DISPATCH_LEVEL ++ ++ The caller of this routine must ensure that no other WRB may be posted ++ until this routine returns. ++ ++*/ ++int be_mcc_ring_destroy(struct be_mcc_object *mcc) ++{ ++ int status = 0; ++ struct be_function_object *pfob = mcc->parent_function; ++ ++ ++ ASSERT(mcc->processing == 0); ++ ++ /* ++ * Remove the ring from the function object. ++ * This transitions back to mailbox mode. ++ */ ++ pfob->mcc = NULL; ++ ++ /* Send fwcmd to destroy the queue. (Using the mailbox.) */ ++ status = be_function_ring_destroy(mcc->parent_function, mcc->sq.ring.id, ++ FWCMD_RING_TYPE_MCC, NULL, NULL, NULL, NULL); ++ ASSERT(status == 0); ++ ++ /* Release the SQ reference to the CQ */ ++ atomic_dec(&mcc->cq_object->ref_count); ++ ++ return status; ++} ++ ++static void ++mcc_wrb_sync_cb(void *context, int staus, struct MCC_WRB_AMAP *wrb) ++{ ++ struct be_mcc_wrb_context *wrb_context = ++ (struct be_mcc_wrb_context *) context; ++ ASSERT(wrb_context); ++ *wrb_context->users_final_status = staus; ++} ++ ++/* ++ This routine posts a command to the MCC send queue ++ ++ mcc - Internal Mcc Object to be destroyed. ++ ++ wrb - wrb to post. ++ ++ Returns BE_SUCCESS if successfull, otherwise an error code is returned. ++ ++ IRQL < DISPATCH_LEVEL if CompletionCallback is not NULL ++ IRQL <=DISPATCH_LEVEL if CompletionCallback is NULL ++ ++ If this routine is called with CompletionCallback != NULL the ++ call is considered to be asynchronous and will return as soon ++ as the WRB is posted to the MCC with BE_PENDING. ++ ++ If CompletionCallback is NULL, then this routine will not return until ++ a completion for this MCC command has been processed. ++ If called at DISPATCH_LEVEL the CompletionCallback must be NULL. ++ ++ This routine should only be called if the MPU has been boostraped past ++ mailbox mode. ++ ++ ++*/ ++int ++_be_mpu_post_wrb_ring(struct be_mcc_object *mcc, struct MCC_WRB_AMAP *wrb, ++ struct be_mcc_wrb_context *wrb_context) ++{ ++ ++ struct MCC_WRB_AMAP *ring_wrb = NULL; ++ int status = BE_PENDING; ++ int final_status = BE_PENDING; ++ mcc_wrb_cqe_callback cb = NULL; ++ struct MCC_DB_AMAP mcc_db; ++ u32 embedded; ++ ++ ASSERT(mp_ring_num_empty(&mcc->sq.ring) > 0); ++ /* ++ * Input wrb is most likely the next wrb in the ring, since the client ++ * can peek at the address. ++ */ ++ ring_wrb = mp_ring_producer_ptr(&mcc->sq.ring); ++ if (wrb != ring_wrb) { ++ /* If not equal, copy it into the ring. */ ++ memcpy(ring_wrb, wrb, sizeof(struct MCC_WRB_AMAP)); ++ } ++#ifdef BE_DEBUG ++ wrb_context->ring_wrb = ring_wrb; ++#endif ++ embedded = AMAP_GET_BITS_PTR(MCC_WRB, embedded, ring_wrb); ++ if (embedded) { ++ /* embedded commands will have the response within the WRB. */ ++ wrb_context->wrb = ring_wrb; ++ } else { ++ /* ++ * non-embedded commands will not have the response ++ * within the WRB, and they may complete out-of-order. ++ * The WRB will not be valid to inspect ++ * during the completion. ++ */ ++ wrb_context->wrb = NULL; ++ } ++ cb = wrb_context->cb; ++ ++ if (cb == NULL) { ++ /* Assign our internal callback if this is a ++ * synchronous call. */ ++ wrb_context->cb = mcc_wrb_sync_cb; ++ wrb_context->cb_context = wrb_context; ++ wrb_context->users_final_status = &final_status; ++ } ++ /* Increment producer index */ ++ ++ mcc_db.dw[0] = 0; /* initialize */ ++ AMAP_SET_BITS_PTR(MCC_DB, rid, &mcc_db, mcc->sq.ring.id); ++ AMAP_SET_BITS_PTR(MCC_DB, numPosted, &mcc_db, 1); ++ ++ mp_ring_produce(&mcc->sq.ring); ++ PD_WRITE(mcc->parent_function, mpu_mcc_db, mcc_db.dw[0]); ++ TRACE(DL_INFO, "pidx: %x and cidx: %x.", mcc->sq.ring.pidx, ++ mcc->sq.ring.cidx); ++ ++ if (cb == NULL) { ++ int polls = 0; /* At >= 1 us per poll */ ++ /* Wait until this command completes, polling the CQ. */ ++ do { ++ TRACE(DL_INFO, "FWCMD submitted in the poll mode."); ++ /* Do not rearm CQ in this context. */ ++ be_mcc_process_cq(mcc, false); ++ ++ if (final_status == BE_PENDING) { ++ if ((++polls & 0x7FFFF) == 0) { ++ TRACE(DL_WARN, ++ "Warning : polling MCC CQ for %d" ++ "ms.", polls / 1000); ++ } ++ ++ udelay(1); ++ } ++ ++ /* final_status changed when the command completes */ ++ } while (final_status == BE_PENDING); ++ ++ status = final_status; ++ } ++ ++ return status; ++} ++ ++struct MCC_WRB_AMAP * ++_be_mpu_peek_ring_wrb(struct be_mcc_object *mcc, bool driving_queue) ++{ ++ /* If we have queued items, do not allow a post to bypass the queue. */ ++ if (!driving_queue && !list_empty(&mcc->backlog)) ++ return NULL; ++ ++ if (mp_ring_num_empty(&mcc->sq.ring) <= 0) ++ return NULL; ++ return (struct MCC_WRB_AMAP *) mp_ring_producer_ptr(&mcc->sq.ring); ++} ++ ++int ++be_mpu_init_mailbox(struct be_function_object *pfob, struct ring_desc *mailbox) ++{ ++ ASSERT(mailbox); ++ pfob->mailbox.va = mailbox->va; ++ pfob->mailbox.pa = cpu_to_le64(mailbox->pa); ++ pfob->mailbox.length = mailbox->length; ++ ++ ASSERT(((u32)(size_t)pfob->mailbox.va & 0xf) == 0); ++ ASSERT(((u32)(size_t)pfob->mailbox.pa & 0xf) == 0); ++ /* ++ * Issue the WRB to set MPU endianness ++ */ ++ { ++ u64 *endian_check = (u64 *) (pfob->mailbox.va + ++ offsetof(struct BE_MCC_MAILBOX_AMAP, wrb)/8); ++ *endian_check = 0xFF1234FFFF5678FFULL; ++ } ++ ++ be_mcc_mailbox_notify_and_wait(pfob); ++ ++ return BE_SUCCESS; ++} ++ ++ ++/* ++ This routine posts a command to the MCC mailbox. ++ ++ FuncObj - Function Object to post the WRB on behalf of. ++ wrb - wrb to post. ++ CompletionCallback - Address of a callback routine to invoke once the WRB ++ is completed. ++ CompletionCallbackContext - Opaque context to be passed during the call to ++ the CompletionCallback. ++ Returns BE_SUCCESS if successfull, otherwise an error code is returned. ++ ++ IRQL <=DISPATCH_LEVEL if CompletionCallback is NULL ++ ++ This routine will block until a completion for this MCC command has been ++ processed. If called at DISPATCH_LEVEL the CompletionCallback must be NULL. ++ ++ This routine should only be called if the MPU has not been boostraped past ++ mailbox mode. ++*/ ++int ++_be_mpu_post_wrb_mailbox(struct be_function_object *pfob, ++ struct MCC_WRB_AMAP *wrb, struct be_mcc_wrb_context *wrb_context) ++{ ++ struct MCC_MAILBOX_AMAP *mailbox = NULL; ++ struct MCC_WRB_AMAP *mb_wrb; ++ struct MCC_CQ_ENTRY_AMAP *mb_cq; ++ u32 offset, status; ++ ++ ASSERT(pfob->mcc == NULL); ++ mailbox = pfob->mailbox.va; ++ ASSERT(mailbox); ++ ++ offset = offsetof(struct BE_MCC_MAILBOX_AMAP, wrb)/8; ++ mb_wrb = (struct MCC_WRB_AMAP *) (u8 *)mailbox + offset; ++ if (mb_wrb != wrb) { ++ memset(mailbox, 0, sizeof(*mailbox)); ++ memcpy(mb_wrb, wrb, sizeof(struct MCC_WRB_AMAP)); ++ } ++ /* The callback can inspect the final WRB to get output parameters. */ ++ wrb_context->wrb = mb_wrb; ++ ++ be_mcc_mailbox_notify_and_wait(pfob); ++ ++ /* A command completed. Use tag to determine which command. */ ++ offset = offsetof(struct BE_MCC_MAILBOX_AMAP, cq)/8; ++ mb_cq = (struct MCC_CQ_ENTRY_AMAP *) ((u8 *)mailbox + offset); ++ be_mcc_process_cqe(pfob, mb_cq); ++ ++ status = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, completion_status, mb_cq); ++ if (status) ++ status = BE_NOT_OK; ++ return status; ++} ++ ++struct be_mcc_wrb_context * ++_be_mcc_allocate_wrb_context(struct be_function_object *pfob) ++{ ++ struct be_mcc_wrb_context *context = NULL; ++ unsigned long irq; ++ ++ spin_lock_irqsave(&pfob->mcc_context_lock, irq); ++ ++ if (!pfob->mailbox.default_context_allocated) { ++ /* Use the single default context that we ++ * always have allocated. */ ++ pfob->mailbox.default_context_allocated = true; ++ context = &pfob->mailbox.default_context; ++ } else if (pfob->mcc) { ++ /* Get a context from the free list. If any are available. */ ++ if (!list_empty(&pfob->mcc->wrb_context.list_head)) { ++ context = list_first_entry( ++ &pfob->mcc->wrb_context.list_head, ++ struct be_mcc_wrb_context, next); ++ } ++ } ++ ++ spin_unlock_irqrestore(&pfob->mcc_context_lock, irq); ++ ++ return context; ++} ++ ++void ++_be_mcc_free_wrb_context(struct be_function_object *pfob, ++ struct be_mcc_wrb_context *context) ++{ ++ unsigned long irq; ++ ++ ASSERT(context); ++ /* ++ * Zero during free to try and catch any bugs where the context ++ * is accessed after a free. ++ */ ++ memset(context, 0, sizeof(context)); ++ ++ spin_lock_irqsave(&pfob->mcc_context_lock, irq); ++ ++ if (context == &pfob->mailbox.default_context) { ++ /* Free the default context. */ ++ ASSERT(pfob->mailbox.default_context_allocated); ++ pfob->mailbox.default_context_allocated = false; ++ } else { ++ /* Add to free list. */ ++ ASSERT(pfob->mcc); ++ list_add_tail(&context->next, ++ &pfob->mcc->wrb_context.list_head); ++ } ++ ++ spin_unlock_irqrestore(&pfob->mcc_context_lock, irq); ++} ++ ++int ++be_mcc_add_async_event_callback(struct be_mcc_object *mcc_object, ++ mcc_async_event_callback cb, void *cb_context) ++{ ++ /* Lock against anyone trying to change the callback/context pointers ++ * while being used. */ ++ spin_lock_irqsave(&mcc_object->parent_function->cq_lock, ++ mcc_object->parent_function->cq_irq); ++ ++ /* Assign the async callback. */ ++ mcc_object->async_context = cb_context; ++ mcc_object->async_cb = cb; ++ ++ spin_unlock_irqrestore(&mcc_object->parent_function->cq_lock, ++ mcc_object->parent_function->cq_irq); ++ ++ return BE_SUCCESS; ++} ++ ++#define MPU_EP_CONTROL 0 ++#define MPU_EP_SEMAPHORE 0xac ++ ++/* ++ *------------------------------------------------------------------- ++ * Function: be_wait_for_POST_complete ++ * Waits until the BladeEngine POST completes (either in error or success). ++ * pfob - ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *------------------------------------------------------------------- ++ */ ++static int be_wait_for_POST_complete(struct be_function_object *pfob) ++{ ++ struct MGMT_HBA_POST_STATUS_STRUCT_AMAP status; ++ int s; ++ u32 post_error, post_stage; ++ ++ const u32 us_per_loop = 1000; /* 1000us */ ++ const u32 print_frequency_loops = 1000000 / us_per_loop; ++ const u32 max_loops = 60 * print_frequency_loops; ++ u32 loops = 0; ++ ++ /* ++ * Wait for arm fw indicating it is done or a fatal error happened. ++ * Note: POST can take some time to complete depending on configuration ++ * settings (consider ARM attempts to acquire an IP address ++ * over DHCP!!!). ++ * ++ */ ++ do { ++ status.dw[0] = ioread32(pfob->csr_va + MPU_EP_SEMAPHORE); ++ post_error = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, ++ error, &status); ++ post_stage = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, ++ stage, &status); ++ if (0 == (loops % print_frequency_loops)) { ++ /* Print current status */ ++ TRACE(DL_INFO, "POST status = 0x%x (stage = 0x%x)", ++ status.dw[0], post_stage); ++ } ++ udelay(us_per_loop); ++ } while ((post_error != 1) && ++ (post_stage != POST_STAGE_ARMFW_READY) && ++ (++loops < max_loops)); ++ ++ if (post_error == 1) { ++ TRACE(DL_ERR, "POST error! Status = 0x%x (stage = 0x%x)", ++ status.dw[0], post_stage); ++ s = BE_NOT_OK; ++ } else if (post_stage != POST_STAGE_ARMFW_READY) { ++ TRACE(DL_ERR, "POST time-out! Status = 0x%x (stage = 0x%x)", ++ status.dw[0], post_stage); ++ s = BE_NOT_OK; ++ } else { ++ s = BE_SUCCESS; ++ } ++ return s; ++} ++ ++/* ++ *------------------------------------------------------------------- ++ * Function: be_kickoff_and_wait_for_POST ++ * Interacts with the BladeEngine management processor to initiate POST, and ++ * subsequently waits until POST completes (either in error or success). ++ * The caller must acquire the reset semaphore before initiating POST ++ * to prevent multiple drivers interacting with the management processor. ++ * Once POST is complete the caller must release the reset semaphore. ++ * Callers who only want to wait for POST complete may call ++ * be_wait_for_POST_complete. ++ * pfob - ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *------------------------------------------------------------------- ++ */ ++static int ++be_kickoff_and_wait_for_POST(struct be_function_object *pfob) ++{ ++ struct MGMT_HBA_POST_STATUS_STRUCT_AMAP status; ++ int s; ++ ++ const u32 us_per_loop = 1000; /* 1000us */ ++ const u32 print_frequency_loops = 1000000 / us_per_loop; ++ const u32 max_loops = 5 * print_frequency_loops; ++ u32 loops = 0; ++ u32 post_error, post_stage; ++ ++ /* Wait for arm fw awaiting host ready or a fatal error happened. */ ++ TRACE(DL_INFO, "Wait for BladeEngine ready to POST"); ++ do { ++ status.dw[0] = ioread32(pfob->csr_va + MPU_EP_SEMAPHORE); ++ post_error = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, ++ error, &status); ++ post_stage = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, ++ stage, &status); ++ if (0 == (loops % print_frequency_loops)) { ++ /* Print current status */ ++ TRACE(DL_INFO, "POST status = 0x%x (stage = 0x%x)", ++ status.dw[0], post_stage); ++ } ++ udelay(us_per_loop); ++ } while ((post_error != 1) && ++ (post_stage < POST_STAGE_AWAITING_HOST_RDY) && ++ (++loops < max_loops)); ++ ++ if (post_error == 1) { ++ TRACE(DL_ERR, "Pre-POST error! Status = 0x%x (stage = 0x%x)", ++ status.dw[0], post_stage); ++ s = BE_NOT_OK; ++ } else if (post_stage == POST_STAGE_AWAITING_HOST_RDY) { ++ iowrite32(POST_STAGE_HOST_RDY, pfob->csr_va + MPU_EP_SEMAPHORE); ++ ++ /* Wait for POST to complete */ ++ s = be_wait_for_POST_complete(pfob); ++ } else { ++ /* ++ * Either a timeout waiting for host ready signal or POST has ++ * moved ahead without requiring a host ready signal. ++ * Might as well give POST a chance to complete ++ * (or timeout again). ++ */ ++ s = be_wait_for_POST_complete(pfob); ++ } ++ return s; ++} ++ ++/* ++ *------------------------------------------------------------------- ++ * Function: be_pci_soft_reset ++ * This function is called to issue a BladeEngine soft reset. ++ * Callers should acquire the soft reset semaphore before calling this ++ * function. Additionaly, callers should ensure they cannot be pre-empted ++ * while the routine executes. Upon completion of this routine, callers ++ * should release the reset semaphore. This routine implicitly waits ++ * for BladeEngine POST to complete. ++ * pfob - ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *------------------------------------------------------------------- ++ */ ++int be_pci_soft_reset(struct be_function_object *pfob) ++{ ++ struct PCICFG_SOFT_RESET_CSR_AMAP soft_reset; ++ struct PCICFG_ONLINE0_CSR_AMAP pciOnline0; ++ struct PCICFG_ONLINE1_CSR_AMAP pciOnline1; ++ struct EP_CONTROL_CSR_AMAP epControlCsr; ++ int status = BE_SUCCESS; ++ u32 i, soft_reset_bit; ++ ++ TRACE(DL_NOTE, "PCI reset..."); ++ ++ /* Issue soft reset #1 to get BladeEngine into a known state. */ ++ soft_reset.dw[0] = PCICFG0_READ(pfob, soft_reset); ++ AMAP_SET_BITS_PTR(PCICFG_SOFT_RESET_CSR, softreset, soft_reset.dw, 1); ++ PCICFG0_WRITE(pfob, host_timer_int_ctrl, soft_reset.dw[0]); ++ /* ++ * wait til soft reset is deasserted - hardware ++ * deasserts after some time. ++ */ ++ i = 0; ++ do { ++ udelay(50); ++ soft_reset.dw[0] = PCICFG0_READ(pfob, soft_reset); ++ soft_reset_bit = AMAP_GET_BITS_PTR(PCICFG_SOFT_RESET_CSR, ++ softreset, soft_reset.dw); ++ } while (soft_reset_bit && (i++ < 1024)); ++ if (soft_reset_bit != 0) { ++ TRACE(DL_ERR, "Soft-reset #1 did not deassert as expected."); ++ status = BE_NOT_OK; ++ goto Error_label; ++ } ++ /* Mask everything */ ++ PCICFG0_WRITE(pfob, ue_status_low_mask, 0xFFFFFFFF); ++ PCICFG0_WRITE(pfob, ue_status_hi_mask, 0xFFFFFFFF); ++ /* ++ * Set everything offline except MPU IRAM (it is offline with ++ * the soft-reset, but soft-reset does not reset the PCICFG registers!) ++ */ ++ pciOnline0.dw[0] = 0; ++ pciOnline1.dw[0] = 0; ++ AMAP_SET_BITS_PTR(PCICFG_ONLINE1_CSR, mpu_iram_online, ++ pciOnline1.dw, 1); ++ PCICFG0_WRITE(pfob, online0, pciOnline0.dw[0]); ++ PCICFG0_WRITE(pfob, online1, pciOnline1.dw[0]); ++ ++ udelay(20000); ++ ++ /* Issue soft reset #2. */ ++ AMAP_SET_BITS_PTR(PCICFG_SOFT_RESET_CSR, softreset, soft_reset.dw, 1); ++ PCICFG0_WRITE(pfob, host_timer_int_ctrl, soft_reset.dw[0]); ++ /* ++ * wait til soft reset is deasserted - hardware ++ * deasserts after some time. ++ */ ++ i = 0; ++ do { ++ udelay(50); ++ soft_reset.dw[0] = PCICFG0_READ(pfob, soft_reset); ++ soft_reset_bit = AMAP_GET_BITS_PTR(PCICFG_SOFT_RESET_CSR, ++ softreset, soft_reset.dw); ++ } while (soft_reset_bit && (i++ < 1024)); ++ if (soft_reset_bit != 0) { ++ TRACE(DL_ERR, "Soft-reset #1 did not deassert as expected."); ++ status = BE_NOT_OK; ++ goto Error_label; ++ } ++ ++ ++ udelay(20000); ++ ++ /* Take MPU out of reset. */ ++ ++ epControlCsr.dw[0] = ioread32(pfob->csr_va + MPU_EP_CONTROL); ++ AMAP_SET_BITS_PTR(EP_CONTROL_CSR, CPU_reset, &epControlCsr, 0); ++ iowrite32((u32)epControlCsr.dw[0], pfob->csr_va + MPU_EP_CONTROL); ++ ++ /* Kickoff BE POST and wait for completion */ ++ status = be_kickoff_and_wait_for_POST(pfob); ++ ++Error_label: ++ return status; ++} ++ ++ ++/* ++ *------------------------------------------------------------------- ++ * Function: be_pci_reset_required ++ * This private function is called to detect if a host entity is ++ * required to issue a PCI soft reset and subsequently drive ++ * BladeEngine POST. Scenarios where this is required: ++ * 1) BIOS-less configuration ++ * 2) Hot-swap/plug/power-on ++ * pfob - ++ * return true if a reset is required, false otherwise ++ *------------------------------------------------------------------- ++ */ ++static bool be_pci_reset_required(struct be_function_object *pfob) ++{ ++ struct MGMT_HBA_POST_STATUS_STRUCT_AMAP status; ++ bool do_reset = false; ++ u32 post_error, post_stage; ++ ++ /* ++ * Read the POST status register ++ */ ++ status.dw[0] = ioread32(pfob->csr_va + MPU_EP_SEMAPHORE); ++ post_error = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, error, ++ &status); ++ post_stage = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, stage, ++ &status); ++ if (post_stage <= POST_STAGE_AWAITING_HOST_RDY) { ++ /* ++ * If BladeEngine is waiting for host ready indication, ++ * we want to do a PCI reset. ++ */ ++ do_reset = true; ++ } ++ ++ return do_reset; ++} ++ ++/* ++ *------------------------------------------------------------------- ++ * Function: be_drive_POST ++ * This function is called to drive BladeEngine POST. The ++ * caller should ensure they cannot be pre-empted while this routine executes. ++ * pfob - ++ * return status - BE_SUCCESS (0) on success. Negative error code on failure. ++ *------------------------------------------------------------------- ++ */ ++int be_drive_POST(struct be_function_object *pfob) ++{ ++ int status; ++ ++ if (false != be_pci_reset_required(pfob)) { ++ /* PCI reset is needed (implicitly starts and waits for POST) */ ++ status = be_pci_soft_reset(pfob); ++ } else { ++ /* No PCI reset is needed, start POST */ ++ status = be_kickoff_and_wait_for_POST(pfob); ++ } ++ ++ return status; ++} +--- /dev/null ++++ b/drivers/staging/benet/mpu_context.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __mpu_context_amap_h__ ++#define __mpu_context_amap_h__ ++ ++/* ++ * Management command and control ring context. The MPUs BTLR_CTRL1 CSR ++ * controls the writeback behavior of the producer and consumer index values. ++ */ ++struct BE_MCC_RING_CONTEXT_AMAP { ++ u8 con_index[16]; /* DWORD 0 */ ++ u8 ring_size[4]; /* DWORD 0 */ ++ u8 cq_id[11]; /* DWORD 0 */ ++ u8 rsvd0; /* DWORD 0 */ ++ u8 prod_index[16]; /* DWORD 1 */ ++ u8 pdid[15]; /* DWORD 1 */ ++ u8 invalid; /* DWORD 1 */ ++ u8 cmd_pending_current[7]; /* DWORD 2 */ ++ u8 rsvd1[25]; /* DWORD 2 */ ++ u8 hpi_port_cq_id[11]; /* DWORD 3 */ ++ u8 rsvd2[5]; /* DWORD 3 */ ++ u8 cmd_pending_max[7]; /* DWORD 3 */ ++ u8 rsvd3[9]; /* DWORD 3 */ ++} __packed; ++struct MCC_RING_CONTEXT_AMAP { ++ u32 dw[4]; ++}; ++ ++#endif /* __mpu_context_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/mpu.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __mpu_amap_h__ ++#define __mpu_amap_h__ ++#include "ep.h" ++ ++/* Provide control parameters for the Managment Processor Unit. */ ++struct BE_MPU_CSRMAP_AMAP { ++ struct BE_EP_CSRMAP_AMAP ep; ++ u8 rsvd0[128]; /* DWORD 64 */ ++ u8 rsvd1[32]; /* DWORD 68 */ ++ u8 rsvd2[192]; /* DWORD 69 */ ++ u8 rsvd3[192]; /* DWORD 75 */ ++ u8 rsvd4[32]; /* DWORD 81 */ ++ u8 rsvd5[32]; /* DWORD 82 */ ++ u8 rsvd6[32]; /* DWORD 83 */ ++ u8 rsvd7[32]; /* DWORD 84 */ ++ u8 rsvd8[32]; /* DWORD 85 */ ++ u8 rsvd9[32]; /* DWORD 86 */ ++ u8 rsvd10[32]; /* DWORD 87 */ ++ u8 rsvd11[32]; /* DWORD 88 */ ++ u8 rsvd12[32]; /* DWORD 89 */ ++ u8 rsvd13[32]; /* DWORD 90 */ ++ u8 rsvd14[32]; /* DWORD 91 */ ++ u8 rsvd15[32]; /* DWORD 92 */ ++ u8 rsvd16[32]; /* DWORD 93 */ ++ u8 rsvd17[32]; /* DWORD 94 */ ++ u8 rsvd18[32]; /* DWORD 95 */ ++ u8 rsvd19[32]; /* DWORD 96 */ ++ u8 rsvd20[32]; /* DWORD 97 */ ++ u8 rsvd21[32]; /* DWORD 98 */ ++ u8 rsvd22[32]; /* DWORD 99 */ ++ u8 rsvd23[32]; /* DWORD 100 */ ++ u8 rsvd24[32]; /* DWORD 101 */ ++ u8 rsvd25[32]; /* DWORD 102 */ ++ u8 rsvd26[32]; /* DWORD 103 */ ++ u8 rsvd27[32]; /* DWORD 104 */ ++ u8 rsvd28[96]; /* DWORD 105 */ ++ u8 rsvd29[32]; /* DWORD 108 */ ++ u8 rsvd30[32]; /* DWORD 109 */ ++ u8 rsvd31[32]; /* DWORD 110 */ ++ u8 rsvd32[32]; /* DWORD 111 */ ++ u8 rsvd33[32]; /* DWORD 112 */ ++ u8 rsvd34[96]; /* DWORD 113 */ ++ u8 rsvd35[32]; /* DWORD 116 */ ++ u8 rsvd36[32]; /* DWORD 117 */ ++ u8 rsvd37[32]; /* DWORD 118 */ ++ u8 rsvd38[32]; /* DWORD 119 */ ++ u8 rsvd39[32]; /* DWORD 120 */ ++ u8 rsvd40[32]; /* DWORD 121 */ ++ u8 rsvd41[134][32]; /* DWORD 122 */ ++} __packed; ++struct MPU_CSRMAP_AMAP { ++ u32 dw[256]; ++}; ++ ++#endif /* __mpu_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/pcicfg.h +@@ -0,0 +1,825 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __pcicfg_amap_h__ ++#define __pcicfg_amap_h__ ++ ++/* Vendor and Device ID Register. */ ++struct BE_PCICFG_ID_CSR_AMAP { ++ u8 vendorid[16]; /* DWORD 0 */ ++ u8 deviceid[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ID_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* IO Bar Register. */ ++struct BE_PCICFG_IOBAR_CSR_AMAP { ++ u8 iospace; /* DWORD 0 */ ++ u8 rsvd0[7]; /* DWORD 0 */ ++ u8 iobar[24]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_IOBAR_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Memory BAR 0 Register. */ ++struct BE_PCICFG_MEMBAR0_CSR_AMAP { ++ u8 memspace; /* DWORD 0 */ ++ u8 type[2]; /* DWORD 0 */ ++ u8 pf; /* DWORD 0 */ ++ u8 rsvd0[10]; /* DWORD 0 */ ++ u8 membar0[18]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MEMBAR0_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Memory BAR 1 - Low Address Register. */ ++struct BE_PCICFG_MEMBAR1_LO_CSR_AMAP { ++ u8 memspace; /* DWORD 0 */ ++ u8 type[2]; /* DWORD 0 */ ++ u8 pf; /* DWORD 0 */ ++ u8 rsvd0[13]; /* DWORD 0 */ ++ u8 membar1lo[15]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MEMBAR1_LO_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Memory BAR 1 - High Address Register. */ ++struct BE_PCICFG_MEMBAR1_HI_CSR_AMAP { ++ u8 membar1hi[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MEMBAR1_HI_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Memory BAR 2 - Low Address Register. */ ++struct BE_PCICFG_MEMBAR2_LO_CSR_AMAP { ++ u8 memspace; /* DWORD 0 */ ++ u8 type[2]; /* DWORD 0 */ ++ u8 pf; /* DWORD 0 */ ++ u8 rsvd0[17]; /* DWORD 0 */ ++ u8 membar2lo[11]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MEMBAR2_LO_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Memory BAR 2 - High Address Register. */ ++struct BE_PCICFG_MEMBAR2_HI_CSR_AMAP { ++ u8 membar2hi[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MEMBAR2_HI_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Subsystem Vendor and ID (Function 0) Register. */ ++struct BE_PCICFG_SUBSYSTEM_ID_F0_CSR_AMAP { ++ u8 subsys_vendor_id[16]; /* DWORD 0 */ ++ u8 subsys_id[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_SUBSYSTEM_ID_F0_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Subsystem Vendor and ID (Function 1) Register. */ ++struct BE_PCICFG_SUBSYSTEM_ID_F1_CSR_AMAP { ++ u8 subsys_vendor_id[16]; /* DWORD 0 */ ++ u8 subsys_id[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_SUBSYSTEM_ID_F1_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Semaphore Register. */ ++struct BE_PCICFG_SEMAPHORE_CSR_AMAP { ++ u8 locked; /* DWORD 0 */ ++ u8 rsvd0[31]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_SEMAPHORE_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Soft Reset Register. */ ++struct BE_PCICFG_SOFT_RESET_CSR_AMAP { ++ u8 rsvd0[7]; /* DWORD 0 */ ++ u8 softreset; /* DWORD 0 */ ++ u8 rsvd1[16]; /* DWORD 0 */ ++ u8 nec_ll_rcvdetect_i[8]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_SOFT_RESET_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Unrecoverable Error Status (Low) Register. Each bit corresponds to ++ * an internal Unrecoverable Error. These are set by hardware and may be ++ * cleared by writing a one to the respective bit(s) to be cleared. Any ++ * bit being set that is also unmasked will result in Unrecoverable Error ++ * interrupt notification to the host CPU and/or Server Management chip ++ * and the transitioning of BladeEngine to an Offline state. ++ */ ++struct BE_PCICFG_UE_STATUS_LOW_CSR_AMAP { ++ u8 cev_ue_status; /* DWORD 0 */ ++ u8 ctx_ue_status; /* DWORD 0 */ ++ u8 dbuf_ue_status; /* DWORD 0 */ ++ u8 erx_ue_status; /* DWORD 0 */ ++ u8 host_ue_status; /* DWORD 0 */ ++ u8 mpu_ue_status; /* DWORD 0 */ ++ u8 ndma_ue_status; /* DWORD 0 */ ++ u8 ptc_ue_status; /* DWORD 0 */ ++ u8 rdma_ue_status; /* DWORD 0 */ ++ u8 rxf_ue_status; /* DWORD 0 */ ++ u8 rxips_ue_status; /* DWORD 0 */ ++ u8 rxulp0_ue_status; /* DWORD 0 */ ++ u8 rxulp1_ue_status; /* DWORD 0 */ ++ u8 rxulp2_ue_status; /* DWORD 0 */ ++ u8 tim_ue_status; /* DWORD 0 */ ++ u8 tpost_ue_status; /* DWORD 0 */ ++ u8 tpre_ue_status; /* DWORD 0 */ ++ u8 txips_ue_status; /* DWORD 0 */ ++ u8 txulp0_ue_status; /* DWORD 0 */ ++ u8 txulp1_ue_status; /* DWORD 0 */ ++ u8 uc_ue_status; /* DWORD 0 */ ++ u8 wdma_ue_status; /* DWORD 0 */ ++ u8 txulp2_ue_status; /* DWORD 0 */ ++ u8 host1_ue_status; /* DWORD 0 */ ++ u8 p0_ob_link_ue_status; /* DWORD 0 */ ++ u8 p1_ob_link_ue_status; /* DWORD 0 */ ++ u8 host_gpio_ue_status; /* DWORD 0 */ ++ u8 mbox_netw_ue_status; /* DWORD 0 */ ++ u8 mbox_stor_ue_status; /* DWORD 0 */ ++ u8 axgmac0_ue_status; /* DWORD 0 */ ++ u8 axgmac1_ue_status; /* DWORD 0 */ ++ u8 mpu_intpend_ue_status; /* DWORD 0 */ ++} __packed; ++struct PCICFG_UE_STATUS_LOW_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Unrecoverable Error Status (High) Register. Each bit corresponds to ++ * an internal Unrecoverable Error. These are set by hardware and may be ++ * cleared by writing a one to the respective bit(s) to be cleared. Any ++ * bit being set that is also unmasked will result in Unrecoverable Error ++ * interrupt notification to the host CPU and/or Server Management chip; ++ * and the transitioning of BladeEngine to an Offline state. ++ */ ++struct BE_PCICFG_UE_STATUS_HI_CSR_AMAP { ++ u8 jtag_ue_status; /* DWORD 0 */ ++ u8 lpcmemhost_ue_status; /* DWORD 0 */ ++ u8 mgmt_mac_ue_status; /* DWORD 0 */ ++ u8 mpu_iram_ue_status; /* DWORD 0 */ ++ u8 pcs0online_ue_status; /* DWORD 0 */ ++ u8 pcs1online_ue_status; /* DWORD 0 */ ++ u8 pctl0_ue_status; /* DWORD 0 */ ++ u8 pctl1_ue_status; /* DWORD 0 */ ++ u8 pmem_ue_status; /* DWORD 0 */ ++ u8 rr_ue_status; /* DWORD 0 */ ++ u8 rxpp_ue_status; /* DWORD 0 */ ++ u8 txpb_ue_status; /* DWORD 0 */ ++ u8 txp_ue_status; /* DWORD 0 */ ++ u8 xaui_ue_status; /* DWORD 0 */ ++ u8 arm_ue_status; /* DWORD 0 */ ++ u8 ipc_ue_status; /* DWORD 0 */ ++ u8 rsvd0[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_UE_STATUS_HI_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Unrecoverable Error Mask (Low) Register. Each bit, when set to one, ++ * will mask the associated Unrecoverable Error status bit from notification ++ * of Unrecoverable Error to the host CPU and/or Server Managment chip and the ++ * transitioning of all BladeEngine units to an Offline state. ++ */ ++struct BE_PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP { ++ u8 cev_ue_mask; /* DWORD 0 */ ++ u8 ctx_ue_mask; /* DWORD 0 */ ++ u8 dbuf_ue_mask; /* DWORD 0 */ ++ u8 erx_ue_mask; /* DWORD 0 */ ++ u8 host_ue_mask; /* DWORD 0 */ ++ u8 mpu_ue_mask; /* DWORD 0 */ ++ u8 ndma_ue_mask; /* DWORD 0 */ ++ u8 ptc_ue_mask; /* DWORD 0 */ ++ u8 rdma_ue_mask; /* DWORD 0 */ ++ u8 rxf_ue_mask; /* DWORD 0 */ ++ u8 rxips_ue_mask; /* DWORD 0 */ ++ u8 rxulp0_ue_mask; /* DWORD 0 */ ++ u8 rxulp1_ue_mask; /* DWORD 0 */ ++ u8 rxulp2_ue_mask; /* DWORD 0 */ ++ u8 tim_ue_mask; /* DWORD 0 */ ++ u8 tpost_ue_mask; /* DWORD 0 */ ++ u8 tpre_ue_mask; /* DWORD 0 */ ++ u8 txips_ue_mask; /* DWORD 0 */ ++ u8 txulp0_ue_mask; /* DWORD 0 */ ++ u8 txulp1_ue_mask; /* DWORD 0 */ ++ u8 uc_ue_mask; /* DWORD 0 */ ++ u8 wdma_ue_mask; /* DWORD 0 */ ++ u8 txulp2_ue_mask; /* DWORD 0 */ ++ u8 host1_ue_mask; /* DWORD 0 */ ++ u8 p0_ob_link_ue_mask; /* DWORD 0 */ ++ u8 p1_ob_link_ue_mask; /* DWORD 0 */ ++ u8 host_gpio_ue_mask; /* DWORD 0 */ ++ u8 mbox_netw_ue_mask; /* DWORD 0 */ ++ u8 mbox_stor_ue_mask; /* DWORD 0 */ ++ u8 axgmac0_ue_mask; /* DWORD 0 */ ++ u8 axgmac1_ue_mask; /* DWORD 0 */ ++ u8 mpu_intpend_ue_mask; /* DWORD 0 */ ++} __packed; ++struct PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Unrecoverable Error Mask (High) Register. Each bit, when set to one, ++ * will mask the associated Unrecoverable Error status bit from notification ++ * of Unrecoverable Error to the host CPU and/or Server Managment chip and the ++ * transitioning of all BladeEngine units to an Offline state. ++ */ ++struct BE_PCICFG_UE_STATUS_HI_MASK_CSR_AMAP { ++ u8 jtag_ue_mask; /* DWORD 0 */ ++ u8 lpcmemhost_ue_mask; /* DWORD 0 */ ++ u8 mgmt_mac_ue_mask; /* DWORD 0 */ ++ u8 mpu_iram_ue_mask; /* DWORD 0 */ ++ u8 pcs0online_ue_mask; /* DWORD 0 */ ++ u8 pcs1online_ue_mask; /* DWORD 0 */ ++ u8 pctl0_ue_mask; /* DWORD 0 */ ++ u8 pctl1_ue_mask; /* DWORD 0 */ ++ u8 pmem_ue_mask; /* DWORD 0 */ ++ u8 rr_ue_mask; /* DWORD 0 */ ++ u8 rxpp_ue_mask; /* DWORD 0 */ ++ u8 txpb_ue_mask; /* DWORD 0 */ ++ u8 txp_ue_mask; /* DWORD 0 */ ++ u8 xaui_ue_mask; /* DWORD 0 */ ++ u8 arm_ue_mask; /* DWORD 0 */ ++ u8 ipc_ue_mask; /* DWORD 0 */ ++ u8 rsvd0[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_UE_STATUS_HI_MASK_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Online Control Register 0. This register controls various units within ++ * BladeEngine being in an Online or Offline state. ++ */ ++struct BE_PCICFG_ONLINE0_CSR_AMAP { ++ u8 cev_online; /* DWORD 0 */ ++ u8 ctx_online; /* DWORD 0 */ ++ u8 dbuf_online; /* DWORD 0 */ ++ u8 erx_online; /* DWORD 0 */ ++ u8 host_online; /* DWORD 0 */ ++ u8 mpu_online; /* DWORD 0 */ ++ u8 ndma_online; /* DWORD 0 */ ++ u8 ptc_online; /* DWORD 0 */ ++ u8 rdma_online; /* DWORD 0 */ ++ u8 rxf_online; /* DWORD 0 */ ++ u8 rxips_online; /* DWORD 0 */ ++ u8 rxulp0_online; /* DWORD 0 */ ++ u8 rxulp1_online; /* DWORD 0 */ ++ u8 rxulp2_online; /* DWORD 0 */ ++ u8 tim_online; /* DWORD 0 */ ++ u8 tpost_online; /* DWORD 0 */ ++ u8 tpre_online; /* DWORD 0 */ ++ u8 txips_online; /* DWORD 0 */ ++ u8 txulp0_online; /* DWORD 0 */ ++ u8 txulp1_online; /* DWORD 0 */ ++ u8 uc_online; /* DWORD 0 */ ++ u8 wdma_online; /* DWORD 0 */ ++ u8 txulp2_online; /* DWORD 0 */ ++ u8 host1_online; /* DWORD 0 */ ++ u8 p0_ob_link_online; /* DWORD 0 */ ++ u8 p1_ob_link_online; /* DWORD 0 */ ++ u8 host_gpio_online; /* DWORD 0 */ ++ u8 mbox_netw_online; /* DWORD 0 */ ++ u8 mbox_stor_online; /* DWORD 0 */ ++ u8 axgmac0_online; /* DWORD 0 */ ++ u8 axgmac1_online; /* DWORD 0 */ ++ u8 mpu_intpend_online; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ONLINE0_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Online Control Register 1. This register controls various units within ++ * BladeEngine being in an Online or Offline state. ++ */ ++struct BE_PCICFG_ONLINE1_CSR_AMAP { ++ u8 jtag_online; /* DWORD 0 */ ++ u8 lpcmemhost_online; /* DWORD 0 */ ++ u8 mgmt_mac_online; /* DWORD 0 */ ++ u8 mpu_iram_online; /* DWORD 0 */ ++ u8 pcs0online_online; /* DWORD 0 */ ++ u8 pcs1online_online; /* DWORD 0 */ ++ u8 pctl0_online; /* DWORD 0 */ ++ u8 pctl1_online; /* DWORD 0 */ ++ u8 pmem_online; /* DWORD 0 */ ++ u8 rr_online; /* DWORD 0 */ ++ u8 rxpp_online; /* DWORD 0 */ ++ u8 txpb_online; /* DWORD 0 */ ++ u8 txp_online; /* DWORD 0 */ ++ u8 xaui_online; /* DWORD 0 */ ++ u8 arm_online; /* DWORD 0 */ ++ u8 ipc_online; /* DWORD 0 */ ++ u8 rsvd0[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ONLINE1_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Host Timer Register. */ ++struct BE_PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP { ++ u8 hosttimer[24]; /* DWORD 0 */ ++ u8 hostintr; /* DWORD 0 */ ++ u8 rsvd0[7]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* Scratchpad Register (for software use). */ ++struct BE_PCICFG_SCRATCHPAD_CSR_AMAP { ++ u8 scratchpad[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_SCRATCHPAD_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express Capabilities Register. */ ++struct BE_PCICFG_PCIE_CAP_CSR_AMAP { ++ u8 capid[8]; /* DWORD 0 */ ++ u8 nextcap[8]; /* DWORD 0 */ ++ u8 capver[4]; /* DWORD 0 */ ++ u8 devport[4]; /* DWORD 0 */ ++ u8 rsvd0[6]; /* DWORD 0 */ ++ u8 rsvd1[2]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_PCIE_CAP_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express Device Capabilities Register. */ ++struct BE_PCICFG_PCIE_DEVCAP_CSR_AMAP { ++ u8 payload[3]; /* DWORD 0 */ ++ u8 rsvd0[3]; /* DWORD 0 */ ++ u8 lo_lat[3]; /* DWORD 0 */ ++ u8 l1_lat[3]; /* DWORD 0 */ ++ u8 rsvd1[3]; /* DWORD 0 */ ++ u8 rsvd2[3]; /* DWORD 0 */ ++ u8 pwr_value[8]; /* DWORD 0 */ ++ u8 pwr_scale[2]; /* DWORD 0 */ ++ u8 rsvd3[4]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_PCIE_DEVCAP_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express Device Control/Status Registers. */ ++struct BE_PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP { ++ u8 CorrErrReportEn; /* DWORD 0 */ ++ u8 NonFatalErrReportEn; /* DWORD 0 */ ++ u8 FatalErrReportEn; /* DWORD 0 */ ++ u8 UnsuppReqReportEn; /* DWORD 0 */ ++ u8 EnableRelaxOrder; /* DWORD 0 */ ++ u8 Max_Payload_Size[3]; /* DWORD 0 */ ++ u8 ExtendTagFieldEnable; /* DWORD 0 */ ++ u8 PhantomFnEnable; /* DWORD 0 */ ++ u8 AuxPwrPMEnable; /* DWORD 0 */ ++ u8 EnableNoSnoop; /* DWORD 0 */ ++ u8 Max_Read_Req_Size[3]; /* DWORD 0 */ ++ u8 rsvd0; /* DWORD 0 */ ++ u8 CorrErrDetect; /* DWORD 0 */ ++ u8 NonFatalErrDetect; /* DWORD 0 */ ++ u8 FatalErrDetect; /* DWORD 0 */ ++ u8 UnsuppReqDetect; /* DWORD 0 */ ++ u8 AuxPwrDetect; /* DWORD 0 */ ++ u8 TransPending; /* DWORD 0 */ ++ u8 rsvd1[10]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express Link Capabilities Register. */ ++struct BE_PCICFG_PCIE_LINK_CAP_CSR_AMAP { ++ u8 MaxLinkSpeed[4]; /* DWORD 0 */ ++ u8 MaxLinkWidth[6]; /* DWORD 0 */ ++ u8 ASPMSupport[2]; /* DWORD 0 */ ++ u8 L0sExitLat[3]; /* DWORD 0 */ ++ u8 L1ExitLat[3]; /* DWORD 0 */ ++ u8 rsvd0[6]; /* DWORD 0 */ ++ u8 PortNum[8]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_PCIE_LINK_CAP_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express Link Status Register. */ ++struct BE_PCICFG_PCIE_LINK_STATUS_CSR_AMAP { ++ u8 ASPMCtl[2]; /* DWORD 0 */ ++ u8 rsvd0; /* DWORD 0 */ ++ u8 ReadCmplBndry; /* DWORD 0 */ ++ u8 LinkDisable; /* DWORD 0 */ ++ u8 RetrainLink; /* DWORD 0 */ ++ u8 CommonClkConfig; /* DWORD 0 */ ++ u8 ExtendSync; /* DWORD 0 */ ++ u8 rsvd1[8]; /* DWORD 0 */ ++ u8 LinkSpeed[4]; /* DWORD 0 */ ++ u8 NegLinkWidth[6]; /* DWORD 0 */ ++ u8 LinkTrainErr; /* DWORD 0 */ ++ u8 LinkTrain; /* DWORD 0 */ ++ u8 SlotClkConfig; /* DWORD 0 */ ++ u8 rsvd2[3]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_PCIE_LINK_STATUS_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express MSI Configuration Register. */ ++struct BE_PCICFG_MSI_CSR_AMAP { ++ u8 capid[8]; /* DWORD 0 */ ++ u8 nextptr[8]; /* DWORD 0 */ ++ u8 tablesize[11]; /* DWORD 0 */ ++ u8 rsvd0[3]; /* DWORD 0 */ ++ u8 funcmask; /* DWORD 0 */ ++ u8 en; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSI_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* MSI-X Table Offset Register. */ ++struct BE_PCICFG_MSIX_TABLE_CSR_AMAP { ++ u8 tablebir[3]; /* DWORD 0 */ ++ u8 offset[29]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSIX_TABLE_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* MSI-X PBA Offset Register. */ ++struct BE_PCICFG_MSIX_PBA_CSR_AMAP { ++ u8 pbabir[3]; /* DWORD 0 */ ++ u8 offset[29]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSIX_PBA_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express MSI-X Message Vector Control Register. */ ++struct BE_PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP { ++ u8 vector_control; /* DWORD 0 */ ++ u8 rsvd0[31]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express MSI-X Message Data Register. */ ++struct BE_PCICFG_MSIX_MSG_DATA_CSR_AMAP { ++ u8 data[16]; /* DWORD 0 */ ++ u8 rsvd0[16]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSIX_MSG_DATA_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express MSI-X Message Address Register - High Part. */ ++struct BE_PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP { ++ u8 addr[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++/* PCI Express MSI-X Message Address Register - Low Part. */ ++struct BE_PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP { ++ u8 rsvd0[2]; /* DWORD 0 */ ++ u8 addr[30]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_PCICFG_ANON_18_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ANON_18_RSVD_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_PCICFG_ANON_19_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ANON_19_RSVD_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_PCICFG_ANON_20_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[25][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_20_RSVD_AMAP { ++ u32 dw[26]; ++}; ++ ++struct BE_PCICFG_ANON_21_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[1919][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_21_RSVD_AMAP { ++ u32 dw[1920]; ++}; ++ ++struct BE_PCICFG_ANON_22_MESSAGE_AMAP { ++ struct BE_PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP vec_ctrl; ++ struct BE_PCICFG_MSIX_MSG_DATA_CSR_AMAP msg_data; ++ struct BE_PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP addr_hi; ++ struct BE_PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP addr_low; ++} __packed; ++struct PCICFG_ANON_22_MESSAGE_AMAP { ++ u32 dw[4]; ++}; ++ ++struct BE_PCICFG_ANON_23_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[895][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_23_RSVD_AMAP { ++ u32 dw[896]; ++}; ++ ++/* These PCI Configuration Space registers are for the Storage Function of ++ * BladeEngine (Function 0). In the memory map of the registers below their ++ * table, ++ */ ++struct BE_PCICFG0_CSRMAP_AMAP { ++ struct BE_PCICFG_ID_CSR_AMAP id; ++ u8 rsvd0[32]; /* DWORD 1 */ ++ u8 rsvd1[32]; /* DWORD 2 */ ++ u8 rsvd2[32]; /* DWORD 3 */ ++ struct BE_PCICFG_IOBAR_CSR_AMAP iobar; ++ struct BE_PCICFG_MEMBAR0_CSR_AMAP membar0; ++ struct BE_PCICFG_MEMBAR1_LO_CSR_AMAP membar1_lo; ++ struct BE_PCICFG_MEMBAR1_HI_CSR_AMAP membar1_hi; ++ struct BE_PCICFG_MEMBAR2_LO_CSR_AMAP membar2_lo; ++ struct BE_PCICFG_MEMBAR2_HI_CSR_AMAP membar2_hi; ++ u8 rsvd3[32]; /* DWORD 10 */ ++ struct BE_PCICFG_SUBSYSTEM_ID_F0_CSR_AMAP subsystem_id; ++ u8 rsvd4[32]; /* DWORD 12 */ ++ u8 rsvd5[32]; /* DWORD 13 */ ++ u8 rsvd6[32]; /* DWORD 14 */ ++ u8 rsvd7[32]; /* DWORD 15 */ ++ struct BE_PCICFG_SEMAPHORE_CSR_AMAP semaphore[4]; ++ struct BE_PCICFG_SOFT_RESET_CSR_AMAP soft_reset; ++ u8 rsvd8[32]; /* DWORD 21 */ ++ struct BE_PCICFG_SCRATCHPAD_CSR_AMAP scratchpad; ++ u8 rsvd9[32]; /* DWORD 23 */ ++ u8 rsvd10[32]; /* DWORD 24 */ ++ u8 rsvd11[32]; /* DWORD 25 */ ++ u8 rsvd12[32]; /* DWORD 26 */ ++ u8 rsvd13[32]; /* DWORD 27 */ ++ u8 rsvd14[2][32]; /* DWORD 28 */ ++ u8 rsvd15[32]; /* DWORD 30 */ ++ u8 rsvd16[32]; /* DWORD 31 */ ++ u8 rsvd17[8][32]; /* DWORD 32 */ ++ struct BE_PCICFG_UE_STATUS_LOW_CSR_AMAP ue_status_low; ++ struct BE_PCICFG_UE_STATUS_HI_CSR_AMAP ue_status_hi; ++ struct BE_PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP ue_status_low_mask; ++ struct BE_PCICFG_UE_STATUS_HI_MASK_CSR_AMAP ue_status_hi_mask; ++ struct BE_PCICFG_ONLINE0_CSR_AMAP online0; ++ struct BE_PCICFG_ONLINE1_CSR_AMAP online1; ++ u8 rsvd18[32]; /* DWORD 46 */ ++ u8 rsvd19[32]; /* DWORD 47 */ ++ u8 rsvd20[32]; /* DWORD 48 */ ++ u8 rsvd21[32]; /* DWORD 49 */ ++ struct BE_PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP host_timer_int_ctrl; ++ u8 rsvd22[32]; /* DWORD 51 */ ++ struct BE_PCICFG_PCIE_CAP_CSR_AMAP pcie_cap; ++ struct BE_PCICFG_PCIE_DEVCAP_CSR_AMAP pcie_devcap; ++ struct BE_PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP pcie_control_status; ++ struct BE_PCICFG_PCIE_LINK_CAP_CSR_AMAP pcie_link_cap; ++ struct BE_PCICFG_PCIE_LINK_STATUS_CSR_AMAP pcie_link_status; ++ struct BE_PCICFG_MSI_CSR_AMAP msi; ++ struct BE_PCICFG_MSIX_TABLE_CSR_AMAP msix_table_offset; ++ struct BE_PCICFG_MSIX_PBA_CSR_AMAP msix_pba_offset; ++ u8 rsvd23[32]; /* DWORD 60 */ ++ u8 rsvd24[32]; /* DWORD 61 */ ++ u8 rsvd25[32]; /* DWORD 62 */ ++ u8 rsvd26[32]; /* DWORD 63 */ ++ u8 rsvd27[32]; /* DWORD 64 */ ++ u8 rsvd28[32]; /* DWORD 65 */ ++ u8 rsvd29[32]; /* DWORD 66 */ ++ u8 rsvd30[32]; /* DWORD 67 */ ++ u8 rsvd31[32]; /* DWORD 68 */ ++ u8 rsvd32[32]; /* DWORD 69 */ ++ u8 rsvd33[32]; /* DWORD 70 */ ++ u8 rsvd34[32]; /* DWORD 71 */ ++ u8 rsvd35[32]; /* DWORD 72 */ ++ u8 rsvd36[32]; /* DWORD 73 */ ++ u8 rsvd37[32]; /* DWORD 74 */ ++ u8 rsvd38[32]; /* DWORD 75 */ ++ u8 rsvd39[32]; /* DWORD 76 */ ++ u8 rsvd40[32]; /* DWORD 77 */ ++ u8 rsvd41[32]; /* DWORD 78 */ ++ u8 rsvd42[32]; /* DWORD 79 */ ++ u8 rsvd43[32]; /* DWORD 80 */ ++ u8 rsvd44[32]; /* DWORD 81 */ ++ u8 rsvd45[32]; /* DWORD 82 */ ++ u8 rsvd46[32]; /* DWORD 83 */ ++ u8 rsvd47[32]; /* DWORD 84 */ ++ u8 rsvd48[32]; /* DWORD 85 */ ++ u8 rsvd49[32]; /* DWORD 86 */ ++ u8 rsvd50[32]; /* DWORD 87 */ ++ u8 rsvd51[32]; /* DWORD 88 */ ++ u8 rsvd52[32]; /* DWORD 89 */ ++ u8 rsvd53[32]; /* DWORD 90 */ ++ u8 rsvd54[32]; /* DWORD 91 */ ++ u8 rsvd55[32]; /* DWORD 92 */ ++ u8 rsvd56[832]; /* DWORD 93 */ ++ u8 rsvd57[32]; /* DWORD 119 */ ++ u8 rsvd58[32]; /* DWORD 120 */ ++ u8 rsvd59[32]; /* DWORD 121 */ ++ u8 rsvd60[32]; /* DWORD 122 */ ++ u8 rsvd61[32]; /* DWORD 123 */ ++ u8 rsvd62[32]; /* DWORD 124 */ ++ u8 rsvd63[32]; /* DWORD 125 */ ++ u8 rsvd64[32]; /* DWORD 126 */ ++ u8 rsvd65[32]; /* DWORD 127 */ ++ u8 rsvd66[61440]; /* DWORD 128 */ ++ struct BE_PCICFG_ANON_22_MESSAGE_AMAP message[32]; ++ u8 rsvd67[28672]; /* DWORD 2176 */ ++ u8 rsvd68[32]; /* DWORD 3072 */ ++ u8 rsvd69[1023][32]; /* DWORD 3073 */ ++} __packed; ++struct PCICFG0_CSRMAP_AMAP { ++ u32 dw[4096]; ++}; ++ ++struct BE_PCICFG_ANON_24_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ANON_24_RSVD_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_PCICFG_ANON_25_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ANON_25_RSVD_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_PCICFG_ANON_26_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++} __packed; ++struct PCICFG_ANON_26_RSVD_AMAP { ++ u32 dw[1]; ++}; ++ ++struct BE_PCICFG_ANON_27_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_27_RSVD_AMAP { ++ u32 dw[2]; ++}; ++ ++struct BE_PCICFG_ANON_28_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[3][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_28_RSVD_AMAP { ++ u32 dw[4]; ++}; ++ ++struct BE_PCICFG_ANON_29_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[36][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_29_RSVD_AMAP { ++ u32 dw[37]; ++}; ++ ++struct BE_PCICFG_ANON_30_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[1930][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_30_RSVD_AMAP { ++ u32 dw[1931]; ++}; ++ ++struct BE_PCICFG_ANON_31_MESSAGE_AMAP { ++ struct BE_PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP vec_ctrl; ++ struct BE_PCICFG_MSIX_MSG_DATA_CSR_AMAP msg_data; ++ struct BE_PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP addr_hi; ++ struct BE_PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP addr_low; ++} __packed; ++struct PCICFG_ANON_31_MESSAGE_AMAP { ++ u32 dw[4]; ++}; ++ ++struct BE_PCICFG_ANON_32_RSVD_AMAP { ++ u8 rsvd0[32]; /* DWORD 0 */ ++ u8 rsvd1[895][32]; /* DWORD 1 */ ++} __packed; ++struct PCICFG_ANON_32_RSVD_AMAP { ++ u32 dw[896]; ++}; ++ ++/* This PCI configuration space register map is for the Networking Function of ++ * BladeEngine (Function 1). ++ */ ++struct BE_PCICFG1_CSRMAP_AMAP { ++ struct BE_PCICFG_ID_CSR_AMAP id; ++ u8 rsvd0[32]; /* DWORD 1 */ ++ u8 rsvd1[32]; /* DWORD 2 */ ++ u8 rsvd2[32]; /* DWORD 3 */ ++ struct BE_PCICFG_IOBAR_CSR_AMAP iobar; ++ struct BE_PCICFG_MEMBAR0_CSR_AMAP membar0; ++ struct BE_PCICFG_MEMBAR1_LO_CSR_AMAP membar1_lo; ++ struct BE_PCICFG_MEMBAR1_HI_CSR_AMAP membar1_hi; ++ struct BE_PCICFG_MEMBAR2_LO_CSR_AMAP membar2_lo; ++ struct BE_PCICFG_MEMBAR2_HI_CSR_AMAP membar2_hi; ++ u8 rsvd3[32]; /* DWORD 10 */ ++ struct BE_PCICFG_SUBSYSTEM_ID_F1_CSR_AMAP subsystem_id; ++ u8 rsvd4[32]; /* DWORD 12 */ ++ u8 rsvd5[32]; /* DWORD 13 */ ++ u8 rsvd6[32]; /* DWORD 14 */ ++ u8 rsvd7[32]; /* DWORD 15 */ ++ struct BE_PCICFG_SEMAPHORE_CSR_AMAP semaphore[4]; ++ struct BE_PCICFG_SOFT_RESET_CSR_AMAP soft_reset; ++ u8 rsvd8[32]; /* DWORD 21 */ ++ struct BE_PCICFG_SCRATCHPAD_CSR_AMAP scratchpad; ++ u8 rsvd9[32]; /* DWORD 23 */ ++ u8 rsvd10[32]; /* DWORD 24 */ ++ u8 rsvd11[32]; /* DWORD 25 */ ++ u8 rsvd12[32]; /* DWORD 26 */ ++ u8 rsvd13[32]; /* DWORD 27 */ ++ u8 rsvd14[2][32]; /* DWORD 28 */ ++ u8 rsvd15[32]; /* DWORD 30 */ ++ u8 rsvd16[32]; /* DWORD 31 */ ++ u8 rsvd17[8][32]; /* DWORD 32 */ ++ struct BE_PCICFG_UE_STATUS_LOW_CSR_AMAP ue_status_low; ++ struct BE_PCICFG_UE_STATUS_HI_CSR_AMAP ue_status_hi; ++ struct BE_PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP ue_status_low_mask; ++ struct BE_PCICFG_UE_STATUS_HI_MASK_CSR_AMAP ue_status_hi_mask; ++ struct BE_PCICFG_ONLINE0_CSR_AMAP online0; ++ struct BE_PCICFG_ONLINE1_CSR_AMAP online1; ++ u8 rsvd18[32]; /* DWORD 46 */ ++ u8 rsvd19[32]; /* DWORD 47 */ ++ u8 rsvd20[32]; /* DWORD 48 */ ++ u8 rsvd21[32]; /* DWORD 49 */ ++ struct BE_PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP host_timer_int_ctrl; ++ u8 rsvd22[32]; /* DWORD 51 */ ++ struct BE_PCICFG_PCIE_CAP_CSR_AMAP pcie_cap; ++ struct BE_PCICFG_PCIE_DEVCAP_CSR_AMAP pcie_devcap; ++ struct BE_PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP pcie_control_status; ++ struct BE_PCICFG_PCIE_LINK_CAP_CSR_AMAP pcie_link_cap; ++ struct BE_PCICFG_PCIE_LINK_STATUS_CSR_AMAP pcie_link_status; ++ struct BE_PCICFG_MSI_CSR_AMAP msi; ++ struct BE_PCICFG_MSIX_TABLE_CSR_AMAP msix_table_offset; ++ struct BE_PCICFG_MSIX_PBA_CSR_AMAP msix_pba_offset; ++ u8 rsvd23[64]; /* DWORD 60 */ ++ u8 rsvd24[32]; /* DWORD 62 */ ++ u8 rsvd25[32]; /* DWORD 63 */ ++ u8 rsvd26[32]; /* DWORD 64 */ ++ u8 rsvd27[32]; /* DWORD 65 */ ++ u8 rsvd28[32]; /* DWORD 66 */ ++ u8 rsvd29[32]; /* DWORD 67 */ ++ u8 rsvd30[32]; /* DWORD 68 */ ++ u8 rsvd31[32]; /* DWORD 69 */ ++ u8 rsvd32[32]; /* DWORD 70 */ ++ u8 rsvd33[32]; /* DWORD 71 */ ++ u8 rsvd34[32]; /* DWORD 72 */ ++ u8 rsvd35[32]; /* DWORD 73 */ ++ u8 rsvd36[32]; /* DWORD 74 */ ++ u8 rsvd37[128]; /* DWORD 75 */ ++ u8 rsvd38[32]; /* DWORD 79 */ ++ u8 rsvd39[1184]; /* DWORD 80 */ ++ u8 rsvd40[61792]; /* DWORD 117 */ ++ struct BE_PCICFG_ANON_31_MESSAGE_AMAP message[32]; ++ u8 rsvd41[28672]; /* DWORD 2176 */ ++ u8 rsvd42[32]; /* DWORD 3072 */ ++ u8 rsvd43[1023][32]; /* DWORD 3073 */ ++} __packed; ++struct PCICFG1_CSRMAP_AMAP { ++ u32 dw[4096]; ++}; ++ ++#endif /* __pcicfg_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/post_codes.h +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __post_codes_amap_h__ ++#define __post_codes_amap_h__ ++ ++/* --- MGMT_HBA_POST_STAGE_ENUM --- */ ++#define POST_STAGE_POWER_ON_RESET (0) /* State after a cold or warm boot. */ ++#define POST_STAGE_AWAITING_HOST_RDY (1) /* ARM boot code awaiting a ++ go-ahed from the host. */ ++#define POST_STAGE_HOST_RDY (2) /* Host has given go-ahed to ARM. */ ++#define POST_STAGE_BE_RESET (3) /* Host wants to reset chip, this is a chip ++ workaround */ ++#define POST_STAGE_SEEPROM_CS_START (256) /* SEEPROM checksum ++ test start. */ ++#define POST_STAGE_SEEPROM_CS_DONE (257) /* SEEPROM checksum test ++ done. */ ++#define POST_STAGE_DDR_CONFIG_START (512) /* DDR configuration start. */ ++#define POST_STAGE_DDR_CONFIG_DONE (513) /* DDR configuration done. */ ++#define POST_STAGE_DDR_CALIBRATE_START (768) /* DDR calibration start. */ ++#define POST_STAGE_DDR_CALIBRATE_DONE (769) /* DDR calibration done. */ ++#define POST_STAGE_DDR_TEST_START (1024) /* DDR memory test start. */ ++#define POST_STAGE_DDR_TEST_DONE (1025) /* DDR memory test done. */ ++#define POST_STAGE_REDBOOT_INIT_START (1536) /* Redboot starts execution. */ ++#define POST_STAGE_REDBOOT_INIT_DONE (1537) /* Redboot done execution. */ ++#define POST_STAGE_FW_IMAGE_LOAD_START (1792) /* Firmware image load to ++ DDR start. */ ++#define POST_STAGE_FW_IMAGE_LOAD_DONE (1793) /* Firmware image load ++ to DDR done. */ ++#define POST_STAGE_ARMFW_START (2048) /* ARMfw runtime code ++ starts execution. */ ++#define POST_STAGE_DHCP_QUERY_START (2304) /* DHCP server query start. */ ++#define POST_STAGE_DHCP_QUERY_DONE (2305) /* DHCP server query done. */ ++#define POST_STAGE_BOOT_TARGET_DISCOVERY_START (2560) /* Boot Target ++ Discovery Start. */ ++#define POST_STAGE_BOOT_TARGET_DISCOVERY_DONE (2561) /* Boot Target ++ Discovery Done. */ ++#define POST_STAGE_RC_OPTION_SET (2816) /* Remote configuration ++ option is set in SEEPROM */ ++#define POST_STAGE_SWITCH_LINK (2817) /* Wait for link up on switch */ ++#define POST_STAGE_SEND_ICDS_MESSAGE (2818) /* Send the ICDS message ++ to switch */ ++#define POST_STAGE_PERFROM_TFTP (2819) /* Download xml using TFTP */ ++#define POST_STAGE_PARSE_XML (2820) /* Parse XML file */ ++#define POST_STAGE_DOWNLOAD_IMAGE (2821) /* Download IMAGE from ++ TFTP server */ ++#define POST_STAGE_FLASH_IMAGE (2822) /* Flash the IMAGE */ ++#define POST_STAGE_RC_DONE (2823) /* Remote configuration ++ complete */ ++#define POST_STAGE_REBOOT_SYSTEM (2824) /* Upgrade IMAGE done, ++ reboot required */ ++#define POST_STAGE_MAC_ADDRESS (3072) /* MAC Address Check */ ++#define POST_STAGE_ARMFW_READY (49152) /* ARMfw is done with POST ++ and ready. */ ++#define POST_STAGE_ARMFW_UE (61440) /* ARMfw has asserted an ++ unrecoverable error. The ++ lower 3 hex digits of the ++ stage code identify the ++ unique error code. ++ */ ++ ++/* This structure defines the format of the MPU semaphore ++ * register when used for POST. ++ */ ++struct BE_MGMT_HBA_POST_STATUS_STRUCT_AMAP { ++ u8 stage[16]; /* DWORD 0 */ ++ u8 rsvd0[10]; /* DWORD 0 */ ++ u8 iscsi_driver_loaded; /* DWORD 0 */ ++ u8 option_rom_installed; /* DWORD 0 */ ++ u8 iscsi_ip_conflict; /* DWORD 0 */ ++ u8 iscsi_no_ip; /* DWORD 0 */ ++ u8 backup_fw; /* DWORD 0 */ ++ u8 error; /* DWORD 0 */ ++} __packed; ++struct MGMT_HBA_POST_STATUS_STRUCT_AMAP { ++ u32 dw[1]; ++}; ++ ++/* --- MGMT_HBA_POST_DUMMY_BITS_ENUM --- */ ++#define POST_BIT_ISCSI_LOADED (26) ++#define POST_BIT_OPTROM_INST (27) ++#define POST_BIT_BAD_IP_ADDR (28) ++#define POST_BIT_NO_IP_ADDR (29) ++#define POST_BIT_BACKUP_FW (30) ++#define POST_BIT_ERROR (31) ++ ++/* --- MGMT_HBA_POST_DUMMY_VALUES_ENUM --- */ ++#define POST_ISCSI_DRIVER_LOADED (67108864) ++#define POST_OPTROM_INSTALLED (134217728) ++#define POST_ISCSI_IP_ADDRESS_CONFLICT (268435456) ++#define POST_ISCSI_NO_IP_ADDRESS (536870912) ++#define POST_BACKUP_FW_LOADED (1073741824) ++#define POST_FATAL_ERROR (2147483648) ++ ++#endif /* __post_codes_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/regmap.h +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2005 - 2008 ServerEngines ++ * All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation. The full GNU General ++ * Public License is included in this distribution in the file called COPYING. ++ * ++ * Contact Information: ++ * linux-drivers@serverengines.com ++ * ++ * ServerEngines ++ * 209 N. Fair Oaks Ave ++ * Sunnyvale, CA 94085 ++ */ ++/* ++ * Autogenerated by srcgen version: 0127 ++ */ ++#ifndef __regmap_amap_h__ ++#define __regmap_amap_h__ ++#include "pcicfg.h" ++#include "ep.h" ++#include "cev.h" ++#include "mpu.h" ++#include "doorbells.h" ++ ++/* ++ * This is the control and status register map for BladeEngine, showing ++ * the relative size and offset of each sub-module. The CSR registers ++ * are identical for the network and storage PCI functions. The ++ * CSR map is shown below, followed by details of each block, ++ * in sub-sections. The sub-sections begin with a description ++ * of CSRs that are instantiated in multiple blocks. ++ */ ++struct BE_BLADE_ENGINE_CSRMAP_AMAP { ++ struct BE_MPU_CSRMAP_AMAP mpu; ++ u8 rsvd0[8192]; /* DWORD 256 */ ++ u8 rsvd1[8192]; /* DWORD 512 */ ++ struct BE_CEV_CSRMAP_AMAP cev; ++ u8 rsvd2[8192]; /* DWORD 1024 */ ++ u8 rsvd3[8192]; /* DWORD 1280 */ ++ u8 rsvd4[8192]; /* DWORD 1536 */ ++ u8 rsvd5[8192]; /* DWORD 1792 */ ++ u8 rsvd6[8192]; /* DWORD 2048 */ ++ u8 rsvd7[8192]; /* DWORD 2304 */ ++ u8 rsvd8[8192]; /* DWORD 2560 */ ++ u8 rsvd9[8192]; /* DWORD 2816 */ ++ u8 rsvd10[8192]; /* DWORD 3072 */ ++ u8 rsvd11[8192]; /* DWORD 3328 */ ++ u8 rsvd12[8192]; /* DWORD 3584 */ ++ u8 rsvd13[8192]; /* DWORD 3840 */ ++ u8 rsvd14[8192]; /* DWORD 4096 */ ++ u8 rsvd15[8192]; /* DWORD 4352 */ ++ u8 rsvd16[8192]; /* DWORD 4608 */ ++ u8 rsvd17[8192]; /* DWORD 4864 */ ++ u8 rsvd18[8192]; /* DWORD 5120 */ ++ u8 rsvd19[8192]; /* DWORD 5376 */ ++ u8 rsvd20[8192]; /* DWORD 5632 */ ++ u8 rsvd21[8192]; /* DWORD 5888 */ ++ u8 rsvd22[8192]; /* DWORD 6144 */ ++ u8 rsvd23[17152][32]; /* DWORD 6400 */ ++} __packed; ++struct BLADE_ENGINE_CSRMAP_AMAP { ++ u32 dw[23552]; ++}; ++ ++#endif /* __regmap_amap_h__ */ +--- /dev/null ++++ b/drivers/staging/benet/TODO +@@ -0,0 +1,7 @@ ++TODO: ++ - fix minor checkpatch.pl issues ++ - remove wrappers around common iowrite functions ++ - full netdev audit of common problems/issues ++ ++Please send all patches and questions to Subbu Seetharaman ++ and Greg Kroah-Hartman +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -49,4 +49,6 @@ source "drivers/staging/otus/Kconfig" + + source "drivers/staging/rt2860/Kconfig" + ++source "drivers/staging/benet/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_USB_ATMEL) += at76_usb/ + obj-$(CONFIG_AGNX) += agnx/ + obj-$(CONFIG_OTUS) += otus/ + obj-$(CONFIG_RT2860) += rt2860/ ++obj-$(CONFIG_BENET) += benet/ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-at76_usb-wireless-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-at76_usb-wireless-driver.patch new file mode 100644 index 000000000..41bbc292a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-at76_usb-wireless-driver.patch @@ -0,0 +1,6246 @@ +From: Pavel Roskin +Subject: staging: at76_usb wireless driver +Patch-mainline: 2.6.28 + + +Add the at76_usb wireless driver to the staging tree while the +other kernel driver (out of tree) gets rewritten to use the internal +wireless stack. + +This patch comes directly from the Fedora kernel tree, with only the +directory placement of the files changed. + +Signed-off-by: Pavel Roskin +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/at76_usb/Kconfig | 8 + drivers/staging/at76_usb/Makefile | 1 + drivers/staging/at76_usb/TODO | 2 + drivers/staging/at76_usb/at76_usb.c | 5559 ++++++++++++++++++++++++++++++++++++ + drivers/staging/at76_usb/at76_usb.h | 619 ++++ + 7 files changed, 6192 insertions(+) + +--- /dev/null ++++ b/drivers/staging/at76_usb/at76_usb.c +@@ -0,0 +1,5559 @@ ++/* ++ * at76c503/at76c505 USB driver ++ * ++ * Copyright (c) 2002 - 2003 Oliver Kurth ++ * Copyright (c) 2004 Joerg Albert ++ * Copyright (c) 2004 Nick Jones ++ * Copyright (c) 2004 Balint Seeber ++ * Copyright (c) 2007 Guido Guenther ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This file is part of the Berlios driver for WLAN USB devices based on the ++ * Atmel AT76C503A/505/505A. ++ * ++ * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "at76_usb.h" ++ ++/* Version information */ ++#define DRIVER_NAME "at76_usb" ++#define DRIVER_VERSION "0.17" ++#define DRIVER_DESC "Atmel at76x USB Wireless LAN Driver" ++ ++/* at76_debug bits */ ++#define DBG_PROGRESS 0x00000001 /* authentication/accociation */ ++#define DBG_BSS_TABLE 0x00000002 /* show BSS table after scans */ ++#define DBG_IOCTL 0x00000004 /* ioctl calls / settings */ ++#define DBG_MAC_STATE 0x00000008 /* MAC state transitions */ ++#define DBG_TX_DATA 0x00000010 /* tx header */ ++#define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */ ++#define DBG_TX_MGMT 0x00000040 /* tx management */ ++#define DBG_RX_DATA 0x00000080 /* rx data header */ ++#define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */ ++#define DBG_RX_MGMT 0x00000200 /* rx mgmt frame headers */ ++#define DBG_RX_BEACON 0x00000400 /* rx beacon */ ++#define DBG_RX_CTRL 0x00000800 /* rx control */ ++#define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */ ++#define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */ ++#define DBG_DEVSTART 0x00004000 /* fw download, device start */ ++#define DBG_URB 0x00008000 /* rx urb status, ... */ ++#define DBG_RX_ATMEL_HDR 0x00010000 /* Atmel-specific Rx headers */ ++#define DBG_PROC_ENTRY 0x00020000 /* procedure entries/exits */ ++#define DBG_PM 0x00040000 /* power management settings */ ++#define DBG_BSS_MATCH 0x00080000 /* BSS match failures */ ++#define DBG_PARAMS 0x00100000 /* show configured parameters */ ++#define DBG_WAIT_COMPLETE 0x00200000 /* command completion */ ++#define DBG_RX_FRAGS_SKB 0x00400000 /* skb header of Rx fragments */ ++#define DBG_BSS_TABLE_RM 0x00800000 /* purging bss table entries */ ++#define DBG_MONITOR_MODE 0x01000000 /* monitor mode */ ++#define DBG_MIB 0x02000000 /* dump all MIBs on startup */ ++#define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */ ++#define DBG_WE_EVENTS 0x08000000 /* dump wireless events */ ++#define DBG_FW 0x10000000 /* firmware download */ ++#define DBG_DFU 0x20000000 /* device firmware upgrade */ ++ ++#define DBG_DEFAULTS 0 ++ ++/* Use our own dbg macro */ ++#define at76_dbg(bits, format, arg...) \ ++ do { \ ++ if (at76_debug & (bits)) \ ++ printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , ## arg); \ ++ } while (0) ++ ++static int at76_debug = DBG_DEFAULTS; ++ ++/* Protect against concurrent firmware loading and parsing */ ++static struct mutex fw_mutex; ++ ++static struct fwentry firmwares[] = { ++ [0] = {""}, ++ [BOARD_503_ISL3861] = {"atmel_at76c503-i3861.bin"}, ++ [BOARD_503_ISL3863] = {"atmel_at76c503-i3863.bin"}, ++ [BOARD_503] = {"atmel_at76c503-rfmd.bin"}, ++ [BOARD_503_ACC] = {"atmel_at76c503-rfmd-acc.bin"}, ++ [BOARD_505] = {"atmel_at76c505-rfmd.bin"}, ++ [BOARD_505_2958] = {"atmel_at76c505-rfmd2958.bin"}, ++ [BOARD_505A] = {"atmel_at76c505a-rfmd2958.bin"}, ++ [BOARD_505AMX] = {"atmel_at76c505amx-rfmd.bin"}, ++}; ++ ++#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) ++ ++static struct usb_device_id dev_table[] = { ++ /* ++ * at76c503-i3861 ++ */ ++ /* Generic AT76C503/3861 device */ ++ {USB_DEVICE(0x03eb, 0x7603), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Linksys WUSB11 v2.1/v2.6 */ ++ {USB_DEVICE(0x066b, 0x2211), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Netgear MA101 rev. A */ ++ {USB_DEVICE(0x0864, 0x4100), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Tekram U300C / Allnet ALL0193 */ ++ {USB_DEVICE(0x0b3b, 0x1612), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* HP HN210W J7801A */ ++ {USB_DEVICE(0x03f0, 0x011c), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Sitecom/Z-Com/Zyxel M4Y-750 */ ++ {USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Dynalink/Askey WLL013 (intersil) */ ++ {USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */ ++ {USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* BenQ AWL300 */ ++ {USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Addtron AWU-120, Compex WLU11 */ ++ {USB_DEVICE(0x05dd, 0xff31), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Intel AP310 AnyPoint II USB */ ++ {USB_DEVICE(0x8086, 0x0200), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Dynalink L11U */ ++ {USB_DEVICE(0x0d8e, 0x7100), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* Arescom WL-210, FCC id 07J-GL2411USB */ ++ {USB_DEVICE(0x0d8e, 0x7110), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* I-O DATA WN-B11/USB */ ++ {USB_DEVICE(0x04bb, 0x0919), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* BT Voyager 1010 */ ++ {USB_DEVICE(0x069a, 0x0821), USB_DEVICE_DATA(BOARD_503_ISL3861)}, ++ /* ++ * at76c503-i3863 ++ */ ++ /* Generic AT76C503/3863 device */ ++ {USB_DEVICE(0x03eb, 0x7604), USB_DEVICE_DATA(BOARD_503_ISL3863)}, ++ /* Samsung SWL-2100U */ ++ {USB_DEVICE(0x055d, 0xa000), USB_DEVICE_DATA(BOARD_503_ISL3863)}, ++ /* ++ * at76c503-rfmd ++ */ ++ /* Generic AT76C503/RFMD device */ ++ {USB_DEVICE(0x03eb, 0x7605), USB_DEVICE_DATA(BOARD_503)}, ++ /* Dynalink/Askey WLL013 (rfmd) */ ++ {USB_DEVICE(0x069a, 0x0321), USB_DEVICE_DATA(BOARD_503)}, ++ /* Linksys WUSB11 v2.6 */ ++ {USB_DEVICE(0x077b, 0x2219), USB_DEVICE_DATA(BOARD_503)}, ++ /* Network Everywhere NWU11B */ ++ {USB_DEVICE(0x077b, 0x2227), USB_DEVICE_DATA(BOARD_503)}, ++ /* Netgear MA101 rev. B */ ++ {USB_DEVICE(0x0864, 0x4102), USB_DEVICE_DATA(BOARD_503)}, ++ /* D-Link DWL-120 rev. E */ ++ {USB_DEVICE(0x2001, 0x3200), USB_DEVICE_DATA(BOARD_503)}, ++ /* Actiontec 802UAT1, HWU01150-01UK */ ++ {USB_DEVICE(0x1668, 0x7605), USB_DEVICE_DATA(BOARD_503)}, ++ /* AirVast W-Buddie WN210 */ ++ {USB_DEVICE(0x03eb, 0x4102), USB_DEVICE_DATA(BOARD_503)}, ++ /* Dick Smith Electronics XH1153 802.11b USB adapter */ ++ {USB_DEVICE(0x1371, 0x5743), USB_DEVICE_DATA(BOARD_503)}, ++ /* CNet CNUSB611 */ ++ {USB_DEVICE(0x1371, 0x0001), USB_DEVICE_DATA(BOARD_503)}, ++ /* FiberLine FL-WL200U */ ++ {USB_DEVICE(0x1371, 0x0002), USB_DEVICE_DATA(BOARD_503)}, ++ /* BenQ AWL400 USB stick */ ++ {USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503)}, ++ /* 3Com 3CRSHEW696 */ ++ {USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503)}, ++ /* Siemens Santis ADSL WLAN USB adapter WLL 013 */ ++ {USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503)}, ++ /* Belkin F5D6050, version 2 */ ++ {USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503)}, ++ /* iBlitzz, BWU613 (not *B or *SB) */ ++ {USB_DEVICE(0x07b8, 0xb000), USB_DEVICE_DATA(BOARD_503)}, ++ /* Gigabyte GN-WLBM101 */ ++ {USB_DEVICE(0x1044, 0x8003), USB_DEVICE_DATA(BOARD_503)}, ++ /* Planex GW-US11S */ ++ {USB_DEVICE(0x2019, 0x3220), USB_DEVICE_DATA(BOARD_503)}, ++ /* Internal WLAN adapter in h5[4,5]xx series iPAQs */ ++ {USB_DEVICE(0x049f, 0x0032), USB_DEVICE_DATA(BOARD_503)}, ++ /* Corega Wireless LAN USB-11 mini */ ++ {USB_DEVICE(0x07aa, 0x0011), USB_DEVICE_DATA(BOARD_503)}, ++ /* Corega Wireless LAN USB-11 mini2 */ ++ {USB_DEVICE(0x07aa, 0x0018), USB_DEVICE_DATA(BOARD_503)}, ++ /* Uniden PCW100 */ ++ {USB_DEVICE(0x05dd, 0xff35), USB_DEVICE_DATA(BOARD_503)}, ++ /* ++ * at76c503-rfmd-acc ++ */ ++ /* SMC2664W */ ++ {USB_DEVICE(0x083a, 0x3501), USB_DEVICE_DATA(BOARD_503_ACC)}, ++ /* Belkin F5D6050, SMC2662W v2, SMC2662W-AR */ ++ {USB_DEVICE(0x0d5c, 0xa002), USB_DEVICE_DATA(BOARD_503_ACC)}, ++ /* ++ * at76c505-rfmd ++ */ ++ /* Generic AT76C505/RFMD */ ++ {USB_DEVICE(0x03eb, 0x7606), USB_DEVICE_DATA(BOARD_505)}, ++ /* ++ * at76c505-rfmd2958 ++ */ ++ /* Generic AT76C505/RFMD, OvisLink WL-1130USB */ ++ {USB_DEVICE(0x03eb, 0x7613), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* Fiberline FL-WL240U */ ++ {USB_DEVICE(0x1371, 0x0014), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* CNet CNUSB-611G */ ++ {USB_DEVICE(0x1371, 0x0013), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* Linksys WUSB11 v2.8 */ ++ {USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */ ++ {USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* Corega WLAN USB Stick 11 */ ++ {USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* Microstar MSI Box MS6978 */ ++ {USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958)}, ++ /* ++ * at76c505a-rfmd2958 ++ */ ++ /* Generic AT76C505A device */ ++ {USB_DEVICE(0x03eb, 0x7614), USB_DEVICE_DATA(BOARD_505A)}, ++ /* Generic AT76C505AS device */ ++ {USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A)}, ++ /* Siemens Gigaset USB WLAN Adapter 11 */ ++ {USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A)}, ++ /* ++ * at76c505amx-rfmd ++ */ ++ /* Generic AT76C505AMX device */ ++ {USB_DEVICE(0x03eb, 0x7615), USB_DEVICE_DATA(BOARD_505AMX)}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(usb, dev_table); ++ ++/* Supported rates of this hardware, bit 7 marks basic rates */ ++static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 }; ++ ++/* Frequency of each channel in MHz */ ++static const long channel_frequency[] = { ++ 2412, 2417, 2422, 2427, 2432, 2437, 2442, ++ 2447, 2452, 2457, 2462, 2467, 2472, 2484 ++}; ++ ++#define NUM_CHANNELS ARRAY_SIZE(channel_frequency) ++ ++static const char *const preambles[] = { "long", "short", "auto" }; ++ ++static const char *const mac_states[] = { ++ [MAC_INIT] = "INIT", ++ [MAC_SCANNING] = "SCANNING", ++ [MAC_AUTH] = "AUTH", ++ [MAC_ASSOC] = "ASSOC", ++ [MAC_JOINING] = "JOINING", ++ [MAC_CONNECTED] = "CONNECTED", ++ [MAC_OWN_IBSS] = "OWN_IBSS" ++}; ++ ++/* Firmware download */ ++/* DFU states */ ++#define STATE_IDLE 0x00 ++#define STATE_DETACH 0x01 ++#define STATE_DFU_IDLE 0x02 ++#define STATE_DFU_DOWNLOAD_SYNC 0x03 ++#define STATE_DFU_DOWNLOAD_BUSY 0x04 ++#define STATE_DFU_DOWNLOAD_IDLE 0x05 ++#define STATE_DFU_MANIFEST_SYNC 0x06 ++#define STATE_DFU_MANIFEST 0x07 ++#define STATE_DFU_MANIFEST_WAIT_RESET 0x08 ++#define STATE_DFU_UPLOAD_IDLE 0x09 ++#define STATE_DFU_ERROR 0x0a ++ ++/* DFU commands */ ++#define DFU_DETACH 0 ++#define DFU_DNLOAD 1 ++#define DFU_UPLOAD 2 ++#define DFU_GETSTATUS 3 ++#define DFU_CLRSTATUS 4 ++#define DFU_GETSTATE 5 ++#define DFU_ABORT 6 ++ ++#define FW_BLOCK_SIZE 1024 ++ ++struct dfu_status { ++ unsigned char status; ++ unsigned char poll_timeout[3]; ++ unsigned char state; ++ unsigned char string; ++} __attribute__((packed)); ++ ++static inline int at76_is_intersil(enum board_type board) ++{ ++ return (board == BOARD_503_ISL3861 || board == BOARD_503_ISL3863); ++} ++ ++static inline int at76_is_503rfmd(enum board_type board) ++{ ++ return (board == BOARD_503 || board == BOARD_503_ACC); ++} ++ ++static inline int at76_is_505a(enum board_type board) ++{ ++ return (board == BOARD_505A || board == BOARD_505AMX); ++} ++ ++/* Load a block of the first (internal) part of the firmware */ ++static int at76_load_int_fw_block(struct usb_device *udev, int blockno, ++ void *block, int size) ++{ ++ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), DFU_DNLOAD, ++ USB_TYPE_CLASS | USB_DIR_OUT | ++ USB_RECIP_INTERFACE, blockno, 0, block, size, ++ USB_CTRL_GET_TIMEOUT); ++} ++ ++static int at76_dfu_get_status(struct usb_device *udev, ++ struct dfu_status *status) ++{ ++ int ret; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATUS, ++ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, ++ 0, 0, status, sizeof(struct dfu_status), ++ USB_CTRL_GET_TIMEOUT); ++ return ret; ++} ++ ++static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state) ++{ ++ int ret; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATE, ++ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, ++ 0, 0, state, 1, USB_CTRL_GET_TIMEOUT); ++ return ret; ++} ++ ++/* Convert timeout from the DFU status to jiffies */ ++static inline unsigned long at76_get_timeout(struct dfu_status *s) ++{ ++ return msecs_to_jiffies((s->poll_timeout[2] << 16) ++ | (s->poll_timeout[1] << 8) ++ | (s->poll_timeout[0])); ++} ++ ++/* Load internal firmware from the buffer. If manifest_sync_timeout > 0, use ++ * its value in jiffies in the MANIFEST_SYNC state. */ ++static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size, ++ int manifest_sync_timeout) ++{ ++ u8 *block; ++ struct dfu_status dfu_stat_buf; ++ int ret = 0; ++ int need_dfu_state = 1; ++ int is_done = 0; ++ u8 dfu_state = 0; ++ u32 dfu_timeout = 0; ++ int bsize = 0; ++ int blockno = 0; ++ ++ at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size, ++ manifest_sync_timeout); ++ ++ if (!size) { ++ dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n"); ++ return -EINVAL; ++ } ++ ++ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL); ++ if (!block) ++ return -ENOMEM; ++ ++ do { ++ if (need_dfu_state) { ++ ret = at76_dfu_get_state(udev, &dfu_state); ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &udev->dev, ++ "cannot get DFU state: %d\n", ret); ++ goto exit; ++ } ++ need_dfu_state = 0; ++ } ++ ++ switch (dfu_state) { ++ case STATE_DFU_DOWNLOAD_SYNC: ++ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC"); ++ ret = at76_dfu_get_status(udev, &dfu_stat_buf); ++ if (ret >= 0) { ++ dfu_state = dfu_stat_buf.state; ++ dfu_timeout = at76_get_timeout(&dfu_stat_buf); ++ need_dfu_state = 0; ++ } else ++ dev_printk(KERN_ERR, &udev->dev, ++ "at76_dfu_get_status returned %d\n", ++ ret); ++ break; ++ ++ case STATE_DFU_DOWNLOAD_BUSY: ++ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY"); ++ need_dfu_state = 1; ++ ++ at76_dbg(DBG_DFU, "DFU: Resetting device"); ++ schedule_timeout_interruptible(dfu_timeout); ++ break; ++ ++ case STATE_DFU_DOWNLOAD_IDLE: ++ at76_dbg(DBG_DFU, "DOWNLOAD..."); ++ /* fall through */ ++ case STATE_DFU_IDLE: ++ at76_dbg(DBG_DFU, "DFU IDLE"); ++ ++ bsize = min_t(int, size, FW_BLOCK_SIZE); ++ memcpy(block, buf, bsize); ++ at76_dbg(DBG_DFU, "int fw, size left = %5d, " ++ "bsize = %4d, blockno = %2d", size, bsize, ++ blockno); ++ ret = ++ at76_load_int_fw_block(udev, blockno, block, bsize); ++ buf += bsize; ++ size -= bsize; ++ blockno++; ++ ++ if (ret != bsize) ++ dev_printk(KERN_ERR, &udev->dev, ++ "at76_load_int_fw_block " ++ "returned %d\n", ret); ++ need_dfu_state = 1; ++ break; ++ ++ case STATE_DFU_MANIFEST_SYNC: ++ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC"); ++ ++ ret = at76_dfu_get_status(udev, &dfu_stat_buf); ++ if (ret < 0) ++ break; ++ ++ dfu_state = dfu_stat_buf.state; ++ dfu_timeout = at76_get_timeout(&dfu_stat_buf); ++ need_dfu_state = 0; ++ ++ /* override the timeout from the status response, ++ needed for AT76C505A */ ++ if (manifest_sync_timeout > 0) ++ dfu_timeout = manifest_sync_timeout; ++ ++ at76_dbg(DBG_DFU, "DFU: Waiting for manifest phase"); ++ schedule_timeout_interruptible(dfu_timeout); ++ break; ++ ++ case STATE_DFU_MANIFEST: ++ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST"); ++ is_done = 1; ++ break; ++ ++ case STATE_DFU_MANIFEST_WAIT_RESET: ++ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET"); ++ is_done = 1; ++ break; ++ ++ case STATE_DFU_UPLOAD_IDLE: ++ at76_dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE"); ++ break; ++ ++ case STATE_DFU_ERROR: ++ at76_dbg(DBG_DFU, "STATE_DFU_ERROR"); ++ ret = -EPIPE; ++ break; ++ ++ default: ++ at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state); ++ ret = -EINVAL; ++ break; ++ } ++ } while (!is_done && (ret >= 0)); ++ ++exit: ++ kfree(block); ++ if (ret >= 0) ++ ret = 0; ++ ++ return ret; ++} ++ ++/* Report that the scan results are ready */ ++static inline void at76_iwevent_scan_complete(struct net_device *netdev) ++{ ++ union iwreq_data wrqu; ++ wrqu.data.length = 0; ++ wrqu.data.flags = 0; ++ wireless_send_event(netdev, SIOCGIWSCAN, &wrqu, NULL); ++ at76_dbg(DBG_WE_EVENTS, "%s: SIOCGIWSCAN sent", netdev->name); ++} ++ ++static inline void at76_iwevent_bss_connect(struct net_device *netdev, ++ u8 *bssid) ++{ ++ union iwreq_data wrqu; ++ wrqu.data.length = 0; ++ wrqu.data.flags = 0; ++ memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL); ++ at76_dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", netdev->name, ++ __func__); ++} ++ ++static inline void at76_iwevent_bss_disconnect(struct net_device *netdev) ++{ ++ union iwreq_data wrqu; ++ wrqu.data.length = 0; ++ wrqu.data.flags = 0; ++ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL); ++ at76_dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", netdev->name, ++ __func__); ++} ++ ++#define HEX2STR_BUFFERS 4 ++#define HEX2STR_MAX_LEN 64 ++#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10) ++ ++/* Convert binary data into hex string */ ++static char *hex2str(void *buf, int len) ++{ ++ static atomic_t a = ATOMIC_INIT(0); ++ static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1]; ++ char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)]; ++ char *obuf = ret; ++ u8 *ibuf = buf; ++ ++ if (len > HEX2STR_MAX_LEN) ++ len = HEX2STR_MAX_LEN; ++ ++ if (len <= 0) { ++ ret[0] = '\0'; ++ return ret; ++ } ++ ++ while (len--) { ++ *obuf++ = BIN2HEX(*ibuf >> 4); ++ *obuf++ = BIN2HEX(*ibuf & 0xf); ++ *obuf++ = '-'; ++ ibuf++; ++ } ++ *(--obuf) = '\0'; ++ ++ return ret; ++} ++ ++#define MAC2STR_BUFFERS 4 ++ ++static inline char *mac2str(u8 *mac) ++{ ++ static atomic_t a = ATOMIC_INIT(0); ++ static char bufs[MAC2STR_BUFFERS][6 * 3]; ++ char *str; ++ ++ str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)]; ++ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ++ return str; ++} ++ ++/* LED trigger */ ++static int tx_activity; ++static void at76_ledtrig_tx_timerfunc(unsigned long data); ++static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0); ++DEFINE_LED_TRIGGER(ledtrig_tx); ++ ++static void at76_ledtrig_tx_timerfunc(unsigned long data) ++{ ++ static int tx_lastactivity; ++ ++ if (tx_lastactivity != tx_activity) { ++ tx_lastactivity = tx_activity; ++ led_trigger_event(ledtrig_tx, LED_FULL); ++ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4); ++ } else ++ led_trigger_event(ledtrig_tx, LED_OFF); ++} ++ ++static void at76_ledtrig_tx_activity(void) ++{ ++ tx_activity++; ++ if (!timer_pending(&ledtrig_tx_timer)) ++ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4); ++} ++ ++/* Check if the given ssid is hidden */ ++static inline int at76_is_hidden_ssid(u8 *ssid, int length) ++{ ++ static const u8 zeros[32]; ++ ++ if (length == 0) ++ return 1; ++ ++ if (length == 1 && ssid[0] == ' ') ++ return 1; ++ ++ return (memcmp(ssid, zeros, length) == 0); ++} ++ ++static inline void at76_free_bss_list(struct at76_priv *priv) ++{ ++ struct list_head *next, *ptr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->bss_list_spinlock, flags); ++ ++ priv->curr_bss = NULL; ++ ++ list_for_each_safe(ptr, next, &priv->bss_list) { ++ list_del(ptr); ++ kfree(list_entry(ptr, struct bss_info, list)); ++ } ++ ++ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags); ++} ++ ++static int at76_remap(struct usb_device *udev) ++{ ++ int ret; ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0a, ++ USB_TYPE_VENDOR | USB_DIR_OUT | ++ USB_RECIP_INTERFACE, 0, 0, NULL, 0, ++ USB_CTRL_GET_TIMEOUT); ++ if (ret < 0) ++ return ret; ++ return 0; ++} ++ ++static int at76_get_op_mode(struct usb_device *udev) ++{ ++ int ret; ++ u8 op_mode; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, ++ USB_TYPE_VENDOR | USB_DIR_IN | ++ USB_RECIP_INTERFACE, 0x01, 0, &op_mode, 1, ++ USB_CTRL_GET_TIMEOUT); ++ if (ret < 0) ++ return ret; ++ else if (ret < 1) ++ return -EIO; ++ else ++ return op_mode; ++} ++ ++/* Load a block of the second ("external") part of the firmware */ ++static inline int at76_load_ext_fw_block(struct usb_device *udev, int blockno, ++ void *block, int size) ++{ ++ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e, ++ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, ++ 0x0802, blockno, block, size, ++ USB_CTRL_GET_TIMEOUT); ++} ++ ++static inline int at76_get_hw_cfg(struct usb_device *udev, ++ union at76_hwcfg *buf, int buf_size) ++{ ++ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, ++ USB_TYPE_VENDOR | USB_DIR_IN | ++ USB_RECIP_INTERFACE, 0x0a02, 0, ++ buf, buf_size, USB_CTRL_GET_TIMEOUT); ++} ++ ++/* Intersil boards use a different "value" for GetHWConfig requests */ ++static inline int at76_get_hw_cfg_intersil(struct usb_device *udev, ++ union at76_hwcfg *buf, int buf_size) ++{ ++ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, ++ USB_TYPE_VENDOR | USB_DIR_IN | ++ USB_RECIP_INTERFACE, 0x0902, 0, ++ buf, buf_size, USB_CTRL_GET_TIMEOUT); ++} ++ ++/* Get the hardware configuration for the adapter and put it to the appropriate ++ * fields of 'priv' (the GetHWConfig request and interpretation of the result ++ * depends on the board type) */ ++static int at76_get_hw_config(struct at76_priv *priv) ++{ ++ int ret; ++ union at76_hwcfg *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL); ++ ++ if (!hwcfg) ++ return -ENOMEM; ++ ++ if (at76_is_intersil(priv->board_type)) { ++ ret = at76_get_hw_cfg_intersil(priv->udev, hwcfg, ++ sizeof(hwcfg->i)); ++ if (ret < 0) ++ goto exit; ++ memcpy(priv->mac_addr, hwcfg->i.mac_addr, ETH_ALEN); ++ priv->regulatory_domain = hwcfg->i.regulatory_domain; ++ } else if (at76_is_503rfmd(priv->board_type)) { ++ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r3)); ++ if (ret < 0) ++ goto exit; ++ memcpy(priv->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN); ++ priv->regulatory_domain = hwcfg->r3.regulatory_domain; ++ } else { ++ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r5)); ++ if (ret < 0) ++ goto exit; ++ memcpy(priv->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN); ++ priv->regulatory_domain = hwcfg->r5.regulatory_domain; ++ } ++ ++exit: ++ kfree(hwcfg); ++ if (ret < 0) ++ printk(KERN_ERR "%s: cannot get HW Config (error %d)\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static struct reg_domain const *at76_get_reg_domain(u16 code) ++{ ++ int i; ++ static struct reg_domain const fd_tab[] = { ++ {0x10, "FCC (USA)", 0x7ff}, /* ch 1-11 */ ++ {0x20, "IC (Canada)", 0x7ff}, /* ch 1-11 */ ++ {0x30, "ETSI (most of Europe)", 0x1fff}, /* ch 1-13 */ ++ {0x31, "Spain", 0x600}, /* ch 10-11 */ ++ {0x32, "France", 0x1e00}, /* ch 10-13 */ ++ {0x40, "MKK (Japan)", 0x2000}, /* ch 14 */ ++ {0x41, "MKK1 (Japan)", 0x3fff}, /* ch 1-14 */ ++ {0x50, "Israel", 0x3fc}, /* ch 3-9 */ ++ {0x00, "", 0xffffffff} /* ch 1-32 */ ++ }; ++ ++ /* Last entry is fallback for unknown domain code */ ++ for (i = 0; i < ARRAY_SIZE(fd_tab) - 1; i++) ++ if (code == fd_tab[i].code) ++ break; ++ ++ return &fd_tab[i]; ++} ++ ++static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf, ++ int buf_size) ++{ ++ int ret; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, ++ USB_TYPE_VENDOR | USB_DIR_IN | ++ USB_RECIP_INTERFACE, mib << 8, 0, buf, buf_size, ++ USB_CTRL_GET_TIMEOUT); ++ if (ret >= 0 && ret != buf_size) ++ return -EIO; ++ return ret; ++} ++ ++/* Return positive number for status, negative for an error */ ++static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd) ++{ ++ u8 stat_buf[40]; ++ int ret; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x22, ++ USB_TYPE_VENDOR | USB_DIR_IN | ++ USB_RECIP_INTERFACE, cmd, 0, stat_buf, ++ sizeof(stat_buf), USB_CTRL_GET_TIMEOUT); ++ if (ret < 0) ++ return ret; ++ ++ return stat_buf[5]; ++} ++ ++static int at76_set_card_command(struct usb_device *udev, int cmd, void *buf, ++ int buf_size) ++{ ++ int ret; ++ struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) + ++ buf_size, GFP_KERNEL); ++ ++ if (!cmd_buf) ++ return -ENOMEM; ++ ++ cmd_buf->cmd = cmd; ++ cmd_buf->reserved = 0; ++ cmd_buf->size = cpu_to_le16(buf_size); ++ memcpy(cmd_buf->data, buf, buf_size); ++ ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e, ++ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, ++ 0, 0, cmd_buf, ++ sizeof(struct at76_command) + buf_size, ++ USB_CTRL_GET_TIMEOUT); ++ kfree(cmd_buf); ++ return ret; ++} ++ ++#define MAKE_CMD_STATUS_CASE(c) case (c): return #c ++static const char *at76_get_cmd_status_string(u8 cmd_status) ++{ ++ switch (cmd_status) { ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE); ++ MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED); ++ } ++ ++ return "UNKNOWN"; ++} ++ ++/* Wait until the command is completed */ ++static int at76_wait_completion(struct at76_priv *priv, int cmd) ++{ ++ int status = 0; ++ unsigned long timeout = jiffies + CMD_COMPLETION_TIMEOUT; ++ ++ do { ++ status = at76_get_cmd_status(priv->udev, cmd); ++ if (status < 0) { ++ printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n", ++ priv->netdev->name, status); ++ break; ++ } ++ ++ at76_dbg(DBG_WAIT_COMPLETE, ++ "%s: Waiting on cmd %d, status = %d (%s)", ++ priv->netdev->name, cmd, status, ++ at76_get_cmd_status_string(status)); ++ ++ if (status != CMD_STATUS_IN_PROGRESS ++ && status != CMD_STATUS_IDLE) ++ break; ++ ++ schedule_timeout_interruptible(HZ / 10); /* 100 ms */ ++ if (time_after(jiffies, timeout)) { ++ printk(KERN_ERR ++ "%s: completion timeout for command %d\n", ++ priv->netdev->name, cmd); ++ status = -ETIMEDOUT; ++ break; ++ } ++ } while (1); ++ ++ return status; ++} ++ ++static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf) ++{ ++ int ret; ++ ++ ret = at76_set_card_command(priv->udev, CMD_SET_MIB, buf, ++ offsetof(struct set_mib_buffer, ++ data) + buf->size); ++ if (ret < 0) ++ return ret; ++ ++ ret = at76_wait_completion(priv, CMD_SET_MIB); ++ if (ret != CMD_STATUS_COMPLETE) { ++ printk(KERN_INFO ++ "%s: set_mib: at76_wait_completion failed " ++ "with %d\n", priv->netdev->name, ret); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++/* Return < 0 on error, == 0 if no command sent, == 1 if cmd sent */ ++static int at76_set_radio(struct at76_priv *priv, int enable) ++{ ++ int ret; ++ int cmd; ++ ++ if (priv->radio_on == enable) ++ return 0; ++ ++ cmd = enable ? CMD_RADIO_ON : CMD_RADIO_OFF; ++ ++ ret = at76_set_card_command(priv->udev, cmd, NULL, 0); ++ if (ret < 0) ++ printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n", ++ priv->netdev->name, cmd, ret); ++ else ++ ret = 1; ++ ++ priv->radio_on = enable; ++ return ret; ++} ++ ++/* Set current power save mode (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART) */ ++static int at76_set_pm_mode(struct at76_priv *priv) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_MAC_MGMT; ++ priv->mib_buf.size = 1; ++ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, power_mgmt_mode); ++ priv->mib_buf.data.byte = priv->pm_mode; ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++/* Set the association id for power save mode */ ++static int at76_set_associd(struct at76_priv *priv, u16 id) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_MAC_MGMT; ++ priv->mib_buf.size = 2; ++ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, station_id); ++ priv->mib_buf.data.word = cpu_to_le16(id); ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (associd) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++/* Set the listen interval for power save mode */ ++static int at76_set_listen_interval(struct at76_priv *priv, u16 interval) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_MAC; ++ priv->mib_buf.size = 2; ++ priv->mib_buf.index = offsetof(struct mib_mac, listen_interval); ++ priv->mib_buf.data.word = cpu_to_le16(interval); ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR ++ "%s: set_mib (listen_interval) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static int at76_set_preamble(struct at76_priv *priv, u8 type) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_LOCAL; ++ priv->mib_buf.size = 1; ++ priv->mib_buf.index = offsetof(struct mib_local, preamble_type); ++ priv->mib_buf.data.byte = type; ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static int at76_set_frag(struct at76_priv *priv, u16 size) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_MAC; ++ priv->mib_buf.size = 2; ++ priv->mib_buf.index = offsetof(struct mib_mac, frag_threshold); ++ priv->mib_buf.data.word = cpu_to_le16(size); ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static int at76_set_rts(struct at76_priv *priv, u16 size) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_MAC; ++ priv->mib_buf.size = 2; ++ priv->mib_buf.index = offsetof(struct mib_mac, rts_threshold); ++ priv->mib_buf.data.word = cpu_to_le16(size); ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (rts) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_LOCAL; ++ priv->mib_buf.size = 1; ++ priv->mib_buf.index = offsetof(struct mib_local, txautorate_fallback); ++ priv->mib_buf.data.byte = onoff; ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static int at76_add_mac_address(struct at76_priv *priv, void *addr) ++{ ++ int ret = 0; ++ ++ priv->mib_buf.type = MIB_MAC_ADDR; ++ priv->mib_buf.size = ETH_ALEN; ++ priv->mib_buf.index = offsetof(struct mib_mac_addr, mac_addr); ++ memcpy(priv->mib_buf.data.addr, addr, ETH_ALEN); ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (MAC_ADDR, mac_addr) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ return ret; ++} ++ ++static void at76_dump_mib_mac_addr(struct at76_priv *priv) ++{ ++ int i; ++ int ret; ++ struct mib_mac_addr *m = kmalloc(sizeof(struct mib_mac_addr), ++ GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m, ++ sizeof(struct mib_mac_addr)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x", ++ priv->netdev->name, ++ mac2str(m->mac_addr), m->res[0], m->res[1]); ++ for (i = 0; i < ARRAY_SIZE(m->group_addr); i++) ++ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, " ++ "status %d", priv->netdev->name, i, ++ mac2str(m->group_addr[i]), m->group_addr_status[i]); ++exit: ++ kfree(m); ++} ++ ++static void at76_dump_mib_mac_wep(struct at76_priv *priv) ++{ ++ int i; ++ int ret; ++ int key_len; ++ struct mib_mac_wep *m = kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m, ++ sizeof(struct mib_mac_wep)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: priv_invoked %u def_key_id %u " ++ "key_len %u excl_unencr %u wep_icv_err %u wep_excluded %u " ++ "encr_level %u key %d", priv->netdev->name, ++ m->privacy_invoked, m->wep_default_key_id, ++ m->wep_key_mapping_len, m->exclude_unencrypted, ++ le32_to_cpu(m->wep_icv_error_count), ++ le32_to_cpu(m->wep_excluded_count), m->encryption_level, ++ m->wep_default_key_id); ++ ++ key_len = (m->encryption_level == 1) ? ++ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; ++ ++ for (i = 0; i < WEP_KEYS; i++) ++ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s", ++ priv->netdev->name, i, ++ hex2str(m->wep_default_keyvalue[i], key_len)); ++exit: ++ kfree(m); ++} ++ ++static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) ++{ ++ int ret; ++ struct mib_mac_mgmt *m = kmalloc(sizeof(struct mib_mac_mgmt), ++ GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m, ++ sizeof(struct mib_mac_mgmt)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration " ++ "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d " ++ "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d " ++ "current_bssid %s current_essid %s current_bss_type %d " ++ "pm_mode %d ibss_change %d res %d " ++ "multi_domain_capability_implemented %d " ++ "international_roaming %d country_string %.3s", ++ priv->netdev->name, le16_to_cpu(m->beacon_period), ++ le16_to_cpu(m->CFP_max_duration), ++ le16_to_cpu(m->medium_occupancy_limit), ++ le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window), ++ m->CFP_mode, m->privacy_option_implemented, m->DTIM_period, ++ m->CFP_period, mac2str(m->current_bssid), ++ hex2str(m->current_essid, IW_ESSID_MAX_SIZE), ++ m->current_bss_type, m->power_mgmt_mode, m->ibss_change, ++ m->res, m->multi_domain_capability_implemented, ++ m->multi_domain_capability_enabled, m->country_string); ++exit: ++ kfree(m); ++} ++ ++static void at76_dump_mib_mac(struct at76_priv *priv) ++{ ++ int ret; ++ struct mib_mac *m = kmalloc(sizeof(struct mib_mac), GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB MAC: max_tx_msdu_lifetime %d " ++ "max_rx_lifetime %d frag_threshold %d rts_threshold %d " ++ "cwmin %d cwmax %d short_retry_time %d long_retry_time %d " ++ "scan_type %d scan_channel %d probe_delay %u " ++ "min_channel_time %d max_channel_time %d listen_int %d " ++ "desired_ssid %s desired_bssid %s desired_bsstype %d", ++ priv->netdev->name, le32_to_cpu(m->max_tx_msdu_lifetime), ++ le32_to_cpu(m->max_rx_lifetime), ++ le16_to_cpu(m->frag_threshold), le16_to_cpu(m->rts_threshold), ++ le16_to_cpu(m->cwmin), le16_to_cpu(m->cwmax), ++ m->short_retry_time, m->long_retry_time, m->scan_type, ++ m->scan_channel, le16_to_cpu(m->probe_delay), ++ le16_to_cpu(m->min_channel_time), ++ le16_to_cpu(m->max_channel_time), ++ le16_to_cpu(m->listen_interval), ++ hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE), ++ mac2str(m->desired_bssid), m->desired_bsstype); ++exit: ++ kfree(m); ++} ++ ++static void at76_dump_mib_phy(struct at76_priv *priv) ++{ ++ int ret; ++ struct mib_phy *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB PHY: ed_threshold %d slot_time %d " ++ "sifs_time %d preamble_length %d plcp_header_length %d " ++ "mpdu_max_length %d cca_mode_supported %d operation_rate_set " ++ "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d " ++ "phy_type %d current_reg_domain %d", ++ priv->netdev->name, le32_to_cpu(m->ed_threshold), ++ le16_to_cpu(m->slot_time), le16_to_cpu(m->sifs_time), ++ le16_to_cpu(m->preamble_length), ++ le16_to_cpu(m->plcp_header_length), ++ le16_to_cpu(m->mpdu_max_length), ++ le16_to_cpu(m->cca_mode_supported), m->operation_rate_set[0], ++ m->operation_rate_set[1], m->operation_rate_set[2], ++ m->operation_rate_set[3], m->channel_id, m->current_cca_mode, ++ m->phy_type, m->current_reg_domain); ++exit: ++ kfree(m); ++} ++ ++static void at76_dump_mib_local(struct at76_priv *priv) ++{ ++ int ret; ++ struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB LOCAL: beacon_enable %d " ++ "txautorate_fallback %d ssid_size %d promiscuous_mode %d " ++ "preamble_type %d", priv->netdev->name, m->beacon_enable, ++ m->txautorate_fallback, m->ssid_size, m->promiscuous_mode, ++ m->preamble_type); ++exit: ++ kfree(m); ++} ++ ++static void at76_dump_mib_mdomain(struct at76_priv *priv) ++{ ++ int ret; ++ struct mib_mdomain *m = kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL); ++ ++ if (!m) ++ return; ++ ++ ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m, ++ sizeof(struct mib_mdomain)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s", ++ priv->netdev->name, ++ hex2str(m->channel_list, sizeof(m->channel_list))); ++ ++ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s", ++ priv->netdev->name, ++ hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel))); ++exit: ++ kfree(m); ++} ++ ++static int at76_get_current_bssid(struct at76_priv *priv) ++{ ++ int ret = 0; ++ struct mib_mac_mgmt *mac_mgmt = ++ kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL); ++ ++ if (!mac_mgmt) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, mac_mgmt, ++ sizeof(struct mib_mac_mgmt)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib failed: %d\n", ++ priv->netdev->name, ret); ++ goto error; ++ } ++ memcpy(priv->bssid, mac_mgmt->current_bssid, ETH_ALEN); ++ printk(KERN_INFO "%s: using BSSID %s\n", priv->netdev->name, ++ mac2str(priv->bssid)); ++error: ++ kfree(mac_mgmt); ++exit: ++ return ret; ++} ++ ++static int at76_get_current_channel(struct at76_priv *priv) ++{ ++ int ret = 0; ++ struct mib_phy *phy = kmalloc(sizeof(struct mib_phy), GFP_KERNEL); ++ ++ if (!phy) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ret = at76_get_mib(priv->udev, MIB_PHY, phy, sizeof(struct mib_phy)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib(MIB_PHY) failed: %d\n", ++ priv->netdev->name, ret); ++ goto error; ++ } ++ priv->channel = phy->channel_id; ++error: ++ kfree(phy); ++exit: ++ return ret; ++} ++ ++/** ++ * at76_start_scan - start a scan ++ * ++ * @use_essid - use the configured ESSID in non passive mode ++ */ ++static int at76_start_scan(struct at76_priv *priv, int use_essid) ++{ ++ struct at76_req_scan scan; ++ ++ memset(&scan, 0, sizeof(struct at76_req_scan)); ++ memset(scan.bssid, 0xff, ETH_ALEN); ++ ++ if (use_essid) { ++ memcpy(scan.essid, priv->essid, IW_ESSID_MAX_SIZE); ++ scan.essid_size = priv->essid_size; ++ } else ++ scan.essid_size = 0; ++ ++ /* jal: why should we start at a certain channel? we do scan the whole ++ range allowed by reg domain. */ ++ scan.channel = priv->channel; ++ ++ /* atmelwlandriver differs between scan type 0 and 1 (active/passive) ++ For ad-hoc mode, it uses type 0 only. */ ++ scan.scan_type = priv->scan_mode; ++ ++ /* INFO: For probe_delay, not multiplying by 1024 as this will be ++ slightly less than min_channel_time ++ (per spec: probe delay < min. channel time) */ ++ scan.min_channel_time = cpu_to_le16(priv->scan_min_time); ++ scan.max_channel_time = cpu_to_le16(priv->scan_max_time); ++ scan.probe_delay = cpu_to_le16(priv->scan_min_time * 1000); ++ scan.international_scan = 0; ++ ++ /* other values are set to 0 for type 0 */ ++ ++ at76_dbg(DBG_PROGRESS, "%s: start_scan (use_essid = %d, intl = %d, " ++ "channel = %d, probe_delay = %d, scan_min_time = %d, " ++ "scan_max_time = %d)", ++ priv->netdev->name, use_essid, ++ scan.international_scan, scan.channel, ++ le16_to_cpu(scan.probe_delay), ++ le16_to_cpu(scan.min_channel_time), ++ le16_to_cpu(scan.max_channel_time)); ++ ++ return at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); ++} ++ ++/* Enable monitor mode */ ++static int at76_start_monitor(struct at76_priv *priv) ++{ ++ struct at76_req_scan scan; ++ int ret; ++ ++ memset(&scan, 0, sizeof(struct at76_req_scan)); ++ memset(scan.bssid, 0xff, ETH_ALEN); ++ ++ scan.channel = priv->channel; ++ scan.scan_type = SCAN_TYPE_PASSIVE; ++ scan.international_scan = 0; ++ ++ ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); ++ if (ret >= 0) ++ ret = at76_get_cmd_status(priv->udev, CMD_SCAN); ++ ++ return ret; ++} ++ ++static int at76_start_ibss(struct at76_priv *priv) ++{ ++ struct at76_req_ibss bss; ++ int ret; ++ ++ WARN_ON(priv->mac_state != MAC_OWN_IBSS); ++ if (priv->mac_state != MAC_OWN_IBSS) ++ return -EBUSY; ++ ++ memset(&bss, 0, sizeof(struct at76_req_ibss)); ++ memset(bss.bssid, 0xff, ETH_ALEN); ++ memcpy(bss.essid, priv->essid, IW_ESSID_MAX_SIZE); ++ bss.essid_size = priv->essid_size; ++ bss.bss_type = ADHOC_MODE; ++ bss.channel = priv->channel; ++ ++ ret = at76_set_card_command(priv->udev, CMD_START_IBSS, &bss, ++ sizeof(struct at76_req_ibss)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: start_ibss failed: %d\n", ++ priv->netdev->name, ret); ++ return ret; ++ } ++ ++ ret = at76_wait_completion(priv, CMD_START_IBSS); ++ if (ret != CMD_STATUS_COMPLETE) { ++ printk(KERN_ERR "%s: start_ibss failed to complete, %d\n", ++ priv->netdev->name, ret); ++ return ret; ++ } ++ ++ ret = at76_get_current_bssid(priv); ++ if (ret < 0) ++ return ret; ++ ++ ret = at76_get_current_channel(priv); ++ if (ret < 0) ++ return ret; ++ ++ /* not sure what this is good for ??? */ ++ priv->mib_buf.type = MIB_MAC_MGMT; ++ priv->mib_buf.size = 1; ++ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, ibss_change); ++ priv->mib_buf.data.byte = 0; ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: set_mib (ibss change ok) failed: %d\n", ++ priv->netdev->name, ret); ++ return ret; ++ } ++ ++ netif_carrier_on(priv->netdev); ++ netif_start_queue(priv->netdev); ++ return 0; ++} ++ ++/* Request card to join BSS in managed or ad-hoc mode */ ++static int at76_join_bss(struct at76_priv *priv, struct bss_info *ptr) ++{ ++ struct at76_req_join join; ++ ++ BUG_ON(!ptr); ++ ++ memset(&join, 0, sizeof(struct at76_req_join)); ++ memcpy(join.bssid, ptr->bssid, ETH_ALEN); ++ memcpy(join.essid, ptr->ssid, ptr->ssid_len); ++ join.essid_size = ptr->ssid_len; ++ join.bss_type = (priv->iw_mode == IW_MODE_ADHOC ? 1 : 2); ++ join.channel = ptr->channel; ++ join.timeout = cpu_to_le16(2000); ++ ++ at76_dbg(DBG_PROGRESS, ++ "%s join addr %s ssid %s type %d ch %d timeout %d", ++ priv->netdev->name, mac2str(join.bssid), join.essid, ++ join.bss_type, join.channel, le16_to_cpu(join.timeout)); ++ return at76_set_card_command(priv->udev, CMD_JOIN, &join, ++ sizeof(struct at76_req_join)); ++} ++ ++/* Calculate padding from txbuf->wlength (which excludes the USB TX header), ++ likely to compensate a flaw in the AT76C503A USB part ... */ ++static inline int at76_calc_padding(int wlen) ++{ ++ /* add the USB TX header */ ++ wlen += AT76_TX_HDRLEN; ++ ++ wlen = wlen % 64; ++ ++ if (wlen < 50) ++ return 50 - wlen; ++ ++ if (wlen >= 61) ++ return 64 + 50 - wlen; ++ ++ return 0; ++} ++ ++/* We are doing a lot of things here in an interrupt. Need ++ a bh handler (Watching TV with a TV card is probably ++ a good test: if you see flickers, we are doing too much. ++ Currently I do see flickers... even with our tasklet :-( ) ++ Maybe because the bttv driver and usb-uhci use the same interrupt ++*/ ++/* Or maybe because our BH handler is preempting bttv's BH handler.. BHs don't ++ * solve everything.. (alex) */ ++static void at76_rx_callback(struct urb *urb) ++{ ++ struct at76_priv *priv = urb->context; ++ ++ priv->rx_tasklet.data = (unsigned long)urb; ++ tasklet_schedule(&priv->rx_tasklet); ++ return; ++} ++ ++static void at76_tx_callback(struct urb *urb) ++{ ++ struct at76_priv *priv = urb->context; ++ struct net_device_stats *stats = &priv->stats; ++ unsigned long flags; ++ struct at76_tx_buffer *mgmt_buf; ++ int ret; ++ ++ switch (urb->status) { ++ case 0: ++ stats->tx_packets++; ++ break; ++ case -ENOENT: ++ case -ECONNRESET: ++ /* urb has been unlinked */ ++ return; ++ default: ++ at76_dbg(DBG_URB, "%s - nonzero tx status received: %d", ++ __func__, urb->status); ++ stats->tx_errors++; ++ break; ++ } ++ ++ spin_lock_irqsave(&priv->mgmt_spinlock, flags); ++ mgmt_buf = priv->next_mgmt_bulk; ++ priv->next_mgmt_bulk = NULL; ++ spin_unlock_irqrestore(&priv->mgmt_spinlock, flags); ++ ++ if (!mgmt_buf) { ++ netif_wake_queue(priv->netdev); ++ return; ++ } ++ ++ /* we don't copy the padding bytes, but add them ++ to the length */ ++ memcpy(priv->bulk_out_buffer, mgmt_buf, ++ le16_to_cpu(mgmt_buf->wlength) + AT76_TX_HDRLEN); ++ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, ++ priv->bulk_out_buffer, ++ le16_to_cpu(mgmt_buf->wlength) + mgmt_buf->padding + ++ AT76_TX_HDRLEN, at76_tx_callback, priv); ++ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC); ++ if (ret) ++ printk(KERN_ERR "%s: error in tx submit urb: %d\n", ++ priv->netdev->name, ret); ++ ++ kfree(mgmt_buf); ++} ++ ++/* Send a management frame on bulk-out. txbuf->wlength must be set */ ++static int at76_tx_mgmt(struct at76_priv *priv, struct at76_tx_buffer *txbuf) ++{ ++ unsigned long flags; ++ int ret; ++ int urb_status; ++ void *oldbuf = NULL; ++ ++ netif_carrier_off(priv->netdev); /* stop netdev watchdog */ ++ netif_stop_queue(priv->netdev); /* stop tx data packets */ ++ ++ spin_lock_irqsave(&priv->mgmt_spinlock, flags); ++ ++ urb_status = priv->tx_urb->status; ++ if (urb_status == -EINPROGRESS) { ++ /* cannot transmit now, put in the queue */ ++ oldbuf = priv->next_mgmt_bulk; ++ priv->next_mgmt_bulk = txbuf; ++ } ++ spin_unlock_irqrestore(&priv->mgmt_spinlock, flags); ++ ++ if (oldbuf) { ++ /* a data/mgmt tx is already pending in the URB - ++ if this is no error in some situations we must ++ implement a queue or silently modify the old msg */ ++ printk(KERN_ERR "%s: removed pending mgmt buffer %s\n", ++ priv->netdev->name, hex2str(oldbuf, 64)); ++ kfree(oldbuf); ++ return 0; ++ } ++ ++ txbuf->tx_rate = TX_RATE_1MBIT; ++ txbuf->padding = at76_calc_padding(le16_to_cpu(txbuf->wlength)); ++ memset(txbuf->reserved, 0, sizeof(txbuf->reserved)); ++ ++ if (priv->next_mgmt_bulk) ++ printk(KERN_ERR "%s: URB status %d, but mgmt is pending\n", ++ priv->netdev->name, urb_status); ++ ++ at76_dbg(DBG_TX_MGMT, ++ "%s: tx mgmt: wlen %d tx_rate %d pad %d %s", ++ priv->netdev->name, le16_to_cpu(txbuf->wlength), ++ txbuf->tx_rate, txbuf->padding, ++ hex2str(txbuf->packet, le16_to_cpu(txbuf->wlength))); ++ ++ /* txbuf was not consumed above -> send mgmt msg immediately */ ++ memcpy(priv->bulk_out_buffer, txbuf, ++ le16_to_cpu(txbuf->wlength) + AT76_TX_HDRLEN); ++ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, ++ priv->bulk_out_buffer, ++ le16_to_cpu(txbuf->wlength) + txbuf->padding + ++ AT76_TX_HDRLEN, at76_tx_callback, priv); ++ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC); ++ if (ret) ++ printk(KERN_ERR "%s: error in tx submit urb: %d\n", ++ priv->netdev->name, ret); ++ ++ kfree(txbuf); ++ ++ return ret; ++} ++ ++/* Go to the next information element */ ++static inline void next_ie(struct ieee80211_info_element **ie) ++{ ++ *ie = (struct ieee80211_info_element *)(&(*ie)->data[(*ie)->len]); ++} ++ ++/* Challenge is the challenge string (in TLV format) ++ we got with seq_nr 2 for shared secret authentication only and ++ send in seq_nr 3 WEP encrypted to prove we have the correct WEP key; ++ otherwise it is NULL */ ++static int at76_auth_req(struct at76_priv *priv, struct bss_info *bss, ++ int seq_nr, struct ieee80211_info_element *challenge) ++{ ++ struct at76_tx_buffer *tx_buffer; ++ struct ieee80211_hdr_3addr *mgmt; ++ struct ieee80211_auth *req; ++ int buf_len = (seq_nr != 3 ? AUTH_FRAME_SIZE : ++ AUTH_FRAME_SIZE + 1 + 1 + challenge->len); ++ ++ BUG_ON(!bss); ++ BUG_ON(seq_nr == 3 && !challenge); ++ tx_buffer = kmalloc(buf_len + MAX_PADDING_SIZE, GFP_ATOMIC); ++ if (!tx_buffer) ++ return -ENOMEM; ++ ++ req = (struct ieee80211_auth *)tx_buffer->packet; ++ mgmt = &req->header; ++ ++ /* make wireless header */ ++ /* first auth msg is not encrypted, only the second (seq_nr == 3) */ ++ mgmt->frame_ctl = ++ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH | ++ (seq_nr == 3 ? IEEE80211_FCTL_PROTECTED : 0)); ++ ++ mgmt->duration_id = cpu_to_le16(0x8000); ++ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN); ++ memcpy(mgmt->addr2, priv->netdev->dev_addr, ETH_ALEN); ++ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN); ++ mgmt->seq_ctl = cpu_to_le16(0); ++ ++ req->algorithm = cpu_to_le16(priv->auth_mode); ++ req->transaction = cpu_to_le16(seq_nr); ++ req->status = cpu_to_le16(0); ++ ++ if (seq_nr == 3) ++ memcpy(req->info_element, challenge, 1 + 1 + challenge->len); ++ ++ /* init. at76_priv tx header */ ++ tx_buffer->wlength = cpu_to_le16(buf_len - AT76_TX_HDRLEN); ++ at76_dbg(DBG_TX_MGMT, "%s: AuthReq bssid %s alg %d seq_nr %d", ++ priv->netdev->name, mac2str(mgmt->addr3), ++ le16_to_cpu(req->algorithm), le16_to_cpu(req->transaction)); ++ if (seq_nr == 3) ++ at76_dbg(DBG_TX_MGMT, "%s: AuthReq challenge: %s ...", ++ priv->netdev->name, hex2str(req->info_element, 18)); ++ ++ /* either send immediately (if no data tx is pending ++ or put it in pending list */ ++ return at76_tx_mgmt(priv, tx_buffer); ++} ++ ++static int at76_assoc_req(struct at76_priv *priv, struct bss_info *bss) ++{ ++ struct at76_tx_buffer *tx_buffer; ++ struct ieee80211_hdr_3addr *mgmt; ++ struct ieee80211_assoc_request *req; ++ struct ieee80211_info_element *ie; ++ char *essid; ++ int essid_len; ++ u16 capa; ++ ++ BUG_ON(!bss); ++ ++ tx_buffer = kmalloc(ASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC); ++ if (!tx_buffer) ++ return -ENOMEM; ++ ++ req = (struct ieee80211_assoc_request *)tx_buffer->packet; ++ mgmt = &req->header; ++ ie = req->info_element; ++ ++ /* make wireless header */ ++ mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | ++ IEEE80211_STYPE_ASSOC_REQ); ++ ++ mgmt->duration_id = cpu_to_le16(0x8000); ++ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN); ++ memcpy(mgmt->addr2, priv->netdev->dev_addr, ETH_ALEN); ++ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN); ++ mgmt->seq_ctl = cpu_to_le16(0); ++ ++ /* we must set the Privacy bit in the capabilities to assure an ++ Agere-based AP with optional WEP transmits encrypted frames ++ to us. AP only set the Privacy bit in their capabilities ++ if WEP is mandatory in the BSS! */ ++ capa = bss->capa; ++ if (priv->wep_enabled) ++ capa |= WLAN_CAPABILITY_PRIVACY; ++ if (priv->preamble_type != PREAMBLE_TYPE_LONG) ++ capa |= WLAN_CAPABILITY_SHORT_PREAMBLE; ++ req->capability = cpu_to_le16(capa); ++ ++ req->listen_interval = cpu_to_le16(2 * bss->beacon_interval); ++ ++ /* write TLV data elements */ ++ ++ ie->id = MFIE_TYPE_SSID; ++ ie->len = bss->ssid_len; ++ memcpy(ie->data, bss->ssid, bss->ssid_len); ++ next_ie(&ie); ++ ++ ie->id = MFIE_TYPE_RATES; ++ ie->len = sizeof(hw_rates); ++ memcpy(ie->data, hw_rates, sizeof(hw_rates)); ++ next_ie(&ie); /* ie points behind the supp_rates field */ ++ ++ /* init. at76_priv tx header */ ++ tx_buffer->wlength = cpu_to_le16((u8 *)ie - (u8 *)mgmt); ++ ++ ie = req->info_element; ++ essid = ie->data; ++ essid_len = min_t(int, IW_ESSID_MAX_SIZE, ie->len); ++ ++ next_ie(&ie); /* points to IE of rates now */ ++ at76_dbg(DBG_TX_MGMT, ++ "%s: AssocReq bssid %s capa 0x%04x ssid %.*s rates %s", ++ priv->netdev->name, mac2str(mgmt->addr3), ++ le16_to_cpu(req->capability), essid_len, essid, ++ hex2str(ie->data, ie->len)); ++ ++ /* either send immediately (if no data tx is pending ++ or put it in pending list */ ++ return at76_tx_mgmt(priv, tx_buffer); ++} ++ ++/* We got to check the bss_list for old entries */ ++static void at76_bss_list_timeout(unsigned long par) ++{ ++ struct at76_priv *priv = (struct at76_priv *)par; ++ unsigned long flags; ++ struct list_head *lptr, *nptr; ++ struct bss_info *ptr; ++ ++ spin_lock_irqsave(&priv->bss_list_spinlock, flags); ++ ++ list_for_each_safe(lptr, nptr, &priv->bss_list) { ++ ++ ptr = list_entry(lptr, struct bss_info, list); ++ ++ if (ptr != priv->curr_bss ++ && time_after(jiffies, ptr->last_rx + BSS_LIST_TIMEOUT)) { ++ at76_dbg(DBG_BSS_TABLE_RM, ++ "%s: bss_list: removing old BSS %s ch %d", ++ priv->netdev->name, mac2str(ptr->bssid), ++ ptr->channel); ++ list_del(&ptr->list); ++ kfree(ptr); ++ } ++ } ++ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags); ++ /* restart the timer */ ++ mod_timer(&priv->bss_list_timer, jiffies + BSS_LIST_TIMEOUT); ++} ++ ++static inline void at76_set_mac_state(struct at76_priv *priv, ++ enum mac_state mac_state) ++{ ++ at76_dbg(DBG_MAC_STATE, "%s state: %s", priv->netdev->name, ++ mac_states[mac_state]); ++ priv->mac_state = mac_state; ++} ++ ++static void at76_dump_bss_table(struct at76_priv *priv) ++{ ++ struct bss_info *ptr; ++ unsigned long flags; ++ struct list_head *lptr; ++ ++ spin_lock_irqsave(&priv->bss_list_spinlock, flags); ++ ++ at76_dbg(DBG_BSS_TABLE, "%s BSS table (curr=%p):", priv->netdev->name, ++ priv->curr_bss); ++ ++ list_for_each(lptr, &priv->bss_list) { ++ ptr = list_entry(lptr, struct bss_info, list); ++ at76_dbg(DBG_BSS_TABLE, "0x%p: bssid %s channel %d ssid %.*s " ++ "(%s) capa 0x%04x rates %s rssi %d link %d noise %d", ++ ptr, mac2str(ptr->bssid), ptr->channel, ptr->ssid_len, ++ ptr->ssid, hex2str(ptr->ssid, ptr->ssid_len), ++ ptr->capa, hex2str(ptr->rates, ptr->rates_len), ++ ptr->rssi, ptr->link_qual, ptr->noise_level); ++ } ++ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags); ++} ++ ++/* Called upon successful association to mark interface as connected */ ++static void at76_work_assoc_done(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ work_assoc_done); ++ ++ mutex_lock(&priv->mtx); ++ ++ WARN_ON(priv->mac_state != MAC_ASSOC); ++ WARN_ON(!priv->curr_bss); ++ if (priv->mac_state != MAC_ASSOC || !priv->curr_bss) ++ goto exit; ++ ++ if (priv->iw_mode == IW_MODE_INFRA) { ++ if (priv->pm_mode != AT76_PM_OFF) { ++ /* calculate the listen interval in units of ++ beacon intervals of the curr_bss */ ++ u32 pm_period_beacon = (priv->pm_period >> 10) / ++ priv->curr_bss->beacon_interval; ++ ++ pm_period_beacon = max(pm_period_beacon, 2u); ++ pm_period_beacon = min(pm_period_beacon, 0xffffu); ++ ++ at76_dbg(DBG_PM, ++ "%s: pm_mode %d assoc id 0x%x listen int %d", ++ priv->netdev->name, priv->pm_mode, ++ priv->assoc_id, pm_period_beacon); ++ ++ at76_set_associd(priv, priv->assoc_id); ++ at76_set_listen_interval(priv, (u16)pm_period_beacon); ++ } ++ schedule_delayed_work(&priv->dwork_beacon, BEACON_TIMEOUT); ++ } ++ at76_set_pm_mode(priv); ++ ++ netif_carrier_on(priv->netdev); ++ netif_wake_queue(priv->netdev); ++ at76_set_mac_state(priv, MAC_CONNECTED); ++ at76_iwevent_bss_connect(priv->netdev, priv->curr_bss->bssid); ++ at76_dbg(DBG_PROGRESS, "%s: connected to BSSID %s", ++ priv->netdev->name, mac2str(priv->curr_bss->bssid)); ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* We only store the new mac address in netdev struct, ++ it gets set when the netdev is opened. */ ++static int at76_set_mac_address(struct net_device *netdev, void *addr) ++{ ++ struct sockaddr *mac = addr; ++ memcpy(netdev->dev_addr, mac->sa_data, ETH_ALEN); ++ return 1; ++} ++ ++static struct net_device_stats *at76_get_stats(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ return &priv->stats; ++} ++ ++static struct iw_statistics *at76_get_wireless_stats(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, "RETURN qual %d level %d noise %d updated %d", ++ priv->wstats.qual.qual, priv->wstats.qual.level, ++ priv->wstats.qual.noise, priv->wstats.qual.updated); ++ ++ return &priv->wstats; ++} ++ ++static void at76_set_multicast(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int promisc; ++ ++ promisc = ((netdev->flags & IFF_PROMISC) != 0); ++ if (promisc != priv->promisc) { ++ /* This gets called in interrupt, must reschedule */ ++ priv->promisc = promisc; ++ schedule_work(&priv->work_set_promisc); ++ } ++} ++ ++/* Stop all network activity, flush all pending tasks */ ++static void at76_quiesce(struct at76_priv *priv) ++{ ++ unsigned long flags; ++ ++ netif_stop_queue(priv->netdev); ++ netif_carrier_off(priv->netdev); ++ ++ at76_set_mac_state(priv, MAC_INIT); ++ ++ cancel_delayed_work(&priv->dwork_get_scan); ++ cancel_delayed_work(&priv->dwork_beacon); ++ cancel_delayed_work(&priv->dwork_auth); ++ cancel_delayed_work(&priv->dwork_assoc); ++ cancel_delayed_work(&priv->dwork_restart); ++ ++ spin_lock_irqsave(&priv->mgmt_spinlock, flags); ++ kfree(priv->next_mgmt_bulk); ++ priv->next_mgmt_bulk = NULL; ++ spin_unlock_irqrestore(&priv->mgmt_spinlock, flags); ++} ++ ++/******************************************************************************* ++ * at76_priv implementations of iw_handler functions: ++ */ ++static int at76_iw_handler_commit(struct net_device *netdev, ++ struct iw_request_info *info, ++ void *null, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, "%s %s: restarting the device", netdev->name, ++ __func__); ++ ++ if (priv->mac_state != MAC_INIT) ++ at76_quiesce(priv); ++ ++ /* Wait half second before the restart to process subsequent ++ * requests from the same iwconfig in a single restart */ ++ schedule_delayed_work(&priv->dwork_restart, HZ / 2); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_get_name(struct net_device *netdev, ++ struct iw_request_info *info, ++ char *name, char *extra) ++{ ++ strcpy(name, "IEEE 802.11b"); ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWNAME - name %s", netdev->name, name); ++ return 0; ++} ++ ++static int at76_iw_handler_set_freq(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int chan = -1; ++ int ret = -EIWCOMMIT; ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - freq.m %d freq.e %d", ++ netdev->name, freq->m, freq->e); ++ ++ if ((freq->e == 0) && (freq->m <= 1000)) ++ /* Setting by channel number */ ++ chan = freq->m; ++ else { ++ /* Setting by frequency - search the table */ ++ int mult = 1; ++ int i; ++ ++ for (i = 0; i < (6 - freq->e); i++) ++ mult *= 10; ++ ++ for (i = 0; i < NUM_CHANNELS; i++) { ++ if (freq->m == (channel_frequency[i] * mult)) ++ chan = i + 1; ++ } ++ } ++ ++ if (chan < 1 || !priv->domain) ++ /* non-positive channels are invalid ++ * we need a domain info to set the channel ++ * either that or an invalid frequency was ++ * provided by the user */ ++ ret = -EINVAL; ++ else if (!(priv->domain->channel_map & (1 << (chan - 1)))) { ++ printk(KERN_INFO "%s: channel %d not allowed for domain %s\n", ++ priv->netdev->name, chan, priv->domain->name); ++ ret = -EINVAL; ++ } ++ ++ if (ret == -EIWCOMMIT) { ++ priv->channel = chan; ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - ch %d", netdev->name, ++ chan); ++ } ++ ++ return ret; ++} ++ ++static int at76_iw_handler_get_freq(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_freq *freq, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ freq->m = priv->channel; ++ freq->e = 0; ++ ++ if (priv->channel) ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - freq %ld x 10e%d", ++ netdev->name, channel_frequency[priv->channel - 1], 6); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - ch %d", netdev->name, ++ priv->channel); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_mode(struct net_device *netdev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode); ++ ++ if ((*mode != IW_MODE_ADHOC) && (*mode != IW_MODE_INFRA) && ++ (*mode != IW_MODE_MONITOR)) ++ return -EINVAL; ++ ++ priv->iw_mode = *mode; ++ if (priv->iw_mode != IW_MODE_INFRA) ++ priv->pm_mode = AT76_PM_OFF; ++ ++ return -EIWCOMMIT; ++} ++ ++static int at76_iw_handler_get_mode(struct net_device *netdev, ++ struct iw_request_info *info, ++ __u32 *mode, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ *mode = priv->iw_mode; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWMODE - %d", netdev->name, *mode); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_get_range(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ /* inspired by atmel.c */ ++ struct at76_priv *priv = netdev_priv(netdev); ++ struct iw_range *range = (struct iw_range *)extra; ++ int i; ++ ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ /* TODO: range->throughput = xxxxxx; */ ++ ++ range->min_nwid = 0x0000; ++ range->max_nwid = 0x0000; ++ ++ /* this driver doesn't maintain sensitivity information */ ++ range->sensitivity = 0; ++ ++ range->max_qual.qual = 100; ++ range->max_qual.level = 100; ++ range->max_qual.noise = 0; ++ range->max_qual.updated = IW_QUAL_NOISE_INVALID; ++ ++ range->avg_qual.qual = 50; ++ range->avg_qual.level = 50; ++ range->avg_qual.noise = 0; ++ range->avg_qual.updated = IW_QUAL_NOISE_INVALID; ++ ++ range->bitrate[0] = 1000000; ++ range->bitrate[1] = 2000000; ++ range->bitrate[2] = 5500000; ++ range->bitrate[3] = 11000000; ++ range->num_bitrates = 4; ++ ++ range->min_rts = 0; ++ range->max_rts = MAX_RTS_THRESHOLD; ++ ++ range->min_frag = MIN_FRAG_THRESHOLD; ++ range->max_frag = MAX_FRAG_THRESHOLD; ++ ++ range->pmp_flags = IW_POWER_PERIOD; ++ range->pmt_flags = IW_POWER_ON; ++ range->pm_capa = IW_POWER_PERIOD | IW_POWER_ALL_R; ++ ++ range->encoding_size[0] = WEP_SMALL_KEY_LEN; ++ range->encoding_size[1] = WEP_LARGE_KEY_LEN; ++ range->num_encoding_sizes = 2; ++ range->max_encoding_tokens = WEP_KEYS; ++ ++ /* both WL-240U and Linksys WUSB11 v2.6 specify 15 dBm as output power ++ - take this for all (ignore antenna gains) */ ++ range->txpower[0] = 15; ++ range->num_txpower = 1; ++ range->txpower_capa = IW_TXPOW_DBM; ++ ++ range->we_version_source = WIRELESS_EXT; ++ range->we_version_compiled = WIRELESS_EXT; ++ ++ /* same as the values used in atmel.c */ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->r_time_flags = 0; ++ range->min_retry = 1; ++ range->max_retry = 255; ++ ++ range->num_channels = NUM_CHANNELS; ++ range->num_frequency = 0; ++ ++ for (i = 0; i < NUM_CHANNELS; i++) { ++ /* test if channel map bit is raised */ ++ if (priv->domain->channel_map & (0x1 << i)) { ++ range->num_frequency += 1; ++ ++ range->freq[i].i = i + 1; ++ range->freq[i].m = channel_frequency[i] * 100000; ++ range->freq[i].e = 1; /* freq * 10^1 */ ++ } ++ } ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRANGE", netdev->name); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_spy(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = 0; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWSPY - number of addresses %d", ++ netdev->name, data->length); ++ ++ spin_lock_bh(&priv->spy_spinlock); ++ ret = iw_handler_set_spy(priv->netdev, info, (union iwreq_data *)data, ++ extra); ++ spin_unlock_bh(&priv->spy_spinlock); ++ ++ return ret; ++} ++ ++static int at76_iw_handler_get_spy(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = 0; ++ ++ spin_lock_bh(&priv->spy_spinlock); ++ ret = iw_handler_get_spy(priv->netdev, info, ++ (union iwreq_data *)data, extra); ++ spin_unlock_bh(&priv->spy_spinlock); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWSPY - number of addresses %d", ++ netdev->name, data->length); ++ ++ return ret; ++} ++ ++static int at76_iw_handler_set_thrspy(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWTHRSPY - number of addresses %d)", ++ netdev->name, data->length); ++ ++ spin_lock_bh(&priv->spy_spinlock); ++ ret = iw_handler_set_thrspy(netdev, info, (union iwreq_data *)data, ++ extra); ++ spin_unlock_bh(&priv->spy_spinlock); ++ ++ return ret; ++} ++ ++static int at76_iw_handler_get_thrspy(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret; ++ ++ spin_lock_bh(&priv->spy_spinlock); ++ ret = iw_handler_get_thrspy(netdev, info, (union iwreq_data *)data, ++ extra); ++ spin_unlock_bh(&priv->spy_spinlock); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWTHRSPY - number of addresses %d)", ++ netdev->name, data->length); ++ ++ return ret; ++} ++ ++static int at76_iw_handler_set_wap(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWAP - wap/bssid %s", netdev->name, ++ mac2str(ap_addr->sa_data)); ++ ++ /* if the incoming address == ff:ff:ff:ff:ff:ff, the user has ++ chosen any or auto AP preference */ ++ if (is_broadcast_ether_addr(ap_addr->sa_data) ++ || is_zero_ether_addr(ap_addr->sa_data)) ++ priv->wanted_bssid_valid = 0; ++ else { ++ /* user wants to set a preferred AP address */ ++ priv->wanted_bssid_valid = 1; ++ memcpy(priv->wanted_bssid, ap_addr->sa_data, ETH_ALEN); ++ } ++ ++ return -EIWCOMMIT; ++} ++ ++static int at76_iw_handler_get_wap(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct sockaddr *ap_addr, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ ap_addr->sa_family = ARPHRD_ETHER; ++ memcpy(ap_addr->sa_data, priv->bssid, ETH_ALEN); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWAP - wap/bssid %s", netdev->name, ++ mac2str(ap_addr->sa_data)); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_scan(struct net_device *netdev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = 0; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name); ++ ++ if (mutex_lock_interruptible(&priv->mtx)) ++ return -EINTR; ++ ++ if (!netif_running(netdev)) { ++ ret = -ENETDOWN; ++ goto exit; ++ } ++ ++ /* jal: we don't allow "iwlist ethX scan" while we are ++ in monitor mode */ ++ if (priv->iw_mode == IW_MODE_MONITOR) { ++ ret = -EBUSY; ++ goto exit; ++ } ++ ++ /* Discard old scan results */ ++ if ((jiffies - priv->last_scan) > (20 * HZ)) ++ priv->scan_state = SCAN_IDLE; ++ priv->last_scan = jiffies; ++ ++ /* Initiate a scan command */ ++ if (priv->scan_state == SCAN_IN_PROGRESS) { ++ ret = -EBUSY; ++ goto exit; ++ } ++ ++ priv->scan_state = SCAN_IN_PROGRESS; ++ ++ at76_quiesce(priv); ++ ++ /* Try to do passive or active scan if WE asks as. */ ++ if (wrqu->data.length ++ && wrqu->data.length == sizeof(struct iw_scan_req)) { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ++ if (req->scan_type == IW_SCAN_TYPE_PASSIVE) ++ priv->scan_mode = SCAN_TYPE_PASSIVE; ++ else if (req->scan_type == IW_SCAN_TYPE_ACTIVE) ++ priv->scan_mode = SCAN_TYPE_ACTIVE; ++ ++ /* Sanity check values? */ ++ if (req->min_channel_time > 0) ++ priv->scan_min_time = req->min_channel_time; ++ ++ if (req->max_channel_time > 0) ++ priv->scan_max_time = req->max_channel_time; ++ } ++ ++ /* change to scanning state */ ++ at76_set_mac_state(priv, MAC_SCANNING); ++ schedule_work(&priv->work_start_scan); ++ ++exit: ++ mutex_unlock(&priv->mtx); ++ return ret; ++} ++ ++static int at76_iw_handler_get_scan(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ unsigned long flags; ++ struct list_head *lptr, *nptr; ++ struct bss_info *curr_bss; ++ struct iw_event *iwe = kmalloc(sizeof(struct iw_event), GFP_KERNEL); ++ char *curr_val, *curr_pos = extra; ++ int i; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWSCAN", netdev->name); ++ ++ if (!iwe) ++ return -ENOMEM; ++ ++ if (priv->scan_state != SCAN_COMPLETED) ++ /* scan not yet finished */ ++ return -EAGAIN; ++ ++ spin_lock_irqsave(&priv->bss_list_spinlock, flags); ++ ++ list_for_each_safe(lptr, nptr, &priv->bss_list) { ++ curr_bss = list_entry(lptr, struct bss_info, list); ++ ++ iwe->cmd = SIOCGIWAP; ++ iwe->u.ap_addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwe->u.ap_addr.sa_data, curr_bss->bssid, 6); ++ curr_pos = iwe_stream_add_event(info, curr_pos, ++ extra + IW_SCAN_MAX_DATA, iwe, ++ IW_EV_ADDR_LEN); ++ ++ iwe->u.data.length = curr_bss->ssid_len; ++ iwe->cmd = SIOCGIWESSID; ++ iwe->u.data.flags = 1; ++ ++ curr_pos = iwe_stream_add_point(info, curr_pos, ++ extra + IW_SCAN_MAX_DATA, iwe, ++ curr_bss->ssid); ++ ++ iwe->cmd = SIOCGIWMODE; ++ iwe->u.mode = (curr_bss->capa & WLAN_CAPABILITY_IBSS) ? ++ IW_MODE_ADHOC : ++ (curr_bss->capa & WLAN_CAPABILITY_ESS) ? ++ IW_MODE_MASTER : IW_MODE_AUTO; ++ /* IW_MODE_AUTO = 0 which I thought is ++ * the most logical value to return in this case */ ++ curr_pos = iwe_stream_add_event(info, curr_pos, ++ extra + IW_SCAN_MAX_DATA, iwe, ++ IW_EV_UINT_LEN); ++ ++ iwe->cmd = SIOCGIWFREQ; ++ iwe->u.freq.m = curr_bss->channel; ++ iwe->u.freq.e = 0; ++ curr_pos = iwe_stream_add_event(info, curr_pos, ++ extra + IW_SCAN_MAX_DATA, iwe, ++ IW_EV_FREQ_LEN); ++ ++ iwe->cmd = SIOCGIWENCODE; ++ if (curr_bss->capa & WLAN_CAPABILITY_PRIVACY) ++ iwe->u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe->u.data.flags = IW_ENCODE_DISABLED; ++ ++ iwe->u.data.length = 0; ++ curr_pos = iwe_stream_add_point(info, curr_pos, ++ extra + IW_SCAN_MAX_DATA, iwe, ++ NULL); ++ ++ /* Add quality statistics */ ++ iwe->cmd = IWEVQUAL; ++ iwe->u.qual.noise = 0; ++ iwe->u.qual.updated = ++ IW_QUAL_NOISE_INVALID | IW_QUAL_LEVEL_UPDATED; ++ iwe->u.qual.level = (curr_bss->rssi * 100 / 42); ++ if (iwe->u.qual.level > 100) ++ iwe->u.qual.level = 100; ++ if (at76_is_intersil(priv->board_type)) ++ iwe->u.qual.qual = curr_bss->link_qual; ++ else { ++ iwe->u.qual.qual = 0; ++ iwe->u.qual.updated |= IW_QUAL_QUAL_INVALID; ++ } ++ /* Add new value to event */ ++ curr_pos = iwe_stream_add_event(info, curr_pos, ++ extra + IW_SCAN_MAX_DATA, iwe, ++ IW_EV_QUAL_LEN); ++ ++ /* Rate: stuffing multiple values in a single event requires ++ * a bit more of magic - Jean II */ ++ curr_val = curr_pos + IW_EV_LCP_LEN; ++ ++ iwe->cmd = SIOCGIWRATE; ++ /* Those two flags are ignored... */ ++ iwe->u.bitrate.fixed = 0; ++ iwe->u.bitrate.disabled = 0; ++ /* Max 8 values */ ++ for (i = 0; i < curr_bss->rates_len; i++) { ++ /* Bit rate given in 500 kb/s units (+ 0x80) */ ++ iwe->u.bitrate.value = ++ ((curr_bss->rates[i] & 0x7f) * 500000); ++ /* Add new value to event */ ++ curr_val = iwe_stream_add_value(info, curr_pos, ++ curr_val, ++ extra + ++ IW_SCAN_MAX_DATA, iwe, ++ IW_EV_PARAM_LEN); ++ } ++ ++ /* Check if we added any event */ ++ if ((curr_val - curr_pos) > IW_EV_LCP_LEN) ++ curr_pos = curr_val; ++ ++ /* more information may be sent back using IWECUSTOM */ ++ ++ } ++ ++ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags); ++ ++ data->length = (curr_pos - extra); ++ data->flags = 0; ++ ++ kfree(iwe); ++ return 0; ++} ++ ++static int at76_iw_handler_set_essid(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWESSID - %s", netdev->name, extra); ++ ++ if (data->flags) { ++ memcpy(priv->essid, extra, data->length); ++ priv->essid_size = data->length; ++ } else ++ priv->essid_size = 0; /* Use any SSID */ ++ ++ return -EIWCOMMIT; ++} ++ ++static int at76_iw_handler_get_essid(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ if (priv->essid_size) { ++ /* not the ANY ssid in priv->essid */ ++ data->flags = 1; ++ data->length = priv->essid_size; ++ memcpy(extra, priv->essid, data->length); ++ } else { ++ /* the ANY ssid was specified */ ++ if (priv->mac_state == MAC_CONNECTED && priv->curr_bss) { ++ /* report the SSID we have found */ ++ data->flags = 1; ++ data->length = priv->curr_bss->ssid_len; ++ memcpy(extra, priv->curr_bss->ssid, data->length); ++ } else { ++ /* report ANY back */ ++ data->flags = 0; ++ data->length = 0; ++ } ++ } ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWESSID - %.*s", netdev->name, ++ data->length, extra); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_rate(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *bitrate, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = -EIWCOMMIT; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRATE - %d", netdev->name, ++ bitrate->value); ++ ++ switch (bitrate->value) { ++ case -1: ++ priv->txrate = TX_RATE_AUTO; ++ break; /* auto rate */ ++ case 1000000: ++ priv->txrate = TX_RATE_1MBIT; ++ break; ++ case 2000000: ++ priv->txrate = TX_RATE_2MBIT; ++ break; ++ case 5500000: ++ priv->txrate = TX_RATE_5_5MBIT; ++ break; ++ case 11000000: ++ priv->txrate = TX_RATE_11MBIT; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int at76_iw_handler_get_rate(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *bitrate, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = 0; ++ ++ switch (priv->txrate) { ++ /* return max rate if RATE_AUTO */ ++ case TX_RATE_AUTO: ++ bitrate->value = 11000000; ++ break; ++ case TX_RATE_1MBIT: ++ bitrate->value = 1000000; ++ break; ++ case TX_RATE_2MBIT: ++ bitrate->value = 2000000; ++ break; ++ case TX_RATE_5_5MBIT: ++ bitrate->value = 5500000; ++ break; ++ case TX_RATE_11MBIT: ++ bitrate->value = 11000000; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ bitrate->fixed = (priv->txrate != TX_RATE_AUTO); ++ bitrate->disabled = 0; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRATE - %d", netdev->name, ++ bitrate->value); ++ ++ return ret; ++} ++ ++static int at76_iw_handler_set_rts(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = -EIWCOMMIT; ++ int rthr = rts->value; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRTS - value %d disabled %s", ++ netdev->name, rts->value, (rts->disabled) ? "true" : "false"); ++ ++ if (rts->disabled) ++ rthr = MAX_RTS_THRESHOLD; ++ ++ if ((rthr < 0) || (rthr > MAX_RTS_THRESHOLD)) ++ ret = -EINVAL; ++ else ++ priv->rts_threshold = rthr; ++ ++ return ret; ++} ++ ++static int at76_iw_handler_get_rts(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *rts, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ rts->value = priv->rts_threshold; ++ rts->disabled = (rts->value >= MAX_RTS_THRESHOLD); ++ rts->fixed = 1; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRTS - value %d disabled %s", ++ netdev->name, rts->value, (rts->disabled) ? "true" : "false"); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_frag(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = -EIWCOMMIT; ++ int fthr = frag->value; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFRAG - value %d, disabled %s", ++ netdev->name, frag->value, ++ (frag->disabled) ? "true" : "false"); ++ ++ if (frag->disabled) ++ fthr = MAX_FRAG_THRESHOLD; ++ ++ if ((fthr < MIN_FRAG_THRESHOLD) || (fthr > MAX_FRAG_THRESHOLD)) ++ ret = -EINVAL; ++ else ++ priv->frag_threshold = fthr & ~0x1; /* get an even value */ ++ ++ return ret; ++} ++ ++static int at76_iw_handler_get_frag(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *frag, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ frag->value = priv->frag_threshold; ++ frag->disabled = (frag->value >= MAX_FRAG_THRESHOLD); ++ frag->fixed = 1; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFRAG - value %d, disabled %s", ++ netdev->name, frag->value, ++ (frag->disabled) ? "true" : "false"); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_get_txpow(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *power, char *extra) ++{ ++ power->value = 15; ++ power->fixed = 1; /* No power control */ ++ power->disabled = 0; ++ power->flags = IW_TXPOW_DBM; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWTXPOW - txpow %d dBm", netdev->name, ++ power->value); ++ ++ return 0; ++} ++ ++/* jal: short retry is handled by the firmware (at least 0.90.x), ++ while long retry is not (?) */ ++static int at76_iw_handler_set_retry(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *retry, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = -EIWCOMMIT; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRETRY disabled %d flags 0x%x val %d", ++ netdev->name, retry->disabled, retry->flags, retry->value); ++ ++ if (!retry->disabled && (retry->flags & IW_RETRY_LIMIT)) { ++ if ((retry->flags & IW_RETRY_MIN) || ++ !(retry->flags & IW_RETRY_MAX)) ++ priv->short_retry_limit = retry->value; ++ else ++ ret = -EINVAL; ++ } else ++ ret = -EINVAL; ++ ++ return ret; ++} ++ ++/* Adapted (ripped) from atmel.c */ ++static int at76_iw_handler_get_retry(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *retry, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRETRY", netdev->name); ++ ++ retry->disabled = 0; /* Can't be disabled */ ++ retry->flags = IW_RETRY_LIMIT; ++ retry->value = priv->short_retry_limit; ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_encode(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *encoding, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int index = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ int len = encoding->length; ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - enc.flags %08x " ++ "pointer %p len %d", netdev->name, encoding->flags, ++ encoding->pointer, encoding->length); ++ at76_dbg(DBG_IOCTL, ++ "%s: SIOCSIWENCODE - old wepstate: enabled %s key_id %d " ++ "auth_mode %s", netdev->name, ++ (priv->wep_enabled) ? "true" : "false", priv->wep_key_id, ++ (priv->auth_mode == ++ WLAN_AUTH_SHARED_KEY) ? "restricted" : "open"); ++ ++ /* take the old default key if index is invalid */ ++ if ((index < 0) || (index >= WEP_KEYS)) ++ index = priv->wep_key_id; ++ ++ if (len > 0) { ++ if (len > WEP_LARGE_KEY_LEN) ++ len = WEP_LARGE_KEY_LEN; ++ ++ memset(priv->wep_keys[index], 0, WEP_KEY_LEN); ++ memcpy(priv->wep_keys[index], extra, len); ++ priv->wep_keys_len[index] = (len <= WEP_SMALL_KEY_LEN) ? ++ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; ++ priv->wep_enabled = 1; ++ } ++ ++ priv->wep_key_id = index; ++ priv->wep_enabled = ((encoding->flags & IW_ENCODE_DISABLED) == 0); ++ ++ if (encoding->flags & IW_ENCODE_RESTRICTED) ++ priv->auth_mode = WLAN_AUTH_SHARED_KEY; ++ if (encoding->flags & IW_ENCODE_OPEN) ++ priv->auth_mode = WLAN_AUTH_OPEN; ++ ++ at76_dbg(DBG_IOCTL, ++ "%s: SIOCSIWENCODE - new wepstate: enabled %s key_id %d " ++ "key_len %d auth_mode %s", netdev->name, ++ (priv->wep_enabled) ? "true" : "false", priv->wep_key_id + 1, ++ priv->wep_keys_len[priv->wep_key_id], ++ (priv->auth_mode == ++ WLAN_AUTH_SHARED_KEY) ? "restricted" : "open"); ++ ++ return -EIWCOMMIT; ++} ++ ++static int at76_iw_handler_get_encode(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *encoding, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int index = (encoding->flags & IW_ENCODE_INDEX) - 1; ++ ++ if ((index < 0) || (index >= WEP_KEYS)) ++ index = priv->wep_key_id; ++ ++ encoding->flags = ++ (priv->auth_mode == WLAN_AUTH_SHARED_KEY) ? ++ IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN; ++ ++ if (!priv->wep_enabled) ++ encoding->flags |= IW_ENCODE_DISABLED; ++ ++ if (encoding->pointer) { ++ encoding->length = priv->wep_keys_len[index]; ++ ++ memcpy(extra, priv->wep_keys[index], priv->wep_keys_len[index]); ++ ++ encoding->flags |= (index + 1); ++ } ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - enc.flags %08x " ++ "pointer %p len %d", netdev->name, encoding->flags, ++ encoding->pointer, encoding->length); ++ at76_dbg(DBG_IOCTL, ++ "%s: SIOCGIWENCODE - wepstate: enabled %s key_id %d " ++ "key_len %d auth_mode %s", netdev->name, ++ (priv->wep_enabled) ? "true" : "false", priv->wep_key_id + 1, ++ priv->wep_keys_len[priv->wep_key_id], ++ (priv->auth_mode == ++ WLAN_AUTH_SHARED_KEY) ? "restricted" : "open"); ++ ++ return 0; ++} ++ ++static int at76_iw_handler_set_power(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *prq, char *extra) ++{ ++ int err = -EIWCOMMIT; ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_IOCTL, ++ "%s: SIOCSIWPOWER - disabled %s flags 0x%x value 0x%x", ++ netdev->name, (prq->disabled) ? "true" : "false", prq->flags, ++ prq->value); ++ ++ if (prq->disabled) ++ priv->pm_mode = AT76_PM_OFF; ++ else { ++ switch (prq->flags & IW_POWER_MODE) { ++ case IW_POWER_ALL_R: ++ case IW_POWER_ON: ++ break; ++ default: ++ err = -EINVAL; ++ goto exit; ++ } ++ if (prq->flags & IW_POWER_PERIOD) ++ priv->pm_period = prq->value; ++ ++ if (prq->flags & IW_POWER_TIMEOUT) { ++ err = -EINVAL; ++ goto exit; ++ } ++ priv->pm_mode = AT76_PM_ON; ++ } ++exit: ++ return err; ++} ++ ++static int at76_iw_handler_get_power(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_param *power, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ power->disabled = (priv->pm_mode == AT76_PM_OFF); ++ if (!power->disabled) { ++ power->flags = IW_POWER_PERIOD | IW_POWER_ALL_R; ++ power->value = priv->pm_period; ++ } ++ ++ at76_dbg(DBG_IOCTL, "%s: SIOCGIWPOWER - %s flags 0x%x value 0x%x", ++ netdev->name, power->disabled ? "disabled" : "enabled", ++ power->flags, power->value); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * Private IOCTLS ++ */ ++static int at76_iw_set_short_preamble(struct net_device *netdev, ++ struct iw_request_info *info, char *name, ++ char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int val = *((int *)name); ++ int ret = -EIWCOMMIT; ++ ++ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SHORT_PREAMBLE, %d", ++ netdev->name, val); ++ ++ if (val < PREAMBLE_TYPE_LONG || val > PREAMBLE_TYPE_AUTO) ++ ret = -EINVAL; ++ else ++ priv->preamble_type = val; ++ ++ return ret; ++} ++ ++static int at76_iw_get_short_preamble(struct net_device *netdev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ snprintf(wrqu->name, sizeof(wrqu->name), "%s (%d)", ++ preambles[priv->preamble_type], priv->preamble_type); ++ return 0; ++} ++ ++static int at76_iw_set_debug(struct net_device *netdev, ++ struct iw_request_info *info, ++ struct iw_point *data, char *extra) ++{ ++ char *ptr; ++ u32 val; ++ ++ if (data->length > 0) { ++ val = simple_strtol(extra, &ptr, 0); ++ ++ if (ptr == extra) ++ val = DBG_DEFAULTS; ++ ++ at76_dbg(DBG_IOCTL, "%s: AT76_SET_DEBUG input %d: %s -> 0x%x", ++ netdev->name, data->length, extra, val); ++ } else ++ val = DBG_DEFAULTS; ++ ++ at76_dbg(DBG_IOCTL, "%s: AT76_SET_DEBUG, old 0x%x, new 0x%x", ++ netdev->name, at76_debug, val); ++ ++ /* jal: some more output to pin down lockups */ ++ at76_dbg(DBG_IOCTL, "%s: netif running %d queue_stopped %d " ++ "carrier_ok %d", netdev->name, netif_running(netdev), ++ netif_queue_stopped(netdev), netif_carrier_ok(netdev)); ++ ++ at76_debug = val; ++ ++ return 0; ++} ++ ++static int at76_iw_get_debug(struct net_device *netdev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ snprintf(wrqu->name, sizeof(wrqu->name), "0x%08x", at76_debug); ++ return 0; ++} ++ ++static int at76_iw_set_powersave_mode(struct net_device *netdev, ++ struct iw_request_info *info, char *name, ++ char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int val = *((int *)name); ++ int ret = -EIWCOMMIT; ++ ++ at76_dbg(DBG_IOCTL, "%s: AT76_SET_POWERSAVE_MODE, %d (%s)", ++ netdev->name, val, ++ val == AT76_PM_OFF ? "active" : val == AT76_PM_ON ? "save" : ++ val == AT76_PM_SMART ? "smart save" : ""); ++ if (val < AT76_PM_OFF || val > AT76_PM_SMART) ++ ret = -EINVAL; ++ else ++ priv->pm_mode = val; ++ ++ return ret; ++} ++ ++static int at76_iw_get_powersave_mode(struct net_device *netdev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int *param = (int *)extra; ++ ++ param[0] = priv->pm_mode; ++ return 0; ++} ++ ++static int at76_iw_set_scan_times(struct net_device *netdev, ++ struct iw_request_info *info, char *name, ++ char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int mint = *((int *)name); ++ int maxt = *((int *)name + 1); ++ int ret = -EIWCOMMIT; ++ ++ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SCAN_TIMES - min %d max %d", ++ netdev->name, mint, maxt); ++ if (mint <= 0 || maxt <= 0 || mint > maxt) ++ ret = -EINVAL; ++ else { ++ priv->scan_min_time = mint; ++ priv->scan_max_time = maxt; ++ } ++ ++ return ret; ++} ++ ++static int at76_iw_get_scan_times(struct net_device *netdev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int *param = (int *)extra; ++ ++ param[0] = priv->scan_min_time; ++ param[1] = priv->scan_max_time; ++ return 0; ++} ++ ++static int at76_iw_set_scan_mode(struct net_device *netdev, ++ struct iw_request_info *info, char *name, ++ char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int val = *((int *)name); ++ int ret = -EIWCOMMIT; ++ ++ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SCAN_MODE - mode %s", ++ netdev->name, (val = SCAN_TYPE_ACTIVE) ? "active" : ++ (val = SCAN_TYPE_PASSIVE) ? "passive" : ""); ++ ++ if (val != SCAN_TYPE_ACTIVE && val != SCAN_TYPE_PASSIVE) ++ ret = -EINVAL; ++ else ++ priv->scan_mode = val; ++ ++ return ret; ++} ++ ++static int at76_iw_get_scan_mode(struct net_device *netdev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int *param = (int *)extra; ++ ++ param[0] = priv->scan_mode; ++ return 0; ++} ++ ++#define AT76_SET_HANDLER(h, f) [h - SIOCIWFIRST] = (iw_handler) f ++ ++/* Standard wireless handlers */ ++static const iw_handler at76_handlers[] = { ++ AT76_SET_HANDLER(SIOCSIWCOMMIT, at76_iw_handler_commit), ++ AT76_SET_HANDLER(SIOCGIWNAME, at76_iw_handler_get_name), ++ AT76_SET_HANDLER(SIOCSIWFREQ, at76_iw_handler_set_freq), ++ AT76_SET_HANDLER(SIOCGIWFREQ, at76_iw_handler_get_freq), ++ AT76_SET_HANDLER(SIOCSIWMODE, at76_iw_handler_set_mode), ++ AT76_SET_HANDLER(SIOCGIWMODE, at76_iw_handler_get_mode), ++ AT76_SET_HANDLER(SIOCGIWRANGE, at76_iw_handler_get_range), ++ AT76_SET_HANDLER(SIOCSIWSPY, at76_iw_handler_set_spy), ++ AT76_SET_HANDLER(SIOCGIWSPY, at76_iw_handler_get_spy), ++ AT76_SET_HANDLER(SIOCSIWTHRSPY, at76_iw_handler_set_thrspy), ++ AT76_SET_HANDLER(SIOCGIWTHRSPY, at76_iw_handler_get_thrspy), ++ AT76_SET_HANDLER(SIOCSIWAP, at76_iw_handler_set_wap), ++ AT76_SET_HANDLER(SIOCGIWAP, at76_iw_handler_get_wap), ++ AT76_SET_HANDLER(SIOCSIWSCAN, at76_iw_handler_set_scan), ++ AT76_SET_HANDLER(SIOCGIWSCAN, at76_iw_handler_get_scan), ++ AT76_SET_HANDLER(SIOCSIWESSID, at76_iw_handler_set_essid), ++ AT76_SET_HANDLER(SIOCGIWESSID, at76_iw_handler_get_essid), ++ AT76_SET_HANDLER(SIOCSIWRATE, at76_iw_handler_set_rate), ++ AT76_SET_HANDLER(SIOCGIWRATE, at76_iw_handler_get_rate), ++ AT76_SET_HANDLER(SIOCSIWRTS, at76_iw_handler_set_rts), ++ AT76_SET_HANDLER(SIOCGIWRTS, at76_iw_handler_get_rts), ++ AT76_SET_HANDLER(SIOCSIWFRAG, at76_iw_handler_set_frag), ++ AT76_SET_HANDLER(SIOCGIWFRAG, at76_iw_handler_get_frag), ++ AT76_SET_HANDLER(SIOCGIWTXPOW, at76_iw_handler_get_txpow), ++ AT76_SET_HANDLER(SIOCSIWRETRY, at76_iw_handler_set_retry), ++ AT76_SET_HANDLER(SIOCGIWRETRY, at76_iw_handler_get_retry), ++ AT76_SET_HANDLER(SIOCSIWENCODE, at76_iw_handler_set_encode), ++ AT76_SET_HANDLER(SIOCGIWENCODE, at76_iw_handler_get_encode), ++ AT76_SET_HANDLER(SIOCSIWPOWER, at76_iw_handler_set_power), ++ AT76_SET_HANDLER(SIOCGIWPOWER, at76_iw_handler_get_power) ++}; ++ ++#define AT76_SET_PRIV(h, f) [h - SIOCIWFIRSTPRIV] = (iw_handler) f ++ ++/* Private wireless handlers */ ++static const iw_handler at76_priv_handlers[] = { ++ AT76_SET_PRIV(AT76_SET_SHORT_PREAMBLE, at76_iw_set_short_preamble), ++ AT76_SET_PRIV(AT76_GET_SHORT_PREAMBLE, at76_iw_get_short_preamble), ++ AT76_SET_PRIV(AT76_SET_DEBUG, at76_iw_set_debug), ++ AT76_SET_PRIV(AT76_GET_DEBUG, at76_iw_get_debug), ++ AT76_SET_PRIV(AT76_SET_POWERSAVE_MODE, at76_iw_set_powersave_mode), ++ AT76_SET_PRIV(AT76_GET_POWERSAVE_MODE, at76_iw_get_powersave_mode), ++ AT76_SET_PRIV(AT76_SET_SCAN_TIMES, at76_iw_set_scan_times), ++ AT76_SET_PRIV(AT76_GET_SCAN_TIMES, at76_iw_get_scan_times), ++ AT76_SET_PRIV(AT76_SET_SCAN_MODE, at76_iw_set_scan_mode), ++ AT76_SET_PRIV(AT76_GET_SCAN_MODE, at76_iw_get_scan_mode), ++}; ++ ++/* Names and arguments of private wireless handlers */ ++static const struct iw_priv_args at76_priv_args[] = { ++ /* 0 - long, 1 - short */ ++ {AT76_SET_SHORT_PREAMBLE, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"}, ++ ++ {AT76_GET_SHORT_PREAMBLE, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 10, "get_preamble"}, ++ ++ /* we must pass the new debug mask as a string, because iwpriv cannot ++ * parse hex numbers starting with 0x :-( */ ++ {AT76_SET_DEBUG, ++ IW_PRIV_TYPE_CHAR | 10, 0, "set_debug"}, ++ ++ {AT76_GET_DEBUG, ++ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 10, "get_debug"}, ++ ++ /* 1 - active, 2 - power save, 3 - smart power save */ ++ {AT76_SET_POWERSAVE_MODE, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_powersave"}, ++ ++ {AT76_GET_POWERSAVE_MODE, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_powersave"}, ++ ++ /* min_channel_time, max_channel_time */ ++ {AT76_SET_SCAN_TIMES, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_scan_times"}, ++ ++ {AT76_GET_SCAN_TIMES, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, "get_scan_times"}, ++ ++ /* 0 - active, 1 - passive scan */ ++ {AT76_SET_SCAN_MODE, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_scan_mode"}, ++ ++ {AT76_GET_SCAN_MODE, ++ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_scan_mode"}, ++}; ++ ++static const struct iw_handler_def at76_handler_def = { ++ .num_standard = ARRAY_SIZE(at76_handlers), ++ .num_private = ARRAY_SIZE(at76_priv_handlers), ++ .num_private_args = ARRAY_SIZE(at76_priv_args), ++ .standard = at76_handlers, ++ .private = at76_priv_handlers, ++ .private_args = at76_priv_args, ++ .get_wireless_stats = at76_get_wireless_stats, ++}; ++ ++static const u8 snapsig[] = { 0xaa, 0xaa, 0x03 }; ++ ++/* RFC 1042 encapsulates Ethernet frames in 802.2 SNAP (0xaa, 0xaa, 0x03) with ++ * a SNAP OID of 0 (0x00, 0x00, 0x00) */ ++static const u8 rfc1042sig[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ++ ++static int at76_tx(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ struct net_device_stats *stats = &priv->stats; ++ int ret = 0; ++ int wlen; ++ int submit_len; ++ struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; ++ struct ieee80211_hdr_3addr *i802_11_hdr = ++ (struct ieee80211_hdr_3addr *)tx_buffer->packet; ++ u8 *payload = i802_11_hdr->payload; ++ struct ethhdr *eh = (struct ethhdr *)skb->data; ++ ++ if (netif_queue_stopped(netdev)) { ++ printk(KERN_ERR "%s: %s called while netdev is stopped\n", ++ netdev->name, __func__); ++ /* skip this packet */ ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ if (priv->tx_urb->status == -EINPROGRESS) { ++ printk(KERN_ERR "%s: %s called while tx urb is pending\n", ++ netdev->name, __func__); ++ /* skip this packet */ ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ if (skb->len < ETH_HLEN) { ++ printk(KERN_ERR "%s: %s: skb too short (%d)\n", ++ netdev->name, __func__, skb->len); ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ ++ ++ /* we can get rid of memcpy if we set netdev->hard_header_len to ++ reserve enough space, but we would need to keep the skb around */ ++ ++ if (ntohs(eh->h_proto) <= ETH_DATA_LEN) { ++ /* this is a 802.3 packet */ ++ if (skb->len >= ETH_HLEN + sizeof(rfc1042sig) ++ && skb->data[ETH_HLEN] == rfc1042sig[0] ++ && skb->data[ETH_HLEN + 1] == rfc1042sig[1]) { ++ /* higher layer delivered SNAP header - keep it */ ++ memcpy(payload, skb->data + ETH_HLEN, ++ skb->len - ETH_HLEN); ++ wlen = IEEE80211_3ADDR_LEN + skb->len - ETH_HLEN; ++ } else { ++ printk(KERN_ERR "%s: dropping non-SNAP 802.2 packet " ++ "(DSAP 0x%02x SSAP 0x%02x cntrl 0x%02x)\n", ++ priv->netdev->name, skb->data[ETH_HLEN], ++ skb->data[ETH_HLEN + 1], ++ skb->data[ETH_HLEN + 2]); ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ } else { ++ /* add RFC 1042 header in front */ ++ memcpy(payload, rfc1042sig, sizeof(rfc1042sig)); ++ memcpy(payload + sizeof(rfc1042sig), &eh->h_proto, ++ skb->len - offsetof(struct ethhdr, h_proto)); ++ wlen = IEEE80211_3ADDR_LEN + sizeof(rfc1042sig) + skb->len - ++ offsetof(struct ethhdr, h_proto); ++ } ++ ++ /* make wireless header */ ++ i802_11_hdr->frame_ctl = ++ cpu_to_le16(IEEE80211_FTYPE_DATA | ++ (priv->wep_enabled ? IEEE80211_FCTL_PROTECTED : 0) | ++ (priv->iw_mode == ++ IW_MODE_INFRA ? IEEE80211_FCTL_TODS : 0)); ++ ++ if (priv->iw_mode == IW_MODE_ADHOC) { ++ memcpy(i802_11_hdr->addr1, eh->h_dest, ETH_ALEN); ++ memcpy(i802_11_hdr->addr2, eh->h_source, ETH_ALEN); ++ memcpy(i802_11_hdr->addr3, priv->bssid, ETH_ALEN); ++ } else if (priv->iw_mode == IW_MODE_INFRA) { ++ memcpy(i802_11_hdr->addr1, priv->bssid, ETH_ALEN); ++ memcpy(i802_11_hdr->addr2, eh->h_source, ETH_ALEN); ++ memcpy(i802_11_hdr->addr3, eh->h_dest, ETH_ALEN); ++ } ++ ++ i802_11_hdr->duration_id = cpu_to_le16(0); ++ i802_11_hdr->seq_ctl = cpu_to_le16(0); ++ ++ /* setup 'Atmel' header */ ++ tx_buffer->wlength = cpu_to_le16(wlen); ++ tx_buffer->tx_rate = priv->txrate; ++ /* for broadcast destination addresses, the firmware 0.100.x ++ seems to choose the highest rate set with CMD_STARTUP in ++ basic_rate_set replacing this value */ ++ ++ memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved)); ++ ++ tx_buffer->padding = at76_calc_padding(wlen); ++ submit_len = wlen + AT76_TX_HDRLEN + tx_buffer->padding; ++ ++ at76_dbg(DBG_TX_DATA_CONTENT, "%s skb->data %s", priv->netdev->name, ++ hex2str(skb->data, 32)); ++ at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr %s", ++ priv->netdev->name, ++ le16_to_cpu(tx_buffer->wlength), ++ tx_buffer->padding, tx_buffer->tx_rate, ++ hex2str(i802_11_hdr, sizeof(*i802_11_hdr))); ++ at76_dbg(DBG_TX_DATA_CONTENT, "%s payload %s", priv->netdev->name, ++ hex2str(payload, 48)); ++ ++ /* send stuff */ ++ netif_stop_queue(netdev); ++ netdev->trans_start = jiffies; ++ ++ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, tx_buffer, ++ submit_len, at76_tx_callback, priv); ++ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC); ++ if (ret) { ++ stats->tx_errors++; ++ printk(KERN_ERR "%s: error in tx submit urb: %d\n", ++ netdev->name, ret); ++ if (ret == -EINVAL) ++ printk(KERN_ERR ++ "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n", ++ priv->netdev->name, priv->tx_urb, ++ priv->tx_urb->hcpriv, priv->tx_urb->complete); ++ } else { ++ stats->tx_bytes += skb->len; ++ dev_kfree_skb(skb); ++ } ++ ++ return ret; ++} ++ ++static void at76_tx_timeout(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ if (!priv) ++ return; ++ dev_warn(&netdev->dev, "tx timeout."); ++ ++ usb_unlink_urb(priv->tx_urb); ++ priv->stats.tx_errors++; ++} ++ ++static int at76_submit_rx_urb(struct at76_priv *priv) ++{ ++ int ret; ++ int size; ++ struct sk_buff *skb = priv->rx_skb; ++ ++ if (!priv->rx_urb) { ++ printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n", ++ priv->netdev->name, __func__); ++ return -EFAULT; ++ } ++ ++ if (!skb) { ++ skb = dev_alloc_skb(sizeof(struct at76_rx_buffer)); ++ if (!skb) { ++ printk(KERN_ERR "%s: cannot allocate rx skbuff\n", ++ priv->netdev->name); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ priv->rx_skb = skb; ++ } else { ++ skb_push(skb, skb_headroom(skb)); ++ skb_trim(skb, 0); ++ } ++ ++ size = skb_tailroom(skb); ++ usb_fill_bulk_urb(priv->rx_urb, priv->udev, priv->rx_pipe, ++ skb_put(skb, size), size, at76_rx_callback, priv); ++ ret = usb_submit_urb(priv->rx_urb, GFP_ATOMIC); ++ if (ret < 0) { ++ if (ret == -ENODEV) ++ at76_dbg(DBG_DEVSTART, ++ "usb_submit_urb returned -ENODEV"); ++ else ++ printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n", ++ priv->netdev->name, ret); ++ } ++ ++exit: ++ if (ret < 0 && ret != -ENODEV) ++ printk(KERN_ERR "%s: cannot submit rx urb - please unload the " ++ "driver and/or power cycle the device\n", ++ priv->netdev->name); ++ ++ return ret; ++} ++ ++static int at76_open(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ int ret = 0; ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s(): entry", __func__); ++ ++ if (mutex_lock_interruptible(&priv->mtx)) ++ return -EINTR; ++ ++ /* if netdev->dev_addr != priv->mac_addr we must ++ set the mac address in the device ! */ ++ if (compare_ether_addr(netdev->dev_addr, priv->mac_addr)) { ++ if (at76_add_mac_address(priv, netdev->dev_addr) >= 0) ++ at76_dbg(DBG_PROGRESS, "%s: set new MAC addr %s", ++ netdev->name, mac2str(netdev->dev_addr)); ++ } ++ ++ priv->scan_state = SCAN_IDLE; ++ priv->last_scan = jiffies; ++ ++ ret = at76_submit_rx_urb(priv); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n", ++ netdev->name, ret); ++ goto error; ++ } ++ ++ schedule_delayed_work(&priv->dwork_restart, 0); ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s(): end", __func__); ++error: ++ mutex_unlock(&priv->mtx); ++ return ret < 0 ? ret : 0; ++} ++ ++static int at76_stop(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ at76_dbg(DBG_DEVSTART, "%s: ENTER", __func__); ++ ++ if (mutex_lock_interruptible(&priv->mtx)) ++ return -EINTR; ++ ++ at76_quiesce(priv); ++ ++ if (!priv->device_unplugged) { ++ /* We are called by "ifconfig ethX down", not because the ++ * device is not available anymore. */ ++ at76_set_radio(priv, 0); ++ ++ /* We unlink rx_urb because at76_open() re-submits it. ++ * If unplugged, at76_delete_device() takes care of it. */ ++ usb_kill_urb(priv->rx_urb); ++ } ++ ++ /* free the bss_list */ ++ at76_free_bss_list(priv); ++ ++ mutex_unlock(&priv->mtx); ++ at76_dbg(DBG_DEVSTART, "%s: EXIT", __func__); ++ ++ return 0; ++} ++ ++static void at76_ethtool_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *info) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ ++ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver)); ++ strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); ++ ++ usb_make_path(priv->udev, info->bus_info, sizeof(info->bus_info)); ++ ++ snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d.%d-%d", ++ priv->fw_version.major, priv->fw_version.minor, ++ priv->fw_version.patch, priv->fw_version.build); ++} ++ ++static u32 at76_ethtool_get_link(struct net_device *netdev) ++{ ++ struct at76_priv *priv = netdev_priv(netdev); ++ return priv->mac_state == MAC_CONNECTED; ++} ++ ++static struct ethtool_ops at76_ethtool_ops = { ++ .get_drvinfo = at76_ethtool_get_drvinfo, ++ .get_link = at76_ethtool_get_link, ++}; ++ ++/* Download external firmware */ ++static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe) ++{ ++ int ret; ++ int op_mode; ++ int blockno = 0; ++ int bsize; ++ u8 *block; ++ u8 *buf = fwe->extfw; ++ int size = fwe->extfw_size; ++ ++ if (!buf || !size) ++ return -ENOENT; ++ ++ op_mode = at76_get_op_mode(udev); ++ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode); ++ ++ if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { ++ dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n", ++ op_mode); ++ return -EINVAL; ++ } ++ ++ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL); ++ if (!block) ++ return -ENOMEM; ++ ++ at76_dbg(DBG_DEVSTART, "downloading external firmware"); ++ ++ /* for fw >= 0.100, the device needs an extra empty block */ ++ do { ++ bsize = min_t(int, size, FW_BLOCK_SIZE); ++ memcpy(block, buf, bsize); ++ at76_dbg(DBG_DEVSTART, ++ "ext fw, size left = %5d, bsize = %4d, blockno = %2d", ++ size, bsize, blockno); ++ ret = at76_load_ext_fw_block(udev, blockno, block, bsize); ++ if (ret != bsize) { ++ dev_printk(KERN_ERR, &udev->dev, ++ "loading %dth firmware block failed: %d\n", ++ blockno, ret); ++ goto exit; ++ } ++ buf += bsize; ++ size -= bsize; ++ blockno++; ++ } while (bsize > 0); ++ ++ if (at76_is_505a(fwe->board_type)) { ++ at76_dbg(DBG_DEVSTART, "200 ms delay for 505a"); ++ schedule_timeout_interruptible(HZ / 5 + 1); ++ } ++ ++exit: ++ kfree(block); ++ if (ret < 0) ++ dev_printk(KERN_ERR, &udev->dev, ++ "downloading external firmware failed: %d\n", ret); ++ return ret; ++} ++ ++/* Download internal firmware */ ++static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe) ++{ ++ int ret; ++ int need_remap = !at76_is_505a(fwe->board_type); ++ ++ ret = at76_usbdfu_download(udev, fwe->intfw, fwe->intfw_size, ++ need_remap ? 0 : 2 * HZ); ++ ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &udev->dev, ++ "downloading internal fw failed with %d\n", ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_DEVSTART, "sending REMAP"); ++ ++ /* no REMAP for 505A (see SF driver) */ ++ if (need_remap) { ++ ret = at76_remap(udev); ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &udev->dev, ++ "sending REMAP failed with %d\n", ret); ++ goto exit; ++ } ++ } ++ ++ at76_dbg(DBG_DEVSTART, "sleeping for 2 seconds"); ++ schedule_timeout_interruptible(2 * HZ + 1); ++ usb_reset_device(udev); ++ ++exit: ++ return ret; ++} ++ ++static int at76_match_essid(struct at76_priv *priv, struct bss_info *ptr) ++{ ++ /* common criteria for both modi */ ++ ++ int ret = (priv->essid_size == 0 /* ANY ssid */ || ++ (priv->essid_size == ptr->ssid_len && ++ !memcmp(priv->essid, ptr->ssid, ptr->ssid_len))); ++ if (!ret) ++ at76_dbg(DBG_BSS_MATCH, ++ "%s bss table entry %p: essid didn't match", ++ priv->netdev->name, ptr); ++ return ret; ++} ++ ++static inline int at76_match_mode(struct at76_priv *priv, struct bss_info *ptr) ++{ ++ int ret; ++ ++ if (priv->iw_mode == IW_MODE_ADHOC) ++ ret = ptr->capa & WLAN_CAPABILITY_IBSS; ++ else ++ ret = ptr->capa & WLAN_CAPABILITY_ESS; ++ if (!ret) ++ at76_dbg(DBG_BSS_MATCH, ++ "%s bss table entry %p: mode didn't match", ++ priv->netdev->name, ptr); ++ return ret; ++} ++ ++static int at76_match_rates(struct at76_priv *priv, struct bss_info *ptr) ++{ ++ int i; ++ ++ for (i = 0; i < ptr->rates_len; i++) { ++ u8 rate = ptr->rates[i]; ++ ++ if (!(rate & 0x80)) ++ continue; ++ ++ /* this is a basic rate we have to support ++ (see IEEE802.11, ch. 7.3.2.2) */ ++ if (rate != (0x80 | hw_rates[0]) ++ && rate != (0x80 | hw_rates[1]) ++ && rate != (0x80 | hw_rates[2]) ++ && rate != (0x80 | hw_rates[3])) { ++ at76_dbg(DBG_BSS_MATCH, ++ "%s: bss table entry %p: basic rate %02x not " ++ "supported", priv->netdev->name, ptr, rate); ++ return 0; ++ } ++ } ++ ++ /* if we use short preamble, the bss must support it */ ++ if (priv->preamble_type == PREAMBLE_TYPE_SHORT && ++ !(ptr->capa & WLAN_CAPABILITY_SHORT_PREAMBLE)) { ++ at76_dbg(DBG_BSS_MATCH, ++ "%s: %p does not support short preamble", ++ priv->netdev->name, ptr); ++ return 0; ++ } else ++ return 1; ++} ++ ++static inline int at76_match_wep(struct at76_priv *priv, struct bss_info *ptr) ++{ ++ if (!priv->wep_enabled && ptr->capa & WLAN_CAPABILITY_PRIVACY) { ++ /* we have disabled WEP, but the BSS signals privacy */ ++ at76_dbg(DBG_BSS_MATCH, ++ "%s: bss table entry %p: requires encryption", ++ priv->netdev->name, ptr); ++ return 0; ++ } ++ /* otherwise if the BSS does not signal privacy it may well ++ accept encrypted packets from us ... */ ++ return 1; ++} ++ ++static inline int at76_match_bssid(struct at76_priv *priv, struct bss_info *ptr) ++{ ++ if (!priv->wanted_bssid_valid || ++ !compare_ether_addr(ptr->bssid, priv->wanted_bssid)) ++ return 1; ++ ++ at76_dbg(DBG_BSS_MATCH, ++ "%s: requested bssid - %s does not match", ++ priv->netdev->name, mac2str(priv->wanted_bssid)); ++ at76_dbg(DBG_BSS_MATCH, ++ " AP bssid - %s of bss table entry %p", ++ mac2str(ptr->bssid), ptr); ++ return 0; ++} ++ ++/** ++ * at76_match_bss - try to find a matching bss in priv->bss ++ * ++ * last - last bss tried ++ * ++ * last == NULL signals a new round starting with priv->bss_list.next ++ * this function must be called inside an acquired priv->bss_list_spinlock ++ * otherwise the timeout on bss may remove the newly chosen entry ++ */ ++static struct bss_info *at76_match_bss(struct at76_priv *priv, ++ struct bss_info *last) ++{ ++ struct bss_info *ptr = NULL; ++ struct list_head *curr; ++ ++ curr = last ? last->list.next : priv->bss_list.next; ++ while (curr != &priv->bss_list) { ++ ptr = list_entry(curr, struct bss_info, list); ++ if (at76_match_essid(priv, ptr) && at76_match_mode(priv, ptr) ++ && at76_match_wep(priv, ptr) && at76_match_rates(priv, ptr) ++ && at76_match_bssid(priv, ptr)) ++ break; ++ curr = curr->next; ++ } ++ ++ if (curr == &priv->bss_list) ++ ptr = NULL; ++ /* otherwise ptr points to the struct bss_info we have chosen */ ++ ++ at76_dbg(DBG_BSS_TABLE, "%s %s: returned %p", priv->netdev->name, ++ __func__, ptr); ++ return ptr; ++} ++ ++/* Start joining a matching BSS, or create own IBSS */ ++static void at76_work_join(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ work_join); ++ int ret; ++ unsigned long flags; ++ ++ mutex_lock(&priv->mtx); ++ ++ WARN_ON(priv->mac_state != MAC_JOINING); ++ if (priv->mac_state != MAC_JOINING) ++ goto exit; ++ ++ /* secure the access to priv->curr_bss ! */ ++ spin_lock_irqsave(&priv->bss_list_spinlock, flags); ++ priv->curr_bss = at76_match_bss(priv, priv->curr_bss); ++ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags); ++ ++ if (!priv->curr_bss) { ++ /* here we haven't found a matching (i)bss ... */ ++ if (priv->iw_mode == IW_MODE_ADHOC) { ++ at76_set_mac_state(priv, MAC_OWN_IBSS); ++ at76_start_ibss(priv); ++ goto exit; ++ } ++ /* haven't found a matching BSS in infra mode - try again */ ++ at76_set_mac_state(priv, MAC_SCANNING); ++ schedule_work(&priv->work_start_scan); ++ goto exit; ++ } ++ ++ ret = at76_join_bss(priv, priv->curr_bss); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: join_bss failed with %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ ret = at76_wait_completion(priv, CMD_JOIN); ++ if (ret != CMD_STATUS_COMPLETE) { ++ if (ret != CMD_STATUS_TIME_OUT) ++ printk(KERN_ERR "%s: join_bss completed with %d\n", ++ priv->netdev->name, ret); ++ else ++ printk(KERN_INFO "%s: join_bss ssid %s timed out\n", ++ priv->netdev->name, ++ mac2str(priv->curr_bss->bssid)); ++ ++ /* retry next BSS immediately */ ++ schedule_work(&priv->work_join); ++ goto exit; ++ } ++ ++ /* here we have joined the (I)BSS */ ++ if (priv->iw_mode == IW_MODE_ADHOC) { ++ struct bss_info *bptr = priv->curr_bss; ++ at76_set_mac_state(priv, MAC_CONNECTED); ++ /* get ESSID, BSSID and channel for priv->curr_bss */ ++ priv->essid_size = bptr->ssid_len; ++ memcpy(priv->essid, bptr->ssid, bptr->ssid_len); ++ memcpy(priv->bssid, bptr->bssid, ETH_ALEN); ++ priv->channel = bptr->channel; ++ at76_iwevent_bss_connect(priv->netdev, bptr->bssid); ++ netif_carrier_on(priv->netdev); ++ netif_start_queue(priv->netdev); ++ /* just to be sure */ ++ cancel_delayed_work(&priv->dwork_get_scan); ++ cancel_delayed_work(&priv->dwork_auth); ++ cancel_delayed_work(&priv->dwork_assoc); ++ } else { ++ /* send auth req */ ++ priv->retries = AUTH_RETRIES; ++ at76_set_mac_state(priv, MAC_AUTH); ++ at76_auth_req(priv, priv->curr_bss, 1, NULL); ++ at76_dbg(DBG_MGMT_TIMER, ++ "%s:%d: starting mgmt_timer + HZ", __func__, __LINE__); ++ schedule_delayed_work(&priv->dwork_auth, AUTH_TIMEOUT); ++ } ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Reap scan results */ ++static void at76_dwork_get_scan(struct work_struct *work) ++{ ++ int status; ++ int ret; ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ dwork_get_scan.work); ++ ++ mutex_lock(&priv->mtx); ++ WARN_ON(priv->mac_state != MAC_SCANNING); ++ if (priv->mac_state != MAC_SCANNING) ++ goto exit; ++ ++ status = at76_get_cmd_status(priv->udev, CMD_SCAN); ++ if (status < 0) { ++ printk(KERN_ERR "%s: %s: at76_get_cmd_status failed with %d\n", ++ priv->netdev->name, __func__, status); ++ status = CMD_STATUS_IN_PROGRESS; ++ /* INFO: Hope it was a one off error - if not, scanning ++ further down the line and stop this cycle */ ++ } ++ at76_dbg(DBG_PROGRESS, ++ "%s %s: got cmd_status %d (state %s, need_any %d)", ++ priv->netdev->name, __func__, status, ++ mac_states[priv->mac_state], priv->scan_need_any); ++ ++ if (status != CMD_STATUS_COMPLETE) { ++ if ((status != CMD_STATUS_IN_PROGRESS) && ++ (status != CMD_STATUS_IDLE)) ++ printk(KERN_ERR "%s: %s: Bad scan status: %s\n", ++ priv->netdev->name, __func__, ++ at76_get_cmd_status_string(status)); ++ ++ /* the first cmd status after scan start is always a IDLE -> ++ start the timer to poll again until COMPLETED */ ++ at76_dbg(DBG_MGMT_TIMER, ++ "%s:%d: starting mgmt_timer for %d ticks", ++ __func__, __LINE__, SCAN_POLL_INTERVAL); ++ schedule_delayed_work(&priv->dwork_get_scan, ++ SCAN_POLL_INTERVAL); ++ goto exit; ++ } ++ ++ if (at76_debug & DBG_BSS_TABLE) ++ at76_dump_bss_table(priv); ++ ++ if (priv->scan_need_any) { ++ ret = at76_start_scan(priv, 0); ++ if (ret < 0) ++ printk(KERN_ERR ++ "%s: %s: start_scan (ANY) failed with %d\n", ++ priv->netdev->name, __func__, ret); ++ at76_dbg(DBG_MGMT_TIMER, ++ "%s:%d: starting mgmt_timer for %d ticks", __func__, ++ __LINE__, SCAN_POLL_INTERVAL); ++ schedule_delayed_work(&priv->dwork_get_scan, ++ SCAN_POLL_INTERVAL); ++ priv->scan_need_any = 0; ++ } else { ++ priv->scan_state = SCAN_COMPLETED; ++ /* report the end of scan to user space */ ++ at76_iwevent_scan_complete(priv->netdev); ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++ } ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Handle loss of beacons from the AP */ ++static void at76_dwork_beacon(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ dwork_beacon.work); ++ ++ mutex_lock(&priv->mtx); ++ if (priv->mac_state != MAC_CONNECTED || priv->iw_mode != IW_MODE_INFRA) ++ goto exit; ++ ++ /* We haven't received any beacons from out AP for BEACON_TIMEOUT */ ++ printk(KERN_INFO "%s: lost beacon bssid %s\n", ++ priv->netdev->name, mac2str(priv->curr_bss->bssid)); ++ ++ netif_carrier_off(priv->netdev); ++ netif_stop_queue(priv->netdev); ++ at76_iwevent_bss_disconnect(priv->netdev); ++ at76_set_mac_state(priv, MAC_SCANNING); ++ schedule_work(&priv->work_start_scan); ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Handle authentication response timeout */ ++static void at76_dwork_auth(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ dwork_auth.work); ++ ++ mutex_lock(&priv->mtx); ++ WARN_ON(priv->mac_state != MAC_AUTH); ++ if (priv->mac_state != MAC_AUTH) ++ goto exit; ++ ++ at76_dbg(DBG_PROGRESS, "%s: authentication response timeout", ++ priv->netdev->name); ++ ++ if (priv->retries-- >= 0) { ++ at76_auth_req(priv, priv->curr_bss, 1, NULL); ++ at76_dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", ++ __func__, __LINE__); ++ schedule_delayed_work(&priv->dwork_auth, AUTH_TIMEOUT); ++ } else { ++ /* try to get next matching BSS */ ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++ } ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Handle association response timeout */ ++static void at76_dwork_assoc(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ dwork_assoc.work); ++ ++ mutex_lock(&priv->mtx); ++ WARN_ON(priv->mac_state != MAC_ASSOC); ++ if (priv->mac_state != MAC_ASSOC) ++ goto exit; ++ ++ at76_dbg(DBG_PROGRESS, "%s: association response timeout", ++ priv->netdev->name); ++ ++ if (priv->retries-- >= 0) { ++ at76_assoc_req(priv, priv->curr_bss); ++ at76_dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", ++ __func__, __LINE__); ++ schedule_delayed_work(&priv->dwork_assoc, ASSOC_TIMEOUT); ++ } else { ++ /* try to get next matching BSS */ ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++ } ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Read new bssid in ad-hoc mode */ ++static void at76_work_new_bss(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ work_new_bss); ++ int ret; ++ struct mib_mac_mgmt mac_mgmt; ++ ++ mutex_lock(&priv->mtx); ++ ++ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, &mac_mgmt, ++ sizeof(struct mib_mac_mgmt)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_get_mib failed: %d\n", ++ priv->netdev->name, ret); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_PROGRESS, "ibss_change = 0x%2x", mac_mgmt.ibss_change); ++ memcpy(priv->bssid, mac_mgmt.current_bssid, ETH_ALEN); ++ at76_dbg(DBG_PROGRESS, "using BSSID %s", mac2str(priv->bssid)); ++ ++ at76_iwevent_bss_connect(priv->netdev, priv->bssid); ++ ++ priv->mib_buf.type = MIB_MAC_MGMT; ++ priv->mib_buf.size = 1; ++ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, ibss_change); ++ priv->mib_buf.data.byte = 0; ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (ibss change ok) failed: %d\n", ++ priv->netdev->name, ret); ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++static int at76_startup_device(struct at76_priv *priv) ++{ ++ struct at76_card_config *ccfg = &priv->card_config; ++ int ret; ++ ++ at76_dbg(DBG_PARAMS, ++ "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d " ++ "keylen %d", priv->netdev->name, priv->essid_size, priv->essid, ++ hex2str(priv->essid, IW_ESSID_MAX_SIZE), ++ priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra", ++ priv->channel, priv->wep_enabled ? "enabled" : "disabled", ++ priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]); ++ at76_dbg(DBG_PARAMS, ++ "%s param: preamble %s rts %d retry %d frag %d " ++ "txrate %s auth_mode %d", priv->netdev->name, ++ preambles[priv->preamble_type], priv->rts_threshold, ++ priv->short_retry_limit, priv->frag_threshold, ++ priv->txrate == TX_RATE_1MBIT ? "1MBit" : priv->txrate == ++ TX_RATE_2MBIT ? "2MBit" : priv->txrate == ++ TX_RATE_5_5MBIT ? "5.5MBit" : priv->txrate == ++ TX_RATE_11MBIT ? "11MBit" : priv->txrate == ++ TX_RATE_AUTO ? "auto" : "", priv->auth_mode); ++ at76_dbg(DBG_PARAMS, ++ "%s param: pm_mode %d pm_period %d auth_mode %s " ++ "scan_times %d %d scan_mode %s", ++ priv->netdev->name, priv->pm_mode, priv->pm_period, ++ priv->auth_mode == WLAN_AUTH_OPEN ? "open" : "shared_secret", ++ priv->scan_min_time, priv->scan_max_time, ++ priv->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive"); ++ ++ memset(ccfg, 0, sizeof(struct at76_card_config)); ++ ccfg->promiscuous_mode = 0; ++ ccfg->short_retry_limit = priv->short_retry_limit; ++ ++ if (priv->wep_enabled) { ++ if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN) ++ ccfg->encryption_type = 2; ++ else ++ ccfg->encryption_type = 1; ++ ++ /* jal: always exclude unencrypted if WEP is active */ ++ ccfg->exclude_unencrypted = 1; ++ } else { ++ ccfg->exclude_unencrypted = 0; ++ ccfg->encryption_type = 0; ++ } ++ ++ ccfg->rts_threshold = cpu_to_le16(priv->rts_threshold); ++ ccfg->fragmentation_threshold = cpu_to_le16(priv->frag_threshold); ++ ++ memcpy(ccfg->basic_rate_set, hw_rates, 4); ++ /* jal: really needed, we do a set_mib for autorate later ??? */ ++ ccfg->auto_rate_fallback = (priv->txrate == TX_RATE_AUTO ? 1 : 0); ++ ccfg->channel = priv->channel; ++ ccfg->privacy_invoked = priv->wep_enabled; ++ memcpy(ccfg->current_ssid, priv->essid, IW_ESSID_MAX_SIZE); ++ ccfg->ssid_len = priv->essid_size; ++ ++ ccfg->wep_default_key_id = priv->wep_key_id; ++ memcpy(ccfg->wep_default_key_value, priv->wep_keys, 4 * WEP_KEY_LEN); ++ ++ ccfg->short_preamble = priv->preamble_type; ++ ccfg->beacon_period = cpu_to_le16(priv->beacon_period); ++ ++ ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config, ++ sizeof(struct at76_card_config)); ++ if (ret < 0) { ++ printk(KERN_ERR "%s: at76_set_card_command failed: %d\n", ++ priv->netdev->name, ret); ++ return ret; ++ } ++ ++ at76_wait_completion(priv, CMD_STARTUP); ++ ++ /* remove BSSID from previous run */ ++ memset(priv->bssid, 0, ETH_ALEN); ++ ++ if (at76_set_radio(priv, 1) == 1) ++ at76_wait_completion(priv, CMD_RADIO_ON); ++ ++ ret = at76_set_preamble(priv, priv->preamble_type); ++ if (ret < 0) ++ return ret; ++ ++ ret = at76_set_frag(priv, priv->frag_threshold); ++ if (ret < 0) ++ return ret; ++ ++ ret = at76_set_rts(priv, priv->rts_threshold); ++ if (ret < 0) ++ return ret; ++ ++ ret = at76_set_autorate_fallback(priv, ++ priv->txrate == TX_RATE_AUTO ? 1 : 0); ++ if (ret < 0) ++ return ret; ++ ++ ret = at76_set_pm_mode(priv); ++ if (ret < 0) ++ return ret; ++ ++ if (at76_debug & DBG_MIB) { ++ at76_dump_mib_mac(priv); ++ at76_dump_mib_mac_addr(priv); ++ at76_dump_mib_mac_mgmt(priv); ++ at76_dump_mib_mac_wep(priv); ++ at76_dump_mib_mdomain(priv); ++ at76_dump_mib_phy(priv); ++ at76_dump_mib_local(priv); ++ } ++ ++ return 0; ++} ++ ++/* Restart the interface */ ++static void at76_dwork_restart(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ dwork_restart.work); ++ ++ mutex_lock(&priv->mtx); ++ ++ netif_carrier_off(priv->netdev); /* stop netdev watchdog */ ++ netif_stop_queue(priv->netdev); /* stop tx data packets */ ++ ++ at76_startup_device(priv); ++ ++ if (priv->iw_mode != IW_MODE_MONITOR) { ++ priv->netdev->type = ARPHRD_ETHER; ++ at76_set_mac_state(priv, MAC_SCANNING); ++ schedule_work(&priv->work_start_scan); ++ } else { ++ priv->netdev->type = ARPHRD_IEEE80211_RADIOTAP; ++ at76_start_monitor(priv); ++ } ++ ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Initiate scanning */ ++static void at76_work_start_scan(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ work_start_scan); ++ int ret; ++ ++ mutex_lock(&priv->mtx); ++ ++ WARN_ON(priv->mac_state != MAC_SCANNING); ++ if (priv->mac_state != MAC_SCANNING) ++ goto exit; ++ ++ /* only clear the bss list when a scan is actively initiated, ++ * otherwise simply rely on at76_bss_list_timeout */ ++ if (priv->scan_state == SCAN_IN_PROGRESS) { ++ at76_free_bss_list(priv); ++ priv->scan_need_any = 1; ++ } else ++ priv->scan_need_any = 0; ++ ++ ret = at76_start_scan(priv, 1); ++ ++ if (ret < 0) ++ printk(KERN_ERR "%s: %s: start_scan failed with %d\n", ++ priv->netdev->name, __func__, ret); ++ else { ++ at76_dbg(DBG_MGMT_TIMER, ++ "%s:%d: starting mgmt_timer for %d ticks", ++ __func__, __LINE__, SCAN_POLL_INTERVAL); ++ schedule_delayed_work(&priv->dwork_get_scan, ++ SCAN_POLL_INTERVAL); ++ } ++ ++exit: ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Enable or disable promiscuous mode */ ++static void at76_work_set_promisc(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ work_set_promisc); ++ int ret = 0; ++ ++ mutex_lock(&priv->mtx); ++ ++ priv->mib_buf.type = MIB_LOCAL; ++ priv->mib_buf.size = 1; ++ priv->mib_buf.index = offsetof(struct mib_local, promiscuous_mode); ++ priv->mib_buf.data.byte = priv->promisc ? 1 : 0; ++ ++ ret = at76_set_mib(priv, &priv->mib_buf); ++ if (ret < 0) ++ printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n", ++ priv->netdev->name, ret); ++ ++ mutex_unlock(&priv->mtx); ++} ++ ++/* Submit Rx urb back to the device */ ++static void at76_work_submit_rx(struct work_struct *work) ++{ ++ struct at76_priv *priv = container_of(work, struct at76_priv, ++ work_submit_rx); ++ ++ mutex_lock(&priv->mtx); ++ at76_submit_rx_urb(priv); ++ mutex_unlock(&priv->mtx); ++} ++ ++/* We got an association response */ ++static void at76_rx_mgmt_assoc(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ struct ieee80211_assoc_response *resp = ++ (struct ieee80211_assoc_response *)buf->packet; ++ u16 assoc_id = le16_to_cpu(resp->aid); ++ u16 status = le16_to_cpu(resp->status); ++ ++ at76_dbg(DBG_RX_MGMT, "%s: rx AssocResp bssid %s capa 0x%04x status " ++ "0x%04x assoc_id 0x%04x rates %s", priv->netdev->name, ++ mac2str(resp->header.addr3), le16_to_cpu(resp->capability), ++ status, assoc_id, hex2str(resp->info_element->data, ++ resp->info_element->len)); ++ ++ if (priv->mac_state != MAC_ASSOC) { ++ printk(KERN_INFO "%s: AssocResp in state %s ignored\n", ++ priv->netdev->name, mac_states[priv->mac_state]); ++ return; ++ } ++ ++ BUG_ON(!priv->curr_bss); ++ ++ cancel_delayed_work(&priv->dwork_assoc); ++ if (status == WLAN_STATUS_SUCCESS) { ++ struct bss_info *ptr = priv->curr_bss; ++ priv->assoc_id = assoc_id & 0x3fff; ++ /* update iwconfig params */ ++ memcpy(priv->bssid, ptr->bssid, ETH_ALEN); ++ memcpy(priv->essid, ptr->ssid, ptr->ssid_len); ++ priv->essid_size = ptr->ssid_len; ++ priv->channel = ptr->channel; ++ schedule_work(&priv->work_assoc_done); ++ } else { ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++ } ++} ++ ++/* Process disassociation request from the AP */ ++static void at76_rx_mgmt_disassoc(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ struct ieee80211_disassoc *resp = ++ (struct ieee80211_disassoc *)buf->packet; ++ struct ieee80211_hdr_3addr *mgmt = &resp->header; ++ ++ at76_dbg(DBG_RX_MGMT, ++ "%s: rx DisAssoc bssid %s reason 0x%04x destination %s", ++ priv->netdev->name, mac2str(mgmt->addr3), ++ le16_to_cpu(resp->reason), mac2str(mgmt->addr1)); ++ ++ /* We are not connected, ignore */ ++ if (priv->mac_state == MAC_SCANNING || priv->mac_state == MAC_INIT ++ || !priv->curr_bss) ++ return; ++ ++ /* Not our BSSID, ignore */ ++ if (compare_ether_addr(mgmt->addr3, priv->curr_bss->bssid)) ++ return; ++ ++ /* Not for our STA and not broadcast, ignore */ ++ if (compare_ether_addr(priv->netdev->dev_addr, mgmt->addr1) ++ && !is_broadcast_ether_addr(mgmt->addr1)) ++ return; ++ ++ if (priv->mac_state != MAC_ASSOC && priv->mac_state != MAC_CONNECTED ++ && priv->mac_state != MAC_JOINING) { ++ printk(KERN_INFO "%s: DisAssoc in state %s ignored\n", ++ priv->netdev->name, mac_states[priv->mac_state]); ++ return; ++ } ++ ++ if (priv->mac_state == MAC_CONNECTED) { ++ netif_carrier_off(priv->netdev); ++ netif_stop_queue(priv->netdev); ++ at76_iwevent_bss_disconnect(priv->netdev); ++ } ++ cancel_delayed_work(&priv->dwork_get_scan); ++ cancel_delayed_work(&priv->dwork_beacon); ++ cancel_delayed_work(&priv->dwork_auth); ++ cancel_delayed_work(&priv->dwork_assoc); ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++} ++ ++static void at76_rx_mgmt_auth(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ struct ieee80211_auth *resp = (struct ieee80211_auth *)buf->packet; ++ struct ieee80211_hdr_3addr *mgmt = &resp->header; ++ int seq_nr = le16_to_cpu(resp->transaction); ++ int alg = le16_to_cpu(resp->algorithm); ++ int status = le16_to_cpu(resp->status); ++ ++ at76_dbg(DBG_RX_MGMT, ++ "%s: rx AuthFrame bssid %s alg %d seq_nr %d status %d " ++ "destination %s", priv->netdev->name, mac2str(mgmt->addr3), ++ alg, seq_nr, status, mac2str(mgmt->addr1)); ++ ++ if (alg == WLAN_AUTH_SHARED_KEY && seq_nr == 2) ++ at76_dbg(DBG_RX_MGMT, "%s: AuthFrame challenge %s ...", ++ priv->netdev->name, hex2str(resp->info_element, 18)); ++ ++ if (priv->mac_state != MAC_AUTH) { ++ printk(KERN_INFO "%s: ignored AuthFrame in state %s\n", ++ priv->netdev->name, mac_states[priv->mac_state]); ++ return; ++ } ++ if (priv->auth_mode != alg) { ++ printk(KERN_INFO "%s: ignored AuthFrame for alg %d\n", ++ priv->netdev->name, alg); ++ return; ++ } ++ ++ BUG_ON(!priv->curr_bss); ++ ++ /* Not our BSSID or not for our STA, ignore */ ++ if (compare_ether_addr(mgmt->addr3, priv->curr_bss->bssid) ++ || compare_ether_addr(priv->netdev->dev_addr, mgmt->addr1)) ++ return; ++ ++ cancel_delayed_work(&priv->dwork_auth); ++ if (status != WLAN_STATUS_SUCCESS) { ++ /* try to join next bss */ ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++ return; ++ } ++ ++ if (priv->auth_mode == WLAN_AUTH_OPEN || seq_nr == 4) { ++ priv->retries = ASSOC_RETRIES; ++ at76_set_mac_state(priv, MAC_ASSOC); ++ at76_assoc_req(priv, priv->curr_bss); ++ at76_dbg(DBG_MGMT_TIMER, ++ "%s:%d: starting mgmt_timer + HZ", __func__, __LINE__); ++ schedule_delayed_work(&priv->dwork_assoc, ASSOC_TIMEOUT); ++ return; ++ } ++ ++ WARN_ON(seq_nr != 2); ++ at76_auth_req(priv, priv->curr_bss, seq_nr + 1, resp->info_element); ++ at76_dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", __func__, ++ __LINE__); ++ schedule_delayed_work(&priv->dwork_auth, AUTH_TIMEOUT); ++} ++ ++static void at76_rx_mgmt_deauth(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ struct ieee80211_disassoc *resp = ++ (struct ieee80211_disassoc *)buf->packet; ++ struct ieee80211_hdr_3addr *mgmt = &resp->header; ++ ++ at76_dbg(DBG_RX_MGMT | DBG_PROGRESS, ++ "%s: rx DeAuth bssid %s reason 0x%04x destination %s", ++ priv->netdev->name, mac2str(mgmt->addr3), ++ le16_to_cpu(resp->reason), mac2str(mgmt->addr1)); ++ ++ if (priv->mac_state != MAC_AUTH && priv->mac_state != MAC_ASSOC ++ && priv->mac_state != MAC_CONNECTED) { ++ printk(KERN_INFO "%s: DeAuth in state %s ignored\n", ++ priv->netdev->name, mac_states[priv->mac_state]); ++ return; ++ } ++ ++ BUG_ON(!priv->curr_bss); ++ ++ /* Not our BSSID, ignore */ ++ if (compare_ether_addr(mgmt->addr3, priv->curr_bss->bssid)) ++ return; ++ ++ /* Not for our STA and not broadcast, ignore */ ++ if (compare_ether_addr(priv->netdev->dev_addr, mgmt->addr1) ++ && !is_broadcast_ether_addr(mgmt->addr1)) ++ return; ++ ++ if (priv->mac_state == MAC_CONNECTED) ++ at76_iwevent_bss_disconnect(priv->netdev); ++ ++ at76_set_mac_state(priv, MAC_JOINING); ++ schedule_work(&priv->work_join); ++ cancel_delayed_work(&priv->dwork_get_scan); ++ cancel_delayed_work(&priv->dwork_beacon); ++ cancel_delayed_work(&priv->dwork_auth); ++ cancel_delayed_work(&priv->dwork_assoc); ++} ++ ++static void at76_rx_mgmt_beacon(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ int varpar_len; ++ /* beacon content */ ++ struct ieee80211_beacon *bdata = (struct ieee80211_beacon *)buf->packet; ++ struct ieee80211_hdr_3addr *mgmt = &bdata->header; ++ ++ struct list_head *lptr; ++ struct bss_info *match; /* entry matching addr3 with its bssid */ ++ int new_entry = 0; ++ int len; ++ struct ieee80211_info_element *ie; ++ int have_ssid = 0; ++ int have_rates = 0; ++ int have_channel = 0; ++ int keep_going = 1; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->bss_list_spinlock, flags); ++ if (priv->mac_state == MAC_CONNECTED) { ++ /* in state MAC_CONNECTED we use the mgmt_timer to control ++ the beacon of the BSS */ ++ BUG_ON(!priv->curr_bss); ++ ++ if (!compare_ether_addr(priv->curr_bss->bssid, mgmt->addr3)) { ++ /* We got our AP's beacon, defer the timeout handler. ++ Kill pending work first, as schedule_delayed_work() ++ won't do it. */ ++ cancel_delayed_work(&priv->dwork_beacon); ++ schedule_delayed_work(&priv->dwork_beacon, ++ BEACON_TIMEOUT); ++ priv->curr_bss->rssi = buf->rssi; ++ priv->beacons_received++; ++ goto exit; ++ } ++ } ++ ++ /* look if we have this BSS already in the list */ ++ match = NULL; ++ ++ if (!list_empty(&priv->bss_list)) { ++ list_for_each(lptr, &priv->bss_list) { ++ struct bss_info *bss_ptr = ++ list_entry(lptr, struct bss_info, list); ++ if (!compare_ether_addr(bss_ptr->bssid, mgmt->addr3)) { ++ match = bss_ptr; ++ break; ++ } ++ } ++ } ++ ++ if (!match) { ++ /* BSS not in the list - append it */ ++ match = kzalloc(sizeof(struct bss_info), GFP_ATOMIC); ++ if (!match) { ++ at76_dbg(DBG_BSS_TABLE, ++ "%s: cannot kmalloc new bss info (%zd byte)", ++ priv->netdev->name, sizeof(struct bss_info)); ++ goto exit; ++ } ++ new_entry = 1; ++ list_add_tail(&match->list, &priv->bss_list); ++ } ++ ++ match->capa = le16_to_cpu(bdata->capability); ++ match->beacon_interval = le16_to_cpu(bdata->beacon_interval); ++ match->rssi = buf->rssi; ++ match->link_qual = buf->link_quality; ++ match->noise_level = buf->noise_level; ++ memcpy(match->bssid, mgmt->addr3, ETH_ALEN); ++ at76_dbg(DBG_RX_BEACON, "%s: bssid %s", priv->netdev->name, ++ mac2str(match->bssid)); ++ ++ ie = bdata->info_element; ++ ++ /* length of var length beacon parameters */ ++ varpar_len = min_t(int, le16_to_cpu(buf->wlength) - ++ sizeof(struct ieee80211_beacon), ++ BEACON_MAX_DATA_LENGTH); ++ ++ /* This routine steps through the bdata->data array to get ++ * some useful information about the access point. ++ * Currently, this implementation supports receipt of: SSID, ++ * supported transfer rates and channel, in any order, with some ++ * tolerance for intermittent unknown codes (although this ++ * functionality may not be necessary as the useful information will ++ * usually arrive in consecutively, but there have been some ++ * reports of some of the useful information fields arriving in a ++ * different order). ++ * It does not support any more IE types although MFIE_TYPE_TIM may ++ * be supported (on my AP at least). ++ * The bdata->data array is about 1500 bytes long but only ~36 of those ++ * bytes are useful, hence the have_ssid etc optimizations. */ ++ ++ while (keep_going && ++ ((&ie->data[ie->len] - (u8 *)bdata->info_element) <= ++ varpar_len)) { ++ ++ switch (ie->id) { ++ ++ case MFIE_TYPE_SSID: ++ if (have_ssid) ++ break; ++ ++ len = min_t(int, IW_ESSID_MAX_SIZE, ie->len); ++ ++ /* we copy only if this is a new entry, ++ or the incoming SSID is not a hidden SSID. This ++ will protect us from overwriting a real SSID read ++ in a ProbeResponse with a hidden one from a ++ following beacon. */ ++ if (!new_entry && at76_is_hidden_ssid(ie->data, len)) { ++ have_ssid = 1; ++ break; ++ } ++ ++ match->ssid_len = len; ++ memcpy(match->ssid, ie->data, len); ++ at76_dbg(DBG_RX_BEACON, "%s: SSID - %.*s", ++ priv->netdev->name, len, match->ssid); ++ have_ssid = 1; ++ break; ++ ++ case MFIE_TYPE_RATES: ++ if (have_rates) ++ break; ++ ++ match->rates_len = ++ min_t(int, sizeof(match->rates), ie->len); ++ memcpy(match->rates, ie->data, match->rates_len); ++ have_rates = 1; ++ at76_dbg(DBG_RX_BEACON, "%s: SUPPORTED RATES %s", ++ priv->netdev->name, ++ hex2str(ie->data, ie->len)); ++ break; ++ ++ case MFIE_TYPE_DS_SET: ++ if (have_channel) ++ break; ++ ++ match->channel = ie->data[0]; ++ have_channel = 1; ++ at76_dbg(DBG_RX_BEACON, "%s: CHANNEL - %d", ++ priv->netdev->name, match->channel); ++ break; ++ ++ case MFIE_TYPE_CF_SET: ++ case MFIE_TYPE_TIM: ++ case MFIE_TYPE_IBSS_SET: ++ default: ++ at76_dbg(DBG_RX_BEACON, "%s: beacon IE id %d len %d %s", ++ priv->netdev->name, ie->id, ie->len, ++ hex2str(ie->data, ie->len)); ++ break; ++ } ++ ++ /* advance to the next informational element */ ++ next_ie(&ie); ++ ++ /* Optimization: after all, the bdata->data array is ++ * varpar_len bytes long, whereas we get all of the useful ++ * information after only ~36 bytes, this saves us a lot of ++ * time (and trouble as the remaining portion of the array ++ * could be full of junk) ++ * Comment this out if you want to see what other information ++ * comes from the AP - although little of it may be useful */ ++ } ++ ++ at76_dbg(DBG_RX_BEACON, "%s: Finished processing beacon data", ++ priv->netdev->name); ++ ++ match->last_rx = jiffies; /* record last rx of beacon */ ++ ++exit: ++ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags); ++} ++ ++/* Calculate the link level from a given rx_buffer */ ++static void at76_calc_level(struct at76_priv *priv, struct at76_rx_buffer *buf, ++ struct iw_quality *qual) ++{ ++ /* just a guess for now, might be different for other chips */ ++ int max_rssi = 42; ++ ++ qual->level = (buf->rssi * 100 / max_rssi); ++ if (qual->level > 100) ++ qual->level = 100; ++ qual->updated |= IW_QUAL_LEVEL_UPDATED; ++} ++ ++/* Calculate the link quality from a given rx_buffer */ ++static void at76_calc_qual(struct at76_priv *priv, struct at76_rx_buffer *buf, ++ struct iw_quality *qual) ++{ ++ if (at76_is_intersil(priv->board_type)) ++ qual->qual = buf->link_quality; ++ else { ++ unsigned long elapsed; ++ ++ /* Update qual at most once a second */ ++ elapsed = jiffies - priv->beacons_last_qual; ++ if (elapsed < 1 * HZ) ++ return; ++ ++ qual->qual = qual->level * priv->beacons_received * ++ msecs_to_jiffies(priv->beacon_period) / elapsed; ++ ++ priv->beacons_last_qual = jiffies; ++ priv->beacons_received = 0; ++ } ++ qual->qual = (qual->qual > 100) ? 100 : qual->qual; ++ qual->updated |= IW_QUAL_QUAL_UPDATED; ++} ++ ++/* Calculate the noise quality from a given rx_buffer */ ++static void at76_calc_noise(struct at76_priv *priv, struct at76_rx_buffer *buf, ++ struct iw_quality *qual) ++{ ++ qual->noise = 0; ++ qual->updated |= IW_QUAL_NOISE_INVALID; ++} ++ ++static void at76_update_wstats(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ struct iw_quality *qual = &priv->wstats.qual; ++ ++ if (buf->rssi && priv->mac_state == MAC_CONNECTED) { ++ qual->updated = 0; ++ at76_calc_level(priv, buf, qual); ++ at76_calc_qual(priv, buf, qual); ++ at76_calc_noise(priv, buf, qual); ++ } else { ++ qual->qual = 0; ++ qual->level = 0; ++ qual->noise = 0; ++ qual->updated = IW_QUAL_ALL_INVALID; ++ } ++} ++ ++static void at76_rx_mgmt(struct at76_priv *priv, struct at76_rx_buffer *buf) ++{ ++ struct ieee80211_hdr_3addr *mgmt = ++ (struct ieee80211_hdr_3addr *)buf->packet; ++ u16 framectl = le16_to_cpu(mgmt->frame_ctl); ++ ++ /* update wstats */ ++ if (priv->mac_state != MAC_INIT && priv->mac_state != MAC_SCANNING) { ++ /* jal: this is a dirty hack needed by Tim in ad-hoc mode */ ++ /* Data packets always seem to have a 0 link level, so we ++ only read link quality info from management packets. ++ Atmel driver actually averages the present, and previous ++ values, we just present the raw value at the moment - TJS */ ++ if (priv->iw_mode == IW_MODE_ADHOC ++ || (priv->curr_bss ++ && !compare_ether_addr(mgmt->addr3, ++ priv->curr_bss->bssid))) ++ at76_update_wstats(priv, buf); ++ } ++ ++ at76_dbg(DBG_RX_MGMT_CONTENT, "%s rx mgmt framectl 0x%x %s", ++ priv->netdev->name, framectl, ++ hex2str(mgmt, le16_to_cpu(buf->wlength))); ++ ++ switch (framectl & IEEE80211_FCTL_STYPE) { ++ case IEEE80211_STYPE_BEACON: ++ case IEEE80211_STYPE_PROBE_RESP: ++ at76_rx_mgmt_beacon(priv, buf); ++ break; ++ ++ case IEEE80211_STYPE_ASSOC_RESP: ++ at76_rx_mgmt_assoc(priv, buf); ++ break; ++ ++ case IEEE80211_STYPE_DISASSOC: ++ at76_rx_mgmt_disassoc(priv, buf); ++ break; ++ ++ case IEEE80211_STYPE_AUTH: ++ at76_rx_mgmt_auth(priv, buf); ++ break; ++ ++ case IEEE80211_STYPE_DEAUTH: ++ at76_rx_mgmt_deauth(priv, buf); ++ break; ++ ++ default: ++ printk(KERN_DEBUG "%s: ignoring frame with framectl 0x%04x\n", ++ priv->netdev->name, framectl); ++ } ++ ++ return; ++} ++ ++/* Convert the 802.11 header into an ethernet-style header, make skb ++ * ready for consumption by netif_rx() */ ++static void at76_ieee80211_to_eth(struct sk_buff *skb, int iw_mode) ++{ ++ struct ieee80211_hdr_3addr *i802_11_hdr; ++ struct ethhdr *eth_hdr_p; ++ u8 *src_addr; ++ u8 *dest_addr; ++ ++ i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data; ++ ++ /* That would be the ethernet header if the hardware converted ++ * the frame for us. Make sure the source and the destination ++ * match the 802.11 header. Which hardware does it? */ ++ eth_hdr_p = (struct ethhdr *)skb_pull(skb, IEEE80211_3ADDR_LEN); ++ ++ dest_addr = i802_11_hdr->addr1; ++ if (iw_mode == IW_MODE_ADHOC) ++ src_addr = i802_11_hdr->addr2; ++ else ++ src_addr = i802_11_hdr->addr3; ++ ++ if (!compare_ether_addr(eth_hdr_p->h_source, src_addr) && ++ !compare_ether_addr(eth_hdr_p->h_dest, dest_addr)) ++ /* Yes, we already have an ethernet header */ ++ skb_reset_mac_header(skb); ++ else { ++ u16 len; ++ ++ /* Need to build an ethernet header */ ++ if (!memcmp(skb->data, snapsig, sizeof(snapsig))) { ++ /* SNAP frame - decapsulate, keep proto */ ++ skb_push(skb, offsetof(struct ethhdr, h_proto) - ++ sizeof(rfc1042sig)); ++ len = 0; ++ } else { ++ /* 802.3 frame, proto is length */ ++ len = skb->len; ++ skb_push(skb, ETH_HLEN); ++ } ++ ++ skb_reset_mac_header(skb); ++ eth_hdr_p = eth_hdr(skb); ++ /* This needs to be done in this order (eth_hdr_p->h_dest may ++ * overlap src_addr) */ ++ memcpy(eth_hdr_p->h_source, src_addr, ETH_ALEN); ++ memcpy(eth_hdr_p->h_dest, dest_addr, ETH_ALEN); ++ if (len) ++ eth_hdr_p->h_proto = htons(len); ++ } ++ ++ skb->protocol = eth_type_trans(skb, skb->dev); ++} ++ ++/* Check for fragmented data in priv->rx_skb. If the packet was no fragment ++ or it was the last of a fragment set a skb containing the whole packet ++ is returned for further processing. Otherwise we get NULL and are ++ done and the packet is either stored inside the fragment buffer ++ or thrown away. Every returned skb starts with the ieee802_11 header ++ and contains _no_ FCS at the end */ ++static struct sk_buff *at76_check_for_rx_frags(struct at76_priv *priv) ++{ ++ struct sk_buff *skb = priv->rx_skb; ++ struct at76_rx_buffer *buf = (struct at76_rx_buffer *)skb->data; ++ struct ieee80211_hdr_3addr *i802_11_hdr = ++ (struct ieee80211_hdr_3addr *)buf->packet; ++ /* seq_ctrl, fragment_number, sequence number of new packet */ ++ u16 sctl = le16_to_cpu(i802_11_hdr->seq_ctl); ++ u16 fragnr = sctl & 0xf; ++ u16 seqnr = sctl >> 4; ++ u16 frame_ctl = le16_to_cpu(i802_11_hdr->frame_ctl); ++ ++ /* Length including the IEEE802.11 header, but without the trailing ++ * FCS and without the Atmel Rx header */ ++ int length = le16_to_cpu(buf->wlength) - IEEE80211_FCS_LEN; ++ ++ /* where does the data payload start in skb->data ? */ ++ u8 *data = i802_11_hdr->payload; ++ ++ /* length of payload, excl. the trailing FCS */ ++ int data_len = length - IEEE80211_3ADDR_LEN; ++ ++ int i; ++ struct rx_data_buf *bptr, *optr; ++ unsigned long oldest = ~0UL; ++ ++ at76_dbg(DBG_RX_FRAGS, ++ "%s: rx data frame_ctl %04x addr2 %s seq/frag %d/%d " ++ "length %d data %d: %s ...", priv->netdev->name, frame_ctl, ++ mac2str(i802_11_hdr->addr2), seqnr, fragnr, length, data_len, ++ hex2str(data, 32)); ++ ++ at76_dbg(DBG_RX_FRAGS_SKB, "%s: incoming skb: head %p data %p " ++ "tail %p end %p len %d", priv->netdev->name, skb->head, ++ skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), ++ skb->len); ++ ++ if (data_len < 0) { ++ /* make sure data starts in the buffer */ ++ printk(KERN_INFO "%s: data frame too short\n", ++ priv->netdev->name); ++ return NULL; ++ } ++ ++ WARN_ON(length <= AT76_RX_HDRLEN); ++ if (length <= AT76_RX_HDRLEN) ++ return NULL; ++ ++ /* remove the at76_rx_buffer header - we don't need it anymore */ ++ /* we need the IEEE802.11 header (for the addresses) if this packet ++ is the first of a chain */ ++ skb_pull(skb, AT76_RX_HDRLEN); ++ ++ /* remove FCS at end */ ++ skb_trim(skb, length); ++ ++ at76_dbg(DBG_RX_FRAGS_SKB, "%s: trimmed skb: head %p data %p tail %p " ++ "end %p len %d data %p data_len %d", priv->netdev->name, ++ skb->head, skb->data, skb_tail_pointer(skb), ++ skb_end_pointer(skb), skb->len, data, data_len); ++ ++ if (fragnr == 0 && !(frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { ++ /* unfragmented packet received */ ++ /* Use a new skb for the next receive */ ++ priv->rx_skb = NULL; ++ at76_dbg(DBG_RX_FRAGS, "%s: unfragmented", priv->netdev->name); ++ return skb; ++ } ++ ++ /* look if we've got a chain for the sender address. ++ afterwards optr points to first free or the oldest entry, ++ or, if i < NR_RX_DATA_BUF, bptr points to the entry for the ++ sender address */ ++ /* determining the oldest entry doesn't cope with jiffies wrapping ++ but I don't care to delete a young entry at these rare moments ... */ ++ ++ bptr = priv->rx_data; ++ optr = NULL; ++ for (i = 0; i < NR_RX_DATA_BUF; i++, bptr++) { ++ if (!bptr->skb) { ++ optr = bptr; ++ oldest = 0UL; ++ continue; ++ } ++ ++ if (!compare_ether_addr(i802_11_hdr->addr2, bptr->sender)) ++ break; ++ ++ if (!optr) { ++ optr = bptr; ++ oldest = bptr->last_rx; ++ } else if (bptr->last_rx < oldest) ++ optr = bptr; ++ } ++ ++ if (i < NR_RX_DATA_BUF) { ++ ++ at76_dbg(DBG_RX_FRAGS, "%s: %d. cacheentry (seq/frag = %d/%d) " ++ "matched sender addr", ++ priv->netdev->name, i, bptr->seqnr, bptr->fragnr); ++ ++ /* bptr points to an entry for the sender address */ ++ if (bptr->seqnr == seqnr) { ++ int left; ++ /* the fragment has the current sequence number */ ++ if (((bptr->fragnr + 1) & 0xf) != fragnr) { ++ /* wrong fragment number -> ignore it */ ++ /* is & 0xf necessary above ??? */ ++ at76_dbg(DBG_RX_FRAGS, ++ "%s: frag nr mismatch: %d + 1 != %d", ++ priv->netdev->name, bptr->fragnr, ++ fragnr); ++ return NULL; ++ } ++ bptr->last_rx = jiffies; ++ /* the next following fragment number -> ++ add the data at the end */ ++ ++ /* for test only ??? */ ++ left = skb_tailroom(bptr->skb); ++ if (left < data_len) ++ printk(KERN_INFO ++ "%s: only %d byte free (need %d)\n", ++ priv->netdev->name, left, data_len); ++ else ++ memcpy(skb_put(bptr->skb, data_len), data, ++ data_len); ++ ++ bptr->fragnr = fragnr; ++ if (frame_ctl & IEEE80211_FCTL_MOREFRAGS) ++ return NULL; ++ ++ /* this was the last fragment - send it */ ++ skb = bptr->skb; ++ bptr->skb = NULL; /* free the entry */ ++ at76_dbg(DBG_RX_FRAGS, "%s: last frag of seq %d", ++ priv->netdev->name, seqnr); ++ return skb; ++ } ++ ++ /* got another sequence number */ ++ if (fragnr == 0) { ++ /* it's the start of a new chain - replace the ++ old one by this */ ++ /* bptr->sender has the correct value already */ ++ at76_dbg(DBG_RX_FRAGS, ++ "%s: start of new seq %d, removing old seq %d", ++ priv->netdev->name, seqnr, bptr->seqnr); ++ bptr->seqnr = seqnr; ++ bptr->fragnr = 0; ++ bptr->last_rx = jiffies; ++ /* swap bptr->skb and priv->rx_skb */ ++ skb = bptr->skb; ++ bptr->skb = priv->rx_skb; ++ priv->rx_skb = skb; ++ } else { ++ /* it from the middle of a new chain -> ++ delete the old entry and skip the new one */ ++ at76_dbg(DBG_RX_FRAGS, ++ "%s: middle of new seq %d (%d) " ++ "removing old seq %d", ++ priv->netdev->name, seqnr, fragnr, ++ bptr->seqnr); ++ dev_kfree_skb(bptr->skb); ++ bptr->skb = NULL; ++ } ++ return NULL; ++ } ++ ++ /* if we didn't find a chain for the sender address, optr ++ points either to the first free or the oldest entry */ ++ ++ if (fragnr != 0) { ++ /* this is not the begin of a fragment chain ... */ ++ at76_dbg(DBG_RX_FRAGS, ++ "%s: no chain for non-first fragment (%d)", ++ priv->netdev->name, fragnr); ++ return NULL; ++ } ++ ++ BUG_ON(!optr); ++ if (optr->skb) { ++ /* swap the skb's */ ++ skb = optr->skb; ++ optr->skb = priv->rx_skb; ++ priv->rx_skb = skb; ++ ++ at76_dbg(DBG_RX_FRAGS, ++ "%s: free old contents: sender %s seq/frag %d/%d", ++ priv->netdev->name, mac2str(optr->sender), ++ optr->seqnr, optr->fragnr); ++ ++ } else { ++ /* take the skb from priv->rx_skb */ ++ optr->skb = priv->rx_skb; ++ /* let at76_submit_rx_urb() allocate a new skb */ ++ priv->rx_skb = NULL; ++ ++ at76_dbg(DBG_RX_FRAGS, "%s: use a free entry", ++ priv->netdev->name); ++ } ++ memcpy(optr->sender, i802_11_hdr->addr2, ETH_ALEN); ++ optr->seqnr = seqnr; ++ optr->fragnr = 0; ++ optr->last_rx = jiffies; ++ ++ return NULL; ++} ++ ++/* Rx interrupt: we expect the complete data buffer in priv->rx_skb */ ++static void at76_rx_data(struct at76_priv *priv) ++{ ++ struct net_device *netdev = priv->netdev; ++ struct net_device_stats *stats = &priv->stats; ++ struct sk_buff *skb = priv->rx_skb; ++ struct at76_rx_buffer *buf = (struct at76_rx_buffer *)skb->data; ++ struct ieee80211_hdr_3addr *i802_11_hdr; ++ int length = le16_to_cpu(buf->wlength); ++ ++ at76_dbg(DBG_RX_DATA, "%s received data packet: %s", netdev->name, ++ hex2str(skb->data, AT76_RX_HDRLEN)); ++ ++ at76_dbg(DBG_RX_DATA_CONTENT, "rx packet: %s", ++ hex2str(skb->data + AT76_RX_HDRLEN, length)); ++ ++ skb = at76_check_for_rx_frags(priv); ++ if (!skb) ++ return; ++ ++ /* Atmel header and the FCS are already removed */ ++ i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data; ++ ++ skb->dev = netdev; ++ skb->ip_summed = CHECKSUM_NONE; /* TODO: should check CRC */ ++ ++ if (is_broadcast_ether_addr(i802_11_hdr->addr1)) { ++ if (!compare_ether_addr(i802_11_hdr->addr1, netdev->broadcast)) ++ skb->pkt_type = PACKET_BROADCAST; ++ else ++ skb->pkt_type = PACKET_MULTICAST; ++ } else if (compare_ether_addr(i802_11_hdr->addr1, netdev->dev_addr)) ++ skb->pkt_type = PACKET_OTHERHOST; ++ ++ at76_ieee80211_to_eth(skb, priv->iw_mode); ++ ++ netdev->last_rx = jiffies; ++ netif_rx(skb); ++ stats->rx_packets++; ++ stats->rx_bytes += length; ++ ++ return; ++} ++ ++static void at76_rx_monitor_mode(struct at76_priv *priv) ++{ ++ struct at76_rx_radiotap *rt; ++ u8 *payload; ++ int skblen; ++ struct net_device *netdev = priv->netdev; ++ struct at76_rx_buffer *buf = ++ (struct at76_rx_buffer *)priv->rx_skb->data; ++ /* length including the IEEE802.11 header and the trailing FCS, ++ but not at76_rx_buffer */ ++ int length = le16_to_cpu(buf->wlength); ++ struct sk_buff *skb = priv->rx_skb; ++ struct net_device_stats *stats = &priv->stats; ++ ++ if (length < IEEE80211_FCS_LEN) { ++ /* buffer contains no data */ ++ at76_dbg(DBG_MONITOR_MODE, ++ "%s: MONITOR MODE: rx skb without data", ++ priv->netdev->name); ++ return; ++ } ++ ++ skblen = sizeof(struct at76_rx_radiotap) + length; ++ ++ skb = dev_alloc_skb(skblen); ++ if (!skb) { ++ printk(KERN_ERR "%s: MONITOR MODE: dev_alloc_skb for radiotap " ++ "header returned NULL\n", priv->netdev->name); ++ return; ++ } ++ ++ skb_put(skb, skblen); ++ ++ rt = (struct at76_rx_radiotap *)skb->data; ++ payload = skb->data + sizeof(struct at76_rx_radiotap); ++ ++ rt->rt_hdr.it_version = 0; ++ rt->rt_hdr.it_pad = 0; ++ rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct at76_rx_radiotap)); ++ rt->rt_hdr.it_present = cpu_to_le32(AT76_RX_RADIOTAP_PRESENT); ++ ++ rt->rt_tsft = cpu_to_le64(le32_to_cpu(buf->rx_time)); ++ rt->rt_rate = hw_rates[buf->rx_rate] & (~0x80); ++ rt->rt_signal = buf->rssi; ++ rt->rt_noise = buf->noise_level; ++ rt->rt_flags = IEEE80211_RADIOTAP_F_FCS; ++ if (buf->fragmentation) ++ rt->rt_flags |= IEEE80211_RADIOTAP_F_FRAG; ++ ++ memcpy(payload, buf->packet, length); ++ skb->dev = netdev; ++ skb->ip_summed = CHECKSUM_NONE; ++ skb_reset_mac_header(skb); ++ skb->pkt_type = PACKET_OTHERHOST; ++ skb->protocol = htons(ETH_P_802_2); ++ ++ netdev->last_rx = jiffies; ++ netif_rx(skb); ++ stats->rx_packets++; ++ stats->rx_bytes += length; ++} ++ ++/* Check if we spy on the sender address in buf and update stats */ ++static void at76_iwspy_update(struct at76_priv *priv, ++ struct at76_rx_buffer *buf) ++{ ++ struct ieee80211_hdr_3addr *hdr = ++ (struct ieee80211_hdr_3addr *)buf->packet; ++ struct iw_quality qual; ++ ++ /* We can only set the level here */ ++ qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; ++ qual.level = 0; ++ qual.noise = 0; ++ at76_calc_level(priv, buf, &qual); ++ ++ spin_lock_bh(&priv->spy_spinlock); ++ ++ if (priv->spy_data.spy_number > 0) ++ wireless_spy_update(priv->netdev, hdr->addr2, &qual); ++ ++ spin_unlock_bh(&priv->spy_spinlock); ++} ++ ++static void at76_rx_tasklet(unsigned long param) ++{ ++ struct urb *urb = (struct urb *)param; ++ struct at76_priv *priv = urb->context; ++ struct net_device *netdev = priv->netdev; ++ struct at76_rx_buffer *buf; ++ struct ieee80211_hdr_3addr *i802_11_hdr; ++ u16 frame_ctl; ++ ++ if (priv->device_unplugged) { ++ at76_dbg(DBG_DEVSTART, "device unplugged"); ++ if (urb) ++ at76_dbg(DBG_DEVSTART, "urb status %d", urb->status); ++ return; ++ } ++ ++ if (!priv->rx_skb || !netdev || !priv->rx_skb->data) ++ return; ++ ++ buf = (struct at76_rx_buffer *)priv->rx_skb->data; ++ ++ i802_11_hdr = (struct ieee80211_hdr_3addr *)buf->packet; ++ ++ frame_ctl = le16_to_cpu(i802_11_hdr->frame_ctl); ++ ++ if (urb->status != 0) { ++ if (urb->status != -ENOENT && urb->status != -ECONNRESET) ++ at76_dbg(DBG_URB, ++ "%s %s: - nonzero Rx bulk status received: %d", ++ __func__, netdev->name, urb->status); ++ return; ++ } ++ ++ at76_dbg(DBG_RX_ATMEL_HDR, ++ "%s: rx frame: rate %d rssi %d noise %d link %d %s", ++ priv->netdev->name, buf->rx_rate, buf->rssi, buf->noise_level, ++ buf->link_quality, hex2str(i802_11_hdr, 48)); ++ if (priv->iw_mode == IW_MODE_MONITOR) { ++ at76_rx_monitor_mode(priv); ++ goto exit; ++ } ++ ++ /* there is a new bssid around, accept it: */ ++ if (buf->newbss && priv->iw_mode == IW_MODE_ADHOC) { ++ at76_dbg(DBG_PROGRESS, "%s: rx newbss", netdev->name); ++ schedule_work(&priv->work_new_bss); ++ } ++ ++ switch (frame_ctl & IEEE80211_FCTL_FTYPE) { ++ case IEEE80211_FTYPE_DATA: ++ at76_rx_data(priv); ++ break; ++ ++ case IEEE80211_FTYPE_MGMT: ++ /* jal: TODO: find out if we can update iwspy also on ++ other frames than management (might depend on the ++ radio chip / firmware version !) */ ++ ++ at76_iwspy_update(priv, buf); ++ ++ at76_rx_mgmt(priv, buf); ++ break; ++ ++ case IEEE80211_FTYPE_CTL: ++ at76_dbg(DBG_RX_CTRL, "%s: ignored ctrl frame: %04x", ++ priv->netdev->name, frame_ctl); ++ break; ++ ++ default: ++ printk(KERN_DEBUG "%s: ignoring frame with framectl 0x%04x\n", ++ priv->netdev->name, frame_ctl); ++ } ++exit: ++ at76_submit_rx_urb(priv); ++} ++ ++/* Load firmware into kernel memory and parse it */ ++static struct fwentry *at76_load_firmware(struct usb_device *udev, ++ enum board_type board_type) ++{ ++ int ret; ++ char *str; ++ struct at76_fw_header *fwh; ++ struct fwentry *fwe = &firmwares[board_type]; ++ ++ mutex_lock(&fw_mutex); ++ ++ if (fwe->loaded) { ++ at76_dbg(DBG_FW, "re-using previously loaded fw"); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname); ++ ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev); ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n", ++ fwe->fwname); ++ dev_printk(KERN_ERR, &udev->dev, ++ "you may need to download the firmware from " ++ "http://developer.berlios.de/projects/at76c503a/"); ++ goto exit; ++ } ++ ++ at76_dbg(DBG_FW, "got it."); ++ fwh = (struct at76_fw_header *)(fwe->fw->data); ++ ++ if (fwe->fw->size <= sizeof(*fwh)) { ++ dev_printk(KERN_ERR, &udev->dev, ++ "firmware is too short (0x%zx)\n", fwe->fw->size); ++ goto exit; ++ } ++ ++ /* CRC currently not checked */ ++ fwe->board_type = le32_to_cpu(fwh->board_type); ++ if (fwe->board_type != board_type) { ++ dev_printk(KERN_ERR, &udev->dev, ++ "board type mismatch, requested %u, got %u\n", ++ board_type, fwe->board_type); ++ goto exit; ++ } ++ ++ fwe->fw_version.major = fwh->major; ++ fwe->fw_version.minor = fwh->minor; ++ fwe->fw_version.patch = fwh->patch; ++ fwe->fw_version.build = fwh->build; ++ ++ str = (char *)fwh + le32_to_cpu(fwh->str_offset); ++ fwe->intfw = (u8 *)fwh + le32_to_cpu(fwh->int_fw_offset); ++ fwe->intfw_size = le32_to_cpu(fwh->int_fw_len); ++ fwe->extfw = (u8 *)fwh + le32_to_cpu(fwh->ext_fw_offset); ++ fwe->extfw_size = le32_to_cpu(fwh->ext_fw_len); ++ ++ fwe->loaded = 1; ++ ++ dev_printk(KERN_DEBUG, &udev->dev, ++ "using firmware %s (version %d.%d.%d-%d)\n", ++ fwe->fwname, fwh->major, fwh->minor, fwh->patch, fwh->build); ++ ++ at76_dbg(DBG_DEVSTART, "board %u, int %d:%d, ext %d:%d", board_type, ++ le32_to_cpu(fwh->int_fw_offset), le32_to_cpu(fwh->int_fw_len), ++ le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len)); ++ at76_dbg(DBG_DEVSTART, "firmware id %s", str); ++ ++exit: ++ mutex_unlock(&fw_mutex); ++ ++ if (fwe->loaded) ++ return fwe; ++ else ++ return NULL; ++} ++ ++/* Allocate network device and initialize private data */ ++static struct at76_priv *at76_alloc_new_device(struct usb_device *udev) ++{ ++ struct net_device *netdev; ++ struct at76_priv *priv; ++ int i; ++ ++ /* allocate memory for our device state and initialize it */ ++ netdev = alloc_etherdev(sizeof(struct at76_priv)); ++ if (!netdev) { ++ dev_printk(KERN_ERR, &udev->dev, "out of memory\n"); ++ return NULL; ++ } ++ ++ priv = netdev_priv(netdev); ++ ++ priv->udev = udev; ++ priv->netdev = netdev; ++ ++ mutex_init(&priv->mtx); ++ INIT_WORK(&priv->work_assoc_done, at76_work_assoc_done); ++ INIT_WORK(&priv->work_join, at76_work_join); ++ INIT_WORK(&priv->work_new_bss, at76_work_new_bss); ++ INIT_WORK(&priv->work_start_scan, at76_work_start_scan); ++ INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc); ++ INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx); ++ INIT_DELAYED_WORK(&priv->dwork_restart, at76_dwork_restart); ++ INIT_DELAYED_WORK(&priv->dwork_get_scan, at76_dwork_get_scan); ++ INIT_DELAYED_WORK(&priv->dwork_beacon, at76_dwork_beacon); ++ INIT_DELAYED_WORK(&priv->dwork_auth, at76_dwork_auth); ++ INIT_DELAYED_WORK(&priv->dwork_assoc, at76_dwork_assoc); ++ ++ spin_lock_init(&priv->mgmt_spinlock); ++ priv->next_mgmt_bulk = NULL; ++ priv->mac_state = MAC_INIT; ++ ++ /* initialize empty BSS list */ ++ priv->curr_bss = NULL; ++ INIT_LIST_HEAD(&priv->bss_list); ++ spin_lock_init(&priv->bss_list_spinlock); ++ ++ init_timer(&priv->bss_list_timer); ++ priv->bss_list_timer.data = (unsigned long)priv; ++ priv->bss_list_timer.function = at76_bss_list_timeout; ++ ++ spin_lock_init(&priv->spy_spinlock); ++ ++ /* mark all rx data entries as unused */ ++ for (i = 0; i < NR_RX_DATA_BUF; i++) ++ priv->rx_data[i].skb = NULL; ++ ++ priv->rx_tasklet.func = at76_rx_tasklet; ++ priv->rx_tasklet.data = 0; ++ ++ priv->pm_mode = AT76_PM_OFF; ++ priv->pm_period = 0; ++ ++ return priv; ++} ++ ++static int at76_alloc_urbs(struct at76_priv *priv, ++ struct usb_interface *interface) ++{ ++ struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out; ++ int i; ++ int buffer_size; ++ struct usb_host_interface *iface_desc; ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__); ++ ++ at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__, ++ interface->altsetting[0].desc.bNumEndpoints); ++ ++ ep_in = NULL; ++ ep_out = NULL; ++ iface_desc = interface->cur_altsetting; ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { ++ endpoint = &iface_desc->endpoint[i].desc; ++ ++ at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x", ++ __func__, i, endpoint->bEndpointAddress, ++ endpoint->bmAttributes); ++ ++ if (!ep_in && usb_endpoint_is_bulk_in(endpoint)) ++ ep_in = endpoint; ++ ++ if (!ep_out && usb_endpoint_is_bulk_out(endpoint)) ++ ep_out = endpoint; ++ } ++ ++ if (!ep_in || !ep_out) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "bulk endpoints missing\n"); ++ return -ENXIO; ++ } ++ ++ priv->rx_pipe = usb_rcvbulkpipe(priv->udev, ep_in->bEndpointAddress); ++ priv->tx_pipe = usb_sndbulkpipe(priv->udev, ep_out->bEndpointAddress); ++ ++ priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL); ++ priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!priv->rx_urb || !priv->tx_urb) { ++ dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n"); ++ return -ENOMEM; ++ } ++ ++ buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE; ++ priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); ++ if (!priv->bulk_out_buffer) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "cannot allocate output buffer\n"); ++ return -ENOMEM; ++ } ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__); ++ ++ return 0; ++} ++ ++/* Register network device and initialize the hardware */ ++static int at76_init_new_device(struct at76_priv *priv, ++ struct usb_interface *interface) ++{ ++ struct net_device *netdev = priv->netdev; ++ int ret; ++ ++ /* set up the endpoint information */ ++ /* check out the endpoints */ ++ ++ at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints", ++ interface->cur_altsetting->desc.bNumEndpoints); ++ ++ ret = at76_alloc_urbs(priv, interface); ++ if (ret < 0) ++ goto exit; ++ ++ /* MAC address */ ++ ret = at76_get_hw_config(priv); ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "cannot get MAC address\n"); ++ goto exit; ++ } ++ ++ priv->domain = at76_get_reg_domain(priv->regulatory_domain); ++ /* init. netdev->dev_addr */ ++ memcpy(netdev->dev_addr, priv->mac_addr, ETH_ALEN); ++ ++ priv->channel = DEF_CHANNEL; ++ priv->iw_mode = IW_MODE_INFRA; ++ priv->rts_threshold = DEF_RTS_THRESHOLD; ++ priv->frag_threshold = DEF_FRAG_THRESHOLD; ++ priv->short_retry_limit = DEF_SHORT_RETRY_LIMIT; ++ priv->txrate = TX_RATE_AUTO; ++ priv->preamble_type = PREAMBLE_TYPE_LONG; ++ priv->beacon_period = 100; ++ priv->beacons_last_qual = jiffies; ++ priv->auth_mode = WLAN_AUTH_OPEN; ++ priv->scan_min_time = DEF_SCAN_MIN_TIME; ++ priv->scan_max_time = DEF_SCAN_MAX_TIME; ++ priv->scan_mode = SCAN_TYPE_ACTIVE; ++ ++ netdev->flags &= ~IFF_MULTICAST; /* not yet or never */ ++ netdev->open = at76_open; ++ netdev->stop = at76_stop; ++ netdev->get_stats = at76_get_stats; ++ netdev->ethtool_ops = &at76_ethtool_ops; ++ ++ /* Add pointers to enable iwspy support. */ ++ priv->wireless_data.spy_data = &priv->spy_data; ++ netdev->wireless_data = &priv->wireless_data; ++ ++ netdev->hard_start_xmit = at76_tx; ++ netdev->tx_timeout = at76_tx_timeout; ++ netdev->watchdog_timeo = 2 * HZ; ++ netdev->wireless_handlers = &at76_handler_def; ++ netdev->set_multicast_list = at76_set_multicast; ++ netdev->set_mac_address = at76_set_mac_address; ++ dev_alloc_name(netdev, "wlan%d"); ++ ++ ret = register_netdev(priv->netdev); ++ if (ret) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "cannot register netdevice (status %d)!\n", ret); ++ goto exit; ++ } ++ priv->netdev_registered = 1; ++ ++ printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n", ++ netdev->name, interface->dev.bus_id, mac2str(priv->mac_addr), ++ priv->fw_version.major, priv->fw_version.minor, ++ priv->fw_version.patch, priv->fw_version.build); ++ printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n", netdev->name, ++ priv->regulatory_domain, priv->domain->name); ++ ++ /* we let this timer run the whole time this driver instance lives */ ++ mod_timer(&priv->bss_list_timer, jiffies + BSS_LIST_TIMEOUT); ++ ++exit: ++ return ret; ++} ++ ++static void at76_delete_device(struct at76_priv *priv) ++{ ++ int i; ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__); ++ ++ /* The device is gone, don't bother turning it off */ ++ priv->device_unplugged = 1; ++ ++ if (priv->netdev_registered) ++ unregister_netdev(priv->netdev); ++ ++ /* assuming we used keventd, it must quiesce too */ ++ flush_scheduled_work(); ++ ++ kfree(priv->bulk_out_buffer); ++ ++ if (priv->tx_urb) { ++ usb_kill_urb(priv->tx_urb); ++ usb_free_urb(priv->tx_urb); ++ } ++ if (priv->rx_urb) { ++ usb_kill_urb(priv->rx_urb); ++ usb_free_urb(priv->rx_urb); ++ } ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__); ++ ++ if (priv->rx_skb) ++ kfree_skb(priv->rx_skb); ++ ++ at76_free_bss_list(priv); ++ del_timer_sync(&priv->bss_list_timer); ++ cancel_delayed_work(&priv->dwork_get_scan); ++ cancel_delayed_work(&priv->dwork_beacon); ++ cancel_delayed_work(&priv->dwork_auth); ++ cancel_delayed_work(&priv->dwork_assoc); ++ ++ if (priv->mac_state == MAC_CONNECTED) ++ at76_iwevent_bss_disconnect(priv->netdev); ++ ++ for (i = 0; i < NR_RX_DATA_BUF; i++) ++ if (priv->rx_data[i].skb) { ++ dev_kfree_skb(priv->rx_data[i].skb); ++ priv->rx_data[i].skb = NULL; ++ } ++ usb_put_dev(priv->udev); ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/netdev", __func__); ++ free_netdev(priv->netdev); /* priv is in netdev */ ++ ++ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__); ++} ++ ++static int at76_probe(struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ int ret; ++ struct at76_priv *priv; ++ struct fwentry *fwe; ++ struct usb_device *udev; ++ int op_mode; ++ int need_ext_fw = 0; ++ struct mib_fw_version fwv; ++ int board_type = (int)id->driver_info; ++ ++ udev = usb_get_dev(interface_to_usbdev(interface)); ++ ++ /* Load firmware into kernel memory */ ++ fwe = at76_load_firmware(udev, board_type); ++ if (!fwe) { ++ ret = -ENOENT; ++ goto error; ++ } ++ ++ op_mode = at76_get_op_mode(udev); ++ ++ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode); ++ ++ /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ??? ++ we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */ ++ ++ if (op_mode == OPMODE_HW_CONFIG_MODE) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "cannot handle a device in HW_CONFIG_MODE\n"); ++ ret = -EBUSY; ++ goto error; ++ } ++ ++ if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH ++ && op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { ++ /* download internal firmware part */ ++ dev_printk(KERN_DEBUG, &interface->dev, ++ "downloading internal firmware\n"); ++ ret = at76_load_internal_fw(udev, fwe); ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "error %d downloading internal firmware\n", ++ ret); ++ goto error; ++ } ++ usb_put_dev(udev); ++ return ret; ++ } ++ ++ /* Internal firmware already inside the device. Get firmware ++ * version to test if external firmware is loaded. ++ * This works only for newer firmware, e.g. the Intersil 0.90.x ++ * says "control timeout on ep0in" and subsequent ++ * at76_get_op_mode() fail too :-( */ ++ ++ /* if version >= 0.100.x.y or device with built-in flash we can ++ * query the device for the fw version */ ++ if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100) ++ || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) { ++ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv)); ++ if (ret < 0 || (fwv.major | fwv.minor) == 0) ++ need_ext_fw = 1; ++ } else ++ /* No way to check firmware version, reload to be sure */ ++ need_ext_fw = 1; ++ ++ if (need_ext_fw) { ++ dev_printk(KERN_DEBUG, &interface->dev, ++ "downloading external firmware\n"); ++ ++ ret = at76_load_external_fw(udev, fwe); ++ if (ret) ++ goto error; ++ ++ /* Re-check firmware version */ ++ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv)); ++ if (ret < 0) { ++ dev_printk(KERN_ERR, &interface->dev, ++ "error %d getting firmware version\n", ret); ++ goto error; ++ } ++ } ++ ++ priv = at76_alloc_new_device(udev); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ SET_NETDEV_DEV(priv->netdev, &interface->dev); ++ usb_set_intfdata(interface, priv); ++ ++ memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version)); ++ priv->board_type = board_type; ++ ++ ret = at76_init_new_device(priv, interface); ++ if (ret < 0) ++ at76_delete_device(priv); ++ ++ return ret; ++ ++error: ++ usb_put_dev(udev); ++ return ret; ++} ++ ++static void at76_disconnect(struct usb_interface *interface) ++{ ++ struct at76_priv *priv; ++ ++ priv = usb_get_intfdata(interface); ++ usb_set_intfdata(interface, NULL); ++ ++ /* Disconnect after loading internal firmware */ ++ if (!priv) ++ return; ++ ++ printk(KERN_INFO "%s: disconnecting\n", priv->netdev->name); ++ at76_delete_device(priv); ++ dev_printk(KERN_INFO, &interface->dev, "disconnected\n"); ++} ++ ++/* Structure for registering this driver with the USB subsystem */ ++static struct usb_driver at76_driver = { ++ .name = DRIVER_NAME, ++ .probe = at76_probe, ++ .disconnect = at76_disconnect, ++ .id_table = dev_table, ++}; ++ ++static int __init at76_mod_init(void) ++{ ++ int result; ++ ++ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n"); ++ ++ mutex_init(&fw_mutex); ++ ++ /* register this driver with the USB subsystem */ ++ result = usb_register(&at76_driver); ++ if (result < 0) ++ printk(KERN_ERR DRIVER_NAME ++ ": usb_register failed (status %d)\n", result); ++ ++ led_trigger_register_simple("at76_usb-tx", &ledtrig_tx); ++ return result; ++} ++ ++static void __exit at76_mod_exit(void) ++{ ++ int i; ++ ++ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n"); ++ usb_deregister(&at76_driver); ++ for (i = 0; i < ARRAY_SIZE(firmwares); i++) { ++ if (firmwares[i].fw) ++ release_firmware(firmwares[i].fw); ++ } ++ led_trigger_unregister_simple(ledtrig_tx); ++} ++ ++module_param_named(debug, at76_debug, int, 0600); ++MODULE_PARM_DESC(debug, "Debugging level"); ++ ++module_init(at76_mod_init); ++module_exit(at76_mod_exit); ++ ++MODULE_AUTHOR("Oliver Kurth "); ++MODULE_AUTHOR("Joerg Albert "); ++MODULE_AUTHOR("Alex "); ++MODULE_AUTHOR("Nick Jones"); ++MODULE_AUTHOR("Balint Seeber "); ++MODULE_AUTHOR("Pavel Roskin "); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/staging/at76_usb/at76_usb.h +@@ -0,0 +1,619 @@ ++/* ++ * Copyright (c) 2002,2003 Oliver Kurth ++ * (c) 2003,2004 Joerg Albert ++ * (c) 2007 Guido Guenther ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This driver was based on information from the Sourceforge driver ++ * released and maintained by Atmel: ++ * ++ * http://sourceforge.net/projects/atmelwlandriver/ ++ * ++ * Although the code was completely re-written, ++ * it would have been impossible without Atmel's decision to ++ * release an Open Source driver (unfortunately the firmware was ++ * kept binary only). Thanks for that decision to Atmel! ++ */ ++ ++#ifndef _AT76_USB_H ++#define _AT76_USB_H ++ ++/* Board types */ ++enum board_type { ++ BOARD_503_ISL3861 = 1, ++ BOARD_503_ISL3863 = 2, ++ BOARD_503 = 3, ++ BOARD_503_ACC = 4, ++ BOARD_505 = 5, ++ BOARD_505_2958 = 6, ++ BOARD_505A = 7, ++ BOARD_505AMX = 8 ++}; ++ ++/* our private ioctl's */ ++/* preamble length (0 - long, 1 - short, 2 - auto) */ ++#define AT76_SET_SHORT_PREAMBLE (SIOCIWFIRSTPRIV + 0) ++#define AT76_GET_SHORT_PREAMBLE (SIOCIWFIRSTPRIV + 1) ++/* which debug channels are enabled */ ++#define AT76_SET_DEBUG (SIOCIWFIRSTPRIV + 2) ++#define AT76_GET_DEBUG (SIOCIWFIRSTPRIV + 3) ++/* power save mode (incl. the Atmel proprietary smart save mode) */ ++#define AT76_SET_POWERSAVE_MODE (SIOCIWFIRSTPRIV + 4) ++#define AT76_GET_POWERSAVE_MODE (SIOCIWFIRSTPRIV + 5) ++/* min and max channel times for scan */ ++#define AT76_SET_SCAN_TIMES (SIOCIWFIRSTPRIV + 6) ++#define AT76_GET_SCAN_TIMES (SIOCIWFIRSTPRIV + 7) ++/* scan mode (0 - active, 1 - passive) */ ++#define AT76_SET_SCAN_MODE (SIOCIWFIRSTPRIV + 8) ++#define AT76_GET_SCAN_MODE (SIOCIWFIRSTPRIV + 9) ++ ++#define CMD_STATUS_IDLE 0x00 ++#define CMD_STATUS_COMPLETE 0x01 ++#define CMD_STATUS_UNKNOWN 0x02 ++#define CMD_STATUS_INVALID_PARAMETER 0x03 ++#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 ++#define CMD_STATUS_TIME_OUT 0x07 ++#define CMD_STATUS_IN_PROGRESS 0x08 ++#define CMD_STATUS_HOST_FAILURE 0xff ++#define CMD_STATUS_SCAN_FAILED 0xf0 ++ ++/* answers to get op mode */ ++#define OPMODE_NONE 0x00 ++#define OPMODE_NORMAL_NIC_WITH_FLASH 0x01 ++#define OPMODE_HW_CONFIG_MODE 0x02 ++#define OPMODE_DFU_MODE_WITH_FLASH 0x03 ++#define OPMODE_NORMAL_NIC_WITHOUT_FLASH 0x04 ++ ++#define CMD_SET_MIB 0x01 ++#define CMD_GET_MIB 0x02 ++#define CMD_SCAN 0x03 ++#define CMD_JOIN 0x04 ++#define CMD_START_IBSS 0x05 ++#define CMD_RADIO_ON 0x06 ++#define CMD_RADIO_OFF 0x07 ++#define CMD_STARTUP 0x0B ++ ++#define MIB_LOCAL 0x01 ++#define MIB_MAC_ADDR 0x02 ++#define MIB_MAC 0x03 ++#define MIB_MAC_MGMT 0x05 ++#define MIB_MAC_WEP 0x06 ++#define MIB_PHY 0x07 ++#define MIB_FW_VERSION 0x08 ++#define MIB_MDOMAIN 0x09 ++ ++#define ADHOC_MODE 1 ++#define INFRASTRUCTURE_MODE 2 ++ ++/* values for struct mib_local, field preamble_type */ ++#define PREAMBLE_TYPE_LONG 0 ++#define PREAMBLE_TYPE_SHORT 1 ++#define PREAMBLE_TYPE_AUTO 2 ++ ++/* values for tx_rate */ ++#define TX_RATE_1MBIT 0 ++#define TX_RATE_2MBIT 1 ++#define TX_RATE_5_5MBIT 2 ++#define TX_RATE_11MBIT 3 ++#define TX_RATE_AUTO 4 ++ ++/* power management modes */ ++#define AT76_PM_OFF 1 ++#define AT76_PM_ON 2 ++#define AT76_PM_SMART 3 ++ ++struct hwcfg_r505 { ++ u8 cr39_values[14]; ++ u8 reserved1[14]; ++ u8 bb_cr[14]; ++ u8 pidvid[4]; ++ u8 mac_addr[ETH_ALEN]; ++ u8 regulatory_domain; ++ u8 reserved2[14]; ++ u8 cr15_values[14]; ++ u8 reserved3[3]; ++} __attribute__((packed)); ++ ++struct hwcfg_rfmd { ++ u8 cr20_values[14]; ++ u8 cr21_values[14]; ++ u8 bb_cr[14]; ++ u8 pidvid[4]; ++ u8 mac_addr[ETH_ALEN]; ++ u8 regulatory_domain; ++ u8 low_power_values[14]; ++ u8 normal_power_values[14]; ++ u8 reserved1[3]; ++} __attribute__((packed)); ++ ++struct hwcfg_intersil { ++ u8 mac_addr[ETH_ALEN]; ++ u8 cr31_values[14]; ++ u8 cr58_values[14]; ++ u8 pidvid[4]; ++ u8 regulatory_domain; ++ u8 reserved[1]; ++} __attribute__((packed)); ++ ++union at76_hwcfg { ++ struct hwcfg_intersil i; ++ struct hwcfg_rfmd r3; ++ struct hwcfg_r505 r5; ++}; ++ ++#define WEP_SMALL_KEY_LEN (40 / 8) ++#define WEP_LARGE_KEY_LEN (104 / 8) ++ ++struct at76_card_config { ++ u8 exclude_unencrypted; ++ u8 promiscuous_mode; ++ u8 short_retry_limit; ++ u8 encryption_type; ++ __le16 rts_threshold; ++ __le16 fragmentation_threshold; /* 256..2346 */ ++ u8 basic_rate_set[4]; ++ u8 auto_rate_fallback; /* 0,1 */ ++ u8 channel; ++ u8 privacy_invoked; ++ u8 wep_default_key_id; /* 0..3 */ ++ u8 current_ssid[32]; ++ u8 wep_default_key_value[4][WEP_KEY_LEN]; ++ u8 ssid_len; ++ u8 short_preamble; ++ __le16 beacon_period; ++} __attribute__((packed)); ++ ++struct at76_command { ++ u8 cmd; ++ u8 reserved; ++ __le16 size; ++ u8 data[0]; ++} __attribute__((packed)); ++ ++/* Length of Atmel-specific Rx header before 802.11 frame */ ++#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet) ++ ++struct at76_rx_buffer { ++ __le16 wlength; ++ u8 rx_rate; ++ u8 newbss; ++ u8 fragmentation; ++ u8 rssi; ++ u8 link_quality; ++ u8 noise_level; ++ __le32 rx_time; ++ u8 packet[IEEE80211_FRAME_LEN + IEEE80211_FCS_LEN]; ++} __attribute__((packed)); ++ ++/* Length of Atmel-specific Tx header before 802.11 frame */ ++#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet) ++ ++struct at76_tx_buffer { ++ __le16 wlength; ++ u8 tx_rate; ++ u8 padding; ++ u8 reserved[4]; ++ u8 packet[IEEE80211_FRAME_LEN + IEEE80211_FCS_LEN]; ++} __attribute__((packed)); ++ ++/* defines for scan_type below */ ++#define SCAN_TYPE_ACTIVE 0 ++#define SCAN_TYPE_PASSIVE 1 ++ ++struct at76_req_scan { ++ u8 bssid[ETH_ALEN]; ++ u8 essid[32]; ++ u8 scan_type; ++ u8 channel; ++ __le16 probe_delay; ++ __le16 min_channel_time; ++ __le16 max_channel_time; ++ u8 essid_size; ++ u8 international_scan; ++} __attribute__((packed)); ++ ++struct at76_req_ibss { ++ u8 bssid[ETH_ALEN]; ++ u8 essid[32]; ++ u8 bss_type; ++ u8 channel; ++ u8 essid_size; ++ u8 reserved[3]; ++} __attribute__((packed)); ++ ++struct at76_req_join { ++ u8 bssid[ETH_ALEN]; ++ u8 essid[32]; ++ u8 bss_type; ++ u8 channel; ++ __le16 timeout; ++ u8 essid_size; ++ u8 reserved; ++} __attribute__((packed)); ++ ++struct set_mib_buffer { ++ u8 type; ++ u8 size; ++ u8 index; ++ u8 reserved; ++ union { ++ u8 byte; ++ __le16 word; ++ u8 addr[ETH_ALEN]; ++ } data; ++} __attribute__((packed)); ++ ++struct mib_local { ++ u16 reserved0; ++ u8 beacon_enable; ++ u8 txautorate_fallback; ++ u8 reserved1; ++ u8 ssid_size; ++ u8 promiscuous_mode; ++ u16 reserved2; ++ u8 preamble_type; ++ u16 reserved3; ++} __attribute__((packed)); ++ ++struct mib_mac_addr { ++ u8 mac_addr[ETH_ALEN]; ++ u8 res[2]; /* ??? */ ++ u8 group_addr[4][ETH_ALEN]; ++ u8 group_addr_status[4]; ++} __attribute__((packed)); ++ ++struct mib_mac { ++ __le32 max_tx_msdu_lifetime; ++ __le32 max_rx_lifetime; ++ __le16 frag_threshold; ++ __le16 rts_threshold; ++ __le16 cwmin; ++ __le16 cwmax; ++ u8 short_retry_time; ++ u8 long_retry_time; ++ u8 scan_type; /* active or passive */ ++ u8 scan_channel; ++ __le16 probe_delay; /* delay before ProbeReq in active scan, RO */ ++ __le16 min_channel_time; ++ __le16 max_channel_time; ++ __le16 listen_interval; ++ u8 desired_ssid[32]; ++ u8 desired_bssid[ETH_ALEN]; ++ u8 desired_bsstype; /* ad-hoc or infrastructure */ ++ u8 reserved2; ++} __attribute__((packed)); ++ ++struct mib_mac_mgmt { ++ __le16 beacon_period; ++ __le16 CFP_max_duration; ++ __le16 medium_occupancy_limit; ++ __le16 station_id; /* assoc id */ ++ __le16 ATIM_window; ++ u8 CFP_mode; ++ u8 privacy_option_implemented; ++ u8 DTIM_period; ++ u8 CFP_period; ++ u8 current_bssid[ETH_ALEN]; ++ u8 current_essid[32]; ++ u8 current_bss_type; ++ u8 power_mgmt_mode; ++ /* rfmd and 505 */ ++ u8 ibss_change; ++ u8 res; ++ u8 multi_domain_capability_implemented; ++ u8 multi_domain_capability_enabled; ++ u8 country_string[3]; ++ u8 reserved[3]; ++} __attribute__((packed)); ++ ++struct mib_mac_wep { ++ u8 privacy_invoked; /* 0 disable encr., 1 enable encr */ ++ u8 wep_default_key_id; ++ u8 wep_key_mapping_len; ++ u8 exclude_unencrypted; ++ __le32 wep_icv_error_count; ++ __le32 wep_excluded_count; ++ u8 wep_default_keyvalue[WEP_KEYS][WEP_KEY_LEN]; ++ u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */ ++} __attribute__((packed)); ++ ++struct mib_phy { ++ __le32 ed_threshold; ++ ++ __le16 slot_time; ++ __le16 sifs_time; ++ __le16 preamble_length; ++ __le16 plcp_header_length; ++ __le16 mpdu_max_length; ++ __le16 cca_mode_supported; ++ ++ u8 operation_rate_set[4]; ++ u8 channel_id; ++ u8 current_cca_mode; ++ u8 phy_type; ++ u8 current_reg_domain; ++} __attribute__((packed)); ++ ++struct mib_fw_version { ++ u8 major; ++ u8 minor; ++ u8 patch; ++ u8 build; ++} __attribute__((packed)); ++ ++struct mib_mdomain { ++ u8 tx_powerlevel[14]; ++ u8 channel_list[14]; /* 0 for invalid channels */ ++} __attribute__((packed)); ++ ++struct at76_fw_header { ++ __le32 crc; /* CRC32 of the whole image */ ++ __le32 board_type; /* firmware compatibility code */ ++ u8 build; /* firmware build number */ ++ u8 patch; /* firmware patch level */ ++ u8 minor; /* firmware minor version */ ++ u8 major; /* firmware major version */ ++ __le32 str_offset; /* offset of the copyright string */ ++ __le32 int_fw_offset; /* internal firmware image offset */ ++ __le32 int_fw_len; /* internal firmware image length */ ++ __le32 ext_fw_offset; /* external firmware image offset */ ++ __le32 ext_fw_len; /* external firmware image length */ ++} __attribute__((packed)); ++ ++enum mac_state { ++ MAC_INIT, ++ MAC_SCANNING, ++ MAC_AUTH, ++ MAC_ASSOC, ++ MAC_JOINING, ++ MAC_CONNECTED, ++ MAC_OWN_IBSS ++}; ++ ++/* a description of a regulatory domain and the allowed channels */ ++struct reg_domain { ++ u16 code; ++ char const *name; ++ u32 channel_map; /* if bit N is set, channel (N+1) is allowed */ ++}; ++ ++/* how long do we keep a (I)BSS in the bss_list in jiffies ++ this should be long enough for the user to retrieve the table ++ (by iwlist ?) after the device started, because all entries from ++ other channels than the one the device locks on get removed, too */ ++#define BSS_LIST_TIMEOUT (120 * HZ) ++/* struct to store BSS info found during scan */ ++#define BSS_LIST_MAX_RATE_LEN 32 /* 32 rates should be enough ... */ ++ ++struct bss_info { ++ struct list_head list; ++ ++ u8 bssid[ETH_ALEN]; /* bssid */ ++ u8 ssid[IW_ESSID_MAX_SIZE]; /* essid */ ++ u8 ssid_len; /* length of ssid above */ ++ u8 channel; ++ u16 capa; /* BSS capabilities */ ++ u16 beacon_interval; /* beacon interval, Kus (1024 microseconds) */ ++ u8 rates[BSS_LIST_MAX_RATE_LEN]; /* supported rates in units of ++ 500 kbps, ORed with 0x80 for ++ basic rates */ ++ u8 rates_len; ++ ++ /* quality of received beacon */ ++ u8 rssi; ++ u8 link_qual; ++ u8 noise_level; ++ ++ unsigned long last_rx; /* time (jiffies) of last beacon received */ ++}; ++ ++/* a rx data buffer to collect rx fragments */ ++struct rx_data_buf { ++ u8 sender[ETH_ALEN]; /* sender address */ ++ u16 seqnr; /* sequence number */ ++ u16 fragnr; /* last fragment received */ ++ unsigned long last_rx; /* jiffies of last rx */ ++ struct sk_buff *skb; /* == NULL if entry is free */ ++}; ++ ++#define NR_RX_DATA_BUF 8 ++ ++/* Data for one loaded firmware file */ ++struct fwentry { ++ const char *const fwname; ++ const struct firmware *fw; ++ int extfw_size; ++ int intfw_size; ++ /* pointer to loaded firmware, no need to free */ ++ u8 *extfw; /* external firmware, extfw_size bytes long */ ++ u8 *intfw; /* internal firmware, intfw_size bytes long */ ++ enum board_type board_type; /* board type */ ++ struct mib_fw_version fw_version; ++ int loaded; /* Loaded and parsed successfully */ ++}; ++ ++struct at76_priv { ++ struct usb_device *udev; /* USB device pointer */ ++ struct net_device *netdev; /* net device pointer */ ++ struct net_device_stats stats; /* net device stats */ ++ struct iw_statistics wstats; /* wireless stats */ ++ ++ struct sk_buff *rx_skb; /* skbuff for receiving data */ ++ void *bulk_out_buffer; /* buffer for sending data */ ++ ++ struct urb *tx_urb; /* URB for sending data */ ++ struct urb *rx_urb; /* URB for receiving data */ ++ ++ unsigned int tx_pipe; /* bulk out pipe */ ++ unsigned int rx_pipe; /* bulk in pipe */ ++ ++ struct mutex mtx; /* locks this structure */ ++ ++ /* work queues */ ++ struct work_struct work_assoc_done; ++ struct work_struct work_join; ++ struct work_struct work_new_bss; ++ struct work_struct work_start_scan; ++ struct work_struct work_set_promisc; ++ struct work_struct work_submit_rx; ++ struct delayed_work dwork_restart; ++ struct delayed_work dwork_get_scan; ++ struct delayed_work dwork_beacon; ++ struct delayed_work dwork_auth; ++ struct delayed_work dwork_assoc; ++ ++ struct tasklet_struct rx_tasklet; ++ ++ /* the WEP stuff */ ++ int wep_enabled; /* 1 if WEP is enabled */ ++ int wep_key_id; /* key id to be used */ ++ u8 wep_keys[WEP_KEYS][WEP_KEY_LEN]; /* the four WEP keys, ++ 5 or 13 bytes are used */ ++ u8 wep_keys_len[WEP_KEYS]; /* the length of the above keys */ ++ ++ int channel; ++ int iw_mode; ++ u8 bssid[ETH_ALEN]; ++ u8 essid[IW_ESSID_MAX_SIZE]; ++ int essid_size; ++ int radio_on; ++ int promisc; ++ ++ int preamble_type; /* 0 - long, 1 - short, 2 - auto */ ++ int auth_mode; /* authentication type: 0 open, 1 shared key */ ++ int txrate; /* 0,1,2,3 = 1,2,5.5,11 Mbps, 4 is auto */ ++ int frag_threshold; /* threshold for fragmentation of tx packets */ ++ int rts_threshold; /* threshold for RTS mechanism */ ++ int short_retry_limit; ++ ++ int scan_min_time; /* scan min channel time */ ++ int scan_max_time; /* scan max channel time */ ++ int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */ ++ int scan_need_any; /* if set, need to scan for any ESSID */ ++ ++ /* the list we got from scanning */ ++ spinlock_t bss_list_spinlock; /* protects bss_list operations */ ++ struct list_head bss_list; /* list of BSS we got beacons from */ ++ struct timer_list bss_list_timer; /* timer to purge old entries ++ from bss_list */ ++ struct bss_info *curr_bss; /* current BSS */ ++ u16 assoc_id; /* current association ID, if associated */ ++ ++ u8 wanted_bssid[ETH_ALEN]; ++ int wanted_bssid_valid; /* != 0 if wanted_bssid is to be used */ ++ ++ /* some data for infrastructure mode only */ ++ spinlock_t mgmt_spinlock; /* this spinlock protects access to ++ next_mgmt_bulk */ ++ ++ struct at76_tx_buffer *next_mgmt_bulk; /* pending management msg to ++ send via bulk out */ ++ enum mac_state mac_state; ++ enum { ++ SCAN_IDLE, ++ SCAN_IN_PROGRESS, ++ SCAN_COMPLETED ++ } scan_state; ++ time_t last_scan; ++ ++ int retries; /* remaining retries in case of timeout when ++ * sending AuthReq or AssocReq */ ++ u8 pm_mode; /* power management mode */ ++ u32 pm_period; /* power management period in microseconds */ ++ ++ struct reg_domain const *domain; /* reg domain description */ ++ ++ /* iwspy support */ ++ spinlock_t spy_spinlock; ++ struct iw_spy_data spy_data; ++ ++ struct iw_public_data wireless_data; ++ ++ /* These fields contain HW config provided by the device (not all of ++ * these fields are used by all board types) */ ++ u8 mac_addr[ETH_ALEN]; ++ u8 regulatory_domain; ++ ++ struct at76_card_config card_config; ++ ++ /* store rx fragments until complete */ ++ struct rx_data_buf rx_data[NR_RX_DATA_BUF]; ++ ++ enum board_type board_type; ++ struct mib_fw_version fw_version; ++ ++ unsigned int device_unplugged:1; ++ unsigned int netdev_registered:1; ++ struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */ ++ ++ /* beacon counting */ ++ int beacon_period; /* period of mgmt beacons, Kus */ ++ int beacons_received; ++ unsigned long beacons_last_qual; /* time we restarted counting ++ beacons */ ++}; ++ ++struct at76_rx_radiotap { ++ struct ieee80211_radiotap_header rt_hdr; ++ __le64 rt_tsft; ++ u8 rt_flags; ++ u8 rt_rate; ++ s8 rt_signal; ++ s8 rt_noise; ++}; ++ ++#define AT76_RX_RADIOTAP_PRESENT \ ++ ((1 << IEEE80211_RADIOTAP_TSFT) | \ ++ (1 << IEEE80211_RADIOTAP_FLAGS) | \ ++ (1 << IEEE80211_RADIOTAP_RATE) | \ ++ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \ ++ (1 << IEEE80211_RADIOTAP_DB_ANTNOISE)) ++ ++#define BEACON_MAX_DATA_LENGTH 1500 ++ ++/* the maximum size of an AssocReq packet */ ++#define ASSOCREQ_MAX_SIZE \ ++ (AT76_TX_HDRLEN + sizeof(struct ieee80211_assoc_request) + \ ++ 1 + 1 + IW_ESSID_MAX_SIZE + 1 + 1 + 4) ++ ++/* for shared secret auth, add the challenge text size */ ++#define AUTH_FRAME_SIZE (AT76_TX_HDRLEN + sizeof(struct ieee80211_auth)) ++ ++/* Maximal number of AuthReq retries */ ++#define AUTH_RETRIES 3 ++ ++/* Maximal number of AssocReq retries */ ++#define ASSOC_RETRIES 3 ++ ++/* Beacon timeout in managed mode when we are connected */ ++#define BEACON_TIMEOUT (10 * HZ) ++ ++/* Timeout for authentication response */ ++#define AUTH_TIMEOUT (1 * HZ) ++ ++/* Timeout for association response */ ++#define ASSOC_TIMEOUT (1 * HZ) ++ ++/* Polling interval when scan is running */ ++#define SCAN_POLL_INTERVAL (HZ / 4) ++ ++/* Command completion timeout */ ++#define CMD_COMPLETION_TIMEOUT (5 * HZ) ++ ++#define DEF_RTS_THRESHOLD 1536 ++#define DEF_FRAG_THRESHOLD 1536 ++#define DEF_SHORT_RETRY_LIMIT 8 ++#define DEF_CHANNEL 10 ++#define DEF_SCAN_MIN_TIME 10 ++#define DEF_SCAN_MAX_TIME 120 ++ ++#define MAX_RTS_THRESHOLD (MAX_FRAG_THRESHOLD + 1) ++ ++/* the max padding size for tx in bytes (see calc_padding) */ ++#define MAX_PADDING_SIZE 53 ++ ++#endif /* _AT76_USB_H */ +--- /dev/null ++++ b/drivers/staging/at76_usb/Kconfig +@@ -0,0 +1,8 @@ ++config USB_ATMEL ++ tristate "Atmel at76c503/at76c505/at76c505a USB cards" ++ depends on WLAN_80211 && USB ++ default N ++ select FW_LOADER ++ ---help--- ++ Enable support for USB Wireless devices using Atmel at76c503, ++ at76c505 or at76c505a chips. +--- /dev/null ++++ b/drivers/staging/at76_usb/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_USB_ATMEL) += at76_usb.o +--- /dev/null ++++ b/drivers/staging/at76_usb/TODO +@@ -0,0 +1,2 @@ ++rewrite the driver to use the proper in-kernel wireless stack ++instead of using its own. +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -41,4 +41,6 @@ source "drivers/staging/wlan-ng/Kconfig" + + source "drivers/staging/echo/Kconfig" + ++source "drivers/staging/at76_usb/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -12,3 +12,4 @@ obj-$(CONFIG_USB_IP_COMMON) += usbip/ + obj-$(CONFIG_W35UND) += winbond/ + obj-$(CONFIG_PRISM2_USB) += wlan-ng/ + obj-$(CONFIG_ECHO) += echo/ ++obj-$(CONFIG_USB_ATMEL) += at76_usb/ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-a-todo-file.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-a-todo-file.patch new file mode 100644 index 000000000..6234eff10 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-a-todo-file.patch @@ -0,0 +1,35 @@ +From foo@baz Wed Jul 15 10:21:36 PDT 2009 +Date: Wed, 15 Jul 2009 10:21:36 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: add a TODO file + +From: Greg Kroah-Hartman + +First cut at what needs to be done to this codebase. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/TODO | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- /dev/null ++++ b/drivers/staging/hv/TODO +@@ -0,0 +1,15 @@ ++TODO: ++ - fix checkpatch warnings/errors ++ - fix sparse issues ++ - remove compatibility layer ++ - fix HANDLE usage to be "real" pointers ++ - audit the vmbus to verify it is working properly with the ++ driver model ++ - see if the vmbus can be merged with the other virtual busses ++ in the kernel ++ - audit the network driver ++ - audit the block driver ++ - audit the scsi driver ++ ++Please send patches for this code to Greg Kroah-Hartman ++and Hank Janssen diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-api-header-files.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-api-header-files.patch new file mode 100644 index 000000000..e0581bb8d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-api-header-files.patch @@ -0,0 +1,4039 @@ +From 50626ba62379de1e1c92abe1e630138bfd096fd0 Mon Sep 17 00:00:00 2001 +From: Hank Janssen +Date: Mon, 13 Jul 2009 15:15:47 -0700 +Subject: Staging: hv: add the Hyper-V api header files + +From: Hank Janssen + +These are the header files for the API to talk to the Hyper-V +core. + +Signed-off-by: Hank Janssen +Signed-off-by: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/hv/include/ChannelMessages.h | 312 +++++++ + drivers/staging/hv/include/HvHalApi.h | 32 + drivers/staging/hv/include/HvHcApi.h | 60 + + drivers/staging/hv/include/HvPtApi.h | 86 ++ + drivers/staging/hv/include/HvStatus.h | 718 ++++++++++++++++++ + drivers/staging/hv/include/HvSynicApi.h | 490 ++++++++++++ + drivers/staging/hv/include/HvTypes.h | 31 + drivers/staging/hv/include/HvVpApi.h | 51 + + drivers/staging/hv/include/List.h | 269 ++++++ + drivers/staging/hv/include/VmbusChannelInterface.h | 131 +++ + drivers/staging/hv/include/VmbusPacketFormat.h | 322 ++++++++ + drivers/staging/hv/include/nvspprotocol.h | 306 +++++++ + drivers/staging/hv/include/rndis.h | 836 +++++++++++++++++++++ + drivers/staging/hv/include/vstorage.h | 309 +++++++ + 14 files changed, 3953 insertions(+) + create mode 100644 drivers/staging/hv/include/ChannelMessages.h + create mode 100644 drivers/staging/hv/include/HvHalApi.h + create mode 100644 drivers/staging/hv/include/HvHcApi.h + create mode 100644 drivers/staging/hv/include/HvPtApi.h + create mode 100644 drivers/staging/hv/include/HvStatus.h + create mode 100644 drivers/staging/hv/include/HvSynicApi.h + create mode 100644 drivers/staging/hv/include/HvTypes.h + create mode 100644 drivers/staging/hv/include/HvVpApi.h + create mode 100644 drivers/staging/hv/include/List.h + create mode 100644 drivers/staging/hv/include/VmbusChannelInterface.h + create mode 100644 drivers/staging/hv/include/VmbusPacketFormat.h + create mode 100644 drivers/staging/hv/include/nvspprotocol.h + create mode 100644 drivers/staging/hv/include/rndis.h + create mode 100644 drivers/staging/hv/include/vstorage.h + +--- /dev/null ++++ b/drivers/staging/hv/include/ChannelMessages.h +@@ -0,0 +1,312 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++#include ++ ++#define C_ASSERT(x) ++typedef UINT32 NTSTATUS; ++ ++#pragma pack(push,1) ++ ++// ++// Version 1 messages ++// ++ ++typedef enum _VMBUS_CHANNEL_MESSAGE_TYPE ++{ ++ ChannelMessageInvalid = 0, ++ ChannelMessageOfferChannel = 1, ++ ChannelMessageRescindChannelOffer = 2, ++ ChannelMessageRequestOffers = 3, ++ ChannelMessageAllOffersDelivered = 4, ++ ChannelMessageOpenChannel = 5, ++ ChannelMessageOpenChannelResult = 6, ++ ChannelMessageCloseChannel = 7, ++ ChannelMessageGpadlHeader = 8, ++ ChannelMessageGpadlBody = 9, ++ ChannelMessageGpadlCreated = 10, ++ ChannelMessageGpadlTeardown = 11, ++ ChannelMessageGpadlTorndown = 12, ++ ChannelMessageRelIdReleased = 13, ++ ChannelMessageInitiateContact = 14, ++ ChannelMessageVersionResponse = 15, ++ ChannelMessageUnload = 16, ++#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD ++ ChannelMessageViewRangeAdd = 17, ++ ChannelMessageViewRangeRemove = 18, ++#endif ++ ChannelMessageCount ++} VMBUS_CHANNEL_MESSAGE_TYPE, *PVMBUS_CHANNEL_MESSAGE_TYPE; ++ ++// begin_wpp config ++// CUSTOM_TYPE(ChannelMessageType, ItemEnum(_VMBUS_CHANNEL_MESSAGE_TYPE)); ++// end_wpp ++ ++typedef struct _VMBUS_CHANNEL_MESSAGE_HEADER ++{ ++ VMBUS_CHANNEL_MESSAGE_TYPE MessageType; ++ UINT32 Padding; ++} VMBUS_CHANNEL_MESSAGE_HEADER, *PVMBUS_CHANNEL_MESSAGE_HEADER; ++ ++// Query VMBus Version parameters ++typedef struct _VMBUS_CHANNEL_QUERY_VMBUS_VERSION ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 Version; ++} VMBUS_CHANNEL_QUERY_VMBUS_VERSION, *PVMBUS_CHANNEL_QUERY_VMBUS_VERSION; ++ ++// VMBus Version Supported parameters ++typedef struct _VMBUS_CHANNEL_VERSION_SUPPORTED ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ BOOLEAN VersionSupported; ++} VMBUS_CHANNEL_VERSION_SUPPORTED, *PVMBUS_CHANNEL_VERSION_SUPPORTED; ++ ++// Offer Channel parameters ++typedef struct _VMBUS_CHANNEL_OFFER_CHANNEL ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ VMBUS_CHANNEL_OFFER Offer; ++ UINT32 ChildRelId; ++ UINT8 MonitorId; ++ BOOLEAN MonitorAllocated; ++} VMBUS_CHANNEL_OFFER_CHANNEL, *PVMBUS_CHANNEL_OFFER_CHANNEL; ++ ++// ++// Make sure VMBUS_CHANNEL_OFFER_CHANNEL fits into Synic message. ++// ++C_ASSERT(sizeof(VMBUS_CHANNEL_OFFER_CHANNEL) <= MAXIMUM_SYNIC_MESSAGE_BYTES); ++ ++// Rescind Offer parameters ++typedef struct _VMBUS_CHANNEL_RESCIND_OFFER ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++} VMBUS_CHANNEL_RESCIND_OFFER, *PVMBUS_CHANNEL_RESCIND_OFFER; ++ ++// Request Offer -- no parameters, SynIC message contains the partition ID ++// Set Snoop -- no parameters, SynIC message contains the partition ID ++// Clear Snoop -- no parameters, SynIC message contains the partition ID ++// All Offers Delivered -- no parameters, SynIC message contains the partition ID ++// Flush Client -- no parameters, SynIC message contains the partition ID ++ ++// Open Channel parameters ++typedef struct _VMBUS_CHANNEL_OPEN_CHANNEL ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ ++ // ++ // Identifies the specific VMBus channel that is being opened. ++ // ++ UINT32 ChildRelId; ++ ++ // ++ // ID making a particular open request at a channel offer unique. ++ // ++ UINT32 OpenId; ++ ++ // ++ // GPADL for the channel's ring buffer. ++ // ++ GPADL_HANDLE RingBufferGpadlHandle; ++ ++ // ++ // GPADL for the channel's server context save area. ++ // ++ GPADL_HANDLE ServerContextAreaGpadlHandle; ++ ++ // ++ // The upstream ring buffer begins at offset zero in the memory described ++ // by RingBufferGpadlHandle. The downstream ring buffer follows it at this ++ // offset (in pages). ++ // ++ UINT32 DownstreamRingBufferPageOffset; ++ ++ // ++ // User-specific data to be passed along to the server endpoint. ++ // ++ UCHAR UserData[MAX_USER_DEFINED_BYTES]; ++ ++} VMBUS_CHANNEL_OPEN_CHANNEL, *PVMBUS_CHANNEL_OPEN_CHANNEL; ++ ++// Reopen Channel parameters; ++typedef VMBUS_CHANNEL_OPEN_CHANNEL VMBUS_CHANNEL_REOPEN_CHANNEL, *PVMBUS_CHANNEL_REOPEN_CHANNEL; ++ ++// Open Channel Result parameters ++typedef struct _VMBUS_CHANNEL_OPEN_RESULT ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++ UINT32 OpenId; ++ NTSTATUS Status; ++} VMBUS_CHANNEL_OPEN_RESULT, *PVMBUS_CHANNEL_OPEN_RESULT; ++ ++// Close channel parameters; ++typedef struct _VMBUS_CHANNEL_CLOSE_CHANNEL ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++} VMBUS_CHANNEL_CLOSE_CHANNEL, *PVMBUS_CHANNEL_CLOSE_CHANNEL; ++ ++// Channel Message GPADL ++#define GPADL_TYPE_RING_BUFFER 1 ++#define GPADL_TYPE_SERVER_SAVE_AREA 2 ++#define GPADL_TYPE_TRANSACTION 8 ++ ++// ++// The number of PFNs in a GPADL message is defined by the number of pages ++// that would be spanned by ByteCount and ByteOffset. If the implied number ++// of PFNs won't fit in this packet, there will be a follow-up packet that ++// contains more. ++// ++ ++typedef struct _VMBUS_CHANNEL_GPADL_HEADER ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++ UINT32 Gpadl; ++ UINT16 RangeBufLen; ++ UINT16 RangeCount; ++ GPA_RANGE Range[0]; ++} VMBUS_CHANNEL_GPADL_HEADER, *PVMBUS_CHANNEL_GPADL_HEADER; ++ ++ ++// ++// This is the followup packet that contains more PFNs. ++// ++ ++typedef struct _VMBUS_CHANNEL_GPADL_BODY ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 MessageNumber; ++ UINT32 Gpadl; ++ UINT64 Pfn[0]; ++} VMBUS_CHANNEL_GPADL_BODY, *PVMBUS_CHANNEL_GPADL_BODY; ++ ++ ++typedef struct _VMBUS_CHANNEL_GPADL_CREATED ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++ UINT32 Gpadl; ++ UINT32 CreationStatus; ++} VMBUS_CHANNEL_GPADL_CREATED, *PVMBUS_CHANNEL_GPADL_CREATED; ++ ++typedef struct _VMBUS_CHANNEL_GPADL_TEARDOWN ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++ UINT32 Gpadl; ++} VMBUS_CHANNEL_GPADL_TEARDOWN, *PVMBUS_CHANNEL_GPADL_TEARDOWN; ++ ++typedef struct _VMBUS_CHANNEL_GPADL_TORNDOWN ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 Gpadl; ++} VMBUS_CHANNEL_GPADL_TORNDOWN, *PVMBUS_CHANNEL_GPADL_TORNDOWN; ++ ++#ifdef VMBUS_FEATURE_PARENT_OR_PEER_MEMORY_MAPPED_INTO_A_CHILD ++typedef struct _VMBUS_CHANNEL_VIEW_RANGE_ADD ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ PHYSICAL_ADDRESS ViewRangeBase; ++ UINT64 ViewRangeLength; ++ UINT32 ChildRelId; ++} VMBUS_CHANNEL_VIEW_RANGE_ADD, *PVMBUS_CHANNEL_VIEW_RANGE_ADD; ++ ++typedef struct _VMBUS_CHANNEL_VIEW_RANGE_REMOVE ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ PHYSICAL_ADDRESS ViewRangeBase; ++ UINT32 ChildRelId; ++} VMBUS_CHANNEL_VIEW_RANGE_REMOVE, *PVMBUS_CHANNEL_VIEW_RANGE_REMOVE; ++#endif ++ ++typedef struct _VMBUS_CHANNEL_RELID_RELEASED ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 ChildRelId; ++} VMBUS_CHANNEL_RELID_RELEASED, *PVMBUS_CHANNEL_RELID_RELEASED; ++ ++typedef struct _VMBUS_CHANNEL_INITIATE_CONTACT ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ UINT32 VMBusVersionRequested; ++ UINT32 Padding2; ++ UINT64 InterruptPage; ++ UINT64 MonitorPage1; ++ UINT64 MonitorPage2; ++} VMBUS_CHANNEL_INITIATE_CONTACT, *PVMBUS_CHANNEL_INITIATE_CONTACT; ++ ++typedef struct _VMBUS_CHANNEL_VERSION_RESPONSE ++{ ++ VMBUS_CHANNEL_MESSAGE_HEADER Header; ++ BOOLEAN VersionSupported; ++} VMBUS_CHANNEL_VERSION_RESPONSE, *PVMBUS_CHANNEL_VERSION_RESPONSE; ++ ++typedef VMBUS_CHANNEL_MESSAGE_HEADER VMBUS_CHANNEL_UNLOAD, *PVMBUS_CHANNEL_UNLOAD; ++ ++// ++// Kind of a table to use the preprocessor to get us the right type for a ++// specified message ID. Used with ChAllocateSendMessage() ++// ++#define ChannelMessageQueryVmbusVersion_TYPE VMBUS_CHANNEL_MESSAGE_HEADER ++#define ChannelMessageVmbusVersionSupported_TYPE VMBUS_CHANNEL_VERSION_SUPPORTED ++#define ChannelMessageOfferChannel_TYPE VMBUS_CHANNEL_OFFER_CHANNEL ++#define ChannelMessageRescindChannelOffer_TYPE VMBUS_CHANNEL_RESCIND_OFFER ++#define ChannelMessageRequestOffers_TYPE VMBUS_CHANNEL_MESSAGE_HEADER ++#define ChannelMessageAllOffersDelivered_TYPE VMBUS_CHANNEL_MESSAGE_HEADER ++#define ChannelMessageOpenChannel_TYPE VMBUS_CHANNEL_OPEN_CHANNEL ++#define ChannelMessageOpenChannelResult_TYPE VMBUS_CHANNEL_OPEN_RESULT ++#define ChannelMessageCloseChannel_TYPE VMBUS_CHANNEL_CLOSE_CHANNEL ++#define ChannelMessageAllGpadlsUnmapped_TYPE VMBUS_CHANNEL_CLOSE_CHANNEL ++#define ChannelMessageGpadlHeader_TYPE VMBUS_CHANNEL_GPADL_HEADER ++#define ChannelMessageGpadlBody_TYPE VMBUS_CHANNEL_GPADL_BODY ++#define ChannelMessageGpadlCreated_TYPE VMBUS_CHANNEL_GPADL_CREATED ++#define ChannelMessageGpadlTeardown_TYPE VMBUS_CHANNEL_GPADL_TEARDOWN ++#define ChannelMessageGpadlTorndown_TYPE VMBUS_CHANNEL_GPADL_TORNDOWN ++#define ChannelMessageViewRangeAdd_TYPE VMBUS_CHANNEL_VIEW_RANGE_ADD ++#define ChannelMessageViewRangeRemove_TYPE VMBUS_CHANNEL_VIEW_RANGE_REMOVE ++#define ChannelMessageRelIdReleased_TYPE VMBUS_CHANNEL_RELID_RELEASED ++#define ChannelMessageInitiateContact_TYPE VMBUS_CHANNEL_INITIATE_CONTACT ++#define ChannelMessageVersionResponse_TYPE VMBUS_CHANNEL_VERSION_RESPONSE ++#define ChannelMessageUnload_TYPE VMBUS_CHANNEL_UNLOAD ++ ++// ++// Preprocessor wrapper to ChAllocateSendMessageSize() converting the return ++// value to the correct pointer and calculate the needed size. ++// ++// Argument: ++// ++// Id - the numberic ID (type VMBUS_CHANNEL_MESSAGE_TYPE) of the message to ++// send. ++// ++#define ChAllocateSendMessage(Id, Fn, Context) \ ++ (Id##_TYPE*)ChAllocateSendMessageSized(sizeof(Id##_TYPE), Id, Fn, Context) ++ ++ ++#pragma pack(pop) ++ +--- /dev/null ++++ b/drivers/staging/hv/include/HvHalApi.h +@@ -0,0 +1,32 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++ ++// ++// Time in the hypervisor is measured in 100 nanosecond units ++// ++typedef UINT64 HV_NANO100_TIME, *PHV_NANO100_TIME; ++typedef UINT64 HV_NANO100_DURATION, *PHV_NANO100_DURATION; +--- /dev/null ++++ b/drivers/staging/hv/include/HvHcApi.h +@@ -0,0 +1,60 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++// ++// Declare the various hypercall operations. ++// ++typedef enum _HV_CALL_CODE ++{ ++ ++ HvCallPostMessage = 0x005c, ++ HvCallSignalEvent = 0x005d, ++ ++} HV_CALL_CODE, *PHV_CALL_CODE; ++// ++// Definition of the HvPostMessage hypercall input structure. ++// ++ ++typedef struct _HV_INPUT_POST_MESSAGE ++{ ++ HV_CONNECTION_ID ConnectionId; ++ UINT32 Reserved; ++ HV_MESSAGE_TYPE MessageType; ++ UINT32 PayloadSize; ++ UINT64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; ++} HV_INPUT_POST_MESSAGE, *PHV_INPUT_POST_MESSAGE; ++ ++ ++// ++// Definition of the HvSignalEvent hypercall input structure. ++// ++ ++typedef struct _HV_INPUT_SIGNAL_EVENT ++{ ++ HV_CONNECTION_ID ConnectionId; ++ UINT16 FlagNumber; ++ UINT16 RsvdZ; ++} HV_INPUT_SIGNAL_EVENT, *PHV_INPUT_SIGNAL_EVENT; +--- /dev/null ++++ b/drivers/staging/hv/include/HvPtApi.h +@@ -0,0 +1,86 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++// ++// Versioning definitions used for guests reporting themselves to the ++// hypervisor, and visa versa. ++// ================================================================== ++// ++ ++// ++// Version info reported by guest OS's ++// ++typedef enum _HV_GUEST_OS_VENDOR ++{ ++ HvGuestOsVendorMicrosoft = 0x0001 ++ ++} HV_GUEST_OS_VENDOR, *PHV_GUEST_OS_VENDOR; ++ ++typedef enum _HV_GUEST_OS_MICROSOFT_IDS ++{ ++ HvGuestOsMicrosoftUndefined = 0x00, ++ HvGuestOsMicrosoftMSDOS = 0x01, ++ HvGuestOsMicrosoftWindows3x = 0x02, ++ HvGuestOsMicrosoftWindows9x = 0x03, ++ HvGuestOsMicrosoftWindowsNT = 0x04, ++ HvGuestOsMicrosoftWindowsCE = 0x05 ++ ++} HV_GUEST_OS_MICROSOFT_IDS, *PHV_GUEST_OS_MICROSOFT_IDS; ++ ++// ++// Declare the MSR used to identify the guest OS. ++// ++#define HV_X64_MSR_GUEST_OS_ID 0x40000000 ++ ++typedef union _HV_X64_MSR_GUEST_OS_ID_CONTENTS ++{ ++ UINT64 AsUINT64; ++ struct ++ { ++ UINT64 BuildNumber : 16; ++ UINT64 ServiceVersion : 8; // Service Pack, etc. ++ UINT64 MinorVersion : 8; ++ UINT64 MajorVersion : 8; ++ UINT64 OsId : 8; // HV_GUEST_OS_MICROSOFT_IDS (If Vendor=MS) ++ UINT64 VendorId : 16; // HV_GUEST_OS_VENDOR ++ }; ++} HV_X64_MSR_GUEST_OS_ID_CONTENTS, *PHV_X64_MSR_GUEST_OS_ID_CONTENTS; ++ ++// ++// Declare the MSR used to setup pages used to communicate with the hypervisor. ++// ++#define HV_X64_MSR_HYPERCALL 0x40000001 ++ ++typedef union _HV_X64_MSR_HYPERCALL_CONTENTS ++{ ++ UINT64 AsUINT64; ++ struct ++ { ++ UINT64 Enable : 1; ++ UINT64 Reserved : 11; ++ UINT64 GuestPhysicalAddress : 52; ++ }; ++} HV_X64_MSR_HYPERCALL_CONTENTS, *PHV_X64_MSR_HYPERCALL_CONTENTS; +--- /dev/null ++++ b/drivers/staging/hv/include/HvStatus.h +@@ -0,0 +1,718 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++// begin_hvgdk ++// ++// Status codes for hypervisor operations. ++// ++typedef UINT16 HV_STATUS, *PHV_STATUS; ++ ++// ++// MessageId: HV_STATUS_SUCCESS ++// ++// MessageText: ++// ++// The specified hypercall succeeded ++// ++#define HV_STATUS_SUCCESS ((HV_STATUS)0x0000) ++ ++// ++// MessageId: HV_STATUS_INVALID_HYPERCALL_CODE ++// ++// MessageText: ++// ++// The hypervisor does not support the operation because the specified hypercall code is not supported. ++// ++#define HV_STATUS_INVALID_HYPERCALL_CODE ((HV_STATUS)0x0002) ++ ++// ++// MessageId: HV_STATUS_INVALID_HYPERCALL_INPUT ++// ++// MessageText: ++// ++// The hypervisor does not support the operation because the encoding for the hypercall input register is not supported. ++// ++#define HV_STATUS_INVALID_HYPERCALL_INPUT ((HV_STATUS)0x0003) ++ ++// ++// MessageId: HV_STATUS_INVALID_ALIGNMENT ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation beacuse a parameter has an invalid alignment. ++// ++#define HV_STATUS_INVALID_ALIGNMENT ((HV_STATUS)0x0004) ++ ++// ++// MessageId: HV_STATUS_INVALID_PARAMETER ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation beacuse an invalid parameter was specified. ++// ++#define HV_STATUS_INVALID_PARAMETER ((HV_STATUS)0x0005) ++ ++// ++// MessageId: HV_STATUS_ACCESS_DENIED ++// ++// MessageText: ++// ++// Access to the specified object was denied. ++// ++#define HV_STATUS_ACCESS_DENIED ((HV_STATUS)0x0006) ++ ++// ++// MessageId: HV_STATUS_INVALID_PARTITION_STATE ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation because the partition is entering or in an invalid state. ++// ++#define HV_STATUS_INVALID_PARTITION_STATE ((HV_STATUS)0x0007) ++ ++// ++// MessageId: HV_STATUS_OPERATION_DENIED ++// ++// MessageText: ++// ++// The operation is not allowed in the current state. ++// ++#define HV_STATUS_OPERATION_DENIED ((HV_STATUS)0x0008) ++ ++// ++// MessageId: HV_STATUS_UNKNOWN_PROPERTY ++// ++// MessageText: ++// ++// The hypervisor does not recognize the specified partition property. ++// ++#define HV_STATUS_UNKNOWN_PROPERTY ((HV_STATUS)0x0009) ++ ++// ++// MessageId: HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE ++// ++// MessageText: ++// ++// The specified value of a partition property is out of range or violates an invariant. ++// ++#define HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE ((HV_STATUS)0x000A) ++ ++// ++// MessageId: HV_STATUS_INSUFFICIENT_MEMORY ++// ++// MessageText: ++// ++// There is not enough memory in the hypervisor pool to complete the operation. ++// ++#define HV_STATUS_INSUFFICIENT_MEMORY ((HV_STATUS)0x000B) ++ ++// ++// MessageId: HV_STATUS_PARTITION_TOO_DEEP ++// ++// MessageText: ++// ++// The maximum partition depth has been exceeded for the partition hierarchy. ++// ++#define HV_STATUS_PARTITION_TOO_DEEP ((HV_STATUS)0x000C) ++ ++// ++// MessageId: HV_STATUS_INVALID_PARTITION_ID ++// ++// MessageText: ++// ++// A partition with the specified partition Id does not exist. ++// ++#define HV_STATUS_INVALID_PARTITION_ID ((HV_STATUS)0x000D) ++ ++// ++// MessageId: HV_STATUS_INVALID_VP_INDEX ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation because the specified VP index is invalid. ++// ++#define HV_STATUS_INVALID_VP_INDEX ((HV_STATUS)0x000E) ++ ++// ++// MessageId: HV_STATUS_NOT_FOUND ++// ++// MessageText: ++// ++// The iteration is complete; no addition items in the iteration could be found. ++// ++#define HV_STATUS_NOT_FOUND ((HV_STATUS)0x0010) ++ ++// ++// MessageId: HV_STATUS_INVALID_PORT_ID ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation because the specified port identifier is invalid. ++// ++#define HV_STATUS_INVALID_PORT_ID ((HV_STATUS)0x0011) ++ ++// ++// MessageId: HV_STATUS_INVALID_CONNECTION_ID ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation because the specified connection identifier is invalid. ++// ++#define HV_STATUS_INVALID_CONNECTION_ID ((HV_STATUS)0x0012) ++ ++// ++// MessageId: HV_STATUS_INSUFFICIENT_BUFFERS ++// ++// MessageText: ++// ++// You did not supply enough message buffers to send a message. ++// ++#define HV_STATUS_INSUFFICIENT_BUFFERS ((HV_STATUS)0x0013) ++ ++// ++// MessageId: HV_STATUS_NOT_ACKNOWLEDGED ++// ++// MessageText: ++// ++// The previous virtual interrupt has not been acknowledged. ++// ++#define HV_STATUS_NOT_ACKNOWLEDGED ((HV_STATUS)0x0014) ++ ++// ++// MessageId: HV_STATUS_INVALID_VP_STATE ++// ++// MessageText: ++// ++// A virtual processor is not in the correct state for the performance of the indicated operation. ++// ++#define HV_STATUS_INVALID_VP_STATE ((HV_STATUS)0x0015) ++ ++// ++// MessageId: HV_STATUS_ACKNOWLEDGED ++// ++// MessageText: ++// ++// The previous virtual interrupt has already been acknowledged. ++// ++#define HV_STATUS_ACKNOWLEDGED ((HV_STATUS)0x0016) ++ ++// ++// MessageId: HV_STATUS_INVALID_SAVE_RESTORE_STATE ++// ++// MessageText: ++// ++// The indicated partition is not in a valid state for saving or restoring. ++// ++#define HV_STATUS_INVALID_SAVE_RESTORE_STATE ((HV_STATUS)0x0017) ++ ++// ++// MessageId: HV_STATUS_INVALID_SYNIC_STATE ++// ++// MessageText: ++// ++// The hypervisor could not complete the operation because a required feature of the synthetic interrupt controller (SynIC) was disabled. ++// ++#define HV_STATUS_INVALID_SYNIC_STATE ((HV_STATUS)0x0018) ++ ++// ++// MessageId: HV_STATUS_OBJECT_IN_USE ++// ++// MessageText: ++// ++// The hypervisor could not perform the operation because the object or value was either already in use or being used for a purpose that would not permit completing the operation. ++// ++#define HV_STATUS_OBJECT_IN_USE ((HV_STATUS)0x0019) ++ ++// ++// MessageId: HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO ++// ++// MessageText: ++// ++// The proximity domain information is invalid. ++// ++#define HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO ((HV_STATUS)0x001A) ++ ++// ++// MessageId: HV_STATUS_NO_DATA ++// ++// MessageText: ++// ++// An attempt to retrieve debugging data failed because none was available. ++// ++#define HV_STATUS_NO_DATA ((HV_STATUS)0x001B) ++ ++// ++// MessageId: HV_STATUS_INACTIVE ++// ++// MessageText: ++// ++// The physical connection being used for debuggging has not recorded any receive activity since the last operation. ++// ++#define HV_STATUS_INACTIVE ((HV_STATUS)0x001C) ++ ++// ++// MessageId: HV_STATUS_NO_RESOURCES ++// ++// MessageText: ++// ++// There are not enough resources to complete the operation. ++// ++#define HV_STATUS_NO_RESOURCES ((HV_STATUS)0x001D) ++ ++// ++// MessageId: HV_STATUS_FEATURE_UNAVAILABLE ++// ++// MessageText: ++// ++// A hypervisor feature is not available to the user. ++// ++#define HV_STATUS_FEATURE_UNAVAILABLE ((HV_STATUS)0x001E) ++ ++// end_hvgdk ++ ++// ++// MessageId: HV_STATUS_UNSUCCESSFUL ++// ++// MessageText: ++// ++// {Operation Failed} ++// The requested operation was unsuccessful. ++// ++#define HV_STATUS_UNSUCCESSFUL ((HV_STATUS)0x1001) ++ ++// ++// MessageId: HV_STATUS_INSUFFICIENT_BUFFER ++// ++// MessageText: ++// ++// The specified buffer was too small to contain all of the requested data. ++// ++#define HV_STATUS_INSUFFICIENT_BUFFER ((HV_STATUS)0x1002) ++ ++// ++// MessageId: HV_STATUS_GPA_NOT_PRESENT ++// ++// MessageText: ++// ++// The guest physical address is not currently associated with a system physical address. ++// ++#define HV_STATUS_GPA_NOT_PRESENT ((HV_STATUS)0x1003) ++ ++// ++// MessageId: HV_STATUS_GUEST_PAGE_FAULT ++// ++// MessageText: ++// ++// The operation would have resulted in a page fault in the guest. ++// ++#define HV_STATUS_GUEST_PAGE_FAULT ((HV_STATUS)0x1004) ++ ++// ++// MessageId: HV_STATUS_RUNDOWN_DISABLED ++// ++// MessageText: ++// ++// The operation cannot proceed as the rundown object was marked disabled. ++// ++#define HV_STATUS_RUNDOWN_DISABLED ((HV_STATUS)0x1005) ++ ++// ++// MessageId: HV_STATUS_KEY_ALREADY_EXISTS ++// ++// MessageText: ++// ++// The entry cannot be added as another entry with the same key already exists. ++// ++#define HV_STATUS_KEY_ALREADY_EXISTS ((HV_STATUS)0x1006) ++ ++// ++// MessageId: HV_STATUS_GPA_INTERCEPT ++// ++// MessageText: ++// ++// The operation resulted an intercept on a region of guest physical memory. ++// ++#define HV_STATUS_GPA_INTERCEPT ((HV_STATUS)0x1007) ++ ++// ++// MessageId: HV_STATUS_GUEST_GENERAL_PROTECTION_FAULT ++// ++// MessageText: ++// ++// The operation would have resulted in a general protection fault in the guest. ++// ++#define HV_STATUS_GUEST_GENERAL_PROTECTION_FAULT ((HV_STATUS)0x1008) ++ ++// ++// MessageId: HV_STATUS_GUEST_STACK_FAULT ++// ++// MessageText: ++// ++// The operation would have resulted in a stack fault in the guest. ++// ++#define HV_STATUS_GUEST_STACK_FAULT ((HV_STATUS)0x1009) ++ ++// ++// MessageId: HV_STATUS_GUEST_INVALID_OPCODE_FAULT ++// ++// MessageText: ++// ++// The operation would have resulted in an invalid opcode fault in the guest. ++// ++#define HV_STATUS_GUEST_INVALID_OPCODE_FAULT ((HV_STATUS)0x100A) ++ ++// ++// MessageId: HV_STATUS_FINALIZE_INCOMPLETE ++// ++// MessageText: ++// ++// The partition is not completely finalized. ++// ++#define HV_STATUS_FINALIZE_INCOMPLETE ((HV_STATUS)0x100B) ++ ++// ++// MessageId: HV_STATUS_GUEST_MACHINE_CHECK_ABORT ++// ++// MessageText: ++// ++// The operation would have resulted in an machine check abort in the guest. ++// ++#define HV_STATUS_GUEST_MACHINE_CHECK_ABORT ((HV_STATUS)0x100C) ++ ++// ++// MessageId: HV_STATUS_ILLEGAL_OVERLAY_ACCESS ++// ++// MessageText: ++// ++// An illegal access was attempted to an overlay page. ++// ++#define HV_STATUS_ILLEGAL_OVERLAY_ACCESS ((HV_STATUS)0x100D) ++ ++// ++// MessageId: HV_STATUS_INSUFFICIENT_SYSTEM_VA ++// ++// MessageText: ++// ++// There is not enough system VA space available to satisfy the request, ++// ++#define HV_STATUS_INSUFFICIENT_SYSTEM_VA ((HV_STATUS)0x100E) ++ ++// ++// MessageId: HV_STATUS_VIRTUAL_ADDRESS_NOT_MAPPED ++// ++// MessageText: ++// ++// The passed virtual address was not mapped in the hypervisor address space. ++// ++#define HV_STATUS_VIRTUAL_ADDRESS_NOT_MAPPED ((HV_STATUS)0x100F) ++ ++// ++// MessageId: HV_STATUS_NOT_IMPLEMENTED ++// ++// MessageText: ++// ++// The requested operation is not implemented in this version of the hypervisor. ++// ++#define HV_STATUS_NOT_IMPLEMENTED ((HV_STATUS)0x1010) ++ ++// ++// MessageId: HV_STATUS_VMX_INSTRUCTION_FAILED ++// ++// MessageText: ++// ++// The requested VMX instruction failed to complete succesfully. ++// ++#define HV_STATUS_VMX_INSTRUCTION_FAILED ((HV_STATUS)0x1011) ++ ++// ++// MessageId: HV_STATUS_VMX_INSTRUCTION_FAILED_WITH_STATUS ++// ++// MessageText: ++// ++// The requested VMX instruction failed to complete succesfully indicating status. ++// ++#define HV_STATUS_VMX_INSTRUCTION_FAILED_WITH_STATUS ((HV_STATUS)0x1012) ++ ++// ++// MessageId: HV_STATUS_MSR_ACCESS_FAILED ++// ++// MessageText: ++// ++// The requested access to the model specific register failed. ++// ++#define HV_STATUS_MSR_ACCESS_FAILED ((HV_STATUS)0x1013) ++ ++// ++// MessageId: HV_STATUS_CR_ACCESS_FAILED ++// ++// MessageText: ++// ++// The requested access to the control register failed. ++// ++#define HV_STATUS_CR_ACCESS_FAILED ((HV_STATUS)0x1014) ++ ++// ++// MessageId: HV_STATUS_TIMEOUT ++// ++// MessageText: ++// ++// The specified timeout expired before the operation completed. ++// ++#define HV_STATUS_TIMEOUT ((HV_STATUS)0x1016) ++ ++// ++// MessageId: HV_STATUS_MSR_INTERCEPT ++// ++// MessageText: ++// ++// The requested access to the model specific register generated an intercept. ++// ++#define HV_STATUS_MSR_INTERCEPT ((HV_STATUS)0x1017) ++ ++// ++// MessageId: HV_STATUS_CPUID_INTERCEPT ++// ++// MessageText: ++// ++// The CPUID instruction generated an intercept. ++// ++#define HV_STATUS_CPUID_INTERCEPT ((HV_STATUS)0x1018) ++ ++// ++// MessageId: HV_STATUS_REPEAT_INSTRUCTION ++// ++// MessageText: ++// ++// The current instruction should be repeated and the instruction pointer not advanced. ++// ++#define HV_STATUS_REPEAT_INSTRUCTION ((HV_STATUS)0x1019) ++ ++// ++// MessageId: HV_STATUS_PAGE_PROTECTION_VIOLATION ++// ++// MessageText: ++// ++// The current instruction should be repeated and the instruction pointer not advanced. ++// ++#define HV_STATUS_PAGE_PROTECTION_VIOLATION ((HV_STATUS)0x101A) ++ ++// ++// MessageId: HV_STATUS_PAGE_TABLE_INVALID ++// ++// MessageText: ++// ++// The current instruction should be repeated and the instruction pointer not advanced. ++// ++#define HV_STATUS_PAGE_TABLE_INVALID ((HV_STATUS)0x101B) ++ ++// ++// MessageId: HV_STATUS_PAGE_NOT_PRESENT ++// ++// MessageText: ++// ++// The current instruction should be repeated and the instruction pointer not advanced. ++// ++#define HV_STATUS_PAGE_NOT_PRESENT ((HV_STATUS)0x101C) ++ ++// ++// MessageId: HV_STATUS_IO_INTERCEPT ++// ++// MessageText: ++// ++// The requested access to the I/O port generated an intercept. ++// ++#define HV_STATUS_IO_INTERCEPT ((HV_STATUS)0x101D) ++ ++// ++// MessageId: HV_STATUS_NOTHING_TO_DO ++// ++// MessageText: ++// ++// There is nothing to do. ++// ++#define HV_STATUS_NOTHING_TO_DO ((HV_STATUS)0x101E) ++ ++// ++// MessageId: HV_STATUS_THREAD_TERMINATING ++// ++// MessageText: ++// ++// The requested thread is terminating. ++// ++#define HV_STATUS_THREAD_TERMINATING ((HV_STATUS)0x101F) ++ ++// ++// MessageId: HV_STATUS_SECTION_ALREADY_CONSTRUCTED ++// ++// MessageText: ++// ++// The specified section was already constructed. ++// ++#define HV_STATUS_SECTION_ALREADY_CONSTRUCTED ((HV_STATUS)0x1020) ++ ++// ++// MessageId: HV_STATUS_SECTION_NOT_ALREADY_CONSTRUCTED ++// ++// MessageText: ++// ++// The specified section was not already constructed. ++// ++#define HV_STATUS_SECTION_NOT_ALREADY_CONSTRUCTED ((HV_STATUS)0x1021) ++ ++// ++// MessageId: HV_STATUS_PAGE_ALREADY_COMMITTED ++// ++// MessageText: ++// ++// The specified virtual address was already backed by physical memory. ++// ++#define HV_STATUS_PAGE_ALREADY_COMMITTED ((HV_STATUS)0x1022) ++ ++// ++// MessageId: HV_STATUS_PAGE_NOT_ALREADY_COMMITTED ++// ++// MessageText: ++// ++// The specified virtual address was not already backed by physical memory. ++// ++#define HV_STATUS_PAGE_NOT_ALREADY_COMMITTED ((HV_STATUS)0x1023) ++ ++// ++// MessageId: HV_STATUS_COMMITTED_PAGES_REMAIN ++// ++// MessageText: ++// ++// Committed pages remain in the section. ++// ++#define HV_STATUS_COMMITTED_PAGES_REMAIN ((HV_STATUS)0x1024) ++ ++// ++// MessageId: HV_STATUS_NO_REMAINING_COMMITTED_PAGES ++// ++// MessageText: ++// ++// No additional committed pages beyond the specified page exist in the section. ++// ++#define HV_STATUS_NO_REMAINING_COMMITTED_PAGES ((HV_STATUS)0x1025) ++ ++// ++// MessageId: HV_STATUS_INSUFFICIENT_COMPARTMENT_VA ++// ++// MessageText: ++// ++// The VA space of the compartment is exhausted. ++// ++#define HV_STATUS_INSUFFICIENT_COMPARTMENT_VA ((HV_STATUS)0x1026) ++ ++// ++// MessageId: HV_STATUS_DEREF_SPA_LIST_FULL ++// ++// MessageText: ++// ++// The SPA dereference list is full, and there are additional entries ++// to be added to it. ++// ++#define HV_STATUS_DEREF_SPA_LIST_FULL ((HV_STATUS)0x1027) ++ ++// ++// MessageId: HV_STATUS_GPA_OUT_OF_RANGE ++// ++// MessageText: ++// ++// The supplied GPA is out of range. ++// ++#define HV_STATUS_GPA_OUT_OF_RANGE ((HV_STATUS)0x1027) ++ ++// ++// MessageId: HV_STATUS_NONVOLATILE_XMM_STALE ++// ++// MessageText: ++// ++// The XMM register that was being accessed is stale. ++// ++#define HV_STATUS_NONVOLATILE_XMM_STALE ((HV_STATUS)0x1028) ++ ++// ++// MessageId: HV_STATUS_UNSUPPORTED_PROCESSOR ++// ++// MessageText: ++// ++// The hypervisor does not support the processors in this system. ++// ++#define HV_STATUS_UNSUPPORTED_PROCESSOR ((HV_STATUS)0x1029) ++ ++// ++// MessageId: HV_STATUS_INSUFFICIENT_CROM_SPACE ++// ++// MessageText: ++// ++// Insufficient space existed for copying over the CROM contents. ++// ++#define HV_STATUS_INSUFFICIENT_CROM_SPACE ((HV_STATUS)0x2000) ++ ++// ++// MessageId: HV_STATUS_BAD_CROM_FORMAT ++// ++// MessageText: ++// ++// The contents of the CROM failed validation attempts. ++// ++#define HV_STATUS_BAD_CROM_FORMAT ((HV_STATUS)0x2001) ++ ++// ++// MessageId: HV_STATUS_UNSUPPORTED_CROM_FORMAT ++// ++// MessageText: ++// ++// The contents of the CROM contain contents the parser doesn't support. ++// ++#define HV_STATUS_UNSUPPORTED_CROM_FORMAT ((HV_STATUS)0x2002) ++ ++// ++// MessageId: HV_STATUS_UNSUPPORTED_CONTROLLER ++// ++// MessageText: ++// ++// The register format of the OHCI controller specified for debugging is not supported. ++// ++#define HV_STATUS_UNSUPPORTED_CONTROLLER ((HV_STATUS)0x2003) ++ ++// ++// MessageId: HV_STATUS_CROM_TOO_LARGE ++// ++// MessageText: ++// ++// The CROM contents were to large to copy over. ++// ++#define HV_STATUS_CROM_TOO_LARGE ((HV_STATUS)0x2004) ++ ++// ++// MessageId: HV_STATUS_CONTROLLER_IN_USE ++// ++// MessageText: ++// ++// The OHCI controller specified for debugging cannot be used as it is already in use. ++// ++#define HV_STATUS_CONTROLLER_IN_USE ((HV_STATUS)0x2005) ++ +--- /dev/null ++++ b/drivers/staging/hv/include/HvSynicApi.h +@@ -0,0 +1,490 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++#pragma once ++ ++// ++// Define the virtual APIC registers ++// ++#define HV_X64_MSR_EOI (0x40000070) ++#define HV_X64_MSR_ICR (0x40000071) ++#define HV_X64_MSR_TPR (0x40000072) ++#define HV_X64_MSR_APIC_ASSIST_PAGE (0x40000073) ++ ++// ++// Define version of the synthetic interrupt controller. ++// ++ ++#define HV_SYNIC_VERSION (1) ++ ++ ++// ++// Define synthetic interrupt controller model specific registers. ++// ++ ++#define HV_X64_MSR_SCONTROL (0x40000080) ++#define HV_X64_MSR_SVERSION (0x40000081) ++#define HV_X64_MSR_SIEFP (0x40000082) ++#define HV_X64_MSR_SIMP (0x40000083) ++#define HV_X64_MSR_EOM (0x40000084) ++#define HV_X64_MSR_SINT0 (0x40000090) ++#define HV_X64_MSR_SINT1 (0x40000091) ++#define HV_X64_MSR_SINT2 (0x40000092) ++#define HV_X64_MSR_SINT3 (0x40000093) ++#define HV_X64_MSR_SINT4 (0x40000094) ++#define HV_X64_MSR_SINT5 (0x40000095) ++#define HV_X64_MSR_SINT6 (0x40000096) ++#define HV_X64_MSR_SINT7 (0x40000097) ++#define HV_X64_MSR_SINT8 (0x40000098) ++#define HV_X64_MSR_SINT9 (0x40000099) ++#define HV_X64_MSR_SINT10 (0x4000009A) ++#define HV_X64_MSR_SINT11 (0x4000009B) ++#define HV_X64_MSR_SINT12 (0x4000009C) ++#define HV_X64_MSR_SINT13 (0x4000009D) ++#define HV_X64_MSR_SINT14 (0x4000009E) ++#define HV_X64_MSR_SINT15 (0x4000009F) ++ ++// ++// Define the expected SynIC version. ++// ++#define HV_SYNIC_VERSION_1 (0x1) ++ ++// ++// Define synthetic interrupt controller message constants. ++// ++ ++#define HV_MESSAGE_SIZE (256) ++#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) ++#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) ++#define HV_ANY_VP (0xFFFFFFFF) ++ ++// ++// Define synthetic interrupt controller flag constants. ++// ++ ++#define HV_EVENT_FLAGS_COUNT (256 * 8) ++#define HV_EVENT_FLAGS_BYTE_COUNT (256) ++#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(UINT32)) ++ ++// ++// Define hypervisor message types. ++// ++typedef enum _HV_MESSAGE_TYPE ++{ ++ HvMessageTypeNone = 0x00000000, ++ ++ // ++ // Memory access messages. ++ // ++ HvMessageTypeUnmappedGpa = 0x80000000, ++ HvMessageTypeGpaIntercept = 0x80000001, ++ ++ // ++ // Timer notification messages. ++ // ++ HvMessageTimerExpired = 0x80000010, ++ ++ // ++ // Error messages. ++ // ++ HvMessageTypeInvalidVpRegisterValue = 0x80000020, ++ HvMessageTypeUnrecoverableException = 0x80000021, ++ HvMessageTypeUnsupportedFeature = 0x80000022, ++ ++ // ++ // Trace buffer complete messages. ++ // ++ HvMessageTypeEventLogBufferComplete = 0x80000040, ++ ++ // ++ // Platform-specific processor intercept messages. ++ // ++ HvMessageTypeX64IoPortIntercept = 0x80010000, ++ HvMessageTypeX64MsrIntercept = 0x80010001, ++ HvMessageTypeX64CpuidIntercept = 0x80010002, ++ HvMessageTypeX64ExceptionIntercept = 0x80010003, ++ HvMessageTypeX64ApicEoi = 0x80010004, ++ HvMessageTypeX64LegacyFpError = 0x80010005 ++ ++} HV_MESSAGE_TYPE, *PHV_MESSAGE_TYPE; ++ ++// ++// Define the number of synthetic interrupt sources. ++// ++ ++#define HV_SYNIC_SINT_COUNT (16) ++#define HV_SYNIC_STIMER_COUNT (4) ++ ++// ++// Define the synthetic interrupt source index type. ++// ++ ++typedef UINT32 HV_SYNIC_SINT_INDEX, *PHV_SYNIC_SINT_INDEX; ++ ++// ++// Define partition identifier type. ++// ++ ++typedef UINT64 HV_PARTITION_ID, *PHV_PARTITION_ID; ++ ++// ++// Define invalid partition identifier. ++// ++#define HV_PARTITION_ID_INVALID ((HV_PARTITION_ID) 0x0) ++ ++// ++// Define connection identifier type. ++// ++ ++typedef union _HV_CONNECTION_ID ++{ ++ UINT32 AsUINT32; ++ ++ struct ++ { ++ UINT32 Id:24; ++ UINT32 Reserved:8; ++ } u; ++ ++} HV_CONNECTION_ID, *PHV_CONNECTION_ID; ++ ++// ++// Define port identifier type. ++// ++ ++typedef union _HV_PORT_ID ++{ ++ UINT32 AsUINT32; ++ ++ struct ++ { ++ UINT32 Id:24; ++ UINT32 Reserved:8; ++ } u ; ++ ++} HV_PORT_ID, *PHV_PORT_ID; ++ ++// ++// Define port type. ++// ++ ++typedef enum _HV_PORT_TYPE ++{ ++ HvPortTypeMessage = 1, ++ HvPortTypeEvent = 2, ++ HvPortTypeMonitor = 3 ++} HV_PORT_TYPE, *PHV_PORT_TYPE; ++ ++// ++// Define port information structure. ++// ++ ++typedef struct _HV_PORT_INFO ++{ ++ HV_PORT_TYPE PortType; ++ UINT32 Padding; ++ ++ union ++ { ++ struct ++ { ++ HV_SYNIC_SINT_INDEX TargetSint; ++ HV_VP_INDEX TargetVp; ++ UINT64 RsvdZ; ++ } MessagePortInfo; ++ ++ struct ++ { ++ HV_SYNIC_SINT_INDEX TargetSint; ++ HV_VP_INDEX TargetVp; ++ UINT16 BaseFlagNumber; ++ UINT16 FlagCount; ++ UINT32 RsvdZ; ++ } EventPortInfo; ++ ++ struct ++ { ++ HV_GPA MonitorAddress; ++ UINT64 RsvdZ; ++ } MonitorPortInfo; ++ }; ++} HV_PORT_INFO, *PHV_PORT_INFO; ++ ++typedef const HV_PORT_INFO *PCHV_PORT_INFO; ++ ++typedef struct _HV_CONNECTION_INFO ++{ ++ HV_PORT_TYPE PortType; ++ UINT32 Padding; ++ ++ union ++ { ++ struct ++ { ++ UINT64 RsvdZ; ++ } MessageConnectionInfo; ++ ++ struct ++ { ++ UINT64 RsvdZ; ++ } EventConnectionInfo; ++ ++ struct ++ { ++ HV_GPA MonitorAddress; ++ } MonitorConnectionInfo; ++ }; ++} HV_CONNECTION_INFO, *PHV_CONNECTION_INFO; ++ ++typedef const HV_CONNECTION_INFO *PCHV_CONNECTION_INFO; ++ ++// ++// Define synthetic interrupt controller message flags. ++// ++ ++typedef union _HV_MESSAGE_FLAGS ++{ ++ UINT8 AsUINT8; ++ struct ++ { ++ UINT8 MessagePending:1; ++ UINT8 Reserved:7; ++ }; ++} HV_MESSAGE_FLAGS, *PHV_MESSAGE_FLAGS; ++ ++ ++// ++// Define synthetic interrupt controller message header. ++// ++ ++typedef struct _HV_MESSAGE_HEADER ++{ ++ HV_MESSAGE_TYPE MessageType; ++ UINT8 PayloadSize; ++ HV_MESSAGE_FLAGS MessageFlags; ++ UINT8 Reserved[2]; ++ union ++ { ++ HV_PARTITION_ID Sender; ++ HV_PORT_ID Port; ++ }; ++ ++} HV_MESSAGE_HEADER, *PHV_MESSAGE_HEADER; ++ ++// ++// Define timer message payload structure. ++// ++typedef struct _HV_TIMER_MESSAGE_PAYLOAD ++{ ++ UINT32 TimerIndex; ++ UINT32 Reserved; ++ HV_NANO100_TIME ExpirationTime; // When the timer expired ++ HV_NANO100_TIME DeliveryTime; // When the message was delivered ++} HV_TIMER_MESSAGE_PAYLOAD, *PHV_TIMER_MESSAGE_PAYLOAD; ++ ++// ++// Define synthetic interrupt controller message format. ++// ++ ++typedef struct _HV_MESSAGE ++{ ++ HV_MESSAGE_HEADER Header; ++ union ++ { ++ UINT64 Payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; ++ } u ; ++} HV_MESSAGE, *PHV_MESSAGE; ++ ++// ++// Define the number of message buffers associated with each port. ++// ++ ++#define HV_PORT_MESSAGE_BUFFER_COUNT (16) ++ ++// ++// Define the synthetic interrupt message page layout. ++// ++ ++typedef struct _HV_MESSAGE_PAGE ++{ ++ volatile HV_MESSAGE SintMessage[HV_SYNIC_SINT_COUNT]; ++} HV_MESSAGE_PAGE, *PHV_MESSAGE_PAGE; ++ ++ ++// ++// Define the synthetic interrupt controller event flags format. ++// ++ ++typedef union _HV_SYNIC_EVENT_FLAGS ++{ ++ UINT8 Flags8[HV_EVENT_FLAGS_BYTE_COUNT]; ++ UINT32 Flags32[HV_EVENT_FLAGS_DWORD_COUNT]; ++} HV_SYNIC_EVENT_FLAGS, *PHV_SYNIC_EVENT_FLAGS; ++ ++ ++// ++// Define the synthetic interrupt flags page layout. ++// ++ ++typedef struct _HV_SYNIC_EVENT_FLAGS_PAGE ++{ ++ volatile HV_SYNIC_EVENT_FLAGS SintEventFlags[HV_SYNIC_SINT_COUNT]; ++} HV_SYNIC_EVENT_FLAGS_PAGE, *PHV_SYNIC_EVENT_FLAGS_PAGE; ++ ++ ++// ++// Define SynIC control register. ++// ++typedef union _HV_SYNIC_SCONTROL ++{ ++ UINT64 AsUINT64; ++ struct ++ { ++ UINT64 Enable:1; ++ UINT64 Reserved:63; ++ }; ++} HV_SYNIC_SCONTROL, *PHV_SYNIC_SCONTROL; ++ ++// ++// Define synthetic interrupt source. ++// ++ ++typedef union _HV_SYNIC_SINT ++{ ++ UINT64 AsUINT64; ++ struct ++ { ++ UINT64 Vector :8; ++ UINT64 Reserved1 :8; ++ UINT64 Masked :1; ++ UINT64 AutoEoi :1; ++ UINT64 Reserved2 :46; ++ }; ++} HV_SYNIC_SINT, *PHV_SYNIC_SINT; ++ ++// ++// Define the format of the SIMP register ++// ++ ++typedef union _HV_SYNIC_SIMP ++{ ++ UINT64 AsUINT64; ++ struct ++ { ++ UINT64 SimpEnabled : 1; ++ UINT64 Preserved : 11; ++ UINT64 BaseSimpGpa : 52; ++ }; ++} HV_SYNIC_SIMP, *PHV_SYNIC_SIMP; ++ ++// ++// Define the format of the SIEFP register ++// ++ ++typedef union _HV_SYNIC_SIEFP ++{ ++ UINT64 AsUINT64; ++ struct ++ { ++ UINT64 SiefpEnabled : 1; ++ UINT64 Preserved : 11; ++ UINT64 BaseSiefpGpa : 52; ++ }; ++} HV_SYNIC_SIEFP, *PHV_SYNIC_SIEFP; ++ ++// ++// Definitions for the monitored notification facility ++// ++ ++typedef union _HV_MONITOR_TRIGGER_GROUP ++{ ++ UINT64 AsUINT64; ++ ++ struct ++ { ++ UINT32 Pending; ++ UINT32 Armed; ++ }; ++ ++} HV_MONITOR_TRIGGER_GROUP, *PHV_MONITOR_TRIGGER_GROUP; ++ ++typedef struct _HV_MONITOR_PARAMETER ++{ ++ HV_CONNECTION_ID ConnectionId; ++ UINT16 FlagNumber; ++ UINT16 RsvdZ; ++} HV_MONITOR_PARAMETER, *PHV_MONITOR_PARAMETER; ++ ++typedef union _HV_MONITOR_TRIGGER_STATE ++{ ++ UINT32 AsUINT32; ++ ++ struct ++ { ++ UINT32 GroupEnable : 4; ++ UINT32 RsvdZ : 28; ++ }; ++ ++} HV_MONITOR_TRIGGER_STATE, *PHV_MONITOR_TRIGGER_STATE; ++ ++// ++// HV_MONITOR_PAGE Layout ++// ------------------------------------------------------ ++// | 0 | TriggerState (4 bytes) | Rsvd1 (4 bytes) | ++// | 8 | TriggerGroup[0] | ++// | 10 | TriggerGroup[1] | ++// | 18 | TriggerGroup[2] | ++// | 20 | TriggerGroup[3] | ++// | 28 | Rsvd2[0] | ++// | 30 | Rsvd2[1] | ++// | 38 | Rsvd2[2] | ++// | 40 | NextCheckTime[0][0] | NextCheckTime[0][1] | ++// | ... | ++// | 240 | Latency[0][0..3] | ++// | 340 | Rsvz3[0] | ++// | 440 | Parameter[0][0] | ++// | 448 | Parameter[0][1] | ++// | ... | ++// | 840 | Rsvd4[0] | ++// ------------------------------------------------------ ++ ++typedef struct _HV_MONITOR_PAGE ++{ ++ HV_MONITOR_TRIGGER_STATE TriggerState; ++ UINT32 RsvdZ1; ++ ++ HV_MONITOR_TRIGGER_GROUP TriggerGroup[4]; ++ UINT64 RsvdZ2[3]; ++ ++ INT32 NextCheckTime[4][32]; ++ ++ UINT16 Latency[4][32]; ++ UINT64 RsvdZ3[32]; ++ ++ HV_MONITOR_PARAMETER Parameter[4][32]; ++ ++ UINT8 RsvdZ4[1984]; ++ ++} HV_MONITOR_PAGE, *PHV_MONITOR_PAGE; ++ ++typedef volatile HV_MONITOR_PAGE* PVHV_MONITOR_PAGE; +--- /dev/null ++++ b/drivers/staging/hv/include/HvTypes.h +@@ -0,0 +1,31 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++typedef UINT64 HV_GPA, *PHV_GPA; ++ ++#define HV_X64_PAGE_SIZE (4096) ++#define HV_PAGE_SIZE HV_X64_PAGE_SIZE ++ +--- /dev/null ++++ b/drivers/staging/hv/include/HvVpApi.h +@@ -0,0 +1,51 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++// ++// Virtual Processor Indices ++// ++typedef UINT32 HV_VP_INDEX, *PHV_VP_INDEX; ++ ++// ++// The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent ++// is set by CPUID(HvCpuIdFunctionVersionAndFeatures). ++// ========================================================================== ++// ++ ++typedef enum _HV_CPUID_FUNCTION ++{ ++ HvCpuIdFunctionVersionAndFeatures = 0x00000001, ++ HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000, ++ HvCpuIdFunctionHvInterface = 0x40000001, ++ ++ // ++ // The remaining functions depend on the value of HvCpuIdFunctionInterface ++ // ++ HvCpuIdFunctionMsHvVersion = 0x40000002, ++ HvCpuIdFunctionMsHvFeatures = 0x40000003, ++ HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004, ++ HvCpuIdFunctionMsHvImplementationLimits = 0x40000005 ++ ++} HV_CPUID_FUNCTION, *PHV_CPUID_FUNCTION; +--- /dev/null ++++ b/drivers/staging/hv/include/List.h +@@ -0,0 +1,269 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _LIST_H_ ++#define _LIST_H_ ++ ++#include "osd.h" ++/* ++ * ++ * Doubly-linked list manipulation routines. Implemented as macros ++ * but logically these are procedures. ++ * ++ */ ++ ++typedef DLIST_ENTRY LIST_ENTRY; ++typedef DLIST_ENTRY *PLIST_ENTRY; ++ ++//typedef struct LIST_ENTRY { ++// struct LIST_ENTRY * volatile Flink; ++// struct LIST_ENTRY * volatile Blink; ++//} LIST_ENTRY, *PLIST_ENTRY; ++ ++ ++ ++/* ++ * VOID ++ * InitializeListHead( ++ * PLIST_ENTRY ListHead ++ * ); ++ */ ++#define INITIALIZE_LIST_HEAD InitializeListHead ++ ++#define InitializeListHead(ListHead) (\ ++ (ListHead)->Flink = (ListHead)->Blink = (ListHead)) ++ ++ ++/* ++ * BOOLEAN ++ * IsListEmpty( ++ * PLIST_ENTRY ListHead ++ * ); ++ */ ++#define IS_LIST_EMPTY IsListEmpty ++ ++#define IsListEmpty(ListHead) \ ++ ((ListHead)->Flink == (ListHead)) ++ ++ ++/* ++ * PLIST_ENTRY ++ * NextListEntry( ++ * PLIST_ENTRY Entry ++ * ); ++ */ ++#define NEXT_LIST_ENTRY NextListEntry ++ ++#define NextListEntry(Entry) \ ++ (Entry)->Flink ++ ++ ++/* ++ * PLIST_ENTRY ++ * PrevListEntry( ++ * PLIST_ENTRY Entry ++ * ); ++ */ ++#define PREV_LIST_ENTRY PrevListEntry ++ ++#define PrevListEntry(Entry) \ ++ (Entry)->Blink ++ ++ ++/* ++ * PLIST_ENTRY ++ * TopListEntry( ++ * PLIST_ENTRY ListHead ++ * ); ++ */ ++#define TOP_LIST_ENTRY TopListEntry ++ ++#define TopListEntry(ListHead) \ ++ (ListHead)->Flink ++ ++ ++ ++/* ++ * PLIST_ENTRY ++ * RemoveHeadList( ++ * PLIST_ENTRY ListHead ++ * ); ++ */ ++ ++#define REMOVE_HEAD_LIST RemoveHeadList ++ ++#define RemoveHeadList(ListHead) \ ++ (ListHead)->Flink;\ ++ {RemoveEntryList((ListHead)->Flink)} ++ ++ ++/* ++ * PLIST_ENTRY ++ * RemoveTailList( ++ * PLIST_ENTRY ListHead ++ * ); ++ */ ++#define REMOVE_TAIL_LIST RemoveTailList ++ ++#define RemoveTailList(ListHead) \ ++ (ListHead)->Blink;\ ++ {RemoveEntryList((ListHead)->Blink)} ++ ++ ++/* ++ * VOID ++ * RemoveEntryList( ++ * PLIST_ENTRY Entry ++ * ); ++ */ ++#define REMOVE_ENTRY_LIST RemoveEntryList ++ ++#define RemoveEntryList(Entry) {\ ++ PLIST_ENTRY _EX_Flink = (Entry)->Flink;\ ++ PLIST_ENTRY _EX_Blink = (Entry)->Blink;\ ++ _EX_Blink->Flink = _EX_Flink;\ ++ _EX_Flink->Blink = _EX_Blink;\ ++ } ++ ++ ++/* ++ * VOID ++ * AttachList( ++ * PLIST_ENTRY ListHead, ++ * PLIST_ENTRY ListEntry ++ * ); ++ */ ++#define ATTACH_LIST AttachList ++ ++#define AttachList(ListHead,ListEntry) {\ ++ PLIST_ENTRY _EX_ListHead = (ListHead);\ ++ PLIST_ENTRY _EX_Blink = (ListHead)->Blink;\ ++ (ListEntry)->Blink->Flink = _EX_ListHead;\ ++ _EX_Blink->Flink = (ListEntry);\ ++ _EX_ListHead->Blink = (ListEntry)->Blink;\ ++ (ListEntry)->Blink = _EX_Blink;\ ++ } ++ ++ ++ ++/* ++ * VOID ++ * InsertTailList( ++ * PLIST_ENTRY ListHead, ++ * PLIST_ENTRY Entry ++ * ); ++ */ ++ ++#define INSERT_TAIL_LIST InsertTailList ++ ++#define InsertTailList(ListHead,Entry) {\ ++ PLIST_ENTRY _EX_ListHead = (ListHead);\ ++ PLIST_ENTRY _EX_Blink = (ListHead)->Blink;\ ++ (Entry)->Flink = _EX_ListHead;\ ++ (Entry)->Blink = _EX_Blink;\ ++ _EX_Blink->Flink = (Entry);\ ++ _EX_ListHead->Blink = (Entry);\ ++ } ++ ++ ++/* ++ * VOID ++ * InsertHeadList( ++ * PLIST_ENTRY ListHead, ++ * PLIST_ENTRY Entry ++ * ); ++ */ ++#define INSERT_HEAD_LIST InsertHeadList ++ ++#define InsertHeadList(ListHead,Entry) {\ ++ PLIST_ENTRY _EX_ListHead = (ListHead);\ ++ PLIST_ENTRY _EX_Flink = (ListHead)->Flink;\ ++ (Entry)->Flink = _EX_Flink;\ ++ (Entry)->Blink = _EX_ListHead;\ ++ _EX_Flink->Blink = (Entry);\ ++ _EX_ListHead->Flink = (Entry);\ ++ } ++ ++ ++/* ++ * VOID ++ * IterateListEntries( ++ * PLIST_ENTRY anchor, ++ * PLIST_ENTRY index, ++ * PLIST_ENTRY listp ++ * ); ++ */ ++ ++#define ITERATE_LIST_ENTRIES IterateListEntries ++ ++#define IterateListEntries(anchor, index, listp) \ ++ (anchor) = (LIST_ENTRY *)(listp); \ ++ for((index) = (anchor)->Flink; (index) != (anchor); (index) = (index)->Flink) ++ ++ ++ ++/* ++ * PSINGLE_LIST_ENTRY ++ * PopEntryList( ++ * PSINGLE_LIST_ENTRY ListHead ++ * ); ++ */ ++ ++#define POP_ENTRY_LIST PopEntryList ++ ++#define PopEntryList(ListHead) \ ++ (ListHead)->Next;\ ++ {\ ++ PSINGLE_LIST_ENTRY FirstEntry;\ ++ FirstEntry = (ListHead)->Next;\ ++ if (FirstEntry != NULL) { \ ++ (ListHead)->Next = FirstEntry->Next;\ ++ } \ ++ } ++ ++ ++ ++/* ++ * VOID ++ * PushEntryList( ++ * PSINGLE_LIST_ENTRY ListHead, ++ * PSINGLE_LIST_ENTRY Entry ++ * ); ++ */ ++ ++#define PUSH_ENTRY_LIST PushEntryList ++ ++#define PushEntryList(ListHead,Entry) \ ++ (Entry)->Next = (ListHead)->Next; \ ++ (ListHead)->Next = (Entry) ++ ++#ifndef CONTAINING_RECORD ++#define CONTAINING_RECORD(address, type, field) ((type *)( \ ++ (PCHAR)(address) - \ ++ (PCHAR)(&((type *)0)->field))) ++#endif /* CONTAINING_RECORD */ ++ ++#endif /* _LIST_H_ */ ++ ++/* EOF */ +--- /dev/null ++++ b/drivers/staging/hv/include/nvspprotocol.h +@@ -0,0 +1,306 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++#include ++ ++#define NVSP_INVALID_PROTOCOL_VERSION ((UINT32)0xFFFFFFFF) ++ ++#define NVSP_PROTOCOL_VERSION_1 2 ++#define NVSP_MIN_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 ++#define NVSP_MAX_PROTOCOL_VERSION NVSP_PROTOCOL_VERSION_1 ++ ++typedef enum _NVSP_MESSAGE_TYPE ++{ ++ NvspMessageTypeNone = 0, ++ ++ // ++ // Init Messages ++ // ++ NvspMessageTypeInit = 1, ++ NvspMessageTypeInitComplete = 2, ++ ++ NvspVersionMessageStart = 100, ++ ++ // ++ // Version 1 Messages ++ // ++ NvspMessage1TypeSendNdisVersion = NvspVersionMessageStart, ++ ++ NvspMessage1TypeSendReceiveBuffer, ++ NvspMessage1TypeSendReceiveBufferComplete, ++ NvspMessage1TypeRevokeReceiveBuffer, ++ ++ NvspMessage1TypeSendSendBuffer, ++ NvspMessage1TypeSendSendBufferComplete, ++ NvspMessage1TypeRevokeSendBuffer, ++ ++ NvspMessage1TypeSendRNDISPacket, ++ NvspMessage1TypeSendRNDISPacketComplete, ++ ++ // ++ // This should be set to the number of messages for the version ++ // with the maximum number of messages. ++ // ++ NvspNumMessagePerVersion = 9, ++ ++} NVSP_MESSAGE_TYPE, *PNVSP_MESSAGE_TYPE; ++ ++typedef enum _NVSP_STATUS ++{ ++ NvspStatusNone = 0, ++ NvspStatusSuccess, ++ NvspStatusFailure, ++ NvspStatusProtocolVersionRangeTooNew, ++ NvspStatusProtocolVersionRangeTooOld, ++ NvspStatusInvalidRndisPacket, ++ NvspStatusBusy, ++ NvspStatusMax, ++} NVSP_STATUS, *PNVSP_STATUS; ++ ++#pragma pack(push, 1) ++ ++typedef struct _NVSP_MESSAGE_HEADER ++{ ++ UINT32 MessageType; ++} NVSP_MESSAGE_HEADER, *PNVSP_MESSAGE_HEADER; ++ ++// ++// Init Messages ++// ++ ++// ++// This message is used by the VSC to initialize the channel ++// after the channels has been opened. This message should ++// never include anything other then versioning (i.e. this ++// message will be the same for ever). ++// ++typedef struct _NVSP_MESSAGE_INIT ++{ ++ UINT32 MinProtocolVersion; ++ UINT32 MaxProtocolVersion; ++} NVSP_MESSAGE_INIT, *PNVSP_MESSAGE_INIT; ++ ++// ++// This message is used by the VSP to complete the initialization ++// of the channel. This message should never include anything other ++// then versioning (i.e. this message will be the same for ever). ++// ++typedef struct _NVSP_MESSAGE_INIT_COMPLETE ++{ ++ UINT32 NegotiatedProtocolVersion; ++ UINT32 MaximumMdlChainLength; ++ UINT32 Status; ++} NVSP_MESSAGE_INIT_COMPLETE, *PNVSP_MESSAGE_INIT_COMPLETE; ++ ++typedef union _NVSP_MESSAGE_INIT_UBER ++{ ++ NVSP_MESSAGE_INIT Init; ++ NVSP_MESSAGE_INIT_COMPLETE InitComplete; ++} NVSP_MESSAGE_INIT_UBER; ++ ++// ++// Version 1 Messages ++// ++ ++// ++// This message is used by the VSC to send the NDIS version ++// to the VSP. The VSP can use this information when handling ++// OIDs sent by the VSC. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_NDIS_VERSION ++{ ++ UINT32 NdisMajorVersion; ++ UINT32 NdisMinorVersion; ++} NVSP_1_MESSAGE_SEND_NDIS_VERSION, *PNVSP_1_MESSAGE_SEND_NDIS_VERSION; ++ ++// ++// This message is used by the VSC to send a receive buffer ++// to the VSP. The VSP can then use the receive buffer to ++// send data to the VSC. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_RECEIVE_BUFFER ++{ ++ GPADL_HANDLE GpadlHandle; ++ UINT16 Id; ++} NVSP_1_MESSAGE_SEND_RECEIVE_BUFFER, *PNVSP_1_MESSAGE_SEND_RECEIVE_BUFFER; ++ ++typedef struct _NVSP_1_RECEIVE_BUFFER_SECTION ++{ ++ UINT32 Offset; ++ UINT32 SubAllocationSize; ++ UINT32 NumSubAllocations; ++ UINT32 EndOffset; ++} NVSP_1_RECEIVE_BUFFER_SECTION, *PNVSP_1_RECEIVE_BUFFER_SECTION; ++ ++// ++// This message is used by the VSP to acknowledge a receive ++// buffer send by the VSC. This message must be sent by the ++// VSP before the VSP uses the receive buffer. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_RECEIVE_BUFFER_COMPLETE ++{ ++ UINT32 Status; ++ UINT32 NumSections; ++ ++ // ++ // The receive buffer is split into two parts, a large ++ // suballocation section and a small suballocation ++ // section. These sections are then suballocated by a ++ // certain size. ++ // ++ // For example, the following break up of the receive ++ // buffer has 6 large suballocations and 10 small ++ // suballocations. ++ // ++ // | Large Section | | Small Section | ++ // ------------------------------------------------------------ ++ // | | | | | | | | | | | | | | | | | | ++ // | | ++ // LargeOffset SmallOffset ++ // ++ NVSP_1_RECEIVE_BUFFER_SECTION Sections[1]; ++ ++} NVSP_1_MESSAGE_SEND_RECEIVE_BUFFER_COMPLETE, *PNVSP_1_MESSAGE_SEND_RECEIVE_BUFFER_COMPLETE; ++ ++// ++// This message is sent by the VSC to revoke the receive buffer. ++// After the VSP completes this transaction, the vsp should never ++// use the receive buffer again. ++// ++typedef struct _NVSP_1_MESSAGE_REVOKE_RECEIVE_BUFFER ++{ ++ UINT16 Id; ++} NVSP_1_MESSAGE_REVOKE_RECEIVE_BUFFER, *PNVSP_1_MESSAGE_REVOKE_RECEIVE_BUFFER; ++ ++// ++// This message is used by the VSC to send a send buffer ++// to the VSP. The VSC can then use the send buffer to ++// send data to the VSP. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_SEND_BUFFER ++{ ++ GPADL_HANDLE GpadlHandle; ++ UINT16 Id; ++} NVSP_1_MESSAGE_SEND_SEND_BUFFER, *PNVSP_1_MESSAGE_SEND_SEND_BUFFER; ++ ++// ++// This message is used by the VSP to acknowledge a send ++// buffer sent by the VSC. This message must be sent by the ++// VSP before the VSP uses the sent buffer. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_SEND_BUFFER_COMPLETE ++{ ++ UINT32 Status; ++ ++ // ++ // The VSC gets to choose the size of the send buffer and ++ // the VSP gets to choose the sections size of the buffer. ++ // This was done to enable dynamic reconfigurations when ++ // the cost of GPA-direct buffers decreases. ++ // ++ UINT32 SectionSize; ++} NVSP_1_MESSAGE_SEND_SEND_BUFFER_COMPLETE, *PNVSP_1_MESSAGE_SEND_SEND_BUFFER_COMPLETE; ++ ++// ++// This message is sent by the VSC to revoke the send buffer. ++// After the VSP completes this transaction, the vsp should never ++// use the send buffer again. ++// ++typedef struct _NVSP_1_MESSAGE_REVOKE_SEND_BUFFER ++{ ++ UINT16 Id; ++} NVSP_1_MESSAGE_REVOKE_SEND_BUFFER, *PNVSP_1_MESSAGE_REVOKE_SEND_BUFFER; ++ ++// ++// This message is used by both the VSP and the VSC to send ++// a RNDIS message to the opposite channel endpoint. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_RNDIS_PACKET ++{ ++ // ++ // This field is specified by RNIDS. They assume there's ++ // two different channels of communication. However, ++ // the Network VSP only has one. Therefore, the channel ++ // travels with the RNDIS packet. ++ // ++ UINT32 ChannelType; ++ ++ // ++ // This field is used to send part or all of the data ++ // through a send buffer. This values specifies an ++ // index into the send buffer. If the index is ++ // 0xFFFFFFFF, then the send buffer is not being used ++ // and all of the data was sent through other VMBus ++ // mechanisms. ++ // ++ UINT32 SendBufferSectionIndex; ++ UINT32 SendBufferSectionSize; ++} NVSP_1_MESSAGE_SEND_RNDIS_PACKET, *PNVSP_1_MESSAGE_SEND_RNDIS_PACKET; ++ ++// ++// This message is used by both the VSP and the VSC to complete ++// a RNDIS message to the opposite channel endpoint. At this ++// point, the initiator of this message cannot use any resources ++// associated with the original RNDIS packet. ++// ++typedef struct _NVSP_1_MESSAGE_SEND_RNDIS_PACKET_COMPLETE ++{ ++ UINT32 Status; ++} NVSP_1_MESSAGE_SEND_RNDIS_PACKET_COMPLETE, *PNVSP_1_MESSAGE_SEND_RNDIS_PACKET_COMPLETE; ++ ++typedef union _NVSP_MESSAGE_1_UBER ++{ ++ NVSP_1_MESSAGE_SEND_NDIS_VERSION SendNdisVersion; ++ ++ NVSP_1_MESSAGE_SEND_RECEIVE_BUFFER SendReceiveBuffer; ++ NVSP_1_MESSAGE_SEND_RECEIVE_BUFFER_COMPLETE SendReceiveBufferComplete; ++ NVSP_1_MESSAGE_REVOKE_RECEIVE_BUFFER RevokeReceiveBuffer; ++ ++ NVSP_1_MESSAGE_SEND_SEND_BUFFER SendSendBuffer; ++ NVSP_1_MESSAGE_SEND_SEND_BUFFER_COMPLETE SendSendBufferComplete; ++ NVSP_1_MESSAGE_REVOKE_SEND_BUFFER RevokeSendBuffer; ++ ++ NVSP_1_MESSAGE_SEND_RNDIS_PACKET SendRNDISPacket; ++ NVSP_1_MESSAGE_SEND_RNDIS_PACKET_COMPLETE SendRNDISPacketComplete; ++} NVSP_1_MESSAGE_UBER; ++ ++typedef union _NVSP_ALL_MESSAGES ++{ ++ NVSP_MESSAGE_INIT_UBER InitMessages; ++ NVSP_1_MESSAGE_UBER Version1Messages; ++ ++} NVSP_ALL_MESSAGES; ++ ++// ++// ALL Messages ++// ++typedef struct _NVSP_MESSAGE ++{ ++ NVSP_MESSAGE_HEADER Header; ++ NVSP_ALL_MESSAGES Messages; ++} NVSP_MESSAGE, *PNVSP_MESSAGE; ++ ++#pragma pack(pop) +--- /dev/null ++++ b/drivers/staging/hv/include/rndis.h +@@ -0,0 +1,836 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _RNDIS_H_ ++#define _RNDIS_H_ ++ ++// ++// Basic types ++// ++typedef UINT32 RNDIS_REQUEST_ID; ++typedef UINT32 RNDIS_HANDLE; ++typedef UINT32 RNDIS_STATUS; ++typedef UINT32 RNDIS_REQUEST_TYPE; ++typedef UINT32 RNDIS_OID; ++typedef UINT32 RNDIS_CLASS_ID; ++typedef UINT32 RNDIS_MEDIUM; ++typedef UINT32 *PRNDIS_REQUEST_ID; ++typedef UINT32 *PRNDIS_HANDLE; ++typedef UINT32 *PRNDIS_STATUS; ++typedef UINT32 *PRNDIS_REQUEST_TYPE; ++typedef UINT32 *PRNDIS_OID; ++typedef UINT32 *PRNDIS_CLASS_ID; ++typedef UINT32 *PRNDIS_MEDIUM; ++typedef UINT32 RNDIS_AF; ++ ++// ++// Status codes ++// ++ ++#ifndef STATUS_SUCCESS ++#define STATUS_SUCCESS (0x00000000L) ++#endif ++ ++#ifndef STATUS_UNSUCCESSFUL ++#define STATUS_UNSUCCESSFUL (0xC0000001L) ++#endif ++ ++#ifndef STATUS_PENDING ++#define STATUS_PENDING (0x00000103L) ++#endif ++ ++#ifndef STATUS_INSUFFICIENT_RESOURCES ++#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AL) ++#endif ++ ++#ifndef STATUS_BUFFER_OVERFLOW ++#define STATUS_BUFFER_OVERFLOW (0x80000005L) ++#endif ++ ++#ifndef STATUS_NOT_SUPPORTED ++#define STATUS_NOT_SUPPORTED (0xC00000BBL) ++#endif ++ ++#define RNDIS_STATUS_SUCCESS ((RNDIS_STATUS)STATUS_SUCCESS) ++#define RNDIS_STATUS_PENDING ((RNDIS_STATUS)STATUS_PENDING) ++#define RNDIS_STATUS_NOT_RECOGNIZED ((RNDIS_STATUS)0x00010001L) ++#define RNDIS_STATUS_NOT_COPIED ((RNDIS_STATUS)0x00010002L) ++#define RNDIS_STATUS_NOT_ACCEPTED ((RNDIS_STATUS)0x00010003L) ++#define RNDIS_STATUS_CALL_ACTIVE ((RNDIS_STATUS)0x00010007L) ++ ++#define RNDIS_STATUS_ONLINE ((RNDIS_STATUS)0x40010003L) ++#define RNDIS_STATUS_RESET_START ((RNDIS_STATUS)0x40010004L) ++#define RNDIS_STATUS_RESET_END ((RNDIS_STATUS)0x40010005L) ++#define RNDIS_STATUS_RING_STATUS ((RNDIS_STATUS)0x40010006L) ++#define RNDIS_STATUS_CLOSED ((RNDIS_STATUS)0x40010007L) ++#define RNDIS_STATUS_WAN_LINE_UP ((RNDIS_STATUS)0x40010008L) ++#define RNDIS_STATUS_WAN_LINE_DOWN ((RNDIS_STATUS)0x40010009L) ++#define RNDIS_STATUS_WAN_FRAGMENT ((RNDIS_STATUS)0x4001000AL) ++#define RNDIS_STATUS_MEDIA_CONNECT ((RNDIS_STATUS)0x4001000BL) ++#define RNDIS_STATUS_MEDIA_DISCONNECT ((RNDIS_STATUS)0x4001000CL) ++#define RNDIS_STATUS_HARDWARE_LINE_UP ((RNDIS_STATUS)0x4001000DL) ++#define RNDIS_STATUS_HARDWARE_LINE_DOWN ((RNDIS_STATUS)0x4001000EL) ++#define RNDIS_STATUS_INTERFACE_UP ((RNDIS_STATUS)0x4001000FL) ++#define RNDIS_STATUS_INTERFACE_DOWN ((RNDIS_STATUS)0x40010010L) ++#define RNDIS_STATUS_MEDIA_BUSY ((RNDIS_STATUS)0x40010011L) ++#define RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION ((RNDIS_STATUS)0x40010012L) ++#define RNDIS_STATUS_WW_INDICATION RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION ++#define RNDIS_STATUS_LINK_SPEED_CHANGE ((RNDIS_STATUS)0x40010013L) ++ ++#define RNDIS_STATUS_NOT_RESETTABLE ((RNDIS_STATUS)0x80010001L) ++#define RNDIS_STATUS_SOFT_ERRORS ((RNDIS_STATUS)0x80010003L) ++#define RNDIS_STATUS_HARD_ERRORS ((RNDIS_STATUS)0x80010004L) ++#define RNDIS_STATUS_BUFFER_OVERFLOW ((RNDIS_STATUS)STATUS_BUFFER_OVERFLOW) ++ ++#define RNDIS_STATUS_FAILURE ((RNDIS_STATUS)STATUS_UNSUCCESSFUL) ++#define RNDIS_STATUS_RESOURCES ((RNDIS_STATUS)STATUS_INSUFFICIENT_RESOURCES) ++#define RNDIS_STATUS_CLOSING ((RNDIS_STATUS)0xC0010002L) ++#define RNDIS_STATUS_BAD_VERSION ((RNDIS_STATUS)0xC0010004L) ++#define RNDIS_STATUS_BAD_CHARACTERISTICS ((RNDIS_STATUS)0xC0010005L) ++#define RNDIS_STATUS_ADAPTER_NOT_FOUND ((RNDIS_STATUS)0xC0010006L) ++#define RNDIS_STATUS_OPEN_FAILED ((RNDIS_STATUS)0xC0010007L) ++#define RNDIS_STATUS_DEVICE_FAILED ((RNDIS_STATUS)0xC0010008L) ++#define RNDIS_STATUS_MULTICAST_FULL ((RNDIS_STATUS)0xC0010009L) ++#define RNDIS_STATUS_MULTICAST_EXISTS ((RNDIS_STATUS)0xC001000AL) ++#define RNDIS_STATUS_MULTICAST_NOT_FOUND ((RNDIS_STATUS)0xC001000BL) ++#define RNDIS_STATUS_REQUEST_ABORTED ((RNDIS_STATUS)0xC001000CL) ++#define RNDIS_STATUS_RESET_IN_PROGRESS ((RNDIS_STATUS)0xC001000DL) ++#define RNDIS_STATUS_CLOSING_INDICATING ((RNDIS_STATUS)0xC001000EL) ++#define RNDIS_STATUS_NOT_SUPPORTED ((RNDIS_STATUS)STATUS_NOT_SUPPORTED) ++#define RNDIS_STATUS_INVALID_PACKET ((RNDIS_STATUS)0xC001000FL) ++#define RNDIS_STATUS_OPEN_LIST_FULL ((RNDIS_STATUS)0xC0010010L) ++#define RNDIS_STATUS_ADAPTER_NOT_READY ((RNDIS_STATUS)0xC0010011L) ++#define RNDIS_STATUS_ADAPTER_NOT_OPEN ((RNDIS_STATUS)0xC0010012L) ++#define RNDIS_STATUS_NOT_INDICATING ((RNDIS_STATUS)0xC0010013L) ++#define RNDIS_STATUS_INVALID_LENGTH ((RNDIS_STATUS)0xC0010014L) ++#define RNDIS_STATUS_INVALID_DATA ((RNDIS_STATUS)0xC0010015L) ++#define RNDIS_STATUS_BUFFER_TOO_SHORT ((RNDIS_STATUS)0xC0010016L) ++#define RNDIS_STATUS_INVALID_OID ((RNDIS_STATUS)0xC0010017L) ++#define RNDIS_STATUS_ADAPTER_REMOVED ((RNDIS_STATUS)0xC0010018L) ++#define RNDIS_STATUS_UNSUPPORTED_MEDIA ((RNDIS_STATUS)0xC0010019L) ++#define RNDIS_STATUS_GROUP_ADDRESS_IN_USE ((RNDIS_STATUS)0xC001001AL) ++#define RNDIS_STATUS_FILE_NOT_FOUND ((RNDIS_STATUS)0xC001001BL) ++#define RNDIS_STATUS_ERROR_READING_FILE ((RNDIS_STATUS)0xC001001CL) ++#define RNDIS_STATUS_ALREADY_MAPPED ((RNDIS_STATUS)0xC001001DL) ++#define RNDIS_STATUS_RESOURCE_CONFLICT ((RNDIS_STATUS)0xC001001EL) ++#define RNDIS_STATUS_NO_CABLE ((RNDIS_STATUS)0xC001001FL) ++ ++#define RNDIS_STATUS_INVALID_SAP ((RNDIS_STATUS)0xC0010020L) ++#define RNDIS_STATUS_SAP_IN_USE ((RNDIS_STATUS)0xC0010021L) ++#define RNDIS_STATUS_INVALID_ADDRESS ((RNDIS_STATUS)0xC0010022L) ++#define RNDIS_STATUS_VC_NOT_ACTIVATED ((RNDIS_STATUS)0xC0010023L) ++#define RNDIS_STATUS_DEST_OUT_OF_ORDER ((RNDIS_STATUS)0xC0010024L) ++#define RNDIS_STATUS_VC_NOT_AVAILABLE ((RNDIS_STATUS)0xC0010025L) ++#define RNDIS_STATUS_CELLRATE_NOT_AVAILABLE ((RNDIS_STATUS)0xC0010026L) ++#define RNDIS_STATUS_INCOMPATABLE_QOS ((RNDIS_STATUS)0xC0010027L) ++#define RNDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((RNDIS_STATUS)0xC0010028L) ++#define RNDIS_STATUS_NO_ROUTE_TO_DESTINATION ((RNDIS_STATUS)0xC0010029L) ++ ++#define RNDIS_STATUS_TOKEN_RING_OPEN_ERROR ((RNDIS_STATUS)0xC0011000L) ++ ++ ++// ++// Object Identifiers used by NdisRequest Query/Set Information ++// ++ ++// ++// General Objects ++// ++ ++#define RNDIS_OID_GEN_SUPPORTED_LIST 0x00010101 ++#define RNDIS_OID_GEN_HARDWARE_STATUS 0x00010102 ++#define RNDIS_OID_GEN_MEDIA_SUPPORTED 0x00010103 ++#define RNDIS_OID_GEN_MEDIA_IN_USE 0x00010104 ++#define RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 ++#define RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 ++#define RNDIS_OID_GEN_LINK_SPEED 0x00010107 ++#define RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 ++#define RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 ++#define RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A ++#define RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B ++#define RNDIS_OID_GEN_VENDOR_ID 0x0001010C ++#define RNDIS_OID_GEN_VENDOR_DESCRIPTION 0x0001010D ++#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER 0x0001010E ++#define RNDIS_OID_GEN_CURRENT_LOOKAHEAD 0x0001010F ++#define RNDIS_OID_GEN_DRIVER_VERSION 0x00010110 ++#define RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 ++#define RNDIS_OID_GEN_PROTOCOL_OPTIONS 0x00010112 ++#define RNDIS_OID_GEN_MAC_OPTIONS 0x00010113 ++#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 ++#define RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 ++#define RNDIS_OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 ++#define RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 ++#define RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 ++#define RNDIS_OID_GEN_MACHINE_NAME 0x0001021A ++#define RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B ++ ++#define RNDIS_OID_GEN_XMIT_OK 0x00020101 ++#define RNDIS_OID_GEN_RCV_OK 0x00020102 ++#define RNDIS_OID_GEN_XMIT_ERROR 0x00020103 ++#define RNDIS_OID_GEN_RCV_ERROR 0x00020104 ++#define RNDIS_OID_GEN_RCV_NO_BUFFER 0x00020105 ++ ++#define RNDIS_OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 ++#define RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 ++#define RNDIS_OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 ++#define RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 ++#define RNDIS_OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 ++#define RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 ++#define RNDIS_OID_GEN_DIRECTED_BYTES_RCV 0x00020207 ++#define RNDIS_OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 ++#define RNDIS_OID_GEN_MULTICAST_BYTES_RCV 0x00020209 ++#define RNDIS_OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A ++#define RNDIS_OID_GEN_BROADCAST_BYTES_RCV 0x0002020B ++#define RNDIS_OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C ++ ++#define RNDIS_OID_GEN_RCV_CRC_ERROR 0x0002020D ++#define RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E ++ ++#define RNDIS_OID_GEN_GET_TIME_CAPS 0x0002020F ++#define RNDIS_OID_GEN_GET_NETCARD_TIME 0x00020210 ++ ++// ++// These are connection-oriented general OIDs. ++// These replace the above OIDs for connection-oriented media. ++// ++#define RNDIS_OID_GEN_CO_SUPPORTED_LIST 0x00010101 ++#define RNDIS_OID_GEN_CO_HARDWARE_STATUS 0x00010102 ++#define RNDIS_OID_GEN_CO_MEDIA_SUPPORTED 0x00010103 ++#define RNDIS_OID_GEN_CO_MEDIA_IN_USE 0x00010104 ++#define RNDIS_OID_GEN_CO_LINK_SPEED 0x00010105 ++#define RNDIS_OID_GEN_CO_VENDOR_ID 0x00010106 ++#define RNDIS_OID_GEN_CO_VENDOR_DESCRIPTION 0x00010107 ++#define RNDIS_OID_GEN_CO_DRIVER_VERSION 0x00010108 ++#define RNDIS_OID_GEN_CO_PROTOCOL_OPTIONS 0x00010109 ++#define RNDIS_OID_GEN_CO_MAC_OPTIONS 0x0001010A ++#define RNDIS_OID_GEN_CO_MEDIA_CONNECT_STATUS 0x0001010B ++#define RNDIS_OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C ++#define RNDIS_OID_GEN_CO_MINIMUM_LINK_SPEED 0x0001010D ++ ++#define RNDIS_OID_GEN_CO_GET_TIME_CAPS 0x00010201 ++#define RNDIS_OID_GEN_CO_GET_NETCARD_TIME 0x00010202 ++ ++// ++// These are connection-oriented statistics OIDs. ++// ++#define RNDIS_OID_GEN_CO_XMIT_PDUS_OK 0x00020101 ++#define RNDIS_OID_GEN_CO_RCV_PDUS_OK 0x00020102 ++#define RNDIS_OID_GEN_CO_XMIT_PDUS_ERROR 0x00020103 ++#define RNDIS_OID_GEN_CO_RCV_PDUS_ERROR 0x00020104 ++#define RNDIS_OID_GEN_CO_RCV_PDUS_NO_BUFFER 0x00020105 ++ ++ ++#define RNDIS_OID_GEN_CO_RCV_CRC_ERROR 0x00020201 ++#define RNDIS_OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202 ++#define RNDIS_OID_GEN_CO_BYTES_XMIT 0x00020203 ++#define RNDIS_OID_GEN_CO_BYTES_RCV 0x00020204 ++#define RNDIS_OID_GEN_CO_BYTES_XMIT_OUTSTANDING 0x00020205 ++#define RNDIS_OID_GEN_CO_NETCARD_LOAD 0x00020206 ++ ++// ++// These are objects for Connection-oriented media call-managers. ++// ++#define RNDIS_OID_CO_ADD_PVC 0xFF000001 ++#define RNDIS_OID_CO_DELETE_PVC 0xFF000002 ++#define RNDIS_OID_CO_GET_CALL_INFORMATION 0xFF000003 ++#define RNDIS_OID_CO_ADD_ADDRESS 0xFF000004 ++#define RNDIS_OID_CO_DELETE_ADDRESS 0xFF000005 ++#define RNDIS_OID_CO_GET_ADDRESSES 0xFF000006 ++#define RNDIS_OID_CO_ADDRESS_CHANGE 0xFF000007 ++#define RNDIS_OID_CO_SIGNALING_ENABLED 0xFF000008 ++#define RNDIS_OID_CO_SIGNALING_DISABLED 0xFF000009 ++ ++ ++// ++// 802.3 Objects (Ethernet) ++// ++ ++#define RNDIS_OID_802_3_PERMANENT_ADDRESS 0x01010101 ++#define RNDIS_OID_802_3_CURRENT_ADDRESS 0x01010102 ++#define RNDIS_OID_802_3_MULTICAST_LIST 0x01010103 ++#define RNDIS_OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 ++#define RNDIS_OID_802_3_MAC_OPTIONS 0x01010105 ++ ++// ++// ++#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 ++ ++#define RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 ++#define RNDIS_OID_802_3_XMIT_ONE_COLLISION 0x01020102 ++#define RNDIS_OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 ++ ++#define RNDIS_OID_802_3_XMIT_DEFERRED 0x01020201 ++#define RNDIS_OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 ++#define RNDIS_OID_802_3_RCV_OVERRUN 0x01020203 ++#define RNDIS_OID_802_3_XMIT_UNDERRUN 0x01020204 ++#define RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 ++#define RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 ++#define RNDIS_OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 ++ ++ ++// ++// Remote NDIS message types ++// ++#define REMOTE_NDIS_PACKET_MSG 0x00000001 ++#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002 ++#define REMOTE_NDIS_HALT_MSG 0x00000003 ++#define REMOTE_NDIS_QUERY_MSG 0x00000004 ++#define REMOTE_NDIS_SET_MSG 0x00000005 ++#define REMOTE_NDIS_RESET_MSG 0x00000006 ++#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007 ++#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008 ++ ++#define REMOTE_CONDIS_MP_CREATE_VC_MSG 0x00008001 ++#define REMOTE_CONDIS_MP_DELETE_VC_MSG 0x00008002 ++#define REMOTE_CONDIS_MP_ACTIVATE_VC_MSG 0x00008005 ++#define REMOTE_CONDIS_MP_DEACTIVATE_VC_MSG 0x00008006 ++#define REMOTE_CONDIS_INDICATE_STATUS_MSG 0x00008007 ++ ++ ++// Remote NDIS message completion types ++#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002 ++#define REMOTE_NDIS_QUERY_CMPLT 0x80000004 ++#define REMOTE_NDIS_SET_CMPLT 0x80000005 ++#define REMOTE_NDIS_RESET_CMPLT 0x80000006 ++#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008 ++ ++#define REMOTE_CONDIS_MP_CREATE_VC_CMPLT 0x80008001 ++#define REMOTE_CONDIS_MP_DELETE_VC_CMPLT 0x80008002 ++#define REMOTE_CONDIS_MP_ACTIVATE_VC_CMPLT 0x80008005 ++#define REMOTE_CONDIS_MP_DEACTIVATE_VC_CMPLT 0x80008006 ++ ++// ++// Reserved message type for private communication between lower-layer ++// host driver and remote device, if necessary. ++// ++#define REMOTE_NDIS_BUS_MSG 0xff000001 ++ ++ ++ ++// ++// Defines for DeviceFlags in RNDIS_INITIALIZE_COMPLETE ++// ++#define RNDIS_DF_CONNECTIONLESS 0x00000001 ++#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002 ++#define RNDIS_DF_RAW_DATA 0x00000004 ++ ++// ++// Remote NDIS medium types. ++// ++#define RNdisMedium802_3 0x00000000 ++#define RNdisMedium802_5 0x00000001 ++#define RNdisMediumFddi 0x00000002 ++#define RNdisMediumWan 0x00000003 ++#define RNdisMediumLocalTalk 0x00000004 ++#define RNdisMediumArcnetRaw 0x00000006 ++#define RNdisMediumArcnet878_2 0x00000007 ++#define RNdisMediumAtm 0x00000008 ++#define RNdisMediumWirelessWan 0x00000009 ++#define RNdisMediumIrda 0x0000000a ++#define RNdisMediumCoWan 0x0000000b ++#define RNdisMediumMax 0x0000000d // Not a real medium, defined as an upper-bound ++ ++// ++// Remote NDIS medium connection states. ++// ++#define RNdisMediaStateConnected 0x00000000 ++#define RNdisMediaStateDisconnected 0x00000001 ++ ++// ++// Remote NDIS version numbers ++// ++#define RNDIS_MAJOR_VERSION 0x00000001 ++#define RNDIS_MINOR_VERSION 0x00000000 ++ ++// ++// NdisInitialize message ++// ++typedef struct _RNDIS_INITIALIZE_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ UINT32 MajorVersion; ++ UINT32 MinorVersion; ++ UINT32 MaxTransferSize; ++} RNDIS_INITIALIZE_REQUEST, *PRNDIS_INITIALIZE_REQUEST; ++ ++ ++// ++// Response to NdisInitialize ++// ++typedef struct _RNDIS_INITIALIZE_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++ UINT32 MajorVersion; ++ UINT32 MinorVersion; ++ UINT32 DeviceFlags; ++ RNDIS_MEDIUM Medium; ++ UINT32 MaxPacketsPerMessage; ++ UINT32 MaxTransferSize; ++ UINT32 PacketAlignmentFactor; ++ UINT32 AFListOffset; ++ UINT32 AFListSize; ++} RNDIS_INITIALIZE_COMPLETE, *PRNDIS_INITIALIZE_COMPLETE; ++ ++ ++// ++// Call manager devices only: Information about an address family ++// supported by the device is appended to the response to NdisInitialize. ++// ++typedef struct _RNDIS_CO_ADDRESS_FAMILY ++{ ++ RNDIS_AF AddressFamily; ++ UINT32 MajorVersion; ++ UINT32 MinorVersion; ++} RNDIS_CO_ADDRESS_FAMILY, *PRNDIS_CO_ADDRESS_FAMILY; ++ ++ ++// ++// NdisHalt message ++// ++typedef struct _RNDIS_HALT_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++} RNDIS_HALT_REQUEST, *PRNDIS_HALT_REQUEST; ++ ++ ++// ++// NdisQueryRequest message ++// ++typedef struct _RNDIS_QUERY_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_OID Oid; ++ UINT32 InformationBufferLength; ++ UINT32 InformationBufferOffset; ++ RNDIS_HANDLE DeviceVcHandle; ++} RNDIS_QUERY_REQUEST, *PRNDIS_QUERY_REQUEST; ++ ++ ++// ++// Response to NdisQueryRequest ++// ++typedef struct _RNDIS_QUERY_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++ UINT32 InformationBufferLength; ++ UINT32 InformationBufferOffset; ++} RNDIS_QUERY_COMPLETE, *PRNDIS_QUERY_COMPLETE; ++ ++ ++// ++// NdisSetRequest message ++// ++typedef struct _RNDIS_SET_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_OID Oid; ++ UINT32 InformationBufferLength; ++ UINT32 InformationBufferOffset; ++ RNDIS_HANDLE DeviceVcHandle; ++} RNDIS_SET_REQUEST, *PRNDIS_SET_REQUEST; ++ ++ ++// ++// Response to NdisSetRequest ++// ++typedef struct _RNDIS_SET_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++} RNDIS_SET_COMPLETE, *PRNDIS_SET_COMPLETE; ++ ++ ++// ++// NdisReset message ++// ++typedef struct _RNDIS_RESET_REQUEST ++{ ++ UINT32 Reserved; ++} RNDIS_RESET_REQUEST, *PRNDIS_RESET_REQUEST; ++ ++// ++// Response to NdisReset ++// ++typedef struct _RNDIS_RESET_COMPLETE ++{ ++ RNDIS_STATUS Status; ++ UINT32 AddressingReset; ++} RNDIS_RESET_COMPLETE, *PRNDIS_RESET_COMPLETE; ++ ++ ++// ++// NdisMIndicateStatus message ++// ++typedef struct _RNDIS_INDICATE_STATUS ++{ ++ RNDIS_STATUS Status; ++ UINT32 StatusBufferLength; ++ UINT32 StatusBufferOffset; ++} RNDIS_INDICATE_STATUS, *PRNDIS_INDICATE_STATUS; ++ ++ ++// ++// Diagnostic information passed as the status buffer in ++// RNDIS_INDICATE_STATUS messages signifying error conditions. ++// ++typedef struct _RNDIS_DIAGNOSTIC_INFO ++{ ++ RNDIS_STATUS DiagStatus; ++ UINT32 ErrorOffset; ++} RNDIS_DIAGNOSTIC_INFO, *PRNDIS_DIAGNOSTIC_INFO; ++ ++ ++ ++// ++// NdisKeepAlive message ++// ++typedef struct _RNDIS_KEEPALIVE_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++} RNDIS_KEEPALIVE_REQUEST, *PRNDIS_KEEPALIVE_REQUEST; ++ ++ ++// ++// Response to NdisKeepAlive ++// ++typedef struct _RNDIS_KEEPALIVE_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++} RNDIS_KEEPALIVE_COMPLETE, *PRNDIS_KEEPALIVE_COMPLETE; ++ ++ ++// ++// Data message. All Offset fields contain byte offsets from the beginning ++// of the RNDIS_PACKET structure. All Length fields are in bytes. ++// VcHandle is set to 0 for connectionless data, otherwise it ++// contains the VC handle. ++// ++typedef struct _RNDIS_PACKET ++{ ++ UINT32 DataOffset; ++ UINT32 DataLength; ++ UINT32 OOBDataOffset; ++ UINT32 OOBDataLength; ++ UINT32 NumOOBDataElements; ++ UINT32 PerPacketInfoOffset; ++ UINT32 PerPacketInfoLength; ++ RNDIS_HANDLE VcHandle; ++ UINT32 Reserved; ++} RNDIS_PACKET, *PRNDIS_PACKET; ++ ++// ++// Optional Out of Band data associated with a Data message. ++// ++typedef struct _RNDIS_OOBD ++{ ++ UINT32 Size; ++ RNDIS_CLASS_ID Type; ++ UINT32 ClassInformationOffset; ++} RNDIS_OOBD, *PRNDIS_OOBD; ++ ++// ++// Packet extension field contents associated with a Data message. ++// ++typedef struct _RNDIS_PER_PACKET_INFO ++{ ++ UINT32 Size; ++ UINT32 Type; ++ UINT32 PerPacketInformationOffset; ++} RNDIS_PER_PACKET_INFO, *PRNDIS_PER_PACKET_INFO; ++ ++ ++// ++// Format of Information buffer passed in a SetRequest for the OID ++// OID_GEN_RNDIS_CONFIG_PARAMETER. ++// ++typedef struct _RNDIS_CONFIG_PARAMETER_INFO ++{ ++ UINT32 ParameterNameOffset; ++ UINT32 ParameterNameLength; ++ UINT32 ParameterType; ++ UINT32 ParameterValueOffset; ++ UINT32 ParameterValueLength; ++} RNDIS_CONFIG_PARAMETER_INFO, *PRNDIS_CONFIG_PARAMETER_INFO; ++ ++// ++// Values for ParameterType in RNDIS_CONFIG_PARAMETER_INFO ++// ++#define RNDIS_CONFIG_PARAM_TYPE_INTEGER 0 ++#define RNDIS_CONFIG_PARAM_TYPE_STRING 2 ++ ++ ++// ++// CONDIS Miniport messages for connection oriented devices ++// that do not implement a call manager. ++// ++ ++// ++// CoNdisMiniportCreateVc message ++// ++typedef struct _RCONDIS_MP_CREATE_VC ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_HANDLE NdisVcHandle; ++} RCONDIS_MP_CREATE_VC, *PRCONDIS_MP_CREATE_VC; ++ ++// ++// Response to CoNdisMiniportCreateVc ++// ++typedef struct _RCONDIS_MP_CREATE_VC_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_HANDLE DeviceVcHandle; ++ RNDIS_STATUS Status; ++} RCONDIS_MP_CREATE_VC_COMPLETE, *PRCONDIS_MP_CREATE_VC_COMPLETE; ++ ++ ++// ++// CoNdisMiniportDeleteVc message ++// ++typedef struct _RCONDIS_MP_DELETE_VC ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_HANDLE DeviceVcHandle; ++} RCONDIS_MP_DELETE_VC, *PRCONDIS_MP_DELETE_VC; ++ ++// ++// Response to CoNdisMiniportDeleteVc ++// ++typedef struct _RCONDIS_MP_DELETE_VC_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++} RCONDIS_MP_DELETE_VC_COMPLETE, *PRCONDIS_MP_DELETE_VC_COMPLETE; ++ ++ ++// ++// CoNdisMiniportQueryRequest message ++// ++typedef struct _RCONDIS_MP_QUERY_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_REQUEST_TYPE RequestType; ++ RNDIS_OID Oid; ++ RNDIS_HANDLE DeviceVcHandle; ++ UINT32 InformationBufferLength; ++ UINT32 InformationBufferOffset; ++} RCONDIS_MP_QUERY_REQUEST, *PRCONDIS_MP_QUERY_REQUEST; ++ ++ ++// ++// CoNdisMiniportSetRequest message ++// ++typedef struct _RCONDIS_MP_SET_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_REQUEST_TYPE RequestType; ++ RNDIS_OID Oid; ++ RNDIS_HANDLE DeviceVcHandle; ++ UINT32 InformationBufferLength; ++ UINT32 InformationBufferOffset; ++} RCONDIS_MP_SET_REQUEST, *PRCONDIS_MP_SET_REQUEST; ++ ++ ++// ++// CoNdisIndicateStatus message ++// ++typedef struct _RCONDIS_INDICATE_STATUS ++{ ++ RNDIS_HANDLE NdisVcHandle; ++ RNDIS_STATUS Status; ++ UINT32 StatusBufferLength; ++ UINT32 StatusBufferOffset; ++} RCONDIS_INDICATE_STATUS, *PRCONDIS_INDICATE_STATUS; ++ ++ ++// ++// CONDIS Call/VC parameters ++// ++ ++typedef struct _RCONDIS_SPECIFIC_PARAMETERS ++{ ++ UINT32 ParameterType; ++ UINT32 ParameterLength; ++ UINT32 ParameterOffset; ++} RCONDIS_SPECIFIC_PARAMETERS, *PRCONDIS_SPECIFIC_PARAMETERS; ++ ++typedef struct _RCONDIS_MEDIA_PARAMETERS ++{ ++ UINT32 Flags; ++ UINT32 Reserved1; ++ UINT32 Reserved2; ++ RCONDIS_SPECIFIC_PARAMETERS MediaSpecific; ++} RCONDIS_MEDIA_PARAMETERS, *PRCONDIS_MEDIA_PARAMETERS; ++ ++ ++typedef struct _RNDIS_FLOWSPEC ++{ ++ UINT32 TokenRate; ++ UINT32 TokenBucketSize; ++ UINT32 PeakBandwidth; ++ UINT32 Latency; ++ UINT32 DelayVariation; ++ UINT32 ServiceType; ++ UINT32 MaxSduSize; ++ UINT32 MinimumPolicedSize; ++} RNDIS_FLOWSPEC, *PRNDIS_FLOWSPEC; ++ ++typedef struct _RCONDIS_CALL_MANAGER_PARAMETERS ++{ ++ RNDIS_FLOWSPEC Transmit; ++ RNDIS_FLOWSPEC Receive; ++ RCONDIS_SPECIFIC_PARAMETERS CallMgrSpecific; ++} RCONDIS_CALL_MANAGER_PARAMETERS, *PRCONDIS_CALL_MANAGER_PARAMETERS; ++ ++// ++// CoNdisMiniportActivateVc message ++// ++typedef struct _RCONDIS_MP_ACTIVATE_VC_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ UINT32 Flags; ++ RNDIS_HANDLE DeviceVcHandle; ++ UINT32 MediaParamsOffset; ++ UINT32 MediaParamsLength; ++ UINT32 CallMgrParamsOffset; ++ UINT32 CallMgrParamsLength; ++} RCONDIS_MP_ACTIVATE_VC_REQUEST, *PRCONDIS_MP_ACTIVATE_VC_REQUEST; ++ ++// ++// Response to CoNdisMiniportActivateVc ++// ++typedef struct _RCONDIS_MP_ACTIVATE_VC_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++} RCONDIS_MP_ACTIVATE_VC_COMPLETE, *PRCONDIS_MP_ACTIVATE_VC_COMPLETE; ++ ++ ++// ++// CoNdisMiniportDeactivateVc message ++// ++typedef struct _RCONDIS_MP_DEACTIVATE_VC_REQUEST ++{ ++ RNDIS_REQUEST_ID RequestId; ++ UINT32 Flags; ++ RNDIS_HANDLE DeviceVcHandle; ++} RCONDIS_MP_DEACTIVATE_VC_REQUEST, *PRCONDIS_MP_DEACTIVATE_VC_REQUEST; ++ ++// ++// Response to CoNdisMiniportDeactivateVc ++// ++typedef struct _RCONDIS_MP_DEACTIVATE_VC_COMPLETE ++{ ++ RNDIS_REQUEST_ID RequestId; ++ RNDIS_STATUS Status; ++} RCONDIS_MP_DEACTIVATE_VC_COMPLETE, *PRCONDIS_MP_DEACTIVATE_VC_COMPLETE; ++ ++ ++// ++// union with all of the RNDIS messages ++// ++typedef union _RNDIS_MESSAGE_CONTAINER ++{ ++ RNDIS_PACKET Packet; ++ RNDIS_INITIALIZE_REQUEST InitializeRequest; ++ RNDIS_HALT_REQUEST HaltRequest; ++ RNDIS_QUERY_REQUEST QueryRequest; ++ RNDIS_SET_REQUEST SetRequest; ++ RNDIS_RESET_REQUEST ResetRequest; ++ RNDIS_KEEPALIVE_REQUEST KeepaliveRequest; ++ RNDIS_INDICATE_STATUS IndicateStatus; ++ RNDIS_INITIALIZE_COMPLETE InitializeComplete; ++ RNDIS_QUERY_COMPLETE QueryComplete; ++ RNDIS_SET_COMPLETE SetComplete; ++ RNDIS_RESET_COMPLETE ResetComplete; ++ RNDIS_KEEPALIVE_COMPLETE KeepaliveComplete; ++ RCONDIS_MP_CREATE_VC CoMiniportCreateVc; ++ RCONDIS_MP_DELETE_VC CoMiniportDeleteVc; ++ RCONDIS_INDICATE_STATUS CoIndicateStatus; ++ RCONDIS_MP_ACTIVATE_VC_REQUEST CoMiniportActivateVc; ++ RCONDIS_MP_DEACTIVATE_VC_REQUEST CoMiniportDeactivateVc; ++ RCONDIS_MP_CREATE_VC_COMPLETE CoMiniportCreateVcComplete; ++ RCONDIS_MP_DELETE_VC_COMPLETE CoMiniportDeleteVcComplete; ++ RCONDIS_MP_ACTIVATE_VC_COMPLETE CoMiniportActivateVcComplete; ++ RCONDIS_MP_DEACTIVATE_VC_COMPLETE CoMiniportDeactivateVcComplete; ++ ++ ++} RNDIS_MESSAGE_CONTAINER, *PRNDIS_MESSAGE_CONTAINER; ++ ++// ++// Remote NDIS message format ++// ++typedef __struct_bcount(MessageLength) struct _RNDIS_MESSAGE ++{ ++ UINT32 NdisMessageType; ++ ++ // ++ // Total length of this message, from the beginning ++ // of the RNDIS_MESSAGE struct, in bytes. ++ // ++ UINT32 MessageLength; ++ ++ // Actual message ++ RNDIS_MESSAGE_CONTAINER Message; ++ ++} RNDIS_MESSAGE, *PRNDIS_MESSAGE; ++ ++ ++ ++// ++// Handy macros ++ ++// get the size of an RNDIS message. Pass in the message type, ++// RNDIS_SET_REQUEST, RNDIS_PACKET for example ++#define RNDIS_MESSAGE_SIZE(Message) \ ++ (sizeof(Message) + (sizeof(RNDIS_MESSAGE) - sizeof(RNDIS_MESSAGE_CONTAINER))) ++ ++// get pointer to info buffer with message pointer ++#define MESSAGE_TO_INFO_BUFFER(Message) \ ++ (((PUCHAR)(Message)) + Message->InformationBufferOffset) ++ ++// get pointer to status buffer with message pointer ++#define MESSAGE_TO_STATUS_BUFFER(Message) \ ++ (((PUCHAR)(Message)) + Message->StatusBufferOffset) ++ ++// get pointer to OOBD buffer with message pointer ++#define MESSAGE_TO_OOBD_BUFFER(Message) \ ++ (((PUCHAR)(Message)) + Message->OOBDataOffset) ++ ++// get pointer to data buffer with message pointer ++#define MESSAGE_TO_DATA_BUFFER(Message) \ ++ (((PUCHAR)(Message)) + Message->PerPacketInfoOffset) ++ ++// get pointer to contained message from NDIS_MESSAGE pointer ++#define RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(RndisMessage) \ ++ ((PVOID) &RndisMessage->Message) ++ ++// get pointer to contained message from NDIS_MESSAGE pointer ++#define RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(RndisMessage) \ ++ ((PVOID) RndisMessage) ++ ++#endif // _RNDIS_H_ +--- /dev/null ++++ b/drivers/staging/hv/include/VmbusChannelInterface.h +@@ -0,0 +1,131 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++// allow nameless unions ++//#pragma warning(disable : 4201) ++ ++// ++// A revision number of vmbus that is used for ensuring both ends on a ++// partition are using compatible versions. ++// ++#define VMBUS_REVISION_NUMBER 13 ++ ++// ++// Make maximum size of pipe payload of 16K ++// ++#define MAX_PIPE_DATA_PAYLOAD (sizeof(BYTE) * 16384) ++ ++// ++// Define PipeMode values. ++// ++#define VMBUS_PIPE_TYPE_BYTE 0x00000000 ++#define VMBUS_PIPE_TYPE_MESSAGE 0x00000004 ++ ++// ++// The size of the user defined data buffer for non-pipe offers. ++// ++#define MAX_USER_DEFINED_BYTES 120 ++ ++// ++// The size of the user defined data buffer for pipe offers. ++// ++#define MAX_PIPE_USER_DEFINED_BYTES 116 ++ ++ ++// ++// At the center of the Channel Management library is ++// the Channel Offer. This struct contains the ++// fundamental information about an offer. ++// ++#pragma pack(push,1) ++ ++typedef struct ++{ ++ ++ GUID InterfaceType; ++ GUID InterfaceInstance; ++ UINT64 InterruptLatencyIn100nsUnits; ++ UINT32 InterfaceRevision; ++ UINT32 ServerContextAreaSize; // in bytes ++ UINT16 ChannelFlags; ++ UINT16 MmioMegabytes; // in bytes * 1024 * 1024 ++ ++ union ++ { ++ // ++ // Non-pipes: The user has MAX_USER_DEFINED_BYTES bytes. ++ // ++ struct ++ { ++ UCHAR UserDefined[MAX_USER_DEFINED_BYTES]; ++ } Standard; ++ ++ // ++ // Pipes: The following sructure is an integrated pipe protocol, which ++ // is implemented on top of standard user-defined data. Pipe clients ++ // have MAX_PIPE_USER_DEFINED_BYTES left for their own use. ++ // ++ struct ++ { ++ UINT32 PipeMode; ++ UCHAR UserDefined[MAX_PIPE_USER_DEFINED_BYTES]; ++ } Pipe; ++ } u; ++ UINT32 Padding; ++} VMBUS_CHANNEL_OFFER, *PVMBUS_CHANNEL_OFFER; ++#pragma pack(pop) ++ ++ ++// ++// Verify the MAX_PIPE_USER_DEFINED_BYTES value. ++// ++//C_ASSERT(MAX_PIPE_USER_DEFINED_BYTES == ++// MAX_USER_DEFINED_BYTES - ++// (FIELD_OFFSET(VMBUS_CHANNEL_OFFER, u.Pipe.UserDefined) - ++// FIELD_OFFSET(VMBUS_CHANNEL_OFFER, u.Standard.UserDefined))); ++// ++ ++typedef UINT32 GPADL_HANDLE; ++ ++// ++// Server Flags ++// ++ ++#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE 1 ++#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES 2 ++#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS 4 ++#define VMBUS_CHANNEL_NAMED_PIPE_MODE 0x10 ++#define VMBUS_CHANNEL_LOOPBACK_OFFER 0x100 ++#define VMBUS_CHANNEL_PARENT_OFFER 0x200 ++#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION 0x400 ++ ++// ++// TEMPTEMP -- move this next define to devioctl.h some day ++// ++ ++#ifndef FILE_DEVICE_VMBUS ++#define FILE_DEVICE_VMBUS 0x0000003E ++#endif ++ +--- /dev/null ++++ b/drivers/staging/hv/include/VmbusPacketFormat.h +@@ -0,0 +1,322 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++//#ifndef PAGE_SIZE ++//#if defined(_IA64_) ++//#error This does not work for IA64 ++//#else ++//#define PAGE_SIZE 0x1000 ++//#endif ++//#endif ++ ++// allow nameless unions ++//#pragma warning(disable : 4201) ++ ++typedef struct ++{ ++ union ++ { ++ struct ++ { ++ volatile UINT32 In; // Offset in bytes from the ring base ++ volatile UINT32 Out; // Offset in bytes from the ring base ++ }; ++ volatile LONGLONG InOut; ++ }; ++ ++ // ++ // If the receiving endpoint sets this to some non-zero value, the sending ++ // endpoint should not send any interrupts. ++ // ++ ++ volatile UINT32 InterruptMask; ++ ++} VMRCB, *PVMRCB; ++ ++typedef struct ++{ ++ union ++ { ++ struct ++ { ++ VMRCB Control; ++ }; ++ ++ UINT8 Reserved[PAGE_SIZE]; ++ }; ++ ++ // ++ // Beginning of the ring data. Note: It must be guaranteed that ++ // this data does not share a page with the control structure. ++ // ++ UINT8 Data[1]; ++} VMRING, *PVMRING; ++ ++#pragma pack(push, 1) ++ ++typedef struct ++{ ++ UINT16 Type; ++ UINT16 DataOffset8; ++ UINT16 Length8; ++ UINT16 Flags; ++ UINT64 TransactionId; ++} VMPACKET_DESCRIPTOR, *PVMPACKET_DESCRIPTOR; ++ ++typedef UINT32 PREVIOUS_PACKET_OFFSET, *PPREVIOUS_PACKET_OFFSET; ++ ++typedef struct ++{ ++ PREVIOUS_PACKET_OFFSET PreviousPacketStartOffset; ++ VMPACKET_DESCRIPTOR Descriptor; ++} VMPACKET_HEADER, *PVMPACKET_HEADER; ++ ++typedef struct ++{ ++ UINT32 ByteCount; ++ UINT32 ByteOffset; ++} VMTRANSFER_PAGE_RANGE, *PVMTRANSFER_PAGE_RANGE; ++ ++#ifdef __cplusplus ++ ++typedef struct _VMTRANSFER_PAGE_PACKET_HEADER : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct VMTRANSFER_PAGE_PACKET_HEADER { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ UINT16 TransferPageSetId; ++ BOOLEAN SenderOwnsSet; ++ UINT8 Reserved; ++ UINT32 RangeCount; ++ VMTRANSFER_PAGE_RANGE Ranges[1]; ++ ++} VMTRANSFER_PAGE_PACKET_HEADER, *PVMTRANSFER_PAGE_PACKET_HEADER; ++ ++ ++#ifdef __cplusplus ++ ++typedef struct _VMGPADL_PACKET_HEADER : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct _VMGPADL_PACKET_HEADER { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ ++ UINT32 Gpadl; ++ UINT32 Reserved; ++ ++} VMGPADL_PACKET_HEADER, *PVMGPADL_PACKET_HEADER; ++ ++#ifdef __cplusplus ++ ++typedef struct _VMADD_REMOVE_TRANSFER_PAGE_SET : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct _VMADD_REMOVE_TRANSFER_PAGE_SET { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ UINT32 Gpadl; ++ UINT16 TransferPageSetId; ++ UINT16 Reserved; ++ ++} VMADD_REMOVE_TRANSFER_PAGE_SET, *PVMADD_REMOVE_TRANSFER_PAGE_SET; ++ ++#pragma pack(pop) ++ ++// ++// This structure defines a range in guest physical space that can be made ++// to look virtually contiguous. ++// ++ ++typedef struct _GPA_RANGE { ++ ++ UINT32 ByteCount; ++ UINT32 ByteOffset; ++ UINT64 PfnArray[0]; ++ ++} GPA_RANGE, *PGPA_RANGE; ++ ++ ++ ++#pragma pack(push, 1) ++ ++// ++// This is the format for an Establish Gpadl packet, which contains a handle ++// by which this GPADL will be known and a set of GPA ranges associated with ++// it. This can be converted to a MDL by the guest OS. If there are multiple ++// GPA ranges, then the resulting MDL will be "chained," representing multiple ++// VA ranges. ++// ++ ++#ifdef __cplusplus ++ ++typedef struct _VMESTABLISH_GPADL : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct _VMESTABLISH_GPADL { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ UINT32 Gpadl; ++ UINT32 RangeCount; ++ GPA_RANGE Range[1]; ++ ++} VMESTABLISH_GPADL, *PVMESTABLISH_GPADL; ++ ++ ++// ++// This is the format for a Teardown Gpadl packet, which indicates that the ++// GPADL handle in the Establish Gpadl packet will never be referenced again. ++// ++ ++#ifdef __cplusplus ++ ++typedef struct _VMTEARDOWN_GPADL : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct _VMTEARDOWN_GPADL { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ UINT32 Gpadl; ++ UINT32 Reserved; // for alignment to a 8-byte boundary ++} VMTEARDOWN_GPADL, *PVMTEARDOWN_GPADL; ++ ++ ++// ++// This is the format for a GPA-Direct packet, which contains a set of GPA ++// ranges, in addition to commands and/or data. ++// ++ ++#ifdef __cplusplus ++ ++typedef struct _VMDATA_GPA_DIRECT : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct _VMDATA_GPA_DIRECT { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ UINT32 Reserved; ++ UINT32 RangeCount; ++ GPA_RANGE Range[1]; ++ ++} VMDATA_GPA_DIRECT, *PVMDATA_GPA_DIRECT; ++ ++ ++ ++// ++// This is the format for a Additional Data Packet. ++// ++ ++#ifdef __cplusplus ++ ++typedef struct _VMADDITIONAL_DATA : VMPACKET_DESCRIPTOR { ++ ++#else ++ ++typedef struct _VMADDITIONAL_DATA { ++ ++ VMPACKET_DESCRIPTOR d; ++ ++#endif ++ ++ UINT64 TotalBytes; ++ UINT32 ByteOffset; ++ UINT32 ByteCount; ++ UCHAR Data[1]; ++ ++} VMADDITIONAL_DATA, *PVMADDITIONAL_DATA; ++ ++ ++#pragma pack(pop) ++ ++typedef union { ++ VMPACKET_DESCRIPTOR SimpleHeader; ++ VMTRANSFER_PAGE_PACKET_HEADER TransferPageHeader; ++ VMGPADL_PACKET_HEADER GpadlHeader; ++ VMADD_REMOVE_TRANSFER_PAGE_SET AddRemoveTransferPageHeader; ++ VMESTABLISH_GPADL EstablishGpadlHeader; ++ VMTEARDOWN_GPADL TeardownGpadlHeader; ++ VMDATA_GPA_DIRECT DataGpaDirectHeader; ++} VMPACKET_LARGEST_POSSIBLE_HEADER, *PVMPACKET_LARGEST_POSSIBLE_HEADER; ++ ++#define VMPACKET_DATA_START_ADDRESS(__packet) \ ++ (PVOID)(((PUCHAR)__packet) + ((PVMPACKET_DESCRIPTOR)__packet)->DataOffset8 * 8) ++ ++#define VMPACKET_DATA_LENGTH(__packet) \ ++ ((((PVMPACKET_DESCRIPTOR)__packet)->Length8 - ((PVMPACKET_DESCRIPTOR)__packet)->DataOffset8) * 8) ++ ++#define VMPACKET_TRANSFER_MODE(__packet) ((PVMPACKET_DESCRIPTOR)__packet)->Type ++ ++typedef enum { ++ VmbusServerEndpoint = 0, ++ VmbusClientEndpoint, ++ VmbusEndpointMaximum ++} ENDPOINT_TYPE, *PENDPOINT_TYPE; ++ ++typedef enum { ++ VmbusPacketTypeInvalid = 0x0, ++ VmbusPacketTypeSynch = 0x1, ++ VmbusPacketTypeAddTransferPageSet = 0x2, ++ VmbusPacketTypeRemoveTransferPageSet = 0x3, ++ VmbusPacketTypeEstablishGpadl = 0x4, ++ VmbusPacketTypeTearDownGpadl = 0x5, ++ VmbusPacketTypeDataInBand = 0x6, ++ VmbusPacketTypeDataUsingTransferPages = 0x7, ++ VmbusPacketTypeDataUsingGpadl = 0x8, ++ VmbusPacketTypeDataUsingGpaDirect = 0x9, ++ VmbusPacketTypeCancelRequest = 0xa, ++ VmbusPacketTypeCompletion = 0xb, ++ VmbusPacketTypeDataUsingAdditionalPackets = 0xc, ++ VmbusPacketTypeAdditionalData = 0xd ++} VMBUS_PACKET_TYPE, *PVMBUS_PACKET_TYPE; ++ ++#define VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED 1 ++ ++ +--- /dev/null ++++ b/drivers/staging/hv/include/vstorage.h +@@ -0,0 +1,309 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++//#include ++//#include ++ ++#define C_ASSERT(x) ++// ++// public interface to the server ++// ++ ++// ++// Storvsp device interface guid ++// ++ ++ ++// ++// Protocol versions. ++// ++ ++// ++// vstorage.w revision number. This is used in the case of a version match, ++// to alert the user that structure sizes may be mismatched even though the ++// protocol versions match. ++// ++ ++#define REVISION_STRING(REVISION_) #REVISION_ ++#define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \ ++{ \ ++ char *revisionString = REVISION_STRING($Revision: 6 $) + 11; \ ++ RESULT_LVALUE_ = 0; \ ++ while (*revisionString >= '0' && *revisionString <= '9') \ ++ { \ ++ RESULT_LVALUE_ *= 10; \ ++ RESULT_LVALUE_ += *revisionString - '0'; \ ++ revisionString++; \ ++ } \ ++} ++ ++// ++// Major/minor macros. Minor version is in LSB, meaning that earlier flat ++// version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). ++// ++ ++#define VMSTOR_PROTOCOL_MAJOR(VERSION_) (((VERSION_) >> 8) & 0xff) ++#define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_) ) & 0xff) ++#define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ ++ (((MINOR_) & 0xff) )) ++ ++// ++// Invalid version. ++// ++ ++#define VMSTOR_INVALID_PROTOCOL_VERSION -1 ++ ++// ++// Version history: ++// V1 Beta 0.1 ++// V1 RC < 2008/1/31 1.0 ++// V1 RC > 2008/1/31 2.0 ++// ++#define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(2, 0) ++ ++ ++// ++// This will get replaced with the max transfer length that is possible on ++// the host adapter. ++// The max transfer length will be published when we offer a vmbus channel. ++// ++ ++#define MAX_TRANSFER_LENGTH 0x40000 ++#define DEFAULT_PACKET_SIZE (sizeof(VMDATA_GPA_DIRECT) + \ ++ sizeof(VSTOR_PACKET) + \ ++ (sizeof(UINT64) * (MAX_TRANSFER_LENGTH / PAGE_SIZE))) ++ ++ ++ ++// ++// Packet structure describing virtual storage requests. ++// ++ ++typedef enum ++{ ++ VStorOperationCompleteIo = 1, ++ VStorOperationRemoveDevice = 2, ++ VStorOperationExecuteSRB = 3, ++ VStorOperationResetLun = 4, ++ VStorOperationResetAdapter = 5, ++ VStorOperationResetBus = 6, ++ VStorOperationBeginInitialization = 7, ++ VStorOperationEndInitialization = 8, ++ VStorOperationQueryProtocolVersion = 9, ++ VStorOperationQueryProperties = 10, ++ VStorOperationMaximum = 10 ++ ++} VSTOR_PACKET_OPERATION; ++ ++ ++// ++// Platform neutral description of a scsi request - ++// this remains the same across the write regardless of 32/64 bit ++// note: it's patterned off the SCSI_PASS_THROUGH structure ++// ++ ++ ++#pragma pack(push,1) ++ ++ ++#define CDB16GENERIC_LENGTH 0x10 ++ ++#ifndef SENSE_BUFFER_SIZE ++#define SENSE_BUFFER_SIZE 0x12 ++#endif ++C_ASSERT(SENSE_BUFFER_SIZE == 0x12); ++ ++#define MAX_DATA_BUFFER_LENGTH_WITH_PADDING 0x14 ++ ++ ++typedef struct ++{ ++ USHORT Length; ++ UCHAR SrbStatus; ++ UCHAR ScsiStatus; ++ ++ UCHAR PortNumber; ++ UCHAR PathId; ++ UCHAR TargetId; ++ UCHAR Lun; ++ ++ UCHAR CdbLength; ++ UCHAR SenseInfoLength; ++ UCHAR DataIn; ++ UCHAR Reserved; ++ ++ ULONG DataTransferLength; ++ ++ union ++ { ++ UCHAR Cdb[CDB16GENERIC_LENGTH]; ++ ++ UCHAR SenseData[SENSE_BUFFER_SIZE]; ++ ++ UCHAR ReservedArray[MAX_DATA_BUFFER_LENGTH_WITH_PADDING]; ++ }; ++ ++} VMSCSI_REQUEST, *PVMSCSI_REQUEST; ++ ++C_ASSERT((sizeof(VMSCSI_REQUEST) % 4) == 0); ++ ++ ++// ++// This structure is sent during the intialization phase to get the different ++// properties of the channel. ++// ++ ++typedef struct ++{ ++ USHORT ProtocolVersion; ++ UCHAR PathId; ++ UCHAR TargetId; ++ ++ // ++ // Note: port number is only really known on the client side ++ // ++ ULONG PortNumber; ++ ++ ULONG Flags; ++ ++ ULONG MaxTransferBytes; ++ ++ // ++ // This id is unique for each channel and will correspond with ++ // vendor specific data in the inquirydata ++ // ++ ++ ULONGLONG UniqueId; ++ ++} VMSTORAGE_CHANNEL_PROPERTIES, *PVMSTORAGE_CHANNEL_PROPERTIES; ++ ++C_ASSERT((sizeof(VMSTORAGE_CHANNEL_PROPERTIES) % 4) == 0); ++ ++ ++// ++// This structure is sent during the storage protocol negotiations. ++// ++ ++typedef struct ++{ ++ // ++ // Major (MSW) and minor (LSW) version numbers. ++ // ++ ++ USHORT MajorMinor; ++ ++ ++ // ++ // Revision number is auto-incremented whenever this file is changed ++ // (See FILL_VMSTOR_REVISION macro above). Mismatch does not definitely ++ // indicate incompatibility--but it does indicate mismatched builds. ++ // ++ ++ USHORT Revision; ++ ++} VMSTORAGE_PROTOCOL_VERSION, *PVMSTORAGE_PROTOCOL_VERSION; ++ ++C_ASSERT((sizeof(VMSTORAGE_PROTOCOL_VERSION) % 4) == 0); ++ ++ ++// ++// Channel Property Flags ++// ++ ++#define STORAGE_CHANNEL_REMOVABLE_FLAG 0x1 ++#define STORAGE_CHANNEL_EMULATED_IDE_FLAG 0x2 ++ ++ ++typedef struct _VSTOR_PACKET ++{ ++ // ++ // Requested operation type ++ // ++ ++ VSTOR_PACKET_OPERATION Operation; ++ ++ // ++ // Flags - see below for values ++ // ++ ++ ULONG Flags; ++ ++ // ++ // Status of the request returned from the server side. ++ // ++ ++ ULONG Status; ++ ++ // ++ // Data payload area ++ // ++ ++ union ++ { ++ // ++ // Structure used to forward SCSI commands from the client to the server. ++ // ++ ++ VMSCSI_REQUEST VmSrb; ++ ++ // ++ // Structure used to query channel properties. ++ // ++ ++ VMSTORAGE_CHANNEL_PROPERTIES StorageChannelProperties; ++ ++ // ++ // Used during version negotiations. ++ // ++ ++ VMSTORAGE_PROTOCOL_VERSION Version; ++ }; ++ ++} VSTOR_PACKET, *PVSTOR_PACKET; ++ ++C_ASSERT((sizeof(VSTOR_PACKET) % 4) == 0); ++ ++// ++// Packet flags ++// ++ ++// ++// This flag indicates that the server should send back a completion for this ++// packet. ++// ++ ++#define REQUEST_COMPLETION_FLAG 0x1 ++ ++// ++// This is the set of flags that the vsc can set in any packets it sends ++// ++ ++#define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG) ++ ++ ++#pragma pack(pop) ++ ++ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-driver-header-files.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-driver-header-files.patch new file mode 100644 index 000000000..42c74e5d7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-driver-header-files.patch @@ -0,0 +1,1098 @@ +From bee20ea87b3e6f246b387f707983a0ef47c8a15b Mon Sep 17 00:00:00 2001 +From: Hank Janssen +Date: Mon, 13 Jul 2009 15:19:28 -0700 +Subject: Staging: hv: add the Hyper-V driver header files + +From: Hank Janssen + +These are the header files for the different Linux Hyper-V drivers to +use. + +Signed-off-by: Hank Janssen +Signed-off-by: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/hv/include/NetVscApi.h | 145 +++++++++++++++++ + drivers/staging/hv/include/StorVscApi.h | 137 ++++++++++++++++ + drivers/staging/hv/include/VmbusApi.h | 262 +++++++++++++++++++++++++++++++ + drivers/staging/hv/include/logging.h | 134 ++++++++++++++++ + drivers/staging/hv/include/osd.h | 263 ++++++++++++++++++++++++++++++++ + drivers/staging/hv/include/vmbus.h | 111 +++++++++++++ + 6 files changed, 1052 insertions(+) + create mode 100644 drivers/staging/hv/include/NetVscApi.h + create mode 100644 drivers/staging/hv/include/StorVscApi.h + create mode 100644 drivers/staging/hv/include/VmbusApi.h + create mode 100644 drivers/staging/hv/include/logging.h + create mode 100644 drivers/staging/hv/include/osd.h + create mode 100644 drivers/staging/hv/include/vmbus.h + +--- /dev/null ++++ b/drivers/staging/hv/include/logging.h +@@ -0,0 +1,134 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _LOGGING_H_ ++#define _LOGGING_H_ ++ ++//#include ++//#include ++ ++#include "osd.h" ++ ++#define VMBUS 0x0001 ++#define STORVSC 0x0002 ++#define NETVSC 0x0004 ++#define INPUTVSC 0x0008 ++#define BLKVSC 0x0010 ++#define VMBUS_DRV 0x0100 ++#define STORVSC_DRV 0x0200 ++#define NETVSC_DRV 0x0400 ++#define INPUTVSC_DRV 0x0800 ++#define BLKVSC_DRV 0x1000 ++ ++#define ALL_MODULES (VMBUS |\ ++ STORVSC |\ ++ NETVSC |\ ++ INPUTVSC |\ ++ BLKVSC |\ ++ VMBUS_DRV |\ ++ STORVSC_DRV |\ ++ NETVSC_DRV |\ ++ INPUTVSC_DRV|\ ++ BLKVSC_DRV) ++ ++// Logging Level ++#define CRITICAL_LVL 2 ++#define ERROR_LVL 3 ++#define WARNING_LVL 4 ++#define INFO_LVL 6 ++#define DEBUG_LVL 7 ++#define DEBUG_LVL_ENTEREXIT 8 ++#define DEBUG_RING_LVL 9 ++ ++extern unsigned int vmbus_loglevel; ++ ++#define ASSERT(expr) \ ++ if (!(expr)) { \ ++ LogMsg("<%d>Assertion failed! %s,%s,%s,line=%d\n", CRITICAL_LVL, #expr,__FILE__,__FUNCTION__,__LINE__); \ ++ __asm__ __volatile__("int3"); \ ++ } ++ ++#define DPRINT(mod, lvl, fmt, args...) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (lvl <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" #mod": %s() " fmt "\n", DEBUG_LVL, __FUNCTION__, ## args)):(0);\ ++ } while (0) ++ ++#define DPRINT_DBG(mod, fmt, args...) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (DEBUG_LVL <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" #mod": %s() " fmt "\n", DEBUG_LVL, __FUNCTION__, ## args)):(0);\ ++ } while (0) ++ ++#define DPRINT_INFO(mod, fmt, args...) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (INFO_LVL <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" #mod": " fmt "\n", INFO_LVL, ## args)):(0);\ ++ } while (0) ++ ++#define DPRINT_WARN(mod, fmt, args...) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (WARNING_LVL <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" #mod": WARNING! " fmt "\n", WARNING_LVL, ## args)):(0);\ ++ } while (0) ++ ++#define DPRINT_ERR(mod, fmt, args...) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (ERROR_LVL <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" #mod": %s() ERROR!! " fmt "\n", ERROR_LVL, __FUNCTION__, ## args)):(0);\ ++ } while (0) ++ ++#ifdef DEBUG ++#define DPRINT_ENTER(mod) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (DEBUG_LVL_ENTEREXIT <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" "["#mod"]: %s() enter\n", DEBUG_LVL, __FUNCTION__)):(0);\ ++ } while (0) ++ ++#define DPRINT_EXIT(mod) do {\ ++ if (mod & (HIWORD(vmbus_loglevel))) \ ++ (DEBUG_LVL_ENTEREXIT <= LOWORD(vmbus_loglevel))?(LogMsg("<%d>" "["#mod"]: %s() exit\n", DEBUG_LVL, __FUNCTION__)):(0);\ ++ } while (0) ++#else ++#define DPRINT_ENTER(mod) ++#define DPRINT_EXIT(mod) ++#endif ++ ++static inline void PrintBytes(const unsigned char* bytes, int len) ++{ ++ int i=0; ++ ++ LogMsg("\n<< "); ++ for (i=0; i< len; i++) ++ { ++ LogMsg("0x%x ", bytes[i]); ++ } ++ LogMsg(">>\n"); ++} ++ ++// ++// Inline ++// ++//static inline void GuidToStr(const GUID g, char *str) ++//{ ++// sprintf(str, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++// g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]); ++// ++//} ++ ++#endif //_LOGGING_H_ +--- /dev/null ++++ b/drivers/staging/hv/include/NetVscApi.h +@@ -0,0 +1,145 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _NETVSC_API_H_ ++#define _NETVSC_API_H_ ++ ++#include "VmbusApi.h" ++ ++// ++// Defines ++// ++#define NETVSC_DEVICE_RING_BUFFER_SIZE 64*PAGE_SIZE ++ ++#define HW_MACADDR_LEN 6 ++ ++// ++// Fwd declaration ++// ++typedef struct _NETVSC_PACKET *PNETVSC_PACKET; ++ ++ ++// ++// Data types ++// ++ ++typedef int (*PFN_ON_OPEN)(DEVICE_OBJECT *Device); ++typedef int (*PFN_ON_CLOSE)(DEVICE_OBJECT *Device); ++ ++typedef void (*PFN_QUERY_LINKSTATUS)(DEVICE_OBJECT *Device); ++typedef int (*PFN_ON_SEND)(DEVICE_OBJECT *dev, PNETVSC_PACKET packet); ++typedef void (*PFN_ON_SENDRECVCOMPLETION)(PVOID Context); ++ ++typedef int (*PFN_ON_RECVCALLBACK)(DEVICE_OBJECT *dev, PNETVSC_PACKET packet); ++typedef void (*PFN_ON_LINKSTATUS_CHANGED)(DEVICE_OBJECT *dev, UINT32 Status); ++ ++// Represent the xfer page packet which contains 1 or more netvsc packet ++typedef struct _XFERPAGE_PACKET { ++ DLIST_ENTRY ListEntry; ++ ++ // # of netvsc packets this xfer packet contains ++ UINT32 Count; ++} XFERPAGE_PACKET; ++ ++ ++// The number of pages which are enough to cover jumbo frame buffer. ++#define NETVSC_PACKET_MAXPAGE 4 ++ ++// Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame within the RNDIS ++typedef struct _NETVSC_PACKET { ++ // Bookkeeping stuff ++ DLIST_ENTRY ListEntry; ++ ++ DEVICE_OBJECT *Device; ++ BOOL IsDataPacket; ++ ++ // Valid only for receives when we break a xfer page packet into multiple netvsc packets ++ XFERPAGE_PACKET *XferPagePacket; ++ ++ union { ++ struct{ ++ UINT64 ReceiveCompletionTid; ++ PVOID ReceiveCompletionContext; ++ PFN_ON_SENDRECVCOMPLETION OnReceiveCompletion; ++ } Recv; ++ struct{ ++ UINT64 SendCompletionTid; ++ PVOID SendCompletionContext; ++ PFN_ON_SENDRECVCOMPLETION OnSendCompletion; ++ } Send; ++ } Completion; ++ ++ // This points to the memory after PageBuffers ++ PVOID Extension; ++ ++ UINT32 TotalDataBufferLength; ++ // Points to the send/receive buffer where the ethernet frame is ++ UINT32 PageBufferCount; ++ PAGE_BUFFER PageBuffers[NETVSC_PACKET_MAXPAGE]; ++ ++} NETVSC_PACKET; ++ ++ ++// Represents the net vsc driver ++typedef struct _NETVSC_DRIVER_OBJECT { ++ DRIVER_OBJECT Base; // Must be the first field ++ ++ UINT32 RingBufferSize; ++ UINT32 RequestExtSize; ++ ++ // Additional num of page buffers to allocate ++ UINT32 AdditionalRequestPageBufferCount; ++ ++ // This is set by the caller to allow us to callback when we receive a packet ++ // from the "wire" ++ PFN_ON_RECVCALLBACK OnReceiveCallback; ++ ++ PFN_ON_LINKSTATUS_CHANGED OnLinkStatusChanged; ++ ++ // Specific to this driver ++ PFN_ON_OPEN OnOpen; ++ PFN_ON_CLOSE OnClose; ++ PFN_ON_SEND OnSend; ++ //PFN_ON_RECVCOMPLETION OnReceiveCompletion; ++ ++ //PFN_QUERY_LINKSTATUS QueryLinkStatus; ++ ++ void* Context; ++} NETVSC_DRIVER_OBJECT; ++ ++ ++typedef struct _NETVSC_DEVICE_INFO { ++ UCHAR MacAddr[6]; ++ BOOL LinkState; // 0 - link up, 1 - link down ++} NETVSC_DEVICE_INFO; ++ ++// ++// Interface ++// ++int ++NetVscInitialize( ++ DRIVER_OBJECT* drv ++ ); ++ ++#endif // _NETVSC_API_H_ +--- /dev/null ++++ b/drivers/staging/hv/include/osd.h +@@ -0,0 +1,263 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _OSD_H_ ++#define _OSD_H_ ++ ++// ++// Defines ++// ++ ++#ifndef PAGE_SIZE ++#define PAGE_SIZE 0x1000 ++#endif ++ ++#ifndef PAGE_SHIFT ++#define PAGE_SHIFT 12 ++#endif ++ ++#ifndef memcpy ++#define memcpy __builtin_memcpy ++#endif ++ ++#ifndef memset ++#define memset __builtin_memset ++#endif ++ ++#ifndef memcmp ++#define memcmp __builtin_memcmp ++#endif ++ ++#ifndef strcpy ++#define strcpy __builtin_strcpy ++#endif ++ ++// ++//#ifndef sprintf ++//#define sprintf __builtin_sprintf ++//#endif ++ ++#define STRUCT_PACKED __attribute__((__packed__)) ++#define STRUCT_ALIGNED(x) __attribute__((__aligned__(x))) ++ ++#define UNUSED_VAR(v) v __attribute__((__unused__)) ++ ++#define ALIGN_UP(value, align) ( ((value) & (align-1))? ( ((value) + (align-1)) & ~(align-1) ): (value) ) ++#define ALIGN_DOWN(value, align) ( (value) & ~(align-1) ) ++#define NUM_PAGES_SPANNED(addr, len) ( (ALIGN_UP(addr+len, PAGE_SIZE) - ALIGN_DOWN(addr, PAGE_SIZE)) >> PAGE_SHIFT ) ++ ++#define MIN(a, b) ((a) < (b)? (a): (b)) ++#define MAX(a, b) ((a) > (b)? (a): (b)) ++ ++#define LOWORD(dw) ((unsigned short) (dw)) ++#define HIWORD(dw) ((unsigned short) (((unsigned int) (dw) >> 16) & 0xFFFF)) ++ ++#define FIELD_OFFSET(t, f) ((unsigned int)(unsigned long)&(((t *)0)->f)) ++ ++#ifdef FALSE ++#undef FALSE ++#endif ++#define FALSE 0 ++ ++#ifdef TRUE ++#undef TRUE ++#endif ++#define TRUE 1 ++ ++#ifndef NULL ++#define NULL (void *)0 ++#endif ++ ++typedef struct _DLIST_ENTRY { ++ struct _DLIST_ENTRY *Flink; ++ struct _DLIST_ENTRY *Blink; ++} DLIST_ENTRY; ++ ++// ++// unsigned types ++// ++typedef unsigned char UINT8; ++typedef unsigned short UINT16; ++typedef unsigned int UINT32; ++#ifdef __x86_64__ ++typedef unsigned long UINT64; ++#else ++typedef unsigned long long UINT64; ++#endif ++ ++typedef unsigned long long ULONGLONG; ++typedef unsigned int ULONG; ++typedef unsigned short USHORT; ++typedef unsigned char UCHAR; ++ ++// ++// signed types ++// ++typedef char INT8; ++typedef short INT16; ++typedef int INT32; ++#ifdef __x86_64__ ++typedef long INT64; ++#else ++typedef long long INT64; ++#endif ++ ++typedef int LONG; ++typedef char CHAR; ++typedef long long LONGLONG; ++ ++// ++// Other types ++// ++typedef unsigned long SIZE_T; ++typedef void VOID; ++//typedef unsigned char GUID[16]; ++typedef void* PVOID; ++typedef unsigned char BOOL; ++typedef unsigned char BOOLEAN; ++typedef void* HANDLE; ++typedef UINT32 DWORD; ++typedef char* PCHAR; ++typedef unsigned char BYTE; ++ ++typedef unsigned long ULONG_PTR; ++ ++typedef struct { ++ unsigned char Data[16]; ++} GUID; ++ ++typedef void (*PFN_WORKITEM_CALLBACK)(void* context); ++typedef void (*PFN_TIMER_CALLBACK)(void* context); ++ ++ ++#ifdef __x86_64__ ++ ++#define RDMSR(reg, v) { \ ++ UINT32 h, l; \ ++ __asm__ __volatile__("rdmsr" \ ++ : "=a" (l), "=d" (h) \ ++ : "c" (reg)); \ ++ v = (((UINT64)h) << 32) | l; \ ++} ++ ++#define WRMSR(reg, v) { \ ++ UINT32 h, l; \ ++ l = (UINT32)(((UINT64)(v)) & 0xFFFFFFFF); \ ++ h = (UINT32)((((UINT64)(v)) >> 32) & 0xFFFFFFFF); \ ++ __asm__ __volatile__("wrmsr" \ ++ : /* no outputs */ \ ++ : "c" (reg), "a" (l), "d" (h)); \ ++} ++ ++#else ++ ++#define RDMSR(reg, v) \ ++ __asm__ __volatile__("rdmsr" \ ++ : "=A" (v) \ ++ : "c" (reg)) ++ ++#define WRMSR(reg, v) \ ++ __asm__ __volatile__("wrmsr" \ ++ : /* no outputs */ \ ++ : "c" (reg), "A" ((UINT64)v)) ++ ++#endif ++ ++ ++static inline void do_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) ++{ ++ __asm__ __volatile__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (op), "c" (ecx)); ++} ++ ++// ++// Osd routines ++// ++extern void LogMsg(const char *fmt, ...); ++ ++extern void BitSet(unsigned int* addr, int value); ++extern void BitClear(unsigned int* addr, int value); ++extern int BitTest(unsigned int* addr, int value); ++extern int BitTestAndClear(unsigned int* addr, int value); ++extern int BitTestAndSet(unsigned int* addr, int value); ++ ++extern int InterlockedIncrement(int *val); ++extern int InterlockedDecrement(int *val); ++extern int InterlockedCompareExchange(int *val, int new, int curr); ++ ++extern void Sleep(unsigned long usecs); ++ ++extern void* VirtualAllocExec(unsigned int size); ++extern void VirtualFree(void* VirtAddr); ++ ++extern void* PageAlloc(unsigned int count); ++extern void PageFree(void* page, unsigned int count); ++ ++extern void* MemMapIO(unsigned long phys, unsigned long size); ++extern void MemUnmapIO(void* virt); ++ ++extern void* MemAlloc(unsigned int size); ++extern void* MemAllocZeroed(unsigned int size); ++extern void* MemAllocAtomic(unsigned int size); ++extern void MemFree(void* buf); ++extern void MemoryFence(VOID); ++ ++extern HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context); ++extern void TimerClose(HANDLE hTimer); ++extern int TimerStop(HANDLE hTimer); ++extern void TimerStart(HANDLE hTimer, UINT32 expirationInUs); ++extern SIZE_T GetTickCount(void); ++ ++extern HANDLE WaitEventCreate(void); ++extern void WaitEventClose(HANDLE hWait); ++extern void WaitEventSet(HANDLE hWait); ++extern int WaitEventWait(HANDLE hWait); ++ ++// If >0, hWait got signaled. If ==0, timeout. If < 0, error ++extern int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs); ++ ++extern HANDLE SpinlockCreate(void); ++extern void SpinlockClose(HANDLE hSpin); ++extern void SpinlockAcquire(HANDLE hSpin); ++extern void SpinlockRelease(HANDLE hSpin); ++ ++ ++#define GetVirtualAddress Physical2LogicalAddr ++void* Physical2LogicalAddr(ULONG_PTR PhysAddr); ++ ++#define GetPhysicalAddress Logical2PhysicalAddr ++ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr); ++ ++ULONG_PTR Virtual2Physical(PVOID VirtAddr); ++ ++void* PageMapVirtualAddress(unsigned long Pfn); ++void PageUnmapVirtualAddress(void* VirtAddr); ++ ++ ++extern HANDLE WorkQueueCreate(char* name); ++extern void WorkQueueClose(HANDLE hWorkQueue); ++extern int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context); ++ ++extern void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context); ++ ++#endif // _OSD_H_ +--- /dev/null ++++ b/drivers/staging/hv/include/StorVscApi.h +@@ -0,0 +1,137 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _STORVSC_API_H_ ++#define _STORVSC_API_H_ ++ ++#include "VmbusApi.h" ++ ++// ++// Defines ++// ++ ++#define STORVSC_RING_BUFFER_SIZE 10*PAGE_SIZE ++#define BLKVSC_RING_BUFFER_SIZE 20*PAGE_SIZE ++ ++#define STORVSC_MAX_IO_REQUESTS 64 ++ ++// In Hyper-V, each port/path/target maps to 1 scsi host adapter. ++// In reality, the path/target is not used (ie always set to 0) so ++// our scsi host adapter essentially has 1 bus with 1 target that contains ++// up to 256 luns. ++ ++#define STORVSC_MAX_LUNS_PER_TARGET 64 ++#define STORVSC_MAX_TARGETS 1 ++#define STORVSC_MAX_CHANNELS 1 ++ ++ ++// Fwd decl ++// ++//struct VMBUS_CHANNEL; ++typedef struct _STORVSC_REQUEST* PSTORVSC_REQUEST; ++ ++// ++// Data types ++// ++typedef int (*PFN_ON_IO_REQUEST)(PDEVICE_OBJECT Device, PSTORVSC_REQUEST Request); ++typedef void (*PFN_ON_IO_REQUEST_COMPLTN)(PSTORVSC_REQUEST Request); ++ ++typedef int (*PFN_ON_HOST_RESET)(PDEVICE_OBJECT Device); ++typedef void (*PFN_ON_HOST_RESCAN)(PDEVICE_OBJECT Device); ++ ++ ++// Matches Windows-end ++typedef enum _STORVSC_REQUEST_TYPE{ ++ WRITE_TYPE, ++ READ_TYPE, ++ UNKNOWN_TYPE, ++} STORVSC_REQUEST_TYPE; ++ ++ ++typedef struct _STORVSC_REQUEST { ++ STORVSC_REQUEST_TYPE Type; ++ UINT32 Host; ++ UINT32 Bus; ++ UINT32 TargetId; ++ UINT32 LunId; ++ UINT8* Cdb; ++ UINT32 CdbLen; ++ UINT32 Status; ++ UINT32 BytesXfer; ++ ++ UCHAR* SenseBuffer; ++ UINT32 SenseBufferSize; ++ ++ PVOID Context; ++ ++ PFN_ON_IO_REQUEST_COMPLTN OnIOCompletion; ++ ++ // This points to the memory after DataBuffer ++ PVOID Extension; ++ ++ MULTIPAGE_BUFFER DataBuffer; ++} STORVSC_REQUEST; ++ ++ ++// Represents the block vsc driver ++typedef struct _STORVSC_DRIVER_OBJECT { ++ DRIVER_OBJECT Base; // Must be the first field ++ ++ // Set by caller (in bytes) ++ UINT32 RingBufferSize; ++ ++ // Allocate this much private extension for each I/O request ++ UINT32 RequestExtSize; ++ ++ // Maximum # of requests in flight per channel/device ++ UINT32 MaxOutstandingRequestsPerChannel; ++ ++ // Set by the caller to allow us to re-enumerate the bus on the host ++ PFN_ON_HOST_RESCAN OnHostRescan; ++ ++ // Specific to this driver ++ PFN_ON_IO_REQUEST OnIORequest; ++ PFN_ON_HOST_RESET OnHostReset; ++ ++} STORVSC_DRIVER_OBJECT; ++ ++typedef struct _STORVSC_DEVICE_INFO { ++ ULONG PortNumber; ++ UCHAR PathId; ++ UCHAR TargetId; ++} STORVSC_DEVICE_INFO; ++ ++// ++// Interface ++// ++int ++StorVscInitialize( ++ DRIVER_OBJECT *Driver ++ ); ++ ++int ++BlkVscInitialize( ++ DRIVER_OBJECT *Driver ++ ); ++#endif // _STORVSC_API_H_ +--- /dev/null ++++ b/drivers/staging/hv/include/VmbusApi.h +@@ -0,0 +1,262 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _VMBUS_API_H_ ++#define _VMBUS_API_H_ ++ ++#include "osd.h" ++ ++// ++// Defines ++// ++ ++#define MAX_PAGE_BUFFER_COUNT 16 ++#define MAX_MULTIPAGE_BUFFER_COUNT 32 // 128K ++ ++ ++// ++// Fwd declarations ++// ++typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT; ++typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT; ++ ++// ++// Data types ++// ++ ++#pragma pack(push,1) ++ ++// Single-page buffer ++typedef struct _PAGE_BUFFER { ++ UINT32 Length; ++ UINT32 Offset; ++ UINT64 Pfn; ++} PAGE_BUFFER; ++ ++// Multiple-page buffer ++typedef struct _MULTIPAGE_BUFFER { ++ // Length and Offset determines the # of pfns in the array ++ UINT32 Length; ++ UINT32 Offset; ++ UINT64 PfnArray[MAX_MULTIPAGE_BUFFER_COUNT]; ++}MULTIPAGE_BUFFER; ++ ++//0x18 includes the proprietary packet header ++#define MAX_PAGE_BUFFER_PACKET (0x18 + (sizeof(PAGE_BUFFER) * MAX_PAGE_BUFFER_COUNT)) ++#define MAX_MULTIPAGE_BUFFER_PACKET (0x18 + sizeof(MULTIPAGE_BUFFER)) ++ ++ ++#pragma pack(pop) ++ ++// All drivers ++typedef int (*PFN_ON_DEVICEADD)(PDEVICE_OBJECT Device, void* AdditionalInfo); ++typedef int (*PFN_ON_DEVICEREMOVE)(PDEVICE_OBJECT Device); ++typedef char** (*PFN_ON_GETDEVICEIDS)(void); ++typedef void (*PFN_ON_CLEANUP)(PDRIVER_OBJECT Driver); ++ ++// Vmbus extensions ++//typedef int (*PFN_ON_MATCH)(PDEVICE_OBJECT dev, PDRIVER_OBJECT drv); ++//typedef int (*PFN_ON_PROBE)(PDEVICE_OBJECT dev); ++typedef int (*PFN_ON_ISR)(PDRIVER_OBJECT drv); ++typedef void (*PFN_ON_DPC)(PDRIVER_OBJECT drv); ++typedef void (*PFN_GET_CHANNEL_OFFERS)(void); ++ ++typedef PDEVICE_OBJECT (*PFN_ON_CHILDDEVICE_CREATE)(GUID DeviceType, GUID DeviceInstance, void *Context); ++typedef void (*PFN_ON_CHILDDEVICE_DESTROY)(PDEVICE_OBJECT Device); ++typedef int (*PFN_ON_CHILDDEVICE_ADD)(PDEVICE_OBJECT RootDevice, PDEVICE_OBJECT ChildDevice); ++typedef void (*PFN_ON_CHILDDEVICE_REMOVE)(PDEVICE_OBJECT Device); ++ ++// Vmbus channel interface ++typedef void (*VMBUS_CHANNEL_CALLBACK)(PVOID context); ++ ++typedef int (*VMBUS_CHANNEL_OPEN)( ++ PDEVICE_OBJECT Device, ++ UINT32 SendBufferSize, ++ UINT32 RecvRingBufferSize, ++ PVOID UserData, ++ UINT32 UserDataLen, ++ VMBUS_CHANNEL_CALLBACK ChannelCallback, ++ PVOID Context ++ ); ++ ++typedef void (*VMBUS_CHANNEL_CLOSE)( ++ PDEVICE_OBJECT Device ++ ); ++ ++typedef int (*VMBUS_CHANNEL_SEND_PACKET)( ++ PDEVICE_OBJECT Device, ++ const PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId, ++ UINT32 Type, ++ UINT32 Flags ++); ++ ++typedef int (*VMBUS_CHANNEL_SEND_PACKET_PAGEBUFFER)( ++ PDEVICE_OBJECT Device, ++ PAGE_BUFFER PageBuffers[], ++ UINT32 PageCount, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++ ); ++ ++typedef int (*VMBUS_CHANNEL_SEND_PACKET_MULTIPAGEBUFFER)( ++ PDEVICE_OBJECT Device, ++ MULTIPAGE_BUFFER *MultiPageBuffer, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++); ++ ++typedef int (*VMBUS_CHANNEL_RECV_PACKET)( ++ PDEVICE_OBJECT Device, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ); ++ ++typedef int (*VMBUS_CHANNEL_RECV_PACKET_PAW)( ++ PDEVICE_OBJECT Device, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ); ++ ++typedef int (*VMBUS_CHANNEL_ESTABLISH_GPADL)( ++ PDEVICE_OBJECT Device, ++ PVOID Buffer, // from kmalloc() ++ UINT32 BufferLen, // page-size multiple ++ UINT32* GpadlHandle ++ ); ++ ++typedef int (*VMBUS_CHANNEL_TEARDOWN_GPADL)( ++ PDEVICE_OBJECT Device, ++ UINT32 GpadlHandle ++ ); ++ ++ ++typedef struct _PORT_INFO { ++ UINT32 InterruptMask; ++ UINT32 ReadIndex; ++ UINT32 WriteIndex; ++ UINT32 BytesAvailToRead; ++ UINT32 BytesAvailToWrite; ++} PORT_INFO; ++ ++ ++typedef struct _DEVICE_INFO { ++ UINT32 ChannelId; ++ UINT32 ChannelState; ++ GUID ChannelType; ++ GUID ChannelInstance; ++ ++ UINT32 MonitorId; ++ UINT32 ServerMonitorPending; ++ UINT32 ServerMonitorLatency; ++ UINT32 ServerMonitorConnectionId; ++ UINT32 ClientMonitorPending; ++ UINT32 ClientMonitorLatency; ++ UINT32 ClientMonitorConnectionId; ++ ++ PORT_INFO Inbound; ++ PORT_INFO Outbound; ++} DEVICE_INFO; ++ ++typedef void (*VMBUS_GET_CHANNEL_INFO)(PDEVICE_OBJECT Device, DEVICE_INFO* DeviceInfo); ++ ++typedef struct _VMBUS_CHANNEL_INTERFACE { ++ VMBUS_CHANNEL_OPEN Open; ++ VMBUS_CHANNEL_CLOSE Close; ++ VMBUS_CHANNEL_SEND_PACKET SendPacket; ++ VMBUS_CHANNEL_SEND_PACKET_PAGEBUFFER SendPacketPageBuffer; ++ VMBUS_CHANNEL_SEND_PACKET_MULTIPAGEBUFFER SendPacketMultiPageBuffer; ++ VMBUS_CHANNEL_RECV_PACKET RecvPacket; ++ VMBUS_CHANNEL_RECV_PACKET_PAW RecvPacketRaw; ++ VMBUS_CHANNEL_ESTABLISH_GPADL EstablishGpadl; ++ VMBUS_CHANNEL_TEARDOWN_GPADL TeardownGpadl; ++ VMBUS_GET_CHANNEL_INFO GetInfo; ++} VMBUS_CHANNEL_INTERFACE; ++ ++typedef void (*VMBUS_GET_CHANNEL_INTERFACE)(VMBUS_CHANNEL_INTERFACE *Interface); ++ ++// Base driver object ++typedef struct _DRIVER_OBJECT { ++ const char* name; ++ GUID deviceType; // the device type supported by this driver ++ ++ PFN_ON_DEVICEADD OnDeviceAdd; ++ PFN_ON_DEVICEREMOVE OnDeviceRemove; ++ PFN_ON_GETDEVICEIDS OnGetDeviceIds; // device ids supported by this driver ++ PFN_ON_CLEANUP OnCleanup; ++ ++ VMBUS_CHANNEL_INTERFACE VmbusChannelInterface; ++} DRIVER_OBJECT; ++ ++ ++// Base device object ++typedef struct _DEVICE_OBJECT { ++ DRIVER_OBJECT* Driver; // the driver for this device ++ char name[64]; ++ GUID deviceType; // the device type id of this device ++ GUID deviceInstance; // the device instance id of this device ++ void* context; ++ void* Extension; // Device extension; ++} DEVICE_OBJECT; ++ ++ ++// Vmbus driver object ++typedef struct _VMBUS_DRIVER_OBJECT { ++ DRIVER_OBJECT Base; // !! Must be the 1st field !! ++ ++ // Set by the caller ++ PFN_ON_CHILDDEVICE_CREATE OnChildDeviceCreate; ++ PFN_ON_CHILDDEVICE_DESTROY OnChildDeviceDestroy; ++ PFN_ON_CHILDDEVICE_ADD OnChildDeviceAdd; ++ PFN_ON_CHILDDEVICE_REMOVE OnChildDeviceRemove; ++ ++ // Set by the callee ++ //PFN_ON_MATCH OnMatch; ++ //PFN_ON_PROBE OnProbe; ++ PFN_ON_ISR OnIsr; ++ PFN_ON_DPC OnMsgDpc; ++ PFN_ON_DPC OnEventDpc; ++ PFN_GET_CHANNEL_OFFERS GetChannelOffers; ++ ++ VMBUS_GET_CHANNEL_INTERFACE GetChannelInterface; ++ VMBUS_GET_CHANNEL_INFO GetChannelInfo; ++} VMBUS_DRIVER_OBJECT; ++ ++ ++// ++// Interface ++// ++int ++VmbusInitialize( ++ DRIVER_OBJECT* drv ++ ); ++ ++#endif // _VMBUS_API_H_ +--- /dev/null ++++ b/drivers/staging/hv/include/vmbus.h +@@ -0,0 +1,111 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _VMBUS_H_ ++#define _VMBUS_H_ ++ ++#include ++ ++#include "VmbusApi.h" ++ ++// ++// Data types ++// ++ ++typedef int (*PFN_DRIVERINITIALIZE)(DRIVER_OBJECT *drv); ++typedef int (*PFN_DRIVEREXIT)(DRIVER_OBJECT *drv); ++ ++struct driver_context { ++ GUID class_id; ++ ++ struct device_driver driver; ++ ++ // Use these methods instead of the struct device_driver so 2.6 kernel stops complaining ++ int (*probe)(struct device *); ++ int (*remove)(struct device *); ++ void (*shutdown)(struct device *); ++}; ++ ++struct device_context { ++ struct work_struct probe_failed_work_item; ++ GUID class_id; ++ GUID device_id; ++ int probe_error; ++ struct device device; ++ DEVICE_OBJECT device_obj; ++}; ++ ++ ++// ++// Global ++// ++ ++// ++// Inlines ++// ++static inline struct device_context *to_device_context(DEVICE_OBJECT *device_obj) ++{ ++ return container_of(device_obj, struct device_context, device_obj); ++} ++ ++static inline struct device_context *device_to_device_context(struct device *device) ++{ ++ return container_of(device, struct device_context, device); ++} ++ ++static inline struct driver_context *driver_to_driver_context(struct device_driver *driver) ++{ ++ return container_of(driver, struct driver_context, driver); ++} ++ ++#if defined(KERNEL_2_6_5) ++static inline void* kzalloc(int size, int flags) ++{ ++ void *p; ++ p = kmalloc(size, flags); ++ if (p) memset(p, 0, size); ++ ++ return p; ++} ++#endif // KERNEL_2_6_5 ++ ++// ++// Vmbus interface ++// ++void ++vmbus_child_driver_register( ++ struct driver_context* driver_ctx ++ ); ++ ++void ++vmbus_child_driver_unregister( ++ struct driver_context *driver_ctx ++ ); ++ ++void ++vmbus_get_interface( ++ VMBUS_CHANNEL_INTERFACE *interface ++ ); ++ ++#endif // _VMBUS_H_ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-block-driver-to-the-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-block-driver-to-the-build.patch new file mode 100644 index 000000000..89cd91766 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-block-driver-to-the-build.patch @@ -0,0 +1,42 @@ +From foo@baz Tue Jul 14 10:25:53 PDT 2009 +Date: Tue, 14 Jul 2009 10:25:53 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: add the Hyper-V virtual block driver to the build + +From: Greg Kroah-Hartman + +Add the Hyper-V virtual block driver to the kernel build system. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/staging/hv/Kconfig | 7 +++++++ + drivers/staging/hv/Makefile | 2 ++ + 2 files changed, 9 insertions(+) + +--- a/drivers/staging/hv/Kconfig ++++ b/drivers/staging/hv/Kconfig +@@ -12,3 +12,10 @@ config HYPERV_STORAGE + default n + help + Select this option to enable the Hyper-V virtual storage driver. ++ ++config HYPERV_BLOCK ++ tristate "Microsoft Hyper-V virtual block driver" ++ depends on HYPERV && BLOCK ++ default n ++ help ++ Select this option to enable the Hyper-V virtual block driver. +--- a/drivers/staging/hv/Makefile ++++ b/drivers/staging/hv/Makefile +@@ -1,5 +1,7 @@ + obj-$(CONFIG_HYPERV) += hv_vmbus.o + obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o ++obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o + + hv_vmbus-objs := vmbus_drv.o osd.o Sources.o + hv_storvsc-objs := storvsc_drv.o osd.o StorVsc.o ++hv_blkvsc-objs := blkvsc_drv.o osd.o BlkVsc.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-block-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-block-driver.patch new file mode 100644 index 000000000..93e1aa358 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-block-driver.patch @@ -0,0 +1,1678 @@ +From 582e26118ab754a3bca9b98351cb874f22b76ffd Mon Sep 17 00:00:00 2001 +From: Hank Janssen +Date: Mon, 13 Jul 2009 15:33:02 -0700 +Subject: Staging: hv: add the Hyper-V virtual block driver + +From: Hank Janssen + +This is the virtual block driver when running Linux on top of Hyper-V. + +Signed-off-by: Hank Janssen +Signed-off-by: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/hv/BlkVsc.c | 107 ++ + drivers/staging/hv/blkvsc_drv.c | 1547 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1654 insertions(+) + create mode 100644 drivers/staging/hv/blkvsc.c + +--- /dev/null ++++ b/drivers/staging/hv/BlkVsc.c +@@ -0,0 +1,107 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "../storvsc/StorVsc.c" ++ ++static const char* gBlkDriverName="blkvsc"; ++ ++//{32412632-86cb-44a2-9b5c-50d1417354f5} ++static const GUID gBlkVscDeviceType={ ++ .Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5} ++}; ++ ++// Static routines ++static int ++BlkVscOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ); ++ ++ ++int ++BlkVscInitialize( ++ DRIVER_OBJECT *Driver ++ ) ++{ ++ STORVSC_DRIVER_OBJECT* storDriver = (STORVSC_DRIVER_OBJECT*)Driver; ++ int ret=0; ++ ++ DPRINT_ENTER(BLKVSC); ++ ++ // Make sure we are at least 2 pages since 1 page is used for control ++ ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); ++ ++ Driver->name = gBlkDriverName; ++ memcpy(&Driver->deviceType, &gBlkVscDeviceType, sizeof(GUID)); ++ ++ storDriver->RequestExtSize = sizeof(STORVSC_REQUEST_EXTENSION); ++ // Divide the ring buffer data size (which is 1 page less than the ring buffer size since that page is reserved for the ring buffer indices) ++ // by the max request size (which is VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + VSTOR_PACKET + UINT64) ++ storDriver->MaxOutstandingRequestsPerChannel = ++ ((storDriver->RingBufferSize - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(VSTOR_PACKET) + sizeof(UINT64),sizeof(UINT64))); ++ ++ DPRINT_INFO(BLKVSC, "max io outstd %u", storDriver->MaxOutstandingRequestsPerChannel); ++ ++ // Setup the dispatch table ++ storDriver->Base.OnDeviceAdd = BlkVscOnDeviceAdd; ++ storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove; ++ storDriver->Base.OnCleanup = StorVscOnCleanup; ++ ++ storDriver->OnIORequest = StorVscOnIORequest; ++ ++ DPRINT_EXIT(BLKVSC); ++ ++ return ret; ++} ++ ++int ++BlkVscOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ) ++{ ++ int ret=0; ++ STORVSC_DEVICE_INFO *deviceInfo = (STORVSC_DEVICE_INFO*)AdditionalInfo; ++ ++ DPRINT_ENTER(BLKVSC); ++ ++ ret = StorVscOnDeviceAdd(Device, AdditionalInfo); ++ ++ if (ret != 0) ++ { ++ DPRINT_EXIT(BLKVSC); ++ ++ return ret; ++ } ++ ++ // We need to use the device instance guid to set the path and target id. For IDE devices, the ++ // device instance id is formatted as - - 8899 - 000000000000. ++ deviceInfo->PathId = Device->deviceInstance.Data[3] << 24 | Device->deviceInstance.Data[2] << 16 | ++ Device->deviceInstance.Data[1] << 8 |Device->deviceInstance.Data[0]; ++ ++ deviceInfo->TargetId = Device->deviceInstance.Data[5] << 8 | Device->deviceInstance.Data[4]; ++ ++ DPRINT_EXIT(BLKVSC); ++ ++ return ret; ++} +--- /dev/null ++++ b/drivers/staging/hv/blkvsc_drv.c +@@ -0,0 +1,1547 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "logging.h" ++#include "vmbus.h" ++ ++#include "StorVscApi.h" ++ ++// ++// #defines ++// ++#define BLKVSC_MINORS 64 ++ ++// ++// Data types ++// ++enum blkvsc_device_type { ++ UNKNOWN_DEV_TYPE, ++ HARDDISK_TYPE, ++ DVD_TYPE, ++}; ++ ++// This request ties the struct request and struct blkvsc_request/STORVSC_REQUEST together ++// A struct request may be represented by 1 or more struct blkvsc_request ++struct blkvsc_request_group { ++ int outstanding; ++ int status; ++ ++ struct list_head blkvsc_req_list; // list of blkvsc_requests ++}; ++ ++ ++struct blkvsc_request { ++ struct list_head req_entry; // blkvsc_request_group.blkvsc_req_list ++ ++ struct list_head pend_entry; // block_device_context.pending_list ++ ++ struct request *req; // This may be null if we generate a request internally ++ struct block_device_context *dev; ++ struct blkvsc_request_group *group; // The group this request is part of. Maybe null ++ ++ wait_queue_head_t wevent; ++ int cond; ++ ++ int write; ++ sector_t sector_start; ++ unsigned long sector_count; ++ ++ unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; ++ unsigned char cmd_len; ++ unsigned char cmnd[MAX_COMMAND_SIZE]; ++ ++ STORVSC_REQUEST request; ++ // !!!DO NOT ADD ANYTHING BELOW HERE!!! Otherwise, memory can overlap, because - ++ // The extension buffer falls right here and is pointed to by request.Extension; ++}; ++ ++// Per device structure ++struct block_device_context { ++ struct device_context *device_ctx; // point back to our device context ++ struct kmem_cache *request_pool; ++ spinlock_t lock; ++ struct gendisk *gd; ++ enum blkvsc_device_type device_type; ++ struct list_head pending_list; ++ ++ unsigned char device_id[64]; ++ unsigned int device_id_len; ++ int num_outstanding_reqs; ++ int shutting_down; ++ int media_not_present; ++ unsigned int sector_size; ++ sector_t capacity; ++ unsigned int port; ++ unsigned char path; ++ unsigned char target; ++ int users; ++}; ++ ++// Per driver ++struct blkvsc_driver_context { ++ // !! These must be the first 2 fields !! ++ struct driver_context drv_ctx; ++ STORVSC_DRIVER_OBJECT drv_obj; ++}; ++ ++// Static decl ++static int blkvsc_probe(struct device *dev); ++static int blkvsc_remove(struct device *device); ++static void blkvsc_shutdown(struct device *device); ++ ++static int blkvsc_open(struct inode *inode, struct file *filep); ++static int blkvsc_release(struct inode *inode, struct file *filep); ++static int blkvsc_media_changed(struct gendisk *gd); ++static int blkvsc_revalidate_disk(struct gendisk *gd); ++static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg); ++static int blkvsc_ioctl(struct inode *inode, struct file *filep, unsigned cmd, unsigned long arg); ++ ++static void blkvsc_request(struct request_queue *queue); ++static void blkvsc_request_completion(STORVSC_REQUEST* request); ++static int blkvsc_do_request(struct block_device_context *blkdev, struct request *req); ++static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req, void (*request_completion)(STORVSC_REQUEST*) ); ++static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req); ++static void blkvsc_cmd_completion(STORVSC_REQUEST* request); ++static int blkvsc_do_inquiry(struct block_device_context *blkdev); ++static int blkvsc_do_read_capacity(struct block_device_context *blkdev); ++static int blkvsc_do_read_capacity16(struct block_device_context *blkdev); ++static int blkvsc_do_flush(struct block_device_context *blkdev); ++static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev); ++static int blkvsc_do_pending_reqs(struct block_device_context *blkdev); ++ ++ ++static int blkvsc_ringbuffer_size = BLKVSC_RING_BUFFER_SIZE; ++ ++// The one and only one ++static struct blkvsc_driver_context g_blkvsc_drv; ++ ++ ++static struct block_device_operations block_ops = ++{ ++ .owner = THIS_MODULE, ++ .open = blkvsc_open, ++ .release = blkvsc_release, ++ .media_changed = blkvsc_media_changed, ++ .revalidate_disk = blkvsc_revalidate_disk, ++ .getgeo = blkvsc_getgeo, ++ .ioctl = blkvsc_ioctl, ++}; ++ ++/*++ ++ ++Name: blkvsc_drv_init() ++ ++Desc: BlkVsc driver initialization. ++ ++--*/ ++int blkvsc_drv_init(PFN_DRIVERINITIALIZE pfn_drv_init) ++{ ++ int ret=0; ++ STORVSC_DRIVER_OBJECT *storvsc_drv_obj=&g_blkvsc_drv.drv_obj; ++ struct driver_context *drv_ctx=&g_blkvsc_drv.drv_ctx; ++ ++ DPRINT_ENTER(BLKVSC_DRV); ++ ++ vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface); ++ ++ storvsc_drv_obj->RingBufferSize = blkvsc_ringbuffer_size; ++ ++ // Callback to client driver to complete the initialization ++ pfn_drv_init(&storvsc_drv_obj->Base); ++ ++ drv_ctx->driver.name = storvsc_drv_obj->Base.name; ++ memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType, sizeof(GUID)); ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++ drv_ctx->driver.probe = blkvsc_probe; ++ drv_ctx->driver.remove = blkvsc_remove; ++#else ++ drv_ctx->probe = blkvsc_probe; ++ drv_ctx->remove = blkvsc_remove; ++ drv_ctx->shutdown = blkvsc_shutdown; ++#endif ++ ++ // The driver belongs to vmbus ++ vmbus_child_driver_register(drv_ctx); ++ ++ DPRINT_EXIT(BLKVSC_DRV); ++ ++ return ret; ++} ++ ++ ++static int blkvsc_drv_exit_cb(struct device *dev, void *data) ++{ ++ struct device **curr = (struct device **)data; ++ *curr = dev; ++ return 1; // stop iterating ++} ++ ++/*++ ++ ++Name: blkvsc_drv_exit() ++ ++Desc: ++ ++--*/ ++void blkvsc_drv_exit(void) ++{ ++ STORVSC_DRIVER_OBJECT *storvsc_drv_obj=&g_blkvsc_drv.drv_obj; ++ struct driver_context *drv_ctx=&g_blkvsc_drv.drv_ctx; ++ ++ struct device *current_dev=NULL; ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#define driver_for_each_device(drv, start, data, fn) \ ++ struct list_head *ptr, *n; \ ++ list_for_each_safe(ptr, n, &((drv)->devices)) {\ ++ struct device *curr_dev;\ ++ curr_dev = list_entry(ptr, struct device, driver_list);\ ++ fn(curr_dev, data);\ ++ } ++#endif // KERNEL_2_6_9 ++ ++ DPRINT_ENTER(BLKVSC_DRV); ++ ++ while (1) ++ { ++ current_dev = NULL; ++ ++ // Get the device ++ driver_for_each_device(&drv_ctx->driver, NULL, (void*)¤t_dev, blkvsc_drv_exit_cb); ++ ++ if (current_dev == NULL) ++ break; ++ ++ // Initiate removal from the top-down ++ device_unregister(current_dev); ++ } ++ ++ if (storvsc_drv_obj->Base.OnCleanup) ++ storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base); ++ ++ vmbus_child_driver_unregister(drv_ctx); ++ ++ DPRINT_EXIT(BLKVSC_DRV); ++ ++ return; ++} ++ ++/*++ ++ ++Name: blkvsc_probe() ++ ++Desc: Add a new device for this driver ++ ++--*/ ++static int blkvsc_probe(struct device *device) ++{ ++ int ret=0; ++ ++ struct driver_context *driver_ctx = driver_to_driver_context(device->driver); ++ struct blkvsc_driver_context *blkvsc_drv_ctx = (struct blkvsc_driver_context*)driver_ctx; ++ STORVSC_DRIVER_OBJECT* storvsc_drv_obj = &blkvsc_drv_ctx->drv_obj; ++ ++ struct device_context *device_ctx = device_to_device_context(device); ++ DEVICE_OBJECT* device_obj = &device_ctx->device_obj; ++ ++ struct block_device_context *blkdev=NULL; ++ STORVSC_DEVICE_INFO device_info; ++ int major=0; ++ int devnum=0; ++ ++ static int ide0_registered=0; ++ static int ide1_registered=0; ++ ++ DPRINT_ENTER(BLKVSC_DRV); ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_probe - enter"); ++ ++ if (!storvsc_drv_obj->Base.OnDeviceAdd) ++ { ++ DPRINT_ERR(BLKVSC_DRV, "OnDeviceAdd() not set"); ++ ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ blkdev = kzalloc(sizeof(struct block_device_context), GFP_KERNEL); ++ if (!blkdev) ++ { ++ ret = -ENOMEM; ++ goto Cleanup; ++ } ++ ++ INIT_LIST_HEAD(&blkdev->pending_list); ++ ++ // Initialize what we can here ++ spin_lock_init(&blkdev->lock); ++ ++ ASSERT(sizeof(struct blkvsc_request_group) <= sizeof(struct blkvsc_request)); ++ ++#ifdef KERNEL_2_6_27 ++ blkdev->request_pool = kmem_cache_create(device_ctx->device.bus_id, ++ sizeof(struct blkvsc_request) + storvsc_drv_obj->RequestExtSize, 0, ++ SLAB_HWCACHE_ALIGN, NULL); ++#else ++ blkdev->request_pool = kmem_cache_create(device_ctx->device.bus_id, ++ sizeof(struct blkvsc_request) + storvsc_drv_obj->RequestExtSize, 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++#endif ++ if (!blkdev->request_pool) ++ { ++ ret = -ENOMEM; ++ goto Cleanup; ++ } ++ ++ ++ // Call to the vsc driver to add the device ++ ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj, &device_info); ++ if (ret != 0) ++ { ++ DPRINT_ERR(BLKVSC_DRV, "unable to add blkvsc device"); ++ goto Cleanup; ++ } ++ ++ blkdev->device_ctx = device_ctx; ++ blkdev->target = device_info.TargetId; // this identified the device 0 or 1 ++ blkdev->path = device_info.PathId; // this identified the ide ctrl 0 or 1 ++ ++ device->driver_data = blkdev; ++ ++ // Calculate the major and device num ++ if (blkdev->path == 0) ++ { ++ major = IDE0_MAJOR; ++ devnum = blkdev->path + blkdev->target; // 0 or 1 ++ ++ if (!ide0_registered) ++ { ++ ret = register_blkdev(major, "ide"); ++ if (ret != 0) ++ { ++ DPRINT_ERR(BLKVSC_DRV, "register_blkdev() failed! ret %d", ret); ++ goto Remove; ++ } ++ ++ ide0_registered = 1; ++ } ++ } ++ else if (blkdev->path == 1) ++ { ++ major = IDE1_MAJOR; ++ devnum = blkdev->path + blkdev->target + 1; // 2 or 3 ++ ++ if (!ide1_registered) ++ { ++ ret = register_blkdev(major, "ide"); ++ if (ret != 0) ++ { ++ DPRINT_ERR(BLKVSC_DRV, "register_blkdev() failed! ret %d", ret); ++ goto Remove; ++ } ++ ++ ide1_registered = 1; ++ } ++ ++ } ++ else ++ { ++ DPRINT_ERR(BLKVSC_DRV, "invalid pathid"); ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ DPRINT_INFO(BLKVSC_DRV, "blkvsc registered for major %d!!", major); ++ ++ blkdev->gd = alloc_disk(BLKVSC_MINORS); ++ if (!blkdev->gd) ++ { ++ DPRINT_ERR(BLKVSC_DRV, "register_blkdev() failed! ret %d", ret); ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ blkdev->gd->queue = blk_init_queue(blkvsc_request, &blkdev->lock); ++ ++ blk_queue_max_segment_size(blkdev->gd->queue, PAGE_SIZE); ++ blk_queue_max_phys_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT); ++ blk_queue_max_hw_segments(blkdev->gd->queue, MAX_MULTIPAGE_BUFFER_COUNT); ++ blk_queue_segment_boundary(blkdev->gd->queue, PAGE_SIZE-1); ++ blk_queue_bounce_limit(blkdev->gd->queue, BLK_BOUNCE_ANY); ++ blk_queue_dma_alignment(blkdev->gd->queue, 511); ++ ++ blkdev->gd->major = major; ++ if (devnum == 1 || devnum == 3) ++ blkdev->gd->first_minor = BLKVSC_MINORS; ++ else ++ blkdev->gd->first_minor = 0; ++ blkdev->gd->fops = &block_ops; ++ blkdev->gd->private_data = blkdev; ++ sprintf(blkdev->gd->disk_name, "hd%c", 'a'+ devnum); ++ ++ blkvsc_do_inquiry(blkdev); ++ if (blkdev->device_type == DVD_TYPE) ++ { ++ set_disk_ro(blkdev->gd, 1); ++ blkdev->gd->flags |= GENHD_FL_REMOVABLE; ++ blkvsc_do_read_capacity(blkdev); ++ } ++ else ++ { ++ blkvsc_do_read_capacity16(blkdev); ++ } ++ ++ set_capacity(blkdev->gd, blkdev->capacity * (blkdev->sector_size/512)); ++ blk_queue_hardsect_size(blkdev->gd->queue, blkdev->sector_size); ++ // go! ++ add_disk(blkdev->gd); ++ ++ DPRINT_INFO(BLKVSC_DRV, "%s added!! capacity %llu sector_size %d", blkdev->gd->disk_name, blkdev->capacity, blkdev->sector_size); ++ ++ return ret; ++ ++Remove: ++ storvsc_drv_obj->Base.OnDeviceRemove(device_obj); ++ ++Cleanup: ++ if (blkdev) ++ { ++ if (blkdev->request_pool) ++ { ++ kmem_cache_destroy(blkdev->request_pool); ++ blkdev->request_pool = NULL; ++ } ++ kfree(blkdev); ++ blkdev = NULL; ++ } ++ ++ DPRINT_EXIT(BLKVSC_DRV); ++ ++ return ret; ++} ++ ++static void blkvsc_shutdown(struct device *device) ++{ ++ struct block_device_context *blkdev = (struct block_device_context*)device->driver_data; ++ unsigned long flags; ++ ++ if (!blkdev) ++ return; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_shutdown - users %d disk %s\n", blkdev->users, blkdev->gd->disk_name); ++ ++ spin_lock_irqsave(&blkdev->lock, flags); ++ ++ blkdev->shutting_down = 1; ++ ++ blk_stop_queue(blkdev->gd->queue); ++ ++ spin_unlock_irqrestore(&blkdev->lock, flags); ++ ++ while (blkdev->num_outstanding_reqs) ++ { ++ DPRINT_INFO(STORVSC, "waiting for %d requests to complete...", blkdev->num_outstanding_reqs); ++ ++ udelay(100); ++ } ++ ++ blkvsc_do_flush(blkdev); ++ ++ spin_lock_irqsave(&blkdev->lock, flags); ++ ++ blkvsc_cancel_pending_reqs(blkdev); ++ ++ spin_unlock_irqrestore(&blkdev->lock, flags); ++} ++ ++static int blkvsc_do_flush(struct block_device_context *blkdev) ++{ ++ struct blkvsc_request *blkvsc_req=NULL; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_flush()\n"); ++ ++ if (blkdev->device_type != HARDDISK_TYPE) ++ return 0; ++ ++ blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL); ++ if (!blkvsc_req) ++ { ++ return -ENOMEM; ++ } ++ ++ memset(blkvsc_req, 0, sizeof(struct blkvsc_request)); ++ init_waitqueue_head(&blkvsc_req->wevent); ++ blkvsc_req->dev = blkdev; ++ blkvsc_req->req = NULL; ++ blkvsc_req->write = 0; ++ ++ blkvsc_req->request.DataBuffer.PfnArray[0] = 0; ++ blkvsc_req->request.DataBuffer.Offset = 0; ++ blkvsc_req->request.DataBuffer.Length = 0; ++ ++ blkvsc_req->cmnd[0] = SYNCHRONIZE_CACHE; ++ blkvsc_req->cmd_len = 10; ++ ++ // Set this here since the completion routine may be invoked and completed before we return ++ blkvsc_req->cond =0; ++ blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion); ++ ++ wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond); ++ ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ ++ return 0; ++} ++ ++// Do a scsi INQUIRY cmd here to get the device type (ie disk or dvd) ++static int blkvsc_do_inquiry(struct block_device_context *blkdev) ++{ ++ struct blkvsc_request *blkvsc_req=NULL; ++ struct page *page_buf; ++ unsigned char *buf; ++ unsigned char device_type; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_inquiry()\n"); ++ ++ blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL); ++ if (!blkvsc_req) ++ { ++ return -ENOMEM; ++ } ++ ++ memset(blkvsc_req, 0, sizeof(struct blkvsc_request)); ++ page_buf = alloc_page(GFP_KERNEL); ++ if (!page_buf) ++ { ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ return -ENOMEM; ++ } ++ ++ init_waitqueue_head(&blkvsc_req->wevent); ++ blkvsc_req->dev = blkdev; ++ blkvsc_req->req = NULL; ++ blkvsc_req->write = 0; ++ ++ blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf); ++ blkvsc_req->request.DataBuffer.Offset = 0; ++ blkvsc_req->request.DataBuffer.Length = 64; ++ ++ blkvsc_req->cmnd[0] = INQUIRY; ++ blkvsc_req->cmnd[1] = 0x1; // Get product data ++ blkvsc_req->cmnd[2] = 0x83; // mode page 83 ++ blkvsc_req->cmnd[4] = 64; ++ blkvsc_req->cmd_len = 6; ++ ++ // Set this here since the completion routine may be invoked and completed before we return ++ blkvsc_req->cond =0; ++ ++ blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion); ++ ++ DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n", blkvsc_req, blkvsc_req->cond); ++ ++ wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond); ++ ++ buf = kmap(page_buf); ++ ++ //PrintBytes(buf, 64); ++ // be to le ++ device_type = buf[0] & 0x1F; ++ ++ if (device_type == 0x0) ++ { ++ blkdev->device_type = HARDDISK_TYPE; ++ } ++ else if (device_type == 0x5) ++ { ++ blkdev->device_type = DVD_TYPE; ++ } ++ else ++ { ++ // TODO: this is currently unsupported device type ++ blkdev->device_type = UNKNOWN_DEV_TYPE; ++ } ++ ++ DPRINT_DBG(BLKVSC_DRV, "device type %d \n", device_type); ++ ++ blkdev->device_id_len = buf[7]; ++ if (blkdev->device_id_len > 64) ++ blkdev->device_id_len = 64; ++ ++ memcpy(blkdev->device_id, &buf[8], blkdev->device_id_len); ++ //PrintBytes(blkdev->device_id, blkdev->device_id_len); ++ ++ kunmap(page_buf); ++ ++ __free_page(page_buf); ++ ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ ++ return 0; ++} ++ ++// Do a scsi READ_CAPACITY cmd here to get the size of the disk ++static int blkvsc_do_read_capacity(struct block_device_context *blkdev) ++{ ++ struct blkvsc_request *blkvsc_req=NULL; ++ struct page *page_buf; ++ unsigned char *buf; ++ struct scsi_sense_hdr sense_hdr; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_read_capacity()\n"); ++ ++ blkdev->sector_size = 0; ++ blkdev->capacity = 0; ++ blkdev->media_not_present = 0; // assume a disk is present ++ ++ blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL); ++ if (!blkvsc_req) ++ { ++ return -ENOMEM; ++ } ++ ++ memset(blkvsc_req, 0, sizeof(struct blkvsc_request)); ++ page_buf = alloc_page(GFP_KERNEL); ++ if (!page_buf) ++ { ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ return -ENOMEM; ++ } ++ ++ init_waitqueue_head(&blkvsc_req->wevent); ++ blkvsc_req->dev = blkdev; ++ blkvsc_req->req = NULL; ++ blkvsc_req->write = 0; ++ ++ blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf); ++ blkvsc_req->request.DataBuffer.Offset = 0; ++ blkvsc_req->request.DataBuffer.Length = 8; ++ ++ blkvsc_req->cmnd[0] = READ_CAPACITY; ++ blkvsc_req->cmd_len = 16; ++ ++ // Set this here since the completion routine may be invoked and completed before we return ++ blkvsc_req->cond =0; ++ ++ blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion); ++ ++ DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n", blkvsc_req, blkvsc_req->cond); ++ ++ wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond); ++ ++ // check error ++ if (blkvsc_req->request.Status) ++ { ++ scsi_normalize_sense(blkvsc_req->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr); ++ ++ if (sense_hdr.asc == 0x3A) // Medium not present ++ { ++ blkdev->media_not_present = 1; ++ } ++ ++ return 0; ++ } ++ buf = kmap(page_buf); ++ ++ // be to le ++ blkdev->capacity = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]) + 1; ++ blkdev->sector_size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; ++ ++ kunmap(page_buf); ++ ++ __free_page(page_buf); ++ ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ ++ return 0; ++} ++ ++ ++static int blkvsc_do_read_capacity16(struct block_device_context *blkdev) ++{ ++ struct blkvsc_request *blkvsc_req=NULL; ++ struct page *page_buf; ++ unsigned char *buf; ++ struct scsi_sense_hdr sense_hdr; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_do_read_capacity16()\n"); ++ ++ blkdev->sector_size = 0; ++ blkdev->capacity = 0; ++ blkdev->media_not_present = 0; // assume a disk is present ++ ++ blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_KERNEL); ++ if (!blkvsc_req) ++ { ++ return -ENOMEM; ++ } ++ ++ memset(blkvsc_req, 0, sizeof(struct blkvsc_request)); ++ page_buf = alloc_page(GFP_KERNEL); ++ if (!page_buf) ++ { ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ return -ENOMEM; ++ } ++ ++ init_waitqueue_head(&blkvsc_req->wevent); ++ blkvsc_req->dev = blkdev; ++ blkvsc_req->req = NULL; ++ blkvsc_req->write = 0; ++ ++ blkvsc_req->request.DataBuffer.PfnArray[0] = page_to_pfn(page_buf); ++ blkvsc_req->request.DataBuffer.Offset = 0; ++ blkvsc_req->request.DataBuffer.Length = 12; ++ ++ blkvsc_req->cmnd[0] = 0x9E; //READ_CAPACITY16; ++ blkvsc_req->cmd_len = 16; ++ ++ // Set this here since the completion routine may be invoked and completed before we return ++ blkvsc_req->cond =0; ++ ++ blkvsc_submit_request(blkvsc_req, blkvsc_cmd_completion); ++ ++ DPRINT_DBG(BLKVSC_DRV, "waiting %p to complete - cond %d\n", blkvsc_req, blkvsc_req->cond); ++ ++ wait_event_interruptible(blkvsc_req->wevent, blkvsc_req->cond); ++ ++ // check error ++ if (blkvsc_req->request.Status) ++ { ++ scsi_normalize_sense(blkvsc_req->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr); ++ ++ if (sense_hdr.asc == 0x3A) // Medium not present ++ { ++ blkdev->media_not_present = 1; ++ } ++ ++ return 0; ++ } ++ buf = kmap(page_buf); ++ ++ // be to le ++ blkdev->capacity = be64_to_cpu(*(unsigned long long*) &buf[0]) + 1; ++ blkdev->sector_size = be32_to_cpu(*(unsigned int*)&buf[8]); ++ ++ //blkdev->capacity = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]) + 1; ++ //blkdev->sector_size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; ++ ++ kunmap(page_buf); ++ ++ __free_page(page_buf); ++ ++ kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req); ++ ++ return 0; ++} ++ ++/*++ ++ ++Name: blkvsc_remove() ++ ++Desc: Callback when our device is removed ++ ++--*/ ++static int blkvsc_remove(struct device *device) ++{ ++ int ret=0; ++ ++ struct driver_context *driver_ctx = driver_to_driver_context(device->driver); ++ struct blkvsc_driver_context *blkvsc_drv_ctx = (struct blkvsc_driver_context*)driver_ctx; ++ STORVSC_DRIVER_OBJECT* storvsc_drv_obj = &blkvsc_drv_ctx->drv_obj; ++ ++ struct device_context *device_ctx = device_to_device_context(device); ++ DEVICE_OBJECT* device_obj = &device_ctx->device_obj; ++ struct block_device_context *blkdev = (struct block_device_context*)device->driver_data; ++ unsigned long flags; ++ ++ DPRINT_ENTER(BLKVSC_DRV); ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_remove()\n"); ++ ++ if (!storvsc_drv_obj->Base.OnDeviceRemove) ++ { ++ DPRINT_EXIT(BLKVSC_DRV); ++ return -1; ++ } ++ ++ // Call to the vsc driver to let it know that the device is being removed ++ ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj); ++ if (ret != 0) ++ { ++ // TODO: ++ DPRINT_ERR(BLKVSC_DRV, "unable to remove blkvsc device (ret %d)", ret); ++ } ++ ++ // Get to a known state ++ spin_lock_irqsave(&blkdev->lock, flags); ++ ++ blkdev->shutting_down = 1; ++ ++ blk_stop_queue(blkdev->gd->queue); ++ ++ spin_unlock_irqrestore(&blkdev->lock, flags); ++ ++ while (blkdev->num_outstanding_reqs) ++ { ++ DPRINT_INFO(STORVSC, "waiting for %d requests to complete...", blkdev->num_outstanding_reqs); ++ ++ udelay(100); ++ } ++ ++ blkvsc_do_flush(blkdev); ++ ++ spin_lock_irqsave(&blkdev->lock, flags); ++ ++ blkvsc_cancel_pending_reqs(blkdev); ++ ++ spin_unlock_irqrestore(&blkdev->lock, flags); ++ ++ blk_cleanup_queue(blkdev->gd->queue); ++ ++ del_gendisk(blkdev->gd); ++ ++ kmem_cache_destroy(blkdev->request_pool); ++ ++ kfree(blkdev); ++ ++ DPRINT_EXIT(BLKVSC_DRV); ++ ++ return ret; ++} ++ ++static void blkvsc_init_rw(struct blkvsc_request *blkvsc_req) ++{ ++ ASSERT(blkvsc_req->req); ++ ASSERT(blkvsc_req->sector_count <= (MAX_MULTIPAGE_BUFFER_COUNT*8)); ++ ++ blkvsc_req->cmd_len = 16; ++ ++ if (blkvsc_req->sector_start > 0xffffffff) ++ { ++ if (rq_data_dir(blkvsc_req->req)) ++ { ++ blkvsc_req->write = 1; ++ blkvsc_req->cmnd[0] = WRITE_16; ++ } ++ else ++ { ++ blkvsc_req->write = 0; ++ blkvsc_req->cmnd[0] = READ_16; ++ } ++ ++ blkvsc_req->cmnd[1] |= blk_fua_rq(blkvsc_req->req) ? 0x8 : 0; ++ ++ *(unsigned long long*)&blkvsc_req->cmnd[2] = cpu_to_be64(blkvsc_req->sector_start); ++ *(unsigned int*)&blkvsc_req->cmnd[10] = cpu_to_be32(blkvsc_req->sector_count); ++ } ++ else if ((blkvsc_req->sector_count > 0xff) || (blkvsc_req->sector_start > 0x1fffff)) ++ { ++ if (rq_data_dir(blkvsc_req->req)) ++ { ++ blkvsc_req->write = 1; ++ blkvsc_req->cmnd[0] = WRITE_10; ++ } ++ else ++ { ++ blkvsc_req->write = 0; ++ blkvsc_req->cmnd[0] = READ_10; ++ } ++ ++ blkvsc_req->cmnd[1] |= blk_fua_rq(blkvsc_req->req) ? 0x8 : 0; ++ ++ *(unsigned int *)&blkvsc_req->cmnd[2] = cpu_to_be32(blkvsc_req->sector_start); ++ *(unsigned short*)&blkvsc_req->cmnd[7] = cpu_to_be16(blkvsc_req->sector_count); ++ } ++ else ++ { ++ if (rq_data_dir(blkvsc_req->req)) ++ { ++ blkvsc_req->write = 1; ++ blkvsc_req->cmnd[0] = WRITE_6; ++ } ++ else ++ { ++ blkvsc_req->write = 0; ++ blkvsc_req->cmnd[0] = READ_6; ++ } ++ ++ *(unsigned int *)&blkvsc_req->cmnd[1] = cpu_to_be32(blkvsc_req->sector_start) >> 8; ++ blkvsc_req->cmnd[1] &= 0x1f; ++ blkvsc_req->cmnd[4] = (unsigned char) blkvsc_req->sector_count; ++ } ++} ++ ++static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req, void (*request_completion)(STORVSC_REQUEST*) ) ++{ ++ struct block_device_context *blkdev = blkvsc_req->dev; ++ struct device_context *device_ctx=blkdev->device_ctx; ++ struct driver_context *driver_ctx = driver_to_driver_context(device_ctx->device.driver); ++ struct blkvsc_driver_context *blkvsc_drv_ctx = (struct blkvsc_driver_context*)driver_ctx; ++ STORVSC_DRIVER_OBJECT* storvsc_drv_obj = &blkvsc_drv_ctx->drv_obj; ++ int ret =0; ++ ++ STORVSC_REQUEST *storvsc_req; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - req %p type %s start_sector %llu count %d offset %d len %d\n", ++ blkvsc_req, ++ (blkvsc_req->write)?"WRITE":"READ", ++ blkvsc_req->sector_start, ++ blkvsc_req->sector_count, ++ blkvsc_req->request.DataBuffer.Offset, ++ blkvsc_req->request.DataBuffer.Length); ++ ++ /*for (i=0; i < (blkvsc_req->request.DataBuffer.Length >> 12); i++) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_submit_request() - req %p pfn[%d] %llx\n", ++ blkvsc_req, ++ i, ++ blkvsc_req->request.DataBuffer.PfnArray[i]); ++ }*/ ++ ++ storvsc_req = &blkvsc_req->request; ++ storvsc_req->Extension = (void*)((unsigned long)blkvsc_req + sizeof(struct blkvsc_request)); ++ ++ storvsc_req->Type = blkvsc_req->write? WRITE_TYPE : READ_TYPE; ++ ++ storvsc_req->OnIOCompletion = request_completion; ++ storvsc_req->Context = blkvsc_req; ++ ++ storvsc_req->Host = blkdev->port; ++ storvsc_req->Bus = blkdev->path; ++ storvsc_req->TargetId = blkdev->target; ++ storvsc_req->LunId = 0; // this is not really used at all ++ ++ storvsc_req->CdbLen = blkvsc_req->cmd_len; ++ storvsc_req->Cdb = blkvsc_req->cmnd; ++ ++ storvsc_req->SenseBuffer = blkvsc_req->sense_buffer; ++ storvsc_req->SenseBufferSize = SCSI_SENSE_BUFFERSIZE; ++ ++ ret = storvsc_drv_obj->OnIORequest(&blkdev->device_ctx->device_obj, &blkvsc_req->request); ++ if (ret == 0) ++ { ++ blkdev->num_outstanding_reqs++; ++ } ++ ++ return ret; ++} ++ ++// ++// We break the request into 1 or more blkvsc_requests and submit them. ++// If we cant submit them all, we put them on the pending_list. The ++// blkvsc_request() will work on the pending_list. ++// ++static int blkvsc_do_request(struct block_device_context *blkdev, struct request *req) ++{ ++ struct bio *bio=NULL; ++ struct bio_vec *bvec=NULL; ++ struct bio_vec *prev_bvec=NULL; ++ ++ struct blkvsc_request *blkvsc_req=NULL; ++ struct blkvsc_request *tmp; ++ int databuf_idx=0; ++ int seg_idx=0; ++ ++ sector_t start_sector; ++ unsigned long num_sectors = 0; ++ int ret=0; ++ int pending=0; ++ struct blkvsc_request_group *group=NULL; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p sect %llu \n", blkdev, req, req->sector); ++ ++ // Create a group to tie req to list of blkvsc_reqs ++ group = (struct blkvsc_request_group*)kmem_cache_alloc(blkdev->request_pool, GFP_ATOMIC); ++ if (!group) ++ { ++ return -ENOMEM; ++ } ++ ++ INIT_LIST_HEAD(&group->blkvsc_req_list); ++ group->outstanding = group->status = 0; ++ ++ start_sector = req->sector; ++ ++ // foreach bio in the request ++ if (req->bio) ++ for (bio = req->bio; bio; bio = bio->bi_next) ++ { ++ // Map this bio into an existing or new storvsc request ++ bio_for_each_segment (bvec, bio, seg_idx) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "bio_for_each_segment() - req %p bio %p bvec %p seg_idx %d databuf_idx %d\n", ++ req, bio, bvec, seg_idx, databuf_idx); ++ ++ // Get a new storvsc request ++ if ( (!blkvsc_req) || // 1st-time ++ (databuf_idx >= MAX_MULTIPAGE_BUFFER_COUNT) || ++ (bvec->bv_offset != 0) || // hole at the begin of page ++ (prev_bvec && (prev_bvec->bv_len != PAGE_SIZE)) ) // hold at the end of page ++ { ++ // submit the prev one ++ if (blkvsc_req) ++ { ++ blkvsc_req->sector_start = start_sector; ++ sector_div(blkvsc_req->sector_start, (blkdev->sector_size >> 9)); ++ ++ blkvsc_req->sector_count = num_sectors / (blkdev->sector_size >> 9); ++ ++ blkvsc_init_rw(blkvsc_req); ++ } ++ ++ // Create new blkvsc_req to represent the current bvec ++ blkvsc_req = kmem_cache_alloc(blkdev->request_pool, GFP_ATOMIC); ++ if (!blkvsc_req) ++ { ++ // free up everything ++ list_for_each_entry_safe(blkvsc_req, tmp, &group->blkvsc_req_list, req_entry) ++ { ++ list_del(&blkvsc_req->req_entry); ++ kmem_cache_free(blkdev->request_pool, blkvsc_req); ++ } ++ ++ kmem_cache_free(blkdev->request_pool, group); ++ return -ENOMEM; ++ } ++ ++ memset(blkvsc_req, 0, sizeof(struct blkvsc_request)); ++ ++ blkvsc_req->dev = blkdev; ++ blkvsc_req->req = req; ++ blkvsc_req->request.DataBuffer.Offset = bvec->bv_offset; ++ blkvsc_req->request.DataBuffer.Length = 0; ++ ++ // Add to the group ++ blkvsc_req->group = group; ++ blkvsc_req->group->outstanding++; ++ list_add_tail(&blkvsc_req->req_entry, &blkvsc_req->group->blkvsc_req_list); ++ ++ start_sector += num_sectors; ++ num_sectors = 0; ++ databuf_idx = 0; ++ } ++ ++ // Add the curr bvec/segment to the curr blkvsc_req ++ blkvsc_req->request.DataBuffer.PfnArray[databuf_idx] = page_to_pfn(bvec->bv_page); ++ blkvsc_req->request.DataBuffer.Length += bvec->bv_len; ++ ++ prev_bvec = bvec; ++ ++ databuf_idx++; ++ num_sectors += bvec->bv_len >> 9; ++ ++ } // bio_for_each_segment ++ ++ } // rq_for_each_bio ++ ++ // Handle the last one ++ if (blkvsc_req) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "blkdev %p req %p group %p count %d\n", blkdev, req, blkvsc_req->group, blkvsc_req->group->outstanding); ++ ++ blkvsc_req->sector_start = start_sector; ++ sector_div(blkvsc_req->sector_start, (blkdev->sector_size >> 9)); ++ ++ blkvsc_req->sector_count = num_sectors / (blkdev->sector_size >> 9); ++ ++ blkvsc_init_rw(blkvsc_req); ++ } ++ ++ list_for_each_entry(blkvsc_req, &group->blkvsc_req_list, req_entry) ++ { ++ if (pending) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "adding blkvsc_req to pending_list - blkvsc_req %p start_sect %llu sect_count %d (%llu %d)\n", ++ blkvsc_req, blkvsc_req->sector_start, blkvsc_req->sector_count, start_sector, num_sectors); ++ ++ list_add_tail(&blkvsc_req->pend_entry, &blkdev->pending_list); ++ } ++ else ++ { ++ ret = blkvsc_submit_request(blkvsc_req, blkvsc_request_completion); ++ if (ret == -1) ++ { ++ pending = 1; ++ list_add_tail(&blkvsc_req->pend_entry, &blkdev->pending_list); ++ } ++ ++ DPRINT_DBG(BLKVSC_DRV, "submitted blkvsc_req %p start_sect %llu sect_count %d (%llu %d) ret %d\n", ++ blkvsc_req, blkvsc_req->sector_start, blkvsc_req->sector_count, start_sector, num_sectors, ret); ++ } ++ } ++ ++ return pending; ++} ++ ++static void blkvsc_cmd_completion(STORVSC_REQUEST* request) ++{ ++ struct blkvsc_request *blkvsc_req=(struct blkvsc_request*)request->Context; ++ struct block_device_context *blkdev = (struct block_device_context*)blkvsc_req->dev; ++ ++ struct scsi_sense_hdr sense_hdr; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_cmd_completion() - req %p\n", blkvsc_req); ++ ++ blkdev->num_outstanding_reqs--; ++ ++ if (blkvsc_req->request.Status) ++ { ++ if (scsi_normalize_sense(blkvsc_req->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sense_hdr)) ++ { ++ scsi_print_sense_hdr("blkvsc", &sense_hdr); ++ } ++ } ++ ++ blkvsc_req->cond =1; ++ wake_up_interruptible(&blkvsc_req->wevent); ++} ++ ++static void blkvsc_request_completion(STORVSC_REQUEST* request) ++{ ++ struct blkvsc_request *blkvsc_req=(struct blkvsc_request*)request->Context; ++ struct block_device_context *blkdev = (struct block_device_context*)blkvsc_req->dev; ++ unsigned long flags; ++ struct blkvsc_request *comp_req, *tmp; ++ ++ ASSERT(blkvsc_req->group); ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkdev %p blkvsc_req %p group %p type %s sect_start %llu sect_count %d len %d group outstd %d total outstd %d\n", ++ blkdev, ++ blkvsc_req, ++ blkvsc_req->group, ++ (blkvsc_req->write)?"WRITE":"READ", ++ blkvsc_req->sector_start, ++ blkvsc_req->sector_count, ++ blkvsc_req->request.DataBuffer.Length, ++ blkvsc_req->group->outstanding, ++ blkdev->num_outstanding_reqs); ++ ++ spin_lock_irqsave(&blkdev->lock, flags); ++ ++ blkdev->num_outstanding_reqs--; ++ blkvsc_req->group->outstanding--; ++ ++ // Only start processing when all the blkvsc_reqs are completed. This guarantees no out-of-order ++ // blkvsc_req completion when calling end_that_request_first() ++ if (blkvsc_req->group->outstanding == 0) ++ { ++ list_for_each_entry_safe(comp_req, tmp, &blkvsc_req->group->blkvsc_req_list, req_entry) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p sect_start %llu sect_count %d \n", ++ comp_req, ++ comp_req->sector_start, ++ comp_req->sector_count); ++ ++ list_del(&comp_req->req_entry); ++ ++#ifdef KERNEL_2_6_27 ++ if (!__blk_end_request( ++ comp_req->req, ++ (!comp_req->request.Status ? 0: -EIO), ++ comp_req->sector_count * blkdev->sector_size)) ++ { ++ //All the sectors have been xferred ie the request is done ++ DPRINT_DBG(BLKVSC_DRV, "req %p COMPLETED\n", comp_req->req); ++ kmem_cache_free(blkdev->request_pool, comp_req->group); ++ } ++#else ++ if (!end_that_request_first(comp_req->req, !comp_req->request.Status, (comp_req->sector_count * (blkdev->sector_size >> 9)))) ++ { ++ //All the sectors have been xferred ie the request is done ++ DPRINT_DBG(BLKVSC_DRV, "req %p COMPLETED\n", comp_req->req); ++ ++ end_that_request_last(comp_req->req, !comp_req->request.Status); ++ ++ kmem_cache_free(blkdev->request_pool, comp_req->group); ++ } ++#endif ++ ++ kmem_cache_free(blkdev->request_pool, comp_req); ++ } ++ ++ if (!blkdev->shutting_down) ++ { ++ blkvsc_do_pending_reqs(blkdev); ++ blk_start_queue(blkdev->gd->queue); ++ blkvsc_request(blkdev->gd->queue); ++ } ++ } ++ ++ spin_unlock_irqrestore(&blkdev->lock, flags); ++} ++ ++static int blkvsc_cancel_pending_reqs(struct block_device_context *blkdev) ++{ ++ struct blkvsc_request *pend_req, *tmp; ++ struct blkvsc_request *comp_req, *tmp2; ++ ++ int ret=0; ++ ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_cancel_pending_reqs()"); ++ ++ // Flush the pending list first ++ list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list, pend_entry) ++ { ++ // The pend_req could be part of a partially completed request. If so, complete those req first ++ // until we hit the pend_req ++ list_for_each_entry_safe(comp_req, tmp2, &pend_req->group->blkvsc_req_list, req_entry) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "completing blkvsc_req %p sect_start %llu sect_count %d \n", ++ comp_req, ++ comp_req->sector_start, ++ comp_req->sector_count); ++ ++ if (comp_req == pend_req) ++ break; ++ ++ list_del(&comp_req->req_entry); ++ ++ if (comp_req->req) ++ { ++#ifdef KERNEL_2_6_27 ++ ret = __blk_end_request( ++ comp_req->req, ++ (!comp_req->request.Status ? 0 : -EIO), ++ comp_req->sector_count * blkdev->sector_size); ++#else ++ ret = end_that_request_first(comp_req->req, !comp_req->request.Status, (comp_req->sector_count * (blkdev->sector_size >> 9))); ++#endif ++ ASSERT(ret != 0); ++ } ++ ++ kmem_cache_free(blkdev->request_pool, comp_req); ++ } ++ ++ DPRINT_DBG(BLKVSC_DRV, "cancelling pending request - %p\n", pend_req); ++ ++ list_del(&pend_req->pend_entry); ++ ++ list_del(&pend_req->req_entry); ++ ++ if (comp_req->req) ++ { ++#ifdef KERNEL_2_6_27 ++ if (!__blk_end_request( ++ pend_req->req, ++ -EIO, ++ pend_req->sector_count * blkdev->sector_size)) ++ { ++ //All the sectors have been xferred ie the request is done ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_cancel_pending_reqs() - req %p COMPLETED\n", pend_req->req); ++ kmem_cache_free(blkdev->request_pool, pend_req->group); ++ } ++#else ++ if (!end_that_request_first(pend_req->req, 0, (pend_req->sector_count * (blkdev->sector_size >> 9)))) ++ { ++ //All the sectors have been xferred ie the request is done ++ DPRINT_DBG(BLKVSC_DRV, "blkvsc_cancel_pending_reqs() - req %p COMPLETED\n", pend_req->req); ++ ++ end_that_request_last(pend_req->req, 0); ++ ++ kmem_cache_free(blkdev->request_pool, pend_req->group); ++ } ++#endif ++ } ++ ++ kmem_cache_free(blkdev->request_pool, pend_req); ++ } ++ ++ return ret; ++} ++ ++static int blkvsc_do_pending_reqs(struct block_device_context *blkdev) ++{ ++ struct blkvsc_request *pend_req, *tmp; ++ int ret=0; ++ ++ // Flush the pending list first ++ list_for_each_entry_safe(pend_req, tmp, &blkdev->pending_list, pend_entry) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "working off pending_list - %p\n", pend_req); ++ ++ ret = blkvsc_submit_request(pend_req, blkvsc_request_completion); ++ if (ret != 0) ++ { ++ break; ++ } ++ else ++ { ++ list_del(&pend_req->pend_entry); ++ } ++ } ++ ++ return ret; ++} ++ ++static void blkvsc_request(struct request_queue *queue) ++{ ++ struct block_device_context *blkdev = NULL; ++ struct request *req; ++ int ret=0; ++ ++ DPRINT_DBG(BLKVSC_DRV, "- enter \n"); ++ while ((req = elv_next_request(queue)) != NULL) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "- req %p\n", req); ++ ++ blkdev = req->rq_disk->private_data; ++ if (blkdev->shutting_down || !blk_fs_request(req) || blkdev->media_not_present) { ++ end_request(req, 0); ++ continue; ++ } ++ ++ ret = blkvsc_do_pending_reqs(blkdev); ++ ++ if (ret != 0) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "- stop queue - pending_list not empty\n"); ++ blk_stop_queue(queue); ++ break; ++ } ++ ++ blkdev_dequeue_request(req); ++ ++ ret = blkvsc_do_request(blkdev, req); ++ if (ret > 0) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "- stop queue - no room\n"); ++ blk_stop_queue(queue); ++ break; ++ } ++ else if (ret < 0) ++ { ++ DPRINT_DBG(BLKVSC_DRV, "- stop queue - no mem\n"); ++ blk_requeue_request(queue, req); ++ blk_stop_queue(queue); ++ break; ++ } ++ } ++} ++ ++static int blkvsc_open(struct inode *inode, struct file *filep) ++{ ++ struct block_device_context *blkdev = inode->i_bdev->bd_disk->private_data; ++ ++ DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users, blkdev->gd->disk_name); ++ ++ spin_lock(&blkdev->lock); ++ ++ if (!blkdev->users && blkdev->device_type == DVD_TYPE) ++ { ++ spin_unlock(&blkdev->lock); ++ check_disk_change(inode->i_bdev); ++ spin_lock(&blkdev->lock); ++ } ++ ++ blkdev->users++; ++ ++ spin_unlock(&blkdev->lock); ++ return 0; ++} ++ ++static int blkvsc_release(struct inode *inode, struct file *filep) ++{ ++ struct block_device_context *blkdev = inode->i_bdev->bd_disk->private_data; ++ ++ DPRINT_DBG(BLKVSC_DRV, "- users %d disk %s\n", blkdev->users, blkdev->gd->disk_name); ++ ++ spin_lock(&blkdev->lock); ++ if (blkdev->users == 1) ++ { ++ spin_unlock(&blkdev->lock); ++ blkvsc_do_flush(blkdev); ++ spin_lock(&blkdev->lock); ++ } ++ ++ blkdev->users--; ++ ++ spin_unlock(&blkdev->lock); ++ return 0; ++} ++ ++static int blkvsc_media_changed(struct gendisk *gd) ++{ ++ DPRINT_DBG(BLKVSC_DRV, "- enter\n"); ++ ++ return 1; ++} ++ ++static int blkvsc_revalidate_disk(struct gendisk *gd) ++{ ++ struct block_device_context *blkdev = gd->private_data; ++ ++ DPRINT_DBG(BLKVSC_DRV, "- enter\n"); ++ ++ if (blkdev->device_type == DVD_TYPE) ++ { ++ blkvsc_do_read_capacity(blkdev); ++ set_capacity(blkdev->gd, blkdev->capacity * (blkdev->sector_size/512)); ++ blk_queue_hardsect_size(gd->queue, blkdev->sector_size); ++ } ++ return 0; ++} ++ ++int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg) ++{ ++ sector_t total_sectors = get_capacity(bd->bd_disk); ++ sector_t cylinder_times_heads=0; ++ sector_t temp=0; ++ ++ int sectors_per_track=0; ++ int heads=0; ++ int cylinders=0; ++ int rem=0; ++ ++ if (total_sectors > (65535 * 16 * 255)) { ++ total_sectors = (65535 * 16 * 255); ++ } ++ ++ if (total_sectors >= (65535 * 16 * 63)) { ++ sectors_per_track = 255; ++ heads = 16; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ } ++ else ++ { ++ sectors_per_track = 17; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ ++ temp = cylinder_times_heads + 1023; ++ rem = sector_div(temp, 1024); // sector_div stores the quotient in temp ++ ++ heads = temp; ++ ++ if (heads < 4) { ++ heads = 4; ++ } ++ ++ if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) { ++ sectors_per_track = 31; ++ heads = 16; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ } ++ ++ if (cylinder_times_heads >= (heads * 1024)) { ++ sectors_per_track = 63; ++ heads = 16; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ } ++ } ++ ++ temp = cylinder_times_heads; ++ rem = sector_div(temp, heads); // sector_div stores the quotient in temp ++ cylinders = temp; ++ ++ hg->heads = heads; ++ hg->sectors = sectors_per_track; ++ hg->cylinders = cylinders; ++ ++ DPRINT_INFO(BLKVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads, sectors_per_track); ++ ++ return 0; ++} ++ ++static int blkvsc_ioctl(struct inode *inode, struct file *filep, unsigned cmd, unsigned long arg) ++{ ++ struct block_device *bd = inode->i_bdev; ++ struct block_device_context *blkdev = bd->bd_disk->private_data; ++ int ret=0; ++ ++ switch (cmd) ++ { ++ // TODO: I think there is certain format for HDIO_GET_IDENTITY rather than just ++ // a GUID. Commented it out for now. ++ /*case HDIO_GET_IDENTITY: ++ DPRINT_INFO(BLKVSC_DRV, "HDIO_GET_IDENTITY\n"); ++ ++ if (copy_to_user((void __user *)arg, blkdev->device_id, blkdev->device_id_len)) ++ { ++ ret = -EFAULT; ++ } ++ ++ break;*/ ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++ ++MODULE_LICENSE("GPL"); ++ ++static int __init blkvsc_init(void) ++{ ++ int ret; ++ ++ ASSERT(sizeof(sector_t) == 8); // Make sure CONFIG_LBD is set ++ ++ DPRINT_ENTER(BLKVSC_DRV); ++ ++ DPRINT_INFO(BLKVSC_DRV, "Blkvsc initializing...."); ++ ++ ret = blkvsc_drv_init(BlkVscInitialize); ++ ++ DPRINT_EXIT(BLKVSC_DRV); ++ ++ return ret; ++} ++ ++static void __exit blkvsc_exit(void) ++{ ++ DPRINT_ENTER(BLKVSC_DRV); ++ ++ blkvsc_drv_exit(); ++ ++ DPRINT_ENTER(BLKVSC_DRV); ++} ++ ++module_param(blkvsc_ringbuffer_size, int, S_IRUGO); ++ ++module_init(blkvsc_init); ++module_exit(blkvsc_exit); ++ ++// eof diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus-to-the-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus-to-the-build.patch new file mode 100644 index 000000000..8ccfffbba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus-to-the-build.patch @@ -0,0 +1,54 @@ +From foo@baz Mon Jul 13 17:07:49 PDT 2009 +Date: Mon, 13 Jul 2009 17:07:49 -0700 +From: Greg Kroah-Hartman +Date: Mon, 13 Jul 2009 16:04:02 -0700 +Subject: Staging: hv: add the Hyper-V virtual bus to the build + +From: Greg Kroah-Hartman + +Add the Hyper-V virtual bus to the kernel build system. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Kconfig | 2 ++ + drivers/staging/Makefile | 1 + + drivers/staging/hv/Kconfig | 8 ++++++++ + drivers/staging/hv/Makefile | 3 +++ + 4 files changed, 14 insertions(+) + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -57,4 +57,6 @@ source "drivers/staging/benet/Kconfig" + + source "drivers/staging/rtl8187se/Kconfig" + ++source "drivers/staging/hv/Kconfig" ++ + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -20,3 +20,4 @@ obj-$(CONFIG_RT2870) += rt2870/ + obj-$(CONFIG_RT3070) += rt3070/ + obj-$(CONFIG_BENET) += benet/ + obj-$(CONFIG_RTL8187SE) += rtl8187se/ ++obj-$(CONFIG_HYPERV) += hv/ +--- /dev/null ++++ b/drivers/staging/hv/Kconfig +@@ -0,0 +1,8 @@ ++config HYPERV ++ tristate "Microsoft Hyper-V client drivers" ++ depends on X86 && !XEN ++ default n ++ help ++ Select this option to run Linux as a Hyper-V client operating ++ system. ++ +--- /dev/null ++++ b/drivers/staging/hv/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_HYPERV) += hv_vmbus.o ++ ++hv_vmbus-objs := vmbus_drv.o osd.o Sources.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus.patch new file mode 100644 index 000000000..e4d4fa435 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-bus.patch @@ -0,0 +1,7192 @@ +From foo@baz Mon Jul 13 16:02:34 PDT 2009 +Date: Mon, 13 Jul 2009 16:02:34 -0700 +From: Hank Janssen +Subject: Staging: hv: add the Hyper-V virtual bus + +From: Hank Janssen + +This is the virtual bus that all of the Linux Hyper-V drivers use. + +Signed-off-by: Hank Janssen +Signed-off-by: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/Channel.c | 1199 +++++++++++++++++++++++++++++++++ + drivers/staging/hv/Channel.h | 157 ++++ + drivers/staging/hv/ChannelInterface.c | 222 ++++++ + drivers/staging/hv/ChannelInterface.h | 41 + + drivers/staging/hv/ChannelMgmt.c | 826 ++++++++++++++++++++++ + drivers/staging/hv/ChannelMgmt.h | 156 ++++ + drivers/staging/hv/Connection.c | 432 +++++++++++ + drivers/staging/hv/Hv.c | 672 ++++++++++++++++++ + drivers/staging/hv/Hv.h | 184 +++++ + drivers/staging/hv/RingBuffer.c | 630 +++++++++++++++++ + drivers/staging/hv/RingBuffer.h | 123 +++ + drivers/staging/hv/Sources.c | 31 + drivers/staging/hv/VersionInfo.h | 29 + drivers/staging/hv/Vmbus.c | 508 ++++++++++++++ + drivers/staging/hv/VmbusPrivate.h | 170 ++++ + drivers/staging/hv/osd.c | 500 +++++++++++++ + drivers/staging/hv/vmbus_drv.c | 1228 ++++++++++++++++++++++++++++++++++ + 17 files changed, 7108 insertions(+) + +--- /dev/null ++++ b/drivers/staging/hv/Channel.c +@@ -0,0 +1,1199 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "osd.h" ++#include "logging.h" ++ ++#include "VmbusPrivate.h" ++ ++// ++// Internal routines ++// ++static int ++VmbusChannelCreateGpadlHeader( ++ PVOID Kbuffer, // must be phys and virt contiguous ++ UINT32 Size, // page-size multiple ++ VMBUS_CHANNEL_MSGINFO **msgInfo, ++ UINT32 *MessageCount ++ ); ++ ++static void ++DumpVmbusChannel( ++ VMBUS_CHANNEL *Channel ++ ); ++ ++ ++static void ++VmbusChannelSetEvent( ++ VMBUS_CHANNEL *Channel ++ ); ++ ++ ++#if 0 ++static void ++DumpMonitorPage( ++ HV_MONITOR_PAGE *MonitorPage ++ ) ++{ ++ int i=0; ++ int j=0; ++ ++ DPRINT_DBG(VMBUS, "monitorPage - %p, trigger state - %d", MonitorPage, MonitorPage->TriggerState); ++ ++ for (i=0; i<4; i++) ++ { ++ DPRINT_DBG(VMBUS, "trigger group (%d) - %llx", i, MonitorPage->TriggerGroup[i].AsUINT64); ++ } ++ ++ for (i=0; i<4; i++) ++ { ++ for (j=0; j<32; j++) ++ { ++ DPRINT_DBG(VMBUS, "latency (%d)(%d) - %llx", i, j, MonitorPage->Latency[i][j]); ++ } ++ } ++ for (i=0; i<4; i++) ++ { ++ for (j=0; j<32; j++) ++ { ++ DPRINT_DBG(VMBUS, "param-conn id (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].ConnectionId.AsUINT32); ++ DPRINT_DBG(VMBUS, "param-flag (%d)(%d) - %d", i, j, MonitorPage->Parameter[i][j].FlagNumber); ++ ++ } ++ } ++} ++#endif ++ ++/*++ ++ ++Name: ++ VmbusChannelSetEvent() ++ ++Description: ++ Trigger an event notification on the specified channel. ++ ++--*/ ++static void ++VmbusChannelSetEvent( ++ VMBUS_CHANNEL *Channel ++ ) ++{ ++ HV_MONITOR_PAGE *monitorPage; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ if (Channel->OfferMsg.MonitorAllocated) ++ { ++ // Each UINT32 represents 32 channels ++ BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31); ++ ++ monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; ++ monitorPage++; // Get the child to parent monitor page ++ ++ BitSet((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit); ++ } ++ else ++ { ++ VmbusSetEvent(Channel->OfferMsg.ChildRelId); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++#if 0 ++static void ++VmbusChannelClearEvent( ++ VMBUS_CHANNEL *Channel ++ ) ++{ ++ HV_MONITOR_PAGE *monitorPage; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ if (Channel->OfferMsg.MonitorAllocated) ++ { ++ // Each UINT32 represents 32 channels ++ BitClear((UINT32*)gVmbusConnection.SendInterruptPage + (Channel->OfferMsg.ChildRelId >> 5), Channel->OfferMsg.ChildRelId & 31); ++ ++ monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; ++ monitorPage++; // Get the child to parent monitor page ++ ++ BitClear((UINT32*) &monitorPage->TriggerGroup[Channel->MonitorGroup].Pending, Channel->MonitorBit); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++#endif ++/*++; ++ ++Name: ++ VmbusChannelGetDebugInfo() ++ ++Description: ++ Retrieve various channel debug info ++ ++--*/ ++void ++VmbusChannelGetDebugInfo( ++ VMBUS_CHANNEL *Channel, ++ VMBUS_CHANNEL_DEBUG_INFO *DebugInfo ++ ) ++{ ++ HV_MONITOR_PAGE *monitorPage; ++ UINT8 monitorGroup = (UINT8)Channel->OfferMsg.MonitorId / 32; ++ UINT8 monitorOffset = (UINT8)Channel->OfferMsg.MonitorId % 32; ++ //UINT32 monitorBit = 1 << monitorOffset; ++ ++ DebugInfo->RelId = Channel->OfferMsg.ChildRelId; ++ DebugInfo->State = Channel->State; ++ memcpy(&DebugInfo->InterfaceType, &Channel->OfferMsg.Offer.InterfaceType, sizeof(GUID)); ++ memcpy(&DebugInfo->InterfaceInstance, &Channel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID)); ++ ++ monitorPage = (HV_MONITOR_PAGE*)gVmbusConnection.MonitorPages; ++ ++ DebugInfo->MonitorId = Channel->OfferMsg.MonitorId; ++ ++ DebugInfo->ServerMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending; ++ DebugInfo->ServerMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset]; ++ DebugInfo->ServerMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id; ++ ++ monitorPage++; ++ ++ DebugInfo->ClientMonitorPending = monitorPage->TriggerGroup[monitorGroup].Pending; ++ DebugInfo->ClientMonitorLatency = monitorPage->Latency[monitorGroup][ monitorOffset]; ++ DebugInfo->ClientMonitorConnectionId = monitorPage->Parameter[monitorGroup][ monitorOffset].ConnectionId.u.Id; ++ ++ RingBufferGetDebugInfo(&Channel->Inbound, &DebugInfo->Inbound); ++ RingBufferGetDebugInfo(&Channel->Outbound, &DebugInfo->Outbound); ++} ++ ++ ++/*++; ++ ++Name: ++ VmbusChannelOpen() ++ ++Description: ++ Open the specified channel. ++ ++--*/ ++int ++VmbusChannelOpen( ++ VMBUS_CHANNEL *NewChannel, ++ UINT32 SendRingBufferSize, ++ UINT32 RecvRingBufferSize, ++ PVOID UserData, ++ UINT32 UserDataLen, ++ PFN_CHANNEL_CALLBACK pfnOnChannelCallback, ++ PVOID Context ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_OPEN_CHANNEL* openMsg; ++ VMBUS_CHANNEL_MSGINFO* openInfo; ++ void *in, *out; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Aligned to page size ++ ASSERT(!(SendRingBufferSize & (PAGE_SIZE -1))); ++ ASSERT(!(RecvRingBufferSize & (PAGE_SIZE -1))); ++ ++ NewChannel->OnChannelCallback = pfnOnChannelCallback; ++ NewChannel->ChannelCallbackContext = Context; ++ ++ // Allocate the ring buffer ++ out = PageAlloc((SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT); ++ //out = MemAllocZeroed(sendRingBufferSize + recvRingBufferSize); ++ ASSERT(out); ++ ASSERT(((ULONG_PTR)out & (PAGE_SIZE-1)) == 0); ++ ++ in = (void*)((ULONG_PTR)out + SendRingBufferSize); ++ ++ NewChannel->RingBufferPages = out; ++ NewChannel->RingBufferPageCount = (SendRingBufferSize + RecvRingBufferSize) >> PAGE_SHIFT; ++ ++ RingBufferInit(&NewChannel->Outbound, out, SendRingBufferSize); ++ ++ RingBufferInit(&NewChannel->Inbound, in, RecvRingBufferSize); ++ ++ // Establish the gpadl for the ring buffer ++ DPRINT_DBG(VMBUS, "Establishing ring buffer's gpadl for channel %p...", NewChannel); ++ ++ NewChannel->RingBufferGpadlHandle = 0; ++ ++ ret = VmbusChannelEstablishGpadl(NewChannel, ++ NewChannel->Outbound.RingBuffer, ++ SendRingBufferSize + RecvRingBufferSize, ++ &NewChannel->RingBufferGpadlHandle); ++ ++ DPRINT_DBG(VMBUS, "channel %p ", ++ NewChannel, ++ NewChannel->OfferMsg.ChildRelId, ++ NewChannel->RingBufferGpadlHandle, ++ NewChannel->Outbound.RingBuffer, ++ NewChannel->Outbound.RingSize, ++ NewChannel->Inbound.RingBuffer, ++ NewChannel->Inbound.RingSize, ++ SendRingBufferSize); ++ ++ // Create and init the channel open message ++ openInfo = ++ (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_OPEN_CHANNEL)); ++ ASSERT(openInfo != NULL); ++ ++ openInfo->WaitEvent = WaitEventCreate(); ++ ++ openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)openInfo->Msg; ++ openMsg->Header.MessageType = ChannelMessageOpenChannel; ++ openMsg->OpenId = NewChannel->OfferMsg.ChildRelId; // FIXME ++ openMsg->ChildRelId = NewChannel->OfferMsg.ChildRelId; ++ openMsg->RingBufferGpadlHandle = NewChannel->RingBufferGpadlHandle; ++ ASSERT(openMsg->RingBufferGpadlHandle); ++ openMsg->DownstreamRingBufferPageOffset = SendRingBufferSize >> PAGE_SHIFT; ++ openMsg->ServerContextAreaGpadlHandle = 0; // TODO ++ ++ ASSERT(UserDataLen <= MAX_USER_DEFINED_BYTES); ++ if (UserDataLen) ++ { ++ memcpy(openMsg->UserData, UserData, UserDataLen); ++ } ++ ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &openInfo->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_DBG(VMBUS, "Sending channel open msg..."); ++ ++ ret = VmbusPostMessage(openMsg, sizeof(VMBUS_CHANNEL_OPEN_CHANNEL)); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS, "unable to open channel - %d", ret); ++ goto Cleanup; ++ } ++ ++ // FIXME: Need to time-out here ++ WaitEventWait(openInfo->WaitEvent); ++ ++ if (openInfo->Response.OpenResult.Status == 0) ++ { ++ DPRINT_INFO(VMBUS, "channel <%p> open success!!", NewChannel); ++ } ++ else ++ { ++ DPRINT_INFO(VMBUS, "channel <%p> open failed - %d!!", NewChannel, openInfo->Response.OpenResult.Status); ++ } ++ ++Cleanup: ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ REMOVE_ENTRY_LIST(&openInfo->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ WaitEventClose(openInfo->WaitEvent); ++ MemFree(openInfo); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return 0; ++} ++ ++/*++; ++ ++Name: ++ DumpGpadlBody() ++ ++Description: ++ Dump the gpadl body message to the console for debugging purposes. ++ ++--*/ ++static void DumpGpadlBody( ++ VMBUS_CHANNEL_GPADL_BODY *Gpadl, ++ UINT32 Len) ++{ ++ int i=0; ++ int pfnCount=0; ++ ++ pfnCount = (Len - sizeof(VMBUS_CHANNEL_GPADL_BODY))/ sizeof(UINT64); ++ DPRINT_DBG(VMBUS, "gpadl body - len %d pfn count %d", Len, pfnCount); ++ ++ for (i=0; i< pfnCount; i++) ++ { ++ DPRINT_DBG(VMBUS, "gpadl body - %d) pfn %llu", i, Gpadl->Pfn[i]); ++ } ++} ++ ++ ++/*++; ++ ++Name: ++ DumpGpadlHeader() ++ ++Description: ++ Dump the gpadl header message to the console for debugging purposes. ++ ++--*/ ++static void DumpGpadlHeader( ++ VMBUS_CHANNEL_GPADL_HEADER *Gpadl ++ ) ++{ ++ int i=0,j=0; ++ int pageCount=0; ++ ++ ++ DPRINT_DBG(VMBUS, "gpadl header - relid %d, range count %d, range buflen %d", ++ Gpadl->ChildRelId, ++ Gpadl->RangeCount, ++ Gpadl->RangeBufLen); ++ for (i=0; i< Gpadl->RangeCount; i++) ++ { ++ pageCount = Gpadl->Range[i].ByteCount >> PAGE_SHIFT; ++ pageCount = (pageCount > 26)? 26 : pageCount; ++ ++ DPRINT_DBG(VMBUS, "gpadl range %d - len %d offset %d page count %d", ++ i, Gpadl->Range[i].ByteCount, Gpadl->Range[i].ByteOffset, pageCount); ++ ++ for (j=0; j< pageCount; j++) ++ { ++ DPRINT_DBG(VMBUS, "%d) pfn %llu", j, Gpadl->Range[i].PfnArray[j]); ++ } ++ } ++} ++ ++/*++; ++ ++Name: ++ VmbusChannelCreateGpadlHeader() ++ ++Description: ++ Creates a gpadl for the specified buffer ++ ++--*/ ++static int ++VmbusChannelCreateGpadlHeader( ++ PVOID Kbuffer, // from kmalloc() ++ UINT32 Size, // page-size multiple ++ VMBUS_CHANNEL_MSGINFO **MsgInfo, ++ UINT32 *MessageCount) ++{ ++ int i; ++ int pageCount; ++ unsigned long long pfn; ++ VMBUS_CHANNEL_GPADL_HEADER* gpaHeader; ++ VMBUS_CHANNEL_GPADL_BODY* gpadlBody; ++ VMBUS_CHANNEL_MSGINFO* msgHeader; ++ VMBUS_CHANNEL_MSGINFO* msgBody; ++ UINT32 msgSize; ++ ++ int pfnSum, pfnCount, pfnLeft, pfnCurr, pfnSize; ++ ++ //ASSERT( (kbuffer & (PAGE_SIZE-1)) == 0); ++ ASSERT( (Size & (PAGE_SIZE-1)) == 0); ++ ++ pageCount = Size >> PAGE_SHIFT; ++ pfn = GetPhysicalAddress(Kbuffer) >> PAGE_SHIFT; ++ ++ // do we need a gpadl body msg ++ pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_HEADER) - sizeof(GPA_RANGE); ++ pfnCount = pfnSize / sizeof(UINT64); ++ ++ if (pageCount > pfnCount) // we need a gpadl body ++ { ++ // fill in the header ++ msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pfnCount*sizeof(UINT64); ++ msgHeader = MemAllocZeroed(msgSize); ++ ++ INITIALIZE_LIST_HEAD(&msgHeader->SubMsgList); ++ msgHeader->MessageSize=msgSize; ++ ++ gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg; ++ gpaHeader->RangeCount = 1; ++ gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); ++ gpaHeader->Range[0].ByteOffset = 0; ++ gpaHeader->Range[0].ByteCount = Size; ++ for (i=0; iRange[0].PfnArray[i] = pfn+i; ++ } ++ *MsgInfo = msgHeader; ++ *MessageCount = 1; ++ ++ pfnSum = pfnCount; ++ pfnLeft = pageCount - pfnCount; ++ ++ // how many pfns can we fit ++ pfnSize = MAX_SIZE_CHANNEL_MESSAGE - sizeof(VMBUS_CHANNEL_GPADL_BODY); ++ pfnCount = pfnSize / sizeof(UINT64); ++ ++ // fill in the body ++ while (pfnLeft) ++ { ++ if (pfnLeft > pfnCount) ++ { ++ pfnCurr = pfnCount; ++ } ++ else ++ { ++ pfnCurr = pfnLeft; ++ } ++ ++ msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_BODY) + pfnCurr*sizeof(UINT64); ++ msgBody = MemAllocZeroed(msgSize); ++ ASSERT(msgBody); ++ msgBody->MessageSize = msgSize; ++ (*MessageCount)++; ++ gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)msgBody->Msg; ++ ++ // FIXME: Gpadl is UINT32 and we are using a pointer which could be 64-bit ++ //gpadlBody->Gpadl = kbuffer; ++ for (i=0; iPfn[i] = pfn + pfnSum + i; ++ } ++ ++ // add to msg header ++ INSERT_TAIL_LIST(&msgHeader->SubMsgList, &msgBody->MsgListEntry); ++ pfnSum += pfnCurr; ++ pfnLeft -= pfnCurr; ++ } ++ } ++ else ++ { ++ // everything fits in a header ++ msgSize = sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_HEADER) + sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); ++ msgHeader = MemAllocZeroed(msgSize); ++ msgHeader->MessageSize=msgSize; ++ ++ gpaHeader = (VMBUS_CHANNEL_GPADL_HEADER*)msgHeader->Msg; ++ gpaHeader->RangeCount = 1; ++ gpaHeader->RangeBufLen = sizeof(GPA_RANGE) + pageCount*sizeof(UINT64); ++ gpaHeader->Range[0].ByteOffset = 0; ++ gpaHeader->Range[0].ByteCount = Size; ++ for (i=0; iRange[0].PfnArray[i] = pfn+i; ++ } ++ ++ *MsgInfo = msgHeader; ++ *MessageCount = 1; ++ } ++ ++ return 0; ++} ++ ++ ++/*++; ++ ++Name: ++ VmbusChannelEstablishGpadl() ++ ++Description: ++ Estabish a GPADL for the specified buffer ++ ++--*/ ++int ++VmbusChannelEstablishGpadl( ++ VMBUS_CHANNEL *Channel, ++ PVOID Kbuffer, // from kmalloc() ++ UINT32 Size, // page-size multiple ++ UINT32 *GpadlHandle ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_GPADL_HEADER* gpadlMsg; ++ VMBUS_CHANNEL_GPADL_BODY* gpadlBody; ++ //VMBUS_CHANNEL_GPADL_CREATED* gpadlCreated; ++ ++ VMBUS_CHANNEL_MSGINFO *msgInfo; ++ VMBUS_CHANNEL_MSGINFO *subMsgInfo; ++ ++ UINT32 msgCount; ++ LIST_ENTRY* anchor; ++ LIST_ENTRY* curr; ++ UINT32 nextGpadlHandle; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ nextGpadlHandle = gVmbusConnection.NextGpadlHandle; ++ InterlockedIncrement((int*)&gVmbusConnection.NextGpadlHandle); ++ ++ VmbusChannelCreateGpadlHeader(Kbuffer, Size, &msgInfo, &msgCount); ++ ASSERT(msgInfo != NULL); ++ ASSERT(msgCount >0); ++ ++ msgInfo->WaitEvent = WaitEventCreate(); ++ gpadlMsg = (VMBUS_CHANNEL_GPADL_HEADER*)msgInfo->Msg; ++ gpadlMsg->Header.MessageType = ChannelMessageGpadlHeader; ++ gpadlMsg->ChildRelId = Channel->OfferMsg.ChildRelId; ++ gpadlMsg->Gpadl = nextGpadlHandle; ++ ++ DumpGpadlHeader(gpadlMsg); ++ ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_DBG(VMBUS, "buffer %p, size %d msg cnt %d", Kbuffer, Size, msgCount); ++ ++ DPRINT_DBG(VMBUS, "Sending GPADL Header - len %d", msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); ++ ++ ret = VmbusPostMessage(gpadlMsg, msgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS, "Unable to open channel - %d", ret); ++ goto Cleanup; ++ } ++ ++ if (msgCount>1) ++ { ++ ITERATE_LIST_ENTRIES(anchor, curr, &msgInfo->SubMsgList) ++ { ++ subMsgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; ++ gpadlBody = (VMBUS_CHANNEL_GPADL_BODY*)subMsgInfo->Msg; ++ ++ gpadlBody->Header.MessageType = ChannelMessageGpadlBody; ++ gpadlBody->Gpadl = nextGpadlHandle; ++ ++ DPRINT_DBG(VMBUS, "Sending GPADL Body - len %d", subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); ++ ++ DumpGpadlBody(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); ++ ret = VmbusPostMessage(gpadlBody, subMsgInfo->MessageSize - sizeof(VMBUS_CHANNEL_MSGINFO)); ++ ASSERT(ret == 0); ++ } ++ } ++ WaitEventWait(msgInfo->WaitEvent); ++ ++ // At this point, we received the gpadl created msg ++ DPRINT_DBG(VMBUS, "Received GPADL created (relid %d, status %d handle %x)", ++ Channel->OfferMsg.ChildRelId, ++ msgInfo->Response.GpadlCreated.CreationStatus, ++ gpadlMsg->Gpadl); ++ ++ *GpadlHandle = gpadlMsg->Gpadl; ++ ++Cleanup: ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ WaitEventClose(msgInfo->WaitEvent); ++ MemFree(msgInfo); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++ ++/*++; ++ ++Name: ++ VmbusChannelTeardownGpadl() ++ ++Description: ++ Teardown the specified GPADL handle ++ ++--*/ ++int ++VmbusChannelTeardownGpadl( ++ VMBUS_CHANNEL *Channel, ++ UINT32 GpadlHandle ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_GPADL_TEARDOWN *msg; ++ VMBUS_CHANNEL_MSGINFO* info; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ ASSERT(GpadlHandle != 0); ++ ++ info = ++ (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN)); ++ ASSERT(info != NULL); ++ ++ info->WaitEvent = WaitEventCreate(); ++ ++ msg = (VMBUS_CHANNEL_GPADL_TEARDOWN*)info->Msg; ++ ++ msg->Header.MessageType = ChannelMessageGpadlTeardown; ++ msg->ChildRelId = Channel->OfferMsg.ChildRelId; ++ msg->Gpadl = GpadlHandle; ++ ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &info->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_GPADL_TEARDOWN)); ++ if (ret != 0) ++ { ++ // TODO: ++ } ++ ++ WaitEventWait(info->WaitEvent); ++ ++ // Received a torndown response ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ REMOVE_ENTRY_LIST(&info->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ WaitEventClose(info->WaitEvent); ++ MemFree(info); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelClose() ++ ++Description: ++ Close the specified channel ++ ++--*/ ++VOID ++VmbusChannelClose( ++ VMBUS_CHANNEL *Channel ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_CLOSE_CHANNEL* msg; ++ VMBUS_CHANNEL_MSGINFO* info; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Stop callback and cancel the timer asap ++ Channel->OnChannelCallback = NULL; ++ TimerStop(Channel->PollTimer); ++ ++ // Send a closing message ++ info = ++ (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL)); ++ ASSERT(info != NULL); ++ ++ //info->waitEvent = WaitEventCreate(); ++ ++ msg = (VMBUS_CHANNEL_CLOSE_CHANNEL*)info->Msg; ++ msg->Header.MessageType = ChannelMessageCloseChannel; ++ msg->ChildRelId = Channel->OfferMsg.ChildRelId; ++ ++ ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_CLOSE_CHANNEL)); ++ if (ret != 0) ++ { ++ // TODO: ++ } ++ ++ // Tear down the gpadl for the channel's ring buffer ++ if (Channel->RingBufferGpadlHandle) ++ { ++ VmbusChannelTeardownGpadl(Channel, Channel->RingBufferGpadlHandle); ++ } ++ ++ // TODO: Send a msg to release the childRelId ++ ++ // Cleanup the ring buffers for this channel ++ RingBufferCleanup(&Channel->Outbound); ++ RingBufferCleanup(&Channel->Inbound); ++ ++ PageFree(Channel->RingBufferPages, Channel->RingBufferPageCount); ++ ++ MemFree(info); ++ ++ // If we are closing the channel during an error path in opening the channel, don't free the channel ++ // since the caller will free the channel ++ if (Channel->State == CHANNEL_OPEN_STATE) ++ { ++ SpinlockAcquire(gVmbusConnection.ChannelLock); ++ REMOVE_ENTRY_LIST(&Channel->ListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelLock); ++ ++ FreeVmbusChannel(Channel); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelSendPacket() ++ ++Description: ++ Send the specified buffer on the given channel ++ ++--*/ ++int ++VmbusChannelSendPacket( ++ VMBUS_CHANNEL *Channel, ++ const PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId, ++ VMBUS_PACKET_TYPE Type, ++ UINT32 Flags ++) ++{ ++ int ret=0; ++ VMPACKET_DESCRIPTOR desc; ++ UINT32 packetLen = sizeof(VMPACKET_DESCRIPTOR) + BufferLen; ++ UINT32 packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); ++ SG_BUFFER_LIST bufferList[3]; ++ UINT64 alignedData=0; ++ ++ DPRINT_ENTER(VMBUS); ++ DPRINT_DBG(VMBUS, "channel %p buffer %p len %d", Channel, Buffer, BufferLen); ++ ++ DumpVmbusChannel(Channel); ++ ++ ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); ++ ++ // Setup the descriptor ++ desc.Type = Type;//VmbusPacketTypeDataInBand; ++ desc.Flags = Flags;//VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; ++ desc.DataOffset8 = sizeof(VMPACKET_DESCRIPTOR) >> 3; // in 8-bytes granularity ++ desc.Length8 = (UINT16)(packetLenAligned >> 3); ++ desc.TransactionId = RequestId; ++ ++ bufferList[0].Data = &desc; ++ bufferList[0].Length = sizeof(VMPACKET_DESCRIPTOR); ++ ++ bufferList[1].Data = Buffer; ++ bufferList[1].Length = BufferLen; ++ ++ bufferList[2].Data = &alignedData; ++ bufferList[2].Length = packetLenAligned - packetLen; ++ ++ ret = RingBufferWrite( ++ &Channel->Outbound, ++ bufferList, ++ 3); ++ ++ // TODO: We should determine if this is optional ++ if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) ++ { ++ VmbusChannelSetEvent(Channel); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelSendPacketPageBuffer() ++ ++Description: ++ Send a range of single-page buffer packets using a GPADL Direct packet type. ++ ++--*/ ++int ++VmbusChannelSendPacketPageBuffer( ++ VMBUS_CHANNEL *Channel, ++ PAGE_BUFFER PageBuffers[], ++ UINT32 PageCount, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++) ++{ ++ int ret=0; ++ int i=0; ++ VMBUS_CHANNEL_PACKET_PAGE_BUFFER desc; ++ UINT32 descSize; ++ UINT32 packetLen; ++ UINT32 packetLenAligned; ++ SG_BUFFER_LIST bufferList[3]; ++ UINT64 alignedData=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ ASSERT(PageCount <= MAX_PAGE_BUFFER_COUNT); ++ ++ DumpVmbusChannel(Channel); ++ ++ // Adjust the size down since VMBUS_CHANNEL_PACKET_PAGE_BUFFER is the largest size we support ++ descSize = sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER) - ((MAX_PAGE_BUFFER_COUNT - PageCount)*sizeof(PAGE_BUFFER)); ++ packetLen = descSize + BufferLen; ++ packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); ++ ++ ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); ++ ++ // Setup the descriptor ++ desc.Type = VmbusPacketTypeDataUsingGpaDirect; ++ desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; ++ desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity ++ desc.Length8 = (UINT16)(packetLenAligned >> 3); ++ desc.TransactionId = RequestId; ++ desc.RangeCount = PageCount; ++ ++ for (i=0; iOutbound, ++ bufferList, ++ 3); ++ ++ // TODO: We should determine if this is optional ++ if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) ++ { ++ VmbusChannelSetEvent(Channel); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelSendPacketMultiPageBuffer() ++ ++Description: ++ Send a multi-page buffer packet using a GPADL Direct packet type. ++ ++--*/ ++int ++VmbusChannelSendPacketMultiPageBuffer( ++ VMBUS_CHANNEL *Channel, ++ MULTIPAGE_BUFFER *MultiPageBuffer, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER desc; ++ UINT32 descSize; ++ UINT32 packetLen; ++ UINT32 packetLenAligned; ++ SG_BUFFER_LIST bufferList[3]; ++ UINT64 alignedData=0; ++ UINT32 PfnCount = NUM_PAGES_SPANNED(MultiPageBuffer->Offset, MultiPageBuffer->Length); ++ ++ DPRINT_ENTER(VMBUS); ++ ++ DumpVmbusChannel(Channel); ++ ++ DPRINT_DBG(VMBUS, "data buffer - offset %u len %u pfn count %u", MultiPageBuffer->Offset, MultiPageBuffer->Length, PfnCount); ++ ++ ASSERT(PfnCount > 0); ++ ASSERT(PfnCount <= MAX_MULTIPAGE_BUFFER_COUNT); ++ ++ // Adjust the size down since VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER is the largest size we support ++ descSize = sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER) - ((MAX_MULTIPAGE_BUFFER_COUNT - PfnCount)*sizeof(UINT64)); ++ packetLen = descSize + BufferLen; ++ packetLenAligned = ALIGN_UP(packetLen, sizeof(UINT64)); ++ ++ ASSERT((packetLenAligned - packetLen) < sizeof(UINT64)); ++ ++ // Setup the descriptor ++ desc.Type = VmbusPacketTypeDataUsingGpaDirect; ++ desc.Flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; ++ desc.DataOffset8 = descSize >> 3; // in 8-bytes grandularity ++ desc.Length8 = (UINT16)(packetLenAligned >> 3); ++ desc.TransactionId = RequestId; ++ desc.RangeCount = 1; ++ ++ desc.Range.Length = MultiPageBuffer->Length; ++ desc.Range.Offset = MultiPageBuffer->Offset; ++ ++ memcpy(desc.Range.PfnArray, MultiPageBuffer->PfnArray, PfnCount*sizeof(UINT64)); ++ ++ bufferList[0].Data = &desc; ++ bufferList[0].Length = descSize; ++ ++ bufferList[1].Data = Buffer; ++ bufferList[1].Length = BufferLen; ++ ++ bufferList[2].Data = &alignedData; ++ bufferList[2].Length = packetLenAligned - packetLen; ++ ++ ret = RingBufferWrite( ++ &Channel->Outbound, ++ bufferList, ++ 3); ++ ++ // TODO: We should determine if this is optional ++ if (ret == 0 && !GetRingBufferInterruptMask(&Channel->Outbound)) ++ { ++ VmbusChannelSetEvent(Channel); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelRecvPacket() ++ ++Description: ++ Retrieve the user packet on the specified channel ++ ++--*/ ++// TODO: Do we ever receive a gpa direct packet other than the ones we send ? ++int ++VmbusChannelRecvPacket( ++ VMBUS_CHANNEL *Channel, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ) ++{ ++ VMPACKET_DESCRIPTOR desc; ++ UINT32 packetLen; ++ UINT32 userLen; ++ int ret; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ *BufferActualLen = 0; ++ *RequestId = 0; ++ ++ SpinlockAcquire(Channel->InboundLock); ++ ++ ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR)); ++ if (ret != 0) ++ { ++ SpinlockRelease(Channel->InboundLock); ++ ++ //DPRINT_DBG(VMBUS, "nothing to read!!"); ++ DPRINT_EXIT(VMBUS); ++ return 0; ++ } ++ ++ //VmbusChannelClearEvent(Channel); ++ ++ packetLen = desc.Length8 << 3; ++ userLen = packetLen - (desc.DataOffset8 << 3); ++ //ASSERT(userLen > 0); ++ ++ DPRINT_DBG(VMBUS, "packet received on channel %p relid %d ", ++ Channel, ++ Channel->OfferMsg.ChildRelId, ++ desc.Type, ++ desc.Flags, ++ desc.TransactionId, packetLen, userLen); ++ ++ *BufferActualLen = userLen; ++ ++ if (userLen > BufferLen) ++ { ++ SpinlockRelease(Channel->InboundLock); ++ ++ DPRINT_ERR(VMBUS, "buffer too small - got %d needs %d", BufferLen, userLen); ++ DPRINT_EXIT(VMBUS); ++ ++ return -1; ++ } ++ ++ *RequestId = desc.TransactionId; ++ ++ // Copy over the packet to the user buffer ++ ret = RingBufferRead(&Channel->Inbound, Buffer, userLen, (desc.DataOffset8 << 3)); ++ ++ SpinlockRelease(Channel->InboundLock); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return 0; ++} ++ ++/*++ ++ ++Name: ++ VmbusChannelRecvPacketRaw() ++ ++Description: ++ Retrieve the raw packet on the specified channel ++ ++--*/ ++int ++VmbusChannelRecvPacketRaw( ++ VMBUS_CHANNEL *Channel, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ) ++{ ++ VMPACKET_DESCRIPTOR desc; ++ UINT32 packetLen; ++ UINT32 userLen; ++ int ret; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ *BufferActualLen = 0; ++ *RequestId = 0; ++ ++ SpinlockAcquire(Channel->InboundLock); ++ ++ ret = RingBufferPeek(&Channel->Inbound, &desc, sizeof(VMPACKET_DESCRIPTOR)); ++ if (ret != 0) ++ { ++ SpinlockRelease(Channel->InboundLock); ++ ++ //DPRINT_DBG(VMBUS, "nothing to read!!"); ++ DPRINT_EXIT(VMBUS); ++ return 0; ++ } ++ ++ //VmbusChannelClearEvent(Channel); ++ ++ packetLen = desc.Length8 << 3; ++ userLen = packetLen - (desc.DataOffset8 << 3); ++ ++ DPRINT_DBG(VMBUS, "packet received on channel %p relid %d ", ++ Channel, ++ Channel->OfferMsg.ChildRelId, ++ desc.Type, ++ desc.Flags, ++ desc.TransactionId, packetLen, userLen); ++ ++ *BufferActualLen = packetLen; ++ ++ if (packetLen > BufferLen) ++ { ++ SpinlockRelease(Channel->InboundLock); ++ ++ DPRINT_ERR(VMBUS, "buffer too small - needed %d bytes but got space for only %d bytes", packetLen, BufferLen); ++ DPRINT_EXIT(VMBUS); ++ return -2; ++ } ++ ++ *RequestId = desc.TransactionId; ++ ++ // Copy over the entire packet to the user buffer ++ ret = RingBufferRead(&Channel->Inbound, Buffer, packetLen, 0); ++ ++ SpinlockRelease(Channel->InboundLock); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return 0; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnChannelEvent() ++ ++Description: ++ Channel event callback ++ ++--*/ ++void ++VmbusChannelOnChannelEvent( ++ VMBUS_CHANNEL *Channel ++ ) ++{ ++ DumpVmbusChannel(Channel); ++ ASSERT(Channel->OnChannelCallback); ++#ifdef ENABLE_POLLING ++ TimerStop(Channel->PollTimer); ++ Channel->OnChannelCallback(Channel->ChannelCallbackContext); ++ TimerStart(Channel->PollTimer, 100 /* 100us */); ++#else ++ Channel->OnChannelCallback(Channel->ChannelCallbackContext); ++#endif ++} ++ ++/*++ ++ ++Name: ++ VmbusChannelOnTimer() ++ ++Description: ++ Timer event callback ++ ++--*/ ++void ++VmbusChannelOnTimer( ++ void *Context ++ ) ++{ ++ VMBUS_CHANNEL *channel = (VMBUS_CHANNEL*)Context; ++ ++ if (channel->OnChannelCallback) ++ { ++ channel->OnChannelCallback(channel->ChannelCallbackContext); ++#ifdef ENABLE_POLLING ++ TimerStart(channel->PollTimer, 100 /* 100us */); ++#endif ++ } ++} ++ ++ ++/*++ ++ ++Name: ++ DumpVmbusChannel() ++ ++Description: ++ Dump vmbus channel info to the console ++ ++--*/ ++static void ++DumpVmbusChannel( ++ VMBUS_CHANNEL *Channel ++ ) ++{ ++ DPRINT_DBG(VMBUS, "Channel (%d)", Channel->OfferMsg.ChildRelId); ++ DumpRingInfo(&Channel->Outbound, "Outbound "); ++ DumpRingInfo(&Channel->Inbound, "Inbound "); ++} ++ ++ ++// eof +--- /dev/null ++++ b/drivers/staging/hv/Channel.h +@@ -0,0 +1,157 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _CHANNEL_H_ ++#define _CHANNEL_H_ ++ ++#include "osd.h" ++#include "ChannelMgmt.h" ++ ++#pragma pack(push,1) ++ ++ ++// The format must be the same as VMDATA_GPA_DIRECT ++typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER { ++ UINT16 Type; ++ UINT16 DataOffset8; ++ UINT16 Length8; ++ UINT16 Flags; ++ UINT64 TransactionId; ++ UINT32 Reserved; ++ UINT32 RangeCount; ++ PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT]; ++} VMBUS_CHANNEL_PACKET_PAGE_BUFFER; ++ ++ ++// The format must be the same as VMDATA_GPA_DIRECT ++typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER { ++ UINT16 Type; ++ UINT16 DataOffset8; ++ UINT16 Length8; ++ UINT16 Flags; ++ UINT64 TransactionId; ++ UINT32 Reserved; ++ UINT32 RangeCount; // Always 1 in this case ++ MULTIPAGE_BUFFER Range; ++} VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER; ++ ++#pragma pack(pop) ++ ++// ++// Routines ++// ++ ++INTERNAL int ++VmbusChannelOpen( ++ VMBUS_CHANNEL *Channel, ++ UINT32 SendRingBufferSize, ++ UINT32 RecvRingBufferSize, ++ PVOID UserData, ++ UINT32 UserDataLen, ++ PFN_CHANNEL_CALLBACK pfnOnChannelCallback, ++ PVOID Context ++ ); ++ ++INTERNAL void ++VmbusChannelClose( ++ VMBUS_CHANNEL *Channel ++ ); ++ ++INTERNAL int ++VmbusChannelSendPacket( ++ VMBUS_CHANNEL *Channel, ++ const PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId, ++ VMBUS_PACKET_TYPE Type, ++ UINT32 Flags ++); ++ ++INTERNAL int ++VmbusChannelSendPacketPageBuffer( ++ VMBUS_CHANNEL *Channel, ++ PAGE_BUFFER PageBuffers[], ++ UINT32 PageCount, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++ ); ++ ++INTERNAL int ++VmbusChannelSendPacketMultiPageBuffer( ++ VMBUS_CHANNEL *Channel, ++ MULTIPAGE_BUFFER *MultiPageBuffer, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++); ++ ++INTERNAL int ++VmbusChannelEstablishGpadl( ++ VMBUS_CHANNEL *Channel, ++ PVOID Kbuffer, // from kmalloc() ++ UINT32 Size, // page-size multiple ++ UINT32 *GpadlHandle ++ ); ++ ++INTERNAL int ++VmbusChannelTeardownGpadl( ++ VMBUS_CHANNEL *Channel, ++ UINT32 GpadlHandle ++ ); ++ ++INTERNAL int ++VmbusChannelRecvPacket( ++ VMBUS_CHANNEL *Channel, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ); ++ ++INTERNAL int ++VmbusChannelRecvPacketRaw( ++ VMBUS_CHANNEL *Channel, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ); ++ ++INTERNAL void ++VmbusChannelOnChannelEvent( ++ VMBUS_CHANNEL *Channel ++ ); ++ ++INTERNAL void ++VmbusChannelGetDebugInfo( ++ VMBUS_CHANNEL *Channel, ++ VMBUS_CHANNEL_DEBUG_INFO *DebugInfo ++ ); ++ ++INTERNAL void ++VmbusChannelOnTimer( ++ void *Context ++ ); ++#endif //_CHANNEL_H_ +--- /dev/null ++++ b/drivers/staging/hv/ChannelInterface.c +@@ -0,0 +1,222 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++#include "VmbusPrivate.h" ++ ++INTERNAL int ++IVmbusChannelOpen( ++ PDEVICE_OBJECT Device, ++ UINT32 SendBufferSize, ++ UINT32 RecvRingBufferSize, ++ PVOID UserData, ++ UINT32 UserDataLen, ++ VMBUS_CHANNEL_CALLBACK ChannelCallback, ++ PVOID Context ++ ) ++{ ++ return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context, ++ SendBufferSize, ++ RecvRingBufferSize, ++ UserData, ++ UserDataLen, ++ ChannelCallback, ++ Context); ++} ++ ++ ++INTERNAL void ++IVmbusChannelClose( ++ PDEVICE_OBJECT Device ++ ) ++{ ++ VmbusChannelClose((VMBUS_CHANNEL*)Device->context); ++} ++ ++ ++INTERNAL int ++IVmbusChannelSendPacket( ++ PDEVICE_OBJECT Device, ++ const PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId, ++ UINT32 Type, ++ UINT32 Flags ++ ) ++{ ++ return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context, ++ Buffer, ++ BufferLen, ++ RequestId, ++ Type, ++ Flags); ++} ++ ++INTERNAL int ++IVmbusChannelSendPacketPageBuffer( ++ PDEVICE_OBJECT Device, ++ PAGE_BUFFER PageBuffers[], ++ UINT32 PageCount, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++ ) ++{ ++ return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context, ++ PageBuffers, ++ PageCount, ++ Buffer, ++ BufferLen, ++ RequestId); ++} ++ ++INTERNAL int ++IVmbusChannelSendPacketMultiPageBuffer( ++ PDEVICE_OBJECT Device, ++ MULTIPAGE_BUFFER *MultiPageBuffer, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT64 RequestId ++ ) ++{ ++ return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context, ++ MultiPageBuffer, ++ Buffer, ++ BufferLen, ++ RequestId); ++} ++ ++INTERNAL int ++IVmbusChannelRecvPacket ( ++ PDEVICE_OBJECT Device, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ) ++{ ++ return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context, ++ Buffer, ++ BufferLen, ++ BufferActualLen, ++ RequestId); ++} ++ ++INTERNAL int ++IVmbusChannelRecvPacketRaw( ++ PDEVICE_OBJECT Device, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* BufferActualLen, ++ UINT64* RequestId ++ ) ++{ ++ return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context, ++ Buffer, ++ BufferLen, ++ BufferActualLen, ++ RequestId); ++} ++ ++INTERNAL int ++IVmbusChannelEstablishGpadl( ++ PDEVICE_OBJECT Device, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32* GpadlHandle ++ ) ++{ ++ return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context, ++ Buffer, ++ BufferLen, ++ GpadlHandle); ++} ++ ++INTERNAL int ++IVmbusChannelTeardownGpadl( ++ PDEVICE_OBJECT Device, ++ UINT32 GpadlHandle ++ ) ++{ ++ return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context, ++ GpadlHandle); ++ ++} ++ ++INTERNAL void ++GetChannelInterface( ++ VMBUS_CHANNEL_INTERFACE *ChannelInterface ++ ) ++{ ++ ChannelInterface->Open = IVmbusChannelOpen; ++ ChannelInterface->Close = IVmbusChannelClose; ++ ChannelInterface->SendPacket = IVmbusChannelSendPacket; ++ ChannelInterface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer; ++ ChannelInterface->SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer; ++ ChannelInterface->RecvPacket = IVmbusChannelRecvPacket; ++ ChannelInterface->RecvPacketRaw = IVmbusChannelRecvPacketRaw; ++ ChannelInterface->EstablishGpadl = IVmbusChannelEstablishGpadl; ++ ChannelInterface->TeardownGpadl = IVmbusChannelTeardownGpadl; ++ ChannelInterface->GetInfo = GetChannelInfo; ++} ++ ++ ++INTERNAL void ++GetChannelInfo( ++ PDEVICE_OBJECT Device, ++ DEVICE_INFO *DeviceInfo ++ ) ++{ ++ VMBUS_CHANNEL_DEBUG_INFO debugInfo; ++ ++ if (Device->context) ++ { ++ VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo); ++ ++ DeviceInfo->ChannelId = debugInfo.RelId; ++ DeviceInfo->ChannelState = debugInfo.State; ++ memcpy(&DeviceInfo->ChannelType, &debugInfo.InterfaceType, sizeof(GUID)); ++ memcpy(&DeviceInfo->ChannelInstance, &debugInfo.InterfaceInstance, sizeof(GUID)); ++ ++ DeviceInfo->MonitorId = debugInfo.MonitorId; ++ ++ DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending; ++ DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency; ++ DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId; ++ ++ DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending; ++ DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency; ++ DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId; ++ ++ DeviceInfo->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask; ++ DeviceInfo->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex; ++ DeviceInfo->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex; ++ DeviceInfo->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead; ++ DeviceInfo->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite; ++ ++ DeviceInfo->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask; ++ DeviceInfo->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex; ++ DeviceInfo->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex; ++ DeviceInfo->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead; ++ DeviceInfo->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite; ++ } ++} +--- /dev/null ++++ b/drivers/staging/hv/ChannelInterface.h +@@ -0,0 +1,41 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _CHANNEL_INTERFACE_H_ ++#define _CHANNEL_INTERFACE_H_ ++ ++#include "VmbusApi.h" ++ ++INTERNAL void ++GetChannelInterface( ++ VMBUS_CHANNEL_INTERFACE *ChannelInterface ++ ); ++ ++INTERNAL void ++GetChannelInfo( ++ PDEVICE_OBJECT Device, ++ DEVICE_INFO *DeviceInfo ++ ); ++ ++#endif // _CHANNEL_INTERFACE_H_ +--- /dev/null ++++ b/drivers/staging/hv/ChannelMgmt.c +@@ -0,0 +1,826 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "osd.h" ++#include "logging.h" ++ ++#include "VmbusPrivate.h" ++ ++// ++// Defines ++// ++ ++// ++// Data types ++// ++ ++typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg); ++ ++typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY { ++ VMBUS_CHANNEL_MESSAGE_TYPE messageType; ++ PFN_CHANNEL_MESSAGE_HANDLER messageHandler; ++} VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY; ++ ++// ++// Internal routines ++// ++ ++static void ++VmbusChannelOnOffer( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++static void ++VmbusChannelOnOpenResult( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++ ++static void ++VmbusChannelOnOfferRescind( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++ ++static void ++VmbusChannelOnGpadlCreated( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++ ++static void ++VmbusChannelOnGpadlTorndown( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++ ++static void ++VmbusChannelOnOffersDelivered( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++ ++static void ++VmbusChannelOnVersionResponse( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ); ++ ++static void ++VmbusChannelProcessOffer( ++ PVOID context ++ ); ++ ++static void ++VmbusChannelProcessRescindOffer( ++ PVOID context ++ ); ++ ++ ++// ++// Globals ++// ++ ++#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4 ++ ++const GUID gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED]= { ++ //{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} ++ {.Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}},// Storage - SCSI ++ //{F8615163-DF3E-46c5-913F-F2D2F965ED0E} ++ {.Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}}, // Network ++ //{CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} ++ {.Data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}}, // Input ++ //{32412632-86cb-44a2-9b5c-50d1417354f5} ++ {.Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}}, // IDE ++ ++}; ++ ++// Channel message dispatch table ++VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= { ++ {ChannelMessageInvalid, NULL}, ++ {ChannelMessageOfferChannel, VmbusChannelOnOffer}, ++ {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind}, ++ {ChannelMessageRequestOffers, NULL}, ++ {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered}, ++ {ChannelMessageOpenChannel, NULL}, ++ {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult}, ++ {ChannelMessageCloseChannel, NULL}, ++ {ChannelMessageGpadlHeader, NULL}, ++ {ChannelMessageGpadlBody, NULL}, ++ {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated}, ++ {ChannelMessageGpadlTeardown, NULL}, ++ {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown}, ++ {ChannelMessageRelIdReleased, NULL}, ++ {ChannelMessageInitiateContact, NULL}, ++ {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse}, ++ {ChannelMessageUnload, NULL}, ++}; ++ ++/*++ ++ ++Name: ++ AllocVmbusChannel() ++ ++Description: ++ Allocate and initialize a vmbus channel object ++ ++--*/ ++VMBUS_CHANNEL* AllocVmbusChannel(void) ++{ ++ VMBUS_CHANNEL* channel; ++ ++ channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL)); ++ if (!channel) ++ { ++ return NULL; ++ } ++ ++ memset(channel, 0,sizeof(VMBUS_CHANNEL)); ++ channel->InboundLock = SpinlockCreate(); ++ if (!channel->InboundLock) ++ { ++ MemFree(channel); ++ return NULL; ++ } ++ ++ channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel); ++ if (!channel->PollTimer) ++ { ++ SpinlockClose(channel->InboundLock); ++ MemFree(channel); ++ return NULL; ++ } ++ ++ //channel->dataWorkQueue = WorkQueueCreate("data"); ++ channel->ControlWQ = WorkQueueCreate("control"); ++ if (!channel->ControlWQ) ++ { ++ TimerClose(channel->PollTimer); ++ SpinlockClose(channel->InboundLock); ++ MemFree(channel); ++ return NULL; ++ } ++ ++ return channel; ++} ++ ++/*++ ++ ++Name: ++ ReleaseVmbusChannel() ++ ++Description: ++ Release the vmbus channel object itself ++ ++--*/ ++static inline void ReleaseVmbusChannel(void* Context) ++{ ++ VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ DPRINT_DBG(VMBUS, "releasing channel (%p)", channel); ++ WorkQueueClose(channel->ControlWQ); ++ DPRINT_DBG(VMBUS, "channel released (%p)", channel); ++ ++ MemFree(channel); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++/*++ ++ ++Name: ++ FreeVmbusChannel() ++ ++Description: ++ Release the resources used by the vmbus channel object ++ ++--*/ ++void FreeVmbusChannel(VMBUS_CHANNEL* Channel) ++{ ++ SpinlockClose(Channel->InboundLock); ++ TimerClose(Channel->PollTimer); ++ ++ // We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context ++ // ie we can't destroy ourselves. ++ WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, ReleaseVmbusChannel, (void*)Channel); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelProcessOffer() ++ ++Description: ++ Process the offer by creating a channel/device associated with this offer ++ ++--*/ ++static void ++VmbusChannelProcessOffer( ++ PVOID context ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context; ++ LIST_ENTRY* anchor; ++ LIST_ENTRY* curr; ++ BOOL fNew=TRUE; ++ VMBUS_CHANNEL* channel; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Make sure this is a new offer ++ SpinlockAcquire(gVmbusConnection.ChannelLock); ++ ++ ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) ++ { ++ channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry); ++ ++ if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(GUID)) && ++ !memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID))) ++ { ++ fNew = FALSE; ++ break; ++ } ++ } ++ ++ if (fNew) ++ { ++ INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry); ++ } ++ SpinlockRelease(gVmbusConnection.ChannelLock); ++ ++ if (!fNew) ++ { ++ DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId); ++ FreeVmbusChannel(newChannel); ++ DPRINT_EXIT(VMBUS); ++ return; ++ } ++ ++ // Start the process of binding this offer to the driver ++ // We need to set the DeviceObject field before calling VmbusChildDeviceAdd() ++ newChannel->DeviceObject = VmbusChildDeviceCreate( ++ newChannel->OfferMsg.Offer.InterfaceType, ++ newChannel->OfferMsg.Offer.InterfaceInstance, ++ newChannel); ++ ++ DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject); ++ ++ // Add the new device to the bus. This will kick off device-driver binding ++ // which eventually invokes the device driver's AddDevice() method. ++ ret = VmbusChildDeviceAdd(newChannel->DeviceObject); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)", ++ newChannel->OfferMsg.ChildRelId); ++ ++ SpinlockAcquire(gVmbusConnection.ChannelLock); ++ REMOVE_ENTRY_LIST(&newChannel->ListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelLock); ++ ++ FreeVmbusChannel(newChannel); ++ } ++ else ++ { ++ // This state is used to indicate a successful open so that when we do close the channel normally, ++ // we can cleanup properly ++ newChannel->State = CHANNEL_OPEN_STATE; ++ } ++ DPRINT_EXIT(VMBUS); ++} ++ ++/*++ ++ ++Name: ++ VmbusChannelProcessRescindOffer() ++ ++Description: ++ Rescind the offer by initiating a device removal ++ ++--*/ ++static void ++VmbusChannelProcessRescindOffer( ++ PVOID context ++ ) ++{ ++ VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ VmbusChildDeviceRemove(channel->DeviceObject); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnOffer() ++ ++Description: ++ Handler for channel offers from vmbus in parent partition. We ignore all offers except ++ network and storage offers. For each network and storage offers, we create a channel object ++ and queue a work item to the channel object to process the offer synchronously ++ ++--*/ ++static void ++VmbusChannelOnOffer( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr; ++ VMBUS_CHANNEL* newChannel; ++ ++ GUID *guidType; ++ GUID *guidInstance; ++ int i; ++ int fSupported=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ for (i=0; iOffer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0) ++ { ++ fSupported = 1; ++ break; ++ } ++ } ++ ++ if (!fSupported) ++ { ++ DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId); ++ DPRINT_EXIT(VMBUS); ++ ++ return; ++ } ++ ++ guidType = &offer->Offer.InterfaceType; ++ guidInstance = &offer->Offer.InterfaceInstance; ++ ++ DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, " ++ "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} " ++ "instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ offer->ChildRelId, ++ offer->MonitorId, ++ offer->MonitorAllocated, ++ guidType->Data[3], guidType->Data[2], guidType->Data[1], guidType->Data[0], guidType->Data[5], guidType->Data[4], guidType->Data[7], guidType->Data[6], guidType->Data[8], guidType->Data[9], guidType->Data[10], guidType->Data[11], guidType->Data[12], guidType->Data[13], guidType->Data[14], guidType->Data[15], ++ guidInstance->Data[3], guidInstance->Data[2], guidInstance->Data[1], guidInstance->Data[0], guidInstance->Data[5], guidInstance->Data[4], guidInstance->Data[7], guidInstance->Data[6], guidInstance->Data[8], guidInstance->Data[9], guidInstance->Data[10], guidInstance->Data[11], guidInstance->Data[12], guidInstance->Data[13], guidInstance->Data[14], guidInstance->Data[15]); ++ ++ // Allocate the channel object and save this offer. ++ newChannel = AllocVmbusChannel(); ++ if (!newChannel) ++ { ++ DPRINT_ERR(VMBUS, "unable to allocate channel object"); ++ return; ++ } ++ ++ DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel); ++ ++ memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL)); ++ newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32; ++ newChannel->MonitorBit = (UINT8)offer->MonitorId % 32; ++ ++ // TODO: Make sure the offer comes from our parent partition ++ WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnOfferRescind() ++ ++Description: ++ Rescind offer handler. We queue a work item to process this offer ++ synchronously ++ ++--*/ ++static void ++VmbusChannelOnOfferRescind( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr; ++ VMBUS_CHANNEL* channel; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ channel = GetChannelFromRelId(rescind->ChildRelId); ++ if (channel == NULL) ++ { ++ DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId); ++ return; ++ } ++ ++ WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnOffersDelivered() ++ ++Description: ++ This is invoked when all offers have been delivered. ++ Nothing to do here. ++ ++--*/ ++static void ++VmbusChannelOnOffersDelivered( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ DPRINT_ENTER(VMBUS); ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnOpenResult() ++ ++Description: ++ Open result handler. This is invoked when we received a response ++ to our channel open request. Find the matching request, copy the ++ response and signal the requesting thread. ++ ++--*/ ++static void ++VmbusChannelOnOpenResult( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr; ++ LIST_ENTRY* anchor; ++ LIST_ENTRY* curr; ++ VMBUS_CHANNEL_MSGINFO* msgInfo; ++ VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader; ++ VMBUS_CHANNEL_OPEN_CHANNEL* openMsg; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status); ++ ++ // Find the open msg, copy the result and signal/unblock the wait event ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ ++ ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) ++ { ++ msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; ++ requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; ++ ++ if (requestHeader->MessageType == ChannelMessageOpenChannel) ++ { ++ openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg; ++ if (openMsg->ChildRelId == result->ChildRelId && ++ openMsg->OpenId == result->OpenId) ++ { ++ memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT)); ++ WaitEventSet(msgInfo->WaitEvent); ++ break; ++ } ++ } ++ } ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnGpadlCreated() ++ ++Description: ++ GPADL created handler. This is invoked when we received a response ++ to our gpadl create request. Find the matching request, copy the ++ response and signal the requesting thread. ++ ++--*/ ++static void ++VmbusChannelOnGpadlCreated( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr; ++ LIST_ENTRY *anchor; ++ LIST_ENTRY *curr; ++ VMBUS_CHANNEL_MSGINFO *msgInfo; ++ VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; ++ VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus); ++ ++ // Find the establish msg, copy the result and signal/unblock the wait event ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ ++ ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) ++ { ++ msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; ++ requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; ++ ++ if (requestHeader->MessageType == ChannelMessageGpadlHeader) ++ { ++ gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader; ++ ++ if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) && ++ (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) ++ { ++ memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED)); ++ WaitEventSet(msgInfo->WaitEvent); ++ break; ++ } ++ } ++ } ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnGpadlTorndown() ++ ++Description: ++ GPADL torndown handler. This is invoked when we received a response ++ to our gpadl teardown request. Find the matching request, copy the ++ response and signal the requesting thread. ++ ++--*/ ++static void ++VmbusChannelOnGpadlTorndown( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr; ++ LIST_ENTRY* anchor; ++ LIST_ENTRY* curr; ++ VMBUS_CHANNEL_MSGINFO* msgInfo; ++ VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; ++ VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Find the open msg, copy the result and signal/unblock the wait event ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ ++ ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) ++ { ++ msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; ++ requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; ++ ++ if (requestHeader->MessageType == ChannelMessageGpadlTeardown) ++ { ++ gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader; ++ ++ if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) ++ { ++ memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN)); ++ WaitEventSet(msgInfo->WaitEvent); ++ break; ++ } ++ } ++ } ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelOnVersionResponse() ++ ++Description: ++ Version response handler. This is invoked when we received a response ++ to our initiate contact request. Find the matching request, copy the ++ response and signal the requesting thread. ++ ++--*/ ++static void ++VmbusChannelOnVersionResponse( ++ PVMBUS_CHANNEL_MESSAGE_HEADER hdr ++ ) ++{ ++ LIST_ENTRY* anchor; ++ LIST_ENTRY* curr; ++ VMBUS_CHANNEL_MSGINFO *msgInfo; ++ VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader; ++ VMBUS_CHANNEL_INITIATE_CONTACT *initiate; ++ VMBUS_CHANNEL_VERSION_RESPONSE *versionResponse = (VMBUS_CHANNEL_VERSION_RESPONSE*)hdr; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ ++ ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList) ++ { ++ msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr; ++ requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; ++ ++ if (requestHeader->MessageType == ChannelMessageInitiateContact) ++ { ++ initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader; ++ memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE)); ++ WaitEventSet(msgInfo->WaitEvent); ++ } ++ } ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusOnChannelMessage() ++ ++Description: ++ Handler for channel protocol messages. ++ This is invoked in the vmbus worker thread context. ++ ++--*/ ++VOID ++VmbusOnChannelMessage( ++ void *Context ++ ) ++{ ++ HV_MESSAGE *msg=(HV_MESSAGE*)Context; ++ VMBUS_CHANNEL_MESSAGE_HEADER* hdr; ++ int size; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload; ++ size=msg->Header.PayloadSize; ++ ++ DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size); ++ ++ if (hdr->MessageType >= ChannelMessageCount) ++ { ++ DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size); ++ PrintBytes((unsigned char *)msg->u.Payload, size); ++ MemFree(msg); ++ return; ++ } ++ ++ if (gChannelMessageTable[hdr->MessageType].messageHandler) ++ { ++ gChannelMessageTable[hdr->MessageType].messageHandler(hdr); ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType); ++ } ++ ++ // Free the msg that was allocated in VmbusOnMsgDPC() ++ MemFree(msg); ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChannelRequestOffers() ++ ++Description: ++ Send a request to get all our pending offers. ++ ++--*/ ++int ++VmbusChannelRequestOffers( ++ VOID ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_MESSAGE_HEADER* msg; ++ VMBUS_CHANNEL_MSGINFO* msgInfo; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ msgInfo = ++ (VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER)); ++ ASSERT(msgInfo != NULL); ++ ++ msgInfo->WaitEvent = WaitEventCreate(); ++ msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg; ++ ++ msg->MessageType = ChannelMessageRequestOffers; ++ ++ /*SpinlockAcquire(gVmbusConnection.channelMsgLock); ++ INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry); ++ SpinlockRelease(gVmbusConnection.channelMsgLock);*/ ++ ++ ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER)); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret); ++ ++ /*SpinlockAcquire(gVmbusConnection.channelMsgLock); ++ REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); ++ SpinlockRelease(gVmbusConnection.channelMsgLock);*/ ++ ++ goto Cleanup; ++ } ++ //WaitEventWait(msgInfo->waitEvent); ++ ++ /*SpinlockAcquire(gVmbusConnection.channelMsgLock); ++ REMOVE_ENTRY_LIST(&msgInfo->msgListEntry); ++ SpinlockRelease(gVmbusConnection.channelMsgLock);*/ ++ ++ ++Cleanup: ++ if (msgInfo) ++ { ++ WaitEventClose(msgInfo->WaitEvent); ++ MemFree(msgInfo); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: ++ VmbusChannelReleaseUnattachedChannels() ++ ++Description: ++ Release channels that are unattached/unconnected ie (no drivers associated) ++ ++--*/ ++void ++VmbusChannelReleaseUnattachedChannels( ++ VOID ++ ) ++{ ++ LIST_ENTRY *entry; ++ VMBUS_CHANNEL *channel; ++ VMBUS_CHANNEL *start=NULL; ++ ++ SpinlockAcquire(gVmbusConnection.ChannelLock); ++ ++ while (!IsListEmpty(&gVmbusConnection.ChannelList)) ++ { ++ entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList); ++ channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry); ++ ++ if (channel == start) ++ break; ++ ++ if (!channel->DeviceObject->Driver) ++ { ++ REMOVE_ENTRY_LIST(&channel->ListEntry); ++ DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject); ++ ++ VmbusChildDeviceRemove(channel->DeviceObject); ++ FreeVmbusChannel(channel); ++ } ++ else ++ { ++ if (!start) ++ { ++ start = channel; ++ } ++ } ++ } ++ ++ SpinlockRelease(gVmbusConnection.ChannelLock); ++} ++ ++// eof ++ +--- /dev/null ++++ b/drivers/staging/hv/ChannelMgmt.h +@@ -0,0 +1,156 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _CHANNEL_MGMT_H_ ++#define _CHANNEL_MGMT_H_ ++ ++#include "osd.h" ++#include "List.h" ++#include "RingBuffer.h" ++ ++#include "VmbusChannelInterface.h" ++#include "ChannelMessages.h" ++ ++ ++ ++typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context); ++ ++typedef enum { ++ CHANNEL_OFFER_STATE, ++ CHANNEL_OPENING_STATE, ++ CHANNEL_OPEN_STATE, ++} VMBUS_CHANNEL_STATE; ++ ++typedef struct _VMBUS_CHANNEL { ++ LIST_ENTRY ListEntry; ++ ++ DEVICE_OBJECT* DeviceObject; ++ ++ HANDLE PollTimer; // SA-111 workaround ++ ++ VMBUS_CHANNEL_STATE State; ++ ++ VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg; ++ // These are based on the OfferMsg.MonitorId. Save it here for easy access. ++ UINT8 MonitorGroup; ++ UINT8 MonitorBit; ++ ++ UINT32 RingBufferGpadlHandle; ++ ++ // Allocated memory for ring buffer ++ VOID* RingBufferPages; ++ UINT32 RingBufferPageCount; ++ RING_BUFFER_INFO Outbound; // send to parent ++ RING_BUFFER_INFO Inbound; // receive from parent ++ HANDLE InboundLock; ++ HANDLE ControlWQ; ++ ++ // Channel callback are invoked in this workqueue context ++ //HANDLE dataWorkQueue; ++ ++ PFN_CHANNEL_CALLBACK OnChannelCallback; ++ PVOID ChannelCallbackContext; ++ ++} VMBUS_CHANNEL; ++ ++ ++typedef struct _VMBUS_CHANNEL_DEBUG_INFO { ++ UINT32 RelId; ++ VMBUS_CHANNEL_STATE State; ++ GUID InterfaceType; ++ GUID InterfaceInstance; ++ UINT32 MonitorId; ++ UINT32 ServerMonitorPending; ++ UINT32 ServerMonitorLatency; ++ UINT32 ServerMonitorConnectionId; ++ UINT32 ClientMonitorPending; ++ UINT32 ClientMonitorLatency; ++ UINT32 ClientMonitorConnectionId; ++ ++ RING_BUFFER_DEBUG_INFO Inbound; ++ RING_BUFFER_DEBUG_INFO Outbound; ++} VMBUS_CHANNEL_DEBUG_INFO; ++ ++ ++typedef union { ++ VMBUS_CHANNEL_VERSION_SUPPORTED VersionSupported; ++ VMBUS_CHANNEL_OPEN_RESULT OpenResult; ++ VMBUS_CHANNEL_GPADL_TORNDOWN GpadlTorndown; ++ VMBUS_CHANNEL_GPADL_CREATED GpadlCreated; ++ VMBUS_CHANNEL_VERSION_RESPONSE VersionResponse; ++} VMBUS_CHANNEL_MESSAGE_RESPONSE; ++ ++ ++// Represents each channel msg on the vmbus connection ++// This is a variable-size data structure depending on ++// the msg type itself ++typedef struct _VMBUS_CHANNEL_MSGINFO { ++ // Bookkeeping stuff ++ LIST_ENTRY MsgListEntry; ++ ++ // So far, this is only used to handle gpadl body message ++ LIST_ENTRY SubMsgList; ++ ++ // Synchronize the request/response if needed ++ HANDLE WaitEvent; ++ ++ VMBUS_CHANNEL_MESSAGE_RESPONSE Response; ++ ++ UINT32 MessageSize; ++ // The channel message that goes out on the "wire". ++ // It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header ++ unsigned char Msg[0]; ++} VMBUS_CHANNEL_MSGINFO; ++ ++ ++// ++// Routines ++// ++ ++INTERNAL VMBUS_CHANNEL* ++AllocVmbusChannel( ++ void ++ ); ++ ++INTERNAL void ++FreeVmbusChannel( ++ VMBUS_CHANNEL *Channel ++ ); ++ ++INTERNAL void ++VmbusOnChannelMessage( ++ void *Context ++ ); ++ ++INTERNAL int ++VmbusChannelRequestOffers( ++ void ++ ); ++ ++INTERNAL void ++VmbusChannelReleaseUnattachedChannels( ++ void ++ ); ++ ++#endif //_CHANNEL_MGMT_H_ +--- /dev/null ++++ b/drivers/staging/hv/Connection.c +@@ -0,0 +1,432 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++ ++#include "VmbusPrivate.h" ++ ++// ++// Globals ++// ++ ++ ++VMBUS_CONNECTION gVmbusConnection = { ++ .ConnectState = Disconnected, ++ .NextGpadlHandle = 0xE1E10, ++}; ++ ++ ++/*++ ++ ++Name: ++ VmbusConnect() ++ ++Description: ++ Sends a connect request on the partition service connection ++ ++--*/ ++int ++VmbusConnect( ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_MSGINFO *msgInfo=NULL; ++ VMBUS_CHANNEL_INITIATE_CONTACT *msg; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Make sure we are not connecting or connected ++ if (gVmbusConnection.ConnectState != Disconnected) ++ return -1; ++ ++ // Initialize the vmbus connection ++ gVmbusConnection.ConnectState = Connecting; ++ gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ"); ++ ++ INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList); ++ gVmbusConnection.ChannelMsgLock = SpinlockCreate(); ++ ++ INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList); ++ gVmbusConnection.ChannelLock = SpinlockCreate(); ++ ++ // Setup the vmbus event connection for channel interrupt abstraction stuff ++ gVmbusConnection.InterruptPage = PageAlloc(1); ++ if (gVmbusConnection.InterruptPage == NULL) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage; ++ gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1)); ++ ++ // Setup the monitor notification facility. The 1st page for parent->child and the 2nd page for child->parent ++ gVmbusConnection.MonitorPages = PageAlloc(2); ++ if (gVmbusConnection.MonitorPages == NULL) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT)); ++ if (msgInfo == NULL) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ msgInfo->WaitEvent = WaitEventCreate(); ++ msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg; ++ ++ msg->Header.MessageType = ChannelMessageInitiateContact; ++ msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER; ++ msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage); ++ msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages); ++ msg->MonitorPage2 = GetPhysicalAddress((PVOID)((ULONG_PTR)gVmbusConnection.MonitorPages + PAGE_SIZE)); ++ ++ // Add to list before we send the request since we may receive the response ++ // before returning from this routine ++ SpinlockAcquire(gVmbusConnection.ChannelMsgLock); ++ INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry); ++ SpinlockRelease(gVmbusConnection.ChannelMsgLock); ++ ++ DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx", ++ msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2); ++ ++ DPRINT_DBG(VMBUS, "Sending channel initiate msg..."); ++ ++ ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT)); ++ if (ret != 0) ++ { ++ REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); ++ goto Cleanup; ++ } ++ ++ // Wait for the connection response ++ WaitEventWait(msgInfo->WaitEvent); ++ ++ REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry); ++ ++ // Check if successful ++ if (msgInfo->Response.VersionResponse.VersionSupported) ++ { ++ DPRINT_INFO(VMBUS, "Vmbus connected!!"); ++ gVmbusConnection.ConnectState = Connected; ++ ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER); ++ ret = -1; ++ ++ goto Cleanup; ++ } ++ ++ ++ WaitEventClose(msgInfo->WaitEvent); ++ MemFree(msgInfo); ++ DPRINT_EXIT(VMBUS); ++ ++ return 0; ++ ++Cleanup: ++ ++ gVmbusConnection.ConnectState = Disconnected; ++ ++ WorkQueueClose(gVmbusConnection.WorkQueue); ++ SpinlockClose(gVmbusConnection.ChannelLock); ++ SpinlockClose(gVmbusConnection.ChannelMsgLock); ++ ++ if (gVmbusConnection.InterruptPage) ++ { ++ PageFree(gVmbusConnection.InterruptPage, 1); ++ gVmbusConnection.InterruptPage = NULL; ++ } ++ ++ if (gVmbusConnection.MonitorPages) ++ { ++ PageFree(gVmbusConnection.MonitorPages, 2); ++ gVmbusConnection.MonitorPages = NULL; ++ } ++ ++ if (msgInfo) ++ { ++ if (msgInfo->WaitEvent) ++ WaitEventClose(msgInfo->WaitEvent); ++ ++ MemFree(msgInfo); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusDisconnect() ++ ++Description: ++ Sends a disconnect request on the partition service connection ++ ++--*/ ++int ++VmbusDisconnect( ++ VOID ++ ) ++{ ++ int ret=0; ++ VMBUS_CHANNEL_UNLOAD *msg; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Make sure we are connected ++ if (gVmbusConnection.ConnectState != Connected) ++ return -1; ++ ++ msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD)); ++ ++ msg->MessageType = ChannelMessageUnload; ++ ++ ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD)); ++ ++ if (ret != 0) ++ { ++ goto Cleanup; ++ } ++ ++ PageFree(gVmbusConnection.InterruptPage, 1); ++ ++ // TODO: iterate thru the msg list and free up ++ ++ SpinlockClose(gVmbusConnection.ChannelMsgLock); ++ ++ WorkQueueClose(gVmbusConnection.WorkQueue); ++ ++ gVmbusConnection.ConnectState = Disconnected; ++ ++ DPRINT_INFO(VMBUS, "Vmbus disconnected!!"); ++ ++Cleanup: ++ if (msg) ++ { ++ MemFree(msg); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ GetChannelFromRelId() ++ ++Description: ++ Get the channel object given its child relative id (ie channel id) ++ ++--*/ ++VMBUS_CHANNEL* ++GetChannelFromRelId( ++ UINT32 relId ++ ) ++{ ++ VMBUS_CHANNEL* channel; ++ VMBUS_CHANNEL* foundChannel=NULL; ++ LIST_ENTRY* anchor; ++ LIST_ENTRY* curr; ++ ++ SpinlockAcquire(gVmbusConnection.ChannelLock); ++ ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList) ++ { ++ channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry); ++ ++ if (channel->OfferMsg.ChildRelId == relId) ++ { ++ foundChannel = channel; ++ break; ++ } ++ } ++ SpinlockRelease(gVmbusConnection.ChannelLock); ++ ++ return foundChannel; ++} ++ ++ ++ ++/*++ ++ ++Name: ++ VmbusProcessChannelEvent() ++ ++Description: ++ Process a channel event notification ++ ++--*/ ++static void ++VmbusProcessChannelEvent( ++ PVOID context ++ ) ++{ ++ VMBUS_CHANNEL* channel; ++ UINT32 relId = (UINT32)(ULONG_PTR)context; ++ ++ ASSERT(relId > 0); ++ ++ // Find the channel based on this relid and invokes ++ // the channel callback to process the event ++ channel = GetChannelFromRelId(relId); ++ ++ if (channel) ++ { ++ VmbusChannelOnChannelEvent(channel); ++ //WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel); ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId); ++ } ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusOnEvents() ++ ++Description: ++ Handler for events ++ ++--*/ ++VOID ++VmbusOnEvents( ++ VOID ++ ) ++{ ++ int dword; ++ //int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes ++ int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; ++ int bit; ++ int relid; ++ UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage; ++ //VMBUS_CHANNEL_MESSAGE* receiveMsg; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Check events ++ if (recvInterruptPage) ++ { ++ for (dword = 0; dword < maxdword; dword++) ++ { ++ if (recvInterruptPage[dword]) ++ { ++ for (bit = 0; bit < 32; bit++) ++ { ++ if (BitTestAndClear(&recvInterruptPage[dword], bit)) ++ { ++ relid = (dword << 5) + bit; ++ ++ DPRINT_DBG(VMBUS, "event detected for relid - %d", relid); ++ ++ if (relid == 0) // special case - vmbus channel protocol msg ++ { ++ DPRINT_DBG(VMBUS, "invalid relid - %d", relid); ++ ++ continue; } ++ else ++ { ++ //QueueWorkItem(VmbusProcessEvent, (void*)relid); ++ //ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid); ++ VmbusProcessChannelEvent((void*)(ULONG_PTR)relid); ++ } ++ } ++ } ++ } ++ } ++ } ++ DPRINT_EXIT(VMBUS); ++ ++ return; ++} ++ ++/*++ ++ ++Name: ++ VmbusPostMessage() ++ ++Description: ++ Send a msg on the vmbus's message connection ++ ++--*/ ++int ++VmbusPostMessage( ++ PVOID buffer, ++ SIZE_T bufferLen ++ ) ++{ ++ int ret=0; ++ HV_CONNECTION_ID connId; ++ ++ ++ connId.AsUINT32 =0; ++ connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID; ++ ret = HvPostMessage( ++ connId, ++ 1, ++ buffer, ++ bufferLen); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: ++ VmbusSetEvent() ++ ++Description: ++ Send an event notification to the parent ++ ++--*/ ++int ++VmbusSetEvent(UINT32 childRelId) ++{ ++ int ret=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Each UINT32 represents 32 channels ++ BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31); ++ ret = HvSignalEvent(); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++// EOF +--- /dev/null ++++ b/drivers/staging/hv/Hv.c +@@ -0,0 +1,672 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++#include "VmbusPrivate.h" ++ ++// ++// Globals ++// ++ ++// The one and only ++HV_CONTEXT gHvContext={ ++ .SynICInitialized = FALSE, ++ .HypercallPage = NULL, ++ .SignalEventParam = NULL, ++ .SignalEventBuffer = NULL, ++}; ++ ++ ++/*++ ++ ++Name: ++ HvQueryHypervisorPresence() ++ ++Description: ++ Query the cpuid for presense of windows hypervisor ++ ++--*/ ++static int ++HvQueryHypervisorPresence ( ++ void ++ ) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ unsigned int op; ++ ++ eax = 0; ++ ebx = 0; ++ ecx = 0; ++ edx = 0; ++ op = HvCpuIdFunctionVersionAndFeatures; ++ do_cpuid(op, &eax, &ebx, &ecx, &edx); ++ ++ return (ecx & HV_PRESENT_BIT); ++} ++ ++ ++/*++ ++ ++Name: ++ HvQueryHypervisorInfo() ++ ++Description: ++ Get version info of the windows hypervisor ++ ++--*/ ++static int ++HvQueryHypervisorInfo ( ++ void ++ ) ++{ ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ unsigned int maxLeaf; ++ unsigned int op; ++ ++ // ++ // Its assumed that this is called after confirming that Viridian is present. ++ // Query id and revision. ++ // ++ ++ eax = 0; ++ ebx = 0; ++ ecx = 0; ++ edx = 0; ++ op = HvCpuIdFunctionHvVendorAndMaxFunction; ++ do_cpuid(op, &eax, &ebx, &ecx, &edx); ++ ++ DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c", ++ (ebx & 0xFF), ++ ((ebx >> 8) & 0xFF), ++ ((ebx >> 16) & 0xFF), ++ ((ebx >> 24) & 0xFF), ++ (ecx & 0xFF), ++ ((ecx >> 8) & 0xFF), ++ ((ecx >> 16) & 0xFF), ++ ((ecx >> 24) & 0xFF), ++ (edx & 0xFF), ++ ((edx >> 8) & 0xFF), ++ ((edx >> 16) & 0xFF), ++ ((edx >> 24) & 0xFF)); ++ ++ maxLeaf = eax; ++ eax = 0; ++ ebx = 0; ++ ecx = 0; ++ edx = 0; ++ op = HvCpuIdFunctionHvInterface; ++ do_cpuid(op, &eax, &ebx, &ecx, &edx); ++ ++ DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c", ++ (eax & 0xFF), ++ ((eax >> 8) & 0xFF), ++ ((eax >> 16) & 0xFF), ++ ((eax >> 24) & 0xFF)); ++ ++ if (maxLeaf >= HvCpuIdFunctionMsHvVersion) { ++ eax = 0; ++ ebx = 0; ++ ecx = 0; ++ edx = 0; ++ op = HvCpuIdFunctionMsHvVersion; ++ do_cpuid(op, &eax, &ebx, &ecx, &edx); ++ DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d", ++ eax, ++ ebx >> 16, ++ ebx & 0xFFFF, ++ ecx, ++ edx >> 24, ++ edx & 0xFFFFFF); ++ } ++ return maxLeaf; ++} ++ ++ ++/*++ ++ ++Name: ++ HvDoHypercall() ++ ++Description: ++ Invoke the specified hypercall ++ ++--*/ ++static UINT64 ++HvDoHypercall ( ++ UINT64 Control, ++ void* Input, ++ void* Output ++ ) ++{ ++#ifdef x86_64 ++ UINT64 hvStatus=0; ++ UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; ++ UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; ++ volatile void* hypercallPage = gHvContext.HypercallPage; ++ ++ DPRINT_DBG(VMBUS, "Hypercall ", ++ Control, ++ inputAddress, ++ Input, ++ outputAddress, ++ Output, ++ hypercallPage); ++ ++ __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8"); ++ __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage)); ++ ++ DPRINT_DBG(VMBUS, "Hypercall ", hvStatus); ++ ++ return hvStatus; ++ ++#else ++ ++ UINT32 controlHi = Control >> 32; ++ UINT32 controlLo = Control & 0xFFFFFFFF; ++ UINT32 hvStatusHi = 1; ++ UINT32 hvStatusLo = 1; ++ UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0; ++ UINT32 inputAddressHi = inputAddress >> 32; ++ UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF; ++ UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0; ++ UINT32 outputAddressHi = outputAddress >> 32; ++ UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF; ++ volatile void* hypercallPage = gHvContext.HypercallPage; ++ ++ DPRINT_DBG(VMBUS, "Hypercall ", ++ Control, ++ Input, ++ Output); ++ ++ __asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage)); ++ ++ ++ DPRINT_DBG(VMBUS, "Hypercall ", hvStatusLo | ((UINT64)hvStatusHi << 32)); ++ ++ return (hvStatusLo | ((UINT64)hvStatusHi << 32)); ++#endif // x86_64 ++} ++ ++/*++ ++ ++Name: ++ HvInit() ++ ++Description: ++ Main initialization routine. This routine must be called ++ before any other routines in here are called ++ ++--*/ ++static int ++HvInit ( ++ void ++ ) ++{ ++ int ret=0; ++ int maxLeaf; ++ HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; ++ void* virtAddr=0; ++ ULONG_PTR physAddr=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); ++ memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS); ++ ++ if (!HvQueryHypervisorPresence()) ++ { ++ DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!"); ++ goto Cleanup; ++ } ++ ++ DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info..."); ++ ++ maxLeaf = HvQueryHypervisorInfo(); ++ //HvQueryHypervisorFeatures(maxLeaf); ++ ++ // Determine if we are running on xenlinux (ie x2v shim) or native linux ++ gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID); ++ ++ if (gHvContext.GuestId == 0) ++ { ++ // Write our OS info ++ WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); ++ ++ gHvContext.GuestId = HV_LINUX_GUEST_ID; ++ } ++ ++ // See if the hypercall page is already set ++ hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); ++ ++ if (gHvContext.GuestId == HV_LINUX_GUEST_ID) ++ { ++ // Allocate the hypercall page memory ++ //virtAddr = PageAlloc(1); ++ virtAddr = VirtualAllocExec(PAGE_SIZE); ++ ++ if (!virtAddr) ++ { ++ DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!"); ++ goto Cleanup; ++ } ++ ++ hypercallMsr.Enable = 1; ++ //hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT; ++ hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT; ++ WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); ++ ++ // Confirm that hypercall page did get setup. ++ hypercallMsr.AsUINT64 = 0; ++ hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL); ++ ++ if (!hypercallMsr.Enable) ++ { ++ DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); ++ goto Cleanup; ++ } ++ ++ gHvContext.HypercallPage = virtAddr; ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId); ++ goto Cleanup; ++ } ++ ++ DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x", ++ (unsigned long)gHvContext.HypercallPage, ++ (unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); ++ ++ // Setup the global signal event param for the signal event hypercall ++ gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER)); ++ if (!gHvContext.SignalEventBuffer) ++ { ++ goto Cleanup; ++ } ++ ++ gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN)); ++ gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0; ++ gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID; ++ gHvContext.SignalEventParam->FlagNumber = 0; ++ gHvContext.SignalEventParam->RsvdZ = 0; ++ ++ //DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++ ++Cleanup: ++ if (virtAddr) ++ { ++ if (hypercallMsr.Enable) ++ { ++ hypercallMsr.AsUINT64 = 0; ++ WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); ++ } ++ ++ VirtualFree(virtAddr); ++ } ++ ret = -1; ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ HvCleanup() ++ ++Description: ++ Cleanup routine. This routine is called normally during driver unloading or exiting. ++ ++--*/ ++void ++HvCleanup ( ++ void ++ ) ++{ ++ HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ if (gHvContext.SignalEventBuffer) ++ { ++ MemFree(gHvContext.SignalEventBuffer); ++ gHvContext.SignalEventBuffer = NULL; ++ gHvContext.SignalEventParam = NULL; ++ } ++ ++ if (gHvContext.GuestId == HV_LINUX_GUEST_ID) ++ { ++ if (gHvContext.HypercallPage) ++ { ++ hypercallMsr.AsUINT64 = 0; ++ WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); ++ VirtualFree(gHvContext.HypercallPage); ++ gHvContext.HypercallPage = NULL; ++ } ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++} ++ ++ ++/*++ ++ ++Name: ++ HvPostMessage() ++ ++Description: ++ Post a message using the hypervisor message IPC. This ++ involves a hypercall. ++ ++--*/ ++HV_STATUS ++HvPostMessage( ++ HV_CONNECTION_ID connectionId, ++ HV_MESSAGE_TYPE messageType, ++ PVOID payload, ++ SIZE_T payloadSize ++ ) ++{ ++ struct alignedInput { ++ UINT64 alignment8; ++ HV_INPUT_POST_MESSAGE msg; ++ }; ++ ++ PHV_INPUT_POST_MESSAGE alignedMsg; ++ HV_STATUS status; ++ ULONG_PTR addr; ++ ++ if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT) ++ { ++ return -1; ++ } ++ ++ addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput)); ++ ++ if (!addr) ++ { ++ return -1; ++ } ++ ++ alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); ++ ++ alignedMsg->ConnectionId = connectionId; ++ alignedMsg->MessageType = messageType; ++ alignedMsg->PayloadSize = payloadSize; ++ memcpy((void*)alignedMsg->Payload, payload, payloadSize); ++ ++ status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF; ++ ++ MemFree((void*)addr); ++ ++ return status; ++} ++ ++ ++/*++ ++ ++Name: ++ HvSignalEvent() ++ ++Description: ++ Signal an event on the specified connection using the hypervisor event IPC. This ++ involves a hypercall. ++ ++--*/ ++HV_STATUS ++HvSignalEvent( ++ ) ++{ ++ HV_STATUS status; ++ ++ status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF; ++ ++ return status; ++} ++ ++ ++/*++ ++ ++Name: ++ HvSynicInit() ++ ++Description: ++ Initialize the Synthethic Interrupt Controller. If it is already initialized by ++ another entity (ie x2v shim), we need to retrieve the initialized message and event pages. ++ Otherwise, we create and initialize the message and event pages. ++ ++--*/ ++int ++HvSynicInit ( ++ UINT32 irqVector ++ ) ++{ ++ UINT64 version; ++ HV_SYNIC_SIMP simp; ++ HV_SYNIC_SIEFP siefp; ++ HV_SYNIC_SINT sharedSint; ++ HV_SYNIC_SCONTROL sctrl; ++ UINT64 guestID; ++ int ret=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ if (!gHvContext.HypercallPage) ++ { ++ DPRINT_EXIT(VMBUS); ++ return ret; ++ } ++ ++ // Check the version ++ version = ReadMsr(HV_X64_MSR_SVERSION); ++ ++ DPRINT_INFO(VMBUS, "SynIC version: %llx", version); ++ ++ // TODO: Handle SMP ++ if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) ++ { ++ DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set."); ++ ++ simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); ++ siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); ++ ++ DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64); ++ ++ // Determine if we are running on xenlinux (ie x2v shim) or native linux ++ guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID); ++ ++ if (guestID == HV_LINUX_GUEST_ID) ++ { ++ gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT); ++ gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT); ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS, "unknown guest id!!"); ++ goto Cleanup; ++ } ++ DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]); ++ } ++ else ++ { ++ gHvContext.synICMessagePage[0] = PageAlloc(1); ++ if (gHvContext.synICMessagePage[0] == NULL) ++ { ++ DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!"); ++ goto Cleanup; ++ } ++ ++ gHvContext.synICEventPage[0] = PageAlloc(1); ++ if (gHvContext.synICEventPage[0] == NULL) ++ { ++ DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!"); ++ goto Cleanup; ++ } ++ ++ // ++ // Setup the Synic's message page ++ // ++ simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); ++ simp.SimpEnabled = 1; ++ simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT; ++ ++ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64); ++ ++ WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); ++ ++ // ++ // Setup the Synic's event page ++ // ++ siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); ++ siefp.SiefpEnabled = 1; ++ siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT; ++ ++ DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64); ++ ++ WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); ++ } ++ // ++ // Setup the interception SINT. ++ // ++ //WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), ++ // interceptionSint.AsUINT64); ++ ++ // ++ // Setup the shared SINT. ++ // ++ sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); ++ ++ sharedSint.AsUINT64 = 0; ++ sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20; ++ sharedSint.Masked = FALSE; ++ sharedSint.AutoEoi = TRUE; ++ ++ DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64); ++ ++ WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); ++ ++ // Enable the global synic bit ++ sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL); ++ sctrl.Enable = 1; ++ ++ WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64); ++ ++ gHvContext.SynICInitialized = TRUE; ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++ ++Cleanup: ++ ret = -1; ++ ++ if (gHvContext.GuestId == HV_LINUX_GUEST_ID) ++ { ++ if (gHvContext.synICEventPage[0]) ++ { ++ PageFree(gHvContext.synICEventPage[0],1); ++ } ++ ++ if (gHvContext.synICMessagePage[0]) ++ { ++ PageFree(gHvContext.synICMessagePage[0], 1); ++ } ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++ ++} ++ ++/*++ ++ ++Name: ++ HvSynicCleanup() ++ ++Description: ++ Cleanup routine for HvSynicInit(). ++ ++--*/ ++VOID ++HvSynicCleanup( ++ VOID ++ ) ++{ ++ HV_SYNIC_SINT sharedSint; ++ HV_SYNIC_SIMP simp; ++ HV_SYNIC_SIEFP siefp; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ if (!gHvContext.SynICInitialized) ++ { ++ DPRINT_EXIT(VMBUS); ++ return; ++ } ++ ++ sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT); ++ ++ sharedSint.Masked = 1; ++ ++ // Disable the interrupt ++ WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); ++ ++ // Disable and free the resources only if we are running as native linux ++ // since in xenlinux, we are sharing the resources with the x2v shim ++ if (gHvContext.GuestId == HV_LINUX_GUEST_ID) ++ { ++ simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP); ++ simp.SimpEnabled = 0; ++ simp.BaseSimpGpa = 0; ++ ++ WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64); ++ ++ siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP); ++ siefp.SiefpEnabled = 0; ++ siefp.BaseSiefpGpa = 0; ++ ++ WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64); ++ ++ PageFree(gHvContext.synICMessagePage[0], 1); ++ PageFree(gHvContext.synICEventPage[0], 1); ++ } ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++// eof +--- /dev/null ++++ b/drivers/staging/hv/Hv.h +@@ -0,0 +1,184 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef __HV_H__ ++#define __HV_H__ ++ ++#include "osd.h" ++ ++#include "HvTypes.h" ++#include "HvStatus.h" ++//#include "HvVmApi.h" ++//#include "HvKeApi.h" ++//#include "HvMmApi.h" ++//#include "HvCpuApi.h" ++#include "HvHalApi.h" ++#include "HvVpApi.h" ++//#include "HvTrApi.h" ++#include "HvSynicApi.h" ++//#include "HvAmApi.h" ++//#include "HvHkApi.h" ++//#include "HvValApi.h" ++#include "HvHcApi.h" ++#include "HvPtApi.h" ++ ++enum ++{ ++ VMBUS_MESSAGE_CONNECTION_ID = 1, ++ VMBUS_MESSAGE_PORT_ID = 1, ++ VMBUS_EVENT_CONNECTION_ID = 2, ++ VMBUS_EVENT_PORT_ID = 2, ++ VMBUS_MONITOR_CONNECTION_ID = 3, ++ VMBUS_MONITOR_PORT_ID = 3, ++ VMBUS_MESSAGE_SINT = 2 ++}; ++// ++// #defines ++// ++#define HV_PRESENT_BIT 0x80000000 ++ ++#define HV_XENLINUX_GUEST_ID_LO 0x00000000 ++#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135 ++#define HV_XENLINUX_GUEST_ID (((UINT64)HV_XENLINUX_GUEST_ID_HI << 32) | HV_XENLINUX_GUEST_ID_LO) ++ ++#define HV_LINUX_GUEST_ID_LO 0x00000000 ++#define HV_LINUX_GUEST_ID_HI 0xB16B00B5 ++#define HV_LINUX_GUEST_ID (((UINT64)HV_LINUX_GUEST_ID_HI << 32) | HV_LINUX_GUEST_ID_LO) ++ ++#define HV_CPU_POWER_MANAGEMENT (1 << 0) ++#define HV_RECOMMENDATIONS_MAX 4 ++ ++#define HV_X64_MAX 5 ++#define HV_CAPS_MAX 8 ++ ++ ++#define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64) ++ ++// ++// Service definitions ++// ++#define HV_SERVICE_PARENT_PORT (0) ++#define HV_SERVICE_PARENT_CONNECTION (0) ++ ++#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0) ++#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1) ++#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2) ++#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3) ++ ++#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1) ++#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2) ++#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3) ++#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4) ++#define HV_SERVICE_MAX_MESSAGE_ID (4) ++ ++#define HV_SERVICE_PROTOCOL_VERSION (0x0010) ++#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64 ++ ++//#define VMBUS_REVISION_NUMBER 6 ++//#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine ++ ++// 628180B8-308D-4c5e-B7DB-1BEB62E62EF4 ++static const GUID VMBUS_SERVICE_ID = {.Data = {0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c, 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4} }; ++ ++#define MAX_NUM_CPUS 1 ++ ++ ++typedef struct { ++ UINT64 Align8; ++ HV_INPUT_SIGNAL_EVENT Event; ++} HV_INPUT_SIGNAL_EVENT_BUFFER; ++ ++typedef struct { ++ UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized ++ void* HypercallPage; ++ ++ BOOL SynICInitialized; ++ // This is used as an input param to HvCallSignalEvent hypercall. The input param is immutable ++ // in our usage and must be dynamic mem (vs stack or global). ++ HV_INPUT_SIGNAL_EVENT_BUFFER *SignalEventBuffer; ++ HV_INPUT_SIGNAL_EVENT *SignalEventParam; // 8-bytes aligned of the buffer above ++ ++ HANDLE synICMessagePage[MAX_NUM_CPUS]; ++ HANDLE synICEventPage[MAX_NUM_CPUS]; ++} HV_CONTEXT; ++ ++extern HV_CONTEXT gHvContext; ++ ++ ++// ++// Inline routines ++// ++static inline unsigned long long ReadMsr(int msr) ++{ ++ unsigned long long val; ++ ++ RDMSR(msr, val); ++ ++ return val; ++} ++ ++static inline void WriteMsr(int msr, UINT64 val) ++{ ++ WRMSR(msr, val); ++ ++ return; ++} ++ ++// ++// Hv Interface ++// ++INTERNAL int ++HvInit( ++ VOID ++ ); ++ ++INTERNAL VOID ++HvCleanup( ++ VOID ++ ); ++ ++INTERNAL HV_STATUS ++HvPostMessage( ++ HV_CONNECTION_ID connectionId, ++ HV_MESSAGE_TYPE messageType, ++ PVOID payload, ++ SIZE_T payloadSize ++ ); ++ ++INTERNAL HV_STATUS ++HvSignalEvent( ++ VOID ++ ); ++ ++INTERNAL int ++HvSynicInit( ++ UINT32 irqVector ++ ); ++ ++INTERNAL VOID ++HvSynicCleanup( ++ VOID ++ ); ++ ++#endif // __HV_H__ +--- /dev/null ++++ b/drivers/staging/hv/osd.c +@@ -0,0 +1,500 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "osd.h" ++ ++// ++// Data types ++// ++typedef struct _TIMER { ++ struct timer_list timer; ++ PFN_TIMER_CALLBACK callback; ++ void* context; ++}TIMER; ++ ++ ++typedef struct _WAITEVENT { ++ int condition; ++ wait_queue_head_t event; ++} WAITEVENT; ++ ++typedef struct _SPINLOCK { ++ spinlock_t lock; ++ unsigned long flags; ++} SPINLOCK; ++ ++typedef struct _WORKQUEUE { ++ struct workqueue_struct *queue; ++} WORKQUEUE; ++ ++typedef struct _WORKITEM { ++ struct work_struct work; ++ PFN_WORKITEM_CALLBACK callback; ++ void* context; ++} WORKITEM; ++ ++ ++// ++// Global ++// ++ ++void LogMsg(const char *fmt, ...) ++{ ++#ifdef KERNEL_2_6_5 ++ char buf[1024]; ++#endif ++ va_list args; ++ ++ va_start(args, fmt); ++#ifdef KERNEL_2_6_5 ++ vsnprintf(buf, 1024, fmt, args); ++ va_end(args); ++ printk(buf); ++#else ++ vprintk(fmt, args); ++ va_end(args); ++#endif ++} ++ ++void BitSet(unsigned int* addr, int bit) ++{ ++ set_bit(bit, (unsigned long*)addr); ++} ++ ++int BitTest(unsigned int* addr, int bit) ++{ ++ return test_bit(bit, (unsigned long*)addr); ++} ++ ++void BitClear(unsigned int* addr, int bit) ++{ ++ clear_bit(bit, (unsigned long*)addr); ++} ++ ++int BitTestAndClear(unsigned int* addr, int bit) ++{ ++ return test_and_clear_bit(bit, (unsigned long*)addr); ++} ++ ++int BitTestAndSet(unsigned int* addr, int bit) ++{ ++ return test_and_set_bit(bit, (unsigned long*)addr); ++} ++ ++ ++int InterlockedIncrement(int *val) ++{ ++#ifdef KERNEL_2_6_5 ++ int i; ++ local_irq_disable(); ++ i = atomic_read((atomic_t*)val); ++ atomic_set((atomic_t*)val, i+1); ++ local_irq_enable(); ++ return i+1; ++#else ++ return atomic_inc_return((atomic_t*)val); ++#endif ++} ++ ++int InterlockedDecrement(int *val) ++{ ++#ifdef KERNEL_2_6_5 ++ int i; ++ local_irq_disable(); ++ i = atomic_read((atomic_t*)val); ++ atomic_set((atomic_t*)val, i-1); ++ local_irq_enable(); ++ return i-1; ++#else ++ return atomic_dec_return((atomic_t*)val); ++#endif ++} ++ ++#ifndef atomic_cmpxchg ++#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new)) ++#endif ++int InterlockedCompareExchange(int *val, int new, int curr) ++{ ++ //return ((int)cmpxchg(((atomic_t*)val), curr, new)); ++ return atomic_cmpxchg((atomic_t*)val, curr, new); ++ ++} ++ ++void Sleep(unsigned long usecs) ++{ ++ udelay(usecs); ++} ++ ++void* VirtualAllocExec(unsigned int size) ++{ ++#ifdef __x86_64__ ++ return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC); ++#else ++ return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX))); ++#endif ++} ++ ++void VirtualFree(void* VirtAddr) ++{ ++ return vfree(VirtAddr); ++} ++ ++void* PageAlloc(unsigned int count) ++{ ++ void *p; ++ p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE)); ++ if (p) memset(p, 0, count * PAGE_SIZE); ++ return p; ++ ++ //struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO); ++ //void *p; ++ ++ ////BUGBUG: We need to use kmap in case we are in HIMEM region ++ //p = page_address(page); ++ //if (p) memset(p, 0, PAGE_SIZE); ++ //return p; ++} ++ ++void PageFree(void* page, unsigned int count) ++{ ++ free_pages((unsigned long)page, get_order(count * PAGE_SIZE)); ++ /*struct page* p = virt_to_page(page); ++ __free_page(p);*/ ++} ++ ++ ++void* PageMapVirtualAddress(unsigned long Pfn) ++{ ++ return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0); ++} ++ ++void PageUnmapVirtualAddress(void* VirtAddr) ++{ ++ kunmap_atomic(VirtAddr, KM_IRQ0); ++} ++ ++void* MemAlloc(unsigned int size) ++{ ++ return kmalloc(size, GFP_KERNEL); ++} ++ ++void* MemAllocZeroed(unsigned int size) ++{ ++ void *p = kmalloc(size, GFP_KERNEL); ++ if (p) memset(p, 0, size); ++ return p; ++} ++ ++void* MemAllocAtomic(unsigned int size) ++{ ++ return kmalloc(size, GFP_ATOMIC); ++} ++ ++void MemFree(void* buf) ++{ ++ kfree(buf); ++} ++ ++void *MemMapIO(unsigned long phys, unsigned long size) ++{ ++#if X2V_LINUX ++#ifdef __x86_64__ ++ return (void*)(phys + 0xFFFF83000C000000); ++#else // i386 ++ return (void*)(phys + 0xfb000000); ++#endif ++#else ++ return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size); ++#endif ++} ++ ++void MemUnmapIO(void *virt) ++{ ++ //iounmap(virt); ++} ++ ++void MemoryFence() ++{ ++ mb(); ++} ++ ++void TimerCallback(unsigned long data) ++{ ++ TIMER* t = (TIMER*)data; ++ ++ t->callback(t->context); ++} ++ ++HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context) ++{ ++ TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL); ++ if (!t) ++ { ++ return NULL; ++ } ++ ++ t->callback = pfnTimerCB; ++ t->context = context; ++ ++ init_timer(&t->timer); ++ t->timer.data = (unsigned long)t; ++ t->timer.function = TimerCallback; ++ ++ return t; ++} ++ ++void TimerStart(HANDLE hTimer, UINT32 expirationInUs) ++{ ++ TIMER* t = (TIMER* )hTimer; ++ ++ t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs); ++ add_timer(&t->timer); ++} ++ ++int TimerStop(HANDLE hTimer) ++{ ++ TIMER* t = (TIMER* )hTimer; ++ ++ return del_timer(&t->timer); ++} ++ ++void TimerClose(HANDLE hTimer) ++{ ++ TIMER* t = (TIMER* )hTimer; ++ ++ del_timer(&t->timer); ++ kfree(t); ++} ++ ++SIZE_T GetTickCount(void) ++{ ++ return jiffies; ++} ++ ++signed long long GetTimestamp(void) ++{ ++ struct timeval t; ++ ++ do_gettimeofday(&t); ++ ++ return timeval_to_ns(&t); ++} ++ ++HANDLE WaitEventCreate(void) ++{ ++ WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL); ++ if (!wait) ++ { ++ return NULL; ++ } ++ ++ wait->condition = 0; ++ init_waitqueue_head(&wait->event); ++ return wait; ++} ++ ++void WaitEventClose(HANDLE hWait) ++{ ++ WAITEVENT* waitEvent = (WAITEVENT* )hWait; ++ kfree(waitEvent); ++} ++ ++void WaitEventSet(HANDLE hWait) ++{ ++ WAITEVENT* waitEvent = (WAITEVENT* )hWait; ++ waitEvent->condition = 1; ++ wake_up_interruptible(&waitEvent->event); ++} ++ ++int WaitEventWait(HANDLE hWait) ++{ ++ int ret=0; ++ WAITEVENT* waitEvent = (WAITEVENT* )hWait; ++ ++ ret= wait_event_interruptible(waitEvent->event, ++ waitEvent->condition); ++ waitEvent->condition = 0; ++ return ret; ++} ++ ++int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs) ++{ ++ int ret=0; ++ WAITEVENT* waitEvent = (WAITEVENT* )hWait; ++ ++ ret= wait_event_interruptible_timeout(waitEvent->event, ++ waitEvent->condition, ++ msecs_to_jiffies(TimeoutInMs)); ++ waitEvent->condition = 0; ++ return ret; ++} ++ ++HANDLE SpinlockCreate(VOID) ++{ ++ SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL); ++ if (!spin) ++ { ++ return NULL; ++ } ++ spin_lock_init(&spin->lock); ++ ++ return spin; ++} ++ ++VOID SpinlockAcquire(HANDLE hSpin) ++{ ++ SPINLOCK* spin = (SPINLOCK* )hSpin; ++ ++ spin_lock_irqsave(&spin->lock, spin->flags); ++} ++ ++VOID SpinlockRelease(HANDLE hSpin) ++{ ++ SPINLOCK* spin = (SPINLOCK* )hSpin; ++ ++ spin_unlock_irqrestore(&spin->lock, spin->flags); ++} ++ ++VOID SpinlockClose(HANDLE hSpin) ++{ ++ SPINLOCK* spin = (SPINLOCK* )hSpin; ++ kfree(spin); ++} ++ ++void* Physical2LogicalAddr(ULONG_PTR PhysAddr) ++{ ++ void* logicalAddr = phys_to_virt(PhysAddr); ++ BUG_ON(!virt_addr_valid(logicalAddr)); ++ return logicalAddr; ++} ++ ++ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr) ++{ ++ BUG_ON(!virt_addr_valid(LogicalAddr)); ++ return virt_to_phys(LogicalAddr); ++} ++ ++ ++ULONG_PTR Virtual2Physical(PVOID VirtAddr) ++{ ++ ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr); ++ ++ return pfn << PAGE_SHIFT; ++} ++ ++#ifdef KERNEL_2_6_27 ++void WorkItemCallback(struct work_struct *work) ++#else ++void WorkItemCallback(void* work) ++#endif ++{ ++ WORKITEM* w = (WORKITEM*)work; ++ ++ w->callback(w->context); ++ ++ kfree(w); ++} ++ ++HANDLE WorkQueueCreate(char* name) ++{ ++ WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL); ++ if (!wq) ++ { ++ return NULL; ++ } ++ wq->queue = create_workqueue(name); ++ ++ return wq; ++} ++ ++void WorkQueueClose(HANDLE hWorkQueue) ++{ ++ WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue; ++ ++ destroy_workqueue(wq->queue); ++ ++ return; ++} ++ ++int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context) ++{ ++ WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue; ++ ++ WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC); ++ if (!w) ++ { ++ return -1; ++ } ++ ++ w->callback = workItem, ++ w->context = context; ++#ifdef KERNEL_2_6_27 ++ INIT_WORK(&w->work, WorkItemCallback); ++#else ++ INIT_WORK(&w->work, WorkItemCallback, w); ++#endif ++ return queue_work(wq->queue, &w->work); ++} ++ ++void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context) ++{ ++ WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC); ++ if (!w) ++ { ++ return; ++ } ++ ++ w->callback = workItem, ++ w->context = context; ++#ifdef KERNEL_2_6_27 ++ INIT_WORK(&w->work, WorkItemCallback); ++#else ++ INIT_WORK(&w->work, WorkItemCallback, w); ++#endif ++ schedule_work(&w->work); ++} +--- /dev/null ++++ b/drivers/staging/hv/RingBuffer.c +@@ -0,0 +1,630 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++#include "RingBuffer.h" ++ ++// ++// #defines ++// ++ ++// Amount of space to write to ++#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w)) ++ ++ ++/*++ ++ ++Name: ++ GetRingBufferAvailBytes() ++ ++Description: ++ Get number of bytes available to read and to write to ++ for the specified ring buffer ++ ++--*/ ++static inline void ++GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write) ++{ ++ UINT32 read_loc,write_loc; ++ ++ // Capture the read/write indices before they changed ++ read_loc = rbi->RingBuffer->ReadIndex; ++ write_loc = rbi->RingBuffer->WriteIndex; ++ ++ *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize); ++ *read = rbi->RingDataSize - *write; ++} ++ ++/*++ ++ ++Name: ++ GetNextWriteLocation() ++ ++Description: ++ Get the next write location for the specified ring buffer ++ ++--*/ ++static inline UINT32 ++GetNextWriteLocation(RING_BUFFER_INFO* RingInfo) ++{ ++ UINT32 next = RingInfo->RingBuffer->WriteIndex; ++ ++ ASSERT(next < RingInfo->RingDataSize); ++ ++ return next; ++} ++ ++/*++ ++ ++Name: ++ SetNextWriteLocation() ++ ++Description: ++ Set the next write location for the specified ring buffer ++ ++--*/ ++static inline void ++SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation) ++{ ++ RingInfo->RingBuffer->WriteIndex = NextWriteLocation; ++} ++ ++/*++ ++ ++Name: ++ GetNextReadLocation() ++ ++Description: ++ Get the next read location for the specified ring buffer ++ ++--*/ ++static inline UINT32 ++GetNextReadLocation(RING_BUFFER_INFO* RingInfo) ++{ ++ UINT32 next = RingInfo->RingBuffer->ReadIndex; ++ ++ ASSERT(next < RingInfo->RingDataSize); ++ ++ return next; ++} ++ ++/*++ ++ ++Name: ++ GetNextReadLocationWithOffset() ++ ++Description: ++ Get the next read location + offset for the specified ring buffer. ++ This allows the caller to skip ++ ++--*/ ++static inline UINT32 ++GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset) ++{ ++ UINT32 next = RingInfo->RingBuffer->ReadIndex; ++ ++ ASSERT(next < RingInfo->RingDataSize); ++ next += Offset; ++ next %= RingInfo->RingDataSize; ++ ++ return next; ++} ++ ++/*++ ++ ++Name: ++ SetNextReadLocation() ++ ++Description: ++ Set the next read location for the specified ring buffer ++ ++--*/ ++static inline void ++SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation) ++{ ++ RingInfo->RingBuffer->ReadIndex = NextReadLocation; ++} ++ ++ ++/*++ ++ ++Name: ++ GetRingBuffer() ++ ++Description: ++ Get the start of the ring buffer ++ ++--*/ ++static inline PVOID ++GetRingBuffer(RING_BUFFER_INFO* RingInfo) ++{ ++ return (PVOID)RingInfo->RingBuffer->Buffer; ++} ++ ++ ++/*++ ++ ++Name: ++ GetRingBufferSize() ++ ++Description: ++ Get the size of the ring buffer ++ ++--*/ ++static inline UINT32 ++GetRingBufferSize(RING_BUFFER_INFO* RingInfo) ++{ ++ return RingInfo->RingDataSize; ++} ++ ++/*++ ++ ++Name: ++ GetRingBufferIndices() ++ ++Description: ++ Get the read and write indices as UINT64 of the specified ring buffer ++ ++--*/ ++static inline UINT64 ++GetRingBufferIndices(RING_BUFFER_INFO* RingInfo) ++{ ++ return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex; ++} ++ ++ ++/*++ ++ ++Name: ++ DumpRingInfo() ++ ++Description: ++ Dump out to console the ring buffer info ++ ++--*/ ++void ++DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix) ++{ ++ UINT32 bytesAvailToWrite; ++ UINT32 bytesAvailToRead; ++ ++ GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); ++ ++ DPRINT(VMBUS, DEBUG_RING_LVL, "%s <>", ++ Prefix, ++ RingInfo, ++ RingInfo->RingBuffer->Buffer, ++ bytesAvailToWrite, ++ bytesAvailToRead, ++ RingInfo->RingBuffer->ReadIndex, ++ RingInfo->RingBuffer->WriteIndex); ++} ++ ++// ++// Internal routines ++// ++static UINT32 ++CopyToRingBuffer( ++ RING_BUFFER_INFO *RingInfo, ++ UINT32 StartWriteOffset, ++ PVOID Src, ++ UINT32 SrcLen); ++ ++static UINT32 ++CopyFromRingBuffer( ++ RING_BUFFER_INFO *RingInfo, ++ PVOID Dest, ++ UINT32 DestLen, ++ UINT32 StartReadOffset); ++ ++ ++ ++/*++ ++ ++Name: ++ RingBufferGetDebugInfo() ++ ++Description: ++ Get various debug metrics for the specified ring buffer ++ ++--*/ ++void ++RingBufferGetDebugInfo( ++ RING_BUFFER_INFO *RingInfo, ++ RING_BUFFER_DEBUG_INFO *DebugInfo ++ ) ++{ ++ UINT32 bytesAvailToWrite; ++ UINT32 bytesAvailToRead; ++ ++ if (RingInfo->RingBuffer) ++ { ++ GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); ++ ++ DebugInfo->BytesAvailToRead = bytesAvailToRead; ++ DebugInfo->BytesAvailToWrite = bytesAvailToWrite; ++ DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; ++ DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; ++ ++ DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; ++ } ++} ++ ++ ++/*++ ++ ++Name: ++ GetRingBufferInterruptMask() ++ ++Description: ++ Get the interrupt mask for the specified ring buffer ++ ++--*/ ++UINT32 ++GetRingBufferInterruptMask( ++ RING_BUFFER_INFO *rbi ++ ) ++{ ++ return rbi->RingBuffer->InterruptMask; ++} ++ ++/*++ ++ ++Name: ++ RingBufferInit() ++ ++Description: ++ Initialize the ring buffer ++ ++--*/ ++int ++RingBufferInit( ++ RING_BUFFER_INFO *RingInfo, ++ VOID *Buffer, ++ UINT32 BufferLen ++ ) ++{ ++ ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE); ++ ++ memset(RingInfo, 0, sizeof(RING_BUFFER_INFO)); ++ ++ RingInfo->RingBuffer = (RING_BUFFER*)Buffer; ++ RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0; ++ ++ RingInfo->RingSize = BufferLen; ++ RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER); ++ ++ RingInfo->RingLock = SpinlockCreate(); ++ ++ return 0; ++} ++ ++/*++ ++ ++Name: ++ RingBufferCleanup() ++ ++Description: ++ Cleanup the ring buffer ++ ++--*/ ++void ++RingBufferCleanup( ++ RING_BUFFER_INFO* RingInfo ++ ) ++{ ++ SpinlockClose(RingInfo->RingLock); ++} ++ ++/*++ ++ ++Name: ++ RingBufferWrite() ++ ++Description: ++ Write to the ring buffer ++ ++--*/ ++int ++RingBufferWrite( ++ RING_BUFFER_INFO* OutRingInfo, ++ SG_BUFFER_LIST SgBuffers[], ++ UINT32 SgBufferCount ++ ) ++{ ++ int i=0; ++ UINT32 byteAvailToWrite; ++ UINT32 byteAvailToRead; ++ UINT32 totalBytesToWrite=0; ++ ++ volatile UINT32 nextWriteLocation; ++ UINT64 prevIndices=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ for (i=0; i < SgBufferCount; i++) ++ { ++ totalBytesToWrite += SgBuffers[i].Length; ++ } ++ ++ totalBytesToWrite += sizeof(UINT64); ++ ++ SpinlockAcquire(OutRingInfo->RingLock); ++ ++ GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); ++ ++ DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); ++ ++ //DumpRingInfo(OutRingInfo, "BEFORE "); ++ ++ // If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer ++ // is empty since the read index == write index ++ if (byteAvailToWrite <= totalBytesToWrite) ++ { ++ DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); ++ ++ SpinlockRelease(OutRingInfo->RingLock); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return -1; ++ } ++ ++ // Write to the ring buffer ++ nextWriteLocation = GetNextWriteLocation(OutRingInfo); ++ ++ for (i=0; i < SgBufferCount; i++) ++ { ++ nextWriteLocation = CopyToRingBuffer(OutRingInfo, ++ nextWriteLocation, ++ SgBuffers[i].Data, ++ SgBuffers[i].Length); ++ } ++ ++ // Set previous packet start ++ prevIndices = GetRingBufferIndices(OutRingInfo); ++ ++ nextWriteLocation = CopyToRingBuffer(OutRingInfo, ++ nextWriteLocation, ++ &prevIndices, ++ sizeof(UINT64)); ++ ++ // Make sure we flush all writes before updating the writeIndex ++ MemoryFence(); ++ ++ // Now, update the write location ++ SetNextWriteLocation(OutRingInfo, nextWriteLocation); ++ ++ //DumpRingInfo(OutRingInfo, "AFTER "); ++ ++ SpinlockRelease(OutRingInfo->RingLock); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return 0; ++} ++ ++ ++/*++ ++ ++Name: ++ RingBufferPeek() ++ ++Description: ++ Read without advancing the read index ++ ++--*/ ++int ++RingBufferPeek( ++ RING_BUFFER_INFO* InRingInfo, ++ void* Buffer, ++ UINT32 BufferLen ++ ) ++{ ++ UINT32 bytesAvailToWrite; ++ UINT32 bytesAvailToRead; ++ UINT32 nextReadLocation=0; ++ ++ SpinlockAcquire(InRingInfo->RingLock); ++ ++ GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); ++ ++ // Make sure there is something to read ++ if (bytesAvailToRead < BufferLen ) ++ { ++ //DPRINT_DBG(VMBUS, "got callback but not enough to read !!", bytesAvailToRead, BufferLen); ++ ++ SpinlockRelease(InRingInfo->RingLock); ++ ++ return -1; ++ } ++ ++ // Convert to byte offset ++ nextReadLocation = GetNextReadLocation(InRingInfo); ++ ++ nextReadLocation = CopyFromRingBuffer(InRingInfo, ++ Buffer, ++ BufferLen, ++ nextReadLocation); ++ ++ SpinlockRelease(InRingInfo->RingLock); ++ ++ return 0; ++} ++ ++ ++/*++ ++ ++Name: ++ RingBufferRead() ++ ++Description: ++ Read and advance the read index ++ ++--*/ ++int ++RingBufferRead( ++ RING_BUFFER_INFO* InRingInfo, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32 Offset ++ ) ++{ ++ UINT32 bytesAvailToWrite; ++ UINT32 bytesAvailToRead; ++ UINT32 nextReadLocation=0; ++ UINT64 prevIndices=0; ++ ++ ASSERT(BufferLen > 0); ++ ++ SpinlockAcquire(InRingInfo->RingLock); ++ ++ GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); ++ ++ DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); ++ ++ //DumpRingInfo(InRingInfo, "BEFORE "); ++ ++ // Make sure there is something to read ++ if (bytesAvailToRead < BufferLen ) ++ { ++ DPRINT_DBG(VMBUS, "got callback but not enough to read !!", bytesAvailToRead, BufferLen); ++ ++ SpinlockRelease(InRingInfo->RingLock); ++ ++ return -1; ++ } ++ ++ nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); ++ ++ nextReadLocation = CopyFromRingBuffer(InRingInfo, ++ Buffer, ++ BufferLen, ++ nextReadLocation); ++ ++ nextReadLocation = CopyFromRingBuffer(InRingInfo, ++ &prevIndices, ++ sizeof(UINT64), ++ nextReadLocation); ++ ++ // Make sure all reads are done before we update the read index since ++ // the writer may start writing to the read area once the read index is updated ++ MemoryFence(); ++ ++ // Update the read index ++ SetNextReadLocation(InRingInfo, nextReadLocation); ++ ++ //DumpRingInfo(InRingInfo, "AFTER "); ++ ++ SpinlockRelease(InRingInfo->RingLock); ++ ++ return 0; ++} ++ ++ ++/*++ ++ ++Name: ++ CopyToRingBuffer() ++ ++Description: ++ Helper routine to copy from source to ring buffer. ++ Assume there is enough room. Handles wrap-around in dest case only!! ++ ++--*/ ++UINT32 ++CopyToRingBuffer( ++ RING_BUFFER_INFO *RingInfo, ++ UINT32 StartWriteOffset, ++ PVOID Src, ++ UINT32 SrcLen) ++{ ++ PVOID ringBuffer=GetRingBuffer(RingInfo); ++ UINT32 ringBufferSize=GetRingBufferSize(RingInfo); ++ UINT32 fragLen; ++ ++ if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected! ++ { ++ DPRINT_DBG(VMBUS, "wrap-around detected!"); ++ ++ fragLen = ringBufferSize - StartWriteOffset; ++ memcpy(ringBuffer + StartWriteOffset, Src, fragLen); ++ memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen); ++ } ++ else ++ { ++ memcpy(ringBuffer + StartWriteOffset, Src, SrcLen); ++ } ++ ++ StartWriteOffset += SrcLen; ++ StartWriteOffset %= ringBufferSize; ++ ++ return StartWriteOffset; ++} ++ ++ ++/*++ ++ ++Name: ++ CopyFromRingBuffer() ++ ++Description: ++ Helper routine to copy to source from ring buffer. ++ Assume there is enough room. Handles wrap-around in src case only!! ++ ++--*/ ++UINT32 ++CopyFromRingBuffer( ++ RING_BUFFER_INFO *RingInfo, ++ PVOID Dest, ++ UINT32 DestLen, ++ UINT32 StartReadOffset) ++{ ++ PVOID ringBuffer=GetRingBuffer(RingInfo); ++ UINT32 ringBufferSize=GetRingBufferSize(RingInfo); ++ ++ UINT32 fragLen; ++ ++ if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src ++ { ++ DPRINT_DBG(VMBUS, "src wrap-around detected!"); ++ ++ fragLen = ringBufferSize - StartReadOffset; ++ ++ memcpy(Dest, ringBuffer + StartReadOffset, fragLen); ++ memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen); ++ } ++ else ++ { ++ memcpy(Dest, ringBuffer + StartReadOffset, DestLen); ++ } ++ ++ StartReadOffset += DestLen; ++ StartReadOffset %= ringBufferSize; ++ ++ return StartReadOffset; ++} ++ ++ ++// eof +--- /dev/null ++++ b/drivers/staging/hv/RingBuffer.h +@@ -0,0 +1,123 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _RING_BUFFER_H_ ++#define _RING_BUFFER_H_ ++ ++#include "osd.h" ++ ++typedef struct _SG_BUFFER_LIST { ++ PVOID Data; ++ UINT32 Length; ++} SG_BUFFER_LIST; ++ ++typedef struct _RING_BUFFER { ++ volatile UINT32 WriteIndex; // Offset in bytes from the start of ring data below ++ volatile UINT32 ReadIndex; // Offset in bytes from the start of ring data below ++ ++ volatile UINT32 InterruptMask; ++ UINT8 Reserved[4084]; // Pad it to PAGE_SIZE so that data starts on page boundary ++ // NOTE: The InterruptMask field is used only for channels but since our vmbus connection ++ // also uses this data structure and its data starts here, we commented out this field. ++ // volatile UINT32 InterruptMask; ++ // Ring data starts here + RingDataStartOffset !!! DO NOT place any fields below this !!! ++ UINT8 Buffer[0]; ++} STRUCT_PACKED RING_BUFFER; ++ ++typedef struct _RING_BUFFER_INFO { ++ RING_BUFFER* RingBuffer; ++ UINT32 RingSize; // Include the shared header ++ HANDLE RingLock; ++ ++ UINT32 RingDataSize; // < ringSize ++ UINT32 RingDataStartOffset; ++ ++} RING_BUFFER_INFO; ++ ++ ++typedef struct _RING_BUFFER_DEBUG_INFO { ++ UINT32 CurrentInterruptMask; ++ UINT32 CurrentReadIndex; ++ UINT32 CurrentWriteIndex; ++ UINT32 BytesAvailToRead; ++ UINT32 BytesAvailToWrite; ++}RING_BUFFER_DEBUG_INFO; ++ ++ ++// ++// Interface ++// ++ ++INTERNAL int ++RingBufferInit( ++ RING_BUFFER_INFO *RingInfo, ++ PVOID Buffer, ++ UINT32 BufferLen ++ ); ++ ++INTERNAL void ++RingBufferCleanup( ++ RING_BUFFER_INFO *RingInfo ++ ); ++ ++INTERNAL int ++RingBufferWrite( ++ RING_BUFFER_INFO *RingInfo, ++ SG_BUFFER_LIST SgBuffers[], ++ UINT32 SgBufferCount ++ ); ++ ++INTERNAL int ++RingBufferPeek( ++ RING_BUFFER_INFO *RingInfo, ++ PVOID Buffer, ++ UINT32 BufferLen ++ ); ++ ++INTERNAL int ++RingBufferRead( ++ RING_BUFFER_INFO *RingInfo, ++ PVOID Buffer, ++ UINT32 BufferLen, ++ UINT32 Offset ++ ); ++ ++INTERNAL UINT32 ++GetRingBufferInterruptMask( ++ RING_BUFFER_INFO *RingInfo ++ ); ++ ++INTERNAL void ++DumpRingInfo( ++ RING_BUFFER_INFO* RingInfo, ++ char *Prefix ++ ); ++ ++INTERNAL void ++RingBufferGetDebugInfo( ++ RING_BUFFER_INFO *RingInfo, ++ RING_BUFFER_DEBUG_INFO *DebugInfo ++ ); ++ ++#endif // _RING_BUFFER_H_ +--- /dev/null ++++ b/drivers/staging/hv/Sources.c +@@ -0,0 +1,31 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "Vmbus.c" ++#include "Hv.c" ++#include "Connection.c" ++#include "Channel.c" ++#include "ChannelMgmt.c" ++#include "ChannelInterface.c" ++#include "RingBuffer.c" +--- /dev/null ++++ b/drivers/staging/hv/VersionInfo.h +@@ -0,0 +1,29 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#pragma once ++ ++const char VersionDate[]=__DATE__; ++const char VersionTime[]=__TIME__; ++const char VersionDesc[]= "Version 2.0"; +--- /dev/null ++++ b/drivers/staging/hv/Vmbus.c +@@ -0,0 +1,508 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++#include "VersionInfo.h" ++#include "VmbusPrivate.h" ++ ++// ++// Globals ++// ++static const char* gDriverName="vmbus"; ++ ++// Windows vmbus does not defined this. We defined this to be consistent with other devices ++//{c5295816-f63a-4d5f-8d1a-4daf999ca185} ++static const GUID gVmbusDeviceType={ ++ .Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85} ++}; ++ ++//{ac3760fc-9adf-40aa-9427-a70ed6de95c5} ++static const GUID gVmbusDeviceId={ ++ .Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5} ++}; ++ ++static DRIVER_OBJECT* gDriver; // vmbus driver object ++static DEVICE_OBJECT* gDevice; // vmbus root device ++ ++ ++// ++// Internal routines ++// ++ ++static void ++VmbusGetChannelInterface( ++ VMBUS_CHANNEL_INTERFACE *Interface ++ ); ++ ++static void ++VmbusGetChannelInfo( ++ DEVICE_OBJECT *DeviceObject, ++ DEVICE_INFO *DeviceInfo ++ ); ++ ++static void ++VmbusGetChannelOffers( ++ void ++ ); ++ ++static int ++VmbusOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ); ++ ++static int ++VmbusOnDeviceRemove( ++ DEVICE_OBJECT* dev ++ ); ++ ++static void ++VmbusOnCleanup( ++ DRIVER_OBJECT* drv ++ ); ++ ++static int ++VmbusOnISR( ++ DRIVER_OBJECT* drv ++ ); ++ ++static void ++VmbusOnMsgDPC( ++ DRIVER_OBJECT* drv ++ ); ++ ++static void ++VmbusOnEventDPC( ++ DRIVER_OBJECT* drv ++ ); ++ ++/*++; ++ ++Name: ++ VmbusInitialize() ++ ++Description: ++ Main entry point ++ ++--*/ ++int ++VmbusInitialize( ++ DRIVER_OBJECT* drv ++ ) ++{ ++ VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; ++ int ret=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime); ++ DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc); ++ ++ DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER); ++ DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT); ++ ++ DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%d, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%d", ++ sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)); ++ ++ drv->name = gDriverName; ++ memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID)); ++ ++ // Setup dispatch table ++ driver->Base.OnDeviceAdd = VmbusOnDeviceAdd; ++ driver->Base.OnDeviceRemove = VmbusOnDeviceRemove; ++ driver->Base.OnCleanup = VmbusOnCleanup; ++ driver->OnIsr = VmbusOnISR; ++ driver->OnMsgDpc = VmbusOnMsgDPC; ++ driver->OnEventDpc = VmbusOnEventDPC; ++ driver->GetChannelOffers = VmbusGetChannelOffers; ++ driver->GetChannelInterface = VmbusGetChannelInterface; ++ driver->GetChannelInfo = VmbusGetChannelInfo; ++ ++ // Hypervisor initialization...setup hypercall page..etc ++ ret = HvInit(); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret); ++ } ++ ++ gDriver = drv; ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++; ++ ++Name: ++ VmbusGetChannelOffers() ++ ++Description: ++ Retrieve the channel offers from the parent partition ++ ++--*/ ++ ++static void ++VmbusGetChannelOffers(void) ++{ ++ DPRINT_ENTER(VMBUS); ++ VmbusChannelRequestOffers(); ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++; ++ ++Name: ++ VmbusGetChannelInterface() ++ ++Description: ++ Get the channel interface ++ ++--*/ ++static void ++VmbusGetChannelInterface( ++ VMBUS_CHANNEL_INTERFACE *Interface ++ ) ++{ ++ GetChannelInterface(Interface); ++} ++ ++ ++/*++; ++ ++Name: ++ VmbusGetChannelInterface() ++ ++Description: ++ Get the device info for the specified device object ++ ++--*/ ++static void ++VmbusGetChannelInfo( ++ DEVICE_OBJECT *DeviceObject, ++ DEVICE_INFO *DeviceInfo ++ ) ++{ ++ GetChannelInfo(DeviceObject, DeviceInfo); ++} ++ ++ ++ ++/*++ ++ ++Name: ++ VmbusCreateChildDevice() ++ ++Description: ++ Creates the child device on the bus that represents the channel offer ++ ++--*/ ++ ++DEVICE_OBJECT* ++VmbusChildDeviceCreate( ++ GUID DeviceType, ++ GUID DeviceInstance, ++ void *Context) ++{ ++ VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; ++ ++ return vmbusDriver->OnChildDeviceCreate( ++ DeviceType, ++ DeviceInstance, ++ Context); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChildDeviceAdd() ++ ++Description: ++ Registers the child device with the vmbus ++ ++--*/ ++int ++VmbusChildDeviceAdd( ++ DEVICE_OBJECT* ChildDevice) ++{ ++ VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; ++ ++ return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusChildDeviceRemove() ++ ++Description: ++ Unregisters the child device from the vmbus ++ ++--*/ ++void ++VmbusChildDeviceRemove( ++ DEVICE_OBJECT* ChildDevice) ++{ ++ VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; ++ ++ vmbusDriver->OnChildDeviceRemove(ChildDevice); ++} ++ ++/*++ ++ ++Name: ++ VmbusChildDeviceDestroy() ++ ++Description: ++ Release the child device from the vmbus ++ ++--*/ ++//void ++//VmbusChildDeviceDestroy( ++// DEVICE_OBJECT* ChildDevice ++// ) ++//{ ++// VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver; ++// ++// vmbusDriver->OnChildDeviceDestroy(ChildDevice); ++//} ++ ++/*++ ++ ++Name: ++ VmbusOnDeviceAdd() ++ ++Description: ++ Callback when the root bus device is added ++ ++--*/ ++static int ++VmbusOnDeviceAdd( ++ DEVICE_OBJECT *dev, ++ void *AdditionalInfo ++ ) ++{ ++ UINT32 *irqvector = (UINT32*) AdditionalInfo; ++ int ret=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ gDevice = dev; ++ ++ memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID)); ++ memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID)); ++ ++ //strcpy(dev->name, "vmbus"); ++ // SynIC setup... ++ ret = HvSynicInit(*irqvector); ++ ++ // Connect to VMBus in the root partition ++ ret = VmbusConnect(); ++ ++ //VmbusSendEvent(device->localPortId+1); ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusOnDeviceRemove() ++ ++Description: ++ Callback when the root bus device is removed ++ ++--*/ ++int VmbusOnDeviceRemove( ++ DEVICE_OBJECT* dev ++ ) ++{ ++ int ret=0; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ VmbusChannelReleaseUnattachedChannels(); ++ ++ VmbusDisconnect(); ++ ++ HvSynicCleanup(); ++ ++ DPRINT_EXIT(VMBUS); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusOnCleanup() ++ ++Description: ++ Perform any cleanup when the driver is removed ++ ++--*/ ++void ++VmbusOnCleanup( ++ DRIVER_OBJECT* drv ++ ) ++{ ++ //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ HvCleanup(); ++ ++ DPRINT_EXIT(VMBUS); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusOnMsgDPC() ++ ++Description: ++ DPC routine to handle messages from the hypervisior ++ ++--*/ ++void ++VmbusOnMsgDPC( ++ DRIVER_OBJECT* drv ++ ) ++{ ++ void *page_addr = gHvContext.synICMessagePage[0]; ++ ++ HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT; ++ HV_MESSAGE *copied; ++ while (1) ++ { ++ if (msg->Header.MessageType == HvMessageTypeNone) // no msg ++ { ++ break; ++ } ++ else ++ { ++ copied = MemAllocAtomic(sizeof(HV_MESSAGE)); ++ if (copied == NULL) ++ { ++ continue; ++ } ++ ++ memcpy(copied, msg, sizeof(HV_MESSAGE)); ++ WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied); ++ } ++ ++ msg->Header.MessageType = HvMessageTypeNone; ++ ++ // Make sure the write to MessageType (ie set to HvMessageTypeNone) happens ++ // before we read the MessagePending and EOMing. Otherwise, the EOMing will not deliver ++ // any more messages since there is no empty slot ++ MemoryFence(); ++ ++ if (msg->Header.MessageFlags.MessagePending) ++ { ++ // This will cause message queue rescan to possibly deliver another msg from the hypervisor ++ WriteMsr(HV_X64_MSR_EOM, 0); ++ } ++ } ++} ++ ++/*++ ++ ++Name: ++ VmbusOnEventDPC() ++ ++Description: ++ DPC routine to handle events from the hypervisior ++ ++--*/ ++void ++VmbusOnEventDPC( ++ DRIVER_OBJECT* drv ++ ) ++{ ++ // TODO: Process any events ++ VmbusOnEvents(); ++} ++ ++ ++/*++ ++ ++Name: ++ VmbusOnISR() ++ ++Description: ++ ISR routine ++ ++--*/ ++int ++VmbusOnISR( ++ DRIVER_OBJECT* drv ++ ) ++{ ++ //VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv; ++ ++ int ret=0; ++ //struct page* page; ++ void *page_addr; ++ HV_MESSAGE* msg; ++ HV_SYNIC_EVENT_FLAGS* event; ++ ++ //page = SynICMessagePage[0]; ++ //page_addr = page_address(page); ++ page_addr = gHvContext.synICMessagePage[0]; ++ msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT; ++ ++ DPRINT_ENTER(VMBUS); ++ ++ // Check if there are actual msgs to be process ++ if (msg->Header.MessageType != HvMessageTypeNone) ++ { ++ DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize); ++ ret |= 0x1; ++ } ++ ++ // TODO: Check if there are events to be process ++ page_addr = gHvContext.synICEventPage[0]; ++ event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT; ++ ++ // Since we are a child, we only need to check bit 0 ++ if (BitTestAndClear(&event->Flags32[0], 0)) ++ { ++ DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]); ++ ret |= 0x2; ++ } ++ ++ DPRINT_EXIT(VMBUS); ++ return ret; ++} ++ ++// eof +--- /dev/null ++++ b/drivers/staging/hv/vmbus_drv.c +@@ -0,0 +1,1228 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "logging.h" ++#include "vmbus.h" ++ ++// ++// Defines ++// ++ ++// FIXME! We need to do this dynamically for PIC and APIC system ++#define VMBUS_IRQ 0x5 ++#ifdef KERNEL_2_6_27 ++#define VMBUS_IRQ_VECTOR IRQ5_VECTOR ++#endif ++// ++// Data types ++// ++ ++// Main vmbus driver data structure ++struct vmbus_driver_context { ++ // !! These must be the first 2 fields !! ++ // The driver field is not used in here. Instead, the bus field is ++ // used to represent the driver ++ struct driver_context drv_ctx; ++ VMBUS_DRIVER_OBJECT drv_obj; ++ ++ struct bus_type bus; ++ struct tasklet_struct msg_dpc; ++ struct tasklet_struct event_dpc; ++ ++ // The bus root device ++ struct device_context device_ctx; ++}; ++ ++// ++// Static decl ++// ++static int vmbus_match(struct device *device, struct device_driver *driver); ++static int vmbus_probe(struct device *device); ++static int vmbus_remove(struct device *device); ++static void vmbus_shutdown(struct device *device); ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#elif defined(KERNEL_2_6_27) ++static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env); ++#else ++static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size); ++#endif ++static void vmbus_msg_dpc(unsigned long data); ++static void vmbus_event_dpc(unsigned long data); ++ ++#ifdef KERNEL_2_6_27 ++static irqreturn_t vmbus_isr(int irq, void* dev_id); ++#else ++static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs); ++#endif ++ ++static void vmbus_device_release(struct device *device); ++static void vmbus_bus_release(struct device *device); ++ ++static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context); ++static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj); ++static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj); ++static void vmbus_child_device_unregister(DEVICE_OBJECT* child_device_obj); ++static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info); ++ ++//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf); ++//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf); ++ ++static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf); ++ ++// ++// Global ++// ++ ++// Global logging setting ++ ++//unsigned int vmbus_loglevel= (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); ++//unsigned int vmbus_loglevel= (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); ++unsigned int vmbus_loglevel= (ALL_MODULES << 16 | INFO_LVL); ++EXPORT_SYMBOL(vmbus_loglevel); ++ ++static int vmbus_irq = VMBUS_IRQ; ++ ++// Setup /proc/sys/bus/vmbus/vmbus_loglevel ++// Allow usage of sysctl cmd to set the logging level ++static struct ctl_table_header *vmbus_ctl_table_hdr; ++ ++static ctl_table vmbus_dev_ctl_table[] = { ++ { .ctl_name = 8461, ++ .procname = "vmbus_loglevel", ++ .data = &vmbus_loglevel, ++ .maxlen = sizeof(vmbus_loglevel), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec }, ++ { } ++}; ++ ++static ctl_table vmbus_ctl_table[] = { ++ { .ctl_name = CTL_DEV, ++ .procname = "vmbus", ++ .mode = 0555, ++ .child = vmbus_dev_ctl_table }, ++ { } ++}; ++ ++static ctl_table vmus_root_ctl_table[] = { ++ { .ctl_name = CTL_BUS, ++ .procname = "bus", ++ .mode = 0555, ++ .child = vmbus_ctl_table }, ++ { } ++}; ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#else ++// ++// Set up per device attributes in /sys/bus/vmbus/devices/ ++// ++static struct device_attribute vmbus_device_attrs[] = { ++ __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL), ++ ++ __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), ++ ++ __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), ++ ++ __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), ++ ++ __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), ++ __ATTR_NULL ++}; ++#endif ++ ++// The one and only one ++static struct vmbus_driver_context g_vmbus_drv={ ++ .bus.name = "vmbus", ++ .bus.match = vmbus_match, ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#else ++ .bus.shutdown = vmbus_shutdown, ++ .bus.remove = vmbus_remove, ++ .bus.probe = vmbus_probe, ++ .bus.uevent = vmbus_uevent, ++ .bus.dev_attrs = vmbus_device_attrs, ++#endif ++}; ++ ++// ++// Routines ++// ++ ++ ++/*++ ++ ++Name: vmbus_show_device_attr() ++ ++Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices//" ++ ++--*/ ++static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf) ++{ ++ struct device_context *device_ctx = device_to_device_context(dev); ++ DEVICE_INFO device_info; ++ ++ memset(&device_info, 0, sizeof(DEVICE_INFO)); ++ ++ vmbus_child_device_get_info(&device_ctx->device_obj, &device_info); ++ ++ if (!strcmp(dev_attr->attr.name, "class_id")) ++ { ++ return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", ++ device_info.ChannelType.Data[3], device_info.ChannelType.Data[2], device_info.ChannelType.Data[1], device_info.ChannelType.Data[0], ++ device_info.ChannelType.Data[5], device_info.ChannelType.Data[4], ++ device_info.ChannelType.Data[7], device_info.ChannelType.Data[6], ++ device_info.ChannelType.Data[8], device_info.ChannelType.Data[9], device_info.ChannelType.Data[10], device_info.ChannelType.Data[11], device_info.ChannelType.Data[12], device_info.ChannelType.Data[13], device_info.ChannelType.Data[14], device_info.ChannelType.Data[15]); ++ ++ } ++ else if (!strcmp(dev_attr->attr.name, "device_id")) ++ { ++ return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", ++ device_info.ChannelInstance.Data[3], device_info.ChannelInstance.Data[2], device_info.ChannelInstance.Data[1], device_info.ChannelInstance.Data[0], ++ device_info.ChannelInstance.Data[5], device_info.ChannelInstance.Data[4], ++ device_info.ChannelInstance.Data[7], device_info.ChannelInstance.Data[6], ++ device_info.ChannelInstance.Data[8], device_info.ChannelInstance.Data[9], device_info.ChannelInstance.Data[10], device_info.ChannelInstance.Data[11], device_info.ChannelInstance.Data[12], device_info.ChannelInstance.Data[13], device_info.ChannelInstance.Data[14], device_info.ChannelInstance.Data[15]); ++ } ++ else if (!strcmp(dev_attr->attr.name, "state")) ++ { ++ return sprintf(buf, "%d\n", device_info.ChannelState); ++ } ++ else if (!strcmp(dev_attr->attr.name, "id")) ++ { ++ return sprintf(buf, "%d\n", device_info.ChannelId); ++ } ++ else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) ++ { ++ return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask); ++ } ++ else if (!strcmp(dev_attr->attr.name, "out_read_index")) ++ { ++ return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex); ++ } ++ else if (!strcmp(dev_attr->attr.name, "out_write_index")) ++ { ++ return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex); ++ } ++ else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) ++ { ++ return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead); ++ } ++ else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) ++ { ++ return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite); ++ } ++ else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) ++ { ++ return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask); ++ } ++ else if (!strcmp(dev_attr->attr.name, "in_read_index")) ++ { ++ return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex); ++ } ++ else if (!strcmp(dev_attr->attr.name, "in_write_index")) ++ { ++ return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex); ++ } ++ else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) ++ { ++ return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead); ++ } ++ else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) ++ { ++ return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite); ++ } ++ else if (!strcmp(dev_attr->attr.name, "monitor_id")) ++ { ++ return sprintf(buf, "%d\n", device_info.MonitorId); ++ } ++ else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) ++ { ++ return sprintf(buf, "%d\n", device_info.ServerMonitorPending); ++ } ++ else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) ++ { ++ return sprintf(buf, "%d\n", device_info.ServerMonitorLatency); ++ } ++ else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) ++ { ++ return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId); ++ } ++ else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) ++ { ++ return sprintf(buf, "%d\n", device_info.ClientMonitorPending); ++ } ++ else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) ++ { ++ return sprintf(buf, "%d\n", device_info.ClientMonitorLatency); ++ } ++ else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) ++ { ++ return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId); ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++/*++ ++ ++Name: vmbus_show_class_id() ++ ++Desc: Show the device class id in sysfs ++ ++--*/ ++//static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf) ++//{ ++// struct device_context *device_ctx = device_to_device_context(dev); ++// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", ++// device_ctx->class_id[3], device_ctx->class_id[2], device_ctx->class_id[1], device_ctx->class_id[0], ++// device_ctx->class_id[5], device_ctx->class_id[4], ++// device_ctx->class_id[7], device_ctx->class_id[6], ++// device_ctx->class_id[8], device_ctx->class_id[9], device_ctx->class_id[10], device_ctx->class_id[11], device_ctx->class_id[12], device_ctx->class_id[13], device_ctx->class_id[14], device_ctx->class_id[15]); ++//} ++ ++/*++ ++ ++Name: vmbus_show_device_id() ++ ++Desc: Show the device instance id in sysfs ++ ++--*/ ++//static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) ++//{ ++// struct device_context *device_ctx = device_to_device_context(dev); ++// return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", ++// device_ctx->device_id[3], device_ctx->device_id[2], device_ctx->device_id[1], device_ctx->device_id[0], ++// device_ctx->device_id[5], device_ctx->device_id[4], ++// device_ctx->device_id[7], device_ctx->device_id[6], ++// device_ctx->device_id[8], device_ctx->device_id[9], device_ctx->device_id[10], device_ctx->device_id[11], device_ctx->device_id[12], device_ctx->device_id[13], device_ctx->device_id[14], device_ctx->device_id[15]); ++//} ++ ++/*++ ++ ++Name: vmbus_bus_init() ++ ++Desc: Main vmbus driver initialization routine. Here, we ++ - initialize the vmbus driver context ++ - setup various driver entry points ++ - invoke the vmbus hv main init routine ++ - get the irq resource ++ - invoke the vmbus to add the vmbus root device ++ - setup the vmbus root device ++ - retrieve the channel offers ++--*/ ++int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init) ++{ ++ int ret=0; ++ unsigned int vector=0; ++ ++ struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv; ++ VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; ++ ++ struct device_context *dev_ctx=&g_vmbus_drv.device_ctx; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Set this up to allow lower layer to callback to add/remove child devices on the bus ++ vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create; ++ vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy; ++ vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register; ++ vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister; ++ ++ // Call to bus driver to initialize ++ ret = pfn_drv_init(&vmbus_drv_obj->Base); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret); ++ goto cleanup; ++ } ++ ++ // Sanity checks ++ if (!vmbus_drv_obj->Base.OnDeviceAdd) ++ { ++ DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set"); ++ ret = -1; ++ goto cleanup; ++ } ++ ++ vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name; ++ ++ // Initialize the bus context ++ tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, (unsigned long)vmbus_drv_obj); ++ tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, (unsigned long)vmbus_drv_obj); ++ ++ // Now, register the bus driver with LDM ++ bus_register(&vmbus_drv_ctx->bus); ++ ++ // Get the interrupt resource ++#ifdef KERNEL_2_6_27 ++ ret = request_irq(vmbus_irq, ++ vmbus_isr, ++ IRQF_SAMPLE_RANDOM, ++ vmbus_drv_obj->Base.name, ++ NULL); ++#else ++ ret = request_irq(vmbus_irq, ++ vmbus_isr, ++ SA_SAMPLE_RANDOM, ++ vmbus_drv_obj->Base.name, ++ NULL); ++#endif ++ ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq); ++ ++ bus_unregister(&vmbus_drv_ctx->bus); ++ ++ ret = -1; ++ goto cleanup; ++ } ++#ifdef KERNEL_2_6_27 ++ vector = VMBUS_IRQ_VECTOR; ++#else ++#if X2V_LINUX ++ vector = vmbus_irq + FIRST_DEVICE_VECTOR - 2; ++#else ++ vector = vmbus_irq + FIRST_EXTERNAL_VECTOR; ++#endif ++#endif ++ ++ DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector); ++ ++ // Call to bus driver to add the root device ++ memset(dev_ctx, 0, sizeof(struct device_context)); ++ ++ ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device"); ++ ++ free_irq(vmbus_irq, NULL); ++ ++ bus_unregister(&vmbus_drv_ctx->bus); ++ ++ ret = -1; ++ goto cleanup; ++ } ++ //strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); ++ sprintf(dev_ctx->device.bus_id, "vmbus_0_0"); ++ memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(GUID)); ++ memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(GUID)); ++ ++ // No need to bind a driver to the root device. ++ dev_ctx->device.parent = NULL; ++ dev_ctx->device.bus = &vmbus_drv_ctx->bus; //NULL; // vmbus_remove() does not get invoked ++ ++ // Setup the device dispatch table ++ dev_ctx->device.release = vmbus_bus_release; ++ ++ // Setup the bus as root device ++ device_register(&dev_ctx->device); ++ ++ vmbus_drv_obj->GetChannelOffers(); ++ ++cleanup: ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: vmbus_bus_exit() ++ ++Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init() ++ ++--*/ ++void vmbus_bus_exit(void) ++{ ++ VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; ++ struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv; ++ ++ struct device_context *dev_ctx=&g_vmbus_drv.device_ctx; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Remove the root device ++ if (vmbus_drv_obj->Base.OnDeviceRemove) ++ vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj); ++ ++ if (vmbus_drv_obj->Base.OnCleanup) ++ vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base); ++ ++ // Unregister the root bus device ++ device_unregister(&dev_ctx->device); ++ ++ bus_unregister(&vmbus_drv_ctx->bus); ++ ++ free_irq(vmbus_irq, NULL); ++ ++ tasklet_kill(&vmbus_drv_ctx->msg_dpc); ++ tasklet_kill(&vmbus_drv_ctx->event_dpc); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return; ++} ++ ++/*++ ++ ++Name: vmbus_child_driver_register() ++ ++Desc: Register a vmbus's child driver ++ ++--*/ ++void vmbus_child_driver_register(struct driver_context* driver_ctx) ++{ ++ VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name); ++ ++ // The child driver on this vmbus ++ driver_ctx->driver.bus = &g_vmbus_drv.bus; ++ ++ driver_register(&driver_ctx->driver); ++ ++ vmbus_drv_obj->GetChannelOffers(); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++EXPORT_SYMBOL(vmbus_child_driver_register); ++ ++/*++ ++ ++Name: vmbus_child_driver_unregister() ++ ++Desc: Unregister a vmbus's child driver ++ ++--*/ ++void vmbus_child_driver_unregister(struct driver_context* driver_ctx) ++{ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name); ++ ++ driver_unregister(&driver_ctx->driver); ++ ++ driver_ctx->driver.bus = NULL; ++ ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++EXPORT_SYMBOL(vmbus_child_driver_unregister); ++ ++/*++ ++ ++Name: vmbus_get_interface() ++ ++Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits ++ above vmbus ++--*/ ++void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface) ++{ ++ VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; ++ ++ vmbus_drv_obj->GetChannelInterface(interface); ++} ++ ++EXPORT_SYMBOL(vmbus_get_interface); ++ ++ ++/*++ ++ ++Name: vmbus_child_device_get_info() ++ ++Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs. ++--*/ ++static void vmbus_child_device_get_info(DEVICE_OBJECT *device_obj, DEVICE_INFO *device_info) ++{ ++ VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj; ++ ++ vmbus_drv_obj->GetChannelInfo(device_obj, device_info); ++} ++ ++ ++/*++ ++ ++Name: vmbus_child_device_create() ++ ++Desc: Creates and registers a new child device on the vmbus. ++ ++--*/ ++static DEVICE_OBJECT* vmbus_child_device_create(GUID type, GUID instance, void* context) ++{ ++ struct device_context *child_device_ctx; ++ DEVICE_OBJECT* child_device_obj; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Allocate the new child device ++ child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL); ++ if (!child_device_ctx) ++ { ++ DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device"); ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return NULL; ++ } ++ ++ DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - " ++ "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}," ++ "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ &child_device_ctx->device, ++ type.Data[3], type.Data[2], type.Data[1], type.Data[0], type.Data[5], type.Data[4], type.Data[7], type.Data[6], type.Data[8], type.Data[9], type.Data[10], type.Data[11], type.Data[12], type.Data[13], type.Data[14], type.Data[15], ++ instance.Data[3], instance.Data[2], instance.Data[1], instance.Data[0], instance.Data[5], instance.Data[4], instance.Data[7], instance.Data[6], instance.Data[8], instance.Data[9], instance.Data[10], instance.Data[11], instance.Data[12], instance.Data[13], instance.Data[14], instance.Data[15]); ++ ++ child_device_obj = &child_device_ctx->device_obj; ++ child_device_obj->context = context; ++ memcpy(&child_device_obj->deviceType, &type, sizeof(GUID)); ++ memcpy(&child_device_obj->deviceInstance, &instance, sizeof(GUID)); ++ ++ memcpy(&child_device_ctx->class_id, &type, sizeof(GUID)); ++ memcpy(&child_device_ctx->device_id, &instance, sizeof(GUID)); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return child_device_obj; ++} ++ ++/*++ ++ ++Name: vmbus_child_device_register() ++ ++Desc: Register the child device on the specified bus ++ ++--*/ ++static int vmbus_child_device_register(DEVICE_OBJECT* root_device_obj, DEVICE_OBJECT* child_device_obj) ++{ ++ int ret=0; ++ struct device_context *root_device_ctx = to_device_context(root_device_obj); ++ struct device_context *child_device_ctx = to_device_context(child_device_obj); ++ static int device_num=0; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx); ++ // ++ // Make sure we are not registered already ++ // ++ if (child_device_ctx->device.bus_id[0] != '\0') ++ { ++ DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id); ++ ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Set the device bus id. Otherwise, device_register()will fail. ++ sprintf(child_device_ctx->device.bus_id, "vmbus_0_%d", InterlockedIncrement(&device_num)); ++ ++ // The new device belongs to this bus ++ child_device_ctx->device.bus = &g_vmbus_drv.bus; //device->dev.bus; ++ child_device_ctx->device.parent = &root_device_ctx->device; ++ child_device_ctx->device.release = vmbus_device_release; ++ ++ // Register with the LDM. This will kick off the driver/device binding...which will ++ // eventually call vmbus_match() and vmbus_probe() ++ ret = device_register(&child_device_ctx->device); ++ ++ // vmbus_probe() error does not get propergate to device_register(). ++ ret = child_device_ctx->probe_error; ++ ++ if (ret) ++ DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p) (%d)", &child_device_ctx->device); ++ else ++ DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device); ++ ++Cleanup: ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: vmbus_child_device_unregister() ++ ++Desc: Remove the specified child device from the vmbus. ++ ++--*/ ++static void vmbus_child_device_unregister(DEVICE_OBJECT* device_obj) ++{ ++ struct device_context *device_ctx = to_device_context(device_obj); ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device); ++ ++ // Kick off the process of unregistering the device. ++ // This will call vmbus_remove() and eventually vmbus_device_release() ++ device_unregister(&device_ctx->device); ++ ++ DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++ ++/*++ ++ ++Name: vmbus_child_device_destroy() ++ ++Desc: Destroy the specified child device on the vmbus. ++ ++--*/ ++static void vmbus_child_device_destroy(DEVICE_OBJECT* device_obj) ++{ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++/*++ ++ ++Name: vmbus_uevent() ++ ++Desc: This routine is invoked when a device is added or removed on the vmbus to generate a uevent to udev in the ++ userspace. The udev will then look at its rule and the uevent generated here to load the appropriate driver ++ ++--*/ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#elif defined(KERNEL_2_6_27) ++static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) ++{ ++ struct device_context *device_ctx = device_to_device_context(device); ++ int i=0; ++ int len=0; ++ int ret; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], ++ device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], ++ device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], ++ device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], ++ device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); ++ ++ env->envp_idx = i; ++ env->buflen = len; ++ ret = add_uevent_var(env, ++ "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], ++ device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], ++ device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], ++ device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], ++ device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); ++ ++ if (ret) ++ { ++ return ret; ++ } ++ ++ ret = add_uevent_var(env, ++ "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0], ++ device_ctx->device_id.Data[5], device_ctx->device_id.Data[4], ++ device_ctx->device_id.Data[7], device_ctx->device_id.Data[6], ++ device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11], ++ device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]); ++ ++ if (ret) ++ { ++ return ret; ++ } ++ ++ env->envp[env->envp_idx] = NULL; ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return 0; ++} ++ ++#else ++static int vmbus_uevent(struct device *device, char **envp, int num_envp, char *buffer, int buffer_size) ++{ ++ struct device_context *device_ctx = device_to_device_context(device); ++ int i=0; ++ int len=0; ++ int ret; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], ++ device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], ++ device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], ++ device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], ++ device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); ++ ++ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, ++ "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ device_ctx->class_id.Data[3], device_ctx->class_id.Data[2], device_ctx->class_id.Data[1], device_ctx->class_id.Data[0], ++ device_ctx->class_id.Data[5], device_ctx->class_id.Data[4], ++ device_ctx->class_id.Data[7], device_ctx->class_id.Data[6], ++ device_ctx->class_id.Data[8], device_ctx->class_id.Data[9], device_ctx->class_id.Data[10], device_ctx->class_id.Data[11], ++ device_ctx->class_id.Data[12], device_ctx->class_id.Data[13], device_ctx->class_id.Data[14], device_ctx->class_id.Data[15]); ++ ++ if (ret) ++ { ++ return ret; ++ } ++ ++ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, ++ "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}", ++ device_ctx->device_id.Data[3], device_ctx->device_id.Data[2], device_ctx->device_id.Data[1], device_ctx->device_id.Data[0], ++ device_ctx->device_id.Data[5], device_ctx->device_id.Data[4], ++ device_ctx->device_id.Data[7], device_ctx->device_id.Data[6], ++ device_ctx->device_id.Data[8], device_ctx->device_id.Data[9], device_ctx->device_id.Data[10], device_ctx->device_id.Data[11], ++ device_ctx->device_id.Data[12], device_ctx->device_id.Data[13], device_ctx->device_id.Data[14], device_ctx->device_id.Data[15]); ++ ++ if (ret) ++ { ++ return ret; ++ } ++ ++ envp[i] = NULL; ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return 0; ++} ++#endif ++ ++/*++ ++ ++Name: vmbus_match() ++ ++Desc: Attempt to match the specified device to the specified driver ++ ++--*/ ++static int vmbus_match(struct device *device, struct device_driver *driver) ++{ ++ int match=0; ++ struct driver_context *driver_ctx = driver_to_driver_context(driver); ++ struct device_context *device_ctx = device_to_device_context(device); ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // We found our driver ? ++ if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(GUID)) == 0) ++ { ++ // !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast it here to access the ++ // DRIVER_OBJECT field ++ struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context*)driver_ctx; ++ device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base; ++ DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, device_ctx->device_obj.Driver); ++ ++ match = 1; ++ } ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return match; ++} ++ ++ ++/*++ ++ ++Name: vmbus_probe_failed_cb() ++ ++Desc: Callback when a driver probe failed in vmbus_probe(). We need a callback because ++ we cannot invoked device_unregister() inside vmbus_probe() since vmbus_probe() may be ++ invoked inside device_register() i.e. we cannot call device_unregister() inside ++ device_register() ++--*/ ++#ifdef KERNEL_2_6_27 ++static void vmbus_probe_failed_cb(struct work_struct *context) ++#else ++static void vmbus_probe_failed_cb(void* context) ++#endif ++{ ++ struct device_context *device_ctx = (struct device_context*)context; ++ ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Kick off the process of unregistering the device. ++ // This will call vmbus_remove() and eventually vmbus_device_release() ++ device_unregister(&device_ctx->device); ++ ++ //put_device(&device_ctx->device); ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++ ++/*++ ++ ++Name: vmbus_probe() ++ ++Desc: Add the new vmbus's child device ++ ++--*/ ++static int vmbus_probe(struct device *child_device) ++{ ++ int ret=0; ++ struct driver_context *driver_ctx = driver_to_driver_context(child_device->driver); ++ struct device_context *device_ctx = device_to_device_context(child_device); ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Let the specific open-source driver handles the probe if it can ++ if (driver_ctx->probe) ++ { ++ ret = device_ctx->probe_error = driver_ctx->probe(child_device); ++ if (ret != 0) ++ { ++ DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s (%p) on driver %s (%d)...", child_device->bus_id, child_device, child_device->driver->name, ret); ++ ++#ifdef KERNEL_2_6_27 ++ INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb); ++#else ++ INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb, device_ctx); ++#endif ++ schedule_work(&device_ctx->probe_failed_work_item); ++ } ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name); ++ ret = -1; ++ } ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: vmbus_remove() ++ ++Desc: Remove a vmbus device ++ ++--*/ ++static int vmbus_remove(struct device *child_device) ++{ ++ int ret=0; ++ struct driver_context *driver_ctx; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Special case root bus device ++ if (child_device->parent == NULL) ++ { ++ // No-op since it is statically defined and handle in vmbus_bus_exit() ++ DPRINT_EXIT(VMBUS_DRV); ++ return 0; ++ } ++ ++ if (child_device->driver) ++ { ++ driver_ctx = driver_to_driver_context(child_device->driver); ++ ++ // Let the specific open-source driver handles the removal if it can ++ if (driver_ctx->remove) ++ { ++ ret = driver_ctx->remove(child_device); ++ } ++ else ++ { ++ DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name); ++ ret = -1; ++ } ++ } ++ else ++ { ++ ++ } ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return 0; ++} ++ ++/*++ ++ ++Name: vmbus_shutdown() ++ ++Desc: Shutdown a vmbus device ++ ++--*/ ++static void vmbus_shutdown(struct device *child_device) ++{ ++ struct driver_context *driver_ctx; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ // Special case root bus device ++ if (child_device->parent == NULL) ++ { ++ // No-op since it is statically defined and handle in vmbus_bus_exit() ++ DPRINT_EXIT(VMBUS_DRV); ++ return; ++ } ++ ++ // The device may not be attached yet ++ if (!child_device->driver) ++ { ++ DPRINT_EXIT(VMBUS_DRV); ++ return; ++ } ++ ++ driver_ctx = driver_to_driver_context(child_device->driver); ++ ++ // Let the specific open-source driver handles the removal if it can ++ if (driver_ctx->shutdown) ++ { ++ driver_ctx->shutdown(child_device); ++ } ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return; ++} ++ ++/*++ ++ ++Name: vmbus_bus_release() ++ ++Desc: Final callback release of the vmbus root device ++ ++--*/ ++static void vmbus_bus_release(struct device *device) ++{ ++ DPRINT_ENTER(VMBUS_DRV); ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++/*++ ++ ++Name: vmbus_device_release() ++ ++Desc: Final callback release of the vmbus child device ++ ++--*/ ++static void vmbus_device_release(struct device *device) ++{ ++ struct device_context *device_ctx = device_to_device_context(device); ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ //vmbus_child_device_destroy(&device_ctx->device_obj); ++ kfree(device_ctx); ++ ++ // !!DO NOT REFERENCE device_ctx anymore at this point!! ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return; ++} ++ ++/*++ ++ ++Name: vmbus_msg_dpc() ++ ++Desc: Tasklet routine to handle hypervisor messages ++ ++--*/ ++static void vmbus_msg_dpc(unsigned long data) ++{ ++ VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ ASSERT(vmbus_drv_obj->OnMsgDpc != NULL); ++ ++ // Call to bus driver to handle interrupt ++ vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++/*++ ++ ++Name: vmbus_msg_dpc() ++ ++Desc: Tasklet routine to handle hypervisor events ++ ++--*/ ++static void vmbus_event_dpc(unsigned long data) ++{ ++ VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ ASSERT(vmbus_drv_obj->OnEventDpc != NULL); ++ ++ // Call to bus driver to handle interrupt ++ vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++} ++ ++/*++ ++ ++Name: vmbus_msg_dpc() ++ ++Desc: ISR routine ++ ++--*/ ++#ifdef KERNEL_2_6_27 ++static irqreturn_t vmbus_isr(int irq, void* dev_id) ++#else ++static int vmbus_isr(int irq, void* dev_id, struct pt_regs *regs) ++#endif ++{ ++ int ret=0; ++ VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ ASSERT(vmbus_driver_obj->OnIsr != NULL); ++ ++ // Call to bus driver to handle interrupt ++ ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base); ++ ++ // Schedules a dpc if necessary ++ if (ret > 0) ++ { ++ if (test_bit(0, (unsigned long*)&ret)) ++ { ++ tasklet_schedule(&g_vmbus_drv.msg_dpc); ++ } ++ ++ if (test_bit(1, (unsigned long*)&ret)) ++ { ++ tasklet_schedule(&g_vmbus_drv.event_dpc); ++ } ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ return IRQ_HANDLED; ++ } ++ else ++ { ++ DPRINT_EXIT(VMBUS_DRV); ++ return IRQ_NONE; ++ } ++} ++ ++MODULE_LICENSE("GPL"); ++ ++ ++/*++ ++ ++Name: vmbus_init() ++ ++Desc: Main vmbus driver entry routine ++ ++--*/ ++static int __init vmbus_init(void) ++{ ++ int ret=0; ++ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ DPRINT_INFO(VMBUS_DRV, ++ "Vmbus initializing.... current log level 0x%x (%x,%x)", ++ vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel)); ++#ifdef KERNEL_2_6_27 ++//Todo: it is used for loglevel, to be ported to new kernel. ++#else ++ vmbus_ctl_table_hdr = register_sysctl_table(vmus_root_ctl_table, 0); ++ if (!vmbus_ctl_table_hdr) ++ { ++ DPRINT_EXIT(VMBUS_DRV); ++ return -ENOMEM; ++ } ++#endif ++ ++ ret = vmbus_bus_init(VmbusInitialize); ++ ++ DPRINT_EXIT(VMBUS_DRV); ++ return ret; ++} ++ ++ ++ ++/*++ ++ ++Name: vmbus_init() ++ ++Desc: Main vmbus driver exit routine ++ ++--*/ ++static void __exit vmbus_exit(void) ++{ ++ DPRINT_ENTER(VMBUS_DRV); ++ ++ vmbus_bus_exit(); ++#ifdef KERNEL_2_6_27 ++//Todo: it is used for loglevel, to be ported to new kernel. ++#else ++ unregister_sysctl_table(vmbus_ctl_table_hdr); ++#endif ++ DPRINT_EXIT(VMBUS_DRV); ++ ++ return; ++} ++ ++#if defined(KERNEL_2_6_5) ++#else ++module_param(vmbus_irq, int, S_IRUGO); ++module_param(vmbus_loglevel, int, S_IRUGO); ++#endif ++ ++module_init(vmbus_init); ++module_exit(vmbus_exit); ++// eof +--- /dev/null ++++ b/drivers/staging/hv/VmbusPrivate.h +@@ -0,0 +1,170 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _VMBUS_PRIVATE_H_ ++#define _VMBUS_PRIVATE_H_ ++ ++#ifndef INTERNAL ++#define INTERNAL static ++#endif ++ ++#include "Hv.h" ++#include "VmbusApi.h" ++#include "Channel.h" ++#include "ChannelMgmt.h" ++#include "ChannelInterface.h" ++//#include "ChannelMessages.h" ++#include "RingBuffer.h" ++//#include "Packet.h" ++#include "List.h" ++ ++// ++// Defines ++// ++ ++// Maximum channels is determined by the size of the interrupt page which is PAGE_SIZE. 1/2 of PAGE_SIZE is for ++// send endpoint interrupt and the other is receive endpoint interrupt ++#define MAX_NUM_CHANNELS (PAGE_SIZE >> 1) << 3 // 16348 channels ++ ++// The value here must be in multiple of 32 ++// TODO: Need to make this configurable ++#define MAX_NUM_CHANNELS_SUPPORTED 256 ++ ++// ++// Data types ++// ++ ++typedef enum { ++ Disconnected, ++ Connecting, ++ Connected, ++ Disconnecting ++} VMBUS_CONNECT_STATE; ++ ++#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT ++ ++typedef struct _VMBUS_CONNECTION { ++ ++ VMBUS_CONNECT_STATE ConnectState; ++ ++ UINT32 NextGpadlHandle; ++ ++ // Represents channel interrupts. Each bit position ++ // represents a channel. ++ // When a channel sends an interrupt via VMBUS, it ++ // finds its bit in the sendInterruptPage, set it and ++ // calls Hv to generate a port event. The other end ++ // receives the port event and parse the recvInterruptPage ++ // to see which bit is set ++ VOID* InterruptPage; ++ VOID* SendInterruptPage; ++ VOID* RecvInterruptPage; ++ ++ // 2 pages - 1st page for parent->child notification and 2nd is child->parent notification ++ VOID* MonitorPages; ++ LIST_ENTRY ChannelMsgList; ++ HANDLE ChannelMsgLock; ++ ++ // List of channels ++ LIST_ENTRY ChannelList; ++ HANDLE ChannelLock; ++ ++ HANDLE WorkQueue; ++} VMBUS_CONNECTION; ++ ++ ++typedef struct _VMBUS_MSGINFO { ++ // Bookkeeping stuff ++ LIST_ENTRY MsgListEntry; ++ ++ // Synchronize the request/response if needed ++ HANDLE WaitEvent; ++ ++ // The message itself ++ unsigned char Msg[0]; ++} VMBUS_MSGINFO; ++ ++ ++// ++// Externs ++// ++extern VMBUS_CONNECTION gVmbusConnection; ++ ++// ++// General vmbus interface ++// ++INTERNAL DEVICE_OBJECT* ++VmbusChildDeviceCreate( ++ GUID deviceType, ++ GUID deviceInstance, ++ void *context); ++ ++INTERNAL int ++VmbusChildDeviceAdd( ++ DEVICE_OBJECT* Device); ++ ++INTERNAL void ++VmbusChildDeviceRemove( ++ DEVICE_OBJECT* Device); ++ ++//INTERNAL void ++//VmbusChildDeviceDestroy( ++// DEVICE_OBJECT*); ++ ++INTERNAL VMBUS_CHANNEL* ++GetChannelFromRelId( ++ UINT32 relId ++ ); ++ ++// ++// Connection interface ++// ++INTERNAL int ++VmbusConnect( ++ VOID ++ ); ++ ++INTERNAL int ++VmbusDisconnect( ++ VOID ++ ); ++ ++INTERNAL int ++VmbusPostMessage( ++ PVOID buffer, ++ SIZE_T bufSize ++ ); ++ ++INTERNAL int ++VmbusSetEvent( ++ UINT32 childRelId ++ ); ++ ++INTERNAL VOID ++VmbusOnEvents( ++ VOID ++ ); ++ ++ ++#endif // _VMBUS_PRIVATE_H_ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-network-driver-to-the-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-network-driver-to-the-build.patch new file mode 100644 index 000000000..2048a6324 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-network-driver-to-the-build.patch @@ -0,0 +1,43 @@ +From foo@baz Tue Jul 14 11:01:18 PDT 2009 +Date: Tue, 14 Jul 2009 11:01:18 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: add the Hyper-V virtual network driver to the build + +From: Greg Kroah-Hartman + +Add the Hyper-V virtual network driver to the kernel build system. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/Kconfig | 7 +++++++ + drivers/staging/hv/Makefile | 2 ++ + 2 files changed, 9 insertions(+) + +--- a/drivers/staging/hv/Kconfig ++++ b/drivers/staging/hv/Kconfig +@@ -19,3 +19,10 @@ config HYPERV_BLOCK + default n + help + Select this option to enable the Hyper-V virtual block driver. ++ ++config HYPERV_NET ++ tristate "Microsoft Hyper-V virtual network driver" ++ depends on HYPERV && NET ++ default n ++ help ++ Select this option to enable the Hyper-V virtual network driver. +--- a/drivers/staging/hv/Makefile ++++ b/drivers/staging/hv/Makefile +@@ -1,7 +1,9 @@ + obj-$(CONFIG_HYPERV) += hv_vmbus.o + obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o + obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o ++obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o + + hv_vmbus-objs := vmbus_drv.o osd.o Sources.o + hv_storvsc-objs := storvsc_drv.o osd.o StorVsc.o + hv_blkvsc-objs := blkvsc_drv.o osd.o BlkVsc.o ++hv_netvsc-objs := netvsc_drv.o osd.o NetVsc.o RndisFilter.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-network-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-network-driver.patch new file mode 100644 index 000000000..7c49cd1aa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-network-driver.patch @@ -0,0 +1,3569 @@ +From fec8755b6193c93a935423fdd6026b354aa2e15e Mon Sep 17 00:00:00 2001 +From: Hank Janssen +Date: Mon, 13 Jul 2009 15:34:54 -0700 +Subject: Staging: hv: add the Hyper-V virtual network driver + +From: Hank Janssen + +This is the virtual network driver when running Linux on top of Hyper-V. + +Signed-off-by: Hank Janssen +Signed-off-by: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/hv/NetVsc.c | 1499 +++++++++++++++++++++++++++++++++++++++ + drivers/staging/hv/NetVsc.h | 91 ++ + drivers/staging/hv/RndisFilter.c | 1162 ++++++++++++++++++++++++++++++ + drivers/staging/hv/RndisFilter.h | 61 + + drivers/staging/hv/netvsc_drv.c | 720 ++++++++++++++++++ + 5 files changed, 3533 insertions(+) + create mode 100644 drivers/staging/hv/netvsc.c + +--- /dev/null ++++ b/drivers/staging/hv/NetVsc.c +@@ -0,0 +1,1499 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++#include "NetVsc.h" ++#include "RndisFilter.h" ++ ++ ++// ++// Globals ++// ++static const char* gDriverName="netvsc"; ++ ++// {F8615163-DF3E-46c5-913F-F2D2F965ED0E} ++static const GUID gNetVscDeviceType={ ++ .Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} ++}; ++ ++ ++// ++// Internal routines ++// ++static int ++NetVscOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ); ++ ++static int ++NetVscOnDeviceRemove( ++ DEVICE_OBJECT *Device ++ ); ++ ++static void ++NetVscOnCleanup( ++ DRIVER_OBJECT *Driver ++ ); ++ ++static void ++NetVscOnChannelCallback( ++ PVOID context ++ ); ++ ++static int ++NetVscInitializeSendBufferWithNetVsp( ++ DEVICE_OBJECT *Device ++ ); ++ ++static int ++NetVscInitializeReceiveBufferWithNetVsp( ++ DEVICE_OBJECT *Device ++ ); ++ ++static int ++NetVscDestroySendBuffer( ++ NETVSC_DEVICE *NetDevice ++ ); ++ ++static int ++NetVscDestroyReceiveBuffer( ++ NETVSC_DEVICE *NetDevice ++ ); ++ ++static int ++NetVscConnectToVsp( ++ DEVICE_OBJECT *Device ++ ); ++ ++static void ++NetVscOnSendCompletion( ++ DEVICE_OBJECT *Device, ++ VMPACKET_DESCRIPTOR *Packet ++ ); ++ ++static int ++NetVscOnSend( ++ DEVICE_OBJECT *Device, ++ NETVSC_PACKET *Packet ++ ); ++ ++static void ++NetVscOnReceive( ++ DEVICE_OBJECT *Device, ++ VMPACKET_DESCRIPTOR *Packet ++ ); ++ ++static void ++NetVscOnReceiveCompletion( ++ PVOID Context ++ ); ++ ++static void ++NetVscSendReceiveCompletion( ++ DEVICE_OBJECT *Device, ++ UINT64 TransactionId ++ ); ++ ++static inline NETVSC_DEVICE* AllocNetDevice(DEVICE_OBJECT *Device) ++{ ++ NETVSC_DEVICE *netDevice; ++ ++ netDevice = MemAllocZeroed(sizeof(NETVSC_DEVICE)); ++ if (!netDevice) ++ return NULL; ++ ++ // Set to 2 to allow both inbound and outbound traffic ++ InterlockedCompareExchange(&netDevice->RefCount, 2, 0); ++ ++ netDevice->Device = Device; ++ Device->Extension = netDevice; ++ ++ return netDevice; ++} ++ ++static inline void FreeNetDevice(NETVSC_DEVICE *Device) ++{ ++ ASSERT(Device->RefCount == 0); ++ Device->Device->Extension = NULL; ++ MemFree(Device); ++} ++ ++ ++// Get the net device object iff exists and its refcount > 1 ++static inline NETVSC_DEVICE* GetOutboundNetDevice(DEVICE_OBJECT *Device) ++{ ++ NETVSC_DEVICE *netDevice; ++ ++ netDevice = (NETVSC_DEVICE*)Device->Extension; ++ if (netDevice && netDevice->RefCount > 1) ++ { ++ InterlockedIncrement(&netDevice->RefCount); ++ } ++ else ++ { ++ netDevice = NULL; ++ } ++ ++ return netDevice; ++} ++ ++// Get the net device object iff exists and its refcount > 0 ++static inline NETVSC_DEVICE* GetInboundNetDevice(DEVICE_OBJECT *Device) ++{ ++ NETVSC_DEVICE *netDevice; ++ ++ netDevice = (NETVSC_DEVICE*)Device->Extension; ++ if (netDevice && netDevice->RefCount) ++ { ++ InterlockedIncrement(&netDevice->RefCount); ++ } ++ else ++ { ++ netDevice = NULL; ++ } ++ ++ return netDevice; ++} ++ ++static inline void PutNetDevice(DEVICE_OBJECT *Device) ++{ ++ NETVSC_DEVICE *netDevice; ++ ++ netDevice = (NETVSC_DEVICE*)Device->Extension; ++ ASSERT(netDevice); ++ ++ InterlockedDecrement(&netDevice->RefCount); ++} ++ ++static inline NETVSC_DEVICE* ReleaseOutboundNetDevice(DEVICE_OBJECT *Device) ++{ ++ NETVSC_DEVICE *netDevice; ++ ++ netDevice = (NETVSC_DEVICE*)Device->Extension; ++ if (netDevice == NULL) ++ return NULL; ++ ++ // Busy wait until the ref drop to 2, then set it to 1 ++ while (InterlockedCompareExchange(&netDevice->RefCount, 1, 2) != 2) ++ { ++ Sleep(100); ++ } ++ ++ return netDevice; ++} ++ ++static inline NETVSC_DEVICE* ReleaseInboundNetDevice(DEVICE_OBJECT *Device) ++{ ++ NETVSC_DEVICE *netDevice; ++ ++ netDevice = (NETVSC_DEVICE*)Device->Extension; ++ if (netDevice == NULL) ++ return NULL; ++ ++ // Busy wait until the ref drop to 1, then set it to 0 ++ while (InterlockedCompareExchange(&netDevice->RefCount, 0, 1) != 1) ++ { ++ Sleep(100); ++ } ++ ++ Device->Extension = NULL; ++ return netDevice; ++} ++ ++/*++; ++ ++ ++Name: ++ NetVscInitialize() ++ ++Description: ++ Main entry point ++ ++--*/ ++int ++NetVscInitialize( ++ DRIVER_OBJECT *drv ++ ) ++{ ++ NETVSC_DRIVER_OBJECT* driver = (NETVSC_DRIVER_OBJECT*)drv; ++ int ret=0; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ DPRINT_DBG(NETVSC, "sizeof(NETVSC_PACKET)=%d, sizeof(NVSP_MESSAGE)=%d, sizeof(VMTRANSFER_PAGE_PACKET_HEADER)=%d", ++ sizeof(NETVSC_PACKET), sizeof(NVSP_MESSAGE), sizeof(VMTRANSFER_PAGE_PACKET_HEADER)); ++ ++ // Make sure we are at least 2 pages since 1 page is used for control ++ ASSERT(driver->RingBufferSize >= (PAGE_SIZE << 1)); ++ ++ drv->name = gDriverName; ++ memcpy(&drv->deviceType, &gNetVscDeviceType, sizeof(GUID)); ++ ++ // Make sure it is set by the caller ++ ASSERT(driver->OnReceiveCallback); ++ ASSERT(driver->OnLinkStatusChanged); ++ ++ // Setup the dispatch table ++ driver->Base.OnDeviceAdd = NetVscOnDeviceAdd; ++ driver->Base.OnDeviceRemove = NetVscOnDeviceRemove; ++ driver->Base.OnCleanup = NetVscOnCleanup; ++ ++ driver->OnSend = NetVscOnSend; ++ ++ RndisFilterInit(driver); ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++static int ++NetVscInitializeReceiveBufferWithNetVsp( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret=0; ++ NETVSC_DEVICE *netDevice; ++ NVSP_MESSAGE *initPacket; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = GetOutboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ ASSERT(netDevice->ReceiveBufferSize > 0); ++ ASSERT((netDevice->ReceiveBufferSize & (PAGE_SIZE-1)) == 0); // page-size grandularity ++ ++ netDevice->ReceiveBuffer = PageAlloc(netDevice->ReceiveBufferSize >> PAGE_SHIFT); ++ if (!netDevice->ReceiveBuffer) ++ { ++ DPRINT_ERR(NETVSC, "unable to allocate receive buffer of size %d", netDevice->ReceiveBufferSize); ++ ret = -1; ++ goto Cleanup; ++ } ++ ASSERT(((ULONG_PTR)netDevice->ReceiveBuffer & (PAGE_SIZE-1)) == 0); // page-aligned buffer ++ ++ DPRINT_INFO(NETVSC, "Establishing receive buffer's GPADL..."); ++ ++ // Establish the gpadl handle for this buffer on this channel. ++ // Note: This call uses the vmbus connection rather than the channel to establish ++ // the gpadl handle. ++ ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device, ++ netDevice->ReceiveBuffer, ++ netDevice->ReceiveBufferSize, ++ &netDevice->ReceiveBufferGpadlHandle); ++ ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to establish receive buffer's gpadl"); ++ goto Cleanup; ++ } ++ ++ //WaitEventWait(ext->ChannelInitEvent); ++ ++ // Notify the NetVsp of the gpadl handle ++ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendReceiveBuffer..."); ++ ++ initPacket = &netDevice->ChannelInitPacket; ++ ++ memset(initPacket, 0, sizeof(NVSP_MESSAGE)); ++ ++ initPacket->Header.MessageType = NvspMessage1TypeSendReceiveBuffer; ++ initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->ReceiveBufferGpadlHandle; ++ initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; ++ ++ // Send the gpadl notification request ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ initPacket, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)initPacket, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to send receive buffer's gpadl to netvsp"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(netDevice->ChannelInitEvent); ++ ++ // Check the response ++ if (initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status != NvspStatusSuccess) ++ { ++ DPRINT_ERR(NETVSC, ++ "Unable to complete receive buffer initialzation with NetVsp - status %d", ++ initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Status); ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Parse the response ++ ASSERT(netDevice->ReceiveSectionCount == 0); ++ ASSERT(netDevice->ReceiveSections == NULL); ++ ++ netDevice->ReceiveSectionCount = initPacket->Messages.Version1Messages.SendReceiveBufferComplete.NumSections; ++ ++ netDevice->ReceiveSections = MemAlloc(netDevice->ReceiveSectionCount * sizeof(NVSP_1_RECEIVE_BUFFER_SECTION)); ++ if (netDevice->ReceiveSections == NULL) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ memcpy(netDevice->ReceiveSections, ++ initPacket->Messages.Version1Messages.SendReceiveBufferComplete.Sections, ++ netDevice->ReceiveSectionCount * sizeof(NVSP_1_RECEIVE_BUFFER_SECTION)); ++ ++ DPRINT_INFO(NETVSC, ++ "Receive sections info (count %d, offset %d, endoffset %d, suballoc size %d, num suballocs %d)", ++ netDevice->ReceiveSectionCount, netDevice->ReceiveSections[0].Offset, netDevice->ReceiveSections[0].EndOffset, ++ netDevice->ReceiveSections[0].SubAllocationSize, netDevice->ReceiveSections[0].NumSubAllocations); ++ ++ ++ //For 1st release, there should only be 1 section that represents the entire receive buffer ++ if (netDevice->ReceiveSectionCount != 1 || ++ netDevice->ReceiveSections->Offset != 0 ) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ goto Exit; ++ ++Cleanup: ++ NetVscDestroyReceiveBuffer(netDevice); ++ ++Exit: ++ PutNetDevice(Device); ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++ ++static int ++NetVscInitializeSendBufferWithNetVsp( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret=0; ++ NETVSC_DEVICE *netDevice; ++ NVSP_MESSAGE *initPacket; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = GetOutboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ ASSERT(netDevice->SendBufferSize > 0); ++ ASSERT((netDevice->SendBufferSize & (PAGE_SIZE-1)) == 0); // page-size grandularity ++ ++ netDevice->SendBuffer = PageAlloc(netDevice->SendBufferSize >> PAGE_SHIFT); ++ if (!netDevice->SendBuffer) ++ { ++ DPRINT_ERR(NETVSC, "unable to allocate send buffer of size %d", netDevice->SendBufferSize); ++ ret = -1; ++ goto Cleanup; ++ } ++ ASSERT(((ULONG_PTR)netDevice->SendBuffer & (PAGE_SIZE-1)) == 0); // page-aligned buffer ++ ++ DPRINT_INFO(NETVSC, "Establishing send buffer's GPADL..."); ++ ++ // Establish the gpadl handle for this buffer on this channel. ++ // Note: This call uses the vmbus connection rather than the channel to establish ++ // the gpadl handle. ++ ret = Device->Driver->VmbusChannelInterface.EstablishGpadl(Device, ++ netDevice->SendBuffer, ++ netDevice->SendBufferSize, ++ &netDevice->SendBufferGpadlHandle); ++ ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to establish send buffer's gpadl"); ++ goto Cleanup; ++ } ++ ++ //WaitEventWait(ext->ChannelInitEvent); ++ ++ // Notify the NetVsp of the gpadl handle ++ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendSendBuffer..."); ++ ++ initPacket = &netDevice->ChannelInitPacket; ++ ++ memset(initPacket, 0, sizeof(NVSP_MESSAGE)); ++ ++ initPacket->Header.MessageType = NvspMessage1TypeSendSendBuffer; ++ initPacket->Messages.Version1Messages.SendReceiveBuffer.GpadlHandle = netDevice->SendBufferGpadlHandle; ++ initPacket->Messages.Version1Messages.SendReceiveBuffer.Id = NETVSC_SEND_BUFFER_ID; ++ ++ // Send the gpadl notification request ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ initPacket, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)initPacket, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to send receive buffer's gpadl to netvsp"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(netDevice->ChannelInitEvent); ++ ++ // Check the response ++ if (initPacket->Messages.Version1Messages.SendSendBufferComplete.Status != NvspStatusSuccess) ++ { ++ DPRINT_ERR(NETVSC, ++ "Unable to complete send buffer initialzation with NetVsp - status %d", ++ initPacket->Messages.Version1Messages.SendSendBufferComplete.Status); ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ netDevice->SendSectionSize = initPacket->Messages.Version1Messages.SendSendBufferComplete.SectionSize; ++ ++ goto Exit; ++ ++Cleanup: ++ NetVscDestroySendBuffer(netDevice); ++ ++Exit: ++ PutNetDevice(Device); ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++static int ++NetVscDestroyReceiveBuffer( ++ NETVSC_DEVICE *NetDevice ++ ) ++{ ++ NVSP_MESSAGE *revokePacket; ++ int ret=0; ++ ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // If we got a section count, it means we received a SendReceiveBufferComplete msg ++ // (ie sent NvspMessage1TypeSendReceiveBuffer msg) therefore, we need to send a revoke msg here ++ if (NetDevice->ReceiveSectionCount) ++ { ++ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeReceiveBuffer..."); ++ ++ // Send the revoke receive buffer ++ revokePacket = &NetDevice->RevokePacket; ++ memset(revokePacket, 0, sizeof(NVSP_MESSAGE)); ++ ++ revokePacket->Header.MessageType = NvspMessage1TypeRevokeReceiveBuffer; ++ revokePacket->Messages.Version1Messages.RevokeReceiveBuffer.Id = NETVSC_RECEIVE_BUFFER_ID; ++ ++ ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device, ++ revokePacket, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)revokePacket, ++ VmbusPacketTypeDataInBand, ++ 0); ++ // If we failed here, we might as well return and have a leak rather than continue and a bugchk ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to send revoke receive buffer to netvsp"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ } ++ ++ // Teardown the gpadl on the vsp end ++ if (NetDevice->ReceiveBufferGpadlHandle) ++ { ++ DPRINT_INFO(NETVSC, "Tearing down receive buffer's GPADL..."); ++ ++ ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device, ++ NetDevice->ReceiveBufferGpadlHandle); ++ ++ // If we failed here, we might as well return and have a leak rather than continue and a bugchk ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to teardown receive buffer's gpadl"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ NetDevice->ReceiveBufferGpadlHandle = 0; ++ } ++ ++ if (NetDevice->ReceiveBuffer) ++ { ++ DPRINT_INFO(NETVSC, "Freeing up receive buffer..."); ++ ++ // Free up the receive buffer ++ PageFree(NetDevice->ReceiveBuffer, NetDevice->ReceiveBufferSize >> PAGE_SHIFT); ++ NetDevice->ReceiveBuffer = NULL; ++ } ++ ++ if (NetDevice->ReceiveSections) ++ { ++ MemFree(NetDevice->ReceiveSections); ++ NetDevice->ReceiveSections = NULL; ++ NetDevice->ReceiveSectionCount = 0; ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++ ++ ++ ++static int ++NetVscDestroySendBuffer( ++ NETVSC_DEVICE *NetDevice ++ ) ++{ ++ NVSP_MESSAGE *revokePacket; ++ int ret=0; ++ ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // If we got a section count, it means we received a SendReceiveBufferComplete msg ++ // (ie sent NvspMessage1TypeSendReceiveBuffer msg) therefore, we need to send a revoke msg here ++ if (NetDevice->SendSectionSize) ++ { ++ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeRevokeSendBuffer..."); ++ ++ // Send the revoke send buffer ++ revokePacket = &NetDevice->RevokePacket; ++ memset(revokePacket, 0, sizeof(NVSP_MESSAGE)); ++ ++ revokePacket->Header.MessageType = NvspMessage1TypeRevokeSendBuffer; ++ revokePacket->Messages.Version1Messages.RevokeSendBuffer.Id = NETVSC_SEND_BUFFER_ID; ++ ++ ret = NetDevice->Device->Driver->VmbusChannelInterface.SendPacket(NetDevice->Device, ++ revokePacket, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)revokePacket, ++ VmbusPacketTypeDataInBand, ++ 0); ++ // If we failed here, we might as well return and have a leak rather than continue and a bugchk ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to send revoke send buffer to netvsp"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ } ++ ++ // Teardown the gpadl on the vsp end ++ if (NetDevice->SendBufferGpadlHandle) ++ { ++ DPRINT_INFO(NETVSC, "Tearing down send buffer's GPADL..."); ++ ++ ret = NetDevice->Device->Driver->VmbusChannelInterface.TeardownGpadl(NetDevice->Device, ++ NetDevice->SendBufferGpadlHandle); ++ ++ // If we failed here, we might as well return and have a leak rather than continue and a bugchk ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to teardown send buffer's gpadl"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ NetDevice->SendBufferGpadlHandle = 0; ++ } ++ ++ if (NetDevice->SendBuffer) ++ { ++ DPRINT_INFO(NETVSC, "Freeing up send buffer..."); ++ ++ // Free up the receive buffer ++ PageFree(NetDevice->SendBuffer, NetDevice->SendBufferSize >> PAGE_SHIFT); ++ NetDevice->SendBuffer = NULL; ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++ ++ ++static int ++NetVscConnectToVsp( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret=0; ++ NETVSC_DEVICE *netDevice; ++ NVSP_MESSAGE *initPacket; ++ int ndisVersion; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = GetOutboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ ++ initPacket = &netDevice->ChannelInitPacket; ++ ++ memset(initPacket, 0, sizeof(NVSP_MESSAGE)); ++ initPacket->Header.MessageType = NvspMessageTypeInit; ++ initPacket->Messages.InitMessages.Init.MinProtocolVersion = NVSP_MIN_PROTOCOL_VERSION; ++ initPacket->Messages.InitMessages.Init.MaxProtocolVersion = NVSP_MAX_PROTOCOL_VERSION; ++ ++ DPRINT_INFO(NETVSC, "Sending NvspMessageTypeInit..."); ++ ++ // Send the init request ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ initPacket, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)initPacket, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ ++ if( ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to send NvspMessageTypeInit"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(netDevice->ChannelInitEvent); ++ ++ // Now, check the response ++ //ASSERT(initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength <= MAX_MULTIPAGE_BUFFER_COUNT); ++ DPRINT_INFO(NETVSC, "NvspMessageTypeInit status(%d) max mdl chain (%d)", ++ initPacket->Messages.InitMessages.InitComplete.Status, ++ initPacket->Messages.InitMessages.InitComplete.MaximumMdlChainLength); ++ ++ if (initPacket->Messages.InitMessages.InitComplete.Status != NvspStatusSuccess) ++ { ++ DPRINT_ERR(NETVSC, "unable to initialize with netvsp (status 0x%x)", initPacket->Messages.InitMessages.InitComplete.Status); ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ if (initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion != NVSP_PROTOCOL_VERSION_1) ++ { ++ DPRINT_ERR(NETVSC, "unable to initialize with netvsp (version expected 1 got %d)", ++ initPacket->Messages.InitMessages.InitComplete.NegotiatedProtocolVersion); ++ ret = -1; ++ goto Cleanup; ++ } ++ DPRINT_INFO(NETVSC, "Sending NvspMessage1TypeSendNdisVersion..."); ++ ++ // Send the ndis version ++ memset(initPacket, 0, sizeof(NVSP_MESSAGE)); ++ ++ ndisVersion = 0x00050000; ++ ++ initPacket->Header.MessageType = NvspMessage1TypeSendNdisVersion; ++ initPacket->Messages.Version1Messages.SendNdisVersion.NdisMajorVersion = (ndisVersion & 0xFFFF0000) >> 16; ++ initPacket->Messages.Version1Messages.SendNdisVersion.NdisMinorVersion = ndisVersion & 0xFFFF; ++ ++ // Send the init request ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ initPacket, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)initPacket, ++ VmbusPacketTypeDataInBand, ++ 0); ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to send NvspMessage1TypeSendNdisVersion"); ++ ret = -1; ++ goto Cleanup; ++ } ++ // ++ // BUGBUG - We have to wait for the above msg since the netvsp uses KMCL which acknowledges packet (completion packet) ++ // since our Vmbus always set the VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag ++ //WaitEventWait(NetVscChannel->ChannelInitEvent); ++ ++ // Post the big receive buffer to NetVSP ++ ret = NetVscInitializeReceiveBufferWithNetVsp(Device); ++ if (ret == 0) ++ { ++ ret = NetVscInitializeSendBufferWithNetVsp(Device); ++ } ++ ++Cleanup: ++ PutNetDevice(Device); ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++static void ++NetVscDisconnectFromVsp( ++ NETVSC_DEVICE *NetDevice ++ ) ++{ ++ DPRINT_ENTER(NETVSC); ++ ++ NetVscDestroyReceiveBuffer(NetDevice); ++ NetVscDestroySendBuffer(NetDevice); ++ ++ DPRINT_EXIT(NETVSC); ++} ++ ++ ++/*++ ++ ++Name: ++ NetVscOnDeviceAdd() ++ ++Description: ++ Callback when the device belonging to this driver is added ++ ++--*/ ++int ++NetVscOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ) ++{ ++ int ret=0; ++ int i; ++ ++ NETVSC_DEVICE* netDevice; ++ NETVSC_PACKET* packet; ++ LIST_ENTRY *entry; ++ ++ NETVSC_DRIVER_OBJECT *netDriver = (NETVSC_DRIVER_OBJECT*) Device->Driver;; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = AllocNetDevice(Device); ++ if (!netDevice) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ DPRINT_DBG(NETVSC, "netvsc channel object allocated - %p", netDevice); ++ ++ // Initialize the NetVSC channel extension ++ netDevice->ReceiveBufferSize = NETVSC_RECEIVE_BUFFER_SIZE; ++ netDevice->ReceivePacketListLock = SpinlockCreate(); ++ ++ netDevice->SendBufferSize = NETVSC_SEND_BUFFER_SIZE; ++ ++ INITIALIZE_LIST_HEAD(&netDevice->ReceivePacketList); ++ ++ for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) ++ { ++ packet = MemAllocZeroed(sizeof(NETVSC_PACKET) + (NETVSC_RECEIVE_SG_COUNT* sizeof(PAGE_BUFFER))); ++ if (!packet) ++ { ++ DPRINT_DBG(NETVSC, "unable to allocate netvsc pkts for receive pool (wanted %d got %d)", NETVSC_RECEIVE_PACKETLIST_COUNT, i); ++ break; ++ } ++ ++ INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->ListEntry); ++ } ++ netDevice->ChannelInitEvent = WaitEventCreate(); ++ ++ // Open the channel ++ ret = Device->Driver->VmbusChannelInterface.Open(Device, ++ netDriver->RingBufferSize, ++ netDriver->RingBufferSize, ++ NULL, 0, ++ NetVscOnChannelCallback, ++ Device ++ ); ++ ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to open channel: %d", ret); ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Channel is opened ++ DPRINT_INFO(NETVSC, "*** NetVSC channel opened successfully! ***"); ++ ++ // Connect with the NetVsp ++ ret = NetVscConnectToVsp(Device); ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "unable to connect to NetVSP - %d", ret); ++ ret = -1; ++ goto Close; ++ } ++ ++ DPRINT_INFO(NETVSC, "*** NetVSC channel handshake result - %d ***", ret); ++ ++ DPRINT_EXIT(NETVSC); ++ return ret; ++ ++Close: ++ // Now, we can close the channel safely ++ Device->Driver->VmbusChannelInterface.Close(Device); ++ ++Cleanup: ++ ++ if (netDevice) ++ { ++ WaitEventClose(netDevice->ChannelInitEvent); ++ ++ while (!IsListEmpty(&netDevice->ReceivePacketList)) ++ { ++ entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList); ++ packet = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); ++ MemFree(packet); ++ } ++ ++ SpinlockClose(netDevice->ReceivePacketListLock); ++ ++ ReleaseOutboundNetDevice(Device); ++ ReleaseInboundNetDevice(Device); ++ ++ FreeNetDevice(netDevice); ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ NetVscOnDeviceRemove() ++ ++Description: ++ Callback when the root bus device is removed ++ ++--*/ ++int ++NetVscOnDeviceRemove( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ NETVSC_DEVICE *netDevice; ++ NETVSC_PACKET *netvscPacket; ++ int ret=0; ++ LIST_ENTRY *entry; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ DPRINT_INFO(NETVSC, "Disabling outbound traffic on net device (%p)...", Device->Extension); ++ ++ // Stop outbound traffic ie sends and receives completions ++ netDevice = ReleaseOutboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "No net device present!!"); ++ return -1; ++ } ++ ++ // Wait for all send completions ++ while (netDevice->NumOutstandingSends) ++ { ++ DPRINT_INFO(NETVSC, "waiting for %d requests to complete...", netDevice->NumOutstandingSends); ++ ++ Sleep(100); ++ } ++ ++ DPRINT_INFO(NETVSC, "Disconnecting from netvsp..."); ++ ++ NetVscDisconnectFromVsp(netDevice); ++ ++ DPRINT_INFO(NETVSC, "Disabling inbound traffic on net device (%p)...", Device->Extension); ++ ++ // Stop inbound traffic ie receives and sends completions ++ netDevice = ReleaseInboundNetDevice(Device); ++ ++ // At this point, no one should be accessing netDevice except in here ++ DPRINT_INFO(NETVSC, "net device (%p) safe to remove", netDevice); ++ ++ // Now, we can close the channel safely ++ Device->Driver->VmbusChannelInterface.Close(Device); ++ ++ // Release all resources ++ while (!IsListEmpty(&netDevice->ReceivePacketList)) ++ { ++ entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList); ++ netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); ++ ++ MemFree(netvscPacket); ++ } ++ ++ SpinlockClose(netDevice->ReceivePacketListLock); ++ WaitEventClose(netDevice->ChannelInitEvent); ++ FreeNetDevice(netDevice); ++ ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++ ++ ++/*++ ++ ++Name: ++ NetVscOnCleanup() ++ ++Description: ++ Perform any cleanup when the driver is removed ++ ++--*/ ++void ++NetVscOnCleanup( ++ DRIVER_OBJECT *drv ++ ) ++{ ++ DPRINT_ENTER(NETVSC); ++ ++ DPRINT_EXIT(NETVSC); ++} ++ ++static void ++NetVscOnSendCompletion( ++ DEVICE_OBJECT *Device, ++ VMPACKET_DESCRIPTOR *Packet ++ ) ++{ ++ NETVSC_DEVICE* netDevice; ++ NVSP_MESSAGE *nvspPacket; ++ NETVSC_PACKET *nvscPacket; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = GetInboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); ++ DPRINT_EXIT(NETVSC); ++ return; ++ } ++ ++ nvspPacket = (NVSP_MESSAGE*)((ULONG_PTR)Packet + (Packet->DataOffset8 << 3)); ++ ++ DPRINT_DBG(NETVSC, "send completion packet - type %d", nvspPacket->Header.MessageType); ++ ++ if (nvspPacket->Header.MessageType == NvspMessageTypeInitComplete || ++ nvspPacket->Header.MessageType == NvspMessage1TypeSendReceiveBufferComplete || ++ nvspPacket->Header.MessageType == NvspMessage1TypeSendSendBufferComplete) ++ { ++ // Copy the response back ++ memcpy(&netDevice->ChannelInitPacket, nvspPacket, sizeof(NVSP_MESSAGE)); ++ WaitEventSet(netDevice->ChannelInitEvent); ++ } ++ else if (nvspPacket->Header.MessageType == NvspMessage1TypeSendRNDISPacketComplete) ++ { ++ // Get the send context ++ nvscPacket = (NETVSC_PACKET *)(ULONG_PTR)Packet->TransactionId; ++ ASSERT(nvscPacket); ++ ++ // Notify the layer above us ++ nvscPacket->Completion.Send.OnSendCompletion(nvscPacket->Completion.Send.SendCompletionContext); ++ ++ InterlockedDecrement(&netDevice->NumOutstandingSends); ++ } ++ else ++ { ++ DPRINT_ERR(NETVSC, "Unknown send completion packet type - %d received!!", nvspPacket->Header.MessageType); ++ } ++ ++ PutNetDevice(Device); ++ DPRINT_EXIT(NETVSC); ++} ++ ++ ++ ++static int ++NetVscOnSend( ++ DEVICE_OBJECT *Device, ++ NETVSC_PACKET *Packet ++ ) ++{ ++ NETVSC_DEVICE* netDevice; ++ int ret=0; ++ ++ NVSP_MESSAGE sendMessage; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = GetOutboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "net device (%p) shutting down...ignoring outbound packets", netDevice); ++ DPRINT_EXIT(NETVSC); ++ return -2; ++ } ++ ++ sendMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacket; ++ if (Packet->IsDataPacket) ++ sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 0;// 0 is RMC_DATA; ++ else ++ sendMessage.Messages.Version1Messages.SendRNDISPacket.ChannelType = 1;// 1 is RMC_CONTROL; ++ ++ // Not using send buffer section ++ sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionIndex = 0xFFFFFFFF; ++ sendMessage.Messages.Version1Messages.SendRNDISPacket.SendBufferSectionSize = 0; ++ ++ if (Packet->PageBufferCount) ++ { ++ ret = Device->Driver->VmbusChannelInterface.SendPacketPageBuffer(Device, ++ Packet->PageBuffers, ++ Packet->PageBufferCount, ++ &sendMessage, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)Packet); ++ } ++ else ++ { ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ &sendMessage, ++ sizeof(NVSP_MESSAGE), ++ (ULONG_PTR)Packet, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ ++ } ++ ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC, "Unable to send packet %p ret %d", Packet, ret); ++ } ++ ++ InterlockedIncrement(&netDevice->NumOutstandingSends); ++ PutNetDevice(Device); ++ ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++ ++static void ++NetVscOnReceive( ++ DEVICE_OBJECT *Device, ++ VMPACKET_DESCRIPTOR *Packet ++ ) ++{ ++ NETVSC_DEVICE* netDevice; ++ VMTRANSFER_PAGE_PACKET_HEADER *vmxferpagePacket; ++ NVSP_MESSAGE *nvspPacket; ++ NETVSC_PACKET *netvscPacket=NULL; ++ LIST_ENTRY* entry; ++ ULONG_PTR start; ++ ULONG_PTR end, endVirtual; ++ //NETVSC_DRIVER_OBJECT *netvscDriver; ++ XFERPAGE_PACKET *xferpagePacket=NULL; ++ LIST_ENTRY listHead; ++ ++ int i=0, j=0; ++ int count=0, bytesRemain=0; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ netDevice = GetInboundNetDevice(Device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); ++ DPRINT_EXIT(NETVSC); ++ return; ++ } ++ ++ // All inbound packets other than send completion should be xfer page packet ++ if (Packet->Type != VmbusPacketTypeDataUsingTransferPages) ++ { ++ DPRINT_ERR(NETVSC, "Unknown packet type received - %d", Packet->Type); ++ PutNetDevice(Device); ++ return; ++ } ++ ++ nvspPacket = (NVSP_MESSAGE*)((ULONG_PTR)Packet + (Packet->DataOffset8 << 3)); ++ ++ // Make sure this is a valid nvsp packet ++ if (nvspPacket->Header.MessageType != NvspMessage1TypeSendRNDISPacket ) ++ { ++ DPRINT_ERR(NETVSC, "Unknown nvsp packet type received - %d", nvspPacket->Header.MessageType); ++ PutNetDevice(Device); ++ return; ++ } ++ ++ DPRINT_DBG(NETVSC, "NVSP packet received - type %d", nvspPacket->Header.MessageType); ++ ++ vmxferpagePacket = (VMTRANSFER_PAGE_PACKET_HEADER*)Packet; ++ ++ if (vmxferpagePacket->TransferPageSetId != NETVSC_RECEIVE_BUFFER_ID) ++ { ++ DPRINT_ERR(NETVSC, "Invalid xfer page set id - expecting %x got %x", NETVSC_RECEIVE_BUFFER_ID, vmxferpagePacket->TransferPageSetId); ++ PutNetDevice(Device); ++ return; ++ } ++ ++ DPRINT_DBG(NETVSC, "xfer page - range count %d", vmxferpagePacket->RangeCount); ++ ++ INITIALIZE_LIST_HEAD(&listHead); ++ ++ // Grab free packets (range count + 1) to represent this xfer page packet. +1 to represent ++ // the xfer page packet itself. We grab it here so that we know exactly how many we can fulfil ++ SpinlockAcquire(netDevice->ReceivePacketListLock); ++ while (!IsListEmpty(&netDevice->ReceivePacketList)) ++ { ++ entry = REMOVE_HEAD_LIST(&netDevice->ReceivePacketList); ++ netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); ++ ++ INSERT_TAIL_LIST(&listHead, &netvscPacket->ListEntry); ++ ++ if (++count == vmxferpagePacket->RangeCount + 1) ++ break; ++ } ++ SpinlockRelease(netDevice->ReceivePacketListLock); ++ ++ // We need at least 2 netvsc pkts (1 to represent the xfer page and at least 1 for the range) ++ // i.e. we can handled some of the xfer page packet ranges... ++ if (count < 2) ++ { ++ DPRINT_ERR(NETVSC, "Got only %d netvsc pkt...needed %d pkts. Dropping this xfer page packet completely!", count, vmxferpagePacket->RangeCount+1); ++ ++ // Return it to the freelist ++ SpinlockAcquire(netDevice->ReceivePacketListLock); ++ for (i=count; i != 0; i--) ++ { ++ entry = REMOVE_HEAD_LIST(&listHead); ++ netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); ++ ++ INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &netvscPacket->ListEntry); ++ } ++ SpinlockRelease(netDevice->ReceivePacketListLock); ++ ++ NetVscSendReceiveCompletion(Device, vmxferpagePacket->d.TransactionId); ++ ++ PutNetDevice(Device); ++ return; ++ } ++ ++ // Remove the 1st packet to represent the xfer page packet itself ++ entry = REMOVE_HEAD_LIST(&listHead); ++ xferpagePacket = CONTAINING_RECORD(entry, XFERPAGE_PACKET, ListEntry); ++ xferpagePacket->Count = count - 1; // This is how much we can satisfy ++ ASSERT(xferpagePacket->Count > 0 && xferpagePacket->Count <= vmxferpagePacket->RangeCount); ++ ++ if (xferpagePacket->Count != vmxferpagePacket->RangeCount) ++ { ++ DPRINT_INFO(NETVSC, "Needed %d netvsc pkts to satisy this xfer page...got %d", vmxferpagePacket->RangeCount, xferpagePacket->Count); ++ } ++ ++ // Each range represents 1 RNDIS pkt that contains 1 ethernet frame ++ for (i=0; i < (count - 1); i++) ++ { ++ entry = REMOVE_HEAD_LIST(&listHead); ++ netvscPacket = CONTAINING_RECORD(entry, NETVSC_PACKET, ListEntry); ++ ++ // Initialize the netvsc packet ++ netvscPacket->XferPagePacket = xferpagePacket; ++ netvscPacket->Completion.Recv.OnReceiveCompletion = NetVscOnReceiveCompletion; ++ netvscPacket->Completion.Recv.ReceiveCompletionContext = netvscPacket; ++ netvscPacket->Device = Device; ++ netvscPacket->Completion.Recv.ReceiveCompletionTid = vmxferpagePacket->d.TransactionId; // Save this so that we can send it back ++ ++ netvscPacket->TotalDataBufferLength = vmxferpagePacket->Ranges[i].ByteCount; ++ netvscPacket->PageBufferCount = 1; ++ ++ ASSERT(vmxferpagePacket->Ranges[i].ByteOffset + vmxferpagePacket->Ranges[i].ByteCount < netDevice->ReceiveBufferSize); ++ ++ netvscPacket->PageBuffers[0].Length = vmxferpagePacket->Ranges[i].ByteCount; ++ ++ start = GetPhysicalAddress((void*)((ULONG_PTR)netDevice->ReceiveBuffer + vmxferpagePacket->Ranges[i].ByteOffset)); ++ ++ netvscPacket->PageBuffers[0].Pfn = start >> PAGE_SHIFT; ++ endVirtual = (ULONG_PTR)netDevice->ReceiveBuffer ++ + vmxferpagePacket->Ranges[i].ByteOffset ++ + vmxferpagePacket->Ranges[i].ByteCount -1; ++ end = GetPhysicalAddress((void*)endVirtual); ++ ++ // Calculate the page relative offset ++ netvscPacket->PageBuffers[0].Offset = vmxferpagePacket->Ranges[i].ByteOffset & (PAGE_SIZE -1); ++ if ((end >> PAGE_SHIFT) != (start>>PAGE_SHIFT)) { ++ //Handle frame across multiple pages: ++ netvscPacket->PageBuffers[0].Length = ++ (netvscPacket->PageBuffers[0].Pfn <TotalDataBufferLength - netvscPacket->PageBuffers[0].Length; ++ for (j=1; jPageBuffers[j].Offset = 0; ++ if (bytesRemain <= PAGE_SIZE) { ++ netvscPacket->PageBuffers[j].Length = bytesRemain; ++ bytesRemain = 0; ++ } else { ++ netvscPacket->PageBuffers[j].Length = PAGE_SIZE; ++ bytesRemain -= PAGE_SIZE; ++ } ++ netvscPacket->PageBuffers[j].Pfn = ++ GetPhysicalAddress((void*)(endVirtual - bytesRemain)) >> PAGE_SHIFT; ++ netvscPacket->PageBufferCount++; ++ if (bytesRemain == 0) ++ break; ++ } ++ ASSERT(bytesRemain == 0); ++ } ++ DPRINT_DBG(NETVSC, "[%d] - (abs offset %u len %u) => (pfn %llx, offset %u, len %u)", ++ i, ++ vmxferpagePacket->Ranges[i].ByteOffset, ++ vmxferpagePacket->Ranges[i].ByteCount, ++ netvscPacket->PageBuffers[0].Pfn, ++ netvscPacket->PageBuffers[0].Offset, ++ netvscPacket->PageBuffers[0].Length); ++ ++ // Pass it to the upper layer ++ ((NETVSC_DRIVER_OBJECT*)Device->Driver)->OnReceiveCallback(Device, netvscPacket); ++ ++ NetVscOnReceiveCompletion(netvscPacket->Completion.Recv.ReceiveCompletionContext); ++ } ++ ++ ASSERT(IsListEmpty(&listHead)); ++ ++ PutNetDevice(Device); ++ DPRINT_EXIT(NETVSC); ++} ++ ++ ++static void ++NetVscSendReceiveCompletion( ++ DEVICE_OBJECT *Device, ++ UINT64 TransactionId ++ ) ++{ ++ NVSP_MESSAGE recvcompMessage; ++ int retries=0; ++ int ret=0; ++ ++ DPRINT_DBG(NETVSC, "Sending receive completion pkt - %llx", TransactionId); ++ ++ recvcompMessage.Header.MessageType = NvspMessage1TypeSendRNDISPacketComplete; ++ ++ // FIXME: Pass in the status ++ recvcompMessage.Messages.Version1Messages.SendRNDISPacketComplete.Status = NvspStatusSuccess; ++ ++retry_send_cmplt: ++ // Send the completion ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ &recvcompMessage, ++ sizeof(NVSP_MESSAGE), ++ TransactionId, ++ VmbusPacketTypeCompletion, ++ 0); ++ if (ret == 0) // success ++ { ++ // no-op ++ } ++ else if (ret == -1) // no more room...wait a bit and attempt to retry 3 times ++ { ++ retries++; ++ DPRINT_ERR(NETVSC, "unable to send receive completion pkt (tid %llx)...retrying %d", TransactionId, retries); ++ ++ if (retries < 4) ++ { ++ Sleep(100); ++ goto retry_send_cmplt; ++ } ++ else ++ { ++ DPRINT_ERR(NETVSC, "unable to send receive completion pkt (tid %llx)...give up retrying", TransactionId); ++ } ++ } ++ else ++ { ++ DPRINT_ERR(NETVSC, "unable to send receive completion pkt - %llx", TransactionId); ++ } ++} ++ ++// ++// Send a receive completion packet to RNDIS device (ie NetVsp) ++// ++static void ++NetVscOnReceiveCompletion( ++ PVOID Context) ++{ ++ NETVSC_PACKET *packet = (NETVSC_PACKET*)Context; ++ DEVICE_OBJECT *device = (DEVICE_OBJECT*)packet->Device; ++ NETVSC_DEVICE* netDevice; ++ UINT64 transactionId=0; ++ BOOL fSendReceiveComp = FALSE; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(packet->XferPagePacket); ++ ++ // Even though it seems logical to do a GetOutboundNetDevice() here to send out receive completion, ++ // we are using GetInboundNetDevice() since we may have disable outbound traffic already. ++ netDevice = GetInboundNetDevice(device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "unable to get net device...device being destroyed?"); ++ DPRINT_EXIT(NETVSC); ++ return; ++ } ++ ++ // Overloading use of the lock. ++ SpinlockAcquire(netDevice->ReceivePacketListLock); ++ ++ ASSERT(packet->XferPagePacket->Count > 0); ++ packet->XferPagePacket->Count--; ++ ++ // Last one in the line that represent 1 xfer page packet. ++ // Return the xfer page packet itself to the freelist ++ if (packet->XferPagePacket->Count == 0) ++ { ++ fSendReceiveComp = TRUE; ++ transactionId = packet->Completion.Recv.ReceiveCompletionTid; ++ ++ INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->XferPagePacket->ListEntry); ++ } ++ ++ // Put the packet back ++ INSERT_TAIL_LIST(&netDevice->ReceivePacketList, &packet->ListEntry); ++ SpinlockRelease(netDevice->ReceivePacketListLock); ++ ++ // Send a receive completion for the xfer page packet ++ if (fSendReceiveComp) ++ { ++ NetVscSendReceiveCompletion(device, transactionId); ++ } ++ ++ PutNetDevice(device); ++ DPRINT_EXIT(NETVSC); ++} ++ ++ ++ ++void ++NetVscOnChannelCallback( ++ PVOID Context ++ ) ++{ ++ const int netPacketSize=2048; ++ int ret=0; ++ DEVICE_OBJECT *device=(DEVICE_OBJECT*)Context; ++ NETVSC_DEVICE *netDevice; ++ ++ UINT32 bytesRecvd; ++ UINT64 requestId; ++ UCHAR packet[netPacketSize]; ++ VMPACKET_DESCRIPTOR *desc; ++ UCHAR *buffer=packet; ++ int bufferlen=netPacketSize; ++ ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(device); ++ ++ netDevice = GetInboundNetDevice(device); ++ if (!netDevice) ++ { ++ DPRINT_ERR(NETVSC, "net device (%p) shutting down...ignoring inbound packets", netDevice); ++ DPRINT_EXIT(NETVSC); ++ return; ++ } ++ ++ do ++ { ++ ret = device->Driver->VmbusChannelInterface.RecvPacketRaw(device, ++ buffer, ++ bufferlen, ++ &bytesRecvd, ++ &requestId); ++ ++ if (ret == 0) ++ { ++ if (bytesRecvd > 0) ++ { ++ DPRINT_DBG(NETVSC, "receive %d bytes, tid %llx", bytesRecvd, requestId); ++ ++ desc = (VMPACKET_DESCRIPTOR*)buffer; ++ switch (desc->Type) ++ { ++ case VmbusPacketTypeCompletion: ++ NetVscOnSendCompletion(device, desc); ++ break; ++ ++ case VmbusPacketTypeDataUsingTransferPages: ++ NetVscOnReceive(device, desc); ++ break; ++ ++ default: ++ DPRINT_ERR(NETVSC, "unhandled packet type %d, tid %llx len %d\n", desc->Type, requestId, bytesRecvd); ++ break; ++ } ++ ++ // reset ++ if (bufferlen > netPacketSize) ++ { ++ MemFree(buffer); ++ ++ buffer = packet; ++ bufferlen = netPacketSize; ++ } ++ } ++ else ++ { ++ //DPRINT_DBG(NETVSC, "nothing else to read..."); ++ ++ // reset ++ if (bufferlen > netPacketSize) ++ { ++ MemFree(buffer); ++ ++ buffer = packet; ++ bufferlen = netPacketSize; ++ } ++ ++ break; ++ } ++ } ++ else if (ret == -2) // Handle large packet ++ { ++ buffer = MemAllocAtomic(bytesRecvd); ++ if (buffer == NULL) ++ { ++ // Try again next time around ++ DPRINT_ERR(NETVSC, "unable to allocate buffer of size (%d)!!", bytesRecvd); ++ break; ++ } ++ ++ bufferlen = bytesRecvd; ++ } ++ else ++ { ++ ASSERT(0); ++ } ++ } while (1); ++ ++ PutNetDevice(device); ++ DPRINT_EXIT(NETVSC); ++ return; ++} +--- /dev/null ++++ b/drivers/staging/hv/netvsc_drv.c +@@ -0,0 +1,720 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#include ++#else ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "logging.h" ++#include "vmbus.h" ++ ++#include "NetVscApi.h" ++ ++MODULE_LICENSE("GPL"); ++ ++// ++// Static decl ++// ++static int netvsc_probe(struct device *device); ++static int netvsc_remove(struct device *device); ++static int netvsc_open(struct net_device *net); ++static void netvsc_xmit_completion(void *context); ++static int netvsc_start_xmit (struct sk_buff *skb, struct net_device *net); ++static int netvsc_recv_callback(DEVICE_OBJECT *device_obj, NETVSC_PACKET* Packet); ++static int netvsc_close(struct net_device *net); ++static struct net_device_stats *netvsc_get_stats(struct net_device *net); ++static void netvsc_linkstatus_callback(DEVICE_OBJECT *device_obj, unsigned int status); ++ ++// ++// Data types ++// ++struct net_device_context { ++ struct device_context *device_ctx; // point back to our device context ++ struct net_device_stats stats; ++}; ++ ++struct netvsc_driver_context { ++ // !! These must be the first 2 fields !! ++ struct driver_context drv_ctx; ++ NETVSC_DRIVER_OBJECT drv_obj; ++}; ++ ++// ++// Globals ++// ++ ++static int netvsc_ringbuffer_size = NETVSC_DEVICE_RING_BUFFER_SIZE; ++ ++// The one and only one ++static struct netvsc_driver_context g_netvsc_drv; ++ ++// ++// Routines ++// ++ ++/*++ ++ ++Name: netvsc_drv_init() ++ ++Desc: NetVsc driver initialization ++ ++--*/ ++int netvsc_drv_init(PFN_DRIVERINITIALIZE pfn_drv_init) ++{ ++ int ret=0; ++ NETVSC_DRIVER_OBJECT *net_drv_obj=&g_netvsc_drv.drv_obj; ++ struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ vmbus_get_interface(&net_drv_obj->Base.VmbusChannelInterface); ++ ++ net_drv_obj->RingBufferSize = netvsc_ringbuffer_size; ++ net_drv_obj->OnReceiveCallback = netvsc_recv_callback; ++ net_drv_obj->OnLinkStatusChanged = netvsc_linkstatus_callback; ++ ++ // Callback to client driver to complete the initialization ++ pfn_drv_init(&net_drv_obj->Base); ++ ++ drv_ctx->driver.name = net_drv_obj->Base.name; ++ memcpy(&drv_ctx->class_id, &net_drv_obj->Base.deviceType, sizeof(GUID)); ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++ drv_ctx->driver.probe = netvsc_probe; ++ drv_ctx->driver.remove = netvsc_remove; ++#else ++ drv_ctx->probe = netvsc_probe; ++ drv_ctx->remove = netvsc_remove; ++#endif ++ ++ // The driver belongs to vmbus ++ vmbus_child_driver_register(drv_ctx); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: netvsc_get_stats() ++ ++Desc: Get the network stats ++ ++--*/ ++static struct net_device_stats *netvsc_get_stats(struct net_device *net) ++{ ++ struct net_device_context *net_device_ctx = netdev_priv(net); ++ ++ return &net_device_ctx->stats; ++} ++ ++/*++ ++ ++Name: netvsc_set_multicast_list() ++ ++Desc: Set the multicast list ++ ++Remark: No-op here ++--*/ ++static void netvsc_set_multicast_list(UNUSED_VAR(struct net_device *net)) ++{ ++} ++ ++ ++/*++ ++ ++Name: netvsc_probe() ++ ++Desc: Add the specified new device to this driver ++ ++--*/ ++static int netvsc_probe(struct device *device) ++{ ++ int ret=0; ++ ++ struct driver_context *driver_ctx = driver_to_driver_context(device->driver); ++ struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; ++ NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; ++ ++ struct device_context *device_ctx = device_to_device_context(device); ++ DEVICE_OBJECT *device_obj = &device_ctx->device_obj; ++ ++ struct net_device *net = NULL; ++ struct net_device_context *net_device_ctx; ++ NETVSC_DEVICE_INFO device_info; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ if (!net_drv_obj->Base.OnDeviceAdd) ++ { ++ return -1; ++ } ++ ++ net = alloc_netdev(sizeof(struct net_device_context), "seth%d", ether_setup); ++ //net = alloc_etherdev(sizeof(struct net_device_context)); ++ if (!net) ++ { ++ return -1; ++ } ++ ++ // Set initial state ++ netif_carrier_off(net); ++ netif_stop_queue(net); ++ ++ net_device_ctx = netdev_priv(net); ++ net_device_ctx->device_ctx = device_ctx; ++ device->driver_data = net; ++ ++ // Notify the netvsc driver of the new device ++ ret = net_drv_obj->Base.OnDeviceAdd(device_obj, (void*)&device_info); ++ if (ret != 0) ++ { ++ free_netdev(net); ++ device->driver_data = NULL; ++ ++ DPRINT_ERR(NETVSC_DRV, "unable to add netvsc device (ret %d)", ret); ++ return ret; ++ } ++ ++ // If carrier is still off ie we did not get a link status callback, update it if necessary ++ // FIXME: We should use a atomic or test/set instead to avoid getting out of sync with the device's link status ++ if (!netif_carrier_ok(net)) ++ { ++ if (!device_info.LinkState) ++ { ++ netif_carrier_on(net); ++ } ++ } ++ ++ memcpy(net->dev_addr, device_info.MacAddr, ETH_ALEN); ++ ++ net->open = netvsc_open; ++ net->hard_start_xmit = netvsc_start_xmit; ++ net->stop = netvsc_close; ++ net->get_stats = netvsc_get_stats; ++ net->set_multicast_list = netvsc_set_multicast_list; ++ ++#if !defined(KERNEL_2_6_27) ++ SET_MODULE_OWNER(net); ++#endif ++ SET_NETDEV_DEV(net, device); ++ ++ ret = register_netdev(net); ++ if (ret != 0) ++ { ++ // Remove the device and release the resource ++ net_drv_obj->Base.OnDeviceRemove(device_obj); ++ free_netdev(net); ++ } ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return ret; ++} ++ ++static int netvsc_remove(struct device *device) ++{ ++ int ret=0; ++ struct driver_context *driver_ctx = driver_to_driver_context(device->driver); ++ struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; ++ NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; ++ ++ struct device_context *device_ctx = device_to_device_context(device); ++ struct net_device *net = (struct net_device *)device_ctx->device.driver_data; ++ DEVICE_OBJECT *device_obj = &device_ctx->device_obj; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ if (net == NULL) ++ { ++ DPRINT_INFO(NETVSC, "no net device to remove"); ++ DPRINT_EXIT(NETVSC_DRV); ++ return 0; ++ } ++ ++ if (!net_drv_obj->Base.OnDeviceRemove) ++ { ++ DPRINT_EXIT(NETVSC_DRV); ++ return -1; ++ } ++ ++ // Stop outbound asap ++ netif_stop_queue(net); ++ //netif_carrier_off(net); ++ ++ unregister_netdev(net); ++ ++ // Call to the vsc driver to let it know that the device is being removed ++ ret = net_drv_obj->Base.OnDeviceRemove(device_obj); ++ if (ret != 0) ++ { ++ // TODO: ++ DPRINT_ERR(NETVSC, "unable to remove vsc device (ret %d)", ret); ++ } ++ ++ free_netdev(net); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: netvsc_open() ++ ++Desc: Open the specified interface device ++ ++--*/ ++static int netvsc_open(struct net_device *net) ++{ ++ int ret=0; ++ struct net_device_context *net_device_ctx = netdev_priv(net); ++ struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); ++ struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; ++ NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; ++ ++ DEVICE_OBJECT *device_obj = &net_device_ctx->device_ctx->device_obj; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ if (netif_carrier_ok(net)) ++ { ++ memset(&net_device_ctx->stats, 0 , sizeof(struct net_device_stats)); ++ ++ // Open up the device ++ ret = net_drv_obj->OnOpen(device_obj); ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC_DRV, "unable to open device (ret %d).", ret); ++ return ret; ++ } ++ ++ netif_start_queue(net); ++ } ++ else ++ { ++ DPRINT_ERR(NETVSC_DRV, "unable to open device...link is down."); ++ } ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ return ret; ++} ++ ++/*++ ++ ++Name: netvsc_close() ++ ++Desc: Close the specified interface device ++ ++--*/ ++static int netvsc_close(struct net_device *net) ++{ ++ int ret=0; ++ struct net_device_context *net_device_ctx = netdev_priv(net); ++ struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); ++ struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; ++ NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; ++ ++ DEVICE_OBJECT *device_obj = &net_device_ctx->device_ctx->device_obj; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ netif_stop_queue(net); ++ ++ ret = net_drv_obj->OnClose(device_obj); ++ if (ret != 0) ++ { ++ DPRINT_ERR(NETVSC_DRV, "unable to close device (ret %d).", ret); ++ } ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: netvsc_xmit_completion() ++ ++Desc: Send completion processing ++ ++--*/ ++static void netvsc_xmit_completion(void *context) ++{ ++ NETVSC_PACKET *packet = (NETVSC_PACKET *)context; ++ struct sk_buff *skb = (struct sk_buff *)(ULONG_PTR)packet->Completion.Send.SendCompletionTid; ++ struct net_device* net; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ kfree(packet); ++ ++ if (skb) ++ { ++ net = skb->dev; ++ ++ dev_kfree_skb_any(skb); ++ ++ if (netif_queue_stopped(net)) ++ { ++ DPRINT_INFO(NETVSC_DRV, "net device (%p) waking up...", net); ++ ++ netif_wake_queue(net); ++ } ++ } ++ ++ DPRINT_EXIT(NETVSC_DRV); ++} ++ ++/*++ ++ ++Name: netvsc_start_xmit() ++ ++Desc: Start a send ++ ++--*/ ++static int netvsc_start_xmit (struct sk_buff *skb, struct net_device *net) ++{ ++ int ret=0; ++ struct net_device_context *net_device_ctx = netdev_priv(net); ++ struct driver_context *driver_ctx = driver_to_driver_context(net_device_ctx->device_ctx->device.driver); ++ struct netvsc_driver_context *net_drv_ctx = (struct netvsc_driver_context*)driver_ctx; ++ NETVSC_DRIVER_OBJECT *net_drv_obj = &net_drv_ctx->drv_obj; ++ ++ int i=0; ++ NETVSC_PACKET* packet; ++ int num_frags; ++ int retries=0; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ // Support only 1 chain of frags ++ ASSERT(skb_shinfo(skb)->frag_list == NULL); ++ ASSERT(skb->dev == net); ++ ++ DPRINT_DBG(NETVSC_DRV, "xmit packet - len %d data_len %d", skb->len, skb->data_len); ++ ++ // Add 1 for skb->data and any additional ones requested ++ num_frags = skb_shinfo(skb)->nr_frags + 1 + net_drv_obj->AdditionalRequestPageBufferCount; ++ ++ // Allocate a netvsc packet based on # of frags. ++ packet = kzalloc(sizeof(NETVSC_PACKET) + (num_frags * sizeof(PAGE_BUFFER)) + net_drv_obj->RequestExtSize, GFP_ATOMIC); ++ if (!packet) ++ { ++ DPRINT_ERR(NETVSC_DRV, "unable to allocate NETVSC_PACKET"); ++ return -1; ++ } ++ ++ packet->Extension = (void*)(unsigned long)packet + sizeof(NETVSC_PACKET) + (num_frags * sizeof(PAGE_BUFFER)) ; ++ ++ // Setup the rndis header ++ packet->PageBufferCount = num_frags; ++ ++ // TODO: Flush all write buffers/ memory fence ??? ++ //wmb(); ++ ++ // Initialize it from the skb ++ ASSERT(skb->data); ++ packet->TotalDataBufferLength = skb->len; ++ ++ // Start filling in the page buffers starting at AdditionalRequestPageBufferCount offset ++ packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; ++ packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Offset = (unsigned long)skb->data & (PAGE_SIZE -1); ++ packet->PageBuffers[net_drv_obj->AdditionalRequestPageBufferCount].Length = skb->len - skb->data_len; ++ ++ ASSERT((skb->len - skb->data_len) <= PAGE_SIZE); ++ ++ for (i=net_drv_obj->AdditionalRequestPageBufferCount+1; iPageBuffers[i].Pfn = page_to_pfn(skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page); ++ packet->PageBuffers[i].Offset = skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].page_offset; ++ packet->PageBuffers[i].Length = skb_shinfo(skb)->frags[i-(net_drv_obj->AdditionalRequestPageBufferCount+1)].size; ++ } ++ ++ // Set the completion routine ++ packet->Completion.Send.OnSendCompletion = netvsc_xmit_completion; ++ packet->Completion.Send.SendCompletionContext = packet; ++ packet->Completion.Send.SendCompletionTid = (ULONG_PTR)skb; ++ ++retry_send: ++ ret = net_drv_obj->OnSend(&net_device_ctx->device_ctx->device_obj, packet); ++ ++ if (ret == 0) ++ { ++#ifdef KERNEL_2_6_5 ++#define NETDEV_TX_OK 0 ++#define NETDEV_TX_BUSY 0 ++#endif ++ ret = NETDEV_TX_OK; ++ net_device_ctx->stats.tx_bytes += skb->len; ++ net_device_ctx->stats.tx_packets++; ++ } ++ else ++ { ++ retries++; ++ if (retries < 4) ++ { ++ DPRINT_ERR(NETVSC_DRV, "unable to send...retrying %d...", retries); ++ udelay(100); ++ goto retry_send; ++ } ++ ++ // no more room or we are shutting down ++ DPRINT_ERR(NETVSC_DRV, "unable to send (%d)...marking net device (%p) busy", ret, net); ++ DPRINT_INFO(NETVSC_DRV, "net device (%p) stopping", net); ++ ++ ret = NETDEV_TX_BUSY; ++ net_device_ctx->stats.tx_dropped++; ++ ++ netif_stop_queue(net); ++ ++ // Null it since the caller will free it instead of the completion routine ++ packet->Completion.Send.SendCompletionTid = 0; ++ ++ // Release the resources since we will not get any send completion ++ netvsc_xmit_completion((void*)packet); ++ } ++ ++ DPRINT_DBG(NETVSC_DRV, "# of xmits %lu total size %lu", net_device_ctx->stats.tx_packets, net_device_ctx->stats.tx_bytes); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: netvsc_linkstatus_callback() ++ ++Desc: Link up/down notification ++ ++--*/ ++static void netvsc_linkstatus_callback(DEVICE_OBJECT *device_obj, unsigned int status) ++{ ++ struct device_context* device_ctx = to_device_context(device_obj); ++ struct net_device* net = (struct net_device *)device_ctx->device.driver_data; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ if (!net) ++ { ++ DPRINT_ERR(NETVSC_DRV, "got link status but net device not initialized yet"); ++ return; ++ } ++ ++ if (status == 1) ++ { ++ netif_carrier_on(net); ++ netif_wake_queue(net); ++ } ++ else ++ { ++ netif_carrier_off(net); ++ netif_stop_queue(net); ++ } ++ DPRINT_EXIT(NETVSC_DRV); ++} ++ ++ ++/*++ ++ ++Name: netvsc_recv_callback() ++ ++Desc: Callback when we receive a packet from the "wire" on the specify device ++ ++--*/ ++static int netvsc_recv_callback(DEVICE_OBJECT *device_obj, NETVSC_PACKET* packet) ++{ ++ int ret=0; ++ struct device_context *device_ctx = to_device_context(device_obj); ++ struct net_device *net = (struct net_device *)device_ctx->device.driver_data; ++ struct net_device_context *net_device_ctx; ++ ++ struct sk_buff *skb; ++ void *data; ++ int i=0; ++ unsigned long flags; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ if (!net) ++ { ++ DPRINT_ERR(NETVSC_DRV, "got receive callback but net device not initialized yet"); ++ return 0; ++ } ++ ++ net_device_ctx = netdev_priv(net); ++ ++ // Allocate a skb - TODO preallocate this ++ //skb = alloc_skb(packet->TotalDataBufferLength, GFP_ATOMIC); ++ skb = dev_alloc_skb(packet->TotalDataBufferLength + 2); // Pad 2-bytes to align IP header to 16 bytes ++ ASSERT(skb); ++ skb_reserve(skb, 2); ++ skb->dev = net; ++ ++ // for kmap_atomic ++ local_irq_save(flags); ++ ++ // Copy to skb. This copy is needed here since the memory pointed by NETVSC_PACKET ++ // cannot be deallocated ++ for (i=0; iPageBufferCount; i++) ++ { ++ data = kmap_atomic(pfn_to_page(packet->PageBuffers[i].Pfn), KM_IRQ1); ++ data = (void*)(unsigned long)data + packet->PageBuffers[i].Offset; ++ ++ memcpy(skb_put(skb, packet->PageBuffers[i].Length), data, packet->PageBuffers[i].Length); ++ ++ kunmap_atomic((void*)((unsigned long)data - packet->PageBuffers[i].Offset), KM_IRQ1); ++ } ++ ++ local_irq_restore(flags); ++ ++ skb->protocol = eth_type_trans(skb, net); ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ // Pass the skb back up. Network stack will deallocate the skb when it is done ++ ret = netif_rx(skb); ++ ++ switch (ret) ++ { ++ case NET_RX_DROP: ++ net_device_ctx->stats.rx_dropped++; ++ break; ++ default: ++ net_device_ctx->stats.rx_packets++; ++ net_device_ctx->stats.rx_bytes += skb->len; ++ break; ++ ++ } ++ DPRINT_DBG(NETVSC_DRV, "# of recvs %lu total size %lu", net_device_ctx->stats.rx_packets, net_device_ctx->stats.rx_bytes); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return 0; ++} ++ ++static int netvsc_drv_exit_cb(struct device *dev, void *data) ++{ ++ struct device **curr = (struct device **)data; ++ *curr = dev; ++ return 1; // stop iterating ++} ++ ++/*++ ++ ++Name: netvsc_drv_exit() ++ ++Desc: ++ ++--*/ ++void netvsc_drv_exit(void) ++{ ++ NETVSC_DRIVER_OBJECT *netvsc_drv_obj=&g_netvsc_drv.drv_obj; ++ struct driver_context *drv_ctx=&g_netvsc_drv.drv_ctx; ++ ++ struct device *current_dev=NULL; ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#define driver_for_each_device(drv, start, data, fn) \ ++ struct list_head *ptr, *n; \ ++ list_for_each_safe(ptr, n, &((drv)->devices)) {\ ++ struct device *curr_dev;\ ++ curr_dev = list_entry(ptr, struct device, driver_list);\ ++ fn(curr_dev, data);\ ++ } ++#endif ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ while (1) ++ { ++ current_dev = NULL; ++ ++ // Get the device ++ driver_for_each_device(&drv_ctx->driver, NULL, (void*)¤t_dev, netvsc_drv_exit_cb); ++ ++ if (current_dev == NULL) ++ break; ++ ++ // Initiate removal from the top-down ++ DPRINT_INFO(NETVSC_DRV, "unregistering device (%p)...", current_dev); ++ ++ device_unregister(current_dev); ++ } ++ ++ if (netvsc_drv_obj->Base.OnCleanup) ++ netvsc_drv_obj->Base.OnCleanup(&netvsc_drv_obj->Base); ++ ++ vmbus_child_driver_unregister(drv_ctx); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return; ++} ++ ++static int __init netvsc_init(void) ++{ ++ int ret; ++ ++ DPRINT_ENTER(NETVSC_DRV); ++ DPRINT_INFO(NETVSC_DRV, "Netvsc initializing...."); ++ ++ ret = netvsc_drv_init(NetVscInitialize); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++ ++ return ret; ++} ++ ++static void __exit netvsc_exit(void) ++{ ++ DPRINT_ENTER(NETVSC_DRV); ++ ++ netvsc_drv_exit(); ++ ++ DPRINT_EXIT(NETVSC_DRV); ++} ++ ++module_param(netvsc_ringbuffer_size, int, S_IRUGO); ++ ++module_init(netvsc_init); ++module_exit(netvsc_exit); +--- /dev/null ++++ b/drivers/staging/hv/NetVsc.h +@@ -0,0 +1,91 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _NETVSC_H_ ++#define _NETVSC_H_ ++ ++#include "VmbusPacketFormat.h" ++#include "nvspprotocol.h" ++ ++#include "List.h" ++ ++#include "NetVscApi.h" ++// ++// #defines ++// ++//#define NVSC_MIN_PROTOCOL_VERSION 1 ++//#define NVSC_MAX_PROTOCOL_VERSION 1 ++ ++#define NETVSC_SEND_BUFFER_SIZE 64*1024 // 64K ++#define NETVSC_SEND_BUFFER_ID 0xface ++ ++ ++#define NETVSC_RECEIVE_BUFFER_SIZE 1024*1024 // 1MB ++ ++#define NETVSC_RECEIVE_BUFFER_ID 0xcafe ++ ++#define NETVSC_RECEIVE_SG_COUNT 1 ++ ++// Preallocated receive packets ++#define NETVSC_RECEIVE_PACKETLIST_COUNT 256 ++ ++// ++// Data types ++// ++ ++// Per netvsc channel-specific ++typedef struct _NETVSC_DEVICE { ++ DEVICE_OBJECT *Device; ++ ++ int RefCount; ++ ++ int NumOutstandingSends; ++ // List of free preallocated NETVSC_PACKET to represent receive packet ++ LIST_ENTRY ReceivePacketList; ++ HANDLE ReceivePacketListLock; ++ ++ // Send buffer allocated by us but manages by NetVSP ++ PVOID SendBuffer; ++ UINT32 SendBufferSize; ++ UINT32 SendBufferGpadlHandle; ++ UINT32 SendSectionSize; ++ ++ // Receive buffer allocated by us but manages by NetVSP ++ PVOID ReceiveBuffer; ++ UINT32 ReceiveBufferSize; ++ UINT32 ReceiveBufferGpadlHandle; ++ UINT32 ReceiveSectionCount; ++ PNVSP_1_RECEIVE_BUFFER_SECTION ReceiveSections; ++ ++ // Used for NetVSP initialization protocol ++ HANDLE ChannelInitEvent; ++ NVSP_MESSAGE ChannelInitPacket; ++ ++ NVSP_MESSAGE RevokePacket; ++ //UCHAR HwMacAddr[HW_MACADDR_LEN]; ++ ++ // Holds rndis device info ++ void *Extension; ++} NETVSC_DEVICE; ++ ++#endif // _NETVSC_H_ +--- /dev/null ++++ b/drivers/staging/hv/RndisFilter.c +@@ -0,0 +1,1162 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++ ++#include "NetVscApi.h" ++#include "RndisFilter.h" ++ ++// ++// Data types ++// ++ ++typedef struct _RNDIS_FILTER_DRIVER_OBJECT { ++ // The original driver ++ NETVSC_DRIVER_OBJECT InnerDriver; ++ ++} RNDIS_FILTER_DRIVER_OBJECT; ++ ++typedef enum { ++ RNDIS_DEV_UNINITIALIZED = 0, ++ RNDIS_DEV_INITIALIZING, ++ RNDIS_DEV_INITIALIZED, ++ RNDIS_DEV_DATAINITIALIZED, ++} RNDIS_DEVICE_STATE; ++ ++typedef struct _RNDIS_DEVICE { ++ NETVSC_DEVICE *NetDevice; ++ ++ RNDIS_DEVICE_STATE State; ++ UINT32 LinkStatus; ++ UINT32 NewRequestId; ++ ++ HANDLE RequestLock; ++ LIST_ENTRY RequestList; ++ ++ UCHAR HwMacAddr[HW_MACADDR_LEN]; ++} RNDIS_DEVICE; ++ ++ ++typedef struct _RNDIS_REQUEST { ++ LIST_ENTRY ListEntry; ++ HANDLE WaitEvent; ++ ++ // FIXME: We assumed a fixed size response here. If we do ever need to handle a bigger response, ++ // we can either define a max response message or add a response buffer variable above this field ++ RNDIS_MESSAGE ResponseMessage; ++ ++ // Simplify allocation by having a netvsc packet inline ++ NETVSC_PACKET Packet; ++ PAGE_BUFFER Buffer; ++ // FIXME: We assumed a fixed size request here. ++ RNDIS_MESSAGE RequestMessage; ++} RNDIS_REQUEST; ++ ++ ++typedef struct _RNDIS_FILTER_PACKET { ++ void *CompletionContext; ++ PFN_ON_SENDRECVCOMPLETION OnCompletion; ++ ++ RNDIS_MESSAGE Message; ++} RNDIS_FILTER_PACKET; ++ ++// ++// Internal routines ++// ++static int ++RndisFilterSendRequest( ++ RNDIS_DEVICE *Device, ++ RNDIS_REQUEST *Request ++ ); ++ ++static void ++RndisFilterReceiveResponse( ++ RNDIS_DEVICE *Device, ++ RNDIS_MESSAGE *Response ++ ); ++ ++static void ++RndisFilterReceiveIndicateStatus( ++ RNDIS_DEVICE *Device, ++ RNDIS_MESSAGE *Response ++ ); ++ ++static void ++RndisFilterReceiveData( ++ RNDIS_DEVICE *Device, ++ RNDIS_MESSAGE *Message, ++ NETVSC_PACKET *Packet ++ ); ++ ++static int ++RndisFilterOnReceive( ++ DEVICE_OBJECT *Device, ++ NETVSC_PACKET *Packet ++ ); ++ ++static int ++RndisFilterQueryDevice( ++ RNDIS_DEVICE *Device, ++ UINT32 Oid, ++ VOID *Result, ++ UINT32 *ResultSize ++ ); ++ ++static inline int ++RndisFilterQueryDeviceMac( ++ RNDIS_DEVICE *Device ++ ); ++ ++static inline int ++RndisFilterQueryDeviceLinkStatus( ++ RNDIS_DEVICE *Device ++ ); ++ ++static int ++RndisFilterSetPacketFilter( ++ RNDIS_DEVICE *Device, ++ UINT32 NewFilter ++ ); ++ ++static int ++RndisFilterInitDevice( ++ RNDIS_DEVICE *Device ++ ); ++ ++static int ++RndisFilterOpenDevice( ++ RNDIS_DEVICE *Device ++ ); ++ ++static int ++RndisFilterCloseDevice( ++ RNDIS_DEVICE *Device ++ ); ++ ++static int ++RndisFilterOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ); ++ ++static int ++RndisFilterOnDeviceRemove( ++ DEVICE_OBJECT *Device ++ ); ++ ++static void ++RndisFilterOnCleanup( ++ DRIVER_OBJECT *Driver ++ ); ++ ++static int ++RndisFilterOnOpen( ++ DEVICE_OBJECT *Device ++ ); ++ ++static int ++RndisFilterOnClose( ++ DEVICE_OBJECT *Device ++ ); ++ ++static int ++RndisFilterOnSend( ++ DEVICE_OBJECT *Device, ++ NETVSC_PACKET *Packet ++ ); ++ ++static void ++RndisFilterOnSendCompletion( ++ void *Context ++ ); ++ ++static void ++RndisFilterOnSendRequestCompletion( ++ void *Context ++ ); ++ ++// ++// Global var ++// ++ ++// The one and only ++RNDIS_FILTER_DRIVER_OBJECT gRndisFilter; ++ ++static inline RNDIS_DEVICE* GetRndisDevice(void) ++{ ++ RNDIS_DEVICE *device; ++ ++ device = MemAllocZeroed(sizeof(RNDIS_DEVICE)); ++ if (!device) ++ { ++ return NULL; ++ } ++ ++ device->RequestLock = SpinlockCreate(); ++ if (!device->RequestLock) ++ { ++ MemFree(device); ++ return NULL; ++ } ++ ++ INITIALIZE_LIST_HEAD(&device->RequestList); ++ ++ device->State = RNDIS_DEV_UNINITIALIZED; ++ ++ return device; ++} ++ ++static inline void PutRndisDevice(RNDIS_DEVICE *Device) ++{ ++ SpinlockClose(Device->RequestLock); ++ MemFree(Device); ++} ++ ++static inline RNDIS_REQUEST* GetRndisRequest(RNDIS_DEVICE *Device, UINT32 MessageType, UINT32 MessageLength) ++{ ++ RNDIS_REQUEST *request; ++ RNDIS_MESSAGE *rndisMessage; ++ RNDIS_SET_REQUEST *set; ++ ++ request = MemAllocZeroed(sizeof(RNDIS_REQUEST)); ++ if (!request) ++ { ++ return NULL; ++ } ++ ++ request->WaitEvent = WaitEventCreate(); ++ if (!request->WaitEvent) ++ { ++ MemFree(request); ++ return NULL; ++ } ++ ++ rndisMessage = &request->RequestMessage; ++ rndisMessage->NdisMessageType = MessageType; ++ rndisMessage->MessageLength = MessageLength; ++ ++ // Set the request id. This field is always after the rndis header for request/response packet types so ++ // we just used the SetRequest as a template ++ set = &rndisMessage->Message.SetRequest; ++ set->RequestId = InterlockedIncrement((int*)&Device->NewRequestId); ++ ++ // Add to the request list ++ SpinlockAcquire(Device->RequestLock); ++ INSERT_TAIL_LIST(&Device->RequestList, &request->ListEntry); ++ SpinlockRelease(Device->RequestLock); ++ ++ return request; ++} ++ ++static inline void PutRndisRequest(RNDIS_DEVICE *Device, RNDIS_REQUEST *Request) ++{ ++ SpinlockAcquire(Device->RequestLock); ++ REMOVE_ENTRY_LIST(&Request->ListEntry); ++ SpinlockRelease(Device->RequestLock); ++ ++ WaitEventClose(Request->WaitEvent); ++ MemFree(Request); ++} ++ ++static inline void DumpRndisMessage(RNDIS_MESSAGE *RndisMessage) ++{ ++ switch (RndisMessage->NdisMessageType) ++ { ++ case REMOTE_NDIS_PACKET_MSG: ++ DPRINT_DBG(NETVSC, "REMOTE_NDIS_PACKET_MSG (len %u, data offset %u data len %u, # oob %u, oob offset %u, oob len %u, pkt offset %u, pkt len %u", ++ RndisMessage->MessageLength, ++ RndisMessage->Message.Packet.DataOffset, ++ RndisMessage->Message.Packet.DataLength, ++ RndisMessage->Message.Packet.NumOOBDataElements, ++ RndisMessage->Message.Packet.OOBDataOffset, ++ RndisMessage->Message.Packet.OOBDataLength, ++ RndisMessage->Message.Packet.PerPacketInfoOffset, ++ RndisMessage->Message.Packet.PerPacketInfoLength); ++ break; ++ ++ case REMOTE_NDIS_INITIALIZE_CMPLT: ++ DPRINT_DBG(NETVSC, "REMOTE_NDIS_INITIALIZE_CMPLT (len %u, id 0x%x, status 0x%x, major %d, minor %d, device flags %d, max xfer size 0x%x, max pkts %u, pkt aligned %u)", ++ RndisMessage->MessageLength, ++ RndisMessage->Message.InitializeComplete.RequestId, ++ RndisMessage->Message.InitializeComplete.Status, ++ RndisMessage->Message.InitializeComplete.MajorVersion, ++ RndisMessage->Message.InitializeComplete.MinorVersion, ++ RndisMessage->Message.InitializeComplete.DeviceFlags, ++ RndisMessage->Message.InitializeComplete.MaxTransferSize, ++ RndisMessage->Message.InitializeComplete.MaxPacketsPerMessage, ++ RndisMessage->Message.InitializeComplete.PacketAlignmentFactor); ++ break; ++ ++ case REMOTE_NDIS_QUERY_CMPLT: ++ DPRINT_DBG(NETVSC, "REMOTE_NDIS_QUERY_CMPLT (len %u, id 0x%x, status 0x%x, buf len %u, buf offset %u)", ++ RndisMessage->MessageLength, ++ RndisMessage->Message.QueryComplete.RequestId, ++ RndisMessage->Message.QueryComplete.Status, ++ RndisMessage->Message.QueryComplete.InformationBufferLength, ++ RndisMessage->Message.QueryComplete.InformationBufferOffset); ++ break; ++ ++ case REMOTE_NDIS_SET_CMPLT: ++ DPRINT_DBG(NETVSC, "REMOTE_NDIS_SET_CMPLT (len %u, id 0x%x, status 0x%x)", ++ RndisMessage->MessageLength, ++ RndisMessage->Message.SetComplete.RequestId, ++ RndisMessage->Message.SetComplete.Status); ++ break; ++ ++ case REMOTE_NDIS_INDICATE_STATUS_MSG: ++ DPRINT_DBG(NETVSC, "REMOTE_NDIS_INDICATE_STATUS_MSG (len %u, status 0x%x, buf len %u, buf offset %u)", ++ RndisMessage->MessageLength, ++ RndisMessage->Message.IndicateStatus.Status, ++ RndisMessage->Message.IndicateStatus.StatusBufferLength, ++ RndisMessage->Message.IndicateStatus.StatusBufferOffset); ++ break; ++ ++ default: ++ DPRINT_DBG(NETVSC, "0x%x (len %u)", ++ RndisMessage->NdisMessageType, ++ RndisMessage->MessageLength); ++ break; ++ } ++} ++ ++static int ++RndisFilterSendRequest( ++ RNDIS_DEVICE *Device, ++ RNDIS_REQUEST *Request ++ ) ++{ ++ int ret=0; ++ NETVSC_PACKET *packet; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // Setup the packet to send it ++ packet = &Request->Packet; ++ ++ packet->IsDataPacket = FALSE; ++ packet->TotalDataBufferLength = Request->RequestMessage.MessageLength; ++ packet->PageBufferCount = 1; ++ ++ packet->PageBuffers[0].Pfn = GetPhysicalAddress(&Request->RequestMessage) >> PAGE_SHIFT; ++ packet->PageBuffers[0].Length = Request->RequestMessage.MessageLength; ++ packet->PageBuffers[0].Offset = (ULONG_PTR)&Request->RequestMessage & (PAGE_SIZE -1); ++ ++ packet->Completion.Send.SendCompletionContext = Request;//packet; ++ packet->Completion.Send.OnSendCompletion = RndisFilterOnSendRequestCompletion; ++ packet->Completion.Send.SendCompletionTid = (ULONG_PTR)Device; ++ ++ ret = gRndisFilter.InnerDriver.OnSend(Device->NetDevice->Device, packet); ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++ ++static void ++RndisFilterReceiveResponse( ++ RNDIS_DEVICE *Device, ++ RNDIS_MESSAGE *Response ++ ) ++{ ++ LIST_ENTRY *anchor; ++ LIST_ENTRY *curr; ++ RNDIS_REQUEST *request=NULL; ++ BOOL found=FALSE; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ SpinlockAcquire(Device->RequestLock); ++ ITERATE_LIST_ENTRIES(anchor, curr, &Device->RequestList) ++ { ++ request = CONTAINING_RECORD(curr, RNDIS_REQUEST, ListEntry); ++ ++ // All request/response message contains RequestId as the 1st field ++ if (request->RequestMessage.Message.InitializeRequest.RequestId == Response->Message.InitializeComplete.RequestId) ++ { ++ DPRINT_DBG(NETVSC, "found rndis request for this response (id 0x%x req type 0x%x res type 0x%x)", ++ request->RequestMessage.Message.InitializeRequest.RequestId, request->RequestMessage.NdisMessageType, Response->NdisMessageType); ++ ++ found = TRUE; ++ break; ++ } ++ } ++ SpinlockRelease(Device->RequestLock); ++ ++ if (found) ++ { ++ if (Response->MessageLength <= sizeof(RNDIS_MESSAGE)) ++ { ++ memcpy(&request->ResponseMessage, Response, Response->MessageLength); ++ } ++ else ++ { ++ DPRINT_ERR(NETVSC, "rndis response buffer overflow detected (size %u max %u)", Response->MessageLength, sizeof(RNDIS_FILTER_PACKET)); ++ ++ if (Response->NdisMessageType == REMOTE_NDIS_RESET_CMPLT) // does not have a request id field ++ { ++ request->ResponseMessage.Message.ResetComplete.Status = STATUS_BUFFER_OVERFLOW; ++ } ++ else ++ { ++ request->ResponseMessage.Message.InitializeComplete.Status = STATUS_BUFFER_OVERFLOW; ++ } ++ } ++ ++ WaitEventSet(request->WaitEvent); ++ } ++ else ++ { ++ DPRINT_ERR(NETVSC, "no rndis request found for this response (id 0x%x res type 0x%x)", ++ Response->Message.InitializeComplete.RequestId, Response->NdisMessageType); ++ } ++ ++ DPRINT_EXIT(NETVSC); ++} ++ ++static void ++RndisFilterReceiveIndicateStatus( ++ RNDIS_DEVICE *Device, ++ RNDIS_MESSAGE *Response ++ ) ++{ ++ RNDIS_INDICATE_STATUS *indicate = &Response->Message.IndicateStatus; ++ ++ if (indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) ++ { ++ gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 1); ++ } ++ else if (indicate->Status == RNDIS_STATUS_MEDIA_DISCONNECT) ++ { ++ gRndisFilter.InnerDriver.OnLinkStatusChanged(Device->NetDevice->Device, 0); ++ } ++ else ++ { ++ // TODO: ++ } ++} ++ ++static void ++RndisFilterReceiveData( ++ RNDIS_DEVICE *Device, ++ RNDIS_MESSAGE *Message, ++ NETVSC_PACKET *Packet ++ ) ++{ ++ RNDIS_PACKET *rndisPacket; ++ UINT32 dataOffset; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // empty ethernet frame ?? ++ ASSERT(Packet->PageBuffers[0].Length > RNDIS_MESSAGE_SIZE(RNDIS_PACKET)); ++ ++ rndisPacket = &Message->Message.Packet; ++ ++ // FIXME: Handle multiple rndis pkt msgs that maybe enclosed in this ++ // netvsc packet (ie TotalDataBufferLength != MessageLength) ++ ++ // Remove the rndis header and pass it back up the stack ++ dataOffset = RNDIS_HEADER_SIZE + rndisPacket->DataOffset; ++ ++ Packet->TotalDataBufferLength -= dataOffset; ++ Packet->PageBuffers[0].Offset += dataOffset; ++ Packet->PageBuffers[0].Length -= dataOffset; ++ ++ Packet->IsDataPacket = TRUE; ++ ++ gRndisFilter.InnerDriver.OnReceiveCallback(Device->NetDevice->Device, Packet); ++ ++ DPRINT_EXIT(NETVSC); ++} ++ ++static int ++RndisFilterOnReceive( ++ DEVICE_OBJECT *Device, ++ NETVSC_PACKET *Packet ++ ) ++{ ++ NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; ++ RNDIS_DEVICE *rndisDevice; ++ RNDIS_MESSAGE rndisMessage; ++ RNDIS_MESSAGE *rndisHeader; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(netDevice); ++ //Make sure the rndis device state is initialized ++ if (!netDevice->Extension) ++ { ++ DPRINT_ERR(NETVSC, "got rndis message but no rndis device...dropping this message!"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ ++ rndisDevice = (RNDIS_DEVICE*)netDevice->Extension; ++ if (rndisDevice->State == RNDIS_DEV_UNINITIALIZED) ++ { ++ DPRINT_ERR(NETVSC, "got rndis message but rndis device uninitialized...dropping this message!"); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ ++ rndisHeader = (RNDIS_MESSAGE*)PageMapVirtualAddress(Packet->PageBuffers[0].Pfn); ++ ++ rndisHeader = (void*)((ULONG_PTR)rndisHeader + Packet->PageBuffers[0].Offset); ++ ++ // Make sure we got a valid rndis message ++ // FIXME: There seems to be a bug in set completion msg where its MessageLength is 16 bytes but ++ // the ByteCount field in the xfer page range shows 52 bytes ++#if 0 ++ if ( Packet->TotalDataBufferLength != rndisHeader->MessageLength ) ++ { ++ PageUnmapVirtualAddress((void*)(ULONG_PTR)rndisHeader - Packet->PageBuffers[0].Offset); ++ ++ DPRINT_ERR(NETVSC, "invalid rndis message? (expected %u bytes got %u)...dropping this message!", ++ rndisHeader->MessageLength, Packet->TotalDataBufferLength); ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++#endif ++ ++ if ((rndisHeader->NdisMessageType != REMOTE_NDIS_PACKET_MSG) && (rndisHeader->MessageLength > sizeof(RNDIS_MESSAGE))) ++ { ++ DPRINT_ERR(NETVSC, "incoming rndis message buffer overflow detected (got %u, max %u)...marking it an error!", ++ rndisHeader->MessageLength, sizeof(RNDIS_MESSAGE)); ++ } ++ ++ memcpy(&rndisMessage, rndisHeader, (rndisHeader->MessageLength > sizeof(RNDIS_MESSAGE))?sizeof(RNDIS_MESSAGE):rndisHeader->MessageLength); ++ ++ PageUnmapVirtualAddress((void*)(ULONG_PTR)rndisHeader - Packet->PageBuffers[0].Offset); ++ ++ DumpRndisMessage(&rndisMessage); ++ ++ switch (rndisMessage.NdisMessageType) ++ { ++ // data msg ++ case REMOTE_NDIS_PACKET_MSG: ++ RndisFilterReceiveData(rndisDevice, &rndisMessage, Packet); ++ break; ++ ++ // completion msgs ++ case REMOTE_NDIS_INITIALIZE_CMPLT: ++ case REMOTE_NDIS_QUERY_CMPLT: ++ case REMOTE_NDIS_SET_CMPLT: ++ //case REMOTE_NDIS_RESET_CMPLT: ++ //case REMOTE_NDIS_KEEPALIVE_CMPLT: ++ RndisFilterReceiveResponse(rndisDevice, &rndisMessage); ++ break; ++ ++ // notification msgs ++ case REMOTE_NDIS_INDICATE_STATUS_MSG: ++ RndisFilterReceiveIndicateStatus(rndisDevice, &rndisMessage); ++ break; ++ default: ++ DPRINT_ERR(NETVSC, "unhandled rndis message (type %u len %u)", rndisMessage.NdisMessageType, rndisMessage.MessageLength); ++ break; ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ return 0; ++} ++ ++ ++static int ++RndisFilterQueryDevice( ++ RNDIS_DEVICE *Device, ++ UINT32 Oid, ++ VOID *Result, ++ UINT32 *ResultSize ++ ) ++{ ++ RNDIS_REQUEST *request; ++ UINT32 inresultSize = *ResultSize; ++ RNDIS_QUERY_REQUEST *query; ++ RNDIS_QUERY_COMPLETE *queryComplete; ++ int ret=0; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(Result); ++ ++ *ResultSize = 0; ++ request = GetRndisRequest(Device, REMOTE_NDIS_QUERY_MSG, RNDIS_MESSAGE_SIZE(RNDIS_QUERY_REQUEST)); ++ if (!request) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Setup the rndis query ++ query = &request->RequestMessage.Message.QueryRequest; ++ query->Oid = Oid; ++ query->InformationBufferOffset = sizeof(RNDIS_QUERY_REQUEST); ++ query->InformationBufferLength = 0; ++ query->DeviceVcHandle = 0; ++ ++ ret = RndisFilterSendRequest(Device, request); ++ if (ret != 0) ++ { ++ goto Cleanup; ++ } ++ ++ WaitEventWait(request->WaitEvent); ++ ++ // Copy the response back ++ queryComplete = &request->ResponseMessage.Message.QueryComplete; ++ ++ if (queryComplete->InformationBufferLength > inresultSize) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ memcpy(Result, ++ (void*)((ULONG_PTR)queryComplete + queryComplete->InformationBufferOffset), ++ queryComplete->InformationBufferLength); ++ ++ *ResultSize = queryComplete->InformationBufferLength; ++ ++Cleanup: ++ if (request) ++ { ++ PutRndisRequest(Device, request); ++ } ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++static inline int ++RndisFilterQueryDeviceMac( ++ RNDIS_DEVICE *Device ++ ) ++{ ++ UINT32 size=HW_MACADDR_LEN; ++ ++ return RndisFilterQueryDevice(Device, ++ RNDIS_OID_802_3_PERMANENT_ADDRESS, ++ Device->HwMacAddr, ++ &size); ++} ++ ++static inline int ++RndisFilterQueryDeviceLinkStatus( ++ RNDIS_DEVICE *Device ++ ) ++{ ++ UINT32 size=sizeof(UINT32); ++ ++ return RndisFilterQueryDevice(Device, ++ RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, ++ &Device->LinkStatus, ++ &size); ++} ++ ++static int ++RndisFilterSetPacketFilter( ++ RNDIS_DEVICE *Device, ++ UINT32 NewFilter ++ ) ++{ ++ RNDIS_REQUEST *request; ++ RNDIS_SET_REQUEST *set; ++ RNDIS_SET_COMPLETE *setComplete; ++ UINT32 status; ++ int ret; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + sizeof(UINT32) <= sizeof(RNDIS_MESSAGE)); ++ ++ request = GetRndisRequest(Device, REMOTE_NDIS_SET_MSG, RNDIS_MESSAGE_SIZE(RNDIS_SET_REQUEST) + sizeof(UINT32)); ++ if (!request) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Setup the rndis set ++ set = &request->RequestMessage.Message.SetRequest; ++ set->Oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER; ++ set->InformationBufferLength = sizeof(UINT32); ++ set->InformationBufferOffset = sizeof(RNDIS_SET_REQUEST); ++ ++ memcpy((void*)(ULONG_PTR)set + sizeof(RNDIS_SET_REQUEST), &NewFilter, sizeof(UINT32)); ++ ++ ret = RndisFilterSendRequest(Device, request); ++ if (ret != 0) ++ { ++ goto Cleanup; ++ } ++ ++ ret = WaitEventWaitEx(request->WaitEvent, 2000/*2sec*/); ++ if (!ret) ++ { ++ ret = -1; ++ DPRINT_ERR(NETVSC, "timeout before we got a set response..."); ++ // We cant deallocate the request since we may still receive a send completion for it. ++ goto Exit; ++ } ++ else ++ { ++ if (ret > 0) ++ { ++ ret = 0; ++ } ++ setComplete = &request->ResponseMessage.Message.SetComplete; ++ status = setComplete->Status; ++ } ++ ++Cleanup: ++ if (request) ++ { ++ PutRndisRequest(Device, request); ++ } ++Exit: ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++int ++RndisFilterInit( ++ NETVSC_DRIVER_OBJECT *Driver ++ ) ++{ ++ DPRINT_ENTER(NETVSC); ++ ++ DPRINT_DBG(NETVSC, "sizeof(RNDIS_FILTER_PACKET) == %d", sizeof(RNDIS_FILTER_PACKET)); ++ ++ Driver->RequestExtSize = sizeof(RNDIS_FILTER_PACKET); ++ Driver->AdditionalRequestPageBufferCount = 1; // For rndis header ++ ++ //Driver->Context = rndisDriver; ++ ++ memset(&gRndisFilter, 0, sizeof(RNDIS_FILTER_DRIVER_OBJECT)); ++ ++ /*rndisDriver->Driver = Driver; ++ ++ ASSERT(Driver->OnLinkStatusChanged); ++ rndisDriver->OnLinkStatusChanged = Driver->OnLinkStatusChanged;*/ ++ ++ // Save the original dispatch handlers before we override it ++ gRndisFilter.InnerDriver.Base.OnDeviceAdd = Driver->Base.OnDeviceAdd; ++ gRndisFilter.InnerDriver.Base.OnDeviceRemove = Driver->Base.OnDeviceRemove; ++ gRndisFilter.InnerDriver.Base.OnCleanup = Driver->Base.OnCleanup; ++ ++ ASSERT(Driver->OnSend); ++ ASSERT(Driver->OnReceiveCallback); ++ gRndisFilter.InnerDriver.OnSend = Driver->OnSend; ++ gRndisFilter.InnerDriver.OnReceiveCallback = Driver->OnReceiveCallback; ++ gRndisFilter.InnerDriver.OnLinkStatusChanged = Driver->OnLinkStatusChanged; ++ ++ // Override ++ Driver->Base.OnDeviceAdd = RndisFilterOnDeviceAdd; ++ Driver->Base.OnDeviceRemove = RndisFilterOnDeviceRemove; ++ Driver->Base.OnCleanup = RndisFilterOnCleanup; ++ Driver->OnSend = RndisFilterOnSend; ++ Driver->OnOpen = RndisFilterOnOpen; ++ Driver->OnClose = RndisFilterOnClose; ++ //Driver->QueryLinkStatus = RndisFilterQueryDeviceLinkStatus; ++ Driver->OnReceiveCallback = RndisFilterOnReceive; ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return 0; ++} ++ ++static int ++RndisFilterInitDevice( ++ RNDIS_DEVICE *Device ++ ) ++{ ++ RNDIS_REQUEST *request; ++ RNDIS_INITIALIZE_REQUEST *init; ++ RNDIS_INITIALIZE_COMPLETE *initComplete; ++ UINT32 status; ++ int ret; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ request = GetRndisRequest(Device, REMOTE_NDIS_INITIALIZE_MSG, RNDIS_MESSAGE_SIZE(RNDIS_INITIALIZE_REQUEST)); ++ if (!request) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Setup the rndis set ++ init = &request->RequestMessage.Message.InitializeRequest; ++ init->MajorVersion = RNDIS_MAJOR_VERSION; ++ init->MinorVersion = RNDIS_MINOR_VERSION; ++ init->MaxTransferSize = 2048; // FIXME: Use 1536 - rounded ethernet frame size ++ ++ Device->State = RNDIS_DEV_INITIALIZING; ++ ++ ret = RndisFilterSendRequest(Device, request); ++ if (ret != 0) ++ { ++ Device->State = RNDIS_DEV_UNINITIALIZED; ++ goto Cleanup; ++ } ++ ++ WaitEventWait(request->WaitEvent); ++ ++ initComplete = &request->ResponseMessage.Message.InitializeComplete; ++ status = initComplete->Status; ++ if (status == RNDIS_STATUS_SUCCESS) ++ { ++ Device->State = RNDIS_DEV_INITIALIZED; ++ ret = 0; ++ } ++ else ++ { ++ Device->State = RNDIS_DEV_UNINITIALIZED; ++ ret = -1; ++ } ++ ++Cleanup: ++ if (request) ++ { ++ PutRndisRequest(Device, request); ++ } ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++static void ++RndisFilterHaltDevice( ++ RNDIS_DEVICE *Device ++ ) ++{ ++ RNDIS_REQUEST *request; ++ RNDIS_HALT_REQUEST *halt; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // Attempt to do a rndis device halt ++ request = GetRndisRequest(Device, REMOTE_NDIS_HALT_MSG, RNDIS_MESSAGE_SIZE(RNDIS_HALT_REQUEST)); ++ if (!request) ++ { ++ goto Cleanup; ++ } ++ ++ // Setup the rndis set ++ halt = &request->RequestMessage.Message.HaltRequest; ++ halt->RequestId = InterlockedIncrement((int*)&Device->NewRequestId); ++ ++ // Ignore return since this msg is optional. ++ RndisFilterSendRequest(Device, request); ++ ++ Device->State = RNDIS_DEV_UNINITIALIZED; ++ ++Cleanup: ++ if (request) ++ { ++ PutRndisRequest(Device, request); ++ } ++ DPRINT_EXIT(NETVSC); ++ return; ++} ++ ++ ++static int ++RndisFilterOpenDevice( ++ RNDIS_DEVICE *Device ++ ) ++{ ++ int ret=0; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ if (Device->State != RNDIS_DEV_INITIALIZED) ++ return 0; ++ ++ ret = RndisFilterSetPacketFilter(Device, NDIS_PACKET_TYPE_BROADCAST|NDIS_PACKET_TYPE_DIRECTED); ++ if (ret == 0) ++ { ++ Device->State = RNDIS_DEV_DATAINITIALIZED; ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ return ret; ++} ++ ++static int ++RndisFilterCloseDevice( ++ RNDIS_DEVICE *Device ++ ) ++{ ++ int ret; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ if (Device->State != RNDIS_DEV_DATAINITIALIZED) ++ return 0; ++ ++ ret = RndisFilterSetPacketFilter(Device, 0); ++ if (ret == 0) ++ { ++ Device->State = RNDIS_DEV_INITIALIZED; ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++ ++int ++RndisFilterOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ) ++{ ++ int ret; ++ NETVSC_DEVICE *netDevice; ++ RNDIS_DEVICE *rndisDevice; ++ NETVSC_DEVICE_INFO *deviceInfo = (NETVSC_DEVICE_INFO*)AdditionalInfo; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ //rndisDevice = MemAlloc(sizeof(RNDIS_DEVICE)); ++ rndisDevice = GetRndisDevice(); ++ if (!rndisDevice) ++ { ++ DPRINT_EXIT(NETVSC); ++ return -1; ++ } ++ ++ DPRINT_DBG(NETVSC, "rndis device object allocated - %p", rndisDevice); ++ ++ // Let the inner driver handle this first to create the netvsc channel ++ // NOTE! Once the channel is created, we may get a receive callback ++ // (RndisFilterOnReceive()) before this call is completed ++ ret = gRndisFilter.InnerDriver.Base.OnDeviceAdd(Device, AdditionalInfo); ++ if (ret != 0) ++ { ++ PutRndisDevice(rndisDevice); ++ DPRINT_EXIT(NETVSC); ++ return ret; ++ } ++ ++ // ++ // Initialize the rndis device ++ // ++ netDevice = (NETVSC_DEVICE*)Device->Extension; ++ ASSERT(netDevice); ++ ASSERT(netDevice->Device); ++ ++ netDevice->Extension = rndisDevice; ++ rndisDevice->NetDevice = netDevice; ++ ++ // Send the rndis initialization message ++ ret = RndisFilterInitDevice(rndisDevice); ++ if (ret != 0) ++ { ++ // TODO: If rndis init failed, we will need to shut down the channel ++ } ++ ++ // Get the mac address ++ ret = RndisFilterQueryDeviceMac(rndisDevice); ++ if (ret != 0) ++ { ++ // TODO: shutdown rndis device and the channel ++ } ++ ++ DPRINT_INFO(NETVSC, "Device 0x%p mac addr %02x%02x%02x%02x%02x%02x", ++ rndisDevice, ++ rndisDevice->HwMacAddr[0], ++ rndisDevice->HwMacAddr[1], ++ rndisDevice->HwMacAddr[2], ++ rndisDevice->HwMacAddr[3], ++ rndisDevice->HwMacAddr[4], ++ rndisDevice->HwMacAddr[5]); ++ ++ memcpy(deviceInfo->MacAddr, rndisDevice->HwMacAddr, HW_MACADDR_LEN); ++ ++ RndisFilterQueryDeviceLinkStatus(rndisDevice); ++ ++ deviceInfo->LinkState = rndisDevice->LinkStatus; ++ DPRINT_INFO(NETVSC, "Device 0x%p link state %s", rndisDevice, ((deviceInfo->LinkState)?("down"):("up"))); ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++ ++static int ++RndisFilterOnDeviceRemove( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; ++ RNDIS_DEVICE *rndisDevice = (RNDIS_DEVICE*)netDevice->Extension; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // Halt and release the rndis device ++ RndisFilterHaltDevice(rndisDevice); ++ ++ PutRndisDevice(rndisDevice); ++ netDevice->Extension = NULL; ++ ++ // Pass control to inner driver to remove the device ++ gRndisFilter.InnerDriver.Base.OnDeviceRemove(Device); ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return 0; ++} ++ ++ ++static void ++RndisFilterOnCleanup( ++ DRIVER_OBJECT *Driver ++ ) ++{ ++ DPRINT_ENTER(NETVSC); ++ ++ DPRINT_EXIT(NETVSC); ++} ++ ++static int ++RndisFilterOnOpen( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret; ++ NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(netDevice); ++ ret = RndisFilterOpenDevice((RNDIS_DEVICE*)netDevice->Extension); ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++static int ++RndisFilterOnClose( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret; ++ NETVSC_DEVICE *netDevice = (NETVSC_DEVICE*)Device->Extension; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ ASSERT(netDevice); ++ ret = RndisFilterCloseDevice((RNDIS_DEVICE*)netDevice->Extension); ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++ ++static int ++RndisFilterOnSend( ++ DEVICE_OBJECT *Device, ++ NETVSC_PACKET *Packet ++ ) ++{ ++ int ret=0; ++ RNDIS_FILTER_PACKET *filterPacket; ++ RNDIS_MESSAGE *rndisMessage; ++ RNDIS_PACKET *rndisPacket; ++ UINT32 rndisMessageSize; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // Add the rndis header ++ filterPacket = (RNDIS_FILTER_PACKET*)Packet->Extension; ++ ASSERT(filterPacket); ++ ++ memset(filterPacket, 0, sizeof(RNDIS_FILTER_PACKET)); ++ ++ rndisMessage = &filterPacket->Message; ++ rndisMessageSize = RNDIS_MESSAGE_SIZE(RNDIS_PACKET); ++ ++ rndisMessage->NdisMessageType = REMOTE_NDIS_PACKET_MSG; ++ rndisMessage->MessageLength = Packet->TotalDataBufferLength + rndisMessageSize; ++ ++ rndisPacket = &rndisMessage->Message.Packet; ++ rndisPacket->DataOffset = sizeof(RNDIS_PACKET); ++ rndisPacket->DataLength = Packet->TotalDataBufferLength; ++ ++ Packet->IsDataPacket = TRUE; ++ Packet->PageBuffers[0].Pfn = GetPhysicalAddress(rndisMessage) >> PAGE_SHIFT; ++ Packet->PageBuffers[0].Offset = (ULONG_PTR)rndisMessage & (PAGE_SIZE-1); ++ Packet->PageBuffers[0].Length = rndisMessageSize; ++ ++ // Save the packet send completion and context ++ filterPacket->OnCompletion = Packet->Completion.Send.OnSendCompletion; ++ filterPacket->CompletionContext = Packet->Completion.Send.SendCompletionContext; ++ ++ // Use ours ++ Packet->Completion.Send.OnSendCompletion = RndisFilterOnSendCompletion; ++ Packet->Completion.Send.SendCompletionContext = filterPacket; ++ ++ ret = gRndisFilter.InnerDriver.OnSend(Device, Packet); ++ if (ret != 0) ++ { ++ // Reset the completion to originals to allow retries from above ++ Packet->Completion.Send.OnSendCompletion = filterPacket->OnCompletion; ++ Packet->Completion.Send.SendCompletionContext = filterPacket->CompletionContext; ++ } ++ ++ DPRINT_EXIT(NETVSC); ++ ++ return ret; ++} ++ ++static void ++RndisFilterOnSendCompletion( ++ void *Context) ++{ ++ RNDIS_FILTER_PACKET *filterPacket = (RNDIS_FILTER_PACKET *)Context; ++ ++ DPRINT_ENTER(NETVSC); ++ ++ // Pass it back to the original handler ++ filterPacket->OnCompletion(filterPacket->CompletionContext); ++ ++ DPRINT_EXIT(NETVSC); ++} ++ ++ ++static void ++RndisFilterOnSendRequestCompletion( ++ void *Context ++ ) ++{ ++ DPRINT_ENTER(NETVSC); ++ ++ // Noop ++ DPRINT_EXIT(NETVSC); ++} +--- /dev/null ++++ b/drivers/staging/hv/RndisFilter.h +@@ -0,0 +1,61 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#ifndef _RNDISFILTER_H_ ++#define _RNDISFILTER_H_ ++ ++#define __struct_bcount(x) ++ ++#include "osd.h" ++#include "NetVsc.h" ++ ++#include "rndis.h" ++ ++#define RNDIS_HEADER_SIZE (sizeof(RNDIS_MESSAGE) - sizeof(RNDIS_MESSAGE_CONTAINER)) ++ ++#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 ++#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 ++#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 ++#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 ++#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 ++#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 ++#define NDIS_PACKET_TYPE_SMT 0x00000040 ++#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 ++#define NDIS_PACKET_TYPE_GROUP 0x00000100 ++#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 ++#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 ++#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 ++ ++ ++ ++// ++// Interface ++// ++int ++RndisFilterInit( ++ NETVSC_DRIVER_OBJECT *Driver ++ ); ++ ++ ++#endif // _RNDISFILTER_H_ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-scsi-driver-to-the-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-scsi-driver-to-the-build.patch new file mode 100644 index 000000000..77887945d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-scsi-driver-to-the-build.patch @@ -0,0 +1,39 @@ +From foo@baz Tue Jul 14 10:19:52 PDT 2009 +Date: Tue, 14 Jul 2009 10:19:52 -0700 +To: Greg KH +From: Greg Kroah-Hartman +Subject: Staging: hv: add the Hyper-V virtual scsi driver to the build + +From: Greg Kroah-Hartman + +Add the Hyper-V virtual scsi driver to the kernel build system. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/Kconfig | 6 ++++++ + drivers/staging/hv/Makefile | 2 ++ + 2 files changed, 8 insertions(+) + +--- a/drivers/staging/hv/Kconfig ++++ b/drivers/staging/hv/Kconfig +@@ -6,3 +6,9 @@ config HYPERV + Select this option to run Linux as a Hyper-V client operating + system. + ++config HYPERV_STORAGE ++ tristate "Microsoft Hyper-V virtual storage driver" ++ depends on HYPERV && SCSI ++ default n ++ help ++ Select this option to enable the Hyper-V virtual storage driver. +--- a/drivers/staging/hv/Makefile ++++ b/drivers/staging/hv/Makefile +@@ -1,3 +1,5 @@ + obj-$(CONFIG_HYPERV) += hv_vmbus.o ++obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o + + hv_vmbus-objs := vmbus_drv.o osd.o Sources.o ++hv_storvsc-objs := storvsc_drv.o osd.o StorVsc.o diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-storage-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-storage-driver.patch new file mode 100644 index 000000000..e10836dc7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-add-the-hyper-v-virtual-storage-driver.patch @@ -0,0 +1,2403 @@ +From foo@baz Mon Jul 13 16:01:31 PDT 2009 +Date: Mon, 13 Jul 2009 16:01:31 -0700 +From: Hank Janssen +Subject: Staging: hv: add the Hyper-V virtual storage driver + +From: Hank Janssen + +This is the virtual storage driver when running Linux on top of Hyper-V. + +Signed-off-by: Hank Janssen +Signed-off-by: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/hv/StorVsc.c | 967 ++++++++++++++++++++++++++ + drivers/staging/hv/storvsc_drv.c | 1413 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 2380 insertions(+) + +--- /dev/null ++++ b/drivers/staging/hv/StorVsc.c +@@ -0,0 +1,967 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include "logging.h" ++ ++#include "StorVscApi.h" ++#include "VmbusPacketFormat.h" ++#include "vstorage.h" ++ ++ ++// ++// #defines ++// ++ ++// ++// Data types ++// ++ ++typedef struct _STORVSC_REQUEST_EXTENSION { ++ //LIST_ENTRY ListEntry; ++ ++ STORVSC_REQUEST *Request; ++ DEVICE_OBJECT *Device; ++ ++ // Synchronize the request/response if needed ++ HANDLE WaitEvent; ++ ++ VSTOR_PACKET VStorPacket; ++} STORVSC_REQUEST_EXTENSION; ++ ++ ++// A storvsc device is a device object that contains a vmbus channel ++typedef struct _STORVSC_DEVICE{ ++ DEVICE_OBJECT *Device; ++ ++ int RefCount; // 0 indicates the device is being destroyed ++ ++ int NumOutstandingRequests; ++ ++ // Each unique Port/Path/Target represents 1 channel ie scsi controller. In reality, the pathid, targetid is always 0 ++ // and the port is set by us ++ ULONG PortNumber; ++ UCHAR PathId; ++ UCHAR TargetId; ++ ++ //LIST_ENTRY OutstandingRequestList; ++ //HANDLE OutstandingRequestLock; ++ ++ // Used for vsc/vsp channel reset process ++ STORVSC_REQUEST_EXTENSION InitRequest; ++ ++ STORVSC_REQUEST_EXTENSION ResetRequest; ++ ++} STORVSC_DEVICE; ++ ++ ++// ++// Globals ++// ++static const char* gDriverName="storvsc"; ++ ++//{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} ++static const GUID gStorVscDeviceType={ ++ .Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f} ++}; ++ ++// ++// Internal routines ++// ++static int ++StorVscOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ); ++ ++static int ++StorVscOnDeviceRemove( ++ DEVICE_OBJECT *Device ++ ); ++ ++static int ++StorVscOnIORequest( ++ DEVICE_OBJECT *Device, ++ STORVSC_REQUEST *Request ++ ); ++ ++static int ++StorVscOnHostReset( ++ DEVICE_OBJECT *Device ++ ); ++ ++static void ++StorVscOnCleanup( ++ DRIVER_OBJECT *Device ++ ); ++ ++static void ++StorVscOnChannelCallback( ++ PVOID Context ++ ); ++ ++static void ++StorVscOnIOCompletion( ++ DEVICE_OBJECT *Device, ++ VSTOR_PACKET *VStorPacket, ++ STORVSC_REQUEST_EXTENSION *RequestExt ++ ); ++ ++static void ++StorVscOnReceive( ++ DEVICE_OBJECT *Device, ++ VSTOR_PACKET *VStorPacket, ++ STORVSC_REQUEST_EXTENSION *RequestExt ++ ); ++ ++static int ++StorVscConnectToVsp( ++ DEVICE_OBJECT *Device ++ ); ++ ++static inline STORVSC_DEVICE* AllocStorDevice(DEVICE_OBJECT *Device) ++{ ++ STORVSC_DEVICE *storDevice; ++ ++ storDevice = MemAllocZeroed(sizeof(STORVSC_DEVICE)); ++ if (!storDevice) ++ return NULL; ++ ++ // Set to 2 to allow both inbound and outbound traffics ++ // (ie GetStorDevice() and MustGetStorDevice()) to proceed. ++ InterlockedCompareExchange(&storDevice->RefCount, 2, 0); ++ ++ storDevice->Device = Device; ++ Device->Extension = storDevice; ++ ++ return storDevice; ++} ++ ++static inline void FreeStorDevice(STORVSC_DEVICE *Device) ++{ ++ ASSERT(Device->RefCount == 0); ++ MemFree(Device); ++} ++ ++// Get the stordevice object iff exists and its refcount > 1 ++static inline STORVSC_DEVICE* GetStorDevice(DEVICE_OBJECT *Device) ++{ ++ STORVSC_DEVICE *storDevice; ++ ++ storDevice = (STORVSC_DEVICE*)Device->Extension; ++ if (storDevice && storDevice->RefCount > 1) ++ { ++ InterlockedIncrement(&storDevice->RefCount); ++ } ++ else ++ { ++ storDevice = NULL; ++ } ++ ++ return storDevice; ++} ++ ++// Get the stordevice object iff exists and its refcount > 0 ++static inline STORVSC_DEVICE* MustGetStorDevice(DEVICE_OBJECT *Device) ++{ ++ STORVSC_DEVICE *storDevice; ++ ++ storDevice = (STORVSC_DEVICE*)Device->Extension; ++ if (storDevice && storDevice->RefCount) ++ { ++ InterlockedIncrement(&storDevice->RefCount); ++ } ++ else ++ { ++ storDevice = NULL; ++ } ++ ++ return storDevice; ++} ++ ++static inline void PutStorDevice(DEVICE_OBJECT *Device) ++{ ++ STORVSC_DEVICE *storDevice; ++ ++ storDevice = (STORVSC_DEVICE*)Device->Extension; ++ ASSERT(storDevice); ++ ++ InterlockedDecrement(&storDevice->RefCount); ++ ASSERT(storDevice->RefCount); ++} ++ ++// Drop ref count to 1 to effectively disable GetStorDevice() ++static inline STORVSC_DEVICE* ReleaseStorDevice(DEVICE_OBJECT *Device) ++{ ++ STORVSC_DEVICE *storDevice; ++ ++ storDevice = (STORVSC_DEVICE*)Device->Extension; ++ ASSERT(storDevice); ++ ++ // Busy wait until the ref drop to 2, then set it to 1 ++ while (InterlockedCompareExchange(&storDevice->RefCount, 1, 2) != 2) ++ { ++ Sleep(100); ++ } ++ ++ return storDevice; ++} ++ ++// Drop ref count to 0. No one can use StorDevice object. ++static inline STORVSC_DEVICE* FinalReleaseStorDevice(DEVICE_OBJECT *Device) ++{ ++ STORVSC_DEVICE *storDevice; ++ ++ storDevice = (STORVSC_DEVICE*)Device->Extension; ++ ASSERT(storDevice); ++ ++ // Busy wait until the ref drop to 1, then set it to 0 ++ while (InterlockedCompareExchange(&storDevice->RefCount, 0, 1) != 1) ++ { ++ Sleep(100); ++ } ++ ++ Device->Extension = NULL; ++ return storDevice; ++} ++ ++/*++; ++ ++ ++Name: ++ StorVscInitialize() ++ ++Description: ++ Main entry point ++ ++--*/ ++int ++StorVscInitialize( ++ DRIVER_OBJECT *Driver ++ ) ++{ ++ STORVSC_DRIVER_OBJECT* storDriver = (STORVSC_DRIVER_OBJECT*)Driver; ++ int ret=0; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%d sizeof(STORVSC_REQUEST_EXTENSION)=%d sizeof(VSTOR_PACKET)=%d, sizeof(VMSCSI_REQUEST)=%d", ++ sizeof(STORVSC_REQUEST), sizeof(STORVSC_REQUEST_EXTENSION), sizeof(VSTOR_PACKET), sizeof(VMSCSI_REQUEST)); ++ ++ // Make sure we are at least 2 pages since 1 page is used for control ++ ASSERT(storDriver->RingBufferSize >= (PAGE_SIZE << 1)); ++ ++ Driver->name = gDriverName; ++ memcpy(&Driver->deviceType, &gStorVscDeviceType, sizeof(GUID)); ++ ++ storDriver->RequestExtSize = sizeof(STORVSC_REQUEST_EXTENSION); ++ ++ // Divide the ring buffer data size (which is 1 page less than the ring buffer size since that page is reserved for the ring buffer indices) ++ // by the max request size (which is VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER + VSTOR_PACKET + UINT64) ++ storDriver->MaxOutstandingRequestsPerChannel = ++ ((storDriver->RingBufferSize - PAGE_SIZE) / ALIGN_UP(MAX_MULTIPAGE_BUFFER_PACKET + sizeof(VSTOR_PACKET) + sizeof(UINT64),sizeof(UINT64))); ++ ++ DPRINT_INFO(STORVSC, "max io %u, currently %u\n", storDriver->MaxOutstandingRequestsPerChannel, STORVSC_MAX_IO_REQUESTS); ++ ++ // Setup the dispatch table ++ storDriver->Base.OnDeviceAdd = StorVscOnDeviceAdd; ++ storDriver->Base.OnDeviceRemove = StorVscOnDeviceRemove; ++ storDriver->Base.OnCleanup = StorVscOnCleanup; ++ ++ storDriver->OnIORequest = StorVscOnIORequest; ++ storDriver->OnHostReset = StorVscOnHostReset; ++ ++ DPRINT_EXIT(STORVSC); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: ++ StorVscOnDeviceAdd() ++ ++Description: ++ Callback when the device belonging to this driver is added ++ ++--*/ ++int ++StorVscOnDeviceAdd( ++ DEVICE_OBJECT *Device, ++ void *AdditionalInfo ++ ) ++{ ++ int ret=0; ++ STORVSC_DEVICE *storDevice; ++ //VMSTORAGE_CHANNEL_PROPERTIES *props; ++ STORVSC_DEVICE_INFO *deviceInfo = (STORVSC_DEVICE_INFO*)AdditionalInfo; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ storDevice = AllocStorDevice(Device); ++ if (!storDevice) ++ { ++ ret = -1; ++ goto Cleanup; ++ } ++ ++ // Save the channel properties to our storvsc channel ++ //props = (VMSTORAGE_CHANNEL_PROPERTIES*) channel->offerMsg.Offer.u.Standard.UserDefined; ++ ++ // FIXME: ++ // If we support more than 1 scsi channel, we need to set the port number here ++ // to the scsi channel but how do we get the scsi channel prior to the bus scan ++ /*storChannel->PortNumber = 0; ++ storChannel->PathId = props->PathId; ++ storChannel->TargetId = props->TargetId;*/ ++ ++ storDevice->PortNumber = deviceInfo->PortNumber; ++ // Send it back up ++ ret = StorVscConnectToVsp(Device); ++ ++ //deviceInfo->PortNumber = storDevice->PortNumber; ++ deviceInfo->PathId = storDevice->PathId; ++ deviceInfo->TargetId = storDevice->TargetId; ++ ++ DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n", storDevice->PortNumber, storDevice->PathId, storDevice->TargetId); ++ ++Cleanup: ++ DPRINT_EXIT(STORVSC); ++ ++ return ret; ++} ++ ++static int StorVscChannelInit(DEVICE_OBJECT *Device) ++{ ++ int ret=0; ++ STORVSC_DEVICE *storDevice; ++ STORVSC_REQUEST_EXTENSION *request; ++ VSTOR_PACKET *vstorPacket; ++ ++ storDevice = GetStorDevice(Device); ++ if (!storDevice) ++ { ++ DPRINT_ERR(STORVSC, "unable to get stor device...device being destroyed?"); ++ DPRINT_EXIT(STORVSC); ++ return -1; ++ } ++ ++ request = &storDevice->InitRequest; ++ vstorPacket = &request->VStorPacket; ++ ++ // Now, initiate the vsc/vsp initialization protocol on the open channel ++ ++ memset(request, sizeof(STORVSC_REQUEST_EXTENSION), 0); ++ request->WaitEvent = WaitEventCreate(); ++ ++ vstorPacket->Operation = VStorOperationBeginInitialization; ++ vstorPacket->Flags = REQUEST_COMPLETION_FLAG; ++ ++ /*SpinlockAcquire(gDriverExt.packetListLock); ++ INSERT_TAIL_LIST(&gDriverExt.packetList, &packet->listEntry.entry); ++ SpinlockRelease(gDriverExt.packetListLock);*/ ++ ++ DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION..."); ++ ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)request, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ if ( ret != 0) ++ { ++ DPRINT_ERR(STORVSC, "unable to send BEGIN_INITIALIZATION_OPERATION"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(request->WaitEvent); ++ ++ if (vstorPacket->Operation != VStorOperationCompleteIo || vstorPacket->Status != 0) ++ { ++ DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed (op %d status 0x%x)", vstorPacket->Operation, vstorPacket->Status); ++ goto Cleanup; ++ } ++ ++ DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION..."); ++ ++ // reuse the packet for version range supported ++ memset(vstorPacket, sizeof(VSTOR_PACKET), 0); ++ vstorPacket->Operation = VStorOperationQueryProtocolVersion; ++ vstorPacket->Flags = REQUEST_COMPLETION_FLAG; ++ ++ vstorPacket->Version.MajorMinor = VMSTOR_PROTOCOL_VERSION_CURRENT; ++ FILL_VMSTOR_REVISION(vstorPacket->Version.Revision); ++ ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)request, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ if ( ret != 0) ++ { ++ DPRINT_ERR(STORVSC, "unable to send BEGIN_INITIALIZATION_OPERATION"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(request->WaitEvent); ++ ++ // TODO: Check returned version ++ if (vstorPacket->Operation != VStorOperationCompleteIo || vstorPacket->Status != 0) ++ { ++ DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed (op %d status 0x%x)", vstorPacket->Operation, vstorPacket->Status); ++ goto Cleanup; ++ } ++ ++ // Query channel properties ++ DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION..."); ++ ++ memset(vstorPacket, sizeof(VSTOR_PACKET), 0); ++ vstorPacket->Operation = VStorOperationQueryProperties; ++ vstorPacket->Flags = REQUEST_COMPLETION_FLAG; ++ vstorPacket->StorageChannelProperties.PortNumber = storDevice->PortNumber; ++ ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)request, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ ++ if ( ret != 0) ++ { ++ DPRINT_ERR(STORVSC, "unable to send QUERY_PROPERTIES_OPERATION"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(request->WaitEvent); ++ ++ // TODO: Check returned version ++ if (vstorPacket->Operation != VStorOperationCompleteIo || vstorPacket->Status != 0) ++ { ++ DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed (op %d status 0x%x)", vstorPacket->Operation, vstorPacket->Status); ++ goto Cleanup; ++ } ++ ++ //storDevice->PortNumber = vstorPacket->StorageChannelProperties.PortNumber; ++ storDevice->PathId = vstorPacket->StorageChannelProperties.PathId; ++ storDevice->TargetId = vstorPacket->StorageChannelProperties.TargetId; ++ ++ DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x", vstorPacket->StorageChannelProperties.Flags, vstorPacket->StorageChannelProperties.MaxTransferBytes); ++ ++ DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION..."); ++ ++ memset(vstorPacket, sizeof(VSTOR_PACKET), 0); ++ vstorPacket->Operation = VStorOperationEndInitialization; ++ vstorPacket->Flags = REQUEST_COMPLETION_FLAG; ++ ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)request, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ ++ if ( ret != 0) ++ { ++ DPRINT_ERR(STORVSC, "unable to send END_INITIALIZATION_OPERATION"); ++ goto Cleanup; ++ } ++ ++ WaitEventWait(request->WaitEvent); ++ ++ if (vstorPacket->Operation != VStorOperationCompleteIo || vstorPacket->Status != 0) ++ { ++ DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed (op %d status 0x%x)", vstorPacket->Operation, vstorPacket->Status); ++ goto Cleanup; ++ } ++ ++ DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****"); ++ ++Cleanup: ++ if (request->WaitEvent) ++ { ++ WaitEventClose(request->WaitEvent); ++ request->WaitEvent = NULL; ++ } ++ ++ PutStorDevice(Device); ++ ++ DPRINT_EXIT(STORVSC); ++ return ret; ++} ++ ++ ++int ++StorVscConnectToVsp( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret=0; ++ VMSTORAGE_CHANNEL_PROPERTIES props; ++ ++ STORVSC_DRIVER_OBJECT *storDriver = (STORVSC_DRIVER_OBJECT*) Device->Driver;; ++ ++ memset(&props, sizeof(VMSTORAGE_CHANNEL_PROPERTIES), 0); ++ ++ // Open the channel ++ ret = Device->Driver->VmbusChannelInterface.Open(Device, ++ storDriver->RingBufferSize, ++ storDriver->RingBufferSize, ++ (PVOID)&props, ++ sizeof(VMSTORAGE_CHANNEL_PROPERTIES), ++ StorVscOnChannelCallback, ++ Device ++ ); ++ ++ DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d", props.PathId, props.TargetId, props.MaxTransferBytes); ++ ++ if (ret != 0) ++ { ++ DPRINT_ERR(STORVSC, "unable to open channel: %d", ret); ++ return -1; ++ } ++ ++ ret = StorVscChannelInit(Device); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: ++ StorVscOnDeviceRemove() ++ ++Description: ++ Callback when the our device is being removed ++ ++--*/ ++int ++StorVscOnDeviceRemove( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ STORVSC_DEVICE *storDevice; ++ int ret=0; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ DPRINT_INFO(STORVSC, "disabling storage device (%p)...", Device->Extension); ++ ++ storDevice = ReleaseStorDevice(Device); ++ ++ // At this point, all outbound traffic should be disable. We only allow inbound traffic (responses) to proceed ++ // so that outstanding requests can be completed. ++ while (storDevice->NumOutstandingRequests) ++ { ++ DPRINT_INFO(STORVSC, "waiting for %d requests to complete...", storDevice->NumOutstandingRequests); ++ ++ Sleep(100); ++ } ++ ++ DPRINT_INFO(STORVSC, "removing storage device (%p)...", Device->Extension); ++ ++ storDevice = FinalReleaseStorDevice(Device); ++ ++ DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", storDevice); ++ ++ // Close the channel ++ Device->Driver->VmbusChannelInterface.Close(Device); ++ ++ FreeStorDevice(storDevice); ++ ++ DPRINT_EXIT(STORVSC); ++ return ret; ++} ++ ++ ++//static void ++//StorVscOnTargetRescan( ++// void *Context ++// ) ++//{ ++// DEVICE_OBJECT *device=(DEVICE_OBJECT*)Context; ++// STORVSC_DRIVER_OBJECT *storDriver; ++// ++// DPRINT_ENTER(STORVSC); ++// ++// storDriver = (STORVSC_DRIVER_OBJECT*) device->Driver; ++// storDriver->OnHostRescan(device); ++// ++// DPRINT_EXIT(STORVSC); ++//} ++ ++int ++StorVscOnHostReset( ++ DEVICE_OBJECT *Device ++ ) ++{ ++ int ret=0; ++ ++ STORVSC_DEVICE *storDevice; ++ STORVSC_REQUEST_EXTENSION *request; ++ VSTOR_PACKET *vstorPacket; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ DPRINT_INFO(STORVSC, "resetting host adapter..."); ++ ++ storDevice = GetStorDevice(Device); ++ if (!storDevice) ++ { ++ DPRINT_ERR(STORVSC, "unable to get stor device...device being destroyed?"); ++ DPRINT_EXIT(STORVSC); ++ return -1; ++ } ++ ++ request = &storDevice->ResetRequest; ++ vstorPacket = &request->VStorPacket; ++ ++ request->WaitEvent = WaitEventCreate(); ++ ++ vstorPacket->Operation = VStorOperationResetBus; ++ vstorPacket->Flags = REQUEST_COMPLETION_FLAG; ++ vstorPacket->VmSrb.PathId = storDevice->PathId; ++ ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)&storDevice->ResetRequest, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ if (ret != 0) ++ { ++ DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d", vstorPacket, ret); ++ goto Cleanup; ++ } ++ ++ // FIXME: Add a timeout ++ WaitEventWait(request->WaitEvent); ++ ++ WaitEventClose(request->WaitEvent); ++ DPRINT_INFO(STORVSC, "host adapter reset completed"); ++ ++ // At this point, all outstanding requests in the adapter should have been flushed out and return to us ++ ++Cleanup: ++ PutStorDevice(Device); ++ DPRINT_EXIT(STORVSC); ++ return ret; ++} ++ ++/*++ ++ ++Name: ++ StorVscOnIORequest() ++ ++Description: ++ Callback to initiate an I/O request ++ ++--*/ ++int ++StorVscOnIORequest( ++ DEVICE_OBJECT *Device, ++ STORVSC_REQUEST *Request ++ ) ++{ ++ STORVSC_DEVICE *storDevice; ++ STORVSC_REQUEST_EXTENSION* requestExtension = (STORVSC_REQUEST_EXTENSION*) Request->Extension; ++ VSTOR_PACKET* vstorPacket =&requestExtension->VStorPacket; ++ int ret=0; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ storDevice = GetStorDevice(Device); ++ ++ DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, Extension %p", ++ Device, storDevice, Request, requestExtension); ++ ++ DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d", ++ Request, Request->DataBuffer.Length, Request->Bus, Request->TargetId, Request->LunId, Request->CdbLen); ++ ++ if (!storDevice) ++ { ++ DPRINT_ERR(STORVSC, "unable to get stor device...device being destroyed?"); ++ DPRINT_EXIT(STORVSC); ++ return -2; ++ } ++ ++ //PrintBytes(Request->Cdb, Request->CdbLen); ++ ++ requestExtension->Request = Request; ++ requestExtension->Device = Device; ++ ++ memset(vstorPacket, 0 , sizeof(VSTOR_PACKET)); ++ ++ vstorPacket->Flags |= REQUEST_COMPLETION_FLAG; ++ ++ vstorPacket->VmSrb.Length = sizeof(VMSCSI_REQUEST); ++ ++ vstorPacket->VmSrb.PortNumber = Request->Host; ++ vstorPacket->VmSrb.PathId = Request->Bus; ++ vstorPacket->VmSrb.TargetId = Request->TargetId; ++ vstorPacket->VmSrb.Lun = Request->LunId; ++ ++ vstorPacket->VmSrb.SenseInfoLength = SENSE_BUFFER_SIZE; ++ ++ // Copy over the scsi command descriptor block ++ vstorPacket->VmSrb.CdbLength = Request->CdbLen; ++ memcpy(&vstorPacket->VmSrb.Cdb, Request->Cdb, Request->CdbLen); ++ ++ vstorPacket->VmSrb.DataIn = Request->Type; ++ vstorPacket->VmSrb.DataTransferLength = Request->DataBuffer.Length; ++ ++ vstorPacket->Operation = VStorOperationExecuteSRB; ++ ++ DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, lun %d senselen %d cdblen %d", ++ vstorPacket->VmSrb.Length, ++ vstorPacket->VmSrb.PortNumber, ++ vstorPacket->VmSrb.PathId, ++ vstorPacket->VmSrb.TargetId, ++ vstorPacket->VmSrb.Lun, ++ vstorPacket->VmSrb.SenseInfoLength, ++ vstorPacket->VmSrb.CdbLength); ++ ++ if (requestExtension->Request->DataBuffer.Length) ++ { ++ ret = Device->Driver->VmbusChannelInterface.SendPacketMultiPageBuffer(Device, ++ &requestExtension->Request->DataBuffer, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)requestExtension); ++ } ++ else ++ { ++ ret = Device->Driver->VmbusChannelInterface.SendPacket(Device, ++ vstorPacket, ++ sizeof(VSTOR_PACKET), ++ (ULONG_PTR)requestExtension, ++ VmbusPacketTypeDataInBand, ++ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); ++ } ++ ++ if (ret != 0) ++ { ++ DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d", vstorPacket, ret); ++ } ++ ++ InterlockedIncrement(&storDevice->NumOutstandingRequests); ++ ++ PutStorDevice(Device); ++ ++ DPRINT_EXIT(STORVSC); ++ return ret; ++} ++ ++/*++ ++ ++Name: ++ StorVscOnCleanup() ++ ++Description: ++ Perform any cleanup when the driver is removed ++ ++--*/ ++void ++StorVscOnCleanup( ++ DRIVER_OBJECT *Driver ++ ) ++{ ++ DPRINT_ENTER(STORVSC); ++ DPRINT_EXIT(STORVSC); ++} ++ ++ ++static void ++StorVscOnIOCompletion( ++ DEVICE_OBJECT *Device, ++ VSTOR_PACKET *VStorPacket, ++ STORVSC_REQUEST_EXTENSION *RequestExt ++ ) ++{ ++ STORVSC_REQUEST *request; ++ STORVSC_DEVICE *storDevice; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ storDevice = MustGetStorDevice(Device); ++ if (!storDevice) ++ { ++ DPRINT_ERR(STORVSC, "unable to get stor device...device being destroyed?"); ++ DPRINT_EXIT(STORVSC); ++ return; ++ } ++ ++ DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p completed bytes xfer %u", ++ RequestExt, VStorPacket->VmSrb.DataTransferLength); ++ ++ ASSERT(RequestExt != NULL); ++ ASSERT(RequestExt->Request != NULL); ++ ++ request = RequestExt->Request; ++ ++ ASSERT(request->OnIOCompletion != NULL); ++ ++ // Copy over the status...etc ++ request->Status = VStorPacket->VmSrb.ScsiStatus; ++ ++ if (request->Status != 0 || VStorPacket->VmSrb.SrbStatus != 1) ++ { ++ DPRINT_WARN(STORVSC, "cmd 0x%x scsi status 0x%x srb status 0x%x\n", ++ request->Cdb[0], ++ VStorPacket->VmSrb.ScsiStatus, ++ VStorPacket->VmSrb.SrbStatus); ++ } ++ ++ if ((request->Status & 0xFF) == 0x02) // CHECK_CONDITION ++ { ++ if (VStorPacket->VmSrb.SrbStatus & 0x80) // autosense data available ++ { ++ DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data valid - len %d\n", ++ RequestExt, VStorPacket->VmSrb.SenseInfoLength); ++ ++ ASSERT(VStorPacket->VmSrb.SenseInfoLength <= request->SenseBufferSize); ++ memcpy(request->SenseBuffer, ++ VStorPacket->VmSrb.SenseData, ++ VStorPacket->VmSrb.SenseInfoLength); ++ ++ request->SenseBufferSize = VStorPacket->VmSrb.SenseInfoLength; ++ } ++ } ++ ++ // TODO: ++ request->BytesXfer = VStorPacket->VmSrb.DataTransferLength; ++ ++ request->OnIOCompletion(request); ++ ++ InterlockedDecrement(&storDevice->NumOutstandingRequests); ++ ++ PutStorDevice(Device); ++ ++ DPRINT_EXIT(STORVSC); ++} ++ ++ ++static void ++StorVscOnReceive( ++ DEVICE_OBJECT *Device, ++ VSTOR_PACKET *VStorPacket, ++ STORVSC_REQUEST_EXTENSION *RequestExt ++ ) ++{ ++ switch(VStorPacket->Operation) ++ { ++ case VStorOperationCompleteIo: ++ ++ DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION"); ++ StorVscOnIOCompletion(Device, VStorPacket, RequestExt); ++ break; ++ ++ //case ENUMERATE_DEVICE_OPERATION: ++ ++ // DPRINT_INFO(STORVSC, "ENUMERATE_DEVICE_OPERATION"); ++ ++ // StorVscOnTargetRescan(Device); ++ // break; ++ ++ case VStorOperationRemoveDevice: ++ ++ DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION"); ++ // TODO: ++ break; ++ ++ default: ++ DPRINT_INFO(STORVSC, "Unknown operation received - %d", VStorPacket->Operation); ++ break; ++ } ++} ++ ++void ++StorVscOnChannelCallback( ++ PVOID Context ++ ) ++{ ++ int ret=0; ++ DEVICE_OBJECT *device = (DEVICE_OBJECT*)Context; ++ STORVSC_DEVICE *storDevice; ++ UINT32 bytesRecvd; ++ UINT64 requestId; ++ UCHAR packet[ALIGN_UP(sizeof(VSTOR_PACKET),8)]; ++ STORVSC_REQUEST_EXTENSION *request; ++ ++ DPRINT_ENTER(STORVSC); ++ ++ ASSERT(device); ++ ++ storDevice = MustGetStorDevice(device); ++ if (!storDevice) ++ { ++ DPRINT_ERR(STORVSC, "unable to get stor device...device being destroyed?"); ++ DPRINT_EXIT(STORVSC); ++ return; ++ } ++ ++ do ++ { ++ ret = device->Driver->VmbusChannelInterface.RecvPacket(device, ++ packet, ++ ALIGN_UP(sizeof(VSTOR_PACKET),8), ++ &bytesRecvd, ++ &requestId); ++ if (ret == 0 && bytesRecvd > 0) ++ { ++ DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx", bytesRecvd, requestId); ++ ++ //ASSERT(bytesRecvd == sizeof(VSTOR_PACKET)); ++ ++ request = (STORVSC_REQUEST_EXTENSION*)(ULONG_PTR)requestId; ++ ASSERT(request); ++ ++ //if (vstorPacket.Flags & SYNTHETIC_FLAG) ++ if ((request == &storDevice->InitRequest) || (request == &storDevice->ResetRequest)) ++ { ++ //DPRINT_INFO(STORVSC, "reset completion - operation %u status %u", vstorPacket.Operation, vstorPacket.Status); ++ ++ memcpy(&request->VStorPacket, packet, sizeof(VSTOR_PACKET)); ++ ++ WaitEventSet(request->WaitEvent); ++ } ++ else ++ { ++ StorVscOnReceive(device, (VSTOR_PACKET*)packet, request); ++ } ++ } ++ else ++ { ++ //DPRINT_DBG(STORVSC, "nothing else to read..."); ++ break; ++ } ++ } while (1); ++ ++ PutStorDevice(device); ++ ++ DPRINT_EXIT(STORVSC); ++ return; ++} +--- /dev/null ++++ b/drivers/staging/hv/storvsc_drv.c +@@ -0,0 +1,1413 @@ ++/* ++ * ++ * Copyright (c) 2009, Microsoft Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Authors: ++ * Haiyang Zhang ++ * Hank Janssen ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef KERNEL_2_6_5 ++#else ++#include ++#endif ++ ++#include "logging.h" ++#include "vmbus.h" ++ ++#include "StorVscApi.h" ++ ++// ++// #defines ++// ++ ++// ++// Data types ++// ++struct host_device_context { ++ struct work_struct host_rescan_work; //must be 1st field ++ struct device_context *device_ctx; // point back to our device context ++#ifdef KERNEL_2_6_27 ++ struct kmem_cache *request_pool; ++#else ++ kmem_cache_t *request_pool; ++#endif ++ unsigned int port; ++ unsigned char path; ++ unsigned char target; ++}; ++ ++struct storvsc_cmd_request { ++ struct list_head entry; ++ struct scsi_cmnd *cmd; ++ ++ unsigned int bounce_sgl_count; ++ struct scatterlist *bounce_sgl; ++ ++ STORVSC_REQUEST request; ++ // !!!DO NOT ADD ANYTHING BELOW HERE!!! ++ // The extension buffer falls right here and is pointed to by request.Extension; ++}; ++ ++struct storvsc_driver_context { ++ // !! These must be the first 2 fields !! ++ struct driver_context drv_ctx; ++ STORVSC_DRIVER_OBJECT drv_obj; ++}; ++ ++// Static decl ++static int storvsc_probe(struct device *dev); ++static int storvsc_queuecommand(struct scsi_cmnd *scmnd, void (*done)(struct scsi_cmnd *)); ++static int storvsc_device_alloc(struct scsi_device *); ++static int storvsc_device_configure(struct scsi_device *); ++static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd); ++#ifdef KERNEL_2_6_27 ++static void storvsc_host_rescan_callback(struct work_struct *work); ++#else ++static void storvsc_host_rescan_callback(void* context); ++#endif ++static void storvsc_host_rescan(DEVICE_OBJECT* device_obj); ++static int storvsc_remove(struct device *dev); ++ ++static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count, unsigned int len); ++static void destroy_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count); ++static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count); ++static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, struct scatterlist *bounce_sgl, unsigned int orig_sgl_count); ++static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, struct scatterlist *bounce_sgl, unsigned int orig_sgl_count); ++ ++static int storvsc_report_luns(struct scsi_device *sdev, unsigned int luns[], unsigned int *lun_count); ++static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, sector_t capacity, int *info); ++ ++ ++static int storvsc_ringbuffer_size = STORVSC_RING_BUFFER_SIZE; ++ ++// The one and only one ++static struct storvsc_driver_context g_storvsc_drv; ++ ++// Scsi driver ++static struct scsi_host_template scsi_driver = { ++ .module = THIS_MODULE, ++ .name = "storvsc_host_t", ++ .bios_param = storvsc_get_chs, ++ .queuecommand = storvsc_queuecommand, ++ .eh_host_reset_handler = storvsc_host_reset_handler, ++ .slave_alloc = storvsc_device_alloc, ++ .slave_configure = storvsc_device_configure, ++ .cmd_per_lun = 1, ++ .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS, // 64 max_queue * 1 target ++ .this_id = -1, ++ // no use setting to 0 since ll_blk_rw reset it to 1 ++ .sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT,// currently 32 ++ // ENABLE_CLUSTERING allows mutiple physically contig bio_vecs to merge into 1 sg element. If set, we must ++ // limit the max_segment_size to PAGE_SIZE, otherwise we may get 1 sg element that represents multiple ++ // physically contig pfns (ie sg[x].length > PAGE_SIZE). ++ .use_clustering = ENABLE_CLUSTERING, ++ // Make sure we dont get a sg segment crosses a page boundary ++ .dma_boundary = PAGE_SIZE-1, ++}; ++ ++ ++/*++ ++ ++Name: storvsc_drv_init() ++ ++Desc: StorVsc driver initialization. ++ ++--*/ ++int storvsc_drv_init(PFN_DRIVERINITIALIZE pfn_drv_init) ++{ ++ int ret=0; ++ STORVSC_DRIVER_OBJECT *storvsc_drv_obj=&g_storvsc_drv.drv_obj; ++ struct driver_context *drv_ctx=&g_storvsc_drv.drv_ctx; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ vmbus_get_interface(&storvsc_drv_obj->Base.VmbusChannelInterface); ++ ++ storvsc_drv_obj->RingBufferSize = storvsc_ringbuffer_size; ++ storvsc_drv_obj->OnHostRescan = storvsc_host_rescan; ++ ++ // Callback to client driver to complete the initialization ++ pfn_drv_init(&storvsc_drv_obj->Base); ++ ++ DPRINT_INFO(STORVSC_DRV, "request extension size %u, max outstanding reqs %u", storvsc_drv_obj->RequestExtSize, storvsc_drv_obj->MaxOutstandingRequestsPerChannel); ++ ++ if (storvsc_drv_obj->MaxOutstandingRequestsPerChannel < STORVSC_MAX_IO_REQUESTS) ++ { ++ DPRINT_ERR(STORVSC_DRV, "The number of outstanding io requests (%d) is larger than that supported (%d) internally.", ++ STORVSC_MAX_IO_REQUESTS, storvsc_drv_obj->MaxOutstandingRequestsPerChannel); ++ return -1; ++ } ++ ++ drv_ctx->driver.name = storvsc_drv_obj->Base.name; ++ memcpy(&drv_ctx->class_id, &storvsc_drv_obj->Base.deviceType, sizeof(GUID)); ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++ drv_ctx->driver.probe = storvsc_probe; ++ drv_ctx->driver.remove = storvsc_remove; ++#else ++ drv_ctx->probe = storvsc_probe; ++ drv_ctx->remove = storvsc_remove; ++#endif ++ ++ // The driver belongs to vmbus ++ vmbus_child_driver_register(drv_ctx); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return ret; ++} ++ ++ ++static int storvsc_drv_exit_cb(struct device *dev, void *data) ++{ ++ struct device **curr = (struct device **)data; ++ *curr = dev; ++ return 1; // stop iterating ++} ++ ++/*++ ++ ++Name: storvsc_drv_exit() ++ ++Desc: ++ ++--*/ ++void storvsc_drv_exit(void) ++{ ++ STORVSC_DRIVER_OBJECT *storvsc_drv_obj=&g_storvsc_drv.drv_obj; ++ struct driver_context *drv_ctx=&g_storvsc_drv.drv_ctx; ++ ++ struct device *current_dev=NULL; ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#define driver_for_each_device(drv, start, data, fn) \ ++ struct list_head *ptr, *n; \ ++ list_for_each_safe(ptr, n, &((drv)->devices)) {\ ++ struct device *curr_dev;\ ++ curr_dev = list_entry(ptr, struct device, driver_list);\ ++ fn(curr_dev, data);\ ++ } ++#endif // KERNEL_2_6_9 ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ while (1) ++ { ++ current_dev = NULL; ++ ++ // Get the device ++ driver_for_each_device(&drv_ctx->driver, NULL, (void*)¤t_dev, storvsc_drv_exit_cb); ++ ++ if (current_dev == NULL) ++ break; ++ ++ // Initiate removal from the top-down ++ device_unregister(current_dev); ++ } ++ ++ if (storvsc_drv_obj->Base.OnCleanup) ++ storvsc_drv_obj->Base.OnCleanup(&storvsc_drv_obj->Base); ++ ++ vmbus_child_driver_unregister(drv_ctx); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return; ++} ++ ++/*++ ++ ++Name: storvsc_probe() ++ ++Desc: Add a new device for this driver ++ ++--*/ ++static int storvsc_probe(struct device *device) ++{ ++ int ret=0; ++ ++ struct driver_context *driver_ctx = driver_to_driver_context(device->driver); ++ struct storvsc_driver_context *storvsc_drv_ctx = (struct storvsc_driver_context*)driver_ctx; ++ STORVSC_DRIVER_OBJECT* storvsc_drv_obj = &storvsc_drv_ctx->drv_obj; ++ ++ struct device_context *device_ctx = device_to_device_context(device); ++ DEVICE_OBJECT* device_obj = &device_ctx->device_obj; ++ ++ struct Scsi_Host *host; ++ struct host_device_context *host_device_ctx; ++ STORVSC_DEVICE_INFO device_info; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ if (!storvsc_drv_obj->Base.OnDeviceAdd) ++ return -1; ++ ++ host = scsi_host_alloc(&scsi_driver, sizeof(struct host_device_context)); ++ if (!host) ++ { ++ DPRINT_ERR(STORVSC_DRV, "unable to allocate scsi host object"); ++ return -ENOMEM; ++ } ++ ++ device->driver_data = host; ++ ++ host_device_ctx = (struct host_device_context*)host->hostdata; ++ memset(host_device_ctx, 0, sizeof(struct host_device_context)); ++ ++ host_device_ctx->port = host->host_no; ++ host_device_ctx->device_ctx = device_ctx; ++ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#elif defined(KERNEL_2_6_27) ++ INIT_WORK(&host_device_ctx->host_rescan_work, storvsc_host_rescan_callback); ++#else ++ INIT_WORK(&host_device_ctx->host_rescan_work, storvsc_host_rescan_callback, device_obj); ++#endif ++ ++#if defined(KERNEL_2_6_27) ++ host_device_ctx->request_pool = ++ kmem_cache_create ++ (device_ctx->device.bus_id, ++ sizeof(struct storvsc_cmd_request) + storvsc_drv_obj->RequestExtSize, ++ 0, ++ SLAB_HWCACHE_ALIGN, NULL); ++#else ++ host_device_ctx->request_pool = ++ kmem_cache_create ++ (device_ctx->device.bus_id, ++ sizeof(struct storvsc_cmd_request) + storvsc_drv_obj->RequestExtSize, ++ 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++#endif ++ ++ if (!host_device_ctx->request_pool) ++ { ++ scsi_host_put(host); ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return -ENOMEM; ++ } ++ ++ device_info.PortNumber = host->host_no; ++ // Call to the vsc driver to add the device ++ ret = storvsc_drv_obj->Base.OnDeviceAdd(device_obj, (void*)&device_info); ++ if (ret != 0) ++ { ++ DPRINT_ERR(STORVSC_DRV, "unable to add scsi vsc device"); ++ kmem_cache_destroy(host_device_ctx->request_pool); ++ scsi_host_put(host); ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return -1; ++ } ++ ++ //host_device_ctx->port = device_info.PortNumber; ++ host_device_ctx->path = device_info.PathId; ++ host_device_ctx->target = device_info.TargetId; ++ ++ host->max_lun = STORVSC_MAX_LUNS_PER_TARGET; // max # of devices per target ++ host->max_id = STORVSC_MAX_TARGETS; // max # of targets per channel ++ host->max_channel = STORVSC_MAX_CHANNELS -1; // max # of channels ++ ++ // Register the HBA and start the scsi bus scan ++ ret = scsi_add_host(host, device); ++ if (ret != 0) ++ { ++ DPRINT_ERR(STORVSC_DRV, "unable to add scsi host device"); ++ ++ storvsc_drv_obj->Base.OnDeviceRemove(device_obj); ++ ++ kmem_cache_destroy(host_device_ctx->request_pool); ++ scsi_host_put(host); ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return -1; ++ } ++ ++ scsi_scan_host(host); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return ret; ++} ++ ++ ++/*++ ++ ++Name: storvsc_remove() ++ ++Desc: Callback when our device is removed ++ ++--*/ ++static int storvsc_remove(struct device *device) ++{ ++ int ret=0; ++ ++ struct driver_context *driver_ctx = driver_to_driver_context(device->driver); ++ struct storvsc_driver_context *storvsc_drv_ctx = (struct storvsc_driver_context*)driver_ctx; ++ STORVSC_DRIVER_OBJECT* storvsc_drv_obj = &storvsc_drv_ctx->drv_obj; ++ ++ struct device_context *device_ctx = device_to_device_context(device); ++ DEVICE_OBJECT* device_obj = &device_ctx->device_obj; ++ ++ struct Scsi_Host *host = (struct Scsi_Host *)device->driver_data; ++ struct host_device_context *host_device_ctx=(struct host_device_context*)host->hostdata; ++ ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ if (!storvsc_drv_obj->Base.OnDeviceRemove) ++ { ++ DPRINT_EXIT(STORVSC_DRV); ++ return -1; ++ } ++ ++ // Call to the vsc driver to let it know that the device is being removed ++ ret = storvsc_drv_obj->Base.OnDeviceRemove(device_obj); ++ if (ret != 0) ++ { ++ // TODO: ++ DPRINT_ERR(STORVSC, "unable to remove vsc device (ret %d)", ret); ++ } ++ ++ if (host_device_ctx->request_pool) ++ { ++ kmem_cache_destroy(host_device_ctx->request_pool); ++ host_device_ctx->request_pool = NULL; ++ } ++ ++ DPRINT_INFO(STORVSC, "removing host adapter (%p)...", host); ++ scsi_remove_host(host); ++ ++ DPRINT_INFO(STORVSC, "releasing host adapter (%p)...", host); ++ scsi_host_put(host); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: storvsc_commmand_completion() ++ ++Desc: Command completion processing ++ ++--*/ ++static void storvsc_commmand_completion(STORVSC_REQUEST* request) ++{ ++ struct storvsc_cmd_request *cmd_request = (struct storvsc_cmd_request*)request->Context; ++ struct scsi_cmnd *scmnd = cmd_request->cmd; ++ struct host_device_context *host_device_ctx = (struct host_device_context*)scmnd->device->host->hostdata; ++ void (*scsi_done_fn)(struct scsi_cmnd *); ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#else ++ struct scsi_sense_hdr sense_hdr; ++#endif ++ ++ ASSERT(request == &cmd_request->request); ++ ASSERT((unsigned long)scmnd->host_scribble == (unsigned long)cmd_request); ++ ASSERT(scmnd); ++ ASSERT(scmnd->scsi_done); ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ if (cmd_request->bounce_sgl_count)// using bounce buffer ++ { ++ //printk("copy_from_bounce_buffer\n"); ++ ++ // FIXME: We can optimize on writes by just skipping this ++#ifdef KERNEL_2_6_27 ++ copy_from_bounce_buffer(scsi_sglist(scmnd), cmd_request->bounce_sgl, scsi_sg_count(scmnd)); ++#else ++ copy_from_bounce_buffer(scmnd->request_buffer, cmd_request->bounce_sgl, scmnd->use_sg); ++#endif ++ destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); ++ } ++ ++ scmnd->result = request->Status; ++ ++ if (scmnd->result) ++ { ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++ DPRINT_INFO(STORVSC_DRV, "scsi result nonzero - %d", scmnd->result); ++#else ++ if (scsi_normalize_sense(scmnd->sense_buffer, request->SenseBufferSize, &sense_hdr)) ++ { ++ scsi_print_sense_hdr("storvsc", &sense_hdr); ++ } ++#endif ++ } ++ ++ ASSERT(request->BytesXfer <= request->DataBuffer.Length); ++#ifdef KERNEL_2_6_27 ++ scsi_set_resid(scmnd, request->DataBuffer.Length - request->BytesXfer); ++#else ++ scmnd->resid = request->DataBuffer.Length - request->BytesXfer; ++#endif ++ ++ scsi_done_fn = scmnd->scsi_done; ++ ++ scmnd->host_scribble = NULL; ++ scmnd->scsi_done = NULL; ++ ++ // !!DO NOT MODIFY the scmnd after this call ++ scsi_done_fn(scmnd); ++ ++ kmem_cache_free(host_device_ctx->request_pool, cmd_request); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++} ++ ++static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) ++{ ++ int i=0; ++ ++ // No need to check ++ if (sg_count < 2) ++ return -1; ++ ++ // We have at least 2 sg entries ++ for ( i=0; i> PAGE_SHIFT; ++ ++ bounce_sgl = kzalloc(num_pages * sizeof(struct scatterlist), GFP_ATOMIC); ++ if (!bounce_sgl) ++ { ++ return NULL; ++ } ++ ++ for(i=0; idevice->host->hostdata; ++ struct device_context *device_ctx=host_device_ctx->device_ctx; ++ struct driver_context *driver_ctx = driver_to_driver_context(device_ctx->device.driver); ++ struct storvsc_driver_context *storvsc_drv_ctx = (struct storvsc_driver_context*)driver_ctx; ++ STORVSC_DRIVER_OBJECT* storvsc_drv_obj = &storvsc_drv_ctx->drv_obj; ++ ++ STORVSC_REQUEST *request; ++ struct storvsc_cmd_request *cmd_request; ++ unsigned int request_size=0; ++ int i; ++ struct scatterlist *sgl; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++#ifdef KERNEL_2_6_27 ++ DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d queue depth %d tagged %d", ++ scmnd, ++ scmnd->sc_data_direction, ++ scsi_sg_count(scmnd), ++ scsi_sglist(scmnd), ++ scsi_bufflen(scmnd), ++ scmnd->device->queue_depth, ++ scmnd->device->tagged_supported); ++#else ++ DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d queue depth %d tagged %d", ++ scmnd, ++ scmnd->sc_data_direction, ++ scmnd->use_sg, ++ scmnd->request_buffer, ++ scmnd->request_bufflen, ++ scmnd->device->queue_depth, ++ scmnd->device->tagged_supported); ++#endif ++ ++ // If retrying, no need to prep the cmd ++ if (scmnd->host_scribble) ++ { ++ ASSERT(scmnd->scsi_done != NULL); ++ ++ cmd_request = (struct storvsc_cmd_request* )scmnd->host_scribble; ++ DPRINT_INFO(STORVSC_DRV, "retrying scmnd %p cmd_request %p", scmnd, cmd_request); ++ ++ goto retry_request; ++ } ++ ++ ASSERT(scmnd->scsi_done == NULL); ++ ASSERT(scmnd->host_scribble == NULL); ++ ++ scmnd->scsi_done = done; ++ ++ request_size = sizeof(struct storvsc_cmd_request); ++ ++ cmd_request = kmem_cache_alloc(host_device_ctx->request_pool, GFP_ATOMIC); ++ if (!cmd_request) ++ { ++ DPRINT_ERR(STORVSC_DRV, "scmnd (%p) - unable to allocate storvsc_cmd_request...marking queue busy", scmnd); ++ ++ scmnd->scsi_done = NULL; ++ return SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ ++ // Setup the cmd request ++ cmd_request->bounce_sgl_count = 0; ++ cmd_request->bounce_sgl = NULL; ++ cmd_request->cmd = scmnd; ++ ++ scmnd->host_scribble = (unsigned char*)cmd_request; ++ ++ request = &cmd_request->request; ++ ++ request->Extension = (void*)((unsigned long)cmd_request + request_size); ++ DPRINT_DBG(STORVSC_DRV, "req %p size %d ext %d", request, request_size, storvsc_drv_obj->RequestExtSize); ++ ++ // Build the SRB ++ switch(scmnd->sc_data_direction) ++ { ++ case DMA_TO_DEVICE: ++ request->Type = WRITE_TYPE; ++ break; ++ case DMA_FROM_DEVICE: ++ request->Type = READ_TYPE; ++ break; ++ default: ++ request->Type = UNKNOWN_TYPE; ++ break; ++ } ++ ++ request->OnIOCompletion = storvsc_commmand_completion; ++ request->Context = cmd_request;//scmnd; ++ ++ //request->PortId = scmnd->device->channel; ++ request->Host = host_device_ctx->port; ++ request->Bus = scmnd->device->channel; ++ request->TargetId = scmnd->device->id; ++ request->LunId = scmnd->device->lun; ++ ++ ASSERT(scmnd->cmd_len <= 16); ++ request->CdbLen = scmnd->cmd_len; ++ request->Cdb = scmnd->cmnd; ++ ++ request->SenseBuffer = scmnd->sense_buffer; ++ request->SenseBufferSize = SCSI_SENSE_BUFFERSIZE; ++ ++ ++#ifdef KERNEL_2_6_27 ++ request->DataBuffer.Length = scsi_bufflen(scmnd); ++ if (scsi_sg_count(scmnd)) ++#else ++ request->DataBuffer.Length = scmnd->request_bufflen; ++ if (scmnd->use_sg) ++#endif ++ { ++#ifdef KERNEL_2_6_27 ++ sgl = (struct scatterlist*)scsi_sglist(scmnd); ++#else ++ sgl = (struct scatterlist*)(scmnd->request_buffer); ++#endif ++ ++ // check if we need to bounce the sgl ++#ifdef KERNEL_2_6_27 ++ if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) ++#else ++ if (do_bounce_buffer(sgl, scmnd->use_sg) != -1) ++#endif ++ { ++ DPRINT_INFO(STORVSC_DRV, "need to bounce buffer for this scmnd %p", scmnd); ++#ifdef KERNEL_2_6_27 ++ cmd_request->bounce_sgl = create_bounce_buffer(sgl, scsi_sg_count(scmnd), scsi_bufflen(scmnd)); ++#else ++ cmd_request->bounce_sgl = create_bounce_buffer( ++ sgl, ++ scmnd->use_sg, scmnd->request_bufflen); ++#endif ++ if (!cmd_request->bounce_sgl) ++ { ++ DPRINT_ERR(STORVSC_DRV, "unable to create bounce buffer for this scmnd %p", scmnd); ++ ++ scmnd->scsi_done = NULL; ++ scmnd->host_scribble = NULL; ++ kmem_cache_free(host_device_ctx->request_pool, cmd_request); ++ ++ return SCSI_MLQUEUE_HOST_BUSY; ++ } ++ ++#ifdef KERNEL_2_6_27 ++ cmd_request->bounce_sgl_count = ALIGN_UP(scsi_bufflen(scmnd), PAGE_SIZE) >> PAGE_SHIFT; ++#else ++ cmd_request->bounce_sgl_count = ALIGN_UP(scmnd->request_bufflen, PAGE_SIZE) >> PAGE_SHIFT; ++#endif ++ ++ //printk("bouncing buffer allocated %p original buffer %p\n", bounce_sgl, sgl); ++ //printk("copy_to_bounce_buffer\n"); ++ // FIXME: We can optimize on reads by just skipping this ++#ifdef KERNEL_2_6_27 ++ copy_to_bounce_buffer(sgl, cmd_request->bounce_sgl, scsi_sg_count(scmnd)); ++#else ++ copy_to_bounce_buffer(sgl, cmd_request->bounce_sgl, scmnd->use_sg); ++#endif ++ ++ sgl = cmd_request->bounce_sgl; ++ } ++ ++ request->DataBuffer.Offset = sgl[0].offset; ++ ++#ifdef KERNEL_2_6_27 ++ for (i = 0; i < scsi_sg_count(scmnd); i++ ) ++#else ++ for (i = 0; i < scmnd->use_sg; i++ ) ++#endif ++ { ++ DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d \n", i, sgl[i].length, sgl[i].offset); ++#ifdef KERNEL_2_6_27 ++ request->DataBuffer.PfnArray[i] = page_to_pfn(sg_page((&sgl[i]))); ++#else ++ request->DataBuffer.PfnArray[i] = page_to_pfn(sgl[i].page); ++#endif ++ } ++ } ++ ++#ifdef KERNEL_2_6_27 ++ else if (scsi_sglist(scmnd)) ++ { ++ ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); ++ request->DataBuffer.Offset = virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1); ++ request->DataBuffer.PfnArray[0] = virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; ++ } ++ else ++ { ++ ASSERT(scsi_bufflen(scmnd) == 0); ++ } ++#else ++ else if (scmnd->request_buffer) ++ { ++ ASSERT(scmnd->request_bufflen <= PAGE_SIZE); ++ request->DataBuffer.Offset = virt_to_phys(scmnd->request_buffer) & (PAGE_SIZE-1); ++ request->DataBuffer.PfnArray[0] = virt_to_phys(scmnd->request_buffer) >> PAGE_SHIFT; ++ } ++ else ++ { ++ ASSERT(scmnd->request_bufflen == 0); ++ } ++#endif ++ ++retry_request: ++ ++ // Invokes the vsc to start an IO ++ ret = storvsc_drv_obj->OnIORequest(&device_ctx->device_obj, &cmd_request->request); ++ if (ret == -1) // no more space ++ { ++ DPRINT_ERR(STORVSC_DRV, "scmnd (%p) - queue FULL...marking queue busy", scmnd); ++ ++ if (cmd_request->bounce_sgl_count) ++ { ++ // FIXME: We can optimize on writes by just skipping this ++#ifdef KERNEL_2_6_27 ++ copy_from_bounce_buffer(scsi_sglist(scmnd), cmd_request->bounce_sgl, scsi_sg_count(scmnd)); ++#else ++ copy_from_bounce_buffer( ++ scmnd->request_buffer, ++ cmd_request->bounce_sgl, ++ scmnd->use_sg); ++#endif ++ destroy_bounce_buffer(cmd_request->bounce_sgl, cmd_request->bounce_sgl_count); ++ } ++ ++ kmem_cache_free(host_device_ctx->request_pool, cmd_request); ++ ++ scmnd->scsi_done = NULL; ++ scmnd->host_scribble = NULL; ++ ++ ret = SCSI_MLQUEUE_DEVICE_BUSY; ++ } ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return ret; ++} ++ ++#ifdef KERNEL_2_6_27 ++static int storvsc_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, struct bio_vec *bvec) ++{ ++ return bvec->bv_len; //checking done by caller. ++} ++#else ++static int storvsc_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec) ++{ ++ // Check if we are adding a new bvec ++ if (bio->bi_vcnt > 0) ++ { ++ //printk("storvsc_merge_bvec() - cnt %u offset %u len %u\n", bio->bi_vcnt, bvec->bv_offset, bvec->bv_len); ++ ++ struct bio_vec *prev = &bio->bi_io_vec[bio->bi_vcnt - 1]; ++ if (bvec == prev) ++ return bvec->bv_len; // success ++ ++ // Adding new bvec. Make sure the prev one is a complete page ++ if (prev->bv_len == PAGE_SIZE && prev->bv_offset == 0) ++ { ++ return bvec->bv_len; // success ++ } ++ else ++ { ++ // Dont reject if the new bvec starts off from the prev one since ++ // they will be merge into 1 bvec or blk_rq_map_sg() will merge them into 1 sg element ++ if ((bvec->bv_page == prev->bv_page) && ++ (bvec->bv_offset == prev->bv_offset + prev->bv_len)) ++ { ++ return bvec->bv_len; // success ++ } ++ else ++ { ++ DPRINT_INFO(STORVSC_DRV, "detected holes in bio request (%p) - cnt %u offset %u len %u", bio, bio->bi_vcnt, bvec->bv_offset, bvec->bv_len); ++ return 0; // dont add the bvec to this bio since we dont allow holes in the middle of a multi-pages bio ++ } ++ } ++ } ++ ++ return bvec->bv_len; // success ++ ++} ++ ++#endif ++ ++/*++ ++ ++Name: storvsc_device_configure() ++ ++Desc: Configure the specified scsi device ++ ++--*/ ++static int storvsc_device_alloc(struct scsi_device *sdevice) ++{ ++#ifdef KERNEL_2_6_5 ++#else ++ DPRINT_DBG(STORVSC_DRV, "sdev (%p) - setting device flag to %d", sdevice, BLIST_SPARSELUN); ++ // This enables luns to be located sparsely. Otherwise, we may not discovered them. ++ sdevice->sdev_bflags |= BLIST_SPARSELUN | BLIST_LARGELUN; ++#endif ++ return 0; ++} ++ ++static int storvsc_device_configure(struct scsi_device *sdevice) ++{ ++ DPRINT_INFO(STORVSC_DRV, "sdev (%p) - curr queue depth %d", sdevice, sdevice->queue_depth); ++ ++ DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting queue depth to %d", sdevice, STORVSC_MAX_IO_REQUESTS); ++ scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG, STORVSC_MAX_IO_REQUESTS); ++ ++ DPRINT_INFO(STORVSC_DRV, "sdev (%p) - setting max segment size to %d", sdevice, PAGE_SIZE); ++ blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); ++ ++ DPRINT_INFO(STORVSC_DRV, "sdev (%p) - adding merge bio vec routine", sdevice); ++ blk_queue_merge_bvec(sdevice->request_queue, storvsc_merge_bvec); ++ ++ blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); ++ //sdevice->timeout = (2000 * HZ);//(75 * HZ); ++ ++ return 0; ++} ++ ++/*++ ++ ++Name: storvsc_host_reset_handler() ++ ++Desc: Reset the scsi HBA ++ ++--*/ ++static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) ++{ ++ int ret=SUCCESS; ++ struct host_device_context *host_device_ctx = (struct host_device_context*)scmnd->device->host->hostdata; ++ struct device_context *device_ctx = host_device_ctx->device_ctx; ++ struct driver_context *driver_ctx = driver_to_driver_context(device_ctx->device.driver); ++ struct storvsc_driver_context *storvsc_drv_ctx = (struct storvsc_driver_context*)driver_ctx; ++ ++ STORVSC_DRIVER_OBJECT *storvsc_drv_obj = &storvsc_drv_ctx->drv_obj; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host resetting...", scmnd->device, &device_ctx->device_obj); ++ ++ // Invokes the vsc to reset the host/bus ++ ASSERT(storvsc_drv_obj->OnHostReset); ++ ret = storvsc_drv_obj->OnHostReset(&device_ctx->device_obj); ++ if (ret != 0) ++ { ++ DPRINT_EXIT(STORVSC_DRV); ++ return ret; ++ } ++ ++ DPRINT_INFO(STORVSC_DRV, "sdev (%p) dev obj (%p) - host reseted", scmnd->device, &device_ctx->device_obj); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return ret; ++} ++ ++/*++ ++ ++Name: storvsc_host_rescan ++ ++Desc: Rescan the scsi HBA ++ ++--*/ ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#else ++ ++#ifdef KERNEL_2_6_27 ++static void storvsc_host_rescan_callback(struct work_struct *work) ++{ ++ DEVICE_OBJECT* device_obj = ++ &((struct host_device_context*)work)->device_ctx->device_obj; ++#else ++static void storvsc_host_rescan_callback(void* context) ++{ ++ ++ DEVICE_OBJECT* device_obj = (DEVICE_OBJECT*)context; ++#endif ++ struct device_context* device_ctx = to_device_context(device_obj); ++ struct Scsi_Host *host = (struct Scsi_Host *)device_ctx->device.driver_data; ++ struct scsi_device *sdev; ++ struct host_device_context *host_device_ctx; ++ struct scsi_device **sdevs_remove_list; ++ unsigned int sdevs_count=0; ++ unsigned int found; ++ unsigned int i; ++ unsigned int lun_count=0; ++ unsigned int *lun_list; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ host_device_ctx = (struct host_device_context*)host->hostdata; ++ lun_list = kzalloc(sizeof(unsigned int)*STORVSC_MAX_LUNS_PER_TARGET, GFP_ATOMIC); ++ if (!lun_list) ++ { ++ DPRINT_ERR(STORVSC_DRV, "unable to allocate lun list"); ++ return; ++ } ++ ++ sdevs_remove_list = kzalloc(sizeof(void*)*STORVSC_MAX_LUNS_PER_TARGET, GFP_ATOMIC); ++ if (!sdevs_remove_list) ++ { ++ kfree(lun_list); ++ DPRINT_ERR(STORVSC_DRV, "unable to allocate lun remove list"); ++ return; ++ } ++ ++ DPRINT_INFO(STORVSC_DRV, "rescanning host for new scsi devices...", device_obj, host_device_ctx->target, host_device_ctx->path); ++ ++ // Rescan for new device ++ scsi_scan_target(&host->shost_gendev, host_device_ctx->path, host_device_ctx->target, SCAN_WILD_CARD, 1); ++ ++ DPRINT_INFO(STORVSC_DRV, "rescanning host for removed scsi device..."); ++ ++ // Use the 1st device to send the report luns cmd ++ shost_for_each_device(sdev, host) ++ { ++ lun_count=STORVSC_MAX_LUNS_PER_TARGET; ++ storvsc_report_luns(sdev, lun_list, &lun_count); ++ ++ DPRINT_INFO(STORVSC_DRV, "report luns on scsi device (%p) found %u luns ", sdev, lun_count); ++ DPRINT_INFO(STORVSC_DRV, "existing luns on scsi device (%p) host (%d)", sdev, host->host_no); ++ ++ scsi_device_put(sdev); ++ break; ++ } ++ ++ for (i=0; ilun == lun_list[i]) ++ { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) ++ { ++ DPRINT_INFO(STORVSC_DRV, "lun (%u) does not exists", sdev->lun); ++ sdevs_remove_list[sdevs_count++] = sdev; ++ } ++ } ++ ++ // Now remove the devices ++ for (i=0; i< sdevs_count; i++) ++ { ++ DPRINT_INFO(STORVSC_DRV, "removing scsi device (%p) lun (%u)...", ++ sdevs_remove_list[i], sdevs_remove_list[i]->lun); ++ ++ // make sure it is not removed from underneath us ++ if (!scsi_device_get(sdevs_remove_list[i])) ++ { ++ scsi_remove_device(sdevs_remove_list[i]); ++ scsi_device_put(sdevs_remove_list[i]); ++ } ++ } ++ ++ DPRINT_INFO(STORVSC_DRV, "rescan completed on dev obj (%p) target (%u) bus (%u)", device_obj, host_device_ctx->target, host_device_ctx->path); ++ ++ kfree(lun_list); ++ kfree(sdevs_remove_list); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++} ++ ++static int storvsc_report_luns(struct scsi_device *sdev, unsigned int luns[], unsigned int *lun_count) ++{ ++ int i,j; ++ unsigned int lun=0; ++ unsigned int num_luns; ++ int result; ++ unsigned char *data; ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++#else ++ struct scsi_sense_hdr sshdr; ++#endif ++ unsigned char cmd[16]={0}; ++ unsigned int report_len = 8*(STORVSC_MAX_LUNS_PER_TARGET+1); // Add 1 to cover the report_lun header ++ unsigned long long *report_luns; ++ const unsigned int in_lun_count = *lun_count; ++ ++ *lun_count = 0; ++ ++ report_luns = kzalloc(report_len, GFP_ATOMIC); ++ if (!report_luns) ++ { ++ return -ENOMEM; ++ } ++ ++ cmd[0] = REPORT_LUNS; ++ ++ // cmd length ++ *(unsigned int*)&cmd[6] = cpu_to_be32(report_len); ++ ++ result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, (unsigned char*)report_luns, report_len, &sshdr, 30*HZ, 3); ++ if (result != 0) ++ { ++ kfree(report_luns); ++ return -EBUSY; ++ } ++ ++ // get the length from the first four bytes ++ report_len = be32_to_cpu(*(unsigned int*)&report_luns[0]); ++ ++ num_luns = (report_len / sizeof(unsigned long long)); ++ if (num_luns > in_lun_count) ++ { ++ kfree(report_luns); ++ return -EINVAL; ++ } ++ ++ *lun_count = num_luns; ++ ++ DPRINT_DBG(STORVSC_DRV, "report luns on scsi device (%p) found %u luns ", sdev, num_luns); ++ ++ // lun id starts at 1 ++ for (i=1; i< num_luns+1; i++) ++ { ++ lun = 0; ++ data = (unsigned char*)&report_luns[i]; ++ for (j = 0; j < sizeof(lun); j += 2) ++ { ++ lun = lun | (((data[j] << 8) | data[j + 1]) << (j * 8)); ++ } ++ ++ luns[i-1] = lun; ++ } ++ ++ kfree(report_luns); ++ return 0; ++} ++#endif // KERNEL_2_6_9 ++ ++static void storvsc_host_rescan(DEVICE_OBJECT* device_obj) ++{ ++ struct device_context* device_ctx = to_device_context(device_obj); ++ struct Scsi_Host *host = (struct Scsi_Host *)device_ctx->device.driver_data; ++ struct host_device_context *host_device_ctx; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++#if defined(KERNEL_2_6_5) || defined(KERNEL_2_6_9) ++ DPRINT_ERR(STORVSC_DRV, "rescan not supported on 2.6.9 kernels!! You will need to reboot if you have added or removed the scsi lun device"); ++#else ++ ++ host_device_ctx = (struct host_device_context*)host->hostdata; ++ ++ DPRINT_INFO(STORVSC_DRV, "initiating rescan on dev obj (%p) target (%u) bus (%u)...", device_obj, host_device_ctx->target, host_device_ctx->path); ++ ++ // We need to queue this since the scanning may block and the caller may be in an intr context ++ //scsi_queue_work(host, &host_device_ctx->host_rescan_work); ++ schedule_work(&host_device_ctx->host_rescan_work); ++#endif // KERNEL_2_6_9 ++ DPRINT_EXIT(STORVSC_DRV); ++} ++ ++static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, sector_t capacity, int *info) ++{ ++ sector_t total_sectors = capacity; ++ sector_t cylinder_times_heads=0; ++ sector_t temp=0; ++ ++ int sectors_per_track=0; ++ int heads=0; ++ int cylinders=0; ++ int rem=0; ++ ++ if (total_sectors > (65535 * 16 * 255)) { ++ total_sectors = (65535 * 16 * 255); ++ } ++ ++ if (total_sectors >= (65535 * 16 * 63)) { ++ sectors_per_track = 255; ++ heads = 16; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ } ++ else ++ { ++ sectors_per_track = 17; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ ++ temp = cylinder_times_heads + 1023; ++ rem = sector_div(temp, 1024); // sector_div stores the quotient in temp ++ ++ heads = temp; ++ ++ if (heads < 4) { ++ heads = 4; ++ } ++ ++ if (cylinder_times_heads >= (heads * 1024) || (heads > 16)) { ++ sectors_per_track = 31; ++ heads = 16; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ } ++ ++ if (cylinder_times_heads >= (heads * 1024)) { ++ sectors_per_track = 63; ++ heads = 16; ++ ++ cylinder_times_heads = total_sectors; ++ rem = sector_div(cylinder_times_heads, sectors_per_track); // sector_div stores the quotient in cylinder_times_heads ++ } ++ } ++ ++ temp = cylinder_times_heads; ++ rem = sector_div(temp, heads); // sector_div stores the quotient in temp ++ cylinders = temp; ++ ++ info[0] = heads; ++ info[1] = sectors_per_track; ++ info[2] = cylinders; ++ ++ DPRINT_INFO(STORVSC_DRV, "CHS (%d, %d, %d)", cylinders, heads, sectors_per_track); ++ ++ return 0; ++} ++ ++MODULE_LICENSE("GPL"); ++ ++static int __init storvsc_init(void) ++{ ++ int ret; ++ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ DPRINT_INFO(STORVSC_DRV, "Storvsc initializing...."); ++ ++ ret = storvsc_drv_init(StorVscInitialize); ++ ++ DPRINT_EXIT(STORVSC_DRV); ++ ++ return ret; ++} ++ ++static void __exit storvsc_exit(void) ++{ ++ DPRINT_ENTER(STORVSC_DRV); ++ ++ storvsc_drv_exit(); ++ ++ DPRINT_ENTER(STORVSC_DRV); ++} ++ ++module_param(storvsc_ringbuffer_size, int, S_IRUGO); ++ ++module_init(storvsc_init); ++module_exit(storvsc_exit); ++ ++// eof diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-blkvsc-fix-up-driver_data-usage.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-blkvsc-fix-up-driver_data-usage.patch new file mode 100644 index 000000000..cbcd1b75d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-blkvsc-fix-up-driver_data-usage.patch @@ -0,0 +1,50 @@ +From foo@baz Fri Jul 24 11:00:10 PDT 2009 +Date: Fri, 24 Jul 2009 11:00:10 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: blkvsc: fix up driver_data usage + +From: Greg Kroah-Hartman + +driver_data is gone now from struct device, so use the proper functions +to access it instead. + +Thanks to Bill Pemberton for pointing out this build error. + +Cc: Bill Pemberton +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/blkvsc_drv.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/staging/hv/blkvsc_drv.c ++++ b/drivers/staging/hv/blkvsc_drv.c +@@ -341,7 +341,7 @@ static int blkvsc_probe(struct device *d + blkdev->target = device_info.TargetId; // this identified the device 0 or 1 + blkdev->path = device_info.PathId; // this identified the ide ctrl 0 or 1 + +- device->driver_data = blkdev; ++ dev_set_drvdata(device, blkdev); + + // Calculate the major and device num + if (blkdev->path == 0) +@@ -457,7 +457,7 @@ Cleanup: + + static void blkvsc_shutdown(struct device *device) + { +- struct block_device_context *blkdev = (struct block_device_context*)device->driver_data; ++ struct block_device_context *blkdev = dev_get_drvdata(device); + unsigned long flags; + + if (!blkdev) +@@ -786,7 +786,7 @@ static int blkvsc_remove(struct device * + + struct device_context *device_ctx = device_to_device_context(device); + DEVICE_OBJECT* device_obj = &device_ctx->device_obj; +- struct block_device_context *blkdev = (struct block_device_context*)device->driver_data; ++ struct block_device_context *blkdev = dev_get_drvdata(device); + unsigned long flags; + + DPRINT_ENTER(BLKVSC_DRV); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-block-driver-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-block-driver-build.patch new file mode 100644 index 000000000..4aa3b3e92 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-block-driver-build.patch @@ -0,0 +1,71 @@ +From foo@baz Tue Jul 14 10:24:38 PDT 2009 +Date: Tue, 14 Jul 2009 10:24:38 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: make the Hyper-V virtual block driver build + +From: Greg Kroah-Hartman + +The #define KERNEL_2_6_27 needs to be set, and I adjusted the include +directories a bit to get things to build properly. + +I also fixed up the direct access of bus_id, as that field is now gone. +Lots of block api changes were needed, and I don't think I got it +all correct. It would be great of someone who knows the block api better +could review it. + +The hv_blkvsc code should now build, with no errors. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/staging/hv/BlkVsc.c | 2 +- + drivers/staging/hv/blkvsc_drv.c | 9 +++++---- + 2 files changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/staging/hv/BlkVsc.c ++++ b/drivers/staging/hv/BlkVsc.c +@@ -21,7 +21,7 @@ + */ + + +-#include "../storvsc/StorVsc.c" ++#include "StorVsc.c" + + static const char* gBlkDriverName="blkvsc"; + +--- a/drivers/staging/hv/blkvsc_drv.c ++++ b/drivers/staging/hv/blkvsc_drv.c +@@ -20,6 +20,7 @@ + * + */ + ++#define KERNEL_2_6_27 + + #include + #include +@@ -34,10 +35,10 @@ + #include + #include + +-#include "logging.h" +-#include "vmbus.h" ++#include "include/logging.h" ++#include "include/vmbus.h" + +-#include "StorVscApi.h" ++#include "include/StorVscApi.h" + + // + // #defines +@@ -313,7 +314,7 @@ static int blkvsc_probe(struct device *d + ASSERT(sizeof(struct blkvsc_request_group) <= sizeof(struct blkvsc_request)); + + #ifdef KERNEL_2_6_27 +- blkdev->request_pool = kmem_cache_create(device_ctx->device.bus_id, ++ blkdev->request_pool = kmem_cache_create(dev_name(&device_ctx->device), + sizeof(struct blkvsc_request) + storvsc_drv_obj->RequestExtSize, 0, + SLAB_HWCACHE_ALIGN, NULL); + #else diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-bus-code-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-bus-code-build.patch new file mode 100644 index 000000000..afa55719b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-bus-code-build.patch @@ -0,0 +1,311 @@ +From foo@baz Mon Jul 13 17:09:34 PDT 2009 +Date: Mon, 13 Jul 2009 17:09:34 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: make the Hyper-V virtual bus code build + +From: Greg Kroah-Hartman + +The #define KERNEL_2_6_27 needs to be set, and I adjusted the include +directories a bit to get things to build properly. + +I also fixed up the direct access of bus_id, as that field is now gone. + +The hv_vmbus code should now build properly, with no errors. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/Channel.c | 4 ++-- + drivers/staging/hv/Channel.h | 2 +- + drivers/staging/hv/ChannelInterface.h | 2 +- + drivers/staging/hv/ChannelMgmt.c | 4 ++-- + drivers/staging/hv/ChannelMgmt.h | 8 ++++---- + drivers/staging/hv/Connection.c | 2 +- + drivers/staging/hv/Hv.c | 2 +- + drivers/staging/hv/Hv.h | 16 ++++++++-------- + drivers/staging/hv/RingBuffer.c | 2 +- + drivers/staging/hv/RingBuffer.h | 2 +- + drivers/staging/hv/Sources.c | 1 + + drivers/staging/hv/Vmbus.c | 2 +- + drivers/staging/hv/VmbusPrivate.h | 4 ++-- + drivers/staging/hv/include/ChannelMessages.h | 2 +- + drivers/staging/hv/osd.c | 3 ++- + drivers/staging/hv/vmbus_drv.c | 15 ++++++++------- + 16 files changed, 37 insertions(+), 34 deletions(-) + +--- a/drivers/staging/hv/Channel.c ++++ b/drivers/staging/hv/Channel.c +@@ -22,8 +22,8 @@ + */ + + +-#include "osd.h" +-#include "logging.h" ++#include "include/osd.h" ++#include "include/logging.h" + + #include "VmbusPrivate.h" + +--- a/drivers/staging/hv/Channel.h ++++ b/drivers/staging/hv/Channel.h +@@ -25,7 +25,7 @@ + #ifndef _CHANNEL_H_ + #define _CHANNEL_H_ + +-#include "osd.h" ++#include "include/osd.h" + #include "ChannelMgmt.h" + + #pragma pack(push,1) +--- a/drivers/staging/hv/ChannelInterface.h ++++ b/drivers/staging/hv/ChannelInterface.h +@@ -25,7 +25,7 @@ + #ifndef _CHANNEL_INTERFACE_H_ + #define _CHANNEL_INTERFACE_H_ + +-#include "VmbusApi.h" ++#include "include/VmbusApi.h" + + INTERNAL void + GetChannelInterface( +--- a/drivers/staging/hv/ChannelMgmt.c ++++ b/drivers/staging/hv/ChannelMgmt.c +@@ -22,8 +22,8 @@ + */ + + +-#include "osd.h" +-#include "logging.h" ++#include "include/osd.h" ++#include "include/logging.h" + + #include "VmbusPrivate.h" + +--- a/drivers/staging/hv/ChannelMgmt.h ++++ b/drivers/staging/hv/ChannelMgmt.h +@@ -25,12 +25,12 @@ + #ifndef _CHANNEL_MGMT_H_ + #define _CHANNEL_MGMT_H_ + +-#include "osd.h" +-#include "List.h" ++#include "include/osd.h" ++#include "include/List.h" + #include "RingBuffer.h" + +-#include "VmbusChannelInterface.h" +-#include "ChannelMessages.h" ++#include "include/VmbusChannelInterface.h" ++#include "include/ChannelMessages.h" + + + +--- a/drivers/staging/hv/Connection.c ++++ b/drivers/staging/hv/Connection.c +@@ -22,7 +22,7 @@ + */ + + +-#include "logging.h" ++#include "include/logging.h" + + #include "VmbusPrivate.h" + +--- a/drivers/staging/hv/Hv.c ++++ b/drivers/staging/hv/Hv.c +@@ -22,7 +22,7 @@ + */ + + +-#include "logging.h" ++#include "include/logging.h" + #include "VmbusPrivate.h" + + // +--- a/drivers/staging/hv/Hv.h ++++ b/drivers/staging/hv/Hv.h +@@ -25,23 +25,23 @@ + #ifndef __HV_H__ + #define __HV_H__ + +-#include "osd.h" ++#include "include/osd.h" + +-#include "HvTypes.h" +-#include "HvStatus.h" ++#include "include/HvTypes.h" ++#include "include/HvStatus.h" + //#include "HvVmApi.h" + //#include "HvKeApi.h" + //#include "HvMmApi.h" + //#include "HvCpuApi.h" +-#include "HvHalApi.h" +-#include "HvVpApi.h" ++#include "include/HvHalApi.h" ++#include "include/HvVpApi.h" + //#include "HvTrApi.h" +-#include "HvSynicApi.h" ++#include "include/HvSynicApi.h" + //#include "HvAmApi.h" + //#include "HvHkApi.h" + //#include "HvValApi.h" +-#include "HvHcApi.h" +-#include "HvPtApi.h" ++#include "include/HvHcApi.h" ++#include "include/HvPtApi.h" + + enum + { +--- a/drivers/staging/hv/include/ChannelMessages.h ++++ b/drivers/staging/hv/include/ChannelMessages.h +@@ -24,7 +24,7 @@ + + #pragma once + +-#include ++#include "VmbusPacketFormat.h" + + #define C_ASSERT(x) + typedef UINT32 NTSTATUS; +--- a/drivers/staging/hv/osd.c ++++ b/drivers/staging/hv/osd.c +@@ -21,6 +21,7 @@ + * + */ + ++#define KERNEL_2_6_27 + + #include + #include +@@ -46,7 +47,7 @@ + #include + #include + +-#include "osd.h" ++#include "include/osd.h" + + // + // Data types +--- a/drivers/staging/hv/RingBuffer.c ++++ b/drivers/staging/hv/RingBuffer.c +@@ -22,7 +22,7 @@ + */ + + +-#include "logging.h" ++#include "include/logging.h" + #include "RingBuffer.h" + + // +--- a/drivers/staging/hv/RingBuffer.h ++++ b/drivers/staging/hv/RingBuffer.h +@@ -25,7 +25,7 @@ + #ifndef _RING_BUFFER_H_ + #define _RING_BUFFER_H_ + +-#include "osd.h" ++#include "include/osd.h" + + typedef struct _SG_BUFFER_LIST { + PVOID Data; +--- a/drivers/staging/hv/Sources.c ++++ b/drivers/staging/hv/Sources.c +@@ -21,6 +21,7 @@ + * + */ + ++#define KERNEL_2_6_27 + + #include "Vmbus.c" + #include "Hv.c" +--- a/drivers/staging/hv/Vmbus.c ++++ b/drivers/staging/hv/Vmbus.c +@@ -22,7 +22,7 @@ + */ + + +-#include "logging.h" ++#include "include/logging.h" + #include "VersionInfo.h" + #include "VmbusPrivate.h" + +--- a/drivers/staging/hv/vmbus_drv.c ++++ b/drivers/staging/hv/vmbus_drv.c +@@ -21,6 +21,7 @@ + * + */ + ++#define KERNEL_2_6_27 + + #include + #include +@@ -29,8 +30,8 @@ + #include + #include + +-#include "logging.h" +-#include "vmbus.h" ++#include "include/logging.h" ++#include "include/vmbus.h" + + // + // Defines +@@ -451,7 +452,7 @@ int vmbus_bus_init(PFN_DRIVERINITIALIZE + goto cleanup; + } + //strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); +- sprintf(dev_ctx->device.bus_id, "vmbus_0_0"); ++ dev_set_name(&dev_ctx->device, "vmbus_0_0"); + memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(GUID)); + memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(GUID)); + +@@ -656,16 +657,16 @@ static int vmbus_child_device_register(D + // + // Make sure we are not registered already + // +- if (child_device_ctx->device.bus_id[0] != '\0') ++ if (strlen(dev_name(&child_device_ctx->device)) != 0) + { +- DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, child_device_ctx->device.bus_id); ++ DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, dev_name(&child_device_ctx->device)); + + ret = -1; + goto Cleanup; + } + + // Set the device bus id. Otherwise, device_register()will fail. +- sprintf(child_device_ctx->device.bus_id, "vmbus_0_%d", InterlockedIncrement(&device_num)); ++ dev_set_name(&child_device_ctx->device, "vmbus_0_%d", InterlockedIncrement(&device_num)); + + // The new device belongs to this bus + child_device_ctx->device.bus = &g_vmbus_drv.bus; //device->dev.bus; +@@ -924,7 +925,7 @@ static int vmbus_probe(struct device *ch + ret = device_ctx->probe_error = driver_ctx->probe(child_device); + if (ret != 0) + { +- DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s (%p) on driver %s (%d)...", child_device->bus_id, child_device, child_device->driver->name, ret); ++ DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s (%p) on driver %s (%d)...", dev_name(child_device), child_device, child_device->driver->name, ret); + + #ifdef KERNEL_2_6_27 + INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb); +--- a/drivers/staging/hv/VmbusPrivate.h ++++ b/drivers/staging/hv/VmbusPrivate.h +@@ -30,14 +30,14 @@ + #endif + + #include "Hv.h" +-#include "VmbusApi.h" ++#include "include/VmbusApi.h" + #include "Channel.h" + #include "ChannelMgmt.h" + #include "ChannelInterface.h" + //#include "ChannelMessages.h" + #include "RingBuffer.h" + //#include "Packet.h" +-#include "List.h" ++#include "include/List.h" + + // + // Defines diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-network-driver-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-network-driver-build.patch new file mode 100644 index 000000000..9817df811 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-network-driver-build.patch @@ -0,0 +1,126 @@ +From foo@baz Tue Jul 14 10:59:56 PDT 2009 +Date: Tue, 14 Jul 2009 10:59:56 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: make the Hyper-V virtual network driver build + +From: Greg Kroah-Hartman + +The #define KERNEL_2_6_27 needs to be set, and I adjusted the include +directories a bit to get things to build properly. + +The driver was changed to use net_device_ops, as that is needed to build +and operate properly now. + +The hv_netvsc code should now build with no errors. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/NetVsc.c | 3 ++- + drivers/staging/hv/NetVsc.h | 8 ++++---- + drivers/staging/hv/RndisFilter.c | 5 +++-- + drivers/staging/hv/RndisFilter.h | 4 ++-- + drivers/staging/hv/include/nvspprotocol.h | 2 +- + drivers/staging/hv/netvsc_drv.c | 7 ++++--- + 6 files changed, 16 insertions(+), 13 deletions(-) + +--- a/drivers/staging/hv/NetVsc.c ++++ b/drivers/staging/hv/NetVsc.c +@@ -20,8 +20,9 @@ + * + */ + ++#define KERNEL_2_6_27 + +-#include "logging.h" ++#include "include/logging.h" + #include "NetVsc.h" + #include "RndisFilter.h" + +--- a/drivers/staging/hv/NetVsc.h ++++ b/drivers/staging/hv/NetVsc.h +@@ -24,12 +24,12 @@ + #ifndef _NETVSC_H_ + #define _NETVSC_H_ + +-#include "VmbusPacketFormat.h" +-#include "nvspprotocol.h" ++#include "include/VmbusPacketFormat.h" ++#include "include/nvspprotocol.h" + +-#include "List.h" ++#include "include/List.h" + +-#include "NetVscApi.h" ++#include "include/NetVscApi.h" + // + // #defines + // +--- a/drivers/staging/hv/RndisFilter.c ++++ b/drivers/staging/hv/RndisFilter.c +@@ -21,10 +21,11 @@ + * + */ + ++#define KERNEL_2_6_27 + +-#include "logging.h" ++#include "include/logging.h" + +-#include "NetVscApi.h" ++#include "include/NetVscApi.h" + #include "RndisFilter.h" + + // +--- a/drivers/staging/hv/RndisFilter.h ++++ b/drivers/staging/hv/RndisFilter.h +@@ -27,10 +27,10 @@ + + #define __struct_bcount(x) + +-#include "osd.h" ++#include "include/osd.h" + #include "NetVsc.h" + +-#include "rndis.h" ++#include "include/rndis.h" + + #define RNDIS_HEADER_SIZE (sizeof(RNDIS_MESSAGE) - sizeof(RNDIS_MESSAGE_CONTAINER)) + +--- a/drivers/staging/hv/include/nvspprotocol.h ++++ b/drivers/staging/hv/include/nvspprotocol.h +@@ -24,7 +24,7 @@ + + #pragma once + +-#include ++#include "VmbusChannelInterface.h" + + #define NVSP_INVALID_PROTOCOL_VERSION ((UINT32)0xFFFFFFFF) + +--- a/drivers/staging/hv/netvsc_drv.c ++++ b/drivers/staging/hv/netvsc_drv.c +@@ -20,6 +20,7 @@ + * + */ + ++#define KERNEL_2_6_27 + + #include + #include +@@ -41,10 +42,10 @@ + #include + #include + +-#include "logging.h" +-#include "vmbus.h" ++#include "include/logging.h" ++#include "include/vmbus.h" + +-#include "NetVscApi.h" ++#include "include/NetVscApi.h" + + MODULE_LICENSE("GPL"); + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-storage-driver-build.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-storage-driver-build.patch new file mode 100644 index 000000000..8185f9afa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-make-the-hyper-v-virtual-storage-driver-build.patch @@ -0,0 +1,77 @@ +From foo@baz Tue Jul 14 10:18:50 PDT 2009 +Date: Tue, 14 Jul 2009 10:18:50 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: make the Hyper-V virtual storage driver build + +From: Greg Kroah-Hartman + +The #define KERNEL_2_6_27 needs to be set, and I adjusted the include +directories a bit to get things to build properly. + +I also fixed up the direct access of bus_id, as that field is now gone. +Some minor scsi api changes were needed as well. + +The hv_storvsc code should now build properly, with no errors. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/StorVsc.c | 9 +++++---- + drivers/staging/hv/storvsc_drv.c | 9 +++++---- + 2 files changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/staging/hv/StorVsc.c ++++ b/drivers/staging/hv/StorVsc.c +@@ -21,12 +21,13 @@ + * + */ + ++#define KERNEL_2_6_27 + +-#include "logging.h" ++#include "include/logging.h" + +-#include "StorVscApi.h" +-#include "VmbusPacketFormat.h" +-#include "vstorage.h" ++#include "include/StorVscApi.h" ++#include "include/VmbusPacketFormat.h" ++#include "include/vstorage.h" + + + // +--- a/drivers/staging/hv/storvsc_drv.c ++++ b/drivers/staging/hv/storvsc_drv.c +@@ -21,6 +21,7 @@ + * + */ + ++#define KERNEL_2_6_27 + + #include + #include +@@ -40,10 +41,10 @@ + #include + #endif + +-#include "logging.h" +-#include "vmbus.h" ++#include "include/logging.h" ++#include "include/vmbus.h" + +-#include "StorVscApi.h" ++#include "include/StorVscApi.h" + + // + // #defines +@@ -296,7 +297,7 @@ static int storvsc_probe(struct device * + #if defined(KERNEL_2_6_27) + host_device_ctx->request_pool = + kmem_cache_create +- (device_ctx->device.bus_id, ++ (dev_name(&device_ctx->device), + sizeof(struct storvsc_cmd_request) + storvsc_drv_obj->RequestExtSize, + 0, + SLAB_HWCACHE_ALIGN, NULL); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-storvsc-fix-up-driver_data-usage.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-storvsc-fix-up-driver_data-usage.patch new file mode 100644 index 000000000..4327b2b2a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-storvsc-fix-up-driver_data-usage.patch @@ -0,0 +1,59 @@ +From foo@baz Fri Jul 24 10:58:22 PDT 2009 +Date: Fri, 24 Jul 2009 10:58:22 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: storvsc: fix up driver_data usage + +From: Greg Kroah-Hartman + +driver_data is gone now from struct device, so use the proper functions +to access it instead. + +Thanks to Bill Pemberton for pointing out this build error. + +Cc: Bill Pemberton +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/storvsc_drv.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/staging/hv/storvsc_drv.c ++++ b/drivers/staging/hv/storvsc_drv.c +@@ -279,7 +279,7 @@ static int storvsc_probe(struct device * + return -ENOMEM; + } + +- device->driver_data = host; ++ dev_set_drvdata(device, host); + + host_device_ctx = (struct host_device_context*)host->hostdata; + memset(host_device_ctx, 0, sizeof(struct host_device_context)); +@@ -380,7 +380,7 @@ static int storvsc_remove(struct device + struct device_context *device_ctx = device_to_device_context(device); + DEVICE_OBJECT* device_obj = &device_ctx->device_obj; + +- struct Scsi_Host *host = (struct Scsi_Host *)device->driver_data; ++ struct Scsi_Host *host = dev_get_drvdata(device); + struct host_device_context *host_device_ctx=(struct host_device_context*)host->hostdata; + + +@@ -1125,7 +1125,7 @@ static void storvsc_host_rescan_callback + DEVICE_OBJECT* device_obj = (DEVICE_OBJECT*)context; + #endif + struct device_context* device_ctx = to_device_context(device_obj); +- struct Scsi_Host *host = (struct Scsi_Host *)device_ctx->device.driver_data; ++ struct Scsi_Host *host = dev_get_drvdata(&device_ctx->device); + struct scsi_device *sdev; + struct host_device_context *host_device_ctx; + struct scsi_device **sdevs_remove_list; +@@ -1293,7 +1293,7 @@ static int storvsc_report_luns(struct sc + static void storvsc_host_rescan(DEVICE_OBJECT* device_obj) + { + struct device_context* device_ctx = to_device_context(device_obj); +- struct Scsi_Host *host = (struct Scsi_Host *)device_ctx->device.driver_data; ++ struct Scsi_Host *host = dev_get_drvdata(&device_ctx->device); + struct host_device_context *host_device_ctx; + + DPRINT_ENTER(STORVSC_DRV); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-use-the-correct-ifdef-for-x86-64.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-use-the-correct-ifdef-for-x86-64.patch new file mode 100644 index 000000000..c76acd93f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-hv-use-the-correct-ifdef-for-x86-64.patch @@ -0,0 +1,29 @@ +From foo@baz Thu Jul 16 22:31:14 PDT 2009 +Date: Thu, 16 Jul 2009 22:31:15 -0700 +From: Greg Kroah-Hartman +Subject: Staging: hv: use the correct #ifdef for x86-64 + +From: Greg Kroah-Hartman + +x86-64 needs a different config check. Thanks to Hank for the debugging +to determine the fix for this. + +Cc: Hank Janssen +Cc: Haiyang Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/hv/Hv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/hv/Hv.c ++++ b/drivers/staging/hv/Hv.c +@@ -165,7 +165,7 @@ HvDoHypercall ( + void* Output + ) + { +-#ifdef x86_64 ++#ifdef CONFIG_X86_64 + UINT64 hvStatus=0; + UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; + UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-rt2860-enable-wpa_supplicant-support.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-rt2860-enable-wpa_supplicant-support.patch new file mode 100644 index 000000000..8e7637b07 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-rt2860-enable-wpa_supplicant-support.patch @@ -0,0 +1,34 @@ +From foo@baz Mon Nov 17 15:55:52 PST 2008 +Date: Mon, 17 Nov 2008 15:55:52 -0800 +To: Greg KH +From: Greg Kroah-Hartman +Subject: Staging: rt2860: enable WPA_SUPPLICANT support +Patch-mainline: 2.6.29 +References: bnc#437959 + +From: Greg Kroah-Hartman + +This is needed in order to get NetworkManager to work properly +with this driver. + +More details can be found at + https://bugzilla.novell.com/show_bug.cgi?id=437959 + +Cc: Helmut Schaa +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/rt2860/Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/staging/rt2860/Makefile ++++ b/drivers/staging/rt2860/Makefile +@@ -6,6 +6,8 @@ EXTRA_CFLAGS += -DRT2860 + EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT + EXTRA_CFLAGS += -DDBG + EXTRA_CFLAGS += -DDOT11_N_SUPPORT ++EXTRA_CFLAGS += -DWPA_SUPPLICANT_SUPPORT ++EXTRA_CFLAGS += -DNATIVE_WPA_SUPPLICANT_SUPPORT + + rt2860sta-objs := \ + common/md5.o \ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-rt2860-sync-driver-up-with-2.6.30-version.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-rt2860-sync-driver-up-with-2.6.30-version.patch new file mode 100644 index 000000000..40e0f91a0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-rt2860-sync-driver-up-with-2.6.30-version.patch @@ -0,0 +1,5283 @@ +From foo@baz Mon Jul 27 15:37:03 PDT 2009 +Date: Mon, 27 Jul 2009 15:37:03 -0700 +From: Greg Kroah-Hartman +Subject: Staging: rt2860: sync driver up with 2.6.30 version +References: bnc#512070 +Patch-mainline: 2.6.30 + +This is needed to get the driver to work properly with some hardware types. + +The 2.6.30 version was backported, minus the netdev_ops changes, which +will not work in the 2.6.27 kernel version. + +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/rt2860/2860_main_dev.c | 64 +---- + drivers/staging/rt2860/Makefile | 1 + drivers/staging/rt2860/TODO | 4 + drivers/staging/rt2860/common/ba_action.c | 18 - + drivers/staging/rt2860/common/cmm_data.c | 32 -- + drivers/staging/rt2860/common/cmm_data_2860.c | 150 +++++++++---- + drivers/staging/rt2860/common/cmm_info.c | 8 + drivers/staging/rt2860/common/cmm_sync.c | 2 + drivers/staging/rt2860/common/cmm_wpa.c | 40 +++ + drivers/staging/rt2860/common/dfs.c | 4 + drivers/staging/rt2860/common/mlme.c | 289 ++++++++++++++++++++------ + drivers/staging/rt2860/common/rtmp_init.c | 196 ++++++++++++----- + drivers/staging/rt2860/common/spectrum.c | 44 +-- + drivers/staging/rt2860/config.mk | 4 + drivers/staging/rt2860/oid.h | 2 + drivers/staging/rt2860/rt2860.h | 26 -- + drivers/staging/rt2860/rt28xx.h | 4 + drivers/staging/rt2860/rt_ate.c | 50 +--- + drivers/staging/rt2860/rt_ate.h | 6 + drivers/staging/rt2860/rt_config.h | 2 + drivers/staging/rt2860/rt_linux.c | 45 ---- + drivers/staging/rt2860/rt_linux.h | 51 +--- + drivers/staging/rt2860/rt_main_dev.c | 183 ++-------------- + drivers/staging/rt2860/rt_profile.c | 29 +- + drivers/staging/rt2860/rtmp.h | 61 ++--- + drivers/staging/rt2860/rtmp_def.h | 31 +- + drivers/staging/rt2860/sta/assoc.c | 23 -- + drivers/staging/rt2860/sta/connect.c | 45 ++-- + drivers/staging/rt2860/sta/dls.c | 4 + drivers/staging/rt2860/sta/rtmp_data.c | 29 +- + drivers/staging/rt2860/sta/sync.c | 18 - + drivers/staging/rt2860/sta/wpa.c | 10 + drivers/staging/rt2860/sta_ioctl.c | 278 ++++++++++++++----------- + drivers/staging/rt2860/wpa.h | 1 + 34 files changed, 935 insertions(+), 819 deletions(-) + +--- a/drivers/staging/rt2860/2860_main_dev.c ++++ b/drivers/staging/rt2860/2860_main_dev.c +@@ -90,12 +90,10 @@ void init_thread_task(PRTMP_ADAPTER pAd) + static void __exit rt2860_cleanup_module(void); + static int __init rt2860_init_module(void); + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #ifdef CONFIG_PM + static int rt2860_suspend(struct pci_dev *pci_dev, pm_message_t state); + static int rt2860_resume(struct pci_dev *pci_dev); + #endif // CONFIG_PM // +-#endif + + + // +@@ -128,22 +126,15 @@ static struct pci_driver rt2860_driver = + name: "rt2860", + id_table: rt2860_pci_tbl, + probe: rt2860_init_one, +-#if LINUX_VERSION_CODE >= 0x20412 + remove: __devexit_p(rt2860_remove_one), +-#else +- remove: __devexit(rt2860_remove_one), +-#endif + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #ifdef CONFIG_PM + suspend: rt2860_suspend, + resume: rt2860_resume, + #endif +-#endif + }; + + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #ifdef CONFIG_PM + + VOID RT2860RejectPendingPackets( +@@ -170,7 +161,7 @@ static int rt2860_suspend( + } + else + { +- pAd = (PRTMP_ADAPTER)net_dev->priv; ++ pAd = net_dev->ml_priv; + + /* we can not use IFF_UP because ra0 down but ra1 up */ + /* and 1 suspend/resume function for 1 module, not for each interface */ +@@ -249,7 +240,7 @@ static int rt2860_resume( + DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); + } + else +- pAd = (PRTMP_ADAPTER)net_dev->priv; ++ pAd = net_dev->ml_priv; + + if (pAd != NULL) + { +@@ -284,16 +275,11 @@ static int rt2860_resume( + return 0; + } + #endif // CONFIG_PM // +-#endif + + + static INT __init rt2860_init_module(VOID) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + return pci_register_driver(&rt2860_driver); +-#else +- return pci_module_init(&rt2860_driver); +-#endif + } + + +@@ -336,7 +322,7 @@ static VOID __devexit rt2860_remove_one( + IN struct pci_dev *pci_dev) + { + struct net_device *net_dev = pci_get_drvdata(pci_dev); +- RTMP_ADAPTER *pAd = net_dev->priv; ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; + + DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_remove_one\n")); + +@@ -374,11 +360,7 @@ static VOID __devexit rt2860_remove_one( + } + + // Free pre-allocated net_device memory +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + free_netdev(net_dev); +-#else +- kfree(net_dev); +-#endif + } + + // +@@ -758,16 +740,13 @@ static void ac0_dma_done_tasklet(unsigne + int print_int_count; + + IRQ_HANDLE_TYPE +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) + rt2860_interrupt(int irq, void *dev_instance) +-#else +-rt2860_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +-#endif + { + struct net_device *net_dev = (struct net_device *) dev_instance; +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; + INT_SOURCE_CSR_STRUC IntSource; + POS_COOKIE pObj; ++ BOOLEAN bOldValue; + + pObj = (POS_COOKIE) pAd->OS_Cookie; + +@@ -800,20 +779,19 @@ rt2860_interrupt(int irq, void *dev_inst + // RT2661 => when ASIC is sleeping, MAC register cannot be read and written. + // RT2860 => when ASIC is sleeping, MAC register can be read and written. + ++ bOldValue = pAd->bPCIclkOff; ++ pAd->bPCIclkOff = FALSE; + { + RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); + RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); // write 1 to clear + } ++ pAd->bPCIclkOff = bOldValue; + + // Do nothing if Reset in progress + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) || + RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +- return IRQ_HANDLED; +-#else +- return; +-#endif ++ return IRQ_HANDLED; + } + + // +@@ -822,8 +800,6 @@ rt2860_interrupt(int irq, void *dev_inst + // The priority can be adjust by altering processing if statement + // + +- pAd->bPCIclkOff = FALSE; +- + // If required spinlock, each interrupt service routine has to acquire + // and release itself. + // +@@ -832,11 +808,8 @@ rt2860_interrupt(int irq, void *dev_inst + if (IntSource.word == 0xffffffff) + { + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS); +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +- return IRQ_HANDLED; +-#else +- return; +-#endif ++ printk("snowpin - IntSource.word == 0xffffffff\n"); ++ return IRQ_HANDLED; + } + + if (IntSource.word & TxCoherent) +@@ -970,10 +943,7 @@ rt2860_interrupt(int irq, void *dev_inst + } + #endif // CONFIG_STA_SUPPORT // + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + return IRQ_HANDLED; +-#endif +- + } + + /* +@@ -1022,15 +992,11 @@ BOOLEAN RT28XXNetDevInit( + IN RTMP_ADAPTER *pAd) + { + struct pci_dev *pci_dev = (struct pci_dev *)_dev_p; +- CHAR *print_name; ++ const CHAR *print_name; + ULONG csr_addr; + + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +- print_name = pci_dev ? pci_name(pci_dev) : "rt2860"; +-#else +- print_name = pci_dev ? pci_dev->slot_name : "rt2860"; +-#endif // LINUX_VERSION_CODE // ++ print_name = pci_dev ? pci_name(pci_dev) : "rt2860"; + + net_dev->base_addr = 0; + net_dev->irq = 0; +@@ -1202,7 +1168,7 @@ VOID RT28xx_UpdateBeaconToAsic( + UCHAR bcn_idx = 0; + + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __func__)); + return; + } + +@@ -1300,7 +1266,7 @@ VOID rt2860_stop(struct net_device *net_ + DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); + } + else +- pAd = (PRTMP_ADAPTER)net_dev->priv; ++ pAd = net_dev->ml_priv; + + if (pAd != NULL) + { +--- a/drivers/staging/rt2860/Makefile ++++ b/drivers/staging/rt2860/Makefile +@@ -2,7 +2,6 @@ obj-$(CONFIG_RT2860) += rt2860sta.o + + # TODO: all of these should be removed + EXTRA_CFLAGS += -DLINUX -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT +-EXTRA_CFLAGS += -DRT2860 + EXTRA_CFLAGS += -DCONFIG_STA_SUPPORT + EXTRA_CFLAGS += -DDBG + EXTRA_CFLAGS += -DDOT11_N_SUPPORT +--- a/drivers/staging/rt2860/TODO ++++ b/drivers/staging/rt2860/TODO +@@ -1,6 +1,6 @@ + I'm hesitant to add a TODO file here, as the wireless developers would + really have people help them out on the "clean" rt2860 driver that can +-be found at the rt2860.sf.net site. ++be found at the http://rt2x00.serialmonkey.com/ site. + + But, if you wish to clean up this driver instead, here's a short list of + things that need to be done to get it into a more mergable shape: +@@ -8,7 +8,7 @@ things that need to be done to get it in + TODO: + - checkpatch.pl clean + - sparse clean +- - port to in-kernel 80211 stack ++ - port to in-kernel 80211 stack and common rt2x00 infrastructure + - remove reading from /etc/ config files + - review by the wireless developer community + +--- a/drivers/staging/rt2860/common/ba_action.c ++++ b/drivers/staging/rt2860/common/ba_action.c +@@ -599,7 +599,7 @@ VOID BAOriSessionAdd( + + pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue; + +- DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap, ++ DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __func__, pEntry->TXBAbitmap, + pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue)); + + // SEND BAR ; +@@ -673,7 +673,7 @@ BOOLEAN BARecSessionAdd( + ba_refresh_reordering_mpdus(pAd, pBAEntry); + } + +- DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx, ++ DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __func__, pAd->BATable.numAsRecipient, Idx, + pFrame->BaParm.BufSize, BAWinSize)); + + // Start fill in parameters. +@@ -915,7 +915,7 @@ VOID BAOriSessionTearDown( + return; + } + +- DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID)); + + pBAEntry = &pAd->BATable.BAOriEntry[Idx]; + DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status)); +@@ -974,7 +974,7 @@ VOID BARecSessionTearDown( + if (Idx == 0) + return; + +- DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID)); ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID)); + + + pBAEntry = &pAd->BATable.BARecEntry[Idx]; +@@ -1185,7 +1185,7 @@ VOID PeerAddBAReqAction( + PULONG ptemp; + PMAC_TABLE_ENTRY pMacEntry; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __func__, Elem->Wcid)); + + //hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen); + +@@ -1269,7 +1269,7 @@ VOID PeerAddBAReqAction( + MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen); + MlmeFreeMemory(pAd, pOutBuffer); + +- DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID, ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __func__, Elem->Wcid, ADDframe.BaParm.TID, + ADDframe.BaParm.BufSize)); + } + +@@ -1288,7 +1288,7 @@ VOID PeerAddBARspAction( + if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE) + return; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __func__, Elem->Wcid)); + + //hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen); + +@@ -1329,7 +1329,7 @@ VOID PeerDelBAAction( + //PUCHAR pOutBuffer = NULL; + PFRAME_DELBA_REQ pDelFrame = NULL; + +- DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __func__)); + //DELBA Request from unknown peer, ignore this. + if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen)) + { +@@ -1366,7 +1366,7 @@ BOOLEAN CntlEnqueueForRecv( + + TID = (UCHAR)pFrame->BARControl.TID; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __func__, Wcid, TID)); + //hex_dump("BAR", (PCHAR) pFrame, MsgLen); + // Do nothing if the driver is starting halt state. + // This might happen when timer already been fired before cancel timer with mlmehalt +--- a/drivers/staging/rt2860/common/cmm_data.c ++++ b/drivers/staging/rt2860/common/cmm_data.c +@@ -105,9 +105,7 @@ NDIS_STATUS MiniportMMRequest( + PNDIS_PACKET pPacket; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + ULONG FreeNum; +-#ifdef RT2860 + unsigned long IrqFlags = 0; +-#endif // RT2860 // + UCHAR IrqState; + UCHAR rtmpHwHdr[TXINFO_SIZE + TXWI_SIZE]; //RTMP_HW_HDR_LEN]; + +@@ -118,10 +116,9 @@ NDIS_STATUS MiniportMMRequest( + // 2860C use Tx Ring + + IrqState = pAd->irq_disabled; +-#ifdef RT2860 ++ + if ((pAd->MACVersion == 0x28600100) && (!IrqState)) + RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags); +-#endif // RT2860 // + + do + { +@@ -175,17 +172,14 @@ NDIS_STATUS MiniportMMRequest( + + } while (FALSE); + +-#ifdef RT2860 + // 2860C use Tx Ring + if ((pAd->MACVersion == 0x28600100) && (!IrqState)) + RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags); +-#endif // RT2860 // + + return Status; + } + + +-#ifdef RT2860 + NDIS_STATUS MiniportMMRequestUnlock( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, +@@ -253,7 +247,6 @@ NDIS_STATUS MiniportMMRequestUnlock( + + return Status; + } +-#endif // RT2860 // + + + /* +@@ -290,17 +283,14 @@ NDIS_STATUS MlmeHardTransmit( + return NDIS_STATUS_FAILURE; + } + +-#ifdef RT2860 + if ( pAd->MACVersion == 0x28600100 ) + return MlmeHardTransmitTxRing(pAd,QueIdx,pPacket); + else +-#endif // RT2860 // + return MlmeHardTransmitMgmtRing(pAd,QueIdx,pPacket); + + } + + +-#ifdef RT2860 + NDIS_STATUS MlmeHardTransmitTxRing( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, +@@ -366,7 +356,7 @@ NDIS_STATUS MlmeHardTransmitTxRing( + { + // outgoing frame always wakeup PHY to prevent frame lost + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +- AsicForceWakeup(pAd, TRUE); ++ AsicForceWakeup(pAd, FROM_TX); + } + #endif // CONFIG_STA_SUPPORT // + pFirstTxWI =(PTXWI_STRUC)pSrcBufVA; +@@ -509,7 +499,6 @@ NDIS_STATUS MlmeHardTransmitTxRing( + + return NDIS_STATUS_SUCCESS; + } +-#endif // RT2860 // + + + NDIS_STATUS MlmeHardTransmitMgmtRing( +@@ -541,7 +530,7 @@ NDIS_STATUS MlmeHardTransmitMgmtRing( + { + // outgoing frame always wakeup PHY to prevent frame lost + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +- AsicForceWakeup(pAd, TRUE); ++ AsicForceWakeup(pAd, FROM_TX); + } + #endif // CONFIG_STA_SUPPORT // + +@@ -943,9 +932,6 @@ BOOLEAN RTMP_FillTxBlkInfo( + } + + return TRUE; +- +-FillTxBlkErr: +- return FALSE; + } + + +@@ -1079,7 +1065,6 @@ VOID RTMPDeQueuePacket( + break; + } + +-#ifdef RT2860 + FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); + + #ifdef DBG_DIAGNOSE +@@ -1104,7 +1089,6 @@ VOID RTMPDeQueuePacket( + RTMPFreeTXDUponTxDmaDone(pAd, QueIdx); + FreeNumber[QueIdx] = GET_TXRING_FREENO(pAd, QueIdx); + } +-#endif // RT2860 // + + // probe the Queue Head + pQueue = &pAd->TxSwQueue[QueIdx]; +@@ -1183,12 +1167,10 @@ VOID RTMPDeQueuePacket( + Status = STAHardTransmit(pAd, pTxBlk, QueIdx); + #endif // CONFIG_STA_SUPPORT // + +-#ifdef RT2860 + DEQUEUE_UNLOCK(&pAd->irq_lock, bIntContext, IrqFlags); + // static rate also need NICUpdateFifoStaCounters() function. + //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) + NICUpdateFifoStaCounters(pAd); +-#endif // RT2860 // + } + + RT28XX_STOP_DEQUEUE(pAd, QueIdx, IrqFlags); +@@ -1767,7 +1749,6 @@ PQUEUE_HEADER RTMPCheckTxSwQueue( + } + + +-#ifdef RT2860 + BOOLEAN RTMPFreeTXDUponTxDmaDone( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx) +@@ -2312,7 +2293,6 @@ VOID DBGPRINT_RX_RING( + DBGPRINT_RAW(RT_DEBUG_TRACE,(" RxSwReadIdx [%d]=", AC0freeIdx)); + DBGPRINT_RAW(RT_DEBUG_TRACE,(" pending-NDIS=%ld\n", pAd->RalinkCounters.PendingNdisPacketCount)); + } +-#endif // RT2860 // + + /* + ======================================================================== +@@ -2637,9 +2617,7 @@ MAC_TABLE_ENTRY *MacTableInsertEntry( + pEntry->AuthMode = pAd->StaCfg.AuthMode; + pEntry->WepStatus = pAd->StaCfg.WepStatus; + pEntry->PrivacyFilter = Ndis802_11PrivFilterAcceptAll; +-#ifdef RT2860 + AsicRemovePairwiseKeyEntry(pAd, pEntry->apidx, (UCHAR)i); +-#endif // RT2860 // + } + #endif // CONFIG_STA_SUPPORT // + } +@@ -2790,7 +2768,7 @@ BOOLEAN MacTableDeleteEntry( + } + else + { +- printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid); ++ printk("\n%s: Impossible Wcid = %d !!!!!\n", __func__, wcid); + } + } + +@@ -2826,9 +2804,7 @@ VOID MacTableReset( + + for (i=1; iMacTab.Content[i].ValidAsCLI == TRUE) + { + +--- a/drivers/staging/rt2860/common/cmm_data_2860.c ++++ b/drivers/staging/rt2860/common/cmm_data_2860.c +@@ -634,7 +634,7 @@ VOID RT28xxPciAsicRadioOff( + } + + // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops. +- pAd->bPCIclkOffDisableTx = TRUE; ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX); + + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { +@@ -651,7 +651,7 @@ VOID RT28xxPciAsicRadioOff( + { + DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime)); + OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); +- pAd->bPCIclkOffDisableTx = FALSE; ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX); + return; + } + else +@@ -688,18 +688,25 @@ VOID RT28xxPciAsicRadioOff( + if (i >= 50) + { + DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy. return on RT28xxPciAsicRadioOff ()\n")); +- pAd->bPCIclkOffDisableTx = FALSE; + RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); + DmaCfg.field.EnableTxDMA = 1; + RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ pAd->CheckDmaBusyCount++; + return; + } ++ else ++ { ++ pAd->CheckDmaBusyCount = 0; ++ } + + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF); + + // Set to 1R. +- tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7); +- RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3); ++ if (pAd->Antenna.field.RxPath > 1) ++ { ++ tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3); ++ } + + // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. + if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) +@@ -714,8 +721,15 @@ VOID RT28xxPciAsicRadioOff( + AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel); + } + +- // When PCI clock is off, don't want to service interrupt. +- RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt); ++ if (Level != RTMP_HALT) ++ { ++ // Change Interrupt bitmask. ++ RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt); ++ } ++ else ++ { ++ NICDisableInterrupt(pAd); ++ } + + RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx); + // Disable MAC Rx +@@ -726,7 +740,8 @@ VOID RT28xxPciAsicRadioOff( + // 2. Send Sleep command + RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff); + RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff); +- AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout unit:40us. ++ // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power ++ AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1); + // 2-1. Wait command success + // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task. + brc = AsicCheckCommanOk(pAd, PowerSafeCID); +@@ -734,7 +749,7 @@ VOID RT28xxPciAsicRadioOff( + if (brc == FALSE) + { + // try again +- AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout unit:40us. ++ AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x01); // send POWER-SAVE command to MCU. Timeout unit:40us. + //RTMPusecDelay(200); + brc = AsicCheckCommanOk(pAd, PowerSafeCID); + } +@@ -759,7 +774,7 @@ VOID RT28xxPciAsicRadioOff( + do + { + RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); +- if (DmaCfg.field.RxDMABusy == 0) ++ if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0)) + break; + RTMPusecDelay(20); + i++; +@@ -767,13 +782,12 @@ VOID RT28xxPciAsicRadioOff( + + if (i >= 50) + { ++ pAd->CheckDmaBusyCount++; + DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. on RT28xxPciAsicRadioOff ()\n")); + } +- // disable DMA Rx. ++ else + { +- RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word); +- DmaCfg.field.EnableRxDMA = 0; +- RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word); ++ pAd->CheckDmaBusyCount = 0; + } + + if (Level == DOT11POWERSAVE) +@@ -799,7 +813,7 @@ VOID RT28xxPciAsicRadioOff( + if (Level == RTMP_HALT) + { + if ((brc == TRUE) && (i < 50)) +- RTMPPCIeLinkCtrlSetting(pAd, 1); ++ RTMPPCIeLinkCtrlSetting(pAd, 0); + } + // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function + else +@@ -808,7 +822,7 @@ VOID RT28xxPciAsicRadioOff( + RTMPPCIeLinkCtrlSetting(pAd, 3); + } + +- pAd->bPCIclkOffDisableTx = FALSE; ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX); + } + + +@@ -835,7 +849,8 @@ BOOLEAN RT28xxPciAsicRadioOn( + { + pAd->Mlme.bPsPollTimerRunning = FALSE; + RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); +- if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE)) ++ if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE) ++ || (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND))) + { + DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n")); + // 1. Set PCI Link Control in Configuration Space. +@@ -845,15 +860,14 @@ BOOLEAN RT28xxPciAsicRadioOn( + } + + pAd->bPCIclkOff = FALSE; +- ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x3a80); + // 2. Send wake up command. +- AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00); ++ AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02); + + // 2-1. wait command ok. + brv = AsicCheckCommanOk(pAd, PowerWakeCID); + if (brv) + { +- //RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT)); + NICEnableInterrupt(pAd); + + // 3. Enable Tx DMA. +@@ -893,13 +907,10 @@ BOOLEAN RT28xxPciAsicRadioOn( + + VOID RT28xxPciStaAsicForceWakeup( + IN PRTMP_ADAPTER pAd, +- IN BOOLEAN bFromTx) ++ IN UCHAR Level) + { + AUTO_WAKEUP_STRUC AutoWakeupCfg; + +- if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +- return; +- + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW)) + { + DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n")); +@@ -907,38 +918,48 @@ VOID RT28xxPciStaAsicForceWakeup( + } + + OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW); ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); + + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + // Support PCIe Advance Power Save +- if (bFromTx == TRUE) ++ if (((Level == FROM_TX) && (pAd->Mlme.bPsPollTimerRunning == TRUE)) || ++ (Level == RTMP_HALT)) + { + pAd->Mlme.bPsPollTimerRunning = FALSE; + RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP); +- RTMPusecDelay(3000); ++ RTMPusecDelay(5000); + DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n")); + } + + AutoWakeupCfg.word = 0; + RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); + +- if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE)) +- { +- // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. +- if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) +- && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) +- { +- // Must using 40MHz. +- AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); +- AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); +- } +- else +- { +- // Must using 20MHz. +- AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); +- AsicLockChannel(pAd, pAd->CommonCfg.Channel); +- } +- } ++ // If this is called from Halt. ALWAYS force wakeup!!! ++ if (Level == RTMP_HALT) ++ { ++ RT28xxPciAsicRadioOn(pAd, RTMP_HALT); ++ } ++ else ++ { ++ if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE)) ++ { ++ // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. ++ if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel) ++ && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ } ++ else ++ { ++ // Must using 20MHz. ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ } ++ } ++ } + } + else + { +@@ -1002,7 +1023,7 @@ VOID RT28xxPciStaAsicSleepThenAutoWakeup + AutoWakeupCfg.field.AutoLeadTime = 5; + RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); + AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us. +- DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __FUNCTION__, TbttNumToNextWakeUp)); ++ DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp)); + } + OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE); + } +@@ -1115,13 +1136,14 @@ VOID RT28xxPciMlmeRadioOn( + if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) + return; + +- DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__)); + + if ((pAd->OpMode == OPMODE_AP) || + ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))) + { + NICResetFromError(pAd); + ++ /* + RTMPRingCleanUp(pAd, QID_AC_BK); + RTMPRingCleanUp(pAd, QID_AC_BE); + RTMPRingCleanUp(pAd, QID_AC_VI); +@@ -1129,6 +1151,7 @@ VOID RT28xxPciMlmeRadioOn( + RTMPRingCleanUp(pAd, QID_HCCA); + RTMPRingCleanUp(pAd, QID_MGMT); + RTMPRingCleanUp(pAd, QID_RX); ++ */ + + // Enable Tx/Rx + RTMPEnableRxTx(pAd); +@@ -1162,20 +1185,25 @@ VOID RT28xxPciMlmeRadioOFF( + WPDMA_GLO_CFG_STRUC GloCfg; + UINT32 i; + ++ if (pAd->StaCfg.bRadio == TRUE) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n")); ++ return; ++ } ++ + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF)) + return; + +- DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__)); + + // Set LED + RTMPSetLED(pAd, LED_RADIO_OFF); +- // Set Radio off flag +- RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); + + #ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + BOOLEAN Cancelled; ++ + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) + { + RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); +@@ -1185,6 +1213,15 @@ VOID RT28xxPciMlmeRadioOFF( + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + BOOLEAN Cancelled; ++ ++ // Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF). ++ if ((pAd->OpMode == OPMODE_STA) && ++ (IDLE_ON(pAd)) && ++ (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) ++ { ++ RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); ++ } ++ + pAd->Mlme.bPsPollTimerRunning = FALSE; + RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); + RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); +@@ -1197,9 +1234,26 @@ VOID RT28xxPciMlmeRadioOFF( + //========================================== + // Clean up old bss table + BssTableInit(&pAd->ScanTab); ++ ++ RTMPRingCleanUp(pAd, QID_AC_BK); ++ RTMPRingCleanUp(pAd, QID_AC_BE); ++ RTMPRingCleanUp(pAd, QID_AC_VI); ++ RTMPRingCleanUp(pAd, QID_AC_VO); ++ RTMPRingCleanUp(pAd, QID_HCCA); ++ RTMPRingCleanUp(pAd, QID_MGMT); ++ RTMPRingCleanUp(pAd, QID_RX); ++ ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) ++ { ++ RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 500); ++ return; ++ } + } + #endif // CONFIG_STA_SUPPORT // + ++ // Set Radio off flag ++ RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); ++ + // Disable Tx/Rx DMA + RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word); // disable DMA + GloCfg.field.EnableTxDMA = 0; +--- a/drivers/staging/rt2860/common/cmm_info.c ++++ b/drivers/staging/rt2860/common/cmm_info.c +@@ -814,7 +814,6 @@ INT Show_DescInfo_Proc( + IN PRTMP_ADAPTER pAd, + IN PUCHAR arg) + { +-#ifdef RT2860 + INT i, QueIdx=0; + PRT28XX_RXD_STRUC pRxD; + PTXD_STRUC pTxD; +@@ -845,7 +844,6 @@ INT Show_DescInfo_Proc( + hex_dump("Rx Descriptor", (char *)pRxD, 16); + printk("pRxD->DDONE = %x\n", pRxD->DDONE); + } +-#endif // RT2860 // + + return TRUE; + } +@@ -1803,9 +1801,7 @@ VOID RTMPAddWcidAttributeEntry( + } + + // For key index and ext IV bit, so only need to update the position(offset+3). +-#ifdef RT2860 + RTMP_IO_WRITE8(pAd, offset+3, IVEIV); +-#endif // RT2860 // + + DBGPRINT(RT_DEBUG_TRACE,("RTMPAddWcidAttributeEntry: WCID #%d, KeyIndex #%d, Alg=%s\n",Wcid, KeyIdx, CipherName[CipherAlg])); + DBGPRINT(RT_DEBUG_TRACE,(" WCIDAttri = 0x%x \n", WCIDAttri)); +@@ -2039,7 +2035,7 @@ VOID RTMPIoctlGetMacTable( + wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE); + if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length)) + { +- DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __func__)); + } + + msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG); +@@ -2827,9 +2823,7 @@ INT Set_OpMode_Proc( + + Value = simple_strtol(arg, 0, 10); + +-#ifdef RT2860 + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE)) +-#endif // RT2860 // + { + DBGPRINT(RT_DEBUG_ERROR, ("Can not switch operate mode on interface up !! \n")); + return FALSE; +--- a/drivers/staging/rt2860/common/cmm_sync.c ++++ b/drivers/staging/rt2860/common/cmm_sync.c +@@ -470,7 +470,7 @@ VOID ScanNextChannel( + { + // BBP and RF are not accessible in PS mode, we has to wake them up first + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +- AsicForceWakeup(pAd, TRUE); ++ AsicForceWakeup(pAd, FROM_TX); + + // leave PSM during scanning. otherwise we may lost ProbeRsp & BEACON + if (pAd->StaCfg.Psm == PWR_SAVE) +--- a/drivers/staging/rt2860/common/cmm_wpa.c ++++ b/drivers/staging/rt2860/common/cmm_wpa.c +@@ -39,8 +39,10 @@ + // WPA OUI + UCHAR OUI_WPA_NONE_AKM[4] = {0x00, 0x50, 0xF2, 0x00}; + UCHAR OUI_WPA_VERSION[4] = {0x00, 0x50, 0xF2, 0x01}; ++UCHAR OUI_WPA_WEP40[4] = {0x00, 0x50, 0xF2, 0x01}; + UCHAR OUI_WPA_TKIP[4] = {0x00, 0x50, 0xF2, 0x02}; + UCHAR OUI_WPA_CCMP[4] = {0x00, 0x50, 0xF2, 0x04}; ++UCHAR OUI_WPA_WEP104[4] = {0x00, 0x50, 0xF2, 0x05}; + UCHAR OUI_WPA_8021X_AKM[4] = {0x00, 0x50, 0xF2, 0x01}; + UCHAR OUI_WPA_PSK_AKM[4] = {0x00, 0x50, 0xF2, 0x02}; + // WPA2 OUI +@@ -49,6 +51,7 @@ UCHAR OUI_WPA2_TKIP[4] = {0 + UCHAR OUI_WPA2_CCMP[4] = {0x00, 0x0F, 0xAC, 0x04}; + UCHAR OUI_WPA2_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x01}; + UCHAR OUI_WPA2_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x02}; ++UCHAR OUI_WPA2_WEP104[4] = {0x00, 0x0F, 0xAC, 0x05}; + // MSA OUI + UCHAR OUI_MSA_8021X_AKM[4] = {0x00, 0x0F, 0xAC, 0x05}; // Not yet final - IEEE 802.11s-D1.06 + UCHAR OUI_MSA_PSK_AKM[4] = {0x00, 0x0F, 0xAC, 0x06}; // Not yet final - IEEE 802.11s-D1.06 +@@ -367,6 +370,24 @@ static VOID RTMPInsertRsnIeCipher( + break; + } + ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) ++ { ++ UINT GroupCipher = pAd->StaCfg.GroupCipher; ++ switch(GroupCipher) ++ { ++ case Ndis802_11GroupWEP40Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP40, 4); ++ break; ++ case Ndis802_11GroupWEP104Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA2_WEP104, 4); ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ + // swap for big-endian platform + pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); + pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); +@@ -427,11 +448,28 @@ static VOID RTMPInsertRsnIeCipher( + break; + } + ++#ifdef CONFIG_STA_SUPPORT ++ if ((pAd->OpMode == OPMODE_STA) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption2Enabled) && ++ (pAd->StaCfg.GroupCipher != Ndis802_11Encryption3Enabled)) ++ { ++ UINT GroupCipher = pAd->StaCfg.GroupCipher; ++ switch(GroupCipher) ++ { ++ case Ndis802_11GroupWEP40Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP40, 4); ++ break; ++ case Ndis802_11GroupWEP104Enabled: ++ NdisMoveMemory(pRsnie_cipher->mcast, OUI_WPA_WEP104, 4); ++ break; ++ } ++ } ++#endif // CONFIG_STA_SUPPORT // ++ + // swap for big-endian platform + pRsnie_cipher->version = cpu2le16(pRsnie_cipher->version); + pRsnie_cipher->ucount = cpu2le16(pRsnie_cipher->ucount); + } +- + } + + /* +--- a/drivers/staging/rt2860/common/dfs.c ++++ b/drivers/staging/rt2860/common/dfs.c +@@ -428,7 +428,7 @@ INT Set_ChMovingTime_Proc( + + pAd->CommonCfg.RadarDetect.ChMovingTime = Value; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__, + pAd->CommonCfg.RadarDetect.ChMovingTime)); + + return TRUE; +@@ -444,7 +444,7 @@ INT Set_LongPulseRadarTh_Proc( + + pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__, ++ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__, + pAd->CommonCfg.RadarDetect.LongPulseRadarTh)); + + return TRUE; +--- a/drivers/staging/rt2860/common/mlme.c ++++ b/drivers/staging/rt2860/common/mlme.c +@@ -527,7 +527,6 @@ NDIS_STATUS MlmeInit( + + + #ifdef CONFIG_STA_SUPPORT +-#ifdef RT2860 + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) +@@ -537,7 +536,6 @@ NDIS_STATUS MlmeInit( + RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer, GET_TIMER_FUNCTION(RadioOnExec), pAd, FALSE); + } + } +-#endif // RT2860 // + #endif // CONFIG_STA_SUPPORT // + + } while (FALSE); +@@ -711,13 +709,11 @@ VOID MlmeHalt( + RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); + RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); + RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); +-#ifdef RT2860 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); + RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); + } +-#endif // RT2860 // + + #ifdef QOS_DLS_SUPPORT + for (i=0; iStaCfg.WepStatus)); ++ //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0. ++ //If the STA security setting is WPAPSK or WPA2PSK, pAd->StaCfg.WpaSupplicantUP = 1. ++ if(pAd->StaCfg.WepStatus<2) ++ { ++ pAd->StaCfg.WpaSupplicantUP = 0; ++ } ++ else ++ { ++ pAd->StaCfg.WpaSupplicantUP = 1; ++ } ++ + #ifdef CONFIG_STA_SUPPORT +-#ifdef RT2860 + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + // If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second. + // Move code to here, because following code will return when radio is off +- if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) == 0) && (pAd->StaCfg.bHardwareRadio == TRUE) && ++ if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) == 0) && ++ (pAd->StaCfg.bHardwareRadio == TRUE) && ++ (RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP)) && + (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && +- (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) && +- (pAd->bPCIclkOff == FALSE)) ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) + { + UINT32 data = 0; + + // Read GPIO pin2 as Hardware controlled radio state +- RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); ++ RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data); + if (data & 0x04) + { + pAd->StaCfg.bHwRadio = TRUE; +@@ -849,7 +858,6 @@ VOID MlmePeriodicExec( + } + } + } +-#endif // RT2860 // + #endif // CONFIG_STA_SUPPORT // + + // Do nothing if the driver is starting halt state. +@@ -860,6 +868,45 @@ VOID MlmePeriodicExec( + fRTMP_ADAPTER_RESET_IN_PROGRESS)))) + return; + ++ IF_DEV_CONFIG_OPMODE_ON_STA(pAd) ++ { ++ if ((pAd->RalinkCounters.LastReceivedByteCount == pAd->RalinkCounters.ReceivedByteCount) && (pAd->StaCfg.bRadio == TRUE)) ++ { ++ // If ReceiveByteCount doesn't change, increase SameRxByteCount by 1. ++ pAd->SameRxByteCount++; ++ } ++ else ++ pAd->SameRxByteCount = 0; ++ ++ // If after BBP, still not work...need to check to reset PBF&MAC. ++ if (pAd->SameRxByteCount == 702) ++ { ++ pAd->SameRxByteCount = 0; ++ AsicResetPBF(pAd); ++ AsicResetMAC(pAd); ++ } ++ ++ // If SameRxByteCount keeps happens for 2 second in infra mode, or for 60 seconds in idle mode. ++ if (((INFRA_ON(pAd)) && (pAd->SameRxByteCount > 20)) || ((IDLE_ON(pAd)) && (pAd->SameRxByteCount > 600))) ++ { ++ if ((pAd->StaCfg.bRadio == TRUE) && (pAd->SameRxByteCount < 700)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("---> SameRxByteCount = %lu !!!!!!!!!!!!!!! \n", pAd->SameRxByteCount)); ++ pAd->SameRxByteCount = 700; ++ AsicResetBBP(pAd); ++ } ++ } ++ ++ // Update lastReceiveByteCount. ++ pAd->RalinkCounters.LastReceivedByteCount = pAd->RalinkCounters.ReceivedByteCount; ++ ++ if ((pAd->CheckDmaBusyCount > 3) && (IDLE_ON(pAd))) ++ { ++ pAd->CheckDmaBusyCount = 0; ++ AsicResetFromDMABusy(pAd); ++ } ++ } ++ + RT28XX_MLME_PRE_SANITY_CHECK(pAd); + + #ifdef RALINK_ATE +@@ -1022,9 +1069,7 @@ VOID MlmePeriodicExec( + #ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { +-#ifdef RT2860 + if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->bPCIclkOff == FALSE)) +-#endif // RT2860 // + { + // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock + // and sending CTS-to-self over and over. +@@ -1081,6 +1126,19 @@ VOID STAMlmePeriodicExec( + pAd->StaCfg.bBlockAssoc = FALSE; + } + ++ //Baron 2008/07/10 ++ //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus)); ++ //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0. ++ //If the STA security setting is WPAPSK or WPA2PSK, pAd->StaCfg.WpaSupplicantUP = 1. ++ if(pAd->StaCfg.WepStatus<2) ++ { ++ pAd->StaCfg.WpaSupplicantUP = 0; ++ } ++ else ++ { ++ pAd->StaCfg.WpaSupplicantUP = 1; ++ } ++ + if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) + { + if (pAd->IndicateMediaState == NdisMediaStateConnected) +@@ -1090,6 +1148,15 @@ VOID STAMlmePeriodicExec( + pAd->PreMediaState = pAd->IndicateMediaState; + } + ++ if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd)) && ++ (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && ++ (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE) && ++ (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && ++ (RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP)) && ++ (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) ++ { ++ RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0); ++ } + + + +@@ -2781,7 +2848,7 @@ VOID MlmeCheckPsmChange( + if (INFRA_ON(pAd) && + (PowerMode != Ndis802_11PowerModeCAM) && + (pAd->StaCfg.Psm == PWR_ACTIVE) && +- (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) ++ RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)) + { + NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); + pAd->RalinkCounters.RxCountSinceLastNULL = 0; +@@ -4065,7 +4132,9 @@ VOID BssTableSsidSort( + continue; + + // check group cipher +- if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) ++ if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && ++ (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) && ++ (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled)) + continue; + + // check pairwise cipher, skip if none matched +@@ -4084,7 +4153,9 @@ VOID BssTableSsidSort( + continue; + + // check group cipher +- if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) ++ if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && ++ (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) && ++ (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled)) + continue; + + // check pairwise cipher, skip if none matched +@@ -4371,8 +4442,10 @@ VOID BssCipherParse( + switch (*pTmp) + { + case 1: +- case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway +- pBss->WPA.GroupCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled; ++ break; ++ case 5: ++ pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled; + break; + case 2: + pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; +@@ -4489,8 +4562,10 @@ VOID BssCipherParse( + switch (pCipher->Type) + { + case 1: +- case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway +- pBss->WPA2.GroupCipher = Ndis802_11Encryption1Enabled; ++ pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled; ++ break; ++ case 5: ++ pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled; + break; + case 2: + pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; +@@ -4953,16 +5028,13 @@ BOOLEAN MlmeDequeue( + VOID MlmeRestartStateMachine( + IN PRTMP_ADAPTER pAd) + { +-#ifdef RT2860 + MLME_QUEUE_ELEM *Elem = NULL; +-#endif // RT2860 // + #ifdef CONFIG_STA_SUPPORT + BOOLEAN Cancelled; + #endif // CONFIG_STA_SUPPORT // + + DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); + +-#ifdef RT2860 + NdisAcquireSpinLock(&pAd->Mlme.TaskLock); + if(pAd->Mlme.bRunning) + { +@@ -4990,7 +5062,6 @@ VOID MlmeRestartStateMachine( + DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n")); + } + } +-#endif // RT2860 // + + #ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +@@ -5039,12 +5110,10 @@ VOID MlmeRestartStateMachine( + } + #endif // CONFIG_STA_SUPPORT // + +-#ifdef RT2860 + // Remove running state + NdisAcquireSpinLock(&pAd->Mlme.TaskLock); + pAd->Mlme.bRunning = FALSE; + NdisReleaseSpinLock(&pAd->Mlme.TaskLock); +-#endif // RT2860 // + } + + /*! \brief test if the MLME Queue is empty +@@ -6149,6 +6218,12 @@ VOID AsicAdjustTxPower( + ULONG TxPwr[5]; + CHAR Value; + ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) ++ || (pAd->bPCIclkOff == TRUE) ++ || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF) ++ || RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) ++ return; ++ + if (pAd->CommonCfg.BBPCurrentBW == BW_40) + { + if (pAd->CommonCfg.CentralChannel > 14) +@@ -6493,10 +6568,10 @@ VOID AsicForceSleep( + */ + VOID AsicForceWakeup( + IN PRTMP_ADAPTER pAd, +- IN BOOLEAN bFromTx) ++ IN UCHAR Level) + { + DBGPRINT(RT_DEBUG_TRACE, ("--> AsicForceWakeup \n")); +- RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx); ++ RT28XX_STA_FORCE_WAKEUP(pAd, Level); + } + #endif // CONFIG_STA_SUPPORT // + /* +@@ -6710,7 +6785,6 @@ VOID AsicEnableIbssSync( + csr9.field.bTsfTicking = 0; + RTMP_IO_WRITE32(pAd, BCN_TIME_CFG, csr9.word); + +-#ifdef RT2860 + // move BEACON TXD and frame content to on-chip memory + ptr = (PUCHAR)&pAd->BeaconTxWI; + for (i=0; iCommonCfg.BeaconPeriod << 4; // ASIC register in units of 1/16 TU +@@ -7097,9 +7170,7 @@ VOID AsicAddSharedKeyEntry( + { + ULONG offset; //, csr0; + SHAREDKEY_MODE_STRUC csr1; +-#ifdef RT2860 + INT i; +-#endif // RT2860 // + + DBGPRINT(RT_DEBUG_TRACE, ("AsicAddSharedKeyEntry BssIndex=%d, KeyIdx=%d\n", BssIndex,KeyIdx)); + //============================================================================================ +@@ -7121,7 +7192,6 @@ VOID AsicAddSharedKeyEntry( + // + // fill key material - key + TX MIC + RX MIC + // +-#ifdef RT2860 + offset = SHARED_KEY_TABLE_BASE + (4*BssIndex + KeyIdx)*HW_KEY_ENTRY_SIZE; + for (i=0; iTxTsc; + UCHAR CipherAlg = pCipherKey->CipherAlg; + SHAREDKEY_MODE_STRUC csr1; +-#ifdef RT2860 + UCHAR i; +-#endif // RT2860 // + + DBGPRINT(RT_DEBUG_TRACE, ("==> AsicAddKeyEntry\n")); + // +@@ -7337,7 +7404,6 @@ VOID AsicAddKeyEntry( + // 2.) Set Key to Asic + // + //for (i = 0; i < KeyLen; i++) +-#ifdef RT2860 + for (i = 0; i < MAX_LEN_OF_PEER_KEY; i++) + { + RTMP_IO_WRITE8(pAd, offset + i, pKey[i]); +@@ -7363,7 +7429,6 @@ VOID AsicAddKeyEntry( + RTMP_IO_WRITE8(pAd, offset + i, pRxMic[i]); + } + } +-#endif // RT2860 // + + + // +@@ -7372,7 +7437,6 @@ VOID AsicAddKeyEntry( + // + if (bTxKey) + { +-#ifdef RT2860 + offset = MAC_IVEIV_TABLE_BASE + (WCID * HW_IVEIV_ENTRY_SIZE); + // + // Write IV +@@ -7395,7 +7459,6 @@ VOID AsicAddKeyEntry( + { + RTMP_IO_WRITE8(pAd, offset + i, pTxtsc[i + 2]); + } +-#endif // RT2860 // + + AsicUpdateWCIDAttribute(pAd, WCID, BssIndex, CipherAlg, bUsePairewiseKeyTable); + } +@@ -7461,12 +7524,10 @@ VOID AsicAddPairwiseKeyEntry( + + // EKEY + offset = PAIRWISE_KEY_TABLE_BASE + (WCID * HW_KEY_ENTRY_SIZE); +-#ifdef RT2860 + for (i=0; i= 100) + { +-#ifdef RT2860 + #ifdef RALINK_ATE + if (pAd->ate.bFWLoading == TRUE) + { +@@ -7583,14 +7637,33 @@ BOOLEAN AsicSendCommandToMcu( + } + else + #endif // RALINK_ATE // +-#endif // RT2860 // + { ++ UINT32 Data; ++ ++ // Reset DMA ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); ++ Data |= 0x2; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ ++ // After Reset DMA, DMA index will become Zero. So Driver need to reset all ring indexs too. ++ // Reset DMA/CPU ring index ++ RTMPRingCleanUp(pAd, QID_AC_BK); ++ RTMPRingCleanUp(pAd, QID_AC_BE); ++ RTMPRingCleanUp(pAd, QID_AC_VI); ++ RTMPRingCleanUp(pAd, QID_AC_VO); ++ RTMPRingCleanUp(pAd, QID_HCCA); ++ RTMPRingCleanUp(pAd, QID_MGMT); ++ RTMPRingCleanUp(pAd, QID_RX); ++ ++ // Clear Reset ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); ++ Data &= 0xfffffffd; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); + DBGPRINT_ERR(("H2M_MAILBOX still hold by MCU. command fail\n")); + } +- return FALSE; ++ //return FALSE; + } + +-#ifdef RT2860 + #ifdef RALINK_ATE + else if (pAd->ate.bFWLoading == TRUE) + { +@@ -7600,7 +7673,6 @@ BOOLEAN AsicSendCommandToMcu( + j = 0; + } + #endif // RALINK_ATE // +-#endif // RT2860 // + + H2MMailbox.field.Owner = 1; // pass ownership to MCU + H2MMailbox.field.CmdToken = Token; +@@ -7619,7 +7691,6 @@ BOOLEAN AsicSendCommandToMcu( + return TRUE; + } + +-#ifdef RT2860 + BOOLEAN AsicCheckCommanOk( + IN PRTMP_ADAPTER pAd, + IN UCHAR Command) +@@ -7684,7 +7755,6 @@ BOOLEAN AsicCheckCommanOk( + + return FALSE; + } +-#endif // RT2860 // + + /* + ======================================================================== +@@ -8096,10 +8166,8 @@ VOID AsicEvaluateRxAnt( + } + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); + #ifdef CONFIG_STA_SUPPORT +-#ifdef RT2860 + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + pAd->StaCfg.BBPR3 = BBPR3; +-#endif // RT2860 // + #endif // CONFIG_STA_SUPPORT // + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) + ) +@@ -8211,9 +8279,7 @@ VOID AsicRxAntEvalTimeout( + BBPR3 |= (0x0); + } + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); +-#ifdef RT2860 +- pAd->StaCfg.BBPR3 = BBPR3; +-#endif // RT2860 // ++ pAd->StaCfg.BBPR3 = BBPR3; + } + + #endif // CONFIG_STA_SUPPORT // +@@ -8439,10 +8505,7 @@ VOID AsicStaBbpTuning( + && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) + ) + && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) +-#ifdef RT2860 +- && (pAd->bPCIclkOff == FALSE) +-#endif // RT2860 // +- ) ++ && (pAd->bPCIclkOff == FALSE)) + { + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); + R66 = OrigR66Value; +@@ -8518,6 +8581,106 @@ VOID AsicStaBbpTuning( + + } + } ++ ++VOID AsicResetFromDMABusy( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UINT32 Data; ++ BOOLEAN bCtrl = FALSE; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("---> AsicResetFromDMABusy !!!!!!!!!!!!!!!!!!!!!!! \n")); ++ ++ // Be sure restore link control value so we can write register. ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) ++ { ++ DBGPRINT(RT_DEBUG_TRACE,("AsicResetFromDMABusy==>\n")); ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_HALT); ++ RTMPusecDelay(6000); ++ pAd->bPCIclkOff = FALSE; ++ bCtrl = TRUE; ++ } ++ // Reset DMA ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); ++ Data |= 0x2; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ ++ // After Reset DMA, DMA index will become Zero. So Driver need to reset all ring indexs too. ++ // Reset DMA/CPU ring index ++ RTMPRingCleanUp(pAd, QID_AC_BK); ++ RTMPRingCleanUp(pAd, QID_AC_BE); ++ RTMPRingCleanUp(pAd, QID_AC_VI); ++ RTMPRingCleanUp(pAd, QID_AC_VO); ++ RTMPRingCleanUp(pAd, QID_HCCA); ++ RTMPRingCleanUp(pAd, QID_MGMT); ++ RTMPRingCleanUp(pAd, QID_RX); ++ ++ // Clear Reset ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); ++ Data &= 0xfffffffd; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ ++ // If in Radio off, should call RTMPPCIePowerLinkCtrl again. ++ if ((bCtrl == TRUE) && (pAd->StaCfg.bRadio == FALSE)) ++ RTMPPCIeLinkCtrlSetting(pAd, 3); ++ ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST | fRTMP_ADAPTER_HALT_IN_PROGRESS); ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- AsicResetFromDMABusy !!!!!!!!!!!!!!!!!!!!!!! \n")); ++} ++ ++VOID AsicResetBBP( ++ IN PRTMP_ADAPTER pAd) ++{ ++ DBGPRINT(RT_DEBUG_TRACE, ("---> Asic HardReset BBP !!!!!!!!!!!!!!!!!!!!!!! \n")); ++ ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x0); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x2); ++ RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xc); ++ ++ // After hard-reset BBP, initialize all BBP values. ++ NICRestoreBBPValue(pAd); ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- Asic HardReset BBP !!!!!!!!!!!!!!!!!!!!!!! \n")); ++} ++ ++VOID AsicResetMAC( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG Data; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("---> AsicResetMAC !!!! \n")); ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); ++ Data |= 0x4; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ Data &= 0xfffffffb; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- AsicResetMAC !!!! \n")); ++} ++ ++VOID AsicResetPBF( ++ IN PRTMP_ADAPTER pAd) ++{ ++ ULONG Value1, Value2; ++ ULONG Data; ++ ++ RTMP_IO_READ32(pAd, TXRXQ_PCNT, &Value1); ++ RTMP_IO_READ32(pAd, PBF_DBG, &Value2); ++ ++ Value2 &= 0xff; ++ // sum should be equals to 0xff, which is the total buffer size. ++ if ((Value1 + Value2) < 0xff) ++ { ++ DBGPRINT(RT_DEBUG_TRACE, ("---> Asic HardReset PBF !!!! \n")); ++ RTMP_IO_READ32(pAd, PBF_SYS_CTRL, &Data); ++ Data |= 0x8; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ Data &= 0xfffffff7; ++ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, Data); ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- Asic HardReset PBF !!!! \n")); ++ } ++} + #endif // CONFIG_STA_SUPPORT // + + VOID RTMPSetAGCInitValue( +--- a/drivers/staging/rt2860/common/rtmp_init.c ++++ b/drivers/staging/rt2860/common/rtmp_init.c +@@ -39,6 +39,7 @@ + */ + #include "../rt_config.h" + #include "firmware.h" ++#include + + UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; + ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, +@@ -89,20 +90,6 @@ const unsigned short ccitt_16Table[] = { + #define ByteCRC16(v, crc) \ + (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) + +-unsigned char BitReverse(unsigned char x) +-{ +- int i; +- unsigned char Temp=0; +- for(i=0; ; i++) +- { +- if(x & 0x80) Temp |= 0x80; +- if(i==7) break; +- x <<= 1; +- Temp >>= 1; +- } +- return Temp; +-} +- + // + // BBP register initialization set + // +@@ -162,9 +149,7 @@ RTMP_REG_PAIR MACRegTable[] = { + {GF20_PROT_CFG, 0x01744004}, // set 19:18 --> Short NAV for MIMO PS + {GF40_PROT_CFG, 0x03F44084}, + {MM20_PROT_CFG, 0x01744004}, +-#ifdef RT2860 + {MM40_PROT_CFG, 0x03F54084}, +-#endif // RT2860 // + {TXOP_CTRL_CFG, 0x0000583f, /*0x0000243f*/ /*0x000024bf*/}, //Extension channel backoff. + {TX_RTS_CFG, 0x00092b20}, + {EXP_ACK_TIME, 0x002400ca}, // default value +@@ -201,9 +186,7 @@ RTMP_REG_PAIR STAMACRegTable[] = { + #define FIRMWAREIMAGEV1_LENGTH 0x1000 + #define FIRMWAREIMAGEV2_LENGTH 0x1000 + +-#ifdef RT2860 + #define FIRMWARE_MINOR_VERSION 2 +-#endif // RT2860 // + + + /* +@@ -261,9 +244,7 @@ NDIS_STATUS RTMPAllocAdapterBlock( + + // Init spin locks + NdisAllocateSpinLock(&pAd->MgmtRingLock); +-#ifdef RT2860 + NdisAllocateSpinLock(&pAd->RxRingLock); +-#endif // RT2860 // + + for (index =0 ; index < NUM_OF_TX_RING; index++) + { +@@ -1568,10 +1549,7 @@ VOID NICInitAsicFromEEPROM( + pAd->LedCntl.word = 0x01; + pAd->Led1 = 0x5555; + pAd->Led2 = 0x2221; +- +-#ifdef RT2860 + pAd->Led3 = 0xA9F8; +-#endif // RT2860 // + } + + AsicSendCommandToMcu(pAd, 0x52, 0xff, (UCHAR)pAd->Led1, (UCHAR)(pAd->Led1 >> 8)); +@@ -1607,12 +1585,10 @@ VOID NICInitAsicFromEEPROM( + else + { + RTMPSetLED(pAd, LED_RADIO_ON); +-#ifdef RT2860 + AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x02); + AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00); + // 2-1. wait command ok. + AsicCheckCommanOk(pAd, PowerWakeCID); +-#endif // RT2860 // + } + } + #endif // CONFIG_STA_SUPPORT // +@@ -1690,10 +1666,8 @@ NDIS_STATUS NICInitializeAdapter( + { + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + WPDMA_GLO_CFG_STRUC GloCfg; +-#ifdef RT2860 + UINT32 Value; + DELAY_INT_CFG_STRUC IntCfg; +-#endif // RT2860 // + ULONG i =0, j=0; + AC_TXOP_CSR0_STRUC csr0; + +@@ -1732,11 +1706,9 @@ retry: + + // asic simulation sequence put this ahead before loading firmware. + // pbf hardware reset +-#ifdef RT2860 + RTMP_IO_WRITE32(pAd, WPDMA_RST_IDX, 0x1003f); // 0x10000 for reset rx, 0x3f resets all 6 tx rings. + RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0xe1f); + RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0xe00); +-#endif // RT2860 // + + // Initialze ASIC for TX & Rx operation + if (NICInitializeAsic(pAd , bHardReset) != NDIS_STATUS_SUCCESS) +@@ -1750,7 +1722,6 @@ retry: + } + + +-#ifdef RT2860 + // Write AC_BK base address register + Value = RTMP_GetPhysicalAddressLow(pAd->TxRing[QID_AC_BK].Cell[0].AllocPa); + RTMP_IO_WRITE32(pAd, TX_BASE_PTR1, Value); +@@ -1823,7 +1794,6 @@ retry: + // Write RX_RING_CSR register + Value = RX_RING_SIZE; + RTMP_IO_WRITE32(pAd, RX_MAX_CNT, Value); +-#endif // RT2860 // + + + // WMM parameter +@@ -1842,7 +1812,6 @@ retry: + RTMP_IO_WRITE32(pAd, WMM_TXOP1_CFG, csr0.word); + + +-#ifdef RT2860 + // 3. Set DMA global configuration except TX_DMA_EN and RX_DMA_EN bits: + i = 0; + do +@@ -1861,7 +1830,6 @@ retry: + + IntCfg.word = 0; + RTMP_IO_WRITE32(pAd, DELAY_INT_CFG, IntCfg.word); +-#endif // RT2860 // + + + // reset action +@@ -1902,7 +1870,6 @@ NDIS_STATUS NICInitializeAsic( + + DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitializeAsic\n")); + +-#ifdef RT2860 + if (bHardReset == TRUE) + { + RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x3); +@@ -1927,7 +1894,6 @@ NDIS_STATUS NICInitializeAsic( + } + } + #endif // CONFIG_STA_SUPPORT // +-#endif // RT2860 // + + + // +@@ -2054,6 +2020,131 @@ NDIS_STATUS NICInitializeAsic( + return NDIS_STATUS_SUCCESS; + } + ++ ++VOID NICRestoreBBPValue( ++ IN PRTMP_ADAPTER pAd) ++{ ++ UCHAR index; ++ UCHAR Value = 0; ++ ULONG Data; ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("---> NICRestoreBBPValue !!!!!!!!!!!!!!!!!!!!!!! \n")); ++ // Initialize BBP register to default value (rtmp_init.c) ++ for (index = 0; index < NUM_BBP_REG_PARMS; index++) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBPRegTable[index].Register, BBPRegTable[index].Value); ++ } ++ // copy from (rtmp_init.c) ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x12); ++ } ++ ++ // copy from (connect.c LinkUp function) ++ if (INFRA_ON(pAd)) ++ { ++ // Change to AP channel ++ if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ // RX : control channel at lower ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ // Record BBPR3 setting, But don't keep R Antenna # information. ++ pAd->StaCfg.BBPR3 = Value; ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) ++ { ++ // Must using 40MHz. ++ pAd->CommonCfg.BBPCurrentBW = BW_40; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ Value |= 0x10; ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data |= 0x1; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value |= (0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ // Record BBPR3 setting, But don't keep R Antenna # information. ++ pAd->StaCfg.BBPR3 = Value; ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel )); ++ } ++ else ++ { ++ pAd->CommonCfg.BBPCurrentBW = BW_20; ++ AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); ++ AsicLockChannel(pAd, pAd->CommonCfg.Channel); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value); ++ Value &= (~0x18); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value); ++ ++ RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); ++ Data &= 0xfffffffe; ++ RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data); ++ ++ RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); ++ Value &= (~0x20); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); ++ // Record BBPR3 setting, But don't keep R Antenna # information. ++ pAd->StaCfg.BBPR3 = Value; ++ ++ if (pAd->MACVersion == 0x28600100) ++ { ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08); ++ RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11); ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" )); ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("!!!20MHz LINK UP !!! \n" )); ++ } ++ } ++ ++ DBGPRINT(RT_DEBUG_TRACE, ("<--- NICRestoreBBPValue !!!!!!!!!!!!!!!!!!!!!!! \n")); ++} ++ + /* + ======================================================================== + +@@ -2555,7 +2646,7 @@ NDIS_STATUS NICLoadFirmware( + #ifdef BIN_IN_FILE + #define NICLF_DEFAULT_USE() \ + flg_default_firm_use = TRUE; \ +- printk("%s - Use default firmware!\n", __FUNCTION__); ++ printk("%s - Use default firmware!\n", __func__); + + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + PUCHAR src; +@@ -2570,7 +2661,7 @@ NDIS_STATUS NICLoadFirmware( + BOOLEAN flg_default_firm_use = FALSE; + + +- DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __func__)); + + /* init */ + pFirmwareImage = NULL; +@@ -2593,7 +2684,7 @@ NDIS_STATUS NICLoadFirmware( + if (pFirmwareImage == NULL) + { + /* allocate fail, use default firmware array in firmware.h */ +- printk("%s - Allocate memory fail!\n", __FUNCTION__); ++ printk("%s - Allocate memory fail!\n", __func__); + NICLF_DEFAULT_USE(); + } + else +@@ -2614,7 +2705,7 @@ NDIS_STATUS NICLoadFirmware( + if (IS_ERR(srcf)) + { + printk("%s - Error %ld opening %s\n", +- __FUNCTION__, -PTR_ERR(srcf), src); ++ __func__, -PTR_ERR(srcf), src); + NICLF_DEFAULT_USE(); + break; + } /* End of if */ +@@ -2622,7 +2713,7 @@ NDIS_STATUS NICLoadFirmware( + /* the object must have a read method */ + if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) + { +- printk("%s - %s does not have a write method\n", __FUNCTION__, src); ++ printk("%s - %s does not have a write method\n", __func__, src); + NICLF_DEFAULT_USE(); + break; + } /* End of if */ +@@ -2636,7 +2727,7 @@ NDIS_STATUS NICLoadFirmware( + if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) + { + printk("%s: error file length (=%d) in RT2860AP.BIN\n", +- __FUNCTION__, FileLength); ++ __func__, FileLength); + NICLF_DEFAULT_USE(); + break; + } +@@ -2648,18 +2739,18 @@ NDIS_STATUS NICLoadFirmware( + + /* calculate firmware CRC */ + for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) +- crc = ByteCRC16(BitReverse(*ptr), crc); ++ crc = ByteCRC16(bitrev8(*ptr), crc); + /* End of for */ + + if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ +- (UCHAR)BitReverse((UCHAR)(crc>>8))) || ++ (UCHAR)bitrev8((UCHAR)(crc>>8))) || + (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ +- (UCHAR)BitReverse((UCHAR)crc))) ++ (UCHAR)bitrev8((UCHAR)crc))) + { + /* CRC fail */ + printk("%s: CRC = 0x%02x 0x%02x " + "error, should be 0x%02x 0x%02x\n", +- __FUNCTION__, ++ __func__, + pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], + pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], + (UCHAR)(crc>>8), (UCHAR)(crc)); +@@ -2678,7 +2769,7 @@ NDIS_STATUS NICLoadFirmware( + ((FIRMWARE_MAJOR_VERSION << 8) + + FIRMWARE_MINOR_VERSION)) + { +- printk("%s: firmware version too old!\n", __FUNCTION__); ++ printk("%s: firmware version too old!\n", __func__); + NICLF_DEFAULT_USE(); + break; + } /* End of if */ +@@ -2783,7 +2874,7 @@ NDIS_STATUS NICLoadFirmware( + } /* End of if */ + + DBGPRINT(RT_DEBUG_TRACE, +- ("<=== %s (status=%d)\n", __FUNCTION__, Status)); ++ ("<=== %s (status=%d)\n", __func__, Status)); + return Status; + } /* End of NICLoadFirmware */ + +@@ -3041,11 +3132,10 @@ VOID UserCfgInit( + pAd->CommonCfg.BBPCurrentBW = BW_20; + + pAd->LedCntl.word = 0; +-#ifdef RT2860 + pAd->LedIndicatorStregth = 0; + pAd->RLnkCtrlOffset = 0; + pAd->HostLnkCtrlOffset = 0; +-#endif // RT2860 // ++ pAd->CheckDmaBusyCount = 0; + + pAd->bAutoTxAgcA = FALSE; // Default is OFF + pAd->bAutoTxAgcG = FALSE; // Default is OFF +@@ -3305,9 +3395,7 @@ VOID UserCfgInit( + pAd->ate.bRxFer = 0; + pAd->ate.bQATxStart = FALSE; + pAd->ate.bQARxStart = FALSE; +-#ifdef RT2860 + pAd->ate.bFWLoading = FALSE; +-#endif // RT2860 // + #ifdef RALINK_28xx_QA + //pAd->ate.Repeat = 0; + pAd->ate.TxStatus = 0; +@@ -3317,11 +3405,9 @@ VOID UserCfgInit( + + + pAd->CommonCfg.bWiFiTest = FALSE; +-#ifdef RT2860 +- pAd->bPCIclkOff = FALSE; +-#endif // RT2860 // +- ++ pAd->bPCIclkOff = FALSE; + ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); + DBGPRINT(RT_DEBUG_TRACE, ("<-- UserCfgInit\n")); + } + +--- a/drivers/staging/rt2860/common/spectrum.c ++++ b/drivers/staging/rt2860/common/spectrum.c +@@ -49,7 +49,7 @@ VOID MeasureReqTabInit( + if (pAd->CommonCfg.pMeasureReqTab) + NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB)); + else +- DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __func__)); + + return; + } +@@ -77,7 +77,7 @@ static PMEASURE_REQ_ENTRY MeasureReqLook + + if (pTab == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__)); + return NULL; + } + +@@ -114,7 +114,7 @@ static PMEASURE_REQ_ENTRY MeasureReqInse + + if(pTab == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__)); + return NULL; + } + +@@ -175,7 +175,7 @@ static PMEASURE_REQ_ENTRY MeasureReqInse + else + { + pEntry = NULL; +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __func__)); + } + + // add this Neighbor entry into HASH table +@@ -210,7 +210,7 @@ static VOID MeasureReqDelete( + + if(pTab == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__)); + return; + } + +@@ -267,7 +267,7 @@ VOID TpcReqTabInit( + if (pAd->CommonCfg.pTpcReqTab) + NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB)); + else +- DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __func__)); + + return; + } +@@ -295,7 +295,7 @@ static PTPC_REQ_ENTRY TpcReqLookUp( + + if (pTab == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__)); + return NULL; + } + +@@ -333,7 +333,7 @@ static PTPC_REQ_ENTRY TpcReqInsert( + + if(pTab == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__)); + return NULL; + } + +@@ -394,7 +394,7 @@ static PTPC_REQ_ENTRY TpcReqInsert( + else + { + pEntry = NULL; +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __func__)); + } + + // add this Neighbor entry into HASH table +@@ -429,7 +429,7 @@ static VOID TpcReqDelete( + + if(pTab == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__)); + return; + } + +@@ -782,7 +782,7 @@ VOID EnqueueMeasurementReq( + NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { +- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); + return; + } + NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); +@@ -844,7 +844,7 @@ VOID EnqueueMeasurementRep( + NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { +- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); + return; + } + NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); +@@ -898,7 +898,7 @@ VOID EnqueueTPCReq( + NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { +- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); + return; + } + NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); +@@ -950,7 +950,7 @@ VOID EnqueueTPCRep( + NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { +- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); + return; + } + NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); +@@ -1003,7 +1003,7 @@ VOID EnqueueChSwAnn( + NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory + if(NStatus != NDIS_STATUS_SUCCESS) + { +- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__)); + return; + } + NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11)); +@@ -1596,7 +1596,7 @@ static VOID PeerMeasureReportAction( + + if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT))); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%zu).\n", __func__, sizeof(MEASURE_RPI_REPORT))); + return; + } + +@@ -1705,7 +1705,7 @@ static VOID PeerTpcRepAction( + { + TpcReqDelete(pAd, pEntry->DialogToken); + DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n", +- __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); ++ __func__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin)); + } + } + +@@ -1821,7 +1821,7 @@ INT Set_MeasureReq_Proc( + MeasureReqType = simple_strtol(thisChar, 0, 16); + if (MeasureReqType > 3) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __func__, MeasureReqType)); + return TRUE; + } + break; +@@ -1833,10 +1833,10 @@ INT Set_MeasureReq_Proc( + ArgIdx++; + } + +- DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __func__, Aid, MeasureReqType, MeasureCh)); + if (!VALID_WCID(Aid)) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid)); + return TRUE; + } + +@@ -1861,10 +1861,10 @@ INT Set_TpcReq_Proc( + + Aid = simple_strtol(arg, 0, 16); + +- DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __func__, Aid)); + if (!VALID_WCID(Aid)) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid)); + return TRUE; + } + +--- a/drivers/staging/rt2860/config.mk ++++ b/drivers/staging/rt2860/config.mk +@@ -108,10 +108,6 @@ ifeq ($(HAS_EXT_BUILD_CHANNEL_LIST),y) + WFLAGS += -DEXT_BUILD_CHANNEL_LIST + endif + +-ifeq ($(CHIPSET),2860) +-WFLAGS +=-DRT2860 +-endif +- + ifeq ($(CHIPSET),2870) + WFLAGS +=-DRT2870 + endif +--- a/drivers/staging/rt2860/oid.h ++++ b/drivers/staging/rt2860/oid.h +@@ -544,6 +544,8 @@ typedef enum _NDIS_802_11_WEP_STATUS + Ndis802_11Encryption3KeyAbsent, + Ndis802_11Encryption4Enabled, // TKIP or AES mix + Ndis802_11Encryption4KeyAbsent, ++ Ndis802_11GroupWEP40Enabled, ++ Ndis802_11GroupWEP104Enabled, + } NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, + NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; + +--- a/drivers/staging/rt2860/rt2860.h ++++ b/drivers/staging/rt2860/rt2860.h +@@ -46,18 +46,10 @@ + Status = NDIS_STATUS_SUCCESS; + + /* function declarations */ +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #define IRQ_HANDLE_TYPE irqreturn_t +-#else +-#define IRQ_HANDLE_TYPE void +-#endif + + IRQ_HANDLE_TYPE +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) + rt2860_interrupt(int irq, void *dev_instance); +-#else +-rt2860_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +-#endif + + /* ----------------- Frimware Related MACRO ----------------- */ + #define RT28XX_WRITE_FIRMWARE(_pAd, _pFwImage, _FwLen) \ +@@ -237,12 +229,10 @@ rt2860_interrupt(int irq, void *dev_inst + #define RTMP_MSI_DISABLE(_pAd) + #endif // PCI_MSI_SUPPORT // + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + #define SA_SHIRQ IRQF_SHARED +-#endif + + #define RT28XX_IRQ_REQUEST(net_dev) \ +-{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->priv); \ ++{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->ml_priv); \ + POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ + RTMP_MSI_ENABLE(_pAd); \ + if ((retval = request_irq(_pObj->pci_dev->irq, \ +@@ -251,20 +241,12 @@ rt2860_interrupt(int irq, void *dev_inst + printk("RT2860: request_irq ERROR(%d)\n", retval); \ + return retval; } } + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #define RT28XX_IRQ_RELEASE(net_dev) \ +-{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->priv); \ ++{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->ml_priv); \ + POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ + synchronize_irq(_pObj->pci_dev->irq); \ + free_irq(_pObj->pci_dev->irq, (net_dev)); \ + RTMP_MSI_DISABLE(_pAd); } +-#else +-#define RT28XX_IRQ_RELEASE(net_dev) \ +-{ PRTMP_ADAPTER _pAd = (PRTMP_ADAPTER)((net_dev)->priv); \ +- POS_COOKIE _pObj = (POS_COOKIE)(_pAd->OS_Cookie); \ +- free_irq(_pObj->pci_dev->irq, (net_dev)); \ +- RTMP_MSI_DISABLE(_pAd); } +-#endif + + #define RT28XX_IRQ_INIT(pAd) \ + { pAd->int_enable_reg = ((DELAYINTMASK) | \ +@@ -333,8 +315,8 @@ rt2860_interrupt(int irq, void *dev_inst + reg16 = cpu2le16(Configuration); \ + pci_write_config_word(pci_dev, offset, reg16); \ + +-#define RT28XX_STA_FORCE_WAKEUP(pAd, bFromTx) \ +- RT28xxPciStaAsicForceWakeup(pAd, bFromTx); ++#define RT28XX_STA_FORCE_WAKEUP(pAd, Level) \ ++ RT28xxPciStaAsicForceWakeup(pAd, Level); + + #define RT28XX_STA_SLEEP_THEN_AUTO_WAKEUP(pAd, TbttNumToNextWakeUp) \ + RT28xxPciStaAsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); +--- a/drivers/staging/rt2860/rt28xx.h ++++ b/drivers/staging/rt2860/rt28xx.h +@@ -1670,11 +1670,9 @@ typedef struct _HW_WCID_ENTRY { // 8-by + #define E2PROM_CSR 0x0004 + #define IO_CNTL_CSR 0x77d0 + +-#ifdef RT2860 + // 8051 firmware image for RT2860 - base address = 0x4000 + #define FIRMWARE_IMAGE_BASE 0x2000 + #define MAX_FIRMWARE_IMAGE_SIZE 0x2000 // 8kbyte +-#endif // RT2860 // + + + // ================================================================ +@@ -2029,7 +2027,6 @@ typedef struct PACKED _TXWI_STRUC { + // + // Rx descriptor format, Rx Ring + // +-#ifdef RT2860 + #ifdef RT_BIG_ENDIAN + typedef struct PACKED _RXD_STRUC { + // Word 0 +@@ -2098,7 +2095,6 @@ typedef struct PACKED _RXD_STRUC { + UINT32 Rsv1:13; + } RXD_STRUC, *PRXD_STRUC, RT28XX_RXD_STRUC, *PRT28XX_RXD_STRUC; + #endif +-#endif // RT2860 // + // + // RXWI wireless information format, in PBF. invisible in driver. + // +--- a/drivers/staging/rt2860/rt_ate.c ++++ b/drivers/staging/rt2860/rt_ate.c +@@ -68,7 +68,6 @@ static int CheckMCSValid( + IN UCHAR Mode, + IN UCHAR Mcs); + +-#ifdef RT2860 + static VOID ATEWriteTxWI( + IN PRTMP_ADAPTER pAd, + IN PTXWI_STRUC pOutTxWI, +@@ -87,7 +86,6 @@ static VOID ATEWriteTxWI( + IN UCHAR Txopmode, + IN BOOLEAN CfAck, + IN HTTRANSMIT_SETTING *pTransmit); +-#endif // RT2860 // + + + static VOID SetJapanFilter( +@@ -95,7 +93,6 @@ static VOID SetJapanFilter( + + /*=========================end of prototype=========================*/ + +-#ifdef RT2860 + static INT TxDmaBusy( + IN PRTMP_ADAPTER pAd) + { +@@ -153,7 +150,6 @@ static VOID RtmpDmaEnable( + + return; + } +-#endif // RT2860 // + + + static VOID BbpSoftReset( +@@ -291,7 +287,7 @@ static INT ATETxPwrHandler( + Bbp94 = BBPR94_DEFAULT; + } + +- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94)); + } + else// 5.5 GHz + { +@@ -318,7 +314,7 @@ static INT ATETxPwrHandler( + R = (ULONG) TxPower; + } + +- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __func__, TxPower, R)); + } + + if (pAd->ate.Channel <= 14) +@@ -431,7 +427,7 @@ static INT ATETxPwrHandler( + Bbp94 = BBPR94_DEFAULT; + } + +- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94)); + + if (pAd->ate.Channel <= 14) + { +@@ -488,7 +484,6 @@ static INT ATETxPwrHandler( + TRUE if all parameters are OK, FALSE otherwise + ========================================================================== + */ +-#ifdef RT2860 + static INT ATECmdHandler( + IN PRTMP_ADAPTER pAd, + IN PUCHAR arg) +@@ -1297,7 +1292,6 @@ static INT ATECmdHandler( + + return TRUE; + } +-#endif // RT2860 // + /* */ + /* */ + /*=======================End of RT2860=======================*/ +@@ -2098,7 +2092,7 @@ INT Set_ATE_Load_E2P_Proc( + UINT32 FileLength = 0; + UINT32 value = simple_strtol(arg, 0, 10); + +- ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value)); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __func__, value)); + + if (value > 0) + { +@@ -2122,14 +2116,14 @@ INT Set_ATE_Load_E2P_Proc( + + if (IS_ERR(srcf)) + { +- ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src); ++ ate_print("%s - Error %ld opening %s\n", __func__, -PTR_ERR(srcf), src); + break; + } + + /* the object must have a read method */ + if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL)) + { +- ate_print("%s - %s does not have a read method\n", __FUNCTION__, src); ++ ate_print("%s - %s does not have a read method\n", __func__, src); + break; + } + +@@ -2142,7 +2136,7 @@ INT Set_ATE_Load_E2P_Proc( + if (FileLength != EEPROM_SIZE) + { + ate_print("%s: error file length (=%d) in e2p.bin\n", +- __FUNCTION__, FileLength); ++ __func__, FileLength); + break; + } + else +@@ -2174,7 +2168,7 @@ INT Set_ATE_Load_E2P_Proc( + current->fsuid = orgfsuid; + current->fsgid = orgfsgid; + } +- ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret)); ++ ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __func__, ret)); + + return ret; + +@@ -2187,12 +2181,12 @@ INT Set_ATE_Load_E2P_Proc( + USHORT WriteEEPROM[(EEPROM_SIZE/2)]; + struct iwreq *wrq = (struct iwreq *)arg; + +- ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __func__, wrq->u.data.length)); + + if (wrq->u.data.length != EEPROM_SIZE) + { + ate_print("%s: error length (=%d) from host\n", +- __FUNCTION__, wrq->u.data.length); ++ __func__, wrq->u.data.length); + return FALSE; + } + else/* (wrq->u.data.length == EEPROM_SIZE) */ +@@ -2211,7 +2205,7 @@ INT Set_ATE_Load_E2P_Proc( + } while(FALSE); + } + +- ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __func__)); + + return TRUE; + +@@ -2907,7 +2901,6 @@ VOID ATEAsicAdjustTxPower( + None + ======================================================================== + */ +-#ifdef RT2860 + static VOID ATEWriteTxWI( + IN PRTMP_ADAPTER pAd, + IN PTXWI_STRUC pOutTxWI, +@@ -2972,7 +2965,6 @@ static VOID ATEWriteTxWI( + + return; + } +-#endif // RT2860 // + + /* + ======================================================================== +@@ -3249,13 +3241,11 @@ VOID RTMPStationStart( + IN PRTMP_ADAPTER pAd) + { + ATEDBGPRINT(RT_DEBUG_TRACE, ("==> RTMPStationStart\n")); +-#ifdef RT2860 +- pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; ++epAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; + // + // We did not cancel this timer when entering ATE mode. + // + // RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); +-#endif // RT2860 // + ATEDBGPRINT(RT_DEBUG_TRACE, ("<== RTMPStationStart\n")); + } + #endif // CONFIG_STA_SUPPORT // +@@ -3268,7 +3258,6 @@ VOID RTMPStationStart( + This routine should only be used in ATE mode. + ========================================================================== + */ +-#ifdef RT2860 + static INT ATESetUpFrame( + IN PRTMP_ADAPTER pAd, + IN UINT32 TxIdx) +@@ -3353,7 +3342,7 @@ static INT ATESetUpFrame( + if (pPacket == NULL) + { + pAd->ate.TxCount = 0; +- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s fail to alloc packet space.\n", __FUNCTION__)); ++ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s fail to alloc packet space.\n", __func__)); + return -1; + } + pTxRing->Cell[TxIdx].pNextNdisPacket = pPacket; +@@ -3455,7 +3444,6 @@ static INT ATESetUpFrame( + /* */ + /* */ + /*=======================End of RT2860=======================*/ +-#endif // RT2860 // + + + VOID rt_ee_read_all(PRTMP_ADAPTER pAd, USHORT *Data) +@@ -3646,7 +3634,7 @@ VOID RtmpDoAte( + + Command_Id = ntohs(pRaCfg->command_id); + +- ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id)); ++ ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __func__, Command_Id)); + + switch (Command_Id) + { +@@ -4578,9 +4566,7 @@ VOID RtmpDoAte( + { + if (pAdapter->ate.TxCount == 0) + { +-#ifdef RT2860 + pAdapter->ate.TxCount = 0xFFFFFFFF; +-#endif // RT2860 // + } + ATEDBGPRINT(RT_DEBUG_TRACE,("START TXFRAME\n")); + pAdapter->ate.bQATxStart = TRUE; +@@ -5375,7 +5361,6 @@ TX_START_ERROR: + + memcpy((PUCHAR)&value, (PUCHAR)&(pRaCfg->status), 2); + value = ntohs(value); +-#ifdef RT2860 + /* TX_FRAME_COUNT == 0 means tx infinitely */ + if (value == 0) + { +@@ -5387,7 +5372,6 @@ TX_START_ERROR: + + } + else +-#endif // RT2860 // + { + sprintf((PCHAR)str, "%d", value); + Set_ATE_TX_COUNT_Proc(pAdapter, str); +@@ -5690,7 +5674,7 @@ BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd + pAd->ate.TxAntennaSel = 2; + break; + default: +- DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __func__)); + return FALSE; + } + break;/* case BBP_R1 */ +@@ -5728,13 +5712,13 @@ BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd + pAd->ate.RxAntennaSel = 3; + break; + default: +- DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __func__)); + return FALSE; + } + break;/* case BBP_R3 */ + + default: +- DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __func__)); + return FALSE; + + } +--- a/drivers/staging/rt2860/rt_ate.h ++++ b/drivers/staging/rt2860/rt_ate.h +@@ -31,12 +31,10 @@ + #ifndef UCOS + #define ate_print printk + #define ATEDBGPRINT DBGPRINT +-#ifdef RT2860 + #define EEPROM_SIZE 0x200 + #ifdef CONFIG_STA_SUPPORT + #define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2860STA/e2p.bin" + #endif // CONFIG_STA_SUPPORT // +-#endif // RT2860 // + + #else // !UCOS // + #define fATE_LOAD_EEPROM 0x0C43 +@@ -69,7 +67,6 @@ do{ int (*org_remote_display)(char *) + #define ATE_ON(_p) (((_p)->ate.Mode) != ATE_STOP) + + /* RT2880_iNIC will define "RT2860". */ +-#ifdef RT2860 + #define ATE_BBP_IO_READ8_BY_REG_ID(_A, _I, _pV) \ + { \ + BBP_CSR_CFG_STRUC BbpCsr; \ +@@ -131,10 +128,8 @@ do{ int (*org_remote_display)(char *) + ATEDBGPRINT(RT_DEBUG_ERROR, ("BBP write R%d fail\n", _I)); \ + } \ + } +-#endif // RT2860 // + + /* RT2880_iNIC will define RT2860. */ +-#ifdef RT2860 + #define EEPROM_SIZE 0x200 + /* iNIC has its own EEPROM_BIN_FILE_NAME */ + #ifndef UCOS +@@ -142,7 +137,6 @@ do{ int (*org_remote_display)(char *) + #define EEPROM_BIN_FILE_NAME "/etc/Wireless/RT2860STA/e2p.bin" + #endif // CONFIG_STA_SUPPORT // + #endif // !UCOS // +-#endif // RT2860 // + + + +--- a/drivers/staging/rt2860/rt_config.h ++++ b/drivers/staging/rt2860/rt_config.h +@@ -53,9 +53,7 @@ + #include "rtmp_def.h" + #include "rt28xx.h" + +-#ifdef RT2860 + #include "rt2860.h" +-#endif // RT2860 // + + + #include "oid.h" +--- a/drivers/staging/rt2860/rt_linux.c ++++ b/drivers/staging/rt2860/rt_linux.c +@@ -48,10 +48,8 @@ BUILD_TIMER_FUNCTION(LeapAuthTimeout); + #endif + BUILD_TIMER_FUNCTION(StaQuickResponeForRateUpExec); + BUILD_TIMER_FUNCTION(WpaDisassocApAndBlockAssoc); +-#ifdef RT2860 + BUILD_TIMER_FUNCTION(PsPollWakeExec); + BUILD_TIMER_FUNCTION(RadioOnExec); +-#endif // RT2860 // + #ifdef QOS_DLS_SUPPORT + BUILD_TIMER_FUNCTION(DlsTimeoutAction); + #endif // QOS_DLS_SUPPORT // +@@ -293,9 +291,7 @@ VOID RTMPFreeAdapter( + + NdisFreeSpinLock(&pAd->MgmtRingLock); + +-#ifdef RT2860 + NdisFreeSpinLock(&pAd->RxRingLock); +-#endif // RT2860 // + + for (index =0 ; index < NUM_OF_TX_RING; index++) + { +@@ -406,7 +402,7 @@ NDIS_STATUS RTMPAllocateNdisPacket( + skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen); + + RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS); +-// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket)); ++// printk("%s : pPacket = %p, len = %d\n", __func__, pPacket, GET_OS_PKT_LEN(pPacket)); + *ppPacket = pPacket; + return NDIS_STATUS_SUCCESS; + } +@@ -773,13 +769,13 @@ VOID RTMPSendWirelessEvent( + + if (event_table_len == 0) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __func__, type)); + return; + } + + if (event >= event_table_len) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __func__, event)); + return; + } + +@@ -817,14 +813,14 @@ VOID RTMPSendWirelessEvent( + //send wireless event + wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf); + +- //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf)); ++ //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __func__, pBuf)); + + kfree(pBuf); + } + else +- DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __func__)); + #else +- DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __func__)); + #endif /* WIRELESS_EXT >= 15 */ + } + +@@ -848,13 +844,13 @@ void send_monitor_packets( + ASSERT(pRxBlk->pRxPacket); + if (pRxBlk->DataSize < 10) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __func__, pRxBlk->DataSize)); + goto err_free_sk_buff; + } + + if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE) + { +- DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%zu)\n", __func__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header))); + goto err_free_sk_buff; + } + +@@ -910,7 +906,7 @@ void send_monitor_packets( + + if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) { + if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) { +- DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __func__)); + goto err_free_sk_buff; + } //end if + } //end if +@@ -1005,35 +1001,14 @@ err_free_sk_buff: + + void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify) + { +- +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + daemonize(pThreadName /*"%s",pAd->net_dev->name*/); + + allow_signal(SIGTERM); + allow_signal(SIGKILL); + current->flags |= PF_NOFREEZE; +-#else +- unsigned long flags; +- +- daemonize(); +- reparent_to_init(); +- strcpy(current->comm, pThreadName); +- +- siginitsetinv(¤t->blocked, sigmask(SIGTERM) | sigmask(SIGKILL)); +- +- /* Allow interception of SIGKILL only +- * Don't allow other signals to interrupt the transmission */ +-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,22) +- spin_lock_irqsave(¤t->sigmask_lock, flags); +- flush_signals(current); +- recalc_sigpending(current); +- spin_unlock_irqrestore(¤t->sigmask_lock, flags); +-#endif +-#endif + +- /* signal that we've started the thread */ ++ /* signal that we've started the thread */ + complete(pNotify); +- + } + + void RTMP_IndicateMediaState( +--- a/drivers/staging/rt2860/rt_linux.h ++++ b/drivers/staging/rt2860/rt_linux.h +@@ -65,7 +65,6 @@ + #include + + +-#include + #include + + // load firmware +@@ -90,28 +89,22 @@ typedef int (*HARD_START_XMIT_FUNC)(stru + // add by kathy + + #ifdef CONFIG_STA_SUPPORT +-#ifdef RT2860 + #define STA_PROFILE_PATH "/etc/Wireless/RT2860STA/RT2860STA.dat" + #define STA_RTMP_FIRMWARE_FILE_NAME "/etc/Wireless/RT2860STA/RT2860STA.bin" + #define STA_NIC_DEVICE_NAME "RT2860STA" +-#define STA_DRIVER_VERSION "1.8.0.0" ++#define STA_DRIVER_VERSION "1.8.1.1" + #ifdef MULTIPLE_CARD_SUPPORT + #define CARD_INFO_PATH "/etc/Wireless/RT2860STA/RT2860STACard.dat" + #endif // MULTIPLE_CARD_SUPPORT // +-#endif // RT2860 // + + + #endif // CONFIG_STA_SUPPORT // + +-#ifdef RT2860 + #ifndef PCI_DEVICE + #define PCI_DEVICE(vend,dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID + #endif // PCI_DEVICE // +-#endif // RT2860 // +- +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + + #define RTMP_TIME_AFTER(a,b) \ + (typecheck(unsigned long, (unsigned long)a) && \ +@@ -123,23 +116,15 @@ typedef int (*HARD_START_XMIT_FUNC)(stru + typecheck(unsigned long, (unsigned long)b) && \ + ((long)(a) - (long)(b) >= 0)) + #define RTMP_TIME_BEFORE(a,b) RTMP_TIME_AFTER_EQ(b,a) +-#else +-#define RTMP_TIME_AFTER(a,b) time_after(a, b) +-#endif + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + #define RT_MOD_INC_USE_COUNT() \ + if (!try_module_get(THIS_MODULE)) \ + { \ +- DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \ ++ DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __func__)); \ + return -1; \ + } + + #define RT_MOD_DEC_USE_COUNT() module_put(THIS_MODULE); +-#else +-#define RT_MOD_INC_USE_COUNT() MOD_INC_USE_COUNT; +-#define RT_MOD_DEC_USE_COUNT() MOD_DEC_USE_COUNT; +-#endif + + #define OS_HZ HZ + +@@ -171,21 +156,12 @@ typedef int (*HARD_START_XMIT_FUNC)(stru + #define NDIS_PACKET_TYPE_ALL_MULTICAST 3 + #endif // CONFIG_STA_SUPPORT // + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + typedef struct pid * THREAD_PID; + #define THREAD_PID_INIT_VALUE NULL + #define GET_PID(_v) find_get_pid(_v) + #define GET_PID_NUMBER(_v) pid_nr(_v) + #define CHECK_PID_LEGALITY(_pid) if (pid_nr(_pid) >= 0) + #define KILL_THREAD_PID(_A, _B, _C) kill_pid(_A, _B, _C) +-#else +-typedef pid_t THREAD_PID; +-#define THREAD_PID_INIT_VALUE -1 +-#define GET_PID(_v) _v +-#define GET_PID_NUMBER(_v) _v +-#define CHECK_PID_LEGALITY(_pid) if (_pid >= 0) +-#define KILL_THREAD_PID(_A, _B, _C) kill_proc(_A, _B, _C) +-#endif + + struct os_lock { + spinlock_t lock; +@@ -194,11 +170,9 @@ struct os_lock { + + + struct os_cookie { +-#ifdef RT2860 + struct pci_dev *pci_dev; + struct pci_dev *parent_pci_dev; + dma_addr_t pAd_pa; +-#endif // RT2860 // + + + struct tasklet_struct rx_done_task; +@@ -209,9 +183,7 @@ struct os_cookie { + struct tasklet_struct ac3_dma_done_task; + struct tasklet_struct hcca_dma_done_task; + struct tasklet_struct tbtt_task; +-#ifdef RT2860 + struct tasklet_struct fifo_statistic_full_task; +-#endif // RT2860 // + + + unsigned long apd_pid; //802.1x daemon pid +@@ -266,7 +238,6 @@ void linux_pci_unmap_single(void *handle + + #define RT2860_PCI_DEVICE_ID 0x0601 + +-#ifdef RT2860 + #define PCI_MAP_SINGLE(_handle, _ptr, _size, _sd_idx, _dir) \ + linux_pci_map_single(_handle, _ptr, _size, _sd_idx, _dir) + +@@ -281,7 +252,6 @@ void linux_pci_unmap_single(void *handle + + #define DEV_ALLOC_SKB(_length) \ + dev_alloc_skb(_length) +-#endif // RT2860 // + + + +@@ -401,7 +371,6 @@ extern ULONG RTDebugLevel; + spin_unlock_irqrestore((spinlock_t *)(__lock), ((unsigned long)__irqflag)); \ + } + +-#ifdef RT2860 + #if defined(INF_TWINPASS) || defined(INF_DANUBE) || defined(IKANOS_VX_1X0) + //Patch for ASIC turst read/write bug, needs to remove after metel fix + #define RTMP_IO_READ32(_A, _R, _pV) \ +@@ -413,6 +382,12 @@ extern ULONG RTDebugLevel; + (*_pV = SWAP32(*((UINT32 *)(_pV)))); \ + } \ + } ++#define RTMP_IO_FORCE_READ32(_A, _R, _pV) \ ++{ \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + (_R)))); \ ++ (*_pV = SWAP32(*((UINT32 *)(_pV)))); \ ++} + #define RTMP_IO_READ8(_A, _R, _pV) \ + { \ + (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ +@@ -452,6 +427,11 @@ extern ULONG RTDebugLevel; + else \ + *_pV = 0; \ + } ++#define RTMP_IO_FORCE_READ32(_A, _R, _pV) \ ++{ \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ ++ (*_pV = readl((void *)((_A)->CSRBaseAddress + (_R)))); \ ++} + #define RTMP_IO_READ8(_A, _R, _pV) \ + { \ + (*_pV = readl((void *)((_A)->CSRBaseAddress + MAC_CSR0))); \ +@@ -492,7 +472,6 @@ extern ULONG RTDebugLevel; + writew((_V), (PUSHORT)((_A)->CSRBaseAddress + (_R))); \ + } + #endif +-#endif // RT2860 // + + + #ifndef wait_event_interruptible_timeout +@@ -544,7 +523,6 @@ typedef void (*TIMER_FUNCTION)(unsigned + #define MlmeAllocateMemory(_pAd, _ppVA) os_alloc_mem(_pAd, _ppVA, MGMT_DMA_BUFFER_SIZE) + #define MlmeFreeMemory(_pAd, _pVA) os_free_mem(_pAd, _pVA) + +-#ifdef RT2860 + #define BUILD_TIMER_FUNCTION(_func) \ + void linux_##_func(unsigned long data) \ + { \ +@@ -554,7 +532,6 @@ void linux_##_func(unsigned long data) + if (pTimer->Repeat) \ + RTMP_OS_Add_Timer(&pTimer->TimerObj, pTimer->TimerValue); \ + } +-#endif // RT2860 // + + + +@@ -907,7 +884,6 @@ int rt28xx_packet_xmit(struct sk_buff *s + + void rtmp_os_thread_init(PUCHAR pThreadName, PVOID pNotify); + +-#ifdef RT2860 + #if !defined(PCI_CAP_ID_EXP) + #define PCI_CAP_ID_EXP 0x10 + #endif +@@ -921,6 +897,5 @@ void rtmp_os_thread_init(PUCHAR pThreadN + #endif + + #define PCIBUS_INTEL_VENDOR 0x8086 +-#endif // RT2860 // + + +--- a/drivers/staging/rt2860/rt_main_dev.c ++++ b/drivers/staging/rt2860/rt_main_dev.c +@@ -58,11 +58,7 @@ UINT32 CW_MAX_IN_BITS; + + char *mac = ""; // default 00:00:00:00:00:00 + char *hostname = ""; // default CMPC +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) +-MODULE_PARM (mac, "s"); +-#else + module_param (mac, charp, 0); +-#endif + MODULE_PARM_DESC (mac, "rt28xx: wireless mac addr"); + + +@@ -75,9 +71,7 @@ extern void ba_reordering_resource_relea + #endif // DOT11_N_SUPPORT // + extern NDIS_STATUS NICLoadRateSwitchingParams(IN PRTMP_ADAPTER pAd); + +-#ifdef RT2860 + extern void init_thread_task(PRTMP_ADAPTER pAd); +-#endif // RT2860 // + + // public function prototype + INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p, +@@ -87,13 +81,6 @@ INT __devinit rt28xx_probe(IN void *_dev + static int rt28xx_init(IN struct net_device *net_dev); + INT rt28xx_send_packets(IN struct sk_buff *skb_p, IN struct net_device *net_dev); + +-#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 +-struct net_device *alloc_netdev( +- int sizeof_priv, +- const char *mask, +- void (*setup)(struct net_device *)); +-#endif // LINUX_VERSION_CODE // +- + static void CfgInitHook(PRTMP_ADAPTER pAd); + + #ifdef CONFIG_STA_SUPPORT +@@ -135,7 +122,7 @@ Note: + */ + int MainVirtualIF_close(IN struct net_device *net_dev) + { +- RTMP_ADAPTER *pAd = net_dev->priv; ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; + + // Sanity check for pAd + if (pAd == NULL) +@@ -174,7 +161,7 @@ Note: + */ + int MainVirtualIF_open(IN struct net_device *net_dev) + { +- RTMP_ADAPTER *pAd = net_dev->priv; ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; + + // Sanity check for pAd + if (pAd == NULL) +@@ -216,7 +203,7 @@ Note: + int rt28xx_close(IN PNET_DEV dev) + { + struct net_device * net_dev = (struct net_device *)dev; +- RTMP_ADAPTER *pAd = net_dev->priv; ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; + BOOLEAN Cancelled = FALSE; + UINT32 i = 0; + +@@ -235,15 +222,13 @@ int rt28xx_close(IN PNET_DEV dev) + #ifdef CONFIG_STA_SUPPORT + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { +-#ifdef RT2860 +- RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_CLOSE); +-#endif // RT2860 // +- + // If dirver doesn't wake up firmware here, + // NICLoadFirmware will hang forever when interface is up again. +- if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) || ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)) + { +- AsicForceWakeup(pAd, TRUE); ++ AsicForceWakeup(pAd, RTMP_HALT); + } + + #ifdef QOS_DLS_SUPPORT +@@ -323,9 +308,7 @@ int rt28xx_close(IN PNET_DEV dev) + #endif // WPA_SUPPLICANT_SUPPORT // + + MlmeRadioOff(pAd); +-#ifdef RT2860 + pAd->bPCIclkOff = FALSE; +-#endif // RT2860 // + } + #endif // CONFIG_STA_SUPPORT // + +@@ -359,7 +342,6 @@ int rt28xx_close(IN PNET_DEV dev) + TpcReqTabExit(pAd); + + +-#ifdef RT2860 + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) + { + NICDisableInterrupt(pAd); +@@ -375,7 +357,6 @@ int rt28xx_close(IN PNET_DEV dev) + RT28XX_IRQ_RELEASE(net_dev) + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_IN_USE); + } +-#endif // RT2860 // + + + // Free Ring or USB buffers +@@ -396,7 +377,7 @@ int rt28xx_close(IN PNET_DEV dev) + + static int rt28xx_init(IN struct net_device *net_dev) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->priv; ++ PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->ml_priv; + UINT index; + UCHAR TmpPhy; + NDIS_STATUS Status; +@@ -439,12 +420,10 @@ static int rt28xx_init(IN struct net_dev + + // Disable interrupts here which is as soon as possible + // This statement should never be true. We might consider to remove it later +-#ifdef RT2860 + if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE)) + { + NICDisableInterrupt(pAd); + } +-#endif // RT2860 // + + Status = RTMPAllocTxRxRingMemory(pAd); + if (Status != NDIS_STATUS_SUCCESS) +@@ -605,8 +584,8 @@ err1: + #endif // DOT11_N_SUPPORT // + RT28XX_IRQ_RELEASE(net_dev); + +- // shall not set priv to NULL here because the priv didn't been free yet. +- //net_dev->priv = 0; ++ // shall not set ml_priv to NULL here because the ml_priv didn't been free yet. ++ //net_dev->ml_priv = 0; + #ifdef INF_AMAZON_SE + err0: + #endif // INF_AMAZON_SE // +@@ -633,7 +612,7 @@ Note: + int rt28xx_open(IN PNET_DEV dev) + { + struct net_device * net_dev = (struct net_device *)dev; +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)net_dev->priv; ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; + int retval = 0; + POS_COOKIE pObj; + +@@ -642,7 +621,7 @@ int rt28xx_open(IN PNET_DEV dev) + if (pAd == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -1; + } + +@@ -667,26 +646,6 @@ int rt28xx_open(IN PNET_DEV dev) + #endif // WIRELESS_EXT >= 12 // + #endif // CONFIG_APSTA_MIXED_SUPPORT // + +-#ifdef CONFIG_STA_SUPPORT +-#ifdef RT2860 +- IF_DEV_CONFIG_OPMODE_ON_STA(pAd) +- { +- // If dirver doesn't wake up firmware here, +- // NICLoadFirmware will hang forever when interface is up again. +- // RT2860 PCI +- if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) && +- OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) +- { +- AUTO_WAKEUP_STRUC AutoWakeupCfg; +- AsicForceWakeup(pAd, TRUE); +- AutoWakeupCfg.word = 0; +- RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); +- OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); +- } +- } +-#endif // RT2860 // +-#endif // CONFIG_STA_SUPPORT // +- + // Init + pObj = (POS_COOKIE)pAd->OS_Cookie; + +@@ -753,10 +712,8 @@ int rt28xx_open(IN PNET_DEV dev) + } + + #ifdef CONFIG_STA_SUPPORT +-#ifdef RT2860 + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + RTMPInitPCIeLinkCtrlValue(pAd); +-#endif // RT2860 // + #endif // CONFIG_STA_SUPPORT // + + return (retval); +@@ -808,9 +765,7 @@ static NDIS_STATUS rt_ieee80211_if_setup + dev->stop = MainVirtualIF_close; //rt28xx_close; + dev->priv_flags = INT_MAIN; + dev->do_ioctl = rt28xx_ioctl; +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +- dev->validate_addr = NULL; +-#endif ++ dev->validate_addr = NULL; + // find available device name + for (i = 0; i < 8; i++) + { +@@ -821,25 +776,11 @@ static NDIS_STATUS rt_ieee80211_if_setup + #endif // MULTIPLE_CARD_SUPPORT // + sprintf(slot_name, "ra%d", i); + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +- device = dev_get_by_name(dev_net(dev), slot_name); +-#else +- device = dev_get_by_name(dev->nd_net, slot_name); +-#endif +-#else +- device = dev_get_by_name(slot_name); +-#endif +- if (device != NULL) dev_put(device); +-#else +- for (device = dev_base; device != NULL; device = device->next) +- { +- if (strncmp(device->name, slot_name, 4) == 0) +- break; +- } +-#endif +- if(device == NULL) ++ device = dev_get_by_name(dev_net(dev), slot_name); ++ if (device != NULL) ++ dev_put(device); ++ ++ if (device == NULL) + break; + } + +@@ -1252,47 +1193,28 @@ INT __devinit rt28xx_probe( + PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) NULL; + INT status; + PVOID handle; +-#ifdef RT2860 + struct pci_dev *dev_p = (struct pci_dev *)_dev_p; +-#endif // RT2860 // + + + #ifdef CONFIG_STA_SUPPORT + DBGPRINT(RT_DEBUG_TRACE, ("STA Driver version-%s\n", STA_DRIVER_VERSION)); + #endif // CONFIG_STA_SUPPORT // + +-#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 +- net_dev = alloc_netdev(sizeof(PRTMP_ADAPTER), "eth%d", ether_setup); +-#else + net_dev = alloc_etherdev(sizeof(PRTMP_ADAPTER)); +-#endif + if (net_dev == NULL) + { + printk("alloc_netdev failed\n"); + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +- module_put(THIS_MODULE); +-#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +-#else +- MOD_DEC_USE_COUNT; +-#endif + goto err_out; + } + +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) +- SET_MODULE_OWNER(net_dev); +-#endif +- + netif_stop_queue(net_dev); + #ifdef NATIVE_WPA_SUPPLICANT_SUPPORT + /* for supporting Network Manager */ + /* Set the sysfs physical device reference for the network logical device + * if set prior to registration will cause a symlink during initialization. + */ +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) + SET_NETDEV_DEV(net_dev, &(dev_p->dev)); +-#endif + #endif // NATIVE_WPA_SUPPLICANT_SUPPORT // + + // Allocate RTMP_ADAPTER miniport adapter structure +@@ -1303,7 +1225,7 @@ INT __devinit rt28xx_probe( + if (status != NDIS_STATUS_SUCCESS) + goto err_out_free_netdev; + +- net_dev->priv = (PVOID)pAd; ++ net_dev->ml_priv = (PVOID)pAd; + pAd->net_dev = net_dev; // must be before RT28XXNetDevInit() + + RT28XXNetDevInit(_dev_p, net_dev, pAd); +@@ -1313,13 +1235,8 @@ INT __devinit rt28xx_probe( + #endif // CONFIG_STA_SUPPORT // + + // Post config +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +- if (RT28XXProbePostConfig(_dev_p, pAd, argc) == FALSE) +- goto err_out_unmap; +-#else + if (RT28XXProbePostConfig(_dev_p, pAd, 0) == FALSE) + goto err_out_unmap; +-#endif // LINUX_VERSION_CODE // + + #ifdef CONFIG_STA_SUPPORT + pAd->OpMode = OPMODE_STA; +@@ -1362,20 +1279,12 @@ err_out_unmap: + RT28XX_UNMAP(); + + err_out_free_netdev: +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +- free_netdev(net_dev); +-#else +- kfree(net_dev); +-#endif ++ free_netdev(net_dev); + + err_out: + RT28XX_PUT_DEVICE(dev_p); + +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +- return (LONG)NULL; +-#else +- return -ENODEV; /* probe fail */ +-#endif // LINUX_VERSION_CODE // ++ return -ENODEV; /* probe fail */ + } /* End of rt28xx_probe */ + + +@@ -1399,7 +1308,7 @@ Note: + int rt28xx_packet_xmit(struct sk_buff *skb) + { + struct net_device *net_dev = skb->dev; +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; + int status = 0; + PNDIS_PACKET pPacket = (PNDIS_PACKET) skb; + +@@ -1478,7 +1387,7 @@ INT rt28xx_send_packets( + IN struct sk_buff *skb_p, + IN struct net_device *net_dev) + { +- RTMP_ADAPTER *pAd = net_dev->priv; ++ RTMP_ADAPTER *pAd = net_dev->ml_priv; + if (!(net_dev->flags & IFF_UP)) + { + RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE); +@@ -1495,40 +1404,6 @@ INT rt28xx_send_packets( + + + +-#if LINUX_VERSION_CODE <= 0x20402 // Red Hat 7.1 +-struct net_device *alloc_netdev( +- int sizeof_priv, +- const char *mask, +- void (*setup)(struct net_device *)) +-{ +- struct net_device *dev; +- INT alloc_size; +- +- +- /* ensure 32-byte alignment of the private area */ +- alloc_size = sizeof (*dev) + sizeof_priv + 31; +- +- dev = (struct net_device *) kmalloc(alloc_size, GFP_KERNEL); +- if (dev == NULL) +- { +- DBGPRINT(RT_DEBUG_ERROR, +- ("alloc_netdev: Unable to allocate device memory.\n")); +- return NULL; +- } +- +- memset(dev, 0, alloc_size); +- +- if (sizeof_priv) +- dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); +- +- setup(dev); +- strcpy(dev->name, mask); +- +- return dev; +-} +-#endif // LINUX_VERSION_CODE // +- +- + void CfgInitHook(PRTMP_ADAPTER pAd) + { + pAd->bBroadComHT = TRUE; +@@ -1540,7 +1415,7 @@ void CfgInitHook(PRTMP_ADAPTER pAd) + struct iw_statistics *rt28xx_get_wireless_stats( + IN struct net_device *net_dev) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) net_dev->priv; ++ PRTMP_ADAPTER pAd = net_dev->ml_priv; + + + DBGPRINT(RT_DEBUG_TRACE, ("rt28xx_get_wireless_stats --->\n")); +@@ -1592,18 +1467,18 @@ INT rt28xx_ioctl( + + if (net_dev->priv_flags == INT_MAIN) + { +- pAd = net_dev->priv; ++ pAd = net_dev->ml_priv; + } + else + { +- pVirtualAd = net_dev->priv; +- pAd = pVirtualAd->RtmpDev->priv; ++ pVirtualAd = net_dev->ml_priv; ++ pAd = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAd == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1640,7 +1515,7 @@ struct net_device_stats *RT28xx_get_ethe + RTMP_ADAPTER *pAd = NULL; + + if (net_dev) +- pAd = net_dev->priv; ++ pAd = net_dev->ml_priv; + + if (pAd) + { +--- a/drivers/staging/rt2860/rt_profile.c ++++ b/drivers/staging/rt2860/rt_profile.c +@@ -925,9 +925,11 @@ NDIS_STATUS RTMPReadParametersHook( + + // Save uid and gid used for filesystem access. + // Set user and group to 0 (root) +- orgfsuid = current->fsuid; +- orgfsgid = current->fsgid; +- current->fsuid=current->fsgid = 0; ++ orgfsuid = current_fsuid(); ++ orgfsgid = current_fsgid(); ++ /* Hm, can't really do this nicely anymore, so rely on these files ++ * being set to the proper permission to read them... */ ++ /* current->cred->fsuid = current->cred->fsgid = 0; */ + orgfs = get_fs(); + set_fs(KERNEL_DS); + +@@ -1022,7 +1024,7 @@ NDIS_STATUS RTMPReadParametersHook( + pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen; + NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID); + NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen); +- DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __func__, tmpbuf)); + } + } + } +@@ -1041,7 +1043,7 @@ NDIS_STATUS RTMPReadParametersHook( + pAd->StaCfg.BssType = BSS_INFRA; + // Reset Ralink supplicant to not use, it will be set to start when UI set PMK key + pAd->StaCfg.WpaState = SS_NOTUSE; +- DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __func__, pAd->StaCfg.BssType)); + } + } + #endif // CONFIG_STA_SUPPORT // +@@ -1335,7 +1337,7 @@ NDIS_STATUS RTMPReadParametersHook( + + pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus)); + } + #endif // CONFIG_STA_SUPPORT // + } +@@ -1361,7 +1363,7 @@ NDIS_STATUS RTMPReadParametersHook( + pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus; + pAd->StaCfg.bMixCipher = FALSE; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus)); + } + #endif // CONFIG_STA_SUPPORT // + } +@@ -1398,7 +1400,7 @@ NDIS_STATUS RTMPReadParametersHook( + else + { + err = 1; +- DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __func__)); + } + + if (err == 0) +@@ -1414,7 +1416,7 @@ NDIS_STATUS RTMPReadParametersHook( + pAd->StaCfg.WpaState = SS_NOTUSE; + } + +- DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __func__, tmpbuf)); + } + } + } +@@ -1449,7 +1451,7 @@ NDIS_STATUS RTMPReadParametersHook( + IF_DEV_CONFIG_OPMODE_ON_STA(pAd) + { + //PSMode +- if (RTMPGetKeyParameter("PSMode", tmpbuf, 10, buffer)) ++ if (RTMPGetKeyParameter("PSMode", tmpbuf, 32, buffer)) + { + if (pAd->StaCfg.BssType == BSS_INFRA) + { +@@ -1551,8 +1553,11 @@ NDIS_STATUS RTMPReadParametersHook( + } + + set_fs(orgfs); +- current->fsuid = orgfsuid; +- current->fsgid = orgfsgid; ++ ++#if 0 ++ current->cred->fsuid = orgfsuid; ++ current->cred->fsgid = orgfsgid; ++#endif + + kfree(buffer); + kfree(tmpbuf); +--- a/drivers/staging/rt2860/rtmp.h ++++ b/drivers/staging/rt2860/rtmp.h +@@ -203,9 +203,7 @@ typedef struct _ATE_INFO { + BOOLEAN bRxFer; + BOOLEAN bQATxStart; // Have compiled QA in and use it to ATE tx. + BOOLEAN bQARxStart; // Have compiled QA in and use it to ATE rx. +-#ifdef RT2860 + BOOLEAN bFWLoading; // Reload firmware when ATE is done. +-#endif // RT2860 // + UINT32 RxTotalCnt; + UINT32 RxCntPerSec; + +@@ -366,6 +364,13 @@ typedef struct _QUEUE_HEADER { + #define RTMP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) + #define RTMP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) + ++// Macro for power save flag. ++#define RTMP_SET_PSFLAG(_M, _F) ((_M)->PSFlags |= (_F)) ++#define RTMP_CLEAR_PSFLAG(_M, _F) ((_M)->PSFlags &= ~(_F)) ++#define RTMP_CLEAR_PSFLAGS(_M) ((_M)->PSFlags = 0) ++#define RTMP_TEST_PSFLAG(_M, _F) (((_M)->PSFlags & (_F)) != 0) ++#define RTMP_TEST_PSFLAGS(_M, _F) (((_M)->PSFlags & (_F)) == (_F)) ++ + #define OPSTATUS_SET_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags |= (_F)) + #define OPSTATUS_CLEAR_FLAG(_pAd, _F) ((_pAd)->CommonCfg.OpStatusFlags &= ~(_F)) + #define OPSTATUS_TEST_FLAG(_pAd, _F) (((_pAd)->CommonCfg.OpStatusFlags & (_F)) != 0) +@@ -478,7 +483,6 @@ typedef struct _QUEUE_HEADER { + // + #define MAX_BUSY_COUNT 100 // Number of retry before failing access BBP & RF indirect register + // +-#ifdef RT2860 + #define RTMP_RF_IO_WRITE32(_A, _V) \ + { \ + PHY_CSR4_STRUC Value; \ +@@ -642,7 +646,6 @@ typedef struct _QUEUE_HEADER { + } \ + } \ + } +-#endif // RT2860 // + + + #define MAP_CHANNEL_ID_TO_KHZ(ch, khz) { \ +@@ -894,7 +897,6 @@ typedef struct _RTMP_SCATTER_GATHER_LIST + // Enqueue this frame to MLME engine + // We need to enqueue the whole frame because MLME need to pass data type + // information from 802.11 header +-#ifdef RT2860 + #define REPORT_MGMT_FRAME_TO_MLME(_pAd, Wcid, _pFrame, _FrameSize, _Rssi0, _Rssi1, _Rssi2, _PlcpSignal) \ + { \ + UINT32 High32TSF, Low32TSF; \ +@@ -902,7 +904,6 @@ typedef struct _RTMP_SCATTER_GATHER_LIST + RTMP_IO_READ32(_pAd, TSF_TIMER_DW0, &Low32TSF); \ + MlmeEnqueueForRecv(_pAd, Wcid, High32TSF, Low32TSF, (UCHAR)_Rssi0, (UCHAR)_Rssi1,(UCHAR)_Rssi2,_FrameSize, _pFrame, (UCHAR)_PlcpSignal); \ + } +-#endif // RT2860 // + + #define NDIS_QUERY_BUFFER(_NdisBuf, _ppVA, _pBufLen) \ + NdisQueryBuffer(_NdisBuf, _ppVA, _pBufLen) +@@ -919,9 +920,10 @@ typedef struct _RTMP_SCATTER_GATHER_LIST + #define STA_PORT_SECURED(_pAd) \ + { \ + _pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; \ +- NdisAcquireSpinLock(&_pAd->MacTabLock); \ ++ RTMP_SET_PSFLAG(_pAd, fRTMP_PS_CAN_GO_SLEEP); \ ++ NdisAcquireSpinLock(&(_pAd)->MacTabLock); \ + _pAd->MacTab.Content[BSSID_WCID].PortSecured = _pAd->StaCfg.PortSecured; \ +- NdisReleaseSpinLock(&_pAd->MacTabLock); \ ++ NdisReleaseSpinLock(&(_pAd)->MacTabLock); \ + } + #endif // CONFIG_STA_SUPPORT // + +@@ -1000,9 +1002,7 @@ typedef struct _RTMP_REORDERBUF + UCHAR DataOffset; + USHORT Datasize; + ULONG AllocSize; +-#ifdef RT2860 + NDIS_PHYSICAL_ADDRESS AllocPa; // TxBuf physical address +-#endif // RT2860 // + } RTMP_REORDERBUF, *PRTMP_REORDERBUF; + + // +@@ -1101,6 +1101,7 @@ typedef struct _COUNTER_802_11 { + + typedef struct _COUNTER_RALINK { + ULONG TransmittedByteCount; // both successful and failure, used to calculate TX throughput ++ ULONG LastReceivedByteCount; + ULONG ReceivedByteCount; // both CRC okay and CRC error, used to calculate RX throughput + ULONG BeenDisassociatedCount; + ULONG BadCQIAutoRecoveryCount; +@@ -1436,11 +1437,9 @@ typedef struct _MLME_STRUCT { + RALINK_TIMER_STRUCT APSDPeriodicTimer; + RALINK_TIMER_STRUCT LinkDownTimer; + RALINK_TIMER_STRUCT LinkUpTimer; +-#ifdef RT2860 + UCHAR bPsPollTimerRunning; + RALINK_TIMER_STRUCT PsPollTimer; + RALINK_TIMER_STRUCT RadioOnOffTimer; +-#endif // RT2860 // + ULONG PeriodicRound; + ULONG OneSecPeriodicRound; + +@@ -2228,9 +2227,7 @@ typedef struct _STA_ADMIN_CONFIG { + RT_HT_PHY_INFO DesiredHtPhyInfo; + BOOLEAN bAutoTxRateSwitch; + +-#ifdef RT2860 + UCHAR BBPR3; +-#endif // RT2860 // + + #ifdef EXT_BUILD_CHANNEL_LIST + UCHAR IEEE80211dClientMode; +@@ -2663,7 +2660,6 @@ typedef struct _RTMP_ADAPTER + PNET_DEV net_dev; + ULONG VirtualIfCnt; + +-#ifdef RT2860 + USHORT LnkCtrlBitMask; + USHORT RLnkCtrlConfiguration; + USHORT RLnkCtrlOffset; +@@ -2671,7 +2667,9 @@ typedef struct _RTMP_ADAPTER + USHORT HostLnkCtrlOffset; + USHORT PCIePowerSaveLevel; + BOOLEAN bPCIclkOff; // flag that indicate if the PICE power status in Configuration SPace.. +- BOOLEAN bPCIclkOffDisableTx; // ++ ULONG CheckDmaBusyCount; // Check Interrupt Status Register Count. ++ USHORT ThisTbttNumToNextWakeUp; ++ ULONG SameRxByteCount; + + + /*****************************************************************************************/ +@@ -2688,7 +2686,6 @@ typedef struct _RTMP_ADAPTER + RTMP_DMABUF RxDescRing; // Shared memory for RX descriptors + RTMP_DMABUF TxDescRing[NUM_OF_TX_RING]; // Shared memory for Tx descriptors + RTMP_TX_RING TxRing[NUM_OF_TX_RING]; // AC0~4 + HCCA +-#endif // RT2860 // + + + NDIS_SPIN_LOCK irq_lock; +@@ -2721,10 +2718,8 @@ typedef struct _RTMP_ADAPTER + /* Rx related parameters */ + /*****************************************************************************************/ + +-#ifdef RT2860 + RTMP_RX_RING RxRing; + NDIS_SPIN_LOCK RxRingLock; // Rx Ring spinlock +-#endif // RT2860 // + + + +@@ -2895,6 +2890,7 @@ typedef struct _RTMP_ADAPTER + + // flags, see fRTMP_ADAPTER_xxx flags + ULONG Flags; // Represent current device status ++ ULONG PSFlags; // Power Save operation flag. + + // current TX sequence # + USHORT Sequence; +@@ -3181,7 +3177,6 @@ typedef struct _TX_BLK_ + //------------------------------------------------------------------------------------------ + + +-#ifdef RT2860 + // + // Enable & Disable NIC interrupt via writing interrupt mask register + // Since it use ADAPTER structure, it have to be put after structure definition. +@@ -3214,7 +3209,6 @@ __inline VOID NICEnableInterrupt( + //RTMP_IO_WRITE32(pAd, PBF_INT_ENA, 0x00000030); // 1 : enable + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); + } +-#endif // RT2860 // + + #ifdef RT_BIG_ENDIAN + static inline VOID WriteBackToDescriptor( +@@ -3291,7 +3285,6 @@ static inline VOID RTMPWIEndianChange( + Call this function when read or update descriptor + ======================================================================== + */ +-#ifdef RT2860 + static inline VOID RTMPDescriptorEndianChange( + IN PUCHAR pData, + IN ULONG DescriptorType) +@@ -3301,7 +3294,6 @@ static inline VOID RTMPDescriptorEndianC + *((UINT32 *)(pData +12)) = SWAP32(*((UINT32 *)(pData + 12))); // Byte 12~15 + *((UINT32 *)(pData + 4)) = SWAP32(*((UINT32 *)(pData + 4))); // Byte 4~7, this must be swapped last + } +-#endif // RT2860 // + + /* + ======================================================================== +@@ -3550,6 +3542,9 @@ NDIS_STATUS NICInitializeAsic( + IN PRTMP_ADAPTER pAd, + IN BOOLEAN bHardReset); + ++VOID NICRestoreBBPValue( ++ IN PRTMP_ADAPTER pAd); ++ + VOID NICIssueReset( + IN PRTMP_ADAPTER pAd); + +@@ -4208,7 +4203,7 @@ VOID AsicForceSleep( + + VOID AsicForceWakeup( + IN PRTMP_ADAPTER pAd, +- IN BOOLEAN bFromTx); ++ IN UCHAR Level); + #endif // CONFIG_STA_SUPPORT // + + VOID AsicSetBssid( +@@ -4304,11 +4299,9 @@ BOOLEAN AsicSendCommandToMcu( + IN UCHAR Arg0, + IN UCHAR Arg1); + +-#ifdef RT2860 + BOOLEAN AsicCheckCommanOk( + IN PRTMP_ADAPTER pAd, + IN UCHAR Command); +-#endif // RT2860 // + + VOID MacAddrRandomBssid( + IN PRTMP_ADAPTER pAd, +@@ -6978,7 +6971,6 @@ void kill_thread_task(PRTMP_ADAPTER pAd) + + void tbtt_tasklet(unsigned long data); + +-#ifdef RT2860 + // + // Function Prototype in cmm_data_2860.c + // +@@ -7069,7 +7061,7 @@ BOOLEAN RT28xxPciAsicRadioOn( + + VOID RT28xxPciStaAsicForceWakeup( + IN PRTMP_ADAPTER pAd, +- IN BOOLEAN bFromTx); ++ IN UCHAR Level); + + VOID RT28xxPciStaAsicSleepThenAutoWakeup( + IN PRTMP_ADAPTER pAd, +@@ -7093,7 +7085,6 @@ VOID RT28xxPciMlmeRadioOn( + + VOID RT28xxPciMlmeRadioOFF( + IN PRTMP_ADAPTER pAd); +-#endif // RT2860 // + + VOID AsicTurnOffRFClk( + IN PRTMP_ADAPTER pAd, +@@ -7132,6 +7123,18 @@ PCHAR RTMPGetRalinkEncryModeStr( + #ifdef CONFIG_STA_SUPPORT + VOID AsicStaBbpTuning( + IN PRTMP_ADAPTER pAd); ++ ++VOID AsicResetFromDMABusy( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicResetBBP( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicResetMAC( ++ IN PRTMP_ADAPTER pAd); ++ ++VOID AsicResetPBF( ++ IN PRTMP_ADAPTER pAd); + #endif // CONFIG_STA_SUPPORT // + + void RTMP_IndicateMediaState( +--- a/drivers/staging/rt2860/rtmp_def.h ++++ b/drivers/staging/rt2860/rtmp_def.h +@@ -111,7 +111,6 @@ + // Entry number for each DMA descriptor ring + // + +-#ifdef RT2860 + #define TX_RING_SIZE 64 //64 + #define MGMT_RING_SIZE 128 + #define RX_RING_SIZE 128 //64 +@@ -119,7 +118,6 @@ + #define MAX_DMA_DONE_PROCESS TX_RING_SIZE + #define MAX_TX_DONE_PROCESS TX_RING_SIZE //8 + #define LOCAL_TXBUF_SIZE 2 +-#endif // RT2860 // + + + #ifdef MULTIPLE_CARD_SUPPORT +@@ -212,6 +210,19 @@ + #define fOP_STATUS_WAKEUP_NOW 0x00008000 + #define fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE 0x00020000 + ++// ++// RTMP_ADAPTER PSFlags : related to advanced power save. ++// ++// Indicate whether driver can go to sleep mode from now. This flag is useful AFTER link up ++#define fRTMP_PS_CAN_GO_SLEEP 0x00000001 ++// Indicate whether driver has issue a LinkControl command to PCIe L1 ++#define fRTMP_PS_SET_PCI_CLK_OFF_COMMAND 0x00000002 ++// Indicate driver should disable kick off hardware to send packets from now. ++#define fRTMP_PS_DISABLE_TX 0x00000004 ++// Indicate driver should IMMEDIATELY fo to sleep after receiving AP's beacon in which doesn't indicate unicate nor multicast packets for me ++//. This flag is used ONLY in RTMPHandleRxDoneInterrupt routine. ++#define fRTMP_PS_GO_TO_SLEEP_NOW 0x00000008 ++ + #ifdef DOT11N_DRAFT3 + #define fOP_STATUS_SCAN_2040 0x00040000 + #endif // DOT11N_DRAFT3 // +@@ -333,7 +344,7 @@ + /* sanity check for apidx */ + #define MBSS_MR_APIDX_SANITY_CHECK(apidx) \ + { if (apidx > MAX_MBSSID_NUM) { \ +- printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \ ++ printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __func__, apidx); \ + apidx = MAIN_MBSSID; } } + + #define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE ) +@@ -1514,12 +1525,14 @@ + #define MCAST_HTMIX 3 + #endif // MCAST_RATE_SPECIFIC // + +-// For AsicRadioOff/AsicRadioOn function +-#define DOT11POWERSAVE 0 +-#define GUIRADIO_OFF 1 +-#define RTMP_HALT 2 +-#define GUI_IDLE_POWER_SAVE 3 +-// -- ++// For AsicRadioOff/AsicRadioOn/AsicForceWakeup function ++// This is to indicate from where to call this function. ++#define DOT11POWERSAVE 0 // TO do .11 power save sleep ++#define GUIRADIO_OFF 1 // To perform Radio OFf command from GUI ++#define RTMP_HALT 2 // Called from Halt handler. ++#define GUI_IDLE_POWER_SAVE 3 // Call to sleep before link up with AP ++#define FROM_TX 4 // Force wake up from Tx packet. ++ + + + // definition for WpaSupport flag +--- a/drivers/staging/rt2860/sta/assoc.c ++++ b/drivers/staging/rt2860/sta/assoc.c +@@ -473,12 +473,7 @@ VOID MlmeAssocReqAction( + RSNIe = IE_WPA2; + } + +-#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT +-#ifdef SIOCSIWGENIE +- if (pAd->StaCfg.WpaSupplicantUP != 1) +-#endif // SIOCSIWGENIE // +-#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // +- RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); ++ RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0); + + // Check for WPA PMK cache list + if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) +@@ -504,17 +499,6 @@ VOID MlmeAssocReqAction( + } + } + +-#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT +-#ifdef SIOCSIWGENIE +- if (pAd->StaCfg.WpaSupplicantUP == 1) +- { +- MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, +- pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE, +- END_OF_ARGS); +- } +- else +-#endif +-#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // + { + MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp, + 1, &RSNIe, +@@ -525,11 +509,6 @@ VOID MlmeAssocReqAction( + + FrameLen += tmp; + +-#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT +-#ifdef SIOCSIWGENIE +- if (pAd->StaCfg.WpaSupplicantUP != 1) +-#endif +-#endif // NATIVE_WPA_SUPPLICANT_SUPPORT // + { + // Append Variable IE + NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1); +--- a/drivers/staging/rt2860/sta/connect.c ++++ b/drivers/staging/rt2860/sta/connect.c +@@ -337,6 +337,10 @@ VOID CntlOidSsidProc( + MLME_DISASSOC_REQ_STRUCT DisassocReq; + ULONG Now; + ++ // BBP and RF are not accessible in PS mode, we has to wake them up first ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ AsicForceWakeup(pAd, RTMP_HALT); ++ + // Step 1. record the desired user settings to MlmeAux + NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID); + NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength); +@@ -1240,6 +1244,13 @@ VOID LinkUp( + UCHAR Value = 0, idx; + MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry; + ++ if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) ++ { ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_HALT); ++ RTMPusecDelay(6000); ++ pAd->bPCIclkOff = FALSE; ++ } ++ + pEntry = &pAd->MacTab.Content[BSSID_WCID]; + + // +@@ -1264,7 +1275,6 @@ VOID LinkUp( + //rt2860b. Don't know why need this + SwitchBetweenWepAndCkip(pAd); + +-#ifdef RT2860 + // Before power save before link up function, We will force use 1R. + // So after link up, check Rx antenna # again. + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); +@@ -1282,7 +1292,6 @@ VOID LinkUp( + } + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); + pAd->StaCfg.BBPR3 = Value; +-#endif // RT2860 // + + if (BssType == BSS_ADHOC) + { +@@ -1330,9 +1339,7 @@ VOID LinkUp( + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); + Value &= (~0x20); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); +-#ifdef RT2860 + pAd->StaCfg.BBPR3 = Value; +-#endif // RT2860 // + + RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data); + Data &= 0xfffffffe; +@@ -1367,9 +1374,7 @@ VOID LinkUp( + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); + Value |= (0x20); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); +-#ifdef RT2860 + pAd->StaCfg.BBPR3 = Value; +-#endif // RT2860 // + + if (pAd->MACVersion == 0x28600100) + { +@@ -1400,9 +1405,7 @@ VOID LinkUp( + RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value); + Value &= (~0x20); + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value); +-#ifdef RT2860 + pAd->StaCfg.BBPR3 = Value; +-#endif // RT2860 // + + if (pAd->MACVersion == 0x28600100) + { +@@ -1598,6 +1601,8 @@ VOID LinkUp( + IV = 0; + IV |= (pAd->StaCfg.DefaultKeyId << 30); + AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0); ++ ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); + } + // NOTE: + // the decision of using "short slot time" or not may change dynamically due to +@@ -1919,6 +1924,7 @@ VOID LinkUp( + } + + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); + + #ifdef DOT11_N_SUPPORT + #ifdef DOT11N_DRAFT3 +@@ -1961,6 +1967,7 @@ VOID LinkDown( + IN BOOLEAN IsReqFromAP) + { + UCHAR i, ByteValue = 0; ++ BOOLEAN Cancelled; + + // Do nothing if monitor mode is on + if (MONITOR_ON(pAd)) +@@ -1972,6 +1979,12 @@ VOID LinkDown( + return; + #endif // RALINK_ATE // + ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); ++ RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); ++ ++ // Not allow go to sleep within linkdown function. ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ + if (pAd->CommonCfg.bWirelessEvent) + { + RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); +@@ -1980,7 +1993,6 @@ VOID LinkDown( + DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n")); + OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED); + +-#ifdef RT2860 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + BOOLEAN Cancelled; +@@ -1988,17 +2000,15 @@ VOID LinkDown( + RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); + } + +- if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) ++ if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) || ++ RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND) || ++ RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)) + { +- AUTO_WAKEUP_STRUC AutoWakeupCfg; +- AsicForceWakeup(pAd, TRUE); +- AutoWakeupCfg.word = 0; +- RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word); ++ AsicForceWakeup(pAd, RTMP_HALT); + OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE); + } + + pAd->bPCIclkOff = FALSE; +-#endif // RT2860 // + if (ADHOC_ON(pAd)) // Adhoc mode link down + { + DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n")); +@@ -2266,6 +2276,9 @@ VOID LinkDown( + RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff); + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS); + ++ // Allow go to sleep after linkdown steps. ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ + #ifdef WPA_SUPPLICANT_SUPPORT + #ifndef NATIVE_WPA_SUPPLICANT_SUPPORT + if (pAd->StaCfg.WpaSupplicantUP) { +@@ -2510,7 +2523,6 @@ VOID AuthParmFill( + + ========================================================================== + */ +-#ifdef RT2860 + VOID ComposePsPoll( + IN PRTMP_ADAPTER pAd) + { +@@ -2534,7 +2546,6 @@ VOID ComposeNullFrame( + COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress); + COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid); + } +-#endif // RT2860 // + + + +--- a/drivers/staging/rt2860/sta/dls.c ++++ b/drivers/staging/rt2860/sta/dls.c +@@ -1419,7 +1419,6 @@ BOOLEAN RTMPRcvFrameDLSCheck( + //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast + //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); + // Add Pair-wise key to Asic +-#ifdef RT2860 + AsicAddPairwiseKeyEntry(pAd, + pAd->StaCfg.DLSEntry[i].MacAddr, + (UCHAR)pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, +@@ -1431,7 +1430,6 @@ BOOLEAN RTMPRcvFrameDLSCheck( + PairwiseKey.CipherAlg, + pEntry); + +-#endif // RT2860 // + NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); + DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Peer STA MAC Address STAKey) \n")); + +@@ -1477,7 +1475,6 @@ BOOLEAN RTMPRcvFrameDLSCheck( + //AsicAddKeyEntry(pAd, (USHORT)(i + 2), BSS0, 0, &PairwiseKey, TRUE, TRUE); // reserve 0 for multicast, 1 for unicast + //AsicUpdateRxWCIDTable(pAd, (USHORT)(i + 2), pAddr); + // Add Pair-wise key to Asic +-#ifdef RT2860 + AsicAddPairwiseKeyEntry(pAd, + pAd->StaCfg.DLSEntry[i].MacAddr, + (UCHAR)pAd->StaCfg.DLSEntry[i].MacTabMatchWCID, +@@ -1488,7 +1485,6 @@ BOOLEAN RTMPRcvFrameDLSCheck( + 0, + PairwiseKey.CipherAlg, + pEntry); +-#endif // RT2860 // + NdisMoveMemory(&pEntry->PairwiseKey, &PairwiseKey, sizeof(CIPHER_KEY)); + DBGPRINT(RT_DEBUG_TRACE,("DLS - Receive STAKey Message-1 (Initiator STA MAC Address STAKey)\n")); + +--- a/drivers/staging/rt2860/sta/rtmp_data.c ++++ b/drivers/staging/rt2860/sta/rtmp_data.c +@@ -75,7 +75,6 @@ VOID STARxEAPOLFrameIndicate( + + if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0) + { +-#ifdef RT2860 + MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[BSSID_WCID]; + + // Set key material and cipherAlg to Asic +@@ -89,7 +88,6 @@ VOID STARxEAPOLFrameIndicate( + + pAd->IndicateMediaState = NdisMediaStateConnected; + pAd->ExtraInfo = GENERAL_LINK_UP; +-#endif // RT2860 // + // For Preventing ShardKey Table is cleared by remove key procedure. + pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg; + pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen; +@@ -693,14 +691,12 @@ BOOLEAN STARxDoneInterruptHandle( + break; + } + +-#ifdef RT2860 + if (RxProcessed++ > MAX_RX_PROCESS_CNT) + { + // need to reschedule rx handle + bReschedule = TRUE; + break; + } +-#endif // RT2860 // + + RxProcessed ++; // test + +@@ -811,6 +807,13 @@ BOOLEAN STARxDoneInterruptHandle( + } + } + ++ // fRTMP_PS_GO_TO_SLEEP_NOW is set if receiving beacon. ++ if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW) && (INFRA_ON(pAd))) ++ { ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); ++ AsicSleepThenAutoWakeup(pAd, pAd->ThisTbttNumToNextWakeUp); ++ bReschedule = FALSE; ++ } + return bReschedule; + } + +@@ -828,7 +831,7 @@ BOOLEAN STARxDoneInterruptHandle( + VOID RTMPHandleTwakeupInterrupt( + IN PRTMP_ADAPTER pAd) + { +- AsicForceWakeup(pAd, FALSE); ++ AsicForceWakeup(pAd, DOT11POWERSAVE); + } + + /* +@@ -1220,7 +1223,6 @@ NDIS_STATUS STASendPacket( + + ======================================================================== + */ +-#ifdef RT2860 + NDIS_STATUS RTMPFreeTXDRequest( + IN PRTMP_ADAPTER pAd, + IN UCHAR QueIdx, +@@ -1264,7 +1266,6 @@ NDIS_STATUS RTMPFreeTXDRequest( + + return (Status); + } +-#endif // RT2860 // + + + +@@ -1889,7 +1890,8 @@ VOID STA_AMPDU_Frame_Tx( + // + // Kick out Tx + // +- HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); + + pAd->RalinkCounters.KickTxCount++; + pAd->RalinkCounters.OneSecTxDoneCount++; +@@ -2019,7 +2021,8 @@ VOID STA_AMSDU_Frame_Tx( + // + // Kick out Tx + // +- HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); + } + #endif // DOT11_N_SUPPORT // + +@@ -2139,7 +2142,8 @@ VOID STA_Legacy_Frame_Tx( + // + // Kick out Tx + // +- HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); + } + + +@@ -2249,7 +2253,8 @@ VOID STA_ARalink_Frame_Tx( + // + // Kick out Tx + // +- HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); ++ if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_DISABLE_TX)) ++ HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx); + + } + +@@ -2526,7 +2531,7 @@ NDIS_STATUS STAHardTransmit( + if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) + { + DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n")); +- AsicForceWakeup(pAd, TRUE); ++ AsicForceWakeup(pAd, FROM_TX); + } + + // It should not change PSM bit, when APSD turn on. +--- a/drivers/staging/rt2860/sta/sync.c ++++ b/drivers/staging/rt2860/sta/sync.c +@@ -228,7 +228,6 @@ VOID MlmeScanReqAction( + // Increase the scan retry counters. + pAd->StaCfg.ScanCnt++; + +-#ifdef RT2860 + if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && + (IDLE_ON(pAd)) && + (pAd->StaCfg.bRadio == TRUE) && +@@ -236,7 +235,6 @@ VOID MlmeScanReqAction( + { + RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); + } +-#endif // RT2860 // + + // first check the parameter sanity + if (MlmeScanReqSanity(pAd, +@@ -349,7 +347,6 @@ VOID MlmeJoinReqAction( + + DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx)); + +-#ifdef RT2860 + if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && + (IDLE_ON(pAd)) && + (pAd->StaCfg.bRadio == TRUE) && +@@ -357,7 +354,6 @@ VOID MlmeJoinReqAction( + { + RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE); + } +-#endif // RT2860 // + + // reset all the timers + RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled); +@@ -1300,8 +1296,6 @@ VOID PeerBeacon( + { + if (pAd->StaCfg.Adhoc20NJoined == FALSE) + { +- UCHAR ByteValue = 0; +- + pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel; + + pAd->StaCfg.Adhoc20NJoined = TRUE; +@@ -1534,13 +1528,10 @@ VOID PeerBeacon( + // 5. otherwise, put PHY back to sleep to save battery. + if (MessageToMe) + { +-#ifdef RT2860 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); +- // Turn clk to 80Mhz. + } +-#endif // RT2860 // + if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && + pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO) + { +@@ -1551,12 +1542,10 @@ VOID PeerBeacon( + } + else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM)) + { +-#ifdef RT2860 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); + } +-#endif // RT2860 // + } + else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) || + (pAd->TxSwQueue[QID_AC_BE].Number != 0) || +@@ -1570,12 +1559,10 @@ VOID PeerBeacon( + { + // TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme + // can we cheat here (i.e. just check MGMT & AC_BE) for better performance? +-#ifdef RT2860 + if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) + { + RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3); + } +-#endif // RT2860 // + } + else + { +@@ -1590,7 +1577,10 @@ VOID PeerBeacon( + + if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) + { +- AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); ++ // Set a flag to go to sleep . Then after parse this RxDoneInterrupt, will go to sleep mode. ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW); ++ pAd->ThisTbttNumToNextWakeUp = TbttNumToNextWakeUp; ++ //AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp); + } + } + } +--- a/drivers/staging/rt2860/sta/wpa.c ++++ b/drivers/staging/rt2860/sta/wpa.c +@@ -1384,6 +1384,10 @@ VOID WpaGroupMsg1Action( + pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; + else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) + pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; + + //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); + } +@@ -1760,7 +1764,7 @@ BOOLEAN ParseKeyData( + // Get GTK length - refer to IEEE 802.11i-2004 p.82 + GTKLEN = pKDE->Len -6; + +- if (GTKLEN < LEN_AES_KEY) ++ if (GTKLEN < MIN_LEN_OF_GTK) + { + DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); + return FALSE; +@@ -1786,6 +1790,10 @@ BOOLEAN ParseKeyData( + pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; + else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) + pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64; ++ else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) ++ pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128; + + return TRUE; + +--- a/drivers/staging/rt2860/sta_ioctl.c ++++ b/drivers/staging/rt2860/sta_ioctl.c +@@ -49,15 +49,9 @@ extern ULONG RTDebugLevel; + + #define GROUP_KEY_NO 4 + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + #define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_A, _B, _C, _D, _E) + #define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_A, _B, _C, _D, _E) + #define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_A, _B, _C, _D, _E, _F) +-#else +-#define IWE_STREAM_ADD_EVENT(_A, _B, _C, _D, _E) iwe_stream_add_event(_B, _C, _D, _E) +-#define IWE_STREAM_ADD_POINT(_A, _B, _C, _D, _E) iwe_stream_add_point(_B, _C, _D, _E) +-#define IWE_STREAM_ADD_VALUE(_A, _B, _C, _D, _E, _F) iwe_stream_add_value(_B, _C, _D, _E, _F) +-#endif + + extern UCHAR CipherWpa2Template[]; + extern UCHAR CipherWpaPskTkip[]; +@@ -358,6 +352,20 @@ VOID RTMPAddKey( + + DBGPRINT(RT_DEBUG_TRACE, ("RTMPAddKey ------>\n")); + ++ RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ if (RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) ++ { ++ if (pAd->StaCfg.bRadio == FALSE) ++ { ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ return; ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPAAddKeyProc1==>\n")); ++ RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_HALT); ++ RTMPusecDelay(6000); ++ pAd->bPCIclkOff = FALSE; ++ } ++ + if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) + { + if (pKey->KeyIndex & 0x80000000) +@@ -551,6 +559,8 @@ VOID RTMPAddKey( + } + } + end: ++ RTMP_SET_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP); ++ DBGPRINT(RT_DEBUG_INFO, ("<------ RTMPAddKey\n")); + return; + } + +@@ -571,11 +581,9 @@ rt_ioctl_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra) + { +-// PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++// PRTMP_ADAPTER pAdapter = dev->ml_priv; + +-#ifdef RT2860 + strncpy(name, "RT2860 Wireless", IFNAMSIZ); +-#endif // RT2860 // + return 0; + } + +@@ -583,7 +591,7 @@ int rt_ioctl_siwfreq(struct net_device * + struct iw_request_info *info, + struct iw_freq *freq, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + int chan = -1; + + //check if the interface is down +@@ -623,19 +631,19 @@ int rt_ioctl_giwfreq(struct net_device * + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -653,7 +661,7 @@ int rt_ioctl_siwmode(struct net_device * + struct iw_request_info *info, + __u32 *mode, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + //check if the interface is down + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) +@@ -670,11 +678,9 @@ int rt_ioctl_siwmode(struct net_device * + case IW_MODE_INFRA: + Set_NetworkType_Proc(pAdapter, "Infra"); + break; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + case IW_MODE_MONITOR: + Set_NetworkType_Proc(pAdapter, "Monitor"); + break; +-#endif + default: + DBGPRINT(RT_DEBUG_TRACE, ("===>rt_ioctl_siwmode::SIOCSIWMODE (unknown %d)\n", *mode)); + return -EINVAL; +@@ -695,19 +701,19 @@ int rt_ioctl_giwmode(struct net_device * + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -715,12 +721,10 @@ int rt_ioctl_giwmode(struct net_device * + *mode = IW_MODE_ADHOC; + else if (INFRA_ON(pAdapter)) + *mode = IW_MODE_INFRA; +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + else if (MONITOR_ON(pAdapter)) + { + *mode = IW_MODE_MONITOR; + } +-#endif + else + *mode = IW_MODE_AUTO; + +@@ -732,7 +736,7 @@ int rt_ioctl_siwsens(struct net_device * + struct iw_request_info *info, + char *name, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + //check if the interface is down + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) +@@ -763,19 +767,19 @@ int rt_ioctl_giwrange(struct net_device + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -857,7 +861,7 @@ int rt_ioctl_siwap(struct net_device *de + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + NDIS_802_11_MAC_ADDRESS Bssid; + + //check if the interface is down +@@ -902,19 +906,19 @@ int rt_ioctl_giwap(struct net_device *de + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -984,7 +988,7 @@ int rt_ioctl_iwaplist(struct net_device + struct iw_request_info *info, + struct iw_point *data, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + struct sockaddr addr[IW_MAX_AP]; + struct iw_quality qual[IW_MAX_AP]; +@@ -1020,7 +1024,7 @@ int rt_ioctl_siwscan(struct net_device * + struct iw_request_info *info, + struct iw_point *data, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + ULONG Now; + int Status = NDIS_STATUS_SUCCESS; +@@ -1038,6 +1042,15 @@ int rt_ioctl_siwscan(struct net_device * + return -EINVAL; + } + ++ if ((pAdapter->OpMode == OPMODE_STA) && (IDLE_ON(pAdapter)) ++ && (pAdapter->StaCfg.bRadio == TRUE) ++ && (RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_IDLE_RADIO_OFF))) ++ { ++ RT28xxPciAsicRadioOn(pAdapter, GUI_IDLE_POWER_SAVE); ++ } ++ // Check if still radio off. ++ else if (pAdapter->bPCIclkOff == TRUE) ++ return 0; + + #ifdef WPA_SUPPLICANT_SUPPORT + if (pAdapter->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_ENABLE) +@@ -1102,7 +1115,7 @@ int rt_ioctl_giwscan(struct net_device * + struct iw_point *data, char *extra) + { + +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + int i=0; + char *current_ev = extra, *previous_ev = extra; + char *end_buf; +@@ -1391,7 +1404,7 @@ int rt_ioctl_siwessid(struct net_device + struct iw_request_info *info, + struct iw_point *data, char *essid) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + //check if the interface is down + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) +@@ -1437,19 +1450,19 @@ int rt_ioctl_giwessid(struct net_device + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1480,7 +1493,7 @@ int rt_ioctl_siwnickn(struct net_device + struct iw_request_info *info, + struct iw_point *data, char *nickname) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + //check if the interface is down + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) +@@ -1508,19 +1521,19 @@ int rt_ioctl_giwnickn(struct net_device + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1537,7 +1550,7 @@ int rt_ioctl_siwrts(struct net_device *d + struct iw_request_info *info, + struct iw_param *rts, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + u16 val; + + //check if the interface is down +@@ -1571,19 +1584,19 @@ int rt_ioctl_giwrts(struct net_device *d + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1605,7 +1618,7 @@ int rt_ioctl_siwfrag(struct net_device * + struct iw_request_info *info, + struct iw_param *frag, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + u16 val; + + //check if the interface is down +@@ -1637,19 +1650,19 @@ int rt_ioctl_giwfrag(struct net_device * + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1673,7 +1686,7 @@ int rt_ioctl_siwencode(struct net_device + struct iw_request_info *info, + struct iw_point *erq, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + //check if the interface is down + if(!RTMP_TEST_FLAG(pAdapter, fRTMP_ADAPTER_INTERRUPT_IN_USE)) +@@ -1756,7 +1769,7 @@ int rt_ioctl_siwencode(struct net_device + } + else + /* Don't complain if only change the mode */ +- if(!erq->flags & IW_ENCODE_MODE) { ++ if (!(erq->flags & IW_ENCODE_MODE)) { + return -EINVAL; + } + } +@@ -1780,19 +1793,19 @@ rt_ioctl_giwencode(struct net_device *de + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; ++ pVirtualAd = dev->ml_priv; + if (pVirtualAd && pVirtualAd->RtmpDev) +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1860,19 +1873,19 @@ rt_ioctl_setparam(struct net_device *dev + + if (dev->priv_flags == INT_MAIN) + { +- pAdapter = dev->priv; ++ pAdapter = dev->ml_priv; + } + else + { +- pVirtualAd = dev->priv; +- pAdapter = pVirtualAd->RtmpDev->priv; ++ pVirtualAd = dev->ml_priv; ++ pAdapter = pVirtualAd->RtmpDev->ml_priv; + } + pObj = (POS_COOKIE) pAdapter->OS_Cookie; + + if (pAdapter == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -1928,7 +1941,7 @@ rt_private_get_statistics(struct net_dev + struct iw_point *wrq, char *extra) + { + INT Status = 0; +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + + if (extra == NULL) + { +@@ -2055,18 +2068,18 @@ rt_private_show(struct net_device *dev, + u32 subcmd = wrq->flags; + + if (dev->priv_flags == INT_MAIN) +- pAd = dev->priv; ++ pAd = dev->ml_priv; + else + { +- pVirtualAd = dev->priv; +- pAd = pVirtualAd->RtmpDev->priv; ++ pVirtualAd = dev->ml_priv; ++ pAd = pVirtualAd->RtmpDev->ml_priv; + } + pObj = (POS_COOKIE) pAd->OS_Cookie; + + if (pAd == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +@@ -2161,12 +2174,6 @@ rt_private_show(struct net_device *dev, + wrq->length = strlen(extra) + 1; // 1: size of '\0' + break; + case RAIO_ON: +- if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) +- { +- sprintf(extra, "Scanning\n"); +- wrq->length = strlen(extra) + 1; // 1: size of '\0' +- break; +- } + pAd->StaCfg.bSwRadio = TRUE; + //if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) + { +@@ -2200,7 +2207,7 @@ rt_private_show(struct net_device *dev, + } + break; + default: +- DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd)); + break; + } + +@@ -2213,13 +2220,13 @@ int rt_ioctl_siwmlme(struct net_device * + union iwreq_data *wrqu, + char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + struct iw_mlme *pMlme = (struct iw_mlme *)wrqu->data.pointer; + MLME_QUEUE_ELEM MsgElem; + MLME_DISASSOC_REQ_STRUCT DisAssocReq; + MLME_DEAUTH_REQ_STRUCT DeAuthReq; + +- DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__)); + + if (pMlme == NULL) + return -EINVAL; +@@ -2228,7 +2235,7 @@ int rt_ioctl_siwmlme(struct net_device * + { + #ifdef IW_MLME_DEAUTH + case IW_MLME_DEAUTH: +- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__)); + COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid); + DeAuthReq.Reason = pMlme->reason_code; + MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT); +@@ -2243,7 +2250,7 @@ int rt_ioctl_siwmlme(struct net_device * + #endif // IW_MLME_DEAUTH // + #ifdef IW_MLME_DISASSOC + case IW_MLME_DISASSOC: +- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__)); + COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid); + DisAssocReq.Reason = pMlme->reason_code; + +@@ -2257,7 +2264,7 @@ int rt_ioctl_siwmlme(struct net_device * + break; + #endif // IW_MLME_DISASSOC // + default: +- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__)); + break; + } + +@@ -2270,7 +2277,7 @@ int rt_ioctl_siwauth(struct net_device * + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + struct iw_param *param = &wrqu->param; + + //check if the interface is down +@@ -2290,7 +2297,7 @@ int rt_ioctl_siwauth(struct net_device * + else if (param->value == IW_AUTH_WPA_VERSION_WPA2) + pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK; + +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_CIPHER_PAIRWISE: + if (param->value == IW_AUTH_CIPHER_NONE) +@@ -2321,7 +2328,7 @@ int rt_ioctl_siwauth(struct net_device * + pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus; + pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled; + } +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_CIPHER_GROUP: + if (param->value == IW_AUTH_CIPHER_NONE) +@@ -2341,7 +2348,7 @@ int rt_ioctl_siwauth(struct net_device * + { + pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled; + } +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_KEY_MGMT: + if (param->value == IW_AUTH_KEY_MGMT_802_1X) +@@ -2370,12 +2377,12 @@ int rt_ioctl_siwauth(struct net_device * + { + STA_PORT_SECURED(pAdapter); + } +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + break; + case IW_AUTH_PRIVACY_INVOKED: +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_DROP_UNENCRYPTED: + if (param->value != 0) +@@ -2384,7 +2391,7 @@ int rt_ioctl_siwauth(struct net_device * + { + STA_PORT_SECURED(pAdapter); + } +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_80211_AUTH_ALG: + if (param->value & IW_AUTH_ALG_SHARED_KEY) +@@ -2397,10 +2404,10 @@ int rt_ioctl_siwauth(struct net_device * + } + else + return -EINVAL; +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value)); + break; + case IW_AUTH_WPA_ENABLED: +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value)); + break; + default: + return -EOPNOTSUPP; +@@ -2413,7 +2420,7 @@ int rt_ioctl_giwauth(struct net_device * + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + struct iw_param *param = &wrqu->param; + + //check if the interface is down +@@ -2450,6 +2457,20 @@ void fnSetCipherKey( + IN BOOLEAN bGTK, + IN struct iw_encode_ext *ext) + { ++ RTMP_CLEAR_PSFLAG(pAdapter, fRTMP_PS_CAN_GO_SLEEP); ++ if (RTMP_TEST_PSFLAG(pAdapter, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) ++ { ++ if (pAdapter->StaCfg.bRadio == FALSE) ++ { ++ RTMP_SET_PSFLAG(pAdapter, fRTMP_PS_CAN_GO_SLEEP); ++ return; ++ } ++ DBGPRINT(RT_DEBUG_TRACE,("RTMPWPAAddKeyProc1==>\n")); ++ RTMPPCIeLinkCtrlValueRestore(pAdapter, RESTORE_HALT); ++ RTMPusecDelay(6000); ++ pAdapter->bPCIclkOff = FALSE; ++ } ++ + NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); + pAdapter->SharedKey[BSS0][keyIdx].KeyLen = LEN_TKIP_EK; + NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, LEN_TKIP_EK); +@@ -2480,6 +2501,8 @@ void fnSetCipherKey( + keyIdx, + pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, + &pAdapter->MacTab.Content[BSSID_WCID]); ++ ++ RTMP_SET_PSFLAG(pAdapter, fRTMP_PS_CAN_GO_SLEEP); + } + + int rt_ioctl_siwencodeext(struct net_device *dev, +@@ -2487,7 +2510,7 @@ int rt_ioctl_siwencodeext(struct net_dev + union iwreq_data *wrqu, + char *extra) + { +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int keyIdx, alg = ext->alg; +@@ -2508,7 +2531,7 @@ int rt_ioctl_siwencodeext(struct net_dev + pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE; + AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx); + NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY)); +- DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags)); + } + else + { +@@ -2520,15 +2543,15 @@ int rt_ioctl_siwencodeext(struct net_dev + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + { + pAdapter->StaCfg.DefaultKeyId = keyIdx; +- DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId)); + } + + switch (alg) { + case IW_ENCODE_ALG_NONE: +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__)); + break; + case IW_ENCODE_ALG_WEP: +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx)); + if (ext->key_len == MAX_WEP_KEY_SIZE) + { + pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE; +@@ -2544,9 +2567,24 @@ int rt_ioctl_siwencodeext(struct net_dev + + NdisZeroMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, 16); + NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len); ++ ++ if (pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled || ++ pAdapter->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled) ++ { ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, pAdapter->SharedKey[BSS0][keyIdx].Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, keyIdx, pAdapter->SharedKey[BSS0][keyIdx].CipherAlg, NULL); ++ ++ STA_PORT_SECURED(pAdapter); ++ ++ // Indicate Connected for GUI ++ pAdapter->IndicateMediaState = NdisMediaStateConnected; ++ } + break; + case IW_ENCODE_ALG_TKIP: +- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len)); ++ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len)); + if (ext->key_len == 32) + { + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) +@@ -2596,7 +2634,7 @@ rt_ioctl_giwencodeext(struct net_device + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + PCHAR pKey = NULL; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; +@@ -2680,7 +2718,7 @@ int rt_ioctl_siwgenie(struct net_device + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + + if (wrqu->data.length > MAX_LEN_OF_RSNIE || + (wrqu->data.length && extra == NULL)) +@@ -2705,7 +2743,7 @@ int rt_ioctl_giwgenie(struct net_device + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + + if ((pAd->StaCfg.RSNIE_Len == 0) || + (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)) +@@ -2751,7 +2789,7 @@ int rt_ioctl_siwpmksa(struct net_device + union iwreq_data *wrqu, + char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + struct iw_pmksa *pPmksa = (struct iw_pmksa *)wrqu->data.pointer; + INT CachedIdx = 0, idx = 0; + +@@ -2834,7 +2872,7 @@ rt_private_ioctl_bbp(struct net_device * + UINT32 bbpValue; + BOOLEAN bIsPrintAllBBP = FALSE; + INT Status = 0; +- PRTMP_ADAPTER pAdapter = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAdapter = dev->ml_priv; + + + memset(extra, 0x00, IW_PRIV_SIZE_MASK); +@@ -2961,7 +2999,7 @@ int rt_ioctl_siwrate(struct net_device * + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + UINT32 rate = wrqu->bitrate.value, fixed = wrqu->bitrate.fixed; + + //check if the interface is down +@@ -3019,7 +3057,7 @@ int rt_ioctl_giwrate(struct net_device * + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) + { +- PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) dev->priv; ++ PRTMP_ADAPTER pAd = dev->ml_priv; + int rate_index = 0, rate_count = 0; + HTTRANSMIT_SETTING ht_setting; + __s32 ralinkrate[] = +@@ -4259,7 +4297,23 @@ INT RTMPSetInformation( + } + + #ifdef WPA_SUPPLICANT_SUPPORT +- if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) ++ if ((pAdapter->StaCfg.WpaSupplicantUP != 0) && ++ (pAdapter->StaCfg.AuthMode >= Ndis802_11AuthModeWPA)) ++ { ++ Key = pWepKey->KeyMaterial; ++ ++ // Set Group key material to Asic ++ AsicAddSharedKeyEntry(pAdapter, BSS0, KeyIdx, CipherAlg, Key, NULL, NULL); ++ ++ // Update WCID attribute table and IVEIV table for this group key table ++ RTMPAddWcidAttributeEntry(pAdapter, BSS0, KeyIdx, CipherAlg, NULL); ++ ++ STA_PORT_SECURED(pAdapter); ++ ++ // Indicate Connected for GUI ++ pAdapter->IndicateMediaState = NdisMediaStateConnected; ++ } ++ else if (pAdapter->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED) + #endif // WPA_SUPPLICANT_SUPPORT + { + Key = pAdapter->SharedKey[BSS0][KeyIdx].Key; +@@ -5265,7 +5319,6 @@ INT RTMPQueryInformation( + case RT_OID_802_11_PRODUCTID: + DBGPRINT(RT_DEBUG_TRACE, ("Query::RT_OID_802_11_PRODUCTID \n")); + +-#ifdef RT2860 + { + + USHORT device_id; +@@ -5275,7 +5328,6 @@ INT RTMPQueryInformation( + DBGPRINT(RT_DEBUG_TRACE, (" pci_dev = NULL\n")); + sprintf(tmp, "%04x %04x\n", NIC_PCI_VENDOR_ID, device_id); + } +-#endif // RT2860 // + wrq->u.data.length = strlen(tmp); + Status = copy_to_user(wrq->u.data.pointer, tmp, wrq->u.data.length); + break; +@@ -5409,19 +5461,19 @@ INT rt28xx_sta_ioctl( + + if (net_dev->priv_flags == INT_MAIN) + { +- pAd = net_dev->priv; ++ pAd = net_dev->ml_priv; + } + else + { +- pVirtualAd = net_dev->priv; +- pAd = pVirtualAd->RtmpDev->priv; ++ pVirtualAd = net_dev->ml_priv; ++ pAd = pVirtualAd->RtmpDev->ml_priv; + } + pObj = (POS_COOKIE) pAd->OS_Cookie; + + if (pAd == NULL) + { + /* if 1st open fail, pAd will be free; +- So the net_dev->priv will be NULL in 2rd open */ ++ So the net_dev->ml_priv will be NULL in 2rd open */ + return -ENETDOWN; + } + +--- a/drivers/staging/rt2860/wpa.h ++++ b/drivers/staging/rt2860/wpa.h +@@ -90,6 +90,7 @@ + #define TKIP_AP_RXMICK_OFFSET (TKIP_AP_TXMICK_OFFSET+LEN_TKIP_TXMICK) + #define TKIP_GTK_LENGTH ((LEN_TKIP_EK)+(LEN_TKIP_RXMICK)+(LEN_TKIP_TXMICK)) + #define LEN_PTK ((LEN_EAP_KEY)+(LEN_TKIP_KEY)) ++#define MIN_LEN_OF_GTK 5 + + // RSN IE Length definition + #define MAX_LEN_OF_RSNIE 90 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-rtl8192e-backport-net_device_ops-conversion.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-rtl8192e-backport-net_device_ops-conversion.patch new file mode 100644 index 000000000..f27721eca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-rtl8192e-backport-net_device_ops-conversion.patch @@ -0,0 +1,64 @@ +From foo@baz Wed Aug 12 09:28:09 PDT 2009 +Date: Wed, 12 Aug 2009 09:28:09 -0700 +To: Greg KH +From: Greg Kroah-Hartman +Subject: Staging: rtl8192e: backport net_device_ops conversion + +2.6.27 does not have struct net_device_ops, so backport the changes +needed to get things to work here. + +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/rtl8192e/ieee80211/ieee80211_module.c | 2 -- + drivers/staging/rtl8192e/r8192E_core.c | 6 ++++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c ++++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c +@@ -118,9 +118,7 @@ struct net_device *alloc_ieee80211(int s + #else + ieee = (struct ieee80211_device *)dev->priv; + #endif +-#if 0 + dev->hard_start_xmit = ieee80211_xmit; +-#endif + + memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv); + ieee->dev = dev; +--- a/drivers/staging/rtl8192e/r8192E_core.c ++++ b/drivers/staging/rtl8192e/r8192E_core.c +@@ -6231,6 +6231,7 @@ void rtl8192_irq_rx_tasklet(struct r8192 + write_nic_dword(priv->ieee80211->dev, INTA_MASK,read_nic_dword(priv->ieee80211->dev, INTA_MASK) | IMR_RDU); + } + ++#if 0 + static const struct net_device_ops rtl8192_netdev_ops = { + .ndo_open = rtl8192_open, + .ndo_stop = rtl8192_close, +@@ -6241,6 +6242,7 @@ static const struct net_device_ops rtl81 + .ndo_set_mac_address = r8192_set_mac_adr, + .ndo_start_xmit = ieee80211_xmit, + }; ++#endif + + /**************************************************************************** + ---------------------------- PCI_STUFF--------------------------- +@@ -6362,8 +6364,9 @@ static int __devinit rtl8192_pci_probe(s + dev->irq = pdev->irq; + priv->irq = 0; + +- dev->netdev_ops = &rtl8192_netdev_ops; + #if 0 ++ dev->netdev_ops = &rtl8192_netdev_ops; ++#endif + dev->open = rtl8192_open; + dev->stop = rtl8192_close; + //dev->hard_start_xmit = rtl8192_8023_hard_start_xmit; +@@ -6372,7 +6375,6 @@ static int __devinit rtl8192_pci_probe(s + dev->do_ioctl = rtl8192_ioctl; + dev->set_multicast_list = r8192_set_multicast; + dev->set_mac_address = r8192_set_mac_adr; +-#endif + + //DMESG("Oops: i'm coming\n"); + #if WIRELESS_EXT >= 12 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/staging-workaround-build-system-bug.patch b/src/patches/suse-2.6.27.31/patches.drivers/staging-workaround-build-system-bug.patch new file mode 100644 index 000000000..dcb39e660 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/staging-workaround-build-system-bug.patch @@ -0,0 +1,49 @@ +From: Greg Kroah-Hartman +Subject: Staging: workaround build system bug +Patch-mainline: 2.6.28 + +This is needed as CONFIG_STAGING is set to y, yet there is no code in +drivers/staging/ to build, so the build-in.o doesn't get created +properly. Create a "dummy" module in drivers/staging called staging.c +to work around this bug. + +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/Makefile | 3 +++ + drivers/staging/staging.c | 19 +++++++++++++++++++ + 2 files changed, 22 insertions(+) + +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -1,5 +1,8 @@ + # Makefile for staging directory + ++# fix for build system bug... ++obj-$(CONFIG_STAGING) += staging.o ++ + obj-$(CONFIG_ET131X) += et131x/ + obj-$(CONFIG_SLICOSS) += slicoss/ + obj-$(CONFIG_SXG) += sxg/ +--- /dev/null ++++ b/drivers/staging/staging.c +@@ -0,0 +1,19 @@ ++#include ++#include ++#include ++ ++static int __init staging_init(void) ++{ ++ return 0; ++} ++ ++static void __exit staging_exit(void) ++{ ++} ++ ++module_init(staging_init); ++module_exit(staging_exit); ++ ++MODULE_AUTHOR("Greg Kroah-Hartman"); ++MODULE_DESCRIPTION("Staging Core"); ++MODULE_LICENSE("GPL"); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/sysfs-crash-debugging.patch b/src/patches/suse-2.6.27.31/patches.drivers/sysfs-crash-debugging.patch new file mode 100644 index 000000000..0868b0454 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/sysfs-crash-debugging.patch @@ -0,0 +1,127 @@ +Subject: display last accessed sysfs file on kernel panic message +From: Andrew Morton +Patch-mainline: never + +Display the most-recently-opened sysfs file's name when oopsing. + +From: Adrian Bunk + + Build fix + +From: Greg Kroah-Hartman + + Modified to make the api call cleaner, and available to all arches if + need be. Also added it to x86-64's crash dump message. + + +Signed-off-by: Adrian Bunk +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/traps_32.c | 2 ++ + arch/x86/kernel/traps_64.c | 2 ++ + fs/sysfs/file.c | 14 ++++++++++++++ + fs/sysfs/mount.c | 2 +- + include/linux/sysfs.h | 7 +++++++ + 5 files changed, 26 insertions(+), 1 deletion(-) + +--- a/arch/x86/kernel/traps_32.c ++++ b/arch/x86/kernel/traps_32.c +@@ -428,6 +428,8 @@ int __kprobes __die(const char *str, str + printk("DEBUG_PAGEALLOC"); + #endif + printk("\n"); ++ ++ sysfs_printk_last_file(); + if (notify_die(DIE_OOPS, str, regs, err, + current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) + return 1; +--- a/arch/x86/kernel/traps_64.c ++++ b/arch/x86/kernel/traps_64.c +@@ -537,6 +537,8 @@ int __kprobes __die(const char *str, str + printk("DEBUG_PAGEALLOC"); + #endif + printk("\n"); ++ ++ sysfs_printk_last_file(); + if (notify_die(DIE_OOPS, str, regs, err, + current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) + return 1; +--- a/fs/sysfs/file.c ++++ b/fs/sysfs/file.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -23,6 +24,9 @@ + + #include "sysfs.h" + ++/* used in crash dumps to help with debugging */ ++static char last_sysfs_file[PATH_MAX]; ++ + /* + * There's one sysfs_buffer for each open file and one + * sysfs_open_dirent for each sysfs_dirent with one or more open +@@ -328,6 +332,11 @@ static int sysfs_open_file(struct inode + struct sysfs_buffer *buffer; + struct sysfs_ops *ops; + int error = -EACCES; ++ char *p; ++ ++ p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); ++ if (p) ++ memmove(last_sysfs_file, p, strlen(p) + 1); + + /* need attr_sd for attr and ops, its parent for kobj */ + if (!sysfs_get_active_two(attr_sd)) +@@ -389,6 +398,11 @@ static int sysfs_open_file(struct inode + return error; + } + ++void sysfs_printk_last_file(void) ++{ ++ printk(KERN_EMERG "last sysfs file: %s\n", last_sysfs_file); ++} ++ + static int sysfs_release(struct inode *inode, struct file *filp) + { + struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; +--- a/fs/sysfs/mount.c ++++ b/fs/sysfs/mount.c +@@ -22,7 +22,7 @@ + /* Random magic number */ + #define SYSFS_MAGIC 0x62656572 + +-static struct vfsmount *sysfs_mount; ++struct vfsmount *sysfs_mount; + struct super_block * sysfs_sb = NULL; + struct kmem_cache *sysfs_dir_cachep; + +--- a/include/linux/sysfs.h ++++ b/include/linux/sysfs.h +@@ -121,6 +121,8 @@ void sysfs_notify(struct kobject *kobj, + + extern int __must_check sysfs_init(void); + ++void sysfs_printk_last_file(void); ++ + #else /* CONFIG_SYSFS */ + + static inline int sysfs_schedule_callback(struct kobject *kobj, +@@ -231,6 +233,11 @@ static inline int __must_check sysfs_ini + return 0; + } + ++static inline void sysfs_printk_last_file(void) ++{ ++ ; ++} ++ + #endif /* CONFIG_SYSFS */ + + #endif /* _SYSFS_H_ */ diff --git a/src/patches/suse-2.6.27.31/patches.drivers/tg3-Add-57780-ASIC-revision.patch b/src/patches/suse-2.6.27.31/patches.drivers/tg3-Add-57780-ASIC-revision.patch new file mode 100644 index 000000000..dfda82bec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/tg3-Add-57780-ASIC-revision.patch @@ -0,0 +1,226 @@ +From 61730cd8941daf8520b6170a93e6a2db3727a4f1 Mon Sep 17 00:00:00 2001 +From: mcarlson +Date: Tue, 30 Sep 2008 08:49:06 -0700 +Subject: [PATCH 1/2] tg3: Add 57780 ASIC revision +Acked-by: Karsten Keil +Reference: bnc#434147 + +This patch adds support for the 57780 device. The patch limits the +changes to the MAC portion. +--- + drivers/net/tg3.c | 28 ++++++++++++++++++++++++++-- + drivers/net/tg3.h | 5 +++++ + 2 files changed, 31 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c +index 71d2c5c..7188675 100644 +--- a/drivers/net/tg3.c ++++ b/drivers/net/tg3.c +@@ -206,6 +206,10 @@ static struct pci_device_id tg3_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, ++ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57720)}, + {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, + {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, + {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, +@@ -5812,6 +5816,7 @@ static int tg3_chip_reset(struct tg3 *tp) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tw32(GRC_FASTBOOT_PC, 0); +@@ -7112,6 +7117,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) + return err; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && ++ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { + /* This value is determined during the probe time DMA +@@ -7353,6 +7359,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) + RDMAC_MODE_LNGREAD_ENAB); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | + RDMAC_MODE_MBUF_RBD_CRPT_ENAB | +@@ -7525,6 +7532,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || ++ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)) + val |= WDMAC_MODE_STATUS_TAG_FIX; +@@ -7589,6 +7597,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) + tp->rx_mode = RX_MODE_ENABLE; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; +@@ -9144,6 +9153,7 @@ static int tg3_set_tso(struct net_device *dev, u32 value) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + dev->features |= NETIF_F_TSO_ECN; + } else +@@ -9402,6 +9412,7 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + ethtool_op_set_tx_ipv6_csum(dev, data); +@@ -9924,6 +9935,7 @@ static int tg3_test_memory(struct tg3 *tp) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + mem_tbl = mem_tbl_5755; +@@ -10132,6 +10144,7 @@ static int tg3_test_loopback(struct tg3 *tp) + return TG3_LOOPBACK_FAILED; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + int i; +@@ -10161,6 +10174,7 @@ static int tg3_test_loopback(struct tg3 *tp) + err |= TG3_MAC_LOOPBACK_FAILED; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + tw32(TG3_CPMU_CTRL, cpmuctrl); +@@ -10811,6 +10825,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) + tg3_get_5755_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_get_5787_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) +@@ -11141,6 +11156,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) && ++ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) && + (tp->nvram_jedecnum == JEDEC_ST) && +@@ -11903,7 +11919,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + + pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, + &prod_id_asic_rev); +- tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK; ++ tp->pci_chip_rev_id = prod_id_asic_rev; + } + + /* Wrong chip ID in 5752 A0. This code can be removed later +@@ -12057,6 +12073,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || +@@ -12079,6 +12096,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { +@@ -12283,6 +12301,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; +@@ -12371,6 +12390,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { + if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 && + tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722) +@@ -12399,7 +12419,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) + tp->coalesce_mode |= HOSTCC_MODE_32BYTE; + +- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) ++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + + err = tg3_mdio_init(tp); +@@ -12539,6 +12560,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) +@@ -13467,6 +13489,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + dev->features |= NETIF_F_TSO_ECN; + } +@@ -13533,6 +13556,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || ++ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + dev->features |= NETIF_F_IPV6_CSUM; +diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h +index f5b8cab..06859d1 100644 +--- a/drivers/net/tg3.h ++++ b/drivers/net/tg3.h +@@ -38,6 +38,10 @@ + #define TG3PCI_DEVICE_TIGON3_2 0x1645 /* BCM5701 */ + #define TG3PCI_DEVICE_TIGON3_3 0x1646 /* BCM5702 */ + #define TG3PCI_DEVICE_TIGON3_4 0x1647 /* BCM5703 */ ++#define TG3PCI_DEVICE_TIGON3_57780 0x1692 ++#define TG3PCI_DEVICE_TIGON3_57760 0x1690 ++#define TG3PCI_DEVICE_TIGON3_57790 0x1694 ++#define TG3PCI_DEVICE_TIGON3_57720 0x168c + #define TG3PCI_COMMAND 0x00000004 + #define TG3PCI_STATUS 0x00000006 + #define TG3PCI_CCREVID 0x00000008 +@@ -129,6 +133,7 @@ + #define ASIC_REV_5784 0x5784 + #define ASIC_REV_5761 0x5761 + #define ASIC_REV_5785 0x5785 ++#define ASIC_REV_57780 0x57780 + #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) + #define CHIPREV_5700_AX 0x70 + #define CHIPREV_5700_BX 0x71 +-- +1.5.6.4 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/tg3_libphy_workaround b/src/patches/suse-2.6.27.31/patches.drivers/tg3_libphy_workaround new file mode 100644 index 000000000..3fb5c7ef6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/tg3_libphy_workaround @@ -0,0 +1,62 @@ +From: Matt Carlson +Subject: tg3 libphy workaround +Reference: bnc#68725 +Acked-by: Karsten Keil + +Hi Philip. Below is the SLES 11 patch that disables 5785 support and +forces the 57780 to use the in-driver phy code rather than the phylib +code. + +While I have your attention, are there any outstanding bootloader +install bugs? On my lab machine, I install SLES 11 onto partition 12 +and tell the installer to install the bootloader (GRUB) into the MBR +of that partition. I then reboot the machine and instruct the existing +bootloader in partition 1 (GRUB again) to chainload to partition 12. + +It seems the SLES 11 installer somehow corrupts the MBR of the disk so +that it no longer boots. I've installed SLES 11 twice now and on the +2nd install, I carefully navigated through the bootloader configuration +portion. I don't think I'm doing anything wrong. Anyways, just an FYI... + + + +diff -Nrup 1/drivers/net/tg3.c 2/drivers/net/tg3.c +--- 1/drivers/net/tg3.c 2009-01-14 15:19:32.000000000 -0800 ++++ 2/drivers/net/tg3.c 2009-01-23 07:06:53.000000000 -0800 +@@ -205,7 +205,6 @@ static struct pci_device_id tg3_pci_tbl[ + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, +- {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, +@@ -12428,8 +12427,7 @@ static int __devinit tg3_get_invariants( + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) + tp->coalesce_mode |= HOSTCC_MODE_32BYTE; + +- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || +- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) ++ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; + + err = tg3_mdio_init(tp); +@@ -13192,6 +13190,7 @@ static char * __devinit tg3_phy_string(s + case PHY_ID_BCM5756: return "5722/5756"; + case PHY_ID_BCM5906: return "5906"; + case PHY_ID_BCM5761: return "5761"; ++ case PHY_ID_BCM57780: return "57780"; + case PHY_ID_BCM8002: return "8002/serdes"; + case 0: return "serdes"; + default: return "unknown"; +diff -Nrup 1/drivers/net/tg3.h 2/drivers/net/tg3.h +--- 1/drivers/net/tg3.h 2009-01-14 15:19:30.000000000 -0800 ++++ 2/drivers/net/tg3.h 2009-01-23 07:04:58.000000000 -0800 +@@ -2586,6 +2586,7 @@ struct tg3 { + #define PHY_ID_BCM5761 0xbc050fd0 + #define PHY_ID_BCM5906 0xdc00ac40 + #define PHY_ID_BCM8002 0x60010140 ++#define PHY_ID_BCM57780 0x5c0d8990 + #define PHY_ID_INVALID 0xffffffff + #define PHY_ID_REV_MASK 0x0000000f + #define PHY_REV_BCM5401_B0 0x1 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/tpm-bcm0102-workaround.patch b/src/patches/suse-2.6.27.31/patches.drivers/tpm-bcm0102-workaround.patch new file mode 100644 index 000000000..25e3e54f0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/tpm-bcm0102-workaround.patch @@ -0,0 +1,47 @@ +From 292cf4a8a989cb564a6a5f0ba7a66e08a095afa1 Mon Sep 17 00:00:00 2001 +From: Valdis Kletnieks +Date: Wed, 15 Oct 2008 22:04:35 -0700 +Subject: [PATCH] tpm: work around bug in Broadcom BCM0102 chipset +Patch-mainline: 2.6.28 +References: bnc#425747 FATE304221 + +Patch tpm-correct-tpm-timeouts-to-jiffies-conversion reveals a bug in the +Broadcom BCM0102 TPM chipset used in the Dell Latitude D820 - although +most of the timeouts are returned in usecs as per the spec, one is +apparently returned in msecs, which results in a too-small value leading +to a timeout when the code treats it as usecs. To prevent a regression, +we check for the known too-short value and adjust it to a value that makes +things work. + +Signed-off-by: Valdis Kletnieks +Cc: Marcin Obara +Cc: Marcel Selhorst +Cc: Kylene Jo Hall +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Jiri Slaby +--- + drivers/char/tpm/tpm.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c +index 6b5a0e0..aa899ce 100644 +--- a/drivers/char/tpm/tpm.c ++++ b/drivers/char/tpm/tpm.c +@@ -557,6 +557,13 @@ duration: + usecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_1_IDX)))); ++ /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above ++ * value wrong and apparently reports msecs rather than usecs. So we ++ * fix up the resulting too-small TPM_SHORT value to make things work. ++ */ ++ if (chip->vendor.duration[TPM_SHORT] < (HZ/100)) ++ chip->vendor.duration[TPM_SHORT] = HZ; ++ + chip->vendor.duration[TPM_MEDIUM] = + usecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/tpm-correct-timeouts.patch b/src/patches/suse-2.6.27.31/patches.drivers/tpm-correct-timeouts.patch new file mode 100644 index 000000000..e5f3f2352 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/tpm-correct-timeouts.patch @@ -0,0 +1,77 @@ +From 9e5b1b12226d5a501fbc6706ca090e00d18a01ad Mon Sep 17 00:00:00 2001 +From: Marcin Obara +Date: Wed, 15 Oct 2008 22:04:34 -0700 +Subject: [PATCH] tpm: correct tpm timeouts to jiffies conversion +Patch-mainline: 2.6.28 +References: bnc#425747 FATE304221 + +This patch fixes timeouts conversion to jiffies, by replacing +msecs_to_jiffies() calls with usecs_to_jiffies(). According to TCG TPM +Specification Version 1.2 Revision 103 (pages 166, 167) TPM timeouts and +durations are returned in microseconds (usec) not in miliseconds (msec). + +This fixes a long hang while loading TPM driver, if TPM chip starts in +"Idle" state instead of "Ready" state. Without this patch - 'modprobe' +may hang for 30 seconds or more. + +Signed-off-by: Marcin Obara +Cc: Marcel Selhorst +Cc: Kylene Jo Hall +Cc: Jiri Slaby +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Jiri Slaby +--- + drivers/char/tpm/tpm.c | 14 +++++++------- + 1 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c +index 1fee703..6b5a0e0 100644 +--- a/drivers/char/tpm/tpm.c ++++ b/drivers/char/tpm/tpm.c +@@ -525,19 +525,19 @@ void tpm_get_timeouts(struct tpm_chip *chip) + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); + if (timeout) +- chip->vendor.timeout_a = msecs_to_jiffies(timeout); ++ chip->vendor.timeout_a = usecs_to_jiffies(timeout); + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); + if (timeout) +- chip->vendor.timeout_b = msecs_to_jiffies(timeout); ++ chip->vendor.timeout_b = usecs_to_jiffies(timeout); + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); + if (timeout) +- chip->vendor.timeout_c = msecs_to_jiffies(timeout); ++ chip->vendor.timeout_c = usecs_to_jiffies(timeout); + timeout = + be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); + if (timeout) +- chip->vendor.timeout_d = msecs_to_jiffies(timeout); ++ chip->vendor.timeout_d = usecs_to_jiffies(timeout); + + duration: + memcpy(data, tpm_cap, sizeof(tpm_cap)); +@@ -554,15 +554,15 @@ duration: + return; + + chip->vendor.duration[TPM_SHORT] = +- msecs_to_jiffies(be32_to_cpu ++ usecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_1_IDX)))); + chip->vendor.duration[TPM_MEDIUM] = +- msecs_to_jiffies(be32_to_cpu ++ usecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_2_IDX)))); + chip->vendor.duration[TPM_LONG] = +- msecs_to_jiffies(be32_to_cpu ++ usecs_to_jiffies(be32_to_cpu + (*((__be32 *) (data + + TPM_GET_CAP_RET_UINT32_3_IDX)))); + } +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/usb-serial-add-qualcomm-wireless-modem-driver.patch b/src/patches/suse-2.6.27.31/patches.drivers/usb-serial-add-qualcomm-wireless-modem-driver.patch new file mode 100644 index 000000000..9417c43e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/usb-serial-add-qualcomm-wireless-modem-driver.patch @@ -0,0 +1,202 @@ +From foo@baz Tue Feb 17 22:39:56 PST 2009 +Date: Tue, 17 Feb 2009 22:39:56 -0800 +To: Greg KH +From: Greg Kroah-Hartman +Subject: USB: serial: add qualcomm wireless modem driver + +Driver originally written by Qualcomm, but rewritten by me due to the +totally different coding style. Cleaned up the probe logic to make a +bit more sense, this is one wierd device. They could have prevented all +of this by just writing sane firmware for the modem. + +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/Kconfig | 9 ++ + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/qcserial.c | 152 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 162 insertions(+) + +--- a/drivers/usb/serial/Kconfig ++++ b/drivers/usb/serial/Kconfig +@@ -472,6 +472,15 @@ config USB_SERIAL_OTI6858 + To compile this driver as a module, choose M here: the + module will be called oti6858. + ++config USB_SERIAL_QUALCOMM ++ tristate "USB Qualcomm Serial modem" ++ help ++ Say Y here if you have a Qualcomm USB modem device. These are ++ usually wireless cellular modems. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called qcserial. ++ + config USB_SERIAL_SPCP8X5 + tristate "USB SPCP8x5 USB To Serial Driver" + help +--- a/drivers/usb/serial/Makefile ++++ b/drivers/usb/serial/Makefile +@@ -44,6 +44,7 @@ obj-$(CONFIG_USB_SERIAL_OMNINET) += omn + obj-$(CONFIG_USB_SERIAL_OPTION) += option.o + obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o + obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o ++obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o + obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o + obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o + obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o +--- /dev/null ++++ b/drivers/usb/serial/qcserial.c +@@ -0,0 +1,152 @@ ++/* ++ * Qualcomm Serial USB driver ++ * ++ * Copyright (c) 2008 QUALCOMM Incorporated. ++ * Copyright (c) 2009 Greg Kroah-Hartman ++ * Copyright (c) 2009 Novell Inc. ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define DRIVER_VERSION "v0.4" ++#define DRIVER_AUTHOR "Qualcomm Inc" ++#define DRIVER_DESC "Qualcomm USB Serial driver" ++ ++#define NUM_BULK_EPS 1 ++#define MAX_BULK_EPS 6 ++ ++static int debug; ++ ++static struct usb_device_id id_table[] = { ++ {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ ++ {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ ++ { } /* Terminating entry */ ++}; ++MODULE_DEVICE_TABLE(usb, id_table); ++ ++static struct usb_driver qcdriver = { ++ .name = "qcserial", ++ .probe = usb_serial_probe, ++ .disconnect = usb_serial_disconnect, ++ .id_table = id_table, ++ .suspend = usb_serial_suspend, ++ .resume = usb_serial_resume, ++ .supports_autosuspend = true, ++}; ++ ++static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) ++{ ++ int retval = -ENODEV; ++ __u8 nintf; ++ __u8 ifnum; ++ ++ dbg("%s", __func__); ++ ++ nintf = serial->dev->actconfig->desc.bNumInterfaces; ++ dbg("Num Interfaces = %d", nintf); ++ ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; ++ dbg("This Interface = %d", ifnum); ++ ++ switch (nintf) { ++ case 1: ++ /* QDL mode */ ++ if (serial->interface->num_altsetting == 2) { ++ struct usb_host_interface *intf; ++ ++ intf = &serial->interface->altsetting[1]; ++ if (intf->desc.bNumEndpoints == 2) { ++ if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && ++ usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { ++ dbg("QDL port found"); ++ retval = usb_set_interface(serial->dev, ifnum, 1); ++ if (retval < 0) { ++ dev_err(&serial->dev->dev, ++ "Could not set interface, error %d\n", ++ retval); ++ retval = -ENODEV; ++ } ++ return retval; ++ } ++ } ++ } ++ break; ++ ++ case 4: ++ /* Composite mode */ ++ if (ifnum == 2) { ++ dbg("Modem port found"); ++ retval = usb_set_interface(serial->dev, ifnum, 0); ++ if (retval < 0) { ++ dev_err(&serial->dev->dev, ++ "Could not set interface, error %d\n", ++ retval); ++ retval = -ENODEV; ++ } ++ return retval; ++ } ++ break; ++ ++ default: ++ dev_err(&serial->dev->dev, ++ "unknown number of interfaces: %d\n", nintf); ++ return -ENODEV; ++ } ++ ++ return retval; ++} ++ ++static struct usb_serial_driver qcdevice = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "qcserial", ++ }, ++ .description = "Qualcomm USB modem", ++ .id_table = id_table, ++ .usb_driver = &qcdriver, ++ .num_ports = 1, ++ .probe = qcprobe, ++}; ++ ++static int __init qcinit(void) ++{ ++ int retval; ++ ++ retval = usb_serial_register(&qcdevice); ++ if (retval) ++ return retval; ++ ++ retval = usb_register(&qcdriver); ++ if (retval) { ++ usb_serial_deregister(&qcdevice); ++ return retval; ++ } ++ ++ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION "\n"); ++ ++ return 0; ++} ++ ++static void __exit qcexit(void) ++{ ++ usb_deregister(&qcdriver); ++ usb_serial_deregister(&qcdevice); ++} ++ ++module_init(qcinit); ++module_exit(qcexit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION(DRIVER_VERSION); ++ ++module_param(debug, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/src/patches/suse-2.6.27.31/patches.drivers/usb-storage-increase-the-bcd-range-in-sony-s-bad-device-table.patch b/src/patches/suse-2.6.27.31/patches.drivers/usb-storage-increase-the-bcd-range-in-sony-s-bad-device-table.patch new file mode 100644 index 000000000..b138bb295 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/usb-storage-increase-the-bcd-range-in-sony-s-bad-device-table.patch @@ -0,0 +1,29 @@ +From foo@baz Tue Aug 18 09:31:28 PDT 2009 +Date: Tue, 18 Aug 2009 09:31:28 -0700 +To: Greg KH +From: Greg Kroah-Hartman +Subject: USB: storage: increase the bcd range in Sony's bad device table. +Patch-mainline: 2.6.32 +References: bnc#466554 + +Another Sony device in the wild is needing this hack. You would think +they would fix their firmware one of these days... + +Cc: Maciej Pilichowski +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/storage/unusual_devs.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -568,7 +568,7 @@ UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + +-UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, ++UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0500, + "Sony", + "DSC-S30/S70/S75/505V/F505/F707/F717/P8", + US_SC_SCSI, US_PR_DEVICE, NULL, diff --git a/src/patches/suse-2.6.27.31/patches.drivers/uvcvideo-ignore-hue-control-for-5986-0241.patch b/src/patches/suse-2.6.27.31/patches.drivers/uvcvideo-ignore-hue-control-for-5986-0241.patch new file mode 100644 index 000000000..030708802 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/uvcvideo-ignore-hue-control-for-5986-0241.patch @@ -0,0 +1,57 @@ +From: Brandon Philips +Subject: uvcvideo: ignore hue control for 5986:0241 +References: bnc#499152 +Patch-mainline: Never? I will submit upstream but there is probably a better fix + +Querying the hue control on Bison 5986:0241 causes the chipset to +lockup. So, create a quirk that will avoid offering V4L2_CID_HUE to user +space. + +Signed-off-by: Brandon Philips + +--- + drivers/media/video/uvc/uvc_ctrl.c | 4 ++++ + drivers/media/video/uvc/uvc_driver.c | 8 ++++++++ + drivers/media/video/uvc/uvcvideo.h | 1 + + 3 files changed, 13 insertions(+) + +--- a/drivers/media/video/uvc/uvc_ctrl.c ++++ b/drivers/media/video/uvc/uvc_ctrl.c +@@ -588,6 +588,10 @@ int uvc_query_v4l2_ctrl(struct uvc_video + __u8 *data; + int ret; + ++ if ((video->dev->quirks & UVC_QUIRK_HUE_EPIPE) && ++ (v4l2_ctrl->id == V4L2_CID_HUE)) ++ return -EINVAL; ++ + ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); + if (ctrl == NULL) + return -EINVAL; +--- a/drivers/media/video/uvc/uvc_driver.c ++++ b/drivers/media/video/uvc/uvc_driver.c +@@ -1948,6 +1948,14 @@ static struct usb_device_id uvc_ids[] = + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, ++ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE ++ | USB_DEVICE_ID_MATCH_INT_INFO, ++ .idVendor = 0x5986, ++ .idProduct = 0x0241, ++ .bInterfaceClass = USB_CLASS_VIDEO, ++ .bInterfaceSubClass = 1, ++ .bInterfaceProtocol = 0, ++ .driver_info = UVC_QUIRK_HUE_EPIPE }, + /* Generic USB Video Class */ + { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, + {} +--- a/drivers/media/video/uvc/uvcvideo.h ++++ b/drivers/media/video/uvc/uvcvideo.h +@@ -314,6 +314,7 @@ struct uvc_xu_control { + #define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 + #define UVC_QUIRK_STREAM_NO_FID 0x00000010 + #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 ++#define UVC_QUIRK_HUE_EPIPE 0x00000100 + + /* Format flags */ + #define UVC_FMT_FLAG_COMPRESSED 0x00000001 diff --git a/src/patches/suse-2.6.27.31/patches.drivers/v4l-dvb-uvcvideo-implement-the-usb-power-management-reset_resume-method.patch b/src/patches/suse-2.6.27.31/patches.drivers/v4l-dvb-uvcvideo-implement-the-usb-power-management-reset_resume-method.patch new file mode 100644 index 000000000..7f17c2aaa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/v4l-dvb-uvcvideo-implement-the-usb-power-management-reset_resume-method.patch @@ -0,0 +1,71 @@ +From 9b0ae867a6fd3035e97e6c33bc07a5bfd7c0f96c Mon Sep 17 00:00:00 2001 +From: Laurent Pinchart +Date: Fri, 22 Aug 2008 17:25:10 -0300 +Subject: [PATCH] V4L/DVB (8754): uvcvideo: Implement the USB power management reset_resume method. +References: bnc#486331 + +When a suspended device has been reset instead of being resumed, USB core +calls the reset_resume method if available instead of unbinding and rebinding +the device. + +This patch implements reset_resume by reusing the current resume +implementation and simplifies the resume method by skipping the controls +restore stage. Resuming from autosuspend should be faster. + +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Brandon Philips +--- + drivers/media/video/uvc/uvc_driver.c | 15 +++++++++++++-- + 1 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c +index 7e10203..4a2d099 100644 +--- a/drivers/media/video/uvc/uvc_driver.c ++++ b/drivers/media/video/uvc/uvc_driver.c +@@ -1663,7 +1663,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) + return uvc_video_suspend(&dev->video); + } + +-static int uvc_resume(struct usb_interface *intf) ++static int __uvc_resume(struct usb_interface *intf, int reset) + { + struct uvc_device *dev = usb_get_intfdata(intf); + int ret; +@@ -1672,7 +1672,7 @@ static int uvc_resume(struct usb_interface *intf) + intf->cur_altsetting->desc.bInterfaceNumber); + + if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) { +- if ((ret = uvc_ctrl_resume_device(dev)) < 0) ++ if (reset && (ret = uvc_ctrl_resume_device(dev)) < 0) + return ret; + + return uvc_status_resume(dev); +@@ -1687,6 +1687,16 @@ static int uvc_resume(struct usb_interface *intf) + return uvc_video_resume(&dev->video); + } + ++static int uvc_resume(struct usb_interface *intf) ++{ ++ return __uvc_resume(intf, 0); ++} ++ ++static int uvc_reset_resume(struct usb_interface *intf) ++{ ++ return __uvc_resume(intf, 1); ++} ++ + /* ------------------------------------------------------------------------ + * Driver initialization and cleanup + */ +@@ -1952,6 +1962,7 @@ struct uvc_driver uvc_driver = { + .disconnect = uvc_disconnect, + .suspend = uvc_suspend, + .resume = uvc_resume, ++ .reset_resume = uvc_reset_resume, + .id_table = uvc_ids, + .supports_autosuspend = 1, + }, +-- +1.6.2 + diff --git a/src/patches/suse-2.6.27.31/patches.drivers/via-unichrome-drm-bugfixes.patch b/src/patches/suse-2.6.27.31/patches.drivers/via-unichrome-drm-bugfixes.patch new file mode 100644 index 000000000..577d5e14e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.drivers/via-unichrome-drm-bugfixes.patch @@ -0,0 +1,919 @@ +From: Bruce Chang +Subject: via: Unichrome DRM bugfixes + +1. Patch the system hang issue caused by multi X support when doing + switch user. +2. Patch system hang issue caused by 3D scaling+ACPI +3. Patch segmentation fault issue caused by playing video with AGP after + resume from suspend. +4. Reverse the wrong modification we did on the in-line source for + coding style only. So ther should no typedef structure... +5. Move private AGP structure into public. +6. Remove the modification we did for bypassing DMA check to improve + performance. + + +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/via/via_dma.c | 341 +++++++++++++++++++++++++++++++++++++++++- + drivers/gpu/drm/via/via_drv.c | 12 + + drivers/gpu/drm/via/via_drv.h | 12 + + drivers/gpu/drm/via/via_map.c | 45 +++++ + drivers/gpu/drm/via/via_mm.c | 137 +++++++++++++++- + include/drm/via_drm.h | 43 +++++ + 6 files changed, 576 insertions(+), 14 deletions(-) + +--- a/drivers/gpu/drm/via/via_dma.c ++++ b/drivers/gpu/drm/via/via_dma.c +@@ -68,6 +68,15 @@ + *vb++ = (w2); \ + dev_priv->dma_low += 8; + ++#define VIA_OUT_VIDEO_AGP_BUFFER(cmd1, cmd2) \ ++ do { \ ++ *cur_virtual++ = cmd1; \ ++ *cur_virtual++ = cmd2; \ ++ cmdbuf_info.cmd_size += 8; \ ++ } while (0); ++ ++static void via_cmdbuf_flush(struct drm_via_private *dev_priv, ++ uint32_t cmd_type); + static void via_cmdbuf_start(drm_via_private_t * dev_priv); + static void via_cmdbuf_pause(drm_via_private_t * dev_priv); + static void via_cmdbuf_reset(drm_via_private_t * dev_priv); +@@ -75,6 +84,7 @@ static void via_cmdbuf_rewind(drm_via_pr + static int via_wait_idle(drm_via_private_t * dev_priv); + static void via_pad_cache(drm_via_private_t * dev_priv, int qwords); + ++ + /* + * Free space in command buffer. + */ +@@ -155,17 +165,35 @@ static inline uint32_t *via_check_dma(dr + + int via_dma_cleanup(struct drm_device * dev) + { ++ struct drm_via_video_save_head *pnode; ++ int i; ++ ++ ++ for (pnode = via_video_save_head; pnode; pnode = ++ (struct drm_via_video_save_head *)pnode->next) ++ memcpy(pnode->psystemmem, pnode->pvideomem, pnode->size); + if (dev->dev_private) { + drm_via_private_t *dev_priv = + (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start) { +- via_cmdbuf_reset(dev_priv); ++ if (dev_priv->cr_status == CR_FOR_RINGBUFFER) ++ via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); ++ ++ via_wait_idle(dev_priv); + + drm_core_ioremapfree(&dev_priv->ring.map, dev); + dev_priv->ring.virtual_start = NULL; + } + ++ for (i = 0; i < 3; i++) { ++ if (dev_priv->video_agp_address_map[i].handle && ++ dev_priv->video_agp_address_map[i].size) ++ drm_core_ioremapfree(dev_priv-> ++ video_agp_address_map+i, dev); ++ /*Fix for suspend reuse video buf*/ ++ dev_priv->video_agp_address_map[i].handle = NULL; ++ } + } + + return 0; +@@ -175,6 +203,7 @@ static int via_initialize(struct drm_dev + drm_via_private_t * dev_priv, + drm_via_dma_init_t * init) + { ++ struct drm_via_video_save_head *pnode; + if (!dev_priv || !dev_priv->mmio) { + DRM_ERROR("via_dma_init called before via_map_init\n"); + return -EFAULT; +@@ -194,6 +223,9 @@ static int via_initialize(struct drm_dev + DRM_ERROR("AGP DMA is not supported on this chip\n"); + return -EINVAL; + } ++ ++ for (pnode = via_video_save_head; pnode; pnode = pnode->next) ++ memcpy(pnode->pvideomem, pnode->psystemmem, pnode->size); + + dev_priv->ring.map.offset = dev->agp->base + init->offset; + dev_priv->ring.map.size = init->size; +@@ -224,6 +256,7 @@ static int via_initialize(struct drm_dev + + via_cmdbuf_start(dev_priv); + ++ dev_priv->cr_status = CR_FOR_RINGBUFFER; + return 0; + } + +@@ -332,12 +365,42 @@ static int via_flush_ioctl(struct drm_de + static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) + { + drm_via_cmdbuffer_t *cmdbuf = data; +- int ret; ++ drm_via_private_t *dev_priv = dev->dev_private; ++ int ret = 0, count; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); + ++ if (dev_priv->cr_status == CR_FOR_VIDEO) { ++ /* Because our driver will hook CR stop cmd behind video cmd, ++ * all we need to do here is to wait for CR idle, ++ * and initialize ring buffer. ++ */ ++ count = 10000000; ++ while (count-- && (VIA_READ(VIA_REG_STATUS) & ++ VIA_CMD_RGTR_BUSY)) ++ cpu_relax(); ++ /* Seldom happen */ ++ if (count < 0) { ++ DRM_INFO("The CR can't be idle from video agp cmd \ ++ dispatch when it is needed by ring buffer \n"); ++ return -1; ++ } ++ /* CR has been idle so that we need to initialize ring buffer */ ++ dev_priv->dma_ptr = dev_priv->ring.virtual_start; ++ dev_priv->dma_low = 0; ++ dev_priv->dma_high = 0x1000000; ++ dev_priv->dma_wrap = 0x1000000; ++ dev_priv->dma_offset = 0x0; ++ dev_priv->last_pause_ptr = NULL; ++ dev_priv->hw_addr_ptr = dev_priv->mmio->handle + 0x418; ++ ++ via_cmdbuf_start(dev_priv); ++ ++ dev_priv->cr_status = CR_FOR_RINGBUFFER; ++ ++ } + ret = via_dispatch_cmdbuffer(dev, cmdbuf); + if (ret) { + return ret; +@@ -346,6 +409,134 @@ static int via_cmdbuffer(struct drm_devi + return 0; + } + ++int via_cmdbuffer_video_agp(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_via_private_t *dev_priv = dev->dev_private; ++ struct drm_via_video_agp_cmd cmdbuf_info; ++ int count; ++ u32 start_addr, start_addr_lo; ++ u32 end_addr, end_addr_lo; ++ u32 pause_addr, pause_addr_hi, pause_addr_lo; ++ u32 *cur_virtual; ++ u32 command; ++ int i = 0; ++ struct drm_map map; ++ ++ LOCK_TEST_WITH_RETURN(dev, file_priv); ++ ++ /* Check whether CR services for ring buffer or for video engine. */ ++ if (dev_priv->cr_status == CR_FOR_RINGBUFFER) { ++ /* Here we need to hook stop cmd in tail of ringbuffer ++ * in order to stop CR, for we will reset start/end/pause ++ * address for fetch cmd from video AGP buffer ++ */ ++ via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); ++ } ++ ++ /* Set CR status here to avoid ring buffer crush in case we ++ * can't initialize CR for video properly ++ */ ++ dev_priv->cr_status = CR_FOR_VIDEO; ++ ++ /* Wait idle since we will reset CR relevant registers. */ ++ count = 10000000; ++ while (count-- && (VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY)) ++ cpu_relax(); ++ ++ /* Seldom happen */ ++ if (count < 0) { ++ DRM_INFO("The CR can't be idle from video agp cmd dispatch \ ++ when it is needed by ring buffer \n"); ++ return -1; ++ } ++ ++ /* Till here, the CR has been idle, all need to here is to initialize ++ * CR START/END/PAUSE address registers according to video AGP buffer ++ * location and size. BE LUCKY!!! ++ */ ++ cmdbuf_info = *(struct drm_via_video_agp_cmd *)data; ++ ++ start_addr = cmdbuf_info.offset + dev->agp->base; ++ end_addr = cmdbuf_info.buffer_size + start_addr; ++ ++ if ((cmdbuf_info.buffer_size & 0xFF) || ++ (start_addr + 2 * 0xFF > end_addr) || ++ start_addr & 0xFF) { ++ DRM_INFO("The video cmd is too large or you didn't set the \ ++ video cmd 2 DWORD alignment. \n"); ++ return -1; ++ } ++ ++ map.offset = start_addr; ++ map.size = cmdbuf_info.buffer_size; ++ map.type = map.flags = map.mtrr = 0; ++ map.handle = 0; ++ ++ for (i = 0; i < 3; i++) { ++ if ((dev_priv->video_agp_address_map[i].offset == map.offset) && ++ (dev_priv->video_agp_address_map[i].size == map.size) && ++ dev_priv->video_agp_address_map[i].handle) { ++ map.handle = dev_priv->video_agp_address_map[i].handle; ++ break; ++ } ++ if (!dev_priv->video_agp_address_map[i].handle) ++ break; ++ } ++ ++ /* Check whether this agp cmd buffer has already been remaped before */ ++ /* case: Never be remaped before */ ++ if (!map.handle) { ++ drm_core_ioremap(&map, dev); ++ if (!map.handle) ++ return -1; ++ /* there is a free hole for filling in this address map */ ++ if (i < 3) ++ dev_priv->video_agp_address_map[i] = map; ++ else { ++ drm_core_ioremapfree(dev_priv->video_agp_address_map, ++ dev); ++ dev_priv->video_agp_address_map[0] = map; ++ } ++ } ++ ++ cur_virtual = map.handle + cmdbuf_info.cmd_size; ++ ++ VIA_OUT_VIDEO_AGP_BUFFER(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) | ++ (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); ++ ++ /* pause register need 0xFF alignment */ ++ do { ++ VIA_OUT_VIDEO_AGP_BUFFER(HC_DUMMY, HC_DUMMY); ++ } while (cmdbuf_info.cmd_size & 0xFF); ++ pause_addr = cmdbuf_info.cmd_size + start_addr - 8; ++ ++ pause_addr_lo = ((HC_SubA_HAGPBpL << 24) | HC_HAGPBpID_STOP | ++ (pause_addr & HC_HAGPBpL_MASK)); ++ pause_addr_hi = ((HC_SubA_HAGPBpH << 24) | (pause_addr >> 24)); ++ start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF)); ++ end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF)); ++ command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) | ++ ((end_addr & 0xff000000) >> 16)); ++ *(cur_virtual-2) = pause_addr_hi; ++ *(cur_virtual-1) = pause_addr_lo; ++ ++ via_flush_write_combine(); ++ ++ VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); ++ VIA_WRITE(VIA_REG_TRANSPACE, command); ++ VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo); ++ VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo); ++ ++ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); ++ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); ++ DRM_WRITEMEMORYBARRIER(); ++ /* fire */ ++ VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); ++ ++ return 0; ++} ++ + static int via_dispatch_pci_cmdbuffer(struct drm_device * dev, + drm_via_cmdbuffer_t * cmd) + { +@@ -735,6 +926,146 @@ static int via_cmdbuf_size(struct drm_de + return ret; + } + ++/*The following functions are for ACPI*/ ++ ++static void initialize3Dengine(drm_via_private_t *dev_priv) ++{ ++ int i = 0; ++ ++ VIA_WRITE(0x43C, 0x00010000); ++ ++ for (i = 0; i <= 0x7D; i++) ++ VIA_WRITE(0x440, (unsigned long) i << 24); ++ ++ VIA_WRITE(0x43C, 0x00020000); ++ ++ for (i = 0; i <= 0x94; i++) ++ VIA_WRITE(0x440, (unsigned long) i << 24); ++ ++ VIA_WRITE(0x440, 0x82400000); ++ VIA_WRITE(0x43C, 0x01020000); ++ ++ for (i = 0; i <= 0x94; i++) ++ VIA_WRITE(0x440, (unsigned long) i << 24); ++ ++ VIA_WRITE(0x440, 0x82400000); ++ VIA_WRITE(0x43C, 0xfe020000); ++ ++ for (i = 0; i <= 0x03; i++) ++ VIA_WRITE(0x440, (unsigned long) i << 24); ++ ++ VIA_WRITE(0x43C, 0x00030000); ++ ++ for (i = 0; i <= 0xff; i++) ++ VIA_WRITE(0x440, 0); ++ ++ VIA_WRITE(0x43C, 0x00100000); ++ VIA_WRITE(0x440, 0x00333004); ++ VIA_WRITE(0x440, 0x10000002); ++ VIA_WRITE(0x440, 0x60000000); ++ VIA_WRITE(0x440, 0x61000000); ++ VIA_WRITE(0x440, 0x62000000); ++ VIA_WRITE(0x440, 0x63000000); ++ VIA_WRITE(0x440, 0x64000000); ++ ++ VIA_WRITE(0x43C, 0x00fe0000); ++ VIA_WRITE(0x440, 0x40008c0f); ++ VIA_WRITE(0x440, 0x44000000); ++ VIA_WRITE(0x440, 0x45080C04); ++ VIA_WRITE(0x440, 0x46800408); ++ VIA_WRITE(0x440, 0x50000000); ++ VIA_WRITE(0x440, 0x51000000); ++ VIA_WRITE(0x440, 0x52000000); ++ VIA_WRITE(0x440, 0x53000000); ++ ++ ++ VIA_WRITE(0x43C, 0x00fe0000); ++ VIA_WRITE(0x440, 0x08000001); ++ VIA_WRITE(0x440, 0x0A000183); ++ VIA_WRITE(0x440, 0x0B00019F); ++ VIA_WRITE(0x440, 0x0C00018B); ++ VIA_WRITE(0x440, 0x0D00019B); ++ VIA_WRITE(0x440, 0x0E000000); ++ VIA_WRITE(0x440, 0x0F000000); ++ VIA_WRITE(0x440, 0x10000000); ++ VIA_WRITE(0x440, 0x11000000); ++ VIA_WRITE(0x440, 0x20000000); ++} ++/* For acpi case, when system resume from suspend or hibernate, ++ * need to re-initialize dma info into HW ++ */ ++int via_drm_resume(struct pci_dev *pci) ++{ ++ struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci); ++ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; ++ struct drm_via_video_save_head *pnode = 0; ++ ++ if (!dev_priv->initialize) ++ return 0; ++ /* when resume, initialize 3d registers */ ++ initialize3Dengine(dev_priv); ++ ++ /* here we need to restore some video memory content */ ++ for (pnode = via_video_save_head; pnode; pnode = pnode->next) ++ memcpy(pnode->pvideomem, pnode->psystemmem, pnode->size); ++ ++ /* if pci path, return */ ++ if (!dev_priv->ring.virtual_start) ++ return 0; ++ ++ dev_priv->dma_ptr = dev_priv->ring.virtual_start; ++ dev_priv->dma_low = 0; ++ dev_priv->dma_high = 0x1000000; ++ dev_priv->dma_wrap = 0x1000000; ++ dev_priv->dma_offset = 0x0; ++ dev_priv->last_pause_ptr = NULL; ++ dev_priv->hw_addr_ptr = dev_priv->mmio->handle + 0x418; ++ ++ via_cmdbuf_start(dev_priv); ++ ++ return 0; ++} ++ ++int via_drm_suspend(struct pci_dev *pci, pm_message_t state) ++{ ++ struct drm_device *dev = (struct drm_device *)pci_get_drvdata(pci); ++ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; ++ ++ struct drm_via_video_save_head *pnode = 0; ++ ++ if (!dev_priv->initialize) ++ return 0; ++ /*here we need to save some video mem information into system memory, ++ to keep the system consistent between suspend *before* and *after* ++ 1.save only necessary */ ++ for (pnode = via_video_save_head; pnode; ++ pnode = (struct drm_via_video_save_head *)pnode->next) ++ memcpy(pnode->psystemmem, pnode->pvideomem, pnode->size); ++ ++ /* Only agp path need to flush the cmd */ ++ if (dev_priv->ring.virtual_start) ++ via_cmdbuf_reset(dev_priv); ++ ++ return 0; ++} ++int via_drm_authmagic(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ return 0; ++} ++ ++int via_drm_init_judge(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_via_private *dev_priv = dev->dev_private; ++ ++ if (dev_priv->initialize) ++ *(int *)data = 1; ++ else ++ *(int *)data = -1; ++ return 0; ++} ++ + struct drm_ioctl_desc via_ioctls[] = { + DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH), +@@ -742,6 +1073,7 @@ struct drm_ioctl_desc via_ioctls[] = { + DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_GET_INFO, via_get_drm_info, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH), +@@ -749,7 +1081,10 @@ struct drm_ioctl_desc via_ioctls[] = { + DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), + DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), +- DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) ++ DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_VIA_AUTH_MAGIC, via_drm_authmagic, 0), ++ DRM_IOCTL_DEF(DRM_VIA_FLUSH_VIDEO, via_cmdbuffer_video_agp, 0), ++ DRM_IOCTL_DEF(DRM_VIA_INIT_JUDGE, via_drm_init_judge, 0) + }; + + int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); +--- a/drivers/gpu/drm/via/via_drv.c ++++ b/drivers/gpu/drm/via/via_drv.c +@@ -37,10 +37,16 @@ static struct pci_device_id pciidlist[] + viadrv_PCI_IDS + }; + ++int via_driver_open(struct drm_device *dev, struct drm_file *priv) ++{ ++ priv->authenticated = 1; ++ return 0; ++} + static struct drm_driver driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | + DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, ++ .open = via_driver_open, + .load = via_driver_load, + .unload = via_driver_unload, + .context_dtor = via_final_context, +@@ -68,8 +74,10 @@ static struct drm_driver driver = { + .fasync = drm_fasync, + }, + .pci_driver = { +- .name = DRIVER_NAME, +- .id_table = pciidlist, ++ .name = DRIVER_NAME, ++ .id_table = pciidlist, ++ .suspend = via_drm_suspend, ++ .resume = via_drm_resume, + }, + + .name = DRIVER_NAME, +--- a/drivers/gpu/drm/via/via_drv.h ++++ b/drivers/gpu/drm/via/via_drv.h +@@ -62,6 +62,7 @@ typedef struct drm_via_private { + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; ++ enum drm_agp_type agptype; + unsigned long agpAddr; + wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS]; + char *dma_ptr; +@@ -93,7 +94,13 @@ typedef struct drm_via_private { + unsigned long vram_offset; + unsigned long agp_offset; + drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; ++ struct drm_map video_agp_address_map[3]; ++ enum { ++ CR_FOR_RINGBUFFER, ++ CR_FOR_VIDEO ++ } cr_status; + uint32_t dma_diff; ++ int initialize; + } drm_via_private_t; + + enum via_family { +@@ -119,6 +126,8 @@ extern int via_mem_free(struct drm_devic + extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv); + extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv); + extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv); ++extern int via_get_drm_info(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); + extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv); + extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv ); + extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv ); +@@ -150,4 +159,7 @@ extern void via_lastclose(struct drm_dev + extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); + extern void via_init_dmablit(struct drm_device *dev); + ++extern int via_drm_resume(struct pci_dev *dev); ++extern int via_drm_suspend(struct pci_dev *dev, pm_message_t state); ++ + #endif +--- a/drivers/gpu/drm/via/via_map.c ++++ b/drivers/gpu/drm/via/via_map.c +@@ -25,6 +25,7 @@ + #include "via_drm.h" + #include "via_drv.h" + ++static int associate; + static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init) + { + drm_via_private_t *dev_priv = dev->dev_private; +@@ -65,12 +66,35 @@ static int via_do_init_map(struct drm_de + via_init_dmablit(dev); + + dev->dev_private = (void *)dev_priv; ++ ++ /* from doing this, we has the stuff in prev data ++ * structure to manage agp ++ */ ++ if (init->agp_type != DISABLED) { ++ dev->agp_buffer_map = drm_core_findmap(dev, init->agp_offset); ++ if (!dev->agp_buffer_map) { ++ DRM_ERROR("failed to find dma buffer region!\n"); ++ return -EINVAL; ++ } ++ if (init->agp_type == AGP_DOUBLE_BUFFER) ++ dev_priv->agptype = AGP_DOUBLE_BUFFER; ++ if (init->agp_type == AGP_RING_BUFFER) ++ dev_priv->agptype = AGP_RING_BUFFER; ++ } else { ++ dev_priv->agptype = DISABLED; ++ dev->agp_buffer_map = 0; ++ } ++ /* end */ ++ dev_priv->initialize = 1; ++ + return 0; + } + + int via_do_cleanup_map(struct drm_device * dev) + { ++ drm_via_private_t *dev_priv = dev->dev_private; + via_dma_cleanup(dev); ++ dev_priv->initialize = 0; + + return 0; + } +@@ -95,6 +119,11 @@ int via_driver_load(struct drm_device *d + { + drm_via_private_t *dev_priv; + int ret = 0; ++ if (!associate) { ++ pci_set_drvdata(dev->pdev, dev); ++ dev->pdev->driver = &dev->driver->pci_driver; ++ associate = 1; ++ } + + dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) +@@ -121,3 +150,19 @@ int via_driver_unload(struct drm_device + + return 0; + } ++int via_get_drm_info(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; ++ struct drm_via_info *info = data; ++ ++ if (!dev_priv->initialize) ++ return -EINVAL; ++ ++ info->RegSize = dev_priv->mmio->size; ++ info->AgpSize = dev->agp_buffer_map->size; ++ info->RegHandle = dev_priv->mmio->offset; ++ info->AgpHandle = dev->agp_buffer_map->offset; ++ ++ return 0; ++} +--- a/drivers/gpu/drm/via/via_mm.c ++++ b/drivers/gpu/drm/via/via_mm.c +@@ -30,6 +30,7 @@ + #include "via_drv.h" + #include "drm_sman.h" + ++struct drm_via_video_save_head *via_video_save_head; + #define VIA_MM_ALIGN_SHIFT 4 + #define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1) + +@@ -56,6 +57,8 @@ int via_agp_init(struct drm_device *dev, + DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size); + return 0; + } ++static void *global_dev; ++static void *global_file_priv; + + int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) + { +@@ -78,6 +81,8 @@ int via_fb_init(struct drm_device *dev, + + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); ++ global_dev = dev; ++ global_file_priv = file_priv; + + return 0; + +@@ -115,6 +120,84 @@ void via_lastclose(struct drm_device *de + mutex_unlock(&dev->struct_mutex); + } + ++static int via_videomem_presave_ok(drm_via_private_t *dev_priv, ++ drm_via_mem_t *mem) ++{ ++ void *pvideomem = 0, *psystemmem = 0; ++ struct drm_via_video_save_head *pnode = 0; ++ ++ if (!mem || !mem->size || (mem->type != VIA_MEM_VIDEO_SAVE)) ++ return 0; ++ ++ /* here the mem->offset is the absolute address, ++ * not the offset within videomem ++ */ ++ pvideomem = (void *)ioremap(dev_priv->fb->offset + mem->offset, ++ mem->size); ++ if (!pvideomem) ++ return 0; ++ ++ psystemmem = kmalloc(mem->size, GFP_KERNEL); ++ if (!psystemmem) { ++ iounmap(pvideomem); ++ return 0; ++ } ++ ++ /* map success, then save this information into ++ * a data structure for later saving usage ++ */ ++ pnode = kmalloc( ++ sizeof(struct drm_via_video_save_head), GFP_KERNEL); ++ if (!pnode) { ++ iounmap(pvideomem); ++ kfree(psystemmem); ++ return 0; ++ } ++ ++ pnode->next = 0; ++ pnode->psystemmem = psystemmem; ++ pnode->pvideomem = pvideomem; ++ pnode->size = mem->size; ++ pnode->token = mem->offset; ++ ++ /* insert this node into list */ ++ if (!via_video_save_head) { ++ via_video_save_head = pnode; ++ } else { ++ pnode->next = via_video_save_head; ++ via_video_save_head = pnode; ++ } ++ ++ return 1; ++} ++ ++static int via_videomem_housekeep_ok(drm_via_mem_t *mem) ++{ ++ struct drm_via_video_save_head **ppnode = 0; ++ struct drm_via_video_save_head *tmpnode = 0; ++ /* if this mem's token match with one node of the list */ ++ for (ppnode = &via_video_save_head; *ppnode; ++ ppnode = (struct drm_via_video_save_head **)(&((*ppnode)->next))) { ++ if ((*ppnode)->token == mem->offset) ++ break; ++ } ++ ++ if (*ppnode == 0) { ++ /* not found, the user may specify the wrong mem node to free */ ++ return 0; ++ } ++ ++ /* delete this node from the list and then ++ *free all the mem to avoid memory leak ++ */ ++ tmpnode = *ppnode; ++ *ppnode = (*ppnode)->next; ++ iounmap(tmpnode->pvideomem); ++ kfree(tmpnode->psystemmem); ++ kfree(tmpnode); ++ ++ return 1; ++} + int via_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) + { +@@ -124,12 +207,13 @@ int via_mem_alloc(struct drm_device *dev + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + unsigned long tmpSize; + +- if (mem->type > VIA_MEM_AGP) { ++ if (mem->type > VIA_MEM_VIDEO_SAVE) { + DRM_ERROR("Unknown memory type allocation\n"); + return -EINVAL; + } + mutex_lock(&dev->struct_mutex); +- if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : ++ if (0 == ((mem->type == VIA_MEM_VIDEO || ++ mem->type == VIA_MEM_VIDEO_SAVE) ? dev_priv->vram_initialized : + dev_priv->agp_initialized)) { + DRM_ERROR + ("Attempt to allocate from uninitialized memory manager.\n"); +@@ -138,15 +222,25 @@ int via_mem_alloc(struct drm_device *dev + } + + tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; +- item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0, +- (unsigned long)file_priv); ++ item = drm_sman_alloc(&dev_priv->sman, ++ (mem->type == VIA_MEM_VIDEO_SAVE ? VIA_MEM_VIDEO : mem->type), ++ tmpSize, 0, (unsigned long)file_priv); + mutex_unlock(&dev->struct_mutex); + if (item) { +- mem->offset = ((mem->type == VIA_MEM_VIDEO) ? +- dev_priv->vram_offset : dev_priv->agp_offset) + +- (item->mm-> +- offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT); ++ mem->offset = ((mem->type == VIA_MEM_VIDEO || ++ mem->type == VIA_MEM_VIDEO_SAVE) ? ++ dev_priv->vram_offset : dev_priv->agp_offset) + ++ (item->mm->offset(item->mm, item->mm_info) << ++ VIA_MM_ALIGN_SHIFT); + mem->index = item->user_hash.key; ++ if (mem->type == VIA_MEM_VIDEO_SAVE) { ++ if (!via_videomem_presave_ok(dev_priv, mem)) { ++ mutex_lock(&dev->struct_mutex); ++ drm_sman_free_key(&dev_priv->sman, mem->index); ++ mutex_unlock(&dev->struct_mutex); ++ retval = -ENOMEM; ++ } ++ } + } else { + mem->offset = 0; + mem->size = 0; +@@ -166,6 +260,10 @@ int via_mem_free(struct drm_device *dev, + + mutex_lock(&dev->struct_mutex); + ret = drm_sman_free_key(&dev_priv->sman, mem->index); ++ if (mem->type == VIA_MEM_VIDEO_SAVE) { ++ if (!via_videomem_housekeep_ok(mem)) ++ ret = -EINVAL; ++ } + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG("free = 0x%lx\n", mem->index); + +@@ -192,3 +290,26 @@ void via_reclaim_buffers_locked(struct d + mutex_unlock(&dev->struct_mutex); + return; + } ++static int via_fb_alloc(drm_via_mem_t *mem) ++{ ++ struct drm_device *dev = global_dev; ++ struct drm_file *file_priv = global_file_priv; ++ ++ if (dev && file_priv) ++ return via_mem_alloc(dev, mem, file_priv); ++ else ++ return -EINVAL; ++} ++EXPORT_SYMBOL(via_fb_alloc); ++ ++static int via_fb_free(drm_via_mem_t *mem) ++{ ++ struct drm_device *dev = global_dev; ++ struct drm_file *file_priv = global_file_priv; ++ ++ if (dev && file_priv) ++ return via_mem_free(dev, mem, file_priv); ++ else ++ return -EINVAL; ++} ++EXPORT_SYMBOL(via_fb_free); +--- a/include/drm/via_drm.h ++++ b/include/drm/via_drm.h +@@ -51,6 +51,12 @@ + #define VIA_LOG_MIN_TEX_REGION_SIZE 16 + #endif + ++struct drm_via_info { ++ unsigned long AgpHandle; ++ unsigned long AgpSize; ++ unsigned long RegHandle; ++ unsigned long RegSize; ++} ; + #define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ + #define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ + #define VIA_UPLOAD_CTX 0x4 +@@ -67,7 +73,7 @@ + #define DRM_VIA_FB_INIT 0x03 + #define DRM_VIA_MAP_INIT 0x04 + #define DRM_VIA_DEC_FUTEX 0x05 +-#define NOT_USED ++#define DRM_VIA_GET_INFO 0x06 + #define DRM_VIA_DMA_INIT 0x07 + #define DRM_VIA_CMDBUFFER 0x08 + #define DRM_VIA_FLUSH 0x09 +@@ -77,6 +83,9 @@ + #define DRM_VIA_WAIT_IRQ 0x0d + #define DRM_VIA_DMA_BLIT 0x0e + #define DRM_VIA_BLIT_SYNC 0x0f ++#define DRM_VIA_AUTH_MAGIC 0x11 ++#define DRM_VIA_FLUSH_VIDEO 0x12 ++#define DRM_VIA_INIT_JUDGE 0x16 + + #define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t) + #define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t) +@@ -84,6 +93,8 @@ + #define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t) + #define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t) + #define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t) ++#define DRM_IOCTL_VIA_GET_INFO DRM_IOR(DRM_COMMAND_BASE + \ ++ DRM_VIA_GET_INFO, struct drm_via_info) + #define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t) + #define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t) + #define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH) +@@ -91,8 +102,14 @@ + #define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \ + drm_via_cmdbuf_size_t) + #define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t) ++#define DRM_IOCTL_VIA_FLUSH_VIDEO DRM_IOW(DRM_COMMAND_BASE + \ ++ DRM_VIA_FLUSH_VIDEO, struct drm_via_video_agp_cmd) + #define DRM_IOCTL_VIA_DMA_BLIT DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_DMA_BLIT, drm_via_dmablit_t) + #define DRM_IOCTL_VIA_BLIT_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_BLIT_SYNC, drm_via_blitsync_t) ++#define DRM_IOCTL_VIA_AUTH_MAGIC DRM_IOW(DRM_COMMAND_BASE + \ ++ DRM_VIA_AUTH_MAGIC, drm_auth_t) ++#define DRM_IOCTL_VIA_INIT_JUDGE DRM_IOR(DRM_COMMAND_BASE + \ ++ DRM_VIA_INIT_JUDGE, int) + + /* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, +@@ -112,6 +129,13 @@ + #define VIA_MEM_SYSTEM 2 + #define VIA_MEM_MIXED 3 + #define VIA_MEM_UNKNOWN 4 ++#define VIA_MEM_VIDEO_SAVE 2 /*For video memory need to be saved in ACPI */ ++ ++enum drm_agp_type { ++ AGP_RING_BUFFER, ++ AGP_DOUBLE_BUFFER, ++ DISABLED ++}; + + typedef struct { + uint32_t offset; +@@ -141,6 +165,8 @@ typedef struct _drm_via_init { + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long agpAddr; ++ unsigned long agp_offset; ++ enum drm_agp_type agp_type; + } drm_via_init_t; + + typedef struct _drm_via_futex { +@@ -245,6 +271,12 @@ typedef union drm_via_irqwait { + struct drm_wait_vblank_reply reply; + } drm_via_irqwait_t; + ++struct drm_via_video_agp_cmd { ++ u32 offset; ++ u32 cmd_size; ++ u32 buffer_size; ++} ; ++ + typedef struct drm_via_blitsync { + uint32_t sync_handle; + unsigned engine; +@@ -272,4 +304,13 @@ typedef struct drm_via_dmablit { + drm_via_blitsync_t sync; + } drm_via_dmablit_t; + ++struct drm_via_video_save_head { ++ void *pvideomem; ++ void *psystemmem; ++ int size; ++ /* token used to identify this video memory */ ++ unsigned long token; ++ void *next; ++} ; ++extern struct drm_via_video_save_head *via_video_save_head; + #endif /* _VIA_DRM_H_ */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0001-md-Relax-minimum-size-restrictions-on-chunk_size.patch b/src/patches/suse-2.6.27.31/patches.fixes/0001-md-Relax-minimum-size-restrictions-on-chunk_size.patch new file mode 100644 index 000000000..41987bb3f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0001-md-Relax-minimum-size-restrictions-on-chunk_size.patch @@ -0,0 +1,82 @@ +From 4bbf3771ca40d0aaec8316d0e7476b16010288e5 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 13 Oct 2008 11:55:12 +1100 +Subject: [PATCH] md: Relax minimum size restrictions on chunk_size. + +Currently, the 'chunk_size' of an array must be at-least PAGE_SIZE. + +This makes moving an array to a machine with a larger PAGE_SIZE, or +changing the kernel to use a larger PAGE_SIZE, can stop an array from +working. + +For RAID10 and RAID4/5/6, this is non-trivial to fix as the resync +process works on whole pages at a time, and assumes them to be wholly +within a stripe. For other raid personalities, this restriction is +not needed at all and can be dropped. + +So remove the test on chunk_size from common can, and add it in just +the places where it is needed: raid10 and raid4/5/6. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 12 +----------- + drivers/md/raid10.c | 5 +++-- + drivers/md/raid5.c | 7 +++++++ + 3 files changed, 11 insertions(+), 13 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -3580,22 +3580,12 @@ static int do_md_run(mddev_t * mddev) + return -EINVAL; + } + /* +- * chunk-size has to be a power of 2 and multiples of PAGE_SIZE ++ * chunk-size has to be a power of 2 + */ + if ( (1 << ffz(~chunk_size)) != chunk_size) { + printk(KERN_ERR "chunk_size of %d not valid\n", chunk_size); + return -EINVAL; + } +- if (chunk_size < PAGE_SIZE) { +- if (mddev->level != 0 && mddev->level != 1) { +- printk(KERN_ERR "too small chunk_size: %d < %ld\n", +- chunk_size, PAGE_SIZE); +- return -EINVAL; +- } else { +- printk(KERN_ERR "too small chunk_size: %d < %ld, but continuing anyway on raid%d. Good luck!\n", +- chunk_size, PAGE_SIZE, mddev->level); +- } +- } + + /* devices must have minimum size of one chunk */ + rdev_for_each(rdev, tmp, mddev) { +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid10.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid10.c +@@ -2025,8 +2025,9 @@ static int run(mddev_t *mddev) + int nc, fc, fo; + sector_t stride, size; + +- if (mddev->chunk_size == 0) { +- printk(KERN_ERR "md/raid10: non-zero chunk size required.\n"); ++ if (mddev->chunk_size < PAGE_SIZE) { ++ printk(KERN_ERR "md/raid10: chunk size must be " ++ "at least PAGE_SIZE(%ld).\n", PAGE_SIZE); + return -EINVAL; + } + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -4010,6 +4010,13 @@ static int run(mddev_t *mddev) + return -EIO; + } + ++ if (mddev->chunk_size < PAGE_SIZE) { ++ printk(KERN_ERR "md/raid5: chunk_size must be at least " ++ "PAGE_SIZE but %d < %ld\n", ++ mddev->chunk_size, PAGE_SIZE); ++ return -EINVAL; ++ } ++ + if (mddev->reshape_position != MaxSector) { + /* Check that we can continue the reshape. + * Currently only disks can change, it must diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0002-md-fix-input-truncation-in-safe_delay_store.patch b/src/patches/suse-2.6.27.31/patches.fixes/0002-md-fix-input-truncation-in-safe_delay_store.patch new file mode 100644 index 000000000..0b8198056 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0002-md-fix-input-truncation-in-safe_delay_store.patch @@ -0,0 +1,43 @@ +From 97ce0a7f9caf9d715cee815a016ee21575f71c95 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Wed, 24 Sep 2008 22:48:19 -0700 +Subject: [PATCH] md: fix input truncation in safe_delay_store() + +safe_delay_store() currently truncates the last character of input since +it tells strlcpy that the buffer can only hold 'len' characters, off by +one. sysfs already null terminates the buffer, so just increase the +last argument to strlcpy. + +Signed-off-by: Dan Williams +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -2454,12 +2454,11 @@ safe_delay_store(mddev_t *mddev, const c + int i; + unsigned long msec; + char buf[30]; +- char *e; ++ + /* remove a period, and count digits after it */ + if (len >= sizeof(buf)) + return -EINVAL; +- strlcpy(buf, cbuf, len); +- buf[len] = 0; ++ strlcpy(buf, cbuf, sizeof(buf)); + for (i=0; i +Date: Fri, 9 Jan 2009 08:31:11 +1100 +Subject: [PATCH] md: don't retry recovery of raid1 that fails due to error on source drive. + +If a raid1 has only one working drive and it has a sector which +gives an error on read, then an attempt to recover onto a spare will +fail, but as the single remaining drive is not removed from the +array, the recovery will be immediately re-attempted, resulting +in an infinite recovery loop. + +So detect this situation and don't retry recovery once an error +on the lone remaining drive is detected. + +Allow recovery to be retried once every time a spare is added +in case the problem wasn't actually a media error. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -1512,6 +1512,9 @@ static int bind_rdev_to_array(mdk_rdev_t + list_add_rcu(&rdev->same_set, &mddev->disks); + bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); + md_integrity_check(rdev, mddev); ++ ++ /* May as well allow recovery to be retried once */ ++ clear_bit(MD_RECOVERY_DISABLED, &mddev->recovery); + return 0; + + fail: diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0004-md-fix-deadlock-when-stopping-arrays.patch b/src/patches/suse-2.6.27.31/patches.fixes/0004-md-fix-deadlock-when-stopping-arrays.patch new file mode 100644 index 000000000..152b7d811 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0004-md-fix-deadlock-when-stopping-arrays.patch @@ -0,0 +1,92 @@ +From 5fd3a17ed456637a224cf4ca82b9ad9d005bc8d4 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Wed, 4 Mar 2009 00:57:25 -0700 +Subject: [PATCH] md: fix deadlock when stopping arrays + +Resolve a deadlock when stopping redundant arrays, i.e. ones that +require a call to sysfs_remove_group when shutdown. The deadlock is +summarized below: + +Thread1 Thread2 +------- ------- +read sysfs attribute stop array + take mddev lock + sysfs_remove_group +sysfs_get_active +wait for mddev lock + wait for active + +Sysrq-w: +-------- +mdmon S 00000017 2212 4163 1 + f1982ea8 00000046 2dcf6b85 00000017 c0b23100 f2f83ed0 c0b23100 f2f8413c + c0b23100 c0b23100 c0b1fb98 f2f8413c 00000000 f2f8413c c0b23100 f2291ecc + 00000002 c0b23100 00000000 00000017 f2f83ed0 f1982eac 00000046 c044d9dd +Call Trace: + [] ? debug_mutex_add_waiter+0x1d/0x58 + [] __mutex_lock_common+0x1d9/0x338 + [] ? __mutex_lock_common+0x1d9/0x338 + [] mutex_lock_interruptible_nested+0x33/0x3a + [] ? mddev_lock+0x14/0x16 + [] mddev_lock+0x14/0x16 + [] md_attr_show+0x2a/0x49 + [] sysfs_read_file+0x93/0xf9 +mdadm D 00000017 2812 4177 1 + f0401d78 00000046 430456f8 00000017 f0401d58 f0401d20 c0b23100 f2da2c4c + c0b23100 c0b23100 c0b1fb98 f2da2c4c 0a10fc36 00000000 c0b23100 f0401d70 + 00000003 c0b23100 00000000 00000017 f2da29e0 00000001 00000002 00000000 +Call Trace: + [] schedule_timeout+0x1b/0x95 + [] ? schedule_timeout+0x1b/0x95 + [] ? wait_for_common+0x34/0xdc + [] ? trace_hardirqs_on_caller+0x18/0x145 + [] ? trace_hardirqs_on+0xb/0xd + [] wait_for_common+0xa0/0xdc + [] ? default_wake_function+0x0/0x12 + [] wait_for_completion+0x17/0x19 + [] sysfs_addrm_finish+0x19f/0x1d1 + [] sysfs_hash_and_remove+0x42/0x55 + [] sysfs_remove_group+0x57/0x86 + [] do_md_stop+0x13a/0x499 + +This has been there for a while, but is easier to trigger now that mdmon +is closely watching sysfs. + +Cc: +Reported-by: Jacek Danecki +Signed-off-by: Dan Williams +Acked-by: NeilBrown +--- + drivers/md/md.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -305,9 +305,14 @@ static inline int mddev_trylock(mddev_t + return mutex_trylock(&mddev->reconfig_mutex); + } + ++static struct attribute_group md_redundancy_group; + static inline void mddev_unlock(mddev_t * mddev) + { + mutex_unlock(&mddev->reconfig_mutex); ++ if (unlikely(mddev->private == &md_redundancy_group)) { ++ sysfs_remove_group(&mddev->kobj, &md_redundancy_group); ++ mddev->private = NULL; ++ } + + md_wakeup_thread(mddev->thread); + } +@@ -3905,10 +3910,9 @@ static int do_md_stop(mddev_t * mddev, i + mddev->queue->merge_bvec_fn = NULL; + mddev->queue->unplug_fn = NULL; + mddev->queue->backing_dev_info.congested_fn = NULL; +- if (mddev->pers->sync_request) +- sysfs_remove_group(&mddev->kobj, &md_redundancy_group); +- + module_put(mddev->pers->owner); ++ if (mddev->pers->sync_request) ++ mddev->private = &md_redundancy_group; + mddev->pers = NULL; + /* tell userspace to handle 'inactive' */ + sysfs_notify(&mddev->kobj, NULL, "array_state"); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0005-md-Fix-is_mddev_idle-test-again.patch b/src/patches/suse-2.6.27.31/patches.fixes/0005-md-Fix-is_mddev_idle-test-again.patch new file mode 100644 index 000000000..bb64290db --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0005-md-Fix-is_mddev_idle-test-again.patch @@ -0,0 +1,72 @@ +From eea1bf384e05b5ab747f8530c4fba9e9e6907fff Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:27:02 +1100 +Subject: [PATCH] md: Fix is_mddev_idle test (again). + +There are two problems with is_mddev_idle. + +1/ sync_io is 'atomic_t' and hence 'int'. curr_events and all the + rest are 'long'. + So if sync_io were to wrap on a 64bit host, the value of + curr_events would go very negative suddenly, and take a very + long time to return to positive. + + So do all calculations as 'int'. That gives us plenty of precision + for what we need. + +2/ To initialise rdev->last_events we simply call is_mddev_idle, on + the assumption that it will make sure that last_events is in a + suitable range. It used to do this, but now it does not. + So now we need to be more explicit about initialisation. + +NOTE: to avoid kabi issues in SLES11, we leave 'last_events' as +long and cast it to (int) where used. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -5582,11 +5582,11 @@ int unregister_md_personality(struct mdk + return 0; + } + +-static int is_mddev_idle(mddev_t *mddev) ++static int is_mddev_idle(mddev_t *mddev, int init) + { + mdk_rdev_t * rdev; + int idle; +- long curr_events; ++ int curr_events; + + idle = 1; + rcu_read_lock(); +@@ -5617,7 +5617,7 @@ static int is_mddev_idle(mddev_t *mddev) + * always make curr_events less than last_events. + * + */ +- if (curr_events - rdev->last_events > 4096) { ++ if (init || curr_events - (int)rdev->last_events > 64) { + rdev->last_events = curr_events; + idle = 0; + } +@@ -5861,7 +5861,7 @@ void md_do_sync(mddev_t *mddev) + "(but not more than %d KB/sec) for %s.\n", + speed_max(mddev), desc); + +- is_mddev_idle(mddev); /* this also initializes IO event counters */ ++ is_mddev_idle(mddev, 1); /* this initializes IO event counters */ + + io_sectors = 0; + for (m = 0; m < SYNC_MARKS; m++) { +@@ -5963,7 +5963,7 @@ void md_do_sync(mddev_t *mddev) + + if (currspeed > speed_min(mddev)) { + if ((currspeed > speed_max(mddev)) || +- !is_mddev_idle(mddev)) { ++ !is_mddev_idle(mddev, 0)) { + msleep(500); + goto repeat; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0006-md-never-clear-bit-from-the-write-intent-bitmap-when.patch b/src/patches/suse-2.6.27.31/patches.fixes/0006-md-never-clear-bit-from-the-write-intent-bitmap-when.patch new file mode 100644 index 000000000..c72552ac8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0006-md-never-clear-bit-from-the-write-intent-bitmap-when.patch @@ -0,0 +1,39 @@ +From d0a4bb492772ce5c4bdfba3744a99ed6f6fb238f Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:27:02 +1100 +Subject: [PATCH] md: never clear bit from the write-intent bitmap when the array is degraded. + +It is safe to clear a bit from the write-intent bitmap for a raid1 +if we know the data has been written to all devices, which is +what the current test does. + +But it is not always safe to update the 'events_cleared' counter in +that case. This is because one request could complete successfully +after some other request has partially failed. + +So simply disable the clearing and updating of events_cleared whenever +the array is degraded. This might end up not clearing some bits that +could safely be cleared, but it is safest approach. + +Note that the bug fixed here did not risk corrupting data by letting +the array get out-of-sync. Rather it meant that when a device is +removed and re-added to the array, it might incorrectly require a full +recovery rather than just recovering based on the bitmap. + +Signed-off-by: NeilBrown +--- + drivers/md/bitmap.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/md/bitmap.c ++++ b/drivers/md/bitmap.c +@@ -1307,6 +1307,9 @@ void bitmap_endwrite(struct bitmap *bitm + PRINTK(KERN_DEBUG "dec write-behind count %d/%d\n", + atomic_read(&bitmap->behind_writes), bitmap->max_write_behind); + } ++ if (bitmap->mddev->degraded) ++ /* Never clear bits or update events_cleared when degraded */ ++ success = 0; + + while (sectors) { + int blocks; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0007-md-write-bitmap-information-to-devices-that-are-unde.patch b/src/patches/suse-2.6.27.31/patches.fixes/0007-md-write-bitmap-information-to-devices-that-are-unde.patch new file mode 100644 index 000000000..f755f89b7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0007-md-write-bitmap-information-to-devices-that-are-unde.patch @@ -0,0 +1,31 @@ +From 355a43e641b948a7b755cb4c2466ec548d5b495f Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:27:02 +1100 +Subject: [PATCH] md: write bitmap information to devices that are undergoing recovery. + +When we add some spares to an array and start recovery, and we have +a bitmap which is stored 'internally' on all devices, we call +bitmap_write_all to make sure the bitmap is correct on the new +device(s). +However that doesn't work as write_sb_page only writes to +'In_sync' devices, and devices undergoing recovery are not +'In_sync' until recovery finishes. + +So extend write_sb_page (actually next_active_rdev) to include devices +that are under recovery. + +Signed-off-by: NeilBrown +--- + drivers/md/bitmap.c | 1 - + 1 file changed, 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/bitmap.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/bitmap.c +@@ -265,7 +265,6 @@ static mdk_rdev_t *next_active_rdev(mdk_ + list_for_each_continue_rcu(pos, &mddev->disks) { + rdev = list_entry(pos, mdk_rdev_t, same_set); + if (rdev->raid_disk >= 0 && +- test_bit(In_sync, &rdev->flags) && + !test_bit(Faulty, &rdev->flags)) { + /* this is a usable devices */ + atomic_inc(&rdev->nr_pending); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0008-md-be-more-consistent-about-setting-WriteMostly-flag.patch b/src/patches/suse-2.6.27.31/patches.fixes/0008-md-be-more-consistent-about-setting-WriteMostly-flag.patch new file mode 100644 index 000000000..390345412 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0008-md-be-more-consistent-about-setting-WriteMostly-flag.patch @@ -0,0 +1,37 @@ +From 575a80fa4f623141e9791e41879d87800fb6d862 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:33:13 +1100 +Subject: [PATCH] md: be more consistent about setting WriteMostly flag when adding a drive to an array + +When a drive is added to an array using ADD_NEW_DISK, there are two +places we can get certain flags from: the metadata on the disk or the +flags passed through the IOCTL. + +For the WriteMostly flag (aka MD_DISK_WRITEMOSTLY) we take the value +from either of those sources depending on if it is set (i.e. we +effectively 'or' the two sources together). + +This makes it awkward to clear, and is at best inconsistent. + +As documented code (in mdadm) requires that setting +MD_DISK_WRITEMOSTLY in the ioctl will be effective, we resolve the +inconsistency by always using the value for this flag from the ioctl, +and ignoring the value on disk. + + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -4351,6 +4351,8 @@ static int add_new_disk(mddev_t * mddev, + clear_bit(In_sync, &rdev->flags); /* just to be sure */ + if (info->state & (1<flags); ++ else ++ clear_bit(WriteMostly, &rdev->flags); + + rdev->raid_disk = -1; + err = bind_rdev_to_array(rdev, mddev); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0009-md-raid5-simplify-interface-for-init_stripe-and-get_.patch b/src/patches/suse-2.6.27.31/patches.fixes/0009-md-raid5-simplify-interface-for-init_stripe-and-get_.patch new file mode 100644 index 000000000..c383dcf28 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0009-md-raid5-simplify-interface-for-init_stripe-and-get_.patch @@ -0,0 +1,159 @@ +From b5663ba405fe3e51176ddb6c91a5e186590c26b5 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:39:38 +1100 +Subject: [PATCH] md/raid5: simplify interface for init_stripe and get_active_stripe + +Rather than passing 'pd_idx' and 'disks' to these functions, just pass +'previous' which tells whether to use the 'previous' or 'current' +geometry during a reshape, and let init_stripe calculate +disks and pd_idx and anything else it might need. + +This is not a substantial simplification and even adds a division. +However we will shortly be adding more complexity to init_stripe +to handle more interesting 'reshape' activities, and without this +change, the interface to these functions would get very complex. + +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 43 ++++++++++++++++++++++--------------------- + 1 file changed, 22 insertions(+), 21 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -276,8 +276,9 @@ static int grow_buffers(struct stripe_he + } + + static void raid5_build_block (struct stripe_head *sh, int i); ++static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks); + +-static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int disks) ++static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) + { + raid5_conf_t *conf = sh->raid_conf; + int i; +@@ -292,11 +293,11 @@ static void init_stripe(struct stripe_he + + remove_hash(sh); + ++ sh->disks = previous ? conf->previous_raid_disks : conf->raid_disks; + sh->sector = sector; +- sh->pd_idx = pd_idx; ++ sh->pd_idx = stripe_to_pdidx(sector, conf, sh->disks); + sh->state = 0; + +- sh->disks = disks; + + for (i = sh->disks; i--; ) { + struct r5dev *dev = &sh->dev[i]; +@@ -332,10 +333,12 @@ static struct stripe_head *__find_stripe + static void unplug_slaves(mddev_t *mddev); + static void raid5_unplug_device(struct request_queue *q); + +-static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks, +- int pd_idx, int noblock) ++static struct stripe_head * ++get_active_stripe(raid5_conf_t *conf, sector_t sector, ++ int previous, int noblock) + { + struct stripe_head *sh; ++ int disks = previous ? conf->previous_raid_disks : conf->raid_disks; + + pr_debug("get_stripe, sector %llu\n", (unsigned long long)sector); + +@@ -363,7 +366,7 @@ static struct stripe_head *get_active_st + ); + conf->inactive_blocked = 0; + } else +- init_stripe(sh, sector, pd_idx, disks); ++ init_stripe(sh, sector, previous); + } else { + if (atomic_read(&sh->count)) { + BUG_ON(!list_empty(&sh->lru)); +@@ -2481,8 +2484,7 @@ static void handle_stripe_expansion(raid + conf->raid_disks - + conf->max_degraded, &dd_idx, + &pd_idx, conf); +- sh2 = get_active_stripe(conf, s, conf->raid_disks, +- pd_idx, 1); ++ sh2 = get_active_stripe(conf, s, 0, 1); + if (sh2 == NULL) + /* so far only the early blocks of this stripe + * have been requested. When later blocks +@@ -3412,8 +3414,10 @@ static int make_request(struct request_q + for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { + DEFINE_WAIT(w); + int disks, data_disks; ++ int previous; + + retry: ++ previous = 0; + prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); + if (likely(conf->expand_progress == MaxSector)) + disks = conf->raid_disks; +@@ -3428,9 +3432,10 @@ static int make_request(struct request_q + */ + spin_lock_irq(&conf->device_lock); + disks = conf->raid_disks; +- if (logical_sector >= conf->expand_progress) ++ if (logical_sector >= conf->expand_progress) { + disks = conf->previous_raid_disks; +- else { ++ previous = 1; ++ } else { + if (logical_sector >= conf->expand_lo) { + spin_unlock_irq(&conf->device_lock); + schedule(); +@@ -3447,7 +3452,8 @@ static int make_request(struct request_q + (unsigned long long)new_sector, + (unsigned long long)logical_sector); + +- sh = get_active_stripe(conf, new_sector, disks, pd_idx, (bi->bi_rw&RWA_MASK)); ++ sh = get_active_stripe(conf, new_sector, previous, ++ (bi->bi_rw&RWA_MASK)); + if (sh) { + if (unlikely(conf->expand_progress != MaxSector)) { + /* expansion might have moved on while waiting for a +@@ -3582,9 +3588,7 @@ static sector_t reshape_request(mddev_t + for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { + int j; + int skipped = 0; +- pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); +- sh = get_active_stripe(conf, sector_nr+i, +- conf->raid_disks, pd_idx, 0); ++ sh = get_active_stripe(conf, sector_nr+i, 0, 0); + set_bit(STRIPE_EXPANDING, &sh->state); + atomic_inc(&conf->reshape_stripes); + /* If any of this stripe is beyond the end of the old +@@ -3632,10 +3636,7 @@ static sector_t reshape_request(mddev_t + if (last_sector >= (mddev->size<<1)) + last_sector = (mddev->size<<1)-1; + while (first_sector <= last_sector) { +- pd_idx = stripe_to_pdidx(first_sector, conf, +- conf->previous_raid_disks); +- sh = get_active_stripe(conf, first_sector, +- conf->previous_raid_disks, pd_idx, 0); ++ sh = get_active_stripe(conf, first_sector, 1, 0); + set_bit(STRIPE_EXPAND_SOURCE, &sh->state); + set_bit(STRIPE_HANDLE, &sh->state); + release_stripe(sh); +@@ -3725,9 +3726,9 @@ static inline sector_t sync_request(mdde + bitmap_cond_end_sync(mddev->bitmap, sector_nr); + + pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks); +- sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1); ++ sh = get_active_stripe(conf, sector_nr, 0, 1); + if (sh == NULL) { +- sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); ++ sh = get_active_stripe(conf, sector_nr, 0, 0); + /* make sure we don't swamp the stripe cache if someone else + * is trying to get access + */ +@@ -3793,7 +3794,7 @@ static int retry_aligned_read(raid5_con + /* already done this stripe */ + continue; + +- sh = get_active_stripe(conf, sector, conf->raid_disks, pd_idx, 1); ++ sh = get_active_stripe(conf, sector, 0, 1); + + if (!sh) { + /* failed to get a stripe - must wait */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0010-md-raid5-change-raid5_compute_sector-and-stripe_to_p.patch b/src/patches/suse-2.6.27.31/patches.fixes/0010-md-raid5-change-raid5_compute_sector-and-stripe_to_p.patch new file mode 100644 index 000000000..257b17fc5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0010-md-raid5-change-raid5_compute_sector-and-stripe_to_p.patch @@ -0,0 +1,212 @@ +From 112bf8970dbdfc00bd4667da5996e57c2ce58066 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:39:38 +1100 +Subject: [PATCH] md/raid5: change raid5_compute_sector and stripe_to_pdidx to take a 'previous' argument + +This similar to the recent change to get_active_stripe. +There is no functional change, just come rearrangement to make +future patches cleaner. + +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 78 +++++++++++++++++++++++------------------------------ + 1 file changed, 34 insertions(+), 44 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -276,7 +276,7 @@ static int grow_buffers(struct stripe_he + } + + static void raid5_build_block (struct stripe_head *sh, int i); +-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks); ++static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous); + + static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) + { +@@ -295,7 +295,7 @@ static void init_stripe(struct stripe_he + + sh->disks = previous ? conf->previous_raid_disks : conf->raid_disks; + sh->sector = sector; +- sh->pd_idx = stripe_to_pdidx(sector, conf, sh->disks); ++ sh->pd_idx = stripe_to_pdidx(sector, conf, previous); + sh->state = 0; + + +@@ -1235,15 +1235,18 @@ static void error(mddev_t *mddev, mdk_rd + * Input: a 'big' sector number, + * Output: index of the data and parity disk, and the sector # in them. + */ +-static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, +- unsigned int data_disks, unsigned int * dd_idx, +- unsigned int * pd_idx, raid5_conf_t *conf) ++static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, ++ int previous, ++ int *dd_idx, int *pd_idx) + { + long stripe; + unsigned long chunk_number; + unsigned int chunk_offset; + sector_t new_sector; + int sectors_per_chunk = conf->chunk_size >> 9; ++ int raid_disks = previous ? conf->previous_raid_disks ++ : conf->raid_disks; ++ int data_disks = raid_disks - conf->max_degraded; + + /* First compute the information on this sector */ + +@@ -1408,7 +1411,9 @@ static sector_t compute_blocknr(struct s + chunk_number = stripe * data_disks + i; + r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset; + +- check = raid5_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); ++ check = raid5_compute_sector (conf, r_sector, ++ (raid_disks != conf->raid_disks), ++ &dummy1, &dummy2); + if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { + printk(KERN_ERR "compute_blocknr: map not correct\n"); + return 0; +@@ -1808,16 +1813,18 @@ static int page_is_zero(struct page *p) + memcmp(a, a+4, STRIPE_SIZE-4)==0); + } + +-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) ++static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous) + { + int sectors_per_chunk = conf->chunk_size >> 9; + int pd_idx, dd_idx; + int chunk_offset = sector_div(stripe, sectors_per_chunk); ++ int disks = previous ? conf->previous_raid_disks : conf->raid_disks; + +- raid5_compute_sector(stripe * (disks - conf->max_degraded) ++ raid5_compute_sector(conf, ++ stripe * (disks - conf->max_degraded) + *sectors_per_chunk + chunk_offset, +- disks, disks - conf->max_degraded, +- &dd_idx, &pd_idx, conf); ++ previous, ++ &dd_idx, &pd_idx); + return pd_idx; + } + +@@ -2480,10 +2487,8 @@ static void handle_stripe_expansion(raid + struct stripe_head *sh2; + + sector_t bn = compute_blocknr(sh, i); +- sector_t s = raid5_compute_sector(bn, conf->raid_disks, +- conf->raid_disks - +- conf->max_degraded, &dd_idx, +- &pd_idx, conf); ++ sector_t s = raid5_compute_sector(conf, bn, 0, ++ &dd_idx, &pd_idx); + sh2 = get_active_stripe(conf, s, 0, 1); + if (sh2 == NULL) + /* so far only the early blocks of this stripe +@@ -2770,8 +2775,7 @@ static bool handle_stripe5(struct stripe + !sh->reconstruct_state) { + /* Need to write out all blocks after computing parity */ + sh->disks = conf->raid_disks; +- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, +- conf->raid_disks); ++ sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0); + schedule_reconstruction5(sh, &s, 1, 1); + } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) { + clear_bit(STRIPE_EXPAND_READY, &sh->state); +@@ -2989,8 +2993,7 @@ static bool handle_stripe6(struct stripe + if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) { + /* Need to write out all blocks after computing P&Q */ + sh->disks = conf->raid_disks; +- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, +- conf->raid_disks); ++ sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0); + compute_parity6(sh, RECONSTRUCT_WRITE); + for (i = conf->raid_disks ; i-- ; ) { + set_bit(R5_LOCKED, &sh->dev[i].flags); +@@ -3262,8 +3265,6 @@ static int chunk_aligned_read(struct req + { + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); +- const unsigned int raid_disks = conf->raid_disks; +- const unsigned int data_disks = raid_disks - conf->max_degraded; + unsigned int dd_idx, pd_idx; + struct bio* align_bi; + mdk_rdev_t *rdev; +@@ -3287,12 +3288,9 @@ static int chunk_aligned_read(struct req + /* + * compute position + */ +- align_bi->bi_sector = raid5_compute_sector(raid_bio->bi_sector, +- raid_disks, +- data_disks, +- &dd_idx, +- &pd_idx, +- conf); ++ align_bi->bi_sector = raid5_compute_sector(conf, raid_bio->bi_sector, ++ 0, ++ &dd_idx, &pd_idx); + + rcu_read_lock(); + rdev = rcu_dereference(conf->disks[dd_idx].rdev); +@@ -3446,8 +3444,9 @@ static int make_request(struct request_q + } + data_disks = disks - conf->max_degraded; + +- new_sector = raid5_compute_sector(logical_sector, disks, data_disks, +- &dd_idx, &pd_idx, conf); ++ new_sector = raid5_compute_sector(conf, logical_sector, ++ previous, ++ &dd_idx, &pd_idx); + pr_debug("raid5: make_request, sector %llu logical %llu\n", + (unsigned long long)new_sector, + (unsigned long long)logical_sector); +@@ -3625,14 +3624,12 @@ static sector_t reshape_request(mddev_t + * block on the destination stripes. + */ + first_sector = +- raid5_compute_sector(sector_nr*(new_data_disks), +- raid_disks, data_disks, +- &dd_idx, &pd_idx, conf); ++ raid5_compute_sector(conf, sector_nr*(new_data_disks), ++ 1, &dd_idx, &pd_idx); + last_sector = +- raid5_compute_sector((sector_nr+conf->chunk_size/512) +- *(new_data_disks) -1, +- raid_disks, data_disks, +- &dd_idx, &pd_idx, conf); ++ raid5_compute_sector(conf, ((sector_nr+conf->chunk_size/512) ++ *(new_data_disks) - 1), ++ 1, &dd_idx, &pd_idx); + if (last_sector >= (mddev->size<<1)) + last_sector = (mddev->size<<1)-1; + while (first_sector <= last_sector) { +@@ -3669,8 +3666,6 @@ static inline sector_t sync_request(mdde + { + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + struct stripe_head *sh; +- int pd_idx; +- int raid_disks = conf->raid_disks; + sector_t max_sector = mddev->size << 1; + int sync_blocks; + int still_degraded = 0; +@@ -3725,7 +3720,6 @@ static inline sector_t sync_request(mdde + + bitmap_cond_end_sync(mddev->bitmap, sector_nr); + +- pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks); + sh = get_active_stripe(conf, sector_nr, 0, 1); + if (sh == NULL) { + sh = get_active_stripe(conf, sector_nr, 0, 0); +@@ -3777,12 +3771,8 @@ static int retry_aligned_read(raid5_con + int handled = 0; + + logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); +- sector = raid5_compute_sector( logical_sector, +- conf->raid_disks, +- conf->raid_disks - conf->max_degraded, +- &dd_idx, +- &pd_idx, +- conf); ++ sector = raid5_compute_sector(conf, logical_sector, ++ 0, &dd_idx, &pd_idx); + last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); + + for (; logical_sector < last_sector; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0011-md-raid6-remove-expectation-that-Q-device-is-immedia.patch b/src/patches/suse-2.6.27.31/patches.fixes/0011-md-raid6-remove-expectation-that-Q-device-is-immedia.patch new file mode 100644 index 000000000..3c53fc605 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0011-md-raid6-remove-expectation-that-Q-device-is-immedia.patch @@ -0,0 +1,526 @@ +From d0dabf7e577411c2bf6b616c751544dc241213d4 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:39:38 +1100 +Subject: [PATCH] md/raid6: remove expectation that Q device is immediately after P device. + +Code currently assumes that the devices in a raid6 stripe are + 0 1 ... N-1 P Q +in some rotated order. We will shortly add new layouts in which +this strict pattern is broken. +So remove this expectation. We still assume that the data disks +are roughly in-order. However P and Q can be inserted anywhere within +that order. + +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 213 ++++++++++++++++++++++++++------------------- + include/linux/raid/raid5.h | 15 +-- + 2 files changed, 133 insertions(+), 95 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -135,12 +135,36 @@ static inline void raid5_set_bi_hw_segme + bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16); + } + ++/* Find first data disk in a raid6 stripe */ ++static inline int raid6_d0(struct stripe_head *sh) ++{ ++ if (sh->qd_idx == sh->disks - 1) ++ return 0; ++ else ++ return sh->qd_idx + 1; ++} + static inline int raid6_next_disk(int disk, int raid_disks) + { + disk++; + return (disk < raid_disks) ? disk : 0; + } + ++/* When walking through the disks in a raid5, starting at raid6_d0, ++ * We need to map each disk to a 'slot', where the data disks are slot ++ * 0 .. raid_disks-3, the parity disk is raid_disks-2 and the Q disk ++ * is raid_disks-1. This help does that mapping. ++ */ ++static int raid6_idx_to_slot(int idx, struct stripe_head *sh, int *count) ++{ ++ int slot; ++ if (idx == sh->pd_idx) ++ return sh->disks - 2; ++ if (idx == sh->qd_idx) ++ return sh->disks - 1; ++ slot = (*count)++; ++ return slot; ++} ++ + static void return_io(struct bio *return_bi) + { + struct bio *bi = return_bi; +@@ -198,6 +222,7 @@ static void __release_stripe(raid5_conf_ + } + } + } ++ + static void release_stripe(struct stripe_head *sh) + { + raid5_conf_t *conf = sh->raid_conf; +@@ -276,12 +301,14 @@ static int grow_buffers(struct stripe_he + } + + static void raid5_build_block (struct stripe_head *sh, int i); +-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous); ++static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous, ++ int *qd_idx); + + static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) + { + raid5_conf_t *conf = sh->raid_conf; + int i; ++ int qd_idx; + + BUG_ON(atomic_read(&sh->count) != 0); + BUG_ON(test_bit(STRIPE_HANDLE, &sh->state)); +@@ -295,7 +322,8 @@ static void init_stripe(struct stripe_he + + sh->disks = previous ? conf->previous_raid_disks : conf->raid_disks; + sh->sector = sector; +- sh->pd_idx = stripe_to_pdidx(sector, conf, previous); ++ sh->pd_idx = stripe_to_pdidx(sector, conf, previous, &qd_idx); ++ sh->qd_idx = qd_idx; + sh->state = 0; + + +@@ -1237,7 +1265,7 @@ static void error(mddev_t *mddev, mdk_rd + */ + static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, + int previous, +- int *dd_idx, int *pd_idx) ++ int *dd_idx, int *pd_idx, int *qd_idx) + { + long stripe; + unsigned long chunk_number; +@@ -1270,6 +1298,7 @@ static sector_t raid5_compute_sector(rai + /* + * Select the parity disk based on the user selected algorithm. + */ ++ *qd_idx = ~0; + switch(conf->level) { + case 4: + *pd_idx = data_disks; +@@ -1305,24 +1334,30 @@ static sector_t raid5_compute_sector(rai + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: + *pd_idx = raid_disks - 1 - (stripe % raid_disks); +- if (*pd_idx == raid_disks-1) ++ *qd_idx = *pd_idx + 1; ++ if (*pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ +- else if (*dd_idx >= *pd_idx) ++ *qd_idx = 0; ++ } else if (*dd_idx >= *pd_idx) + (*dd_idx) += 2; /* D D P Q D */ + break; + case ALGORITHM_RIGHT_ASYMMETRIC: + *pd_idx = stripe % raid_disks; +- if (*pd_idx == raid_disks-1) ++ *qd_idx = *pd_idx + 1; ++ if (*pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ +- else if (*dd_idx >= *pd_idx) ++ *qd_idx = 0; ++ } else if (*dd_idx >= *pd_idx) + (*dd_idx) += 2; /* D D P Q D */ + break; + case ALGORITHM_LEFT_SYMMETRIC: + *pd_idx = raid_disks - 1 - (stripe % raid_disks); ++ *qd_idx = (*pd_idx + 1) % raid_disks; + *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; + break; + case ALGORITHM_RIGHT_SYMMETRIC: + *pd_idx = stripe % raid_disks; ++ *qd_idx = (*pd_idx + 1) % raid_disks; + *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; + break; + default: +@@ -1349,7 +1384,7 @@ static sector_t compute_blocknr(struct s + int sectors_per_chunk = conf->chunk_size >> 9; + sector_t stripe; + int chunk_offset; +- int chunk_number, dummy1, dummy2, dd_idx = i; ++ int chunk_number, dummy1, dummy2, dummy3, dd_idx = i; + sector_t r_sector; + + +@@ -1380,7 +1415,7 @@ static sector_t compute_blocknr(struct s + } + break; + case 6: +- if (i == raid6_next_disk(sh->pd_idx, raid_disks)) ++ if (i == sh->qd_idx) + return 0; /* It is the Q disk */ + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: +@@ -1413,7 +1448,7 @@ static sector_t compute_blocknr(struct s + + check = raid5_compute_sector (conf, r_sector, + (raid_disks != conf->raid_disks), +- &dummy1, &dummy2); ++ &dummy1, &dummy2, &dummy3); + if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { + printk(KERN_ERR "compute_blocknr: map not correct\n"); + return 0; +@@ -1482,13 +1517,14 @@ static void copy_data(int frombio, struc + static void compute_parity6(struct stripe_head *sh, int method) + { + raid6_conf_t *conf = sh->raid_conf; +- int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = sh->disks, count; ++ int i, pd_idx, qd_idx, d0_idx, disks = sh->disks, count; + struct bio *chosen; + /**** FIX THIS: This could be very bad if disks is close to 256 ****/ + void *ptrs[disks]; + +- qd_idx = raid6_next_disk(pd_idx, disks); +- d0_idx = raid6_next_disk(qd_idx, disks); ++ pd_idx = sh->pd_idx; ++ qd_idx = sh->qd_idx; ++ d0_idx = raid6_d0(sh); + + pr_debug("compute_parity, stripe %llu, method %d\n", + (unsigned long long)sh->sector, method); +@@ -1526,22 +1562,22 @@ static void compute_parity6(struct strip + set_bit(R5_UPTODATE, &sh->dev[i].flags); + } + +-// switch(method) { +-// case RECONSTRUCT_WRITE: +-// case CHECK_PARITY: +-// case UPDATE_PARITY: +- /* Note that unlike RAID-5, the ordering of the disks matters greatly. */ +- /* FIX: Is this ordering of drives even remotely optimal? */ +- count = 0; +- i = d0_idx; +- do { +- ptrs[count++] = page_address(sh->dev[i].page); +- if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags)) +- printk("block %d/%d not uptodate on parity calc\n", i,count); +- i = raid6_next_disk(i, disks); +- } while ( i != d0_idx ); +-// break; +-// } ++ /* Note that unlike RAID-5, the ordering of the disks matters greatly.*/ ++ /* FIX: Is this ordering of drives even remotely optimal? */ ++ count = 0; ++ i = d0_idx; ++ do { ++ int slot = raid6_idx_to_slot(i, sh, &count); ++ ptrs[slot] = page_address(sh->dev[i].page); ++ if (slot < sh->disks - 2 && ++ !test_bit(R5_UPTODATE, &sh->dev[i].flags)) { ++ printk(KERN_ERR "block %d/%d not uptodate " ++ "on parity calc\n", i, count); ++ BUG(); ++ } ++ i = raid6_next_disk(i, disks); ++ } while (i != d0_idx); ++ BUG_ON(count+2 != disks); + + raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); + +@@ -1565,8 +1601,7 @@ static void compute_block_1(struct strip + { + int i, count, disks = sh->disks; + void *ptr[MAX_XOR_BLOCKS], *dest, *p; +- int pd_idx = sh->pd_idx; +- int qd_idx = raid6_next_disk(pd_idx, disks); ++ int qd_idx = sh->qd_idx; + + pr_debug("compute_block_1, stripe %llu, idx %d\n", + (unsigned long long)sh->sector, dd_idx); +@@ -1602,21 +1637,31 @@ static void compute_block_1(struct strip + static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) + { + int i, count, disks = sh->disks; +- int pd_idx = sh->pd_idx; +- int qd_idx = raid6_next_disk(pd_idx, disks); +- int d0_idx = raid6_next_disk(qd_idx, disks); +- int faila, failb; +- +- /* faila and failb are disk numbers relative to d0_idx */ +- /* pd_idx become disks-2 and qd_idx become disks-1 */ +- faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx; +- failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx; ++ int d0_idx = raid6_d0(sh); ++ int faila = -1, failb = -1; ++ /**** FIX THIS: This could be very bad if disks is close to 256 ****/ ++ void *ptrs[disks]; ++ ++ count = 0; ++ i = d0_idx; ++ do { ++ int slot; ++ slot = raid6_idx_to_slot(i, sh, &count); ++ ptrs[slot] = page_address(sh->dev[i].page); ++ if (i == dd_idx1) ++ faila = slot; ++ if (i == dd_idx2) ++ failb = slot; ++ i = raid6_next_disk(i, disks); ++ } while (i != d0_idx); ++ BUG_ON(count+2 != disks); + + BUG_ON(faila == failb); + if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } + + pr_debug("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n", +- (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb); ++ (unsigned long long)sh->sector, dd_idx1, dd_idx2, ++ faila, failb); + + if ( failb == disks-1 ) { + /* Q disk is one of the missing disks */ +@@ -1626,39 +1671,26 @@ static void compute_block_2(struct strip + return; + } else { + /* We're missing D+Q; recompute D from P */ +- compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0); ++ compute_block_1(sh, ((dd_idx1 == sh->qd_idx) ? ++ dd_idx2 : dd_idx1), ++ 0); + compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */ + return; + } + } + +- /* We're missing D+P or D+D; build pointer table */ +- { +- /**** FIX THIS: This could be very bad if disks is close to 256 ****/ +- void *ptrs[disks]; +- +- count = 0; +- i = d0_idx; +- do { +- ptrs[count++] = page_address(sh->dev[i].page); +- i = raid6_next_disk(i, disks); +- if (i != dd_idx1 && i != dd_idx2 && +- !test_bit(R5_UPTODATE, &sh->dev[i].flags)) +- printk("compute_2 with missing block %d/%d\n", count, i); +- } while ( i != d0_idx ); +- +- if ( failb == disks-2 ) { +- /* We're missing D+P. */ +- raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); +- } else { +- /* We're missing D+D. */ +- raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); +- } +- +- /* Both the above update both missing blocks */ +- set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); +- set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); ++ /* We're missing D+P or D+D; */ ++ if (failb == disks-2) { ++ /* We're missing D+P. */ ++ raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); ++ } else { ++ /* We're missing D+D. */ ++ raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); + } ++ ++ /* Both the above update both missing blocks */ ++ set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); ++ set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); + } + + static void +@@ -1813,7 +1845,8 @@ static int page_is_zero(struct page *p) + memcmp(a, a+4, STRIPE_SIZE-4)==0); + } + +-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous) ++static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous, ++ int *qd_idxp) + { + int sectors_per_chunk = conf->chunk_size >> 9; + int pd_idx, dd_idx; +@@ -1824,7 +1857,7 @@ static int stripe_to_pdidx(sector_t stri + stripe * (disks - conf->max_degraded) + *sectors_per_chunk + chunk_offset, + previous, +- &dd_idx, &pd_idx); ++ &dd_idx, &pd_idx, qd_idxp); + return pd_idx; + } + +@@ -2483,12 +2516,13 @@ static void handle_stripe_expansion(raid + clear_bit(STRIPE_EXPAND_SOURCE, &sh->state); + for (i = 0; i < sh->disks; i++) + if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) { +- int dd_idx, pd_idx, j; ++ int dd_idx, pd_idx, qd_idx, j; + struct stripe_head *sh2; + + sector_t bn = compute_blocknr(sh, i); +- sector_t s = raid5_compute_sector(conf, bn, 0, +- &dd_idx, &pd_idx); ++ sector_t s = ++ raid5_compute_sector(conf, bn, 0, ++ &dd_idx, &pd_idx, &qd_idx); + sh2 = get_active_stripe(conf, s, 0, 1); + if (sh2 == NULL) + /* so far only the early blocks of this stripe +@@ -2512,8 +2546,7 @@ static void handle_stripe_expansion(raid + set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags); + for (j = 0; j < conf->raid_disks; j++) + if (j != sh2->pd_idx && +- (!r6s || j != raid6_next_disk(sh2->pd_idx, +- sh2->disks)) && ++ (!r6s || j != sh2->qd_idx) && + !test_bit(R5_Expanded, &sh2->dev[j].flags)) + break; + if (j == conf->raid_disks) { +@@ -2773,9 +2806,11 @@ static bool handle_stripe5(struct stripe + + if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) && + !sh->reconstruct_state) { ++ int qd_idx; + /* Need to write out all blocks after computing parity */ + sh->disks = conf->raid_disks; +- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0); ++ sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0, &qd_idx); ++ sh->qd_idx = qd_idx; + schedule_reconstruction5(sh, &s, 1, 1); + } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) { + clear_bit(STRIPE_EXPAND_READY, &sh->state); +@@ -2816,7 +2851,7 @@ static bool handle_stripe6(struct stripe + struct r5dev *dev, *pdev, *qdev; + mdk_rdev_t *blocked_rdev = NULL; + +- r6s.qd_idx = raid6_next_disk(pd_idx, disks); ++ r6s.qd_idx = sh->qd_idx; + pr_debug("handling stripe %llu, state=%#lx cnt=%d, " + "pd_idx=%d, qd_idx=%d\n", + (unsigned long long)sh->sector, sh->state, +@@ -2992,8 +3027,10 @@ static bool handle_stripe6(struct stripe + + if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) { + /* Need to write out all blocks after computing P&Q */ ++ int qd_idx; + sh->disks = conf->raid_disks; +- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0); ++ sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0, &qd_idx); ++ sh->qd_idx = qd_idx; + compute_parity6(sh, RECONSTRUCT_WRITE); + for (i = conf->raid_disks ; i-- ; ) { + set_bit(R5_LOCKED, &sh->dev[i].flags); +@@ -3265,7 +3302,7 @@ static int chunk_aligned_read(struct req + { + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); +- unsigned int dd_idx, pd_idx; ++ unsigned int dd_idx, pd_idx, qd_idx; + struct bio* align_bi; + mdk_rdev_t *rdev; + +@@ -3290,7 +3327,7 @@ static int chunk_aligned_read(struct req + */ + align_bi->bi_sector = raid5_compute_sector(conf, raid_bio->bi_sector, + 0, +- &dd_idx, &pd_idx); ++ &dd_idx, &pd_idx, &qd_idx); + + rcu_read_lock(); + rdev = rcu_dereference(conf->disks[dd_idx].rdev); +@@ -3382,7 +3419,7 @@ static int make_request(struct request_q + { + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); +- unsigned int dd_idx, pd_idx; ++ int dd_idx, pd_idx, qd_idx; + sector_t new_sector; + sector_t logical_sector, last_sector; + struct stripe_head *sh; +@@ -3446,7 +3483,7 @@ static int make_request(struct request_q + + new_sector = raid5_compute_sector(conf, logical_sector, + previous, +- &dd_idx, &pd_idx); ++ &dd_idx, &pd_idx, &qd_idx); + pr_debug("raid5: make_request, sector %llu logical %llu\n", + (unsigned long long)new_sector, + (unsigned long long)logical_sector); +@@ -3535,7 +3572,7 @@ static sector_t reshape_request(mddev_t + */ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + struct stripe_head *sh; +- int pd_idx; ++ int pd_idx, qd_idx; + sector_t first_sector, last_sector; + int raid_disks = conf->previous_raid_disks; + int data_disks = raid_disks - conf->max_degraded; +@@ -3598,7 +3635,7 @@ static sector_t reshape_request(mddev_t + if (j == sh->pd_idx) + continue; + if (conf->level == 6 && +- j == raid6_next_disk(sh->pd_idx, sh->disks)) ++ j == sh->qd_idx) + continue; + s = compute_blocknr(sh, j); + if (s < mddev->array_sectors) { +@@ -3625,11 +3662,11 @@ static sector_t reshape_request(mddev_t + */ + first_sector = + raid5_compute_sector(conf, sector_nr*(new_data_disks), +- 1, &dd_idx, &pd_idx); ++ 1, &dd_idx, &pd_idx, &qd_idx); + last_sector = + raid5_compute_sector(conf, ((sector_nr+conf->chunk_size/512) + *(new_data_disks) - 1), +- 1, &dd_idx, &pd_idx); ++ 1, &dd_idx, &pd_idx, &qd_idx); + if (last_sector >= (mddev->size<<1)) + last_sector = (mddev->size<<1)-1; + while (first_sector <= last_sector) { +@@ -3764,7 +3801,7 @@ static int retry_aligned_read(raid5_con + * it will be only one 'dd_idx' and only need one call to raid5_compute_sector. + */ + struct stripe_head *sh; +- int dd_idx, pd_idx; ++ int dd_idx, pd_idx, qd_idx; + sector_t sector, logical_sector, last_sector; + int scnt = 0; + int remaining; +@@ -3772,7 +3809,7 @@ static int retry_aligned_read(raid5_con + + logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + sector = raid5_compute_sector(conf, logical_sector, +- 0, &dd_idx, &pd_idx); ++ 0, &dd_idx, &pd_idx, &qd_idx); + last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); + + for (; logical_sector < last_sector; +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/raid5.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/raid5.h +@@ -197,15 +197,16 @@ enum reconstruct_states { + + struct stripe_head { + struct hlist_node hash; +- struct list_head lru; /* inactive_list or handle_list */ +- struct raid5_private_data *raid_conf; +- sector_t sector; /* sector of this row */ +- int pd_idx; /* parity disk index */ +- unsigned long state; /* state flags */ +- atomic_t count; /* nr of active thread/requests */ ++ struct list_head lru; /* inactive_list or handle_list */ ++ struct raid5_private_data *raid_conf; ++ sector_t sector; /* sector of this row */ ++ short pd_idx; /* parity disk index */ ++ short qd_idx; /* 'Q' disk index for raid6 */ ++ unsigned long state; /* state flags */ ++ atomic_t count; /* nr of active thread/requests */ + spinlock_t lock; + int bm_seq; /* sequence number for bitmap flushes */ +- int disks; /* disks in stripe */ ++ int disks; /* disks in stripe */ + enum check_states check_state; + enum reconstruct_states reconstruct_state; + /* stripe_operations diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0012-md-raid5-simplify-raid5_compute_sector-interface.patch b/src/patches/suse-2.6.27.31/patches.fixes/0012-md-raid5-simplify-raid5_compute_sector-interface.patch new file mode 100644 index 000000000..97e617f2f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0012-md-raid5-simplify-raid5_compute_sector-interface.patch @@ -0,0 +1,326 @@ +From 911d4ee8536d89ea8a6cd3e96b1c95a3ebc5ea66 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:39:38 +1100 +Subject: [PATCH] md/raid5: simplify raid5_compute_sector interface + +Rather than passing 'pd_idx' and 'qd_idx' to be filled in, pass +a 'struct stripe_head *' and fill in the relevant fields. This is +more extensible. + +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 118 ++++++++++++++++++++++++++--------------------------- + 1 file changed, 58 insertions(+), 60 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -301,14 +301,13 @@ static int grow_buffers(struct stripe_he + } + + static void raid5_build_block (struct stripe_head *sh, int i); +-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous, +- int *qd_idx); ++static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous, ++ struct stripe_head *sh); + + static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) + { + raid5_conf_t *conf = sh->raid_conf; + int i; +- int qd_idx; + + BUG_ON(atomic_read(&sh->count) != 0); + BUG_ON(test_bit(STRIPE_HANDLE, &sh->state)); +@@ -322,8 +321,7 @@ static void init_stripe(struct stripe_he + + sh->disks = previous ? conf->previous_raid_disks : conf->raid_disks; + sh->sector = sector; +- sh->pd_idx = stripe_to_pdidx(sector, conf, previous, &qd_idx); +- sh->qd_idx = qd_idx; ++ stripe_set_idx(sector, conf, previous, sh); + sh->state = 0; + + +@@ -1264,12 +1262,13 @@ static void error(mddev_t *mddev, mdk_rd + * Output: index of the data and parity disk, and the sector # in them. + */ + static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, +- int previous, +- int *dd_idx, int *pd_idx, int *qd_idx) ++ int previous, int *dd_idx, ++ struct stripe_head *sh) + { + long stripe; + unsigned long chunk_number; + unsigned int chunk_offset; ++ int pd_idx, qd_idx; + sector_t new_sector; + int sectors_per_chunk = conf->chunk_size >> 9; + int raid_disks = previous ? conf->previous_raid_disks +@@ -1298,30 +1297,30 @@ static sector_t raid5_compute_sector(rai + /* + * Select the parity disk based on the user selected algorithm. + */ +- *qd_idx = ~0; ++ pd_idx = qd_idx = ~0; + switch(conf->level) { + case 4: +- *pd_idx = data_disks; ++ pd_idx = data_disks; + break; + case 5: + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: +- *pd_idx = data_disks - stripe % raid_disks; +- if (*dd_idx >= *pd_idx) ++ pd_idx = data_disks - stripe % raid_disks; ++ if (*dd_idx >= pd_idx) + (*dd_idx)++; + break; + case ALGORITHM_RIGHT_ASYMMETRIC: +- *pd_idx = stripe % raid_disks; +- if (*dd_idx >= *pd_idx) ++ pd_idx = stripe % raid_disks; ++ if (*dd_idx >= pd_idx) + (*dd_idx)++; + break; + case ALGORITHM_LEFT_SYMMETRIC: +- *pd_idx = data_disks - stripe % raid_disks; +- *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; ++ pd_idx = data_disks - stripe % raid_disks; ++ *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; + break; + case ALGORITHM_RIGHT_SYMMETRIC: +- *pd_idx = stripe % raid_disks; +- *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; ++ pd_idx = stripe % raid_disks; ++ *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; + break; + default: + printk(KERN_ERR "raid5: unsupported algorithm %d\n", +@@ -1333,32 +1332,32 @@ static sector_t raid5_compute_sector(rai + /**** FIX THIS ****/ + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: +- *pd_idx = raid_disks - 1 - (stripe % raid_disks); +- *qd_idx = *pd_idx + 1; +- if (*pd_idx == raid_disks-1) { ++ pd_idx = raid_disks - 1 - (stripe % raid_disks); ++ qd_idx = pd_idx + 1; ++ if (pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ +- *qd_idx = 0; +- } else if (*dd_idx >= *pd_idx) ++ qd_idx = 0; ++ } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ + break; + case ALGORITHM_RIGHT_ASYMMETRIC: +- *pd_idx = stripe % raid_disks; +- *qd_idx = *pd_idx + 1; +- if (*pd_idx == raid_disks-1) { ++ pd_idx = stripe % raid_disks; ++ qd_idx = pd_idx + 1; ++ if (pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ +- *qd_idx = 0; +- } else if (*dd_idx >= *pd_idx) ++ qd_idx = 0; ++ } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ + break; + case ALGORITHM_LEFT_SYMMETRIC: +- *pd_idx = raid_disks - 1 - (stripe % raid_disks); +- *qd_idx = (*pd_idx + 1) % raid_disks; +- *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; ++ pd_idx = raid_disks - 1 - (stripe % raid_disks); ++ qd_idx = (pd_idx + 1) % raid_disks; ++ *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; + break; + case ALGORITHM_RIGHT_SYMMETRIC: +- *pd_idx = stripe % raid_disks; +- *qd_idx = (*pd_idx + 1) % raid_disks; +- *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; ++ pd_idx = stripe % raid_disks; ++ qd_idx = (pd_idx + 1) % raid_disks; ++ *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; + break; + default: + printk (KERN_CRIT "raid6: unsupported algorithm %d\n", +@@ -1367,6 +1366,10 @@ static sector_t raid5_compute_sector(rai + break; + } + ++ if (sh) { ++ sh->pd_idx = pd_idx; ++ sh->qd_idx = qd_idx; ++ } + /* + * Finally, compute the new sector number + */ +@@ -1384,8 +1387,9 @@ static sector_t compute_blocknr(struct s + int sectors_per_chunk = conf->chunk_size >> 9; + sector_t stripe; + int chunk_offset; +- int chunk_number, dummy1, dummy2, dummy3, dd_idx = i; ++ int chunk_number, dummy1, dd_idx = i; + sector_t r_sector; ++ struct stripe_head sh2; + + + chunk_offset = sector_div(new_sector, sectors_per_chunk); +@@ -1448,8 +1452,9 @@ static sector_t compute_blocknr(struct s + + check = raid5_compute_sector (conf, r_sector, + (raid_disks != conf->raid_disks), +- &dummy1, &dummy2, &dummy3); +- if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { ++ &dummy1, &sh2); ++ if (check != sh->sector || dummy1 != dd_idx || sh2.pd_idx != sh->pd_idx ++ || sh2.qd_idx != sh->qd_idx) { + printk(KERN_ERR "compute_blocknr: map not correct\n"); + return 0; + } +@@ -1845,11 +1850,11 @@ static int page_is_zero(struct page *p) + memcmp(a, a+4, STRIPE_SIZE-4)==0); + } + +-static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int previous, +- int *qd_idxp) ++static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous, ++ struct stripe_head *sh) + { + int sectors_per_chunk = conf->chunk_size >> 9; +- int pd_idx, dd_idx; ++ int dd_idx; + int chunk_offset = sector_div(stripe, sectors_per_chunk); + int disks = previous ? conf->previous_raid_disks : conf->raid_disks; + +@@ -1857,8 +1862,7 @@ static int stripe_to_pdidx(sector_t stri + stripe * (disks - conf->max_degraded) + *sectors_per_chunk + chunk_offset, + previous, +- &dd_idx, &pd_idx, qd_idxp); +- return pd_idx; ++ &dd_idx, sh); + } + + static void +@@ -2516,13 +2520,12 @@ static void handle_stripe_expansion(raid + clear_bit(STRIPE_EXPAND_SOURCE, &sh->state); + for (i = 0; i < sh->disks; i++) + if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) { +- int dd_idx, pd_idx, qd_idx, j; ++ int dd_idx, j; + struct stripe_head *sh2; + + sector_t bn = compute_blocknr(sh, i); +- sector_t s = +- raid5_compute_sector(conf, bn, 0, +- &dd_idx, &pd_idx, &qd_idx); ++ sector_t s = raid5_compute_sector(conf, bn, 0, ++ &dd_idx, NULL); + sh2 = get_active_stripe(conf, s, 0, 1); + if (sh2 == NULL) + /* so far only the early blocks of this stripe +@@ -2806,11 +2809,9 @@ static bool handle_stripe5(struct stripe + + if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) && + !sh->reconstruct_state) { +- int qd_idx; + /* Need to write out all blocks after computing parity */ + sh->disks = conf->raid_disks; +- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0, &qd_idx); +- sh->qd_idx = qd_idx; ++ stripe_set_idx(sh->sector, conf, 0, sh); + schedule_reconstruction5(sh, &s, 1, 1); + } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) { + clear_bit(STRIPE_EXPAND_READY, &sh->state); +@@ -3027,10 +3028,8 @@ static bool handle_stripe6(struct stripe + + if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) { + /* Need to write out all blocks after computing P&Q */ +- int qd_idx; + sh->disks = conf->raid_disks; +- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, 0, &qd_idx); +- sh->qd_idx = qd_idx; ++ stripe_set_idx(sh->sector, conf, 0, sh); + compute_parity6(sh, RECONSTRUCT_WRITE); + for (i = conf->raid_disks ; i-- ; ) { + set_bit(R5_LOCKED, &sh->dev[i].flags); +@@ -3302,7 +3301,7 @@ static int chunk_aligned_read(struct req + { + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); +- unsigned int dd_idx, pd_idx, qd_idx; ++ unsigned int dd_idx; + struct bio* align_bi; + mdk_rdev_t *rdev; + +@@ -3327,7 +3326,7 @@ static int chunk_aligned_read(struct req + */ + align_bi->bi_sector = raid5_compute_sector(conf, raid_bio->bi_sector, + 0, +- &dd_idx, &pd_idx, &qd_idx); ++ &dd_idx, NULL); + + rcu_read_lock(); + rdev = rcu_dereference(conf->disks[dd_idx].rdev); +@@ -3419,7 +3418,7 @@ static int make_request(struct request_q + { + mddev_t *mddev = q->queuedata; + raid5_conf_t *conf = mddev_to_conf(mddev); +- int dd_idx, pd_idx, qd_idx; ++ int dd_idx; + sector_t new_sector; + sector_t logical_sector, last_sector; + struct stripe_head *sh; +@@ -3483,7 +3482,7 @@ static int make_request(struct request_q + + new_sector = raid5_compute_sector(conf, logical_sector, + previous, +- &dd_idx, &pd_idx, &qd_idx); ++ &dd_idx, NULL); + pr_debug("raid5: make_request, sector %llu logical %llu\n", + (unsigned long long)new_sector, + (unsigned long long)logical_sector); +@@ -3572,7 +3571,6 @@ static sector_t reshape_request(mddev_t + */ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + struct stripe_head *sh; +- int pd_idx, qd_idx; + sector_t first_sector, last_sector; + int raid_disks = conf->previous_raid_disks; + int data_disks = raid_disks - conf->max_degraded; +@@ -3662,11 +3660,11 @@ static sector_t reshape_request(mddev_t + */ + first_sector = + raid5_compute_sector(conf, sector_nr*(new_data_disks), +- 1, &dd_idx, &pd_idx, &qd_idx); ++ 1, &dd_idx, NULL); + last_sector = + raid5_compute_sector(conf, ((sector_nr+conf->chunk_size/512) + *(new_data_disks) - 1), +- 1, &dd_idx, &pd_idx, &qd_idx); ++ 1, &dd_idx, NULL); + if (last_sector >= (mddev->size<<1)) + last_sector = (mddev->size<<1)-1; + while (first_sector <= last_sector) { +@@ -3801,7 +3799,7 @@ static int retry_aligned_read(raid5_con + * it will be only one 'dd_idx' and only need one call to raid5_compute_sector. + */ + struct stripe_head *sh; +- int dd_idx, pd_idx, qd_idx; ++ int dd_idx; + sector_t sector, logical_sector, last_sector; + int scnt = 0; + int remaining; +@@ -3809,7 +3807,7 @@ static int retry_aligned_read(raid5_con + + logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + sector = raid5_compute_sector(conf, logical_sector, +- 0, &dd_idx, &pd_idx, &qd_idx); ++ 0, &dd_idx, NULL); + last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); + + for (; logical_sector < last_sector; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch b/src/patches/suse-2.6.27.31/patches.fixes/0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch new file mode 100644 index 000000000..5d2c7aac5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch @@ -0,0 +1,351 @@ +From 99c0fb5f92828ae96909d390f2df137b89093b37 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:39:38 +1100 +Subject: [PATCH] md/raid5: Add support for new layouts for raid5 and raid6. + +DDF uses different layouts for P and Q blocks than current md/raid6 +so add those that are missing. +Also add support for RAID6 layouts that are identical to various +raid5 layouts with the simple addition of one device to hold all of +the 'Q' blocks. +Finally add 'raid5' layouts to match raid4. +These last to will allow online level conversion. + +Note that this does not provide correct support for DDF/raid6 yet +as the order in which data blocks are summed to produce the Q block +is significant and different between current md code and DDF +requirements. + +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 151 ++++++++++++++++++++++++++++++++++++++++----- + include/linux/raid/raid5.h | 61 ++++++++++++++++-- + 2 files changed, 193 insertions(+), 19 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -1100,7 +1100,7 @@ static void shrink_stripes(raid5_conf_t + + static void raid5_end_read_request(struct bio * bi, int error) + { +- struct stripe_head *sh = bi->bi_private; ++ struct stripe_head *sh = bi->bi_private; + raid5_conf_t *conf = sh->raid_conf; + int disks = sh->disks, i; + int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); +@@ -1182,7 +1182,7 @@ static void raid5_end_read_request(struc + + static void raid5_end_write_request (struct bio *bi, int error) + { +- struct stripe_head *sh = bi->bi_private; ++ struct stripe_head *sh = bi->bi_private; + raid5_conf_t *conf = sh->raid_conf; + int disks = sh->disks, i; + int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); +@@ -1322,20 +1322,27 @@ static sector_t raid5_compute_sector(rai + pd_idx = stripe % raid_disks; + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; + break; ++ case ALGORITHM_PARITY_0: ++ pd_idx = 0; ++ (*dd_idx)++; ++ break; ++ case ALGORITHM_PARITY_N: ++ pd_idx = data_disks; ++ break; + default: + printk(KERN_ERR "raid5: unsupported algorithm %d\n", + conf->algorithm); ++ BUG(); + } + break; + case 6: + +- /**** FIX THIS ****/ + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: + pd_idx = raid_disks - 1 - (stripe % raid_disks); + qd_idx = pd_idx + 1; + if (pd_idx == raid_disks-1) { +- (*dd_idx)++; /* Q D D D P */ ++ (*dd_idx)++; /* Q D D D P */ + qd_idx = 0; + } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ +@@ -1344,7 +1351,7 @@ static sector_t raid5_compute_sector(rai + pd_idx = stripe % raid_disks; + qd_idx = pd_idx + 1; + if (pd_idx == raid_disks-1) { +- (*dd_idx)++; /* Q D D D P */ ++ (*dd_idx)++; /* Q D D D P */ + qd_idx = 0; + } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ +@@ -1359,9 +1366,89 @@ static sector_t raid5_compute_sector(rai + qd_idx = (pd_idx + 1) % raid_disks; + *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; + break; ++ ++ case ALGORITHM_PARITY_0: ++ pd_idx = 0; ++ qd_idx = 1; ++ (*dd_idx) += 2; ++ break; ++ case ALGORITHM_PARITY_N: ++ pd_idx = data_disks; ++ qd_idx = data_disks + 1; ++ break; ++ ++ case ALGORITHM_ROTATING_ZERO_RESTART: ++ /* Exactly the same as RIGHT_ASYMMETRIC, but or ++ * of blocks for computing Q is different. ++ */ ++ pd_idx = stripe % raid_disks; ++ qd_idx = pd_idx + 1; ++ if (pd_idx == raid_disks-1) { ++ (*dd_idx)++; /* Q D D D P */ ++ qd_idx = 0; ++ } else if (*dd_idx >= pd_idx) ++ (*dd_idx) += 2; /* D D P Q D */ ++ break; ++ ++ case ALGORITHM_ROTATING_N_RESTART: ++ /* Same a left_asymmetric, by first stripe is ++ * D D D P Q rather than ++ * Q D D D P ++ */ ++ pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks); ++ qd_idx = pd_idx + 1; ++ if (pd_idx == raid_disks-1) { ++ (*dd_idx)++; /* Q D D D P */ ++ qd_idx = 0; ++ } else if (*dd_idx >= pd_idx) ++ (*dd_idx) += 2; /* D D P Q D */ ++ break; ++ ++ case ALGORITHM_ROTATING_N_CONTINUE: ++ /* Same as left_symmetric but Q is before P */ ++ pd_idx = raid_disks - 1 - (stripe % raid_disks); ++ qd_idx = (pd_idx + raid_disks - 1) % raid_disks; ++ *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; ++ break; ++ ++ case ALGORITHM_LEFT_ASYMMETRIC_6: ++ /* RAID5 left_asymmetric, with Q on last device */ ++ pd_idx = data_disks - stripe % (raid_disks-1); ++ if (*dd_idx >= pd_idx) ++ (*dd_idx)++; ++ qd_idx = raid_disks - 1; ++ break; ++ ++ case ALGORITHM_RIGHT_ASYMMETRIC_6: ++ pd_idx = stripe % (raid_disks-1); ++ if (*dd_idx >= pd_idx) ++ (*dd_idx)++; ++ qd_idx = raid_disks - 1; ++ break; ++ ++ case ALGORITHM_LEFT_SYMMETRIC_6: ++ pd_idx = data_disks - stripe % (raid_disks-1); ++ *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); ++ qd_idx = raid_disks - 1; ++ break; ++ ++ case ALGORITHM_RIGHT_SYMMETRIC_6: ++ pd_idx = stripe % (raid_disks-1); ++ *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); ++ qd_idx = raid_disks - 1; ++ break; ++ ++ case ALGORITHM_PARITY_0_6: ++ pd_idx = 0; ++ (*dd_idx)++; ++ qd_idx = raid_disks - 1; ++ break; ++ ++ + default: + printk (KERN_CRIT "raid6: unsupported algorithm %d\n", + conf->algorithm); ++ BUG(); + } + break; + } +@@ -1413,9 +1500,15 @@ static sector_t compute_blocknr(struct s + i += raid_disks; + i -= (sh->pd_idx + 1); + break; ++ case ALGORITHM_PARITY_0: ++ i -= 1; ++ break; ++ case ALGORITHM_PARITY_N: ++ break; + default: + printk(KERN_ERR "raid5: unsupported algorithm %d\n", + conf->algorithm); ++ BUG(); + } + break; + case 6: +@@ -1424,8 +1517,10 @@ static sector_t compute_blocknr(struct s + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: + case ALGORITHM_RIGHT_ASYMMETRIC: +- if (sh->pd_idx == raid_disks-1) +- i--; /* Q D D D P */ ++ case ALGORITHM_ROTATING_ZERO_RESTART: ++ case ALGORITHM_ROTATING_N_RESTART: ++ if (sh->pd_idx == raid_disks-1) ++ i--; /* Q D D D P */ + else if (i > sh->pd_idx) + i -= 2; /* D D P Q D */ + break; +@@ -1440,9 +1535,35 @@ static sector_t compute_blocknr(struct s + i -= (sh->pd_idx + 2); + } + break; ++ case ALGORITHM_PARITY_0: ++ i -= 2; ++ break; ++ case ALGORITHM_PARITY_N: ++ break; ++ case ALGORITHM_ROTATING_N_CONTINUE: ++ if (sh->pd_idx == 0) ++ i--; /* P D D D Q */ ++ else if (i > sh->pd_idx) ++ i -= 2; /* D D Q P D */ ++ break; ++ case ALGORITHM_LEFT_ASYMMETRIC_6: ++ case ALGORITHM_RIGHT_ASYMMETRIC_6: ++ if (i > sh->pd_idx) ++ i--; ++ break; ++ case ALGORITHM_LEFT_SYMMETRIC_6: ++ case ALGORITHM_RIGHT_SYMMETRIC_6: ++ if (i < sh->pd_idx) ++ i += data_disks + 1; ++ i -= (sh->pd_idx + 1); ++ break; ++ case ALGORITHM_PARITY_0_6: ++ i -= 1; ++ break; + default: + printk (KERN_CRIT "raid6: unsupported algorithm %d\n", + conf->algorithm); ++ BUG(); + } + break; + } +@@ -3310,7 +3431,7 @@ static int chunk_aligned_read(struct req + return 0; + } + /* +- * use bio_clone to make a copy of the bio ++ * use bio_clone to make a copy of the bio + */ + align_bi = bio_clone(raid_bio, GFP_NOIO); + if (!align_bi) +@@ -3438,7 +3559,7 @@ static int make_request(struct request_q + if (rw == READ && + mddev->reshape_position == MaxSector && + chunk_aligned_read(q,bi)) +- return 0; ++ return 0; + + logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + last_sector = bi->bi_sector + (bi->bi_size>>9); +@@ -4035,6 +4156,12 @@ static int run(mddev_t *mddev) + mdname(mddev), mddev->level); + return -EIO; + } ++ if ((mddev->level == 5 && !algorithm_valid_raid5(mddev->layout)) || ++ (mddev->level == 6 && !algorithm_valid_raid6(mddev->layout))) { ++ printk(KERN_ERR "raid5: %s: layout %d not supported\n", ++ mdname(mddev), mddev->layout); ++ return -EIO; ++ } + + if (mddev->chunk_size < PAGE_SIZE) { + printk(KERN_ERR "md/raid5: chunk_size must be at least " +@@ -4186,12 +4313,6 @@ static int run(mddev_t *mddev) + conf->chunk_size, mdname(mddev)); + goto abort; + } +- if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { +- printk(KERN_ERR +- "raid5: unsupported parity algorithm %d for %s\n", +- conf->algorithm, mdname(mddev)); +- goto abort; +- } + if (mddev->degraded > conf->max_degraded) { + printk(KERN_ERR "raid5: not enough operational devices for %s" + " (%d/%d failed)\n", +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/raid5.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/raid5.h +@@ -395,9 +395,62 @@ typedef struct raid5_private_data raid5_ + /* + * Our supported algorithms + */ +-#define ALGORITHM_LEFT_ASYMMETRIC 0 +-#define ALGORITHM_RIGHT_ASYMMETRIC 1 +-#define ALGORITHM_LEFT_SYMMETRIC 2 +-#define ALGORITHM_RIGHT_SYMMETRIC 3 ++#define ALGORITHM_LEFT_ASYMMETRIC 0 /* Rotating Parity N with Data Restart */ ++#define ALGORITHM_RIGHT_ASYMMETRIC 1 /* Rotating Parity 0 with Data Restart */ ++#define ALGORITHM_LEFT_SYMMETRIC 2 /* Rotating Parity N with Data Continuation */ ++#define ALGORITHM_RIGHT_SYMMETRIC 3 /* Rotating Parity 0 with Data Continuation */ + ++/* Define non-rotating (raid4) algorithms. These allow ++ * conversion of raid4 to raid5. ++ */ ++#define ALGORITHM_PARITY_0 4 /* P or P,Q are initial devices */ ++#define ALGORITHM_PARITY_N 5 /* P or P,Q are final devices. */ ++ ++/* DDF RAID6 layouts differ from md/raid6 layouts in two ways. ++ * Firstly, the exact positioning of the parity block is slightly ++ * different between the 'LEFT_*' modes of md and the "_N_*" modes ++ * of DDF. ++ * Secondly, or order of datablocks over which the Q syndrome is computed ++ * is different. ++ * Consequently we have different layouts for DDF/raid6 than md/raid6. ++ * These layouts are from the DDFv1.2 spec. ++ * Interestingly DDFv1.2-Errata-A does not specify N_CONTINUE but ++ * leaves RLQ=3 as 'Vendor Specific' ++ */ ++ ++#define ALGORITHM_ROTATING_ZERO_RESTART 8 /* DDF PRL=6 RLQ=1 */ ++#define ALGORITHM_ROTATING_N_RESTART 9 /* DDF PRL=6 RLQ=2 */ ++#define ALGORITHM_ROTATING_N_CONTINUE 10 /*DDF PRL=6 RLQ=3 */ ++ ++ ++/* For every RAID5 algorithm we define a RAID6 algorithm ++ * with exactly the same layout for data and parity, and ++ * with the Q block always on the last device (N-1). ++ * This allows trivial conversion from RAID5 to RAID6 ++ */ ++#define ALGORITHM_LEFT_ASYMMETRIC_6 16 ++#define ALGORITHM_RIGHT_ASYMMETRIC_6 17 ++#define ALGORITHM_LEFT_SYMMETRIC_6 18 ++#define ALGORITHM_RIGHT_SYMMETRIC_6 19 ++#define ALGORITHM_PARITY_0_6 20 ++#define ALGORITHM_PARITY_N_6 ALGORITHM_PARITY_N ++ ++static inline int algorithm_valid_raid5(int layout) ++{ ++ return (layout >= 0) && ++ (layout <= 5); ++} ++static inline int algorithm_valid_raid6(int layout) ++{ ++ return (layout >= 0 && layout <= 5) ++ || ++ (layout == 8 || layout == 10) ++ || ++ (layout >= 16 && layout <= 20); ++} ++ ++static inline int algorithm_is_DDF(int layout) ++{ ++ return layout >= 8 && layout <= 10; ++} + #endif diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0014-md-raid5-finish-support-for-DDF-raid6.patch b/src/patches/suse-2.6.27.31/patches.fixes/0014-md-raid5-finish-support-for-DDF-raid6.patch new file mode 100644 index 000000000..85c1c6ec8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0014-md-raid5-finish-support-for-DDF-raid6.patch @@ -0,0 +1,210 @@ +From 67cc2b8165857ba019920d1f00d64bcc4140075d Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 14:39:38 +1100 +Subject: [PATCH] md/raid5: finish support for DDF/raid6 + +DDF requires RAID6 calculations over different devices in a different +order. +For md/raid6, we calculate over just the data devices, starting +immediately after the 'Q' block. +For ddf/raid6 we calculate over all devices, using zeros in place of +the P and Q blocks. + +This requires unfortunately complex loops... + +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 58 +++++++++++++++++++++++++++++++-------------- + include/linux/raid/raid5.h | 1 + 2 files changed, 41 insertions(+), 18 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -138,6 +138,10 @@ static inline void raid5_set_bi_hw_segme + /* Find first data disk in a raid6 stripe */ + static inline int raid6_d0(struct stripe_head *sh) + { ++ if (sh->ddf_layout) ++ /* ddf always start from first device */ ++ return 0; ++ /* md starts just after Q block */ + if (sh->qd_idx == sh->disks - 1) + return 0; + else +@@ -154,13 +158,15 @@ static inline int raid6_next_disk(int di + * 0 .. raid_disks-3, the parity disk is raid_disks-2 and the Q disk + * is raid_disks-1. This help does that mapping. + */ +-static int raid6_idx_to_slot(int idx, struct stripe_head *sh, int *count) ++static int raid6_idx_to_slot(int idx, struct stripe_head *sh, ++ int *count, int syndrome_disks) + { + int slot; ++ + if (idx == sh->pd_idx) +- return sh->disks - 2; ++ return syndrome_disks; + if (idx == sh->qd_idx) +- return sh->disks - 1; ++ return syndrome_disks + 1; + slot = (*count)++; + return slot; + } +@@ -1269,6 +1275,7 @@ static sector_t raid5_compute_sector(rai + unsigned long chunk_number; + unsigned int chunk_offset; + int pd_idx, qd_idx; ++ int ddf_layout = 0; + sector_t new_sector; + int sectors_per_chunk = conf->chunk_size >> 9; + int raid_disks = previous ? conf->previous_raid_disks +@@ -1388,6 +1395,7 @@ static sector_t raid5_compute_sector(rai + qd_idx = 0; + } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ ++ ddf_layout = 1; + break; + + case ALGORITHM_ROTATING_N_RESTART: +@@ -1402,6 +1410,7 @@ static sector_t raid5_compute_sector(rai + qd_idx = 0; + } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ ++ ddf_layout = 1; + break; + + case ALGORITHM_ROTATING_N_CONTINUE: +@@ -1409,6 +1418,7 @@ static sector_t raid5_compute_sector(rai + pd_idx = raid_disks - 1 - (stripe % raid_disks); + qd_idx = (pd_idx + raid_disks - 1) % raid_disks; + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; ++ ddf_layout = 1; + break; + + case ALGORITHM_LEFT_ASYMMETRIC_6: +@@ -1456,6 +1466,7 @@ static sector_t raid5_compute_sector(rai + if (sh) { + sh->pd_idx = pd_idx; + sh->qd_idx = qd_idx; ++ sh->ddf_layout = ddf_layout; + } + /* + * Finally, compute the new sector number +@@ -1644,9 +1655,10 @@ static void compute_parity6(struct strip + { + raid6_conf_t *conf = sh->raid_conf; + int i, pd_idx, qd_idx, d0_idx, disks = sh->disks, count; ++ int syndrome_disks = sh->ddf_layout ? disks : (disks - 2); + struct bio *chosen; + /**** FIX THIS: This could be very bad if disks is close to 256 ****/ +- void *ptrs[disks]; ++ void *ptrs[syndrome_disks+2]; + + pd_idx = sh->pd_idx; + qd_idx = sh->qd_idx; +@@ -1689,23 +1701,28 @@ static void compute_parity6(struct strip + } + + /* Note that unlike RAID-5, the ordering of the disks matters greatly.*/ +- /* FIX: Is this ordering of drives even remotely optimal? */ ++ ++ for (i = 0; i < disks; i++) ++ ptrs[i] = (void *)raid6_empty_zero_page; ++ + count = 0; + i = d0_idx; + do { +- int slot = raid6_idx_to_slot(i, sh, &count); ++ int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); ++ + ptrs[slot] = page_address(sh->dev[i].page); +- if (slot < sh->disks - 2 && ++ if (slot < syndrome_disks && + !test_bit(R5_UPTODATE, &sh->dev[i].flags)) { + printk(KERN_ERR "block %d/%d not uptodate " + "on parity calc\n", i, count); + BUG(); + } ++ + i = raid6_next_disk(i, disks); + } while (i != d0_idx); +- BUG_ON(count+2 != disks); ++ BUG_ON(count != syndrome_disks); + +- raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); ++ raid6_call.gen_syndrome(syndrome_disks+2, STRIPE_SIZE, ptrs); + + switch(method) { + case RECONSTRUCT_WRITE: +@@ -1763,24 +1780,28 @@ static void compute_block_1(struct strip + static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) + { + int i, count, disks = sh->disks; ++ int syndrome_disks = sh->ddf_layout ? disks : disks-2; + int d0_idx = raid6_d0(sh); + int faila = -1, failb = -1; + /**** FIX THIS: This could be very bad if disks is close to 256 ****/ +- void *ptrs[disks]; ++ void *ptrs[syndrome_disks+2]; + ++ for (i = 0; i < disks ; i++) ++ ptrs[i] = (void *)raid6_empty_zero_page; + count = 0; + i = d0_idx; + do { +- int slot; +- slot = raid6_idx_to_slot(i, sh, &count); ++ int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); ++ + ptrs[slot] = page_address(sh->dev[i].page); ++ + if (i == dd_idx1) + faila = slot; + if (i == dd_idx2) + failb = slot; + i = raid6_next_disk(i, disks); + } while (i != d0_idx); +- BUG_ON(count+2 != disks); ++ BUG_ON(count != syndrome_disks); + + BUG_ON(faila == failb); + if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } +@@ -1789,9 +1810,9 @@ static void compute_block_2(struct strip + (unsigned long long)sh->sector, dd_idx1, dd_idx2, + faila, failb); + +- if ( failb == disks-1 ) { ++ if (failb == syndrome_disks+1) { + /* Q disk is one of the missing disks */ +- if ( faila == disks-2 ) { ++ if (faila == syndrome_disks) { + /* Missing P+Q, just recompute */ + compute_parity6(sh, UPDATE_PARITY); + return; +@@ -1806,12 +1827,13 @@ static void compute_block_2(struct strip + } + + /* We're missing D+P or D+D; */ +- if (failb == disks-2) { ++ if (failb == syndrome_disks) { + /* We're missing D+P. */ +- raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); ++ raid6_datap_recov(syndrome_disks+2, STRIPE_SIZE, faila, ptrs); + } else { + /* We're missing D+D. */ +- raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); ++ raid6_2data_recov(syndrome_disks+2, STRIPE_SIZE, faila, failb, ++ ptrs); + } + + /* Both the above update both missing blocks */ +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/raid5.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/raid5.h +@@ -202,6 +202,7 @@ struct stripe_head { + sector_t sector; /* sector of this row */ + short pd_idx; /* parity disk index */ + short qd_idx; /* 'Q' disk index for raid6 */ ++ short ddf_layout;/* use DDF ordering to calculate Q */ + unsigned long state; /* state flags */ + atomic_t count; /* nr of active thread/requests */ + spinlock_t lock; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0015-md-add-size-as-a-personality-method.patch b/src/patches/suse-2.6.27.31/patches.fixes/0015-md-add-size-as-a-personality-method.patch new file mode 100644 index 000000000..ec0bd5540 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0015-md-add-size-as-a-personality-method.patch @@ -0,0 +1,352 @@ +From 80c3a6ce4ba4470379b9e6a4d9bcd9d2ee26ae03 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Tue, 17 Mar 2009 18:10:40 -0700 +Subject: [PATCH] md: add 'size' as a personality method + +In preparation for giving userspace control over ->array_sectors we need +to be able to retrieve the 'default' size, and the 'anticipated' size +when a reshape is requested. For personalities that do not reshape emit +a warning if anything but the default size is requested. + +In the raid5 case we need to update ->previous_raid_disks to make the +new 'default' size available. + +Reviewed-by: Andre Noll +Signed-off-by: Dan Williams +Acked-by: NeilBrown +--- + drivers/md/faulty.c | 12 ++++++++++++ + drivers/md/linear.c | 15 +++++++++++++-- + drivers/md/multipath.c | 9 +++++++++ + drivers/md/raid0.c | 21 ++++++++++++++++----- + drivers/md/raid1.c | 11 ++++++++++- + drivers/md/raid10.c | 24 ++++++++++++++++++++++-- + drivers/md/raid5.c | 35 +++++++++++++++++++++++++---------- + include/linux/raid/md_k.h | 1 + + 8 files changed, 108 insertions(+), 20 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/faulty.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/faulty.c +@@ -280,6 +280,17 @@ static int reconfig(mddev_t *mddev, int + return 0; + } + ++static sector_t faulty_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ WARN_ONCE(raid_disks, ++ "%s does not support generic reshape\n", __func__); ++ ++ if (sectors == 0) ++ return mddev->size*2; ++ ++ return sectors; ++} ++ + static int run(mddev_t *mddev) + { + mdk_rdev_t *rdev; +@@ -324,6 +335,7 @@ static struct mdk_personality faulty_per + .stop = stop, + .status = status, + .reconfig = reconfig, ++ .size = faulty_size, + }; + + static int __init raid_init(void) +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/linear.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/linear.c +@@ -106,6 +106,16 @@ static int linear_congested(void *data, + return ret; + } + ++static sector_t linear_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ linear_conf_t *conf = mddev_to_conf(mddev); ++ ++ WARN_ONCE(sectors || raid_disks, ++ "%s does not support generic reshape\n", __func__); ++ ++ return conf->array_sectors; ++} ++ + static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) + { + linear_conf_t *conf; +@@ -260,7 +270,7 @@ static int linear_run (mddev_t *mddev) + if (!conf) + return 1; + mddev->private = conf; +- mddev->array_sectors = conf->array_sectors; ++ mddev->array_sectors = linear_size(mddev, 0, 0); + + blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); + mddev->queue->unplug_fn = linear_unplug; +@@ -294,7 +304,7 @@ static int linear_add(mddev_t *mddev, md + newconf->prev = mddev_to_conf(mddev); + mddev->private = newconf; + mddev->raid_disks++; +- mddev->array_sectors = newconf->array_sectors; ++ mddev->array_sectors = linear_size(mddev, 0, 0); + set_capacity(mddev->gendisk, mddev->array_sectors); + return 0; + } +@@ -407,6 +417,7 @@ static struct mdk_personality linear_per + .stop = linear_stop, + .status = linear_status, + .hot_add_disk = linear_add, ++ .size = linear_size, + }; + + static int __init linear_init (void) +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/multipath.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/multipath.c +@@ -407,6 +407,14 @@ static void multipathd (mddev_t *mddev) + spin_unlock_irqrestore(&conf->device_lock, flags); + } + ++static sector_t multipath_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ WARN_ONCE(sectors || raid_disks, ++ "%s does not support generic reshape\n", __func__); ++ ++ return mddev->size*2; ++} ++ + static int multipath_run (mddev_t *mddev) + { + multipath_conf_t *conf; +@@ -549,6 +557,7 @@ static struct mdk_personality multipath_ + .error_handler = multipath_error, + .hot_add_disk = multipath_add_disk, + .hot_remove_disk= multipath_remove_disk, ++ .size = multipath_size, + }; + + static int __init multipath_init (void) +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid0.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid0.c +@@ -264,13 +264,25 @@ static int raid0_mergeable_bvec(struct r + return max; + } + ++static sector_t raid0_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ sector_t array_sectors = 0; ++ mdk_rdev_t *rdev; ++ ++ WARN_ONCE(sectors || raid_disks, ++ "%s does not support generic reshape\n", __func__); ++ ++ list_for_each_entry(rdev, &mddev->disks, same_set) ++ array_sectors += rdev->size*2; ++ ++ return array_sectors; ++} ++ + static int raid0_run (mddev_t *mddev) + { + unsigned cur=0, i=0, nb_zone; + s64 size; + raid0_conf_t *conf; +- mdk_rdev_t *rdev; +- struct list_head *tmp; + + if (mddev->chunk_size == 0) { + printk(KERN_ERR "md/raid0: non-zero chunk size required.\n"); +@@ -295,9 +307,7 @@ static int raid0_run (mddev_t *mddev) + goto out_free_conf; + + /* calculate array device size */ +- mddev->array_sectors = 0; +- rdev_for_each(rdev, tmp, mddev) +- mddev->array_sectors += rdev->size * 2; ++ mddev->array_sectors = raid0_size(mddev, 0, 0); + + printk("raid0 : md_size is %llu blocks.\n", + (unsigned long long)mddev->array_sectors / 2); +@@ -512,6 +522,7 @@ static struct mdk_personality raid0_pers + .run = raid0_run, + .stop = raid0_stop, + .status = raid0_status, ++ .size = raid0_size, + }; + + static int __init raid0_init (void) +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid1.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid1.c +@@ -1915,6 +1915,14 @@ static sector_t sync_request(mddev_t *md + return nr_sectors; + } + ++static sector_t raid1_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ if (sectors) ++ return sectors; ++ ++ return mddev->size*2; ++} ++ + static int run(mddev_t *mddev) + { + conf_t *conf; +@@ -2107,7 +2115,7 @@ static int raid1_resize(mddev_t *mddev, + * any io in the removed space completes, but it hardly seems + * worth it. + */ +- mddev->array_sectors = sectors; ++ mddev->array_sectors = raid1_size(mddev, sectors, 0); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + if (mddev->array_sectors / 2 > mddev->size && +@@ -2261,6 +2269,7 @@ static struct mdk_personality raid1_pers + .spare_active = raid1_spare_active, + .sync_request = sync_request, + .resize = raid1_resize, ++ .size = raid1_size, + .check_reshape = raid1_reshape, + .quiesce = raid1_quiesce, + }; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid10.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid10.c +@@ -2015,6 +2015,25 @@ static sector_t sync_request(mddev_t *md + goto skipped; + } + ++static sector_t ++raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ sector_t size; ++ conf_t *conf = mddev_to_conf(mddev); ++ ++ if (!raid_disks) ++ raid_disks = mddev->raid_disks; ++ if (!sectors) ++ sectors = mddev->size*2; ++ ++ size = sectors >> conf->chunk_shift; ++ sector_div(size, conf->far_copies); ++ size = size * raid_disks; ++ sector_div(size, conf->near_copies); ++ ++ return size << conf->chunk_shift; ++} ++ + static int run(mddev_t *mddev) + { + conf_t *conf; +@@ -2167,8 +2186,8 @@ static int run(mddev_t *mddev) + /* + * Ok, everything is just fine now + */ +- mddev->array_sectors = size << conf->chunk_shift; +- mddev->resync_max_sectors = size << conf->chunk_shift; ++ mddev->array_sectors = raid10_size(mddev, 0, 0); ++ mddev->resync_max_sectors = mddev->array_sectors; + + mddev->queue->unplug_fn = raid10_unplug; + mddev->queue->backing_dev_info.congested_fn = raid10_congested; +@@ -2251,6 +2270,7 @@ static struct mdk_personality raid10_per + .spare_active = raid10_spare_active, + .sync_request = sync_request, + .quiesce = raid10_quiesce, ++ .size = raid10_size, + }; + + static int __init raid_init(void) +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -4163,6 +4163,20 @@ static struct attribute_group raid5_attr + .attrs = raid5_attrs, + }; + ++static sector_t ++raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks) ++{ ++ raid5_conf_t *conf = mddev_to_conf(mddev); ++ ++ if (!sectors) ++ sectors = mddev->size*2; ++ if (!raid_disks) ++ raid_disks = conf->previous_raid_disks; ++ ++ sectors &= ~((sector_t)mddev->chunk_size/512 - 1); ++ return sectors * (raid_disks - conf->max_degraded); ++} ++ + static int run(mddev_t *mddev) + { + raid5_conf_t *conf; +@@ -4423,8 +4437,7 @@ static int run(mddev_t *mddev) + mddev->queue->backing_dev_info.congested_data = mddev; + mddev->queue->backing_dev_info.congested_fn = raid5_congested; + +- mddev->array_sectors = 2 * mddev->size * (conf->previous_raid_disks - +- conf->max_degraded); ++ mddev->array_sectors = raid5_size(mddev, 0, 0); + + blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec); + +@@ -4644,11 +4657,8 @@ static int raid5_resize(mddev_t *mddev, + * any io in the removed space completes, but it hardly seems + * worth it. + */ +- raid5_conf_t *conf = mddev_to_conf(mddev); +- + sectors &= ~((sector_t)mddev->chunk_size/512 - 1); +- mddev->array_sectors = sectors * (mddev->raid_disks +- - conf->max_degraded); ++ mddev->array_sectors = raid5_size(mddev, sectors, mddev->raid_disks); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { +@@ -4785,10 +4795,12 @@ static void end_reshape(raid5_conf_t *co + struct block_device *bdev; + + if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { +- conf->mddev->array_sectors = 2 * conf->mddev->size * +- (conf->raid_disks - conf->max_degraded); +- set_capacity(conf->mddev->gendisk, conf->mddev->array_sectors); +- conf->mddev->changed = 1; ++ mddev_t *mddev = conf->mddev; ++ ++ mddev->array_sectors = raid5_size(mddev, 0, conf->raid_disks); ++ set_capacity(mddev->gendisk, mddev->array_sectors); ++ mddev->changed = 1; ++ conf->previous_raid_disks = conf->raid_disks; + + bdev = bdget_disk(conf->mddev->gendisk, 0); + if (bdev) { +@@ -4860,6 +4872,7 @@ static struct mdk_personality raid6_pers + .spare_active = raid5_spare_active, + .sync_request = sync_request, + .resize = raid5_resize, ++ .size = raid5_size, + #ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, +@@ -4881,6 +4894,7 @@ static struct mdk_personality raid5_pers + .spare_active = raid5_spare_active, + .sync_request = sync_request, + .resize = raid5_resize, ++ .size = raid5_size, + #ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, +@@ -4903,6 +4917,7 @@ static struct mdk_personality raid4_pers + .spare_active = raid5_spare_active, + .sync_request = sync_request, + .resize = raid5_resize, ++ .size = raid5_size, + #ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/md_k.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/md_k.h +@@ -305,6 +305,7 @@ struct mdk_personality + int (*spare_active) (mddev_t *mddev); + sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster); + int (*resize) (mddev_t *mddev, sector_t sectors); ++ sector_t (*size) (mddev_t *mddev, sector_t sectors, int raid_disks); + int (*check_reshape) (mddev_t *mddev); + int (*start_reshape) (mddev_t *mddev); + int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0016-md-centralize-array_sectors-modifications.patch b/src/patches/suse-2.6.27.31/patches.fixes/0016-md-centralize-array_sectors-modifications.patch new file mode 100644 index 000000000..bc041587c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0016-md-centralize-array_sectors-modifications.patch @@ -0,0 +1,119 @@ +From 1f403624bde3c678a166984b1e6a727a0ce06f2b Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Tue, 31 Mar 2009 14:59:03 +1100 +Subject: [PATCH] md: centralize ->array_sectors modifications + +Get personalities out of the business of directly modifying +->array_sectors. Lays groundwork to introduce policy on when +->array_sectors can be modified. + +Reviewed-by: Andre Noll +Signed-off-by: Dan Williams +Acked-by: NeilBrown +--- + drivers/md/linear.c | 4 ++-- + drivers/md/md.c | 6 ++++++ + drivers/md/raid1.c | 2 +- + drivers/md/raid10.c | 2 +- + drivers/md/raid5.c | 8 +++++--- + include/linux/raid/md.h | 1 + + 6 files changed, 16 insertions(+), 7 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/linear.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/linear.c +@@ -270,7 +270,7 @@ static int linear_run (mddev_t *mddev) + if (!conf) + return 1; + mddev->private = conf; +- mddev->array_sectors = linear_size(mddev, 0, 0); ++ md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); + + blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); + mddev->queue->unplug_fn = linear_unplug; +@@ -304,7 +304,7 @@ static int linear_add(mddev_t *mddev, md + newconf->prev = mddev_to_conf(mddev); + mddev->private = newconf; + mddev->raid_disks++; +- mddev->array_sectors = linear_size(mddev, 0, 0); ++ md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); + set_capacity(mddev->gendisk, mddev->array_sectors); + return 0; + } +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -4662,6 +4662,12 @@ static int set_array_info(mddev_t * mdde + return 0; + } + ++void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors) ++{ ++ mddev->array_sectors = array_sectors; ++} ++EXPORT_SYMBOL(md_set_array_sectors); ++ + static int update_size(mddev_t *mddev, sector_t num_sectors) + { + mdk_rdev_t * rdev; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid1.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid1.c +@@ -2115,7 +2115,7 @@ static int raid1_resize(mddev_t *mddev, + * any io in the removed space completes, but it hardly seems + * worth it. + */ +- mddev->array_sectors = raid1_size(mddev, sectors, 0); ++ md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0)); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + if (mddev->array_sectors / 2 > mddev->size && +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid10.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid10.c +@@ -2186,7 +2186,7 @@ static int run(mddev_t *mddev) + /* + * Ok, everything is just fine now + */ +- mddev->array_sectors = raid10_size(mddev, 0, 0); ++ md_set_array_sectors(mddev, raid10_size(mddev, 0, 0)); + mddev->resync_max_sectors = mddev->array_sectors; + + mddev->queue->unplug_fn = raid10_unplug; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -4437,7 +4437,7 @@ static int run(mddev_t *mddev) + mddev->queue->backing_dev_info.congested_data = mddev; + mddev->queue->backing_dev_info.congested_fn = raid5_congested; + +- mddev->array_sectors = raid5_size(mddev, 0, 0); ++ md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); + + blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec); + +@@ -4658,7 +4658,8 @@ static int raid5_resize(mddev_t *mddev, + * worth it. + */ + sectors &= ~((sector_t)mddev->chunk_size/512 - 1); +- mddev->array_sectors = raid5_size(mddev, sectors, mddev->raid_disks); ++ md_set_array_sectors(mddev, raid5_size(mddev, sectors, ++ mddev->raid_disks)); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { +@@ -4797,7 +4798,8 @@ static void end_reshape(raid5_conf_t *co + if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { + mddev_t *mddev = conf->mddev; + +- mddev->array_sectors = raid5_size(mddev, 0, conf->raid_disks); ++ md_set_array_sectors(mddev, raid5_size(mddev, 0, ++ conf->raid_disks)); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + conf->previous_raid_disks = conf->raid_disks; +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/md.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/md.h +@@ -97,6 +97,7 @@ extern void md_do_sync(mddev_t *mddev); + extern void md_new_event(mddev_t *mddev); + extern int md_allow_write(mddev_t *mddev); + extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); ++extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); + + #endif /* CONFIG_MD */ + #endif diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0017-md-array_size-sysfs-attribute.patch b/src/patches/suse-2.6.27.31/patches.fixes/0017-md-array_size-sysfs-attribute.patch new file mode 100644 index 000000000..be0595650 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0017-md-array_size-sysfs-attribute.patch @@ -0,0 +1,284 @@ +From b522adcde9c4d3fb7b579cfa9160d8bde7744be8 Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Tue, 31 Mar 2009 15:00:31 +1100 +Subject: [PATCH] md: 'array_size' sysfs attribute + +Allow userspace to set the size of the array according to the following +semantics: + +1/ size must be <= to the size returned by mddev->pers->size(mddev, 0, 0) + a) If size is set before the array is running, do_md_run will fail + if size is greater than the default size + b) A reshape attempt that reduces the default size to less than the set + array size should be blocked +2/ once userspace sets the size the kernel will not change it +3/ writing 'default' to this attribute returns control of the size to the + kernel and reverts to the size reported by the personality + +Also, convert locations that need to know the default size from directly +reading ->array_sectors to _size. Resync/reshape operations +always follow the default size. + +Finally, fixup other locations that read a number of 1k-blocks from +userspace to use strict_blocks_to_sectors() which checks for unsigned +long long to sector_t overflow and blocks to sectors overflow. + +Reviewed-by: Andre Noll +Signed-off-by: Dan Williams +Acked-by: NeilBrown +--- + drivers/md/md.c | 101 +++++++++++++++++++++++++++++++++++++++++++++- + drivers/md/raid0.c | 2 + drivers/md/raid1.c | 6 +- + drivers/md/raid10.c | 2 + drivers/md/raid5.c | 9 +++- + include/linux/raid/md_k.h | 3 + + 6 files changed, 116 insertions(+), 7 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -300,6 +300,11 @@ static inline int mddev_lock(mddev_t * m + return mutex_lock_interruptible(&mddev->reconfig_mutex); + } + ++static inline int mddev_is_locked(mddev_t *mddev) ++{ ++ return mutex_is_locked(&mddev->reconfig_mutex); ++} ++ + static inline int mddev_trylock(mddev_t * mddev) + { + return mutex_trylock(&mddev->reconfig_mutex); +@@ -2146,6 +2151,25 @@ static int overlaps(sector_t s1, sector_ + return 1; + } + ++static int strict_blocks_to_sectors(const char *buf, sector_t *sectors) ++{ ++ unsigned long long blocks; ++ sector_t new; ++ ++ if (strict_strtoull(buf, 10, &blocks) < 0) ++ return -EINVAL; ++ ++ if (blocks & 1ULL << (8 * sizeof(blocks) - 1)) ++ return -EINVAL; /* sector conversion overflow */ ++ ++ new = blocks * 2; ++ if (new != blocks * 2) ++ return -EINVAL; /* unsigned long long to sector_t overflow */ ++ ++ *sectors = new; ++ return 0; ++} ++ + static ssize_t + rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) + { +@@ -3398,6 +3422,57 @@ static struct md_sysfs_entry md_reshape_ + __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show, + reshape_position_store); + ++static ssize_t ++array_size_show(mddev_t *mddev, char *page) ++{ ++ if (mddev->external_size) ++ return sprintf(page, "%llu\n", ++ (unsigned long long)mddev->array_sectors/2); ++ else ++ return sprintf(page, "default\n"); ++} ++ ++static ssize_t ++array_size_store(mddev_t *mddev, const char *buf, size_t len) ++{ ++ sector_t sectors; ++ ++ if (strncmp(buf, "default", 7) == 0) { ++ if (mddev->pers) ++ sectors = mddev->pers->size(mddev, 0, 0); ++ else ++ sectors = mddev->array_sectors; ++ ++ mddev->external_size = 0; ++ } else { ++ if (strict_blocks_to_sectors(buf, §ors) < 0) ++ return -EINVAL; ++ if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) ++ return -EINVAL; ++ ++ mddev->external_size = 1; ++ } ++ ++ mddev->array_sectors = sectors; ++ set_capacity(mddev->gendisk, mddev->array_sectors); ++ if (mddev->pers) { ++ struct block_device *bdev = bdget_disk(mddev->gendisk, 0); ++ ++ if (bdev) { ++ mutex_lock(&bdev->bd_inode->i_mutex); ++ i_size_write(bdev->bd_inode, ++ (loff_t)mddev->array_sectors << 9); ++ mutex_unlock(&bdev->bd_inode->i_mutex); ++ bdput(bdev); ++ } ++ } ++ ++ return len; ++} ++ ++static struct md_sysfs_entry md_array_size = ++__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show, ++ array_size_store); + + static struct attribute *md_default_attrs[] = { + &md_level.attr, +@@ -3411,6 +3486,7 @@ static struct attribute *md_default_attr + &md_safe_delay.attr, + &md_array_state.attr, + &md_reshape_position.attr, ++ &md_array_size.attr, + NULL, + }; + +@@ -3722,7 +3798,17 @@ static int do_md_run(mddev_t * mddev) + err = mddev->pers->run(mddev); + if (err) + printk(KERN_ERR "md: pers->run() failed ...\n"); +- else if (mddev->pers->sync_request) { ++ else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) { ++ WARN_ONCE(!mddev->external_size, "%s: default size too small," ++ " but 'external_size' not in effect?\n", __func__); ++ printk(KERN_ERR ++ "md: invalid array_size %llu > default size %llu\n", ++ (unsigned long long)mddev->array_sectors / 2, ++ (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2); ++ err = -EINVAL; ++ mddev->pers->stop(mddev); ++ } ++ if (err == 0 && mddev->pers->sync_request) { + err = bitmap_create(mddev); + if (err) { + printk(KERN_ERR "%s: failed to create bitmap (%d)\n", +@@ -4664,10 +4750,23 @@ static int set_array_info(mddev_t * mdde + + void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors) + { ++ WARN(!mddev_is_locked(mddev), "%s: unlocked mddev!\n", __func__); ++ ++ if (mddev->external_size) ++ return; ++ + mddev->array_sectors = array_sectors; + } + EXPORT_SYMBOL(md_set_array_sectors); + ++void md_set_array_sectors_lock(mddev_t *mddev, sector_t array_sectors) ++{ ++ mddev_lock(mddev); ++ md_set_array_sectors(mddev, array_sectors); ++ mddev_unlock(mddev); ++} ++EXPORT_SYMBOL(md_set_array_sectors_lock); ++ + static int update_size(mddev_t *mddev, sector_t num_sectors) + { + mdk_rdev_t * rdev; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid0.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid0.c +@@ -314,7 +314,7 @@ static int raid0_run (mddev_t *mddev) + printk("raid0 : conf->hash_spacing is %llu blocks.\n", + (unsigned long long)conf->hash_spacing); + { +- sector_t s = mddev->array_sectors / 2; ++ sector_t s = raid0_size(mddev, 0, 0) / 2; + sector_t space = conf->hash_spacing; + int round; + conf->preshift = 0; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid1.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid1.c +@@ -2116,14 +2116,16 @@ static int raid1_resize(mddev_t *mddev, + * worth it. + */ + md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0)); ++ if (mddev->array_sectors > raid1_size(mddev, sectors, 0)) ++ return -EINVAL; + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; +- if (mddev->array_sectors / 2 > mddev->size && ++ if (sectors / 2 > mddev->size && + mddev->recovery_cp == MaxSector) { + mddev->recovery_cp = mddev->size << 1; + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + } +- mddev->size = mddev->array_sectors / 2; ++ mddev->size = sectors / 2; + mddev->resync_max_sectors = sectors; + return 0; + } +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid10.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid10.c +@@ -2187,7 +2187,7 @@ static int run(mddev_t *mddev) + * Ok, everything is just fine now + */ + md_set_array_sectors(mddev, raid10_size(mddev, 0, 0)); +- mddev->resync_max_sectors = mddev->array_sectors; ++ mddev->resync_max_sectors = raid10_size(mddev, 0, 0); + + mddev->queue->unplug_fn = raid10_unplug; + mddev->queue->backing_dev_info.congested_fn = raid10_congested; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -3700,6 +3700,8 @@ static int make_request(struct request_q + return 0; + } + ++static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks); ++ + static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) + { + /* reshaping is quite different to recovery/resync so it is +@@ -3778,7 +3780,7 @@ static sector_t reshape_request(mddev_t + j == sh->qd_idx) + continue; + s = compute_blocknr(sh, j); +- if (s < mddev->array_sectors) { ++ if (s < raid5_size(mddev, 0, 0)) { + skipped = 1; + continue; + } +@@ -4660,6 +4662,9 @@ static int raid5_resize(mddev_t *mddev, + sectors &= ~((sector_t)mddev->chunk_size/512 - 1); + md_set_array_sectors(mddev, raid5_size(mddev, sectors, + mddev->raid_disks)); ++ if (mddev->array_sectors > ++ raid5_size(mddev, sectors, mddev->raid_disks)) ++ return -EINVAL; + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { +@@ -4798,7 +4803,7 @@ static void end_reshape(raid5_conf_t *co + if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { + mddev_t *mddev = conf->mddev; + +- md_set_array_sectors(mddev, raid5_size(mddev, 0, ++ md_set_array_sectors_lock(mddev, raid5_size(mddev, 0, + conf->raid_disks)); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/md_k.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/md_k.h +@@ -152,6 +152,8 @@ struct mddev_s + int max_disks; + sector_t size; /* used size of component devices */ + sector_t array_sectors; /* exported array size */ ++ int external_size; /* size managed ++ * externally */ + __u64 events; + + char uuid[16]; +@@ -394,3 +396,4 @@ static inline void safe_put_page(struct + #endif /* CONFIG_BLOCK */ + #endif + ++extern void md_set_array_sectors_lock(mddev_t *mddev, sector_t array_sectors); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0017A-md-array_size-sysfs-arrtibute.patch b/src/patches/suse-2.6.27.31/patches.fixes/0017A-md-array_size-sysfs-arrtibute.patch new file mode 100644 index 000000000..40d74ea91 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0017A-md-array_size-sysfs-arrtibute.patch @@ -0,0 +1,222 @@ +From: NeilBrown +Subject: [PATCH] md: 'array_size' sysfs attribute +References: bnc#498358 + +Allow userspace to set the size of the array according to the following +semantics: + +1/ size must be <= to the size stored in mddev->array_size + a) If size is set before the array is running, do_md_run will fail + if size is greater than the default size + b) A reshape attempt that reduces the default size to less than the set + array size should be blocked +2/ once userspace sets the size the kernel will not change it +3/ writing 'default' to this attribute returns control of the size to the + kernel and reverts to the size reported by the personality + +To avoid kabi break we store the user-specified size in ->queue->end_sector +which is otherwise unused by md devices. + +(based on a patch which was) +Signed-off-by: Dan Williams +Signed-off-by: NeilBrown +Acked-by: NeilBrown +--- + drivers/md/linear.c | 3 + + drivers/md/md.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++-- + drivers/md/raid1.c | 14 ++++---- + drivers/md/raid5.c | 9 +++-- + 4 files changed, 99 insertions(+), 12 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/linear.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/linear.c +@@ -295,7 +295,8 @@ static int linear_add(mddev_t *mddev, md + mddev->private = newconf; + mddev->raid_disks++; + mddev->array_sectors = newconf->array_sectors; +- set_capacity(mddev->gendisk, mddev->array_sectors); ++ if (mddev->queue->end_sector == 0) ++ set_capacity(mddev->gendisk, mddev->array_sectors); + return 0; + } + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -287,6 +287,7 @@ static mddev_t * mddev_find(dev_t unit) + kfree(new); + return NULL; + } ++ new->queue->end_sector = 0; + /* Can be unlocked because the queue is new: no concurrency */ + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue); + +@@ -2136,6 +2137,25 @@ rdev_size_show(mdk_rdev_t *rdev, char *p + return sprintf(page, "%llu\n", (unsigned long long)rdev->size); + } + ++static int strict_blocks_to_sectors(const char *buf, sector_t *sectors) ++{ ++ unsigned long long blocks; ++ sector_t new; ++ ++ if (strict_strtoull(buf, 10, &blocks) < 0) ++ return -EINVAL; ++ ++ if (blocks & 1ULL << (8 * sizeof(blocks) - 1)) ++ return -EINVAL; /* sector conversion overflow */ ++ ++ new = blocks * 2; ++ if (new != blocks * 2) ++ return -EINVAL; /* unsigned long long to sector_t overflow */ ++ ++ *sectors = new; ++ return 0; ++} ++ + static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2) + { + /* check if two start/length pairs overlap */ +@@ -3397,6 +3417,55 @@ static struct md_sysfs_entry md_reshape_ + __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show, + reshape_position_store); + ++static ssize_t ++array_size_show(mddev_t *mddev, char *page) ++{ ++ if (mddev->queue->end_sector) ++ return sprintf(page, "%llu\n", ++ (unsigned long long)mddev->queue->end_sector/2); ++ else ++ return sprintf(page, "default\n"); ++} ++ ++static ssize_t ++array_size_store(mddev_t *mddev, const char *buf, size_t len) ++{ ++ sector_t sectors; ++ ++ if (strncmp(buf, "default", 7) == 0) { ++ sectors = mddev->array_sectors; ++ ++ mddev->queue->end_sector = 0; ++ } else { ++ if (strict_blocks_to_sectors(buf, §ors) < 0) ++ return -EINVAL; ++ if (sectors < 2) ++ return -EINVAL; ++ if (mddev->pers && mddev->array_sectors < sectors) ++ return -E2BIG; ++ ++ mddev->queue->end_sector = sectors; ++ } ++ ++ set_capacity(mddev->gendisk, sectors); ++ if (mddev->pers) { ++ struct block_device *bdev = bdget_disk(mddev->gendisk, 0); ++ ++ if (bdev) { ++ mutex_lock(&bdev->bd_inode->i_mutex); ++ i_size_write(bdev->bd_inode, ++ (loff_t)sectors << 9); ++ mutex_unlock(&bdev->bd_inode->i_mutex); ++ bdput(bdev); ++ } ++ } ++ ++ return len; ++} ++ ++static struct md_sysfs_entry md_array_size = ++__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show, ++ array_size_store); + + static struct attribute *md_default_attrs[] = { + &md_level.attr, +@@ -3410,6 +3479,7 @@ static struct attribute *md_default_attr + &md_safe_delay.attr, + &md_array_state.attr, + &md_reshape_position.attr, ++ &md_array_size.attr, + NULL, + }; + +@@ -3721,7 +3791,15 @@ static int do_md_run(mddev_t * mddev) + err = mddev->pers->run(mddev); + if (err) + printk(KERN_ERR "md: pers->run() failed ...\n"); +- else if (mddev->pers->sync_request) { ++ else if (mddev->queue->end_sector && ++ mddev->queue->end_sector > mddev->array_sectors) { ++ printk(KERN_ERR ++ "md: invalid array_size %llu > default size %llu\n", ++ (unsigned long long)mddev->queue->end_sector / 2, ++ (unsigned long long)mddev->array_sectors / 2); ++ err = -EINVAL; ++ mddev->pers->stop(mddev); ++ } else if (mddev->pers->sync_request) { + err = bitmap_create(mddev); + if (err) { + printk(KERN_ERR "%s: failed to create bitmap (%d)\n", +@@ -3764,7 +3842,10 @@ static int do_md_run(mddev_t * mddev) + if (mddev->flags) + md_update_sb(mddev, 0); + +- set_capacity(disk, mddev->array_sectors); ++ if (mddev->queue->end_sector) ++ set_capacity(disk, mddev->queue->end_sector); ++ else ++ set_capacity(disk, mddev->array_sectors); + + /* If we call blk_queue_make_request here, it will + * re-initialise max_sectors etc which may have been +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid1.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid1.c +@@ -2108,12 +2108,14 @@ static int raid1_resize(mddev_t *mddev, + * worth it. + */ + mddev->array_sectors = sectors; +- set_capacity(mddev->gendisk, mddev->array_sectors); +- mddev->changed = 1; +- if (mddev->array_sectors / 2 > mddev->size && +- mddev->recovery_cp == MaxSector) { +- mddev->recovery_cp = mddev->size << 1; +- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); ++ if (mddev->queue->end_sector == 0) { ++ set_capacity(mddev->gendisk, mddev->array_sectors); ++ mddev->changed = 1; ++ if (mddev->array_sectors / 2 > mddev->size && ++ mddev->recovery_cp == MaxSector) { ++ mddev->recovery_cp = mddev->size << 1; ++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); ++ } + } + mddev->size = mddev->array_sectors / 2; + mddev->resync_max_sectors = sectors; +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -4650,7 +4650,8 @@ static int raid5_resize(mddev_t *mddev, + sectors &= ~((sector_t)mddev->chunk_size/512 - 1); + mddev->array_sectors = sectors * (mddev->raid_disks + - conf->max_degraded); +- set_capacity(mddev->gendisk, mddev->array_sectors); ++ if (mddev->queue->end_sector == 0) ++ set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { + mddev->recovery_cp = mddev->size << 1; +@@ -4788,11 +4789,13 @@ static void end_reshape(raid5_conf_t *co + if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { + conf->mddev->array_sectors = 2 * conf->mddev->size * + (conf->raid_disks - conf->max_degraded); +- set_capacity(conf->mddev->gendisk, conf->mddev->array_sectors); ++ if (conf->mddev->queue->end_sector == 0) ++ set_capacity(conf->mddev->gendisk, ++ conf->mddev->array_sectors); + conf->mddev->changed = 1; + + bdev = bdget_disk(conf->mddev->gendisk, 0); +- if (bdev) { ++ if (bdev && conf->mddev->queue->end_sector == 0) { + mutex_lock(&bdev->bd_inode->i_mutex); + i_size_write(bdev->bd_inode, + (loff_t)conf->mddev->array_sectors << 9); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0018-md-raid5-run-Fix-max_degraded-for-raid-level-4.patch b/src/patches/suse-2.6.27.31/patches.fixes/0018-md-raid5-run-Fix-max_degraded-for-raid-level-4.patch new file mode 100644 index 000000000..f9c44bc10 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0018-md-raid5-run-Fix-max_degraded-for-raid-level-4.patch @@ -0,0 +1,24 @@ +From 18b0033491f584a2d79697da714b1ef9d6b27d22 Mon Sep 17 00:00:00 2001 +From: Andre Noll +Date: Tue, 31 Mar 2009 15:00:56 +1100 +Subject: [PATCH] md: raid5 run(): Fix max_degraded for raid level 4. + +raid4 allows only one failed disk. + +Signed-off-by: Andre Noll +Signed-off-by: NeilBrown +--- + drivers/md/raid5.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -4200,7 +4200,7 @@ static int run(mddev_t *mddev) + */ + sector_t here_new, here_old; + int old_disks; +- int max_degraded = (mddev->level == 5 ? 1 : 2); ++ int max_degraded = (mddev->level == 6 ? 2 : 1); + + if (mddev->new_level != mddev->level || + mddev->new_layout != mddev->layout || diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0019-md-allow-setting-newly-added-device-to-in_sync-via-s.patch b/src/patches/suse-2.6.27.31/patches.fixes/0019-md-allow-setting-newly-added-device-to-in_sync-via-s.patch new file mode 100644 index 000000000..841551aad --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0019-md-allow-setting-newly-added-device-to-in_sync-via-s.patch @@ -0,0 +1,45 @@ +From 6d56e278444bc8323b1bcfcada126b8e4dbba0f4 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 14 Apr 2009 12:01:57 +1000 +Subject: [PATCH] md: allow setting newly added device to 'in_sync' via sysfs. + +When adding devices to an active array via sysfs, there is currently +no way to mark a device as 'in-sync' which is useful when +incrementally assembling an array. + +So add that option. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -1950,6 +1950,7 @@ state_store(mdk_rdev_t *rdev, const char + * -writemostly - clears write_mostly + * blocked - sets the Blocked flag + * -blocked - clears the Blocked flag ++ * insync - sets Insync providing device isn't active + */ + int err = -EINVAL; + if (cmd_match(buf, "faulty") && rdev->mddev->pers) { +@@ -1982,6 +1983,9 @@ state_store(mdk_rdev_t *rdev, const char + md_wakeup_thread(rdev->mddev->thread); + + err = 0; ++ } else if (cmd_match(buf, "insync") && rdev->raid_disk == -1) { ++ set_bit(In_sync, &rdev->flags); ++ err = 0; + } + if (!err) + sysfs_notify(&rdev->kobj, NULL, "state"); +@@ -2055,7 +2059,7 @@ slot_store(mdk_rdev_t *rdev, const char + mdk_rdev_t *rdev2; + struct list_head *tmp; + /* Activating a spare .. or possibly reactivating +- * if we every get bitmaps working here. ++ * if we ever get bitmaps working here. + */ + + if (rdev->raid_disk != -1) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0020-md-support-bitmaps-on-RAID10-arrays-larger-then-2-te.patch b/src/patches/suse-2.6.27.31/patches.fixes/0020-md-support-bitmaps-on-RAID10-arrays-larger-then-2-te.patch new file mode 100644 index 000000000..97363c01f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0020-md-support-bitmaps-on-RAID10-arrays-larger-then-2-te.patch @@ -0,0 +1,38 @@ +From 1f59390339f263c0fe7908fbe54466dbf3a64b58 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 20 Apr 2009 11:50:24 +1000 +Subject: [PATCH] md: support bitmaps on RAID10 arrays larger then 2 terabytes + +.. and other arrays with components larger than 2 terabytes. + +We use a "long" rather than a "sector_t" in part of the bitmap +size calculations, which is sad. + +Reported-by: "Mario 'BitKoenig' Holbe" +Signed-off-by: NeilBrown +--- + drivers/md/bitmap.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/md/bitmap.c ++++ b/drivers/md/bitmap.c +@@ -1587,7 +1587,7 @@ void bitmap_destroy(mddev_t *mddev) + int bitmap_create(mddev_t *mddev) + { + struct bitmap *bitmap; +- unsigned long blocks = mddev->resync_max_sectors; ++ sector_t blocks = mddev->resync_max_sectors; + unsigned long chunks; + unsigned long pages; + struct file *file = mddev->bitmap_file; +@@ -1629,8 +1629,8 @@ int bitmap_create(mddev_t *mddev) + bitmap->chunkshift = ffz(~bitmap->chunksize); + + /* now that chunksize and chunkshift are set, we can use these macros */ +- chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) / +- CHUNK_BLOCK_RATIO(bitmap); ++ chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) >> ++ CHUNK_BLOCK_SHIFT(bitmap); + pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO; + + BUG_ON(!pages); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0024-md-tidy-up-status_resync-to-handle-large-arrays.patch b/src/patches/suse-2.6.27.31/patches.fixes/0024-md-tidy-up-status_resync-to-handle-large-arrays.patch new file mode 100644 index 000000000..c94297d42 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0024-md-tidy-up-status_resync-to-handle-large-arrays.patch @@ -0,0 +1,123 @@ +From dd71cf6b2773310b01c6fe6c773064c80fd2476b Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Thu, 7 May 2009 12:49:35 +1000 +Subject: [PATCH] md: tidy up status_resync to handle large arrays. + +Two problems in status_resync. +1/ It still used Kilobytes as the basic block unit, while most code + now uses sectors uniformly. +2/ It doesn't allow for the possibility that max_sectors exceeds + the range of "unsigned long". + +So + - change "max_blocks" to "max_sectors", and store sector numbers + in there and in 'resync' + - Make 'rt' a 'sector_t' so it can temporarily hold the number of + remaining sectors. + - use sector_div rather than normal division. + - change the magic '100' used to preserve precision to '32'. + + making it a power of 2 makes division easier + + it doesn't need to be as large as it was chosen when we averaged + speed over the entire run. Now we average speed over the last 30 + seconds or so. + +Reported-by: "Mario 'BitKoenig' Holbe" +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 45 ++++++++++++++++++++++++++++----------------- + 1 file changed, 28 insertions(+), 17 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -5340,37 +5340,38 @@ static void status_unused(struct seq_fil + + static void status_resync(struct seq_file *seq, mddev_t * mddev) + { +- sector_t max_blocks, resync, res; +- unsigned long dt, db, rt; ++ sector_t max_sectors, resync, res; ++ unsigned long dt, db; ++ sector_t rt; + int scale; + unsigned int per_milli; + +- resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; ++ resync = mddev->curr_resync - atomic_read(&mddev->recovery_active); + + if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) +- max_blocks = mddev->resync_max_sectors >> 1; ++ max_sectors = mddev->resync_max_sectors; + else +- max_blocks = mddev->size; ++ max_sectors = mddev->size << 1; + + /* + * Should not happen. + */ +- if (!max_blocks) { ++ if (!max_sectors) { + MD_BUG(); + return; + } + /* Pick 'scale' such that (resync>>scale)*1000 will fit +- * in a sector_t, and (max_blocks>>scale) will fit in a ++ * in a sector_t, and (max_sectors>>scale) will fit in a + * u32, as those are the requirements for sector_div. + * Thus 'scale' must be at least 10 + */ + scale = 10; + if (sizeof(sector_t) > sizeof(unsigned long)) { +- while ( max_blocks/2 > (1ULL<<(scale+32))) ++ while ( max_sectors/2 > (1ULL<<(scale+32))) + scale++; + } + res = (resync>>scale)*1000; +- sector_div(res, (u32)((max_blocks>>scale)+1)); ++ sector_div(res, (u32)((max_sectors>>scale)+1)); + + per_milli = res; + { +@@ -5391,25 +5392,35 @@ static void status_resync(struct seq_fil + (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ? + "resync" : "recovery"))), + per_milli/10, per_milli % 10, +- (unsigned long long) resync, +- (unsigned long long) max_blocks); ++ (unsigned long long) resync/2, ++ (unsigned long long) max_sectors/2); + + /* +- * We do not want to overflow, so the order of operands and +- * the * 100 / 100 trick are important. We do a +1 to be +- * safe against division by zero. We only estimate anyway. +- * + * dt: time from mark until now + * db: blocks written from mark until now + * rt: remaining time ++ * ++ * rt is a sector_t, so could be 32bit or 64bit. ++ * So we divide before multiply in case it is 32bit and close ++ * to the limit. ++ * We scale the divisor (db) by 32 to avoid loosing precision ++ * near the end of resync when the number of remaining sectors ++ * is close to 'db'. ++ * We then divide rt by 32 after multiplying by db to compensate. ++ * The '+1' avoids division by zero if db is very small. + */ + dt = ((jiffies - mddev->resync_mark) / HZ); + if (!dt) dt++; + db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active)) + - mddev->resync_mark_cnt; +- rt = (dt * ((unsigned long)(max_blocks-resync) / (db/2/100+1)))/100; + +- seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); ++ rt = max_sectors - resync; /* number of remaining sectors */ ++ sector_div(rt, db/32+1); ++ rt *= dt; ++ rt >>= 5; ++ ++ seq_printf(seq, " finish=%lu.%lumin", (unsigned long)rt / 60, ++ ((unsigned long)rt % 60)/6); + + seq_printf(seq, " speed=%ldK/sec", db/2/dt); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0026-md-remove-rd-d-links-immediately-after-stopping-an-a.patch b/src/patches/suse-2.6.27.31/patches.fixes/0026-md-remove-rd-d-links-immediately-after-stopping-an-a.patch new file mode 100644 index 000000000..c370e1d4f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0026-md-remove-rd-d-links-immediately-after-stopping-an-a.patch @@ -0,0 +1,73 @@ +From c4647292fda0833bebe45be27f04453b736981fa Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Thu, 7 May 2009 12:51:06 +1000 +Subject: [PATCH] md: remove rd%d links immediately after stopping an array. + +md maintains link in sys/mdXX/md/ to identify which device has +which role in the array. e.g. + rd2 -> dev-sda + +indicates that the device with role '2' in the array is sda. + +These links are only present when the array is active. They are +created immediately after ->run is called, and so should be removed +immediately after ->stop is called. +However they are currently removed a little bit later, and it is +possible for ->run to be called again, thus adding these links, before +they are removed. + +So move the removal earlier so they are consistently only present when +the array is active. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -3960,6 +3960,7 @@ static int do_md_stop(mddev_t * mddev, i + { + int err = 0; + struct gendisk *disk = mddev->gendisk; ++ mdk_rdev_t *rdev; + + if (atomic_read(&mddev->openers) > is_open) { + printk("md: %s still in use.\n",mdname(mddev)); +@@ -4002,6 +4003,13 @@ static int do_md_stop(mddev_t * mddev, i + /* tell userspace to handle 'inactive' */ + sysfs_notify(&mddev->kobj, NULL, "array_state"); + ++ list_for_each_entry(rdev, &mddev->disks, same_set) ++ if (rdev->raid_disk >= 0) { ++ char nm[20]; ++ sprintf(nm, "rd%d", rdev->raid_disk); ++ sysfs_remove_link(&mddev->kobj, nm); ++ } ++ + set_capacity(disk, 0); + mddev->changed = 1; + +@@ -4022,8 +4030,6 @@ static int do_md_stop(mddev_t * mddev, i + * Free resources if final stop + */ + if (mode == 0) { +- mdk_rdev_t *rdev; +- struct list_head *tmp; + + printk(KERN_INFO "md: %s stopped.\n", mdname(mddev)); + +@@ -4035,13 +4041,6 @@ static int do_md_stop(mddev_t * mddev, i + } + mddev->bitmap_offset = 0; + +- rdev_for_each(rdev, tmp, mddev) +- if (rdev->raid_disk >= 0) { +- char nm[20]; +- sprintf(nm, "rd%d", rdev->raid_disk); +- sysfs_remove_link(&mddev->kobj, nm); +- } +- + /* make sure all md_delayed_delete calls have finished */ + flush_scheduled_work(); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0027-md-improve-errno-return-when-setting-array_size.patch b/src/patches/suse-2.6.27.31/patches.fixes/0027-md-improve-errno-return-when-setting-array_size.patch new file mode 100644 index 000000000..0ef1247e9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0027-md-improve-errno-return-when-setting-array_size.patch @@ -0,0 +1,27 @@ +From 2b69c83924396ad1eda36fdd267c9d2f360f5555 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 26 May 2009 09:41:17 +1000 +Subject: [PATCH] md: improve errno return when setting array_size + +Instead of always returns EINVAL if anything goes wrong +when setting the array size, add the option of + E2BIG +if the size requested is too large. This makes it easier +for user-space to be sure what went wrong. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -3449,7 +3449,7 @@ array_size_store(mddev_t *mddev, const c + if (strict_blocks_to_sectors(buf, §ors) < 0) + return -EINVAL; + if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) +- return -EINVAL; ++ return -E2BIG; + + mddev->external_size = 1; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0028-md-add-explicit-method-to-signal-the-end-of-a-reshap.patch b/src/patches/suse-2.6.27.31/patches.fixes/0028-md-add-explicit-method-to-signal-the-end-of-a-reshap.patch new file mode 100644 index 000000000..04d6c17fc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/0028-md-add-explicit-method-to-signal-the-end-of-a-reshap.patch @@ -0,0 +1,176 @@ +From cea9c22800773cecb1d41f4a6139f9eb6a95368b Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 31 Mar 2009 15:15:05 +1100 +Subject: [PATCH] md: add explicit method to signal the end of a reshape. + +Currently raid5 (the only module that supports restriping) +notices that the reshape has finished be sync_request being +given a large value, and handles any cleanup them. + +This patch changes it so md_check_recovery calls into an +explicit finish_reshape method as well. + +The clean-up from sync_request can do things that need to be +done promptly, typically things local to the raid5_conf_t +structure. + +The "finish_reshape" method is called under the mddev_lock +so it can do things involving reconfiguring the device. + +This allows us to get rid of md_set_array_sectors_locked, which +would have caused a deadlock if you tried to stop and array +while a reshape was happening. + +Signed-off-by: NeilBrown +--- + drivers/md/md.c | 11 ++-------- + drivers/md/raid5.c | 50 +++++++++++++++++++++++++++------------------- + include/linux/raid/md_k.h | 2 - + 3 files changed, 34 insertions(+), 29 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -4759,14 +4759,6 @@ void md_set_array_sectors(mddev_t *mddev + } + EXPORT_SYMBOL(md_set_array_sectors); + +-void md_set_array_sectors_lock(mddev_t *mddev, sector_t array_sectors) +-{ +- mddev_lock(mddev); +- md_set_array_sectors(mddev, array_sectors); +- mddev_unlock(mddev); +-} +-EXPORT_SYMBOL(md_set_array_sectors_lock); +- + static int update_size(mddev_t *mddev, sector_t num_sectors) + { + mdk_rdev_t * rdev; +@@ -6313,6 +6305,9 @@ void md_check_recovery(mddev_t *mddev) + sysfs_notify(&mddev->kobj, NULL, + "degraded"); + } ++ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && ++ mddev->pers->finish_reshape) ++ mddev->pers->finish_reshape(mddev); + md_update_sb(mddev, 1); + + /* if array is no-longer degraded, then any saved_raid_disk +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c +@@ -3853,6 +3853,7 @@ static inline sector_t sync_request(mdde + if (sector_nr >= max_sector) { + /* just being told to finish up .. nothing much to do */ + unplug_slaves(mddev); ++ + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { + end_reshape(conf); + return 0; +@@ -4798,43 +4799,49 @@ static int raid5_start_reshape(mddev_t * + + static void end_reshape(raid5_conf_t *conf) + { +- struct block_device *bdev; + + if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { +- mddev_t *mddev = conf->mddev; +- +- md_set_array_sectors_lock(mddev, raid5_size(mddev, 0, +- conf->raid_disks)); +- set_capacity(mddev->gendisk, mddev->array_sectors); +- mddev->changed = 1; +- conf->previous_raid_disks = conf->raid_disks; + +- bdev = bdget_disk(conf->mddev->gendisk, 0); +- if (bdev) { +- mutex_lock(&bdev->bd_inode->i_mutex); +- i_size_write(bdev->bd_inode, +- (loff_t)conf->mddev->array_sectors << 9); +- mutex_unlock(&bdev->bd_inode->i_mutex); +- bdput(bdev); +- } + spin_lock_irq(&conf->device_lock); ++ conf->previous_raid_disks = conf->raid_disks; + conf->expand_progress = MaxSector; + spin_unlock_irq(&conf->device_lock); +- conf->mddev->reshape_position = MaxSector; + + /* read-ahead size must cover two whole stripes, which is + * 2 * (datadisks) * chunksize where 'n' is the number of raid devices + */ + { +- int data_disks = conf->previous_raid_disks - conf->max_degraded; +- int stripe = data_disks * +- (conf->mddev->chunk_size / PAGE_SIZE); ++ int data_disks = conf->raid_disks - conf->max_degraded; ++ int stripe = data_disks * (conf->chunk_size ++ / PAGE_SIZE); + if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) + conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; + } + } + } + ++static void raid5_finish_reshape(mddev_t *mddev) ++{ ++ struct block_device *bdev; ++ ++ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { ++ ++ md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); ++ set_capacity(mddev->gendisk, mddev->array_sectors); ++ mddev->changed = 1; ++ mddev->reshape_position = MaxSector; ++ ++ bdev = bdget_disk(mddev->gendisk, 0); ++ if (bdev) { ++ mutex_lock(&bdev->bd_inode->i_mutex); ++ i_size_write(bdev->bd_inode, ++ (loff_t)mddev->array_sectors << 9); ++ mutex_unlock(&bdev->bd_inode->i_mutex); ++ bdput(bdev); ++ } ++ } ++} ++ + static void raid5_quiesce(mddev_t *mddev, int state) + { + raid5_conf_t *conf = mddev_to_conf(mddev); +@@ -4883,6 +4890,7 @@ static struct mdk_personality raid6_pers + #ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, ++ .finish_reshape = raid5_finish_reshape, + #endif + .quiesce = raid5_quiesce, + }; +@@ -4905,6 +4913,7 @@ static struct mdk_personality raid5_pers + #ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, ++ .finish_reshape = raid5_finish_reshape, + #endif + .quiesce = raid5_quiesce, + }; +@@ -4928,6 +4937,7 @@ static struct mdk_personality raid4_pers + #ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, ++ .finish_reshape = raid5_finish_reshape, + #endif + .quiesce = raid5_quiesce, + }; +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/md_k.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/md_k.h +@@ -310,6 +310,7 @@ struct mdk_personality + sector_t (*size) (mddev_t *mddev, sector_t sectors, int raid_disks); + int (*check_reshape) (mddev_t *mddev); + int (*start_reshape) (mddev_t *mddev); ++ void (*finish_reshape) (mddev_t *mddev); + int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); + /* quiesce moves between quiescence states + * 0 - fully active +@@ -396,4 +397,3 @@ static inline void safe_put_page(struct + #endif /* CONFIG_BLOCK */ + #endif + +-extern void md_set_array_sectors_lock(mddev_t *mddev, sector_t array_sectors); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/Hibernate-Take-overlapping-zones-into-account-rev-2.patch b/src/patches/suse-2.6.27.31/patches.fixes/Hibernate-Take-overlapping-zones-into-account-rev-2.patch new file mode 100644 index 000000000..2eff84f04 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/Hibernate-Take-overlapping-zones-into-account-rev-2.patch @@ -0,0 +1,547 @@ +From: Rafael J. Wysocki +Subject: Hibernate: Take overlapping zones into account (rev. 2) +References: bnc#438914 +Patch-mainline: 846705deb059c352cc0e5806d5964f815b8c6d98 + +It has been requested to make hibernation work with memory +hotplugging enabled and for this purpose the hibernation code has to +be reworked to take the possible overlapping of zones into account. +Thus, rework the hibernation memory bitmaps code to prevent +duplication of PFNs from occuring and add checks to make sure that +one page frame will not be marked as saveable many times. + +Additionally, use list.h lists instead of open-coded lists to +implement the memory bitmaps. + +Signed-off-by: Rafael J. Wysocki +--- + kernel/power/snapshot.c | 327 ++++++++++++++++++++++++------------------------ + 1 file changed, 167 insertions(+), 160 deletions(-) + +Index: linux-2.6.27/kernel/power/snapshot.c +=================================================================== +--- linux-2.6.27.orig/kernel/power/snapshot.c ++++ linux-2.6.27/kernel/power/snapshot.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -192,12 +193,6 @@ static void *chain_alloc(struct chain_al + return ret; + } + +-static void chain_free(struct chain_allocator *ca, int clear_page_nosave) +-{ +- free_list_of_pages(ca->chain, clear_page_nosave); +- memset(ca, 0, sizeof(struct chain_allocator)); +-} +- + /** + * Data types related to memory bitmaps. + * +@@ -233,7 +228,7 @@ static void chain_free(struct chain_allo + #define BM_BITS_PER_BLOCK (PAGE_SIZE << 3) + + struct bm_block { +- struct bm_block *next; /* next element of the list */ ++ struct list_head hook; /* hook into a list of bitmap blocks */ + unsigned long start_pfn; /* pfn represented by the first bit */ + unsigned long end_pfn; /* pfn represented by the last bit plus 1 */ + unsigned long *data; /* bitmap representing pages */ +@@ -244,24 +239,15 @@ static inline unsigned long bm_block_bit + return bb->end_pfn - bb->start_pfn; + } + +-struct zone_bitmap { +- struct zone_bitmap *next; /* next element of the list */ +- unsigned long start_pfn; /* minimal pfn in this zone */ +- unsigned long end_pfn; /* maximal pfn in this zone plus 1 */ +- struct bm_block *bm_blocks; /* list of bitmap blocks */ +- struct bm_block *cur_block; /* recently used bitmap block */ +-}; +- + /* strcut bm_position is used for browsing memory bitmaps */ + + struct bm_position { +- struct zone_bitmap *zone_bm; + struct bm_block *block; + int bit; + }; + + struct memory_bitmap { +- struct zone_bitmap *zone_bm_list; /* list of zone bitmaps */ ++ struct list_head blocks; /* list of bitmap blocks */ + struct linked_page *p_list; /* list of pages used to store zone + * bitmap objects and bitmap block + * objects +@@ -273,11 +259,7 @@ struct memory_bitmap { + + static void memory_bm_position_reset(struct memory_bitmap *bm) + { +- struct zone_bitmap *zone_bm; +- +- zone_bm = bm->zone_bm_list; +- bm->cur.zone_bm = zone_bm; +- bm->cur.block = zone_bm->bm_blocks; ++ bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook); + bm->cur.bit = 0; + } + +@@ -285,151 +267,184 @@ static void memory_bm_free(struct memory + + /** + * create_bm_block_list - create a list of block bitmap objects +- */ +- +-static inline struct bm_block * +-create_bm_block_list(unsigned int nr_blocks, struct chain_allocator *ca) ++ * @nr_blocks - number of blocks to allocate ++ * @list - list to put the allocated blocks into ++ * @ca - chain allocator to be used for allocating memory ++ */ ++static int create_bm_block_list(unsigned long pages, ++ struct list_head *list, ++ struct chain_allocator *ca) + { +- struct bm_block *bblist = NULL; ++ unsigned int nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK); + + while (nr_blocks-- > 0) { + struct bm_block *bb; + + bb = chain_alloc(ca, sizeof(struct bm_block)); + if (!bb) +- return NULL; +- +- bb->next = bblist; +- bblist = bb; ++ return -ENOMEM; ++ list_add(&bb->hook, list); + } +- return bblist; ++ ++ return 0; + } + ++struct mem_extent { ++ struct list_head hook; ++ unsigned long start; ++ unsigned long end; ++}; ++ + /** +- * create_zone_bm_list - create a list of zone bitmap objects ++ * free_mem_extents - free a list of memory extents ++ * @list - list of extents to empty + */ ++static void free_mem_extents(struct list_head *list) ++{ ++ struct mem_extent *ext, *aux; + +-static inline struct zone_bitmap * +-create_zone_bm_list(unsigned int nr_zones, struct chain_allocator *ca) ++ list_for_each_entry_safe(ext, aux, list, hook) { ++ list_del(&ext->hook); ++ kfree(ext); ++ } ++} ++ ++/** ++ * create_mem_extents - create a list of memory extents representing ++ * contiguous ranges of PFNs ++ * @list - list to put the extents into ++ * @gfp_mask - mask to use for memory allocations ++ */ ++static int create_mem_extents(struct list_head *list, gfp_t gfp_mask) + { +- struct zone_bitmap *zbmlist = NULL; ++ struct zone *zone; + +- while (nr_zones-- > 0) { +- struct zone_bitmap *zbm; ++ INIT_LIST_HEAD(list); + +- zbm = chain_alloc(ca, sizeof(struct zone_bitmap)); +- if (!zbm) +- return NULL; ++ for_each_zone(zone) { ++ unsigned long zone_start, zone_end; ++ struct mem_extent *ext, *cur, *aux; ++ ++ if (!populated_zone(zone)) ++ continue; ++ ++ zone_start = zone->zone_start_pfn; ++ zone_end = zone->zone_start_pfn + zone->spanned_pages; ++ ++ list_for_each_entry(ext, list, hook) ++ if (zone_start <= ext->end) ++ break; ++ ++ if (&ext->hook == list || zone_end < ext->start) { ++ /* New extent is necessary */ ++ struct mem_extent *new_ext; ++ ++ new_ext = kzalloc(sizeof(struct mem_extent), gfp_mask); ++ if (!new_ext) { ++ free_mem_extents(list); ++ return -ENOMEM; ++ } ++ new_ext->start = zone_start; ++ new_ext->end = zone_end; ++ list_add_tail(&new_ext->hook, &ext->hook); ++ continue; ++ } + +- zbm->next = zbmlist; +- zbmlist = zbm; ++ /* Merge this zone's range of PFNs with the existing one */ ++ if (zone_start < ext->start) ++ ext->start = zone_start; ++ if (zone_end > ext->end) ++ ext->end = zone_end; ++ ++ /* More merging may be possible */ ++ cur = ext; ++ list_for_each_entry_safe_continue(cur, aux, list, hook) { ++ if (zone_end < cur->start) ++ break; ++ if (zone_end < cur->end) ++ ext->end = cur->end; ++ list_del(&cur->hook); ++ kfree(cur); ++ } + } +- return zbmlist; ++ ++ return 0; + } + + /** + * memory_bm_create - allocate memory for a memory bitmap + */ +- + static int + memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) + { + struct chain_allocator ca; +- struct zone *zone; +- struct zone_bitmap *zone_bm; +- struct bm_block *bb; +- unsigned int nr; ++ struct list_head mem_extents; ++ struct mem_extent *ext; ++ int error; + + chain_init(&ca, gfp_mask, safe_needed); ++ INIT_LIST_HEAD(&bm->blocks); + +- /* Compute the number of zones */ +- nr = 0; +- for_each_zone(zone) +- if (populated_zone(zone)) +- nr++; +- +- /* Allocate the list of zones bitmap objects */ +- zone_bm = create_zone_bm_list(nr, &ca); +- bm->zone_bm_list = zone_bm; +- if (!zone_bm) { +- chain_free(&ca, PG_UNSAFE_CLEAR); +- return -ENOMEM; +- } ++ error = create_mem_extents(&mem_extents, gfp_mask); ++ if (error) ++ return error; + +- /* Initialize the zone bitmap objects */ +- for_each_zone(zone) { +- unsigned long pfn; ++ list_for_each_entry(ext, &mem_extents, hook) { ++ struct bm_block *bb; ++ unsigned long pfn = ext->start; ++ unsigned long pages = ext->end - ext->start; + +- if (!populated_zone(zone)) +- continue; ++ bb = list_entry(bm->blocks.prev, struct bm_block, hook); + +- zone_bm->start_pfn = zone->zone_start_pfn; +- zone_bm->end_pfn = zone->zone_start_pfn + zone->spanned_pages; +- /* Allocate the list of bitmap block objects */ +- nr = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); +- bb = create_bm_block_list(nr, &ca); +- zone_bm->bm_blocks = bb; +- zone_bm->cur_block = bb; +- if (!bb) +- goto Free; ++ error = create_bm_block_list(pages, bm->blocks.prev, &ca); ++ if (error) ++ goto Error; + +- nr = zone->spanned_pages; +- pfn = zone->zone_start_pfn; +- /* Initialize the bitmap block objects */ +- while (bb) { +- unsigned long *ptr; +- +- ptr = get_image_page(gfp_mask, safe_needed); +- bb->data = ptr; +- if (!ptr) +- goto Free; ++ list_for_each_entry_continue(bb, &bm->blocks, hook) { ++ bb->data = get_image_page(gfp_mask, safe_needed); ++ if (!bb->data) { ++ error = -ENOMEM; ++ goto Error; ++ } + + bb->start_pfn = pfn; +- if (nr >= BM_BITS_PER_BLOCK) { ++ if (pages >= BM_BITS_PER_BLOCK) { + pfn += BM_BITS_PER_BLOCK; +- nr -= BM_BITS_PER_BLOCK; ++ pages -= BM_BITS_PER_BLOCK; + } else { + /* This is executed only once in the loop */ +- pfn += nr; ++ pfn += pages; + } + bb->end_pfn = pfn; +- bb = bb->next; + } +- zone_bm = zone_bm->next; + } ++ + bm->p_list = ca.chain; + memory_bm_position_reset(bm); +- return 0; ++ Exit: ++ free_mem_extents(&mem_extents); ++ return error; + +- Free: ++ Error: + bm->p_list = ca.chain; + memory_bm_free(bm, PG_UNSAFE_CLEAR); +- return -ENOMEM; ++ goto Exit; + } + + /** + * memory_bm_free - free memory occupied by the memory bitmap @bm + */ +- + static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) + { +- struct zone_bitmap *zone_bm; ++ struct bm_block *bb; + +- /* Free the list of bit blocks for each zone_bitmap object */ +- zone_bm = bm->zone_bm_list; +- while (zone_bm) { +- struct bm_block *bb; ++ list_for_each_entry(bb, &bm->blocks, hook) ++ if (bb->data) ++ free_image_page(bb->data, clear_nosave_free); + +- bb = zone_bm->bm_blocks; +- while (bb) { +- if (bb->data) +- free_image_page(bb->data, clear_nosave_free); +- bb = bb->next; +- } +- zone_bm = zone_bm->next; +- } + free_list_of_pages(bm->p_list, clear_nosave_free); +- bm->zone_bm_list = NULL; ++ ++ INIT_LIST_HEAD(&bm->blocks); + } + + /** +@@ -437,38 +452,33 @@ static void memory_bm_free(struct memory + * to given pfn. The cur_zone_bm member of @bm and the cur_block member + * of @bm->cur_zone_bm are updated. + */ +- + static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, + void **addr, unsigned int *bit_nr) + { +- struct zone_bitmap *zone_bm; + struct bm_block *bb; + +- /* Check if the pfn is from the current zone */ +- zone_bm = bm->cur.zone_bm; +- if (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) { +- zone_bm = bm->zone_bm_list; +- /* We don't assume that the zones are sorted by pfns */ +- while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) { +- zone_bm = zone_bm->next; +- +- if (!zone_bm) +- return -EFAULT; +- } +- bm->cur.zone_bm = zone_bm; +- } +- /* Check if the pfn corresponds to the current bitmap block */ +- bb = zone_bm->cur_block; ++ /* ++ * Check if the pfn corresponds to the current bitmap block and find ++ * the block where it fits if this is not the case. ++ */ ++ bb = bm->cur.block; + if (pfn < bb->start_pfn) +- bb = zone_bm->bm_blocks; ++ list_for_each_entry_continue_reverse(bb, &bm->blocks, hook) ++ if (pfn >= bb->start_pfn) ++ break; ++ ++ if (pfn >= bb->end_pfn) ++ list_for_each_entry_continue(bb, &bm->blocks, hook) ++ if (pfn >= bb->start_pfn && pfn < bb->end_pfn) ++ break; + +- while (pfn >= bb->end_pfn) { +- bb = bb->next; ++ if (&bb->hook == &bm->blocks) ++ return -EFAULT; + +- BUG_ON(!bb); +- } +- zone_bm->cur_block = bb; ++ /* The block has been found */ ++ bm->cur.block = bb; + pfn -= bb->start_pfn; ++ bm->cur.bit = pfn + 1; + *bit_nr = pfn; + *addr = bb->data; + return 0; +@@ -530,29 +540,21 @@ static int memory_bm_test_bit(struct mem + + static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) + { +- struct zone_bitmap *zone_bm; + struct bm_block *bb; + int bit; + ++ bb = bm->cur.block; + do { +- bb = bm->cur.block; +- do { +- bit = bm->cur.bit; +- bit = find_next_bit(bb->data, bm_block_bits(bb), bit); +- if (bit < bm_block_bits(bb)) +- goto Return_pfn; +- +- bb = bb->next; +- bm->cur.block = bb; +- bm->cur.bit = 0; +- } while (bb); +- zone_bm = bm->cur.zone_bm->next; +- if (zone_bm) { +- bm->cur.zone_bm = zone_bm; +- bm->cur.block = zone_bm->bm_blocks; +- bm->cur.bit = 0; +- } +- } while (zone_bm); ++ bit = bm->cur.bit; ++ bit = find_next_bit(bb->data, bm_block_bits(bb), bit); ++ if (bit < bm_block_bits(bb)) ++ goto Return_pfn; ++ ++ bb = list_entry(bb->hook.next, struct bm_block, hook); ++ bm->cur.block = bb; ++ bm->cur.bit = 0; ++ } while (&bb->hook != &bm->blocks); ++ + memory_bm_position_reset(bm); + return BM_END_OF_MAP; + +@@ -808,8 +810,7 @@ static unsigned int count_free_highmem_p + * We should save the page if it isn't Nosave or NosaveFree, or Reserved, + * and it isn't a part of a free chunk of pages. + */ +- +-static struct page *saveable_highmem_page(unsigned long pfn) ++static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) + { + struct page *page; + +@@ -817,6 +818,8 @@ static struct page *saveable_highmem_pag + return NULL; + + page = pfn_to_page(pfn); ++ if (page_zone(page) != zone) ++ return NULL; + + BUG_ON(!PageHighMem(page)); + +@@ -846,13 +849,16 @@ unsigned int count_highmem_pages(void) + mark_free_pages(zone); + max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) +- if (saveable_highmem_page(pfn)) ++ if (saveable_highmem_page(zone, pfn)) + n++; + } + return n; + } + #else +-static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; } ++static inline void *saveable_highmem_page(struct zone *z, unsigned long p) ++{ ++ return NULL; ++} + #endif /* CONFIG_HIGHMEM */ + + /** +@@ -863,8 +869,7 @@ static inline void *saveable_highmem_pag + * of pages statically defined as 'unsaveable', and it isn't a part of + * a free chunk of pages. + */ +- +-static struct page *saveable_page(unsigned long pfn) ++static struct page *saveable_page(struct zone *zone, unsigned long pfn) + { + struct page *page; + +@@ -872,6 +877,8 @@ static struct page *saveable_page(unsign + return NULL; + + page = pfn_to_page(pfn); ++ if (page_zone(page) != zone) ++ return NULL; + + BUG_ON(PageHighMem(page)); + +@@ -903,7 +910,7 @@ unsigned int count_data_pages(void) + mark_free_pages(zone); + max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; + for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) +- if(saveable_page(pfn)) ++ if (saveable_page(zone, pfn)) + n++; + } + return n; +@@ -944,7 +951,7 @@ static inline struct page * + page_is_saveable(struct zone *zone, unsigned long pfn) + { + return is_highmem(zone) ? +- saveable_highmem_page(pfn) : saveable_page(pfn); ++ saveable_highmem_page(zone, pfn) : saveable_page(zone, pfn); + } + + static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) +@@ -975,7 +982,7 @@ static void copy_data_page(unsigned long + } + } + #else +-#define page_is_saveable(zone, pfn) saveable_page(pfn) ++#define page_is_saveable(zone, pfn) saveable_page(zone, pfn) + + static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/NFSv4-Fix-an-Oops-in-nfs4_free_lock_state.patch b/src/patches/suse-2.6.27.31/patches.fixes/NFSv4-Fix-an-Oops-in-nfs4_free_lock_state.patch new file mode 100644 index 000000000..0fadf39fa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/NFSv4-Fix-an-Oops-in-nfs4_free_lock_state.patch @@ -0,0 +1,38 @@ +Patch-mainline: 2.6.31 +From: b64aec8d1e1d8482a7b6cca60c8105c756bf1fe4 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Tue, 21 Jul 2009 16:47:46 -0400 +Subject: [PATCH] NFSv4: Fix an Oops in nfs4_free_lock_state + +The oops http://www.kerneloops.org/raw.php?rawid=537858&msgid= appears to +be due to the nfs4_lock_state->ls_state field being uninitialised. This +happens if the call to nfs4_free_lock_state() is triggered at the end of +nfs4_get_lock_state(). + +The fix is to move the initialisation of ls_state into the allocator. + +Signed-off-by: Trond Myklebust +Acked-by: NeilBrown + +--- + fs/nfs/nfs4state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/nfs4state.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs4state.c +@@ -545,6 +545,7 @@ static struct nfs4_lock_state *nfs4_allo + INIT_LIST_HEAD(&lsp->ls_sequence.list); + lsp->ls_seqid.sequence = &lsp->ls_sequence; + atomic_set(&lsp->ls_count, 1); ++ lsp->ls_state = state; + lsp->ls_owner = fl_owner; + spin_lock(&clp->cl_lock); + nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); +@@ -580,7 +581,6 @@ static struct nfs4_lock_state *nfs4_get_ + if (lsp != NULL) + break; + if (new != NULL) { +- new->ls_state = state; + list_add(&new->ls_locks, &state->lock_states); + set_bit(LK_STATE_IN_USE, &state->flags); + lsp = new; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/acpi_assure_unique_processor_proc_creation.patch b/src/patches/suse-2.6.27.31/patches.fixes/acpi_assure_unique_processor_proc_creation.patch new file mode 100644 index 000000000..43c6d19c5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/acpi_assure_unique_processor_proc_creation.patch @@ -0,0 +1,71 @@ +From: Zhao Yakui +Subject: ACPI: Rename ACPI processor device bus ID +References: bnc#528769 +Patch-Mainline: yes +Commit-ID: 7a04b8491a077471a34938b8ca060c37220953be + +Signed-off-by: Thomas Renninger + +Some BIOS re-use the same processor bus id +in different scope: + + \_SB.SCK0.CPU0 + \_SB.SCK1.CPU0 + +But the (deprecated) /proc/acpi/ interface +assumes the bus-id's are unique, resulting in an OOPS +when the processor driver is loaded: + +WARNING: at fs/proc/generic.c:590 proc_register+0x148/0x180() +Hardware name: Sunrise Ridge +proc_dir_entry 'processor/CPU0' already registered +Call Trace: + [] warn_slowpath+0xb1/0xe5 + [] ? ida_get_new_above+0x190/0x1b1 + [] ? idr_pre_get+0x5f/0x75 + [] proc_register+0x148/0x180 + [] proc_mkdir_mode+0x3d/0x52 + [] proc_mkdir+0x11/0x13 + [] acpi_processor_start+0x755/0x9bc [processor] + +Rename the processor device bus id. And the new bus id will be +generated as the following format: + CPU+ CPU ID + +For example: If the cpu ID is 5, then the bus ID will be "CPU5". + If the CPU ID is 10, then the bus ID will be "CPUA". + +Yes, this will change the directory names seen +in /proc/acpi/processor/* on some systems. +Before this patch, those directory names where +totally arbitrary strings based on the interal AML device strings. + +http://bugzilla.kernel.org/show_bug.cgi?id=13612 + +Signed-off-by: Zhao Yakui +Signed-off-by: Len Brown + +--- + drivers/acpi/processor_core.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/acpi/processor_core.c ++++ b/drivers/acpi/processor_core.c +@@ -624,7 +624,16 @@ static int acpi_processor_get_info(struc + return -ENODEV; + } + } +- ++ /* ++ * On some boxes several processors use the same processor bus id. ++ * But they are located in different scope. For example: ++ * \_SB.SCK0.CPU0 ++ * \_SB.SCK1.CPU0 ++ * Rename the processor device bus id. And the new bus id will be ++ * generated as the following format: ++ * CPU+CPU ID. ++ */ ++ sprintf(acpi_device_bid(device), "CPU%X", pr->id); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, + pr->acpi_id)); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/acpi_use_acpi_exception.patch b/src/patches/suse-2.6.27.31/patches.fixes/acpi_use_acpi_exception.patch new file mode 100644 index 000000000..8f2afa703 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/acpi_use_acpi_exception.patch @@ -0,0 +1,38 @@ +From: Thomas Renninger +Subject: ACPI dock/bay: Use ACPI_EXCEPTION instead of printk(KERN_ERR +Patch-Mainline: not yet + +Getting this error: +ACPI: \_SB_.PCI0.IDE1.PRI_.MAST: found ejectable bay +ACPI: \_SB_.PCI0.IDE1.PRI_.MAST: Adding notify handler +ACPI: Error installing bay notify handler + +there could be various reasons why installing the notify handler failed. +It is expected that the dock driver already has installed the notify +handler for this device, but this is not clear. +printk suppresses this information. +The return value of the previous called and failed acpica function +holds this information and should be printed using ACPI_EXCEPTION which +is designed for printing error messages on failed acpica calls. + +IMO this should get documented in Documentation/acpi/..., but I +was unsure whether it's worth to start a acpi_programming_rules.txt +(couldn't think of much more ading there for now) or +whether it's worth to add print_acpica_errors_in_kernel_drivers.txt +(or similar). + +--- + +--- linux-2.6.26.orig/drivers/acpi/dock.c 2008-09-25 22:48:33.000000000 +0200 ++++ linux-2.6.26/drivers/acpi/dock.c 2008-09-25 22:49:41.000000000 +0200 +@@ -488,8 +488,8 @@ + arg.integer.value = dock; + status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) +- printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", +- (char *)name_buffer.pointer); ++ ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute" ++ " _DCK\n", (char *)name_buffer.pointer)); + kfree(buffer.pointer); + kfree(name_buffer.pointer); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/aggressive-zone-reclaim.patch b/src/patches/suse-2.6.27.31/patches.fixes/aggressive-zone-reclaim.patch new file mode 100644 index 000000000..fcdec96bd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/aggressive-zone-reclaim.patch @@ -0,0 +1,66 @@ +From: Nick Piggin +Subject: be more aggressive with zone reclaims +References: bnc#476525 +Patch-mainline: no + +The zone reclaim design is not very good for parallel allocations. +The primary problem is that only one thread is allowed to perform +zone-reclaim at a time. If another thread needs memory from that +zone/node, then its zone-reclaim will fail and it will be forced +to fall back to allocating from another zone. + +Additionally, the default zone reclaim priority is insufficient +for massively parallel allocations. Lower ZONE_RECLAIM_PRIORITY +to fix it. This can result in higher latency spikes, but similar +kind of page allocation latency can often be encountered as +normal part of page reclaim when pagecache fills memory. + +Signed-off-by: Petr Tesarik + +--- + mm/vmscan.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/mm/vmscan.c 2008-10-20 17:24:19.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/mm/vmscan.c 2009-06-29 12:59:09.000000000 +0200 +@@ -1988,7 +1988,7 @@ int zone_reclaim_mode __read_mostly; + * of a node considered for each zone_reclaim. 4 scans 1/16th of + * a zone. + */ +-#define ZONE_RECLAIM_PRIORITY 4 ++#define ZONE_RECLAIM_PRIORITY 0 + + /* + * Percentage of pages in a zone that must be unmapped for zone_reclaim to +@@ -2052,6 +2052,8 @@ static int __zone_reclaim(struct zone *z + + slab_reclaimable = zone_page_state(zone, NR_SLAB_RECLAIMABLE); + if (slab_reclaimable > zone->min_slab_pages) { ++ unsigned long lru_pages = zone_page_state(zone, NR_ACTIVE) ++ + zone_page_state(zone, NR_INACTIVE); + /* + * shrink_slab() does not currently allow us to determine how + * many pages were freed in this zone. So we take the current +@@ -2062,10 +2064,7 @@ static int __zone_reclaim(struct zone *z + * Note that shrink_slab will free memory on all zones and may + * take a long time. + */ +- while (shrink_slab(sc.nr_scanned, gfp_mask, order) && +- zone_page_state(zone, NR_SLAB_RECLAIMABLE) > +- slab_reclaimable - nr_pages) +- ; ++ shrink_slab(sc.nr_scanned, gfp_mask, lru_pages); + + /* + * Update nr_reclaimed by the number of slab pages we +@@ -2120,10 +2119,7 @@ int zone_reclaim(struct zone *zone, gfp_ + if (node_state(node_id, N_CPU) && node_id != numa_node_id()) + return 0; + +- if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED)) +- return 0; + ret = __zone_reclaim(zone, gfp_mask, order); +- zone_clear_flag(zone, ZONE_RECLAIM_LOCKED); + + return ret; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/aic7xxx-leaves-timer-running-on-init-failure b/src/patches/suse-2.6.27.31/patches.fixes/aic7xxx-leaves-timer-running-on-init-failure new file mode 100644 index 000000000..bc94ef773 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/aic7xxx-leaves-timer-running-on-init-failure @@ -0,0 +1,61 @@ +From: Hannes Reinecke +Date: Wed, 25 Mar 2009 11:18:16 +0100 +Subject: aic7xxx leaves timer running on init failure +References: bnc#469576 + +aic79xx leaves timers inserted when ahd_init() (which inserts +two timers at its very end) succeeds but ahd_pci_map_int() +fails. In this case ahd->init_level gets incremented to 5 only +when that function succeeds, but ahd_free() calls ahd_shutdown() +only when ahd->init_level == 5, and ahd_shutdown() is where the +timers get removed. Since the freeing of the IRQ is not controlled +by ahd->init_level, we should increment init_level prior to +calling ahd_pci_map_int(). + +Reported-by: Jan Beulich +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/aic7xxx/aic79xx_pci.c | 6 ++---- + drivers/scsi/aic7xxx/aic7xxx_pci.c | 8 ++------ + 2 files changed, 4 insertions(+), 10 deletions(-) + +--- a/drivers/scsi/aic7xxx/aic79xx_pci.c ++++ b/drivers/scsi/aic7xxx/aic79xx_pci.c +@@ -379,14 +379,12 @@ ahd_pci_config(struct ahd_softc *ahd, co + error = ahd_init(ahd); + if (error != 0) + return (error); ++ ahd->init_level++; + + /* + * Allow interrupts now that we are completely setup. + */ +- error = ahd_pci_map_int(ahd); +- if (!error) +- ahd->init_level++; +- return error; ++ return ahd_pci_map_int(ahd); + } + + #ifdef CONFIG_PM +--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c ++++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c +@@ -960,16 +960,12 @@ ahc_pci_config(struct ahc_softc *ahc, co + error = ahc_init(ahc); + if (error != 0) + return (error); ++ ahc->init_level++; + + /* + * Allow interrupts now that we are completely setup. + */ +- error = ahc_pci_map_int(ahc); +- if (error != 0) +- return (error); +- +- ahc->init_level++; +- return (0); ++ return ahc_pci_map_int(ahc); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/altstack-avoid-copying-stack_t-as-a-structure-to-userspace b/src/patches/suse-2.6.27.31/patches.fixes/altstack-avoid-copying-stack_t-as-a-structure-to-userspace new file mode 100644 index 000000000..e15279999 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/altstack-avoid-copying-stack_t-as-a-structure-to-userspace @@ -0,0 +1,66 @@ +From: Linus Torvalds +Date: Sat, 1 Aug 2009 17:34:56 +0000 (-0700) +Subject: do_sigaltstack: avoid copying 'stack_t' as a structure to user space +Git-commit: 0083fc2c50e6c5127c2802ad323adf8143ab7856 +Patch-mainline: 2.6.31 +References: bnc#527848 + +do_sigaltstack: avoid copying 'stack_t' as a structure to user space + +Ulrich Drepper correctly points out that there is generally padding in +the structure on 64-bit hosts, and that copying the structure from +kernel to user space can leak information from the kernel stack in those +padding bytes. + +Avoid the whole issue by just copying the three members one by one +instead, which also means that the function also can avoid the need for +a stack frame. This also happens to match how we copy the new structure +from user space, so it all even makes sense. + +[ The obvious solution of adding a memset() generates horrid code, gcc + does really stupid things. ] + +Reported-by: Ulrich Drepper +Signed-off-by: Linus Torvalds +Acked-by: Jeff Mahoney +--- + + kernel/signal.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -2353,11 +2353,9 @@ do_sigaltstack (const stack_t __user *us + stack_t oss; + int error; + +- if (uoss) { +- oss.ss_sp = (void __user *) current->sas_ss_sp; +- oss.ss_size = current->sas_ss_size; +- oss.ss_flags = sas_ss_flags(sp); +- } ++ oss.ss_sp = (void __user *) current->sas_ss_sp; ++ oss.ss_size = current->sas_ss_size; ++ oss.ss_flags = sas_ss_flags(sp); + + if (uss) { + void __user *ss_sp; +@@ -2400,13 +2398,16 @@ do_sigaltstack (const stack_t __user *us + current->sas_ss_size = ss_size; + } + ++ error = 0; + if (uoss) { + error = -EFAULT; +- if (copy_to_user(uoss, &oss, sizeof(oss))) ++ if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) + goto out; ++ error = __put_user(oss.ss_sp, &uoss->ss_sp) | ++ __put_user(oss.ss_size, &uoss->ss_size) | ++ __put_user(oss.ss_flags, &uoss->ss_flags); + } + +- error = 0; + out: + return error; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ath5k-5211-protected-fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/ath5k-5211-protected-fix.patch new file mode 100644 index 000000000..6035268d5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ath5k-5211-protected-fix.patch @@ -0,0 +1,29 @@ +From 0f9a52f34d44a985dd9db9a1c7bdea9a52d0fff7 Mon Sep 17 00:00:00 2001 +From: Jiri Slaby +Date: Sat, 25 Apr 2009 12:36:41 +0200 +Subject: ath5k: 5211, don't crypt every protected frame +References: bnc#464360 + +Set null key type even on ar5211, otherwise it en/decrypts every frame with +protected bit set. + +Signed-off-by: Jiri Slaby +Cc: Luis R. Rodriguez +Cc: Bob Copeland +Acked-by: Nick Kossifidis +Signed-off-by: John W. Linville +--- + drivers/net/wireless/ath5k/hw.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath5k/hw.c ++++ b/drivers/net/wireless/ath5k/hw.c +@@ -3134,7 +3134,7 @@ int ath5k_hw_reset_key(struct ath5k_hw * + * Note2: Windows driver (ndiswrapper) sets this to + * 0x00000714 instead of 0x00000007 + */ +- if (ah->ah_version > AR5K_AR5211) ++ if (ah->ah_version >= AR5K_AR5211) + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(entry)); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ath5k-aspire-one-led.patch b/src/patches/suse-2.6.27.31/patches.fixes/ath5k-aspire-one-led.patch new file mode 100644 index 000000000..13fe163fa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ath5k-aspire-one-led.patch @@ -0,0 +1,52 @@ +From: Bob Copeland +Subject: ath5k: support LEDs on Acer Aspire One netbook +Patch-mainline: 2.6.30 +References: bnc#486728 + +Add vendor ID for Foxconn and use it to set the ath5k LED gpio and +polarity for Acer branded laptops. + +base.c: +Changes-licensed-under: 3-Clause-BSD + +Reported-by: Maxim Levitsky +Tested-by: Maxim Levitsky +Tested-by: Andreas Mohr +Signed-off-by: Bob Copeland +Signed-off-by: John W. Linville +Acked-by: Helmut Schaa +Acked-by: Jiri Benc + +--- + +diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c +index e4fe13e..9a7072e 100644 +--- a/drivers/net/wireless/ath5k/base.c ++++ b/drivers/net/wireless/ath5k/base.c +@@ -2593,6 +2593,13 @@ ath5k_init_leds(struct ath5k_softc *sc) + sc->led_pin = 1; + sc->led_on = 1; /* active high */ + } ++ /* Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) */ ++ if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN) { ++ __set_bit(ATH_STAT_LEDSOFT, sc->status); ++ sc->led_pin = 3; ++ sc->led_on = 0; /* active low */ ++ } ++ + if (!test_bit(ATH_STAT_LEDSOFT, sc->status)) + goto out; + +diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +index aca8c45..b574815 100644 +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -823,6 +823,8 @@ + #define PCI_DEVICE_ID_PROMISE_20276 0x5275 + #define PCI_DEVICE_ID_PROMISE_20277 0x7275 + ++#define PCI_VENDOR_ID_FOXCONN 0x105b ++ + #define PCI_VENDOR_ID_UMC 0x1060 + #define PCI_DEVICE_ID_UMC_UM8673F 0x0101 + #define PCI_DEVICE_ID_UMC_UM8886BF 0x673a diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ath5k-ignore-calibration-return-value.patch b/src/patches/suse-2.6.27.31/patches.fixes/ath5k-ignore-calibration-return-value.patch new file mode 100644 index 000000000..3717ff189 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ath5k-ignore-calibration-return-value.patch @@ -0,0 +1,50 @@ +From 8b0162a3dc5c30e862b7a73da29e32de3170f5e4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 3 Nov 2008 11:27:38 +0100 +Subject: [PATCH] ath5k: ignore the return value of ath5k_hw_noise_floor_calibration +References: bnc#446541 +Patch-mainline: 2.6.28-rc7 + +Noise floor calibration occasionally fails on Atheros hardware. +This is not fatal and can happen if there's simply too much +noise on the air. Ignoring the calibration error is the right +thing to do here, because when the error is ignored, the hardware +will still work, whereas if the error causes the driver to bail out +of a bigger configuration function and does not configure the tx +queues or the IMR (as is the case in reset.c), the hw no longer +works properly until the next reset. + +Signed-off-by: Felix Fietkau +Signed-off-by: John W. Linville +Signed-off-by: Jiri Slaby +--- + drivers/net/wireless/ath5k/hw.c | 4 +--- + drivers/net/wireless/ath5k/phy.c | 4 +--- + 2 files changed, 2 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ath5k/hw.c ++++ b/drivers/net/wireless/ath5k/hw.c +@@ -1131,9 +1131,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, + * + * XXX: Find an interval that's OK for all cards... + */ +- ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); +- if (ret) +- return ret; ++ ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + + /* + * Reset queues and start beacon timers at the end of the reset routine +--- a/drivers/net/wireless/ath5k/phy.c ++++ b/drivers/net/wireless/ath5k/phy.c +@@ -2193,9 +2193,7 @@ static int ath5k_hw_rf5110_calibrate(str + return ret; + } + +- ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); +- if (ret) +- return ret; ++ ath5k_hw_noise_floor_calibration(ah, channel->center_freq); + + /* + * Re-enable RX/TX and beacons diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-dont-invoke-request_fn-on-stopped-queue b/src/patches/suse-2.6.27.31/patches.fixes/blk-dont-invoke-request_fn-on-stopped-queue new file mode 100644 index 000000000..ba237225f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-dont-invoke-request_fn-on-stopped-queue @@ -0,0 +1,102 @@ +Subject: block: only call ->request_fn when the queue is not stopped +From: Jens Axboe +Date: Fri Oct 17 08:46:57 2008 +0200: +Git: 80a4b58e36b63d7b0b592beb1bd6410aadeeb63c +References: bnc#457041 + +Callers should use either blk_run_queue/__blk_run_queue, or +blk_start_queueing() to invoke request handling instead of calling +->request_fn() directly as that does not take the queue stopped +flag into account. + +Also add appropriate comments on the above functions to detail +their usage. + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 19 +++++++++++++++++-- + block/elevator.c | 7 +++---- + 2 files changed, 20 insertions(+), 6 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -324,6 +324,9 @@ EXPORT_SYMBOL(blk_unplug); + + static void blk_invoke_request_fn(struct request_queue *q) + { ++ if (unlikely(blk_queue_stopped(q))) ++ return; ++ + /* + * one level of recursion is ok and is much faster than kicking + * the unplug handling +@@ -399,8 +402,13 @@ void blk_sync_queue(struct request_queue + EXPORT_SYMBOL(blk_sync_queue); + + /** +- * blk_run_queue - run a single device queue ++ * __blk_run_queue - run a single device queue + * @q: The queue to run ++ * ++ * Description: ++ * See @blk_run_queue. This variant must be called with the queue lock ++ * held and interrupts disabled. ++ * + */ + void __blk_run_queue(struct request_queue *q) + { +@@ -418,6 +426,12 @@ EXPORT_SYMBOL(__blk_run_queue); + /** + * blk_run_queue - run a single device queue + * @q: The queue to run ++ * ++ * Description: ++ * Invoke request handling on this queue, if it has pending work to do. ++ * May be used to restart queueing when a request has completed. Also ++ * See @blk_start_queueing. ++ * + */ + void blk_run_queue(struct request_queue *q) + { +@@ -883,7 +897,8 @@ EXPORT_SYMBOL(blk_get_request); + * + * This is basically a helper to remove the need to know whether a queue + * is plugged or not if someone just wants to initiate dispatch of requests +- * for this queue. ++ * for this queue. Should be used to start queueing on a device outside ++ * of ->request_fn() context. Also see @blk_run_queue. + * + * The queue lock must be held with interrupts disabled. + */ +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -620,7 +620,7 @@ void elv_insert(struct request_queue *q, + * processing. + */ + blk_remove_plug(q); +- q->request_fn(q); ++ blk_start_queueing(q); + break; + + case ELEVATOR_INSERT_SORT: +@@ -951,7 +951,7 @@ void elv_completed_request(struct reques + blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN && + blk_ordered_req_seq(first_rq) > QUEUE_ORDSEQ_DRAIN) { + blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0); +- q->request_fn(q); ++ blk_start_queueing(q); + } + } + } +@@ -1110,8 +1110,7 @@ static int elevator_switch(struct reques + elv_drain_elevator(q); + + while (q->rq.elvpriv) { +- blk_remove_plug(q); +- q->request_fn(q); ++ blk_start_queueing(q); + spin_unlock_irq(q->queue_lock); + msleep(10); + spin_lock_irq(q->queue_lock); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-get-extra-reference-before-unmap b/src/patches/suse-2.6.27.31/patches.fixes/blk-get-extra-reference-before-unmap new file mode 100644 index 000000000..c3940abe5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-get-extra-reference-before-unmap @@ -0,0 +1,37 @@ +Subject: block: hold extra reference to bio in blk_rq_map_user_iov() +From: Jens Axboe +Date: Tue Nov 18 15:08:56 2008 +0100: +Git: c26156b2534c75bb3cdedf76f6ad1340971cf5bd + +If the size passed in is OK but we end up mapping too many segments, +we call the unmap path directly like from IO completion. But from IO +completion we have an extra reference to the bio, so this error case +goes OOPS when it attempts to free and already free bio. + +Fix it by getting an extra reference to the bio before calling the +unmap failure case. + +Reported-by: Petr Vandrovec + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-map.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/block/blk-map.c ++++ b/block/blk-map.c +@@ -202,6 +202,12 @@ int blk_rq_map_user_iov(struct request_q + return PTR_ERR(bio); + + if (bio->bi_size != len) { ++ /* ++ * Grab an extra reference to this bio, as bio_unmap_user() ++ * expects to be able to drop it twice as it happens on the ++ * normal IO completion path ++ */ ++ bio_get(bio); + bio_endio(bio, 0); + bio_unmap_user(bio); + return -EINVAL; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-leave-sync-timer-running b/src/patches/suse-2.6.27.31/patches.fixes/blk-leave-sync-timer-running new file mode 100644 index 000000000..2be6c85df --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-leave-sync-timer-running @@ -0,0 +1,51 @@ +From: Jens Axboe +Date: Wed, 19 Nov 2008 13:38:39 +0000 (+0100) +Subject: block: leave request timeout timer running on an empty list +References: bnc#447249 +X-Git-Tag: next-20081124~22^2~5 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fsfr%2Flinux-next.git;a=commitdiff_plain;h=4fc4d9c3fc9091db5a9fc534bd1c86bb338aff9f + +block: leave the request timeout timer running even on an empty list + +For sync IO, we'll often do them serialized. This means we'll be touching +the queue timer for every IO, as opposed to only occasionally like we +do for queued IO. Instead of deleting the timer when the last request +is removed, just let continue running. If a new request comes up soon +we then don't have to readd the timer again. If no new requests arrive, +the timer will expire without side effect later. + +This improves high iops sync IO by ~1%. + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + +--- + block/blk-core.c | 1 + + block/blk-timeout.c | 3 --- + 2 files changed, 1 insertion(+), 3 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -393,6 +393,7 @@ EXPORT_SYMBOL(blk_stop_queue); + void blk_sync_queue(struct request_queue *q) + { + del_timer_sync(&q->unplug_timer); ++ del_timer_sync(&q->timeout); + kblockd_flush_work(&q->unplug_work); + } + EXPORT_SYMBOL(blk_sync_queue); +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -14,11 +14,7 @@ + */ + void blk_delete_timer(struct request *req) + { +- struct request_queue *q = req->q; +- + list_del_init(&req->timeout_list); +- if (list_empty(&q->timeout_list)) +- del_timer(&q->timeout); + } + + static void blk_rq_timed_out(struct request *req) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-move-unplug_work-init b/src/patches/suse-2.6.27.31/patches.fixes/blk-move-unplug_work-init new file mode 100644 index 000000000..8fb64c3b4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-move-unplug_work-init @@ -0,0 +1,43 @@ +Subject: block: move q->unplug_work initialization +From: Peter Zijlstra +Date: Fri Oct 17 08:46:57 2008 +0200: +Git: 713ada9ba94f2ad874cffd074b83e3dc681ca82f + +modprobe loop; rmmod loop effectively creates a blk_queue and destroys it +which results in q->unplug_work being canceled without it ever being +initialized. + +Therefore, move the initialization of q->unplug_work from +blk_queue_make_request() to blk_alloc_queue*(). + +Reported-by: Alexey Dobriyan +Signed-off-by: Peter Zijlstra +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 1 + + block/blk-settings.c | 2 -- + 2 files changed, 1 insertion(+), 2 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -515,6 +515,7 @@ struct request_queue *blk_alloc_queue_no + init_timer(&q->unplug_timer); + setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); + INIT_LIST_HEAD(&q->timeout_list); ++ INIT_WORK(&q->unplug_work, blk_unplug_work); + + kobject_init(&q->kobj, &blk_queue_ktype); + +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -135,8 +135,6 @@ void blk_queue_make_request(struct reque + if (q->unplug_delay == 0) + q->unplug_delay = 1; + +- INIT_WORK(&q->unplug_work, blk_unplug_work); +- + q->unplug_timer.function = blk_unplug_timeout; + q->unplug_timer.data = (unsigned long)q; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-set-segment-boundary-mask b/src/patches/suse-2.6.27.31/patches.fixes/blk-set-segment-boundary-mask new file mode 100644 index 000000000..7e297ca78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-set-segment-boundary-mask @@ -0,0 +1,134 @@ +Subject: block: fix setting of max_segment_size and seg_boundary mask +From: Milan Broz +Date: Wed Dec 3 12:55:55 2008 +0100: +Git: 0e435ac26e3f951d83338ed3d4ab7dc0fe0055bc + +Fix setting of max_segment_size and seg_boundary mask for stacked md/dm +devices. + +When stacking devices (LVM over MD over SCSI) some of the request queue +parameters are not set up correctly in some cases by default, namely +max_segment_size and and seg_boundary mask. + +If you create MD device over SCSI, these attributes are zeroed. + +Problem become when there is over this mapping next device-mapper mapping +- queue attributes are set in DM this way: + +request_queue max_segment_size seg_boundary_mask +SCSI 65536 0xffffffff +MD RAID1 0 0 +LVM 65536 -1 (64bit) + +Unfortunately bio_add_page (resp. bio_phys_segments) calculates number of +physical segments according to these parameters. + +During the generic_make_request() is segment cout recalculated and can +increase bio->bi_phys_segments count over the allowed limit. (After +bio_clone() in stack operation.) + +Thi is specially problem in CCISS driver, where it produce OOPS here + + BUG_ON(creq->nr_phys_segments > MAXSGENTRIES); + +(MAXSEGENTRIES is 31 by default.) + +Sometimes even this command is enough to cause oops: + + dd iflag=direct if=/dev// of=/dev/null bs=128000 count=10 + +This command generates bios with 250 sectors, allocated in 32 4k-pages +(last page uses only 1024 bytes). + +For LVM layer, it allocates bio with 31 segments (still OK for CCISS), +unfortunatelly on lower layer it is recalculated to 32 segments and this +violates CCISS restriction and triggers BUG_ON(). + +The patch tries to fix it by: + + * initializing attributes above in queue request constructor + blk_queue_make_request() + + * make sure that blk_queue_stack_limits() inherits setting + + (DM uses its own function to set the limits because it + blk_queue_stack_limits() was introduced later. It should probably switch + to use generic stack limit function too.) + + * sets the default seg_boundary value in one place (blkdev.h) + + * use this mask as default in DM (instead of -1, which differs in 64bit) + +Bugs related to this: +https://bugzilla.redhat.com/show_bug.cgi?id=471639 +http://bugzilla.kernel.org/show_bug.cgi?id=8672 + +Signed-off-by: Milan Broz +Reviewed-by: Alasdair G Kergon +Cc: Neil Brown +Cc: FUJITA Tomonori +Cc: Tejun Heo +Cc: Mike Miller +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 2 +- + block/blk-settings.c | 4 ++++ + drivers/md/dm-table.c | 2 +- + include/linux/blkdev.h | 2 ++ + 4 files changed, 8 insertions(+), 2 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -596,7 +596,7 @@ blk_init_queue_node(request_fn_proc *rfn + 1 << QUEUE_FLAG_STACKABLE); + q->queue_lock = lock; + +- blk_queue_segment_boundary(q, 0xffffffff); ++ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK); + + blk_queue_make_request(q, __make_request); + blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE); +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -125,6 +125,9 @@ void blk_queue_make_request(struct reque + q->nr_requests = BLKDEV_MAX_RQ; + blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); + blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS); ++ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK); ++ blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE); ++ + q->make_request_fn = mfn; + q->backing_dev_info.ra_pages = + (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; +@@ -314,6 +317,7 @@ void blk_queue_stack_limits(struct reque + /* zero is "infinity" */ + t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); + t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); ++ t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask); + + t->max_phys_segments = min(t->max_phys_segments, b->max_phys_segments); + t->max_hw_segments = min(t->max_hw_segments, b->max_hw_segments); +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -687,7 +687,7 @@ static void check_for_valid_limits(struc + if (!rs->max_segment_size) + rs->max_segment_size = MAX_SEGMENT_SIZE; + if (!rs->seg_boundary_mask) +- rs->seg_boundary_mask = -1; ++ rs->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; + if (!rs->bounce_pfn) + rs->bounce_pfn = -1; + } +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -908,6 +908,8 @@ extern void blk_set_cmd_filter_defaults( + + #define MAX_SEGMENT_SIZE 65536 + ++#define BLK_SEG_BOUNDARY_MASK 0xFFFFFFFFUL ++ + #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist) + + static inline int queue_hardsect_size(struct request_queue *q) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-timeout-readd-timeout-list b/src/patches/suse-2.6.27.31/patches.fixes/blk-timeout-readd-timeout-list new file mode 100644 index 000000000..cfc4dfd26 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-timeout-readd-timeout-list @@ -0,0 +1,38 @@ +From: Hannes Reinecke +Subject: Kernel bug in kmpathd during FC cable pulls +References: bnc#476330 + +Kernel bug in kmpathd during FC cable pulls. +After one FC cable pull cycle system produced call trace. + +As it turned out blk_abort_requests() will not touch +any requests for which the endio processing has already +started. So we need to splice those requests back onto +the timeout list for endio processing to be able to +continue properly. + +Signed-off-by: Hannes Reinecke + +diff --git a/block/blk-timeout.c b/block/blk-timeout.c +index 4cc0205..bcadbb2 100644 +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -145,6 +145,8 @@ void blk_add_timer(struct request *req) + * blk_abort_queue -- Abort all request on given queue + * @queue: pointer to queue + * ++ * We have to use list_splice() here as blk_abort_request() ++ * might add requests back on the timeout list. + */ + void blk_abort_queue(struct request_queue *q) + { +@@ -161,6 +163,9 @@ void blk_abort_queue(struct request_queue *q) + list_for_each_entry_safe(rq, tmp, &list, timeout_list) + blk_abort_request(rq); + ++ /* Add remaining requests back on the list */ ++ list_splice(&list, &q->timeout_list); ++ + spin_unlock_irqrestore(q->queue_lock, flags); + + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/blk-timeout-splice-timeout-list b/src/patches/suse-2.6.27.31/patches.fixes/blk-timeout-splice-timeout-list new file mode 100644 index 000000000..d9198ac87 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/blk-timeout-splice-timeout-list @@ -0,0 +1,65 @@ +From: Hannes Reinecke +Subject: Deadlock during multipath failover +References: bnc#475107 + +During multipath failover tests with SCSI on System z, the kernel +deadlocks in this situation: + +> STACK: +> 0 blk_add_timer+206 [0x2981ea] +> 1 blk_rq_timed_out+132 [0x2982a8] +> 2 blk_abort_request+114 [0x29833e] +> 3 blk_abort_queue+92 [0x2983a8] +> 4 deactivate_path+74 [0x3e00009625a] +> 5 run_workqueue+236 [0x149e04] +> 6 worker_thread+294 [0x149fce] +> 7 kthread+110 [0x14f436] +> 8 kernel_thread_starter+6 [0x10941a] + +blk_abort_queue takes the queue_lock with spinlock_irqsave and +walks the timer_list with list_for_each_entry_safe. Since a +path to a SCSI device just failed, the rport state is +FC_PORTSTATE_BLOCKED. This rport state triggers blk_add_timer() +that calls list_add_tail() to move the request to the end of +timer_list. Thus, the list_for_each_entry_safe never reaches +the end of the timer_list, it continously moves the requests +to the end of the list. + +The rport state FC_PORTSTATE_BLOCKED would end when the function +fc_timeout_deleted_rport() would run to remove the rport. But +this function was schedules from queue_delayed_work. +The timer already expired, but the timer function does not run, +because the timer interrupt is disabled from the +spinlock_irqsave call. + +But just using a list_splice_init() here we will be traversing +our private list and break the deadlock. +And the timer would be triggered correctly as blk_add_timer() +will always add a one second delay here, during which we should +be able to process the list. + +Signed-off-by: Hannes Reinecke + +--- + block/blk-timeout.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -150,12 +150,15 @@ void blk_abort_queue(struct request_queu + { + unsigned long flags; + struct request *rq, *tmp; ++ LIST_HEAD(list); + + spin_lock_irqsave(q->queue_lock, flags); + + elv_abort_queue(q); + +- list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) ++ list_splice_init(&q->timeout_list, &list); ++ ++ list_for_each_entry_safe(rq, tmp, &list, timeout_list) + blk_abort_request(rq); + + spin_unlock_irqrestore(q->queue_lock, flags); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-add-comment-in-blk_rq_timed_out b/src/patches/suse-2.6.27.31/patches.fixes/block-add-comment-in-blk_rq_timed_out new file mode 100644 index 000000000..a3a9e915c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-add-comment-in-blk_rq_timed_out @@ -0,0 +1,29 @@ +Subject: block: add comment in blk_rq_timed_out() about why next can not be 0 +From: Jens Axboe +Date: Mon Dec 29 08:28:42 2008 +0100: +Git: 65d3618ccfe686e8d7b3f01a838d0578182406df +References: bnc#464155 + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-timeout.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -69,7 +69,12 @@ void blk_rq_timed_out_timer(unsigned lon + } + } + +- if (next_set && !list_empty(&q->timeout_list)) ++ /* ++ * next can never be 0 here with the list non-empty, since we always ++ * bump ->deadline to 1 so we can detect if the timer was ever added ++ * or not. See comment in blk_add_timer() ++ */ ++ if (next) + mod_timer(&q->timeout, round_jiffies_up(next)); + + spin_unlock_irqrestore(q->queue_lock, flags); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-discard-requests b/src/patches/suse-2.6.27.31/patches.fixes/block-discard-requests new file mode 100644 index 000000000..2abe8413e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-discard-requests @@ -0,0 +1,782 @@ +From b24db85c3e8a53ff0d3255b22e8e8b674572bdbc Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 23 Oct 2008 13:53:12 +0200 +Subject: [PATCH] Implement block discard + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + block/blk-barrier.c | 69 +++++++++++++++++++++++++++++++++++++++ + block/blk-core.c | 34 +++++++++++++------ + block/blk-merge.c | 27 +++++++++------ + block/blk-settings.c | 17 +++++++++ + block/blktrace.c | 29 ++++------------ + block/compat_ioctl.c | 1 + block/elevator.c | 12 +++++- + block/ioctl.c | 76 +++++++++++++++++++++++++++++++++++++++++++ + drivers/mtd/ftl.c | 24 +++++++++++++ + drivers/mtd/mtd_blkdevs.c | 16 +++++++++ + fs/fat/fatent.c | 14 +++++++ + include/linux/bio.h | 10 +++-- + include/linux/blkdev.h | 22 +++++++++++- + include/linux/blktrace_api.h | 6 ++- + include/linux/fs.h | 5 ++ + include/linux/mtd/blktrans.h | 2 + + 16 files changed, 314 insertions(+), 50 deletions(-) + +--- a/block/blk-barrier.c ++++ b/block/blk-barrier.c +@@ -315,3 +315,72 @@ int blkdev_issue_flush(struct block_devi + return ret; + } + EXPORT_SYMBOL(blkdev_issue_flush); ++ ++static void blkdev_discard_end_io(struct bio *bio, int err) ++{ ++ if (err) { ++ if (err == -EOPNOTSUPP) ++ set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); ++ clear_bit(BIO_UPTODATE, &bio->bi_flags); ++ } ++ ++ bio_put(bio); ++} ++ ++/** ++ * blkdev_issue_discard - queue a discard ++ * @bdev: blockdev to issue discard for ++ * @sector: start sector ++ * @nr_sects: number of sectors to discard ++ * ++ * Description: ++ * Issue a discard request for the sectors in question. Does not wait. ++ */ ++int blkdev_issue_discard(struct block_device *bdev, sector_t sector, ++ unsigned nr_sects) ++{ ++ struct request_queue *q; ++ struct bio *bio; ++ int ret = 0; ++ ++ if (bdev->bd_disk == NULL) ++ return -ENXIO; ++ ++ q = bdev_get_queue(bdev); ++ if (!q) ++ return -ENXIO; ++ ++ if (!q->prepare_discard_fn) ++ return -EOPNOTSUPP; ++ ++ while (nr_sects && !ret) { ++ bio = bio_alloc(GFP_KERNEL, 0); ++ if (!bio) ++ return -ENOMEM; ++ ++ bio->bi_end_io = blkdev_discard_end_io; ++ bio->bi_bdev = bdev; ++ ++ bio->bi_sector = sector; ++ ++ if (nr_sects > q->max_hw_sectors) { ++ bio->bi_size = q->max_hw_sectors << 9; ++ nr_sects -= q->max_hw_sectors; ++ sector += q->max_hw_sectors; ++ } else { ++ bio->bi_size = nr_sects << 9; ++ nr_sects = 0; ++ } ++ bio_get(bio); ++ submit_bio(DISCARD_BARRIER, bio); ++ ++ /* Check if it failed immediately */ ++ if (bio_flagged(bio, BIO_EOPNOTSUPP)) ++ ret = -EOPNOTSUPP; ++ else if (!bio_flagged(bio, BIO_UPTODATE)) ++ ret = -EIO; ++ bio_put(bio); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(blkdev_issue_discard); +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -1077,7 +1077,12 @@ void init_request_from_bio(struct reques + /* + * REQ_BARRIER implies no merging, but lets make it explicit + */ +- if (unlikely(bio_barrier(bio))) ++ if (unlikely(bio_discard(bio))) { ++ req->cmd_flags |= REQ_DISCARD; ++ if (bio_barrier(bio)) ++ req->cmd_flags |= REQ_SOFTBARRIER; ++ req->q->prepare_discard_fn(req->q, req); ++ } else if (unlikely(bio_barrier(bio))) + req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + + if (bio_sync(bio)) +@@ -1095,7 +1100,7 @@ void init_request_from_bio(struct reques + static int __make_request(struct request_queue *q, struct bio *bio) + { + struct request *req; +- int el_ret, nr_sectors, barrier, err; ++ int el_ret, nr_sectors, barrier, discard, err; + const unsigned short prio = bio_prio(bio); + const int sync = bio_sync(bio); + int rw_flags; +@@ -1110,7 +1115,14 @@ static int __make_request(struct request + blk_queue_bounce(q, &bio); + + barrier = bio_barrier(bio); +- if (unlikely(barrier) && (q->next_ordered == QUEUE_ORDERED_NONE)) { ++ if (unlikely(barrier) && bio_has_data(bio) && ++ (q->next_ordered == QUEUE_ORDERED_NONE)) { ++ err = -EOPNOTSUPP; ++ goto end_io; ++ } ++ ++ discard = bio_discard(bio); ++ if (unlikely(discard) && !q->prepare_discard_fn) { + err = -EOPNOTSUPP; + goto end_io; + } +@@ -1405,7 +1417,8 @@ end_io: + + if (bio_check_eod(bio, nr_sectors)) + goto end_io; +- if (bio_empty_barrier(bio) && !q->prepare_flush_fn) { ++ if ((bio_empty_barrier(bio) && !q->prepare_flush_fn) || ++ (bio_discard(bio) && !q->prepare_discard_fn)) { + err = -EOPNOTSUPP; + goto end_io; + } +@@ -1487,7 +1500,6 @@ void submit_bio(int rw, struct bio *bio) + * go through the normal accounting stuff before submission. + */ + if (bio_has_data(bio)) { +- + if (rw & WRITE) { + count_vm_events(PGPGOUT, count); + } else { +@@ -1881,7 +1893,7 @@ static int blk_end_io(struct request *rq + struct request_queue *q = rq->q; + unsigned long flags = 0UL; + +- if (bio_has_data(rq->bio)) { ++ if (bio_has_data(rq->bio) || blk_discard_rq(rq)) { + if (__end_that_request_first(rq, error, nr_bytes)) + return 1; + +@@ -1939,7 +1951,7 @@ EXPORT_SYMBOL_GPL(blk_end_request); + **/ + int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) + { +- if (bio_has_data(rq->bio) && ++ if ((bio_has_data(rq->bio) || blk_discard_rq(rq)) && + __end_that_request_first(rq, error, nr_bytes)) + return 1; + +@@ -2012,12 +2024,14 @@ void blk_rq_bio_prep(struct request_queu + we want BIO_RW_AHEAD (bit 1) to imply REQ_FAILFAST (bit 1). */ + rq->cmd_flags |= (bio->bi_rw & 3); + +- rq->nr_phys_segments = bio_phys_segments(q, bio); +- rq->nr_hw_segments = bio_hw_segments(q, bio); ++ if (bio_has_data(bio)) { ++ rq->nr_phys_segments = bio_phys_segments(q, bio); ++ rq->nr_hw_segments = bio_hw_segments(q, bio); ++ rq->buffer = bio_data(bio); ++ } + rq->current_nr_sectors = bio_cur_sectors(bio); + rq->hard_cur_sectors = rq->current_nr_sectors; + rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio); +- rq->buffer = bio_data(bio); + rq->data_len = bio->bi_size; + + rq->bio = rq->biotail = bio; +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -11,7 +11,7 @@ + + void blk_recalc_rq_sectors(struct request *rq, int nsect) + { +- if (blk_fs_request(rq)) { ++ if (blk_fs_request(rq) || blk_discard_rq(rq)) { + rq->hard_sector += nsect; + rq->hard_nr_sectors -= nsect; + +@@ -138,14 +138,18 @@ static int blk_phys_contig_segment(struc + if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags)) + return 0; + +- if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt))) +- return 0; + if (bio->bi_seg_back_size + nxt->bi_seg_front_size > + q->max_segment_size) + return 0; + ++ if (!bio_has_data(bio)) ++ return 1; ++ ++ if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt))) ++ return 0; ++ + /* +- * bio and nxt are contigous in memory, check if the queue allows ++ * bio and nxt are contiguous in memory, check if the queue allows + * these two to be merged into one + */ + if (BIO_SEG_BOUNDARY(q, bio, nxt)) +@@ -161,8 +165,9 @@ static int blk_hw_contig_segment(struct + blk_recount_segments(q, bio); + if (!bio_flagged(nxt, BIO_SEG_VALID)) + blk_recount_segments(q, nxt); +- if (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) || +- BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size)) ++ if (bio_has_data(bio) && ++ (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) || ++ BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size))) + return 0; + if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size) + return 0; +@@ -325,8 +330,9 @@ int ll_back_merge_fn(struct request_queu + if (!bio_flagged(bio, BIO_SEG_VALID)) + blk_recount_segments(q, bio); + len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size; +- if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)) +- && !BIOVEC_VIRT_OVERSIZE(len)) { ++ if (!bio_has_data(bio) || ++ (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)) ++ && !BIOVEC_VIRT_OVERSIZE(len))) { + int mergeable = ll_new_mergeable(q, req, bio); + + if (mergeable) { +@@ -364,8 +370,9 @@ int ll_front_merge_fn(struct request_que + blk_recount_segments(q, bio); + if (!bio_flagged(req->bio, BIO_SEG_VALID)) + blk_recount_segments(q, req->bio); +- if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) && +- !BIOVEC_VIRT_OVERSIZE(len)) { ++ if (!bio_has_data(bio) || ++ (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) && ++ !BIOVEC_VIRT_OVERSIZE(len))) { + int mergeable = ll_new_mergeable(q, req, bio); + + if (mergeable) { +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -33,6 +33,23 @@ void blk_queue_prep_rq(struct request_qu + EXPORT_SYMBOL(blk_queue_prep_rq); + + /** ++ * blk_queue_set_discard - set a discard_sectors function for queue ++ * @q: queue ++ * @dfn: prepare_discard function ++ * ++ * It's possible for a queue to register a discard callback which is used ++ * to transform a discard request into the appropriate type for the ++ * hardware. If none is registered, then discard requests are failed ++ * with %EOPNOTSUPP. ++ * ++ */ ++void blk_queue_set_discard(struct request_queue *q, prepare_discard_fn *dfn) ++{ ++ q->prepare_discard_fn = dfn; ++} ++EXPORT_SYMBOL(blk_queue_set_discard); ++ ++/** + * blk_queue_merge_bvec - set a merge_bvec function for queue + * @q: queue + * @mbfn: merge_bvec_fn +--- a/block/blktrace.c ++++ b/block/blktrace.c +@@ -111,23 +111,9 @@ static int act_log_check(struct blk_trac + */ + static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK_TC_WRITE) }; + +-/* +- * Bio action bits of interest +- */ +-static u32 bio_act[9] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD), 0, 0, 0, BLK_TC_ACT(BLK_TC_META) }; +- +-/* +- * More could be added as needed, taking care to increment the decrementer +- * to get correct indexing +- */ +-#define trace_barrier_bit(rw) \ +- (((rw) & (1 << BIO_RW_BARRIER)) >> (BIO_RW_BARRIER - 0)) +-#define trace_sync_bit(rw) \ +- (((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1)) +-#define trace_ahead_bit(rw) \ +- (((rw) & (1 << BIO_RW_AHEAD)) << (2 - BIO_RW_AHEAD)) +-#define trace_meta_bit(rw) \ +- (((rw) & (1 << BIO_RW_META)) >> (BIO_RW_META - 3)) ++/* The ilog2() calls fall out because they're constant */ ++#define MASK_TC_BIT(rw, __name) ( (rw & (1 << BIO_RW_ ## __name)) << \ ++ (ilog2(BLK_TC_ ## __name) + BLK_TC_SHIFT - BIO_RW_ ## __name) ) + + /* + * The worker for the various blk_add_trace*() types. Fills out a +@@ -147,10 +133,11 @@ void __blk_add_trace(struct blk_trace *b + return; + + what |= ddir_act[rw & WRITE]; +- what |= bio_act[trace_barrier_bit(rw)]; +- what |= bio_act[trace_sync_bit(rw)]; +- what |= bio_act[trace_ahead_bit(rw)]; +- what |= bio_act[trace_meta_bit(rw)]; ++ what |= MASK_TC_BIT(rw, BARRIER); ++ what |= MASK_TC_BIT(rw, SYNC); ++ what |= MASK_TC_BIT(rw, AHEAD); ++ what |= MASK_TC_BIT(rw, META); ++ what |= MASK_TC_BIT(rw, DISCARD); + + pid = tsk->pid; + if (unlikely(act_log_check(bt, what, sector, pid))) +--- a/block/compat_ioctl.c ++++ b/block/compat_ioctl.c +@@ -788,6 +788,7 @@ long compat_blkdev_ioctl(struct file *fi + return compat_hdio_getgeo(disk, bdev, compat_ptr(arg)); + case BLKFLSBUF: + case BLKROSET: ++ case BLKDISCARD: + /* + * the ones below are implemented in blkdev_locked_ioctl, + * but we call blkdev_ioctl, which gets the lock for us +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -75,6 +75,12 @@ int elv_rq_merge_ok(struct request *rq, + return 0; + + /* ++ * Don't merge file system requests and discard requests ++ */ ++ if (bio_discard(bio) != bio_discard(rq->bio)) ++ return 0; ++ ++ /* + * different data direction or already started, don't merge + */ + if (bio_data_dir(bio) != rq_data_dir(rq)) +@@ -438,6 +444,8 @@ void elv_dispatch_sort(struct request_qu + list_for_each_prev(entry, &q->queue_head) { + struct request *pos = list_entry_rq(entry); + ++ if (blk_discard_rq(rq) != blk_discard_rq(pos)) ++ break; + if (rq_data_dir(rq) != rq_data_dir(pos)) + break; + if (pos->cmd_flags & stop_flags) +@@ -607,7 +615,7 @@ void elv_insert(struct request_queue *q, + break; + + case ELEVATOR_INSERT_SORT: +- BUG_ON(!blk_fs_request(rq)); ++ BUG_ON(!blk_fs_request(rq) && !blk_discard_rq(rq)); + rq->cmd_flags |= REQ_SORTED; + q->nr_sorted++; + if (rq_mergeable(rq)) { +@@ -692,7 +700,7 @@ void __elv_add_request(struct request_qu + * this request is scheduling boundary, update + * end_sector + */ +- if (blk_fs_request(rq)) { ++ if (blk_fs_request(rq) || blk_discard_rq(rq)) { + q->end_sector = rq_end_sector(rq); + q->boundary_rq = rq; + } +--- a/block/ioctl.c ++++ b/block/ioctl.c +@@ -111,6 +111,69 @@ static int blkdev_reread_part(struct blo + return res; + } + ++static void blk_ioc_discard_endio(struct bio *bio, int err) ++{ ++ if (err) { ++ if (err == -EOPNOTSUPP) ++ set_bit(BIO_EOPNOTSUPP, &bio->bi_flags); ++ clear_bit(BIO_UPTODATE, &bio->bi_flags); ++ } ++ complete(bio->bi_private); ++} ++ ++static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, ++ uint64_t len) ++{ ++ struct request_queue *q = bdev_get_queue(bdev); ++ int ret = 0; ++ ++ if (start & 511) ++ return -EINVAL; ++ if (len & 511) ++ return -EINVAL; ++ start >>= 9; ++ len >>= 9; ++ ++ if (start + len > (bdev->bd_inode->i_size >> 9)) ++ return -EINVAL; ++ ++ if (!q->prepare_discard_fn) ++ return -EOPNOTSUPP; ++ ++ while (len && !ret) { ++ DECLARE_COMPLETION_ONSTACK(wait); ++ struct bio *bio; ++ ++ bio = bio_alloc(GFP_KERNEL, 0); ++ if (!bio) ++ return -ENOMEM; ++ ++ bio->bi_end_io = blk_ioc_discard_endio; ++ bio->bi_bdev = bdev; ++ bio->bi_private = &wait; ++ bio->bi_sector = start; ++ ++ if (len > q->max_hw_sectors) { ++ bio->bi_size = q->max_hw_sectors << 9; ++ len -= q->max_hw_sectors; ++ start += q->max_hw_sectors; ++ } else { ++ bio->bi_size = len << 9; ++ len = 0; ++ } ++ submit_bio(DISCARD_NOBARRIER, bio); ++ ++ wait_for_completion(&wait); ++ ++ if (bio_flagged(bio, BIO_EOPNOTSUPP)) ++ ret = -EOPNOTSUPP; ++ else if (!bio_flagged(bio, BIO_UPTODATE)) ++ ret = -EIO; ++ bio_put(bio); ++ } ++ return ret; ++} ++ + static int put_ushort(unsigned long arg, unsigned short val) + { + return put_user(val, (unsigned short __user *)arg); +@@ -258,6 +321,19 @@ int blkdev_ioctl(struct inode *inode, st + set_device_ro(bdev, n); + unlock_kernel(); + return 0; ++ ++ case BLKDISCARD: { ++ uint64_t range[2]; ++ ++ if (!(file->f_mode & FMODE_WRITE)) ++ return -EBADF; ++ ++ if (copy_from_user(range, (void __user *)arg, sizeof(range))) ++ return -EFAULT; ++ ++ return blk_ioctl_discard(bdev, range[0], range[1]); ++ } ++ + case HDIO_GETGEO: { + struct hd_geometry geo; + +--- a/drivers/mtd/ftl.c ++++ b/drivers/mtd/ftl.c +@@ -1005,6 +1005,29 @@ static int ftl_writesect(struct mtd_blkt + return ftl_write((void *)dev, buf, block, 1); + } + ++static int ftl_discardsect(struct mtd_blktrans_dev *dev, ++ unsigned long sector, unsigned nr_sects) ++{ ++ partition_t *part = (void *)dev; ++ uint32_t bsize = 1 << part->header.EraseUnitSize; ++ ++ DEBUG(1, "FTL erase sector %ld for %d sectors\n", ++ sector, nr_sects); ++ ++ while (nr_sects) { ++ uint32_t old_addr = part->VirtualBlockMap[sector]; ++ if (old_addr != 0xffffffff) { ++ part->VirtualBlockMap[sector] = 0xffffffff; ++ part->EUNInfo[old_addr/bsize].Deleted++; ++ if (set_bam_entry(part, old_addr, 0)) ++ return -EIO; ++ } ++ nr_sects--; ++ sector++; ++ } ++ ++ return 0; ++} + /*====================================================================*/ + + static void ftl_freepart(partition_t *part) +@@ -1069,6 +1092,7 @@ static struct mtd_blktrans_ops ftl_tr = + .blksize = SECTOR_SIZE, + .readsect = ftl_readsect, + .writesect = ftl_writesect, ++ .discard = ftl_discardsect, + .getgeo = ftl_getgeo, + .add_mtd = ftl_add_mtd, + .remove_dev = ftl_remove_dev, +--- a/drivers/mtd/mtd_blkdevs.c ++++ b/drivers/mtd/mtd_blkdevs.c +@@ -32,6 +32,14 @@ struct mtd_blkcore_priv { + spinlock_t queue_lock; + }; + ++static int blktrans_discard_request(struct request_queue *q, ++ struct request *req) ++{ ++ req->cmd_type = REQ_TYPE_LINUX_BLOCK; ++ req->cmd[0] = REQ_LB_OP_DISCARD; ++ return 0; ++} ++ + static int do_blktrans_request(struct mtd_blktrans_ops *tr, + struct mtd_blktrans_dev *dev, + struct request *req) +@@ -44,6 +52,10 @@ static int do_blktrans_request(struct mt + + buf = req->buffer; + ++ if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && ++ req->cmd[0] == REQ_LB_OP_DISCARD) ++ return !tr->discard(dev, block, nsect); ++ + if (!blk_fs_request(req)) + return 0; + +@@ -367,6 +379,10 @@ int register_mtd_blktrans(struct mtd_blk + + tr->blkcore_priv->rq->queuedata = tr; + blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); ++ if (tr->discard) ++ blk_queue_set_discard(tr->blkcore_priv->rq, ++ blktrans_discard_request); ++ + tr->blkshift = ffs(tr->blksize) - 1; + + tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr, +--- a/fs/fat/fatent.c ++++ b/fs/fat/fatent.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + struct fatent_operations { + void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); +@@ -535,6 +536,7 @@ int fat_free_clusters(struct inode *inod + struct fat_entry fatent; + struct buffer_head *bhs[MAX_BUF_PER_PAGE]; + int i, err, nr_bhs; ++ int first_cl = cluster; + + nr_bhs = 0; + fatent_init(&fatent); +@@ -551,6 +553,18 @@ int fat_free_clusters(struct inode *inod + goto error; + } + ++ /* ++ * Issue discard for the sectors we no longer care about, ++ * batching contiguous clusters into one request ++ */ ++ if (cluster != fatent.entry + 1) { ++ int nr_clus = fatent.entry - first_cl + 1; ++ ++ sb_issue_discard(sb, fat_clus_to_blknr(sbi, first_cl), ++ nr_clus * sbi->sec_per_clus); ++ first_cl = cluster; ++ } ++ + ops->ent_put(&fatent, FAT_ENT_FREE); + if (sbi->free_clusters != -1) { + sbi->free_clusters++; +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -156,6 +156,8 @@ struct bio { + * bit 2 -- barrier + * bit 3 -- fail fast, don't want low level driver retries + * bit 4 -- synchronous I/O hint: the block layer will unplug immediately ++ * bit 5 -- metadata request ++ * bit 6 -- discard sectors + */ + #define BIO_RW 0 /* Must match RW in req flags (blkdev.h) */ + #define BIO_RW_AHEAD 1 /* Must match FAILFAST in req flags */ +@@ -163,6 +165,7 @@ struct bio { + #define BIO_RW_FAILFAST 3 + #define BIO_RW_SYNC 4 + #define BIO_RW_META 5 ++#define BIO_RW_DISCARD 6 + + /* + * upper 16 bits of bi_rw define the io priority of this bio +@@ -192,14 +195,15 @@ struct bio { + #define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) + #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) + #define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) +-#define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio)) ++#define bio_discard(bio) ((bio)->bi_rw & (1 << BIO_RW_DISCARD)) ++#define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio) && !bio_discard(bio)) + + static inline unsigned int bio_cur_sectors(struct bio *bio) + { + if (bio->bi_vcnt) + return bio_iovec(bio)->bv_len >> 9; +- +- return 0; ++ else /* dataless requests such as discard */ ++ return bio->bi_size >> 9; + } + + static inline void *bio_data(struct bio *bio) +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -81,6 +81,7 @@ enum { + */ + REQ_LB_OP_EJECT = 0x40, /* eject request */ + REQ_LB_OP_FLUSH = 0x41, /* flush device */ ++ REQ_LB_OP_DISCARD = 0x42, /* discard sectors */ + }; + + /* +@@ -89,6 +90,7 @@ enum { + enum rq_flag_bits { + __REQ_RW, /* not set, read. set, write */ + __REQ_FAILFAST, /* no low level driver retries */ ++ __REQ_DISCARD, /* request to discard sectors */ + __REQ_SORTED, /* elevator knows about this request */ + __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ + __REQ_HARDBARRIER, /* may not be passed by drive either */ +@@ -111,6 +113,7 @@ enum rq_flag_bits { + }; + + #define REQ_RW (1 << __REQ_RW) ++#define REQ_DISCARD (1 << __REQ_DISCARD) + #define REQ_FAILFAST (1 << __REQ_FAILFAST) + #define REQ_SORTED (1 << __REQ_SORTED) + #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) +@@ -252,6 +255,7 @@ typedef void (request_fn_proc) (struct r + typedef int (make_request_fn) (struct request_queue *q, struct bio *bio); + typedef int (prep_rq_fn) (struct request_queue *, struct request *); + typedef void (unplug_fn) (struct request_queue *); ++typedef int (prepare_discard_fn) (struct request_queue *, struct request *); + + struct bio_vec; + struct bvec_merge_data { +@@ -307,6 +311,7 @@ struct request_queue + make_request_fn *make_request_fn; + prep_rq_fn *prep_rq_fn; + unplug_fn *unplug_fn; ++ prepare_discard_fn *prepare_discard_fn; + merge_bvec_fn *merge_bvec_fn; + prepare_flush_fn *prepare_flush_fn; + softirq_done_fn *softirq_done_fn; +@@ -536,7 +541,7 @@ enum { + #define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST) + #define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED) + +-#define blk_account_rq(rq) (blk_rq_started(rq) && blk_fs_request(rq)) ++#define blk_account_rq(rq) (blk_rq_started(rq) && (blk_fs_request(rq) || blk_discard_rq(rq))) + + #define blk_pm_suspend_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_SUSPEND) + #define blk_pm_resume_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_RESUME) +@@ -546,6 +551,7 @@ enum { + #define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED) + #define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER) + #define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA) ++#define blk_discard_rq(rq) ((rq)->cmd_flags & REQ_DISCARD) + #define blk_bidi_rq(rq) ((rq)->next_rq != NULL) + #define blk_empty_barrier(rq) (blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors) + /* rq->queuelist of dequeued request must be list_empty() */ +@@ -592,7 +598,8 @@ static inline void blk_clear_queue_full( + #define RQ_NOMERGE_FLAGS \ + (REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER) + #define rq_mergeable(rq) \ +- (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq))) ++ (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \ ++ (blk_discard_rq(rq) || blk_fs_request((rq)))) + + /* + * q->prep_rq_fn return values +@@ -797,6 +804,7 @@ extern void blk_queue_merge_bvec(struct + extern void blk_queue_dma_alignment(struct request_queue *, int); + extern void blk_queue_update_dma_alignment(struct request_queue *, int); + extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); ++extern void blk_queue_set_discard(struct request_queue *, prepare_discard_fn *); + extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); + extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *); + extern int blk_do_ordered(struct request_queue *, struct request **); +@@ -838,6 +846,16 @@ static inline struct request *blk_map_qu + } + + extern int blkdev_issue_flush(struct block_device *, sector_t *); ++extern int blkdev_issue_discard(struct block_device *, sector_t sector, ++ unsigned nr_sects); ++ ++static inline int sb_issue_discard(struct super_block *sb, ++ sector_t block, unsigned nr_blocks) ++{ ++ block <<= (sb->s_blocksize_bits - 9); ++ nr_blocks <<= (sb->s_blocksize_bits - 9); ++ return blkdev_issue_discard(sb->s_bdev, block, nr_blocks); ++} + + /* + * command filter functions +--- a/include/linux/blktrace_api.h ++++ b/include/linux/blktrace_api.h +@@ -23,7 +23,8 @@ enum blktrace_cat { + BLK_TC_NOTIFY = 1 << 10, /* special message */ + BLK_TC_AHEAD = 1 << 11, /* readahead */ + BLK_TC_META = 1 << 12, /* metadata */ +- BLK_TC_DRV_DATA = 1 << 13, /* binary per-driver data */ ++ BLK_TC_DISCARD = 1 << 13, /* discard requests */ ++ BLK_TC_DRV_DATA = 1 << 14, /* binary per-drivers data */ + + BLK_TC_END = 1 << 15, /* only 16-bits, reminder */ + }; +@@ -204,6 +205,9 @@ static inline void blk_add_trace_rq(stru + if (likely(!bt)) + return; + ++ if (blk_discard_rq(rq)) ++ rw |= (1 << BIO_RW_DISCARD); ++ + if (blk_pc_request(rq)) { + what |= BLK_TC_ACT(BLK_TC_PC); + __blk_add_trace(bt, 0, rq->data_len, rw, what, rq->errors, sizeof(rq->cmd), rq->cmd); +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -91,7 +91,9 @@ extern int dir_notify_enable; + #define READ_META (READ | (1 << BIO_RW_META)) + #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) + #define SWRITE_SYNC (SWRITE | (1 << BIO_RW_SYNC)) +-#define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER)) ++#define WRITE_BARRIER (WRITE | (1 << BIO_RW_BARRIER)) ++#define DISCARD_NOBARRIER (1 << BIO_RW_DISCARD) ++#define DISCARD_BARRIER ((1 << BIO_RW_DISCARD) | (1 << BIO_RW_BARRIER)) + + #define SEL_IN 1 + #define SEL_OUT 2 +@@ -229,6 +231,7 @@ extern int dir_notify_enable; + #define BLKTRACESTART _IO(0x12,116) + #define BLKTRACESTOP _IO(0x12,117) + #define BLKTRACETEARDOWN _IO(0x12,118) ++#define BLKDISCARD _IO(0x12,119) + + #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ + #define FIBMAP _IO(0x00,1) /* bmap access */ +--- a/include/linux/mtd/blktrans.h ++++ b/include/linux/mtd/blktrans.h +@@ -41,6 +41,8 @@ struct mtd_blktrans_ops { + unsigned long block, char *buffer); + int (*writesect)(struct mtd_blktrans_dev *dev, + unsigned long block, char *buffer); ++ int (*discard)(struct mtd_blktrans_dev *dev, ++ unsigned long block, unsigned nr_blocks); + + /* Block layer ioctls */ + int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-failfast-merge-fix b/src/patches/suse-2.6.27.31/patches.fixes/block-failfast-merge-fix new file mode 100644 index 000000000..33e4fb9f2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-failfast-merge-fix @@ -0,0 +1,67 @@ +From ab0fd1debe730ec9998678a0c53caefbd121ed10 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Fri, 3 Jul 2009 12:56:18 +0200 +Subject: [PATCH] block: don't merge requests of different failfast settings +References: bnc#519111 + +Block layer used to merge requests and bios with different failfast +settings. This caused regular IOs to fail prematurely when they were +merged into failfast requests for readahead. + +Niel Lambrechts could trigger the problem semi-reliably on ext4 when +resuming from STR. ext4 uses readahead when reading inodes and +combined with the deterministic extra SATA PHY exception cycle during +resume on the specific configuration, non-readahead inode read would +fail causing ext4 errors. Please read the following thread for +details. + + http://lkml.org/lkml/2009/5/23/21 + +This patch makes block layer reject merging if the failfast settings +don't match. This is correct but likely to lower IO performance by +preventing regular IOs from mingling into surrounding readahead +requests. Changes to allow such mixed merges and handle errors +correctly will be added later. + +Signed-off-by: Tejun Heo +Reported-by: Niel Lambrechts +Cc: Theodore Tso +Signed-off-by: Jens Axboe +Signed-off-by: Tejun Heo +--- + block/blk-merge.c | 6 ++++++ + block/elevator.c | 8 ++++++++ + 2 files changed, 14 insertions(+) + +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -376,6 +376,12 @@ static int attempt_merge(struct request_ + if (blk_integrity_rq(req) != blk_integrity_rq(next)) + return 0; + ++ /* don't merge requests of different failfast settings */ ++ if (blk_failfast_dev(req) != blk_failfast_dev(next) || ++ blk_failfast_transport(req) != blk_failfast_transport(next) || ++ blk_failfast_driver(req) != blk_failfast_driver(next)) ++ return 0; ++ + /* + * If we are allowed to merge, then append bio list + * from next to rq and release next. merge_requests_fn +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -97,6 +97,14 @@ int elv_rq_merge_ok(struct request *rq, + if (bio_integrity(bio) != blk_integrity_rq(rq)) + return 0; + ++ /* ++ * Don't merge if failfast settings don't match ++ */ ++ if (!bio_failfast_dev(bio) != !blk_failfast_dev(rq) || ++ !bio_failfast_transport(bio) != !blk_failfast_transport(rq) || ++ !bio_failfast_driver(bio) != !blk_failfast_driver(rq)) ++ return 0; ++ + if (!elv_iosched_allow_merge(rq, bio)) + return 0; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-fix-blk_start_queueing b/src/patches/suse-2.6.27.31/patches.fixes/block-fix-blk_start_queueing new file mode 100644 index 000000000..e515e5853 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-fix-blk_start_queueing @@ -0,0 +1,34 @@ +Subject: block: Fix blk_start_queueing() to not kick a stopped queue +From: Elias Oltmanns +Date: Thu Oct 9 08:56:20 2008 +0200: +Git: 336c3d8ce771608815b65bcfa27a17a83b297328 +References: bnc#464155 + +blk_start_queueing() should act like the generic queue unplugging +and kicking and ignore a stopped queue. Such a queue may not be +run until after a call to blk_start_queue(). + +Signed-off-by: Elias Oltmanns +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -905,9 +905,11 @@ EXPORT_SYMBOL(blk_get_request); + */ + void blk_start_queueing(struct request_queue *q) + { +- if (!blk_queue_plugged(q)) ++ if (!blk_queue_plugged(q)) { ++ if (unlikely(blk_queue_stopped(q))) ++ return; + q->request_fn(q); +- else ++ } else + __generic_unplug_device(q); + } + EXPORT_SYMBOL(blk_start_queueing); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-get-rid-of-the-manual-directory-counting-in-blktrace.patch b/src/patches/suse-2.6.27.31/patches.fixes/block-get-rid-of-the-manual-directory-counting-in-blktrace.patch new file mode 100644 index 000000000..21e8eca35 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-get-rid-of-the-manual-directory-counting-in-blktrace.patch @@ -0,0 +1,124 @@ +From: Jens Axboe +Date: Mon Jan 5 10:17:25 2009 +0100 +Subject: block: get rid of the manual directory counting in blktrace +References: bnc#475149 + + It can result in a stuck blktrace system, if --kill is used. + + Signed-off-by: Jens Axboe + +Acked-by: Jan Blunck +--- + block/blktrace.c | 72 ++++++++++++++++--------------------------------------- + 1 file changed, 21 insertions(+), 51 deletions(-) + +Index: b/block/blktrace.c +=================================================================== +--- a/block/blktrace.c ++++ b/block/blktrace.c +@@ -181,59 +181,12 @@ EXPORT_SYMBOL_GPL(__blk_add_trace); + + static struct dentry *blk_tree_root; + static DEFINE_MUTEX(blk_tree_mutex); +-static unsigned int root_users; +- +-static inline void blk_remove_root(void) +-{ +- if (blk_tree_root) { +- debugfs_remove(blk_tree_root); +- blk_tree_root = NULL; +- } +-} +- +-static void blk_remove_tree(struct dentry *dir) +-{ +- mutex_lock(&blk_tree_mutex); +- debugfs_remove(dir); +- if (--root_users == 0) +- blk_remove_root(); +- mutex_unlock(&blk_tree_mutex); +-} +- +-static struct dentry *blk_create_tree(const char *blk_name) +-{ +- struct dentry *dir = NULL; +- int created = 0; +- +- mutex_lock(&blk_tree_mutex); +- +- if (!blk_tree_root) { +- blk_tree_root = debugfs_create_dir("block", NULL); +- if (!blk_tree_root) +- goto err; +- created = 1; +- } +- +- dir = debugfs_create_dir(blk_name, blk_tree_root); +- if (dir) +- root_users++; +- else { +- /* Delete root only if we created it */ +- if (created) +- blk_remove_root(); +- } +- +-err: +- mutex_unlock(&blk_tree_mutex); +- return dir; +-} + + static void blk_trace_cleanup(struct blk_trace *bt) + { +- relay_close(bt->rchan); + debugfs_remove(bt->msg_file); + debugfs_remove(bt->dropped_file); +- blk_remove_tree(bt->dir); ++ relay_close(bt->rchan); + free_percpu(bt->sequence); + free_percpu(bt->msg_data); + kfree(bt); +@@ -336,7 +289,18 @@ static int blk_subbuf_start_callback(str + + static int blk_remove_buf_file_callback(struct dentry *dentry) + { ++ struct dentry *parent = dentry->d_parent; + debugfs_remove(dentry); ++ ++ /* ++ * this will fail for all but the last file, but that is ok. what we ++ * care about is the top level buts->name directory going away, when ++ * the last trace file is gone. Then we don't have to rmdir() that ++ * manually on trace stop, so it nicely solves the issue with ++ * force killing of running traces. ++ */ ++ ++ debugfs_remove(parent); + return 0; + } + +@@ -393,7 +357,15 @@ int do_blk_trace_setup(struct request_qu + goto err; + + ret = -ENOENT; +- dir = blk_create_tree(buts->name); ++ ++ if (!blk_tree_root) { ++ blk_tree_root = debugfs_create_dir("block", NULL); ++ if (!blk_tree_root) ++ return -ENOMEM; ++ } ++ ++ dir = debugfs_create_dir(buts->name, blk_tree_root); ++ + if (!dir) + goto err; + +@@ -436,8 +408,6 @@ int do_blk_trace_setup(struct request_qu + + return 0; + err: +- if (dir) +- blk_remove_tree(dir); + if (bt) { + if (bt->msg_file) + debugfs_remove(bt->msg_file); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-git-fixes b/src/patches/suse-2.6.27.31/patches.fixes/block-git-fixes new file mode 100644 index 000000000..9958f7ff2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-git-fixes @@ -0,0 +1,1702 @@ +From: Jens Axboe +Subject: Block layer fixes for 2.6.28 +Patch-Mainline: 2.6.28 + +This is a combined patchset with block layer fixes from 2.6.28. +Commit IDs: +97dee27d1c4d6041ff1cc8150db95fe3eab6be5a +00bbda44114e70fc9879731be3c888122b1de8b1 +7452d2a2be657becb2f385d0e0864ba51f1ae694 +075a108f7d4dd24b8b69e59edcdf1a0fd84e6541 +7a1b6029bf9ff3d0636e318d2482031dc493df16 +b3a5faf3cefbff4b69ca181767b882bbd6189aaf +8fe902de23b4f4012db91f538cafd864c63308e7 +dfef13dad8d34d0a9e83adee3e8cd9f94cca465e +d2629dd70132f90f9d1bca07572197e9adea25b1 +1f08a4484a223cb337e0466042005421cd55d22b +fcdc7361d2925596d69d0538d738c08c221a69c9 +cd93bcfa9ca9b15051220614160131c53d7f33f0 +d371ca6b8a21a617b8607d23f7202197ad40482a +910ee03b1e61d5cfb121dfb1ee7c127f18bdae01 + +Signed-off-by: Hannes Reinecke + +--- + Documentation/DocBook/kernel-api.tmpl | 4 + Documentation/block/deadline-iosched.txt | 14 +- + block/Makefile | 4 + block/blk-core.c | 166 +++++++------------------------ + block/blk-exec.c | 6 - + block/blk-integrity.c | 4 + block/blk-map.c | 16 +- + block/blk-merge.c | 100 ------------------ + block/blk-settings.c | 8 - + block/blk-softirq.c | 103 +++++++++++++++++++ + block/blk-tag.c | 8 - + block/cfq-iosched.c | 47 +++++++- + block/deadline-iosched.c | 40 ++----- + block/elevator.c | 5 + block/genhd.c | 5 + drivers/block/ps3disk.c | 9 + + drivers/block/virtio_blk.c | 4 + drivers/md/raid1.c | 4 + drivers/md/raid10.c | 4 + drivers/md/raid5.c | 66 +++++++++--- + fs/bio.c | 16 -- + include/linux/bio.h | 33 ------ + include/linux/blkdev.h | 18 +-- + 23 files changed, 310 insertions(+), 374 deletions(-) + +--- a/Documentation/DocBook/kernel-api.tmpl ++++ b/Documentation/DocBook/kernel-api.tmpl +@@ -364,6 +364,10 @@ X!Edrivers/pnp/system.c + !Eblock/blk-barrier.c + !Eblock/blk-tag.c + !Iblock/blk-tag.c ++!Eblock/blk-integrity.c ++!Iblock/blktrace.c ++!Iblock/genhd.c ++!Eblock/genhd.c + + + +--- a/Documentation/block/deadline-iosched.txt ++++ b/Documentation/block/deadline-iosched.txt +@@ -30,12 +30,18 @@ write_expire (in ms) + Similar to read_expire mentioned above, but for writes. + + +-fifo_batch ++fifo_batch (number of requests) + ---------- + +-When a read request expires its deadline, we must move some requests from +-the sorted io scheduler list to the block device dispatch queue. fifo_batch +-controls how many requests we move. ++Requests are grouped into ``batches'' of a particular data direction (read or ++write) which are serviced in increasing sector order. To limit extra seeking, ++deadline expiries are only checked between batches. fifo_batch controls the ++maximum number of requests per batch. ++ ++This parameter tunes the balance between per-request latency and aggregate ++throughput. When low latency is the primary concern, smaller is better (where ++a value of 1 yields first-come first-served behaviour). Increasing fifo_batch ++generally improves throughput, at the cost of latency variation. + + + writes_starved (number of dispatches) +--- a/block/Makefile ++++ b/block/Makefile +@@ -4,8 +4,8 @@ + + obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ + blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ +- blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o \ +- cmd-filter.o ++ blk-exec.o blk-merge.o blk-softirq.o ioctl.o genhd.o \ ++ scsi_ioctl.o cmd-filter.o + + obj-$(CONFIG_BLK_DEV_BSG) += bsg.o + obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -26,8 +26,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + +@@ -50,8 +48,6 @@ struct kmem_cache *blk_requestq_cachep; + */ + static struct workqueue_struct *kblockd_workqueue; + +-static DEFINE_PER_CPU(struct list_head, blk_cpu_done); +- + static void drive_stat_acct(struct request *rq, int new_io) + { + struct hd_struct *part; +@@ -531,7 +527,7 @@ EXPORT_SYMBOL(blk_alloc_queue_node); + * request queue; this lock will be taken also from interrupt context, so irq + * disabling is needed for it. + * +- * Function returns a pointer to the initialized request queue, or NULL if ++ * Function returns a pointer to the initialized request queue, or %NULL if + * it didn't succeed. + * + * Note: +@@ -913,7 +909,7 @@ void blk_requeue_request(struct request_ + EXPORT_SYMBOL(blk_requeue_request); + + /** +- * blk_insert_request - insert a special request in to a request queue ++ * blk_insert_request - insert a special request into a request queue + * @q: request queue where request should be inserted + * @rq: request to be inserted + * @at_head: insert request at head or tail of queue +@@ -923,8 +919,8 @@ EXPORT_SYMBOL(blk_requeue_request); + * Many block devices need to execute commands asynchronously, so they don't + * block the whole kernel from preemption during request execution. This is + * accomplished normally by inserting aritficial requests tagged as +- * REQ_SPECIAL in to the corresponding request queue, and letting them be +- * scheduled for actual execution by the request queue. ++ * REQ_TYPE_SPECIAL in to the corresponding request queue, and letting them ++ * be scheduled for actual execution by the request queue. + * + * We have the option of inserting the head or the tail of the queue. + * Typically we use the tail for new ioctls and so forth. We use the head +@@ -1322,7 +1318,7 @@ static inline int bio_check_eod(struct b + } + + /** +- * generic_make_request: hand a buffer to its device driver for I/O ++ * generic_make_request - hand a buffer to its device driver for I/O + * @bio: The bio describing the location in memory and on the device. + * + * generic_make_request() is used to make I/O requests of block +@@ -1480,13 +1476,13 @@ void generic_make_request(struct bio *bi + EXPORT_SYMBOL(generic_make_request); + + /** +- * submit_bio: submit a bio to the block device layer for I/O ++ * submit_bio - submit a bio to the block device layer for I/O + * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) + * @bio: The &struct bio which describes the I/O + * + * submit_bio() is very similar in purpose to generic_make_request(), and + * uses that function to do most of the work. Both are fairly rough +- * interfaces, @bio must be presetup and ready for I/O. ++ * interfaces; @bio must be presetup and ready for I/O. + * + */ + void submit_bio(int rw, struct bio *bio) +@@ -1524,7 +1520,7 @@ EXPORT_SYMBOL(submit_bio); + /** + * __end_that_request_first - end I/O on a request + * @req: the request being processed +- * @error: 0 for success, < 0 for error ++ * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: +@@ -1532,8 +1528,8 @@ EXPORT_SYMBOL(submit_bio); + * for the next range of segments (if any) in the cluster. + * + * Return: +- * 0 - we are done with this request, call end_that_request_last() +- * 1 - still buffers pending for this request ++ * %0 - we are done with this request, call end_that_request_last() ++ * %1 - still buffers pending for this request + **/ + static int __end_that_request_first(struct request *req, int error, + int nr_bytes) +@@ -1544,7 +1540,7 @@ static int __end_that_request_first(stru + blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE); + + /* +- * for a REQ_BLOCK_PC request, we want to carry any eventual ++ * for a REQ_TYPE_BLOCK_PC request, we want to carry any eventual + * sense key with us all the way through + */ + if (!blk_pc_request(req)) +@@ -1646,82 +1642,6 @@ static int __end_that_request_first(stru + } + + /* +- * splice the completion data to a local structure and hand off to +- * process_completion_queue() to complete the requests +- */ +-static void blk_done_softirq(struct softirq_action *h) +-{ +- struct list_head *cpu_list, local_list; +- +- local_irq_disable(); +- cpu_list = &__get_cpu_var(blk_cpu_done); +- list_replace_init(cpu_list, &local_list); +- local_irq_enable(); +- +- while (!list_empty(&local_list)) { +- struct request *rq; +- +- rq = list_entry(local_list.next, struct request, donelist); +- list_del_init(&rq->donelist); +- rq->q->softirq_done_fn(rq); +- } +-} +- +-static int __cpuinit blk_cpu_notify(struct notifier_block *self, +- unsigned long action, void *hcpu) +-{ +- /* +- * If a CPU goes away, splice its entries to the current CPU +- * and trigger a run of the softirq +- */ +- if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { +- int cpu = (unsigned long) hcpu; +- +- local_irq_disable(); +- list_splice_init(&per_cpu(blk_cpu_done, cpu), +- &__get_cpu_var(blk_cpu_done)); +- raise_softirq_irqoff(BLOCK_SOFTIRQ); +- local_irq_enable(); +- } +- +- return NOTIFY_OK; +-} +- +- +-static struct notifier_block blk_cpu_notifier __cpuinitdata = { +- .notifier_call = blk_cpu_notify, +-}; +- +-/** +- * blk_complete_request - end I/O on a request +- * @req: the request being processed +- * +- * Description: +- * Ends all I/O on a request. It does not handle partial completions, +- * unless the driver actually implements this in its completion callback +- * through requeueing. The actual completion happens out-of-order, +- * through a softirq handler. The user must have registered a completion +- * callback through blk_queue_softirq_done(). +- **/ +- +-void blk_complete_request(struct request *req) +-{ +- struct list_head *cpu_list; +- unsigned long flags; +- +- BUG_ON(!req->q->softirq_done_fn); +- +- local_irq_save(flags); +- +- cpu_list = &__get_cpu_var(blk_cpu_done); +- list_add_tail(&req->donelist, cpu_list); +- raise_softirq_irqoff(BLOCK_SOFTIRQ); +- +- local_irq_restore(flags); +-} +-EXPORT_SYMBOL(blk_complete_request); +- +-/* + * queue lock must be held + */ + static void end_that_request_last(struct request *req, int error) +@@ -1810,11 +1730,11 @@ EXPORT_SYMBOL_GPL(blk_rq_cur_bytes); + /** + * end_queued_request - end all I/O on a queued request + * @rq: the request being processed +- * @uptodate: error value or 0/1 uptodate flag ++ * @uptodate: error value or %0/%1 uptodate flag + * + * Description: + * Ends all I/O on a request, and removes it from the block layer queues. +- * Not suitable for normal IO completion, unless the driver still has ++ * Not suitable for normal I/O completion, unless the driver still has + * the request attached to the block layer. + * + **/ +@@ -1827,7 +1747,7 @@ EXPORT_SYMBOL(end_queued_request); + /** + * end_dequeued_request - end all I/O on a dequeued request + * @rq: the request being processed +- * @uptodate: error value or 0/1 uptodate flag ++ * @uptodate: error value or %0/%1 uptodate flag + * + * Description: + * Ends all I/O on a request. The request must already have been +@@ -1845,14 +1765,14 @@ EXPORT_SYMBOL(end_dequeued_request); + /** + * end_request - end I/O on the current segment of the request + * @req: the request being processed +- * @uptodate: error value or 0/1 uptodate flag ++ * @uptodate: error value or %0/%1 uptodate flag + * + * Description: + * Ends I/O on the current segment of a request. If that is the only + * remaining segment, the request is also completed and freed. + * +- * This is a remnant of how older block drivers handled IO completions. +- * Modern drivers typically end IO on the full request in one go, unless ++ * This is a remnant of how older block drivers handled I/O completions. ++ * Modern drivers typically end I/O on the full request in one go, unless + * they have a residual value to account for. For that case this function + * isn't really useful, unless the residual just happens to be the + * full current segment. In other words, don't use this function in new +@@ -1870,12 +1790,12 @@ EXPORT_SYMBOL(end_request); + /** + * blk_end_io - Generic end_io function to complete a request. + * @rq: the request being processed +- * @error: 0 for success, < 0 for error ++ * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete @rq + * @bidi_bytes: number of bytes to complete @rq->next_rq + * @drv_callback: function called between completion of bios in the request + * and completion of the request. +- * If the callback returns non 0, this helper returns without ++ * If the callback returns non %0, this helper returns without + * completion of the request. + * + * Description: +@@ -1883,8 +1803,8 @@ EXPORT_SYMBOL(end_request); + * If @rq has leftover, sets it up for the next range of segments. + * + * Return: +- * 0 - we are done with this request +- * 1 - this request is not freed yet, it still has pending buffers. ++ * %0 - we are done with this request ++ * %1 - this request is not freed yet, it still has pending buffers. + **/ + static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes, + unsigned int bidi_bytes, +@@ -1893,7 +1813,7 @@ static int blk_end_io(struct request *rq + struct request_queue *q = rq->q; + unsigned long flags = 0UL; + +- if (bio_has_data(rq->bio) || blk_discard_rq(rq)) { ++ if (rq->bio) { + if (__end_that_request_first(rq, error, nr_bytes)) + return 1; + +@@ -1919,7 +1839,7 @@ static int blk_end_io(struct request *rq + /** + * blk_end_request - Helper function for drivers to complete the request. + * @rq: the request being processed +- * @error: 0 for success, < 0 for error ++ * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: +@@ -1927,8 +1847,8 @@ static int blk_end_io(struct request *rq + * If @rq has leftover, sets it up for the next range of segments. + * + * Return: +- * 0 - we are done with this request +- * 1 - still buffers pending for this request ++ * %0 - we are done with this request ++ * %1 - still buffers pending for this request + **/ + int blk_end_request(struct request *rq, int error, unsigned int nr_bytes) + { +@@ -1939,20 +1859,19 @@ EXPORT_SYMBOL_GPL(blk_end_request); + /** + * __blk_end_request - Helper function for drivers to complete the request. + * @rq: the request being processed +- * @error: 0 for success, < 0 for error ++ * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * + * Description: + * Must be called with queue lock held unlike blk_end_request(). + * + * Return: +- * 0 - we are done with this request +- * 1 - still buffers pending for this request ++ * %0 - we are done with this request ++ * %1 - still buffers pending for this request + **/ + int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) + { +- if ((bio_has_data(rq->bio) || blk_discard_rq(rq)) && +- __end_that_request_first(rq, error, nr_bytes)) ++ if (rq->bio && __end_that_request_first(rq, error, nr_bytes)) + return 1; + + add_disk_randomness(rq->rq_disk); +@@ -1966,7 +1885,7 @@ EXPORT_SYMBOL_GPL(__blk_end_request); + /** + * blk_end_bidi_request - Helper function for drivers to complete bidi request. + * @rq: the bidi request being processed +- * @error: 0 for success, < 0 for error ++ * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete @rq + * @bidi_bytes: number of bytes to complete @rq->next_rq + * +@@ -1974,8 +1893,8 @@ EXPORT_SYMBOL_GPL(__blk_end_request); + * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. + * + * Return: +- * 0 - we are done with this request +- * 1 - still buffers pending for this request ++ * %0 - we are done with this request ++ * %1 - still buffers pending for this request + **/ + int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes, + unsigned int bidi_bytes) +@@ -1987,11 +1906,11 @@ EXPORT_SYMBOL_GPL(blk_end_bidi_request); + /** + * blk_end_request_callback - Special helper function for tricky drivers + * @rq: the request being processed +- * @error: 0 for success, < 0 for error ++ * @error: %0 for success, < %0 for error + * @nr_bytes: number of bytes to complete + * @drv_callback: function called between completion of bios in the request + * and completion of the request. +- * If the callback returns non 0, this helper returns without ++ * If the callback returns non %0, this helper returns without + * completion of the request. + * + * Description: +@@ -2004,10 +1923,10 @@ EXPORT_SYMBOL_GPL(blk_end_bidi_request); + * Don't use this interface in other places anymore. + * + * Return: +- * 0 - we are done with this request +- * 1 - this request is not freed yet. +- * this request still has pending buffers or +- * the driver doesn't want to finish this request yet. ++ * %0 - we are done with this request ++ * %1 - this request is not freed yet. ++ * this request still has pending buffers or ++ * the driver doesn't want to finish this request yet. + **/ + int blk_end_request_callback(struct request *rq, int error, + unsigned int nr_bytes, +@@ -2026,7 +1945,6 @@ void blk_rq_bio_prep(struct request_queu + + if (bio_has_data(bio)) { + rq->nr_phys_segments = bio_phys_segments(q, bio); +- rq->nr_hw_segments = bio_hw_segments(q, bio); + rq->buffer = bio_data(bio); + } + rq->current_nr_sectors = bio_cur_sectors(bio); +@@ -2054,8 +1972,6 @@ EXPORT_SYMBOL(kblockd_flush_work); + + int __init blk_dev_init(void) + { +- int i; +- + kblockd_workqueue = create_workqueue("kblockd"); + if (!kblockd_workqueue) + panic("Failed to create kblockd\n"); +@@ -2066,12 +1982,6 @@ int __init blk_dev_init(void) + blk_requestq_cachep = kmem_cache_create("blkdev_queue", + sizeof(struct request_queue), 0, SLAB_PANIC, NULL); + +- for_each_possible_cpu(i) +- INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); +- +- open_softirq(BLOCK_SOFTIRQ, blk_done_softirq); +- register_hotcpu_notifier(&blk_cpu_notifier); +- + return 0; + } + +--- a/block/blk-exec.c ++++ b/block/blk-exec.c +@@ -16,7 +16,7 @@ + /** + * blk_end_sync_rq - executes a completion event on a request + * @rq: request to complete +- * @error: end io status of the request ++ * @error: end I/O status of the request + */ + static void blk_end_sync_rq(struct request *rq, int error) + { +@@ -41,7 +41,7 @@ static void blk_end_sync_rq(struct reque + * @done: I/O completion handler + * + * Description: +- * Insert a fully prepared request at the back of the io scheduler queue ++ * Insert a fully prepared request at the back of the I/O scheduler queue + * for execution. Don't wait for completion. + */ + void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, +@@ -72,7 +72,7 @@ EXPORT_SYMBOL_GPL(blk_execute_rq_nowait) + * @at_head: insert request at head or tail of queue + * + * Description: +- * Insert a fully prepared request at the back of the io scheduler queue ++ * Insert a fully prepared request at the back of the I/O scheduler queue + * for execution and wait for completion. + */ + int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk, +--- a/block/blk-integrity.c ++++ b/block/blk-integrity.c +@@ -109,8 +109,8 @@ EXPORT_SYMBOL(blk_rq_map_integrity_sg); + + /** + * blk_integrity_compare - Compare integrity profile of two block devices +- * @b1: Device to compare +- * @b2: Device to compare ++ * @bd1: Device to compare ++ * @bd2: Device to compare + * + * Description: Meta-devices like DM and MD need to verify that all + * sub-devices use the same integrity format before advertising to +--- a/block/blk-map.c ++++ b/block/blk-map.c +@@ -85,17 +85,17 @@ static int __blk_rq_map_user(struct requ + } + + /** +- * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage ++ * blk_rq_map_user - map user data to a request, for REQ_TYPE_BLOCK_PC usage + * @q: request queue where request should be inserted + * @rq: request structure to fill + * @ubuf: the user buffer + * @len: length of user data + * + * Description: +- * Data will be mapped directly for zero copy io, if possible. Otherwise ++ * Data will be mapped directly for zero copy I/O, if possible. Otherwise + * a kernel bounce buffer is used. + * +- * A matching blk_rq_unmap_user() must be issued at the end of io, while ++ * A matching blk_rq_unmap_user() must be issued at the end of I/O, while + * still in process context. + * + * Note: The mapped bio may need to be bounced through blk_queue_bounce() +@@ -154,7 +154,7 @@ unmap_rq: + EXPORT_SYMBOL(blk_rq_map_user); + + /** +- * blk_rq_map_user_iov - map user data to a request, for REQ_BLOCK_PC usage ++ * blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage + * @q: request queue where request should be inserted + * @rq: request to map data to + * @iov: pointer to the iovec +@@ -162,10 +162,10 @@ EXPORT_SYMBOL(blk_rq_map_user); + * @len: I/O byte count + * + * Description: +- * Data will be mapped directly for zero copy io, if possible. Otherwise ++ * Data will be mapped directly for zero copy I/O, if possible. Otherwise + * a kernel bounce buffer is used. + * +- * A matching blk_rq_unmap_user() must be issued at the end of io, while ++ * A matching blk_rq_unmap_user() must be issued at the end of I/O, while + * still in process context. + * + * Note: The mapped bio may need to be bounced through blk_queue_bounce() +@@ -224,7 +224,7 @@ int blk_rq_map_user_iov(struct request_q + * Description: + * Unmap a rq previously mapped by blk_rq_map_user(). The caller must + * supply the original rq->bio from the blk_rq_map_user() return, since +- * the io completion may have changed rq->bio. ++ * the I/O completion may have changed rq->bio. + */ + int blk_rq_unmap_user(struct bio *bio) + { +@@ -250,7 +250,7 @@ int blk_rq_unmap_user(struct bio *bio) + EXPORT_SYMBOL(blk_rq_unmap_user); + + /** +- * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage ++ * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage + * @q: request queue where request should be inserted + * @rq: request to fill + * @kbuf: the kernel buffer +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -41,12 +41,9 @@ void blk_recalc_rq_sectors(struct reques + void blk_recalc_rq_segments(struct request *rq) + { + int nr_phys_segs; +- int nr_hw_segs; + unsigned int phys_size; +- unsigned int hw_size; + struct bio_vec *bv, *bvprv = NULL; + int seg_size; +- int hw_seg_size; + int cluster; + struct req_iterator iter; + int high, highprv = 1; +@@ -56,8 +53,8 @@ void blk_recalc_rq_segments(struct reque + return; + + cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); +- hw_seg_size = seg_size = 0; +- phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; ++ seg_size = 0; ++ phys_size = nr_phys_segs = 0; + rq_for_each_segment(bv, rq, iter) { + /* + * the trick here is making sure that a high page is never +@@ -66,7 +63,7 @@ void blk_recalc_rq_segments(struct reque + */ + high = page_to_pfn(bv->bv_page) > q->bounce_pfn; + if (high || highprv) +- goto new_hw_segment; ++ goto new_segment; + if (cluster) { + if (seg_size + bv->bv_len > q->max_segment_size) + goto new_segment; +@@ -74,27 +71,12 @@ void blk_recalc_rq_segments(struct reque + goto new_segment; + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv)) + goto new_segment; +- if (BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len)) +- goto new_hw_segment; + + seg_size += bv->bv_len; +- hw_seg_size += bv->bv_len; + bvprv = bv; + continue; + } + new_segment: +- if (BIOVEC_VIRT_MERGEABLE(bvprv, bv) && +- !BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len)) +- hw_seg_size += bv->bv_len; +- else { +-new_hw_segment: +- if (nr_hw_segs == 1 && +- hw_seg_size > rq->bio->bi_hw_front_size) +- rq->bio->bi_hw_front_size = hw_seg_size; +- hw_seg_size = BIOVEC_VIRT_START_SIZE(bv) + bv->bv_len; +- nr_hw_segs++; +- } +- + if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) + rq->bio->bi_seg_front_size = seg_size; + +@@ -104,17 +86,11 @@ new_hw_segment: + highprv = high; + } + +- if (nr_hw_segs == 1 && +- hw_seg_size > rq->bio->bi_hw_front_size) +- rq->bio->bi_hw_front_size = hw_seg_size; +- if (hw_seg_size > rq->biotail->bi_hw_back_size) +- rq->biotail->bi_hw_back_size = hw_seg_size; + if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size) + rq->bio->bi_seg_front_size = seg_size; + if (seg_size > rq->biotail->bi_seg_back_size) + rq->biotail->bi_seg_back_size = seg_size; + rq->nr_phys_segments = nr_phys_segs; +- rq->nr_hw_segments = nr_hw_segs; + } + + void blk_recount_segments(struct request_queue *q, struct bio *bio) +@@ -127,7 +103,6 @@ void blk_recount_segments(struct request + blk_recalc_rq_segments(&rq); + bio->bi_next = nxt; + bio->bi_phys_segments = rq.nr_phys_segments; +- bio->bi_hw_segments = rq.nr_hw_segments; + bio->bi_flags |= (1 << BIO_SEG_VALID); + } + EXPORT_SYMBOL(blk_recount_segments); +@@ -158,23 +133,6 @@ static int blk_phys_contig_segment(struc + return 0; + } + +-static int blk_hw_contig_segment(struct request_queue *q, struct bio *bio, +- struct bio *nxt) +-{ +- if (!bio_flagged(bio, BIO_SEG_VALID)) +- blk_recount_segments(q, bio); +- if (!bio_flagged(nxt, BIO_SEG_VALID)) +- blk_recount_segments(q, nxt); +- if (bio_has_data(bio) && +- (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) || +- BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size))) +- return 0; +- if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size) +- return 0; +- +- return 1; +-} +- + /* + * map a request to scatterlist, return number of sg entries setup. Caller + * must make sure sg can hold rq->nr_phys_segments entries +@@ -288,10 +246,9 @@ static inline int ll_new_hw_segment(stru + struct request *req, + struct bio *bio) + { +- int nr_hw_segs = bio_hw_segments(q, bio); + int nr_phys_segs = bio_phys_segments(q, bio); + +- if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments ++ if (req->nr_phys_segments + nr_phys_segs > q->max_hw_segments + || req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) { + req->cmd_flags |= REQ_NOMERGE; + if (req == q->last_merge) +@@ -303,7 +260,6 @@ static inline int ll_new_hw_segment(stru + * This will form the start of a new hw segment. Bump both + * counters. + */ +- req->nr_hw_segments += nr_hw_segs; + req->nr_phys_segments += nr_phys_segs; + return 1; + } +@@ -312,7 +268,6 @@ int ll_back_merge_fn(struct request_queu + struct bio *bio) + { + unsigned short max_sectors; +- int len; + + if (unlikely(blk_pc_request(req))) + max_sectors = q->max_hw_sectors; +@@ -329,20 +284,6 @@ int ll_back_merge_fn(struct request_queu + blk_recount_segments(q, req->biotail); + if (!bio_flagged(bio, BIO_SEG_VALID)) + blk_recount_segments(q, bio); +- len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size; +- if (!bio_has_data(bio) || +- (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)) +- && !BIOVEC_VIRT_OVERSIZE(len))) { +- int mergeable = ll_new_mergeable(q, req, bio); +- +- if (mergeable) { +- if (req->nr_hw_segments == 1) +- req->bio->bi_hw_front_size = len; +- if (bio->bi_hw_segments == 1) +- bio->bi_hw_back_size = len; +- } +- return mergeable; +- } + + return ll_new_hw_segment(q, req, bio); + } +@@ -351,7 +292,6 @@ int ll_front_merge_fn(struct request_que + struct bio *bio) + { + unsigned short max_sectors; +- int len; + + if (unlikely(blk_pc_request(req))) + max_sectors = q->max_hw_sectors; +@@ -365,24 +305,10 @@ int ll_front_merge_fn(struct request_que + q->last_merge = NULL; + return 0; + } +- len = bio->bi_hw_back_size + req->bio->bi_hw_front_size; + if (!bio_flagged(bio, BIO_SEG_VALID)) + blk_recount_segments(q, bio); + if (!bio_flagged(req->bio, BIO_SEG_VALID)) + blk_recount_segments(q, req->bio); +- if (!bio_has_data(bio) || +- (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) && +- !BIOVEC_VIRT_OVERSIZE(len))) { +- int mergeable = ll_new_mergeable(q, req, bio); +- +- if (mergeable) { +- if (bio->bi_hw_segments == 1) +- bio->bi_hw_front_size = len; +- if (req->nr_hw_segments == 1) +- req->biotail->bi_hw_back_size = len; +- } +- return mergeable; +- } + + return ll_new_hw_segment(q, req, bio); + } +@@ -391,7 +317,6 @@ static int ll_merge_requests_fn(struct r + struct request *next) + { + int total_phys_segments; +- int total_hw_segments; + unsigned int seg_size = + req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size; + +@@ -420,26 +345,11 @@ static int ll_merge_requests_fn(struct r + if (total_phys_segments > q->max_phys_segments) + return 0; + +- total_hw_segments = req->nr_hw_segments + next->nr_hw_segments; +- if (blk_hw_contig_segment(q, req->biotail, next->bio)) { +- int len = req->biotail->bi_hw_back_size + +- next->bio->bi_hw_front_size; +- /* +- * propagate the combined length to the end of the requests +- */ +- if (req->nr_hw_segments == 1) +- req->bio->bi_hw_front_size = len; +- if (next->nr_hw_segments == 1) +- next->biotail->bi_hw_back_size = len; +- total_hw_segments--; +- } +- +- if (total_hw_segments > q->max_hw_segments) ++ if (total_phys_segments > q->max_hw_segments) + return 0; + + /* Merge is OK... */ + req->nr_phys_segments = total_phys_segments; +- req->nr_hw_segments = total_hw_segments; + return 1; + } + +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -144,7 +144,7 @@ EXPORT_SYMBOL(blk_queue_make_request); + * Different hardware can have different requirements as to what pages + * it can do I/O directly to. A low level driver can call + * blk_queue_bounce_limit to have lower memory pages allocated as bounce +- * buffers for doing I/O to pages residing above @page. ++ * buffers for doing I/O to pages residing above @dma_addr. + **/ + void blk_queue_bounce_limit(struct request_queue *q, u64 dma_addr) + { +@@ -229,7 +229,7 @@ EXPORT_SYMBOL(blk_queue_max_phys_segment + * Description: + * Enables a low level driver to set an upper limit on the number of + * hw data segments in a request. This would be the largest number of +- * address/length pairs the host adapter can actually give as once ++ * address/length pairs the host adapter can actually give at once + * to the device. + **/ + void blk_queue_max_hw_segments(struct request_queue *q, +@@ -410,7 +410,7 @@ EXPORT_SYMBOL(blk_queue_segment_boundary + * @mask: alignment mask + * + * description: +- * set required memory and length aligment for direct dma transactions. ++ * set required memory and length alignment for direct dma transactions. + * this is used when buiding direct io requests for the queue. + * + **/ +@@ -426,7 +426,7 @@ EXPORT_SYMBOL(blk_queue_dma_alignment); + * @mask: alignment mask + * + * description: +- * update required memory and length aligment for direct dma transactions. ++ * update required memory and length alignment for direct dma transactions. + * If the requested alignment is larger than the current alignment, then + * the current queue alignment is updated to the new value, otherwise it + * is left alone. The design of this is to allow multiple objects +--- /dev/null ++++ b/block/blk-softirq.c +@@ -0,0 +1,103 @@ ++/* ++ * Functions related to softirq rq completions ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "blk.h" ++ ++static DEFINE_PER_CPU(struct list_head, blk_cpu_done); ++ ++static int __cpuinit blk_cpu_notify(struct notifier_block *self, ++ unsigned long action, void *hcpu) ++{ ++ /* ++ * If a CPU goes away, splice its entries to the current CPU ++ * and trigger a run of the softirq ++ */ ++ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { ++ int cpu = (unsigned long) hcpu; ++ ++ local_irq_disable(); ++ list_splice_init(&per_cpu(blk_cpu_done, cpu), ++ &__get_cpu_var(blk_cpu_done)); ++ raise_softirq_irqoff(BLOCK_SOFTIRQ); ++ local_irq_enable(); ++ } ++ ++ return NOTIFY_OK; ++} ++ ++ ++static struct notifier_block blk_cpu_notifier __cpuinitdata = { ++ .notifier_call = blk_cpu_notify, ++}; ++ ++/* ++ * splice the completion data to a local structure and hand off to ++ * process_completion_queue() to complete the requests ++ */ ++static void blk_done_softirq(struct softirq_action *h) ++{ ++ struct list_head *cpu_list, local_list; ++ ++ local_irq_disable(); ++ cpu_list = &__get_cpu_var(blk_cpu_done); ++ list_replace_init(cpu_list, &local_list); ++ local_irq_enable(); ++ ++ while (!list_empty(&local_list)) { ++ struct request *rq; ++ ++ rq = list_entry(local_list.next, struct request, donelist); ++ list_del_init(&rq->donelist); ++ rq->q->softirq_done_fn(rq); ++ } ++} ++ ++/** ++ * blk_complete_request - end I/O on a request ++ * @req: the request being processed ++ * ++ * Description: ++ * Ends all I/O on a request. It does not handle partial completions, ++ * unless the driver actually implements this in its completion callback ++ * through requeueing. The actual completion happens out-of-order, ++ * through a softirq handler. The user must have registered a completion ++ * callback through blk_queue_softirq_done(). ++ **/ ++ ++void blk_complete_request(struct request *req) ++{ ++ struct list_head *cpu_list; ++ unsigned long flags; ++ ++ BUG_ON(!req->q->softirq_done_fn); ++ ++ local_irq_save(flags); ++ ++ cpu_list = &__get_cpu_var(blk_cpu_done); ++ list_add_tail(&req->donelist, cpu_list); ++ raise_softirq_irqoff(BLOCK_SOFTIRQ); ++ ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL(blk_complete_request); ++ ++int __init blk_softirq_init(void) ++{ ++ int i; ++ ++ for_each_possible_cpu(i) ++ INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); ++ ++ open_softirq(BLOCK_SOFTIRQ, blk_done_softirq); ++ register_hotcpu_notifier(&blk_cpu_notifier); ++ return 0; ++} ++subsys_initcall(blk_softirq_init); +--- a/block/blk-tag.c ++++ b/block/blk-tag.c +@@ -29,7 +29,7 @@ EXPORT_SYMBOL(blk_queue_find_tag); + * __blk_free_tags - release a given set of tag maintenance info + * @bqt: the tag map to free + * +- * Tries to free the specified @bqt@. Returns true if it was ++ * Tries to free the specified @bqt. Returns true if it was + * actually freed and false if there are still references using it + */ + static int __blk_free_tags(struct blk_queue_tag *bqt) +@@ -78,7 +78,7 @@ void __blk_queue_free_tags(struct reques + * blk_free_tags - release a given set of tag maintenance info + * @bqt: the tag map to free + * +- * For externally managed @bqt@ frees the map. Callers of this ++ * For externally managed @bqt frees the map. Callers of this + * function must guarantee to have released all the queues that + * might have been using this tag map. + */ +@@ -94,7 +94,7 @@ EXPORT_SYMBOL(blk_free_tags); + * @q: the request queue for the device + * + * Notes: +- * This is used to disabled tagged queuing to a device, yet leave ++ * This is used to disable tagged queuing to a device, yet leave + * queue in function. + **/ + void blk_queue_free_tags(struct request_queue *q) +@@ -271,7 +271,7 @@ EXPORT_SYMBOL(blk_queue_resize_tags); + * @rq: the request that has completed + * + * Description: +- * Typically called when end_that_request_first() returns 0, meaning ++ * Typically called when end_that_request_first() returns %0, meaning + * all transfers have been done for a request. It's important to call + * this function before end_that_request_last(), as that will put the + * request back on the free list thus corrupting the internal tag list. +--- a/block/cfq-iosched.c ++++ b/block/cfq-iosched.c +@@ -39,6 +39,7 @@ static int cfq_slice_idle = HZ / 125; + #define CFQ_MIN_TT (2) + + #define CFQ_SLICE_SCALE (5) ++#define CFQ_HW_QUEUE_MIN (5) + + #define RQ_CIC(rq) \ + ((struct cfq_io_context *) (rq)->elevator_private) +@@ -86,7 +87,14 @@ struct cfq_data { + + int rq_in_driver; + int sync_flight; ++ ++ /* ++ * queue-depth detection ++ */ ++ int rq_queued; + int hw_tag; ++ int hw_tag_samples; ++ int rq_in_driver_peak; + + /* + * idle window management +@@ -654,15 +662,6 @@ static void cfq_activate_request(struct + cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", + cfqd->rq_in_driver); + +- /* +- * If the depth is larger 1, it really could be queueing. But lets +- * make the mark a little higher - idling could still be good for +- * low queueing, and a low queueing number could also just indicate +- * a SCSI mid layer like behaviour where limit+1 is often seen. +- */ +- if (!cfqd->hw_tag && cfqd->rq_in_driver > 4) +- cfqd->hw_tag = 1; +- + cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors; + } + +@@ -686,6 +685,7 @@ static void cfq_remove_request(struct re + list_del_init(&rq->queuelist); + cfq_del_rq_rb(rq); + ++ cfqq->cfqd->rq_queued--; + if (rq_is_meta(rq)) { + WARN_ON(!cfqq->meta_pending); + cfqq->meta_pending--; +@@ -1833,6 +1833,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, s + { + struct cfq_io_context *cic = RQ_CIC(rq); + ++ cfqd->rq_queued++; + if (rq_is_meta(rq)) + cfqq->meta_pending++; + +@@ -1880,6 +1881,31 @@ static void cfq_insert_request(struct re + cfq_rq_enqueued(cfqd, cfqq, rq); + } + ++/* ++ * Update hw_tag based on peak queue depth over 50 samples under ++ * sufficient load. ++ */ ++static void cfq_update_hw_tag(struct cfq_data *cfqd) ++{ ++ if (cfqd->rq_in_driver > cfqd->rq_in_driver_peak) ++ cfqd->rq_in_driver_peak = cfqd->rq_in_driver; ++ ++ if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN && ++ cfqd->rq_in_driver <= CFQ_HW_QUEUE_MIN) ++ return; ++ ++ if (cfqd->hw_tag_samples++ < 50) ++ return; ++ ++ if (cfqd->rq_in_driver_peak >= CFQ_HW_QUEUE_MIN) ++ cfqd->hw_tag = 1; ++ else ++ cfqd->hw_tag = 0; ++ ++ cfqd->hw_tag_samples = 0; ++ cfqd->rq_in_driver_peak = 0; ++} ++ + static void cfq_completed_request(struct request_queue *q, struct request *rq) + { + struct cfq_queue *cfqq = RQ_CFQQ(rq); +@@ -1890,6 +1916,8 @@ static void cfq_completed_request(struct + now = jiffies; + cfq_log_cfqq(cfqd, cfqq, "complete"); + ++ cfq_update_hw_tag(cfqd); ++ + WARN_ON(!cfqd->rq_in_driver); + WARN_ON(!cfqq->dispatched); + cfqd->rq_in_driver--; +@@ -2200,6 +2228,7 @@ static void *cfq_init_queue(struct reque + cfqd->cfq_slice[1] = cfq_slice_sync; + cfqd->cfq_slice_async_rq = cfq_slice_async_rq; + cfqd->cfq_slice_idle = cfq_slice_idle; ++ cfqd->hw_tag = 1; + + return cfqd; + } +--- a/block/deadline-iosched.c ++++ b/block/deadline-iosched.c +@@ -33,7 +33,7 @@ struct deadline_data { + */ + struct rb_root sort_list[2]; + struct list_head fifo_list[2]; +- ++ + /* + * next in sort order. read, write or both are NULL + */ +@@ -53,7 +53,11 @@ struct deadline_data { + + static void deadline_move_request(struct deadline_data *, struct request *); + +-#define RQ_RB_ROOT(dd, rq) (&(dd)->sort_list[rq_data_dir((rq))]) ++static inline struct rb_root * ++deadline_rb_root(struct deadline_data *dd, struct request *rq) ++{ ++ return &dd->sort_list[rq_data_dir(rq)]; ++} + + /* + * get the request after `rq' in sector-sorted order +@@ -72,15 +76,11 @@ deadline_latter_request(struct request * + static void + deadline_add_rq_rb(struct deadline_data *dd, struct request *rq) + { +- struct rb_root *root = RQ_RB_ROOT(dd, rq); ++ struct rb_root *root = deadline_rb_root(dd, rq); + struct request *__alias; + +-retry: +- __alias = elv_rb_add(root, rq); +- if (unlikely(__alias)) { ++ while (unlikely(__alias = elv_rb_add(root, rq))) + deadline_move_request(dd, __alias); +- goto retry; +- } + } + + static inline void +@@ -91,7 +91,7 @@ deadline_del_rq_rb(struct deadline_data + if (dd->next_rq[data_dir] == rq) + dd->next_rq[data_dir] = deadline_latter_request(rq); + +- elv_rb_del(RQ_RB_ROOT(dd, rq), rq); ++ elv_rb_del(deadline_rb_root(dd, rq), rq); + } + + /* +@@ -106,7 +106,7 @@ deadline_add_request(struct request_queu + deadline_add_rq_rb(dd, rq); + + /* +- * set expire time (only used for reads) and add to fifo list ++ * set expire time and add to fifo list + */ + rq_set_fifo_time(rq, jiffies + dd->fifo_expire[data_dir]); + list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]); +@@ -162,7 +162,7 @@ static void deadline_merged_request(stru + * if the merge was a front merge, we need to reposition request + */ + if (type == ELEVATOR_FRONT_MERGE) { +- elv_rb_del(RQ_RB_ROOT(dd, req), req); ++ elv_rb_del(deadline_rb_root(dd, req), req); + deadline_add_rq_rb(dd, req); + } + } +@@ -212,7 +212,7 @@ deadline_move_request(struct deadline_da + dd->next_rq[WRITE] = NULL; + dd->next_rq[data_dir] = deadline_latter_request(rq); + +- dd->last_sector = rq->sector + rq->nr_sectors; ++ dd->last_sector = rq_end_sector(rq); + + /* + * take it off the sort and fifo list, move +@@ -222,7 +222,7 @@ deadline_move_request(struct deadline_da + } + + /* +- * deadline_check_fifo returns 0 if there are no expired reads on the fifo, ++ * deadline_check_fifo returns 0 if there are no expired requests on the fifo, + * 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir]) + */ + static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) +@@ -258,17 +258,9 @@ static int deadline_dispatch_requests(st + else + rq = dd->next_rq[READ]; + +- if (rq) { +- /* we have a "next request" */ +- +- if (dd->last_sector != rq->sector) +- /* end the batch on a non sequential request */ +- dd->batching += dd->fifo_batch; +- +- if (dd->batching < dd->fifo_batch) +- /* we are still entitled to batch */ +- goto dispatch_request; +- } ++ if (rq && dd->batching < dd->fifo_batch) ++ /* we have a next request are still entitled to batch */ ++ goto dispatch_request; + + /* + * at this point we are not running a batch. select the appropriate +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -34,8 +34,7 @@ + #include + #include + #include +- +-#include ++#include + + static DEFINE_SPINLOCK(elv_list_lock); + static LIST_HEAD(elv_list); +@@ -790,7 +789,6 @@ struct request *elv_next_request(struct + * device can handle + */ + rq->nr_phys_segments++; +- rq->nr_hw_segments++; + } + + if (!q->prep_rq_fn) +@@ -813,7 +811,6 @@ struct request *elv_next_request(struct + * so that we don't add it again + */ + --rq->nr_phys_segments; +- --rq->nr_hw_segments; + } + + rq = NULL; +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -211,10 +211,11 @@ void unlink_gendisk(struct gendisk *disk + + /** + * get_gendisk - get partitioning information for a given device +- * @dev: device to get partitioning information for ++ * @devt: device to get partitioning information for ++ * @part: returned partition index + * + * This function gets the structure containing partitioning +- * information for the given device @dev. ++ * information for the given device @devt. + */ + struct gendisk *get_gendisk(dev_t devt, int *part) + { +--- a/drivers/block/ps3disk.c ++++ b/drivers/block/ps3disk.c +@@ -199,7 +199,8 @@ static void ps3disk_do_request(struct ps + if (blk_fs_request(req)) { + if (ps3disk_submit_request_sg(dev, req)) + break; +- } else if (req->cmd_type == REQ_TYPE_FLUSH) { ++ } else if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && ++ req->cmd[0] == REQ_LB_OP_FLUSH) { + if (ps3disk_submit_flush_request(dev, req)) + break; + } else { +@@ -257,7 +258,8 @@ static irqreturn_t ps3disk_interrupt(int + return IRQ_HANDLED; + } + +- if (req->cmd_type == REQ_TYPE_FLUSH) { ++ if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && ++ req->cmd[0] == REQ_LB_OP_FLUSH) { + read = 0; + num_sectors = req->hard_cur_sectors; + op = "flush"; +@@ -405,7 +407,8 @@ static void ps3disk_prepare_flush(struct + + dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); + +- req->cmd_type = REQ_TYPE_FLUSH; ++ req->cmd_type = REQ_TYPE_LINUX_BLOCK; ++ req->cmd[0] = REQ_LB_OP_FLUSH; + } + + static unsigned long ps3disk_mask; +--- a/drivers/block/virtio_blk.c ++++ b/drivers/block/virtio_blk.c +@@ -84,11 +84,11 @@ static bool do_req(struct request_queue + if (blk_fs_request(vbr->req)) { + vbr->out_hdr.type = 0; + vbr->out_hdr.sector = vbr->req->sector; +- vbr->out_hdr.ioprio = vbr->req->ioprio; ++ vbr->out_hdr.ioprio = req_get_ioprio(vbr->req); + } else if (blk_pc_request(vbr->req)) { + vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD; + vbr->out_hdr.sector = 0; +- vbr->out_hdr.ioprio = vbr->req->ioprio; ++ vbr->out_hdr.ioprio = req_get_ioprio(vbr->req); + } else { + /* We don't put anything else in the queue. */ + BUG(); +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1303,9 +1303,6 @@ static void sync_request_write(mddev_t * + sbio->bi_size = r1_bio->sectors << 9; + sbio->bi_idx = 0; + sbio->bi_phys_segments = 0; +- sbio->bi_hw_segments = 0; +- sbio->bi_hw_front_size = 0; +- sbio->bi_hw_back_size = 0; + sbio->bi_flags &= ~(BIO_POOL_MASK - 1); + sbio->bi_flags |= 1 << BIO_UPTODATE; + sbio->bi_next = NULL; +@@ -1791,7 +1788,6 @@ static sector_t sync_request(mddev_t *md + bio->bi_vcnt = 0; + bio->bi_idx = 0; + bio->bi_phys_segments = 0; +- bio->bi_hw_segments = 0; + bio->bi_size = 0; + bio->bi_end_io = NULL; + bio->bi_private = NULL; +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -1346,9 +1346,6 @@ static void sync_request_write(mddev_t * + tbio->bi_size = r10_bio->sectors << 9; + tbio->bi_idx = 0; + tbio->bi_phys_segments = 0; +- tbio->bi_hw_segments = 0; +- tbio->bi_hw_front_size = 0; +- tbio->bi_hw_back_size = 0; + tbio->bi_flags &= ~(BIO_POOL_MASK - 1); + tbio->bi_flags |= 1 << BIO_UPTODATE; + tbio->bi_next = NULL; +@@ -1948,7 +1945,6 @@ static sector_t sync_request(mddev_t *md + bio->bi_vcnt = 0; + bio->bi_idx = 0; + bio->bi_phys_segments = 0; +- bio->bi_hw_segments = 0; + bio->bi_size = 0; + } + +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -101,6 +101,40 @@ + const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); + #endif + ++/* ++ * We maintain a biased count of active stripes in the bottom 16 bits of ++ * bi_phys_segments, and a count of processed stripes in the upper 16 bits ++ */ ++static inline int raid5_bi_phys_segments(struct bio *bio) ++{ ++ return bio->bi_phys_segments & 0xffff; ++} ++ ++static inline int raid5_bi_hw_segments(struct bio *bio) ++{ ++ return (bio->bi_phys_segments >> 16) & 0xffff; ++} ++ ++static inline int raid5_dec_bi_phys_segments(struct bio *bio) ++{ ++ --bio->bi_phys_segments; ++ return raid5_bi_phys_segments(bio); ++} ++ ++static inline int raid5_dec_bi_hw_segments(struct bio *bio) ++{ ++ unsigned short val = raid5_bi_hw_segments(bio); ++ ++ --val; ++ bio->bi_phys_segments = (val << 16) | raid5_bi_phys_segments(bio); ++ return val; ++} ++ ++static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt) ++{ ++ bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16); ++} ++ + static inline int raid6_next_disk(int disk, int raid_disks) + { + disk++; +@@ -507,7 +541,7 @@ static void ops_complete_biofill(void *s + while (rbi && rbi->bi_sector < + dev->sector + STRIPE_SECTORS) { + rbi2 = r5_next_bio(rbi, dev->sector); +- if (--rbi->bi_phys_segments == 0) { ++ if (!raid5_dec_bi_phys_segments(rbi)) { + rbi->bi_next = return_bi; + return_bi = rbi; + } +@@ -1725,7 +1759,7 @@ static int add_stripe_bio(struct stripe_ + if (*bip) + bi->bi_next = *bip; + *bip = bi; +- bi->bi_phys_segments ++; ++ bi->bi_phys_segments++; + spin_unlock_irq(&conf->device_lock); + spin_unlock(&sh->lock); + +@@ -1819,7 +1853,7 @@ handle_failed_stripe(raid5_conf_t *conf, + sh->dev[i].sector + STRIPE_SECTORS) { + struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); + clear_bit(BIO_UPTODATE, &bi->bi_flags); +- if (--bi->bi_phys_segments == 0) { ++ if (!raid5_dec_bi_phys_segments(bi)) { + md_write_end(conf->mddev); + bi->bi_next = *return_bi; + *return_bi = bi; +@@ -1834,7 +1868,7 @@ handle_failed_stripe(raid5_conf_t *conf, + sh->dev[i].sector + STRIPE_SECTORS) { + struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); + clear_bit(BIO_UPTODATE, &bi->bi_flags); +- if (--bi->bi_phys_segments == 0) { ++ if (!raid5_dec_bi_phys_segments(bi)) { + md_write_end(conf->mddev); + bi->bi_next = *return_bi; + *return_bi = bi; +@@ -1858,7 +1892,7 @@ handle_failed_stripe(raid5_conf_t *conf, + struct bio *nextbi = + r5_next_bio(bi, sh->dev[i].sector); + clear_bit(BIO_UPTODATE, &bi->bi_flags); +- if (--bi->bi_phys_segments == 0) { ++ if (!raid5_dec_bi_phys_segments(bi)) { + bi->bi_next = *return_bi; + *return_bi = bi; + } +@@ -2033,7 +2067,7 @@ static void handle_stripe_clean_event(ra + while (wbi && wbi->bi_sector < + dev->sector + STRIPE_SECTORS) { + wbi2 = r5_next_bio(wbi, dev->sector); +- if (--wbi->bi_phys_segments == 0) { ++ if (!raid5_dec_bi_phys_segments(wbi)) { + md_write_end(conf->mddev); + wbi->bi_next = *return_bi; + *return_bi = wbi; +@@ -2814,7 +2848,7 @@ static bool handle_stripe6(struct stripe + copy_data(0, rbi, dev->page, dev->sector); + rbi2 = r5_next_bio(rbi, dev->sector); + spin_lock_irq(&conf->device_lock); +- if (--rbi->bi_phys_segments == 0) { ++ if (!raid5_dec_bi_phys_segments(rbi)) { + rbi->bi_next = return_bi; + return_bi = rbi; + } +@@ -3155,8 +3189,11 @@ static struct bio *remove_bio_from_retry + if(bi) { + conf->retry_read_aligned_list = bi->bi_next; + bi->bi_next = NULL; ++ /* ++ * this sets the active strip count to 1 and the processed ++ * strip count to zero (upper 8 bits) ++ */ + bi->bi_phys_segments = 1; /* biased count of active stripes */ +- bi->bi_hw_segments = 0; /* count of processed stripes */ + } + + return bi; +@@ -3206,8 +3243,7 @@ static int bio_fits_rdev(struct bio *bi) + if ((bi->bi_size>>9) > q->max_sectors) + return 0; + blk_recount_segments(q, bi); +- if (bi->bi_phys_segments > q->max_phys_segments || +- bi->bi_hw_segments > q->max_hw_segments) ++ if (bi->bi_phys_segments > q->max_phys_segments) + return 0; + + if (q->merge_bvec_fn) +@@ -3469,7 +3505,7 @@ static int make_request(struct request_q + + } + spin_lock_irq(&conf->device_lock); +- remaining = --bi->bi_phys_segments; ++ remaining = raid5_dec_bi_phys_segments(bi); + spin_unlock_irq(&conf->device_lock); + if (remaining == 0) { + +@@ -3753,7 +3789,7 @@ static int retry_aligned_read(raid5_con + sector += STRIPE_SECTORS, + scnt++) { + +- if (scnt < raid_bio->bi_hw_segments) ++ if (scnt < raid5_bi_hw_segments(raid_bio)) + /* already done this stripe */ + continue; + +@@ -3761,7 +3797,7 @@ static int retry_aligned_read(raid5_con + + if (!sh) { + /* failed to get a stripe - must wait */ +- raid_bio->bi_hw_segments = scnt; ++ raid5_set_bi_hw_segments(raid_bio, scnt); + conf->retry_read_aligned = raid_bio; + return handled; + } +@@ -3769,7 +3805,7 @@ static int retry_aligned_read(raid5_con + set_bit(R5_ReadError, &sh->dev[dd_idx].flags); + if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) { + release_stripe(sh); +- raid_bio->bi_hw_segments = scnt; ++ raid5_set_bi_hw_segments(raid_bio, scnt); + conf->retry_read_aligned = raid_bio; + return handled; + } +@@ -3779,7 +3815,7 @@ static int retry_aligned_read(raid5_con + handled++; + } + spin_lock_irq(&conf->device_lock); +- remaining = --raid_bio->bi_phys_segments; ++ remaining = raid5_dec_bi_phys_segments(raid_bio); + spin_unlock_irq(&conf->device_lock); + if (remaining == 0) + bio_endio(raid_bio, 0); +--- a/fs/bio.c ++++ b/fs/bio.c +@@ -208,14 +208,6 @@ inline int bio_phys_segments(struct requ + return bio->bi_phys_segments; + } + +-inline int bio_hw_segments(struct request_queue *q, struct bio *bio) +-{ +- if (unlikely(!bio_flagged(bio, BIO_SEG_VALID))) +- blk_recount_segments(q, bio); +- +- return bio->bi_hw_segments; +-} +- + /** + * __bio_clone - clone a bio + * @bio: destination bio +@@ -350,8 +342,7 @@ static int __bio_add_page(struct request + */ + + while (bio->bi_phys_segments >= q->max_phys_segments +- || bio->bi_hw_segments >= q->max_hw_segments +- || BIOVEC_VIRT_OVERSIZE(bio->bi_size)) { ++ || bio->bi_phys_segments >= q->max_hw_segments) { + + if (retried_segments) + return 0; +@@ -395,13 +386,11 @@ static int __bio_add_page(struct request + } + + /* If we may be able to merge these biovecs, force a recount */ +- if (bio->bi_vcnt && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec) || +- BIOVEC_VIRT_MERGEABLE(bvec-1, bvec))) ++ if (bio->bi_vcnt && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec))) + bio->bi_flags &= ~(1 << BIO_SEG_VALID); + + bio->bi_vcnt++; + bio->bi_phys_segments++; +- bio->bi_hw_segments++; + done: + bio->bi_size += len; + return len; +@@ -1393,7 +1382,6 @@ EXPORT_SYMBOL(bio_init); + EXPORT_SYMBOL(__bio_clone); + EXPORT_SYMBOL(bio_clone); + EXPORT_SYMBOL(bio_phys_segments); +-EXPORT_SYMBOL(bio_hw_segments); + EXPORT_SYMBOL(bio_add_page); + EXPORT_SYMBOL(bio_add_pc_page); + EXPORT_SYMBOL(bio_get_nr_vecs); +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -26,21 +26,8 @@ + + #ifdef CONFIG_BLOCK + +-/* Platforms may set this to teach the BIO layer about IOMMU hardware. */ + #include + +-#if defined(BIO_VMERGE_MAX_SIZE) && defined(BIO_VMERGE_BOUNDARY) +-#define BIOVEC_VIRT_START_SIZE(x) (bvec_to_phys(x) & (BIO_VMERGE_BOUNDARY - 1)) +-#define BIOVEC_VIRT_OVERSIZE(x) ((x) > BIO_VMERGE_MAX_SIZE) +-#else +-#define BIOVEC_VIRT_START_SIZE(x) 0 +-#define BIOVEC_VIRT_OVERSIZE(x) 0 +-#endif +- +-#ifndef BIO_VMERGE_BOUNDARY +-#define BIO_VMERGE_BOUNDARY 0 +-#endif +- + #define BIO_DEBUG + + #ifdef BIO_DEBUG +@@ -88,12 +75,7 @@ struct bio { + /* Number of segments in this BIO after + * physical address coalescing is performed. + */ +- unsigned short bi_phys_segments; +- +- /* Number of segments after physical and DMA remapping +- * hardware coalescing is performed. +- */ +- unsigned short bi_hw_segments; ++ unsigned int bi_phys_segments; + + unsigned int bi_size; /* residual I/O count */ + +@@ -104,14 +86,6 @@ struct bio { + unsigned int bi_seg_front_size; + unsigned int bi_seg_back_size; + +- /* +- * To keep track of the max hw size, we account for the +- * sizes of the first and last virtually mergeable segments +- * in this bio +- */ +- unsigned int bi_hw_front_size; +- unsigned int bi_hw_back_size; +- + unsigned int bi_max_vecs; /* max bvl_vecs we can hold */ + + struct bio_vec *bi_io_vec; /* the actual vec list */ +@@ -133,7 +107,7 @@ struct bio { + #define BIO_UPTODATE 0 /* ok after I/O completion */ + #define BIO_RW_BLOCK 1 /* RW_AHEAD set, and read/write would block */ + #define BIO_EOF 2 /* out-out-bounds error */ +-#define BIO_SEG_VALID 3 /* nr_hw_seg valid */ ++#define BIO_SEG_VALID 3 /* bi_phys_segments valid */ + #define BIO_CLONED 4 /* doesn't own data */ + #define BIO_BOUNCED 5 /* bio is a bounce bio */ + #define BIO_USER_MAPPED 6 /* contains user pages */ +@@ -247,8 +221,6 @@ static inline void *bio_data(struct bio + ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) + #endif + +-#define BIOVEC_VIRT_MERGEABLE(vec1, vec2) \ +- ((((bvec_to_phys((vec1)) + (vec1)->bv_len) | bvec_to_phys((vec2))) & (BIO_VMERGE_BOUNDARY - 1)) == 0) + #define __BIO_SEG_BOUNDARY(addr1, addr2, mask) \ + (((addr1) | (mask)) == (((addr2) - 1) | (mask))) + #define BIOVEC_SEG_BOUNDARY(q, b1, b2) \ +@@ -346,7 +318,6 @@ extern void bio_free(struct bio *, struc + extern void bio_endio(struct bio *, int); + struct request_queue; + extern int bio_phys_segments(struct request_queue *, struct bio *); +-extern int bio_hw_segments(struct request_queue *, struct bio *); + + extern void __bio_clone(struct bio *, struct bio *); + extern struct bio *bio_clone(struct bio *, gfp_t); +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -54,7 +54,6 @@ enum rq_cmd_type_bits { + REQ_TYPE_PM_SUSPEND, /* suspend request */ + REQ_TYPE_PM_RESUME, /* resume request */ + REQ_TYPE_PM_SHUTDOWN, /* shutdown request */ +- REQ_TYPE_FLUSH, /* flush request */ + REQ_TYPE_SPECIAL, /* driver defined type */ + REQ_TYPE_LINUX_BLOCK, /* generic block layer message */ + /* +@@ -76,11 +75,8 @@ enum rq_cmd_type_bits { + * + */ + enum { +- /* +- * just examples for now +- */ + REQ_LB_OP_EJECT = 0x40, /* eject request */ +- REQ_LB_OP_FLUSH = 0x41, /* flush device */ ++ REQ_LB_OP_FLUSH = 0x41, /* flush request */ + REQ_LB_OP_DISCARD = 0x42, /* discard sectors */ + }; + +@@ -193,13 +189,6 @@ struct request { + */ + unsigned short nr_phys_segments; + +- /* Number of scatter-gather addr+len pairs after +- * physical and DMA remapping hardware coalescing is performed. +- * This is the number of scatter-gather entries the driver +- * will actually have to deal with after DMA mapping is done. +- */ +- unsigned short nr_hw_segments; +- + unsigned short ioprio; + + void *special; +@@ -236,6 +225,11 @@ struct request { + struct request *next_rq; + }; + ++static inline unsigned short req_get_ioprio(struct request *req) ++{ ++ return req->ioprio; ++} ++ + /* + * State information carried for REQ_TYPE_PM_SUSPEND and REQ_TYPE_PM_RESUME + * requests. Some step values could eventually be made generic. diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-integrity-update b/src/patches/suse-2.6.27.31/patches.fixes/block-integrity-update new file mode 100644 index 000000000..76c9e8abd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-integrity-update @@ -0,0 +1,206 @@ +Subject: Block integrity update +From: Martin K. Petersen +Date: Mon Dec 8 09:36:35 2008 +0100: +References: FATE#304345 + +This patch series contains block layer integrity updates for 2.6.28. + +There are a few fixes to the core bits, including a switch from +block_device to gendisk in the integrity compare function. I also had +to add a helper to access a gendisk's integrity profile. This is used +by MD. + +Signed-off-by: Martin K. Petersen +Signed-off-by: Hannes Reinecke + +--- + block/blk-integrity.c | 30 +++++++++++++++--------------- + fs/bio-integrity.c | 3 ++- + fs/bio.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/bio.h | 2 ++ + include/linux/blkdev.h | 8 +++++++- + 5 files changed, 62 insertions(+), 17 deletions(-) + +--- a/block/blk-integrity.c ++++ b/block/blk-integrity.c +@@ -108,51 +108,51 @@ new_segment: + EXPORT_SYMBOL(blk_rq_map_integrity_sg); + + /** +- * blk_integrity_compare - Compare integrity profile of two block devices +- * @bd1: Device to compare +- * @bd2: Device to compare ++ * blk_integrity_compare - Compare integrity profile of two disks ++ * @gd1: Disk to compare ++ * @gd2: Disk to compare + * + * Description: Meta-devices like DM and MD need to verify that all + * sub-devices use the same integrity format before advertising to + * upper layers that they can send/receive integrity metadata. This +- * function can be used to check whether two block devices have ++ * function can be used to check whether two gendisk devices have + * compatible integrity formats. + */ +-int blk_integrity_compare(struct block_device *bd1, struct block_device *bd2) ++int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2) + { +- struct blk_integrity *b1 = bd1->bd_disk->integrity; +- struct blk_integrity *b2 = bd2->bd_disk->integrity; ++ struct blk_integrity *b1 = gd1->integrity; ++ struct blk_integrity *b2 = gd2->integrity; + +- BUG_ON(bd1->bd_disk == NULL); +- BUG_ON(bd2->bd_disk == NULL); ++ if (!b1 && !b2) ++ return 0; + + if (!b1 || !b2) +- return 0; ++ return -1; + + if (b1->sector_size != b2->sector_size) { + printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__, +- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, ++ gd1->disk_name, gd2->disk_name, + b1->sector_size, b2->sector_size); + return -1; + } + + if (b1->tuple_size != b2->tuple_size) { + printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__, +- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, ++ gd1->disk_name, gd2->disk_name, + b1->tuple_size, b2->tuple_size); + return -1; + } + + if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) { + printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__, +- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, ++ gd1->disk_name, gd2->disk_name, + b1->tag_size, b2->tag_size); + return -1; + } + + if (strcmp(b1->name, b2->name)) { + printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__, +- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, ++ gd1->disk_name, gd2->disk_name, + b1->name, b2->name); + return -1; + } +@@ -375,7 +375,7 @@ void blk_integrity_unregister(struct gen + + kobject_uevent(&bi->kobj, KOBJ_REMOVE); + kobject_del(&bi->kobj); +- kobject_put(&disk->dev.kobj); + kmem_cache_free(integrity_cachep, bi); ++ disk->integrity = NULL; + } + EXPORT_SYMBOL(blk_integrity_unregister); +--- a/fs/bio.c ++++ b/fs/bio.c +@@ -1274,6 +1274,42 @@ struct bio_pair *bio_split(struct bio *b + return bp; + } + ++/** ++ * bio_sector_offset - Find hardware sector offset in bio ++ * @bio: bio to inspect ++ * @index: bio_vec index ++ * @offset: offset in bv_page ++ * ++ * Return the number of hardware sectors between beginning of bio ++ * and an end point indicated by a bio_vec index and an offset ++ * within that vector's page. ++ */ ++sector_t bio_sector_offset(struct bio *bio, unsigned short index, ++ unsigned int offset) ++{ ++ unsigned int sector_sz = queue_hardsect_size(bio->bi_bdev->bd_disk->queue); ++ struct bio_vec *bv; ++ sector_t sectors; ++ int i; ++ ++ sectors = 0; ++ ++ if (index >= bio->bi_idx) ++ index = bio->bi_vcnt - 1; ++ ++ __bio_for_each_segment(bv, bio, i, 0) { ++ if (i == index) { ++ if (offset > bv->bv_offset) ++ sectors += (offset - bv->bv_offset) / sector_sz; ++ break; ++ } ++ ++ sectors += bv->bv_len / sector_sz; ++ } ++ ++ return sectors; ++} ++EXPORT_SYMBOL(bio_sector_offset); + + /* + * create memory pools for biovec's in a bio_set. +--- a/fs/bio-integrity.c ++++ b/fs/bio-integrity.c +@@ -107,7 +107,8 @@ void bio_integrity_free(struct bio *bio, + BUG_ON(bip == NULL); + + /* A cloned bio doesn't own the integrity metadata */ +- if (!bio_flagged(bio, BIO_CLONED) && bip->bip_buf != NULL) ++ if (!bio_flagged(bio, BIO_CLONED) && !bio_flagged(bio, BIO_FS_INTEGRITY) ++ && bip->bip_buf != NULL) + kfree(bip->bip_buf); + + mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]); +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -115,6 +115,7 @@ struct bio { + #define BIO_USER_MAPPED 6 /* contains user pages */ + #define BIO_EOPNOTSUPP 7 /* not supported */ + #define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */ ++#define BIO_FS_INTEGRITY 10 /* fs owns integrity data, not block layer */ + #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) + + /* +@@ -331,6 +332,7 @@ extern int bio_add_page(struct bio *, st + extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *, + unsigned int, unsigned int); + extern int bio_get_nr_vecs(struct block_device *); ++extern sector_t bio_sector_offset(struct bio *, unsigned short, unsigned int); + extern struct bio *bio_map_user(struct request_queue *, struct block_device *, + unsigned long, unsigned int, int); + struct sg_iovec; +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -980,7 +980,7 @@ struct blk_integrity { + + extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); + extern void blk_integrity_unregister(struct gendisk *); +-extern int blk_integrity_compare(struct block_device *, struct block_device *); ++extern int blk_integrity_compare(struct gendisk *, struct gendisk *); + extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *); + extern int blk_rq_count_integrity_sg(struct request *); + +@@ -997,6 +997,11 @@ static inline struct blk_integrity *bdev + return bdev->bd_disk->integrity; + } + ++static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk) ++{ ++ return disk->integrity; ++} ++ + static inline unsigned int bdev_get_tag_size(struct block_device *bdev) + { + struct blk_integrity *bi = bdev_get_integrity(bdev); +@@ -1039,6 +1044,7 @@ static inline int blk_integrity_rq(struc + #define blk_rq_count_integrity_sg(a) (0) + #define blk_rq_map_integrity_sg(a, b) (0) + #define bdev_get_integrity(a) (0) ++#define blk_get_integrity(a) (0) + #define bdev_get_tag_size(a) (0) + #define blk_integrity_compare(a, b) (0) + #define blk_integrity_register(a, b) (0) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-optimizations-in-blk_rq_timed_out_timer b/src/patches/suse-2.6.27.31/patches.fixes/block-optimizations-in-blk_rq_timed_out_timer new file mode 100644 index 000000000..325acecc6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-optimizations-in-blk_rq_timed_out_timer @@ -0,0 +1,45 @@ +Subject: block: optimizations in blk_rq_timed_out_timer() +From: malahal@us.ibm.com +Date: Mon Dec 29 08:28:42 2008 +0100: +Git: 565e411d764eeda006738dfadbccca79d48381e1 +References: bnc#464155 + +Now the rq->deadline can't be zero if the request is in the +timeout_list, so there is no need to have next_set. There is no need to +access a request's deadline field if blk_rq_timed_out is called on it. + +Signed-off-by: Malahal Naineni +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-timeout.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -48,7 +48,7 @@ static void blk_rq_timed_out(struct requ + void blk_rq_timed_out_timer(unsigned long data) + { + struct request_queue *q = (struct request_queue *) data; +- unsigned long flags, uninitialized_var(next), next_set = 0; ++ unsigned long flags, next = 0; + struct request *rq, *tmp; + + spin_lock_irqsave(q->queue_lock, flags); +@@ -63,12 +63,10 @@ void blk_rq_timed_out_timer(unsigned lon + if (blk_mark_rq_complete(rq)) + continue; + blk_rq_timed_out(rq); ++ } else { ++ if (!next || time_after(next, rq->deadline)) ++ next = rq->deadline; + } +- if (!next_set) { +- next = rq->deadline; +- next_set = 1; +- } else if (time_after(next, rq->deadline)) +- next = rq->deadline; + } + + if (next_set && !list_empty(&q->timeout_list)) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-rq-affinity b/src/patches/suse-2.6.27.31/patches.fixes/block-rq-affinity new file mode 100644 index 000000000..3e2f8b0c3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-rq-affinity @@ -0,0 +1,568 @@ +From: Jens Axboe +Subject: Implement rq affinity +Patch-Mainline: 2.6.28 + +This is a combined patchset from linux-2.6.git. Commit IDs: +700e1be34289bde0359c15d6507d4cf90e5a5a7d +9f6dd15ebf6591fb2aff8aa774b1b9f4f8d8535d +962b69a665ed7e8aa3d8b9b9b318f9133501f866 + +Signed-off-by: Hannes Reinecke + +--- + block/as-iosched.c | 6 +- + block/blk-core.c | 54 ++++++++++---------- + block/blk-merge.c | 2 + block/blk-settings.c | 2 + block/blk-softirq.c | 126 +++++++++++++++++++++++++++++++++++------------ + block/blk-sysfs.c | 31 +++++++++++ + block/blk.h | 12 ++++ + block/cfq-iosched.c | 2 + fs/bio.c | 1 + include/linux/bio.h | 11 ++++ + include/linux/blkdev.h | 8 ++ + include/linux/elevator.h | 8 +- + 12 files changed, 196 insertions(+), 67 deletions(-) + +--- a/block/as-iosched.c ++++ b/block/as-iosched.c +@@ -462,7 +462,7 @@ static void as_antic_stop(struct as_data + del_timer(&ad->antic_timer); + ad->antic_status = ANTIC_FINISHED; + /* see as_work_handler */ +- kblockd_schedule_work(&ad->antic_work); ++ kblockd_schedule_work(ad->q, &ad->antic_work); + } + } + +@@ -483,7 +483,7 @@ static void as_antic_timeout(unsigned lo + aic = ad->io_context->aic; + + ad->antic_status = ANTIC_FINISHED; +- kblockd_schedule_work(&ad->antic_work); ++ kblockd_schedule_work(q, &ad->antic_work); + + if (aic->ttime_samples == 0) { + /* process anticipated on has exited or timed out*/ +@@ -844,7 +844,7 @@ static void as_completed_request(struct + if (ad->changed_batch && ad->nr_dispatched == 1) { + ad->current_batch_expires = jiffies + + ad->batch_expire[ad->batch_data_dir]; +- kblockd_schedule_work(&ad->antic_work); ++ kblockd_schedule_work(q, &ad->antic_work); + ad->changed_batch = 0; + + if (ad->batch_data_dir == REQ_SYNC) +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -109,7 +109,7 @@ void blk_rq_init(struct request_queue *q + memset(rq, 0, sizeof(*rq)); + + INIT_LIST_HEAD(&rq->queuelist); +- INIT_LIST_HEAD(&rq->donelist); ++ rq->cpu = -1; + rq->q = q; + rq->sector = rq->hard_sector = (sector_t) -1; + INIT_HLIST_NODE(&rq->hash); +@@ -304,7 +304,7 @@ void blk_unplug_timeout(unsigned long da + blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL, + q->rq.count[READ] + q->rq.count[WRITE]); + +- kblockd_schedule_work(&q->unplug_work); ++ kblockd_schedule_work(q, &q->unplug_work); + } + + void blk_unplug(struct request_queue *q) +@@ -321,6 +321,21 @@ void blk_unplug(struct request_queue *q) + } + EXPORT_SYMBOL(blk_unplug); + ++static void blk_invoke_request_fn(struct request_queue *q) ++{ ++ /* ++ * one level of recursion is ok and is much faster than kicking ++ * the unplug handling ++ */ ++ if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { ++ q->request_fn(q); ++ queue_flag_clear(QUEUE_FLAG_REENTER, q); ++ } else { ++ queue_flag_set(QUEUE_FLAG_PLUGGED, q); ++ kblockd_schedule_work(q, &q->unplug_work); ++ } ++} ++ + /** + * blk_start_queue - restart a previously stopped queue + * @q: The &struct request_queue in question +@@ -335,18 +350,7 @@ void blk_start_queue(struct request_queu + WARN_ON(!irqs_disabled()); + + queue_flag_clear(QUEUE_FLAG_STOPPED, q); +- +- /* +- * one level of recursion is ok and is much faster than kicking +- * the unplug handling +- */ +- if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { +- q->request_fn(q); +- queue_flag_clear(QUEUE_FLAG_REENTER, q); +- } else { +- blk_plug_device(q); +- kblockd_schedule_work(&q->unplug_work); +- } ++ blk_invoke_request_fn(q); + } + EXPORT_SYMBOL(blk_start_queue); + +@@ -404,15 +408,8 @@ void __blk_run_queue(struct request_queu + * Only recurse once to avoid overrunning the stack, let the unplug + * handling reinvoke the handler shortly if we already got there. + */ +- if (!elv_queue_empty(q)) { +- if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { +- q->request_fn(q); +- queue_flag_clear(QUEUE_FLAG_REENTER, q); +- } else { +- blk_plug_device(q); +- kblockd_schedule_work(&q->unplug_work); +- } +- } ++ if (!elv_queue_empty(q)) ++ blk_invoke_request_fn(q); + } + EXPORT_SYMBOL(__blk_run_queue); + +@@ -1062,6 +1059,7 @@ EXPORT_SYMBOL(blk_put_request); + + void init_request_from_bio(struct request *req, struct bio *bio) + { ++ req->cpu = bio->bi_comp_cpu; + req->cmd_type = REQ_TYPE_FS; + + /* +@@ -1142,6 +1140,8 @@ static int __make_request(struct request + req->biotail = bio; + req->nr_sectors = req->hard_nr_sectors += nr_sectors; + req->ioprio = ioprio_best(req->ioprio, prio); ++ if (!blk_rq_cpu_valid(req)) ++ req->cpu = bio->bi_comp_cpu; + drive_stat_acct(req, 0); + if (!attempt_back_merge(q, req)) + elv_merged_request(q, req, el_ret); +@@ -1169,6 +1169,8 @@ static int __make_request(struct request + req->sector = req->hard_sector = bio->bi_sector; + req->nr_sectors = req->hard_nr_sectors += nr_sectors; + req->ioprio = ioprio_best(req->ioprio, prio); ++ if (!blk_rq_cpu_valid(req)) ++ req->cpu = bio->bi_comp_cpu; + drive_stat_acct(req, 0); + if (!attempt_front_merge(q, req)) + elv_merged_request(q, req, el_ret); +@@ -1204,13 +1206,15 @@ get_rq: + init_request_from_bio(req, bio); + + spin_lock_irq(q->queue_lock); ++ if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) || ++ bio_flagged(bio, BIO_CPU_AFFINE)) ++ req->cpu = blk_cpu_to_group(smp_processor_id()); + if (elv_queue_empty(q)) + blk_plug_device(q); + add_request(q, req); + out: + if (sync) + __generic_unplug_device(q); +- + spin_unlock_irq(q->queue_lock); + return 0; + +@@ -1958,7 +1962,7 @@ void blk_rq_bio_prep(struct request_queu + rq->rq_disk = bio->bi_bdev->bd_disk; + } + +-int kblockd_schedule_work(struct work_struct *work) ++int kblockd_schedule_work(struct request_queue *q, struct work_struct *work) + { + return queue_work(kblockd_workqueue, work); + } +--- a/block/blk.h ++++ b/block/blk.h +@@ -59,4 +59,16 @@ static inline int queue_congestion_off_t + + #endif /* BLK_DEV_INTEGRITY */ + ++static inline int blk_cpu_to_group(int cpu) ++{ ++#ifdef CONFIG_SCHED_MC ++ cpumask_t mask = cpu_coregroup_map(cpu); ++ return first_cpu(mask); ++#elif defined(CONFIG_SCHED_SMT) ++ return first_cpu(per_cpu(cpu_sibling_map, cpu)); ++#else ++ return cpu; ++#endif ++} ++ + #endif +--- a/block/blk-merge.c ++++ b/block/blk-merge.c +@@ -413,6 +413,8 @@ static int attempt_merge(struct request_ + } + + req->ioprio = ioprio_best(req->ioprio, next->ioprio); ++ if (blk_rq_cpu_valid(next)) ++ req->cpu = next->cpu; + + __blk_put_request(q, next); + return 1; +--- a/block/blk-settings.c ++++ b/block/blk-settings.c +@@ -443,7 +443,7 @@ void blk_queue_update_dma_alignment(stru + } + EXPORT_SYMBOL(blk_queue_update_dma_alignment); + +-static int __init blk_settings_init(void) ++int __init blk_settings_init(void) + { + blk_max_low_pfn = max_low_pfn - 1; + blk_max_pfn = max_pfn - 1; +--- a/block/blk-softirq.c ++++ b/block/blk-softirq.c +@@ -13,6 +13,70 @@ + + static DEFINE_PER_CPU(struct list_head, blk_cpu_done); + ++/* ++ * Softirq action handler - move entries to local list and loop over them ++ * while passing them to the queue registered handler. ++ */ ++static void blk_done_softirq(struct softirq_action *h) ++{ ++ struct list_head *cpu_list, local_list; ++ ++ local_irq_disable(); ++ cpu_list = &__get_cpu_var(blk_cpu_done); ++ list_replace_init(cpu_list, &local_list); ++ local_irq_enable(); ++ ++ while (!list_empty(&local_list)) { ++ struct request *rq; ++ ++ rq = list_entry(local_list.next, struct request, csd.list); ++ list_del_init(&rq->csd.list); ++ rq->q->softirq_done_fn(rq); ++ } ++} ++ ++#if defined(CONFIG_SMP) && defined(CONFIG_USE_GENERIC_SMP_HELPERS) ++static void trigger_softirq(void *data) ++{ ++ struct request *rq = data; ++ unsigned long flags; ++ struct list_head *list; ++ ++ local_irq_save(flags); ++ list = &__get_cpu_var(blk_cpu_done); ++ list_add_tail(&rq->csd.list, list); ++ ++ if (list->next == &rq->csd.list) ++ raise_softirq_irqoff(BLOCK_SOFTIRQ); ++ ++ local_irq_restore(flags); ++} ++ ++/* ++ * Setup and invoke a run of 'trigger_softirq' on the given cpu. ++ */ ++static int raise_blk_irq(int cpu, struct request *rq) ++{ ++ if (cpu_online(cpu)) { ++ struct call_single_data *data = &rq->csd; ++ ++ data->func = trigger_softirq; ++ data->info = rq; ++ data->flags = 0; ++ ++ __smp_call_function_single(cpu, data); ++ return 0; ++ } ++ ++ return 1; ++} ++#else /* CONFIG_SMP && CONFIG_USE_GENERIC_SMP_HELPERS */ ++static int raise_blk_irq(int cpu, struct request *rq) ++{ ++ return 1; ++} ++#endif ++ + static int __cpuinit blk_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) + { +@@ -33,33 +97,10 @@ static int __cpuinit blk_cpu_notify(stru + return NOTIFY_OK; + } + +- +-static struct notifier_block blk_cpu_notifier __cpuinitdata = { ++static struct notifier_block __cpuinitdata blk_cpu_notifier = { + .notifier_call = blk_cpu_notify, + }; + +-/* +- * splice the completion data to a local structure and hand off to +- * process_completion_queue() to complete the requests +- */ +-static void blk_done_softirq(struct softirq_action *h) +-{ +- struct list_head *cpu_list, local_list; +- +- local_irq_disable(); +- cpu_list = &__get_cpu_var(blk_cpu_done); +- list_replace_init(cpu_list, &local_list); +- local_irq_enable(); +- +- while (!list_empty(&local_list)) { +- struct request *rq; +- +- rq = list_entry(local_list.next, struct request, donelist); +- list_del_init(&rq->donelist); +- rq->q->softirq_done_fn(rq); +- } +-} +- + /** + * blk_complete_request - end I/O on a request + * @req: the request being processed +@@ -71,25 +112,48 @@ static void blk_done_softirq(struct soft + * through a softirq handler. The user must have registered a completion + * callback through blk_queue_softirq_done(). + **/ +- + void blk_complete_request(struct request *req) + { +- struct list_head *cpu_list; ++ struct request_queue *q = req->q; + unsigned long flags; ++ int ccpu, cpu, group_cpu; + +- BUG_ON(!req->q->softirq_done_fn); ++ BUG_ON(!q->softirq_done_fn); + + local_irq_save(flags); ++ cpu = smp_processor_id(); ++ group_cpu = blk_cpu_to_group(cpu); + +- cpu_list = &__get_cpu_var(blk_cpu_done); +- list_add_tail(&req->donelist, cpu_list); +- raise_softirq_irqoff(BLOCK_SOFTIRQ); ++ /* ++ * Select completion CPU ++ */ ++ if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) && req->cpu != -1) ++ ccpu = req->cpu; ++ else ++ ccpu = cpu; ++ ++ if (ccpu == cpu || ccpu == group_cpu) { ++ struct list_head *list; ++do_local: ++ list = &__get_cpu_var(blk_cpu_done); ++ list_add_tail(&req->csd.list, list); ++ ++ /* ++ * if the list only contains our just added request, ++ * signal a raise of the softirq. If there are already ++ * entries there, someone already raised the irq but it ++ * hasn't run yet. ++ */ ++ if (list->next == &req->csd.list) ++ raise_softirq_irqoff(BLOCK_SOFTIRQ); ++ } else if (raise_blk_irq(ccpu, req)) ++ goto do_local; + + local_irq_restore(flags); + } + EXPORT_SYMBOL(blk_complete_request); + +-int __init blk_softirq_init(void) ++__init int blk_softirq_init(void) + { + int i; + +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -156,6 +156,30 @@ static ssize_t queue_nomerges_store(stru + return ret; + } + ++static ssize_t queue_rq_affinity_show(struct request_queue *q, char *page) ++{ ++ unsigned int set = test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags); ++ ++ return queue_var_show(set != 0, page); ++} ++ ++static ssize_t ++queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count) ++{ ++ ssize_t ret = -EINVAL; ++#if defined(CONFIG_USE_GENERIC_SMP_HELPERS) ++ unsigned long val; ++ ++ ret = queue_var_store(&val, page, count); ++ spin_lock_irq(q->queue_lock); ++ if (val) ++ queue_flag_set(QUEUE_FLAG_SAME_COMP, q); ++ else ++ queue_flag_clear(QUEUE_FLAG_SAME_COMP, q); ++ spin_unlock_irq(q->queue_lock); ++#endif ++ return ret; ++} + + static struct queue_sysfs_entry queue_requests_entry = { + .attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR }, +@@ -197,6 +221,12 @@ static struct queue_sysfs_entry queue_no + .store = queue_nomerges_store, + }; + ++static struct queue_sysfs_entry queue_rq_affinity_entry = { ++ .attr = {.name = "rq_affinity", .mode = S_IRUGO | S_IWUSR }, ++ .show = queue_rq_affinity_show, ++ .store = queue_rq_affinity_store, ++}; ++ + static struct attribute *default_attrs[] = { + &queue_requests_entry.attr, + &queue_ra_entry.attr, +@@ -205,6 +235,7 @@ static struct attribute *default_attrs[] + &queue_iosched_entry.attr, + &queue_hw_sector_size_entry.attr, + &queue_nomerges_entry.attr, ++ &queue_rq_affinity_entry.attr, + NULL, + }; + +--- a/block/cfq-iosched.c ++++ b/block/cfq-iosched.c +@@ -252,7 +252,7 @@ static inline void cfq_schedule_dispatch + { + if (cfqd->busy_queues) { + cfq_log(cfqd, "schedule dispatch"); +- kblockd_schedule_work(&cfqd->unplug_work); ++ kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work); + } + } + +--- a/fs/bio.c ++++ b/fs/bio.c +@@ -111,6 +111,7 @@ void bio_init(struct bio *bio) + { + memset(bio, 0, sizeof(*bio)); + bio->bi_flags = 1 << BIO_UPTODATE; ++ bio->bi_comp_cpu = -1; + atomic_set(&bio->bi_cnt, 1); + } + +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -88,6 +88,8 @@ struct bio { + + unsigned int bi_max_vecs; /* max bvl_vecs we can hold */ + ++ unsigned int bi_comp_cpu; /* completion CPU */ ++ + struct bio_vec *bi_io_vec; /* the actual vec list */ + + bio_end_io_t *bi_end_io; +@@ -112,6 +114,7 @@ struct bio { + #define BIO_BOUNCED 5 /* bio is a bounce bio */ + #define BIO_USER_MAPPED 6 /* contains user pages */ + #define BIO_EOPNOTSUPP 7 /* not supported */ ++#define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */ + #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) + + /* +@@ -350,6 +353,14 @@ extern struct bio_vec *bvec_alloc_bs(gfp + extern unsigned int bvec_nr_vecs(unsigned short idx); + + /* ++ * Allow queuer to specify a completion CPU for this bio ++ */ ++static inline void bio_set_completion_cpu(struct bio *bio, unsigned int cpu) ++{ ++ bio->bi_comp_cpu = cpu; ++} ++ ++/* + * bio_set is used to allow other portions of the IO system to + * allocate their own private memory pools for bio and iovec structures. + * These memory pools in turn all allocate from the bio_slab +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + +@@ -139,7 +140,8 @@ enum rq_flag_bits { + */ + struct request { + struct list_head queuelist; +- struct list_head donelist; ++ struct call_single_data csd; ++ int cpu; + + struct request_queue *q; + +@@ -420,6 +422,7 @@ struct request_queue + #define QUEUE_FLAG_ELVSWITCH 8 /* don't use elevator, just do FIFO */ + #define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */ + #define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */ ++#define QUEUE_FLAG_SAME_COMP 11 /* force complete on same CPU */ + + static inline int queue_is_locked(struct request_queue *q) + { +@@ -542,6 +545,7 @@ enum { + #define blk_pm_request(rq) \ + (blk_pm_suspend_request(rq) || blk_pm_resume_request(rq)) + ++#define blk_rq_cpu_valid(rq) ((rq)->cpu != -1) + #define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED) + #define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER) + #define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA) +@@ -913,7 +917,7 @@ static inline void put_dev_sector(Sector + } + + struct work_struct; +-int kblockd_schedule_work(struct work_struct *work); ++int kblockd_schedule_work(struct request_queue *q, struct work_struct *work); + void kblockd_flush_work(struct work_struct *work); + + #define MODULE_ALIAS_BLOCKDEV(major,minor) \ +--- a/include/linux/elevator.h ++++ b/include/linux/elevator.h +@@ -173,15 +173,15 @@ enum { + #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) + + /* +- * Hack to reuse the donelist list_head as the fifo time holder while ++ * Hack to reuse the csd.list list_head as the fifo time holder while + * the request is in the io scheduler. Saves an unsigned long in rq. + */ +-#define rq_fifo_time(rq) ((unsigned long) (rq)->donelist.next) +-#define rq_set_fifo_time(rq,exp) ((rq)->donelist.next = (void *) (exp)) ++#define rq_fifo_time(rq) ((unsigned long) (rq)->csd.list.next) ++#define rq_set_fifo_time(rq,exp) ((rq)->csd.list.next = (void *) (exp)) + #define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) + #define rq_fifo_clear(rq) do { \ + list_del_init(&(rq)->queuelist); \ +- INIT_LIST_HEAD(&(rq)->donelist); \ ++ INIT_LIST_HEAD(&(rq)->csd.list); \ + } while (0) + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-sanitize-invalid-partition-table-entries b/src/patches/suse-2.6.27.31/patches.fixes/block-sanitize-invalid-partition-table-entries new file mode 100644 index 000000000..d2711a087 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-sanitize-invalid-partition-table-entries @@ -0,0 +1,92 @@ +From: Kay Sievers +Date: Thu, 16 Oct 2008 05:04:21 +0000 (-0700) +Subject: block: sanitize invalid partition table entries +Git-commit: ac0d86f5809598ddcd6bfa0ea8245ccc910e9eac +Patch-mainline: 2.6.28 +References: bnc#371657 + +block: sanitize invalid partition table entries + +We currently follow blindly what the partition table lies about the +disk, and let the kernel create block devices which can not be accessed. +Trying to identify the device leads to kernel logs full of: + sdb: rw=0, want=73392, limit=28800 + attempt to access beyond end of device + +Here is an example of a broken partition table, where sda2 starts +behind the end of the disk, and sdb3 is larger than the entire disk: + Disk /dev/sdb: 14 MB, 14745600 bytes + 1 heads, 29 sectors/track, 993 cylinders, total 28800 sectors + Device Boot Start End Blocks Id System + /dev/sdb1 29 7800 3886 83 Linux + /dev/sdb2 37801 45601 3900+ 83 Linux + /dev/sdb3 15602 73402 28900+ 83 Linux + /dev/sdb4 23403 28796 2697 83 Linux + +The kernel creates these completely invalid devices, which can not be +accessed, or may lead to other unpredictable failures: + grep . /sys/class/block/sdb*/{start,size} + /sys/class/block/sdb/size:28800 + /sys/class/block/sdb1/start:29 + /sys/class/block/sdb1/size:7772 + /sys/class/block/sdb2/start:37801 + /sys/class/block/sdb2/size:7801 + /sys/class/block/sdb3/start:15602 + /sys/class/block/sdb3/size:57801 + /sys/class/block/sdb4/start:23403 + /sys/class/block/sdb4/size:5394 + +With this patch, we ignore partitions which start behind the end of the disk, +and limit partitions to the end of the disk if they pretend to be larger: + grep . /sys/class/block/sdb*/{start,size} + /sys/class/block/sdb/size:28800 + /sys/class/block/sdb1/start:29 + /sys/class/block/sdb1/size:7772 + /sys/class/block/sdb3/start:15602 + /sys/class/block/sdb3/size:13198 + /sys/class/block/sdb4/start:23403 + /sys/class/block/sdb4/size:5394 + +These warnings are printed to the kernel log: + sdb: p2 ignored, start 37801 is behind the end of the disk + sdb: p3 size 57801 limited to end of disk + +Signed-off-by: Kay Sievers +Cc: Herton Ronaldo Krzesinski +Cc: Jens Axboe +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Acked-by: Jeff Mahoney +--- + + fs/partitions/check.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +--- a/fs/partitions/check.c ++++ b/fs/partitions/check.c +@@ -498,10 +498,23 @@ int rescan_partitions(struct gendisk *di + sector_t from = state->parts[p].from; + if (!size) + continue; ++ if (from >= get_capacity(disk)) { ++ printk(KERN_WARNING ++ "%s: p%d ignored, start %llu is behind the end of the disk\n", ++ disk->disk_name, p, (unsigned long long) from); ++ continue; ++ } + if (from + size > get_capacity(disk)) { ++ /* ++ * we can not ignore partitions of broken tables ++ * created by for example camera firmware, but we ++ * limit them to the end of the disk to avoid ++ * creating invalid block devices ++ */ + printk(KERN_WARNING +- "%s: p%d exceeds device capacity\n", +- disk->disk_name, p); ++ "%s: p%d size %llu limited to end of disk\n", ++ disk->disk_name, p, (unsigned long long) size); ++ size = get_capacity(disk) - from; + } + res = add_partition(disk, p, from, size, state->parts[p].flags); + if (res) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-suppress-buffer-IO-errors b/src/patches/suse-2.6.27.31/patches.fixes/block-suppress-buffer-IO-errors new file mode 100644 index 000000000..2c9ca3934 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-suppress-buffer-IO-errors @@ -0,0 +1,148 @@ +Subject: block: Supress Buffer I/O errors when SCSI REQ_QUIET flag set +From: Keith Mannthey +Date: Mon Dec 29 08:28:44 2008 +0100: +Git: 08bafc0341f2f7920e9045bc32c40299cac8c21b +References: bnc#464155 + +Allow the scsi request REQ_QUIET flag to be propagated to the buffer +file system layer. The basic ideas is to pass the flag from the scsi +request to the bio (block IO) and then to the buffer layer. The buffer +layer can then suppress needless printks. + +This patch declutters the kernel log by removed the 40-50 (per lun) +buffer io error messages seen during a boot in my multipath setup . It +is a good chance any real errors will be missed in the "noise" it the +logs without this patch. + +During boot I see blocks of messages like +" +__ratelimit: 211 callbacks suppressed +Buffer I/O error on device sdm, logical block 5242879 +Buffer I/O error on device sdm, logical block 5242879 +Buffer I/O error on device sdm, logical block 5242847 +Buffer I/O error on device sdm, logical block 1 +Buffer I/O error on device sdm, logical block 5242878 +Buffer I/O error on device sdm, logical block 5242879 +Buffer I/O error on device sdm, logical block 5242879 +Buffer I/O error on device sdm, logical block 5242879 +Buffer I/O error on device sdm, logical block 5242879 +Buffer I/O error on device sdm, logical block 5242872 +" +in my logs. + +My disk environment is multipath fiber channel using the SCSI_DH_RDAC +code and multipathd. This topology includes an "active" and "ghost" +path for each lun. IO's to the "ghost" path will never complete and the +SCSI layer, via the scsi device handler rdac code, quick returns the IOs +to theses paths and sets the REQ_QUIET scsi flag to suppress the scsi +layer messages. + + I am wanting to extend the QUIET behavior to include the buffer file +system layer to deal with these errors as well. I have been running this +patch for a while now on several boxes without issue. A few runs of +bonnie++ show no noticeable difference in performance in my setup. + +Thanks for John Stultz for the quiet_error finalization. + +Submitted-by: Keith Mannthey +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 3 +++ + fs/buffer.c | 19 +++++++++++++++---- + include/linux/bio.h | 1 + + include/linux/buffer_head.h | 1 + + 4 files changed, 20 insertions(+), 4 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -138,6 +138,9 @@ static void req_bio_endio(struct request + nbytes = bio->bi_size; + } + ++ if (unlikely(rq->cmd_flags & REQ_QUIET)) ++ set_bit(BIO_QUIET, &bio->bi_flags); ++ + bio->bi_size -= nbytes; + bio->bi_sector += (nbytes >> 9); + +--- a/fs/buffer.c ++++ b/fs/buffer.c +@@ -100,10 +100,18 @@ __clear_page_buffers(struct page *page) + page_cache_release(page); + } + ++ ++static int quiet_error(struct buffer_head *bh) ++{ ++ if (!test_bit(BH_Quiet, &bh->b_state) && printk_ratelimit()) ++ return 0; ++ return 1; ++} ++ ++ + static void buffer_io_error(struct buffer_head *bh) + { + char b[BDEVNAME_SIZE]; +- + printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n", + bdevname(bh->b_bdev, b), + (unsigned long long)bh->b_blocknr); +@@ -145,7 +153,7 @@ void end_buffer_write_sync(struct buffer + if (uptodate) { + set_buffer_uptodate(bh); + } else { +- if (!buffer_eopnotsupp(bh) && printk_ratelimit()) { ++ if (!buffer_eopnotsupp(bh) && !quiet_error(bh)) { + buffer_io_error(bh); + printk(KERN_WARNING "lost page write due to " + "I/O error on %s\n", +@@ -395,7 +403,7 @@ static void end_buffer_async_read(struct + set_buffer_uptodate(bh); + } else { + clear_buffer_uptodate(bh); +- if (printk_ratelimit()) ++ if (!quiet_error(bh)) + buffer_io_error(bh); + SetPageError(page); + } +@@ -456,7 +464,7 @@ static void end_buffer_async_write(struc + if (uptodate) { + set_buffer_uptodate(bh); + } else { +- if (printk_ratelimit()) { ++ if (!quiet_error(bh)) { + buffer_io_error(bh); + printk(KERN_WARNING "lost page write due to " + "I/O error on %s\n", +@@ -2958,6 +2966,9 @@ static void end_bio_bh_io_sync(struct bi + set_bit(BH_Eopnotsupp, &bh->b_state); + } + ++ if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags))) ++ set_bit(BH_Quiet, &bh->b_state); ++ + bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); + bio_put(bio); + } +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -116,6 +116,7 @@ struct bio { + #define BIO_EOPNOTSUPP 7 /* not supported */ + #define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */ + #define BIO_FS_INTEGRITY 10 /* fs owns integrity data, not block layer */ ++#define BIO_QUIET 11 /* Make BIO Quiet */ + #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) + + /* +--- a/include/linux/buffer_head.h ++++ b/include/linux/buffer_head.h +@@ -35,6 +35,7 @@ enum bh_state_bits { + BH_Ordered, /* ordered write */ + BH_Eopnotsupp, /* operation not supported (barrier) */ + BH_Unwritten, /* Buffer is allocated on disk but not written */ ++ BH_Quiet, /* Buffer Error Prinks to be quiet */ + + BH_PrivateStart,/* not a state bit, but the first bit available + * for private allocation by other entities diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-use-bio_has_data b/src/patches/suse-2.6.27.31/patches.fixes/block-use-bio_has_data new file mode 100644 index 000000000..d11dd5020 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-use-bio_has_data @@ -0,0 +1,131 @@ +From 0f96bb8e2923065d58d89c5c82c9f37ad1f18404 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Thu, 23 Oct 2008 13:42:06 +0200 +Subject: [PATCH] Implement bio_has_data() + +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke +--- + block/blk-core.c | 21 +++++++-------------- + include/linux/bio.h | 14 +++++++++++--- + include/linux/blkdev.h | 2 +- + mm/bounce.c | 2 +- + 4 files changed, 20 insertions(+), 19 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -624,10 +624,6 @@ blk_alloc_request(struct request_queue * + + blk_rq_init(q, rq); + +- /* +- * first three bits are identical in rq->cmd_flags and bio->bi_rw, +- * see bio.h and blkdev.h +- */ + rq->cmd_flags = rw | REQ_ALLOCED; + + if (priv) { +@@ -1490,10 +1486,7 @@ void submit_bio(int rw, struct bio *bio) + * If it's a regular read/write or a barrier with data attached, + * go through the normal accounting stuff before submission. + */ +- if (!bio_empty_barrier(bio)) { +- +- BIO_BUG_ON(!bio->bi_size); +- BIO_BUG_ON(!bio->bi_io_vec); ++ if (bio_has_data(bio)) { + + if (rw & WRITE) { + count_vm_events(PGPGOUT, count); +@@ -1888,7 +1881,7 @@ static int blk_end_io(struct request *rq + struct request_queue *q = rq->q; + unsigned long flags = 0UL; + +- if (blk_fs_request(rq) || blk_pc_request(rq)) { ++ if (bio_has_data(rq->bio)) { + if (__end_that_request_first(rq, error, nr_bytes)) + return 1; + +@@ -1946,10 +1939,9 @@ EXPORT_SYMBOL_GPL(blk_end_request); + **/ + int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) + { +- if (blk_fs_request(rq) || blk_pc_request(rq)) { +- if (__end_that_request_first(rq, error, nr_bytes)) +- return 1; +- } ++ if (bio_has_data(rq->bio) && ++ __end_that_request_first(rq, error, nr_bytes)) ++ return 1; + + add_disk_randomness(rq->rq_disk); + +@@ -2016,7 +2008,8 @@ EXPORT_SYMBOL_GPL(blk_end_request_callba + void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio) + { +- /* first two bits are identical in rq->cmd_flags and bio->bi_rw */ ++ /* Bit 0 (R/W) is identical in rq->cmd_flags and bio->bi_rw, and ++ we want BIO_RW_AHEAD (bit 1) to imply REQ_FAILFAST (bit 1). */ + rq->cmd_flags |= (bio->bi_rw & 3); + + rq->nr_phys_segments = bio_phys_segments(q, bio); +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -157,8 +157,8 @@ struct bio { + * bit 3 -- fail fast, don't want low level driver retries + * bit 4 -- synchronous I/O hint: the block layer will unplug immediately + */ +-#define BIO_RW 0 +-#define BIO_RW_AHEAD 1 ++#define BIO_RW 0 /* Must match RW in req flags (blkdev.h) */ ++#define BIO_RW_AHEAD 1 /* Must match FAILFAST in req flags */ + #define BIO_RW_BARRIER 2 + #define BIO_RW_FAILFAST 3 + #define BIO_RW_SYNC 4 +@@ -192,7 +192,7 @@ struct bio { + #define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) + #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) + #define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) +-#define bio_empty_barrier(bio) (bio_barrier(bio) && !(bio)->bi_size) ++#define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio)) + + static inline unsigned int bio_cur_sectors(struct bio *bio) + { +@@ -452,6 +452,14 @@ static inline char *__bio_kmap_irq(struc + __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) + #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) + ++/* ++ * Check whether this bio carries any data or not. A NULL bio is allowed. ++ */ ++static inline int bio_has_data(struct bio *bio) ++{ ++ return bio && bio->bi_io_vec != NULL; ++} ++ + #if defined(CONFIG_BLK_DEV_INTEGRITY) + + #define bip_vec_idx(bip, idx) (&(bip->bip_vec[(idx)])) +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -84,7 +84,7 @@ enum { + }; + + /* +- * request type modified bits. first three bits match BIO_RW* bits, important ++ * request type modified bits. first two bits match BIO_RW* bits, important + */ + enum rq_flag_bits { + __REQ_RW, /* not set, read. set, write */ +--- a/mm/bounce.c ++++ b/mm/bounce.c +@@ -267,7 +267,7 @@ void blk_queue_bounce(struct request_que + /* + * Data-less bio, nothing to bounce + */ +- if (bio_empty_barrier(*bio_orig)) ++ if (!bio_has_data(*bio_orig)) + return; + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/block-use-round_jiffies_up b/src/patches/suse-2.6.27.31/patches.fixes/block-use-round_jiffies_up new file mode 100644 index 000000000..6d3b0b1b8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/block-use-round_jiffies_up @@ -0,0 +1,68 @@ +Subject: Block: use round_jiffies_up() +From: Alan Stern +Date: Thu Nov 6 08:42:49 2008 +0100: +Git: 7838c15b8dd18e78a523513749e5b54bda07b0cb +References: bnc#464155 + +This patch (as1159b) changes the timeout routines in the block core to +use round_jiffies_up(). There's no point in rounding the timer +deadline down, since if it expires too early we will have to restart +it. + +The patch also removes some unnecessary tests when a request is +removed from the queue's timer list. + +Signed-off-by: Alan Stern +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +--- + block/blk-timeout.c | 20 +++----------------- + 1 file changed, 3 insertions(+), 17 deletions(-) + +--- a/block/blk-timeout.c ++++ b/block/blk-timeout.c +@@ -16,14 +16,7 @@ void blk_delete_timer(struct request *re + { + struct request_queue *q = req->q; + +- /* +- * Nothing to detach +- */ +- if (!q->rq_timed_out_fn || !req->deadline) +- return; +- + list_del_init(&req->timeout_list); +- + if (list_empty(&q->timeout_list)) + del_timer(&q->timeout); + } +@@ -83,7 +76,7 @@ void blk_rq_timed_out_timer(unsigned lon + } + + if (next_set && !list_empty(&q->timeout_list)) +- mod_timer(&q->timeout, round_jiffies(next)); ++ mod_timer(&q->timeout, round_jiffies_up(next)); + + spin_unlock_irqrestore(q->queue_lock, flags); + } +@@ -139,17 +132,10 @@ void blk_add_timer(struct request *req) + + /* + * If the timer isn't already pending or this timeout is earlier +- * than an existing one, modify the timer. Round to next nearest ++ * than an existing one, modify the timer. Round up to next nearest + * second. + */ +- expiry = round_jiffies(req->deadline); +- +- /* +- * We use ->deadline == 0 to detect whether a timer was added or +- * not, so just increase to next jiffy for that specific case +- */ +- if (unlikely(!req->deadline)) +- req->deadline = 1; ++ expiry = round_jiffies_up(req->deadline); + + if (!timer_pending(&q->timeout) || + time_before(expiry, q->timeout.expires)) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bnx2x-block-nvram-access-when-device-is-inactive b/src/patches/suse-2.6.27.31/patches.fixes/bnx2x-block-nvram-access-when-device-is-inactive new file mode 100644 index 000000000..920c93e84 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bnx2x-block-nvram-access-when-device-is-inactive @@ -0,0 +1,35 @@ +From: Eilon Greenstein +Date: Wed, 14 Jan 2009 06:44:07 +0000 (+0000) +Subject: bnx2x: Block nvram access when the device is inactive +Patch-mainline: 2.6.29-rc3 +Git-commit: 2add3acb11a26cc14b54669433ae6ace6406cbf2 +References: bnc#470898 + +bnx2x: Block nvram access when the device is inactive + +Don't dump eeprom when bnx2x adapter is down. Running ethtool -e causes an eeh +without it when the device is down + +Signed-off-by: Paul Larson +Signed-off-by: Eilon Greenstein +Signed-off-by: David S. Miller +Acked-by: Jeff Mahoney +--- + + drivers/net/bnx2x_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +=================================================================== +--- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c ++++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c +@@ -8280,6 +8280,9 @@ static int bnx2x_set_eeprom(struct net_d + struct bnx2x *bp = netdev_priv(dev); + int rc; + ++ if (!netif_running(dev)) ++ return -EAGAIN; ++ + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bridge-module-get-put.patch b/src/patches/suse-2.6.27.31/patches.fixes/bridge-module-get-put.patch new file mode 100644 index 000000000..82f0fe416 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bridge-module-get-put.patch @@ -0,0 +1,45 @@ +From: jbeulich@novell.com +Subject: Module use count must be updated as bridges are created/destroyed +Patch-mainline: unknown +References: 267651 + +Otherwise 'modprobe -r' on a module having a dependency on bridge will +implicitly unload bridge, bringing down all connectivity that was using +bridges. + +--- + net/bridge/br_if.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -271,6 +271,11 @@ int br_add_bridge(const char *name) + if (!dev) + return -ENOMEM; + ++ if (!try_module_get(THIS_MODULE)) { ++ free_netdev(dev); ++ return -ENOENT; ++ } ++ + rtnl_lock(); + if (strchr(dev->name, '%')) { + ret = dev_alloc_name(dev, dev->name); +@@ -287,6 +292,8 @@ int br_add_bridge(const char *name) + unregister_netdevice(dev); + out: + rtnl_unlock(); ++ if (ret) ++ module_put(THIS_MODULE); + return ret; + + out_free: +@@ -318,6 +325,8 @@ int br_del_bridge(const char *name) + del_br(netdev_priv(dev)); + + rtnl_unlock(); ++ if (ret == 0) ++ module_put(THIS_MODULE); + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_1_sched_clock_lock.patch b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_1_sched_clock_lock.patch new file mode 100644 index 000000000..f96bbdb00 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_1_sched_clock_lock.patch @@ -0,0 +1,35 @@ +Subject: sched: only update rq->clock while holding rq->lock +From: Peter Zijlstra +References: 437171 - LTC47404 + +Vatsa noticed rq->clock going funny and tracked it down to an update_rq_clock() +outside a rq->lock section. + +This is a problem because things like double_rq_lock() update the rq->clock +value for both rqs. Therefore disabling interrupts isn't strong enough. + +Reported-by: Srivatsa Vaddagiri +Signed-off-by: Peter Zijlstra +Signed-off-by: Ingo Molnar +Signed-off-by: Olaf Hering + +--- + kernel/sched.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -4449,12 +4449,9 @@ need_resched_nonpreemptible: + if (sched_feat(HRTICK)) + hrtick_clear(rq); + +- /* +- * Do the rq-clock update outside the rq lock: +- */ + local_irq_disable(); +- update_rq_clock(rq); + spin_lock(&rq->lock); ++ update_rq_clock(rq); + clear_tsk_need_resched(prev); + + if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_2_sched_delta_weight.patch b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_2_sched_delta_weight.patch new file mode 100644 index 000000000..74b546f52 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_2_sched_delta_weight.patch @@ -0,0 +1,109 @@ +Subject: sched: revert back to per-rq vruntime +From: Peter Zijlstra +References: 437171 - LTC47404 + +Vatsa rightly points out that having the runqueue weight in the vruntime +calculations can cause unfairness in the face of task joins/leaves. + +Suppose: dv = dt * rw / w + +Then take 10 tasks t_n, each of similar weight. If the first will run 1 +then its vruntime will increase by 10. Now, if the next 8 tasks leave after +having run their 1, then the last task will get a vruntime increase of 2 +after having run 1. + +Which will leave us with 2 tasks of equal weight and equal runtime, of which +one will not be scheduled for 8/2=4 units of time. + +Ergo, we cannot do that and must use: dv = dt / w. + +This means we cannot have a global vruntime based on effective priority, but +must instead go back to the vruntime per rq model we started out with. + +This patch was lightly tested by doing starting while loops on each nice level +and observing their execution time, and a simple group scenario of 1:2:3 pinned +to a single cpu. + +Reported-by: Srivatsa Vaddagiri +Signed-off-by: Peter Zijlstra +Signed-off-by: Olaf Hering +--- + kernel/sched_fair.c | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -334,7 +334,7 @@ int sched_nr_latency_handler(struct ctl_ + #endif + + /* +- * delta *= w / rw ++ * delta *= P[w / rw] + */ + static inline unsigned long + calc_delta_weight(unsigned long delta, struct sched_entity *se) +@@ -348,15 +348,13 @@ calc_delta_weight(unsigned long delta, s + } + + /* +- * delta *= rw / w ++ * delta /= w + */ + static inline unsigned long + calc_delta_fair(unsigned long delta, struct sched_entity *se) + { +- for_each_sched_entity(se) { +- delta = calc_delta_mine(delta, +- cfs_rq_of(se)->load.weight, &se->load); +- } ++ if (unlikely(se->load.weight != NICE_0_LOAD)) ++ delta = calc_delta_mine(delta, NICE_0_LOAD, &se->load); + + return delta; + } +@@ -386,26 +384,26 @@ static u64 __sched_period(unsigned long + * We calculate the wall-time slice from the period by taking a part + * proportional to the weight. + * +- * s = p*w/rw ++ * s = p*P[w/rw] + */ + static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) + { +- return calc_delta_weight(__sched_period(cfs_rq->nr_running), se); ++ unsigned long nr_running = cfs_rq->nr_running; ++ ++ if (unlikely(!se->on_rq)) ++ nr_running++; ++ ++ return calc_delta_weight(__sched_period(nr_running), se); + } + + /* + * We calculate the vruntime slice of a to be inserted task + * +- * vs = s*rw/w = p ++ * vs = s/w + */ +-static u64 sched_vslice_add(struct cfs_rq *cfs_rq, struct sched_entity *se) ++static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se) + { +- unsigned long nr_running = cfs_rq->nr_running; +- +- if (!se->on_rq) +- nr_running++; +- +- return __sched_period(nr_running); ++ return calc_delta_fair(sched_slice(cfs_rq, se), se); + } + + /* +@@ -683,7 +681,7 @@ place_entity(struct cfs_rq *cfs_rq, stru + * stays open at the end. + */ + if (initial && sched_feat(START_DEBIT)) +- vruntime += sched_vslice_add(cfs_rq, se); ++ vruntime += sched_vslice(cfs_rq, se); + + if (!initial) { + /* sleeps upto a single latency don't count. */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_3_rework_wakeup_preemption.patch b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_3_rework_wakeup_preemption.patch new file mode 100644 index 000000000..1c1a609b8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_3_rework_wakeup_preemption.patch @@ -0,0 +1,184 @@ +Subject: sched: rework wakeup preemption +From: Peter Zijlstra +References: 437171 - LTC47404 + + + Rework the wakeup preemption to work on real runtime instead of + the virtual runtime. This greatly simplifies the code. + + Signed-off-by: Peter Zijlstra + Signed-off-by: Ingo Molnar + +Signed-off-by: Olaf Hering +--- + kernel/sched_fair.c | 133 +--------------------------------------------------- + 1 file changed, 4 insertions(+), 129 deletions(-) + +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -407,64 +407,6 @@ static u64 sched_vslice(struct cfs_rq *c + } + + /* +- * The goal of calc_delta_asym() is to be asymmetrically around NICE_0_LOAD, in +- * that it favours >=0 over <0. +- * +- * -20 | +- * | +- * 0 --------+------- +- * .' +- * 19 .' +- * +- */ +-static unsigned long +-calc_delta_asym(unsigned long delta, struct sched_entity *se) +-{ +- struct load_weight lw = { +- .weight = NICE_0_LOAD, +- .inv_weight = 1UL << (WMULT_SHIFT-NICE_0_SHIFT) +- }; +- +- for_each_sched_entity(se) { +- struct load_weight *se_lw = &se->load; +- unsigned long rw = cfs_rq_of(se)->load.weight; +- +-#ifdef CONFIG_FAIR_SCHED_GROUP +- struct cfs_rq *cfs_rq = se->my_q; +- struct task_group *tg = NULL +- +- if (cfs_rq) +- tg = cfs_rq->tg; +- +- if (tg && tg->shares < NICE_0_LOAD) { +- /* +- * scale shares to what it would have been had +- * tg->weight been NICE_0_LOAD: +- * +- * weight = 1024 * shares / tg->weight +- */ +- lw.weight *= se->load.weight; +- lw.weight /= tg->shares; +- +- lw.inv_weight = 0; +- +- se_lw = &lw; +- rw += lw.weight - se->load.weight; +- } else +-#endif +- +- if (se->load.weight < NICE_0_LOAD) { +- se_lw = &lw; +- rw += NICE_0_LOAD - se->load.weight; +- } +- +- delta = calc_delta_mine(delta, rw, se_lw); +- } +- +- return delta; +-} +- +-/* + * Update the current task's runtime statistics. Skip current tasks that + * are not in our scheduling class. + */ +@@ -1279,54 +1221,12 @@ static unsigned long wakeup_gran(struct + * + nice tasks. + */ + if (sched_feat(ASYM_GRAN)) +- gran = calc_delta_asym(sysctl_sched_wakeup_granularity, se); +- else +- gran = calc_delta_fair(sysctl_sched_wakeup_granularity, se); ++ gran = calc_delta_mine(gran, NICE_0_LOAD, &se->load); + + return gran; + } + + /* +- * Should 'se' preempt 'curr'. +- * +- * |s1 +- * |s2 +- * |s3 +- * g +- * |<--->|c +- * +- * w(c, s1) = -1 +- * w(c, s2) = 0 +- * w(c, s3) = 1 +- * +- */ +-static int +-wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se) +-{ +- s64 gran, vdiff = curr->vruntime - se->vruntime; +- +- if (vdiff < 0) +- return -1; +- +- gran = wakeup_gran(curr); +- if (vdiff > gran) +- return 1; +- +- return 0; +-} +- +-/* return depth at which a sched entity is present in the hierarchy */ +-static inline int depth_se(struct sched_entity *se) +-{ +- int depth = 0; +- +- for_each_sched_entity(se) +- depth++; +- +- return depth; +-} +- +-/* + * Preempt the current task with a newly woken task if needed: + */ + static void check_preempt_wakeup(struct rq *rq, struct task_struct *p) +@@ -1334,7 +1234,7 @@ static void check_preempt_wakeup(struct + struct task_struct *curr = rq->curr; + struct cfs_rq *cfs_rq = task_cfs_rq(curr); + struct sched_entity *se = &curr->se, *pse = &p->se; +- int se_depth, pse_depth; ++ s64 delta_exec; + + if (unlikely(rt_prio(p->prio))) { + update_rq_clock(rq); +@@ -1358,33 +1258,8 @@ static void check_preempt_wakeup(struct + if (!sched_feat(WAKEUP_PREEMPT)) + return; + +- /* +- * preemption test can be made between sibling entities who are in the +- * same cfs_rq i.e who have a common parent. Walk up the hierarchy of +- * both tasks until we find their ancestors who are siblings of common +- * parent. +- */ +- +- /* First walk up until both entities are at same depth */ +- se_depth = depth_se(se); +- pse_depth = depth_se(pse); +- +- while (se_depth > pse_depth) { +- se_depth--; +- se = parent_entity(se); +- } +- +- while (pse_depth > se_depth) { +- pse_depth--; +- pse = parent_entity(pse); +- } +- +- while (!is_same_group(se, pse)) { +- se = parent_entity(se); +- pse = parent_entity(pse); +- } +- +- if (wakeup_preempt_entity(se, pse) == 1) ++ delta_exec = se->sum_exec_runtime - se->prev_sum_exec_runtime; ++ if (delta_exec > wakeup_gran(pse)) + resched_task(curr); + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_4_sched_reinstate_vruntime_wakeup.patch b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_4_sched_reinstate_vruntime_wakeup.patch new file mode 100644 index 000000000..36081c7ee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bug-437171_4_sched_reinstate_vruntime_wakeup.patch @@ -0,0 +1,155 @@ +Subject: sched: re-instate vruntime based wakeup preemption +From: Peter Zijlstra +References: 437171 - LTC47404 + +The advantage is that vruntime based wakeup preemption has a better +conceptual model. Here wakeup_gran = 0 means: preempt when 'fair'. +Therefore wakeup_gran is the granularity of unfairness we allow in order +to make progress. + +Signed-off-by: Peter Zijlstra +Signed-off-by: Olaf Hering +--- + kernel/sched_fair.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 92 insertions(+), 6 deletions(-) + +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -141,6 +141,49 @@ static inline struct sched_entity *paren + return se->parent; + } + ++/* return depth at which a sched entity is present in the hierarchy */ ++static inline int depth_se(struct sched_entity *se) ++{ ++ int depth = 0; ++ ++ for_each_sched_entity(se) ++ depth++; ++ ++ return depth; ++} ++ ++static void ++find_matching_se(struct sched_entity **se, struct sched_entity **pse) ++{ ++ int se_depth, pse_depth; ++ ++ /* ++ * preemption test can be made between sibling entities who are in the ++ * same cfs_rq i.e who have a common parent. Walk up the hierarchy of ++ * both tasks until we find their ancestors who are siblings of common ++ * parent. ++ */ ++ ++ /* First walk up until both entities are at same depth */ ++ se_depth = depth_se(*se); ++ pse_depth = depth_se(*pse); ++ ++ while (se_depth > pse_depth) { ++ se_depth--; ++ *se = parent_entity(*se); ++ } ++ ++ while (pse_depth > se_depth) { ++ pse_depth--; ++ *pse = parent_entity(*pse); ++ } ++ ++ while (!is_same_group(*se, *pse)) { ++ *se = parent_entity(*se); ++ *pse = parent_entity(*pse); ++ } ++} ++ + #else /* CONFIG_FAIR_GROUP_SCHED */ + + static inline struct rq *rq_of(struct cfs_rq *cfs_rq) +@@ -191,6 +234,11 @@ static inline struct sched_entity *paren + return NULL; + } + ++static inline void ++find_matching_se(struct sched_entity **se, struct sched_entity **pse) ++{ ++} ++ + #endif /* CONFIG_FAIR_GROUP_SCHED */ + + +@@ -1220,13 +1268,42 @@ static unsigned long wakeup_gran(struct + * More easily preempt - nice tasks, while not making it harder for + * + nice tasks. + */ +- if (sched_feat(ASYM_GRAN)) +- gran = calc_delta_mine(gran, NICE_0_LOAD, &se->load); ++ if (!sched_feat(ASYM_GRAN) || se->load.weight > NICE_0_LOAD) ++ gran = calc_delta_fair(sysctl_sched_wakeup_granularity, se); + + return gran; + } + + /* ++ * Should 'se' preempt 'curr'. ++ * ++ * |s1 ++ * |s2 ++ * |s3 ++ * g ++ * |<--->|c ++ * ++ * w(c, s1) = -1 ++ * w(c, s2) = 0 ++ * w(c, s3) = 1 ++ * ++ */ ++static int ++wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se) ++{ ++ s64 gran, vdiff = curr->vruntime - se->vruntime; ++ ++ if (vdiff <= 0) ++ return -1; ++ ++ gran = wakeup_gran(curr); ++ if (vdiff > gran) ++ return 1; ++ ++ return 0; ++} ++ ++/* + * Preempt the current task with a newly woken task if needed: + */ + static void check_preempt_wakeup(struct rq *rq, struct task_struct *p) +@@ -1234,7 +1311,6 @@ static void check_preempt_wakeup(struct + struct task_struct *curr = rq->curr; + struct cfs_rq *cfs_rq = task_cfs_rq(curr); + struct sched_entity *se = &curr->se, *pse = &p->se; +- s64 delta_exec; + + if (unlikely(rt_prio(p->prio))) { + update_rq_clock(rq); +@@ -1258,9 +1334,19 @@ static void check_preempt_wakeup(struct + if (!sched_feat(WAKEUP_PREEMPT)) + return; + +- delta_exec = se->sum_exec_runtime - se->prev_sum_exec_runtime; +- if (delta_exec > wakeup_gran(pse)) +- resched_task(curr); ++ find_matching_se(&se, &pse); ++ ++ while (se) { ++ BUG_ON(!pse); ++ ++ if (wakeup_preempt_entity(se, pse) == 1) { ++ resched_task(curr); ++ break; ++ } ++ ++ se = parent_entity(se); ++ pse = parent_entity(pse); ++ } + } + + static struct task_struct *pick_next_task_fair(struct rq *rq) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/bug-502026_fix_apicid_panic.patch b/src/patches/suse-2.6.27.31/patches.fixes/bug-502026_fix_apicid_panic.patch new file mode 100644 index 000000000..863db2b3a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/bug-502026_fix_apicid_panic.patch @@ -0,0 +1,117 @@ +From: Youquan Song +Subject: x86: Fix APICID panic +References: bnc#502026 + +Signed-off-by: Rafael J. Wysocki + +--- + arch/x86/kernel/apic_64.c | 12 ++++++++++++ + arch/x86/kernel/genapic_64.c | 10 ++++++++++ + arch/x86/kernel/genx2apic_cluster.c | 5 +---- + arch/x86/kernel/genx2apic_phys.c | 10 +++++----- + include/asm-x86/apic.h | 10 +++++++++- + 5 files changed, 37 insertions(+), 10 deletions(-) + +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -928,6 +928,18 @@ void enable_x2apic(void) + } + } + ++int x2apic_enabled(void) ++{ ++ int msr, msr2; ++ if (!cpu_has_x2apic) ++ return 0; ++ ++ rdmsr(MSR_IA32_APICBASE, msr, msr2); ++ if (msr & X2APIC_ENABLE) ++ return 1; ++ return 0; ++} ++ + void __init enable_IR_x2apic(void) + { + #ifdef CONFIG_INTR_REMAP +--- a/arch/x86/kernel/genapic_64.c ++++ b/arch/x86/kernel/genapic_64.c +@@ -48,6 +48,16 @@ void __init setup_apic_routing(void) + genapic = &apic_flat; + } + ++ if (x2apic && (genapic != &apic_x2apic_phys && ++ genapic != &apic_x2apic_uv_x && ++ genapic != &apic_x2apic_cluster)) { ++ if (x2apic_phys) ++ genapic = &apic_x2apic_phys; ++ else ++ genapic = &apic_x2apic_cluster; ++ printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); ++ } ++ + if (genapic == &apic_flat) { + if (max_physical_apicid >= 8) + genapic = &apic_physflat; +--- a/arch/x86/kernel/genx2apic_cluster.c ++++ b/arch/x86/kernel/genx2apic_cluster.c +@@ -14,10 +14,7 @@ DEFINE_PER_CPU(u32, x86_cpu_to_logical_a + + static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { +- if (cpu_has_x2apic) +- return 1; +- +- return 0; ++ return x2apic_enabled(); + } + + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ +--- a/arch/x86/kernel/genx2apic_phys.c ++++ b/arch/x86/kernel/genx2apic_phys.c +@@ -12,7 +12,7 @@ + + DEFINE_PER_CPU(int, x2apic_extra_bits); + +-static int x2apic_phys; ++int x2apic_phys; + + static int set_x2apic_phys_mode(char *arg) + { +@@ -23,10 +23,10 @@ early_param("x2apic_phys", set_x2apic_ph + + static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) + { +- if (cpu_has_x2apic && x2apic_phys) +- return 1; +- +- return 0; ++ if (x2apic_phys) ++ return x2apic_enabled(); ++ else ++ return 0; + } + + /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ +--- a/include/asm-x86/apic.h ++++ b/include/asm-x86/apic.h +@@ -90,11 +90,19 @@ static inline u32 native_apic_msr_read(u + } + + #ifndef CONFIG_X86_32 +- extern int x2apic, x2apic_preenabled; ++ extern int x2apic, x2apic_preenabled, x2apic_phys; + extern void check_x2apic(void); + extern void enable_x2apic(void); ++ extern int x2apic_enabled(void); + extern void enable_IR_x2apic(void); + extern void x2apic_icr_write(u32 low, u32 id); ++#else ++ #define x2apic 0 ++ #define x2apic_phys 0 ++static inline int x2apic_enabled(void) ++{ ++ return 0; ++} + #endif + + struct apic_ops { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/cgroups-suppress-cloning-warning.patch b/src/patches/suse-2.6.27.31/patches.fixes/cgroups-suppress-cloning-warning.patch new file mode 100644 index 000000000..b4ba63252 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/cgroups-suppress-cloning-warning.patch @@ -0,0 +1,33 @@ +From e368d3a836797ddf193b1ec18c97407a791d2451 Mon Sep 17 00:00:00 2001 +From: Sharyathi Nagesh +Date: Tue, 23 Dec 2008 13:57:12 -0800 +Subject: [PATCH] cgroups: suppress bogus warning messages +References: bnc#460961 +Patch-mainline: 2.6.28 + +Remove spurious warning messages that are thrown onto the console during +cgroup operations. + +Signed-off-by: Alexey Dobriyan +Signed-off-by: Sharyathi Nagesh +Acked-by: Serge E. Hallyn +Cc: Paul Menage +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Jiri Slaby +--- + kernel/cgroup.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -2875,9 +2875,6 @@ int cgroup_clone(struct task_struct *tsk + again: + root = subsys->root; + if (root == &rootnode) { +- printk(KERN_INFO +- "Not cloning cgroup for unused subsystem %s\n", +- subsys->name); + mutex_unlock(&cgroup_mutex); + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_export_latency.patch b/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_export_latency.patch new file mode 100644 index 000000000..a5999f237 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_export_latency.patch @@ -0,0 +1,71 @@ +From: Thomas Renninger +Subject: CPUFREQ: Introduce /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_transition_latency +References: bnc#464461 +Patch-Mainline: not yet + +It's not only useful for the ondemand and conservative governors, but +also for userspace daemons to know about the HW transition latency of +the CPU. +It is especially useful for userspace to know about this value when +the ondemand or conservative governors are run. The sampling rate +control value depends on it and for userspace being able to set sane +tuning values there it has to know about the transition latency. + +Signed-off-by: Thomas Renninger + +--- + Documentation/cpu-freq/user-guide.txt | 12 ++++++++++++ + drivers/cpufreq/cpufreq.c | 3 +++ + 2 files changed, 15 insertions(+) + +Index: linux-2.6.27/Documentation/cpu-freq/user-guide.txt +=================================================================== +--- linux-2.6.27.orig/Documentation/cpu-freq/user-guide.txt ++++ linux-2.6.27/Documentation/cpu-freq/user-guide.txt +@@ -142,6 +142,18 @@ cpuinfo_min_freq : this file shows the + frequency the processor can run at(in kHz) + cpuinfo_max_freq : this file shows the maximum operating + frequency the processor can run at(in kHz) ++cpuinfo_transition_latency The time it takes on this CPU to ++ switch between two frequencies in nano ++ seconds. If unknown or known to be ++ that high that the driver does not ++ work with the ondemand governor, -1 ++ (CPUFREQ_ETERNAL) will be returned. ++ Using this information can be useful ++ to choose an appropriate polling ++ frequency for a kernel governor or ++ userspace daemon. Make sure to not ++ switch the frequency too often ++ resulting in performance loss. + scaling_driver : this file shows what cpufreq driver is + used to set the frequency on this CPU + +Index: linux-2.6.27/drivers/cpufreq/cpufreq.c +=================================================================== +--- linux-2.6.27.orig/drivers/cpufreq/cpufreq.c ++++ linux-2.6.27/drivers/cpufreq/cpufreq.c +@@ -455,6 +455,7 @@ static ssize_t show_##file_name \ + + show_one(cpuinfo_min_freq, cpuinfo.min_freq); + show_one(cpuinfo_max_freq, cpuinfo.max_freq); ++show_one(cpuinfo_transition_latency, cpuinfo.transition_latency); + show_one(scaling_min_freq, min); + show_one(scaling_max_freq, max); + show_one(scaling_cur_freq, cur); +@@ -660,6 +661,7 @@ __ATTR(_name, 0644, show_##_name, store_ + define_one_ro0400(cpuinfo_cur_freq); + define_one_ro(cpuinfo_min_freq); + define_one_ro(cpuinfo_max_freq); ++define_one_ro(cpuinfo_transition_latency); + define_one_ro(scaling_available_governors); + define_one_ro(scaling_driver); + define_one_ro(scaling_cur_freq); +@@ -673,6 +675,7 @@ define_one_rw(scaling_setspeed); + static struct attribute *default_attrs[] = { + &cpuinfo_min_freq.attr, + &cpuinfo_max_freq.attr, ++ &cpuinfo_transition_latency.attr, + &scaling_min_freq.attr, + &scaling_max_freq.attr, + &affected_cpus.attr, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_ondemand_adjust_sampling_rate_limit.patch b/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_ondemand_adjust_sampling_rate_limit.patch new file mode 100644 index 000000000..ab1d877be --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_ondemand_adjust_sampling_rate_limit.patch @@ -0,0 +1,122 @@ +From: Thomas Renninger +Subject: CPUFREQ: ondemand/conservative: sanitize sampling_rate restrictions +References: bnc#464461 +Patch-Mainline: not yet + +Limit sampling rate to transition_latency * 100 or kernel limits. +If sampling_rate is tried to be set too low, set the lowest allowed value. + +Signed-off-by: Thomas Renninger + +--- + Documentation/cpu-freq/governors.txt | 14 +++++++++++++- + drivers/cpufreq/cpufreq_conservative.c | 19 ++++++++++++++++--- + drivers/cpufreq/cpufreq_ondemand.c | 19 +++++++++++++++---- + 3 files changed, 44 insertions(+), 8 deletions(-) + +Index: linux-2.6.27/Documentation/cpu-freq/governors.txt +=================================================================== +--- linux-2.6.27.orig/Documentation/cpu-freq/governors.txt ++++ linux-2.6.27/Documentation/cpu-freq/governors.txt +@@ -117,7 +117,19 @@ accessible parameters: + sampling_rate: measured in uS (10^-6 seconds), this is how often you + want the kernel to look at the CPU usage and to make decisions on + what to do about the frequency. Typically this is set to values of +-around '10000' or more. ++around '10000' or more. It's default value is (cmp. with users-guide.txt): ++transition_latency * 1000 ++The lowest value you can set is: ++transition_latency * 100 or it may get restricted to a value where it ++makes not sense for the kernel anymore to poll that often which depends ++on your HZ config variable (HZ=1000: max=20000us, HZ=250: max=5000). ++Be aware that transition latency is in ns and sampling_rate is in us, so you ++get the same sysfs value by default. ++Sampling rate should always get adjusted considering the transition latency ++To set the sampling rate 750 times as high as the transition latency ++in the bash (as said, 1000 is default), do: ++echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \ ++ >ondemand/sampling_rate + + show_sampling_rate_(min|max): the minimum and maximum sampling rates + available that you may set 'sampling_rate' to. +Index: linux-2.6.27/drivers/cpufreq/cpufreq_conservative.c +=================================================================== +--- linux-2.6.27.orig/drivers/cpufreq/cpufreq_conservative.c ++++ linux-2.6.27/drivers/cpufreq/cpufreq_conservative.c +@@ -54,7 +54,18 @@ static unsigned int def_sampling_rate; + (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) + #define MIN_SAMPLING_RATE \ + (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) ++/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon ++ * Define the minimal settable sampling rate to the greater of: ++ * - "HW transition latency" * 100 (same as default sampling / 10) ++ * - MIN_STAT_SAMPLING_RATE ++ * To avoid that userspace shoots itself. ++*/ ++#define MINIMUM_SAMPLING_RATE \ ++ ((def_sampling_rate / 10) < MIN_STAT_SAMPLING_RATE \ ++ ? MIN_STAT_SAMPLING_RATE : (def_sampling_rate / 10)) ++/* This will also vanish soon with removing sampling_rate_max */ + #define MAX_SAMPLING_RATE (500 * def_sampling_rate) ++ + #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) + #define DEF_SAMPLING_DOWN_FACTOR (1) + #define MAX_SAMPLING_DOWN_FACTOR (10) +@@ -193,12 +204,14 @@ static ssize_t store_sampling_rate(struc + ret = sscanf (buf, "%u", &input); + + mutex_lock(&dbs_mutex); +- if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) { ++ if (ret != 1) { + mutex_unlock(&dbs_mutex); + return -EINVAL; + } +- +- dbs_tuners_ins.sampling_rate = input; ++ if (input < MINIMUM_SAMPLING_RATE) ++ dbs_tuners_ins.sampling_rate = MINIMUM_SAMPLING_RATE; ++ else ++ dbs_tuners_ins.sampling_rate = input; + mutex_unlock(&dbs_mutex); + + return count; +Index: linux-2.6.27/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- linux-2.6.27.orig/drivers/cpufreq/cpufreq_ondemand.c ++++ linux-2.6.27/drivers/cpufreq/cpufreq_ondemand.c +@@ -45,6 +45,16 @@ static unsigned int def_sampling_rate; + (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) + #define MIN_SAMPLING_RATE \ + (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) ++/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon ++ * Define the minimal settable sampling rate to the greater of: ++ * - "HW transition latency" * 100 (same as default sampling / 10) ++ * - MIN_STAT_SAMPLING_RATE ++ * To avoid that userspace shoots itself. ++*/ ++#define MINIMUM_SAMPLING_RATE \ ++ ((def_sampling_rate / 10) < MIN_STAT_SAMPLING_RATE \ ++ ? MIN_STAT_SAMPLING_RATE : (def_sampling_rate / 10)) ++/* This will also vanish soon with removing sampling_rate_max */ + #define MAX_SAMPLING_RATE (500 * def_sampling_rate) + #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) + #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) +@@ -219,13 +229,14 @@ static ssize_t store_sampling_rate(struc + ret = sscanf(buf, "%u", &input); + + mutex_lock(&dbs_mutex); +- if (ret != 1 || input > MAX_SAMPLING_RATE +- || input < MIN_SAMPLING_RATE) { ++ if (ret != 1) { + mutex_unlock(&dbs_mutex); + return -EINVAL; + } +- +- dbs_tuners_ins.sampling_rate = input; ++ if (input < MINIMUM_SAMPLING_RATE) ++ dbs_tuners_ins.sampling_rate = MINIMUM_SAMPLING_RATE; ++ else ++ dbs_tuners_ins.sampling_rate = input; + mutex_unlock(&dbs_mutex); + + return count; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_ondemand_performance_optimise_default_settings.patch b/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_ondemand_performance_optimise_default_settings.patch new file mode 100644 index 000000000..1c5b80611 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/cpufreq_ondemand_performance_optimise_default_settings.patch @@ -0,0 +1,67 @@ +From: Thomas Renninger +Subject: CPUFREQ: ondemand: Limit default sampling rate to 300ms max. +References: bnc#464461 +Patch-Mainline: never, SLE11 only + +HW cpufreq drivers (e.g. all non-acpi AMD) may report too high latency values. +The default sampling rate (how often the ondemand/conservative governor +checks for frequency adjustments) may therefore be much too high, +resulting in performance loss. + +Restrict default sampling rate to 300ms. 333ms sampling rate is field +tested with userspace governors, 300ms should be a fine maximum default +value for the ondemand kernel governor for all HW out there. + +Set default up_threshold to 40 on multi core systems. +This should avoid effects where two CPU intensive threads are waiting on +each other on separate cores. On a single core machine these would all be +processed on one core resulting in higher utilization of the one core. + +--- + drivers/cpufreq/cpufreq_ondemand.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +Index: linux-2.6.27/drivers/cpufreq/cpufreq_ondemand.c +=================================================================== +--- linux-2.6.27.orig/drivers/cpufreq/cpufreq_ondemand.c ++++ linux-2.6.27/drivers/cpufreq/cpufreq_ondemand.c +@@ -58,6 +58,7 @@ static unsigned int def_sampling_rate; + #define MAX_SAMPLING_RATE (500 * def_sampling_rate) + #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) + #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) ++#define MAX_DEFAULT_SAMPLING_RATE (300 * 1000) + + static void do_dbs_timer(struct work_struct *work); + +@@ -558,6 +559,31 @@ static int cpufreq_governor_dbs(struct c + if (def_sampling_rate < MIN_STAT_SAMPLING_RATE) + def_sampling_rate = MIN_STAT_SAMPLING_RATE; + ++ /* ++ * Cut def_sampling rate to 300ms if it was above, ++ * still consider to not set it above latency ++ * transition * 100 ++ */ ++ if (def_sampling_rate > MAX_DEFAULT_SAMPLING_RATE) { ++ def_sampling_rate = ++ (MAX_DEFAULT_SAMPLING_RATE < MINIMUM_SAMPLING_RATE) ++ ? MINIMUM_SAMPLING_RATE : MAX_DEFAULT_SAMPLING_RATE; ++ printk(KERN_INFO "CPUFREQ: ondemand sampling " ++ "rate set to %d ms\n", ++ def_sampling_rate / 1000); ++ } ++ /* ++ * Be conservative in respect to performance. ++ * If an application calculates using two threads ++ * depending on each other, they will be run on several ++ * CPU cores resulting on 50% load on both. ++ * SLED might still want to prefer 80% up_threshold ++ * by default, but we cannot differ that here. ++ */ ++ if (num_online_cpus() > 1) ++ dbs_tuners_ins.up_threshold = ++ DEF_FREQUENCY_UP_THRESHOLD / 2; ++ + dbs_tuners_ins.sampling_rate = def_sampling_rate; + } + dbs_timer_init(this_dbs_info); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dcb-fix-setpfcstate b/src/patches/suse-2.6.27.31/patches.fixes/dcb-fix-setpfcstate new file mode 100644 index 000000000..dc4541de1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dcb-fix-setpfcstate @@ -0,0 +1,53 @@ +Subject: Fix setpfcstate +From: Hannes Reinecke +Date: Fri Nov 7 15:36:08 2008 +0100: +Git: f7e09ce313fdc4f79403d43b1ac570f6807973bd +References: bnc#438954 + +Fixup setpfcstate and setnumtcs command. + +Signed-off-by: John Fastabend +Signed-off-by: Hannes Reinecke + +diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c +index f5e2b0b..be9dcbb 100644 +--- a/net/dcb/dcbnl.c ++++ b/net/dcb/dcbnl.c +@@ -435,7 +435,6 @@ static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, + struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; + int ret = -EINVAL; + u8 value; +- u8 status; + int i; + + if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setstate) +@@ -458,14 +457,11 @@ static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, + ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); + + if (ret) +- goto err; ++ goto operr; + } + +- value = nla_get_u8(tb[DCB_ATTR_STATE]); +- +- status = netdev->dcbnl_ops->setnumtcs(netdev, i, value); +- +- ret = dcbnl_reply(!!status, RTM_SETDCB, DCB_CMD_SNUMTCS, ++operr: ++ ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, + DCB_ATTR_NUMTCS, pid, seq, flags); + + err: +@@ -496,9 +492,9 @@ static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, + if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) + return ret; + +- value = nla_get_u8(tb[DCB_ATTR_STATE]); ++ value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); + +- netdev->dcbnl_ops->setstate(netdev, value); ++ netdev->dcbnl_ops->setpfcstate(netdev, value); + + ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, + pid, seq, flags); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dcb-setting-pg-will-cause-tx-hang b/src/patches/suse-2.6.27.31/patches.fixes/dcb-setting-pg-will-cause-tx-hang new file mode 100644 index 000000000..abece8ff2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dcb-setting-pg-will-cause-tx-hang @@ -0,0 +1,74 @@ +Subject: DCB: setting pg will cause tx unit hangs +From: Alexander Duyck +References: bnc#438954 + +It seems like the configuration may be doing things while the adapter is +still up that it shouldn't. + +Signed-off-by: Alexander Duyck +Acked-by: Hannes Reinecke +--- + + drivers/net/ixgbe/ixgbe_dcb_nl.c | 16 ++++++++++------ + 1 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c +index 32d11e5..ca2537e 100644 +--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c ++++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c +@@ -135,7 +135,7 @@ static void ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + return; + } else { +- if (netdev->flags & IFF_UP) ++ if (netif_running(netdev)) + netdev->stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); +@@ -149,13 +149,13 @@ static void ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) + adapter->flags |= IXGBE_FLAG_DCB_ENABLED; + ixgbe_init_interrupt_scheme(adapter); + ixgbe_napi_add_all(adapter); +- if (netdev->flags & IFF_UP) ++ if (netif_running(netdev)) + netdev->open(netdev); + } + } else { + /* Turn off DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { +- if (netdev->flags & IFF_UP) ++ if (netif_running(netdev)) + netdev->stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); +@@ -169,7 +169,7 @@ static void ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) + adapter->flags |= IXGBE_FLAG_RSS_ENABLED; + ixgbe_init_interrupt_scheme(adapter); + ixgbe_napi_add_all(adapter); +- if (netdev->flags & IFF_UP) ++ if (netif_running(netdev)) + netdev->open(netdev); + } else { + return; +@@ -338,6 +338,9 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); + ++ if (netif_running(netdev)) ++ ixgbe_down(adapter); ++ + ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, + adapter->ring_feature[RING_F_DCB].indices); + if (ret) { +@@ -345,8 +348,9 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) + return ret; + } + +- ixgbe_down(adapter); +- ixgbe_up(adapter); ++ if (netif_running(netdev)) ++ ixgbe_up(adapter); ++ + adapter->dcb_set_bitmap = 0x00; + clear_bit(__IXGBE_RESETTING, &adapter->state); + return ret; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-Fix-uninitialised-variable-warning-in-lock.c.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-Fix-uninitialised-variable-warning-in-lock.c.patch new file mode 100644 index 000000000..6b5aad4fa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-Fix-uninitialised-variable-warning-in-lock.c.patch @@ -0,0 +1,37 @@ +From a566a6b11c86147fe9fc9db7ab15f9eecca3e862 Mon Sep 17 00:00:00 2001 +From: Steven Whitehouse +Date: Mon, 15 Jun 2009 08:26:48 +0100 +Subject: [PATCH] dlm: Fix uninitialised variable warning in lock.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + + CC [M] fs/dlm/lock.o +fs/dlm/lock.c: In function ‘find_rsb’: +fs/dlm/lock.c:438: warning: ‘r’ may be used uninitialized in this function + +Since r is used on the error path to set r_ret, set it to NULL. + +Signed-off-by: Steven Whitehouse +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- + fs/dlm/lock.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 205ec95..eb507c4 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -435,7 +435,7 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b, + static int find_rsb(struct dlm_ls *ls, char *name, int namelen, + unsigned int flags, struct dlm_rsb **r_ret) + { +- struct dlm_rsb *r, *tmp; ++ struct dlm_rsb *r = NULL, *tmp; + uint32_t hash, bucket; + int error = -EINVAL; + +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-allow-multiple-lockspaces.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-allow-multiple-lockspaces.patch new file mode 100644 index 000000000..57014c928 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-allow-multiple-lockspaces.patch @@ -0,0 +1,427 @@ +From: David Teigland +Subject: [PATCH] dlm: allow multiple lockspace creates +Patch-mainline: 2.6.28? +References: FATE110294 + +Add a count for lockspace create and release so that create can +be called multiple times to use the lockspace from different places. +Also add the new flag DLM_LSFL_NEWEXCL to create a lockspace with +the previous behavior of returning -EEXIST if the lockspace already +exists. + +Signed-off-by: David Teigland +Acked-by: Mark Fasheh +--- + fs/dlm/dlm_internal.h | 6 ++- + fs/dlm/lockspace.c | 107 ++++++++++++++++++++++++++++--------------- + fs/dlm/user.c | 54 +++++++++++++-------- + fs/dlm/user.h | 3 +- + fs/gfs2/locking/dlm/mount.c | 3 +- + include/linux/dlm.h | 5 ++- + include/linux/dlm_device.h | 2 +- + 7 files changed, 116 insertions(+), 64 deletions(-) + +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index 5a7ac33..9e0622a 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -2,7 +2,7 @@ + ******************************************************************************* + ** + ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +-** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -441,7 +441,9 @@ struct dlm_ls { + uint32_t ls_global_id; /* global unique lockspace ID */ + uint32_t ls_exflags; + int ls_lvblen; +- int ls_count; /* reference count */ ++ int ls_count; /* refcount of processes in ++ the dlm using this ls */ ++ int ls_create_count; /* create/release refcount */ + unsigned long ls_flags; /* LSFL_ */ + struct kobject ls_kobj; + +diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c +index 499e167..56eae4e 100644 +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -2,7 +2,7 @@ + ******************************************************************************* + ** + ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +-** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -23,6 +23,7 @@ + #include "lock.h" + #include "recover.h" + #include "requestqueue.h" ++#include "user.h" + + static int ls_count; + static struct mutex ls_lock; +@@ -246,23 +247,6 @@ static void dlm_scand_stop(void) + kthread_stop(scand_task); + } + +-static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen) +-{ +- struct dlm_ls *ls; +- +- spin_lock(&lslist_lock); +- +- list_for_each_entry(ls, &lslist, ls_list) { +- if (ls->ls_namelen == namelen && +- memcmp(ls->ls_name, name, namelen) == 0) +- goto out; +- } +- ls = NULL; +- out: +- spin_unlock(&lslist_lock); +- return ls; +-} +- + struct dlm_ls *dlm_find_lockspace_global(uint32_t id) + { + struct dlm_ls *ls; +@@ -327,6 +311,7 @@ static void remove_lockspace(struct dlm_ls *ls) + for (;;) { + spin_lock(&lslist_lock); + if (ls->ls_count == 0) { ++ WARN_ON(ls->ls_create_count != 0); + list_del(&ls->ls_list); + spin_unlock(&lslist_lock); + return; +@@ -381,7 +366,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + uint32_t flags, int lvblen) + { + struct dlm_ls *ls; +- int i, size, error = -ENOMEM; ++ int i, size, error; + int do_unreg = 0; + + if (namelen > DLM_LOCKSPACE_LEN) +@@ -393,12 +378,32 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + if (!try_module_get(THIS_MODULE)) + return -EINVAL; + +- ls = dlm_find_lockspace_name(name, namelen); +- if (ls) { +- *lockspace = ls; ++ error = 0; ++ ++ spin_lock(&lslist_lock); ++ list_for_each_entry(ls, &lslist, ls_list) { ++ WARN_ON(ls->ls_create_count <= 0); ++ if (ls->ls_namelen != namelen) ++ continue; ++ if (memcmp(ls->ls_name, name, namelen)) ++ continue; ++ if (flags & DLM_LSFL_NEWEXCL) { ++ error = -EEXIST; ++ break; ++ } ++ ls->ls_create_count++; + module_put(THIS_MODULE); +- return -EEXIST; ++ error = 1; /* not an error, return 0 */ ++ break; + } ++ spin_unlock(&lslist_lock); ++ ++ if (error < 0) ++ goto out; ++ if (error) ++ goto ret_zero; ++ ++ error = -ENOMEM; + + ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL); + if (!ls) +@@ -418,8 +423,9 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + ls->ls_allocation = GFP_KERNEL; + + /* ls_exflags are forced to match among nodes, and we don't +- need to require all nodes to have TIMEWARN or FS set */ +- ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS)); ++ need to require all nodes to have some flags set */ ++ ls->ls_exflags = (flags & ~(DLM_LSFL_TIMEWARN | DLM_LSFL_FS | ++ DLM_LSFL_NEWEXCL)); + + size = dlm_config.ci_rsbtbl_size; + ls->ls_rsbtbl_size = size; +@@ -510,6 +516,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + down_write(&ls->ls_in_recovery); + + spin_lock(&lslist_lock); ++ ls->ls_create_count = 1; + list_add(&ls->ls_list, &lslist); + spin_unlock(&lslist_lock); + +@@ -548,7 +555,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + dlm_create_debug_file(ls); + + log_debug(ls, "join complete"); +- ++ ret_zero: + *lockspace = ls; + return 0; + +@@ -635,11 +642,32 @@ static int release_lockspace(struct dlm_ls *ls, int force) + struct dlm_lkb *lkb; + struct dlm_rsb *rsb; + struct list_head *head; +- int i; +- int busy = lockspace_busy(ls); ++ int i, busy, rv; ++ ++ busy = lockspace_busy(ls); ++ ++ spin_lock(&lslist_lock); ++ if (ls->ls_create_count == 1) { ++ if (busy > force) ++ rv = -EBUSY; ++ else { ++ /* remove_lockspace takes ls off lslist */ ++ ls->ls_create_count = 0; ++ rv = 0; ++ } ++ } else if (ls->ls_create_count > 1) { ++ rv = --ls->ls_create_count; ++ } else { ++ rv = -EINVAL; ++ } ++ spin_unlock(&lslist_lock); ++ ++ if (rv) { ++ log_debug(ls, "release_lockspace no remove %d", rv); ++ return rv; ++ } + +- if (busy > force) +- return -EBUSY; ++ dlm_device_deregister(ls); + + if (force < 3) + do_uevent(ls, 0); +@@ -720,15 +748,10 @@ static int release_lockspace(struct dlm_ls *ls, int force) + dlm_clear_members(ls); + dlm_clear_members_gone(ls); + kfree(ls->ls_node_array); ++ log_debug(ls, "release_lockspace final free"); + kobject_put(&ls->ls_kobj); + /* The ls structure will be freed when the kobject is done with */ + +- mutex_lock(&ls_lock); +- ls_count--; +- if (!ls_count) +- threads_stop(); +- mutex_unlock(&ls_lock); +- + module_put(THIS_MODULE); + return 0; + } +@@ -750,11 +773,21 @@ static int release_lockspace(struct dlm_ls *ls, int force) + int dlm_release_lockspace(void *lockspace, int force) + { + struct dlm_ls *ls; ++ int error; + + ls = dlm_find_lockspace_local(lockspace); + if (!ls) + return -EINVAL; + dlm_put_lockspace(ls); +- return release_lockspace(ls, force); ++ ++ mutex_lock(&ls_lock); ++ error = release_lockspace(ls, force); ++ if (!error) ++ ls_count--; ++ else if (!ls_count) ++ threads_stop(); ++ mutex_unlock(&ls_lock); ++ ++ return error; + } + +diff --git a/fs/dlm/user.c b/fs/dlm/user.c +index 34f14a1..6542110 100644 +--- a/fs/dlm/user.c ++++ b/fs/dlm/user.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions +@@ -340,10 +340,15 @@ static int device_user_deadlock(struct dlm_user_proc *proc, + return error; + } + +-static int create_misc_device(struct dlm_ls *ls, char *name) ++static int dlm_device_register(struct dlm_ls *ls, char *name) + { + int error, len; + ++ /* The device is already registered. This happens when the ++ lockspace is created multiple times from userspace. */ ++ if (ls->ls_device.name) ++ return 0; ++ + error = -ENOMEM; + len = strlen(name) + strlen(name_prefix) + 2; + ls->ls_device.name = kzalloc(len, GFP_KERNEL); +@@ -363,6 +368,22 @@ fail: + return error; + } + ++int dlm_device_deregister(struct dlm_ls *ls) ++{ ++ int error; ++ ++ /* The device is not registered. This happens when the lockspace ++ was never used from userspace, or when device_create_lockspace() ++ calls dlm_release_lockspace() after the register fails. */ ++ if (!ls->ls_device.name) ++ return 0; ++ ++ error = misc_deregister(&ls->ls_device); ++ if (!error) ++ kfree(ls->ls_device.name); ++ return error; ++} ++ + static int device_user_purge(struct dlm_user_proc *proc, + struct dlm_purge_params *params) + { +@@ -397,7 +418,7 @@ static int device_create_lockspace(struct dlm_lspace_params *params) + if (!ls) + return -ENOENT; + +- error = create_misc_device(ls, params->name); ++ error = dlm_device_register(ls, params->name); + dlm_put_lockspace(ls); + + if (error) +@@ -421,31 +442,22 @@ static int device_remove_lockspace(struct dlm_lspace_params *params) + if (!ls) + return -ENOENT; + +- /* Deregister the misc device first, so we don't have +- * a device that's not attached to a lockspace. If +- * dlm_release_lockspace fails then we can recreate it +- */ +- error = misc_deregister(&ls->ls_device); +- if (error) { +- dlm_put_lockspace(ls); +- goto out; +- } +- kfree(ls->ls_device.name); +- + if (params->flags & DLM_USER_LSFLG_FORCEFREE) + force = 2; + + lockspace = ls->ls_local_handle; ++ dlm_put_lockspace(ls); + +- /* dlm_release_lockspace waits for references to go to zero, +- so all processes will need to close their device for the ls +- before the release will procede */ ++ /* The final dlm_release_lockspace waits for references to go to ++ zero, so all processes will need to close their device for the ++ ls before the release will proceed. release also calls the ++ device_deregister above. Converting a positive return value ++ from release to zero means that userspace won't know when its ++ release was the final one, but it shouldn't need to know. */ + +- dlm_put_lockspace(ls); + error = dlm_release_lockspace(lockspace, force); +- if (error) +- create_misc_device(ls, ls->ls_name); +- out: ++ if (error > 0) ++ error = 0; + return error; + } + +diff --git a/fs/dlm/user.h b/fs/dlm/user.h +index d38e9f3..c528b6b 100644 +--- a/fs/dlm/user.h ++++ b/fs/dlm/user.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions +@@ -12,5 +12,6 @@ + void dlm_user_add_ast(struct dlm_lkb *lkb, int type); + int dlm_user_init(void); + void dlm_user_exit(void); ++int dlm_device_deregister(struct dlm_ls *ls); + + #endif +diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c +index 09d78c2..0c4cbe6 100644 +--- a/fs/gfs2/locking/dlm/mount.c ++++ b/fs/gfs2/locking/dlm/mount.c +@@ -144,7 +144,8 @@ static int gdlm_mount(char *table_name, char *host_data, + + error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname), + &ls->dlm_lockspace, +- DLM_LSFL_FS | (nodir ? DLM_LSFL_NODIR : 0), ++ DLM_LSFL_FS | DLM_LSFL_NEWEXCL | ++ (nodir ? DLM_LSFL_NODIR : 0), + GDLM_LVB_SIZE); + if (error) { + log_error("dlm_new_lockspace error %d", error); +diff --git a/include/linux/dlm.h b/include/linux/dlm.h +index 203a025..b9cd386 100644 +--- a/include/linux/dlm.h ++++ b/include/linux/dlm.h +@@ -2,7 +2,7 @@ + ******************************************************************************* + ** + ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +-** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -65,9 +65,12 @@ struct dlm_lksb { + char * sb_lvbptr; + }; + ++/* dlm_new_lockspace() flags */ ++ + #define DLM_LSFL_NODIR 0x00000001 + #define DLM_LSFL_TIMEWARN 0x00000002 + #define DLM_LSFL_FS 0x00000004 ++#define DLM_LSFL_NEWEXCL 0x00000008 + + #ifdef __KERNEL__ + +diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h +index c603450..3060783 100644 +--- a/include/linux/dlm_device.h ++++ b/include/linux/dlm_device.h +@@ -26,7 +26,7 @@ + /* Version of the device interface */ + #define DLM_DEVICE_VERSION_MAJOR 6 + #define DLM_DEVICE_VERSION_MINOR 0 +-#define DLM_DEVICE_VERSION_PATCH 0 ++#define DLM_DEVICE_VERSION_PATCH 1 + + /* struct passed to the lock write */ + struct dlm_lock_params { +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-connect-to-nodes-earlier.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-connect-to-nodes-earlier.patch new file mode 100644 index 000000000..48a14d7e7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-connect-to-nodes-earlier.patch @@ -0,0 +1,120 @@ +From 391fbdc5d527149578490db2f1619951d91f3561 Mon Sep 17 00:00:00 2001 +From: Christine Caulfield +Date: Thu, 7 May 2009 10:54:16 -0500 +Subject: [PATCH] dlm: connect to nodes earlier + +Make network connections to other nodes earlier, in the context of +dlm_recoverd. This avoids connecting to nodes from dlm_send where we +try to avoid allocations which could possibly deadlock if memory reclaim +goes into the cluster fs which may try to do a dlm operation. + +Signed-off-by: Christine Caulfield +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- + fs/dlm/lowcomms.c | 16 +++++++++++++++- + fs/dlm/lowcomms.h | 3 ++- + fs/dlm/member.c | 11 +++++++++-- + 3 files changed, 26 insertions(+), 4 deletions(-) + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 609108a..2559a97 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -309,6 +309,20 @@ static void lowcomms_state_change(struct sock *sk) + lowcomms_write_space(sk); + } + ++int dlm_lowcomms_connect_node(int nodeid) ++{ ++ struct connection *con; ++ ++ if (nodeid == dlm_our_nodeid()) ++ return 0; ++ ++ con = nodeid2con(nodeid, GFP_NOFS); ++ if (!con) ++ return -ENOMEM; ++ lowcomms_connect_sock(con); ++ return 0; ++} ++ + /* Make a socket active */ + static int add_sock(struct socket *sock, struct connection *con) + { +@@ -1421,7 +1435,7 @@ static int work_start(void) + static void stop_conn(struct connection *con) + { + con->flags |= 0x0F; +- if (con->sock) ++ if (con->sock && con->sock->sk) + con->sock->sk->sk_user_data = NULL; + } + +diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h +index a9a9618..1311e64 100644 +--- a/fs/dlm/lowcomms.h ++++ b/fs/dlm/lowcomms.h +@@ -2,7 +2,7 @@ + ******************************************************************************* + ** + ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -19,6 +19,7 @@ void dlm_lowcomms_stop(void); + int dlm_lowcomms_close(int nodeid); + void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc); + void dlm_lowcomms_commit_buffer(void *mh); ++int dlm_lowcomms_connect_node(int nodeid); + + #endif /* __LOWCOMMS_DOT_H__ */ + +diff --git a/fs/dlm/member.c b/fs/dlm/member.c +index 26133f0..2afb770 100644 +--- a/fs/dlm/member.c ++++ b/fs/dlm/member.c +@@ -1,7 +1,7 @@ + /****************************************************************************** + ******************************************************************************* + ** +-** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2005-2009 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -17,6 +17,7 @@ + #include "recover.h" + #include "rcom.h" + #include "config.h" ++#include "lowcomms.h" + + static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new) + { +@@ -45,7 +46,7 @@ static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new) + static int dlm_add_member(struct dlm_ls *ls, int nodeid) + { + struct dlm_member *memb; +- int w; ++ int w, error; + + memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL); + if (!memb) +@@ -57,6 +58,12 @@ static int dlm_add_member(struct dlm_ls *ls, int nodeid) + return w; + } + ++ error = dlm_lowcomms_connect_node(nodeid); ++ if (error < 0) { ++ kfree(memb); ++ return error; ++ } ++ + memb->nodeid = nodeid; + memb->weight = w; + add_ordered_member(ls, memb); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-plock-use-after-free.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-plock-use-after-free.patch new file mode 100644 index 000000000..6cc707abb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-plock-use-after-free.patch @@ -0,0 +1,67 @@ +From c78a87d0a1fc885dfdbe21fd5e07787691dfb068 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Thu, 18 Jun 2009 13:20:24 -0500 +Subject: [PATCH] dlm: fix plock use-after-free + +Fix a regression from the original addition of nfs lock support +586759f03e2e9031ac5589912a51a909ed53c30a. When a synchronous +(non-nfs) plock completes, the waiting thread will wake up and +free the op struct. This races with the user thread in +dev_write() which goes on to read the op's callback field to +check if the lock is async and needs a callback. This check +can happen on the freed op. The fix is to note the callback +value before the op can be freed. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- + fs/dlm/plock.c | 17 ++++++++++------- + 1 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c +index 894a32d..16f682e 100644 +--- a/fs/dlm/plock.c ++++ b/fs/dlm/plock.c +@@ -353,7 +353,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, + { + struct dlm_plock_info info; + struct plock_op *op; +- int found = 0; ++ int found = 0, do_callback = 0; + + if (count != sizeof(info)) + return -EINVAL; +@@ -366,21 +366,24 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, + + spin_lock(&ops_lock); + list_for_each_entry(op, &recv_list, list) { +- if (op->info.fsid == info.fsid && op->info.number == info.number && ++ if (op->info.fsid == info.fsid && ++ op->info.number == info.number && + op->info.owner == info.owner) { ++ struct plock_xop *xop = (struct plock_xop *)op; + list_del_init(&op->list); +- found = 1; +- op->done = 1; + memcpy(&op->info, &info, sizeof(info)); ++ if (xop->callback) ++ do_callback = 1; ++ else ++ op->done = 1; ++ found = 1; + break; + } + } + spin_unlock(&ops_lock); + + if (found) { +- struct plock_xop *xop; +- xop = (struct plock_xop *)op; +- if (xop->callback) ++ if (do_callback) + dlm_plock_callback(op); + else + wake_up(&recv_wq); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-shutdown-cleanup.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-shutdown-cleanup.patch new file mode 100644 index 000000000..7b15930fd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-shutdown-cleanup.patch @@ -0,0 +1,34 @@ +From: Coly Li +Author: David Teigland +References: bnc#457213 +Subject: dlm: fix shutdown cleanup + + Fixes a regression from commit 0f8e0d9a317406612700426fad3efab0b7bbc467, + "dlm: allow multiple lockspace creates". + + An extraneous 'else' slipped into a code fragment being moved from + release_lockspace() to dlm_release_lockspace(). The result of the + unwanted 'else' is that dlm threads and structures are not stopped + and cleaned up when the final dlm lockspace is removed. Trying to + create a new lockspace again afterward will fail with + "kmem_cache_create: duplicate cache dlm_conn" because the cache + was not previously destroyed. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- +--- + fs/dlm/lockspace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -784,7 +784,7 @@ int dlm_release_lockspace(void *lockspac + error = release_lockspace(ls, force); + if (!error) + ls_count--; +- else if (!ls_count) ++ if (!ls_count) + threads_stop(); + mutex_unlock(&ls_lock); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-use-count-with-multiple-joins.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-use-count-with-multiple-joins.patch new file mode 100644 index 000000000..868b40a24 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-fix-use-count-with-multiple-joins.patch @@ -0,0 +1,62 @@ +From 8511a2728ab82cab398e39d019f5cf1246021c1c Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Wed, 8 Apr 2009 15:38:43 -0500 +Subject: [PATCH] dlm: fix use count with multiple joins + +When a lockspace was joined multiple times, the global dlm +use count was incremented when it should not have been. This +caused the global dlm threads to not be stopped when all +lockspaces were eventually be removed. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- + fs/dlm/lockspace.c | 13 ++++++------- + 1 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c +index 82528d9..d489fcc 100644 +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -419,16 +419,14 @@ static int new_lockspace(const char *name, int namelen, void **lockspace, + break; + } + ls->ls_create_count++; +- module_put(THIS_MODULE); +- error = 1; /* not an error, return 0 */ ++ *lockspace = ls; ++ error = 1; + break; + } + spin_unlock(&lslist_lock); + +- if (error < 0) +- goto out; + if (error) +- goto ret_zero; ++ goto out; + + error = -ENOMEM; + +@@ -583,7 +581,6 @@ static int new_lockspace(const char *name, int namelen, void **lockspace, + dlm_create_debug_file(ls); + + log_debug(ls, "join complete"); +- ret_zero: + *lockspace = ls; + return 0; + +@@ -628,7 +625,9 @@ int dlm_new_lockspace(const char *name, int namelen, void **lockspace, + error = new_lockspace(name, namelen, lockspace, flags, lvblen); + if (!error) + ls_count++; +- else if (!ls_count) ++ if (error > 0) ++ error = 0; ++ if (!ls_count) + threads_stop(); + out: + mutex_unlock(&ls_lock); +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-free-socket-in-error-exit-path.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-free-socket-in-error-exit-path.patch new file mode 100644 index 000000000..c74c5a9a6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-free-socket-in-error-exit-path.patch @@ -0,0 +1,40 @@ +From a89d63a159b1ba5833be2bef00adf8ad8caac8be Mon Sep 17 00:00:00 2001 +From: Casey Dahlin +Date: Tue, 14 Jul 2009 12:17:51 -0500 +Subject: [PATCH] dlm: free socket in error exit path + +In the tcp_connect_to_sock() error exit path, the socket +allocated at the top of the function was not being freed. + +Signed-off-by: Casey Dahlin +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- + fs/dlm/lowcomms.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index cdb580a..618a60f 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -902,7 +902,7 @@ static void tcp_connect_to_sock(struct connection *con) + int result = -EHOSTUNREACH; + struct sockaddr_storage saddr, src_addr; + int addr_len; +- struct socket *sock; ++ struct socket *sock = NULL; + + if (con->nodeid == 0) { + log_print("attempt to connect sock 0 foiled"); +@@ -962,6 +962,8 @@ out_err: + if (con->sock) { + sock_release(con->sock); + con->sock = NULL; ++ } else if (sock) { ++ sock_release(sock); + } + /* + * Some errors are fatal and this list might need adjusting. For other +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dlm-use-more-NOFS-allocation.patch b/src/patches/suse-2.6.27.31/patches.fixes/dlm-use-more-NOFS-allocation.patch new file mode 100644 index 000000000..093d90e42 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dlm-use-more-NOFS-allocation.patch @@ -0,0 +1,138 @@ +From 748285ccf7ea76d3d76d0d5f2945ad6fb91f5329 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 15 May 2009 10:50:57 -0500 +Subject: [PATCH] dlm: use more NOFS allocation + +Change some GFP_KERNEL allocations to use either GFP_NOFS or +ls_allocation (when available) which the fs sets to GFP_NOFS. +The point is to prevent allocations from going back into the +cluster fs in places where that might lead to deadlock. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li +--- + fs/dlm/dir.c | 7 ++++--- + fs/dlm/lowcomms.c | 6 +++--- + fs/dlm/member.c | 8 ++++---- + fs/dlm/requestqueue.c | 2 +- + 4 files changed, 12 insertions(+), 11 deletions(-) + +diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c +index 858fba1..c4dfa1d 100644 +--- a/fs/dlm/dir.c ++++ b/fs/dlm/dir.c +@@ -49,7 +49,8 @@ static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) + spin_unlock(&ls->ls_recover_list_lock); + + if (!found) +- de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_KERNEL); ++ de = kzalloc(sizeof(struct dlm_direntry) + len, ++ ls->ls_allocation); + return de; + } + +@@ -211,7 +212,7 @@ int dlm_recover_directory(struct dlm_ls *ls) + + dlm_dir_clear(ls); + +- last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL); ++ last_name = kmalloc(DLM_RESNAME_MAXLEN, ls->ls_allocation); + if (!last_name) + goto out; + +@@ -322,7 +323,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, + if (namelen > DLM_RESNAME_MAXLEN) + return -EINVAL; + +- de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_KERNEL); ++ de = kzalloc(sizeof(struct dlm_direntry) + namelen, ls->ls_allocation); + if (!de) + return -ENOMEM; + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 2559a97..cdb580a 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -500,7 +500,7 @@ static void process_sctp_notification(struct connection *con, + return; + } + +- new_con = nodeid2con(nodeid, GFP_KERNEL); ++ new_con = nodeid2con(nodeid, GFP_NOFS); + if (!new_con) + return; + +@@ -736,7 +736,7 @@ static int tcp_accept_from_sock(struct connection *con) + * the same time and the connections cross on the wire. + * In this case we store the incoming one in "othercon" + */ +- newcon = nodeid2con(nodeid, GFP_KERNEL); ++ newcon = nodeid2con(nodeid, GFP_NOFS); + if (!newcon) { + result = -ENOMEM; + goto accept_err; +@@ -746,7 +746,7 @@ static int tcp_accept_from_sock(struct connection *con) + struct connection *othercon = newcon->othercon; + + if (!othercon) { +- othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL); ++ othercon = kmem_cache_zalloc(con_cache, GFP_NOFS); + if (!othercon) { + log_print("failed to allocate incoming socket"); + mutex_unlock(&newcon->sock_mutex); +diff --git a/fs/dlm/member.c b/fs/dlm/member.c +index 2afb770..b128775 100644 +--- a/fs/dlm/member.c ++++ b/fs/dlm/member.c +@@ -48,7 +48,7 @@ static int dlm_add_member(struct dlm_ls *ls, int nodeid) + struct dlm_member *memb; + int w, error; + +- memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL); ++ memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation); + if (!memb) + return -ENOMEM; + +@@ -143,7 +143,7 @@ static void make_member_array(struct dlm_ls *ls) + + ls->ls_total_weight = total; + +- array = kmalloc(sizeof(int) * total, GFP_KERNEL); ++ array = kmalloc(sizeof(int) * total, ls->ls_allocation); + if (!array) + return; + +@@ -226,7 +226,7 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) + continue; + log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]); + +- memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL); ++ memb = kzalloc(sizeof(struct dlm_member), ls->ls_allocation); + if (!memb) + return -ENOMEM; + memb->nodeid = rv->new[i]; +@@ -341,7 +341,7 @@ int dlm_ls_start(struct dlm_ls *ls) + int *ids = NULL, *new = NULL; + int error, ids_count = 0, new_count = 0; + +- rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL); ++ rv = kzalloc(sizeof(struct dlm_recover), ls->ls_allocation); + if (!rv) + return -ENOMEM; + +diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c +index daa4183..7a2307c 100644 +--- a/fs/dlm/requestqueue.c ++++ b/fs/dlm/requestqueue.c +@@ -35,7 +35,7 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms) + struct rq_entry *e; + int length = ms->m_header.h_length - sizeof(struct dlm_message); + +- e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL); ++ e = kmalloc(sizeof(struct rq_entry) + length, ls->ls_allocation); + if (!e) { + log_print("dlm_add_requestqueue: out of memory len %d", length); + return; +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-avoid-put-table-dm_any_congested b/src/patches/suse-2.6.27.31/patches.fixes/dm-avoid-put-table-dm_any_congested new file mode 100644 index 000000000..c8d36c363 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-avoid-put-table-dm_any_congested @@ -0,0 +1,82 @@ +From: Chandra Seetharaman +Subject: dm: avoid destroying table in dm_any_congested +References: bnc#457205 +Patch-mainline: 2.6.28-rc4 +Signed-off-by: Nikanth Karthikesan + +[PATCH 1/3] for bnc 457205. Even though this fix is almost +reverted by 3rd patch in this series, this patch is used as it +fixes a suble bug of calling dm_table_put only when dm_get_table +succeeds. Also this makes code more inline with the mainline. + +mainline commit 8a57dfc6f943c92b861c9a19b0c86ddcb2aba768 + + dm_any_congested() just checks for the DMF_BLOCK_IO and has no + code to make sure that suspend waits for dm_any_congested() to + complete. This patch adds such a check. + + Without it, a race can occur with dm_table_put() attempting to + destroying the table in the wrong thread, the one running + dm_any_congested() which is meant to be quick and return + immediately. + + Two examples of problems: + 1. Sleeping functions called from congested code, the caller + of which holds a spin lock. + 2. An ABBA deadlock between pdflush and multipathd. The two locks + in contention are inode lock and kernel lock. + + Signed-off-by: Chandra Seetharaman + Signed-off-by: Mikulas Patocka + Signed-off-by: Alasdair G Kergon + +Index: linux-2.6.27/drivers/md/dm.c +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm.c ++++ linux-2.6.27/drivers/md/dm.c +@@ -1640,22 +1640,32 @@ static void dm_unplug_all(struct request + + static int dm_any_congested(void *congested_data, int bdi_bits) + { +- int r; ++ int r = bdi_bits; + struct mapped_device *md = (struct mapped_device *) congested_data; +- struct dm_table *map = dm_get_table(md); ++ struct dm_table *map; + +- if (!map || test_bit(DMF_BLOCK_IO, &md->flags)) +- r = bdi_bits; +- else if (dm_request_based(md)) +- /* +- * Request-based dm cares about only own queue for +- * the query about congestion status of request_queue +- */ +- r = md->queue->backing_dev_info.state & bdi_bits; +- else +- r = dm_table_any_congested(map, bdi_bits); ++ atomic_inc(&md->pending); ++ ++ if (!test_bit(DMF_BLOCK_IO, &md->flags)) { ++ map = dm_get_table(md); ++ if (map) { ++ if (dm_request_based(md)) ++ /* ++ * Request-based dm cares about only own queue for ++ * the query about congestion status of request_queue ++ */ ++ r = md->queue->backing_dev_info.state & bdi_bits; ++ else ++ r = dm_table_any_congested(map, bdi_bits); ++ dm_table_put(map); ++ } ++ } ++ ++ ++ if (!atomic_dec_return(&md->pending)) ++ /* nudge anyone waiting on suspend queue */ ++ wake_up(&md->wait); + +- dm_table_put(map); + return r; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-leastpending-correction b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-leastpending-correction new file mode 100644 index 000000000..b9c3c7688 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-leastpending-correction @@ -0,0 +1,22 @@ +From: Vijayakumar Balasubramanian +Subject: Path selector fix to dm-least-pending +References: bnc#444199 + +We found that the lpp path selector had a small logical +problem causing this issue. Attached patch would solve the issue. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/md/dm-least-pending.c b/drivers/md/dm-least-pending.c +index a85bc90..c3ee548 100644 +--- a/drivers/md/dm-least-pending.c ++++ b/drivers/md/dm-least-pending.c +@@ -194,7 +194,7 @@ static struct dm_path *lpp_select_path(struct path_selector *ps, + return NULL; + + atomic_inc(&least_io_path->io_count); +- *repeat_count = pi->repeat_count; ++ *repeat_count = least_io_path->repeat_count; + + return least_io_path->path; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-reattach-dh b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-reattach-dh new file mode 100644 index 000000000..a60eaf701 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-reattach-dh @@ -0,0 +1,77 @@ +From: Hannes Reinecke +Subject: Reattach device handler for multipath devices +References: bnc#435688 + +The multipath daemon might have specified a different device_handler +than the one a device is attached to by default. +So we should try to re-attach with the user-specified device_handler +and only return an error if that fails. +And we should _not_ detach existing hardware handlers. This will +set the path to failed during failover. + +Signed-off-by: Hannes Reinecke list); +- if (m->hw_handler_name) +- scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); + dm_put_device(ti, pgpath->path.dev); + spin_lock_irqsave(&m->lock, flags); + if (m->pgpath_to_activate == pgpath) +@@ -599,9 +597,19 @@ static struct pgpath *parse_path(struct + } + + if (m->hw_handler_name) { +- r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev), +- m->hw_handler_name); ++ struct request_queue *q = bdev_get_queue(p->path.dev->bdev); ++ ++ r = scsi_dh_attach(q, m->hw_handler_name); ++ if (r == -EBUSY) { ++ /* ++ * Already attached to different hw_handler, ++ * try to reattach with correct one. ++ */ ++ scsi_dh_detach(q); ++ r = scsi_dh_attach(q, m->hw_handler_name); ++ } + if (r < 0) { ++ ti->error = "error attaching hardware handler"; + dm_put_device(ti, p->path.dev); + goto bad; + } +--- a/drivers/scsi/device_handler/scsi_dh.c ++++ b/drivers/scsi/device_handler/scsi_dh.c +@@ -498,7 +498,6 @@ void scsi_dh_detach(struct request_queue + { + unsigned long flags; + struct scsi_device *sdev; +- struct scsi_device_handler *scsi_dh = NULL; + + spin_lock_irqsave(q->queue_lock, flags); + sdev = scsi_device_from_queue(q); +@@ -509,12 +508,9 @@ void scsi_dh_detach(struct request_queue + if (!sdev) + return; + +- if (sdev->scsi_dh_data) { +- /* if sdev is not on internal list, detach */ +- scsi_dh = sdev->scsi_dh_data->scsi_dh; +- if (!device_handler_match(scsi_dh, sdev)) +- scsi_dh_handler_detach(sdev, scsi_dh); +- } ++ if (sdev->scsi_dh_data) ++ scsi_dh_handler_detach(sdev, sdev->scsi_dh_data->scsi_dh); ++ + put_device(&sdev->sdev_gendev); + } + EXPORT_SYMBOL_GPL(scsi_dh_detach); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-remove-is_active b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-remove-is_active new file mode 100644 index 000000000..bb7c6132e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-remove-is_active @@ -0,0 +1,94 @@ +Subject: dm mpath: remove is_active from struct dm_path +From: Hannes Reinecke +Date: Fri Oct 24 13:31:15 2008 +0200: +Git: 1271668e1c80210efa60c51a52b72bfb587eebe7 + +This patch moves 'is_active' from struct dm_path to struct pgpath +as it does not need exporting. + +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Signed-off-by: Alasdair G Kergon + +Conflicts: + + drivers/md/dm-mpath.c + +--- + drivers/md/dm-mpath.c | 13 +++++++------ + drivers/md/dm-mpath.h | 2 -- + 2 files changed, 7 insertions(+), 8 deletions(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -28,6 +28,7 @@ struct pgpath { + struct list_head list; + + struct priority_group *pg; /* Owning PG */ ++ unsigned is_active; /* Path status */ + unsigned fail_count; /* Cumulative failure count */ + + struct dm_path path; +@@ -122,7 +123,7 @@ static struct pgpath *alloc_pgpath(void) + struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL); + + if (pgpath) { +- pgpath->path.is_active = 1; ++ pgpath->is_active = 1; + INIT_WORK(&pgpath->deactivate_path, deactivate_path); + } + +@@ -880,13 +881,13 @@ static int fail_path(struct pgpath *pgpa + + spin_lock_irqsave(&m->lock, flags); + +- if (!pgpath->path.is_active) ++ if (!pgpath->is_active) + goto out; + + DMWARN("Failing path %s.", pgpath->path.dev->name); + + pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); +- pgpath->path.is_active = 0; ++ pgpath->is_active = 0; + pgpath->fail_count++; + + m->nr_valid_paths--; +@@ -917,7 +918,7 @@ static int reinstate_path(struct pgpath + + spin_lock_irqsave(&m->lock, flags); + +- if (pgpath->path.is_active) ++ if (pgpath->is_active) + goto out; + + if (!pgpath->pg->ps.type->reinstate_path) { +@@ -931,7 +932,7 @@ static int reinstate_path(struct pgpath + if (r) + goto out; + +- pgpath->path.is_active = 1; ++ pgpath->is_active = 1; + + m->current_pgpath = NULL; + if (!m->nr_valid_paths++ && m->queue_size) +@@ -1306,7 +1307,7 @@ static int multipath_status(struct dm_ta + + list_for_each_entry(p, &pg->pgpaths, list) { + DMEMIT("%s %s %u ", p->path.dev->name, +- p->path.is_active ? "A" : "F", ++ p->is_active ? "A" : "F", + p->fail_count); + if (pg->ps.type->status) + sz += pg->ps.type->status(&pg->ps, +--- a/drivers/md/dm-mpath.h ++++ b/drivers/md/dm-mpath.h +@@ -13,8 +13,6 @@ struct dm_dev; + + struct dm_path { + struct dm_dev *dev; /* Read-only */ +- unsigned is_active; /* Read-only */ +- + void *pscontext; /* For path-selector use */ + }; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-send-activate-to-every-path b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-send-activate-to-every-path new file mode 100644 index 000000000..0144d202f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-send-activate-to-every-path @@ -0,0 +1,141 @@ +From 67a6e30aa338e2e4b8ec3629df247bd8f653988b Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Tue, 16 Dec 2008 09:25:25 +0100 +Subject: [PATCH] Handle multiple paths in a path group properly during pg_init + +All of the hardware handlers, do have a state now, and they are set to +active and (some form of) inactive. All of them have prep_fn, which use +this "state" to fail the I/O without it ever being sent to the device. + +As Babu has noted in his email, the pg_init/activate is sent on only one +path and the "state" of that path is changed appropriately to "active" +while other paths in the same path group are never changed as they never +got an "activate". + +This patch makes changes in the dm-multipath layer to send an "activate" +on each paths in the path groups. + +Signed-off-by: Chandra Seetharaman +Acked-by: "Moger, Babu" +Signed-off-by: Hannes Reinecke +--- + drivers/md/dm-mpath.c | 48 ++++++++++++++++-------------------------------- + 1 file changed, 16 insertions(+), 32 deletions(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -33,6 +33,7 @@ struct pgpath { + + struct dm_path path; + struct work_struct deactivate_path; ++ struct work_struct activate_path; + }; + + #define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path) +@@ -62,8 +63,6 @@ struct multipath { + spinlock_t lock; + + const char *hw_handler_name; +- struct work_struct activate_path; +- struct pgpath *pgpath_to_activate; + unsigned nr_priority_groups; + struct list_head priority_groups; + unsigned pg_init_required; /* pg_init needs calling? */ +@@ -126,6 +125,7 @@ static struct pgpath *alloc_pgpath(void) + if (pgpath) { + pgpath->is_active = 1; + INIT_WORK(&pgpath->deactivate_path, deactivate_path); ++ INIT_WORK(&pgpath->activate_path, activate_path); + } + + return pgpath; +@@ -165,10 +165,6 @@ static void free_pgpaths(struct list_hea + list_for_each_entry_safe(pgpath, tmp, pgpaths, list) { + list_del(&pgpath->list); + dm_put_device(ti, pgpath->path.dev); +- spin_lock_irqsave(&m->lock, flags); +- if (m->pgpath_to_activate == pgpath) +- m->pgpath_to_activate = NULL; +- spin_unlock_irqrestore(&m->lock, flags); + free_pgpath(pgpath); + } + } +@@ -199,7 +195,6 @@ static struct multipath *alloc_multipath + m->queue_io = 1; + INIT_WORK(&m->process_queued_ios, process_queued_ios); + INIT_WORK(&m->trigger_event, trigger_event); +- INIT_WORK(&m->activate_path, activate_path); + m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache); + if (!m->mpio_pool) { + kfree(m); +@@ -435,8 +430,8 @@ static void process_queued_ios(struct wo + { + struct multipath *m = + container_of(work, struct multipath, process_queued_ios); +- struct pgpath *pgpath = NULL; +- unsigned init_required = 0, must_queue = 1; ++ struct pgpath *pgpath = NULL, *tmp; ++ unsigned must_queue = 1; + unsigned long flags; + + spin_lock_irqsave(&m->lock, flags); +@@ -454,19 +449,15 @@ static void process_queued_ios(struct wo + must_queue = 0; + + if (m->pg_init_required && !m->pg_init_in_progress && pgpath) { +- m->pgpath_to_activate = pgpath; + m->pg_init_count++; + m->pg_init_required = 0; +- m->pg_init_in_progress = 1; +- init_required = 1; ++ list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) { ++ queue_work(kmpath_handlerd, &tmp->activate_path); ++ m->pg_init_in_progress++; ++ } + } +- + out: + spin_unlock_irqrestore(&m->lock, flags); +- +- if (init_required) +- queue_work(kmpath_handlerd, &m->activate_path); +- + if (!must_queue) + dispatch_queued_ios(m); + } +@@ -1136,27 +1127,20 @@ static void pg_init_done(struct dm_path + pg->bypassed = 0; + } + +- m->pg_init_in_progress = 0; +- queue_work(kmultipathd, &m->process_queued_ios); +- spin_unlock_irqrestore(&m->lock, flags); ++ m->pg_init_in_progress--; ++ if (!m->pg_init_in_progress) ++ queue_work(kmultipathd, &m->process_queued_ios); ++ spin_unlock_irqrestore(&m->lock, flags); + } + + static void activate_path(struct work_struct *work) + { + int ret; +- struct multipath *m = +- container_of(work, struct multipath, activate_path); +- struct dm_path *path; +- unsigned long flags; ++ struct pgpath *pgpath = ++ container_of(work, struct pgpath, activate_path); + +- spin_lock_irqsave(&m->lock, flags); +- path = &m->pgpath_to_activate->path; +- m->pgpath_to_activate = NULL; +- spin_unlock_irqrestore(&m->lock, flags); +- if (!path) +- return; +- ret = scsi_dh_activate(bdev_get_queue(path->dev->bdev)); +- pg_init_done(path, ret); ++ ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev)); ++ pg_init_done(&pgpath->path, ret); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-skip-inactive-paths-during-activation b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-skip-inactive-paths-during-activation new file mode 100644 index 000000000..f42717407 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-mpath-skip-inactive-paths-during-activation @@ -0,0 +1,37 @@ +From: Hannes Reinecke +Date: Fri, 14 Aug 2009 16:04:05 +0200 +Subject: dm-mpath: Skip inactive paths when activating pathgroup +References: bnc#524797 + +Whenever switch pathgroup happens device mapper will try to activate all the +paths in the new path group. There is no check to see if the path has already +failed. Eventually the failed path will report error. This will reset the +current_pgpath and current_pg. The will result in infinite loop. I have added a +check to skip the activate_path for the failed path. This fixes the problem. + +Signed-off-by: Babu Moger +Signed-off-by: Hannes Reinecke +--- + drivers/md/dm-mpath.c | 5 +++-- + 1 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c +index ffe3a30..642f85f 100644 +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -465,9 +465,10 @@ static void process_queued_ios(struct work_struct *work) + m->pg_init_count++; + m->pg_init_required = 0; + list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) { +- /* Skip disabled paths */ +- if (!tmp->path.dev) ++ /* Skip disabled or failed paths */ ++ if (!tmp->path.dev || !tmp->is_active) + continue; ++ + queue_work(kmpath_handlerd, &tmp->activate_path); + m->pg_init_in_progress++; + } +-- +1.6.0.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-path-selector-ref-count b/src/patches/suse-2.6.27.31/patches.fixes/dm-path-selector-ref-count new file mode 100644 index 000000000..8696401d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-path-selector-ref-count @@ -0,0 +1,124 @@ +From: "Jun'ichi Nomura" +Subject: dm-path-selector: fix refcount corruption + +Hi, + +Refcounting of path-selector module is not safe in SMP environment. +The counter may corrupt and trigger BUG() like this: + kernel BUG at linux-2.6.29-rc3/drivers/md/dm-path-selector.c:90! +though it's rare under normal usage. + +The bug is here: + void dm_put_path_selector(struct path_selector_type *pst) + { + ... + down_read(&_ps_lock); + psi = __find_path_selector_type(pst->name); + if (!psi) + goto out; + + if (--psi->use == 0) + module_put(psi->pst.module); + + BUG_ON(psi->use < 0); + +The code manipulates the counter without exclusive lock or atomic ops. +So if 2 processors come in, the counter may corrupt. + +While it could be fixed using atomic ops for the counter manipulation, +we can just drop the 'use' counter like Cheng Renquan did for dm-target: +https://www.redhat.com/archives/dm-devel/2008-December/msg00075.html + +(Actually, without his patch, dm-target.c hits the same problem.) + +Signed-off-by: Hannes Reinecke + +-- +Jun'ichi Nomura, NEC Corporation + + +Fix refcount corruption in dm-path-selector + +Refcounting with non-atomic ops under shared lock will corrupt the counter +in multi-processor system and may trigger BUG_ON(). +Use module refcount. +# same approach as dm-target-use-module-refcount-directly.patch here +# https://www.redhat.com/archives/dm-devel/2008-December/msg00075.html + +Typical oops: + kernel BUG at linux-2.6.29-rc3/drivers/md/dm-path-selector.c:90! + Pid: 11148, comm: dmsetup Not tainted 2.6.29-rc3-nm #1 + dm_put_path_selector+0x4d/0x61 [dm_multipath] + Call Trace: + [] free_priority_group+0x33/0xb3 [dm_multipath] + [] free_multipath+0x31/0x67 [dm_multipath] + [] multipath_dtr+0x2d/0x32 [dm_multipath] + [] dm_table_destroy+0x64/0xd8 [dm_mod] + [] __unbind+0x46/0x4b [dm_mod] + [] dm_swap_table+0x60/0x14d [dm_mod] + [] dev_suspend+0xfd/0x177 [dm_mod] + [] dm_ctl_ioctl+0x24c/0x29c [dm_mod] + [] ? get_page_from_freelist+0x49c/0x61d + [] ? dev_suspend+0x0/0x177 [dm_mod] + [] vfs_ioctl+0x2a/0x77 + [] do_vfs_ioctl+0x448/0x4a0 + [] sys_ioctl+0x57/0x7a + [] system_call_fastpath+0x16/0x1b + +Signed-off-by: Jun'ichi Nomura +--- + drivers/md/dm-path-selector.c | 21 +++------------------ + 1 file changed, 3 insertions(+), 18 deletions(-) + +--- a/drivers/md/dm-path-selector.c ++++ b/drivers/md/dm-path-selector.c +@@ -16,9 +16,7 @@ + + struct ps_internal { + struct path_selector_type pst; +- + struct list_head list; +- long use; + }; + + #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst) +@@ -44,12 +42,8 @@ static struct ps_internal *get_path_sele + + down_read(&_ps_lock); + psi = __find_path_selector_type(name); +- if (psi) { +- if ((psi->use == 0) && !try_module_get(psi->pst.module)) +- psi = NULL; +- else +- psi->use++; +- } ++ if (psi && !try_module_get(psi->pst.module)) ++ psi = NULL; + up_read(&_ps_lock); + + return psi; +@@ -83,11 +77,7 @@ void dm_put_path_selector(struct path_se + if (!psi) + goto out; + +- if (--psi->use == 0) +- module_put(psi->pst.module); +- +- BUG_ON(psi->use < 0); +- ++ module_put(psi->pst.module); + out: + up_read(&_ps_lock); + } +@@ -135,11 +125,6 @@ int dm_unregister_path_selector(struct p + return -EINVAL; + } + +- if (psi->use) { +- up_write(&_ps_lock); +- return -ETXTBSY; +- } +- + list_del(&psi->list); + + up_write(&_ps_lock); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-release-map_lock-before-set_disk_ro b/src/patches/suse-2.6.27.31/patches.fixes/dm-release-map_lock-before-set_disk_ro new file mode 100644 index 000000000..66336419e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-release-map_lock-before-set_disk_ro @@ -0,0 +1,39 @@ +From: Nikanth Karthikesan +Subject: Release md->map_lock before set_disk_ro +Patch-mainline: No +References: bnc#479784 + +Signed-off-by: Nikanth Karthikesan + +Calling set_disk_ro() with irqs disabled triggers a warning. + +set_disk_ro() can be called outside the +write_lock_irqsave(&md->map_lock)? And to get the +dm_table_get_mode(md->map), we just need to hold a reference +with dm_get_table() and dm_table_put() + + +Index: linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/dm.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c +@@ -1948,12 +1948,15 @@ static int __bind(struct mapped_device * + md->map = t; + dm_table_set_restrictions(t, q); + dm_table_set_integrity(t, md); +- if (!(dm_table_get_mode(t) & FMODE_WRITE)) { +- set_disk_ro(md->disk, 1); +- } else { ++ write_unlock_irqrestore(&md->map_lock, flags); ++ ++ dm_get_table(md); ++ if (dm_table_get_mode(md->map) & FMODE_WRITE) { + set_disk_ro(md->disk, 0); ++ } else { ++ set_disk_ro(md->disk, 1); + } +- write_unlock_irqrestore(&md->map_lock, flags); ++ dm_table_put(md->map); + + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-table-ref-count b/src/patches/suse-2.6.27.31/patches.fixes/dm-table-ref-count new file mode 100644 index 000000000..09a4d1af7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-table-ref-count @@ -0,0 +1,241 @@ +From: Mikulas Patocka +Subject: dm table: rework reference counting +Patch-mainline: 2.6.28 +References: bnc#457205 +Signed-off-by: Nikanth Karthikesan + +[PATCH 3/3] for bnc 457205. + +mainline commit d58168763f74d1edbc296d7038c60efe6493fdd4 + + + Rework table reference counting. + + The existing code uses a reference counter. When the last reference is + dropped and the counter reaches zero, the table destructor is called. + Table reference counters are acquired/released from upcalls from other + kernel code (dm_any_congested, dm_merge_bvec, dm_unplug_all). + If the reference counter reaches zero in one of the upcalls, the table + destructor is called from almost random kernel code. + + This leads to various problems: + * dm_any_congested being called under a spinlock, which calls the + destructor, which calls some sleeping function. + * the destructor attempting to take a lock that is already taken by the + same process. + * stale reference from some other kernel code keeps the table + constructed, which keeps some devices open, even after successful + return from "dmsetup remove". This can confuse lvm and prevent closing + of underlying devices or reusing device minor numbers. + + The patch changes reference counting so that the table destructor can be + called only at predetermined places. + + The table has always exactly one reference from either mapped_device->map + or hash_cell->new_map. After this patch, this reference is not counted + in table->holders. A pair of dm_create_table/dm_destroy_table functions + is used for table creation/destruction. + + Temporary references from the other code increase table->holders. A pair + of dm_table_get/dm_table_put functions is used to manipulate it. + + When the table is about to be destroyed, we wait for table->holders to + reach 0. Then, we call the table destructor. We use active waiting with + msleep(1), because the situation happens rarely (to one user in 5 years) + and removing the device isn't performance-critical task: the user doesn't + care if it takes one tick more or not. + + This way, the destructor is called only at specific points + (dm_table_destroy function) and the above problems associated with lazy + destruction can't happen. + + Finally remove the temporary protection added to dm_any_congested(). + + Signed-off-by: Mikulas Patocka + Signed-off-by: Alasdair G Kergon + +--- + drivers/md/dm-ioctl.c | 10 ++++------ + drivers/md/dm-table.c | 28 +++++++++++++++++++++++----- + drivers/md/dm.c | 14 +++++--------- + drivers/md/dm.h | 1 + + 4 files changed, 33 insertions(+), 20 deletions(-) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1644,8 +1644,6 @@ static int dm_any_congested(void *conges + struct mapped_device *md = (struct mapped_device *) congested_data; + struct dm_table *map; + +- atomic_inc(&md->pending); +- + if (!test_bit(DMF_BLOCK_IO, &md->flags)) { + map = dm_get_table(md); + if (map) { +@@ -1662,10 +1660,6 @@ static int dm_any_congested(void *conges + } + + +- if (!atomic_dec_return(&md->pending)) +- /* nudge anyone waiting on suspend queue */ +- wake_up(&md->wait); +- + return r; + } + +@@ -1926,10 +1920,12 @@ static int __bind(struct mapped_device * + + if (md->suspended_bdev) + __set_size(md, size); +- if (size == 0) ++ ++ if (!size) { ++ dm_table_destroy(t); + return 0; ++ } + +- dm_table_get(t); + dm_table_event_callback(t, event_callback, md); + + /* +@@ -1967,7 +1963,7 @@ static void __unbind(struct mapped_devic + write_lock(&md->map_lock); + md->map = NULL; + write_unlock(&md->map_lock); +- dm_table_put(map); ++ dm_table_destroy(map); + } + + /* +--- a/drivers/md/dm.h ++++ b/drivers/md/dm.h +@@ -46,6 +46,7 @@ struct dm_table; + /*----------------------------------------------------------------- + * Internal table functions. + *---------------------------------------------------------------*/ ++void dm_table_destroy(struct dm_table *t); + void dm_table_event_callback(struct dm_table *t, + void (*fn)(void *), void *context); + struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -233,7 +233,7 @@ static void __hash_remove(struct hash_ce + } + + if (hc->new_map) +- dm_table_put(hc->new_map); ++ dm_table_destroy(hc->new_map); + dm_put(hc->md); + free_cell(hc); + } +@@ -828,8 +828,8 @@ static int do_resume(struct dm_ioctl *pa + + r = dm_swap_table(md, new_map); + if (r) { ++ dm_table_destroy(new_map); + dm_put(md); +- dm_table_put(new_map); + return r; + } + +@@ -837,8 +837,6 @@ static int do_resume(struct dm_ioctl *pa + set_disk_ro(dm_disk(md), 0); + else + set_disk_ro(dm_disk(md), 1); +- +- dm_table_put(new_map); + } + + if (dm_suspended(md)) +@@ -1094,7 +1092,7 @@ static int table_load(struct dm_ioctl *p + } + + if (hc->new_map) +- dm_table_put(hc->new_map); ++ dm_table_destroy(hc->new_map); + hc->new_map = t; + up_write(&_hash_lock); + +@@ -1123,7 +1121,7 @@ static int table_clear(struct dm_ioctl * + } + + if (hc->new_map) { +- dm_table_put(hc->new_map); ++ dm_table_destroy(hc->new_map); + hc->new_map = NULL; + } + +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2001 Sistina Software (UK) Limited. +- * Copyright (C) 2004 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + * + * This file is released under the GPL. + */ +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + + #define DM_MSG_PREFIX "table" +@@ -24,6 +25,19 @@ + #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) + #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) + ++/* ++ * The table has always exactly one reference from either mapped_device->map ++ * or hash_cell->new_map. This reference is not counted in table->holders. ++ * A pair of dm_create_table/dm_destroy_table functions is used for table ++ * creation/destruction. ++ * ++ * Temporary references from the other code increase table->holders. A pair ++ * of dm_table_get/dm_table_put functions is used to manipulate it. ++ * ++ * When the table is about to be destroyed, we wait for table->holders to ++ * drop to zero. ++ */ ++ + struct dm_table { + struct mapped_device *md; + atomic_t holders; +@@ -231,7 +245,7 @@ int dm_table_create(struct dm_table **re + return -ENOMEM; + + INIT_LIST_HEAD(&t->devices); +- atomic_set(&t->holders, 1); ++ atomic_set(&t->holders, 0); + + if (!num_targets) + num_targets = KEYS_PER_NODE; +@@ -260,10 +274,14 @@ static void free_devices(struct list_hea + } + } + +-static void table_destroy(struct dm_table *t) ++void dm_table_destroy(struct dm_table *t) + { + unsigned int i; + ++ while (atomic_read(&t->holders)) ++ msleep(1); ++ smp_mb(); ++ + /* free the indexes (see dm_table_complete) */ + if (t->depth >= 2) + vfree(t->index[t->depth - 2]); +@@ -301,8 +319,8 @@ void dm_table_put(struct dm_table *t) + if (!t) + return; + +- if (atomic_dec_and_test(&t->holders)) +- table_destroy(t); ++ smp_mb__before_atomic_dec(); ++ atomic_dec(&t->holders); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-table-switch-to-readonly b/src/patches/suse-2.6.27.31/patches.fixes/dm-table-switch-to-readonly new file mode 100644 index 000000000..d4814092d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-table-switch-to-readonly @@ -0,0 +1,89 @@ +From: Hannes Reinecke +Subject: dm multipath devices are not getting created for readonly devices +References: bnc#382705 + +Currently we cannot create device-mapper tables for multipath devices +whenever they are read-only. +This patch modifies the device-mapper to set the 'READ-ONLY' flag +automatically whenever a read-only is added to the table. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-table.c | 10 +++++++++- + drivers/md/dm.c | 18 ++++++++++++++++-- + 2 files changed, 25 insertions(+), 3 deletions(-) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -310,16 +310,25 @@ static void __exit dm_exit(void) + static int dm_blk_open(struct inode *inode, struct file *file) + { + struct mapped_device *md; ++ int retval = 0; + + spin_lock(&_minor_lock); + + md = inode->i_bdev->bd_disk->private_data; +- if (!md) ++ if (!md) { ++ retval = -ENXIO; + goto out; ++ } + + if (test_bit(DMF_FREEING, &md->flags) || + test_bit(DMF_DELETING, &md->flags)) { + md = NULL; ++ retval = -ENXIO; ++ goto out; ++ } ++ if (md->disk->policy && (file->f_mode & FMODE_WRITE)) { ++ md = NULL; ++ retval = -EROFS; + goto out; + } + +@@ -329,7 +338,7 @@ static int dm_blk_open(struct inode *ino + out: + spin_unlock(&_minor_lock); + +- return md ? 0 : -ENXIO; ++ return retval; + } + + static int dm_blk_close(struct inode *inode, struct file *file) +@@ -1901,6 +1910,11 @@ static int __bind(struct mapped_device * + write_lock(&md->map_lock); + md->map = t; + dm_table_set_restrictions(t, q); ++ if (!(dm_table_get_mode(t) & FMODE_WRITE)) { ++ set_disk_ro(md->disk, 1); ++ } else { ++ set_disk_ro(md->disk, 0); ++ } + write_unlock(&md->map_lock); + + return 0; +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -451,11 +451,19 @@ static int __table_get_device(struct dm_ + dd->mode = mode; + dd->bdev = NULL; + +- if ((r = open_dev(dd, dev, t->md))) { ++ r = open_dev(dd, dev, t->md); ++ if (r == -EROFS) { ++ dd->mode &= ~FMODE_WRITE; ++ r = open_dev(dd, dev, t->md); ++ } ++ if (r) { + kfree(dd); + return r; + } + ++ if (dd->mode != mode) ++ t->mode = dd->mode; ++ + format_dev_t(dd->name, dev); + + atomic_set(&dd->count, 0); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-table-upgrade-mode-race-fix b/src/patches/suse-2.6.27.31/patches.fixes/dm-table-upgrade-mode-race-fix new file mode 100644 index 000000000..de4767b36 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-table-upgrade-mode-race-fix @@ -0,0 +1,75 @@ +Patch-mainline: 2.6.30 +References: bnc#486430 +X-Git: 570b9d968bf9b16974252ef7cbce73fa6dac34f3 Mon Sep 17 00:00:00 2001 +From: Alasdair G Kergon +Date: Thu, 2 Apr 2009 19:55:28 +0100 +Subject: [PATCH] dm table: fix upgrade mode race + +upgrade_mode() sets bdev to NULL temporarily, and does not have any +locking to exclude anything from seeing that NULL. + +In dm_table_any_congested() bdev_get_queue() can dereference that NULL and +cause a reported oops. + +Fix this by not changing that field during the mode upgrade. + +Cc: stable@kernel.org +Cc: Neil Brown +Signed-off-by: Alasdair G Kergon +Acked-by: Neil Brown + +--- + drivers/md/dm-table.c | 32 +++++++++++++++++--------------- + 1 file changed, 17 insertions(+), 15 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/dm-table.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm-table.c +@@ -411,31 +411,33 @@ static int check_device_area(struct dm_d + } + + /* +- * This upgrades the mode on an already open dm_dev. Being ++ * This upgrades the mode on an already open dm_dev, being + * careful to leave things as they were if we fail to reopen the +- * device. ++ * device and not to touch the existing bdev field in case ++ * it is accessed concurrently inside dm_table_any_congested(). + */ + static int upgrade_mode(struct dm_dev *dd, int new_mode, struct mapped_device *md) + { + int r; +- struct dm_dev dd_copy; +- dev_t dev = dd->bdev->bd_dev; ++ struct dm_dev dd_new, dd_old; + +- dd_copy = *dd; ++ dd_new = dd_old = *dd; + +- dd->mode = new_mode; +- dd->bdev = NULL; +- r = open_dev(dd, dev, md); ++ dd_new.mode = new_mode; ++ dd_new.bdev = NULL; ++ ++ r = open_dev(&dd_new, dd->bdev->bd_dev, md); + if (r == -EROFS) { +- dd->mode &= ~FMODE_WRITE; +- r = open_dev(dd, dev, md); ++ dd_new.mode &= ~FMODE_WRITE; ++ r = open_dev(&dd_new, dd->bdev->bd_dev, md); + } +- if (!r) +- close_dev(&dd_copy, md); +- else +- *dd = dd_copy; ++ if (r) ++ return r; + +- return r; ++ dd->mode |= new_mode; ++ close_dev(&dd_old, md); ++ ++ return 0; + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm-unbind-drop-ref b/src/patches/suse-2.6.27.31/patches.fixes/dm-unbind-drop-ref new file mode 100644 index 000000000..470314b93 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm-unbind-drop-ref @@ -0,0 +1,36 @@ +From: Mikulas Patocka +Subject: dm table: drop reference at unbind +References: bnc#457205 +Patch-mainline: 2.6.28-rc4 +Signed-off-by: Nikanth Karthikesan + +[PATCH 2/3] for bnc 457205 + +mainline commit a1b51e98676932d031f5eec1325b2df4bbdc8f26 + + + Move one dm_table_put() so that the last reference in the thread + gets dropped in __unbind(). + + This is required for a following patch, + dm-table-rework-reference-counting.patch, which will change the logic in + such a way that table destructor is called only at specific points in + the code. + + Signed-off-by: Mikulas Patocka + Signed-off-by: Alasdair G Kergon + +Index: linux-2.6.27/drivers/md/dm.c +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm.c ++++ linux-2.6.27/drivers/md/dm.c +@@ -2055,8 +2055,8 @@ void dm_put(struct mapped_device *md) + dm_table_presuspend_targets(map); + dm_table_postsuspend_targets(map); + } +- __unbind(md); + dm_table_put(map); ++ __unbind(md); + free_dev(md); + } + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/dm_flag_queue_barrier_support b/src/patches/suse-2.6.27.31/patches.fixes/dm_flag_queue_barrier_support new file mode 100644 index 000000000..44713296c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/dm_flag_queue_barrier_support @@ -0,0 +1,34 @@ +From: Mikulas Patocka +Subject: dm: set queue ordered mode +Patch-mainline: 2.6.30 +References: bnc#496353 +Acked-by: Nikanth Karthikesan + +commit 99360b4c18f7675b50d283301d46d755affe75fd +Author: Mikulas Patocka +Date: Thu Apr 2 19:55:39 2009 +0100 + + dm: set queue ordered mode + + Set queue ordered mode. It doesn't really matter what we set here + because we don't ever put any requests on the queue. But we need to set + something other than QUEUE_ORDERED_NONE so that __generic_make_request + passes barrier requests to us. + + Signed-off-by: Mikulas Patocka + Signed-off-by: Alasdair G Kergon + +--- + drivers/md/dm.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1801,6 +1801,7 @@ static struct mapped_device *alloc_dev(i + md->queue->backing_dev_info.congested_fn = dm_any_congested; + md->queue->backing_dev_info.congested_data = md; + blk_queue_make_request(md->queue, dm_request); ++ blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL); + blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); + md->queue->unplug_fn = dm_unplug_all; + blk_queue_merge_bvec(md->queue, dm_merge_bvec); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/do_anonymous_page-race b/src/patches/suse-2.6.27.31/patches.fixes/do_anonymous_page-race new file mode 100644 index 000000000..fc36ee153 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/do_anonymous_page-race @@ -0,0 +1,34 @@ +From: Andrea Arcangeli +Subject: Race condition in userspace testcase +References: 46948, LTC11574 + + +Additional Comment #103 From Andrea Arcangeli 2004-10-15 19:41 +the last patch I attached is the safest I believe. + +I'm not sure if a lock_unlock or lock_unlock is always guaranteed to happen +after the I/O, and this makes sure no race can happen anymore. + +--- + fs/bio.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/fs/bio.c ++++ b/fs/bio.c +@@ -1192,6 +1192,16 @@ void bio_endio(struct bio *bio, int erro + else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + error = -EIO; + ++ if (bio_data_dir(bio) == READ) ++ /* ++ * If the current cpu has written to the page by hand ++ * without dma, we must enforce ordering to be sure ++ * this written data will be visible before we expose ++ * the page contents to other cpus (for example with ++ * a set_pte). ++ */ ++ smp_wmb(); ++ + if (bio->bi_end_io) + bio->bi_end_io(bio, error); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ds1682-build-fix b/src/patches/suse-2.6.27.31/patches.fixes/ds1682-build-fix new file mode 100644 index 000000000..218eea2ed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ds1682-build-fix @@ -0,0 +1,34 @@ +From: Jeff Mahoney +Subject: [PATCH] ds1682: compile fix + + I'm not sure this should go to mainline. It fixes the linkage, but I'm + pretty sure it's due to a section conflict. + + The failure was that ds1682_{show,store} were undefined at link time. + +Signed-off-by: Jeff Mahoney +--- + + drivers/i2c/chips/ds1682.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/i2c/chips/ds1682.c ++++ b/drivers/i2c/chips/ds1682.c +@@ -56,7 +56,7 @@ + /* + * Generic counter attributes + */ +-static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr, ++ssize_t ds1682_show(struct device *dev, struct device_attribute *attr, + char *buf) + { + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); +@@ -82,7 +82,7 @@ static ssize_t ds1682_show(struct device + return sprintf(buf, "%li\n", (long)le32_to_cpu(val)); + } + +-static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr, ++ssize_t ds1682_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext3-mark-super-uptodate b/src/patches/suse-2.6.27.31/patches.fixes/ext3-mark-super-uptodate new file mode 100644 index 000000000..952ce790c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext3-mark-super-uptodate @@ -0,0 +1,40 @@ +From: Jeff Mahoney +Subject: [PATCH] ext3: always mark super uptodate before dirty +References: bnc#457043 + + The superblock's bh is something of an exception. It is only read + during mount and is only released during unmount. The in-memory + copy is invariably the most recent one. + + If a write error occurs while syncing the superblock, it will be marked + !uptodate. When another error occurs, ext3_error will invoke + ext3_commit_super, which will mark the superblock dirty and try to + sync it out again. If the buffer is !uptodate, then mark_buffer_dirty + will issue a warning, but continue anyway. + + This patch marks it uptodate before writing it out. This doesn't really + change anything other than silencing the warning in mark_buffer_dirty. + If the write succeeds, good. Otherwise, it will just have uptodate + cleared again. + +Signed-off-by: Jeff Mahoney +--- + fs/ext3/super.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/fs/ext3/super.c ++++ b/fs/ext3/super.c +@@ -2265,6 +2265,13 @@ static void ext3_commit_super (struct su + es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); + es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); + BUFFER_TRACE(sbh, "marking dirty"); ++ ++ /* We only read the superblock once. The in-memory version is ++ * always the most recent. If ext3_error is called after a ++ * superblock write failure, it will be !uptodate. This write ++ * will likely fail also, but it avoids the WARN_ON in ++ * mark_buffer_dirty. */ ++ set_buffer_uptodate(sbh); + mark_buffer_dirty(sbh); + if (sync) + sync_dirty_buffer(sbh); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext4-avoid-corrupting-the-uninitialized-bit-in-the-extent-during-truncate b/src/patches/suse-2.6.27.31/patches.fixes/ext4-avoid-corrupting-the-uninitialized-bit-in-the-extent-during-truncate new file mode 100644 index 000000000..c649263a4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext4-avoid-corrupting-the-uninitialized-bit-in-the-extent-during-truncate @@ -0,0 +1,47 @@ +From: Aneesh Kumar K.V +Date: Wed, 10 Jun 2009 18:22:55 +0000 (-0400) +Subject: ext4: Avoid corrupting the uninitialized bit in the extent during truncate +Patch-mainline: 2.6.31-rc1 +Git-commit: a41f20716975910d9beb90b7efc61107901492b8 +References: bnc#514265 + +ext4: Avoid corrupting the uninitialized bit in the extent during truncate + +The unitialized bit was not properly getting preserved in in an extent +which is partially truncated because the it was geting set to the +value of the first extent to be removed or truncated as part of the +truncate operation, and if there are multiple extents are getting +removed or modified as part of the truncate operation, it is only the +last extent which will might be partially truncated, and its +uninitalized bit is not necessarily the same as the first extent to be +truncated. + +Signed-off-by: Aneesh Kumar K.V +Signed-off-by: "Theodore Ts'o" +Acked-by: Jeff Mahoney +--- + + fs/ext4/extents.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -1877,12 +1877,16 @@ ext4_ext_rm_leaf(handle_t *handle, struc + ex = EXT_LAST_EXTENT(eh); + + ex_ee_block = le32_to_cpu(ex->ee_block); +- if (ext4_ext_is_uninitialized(ex)) +- uninitialized = 1; + ex_ee_len = ext4_ext_get_actual_len(ex); + + while (ex >= EXT_FIRST_EXTENT(eh) && + ex_ee_block + ex_ee_len > start) { ++ ++ if (ext4_ext_is_uninitialized(ex)) ++ uninitialized = 1; ++ else ++ uninitialized = 0; ++ + ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len); + path[depth].p_ext = ex; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext4-clear-unwritten-flag-after-extent-initialization b/src/patches/suse-2.6.27.31/patches.fixes/ext4-clear-unwritten-flag-after-extent-initialization new file mode 100644 index 000000000..3c0bcb2c0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext4-clear-unwritten-flag-after-extent-initialization @@ -0,0 +1,59 @@ +From: Aneesh Kumar K.V +Date: Thu, 14 May 2009 21:05:39 +0000 (-0400) +Subject: ext4: Clear the unwritten buffer_head flag after the extent is initialized +Patch-mainline: 2.6.30-rc6 +Git-commit: 2a8964d63d50dd2d65d71d342bc7fb6ef4117614 +References: bnc#503161 + +ext4: Clear the unwritten buffer_head flag after the extent is initialized + +The BH_Unwritten flag indicates that the buffer is allocated on disk +but has not been written; that is, the disk was part of a persistent +preallocation area. That flag should only be set when a get_blocks() +function is looking up a inode's logical to physical block mapping. + +When ext4_get_blocks_wrap() is called with create=1, the uninitialized +extent is converted into an initialized one, so the BH_Unwritten flag +is no longer appropriate. Hence, we need to make sure the +BH_Unwritten is not left set, since the combination of BH_Mapped and +BH_Unwritten is not allowed; among other things, it will result ext4's +get_block() to be called over and over again during the write_begin +phase of write(2). + +Signed-off-by: Aneesh Kumar K.V +Signed-off-by: "Theodore Ts'o" +Acked-by: Jeff Mahoney +--- + + fs/ext4/inode.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1058,6 +1058,7 @@ int ext4_get_blocks_wrap(handle_t *handl + int retval; + + clear_buffer_mapped(bh); ++ clear_buffer_unwritten(bh); + + /* + * Try to see if we can get the block without requesting +@@ -1088,6 +1089,18 @@ int ext4_get_blocks_wrap(handle_t *handl + return retval; + + /* ++ * When we call get_blocks without the create flag, the ++ * BH_Unwritten flag could have gotten set if the blocks ++ * requested were part of a uninitialized extent. We need to ++ * clear this flag now that we are committed to convert all or ++ * part of the uninitialized extent to be an initialized ++ * extent. This is because we need to avoid the combination ++ * of BH_Unwritten and BH_Mapped flags being simultaneously ++ * set on the buffer_head. ++ */ ++ clear_buffer_unwritten(bh); ++ ++ /* + * New blocks allocate and/or writing to uninitialized extent + * will possibly result in updating i_data, so we take + * the write lock of i_data_sem, and call get_blocks() diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext4-fix-sub-block-zeroing-for-preallocated-writes b/src/patches/suse-2.6.27.31/patches.fixes/ext4-fix-sub-block-zeroing-for-preallocated-writes new file mode 100644 index 000000000..e777a4525 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext4-fix-sub-block-zeroing-for-preallocated-writes @@ -0,0 +1,54 @@ +From: Aneesh Kumar K.V +Date: Wed, 13 May 2009 22:36:58 +0000 (-0400) +Subject: ext4: Fix sub-block zeroing for writes into preallocated extents +Patch-mainline: 2.6.30 +Git-commit: 9c1ee184a30394e54165fa4c15923cabd952c106 +References: bnc#503161 + +ext4: Fix sub-block zeroing for writes into preallocated extents + +We need to mark the buffer_head mapping preallocated space as new +during write_begin. Otherwise we don't zero out the page cache content +properly for a partial write. This will cause file corruption with +preallocation. + +Now that we mark the buffer_head new we also need to have a valid +buffer_head blocknr so that unmap_underlying_metadata() unmaps the +correct block. + +Signed-off-by: Aneesh Kumar K.V +Signed-off-by: "Theodore Ts'o" +Acked-by: Jeff Mahoney +--- + + fs/ext4/extents.c | 2 ++ + fs/ext4/inode.c | 7 +++++++ + 2 files changed, 9 insertions(+) + +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -2664,6 +2664,8 @@ int ext4_ext_get_blocks(handle_t *handle + if (allocated > max_blocks) + allocated = max_blocks; + set_buffer_unwritten(bh_result); ++ bh_result->b_bdev = inode->i_sb->s_bdev; ++ bh_result->b_blocknr = newblock; + goto out2; + } + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2220,6 +2220,13 @@ static int ext4_da_get_block_prep(struct + set_buffer_delay(bh_result); + } else if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); ++ /* ++ * With sub-block writes into unwritten extents ++ * we also need to mark the buffer as new so that ++ * the unwritten parts of the buffer gets correctly zeroed. ++ */ ++ if (buffer_unwritten(bh_result)) ++ set_buffer_new(bh_result); + ret = 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext4-fixes-2.6.28-rc8.patch b/src/patches/suse-2.6.27.31/patches.fixes/ext4-fixes-2.6.28-rc8.patch new file mode 100644 index 000000000..eb0e3c694 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext4-fixes-2.6.28-rc8.patch @@ -0,0 +1,10138 @@ +From: Mingming Cao +Subject: Ext4 update +References: fate#303783 + +Bring ext4 codebase to the state of 2.6.28-rc8. It has lots of bugfixes, some +of them really important ones (data corruption, easily triggerable kernel +oopses with delayed allocation, ...). + +Signed-off-by: Jan Kara + +diff -rup b/fs/ext4//acl.h a/fs/ext4///acl.h +--- b/fs/ext4/acl.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/acl.h 2009-02-10 21:40:14.000000000 +0100 +@@ -51,18 +51,18 @@ static inline int ext4_acl_count(size_t + } + } + +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + + /* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl + if the ACL has not been cached */ + #define EXT4_ACL_NOT_CACHED ((void *)-1) + + /* acl.c */ +-extern int ext4_permission (struct inode *, int); +-extern int ext4_acl_chmod (struct inode *); +-extern int ext4_init_acl (handle_t *, struct inode *, struct inode *); ++extern int ext4_permission(struct inode *, int); ++extern int ext4_acl_chmod(struct inode *); ++extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); + +-#else /* CONFIG_EXT4DEV_FS_POSIX_ACL */ ++#else /* CONFIG_EXT4_FS_POSIX_ACL */ + #include + #define ext4_permission NULL + +@@ -77,5 +77,5 @@ ext4_init_acl(handle_t *handle, struct i + { + return 0; + } +-#endif /* CONFIG_EXT4DEV_FS_POSIX_ACL */ ++#endif /* CONFIG_EXT4_FS_POSIX_ACL */ + +diff -rup b/fs/ext4//balloc.c a/fs/ext4///balloc.c +--- b/fs/ext4/balloc.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/balloc.c 2009-02-10 21:40:11.000000000 +0100 +@@ -20,6 +20,7 @@ + #include "ext4.h" + #include "ext4_jbd2.h" + #include "group.h" ++#include "mballoc.h" + + /* + * balloc.c contains the blocks allocation and deallocation routines +@@ -83,6 +84,7 @@ static int ext4_group_used_meta_blocks(s + } + return used_blocks; + } ++ + /* Initializes an uninitialized block bitmap if given, and returns the + * number of blocks free in the group. */ + unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, +@@ -99,10 +101,10 @@ unsigned ext4_init_block_bitmap(struct s + * essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { + ext4_error(sb, __func__, +- "Checksum bad for group %lu\n", block_group); +- gdp->bg_free_blocks_count = 0; +- gdp->bg_free_inodes_count = 0; +- gdp->bg_itable_unused = 0; ++ "Checksum bad for group %u\n", block_group); ++ ext4_free_blks_set(sb, gdp, 0); ++ ext4_free_inodes_set(sb, gdp, 0); ++ ext4_itable_unused_set(sb, gdp, 0); + memset(bh->b_data, 0xff, sb->s_blocksize); + return 0; + } +@@ -132,7 +134,7 @@ unsigned ext4_init_block_bitmap(struct s + */ + group_blocks = ext4_blocks_count(sbi->s_es) - + le32_to_cpu(sbi->s_es->s_first_data_block) - +- (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1)); ++ (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1)); + } else { + group_blocks = EXT4_BLOCKS_PER_GROUP(sb); + } +@@ -200,20 +202,20 @@ unsigned ext4_init_block_bitmap(struct s + * @bh: pointer to the buffer head to store the block + * group descriptor + */ +-struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, ++struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, + ext4_group_t block_group, +- struct buffer_head ** bh) ++ struct buffer_head **bh) + { +- unsigned long group_desc; +- unsigned long offset; +- struct ext4_group_desc * desc; ++ unsigned int group_desc; ++ unsigned int offset; ++ struct ext4_group_desc *desc; + struct ext4_sb_info *sbi = EXT4_SB(sb); + + if (block_group >= sbi->s_groups_count) { +- ext4_error (sb, "ext4_get_group_desc", +- "block_group >= groups_count - " +- "block_group = %lu, groups_count = %lu", +- block_group, sbi->s_groups_count); ++ ext4_error(sb, "ext4_get_group_desc", ++ "block_group >= groups_count - " ++ "block_group = %u, groups_count = %u", ++ block_group, sbi->s_groups_count); + + return NULL; + } +@@ -222,10 +224,10 @@ struct ext4_group_desc * ext4_get_group_ + group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); + offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); + if (!sbi->s_group_desc[group_desc]) { +- ext4_error (sb, "ext4_get_group_desc", +- "Group descriptor not loaded - " +- "block_group = %lu, group_desc = %lu, desc = %lu", +- block_group, group_desc, offset); ++ ext4_error(sb, "ext4_get_group_desc", ++ "Group descriptor not loaded - " ++ "block_group = %u, group_desc = %u, desc = %u", ++ block_group, group_desc, offset); + return NULL; + } + +@@ -302,8 +304,8 @@ err_out: + struct buffer_head * + ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group) + { +- struct ext4_group_desc * desc; +- struct buffer_head * bh = NULL; ++ struct ext4_group_desc *desc; ++ struct buffer_head *bh = NULL; + ext4_fsblk_t bitmap_blk; + + desc = ext4_get_group_desc(sb, block_group, NULL); +@@ -314,27 +316,50 @@ ext4_read_block_bitmap(struct super_bloc + if (unlikely(!bh)) { + ext4_error(sb, __func__, + "Cannot read block bitmap - " +- "block_group = %lu, block_bitmap = %llu", ++ "block_group = %u, block_bitmap = %llu", + block_group, bitmap_blk); + return NULL; + } +- if (bh_uptodate_or_lock(bh)) ++ ++ if (bitmap_uptodate(bh)) + return bh; + ++ lock_buffer(bh); ++ if (bitmap_uptodate(bh)) { ++ unlock_buffer(bh); ++ return bh; ++ } + spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + ext4_init_block_bitmap(sb, bh, block_group, desc); ++ set_bitmap_uptodate(bh); + set_buffer_uptodate(bh); +- unlock_buffer(bh); + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); ++ unlock_buffer(bh); + return bh; + } + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); ++ if (buffer_uptodate(bh)) { ++ /* ++ * if not uninit if bh is uptodate, ++ * bitmap is also uptodate ++ */ ++ set_bitmap_uptodate(bh); ++ unlock_buffer(bh); ++ return bh; ++ } ++ /* ++ * submit the buffer_head for read. We can ++ * safely mark the bitmap as uptodate now. ++ * We do it here so the bitmap uptodate bit ++ * get set with buffer lock held. ++ */ ++ set_bitmap_uptodate(bh); + if (bh_submit_read(bh) < 0) { + put_bh(bh); + ext4_error(sb, __func__, + "Cannot read block bitmap - " +- "block_group = %lu, block_bitmap = %llu", ++ "block_group = %u, block_bitmap = %llu", + block_group, bitmap_blk); + return NULL; + } +@@ -345,356 +370,50 @@ ext4_read_block_bitmap(struct super_bloc + */ + return bh; + } +-/* +- * The reservation window structure operations +- * -------------------------------------------- +- * Operations include: +- * dump, find, add, remove, is_empty, find_next_reservable_window, etc. +- * +- * We use a red-black tree to represent per-filesystem reservation +- * windows. +- * +- */ +- +-/** +- * __rsv_window_dump() -- Dump the filesystem block allocation reservation map +- * @rb_root: root of per-filesystem reservation rb tree +- * @verbose: verbose mode +- * @fn: function which wishes to dump the reservation map +- * +- * If verbose is turned on, it will print the whole block reservation +- * windows(start, end). Otherwise, it will only print out the "bad" windows, +- * those windows that overlap with their immediate neighbors. +- */ +-#if 1 +-static void __rsv_window_dump(struct rb_root *root, int verbose, +- const char *fn) +-{ +- struct rb_node *n; +- struct ext4_reserve_window_node *rsv, *prev; +- int bad; +- +-restart: +- n = rb_first(root); +- bad = 0; +- prev = NULL; +- +- printk("Block Allocation Reservation Windows Map (%s):\n", fn); +- while (n) { +- rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node); +- if (verbose) +- printk("reservation window 0x%p " +- "start: %llu, end: %llu\n", +- rsv, rsv->rsv_start, rsv->rsv_end); +- if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { +- printk("Bad reservation %p (start >= end)\n", +- rsv); +- bad = 1; +- } +- if (prev && prev->rsv_end >= rsv->rsv_start) { +- printk("Bad reservation %p (prev->end >= start)\n", +- rsv); +- bad = 1; +- } +- if (bad) { +- if (!verbose) { +- printk("Restarting reservation walk in verbose mode\n"); +- verbose = 1; +- goto restart; +- } +- } +- n = rb_next(n); +- prev = rsv; +- } +- printk("Window map complete.\n"); +- BUG_ON(bad); +-} +-#define rsv_window_dump(root, verbose) \ +- __rsv_window_dump((root), (verbose), __func__) +-#else +-#define rsv_window_dump(root, verbose) do {} while (0) +-#endif +- +-/** +- * goal_in_my_reservation() +- * @rsv: inode's reservation window +- * @grp_goal: given goal block relative to the allocation block group +- * @group: the current allocation block group +- * @sb: filesystem super block +- * +- * Test if the given goal block (group relative) is within the file's +- * own block reservation window range. +- * +- * If the reservation window is outside the goal allocation group, return 0; +- * grp_goal (given goal block) could be -1, which means no specific +- * goal block. In this case, always return 1. +- * If the goal block is within the reservation window, return 1; +- * otherwise, return 0; +- */ +-static int +-goal_in_my_reservation(struct ext4_reserve_window *rsv, ext4_grpblk_t grp_goal, +- ext4_group_t group, struct super_block *sb) +-{ +- ext4_fsblk_t group_first_block, group_last_block; +- +- group_first_block = ext4_group_first_block_no(sb, group); +- group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); +- +- if ((rsv->_rsv_start > group_last_block) || +- (rsv->_rsv_end < group_first_block)) +- return 0; +- if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start) +- || (grp_goal + group_first_block > rsv->_rsv_end))) +- return 0; +- return 1; +-} + + /** +- * search_reserve_window() +- * @rb_root: root of reservation tree +- * @goal: target allocation block +- * +- * Find the reserved window which includes the goal, or the previous one +- * if the goal is not in any window. +- * Returns NULL if there are no windows or if all windows start after the goal. +- */ +-static struct ext4_reserve_window_node * +-search_reserve_window(struct rb_root *root, ext4_fsblk_t goal) +-{ +- struct rb_node *n = root->rb_node; +- struct ext4_reserve_window_node *rsv; +- +- if (!n) +- return NULL; +- +- do { +- rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node); +- +- if (goal < rsv->rsv_start) +- n = n->rb_left; +- else if (goal > rsv->rsv_end) +- n = n->rb_right; +- else +- return rsv; +- } while (n); +- /* +- * We've fallen off the end of the tree: the goal wasn't inside +- * any particular node. OK, the previous node must be to one +- * side of the interval containing the goal. If it's the RHS, +- * we need to back up one. +- */ +- if (rsv->rsv_start > goal) { +- n = rb_prev(&rsv->rsv_node); +- rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node); +- } +- return rsv; +-} +- +-/** +- * ext4_rsv_window_add() -- Insert a window to the block reservation rb tree. +- * @sb: super block +- * @rsv: reservation window to add +- * +- * Must be called with rsv_lock hold. +- */ +-void ext4_rsv_window_add(struct super_block *sb, +- struct ext4_reserve_window_node *rsv) +-{ +- struct rb_root *root = &EXT4_SB(sb)->s_rsv_window_root; +- struct rb_node *node = &rsv->rsv_node; +- ext4_fsblk_t start = rsv->rsv_start; +- +- struct rb_node ** p = &root->rb_node; +- struct rb_node * parent = NULL; +- struct ext4_reserve_window_node *this; +- +- while (*p) +- { +- parent = *p; +- this = rb_entry(parent, struct ext4_reserve_window_node, rsv_node); +- +- if (start < this->rsv_start) +- p = &(*p)->rb_left; +- else if (start > this->rsv_end) +- p = &(*p)->rb_right; +- else { +- rsv_window_dump(root, 1); +- BUG(); +- } +- } +- +- rb_link_node(node, parent, p); +- rb_insert_color(node, root); +-} +- +-/** +- * ext4_rsv_window_remove() -- unlink a window from the reservation rb tree +- * @sb: super block +- * @rsv: reservation window to remove +- * +- * Mark the block reservation window as not allocated, and unlink it +- * from the filesystem reservation window rb tree. Must be called with +- * rsv_lock hold. +- */ +-static void rsv_window_remove(struct super_block *sb, +- struct ext4_reserve_window_node *rsv) +-{ +- rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +- rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +- rsv->rsv_alloc_hit = 0; +- rb_erase(&rsv->rsv_node, &EXT4_SB(sb)->s_rsv_window_root); +-} +- +-/* +- * rsv_is_empty() -- Check if the reservation window is allocated. +- * @rsv: given reservation window to check +- * +- * returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED. +- */ +-static inline int rsv_is_empty(struct ext4_reserve_window *rsv) +-{ +- /* a valid reservation end block could not be 0 */ +- return rsv->_rsv_end == EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +-} +- +-/** +- * ext4_init_block_alloc_info() +- * @inode: file inode structure +- * +- * Allocate and initialize the reservation window structure, and +- * link the window to the ext4 inode structure at last +- * +- * The reservation window structure is only dynamically allocated +- * and linked to ext4 inode the first time the open file +- * needs a new block. So, before every ext4_new_block(s) call, for +- * regular files, we should check whether the reservation window +- * structure exists or not. In the latter case, this function is called. +- * Fail to do so will result in block reservation being turned off for that +- * open file. +- * +- * This function is called from ext4_get_blocks_handle(), also called +- * when setting the reservation window size through ioctl before the file +- * is open for write (needs block allocation). +- * +- * Needs down_write(i_data_sem) protection prior to call this function. +- */ +-void ext4_init_block_alloc_info(struct inode *inode) +-{ +- struct ext4_inode_info *ei = EXT4_I(inode); +- struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info; +- struct super_block *sb = inode->i_sb; +- +- block_i = kmalloc(sizeof(*block_i), GFP_NOFS); +- if (block_i) { +- struct ext4_reserve_window_node *rsv = &block_i->rsv_window_node; +- +- rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +- rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +- +- /* +- * if filesystem is mounted with NORESERVATION, the goal +- * reservation window size is set to zero to indicate +- * block reservation is off +- */ +- if (!test_opt(sb, RESERVATION)) +- rsv->rsv_goal_size = 0; +- else +- rsv->rsv_goal_size = EXT4_DEFAULT_RESERVE_BLOCKS; +- rsv->rsv_alloc_hit = 0; +- block_i->last_alloc_logical_block = 0; +- block_i->last_alloc_physical_block = 0; +- } +- ei->i_block_alloc_info = block_i; +-} +- +-/** +- * ext4_discard_reservation() +- * @inode: inode +- * +- * Discard(free) block reservation window on last file close, or truncate +- * or at last iput(). +- * +- * It is being called in three cases: +- * ext4_release_file(): last writer close the file +- * ext4_clear_inode(): last iput(), when nobody link to this file. +- * ext4_truncate(): when the block indirect map is about to change. +- * +- */ +-void ext4_discard_reservation(struct inode *inode) +-{ +- struct ext4_inode_info *ei = EXT4_I(inode); +- struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info; +- struct ext4_reserve_window_node *rsv; +- spinlock_t *rsv_lock = &EXT4_SB(inode->i_sb)->s_rsv_window_lock; +- +- ext4_mb_discard_inode_preallocations(inode); +- +- if (!block_i) +- return; +- +- rsv = &block_i->rsv_window_node; +- if (!rsv_is_empty(&rsv->rsv_window)) { +- spin_lock(rsv_lock); +- if (!rsv_is_empty(&rsv->rsv_window)) +- rsv_window_remove(inode->i_sb, rsv); +- spin_unlock(rsv_lock); +- } +-} +- +-/** +- * ext4_free_blocks_sb() -- Free given blocks and update quota ++ * ext4_add_groupblocks() -- Add given blocks to an existing group + * @handle: handle to this transaction + * @sb: super block +- * @block: start physcial block to free ++ * @block: start physcial block to add to the block group + * @count: number of blocks to free +- * @pdquot_freed_blocks: pointer to quota ++ * ++ * This marks the blocks as free in the bitmap. We ask the ++ * mballoc to reload the buddy after this by setting group ++ * EXT4_GROUP_INFO_NEED_INIT_BIT flag + */ +-void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, +- ext4_fsblk_t block, unsigned long count, +- unsigned long *pdquot_freed_blocks) ++void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, ++ ext4_fsblk_t block, unsigned long count) + { + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *gd_bh; + ext4_group_t block_group; + ext4_grpblk_t bit; +- unsigned long i; +- unsigned long overflow; +- struct ext4_group_desc * desc; +- struct ext4_super_block * es; ++ unsigned int i; ++ struct ext4_group_desc *desc; ++ struct ext4_super_block *es; + struct ext4_sb_info *sbi; +- int err = 0, ret; +- ext4_grpblk_t group_freed; ++ int err = 0, ret, blk_free_count; ++ ext4_grpblk_t blocks_freed; ++ struct ext4_group_info *grp; + +- *pdquot_freed_blocks = 0; + sbi = EXT4_SB(sb); + es = sbi->s_es; +- if (block < le32_to_cpu(es->s_first_data_block) || +- block + count < block || +- block + count > ext4_blocks_count(es)) { +- ext4_error (sb, "ext4_free_blocks", +- "Freeing blocks not in datazone - " +- "block = %llu, count = %lu", block, count); +- goto error_return; +- } +- +- ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1); ++ ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1); + +-do_more: +- overflow = 0; + ext4_get_group_no_and_offset(sb, block, &block_group, &bit); ++ grp = ext4_get_group_info(sb, block_group); + /* + * Check to see if we are freeing blocks across a group + * boundary. + */ + if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) { +- overflow = bit + count - EXT4_BLOCKS_PER_GROUP(sb); +- count -= overflow; ++ goto error_return; + } +- brelse(bitmap_bh); + bitmap_bh = ext4_read_block_bitmap(sb, block_group); + if (!bitmap_bh) + goto error_return; +- desc = ext4_get_group_desc (sb, block_group, &gd_bh); ++ desc = ext4_get_group_desc(sb, block_group, &gd_bh); + if (!desc) + goto error_return; + +@@ -703,18 +422,17 @@ do_more: + in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) || + in_range(block + count - 1, ext4_inode_table(sb, desc), + sbi->s_itb_per_group)) { +- ext4_error (sb, "ext4_free_blocks", +- "Freeing blocks in system zones - " +- "Block = %llu, count = %lu", +- block, count); ++ ext4_error(sb, __func__, ++ "Adding blocks in system zones - " ++ "Block = %llu, count = %lu", ++ block, count); + goto error_return; + } + + /* +- * We are about to start releasing blocks in the bitmap, ++ * We are about to add blocks to the bitmap, + * so we need undo access. + */ +- /* @@@ check errors */ + BUFFER_TRACE(bitmap_bh, "getting undo access"); + err = ext4_journal_get_undo_access(handle, bitmap_bh); + if (err) +@@ -729,90 +447,43 @@ do_more: + err = ext4_journal_get_write_access(handle, gd_bh); + if (err) + goto error_return; +- +- jbd_lock_bh_state(bitmap_bh); +- +- for (i = 0, group_freed = 0; i < count; i++) { +- /* +- * An HJ special. This is expensive... +- */ +-#ifdef CONFIG_JBD2_DEBUG +- jbd_unlock_bh_state(bitmap_bh); +- { +- struct buffer_head *debug_bh; +- debug_bh = sb_find_get_block(sb, block + i); +- if (debug_bh) { +- BUFFER_TRACE(debug_bh, "Deleted!"); +- if (!bh2jh(bitmap_bh)->b_committed_data) +- BUFFER_TRACE(debug_bh, +- "No commited data in bitmap"); +- BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap"); +- __brelse(debug_bh); +- } +- } +- jbd_lock_bh_state(bitmap_bh); +-#endif +- if (need_resched()) { +- jbd_unlock_bh_state(bitmap_bh); +- cond_resched(); +- jbd_lock_bh_state(bitmap_bh); +- } +- /* @@@ This prevents newly-allocated data from being +- * freed and then reallocated within the same +- * transaction. +- * +- * Ideally we would want to allow that to happen, but to +- * do so requires making jbd2_journal_forget() capable of +- * revoking the queued write of a data block, which +- * implies blocking on the journal lock. *forget() +- * cannot block due to truncate races. +- * +- * Eventually we can fix this by making jbd2_journal_forget() +- * return a status indicating whether or not it was able +- * to revoke the buffer. On successful revoke, it is +- * safe not to set the allocation bit in the committed +- * bitmap, because we know that there is no outstanding +- * activity on the buffer any more and so it is safe to +- * reallocate it. +- */ +- BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); +- J_ASSERT_BH(bitmap_bh, +- bh2jh(bitmap_bh)->b_committed_data != NULL); +- ext4_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, +- bh2jh(bitmap_bh)->b_committed_data); +- +- /* +- * We clear the bit in the bitmap after setting the committed +- * data bit, because this is the reverse order to that which +- * the allocator uses. +- */ ++ /* ++ * make sure we don't allow a parallel init on other groups in the ++ * same buddy cache ++ */ ++ down_write(&grp->alloc_sem); ++ for (i = 0, blocks_freed = 0; i < count; i++) { + BUFFER_TRACE(bitmap_bh, "clear bit"); + if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit + i, bitmap_bh->b_data)) { +- jbd_unlock_bh_state(bitmap_bh); + ext4_error(sb, __func__, + "bit already cleared for block %llu", + (ext4_fsblk_t)(block + i)); +- jbd_lock_bh_state(bitmap_bh); + BUFFER_TRACE(bitmap_bh, "bit already cleared"); + } else { +- group_freed++; ++ blocks_freed++; + } + } +- jbd_unlock_bh_state(bitmap_bh); +- + spin_lock(sb_bgl_lock(sbi, block_group)); +- le16_add_cpu(&desc->bg_free_blocks_count, group_freed); ++ blk_free_count = blocks_freed + ext4_free_blks_count(sb, desc); ++ ext4_free_blks_set(sb, desc, blk_free_count); + desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); + spin_unlock(sb_bgl_lock(sbi, block_group)); +- percpu_counter_add(&sbi->s_freeblocks_counter, count); ++ percpu_counter_add(&sbi->s_freeblocks_counter, blocks_freed); + + if (sbi->s_log_groups_per_flex) { + ext4_group_t flex_group = ext4_flex_group(sbi, block_group); + spin_lock(sb_bgl_lock(sbi, flex_group)); +- sbi->s_flex_groups[flex_group].free_blocks += count; ++ sbi->s_flex_groups[flex_group].free_blocks += blocks_freed; + spin_unlock(sb_bgl_lock(sbi, flex_group)); + } ++ /* ++ * request to reload the buddy with the ++ * new bitmap information ++ */ ++ set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state)); ++ ext4_mb_update_group_info(grp, blocks_freed); ++ up_write(&grp->alloc_sem); + + /* We dirtied the bitmap block */ + BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); +@@ -821,15 +492,10 @@ do_more: + /* And the group descriptor block */ + BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); + ret = ext4_journal_dirty_metadata(handle, gd_bh); +- if (!err) err = ret; +- *pdquot_freed_blocks += group_freed; +- +- if (overflow && !err) { +- block += count; +- count = overflow; +- goto do_more; +- } ++ if (!err) ++ err = ret; + sb->s_dirt = 1; ++ + error_return: + brelse(bitmap_bh); + ext4_std_error(sb, err); +@@ -848,792 +514,86 @@ void ext4_free_blocks(handle_t *handle, + ext4_fsblk_t block, unsigned long count, + int metadata) + { +- struct super_block * sb; ++ struct super_block *sb; + unsigned long dquot_freed_blocks; + + /* this isn't the right place to decide whether block is metadata + * inode.c/extents.c knows better, but for safety ... */ +- if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) || +- ext4_should_journal_data(inode)) ++ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) ++ metadata = 1; ++ ++ /* We need to make sure we don't reuse ++ * block released untill the transaction commit. ++ * writeback mode have weak data consistency so ++ * don't force data as metadata when freeing block ++ * for writeback mode. ++ */ ++ if (metadata == 0 && !ext4_should_writeback_data(inode)) + metadata = 1; + + sb = inode->i_sb; + +- if (!test_opt(sb, MBALLOC) || !EXT4_SB(sb)->s_group_info) +- ext4_free_blocks_sb(handle, sb, block, count, +- &dquot_freed_blocks); +- else +- ext4_mb_free_blocks(handle, inode, block, count, +- metadata, &dquot_freed_blocks); ++ ext4_mb_free_blocks(handle, inode, block, count, ++ metadata, &dquot_freed_blocks); + if (dquot_freed_blocks) + DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + return; + } + + /** +- * ext4_test_allocatable() +- * @nr: given allocation block group +- * @bh: bufferhead contains the bitmap of the given block group +- * +- * For ext4 allocations, we must not reuse any blocks which are +- * allocated in the bitmap buffer's "last committed data" copy. This +- * prevents deletes from freeing up the page for reuse until we have +- * committed the delete transaction. +- * +- * If we didn't do this, then deleting something and reallocating it as +- * data would allow the old block to be overwritten before the +- * transaction committed (because we force data to disk before commit). +- * This would lead to corruption if we crashed between overwriting the +- * data and committing the delete. +- * +- * @@@ We may want to make this allocation behaviour conditional on +- * data-writes at some point, and disable it for metadata allocations or +- * sync-data inodes. +- */ +-static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh) +-{ +- int ret; +- struct journal_head *jh = bh2jh(bh); +- +- if (ext4_test_bit(nr, bh->b_data)) +- return 0; +- +- jbd_lock_bh_state(bh); +- if (!jh->b_committed_data) +- ret = 1; +- else +- ret = !ext4_test_bit(nr, jh->b_committed_data); +- jbd_unlock_bh_state(bh); +- return ret; +-} +- +-/** +- * bitmap_search_next_usable_block() +- * @start: the starting block (group relative) of the search +- * @bh: bufferhead contains the block group bitmap +- * @maxblocks: the ending block (group relative) of the reservation +- * +- * The bitmap search --- search forward alternately through the actual +- * bitmap on disk and the last-committed copy in journal, until we find a +- * bit free in both bitmaps. +- */ +-static ext4_grpblk_t +-bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh, +- ext4_grpblk_t maxblocks) +-{ +- ext4_grpblk_t next; +- struct journal_head *jh = bh2jh(bh); +- +- while (start < maxblocks) { +- next = ext4_find_next_zero_bit(bh->b_data, maxblocks, start); +- if (next >= maxblocks) +- return -1; +- if (ext4_test_allocatable(next, bh)) +- return next; +- jbd_lock_bh_state(bh); +- if (jh->b_committed_data) +- start = ext4_find_next_zero_bit(jh->b_committed_data, +- maxblocks, next); +- jbd_unlock_bh_state(bh); +- } +- return -1; +-} +- +-/** +- * find_next_usable_block() +- * @start: the starting block (group relative) to find next +- * allocatable block in bitmap. +- * @bh: bufferhead contains the block group bitmap +- * @maxblocks: the ending block (group relative) for the search +- * +- * Find an allocatable block in a bitmap. We honor both the bitmap and +- * its last-committed copy (if that exists), and perform the "most +- * appropriate allocation" algorithm of looking for a free block near +- * the initial goal; then for a free byte somewhere in the bitmap; then +- * for any free bit in the bitmap. +- */ +-static ext4_grpblk_t +-find_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh, +- ext4_grpblk_t maxblocks) +-{ +- ext4_grpblk_t here, next; +- char *p, *r; +- +- if (start > 0) { +- /* +- * The goal was occupied; search forward for a free +- * block within the next XX blocks. +- * +- * end_goal is more or less random, but it has to be +- * less than EXT4_BLOCKS_PER_GROUP. Aligning up to the +- * next 64-bit boundary is simple.. +- */ +- ext4_grpblk_t end_goal = (start + 63) & ~63; +- if (end_goal > maxblocks) +- end_goal = maxblocks; +- here = ext4_find_next_zero_bit(bh->b_data, end_goal, start); +- if (here < end_goal && ext4_test_allocatable(here, bh)) +- return here; +- ext4_debug("Bit not found near goal\n"); +- } +- +- here = start; +- if (here < 0) +- here = 0; +- +- p = ((char *)bh->b_data) + (here >> 3); +- r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3)); +- next = (r - ((char *)bh->b_data)) << 3; +- +- if (next < maxblocks && next >= start && ext4_test_allocatable(next, bh)) +- return next; +- +- /* +- * The bitmap search --- search forward alternately through the actual +- * bitmap and the last-committed copy until we find a bit free in +- * both +- */ +- here = bitmap_search_next_usable_block(here, bh, maxblocks); +- return here; +-} +- +-/** +- * claim_block() +- * @block: the free block (group relative) to allocate +- * @bh: the bufferhead containts the block group bitmap +- * +- * We think we can allocate this block in this bitmap. Try to set the bit. +- * If that succeeds then check that nobody has allocated and then freed the +- * block since we saw that is was not marked in b_committed_data. If it _was_ +- * allocated and freed then clear the bit in the bitmap again and return +- * zero (failure). +- */ +-static inline int +-claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh) +-{ +- struct journal_head *jh = bh2jh(bh); +- int ret; +- +- if (ext4_set_bit_atomic(lock, block, bh->b_data)) +- return 0; +- jbd_lock_bh_state(bh); +- if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) { +- ext4_clear_bit_atomic(lock, block, bh->b_data); +- ret = 0; +- } else { +- ret = 1; +- } +- jbd_unlock_bh_state(bh); +- return ret; +-} +- +-/** +- * ext4_try_to_allocate() +- * @sb: superblock +- * @handle: handle to this transaction +- * @group: given allocation block group +- * @bitmap_bh: bufferhead holds the block bitmap +- * @grp_goal: given target block within the group +- * @count: target number of blocks to allocate +- * @my_rsv: reservation window +- * +- * Attempt to allocate blocks within a give range. Set the range of allocation +- * first, then find the first free bit(s) from the bitmap (within the range), +- * and at last, allocate the blocks by claiming the found free bit as allocated. +- * +- * To set the range of this allocation: +- * if there is a reservation window, only try to allocate block(s) from the +- * file's own reservation window; +- * Otherwise, the allocation range starts from the give goal block, ends at +- * the block group's last block. +- * +- * If we failed to allocate the desired block then we may end up crossing to a +- * new bitmap. In that case we must release write access to the old one via +- * ext4_journal_release_buffer(), else we'll run out of credits. +- */ +-static ext4_grpblk_t +-ext4_try_to_allocate(struct super_block *sb, handle_t *handle, +- ext4_group_t group, struct buffer_head *bitmap_bh, +- ext4_grpblk_t grp_goal, unsigned long *count, +- struct ext4_reserve_window *my_rsv) +-{ +- ext4_fsblk_t group_first_block; +- ext4_grpblk_t start, end; +- unsigned long num = 0; +- +- /* we do allocation within the reservation window if we have a window */ +- if (my_rsv) { +- group_first_block = ext4_group_first_block_no(sb, group); +- if (my_rsv->_rsv_start >= group_first_block) +- start = my_rsv->_rsv_start - group_first_block; +- else +- /* reservation window cross group boundary */ +- start = 0; +- end = my_rsv->_rsv_end - group_first_block + 1; +- if (end > EXT4_BLOCKS_PER_GROUP(sb)) +- /* reservation window crosses group boundary */ +- end = EXT4_BLOCKS_PER_GROUP(sb); +- if ((start <= grp_goal) && (grp_goal < end)) +- start = grp_goal; +- else +- grp_goal = -1; +- } else { +- if (grp_goal > 0) +- start = grp_goal; +- else +- start = 0; +- end = EXT4_BLOCKS_PER_GROUP(sb); +- } +- +- BUG_ON(start > EXT4_BLOCKS_PER_GROUP(sb)); +- +-repeat: +- if (grp_goal < 0 || !ext4_test_allocatable(grp_goal, bitmap_bh)) { +- grp_goal = find_next_usable_block(start, bitmap_bh, end); +- if (grp_goal < 0) +- goto fail_access; +- if (!my_rsv) { +- int i; +- +- for (i = 0; i < 7 && grp_goal > start && +- ext4_test_allocatable(grp_goal - 1, +- bitmap_bh); +- i++, grp_goal--) +- ; +- } +- } +- start = grp_goal; +- +- if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group), +- grp_goal, bitmap_bh)) { +- /* +- * The block was allocated by another thread, or it was +- * allocated and then freed by another thread +- */ +- start++; +- grp_goal++; +- if (start >= end) +- goto fail_access; +- goto repeat; +- } +- num++; +- grp_goal++; +- while (num < *count && grp_goal < end +- && ext4_test_allocatable(grp_goal, bitmap_bh) +- && claim_block(sb_bgl_lock(EXT4_SB(sb), group), +- grp_goal, bitmap_bh)) { +- num++; +- grp_goal++; +- } +- *count = num; +- return grp_goal - num; +-fail_access: +- *count = num; +- return -1; +-} +- +-/** +- * find_next_reservable_window(): +- * find a reservable space within the given range. +- * It does not allocate the reservation window for now: +- * alloc_new_reservation() will do the work later. +- * +- * @search_head: the head of the searching list; +- * This is not necessarily the list head of the whole filesystem +- * +- * We have both head and start_block to assist the search +- * for the reservable space. The list starts from head, +- * but we will shift to the place where start_block is, +- * then start from there, when looking for a reservable space. +- * +- * @size: the target new reservation window size +- * +- * @group_first_block: the first block we consider to start +- * the real search from +- * +- * @last_block: +- * the maximum block number that our goal reservable space +- * could start from. This is normally the last block in this +- * group. The search will end when we found the start of next +- * possible reservable space is out of this boundary. +- * This could handle the cross boundary reservation window +- * request. +- * +- * basically we search from the given range, rather than the whole +- * reservation double linked list, (start_block, last_block) +- * to find a free region that is of my size and has not +- * been reserved. +- * +- */ +-static int find_next_reservable_window( +- struct ext4_reserve_window_node *search_head, +- struct ext4_reserve_window_node *my_rsv, +- struct super_block * sb, +- ext4_fsblk_t start_block, +- ext4_fsblk_t last_block) +-{ +- struct rb_node *next; +- struct ext4_reserve_window_node *rsv, *prev; +- ext4_fsblk_t cur; +- int size = my_rsv->rsv_goal_size; +- +- /* TODO: make the start of the reservation window byte-aligned */ +- /* cur = *start_block & ~7;*/ +- cur = start_block; +- rsv = search_head; +- if (!rsv) +- return -1; +- +- while (1) { +- if (cur <= rsv->rsv_end) +- cur = rsv->rsv_end + 1; +- +- /* TODO? +- * in the case we could not find a reservable space +- * that is what is expected, during the re-search, we could +- * remember what's the largest reservable space we could have +- * and return that one. +- * +- * For now it will fail if we could not find the reservable +- * space with expected-size (or more)... +- */ +- if (cur > last_block) +- return -1; /* fail */ +- +- prev = rsv; +- next = rb_next(&rsv->rsv_node); +- rsv = rb_entry(next,struct ext4_reserve_window_node,rsv_node); +- +- /* +- * Reached the last reservation, we can just append to the +- * previous one. +- */ +- if (!next) +- break; +- +- if (cur + size <= rsv->rsv_start) { +- /* +- * Found a reserveable space big enough. We could +- * have a reservation across the group boundary here +- */ +- break; +- } +- } +- /* +- * we come here either : +- * when we reach the end of the whole list, +- * and there is empty reservable space after last entry in the list. +- * append it to the end of the list. +- * +- * or we found one reservable space in the middle of the list, +- * return the reservation window that we could append to. +- * succeed. +- */ +- +- if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) +- rsv_window_remove(sb, my_rsv); +- +- /* +- * Let's book the whole avaliable window for now. We will check the +- * disk bitmap later and then, if there are free blocks then we adjust +- * the window size if it's larger than requested. +- * Otherwise, we will remove this node from the tree next time +- * call find_next_reservable_window. +- */ +- my_rsv->rsv_start = cur; +- my_rsv->rsv_end = cur + size - 1; +- my_rsv->rsv_alloc_hit = 0; +- +- if (prev != my_rsv) +- ext4_rsv_window_add(sb, my_rsv); +- +- return 0; +-} +- +-/** +- * alloc_new_reservation()--allocate a new reservation window +- * +- * To make a new reservation, we search part of the filesystem +- * reservation list (the list that inside the group). We try to +- * allocate a new reservation window near the allocation goal, +- * or the beginning of the group, if there is no goal. +- * +- * We first find a reservable space after the goal, then from +- * there, we check the bitmap for the first free block after +- * it. If there is no free block until the end of group, then the +- * whole group is full, we failed. Otherwise, check if the free +- * block is inside the expected reservable space, if so, we +- * succeed. +- * If the first free block is outside the reservable space, then +- * start from the first free block, we search for next available +- * space, and go on. +- * +- * on succeed, a new reservation will be found and inserted into the list +- * It contains at least one free block, and it does not overlap with other +- * reservation windows. +- * +- * failed: we failed to find a reservation window in this group +- * +- * @rsv: the reservation +- * +- * @grp_goal: The goal (group-relative). It is where the search for a +- * free reservable space should start from. +- * if we have a grp_goal(grp_goal >0 ), then start from there, +- * no grp_goal(grp_goal = -1), we start from the first block +- * of the group. +- * +- * @sb: the super block +- * @group: the group we are trying to allocate in +- * @bitmap_bh: the block group block bitmap ++ * ext4_has_free_blocks() ++ * @sbi: in-core super block structure. ++ * @nblocks: number of needed blocks + * ++ * Check if filesystem has nblocks free & available for allocation. ++ * On success return 1, return 0 on failure. + */ +-static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv, +- ext4_grpblk_t grp_goal, struct super_block *sb, +- ext4_group_t group, struct buffer_head *bitmap_bh) ++int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) + { +- struct ext4_reserve_window_node *search_head; +- ext4_fsblk_t group_first_block, group_end_block, start_block; +- ext4_grpblk_t first_free_block; +- struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root; +- unsigned long size; +- int ret; +- spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock; +- +- group_first_block = ext4_group_first_block_no(sb, group); +- group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); +- +- if (grp_goal < 0) +- start_block = group_first_block; +- else +- start_block = grp_goal + group_first_block; ++ s64 free_blocks, dirty_blocks, root_blocks; ++ struct percpu_counter *fbc = &sbi->s_freeblocks_counter; ++ struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; + +- size = my_rsv->rsv_goal_size; ++ free_blocks = percpu_counter_read_positive(fbc); ++ dirty_blocks = percpu_counter_read_positive(dbc); ++ root_blocks = ext4_r_blocks_count(sbi->s_es); + +- if (!rsv_is_empty(&my_rsv->rsv_window)) { +- /* +- * if the old reservation is cross group boundary +- * and if the goal is inside the old reservation window, +- * we will come here when we just failed to allocate from +- * the first part of the window. We still have another part +- * that belongs to the next group. In this case, there is no +- * point to discard our window and try to allocate a new one +- * in this group(which will fail). we should +- * keep the reservation window, just simply move on. +- * +- * Maybe we could shift the start block of the reservation +- * window to the first block of next group. +- */ +- +- if ((my_rsv->rsv_start <= group_end_block) && +- (my_rsv->rsv_end > group_end_block) && +- (start_block >= my_rsv->rsv_start)) +- return -1; +- +- if ((my_rsv->rsv_alloc_hit > +- (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { +- /* +- * if the previously allocation hit ratio is +- * greater than 1/2, then we double the size of +- * the reservation window the next time, +- * otherwise we keep the same size window +- */ +- size = size * 2; +- if (size > EXT4_MAX_RESERVE_BLOCKS) +- size = EXT4_MAX_RESERVE_BLOCKS; +- my_rsv->rsv_goal_size= size; ++ if (free_blocks - (nblocks + root_blocks + dirty_blocks) < ++ EXT4_FREEBLOCKS_WATERMARK) { ++ free_blocks = percpu_counter_sum_positive(fbc); ++ dirty_blocks = percpu_counter_sum_positive(dbc); ++ if (dirty_blocks < 0) { ++ printk(KERN_CRIT "Dirty block accounting " ++ "went wrong %lld\n", ++ (long long)dirty_blocks); + } + } +- +- spin_lock(rsv_lock); +- /* +- * shift the search start to the window near the goal block +- */ +- search_head = search_reserve_window(fs_rsv_root, start_block); +- +- /* +- * find_next_reservable_window() simply finds a reservable window +- * inside the given range(start_block, group_end_block). +- * +- * To make sure the reservation window has a free bit inside it, we +- * need to check the bitmap after we found a reservable window. +- */ +-retry: +- ret = find_next_reservable_window(search_head, my_rsv, sb, +- start_block, group_end_block); +- +- if (ret == -1) { +- if (!rsv_is_empty(&my_rsv->rsv_window)) +- rsv_window_remove(sb, my_rsv); +- spin_unlock(rsv_lock); +- return -1; +- } +- +- /* +- * On success, find_next_reservable_window() returns the +- * reservation window where there is a reservable space after it. +- * Before we reserve this reservable space, we need +- * to make sure there is at least a free block inside this region. +- * +- * searching the first free bit on the block bitmap and copy of +- * last committed bitmap alternatively, until we found a allocatable +- * block. Search start from the start block of the reservable space +- * we just found. +- */ +- spin_unlock(rsv_lock); +- first_free_block = bitmap_search_next_usable_block( +- my_rsv->rsv_start - group_first_block, +- bitmap_bh, group_end_block - group_first_block + 1); +- +- if (first_free_block < 0) { +- /* +- * no free block left on the bitmap, no point +- * to reserve the space. return failed. +- */ +- spin_lock(rsv_lock); +- if (!rsv_is_empty(&my_rsv->rsv_window)) +- rsv_window_remove(sb, my_rsv); +- spin_unlock(rsv_lock); +- return -1; /* failed */ +- } +- +- start_block = first_free_block + group_first_block; +- /* +- * check if the first free block is within the +- * free space we just reserved +- */ +- if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end) +- return 0; /* success */ +- /* +- * if the first free bit we found is out of the reservable space +- * continue search for next reservable space, +- * start from where the free block is, +- * we also shift the list head to where we stopped last time +- */ +- search_head = my_rsv; +- spin_lock(rsv_lock); +- goto retry; +-} +- +-/** +- * try_to_extend_reservation() +- * @my_rsv: given reservation window +- * @sb: super block +- * @size: the delta to extend +- * +- * Attempt to expand the reservation window large enough to have +- * required number of free blocks +- * +- * Since ext4_try_to_allocate() will always allocate blocks within +- * the reservation window range, if the window size is too small, +- * multiple blocks allocation has to stop at the end of the reservation +- * window. To make this more efficient, given the total number of +- * blocks needed and the current size of the window, we try to +- * expand the reservation window size if necessary on a best-effort +- * basis before ext4_new_blocks() tries to allocate blocks, +- */ +-static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv, +- struct super_block *sb, int size) +-{ +- struct ext4_reserve_window_node *next_rsv; +- struct rb_node *next; +- spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock; +- +- if (!spin_trylock(rsv_lock)) +- return; +- +- next = rb_next(&my_rsv->rsv_node); +- +- if (!next) +- my_rsv->rsv_end += size; +- else { +- next_rsv = rb_entry(next, struct ext4_reserve_window_node, rsv_node); +- +- if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) +- my_rsv->rsv_end += size; +- else +- my_rsv->rsv_end = next_rsv->rsv_start - 1; +- } +- spin_unlock(rsv_lock); +-} +- +-/** +- * ext4_try_to_allocate_with_rsv() +- * @sb: superblock +- * @handle: handle to this transaction +- * @group: given allocation block group +- * @bitmap_bh: bufferhead holds the block bitmap +- * @grp_goal: given target block within the group +- * @count: target number of blocks to allocate +- * @my_rsv: reservation window +- * @errp: pointer to store the error code +- * +- * This is the main function used to allocate a new block and its reservation +- * window. +- * +- * Each time when a new block allocation is need, first try to allocate from +- * its own reservation. If it does not have a reservation window, instead of +- * looking for a free bit on bitmap first, then look up the reservation list to +- * see if it is inside somebody else's reservation window, we try to allocate a +- * reservation window for it starting from the goal first. Then do the block +- * allocation within the reservation window. +- * +- * This will avoid keeping on searching the reservation list again and +- * again when somebody is looking for a free block (without +- * reservation), and there are lots of free blocks, but they are all +- * being reserved. +- * +- * We use a red-black tree for the per-filesystem reservation list. +- * +- */ +-static ext4_grpblk_t +-ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, +- ext4_group_t group, struct buffer_head *bitmap_bh, +- ext4_grpblk_t grp_goal, +- struct ext4_reserve_window_node * my_rsv, +- unsigned long *count, int *errp) +-{ +- ext4_fsblk_t group_first_block, group_last_block; +- ext4_grpblk_t ret = 0; +- int fatal; +- unsigned long num = *count; +- +- *errp = 0; +- +- /* +- * Make sure we use undo access for the bitmap, because it is critical +- * that we do the frozen_data COW on bitmap buffers in all cases even +- * if the buffer is in BJ_Forget state in the committing transaction. ++ /* Check whether we have space after ++ * accounting for current dirty blocks & root reserved blocks. + */ +- BUFFER_TRACE(bitmap_bh, "get undo access for new block"); +- fatal = ext4_journal_get_undo_access(handle, bitmap_bh); +- if (fatal) { +- *errp = fatal; +- return -1; +- } +- +- /* +- * we don't deal with reservation when +- * filesystem is mounted without reservation +- * or the file is not a regular file +- * or last attempt to allocate a block with reservation turned on failed +- */ +- if (my_rsv == NULL ) { +- ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh, +- grp_goal, count, NULL); +- goto out; +- } +- /* +- * grp_goal is a group relative block number (if there is a goal) +- * 0 <= grp_goal < EXT4_BLOCKS_PER_GROUP(sb) +- * first block is a filesystem wide block number +- * first block is the block number of the first block in this group +- */ +- group_first_block = ext4_group_first_block_no(sb, group); +- group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); +- +- /* +- * Basically we will allocate a new block from inode's reservation +- * window. +- * +- * We need to allocate a new reservation window, if: +- * a) inode does not have a reservation window; or +- * b) last attempt to allocate a block from existing reservation +- * failed; or +- * c) we come here with a goal and with a reservation window +- * +- * We do not need to allocate a new reservation window if we come here +- * at the beginning with a goal and the goal is inside the window, or +- * we don't have a goal but already have a reservation window. +- * then we could go to allocate from the reservation window directly. +- */ +- while (1) { +- if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || +- !goal_in_my_reservation(&my_rsv->rsv_window, +- grp_goal, group, sb)) { +- if (my_rsv->rsv_goal_size < *count) +- my_rsv->rsv_goal_size = *count; +- ret = alloc_new_reservation(my_rsv, grp_goal, sb, +- group, bitmap_bh); +- if (ret < 0) +- break; /* failed */ +- +- if (!goal_in_my_reservation(&my_rsv->rsv_window, +- grp_goal, group, sb)) +- grp_goal = -1; +- } else if (grp_goal >= 0) { +- int curr = my_rsv->rsv_end - +- (grp_goal + group_first_block) + 1; +- +- if (curr < *count) +- try_to_extend_reservation(my_rsv, sb, +- *count - curr); +- } ++ if (free_blocks >= ((root_blocks + nblocks) + dirty_blocks)) ++ return 1; + +- if ((my_rsv->rsv_start > group_last_block) || +- (my_rsv->rsv_end < group_first_block)) { +- rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1); +- BUG(); +- } +- ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh, +- grp_goal, &num, &my_rsv->rsv_window); +- if (ret >= 0) { +- my_rsv->rsv_alloc_hit += num; +- *count = num; +- break; /* succeed */ +- } +- num = *count; +- } +-out: +- if (ret >= 0) { +- BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for " +- "bitmap block"); +- fatal = ext4_journal_dirty_metadata(handle, bitmap_bh); +- if (fatal) { +- *errp = fatal; +- return -1; +- } +- return ret; ++ /* Hm, nope. Are (enough) root reserved blocks available? */ ++ if (sbi->s_resuid == current_fsuid() || ++ ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || ++ capable(CAP_SYS_RESOURCE)) { ++ if (free_blocks >= (nblocks + dirty_blocks)) ++ return 1; + } + +- BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); +- ext4_journal_release_buffer(handle, bitmap_bh); +- return ret; ++ return 0; + } + +-/** +- * ext4_has_free_blocks() +- * @sbi: in-core super block structure. +- * @nblocks: number of neeed blocks +- * +- * Check if filesystem has free blocks available for allocation. +- * Return the number of blocks avaible for allocation for this request +- * On success, return nblocks +- */ +-ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, +- ext4_fsblk_t nblocks) ++int ext4_claim_free_blocks(struct ext4_sb_info *sbi, ++ s64 nblocks) + { +- ext4_fsblk_t free_blocks; +- ext4_fsblk_t root_blocks = 0; +- +- free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); +- +- if (!capable(CAP_SYS_RESOURCE) && +- sbi->s_resuid != current->fsuid && +- (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) +- root_blocks = ext4_r_blocks_count(sbi->s_es); +-#ifdef CONFIG_SMP +- if (free_blocks - root_blocks < FBC_BATCH) +- free_blocks = +- percpu_counter_sum(&sbi->s_freeblocks_counter); +-#endif +- if (free_blocks <= root_blocks) +- /* we don't have free space */ ++ if (ext4_has_free_blocks(sbi, nblocks)) { ++ percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); + return 0; +- if (free_blocks - root_blocks < nblocks) +- return free_blocks - root_blocks; +- return nblocks; +- } +- ++ } else ++ return -ENOSPC; ++} + + /** + * ext4_should_retry_alloc() +@@ -1657,402 +617,45 @@ int ext4_should_retry_alloc(struct super + return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal); + } + +-/** +- * ext4_old_new_blocks() -- core block bitmap based block allocation function +- * +- * @handle: handle to this transaction +- * @inode: file inode +- * @goal: given target block(filesystem wide) +- * @count: target number of blocks to allocate +- * @errp: error code +- * +- * ext4_old_new_blocks uses a goal block to assist allocation and look up +- * the block bitmap directly to do block allocation. It tries to +- * allocate block(s) from the block group contains the goal block first. If +- * that fails, it will try to allocate block(s) from other block groups +- * without any specific goal block. +- * +- * This function is called when -o nomballoc mount option is enabled +- * +- */ +-ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, +- ext4_fsblk_t goal, unsigned long *count, int *errp) +-{ +- struct buffer_head *bitmap_bh = NULL; +- struct buffer_head *gdp_bh; +- ext4_group_t group_no; +- ext4_group_t goal_group; +- ext4_grpblk_t grp_target_blk; /* blockgroup relative goal block */ +- ext4_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ +- ext4_fsblk_t ret_block; /* filesyetem-wide allocated block */ +- ext4_group_t bgi; /* blockgroup iteration index */ +- int fatal = 0, err; +- int performed_allocation = 0; +- ext4_grpblk_t free_blocks; /* number of free blocks in a group */ +- struct super_block *sb; +- struct ext4_group_desc *gdp; +- struct ext4_super_block *es; +- struct ext4_sb_info *sbi; +- struct ext4_reserve_window_node *my_rsv = NULL; +- struct ext4_block_alloc_info *block_i; +- unsigned short windowsz = 0; +- ext4_group_t ngroups; +- unsigned long num = *count; +- +- sb = inode->i_sb; +- if (!sb) { +- *errp = -ENODEV; +- printk("ext4_new_block: nonexistent device"); +- return 0; +- } +- +- sbi = EXT4_SB(sb); +- if (!EXT4_I(inode)->i_delalloc_reserved_flag) { +- /* +- * With delalloc we already reserved the blocks +- */ +- *count = ext4_has_free_blocks(sbi, *count); +- } +- if (*count == 0) { +- *errp = -ENOSPC; +- return 0; /*return with ENOSPC error */ +- } +- num = *count; +- +- /* +- * Check quota for allocation of this block. +- */ +- if (DQUOT_ALLOC_BLOCK(inode, num)) { +- *errp = -EDQUOT; +- return 0; +- } +- +- sbi = EXT4_SB(sb); +- es = EXT4_SB(sb)->s_es; +- ext4_debug("goal=%llu.\n", goal); +- /* +- * Allocate a block from reservation only when +- * filesystem is mounted with reservation(default,-o reservation), and +- * it's a regular file, and +- * the desired window size is greater than 0 (One could use ioctl +- * command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off +- * reservation on that particular file) +- */ +- block_i = EXT4_I(inode)->i_block_alloc_info; +- if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) +- my_rsv = &block_i->rsv_window_node; +- +- /* +- * First, test whether the goal block is free. +- */ +- if (goal < le32_to_cpu(es->s_first_data_block) || +- goal >= ext4_blocks_count(es)) +- goal = le32_to_cpu(es->s_first_data_block); +- ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk); +- goal_group = group_no; +-retry_alloc: +- gdp = ext4_get_group_desc(sb, group_no, &gdp_bh); +- if (!gdp) +- goto io_error; +- +- free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); +- /* +- * if there is not enough free blocks to make a new resevation +- * turn off reservation for this allocation +- */ +- if (my_rsv && (free_blocks < windowsz) +- && (rsv_is_empty(&my_rsv->rsv_window))) +- my_rsv = NULL; +- +- if (free_blocks > 0) { +- bitmap_bh = ext4_read_block_bitmap(sb, group_no); +- if (!bitmap_bh) +- goto io_error; +- grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle, +- group_no, bitmap_bh, grp_target_blk, +- my_rsv, &num, &fatal); +- if (fatal) +- goto out; +- if (grp_alloc_blk >= 0) +- goto allocated; +- } +- +- ngroups = EXT4_SB(sb)->s_groups_count; +- smp_rmb(); +- +- /* +- * Now search the rest of the groups. We assume that +- * group_no and gdp correctly point to the last group visited. +- */ +- for (bgi = 0; bgi < ngroups; bgi++) { +- group_no++; +- if (group_no >= ngroups) +- group_no = 0; +- gdp = ext4_get_group_desc(sb, group_no, &gdp_bh); +- if (!gdp) +- goto io_error; +- free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); +- /* +- * skip this group if the number of +- * free blocks is less than half of the reservation +- * window size. +- */ +- if (free_blocks <= (windowsz/2)) +- continue; +- +- brelse(bitmap_bh); +- bitmap_bh = ext4_read_block_bitmap(sb, group_no); +- if (!bitmap_bh) +- goto io_error; +- /* +- * try to allocate block(s) from this group, without a goal(-1). +- */ +- grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle, +- group_no, bitmap_bh, -1, my_rsv, +- &num, &fatal); +- if (fatal) +- goto out; +- if (grp_alloc_blk >= 0) +- goto allocated; +- } +- /* +- * We may end up a bogus ealier ENOSPC error due to +- * filesystem is "full" of reservations, but +- * there maybe indeed free blocks avaliable on disk +- * In this case, we just forget about the reservations +- * just do block allocation as without reservations. +- */ +- if (my_rsv) { +- my_rsv = NULL; +- windowsz = 0; +- group_no = goal_group; +- goto retry_alloc; +- } +- /* No space left on the device */ +- *errp = -ENOSPC; +- goto out; +- +-allocated: +- +- ext4_debug("using block group %lu(%d)\n", +- group_no, gdp->bg_free_blocks_count); +- +- BUFFER_TRACE(gdp_bh, "get_write_access"); +- fatal = ext4_journal_get_write_access(handle, gdp_bh); +- if (fatal) +- goto out; +- +- ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no); +- +- if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) || +- in_range(ext4_inode_bitmap(sb, gdp), ret_block, num) || +- in_range(ret_block, ext4_inode_table(sb, gdp), +- EXT4_SB(sb)->s_itb_per_group) || +- in_range(ret_block + num - 1, ext4_inode_table(sb, gdp), +- EXT4_SB(sb)->s_itb_per_group)) { +- ext4_error(sb, "ext4_new_block", +- "Allocating block in system zone - " +- "blocks from %llu, length %lu", +- ret_block, num); +- /* +- * claim_block marked the blocks we allocated +- * as in use. So we may want to selectively +- * mark some of the blocks as free +- */ +- goto retry_alloc; +- } +- +- performed_allocation = 1; +- +-#ifdef CONFIG_JBD2_DEBUG +- { +- struct buffer_head *debug_bh; +- +- /* Record bitmap buffer state in the newly allocated block */ +- debug_bh = sb_find_get_block(sb, ret_block); +- if (debug_bh) { +- BUFFER_TRACE(debug_bh, "state when allocated"); +- BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state"); +- brelse(debug_bh); +- } +- } +- jbd_lock_bh_state(bitmap_bh); +- spin_lock(sb_bgl_lock(sbi, group_no)); +- if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { +- int i; +- +- for (i = 0; i < num; i++) { +- if (ext4_test_bit(grp_alloc_blk+i, +- bh2jh(bitmap_bh)->b_committed_data)) { +- printk("%s: block was unexpectedly set in " +- "b_committed_data\n", __func__); +- } +- } +- } +- ext4_debug("found bit %d\n", grp_alloc_blk); +- spin_unlock(sb_bgl_lock(sbi, group_no)); +- jbd_unlock_bh_state(bitmap_bh); +-#endif +- +- if (ret_block + num - 1 >= ext4_blocks_count(es)) { +- ext4_error(sb, "ext4_new_block", +- "block(%llu) >= blocks count(%llu) - " +- "block_group = %lu, es == %p ", ret_block, +- ext4_blocks_count(es), group_no, es); +- goto out; +- } +- +- /* +- * It is up to the caller to add the new buffer to a journal +- * list of some description. We don't know in advance whether +- * the caller wants to use it as metadata or data. +- */ +- spin_lock(sb_bgl_lock(sbi, group_no)); +- if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) +- gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); +- le16_add_cpu(&gdp->bg_free_blocks_count, -num); +- gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); +- spin_unlock(sb_bgl_lock(sbi, group_no)); +- if (!EXT4_I(inode)->i_delalloc_reserved_flag) +- percpu_counter_sub(&sbi->s_freeblocks_counter, num); +- +- if (sbi->s_log_groups_per_flex) { +- ext4_group_t flex_group = ext4_flex_group(sbi, group_no); +- spin_lock(sb_bgl_lock(sbi, flex_group)); +- sbi->s_flex_groups[flex_group].free_blocks -= num; +- spin_unlock(sb_bgl_lock(sbi, flex_group)); +- } +- +- BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); +- err = ext4_journal_dirty_metadata(handle, gdp_bh); +- if (!fatal) +- fatal = err; +- +- sb->s_dirt = 1; +- if (fatal) +- goto out; +- +- *errp = 0; +- brelse(bitmap_bh); +- DQUOT_FREE_BLOCK(inode, *count-num); +- *count = num; +- return ret_block; +- +-io_error: +- *errp = -EIO; +-out: +- if (fatal) { +- *errp = fatal; +- ext4_std_error(sb, fatal); +- } +- /* +- * Undo the block allocation +- */ +- if (!performed_allocation) +- DQUOT_FREE_BLOCK(inode, *count); +- brelse(bitmap_bh); +- return 0; +-} +- +-#define EXT4_META_BLOCK 0x1 +- +-static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode, +- ext4_lblk_t iblock, ext4_fsblk_t goal, +- unsigned long *count, int *errp, int flags) +-{ +- struct ext4_allocation_request ar; +- ext4_fsblk_t ret; +- +- if (!test_opt(inode->i_sb, MBALLOC)) { +- return ext4_old_new_blocks(handle, inode, goal, count, errp); +- } +- +- memset(&ar, 0, sizeof(ar)); +- /* Fill with neighbour allocated blocks */ +- +- ar.inode = inode; +- ar.goal = goal; +- ar.len = *count; +- ar.logical = iblock; +- +- if (S_ISREG(inode->i_mode) && !(flags & EXT4_META_BLOCK)) +- /* enable in-core preallocation for data block allocation */ +- ar.flags = EXT4_MB_HINT_DATA; +- else +- /* disable in-core preallocation for non-regular files */ +- ar.flags = 0; +- +- ret = ext4_mb_new_blocks(handle, &ar, errp); +- *count = ar.len; +- return ret; +-} +- + /* + * ext4_new_meta_blocks() -- allocate block for meta data (indexing) blocks + * + * @handle: handle to this transaction + * @inode: file inode + * @goal: given target block(filesystem wide) +- * @count: total number of blocks need ++ * @count: pointer to total number of blocks needed + * @errp: error code + * +- * Return 1st allocated block numberon success, *count stores total account ++ * Return 1st allocated block number on success, *count stores total account + * error stores in errp pointer + */ + ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, unsigned long *count, int *errp) + { ++ struct ext4_allocation_request ar; + ext4_fsblk_t ret; +- ret = do_blk_alloc(handle, inode, 0, goal, +- count, errp, EXT4_META_BLOCK); ++ ++ memset(&ar, 0, sizeof(ar)); ++ /* Fill with neighbour allocated blocks */ ++ ar.inode = inode; ++ ar.goal = goal; ++ ar.len = count ? *count : 1; ++ ++ ret = ext4_mb_new_blocks(handle, &ar, errp); ++ if (count) ++ *count = ar.len; ++ + /* + * Account for the allocated meta blocks + */ +- if (!(*errp)) { ++ if (!(*errp) && EXT4_I(inode)->i_delalloc_reserved_flag) { + spin_lock(&EXT4_I(inode)->i_block_reservation_lock); +- EXT4_I(inode)->i_allocated_meta_blocks += *count; ++ EXT4_I(inode)->i_allocated_meta_blocks += ar.len; + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + } + return ret; + } + +-/* +- * ext4_new_meta_block() -- allocate block for meta data (indexing) blocks +- * +- * @handle: handle to this transaction +- * @inode: file inode +- * @goal: given target block(filesystem wide) +- * @errp: error code +- * +- * Return allocated block number on success +- */ +-ext4_fsblk_t ext4_new_meta_block(handle_t *handle, struct inode *inode, +- ext4_fsblk_t goal, int *errp) +-{ +- unsigned long count = 1; +- return ext4_new_meta_blocks(handle, inode, goal, &count, errp); +-} +- +-/* +- * ext4_new_blocks() -- allocate data blocks +- * +- * @handle: handle to this transaction +- * @inode: file inode +- * @goal: given target block(filesystem wide) +- * @count: total number of blocks need +- * @errp: error code +- * +- * Return 1st allocated block numberon success, *count stores total account +- * error stores in errp pointer +- */ +- +-ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, +- ext4_lblk_t iblock, ext4_fsblk_t goal, +- unsigned long *count, int *errp) +-{ +- return do_blk_alloc(handle, inode, iblock, goal, count, errp, 0); +-} +- + /** + * ext4_count_free_blocks() -- count filesystem free blocks + * @sb: superblock +@@ -2068,7 +671,7 @@ ext4_fsblk_t ext4_count_free_blocks(stru + #ifdef EXT4FS_DEBUG + struct ext4_super_block *es; + ext4_fsblk_t bitmap_count; +- unsigned long x; ++ unsigned int x; + struct buffer_head *bitmap_bh = NULL; + + es = EXT4_SB(sb)->s_es; +@@ -2088,15 +691,14 @@ ext4_fsblk_t ext4_count_free_blocks(stru + continue; + + x = ext4_count_free(bitmap_bh, sb->s_blocksize); +- printk(KERN_DEBUG "group %lu: stored = %d, counted = %lu\n", ++ printk(KERN_DEBUG "group %lu: stored = %d, counted = %u\n", + i, le16_to_cpu(gdp->bg_free_blocks_count), x); + bitmap_count += x; + } + brelse(bitmap_bh); +- printk("ext4_count_free_blocks: stored = %llu" +- ", computed = %llu, %llu\n", +- ext4_free_blocks_count(es), +- desc_count, bitmap_count); ++ printk(KERN_DEBUG "ext4_count_free_blocks: stored = %llu" ++ ", computed = %llu, %llu\n", ext4_free_blocks_count(es), ++ desc_count, bitmap_count); + return bitmap_count; + #else + desc_count = 0; +@@ -2105,7 +707,7 @@ ext4_fsblk_t ext4_count_free_blocks(stru + gdp = ext4_get_group_desc(sb, i, NULL); + if (!gdp) + continue; +- desc_count += le16_to_cpu(gdp->bg_free_blocks_count); ++ desc_count += ext4_free_blks_count(sb, gdp); + } + + return desc_count; +@@ -2183,8 +785,9 @@ unsigned long ext4_bg_num_gdb(struct sup + + if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) || + metagroup < first_meta_bg) +- return ext4_bg_num_gdb_nometa(sb,group); ++ return ext4_bg_num_gdb_nometa(sb, group); + + return ext4_bg_num_gdb_meta(sb,group); + + } ++ +diff -rup b/fs/ext4//bitmap.c a/fs/ext4///bitmap.c +--- b/fs/ext4/bitmap.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/bitmap.c 2009-02-10 21:40:11.000000000 +0100 +@@ -15,17 +15,16 @@ + + static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + +-unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars) ++unsigned int ext4_count_free(struct buffer_head *map, unsigned int numchars) + { +- unsigned int i; +- unsigned long sum = 0; ++ unsigned int i, sum = 0; + + if (!map) +- return (0); ++ return 0; + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; +- return (sum); ++ return sum; + } + + #endif /* EXT4FS_DEBUG */ +diff -rup b/fs/ext4//dir.c a/fs/ext4///dir.c +--- b/fs/ext4/dir.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/dir.c 2009-02-10 21:40:11.000000000 +0100 +@@ -33,10 +33,10 @@ static unsigned char ext4_filetype_table + }; + + static int ext4_readdir(struct file *, void *, filldir_t); +-static int ext4_dx_readdir(struct file * filp, +- void * dirent, filldir_t filldir); +-static int ext4_release_dir (struct inode * inode, +- struct file * filp); ++static int ext4_dx_readdir(struct file *filp, ++ void *dirent, filldir_t filldir); ++static int ext4_release_dir(struct inode *inode, ++ struct file *filp); + + const struct file_operations ext4_dir_operations = { + .llseek = generic_file_llseek, +@@ -61,12 +61,12 @@ static unsigned char get_dtype(struct su + } + + +-int ext4_check_dir_entry (const char * function, struct inode * dir, +- struct ext4_dir_entry_2 * de, +- struct buffer_head * bh, +- unsigned long offset) ++int ext4_check_dir_entry(const char *function, struct inode *dir, ++ struct ext4_dir_entry_2 *de, ++ struct buffer_head *bh, ++ unsigned int offset) + { +- const char * error_msg = NULL; ++ const char *error_msg = NULL; + const int rlen = ext4_rec_len_from_disk(de->rec_len); + + if (rlen < EXT4_DIR_REC_LEN(1)) +@@ -82,20 +82,20 @@ int ext4_check_dir_entry (const char * f + error_msg = "inode out of bounds"; + + if (error_msg != NULL) +- ext4_error (dir->i_sb, function, ++ ext4_error(dir->i_sb, function, + "bad entry in directory #%lu: %s - " +- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", ++ "offset=%u, inode=%u, rec_len=%d, name_len=%d", + dir->i_ino, error_msg, offset, +- (unsigned long) le32_to_cpu(de->inode), ++ le32_to_cpu(de->inode), + rlen, de->name_len); + return error_msg == NULL ? 1 : 0; + } + +-static int ext4_readdir(struct file * filp, +- void * dirent, filldir_t filldir) ++static int ext4_readdir(struct file *filp, ++ void *dirent, filldir_t filldir) + { + int error = 0; +- unsigned long offset; ++ unsigned int offset; + int i, stored; + struct ext4_dir_entry_2 *de; + struct super_block *sb; +@@ -192,14 +192,14 @@ revalidate: + while (!error && filp->f_pos < inode->i_size + && offset < sb->s_blocksize) { + de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); +- if (!ext4_check_dir_entry ("ext4_readdir", inode, de, +- bh, offset)) { ++ if (!ext4_check_dir_entry("ext4_readdir", inode, de, ++ bh, offset)) { + /* + * On error, skip the f_pos to the next block + */ + filp->f_pos = (filp->f_pos | + (sb->s_blocksize - 1)) + 1; +- brelse (bh); ++ brelse(bh); + ret = stored; + goto out; + } +@@ -223,12 +223,12 @@ revalidate: + break; + if (version != filp->f_version) + goto revalidate; +- stored ++; ++ stored++; + } + filp->f_pos += ext4_rec_len_from_disk(de->rec_len); + } + offset = 0; +- brelse (bh); ++ brelse(bh); + } + out: + return ret; +@@ -295,9 +295,9 @@ static void free_rb_tree_fname(struct rb + parent = rb_parent(n); + fname = rb_entry(n, struct fname, rb_hash); + while (fname) { +- struct fname * old = fname; ++ struct fname *old = fname; + fname = fname->next; +- kfree (old); ++ kfree(old); + } + if (!parent) + root->rb_node = NULL; +@@ -336,7 +336,7 @@ int ext4_htree_store_dirent(struct file + struct ext4_dir_entry_2 *dirent) + { + struct rb_node **p, *parent = NULL; +- struct fname * fname, *new_fn; ++ struct fname *fname, *new_fn; + struct dir_private_info *info; + int len; + +@@ -393,19 +393,20 @@ int ext4_htree_store_dirent(struct file + * for all entres on the fname linked list. (Normally there is only + * one entry on the linked list, unless there are 62 bit hash collisions.) + */ +-static int call_filldir(struct file * filp, void * dirent, ++static int call_filldir(struct file *filp, void *dirent, + filldir_t filldir, struct fname *fname) + { + struct dir_private_info *info = filp->private_data; + loff_t curr_pos; + struct inode *inode = filp->f_path.dentry->d_inode; +- struct super_block * sb; ++ struct super_block *sb; + int error; + + sb = inode->i_sb; + + if (!fname) { +- printk("call_filldir: called with null fname?!?\n"); ++ printk(KERN_ERR "ext4: call_filldir: called with " ++ "null fname?!?\n"); + return 0; + } + curr_pos = hash2pos(fname->hash, fname->minor_hash); +@@ -424,8 +425,8 @@ static int call_filldir(struct file * fi + return 0; + } + +-static int ext4_dx_readdir(struct file * filp, +- void * dirent, filldir_t filldir) ++static int ext4_dx_readdir(struct file *filp, ++ void *dirent, filldir_t filldir) + { + struct dir_private_info *info = filp->private_data; + struct inode *inode = filp->f_path.dentry->d_inode; +@@ -512,7 +513,7 @@ finished: + return 0; + } + +-static int ext4_release_dir (struct inode * inode, struct file * filp) ++static int ext4_release_dir(struct inode *inode, struct file *filp) + { + if (filp->private_data) + ext4_htree_free_dir_info(filp->private_data); +diff -rup b/fs/ext4//ext4_extents.h a/fs/ext4///ext4_extents.h +--- b/fs/ext4/ext4_extents.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/ext4_extents.h 2009-02-10 21:40:14.000000000 +0100 +@@ -181,11 +181,6 @@ static inline unsigned short ext_depth(s + return le16_to_cpu(ext_inode_hdr(inode)->eh_depth); + } + +-static inline void ext4_ext_tree_changed(struct inode *inode) +-{ +- EXT4_I(inode)->i_ext_generation++; +-} +- + static inline void + ext4_ext_invalidate_cache(struct inode *inode) + { +diff -rup b/fs/ext4//ext4.h a/fs/ext4///ext4.h +--- b/fs/ext4/ext4.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/ext4.h 2009-02-10 21:40:14.000000000 +0100 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include "ext4_i.h" + + /* +@@ -44,9 +45,9 @@ + #ifdef EXT4FS_DEBUG + #define ext4_debug(f, a...) \ + do { \ +- printk (KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \ ++ printk(KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \ + __FILE__, __LINE__, __func__); \ +- printk (KERN_DEBUG f, ## a); \ ++ printk(KERN_DEBUG f, ## a); \ + } while (0) + #else + #define ext4_debug(f, a...) do {} while (0) +@@ -94,9 +95,9 @@ struct ext4_allocation_request { + /* phys. block for ^^^ */ + ext4_fsblk_t pright; + /* how many blocks we want to allocate */ +- unsigned long len; ++ unsigned int len; + /* flags. see above EXT4_MB_HINT_* */ +- unsigned long flags; ++ unsigned int flags; + }; + + /* +@@ -128,7 +129,7 @@ struct ext4_allocation_request { + #else + # define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size) + #endif +-#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (__u32)) ++#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof(__u32)) + #ifdef __KERNEL__ + # define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) + #else +@@ -156,12 +157,12 @@ struct ext4_group_desc + __le32 bg_block_bitmap_lo; /* Blocks bitmap block */ + __le32 bg_inode_bitmap_lo; /* Inodes bitmap block */ + __le32 bg_inode_table_lo; /* Inodes table block */ +- __le16 bg_free_blocks_count; /* Free blocks count */ +- __le16 bg_free_inodes_count; /* Free inodes count */ +- __le16 bg_used_dirs_count; /* Directories count */ ++ __le16 bg_free_blocks_count_lo;/* Free blocks count */ ++ __le16 bg_free_inodes_count_lo;/* Free inodes count */ ++ __le16 bg_used_dirs_count_lo; /* Directories count */ + __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ + __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */ +- __le16 bg_itable_unused; /* Unused inodes count */ ++ __le16 bg_itable_unused_lo; /* Unused inodes count */ + __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ + __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ + __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ +@@ -169,7 +170,7 @@ struct ext4_group_desc + __le16 bg_free_blocks_count_hi;/* Free blocks count MSB */ + __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ + __le16 bg_used_dirs_count_hi; /* Directories count MSB */ +- __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ ++ __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ + __u32 bg_reserved2[3]; + }; + +@@ -245,7 +246,7 @@ struct flex_groups { + #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ + + #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ +-#define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ ++#define EXT4_FL_USER_MODIFIABLE 0x000B80FF /* User modifiable flags */ + + /* + * Inode dynamic state flags +@@ -511,7 +512,6 @@ do { \ + /* + * Mount flags + */ +-#define EXT4_MOUNT_CHECK 0x00001 /* Do mount-time checks */ + #define EXT4_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */ + #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ + #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ +@@ -539,7 +539,6 @@ do { \ + #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ + #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ + #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ +-#define EXT4_MOUNT_MBALLOC 0x4000000 /* Buddy allocation support */ + #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ + /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ + #ifndef _LINUX_EXT2_FS_H +@@ -668,7 +667,7 @@ struct ext4_super_block { + }; + + #ifdef __KERNEL__ +-static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb) ++static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) + { + return sb->s_fs_info; + } +@@ -726,11 +725,11 @@ static inline int ext4_valid_inum(struct + */ + + #define EXT4_HAS_COMPAT_FEATURE(sb,mask) \ +- ( EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) ++ ((EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask)) != 0) + #define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask) \ +- ( EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) ++ ((EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask)) != 0) + #define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \ +- ( EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) ++ ((EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask)) != 0) + #define EXT4_SET_COMPAT_FEATURE(sb,mask) \ + EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) + #define EXT4_SET_RO_COMPAT_FEATURE(sb,mask) \ +@@ -790,6 +789,8 @@ static inline int ext4_valid_inum(struct + #define EXT4_DEF_RESUID 0 + #define EXT4_DEF_RESGID 0 + ++#define EXT4_DEF_INODE_READAHEAD_BLKS 32 ++ + /* + * Default mount options + */ +@@ -889,6 +890,9 @@ static inline __le16 ext4_rec_len_to_dis + #define DX_HASH_LEGACY 0 + #define DX_HASH_HALF_MD4 1 + #define DX_HASH_TEA 2 ++#define DX_HASH_LEGACY_UNSIGNED 3 ++#define DX_HASH_HALF_MD4_UNSIGNED 4 ++#define DX_HASH_TEA_UNSIGNED 5 + + #ifdef __KERNEL__ + +@@ -953,7 +957,25 @@ ext4_group_first_block_no(struct super_b + #define ERR_BAD_DX_DIR -75000 + + void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, +- unsigned long *blockgrpp, ext4_grpblk_t *offsetp); ++ ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp); ++ ++extern struct proc_dir_entry *ext4_proc_root; ++ ++#ifdef CONFIG_PROC_FS ++extern const struct file_operations ext4_ui_proc_fops; ++ ++#define EXT4_PROC_HANDLER(name, var) \ ++do { \ ++ proc = proc_create_data(name, mode, sbi->s_proc, \ ++ &ext4_ui_proc_fops, &sbi->s_##var); \ ++ if (proc == NULL) { \ ++ printk(KERN_ERR "EXT4-fs: can't create %s\n", name); \ ++ goto err_out; \ ++ } \ ++} while (0) ++#else ++#define EXT4_PROC_HANDLER(name, var) ++#endif + + /* + * Function prototypes +@@ -967,6 +989,9 @@ void ext4_get_group_no_and_offset(struct + # define ATTRIB_NORET __attribute__((noreturn)) + # define NORET_AND noreturn, + ++/* bitmap.c */ ++extern unsigned int ext4_count_free(struct buffer_head *, unsigned); ++ + /* balloc.c */ + extern unsigned int ext4_block_group(struct super_block *sb, + ext4_fsblk_t blocknr); +@@ -975,55 +1000,44 @@ extern ext4_grpblk_t ext4_block_group_of + extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group); + extern unsigned long ext4_bg_num_gdb(struct super_block *sb, + ext4_group_t group); +-extern ext4_fsblk_t ext4_new_meta_block(handle_t *handle, struct inode *inode, +- ext4_fsblk_t goal, int *errp); + extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t goal, unsigned long *count, int *errp); +-extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, +- ext4_lblk_t iblock, ext4_fsblk_t goal, +- unsigned long *count, int *errp); +-extern ext4_fsblk_t ext4_old_new_blocks(handle_t *handle, struct inode *inode, +- ext4_fsblk_t goal, unsigned long *count, int *errp); +-extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, +- ext4_fsblk_t nblocks); +-extern void ext4_free_blocks (handle_t *handle, struct inode *inode, ++extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); ++extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); ++extern void ext4_free_blocks(handle_t *handle, struct inode *inode, + ext4_fsblk_t block, unsigned long count, int metadata); +-extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb, +- ext4_fsblk_t block, unsigned long count, +- unsigned long *pdquot_freed_blocks); +-extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *); +-extern void ext4_check_blocks_bitmap (struct super_block *); ++extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, ++ ext4_fsblk_t block, unsigned long count); ++extern ext4_fsblk_t ext4_count_free_blocks(struct super_block *); ++extern void ext4_check_blocks_bitmap(struct super_block *); + extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, + ext4_group_t block_group, + struct buffer_head ** bh); + extern int ext4_should_retry_alloc(struct super_block *sb, int *retries); +-extern void ext4_init_block_alloc_info(struct inode *); +-extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv); + + /* dir.c */ + extern int ext4_check_dir_entry(const char *, struct inode *, + struct ext4_dir_entry_2 *, +- struct buffer_head *, unsigned long); ++ struct buffer_head *, unsigned int); + extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, + __u32 minor_hash, + struct ext4_dir_entry_2 *dirent); + extern void ext4_htree_free_dir_info(struct dir_private_info *p); + + /* fsync.c */ +-extern int ext4_sync_file (struct file *, struct dentry *, int); ++extern int ext4_sync_file(struct file *, struct dentry *, int); + + /* hash.c */ + extern int ext4fs_dirhash(const char *name, int len, struct + dx_hash_info *hinfo); + + /* ialloc.c */ +-extern struct inode * ext4_new_inode (handle_t *, struct inode *, int); +-extern void ext4_free_inode (handle_t *, struct inode *); +-extern struct inode * ext4_orphan_get (struct super_block *, unsigned long); +-extern unsigned long ext4_count_free_inodes (struct super_block *); +-extern unsigned long ext4_count_dirs (struct super_block *); +-extern void ext4_check_inodes_bitmap (struct super_block *); +-extern unsigned long ext4_count_free (struct buffer_head *, unsigned); ++extern struct inode * ext4_new_inode(handle_t *, struct inode *, int); ++extern void ext4_free_inode(handle_t *, struct inode *); ++extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); ++extern unsigned long ext4_count_free_inodes(struct super_block *); ++extern unsigned long ext4_count_dirs(struct super_block *); ++extern void ext4_check_inodes_bitmap(struct super_block *); + + /* mballoc.c */ + extern long ext4_mb_stats; +@@ -1033,17 +1047,18 @@ extern int ext4_mb_release(struct super_ + extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *, + struct ext4_allocation_request *, int *); + extern int ext4_mb_reserve_blocks(struct super_block *, int); +-extern void ext4_mb_discard_inode_preallocations(struct inode *); ++extern void ext4_discard_preallocations(struct inode *); + extern int __init init_ext4_mballoc(void); + extern void exit_ext4_mballoc(void); + extern void ext4_mb_free_blocks(handle_t *, struct inode *, + unsigned long, unsigned long, int, unsigned long *); +-extern int ext4_mb_add_more_groupinfo(struct super_block *sb, ++extern int ext4_mb_add_groupinfo(struct super_block *sb, + ext4_group_t i, struct ext4_group_desc *desc); + extern void ext4_mb_update_group_info(struct ext4_group_info *grp, + ext4_grpblk_t add); +- +- ++extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t); ++extern void ext4_mb_put_buddy_cache_lock(struct super_block *, ++ ext4_group_t, int); + /* inode.c */ + int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t blocknr); +@@ -1051,24 +1066,19 @@ struct buffer_head *ext4_getblk(handle_t + ext4_lblk_t, int, int *); + struct buffer_head *ext4_bread(handle_t *, struct inode *, + ext4_lblk_t, int, int *); +-int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, +- ext4_lblk_t iblock, unsigned long maxblocks, +- struct buffer_head *bh_result, +- int create, int extend_disksize); + + extern struct inode *ext4_iget(struct super_block *, unsigned long); +-extern int ext4_write_inode (struct inode *, int); +-extern int ext4_setattr (struct dentry *, struct iattr *); ++extern int ext4_write_inode(struct inode *, int); ++extern int ext4_setattr(struct dentry *, struct iattr *); + extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat); +-extern void ext4_delete_inode (struct inode *); +-extern int ext4_sync_inode (handle_t *, struct inode *); +-extern void ext4_discard_reservation (struct inode *); ++extern void ext4_delete_inode(struct inode *); ++extern int ext4_sync_inode(handle_t *, struct inode *); + extern void ext4_dirty_inode(struct inode *); + extern int ext4_change_inode_journal_flag(struct inode *, int); + extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); + extern int ext4_can_truncate(struct inode *inode); +-extern void ext4_truncate (struct inode *); ++extern void ext4_truncate(struct inode *); + extern void ext4_set_inode_flags(struct inode *); + extern void ext4_get_inode_flags(struct ext4_inode_info *); + extern void ext4_set_aops(struct inode *inode); +@@ -1081,7 +1091,7 @@ extern int ext4_page_mkwrite(struct vm_a + + /* ioctl.c */ + extern long ext4_ioctl(struct file *, unsigned int, unsigned long); +-extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long); ++extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); + + /* migrate.c */ + extern int ext4_ext_migrate(struct inode *); +@@ -1099,14 +1109,17 @@ extern int ext4_group_extend(struct supe + ext4_fsblk_t n_blocks_count); + + /* super.c */ +-extern void ext4_error (struct super_block *, const char *, const char *, ...) ++extern void ext4_error(struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +-extern void __ext4_std_error (struct super_block *, const char *, int); +-extern void ext4_abort (struct super_block *, const char *, const char *, ...) ++extern void __ext4_std_error(struct super_block *, const char *, int); ++extern void ext4_abort(struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +-extern void ext4_warning (struct super_block *, const char *, const char *, ...) ++extern void ext4_warning(struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +-extern void ext4_update_dynamic_rev (struct super_block *sb); ++extern void ext4_grp_locked_error(struct super_block *, ext4_group_t, ++ const char *, const char *, ...) ++ __attribute__ ((format (printf, 4, 5))); ++extern void ext4_update_dynamic_rev(struct super_block *sb); + extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb, + __u32 compat); + extern int ext4_update_rocompat_feature(handle_t *handle, +@@ -1119,12 +1132,28 @@ extern ext4_fsblk_t ext4_inode_bitmap(st + struct ext4_group_desc *bg); + extern ext4_fsblk_t ext4_inode_table(struct super_block *sb, + struct ext4_group_desc *bg); ++extern __u32 ext4_free_blks_count(struct super_block *sb, ++ struct ext4_group_desc *bg); ++extern __u32 ext4_free_inodes_count(struct super_block *sb, ++ struct ext4_group_desc *bg); ++extern __u32 ext4_used_dirs_count(struct super_block *sb, ++ struct ext4_group_desc *bg); ++extern __u32 ext4_itable_unused_count(struct super_block *sb, ++ struct ext4_group_desc *bg); + extern void ext4_block_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk); + extern void ext4_inode_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk); + extern void ext4_inode_table_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk); ++extern void ext4_free_blks_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count); ++extern void ext4_free_inodes_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count); ++extern void ext4_used_dirs_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count); ++extern void ext4_itable_unused_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count); + + static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) + { +@@ -1179,7 +1208,7 @@ static inline void ext4_isize_set(struct + + static inline + struct ext4_group_info *ext4_get_group_info(struct super_block *sb, +- ext4_group_t group) ++ ext4_group_t group) + { + struct ext4_group_info ***grp_info; + long indexv, indexh; +@@ -1207,6 +1236,72 @@ do { \ + __ext4_std_error((sb), __func__, (errno)); \ + } while (0) + ++#ifdef CONFIG_SMP ++/* Each CPU can accumulate FBC_BATCH blocks in their local ++ * counters. So we need to make sure we have free blocks more ++ * than FBC_BATCH * nr_cpu_ids. Also add a window of 4 times. ++ */ ++#define EXT4_FREEBLOCKS_WATERMARK (4 * (FBC_BATCH * nr_cpu_ids)) ++#else ++#define EXT4_FREEBLOCKS_WATERMARK 0 ++#endif ++ ++static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize) ++{ ++ /* ++ * XXX: replace with spinlock if seen contended -bzzz ++ */ ++ down_write(&EXT4_I(inode)->i_data_sem); ++ if (newsize > EXT4_I(inode)->i_disksize) ++ EXT4_I(inode)->i_disksize = newsize; ++ up_write(&EXT4_I(inode)->i_data_sem); ++ return ; ++} ++ ++struct ext4_group_info { ++ unsigned long bb_state; ++ struct rb_root bb_free_root; ++ unsigned short bb_first_free; ++ unsigned short bb_free; ++ unsigned short bb_fragments; ++ struct list_head bb_prealloc_list; ++#ifdef DOUBLE_CHECK ++ void *bb_bitmap; ++#endif ++ struct rw_semaphore alloc_sem; ++ unsigned short bb_counters[]; ++}; ++ ++#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 ++#define EXT4_GROUP_INFO_LOCKED_BIT 1 ++ ++#define EXT4_MB_GRP_NEED_INIT(grp) \ ++ (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) ++ ++static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) ++{ ++ struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); ++ ++ bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); ++} ++ ++static inline void ext4_unlock_group(struct super_block *sb, ++ ext4_group_t group) ++{ ++ struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); ++ ++ bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); ++} ++ ++static inline int ext4_is_group_locked(struct super_block *sb, ++ ext4_group_t group) ++{ ++ struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); ++ ++ return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT, ++ &(grinfo->bb_state)); ++} ++ + /* + * Inodes and files operations + */ +@@ -1232,18 +1327,37 @@ extern int ext4_ext_writepage_trans_bloc + extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks, + int chunk); + extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, +- ext4_lblk_t iblock, +- unsigned long max_blocks, struct buffer_head *bh_result, +- int create, int extend_disksize); ++ ext4_lblk_t iblock, unsigned int max_blocks, ++ struct buffer_head *bh_result, ++ int create, int extend_disksize); + extern void ext4_ext_truncate(struct inode *); + extern void ext4_ext_init(struct super_block *); + extern void ext4_ext_release(struct super_block *); + extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset, + loff_t len); + extern int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, +- sector_t block, unsigned long max_blocks, ++ sector_t block, unsigned int max_blocks, + struct buffer_head *bh, int create, + int extend_disksize, int flag); ++ ++#define BH_JBDPrivateStart (BH_Unshadow+1) ++/* ++ * Add new method to test wether block and inode bitmaps are properly ++ * initialized. With uninit_bg reading the block from disk is not enough ++ * to mark the bitmap uptodate. We need to also zero-out the bitmap ++ */ ++#define BH_BITMAP_UPTODATE BH_JBDPrivateStart ++ ++static inline int bitmap_uptodate(struct buffer_head *bh) ++{ ++ return (buffer_uptodate(bh) && ++ test_bit(BH_BITMAP_UPTODATE, &(bh)->b_state)); ++} ++static inline void set_bitmap_uptodate(struct buffer_head *bh) ++{ ++ set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state); ++} ++ + #endif /* __KERNEL__ */ + + #endif /* _EXT4_H */ +diff -rup b/fs/ext4//ext4_i.h a/fs/ext4///ext4_i.h +--- b/fs/ext4/ext4_i.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/ext4_i.h 2009-02-10 21:40:14.000000000 +0100 +@@ -31,39 +31,7 @@ typedef unsigned long long ext4_fsblk_t; + typedef __u32 ext4_lblk_t; + + /* data type for block group number */ +-typedef unsigned long ext4_group_t; +- +-struct ext4_reserve_window { +- ext4_fsblk_t _rsv_start; /* First byte reserved */ +- ext4_fsblk_t _rsv_end; /* Last byte reserved or 0 */ +-}; +- +-struct ext4_reserve_window_node { +- struct rb_node rsv_node; +- __u32 rsv_goal_size; +- __u32 rsv_alloc_hit; +- struct ext4_reserve_window rsv_window; +-}; +- +-struct ext4_block_alloc_info { +- /* information about reservation window */ +- struct ext4_reserve_window_node rsv_window_node; +- /* +- * was i_next_alloc_block in ext4_inode_info +- * is the logical (file-relative) number of the +- * most-recently-allocated block in this file. +- * We use this for detecting linearly ascending allocation requests. +- */ +- ext4_lblk_t last_alloc_logical_block; +- /* +- * Was i_next_alloc_goal in ext4_inode_info +- * is the *physical* companion to i_next_alloc_block. +- * it the physical block number of the block which was most-recentl +- * allocated to this file. This give us the goal (target) for the next +- * allocation when we detect linearly ascending requests. +- */ +- ext4_fsblk_t last_alloc_physical_block; +-}; ++typedef unsigned int ext4_group_t; + + #define rsv_start rsv_window._rsv_start + #define rsv_end rsv_window._rsv_end +@@ -97,11 +65,8 @@ struct ext4_inode_info { + ext4_group_t i_block_group; + __u32 i_state; /* Dynamic state flags for ext4 */ + +- /* block reservation info */ +- struct ext4_block_alloc_info *i_block_alloc_info; +- + ext4_lblk_t i_dir_start_lookup; +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + /* + * Extended attributes can be read independently of the main file + * data. Taking i_mutex even when reading would cause contention +@@ -111,7 +76,7 @@ struct ext4_inode_info { + */ + struct rw_semaphore xattr_sem; + #endif +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; + #endif +@@ -135,9 +100,6 @@ struct ext4_inode_info { + */ + loff_t i_disksize; + +- /* on-disk additional length */ +- __u16 i_extra_isize; +- + /* + * i_data_sem is for serialising ext4_truncate() against + * ext4_getblock(). In the 2.4 ext2 design, great chunks of inode's +@@ -152,7 +114,6 @@ struct ext4_inode_info { + struct inode vfs_inode; + struct jbd2_inode jinode; + +- unsigned long i_ext_generation; + struct ext4_ext_cache i_cached_extent; + /* + * File creation time. Its function is same as that of +@@ -165,10 +126,14 @@ struct ext4_inode_info { + spinlock_t i_prealloc_lock; + + /* allocation reservation info for delalloc */ +- unsigned long i_reserved_data_blocks; +- unsigned long i_reserved_meta_blocks; +- unsigned long i_allocated_meta_blocks; ++ unsigned int i_reserved_data_blocks; ++ unsigned int i_reserved_meta_blocks; ++ unsigned int i_allocated_meta_blocks; + unsigned short i_delalloc_reserved_flag; ++ ++ /* on-disk additional length */ ++ __u16 i_extra_isize; ++ + spinlock_t i_block_reservation_lock; + }; + +diff -rup b/fs/ext4//ext4_sb.h a/fs/ext4///ext4_sb.h +--- b/fs/ext4/ext4_sb.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/ext4_sb.h 2009-02-10 21:40:14.000000000 +0100 +@@ -40,8 +40,8 @@ struct ext4_sb_info { + unsigned long s_blocks_last; /* Last seen block count */ + loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ + struct buffer_head * s_sbh; /* Buffer containing the super block */ +- struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */ +- struct buffer_head ** s_group_desc; ++ struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ ++ struct buffer_head **s_group_desc; + unsigned long s_mount_opt; + ext4_fsblk_t s_sb_block; + uid_t s_resuid; +@@ -52,23 +52,26 @@ struct ext4_sb_info { + int s_desc_per_block_bits; + int s_inode_size; + int s_first_ino; ++ unsigned int s_inode_readahead_blks; + spinlock_t s_next_gen_lock; + u32 s_next_generation; + u32 s_hash_seed[4]; + int s_def_hash_version; ++ int s_hash_unsigned; /* 3 if hash should be signed, 0 if not */ + struct percpu_counter s_freeblocks_counter; + struct percpu_counter s_freeinodes_counter; + struct percpu_counter s_dirs_counter; ++ struct percpu_counter s_dirtyblocks_counter; + struct blockgroup_lock s_blockgroup_lock; ++ struct proc_dir_entry *s_proc; + + /* root of the per fs reservation window tree */ + spinlock_t s_rsv_window_lock; + struct rb_root s_rsv_window_root; +- struct ext4_reserve_window_node s_rsv_window_head; + + /* Journaling */ +- struct inode * s_journal_inode; +- struct journal_s * s_journal; ++ struct inode *s_journal_inode; ++ struct journal_s *s_journal; + struct list_head s_orphan; + unsigned long s_commit_interval; + struct block_device *journal_bdev; +@@ -106,12 +109,12 @@ struct ext4_sb_info { + + /* tunables */ + unsigned long s_stripe; +- unsigned long s_mb_stream_request; +- unsigned long s_mb_max_to_scan; +- unsigned long s_mb_min_to_scan; +- unsigned long s_mb_stats; +- unsigned long s_mb_order2_reqs; +- unsigned long s_mb_group_prealloc; ++ unsigned int s_mb_stream_request; ++ unsigned int s_mb_max_to_scan; ++ unsigned int s_mb_min_to_scan; ++ unsigned int s_mb_stats; ++ unsigned int s_mb_order2_reqs; ++ unsigned int s_mb_group_prealloc; + /* where last allocation was done - for stream allocation */ + unsigned long s_mb_last_group; + unsigned long s_mb_last_start; +@@ -121,7 +124,6 @@ struct ext4_sb_info { + int s_mb_history_cur; + int s_mb_history_max; + int s_mb_history_num; +- struct proc_dir_entry *s_mb_proc; + spinlock_t s_mb_history_lock; + int s_mb_history_filter; + +diff -rup b/fs/ext4//extents.c a/fs/ext4///extents.c +--- b/fs/ext4/extents.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/extents.c 2009-02-10 21:40:11.000000000 +0100 +@@ -190,7 +190,7 @@ ext4_ext_new_meta_block(handle_t *handle + ext4_fsblk_t goal, newblock; + + goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); +- newblock = ext4_new_meta_block(handle, inode, goal, err); ++ newblock = ext4_new_meta_blocks(handle, inode, goal, NULL, err); + return newblock; + } + +@@ -383,8 +383,8 @@ static void ext4_ext_show_leaf(struct in + ext_debug("\n"); + } + #else +-#define ext4_ext_show_path(inode,path) +-#define ext4_ext_show_leaf(inode,path) ++#define ext4_ext_show_path(inode, path) ++#define ext4_ext_show_leaf(inode, path) + #endif + + void ext4_ext_drop_refs(struct ext4_ext_path *path) +@@ -440,9 +440,10 @@ ext4_ext_binsearch_idx(struct inode *ino + for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) { + if (k != 0 && + le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) { +- printk("k=%d, ix=0x%p, first=0x%p\n", k, +- ix, EXT_FIRST_INDEX(eh)); +- printk("%u <= %u\n", ++ printk(KERN_DEBUG "k=%d, ix=0x%p, " ++ "first=0x%p\n", k, ++ ix, EXT_FIRST_INDEX(eh)); ++ printk(KERN_DEBUG "%u <= %u\n", + le32_to_cpu(ix->ei_block), + le32_to_cpu(ix[-1].ei_block)); + } +@@ -1158,15 +1159,13 @@ ext4_ext_search_right(struct inode *inod + while (--depth >= 0) { + ix = path[depth].p_idx; + if (ix != EXT_LAST_INDEX(path[depth].p_hdr)) +- break; ++ goto got_index; + } + +- if (depth < 0) { +- /* we've gone up to the root and +- * found no index to the right */ +- return 0; +- } ++ /* we've gone up to the root and found no index to the right */ ++ return 0; + ++got_index: + /* we've found index to the right, let's + * follow it and find the closest allocated + * block to the right */ +@@ -1199,7 +1198,6 @@ ext4_ext_search_right(struct inode *inod + *phys = ext_pblock(ex); + put_bh(bh); + return 0; +- + } + + /* +@@ -1475,7 +1473,7 @@ int ext4_ext_insert_extent(handle_t *han + struct ext4_ext_path *path, + struct ext4_extent *newext) + { +- struct ext4_extent_header * eh; ++ struct ext4_extent_header *eh; + struct ext4_extent *ex, *fex; + struct ext4_extent *nearex; /* nearest extent */ + struct ext4_ext_path *npath = NULL; +@@ -1620,7 +1618,6 @@ cleanup: + ext4_ext_drop_refs(npath); + kfree(npath); + } +- ext4_ext_tree_changed(inode); + ext4_ext_invalidate_cache(inode); + return err; + } +@@ -2124,7 +2121,6 @@ static int ext4_ext_remove_space(struct + } + } + out: +- ext4_ext_tree_changed(inode); + ext4_ext_drop_refs(path); + kfree(path); + ext4_journal_stop(handle); +@@ -2142,7 +2138,7 @@ void ext4_ext_init(struct super_block *s + */ + + if (test_opt(sb, EXTENTS)) { +- printk("EXT4-fs: file extents enabled"); ++ printk(KERN_INFO "EXT4-fs: file extents enabled"); + #ifdef AGGRESSIVE_TEST + printk(", aggressive tests"); + #endif +@@ -2271,7 +2267,7 @@ static int ext4_ext_convert_to_initializ + struct inode *inode, + struct ext4_ext_path *path, + ext4_lblk_t iblock, +- unsigned long max_blocks) ++ unsigned int max_blocks) + { + struct ext4_extent *ex, newex, orig_ex; + struct ext4_extent *ex1 = NULL; +@@ -2569,26 +2565,26 @@ fix_extent_len: + */ + int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, + ext4_lblk_t iblock, +- unsigned long max_blocks, struct buffer_head *bh_result, ++ unsigned int max_blocks, struct buffer_head *bh_result, + int create, int extend_disksize) + { + struct ext4_ext_path *path = NULL; + struct ext4_extent_header *eh; + struct ext4_extent newex, *ex; +- ext4_fsblk_t goal, newblock; +- int err = 0, depth, ret; +- unsigned long allocated = 0; ++ ext4_fsblk_t newblock; ++ int err = 0, depth, ret, cache_type; ++ unsigned int allocated = 0; + struct ext4_allocation_request ar; + loff_t disksize; + + __clear_bit(BH_New, &bh_result->b_state); +- ext_debug("blocks %u/%lu requested for inode %u\n", ++ ext_debug("blocks %u/%u requested for inode %u\n", + iblock, max_blocks, inode->i_ino); + + /* check in cache */ +- goal = ext4_ext_in_cache(inode, iblock, &newex); +- if (goal) { +- if (goal == EXT4_EXT_CACHE_GAP) { ++ cache_type = ext4_ext_in_cache(inode, iblock, &newex); ++ if (cache_type) { ++ if (cache_type == EXT4_EXT_CACHE_GAP) { + if (!create) { + /* + * block isn't allocated yet and +@@ -2597,7 +2593,7 @@ int ext4_ext_get_blocks(handle_t *handle + goto out2; + } + /* we should allocate requested block */ +- } else if (goal == EXT4_EXT_CACHE_EXTENT) { ++ } else if (cache_type == EXT4_EXT_CACHE_EXTENT) { + /* block is already allocated */ + newblock = iblock + - le32_to_cpu(newex.ee_block) +@@ -2696,11 +2692,8 @@ int ext4_ext_get_blocks(handle_t *handle + goto out2; + } + /* +- * Okay, we need to do block allocation. Lazily initialize the block +- * allocation info here if necessary. ++ * Okay, we need to do block allocation. + */ +- if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info)) +- ext4_init_block_alloc_info(inode); + + /* find neighbour allocated blocks */ + ar.lleft = iblock; +@@ -2748,7 +2741,7 @@ int ext4_ext_get_blocks(handle_t *handle + if (!newblock) + goto out2; + ext_debug("allocate new block: goal %llu, found %llu/%lu\n", +- goal, newblock, allocated); ++ ar.goal, newblock, allocated); + + /* try to insert new extent into found leaf and return */ + ext4_ext_store_pblock(&newex, newblock); +@@ -2760,7 +2753,7 @@ int ext4_ext_get_blocks(handle_t *handle + /* free data blocks we just allocated */ + /* not a good idea to call discard here directly, + * but otherwise we'd need to call it every free() */ +- ext4_mb_discard_inode_preallocations(inode); ++ ext4_discard_preallocations(inode); + ext4_free_blocks(handle, inode, ext_pblock(&newex), + ext4_ext_get_actual_len(&newex), 0); + goto out2; +@@ -2824,7 +2817,7 @@ void ext4_ext_truncate(struct inode *ino + down_write(&EXT4_I(inode)->i_data_sem); + ext4_ext_invalidate_cache(inode); + +- ext4_discard_reservation(inode); ++ ext4_discard_preallocations(inode); + + /* + * TODO: optimization is possible here. +@@ -2877,10 +2870,11 @@ static void ext4_falloc_update_inode(str + * Update only when preallocation was requested beyond + * the file size. + */ +- if (!(mode & FALLOC_FL_KEEP_SIZE) && +- new_size > i_size_read(inode)) { +- i_size_write(inode, new_size); +- EXT4_I(inode)->i_disksize = new_size; ++ if (!(mode & FALLOC_FL_KEEP_SIZE)) { ++ if (new_size > i_size_read(inode)) ++ i_size_write(inode, new_size); ++ if (new_size > EXT4_I(inode)->i_disksize) ++ ext4_update_i_disksize(inode, new_size); + } + + } +@@ -2897,7 +2891,7 @@ long ext4_fallocate(struct inode *inode, + handle_t *handle; + ext4_lblk_t block; + loff_t new_size; +- unsigned long max_blocks; ++ unsigned int max_blocks; + int ret = 0; + int ret2 = 0; + int retries = 0; +diff -rup b/fs/ext4//file.c a/fs/ext4///file.c +--- b/fs/ext4/file.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/file.c 2009-02-10 21:40:11.000000000 +0100 +@@ -31,14 +31,14 @@ + * from ext4_file_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +-static int ext4_release_file (struct inode * inode, struct file * filp) ++static int ext4_release_file(struct inode *inode, struct file *filp) + { + /* if we are the last writer on the inode, drop the block reservation */ + if ((filp->f_mode & FMODE_WRITE) && + (atomic_read(&inode->i_writecount) == 1)) + { + down_write(&EXT4_I(inode)->i_data_sem); +- ext4_discard_reservation(inode); ++ ext4_discard_preallocations(inode); + up_write(&EXT4_I(inode)->i_data_sem); + } + if (is_dx(inode) && filp->private_data) +@@ -162,7 +162,7 @@ const struct inode_operations ext4_file_ + .truncate = ext4_truncate, + .setattr = ext4_setattr, + .getattr = ext4_getattr, +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext4_listxattr, +diff -rup b/fs/ext4//fsync.c a/fs/ext4///fsync.c +--- b/fs/ext4/fsync.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/fsync.c 2009-02-10 21:40:11.000000000 +0100 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include "ext4.h" + #include "ext4_jbd2.h" + +@@ -43,7 +44,7 @@ + * inode to disk. + */ + +-int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync) ++int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) + { + struct inode *inode = dentry->d_inode; + journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; +@@ -51,6 +52,10 @@ int ext4_sync_file(struct file * file, s + + J_ASSERT(ext4_journal_current_handle() == NULL); + ++ trace_mark(ext4_sync_file, "dev %s datasync %d ino %ld parent %ld", ++ inode->i_sb->s_id, datasync, inode->i_ino, ++ dentry->d_parent->d_inode->i_ino); ++ + /* + * data=writeback: + * The caller's filemap_fdatawrite()/wait will sync the data. +diff -rup b/fs/ext4//hash.c a/fs/ext4///hash.c +--- b/fs/ext4/hash.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/hash.c 2009-02-10 21:40:11.000000000 +0100 +@@ -27,7 +27,7 @@ static void TEA_transform(__u32 buf[4], + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); +- } while(--n); ++ } while (--n); + + buf[0] += b0; + buf[1] += b1; +@@ -35,23 +35,43 @@ static void TEA_transform(__u32 buf[4], + + + /* The old legacy hash */ +-static __u32 dx_hack_hash (const char *name, int len) ++static __u32 dx_hack_hash_unsigned(const char *name, int len) + { +- __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; ++ __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; ++ const unsigned char *ucp = (const unsigned char *) name; ++ ++ while (len--) { ++ hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373)); ++ ++ if (hash & 0x80000000) ++ hash -= 0x7fffffff; ++ hash1 = hash0; ++ hash0 = hash; ++ } ++ return hash0 << 1; ++} ++ ++static __u32 dx_hack_hash_signed(const char *name, int len) ++{ ++ __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; ++ const signed char *scp = (const signed char *) name; ++ + while (len--) { +- __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373)); ++ hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); + +- if (hash & 0x80000000) hash -= 0x7fffffff; ++ if (hash & 0x80000000) ++ hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } +- return (hash0 << 1); ++ return hash0 << 1; + } + +-static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) ++static void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num) + { + __u32 pad, val; + int i; ++ const signed char *scp = (const signed char *) msg; + + pad = (__u32)len | ((__u32)len << 8); + pad |= pad << 16; +@@ -59,10 +79,38 @@ static void str2hashbuf(const char *msg, + val = pad; + if (len > num*4) + len = num * 4; +- for (i=0; i < len; i++) { ++ for (i = 0; i < len; i++) { + if ((i % 4) == 0) + val = pad; +- val = msg[i] + (val << 8); ++ val = ((int) scp[i]) + (val << 8); ++ if ((i % 4) == 3) { ++ *buf++ = val; ++ val = pad; ++ num--; ++ } ++ } ++ if (--num >= 0) ++ *buf++ = val; ++ while (--num >= 0) ++ *buf++ = pad; ++} ++ ++static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) ++{ ++ __u32 pad, val; ++ int i; ++ const unsigned char *ucp = (const unsigned char *) msg; ++ ++ pad = (__u32)len | ((__u32)len << 8); ++ pad |= pad << 16; ++ ++ val = pad; ++ if (len > num*4) ++ len = num * 4; ++ for (i = 0; i < len; i++) { ++ if ((i % 4) == 0) ++ val = pad; ++ val = ((int) ucp[i]) + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; +@@ -95,6 +143,8 @@ int ext4fs_dirhash(const char *name, int + const char *p; + int i; + __u32 in[8], buf[4]; ++ void (*str2hashbuf)(const char *, int, __u32 *, int) = ++ str2hashbuf_signed; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; +@@ -104,7 +154,7 @@ int ext4fs_dirhash(const char *name, int + + /* Check to see if the seed is all zero's */ + if (hinfo->seed) { +- for (i=0; i < 4; i++) { ++ for (i = 0; i < 4; i++) { + if (hinfo->seed[i]) + break; + } +@@ -113,13 +163,18 @@ int ext4fs_dirhash(const char *name, int + } + + switch (hinfo->hash_version) { ++ case DX_HASH_LEGACY_UNSIGNED: ++ hash = dx_hack_hash_unsigned(name, len); ++ break; + case DX_HASH_LEGACY: +- hash = dx_hack_hash(name, len); ++ hash = dx_hack_hash_signed(name, len); + break; ++ case DX_HASH_HALF_MD4_UNSIGNED: ++ str2hashbuf = str2hashbuf_unsigned; + case DX_HASH_HALF_MD4: + p = name; + while (len > 0) { +- str2hashbuf(p, len, in, 8); ++ (*str2hashbuf)(p, len, in, 8); + half_md4_transform(buf, in); + len -= 32; + p += 32; +@@ -127,10 +182,12 @@ int ext4fs_dirhash(const char *name, int + minor_hash = buf[2]; + hash = buf[1]; + break; ++ case DX_HASH_TEA_UNSIGNED: ++ str2hashbuf = str2hashbuf_unsigned; + case DX_HASH_TEA: + p = name; + while (len > 0) { +- str2hashbuf(p, len, in, 4); ++ (*str2hashbuf)(p, len, in, 4); + TEA_transform(buf, in); + len -= 16; + p += 16; +diff -rup b/fs/ext4//ialloc.c a/fs/ext4///ialloc.c +--- b/fs/ext4/ialloc.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/ialloc.c 2009-02-10 21:40:11.000000000 +0100 +@@ -74,17 +74,17 @@ unsigned ext4_init_inode_bitmap(struct s + /* If checksum is bad mark all blocks and inodes use to prevent + * allocation, essentially implementing a per-group read-only flag. */ + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { +- ext4_error(sb, __func__, "Checksum bad for group %lu\n", ++ ext4_error(sb, __func__, "Checksum bad for group %u\n", + block_group); +- gdp->bg_free_blocks_count = 0; +- gdp->bg_free_inodes_count = 0; +- gdp->bg_itable_unused = 0; ++ ext4_free_blks_set(sb, gdp, 0); ++ ext4_free_inodes_set(sb, gdp, 0); ++ ext4_itable_unused_set(sb, gdp, 0); + memset(bh->b_data, 0xff, sb->s_blocksize); + return 0; + } + + memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); +- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), ++ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, + bh->b_data); + + return EXT4_INODES_PER_GROUP(sb); +@@ -111,27 +111,49 @@ ext4_read_inode_bitmap(struct super_bloc + if (unlikely(!bh)) { + ext4_error(sb, __func__, + "Cannot read inode bitmap - " +- "block_group = %lu, inode_bitmap = %llu", ++ "block_group = %u, inode_bitmap = %llu", + block_group, bitmap_blk); + return NULL; + } +- if (bh_uptodate_or_lock(bh)) ++ if (bitmap_uptodate(bh)) + return bh; + ++ lock_buffer(bh); ++ if (bitmap_uptodate(bh)) { ++ unlock_buffer(bh); ++ return bh; ++ } + spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { + ext4_init_inode_bitmap(sb, bh, block_group, desc); ++ set_bitmap_uptodate(bh); + set_buffer_uptodate(bh); +- unlock_buffer(bh); + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); ++ unlock_buffer(bh); + return bh; + } + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); ++ if (buffer_uptodate(bh)) { ++ /* ++ * if not uninit if bh is uptodate, ++ * bitmap is also uptodate ++ */ ++ set_bitmap_uptodate(bh); ++ unlock_buffer(bh); ++ return bh; ++ } ++ /* ++ * submit the buffer_head for read. We can ++ * safely mark the bitmap as uptodate now. ++ * We do it here so the bitmap uptodate bit ++ * get set with buffer lock held. ++ */ ++ set_bitmap_uptodate(bh); + if (bh_submit_read(bh) < 0) { + put_bh(bh); + ext4_error(sb, __func__, + "Cannot read inode bitmap - " +- "block_group = %lu, inode_bitmap = %llu", ++ "block_group = %u, inode_bitmap = %llu", + block_group, bitmap_blk); + return NULL; + } +@@ -154,39 +176,40 @@ ext4_read_inode_bitmap(struct super_bloc + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ +-void ext4_free_inode (handle_t *handle, struct inode * inode) ++void ext4_free_inode(handle_t *handle, struct inode *inode) + { +- struct super_block * sb = inode->i_sb; ++ struct super_block *sb = inode->i_sb; + int is_directory; + unsigned long ino; + struct buffer_head *bitmap_bh = NULL; + struct buffer_head *bh2; + ext4_group_t block_group; + unsigned long bit; +- struct ext4_group_desc * gdp; +- struct ext4_super_block * es; ++ struct ext4_group_desc *gdp; ++ struct ext4_super_block *es; + struct ext4_sb_info *sbi; +- int fatal = 0, err; ++ int fatal = 0, err, count; + ext4_group_t flex_group; + + if (atomic_read(&inode->i_count) > 1) { +- printk ("ext4_free_inode: inode has count=%d\n", +- atomic_read(&inode->i_count)); ++ printk(KERN_ERR "ext4_free_inode: inode has count=%d\n", ++ atomic_read(&inode->i_count)); + return; + } + if (inode->i_nlink) { +- printk ("ext4_free_inode: inode has nlink=%d\n", +- inode->i_nlink); ++ printk(KERN_ERR "ext4_free_inode: inode has nlink=%d\n", ++ inode->i_nlink); + return; + } + if (!sb) { +- printk("ext4_free_inode: inode on nonexistent device\n"); ++ printk(KERN_ERR "ext4_free_inode: inode on " ++ "nonexistent device\n"); + return; + } + sbi = EXT4_SB(sb); + + ino = inode->i_ino; +- ext4_debug ("freeing inode %lu\n", ino); ++ ext4_debug("freeing inode %lu\n", ino); + + /* + * Note: we must free any quota before locking the superblock, +@@ -200,12 +223,12 @@ void ext4_free_inode (handle_t *handle, + is_directory = S_ISDIR(inode->i_mode); + + /* Do this BEFORE marking the inode not in use or returning an error */ +- clear_inode (inode); ++ clear_inode(inode); + + es = EXT4_SB(sb)->s_es; + if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { +- ext4_error (sb, "ext4_free_inode", +- "reserved or nonexistent inode %lu", ino); ++ ext4_error(sb, "ext4_free_inode", ++ "reserved or nonexistent inode %lu", ino); + goto error_return; + } + block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); +@@ -222,10 +245,10 @@ void ext4_free_inode (handle_t *handle, + /* Ok, now we can actually update the inode bitmaps.. */ + if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit, bitmap_bh->b_data)) +- ext4_error (sb, "ext4_free_inode", +- "bit already cleared for inode %lu", ino); ++ ext4_error(sb, "ext4_free_inode", ++ "bit already cleared for inode %lu", ino); + else { +- gdp = ext4_get_group_desc (sb, block_group, &bh2); ++ gdp = ext4_get_group_desc(sb, block_group, &bh2); + + BUFFER_TRACE(bh2, "get_write_access"); + fatal = ext4_journal_get_write_access(handle, bh2); +@@ -233,9 +256,12 @@ void ext4_free_inode (handle_t *handle, + + if (gdp) { + spin_lock(sb_bgl_lock(sbi, block_group)); +- le16_add_cpu(&gdp->bg_free_inodes_count, 1); +- if (is_directory) +- le16_add_cpu(&gdp->bg_used_dirs_count, -1); ++ count = ext4_free_inodes_count(sb, gdp) + 1; ++ ext4_free_inodes_set(sb, gdp, count); ++ if (is_directory) { ++ count = ext4_used_dirs_count(sb, gdp) - 1; ++ ext4_used_dirs_set(sb, gdp, count); ++ } + gdp->bg_checksum = ext4_group_desc_csum(sbi, + block_group, gdp); + spin_unlock(sb_bgl_lock(sbi, block_group)); +@@ -287,14 +313,14 @@ static int find_group_dir(struct super_b + avefreei = freei / ngroups; + + for (group = 0; group < ngroups; group++) { +- desc = ext4_get_group_desc (sb, group, NULL); +- if (!desc || !desc->bg_free_inodes_count) ++ desc = ext4_get_group_desc(sb, group, NULL); ++ if (!desc || !ext4_free_inodes_count(sb, desc)) + continue; +- if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) ++ if (ext4_free_inodes_count(sb, desc) < avefreei) + continue; + if (!best_desc || +- (le16_to_cpu(desc->bg_free_blocks_count) > +- le16_to_cpu(best_desc->bg_free_blocks_count))) { ++ (ext4_free_blks_count(sb, desc) > ++ ext4_free_blks_count(sb, best_desc))) { + *best_group = group; + best_desc = desc; + ret = 0; +@@ -366,7 +392,7 @@ found_flexbg: + for (i = best_flex * flex_size; i < ngroups && + i < (best_flex + 1) * flex_size; i++) { + desc = ext4_get_group_desc(sb, i, &bh); +- if (le16_to_cpu(desc->bg_free_inodes_count)) { ++ if (ext4_free_inodes_count(sb, desc)) { + *best_group = i; + goto out; + } +@@ -440,17 +466,17 @@ static int find_group_orlov(struct super + for (i = 0; i < ngroups; i++) { + grp = (parent_group + i) % ngroups; + desc = ext4_get_group_desc(sb, grp, NULL); +- if (!desc || !desc->bg_free_inodes_count) ++ if (!desc || !ext4_free_inodes_count(sb, desc)) + continue; +- if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) ++ if (ext4_used_dirs_count(sb, desc) >= best_ndir) + continue; +- if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) ++ if (ext4_free_inodes_count(sb, desc) < avefreei) + continue; +- if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) ++ if (ext4_free_blks_count(sb, desc) < avefreeb) + continue; + *group = grp; + ret = 0; +- best_ndir = le16_to_cpu(desc->bg_used_dirs_count); ++ best_ndir = ext4_used_dirs_count(sb, desc); + } + if (ret == 0) + return ret; +@@ -476,13 +502,13 @@ static int find_group_orlov(struct super + for (i = 0; i < ngroups; i++) { + *group = (parent_group + i) % ngroups; + desc = ext4_get_group_desc(sb, *group, NULL); +- if (!desc || !desc->bg_free_inodes_count) ++ if (!desc || !ext4_free_inodes_count(sb, desc)) + continue; +- if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) ++ if (ext4_used_dirs_count(sb, desc) >= max_dirs) + continue; +- if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) ++ if (ext4_free_inodes_count(sb, desc) < min_inodes) + continue; +- if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) ++ if (ext4_free_blks_count(sb, desc) < min_blocks) + continue; + return 0; + } +@@ -491,8 +517,8 @@ fallback: + for (i = 0; i < ngroups; i++) { + *group = (parent_group + i) % ngroups; + desc = ext4_get_group_desc(sb, *group, NULL); +- if (desc && desc->bg_free_inodes_count && +- le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) ++ if (desc && ext4_free_inodes_count(sb, desc) && ++ ext4_free_inodes_count(sb, desc) >= avefreei) + return 0; + } + +@@ -521,8 +547,8 @@ static int find_group_other(struct super + */ + *group = parent_group; + desc = ext4_get_group_desc(sb, *group, NULL); +- if (desc && le16_to_cpu(desc->bg_free_inodes_count) && +- le16_to_cpu(desc->bg_free_blocks_count)) ++ if (desc && ext4_free_inodes_count(sb, desc) && ++ ext4_free_blks_count(sb, desc)) + return 0; + + /* +@@ -545,8 +571,8 @@ static int find_group_other(struct super + if (*group >= ngroups) + *group -= ngroups; + desc = ext4_get_group_desc(sb, *group, NULL); +- if (desc && le16_to_cpu(desc->bg_free_inodes_count) && +- le16_to_cpu(desc->bg_free_blocks_count)) ++ if (desc && ext4_free_inodes_count(sb, desc) && ++ ext4_free_blks_count(sb, desc)) + return 0; + } + +@@ -559,7 +585,7 @@ static int find_group_other(struct super + if (++*group >= ngroups) + *group = 0; + desc = ext4_get_group_desc(sb, *group, NULL); +- if (desc && le16_to_cpu(desc->bg_free_inodes_count)) ++ if (desc && ext4_free_inodes_count(sb, desc)) + return 0; + } + +@@ -567,6 +593,79 @@ static int find_group_other(struct super + } + + /* ++ * claim the inode from the inode bitmap. If the group ++ * is uninit we need to take the groups's sb_bgl_lock ++ * and clear the uninit flag. The inode bitmap update ++ * and group desc uninit flag clear should be done ++ * after holding sb_bgl_lock so that ext4_read_inode_bitmap ++ * doesn't race with the ext4_claim_inode ++ */ ++static int ext4_claim_inode(struct super_block *sb, ++ struct buffer_head *inode_bitmap_bh, ++ unsigned long ino, ext4_group_t group, int mode) ++{ ++ int free = 0, retval = 0, count; ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); ++ ++ spin_lock(sb_bgl_lock(sbi, group)); ++ if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) { ++ /* not a free inode */ ++ retval = 1; ++ goto err_ret; ++ } ++ ino++; ++ if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || ++ ino > EXT4_INODES_PER_GROUP(sb)) { ++ spin_unlock(sb_bgl_lock(sbi, group)); ++ ext4_error(sb, __func__, ++ "reserved inode or inode > inodes count - " ++ "block_group = %u, inode=%lu", group, ++ ino + group * EXT4_INODES_PER_GROUP(sb)); ++ return 1; ++ } ++ /* If we didn't allocate from within the initialized part of the inode ++ * table then we need to initialize up to this inode. */ ++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { ++ ++ if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { ++ gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); ++ /* When marking the block group with ++ * ~EXT4_BG_INODE_UNINIT we don't want to depend ++ * on the value of bg_itable_unused even though ++ * mke2fs could have initialized the same for us. ++ * Instead we calculated the value below ++ */ ++ ++ free = 0; ++ } else { ++ free = EXT4_INODES_PER_GROUP(sb) - ++ ext4_itable_unused_count(sb, gdp); ++ } ++ ++ /* ++ * Check the relative inode number against the last used ++ * relative inode number in this group. if it is greater ++ * we need to update the bg_itable_unused count ++ * ++ */ ++ if (ino > free) ++ ext4_itable_unused_set(sb, gdp, ++ (EXT4_INODES_PER_GROUP(sb) - ino)); ++ } ++ count = ext4_free_inodes_count(sb, gdp) - 1; ++ ext4_free_inodes_set(sb, gdp, count); ++ if (S_ISDIR(mode)) { ++ count = ext4_used_dirs_count(sb, gdp) + 1; ++ ext4_used_dirs_set(sb, gdp, count); ++ } ++ gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); ++err_ret: ++ spin_unlock(sb_bgl_lock(sbi, group)); ++ return retval; ++} ++ ++/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of +@@ -576,16 +675,16 @@ static int find_group_other(struct super + * For other inodes, search forward from the parent directory's block + * group to find a free inode. + */ +-struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode) ++struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) + { + struct super_block *sb; +- struct buffer_head *bitmap_bh = NULL; +- struct buffer_head *bh2; ++ struct buffer_head *inode_bitmap_bh = NULL; ++ struct buffer_head *group_desc_bh; + ext4_group_t group = 0; + unsigned long ino = 0; +- struct inode * inode; +- struct ext4_group_desc * gdp = NULL; +- struct ext4_super_block * es; ++ struct inode *inode; ++ struct ext4_group_desc *gdp = NULL; ++ struct ext4_super_block *es; + struct ext4_inode_info *ei; + struct ext4_sb_info *sbi; + int ret2, err = 0; +@@ -613,7 +712,7 @@ struct inode *ext4_new_inode(handle_t *h + } + + if (S_ISDIR(mode)) { +- if (test_opt (sb, OLDALLOC)) ++ if (test_opt(sb, OLDALLOC)) + ret2 = find_group_dir(sb, dir, &group); + else + ret2 = find_group_orlov(sb, dir, &group); +@@ -628,40 +727,50 @@ got_group: + for (i = 0; i < sbi->s_groups_count; i++) { + err = -EIO; + +- gdp = ext4_get_group_desc(sb, group, &bh2); ++ gdp = ext4_get_group_desc(sb, group, &group_desc_bh); + if (!gdp) + goto fail; + +- brelse(bitmap_bh); +- bitmap_bh = ext4_read_inode_bitmap(sb, group); +- if (!bitmap_bh) ++ brelse(inode_bitmap_bh); ++ inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); ++ if (!inode_bitmap_bh) + goto fail; + + ino = 0; + + repeat_in_this_group: + ino = ext4_find_next_zero_bit((unsigned long *) +- bitmap_bh->b_data, EXT4_INODES_PER_GROUP(sb), ino); ++ inode_bitmap_bh->b_data, ++ EXT4_INODES_PER_GROUP(sb), ino); + if (ino < EXT4_INODES_PER_GROUP(sb)) { + +- BUFFER_TRACE(bitmap_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bitmap_bh); ++ BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); ++ err = ext4_journal_get_write_access(handle, ++ inode_bitmap_bh); + if (err) + goto fail; + +- if (!ext4_set_bit_atomic(sb_bgl_lock(sbi, group), +- ino, bitmap_bh->b_data)) { ++ BUFFER_TRACE(group_desc_bh, "get_write_access"); ++ err = ext4_journal_get_write_access(handle, ++ group_desc_bh); ++ if (err) ++ goto fail; ++ if (!ext4_claim_inode(sb, inode_bitmap_bh, ++ ino, group, mode)) { + /* we won it */ +- BUFFER_TRACE(bitmap_bh, ++ BUFFER_TRACE(inode_bitmap_bh, + "call ext4_journal_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, +- bitmap_bh); ++ inode_bitmap_bh); + if (err) + goto fail; ++ /* zero bit is inode number 1*/ ++ ino++; + goto got; + } + /* we lost it */ +- jbd2_journal_release_buffer(handle, bitmap_bh); ++ jbd2_journal_release_buffer(handle, inode_bitmap_bh); ++ jbd2_journal_release_buffer(handle, group_desc_bh); + + if (++ino < EXT4_INODES_PER_GROUP(sb)) + goto repeat_in_this_group; +@@ -681,30 +790,16 @@ repeat_in_this_group: + goto out; + + got: +- ino++; +- if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || +- ino > EXT4_INODES_PER_GROUP(sb)) { +- ext4_error(sb, __func__, +- "reserved inode or inode > inodes count - " +- "block_group = %lu, inode=%lu", group, +- ino + group * EXT4_INODES_PER_GROUP(sb)); +- err = -EIO; +- goto fail; +- } +- +- BUFFER_TRACE(bh2, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh2); +- if (err) goto fail; +- + /* We may have to initialize the block bitmap if it isn't already */ + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && + gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { +- struct buffer_head *block_bh = ext4_read_block_bitmap(sb, group); ++ struct buffer_head *block_bitmap_bh; + +- BUFFER_TRACE(block_bh, "get block bitmap access"); +- err = ext4_journal_get_write_access(handle, block_bh); ++ block_bitmap_bh = ext4_read_block_bitmap(sb, group); ++ BUFFER_TRACE(block_bitmap_bh, "get block bitmap access"); ++ err = ext4_journal_get_write_access(handle, block_bitmap_bh); + if (err) { +- brelse(block_bh); ++ brelse(block_bitmap_bh); + goto fail; + } + +@@ -712,9 +807,9 @@ got: + spin_lock(sb_bgl_lock(sbi, group)); + /* recheck and clear flag under lock if we still need to */ + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { +- gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); + free = ext4_free_blocks_after_init(sb, group, gdp); +- gdp->bg_free_blocks_count = cpu_to_le16(free); ++ gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ++ ext4_free_blks_set(sb, gdp, free); + gdp->bg_checksum = ext4_group_desc_csum(sbi, group, + gdp); + } +@@ -722,55 +817,19 @@ got: + + /* Don't need to dirty bitmap block if we didn't change it */ + if (free) { +- BUFFER_TRACE(block_bh, "dirty block bitmap"); +- err = ext4_journal_dirty_metadata(handle, block_bh); ++ BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap"); ++ err = ext4_journal_dirty_metadata(handle, ++ block_bitmap_bh); + } + +- brelse(block_bh); ++ brelse(block_bitmap_bh); + if (err) + goto fail; + } +- +- spin_lock(sb_bgl_lock(sbi, group)); +- /* If we didn't allocate from within the initialized part of the inode +- * table then we need to initialize up to this inode. */ +- if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { +- if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { +- gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); +- +- /* When marking the block group with +- * ~EXT4_BG_INODE_UNINIT we don't want to depend +- * on the value of bg_itable_unused even though +- * mke2fs could have initialized the same for us. +- * Instead we calculated the value below +- */ +- +- free = 0; +- } else { +- free = EXT4_INODES_PER_GROUP(sb) - +- le16_to_cpu(gdp->bg_itable_unused); +- } +- +- /* +- * Check the relative inode number against the last used +- * relative inode number in this group. if it is greater +- * we need to update the bg_itable_unused count +- * +- */ +- if (ino > free) +- gdp->bg_itable_unused = +- cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino); +- } +- +- le16_add_cpu(&gdp->bg_free_inodes_count, -1); +- if (S_ISDIR(mode)) { +- le16_add_cpu(&gdp->bg_used_dirs_count, 1); +- } +- gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); +- spin_unlock(sb_bgl_lock(sbi, group)); +- BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); +- err = ext4_journal_dirty_metadata(handle, bh2); +- if (err) goto fail; ++ BUFFER_TRACE(group_desc_bh, "call ext4_journal_dirty_metadata"); ++ err = ext4_journal_dirty_metadata(handle, group_desc_bh); ++ if (err) ++ goto fail; + + percpu_counter_dec(&sbi->s_freeinodes_counter); + if (S_ISDIR(mode)) +@@ -784,15 +843,15 @@ got: + spin_unlock(sb_bgl_lock(sbi, flex_group)); + } + +- inode->i_uid = current->fsuid; +- if (test_opt (sb, GRPID)) ++ inode->i_uid = current_fsuid(); ++ if (test_opt(sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else +- inode->i_gid = current->fsgid; ++ inode->i_gid = current_fsgid(); + inode->i_mode = mode; + + inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); +@@ -818,7 +877,6 @@ got: + ei->i_flags &= ~EXT4_DIRSYNC_FL; + ei->i_file_acl = 0; + ei->i_dtime = 0; +- ei->i_block_alloc_info = NULL; + ei->i_block_group = group; + + ext4_set_inode_flags(inode); +@@ -834,7 +892,7 @@ got: + ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; + + ret = inode; +- if(DQUOT_ALLOC_INODE(inode)) { ++ if (DQUOT_ALLOC_INODE(inode)) { + err = -EDQUOT; + goto fail_drop; + } +@@ -843,7 +901,7 @@ got: + if (err) + goto fail_free_drop; + +- err = ext4_init_security(handle,inode, dir); ++ err = ext4_init_security(handle, inode, dir); + if (err) + goto fail_free_drop; + +@@ -869,7 +927,7 @@ out: + iput(inode); + ret = ERR_PTR(err); + really_out: +- brelse(bitmap_bh); ++ brelse(inode_bitmap_bh); + return ret; + + fail_free_drop: +@@ -880,7 +938,7 @@ fail_drop: + inode->i_flags |= S_NOQUOTA; + inode->i_nlink = 0; + iput(inode); +- brelse(bitmap_bh); ++ brelse(inode_bitmap_bh); + return ERR_PTR(err); + } + +@@ -961,7 +1019,7 @@ error: + return ERR_PTR(err); + } + +-unsigned long ext4_count_free_inodes (struct super_block * sb) ++unsigned long ext4_count_free_inodes(struct super_block *sb) + { + unsigned long desc_count; + struct ext4_group_desc *gdp; +@@ -976,10 +1034,10 @@ unsigned long ext4_count_free_inodes (st + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { +- gdp = ext4_get_group_desc (sb, i, NULL); ++ gdp = ext4_get_group_desc(sb, i, NULL); + if (!gdp) + continue; +- desc_count += le16_to_cpu(gdp->bg_free_inodes_count); ++ desc_count += ext4_free_inodes_count(sb, gdp); + brelse(bitmap_bh); + bitmap_bh = ext4_read_inode_bitmap(sb, i); + if (!bitmap_bh) +@@ -987,20 +1045,21 @@ unsigned long ext4_count_free_inodes (st + + x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8); + printk(KERN_DEBUG "group %lu: stored = %d, counted = %lu\n", +- i, le16_to_cpu(gdp->bg_free_inodes_count), x); ++ i, ext4_free_inodes_count(sb, gdp), x); + bitmap_count += x; + } + brelse(bitmap_bh); +- printk("ext4_count_free_inodes: stored = %u, computed = %lu, %lu\n", +- le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); ++ printk(KERN_DEBUG "ext4_count_free_inodes: " ++ "stored = %u, computed = %lu, %lu\n", ++ le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); + return desc_count; + #else + desc_count = 0; + for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { +- gdp = ext4_get_group_desc (sb, i, NULL); ++ gdp = ext4_get_group_desc(sb, i, NULL); + if (!gdp) + continue; +- desc_count += le16_to_cpu(gdp->bg_free_inodes_count); ++ desc_count += ext4_free_inodes_count(sb, gdp); + cond_resched(); + } + return desc_count; +@@ -1008,16 +1067,16 @@ unsigned long ext4_count_free_inodes (st + } + + /* Called at mount-time, super-block is locked */ +-unsigned long ext4_count_dirs (struct super_block * sb) ++unsigned long ext4_count_dirs(struct super_block * sb) + { + unsigned long count = 0; + ext4_group_t i; + + for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { +- struct ext4_group_desc *gdp = ext4_get_group_desc (sb, i, NULL); ++ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); + if (!gdp) + continue; +- count += le16_to_cpu(gdp->bg_used_dirs_count); ++ count += ext4_used_dirs_count(sb, gdp); + } + return count; + } +diff -rup b/fs/ext4//inode.c a/fs/ext4///inode.c +--- b/fs/ext4/inode.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/inode.c 2009-02-11 01:08:42.000000000 +0100 +@@ -190,7 +190,7 @@ static int ext4_journal_test_restart(han + /* + * Called at the last iput() if i_nlink is zero. + */ +-void ext4_delete_inode (struct inode * inode) ++void ext4_delete_inode(struct inode *inode) + { + handle_t *handle; + int err; +@@ -330,11 +330,11 @@ static int ext4_block_to_path(struct ino + int final = 0; + + if (i_block < 0) { +- ext4_warning (inode->i_sb, "ext4_block_to_path", "block < 0"); ++ ext4_warning(inode->i_sb, "ext4_block_to_path", "block < 0"); + } else if (i_block < direct_blocks) { + offsets[n++] = i_block; + final = direct_blocks; +- } else if ( (i_block -= direct_blocks) < indirect_blocks) { ++ } else if ((i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = EXT4_IND_BLOCK; + offsets[n++] = i_block; + final = ptrs; +@@ -400,14 +400,14 @@ static Indirect *ext4_get_branch(struct + + *err = 0; + /* i_data is not going away, no lock needed */ +- add_chain (chain, NULL, EXT4_I(inode)->i_data + *offsets); ++ add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + bh = sb_bread(sb, le32_to_cpu(p->key)); + if (!bh) + goto failure; +- add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); ++ add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; +@@ -443,7 +443,7 @@ no_block: + static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) + { + struct ext4_inode_info *ei = EXT4_I(inode); +- __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data; ++ __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data; + __le32 *p; + ext4_fsblk_t bg_start; + ext4_fsblk_t last_block; +@@ -486,18 +486,9 @@ static ext4_fsblk_t ext4_find_near(struc + static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, + Indirect *partial) + { +- struct ext4_block_alloc_info *block_i; +- +- block_i = EXT4_I(inode)->i_block_alloc_info; +- + /* +- * try the heuristic for sequential allocation, +- * failing that at least try to get decent locality. ++ * XXX need to get goal block from mballoc's data structures + */ +- if (block_i && (block == block_i->last_alloc_logical_block + 1) +- && (block_i->last_alloc_physical_block != 0)) { +- return block_i->last_alloc_physical_block + 1; +- } + + return ext4_find_near(inode, partial); + } +@@ -514,10 +505,10 @@ static ext4_fsblk_t ext4_find_goal(struc + * return the total number of blocks to be allocate, including the + * direct and indirect blocks. + */ +-static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned long blks, ++static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, + int blocks_to_boundary) + { +- unsigned long count = 0; ++ unsigned int count = 0; + + /* + * Simple case, [t,d]Indirect block(s) has not allocated yet +@@ -555,6 +546,7 @@ static int ext4_alloc_blocks(handle_t *h + int indirect_blks, int blks, + ext4_fsblk_t new_blocks[4], int *err) + { ++ struct ext4_allocation_request ar; + int target, i; + unsigned long count = 0, blk_allocated = 0; + int index = 0; +@@ -603,10 +595,15 @@ static int ext4_alloc_blocks(handle_t *h + if (!target) + goto allocated; + /* Now allocate data blocks */ +- count = target; +- /* allocating blocks for data blocks */ +- current_block = ext4_new_blocks(handle, inode, iblock, +- goal, &count, err); ++ memset(&ar, 0, sizeof(ar)); ++ ar.inode = inode; ++ ar.goal = goal; ++ ar.len = target; ++ ar.logical = iblock; ++ ar.flags = EXT4_MB_HINT_DATA; ++ ++ current_block = ext4_mb_new_blocks(handle, &ar, err); ++ + if (*err && (target == blks)) { + /* + * if the allocation failed and we didn't allocate +@@ -622,7 +619,7 @@ static int ext4_alloc_blocks(handle_t *h + */ + new_blocks[index] = current_block; + } +- blk_allocated += count; ++ blk_allocated += ar.len; + } + allocated: + /* total number of blocks allocated for direct blocks */ +@@ -630,7 +627,7 @@ allocated: + *err = 0; + return ret; + failed_out: +- for (i = 0; i b_data + offsets[n]; + branch[n].key = cpu_to_le32(new_blocks[n]); + *branch[n].p = branch[n].key; +- if ( n == indirect_blks) { ++ if (n == indirect_blks) { + current_block = new_blocks[n]; + /* + * End of chain, update the last new metablock of +@@ -730,7 +727,7 @@ failed: + BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget"); + ext4_journal_forget(handle, branch[i].bh); + } +- for (i = 0; i i_block_alloc_info; + /* + * If we're splicing into a [td]indirect block (as opposed to the + * inode) then we need to get write access to the [td]indirect block +@@ -783,18 +778,7 @@ static int ext4_splice_branch(handle_t * + if (num == 0 && blks > 1) { + current_block = le32_to_cpu(where->key) + 1; + for (i = 1; i < blks; i++) +- *(where->p + i ) = cpu_to_le32(current_block++); +- } +- +- /* +- * update the most recently allocated logical & physical block +- * in i_block_alloc_info, to assist find the proper goal block for next +- * allocation +- */ +- if (block_i) { +- block_i->last_alloc_logical_block = block + blks - 1; +- block_i->last_alloc_physical_block = +- le32_to_cpu(where[num].key) + blks - 1; ++ *(where->p + i) = cpu_to_le32(current_block++); + } + + /* We are done with atomic stuff, now do the rest of housekeeping */ +@@ -861,10 +845,10 @@ err_out: + * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block + * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem) + */ +-int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, +- ext4_lblk_t iblock, unsigned long maxblocks, +- struct buffer_head *bh_result, +- int create, int extend_disksize) ++static int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, ++ ext4_lblk_t iblock, unsigned int maxblocks, ++ struct buffer_head *bh_result, ++ int create, int extend_disksize) + { + int err = -EIO; + ext4_lblk_t offsets[4]; +@@ -914,12 +898,8 @@ int ext4_get_blocks_handle(handle_t *han + goto cleanup; + + /* +- * Okay, we need to do block allocation. Lazily initialize the block +- * allocation info here if necessary ++ * Okay, we need to do block allocation. + */ +- if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) +- ext4_init_block_alloc_info(inode); +- + goal = ext4_find_goal(inode, iblock, partial); + + /* the number of blocks need to allocate for [d,t]indirect blocks */ +@@ -1030,19 +1010,20 @@ static void ext4_da_update_reserve_space + BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); + mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; + +- /* Account for allocated meta_blocks */ +- mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; +- +- /* update fs free blocks counter for truncate case */ +- percpu_counter_add(&sbi->s_freeblocks_counter, mdb_free); ++ if (mdb_free) { ++ /* Account for allocated meta_blocks */ ++ mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; ++ ++ /* update fs dirty blocks counter */ ++ percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free); ++ EXT4_I(inode)->i_allocated_meta_blocks = 0; ++ EXT4_I(inode)->i_reserved_meta_blocks = mdb; ++ } + + /* update per-inode reservations */ + BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks); + EXT4_I(inode)->i_reserved_data_blocks -= used; + +- BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); +- EXT4_I(inode)->i_reserved_meta_blocks = mdb; +- EXT4_I(inode)->i_allocated_meta_blocks = 0; + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + } + +@@ -1069,7 +1050,7 @@ static void ext4_da_update_reserve_space + * It returns the error in case of allocation failure. + */ + int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, +- unsigned long max_blocks, struct buffer_head *bh, ++ unsigned int max_blocks, struct buffer_head *bh, + int create, int extend_disksize, int flag) + { + int retval; +@@ -1241,7 +1222,7 @@ struct buffer_head *ext4_getblk(handle_t + BUFFER_TRACE(bh, "call get_create_access"); + fatal = ext4_journal_get_create_access(handle, bh); + if (!fatal && !buffer_uptodate(bh)) { +- memset(bh->b_data,0,inode->i_sb->s_blocksize); ++ memset(bh->b_data, 0, inode->i_sb->s_blocksize); + set_buffer_uptodate(bh); + } + unlock_buffer(bh); +@@ -1266,7 +1247,7 @@ err: + struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, + ext4_lblk_t block, int create, int *err) + { +- struct buffer_head * bh; ++ struct buffer_head *bh; + + bh = ext4_getblk(handle, inode, block, create, err); + if (!bh) +@@ -1282,13 +1263,13 @@ struct buffer_head *ext4_bread(handle_t + return NULL; + } + +-static int walk_page_buffers( handle_t *handle, +- struct buffer_head *head, +- unsigned from, +- unsigned to, +- int *partial, +- int (*fn)( handle_t *handle, +- struct buffer_head *bh)) ++static int walk_page_buffers(handle_t *handle, ++ struct buffer_head *head, ++ unsigned from, ++ unsigned to, ++ int *partial, ++ int (*fn)(handle_t *handle, ++ struct buffer_head *bh)) + { + struct buffer_head *bh; + unsigned block_start, block_end; +@@ -1296,9 +1277,9 @@ static int walk_page_buffers( handle_t * + int err, ret = 0; + struct buffer_head *next; + +- for ( bh = head, block_start = 0; +- ret == 0 && (bh != head || !block_start); +- block_start = block_end, bh = next) ++ for (bh = head, block_start = 0; ++ ret == 0 && (bh != head || !block_start); ++ block_start = block_end, bh = next) + { + next = bh->b_this_page; + block_end = block_start + blocksize; +@@ -1351,23 +1332,23 @@ static int ext4_write_begin(struct file + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) + { +- struct inode *inode = mapping->host; ++ struct inode *inode = mapping->host; + int ret, needed_blocks = ext4_writepage_trans_blocks(inode); + handle_t *handle; + int retries = 0; +- struct page *page; ++ struct page *page; + pgoff_t index; +- unsigned from, to; ++ unsigned from, to; + + index = pos >> PAGE_CACHE_SHIFT; +- from = pos & (PAGE_CACHE_SIZE - 1); +- to = from + len; ++ from = pos & (PAGE_CACHE_SIZE - 1); ++ to = from + len; + + retry: +- handle = ext4_journal_start(inode, needed_blocks); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- goto out; ++ handle = ext4_journal_start(inode, needed_blocks); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ goto out; + } + + page = grab_cache_page_write_begin(mapping, index, flags); +@@ -1387,9 +1368,16 @@ retry: + } + + if (ret) { +- unlock_page(page); ++ unlock_page(page); + ext4_journal_stop(handle); +- page_cache_release(page); ++ page_cache_release(page); ++ /* ++ * block_write_begin may have instantiated a few blocks ++ * outside i_size. Trim these off again. Don't need ++ * i_size_read because we hold i_mutex. ++ */ ++ if (pos + len > inode->i_size) ++ vmtruncate(inode, inode->i_size); + } + + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) +@@ -1426,16 +1414,18 @@ static int ext4_ordered_write_end(struct + ret = ext4_jbd2_file_inode(handle, inode); + + if (ret == 0) { +- /* +- * generic_write_end() will run mark_inode_dirty() if i_size +- * changes. So let's piggyback the i_disksize mark_inode_dirty +- * into that. +- */ + loff_t new_i_size; + + new_i_size = pos + copied; +- if (new_i_size > EXT4_I(inode)->i_disksize) +- EXT4_I(inode)->i_disksize = new_i_size; ++ if (new_i_size > EXT4_I(inode)->i_disksize) { ++ ext4_update_i_disksize(inode, new_i_size); ++ /* We need to mark inode dirty even if ++ * new_i_size is less that inode->i_size ++ * bu greater than i_disksize.(hint delalloc) ++ */ ++ ext4_mark_inode_dirty(handle, inode); ++ } ++ + ret2 = generic_write_end(file, mapping, pos, len, copied, + page, fsdata); + copied = ret2; +@@ -1460,8 +1450,14 @@ static int ext4_writeback_write_end(stru + loff_t new_i_size; + + new_i_size = pos + copied; +- if (new_i_size > EXT4_I(inode)->i_disksize) +- EXT4_I(inode)->i_disksize = new_i_size; ++ if (new_i_size > EXT4_I(inode)->i_disksize) { ++ ext4_update_i_disksize(inode, new_i_size); ++ /* We need to mark inode dirty even if ++ * new_i_size is less that inode->i_size ++ * bu greater than i_disksize.(hint delalloc) ++ */ ++ ext4_mark_inode_dirty(handle, inode); ++ } + + ret2 = generic_write_end(file, mapping, pos, len, copied, + page, fsdata); +@@ -1486,6 +1482,7 @@ static int ext4_journalled_write_end(str + int ret = 0, ret2; + int partial = 0; + unsigned from, to; ++ loff_t new_i_size; + + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; +@@ -1500,11 +1497,12 @@ static int ext4_journalled_write_end(str + to, &partial, write_end_fn); + if (!partial) + SetPageUptodate(page); +- if (pos+copied > inode->i_size) ++ new_i_size = pos + copied; ++ if (new_i_size > inode->i_size) + i_size_write(inode, pos+copied); + EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; +- if (inode->i_size > EXT4_I(inode)->i_disksize) { +- EXT4_I(inode)->i_disksize = inode->i_size; ++ if (new_i_size > EXT4_I(inode)->i_disksize) { ++ ext4_update_i_disksize(inode, new_i_size); + ret2 = ext4_mark_inode_dirty(handle, inode); + if (!ret) + ret = ret2; +@@ -1521,6 +1519,7 @@ static int ext4_journalled_write_end(str + + static int ext4_da_reserve_space(struct inode *inode, int nrblocks) + { ++ int retries = 0; + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + unsigned long md_needed, mdblocks, total = 0; + +@@ -1529,6 +1528,7 @@ static int ext4_da_reserve_space(struct + * in order to allocate nrblocks + * worse case is one extent per block + */ ++repeat: + spin_lock(&EXT4_I(inode)->i_block_reservation_lock); + total = EXT4_I(inode)->i_reserved_data_blocks + nrblocks; + mdblocks = ext4_calc_metadata_amount(inode, total); +@@ -1537,13 +1537,14 @@ static int ext4_da_reserve_space(struct + md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks; + total = md_needed + nrblocks; + +- if (ext4_has_free_blocks(sbi, total) < total) { ++ if (ext4_claim_free_blocks(sbi, total)) { + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); ++ if (ext4_should_retry_alloc(inode->i_sb, &retries)) { ++ yield(); ++ goto repeat; ++ } + return -ENOSPC; + } +- /* reduce fs free blocks counter */ +- percpu_counter_sub(&sbi->s_freeblocks_counter, total); +- + EXT4_I(inode)->i_reserved_data_blocks += nrblocks; + EXT4_I(inode)->i_reserved_meta_blocks = mdblocks; + +@@ -1585,8 +1586,8 @@ static void ext4_da_release_space(struct + + release = to_free + mdb_free; + +- /* update fs free blocks counter for truncate case */ +- percpu_counter_add(&sbi->s_freeblocks_counter, release); ++ /* update fs dirty blocks counter for truncate case */ ++ percpu_counter_sub(&sbi->s_dirtyblocks_counter, release); + + /* update per-inode reservations */ + BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks); +@@ -1629,7 +1630,8 @@ struct mpage_da_data { + get_block_t *get_block; + struct writeback_control *wbc; + int io_done; +- long pages_written; ++ int pages_written; ++ int retval; + }; + + /* +@@ -1648,18 +1650,25 @@ struct mpage_da_data { + */ + static int mpage_da_submit_io(struct mpage_da_data *mpd) + { +- struct address_space *mapping = mpd->inode->i_mapping; +- int ret = 0, err, nr_pages, i; +- unsigned long index, end; ++ long pages_skipped; + struct pagevec pvec; ++ unsigned long index, end; ++ int ret = 0, err, nr_pages, i; ++ struct inode *inode = mpd->inode; ++ struct address_space *mapping = inode->i_mapping; + + BUG_ON(mpd->next_page <= mpd->first_page); +- pagevec_init(&pvec, 0); ++ /* ++ * We need to start from the first_page to the next_page - 1 ++ * to make sure we also write the mapped dirty buffer_heads. ++ * If we look at mpd->lbh.b_blocknr we would only be looking ++ * at the currently mapped buffer_heads. ++ */ + index = mpd->first_page; + end = mpd->next_page - 1; + ++ pagevec_init(&pvec, 0); + while (index <= end) { +- /* XXX: optimize tail */ + nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); + if (nr_pages == 0) + break; +@@ -1671,8 +1680,16 @@ static int mpage_da_submit_io(struct mpa + break; + index++; + ++ BUG_ON(!PageLocked(page)); ++ BUG_ON(PageWriteback(page)); ++ ++ pages_skipped = mpd->wbc->pages_skipped; + err = mapping->a_ops->writepage(page, mpd->wbc); +- if (!err) ++ if (!err && (pages_skipped == mpd->wbc->pages_skipped)) ++ /* ++ * have successfully written the page ++ * without skipping the same ++ */ + mpd->pages_written++; + /* + * In error case, we have to continue because +@@ -1783,6 +1800,57 @@ static inline void __unmap_underlying_bl + unmap_underlying_metadata(bdev, bh->b_blocknr + i); + } + ++static void ext4_da_block_invalidatepages(struct mpage_da_data *mpd, ++ sector_t logical, long blk_cnt) ++{ ++ int nr_pages, i; ++ pgoff_t index, end; ++ struct pagevec pvec; ++ struct inode *inode = mpd->inode; ++ struct address_space *mapping = inode->i_mapping; ++ ++ index = logical >> (PAGE_CACHE_SHIFT - inode->i_blkbits); ++ end = (logical + blk_cnt - 1) >> ++ (PAGE_CACHE_SHIFT - inode->i_blkbits); ++ while (index <= end) { ++ nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); ++ if (nr_pages == 0) ++ break; ++ for (i = 0; i < nr_pages; i++) { ++ struct page *page = pvec.pages[i]; ++ index = page->index; ++ if (index > end) ++ break; ++ index++; ++ ++ BUG_ON(!PageLocked(page)); ++ BUG_ON(PageWriteback(page)); ++ block_invalidatepage(page, 0); ++ ClearPageUptodate(page); ++ unlock_page(page); ++ } ++ } ++ return; ++} ++ ++static void ext4_print_free_blocks(struct inode *inode) ++{ ++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); ++ printk(KERN_EMERG "Total free blocks count %lld\n", ++ ext4_count_free_blocks(inode->i_sb)); ++ printk(KERN_EMERG "Free/Dirty block details\n"); ++ printk(KERN_EMERG "free_blocks=%lld\n", ++ (long long)percpu_counter_sum(&sbi->s_freeblocks_counter)); ++ printk(KERN_EMERG "dirty_blocks=%lld\n", ++ (long long)percpu_counter_sum(&sbi->s_dirtyblocks_counter)); ++ printk(KERN_EMERG "Block reservation details\n"); ++ printk(KERN_EMERG "i_reserved_data_blocks=%u\n", ++ EXT4_I(inode)->i_reserved_data_blocks); ++ printk(KERN_EMERG "i_reserved_meta_blocks=%u\n", ++ EXT4_I(inode)->i_reserved_meta_blocks); ++ return; ++} ++ + /* + * mpage_da_map_blocks - go through given space + * +@@ -1792,32 +1860,69 @@ static inline void __unmap_underlying_bl + * The function skips space we know is already mapped to disk blocks. + * + */ +-static void mpage_da_map_blocks(struct mpage_da_data *mpd) ++static int mpage_da_map_blocks(struct mpage_da_data *mpd) + { + int err = 0; +- struct buffer_head *lbh = &mpd->lbh; +- sector_t next = lbh->b_blocknr; + struct buffer_head new; ++ struct buffer_head *lbh = &mpd->lbh; ++ sector_t next; + + /* + * We consider only non-mapped and non-allocated blocks + */ + if (buffer_mapped(lbh) && !buffer_delay(lbh)) +- return; +- ++ return 0; + new.b_state = lbh->b_state; + new.b_blocknr = 0; + new.b_size = lbh->b_size; +- ++ next = lbh->b_blocknr; + /* + * If we didn't accumulate anything + * to write simply return + */ + if (!new.b_size) +- return; ++ return 0; + err = mpd->get_block(mpd->inode, next, &new, 1); +- if (err) +- return; ++ if (err) { ++ ++ /* If get block returns with error ++ * we simply return. Later writepage ++ * will redirty the page and writepages ++ * will find the dirty page again ++ */ ++ if (err == -EAGAIN) ++ return 0; ++ ++ if (err == -ENOSPC && ++ ext4_count_free_blocks(mpd->inode->i_sb)) { ++ mpd->retval = err; ++ return 0; ++ } ++ ++ /* ++ * get block failure will cause us ++ * to loop in writepages. Because ++ * a_ops->writepage won't be able to ++ * make progress. The page will be redirtied ++ * by writepage and writepages will again ++ * try to write the same. ++ */ ++ printk(KERN_EMERG "%s block allocation failed for inode %lu " ++ "at logical offset %llu with max blocks " ++ "%zd with error %d\n", ++ __func__, mpd->inode->i_ino, ++ (unsigned long long)next, ++ lbh->b_size >> mpd->inode->i_blkbits, err); ++ printk(KERN_EMERG "This should not happen.!! " ++ "Data will be lost\n"); ++ if (err == -ENOSPC) { ++ ext4_print_free_blocks(mpd->inode); ++ } ++ /* invlaidate all the pages */ ++ ext4_da_block_invalidatepages(mpd, next, ++ lbh->b_size >> mpd->inode->i_blkbits); ++ return err; ++ } + BUG_ON(new.b_size == 0); + + if (buffer_new(&new)) +@@ -1830,7 +1935,7 @@ static void mpage_da_map_blocks(struct m + if (buffer_delay(lbh) || buffer_unwritten(lbh)) + mpage_put_bnr_to_bhs(mpd, next, &new); + +- return; ++ return 0; + } + + #define BH_FLAGS ((1 << BH_Uptodate) | (1 << BH_Mapped) | \ +@@ -1899,8 +2004,8 @@ flush_it: + * We couldn't merge the block to our extent, so we + * need to flush current extent and start new one + */ +- mpage_da_map_blocks(mpd); +- mpage_da_submit_io(mpd); ++ if (mpage_da_map_blocks(mpd) == 0) ++ mpage_da_submit_io(mpd); + mpd->io_done = 1; + return; + } +@@ -1942,8 +2047,8 @@ static int __mpage_da_writepage(struct p + * and start IO on them using writepage() + */ + if (mpd->next_page != mpd->first_page) { +- mpage_da_map_blocks(mpd); +- mpage_da_submit_io(mpd); ++ if (mpage_da_map_blocks(mpd) == 0) ++ mpage_da_submit_io(mpd); + /* + * skip rest of the page in the page_vec + */ +@@ -1991,11 +2096,29 @@ static int __mpage_da_writepage(struct p + bh = head; + do { + BUG_ON(buffer_locked(bh)); ++ /* ++ * We need to try to allocate ++ * unmapped blocks in the same page. ++ * Otherwise we won't make progress ++ * with the page in ext4_da_writepage ++ */ + if (buffer_dirty(bh) && + (!buffer_mapped(bh) || buffer_delay(bh))) { + mpage_add_bh_to_extent(mpd, logical, bh); + if (mpd->io_done) + return MPAGE_DA_EXTENT_TAIL; ++ } else if (buffer_dirty(bh) && (buffer_mapped(bh))) { ++ /* ++ * mapped dirty buffer. We need to update ++ * the b_state because we look at ++ * b_state in mpage_da_map_blocks. We don't ++ * update b_size because if we find an ++ * unmapped buffer_head later we need to ++ * use the b_state flag of that buffer_head. ++ */ ++ if (mpd->lbh.b_size == 0) ++ mpd->lbh.b_state = ++ bh->b_state & BH_FLAGS; + } + logical++; + } while ((bh = bh->b_this_page) != head); +@@ -2018,39 +2141,42 @@ static int __mpage_da_writepage(struct p + */ + static int mpage_da_writepages(struct address_space *mapping, + struct writeback_control *wbc, +- get_block_t get_block) ++ struct mpage_da_data *mpd) + { +- struct mpage_da_data mpd; +- long to_write; + int ret; ++ long nr_to_write; ++ pgoff_t index; + +- if (!get_block) +- return generic_writepages(mapping, wbc); +- +- mpd.wbc = wbc; +- mpd.inode = mapping->host; +- mpd.lbh.b_size = 0; +- mpd.lbh.b_state = 0; +- mpd.lbh.b_blocknr = 0; +- mpd.first_page = 0; +- mpd.next_page = 0; +- mpd.get_block = get_block; +- mpd.io_done = 0; +- mpd.pages_written = 0; + +- to_write = wbc->nr_to_write; + +- ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, &mpd); ++ if (!mpd->get_block) ++ return generic_writepages(mapping, wbc); + ++ mpd->lbh.b_size = 0; ++ mpd->lbh.b_state = 0; ++ mpd->lbh.b_blocknr = 0; ++ mpd->first_page = 0; ++ mpd->next_page = 0; ++ mpd->io_done = 0; ++ mpd->pages_written = 0; ++ mpd->retval = 0; ++ ++ nr_to_write = wbc->nr_to_write; ++ index = mapping->writeback_index; ++ ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, mpd); ++ wbc->nr_to_write = nr_to_write; ++ mapping->writeback_index = index; + /* + * Handle last extent of pages + */ +- if (!mpd.io_done && mpd.next_page != mpd.first_page) { +- mpage_da_map_blocks(&mpd); +- mpage_da_submit_io(&mpd); +- } ++ if (!mpd->io_done && mpd->next_page != mpd->first_page) { ++ if (mpage_da_map_blocks(mpd) == 0) ++ mpage_da_submit_io(mpd); + +- wbc->nr_to_write = to_write - mpd.pages_written; ++ mpd->io_done = 1; ++ ret = MPAGE_DA_EXTENT_TAIL; ++ } ++ wbc->nr_to_write -= mpd->pages_written; + return ret; + } + +@@ -2103,18 +2229,24 @@ static int ext4_da_get_block_write(struc + handle_t *handle = NULL; + + handle = ext4_journal_current_handle(); +- if (!handle) { +- ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks, +- bh_result, 0, 0, 0); +- BUG_ON(!ret); +- } else { +- ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks, +- bh_result, create, 0, EXT4_DELALLOC_RSVED); +- } +- ++ BUG_ON(!handle); ++ ret = ext4_get_blocks_wrap(handle, inode, iblock, max_blocks, ++ bh_result, create, 0, EXT4_DELALLOC_RSVED); + if (ret > 0) { ++ + bh_result->b_size = (ret << inode->i_blkbits); + ++ if (ext4_should_order_data(inode)) { ++ int retval; ++ retval = ext4_jbd2_file_inode(handle, inode); ++ if (retval) ++ /* ++ * Failed to add inode for ordered ++ * mode. Don't update file size ++ */ ++ return retval; ++ } ++ + /* + * Update on-disk size along with block allocation + * we don't use 'extend_disksize' as size may change +@@ -2124,18 +2256,9 @@ static int ext4_da_get_block_write(struc + if (disksize > i_size_read(inode)) + disksize = i_size_read(inode); + if (disksize > EXT4_I(inode)->i_disksize) { +- /* +- * XXX: replace with spinlock if seen contended -bzzz +- */ +- down_write(&EXT4_I(inode)->i_data_sem); +- if (disksize > EXT4_I(inode)->i_disksize) +- EXT4_I(inode)->i_disksize = disksize; +- up_write(&EXT4_I(inode)->i_data_sem); +- +- if (EXT4_I(inode)->i_disksize == disksize) { +- ret = ext4_mark_inode_dirty(handle, inode); +- return ret; +- } ++ ext4_update_i_disksize(inode, disksize); ++ ret = ext4_mark_inode_dirty(handle, inode); ++ return ret; + } + ret = 0; + } +@@ -2181,7 +2304,7 @@ static int ext4_da_writepage(struct page + { + int ret = 0; + loff_t size; +- unsigned long len; ++ unsigned int len; + struct buffer_head *page_bufs; + struct inode *inode = page->mapping->host; + +@@ -2284,11 +2407,14 @@ static int ext4_da_writepages_trans_bloc + static int ext4_da_writepages(struct address_space *mapping, + struct writeback_control *wbc) + { ++ pgoff_t index; ++ int range_whole = 0; + handle_t *handle = NULL; +- loff_t range_start = 0; ++ struct mpage_da_data mpd; + struct inode *inode = mapping->host; ++ int pages_written = 0; ++ long pages_skipped; + int needed_blocks, ret = 0, nr_to_writebump = 0; +- long to_write, pages_skipped = 0; + struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); + + /* +@@ -2298,6 +2424,20 @@ static int ext4_da_writepages(struct add + */ + if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) + return 0; ++ ++ /* ++ * If the filesystem has aborted, it is read-only, so return ++ * right away instead of dumping stack traces later on that ++ * will obscure the real source of the problem. We test ++ * EXT4_MOUNT_ABORT instead of sb->s_flag's MS_RDONLY because ++ * the latter could be true if the filesystem is mounted ++ * read-only, and in that case, ext4_da_writepages should ++ * *never* be called, so if that ever happens, we would want ++ * the stack trace. ++ */ ++ if (unlikely(sbi->s_mount_opt & EXT4_MOUNT_ABORT)) ++ return -EROFS; ++ + /* + * Make sure nr_to_write is >= sbi->s_mb_stream_request + * This make sure small files blocks are allocated in +@@ -2308,20 +2448,24 @@ static int ext4_da_writepages(struct add + nr_to_writebump = sbi->s_mb_stream_request - wbc->nr_to_write; + wbc->nr_to_write = sbi->s_mb_stream_request; + } ++ if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) ++ range_whole = 1; + +- if (!wbc->range_cyclic) +- /* +- * If range_cyclic is not set force range_cont +- * and save the old writeback_index +- */ +- wbc->range_cont = 1; ++ if (wbc->range_cyclic) ++ index = mapping->writeback_index; ++ else ++ index = wbc->range_start >> PAGE_CACHE_SHIFT; + +- range_start = wbc->range_start; ++ mpd.wbc = wbc; ++ mpd.inode = mapping->host; ++ ++ /* ++ * we don't want write_cache_pages to update ++ * nr_to_write and writeback_index ++ */ + pages_skipped = wbc->pages_skipped; + +-restart_loop: +- to_write = wbc->nr_to_write; +- while (!ret && to_write > 0) { ++ while (!ret && wbc->nr_to_write > 0) { + + /* + * we insert one extent at a time. So we need +@@ -2336,63 +2480,87 @@ restart_loop: + handle = ext4_journal_start(inode, needed_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); +- printk(KERN_EMERG "%s: jbd2_start: " ++ printk(KERN_CRIT "%s: jbd2_start: " + "%ld pages, ino %lu; err %d\n", __func__, + wbc->nr_to_write, inode->i_ino, ret); + dump_stack(); + goto out_writepages; + } +- if (ext4_should_order_data(inode)) { +- /* +- * With ordered mode we need to add +- * the inode to the journal handl +- * when we do block allocation. +- */ +- ret = ext4_jbd2_file_inode(handle, inode); +- if (ret) { +- ext4_journal_stop(handle); +- goto out_writepages; +- } +- } ++ mpd.get_block = ext4_da_get_block_write; ++ ret = mpage_da_writepages(mapping, wbc, &mpd); + +- to_write -= wbc->nr_to_write; +- ret = mpage_da_writepages(mapping, wbc, +- ext4_da_get_block_write); + ext4_journal_stop(handle); +- if (ret == MPAGE_DA_EXTENT_TAIL) { ++ ++ if (mpd.retval == -ENOSPC) { ++ /* commit the transaction which would ++ * free blocks released in the transaction ++ * and try again ++ */ ++ jbd2_journal_force_commit_nested(sbi->s_journal); ++ wbc->pages_skipped = pages_skipped; ++ ret = 0; ++ } else if (ret == MPAGE_DA_EXTENT_TAIL) { + /* + * got one extent now try with + * rest of the pages + */ +- to_write += wbc->nr_to_write; ++ pages_written += mpd.pages_written; ++ wbc->pages_skipped = pages_skipped; + ret = 0; +- } else if (wbc->nr_to_write) { ++ } else if (wbc->nr_to_write) + /* + * There is no more writeout needed + * or we requested for a noblocking writeout + * and we found the device congested + */ +- to_write += wbc->nr_to_write; + break; +- } +- wbc->nr_to_write = to_write; +- } +- +- if (wbc->range_cont && (pages_skipped != wbc->pages_skipped)) { +- /* We skipped pages in this loop */ +- wbc->range_start = range_start; +- wbc->nr_to_write = to_write + +- wbc->pages_skipped - pages_skipped; +- wbc->pages_skipped = pages_skipped; +- goto restart_loop; + } ++ if (pages_skipped != wbc->pages_skipped) ++ printk(KERN_EMERG "This should not happen leaving %s " ++ "with nr_to_write = %ld ret = %d\n", ++ __func__, wbc->nr_to_write, ret); ++ ++ /* Update index */ ++ index += pages_written; ++ if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) ++ /* ++ * set the writeback_index so that range_cyclic ++ * mode will write it back later ++ */ ++ mapping->writeback_index = index; + + out_writepages: +- wbc->nr_to_write = to_write - nr_to_writebump; +- wbc->range_start = range_start; ++ wbc->nr_to_write -= nr_to_writebump; + return ret; + } + ++#define FALL_BACK_TO_NONDELALLOC 1 ++static int ext4_nonda_switch(struct super_block *sb) ++{ ++ s64 free_blocks, dirty_blocks; ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ ++ /* ++ * switch to non delalloc mode if we are running low ++ * on free block. The free block accounting via percpu ++ * counters can get slightly wrong with FBC_BATCH getting ++ * accumulated on each CPU without updating global counters ++ * Delalloc need an accurate free block accounting. So switch ++ * to non delalloc when we are near to error range. ++ */ ++ free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); ++ dirty_blocks = percpu_counter_read_positive(&sbi->s_dirtyblocks_counter); ++ if (2 * free_blocks < 3 * dirty_blocks || ++ free_blocks < (dirty_blocks + EXT4_FREEBLOCKS_WATERMARK)) { ++ /* ++ * free block count is less that 150% of dirty blocks ++ * or free blocks is less that watermark ++ */ ++ return 1; ++ } ++ return 0; ++} ++ + static int ext4_da_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +@@ -2408,6 +2576,12 @@ static int ext4_da_write_begin(struct fi + from = pos & (PAGE_CACHE_SIZE - 1); + to = from + len; + ++ if (ext4_nonda_switch(inode->i_sb)) { ++ *fsdata = (void *)FALL_BACK_TO_NONDELALLOC; ++ return ext4_write_begin(file, mapping, pos, ++ len, flags, pagep, fsdata); ++ } ++ *fsdata = (void *)0; + retry: + /* + * With delayed allocation, we don't log the i_disksize update +@@ -2435,6 +2609,13 @@ retry: + unlock_page(page); + ext4_journal_stop(handle); + page_cache_release(page); ++ /* ++ * block_write_begin may have instantiated a few blocks ++ * outside i_size. Trim these off again. Don't need ++ * i_size_read because we hold i_mutex. ++ */ ++ if (pos + len > inode->i_size) ++ vmtruncate(inode, inode->i_size); + } + + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) +@@ -2458,7 +2639,7 @@ static int ext4_da_should_update_i_disks + bh = page_buffers(page); + idx = offset >> inode->i_blkbits; + +- for (i=0; i < idx; i++) ++ for (i = 0; i < idx; i++) + bh = bh->b_this_page; + + if (!buffer_mapped(bh) || (buffer_delay(bh))) +@@ -2476,9 +2657,22 @@ static int ext4_da_write_end(struct file + handle_t *handle = ext4_journal_current_handle(); + loff_t new_i_size; + unsigned long start, end; ++ int write_mode = (int)(unsigned long)fsdata; ++ ++ if (write_mode == FALL_BACK_TO_NONDELALLOC) { ++ if (ext4_should_order_data(inode)) { ++ return ext4_ordered_write_end(file, mapping, pos, ++ len, copied, page, fsdata); ++ } else if (ext4_should_writeback_data(inode)) { ++ return ext4_writeback_write_end(file, mapping, pos, ++ len, copied, page, fsdata); ++ } else { ++ BUG(); ++ } ++ } + + start = pos & (PAGE_CACHE_SIZE - 1); +- end = start + copied -1; ++ end = start + copied - 1; + + /* + * generic_write_end() will run mark_inode_dirty() if i_size +@@ -2502,6 +2696,11 @@ static int ext4_da_write_end(struct file + EXT4_I(inode)->i_disksize = new_i_size; + } + up_write(&EXT4_I(inode)->i_data_sem); ++ /* We need to mark inode dirty even if ++ * new_i_size is less that inode->i_size ++ * bu greater than i_disksize.(hint delalloc) ++ */ ++ ext4_mark_inode_dirty(handle, inode); + } + } + ret2 = generic_write_end(file, mapping, pos, len, copied, +@@ -2593,7 +2792,7 @@ static sector_t ext4_bmap(struct address + return 0; + } + +- return generic_block_bmap(mapping,block,ext4_get_block); ++ return generic_block_bmap(mapping, block, ext4_get_block); + } + + static int bget_one(handle_t *handle, struct buffer_head *bh) +@@ -3199,7 +3398,7 @@ static Indirect *ext4_find_shared(struct + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; +- for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--) ++ for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our +@@ -3218,7 +3417,7 @@ static Indirect *ext4_find_shared(struct + } + /* Writer: end */ + +- while(partial > p) { ++ while (partial > p) { + brelse(partial->bh); + partial--; + } +@@ -3410,9 +3609,9 @@ static void ext4_free_branches(handle_t + /* This zaps the entire block. Bottom up. */ + BUFFER_TRACE(bh, "free child branches"); + ext4_free_branches(handle, inode, bh, +- (__le32*)bh->b_data, +- (__le32*)bh->b_data + addr_per_block, +- depth); ++ (__le32 *) bh->b_data, ++ (__le32 *) bh->b_data + addr_per_block, ++ depth); + + /* + * We've probably journalled the indirect block several +@@ -3580,7 +3779,7 @@ void ext4_truncate(struct inode *inode) + */ + down_write(&ei->i_data_sem); + +- ext4_discard_reservation(inode); ++ ext4_discard_preallocations(inode); + + /* + * The orphan list entry will now protect us from any crash which +@@ -3675,41 +3874,6 @@ out_stop: + ext4_journal_stop(handle); + } + +-static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb, +- unsigned long ino, struct ext4_iloc *iloc) +-{ +- ext4_group_t block_group; +- unsigned long offset; +- ext4_fsblk_t block; +- struct ext4_group_desc *gdp; +- +- if (!ext4_valid_inum(sb, ino)) { +- /* +- * This error is already checked for in namei.c unless we are +- * looking at an NFS filehandle, in which case no error +- * report is needed +- */ +- return 0; +- } +- +- block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); +- gdp = ext4_get_group_desc(sb, block_group, NULL); +- if (!gdp) +- return 0; +- +- /* +- * Figure out the offset within the block group inode table +- */ +- offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) * +- EXT4_INODE_SIZE(sb); +- block = ext4_inode_table(sb, gdp) + +- (offset >> EXT4_BLOCK_SIZE_BITS(sb)); +- +- iloc->block_group = block_group; +- iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1); +- return block; +-} +- + /* + * ext4_get_inode_loc returns with an extra refcount against the inode's + * underlying buffer_head on success. If 'in_mem' is true, we have all +@@ -3719,19 +3883,35 @@ static ext4_fsblk_t ext4_get_inode_block + static int __ext4_get_inode_loc(struct inode *inode, + struct ext4_iloc *iloc, int in_mem) + { +- ext4_fsblk_t block; +- struct buffer_head *bh; ++ struct ext4_group_desc *gdp; ++ struct buffer_head *bh; ++ struct super_block *sb = inode->i_sb; ++ ext4_fsblk_t block; ++ int inodes_per_block, inode_offset; ++ ++ iloc->bh = NULL; ++ if (!ext4_valid_inum(sb, inode->i_ino)) ++ return -EIO; + +- block = ext4_get_inode_block(inode->i_sb, inode->i_ino, iloc); +- if (!block) ++ iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb); ++ gdp = ext4_get_group_desc(sb, iloc->block_group, NULL); ++ if (!gdp) + return -EIO; + +- bh = sb_getblk(inode->i_sb, block); ++ /* ++ * Figure out the offset within the block group inode table ++ */ ++ inodes_per_block = (EXT4_BLOCK_SIZE(sb) / EXT4_INODE_SIZE(sb)); ++ inode_offset = ((inode->i_ino - 1) % ++ EXT4_INODES_PER_GROUP(sb)); ++ block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block); ++ iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb); ++ ++ bh = sb_getblk(sb, block); + if (!bh) { +- ext4_error (inode->i_sb, "ext4_get_inode_loc", +- "unable to read inode block - " +- "inode=%lu, block=%llu", +- inode->i_ino, block); ++ ext4_error(sb, "ext4_get_inode_loc", "unable to read " ++ "inode block - inode=%lu, block=%llu", ++ inode->i_ino, block); + return -EIO; + } + if (!buffer_uptodate(bh)) { +@@ -3759,28 +3939,12 @@ static int __ext4_get_inode_loc(struct i + */ + if (in_mem) { + struct buffer_head *bitmap_bh; +- struct ext4_group_desc *desc; +- int inodes_per_buffer; +- int inode_offset, i; +- ext4_group_t block_group; +- int start; +- +- block_group = (inode->i_ino - 1) / +- EXT4_INODES_PER_GROUP(inode->i_sb); +- inodes_per_buffer = bh->b_size / +- EXT4_INODE_SIZE(inode->i_sb); +- inode_offset = ((inode->i_ino - 1) % +- EXT4_INODES_PER_GROUP(inode->i_sb)); +- start = inode_offset & ~(inodes_per_buffer - 1); ++ int i, start; + +- /* Is the inode bitmap in cache? */ +- desc = ext4_get_group_desc(inode->i_sb, +- block_group, NULL); +- if (!desc) +- goto make_io; ++ start = inode_offset & ~(inodes_per_block - 1); + +- bitmap_bh = sb_getblk(inode->i_sb, +- ext4_inode_bitmap(inode->i_sb, desc)); ++ /* Is the inode bitmap in cache? */ ++ bitmap_bh = sb_getblk(sb, ext4_inode_bitmap(sb, gdp)); + if (!bitmap_bh) + goto make_io; + +@@ -3793,14 +3957,14 @@ static int __ext4_get_inode_loc(struct i + brelse(bitmap_bh); + goto make_io; + } +- for (i = start; i < start + inodes_per_buffer; i++) { ++ for (i = start; i < start + inodes_per_block; i++) { + if (i == inode_offset) + continue; + if (ext4_test_bit(i, bitmap_bh->b_data)) + break; + } + brelse(bitmap_bh); +- if (i == start + inodes_per_buffer) { ++ if (i == start + inodes_per_block) { + /* all other inodes are free, so skip I/O */ + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); +@@ -3811,6 +3975,36 @@ static int __ext4_get_inode_loc(struct i + + make_io: + /* ++ * If we need to do any I/O, try to pre-readahead extra ++ * blocks from the inode table. ++ */ ++ if (EXT4_SB(sb)->s_inode_readahead_blks) { ++ ext4_fsblk_t b, end, table; ++ unsigned num; ++ ++ table = ext4_inode_table(sb, gdp); ++ /* Make sure s_inode_readahead_blks is a power of 2 */ ++ while (EXT4_SB(sb)->s_inode_readahead_blks & ++ (EXT4_SB(sb)->s_inode_readahead_blks-1)) ++ EXT4_SB(sb)->s_inode_readahead_blks = ++ (EXT4_SB(sb)->s_inode_readahead_blks & ++ (EXT4_SB(sb)->s_inode_readahead_blks-1)); ++ b = block & ~(EXT4_SB(sb)->s_inode_readahead_blks-1); ++ if (table > b) ++ b = table; ++ end = b + EXT4_SB(sb)->s_inode_readahead_blks; ++ num = EXT4_INODES_PER_GROUP(sb); ++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ++ num -= ext4_itable_unused_count(sb, gdp); ++ table += num / inodes_per_block; ++ if (end > table) ++ end = table; ++ while (b <= end) ++ sb_breadahead(sb, b++); ++ } ++ ++ /* + * There are other valid inodes in the buffer, this inode + * has in-inode xattrs, or we don't have this inode in memory. + * Read the block from disk. +@@ -3820,10 +4014,9 @@ make_io: + submit_bh(READ_META, bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { +- ext4_error(inode->i_sb, "ext4_get_inode_loc", +- "unable to read inode block - " +- "inode=%lu, block=%llu", +- inode->i_ino, block); ++ ext4_error(sb, __func__, ++ "unable to read inode block - inode=%lu, " ++ "block=%llu", inode->i_ino, block); + brelse(bh); + return -EIO; + } +@@ -3915,11 +4108,10 @@ struct inode *ext4_iget(struct super_blo + return inode; + + ei = EXT4_I(inode); +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + ei->i_acl = EXT4_ACL_NOT_CACHED; + ei->i_default_acl = EXT4_ACL_NOT_CACHED; + #endif +- ei->i_block_alloc_info = NULL; + + ret = __ext4_get_inode_loc(inode, &iloc, 0); + if (ret < 0) +@@ -3929,7 +4121,7 @@ struct inode *ext4_iget(struct super_blo + inode->i_mode = le16_to_cpu(raw_inode->i_mode); + inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); +- if(!(test_opt (inode->i_sb, NO_UID32))) { ++ if (!(test_opt(inode->i_sb, NO_UID32))) { + inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + } +@@ -3947,7 +4139,7 @@ struct inode *ext4_iget(struct super_blo + if (inode->i_mode == 0 || + !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) { + /* this inode is deleted */ +- brelse (bh); ++ brelse(bh); + ret = -ESTALE; + goto bad_inode; + } +@@ -3980,7 +4172,7 @@ struct inode *ext4_iget(struct super_blo + ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); + if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > + EXT4_INODE_SIZE(inode->i_sb)) { +- brelse (bh); ++ brelse(bh); + ret = -EIO; + goto bad_inode; + } +@@ -4033,7 +4225,7 @@ struct inode *ext4_iget(struct super_blo + init_special_inode(inode, inode->i_mode, + new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); + } +- brelse (iloc.bh); ++ brelse(iloc.bh); + ext4_set_inode_flags(inode); + unlock_new_inode(inode); + return inode; +@@ -4050,7 +4242,6 @@ static int ext4_inode_blocks_set(handle_ + struct inode *inode = &(ei->vfs_inode); + u64 i_blocks = inode->i_blocks; + struct super_block *sb = inode->i_sb; +- int err = 0; + + if (i_blocks <= ~0U) { + /* +@@ -4060,36 +4251,27 @@ static int ext4_inode_blocks_set(handle_ + raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); + raw_inode->i_blocks_high = 0; + ei->i_flags &= ~EXT4_HUGE_FILE_FL; +- } else if (i_blocks <= 0xffffffffffffULL) { ++ return 0; ++ } ++ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) ++ return -EFBIG; ++ ++ if (i_blocks <= 0xffffffffffffULL) { + /* + * i_blocks can be represented in a 48 bit variable + * as multiple of 512 bytes + */ +- err = ext4_update_rocompat_feature(handle, sb, +- EXT4_FEATURE_RO_COMPAT_HUGE_FILE); +- if (err) +- goto err_out; +- /* i_block is stored in the split 48 bit fields */ + raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); + raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); + ei->i_flags &= ~EXT4_HUGE_FILE_FL; + } else { +- /* +- * i_blocks should be represented in a 48 bit variable +- * as multiple of file system block size +- */ +- err = ext4_update_rocompat_feature(handle, sb, +- EXT4_FEATURE_RO_COMPAT_HUGE_FILE); +- if (err) +- goto err_out; + ei->i_flags |= EXT4_HUGE_FILE_FL; + /* i_block is stored in file system block size */ + i_blocks = i_blocks >> (inode->i_blkbits - 9); + raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); + raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); + } +-err_out: +- return err; ++ return 0; + } + + /* +@@ -4115,14 +4297,14 @@ static int ext4_do_update_inode(handle_t + + ext4_get_inode_flags(ei); + raw_inode->i_mode = cpu_to_le16(inode->i_mode); +- if(!(test_opt(inode->i_sb, NO_UID32))) { ++ if (!(test_opt(inode->i_sb, NO_UID32))) { + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); + raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); + /* + * Fix up interoperability with old kernels. Otherwise, old inodes get + * re-used with the upper 16 bits of the uid/gid intact + */ +- if(!ei->i_dtime) { ++ if (!ei->i_dtime) { + raw_inode->i_uid_high = + cpu_to_le16(high_16_bits(inode->i_uid)); + raw_inode->i_gid_high = +@@ -4210,7 +4392,7 @@ static int ext4_do_update_inode(handle_t + ei->i_state &= ~EXT4_STATE_NEW; + + out_brelse: +- brelse (bh); ++ brelse(bh); + ext4_std_error(inode->i_sb, err); + return err; + } +@@ -4814,6 +4996,7 @@ int ext4_page_mkwrite(struct vm_area_str + loff_t size; + unsigned long len; + int ret = -EINVAL; ++ void *fsdata; + struct file *file = vma->vm_file; + struct inode *inode = file->f_path.dentry->d_inode; + struct address_space *mapping = inode->i_mapping; +@@ -4852,11 +5035,11 @@ int ext4_page_mkwrite(struct vm_area_str + * on the same page though + */ + ret = mapping->a_ops->write_begin(file, mapping, page_offset(page), +- len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); ++ len, AOP_FLAG_UNINTERRUPTIBLE, &page, &fsdata); + if (ret < 0) + goto out_unlock; + ret = mapping->a_ops->write_end(file, mapping, page_offset(page), +- len, len, page, NULL); ++ len, len, page, fsdata); + if (ret < 0) + goto out_unlock; + ret = 0; +diff -rup b/fs/ext4//ioctl.c a/fs/ext4///ioctl.c +--- b/fs/ext4/ioctl.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/ioctl.c 2009-02-10 21:40:11.000000000 +0100 +@@ -23,9 +23,8 @@ long ext4_ioctl(struct file *filp, unsig + struct inode *inode = filp->f_dentry->d_inode; + struct ext4_inode_info *ei = EXT4_I(inode); + unsigned int flags; +- unsigned short rsv_window_size; + +- ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg); ++ ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { + case EXT4_IOC_GETFLAGS: +@@ -34,7 +33,7 @@ long ext4_ioctl(struct file *filp, unsig + return put_user(flags, (int __user *) arg); + case EXT4_IOC_SETFLAGS: { + handle_t *handle = NULL; +- int err; ++ int err, migrate = 0; + struct ext4_iloc iloc; + unsigned int oldflags; + unsigned int jflag; +@@ -82,6 +81,17 @@ long ext4_ioctl(struct file *filp, unsig + if (!capable(CAP_SYS_RESOURCE)) + goto flags_out; + } ++ if (oldflags & EXT4_EXTENTS_FL) { ++ /* We don't support clearning extent flags */ ++ if (!(flags & EXT4_EXTENTS_FL)) { ++ err = -EOPNOTSUPP; ++ goto flags_out; ++ } ++ } else if (flags & EXT4_EXTENTS_FL) { ++ /* migrate the file */ ++ migrate = 1; ++ flags &= ~EXT4_EXTENTS_FL; ++ } + + handle = ext4_journal_start(inode, 1); + if (IS_ERR(handle)) { +@@ -109,6 +119,10 @@ flags_err: + + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) + err = ext4_change_inode_journal_flag(inode, jflag); ++ if (err) ++ goto flags_out; ++ if (migrate) ++ err = ext4_ext_migrate(inode); + flags_out: + mutex_unlock(&inode->i_mutex); + mnt_drop_write(filp->f_path.mnt); +@@ -175,53 +189,10 @@ setversion_out: + return ret; + } + #endif +- case EXT4_IOC_GETRSVSZ: +- if (test_opt(inode->i_sb, RESERVATION) +- && S_ISREG(inode->i_mode) +- && ei->i_block_alloc_info) { +- rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; +- return put_user(rsv_window_size, (int __user *)arg); +- } +- return -ENOTTY; +- case EXT4_IOC_SETRSVSZ: { +- int err; +- +- if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) +- return -ENOTTY; +- +- if (!is_owner_or_cap(inode)) +- return -EACCES; +- +- if (get_user(rsv_window_size, (int __user *)arg)) +- return -EFAULT; +- +- err = mnt_want_write(filp->f_path.mnt); +- if (err) +- return err; +- +- if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) +- rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; +- +- /* +- * need to allocate reservation structure for this inode +- * before set the window size +- */ +- down_write(&ei->i_data_sem); +- if (!ei->i_block_alloc_info) +- ext4_init_block_alloc_info(inode); +- +- if (ei->i_block_alloc_info){ +- struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; +- rsv->rsv_goal_size = rsv_window_size; +- } +- up_write(&ei->i_data_sem); +- mnt_drop_write(filp->f_path.mnt); +- return 0; +- } + case EXT4_IOC_GROUP_EXTEND: { + ext4_fsblk_t n_blocks_count; + struct super_block *sb = inode->i_sb; +- int err; ++ int err, err2; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; +@@ -235,8 +206,10 @@ setversion_out: + + err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); +- jbd2_journal_flush(EXT4_SB(sb)->s_journal); ++ err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); ++ if (err == 0) ++ err = err2; + mnt_drop_write(filp->f_path.mnt); + + return err; +@@ -244,7 +217,7 @@ setversion_out: + case EXT4_IOC_GROUP_ADD: { + struct ext4_new_group_data input; + struct super_block *sb = inode->i_sb; +- int err; ++ int err, err2; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; +@@ -259,8 +232,10 @@ setversion_out: + + err = ext4_group_add(sb, &input); + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); +- jbd2_journal_flush(EXT4_SB(sb)->s_journal); ++ err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); ++ if (err == 0) ++ err = err2; + mnt_drop_write(filp->f_path.mnt); + + return err; +diff -rup b/fs/ext4//mballoc.c a/fs/ext4///mballoc.c +--- b/fs/ext4/mballoc.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/mballoc.c 2009-02-10 21:40:11.000000000 +0100 +@@ -100,7 +100,7 @@ + * inode as: + * + * { page } +- * [ group 0 buddy][ group 0 bitmap] [group 1][ group 1]... ++ * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]... + * + * + * one block each for bitmap and buddy information. So for each group we +@@ -330,6 +330,20 @@ + * object + * + */ ++static struct kmem_cache *ext4_pspace_cachep; ++static struct kmem_cache *ext4_ac_cachep; ++static struct kmem_cache *ext4_free_ext_cachep; ++static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, ++ ext4_group_t group); ++static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, ++ ext4_group_t group); ++static int ext4_mb_init_per_dev_proc(struct super_block *sb); ++static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); ++static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *); ++static void ext4_mb_free_committed_blocks(struct super_block *); ++ ++ ++ + + static inline void *mb_correct_addr_and_bit(int *bit, void *addr) + { +@@ -445,9 +459,9 @@ static void mb_free_blocks_double(struct + blocknr += first + i; + blocknr += + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); +- +- ext4_error(sb, __func__, "double-free of inode" +- " %lu's block %llu(bit %u in group %lu)\n", ++ ext4_grp_locked_error(sb, e4b->bd_group, ++ __func__, "double-free of inode" ++ " %lu's block %llu(bit %u in group %u)\n", + inode ? inode->i_ino : 0, blocknr, + first + i, e4b->bd_group); + } +@@ -477,9 +491,10 @@ static void mb_cmp_bitmaps(struct ext4_b + b2 = (unsigned char *) bitmap; + for (i = 0; i < e4b->bd_sb->s_blocksize; i++) { + if (b1[i] != b2[i]) { +- printk("corruption in group %lu at byte %u(%u):" +- " %x in copy != %x on disk/prealloc\n", +- e4b->bd_group, i, i * 8, b1[i], b2[i]); ++ printk(KERN_ERR "corruption in group %u " ++ "at byte %u(%u): %x in copy != %x " ++ "on disk/prealloc\n", ++ e4b->bd_group, i, i * 8, b1[i], b2[i]); + BUG(); + } + } +@@ -533,9 +548,6 @@ static int __mb_check_buddy(struct ext4_ + void *buddy; + void *buddy2; + +- if (!test_opt(sb, MBALLOC)) +- return 0; +- + { + static int mb_check_counter; + if (mb_check_counter++ % 100 != 0) +@@ -692,8 +704,8 @@ static void ext4_mb_generate_buddy(struc + grp->bb_fragments = fragments; + + if (free != grp->bb_free) { +- ext4_error(sb, __func__, +- "EXT4-fs: group %lu: %u blocks in bitmap, %u in gd\n", ++ ext4_grp_locked_error(sb, group, __func__, ++ "EXT4-fs: group %u: %u blocks in bitmap, %u in gd\n", + group, free, grp->bb_free); + /* + * If we intent to continue, we consider group descritor +@@ -718,7 +730,7 @@ static void ext4_mb_generate_buddy(struc + * stored in the inode as + * + * { page } +- * [ group 0 buddy][ group 0 bitmap] [group 1][ group 1]... ++ * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]... + * + * + * one block each for bitmap and buddy information. +@@ -784,23 +796,45 @@ static int ext4_mb_init_cache(struct pag + if (bh[i] == NULL) + goto out; + +- if (bh_uptodate_or_lock(bh[i])) ++ if (bitmap_uptodate(bh[i])) + continue; + ++ lock_buffer(bh[i]); ++ if (bitmap_uptodate(bh[i])) { ++ unlock_buffer(bh[i]); ++ continue; ++ } + spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + ext4_init_block_bitmap(sb, bh[i], + first_group + i, desc); ++ set_bitmap_uptodate(bh[i]); + set_buffer_uptodate(bh[i]); +- unlock_buffer(bh[i]); + spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); ++ unlock_buffer(bh[i]); + continue; + } + spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); ++ if (buffer_uptodate(bh[i])) { ++ /* ++ * if not uninit if bh is uptodate, ++ * bitmap is also uptodate ++ */ ++ set_bitmap_uptodate(bh[i]); ++ unlock_buffer(bh[i]); ++ continue; ++ } + get_bh(bh[i]); ++ /* ++ * submit the buffer_head for read. We can ++ * safely mark the bitmap as uptodate now. ++ * We do it here so the bitmap uptodate bit ++ * get set with buffer lock held. ++ */ ++ set_bitmap_uptodate(bh[i]); + bh[i]->b_end_io = end_buffer_read_sync; + submit_bh(READ, bh[i]); +- mb_debug("read bitmap for group %lu\n", first_group + i); ++ mb_debug("read bitmap for group %u\n", first_group + i); + } + + /* wait for I/O completion */ +@@ -814,6 +848,8 @@ static int ext4_mb_init_cache(struct pag + + err = 0; + first_block = page->index * blocks_per_page; ++ /* init the page */ ++ memset(page_address(page), 0xff, PAGE_CACHE_SIZE); + for (i = 0; i < blocks_per_page; i++) { + int group; + struct ext4_group_info *grinfo; +@@ -840,7 +876,6 @@ static int ext4_mb_init_cache(struct pag + BUG_ON(incore == NULL); + mb_debug("put buddy for group %u in page %lu/%x\n", + group, page->index, i * blocksize); +- memset(data, 0xff, blocksize); + grinfo = ext4_get_group_info(sb, group); + grinfo->bb_fragments = 0; + memset(grinfo->bb_counters, 0, +@@ -848,7 +883,9 @@ static int ext4_mb_init_cache(struct pag + /* + * incore got set to the group block bitmap below + */ ++ ext4_lock_group(sb, group); + ext4_mb_generate_buddy(sb, data, incore, group); ++ ext4_unlock_group(sb, group); + incore = NULL; + } else { + /* this is block of bitmap */ +@@ -862,6 +899,7 @@ static int ext4_mb_init_cache(struct pag + + /* mark all preallocated blks used in in-core bitmap */ + ext4_mb_generate_from_pa(sb, data, group); ++ ext4_mb_generate_from_freelist(sb, data, group); + ext4_unlock_group(sb, group); + + /* set incore so that the buddy information can be +@@ -885,19 +923,22 @@ out: + static noinline_for_stack int + ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, + struct ext4_buddy *e4b) ++__acquires(e4b->alloc_semp) + { +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct inode *inode = sbi->s_buddy_cache; + int blocks_per_page; + int block; + int pnum; + int poff; + struct page *page; + int ret; ++ struct ext4_group_info *grp; ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct inode *inode = sbi->s_buddy_cache; + +- mb_debug("load group %lu\n", group); ++ mb_debug("load group %u\n", group); + + blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; ++ grp = ext4_get_group_info(sb, group); + + e4b->bd_blkbits = sb->s_blocksize_bits; + e4b->bd_info = ext4_get_group_info(sb, group); +@@ -905,6 +946,16 @@ ext4_mb_load_buddy(struct super_block *s + e4b->bd_group = group; + e4b->bd_buddy_page = NULL; + e4b->bd_bitmap_page = NULL; ++ e4b->alloc_semp = &grp->alloc_sem; ++ ++ /* Take the read lock on the group alloc ++ * sem. This would make sure a parallel ++ * ext4_mb_init_group happening on other ++ * groups mapped by the page is blocked ++ * till we are done with allocation ++ */ ++ down_read(e4b->alloc_semp); ++ __acquire(e4b->alloc_semp); + + /* + * the buddy cache inode stores the block bitmap +@@ -920,6 +971,14 @@ ext4_mb_load_buddy(struct super_block *s + page = find_get_page(inode->i_mapping, pnum); + if (page == NULL || !PageUptodate(page)) { + if (page) ++ /* ++ * drop the page reference and try ++ * to get the page with lock. If we ++ * are not uptodate that implies ++ * somebody just created the page but ++ * is yet to initialize the same. So ++ * wait for it to initialize. ++ */ + page_cache_release(page); + page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); + if (page) { +@@ -985,15 +1044,23 @@ err: + page_cache_release(e4b->bd_buddy_page); + e4b->bd_buddy = NULL; + e4b->bd_bitmap = NULL; ++ ++ /* Done with the buddy cache */ ++ up_read(e4b->alloc_semp); + return ret; + } + + static void ext4_mb_release_desc(struct ext4_buddy *e4b) ++__releases(e4b->alloc_semp) + { + if (e4b->bd_bitmap_page) + page_cache_release(e4b->bd_bitmap_page); + if (e4b->bd_buddy_page) + page_cache_release(e4b->bd_buddy_page); ++ /* Done with the buddy cache */ ++ if (e4b->alloc_semp) ++ up_read(e4b->alloc_semp); ++ __release(e4b->alloc_semp); + } + + +@@ -1031,7 +1098,10 @@ static void mb_clear_bits(spinlock_t *lo + cur += 32; + continue; + } +- mb_clear_bit_atomic(lock, cur, bm); ++ if (lock) ++ mb_clear_bit_atomic(lock, cur, bm); ++ else ++ mb_clear_bit(cur, bm); + cur++; + } + } +@@ -1049,7 +1119,10 @@ static void mb_set_bits(spinlock_t *lock + cur += 32; + continue; + } +- mb_set_bit_atomic(lock, cur, bm); ++ if (lock) ++ mb_set_bit_atomic(lock, cur, bm); ++ else ++ mb_set_bit(cur, bm); + cur++; + } + } +@@ -1094,12 +1167,11 @@ static void mb_free_blocks(struct inode + blocknr += block; + blocknr += + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); +- ext4_unlock_group(sb, e4b->bd_group); +- ext4_error(sb, __func__, "double-free of inode" +- " %lu's block %llu(bit %u in group %lu)\n", ++ ext4_grp_locked_error(sb, e4b->bd_group, ++ __func__, "double-free of inode" ++ " %lu's block %llu(bit %u in group %u)\n", + inode ? inode->i_ino : 0, blocknr, block, + e4b->bd_group); +- ext4_lock_group(sb, e4b->bd_group); + } + mb_clear_bit(block, EXT4_MB_BITMAP(e4b)); + e4b->bd_info->bb_counters[order]++; +@@ -1296,13 +1368,20 @@ static void ext4_mb_use_best_found(struc + ac->ac_tail = ret & 0xffff; + ac->ac_buddy = ret >> 16; + +- /* XXXXXXX: SUCH A HORRIBLE **CK */ +- /*FIXME!! Why ? */ ++ /* ++ * take the page reference. We want the page to be pinned ++ * so that we don't get a ext4_mb_init_cache_call for this ++ * group until we update the bitmap. That would mean we ++ * double allocate blocks. The reference is dropped ++ * in ext4_mb_release_context ++ */ + ac->ac_bitmap_page = e4b->bd_bitmap_page; + get_page(ac->ac_bitmap_page); + ac->ac_buddy_page = e4b->bd_buddy_page; + get_page(ac->ac_buddy_page); +- ++ /* on allocation we use ac to track the held semaphore */ ++ ac->alloc_semp = e4b->alloc_semp; ++ e4b->alloc_semp = NULL; + /* store last allocated for subsequent stream allocation */ + if ((ac->ac_flags & EXT4_MB_HINT_DATA)) { + spin_lock(&sbi->s_md_lock); +@@ -1433,8 +1512,10 @@ static int ext4_mb_try_best_found(struct + + BUG_ON(ex.fe_len <= 0); + err = ext4_mb_load_buddy(ac->ac_sb, group, e4b); +- if (err) ++ if (err) { ++ __release(e4b->alloc_semp); + return err; ++ } + + ext4_lock_group(ac->ac_sb, group); + max = mb_find_extent(e4b, 0, ex.fe_start, ex.fe_len, &ex); +@@ -1464,8 +1545,10 @@ static int ext4_mb_find_by_goal(struct e + return 0; + + err = ext4_mb_load_buddy(ac->ac_sb, group, e4b); +- if (err) ++ if (err) { ++ __release(e4b->alloc_semp); + return err; ++ } + + ext4_lock_group(ac->ac_sb, group); + max = mb_find_extent(e4b, 0, ac->ac_g_ex.fe_start, +@@ -1575,7 +1658,8 @@ static void ext4_mb_complex_scan_group(s + * free blocks even though group info says we + * we have free blocks + */ +- ext4_error(sb, __func__, "%d free blocks as per " ++ ext4_grp_locked_error(sb, e4b->bd_group, ++ __func__, "%d free blocks as per " + "group info. But bitmap says 0\n", + free); + break; +@@ -1584,7 +1668,8 @@ static void ext4_mb_complex_scan_group(s + mb_find_extent(e4b, 0, i, ac->ac_g_ex.fe_len, &ex); + BUG_ON(ex.fe_len <= 0); + if (free < ex.fe_len) { +- ext4_error(sb, __func__, "%d free blocks as per " ++ ext4_grp_locked_error(sb, e4b->bd_group, ++ __func__, "%d free blocks as per " + "group info. But got %d blocks\n", + free, ex.fe_len); + /* +@@ -1692,6 +1777,173 @@ static int ext4_mb_good_group(struct ext + return 0; + } + ++/* ++ * lock the group_info alloc_sem of all the groups ++ * belonging to the same buddy cache page. This ++ * make sure other parallel operation on the buddy ++ * cache doesn't happen whild holding the buddy cache ++ * lock ++ */ ++int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group) ++{ ++ int i; ++ int block, pnum; ++ int blocks_per_page; ++ int groups_per_page; ++ ext4_group_t first_group; ++ struct ext4_group_info *grp; ++ ++ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; ++ /* ++ * the buddy cache inode stores the block bitmap ++ * and buddy information in consecutive blocks. ++ * So for each group we need two blocks. ++ */ ++ block = group * 2; ++ pnum = block / blocks_per_page; ++ first_group = pnum * blocks_per_page / 2; ++ ++ groups_per_page = blocks_per_page >> 1; ++ if (groups_per_page == 0) ++ groups_per_page = 1; ++ /* read all groups the page covers into the cache */ ++ for (i = 0; i < groups_per_page; i++) { ++ ++ if ((first_group + i) >= EXT4_SB(sb)->s_groups_count) ++ break; ++ grp = ext4_get_group_info(sb, first_group + i); ++ /* take all groups write allocation ++ * semaphore. This make sure there is ++ * no block allocation going on in any ++ * of that groups ++ */ ++ down_write_nested(&grp->alloc_sem, i); ++ } ++ return i; ++} ++ ++void ext4_mb_put_buddy_cache_lock(struct super_block *sb, ++ ext4_group_t group, int locked_group) ++{ ++ int i; ++ int block, pnum; ++ int blocks_per_page; ++ ext4_group_t first_group; ++ struct ext4_group_info *grp; ++ ++ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; ++ /* ++ * the buddy cache inode stores the block bitmap ++ * and buddy information in consecutive blocks. ++ * So for each group we need two blocks. ++ */ ++ block = group * 2; ++ pnum = block / blocks_per_page; ++ first_group = pnum * blocks_per_page / 2; ++ /* release locks on all the groups */ ++ for (i = 0; i < locked_group; i++) { ++ ++ grp = ext4_get_group_info(sb, first_group + i); ++ /* take all groups write allocation ++ * semaphore. This make sure there is ++ * no block allocation going on in any ++ * of that groups ++ */ ++ up_write(&grp->alloc_sem); ++ } ++ ++} ++ ++static int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) ++{ ++ ++ int ret; ++ void *bitmap; ++ int blocks_per_page; ++ int block, pnum, poff; ++ int num_grp_locked = 0; ++ struct ext4_group_info *this_grp; ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct inode *inode = sbi->s_buddy_cache; ++ struct page *page = NULL, *bitmap_page = NULL; ++ ++ mb_debug("init group %lu\n", group); ++ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; ++ this_grp = ext4_get_group_info(sb, group); ++ /* ++ * This ensures we don't add group ++ * to this buddy cache via resize ++ */ ++ num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, group); ++ if (!EXT4_MB_GRP_NEED_INIT(this_grp)) { ++ /* ++ * somebody initialized the group ++ * return without doing anything ++ */ ++ ret = 0; ++ goto err; ++ } ++ /* ++ * the buddy cache inode stores the block bitmap ++ * and buddy information in consecutive blocks. ++ * So for each group we need two blocks. ++ */ ++ block = group * 2; ++ pnum = block / blocks_per_page; ++ poff = block % blocks_per_page; ++ page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); ++ if (page) { ++ BUG_ON(page->mapping != inode->i_mapping); ++ ret = ext4_mb_init_cache(page, NULL); ++ if (ret) { ++ unlock_page(page); ++ goto err; ++ } ++ unlock_page(page); ++ } ++ if (page == NULL || !PageUptodate(page)) { ++ ret = -EIO; ++ goto err; ++ } ++ mark_page_accessed(page); ++ bitmap_page = page; ++ bitmap = page_address(page) + (poff * sb->s_blocksize); ++ ++ /* init buddy cache */ ++ block++; ++ pnum = block / blocks_per_page; ++ poff = block % blocks_per_page; ++ page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); ++ if (page == bitmap_page) { ++ /* ++ * If both the bitmap and buddy are in ++ * the same page we don't need to force ++ * init the buddy ++ */ ++ unlock_page(page); ++ } else if (page) { ++ BUG_ON(page->mapping != inode->i_mapping); ++ ret = ext4_mb_init_cache(page, bitmap); ++ if (ret) { ++ unlock_page(page); ++ goto err; ++ } ++ unlock_page(page); ++ } ++ if (page == NULL || !PageUptodate(page)) { ++ ret = -EIO; ++ goto err; ++ } ++ mark_page_accessed(page); ++err: ++ ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked); ++ if (bitmap_page) ++ page_cache_release(bitmap_page); ++ if (page) ++ page_cache_release(page); ++ return ret; ++} ++ + static noinline_for_stack int + ext4_mb_regular_allocator(struct ext4_allocation_context *ac) + { +@@ -1775,7 +2027,7 @@ repeat: + group = 0; + + /* quick check to skip empty groups */ +- grp = ext4_get_group_info(ac->ac_sb, group); ++ grp = ext4_get_group_info(sb, group); + if (grp->bb_free == 0) + continue; + +@@ -1788,10 +2040,9 @@ repeat: + * we need full data about the group + * to make a good selection + */ +- err = ext4_mb_load_buddy(sb, group, &e4b); ++ err = ext4_mb_init_group(sb, group); + if (err) + goto out; +- ext4_mb_release_desc(&e4b); + } + + /* +@@ -1802,8 +2053,10 @@ repeat: + continue; + + err = ext4_mb_load_buddy(sb, group, &e4b); +- if (err) ++ if (err) { ++ __release(e4b->alloc_semp); + goto out; ++ } + + ext4_lock_group(sb, group); + if (!ext4_mb_good_group(ac, group, cr)) { +@@ -1932,13 +2185,13 @@ static int ext4_mb_seq_history_show(stru + if (hs->op == EXT4_MB_HISTORY_ALLOC) { + fmt = "%-5u %-8u %-23s %-23s %-23s %-5u %-5u %-2u " + "%-5u %-5s %-5u %-6u\n"; +- sprintf(buf2, "%lu/%d/%u@%u", hs->result.fe_group, ++ sprintf(buf2, "%u/%d/%u@%u", hs->result.fe_group, + hs->result.fe_start, hs->result.fe_len, + hs->result.fe_logical); +- sprintf(buf, "%lu/%d/%u@%u", hs->orig.fe_group, ++ sprintf(buf, "%u/%d/%u@%u", hs->orig.fe_group, + hs->orig.fe_start, hs->orig.fe_len, + hs->orig.fe_logical); +- sprintf(buf3, "%lu/%d/%u@%u", hs->goal.fe_group, ++ sprintf(buf3, "%u/%d/%u@%u", hs->goal.fe_group, + hs->goal.fe_start, hs->goal.fe_len, + hs->goal.fe_logical); + seq_printf(seq, fmt, hs->pid, hs->ino, buf, buf3, buf2, +@@ -1947,20 +2200,20 @@ static int ext4_mb_seq_history_show(stru + hs->buddy ? 1 << hs->buddy : 0); + } else if (hs->op == EXT4_MB_HISTORY_PREALLOC) { + fmt = "%-5u %-8u %-23s %-23s %-23s\n"; +- sprintf(buf2, "%lu/%d/%u@%u", hs->result.fe_group, ++ sprintf(buf2, "%u/%d/%u@%u", hs->result.fe_group, + hs->result.fe_start, hs->result.fe_len, + hs->result.fe_logical); +- sprintf(buf, "%lu/%d/%u@%u", hs->orig.fe_group, ++ sprintf(buf, "%u/%d/%u@%u", hs->orig.fe_group, + hs->orig.fe_start, hs->orig.fe_len, + hs->orig.fe_logical); + seq_printf(seq, fmt, hs->pid, hs->ino, buf, "", buf2); + } else if (hs->op == EXT4_MB_HISTORY_DISCARD) { +- sprintf(buf2, "%lu/%d/%u", hs->result.fe_group, ++ sprintf(buf2, "%u/%d/%u", hs->result.fe_group, + hs->result.fe_start, hs->result.fe_len); + seq_printf(seq, "%-5u %-8u %-23s discard\n", + hs->pid, hs->ino, buf2); + } else if (hs->op == EXT4_MB_HISTORY_FREE) { +- sprintf(buf2, "%lu/%d/%u", hs->result.fe_group, ++ sprintf(buf2, "%u/%d/%u", hs->result.fe_group, + hs->result.fe_start, hs->result.fe_len); + seq_printf(seq, "%-5u %-8u %-23s free\n", + hs->pid, hs->ino, buf2); +@@ -2073,7 +2326,7 @@ static void *ext4_mb_seq_groups_start(st + return NULL; + + group = *pos + 1; +- return (void *) group; ++ return (void *) ((unsigned long) group); + } + + static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos) +@@ -2086,13 +2339,13 @@ static void *ext4_mb_seq_groups_next(str + if (*pos < 0 || *pos >= sbi->s_groups_count) + return NULL; + group = *pos + 1; +- return (void *) group;; ++ return (void *) ((unsigned long) group); + } + + static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v) + { + struct super_block *sb = seq->private; +- long group = (long) v; ++ ext4_group_t group = (ext4_group_t) ((unsigned long) v); + int i; + int err; + struct ext4_buddy e4b; +@@ -2114,7 +2367,8 @@ static int ext4_mb_seq_groups_show(struc + sizeof(struct ext4_group_info); + err = ext4_mb_load_buddy(sb, group, &e4b); + if (err) { +- seq_printf(seq, "#%-5lu: I/O error\n", group); ++ __release(e4b->alloc_semp); ++ seq_printf(seq, "#%-5u: I/O error\n", group); + return 0; + } + ext4_lock_group(sb, group); +@@ -2122,7 +2376,7 @@ static int ext4_mb_seq_groups_show(struc + ext4_unlock_group(sb, group); + ext4_mb_release_desc(&e4b); + +- seq_printf(seq, "#%-5lu: %-5u %-5u %-5u [", group, sg.info.bb_free, ++ seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free, + sg.info.bb_fragments, sg.info.bb_first_free); + for (i = 0; i <= 13; i++) + seq_printf(seq, " %-5u", i <= sb->s_blocksize_bits + 1 ? +@@ -2169,9 +2423,10 @@ static void ext4_mb_history_release(stru + { + struct ext4_sb_info *sbi = EXT4_SB(sb); + +- remove_proc_entry("mb_groups", sbi->s_mb_proc); +- remove_proc_entry("mb_history", sbi->s_mb_proc); +- ++ if (sbi->s_proc != NULL) { ++ remove_proc_entry("mb_groups", sbi->s_proc); ++ remove_proc_entry("mb_history", sbi->s_proc); ++ } + kfree(sbi->s_mb_history); + } + +@@ -2180,10 +2435,10 @@ static void ext4_mb_history_init(struct + struct ext4_sb_info *sbi = EXT4_SB(sb); + int i; + +- if (sbi->s_mb_proc != NULL) { +- proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc, ++ if (sbi->s_proc != NULL) { ++ proc_create_data("mb_history", S_IRUGO, sbi->s_proc, + &ext4_mb_seq_history_fops, sb); +- proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc, ++ proc_create_data("mb_groups", S_IRUGO, sbi->s_proc, + &ext4_mb_seq_groups_fops, sb); + } + +@@ -2295,10 +2550,12 @@ int ext4_mb_add_groupinfo(struct super_b + ext4_free_blocks_after_init(sb, group, desc); + } else { + meta_group_info[i]->bb_free = +- le16_to_cpu(desc->bg_free_blocks_count); ++ ext4_free_blks_count(sb, desc); + } + + INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list); ++ init_rwsem(&meta_group_info[i]->alloc_sem); ++ meta_group_info[i]->bb_free_root.rb_node = NULL;; + + #ifdef DOUBLE_CHECK + { +@@ -2325,54 +2582,6 @@ exit_meta_group_info: + } /* ext4_mb_add_groupinfo */ + + /* +- * Add a group to the existing groups. +- * This function is used for online resize +- */ +-int ext4_mb_add_more_groupinfo(struct super_block *sb, ext4_group_t group, +- struct ext4_group_desc *desc) +-{ +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct inode *inode = sbi->s_buddy_cache; +- int blocks_per_page; +- int block; +- int pnum; +- struct page *page; +- int err; +- +- /* Add group based on group descriptor*/ +- err = ext4_mb_add_groupinfo(sb, group, desc); +- if (err) +- return err; +- +- /* +- * Cache pages containing dynamic mb_alloc datas (buddy and bitmap +- * datas) are set not up to date so that they will be re-initilaized +- * during the next call to ext4_mb_load_buddy +- */ +- +- /* Set buddy page as not up to date */ +- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; +- block = group * 2; +- pnum = block / blocks_per_page; +- page = find_get_page(inode->i_mapping, pnum); +- if (page != NULL) { +- ClearPageUptodate(page); +- page_cache_release(page); +- } +- +- /* Set bitmap page as not up to date */ +- block++; +- pnum = block / blocks_per_page; +- page = find_get_page(inode->i_mapping, pnum); +- if (page != NULL) { +- ClearPageUptodate(page); +- page_cache_release(page); +- } +- +- return 0; +-} +- +-/* + * Update an existing group. + * This function is used for online resize + */ +@@ -2455,7 +2664,7 @@ static int ext4_mb_init_backend(struct s + desc = ext4_get_group_desc(sb, i, NULL); + if (desc == NULL) { + printk(KERN_ERR +- "EXT4-fs: can't read descriptor %lu\n", i); ++ "EXT4-fs: can't read descriptor %u\n", i); + goto err_freebuddy; + } + if (ext4_mb_add_groupinfo(sb, i, desc) != 0) +@@ -2485,19 +2694,14 @@ int ext4_mb_init(struct super_block *sb, + unsigned max; + int ret; + +- if (!test_opt(sb, MBALLOC)) +- return 0; +- + i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short); + + sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL); + if (sbi->s_mb_offsets == NULL) { +- clear_opt(sbi->s_mount_opt, MBALLOC); + return -ENOMEM; + } + sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL); + if (sbi->s_mb_maxs == NULL) { +- clear_opt(sbi->s_mount_opt, MBALLOC); + kfree(sbi->s_mb_maxs); + return -ENOMEM; + } +@@ -2520,7 +2724,6 @@ int ext4_mb_init(struct super_block *sb, + /* init file for buddy data */ + ret = ext4_mb_init_backend(sb); + if (ret != 0) { +- clear_opt(sbi->s_mount_opt, MBALLOC); + kfree(sbi->s_mb_offsets); + kfree(sbi->s_mb_maxs); + return ret; +@@ -2540,17 +2743,15 @@ int ext4_mb_init(struct super_block *sb, + sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT; + sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC; + +- i = sizeof(struct ext4_locality_group) * nr_cpu_ids; +- sbi->s_locality_groups = kmalloc(i, GFP_KERNEL); ++ sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group); + if (sbi->s_locality_groups == NULL) { +- clear_opt(sbi->s_mount_opt, MBALLOC); + kfree(sbi->s_mb_offsets); + kfree(sbi->s_mb_maxs); + return -ENOMEM; + } +- for (i = 0; i < nr_cpu_ids; i++) { ++ for_each_possible_cpu(i) { + struct ext4_locality_group *lg; +- lg = &sbi->s_locality_groups[i]; ++ lg = per_cpu_ptr(sbi->s_locality_groups, i); + mutex_init(&lg->lg_mutex); + for (j = 0; j < PREALLOC_TB_SIZE; j++) + INIT_LIST_HEAD(&lg->lg_prealloc_list[j]); +@@ -2560,7 +2761,7 @@ int ext4_mb_init(struct super_block *sb, + ext4_mb_init_per_dev_proc(sb); + ext4_mb_history_init(sb); + +- printk("EXT4-fs: mballoc enabled\n"); ++ printk(KERN_INFO "EXT4-fs: mballoc enabled\n"); + return 0; + } + +@@ -2589,9 +2790,6 @@ int ext4_mb_release(struct super_block * + struct ext4_group_info *grinfo; + struct ext4_sb_info *sbi = EXT4_SB(sb); + +- if (!test_opt(sb, MBALLOC)) +- return 0; +- + /* release freed, non-committed blocks */ + spin_lock(&sbi->s_md_lock); + list_splice_init(&sbi->s_closed_transaction, +@@ -2647,8 +2845,7 @@ int ext4_mb_release(struct super_block * + atomic_read(&sbi->s_mb_discarded)); + } + +- kfree(sbi->s_locality_groups); +- ++ free_percpu(sbi->s_locality_groups); + ext4_mb_history_release(sb); + ext4_mb_destroy_per_dev_proc(sb); + +@@ -2658,13 +2855,11 @@ int ext4_mb_release(struct super_block * + static noinline_for_stack void + ext4_mb_free_committed_blocks(struct super_block *sb) + { +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- int err; +- int i; +- int count = 0; +- int count2 = 0; +- struct ext4_free_metadata *md; + struct ext4_buddy e4b; ++ struct ext4_group_info *db; ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ int err, count = 0, count2 = 0; ++ struct ext4_free_data *entry; + + if (list_empty(&sbi->s_committed_transaction)) + return; +@@ -2672,44 +2867,46 @@ ext4_mb_free_committed_blocks(struct sup + /* there is committed blocks to be freed yet */ + do { + /* get next array of blocks */ +- md = NULL; ++ entry = NULL; + spin_lock(&sbi->s_md_lock); + if (!list_empty(&sbi->s_committed_transaction)) { +- md = list_entry(sbi->s_committed_transaction.next, +- struct ext4_free_metadata, list); +- list_del(&md->list); ++ entry = list_entry(sbi->s_committed_transaction.next, ++ struct ext4_free_data, list); ++ list_del(&entry->list); + } + spin_unlock(&sbi->s_md_lock); + +- if (md == NULL) ++ if (entry == NULL) + break; + +- mb_debug("gonna free %u blocks in group %lu (0x%p):", +- md->num, md->group, md); ++ mb_debug("gonna free %u blocks in group %u (0x%p):", ++ entry->count, entry->group, entry); + +- err = ext4_mb_load_buddy(sb, md->group, &e4b); ++ err = ext4_mb_load_buddy(sb, entry->group, &e4b); + /* we expect to find existing buddy because it's pinned */ + BUG_ON(err != 0); + ++ db = e4b.bd_info; + /* there are blocks to put in buddy to make them really free */ +- count += md->num; ++ count += entry->count; + count2++; +- ext4_lock_group(sb, md->group); +- for (i = 0; i < md->num; i++) { +- mb_debug(" %u", md->blocks[i]); +- mb_free_blocks(NULL, &e4b, md->blocks[i], 1); +- } +- mb_debug("\n"); +- ext4_unlock_group(sb, md->group); +- +- /* balance refcounts from ext4_mb_free_metadata() */ +- page_cache_release(e4b.bd_buddy_page); +- page_cache_release(e4b.bd_bitmap_page); ++ ext4_lock_group(sb, entry->group); ++ /* Take it out of per group rb tree */ ++ rb_erase(&entry->node, &(db->bb_free_root)); ++ mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count); ++ ++ if (!db->bb_free_root.rb_node) { ++ /* No more items in the per group rb tree ++ * balance refcounts from ext4_mb_free_metadata() ++ */ ++ page_cache_release(e4b.bd_buddy_page); ++ page_cache_release(e4b.bd_bitmap_page); ++ } ++ ext4_unlock_group(sb, entry->group); + +- kfree(md); ++ kmem_cache_free(ext4_free_ext_cachep, entry); + ext4_mb_release_desc(&e4b); +- +- } while (md); ++ } while (1); + + mb_debug("freed %u blocks in %u structures\n", count, count2); + } +@@ -2721,129 +2918,52 @@ ext4_mb_free_committed_blocks(struct sup + #define EXT4_MB_STREAM_REQ "stream_req" + #define EXT4_MB_GROUP_PREALLOC "group_prealloc" + +- +- +-#define MB_PROC_FOPS(name) \ +-static int ext4_mb_##name##_proc_show(struct seq_file *m, void *v) \ +-{ \ +- struct ext4_sb_info *sbi = m->private; \ +- \ +- seq_printf(m, "%ld\n", sbi->s_mb_##name); \ +- return 0; \ +-} \ +- \ +-static int ext4_mb_##name##_proc_open(struct inode *inode, struct file *file)\ +-{ \ +- return single_open(file, ext4_mb_##name##_proc_show, PDE(inode)->data);\ +-} \ +- \ +-static ssize_t ext4_mb_##name##_proc_write(struct file *file, \ +- const char __user *buf, size_t cnt, loff_t *ppos) \ +-{ \ +- struct ext4_sb_info *sbi = PDE(file->f_path.dentry->d_inode)->data;\ +- char str[32]; \ +- long value; \ +- if (cnt >= sizeof(str)) \ +- return -EINVAL; \ +- if (copy_from_user(str, buf, cnt)) \ +- return -EFAULT; \ +- value = simple_strtol(str, NULL, 0); \ +- if (value <= 0) \ +- return -ERANGE; \ +- sbi->s_mb_##name = value; \ +- return cnt; \ +-} \ +- \ +-static const struct file_operations ext4_mb_##name##_proc_fops = { \ +- .owner = THIS_MODULE, \ +- .open = ext4_mb_##name##_proc_open, \ +- .read = seq_read, \ +- .llseek = seq_lseek, \ +- .release = single_release, \ +- .write = ext4_mb_##name##_proc_write, \ +-}; +- +-MB_PROC_FOPS(stats); +-MB_PROC_FOPS(max_to_scan); +-MB_PROC_FOPS(min_to_scan); +-MB_PROC_FOPS(order2_reqs); +-MB_PROC_FOPS(stream_request); +-MB_PROC_FOPS(group_prealloc); +- +-#define MB_PROC_HANDLER(name, var) \ +-do { \ +- proc = proc_create_data(name, mode, sbi->s_mb_proc, \ +- &ext4_mb_##var##_proc_fops, sbi); \ +- if (proc == NULL) { \ +- printk(KERN_ERR "EXT4-fs: can't to create %s\n", name); \ +- goto err_out; \ +- } \ +-} while (0) +- + static int ext4_mb_init_per_dev_proc(struct super_block *sb) + { ++#ifdef CONFIG_PROC_FS + mode_t mode = S_IFREG | S_IRUGO | S_IWUSR; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct proc_dir_entry *proc; +- char devname[BDEVNAME_SIZE], *p; + +- if (proc_root_ext4 == NULL) { +- sbi->s_mb_proc = NULL; ++ if (sbi->s_proc == NULL) + return -EINVAL; +- } +- bdevname(sb->s_bdev, devname); +- p = devname; +- while ((p = strchr(p, '/'))) +- *p = '!'; +- +- sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4); +- if (!sbi->s_mb_proc) +- goto err_create_dir; +- +- MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats); +- MB_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, max_to_scan); +- MB_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, min_to_scan); +- MB_PROC_HANDLER(EXT4_MB_ORDER2_REQ, order2_reqs); +- MB_PROC_HANDLER(EXT4_MB_STREAM_REQ, stream_request); +- MB_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, group_prealloc); + ++ EXT4_PROC_HANDLER(EXT4_MB_STATS_NAME, mb_stats); ++ EXT4_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, mb_max_to_scan); ++ EXT4_PROC_HANDLER(EXT4_MB_MIN_TO_SCAN_NAME, mb_min_to_scan); ++ EXT4_PROC_HANDLER(EXT4_MB_ORDER2_REQ, mb_order2_reqs); ++ EXT4_PROC_HANDLER(EXT4_MB_STREAM_REQ, mb_stream_request); ++ EXT4_PROC_HANDLER(EXT4_MB_GROUP_PREALLOC, mb_group_prealloc); + return 0; + + err_out: +- remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc); +- remove_proc_entry(devname, proc_root_ext4); +- sbi->s_mb_proc = NULL; +-err_create_dir: +- printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname); +- ++ remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc); + return -ENOMEM; ++#else ++ return 0; ++#endif + } + + static int ext4_mb_destroy_per_dev_proc(struct super_block *sb) + { ++#ifdef CONFIG_PROC_FS + struct ext4_sb_info *sbi = EXT4_SB(sb); +- char devname[BDEVNAME_SIZE], *p; + +- if (sbi->s_mb_proc == NULL) ++ if (sbi->s_proc == NULL) + return -EINVAL; + +- bdevname(sb->s_bdev, devname); +- p = devname; +- while ((p = strchr(p, '/'))) +- *p = '!'; +- remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc); +- remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc); +- remove_proc_entry(devname, proc_root_ext4); +- ++ remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_MIN_TO_SCAN_NAME, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_MAX_TO_SCAN_NAME, sbi->s_proc); ++ remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_proc); ++#endif + return 0; + } + +@@ -2864,11 +2984,16 @@ int __init init_ext4_mballoc(void) + kmem_cache_destroy(ext4_pspace_cachep); + return -ENOMEM; + } +-#ifdef CONFIG_PROC_FS +- proc_root_ext4 = proc_mkdir("fs/ext4", NULL); +- if (proc_root_ext4 == NULL) +- printk(KERN_ERR "EXT4-fs: Unable to create fs/ext4\n"); +-#endif ++ ++ ext4_free_ext_cachep = ++ kmem_cache_create("ext4_free_block_extents", ++ sizeof(struct ext4_free_data), ++ 0, SLAB_RECLAIM_ACCOUNT, NULL); ++ if (ext4_free_ext_cachep == NULL) { ++ kmem_cache_destroy(ext4_pspace_cachep); ++ kmem_cache_destroy(ext4_ac_cachep); ++ return -ENOMEM; ++ } + return 0; + } + +@@ -2877,9 +3002,7 @@ void exit_ext4_mballoc(void) + /* XXX: synchronize_rcu(); */ + kmem_cache_destroy(ext4_pspace_cachep); + kmem_cache_destroy(ext4_ac_cachep); +-#ifdef CONFIG_PROC_FS +- remove_proc_entry("fs/ext4", NULL); +-#endif ++ kmem_cache_destroy(ext4_free_ext_cachep); + } + + +@@ -2889,7 +3012,7 @@ void exit_ext4_mballoc(void) + */ + static noinline_for_stack int + ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, +- handle_t *handle) ++ handle_t *handle, unsigned int reserv_blks) + { + struct buffer_head *bitmap_bh = NULL; + struct ext4_super_block *es; +@@ -2922,7 +3045,7 @@ ext4_mb_mark_diskspace_used(struct ext4_ + if (!gdp) + goto out_err; + +- ext4_debug("using block group %lu(%d)\n", ac->ac_b_ex.fe_group, ++ ext4_debug("using block group %u(%d)\n", ac->ac_b_ex.fe_group, + gdp->bg_free_blocks_count); + + err = ext4_journal_get_write_access(handle, gdp_bh); +@@ -2941,8 +3064,8 @@ ext4_mb_mark_diskspace_used(struct ext4_ + in_range(block + len - 1, ext4_inode_table(sb, gdp), + EXT4_SB(sb)->s_itb_per_group)) { + ext4_error(sb, __func__, +- "Allocating block in system zone - block = %llu", +- block); ++ "Allocating block %llu in system zone of %d group\n", ++ block, ac->ac_b_ex.fe_group); + /* File system mounted not to panic on error + * Fix the bitmap and repeat the block allocation + * We leak some of the blocks here. +@@ -2964,29 +3087,29 @@ ext4_mb_mark_diskspace_used(struct ext4_ + } + } + #endif +- mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group), bitmap_bh->b_data, +- ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len); +- + spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); ++ mb_set_bits(NULL, bitmap_bh->b_data, ++ ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len); + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); +- gdp->bg_free_blocks_count = +- cpu_to_le16(ext4_free_blocks_after_init(sb, +- ac->ac_b_ex.fe_group, +- gdp)); ++ ext4_free_blks_set(sb, gdp, ++ ext4_free_blocks_after_init(sb, ++ ac->ac_b_ex.fe_group, gdp)); + } +- le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len); ++ len = ext4_free_blks_count(sb, gdp) - ac->ac_b_ex.fe_len; ++ ext4_free_blks_set(sb, gdp, len); + gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); + spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); +- ++ percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len); + /* +- * free blocks account has already be reduced/reserved +- * at write_begin() time for delayed allocation +- * do not double accounting ++ * Now reduce the dirty block count also. Should not go negative + */ + if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED)) +- percpu_counter_sub(&sbi->s_freeblocks_counter, +- ac->ac_b_ex.fe_len); ++ /* release all the reserved blocks if non delalloc */ ++ percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks); ++ else ++ percpu_counter_sub(&sbi->s_dirtyblocks_counter, ++ ac->ac_b_ex.fe_len); + + if (sbi->s_log_groups_per_flex) { + ext4_group_t flex_group = ext4_flex_group(sbi, +@@ -3128,7 +3251,7 @@ ext4_mb_normalize_request(struct ext4_al + /* check we don't cross already preallocated blocks */ + rcu_read_lock(); + list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { +- unsigned long pa_end; ++ ext4_lblk_t pa_end; + + if (pa->pa_deleted) + continue; +@@ -3172,7 +3295,7 @@ ext4_mb_normalize_request(struct ext4_al + /* XXX: extra loop to check we really don't overlap preallocations */ + rcu_read_lock(); + list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { +- unsigned long pa_end; ++ ext4_lblk_t pa_end; + spin_lock(&pa->pa_lock); + if (pa->pa_deleted == 0) { + pa_end = pa->pa_lstart + pa->pa_len; +@@ -3404,6 +3527,32 @@ ext4_mb_use_preallocated(struct ext4_all + } + + /* ++ * the function goes through all block freed in the group ++ * but not yet committed and marks them used in in-core bitmap. ++ * buddy must be generated from this bitmap ++ * Need to be called with ext4 group lock (ext4_lock_group) ++ */ ++static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, ++ ext4_group_t group) ++{ ++ struct rb_node *n; ++ struct ext4_group_info *grp; ++ struct ext4_free_data *entry; ++ ++ grp = ext4_get_group_info(sb, group); ++ n = rb_first(&(grp->bb_free_root)); ++ ++ while (n) { ++ entry = rb_entry(n, struct ext4_free_data, node); ++ mb_set_bits(sb_bgl_lock(EXT4_SB(sb), group), ++ bitmap, entry->start_blk, ++ entry->count); ++ n = rb_next(n); ++ } ++ return; ++} ++ ++/* + * the function goes through all preallocation in this group and marks them + * used in in-core bitmap. buddy must be generated from this bitmap + * Need to be called with ext4 group lock (ext4_lock_group) +@@ -3443,7 +3592,7 @@ static void ext4_mb_generate_from_pa(str + preallocated += len; + count++; + } +- mb_debug("prellocated %u for group %lu\n", preallocated, group); ++ mb_debug("prellocated %u for group %u\n", preallocated, group); + } + + static void ext4_mb_pa_callback(struct rcu_head *head) +@@ -3460,7 +3609,7 @@ static void ext4_mb_pa_callback(struct r + static void ext4_mb_put_pa(struct ext4_allocation_context *ac, + struct super_block *sb, struct ext4_prealloc_space *pa) + { +- unsigned long grp; ++ ext4_group_t grp; + + if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) + return; +@@ -3676,8 +3825,8 @@ ext4_mb_release_inode_pa(struct ext4_bud + { + struct super_block *sb = e4b->bd_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); +- unsigned long end; +- unsigned long next; ++ unsigned int end; ++ unsigned int next; + ext4_group_t group; + ext4_grpblk_t bit; + sector_t start; +@@ -3723,8 +3872,9 @@ ext4_mb_release_inode_pa(struct ext4_bud + pa, (unsigned long) pa->pa_lstart, + (unsigned long) pa->pa_pstart, + (unsigned long) pa->pa_len); +- ext4_error(sb, __func__, "free %u, pa_free %u\n", +- free, pa->pa_free); ++ ext4_grp_locked_error(sb, group, ++ __func__, "free %u, pa_free %u\n", ++ free, pa->pa_free); + /* + * pa is already deleted so we use the value obtained + * from the bitmap and continue. +@@ -3789,7 +3939,7 @@ ext4_mb_discard_group_preallocations(str + int busy = 0; + int free = 0; + +- mb_debug("discard preallocation for group %lu\n", group); ++ mb_debug("discard preallocation for group %u\n", group); + + if (list_empty(&grp->bb_prealloc_list)) + return 0; +@@ -3797,14 +3947,15 @@ ext4_mb_discard_group_preallocations(str + bitmap_bh = ext4_read_block_bitmap(sb, group); + if (bitmap_bh == NULL) { + ext4_error(sb, __func__, "Error in reading block " +- "bitmap for %lu\n", group); ++ "bitmap for %u\n", group); + return 0; + } + + err = ext4_mb_load_buddy(sb, group, &e4b); + if (err) { ++ __release(e4b->alloc_semp); + ext4_error(sb, __func__, "Error in loading buddy " +- "information for %lu\n", group); ++ "information for %u\n", group); + put_bh(bitmap_bh); + return 0; + } +@@ -3894,7 +4045,7 @@ out: + * + * FIXME!! Make sure it is valid at all the call sites + */ +-void ext4_mb_discard_inode_preallocations(struct inode *inode) ++void ext4_discard_preallocations(struct inode *inode) + { + struct ext4_inode_info *ei = EXT4_I(inode); + struct super_block *sb = inode->i_sb; +@@ -3906,7 +4057,7 @@ void ext4_mb_discard_inode_preallocation + struct ext4_buddy e4b; + int err; + +- if (!test_opt(sb, MBALLOC) || !S_ISREG(inode->i_mode)) { ++ if (!S_ISREG(inode->i_mode)) { + /*BUG_ON(!list_empty(&ei->i_prealloc_list));*/ + return; + } +@@ -3970,15 +4121,16 @@ repeat: + + err = ext4_mb_load_buddy(sb, group, &e4b); + if (err) { ++ __release(e4b->alloc_semp); + ext4_error(sb, __func__, "Error in loading buddy " +- "information for %lu\n", group); ++ "information for %u\n", group); + continue; + } + + bitmap_bh = ext4_read_block_bitmap(sb, group); + if (bitmap_bh == NULL) { + ext4_error(sb, __func__, "Error in reading block " +- "bitmap for %lu\n", group); ++ "bitmap for %u\n", group); + ext4_mb_release_desc(&e4b); + continue; + } +@@ -4104,8 +4256,7 @@ static void ext4_mb_group_or_file(struct + * per cpu locality group is to reduce the contention between block + * request from multiple CPUs. + */ +- ac->ac_lg = &sbi->s_locality_groups[get_cpu()]; +- put_cpu(); ++ ac->ac_lg = per_cpu_ptr(sbi->s_locality_groups, raw_smp_processor_id()); + + /* we're going to use group allocation */ + ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC; +@@ -4122,8 +4273,8 @@ ext4_mb_initialize_context(struct ext4_a + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + ext4_group_t group; +- unsigned long len; +- unsigned long goal; ++ unsigned int len; ++ ext4_fsblk_t goal; + ext4_grpblk_t block; + + /* we can't allocate > group size */ +@@ -4166,6 +4317,7 @@ ext4_mb_initialize_context(struct ext4_a + ac->ac_pa = NULL; + ac->ac_bitmap_page = NULL; + ac->ac_buddy_page = NULL; ++ ac->alloc_semp = NULL; + ac->ac_lg = NULL; + + /* we have to define context: we'll we work with a file or +@@ -4243,8 +4395,9 @@ ext4_mb_discard_lg_preallocations(struct + + ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL); + if (ext4_mb_load_buddy(sb, group, &e4b)) { ++ __release(e4b->alloc_semp); + ext4_error(sb, __func__, "Error in loading buddy " +- "information for %lu\n", group); ++ "information for %u\n", group); + continue; + } + ext4_lock_group(sb, group); +@@ -4346,6 +4499,8 @@ static int ext4_mb_release_context(struc + } + ext4_mb_put_pa(ac, ac->ac_sb, pa); + } ++ if (ac->alloc_semp) ++ up_read(ac->alloc_semp); + if (ac->ac_bitmap_page) + page_cache_release(ac->ac_bitmap_page); + if (ac->ac_buddy_page) +@@ -4379,40 +4534,39 @@ static int ext4_mb_discard_preallocation + ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, + struct ext4_allocation_request *ar, int *errp) + { ++ int freed; + struct ext4_allocation_context *ac = NULL; + struct ext4_sb_info *sbi; + struct super_block *sb; + ext4_fsblk_t block = 0; +- int freed; +- int inquota; ++ unsigned int inquota; ++ unsigned int reserv_blks = 0; + + sb = ar->inode->i_sb; + sbi = EXT4_SB(sb); + +- if (!test_opt(sb, MBALLOC)) { +- block = ext4_old_new_blocks(handle, ar->inode, ar->goal, +- &(ar->len), errp); +- return block; +- } + if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) { + /* + * With delalloc we already reserved the blocks + */ +- ar->len = ext4_has_free_blocks(sbi, ar->len); +- } +- +- if (ar->len == 0) { +- *errp = -ENOSPC; +- return 0; ++ while (ar->len && ext4_claim_free_blocks(sbi, ar->len)) { ++ /* let others to free the space */ ++ yield(); ++ ar->len = ar->len >> 1; ++ } ++ if (!ar->len) { ++ *errp = -ENOSPC; ++ return 0; ++ } ++ reserv_blks = ar->len; + } +- + while (ar->len && DQUOT_ALLOC_BLOCK(ar->inode, ar->len)) { + ar->flags |= EXT4_MB_HINT_NOPREALLOC; + ar->len--; + } + if (ar->len == 0) { + *errp = -EDQUOT; +- return 0; ++ goto out3; + } + inquota = ar->len; + +@@ -4449,10 +4603,14 @@ repeat: + ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) + ext4_mb_new_preallocation(ac); + } +- + if (likely(ac->ac_status == AC_STATUS_FOUND)) { +- *errp = ext4_mb_mark_diskspace_used(ac, handle); ++ *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks); + if (*errp == -EAGAIN) { ++ /* ++ * drop the reference that we took ++ * in ext4_mb_use_best_found ++ */ ++ ext4_mb_release_context(ac); + ac->ac_b_ex.fe_group = 0; + ac->ac_b_ex.fe_start = 0; + ac->ac_b_ex.fe_len = 0; +@@ -4483,6 +4641,13 @@ out2: + out1: + if (ar->len < inquota) + DQUOT_FREE_BLOCK(ar->inode, inquota - ar->len); ++out3: ++ if (!ar->len) { ++ if (!EXT4_I(ar->inode)->i_delalloc_reserved_flag) ++ /* release all the reserved blocks if non delalloc */ ++ percpu_counter_sub(&sbi->s_dirtyblocks_counter, ++ reserv_blks); ++ } + + return block; + } +@@ -4517,65 +4682,97 @@ static void ext4_mb_poll_new_transaction + ext4_mb_free_committed_blocks(sb); + } + ++/* ++ * We can merge two free data extents only if the physical blocks ++ * are contiguous, AND the extents were freed by the same transaction, ++ * AND the blocks are associated with the same group. ++ */ ++static int can_merge(struct ext4_free_data *entry1, ++ struct ext4_free_data *entry2) ++{ ++ if ((entry1->t_tid == entry2->t_tid) && ++ (entry1->group == entry2->group) && ++ ((entry1->start_blk + entry1->count) == entry2->start_blk)) ++ return 1; ++ return 0; ++} ++ + static noinline_for_stack int + ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, +- ext4_group_t group, ext4_grpblk_t block, int count) ++ struct ext4_free_data *new_entry) + { ++ ext4_grpblk_t block; ++ struct ext4_free_data *entry; + struct ext4_group_info *db = e4b->bd_info; + struct super_block *sb = e4b->bd_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct ext4_free_metadata *md; +- int i; ++ struct rb_node **n = &db->bb_free_root.rb_node, *node; ++ struct rb_node *parent = NULL, *new_node; + + BUG_ON(e4b->bd_bitmap_page == NULL); + BUG_ON(e4b->bd_buddy_page == NULL); + +- ext4_lock_group(sb, group); +- for (i = 0; i < count; i++) { +- md = db->bb_md_cur; +- if (md && db->bb_tid != handle->h_transaction->t_tid) { +- db->bb_md_cur = NULL; +- md = NULL; ++ new_node = &new_entry->node; ++ block = new_entry->start_blk; ++ ++ if (!*n) { ++ /* first free block exent. We need to ++ protect buddy cache from being freed, ++ * otherwise we'll refresh it from ++ * on-disk bitmap and lose not-yet-available ++ * blocks */ ++ page_cache_get(e4b->bd_buddy_page); ++ page_cache_get(e4b->bd_bitmap_page); ++ } ++ while (*n) { ++ parent = *n; ++ entry = rb_entry(parent, struct ext4_free_data, node); ++ if (block < entry->start_blk) ++ n = &(*n)->rb_left; ++ else if (block >= (entry->start_blk + entry->count)) ++ n = &(*n)->rb_right; ++ else { ++ ext4_grp_locked_error(sb, e4b->bd_group, __func__, ++ "Double free of blocks %d (%d %d)\n", ++ block, entry->start_blk, entry->count); ++ return 0; + } ++ } + +- if (md == NULL) { +- ext4_unlock_group(sb, group); +- md = kmalloc(sizeof(*md), GFP_NOFS); +- if (md == NULL) +- return -ENOMEM; +- md->num = 0; +- md->group = group; ++ rb_link_node(new_node, parent, n); ++ rb_insert_color(new_node, &db->bb_free_root); + +- ext4_lock_group(sb, group); +- if (db->bb_md_cur == NULL) { +- spin_lock(&sbi->s_md_lock); +- list_add(&md->list, &sbi->s_active_transaction); +- spin_unlock(&sbi->s_md_lock); +- /* protect buddy cache from being freed, +- * otherwise we'll refresh it from +- * on-disk bitmap and lose not-yet-available +- * blocks */ +- page_cache_get(e4b->bd_buddy_page); +- page_cache_get(e4b->bd_bitmap_page); +- db->bb_md_cur = md; +- db->bb_tid = handle->h_transaction->t_tid; +- mb_debug("new md 0x%p for group %lu\n", +- md, md->group); +- } else { +- kfree(md); +- md = db->bb_md_cur; +- } ++ /* Now try to see the extent can be merged to left and right */ ++ node = rb_prev(new_node); ++ if (node) { ++ entry = rb_entry(node, struct ext4_free_data, node); ++ if (can_merge(entry, new_entry)) { ++ new_entry->start_blk = entry->start_blk; ++ new_entry->count += entry->count; ++ rb_erase(node, &(db->bb_free_root)); ++ spin_lock(&sbi->s_md_lock); ++ list_del(&entry->list); ++ spin_unlock(&sbi->s_md_lock); ++ kmem_cache_free(ext4_free_ext_cachep, entry); + } ++ } + +- BUG_ON(md->num >= EXT4_BB_MAX_BLOCKS); +- md->blocks[md->num] = block + i; +- md->num++; +- if (md->num == EXT4_BB_MAX_BLOCKS) { +- /* no more space, put full container on a sb's list */ +- db->bb_md_cur = NULL; ++ node = rb_next(new_node); ++ if (node) { ++ entry = rb_entry(node, struct ext4_free_data, node); ++ if (can_merge(new_entry, entry)) { ++ new_entry->count += entry->count; ++ rb_erase(node, &(db->bb_free_root)); ++ spin_lock(&sbi->s_md_lock); ++ list_del(&entry->list); ++ spin_unlock(&sbi->s_md_lock); ++ kmem_cache_free(ext4_free_ext_cachep, entry); + } + } +- ext4_unlock_group(sb, group); ++ /* Add the extent to active_transaction list */ ++ spin_lock(&sbi->s_md_lock); ++ list_add(&new_entry->list, &sbi->s_active_transaction); ++ spin_unlock(&sbi->s_md_lock); + return 0; + } + +@@ -4591,7 +4788,7 @@ void ext4_mb_free_blocks(handle_t *handl + struct ext4_allocation_context *ac = NULL; + struct ext4_group_desc *gdp; + struct ext4_super_block *es; +- unsigned long overflow; ++ unsigned int overflow; + ext4_grpblk_t bit; + struct buffer_head *gd_bh; + ext4_group_t block_group; +@@ -4675,11 +4872,6 @@ do_more: + err = ext4_journal_get_write_access(handle, gd_bh); + if (err) + goto error_return; +- +- err = ext4_mb_load_buddy(sb, block_group, &e4b); +- if (err) +- goto error_return; +- + #ifdef AGGRESSIVE_CHECK + { + int i; +@@ -4687,13 +4879,6 @@ do_more: + BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data)); + } + #endif +- mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, +- bit, count); +- +- /* We dirtied the bitmap block */ +- BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); +- err = ext4_journal_dirty_metadata(handle, bitmap_bh); +- + if (ac) { + ac->ac_b_ex.fe_group = block_group; + ac->ac_b_ex.fe_start = bit; +@@ -4701,19 +4886,43 @@ do_more: + ext4_mb_store_history(ac); + } + ++ err = ext4_mb_load_buddy(sb, block_group, &e4b); ++ if (err) { ++ __release(e4b->alloc_semp); ++ goto error_return; ++ } + if (metadata) { +- /* blocks being freed are metadata. these blocks shouldn't +- * be used until this transaction is committed */ +- ext4_mb_free_metadata(handle, &e4b, block_group, bit, count); ++ struct ext4_free_data *new_entry; ++ /* ++ * blocks being freed are metadata. these blocks shouldn't ++ * be used until this transaction is committed ++ */ ++ new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS); ++ new_entry->start_blk = bit; ++ new_entry->group = block_group; ++ new_entry->count = count; ++ new_entry->t_tid = handle->h_transaction->t_tid; ++ ext4_lock_group(sb, block_group); ++ mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, ++ bit, count); ++ ext4_mb_free_metadata(handle, &e4b, new_entry); ++ ext4_unlock_group(sb, block_group); + } else { + ext4_lock_group(sb, block_group); ++ /* need to update group_info->bb_free and bitmap ++ * with group lock held. generate_buddy look at ++ * them with group lock_held ++ */ ++ mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, ++ bit, count); + mb_free_blocks(inode, &e4b, bit, count); + ext4_mb_return_to_preallocation(inode, &e4b, block, count); + ext4_unlock_group(sb, block_group); + } + + spin_lock(sb_bgl_lock(sbi, block_group)); +- le16_add_cpu(&gdp->bg_free_blocks_count, count); ++ ret = ext4_free_blks_count(sb, gdp) + count; ++ ext4_free_blks_set(sb, gdp, ret); + gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_add(&sbi->s_freeblocks_counter, count); +@@ -4729,6 +4938,10 @@ do_more: + + *freed += count; + ++ /* We dirtied the bitmap block */ ++ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); ++ err = ext4_journal_dirty_metadata(handle, bitmap_bh); ++ + /* And the group descriptor block */ + BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); + ret = ext4_journal_dirty_metadata(handle, gd_bh); +diff -rup b/fs/ext4//mballoc.h a/fs/ext4///mballoc.h +--- b/fs/ext4/mballoc.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/mballoc.h 2009-02-10 21:40:14.000000000 +0100 +@@ -18,6 +18,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include "ext4_jbd2.h" + #include "ext4.h" + #include "group.h" +@@ -96,41 +99,24 @@ + */ + #define MB_DEFAULT_GROUP_PREALLOC 512 + +-static struct kmem_cache *ext4_pspace_cachep; +-static struct kmem_cache *ext4_ac_cachep; + +-#ifdef EXT4_BB_MAX_BLOCKS +-#undef EXT4_BB_MAX_BLOCKS +-#endif +-#define EXT4_BB_MAX_BLOCKS 30 ++struct ext4_free_data { ++ /* this links the free block information from group_info */ ++ struct rb_node node; + +-struct ext4_free_metadata { +- ext4_group_t group; +- unsigned short num; +- ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS]; ++ /* this links the free block information from ext4_sb_info */ + struct list_head list; +-}; +- +-struct ext4_group_info { +- unsigned long bb_state; +- unsigned long bb_tid; +- struct ext4_free_metadata *bb_md_cur; +- unsigned short bb_first_free; +- unsigned short bb_free; +- unsigned short bb_fragments; +- struct list_head bb_prealloc_list; +-#ifdef DOUBLE_CHECK +- void *bb_bitmap; +-#endif +- unsigned short bb_counters[]; +-}; + +-#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 +-#define EXT4_GROUP_INFO_LOCKED_BIT 1 ++ /* group which free block extent belongs */ ++ ext4_group_t group; + +-#define EXT4_MB_GRP_NEED_INIT(grp) \ +- (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) ++ /* free block extent */ ++ ext4_grpblk_t start_blk; ++ ext4_grpblk_t count; + ++ /* transaction which freed this extent */ ++ tid_t t_tid; ++}; + + struct ext4_prealloc_space { + struct list_head pa_inode_list; +@@ -209,6 +195,11 @@ struct ext4_allocation_context { + __u8 ac_op; /* operation, for history only */ + struct page *ac_bitmap_page; + struct page *ac_buddy_page; ++ /* ++ * pointer to the held semaphore upon successful ++ * block allocation ++ */ ++ struct rw_semaphore *alloc_semp; + struct ext4_prealloc_space *ac_pa; + struct ext4_locality_group *ac_lg; + }; +@@ -242,6 +233,7 @@ struct ext4_buddy { + struct super_block *bd_sb; + __u16 bd_blkbits; + ext4_group_t bd_group; ++ struct rw_semaphore *alloc_semp; + }; + #define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap) + #define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy) +@@ -251,53 +243,12 @@ static inline void ext4_mb_store_history + { + return; + } +-#else +-static void ext4_mb_store_history(struct ext4_allocation_context *ac); + #endif + + #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + +-static struct proc_dir_entry *proc_root_ext4; + struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t); +- +-static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, +- ext4_group_t group); +-static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *); +-static void ext4_mb_free_committed_blocks(struct super_block *); +-static void ext4_mb_return_to_preallocation(struct inode *inode, +- struct ext4_buddy *e4b, sector_t block, +- int count); +-static void ext4_mb_put_pa(struct ext4_allocation_context *, +- struct super_block *, struct ext4_prealloc_space *pa); +-static int ext4_mb_init_per_dev_proc(struct super_block *sb); +-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); +- +- +-static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) +-{ +- struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); +- +- bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); +-} +- +-static inline void ext4_unlock_group(struct super_block *sb, +- ext4_group_t group) +-{ +- struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); +- +- bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state)); +-} +- +-static inline int ext4_is_group_locked(struct super_block *sb, +- ext4_group_t group) +-{ +- struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); +- +- return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT, +- &(grinfo->bb_state)); +-} +- +-static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, ++static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, + struct ext4_free_extent *fex) + { + ext4_fsblk_t block; +diff -rup b/fs/ext4//namei.c a/fs/ext4///namei.c +--- b/fs/ext4/namei.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/namei.c 2009-02-10 21:40:11.000000000 +0100 +@@ -151,34 +151,36 @@ struct dx_map_entry + + static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); + static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); +-static inline unsigned dx_get_hash (struct dx_entry *entry); +-static void dx_set_hash (struct dx_entry *entry, unsigned value); +-static unsigned dx_get_count (struct dx_entry *entries); +-static unsigned dx_get_limit (struct dx_entry *entries); +-static void dx_set_count (struct dx_entry *entries, unsigned value); +-static void dx_set_limit (struct dx_entry *entries, unsigned value); +-static unsigned dx_root_limit (struct inode *dir, unsigned infosize); +-static unsigned dx_node_limit (struct inode *dir); +-static struct dx_frame *dx_probe(struct dentry *dentry, ++static inline unsigned dx_get_hash(struct dx_entry *entry); ++static void dx_set_hash(struct dx_entry *entry, unsigned value); ++static unsigned dx_get_count(struct dx_entry *entries); ++static unsigned dx_get_limit(struct dx_entry *entries); ++static void dx_set_count(struct dx_entry *entries, unsigned value); ++static void dx_set_limit(struct dx_entry *entries, unsigned value); ++static unsigned dx_root_limit(struct inode *dir, unsigned infosize); ++static unsigned dx_node_limit(struct inode *dir); ++static struct dx_frame *dx_probe(const struct qstr *d_name, + struct inode *dir, + struct dx_hash_info *hinfo, + struct dx_frame *frame, + int *err); +-static void dx_release (struct dx_frame *frames); +-static int dx_make_map (struct ext4_dir_entry_2 *de, int size, +- struct dx_hash_info *hinfo, struct dx_map_entry map[]); ++static void dx_release(struct dx_frame *frames); ++static int dx_make_map(struct ext4_dir_entry_2 *de, int size, ++ struct dx_hash_info *hinfo, struct dx_map_entry map[]); + static void dx_sort_map(struct dx_map_entry *map, unsigned count); +-static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to, ++static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to, + struct dx_map_entry *offsets, int count); +-static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size); ++static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size); + static void dx_insert_block(struct dx_frame *frame, + u32 hash, ext4_lblk_t block); + static int ext4_htree_next_block(struct inode *dir, __u32 hash, + struct dx_frame *frame, + struct dx_frame *frames, + __u32 *start_hash); +-static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, +- struct ext4_dir_entry_2 **res_dir, int *err); ++static struct buffer_head * ext4_dx_find_entry(struct inode *dir, ++ const struct qstr *d_name, ++ struct ext4_dir_entry_2 **res_dir, ++ int *err); + static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, + struct inode *inode); + +@@ -207,44 +209,44 @@ static inline void dx_set_block(struct d + entry->block = cpu_to_le32(value); + } + +-static inline unsigned dx_get_hash (struct dx_entry *entry) ++static inline unsigned dx_get_hash(struct dx_entry *entry) + { + return le32_to_cpu(entry->hash); + } + +-static inline void dx_set_hash (struct dx_entry *entry, unsigned value) ++static inline void dx_set_hash(struct dx_entry *entry, unsigned value) + { + entry->hash = cpu_to_le32(value); + } + +-static inline unsigned dx_get_count (struct dx_entry *entries) ++static inline unsigned dx_get_count(struct dx_entry *entries) + { + return le16_to_cpu(((struct dx_countlimit *) entries)->count); + } + +-static inline unsigned dx_get_limit (struct dx_entry *entries) ++static inline unsigned dx_get_limit(struct dx_entry *entries) + { + return le16_to_cpu(((struct dx_countlimit *) entries)->limit); + } + +-static inline void dx_set_count (struct dx_entry *entries, unsigned value) ++static inline void dx_set_count(struct dx_entry *entries, unsigned value) + { + ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); + } + +-static inline void dx_set_limit (struct dx_entry *entries, unsigned value) ++static inline void dx_set_limit(struct dx_entry *entries, unsigned value) + { + ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); + } + +-static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize) ++static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) + { + unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - + EXT4_DIR_REC_LEN(2) - infosize; + return entry_space / sizeof(struct dx_entry); + } + +-static inline unsigned dx_node_limit (struct inode *dir) ++static inline unsigned dx_node_limit(struct inode *dir) + { + unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); + return entry_space / sizeof(struct dx_entry); +@@ -254,12 +256,12 @@ static inline unsigned dx_node_limit (st + * Debug + */ + #ifdef DX_DEBUG +-static void dx_show_index (char * label, struct dx_entry *entries) ++static void dx_show_index(char * label, struct dx_entry *entries) + { + int i, n = dx_get_count (entries); +- printk("%s index ", label); ++ printk(KERN_DEBUG "%s index ", label); + for (i = 0; i < n; i++) { +- printk("%x->%lu ", i? dx_get_hash(entries + i) : ++ printk("%x->%lu ", i ? dx_get_hash(entries + i) : + 0, (unsigned long)dx_get_block(entries + i)); + } + printk("\n"); +@@ -306,7 +308,7 @@ struct stats dx_show_entries(struct dx_h + struct dx_entry *entries, int levels) + { + unsigned blocksize = dir->i_sb->s_blocksize; +- unsigned count = dx_get_count (entries), names = 0, space = 0, i; ++ unsigned count = dx_get_count(entries), names = 0, space = 0, i; + unsigned bcount = 0; + struct buffer_head *bh; + int err; +@@ -325,11 +327,12 @@ struct stats dx_show_entries(struct dx_h + names += stats.names; + space += stats.space; + bcount += stats.bcount; +- brelse (bh); ++ brelse(bh); + } + if (bcount) +- printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ", +- names, space/bcount,(space/bcount)*100/blocksize); ++ printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n", ++ levels ? "" : " ", names, space/bcount, ++ (space/bcount)*100/blocksize); + return (struct stats) { names, space, bcount}; + } + #endif /* DX_DEBUG */ +@@ -344,7 +347,7 @@ struct stats dx_show_entries(struct dx_h + * back to userspace. + */ + static struct dx_frame * +-dx_probe(struct dentry *dentry, struct inode *dir, ++dx_probe(const struct qstr *d_name, struct inode *dir, + struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) + { + unsigned count, indirect; +@@ -355,8 +358,6 @@ dx_probe(struct dentry *dentry, struct i + u32 hash; + + frame->bh = NULL; +- if (dentry) +- dir = dentry->d_parent->d_inode; + if (!(bh = ext4_bread (NULL,dir, 0, 0, err))) + goto fail; + root = (struct dx_root *) bh->b_data; +@@ -371,9 +372,11 @@ dx_probe(struct dentry *dentry, struct i + goto fail; + } + hinfo->hash_version = root->info.hash_version; ++ if (hinfo->hash_version <= DX_HASH_TEA) ++ hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; +- if (dentry) +- ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); ++ if (d_name) ++ ext4fs_dirhash(d_name->name, d_name->len, hinfo); + hash = hinfo->hash; + + if (root->info.unused_flags & 1) { +@@ -406,7 +409,7 @@ dx_probe(struct dentry *dentry, struct i + goto fail; + } + +- dxtrace (printk("Look up %x", hash)); ++ dxtrace(printk("Look up %x", hash)); + while (1) + { + count = dx_get_count(entries); +@@ -555,7 +558,7 @@ static int ext4_htree_next_block(struct + 0, &err))) + return err; /* Failure */ + p++; +- brelse (p->bh); ++ brelse(p->bh); + p->bh = bh; + p->at = p->entries = ((struct dx_node *) bh->b_data)->entries; + } +@@ -593,7 +596,7 @@ static int htree_dirblock_to_tree(struct + /* On error, skip the f_pos to the next block. */ + dir_file->f_pos = (dir_file->f_pos | + (dir->i_sb->s_blocksize - 1)) + 1; +- brelse (bh); ++ brelse(bh); + return count; + } + ext4fs_dirhash(de->name, de->name_len, hinfo); +@@ -635,11 +638,14 @@ int ext4_htree_fill_tree(struct file *di + int ret, err; + __u32 hashval; + +- dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, +- start_minor_hash)); ++ dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n", ++ start_hash, start_minor_hash)); + dir = dir_file->f_path.dentry->d_inode; + if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) { + hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; ++ if (hinfo.hash_version <= DX_HASH_TEA) ++ hinfo.hash_version += ++ EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; + count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, + start_hash, start_minor_hash); +@@ -648,7 +654,7 @@ int ext4_htree_fill_tree(struct file *di + } + hinfo.hash = start_hash; + hinfo.minor_hash = 0; +- frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err); ++ frame = dx_probe(NULL, dir, &hinfo, frames, &err); + if (!frame) + return err; + +@@ -694,8 +700,8 @@ int ext4_htree_fill_tree(struct file *di + break; + } + dx_release(frames); +- dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", +- count, *next_hash)); ++ dxtrace(printk(KERN_DEBUG "Fill tree: returned %d entries, " ++ "next hash: %x\n", count, *next_hash)); + return count; + errout: + dx_release(frames); +@@ -802,17 +808,17 @@ static inline int ext4_match (int len, c + /* + * Returns 0 if not found, -1 on failure, and 1 on success + */ +-static inline int search_dirblock(struct buffer_head * bh, ++static inline int search_dirblock(struct buffer_head *bh, + struct inode *dir, +- struct dentry *dentry, +- unsigned long offset, ++ const struct qstr *d_name, ++ unsigned int offset, + struct ext4_dir_entry_2 ** res_dir) + { + struct ext4_dir_entry_2 * de; + char * dlimit; + int de_len; +- const char *name = dentry->d_name.name; +- int namelen = dentry->d_name.len; ++ const char *name = d_name->name; ++ int namelen = d_name->len; + + de = (struct ext4_dir_entry_2 *) bh->b_data; + dlimit = bh->b_data + dir->i_sb->s_blocksize; +@@ -851,12 +857,13 @@ static inline int search_dirblock(struct + * The returned buffer_head has ->b_count elevated. The caller is expected + * to brelse() it when appropriate. + */ +-static struct buffer_head * ext4_find_entry (struct dentry *dentry, ++static struct buffer_head * ext4_find_entry (struct inode *dir, ++ const struct qstr *d_name, + struct ext4_dir_entry_2 ** res_dir) + { +- struct super_block * sb; +- struct buffer_head * bh_use[NAMEI_RA_SIZE]; +- struct buffer_head * bh, *ret = NULL; ++ struct super_block *sb; ++ struct buffer_head *bh_use[NAMEI_RA_SIZE]; ++ struct buffer_head *bh, *ret = NULL; + ext4_lblk_t start, block, b; + int ra_max = 0; /* Number of bh's in the readahead + buffer, bh_use[] */ +@@ -865,16 +872,15 @@ static struct buffer_head * ext4_find_en + int num = 0; + ext4_lblk_t nblocks; + int i, err; +- struct inode *dir = dentry->d_parent->d_inode; + int namelen; + + *res_dir = NULL; + sb = dir->i_sb; +- namelen = dentry->d_name.len; ++ namelen = d_name->len; + if (namelen > EXT4_NAME_LEN) + return NULL; + if (is_dx(dir)) { +- bh = ext4_dx_find_entry(dentry, res_dir, &err); ++ bh = ext4_dx_find_entry(dir, d_name, res_dir, &err); + /* + * On success, or if the error was file not found, + * return. Otherwise, fall back to doing a search the +@@ -882,7 +888,8 @@ static struct buffer_head * ext4_find_en + */ + if (bh || (err != ERR_BAD_DX_DIR)) + return bh; +- dxtrace(printk("ext4_find_entry: dx failed, falling back\n")); ++ dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " ++ "falling back\n")); + } + nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); + start = EXT4_I(dir)->i_dir_start_lookup; +@@ -926,7 +933,7 @@ restart: + brelse(bh); + goto next; + } +- i = search_dirblock(bh, dir, dentry, ++ i = search_dirblock(bh, dir, d_name, + block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); + if (i == 1) { + EXT4_I(dir)->i_dir_start_lookup = block; +@@ -956,11 +963,11 @@ restart: + cleanup_and_exit: + /* Clean up the read-ahead blocks */ + for (; ra_ptr < ra_max; ra_ptr++) +- brelse (bh_use[ra_ptr]); ++ brelse(bh_use[ra_ptr]); + return ret; + } + +-static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, ++static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name, + struct ext4_dir_entry_2 **res_dir, int *err) + { + struct super_block * sb; +@@ -971,14 +978,13 @@ static struct buffer_head * ext4_dx_find + struct buffer_head *bh; + ext4_lblk_t block; + int retval; +- int namelen = dentry->d_name.len; +- const u8 *name = dentry->d_name.name; +- struct inode *dir = dentry->d_parent->d_inode; ++ int namelen = d_name->len; ++ const u8 *name = d_name->name; + + sb = dir->i_sb; + /* NFS may look up ".." - look at dx_root directory block */ + if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ +- if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) ++ if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err))) + return NULL; + } else { + frame = frames; +@@ -1010,7 +1016,7 @@ static struct buffer_head * ext4_dx_find + return bh; + } + } +- brelse (bh); ++ brelse(bh); + /* Check to see if we should continue to search */ + retval = ext4_htree_next_block(dir, hash, frame, + frames, NULL); +@@ -1025,28 +1031,28 @@ static struct buffer_head * ext4_dx_find + + *err = -ENOENT; + errout: +- dxtrace(printk("%s not found\n", name)); ++ dxtrace(printk(KERN_DEBUG "%s not found\n", name)); + dx_release (frames); + return NULL; + } + +-static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) ++static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) + { +- struct inode * inode; +- struct ext4_dir_entry_2 * de; +- struct buffer_head * bh; ++ struct inode *inode; ++ struct ext4_dir_entry_2 *de; ++ struct buffer_head *bh; + + if (dentry->d_name.len > EXT4_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + +- bh = ext4_find_entry(dentry, &de); ++ bh = ext4_find_entry(dir, &dentry->d_name, &de); + inode = NULL; + if (bh) { +- unsigned long ino = le32_to_cpu(de->inode); +- brelse (bh); ++ __u32 ino = le32_to_cpu(de->inode); ++ brelse(bh); + if (!ext4_valid_inum(dir->i_sb, ino)) { + ext4_error(dir->i_sb, "ext4_lookup", +- "bad inode number: %lu", ino); ++ "bad inode number: %u", ino); + return ERR_PTR(-EIO); + } + inode = ext4_iget(dir->i_sb, ino); +@@ -1059,18 +1065,17 @@ static struct dentry *ext4_lookup(struct + + struct dentry *ext4_get_parent(struct dentry *child) + { +- unsigned long ino; ++ __u32 ino; + struct dentry *parent; + struct inode *inode; +- struct dentry dotdot; ++ static const struct qstr dotdot = { ++ .name = "..", ++ .len = 2, ++ }; + struct ext4_dir_entry_2 * de; + struct buffer_head *bh; + +- dotdot.d_name.name = ".."; +- dotdot.d_name.len = 2; +- dotdot.d_parent = child; /* confusing, isn't it! */ +- +- bh = ext4_find_entry(&dotdot, &de); ++ bh = ext4_find_entry(child->d_inode, &dotdot, &de); + inode = NULL; + if (!bh) + return ERR_PTR(-ENOENT); +@@ -1079,7 +1084,7 @@ struct dentry *ext4_get_parent(struct de + + if (!ext4_valid_inum(child->d_inode->i_sb, ino)) { + ext4_error(child->d_inode->i_sb, "ext4_get_parent", +- "bad inode number: %lu", ino); ++ "bad inode number: %u", ino); + return ERR_PTR(-EIO); + } + +@@ -1176,9 +1181,9 @@ static struct ext4_dir_entry_2 *do_split + u32 hash2; + struct dx_map_entry *map; + char *data1 = (*bh)->b_data, *data2; +- unsigned split, move, size, i; ++ unsigned split, move, size; + struct ext4_dir_entry_2 *de = NULL, *de2; +- int err = 0; ++ int err = 0, i; + + bh2 = ext4_append (handle, dir, &newblock, &err); + if (!(bh2)) { +@@ -1201,10 +1206,10 @@ static struct ext4_dir_entry_2 *do_split + + /* create map in the end of data2 block */ + map = (struct dx_map_entry *) (data2 + blocksize); +- count = dx_make_map ((struct ext4_dir_entry_2 *) data1, ++ count = dx_make_map((struct ext4_dir_entry_2 *) data1, + blocksize, hinfo, map); + map -= count; +- dx_sort_map (map, count); ++ dx_sort_map(map, count); + /* Split the existing block in the middle, size-wise */ + size = 0; + move = 0; +@@ -1225,7 +1230,7 @@ static struct ext4_dir_entry_2 *do_split + + /* Fancy dance to stay within two buffers */ + de2 = dx_move_dirents(data1, data2, map + split, count - split); +- de = dx_pack_dirents(data1,blocksize); ++ de = dx_pack_dirents(data1, blocksize); + de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de); + de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2); + dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); +@@ -1237,15 +1242,15 @@ static struct ext4_dir_entry_2 *do_split + swap(*bh, bh2); + de = de2; + } +- dx_insert_block (frame, hash2 + continued, newblock); +- err = ext4_journal_dirty_metadata (handle, bh2); ++ dx_insert_block(frame, hash2 + continued, newblock); ++ err = ext4_journal_dirty_metadata(handle, bh2); + if (err) + goto journal_error; +- err = ext4_journal_dirty_metadata (handle, frame->bh); ++ err = ext4_journal_dirty_metadata(handle, frame->bh); + if (err) + goto journal_error; +- brelse (bh2); +- dxtrace(dx_show_index ("frame", frame->entries)); ++ brelse(bh2); ++ dxtrace(dx_show_index("frame", frame->entries)); + return de; + + journal_error: +@@ -1271,12 +1276,12 @@ errout: + */ + static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, + struct inode *inode, struct ext4_dir_entry_2 *de, +- struct buffer_head * bh) ++ struct buffer_head *bh) + { + struct inode *dir = dentry->d_parent->d_inode; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; +- unsigned long offset = 0; ++ unsigned int offset = 0; + unsigned short reclen; + int nlen, rlen, err; + char *top; +@@ -1288,11 +1293,11 @@ static int add_dirent_to_buf(handle_t *h + while ((char *) de <= top) { + if (!ext4_check_dir_entry("ext4_add_entry", dir, de, + bh, offset)) { +- brelse (bh); ++ brelse(bh); + return -EIO; + } +- if (ext4_match (namelen, name, de)) { +- brelse (bh); ++ if (ext4_match(namelen, name, de)) { ++ brelse(bh); + return -EEXIST; + } + nlen = EXT4_DIR_REC_LEN(de->name_len); +@@ -1329,7 +1334,7 @@ static int add_dirent_to_buf(handle_t *h + } else + de->inode = 0; + de->name_len = namelen; +- memcpy (de->name, name, namelen); ++ memcpy(de->name, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend +@@ -1377,7 +1382,7 @@ static int make_indexed_dir(handle_t *ha + struct fake_dirent *fde; + + blocksize = dir->i_sb->s_blocksize; +- dxtrace(printk("Creating index\n")); ++ dxtrace(printk(KERN_DEBUG "Creating index\n")); + retval = ext4_journal_get_write_access(handle, bh); + if (retval) { + ext4_std_error(dir->i_sb, retval); +@@ -1386,7 +1391,7 @@ static int make_indexed_dir(handle_t *ha + } + root = (struct dx_root *) bh->b_data; + +- bh2 = ext4_append (handle, dir, &block, &retval); ++ bh2 = ext4_append(handle, dir, &block, &retval); + if (!(bh2)) { + brelse(bh); + return retval; +@@ -1412,12 +1417,14 @@ static int make_indexed_dir(handle_t *ha + root->info.info_length = sizeof(root->info); + root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; + entries = root->entries; +- dx_set_block (entries, 1); +- dx_set_count (entries, 1); +- dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info))); ++ dx_set_block(entries, 1); ++ dx_set_count(entries, 1); ++ dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info))); + + /* Initialize as for dx_probe */ + hinfo.hash_version = root->info.hash_version; ++ if (hinfo.hash_version <= DX_HASH_TEA) ++ hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; + ext4fs_dirhash(name, namelen, &hinfo); + frame = frames; +@@ -1443,14 +1450,13 @@ static int make_indexed_dir(handle_t *ha + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +-static int ext4_add_entry (handle_t *handle, struct dentry *dentry, +- struct inode *inode) ++static int ext4_add_entry(handle_t *handle, struct dentry *dentry, ++ struct inode *inode) + { + struct inode *dir = dentry->d_parent->d_inode; +- unsigned long offset; +- struct buffer_head * bh; ++ struct buffer_head *bh; + struct ext4_dir_entry_2 *de; +- struct super_block * sb; ++ struct super_block *sb; + int retval; + int dx_fallback=0; + unsigned blocksize; +@@ -1469,7 +1475,7 @@ static int ext4_add_entry (handle_t *han + ext4_mark_inode_dirty(handle, dir); + } + blocks = dir->i_size >> sb->s_blocksize_bits; +- for (block = 0, offset = 0; block < blocks; block++) { ++ for (block = 0; block < blocks; block++) { + bh = ext4_bread(handle, dir, block, 0, &retval); + if(!bh) + return retval; +@@ -1500,13 +1506,13 @@ static int ext4_dx_add_entry(handle_t *h + struct dx_frame frames[2], *frame; + struct dx_entry *entries, *at; + struct dx_hash_info hinfo; +- struct buffer_head * bh; ++ struct buffer_head *bh; + struct inode *dir = dentry->d_parent->d_inode; +- struct super_block * sb = dir->i_sb; ++ struct super_block *sb = dir->i_sb; + struct ext4_dir_entry_2 *de; + int err; + +- frame = dx_probe(dentry, NULL, &hinfo, frames, &err); ++ frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); + if (!frame) + return err; + entries = frame->entries; +@@ -1527,7 +1533,7 @@ static int ext4_dx_add_entry(handle_t *h + } + + /* Block full, should compress but for now just split */ +- dxtrace(printk("using %u of %u node entries\n", ++ dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", + dx_get_count(entries), dx_get_limit(entries))); + /* Need to split index? */ + if (dx_get_count(entries) == dx_get_limit(entries)) { +@@ -1559,7 +1565,8 @@ static int ext4_dx_add_entry(handle_t *h + if (levels) { + unsigned icount1 = icount/2, icount2 = icount - icount1; + unsigned hash2 = dx_get_hash(entries + icount1); +- dxtrace(printk("Split index %i/%i\n", icount1, icount2)); ++ dxtrace(printk(KERN_DEBUG "Split index %i/%i\n", ++ icount1, icount2)); + + BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ + err = ext4_journal_get_write_access(handle, +@@ -1567,11 +1574,11 @@ static int ext4_dx_add_entry(handle_t *h + if (err) + goto journal_error; + +- memcpy ((char *) entries2, (char *) (entries + icount1), +- icount2 * sizeof(struct dx_entry)); +- dx_set_count (entries, icount1); +- dx_set_count (entries2, icount2); +- dx_set_limit (entries2, dx_node_limit(dir)); ++ memcpy((char *) entries2, (char *) (entries + icount1), ++ icount2 * sizeof(struct dx_entry)); ++ dx_set_count(entries, icount1); ++ dx_set_count(entries2, icount2); ++ dx_set_limit(entries2, dx_node_limit(dir)); + + /* Which index block gets the new entry? */ + if (at - entries >= icount1) { +@@ -1579,16 +1586,17 @@ static int ext4_dx_add_entry(handle_t *h + frame->entries = entries = entries2; + swap(frame->bh, bh2); + } +- dx_insert_block (frames + 0, hash2, newblock); +- dxtrace(dx_show_index ("node", frames[1].entries)); +- dxtrace(dx_show_index ("node", ++ dx_insert_block(frames + 0, hash2, newblock); ++ dxtrace(dx_show_index("node", frames[1].entries)); ++ dxtrace(dx_show_index("node", + ((struct dx_node *) bh2->b_data)->entries)); + err = ext4_journal_dirty_metadata(handle, bh2); + if (err) + goto journal_error; + brelse (bh2); + } else { +- dxtrace(printk("Creating second level index...\n")); ++ dxtrace(printk(KERN_DEBUG ++ "Creating second level index...\n")); + memcpy((char *) entries2, (char *) entries, + icount * sizeof(struct dx_entry)); + dx_set_limit(entries2, dx_node_limit(dir)); +@@ -1630,12 +1638,12 @@ cleanup: + * ext4_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +-static int ext4_delete_entry (handle_t *handle, +- struct inode * dir, +- struct ext4_dir_entry_2 * de_del, +- struct buffer_head * bh) ++static int ext4_delete_entry(handle_t *handle, ++ struct inode *dir, ++ struct ext4_dir_entry_2 *de_del, ++ struct buffer_head *bh) + { +- struct ext4_dir_entry_2 * de, * pde; ++ struct ext4_dir_entry_2 *de, *pde; + int i; + + i = 0; +@@ -1716,11 +1724,11 @@ static int ext4_add_nondir(handle_t *han + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +-static int ext4_create (struct inode * dir, struct dentry * dentry, int mode, +- struct nameidata *nd) ++static int ext4_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) + { + handle_t *handle; +- struct inode * inode; ++ struct inode *inode; + int err, retries = 0; + + retry: +@@ -1747,8 +1755,8 @@ retry: + return err; + } + +-static int ext4_mknod (struct inode * dir, struct dentry *dentry, +- int mode, dev_t rdev) ++static int ext4_mknod(struct inode *dir, struct dentry *dentry, ++ int mode, dev_t rdev) + { + handle_t *handle; + struct inode *inode; +@@ -1767,11 +1775,11 @@ retry: + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + +- inode = ext4_new_inode (handle, dir, mode); ++ inode = ext4_new_inode(handle, dir, mode); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + init_special_inode(inode, inode->i_mode, rdev); +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + inode->i_op = &ext4_special_inode_operations; + #endif + err = ext4_add_nondir(handle, dentry, inode); +@@ -1782,12 +1790,12 @@ retry: + return err; + } + +-static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode) ++static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) + { + handle_t *handle; +- struct inode * inode; +- struct buffer_head * dir_block; +- struct ext4_dir_entry_2 * de; ++ struct inode *inode; ++ struct buffer_head *dir_block; ++ struct ext4_dir_entry_2 *de; + int err, retries = 0; + + if (EXT4_DIR_LINK_MAX(dir)) +@@ -1803,7 +1811,7 @@ retry: + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + +- inode = ext4_new_inode (handle, dir, S_IFDIR | mode); ++ inode = ext4_new_inode(handle, dir, S_IFDIR | mode); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; +@@ -1811,7 +1819,7 @@ retry: + inode->i_op = &ext4_dir_inode_operations; + inode->i_fop = &ext4_dir_operations; + inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; +- dir_block = ext4_bread (handle, inode, 0, 1, &err); ++ dir_block = ext4_bread(handle, inode, 0, 1, &err); + if (!dir_block) + goto out_clear_inode; + BUFFER_TRACE(dir_block, "get_write_access"); +@@ -1820,26 +1828,26 @@ retry: + de->inode = cpu_to_le32(inode->i_ino); + de->name_len = 1; + de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len)); +- strcpy (de->name, "."); ++ strcpy(de->name, "."); + ext4_set_de_type(dir->i_sb, de, S_IFDIR); + de = ext4_next_entry(de); + de->inode = cpu_to_le32(dir->i_ino); + de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize - + EXT4_DIR_REC_LEN(1)); + de->name_len = 2; +- strcpy (de->name, ".."); ++ strcpy(de->name, ".."); + ext4_set_de_type(dir->i_sb, de, S_IFDIR); + inode->i_nlink = 2; + BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata"); + ext4_journal_dirty_metadata(handle, dir_block); +- brelse (dir_block); ++ brelse(dir_block); + ext4_mark_inode_dirty(handle, inode); +- err = ext4_add_entry (handle, dentry, inode); ++ err = ext4_add_entry(handle, dentry, inode); + if (err) { + out_clear_inode: + clear_nlink(inode); + ext4_mark_inode_dirty(handle, inode); +- iput (inode); ++ iput(inode); + goto out_stop; + } + ext4_inc_count(handle, dir); +@@ -1856,17 +1864,17 @@ out_stop: + /* + * routine to check that the specified directory is empty (for rmdir) + */ +-static int empty_dir (struct inode * inode) ++static int empty_dir(struct inode *inode) + { +- unsigned long offset; +- struct buffer_head * bh; +- struct ext4_dir_entry_2 * de, * de1; +- struct super_block * sb; ++ unsigned int offset; ++ struct buffer_head *bh; ++ struct ext4_dir_entry_2 *de, *de1; ++ struct super_block *sb; + int err = 0; + + sb = inode->i_sb; + if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || +- !(bh = ext4_bread (NULL, inode, 0, 0, &err))) { ++ !(bh = ext4_bread(NULL, inode, 0, 0, &err))) { + if (err) + ext4_error(inode->i_sb, __func__, + "error %d reading directory #%lu offset 0", +@@ -1881,29 +1889,29 @@ static int empty_dir (struct inode * ino + de1 = ext4_next_entry(de); + if (le32_to_cpu(de->inode) != inode->i_ino || + !le32_to_cpu(de1->inode) || +- strcmp (".", de->name) || +- strcmp ("..", de1->name)) { +- ext4_warning (inode->i_sb, "empty_dir", +- "bad directory (dir #%lu) - no `.' or `..'", +- inode->i_ino); +- brelse (bh); ++ strcmp(".", de->name) || ++ strcmp("..", de1->name)) { ++ ext4_warning(inode->i_sb, "empty_dir", ++ "bad directory (dir #%lu) - no `.' or `..'", ++ inode->i_ino); ++ brelse(bh); + return 1; + } + offset = ext4_rec_len_from_disk(de->rec_len) + + ext4_rec_len_from_disk(de1->rec_len); + de = ext4_next_entry(de1); +- while (offset < inode->i_size ) { ++ while (offset < inode->i_size) { + if (!bh || + (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { + err = 0; +- brelse (bh); +- bh = ext4_bread (NULL, inode, ++ brelse(bh); ++ bh = ext4_bread(NULL, inode, + offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err); + if (!bh) { + if (err) + ext4_error(sb, __func__, + "error %d reading directory" +- " #%lu offset %lu", ++ " #%lu offset %u", + err, inode->i_ino, offset); + offset += sb->s_blocksize; + continue; +@@ -1917,13 +1925,13 @@ static int empty_dir (struct inode * ino + continue; + } + if (le32_to_cpu(de->inode)) { +- brelse (bh); ++ brelse(bh); + return 0; + } + offset += ext4_rec_len_from_disk(de->rec_len); + de = ext4_next_entry(de); + } +- brelse (bh); ++ brelse(bh); + return 1; + } + +@@ -1954,8 +1962,8 @@ int ext4_orphan_add(handle_t *handle, st + * ->i_nlink. For, say it, character device. Not a regular file, + * not a directory, not a symlink and ->i_nlink > 0. + */ +- J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || +- S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); ++ J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || ++ S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); + + BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); + err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); +@@ -2003,7 +2011,7 @@ int ext4_orphan_del(handle_t *handle, st + struct list_head *prev; + struct ext4_inode_info *ei = EXT4_I(inode); + struct ext4_sb_info *sbi; +- unsigned long ino_next; ++ __u32 ino_next; + struct ext4_iloc iloc; + int err = 0; + +@@ -2033,7 +2041,7 @@ int ext4_orphan_del(handle_t *handle, st + goto out_err; + + if (prev == &sbi->s_orphan) { +- jbd_debug(4, "superblock will point to %lu\n", ino_next); ++ jbd_debug(4, "superblock will point to %u\n", ino_next); + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); + err = ext4_journal_get_write_access(handle, sbi->s_sbh); + if (err) +@@ -2045,7 +2053,7 @@ int ext4_orphan_del(handle_t *handle, st + struct inode *i_prev = + &list_entry(prev, struct ext4_inode_info, i_orphan)->vfs_inode; + +- jbd_debug(4, "orphan inode %lu will point to %lu\n", ++ jbd_debug(4, "orphan inode %lu will point to %u\n", + i_prev->i_ino, ino_next); + err = ext4_reserve_inode_write(handle, i_prev, &iloc2); + if (err) +@@ -2069,12 +2077,12 @@ out_brelse: + goto out_err; + } + +-static int ext4_rmdir (struct inode * dir, struct dentry *dentry) ++static int ext4_rmdir(struct inode *dir, struct dentry *dentry) + { + int retval; +- struct inode * inode; +- struct buffer_head * bh; +- struct ext4_dir_entry_2 * de; ++ struct inode *inode; ++ struct buffer_head *bh; ++ struct ext4_dir_entry_2 *de; + handle_t *handle; + + /* Initialize quotas before so that eventual writes go in +@@ -2085,7 +2093,7 @@ static int ext4_rmdir (struct inode * di + return PTR_ERR(handle); + + retval = -ENOENT; +- bh = ext4_find_entry (dentry, &de); ++ bh = ext4_find_entry(dir, &dentry->d_name, &de); + if (!bh) + goto end_rmdir; + +@@ -2099,16 +2107,16 @@ static int ext4_rmdir (struct inode * di + goto end_rmdir; + + retval = -ENOTEMPTY; +- if (!empty_dir (inode)) ++ if (!empty_dir(inode)) + goto end_rmdir; + + retval = ext4_delete_entry(handle, dir, de, bh); + if (retval) + goto end_rmdir; + if (!EXT4_DIR_LINK_EMPTY(inode)) +- ext4_warning (inode->i_sb, "ext4_rmdir", +- "empty directory has too many links (%d)", +- inode->i_nlink); ++ ext4_warning(inode->i_sb, "ext4_rmdir", ++ "empty directory has too many links (%d)", ++ inode->i_nlink); + inode->i_version++; + clear_nlink(inode); + /* There's no need to set i_disksize: the fact that i_nlink is +@@ -2124,16 +2132,16 @@ static int ext4_rmdir (struct inode * di + + end_rmdir: + ext4_journal_stop(handle); +- brelse (bh); ++ brelse(bh); + return retval; + } + +-static int ext4_unlink(struct inode * dir, struct dentry *dentry) ++static int ext4_unlink(struct inode *dir, struct dentry *dentry) + { + int retval; +- struct inode * inode; +- struct buffer_head * bh; +- struct ext4_dir_entry_2 * de; ++ struct inode *inode; ++ struct buffer_head *bh; ++ struct ext4_dir_entry_2 *de; + handle_t *handle; + + /* Initialize quotas before so that eventual writes go +@@ -2147,7 +2155,7 @@ static int ext4_unlink(struct inode * di + handle->h_sync = 1; + + retval = -ENOENT; +- bh = ext4_find_entry (dentry, &de); ++ bh = ext4_find_entry(dir, &dentry->d_name, &de); + if (!bh) + goto end_unlink; + +@@ -2158,9 +2166,9 @@ static int ext4_unlink(struct inode * di + goto end_unlink; + + if (!inode->i_nlink) { +- ext4_warning (inode->i_sb, "ext4_unlink", +- "Deleting nonexistent file (%lu), %d", +- inode->i_ino, inode->i_nlink); ++ ext4_warning(inode->i_sb, "ext4_unlink", ++ "Deleting nonexistent file (%lu), %d", ++ inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = ext4_delete_entry(handle, dir, de, bh); +@@ -2178,15 +2186,15 @@ static int ext4_unlink(struct inode * di + + end_unlink: + ext4_journal_stop(handle); +- brelse (bh); ++ brelse(bh); + return retval; + } + +-static int ext4_symlink (struct inode * dir, +- struct dentry *dentry, const char * symname) ++static int ext4_symlink(struct inode *dir, ++ struct dentry *dentry, const char *symname) + { + handle_t *handle; +- struct inode * inode; ++ struct inode *inode; + int l, err, retries = 0; + + l = strlen(symname)+1; +@@ -2203,12 +2211,12 @@ retry: + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + +- inode = ext4_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); ++ inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; + +- if (l > sizeof (EXT4_I(inode)->i_data)) { ++ if (l > sizeof(EXT4_I(inode)->i_data)) { + inode->i_op = &ext4_symlink_inode_operations; + ext4_set_aops(inode); + /* +@@ -2216,18 +2224,19 @@ retry: + * We have a transaction open. All is sweetness. It also sets + * i_size in generic_commit_write(). + */ +- err = __page_symlink(inode, symname, l, 1); ++ err = __page_symlink(inode, symname, l, ++ mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + if (err) { + clear_nlink(inode); + ext4_mark_inode_dirty(handle, inode); +- iput (inode); ++ iput(inode); + goto out_stop; + } + } else { + /* clear the extent format for fast symlink */ + EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL; + inode->i_op = &ext4_fast_symlink_inode_operations; +- memcpy((char*)&EXT4_I(inode)->i_data,symname,l); ++ memcpy((char *)&EXT4_I(inode)->i_data, symname, l); + inode->i_size = l-1; + } + EXT4_I(inode)->i_disksize = inode->i_size; +@@ -2239,8 +2248,8 @@ out_stop: + return err; + } + +-static int ext4_link (struct dentry * old_dentry, +- struct inode * dir, struct dentry *dentry) ++static int ext4_link(struct dentry *old_dentry, ++ struct inode *dir, struct dentry *dentry) + { + handle_t *handle; + struct inode *inode = old_dentry->d_inode; +@@ -2283,13 +2292,13 @@ retry: + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +-static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry, +- struct inode * new_dir,struct dentry *new_dentry) ++static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry) + { + handle_t *handle; +- struct inode * old_inode, * new_inode; +- struct buffer_head * old_bh, * new_bh, * dir_bh; +- struct ext4_dir_entry_2 * old_de, * new_de; ++ struct inode *old_inode, *new_inode; ++ struct buffer_head *old_bh, *new_bh, *dir_bh; ++ struct ext4_dir_entry_2 *old_de, *new_de; + int retval; + + old_bh = new_bh = dir_bh = NULL; +@@ -2307,7 +2316,7 @@ static int ext4_rename (struct inode * o + if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) + handle->h_sync = 1; + +- old_bh = ext4_find_entry (old_dentry, &old_de); ++ old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de); + /* + * Check for inode number is _not_ due to possible IO errors. + * We might rmdir the source, keep it as pwd of some process +@@ -2320,32 +2329,32 @@ static int ext4_rename (struct inode * o + goto end_rename; + + new_inode = new_dentry->d_inode; +- new_bh = ext4_find_entry (new_dentry, &new_de); ++ new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new_de); + if (new_bh) { + if (!new_inode) { +- brelse (new_bh); ++ brelse(new_bh); + new_bh = NULL; + } + } + if (S_ISDIR(old_inode->i_mode)) { + if (new_inode) { + retval = -ENOTEMPTY; +- if (!empty_dir (new_inode)) ++ if (!empty_dir(new_inode)) + goto end_rename; + } + retval = -EIO; +- dir_bh = ext4_bread (handle, old_inode, 0, 0, &retval); ++ dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; +- if (!new_inode && new_dir!=old_dir && ++ if (!new_inode && new_dir != old_dir && + new_dir->i_nlink >= EXT4_LINK_MAX) + goto end_rename; + } + if (!new_bh) { +- retval = ext4_add_entry (handle, new_dentry, old_inode); ++ retval = ext4_add_entry(handle, new_dentry, old_inode); + if (retval) + goto end_rename; + } else { +@@ -2387,7 +2396,7 @@ static int ext4_rename (struct inode * o + struct buffer_head *old_bh2; + struct ext4_dir_entry_2 *old_de2; + +- old_bh2 = ext4_find_entry(old_dentry, &old_de2); ++ old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2); + if (old_bh2) { + retval = ext4_delete_entry(handle, old_dir, + old_de2, old_bh2); +@@ -2432,9 +2441,9 @@ static int ext4_rename (struct inode * o + retval = 0; + + end_rename: +- brelse (dir_bh); +- brelse (old_bh); +- brelse (new_bh); ++ brelse(dir_bh); ++ brelse(old_bh); ++ brelse(new_bh); + ext4_journal_stop(handle); + return retval; + } +@@ -2453,7 +2462,7 @@ const struct inode_operations ext4_dir_i + .mknod = ext4_mknod, + .rename = ext4_rename, + .setattr = ext4_setattr, +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext4_listxattr, +@@ -2464,7 +2473,7 @@ const struct inode_operations ext4_dir_i + + const struct inode_operations ext4_special_inode_operations = { + .setattr = ext4_setattr, +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext4_listxattr, +diff -rup b/fs/ext4//resize.c a/fs/ext4///resize.c +--- b/fs/ext4/resize.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/resize.c 2009-02-10 21:40:11.000000000 +0100 +@@ -50,7 +50,7 @@ static int verify_group_input(struct sup + ext4_get_group_no_and_offset(sb, start, NULL, &offset); + if (group != sbi->s_groups_count) + ext4_warning(sb, __func__, +- "Cannot add at group %u (only %lu groups)", ++ "Cannot add at group %u (only %u groups)", + input->group, sbi->s_groups_count); + else if (offset != 0) + ext4_warning(sb, __func__, "Last group not full"); +@@ -284,11 +284,9 @@ static int setup_new_group_blocks(struct + if ((err = extend_or_restart_transaction(handle, 2, bh))) + goto exit_bh; + +- mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb), +- bh->b_data); ++ mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8, bh->b_data); + ext4_journal_dirty_metadata(handle, bh); + brelse(bh); +- + /* Mark unused entries in inode bitmap used */ + ext4_debug("clear inode bitmap %#04llx (+%llu)\n", + input->inode_bitmap, input->inode_bitmap - start); +@@ -297,7 +295,7 @@ static int setup_new_group_blocks(struct + goto exit_journal; + } + +- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), ++ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, + bh->b_data); + ext4_journal_dirty_metadata(handle, bh); + exit_bh: +@@ -416,8 +414,8 @@ static int add_new_gdb(handle_t *handle, + "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n", + gdb_num); + +- /* +- * If we are not using the primary superblock/GDT copy don't resize, ++ /* ++ * If we are not using the primary superblock/GDT copy don't resize, + * because the user tools have no way of handling this. Probably a + * bad time to do it anyways. + */ +@@ -715,7 +713,7 @@ static void update_backups(struct super_ + exit_err: + if (err) { + ext4_warning(sb, __func__, +- "can't update backup for group %lu (err %d), " ++ "can't update backup for group %u (err %d), " + "forcing fsck on next reboot", group, err); + sbi->s_mount_state &= ~EXT4_VALID_FS; + sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS); +@@ -747,6 +745,7 @@ int ext4_group_add(struct super_block *s + struct inode *inode = NULL; + handle_t *handle; + int gdb_off, gdb_num; ++ int num_grp_locked = 0; + int err, err2; + + gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); +@@ -787,6 +786,7 @@ int ext4_group_add(struct super_block *s + } + } + ++ + if ((err = verify_group_input(sb, input))) + goto exit_put; + +@@ -855,6 +855,7 @@ int ext4_group_add(struct super_block *s + * using the new disk blocks. + */ + ++ num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, input->group); + /* Update group descriptor block for new group */ + gdp = (struct ext4_group_desc *)((char *)primary->b_data + + gdb_off * EXT4_DESC_SIZE(sb)); +@@ -862,19 +863,21 @@ int ext4_group_add(struct super_block *s + ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */ + ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */ + ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */ +- gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); +- gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); ++ ext4_free_blks_set(sb, gdp, input->free_blocks_count); ++ ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); ++ gdp->bg_flags |= cpu_to_le16(EXT4_BG_INODE_ZEROED); + gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp); + + /* + * We can allocate memory for mb_alloc based on the new group + * descriptor + */ +- if (test_opt(sb, MBALLOC)) { +- err = ext4_mb_add_more_groupinfo(sb, input->group, gdp); +- if (err) +- goto exit_journal; ++ err = ext4_mb_add_groupinfo(sb, input->group, gdp); ++ if (err) { ++ ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); ++ goto exit_journal; + } ++ + /* + * Make the new blocks and inodes valid next. We do this before + * increasing the group count so that once the group is enabled, +@@ -915,6 +918,7 @@ int ext4_group_add(struct super_block *s + + /* Update the global fs size fields */ + sbi->s_groups_count++; ++ ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); + + ext4_journal_dirty_metadata(handle, primary); + +@@ -973,12 +977,10 @@ int ext4_group_extend(struct super_block + ext4_group_t o_groups_count; + ext4_grpblk_t last; + ext4_grpblk_t add; +- struct buffer_head * bh; ++ struct buffer_head *bh; + handle_t *handle; + int err; +- unsigned long freed_blocks; + ext4_group_t group; +- struct ext4_group_info *grp; + + /* We don't need to worry about locking wrt other resizers just + * yet: we're going to revalidate es->s_blocks_count after +@@ -1077,50 +1079,13 @@ int ext4_group_extend(struct super_block + unlock_super(sb); + ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, + o_blocks_count + add); +- ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); ++ /* We add the blocks to the bitmap and set the group need init bit */ ++ ext4_add_groupblocks(handle, sb, o_blocks_count, add); + ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, + o_blocks_count + add); + if ((err = ext4_journal_stop(handle))) + goto exit_put; + +- /* +- * Mark mballoc pages as not up to date so that they will be updated +- * next time they are loaded by ext4_mb_load_buddy. +- */ +- if (test_opt(sb, MBALLOC)) { +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct inode *inode = sbi->s_buddy_cache; +- int blocks_per_page; +- int block; +- int pnum; +- struct page *page; +- +- /* Set buddy page as not up to date */ +- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; +- block = group * 2; +- pnum = block / blocks_per_page; +- page = find_get_page(inode->i_mapping, pnum); +- if (page != NULL) { +- ClearPageUptodate(page); +- page_cache_release(page); +- } +- +- /* Set bitmap page as not up to date */ +- block++; +- pnum = block / blocks_per_page; +- page = find_get_page(inode->i_mapping, pnum); +- if (page != NULL) { +- ClearPageUptodate(page); +- page_cache_release(page); +- } +- +- /* Get the info on the last group */ +- grp = ext4_get_group_info(sb, group); +- +- /* Update free blocks in group info */ +- ext4_mb_update_group_info(grp, add); +- } +- + if (test_opt(sb, DEBUG)) + printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n", + ext4_blocks_count(es)); +diff -rup b/fs/ext4//super.c a/fs/ext4///super.c +--- b/fs/ext4/super.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/super.c 2009-02-11 13:47:04.000000000 +0100 +@@ -34,6 +34,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -45,6 +47,8 @@ + #include "namei.h" + #include "group.h" + ++struct proc_dir_entry *ext4_proc_root; ++ + static int ext4_load_journal(struct super_block *, struct ext4_super_block *, + unsigned long journal_devnum); + static int ext4_create_journal(struct super_block *, struct ext4_super_block *, +@@ -89,6 +93,38 @@ ext4_fsblk_t ext4_inode_table(struct sup + (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0); + } + ++__u32 ext4_free_blks_count(struct super_block *sb, ++ struct ext4_group_desc *bg) ++{ ++ return le16_to_cpu(bg->bg_free_blocks_count_lo) | ++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? ++ (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0); ++} ++ ++__u32 ext4_free_inodes_count(struct super_block *sb, ++ struct ext4_group_desc *bg) ++{ ++ return le16_to_cpu(bg->bg_free_inodes_count_lo) | ++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? ++ (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0); ++} ++ ++__u32 ext4_used_dirs_count(struct super_block *sb, ++ struct ext4_group_desc *bg) ++{ ++ return le16_to_cpu(bg->bg_used_dirs_count_lo) | ++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? ++ (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0); ++} ++ ++__u32 ext4_itable_unused_count(struct super_block *sb, ++ struct ext4_group_desc *bg) ++{ ++ return le16_to_cpu(bg->bg_itable_unused_lo) | ++ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? ++ (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0); ++} ++ + void ext4_block_bitmap_set(struct super_block *sb, + struct ext4_group_desc *bg, ext4_fsblk_t blk) + { +@@ -113,6 +149,38 @@ void ext4_inode_table_set(struct super_b + bg->bg_inode_table_hi = cpu_to_le32(blk >> 32); + } + ++void ext4_free_blks_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count) ++{ ++ bg->bg_free_blocks_count_lo = cpu_to_le16((__u16)count); ++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) ++ bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16); ++} ++ ++void ext4_free_inodes_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count) ++{ ++ bg->bg_free_inodes_count_lo = cpu_to_le16((__u16)count); ++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) ++ bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16); ++} ++ ++void ext4_used_dirs_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count) ++{ ++ bg->bg_used_dirs_count_lo = cpu_to_le16((__u16)count); ++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) ++ bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16); ++} ++ ++void ext4_itable_unused_set(struct super_block *sb, ++ struct ext4_group_desc *bg, __u32 count) ++{ ++ bg->bg_itable_unused_lo = cpu_to_le16((__u16)count); ++ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) ++ bg->bg_itable_unused_hi = cpu_to_le16(count >> 16); ++} ++ + /* + * Wrappers for jbd2_journal_start/end. + * +@@ -329,7 +397,8 @@ void ext4_abort(struct super_block *sb, + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; + sb->s_flags |= MS_RDONLY; + EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; +- jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); ++ if (EXT4_SB(sb)->s_journal) ++ jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); + } + + void ext4_warning(struct super_block *sb, const char *function, +@@ -345,6 +414,44 @@ void ext4_warning(struct super_block *sb + va_end(args); + } + ++void ext4_grp_locked_error(struct super_block *sb, ext4_group_t grp, ++ const char *function, const char *fmt, ...) ++__releases(bitlock) ++__acquires(bitlock) ++{ ++ va_list args; ++ struct ext4_super_block *es = EXT4_SB(sb)->s_es; ++ ++ va_start(args, fmt); ++ printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function); ++ vprintk(fmt, args); ++ printk("\n"); ++ va_end(args); ++ ++ if (test_opt(sb, ERRORS_CONT)) { ++ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; ++ es->s_state |= cpu_to_le16(EXT4_ERROR_FS); ++ ext4_commit_super(sb, es, 0); ++ return; ++ } ++ ext4_unlock_group(sb, grp); ++ ext4_handle_error(sb); ++ /* ++ * We only get here in the ERRORS_RO case; relocking the group ++ * may be dangerous, but nothing bad will happen since the ++ * filesystem will have already been marked read/only and the ++ * journal has been aborted. We return 1 as a hint to callers ++ * who might what to use the return value from ++ * ext4_grp_locked_error() to distinguish beween the ++ * ERRORS_CONT and ERRORS_RO case, and perhaps return more ++ * aggressively from the ext4 function in question, with a ++ * more appropriate error code. ++ */ ++ ext4_lock_group(sb, grp); ++ return; ++} ++ ++ + void ext4_update_dynamic_rev(struct super_block *sb) + { + struct ext4_super_block *es = EXT4_SB(sb)->s_es; +@@ -370,66 +477,6 @@ void ext4_update_dynamic_rev(struct supe + */ + } + +-int ext4_update_compat_feature(handle_t *handle, +- struct super_block *sb, __u32 compat) +-{ +- int err = 0; +- if (!EXT4_HAS_COMPAT_FEATURE(sb, compat)) { +- err = ext4_journal_get_write_access(handle, +- EXT4_SB(sb)->s_sbh); +- if (err) +- return err; +- EXT4_SET_COMPAT_FEATURE(sb, compat); +- sb->s_dirt = 1; +- handle->h_sync = 1; +- BUFFER_TRACE(EXT4_SB(sb)->s_sbh, +- "call ext4_journal_dirty_met adata"); +- err = ext4_journal_dirty_metadata(handle, +- EXT4_SB(sb)->s_sbh); +- } +- return err; +-} +- +-int ext4_update_rocompat_feature(handle_t *handle, +- struct super_block *sb, __u32 rocompat) +-{ +- int err = 0; +- if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, rocompat)) { +- err = ext4_journal_get_write_access(handle, +- EXT4_SB(sb)->s_sbh); +- if (err) +- return err; +- EXT4_SET_RO_COMPAT_FEATURE(sb, rocompat); +- sb->s_dirt = 1; +- handle->h_sync = 1; +- BUFFER_TRACE(EXT4_SB(sb)->s_sbh, +- "call ext4_journal_dirty_met adata"); +- err = ext4_journal_dirty_metadata(handle, +- EXT4_SB(sb)->s_sbh); +- } +- return err; +-} +- +-int ext4_update_incompat_feature(handle_t *handle, +- struct super_block *sb, __u32 incompat) +-{ +- int err = 0; +- if (!EXT4_HAS_INCOMPAT_FEATURE(sb, incompat)) { +- err = ext4_journal_get_write_access(handle, +- EXT4_SB(sb)->s_sbh); +- if (err) +- return err; +- EXT4_SET_INCOMPAT_FEATURE(sb, incompat); +- sb->s_dirt = 1; +- handle->h_sync = 1; +- BUFFER_TRACE(EXT4_SB(sb)->s_sbh, +- "call ext4_journal_dirty_met adata"); +- err = ext4_journal_dirty_metadata(handle, +- EXT4_SB(sb)->s_sbh); +- } +- return err; +-} +- + /* + * Open the external journal device + */ +@@ -505,13 +552,16 @@ static void ext4_put_super(struct super_ + ext4_xattr_put_super(sb); + jbd2_journal_destroy(sbi->s_journal); + sbi->s_journal = NULL; ++ + if (!(sb->s_flags & MS_RDONLY)) { + EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); + es->s_state = cpu_to_le16(sbi->s_mount_state); +- BUFFER_TRACE(sbi->s_sbh, "marking dirty"); +- mark_buffer_dirty(sbi->s_sbh); + ext4_commit_super(sb, es, 1); + } ++ if (sbi->s_proc) { ++ remove_proc_entry("inode_readahead_blks", sbi->s_proc); ++ remove_proc_entry(sb->s_id, ext4_proc_root); ++ } + + for (i = 0; i < sbi->s_gdb_count; i++) + brelse(sbi->s_group_desc[i]); +@@ -520,6 +570,7 @@ static void ext4_put_super(struct super_ + percpu_counter_destroy(&sbi->s_freeblocks_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); ++ percpu_counter_destroy(&sbi->s_dirtyblocks_counter); + brelse(sbi->s_sbh); + #ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) +@@ -562,11 +613,10 @@ static struct inode *ext4_alloc_inode(st + ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS); + if (!ei) + return NULL; +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + ei->i_acl = EXT4_ACL_NOT_CACHED; + ei->i_default_acl = EXT4_ACL_NOT_CACHED; + #endif +- ei->i_block_alloc_info = NULL; + ei->vfs_inode.i_version = 1; + ei->vfs_inode.i_data.writeback_index = 0; + memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); +@@ -599,7 +649,7 @@ static void init_once(void *foo) + struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; + + INIT_LIST_HEAD(&ei->i_orphan); +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + init_rwsem(&ei->xattr_sem); + #endif + init_rwsem(&ei->i_data_sem); +@@ -625,8 +675,7 @@ static void destroy_inodecache(void) + + static void ext4_clear_inode(struct inode *inode) + { +- struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info; +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + if (EXT4_I(inode)->i_acl && + EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) { + posix_acl_release(EXT4_I(inode)->i_acl); +@@ -638,10 +687,7 @@ static void ext4_clear_inode(struct inod + EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED; + } + #endif +- ext4_discard_reservation(inode); +- EXT4_I(inode)->i_block_alloc_info = NULL; +- if (unlikely(rsv)) +- kfree(rsv); ++ ext4_discard_preallocations(inode); + jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal, + &EXT4_I(inode)->jinode); + } +@@ -654,7 +700,7 @@ static inline void ext4_show_quota_optio + + if (sbi->s_jquota_fmt) + seq_printf(seq, ",jqfmt=%s", +- (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0"); ++ (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold" : "vfsv0"); + + if (sbi->s_qf_names[USRQUOTA]) + seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); +@@ -718,7 +764,7 @@ static int ext4_show_options(struct seq_ + seq_puts(seq, ",debug"); + if (test_opt(sb, OLDALLOC)) + seq_puts(seq, ",oldalloc"); +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + if (test_opt(sb, XATTR_USER) && + !(def_mount_opts & EXT4_DEFM_XATTR_USER)) + seq_puts(seq, ",user_xattr"); +@@ -727,7 +773,7 @@ static int ext4_show_options(struct seq_ + seq_puts(seq, ",nouser_xattr"); + } + #endif +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL)) + seq_puts(seq, ",acl"); + if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL)) +@@ -752,8 +798,6 @@ static int ext4_show_options(struct seq_ + seq_puts(seq, ",nobh"); + if (!test_opt(sb, EXTENTS)) + seq_puts(seq, ",noextents"); +- if (!test_opt(sb, MBALLOC)) +- seq_puts(seq, ",nomballoc"); + if (test_opt(sb, I_VERSION)) + seq_puts(seq, ",i_version"); + if (!test_opt(sb, DELALLOC)) +@@ -773,6 +817,10 @@ static int ext4_show_options(struct seq_ + else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) + seq_puts(seq, ",data=writeback"); + ++ if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS) ++ seq_printf(seq, ",inode_readahead_blks=%u", ++ sbi->s_inode_readahead_blks); ++ + ext4_show_quota_options(seq, sb); + return 0; + } +@@ -822,7 +870,7 @@ static struct dentry *ext4_fh_to_parent( + } + + #ifdef CONFIG_QUOTA +-#define QTYPE2NAME(t) ((t) == USRQUOTA?"user":"group") ++#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group") + #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) + + static int ext4_dquot_initialize(struct inode *inode, int type); +@@ -896,7 +944,7 @@ static const struct export_operations ex + enum { + Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, + Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, +- Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, ++ Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov, + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, + Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh, + Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, +@@ -906,10 +954,11 @@ enum { + Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, + Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, + Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version, +- Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_delalloc, Opt_nodelalloc, ++ Opt_stripe, Opt_delalloc, Opt_nodelalloc, ++ Opt_inode_readahead_blks + }; + +-static match_table_t tokens = { ++static const match_table_t tokens = { + {Opt_bsd_df, "bsddf"}, + {Opt_minix_df, "minixdf"}, + {Opt_grpid, "grpid"}, +@@ -923,8 +972,6 @@ static match_table_t tokens = { + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, + {Opt_nouid32, "nouid32"}, +- {Opt_nocheck, "nocheck"}, +- {Opt_nocheck, "check=none"}, + {Opt_debug, "debug"}, + {Opt_oldalloc, "oldalloc"}, + {Opt_orlov, "orlov"}, +@@ -961,12 +1008,11 @@ static match_table_t tokens = { + {Opt_extents, "extents"}, + {Opt_noextents, "noextents"}, + {Opt_i_version, "i_version"}, +- {Opt_mballoc, "mballoc"}, +- {Opt_nomballoc, "nomballoc"}, + {Opt_stripe, "stripe=%u"}, + {Opt_resize, "resize"}, + {Opt_delalloc, "delalloc"}, + {Opt_nodelalloc, "nodelalloc"}, ++ {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, + {Opt_err, NULL}, + }; + +@@ -981,7 +1027,7 @@ static ext4_fsblk_t get_sb_block(void ** + /*todo: use simple_strtoll with >32bit ext4 */ + sb_block = simple_strtoul(options, &options, 0); + if (*options && *options != ',') { +- printk("EXT4-fs: Invalid sb specification: %s\n", ++ printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n", + (char *) *data); + return 1; + } +@@ -1060,9 +1106,6 @@ static int parse_options(char *options, + case Opt_nouid32: + set_opt(sbi->s_mount_opt, NO_UID32); + break; +- case Opt_nocheck: +- clear_opt(sbi->s_mount_opt, CHECK); +- break; + case Opt_debug: + set_opt(sbi->s_mount_opt, DEBUG); + break; +@@ -1072,7 +1115,7 @@ static int parse_options(char *options, + case Opt_orlov: + clear_opt(sbi->s_mount_opt, OLDALLOC); + break; +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + case Opt_user_xattr: + set_opt(sbi->s_mount_opt, XATTR_USER); + break; +@@ -1082,10 +1125,11 @@ static int parse_options(char *options, + #else + case Opt_user_xattr: + case Opt_nouser_xattr: +- printk("EXT4 (no)user_xattr options not supported\n"); ++ printk(KERN_ERR "EXT4 (no)user_xattr options " ++ "not supported\n"); + break; + #endif +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + case Opt_acl: + set_opt(sbi->s_mount_opt, POSIX_ACL); + break; +@@ -1095,7 +1139,8 @@ static int parse_options(char *options, + #else + case Opt_acl: + case Opt_noacl: +- printk("EXT4 (no)acl options not supported\n"); ++ printk(KERN_ERR "EXT4 (no)acl options " ++ "not supported\n"); + break; + #endif + case Opt_reservation: +@@ -1185,12 +1230,11 @@ static int parse_options(char *options, + case Opt_grpjquota: + qtype = GRPQUOTA; + set_qf_name: +- if ((sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) && ++ if (sb_any_quota_loaded(sb) && + !sbi->s_qf_names[qtype]) { + printk(KERN_ERR +- "EXT4-fs: Cannot change journaled " +- "quota options when quota turned on.\n"); ++ "EXT4-fs: Cannot change journaled " ++ "quota options when quota turned on.\n"); + return 0; + } + qname = match_strdup(&args[0]); +@@ -1225,8 +1269,7 @@ set_qf_name: + case Opt_offgrpjquota: + qtype = GRPQUOTA; + clear_qf_name: +- if ((sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) && ++ if (sb_any_quota_loaded(sb) && + sbi->s_qf_names[qtype]) { + printk(KERN_ERR "EXT4-fs: Cannot change " + "journaled quota options when " +@@ -1245,8 +1288,7 @@ clear_qf_name: + case Opt_jqfmt_vfsv0: + qfmt = QFMT_VFS_V0; + set_qf_format: +- if ((sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) && ++ if (sb_any_quota_loaded(sb) && + sbi->s_jquota_fmt != qfmt) { + printk(KERN_ERR "EXT4-fs: Cannot change " + "journaled quota options when " +@@ -1265,7 +1307,7 @@ set_qf_format: + set_opt(sbi->s_mount_opt, GRPQUOTA); + break; + case Opt_noquota: +- if (sb_any_quota_enabled(sb)) { ++ if (sb_any_quota_loaded(sb)) { + printk(KERN_ERR "EXT4-fs: Cannot change quota " + "options when quota turned on.\n"); + return 0; +@@ -1357,12 +1399,6 @@ set_qf_format: + case Opt_nodelalloc: + clear_opt(sbi->s_mount_opt, DELALLOC); + break; +- case Opt_mballoc: +- set_opt(sbi->s_mount_opt, MBALLOC); +- break; +- case Opt_nomballoc: +- clear_opt(sbi->s_mount_opt, MBALLOC); +- break; + case Opt_stripe: + if (match_int(&args[0], &option)) + return 0; +@@ -1373,6 +1409,13 @@ set_qf_format: + case Opt_delalloc: + set_opt(sbi->s_mount_opt, DELALLOC); + break; ++ case Opt_inode_readahead_blks: ++ if (match_int(&args[0], &option)) ++ return 0; ++ if (option < 0 || option > (1 << 30)) ++ return 0; ++ sbi->s_inode_readahead_blks = option; ++ break; + default: + printk(KERN_ERR + "EXT4-fs: Unrecognized mount option \"%s\" " +@@ -1465,7 +1508,7 @@ static int ext4_setup_super(struct super + + ext4_commit_super(sb, es, 1); + if (test_opt(sb, DEBUG)) +- printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%lu, " ++ printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " + "bpg=%lu, ipg=%lu, mo=%04lx]\n", + sb->s_blocksize, + sbi->s_groups_count, +@@ -1473,14 +1516,14 @@ static int ext4_setup_super(struct super + EXT4_INODES_PER_GROUP(sb), + sbi->s_mount_opt); + +- printk(KERN_INFO "EXT4 FS on %s, ", sb->s_id); + if (EXT4_SB(sb)->s_journal->j_inode == NULL) { + char b[BDEVNAME_SIZE]; + +- printk("external journal on %s\n", +- bdevname(EXT4_SB(sb)->s_journal->j_dev, b)); ++ printk(KERN_INFO "EXT4 FS on %s, external journal on %s\n", ++ sb->s_id, bdevname(EXT4_SB(sb)->s_journal->j_dev, b)); + } else { +- printk("internal journal\n"); ++ printk(KERN_INFO "EXT4 FS on %s, internal journal\n", ++ sb->s_id); + } + return res; + } +@@ -1493,7 +1536,6 @@ static int ext4_fill_flex_info(struct su + ext4_group_t flex_group_count; + ext4_group_t flex_group; + int groups_per_flex = 0; +- __u64 block_bitmap = 0; + int i; + + if (!sbi->s_es->s_log_groups_per_flex) { +@@ -1512,21 +1554,18 @@ static int ext4_fill_flex_info(struct su + sizeof(struct flex_groups), GFP_KERNEL); + if (sbi->s_flex_groups == NULL) { + printk(KERN_ERR "EXT4-fs: not enough memory for " +- "%lu flex groups\n", flex_group_count); ++ "%u flex groups\n", flex_group_count); + goto failed; + } + +- gdp = ext4_get_group_desc(sb, 1, &bh); +- block_bitmap = ext4_block_bitmap(sb, gdp) - 1; +- + for (i = 0; i < sbi->s_groups_count; i++) { + gdp = ext4_get_group_desc(sb, i, &bh); + + flex_group = ext4_flex_group(sbi, i); + sbi->s_flex_groups[flex_group].free_inodes += +- le16_to_cpu(gdp->bg_free_inodes_count); ++ ext4_free_inodes_count(sb, gdp); + sbi->s_flex_groups[flex_group].free_blocks += +- le16_to_cpu(gdp->bg_free_blocks_count); ++ ext4_free_blks_count(sb, gdp); + } + + return 1; +@@ -1586,7 +1625,7 @@ static int ext4_check_descriptors(struct + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) + flexbg_flag = 1; + +- ext4_debug ("Checking group descriptors"); ++ ext4_debug("Checking group descriptors"); + + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); +@@ -1600,29 +1639,29 @@ static int ext4_check_descriptors(struct + block_bitmap = ext4_block_bitmap(sb, gdp); + if (block_bitmap < first_block || block_bitmap > last_block) { + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " +- "Block bitmap for group %lu not in group " +- "(block %llu)!", i, block_bitmap); ++ "Block bitmap for group %u not in group " ++ "(block %llu)!\n", i, block_bitmap); + return 0; + } + inode_bitmap = ext4_inode_bitmap(sb, gdp); + if (inode_bitmap < first_block || inode_bitmap > last_block) { + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " +- "Inode bitmap for group %lu not in group " +- "(block %llu)!", i, inode_bitmap); ++ "Inode bitmap for group %u not in group " ++ "(block %llu)!\n", i, inode_bitmap); + return 0; + } + inode_table = ext4_inode_table(sb, gdp); + if (inode_table < first_block || + inode_table + sbi->s_itb_per_group - 1 > last_block) { + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " +- "Inode table for group %lu not in group " +- "(block %llu)!", i, inode_table); ++ "Inode table for group %u not in group " ++ "(block %llu)!\n", i, inode_table); + return 0; + } + spin_lock(sb_bgl_lock(sbi, i)); + if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { + printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " +- "Checksum for group %lu failed (%u!=%u)\n", ++ "Checksum for group %u failed (%u!=%u)\n", + i, le16_to_cpu(ext4_group_desc_csum(sbi, i, + gdp)), le16_to_cpu(gdp->bg_checksum)); + if (!(sb->s_flags & MS_RDONLY)) { +@@ -1718,9 +1757,9 @@ static void ext4_orphan_cleanup(struct s + DQUOT_INIT(inode); + if (inode->i_nlink) { + printk(KERN_DEBUG +- "%s: truncating inode %lu to %Ld bytes\n", ++ "%s: truncating inode %lu to %lld bytes\n", + __func__, inode->i_ino, inode->i_size); +- jbd_debug(2, "truncating inode %lu to %Ld bytes\n", ++ jbd_debug(2, "truncating inode %lu to %lld bytes\n", + inode->i_ino, inode->i_size); + ext4_truncate(inode); + nr_truncates++; +@@ -1761,13 +1800,13 @@ static void ext4_orphan_cleanup(struct s + * + * Note, this does *not* consider any metadata overhead for vfs i_blocks. + */ +-static loff_t ext4_max_size(int blkbits) ++static loff_t ext4_max_size(int blkbits, int has_huge_files) + { + loff_t res; + loff_t upper_limit = MAX_LFS_FILESIZE; + + /* small i_blocks in vfs inode? */ +- if (sizeof(blkcnt_t) < sizeof(u64)) { ++ if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { + /* + * CONFIG_LSF is not enabled implies the inode + * i_block represent total blocks in 512 bytes +@@ -1797,7 +1836,7 @@ static loff_t ext4_max_size(int blkbits) + * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks. + * We need to be 1 filesystem block less than the 2^48 sector limit. + */ +-static loff_t ext4_max_bitmap_size(int bits) ++static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) + { + loff_t res = EXT4_NDIR_BLOCKS; + int meta_blocks; +@@ -1810,11 +1849,11 @@ static loff_t ext4_max_bitmap_size(int b + * total number of 512 bytes blocks of the file + */ + +- if (sizeof(blkcnt_t) < sizeof(u64)) { ++ if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { + /* +- * CONFIG_LSF is not enabled implies the inode +- * i_block represent total blocks in 512 bytes +- * 32 == size of vfs inode i_blocks * 8 ++ * !has_huge_files or CONFIG_LSF is not enabled ++ * implies the inode i_block represent total blocks in ++ * 512 bytes 32 == size of vfs inode i_blocks * 8 + */ + upper_limit = (1LL << 32) - 1; + +@@ -1918,12 +1957,13 @@ static int ext4_fill_super(struct super_ + unsigned long journal_devnum = 0; + unsigned long def_mount_opts; + struct inode *root; ++ char *cp; + int ret = -EINVAL; + int blocksize; + int db_count; + int i; +- int needs_recovery; +- __le32 features; ++ int needs_recovery, has_huge_files; ++ int features; + __u64 blocks_count; + int err; + +@@ -1934,10 +1974,15 @@ static int ext4_fill_super(struct super_ + sbi->s_mount_opt = 0; + sbi->s_resuid = EXT4_DEF_RESUID; + sbi->s_resgid = EXT4_DEF_RESGID; ++ sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; + sbi->s_sb_block = sb_block; + + unlock_kernel(); + ++ /* Cleanup superblock name */ ++ for (cp = sb->s_id; (cp = strchr(cp, '/'));) ++ *cp = '!'; ++ + blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE); + if (!blocksize) { + printk(KERN_ERR "EXT4-fs: unable to set blocksize\n"); +@@ -1977,11 +2022,11 @@ static int ext4_fill_super(struct super_ + set_opt(sbi->s_mount_opt, GRPID); + if (def_mount_opts & EXT4_DEFM_UID16) + set_opt(sbi->s_mount_opt, NO_UID32); +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + if (def_mount_opts & EXT4_DEFM_XATTR_USER) + set_opt(sbi->s_mount_opt, XATTR_USER); + #endif +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + if (def_mount_opts & EXT4_DEFM_ACL) + set_opt(sbi->s_mount_opt, POSIX_ACL); + #endif +@@ -2016,11 +2061,6 @@ static int ext4_fill_super(struct super_ + ext4_warning(sb, __func__, + "extents feature not enabled on this filesystem, " + "use tune2fs.\n"); +- /* +- * turn on mballoc code by default in ext4 filesystem +- * Use -o nomballoc to turn it off +- */ +- set_opt(sbi->s_mount_opt, MBALLOC); + + /* + * enable delayed allocation by default +@@ -2045,16 +2085,6 @@ static int ext4_fill_super(struct super_ + "running e2fsck is recommended\n"); + + /* +- * Since ext4 is still considered development code, we require +- * that the TEST_FILESYS flag in s->flags be set. +- */ +- if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)) { +- printk(KERN_WARNING "EXT4-fs: %s: not marked " +- "OK to use with test code.\n", sb->s_id); +- goto failed_mount; +- } +- +- /* + * Check feature flags regardless of the revision level, since we + * previously didn't change the revision level when setting the flags, + * so there is a chance incompat flags are set on a rev 0 filesystem. +@@ -2062,18 +2092,22 @@ static int ext4_fill_super(struct super_ + features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP); + if (features) { + printk(KERN_ERR "EXT4-fs: %s: couldn't mount because of " +- "unsupported optional features (%x).\n", +- sb->s_id, le32_to_cpu(features)); ++ "unsupported optional features (%x).\n", sb->s_id, ++ (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & ++ ~EXT4_FEATURE_INCOMPAT_SUPP)); + goto failed_mount; + } + features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP); + if (!(sb->s_flags & MS_RDONLY) && features) { + printk(KERN_ERR "EXT4-fs: %s: couldn't mount RDWR because of " +- "unsupported optional features (%x).\n", +- sb->s_id, le32_to_cpu(features)); ++ "unsupported optional features (%x).\n", sb->s_id, ++ (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & ++ ~EXT4_FEATURE_RO_COMPAT_SUPP)); + goto failed_mount; + } +- if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { ++ has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb, ++ EXT4_FEATURE_RO_COMPAT_HUGE_FILE); ++ if (has_huge_files) { + /* + * Large file size enabled file system can only be + * mount if kernel is build with CONFIG_LSF +@@ -2123,8 +2157,9 @@ static int ext4_fill_super(struct super_ + } + } + +- sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits); +- sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits); ++ sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, ++ has_huge_files); ++ sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); + + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { + sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; +@@ -2172,6 +2207,18 @@ static int ext4_fill_super(struct super_ + for (i = 0; i < 4; i++) + sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); + sbi->s_def_hash_version = es->s_def_hash_version; ++ i = le32_to_cpu(es->s_flags); ++ if (i & EXT2_FLAGS_UNSIGNED_HASH) ++ sbi->s_hash_unsigned = 3; ++ else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { ++#ifdef __CHAR_UNSIGNED__ ++ es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); ++ sbi->s_hash_unsigned = 3; ++#else ++ es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); ++#endif ++ sb->s_dirt = 1; ++ } + + if (sbi->s_blocks_per_group > blocksize * 8) { + printk(KERN_ERR +@@ -2223,6 +2270,16 @@ static int ext4_fill_super(struct super_ + goto failed_mount; + } + ++#ifdef CONFIG_PROC_FS ++ if (ext4_proc_root) ++ sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); ++ ++ if (sbi->s_proc) ++ proc_create_data("inode_readahead_blks", 0644, sbi->s_proc, ++ &ext4_ui_proc_fops, ++ &sbi->s_inode_readahead_blks); ++#endif ++ + bgl_lock_init(&sbi->s_blockgroup_lock); + + for (i = 0; i < db_count; i++) { +@@ -2261,24 +2318,14 @@ static int ext4_fill_super(struct super_ + err = percpu_counter_init(&sbi->s_dirs_counter, + ext4_count_dirs(sb)); + } ++ if (!err) { ++ err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0); ++ } + if (err) { + printk(KERN_ERR "EXT4-fs: insufficient memory\n"); + goto failed_mount3; + } + +- /* per fileystem reservation list head & lock */ +- spin_lock_init(&sbi->s_rsv_window_lock); +- sbi->s_rsv_window_root = RB_ROOT; +- /* Add a single, static dummy reservation to the start of the +- * reservation window list --- it gives us a placeholder for +- * append-at-start-of-list which makes the allocation logic +- * _much_ simpler. */ +- sbi->s_rsv_window_head.rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +- sbi->s_rsv_window_head.rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED; +- sbi->s_rsv_window_head.rsv_alloc_hit = 0; +- sbi->s_rsv_window_head.rsv_goal_size = 0; +- ext4_rsv_window_add(sb, &sbi->s_rsv_window_head); +- + sbi->s_stripe = ext4_get_stripe_size(sbi); + + /* +@@ -2498,11 +2545,16 @@ failed_mount3: + percpu_counter_destroy(&sbi->s_freeblocks_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); ++ percpu_counter_destroy(&sbi->s_dirtyblocks_counter); + failed_mount2: + for (i = 0; i < db_count; i++) + brelse(sbi->s_group_desc[i]); + kfree(sbi->s_group_desc); + failed_mount: ++ if (sbi->s_proc) { ++ remove_proc_entry("inode_readahead_blks", sbi->s_proc); ++ remove_proc_entry(sb->s_id, ext4_proc_root); ++ } + #ifdef CONFIG_QUOTA + for (i = 0; i < MAXQUOTAS; i++) + kfree(sbi->s_qf_names[i]); +@@ -2561,7 +2613,7 @@ static journal_t *ext4_get_journal(struc + return NULL; + } + +- jbd_debug(2, "Journal inode found at %p: %Ld bytes\n", ++ jbd_debug(2, "Journal inode found at %p: %lld bytes\n", + journal_inode, journal_inode->i_size); + if (!S_ISREG(journal_inode->i_mode)) { + printk(KERN_ERR "EXT4-fs: invalid journal inode.\n"); +@@ -2724,6 +2776,11 @@ static int ext4_load_journal(struct supe + return -EINVAL; + } + ++ if (journal->j_flags & JBD2_BARRIER) ++ printk(KERN_INFO "EXT4-fs: barriers enabled\n"); ++ else ++ printk(KERN_INFO "EXT4-fs: barriers disabled\n"); ++ + if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { + err = jbd2_journal_update_format(journal); + if (err) { +@@ -2823,8 +2880,11 @@ static void ext4_commit_super(struct sup + set_buffer_uptodate(sbh); + } + es->s_wtime = cpu_to_le32(get_seconds()); +- ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb)); +- es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); ++ ext4_free_blocks_count_set(es, percpu_counter_sum_positive( ++ &EXT4_SB(sb)->s_freeblocks_counter)); ++ es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive( ++ &EXT4_SB(sb)->s_freeinodes_counter)); ++ + BUFFER_TRACE(sbh, "marking dirty"); + mark_buffer_dirty(sbh); + if (sync) { +@@ -2850,7 +2910,9 @@ static void ext4_mark_recovery_complete( + journal_t *journal = EXT4_SB(sb)->s_journal; + + jbd2_journal_lock_updates(journal); +- jbd2_journal_flush(journal); ++ if (jbd2_journal_flush(journal) < 0) ++ goto out; ++ + lock_super(sb); + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) && + sb->s_flags & MS_RDONLY) { +@@ -2859,6 +2921,8 @@ static void ext4_mark_recovery_complete( + ext4_commit_super(sb, es, 1); + } + unlock_super(sb); ++ ++out: + jbd2_journal_unlock_updates(journal); + } + +@@ -2934,6 +2998,7 @@ static int ext4_sync_fs(struct super_blo + { + int ret = 0; + ++ trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait); + sb->s_dirt = 0; + if (wait) + ret = ext4_force_commit(sb); +@@ -2955,7 +3020,13 @@ static void ext4_write_super_lockfs(stru + + /* Now we set up the journal barrier. */ + jbd2_journal_lock_updates(journal); +- jbd2_journal_flush(journal); ++ ++ /* ++ * We don't want to clear needs_recovery flag when we failed ++ * to flush the journal. ++ */ ++ if (jbd2_journal_flush(journal) < 0) ++ return; + + /* Journal blocked and flushed, clear needs_recovery flag. */ + EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); +@@ -3053,13 +3124,14 @@ static int ext4_remount(struct super_blo + ext4_mark_recovery_complete(sb, es); + lock_super(sb); + } else { +- __le32 ret; ++ int ret; + if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, + ~EXT4_FEATURE_RO_COMPAT_SUPP))) { + printk(KERN_WARNING "EXT4-fs: %s: couldn't " + "remount RDWR because of unsupported " +- "optional features (%x).\n", +- sb->s_id, le32_to_cpu(ret)); ++ "optional features (%x).\n", sb->s_id, ++ (le32_to_cpu(sbi->s_es->s_feature_ro_compat) & ++ ~EXT4_FEATURE_RO_COMPAT_SUPP)); + err = -EROFS; + goto restore_opts; + } +@@ -3076,7 +3148,7 @@ static int ext4_remount(struct super_blo + if (!ext4_group_desc_csum_verify(sbi, g, gdp)) { + printk(KERN_ERR + "EXT4-fs: ext4_remount: " +- "Checksum for group %lu failed (%u!=%u)\n", ++ "Checksum for group %u failed (%u!=%u)\n", + g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), + le16_to_cpu(gdp->bg_checksum)); + err = -EINVAL; +@@ -3189,7 +3261,8 @@ static int ext4_statfs(struct dentry *de + buf->f_type = EXT4_SUPER_MAGIC; + buf->f_bsize = sb->s_blocksize; + buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; +- buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); ++ buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) - ++ percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter); + ext4_free_blocks_count_set(es, buf->f_bfree); + buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); + if (buf->f_bfree < ext4_r_blocks_count(es)) +@@ -3394,8 +3467,12 @@ static int ext4_quota_on(struct super_bl + * otherwise be livelocked... + */ + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); +- jbd2_journal_flush(EXT4_SB(sb)->s_journal); ++ err = jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); ++ if (err) { ++ path_put(&nd.path); ++ return err; ++ } + } + + err = vfs_quota_on_path(sb, type, format_id, &nd.path); +@@ -3459,7 +3536,7 @@ static ssize_t ext4_quota_write(struct s + handle_t *handle = journal_current_handle(); + + if (!handle) { +- printk(KERN_WARNING "EXT4-fs: Quota write (off=%Lu, len=%Lu)" ++ printk(KERN_WARNING "EXT4-fs: Quota write (off=%llu, len=%llu)" + " cancelled because transaction is not started.\n", + (unsigned long long)off, (unsigned long long)len); + return -EIO; +@@ -3520,18 +3597,73 @@ static int ext4_get_sb(struct file_syste + return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt); + } + ++#ifdef CONFIG_PROC_FS ++static int ext4_ui_proc_show(struct seq_file *m, void *v) ++{ ++ unsigned int *p = m->private; ++ ++ seq_printf(m, "%u\n", *p); ++ return 0; ++} ++ ++static int ext4_ui_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, ext4_ui_proc_show, PDE(inode)->data); ++} ++ ++static ssize_t ext4_ui_proc_write(struct file *file, const char __user *buf, ++ size_t cnt, loff_t *ppos) ++{ ++ unsigned long *p = PDE(file->f_path.dentry->d_inode)->data; ++ char str[32]; ++ ++ if (cnt >= sizeof(str)) ++ return -EINVAL; ++ if (copy_from_user(str, buf, cnt)) ++ return -EFAULT; ++ ++ *p = simple_strtoul(str, NULL, 0); ++ return cnt; ++} ++ ++const struct file_operations ext4_ui_proc_fops = { ++ .owner = THIS_MODULE, ++ .open = ext4_ui_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = ext4_ui_proc_write, ++}; ++#endif ++ ++static struct file_system_type ext4_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "ext4", ++ .get_sb = ext4_get_sb, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV, ++}; ++ ++static int ext4dev_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *data, struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt); ++} ++ + static struct file_system_type ext4dev_fs_type = { + .owner = THIS_MODULE, + .name = "ext4dev", +- .get_sb = ext4_get_sb, ++ .get_sb = ext4dev_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, + }; ++MODULE_ALIAS("ext4dev"); + + static int __init init_ext4_fs(void) + { + int err; + ++ ext4_proc_root = proc_mkdir("fs/ext4", NULL); + err = init_ext4_mballoc(); + if (err) + return err; +@@ -3542,9 +3674,14 @@ static int __init init_ext4_fs(void) + err = init_inodecache(); + if (err) + goto out1; +- err = register_filesystem(&ext4dev_fs_type); ++ err = register_filesystem(&ext4_fs_type); + if (err) + goto out; ++ err = register_filesystem(&ext4dev_fs_type); ++ if (err) { ++ unregister_filesystem(&ext4_fs_type); ++ goto out; ++ } + return 0; + out: + destroy_inodecache(); +@@ -3557,10 +3694,12 @@ out2: + + static void __exit exit_ext4_fs(void) + { ++ unregister_filesystem(&ext4_fs_type); + unregister_filesystem(&ext4dev_fs_type); + destroy_inodecache(); + exit_ext4_xattr(); + exit_ext4_mballoc(); ++ remove_proc_entry("fs/ext4", NULL); + } + + MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); +diff -rup b/fs/ext4//symlink.c a/fs/ext4///symlink.c +--- b/fs/ext4/symlink.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/symlink.c 2009-02-10 21:40:11.000000000 +0100 +@@ -23,10 +23,10 @@ + #include "ext4.h" + #include "xattr.h" + +-static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd) ++static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd) + { + struct ext4_inode_info *ei = EXT4_I(dentry->d_inode); +- nd_set_link(nd, (char*)ei->i_data); ++ nd_set_link(nd, (char *) ei->i_data); + return NULL; + } + +@@ -34,7 +34,7 @@ const struct inode_operations ext4_symli + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext4_listxattr, +@@ -45,7 +45,7 @@ const struct inode_operations ext4_symli + const struct inode_operations ext4_fast_symlink_inode_operations = { + .readlink = generic_readlink, + .follow_link = ext4_follow_link, +-#ifdef CONFIG_EXT4DEV_FS_XATTR ++#if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ext4_listxattr, +diff -rup b/fs/ext4//xattr.c a/fs/ext4///xattr.c +--- b/fs/ext4/xattr.c 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/xattr.c 2009-02-10 21:40:11.000000000 +0100 +@@ -99,12 +99,12 @@ static struct mb_cache *ext4_xattr_cache + + static struct xattr_handler *ext4_xattr_handler_map[] = { + [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext4_xattr_acl_access_handler, + [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler, + #endif + [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, +-#ifdef CONFIG_EXT4DEV_FS_SECURITY ++#if defined(CONFIG_EXT4_FS_SECURITY) || defined(CONFIG_EXT4DEV_FS_SECURITY) + [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, + #endif + }; +@@ -112,11 +112,11 @@ static struct xattr_handler *ext4_xattr_ + struct xattr_handler *ext4_xattr_handlers[] = { + &ext4_xattr_user_handler, + &ext4_xattr_trusted_handler, +-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ++#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4DEV_FS_POSIX_ACL) + &ext4_xattr_acl_access_handler, + &ext4_xattr_acl_default_handler, + #endif +-#ifdef CONFIG_EXT4DEV_FS_SECURITY ++#if defined(CONFIG_EXT4_FS_SECURITY) || defined(CONFIG_EXT4DEV_FS_SECURITY) + &ext4_xattr_security_handler, + #endif + NULL +@@ -810,8 +810,8 @@ inserted: + /* We need to allocate a new block */ + ext4_fsblk_t goal = ext4_group_first_block_no(sb, + EXT4_I(inode)->i_block_group); +- ext4_fsblk_t block = ext4_new_meta_block(handle, inode, +- goal, &error); ++ ext4_fsblk_t block = ext4_new_meta_blocks(handle, inode, ++ goal, NULL, &error); + if (error) + goto cleanup; + ea_idebug(inode, "creating block %d", block); +diff -rup b/fs/ext4//xattr.h a/fs/ext4///xattr.h +--- b/fs/ext4/xattr.h 2009-02-11 14:37:58.000000000 +0100 ++++ a/fs/ext4/xattr.h 2009-02-10 21:40:14.000000000 +0100 +@@ -51,8 +51,8 @@ struct ext4_xattr_entry { + (((name_len) + EXT4_XATTR_ROUND + \ + sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND) + #define EXT4_XATTR_NEXT(entry) \ +- ( (struct ext4_xattr_entry *)( \ +- (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)) ) ++ ((struct ext4_xattr_entry *)( \ ++ (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len))) + #define EXT4_XATTR_SIZE(size) \ + (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND) + +@@ -63,7 +63,7 @@ struct ext4_xattr_entry { + EXT4_I(inode)->i_extra_isize)) + #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) + +-# ifdef CONFIG_EXT4DEV_FS_XATTR ++# if defined(CONFIG_EXT4_FS_XATTR) || defined(CONFIG_EXT4DEV_FS_XATTR) + + extern struct xattr_handler ext4_xattr_user_handler; + extern struct xattr_handler ext4_xattr_trusted_handler; +@@ -88,7 +88,7 @@ extern void exit_ext4_xattr(void); + + extern struct xattr_handler *ext4_xattr_handlers[]; + +-# else /* CONFIG_EXT4DEV_FS_XATTR */ ++# else /* CONFIG_EXT4_FS_XATTR */ + + static inline int + ext4_xattr_get(struct inode *inode, int name_index, const char *name, +@@ -141,9 +141,9 @@ ext4_expand_extra_isize_ea(struct inode + + #define ext4_xattr_handlers NULL + +-# endif /* CONFIG_EXT4DEV_FS_XATTR */ ++# endif /* CONFIG_EXT4_FS_XATTR */ + +-#ifdef CONFIG_EXT4DEV_FS_SECURITY ++#if defined(CONFIG_EXT4_FS_SECURITY) || defined(CONFIG_EXT4DEV_FS_SECURITY) + extern int ext4_init_security(handle_t *handle, struct inode *inode, + struct inode *dir); + #else diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext4-mballoc-preallocate.patch b/src/patches/suse-2.6.27.31/patches.fixes/ext4-mballoc-preallocate.patch new file mode 100644 index 000000000..e35f64b51 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext4-mballoc-preallocate.patch @@ -0,0 +1,26 @@ +From: Jan Kara +Subject: Fix assertion failure in mballoc code +References: bnc#480749 +Patch-mainline: 2.6.28 + +Backport of ext4 changes made a mistake and we enabled preallocation also for +non-regular files. This is not expected by the mballoc code and so we +eventually hit an assertion failure. Disable preallocation for non-regular +files as mainline does. + +Signed-off-by: Jan Kara + +diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/ext4/inode.c linux-2.6.27-SLE11_BRANCH-1-ext4_mballoc_fix/fs/ext4/inode.c +--- linux-2.6.27-SLE11_BRANCH/fs/ext4/inode.c 2009-03-10 16:07:41.000000000 +0100 ++++ linux-2.6.27-SLE11_BRANCH-1-ext4_mballoc_fix/fs/ext4/inode.c 2009-03-10 16:09:05.000000000 +0100 +@@ -600,7 +600,9 @@ static int ext4_alloc_blocks(handle_t *h + ar.goal = goal; + ar.len = target; + ar.logical = iblock; +- ar.flags = EXT4_MB_HINT_DATA; ++ if (S_ISREG(inode->i_mode)) ++ /* preallocate only for regular files */ ++ ar.flags = EXT4_MB_HINT_DATA; + + current_block = ext4_mb_new_blocks(handle, &ar, err); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ext4-use-a-fake-block-number-for-delayed-new-buffer_head b/src/patches/suse-2.6.27.31/patches.fixes/ext4-use-a-fake-block-number-for-delayed-new-buffer_head new file mode 100644 index 000000000..1bb306990 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ext4-use-a-fake-block-number-for-delayed-new-buffer_head @@ -0,0 +1,43 @@ +From: Aneesh Kumar K.V +Date: Tue, 12 May 2009 18:40:37 +0000 (-0400) +Subject: ext4: Use a fake block number for delayed new buffer_head +Patch-mainline: 2.6.30-rc6 +Git-commit: 33b9817e2ae097c7b8d256e3510ac6c54fc6d9d0 +References: bnc#503161 + +ext4: Use a fake block number for delayed new buffer_head + +Use a very large unsigned number (~0xffff) as as the fake block number +for the delayed new buffer. The VFS should never try to write out this +number, but if it does, this will make it obvious. + +Signed-off-by: Aneesh Kumar K.V +Signed-off-by: "Theodore Ts'o" +Acked-by: Jeff Mahoney +--- + + fs/ext4/inode.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2190,6 +2190,10 @@ static int ext4_da_get_block_prep(struct + struct buffer_head *bh_result, int create) + { + int ret = 0; ++ sector_t invalid_block = ~((sector_t) 0xffff); ++ ++ if (invalid_block < ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es)) ++ invalid_block = ~0; + + BUG_ON(create == 0); + BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize); +@@ -2211,7 +2215,7 @@ static int ext4_da_get_block_prep(struct + /* not enough space to reserve */ + return ret; + +- map_bh(bh_result, inode->i_sb, 0); ++ map_bh(bh_result, inode->i_sb, invalid_block); + set_buffer_new(bh_result); + set_buffer_delay(bh_result); + } else if (ret > 0) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/fc_transport-devloss-callback-restore b/src/patches/suse-2.6.27.31/patches.fixes/fc_transport-devloss-callback-restore new file mode 100644 index 000000000..b32c7ed65 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/fc_transport-devloss-callback-restore @@ -0,0 +1,93 @@ +Subject: FC devloss callback not called when devloss timer fires +From: James Smart +References: bnc#463289 + +When a SCSI target goes away for more than devloss timer the LLDD is not being +called for dev_loss_tmo_callbk in the FC transport code. + +The correct fix is to call dev_loss_tmo_callbk() at the tail end of +fc_timeout_deleted_rport() - but it has to be synchronized with the completion +of fc_starget_delete() that is pushed to the work queue just prior to the +routine exiting. + +Signed-off-by: James Smart +Signed-off-by: Hannes Reinecke + + --- + +drivers/scsi/scsi_transport_fc.c | 22 ++++++++++++++++++++-- +include/scsi/scsi_transport_fc.h | 1 + + 2 files changed, 21 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/scsi_transport_fc.c 2008-12-19 13:50:10.000000000 -0500 ++++ b/drivers/scsi/scsi_transport_fc.c 2008-12-19 13:50:06.000000000 -0500 +@@ -2407,8 +2407,12 @@ fc_rport_final_delete(struct work_struct + /* + * Notify the driver that the rport is now dead. The LLDD will + * also guarantee that any communication to the rport is terminated ++ * ++ * Avoid this call if we already called it when we preserved the ++ * rport for the binding. + */ +- if (i->f->dev_loss_tmo_callbk) ++ if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && ++ (i->f->dev_loss_tmo_callbk)) + i->f->dev_loss_tmo_callbk(rport); + + transport_remove_device(dev); +@@ -2647,7 +2651,8 @@ fc_remote_port_add(struct Scsi_Host *sho + spin_lock_irqsave(shost->host_lock, flags); + + rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | +- FC_RPORT_DEVLOSS_PENDING); ++ FC_RPORT_DEVLOSS_PENDING | ++ FC_RPORT_DEVLOSS_CALLBK_DONE); + + /* if target, initiate a scan */ + if (rport->scsi_target_id != -1) { +@@ -2944,6 +2949,7 @@ fc_timeout_deleted_rport(struct work_str + struct fc_rport *rport = + container_of(work, struct fc_rport, dev_loss_work.work); + struct Scsi_Host *shost = rport_to_shost(rport); ++ struct fc_internal *i = to_fc_internal(shost->transportt); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); + unsigned long flags; + +@@ -3030,6 +3036,8 @@ fc_timeout_deleted_rport(struct work_str + break; + } + ++ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; ++ + /* + * As this only occurs if the remote port (scsi target) + * went away and didn't come back - we'll remove +@@ -3039,8 +3047,18 @@ fc_timeout_deleted_rport(struct work_str + + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); ++ ++ /* ++ * Notify the driver that the rport is now dead. The LLDD will ++ * also guarantee that any communication to the rport is terminated ++ * ++ * Note: we set the CALLBK_DONE flag above to correspond ++ */ ++ if (i->f->dev_loss_tmo_callbk) ++ i->f->dev_loss_tmo_callbk(rport); + } + ++ + /** + * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target. + * @work: rport to terminate io on. +--- a/include/scsi/scsi_transport_fc.h 2008-12-19 11:20:30.000000000 -0500 ++++ b/include/scsi/scsi_transport_fc.h 2008-12-19 11:21:24.000000000 -0500 +@@ -358,6 +358,7 @@ struct fc_rport { /* aka fc_starget_attr + #define FC_RPORT_DEVLOSS_PENDING 0x01 + #define FC_RPORT_SCAN_PENDING 0x02 + #define FC_RPORT_FAST_FAIL_TIMEDOUT 0x04 ++#define FC_RPORT_DEVLOSS_CALLBK_DONE 0x08 + + #define dev_to_rport(d) \ + container_of(d, struct fc_rport, dev) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/fix-device-number-in-blktrace.patch b/src/patches/suse-2.6.27.31/patches.fixes/fix-device-number-in-blktrace.patch new file mode 100644 index 000000000..e6196970b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/fix-device-number-in-blktrace.patch @@ -0,0 +1,49 @@ +From: Martin Peschke +Subject: [Patch] sg: fix device number in blktrace data +Date: 2009-01-30 14:46:23 +References: bnc#473537 + + Description: blktrace: scsi generic devices have no device number set + Symptom: Start btrace on a SCSI generic device like in the sample output: + [root@t6315030 ~]# lsscsi -g | grep "sda " + [0:0:10:1075855393]disk IBM 2107900 1.50 /dev/sda /dev/sg0 + [root@t6315030 ~]# ls -la /dev/sda /dev/sg0 + brw-rw---- 1 root disk 8, 0 2009-02-03 08:04 /dev/sda + crw-r----- 1 root disk 21, 0 2009-02-03 08:04 /dev/sg0 + [root@t6315030 ~]# btrace /dev/sg0 | head + 8,0 0 1 0.000000000 7700 A R 6742 + 8 <- (8,1) 6680 + 0,0 0 2 0.000000235 7700 Q R 6742 + 8 [ls] + 0,0 0 3 0.000006860 7700 G R 6742 + 8 [ls] + 0,0 0 4 0.000010250 7700 P N [ls] + 0,0 0 5 0.000013172 7700 I R 6742 + 8 [ls] + 0,0 0 6 0.000017266 7700 U N [ls] 1 + 0,0 0 7 0.000023078 7700 D R 6742 + 8 [ls] + 0,0 1 2 0.000446668 0 C R 6742 + 8 [0] + 8,0 1 3 0.000624106 7700 A R 9699406 + 8 <- (8,1) + 0,0 1 4 0.000624403 7700 Q R 9699406 + 8 [ls] + Note that in the first column, the device number for the named + device (8:0) is reported correctly, while the device number for + the scsi generic device is reported as 0:0 instead of 21:0. + Problem: The device number for the scsi generic device is not correctly + set during initialization of blktrace. + Solution: Initialize with the correct device number, see + s390-sles11-fix-device-number-in-blktrace.patch + +Acked-by: Jan Blunck +--- + drivers/scsi/sg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/drivers/scsi/sg.c +=================================================================== +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1097,7 +1097,7 @@ sg_ioctl(struct inode *inode, struct fil + case BLKTRACESETUP: + return blk_trace_setup(sdp->device->request_queue, + sdp->disk->disk_name, +- sdp->device->sdev_gendev.devt, ++ MKDEV(SCSI_GENERIC_MAJOR, sdp->index), + (char *)arg); + case BLKTRACESTART: + return blk_trace_startstop(sdp->device->request_queue, 1); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/fix-nf_conntrack_slp b/src/patches/suse-2.6.27.31/patches.fixes/fix-nf_conntrack_slp new file mode 100644 index 000000000..4f6f280ea --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/fix-nf_conntrack_slp @@ -0,0 +1,62 @@ +From: Ludwig Nussel +Subject: make nf_conntrack_slp actually work +References: bnc#470963 + +Acked-by: Jeff Mahoney +--- + + nf_conntrack_slp.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/net/netfilter/nf_conntrack_slp.c ++++ b/net/netfilter/nf_conntrack_slp.c +@@ -47,15 +47,15 @@ static int help(struct sk_buff *skb, uns + struct nf_conn *ct, enum ip_conntrack_info ctinfo) + { + struct nf_conntrack_expect *exp; +- struct iphdr *iph = ip_hdr(skb); + struct rtable *rt = skb->rtable; + struct in_device *in_dev; + __be32 mask = 0; ++ __be32 src = 0; + + /* we're only interested in locally generated packets */ + if (skb->sk == NULL) + goto out; +- if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST)) ++ if (rt == NULL || !(rt->rt_flags & (RTCF_MULTICAST|RTCF_BROADCAST))) + goto out; + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) + goto out; +@@ -64,15 +64,18 @@ static int help(struct sk_buff *skb, uns + in_dev = __in_dev_get_rcu(rt->u.dst.dev); + if (in_dev != NULL) { + for_primary_ifa(in_dev) { +- if (ifa->ifa_broadcast == iph->daddr) { +- mask = ifa->ifa_mask; +- break; +- } ++ /* this is a hack as slp uses multicast we can't match ++ * the destination address to some broadcast address. So ++ * just take the first one. Better would be to install ++ * expectations for all addresses */ ++ mask = ifa->ifa_mask; ++ src = ifa->ifa_broadcast; ++ break; + } endfor_ifa(in_dev); + } + rcu_read_unlock(); + +- if (mask == 0) ++ if (mask == 0 || src == 0) + goto out; + + exp = nf_ct_expect_alloc(ct); +@@ -80,6 +83,7 @@ static int help(struct sk_buff *skb, uns + goto out; + + exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ exp->tuple.src.u3.ip = src; + exp->tuple.src.u.udp.port = htons(SLP_PORT); + + exp->mask.src.u3.ip = mask; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/fix-nr_uninterruptible-accounting-of-frozen-tasks b/src/patches/suse-2.6.27.31/patches.fixes/fix-nr_uninterruptible-accounting-of-frozen-tasks new file mode 100644 index 000000000..a9a49da40 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/fix-nr_uninterruptible-accounting-of-frozen-tasks @@ -0,0 +1,73 @@ +From: Thomas Gleixner +To: LKML +Cc: Andrew Morton , Rafael Wysocki , Ingo Molnar , Peter Zijlstra , Nathan Lynch , Nigel Cunningham , , containers@lists.linux-foundation.org, linux-pm@lists.linux-foundation.org, Matt Helsley +Subject: [patch 2/2] sched: fix nr_uninterruptible accounting of frozen tasks really +References: bnc#529660 + +commit e3c8ca8336 (sched: do not count frozen tasks toward load) broke +the nr_uninterruptible accounting on freeze/thaw. On freeze the task +is excluded from accounting with a check for (task->flags & +PF_FROZEN), but that flag is cleared before the task is thawed. So +while we prevent that the freezing task with state +TASK_UNINTERRUPTIBLE is accounted to nr_uninterruptible we decrement +nr_uninterruptible on thaw. + +Use a separate flag which is handled by the freezing task itself. Set +it before calling the scheduler with TASK_UNINTERRUPTIBLE state and +clear it after we return from frozen state. + +Signed-off-by: Thomas Gleixner +Cc: Nathan Lynch +Cc: Andrew Morton +Cc: Nigel Cunningham +Cc: +Cc: containers@lists.linux-foundation.org +Cc: linux-pm@lists.linux-foundation.org +Cc: Matt Helsley +Acked-by: Jeff Mahoney +--- + include/linux/sched.h | 3 ++- + kernel/freezer.c | 7 +++++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -203,7 +203,7 @@ extern unsigned long long time_sync_thre + ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0) + #define task_contributes_to_load(task) \ + ((task->state & TASK_UNINTERRUPTIBLE) != 0 && \ +- (task->flags & PF_FROZEN) == 0) ++ (task->flags & PF_FREEZING) == 0) + + #define __set_task_state(tsk, state_value) \ + do { (tsk)->state = (state_value); } while (0) +@@ -1507,6 +1507,7 @@ extern cputime_t task_gtime(struct task_ + #define PF_MEMALLOC 0x00000800 /* Allocating memory */ + #define PF_FLUSHER 0x00001000 /* responsible for disk writeback */ + #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ ++#define PF_FREEZING 0x00004000 /* freeze in progress. do not account to load */ + #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ + #define PF_FROZEN 0x00010000 /* frozen for system suspend */ + #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ +--- a/kernel/freezer.c ++++ b/kernel/freezer.c +@@ -44,12 +44,19 @@ void refrigerator(void) + recalc_sigpending(); /* We sent fake signal, clean it up */ + spin_unlock_irq(¤t->sighand->siglock); + ++ /* prevent accounting of that task to load */ ++ current->flags |= PF_FREEZING; ++ + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (!frozen(current)) + break; + schedule(); + } ++ ++ /* Remove the accounting blocker */ ++ current->flags &= ~PF_FREEZING; ++ + pr_debug("%s left refrigerator\n", current->comm); + __set_current_state(save); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/fujisu_laptop_fix_section_mismatch.patch b/src/patches/suse-2.6.27.31/patches.fixes/fujisu_laptop_fix_section_mismatch.patch new file mode 100644 index 000000000..a16a6cc1f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/fujisu_laptop_fix_section_mismatch.patch @@ -0,0 +1,22 @@ +From: Thomas Renninger +Subject: Fix section mismatch in fujitsu_laptop driver +Patch-Mainline: not yet +References: none + +--- + drivers/misc/fujitsu-laptop.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.26/drivers/misc/fujitsu-laptop.c +=================================================================== +--- linux-2.6.26.orig/drivers/misc/fujitsu-laptop.c ++++ linux-2.6.26/drivers/misc/fujitsu-laptop.c +@@ -455,7 +455,7 @@ static int dmi_check_cb_s6410(const stru + return 0; + } + +-static struct dmi_system_id __initdata fujitsu_dmi_table[] = { ++static struct dmi_system_id fujitsu_dmi_table[] = { + { + .ident = "Fujitsu Siemens", + .matches = { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/grab-swap-token-oops b/src/patches/suse-2.6.27.31/patches.fixes/grab-swap-token-oops new file mode 100644 index 000000000..fdc3b38e2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/grab-swap-token-oops @@ -0,0 +1,29 @@ +From: Dean Roe +Subject: Prevent NULL pointer deref in grab_swap_token +References: 159260 + +grab_swap_token() assumes that the current process has an mm struct, +which is not true for kernel threads invoking get_user_pages(). Since +this should be extremely rare, just return from grab_swap_token() +without doing anything. + +Signed-off-by: Dean Roe +Acked-by: mason@suse.de +Acked-by: okir@suse.de + + + mm/thrash.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/mm/thrash.c ++++ b/mm/thrash.c +@@ -31,6 +31,9 @@ void grab_swap_token(void) + int current_interval; + + global_faults++; ++ if (current->mm == NULL) ++ return; ++ + + current_interval = global_faults - current->mm->faultstamp; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/hid-rdesc-quirk-for-sony-vaio-VGX-TP1E.patch b/src/patches/suse-2.6.27.31/patches.fixes/hid-rdesc-quirk-for-sony-vaio-VGX-TP1E.patch new file mode 100644 index 000000000..5dd821b71 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/hid-rdesc-quirk-for-sony-vaio-VGX-TP1E.patch @@ -0,0 +1,75 @@ +From: Jiri Kosina +Subject: HID: Fix Sony Vaio VGX report descriptor +References: bnc#437758 +Patch-mainline: queued in subsystem tree, planned for 2.6.28 + +Sony Vaio VGX has wrongly mouse pointer declared as constant non-data +variable, which make HID code to completely ignore all the Pointer +usages. + +Fix the report descriptor before it enters the parses to contain correct +data. + +Signed-off-by: Jiri Kosina + +--- + drivers/hid/usbhid/hid-quirks.c | 16 ++++++++++++++++ + include/linux/hid.h | 1 + + 2 files changed, 17 insertions(+) + +--- a/drivers/hid/usbhid/hid-quirks.c ++++ b/drivers/hid/usbhid/hid-quirks.c +@@ -383,6 +383,7 @@ + #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 + + #define USB_VENDOR_ID_SONY 0x054c ++#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b + #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 + + #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 +@@ -761,6 +762,8 @@ static const struct hid_rdesc_blacklist + + { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP }, + ++ { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE, HID_QUIRK_RDESC_SONY_VAIO_VGX }, ++ + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, + +@@ -1133,6 +1136,16 @@ static void usbhid_fixup_button_consumer + } + } + ++/* Sony Vaio VGX has wrongly mouse pointer declared as constant */ ++static void usbhid_fixup_sony_vaio_vgx(unsigned char *rdesc, int rsize) ++{ ++ if (rsize >= 56 && rdesc[54] == 0x81 ++ && rdesc[55] == 0x07) { ++ printk(KERN_INFO "Fixing up Sony Vaio VGX report descriptor\n"); ++ rdesc[55] = 0x06; ++ } ++} ++ + /* + * Microsoft Wireless Desktop Receiver (Model 1028) has + * 'Usage Min/Max' where it ought to have 'Physical Min/Max' +@@ -1175,6 +1188,9 @@ static void __usbhid_fixup_report_descri + + if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP) + usbhid_fixup_sunplus_wdesktop(rdesc, rsize); ++ ++ if (quirks & HID_QUIRK_RDESC_SONY_VAIO_VGX) ++ usbhid_fixup_sony_vaio_vgx(rdesc, rsize); + } + + /** +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -298,6 +298,7 @@ struct hid_item { + #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 + #define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080 + #define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100 ++#define HID_QUIRK_RDESC_SONY_VAIO_VGX 0x00000200 + + /* + * This is the global environment of the parser. This information is diff --git a/src/patches/suse-2.6.27.31/patches.fixes/hpet-fix-for-LS21-boot-hang b/src/patches/suse-2.6.27.31/patches.fixes/hpet-fix-for-LS21-boot-hang new file mode 100644 index 000000000..5f9ca5921 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/hpet-fix-for-LS21-boot-hang @@ -0,0 +1,56 @@ +From: john stultz +Date: Fri, 13 Feb 2009 02:48:53 +0000 (-0800) +Subject: x86, hpet: fix for LS21 + HPET = boot hang +Patch-mainline: 2.6.29-rc6 +Git-commit: b13e24644c138d0ddbc451403c30a96b09bfd556 +References: bnc#476877 + +x86, hpet: fix for LS21 + HPET = boot hang + +Between 2.6.23 and 2.6.24-rc1 a change was made that broke IBM LS21 +systems that had the HPET enabled in the BIOS, resulting in boot hangs +for x86_64. + +Specifically commit b8ce33590687888ebb900d09557b8807c4539022, which +merges the i386 and x86_64 HPET code. + +Prior to this commit, when we setup the HPET timers in x86_64, we did +the following: + + hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | + HPET_TN_32BIT, HPET_T0_CFG); + +However after the i386/x86_64 HPET merge, we do the following: + + cfg = hpet_readl(HPET_Tn_CFG(timer)); + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | + HPET_TN_SETVAL | HPET_TN_32BIT; + hpet_writel(cfg, HPET_Tn_CFG(timer)); + +However on LS21s with HPET enabled in the BIOS, the HPET_T0_CFG register +boots with Level triggered interrupts (HPET_TN_LEVEL) enabled. This +causes the periodic interrupt to be not so periodic, and that results in +the boot time hang I reported earlier in the delay calibration. + +My fix: Always disable HPET_TN_LEVEL when setting up periodic mode. + +Signed-off-by: John Stultz +Signed-off-by: Ingo Molnar +Acked-by: Jeff Mahoney +--- + +--- + arch/x86/kernel/hpet.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/x86/kernel/hpet.c ++++ b/arch/x86/kernel/hpet.c +@@ -304,6 +304,8 @@ static void hpet_legacy_set_mode(enum cl + now = hpet_read_value(HPET_COUNTER); + cmp = now + (unsigned long) delta; + cfg = hpet_readl(HPET_T0_CFG); ++ /* Make sure we use edge triggered interrupts */ ++ cfg &= ~HPET_TN_LEVEL; + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | + HPET_TN_SETVAL | + (hpet_legacy_use_64_bits ? 0 : HPET_TN_32BIT); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/hpilo-open-close-fix b/src/patches/suse-2.6.27.31/patches.fixes/hpilo-open-close-fix new file mode 100644 index 000000000..acba546b3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/hpilo-open-close-fix @@ -0,0 +1,71 @@ +From: David Altobelli +Subject: [PATCH] hpilo open/close fix +References: bnc#466517 + +Fix to hpilo module, patch against 2.6.28. +The device can take a while to respond to an open/close request, so increase +the time kernel will wait for response (1 ms to 10ms). +Also, properly clean up a channel on a failed open, by calling the +channel close routine. Just freeing the memory isn't sufficient, the device +needs to be informed that the channel is no longer open, and the device +memory cleared of references to freed dma buffer. + +Please CC me on any replies. + +Signed-off-by: David Altobelli +Acked-by: Jeff Mahoney +--- + + drivers/misc/hpilo.c | 8 ++++---- + drivers/misc/hpilo.h | 2 ++ + 2 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/misc/hpilo.c ++++ b/drivers/misc/hpilo.c +@@ -207,7 +207,7 @@ static void ilo_ccb_close(struct pci_dev + &device_ccb->recv_ctrl); + + /* give iLO some time to process stop request */ +- for (retries = 1000; retries > 0; retries--) { ++ for (retries = MAX_WAIT; retries > 0; retries--) { + doorbell_set(driver_ccb); + udelay(1); + if (!(ioread32(&device_ccb->send_ctrl) & (1 << CTRL_BITPOS_A)) +@@ -309,7 +309,7 @@ static int ilo_ccb_open(struct ilo_hwinf + doorbell_clr(driver_ccb); + + /* make sure iLO is really handling requests */ +- for (i = 1000; i > 0; i--) { ++ for (i = MAX_WAIT; i > 0; i--) { + if (ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, NULL, NULL)) + break; + udelay(1); +@@ -326,7 +326,7 @@ static int ilo_ccb_open(struct ilo_hwinf + + return 0; + free: +- pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa); ++ ilo_ccb_close(pdev, data); + out: + return error; + } +@@ -759,7 +759,7 @@ static void __exit ilo_exit(void) + class_destroy(ilo_class); + } + +-MODULE_VERSION("0.05"); ++MODULE_VERSION("0.06"); + MODULE_ALIAS(ILO_NAME); + MODULE_DESCRIPTION(ILO_NAME); + MODULE_AUTHOR("David Altobelli "); +--- a/drivers/misc/hpilo.h ++++ b/drivers/misc/hpilo.h +@@ -19,6 +19,8 @@ + #define MAX_ILO_DEV 1 + /* max number of files */ + #define MAX_OPEN (MAX_CCB * MAX_ILO_DEV) ++/* spin counter for open/close delay */ ++#define MAX_WAIT 10000 + + /* + * Per device, used to track global memory allocations. diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ia64-configure-HAVE_UNSTABLE_SCHED_CLOCK-for-SGI_SN.patch b/src/patches/suse-2.6.27.31/patches.fixes/ia64-configure-HAVE_UNSTABLE_SCHED_CLOCK-for-SGI_SN.patch new file mode 100644 index 000000000..66c17fabc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ia64-configure-HAVE_UNSTABLE_SCHED_CLOCK-for-SGI_SN.patch @@ -0,0 +1,43 @@ +Date: Tue, 6 Jan 2009 10:27:41 -0600 +From: Dimitri Sivanich +To: linux-ia64@vger.kernel.org, Tony Luck , + Greg KH +Cc: linux-kernel@vger.kernel.org, + Peter Zijlstra , + Gregory Haskins , Nick Piggin , + Tony Luck , Robin Holt +Subject: configure HAVE_UNSTABLE_SCHED_CLOCK for SGI_SN systems + +Turn on CONFIG_HAVE_UNSTABLE_SCHED_CLOCK for SGI_SN. + +SGI Altix has unsynchronized itc clocks. This results in rq->clock +occasionally being set to a time in the past by a remote cpu. + +Note that it is possible that this problem may exist for other ia64 +machines as well, based on the following comment for sched_clock() in +arch/ia64/kernel/head.S: + + * Return a CPU-local timestamp in nano-seconds. This timestamp is + * NOT synchronized across CPUs its return value must never be + * compared against the values returned on another CPU. The usage in + * kernel/sched.c ensures that. + + +Signed-off-by: Dimitri Sivanich +Signed-off-by: Gregory Haskins + +--- + + arch/ia64/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/ia64/Kconfig ++++ b/arch/ia64/Kconfig +@@ -504,6 +504,7 @@ config IA64_MC_ERR_INJECT + + config SGI_SN + def_bool y if (IA64_SGI_SN2 || IA64_GENERIC) ++ select HAVE_UNSTABLE_SCHED_CLOCK + + config IA64_ESI + bool "ESI (Extensible SAL Interface) support" diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ib-ipath-fix-hang-on-module-unload b/src/patches/suse-2.6.27.31/patches.fixes/ib-ipath-fix-hang-on-module-unload new file mode 100644 index 000000000..f688e1a45 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ib-ipath-fix-hang-on-module-unload @@ -0,0 +1,41 @@ +From: Yannick Cote +Date: Tue, 30 Sep 2008 04:24:04 +0000 (-0700) +Subject: IB/ipath: Fix hang on module unload +Patch-mainline: 2.6.28-rc1 +Git-commit: e441d6342890838bfc6d64ca2f0964aca08ae2a2 +References: bnc#495068 + +IB/ipath: Fix hang on module unload + +Handle the case where posting a send is requested when the link is +down. This fixes . + +Signed-off-by: Yannick Cote +Signed-off-by: Roland Dreier +Acked-by: Jeff Mahoney +--- + + drivers/infiniband/hw/ipath/ipath_verbs.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c +index b766e40..eabc424 100644 +--- a/drivers/infiniband/hw/ipath/ipath_verbs.c ++++ b/drivers/infiniband/hw/ipath/ipath_verbs.c +@@ -340,9 +340,16 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr) + int acc; + int ret; + unsigned long flags; ++ struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd; + + spin_lock_irqsave(&qp->s_lock, flags); + ++ if (qp->ibqp.qp_type != IB_QPT_SMI && ++ !(dd->ipath_flags & IPATH_LINKACTIVE)) { ++ ret = -ENETDOWN; ++ goto bail; ++ } ++ + /* Check that state is OK to post send. */ + if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) + goto bail_inval; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ieee1394-sbp2_long_sysfs_ieee1394_id.patch b/src/patches/suse-2.6.27.31/patches.fixes/ieee1394-sbp2_long_sysfs_ieee1394_id.patch new file mode 100644 index 000000000..e363f5e2d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ieee1394-sbp2_long_sysfs_ieee1394_id.patch @@ -0,0 +1,26 @@ +From: unknown@suse.de +Subject: some unknown ieee1394 patch + +make the long format the default because its also the default in the +new firewire stack. +Maybe it simplifies migration for new 10.3 installs to 11.0 or later. +Maybe it is bad for existing 10.3 and earlier installs. + +modprobe -v sbp2 sbp2_long_sysfs_ieee1394_id=0 to get the old short name +modprobe -v sbp2 sbp2_long_sysfs_ieee1394_id=1 to get the new long name + +--- + drivers/ieee1394/sbp2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/ieee1394/sbp2.c ++++ b/drivers/ieee1394/sbp2.c +@@ -225,7 +225,7 @@ MODULE_PARM_DESC(workarounds, "Work arou + * independent of the implementation of the ieee1394 nodemgr, the longer format + * is recommended for future use. + */ +-static int sbp2_long_sysfs_ieee1394_id; ++static int sbp2_long_sysfs_ieee1394_id = 1; + module_param_named(long_ieee1394_id, sbp2_long_sysfs_ieee1394_id, bool, 0644); + MODULE_PARM_DESC(long_ieee1394_id, "8+3+2 bytes format of ieee1394_id in sysfs " + "(default = backwards-compatible = N, SAM-conforming = Y)"); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/initialize-dev-power-entry b/src/patches/suse-2.6.27.31/patches.fixes/initialize-dev-power-entry new file mode 100644 index 000000000..d0541baff --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/initialize-dev-power-entry @@ -0,0 +1,24 @@ +From: Jeff Mahoney +Subject: pm: initialize &dev->power.entry +References: bnc#514022 + + dev->power.entry is uninitialized, which can lead to Oopses if the device + is removed early. + +Signed-off-by: Jeff Mahoney +--- + drivers/base/power/power.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/base/power/power.h ++++ b/drivers/base/power/power.h +@@ -1,6 +1,9 @@ + static inline void device_pm_init(struct device *dev) + { + dev->power.status = DPM_ON; ++#ifdef CONFIG_PM_SLEEP ++ INIT_LIST_HEAD(&dev->power.entry); ++#endif + } + + #ifdef CONFIG_PM_SLEEP diff --git a/src/patches/suse-2.6.27.31/patches.fixes/input-add-acer-aspire-5710-to-nomux.patch b/src/patches/suse-2.6.27.31/patches.fixes/input-add-acer-aspire-5710-to-nomux.patch new file mode 100644 index 000000000..01aca70dd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/input-add-acer-aspire-5710-to-nomux.patch @@ -0,0 +1,30 @@ +From: Jiri Kosina +Subject: Input: Add Acer Aspire 5710 to nomux blacklist +References: bnc#404881 +Patch-mainline: submitted + +Acer Aspire needs to be added to nomux blacklist, otherwise the touchpad +misbehaves. + +Signed-off-by: Jiri Kosina + +--- + drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/input/serio/i8042-x86ia64io.h ++++ b/drivers/input/serio/i8042-x86ia64io.h +@@ -324,6 +324,13 @@ static struct dmi_system_id __initdata i + }, + }, + { ++ .ident = "Acer Aspire 5710", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"), ++ }, ++ }, ++ { + .ident = "Gericom Bellagio", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), diff --git a/src/patches/suse-2.6.27.31/patches.fixes/input-add-nomux-dell-vostro-1510.patch b/src/patches/suse-2.6.27.31/patches.fixes/input-add-nomux-dell-vostro-1510.patch new file mode 100644 index 000000000..06e44ae1e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/input-add-nomux-dell-vostro-1510.patch @@ -0,0 +1,32 @@ +From: Jiri Kosina +Subject: Input: add Dell Vostro 1510 to nomux list +References: bnc#404881 +Patch-mainline: yes + +Dell Vostro needs 'nomux' quirk, otherwise the touchpad misbehaves. + +Reported-by: Robert Kiwanuka +Signed-off-by: Jiri Kosina + +--- + +--- + drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/input/serio/i8042-x86ia64io.h ++++ b/drivers/input/serio/i8042-x86ia64io.h +@@ -358,6 +358,13 @@ static struct dmi_system_id __initdata i + DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), + }, + }, ++ { ++ .ident = "Dell Vostro 1510", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), ++ }, ++ }, + { } + }; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ipw2200-send-noassoc.patch b/src/patches/suse-2.6.27.31/patches.fixes/ipw2200-send-noassoc.patch new file mode 100644 index 000000000..891541fa7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ipw2200-send-noassoc.patch @@ -0,0 +1,30 @@ +From: Zhu Yi +Subject: ipw2200: fix oops in ipw_tx_skb +Patch-mainline: not yet +References: bnc#397390 + +Fixes Oops in ipw2200:ipw_tx_skb when pinging through +a WPA enterprise connection. + +Signed-off-by: Zhu Yi +Tested-by: Frank Seidel +Signed-off-by: Ffrank Seidel + +--- + drivers/net/wireless/ipw2200.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/net/wireless/ipw2200.c ++++ b/drivers/net/wireless/ipw2200.c +@@ -10206,6 +10206,11 @@ static int ipw_tx_skb(struct ipw_priv *p + u16 remaining_bytes; + int fc; + ++ if (!(priv->status & STATUS_ASSOCIATED)) { ++ IPW_DEBUG_TX("Tx attempt while not associated.\n"); ++ goto drop; ++ } ++ + hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwl3945-fix-crash-on-rmmod.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwl3945-fix-crash-on-rmmod.patch new file mode 100644 index 000000000..b9b4712e8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwl3945-fix-crash-on-rmmod.patch @@ -0,0 +1,41 @@ +From: Kolekar, Abhijeet +Subject: iwl3945: release resources before shutting down +Patch-mainline: 2.6.30 +Reference: bnc#495816 + +Release resource before shutting down and notify upper stack. + +Signed-off-by: Abhijeet Kolekar +Signed-off-by: Zhu Yi +Signed-off-by: John W. Linville +Acked-by: Helmut Schaa +Acked-by: Jiri Benc + +diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c +index 38b1f90..722fc44 100644 +--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c ++++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c +@@ -8105,7 +8105,12 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) + + set_bit(STATUS_EXIT_PENDING, &priv->status); + +- iwl3945_down(priv); ++ if (priv->mac80211_registered) { ++ ieee80211_unregister_hw(priv->hw); ++ priv->mac80211_registered = 0; ++ } else { ++ iwl3945_down(priv); ++ } + + /* make sure we flush any pending irq or + * tasklet for the driver +@@ -8130,9 +8130,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) + iwl3945_unset_hw_setting(priv); + iwl3945_clear_stations_table(priv); + +- if (priv->mac80211_registered) +- ieee80211_unregister_hw(priv->hw); +- + /*netif_stop_queue(dev); */ + flush_workqueue(priv->workqueue); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwl3945-fix-rfkill.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwl3945-fix-rfkill.patch new file mode 100644 index 000000000..d2bb450c1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwl3945-fix-rfkill.patch @@ -0,0 +1,216 @@ +From: Helmut Schaa +Subject: iwl3945: report killswitch changes even if the interface is down +Patch-mainline: wireless-testing (2.6.30?) +References: bnc#446013 + +Signed-off-by: Helmut Schaa +Acked-by: Samuel Ortiz +Signed-off-by: John W. Linville +Acked-by: Helmut Schaa +--- + +--- + drivers/net/wireless/iwlwifi/iwl-3945.h | 1 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 83 ++++++++++++++++++---------- + 2 files changed, 57 insertions(+), 27 deletions(-) + +--- linux-2.6.27.orig/drivers/net/wireless/iwlwifi/iwl-3945.h ++++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-3945.h +@@ -893,6 +893,7 @@ struct iwl3945_priv { + struct delayed_work alive_start; + struct delayed_work activity_timer; + struct delayed_work thermal_periodic; ++ struct delayed_work rfkill_poll; + struct delayed_work gather_stats; + struct delayed_work scan_check; + struct delayed_work post_associate; +--- linux-2.6.27.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c ++++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl3945-base.c +@@ -6023,7 +6023,8 @@ static void iwl3945_bg_rf_kill(struct wo + IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); +- if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) ++ if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && ++ test_bit(STATUS_ALIVE, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + +@@ -6040,6 +6041,25 @@ static void iwl3945_bg_rf_kill(struct wo + iwl3945_rfkill_set_hw_state(priv); + } + ++static void iwl3945_rfkill_poll(struct work_struct *data) ++{ ++ struct iwl3945_priv *priv = ++ container_of(data, struct iwl3945_priv, rfkill_poll.work); ++ unsigned long status = priv->status; ++ ++ if (iwl3945_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) ++ clear_bit(STATUS_RF_KILL_HW, &priv->status); ++ else ++ set_bit(STATUS_RF_KILL_HW, &priv->status); ++ ++ if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) ++ queue_work(priv->workqueue, &priv->rf_kill); ++ ++ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, ++ round_jiffies_relative(2 * HZ)); ++ ++} ++ + static void iwl3945_bg_set_monitor(struct work_struct *work) + { + struct iwl3945_priv *priv = container_of(work, +@@ -6481,20 +6501,6 @@ static int iwl3945_mac_start(struct ieee + + IWL_DEBUG_MAC80211("enter\n"); + +- if (pci_enable_device(priv->pci_dev)) { +- IWL_ERROR("Fail to pci_enable_device\n"); +- return -ENODEV; +- } +- pci_restore_state(priv->pci_dev); +- pci_enable_msi(priv->pci_dev); +- +- ret = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED, +- DRV_NAME, priv); +- if (ret) { +- IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); +- goto out_disable_msi; +- } +- + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + +@@ -6539,15 +6545,15 @@ static int iwl3945_mac_start(struct ieee + } + } + ++ /* ucode is running and will send rfkill notifications, ++ * no need to poll the killswitch state anymore */ ++ cancel_delayed_work(&priv->rfkill_poll); ++ + priv->is_open = 1; + IWL_DEBUG_MAC80211("leave\n"); + return 0; + + out_release_irq: +- free_irq(priv->pci_dev->irq, priv); +-out_disable_msi: +- pci_disable_msi(priv->pci_dev); +- pci_disable_device(priv->pci_dev); + priv->is_open = 0; + IWL_DEBUG_MAC80211("leave - failed\n"); + return ret; +@@ -6579,10 +6585,10 @@ static void iwl3945_mac_stop(struct ieee + iwl3945_down(priv); + + flush_workqueue(priv->workqueue); +- free_irq(priv->pci_dev->irq, priv); +- pci_disable_msi(priv->pci_dev); +- pci_save_state(priv->pci_dev); +- pci_disable_device(priv->pci_dev); ++ ++ /* start polling the killswitch state again */ ++ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, ++ round_jiffies_relative(2 * HZ)); + + IWL_DEBUG_MAC80211("leave\n"); + } +@@ -7776,6 +7782,7 @@ static void iwl3945_setup_deferred_work( + INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); ++ INIT_DELAYED_WORK(&priv->rfkill_poll, iwl3945_rfkill_poll); + + iwl3945_hw_setup_deferred_work(priv); + +@@ -7988,6 +7995,15 @@ static int iwl3945_pci_probe(struct pci_ + iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + ++ pci_enable_msi(priv->pci_dev); ++ ++ err = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED, ++ DRV_NAME, priv); ++ if (err) { ++ IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); ++ goto out_disable_msi; ++ } ++ + err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); +@@ -8037,14 +8053,16 @@ static int iwl3945_pci_probe(struct pci_ + + priv->hw->conf.beacon_int = 100; + priv->mac80211_registered = 1; +- pci_save_state(pdev); +- pci_disable_device(pdev); + + err = iwl3945_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); + ++ /* Start monitoring the killswitch */ ++ queue_delayed_work(priv->workqueue, &priv->rfkill_poll, ++ 2 * HZ); ++ + return 0; + + out_free_geos: +@@ -8055,10 +8073,13 @@ static int iwl3945_pci_probe(struct pci_ + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + + out_release_irq: ++ free_irq(priv->pci_dev->irq, priv); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + iwl3945_unset_hw_setting(priv); +- ++ out_disable_msi: ++ pci_disable_msi(priv->pci_dev); ++ + out_iounmap: + pci_iounmap(pdev, priv->hw_base); + out_pci_release_regions: +@@ -8098,6 +8119,8 @@ static void __devexit iwl3945_pci_remove + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + + iwl3945_rfkill_unregister(priv); ++ cancel_delayed_work(&priv->rfkill_poll); ++ + iwl3945_dealloc_ucode_pci(priv); + + if (priv->rxq.bd) +@@ -8119,6 +8142,9 @@ static void __devexit iwl3945_pci_remove + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + ++ free_irq(pdev->irq, priv); ++ pci_disable_msi(pdev); ++ + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +@@ -8144,7 +8170,8 @@ static int iwl3945_pci_suspend(struct pc + iwl3945_mac_stop(priv->hw); + priv->is_open = 1; + } +- ++ pci_save_state(pdev); ++ pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +@@ -8155,6 +8182,8 @@ static int iwl3945_pci_resume(struct pci + struct iwl3945_priv *priv = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); ++ pci_enable_device(pdev); ++ pci_restore_state(pdev); + + if (priv->is_open) + iwl3945_mac_start(priv->hw); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-error-path.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-error-path.patch new file mode 100644 index 000000000..5d9067303 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-error-path.patch @@ -0,0 +1,40 @@ +From: Helmut Schaa +Subject: iwlagn: clean up error path in iwl_pci_probe +Patch-mainline: not yet +References: bnc#474043 + +This avoids triggering a BUG_ON in pci_disable_msi in the error path. +Furthermore remove the first call to pci_disable_device as it is already +called at out_pci_disable_device. + +Both issues were introduced in the patch "iwlagn: fix hw-rfkill while +the interface is down". + +Signed-off-by: Helmut Schaa +Acked-by: Helmut Schaa +Acked-by: Jiri Benc +--- +diff -urNp linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn.c linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn.c +--- linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn.c 2009-02-13 14:10:57.000000000 +0100 ++++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn.c 2009-02-13 14:09:10.000000000 +0100 +@@ -4307,7 +4307,7 @@ static int iwl4965_pci_probe(struct pci_ + err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); +- goto out_uninit_drv; ++ goto out_free_irq; + } + + iwl_setup_deferred_work(priv); +@@ -4352,9 +4352,10 @@ static int iwl4965_pci_probe(struct pci_ + + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); ++ out_free_irq: ++ free_irq(priv->pci_dev->irq, priv); + out_disable_msi: + pci_disable_msi(priv->pci_dev); +- pci_disable_device(priv->pci_dev); + out_uninit_drv: + iwl_uninit_drv(priv); + out_free_eeprom: diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-rfkill.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-rfkill.patch new file mode 100644 index 000000000..f1f2ac816 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-rfkill.patch @@ -0,0 +1,263 @@ +From: Helmut Schaa +Date: Mon Jan 19 13:10:07 2009 +0100 +Subject: iwlagn: fix hw-rfkill while the interface is down +Patch-mainline: wireless-testing (2.6.30?) +References: bnc#446158 + +iwlagn: fix hw-rfkill while the interface is down + +Currently iwlagn is not able to report hw-killswitch events while the +interface is down. This has implications on user space tools (like +NetworkManager) relying on rfkill notifications to bring the interface +up once the wireless gets enabled through a hw killswitch. + +Thus, enable the device already in iwl_pci_probe instead of iwl_up +and enable interrups while the interface is down in order to get +notified about killswitch state changes. The firmware loading is still +done in iwl_up. + +Signed-off-by: Helmut Schaa +Acked-by: Reinette Chatre +Signed-off-by: John W. Linville +Acked-by: Helmut Schaa +Acked-by: Jiri Benc + +--- + drivers/net/wireless/iwlwifi/iwl-agn.c | 111 +++++++++++++++++---------------- + 1 file changed, 58 insertions(+), 53 deletions(-) + +--- linux-2.6.27.orig/drivers/net/wireless/iwlwifi/iwl-agn.c ++++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn.c +@@ -1643,11 +1643,17 @@ static void iwl4965_irq_tasklet(struct i + hw_rf_kill ? "disable radio":"enable radio"); + + /* driver only loads ucode once setting the interface up. +- * the driver as well won't allow loading if RFKILL is set +- * therefore no need to restart the driver from this handler +- */ +- if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) +- clear_bit(STATUS_RF_KILL_HW, &priv->status); ++ * the driver allows loading the ucode even if the radio ++ * is killed. Hence update the killswitch state here. The ++ * rfkill handler will care about restarting if needed. ++ */ ++ if (!test_bit(STATUS_ALIVE, &priv->status)) { ++ if (hw_rf_kill) ++ set_bit(STATUS_RF_KILL_HW, &priv->status); ++ else ++ clear_bit(STATUS_RF_KILL_HW, &priv->status); ++ queue_work(priv->workqueue, &priv->rf_kill); ++ } + + handled |= CSR_INT_BIT_RF_KILL; + } +@@ -2349,7 +2355,8 @@ static void iwl4965_bg_rf_kill(struct wo + IWL_DEBUG(IWL_DL_RF_KILL, + "HW and/or SW RF Kill no longer active, restarting " + "device\n"); +- if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) ++ if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && ++ test_bit(STATUS_ALIVE, &priv->status)) + queue_work(priv->workqueue, &priv->restart); + } else { + /* make sure mac80211 stop sending Tx frame */ +@@ -2593,31 +2600,9 @@ static int iwl4965_mac_start(struct ieee + { + struct iwl_priv *priv = hw->priv; + int ret; +- u16 pci_cmd; + + IWL_DEBUG_MAC80211("enter\n"); + +- if (pci_enable_device(priv->pci_dev)) { +- IWL_ERROR("Fail to pci_enable_device\n"); +- return -ENODEV; +- } +- pci_restore_state(priv->pci_dev); +- pci_enable_msi(priv->pci_dev); +- +- /* enable interrupts if needed: hw bug w/a */ +- pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); +- if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { +- pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; +- pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); +- } +- +- ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, +- DRV_NAME, priv); +- if (ret) { +- IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); +- goto out_disable_msi; +- } +- + /* we should be verifying the device is ready to be opened */ + mutex_lock(&priv->mutex); + +@@ -2630,7 +2615,7 @@ static int iwl4965_mac_start(struct ieee + if (ret) { + IWL_ERROR("Could not read microcode: %d\n", ret); + mutex_unlock(&priv->mutex); +- goto out_release_irq; ++ return ret; + } + } + +@@ -2641,7 +2626,7 @@ static int iwl4965_mac_start(struct ieee + iwl_rfkill_set_hw_state(priv); + + if (ret) +- goto out_release_irq; ++ return ret; + + if (iwl_is_rfkill(priv)) + goto out; +@@ -2660,8 +2645,7 @@ static int iwl4965_mac_start(struct ieee + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_ERROR("START_ALIVE timeout after %dms.\n", + jiffies_to_msecs(UCODE_READY_TIMEOUT)); +- ret = -ETIMEDOUT; +- goto out_release_irq; ++ return -ETIMEDOUT; + } + } + +@@ -2669,15 +2653,6 @@ out: + priv->is_open = 1; + IWL_DEBUG_MAC80211("leave\n"); + return 0; +- +-out_release_irq: +- free_irq(priv->pci_dev->irq, priv); +-out_disable_msi: +- pci_disable_msi(priv->pci_dev); +- pci_disable_device(priv->pci_dev); +- priv->is_open = 0; +- IWL_DEBUG_MAC80211("leave - failed\n"); +- return ret; + } + + static void iwl4965_mac_stop(struct ieee80211_hw *hw) +@@ -2705,10 +2680,10 @@ static void iwl4965_mac_stop(struct ieee + iwl4965_down(priv); + + flush_workqueue(priv->workqueue); +- free_irq(priv->pci_dev->irq, priv); +- pci_disable_msi(priv->pci_dev); +- pci_save_state(priv->pci_dev); +- pci_disable_device(priv->pci_dev); ++ ++ /* enable interrupts again in order to receive rfkill changes */ ++ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); ++ iwl4965_enable_interrupts(priv); + + IWL_DEBUG_MAC80211("leave\n"); + } +@@ -4176,6 +4151,7 @@ static int iwl4965_pci_probe(struct pci_ + struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); + unsigned long flags; + DECLARE_MAC_BUF(mac); ++ u16 pci_cmd; + + /************************ + * 1. Allocating HW data +@@ -4320,26 +4296,36 @@ static int iwl4965_pci_probe(struct pci_ + iwl4965_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + ++ pci_enable_msi(priv->pci_dev); ++ ++ err = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, ++ DRV_NAME, priv); ++ if (err) { ++ IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); ++ goto out_disable_msi; ++ } + err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); + if (err) { + IWL_ERROR("failed to create sysfs device attributes\n"); + goto out_uninit_drv; + } + +- + iwl_setup_deferred_work(priv); + iwl_setup_rx_handlers(priv); + +- /******************** +- * 9. Conclude +- ********************/ +- pci_save_state(pdev); +- pci_disable_device(pdev); +- + /********************************** +- * 10. Setup and register mac80211 ++ * 9. Setup and register mac80211 + **********************************/ + ++ /* enable interrupts if needed: hw bug w/a */ ++ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); ++ if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { ++ pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; ++ pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); ++ } ++ ++ iwl4965_enable_interrupts(priv); ++ + err = iwl_setup_mac(priv); + if (err) + goto out_remove_sysfs; +@@ -4348,15 +4334,27 @@ static int iwl4965_pci_probe(struct pci_ + if (err) + IWL_ERROR("failed to create debugfs files\n"); + ++ /* If platform's RF_KILL switch is NOT set to KILL */ ++ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) ++ clear_bit(STATUS_RF_KILL_HW, &priv->status); ++ else ++ set_bit(STATUS_RF_KILL_HW, &priv->status); ++ + err = iwl_rfkill_init(priv); + if (err) + IWL_ERROR("Unable to initialize RFKILL system. " + "Ignoring error: %d\n", err); ++ else ++ iwl_rfkill_set_hw_state(priv); ++ + iwl_power_initialize(priv); + return 0; + + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); ++ out_disable_msi: ++ pci_disable_msi(priv->pci_dev); ++ pci_disable_device(priv->pci_dev); + out_uninit_drv: + iwl_uninit_drv(priv); + out_free_eeprom: +@@ -4428,6 +4426,8 @@ static void __devexit iwl4965_pci_remove + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; + ++ free_irq(priv->pci_dev->irq, priv); ++ pci_disable_msi(priv->pci_dev); + pci_iounmap(pdev, priv->hw_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +@@ -4453,6 +4453,8 @@ static int iwl4965_pci_suspend(struct pc + priv->is_open = 1; + } + ++ pci_save_state(pdev); ++ pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +@@ -4463,6 +4465,9 @@ static int iwl4965_pci_resume(struct pci + struct iwl_priv *priv = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); ++ pci_enable_device(pdev); ++ pci_restore_state(pdev); ++ iwl4965_enable_interrupts(priv); + + if (priv->is_open) + iwl4965_mac_start(priv->hw); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-dont-clean-static-wep-keys.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-dont-clean-static-wep-keys.patch new file mode 100644 index 000000000..41bda992f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-dont-clean-static-wep-keys.patch @@ -0,0 +1,44 @@ +From: Mohamed Abbas +Date: Wed, 11 Mar 2009 11:17:59 -0700 +Subject: [PATCH] iwlagn: fix warning when set WEP key +Patch-mainline: 2.6.29? (wireless-testing: 31078197aa3ab891b1260627c0497e07060222c8) +References: bnc#487247 + +iwl_clear_station_table will be called every time rxon called. +In this function ucode_key_table is set to 0 even though a static +WEP security is set. This will cause in many warning and might be +an issue if dynamic WEP is set. This patch make sure we keep track +of all existing static WEP when this function is called. + +Signed-off-by: Mohamed Abbas +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Acked-by: Jiri Benc + +--- + drivers/net/wireless/iwlwifi/iwl-core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/wireless/iwlwifi/iwl-core.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/wireless/iwlwifi/iwl-core.c +@@ -279,6 +279,7 @@ EXPORT_SYMBOL(iwl_hw_nic_init); + void iwl_clear_stations_table(struct iwl_priv *priv) + { + unsigned long flags; ++ int i; + + spin_lock_irqsave(&priv->sta_lock, flags); + +@@ -293,6 +294,12 @@ void iwl_clear_stations_table(struct iwl + /* clean ucode key table bit map */ + priv->ucode_key_table = 0; + ++ /* keep track of static keys */ ++ for (i = 0; i < WEP_KEYS_MAX ; i++) { ++ if (priv->wep_keys[i].key_size) ++ test_and_set_bit(i, &priv->ucode_key_table); ++ } ++ + spin_unlock_irqrestore(&priv->sta_lock, flags); + } + EXPORT_SYMBOL(iwl_clear_stations_table); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-fix-rs_get_rate-oops.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-fix-rs_get_rate-oops.patch new file mode 100644 index 000000000..34879cc16 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-fix-rs_get_rate-oops.patch @@ -0,0 +1,119 @@ +From: Abbas, Mohamed +Subject: iwlwifi: fix rs_get_rate WARN_ON() +Patch-mainline: not yet +References: bnc#456002 + +In ieee80211_sta structure there is u64 supp_rates[IEEE80211_NUM_BANDS] +this is filled with all support rate from assoc_resp. If we associate +with G-band AP only supp_rates of G-band will be set the other band +supp_rates will be set to 0. If the user type this command +this will cause mac80211 to set to new channel, mac80211 +does not disassociate in setting new channel, so the active +band is now A-band. then in handling the new essid mac80211 will +kick in the assoc steps which involve sending disassociation frame. +in this mac80211 will WARN_ON sta->supp_rates[A_BAND] == 0. + +This fixes: +http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1822 +http://www.kerneloops.org/searchweek.php?search=rs_get_rate + +Signed-off-by: mohamed abbas +Signed-off-by: Reinette Chatre +Acked-by: Helmut Schaa +Acked-by: Jiri Benc + +--- + drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 11 ++++++++--- + drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 14 ++++++++++++-- + 2 files changed, 20 insertions(+), 5 deletions(-) + +--- linux-2.6.27.orig/drivers/net/wireless/iwlwifi/iwl-3945-rs.c ++++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +@@ -652,7 +652,8 @@ static void rs_get_rate(void *priv_rate, + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct sta_info *sta; +- u16 fc, rate_mask; ++ u16 fc; ++ u16 rate_mask = 0; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; + DECLARE_MAC_BUF(mac); + +@@ -661,6 +662,8 @@ static void rs_get_rate(void *priv_rate, + rcu_read_lock(); + + sta = sta_info_get(local, hdr->addr1); ++ if (sta) ++ rate_mask = sta->supp_rates[sband->band]; + + /* Send management frames and broadcast/multicast data using lowest + * rate. */ +@@ -669,12 +672,14 @@ static void rs_get_rate(void *priv_rate, + is_multicast_ether_addr(hdr->addr1) || + !sta || !sta->rate_ctrl_priv) { + IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); +- sel->rate_idx = rate_lowest_index(local, sband, sta); ++ if (!rate_mask) ++ sel->rate_idx = rate_lowest_index(local, sband, NULL); ++ else ++ sel->rate_idx = rate_lowest_index(local, sband, sta); + rcu_read_unlock(); + return; + } + +- rate_mask = sta->supp_rates[sband->band]; + index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); + + if (sband->band == IEEE80211_BAND_5GHZ) +--- linux-2.6.27.orig/drivers/net/wireless/iwlwifi/iwl-agn-rs.c ++++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +@@ -795,9 +795,12 @@ static void rs_tx_status(void *priv_rate + u8 active_index = 0; + __le16 fc = hdr->frame_control; + s32 tpt = 0; ++ struct ieee80211_supported_band *sband; + + IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); + ++ sband = local->hw.wiphy->bands[info->band]; ++ + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + return; + +@@ -965,7 +968,8 @@ static void rs_tx_status(void *priv_rate + } + + /* See if there's a better rate or modulation mode to try. */ +- rs_rate_scale_perform(priv, dev, hdr, sta); ++ if(sta && sta->supp_rates[sband->band]) ++ rs_rate_scale_perform(priv, dev, hdr, sta); + out: + rcu_read_unlock(); + return; +@@ -2090,19 +2094,25 @@ static void rs_get_rate(void *priv_rate, + __le16 fc; + struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl_lq_sta *lq_sta; ++ u64 mask_bit = 0; + + IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); + + rcu_read_lock(); + + sta = sta_info_get(local, hdr->addr1); ++ if (sta) ++ mask_bit = sta->supp_rates[sband->band]; + + /* Send management frames and broadcast/multicast data using lowest + * rate. */ + fc = hdr->frame_control; + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta || !sta->rate_ctrl_priv) { +- sel->rate_idx = rate_lowest_index(local, sband, sta); ++ if (!mask_bit) ++ sel->rate_idx = rate_lowest_index(local, sband, NULL); ++ else ++ sel->rate_idx = rate_lowest_index(local, sband, sta); + goto out; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-fix-updating-key-flags.patch b/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-fix-updating-key-flags.patch new file mode 100644 index 000000000..defba7559 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/iwlwifi-fix-updating-key-flags.patch @@ -0,0 +1,90 @@ +From 299f5462087f3bc2141e6bc83ba7e2b15d8a07d2 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre +Date: Thu, 30 Apr 2009 13:56:31 -0700 +Subject: [PATCH] iwlwifi: update key flags at time key is set +Patch-mainline: 2.6.30-rc6 +References: bnc#487247 + +We need to be symmetrical in what is done when key is set and cleared. +This is important wrt the key flags as they are used during key +clearing and if they are not set when the key is set the key cannot be +cleared completely. + +This addresses the many occurences of the WARN found in +iwl_set_tkip_dynamic_key_info() and tracked in +http://www.kerneloops.org/searchweek.php?search=iwl_set_dynamic_key + +If calling iwl_set_tkip_dynamic_key_info()/iwl_remove_dynamic_key() +pair a few times in a row will cause that we run out of key space. +This is because the index stored in the key flags is used by +iwl_remove_dynamic_key() to decide if it should remove the key. +Unfortunately the key flags, and hence the key index is currently only +set at the time the key is written to the device (in +iwl_update_tkip_key()) and _not_ in iwl_set_tkip_dynamic_key_info(). +Fix this by setting flags in iwl_set_tkip_dynamic_key_info(). + +Signed-off-by: Reinette Chatre +Signed-off-by: John W. Linville +Acked-by: Jiri Benc + +--- + drivers/net/wireless/iwlwifi/iwl-agn.c | 10 ---------- + drivers/net/wireless/iwlwifi/iwl-sta.c | 11 +++++++++++ + 2 files changed, 11 insertions(+), 10 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/wireless/iwlwifi/iwl-agn.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/wireless/iwlwifi/iwl-agn.c +@@ -3227,9 +3227,7 @@ static void iwl4965_mac_update_tkip_key( + struct iwl_priv *priv = hw->priv; + u8 sta_id = IWL_INVALID_STATION; + unsigned long flags; +- __le16 key_flags = 0; + int i; +- DECLARE_MAC_BUF(mac); + + IWL_DEBUG_MAC80211("enter\n"); + +@@ -3246,16 +3244,8 @@ static void iwl4965_mac_update_tkip_key( + return; + } + +- key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); +- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); +- key_flags &= ~STA_KEY_FLG_INVALID; +- +- if (sta_id == priv->hw_params.bcast_sta_id) +- key_flags |= STA_KEY_MULTICAST_MSK; +- + spin_lock_irqsave(&priv->sta_lock, flags); + +- priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/wireless/iwlwifi/iwl-sta.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/net/wireless/iwlwifi/iwl-sta.c +@@ -688,6 +688,14 @@ static int iwl_set_tkip_dynamic_key_info + { + unsigned long flags; + int ret = 0; ++ __le16 key_flags = 0; ++ ++ key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); ++ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); ++ key_flags &= ~STA_KEY_FLG_INVALID; ++ ++ if (sta_id == priv->hw_params.bcast_sta_id) ++ key_flags |= STA_KEY_MULTICAST_MSK; + + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; +@@ -707,6 +715,9 @@ static int iwl_set_tkip_dynamic_key_info + WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, + "no space for new kew"); + ++ priv->stations[sta_id].sta.key.key_flags = key_flags; ++ ++ + /* This copy is acutally not needed: we get the key with each TX */ + memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/kdb-Commited_AS-fix b/src/patches/suse-2.6.27.31/patches.fixes/kdb-Commited_AS-fix new file mode 100644 index 000000000..c94049d3d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/kdb-Commited_AS-fix @@ -0,0 +1,23 @@ +From: Jeff Mahoney +Subject: [PATCH] kdb: account for vm_committed_space -> vm_committed_as change +References: bnc#505831 + + patches.fixes/mm-fix-Commited_AS-underflow-on-large-NR_CPUS changed + vm_committed_space to a percpu. This patch accounts for that in the kdb code. + +Signed-off-by: Jeff Mahoney +--- + fs/proc/proc_misc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/proc/proc_misc.c ++++ b/fs/proc/proc_misc.c +@@ -258,7 +258,7 @@ kdb_meminfo_read_proc(void) + #define K(x) ((x) << (PAGE_SHIFT - 10)) + si_meminfo(&i); + kdb_si_swapinfo(&i); +- committed = atomic_read(&vm_committed_space); ++ committed = percpu_counter_read_positive(&vm_committed_as); + allowed = ((totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100) + total_swap_pages; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/kdb-bb_all-fixes b/src/patches/suse-2.6.27.31/patches.fixes/kdb-bb_all-fixes new file mode 100644 index 000000000..6e4d18fda --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/kdb-bb_all-fixes @@ -0,0 +1,171 @@ +From: Martin Hicks +Subject: KDB Backtrace Fixes +References: bnc#501114 + + This patch fixes a failure in bb_all. + +Acked-by: Jeff Mahoney +--- + + arch/x86/kdb/kdba_bt.c | 61 ++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 51 insertions(+), 10 deletions(-) +--- a/arch/x86/kdb/kdba_bt.c ++++ b/arch/x86/kdb/kdba_bt.c +@@ -416,34 +416,29 @@ static struct bb_name_state bb_special_c + NS_MEM("ia32_ptregs_common", partial_pt_regs_plus_1, 0), + NS_MEM("ia32_sysret", partial_pt_regs, 0), + NS_MEM("int_careful", partial_pt_regs, 0), ++ NS_MEM("ia32_badarg", partial_pt_regs, 0), + NS_MEM("int_restore_rest", full_pt_regs, 0), + NS_MEM("int_signal", full_pt_regs, 0), + NS_MEM("int_very_careful", partial_pt_regs, 0), +- NS_MEM("int_with_check", partial_pt_regs, 0), + #ifdef CONFIG_TRACE_IRQFLAGS + NS_MEM("paranoid_exit0", full_pt_regs, 0), + #endif /* CONFIG_TRACE_IRQFLAGS */ + NS_MEM("paranoid_exit1", full_pt_regs, 0), + NS_MEM("ptregscall_common", partial_pt_regs_plus_1, 0), +- NS_MEM("restore_norax", partial_pt_regs, 0), +- NS_MEM("restore", partial_pt_regs, 0), + NS_MEM("ret_from_intr", partial_pt_regs_plus_2, 0), + NS_MEM("stub32_clone", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_execve", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_fork", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_iopl", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_rt_sigreturn", partial_pt_regs_plus_1, 0), +- NS_MEM("stub32_rt_sigsuspend", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_sigaltstack", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_sigreturn", partial_pt_regs_plus_1, 0), +- NS_MEM("stub32_sigsuspend", partial_pt_regs_plus_1, 0), + NS_MEM("stub32_vfork", partial_pt_regs_plus_1, 0), + NS_MEM("stub_clone", partial_pt_regs_plus_1, 0), + NS_MEM("stub_execve", partial_pt_regs_plus_1, 0), + NS_MEM("stub_fork", partial_pt_regs_plus_1, 0), + NS_MEM("stub_iopl", partial_pt_regs_plus_1, 0), + NS_MEM("stub_rt_sigreturn", partial_pt_regs_plus_1, 0), +- NS_MEM("stub_rt_sigsuspend", partial_pt_regs_plus_1, 0), + NS_MEM("stub_sigaltstack", partial_pt_regs_plus_1, 0), + NS_MEM("stub_vfork", partial_pt_regs_plus_1, 0), + +@@ -464,6 +459,17 @@ static struct bb_name_state bb_special_c + BB_SKIP(RAX) | BB_SKIP(RCX)), + NS_MEM("ia32_badsys", partial_pt_regs, 0), + ++#ifdef CONFIG_AUDITSYSCALL ++ NS_MEM_FROM("int_with_check", "sysexit_audit", partial_pt_regs, ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX)), ++ NS_MEM_FROM("int_with_check", "ia32_cstar_target", partial_pt_regs, ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++#endif ++ NS_MEM("int_with_check", no_memory, 0), ++ ++ + /* Various bits of code branch to int_ret_from_sys_call, with slightly + * different missing values in pt_regs. + */ +@@ -540,11 +546,11 @@ static struct bb_name_state bb_special_c + + NS_REG("bad_put_user", + all_regs, +- BB_SKIP(RAX) | BB_SKIP(RCX) | BB_SKIP(R8)), ++ BB_SKIP(RBX)), + + NS_REG("bad_get_user", + all_regs, +- BB_SKIP(RAX) | BB_SKIP(RCX) | BB_SKIP(R8)), ++ BB_SKIP(RAX) | BB_SKIP(RDX)), + + NS_REG("bad_to_user", + all_regs, +@@ -585,11 +591,17 @@ static const char *bb_spurious[] = { + "rff_action", + "rff_trace", + /* system_call */ ++ "system_call_after_swapgs", ++ "system_call_fastpath", + "ret_from_sys_call", + "sysret_check", + "sysret_careful", + "sysret_signal", + "badsys", ++#ifdef CONFIG_AUDITSYSCALL ++ "auditsys", ++ "sysret_audit", ++#endif + "tracesys", + "int_ret_from_sys_call", + "int_with_check", +@@ -635,11 +647,22 @@ static const char *bb_spurious[] = { + "bad_gs", + /* ia32_sysenter_target */ + "sysenter_do_call", ++ "sysenter_dispatch", ++ "sysexit_from_sys_call", ++#ifdef CONFIG_AUDITSYSCALL ++ "sysenter_auditsys", ++ "sysexit_audit", ++#endif + "sysenter_tracesys", + /* ia32_cstar_target */ + "cstar_do_call", ++ "cstar_dispatch", ++ "sysretl_from_sys_call", ++#ifdef CONFIG_AUDITSYSCALL ++ "cstar_auditsys", ++ "sysretl_audit", ++#endif + "cstar_tracesys", +- "ia32_badarg", + /* ia32_syscall */ + "ia32_do_syscall", + "ia32_sysret", +@@ -1805,6 +1828,7 @@ enum bb_operand_usage { + BBOU_RSRDWSWD, /* 15 */ + /* opcode specific entries */ + BBOU_ADD, ++ BBOU_AND, + BBOU_CALL, + BBOU_CBW, + BBOU_CMOV, +@@ -1896,7 +1920,7 @@ static const struct bb_opcode_usage + bb_opcode_usage_all[] = { + {3, BBOU_RSRDWD, "adc"}, + {3, BBOU_ADD, "add"}, +- {3, BBOU_RSRDWD, "and"}, ++ {3, BBOU_AND, "and"}, + {3, BBOU_RSWD, "bsf"}, + {3, BBOU_RSWD, "bsr"}, + {5, BBOU_RSWS, "bswap"}, +@@ -2952,6 +2976,12 @@ bb_sanity_check(int type) + (strcmp(bb_func_name, "ptregscall_common") == 0 || + strcmp(bb_func_name, "ia32_ptregs_common") == 0)))) + continue; ++ /* The put_user and save_paranoid functions are special. ++ * %rbx gets clobbered */ ++ if (expect == BBRG_RBX && ++ (strncmp(bb_func_name, "__put_user_", 11) == 0 || ++ strcmp(bb_func_name, "save_paranoid") == 0)) ++ continue; + kdb_printf("%s: Expected %s, got %s", + __FUNCTION__, + bbrg_name[expect], bbrg_name[actual]); +@@ -3445,6 +3475,17 @@ bb_usage(void) + } else { + usage = BBOU_RSRDWD; + } ++ break; ++ case BBOU_AND: ++ /* Special case when trying to round the stack pointer ++ * to achieve byte alignment ++ */ ++ if (dst->reg && dst->base_rc == BBRG_RSP && ++ src->immediate && strncmp(bb_func_name, "efi_call", 8) == 0) { ++ usage = BBOU_NOP; ++ } else { ++ usage = BBOU_RSRDWD; ++ } + break; + case BBOU_CALL: + /* Invalidate the scratch registers. Functions sync_regs and diff --git a/src/patches/suse-2.6.27.31/patches.fixes/kdb-fix-stack-overflow.patch b/src/patches/suse-2.6.27.31/patches.fixes/kdb-fix-stack-overflow.patch new file mode 100644 index 000000000..349ee87ba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/kdb-fix-stack-overflow.patch @@ -0,0 +1,176 @@ +From: Mike Travis +Subject: kdb: fix stack overflow for large NR_CPUS count +References: bnc#440361 + +V2: remove spinlock + +In auditing the 2.6.27 source I found a *big* problem in kdb. The stack in +kdb_bp will overflow with NR_CPUS=4096 ... the stack is 31744 bytes! + + ====== Stack (-l 500) + + 1 - x86_64_default_128 (NR_CPUS=128) + 2 - x86_64_default (NR_CPUS=4096) + + .1. .2. ..final.. + 1088 +31744 32832 +2917% kdb_bp + 0 +2632 2632 . smp_call_function_mask + 0 +2216 2216 . __build_sched_domains + 0 +1544 1544 . tick_handle_oneshot_broadcast + +The problem looks like the static array in kdb_bp (template): + + static int + kdb_bp(int argc, const char **argv) + { + ... + kdb_bp_t template = {0}; + +Which has a field sized by NR_CPUS: + + kdbhard_bp_t *bp_hard[NR_CPUS]; /* Hardware breakpoint structure */ + +When NR_CPUS=4096, the above struct will overflow the 16k stack. + +The fix I implemented is to move the template to static memory. This struct +does not need to be protected because KDB stops all the cpus and only accepts +console input from one cpu at a time. + +Some other minor tweaks to reduce stack size also implemented: + + kdb_cpu_callback: use set_cpus_allowed_ptr() to prevent passing cpumask_t + on the stack. + + kdb_per_cpu: use cpus_clear which prevents creating an empty cpumask_t + (CPU_MASK_NONE) on the stack. + + +For the next release, any arrays should be allocated using nr_cpu_ids. + +Based on linux-2.6.27. + +Signed-off-by: Mike Travis +Acked-by: Bernhard Walle + +--- + kdb/kdb_bp.c | 27 +++++++++++++++------------ + kdb/kdbmain.c | 12 ++++++------ + 2 files changed, 21 insertions(+), 18 deletions(-) + +--- linux-2.6.27.orig/kdb/kdb_bp.c ++++ linux-2.6.27/kdb/kdb_bp.c +@@ -285,7 +285,7 @@ kdb_bp(int argc, const char **argv) + char *symname = NULL; + long offset = 0ul; + int nextarg; +- kdb_bp_t template = {0}; ++ static kdb_bp_t kdb_bp_template; + + if (argc == 0) { + /* +@@ -300,21 +300,23 @@ kdb_bp(int argc, const char **argv) + return 0; + } + +- template.bp_global = ((strcmp(argv[0], "bpa") == 0) ++ memset(&kdb_bp_template, 0, sizeof(kdb_bp_template)); ++ ++ kdb_bp_template.bp_global = ((strcmp(argv[0], "bpa") == 0) + || (strcmp(argv[0], "bpha") == 0)); +- template.bp_forcehw = ((strcmp(argv[0], "bph") == 0) ++ kdb_bp_template.bp_forcehw = ((strcmp(argv[0], "bph") == 0) + || (strcmp(argv[0], "bpha") == 0)); + + /* Fix me: "bp" is treated as "bpa" to avoid system freeze. -jlan */ + if (strcmp(argv[0], "bp") == 0) +- template.bp_global = 1; ++ kdb_bp_template.bp_global = 1; + + nextarg = 1; +- diag = kdbgetaddrarg(argc, argv, &nextarg, &template.bp_addr, ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &kdb_bp_template.bp_addr, + &offset, &symname); + if (diag) + return diag; +- if (!template.bp_addr) ++ if (!kdb_bp_template.bp_addr) + return KDB_BADINT; + + /* +@@ -333,7 +335,7 @@ kdb_bp(int argc, const char **argv) + /* + * Handle architecture dependent parsing + */ +- diag = kdba_parsebp(argc, argv, &nextarg, &template); ++ diag = kdba_parsebp(argc, argv, &nextarg, &kdb_bp_template); + if (diag) { + return diag; + } +@@ -348,20 +350,21 @@ kdb_bp(int argc, const char **argv) + */ + for(i=0,bp_check=kdb_breakpoints; ibp_free && +- bp_check->bp_addr == template.bp_addr && ++ bp_check->bp_addr == kdb_bp_template.bp_addr && + (bp_check->bp_global || +- bp_check->bp_cpu == template.bp_cpu)) { +- kdb_printf("You already have a breakpoint at " kdb_bfd_vma_fmt0 "\n", template.bp_addr); ++ bp_check->bp_cpu == kdb_bp_template.bp_cpu)) { ++ kdb_printf("You already have a breakpoint at " ++ kdb_bfd_vma_fmt0 "\n", kdb_bp_template.bp_addr); + return KDB_DUPBPT; + } + } + +- template.bp_enabled = 1; ++ kdb_bp_template.bp_enabled = 1; + + /* + * Actually allocate the breakpoint found earlier + */ +- *bp = template; ++ *bp = kdb_bp_template; + bp->bp_free = 0; + + if (!bp->bp_global) { +--- linux-2.6.27.orig/kdb/kdbmain.c ++++ linux-2.6.27/kdb/kdbmain.c +@@ -3715,13 +3715,14 @@ kdb_per_cpu(int argc, const char **argv) + { + char buf[256], fmtstr[64]; + kdb_symtab_t symtab; +- cpumask_t suppress = CPU_MASK_NONE; ++ cpumask_t suppress; + int cpu, diag; + unsigned long addr, val, bytesperword = 0, whichcpu = ~0UL; + + if (argc < 1 || argc > 3) + return KDB_ARGCOUNT; + ++ cpus_clear(suppress); + snprintf(buf, sizeof(buf), "per_cpu__%s", argv[1]); + if (!kdbgetsymval(buf, &symtab)) { + kdb_printf("%s is not a per_cpu variable\n", argv[1]); +@@ -3779,7 +3780,7 @@ kdb_per_cpu(int argc, const char **argv) + if (cpus_weight(suppress) == 0) + return 0; + kdb_printf("Zero suppressed cpu(s):"); +- for (cpu = first_cpu(suppress); cpu < NR_CPUS; cpu = next_cpu(cpu, suppress)) { ++ for_each_cpu_mask(cpu, suppress) { + kdb_printf(" %d", cpu); + if (cpu == NR_CPUS-1 || next_cpu(cpu, suppress) != cpu + 1) + continue; +@@ -4234,10 +4235,9 @@ kdb_cpu_callback(struct notifier_block * + if (action == CPU_ONLINE) { + int cpu =(unsigned long)hcpu; + cpumask_t save_cpus_allowed = current->cpus_allowed; +- cpumask_t new_cpus_allowed = cpumask_of_cpu(cpu); +- set_cpus_allowed(current, new_cpus_allowed); +- kdb(KDB_REASON_CPU_UP, 0, NULL); /* do kdb setup on this cpu */ +- set_cpus_allowed(current, save_cpus_allowed); ++ set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); ++ kdb(KDB_REASON_CPU_UP, 0, NULL); /* do kdb setup on this cpu */ ++ set_cpus_allowed_ptr(current, &save_cpus_allowed); + } + return NOTIFY_OK; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/kvm-vmx-dont-allow-uninhibited-access-to-EFER-on-i386 b/src/patches/suse-2.6.27.31/patches.fixes/kvm-vmx-dont-allow-uninhibited-access-to-EFER-on-i386 new file mode 100644 index 000000000..943a1ba20 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/kvm-vmx-dont-allow-uninhibited-access-to-EFER-on-i386 @@ -0,0 +1,38 @@ +From: Avi Kivity +Date: Mon, 23 Mar 2009 22:13:44 +0200 +Subject: KVM: VMX: Don't allow uninhibited access to EFER on i386 +Git-commit: 16175a796d061833aacfbd9672235f2d2725df65 +Patch-mainline: 2.6.30-rc1 +References: bnc#492760 + +vmx_set_msr() does not allow i386 guests to touch EFER, but they can still +do so through the default: label in the switch. If they set EFER_LME, they +can oops the host. + +Fix by having EFER access through the normal channel (which will check for +EFER_LME) even on i386. + +Reported-and-tested-by: Benjamin Gilbert +Cc: stable@kernel.org +Signed-off-by: Avi Kivity +Acked-by: Jeff Mahoney +--- + + arch/x86/kvm/vmx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -898,11 +898,11 @@ static int vmx_set_msr(struct kvm_vcpu * + int ret = 0; + + switch (msr_index) { +-#ifdef CONFIG_X86_64 + case MSR_EFER: + vmx_load_host_state(vmx); + ret = kvm_set_msr_common(vcpu, msr_index, data); + break; ++#ifdef CONFIG_X86_64 + case MSR_FS_BASE: + vmcs_writel(GUEST_FS_BASE, data); + break; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-don-t-let-io-sit-in-queue-when-session-has-failed b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-don-t-let-io-sit-in-queue-when-session-has-failed new file mode 100644 index 000000000..68a5026de --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-don-t-let-io-sit-in-queue-when-session-has-failed @@ -0,0 +1,56 @@ +From: Mike Christie +Date: Wed, 13 May 2009 17:57:47 -0500 +X-Git: 301e0f7e4d78e956c58b66888e134dbdb44ea28e +Subject: libiscsi: don't let io sit in queue when session has failed + +If the session is failed, but we have not yet fully transitioned +to the recovery stage we were still queueuing IO. The idea is +that for some failures we can recvover at the command level +and still continue to execute other IO. Well, we never have +added the recovery within a command code, so queueing up IO here +just creates the possibility that it might time time out so +this just has us requeue the IO the scsi layer for now. + +Signed-off-by: Mike Christie +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/libiscsi.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -1242,13 +1242,7 @@ int iscsi_queuecommand(struct scsi_cmnd + goto fault; + } + +- /* +- * ISCSI_STATE_FAILED is a temp. state. The recovery +- * code will decide what is best to do with command queued +- * during this time +- */ +- if (session->state != ISCSI_STATE_LOGGED_IN && +- session->state != ISCSI_STATE_FAILED) { ++ if (session->state != ISCSI_STATE_LOGGED_IN) { + /* + * to handle the race between when we set the recovery state + * and block the session we requeue here (commands could +@@ -1256,12 +1250,15 @@ int iscsi_queuecommand(struct scsi_cmnd + * up because the block code is not locked) + */ + switch (session->state) { ++ case ISCSI_STATE_FAILED: + case ISCSI_STATE_IN_RECOVERY: + reason = FAILURE_SESSION_IN_RECOVERY; +- goto reject; ++ sc->result = DID_IMM_RETRY << 16; ++ break; + case ISCSI_STATE_LOGGING_OUT: + reason = FAILURE_SESSION_LOGGING_OUT; +- goto reject; ++ sc->result = DID_IMM_RETRY << 16; ++ break; + case ISCSI_STATE_RECOVERY_FAILED: + reason = FAILURE_SESSION_RECOVERY_TIMEOUT; + sc->result = DID_TRANSPORT_FAILFAST << 16; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-locking-in-eh_device_reset b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-locking-in-eh_device_reset new file mode 100644 index 000000000..033b6e79a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-locking-in-eh_device_reset @@ -0,0 +1,49 @@ +From: Mike Christie +Date: Wed Sep 24 11:46:15 2008 -0500 +Subject: fix locking in iscsi_eh_device_reset +X-Git: a343914831a8e29d89af3b26495ab1136a9e3153 +References: bnc#498369 + +We must be using the bh spin locking functions in +iscsi_eh_device_reset becuase the session lock interacts with +a thread and softirq. + +This patch also fixes up a bogus comment and check in fail_command, +because no one drops the lock (bnx2i did but it is not going +upstream yet and there were other refcount changes for that). + +Signed-off-by: Mike Christie +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/libiscsi.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -413,11 +413,6 @@ static void fail_command(struct iscsi_co + conn->session->queued_cmdsn--; + else + conn->session->tt->cleanup_task(conn, task); +- /* +- * Check if cleanup_task dropped the lock and the command completed, +- */ +- if (!task->sc) +- return; + + sc->result = err; + if (!scsi_bidi_cmnd(sc)) +@@ -1839,10 +1834,10 @@ int iscsi_eh_device_reset(struct scsi_cm + + iscsi_suspend_tx(conn); + +- spin_lock(&session->lock); ++ spin_lock_bh(&session->lock); + fail_all_commands(conn, sc->device->lun, DID_ERROR); + conn->tmf_state = TMF_INITIAL; +- spin_unlock(&session->lock); ++ spin_unlock_bh(&session->lock); + + iscsi_start_tx(conn); + goto done; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-nop-response-reply-and-session-cleanup.patch b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-nop-response-reply-and-session-cleanup.patch new file mode 100644 index 000000000..f49fb253a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-nop-response-reply-and-session-cleanup.patch @@ -0,0 +1,61 @@ +From: Mike Christie +Date: Tue, 28 Apr 2009 13:38:18 -0400 +Subject: libiscsi: fix nop response/reply and session cleanup race +References: bnc#499558 + +If we are responding to a nop from the target by sending our nop, +and the session is getting torn down, then iscsi_start_session_recovery +could set the conn stop bits while the recv path is sending the nop +response and we will hit the bug ons in __iscsi_conn_send_pdu. + +This has us check the state in __iscsi_conn_send_pdu and fail all +incoming mgmt IO if we are not logged in and if the pdu is not login +related. It also changes the ordering of the setting of conn stop state +bits so they are set after the session state is set (both are set under +the session lock). + +Acked-by: Jean Delvare +--- + drivers/scsi/libiscsi.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -502,6 +502,9 @@ __iscsi_conn_send_pdu(struct iscsi_conn + */ + task = conn->login_task; + else { ++ if (session->state != ISCSI_STATE_LOGGED_IN) ++ return NULL; ++ + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); + BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); + +@@ -2414,8 +2417,6 @@ static void iscsi_start_session_recovery + { + int old_stop_stage; + +- del_timer_sync(&conn->transport_timer); +- + mutex_lock(&session->eh_mutex); + spin_lock_bh(&session->lock); + if (conn->stop_stage == STOP_CONN_TERM) { +@@ -2433,13 +2434,17 @@ static void iscsi_start_session_recovery + session->state = ISCSI_STATE_TERMINATE; + else if (conn->stop_stage != STOP_CONN_RECOVER) + session->state = ISCSI_STATE_IN_RECOVERY; ++ spin_unlock_bh(&session->lock); + ++ del_timer_sync(&conn->transport_timer); ++ iscsi_suspend_tx(conn); ++ ++ spin_lock_bh(&session->lock); + old_stop_stage = conn->stop_stage; + conn->stop_stage = flag; + conn->c_stage = ISCSI_CONN_STOPPED; + spin_unlock_bh(&session->lock); + +- iscsi_suspend_tx(conn); + /* + * for connection level recovery we should not calculate + * header digest. conn->hdr_size used for optimization diff --git a/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-null-pointer-in-fail-all-commands b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-null-pointer-in-fail-all-commands new file mode 100644 index 000000000..45d9990c9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/libiscsi-fix-null-pointer-in-fail-all-commands @@ -0,0 +1,38 @@ +From: Mike Christie +Date: Thu Mar 5 14:46:07 2009 -0600 +X-Git: 728996829b3e2a3bbacb7390e6c040dd839cdf21 +Subject: libiscsi: fix possbile null ptr session command cleanup +References: bnc#498369 + +If the iscsi eh fires when the current task is a nop, then +the task->sc pointer is null. fail_all_commands could +then try to do task->sc->device and oops. We actually do +not need to access the curr task in this path, because +if it is a cmd task the fail_command call will handle +this and if it is mgmt task then the flush of the mgmt +queues will handle that. + +Signed-off-by: Mike Christie +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/libiscsi.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -1498,8 +1498,11 @@ static void fail_all_commands(struct isc + { + struct iscsi_task *task, *tmp; + +- if (conn->task && (conn->task->sc->device->lun == lun || lun == -1)) +- conn->task = NULL; ++ if (conn->task) { ++ if (lun == -1 || ++ (conn->task->sc && conn->task->sc->device->lun == lun)) ++ conn->task = NULL; ++ } + + /* flush pending */ + list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/mac80211-add-direct-probe.patch b/src/patches/suse-2.6.27.31/patches.fixes/mac80211-add-direct-probe.patch new file mode 100644 index 000000000..71dcdcb1c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/mac80211-add-direct-probe.patch @@ -0,0 +1,230 @@ +From: Ron Rindjunsky +Date: Sat, 9 Aug 2008 03:02:19 +0300 +Subject: [PATCH] mac80211: add direct probe before association +Patch-mainline: 2.6.28-rc1 +References: bnc#461889 + +This patch adds a direct probe request as first step in the association +flow if data we have is not up to date. Motivation of this step is to make +sure that the bss information we have is correct, since last scan could +have been done a while ago, and beacons do not fully answer this need as +there are potential differences between them and probe responses (e.g. +WMM parameter element) + +Signed-off-by: Ron Rindjunsky +Signed-off-by: Tomas Winkler +Signed-off-by: John W. Linville + +Modified not to break kABI: auth_tries is overriden to also mean +direct_probe_tries, last_probe_resp is moved to the end of the +ieee80211_sta_bss structure. + +Signed-off-by: Jiri Benc + +--- + net/mac80211/ieee80211_i.h | 10 +++++ + net/mac80211/mlme.c | 79 ++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 77 insertions(+), 12 deletions(-) + +--- linux-2.6.27.orig/net/mac80211/ieee80211_i.h ++++ linux-2.6.27/net/mac80211/ieee80211_i.h +@@ -117,6 +117,10 @@ struct ieee80211_sta_bss { + * otherwise, you probably don't want to use them. */ + int has_erp_value; + u8 erp_value; ++ ++#ifndef __GENKSYMS__ ++ unsigned long last_probe_resp; ++#endif + }; + + static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss) +@@ -310,6 +314,9 @@ struct ieee80211_if_sta { + IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, + IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED, + IEEE80211_MESH_UP ++#ifndef __GENKSYMS__ ++ , IEEE80211_DIRECT_PROBE ++#endif + } state; + size_t ssid_len; + u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; +@@ -363,6 +370,7 @@ struct ieee80211_if_sta { + #define IEEE80211_STA_REQ_SCAN 0 + #define IEEE80211_STA_REQ_AUTH 1 + #define IEEE80211_STA_REQ_RUN 2 ++#define IEEE80211_STA_REQ_DIRECT_PROBE 3 + + #define IEEE80211_AUTH_ALG_OPEN BIT(0) + #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) +--- linux-2.6.27.orig/net/mac80211/mlme.c ++++ linux-2.6.27/net/mac80211/mlme.c +@@ -658,6 +658,36 @@ static void ieee80211_send_auth(struct n + ieee80211_sta_tx(dev, skb, encrypt); + } + ++static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_if_sta *ifsta) ++{ ++ DECLARE_MAC_BUF(mac); ++ ++ ifsta->auth_tries++; /* used as direct_probe_tries */ ++ if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { ++ printk(KERN_DEBUG "%s: direct probe to AP %s timed out\n", ++ sdata->dev->name, print_mac(mac, ifsta->bssid)); ++ ifsta->state = IEEE80211_DISABLED; ++ return; ++ } ++ ++ printk(KERN_DEBUG "%s: direct probe to AP %s try %d\n", ++ sdata->dev->name, print_mac(mac, ifsta->bssid), ++ ifsta->auth_tries); ++ ++ ifsta->state = IEEE80211_DIRECT_PROBE; ++ ++ set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request); ++ ++ /* Direct probe is sent to broadcast address as some APs ++ * will not answer to direct packet in unassociated state. ++ */ ++ ieee80211_send_probe_req(sdata->dev, NULL, ++ ifsta->ssid, ifsta->ssid_len); ++ ++ mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); ++} ++ + + static void ieee80211_authenticate(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +@@ -1958,7 +1988,7 @@ static void ieee80211_rx_mgmt_deauth(str + if (ifsta->state == IEEE80211_AUTHENTICATE || + ifsta->state == IEEE80211_ASSOCIATE || + ifsta->state == IEEE80211_ASSOCIATED) { +- ifsta->state = IEEE80211_AUTHENTICATE; ++ ifsta->state = IEEE80211_DIRECT_PROBE; + mod_timer(&ifsta->timer, jiffies + + IEEE80211_RETRY_AUTH_INTERVAL); + } +@@ -2559,8 +2589,7 @@ static void ieee80211_rx_bss_info(struct + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status, +- struct ieee802_11_elems *elems, +- int beacon) ++ struct ieee802_11_elems *elems) + { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int freq, clen; +@@ -2569,6 +2598,7 @@ static void ieee80211_rx_bss_info(struct + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + u64 beacon_timestamp, rx_timestamp; + struct ieee80211_channel *channel; ++ bool beacon = ieee80211_is_beacon(mgmt->frame_control); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + +@@ -2728,15 +2758,14 @@ static void ieee80211_rx_bss_info(struct + bss->signal = rx_status->signal; + bss->noise = rx_status->noise; + bss->qual = rx_status->qual; +- if (!beacon && !bss->probe_resp) +- bss->probe_resp = true; +- ++ if (!beacon) ++ bss->last_probe_resp = jiffies; + /* + * In STA mode, the remaining parameters should not be overridden + * by beacons because they're not necessarily accurate there. + */ + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && +- bss->probe_resp && beacon) { ++ bss->last_probe_resp && beacon) { + ieee80211_rx_bss_put(local, bss); + return; + } +@@ -2891,6 +2920,8 @@ static void ieee80211_rx_mgmt_probe_resp + { + size_t baselen; + struct ieee802_11_elems elems; ++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct ieee80211_if_sta *ifsta = &sdata->u.sta; + + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; + if (baselen > len) +@@ -2899,7 +2930,17 @@ static void ieee80211_rx_mgmt_probe_resp + ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, + &elems); + +- ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0); ++ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems); ++ ++ /* direct probe may be part of the association flow */ ++ if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, ++ &ifsta->request)) { ++ printk(KERN_DEBUG "%s direct probe responded\n", ++ sdata->dev->name); ++ ifsta->auth_tries = 0; /* direct_probe_tries -> auth_tries */ ++ ieee80211_authenticate(dev, ifsta); ++ } ++ + } + + +@@ -2923,7 +2964,7 @@ static void ieee80211_rx_mgmt_beacon(str + + ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); + +- ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 1); ++ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems); + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) +@@ -3361,7 +3402,8 @@ void ieee80211_sta_work(struct work_stru + mesh_path_start_discovery(dev); + #endif + +- if (ifsta->state != IEEE80211_AUTHENTICATE && ++ if (ifsta->state != IEEE80211_DIRECT_PROBE && ++ ifsta->state != IEEE80211_AUTHENTICATE && + ifsta->state != IEEE80211_ASSOCIATE && + test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { + if (ifsta->scan_ssid_len) +@@ -3381,6 +3423,10 @@ void ieee80211_sta_work(struct work_stru + switch (ifsta->state) { + case IEEE80211_DISABLED: + break; ++ case IEEE80211_DIRECT_PROBE: ++ ieee80211_direct_probe(sdata, ifsta); ++ break; ++ + case IEEE80211_AUTHENTICATE: + ieee80211_authenticate(dev, ifsta); + break; +@@ -3541,8 +3587,18 @@ static int ieee80211_sta_config_auth(str + selected->ssid_len); + ieee80211_sta_set_bssid(dev, selected->bssid); + ieee80211_sta_def_wmm_params(dev, selected, 0); ++ ++ /* Send out direct probe if no probe resp was received or ++ * the one we have is outdated ++ */ ++ if (!selected->last_probe_resp || ++ time_after(jiffies, selected->last_probe_resp ++ + IEEE80211_SCAN_RESULT_EXPIRE)) ++ ifsta->state = IEEE80211_DIRECT_PROBE; ++ else ++ ifsta->state = IEEE80211_AUTHENTICATE; ++ + ieee80211_rx_bss_put(local, selected); +- ifsta->state = IEEE80211_AUTHENTICATE; + ieee80211_sta_reset_auth(dev, ifsta); + return 0; + } else { +@@ -3553,6 +3609,7 @@ static int ieee80211_sta_config_auth(str + ieee80211_sta_start_scan(dev, ifsta->ssid, + ifsta->ssid_len); + ifsta->state = IEEE80211_AUTHENTICATE; ++ ifsta->auth_tries = 0; /* direct_probe_tries -> auth_tries */ + set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); + } else + ifsta->state = IEEE80211_DISABLED; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/md-disable-recovery-on-faulty-degraded-array b/src/patches/suse-2.6.27.31/patches.fixes/md-disable-recovery-on-faulty-degraded-array new file mode 100644 index 000000000..774472d6c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/md-disable-recovery-on-faulty-degraded-array @@ -0,0 +1,117 @@ +From: NeilBrown +Subject: Disable recovery when degraded RAID1 array appears to be faulty. +Patch-mainline: no +References: bnc#447835 + + +If a raid1 has only one working drive and it has a sector which +gives an error on read, then an attempt to recover onto a spare will +fail, but as the single remaining drive is not removed from the +array, the recovery will be immediately re-attempted, resulting +in an infinite recovery loop. + +So detect this situation and don't retry recovery once an error +on the lone remaining drive is detected. + +Allow recovery to be retried once every time a spare is added +in case the problem wasn't actually a media error. + + +Signed-off-by: Neil Brown + +--- + drivers/md/md.c | 11 ++++++----- + drivers/md/raid1.c | 8 ++++++-- + include/linux/raid/md_k.h | 5 +++++ + 3 files changed, 17 insertions(+), 7 deletions(-) + +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -3071,7 +3071,7 @@ action_store(mddev_t *mddev, const char + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + md_unregister_thread(mddev->sync_thread); + mddev->sync_thread = NULL; +- mddev->recovery = 0; ++ mddev->recovery &= ~65535; + } + } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || + test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) +@@ -4530,7 +4530,7 @@ static int set_bitmap_file(mddev_t *mdde + if (mddev->pers) { + if (!mddev->pers->quiesce) + return -EBUSY; +- if (mddev->recovery || mddev->sync_thread) ++ if ((mddev->recovery & 65535) || mddev->sync_thread) + return -EBUSY; + /* we should be able to change the bitmap.. */ + } +@@ -4785,7 +4785,7 @@ static int update_array_info(mddev_t *md + if ((state ^ info->state) & (1<pers->quiesce == NULL) + return -EINVAL; +- if (mddev->recovery || mddev->sync_thread) ++ if ((mddev->recovery & 65535) || mddev->sync_thread) + return -EBUSY; + if (info->state & (1<degraded && ! mddev->ro) { ++ if (mddev->degraded && ! mddev->ro && ++ !test_bit(MD_RECOVERY_DISABLED, &mddev->recovery)) { + rdev_for_each(rdev, rtmp, mddev) { + if (rdev->raid_disk >= 0 && + !test_bit(In_sync, &rdev->flags) && +@@ -6202,7 +6203,7 @@ void md_check_recovery(mddev_t *mddev) + rdev_for_each(rdev, rtmp, mddev) + rdev->saved_raid_disk = -1; + +- mddev->recovery = 0; ++ mddev->recovery &= ~65535; + /* flag recovery needed just to double check */ + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + sysfs_notify(&mddev->kobj, NULL, "sync_action"); +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1012,12 +1012,16 @@ static void error(mddev_t *mddev, mdk_rd + * else mark the drive as failed + */ + if (test_bit(In_sync, &rdev->flags) +- && (conf->raid_disks - mddev->degraded) == 1) ++ && (conf->raid_disks - mddev->degraded) == 1) { + /* + * Don't fail the drive, act as though we were just a +- * normal single drive ++ * normal single drive. ++ * Disable any future recovery attempts as they will ++ * likely hit an error on this device. + */ ++ set_bit(MD_RECOVERY_DISABLED, &mddev->recovery); + return; ++ } + if (test_and_clear_bit(In_sync, &rdev->flags)) { + unsigned long flags; + spin_lock_irqsave(&conf->device_lock, flags); +--- a/include/linux/raid/md_k.h ++++ b/include/linux/raid/md_k.h +@@ -200,6 +200,8 @@ struct mddev_s + * RESHAPE: A reshape is happening + * + * If neither SYNC or RESHAPE are set, then it is a recovery. ++ * ++ * DISABLED: read error on degraded array makes recovery impossible. + */ + #define MD_RECOVERY_RUNNING 0 + #define MD_RECOVERY_SYNC 1 +@@ -212,6 +214,9 @@ struct mddev_s + #define MD_RECOVERY_RESHAPE 8 + #define MD_RECOVERY_FROZEN 9 + ++ ++#define MD_RECOVERY_DISABLED 16 ++ + unsigned long recovery; + + int in_sync; /* know to not need resync */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/md-raid1-chunksize b/src/patches/suse-2.6.27.31/patches.fixes/md-raid1-chunksize new file mode 100644 index 000000000..7b8871003 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/md-raid1-chunksize @@ -0,0 +1,42 @@ +From: NeilBrown +Subject: Don't fail to start a RAID1 with a small chunksize +Patch-mainline: no +References: 459557 + +For a RAID1 array, chunksize is almost meaningless (it is used to +round down the device size to a multiple of chunksize, but that is +largely of historical interest). +However it is possible to set the chunksize, and it is possible to +set it to be less than PAGE_SIZE. This currently causes the +array to fail to start. However there is no good reason for that. +And YaST seems to create RAID1 arrays with a 4K chunks which breaks +on PPC-64 machines with 64K pages. + +So ignore the "chunk_size < PAGE_SIZE" check on RAID1 like we do +for RAID0 + +Signed-off-by: Neil Brown + +--- + drivers/md/md.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -3587,13 +3587,13 @@ static int do_md_run(mddev_t * mddev) + return -EINVAL; + } + if (chunk_size < PAGE_SIZE) { +- if (mddev->level) { ++ if (mddev->level != 0 && mddev->level != 1) { + printk(KERN_ERR "too small chunk_size: %d < %ld\n", + chunk_size, PAGE_SIZE); + return -EINVAL; + } else { +- printk(KERN_ERR "too small chunk_size: %d < %ld, but continuing anyway on raid0. Good luck!\n", +- chunk_size, PAGE_SIZE); ++ printk(KERN_ERR "too small chunk_size: %d < %ld, but continuing anyway on raid%d. Good luck!\n", ++ chunk_size, PAGE_SIZE, mddev->level); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/md-raid1-handle-read-error.patch b/src/patches/suse-2.6.27.31/patches.fixes/md-raid1-handle-read-error.patch new file mode 100644 index 000000000..1bcebd216 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/md-raid1-handle-read-error.patch @@ -0,0 +1,33 @@ +From: NeilBrown +Subject: Allow read error in single drive in raid1 to be passed up +Patch-mainline: 2.6.29 +References: bnc#447835 + +If a raid1 only has a single working device and gets a read error, +we choose to simply return that error up to the filesystem (or whatever) +rather than failing the whol array. + +However the codes doesn't quite do that. We attempt a readbalance +which allocated the same drive, so we retry the read - indefinitely. + +Instead: If read_balance in the error case choose the same drive that just +failed, treat it as a failure and don't retry. + +Signed-off-by: Neil Brown + +--- + drivers/md/raid1.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -1637,7 +1637,8 @@ static void raid1d(mddev_t *mddev) + } + + bio = r1_bio->bios[r1_bio->read_disk]; +- if ((disk=read_balance(conf, r1_bio)) == -1) { ++ if ((disk=read_balance(conf, r1_bio)) == -1 || ++ disk == r1_bio->read_disk) { + printk(KERN_ALERT "raid1: %s: unrecoverable I/O" + " read error for block %llu\n", + bdevname(bio->bi_bdev,b), diff --git a/src/patches/suse-2.6.27.31/patches.fixes/md-update-size b/src/patches/suse-2.6.27.31/patches.fixes/md-update-size new file mode 100644 index 000000000..8c682166f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/md-update-size @@ -0,0 +1,28 @@ +From: NeilBrown +References: bnc#509495 +Subject: Update size of md device as soon as it is successfully assemble. + +It is import that we get the size of an md device 'right' before +generating the KOBJ_CHANGE message. If we don't, then if a program +runs as a result of that message and open the md device before the +mdadm which created the device closes it, the new program will see a +size of zero which will be confusing. + +So call revalidate_disk, which checks and updates the size. + +Signed-off-by: NeilBrown + +--- + drivers/md/md.c | 1 + + 1 file changed, 1 insertion(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -3892,6 +3892,7 @@ static int do_md_run(mddev_t * mddev) + md_wakeup_thread(mddev->thread); + md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */ + ++ revalidate_disk(mddev->gendisk); + mddev->changed = 1; + md_new_event(mddev); + sysfs_notify(&mddev->kobj, NULL, "array_state"); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/md-utime-fix b/src/patches/suse-2.6.27.31/patches.fixes/md-utime-fix new file mode 100644 index 000000000..35f63c8c0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/md-utime-fix @@ -0,0 +1,41 @@ +Patch-mainline: 2.6.30 +References: 498402 +Git: 1b57f132231593923cb4ab99943ddd777e8745bc Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Thu, 18 Jun 2009 08:48:19 +1000 +Subject: [PATCH] md: move assignment of ->utime so that it never gets skipped. + +Currently the assignment to utime gets skipped for 'external' +metadata. So move it to the top of the function so that it +always gets effected. +This is of largely cosmetic interest. Nothing actually depends +on ->utime being right for external arrays. +"mdadm --monitor" does use it for 0.90 and 1.x arrays, but with +mdadm-3.0, this is not important for external metadata. + +However the 3.0-pre mdadm in SLES11 does depend on this being correct. + +Signed-off-by: NeilBrown + +--- + drivers/md/md.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/md.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/md.c +@@ -1758,6 +1758,7 @@ static void md_update_sb(mddev_t * mddev + int sync_req; + int nospares = 0; + ++ mddev->utime = get_seconds(); + if (mddev->external) + return; + repeat: +@@ -1787,7 +1788,6 @@ repeat: + nospares = 0; + + sync_req = mddev->in_sync; +- mddev->utime = get_seconds(); + + /* If this is just a dirty<->clean transition, and the array is clean + * and 'events' is odd, we can roll back to the previous clean state */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/mm-fix-Commited_AS-underflow-on-large-NR_CPUS b/src/patches/suse-2.6.27.31/patches.fixes/mm-fix-Commited_AS-underflow-on-large-NR_CPUS new file mode 100644 index 000000000..55ea6084c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/mm-fix-Commited_AS-underflow-on-large-NR_CPUS @@ -0,0 +1,215 @@ +From: KOSAKI Motohiro +Subject: mm: fix Committed_AS underflow on large NR_CPUS environment +Patch-mainline: 2.6.30-rc5 +Git-commit: 00a62ce91e554198ef28234c91c36f850f5a3bc9 +References: bnc#505831 + +mm: fix Committed_AS underflow on large NR_CPUS environment + +The Committed_AS field can underflow in certain situations: + +> # while true; do cat /proc/meminfo | grep _AS; sleep 1; done | uniq -c +> 1 Committed_AS: 18446744073709323392 kB +> 11 Committed_AS: 18446744073709455488 kB +> 6 Committed_AS: 35136 kB +> 5 Committed_AS: 18446744073709454400 kB +> 7 Committed_AS: 35904 kB +> 3 Committed_AS: 18446744073709453248 kB +> 2 Committed_AS: 34752 kB +> 9 Committed_AS: 18446744073709453248 kB +> 8 Committed_AS: 34752 kB +> 3 Committed_AS: 18446744073709320960 kB +> 7 Committed_AS: 18446744073709454080 kB +> 3 Committed_AS: 18446744073709320960 kB +> 5 Committed_AS: 18446744073709454080 kB +> 6 Committed_AS: 18446744073709320960 kB + +Because NR_CPUS can be greater than 1000 and meminfo_proc_show() does +not check for underflow. + +But NR_CPUS proportional isn't good calculation. In general, +possibility of lock contention is proportional to the number of online +cpus, not theorical maximum cpus (NR_CPUS). + +The current kernel has generic percpu-counter stuff. using it is right +way. it makes code simplify and percpu_counter_read_positive() don't +make underflow issue. + +Reported-by: Dave Hansen +Signed-off-by: KOSAKI Motohiro +Cc: Eric B Munson +Cc: Mel Gorman +Cc: Christoph Lameter +Cc: [All kernel versions] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Backported-by: Jeff Mahoney +Signed-off-by: Jeff Mahoney +--- + fs/proc/proc_misc.c | 2 +- + include/linux/mman.h | 9 +++------ + kernel/fork.c | 2 ++ + mm/mmap.c | 8 ++------ + mm/nommu.c | 9 +++------ + mm/swap.c | 46 ---------------------------------------------- + 6 files changed, 11 insertions(+), 65 deletions(-) + +--- a/fs/proc/proc_misc.c ++++ b/fs/proc/proc_misc.c +@@ -145,7 +145,7 @@ static int meminfo_read_proc(char *page, + #define K(x) ((x) << (PAGE_SHIFT - 10)) + si_meminfo(&i); + si_swapinfo(&i); +- committed = atomic_long_read(&vm_committed_space); ++ committed = percpu_counter_read_positive(&vm_committed_as); + allowed = ((totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100) + total_swap_pages; + +--- a/include/linux/mman.h ++++ b/include/linux/mman.h +@@ -12,21 +12,18 @@ + + #ifdef __KERNEL__ + #include ++#include + + #include + + extern int sysctl_overcommit_memory; + extern int sysctl_overcommit_ratio; +-extern atomic_long_t vm_committed_space; ++extern struct percpu_counter vm_committed_as; + +-#ifdef CONFIG_SMP +-extern void vm_acct_memory(long pages); +-#else + static inline void vm_acct_memory(long pages) + { +- atomic_long_add(pages, &vm_committed_space); ++ percpu_counter_add(&vm_committed_as, pages); + } +-#endif + + static inline void vm_unacct_memory(long pages) + { +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1442,6 +1442,8 @@ void __init proc_caches_init(void) + mm_cachep = kmem_cache_create("mm_struct", + sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); ++ if (percpu_counter_init(&vm_committed_as, 0)) ++ panic("Failed to allocate vm_committed_as"); + } + + /* +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -84,7 +84,7 @@ EXPORT_SYMBOL(vm_get_page_prot); + int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */ + int sysctl_overcommit_ratio = 50; /* default is 50% */ + int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; +-atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0); ++struct percpu_counter vm_committed_as; + int heap_stack_gap __read_mostly = 1; + + /* amount of vm to protect from userspace access */ +@@ -181,11 +181,7 @@ int __vm_enough_memory(struct mm_struct + leave 3% of the size of this process for other processes */ + allowed -= mm->total_vm / 32; + +- /* +- * cast `allowed' as a signed long because vm_committed_space +- * sometimes has a negative value +- */ +- if (atomic_long_read(&vm_committed_space) < (long)allowed) ++ if (percpu_counter_read_positive(&vm_committed_as) < allowed) + return 0; + error: + vm_unacct_memory(pages); +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -39,7 +39,7 @@ struct page *mem_map; + unsigned long max_mapnr; + unsigned long num_physpages; + unsigned long askedalloc, realalloc; +-atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0); ++struct percpu_counter vm_committed_as; + int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */ + int sysctl_overcommit_ratio = 50; /* default is 50% */ + int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; +@@ -1434,12 +1434,9 @@ int __vm_enough_memory(struct mm_struct + leave 3% of the size of this process for other processes */ + allowed -= current->mm->total_vm / 32; + +- /* +- * cast `allowed' as a signed long because vm_committed_space +- * sometimes has a negative value +- */ +- if (atomic_long_read(&vm_committed_space) < (long)allowed) ++ if (percpu_counter_read_positive(&vm_committed_as) < allowed) + return 0; ++ + error: + vm_unacct_memory(pages); + +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -474,49 +474,6 @@ unsigned pagevec_lookup_tag(struct pagev + + EXPORT_SYMBOL(pagevec_lookup_tag); + +-#ifdef CONFIG_SMP +-/* +- * We tolerate a little inaccuracy to avoid ping-ponging the counter between +- * CPUs +- */ +-#define ACCT_THRESHOLD max(16, NR_CPUS * 2) +- +-static DEFINE_PER_CPU(long, committed_space); +- +-void vm_acct_memory(long pages) +-{ +- long *local; +- +- preempt_disable(); +- local = &__get_cpu_var(committed_space); +- *local += pages; +- if (*local > ACCT_THRESHOLD || *local < -ACCT_THRESHOLD) { +- atomic_long_add(*local, &vm_committed_space); +- *local = 0; +- } +- preempt_enable(); +-} +- +-#ifdef CONFIG_HOTPLUG_CPU +- +-/* Drop the CPU's cached committed space back into the central pool. */ +-static int cpu_swap_callback(struct notifier_block *nfb, +- unsigned long action, +- void *hcpu) +-{ +- long *committed; +- +- committed = &per_cpu(committed_space, (long)hcpu); +- if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { +- atomic_long_add(*committed, &vm_committed_space); +- *committed = 0; +- drain_cpu_pagevecs((long)hcpu); +- } +- return NOTIFY_OK; +-} +-#endif /* CONFIG_HOTPLUG_CPU */ +-#endif /* CONFIG_SMP */ +- + /* + * Perform any setup for the swap system + */ +@@ -537,7 +494,4 @@ void __init swap_setup(void) + * Right now other parts of the system means that we + * _really_ don't want to cluster much more + */ +-#ifdef CONFIG_HOTPLUG_CPU +- hotcpu_notifier(cpu_swap_callback, 0); +-#endif + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/mm-madvise-fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/mm-madvise-fix.patch new file mode 100644 index 000000000..36d1a8c76 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/mm-madvise-fix.patch @@ -0,0 +1,57 @@ +From: Nick Piggin +Subject: mm: madvise correct return code +References: bnc#352998 + +madvise should return -EINVAL if passed in an invalid flag, even if the +requested range is 0. + +Signed-off-by: Nick Piggin +--- +--- + mm/madvise.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +--- a/mm/madvise.c ++++ b/mm/madvise.c +@@ -247,12 +247,30 @@ madvise_vma(struct vm_area_struct *vma, + break; + + default: +- error = -EINVAL; ++ BUG(); + break; + } + return error; + } + ++static int ++madvise_behavior_valid(int behavior) ++{ ++ switch (behavior) { ++ case MADV_DOFORK: ++ case MADV_DONTFORK: ++ case MADV_NORMAL: ++ case MADV_SEQUENTIAL: ++ case MADV_RANDOM: ++ case MADV_REMOVE: ++ case MADV_WILLNEED: ++ case MADV_DONTNEED: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} + /* + * The madvise(2) system call. + * +@@ -298,6 +316,9 @@ SYSCALL_DEFINE3(madvise, unsigned long, + int write; + size_t len; + ++ if (!madvise_behavior_valid(behavior)) ++ return error; ++ + write = madvise_need_mmap_write(behavior); + if (write) + down_write(¤t->mm->mmap_sem); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/mm-nr_pdflush-race-fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/mm-nr_pdflush-race-fix.patch new file mode 100644 index 000000000..b0344f105 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/mm-nr_pdflush-race-fix.patch @@ -0,0 +1,85 @@ +Subject: mm: fix pdflush thread creation upper bound. +From: Peter W. Morreale +References: bnc#460284 +Patch-upstream: not yet + + This patch fixes a race on creating pdflush threads. Without the patch, + it is possible to create more than MAX_PDFLUSH_THREADS threads, and this + has been observed in practice. + + The fix involves moving the lock around to protect the check against the + thread count and correctly dealing with thread creation failure. + + Signed-Off-By: Peter W. Morreale +Acked-by: Nick Piggin +--- +--- + mm/pdflush.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +--- a/mm/pdflush.c ++++ b/mm/pdflush.c +@@ -98,7 +98,6 @@ static int __pdflush(struct pdflush_work + INIT_LIST_HEAD(&my_work->list); + + spin_lock_irq(&pdflush_lock); +- nr_pdflush_threads++; + for ( ; ; ) { + struct pdflush_work *pdf; + +@@ -126,20 +125,23 @@ static int __pdflush(struct pdflush_work + + (*my_work->fn)(my_work->arg0); + ++ spin_lock_irq(&pdflush_lock); ++ + /* + * Thread creation: For how long have there been zero + * available threads? + */ + if (time_after(jiffies, last_empty_jifs + 1 * HZ)) { +- /* unlocked list_empty() test is OK here */ + if (list_empty(&pdflush_list)) { +- /* unlocked test is OK here */ +- if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) ++ if (nr_pdflush_threads < MAX_PDFLUSH_THREADS) { ++ nr_pdflush_threads++; ++ spin_unlock_irq(&pdflush_lock); + start_one_pdflush_thread(); ++ spin_lock_irq(&pdflush_lock); ++ } + } + } + +- spin_lock_irq(&pdflush_lock); + my_work->fn = NULL; + + /* +@@ -226,13 +228,26 @@ int pdflush_operation(void (*fn)(unsigne + + static void start_one_pdflush_thread(void) + { +- kthread_run(pdflush, NULL, "pdflush"); ++ struct task_struct *k; ++ ++ k = kthread_run(pdflush, NULL, "pdflush"); ++ if (unlikely(IS_ERR(k))) { ++ spin_lock_irq(&pdflush_lock); ++ nr_pdflush_threads--; ++ spin_unlock_irq(&pdflush_lock); ++ } + } + + static int __init pdflush_init(void) + { + int i; + ++ /* ++ * Pre-set nr_pdflush_threads... If we fail to create, ++ * the count will be decremented. ++ */ ++ nr_pdflush_threads = MIN_PDFLUSH_THREADS; ++ + for (i = 0; i < MIN_PDFLUSH_THREADS; i++) + start_one_pdflush_thread(); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/multiq-requeue-should-rewind-current_band b/src/patches/suse-2.6.27.31/patches.fixes/multiq-requeue-should-rewind-current_band new file mode 100644 index 000000000..c621c668f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/multiq-requeue-should-rewind-current_band @@ -0,0 +1,38 @@ +Subject: multiq: requeue should rewind the current_band +From: Alexander Duyck +References: bnc#438954 + +Currently dequeueing a packet and requeueing the same packet will cause a +different packet to be pulled on the next dequeue. This change forces +requeue to rewind the current_band. + +Signed-off-by: Alexander Duyck +Signed-off-by: Hannes Reinecke +--- + + net/sched/sch_multiq.c | 5 +++++ + 1 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c +index ce00df4..7f4dbf0 100644 +--- a/net/sched/sch_multiq.c ++++ b/net/sched/sch_multiq.c +@@ -97,6 +97,7 @@ static int + multiq_requeue(struct sk_buff *skb, struct Qdisc *sch) + { + struct Qdisc *qdisc; ++ struct multiq_sched_data *q = qdisc_priv(sch); + int ret; + + qdisc = multiq_classify(skb, sch, &ret); +@@ -113,6 +114,10 @@ multiq_requeue(struct sk_buff *skb, struct Qdisc *sch) + if (ret == NET_XMIT_SUCCESS) { + sch->q.qlen++; + sch->qstats.requeues++; ++ if (q->curband) ++ q->curband--; ++ else ++ q->curband = q->bands - 1; + return NET_XMIT_SUCCESS; + } + if (net_xmit_drop_count(ret)) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-01-Uninline-the-function-put_mnt_ns b/src/patches/suse-2.6.27.31/patches.fixes/nfs-01-Uninline-the-function-put_mnt_ns new file mode 100644 index 000000000..17e3f66ba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-01-Uninline-the-function-put_mnt_ns @@ -0,0 +1,52 @@ +From 616511d039af402670de8500d0e24495113a9cab Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 22 Jun 2009 15:09:13 -0400 +Subject: [PATCH 1/5] VFS: Uninline the function put_mnt_ns() + +In order to allow modules to use it without having to export vfsmount_lock. + +Signed-off-by: Trond Myklebust +Signed-off-by: Linus Torvalds +Acked-by: NeilBrown +--- + fs/namespace.c | 8 ++++++-- + include/linux/mnt_namespace.h | 9 +-------- + 2 files changed, 7 insertions(+), 10 deletions(-) + +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -2310,10 +2310,14 @@ void __init mnt_init(void) + init_mount_tree(); + } + +-void __put_mnt_ns(struct mnt_namespace *ns) ++void put_mnt_ns(struct mnt_namespace *ns) + { +- struct vfsmount *root = ns->root; ++ struct vfsmount *root; + LIST_HEAD(umount_list); ++ ++ if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock)) ++ return; ++ root = ns->root; + ns->root = NULL; + spin_unlock(&vfsmount_lock); + down_write(&namespace_sem); +--- a/include/linux/mnt_namespace.h ++++ b/include/linux/mnt_namespace.h +@@ -24,14 +24,7 @@ struct proc_mounts { + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct fs_struct *); +-extern void __put_mnt_ns(struct mnt_namespace *ns); +- +-static inline void put_mnt_ns(struct mnt_namespace *ns) +-{ +- if (atomic_dec_and_lock(&ns->count, &vfsmount_lock)) +- /* releases vfsmount_lock */ +- __put_mnt_ns(ns); +-} ++extern void put_mnt_ns(struct mnt_namespace *ns); + + static inline void exit_mnt_ns(struct task_struct *p) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-02-Add-VFS-helper-functions-for-setting-up-private-namespaces b/src/patches/suse-2.6.27.31/patches.fixes/nfs-02-Add-VFS-helper-functions-for-setting-up-private-namespaces new file mode 100644 index 000000000..2aef92da7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-02-Add-VFS-helper-functions-for-setting-up-private-namespaces @@ -0,0 +1,116 @@ +From cf8d2c11cb77f129675478792122f50827e5b0ae Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 22 Jun 2009 15:09:13 -0400 +Subject: [PATCH 2/5] VFS: Add VFS helper functions for setting up private namespaces + +The purpose of this patch is to improve the remote mount path lookup +support for distributed filesystems such as the NFSv4 client. + +When given a mount command of the form "mount server:/foo/bar /mnt", the +NFSv4 client is required to look up the filehandle for "server:/", and +then look up each component of the remote mount path "foo/bar" in order +to find the directory that is actually going to be mounted on /mnt. +Following that remote mount path may involve following symlinks, +crossing server-side mount points and even following referrals to +filesystem volumes on other servers. + +Since the standard VFS path lookup code already supports walking paths +that contain all these features (using in-kernel automounts for +following referrals) we would like to be able to reuse that rather than +duplicate the full path traversal functionality in the NFSv4 client code. + +This patch therefore defines a VFS helper function create_mnt_ns(), that +sets up a temporary filesystem namespace and attaches a root filesystem to +it. It exports the create_mnt_ns() and put_mnt_ns() function for use by +filesystem modules. + +Signed-off-by: Trond Myklebust +Signed-off-by: Linus Torvalds +Acked-by: NeilBrown +--- + fs/namespace.c | 45 ++++++++++++++++++++++++++++++++++-------- + include/linux/mnt_namespace.h | 1 + 2 files changed, 38 insertions(+), 8 deletions(-) + +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -1939,6 +1939,21 @@ dput_out: + return retval; + } + ++static struct mnt_namespace *alloc_mnt_ns(void) ++{ ++ struct mnt_namespace *new_ns; ++ ++ new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); ++ if (!new_ns) ++ return ERR_PTR(-ENOMEM); ++ atomic_set(&new_ns->count, 1); ++ new_ns->root = NULL; ++ INIT_LIST_HEAD(&new_ns->list); ++ init_waitqueue_head(&new_ns->poll); ++ new_ns->event = 0; ++ return new_ns; ++} ++ + /* + * Allocate a new namespace structure and populate it with contents + * copied from the namespace of the passed in task structure. +@@ -1950,14 +1965,9 @@ static struct mnt_namespace *dup_mnt_ns( + struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; + struct vfsmount *p, *q; + +- new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); +- if (!new_ns) +- return ERR_PTR(-ENOMEM); +- +- atomic_set(&new_ns->count, 1); +- INIT_LIST_HEAD(&new_ns->list); +- init_waitqueue_head(&new_ns->poll); +- new_ns->event = 0; ++ new_ns = alloc_mnt_ns(); ++ if (IS_ERR(new_ns)) ++ return new_ns; + + down_write(&namespace_sem); + /* First pass: copy the tree topology */ +@@ -2021,6 +2031,24 @@ struct mnt_namespace *copy_mnt_ns(unsign + return new_ns; + } + ++/** ++ * create_mnt_ns - creates a private namespace and adds a root filesystem ++ * @mnt: pointer to the new root filesystem mountpoint ++ */ ++struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) ++{ ++ struct mnt_namespace *new_ns; ++ ++ new_ns = alloc_mnt_ns(); ++ if (!IS_ERR(new_ns)) { ++ mnt->mnt_ns = new_ns; ++ new_ns->root = mnt; ++ list_add(&new_ns->list, &new_ns->root->mnt_list); ++ } ++ return new_ns; ++} ++EXPORT_SYMBOL(create_mnt_ns); ++ + SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, + char __user *, type, unsigned long, flags, void __user *, data) + { +@@ -2328,3 +2356,4 @@ void put_mnt_ns(struct mnt_namespace *ns + release_mounts(&umount_list); + kfree(ns); + } ++EXPORT_SYMBOL(put_mnt_ns); +--- a/include/linux/mnt_namespace.h ++++ b/include/linux/mnt_namespace.h +@@ -22,6 +22,7 @@ struct proc_mounts { + int event; + }; + ++extern struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt); + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct fs_struct *); + extern void put_mnt_ns(struct mnt_namespace *ns); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-03-NFSv4-Replace-nfs4_path_walk-with-VFS-path-lookup-in-private-namespace b/src/patches/suse-2.6.27.31/patches.fixes/nfs-03-NFSv4-Replace-nfs4_path_walk-with-VFS-path-lookup-in-private-namespace new file mode 100644 index 000000000..14d6fbb85 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-03-NFSv4-Replace-nfs4_path_walk-with-VFS-path-lookup-in-private-namespace @@ -0,0 +1,291 @@ +From c02d7adf8c5429727a98bad1d039bccad4c61c50 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 22 Jun 2009 15:09:14 -0400 +Subject: [PATCH 3/5] NFSv4: Replace nfs4_path_walk() with VFS path lookup in a private namespace + +As noted in the previous patch, the NFSv4 client mount code currently +has several limitations. If the mount path contains symlinks, or +referrals, or even if it just contains a '..', then the client code in +nfs4_path_walk() will fail with an error. + +This patch replaces the nfs4_path_walk()-based lookup with a helper +function that sets up a private namespace to represent the namespace on the +server, then uses the ordinary VFS and NFS path lookup code to walk down the +mount path in that namespace. + +Signed-off-by: Trond Myklebust +Signed-off-by: Linus Torvalds +Acked-by: NeilBrown +--- + fs/nfs/super.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 156 insertions(+), 20 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/super.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/super.c +@@ -42,6 +42,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -244,10 +246,14 @@ static const struct super_operations nfs + #ifdef CONFIG_NFS_V4 + static int nfs4_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); ++static int nfs4_remote_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); + static int nfs4_xdev_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); + static int nfs4_referral_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); ++static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); + static void nfs4_kill_super(struct super_block *sb); + + static struct file_system_type nfs4_fs_type = { +@@ -258,6 +264,14 @@ static struct file_system_type nfs4_fs_t + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, + }; + ++static struct file_system_type nfs4_remote_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "nfs4", ++ .get_sb = nfs4_remote_get_sb, ++ .kill_sb = nfs4_kill_super, ++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, ++}; ++ + struct file_system_type nfs4_xdev_fs_type = { + .owner = THIS_MODULE, + .name = "nfs4", +@@ -266,6 +280,14 @@ struct file_system_type nfs4_xdev_fs_typ + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, + }; + ++static struct file_system_type nfs4_remote_referral_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "nfs4", ++ .get_sb = nfs4_remote_referral_get_sb, ++ .kill_sb = nfs4_kill_super, ++ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, ++}; ++ + struct file_system_type nfs4_referral_fs_type = { + .owner = THIS_MODULE, + .name = "nfs4", +@@ -2294,12 +2316,12 @@ out_no_client_address: + } + + /* +- * Get the superblock for an NFS4 mountpoint ++ * Get the superblock for the NFS4 root partition + */ +-static int nfs4_get_sb(struct file_system_type *fs_type, ++static int nfs4_remote_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) + { +- struct nfs_parsed_mount_data *data; ++ struct nfs_parsed_mount_data *data = raw_data; + struct super_block *s; + struct nfs_server *server; + struct nfs_fh *mntfh; +@@ -2310,18 +2332,12 @@ static int nfs4_get_sb(struct file_syste + }; + int error = -ENOMEM; + +- data = kzalloc(sizeof(*data), GFP_KERNEL); + mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); + if (data == NULL || mntfh == NULL) + goto out_free_fh; + + security_init_mnt_opts(&data->lsm_opts); + +- /* Validate the mount data */ +- error = nfs4_validate_mount_data(raw_data, data, dev_name); +- if (error < 0) +- goto out; +- + /* Get a volume representation */ + server = nfs4_create_server(data, mntfh); + if (IS_ERR(server)) { +@@ -2334,7 +2350,7 @@ static int nfs4_get_sb(struct file_syste + compare_super = NULL; + + /* Get a superblock - note that we may end up sharing one that already exists */ +- s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); ++ s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); + if (IS_ERR(s)) { + error = PTR_ERR(s); + goto out_free; +@@ -2370,13 +2386,9 @@ static int nfs4_get_sb(struct file_syste + error = 0; + + out: +- kfree(data->client_address); +- kfree(data->nfs_server.export_path); +- kfree(data->nfs_server.hostname); + security_free_mnt_opts(&data->lsm_opts); + out_free_fh: + kfree(mntfh); +- kfree(data); + return error; + + out_free: +@@ -2391,6 +2403,101 @@ error_splat_super: + goto out; + } + ++static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, ++ int flags, void *data, const char *hostname) ++{ ++ struct vfsmount *root_mnt; ++ char *root_devname; ++ size_t len; ++ ++ len = strlen(hostname) + 3; ++ root_devname = kmalloc(len, GFP_KERNEL); ++ if (root_devname == NULL) ++ return ERR_PTR(-ENOMEM); ++ snprintf(root_devname, len, "%s:/", hostname); ++ root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); ++ kfree(root_devname); ++ return root_mnt; ++} ++ ++static int nfs_follow_remote_path(struct vfsmount *root_mnt, ++ const char *export_path, struct vfsmount *mnt_target) ++{ ++ struct mnt_namespace *ns_private; ++ struct nameidata nd; ++ struct super_block *s; ++ int ret; ++ ++ ns_private = create_mnt_ns(root_mnt); ++ ret = PTR_ERR(ns_private); ++ if (IS_ERR(ns_private)) ++ goto out_mntput; ++ ++ ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, ++ export_path, LOOKUP_FOLLOW, &nd); ++ ++ put_mnt_ns(ns_private); ++ ++ if (ret != 0) ++ goto out_err; ++ ++ s = nd.path.mnt->mnt_sb; ++ atomic_inc(&s->s_active); ++ mnt_target->mnt_sb = s; ++ mnt_target->mnt_root = dget(nd.path.dentry); ++ ++ path_put(&nd.path); ++ down_write(&s->s_umount); ++ return 0; ++out_mntput: ++ mntput(root_mnt); ++out_err: ++ return ret; ++} ++ ++/* ++ * Get the superblock for an NFS4 mountpoint ++ */ ++static int nfs4_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) ++{ ++ struct nfs_parsed_mount_data *data; ++ char *export_path; ++ struct vfsmount *root_mnt; ++ int error = -ENOMEM; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (data == NULL) ++ goto out_free_data; ++ ++ /* Validate the mount data */ ++ error = nfs4_validate_mount_data(raw_data, data, dev_name); ++ if (error < 0) ++ goto out; ++ ++ export_path = data->nfs_server.export_path; ++ data->nfs_server.export_path = "/"; ++ root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, ++ data->nfs_server.hostname); ++ data->nfs_server.export_path = export_path; ++ ++ error = PTR_ERR(root_mnt); ++ if (IS_ERR(root_mnt)) ++ goto out; ++ ++ error = nfs_follow_remote_path(root_mnt, export_path, mnt); ++ ++out: ++ kfree(data->client_address); ++ kfree(data->nfs_server.export_path); ++ kfree(data->nfs_server.hostname); ++out_free_data: ++ kfree(data); ++ dprintk("<-- nfs4_get_sb() = %d%s\n", error, ++ error != 0 ? " [error]" : ""); ++ return error; ++} ++ + static void nfs4_kill_super(struct super_block *sb) + { + struct nfs_server *server = NFS_SB(sb); +@@ -2486,12 +2593,9 @@ error_splat_super: + return error; + } + +-/* +- * Create an NFS4 server record on referral traversal +- */ +-static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, +- const char *dev_name, void *raw_data, +- struct vfsmount *mnt) ++static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *raw_data, ++ struct vfsmount *mnt) + { + struct nfs_clone_mount *data = raw_data; + struct super_block *s; +@@ -2571,4 +2675,36 @@ error_splat_super: + return error; + } + ++/* ++ * Create an NFS4 server record on referral traversal ++ */ ++static int nfs4_referral_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *raw_data, ++ struct vfsmount *mnt) ++{ ++ struct nfs_clone_mount *data = raw_data; ++ char *export_path; ++ struct vfsmount *root_mnt; ++ int error; ++ ++ dprintk("--> nfs4_referral_get_sb()\n"); ++ ++ export_path = data->mnt_path; ++ data->mnt_path = "/"; ++ ++ root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, ++ flags, data, data->hostname); ++ data->mnt_path = export_path; ++ ++ error = PTR_ERR(root_mnt); ++ if (IS_ERR(root_mnt)) ++ goto out; ++ ++ error = nfs_follow_remote_path(root_mnt, export_path, mnt); ++out: ++ dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error, ++ error != 0 ? " [error]" : ""); ++ return error; ++} ++ + #endif /* CONFIG_NFS_V4 */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-04-Fix-nfs_path-to-always-return-a-slash-at-the-beginning-of-the-path b/src/patches/suse-2.6.27.31/patches.fixes/nfs-04-Fix-nfs_path-to-always-return-a-slash-at-the-beginning-of-the-path new file mode 100644 index 000000000..3fd25fe7d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-04-Fix-nfs_path-to-always-return-a-slash-at-the-beginning-of-the-path @@ -0,0 +1,26 @@ +From 0b75b35c7cad33e7613f5adf28fa10fe8b09b1c3 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 22 Jun 2009 15:09:14 -0400 +Subject: [PATCH 4/5] NFS: Fix nfs_path() to always return a '/' at the beginning of the path + +Signed-off-by: Trond Myklebust +Signed-off-by: Linus Torvalds +Acked-by: NeilBrown +--- + fs/nfs/namespace.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/namespace.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/namespace.c +@@ -65,6 +65,11 @@ char *nfs_path(const char *base, + dentry = dentry->d_parent; + } + spin_unlock(&dcache_lock); ++ if (*end != '/') { ++ if (--buflen < 0) ++ goto Elong; ++ *--end = '/'; ++ } + namelen = strlen(base); + /* Strip off excess slashes in base string */ + while (namelen > 0 && base[namelen - 1] == '/') diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-05-Correct-the-NFS-mount-path-when-following-a-referral b/src/patches/suse-2.6.27.31/patches.fixes/nfs-05-Correct-the-NFS-mount-path-when-following-a-referral new file mode 100644 index 000000000..8a95f5d02 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-05-Correct-the-NFS-mount-path-when-following-a-referral @@ -0,0 +1,52 @@ +From b88f8a546f5dba213938fdfc11e66bc5c2421623 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 22 Jun 2009 15:09:14 -0400 +Subject: [PATCH 5/5] NFS: Correct the NFS mount path when following a referral + +Signed-off-by: Trond Myklebust +Signed-off-by: Linus Torvalds +Acked-by: NeilBrown +--- + fs/nfs/super.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/super.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/super.c +@@ -2420,6 +2420,27 @@ static struct vfsmount *nfs_do_root_moun + return root_mnt; + } + ++static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) ++{ ++ char *page = (char *) __get_free_page(GFP_KERNEL); ++ char *devname, *tmp; ++ ++ if (page == NULL) ++ return; ++ devname = nfs_path(path->mnt->mnt_devname, ++ path->mnt->mnt_root, path->dentry, ++ page, PAGE_SIZE); ++ if (devname == NULL) ++ goto out_freepage; ++ tmp = kstrdup(devname, GFP_KERNEL); ++ if (tmp == NULL) ++ goto out_freepage; ++ kfree(mnt->mnt_devname); ++ mnt->mnt_devname = tmp; ++out_freepage: ++ free_page((unsigned long)page); ++} ++ + static int nfs_follow_remote_path(struct vfsmount *root_mnt, + const char *export_path, struct vfsmount *mnt_target) + { +@@ -2446,6 +2467,9 @@ static int nfs_follow_remote_path(struct + mnt_target->mnt_sb = s; + mnt_target->mnt_root = dget(nd.path.dentry); + ++ /* Correct the device pathname */ ++ nfs_fix_devname(&nd.path, mnt_target); ++ + path_put(&nd.path); + down_write(&s->s_umount); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-06-dont-bother-with-check_mnt-in-do_add_mount-on-shrinkable-ones b/src/patches/suse-2.6.27.31/patches.fixes/nfs-06-dont-bother-with-check_mnt-in-do_add_mount-on-shrinkable-ones new file mode 100644 index 000000000..579bc0161 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-06-dont-bother-with-check_mnt-in-do_add_mount-on-shrinkable-ones @@ -0,0 +1,29 @@ +Git: dd5cae6e9772ecc62fd374f7a8ec10eb51c96c4d +From: Al Viro +Subject: Don't bother with check_mnt() in do_add_mount() on shrinkable ones +Date: Tue Apr 7 12:21:18 2009 -0400 +Patch-mainline: 2.7.30 +References: bnc#490030, bnc#531633 + +These guys are what we add as submounts; checks for "is that attached in +our namespace" are simply irrelevant for those and counterproductive for +use of private vfsmount trees a-la what NFS folks want. + +Signed-off-by: Al Viro +Acked-by: NeilBrown + +--- + fs/namespace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/namespace.c ++++ linux-2.6.27-SLE11_BRANCH/fs/namespace.c +@@ -1658,7 +1658,7 @@ int do_add_mount(struct vfsmount *newmnt + follow_down(&path->mnt, &path->dentry)) + ; + err = -EINVAL; +- if (!check_mnt(path->mnt)) ++ if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) + goto unlock; + + /* Refuse the same filesystem on the same mount point */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-file-cred-context-null b/src/patches/suse-2.6.27.31/patches.fixes/nfs-file-cred-context-null new file mode 100644 index 000000000..2406bfdb6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-file-cred-context-null @@ -0,0 +1,33 @@ +From: NeilBrown +Subject: nfs_file_cred should cope if 'file' hasn't been opened properly +Patch-mainline: Not relevant +References: bnc#431785 + + +.. and so doesn't have a 'context'. This can happen when e.g. +a chmod on a device-special-file happens. The object isn't opened over +NFS so there is no open context, but we currently look for one when +doing a setattr. + +Signed-off-by: Neil Brown + +--- + include/linux/nfs_fs.h | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- linux-2.6.27-neilb.orig/include/linux/nfs_fs.h ++++ linux-2.6.27-neilb/include/linux/nfs_fs.h +@@ -372,8 +372,11 @@ static inline struct nfs_open_context *n + + static inline struct rpc_cred *nfs_file_cred(struct file *file) + { +- if (file != NULL) +- return nfs_file_open_context(file)->cred; ++ if (file != NULL) { ++ struct nfs_open_context *ctx = nfs_file_open_context(file); ++ if (ctx) ++ return ctx->cred; ++ } + return NULL; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-nfs3_xdr_setaclargs b/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-nfs3_xdr_setaclargs new file mode 100644 index 000000000..a5a79f9e5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-nfs3_xdr_setaclargs @@ -0,0 +1,30 @@ +From: Trond Myklebust +Subject: NFS: Fix the XDR iovec calculation in nfs3_xdr_setaclargs +References: 465854 +Patch-mainline: Queued-up + +Commit ae46141ff08f1965b17c531b571953c39ce8b9e2 (NFSv3: Fix posix ACL code) +introduces a bug in the calculation of the XDR header iovec. In the case +where we are inlining the acls, we need to adjust the length of the iovec +req->rq_svec, in addition to adjusting the total buffer length. + +Signed-off-by: Trond Myklebust +Signed-off-by: Suresh Jayaraman +--- + fs/nfs/nfs3xdr.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3xdr.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/nfs3xdr.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3xdr.c +@@ -716,7 +716,8 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req + if (args->npages != 0) + xdr_encode_pages(buf, args->pages, 0, args->len); + else +- req->rq_slen += args->len; ++ req->rq_slen = xdr_adjust_iovec(req->rq_svec, ++ p + XDR_QUADLEN(args->len)); + + err = nfsacl_encode(buf, base, args->inode, + (args->mask & NFS_ACL) ? diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-posix-acl b/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-posix-acl new file mode 100644 index 000000000..0c51076ed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-posix-acl @@ -0,0 +1,174 @@ +From: Trond Myklebust +Subject: NFSv3: Fix posix ACL code +References: 465854 +Patch-mainline: 2.6.29-rc7 + +Upstream commit ae46141ff08f1965b17c531b571953c39ce8b9e2. + + Fix a memory leak due to allocation in the XDR layer. In cases where the + RPC call needs to be retransmitted, we end up allocating new pages without + clearing the old ones. Fix this by moving the allocation into + nfs3_proc_setacls(). + + Also fix an issue discovered by Kevin Rudd, whereby the amount of memory + reserved for the acls in the xdr_buf->head was miscalculated, and causing + corruption. + +Signed-off-by: Trond Myklebust +Signed-off-by: Suresh Jayaraman +--- + + fs/nfs/nfs3acl.c | 27 +++++++++++++++++++++------ + fs/nfs/nfs3xdr.c | 34 +++++++++++++--------------------- + include/linux/nfs_xdr.h | 2 ++ + include/linux/nfsacl.h | 3 +++ + 4 files changed, 39 insertions(+), 27 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3acl.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/nfs3acl.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3acl.c +@@ -291,7 +291,7 @@ static int nfs3_proc_setacls(struct inod + { + struct nfs_server *server = NFS_SERVER(inode); + struct nfs_fattr fattr; +- struct page *pages[NFSACL_MAXPAGES] = { }; ++ struct page *pages[NFSACL_MAXPAGES]; + struct nfs3_setaclargs args = { + .inode = inode, + .mask = NFS_ACL, +@@ -302,7 +302,7 @@ static int nfs3_proc_setacls(struct inod + .rpc_argp = &args, + .rpc_resp = &fattr, + }; +- int status, count; ++ int status; + + status = -EOPNOTSUPP; + if (!nfs_server_capable(inode, NFS_CAP_ACLS)) +@@ -318,6 +318,20 @@ static int nfs3_proc_setacls(struct inod + if (S_ISDIR(inode->i_mode)) { + args.mask |= NFS_DFACL; + args.acl_default = dfacl; ++ args.len = nfsacl_size(acl, dfacl); ++ } else ++ args.len = nfsacl_size(acl, NULL); ++ ++ if (args.len > NFS_ACL_INLINE_BUFSIZE) { ++ unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT); ++ ++ status = -ENOMEM; ++ do { ++ args.pages[args.npages] = alloc_page(GFP_KERNEL); ++ if (args.pages[args.npages] == NULL) ++ goto out_freepages; ++ args.npages++; ++ } while (args.npages < npages); + } + + dprintk("NFS call setacl\n"); +@@ -327,10 +341,6 @@ static int nfs3_proc_setacls(struct inod + nfs_zap_acl_cache(inode); + dprintk("NFS reply setacl: %d\n", status); + +- /* pages may have been allocated at the xdr layer. */ +- for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) +- __free_page(args.pages[count]); +- + switch (status) { + case 0: + status = nfs_refresh_inode(inode, &fattr); +@@ -344,6 +354,11 @@ static int nfs3_proc_setacls(struct inod + case -ENOTSUPP: + status = -EOPNOTSUPP; + } ++out_freepages: ++ while (args.npages != 0) { ++ args.npages--; ++ __free_page(args.pages[args.npages]); ++ } + out: + return status; + } +Index: linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3xdr.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/nfs3xdr.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3xdr.c +@@ -82,8 +82,10 @@ + #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) + + #define ACL3_getaclargs_sz (NFS3_fh_sz+1) +-#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3)) +-#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3)) ++#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \ ++ XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) ++#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \ ++ XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)) + #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz) + + /* +@@ -703,28 +705,18 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req + struct nfs3_setaclargs *args) + { + struct xdr_buf *buf = &req->rq_snd_buf; +- unsigned int base, len_in_head, len = nfsacl_size( +- (args->mask & NFS_ACL) ? args->acl_access : NULL, +- (args->mask & NFS_DFACL) ? args->acl_default : NULL); +- int count, err; ++ unsigned int base; ++ int err; + + p = xdr_encode_fhandle(p, NFS_FH(args->inode)); + *p++ = htonl(args->mask); +- base = (char *)p - (char *)buf->head->iov_base; +- /* put as much of the acls into head as possible. */ +- len_in_head = min_t(unsigned int, buf->head->iov_len - base, len); +- len -= len_in_head; +- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2)); +- +- for (count = 0; (count << PAGE_SHIFT) < len; count++) { +- args->pages[count] = alloc_page(GFP_KERNEL); +- if (!args->pages[count]) { +- while (count) +- __free_page(args->pages[--count]); +- return -ENOMEM; +- } +- } +- xdr_encode_pages(buf, args->pages, 0, len); ++ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); ++ base = req->rq_slen; ++ ++ if (args->npages != 0) ++ xdr_encode_pages(buf, args->pages, 0, args->len); ++ else ++ req->rq_slen += args->len; + + err = nfsacl_encode(buf, base, args->inode, + (args->mask & NFS_ACL) ? +Index: linux-2.6.27-SLE11_BRANCH/include/linux/nfs_xdr.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/nfs_xdr.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/nfs_xdr.h +@@ -404,6 +404,8 @@ struct nfs3_setaclargs { + int mask; + struct posix_acl * acl_access; + struct posix_acl * acl_default; ++ size_t len; ++ unsigned int npages; + struct page ** pages; + }; + +Index: linux-2.6.27-SLE11_BRANCH/include/linux/nfsacl.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/nfsacl.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/nfsacl.h +@@ -37,6 +37,9 @@ + #define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \ + >> PAGE_SHIFT) + ++#define NFS_ACL_MAX_ENTRIES_INLINE (5) ++#define NFS_ACL_INLINE_BUFSIZE ((2*(2+3*NFS_ACL_MAX_ENTRIES_INLINE)) << 2) ++ + static inline unsigned int + nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-handle-ESTALE-on-ACCESS b/src/patches/suse-2.6.27.31/patches.fixes/nfs-handle-ESTALE-on-ACCESS new file mode 100644 index 000000000..00bb3588d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-handle-ESTALE-on-ACCESS @@ -0,0 +1,66 @@ +From: Suresh Jayaraman +Subject: NFS: Handle -ESTALE error in access() +References: 465955 +Patch-mainline: 2.6.29-rc7 + +Upstream commit a71ee337b31271e701f689d544b6153b75609bc5. + +Hi Trond, + + I have been looking at a bugreport where trying to open applications on KDE + on a NFS mounted home fails temporarily. There have been multiple reports on + different kernel versions pointing to this common issue: + http://bugzilla.kernel.org/show_bug.cgi?id=12557 + https://bugs.launchpad.net/ubuntu/+source/linux/+bug/269954 + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=508866.html + + This issue can be reproducible consistently by doing this on a NFS mounted + home (KDE): + 1. Open 2 xterm sessions + 2. From one of the xterm session, do "ssh -X " + 3. "stat ~/.Xauthority" on the remote SSH session + 4. Close the two xterm sessions + 5. On the server do a "stat ~/.Xauthority" + 6. Now on the client, try to open xterm + This will fail. + + Even if the filehandle had become stale, the NFS client should invalidate + the cache/inode and should repeat LOOKUP. Looking at the packet capture when + the failure occurs shows that there were two subsequent ACCESS() calls with + the same filehandle and both fails with -ESTALE error. + + I have tested the fix below. Now the client issue a LOOKUP after the + ACCESS() call fails with -ESTALE. If all this makes sense to you, can you + consider this for inclusion? + + If the server returns an -ESTALE error due to stale filehandle in response to + an ACCESS() call, we need to invalidate the cache and inode so that LOOKUP() + can be retried. Without this change, the nfs client retries ACCESS() with the + same filehandle, fails again and could lead to temporary failure of + applications running on nfs mounted home. + +Signed-off-by: Suresh Jayaraman +Signed-off-by: Trond Myklebust +--- + + fs/nfs/dir.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -1879,8 +1879,14 @@ static int nfs_do_access(struct inode *i + cache.cred = cred; + cache.jiffies = jiffies; + status = NFS_PROTO(inode)->access(inode, &cache); +- if (status != 0) ++ if (status != 0) { ++ if (status == -ESTALE) { ++ nfs_zap_caches(inode); ++ if (!S_ISDIR(inode->i_mode)) ++ set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); ++ } + return status; ++ } + nfs_access_add_cache(inode, &cache); + out: + if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-lock-release-lockargs b/src/patches/suse-2.6.27.31/patches.fixes/nfs-lock-release-lockargs new file mode 100644 index 000000000..5ca83e403 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-lock-release-lockargs @@ -0,0 +1,70 @@ +From: Felix Blyakher +Patch-mainline: queued for 2.6.31 +References: bnc#501651 +Date: Tue, 31 Mar 2009 20:12:56 +0000 (-0500) +Subject: lockd: call locks_release_private to cleanup per-filesystem state +X-Git-Url: http://git.linux-nfs.org/?p=bfields%2Flinux.git;a=commitdiff_plain;h=a9e61e25f9d2e7e43bf17625f5cb56c9e0a89b17 + +lockd: call locks_release_private to cleanup per-filesystem state + +For every lock request lockd creates a new file_lock object +in nlmsvc_setgrantargs() by copying the passed in file_lock with +locks_copy_lock(). A filesystem can attach it's own lock_operations +vector to the file_lock. It has to be cleaned up at the end of the +file_lock's life. However, lockd doesn't do it today, yet it +asserts in nlmclnt_release_lockargs() that the per-filesystem +state is clean. +This patch fixes it by exporting locks_release_private() and adding +it to nlmsvc_freegrantargs(), to be symmetrical to creating a +file_lock in nlmsvc_setgrantargs(). + +Signed-off-by: Felix Blyakher + +Acked-by: NeilBrown + +--- + fs/lockd/svclock.c | 2 ++ + fs/locks.c | 3 ++- + include/linux/fs.h | 1 + + 3 files changed, 5 insertions(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/lockd/svclock.c ++++ linux-2.6.27-SLE11_BRANCH/fs/lockd/svclock.c +@@ -326,6 +326,8 @@ static void nlmsvc_freegrantargs(struct + { + if (call->a_args.lock.oh.data != call->a_owner) + kfree(call->a_args.lock.oh.data); ++ ++ locks_release_private(&call->a_args.lock.fl); + } + + /* +--- linux-2.6.27-SLE11_BRANCH.orig/fs/locks.c ++++ linux-2.6.27-SLE11_BRANCH/fs/locks.c +@@ -151,7 +151,7 @@ static struct file_lock *locks_alloc_loc + return kmem_cache_alloc(filelock_cache, GFP_KERNEL); + } + +-static void locks_release_private(struct file_lock *fl) ++void locks_release_private(struct file_lock *fl) + { + if (fl->fl_ops) { + if (fl->fl_ops->fl_release_private) +@@ -165,6 +165,7 @@ static void locks_release_private(struct + } + + } ++EXPORT_SYMBOL_GPL(locks_release_private); + + /* Free a lock which is not in use. */ + static void locks_free_lock(struct file_lock *fl) +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/fs.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/fs.h +@@ -1015,6 +1015,7 @@ extern void locks_copy_lock(struct file_ + extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); + extern void locks_remove_posix(struct file *, fl_owner_t); + extern void locks_remove_flock(struct file *); ++extern void locks_release_private(struct file_lock *); + extern void posix_test_lock(struct file *, struct file_lock *); + extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); + extern int posix_lock_file_wait(struct file *, struct file_lock *); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-write.c-bug-removal.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfs-write.c-bug-removal.patch new file mode 100644 index 000000000..edebc1881 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfs-write.c-bug-removal.patch @@ -0,0 +1,170 @@ +From: ffilz@us.ibm.com +Subject: Revert "NFS: Allow redirtying of a completed unstable write." +Patch-mainline: REVERT patch from 2.6.27 +References: 442267 + +mainline commit e468bae97d243fe0e1515abaa1f7d0edf1476ad0 +introduces a BUG() that is apprently fairly easy to trigger. +As it is just making a minor performance enhancement, it is best to +revert the patch until the issue is better understood. + +Acked-by: NeilBrown +Signed-off-by: Neil Brown + +--- + fs/nfs/write.c | 65 ++++++++++++++++++++++++++++----------------------------- + 1 file changed, 33 insertions(+), 32 deletions(-) + +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -282,9 +282,12 @@ static int nfs_page_async_flush(struct n + return ret; + spin_lock(&inode->i_lock); + } +- if (test_bit(PG_CLEAN, &req->wb_flags)) { ++ if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { ++ /* This request is marked for commit */ + spin_unlock(&inode->i_lock); +- BUG(); ++ nfs_clear_page_tag_locked(req); ++ nfs_pageio_complete(pgio); ++ return 0; + } + if (nfs_set_page_writeback(page) != 0) { + spin_unlock(&inode->i_lock); +@@ -458,6 +461,19 @@ nfs_mark_request_dirty(struct nfs_page * + __set_page_dirty_nobuffers(req->wb_page); + } + ++/* ++ * Check if a request is dirty ++ */ ++static inline int ++nfs_dirty_request(struct nfs_page *req) ++{ ++ struct page *page = req->wb_page; ++ ++ if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags)) ++ return 0; ++ return !PageWriteback(page); ++} ++ + #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) + /* + * Add a request to the inode's commit list. +@@ -470,7 +486,7 @@ nfs_mark_request_commit(struct nfs_page + + spin_lock(&inode->i_lock); + nfsi->ncommit++; +- set_bit(PG_CLEAN, &(req)->wb_flags); ++ set_bit(PG_NEED_COMMIT, &(req)->wb_flags); + radix_tree_tag_set(&nfsi->nfs_page_tree, + req->wb_index, + NFS_PAGE_TAG_COMMIT); +@@ -481,19 +497,6 @@ nfs_mark_request_commit(struct nfs_page + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + } + +-static int +-nfs_clear_request_commit(struct nfs_page *req) +-{ +- struct page *page = req->wb_page; +- +- if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) { +- dec_zone_page_state(page, NR_UNSTABLE_NFS); +- dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE); +- return 1; +- } +- return 0; +-} +- + static inline + int nfs_write_need_commit(struct nfs_write_data *data) + { +@@ -503,7 +506,7 @@ int nfs_write_need_commit(struct nfs_wri + static inline + int nfs_reschedule_unstable_write(struct nfs_page *req) + { +- if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { ++ if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { + nfs_mark_request_commit(req); + return 1; + } +@@ -519,12 +522,6 @@ nfs_mark_request_commit(struct nfs_page + { + } + +-static inline int +-nfs_clear_request_commit(struct nfs_page *req) +-{ +- return 0; +-} +- + static inline + int nfs_write_need_commit(struct nfs_write_data *data) + { +@@ -582,8 +579,11 @@ static void nfs_cancel_commit_list(struc + + while(!list_empty(head)) { + req = nfs_list_entry(head->next); ++ dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); ++ dec_bdi_stat(req->wb_page->mapping->backing_dev_info, ++ BDI_RECLAIMABLE); + nfs_list_remove_request(req); +- nfs_clear_request_commit(req); ++ clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); + nfs_inode_remove_request(req); + nfs_unlock_request(req); + } +@@ -655,7 +655,8 @@ static struct nfs_page *nfs_try_to_updat + * Note: nfs_flush_incompatible() will already + * have flushed out requests having wrong owners. + */ +- if (offset > rqend ++ if (!nfs_dirty_request(req) ++ || offset > rqend + || end < req->wb_offset) + goto out_flushme; + +@@ -671,10 +672,6 @@ static struct nfs_page *nfs_try_to_updat + spin_lock(&inode->i_lock); + } + +- if (nfs_clear_request_commit(req)) +- radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, +- req->wb_index, NFS_PAGE_TAG_COMMIT); +- + /* Okay, the request matches. Update the region */ + if (offset < req->wb_offset) { + req->wb_offset = offset; +@@ -756,7 +753,8 @@ int nfs_flush_incompatible(struct file * + req = nfs_page_find_request(page); + if (req == NULL) + return 0; +- do_flush = req->wb_page != page || req->wb_context != ctx; ++ do_flush = req->wb_page != page || req->wb_context != ctx ++ || !nfs_dirty_request(req); + nfs_release_request(req); + if (!do_flush) + return 0; +@@ -1361,7 +1359,10 @@ static void nfs_commit_release(void *cal + while (!list_empty(&data->pages)) { + req = nfs_list_entry(data->pages.next); + nfs_list_remove_request(req); +- nfs_clear_request_commit(req); ++ clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); ++ dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); ++ dec_bdi_stat(req->wb_page->mapping->backing_dev_info, ++ BDI_RECLAIMABLE); + + dprintk("NFS: commit (%s/%lld %d@%lld)", + req->wb_context->path.dentry->d_inode->i_sb->s_id, +@@ -1537,7 +1538,7 @@ int nfs_wb_page_cancel(struct inode *ino + req = nfs_page_find_request(page); + if (req == NULL) + goto out; +- if (test_bit(PG_CLEAN, &req->wb_flags)) { ++ if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { + nfs_release_request(req); + break; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-01-sunrpc-cache-simplify-cache_fresh_locked-and-cache_f.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-01-sunrpc-cache-simplify-cache_fresh_locked-and-cache_f.patch new file mode 100644 index 000000000..8d93b3cb0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-01-sunrpc-cache-simplify-cache_fresh_locked-and-cache_f.patch @@ -0,0 +1,94 @@ +Patch-mainline: submitted 4aug09 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:37 +1000 +Subject: [PATCH 03/12] sunrpc/cache: simplify cache_fresh_locked and cache_fresh_unlocked. + +The extra call to cache_revisit_request in cache_fresh_unlocked is not +needed, as should have been fairly clear at the time of + commit 4013edea9a0b6cdcb1fdf5d4011e47e068fd6efb + +If there are requests to be revisited, then we can be sure that +CACHE_PENDING is set, so the second call is sufficient. + +So remove the first call. +Then remove the 'new' parameter, +then remove the return value for cache_fresh_locked which is only used +to provide the value for 'new'. + +Signed-off-by: NeilBrown + +--- + net/sunrpc/cache.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/cache.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/cache.c +@@ -103,18 +103,16 @@ EXPORT_SYMBOL(sunrpc_cache_lookup); + + static void queue_loose(struct cache_detail *detail, struct cache_head *ch); + +-static int cache_fresh_locked(struct cache_head *head, time_t expiry) ++static void cache_fresh_locked(struct cache_head *head, time_t expiry) + { + head->expiry_time = expiry; + head->last_refresh = get_seconds(); +- return !test_and_set_bit(CACHE_VALID, &head->flags); ++ set_bit(CACHE_VALID, &head->flags); + } + + static void cache_fresh_unlocked(struct cache_head *head, +- struct cache_detail *detail, int new) ++ struct cache_detail *detail) + { +- if (new) +- cache_revisit_request(head); + if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { + cache_revisit_request(head); + queue_loose(detail, head); +@@ -130,7 +128,6 @@ struct cache_head *sunrpc_cache_update(s + */ + struct cache_head **head; + struct cache_head *tmp; +- int is_new; + + if (!test_bit(CACHE_VALID, &old->flags)) { + write_lock(&detail->hash_lock); +@@ -139,9 +136,9 @@ struct cache_head *sunrpc_cache_update(s + set_bit(CACHE_NEGATIVE, &old->flags); + else + detail->update(old, new); +- is_new = cache_fresh_locked(old, new->expiry_time); ++ cache_fresh_locked(old, new->expiry_time); + write_unlock(&detail->hash_lock); +- cache_fresh_unlocked(old, detail, is_new); ++ cache_fresh_unlocked(old, detail); + return old; + } + write_unlock(&detail->hash_lock); +@@ -165,11 +162,11 @@ struct cache_head *sunrpc_cache_update(s + *head = tmp; + detail->entries++; + cache_get(tmp); +- is_new = cache_fresh_locked(tmp, new->expiry_time); ++ cache_fresh_locked(tmp, new->expiry_time); + cache_fresh_locked(old, 0); + write_unlock(&detail->hash_lock); +- cache_fresh_unlocked(tmp, detail, is_new); +- cache_fresh_unlocked(old, detail, 0); ++ cache_fresh_unlocked(tmp, detail); ++ cache_fresh_unlocked(old, detail); + cache_put(old, detail); + return tmp; + } +@@ -223,8 +220,8 @@ int cache_check(struct cache_detail *det + clear_bit(CACHE_PENDING, &h->flags); + if (rv == -EAGAIN) { + set_bit(CACHE_NEGATIVE, &h->flags); +- cache_fresh_unlocked(h, detail, +- cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); ++ cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY); ++ cache_fresh_unlocked(h, detail); + rv = -ENOENT; + } + break; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-02-sunrpc-cache-recheck-cache-validity-after-cache_defe.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-02-sunrpc-cache-recheck-cache-validity-after-cache_defe.patch new file mode 100644 index 000000000..a6fcb278a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-02-sunrpc-cache-recheck-cache-validity-after-cache_defe.patch @@ -0,0 +1,117 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:37 +1000 +Subject: [PATCH 04/12] sunrpc/cache: recheck cache validity after cache_defer_req + +If cache_defer_req did not leave the request on a queue, then it could +possibly have waited long enough that the cache became valid. So check the +status after the call. + +Signed-off-by: NeilBrown + +--- + net/sunrpc/cache.c | 53 +++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 33 insertions(+), 20 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/cache.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/cache.c +@@ -173,6 +173,22 @@ struct cache_head *sunrpc_cache_update(s + EXPORT_SYMBOL(sunrpc_cache_update); + + static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); ++ ++static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) ++{ ++ if (!test_bit(CACHE_VALID, &h->flags) || ++ h->expiry_time < get_seconds()) ++ return -EAGAIN; ++ else if (detail->flush_time > h->last_refresh) ++ return -EAGAIN; ++ else { ++ /* entry is valid */ ++ if (test_bit(CACHE_NEGATIVE, &h->flags)) ++ return -ENOENT; ++ else ++ return 0; ++ } ++} + /* + * This is the generic cache management routine for all + * the authentication caches. +@@ -181,8 +197,10 @@ static int cache_make_upcall(struct cach + * + * + * Returns 0 if the cache_head can be used, or cache_puts it and returns +- * -EAGAIN if upcall is pending, +- * -ETIMEDOUT if upcall failed and should be retried, ++ * -EAGAIN if upcall is pending and request has been queued ++ * -ETIMEDOUT if upcall failed or request could not be queue or ++ * upcall completed but item is still invalid (implying that ++ * the cache item has been replaced with a newer one). + * -ENOENT if cache entry was negative + */ + int cache_check(struct cache_detail *detail, +@@ -192,17 +210,7 @@ int cache_check(struct cache_detail *det + long refresh_age, age; + + /* First decide return status as best we can */ +- if (!test_bit(CACHE_VALID, &h->flags) || +- h->expiry_time < get_seconds()) +- rv = -EAGAIN; +- else if (detail->flush_time > h->last_refresh) +- rv = -EAGAIN; +- else { +- /* entry is valid */ +- if (test_bit(CACHE_NEGATIVE, &h->flags)) +- rv = -ENOENT; +- else rv = 0; +- } ++ rv = cache_is_valid(detail, h); + + /* now see if we want to start an upcall */ + refresh_age = (h->expiry_time - h->last_refresh); +@@ -234,10 +242,14 @@ int cache_check(struct cache_detail *det + } + } + +- if (rv == -EAGAIN) +- if (cache_defer_req(rqstp, h) != 0) +- rv = -ETIMEDOUT; +- ++ if (rv == -EAGAIN) { ++ if (cache_defer_req(rqstp, h) == 0) { ++ /* Request is not deferred */ ++ rv = cache_is_valid(detail, h); ++ if (rv == -EAGAIN) ++ rv = -ETIMEDOUT; ++ } ++ } + if (rv) + cache_put(h, detail); + return rv; +@@ -558,11 +570,11 @@ static int cache_defer_req(struct cache_ + * or continue and drop the oldest below + */ + if (net_random()&1) +- return -ETIMEDOUT; ++ return 0; + } + dreq = req->defer(req); + if (dreq == NULL) +- return -ETIMEDOUT; ++ return 0; + + dreq->item = item; + +@@ -592,8 +604,9 @@ static int cache_defer_req(struct cache_ + if (!test_bit(CACHE_PENDING, &item->flags)) { + /* must have just been validated... */ + cache_revisit_request(item); ++ return 0; + } +- return 0; ++ return 1; + } + + static void cache_revisit_request(struct cache_head *item) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-03-sunrpc-cache-use-list_del_init-for-the-list_head-ent.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-03-sunrpc-cache-use-list_del_init-for-the-list_head-ent.patch new file mode 100644 index 000000000..ee0ad0f6d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-03-sunrpc-cache-use-list_del_init-for-the-list_head-ent.patch @@ -0,0 +1,47 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:38 +1000 +Subject: [PATCH 05/12] sunrpc/cache: use list_del_init for the list_head entries in cache_deferred_req + +Using list_del_init is generally safer than list_del, and it will +allow us, in the next patch, to see if an entry has already been +processed or not. + +Signed-off-by: NeilBrown + +--- + net/sunrpc/cache.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/cache.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/cache.c +@@ -591,8 +591,8 @@ static int cache_defer_req(struct cache_ + if (++cache_defer_cnt > DFR_MAX) { + dreq = list_entry(cache_defer_list.prev, + struct cache_deferred_req, recent); +- list_del(&dreq->recent); +- list_del(&dreq->hash); ++ list_del_init(&dreq->recent); ++ list_del_init(&dreq->hash); + cache_defer_cnt--; + } + spin_unlock(&cache_defer_lock); +@@ -626,7 +626,7 @@ static void cache_revisit_request(struct + dreq = list_entry(lp, struct cache_deferred_req, hash); + lp = lp->next; + if (dreq->item == item) { +- list_del(&dreq->hash); ++ list_del_init(&dreq->hash); + list_move(&dreq->recent, &pending); + cache_defer_cnt--; + } +@@ -652,7 +652,7 @@ void cache_clean_deferred(void *owner) + + list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { + if (dreq->owner == owner) { +- list_del(&dreq->hash); ++ list_del_init(&dreq->hash); + list_move(&dreq->recent, &pending); + cache_defer_cnt--; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-04-sunrpc-cache-avoid-variable-over-loading-in-cache_de.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-04-sunrpc-cache-avoid-variable-over-loading-in-cache_de.patch new file mode 100644 index 000000000..2c96296fd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-04-sunrpc-cache-avoid-variable-over-loading-in-cache_de.patch @@ -0,0 +1,59 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:38 +1000 +Subject: [PATCH 06/12] sunrpc/cache: avoid variable over-loading in cache_defer_req + +In cache_defer_req, 'dreq' is used for two significantly different +values that happen to be of the same type. + +This is both confusing, and make it hard to extend the range of one of +the values as we will in the next patch. +So introduce 'discard' to take one of the values. + +Signed-off-by: NeilBrown + +--- + net/sunrpc/cache.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/cache.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/cache.c +@@ -562,7 +562,7 @@ static int cache_defer_cnt; + + static int cache_defer_req(struct cache_req *req, struct cache_head *item) + { +- struct cache_deferred_req *dreq; ++ struct cache_deferred_req *dreq, *discard; + int hash = DFR_HASH(item); + + if (cache_defer_cnt >= DFR_MAX) { +@@ -587,20 +587,20 @@ static int cache_defer_req(struct cache_ + list_add(&dreq->hash, &cache_defer_hash[hash]); + + /* it is in, now maybe clean up */ +- dreq = NULL; ++ discard = NULL; + if (++cache_defer_cnt > DFR_MAX) { +- dreq = list_entry(cache_defer_list.prev, +- struct cache_deferred_req, recent); ++ discard = list_entry(cache_defer_list.prev, ++ struct cache_deferred_req, recent); +- list_del_init(&dreq->recent); +- list_del_init(&dreq->hash); ++ list_del_init(&discard->recent); ++ list_del_init(&discard->hash); + cache_defer_cnt--; + } + spin_unlock(&cache_defer_lock); + +- if (dreq) { ++ if (discard) + /* there was one too many */ +- dreq->revisit(dreq, 1); +- } ++ discard->revisit(discard, 1); ++ + if (!test_bit(CACHE_PENDING, &item->flags)) { + /* must have just been validated... */ + cache_revisit_request(item); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-05-sunrpc-cache-allow-thread-to-block-while-waiting-for.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-05-sunrpc-cache-allow-thread-to-block-while-waiting-for.patch new file mode 100644 index 000000000..5ace31d1a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-05-sunrpc-cache-allow-thread-to-block-while-waiting-for.patch @@ -0,0 +1,149 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:38 +1000 +Subject: [PATCH 07/12] sunrpc/cache: allow thread to block while waiting for cache update. + +The current practice of waiting for cache updates by queueing the +whole request to be retried has (at least) two problems. + +1/ We NFSv4, requests can be quite complex and re-trying a whole + request when a later part fails should only be a list-resort, not a + normal practice. + +2/ Large requests, and in particular any 'write' request, will not be + queued by the current code and doing so would be undesirable. + +In many cases only a very sort wait is needed before the cache gets +valid data. + +So, providing the underlying transport permits it by setting + ->thread_wait, +arrange to wait briefly for an upcall to be completed (as reflected in +the clearing of CACHE_PENDING). +If the short wait was not long enough and CACHE_PENDING is still set, +fall back on the old approach. + +The 'thread_wait' value is set to 5 seconds when there are spare +threads, and 1 second when there are no spare threads. + +These values are probably much higher than needed, but will ensure +some forward progress. + +Signed-off-by: NeilBrown + +--- + include/linux/sunrpc/cache.h | 3 ++ + net/sunrpc/cache.c | 44 ++++++++++++++++++++++++++++++++++++++++++- + net/sunrpc/svc_xprt.c | 11 ++++++++++ + 3 files changed, 57 insertions(+), 1 deletion(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/sunrpc/cache.h ++++ linux-2.6.27-SLE11_BRANCH/include/linux/sunrpc/cache.h +@@ -112,6 +112,9 @@ struct cache_detail { + */ + struct cache_req { + struct cache_deferred_req *(*defer)(struct cache_req *req); ++ int thread_wait; /* How long (jiffies) we can block the ++ * current thread to wait for updates. ++ */ + }; + /* this must be embedded in a deferred_request that is being + * delayed awaiting cache-fill +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/cache.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/cache.c +@@ -560,10 +560,22 @@ static LIST_HEAD(cache_defer_list); + static struct list_head cache_defer_hash[DFR_HASHSIZE]; + static int cache_defer_cnt; + ++struct thread_deferred_req { ++ struct cache_deferred_req handle; ++ wait_queue_head_t wait; ++}; ++static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many) ++{ ++ struct thread_deferred_req *dr = ++ container_of(dreq, struct thread_deferred_req, handle); ++ wake_up(&dr->wait); ++} ++ + static int cache_defer_req(struct cache_req *req, struct cache_head *item) + { + struct cache_deferred_req *dreq, *discard; + int hash = DFR_HASH(item); ++ struct thread_deferred_req sleeper; + + if (cache_defer_cnt >= DFR_MAX) { + /* too much in the cache, randomly drop this one, +@@ -572,7 +584,14 @@ static int cache_defer_req(struct cache_ + if (net_random()&1) + return 0; + } +- dreq = req->defer(req); ++ if (req->thread_wait) { ++ dreq = &sleeper.handle; ++ init_waitqueue_head(&sleeper.wait); ++ dreq->revisit = cache_restart_thread; ++ } else ++ dreq = req->defer(req); ++ ++ retry: + if (dreq == NULL) + return 0; + +@@ -606,6 +625,29 @@ static int cache_defer_req(struct cache_ + cache_revisit_request(item); + return 0; + } ++ ++ if (dreq == &sleeper.handle) { ++ wait_event_interruptible_timeout( ++ sleeper.wait, ++ !test_bit(CACHE_PENDING, &item->flags) ++ || list_empty(&sleeper.handle.hash), ++ req->thread_wait); ++ spin_lock(&cache_defer_lock); ++ if (!list_empty(&sleeper.handle.hash)) { ++ list_del_init(&sleeper.handle.recent); ++ list_del_init(&sleeper.handle.hash); ++ cache_defer_cnt--; ++ } ++ spin_unlock(&cache_defer_lock); ++ if (test_bit(CACHE_PENDING, &item->flags)) { ++ /* item is still pending, try request ++ * deferral ++ */ ++ dreq = req->defer(req); ++ goto retry; ++ } ++ return 0; ++ } + return 1; + } + +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/svc_xprt.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/svc_xprt.c +@@ -593,12 +593,23 @@ int svc_recv(struct svc_rqst *rqstp, lon + return -EINTR; + + spin_lock_bh(&pool->sp_lock); ++ ++ /* Normally we will wait up to 5 seconds for any required ++ * cache information to be provided. ++ */ ++ rqstp->rq_chandle.thread_wait = 5*HZ; + xprt = svc_xprt_dequeue(pool); + if (xprt) { + rqstp->rq_xprt = xprt; + svc_xprt_get(xprt); + rqstp->rq_reserved = serv->sv_max_mesg; + atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); ++ ++ /* As there is a shortage of threads and this request ++ * had to be queue, don't allow the thread to wait so ++ * long for cache updates. ++ */ ++ rqstp->rq_chandle.thread_wait = 1*HZ; + } else { + /* No data pending. Go to sleep */ + svc_thread_enqueue(pool, rqstp); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-06-sunrpc-cache-retry-cache-lookups-that-return-ETIMEDO.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-06-sunrpc-cache-retry-cache-lookups-that-return-ETIMEDO.patch new file mode 100644 index 000000000..078db781c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-06-sunrpc-cache-retry-cache-lookups-that-return-ETIMEDO.patch @@ -0,0 +1,122 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:38 +1000 +Subject: [PATCH 08/12] sunrpc/cache: retry cache lookups that return -ETIMEDOUT + +If cache_check returns -ETIMEDOUT, then the cache item is not +up-to-date, but there is no pending upcall. +This could mean the data is not available, or it could mean that the +good data has been stored in a new cache item. + +So re-do the lookup and if that returns a new item, proceed using that +item. + +Signed-off-by: NeilBrown + +--- + fs/nfsd/export.c | 18 ++++++++++++++++++ + net/sunrpc/svcauth_unix.c | 22 ++++++++++++++++++++-- + 2 files changed, 38 insertions(+), 2 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfsd/export.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfsd/export.c +@@ -796,9 +796,18 @@ exp_find_key(svc_client *clp, int fsid_t + memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); + + ek = svc_expkey_lookup(&key); ++ again: + if (ek == NULL) + return ERR_PTR(-ENOMEM); + err = cache_check(&svc_expkey_cache, &ek->h, reqp); ++ if (err == -ETIMEDOUT) { ++ struct svc_expkey *prev_ek = ek; ++ ek = svc_expkey_lookup(&key); ++ if (ek != prev_ek) ++ goto again; ++ if (ek) ++ cache_put(&ek->h, &svc_expkey_cache); ++ } + if (err) + return ERR_PTR(err); + return ek; +@@ -870,9 +879,18 @@ static svc_export *exp_get_by_name(svc_c + key.ex_path.dentry = dentry; + + exp = svc_export_lookup(&key); ++ retry: + if (exp == NULL) + return ERR_PTR(-ENOMEM); + err = cache_check(&svc_export_cache, &exp->h, reqp); ++ if (err == -ETIMEDOUT) { ++ struct svc_export *prev_exp = exp; ++ exp = svc_export_lookup(&key); ++ if (exp != prev_exp) ++ goto retry; ++ if (exp) ++ cache_put(&exp->h, &svc_export_cache); ++ } + if (err) + return ERR_PTR(err); + return exp; +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/svcauth_unix.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/svcauth_unix.c +@@ -659,8 +659,10 @@ static int unix_gid_find(uid_t uid, stru + struct svc_rqst *rqstp) + { + struct unix_gid *ug = unix_gid_lookup(uid); ++ struct unix_gid *prevug; + if (!ug) + return -EAGAIN; ++ retry: + switch (cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle)) { + case -ENOENT: + *gip = NULL; +@@ -669,6 +671,13 @@ static int unix_gid_find(uid_t uid, stru + *gip = ug->gi; + get_group_info(*gip); + return 0; ++ case -ETIMEDOUT: ++ prevug = ug; ++ ug = unix_gid_lookup(uid); ++ if (ug != prevug) ++ goto retry; ++ if (ug) ++ cache_put(&ug->h, &unix_gid_cache); + default: + return -EAGAIN; + } +@@ -679,7 +688,7 @@ svcauth_unix_set_client(struct svc_rqst + { + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6, sin6_storage; +- struct ip_map *ipm; ++ struct ip_map *ipm, *prev_ipm; + + switch (rqstp->rq_addr.ss_family) { + case AF_INET: +@@ -704,14 +713,23 @@ svcauth_unix_set_client(struct svc_rqst + ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, + &sin6->sin6_addr); + ++ retry: + if (ipm == NULL) + return SVC_DENIED; + + switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) { + default: + BUG(); +- case -EAGAIN: + case -ETIMEDOUT: ++ prev_ipm = ipm; ++ ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, ++ &sin6->sin6_addr); ++ if (ipm != prev_ipm) ++ goto retry; ++ if (ipm) ++ cache_put(&ipm->h, &ip_map_cache); ++ ++ case -EAGAIN: + return SVC_DROP; + case -ENOENT: + return SVC_DENIED; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-07-nfsd-idmap-drop-special-request-deferal-in-favour-of.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-07-nfsd-idmap-drop-special-request-deferal-in-favour-of.patch new file mode 100644 index 000000000..266855945 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-07-nfsd-idmap-drop-special-request-deferal-in-favour-of.patch @@ -0,0 +1,141 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:39 +1000 +Subject: [PATCH 09/12] nfsd/idmap: drop special request deferal in favour of improved default. + +The idmap code manages request deferal by waiting for a reply from +userspace rather than putting the NFS request on a queue to be retried +from the start. +Now that the comment deferal code does this there is no need for the +special code in idmap. + +Signed-off-by: NeilBrown + +--- + fs/nfsd/nfs4idmap.c | 105 +++++----------------------------------------------- + 1 file changed, 11 insertions(+), 94 deletions(-) + +--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfsd/nfs4idmap.c ++++ linux-2.6.27-SLE11_BRANCH/fs/nfsd/nfs4idmap.c +@@ -485,109 +485,26 @@ nfsd_idmap_shutdown(void) + cache_unregister(&nametoid_cache); + } + +-/* +- * Deferred request handling +- */ +- +-struct idmap_defer_req { +- struct cache_req req; +- struct cache_deferred_req deferred_req; +- wait_queue_head_t waitq; +- atomic_t count; +-}; +- +-static inline void +-put_mdr(struct idmap_defer_req *mdr) +-{ +- if (atomic_dec_and_test(&mdr->count)) +- kfree(mdr); +-} +- +-static inline void +-get_mdr(struct idmap_defer_req *mdr) +-{ +- atomic_inc(&mdr->count); +-} +- +-static void +-idmap_revisit(struct cache_deferred_req *dreq, int toomany) +-{ +- struct idmap_defer_req *mdr = +- container_of(dreq, struct idmap_defer_req, deferred_req); +- +- wake_up(&mdr->waitq); +- put_mdr(mdr); +-} +- +-static struct cache_deferred_req * +-idmap_defer(struct cache_req *req) +-{ +- struct idmap_defer_req *mdr = +- container_of(req, struct idmap_defer_req, req); +- +- mdr->deferred_req.revisit = idmap_revisit; +- get_mdr(mdr); +- return (&mdr->deferred_req); +-} +- +-static inline int +-do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key, +- struct cache_detail *detail, struct ent **item, +- struct idmap_defer_req *mdr) +-{ +- *item = lookup_fn(key); +- if (!*item) +- return -ENOMEM; +- return cache_check(detail, &(*item)->h, &mdr->req); +-} +- +-static inline int +-do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *), +- struct ent *key, struct cache_detail *detail, +- struct ent **item) +-{ +- int ret = -ENOMEM; +- +- *item = lookup_fn(key); +- if (!*item) +- goto out_err; +- ret = -ETIMEDOUT; +- if (!test_bit(CACHE_VALID, &(*item)->h.flags) +- || (*item)->h.expiry_time < get_seconds() +- || detail->flush_time > (*item)->h.last_refresh) +- goto out_put; +- ret = -ENOENT; +- if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) +- goto out_put; +- return 0; +-out_put: +- cache_put(&(*item)->h, detail); +-out_err: +- *item = NULL; +- return ret; +-} +- + static int + idmap_lookup(struct svc_rqst *rqstp, + struct ent *(*lookup_fn)(struct ent *), struct ent *key, + struct cache_detail *detail, struct ent **item) + { +- struct idmap_defer_req *mdr; + int ret; + +- mdr = kzalloc(sizeof(*mdr), GFP_KERNEL); +- if (!mdr) ++ *item = lookup_fn(key); ++ if (!*item) + return -ENOMEM; +- atomic_set(&mdr->count, 1); +- init_waitqueue_head(&mdr->waitq); +- mdr->req.defer = idmap_defer; +- ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr); +- if (ret == -EAGAIN) { +- wait_event_interruptible_timeout(mdr->waitq, +- test_bit(CACHE_VALID, &(*item)->h.flags), 1 * HZ); +- ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item); ++ retry: ++ ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle); ++ ++ if (ret == -ETIMEDOUT) { ++ struct ent *prev_item = *item; ++ *item = lookup_fn(key); ++ if (*item != prev_item) ++ goto retry; ++ cache_put(&(*item)->h, detail); + } +- put_mdr(mdr); + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-08-sunrpc-fix-memory-leak-in-unix_gid-cache.patch b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-08-sunrpc-fix-memory-leak-in-unix_gid-cache.patch new file mode 100644 index 000000000..4d6ce858b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-08-sunrpc-fix-memory-leak-in-unix_gid-cache.patch @@ -0,0 +1,26 @@ +Patch-mainline: submitted 04aug2009 +References: bnc#498708 +From: NeilBrown +Date: Tue, 4 Aug 2009 15:06:39 +1000 +Subject: [PATCH 10/12] sunrpc: fix memory leak in unix_gid cache. + +When we look up an entry in the uid->gidlist cache, we take +a reference to the content but don't drop the reference to the +cache entry. So it never gets freed. + +Signed-off-by: NeilBrown + +--- + net/sunrpc/svcauth_unix.c | 1 + + 1 file changed, 1 insertion(+) + +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/svcauth_unix.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/svcauth_unix.c +@@ -670,6 +670,7 @@ static int unix_gid_find(uid_t uid, stru + case 0: + *gip = ug->gi; + get_group_info(*gip); ++ cache_put(&ug->h, &unix_gid_cache); + return 0; + case -ETIMEDOUT: + prevug = ug; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfsd-09-fix-kabi b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-09-fix-kabi new file mode 100644 index 000000000..8eb6c6db7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nfsd-09-fix-kabi @@ -0,0 +1,89 @@ +From: NeilBrown + +--- + include/linux/sunrpc/cache.h | 3 --- + net/sunrpc/cache.c | 12 +++++------- + net/sunrpc/svc_xprt.c | 9 --------- + 3 files changed, 5 insertions(+), 19 deletions(-) + +--- linux-2.6.27-working.orig/include/linux/sunrpc/cache.h ++++ linux-2.6.27-working/include/linux/sunrpc/cache.h +@@ -112,9 +112,6 @@ struct cache_detail { + */ + struct cache_req { + struct cache_deferred_req *(*defer)(struct cache_req *req); +- int thread_wait; /* How long (jiffies) we can block the +- * current thread to wait for updates. +- */ + }; + /* this must be embedded in a deferred_request that is being + * delayed awaiting cache-fill +--- linux-2.6.27-working.orig/net/sunrpc/cache.c ++++ linux-2.6.27-working/net/sunrpc/cache.c +@@ -584,12 +584,10 @@ static int cache_defer_req(struct cache_ + if (net_random()&1) + return 0; + } +- if (req->thread_wait) { +- dreq = &sleeper.handle; +- init_waitqueue_head(&sleeper.wait); +- dreq->revisit = cache_restart_thread; +- } else +- dreq = req->defer(req); ++ ++ dreq = &sleeper.handle; ++ init_waitqueue_head(&sleeper.wait); ++ dreq->revisit = cache_restart_thread; + + retry: + if (dreq == NULL) +@@ -631,7 +629,7 @@ static int cache_defer_req(struct cache_ + sleeper.wait, + !test_bit(CACHE_PENDING, &item->flags) + || list_empty(&sleeper.handle.hash), +- req->thread_wait); ++ 3*HZ); + spin_lock(&cache_defer_lock); + if (!list_empty(&sleeper.handle.hash)) { + list_del_init(&sleeper.handle.recent); +--- linux-2.6.27-working.orig/net/sunrpc/svc_xprt.c ++++ linux-2.6.27-working/net/sunrpc/svc_xprt.c +@@ -594,10 +594,6 @@ int svc_recv(struct svc_rqst *rqstp, lon + + spin_lock_bh(&pool->sp_lock); + +- /* Normally we will wait up to 5 seconds for any required +- * cache information to be provided. +- */ +- rqstp->rq_chandle.thread_wait = 5*HZ; + xprt = svc_xprt_dequeue(pool); + if (xprt) { + rqstp->rq_xprt = xprt; +@@ -605,11 +601,6 @@ int svc_recv(struct svc_rqst *rqstp, lon + rqstp->rq_reserved = serv->sv_max_mesg; + atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); + +- /* As there is a shortage of threads and this request +- * had to be queue, don't allow the thread to wait so +- * long for cache updates. +- */ +- rqstp->rq_chandle.thread_wait = 1*HZ; + } else { + /* No data pending. Go to sleep */ + svc_thread_enqueue(pool, rqstp); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/no-sys_uv-on-non-uv-systems b/src/patches/suse-2.6.27.31/patches.fixes/no-sys_uv-on-non-uv-systems new file mode 100644 index 000000000..339379ce3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/no-sys_uv-on-non-uv-systems @@ -0,0 +1,35 @@ +From: Russ Anderson +Subject: [PATCH] sgi_uv: Don't publish /sys/firmware/sgi_uv on !uv systems +References: bnc#482506 +Patch-mainline: Submitted Mar 6 2009 by SGI + + MPT testing of sles11 found /sys/firmware/sgi_uv gets created on non-UV x86_64 + systems. This confuses MPT which uses /sys/firmware/sgi_uv to indicate the + platform is a UV system. + +Acked-by: Jeff Mahoney +--- + + arch/x86/kernel/uv_sysfs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/x86/kernel/uv_sysfs.c ++++ b/arch/x86/kernel/uv_sysfs.c +@@ -21,6 +21,7 @@ + + #include + #include ++#include + + struct kobject *sgi_uv_kobj; + +@@ -46,6 +47,9 @@ + static int __init sgi_uv_sysfs_init(void) + { + unsigned long ret; ++ ++ if (!is_uv_system()) ++ return -ENODEV; + + if (!sgi_uv_kobj) + sgi_uv_kobj = kobject_create_and_add("sgi_uv", firmware_kobj); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nr-irqs-file b/src/patches/suse-2.6.27.31/patches.fixes/nr-irqs-file new file mode 100644 index 000000000..da4c78058 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/nr-irqs-file @@ -0,0 +1,14 @@ +From: schwab@suse.de +Subject: Don't clean + +--- a/arch/ia64/kernel/Makefile ++++ b/arch/ia64/kernel/Makefile +@@ -104,7 +104,7 @@ arch/$(SRCARCH)/kernel/nr-irqs.s: $(srctree)/arch/$(SRCARCH)/kernel/nr-irqs.c \ + $(Q)mkdir -p $(dir $@) + $(call cmd,nr_irqs) + +-clean-files += $(objtree)/arch/ia64/include/asm/nr-irqs.h ++MRPROPER_FILES += $(objtree)/arch/ia64/include/asm/nr-irqs.h + + # + # native ivt.S and entry.S diff --git a/src/patches/suse-2.6.27.31/patches.fixes/numa-enable-hashdist-default.patch b/src/patches/suse-2.6.27.31/patches.fixes/numa-enable-hashdist-default.patch new file mode 100644 index 000000000..d7b146e43 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/numa-enable-hashdist-default.patch @@ -0,0 +1,66 @@ +From: Anton Blanchard +Subject: mm: enable hashdist by default on 64bit NUMA +References: bnc#501160 +Patch-upstream: yes +Git: c2fdf3a9b2d52842808a8e551b53b55dd9b45030 + + mm: enable hashdist by default on 64bit NUMA + + On PowerPC we allocate large boot time hashes on node 0. This leads to an + imbalance in the free memory, for example on a 64GB box (4 x 16GB nodes): + + Free memory: + Node 0: 97.03% + Node 1: 98.54% + Node 2: 98.42% + Node 3: 98.53% + + If we switch to using vmalloc (like ia64 and x86-64) things are more + balanced: + + Free memory: + Node 0: 97.53% + Node 1: 98.35% + Node 2: 98.33% + Node 3: 98.33% + + For many HPC applications we are limited by the free available memory on + the smallest node, so even though the same amount of memory is used the + better balancing helps. + + Since all 64bit NUMA capable architectures should have sufficient vmalloc + space, it makes sense to enable it via CONFIG_64BIT. + + Signed-off-by: Anton Blanchard + Acked-by: David S. Miller + Acked-by: Benjamin Herrenschmidt + Acked-by: Ralf Baechle + Cc: Heiko Carstens + Cc: Martin Schwidefsky + Cc: Ivan Kokshaysky + Cc: Richard Henderson + Signed-off-by: Andrew Morton + Signed-off-by: Linus Torvalds + +Acked-by: Nick Piggin + +--- + include/linux/bootmem.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/include/linux/bootmem.h ++++ b/include/linux/bootmem.h +@@ -144,10 +144,10 @@ extern void *alloc_large_system_hash(con + + #define HASH_EARLY 0x00000001 /* Allocating during early boot? */ + +-/* Only NUMA needs hash distribution. +- * IA64 and x86_64 have sufficient vmalloc space. ++/* Only NUMA needs hash distribution. 64bit NUMA architectures have ++ * sufficient vmalloc space. + */ +-#if defined(CONFIG_NUMA) && (defined(CONFIG_IA64) || defined(CONFIG_X86_64)) ++#if defined(CONFIG_NUMA) && defined(CONFIG_64BIT) + #define HASHDIST_DEFAULT 1 + #else + #define HASHDIST_DEFAULT 0 diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-4e8a301929bfa017e6ffe11e3cf78ccaf8492801 b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-4e8a301929bfa017e6ffe11e3cf78ccaf8492801 new file mode 100644 index 000000000..72ce017d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-4e8a301929bfa017e6ffe11e3cf78ccaf8492801 @@ -0,0 +1,34 @@ +From: Jan Kara +Subject: ocfs2: Fix possible deadlock in ocfs2_global_read_dquot() +Patch-mainline: 2.6.31 + +It is not possible to get a read lock and then try to get the same write lock +in one thread as that can block on downconvert being requested by other node +leading to deadlock. So first drop the quota lock for reading and only after +that get it for writing. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota_global.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/ocfs2/quota_global.c ++++ b/fs/ocfs2/quota_global.c +@@ -354,6 +354,7 @@ int ocfs2_global_read_dquot(struct dquot + OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; + if (!dquot->dq_off) { /* No real quota entry? */ + /* Upgrade to exclusive lock for allocation */ ++ ocfs2_qinfo_unlock(info, 0); + err = ocfs2_qinfo_lock(info, 1); + if (err < 0) + goto out_qlock; +@@ -368,7 +369,8 @@ int ocfs2_global_read_dquot(struct dquot + out_qlock: + if (ex) + ocfs2_qinfo_unlock(info, 1); +- ocfs2_qinfo_unlock(info, 0); ++ else ++ ocfs2_qinfo_unlock(info, 0); + out: + if (err < 0) + mlog_errno(err); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-65bac575e35915801ea518b9d8d8824367d125c8 b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-65bac575e35915801ea518b9d8d8824367d125c8 new file mode 100644 index 000000000..2a53d27f6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-65bac575e35915801ea518b9d8d8824367d125c8 @@ -0,0 +1,116 @@ +From: Jan Kara +Subject: ocfs2: Fix possible deadlock with quotas in ocfs2_setattr() +Patch-mainline: 2.6.31 + +We called vfs_dq_transfer() with global quota file lock held. This can lead +to deadlocks as if vfs_dq_transfer() has to allocate new quota structure, +it calls ocfs2_dquot_acquire() which tries to get quota file lock again and +this can block if another node requested the lock in the mean time. + +Since we have to call vfs_dq_transfer() with transaction already started +and quota file lock ranks above the transaction start, we cannot just rely +on ocfs2_dquot_acquire() or ocfs2_dquot_release() on getting the lock +if they need it. We fix the problem by acquiring pointers to all quota +structures needed by vfs_dq_transfer() already before calling the function. +By this we are sure that all quota structures are properly allocated and +they can be freed only after we drop references to them. Thus we don't need +quota file lock anywhere inside vfs_dq_transfer(). + +Signed-off-by: Jan Kara +--- + fs/ocfs2/file.c | 53 ++++++++++++++++++++++++++++++----------------------- + 1 file changed, 30 insertions(+), 23 deletions(-) + +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -899,9 +899,9 @@ int ocfs2_setattr(struct dentry *dentry, + struct ocfs2_super *osb = OCFS2_SB(sb); + struct buffer_head *bh = NULL; + handle_t *handle = NULL; +- int locked[MAXQUOTAS] = {0, 0}; +- int credits, qtype; +- struct ocfs2_mem_dqinfo *oinfo; ++ int qtype; ++ struct dquot *transfer_from[MAXQUOTAS] = { }; ++ struct dquot *transfer_to[MAXQUOTAS] = { }; + + mlog_entry("(0x%p, '%.*s')\n", dentry, + dentry->d_name.len, dentry->d_name.name); +@@ -974,30 +974,37 @@ int ocfs2_setattr(struct dentry *dentry, + + if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || + (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { +- credits = OCFS2_INODE_UPDATE_CREDITS; ++ /* ++ * Gather pointers to quota structures so that allocation / ++ * freeing of quota structures happens here and not inside ++ * vfs_dq_transfer() where we have problems with lock ordering ++ */ + if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid + && OCFS2_HAS_RO_COMPAT_FEATURE(sb, + OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { +- oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv; +- status = ocfs2_lock_global_qf(oinfo, 1); +- if (status < 0) ++ transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, ++ USRQUOTA); ++ transfer_from[USRQUOTA] = dqget(sb, inode->i_uid, ++ USRQUOTA); ++ if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) { ++ status = -ESRCH; + goto bail_unlock; +- credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) + +- ocfs2_calc_qdel_credits(sb, USRQUOTA); +- locked[USRQUOTA] = 1; ++ } + } + if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid + && OCFS2_HAS_RO_COMPAT_FEATURE(sb, + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { +- oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv; +- status = ocfs2_lock_global_qf(oinfo, 1); +- if (status < 0) ++ transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, ++ GRPQUOTA); ++ transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid, ++ GRPQUOTA); ++ if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) { ++ status = -ESRCH; + goto bail_unlock; +- credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) + +- ocfs2_calc_qdel_credits(sb, GRPQUOTA); +- locked[GRPQUOTA] = 1; ++ } + } +- handle = ocfs2_start_trans(osb, credits); ++ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS + ++ 2 * ocfs2_quota_trans_credits(sb)); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); +@@ -1035,12 +1042,6 @@ int ocfs2_setattr(struct dentry *dentry, + bail_commit: + ocfs2_commit_trans(osb, handle); + bail_unlock: +- for (qtype = 0; qtype < MAXQUOTAS; qtype++) { +- if (!locked[qtype]) +- continue; +- oinfo = sb_dqinfo(sb, qtype)->dqi_priv; +- ocfs2_unlock_global_qf(oinfo, 1); +- } + ocfs2_inode_unlock(inode, 1); + bail_unlock_rw: + if (size_change) +@@ -1048,6 +1049,12 @@ bail_unlock_rw: + bail: + brelse(bh); + ++ /* Release quota pointers in case we acquired them */ ++ for (qtype = 0; qtype < MAXQUOTAS; qtype++) { ++ dqput(transfer_to[qtype]); ++ dqput(transfer_from[qtype]); ++ } ++ + if (!status && attr->ia_valid & ATTR_MODE) { + status = ocfs2_acl_chmod(inode); + if (status < 0) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-80d73f15d12f087f3fe074f8a4d6e5c5624f2b47 b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-80d73f15d12f087f3fe074f8a4d6e5c5624f2b47 new file mode 100644 index 000000000..3eec7a15c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-80d73f15d12f087f3fe074f8a4d6e5c5624f2b47 @@ -0,0 +1,70 @@ +From: Jan Kara +Subject: ocfs2: Fix possible deadlock in quota recovery +Patch-mainline: 2.6.31 + +In ocfs2_finish_quota_recovery() we acquired global quota file lock and started +recovering local quota file. During this process we need to get quota +structures, which calls ocfs2_dquot_acquire() which gets global quota file lock +again. This second lock can block in case some other node has requested the +quota file lock in the mean time. Fix the problem by moving quota file locking +down into the function where it is really needed. Then dqget() or dqput() +won't be called with the lock held. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota_local.c | 16 +++++++++------- + 1 files changed, 9 insertions(+), 7 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_local.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/quota_local.c 2009-07-16 13:16:27.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_local.c 2009-07-16 13:20:05.000000000 +0200 +@@ -438,10 +438,6 @@ + + mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type); + +- status = ocfs2_lock_global_qf(oinfo, 1); +- if (status < 0) +- goto out; +- + list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) { + chunk = rchunk->rc_chunk; + hbh = ocfs2_bread(lqinode, ol_quota_chunk_block(sb, chunk), +@@ -471,12 +467,18 @@ + type); + goto out_put_bh; + } ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_put_dquot; ++ } ++ + handle = ocfs2_start_trans(OCFS2_SB(sb), + OCFS2_QSYNC_CREDITS); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); +- goto out_put_dquot; ++ goto out_drop_lock; + } + mutex_lock(&sb_dqopt(sb)->dqio_mutex); + spin_lock(&dq_data_lock); +@@ -514,6 +516,8 @@ + out_commit: + mutex_unlock(&sb_dqopt(sb)->dqio_mutex); + ocfs2_commit_trans(OCFS2_SB(sb), handle); ++out_drop_lock: ++ ocfs2_unlock_global_qf(oinfo, 1); + out_put_dquot: + dqput(dquot); + out_put_bh: +@@ -528,8 +532,6 @@ + if (status < 0) + break; + } +- ocfs2_unlock_global_qf(oinfo, 1); +-out: + if (status < 0) + free_recovery_list(&(rec->r_list[type])); + mlog_exit(status); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-b4c30de39a2596503e888a7b47d19792f25913d6 b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-b4c30de39a2596503e888a7b47d19792f25913d6 new file mode 100644 index 000000000..b58feed1b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-1.4-git-b4c30de39a2596503e888a7b47d19792f25913d6 @@ -0,0 +1,45 @@ +From: Jan Kara +Subject: ocfs2: Fix lock inversion in ocfs2_local_read_info() +Patch-mainline: 2.6.31 + +This function is called with dqio_mutex held but it has to acquire lock +from global quota file which ranks above this lock. This is not deadlockable +lock inversion since this code path is take only during mount when noone +else can race with us but let's clean this up to silence lockdep. + +We just drop the dqio_mutex in the beginning of the function and reacquire +it in the end since we don't need it - noone can race with us at this moment. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota_local.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -647,6 +647,9 @@ static int ocfs2_local_read_info(struct + struct ocfs2_quota_recovery *rec; + int locked = 0; + ++ /* We don't need the lock and we have to acquire quota file locks ++ * which will later depend on this lock */ ++ mutex_unlock(&sb_dqopt(sb)->dqio_mutex); + info->dqi_maxblimit = 0x7fffffffffffffffLL; + info->dqi_maxilimit = 0x7fffffffffffffffLL; + oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); +@@ -725,6 +728,7 @@ static int ocfs2_local_read_info(struct + goto out_err; + } + ++ mutex_lock(&sb_dqopt(sb)->dqio_mutex); + return 0; + out_err: + if (oinfo) { +@@ -738,6 +742,7 @@ out_err: + kfree(oinfo); + } + brelse(bh); ++ mutex_lock(&sb_dqopt(sb)->dqio_mutex); + return -1; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Add-JBD2-compat-feature-bit.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Add-JBD2-compat-feature-bit.patch new file mode 100644 index 000000000..1c078a8d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Add-JBD2-compat-feature-bit.patch @@ -0,0 +1,38 @@ +From: Joel Becker +Date: Tue, 16 Dec 2008 18:10:18 -0800 +Subject: ocfs2: Add JBD2 compat feature bit. + +Define the OCFS2_FEATURE_COMPAT_JBD2 bit in the filesystem header. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/ocfs2_fs.h | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2_fs.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h +@@ -86,7 +86,8 @@ + #define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + OCFS2_SB(sb)->s_feature_incompat &= ~(mask) + +-#define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB ++#define OCFS2_FEATURE_COMPAT_SUPP (OCFS2_FEATURE_COMPAT_BACKUP_SB \ ++ | OCFS2_FEATURE_COMPAT_JBD2_SB) + #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \ + | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ + | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \ +@@ -153,6 +154,11 @@ + #define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001 + + /* ++ * The filesystem will correctly handle journal feature bits. ++ */ ++#define OCFS2_FEATURE_COMPAT_JBD2_SB 0x0002 ++ ++/* + * Unwritten extents support. + */ + #define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001 diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Always-update-xattr-search-when-creating-buck.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Always-update-xattr-search-when-creating-buck.patch new file mode 100644 index 000000000..ee4eeb883 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Always-update-xattr-search-when-creating-buck.patch @@ -0,0 +1,31 @@ +From: Tao Ma +Date: Fri, 5 Dec 2008 09:14:10 +0800 +Subject: ocfs2: Always update xattr search when creating bucket. + +When we create xattr bucket during the process of xattr set, we always +need to update the ocfs2_xattr_search since even if the bucket size is +the same as block size, the offset will change because of the removal +of the ocfs2_xattr_block header. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -2645,9 +2645,9 @@ static int ocfs2_xattr_update_xattr_sear + return ret; + } + +- i = xs->here - old_xh->xh_entries; +- xs->here = &xs->header->xh_entries[i]; + } ++ i = xs->here - old_xh->xh_entries; ++ xs->here = &xs->header->xh_entries[i]; + } + + return ret; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-errors-from-ocfs2_xattr_update_xattr_se.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-errors-from-ocfs2_xattr_update_xattr_se.patch new file mode 100644 index 000000000..a3579e08c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-errors-from-ocfs2_xattr_update_xattr_se.patch @@ -0,0 +1,31 @@ +From: Joel Becker +Date: Mon, 20 Oct 2008 18:25:56 -0700 +Subject: ocfs2: Check errors from ocfs2_xattr_update_xattr_search() + +The ocfs2_xattr_update_xattr_search() function can return an error when +trying to read blocks off of disk. The caller needs to check this error +before using those (possibly invalid) blocks. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -2825,7 +2825,11 @@ static int ocfs2_xattr_create_index_bloc + if (data_bh) + ocfs2_journal_dirty(handle, data_bh); + +- ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh); ++ ret = ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } + + /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */ + memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-search-result-in-ocfs2_xattr_block_get.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-search-result-in-ocfs2_xattr_block_get.patch new file mode 100644 index 000000000..b8281493d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-search-result-in-ocfs2_xattr_block_get.patch @@ -0,0 +1,40 @@ +From: Tiger Yang +Date: Sun, 2 Nov 2008 19:04:21 +0800 +Subject: ocfs2: Check search result in ocfs2_xattr_block_get() + +ocfs2_xattr_block_get() calls ocfs2_xattr_search() to find an external +xattr, but doesn't check the search result that is passed back via struct +ocfs2_xattr_search. Add a check for search result, and pass back -ENODATA if +the xattr search failed. This avoids a later NULL pointer error. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 7 ++++++- + 1 files changed, 6 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -777,6 +777,11 @@ static int ocfs2_xattr_block_get(struct + goto cleanup; + } + ++ if (xs->not_found) { ++ ret = -ENODATA; ++ goto cleanup; ++ } ++ + xb = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; + size = le64_to_cpu(xs->here->xe_value_size); + if (buffer) { +@@ -860,7 +865,7 @@ static int ocfs2_xattr_get(struct inode + down_read(&oi->ip_xattr_sem); + ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, + buffer_size, &xis); +- if (ret == -ENODATA) ++ if (ret == -ENODATA && di->i_xattr_loc) + ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, + buffer_size, &xbs); + up_read(&oi->ip_xattr_sem); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-xattr-block-signatures-properly.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-xattr-block-signatures-properly.patch new file mode 100644 index 000000000..fa8d6f585 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Check-xattr-block-signatures-properly.patch @@ -0,0 +1,118 @@ +From: Joel Becker +Date: Mon, 20 Oct 2008 18:20:43 -0700 +Subject: ocfs2: Check xattr block signatures properly. + +The xattr.c code is currently memcmp()ing naking buffer pointers. +Create the OCFS2_IS_VALID_XATTR_BLOCK() macro to match its peers and use +that. + +In addition, failed signature checks were returning -EFAULT, which is +completely wrong. Return -EIO. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/ocfs2.h | 3 +++ + fs/ocfs2/xattr.c | 38 ++++++++++++++++---------------------- + 2 files changed, 19 insertions(+), 22 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h +@@ -473,6 +473,9 @@ static inline int ocfs2_uses_extended_sl + (____gd)->bg_signature); \ + } while (0) + ++#define OCFS2_IS_VALID_XATTR_BLOCK(ptr) \ ++ (!strcmp((ptr)->xb_signature, OCFS2_XATTR_BLOCK_SIGNATURE)) ++ + static inline unsigned long ino_from_blkno(struct super_block *sb, + u64 blkno) + { +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -555,14 +555,12 @@ static int ocfs2_xattr_block_list(struct + mlog_errno(ret); + return ret; + } +- /*Verify the signature of xattr block*/ +- if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, +- strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { +- ret = -EFAULT; +- goto cleanup; +- } + + xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { ++ ret = -EIO; ++ goto cleanup; ++ } + + if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { + struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header; +@@ -779,15 +777,14 @@ static int ocfs2_xattr_block_get(struct + mlog_errno(ret); + return ret; + } +- /*Verify the signature of xattr block*/ +- if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, +- strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { +- ret = -EFAULT; ++ ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { ++ ret = -EIO; + goto cleanup; + } + + xs->xattr_bh = blk_bh; +- xb = (struct ocfs2_xattr_block *)blk_bh->b_data; + + if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { + xs->header = &xb->xb_attrs.xb_header; +@@ -1527,10 +1524,9 @@ static int ocfs2_xattr_free_block(struct + goto out; + } + +- /*Verify the signature of xattr block*/ +- if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, +- strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { +- ret = -EFAULT; ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { ++ ret = -EIO; + goto out; + } + +@@ -1540,7 +1536,6 @@ static int ocfs2_xattr_free_block(struct + goto out; + } + +- xb = (struct ocfs2_xattr_block *)blk_bh->b_data; + blk = le64_to_cpu(xb->xb_blkno); + bit = le16_to_cpu(xb->xb_suballoc_bit); + bg_blkno = ocfs2_which_suballoc_group(blk, bit); +@@ -1784,15 +1779,14 @@ static int ocfs2_xattr_block_find(struct + mlog_errno(ret); + return ret; + } +- /*Verify the signature of xattr block*/ +- if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, +- strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { +- ret = -EFAULT; +- goto cleanup; ++ ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { ++ ret = -EIO; ++ goto cleanup; + } + + xs->xattr_bh = blk_bh; +- xb = (struct ocfs2_xattr_block *)blk_bh->b_data; + + if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { + xs->header = &xb->xb_attrs.xb_header; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Don-t-repeat-ocfs2_xattr_block_find.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Don-t-repeat-ocfs2_xattr_block_find.patch new file mode 100644 index 000000000..d2093b7d8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Don-t-repeat-ocfs2_xattr_block_find.patch @@ -0,0 +1,89 @@ +From: Joel Becker +Date: Mon, 20 Oct 2008 18:43:07 -0700 +Subject: ocfs2: Don't repeat ocfs2_xattr_block_find() + +ocfs2_xattr_block_get() looks up the xattr in a startlingly familiar +way; it's identical to the function ocfs2_xattr_block_find(). Let's just +use the later in the former. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 39 +++++++++------------------------------ + 1 files changed, 9 insertions(+), 30 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -111,6 +111,10 @@ static int ocfs2_xattr_bucket_get_name_v + int *block_off, + int *new_offset); + ++static int ocfs2_xattr_block_find(struct inode *inode, ++ int name_index, ++ const char *name, ++ struct ocfs2_xattr_search *xs); + static int ocfs2_xattr_index_block_find(struct inode *inode, + struct buffer_head *root_bh, + int name_index, +@@ -760,46 +764,20 @@ static int ocfs2_xattr_block_get(struct + size_t buffer_size, + struct ocfs2_xattr_search *xs) + { +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; +- struct buffer_head *blk_bh = NULL; + struct ocfs2_xattr_block *xb; + struct ocfs2_xattr_value_root *xv; + size_t size; + int ret = -ENODATA, name_offset, name_len, block_off, i; + +- if (!di->i_xattr_loc) +- return ret; +- + memset(&xs->bucket, 0, sizeof(xs->bucket)); + +- ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh); +- if (ret < 0) { ++ ret = ocfs2_xattr_block_find(inode, name_index, name, xs); ++ if (ret) { + mlog_errno(ret); +- return ret; +- } +- +- xb = (struct ocfs2_xattr_block *)blk_bh->b_data; +- if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { +- ret = -EIO; + goto cleanup; + } + +- xs->xattr_bh = blk_bh; +- +- if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { +- xs->header = &xb->xb_attrs.xb_header; +- xs->base = (void *)xs->header; +- xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; +- xs->here = xs->header->xh_entries; +- +- ret = ocfs2_xattr_find_entry(name_index, name, xs); +- } else +- ret = ocfs2_xattr_index_block_find(inode, blk_bh, +- name_index, +- name, xs); +- +- if (ret) +- goto cleanup; ++ xb = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; + size = le64_to_cpu(xs->here->xe_value_size); + if (buffer) { + ret = -ERANGE; +@@ -838,7 +816,8 @@ cleanup: + brelse(xs->bucket.bhs[i]); + memset(&xs->bucket, 0, sizeof(xs->bucket)); + +- brelse(blk_bh); ++ brelse(xs->xattr_bh); ++ xs->xattr_bh = NULL; + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Don-t-return-EFAULT-from-a-corrupt-xattr-ent.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Don-t-return-EFAULT-from-a-corrupt-xattr-ent.patch new file mode 100644 index 000000000..f146954d3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Don-t-return-EFAULT-from-a-corrupt-xattr-ent.patch @@ -0,0 +1,25 @@ +From: Joel Becker +Date: Mon, 20 Oct 2008 18:24:03 -0700 +Subject: ocfs2: Don't return -EFAULT from a corrupt xattr entry. + +If the xattr disk structures are corrupt, return -EIO, not -EFAULT. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -1239,7 +1239,7 @@ static int ocfs2_xattr_set_entry(struct + + free = min_offs - ((void *)last - xs->base) - sizeof(__u32); + if (free < 0) +- return -EFAULT; ++ return -EIO; + + if (!xs->not_found) { + size_t size = 0; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-check-of-return-value-of-ocfs2_start_tran.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-check-of-return-value-of-ocfs2_start_tran.patch new file mode 100644 index 000000000..a909e14b0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-check-of-return-value-of-ocfs2_start_tran.patch @@ -0,0 +1,73 @@ +From: Jan Kara +Date: Mon, 20 Oct 2008 19:23:51 +0200 +Subject: ocfs2: Fix check of return value of ocfs2_start_trans() + +On failure, ocfs2_start_trans() returns values like ERR_PTR(-ENOMEM). +Thus checks for !handle are wrong. Fix them to use IS_ERR(). + +Signed-off-by: Jan Kara +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/file.c | 20 ++++++++++---------- + 1 files changed, 10 insertions(+), 10 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.c +@@ -247,8 +247,8 @@ int ocfs2_update_inode_atime(struct inod + mlog_entry_void(); + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); +- if (handle == NULL) { +- ret = -ENOMEM; ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } +@@ -312,8 +312,8 @@ static int ocfs2_simple_size_update(stru + handle_t *handle = NULL; + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); +- if (handle == NULL) { +- ret = -ENOMEM; ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } +@@ -1055,8 +1055,8 @@ static int __ocfs2_write_remove_suid(str + (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode); + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); +- if (handle == NULL) { +- ret = -ENOMEM; ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } +@@ -1259,8 +1259,8 @@ static int __ocfs2_remove_inode_range(st + } + + handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); +- if (handle == NULL) { +- ret = -ENOMEM; ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } +@@ -1352,8 +1352,8 @@ static int ocfs2_zero_partial_clusters(s + goto out; + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); +- if (handle == NULL) { +- ret = -ENOMEM; ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); + mlog_errno(ret); + goto out; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-checking-of-return-value-of-new_inode.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-checking-of-return-value-of-new_inode.patch new file mode 100644 index 000000000..93634f04f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-checking-of-return-value-of-new_inode.patch @@ -0,0 +1,29 @@ +From: Jan Kara +Date: Mon, 20 Oct 2008 19:23:53 +0200 +Subject: ocfs2: Fix checking of return value of new_inode() + +new_inode() does not return ERR_PTR() but NULL in case of failure. Correct +checking of the return value. + +Signed-off-by: Jan Kara +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/namei.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/namei.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/namei.c +@@ -378,8 +378,8 @@ static int ocfs2_mknod_locked(struct ocf + } + + inode = new_inode(dir->i_sb); +- if (IS_ERR(inode)) { +- status = PTR_ERR(inode); ++ if (!inode) { ++ status = -ENOMEM; + mlog(ML_ERROR, "new_inode failed!\n"); + goto leave; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-some-typos-in-xattr-annotations.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-some-typos-in-xattr-annotations.patch new file mode 100644 index 000000000..f51ab013a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Fix-some-typos-in-xattr-annotations.patch @@ -0,0 +1,59 @@ +From: Tao Ma +Date: Fri, 24 Oct 2008 22:24:17 +0800 +Subject: ocfs2: Fix some typos in xattr annotations. + +Fix some typos in the xattr annotations. + +Signed-off-by: Tao Ma +Reported-by: Coly Li +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/ocfs2_fs.h | 17 +++++++++-------- + 1 files changed, 9 insertions(+), 8 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2_fs.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h +@@ -742,12 +742,12 @@ struct ocfs2_group_desc + */ + struct ocfs2_xattr_entry { + __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */ +- __le16 xe_name_offset; /* byte offset from the 1st etnry in the local ++ __le16 xe_name_offset; /* byte offset from the 1st entry in the + local xattr storage(inode, xattr block or + xattr bucket). */ + __u8 xe_name_len; /* xattr name len, does't include prefix. */ +- __u8 xe_type; /* the low 7 bits indicates the name prefix's +- * type and the highest 1 bits indicate whether ++ __u8 xe_type; /* the low 7 bits indicate the name prefix ++ * type and the highest bit indicates whether + * the EA is stored in the local storage. */ + __le64 xe_value_size; /* real xattr value length. */ + }; +@@ -766,9 +766,10 @@ struct ocfs2_xattr_header { + xattr. */ + __le16 xh_name_value_len; /* total length of name/value + length in this bucket. */ +- __le16 xh_num_buckets; /* bucket nums in one extent +- record, only valid in the +- first bucket. */ ++ __le16 xh_num_buckets; /* Number of xattr buckets ++ in this extent record, ++ only valid in the first ++ bucket. */ + __le64 xh_csum; + struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */ + }; +@@ -776,8 +777,8 @@ struct ocfs2_xattr_header { + /* + * On disk structure for xattr value root. + * +- * It is used when one extended attribute's size is larger, and we will save it +- * in an outside cluster. It will stored in a b-tree like file content. ++ * When an xattr's value is large enough, it is stored in an external ++ * b-tree like file data. The xattr value root points to this structure. + */ + struct ocfs2_xattr_value_root { + /*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Let-inode-be-really-deleted-when-ocfs2_mknod_.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Let-inode-be-really-deleted-when-ocfs2_mknod_.patch new file mode 100644 index 000000000..0bcb00da1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Let-inode-be-really-deleted-when-ocfs2_mknod_.patch @@ -0,0 +1,31 @@ +From: Jan Kara +Date: Mon, 20 Oct 2008 19:23:54 +0200 +Subject: ocfs2: Let inode be really deleted when ocfs2_mknod_locked() fails + +We forgot to set i_nlink to 0 when returning due to error from ocfs2_mknod_locked() +and thus inode was not properly released via ocfs2_delete_inode() (e.g. claimed +space was not released). Fix it. + +Signed-off-by: Jan Kara +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/namei.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/namei.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/namei.c +@@ -491,8 +491,10 @@ leave: + brelse(*new_fe_bh); + *new_fe_bh = NULL; + } +- if (inode) ++ if (inode) { ++ clear_nlink(inode); + iput(inode); ++ } + } + + mlog_exit(status); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Remove-unused-ocfs2_restore_xattr_block.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Remove-unused-ocfs2_restore_xattr_block.patch new file mode 100644 index 000000000..20e0625c3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Remove-unused-ocfs2_restore_xattr_block.patch @@ -0,0 +1,81 @@ +From: Tao Ma +Date: Fri, 17 Oct 2008 12:44:36 +0800 +Subject: ocfs2: Remove unused ocfs2_restore_xattr_block(). + +Since now ocfs2 supports empty xattr buckets, we will never remove +the xattr index tree even if all the xattrs are removed, so this +function will never be called. So remove it. + +Signed-off-by: Tao Ma +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 48 ------------------------------------------------ + 1 files changed, 0 insertions(+), 48 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -1792,52 +1792,6 @@ cleanup: + } + + /* +- * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree +- * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header +- * re-initialized. +- */ +-static int ocfs2_restore_xattr_block(struct inode *inode, +- struct ocfs2_xattr_search *xs) +-{ +- int ret; +- handle_t *handle; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; +- struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; +- u16 xb_flags = le16_to_cpu(xb->xb_flags); +- +- BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) || +- le16_to_cpu(el->l_next_free_rec) != 0); +- +- handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- handle = NULL; +- goto out; +- } +- +- ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret < 0) { +- mlog_errno(ret); +- goto out_commit; +- } +- +- memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - +- offsetof(struct ocfs2_xattr_block, xb_attrs)); +- +- xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED); +- +- ocfs2_journal_dirty(handle, xs->xattr_bh); +- +-out_commit: +- ocfs2_commit_trans(osb, handle); +-out: +- return ret; +-} +- +-/* + * ocfs2_xattr_block_set() + * + * Set, replace or remove an extended attribute into external block. +@@ -1947,8 +1901,6 @@ out: + } + + ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs); +- if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0) +- ret = ocfs2_restore_xattr_block(inode, xs); + + end: + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Set-journal-descriptor-to-NULL-after-journal.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Set-journal-descriptor-to-NULL-after-journal.patch new file mode 100644 index 000000000..7354d1227 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Set-journal-descriptor-to-NULL-after-journal.patch @@ -0,0 +1,48 @@ +From: Sunil Mushran +Date: Wed, 22 Oct 2008 13:24:29 -0700 +Subject: ocfs2: Set journal descriptor to NULL after journal shutdown +References: BZ 450579 +Patch-mainline: 2.6.28 + +Patch sets journal descriptor to NULL after the journal is shutdown. +This ensures that jbd2_journal_release_jbd_inode(), which removes the +jbd2 inode from txn lists, can be called safely from ocfs2_clear_inode() +even after the journal has been shutdown. + +Signed-off-by: Sunil Mushran +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/inode.c | 6 ++++++ + fs/ocfs2/journal.c | 1 + + 2 files changed, 7 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/inode.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/inode.c +@@ -1106,6 +1106,12 @@ void ocfs2_clear_inode(struct inode *ino + oi->ip_last_trans = 0; + oi->ip_dir_start_lookup = 0; + oi->ip_blkno = 0ULL; ++ ++ /* ++ * ip_jinode is used to track txns against this inode. We ensure that ++ * the journal is flushed before journal shutdown. Thus it is safe to ++ * have inodes get cleaned up after journal shutdown. ++ */ + jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal, + &oi->ip_jinode); + +Index: linux-2.6.27-ocfs2/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/journal.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/journal.c +@@ -690,6 +690,7 @@ void ocfs2_journal_shutdown(struct ocfs2 + + /* Shutdown the kernel journal system */ + jbd2_journal_destroy(journal->j_journal); ++ journal->j_journal = NULL; + + OCFS2_I(inode)->ip_open_count--; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Specify-appropriate-journal-access-for-new-xa.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Specify-appropriate-journal-access-for-new-xa.patch new file mode 100644 index 000000000..5678f6227 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-Specify-appropriate-journal-access-for-new-xa.patch @@ -0,0 +1,38 @@ +From: Joel Becker +Date: Mon, 20 Oct 2008 18:32:48 -0700 +Subject: ocfs2: Specify appropriate journal access for new xattr buckets. + +There are a couple places that get an xattr bucket that may be reading +an existing one or may be allocating a new one. They should specify the +correct journal access mode depending. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -3231,7 +3231,9 @@ static int ocfs2_half_xattr_bucket(struc + + for (i = 0; i < blk_per_bucket; i++) { + ret = ocfs2_journal_access(handle, inode, t_bhs[i], +- OCFS2_JOURNAL_ACCESS_CREATE); ++ new_bucket_head ? ++ OCFS2_JOURNAL_ACCESS_CREATE : ++ OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; +@@ -3393,6 +3395,8 @@ static int ocfs2_cp_xattr_bucket(struct + + for (i = 0; i < blk_per_bucket; i++) { + ret = ocfs2_journal_access(handle, inode, t_bhs[i], ++ t_is_new ? ++ OCFS2_JOURNAL_ACCESS_CREATE : + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-access-and-dirty-the-buffer_head-in-mark_writ.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-access-and-dirty-the-buffer_head-in-mark_writ.patch new file mode 100644 index 000000000..943733d86 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-access-and-dirty-the-buffer_head-in-mark_writ.patch @@ -0,0 +1,62 @@ +From: Tao Ma +Date: Fri, 9 Jan 2009 07:32:48 +0800 +Subject: [PATCH] ocfs2: Access and dirty the buffer_head in mark_written. +Patch-mainline: 2.6.29 + +In __ocfs2_mark_extent_written, when we meet with the situation +of c_split_covers_rec, the old solution just replace the extent +record and forget to access and dirty the buffer_head. This will +cause a problem when the unwritten extent is in an extent block. +So access and dirty it. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 27 ++++++++++++++++++++++++++- + 1 files changed, 26 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/alloc.c +@@ -4708,6 +4708,29 @@ out: + return ret; + } + ++static int ocfs2_replace_extent_rec(struct inode *inode, ++ handle_t *handle, ++ struct ocfs2_path *path, ++ struct ocfs2_extent_list *el, ++ int split_index, ++ struct ocfs2_extent_rec *split_rec) ++{ ++ int ret; ++ ++ ret = ocfs2_journal_access(handle, inode, path_leaf_bh(path), ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ el->l_recs[split_index] = *split_rec; ++ ++ ocfs2_journal_dirty(handle, path_leaf_bh(path)); ++out: ++ return ret; ++} ++ + /* + * Mark part or all of the extent record at split_index in the leaf + * pointed to by path as written. This removes the unwritten +@@ -4802,7 +4825,9 @@ static int __ocfs2_mark_extent_written(s + + if (ctxt.c_contig_type == CONTIG_NONE) { + if (ctxt.c_split_covers_rec) +- el->l_recs[split_index] = *split_rec; ++ ret = ocfs2_replace_extent_rec(inode, handle, ++ path, el, ++ split_index, split_rec); + else + ret = ocfs2_split_and_insert(inode, handle, path, et, + &last_eb_bh, split_index, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-handler_map-array-bounds-checking.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-handler_map-array-bounds-checking.patch new file mode 100644 index 000000000..fa2073884 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-handler_map-array-bounds-checking.patch @@ -0,0 +1,29 @@ +From: Tiger Yang +Date: Thu, 23 Oct 2008 16:34:44 +0800 +Subject: ocfs2: add handler_map array bounds checking + +Make the handler_map array as large as the possible value range to avoid +a fencepost error. + +[ Utilize alternate method -- Joel ] + +Signed-off-by: Tiger Yang +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -78,7 +78,7 @@ struct xattr_handler *ocfs2_xattr_handle + NULL + }; + +-static struct xattr_handler *ocfs2_xattr_handler_map[] = { ++static struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = { + [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, + [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, + }; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-io-error-check-in-ocfs2_get_sector.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-io-error-check-in-ocfs2_get_sector.patch new file mode 100644 index 000000000..bc1ff6f72 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-io-error-check-in-ocfs2_get_sector.patch @@ -0,0 +1,31 @@ +From: wengang wang +Date: Fri, 13 Feb 2009 10:11:47 +0800 +Subject: [PATCH] ocfs2: add IO error check in ocfs2_get_sector() +Patch-mainline: 2.6.29 + +Check for IO error in ocfs2_get_sector(). + +Signed-off-by: Wengang Wang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/super.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/super.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/super.c +@@ -1538,6 +1538,13 @@ static int ocfs2_get_sector(struct super + unlock_buffer(*bh); + ll_rw_block(READ, 1, bh); + wait_on_buffer(*bh); ++ if (!buffer_uptodate(*bh)) { ++ mlog_errno(-EIO); ++ brelse(*bh); ++ *bh = NULL; ++ return -EIO; ++ } ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-quota-call-to-ocfs2_remove_btree_range.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-quota-call-to-ocfs2_remove_btree_range.patch new file mode 100644 index 000000000..6c163db4b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-add-quota-call-to-ocfs2_remove_btree_range.patch @@ -0,0 +1,31 @@ +From: Mark Fasheh +Date: Thu, 29 Jan 2009 15:06:21 -0800 +Subject: [PATCH] ocfs2: add quota call to ocfs2_remove_btree_range() +Patch-mainline: 2.6.29 + +We weren't reclaiming the clusters which get free'd from this function, +so any user punching holes in a file would still have those bytes accounted +against him/her. Add the call to vfs_dq_free_space_nodirty() to fix this. +Interestingly enough, the journal credits calculation already took this into +account. + +Signed-off-by: Mark Fasheh +Acked-by: Jan Kara +--- + fs/ocfs2/alloc.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/alloc.c +@@ -5307,6 +5307,9 @@ int ocfs2_remove_btree_range(struct inod + goto out; + } + ++ vfs_dq_free_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(inode->i_sb, len)); ++ + ret = ocfs2_remove_extent(inode, et, cpos, len, handle, meta_ac, + dealloc); + if (ret) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-comments-typo-fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-comments-typo-fix.patch new file mode 100644 index 000000000..19ef161bf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-comments-typo-fix.patch @@ -0,0 +1,39 @@ +From: Coly Li +Date: Wed, 5 Nov 2008 15:16:24 +0800 +Subject: ocfs2: comments typo fix + +This patch fixes two typos in comments of ocfs2. + +Signed-off-by: Coly Li +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/userdlm.h | 2 +- + fs/ocfs2/ocfs2.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/dlm/userdlm.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlm/userdlm.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/dlm/userdlm.h +@@ -33,7 +33,7 @@ + #include + + /* user_lock_res->l_flags flags. */ +-#define USER_LOCK_ATTACHED (0x00000001) /* have we initialized ++#define USER_LOCK_ATTACHED (0x00000001) /* we have initialized + * the lvb */ + #define USER_LOCK_BUSY (0x00000002) /* we are currently in + * dlm_lock */ +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h +@@ -85,7 +85,7 @@ enum ocfs2_unlock_action { + }; + + /* ocfs2_lock_res->l_flags flags. */ +-#define OCFS2_LOCK_ATTACHED (0x00000001) /* have we initialized ++#define OCFS2_LOCK_ATTACHED (0x00000001) /* we have initialized + * the lvb */ + #define OCFS2_LOCK_BUSY (0x00000002) /* we are currently in + * dlm_lock */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-Hold-off-sending-lockres-drop-ref-message.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-Hold-off-sending-lockres-drop-ref-message.patch new file mode 100644 index 000000000..43170e784 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-Hold-off-sending-lockres-drop-ref-message.patch @@ -0,0 +1,35 @@ +From: Sunil Mushran +Date: Tue, 16 Dec 2008 15:49:21 -0800 +Subject: ocfs2/dlm: Hold off sending lockres drop ref message while lockres is migrating +References: BZ 450579 +Patch-mainline: 2.6.29 + +During lockres purge, o2dlm sends a drop reference message to the lockres +master. This patch delays the message if the lockres is being migrated. + +Fixes oss bugzilla#1012 +http://oss.oracle.com/bugzilla/show_bug.cgi?id=1012 + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmthread.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c +index 4060bb3..d129520 100644 +--- a/fs/ocfs2/dlm/dlmthread.c ++++ b/fs/ocfs2/dlm/dlmthread.c +@@ -181,7 +181,8 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm, + + spin_lock(&res->spinlock); + /* This ensures that clear refmap is sent after the set */ +- __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG); ++ __dlm_wait_on_lockres_flags(res, (DLM_LOCK_RES_SETREF_INPROG | ++ DLM_LOCK_RES_MIGRATING)); + spin_unlock(&res->spinlock); + + /* clear our bit from the master's refmap, ignore errors */ +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-activate-dlm-master_hash-for-master-list.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-activate-dlm-master_hash-for-master-list.patch new file mode 100644 index 000000000..c373b3279 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-activate-dlm-master_hash-for-master-list.patch @@ -0,0 +1,280 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:41 -0800 +Subject: ocfs2/dlm: Activate dlm->master_hash for master list entries +Patch-mainline: 2.6.30 +References: bnc#408304 + +With this patch, the mles are stored in a hash and not a simple list. +This should improve the mle lookup time when the number of outstanding +masteries is large. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 4 +- + fs/ocfs2/dlm/dlmdebug.c | 24 +++++++++++------- + fs/ocfs2/dlm/dlmdomain.c | 1 - + fs/ocfs2/dlm/dlmmaster.c | 61 ++++++++++++++++++++++++++++++++------------- + 4 files changed, 60 insertions(+), 30 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -56,12 +56,13 @@ enum dlm_mle_type { + }; + + struct dlm_lock_name { ++ unsigned int hash; + unsigned int len; + unsigned char name[DLM_LOCKID_NAME_MAX]; + }; + + struct dlm_master_list_entry { +- struct list_head list; ++ struct hlist_node master_hash_node; + struct list_head hb_events; + struct dlm_ctxt *dlm; + spinlock_t spinlock; +@@ -152,7 +153,6 @@ struct dlm_ctxt + struct dlm_recovery_ctxt reco; + spinlock_t master_lock; + struct hlist_head **master_hash; +- struct list_head master_list; + struct list_head mle_hb_events; + + /* these give a really vague idea of the system load */ +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdebug.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +@@ -501,18 +501,25 @@ static struct file_operations debug_purg + static int debug_mle_print(struct dlm_ctxt *dlm, struct debug_buffer *db) + { + struct dlm_master_list_entry *mle; +- int out = 0; ++ struct hlist_head *bucket; ++ struct hlist_node *list; ++ int i, out = 0; + unsigned long total = 0; + + out += snprintf(db->buf + out, db->len - out, + "Dumping MLEs for Domain: %s\n", dlm->name); + + spin_lock(&dlm->master_lock); +- list_for_each_entry(mle, &dlm->master_list, list) { +- ++total; +- if (db->len - out < 200) +- continue; +- out += dump_mle(mle, db->buf + out, db->len - out); ++ for (i = 0; i < DLM_HASH_BUCKETS; i++) { ++ bucket = dlm_master_hash(dlm, i); ++ hlist_for_each(list, bucket) { ++ mle = hlist_entry(list, struct dlm_master_list_entry, ++ master_hash_node); ++ ++total; ++ if (db->len - out < 200) ++ continue; ++ out += dump_mle(mle, db->buf + out, db->len - out); ++ } + } + spin_unlock(&dlm->master_lock); + +@@ -813,12 +820,11 @@ static int debug_state_print(struct dlm_ + /* Lists: Dirty=Empty Purge=InUse PendingASTs=Empty ... */ + out += snprintf(db->buf + out, db->len - out, + "Lists: Dirty=%s Purge=%s PendingASTs=%s " +- "PendingBASTs=%s Master=%s\n", ++ "PendingBASTs=%s\n", + (list_empty(&dlm->dirty_list) ? "Empty" : "InUse"), + (list_empty(&dlm->purge_list) ? "Empty" : "InUse"), + (list_empty(&dlm->pending_asts) ? "Empty" : "InUse"), +- (list_empty(&dlm->pending_basts) ? "Empty" : "InUse"), +- (list_empty(&dlm->master_list) ? "Empty" : "InUse")); ++ (list_empty(&dlm->pending_basts) ? "Empty" : "InUse")); + + /* Purge Count: xxx Refs: xxx */ + out += snprintf(db->buf + out, db->len - out, +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdomain.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdomain.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdomain.c +@@ -1597,7 +1597,6 @@ static struct dlm_ctxt *dlm_alloc_ctxt(c + init_waitqueue_head(&dlm->reco.event); + init_waitqueue_head(&dlm->ast_wq); + init_waitqueue_head(&dlm->migration_wq); +- INIT_LIST_HEAD(&dlm->master_list); + INIT_LIST_HEAD(&dlm->mle_hb_events); + + dlm->joining_node = DLM_LOCK_RES_OWNER_UNKNOWN; +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -69,7 +69,8 @@ static int dlm_do_assert_master(struct d + static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data); + + static inline void __dlm_mle_name(struct dlm_master_list_entry *mle, +- unsigned char **name, unsigned int *namelen) ++ unsigned char **name, unsigned int *namelen, ++ unsigned int *namehash) + { + BUG_ON(mle->type != DLM_MLE_BLOCK && + mle->type != DLM_MLE_MASTER && +@@ -78,9 +79,13 @@ static inline void __dlm_mle_name(struct + if (mle->type != DLM_MLE_MASTER) { + *name = mle->u.mlename.name; + *namelen = mle->u.mlename.len; ++ if (namehash) ++ *namehash = mle->u.mlename.hash; + } else { + *name = (unsigned char *)mle->u.mleres->lockname.name; + *namelen = mle->u.mleres->lockname.len; ++ if (namehash) ++ *namehash = mle->u.mleres->lockname.hash; + } + } + +@@ -95,7 +100,7 @@ static inline int dlm_mle_equal(struct d + if (dlm != mle->dlm) + return 0; + +- __dlm_mle_name(mle, &mlename, &mlelen); ++ __dlm_mle_name(mle, &mlename, &mlelen, NULL); + + if (namelen != mlelen || memcmp(name, mlename, namelen) != 0) + return 0; +@@ -294,7 +299,7 @@ static void dlm_init_mle(struct dlm_mast + + mle->dlm = dlm; + mle->type = type; +- INIT_LIST_HEAD(&mle->list); ++ INIT_HLIST_NODE(&mle->master_hash_node); + INIT_LIST_HEAD(&mle->hb_events); + memset(mle->maybe_map, 0, sizeof(mle->maybe_map)); + spin_lock_init(&mle->spinlock); +@@ -317,6 +322,7 @@ static void dlm_init_mle(struct dlm_mast + BUG_ON(!name); + memcpy(mle->u.mlename.name, name, namelen); + mle->u.mlename.len = namelen; ++ mle->u.mlename.hash = dlm_lockid_hash(name, namelen); + } + + /* copy off the node_map and register hb callbacks on our copy */ +@@ -334,15 +340,21 @@ void __dlm_unlink_mle(struct dlm_ctxt *d + assert_spin_locked(&dlm->spinlock); + assert_spin_locked(&dlm->master_lock); + +- if (!list_empty(&mle->list)) +- list_del_init(&mle->list); ++ if (!hlist_unhashed(&mle->master_hash_node)) ++ hlist_del_init(&mle->master_hash_node); + } + + void __dlm_insert_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle) + { ++ struct hlist_head *bucket; ++ unsigned char *mname; ++ unsigned int mlen, hash; ++ + assert_spin_locked(&dlm->master_lock); + +- list_add(&mle->list, &dlm->master_list); ++ __dlm_mle_name(mle, &mname, &mlen, &hash); ++ bucket = dlm_master_hash(dlm, hash); ++ hlist_add_head(&mle->master_hash_node, bucket); + } + + /* returns 1 if found, 0 if not */ +@@ -351,10 +363,17 @@ static int dlm_find_mle(struct dlm_ctxt + char *name, unsigned int namelen) + { + struct dlm_master_list_entry *tmpmle; ++ struct hlist_head *bucket; ++ struct hlist_node *list; ++ unsigned int hash; + + assert_spin_locked(&dlm->master_lock); + +- list_for_each_entry(tmpmle, &dlm->master_list, list) { ++ hash = dlm_lockid_hash(name, namelen); ++ bucket = dlm_master_hash(dlm, hash); ++ hlist_for_each(list, bucket) { ++ tmpmle = hlist_entry(list, struct dlm_master_list_entry, ++ master_hash_node); + if (!dlm_mle_equal(dlm, tmpmle, name, namelen)) + continue; + dlm_get_mle(tmpmle); +@@ -428,23 +447,20 @@ static void dlm_mle_release(struct kref + { + struct dlm_master_list_entry *mle; + struct dlm_ctxt *dlm; ++ unsigned char *mname; ++ unsigned int mlen; + + mlog_entry_void(); + + mle = container_of(kref, struct dlm_master_list_entry, mle_refs); + dlm = mle->dlm; + +- if (mle->type != DLM_MLE_MASTER) { +- mlog(0, "calling mle_release for %.*s, type %d\n", +- mle->u.mlename.len, mle->u.mlename.name, mle->type); +- } else { +- mlog(0, "calling mle_release for %.*s, type %d\n", +- mle->u.mleres->lockname.len, +- mle->u.mleres->lockname.name, mle->type); +- } + assert_spin_locked(&dlm->spinlock); + assert_spin_locked(&dlm->master_lock); + ++ __dlm_mle_name(mle, &mname, &mlen, NULL); ++ mlog(0, "Releasing mle for %.*s, type %d\n", mlen, mname, mle->type); ++ + /* remove from list if not already */ + __dlm_unlink_mle(dlm, mle); + +@@ -1335,7 +1351,7 @@ static int dlm_do_master_request(struct + + BUG_ON(mle->type == DLM_MLE_MIGRATION); + +- __dlm_mle_name(mle, &mlename, &mlenamelen); ++ __dlm_mle_name(mle, &mlename, &mlenamelen, NULL); + + request.namelen = (u8)mlenamelen; + memcpy(request.name, mlename, request.namelen); +@@ -3264,8 +3280,11 @@ static void dlm_clean_block_mle(struct d + + void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node) + { +- struct dlm_master_list_entry *mle, *next; ++ struct dlm_master_list_entry *mle; + struct dlm_lock_resource *res; ++ struct hlist_head *bucket; ++ struct hlist_node *list; ++ unsigned int i; + + mlog_entry("dlm=%s, dead node=%u\n", dlm->name, dead_node); + top: +@@ -3273,7 +3292,12 @@ top: + + /* clean the master list */ + spin_lock(&dlm->master_lock); +- list_for_each_entry_safe(mle, next, &dlm->master_list, list) { ++ for (i = 0; i < DLM_HASH_BUCKETS; i++) { ++ bucket = dlm_master_hash(dlm, i); ++ hlist_for_each(list, bucket) { ++ mle = hlist_entry(list, struct dlm_master_list_entry, ++ master_hash_node); ++ + BUG_ON(mle->type != DLM_MLE_BLOCK && + mle->type != DLM_MLE_MASTER && + mle->type != DLM_MLE_MIGRATION); +@@ -3329,6 +3353,7 @@ top: + /* this may be the last reference */ + __dlm_put_mle(mle); + } ++ } + spin_unlock(&dlm->master_lock); + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-clean-up-struct-dlm_lock_name.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-clean-up-struct-dlm_lock_name.patch new file mode 100644 index 000000000..b0c73f10f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-clean-up-struct-dlm_lock_name.patch @@ -0,0 +1,216 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:38 -0800 +Subject: ocfs2/dlm: Clean up struct dlm_lock_name +Patch-mainline: 2.6.30 +References: bnc#408304 + +For master mle, the name it stored in the attached lockres in struct qstr. +For block and migration mle, the name is stored inline in struct dlm_lock_name. +This patch attempts to make struct dlm_lock_name look like a struct qstr. While +we could use struct qstr, we don't because we want to avoid having to malloc +and free the lockname string as the mle's lifetime is fairly short. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 8 ++-- + fs/ocfs2/dlm/dlmdebug.c | 10 +++--- + fs/ocfs2/dlm/dlmmaster.c | 79 +++++++++++++++++++++++++-------------------- + 3 files changed, 53 insertions(+), 44 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -56,8 +56,8 @@ enum dlm_mle_type { + }; + + struct dlm_lock_name { +- u8 len; +- u8 name[DLM_LOCKID_NAME_MAX]; ++ unsigned int len; ++ unsigned char name[DLM_LOCKID_NAME_MAX]; + }; + + struct dlm_master_list_entry { +@@ -79,8 +79,8 @@ struct dlm_master_list_entry { + struct o2hb_callback_func mle_hb_up; + struct o2hb_callback_func mle_hb_down; + union { +- struct dlm_lock_resource *res; +- struct dlm_lock_name name; ++ struct dlm_lock_resource *mleres; ++ struct dlm_lock_name mlename; + } u; + }; + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdebug.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +@@ -288,15 +288,15 @@ static int dump_mle(struct dlm_master_li + { + int out = 0; + unsigned int namelen; +- const char *name; ++ unsigned char *name; + char *mle_type; + + if (mle->type != DLM_MLE_MASTER) { +- namelen = mle->u.name.len; +- name = mle->u.name.name; ++ name = mle->u.mlename.name; ++ namelen = mle->u.mlename.len; + } else { +- namelen = mle->u.res->lockname.len; +- name = mle->u.res->lockname.name; ++ name = (unsigned char *)mle->u.mleres->lockname.name; ++ namelen = mle->u.mleres->lockname.len; + } + + if (mle->type == DLM_MLE_BLOCK) +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -68,27 +68,38 @@ static int dlm_do_assert_master(struct d + void *nodemap, u32 flags); + static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data); + ++static inline void __dlm_mle_name(struct dlm_master_list_entry *mle, ++ unsigned char **name, unsigned int *namelen) ++{ ++ BUG_ON(mle->type != DLM_MLE_BLOCK && ++ mle->type != DLM_MLE_MASTER && ++ mle->type != DLM_MLE_MIGRATION); ++ ++ if (mle->type != DLM_MLE_MASTER) { ++ *name = mle->u.mlename.name; ++ *namelen = mle->u.mlename.len; ++ } else { ++ *name = (unsigned char *)mle->u.mleres->lockname.name; ++ *namelen = mle->u.mleres->lockname.len; ++ } ++} ++ + static inline int dlm_mle_equal(struct dlm_ctxt *dlm, + struct dlm_master_list_entry *mle, + const char *name, + unsigned int namelen) + { +- struct dlm_lock_resource *res; ++ unsigned char *mlename; ++ unsigned int mlelen; + + if (dlm != mle->dlm) + return 0; + +- if (mle->type == DLM_MLE_BLOCK || +- mle->type == DLM_MLE_MIGRATION) { +- if (namelen != mle->u.name.len || +- memcmp(name, mle->u.name.name, namelen)!=0) +- return 0; +- } else { +- res = mle->u.res; +- if (namelen != res->lockname.len || +- memcmp(res->lockname.name, name, namelen) != 0) +- return 0; +- } ++ __dlm_mle_name(mle, &mlename, &mlelen); ++ ++ if (namelen != mlelen || memcmp(name, mlename, namelen) != 0) ++ return 0; ++ + return 1; + } + +@@ -295,17 +306,17 @@ static void dlm_init_mle(struct dlm_mast + mle->new_master = O2NM_MAX_NODES; + mle->inuse = 0; + ++ BUG_ON(mle->type != DLM_MLE_BLOCK && ++ mle->type != DLM_MLE_MASTER && ++ mle->type != DLM_MLE_MIGRATION); ++ + if (mle->type == DLM_MLE_MASTER) { + BUG_ON(!res); +- mle->u.res = res; +- } else if (mle->type == DLM_MLE_BLOCK) { +- BUG_ON(!name); +- memcpy(mle->u.name.name, name, namelen); +- mle->u.name.len = namelen; +- } else /* DLM_MLE_MIGRATION */ { ++ mle->u.mleres = res; ++ } else { + BUG_ON(!name); +- memcpy(mle->u.name.name, name, namelen); +- mle->u.name.len = namelen; ++ memcpy(mle->u.mlename.name, name, namelen); ++ mle->u.mlename.len = namelen; + } + + /* copy off the node_map and register hb callbacks on our copy */ +@@ -425,11 +436,11 @@ static void dlm_mle_release(struct kref + + if (mle->type != DLM_MLE_MASTER) { + mlog(0, "calling mle_release for %.*s, type %d\n", +- mle->u.name.len, mle->u.name.name, mle->type); ++ mle->u.mlename.len, mle->u.mlename.name, mle->type); + } else { + mlog(0, "calling mle_release for %.*s, type %d\n", +- mle->u.res->lockname.len, +- mle->u.res->lockname.name, mle->type); ++ mle->u.mleres->lockname.len, ++ mle->u.mleres->lockname.name, mle->type); + } + assert_spin_locked(&dlm->spinlock); + assert_spin_locked(&dlm->master_lock); +@@ -1277,7 +1288,7 @@ static int dlm_restart_lock_mastery(stru + res->lockname.len, + res->lockname.name); + mle->type = DLM_MLE_MASTER; +- mle->u.res = res; ++ mle->u.mleres = res; + } + } + } +@@ -1316,20 +1327,18 @@ static int dlm_do_master_request(struct + struct dlm_ctxt *dlm = mle->dlm; + struct dlm_master_request request; + int ret, response=0, resend; ++ unsigned char *mlename; ++ unsigned int mlenamelen; + + memset(&request, 0, sizeof(request)); + request.node_idx = dlm->node_num; + + BUG_ON(mle->type == DLM_MLE_MIGRATION); + +- if (mle->type != DLM_MLE_MASTER) { +- request.namelen = mle->u.name.len; +- memcpy(request.name, mle->u.name.name, request.namelen); +- } else { +- request.namelen = mle->u.res->lockname.len; +- memcpy(request.name, mle->u.res->lockname.name, +- request.namelen); +- } ++ __dlm_mle_name(mle, &mlename, &mlenamelen); ++ ++ request.namelen = (u8)mlenamelen; ++ memcpy(request.name, mlename, request.namelen); + + again: + ret = o2net_send_message(DLM_MASTER_REQUEST_MSG, dlm->key, &request, +@@ -3264,9 +3273,9 @@ top: + mle->master, mle->new_master); + /* if there is a lockres associated with this + * mle, find it and set its owner to UNKNOWN */ +- hash = dlm_lockid_hash(mle->u.name.name, mle->u.name.len); +- res = __dlm_lookup_lockres(dlm, mle->u.name.name, +- mle->u.name.len, hash); ++ hash = dlm_lockid_hash(mle->u.mlename.name, mle->u.mlename.len); ++ res = __dlm_lookup_lockres(dlm, mle->u.mlename.name, ++ mle->u.mlename.len, hash); + if (res) { + /* unfortunately if we hit this rare case, our + * lock ordering is messed. we need to drop diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-create-and-destroy-the-dlm-master_hash.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-create-and-destroy-the-dlm-master_hash.patch new file mode 100644 index 000000000..24627b8b8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-create-and-destroy-the-dlm-master_hash.patch @@ -0,0 +1,83 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:40 -0800 +Subject: ocfs2/dlm: Create and destroy the dlm->master_hash +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch adds code to create and destroy the dlm->master_hash. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 8 ++++++++ + fs/ocfs2/dlm/dlmdomain.c | 18 ++++++++++++++++++ + 2 files changed, 26 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -151,6 +151,7 @@ struct dlm_ctxt + unsigned long recovery_map[BITS_TO_LONGS(O2NM_MAX_NODES)]; + struct dlm_recovery_ctxt reco; + spinlock_t master_lock; ++ struct hlist_head **master_hash; + struct list_head master_list; + struct list_head mle_hb_events; + +@@ -195,6 +196,13 @@ static inline struct hlist_head *dlm_loc + return dlm->lockres_hash[(i / DLM_BUCKETS_PER_PAGE) % DLM_HASH_PAGES] + (i % DLM_BUCKETS_PER_PAGE); + } + ++static inline struct hlist_head *dlm_master_hash(struct dlm_ctxt *dlm, ++ unsigned i) ++{ ++ return dlm->master_hash[(i / DLM_BUCKETS_PER_PAGE) % DLM_HASH_PAGES] + ++ (i % DLM_BUCKETS_PER_PAGE); ++} ++ + /* these keventd work queue items are for less-frequently + * called functions that cannot be directly called from the + * net message handlers for some reason, usually because +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdomain.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdomain.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdomain.c +@@ -304,6 +304,9 @@ static void dlm_free_ctxt_mem(struct dlm + if (dlm->lockres_hash) + dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); + ++ if (dlm->master_hash) ++ dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES); ++ + if (dlm->name) + kfree(dlm->name); + +@@ -1534,12 +1537,27 @@ static struct dlm_ctxt *dlm_alloc_ctxt(c + for (i = 0; i < DLM_HASH_BUCKETS; i++) + INIT_HLIST_HEAD(dlm_lockres_hash(dlm, i)); + ++ dlm->master_hash = (struct hlist_head **) ++ dlm_alloc_pagevec(DLM_HASH_PAGES); ++ if (!dlm->master_hash) { ++ mlog_errno(-ENOMEM); ++ dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); ++ kfree(dlm->name); ++ kfree(dlm); ++ dlm = NULL; ++ goto leave; ++ } ++ ++ for (i = 0; i < DLM_HASH_BUCKETS; i++) ++ INIT_HLIST_HEAD(dlm_master_hash(dlm, i)); ++ + strcpy(dlm->name, domain); + dlm->key = key; + dlm->node_num = o2nm_this_node(); + + ret = dlm_create_debugfs_subroot(dlm); + if (ret < 0) { ++ dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES); + dlm_free_pagevec((void **)dlm->lockres_hash, DLM_HASH_PAGES); + kfree(dlm->name); + kfree(dlm); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-dlm_set_lockres_owner-and-dlm_change_lo.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-dlm_set_lockres_owner-and-dlm_change_lo.patch new file mode 100644 index 000000000..871dc1f47 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-dlm_set_lockres_owner-and-dlm_change_lo.patch @@ -0,0 +1,84 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:45 -0800 +Subject: ocfs2/dlm: dlm_set_lockres_owner() and dlm_change_lockres_owner() inlined +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch inlines dlm_set_lockres_owner() and dlm_change_lockres_owner(). + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 21 ++++++++++++++++++--- + fs/ocfs2/dlm/dlmmaster.c | 19 ------------------- + 2 files changed, 18 insertions(+), 22 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -858,9 +858,7 @@ struct dlm_lock_resource * dlm_lookup_lo + unsigned int len); + + int dlm_is_host_down(int errno); +-void dlm_change_lockres_owner(struct dlm_ctxt *dlm, +- struct dlm_lock_resource *res, +- u8 owner); ++ + struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm, + const char *lockid, + int namelen, +@@ -1123,6 +1121,23 @@ static inline int dlm_node_iter_next(str + return bit; + } + ++static inline void dlm_set_lockres_owner(struct dlm_ctxt *dlm, ++ struct dlm_lock_resource *res, ++ u8 owner) ++{ ++ assert_spin_locked(&res->spinlock); ++ ++ res->owner = owner; ++} + ++static inline void dlm_change_lockres_owner(struct dlm_ctxt *dlm, ++ struct dlm_lock_resource *res, ++ u8 owner) ++{ ++ assert_spin_locked(&res->spinlock); ++ ++ if (owner != res->owner) ++ dlm_set_lockres_owner(dlm, res, owner); ++} + + #endif /* DLMCOMMON_H */ +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -511,25 +511,6 @@ void dlm_destroy_master_caches(void) + kmem_cache_destroy(dlm_lockres_cache); + } + +-static void dlm_set_lockres_owner(struct dlm_ctxt *dlm, +- struct dlm_lock_resource *res, +- u8 owner) +-{ +- assert_spin_locked(&res->spinlock); +- +- res->owner = owner; +-} +- +-void dlm_change_lockres_owner(struct dlm_ctxt *dlm, +- struct dlm_lock_resource *res, u8 owner) +-{ +- assert_spin_locked(&res->spinlock); +- +- if (owner != res->owner) +- dlm_set_lockres_owner(dlm, res, owner); +-} +- +- + static void dlm_lockres_release(struct kref *kref) + { + struct dlm_lock_resource *res; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-do-not-purge-lockres-that-is-being-migrat.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-do-not-purge-lockres-that-is-being-migrat.patch new file mode 100644 index 000000000..3ca797dc0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-do-not-purge-lockres-that-is-being-migrat.patch @@ -0,0 +1,49 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:48 -0800 +Subject: ocfs2/dlm: Do not purge lockres that is being migrated dlm_purge_lockres() +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch attempts to fix a fine race between purging and migration. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmthread.c | 20 ++++++++++++++++++-- + 1 files changed, 18 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmthread.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmthread.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmthread.c +@@ -162,12 +162,28 @@ static int dlm_purge_lockres(struct dlm_ + + spin_lock(&res->spinlock); + if (!__dlm_lockres_unused(res)) { +- spin_unlock(&res->spinlock); + mlog(0, "%s:%.*s: tried to purge but not unused\n", + dlm->name, res->lockname.len, res->lockname.name); +- return -ENOTEMPTY; ++ __dlm_print_one_lock_resource(res); ++ spin_unlock(&res->spinlock); ++ BUG(); + } ++ ++ if (res->state & DLM_LOCK_RES_MIGRATING) { ++ mlog(0, "%s:%.*s: Delay dropref as this lockres is " ++ "being remastered\n", dlm->name, res->lockname.len, ++ res->lockname.name); ++ /* Re-add the lockres to the end of the purge list */ ++ if (!list_empty(&res->purge)) { ++ list_del_init(&res->purge); ++ list_add_tail(&res->purge, &dlm->purge_list); ++ } ++ spin_unlock(&res->spinlock); ++ return 0; ++ } ++ + master = (res->owner == dlm->node_num); ++ + if (!master) + res->state |= DLM_LOCK_RES_DROPPING_REF; + spin_unlock(&res->spinlock); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-encapsulate-adding-and-removing-of-mle-fr.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-encapsulate-adding-and-removing-of-mle-fr.patch new file mode 100644 index 000000000..405054b1f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-encapsulate-adding-and-removing-of-mle-fr.patch @@ -0,0 +1,125 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:37 -0800 +Subject: ocfs2/dlm: Encapsulate adding and removing of mle from dlm->master_list +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch encapsulates adding and removing of the mle from the +dlm->master_list. This patch is part of the series of patches that +converts the mle list to a mle hash. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 3 +++ + fs/ocfs2/dlm/dlmmaster.c | 34 +++++++++++++++++++++++----------- + 2 files changed, 26 insertions(+), 11 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -1008,6 +1008,9 @@ static inline void __dlm_wait_on_lockres + DLM_LOCK_RES_MIGRATING)); + } + ++void __dlm_unlink_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle); ++void __dlm_insert_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle); ++ + /* create/destroy slab caches */ + int dlm_init_master_caches(void); + void dlm_destroy_master_caches(void); +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -318,6 +318,21 @@ static void dlm_init_mle(struct dlm_mast + __dlm_mle_attach_hb_events(dlm, mle); + } + ++void __dlm_unlink_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle) ++{ ++ assert_spin_locked(&dlm->spinlock); ++ assert_spin_locked(&dlm->master_lock); ++ ++ if (!list_empty(&mle->list)) ++ list_del_init(&mle->list); ++} ++ ++void __dlm_insert_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle) ++{ ++ assert_spin_locked(&dlm->master_lock); ++ ++ list_add(&mle->list, &dlm->master_list); ++} + + /* returns 1 if found, 0 if not */ + static int dlm_find_mle(struct dlm_ctxt *dlm, +@@ -420,8 +435,7 @@ static void dlm_mle_release(struct kref + assert_spin_locked(&dlm->master_lock); + + /* remove from list if not already */ +- if (!list_empty(&mle->list)) +- list_del_init(&mle->list); ++ __dlm_unlink_mle(dlm, mle); + + /* detach the mle from the domain node up/down events */ + __dlm_mle_detach_hb_events(dlm, mle); +@@ -836,7 +850,7 @@ lookup: + alloc_mle = NULL; + dlm_init_mle(mle, DLM_MLE_MASTER, dlm, res, NULL, 0); + set_bit(dlm->node_num, mle->maybe_map); +- list_add(&mle->list, &dlm->master_list); ++ __dlm_insert_mle(dlm, mle); + + /* still holding the dlm spinlock, check the recovery map + * to see if there are any nodes that still need to be +@@ -1568,7 +1582,7 @@ way_up_top: + // "add the block.\n"); + dlm_init_mle(mle, DLM_MLE_BLOCK, dlm, NULL, name, namelen); + set_bit(request->node_idx, mle->maybe_map); +- list_add(&mle->list, &dlm->master_list); ++ __dlm_insert_mle(dlm, mle); + response = DLM_MASTER_RESP_NO; + } else { + // mlog(0, "mle was found\n"); +@@ -1960,7 +1974,7 @@ ok: + assert->node_idx, rr, extra_ref, mle->inuse); + dlm_print_one_mle(mle); + } +- list_del_init(&mle->list); ++ __dlm_unlink_mle(dlm, mle); + __dlm_mle_detach_hb_events(dlm, mle); + __dlm_put_mle(mle); + if (extra_ref) { +@@ -3137,10 +3151,8 @@ static int dlm_add_migration_mle(struct + tmp->master = master; + atomic_set(&tmp->woken, 1); + wake_up(&tmp->wq); +- /* remove it from the list so that only one +- * mle will be found */ +- list_del_init(&tmp->list); +- /* this was obviously WRONG. mle is uninited here. should be tmp. */ ++ /* remove it so that only one mle will be found */ ++ __dlm_unlink_mle(dlm, tmp); + __dlm_mle_detach_hb_events(dlm, tmp); + ret = DLM_MIGRATE_RESPONSE_MASTERY_REF; + mlog(0, "%s:%.*s: master=%u, newmaster=%u, " +@@ -3159,7 +3171,7 @@ static int dlm_add_migration_mle(struct + mle->master = master; + /* do this for consistency with other mle types */ + set_bit(new_master, mle->maybe_map); +- list_add(&mle->list, &dlm->master_list); ++ __dlm_insert_mle(dlm, mle); + + return ret; + } +@@ -3242,7 +3254,7 @@ top: + * list_head while in list_for_each_safe */ + __dlm_mle_detach_hb_events(dlm, mle); + spin_lock(&mle->spinlock); +- list_del_init(&mle->list); ++ __dlm_unlink_mle(dlm, mle); + atomic_set(&mle->woken, 1); + spin_unlock(&mle->spinlock); + wake_up(&mle->wq); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-fix-race-in-adding-removing-lockres-to-f.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-fix-race-in-adding-removing-lockres-to-f.patch new file mode 100644 index 000000000..d874869ef --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-fix-race-in-adding-removing-lockres-to-f.patch @@ -0,0 +1,176 @@ +From: Sunil Mushran +Date: Tue, 16 Dec 2008 15:49:22 -0800 +Subject: ocfs2/dlm: Fix race in adding/removing lockres' to/from the tracking list +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch adds a new lock, dlm->tracking_lock, to protect adding/removing +lockres' to/from the dlm->tracking_list. We were previously using dlm->spinlock +for the same, but that proved inadequate as we could be freeing a lockres from +a context that did not hold that lock. As the new lock only protects this list, +we can explicitly take it when removing the lockres from the tracking list. + +This bug was exposed when testing multiple processes concurrently flock() the +same file. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 3 ++ + fs/ocfs2/dlm/dlmdebug.c | 53 ++++++++++++++++++++------------------------- + fs/ocfs2/dlm/dlmdomain.c | 1 + + fs/ocfs2/dlm/dlmmaster.c | 10 ++++++++ + 4 files changed, 38 insertions(+), 29 deletions(-) + +diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h +index d5a86fb..bb53714 100644 +--- a/fs/ocfs2/dlm/dlmcommon.h ++++ b/fs/ocfs2/dlm/dlmcommon.h +@@ -140,6 +140,7 @@ struct dlm_ctxt + unsigned int purge_count; + spinlock_t spinlock; + spinlock_t ast_lock; ++ spinlock_t track_lock; + char *name; + u8 node_num; + u32 key; +@@ -316,6 +317,8 @@ struct dlm_lock_resource + * put on a list for the dlm thread to run. */ + unsigned long last_used; + ++ struct dlm_ctxt *dlm; ++ + unsigned migration_pending:1; + atomic_t asts_reserved; + spinlock_t spinlock; +diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c +index 1b81dcb..b32f60a 100644 +--- a/fs/ocfs2/dlm/dlmdebug.c ++++ b/fs/ocfs2/dlm/dlmdebug.c +@@ -630,43 +630,38 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos) + { + struct debug_lockres *dl = m->private; + struct dlm_ctxt *dlm = dl->dl_ctxt; ++ struct dlm_lock_resource *oldres = dl->dl_res; + struct dlm_lock_resource *res = NULL; ++ struct list_head *track_list; + +- spin_lock(&dlm->spinlock); ++ spin_lock(&dlm->track_lock); ++ if (oldres) ++ track_list = &oldres->tracking; ++ else ++ track_list = &dlm->tracking_list; + +- if (dl->dl_res) { +- list_for_each_entry(res, &dl->dl_res->tracking, tracking) { +- if (dl->dl_res) { +- dlm_lockres_put(dl->dl_res); +- dl->dl_res = NULL; +- } +- if (&res->tracking == &dlm->tracking_list) { +- mlog(0, "End of list found, %p\n", res); +- dl = NULL; +- break; +- } ++ list_for_each_entry(res, track_list, tracking) { ++ if (&res->tracking == &dlm->tracking_list) ++ res = NULL; ++ else + dlm_lockres_get(res); +- dl->dl_res = res; +- break; +- } +- } else { +- if (!list_empty(&dlm->tracking_list)) { +- list_for_each_entry(res, &dlm->tracking_list, tracking) +- break; +- dlm_lockres_get(res); +- dl->dl_res = res; +- } else +- dl = NULL; ++ break; + } ++ spin_unlock(&dlm->track_lock); + +- if (dl) { +- spin_lock(&dl->dl_res->spinlock); +- dump_lockres(dl->dl_res, dl->dl_buf, dl->dl_len - 1); +- spin_unlock(&dl->dl_res->spinlock); +- } ++ if (oldres) ++ dlm_lockres_put(oldres); + +- spin_unlock(&dlm->spinlock); ++ dl->dl_res = res; ++ ++ if (res) { ++ spin_lock(&res->spinlock); ++ dump_lockres(res, dl->dl_buf, dl->dl_len - 1); ++ spin_unlock(&res->spinlock); ++ } else ++ dl = NULL; + ++ /* passed to seq_show */ + return dl; + } + +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 63f8125..d8d578f 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1550,6 +1550,7 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, + spin_lock_init(&dlm->spinlock); + spin_lock_init(&dlm->master_lock); + spin_lock_init(&dlm->ast_lock); ++ spin_lock_init(&dlm->track_lock); + INIT_LIST_HEAD(&dlm->list); + INIT_LIST_HEAD(&dlm->dirty_list); + INIT_LIST_HEAD(&dlm->reco.resources); +diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c +index 92fd1d7..cbf3abe 100644 +--- a/fs/ocfs2/dlm/dlmmaster.c ++++ b/fs/ocfs2/dlm/dlmmaster.c +@@ -505,8 +505,10 @@ void dlm_change_lockres_owner(struct dlm_ctxt *dlm, + static void dlm_lockres_release(struct kref *kref) + { + struct dlm_lock_resource *res; ++ struct dlm_ctxt *dlm; + + res = container_of(kref, struct dlm_lock_resource, refs); ++ dlm = res->dlm; + + /* This should not happen -- all lockres' have a name + * associated with them at init time. */ +@@ -515,6 +517,7 @@ static void dlm_lockres_release(struct kref *kref) + mlog(0, "destroying lockres %.*s\n", res->lockname.len, + res->lockname.name); + ++ spin_lock(&dlm->track_lock); + if (!list_empty(&res->tracking)) + list_del_init(&res->tracking); + else { +@@ -522,6 +525,9 @@ static void dlm_lockres_release(struct kref *kref) + res->lockname.len, res->lockname.name); + dlm_print_one_lock_resource(res); + } ++ spin_unlock(&dlm->track_lock); ++ ++ dlm_put(dlm); + + if (!hlist_unhashed(&res->hash_node) || + !list_empty(&res->granted) || +@@ -595,6 +601,10 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm, + res->migration_pending = 0; + res->inflight_locks = 0; + ++ /* put in dlm_lockres_release */ ++ dlm_grab(dlm); ++ res->dlm = dlm; ++ + kref_init(&res->refs); + + /* just for consistency */ +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-improve-lockres-counts.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-improve-lockres-counts.patch new file mode 100644 index 000000000..3ff29f4fe --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-improve-lockres-counts.patch @@ -0,0 +1,148 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:44 -0800 +Subject: ocfs2/dlm: Improve lockres counts +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch replaces the lockres counts that tracked the number number of +locally and remotely mastered lockres' with a current and total count. The +total count is the number of lockres' that have been created since the dlm +domain was created. + +The number of locally and remotely mastered counts can be computed using +the locking_state output. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 5 ++--- + fs/ocfs2/dlm/dlmdebug.c | 12 ------------ + fs/ocfs2/dlm/dlmdomain.c | 5 ++--- + fs/ocfs2/dlm/dlmmaster.c | 27 +++++++-------------------- + 4 files changed, 11 insertions(+), 38 deletions(-) + +diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h +index 67b3447..e5026ce 100644 +--- a/fs/ocfs2/dlm/dlmcommon.h ++++ b/fs/ocfs2/dlm/dlmcommon.h +@@ -159,9 +159,8 @@ struct dlm_ctxt + /* these give a really vague idea of the system load */ + atomic_t mle_tot_count[DLM_MLE_NUM_TYPES]; + atomic_t mle_cur_count[DLM_MLE_NUM_TYPES]; +- atomic_t local_resources; +- atomic_t remote_resources; +- atomic_t unknown_resources; ++ atomic_t res_tot_count; ++ atomic_t res_cur_count; + + struct dlm_debug_ctxt *dlm_debug_ctxt; + struct dentry *dlm_debugfs_subroot; +diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c +index 336a98e..d7decaa 100644 +--- a/fs/ocfs2/dlm/dlmdebug.c ++++ b/fs/ocfs2/dlm/dlmdebug.c +@@ -763,12 +763,6 @@ static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db) + int out = 0; + struct dlm_reco_node_data *node; + char *state; +- int lres, rres, ures, tres; +- +- lres = atomic_read(&dlm->local_resources); +- rres = atomic_read(&dlm->remote_resources); +- ures = atomic_read(&dlm->unknown_resources); +- tres = lres + rres + ures; + + spin_lock(&dlm->spinlock); + +@@ -811,12 +805,6 @@ static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db) + db->buf + out, db->len - out); + out += snprintf(db->buf + out, db->len - out, "\n"); + +- /* Mastered Resources Total: xxx Locally: xxx Remotely: ... */ +- out += snprintf(db->buf + out, db->len - out, +- "Mastered Resources Total: %d Locally: %d " +- "Remotely: %d Unknown: %d\n", +- tres, lres, rres, ures); +- + /* Lists: Dirty=Empty Purge=InUse PendingASTs=Empty ... */ + out += snprintf(db->buf + out, db->len - out, + "Lists: Dirty=%s Purge=%s PendingASTs=%s " +diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c +index 0479bdf..4d9e6b2 100644 +--- a/fs/ocfs2/dlm/dlmdomain.c ++++ b/fs/ocfs2/dlm/dlmdomain.c +@@ -1604,10 +1604,9 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, + + dlm->reco.new_master = O2NM_INVALID_NODE_NUM; + dlm->reco.dead_node = O2NM_INVALID_NODE_NUM; +- atomic_set(&dlm->local_resources, 0); +- atomic_set(&dlm->remote_resources, 0); +- atomic_set(&dlm->unknown_resources, 0); + ++ atomic_set(&dlm->res_tot_count, 0); ++ atomic_set(&dlm->res_cur_count, 0); + for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) { + atomic_set(&dlm->mle_tot_count[i], 0); + atomic_set(&dlm->mle_cur_count[i], 0); +diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c +index acfc928..d70cdd5 100644 +--- a/fs/ocfs2/dlm/dlmmaster.c ++++ b/fs/ocfs2/dlm/dlmmaster.c +@@ -517,15 +517,6 @@ static void dlm_set_lockres_owner(struct dlm_ctxt *dlm, + { + assert_spin_locked(&res->spinlock); + +- mlog_entry("%.*s, %u\n", res->lockname.len, res->lockname.name, owner); +- +- if (owner == dlm->node_num) +- atomic_inc(&dlm->local_resources); +- else if (owner == DLM_LOCK_RES_OWNER_UNKNOWN) +- atomic_inc(&dlm->unknown_resources); +- else +- atomic_inc(&dlm->remote_resources); +- + res->owner = owner; + } + +@@ -534,17 +525,8 @@ void dlm_change_lockres_owner(struct dlm_ctxt *dlm, + { + assert_spin_locked(&res->spinlock); + +- if (owner == res->owner) +- return; +- +- if (res->owner == dlm->node_num) +- atomic_dec(&dlm->local_resources); +- else if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) +- atomic_dec(&dlm->unknown_resources); +- else +- atomic_dec(&dlm->remote_resources); +- +- dlm_set_lockres_owner(dlm, res, owner); ++ if (owner != res->owner) ++ dlm_set_lockres_owner(dlm, res, owner); + } + + +@@ -573,6 +555,8 @@ static void dlm_lockres_release(struct kref *kref) + } + spin_unlock(&dlm->track_lock); + ++ atomic_dec(&dlm->res_cur_count); ++ + dlm_put(dlm); + + if (!hlist_unhashed(&res->hash_node) || +@@ -653,6 +637,9 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm, + + kref_init(&res->refs); + ++ atomic_inc(&dlm->res_tot_count); ++ atomic_inc(&dlm->res_cur_count); ++ + /* just for consistency */ + spin_lock(&res->spinlock); + dlm_set_lockres_owner(dlm, res, DLM_LOCK_RES_OWNER_UNKNOWN); +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-indent-dlm_cleanup_master_list.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-indent-dlm_cleanup_master_list.patch new file mode 100644 index 000000000..8e993b5e0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-indent-dlm_cleanup_master_list.patch @@ -0,0 +1,140 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:42 -0800 +Subject: ocfs2/dlm: Indent dlm_cleanup_master_list() +Patch-mainline: 2.6.30 +References: bnc#408304 + +The previous patch explicitly did not indent dlm_cleanup_master_list() +so as to make the patch readable. This patch properly indents the +function. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmmaster.c | 106 ++++++++++++++++++++++----------------------- + 1 files changed, 52 insertions(+), 54 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -3298,66 +3298,64 @@ top: + mle = hlist_entry(list, struct dlm_master_list_entry, + master_hash_node); + +- BUG_ON(mle->type != DLM_MLE_BLOCK && +- mle->type != DLM_MLE_MASTER && +- mle->type != DLM_MLE_MIGRATION); +- +- /* MASTER mles are initiated locally. the waiting +- * process will notice the node map change +- * shortly. let that happen as normal. */ +- if (mle->type == DLM_MLE_MASTER) +- continue; +- +- +- /* BLOCK mles are initiated by other nodes. +- * need to clean up if the dead node would have +- * been the master. */ +- if (mle->type == DLM_MLE_BLOCK) { +- dlm_clean_block_mle(dlm, mle, dead_node); +- continue; +- } +- +- /* everything else is a MIGRATION mle */ +- +- /* the rule for MIGRATION mles is that the master +- * becomes UNKNOWN if *either* the original or +- * the new master dies. all UNKNOWN lockreses +- * are sent to whichever node becomes the recovery +- * master. the new master is responsible for +- * determining if there is still a master for +- * this lockres, or if he needs to take over +- * mastery. either way, this node should expect +- * another message to resolve this. */ +- if (mle->master != dead_node && +- mle->new_master != dead_node) +- continue; +- +- /* if we have reached this point, this mle needs to +- * be removed from the list and freed. */ +- dlm_clean_migration_mle(dlm, mle); +- +- mlog(0, "%s: node %u died during migration from " +- "%u to %u!\n", dlm->name, dead_node, +- mle->master, mle->new_master); +- +- /* If we find a lockres associated with the mle, we've +- * hit this rare case that messes up our lock ordering. +- * If so, we need to drop the master lock so that we can +- * take the lockres lock, meaning that we will have to +- * restart from the head of list. */ +- res = dlm_reset_mleres_owner(dlm, mle); +- if (res) +- /* restart */ +- goto top; ++ BUG_ON(mle->type != DLM_MLE_BLOCK && ++ mle->type != DLM_MLE_MASTER && ++ mle->type != DLM_MLE_MIGRATION); ++ ++ /* MASTER mles are initiated locally. The waiting ++ * process will notice the node map change shortly. ++ * Let that happen as normal. */ ++ if (mle->type == DLM_MLE_MASTER) ++ continue; ++ ++ /* BLOCK mles are initiated by other nodes. Need to ++ * clean up if the dead node would have been the ++ * master. */ ++ if (mle->type == DLM_MLE_BLOCK) { ++ dlm_clean_block_mle(dlm, mle, dead_node); ++ continue; ++ } ++ ++ /* Everything else is a MIGRATION mle */ ++ ++ /* The rule for MIGRATION mles is that the master ++ * becomes UNKNOWN if *either* the original or the new ++ * master dies. All UNKNOWN lockres' are sent to ++ * whichever node becomes the recovery master. The new ++ * master is responsible for determining if there is ++ * still a master for this lockres, or if he needs to ++ * take over mastery. Either way, this node should ++ * expect another message to resolve this. */ ++ ++ if (mle->master != dead_node && ++ mle->new_master != dead_node) ++ continue; ++ ++ /* If we have reached this point, this mle needs to be ++ * removed from the list and freed. */ ++ dlm_clean_migration_mle(dlm, mle); ++ ++ mlog(0, "%s: node %u died during migration from " ++ "%u to %u!\n", dlm->name, dead_node, mle->master, ++ mle->new_master); ++ ++ /* If we find a lockres associated with the mle, we've ++ * hit this rare case that messes up our lock ordering. ++ * If so, we need to drop the master lock so that we can ++ * take the lockres lock, meaning that we will have to ++ * restart from the head of list. */ ++ res = dlm_reset_mleres_owner(dlm, mle); ++ if (res) ++ /* restart */ ++ goto top; + +- /* this may be the last reference */ +- __dlm_put_mle(mle); +- } ++ /* This may be the last reference */ ++ __dlm_put_mle(mle); ++ } + } + spin_unlock(&dlm->master_lock); + } + +- + int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, + u8 old_master) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-make-dlm_assert_master_handler-kill-its.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-make-dlm_assert_master_handler-kill-its.patch new file mode 100644 index 000000000..5fab6da06 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-make-dlm_assert_master_handler-kill-its.patch @@ -0,0 +1,43 @@ +From: Sunil Mushran +Date: Tue, 3 Feb 2009 12:37:16 -0800 +Subject: [PATCH] ocfs2/dlm: Make dlm_assert_master_handler() kill itself instead of the asserter +Patch-mainline: 2.6.29 + +In dlm_assert_master_handler(), if we get an incorrect assert master from a node +that, we reply with EINVAL asking the asserter to die. The problem is that an +assert is sent after so many hoops, it is invariably the node that thinks the +asserter is wrong, is actually wrong. So instead of killing the asserter, this +patch kills the assertee. + +This patch papers over a race that is still being addressed. + +Signed-off-by: Sunil Mushran +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmmaster.c | 12 ++++++------ + 1 files changed, 6 insertions(+), 6 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/dlm/dlmmaster.c +@@ -1832,12 +1832,12 @@ int dlm_assert_master_handler(struct o2n + if (!mle) { + if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN && + res->owner != assert->node_idx) { +- mlog(ML_ERROR, "assert_master from " +- "%u, but current owner is " +- "%u! (%.*s)\n", +- assert->node_idx, res->owner, +- namelen, name); +- goto kill; ++ mlog(ML_ERROR, "DIE! Mastery assert from %u, " ++ "but current owner is %u! (%.*s)\n", ++ assert->node_idx, res->owner, namelen, ++ name); ++ __dlm_print_one_lock_resource(res); ++ BUG(); + } + } else if (mle->type != DLM_MLE_MIGRATION) { + if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-refactor-dlm_clean_master_list.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-refactor-dlm_clean_master_list.patch new file mode 100644 index 000000000..c940d6076 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-refactor-dlm_clean_master_list.patch @@ -0,0 +1,200 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:39 -0800 +Subject: ocfs2/dlm: Refactor dlm_clean_master_list() +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch refactors dlm_clean_master_list() so as to make it +easier to convert the mle list to a hash. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmmaster.c | 148 ++++++++++++++++++++++++++------------------- + 1 files changed, 85 insertions(+), 63 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -3185,12 +3185,87 @@ static int dlm_add_migration_mle(struct + return ret; + } + ++/* ++ * Sets the owner of the lockres, associated to the mle, to UNKNOWN ++ */ ++static struct dlm_lock_resource *dlm_reset_mleres_owner(struct dlm_ctxt *dlm, ++ struct dlm_master_list_entry *mle) ++{ ++ struct dlm_lock_resource *res; ++ unsigned int hash; ++ ++ /* Find the lockres associated to the mle and set its owner to UNK */ ++ hash = dlm_lockid_hash(mle->u.mlename.name, mle->u.mlename.len); ++ res = __dlm_lookup_lockres(dlm, mle->u.mlename.name, mle->u.mlename.len, ++ hash); ++ if (res) { ++ spin_unlock(&dlm->master_lock); ++ ++ /* move lockres onto recovery list */ ++ spin_lock(&res->spinlock); ++ dlm_set_lockres_owner(dlm, res, DLM_LOCK_RES_OWNER_UNKNOWN); ++ dlm_move_lockres_to_recovery_list(dlm, res); ++ spin_unlock(&res->spinlock); ++ dlm_lockres_put(res); ++ ++ /* about to get rid of mle, detach from heartbeat */ ++ __dlm_mle_detach_hb_events(dlm, mle); ++ ++ /* dump the mle */ ++ spin_lock(&dlm->master_lock); ++ __dlm_put_mle(mle); ++ spin_unlock(&dlm->master_lock); ++ } ++ ++ return res; ++} ++ ++static void dlm_clean_migration_mle(struct dlm_ctxt *dlm, ++ struct dlm_master_list_entry *mle) ++{ ++ __dlm_mle_detach_hb_events(dlm, mle); ++ ++ spin_lock(&mle->spinlock); ++ __dlm_unlink_mle(dlm, mle); ++ atomic_set(&mle->woken, 1); ++ spin_unlock(&mle->spinlock); ++ ++ wake_up(&mle->wq); ++} ++ ++static void dlm_clean_block_mle(struct dlm_ctxt *dlm, ++ struct dlm_master_list_entry *mle, u8 dead_node) ++{ ++ int bit; ++ ++ BUG_ON(mle->type != DLM_MLE_BLOCK); ++ ++ spin_lock(&mle->spinlock); ++ bit = find_next_bit(mle->maybe_map, O2NM_MAX_NODES, 0); ++ if (bit != dead_node) { ++ mlog(0, "mle found, but dead node %u would not have been " ++ "master\n", dead_node); ++ spin_unlock(&mle->spinlock); ++ } else { ++ /* Must drop the refcount by one since the assert_master will ++ * never arrive. This may result in the mle being unlinked and ++ * freed, but there may still be a process waiting in the ++ * dlmlock path which is fine. */ ++ mlog(0, "node %u was expected master\n", dead_node); ++ atomic_set(&mle->woken, 1); ++ spin_unlock(&mle->spinlock); ++ wake_up(&mle->wq); ++ ++ /* Do not need events any longer, so detach from heartbeat */ ++ __dlm_mle_detach_hb_events(dlm, mle); ++ __dlm_put_mle(mle); ++ } ++} + + void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node) + { + struct dlm_master_list_entry *mle, *next; + struct dlm_lock_resource *res; +- unsigned int hash; + + mlog_entry("dlm=%s, dead node=%u\n", dlm->name, dead_node); + top: +@@ -3214,30 +3289,7 @@ top: + * need to clean up if the dead node would have + * been the master. */ + if (mle->type == DLM_MLE_BLOCK) { +- int bit; +- +- spin_lock(&mle->spinlock); +- bit = find_next_bit(mle->maybe_map, O2NM_MAX_NODES, 0); +- if (bit != dead_node) { +- mlog(0, "mle found, but dead node %u would " +- "not have been master\n", dead_node); +- spin_unlock(&mle->spinlock); +- } else { +- /* must drop the refcount by one since the +- * assert_master will never arrive. this +- * may result in the mle being unlinked and +- * freed, but there may still be a process +- * waiting in the dlmlock path which is fine. */ +- mlog(0, "node %u was expected master\n", +- dead_node); +- atomic_set(&mle->woken, 1); +- spin_unlock(&mle->spinlock); +- wake_up(&mle->wq); +- /* do not need events any longer, so detach +- * from heartbeat */ +- __dlm_mle_detach_hb_events(dlm, mle); +- __dlm_put_mle(mle); +- } ++ dlm_clean_block_mle(dlm, mle, dead_node); + continue; + } + +@@ -3258,51 +3310,21 @@ top: + + /* if we have reached this point, this mle needs to + * be removed from the list and freed. */ +- +- /* remove from the list early. NOTE: unlinking +- * list_head while in list_for_each_safe */ +- __dlm_mle_detach_hb_events(dlm, mle); +- spin_lock(&mle->spinlock); +- __dlm_unlink_mle(dlm, mle); +- atomic_set(&mle->woken, 1); +- spin_unlock(&mle->spinlock); +- wake_up(&mle->wq); ++ dlm_clean_migration_mle(dlm, mle); + + mlog(0, "%s: node %u died during migration from " + "%u to %u!\n", dlm->name, dead_node, + mle->master, mle->new_master); +- /* if there is a lockres associated with this +- * mle, find it and set its owner to UNKNOWN */ +- hash = dlm_lockid_hash(mle->u.mlename.name, mle->u.mlename.len); +- res = __dlm_lookup_lockres(dlm, mle->u.mlename.name, +- mle->u.mlename.len, hash); +- if (res) { +- /* unfortunately if we hit this rare case, our +- * lock ordering is messed. we need to drop +- * the master lock so that we can take the +- * lockres lock, meaning that we will have to +- * restart from the head of list. */ +- spin_unlock(&dlm->master_lock); +- +- /* move lockres onto recovery list */ +- spin_lock(&res->spinlock); +- dlm_set_lockres_owner(dlm, res, +- DLM_LOCK_RES_OWNER_UNKNOWN); +- dlm_move_lockres_to_recovery_list(dlm, res); +- spin_unlock(&res->spinlock); +- dlm_lockres_put(res); +- +- /* about to get rid of mle, detach from heartbeat */ +- __dlm_mle_detach_hb_events(dlm, mle); +- +- /* dump the mle */ +- spin_lock(&dlm->master_lock); +- __dlm_put_mle(mle); +- spin_unlock(&dlm->master_lock); + ++ /* If we find a lockres associated with the mle, we've ++ * hit this rare case that messes up our lock ordering. ++ * If so, we need to drop the master lock so that we can ++ * take the lockres lock, meaning that we will have to ++ * restart from the head of list. */ ++ res = dlm_reset_mleres_owner(dlm, mle); ++ if (res) + /* restart */ + goto top; +- } + + /* this may be the last reference */ + __dlm_put_mle(mle); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-remove-struct-dlm_lock_name-in-struct-dlm.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-remove-struct-dlm_lock_name-in-struct-dlm.patch new file mode 100644 index 000000000..8fad9b703 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-remove-struct-dlm_lock_name-in-struct-dlm.patch @@ -0,0 +1,233 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:47 -0800 +Subject: ocfs2/dlm: Remove struct dlm_lock_name in struct dlm_master_list_entry +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch removes struct dlm_lock_name and adds the entries directly +to struct dlm_master_list_entry. Under the new scheme, both mles that +are backed by a lockres or not, will have the name populated in mle->mname. +This allows us to get rid of code that was figuring out the location of +the mle name. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 14 +++------- + fs/ocfs2/dlm/dlmdebug.c | 12 +------- + fs/ocfs2/dlm/dlmmaster.c | 68 ++++++++++++--------------------------------- + 3 files changed, 23 insertions(+), 71 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -56,12 +56,6 @@ enum dlm_mle_type { + DLM_MLE_NUM_TYPES + }; + +-struct dlm_lock_name { +- unsigned int hash; +- unsigned int len; +- unsigned char name[DLM_LOCKID_NAME_MAX]; +-}; +- + struct dlm_master_list_entry { + struct hlist_node master_hash_node; + struct list_head hb_events; +@@ -80,10 +74,10 @@ struct dlm_master_list_entry { + enum dlm_mle_type type; + struct o2hb_callback_func mle_hb_up; + struct o2hb_callback_func mle_hb_down; +- union { +- struct dlm_lock_resource *mleres; +- struct dlm_lock_name mlename; +- } u; ++ struct dlm_lock_resource *mleres; ++ unsigned char mname[DLM_LOCKID_NAME_MAX]; ++ unsigned int mnamelen; ++ unsigned int mnamehash; + }; + + enum dlm_ast_type { +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdebug.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +@@ -287,18 +287,8 @@ static int stringify_nodemap(unsigned lo + static int dump_mle(struct dlm_master_list_entry *mle, char *buf, int len) + { + int out = 0; +- unsigned int namelen; +- unsigned char *name; + char *mle_type; + +- if (mle->type != DLM_MLE_MASTER) { +- name = mle->u.mlename.name; +- namelen = mle->u.mlename.len; +- } else { +- name = (unsigned char *)mle->u.mleres->lockname.name; +- namelen = mle->u.mleres->lockname.len; +- } +- + if (mle->type == DLM_MLE_BLOCK) + mle_type = "BLK"; + else if (mle->type == DLM_MLE_MASTER) +@@ -306,7 +296,7 @@ static int dump_mle(struct dlm_master_li + else + mle_type = "MIG"; + +- out += stringify_lockname(name, namelen, buf + out, len - out); ++ out += stringify_lockname(mle->mname, mle->mnamelen, buf + out, len - out); + out += snprintf(buf + out, len - out, + "\t%3s\tmas=%3u\tnew=%3u\tevt=%1d\tuse=%1d\tref=%3d\n", + mle_type, mle->master, mle->new_master, +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -68,41 +68,16 @@ static int dlm_do_assert_master(struct d + void *nodemap, u32 flags); + static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data); + +-static inline void __dlm_mle_name(struct dlm_master_list_entry *mle, +- unsigned char **name, unsigned int *namelen, +- unsigned int *namehash) +-{ +- BUG_ON(mle->type != DLM_MLE_BLOCK && +- mle->type != DLM_MLE_MASTER && +- mle->type != DLM_MLE_MIGRATION); +- +- if (mle->type != DLM_MLE_MASTER) { +- *name = mle->u.mlename.name; +- *namelen = mle->u.mlename.len; +- if (namehash) +- *namehash = mle->u.mlename.hash; +- } else { +- *name = (unsigned char *)mle->u.mleres->lockname.name; +- *namelen = mle->u.mleres->lockname.len; +- if (namehash) +- *namehash = mle->u.mleres->lockname.hash; +- } +-} +- + static inline int dlm_mle_equal(struct dlm_ctxt *dlm, + struct dlm_master_list_entry *mle, + const char *name, + unsigned int namelen) + { +- unsigned char *mlename; +- unsigned int mlelen; +- + if (dlm != mle->dlm) + return 0; + +- __dlm_mle_name(mle, &mlename, &mlelen, NULL); +- +- if (namelen != mlelen || memcmp(name, mlename, namelen) != 0) ++ if (namelen != mle->mnamelen || ++ memcmp(name, mle->mname, namelen) != 0) + return 0; + + return 1; +@@ -317,12 +292,16 @@ static void dlm_init_mle(struct dlm_mast + + if (mle->type == DLM_MLE_MASTER) { + BUG_ON(!res); +- mle->u.mleres = res; ++ mle->mleres = res; ++ memcpy(mle->mname, res->lockname.name, res->lockname.len); ++ mle->mnamelen = res->lockname.len; ++ mle->mnamehash = res->lockname.hash; + } else { + BUG_ON(!name); +- memcpy(mle->u.mlename.name, name, namelen); +- mle->u.mlename.len = namelen; +- mle->u.mlename.hash = dlm_lockid_hash(name, namelen); ++ mle->mleres = NULL; ++ memcpy(mle->mname, name, namelen); ++ mle->mnamelen = namelen; ++ mle->mnamehash = dlm_lockid_hash(name, namelen); + } + + atomic_inc(&dlm->mle_tot_count[mle->type]); +@@ -350,13 +329,10 @@ void __dlm_unlink_mle(struct dlm_ctxt *d + void __dlm_insert_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle) + { + struct hlist_head *bucket; +- unsigned char *mname; +- unsigned int mlen, hash; + + assert_spin_locked(&dlm->master_lock); + +- __dlm_mle_name(mle, &mname, &mlen, &hash); +- bucket = dlm_master_hash(dlm, hash); ++ bucket = dlm_master_hash(dlm, mle->mnamehash); + hlist_add_head(&mle->master_hash_node, bucket); + } + +@@ -450,8 +426,6 @@ static void dlm_mle_release(struct kref + { + struct dlm_master_list_entry *mle; + struct dlm_ctxt *dlm; +- unsigned char *mname; +- unsigned int mlen; + + mlog_entry_void(); + +@@ -461,8 +435,8 @@ static void dlm_mle_release(struct kref + assert_spin_locked(&dlm->spinlock); + assert_spin_locked(&dlm->master_lock); + +- __dlm_mle_name(mle, &mname, &mlen, NULL); +- mlog(0, "Releasing mle for %.*s, type %d\n", mlen, mname, mle->type); ++ mlog(0, "Releasing mle for %.*s, type %d\n", mle->mnamelen, mle->mname, ++ mle->type); + + /* remove from list if not already */ + __dlm_unlink_mle(dlm, mle); +@@ -1277,7 +1251,7 @@ static int dlm_restart_lock_mastery(stru + res->lockname.len, + res->lockname.name); + mle->type = DLM_MLE_MASTER; +- mle->u.mleres = res; ++ mle->mleres = res; + } + } + } +@@ -1316,18 +1290,14 @@ static int dlm_do_master_request(struct + struct dlm_ctxt *dlm = mle->dlm; + struct dlm_master_request request; + int ret, response=0, resend; +- unsigned char *mlename; +- unsigned int mlenamelen; + + memset(&request, 0, sizeof(request)); + request.node_idx = dlm->node_num; + + BUG_ON(mle->type == DLM_MLE_MIGRATION); + +- __dlm_mle_name(mle, &mlename, &mlenamelen, NULL); +- +- request.namelen = (u8)mlenamelen; +- memcpy(request.name, mlename, request.namelen); ++ request.namelen = (u8)mle->mnamelen; ++ memcpy(request.name, mle->mname, request.namelen); + + again: + ret = o2net_send_message(DLM_MASTER_REQUEST_MSG, dlm->key, &request, +@@ -3181,12 +3151,10 @@ static struct dlm_lock_resource *dlm_res + struct dlm_master_list_entry *mle) + { + struct dlm_lock_resource *res; +- unsigned int hash; + + /* Find the lockres associated to the mle and set its owner to UNK */ +- hash = dlm_lockid_hash(mle->u.mlename.name, mle->u.mlename.len); +- res = __dlm_lookup_lockres(dlm, mle->u.mlename.name, mle->u.mlename.len, +- hash); ++ res = __dlm_lookup_lockres(dlm, mle->mname, mle->mnamelen, ++ mle->mnamehash); + if (res) { + spin_unlock(&dlm->master_lock); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-show-the-number-of-lockres-mles-in-dlm_st.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-show-the-number-of-lockres-mles-in-dlm_st.patch new file mode 100644 index 000000000..89766a1c2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-show-the-number-of-lockres-mles-in-dlm_st.patch @@ -0,0 +1,68 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:46 -0800 +Subject: ocfs2/dlm: Show the number of lockres/mles in dlm_state +Patch-mainline: 2.6.30 +References: bnc#408304 + +This patch shows the number of lockres' and mles in the debugfs file, dlm_state. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmdebug.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 files changed, 36 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdebug.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdebug.c +@@ -763,6 +763,8 @@ static int debug_state_print(struct dlm_ + int out = 0; + struct dlm_reco_node_data *node; + char *state; ++ int cur_mles = 0, tot_mles = 0; ++ int i; + + spin_lock(&dlm->spinlock); + +@@ -805,6 +807,40 @@ static int debug_state_print(struct dlm_ + db->buf + out, db->len - out); + out += snprintf(db->buf + out, db->len - out, "\n"); + ++ /* Lock Resources: xxx (xxx) */ ++ out += snprintf(db->buf + out, db->len - out, ++ "Lock Resources: %d (%d)\n", ++ atomic_read(&dlm->res_cur_count), ++ atomic_read(&dlm->res_tot_count)); ++ ++ for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) ++ tot_mles += atomic_read(&dlm->mle_tot_count[i]); ++ ++ for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) ++ cur_mles += atomic_read(&dlm->mle_cur_count[i]); ++ ++ /* MLEs: xxx (xxx) */ ++ out += snprintf(db->buf + out, db->len - out, ++ "MLEs: %d (%d)\n", cur_mles, tot_mles); ++ ++ /* Blocking: xxx (xxx) */ ++ out += snprintf(db->buf + out, db->len - out, ++ " Blocking: %d (%d)\n", ++ atomic_read(&dlm->mle_cur_count[DLM_MLE_BLOCK]), ++ atomic_read(&dlm->mle_tot_count[DLM_MLE_BLOCK])); ++ ++ /* Mastery: xxx (xxx) */ ++ out += snprintf(db->buf + out, db->len - out, ++ " Mastery: %d (%d)\n", ++ atomic_read(&dlm->mle_cur_count[DLM_MLE_MASTER]), ++ atomic_read(&dlm->mle_tot_count[DLM_MLE_MASTER])); ++ ++ /* Migration: xxx (xxx) */ ++ out += snprintf(db->buf + out, db->len - out, ++ " Migration: %d (%d)\n", ++ atomic_read(&dlm->mle_cur_count[DLM_MLE_MIGRATION]), ++ atomic_read(&dlm->mle_tot_count[DLM_MLE_MIGRATION])); ++ + /* Lists: Dirty=Empty Purge=InUse PendingASTs=Empty ... */ + out += snprintf(db->buf + out, db->len - out, + "Lists: Dirty=%s Purge=%s PendingASTs=%s " diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-track-number-of-mles.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-track-number-of-mles.patch new file mode 100644 index 000000000..05ed15a88 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-track-number-of-mles.patch @@ -0,0 +1,82 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:43 -0800 +Subject: ocfs2/dlm: Track number of mles +Patch-mainline: 2.6.30 +References: bnc#408304 + +The lifetime of a mle is limited to the duration of the lockres mastery +process. While typically this lifetime is fairly short, we have noticed +the number of mles explode under certain circumstances. This patch tracks +the number of each different types of mles and should help us determine +how best to speed up the mastery process. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmcommon.h | 5 ++++- + fs/ocfs2/dlm/dlmdomain.c | 5 +++++ + fs/ocfs2/dlm/dlmmaster.c | 5 +++++ + 3 files changed, 14 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmcommon.h ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmcommon.h +@@ -52,7 +52,8 @@ + enum dlm_mle_type { + DLM_MLE_BLOCK, + DLM_MLE_MASTER, +- DLM_MLE_MIGRATION ++ DLM_MLE_MIGRATION, ++ DLM_MLE_NUM_TYPES + }; + + struct dlm_lock_name { +@@ -156,6 +157,8 @@ struct dlm_ctxt + struct list_head mle_hb_events; + + /* these give a really vague idea of the system load */ ++ atomic_t mle_tot_count[DLM_MLE_NUM_TYPES]; ++ atomic_t mle_cur_count[DLM_MLE_NUM_TYPES]; + atomic_t local_resources; + atomic_t remote_resources; + atomic_t unknown_resources; +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdomain.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmdomain.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmdomain.c +@@ -1608,6 +1608,11 @@ static struct dlm_ctxt *dlm_alloc_ctxt(c + atomic_set(&dlm->remote_resources, 0); + atomic_set(&dlm->unknown_resources, 0); + ++ for (i = 0; i < DLM_MLE_NUM_TYPES; ++i) { ++ atomic_set(&dlm->mle_tot_count[i], 0); ++ atomic_set(&dlm->mle_cur_count[i], 0); ++ } ++ + spin_lock_init(&dlm->work_lock); + INIT_LIST_HEAD(&dlm->work_list); + INIT_WORK(&dlm->dispatched_work, dlm_dispatch_work); +Index: linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update.orig/fs/ocfs2/dlm/dlmmaster.c ++++ linux-2.6.27-sle11_ocfs2_update/fs/ocfs2/dlm/dlmmaster.c +@@ -325,6 +325,9 @@ static void dlm_init_mle(struct dlm_mast + mle->u.mlename.hash = dlm_lockid_hash(name, namelen); + } + ++ atomic_inc(&dlm->mle_tot_count[mle->type]); ++ atomic_inc(&dlm->mle_cur_count[mle->type]); ++ + /* copy off the node_map and register hb callbacks on our copy */ + memcpy(mle->node_map, dlm->domain_map, sizeof(mle->node_map)); + memcpy(mle->vote_map, dlm->domain_map, sizeof(mle->vote_map)); +@@ -467,6 +470,8 @@ static void dlm_mle_release(struct kref + /* detach the mle from the domain node up/down events */ + __dlm_mle_detach_hb_events(dlm, mle); + ++ atomic_dec(&dlm->mle_cur_count[mle->type]); ++ + /* NOTE: kfree under spinlock here. + * if this is bad, we can move this to a freelist. */ + kmem_cache_free(dlm_mle_cache, mle); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-tweak-mle_state-output.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-tweak-mle_state-output.patch new file mode 100644 index 000000000..0cbcbb049 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-tweak-mle_state-output.patch @@ -0,0 +1,48 @@ +From: Sunil Mushran +Date: Thu, 26 Feb 2009 15:00:49 -0800 +Subject: ocfs2/dlm: Tweak mle_state output +Patch-mainline: 2.6.30 +References: bnc#408304 + +The debugfs file, mle_state, now prints the number of largest number of mles +in one hash link. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmdebug.c | 7 +++++-- + 1 files changed, 5 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/dlm/dlmdebug.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/dlm/dlmdebug.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/dlm/dlmdebug.c +@@ -494,7 +494,7 @@ static int debug_mle_print(struct dlm_ct + struct hlist_head *bucket; + struct hlist_node *list; + int i, out = 0; +- unsigned long total = 0; ++ unsigned long total = 0, longest = 0, bktcnt; + + out += snprintf(db->buf + out, db->len - out, + "Dumping MLEs for Domain: %s\n", dlm->name); +@@ -506,15 +506,18 @@ static int debug_mle_print(struct dlm_ct + mle = hlist_entry(list, struct dlm_master_list_entry, + master_hash_node); + ++total; ++ ++bktcnt; + if (db->len - out < 200) + continue; + out += dump_mle(mle, db->buf + out, db->len - out); + } ++ longest = max(longest, bktcnt); ++ bktcnt = 0; + } + spin_unlock(&dlm->master_lock); + + out += snprintf(db->buf + out, db->len - out, +- "Total on list: %ld\n", total); ++ "Total: %ld, Longest: %ld\n", total, longest); + return out; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-use-ast_lock-to-protect-ast_list.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-use-ast_lock-to-protect-ast_list.patch new file mode 100644 index 000000000..456455f04 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-dlm-use-ast_lock-to-protect-ast_list.patch @@ -0,0 +1,33 @@ +From: Sunil Mushran +Date: Tue, 3 Feb 2009 12:37:15 -0800 +Subject: [PATCH] ocfs2/dlm: Use ast_lock to protect ast_list +Patch-mainline: 2.6.29 + +The code was using dlm->spinlock instead of dlm->ast_lock to protect the +ast_list. This patch fixes the issue. + +Signed-off-by: Sunil Mushran +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmunlock.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/dlm/dlmunlock.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/dlm/dlmunlock.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/dlm/dlmunlock.c +@@ -117,11 +117,11 @@ static enum dlm_status dlmunlock_common( + else + BUG_ON(res->owner == dlm->node_num); + +- spin_lock(&dlm->spinlock); ++ spin_lock(&dlm->ast_lock); + /* We want to be sure that we're not freeing a lock + * that still has AST's pending... */ + in_use = !list_empty(&lock->ast_list); +- spin_unlock(&dlm->spinlock); ++ spin_unlock(&dlm->ast_lock); + if (in_use) { + mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock " + "while waiting for an ast!", res->lockname.len, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-a-bug-found-by-sparse-check.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-a-bug-found-by-sparse-check.patch new file mode 100644 index 000000000..dcd6a2f79 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-a-bug-found-by-sparse-check.patch @@ -0,0 +1,29 @@ +From: Tao Ma +Date: Thu, 12 Mar 2009 06:24:23 +0800 +Subject: [PATCH] ocfs2: Fix a bug found by sparse check. +Patch-mainline: 2.6.29 + +We need to use le32_to_cpu to test rec->e_cpos in +ocfs2_dinode_insert_check. + +Signed-off-by: Tao Ma +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/alloc.c +@@ -174,7 +174,8 @@ static int ocfs2_dinode_insert_check(str + + BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) && +- (OCFS2_I(inode)->ip_clusters != rec->e_cpos), ++ (OCFS2_I(inode)->ip_clusters != ++ le32_to_cpu(rec->e_cpos)), + "Device %s, asking for sparse allocation: inode %llu, " + "cpos %u, clusters %u\n", + osb->dev_str, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-function-declaration-and-definition-in-xa.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-function-declaration-and-definition-in-xa.patch new file mode 100644 index 000000000..a04a353c4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-function-declaration-and-definition-in-xa.patch @@ -0,0 +1,102 @@ +From: Tiger Yang +Date: Thu, 23 Oct 2008 16:33:33 +0800 +Subject: ocfs2: fix function declaration and definition in xattr + +Because we merged the xattr sources into one file, some functions +no longer belong in the header file. + +Signed-off-by: Tiger Yang +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 28 +++++++++++++++++++++++----- + fs/ocfs2/xattr.h | 26 ++++---------------------- + 2 files changed, 27 insertions(+), 27 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 2f8952e..420d8e3 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -132,6 +132,24 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, + static int ocfs2_delete_xattr_index_block(struct inode *inode, + struct buffer_head *xb_bh); + ++static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) ++{ ++ return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE; ++} ++ ++static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) ++{ ++ return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); ++} ++ ++static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) ++{ ++ u16 len = sb->s_blocksize - ++ offsetof(struct ocfs2_xattr_header, xh_entries); ++ ++ return len / sizeof(struct ocfs2_xattr_entry); ++} ++ + static inline const char *ocfs2_xattr_prefix(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -832,11 +850,11 @@ cleanup: + * Copy an extended attribute into the buffer provided. + * Buffer is NULL to compute the size of buffer required. + */ +-int ocfs2_xattr_get(struct inode *inode, +- int name_index, +- const char *name, +- void *buffer, +- size_t buffer_size) ++static int ocfs2_xattr_get(struct inode *inode, ++ int name_index, ++ const char *name, ++ void *buffer, ++ size_t buffer_size) + { + int ret; + struct ocfs2_dinode *di = NULL; +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index e4e45c8..1d8314c 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -32,29 +32,11 @@ enum ocfs2_xattr_type { + + extern struct xattr_handler ocfs2_xattr_user_handler; + extern struct xattr_handler ocfs2_xattr_trusted_handler; +- +-extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); +-extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t); +-extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *, +- size_t, int); +-extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh); + extern struct xattr_handler *ocfs2_xattr_handlers[]; + +-static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) +-{ +- return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE; +-} +- +-static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) +-{ +- return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); +-} +- +-static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) +-{ +- u16 len = sb->s_blocksize - +- offsetof(struct ocfs2_xattr_header, xh_entries); ++ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); ++int ocfs2_xattr_set(struct inode *, int, const char *, const void *, ++ size_t, int); ++int ocfs2_xattr_remove(struct inode *, struct buffer_head *); + +- return len / sizeof(struct ocfs2_xattr_entry); +-} + #endif /* OCFS2_XATTR_H */ +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-license-in-xattr.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-license-in-xattr.patch new file mode 100644 index 000000000..4efb3c647 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-license-in-xattr.patch @@ -0,0 +1,82 @@ +From: Tiger Yang +Date: Thu, 23 Oct 2008 16:33:03 +0800 +Subject: ocfs2: fix license in xattr + +This patch fixes the license in xattr.c and xattr.h. + +Signed-off-by: Tiger Yang +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 13 ++++--------- + fs/ocfs2/xattr.h | 12 ++---------- + 2 files changed, 6 insertions(+), 19 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 802c414..2f8952e 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -3,25 +3,20 @@ + * + * xattr.c + * +- * Copyright (C) 2008 Oracle. All rights reserved. ++ * Copyright (C) 2004, 2008 Oracle. All rights reserved. + * + * CREDITS: +- * Lots of code in this file is taken from ext3. ++ * Lots of code in this file is copy from linux/fs/ext3/xattr.c. ++ * Copyright (C) 2001-2003 Andreas Gruenbacher, + * + * 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. ++ * License version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public +- * License along with this program; if not, write to the +- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, +- * Boston, MA 021110-1307, USA. + */ + + #include +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index c25c7c6..e4e45c8 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -3,24 +3,16 @@ + * + * xattr.h + * +- * Function prototypes +- * +- * Copyright (C) 2008 Oracle. All rights reserved. ++ * Copyright (C) 2004, 2008 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. ++ * License version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public +- * License along with this program; if not, write to the +- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, +- * Boston, MA 021110-1307, USA. + */ + + #ifndef OCFS2_XATTR_H +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-printk-related-build-warnings-in-xattr.c.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-printk-related-build-warnings-in-xattr.c.patch new file mode 100644 index 000000000..61bb34f0a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-printk-related-build-warnings-in-xattr.c.patch @@ -0,0 +1,138 @@ +From: Mark Fasheh +Date: Wed, 29 Oct 2008 14:45:30 -0700 +Subject: ocfs2: fix printk related build warnings in xattr.c + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 34 ++++++++++++++++++++-------------- + 1 files changed, 20 insertions(+), 14 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -2336,7 +2336,8 @@ static int ocfs2_xattr_index_block_find( + BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash); + + mlog(0, "find xattr extent rec %u clusters from %llu, the first hash " +- "in the rec is %u\n", num_clusters, p_blkno, first_hash); ++ "in the rec is %u\n", num_clusters, (unsigned long long)p_blkno, ++ first_hash); + + ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash, + p_blkno, first_hash, num_clusters, xs); +@@ -2360,7 +2361,7 @@ static int ocfs2_iterate_xattr_buckets(s + memset(&bucket, 0, sizeof(bucket)); + + mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n", +- clusters, blkno); ++ clusters, (unsigned long long)blkno); + + for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { + ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, +@@ -2378,7 +2379,8 @@ static int ocfs2_iterate_xattr_buckets(s + if (i == 0) + num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); + +- mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno, ++ mlog(0, "iterating xattr bucket %llu, first hash %u\n", ++ (unsigned long long)blkno, + le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash)); + if (func) { + ret = func(inode, &bucket, para); +@@ -2714,7 +2716,8 @@ static int ocfs2_xattr_create_index_bloc + */ + blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off); + +- mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno); ++ mlog(0, "allocate 1 cluster from %llu to xattr block\n", ++ (unsigned long long)blkno); + + xh_bh = sb_getblk(inode->i_sb, blkno); + if (!xh_bh) { +@@ -2883,8 +2886,8 @@ static int ocfs2_defrag_xattr_bucket(str + + mlog(0, "adjust xattr bucket in %llu, count = %u, " + "xh_free_start = %u, xh_name_value_len = %u.\n", +- blkno, le16_to_cpu(xh->xh_count), xh_free_start, +- le16_to_cpu(xh->xh_name_value_len)); ++ (unsigned long long)blkno, le16_to_cpu(xh->xh_count), ++ xh_free_start, le16_to_cpu(xh->xh_name_value_len)); + + /* + * sort all the entries by their offset. +@@ -3000,7 +3003,7 @@ static int ocfs2_mv_xattr_bucket_cross_c + prev_blkno += (num_clusters - 1) * bpc + bpc / 2; + + mlog(0, "move half of xattrs in cluster %llu to %llu\n", +- prev_blkno, new_blkno); ++ (unsigned long long)prev_blkno, (unsigned long long)new_blkno); + + /* + * We need to update the 1st half of the new cluster and +@@ -3177,7 +3180,7 @@ static int ocfs2_divide_xattr_bucket(str + int blocksize = inode->i_sb->s_blocksize; + + mlog(0, "move some of xattrs from bucket %llu to %llu\n", +- blk, new_blk); ++ (unsigned long long)blk, (unsigned long long)new_blk); + + s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); + if (!s_bhs) +@@ -3376,7 +3379,8 @@ static int ocfs2_cp_xattr_bucket(struct + BUG_ON(s_blkno == t_blkno); + + mlog(0, "cp bucket %llu to %llu, target is %d\n", +- s_blkno, t_blkno, t_is_new); ++ (unsigned long long)s_blkno, (unsigned long long)t_blkno, ++ t_is_new); + + s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, + GFP_NOFS); +@@ -3448,7 +3452,8 @@ static int ocfs2_cp_xattr_cluster(struct + struct ocfs2_xattr_header *xh; + u64 to_blk_start = to_blk; + +- mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk); ++ mlog(0, "cp xattrs from cluster %llu to %llu\n", ++ (unsigned long long)src_blk, (unsigned long long)to_blk); + + /* + * We need to update the new cluster and 1 more for the update of +@@ -3579,7 +3584,8 @@ static int ocfs2_adjust_xattr_cross_clus + int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); + + mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n", +- prev_blk, prev_clusters, new_blk); ++ (unsigned long long)prev_blk, prev_clusters, ++ (unsigned long long)new_blk); + + if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1) + ret = ocfs2_mv_xattr_bucket_cross_cluster(inode, +@@ -3649,7 +3655,7 @@ static int ocfs2_add_new_xattr_cluster(s + mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, " + "previous xattr blkno = %llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno, +- prev_cpos, prev_blkno); ++ prev_cpos, (unsigned long long)prev_blkno); + + ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); + +@@ -3736,7 +3742,7 @@ static int ocfs2_add_new_xattr_cluster(s + } + } + mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", +- num_bits, block, v_start); ++ num_bits, (unsigned long long)block, v_start); + ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, + num_bits, 0, meta_ac); + if (ret < 0) { +@@ -3781,7 +3787,7 @@ static int ocfs2_extend_xattr_bucket(str + u16 bucket = le16_to_cpu(first_xh->xh_num_buckets); + + mlog(0, "extend xattr bucket in %llu, xattr extend rec starting " +- "from %llu, len = %u\n", start_blk, ++ "from %llu, len = %u\n", (unsigned long long)start_blk, + (unsigned long long)first_bh->b_blocknr, num_clusters); + + BUG_ON(bucket >= num_buckets); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-regression-in-ocfs2_read_blocks_sync.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-regression-in-ocfs2_read_blocks_sync.patch new file mode 100644 index 000000000..cd1f084bc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-regression-in-ocfs2_read_blocks_sync.patch @@ -0,0 +1,57 @@ +From: Mark Fasheh +Date: Fri, 21 Nov 2008 14:06:55 -0800 +Subject: ocfs2: fix regression in ocfs2_read_blocks_sync() + +We're panicing in ocfs2_read_blocks_sync() if a jbd-managed buffer is seen. +At first glance, this seems ok but in reality it can happen. My test case +was to just run 'exorcist'. A struct inode is being pushed out of memory but +is then re-read at a later time, before the buffer has been checkpointed by +jbd. This causes a BUG to be hit in ocfs2_read_blocks_sync(). + +Reviewed-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/buffer_head_io.c | 15 ++++----------- + 1 files changed, 4 insertions(+), 11 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/buffer_head_io.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/buffer_head_io.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/buffer_head_io.c +@@ -112,7 +112,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_ + bh = bhs[i]; + + if (buffer_jbd(bh)) { +- mlog(ML_ERROR, ++ mlog(ML_BH_IO, + "trying to sync read a jbd " + "managed bh (blocknr = %llu), skipping\n", + (unsigned long long)bh->b_blocknr); +@@ -147,15 +147,10 @@ int ocfs2_read_blocks_sync(struct ocfs2_ + for (i = nr; i > 0; i--) { + bh = bhs[i - 1]; + +- if (buffer_jbd(bh)) { +- mlog(ML_ERROR, +- "the journal got the buffer while it was " +- "locked for io! (blocknr = %llu)\n", +- (unsigned long long)bh->b_blocknr); +- BUG(); +- } ++ /* No need to wait on the buffer if it's managed by JBD. */ ++ if (!buffer_jbd(bh)) ++ wait_on_buffer(bh); + +- wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + /* Status won't be cleared from here on out, + * so we can safely record this and loop back +@@ -251,8 +246,6 @@ int ocfs2_read_blocks(struct inode *inod + ignore_cache = 1; + } + +- /* XXX: Can we ever get this and *not* have the cached +- * flag set? */ + if (buffer_jbd(bh)) { + if (ignore_cache) + mlog(ML_BH_IO, "trying to sync read a jbd " diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-return-value-set-in-init_dlmfs_fs.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-return-value-set-in-init_dlmfs_fs.patch new file mode 100644 index 000000000..4a61462d3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-return-value-set-in-init_dlmfs_fs.patch @@ -0,0 +1,30 @@ +From: Coly Li +Date: Mon, 17 Nov 2008 12:38:22 +0800 +Subject: ocfs2: fix return value set in init_dlmfs_fs() + +In init_dlmfs_fs(), if calling kmem_cache_create() failed, the code will use return value from +calling bdi_init(). The correct behavior should be set status as -ENOMEM before going to "bail:". + +Signed-off-by: Coly Li +Acked-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlm/dlmfs.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/dlm/dlmfs.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlm/dlmfs.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/dlm/dlmfs.c +@@ -608,8 +608,10 @@ static int __init init_dlmfs_fs(void) + 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + dlmfs_init_once); +- if (!dlmfs_inode_cache) ++ if (!dlmfs_inode_cache) { ++ status = -ENOMEM; + goto bail; ++ } + cleanup_inode = 1; + + user_dlm_worker = create_singlethread_workqueue("user_dlm"); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-wake_up-in-unlock_ast.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-wake_up-in-unlock_ast.patch new file mode 100644 index 000000000..8894e9940 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-fix-wake_up-in-unlock_ast.patch @@ -0,0 +1,29 @@ +From: David Teigland +Date: Mon, 17 Nov 2008 12:28:48 -0600 +Subject: ocfs2: fix wake_up in unlock_ast + +In ocfs2_unlock_ast(), call wake_up() on lockres before releasing +the spin lock on it. As soon as the spin lock is released, the +lockres can be freed. + +Signed-off-by: David Teigland +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlmglue.c | 3 +-- + 1 files changed, 1 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlmglue.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.c +@@ -2841,9 +2841,8 @@ static void ocfs2_unlock_ast(void *opaqu + + lockres_clear_flags(lockres, OCFS2_LOCK_BUSY); + lockres->l_unlock_action = OCFS2_UNLOCK_INVALID; +- spin_unlock_irqrestore(&lockres->l_lock, flags); +- + wake_up(&lockres->l_event); ++ spin_unlock_irqrestore(&lockres->l_lock, flags); + + mlog_exit_void(); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-count-before-generic_write_checks b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-count-before-generic_write_checks new file mode 100644 index 000000000..6fcd8eb5e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-count-before-generic_write_checks @@ -0,0 +1,28 @@ +From: Goldwyn Rodrigues +Subject: Initialize count in aio_write before generic_write_checks +References: bnc#517098 + +generic_write_checks() expects count to be initialized to the size of +the write. +Writes to files open with O_DIRECT|O_LARGEFILE write 0 bytes because +"count" is uninitialized. + +Signed-off-by: Goldwyn Rodrigues +Signed-off-by: Sunil Mushran + +--- + fs/ocfs2/file.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/file.c 2009-07-20 19:18:59.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/file.c 2009-07-20 19:23:21.000000000 +0200 +@@ -1855,6 +1855,7 @@ relock: + if (ret) + goto out_dio; + ++ count = ocount; + ret = generic_write_checks(file, ppos, &count, + S_ISBLK(inode->i_mode)); + if (ret) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-stack_user-lvbptr.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-stack_user-lvbptr.patch new file mode 100644 index 000000000..a70acbfc9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-stack_user-lvbptr.patch @@ -0,0 +1,28 @@ +From: David Teigland +Date: Mon, 10 Nov 2008 16:24:57 -0600 +Subject: ocfs2: initialize stack_user lvbptr + +The locking_state dump, ocfs2_dlm_seq_show, reads the lvb on locks where it +has not yet been initialized by a lock call. + +Signed-off-by: David Teigland +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/stack_user.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/stack_user.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/stack_user.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/stack_user.c +@@ -740,6 +740,9 @@ static int user_dlm_lock_status(union oc + + static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) + { ++ if (!lksb->lksb_fsdlm.sb_lvbptr) ++ lksb->lksb_fsdlm.sb_lvbptr = (char *)lksb + ++ sizeof(struct dlm_lksb); + return (void *)(lksb->lksb_fsdlm.sb_lvbptr); + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-the-cluster-we-re-writing-to.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-the-cluster-we-re-writing-to.patch new file mode 100644 index 000000000..4046ce62a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-initialize-the-cluster-we-re-writing-to.patch @@ -0,0 +1,193 @@ +From e7432675f8ca868a4af365759a8d4c3779a3d922 Mon Sep 17 00:00:00 2001 +From: Sunil Mushran +Date: Thu, 6 Aug 2009 16:12:58 -0700 +Subject: ocfs2: Initialize the cluster we're writing to in a non-sparse extend +References: bnc#501563 + +In a non-sparse extend, we correctly allocate (and zero) the clusters between +the old_i_size and pos, but we don't zero the portions of the cluster we're +writing to outside of pos<->len. + +It handles clustersize > pagesize and blocksize < pagesize. + +[Cleaned up by Joel Becker.] + +Signed-off-by: Sunil Mushran +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/aops.c | 66 +++++++++++++++++++++++++++++++++++++++--------------- + 1 files changed, 47 insertions(+), 19 deletions(-) + +Index: linux-2.6.27-ocfs2-update-sle11/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27-ocfs2-update-sle11.orig/fs/ocfs2/aops.c ++++ linux-2.6.27-ocfs2-update-sle11/fs/ocfs2/aops.c +@@ -909,18 +909,17 @@ struct ocfs2_write_cluster_desc { + */ + unsigned c_new; + unsigned c_unwritten; ++ unsigned c_needs_zero; + }; + +-static inline int ocfs2_should_zero_cluster(struct ocfs2_write_cluster_desc *d) +-{ +- return d->c_new || d->c_unwritten; +-} +- + struct ocfs2_write_ctxt { + /* Logical cluster position / len of write */ + u32 w_cpos; + u32 w_clen; + ++ /* First cluster allocated in a nonsparse extend */ ++ u32 w_first_new_cpos; ++ + struct ocfs2_write_cluster_desc w_desc[OCFS2_MAX_CLUSTERS_PER_PAGE]; + + /* +@@ -998,6 +997,7 @@ static int ocfs2_alloc_write_ctxt(struct + return -ENOMEM; + + wc->w_cpos = pos >> osb->s_clustersize_bits; ++ wc->w_first_new_cpos = UINT_MAX; + cend = (pos + len - 1) >> osb->s_clustersize_bits; + wc->w_clen = cend - wc->w_cpos + 1; + get_bh(di_bh); +@@ -1239,20 +1239,18 @@ out: + */ + static int ocfs2_write_cluster(struct address_space *mapping, + u32 phys, unsigned int unwritten, ++ unsigned int should_zero, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_write_ctxt *wc, u32 cpos, + loff_t user_pos, unsigned user_len) + { +- int ret, i, new, should_zero = 0; ++ int ret, i, new; + u64 v_blkno, p_blkno; + struct inode *inode = mapping->host; + struct ocfs2_extent_tree et; + + new = phys == 0 ? 1 : 0; +- if (new || unwritten) +- should_zero = 1; +- + if (new) { + u32 tmp_pos; + +@@ -1363,7 +1361,9 @@ static int ocfs2_write_cluster_by_desc(s + local_len = osb->s_clustersize - cluster_off; + + ret = ocfs2_write_cluster(mapping, desc->c_phys, +- desc->c_unwritten, data_ac, meta_ac, ++ desc->c_unwritten, ++ desc->c_needs_zero, ++ data_ac, meta_ac, + wc, desc->c_cpos, pos, local_len); + if (ret) { + mlog_errno(ret); +@@ -1413,14 +1413,14 @@ static void ocfs2_set_target_boundaries( + * newly allocated cluster. + */ + desc = &wc->w_desc[0]; +- if (ocfs2_should_zero_cluster(desc)) ++ if (desc->c_needs_zero) + ocfs2_figure_cluster_boundaries(osb, + desc->c_cpos, + &wc->w_target_from, + NULL); + + desc = &wc->w_desc[wc->w_clen - 1]; +- if (ocfs2_should_zero_cluster(desc)) ++ if (desc->c_needs_zero) + ocfs2_figure_cluster_boundaries(osb, + desc->c_cpos, + NULL, +@@ -1488,13 +1488,28 @@ static int ocfs2_populate_write_desc(str + phys++; + } + ++ /* ++ * If w_first_new_cpos is < UINT_MAX, we have a non-sparse ++ * file that got extended. w_first_new_cpos tells us ++ * where the newly allocated clusters are so we can ++ * zero them. ++ */ ++ if (desc->c_cpos >= wc->w_first_new_cpos) { ++ BUG_ON(phys == 0); ++ desc->c_needs_zero = 1; ++ } ++ + desc->c_phys = phys; + if (phys == 0) { + desc->c_new = 1; ++ desc->c_needs_zero = 1; + *clusters_to_alloc = *clusters_to_alloc + 1; + } +- if (ext_flags & OCFS2_EXT_UNWRITTEN) ++ ++ if (ext_flags & OCFS2_EXT_UNWRITTEN) { + desc->c_unwritten = 1; ++ desc->c_needs_zero = 1; ++ } + + num_clusters--; + } +@@ -1654,10 +1669,13 @@ static int ocfs2_expand_nonsparse_inode( + if (newsize <= i_size_read(inode)) + return 0; + +- ret = ocfs2_extend_no_holes(inode, newsize, newsize - len); ++ ret = ocfs2_extend_no_holes(inode, newsize, pos); + if (ret) + mlog_errno(ret); + ++ wc->w_first_new_cpos = ++ ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode)); ++ + return ret; + } + +@@ -1666,7 +1684,7 @@ int ocfs2_write_begin_nolock(struct addr + struct page **pagep, void **fsdata, + struct buffer_head *di_bh, struct page *mmap_page) + { +- int ret, credits = OCFS2_INODE_UPDATE_CREDITS; ++ int ret, cluster_of_pages, credits = OCFS2_INODE_UPDATE_CREDITS; + unsigned int clusters_to_alloc, extents_to_split; + struct ocfs2_write_ctxt *wc; + struct inode *inode = mapping->host; +@@ -1744,8 +1762,19 @@ int ocfs2_write_begin_nolock(struct addr + + } + +- ocfs2_set_target_boundaries(osb, wc, pos, len, +- clusters_to_alloc + extents_to_split); ++ /* ++ * We have to zero sparse allocated clusters, unwritten extent clusters, ++ * and non-sparse clusters we just extended. For non-sparse writes, ++ * we know zeros will only be needed in the first and/or last cluster. ++ */ ++ if (clusters_to_alloc || extents_to_split || ++ wc->w_desc[0].c_needs_zero || ++ wc->w_desc[wc->w_clen - 1].c_needs_zero) ++ cluster_of_pages = 1; ++ else ++ cluster_of_pages = 0; ++ ++ ocfs2_set_target_boundaries(osb, wc, pos, len, cluster_of_pages); + + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { +@@ -1778,8 +1807,7 @@ int ocfs2_write_begin_nolock(struct addr + * extent. + */ + ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos, +- clusters_to_alloc + extents_to_split, +- mmap_page); ++ cluster_of_pages, mmap_page); + if (ret) { + mlog_errno(ret); + goto out_quota; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-more_start_tran_fixes.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-more_start_tran_fixes.patch new file mode 100644 index 000000000..2355b227f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-more_start_tran_fixes.patch @@ -0,0 +1,39 @@ +From: Tao Ma +Date: Fri, 24 Oct 2008 07:57:28 +0800 +Subject: ocfs2: Fix check of return value of ocfs2_start_trans() in xattr.c. + +On failure, ocfs2_start_trans() returns values like ERR_PTR(-ENOMEM), +so we should check whether handle is NULL. Fix them to use IS_ERR(). +Jan has made the patch for other part in ocfs2(thank Jan for it), so +this is just the fix for fs/ocfs2/xattr.c. + +Signed-off-by: Tao Ma +Cc: Jan Kara +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -4092,7 +4092,7 @@ static int ocfs2_xattr_value_update_size + handle_t *handle = NULL; + + handle = ocfs2_start_trans(osb, 1); +- if (handle == NULL) { ++ if (IS_ERR(handle)) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; +@@ -4259,7 +4259,7 @@ static int ocfs2_rm_xattr_cluster(struct + } + + handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); +- if (handle == NULL) { ++ if (IS_ERR(handle)) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-push-out-dropping-of-dentry-lock-to-ocfs2_wq.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-push-out-dropping-of-dentry-lock-to-ocfs2_wq.patch new file mode 100644 index 000000000..2406d029a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-push-out-dropping-of-dentry-lock-to-ocfs2_wq.patch @@ -0,0 +1,151 @@ +From: Jan Kara +Date: Mon, 12 Jan 2009 23:20:31 +0100 +Subject: [PATCH] ocfs2: Push out dropping of dentry lock to ocfs2_wq +Patch-mainline: 2.6.29 + +Dropping of last reference to dentry lock is a complicated operation involving +dropping of reference to inode. This can get complicated and quota code in +particular needs to obtain some quota locks which leads to potential deadlock. +Thus we defer dropping of inode reference to ocfs2_wq. + +Signed-off-by: Jan Kara +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dcache.c | 42 +++++++++++++++++++++++++++++++++++++++--- + fs/ocfs2/dcache.h | 9 ++++++++- + fs/ocfs2/ocfs2.h | 6 ++++++ + fs/ocfs2/super.c | 3 +++ + 4 files changed, 56 insertions(+), 4 deletions(-) + +--- a/fs/ocfs2/dcache.c ++++ b/fs/ocfs2/dcache.c +@@ -38,6 +38,7 @@ + #include "dlmglue.h" + #include "file.h" + #include "inode.h" ++#include "super.h" + + + static int ocfs2_dentry_revalidate(struct dentry *dentry, +@@ -294,6 +295,34 @@ out_attach: + return ret; + } + ++static DEFINE_SPINLOCK(dentry_list_lock); ++ ++/* We limit the number of dentry locks to drop in one go. We have ++ * this limit so that we don't starve other users of ocfs2_wq. */ ++#define DL_INODE_DROP_COUNT 64 ++ ++/* Drop inode references from dentry locks */ ++void ocfs2_drop_dl_inodes(struct work_struct *work) ++{ ++ struct ocfs2_super *osb = container_of(work, struct ocfs2_super, ++ dentry_lock_work); ++ struct ocfs2_dentry_lock *dl; ++ int drop_count = DL_INODE_DROP_COUNT; ++ ++ spin_lock(&dentry_list_lock); ++ while (osb->dentry_lock_list && drop_count--) { ++ dl = osb->dentry_lock_list; ++ osb->dentry_lock_list = dl->dl_next; ++ spin_unlock(&dentry_list_lock); ++ iput(dl->dl_inode); ++ kfree(dl); ++ spin_lock(&dentry_list_lock); ++ } ++ if (osb->dentry_lock_list) ++ queue_work(ocfs2_wq, &osb->dentry_lock_work); ++ spin_unlock(&dentry_list_lock); ++} ++ + /* + * ocfs2_dentry_iput() and friends. + * +@@ -318,16 +347,23 @@ out_attach: + static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb, + struct ocfs2_dentry_lock *dl) + { +- iput(dl->dl_inode); + ocfs2_simple_drop_lockres(osb, &dl->dl_lockres); + ocfs2_lock_res_free(&dl->dl_lockres); +- kfree(dl); ++ ++ /* We leave dropping of inode reference to ocfs2_wq as that can ++ * possibly lead to inode deletion which gets tricky */ ++ spin_lock(&dentry_list_lock); ++ if (!osb->dentry_lock_list) ++ queue_work(ocfs2_wq, &osb->dentry_lock_work); ++ dl->dl_next = osb->dentry_lock_list; ++ osb->dentry_lock_list = dl; ++ spin_unlock(&dentry_list_lock); + } + + void ocfs2_dentry_lock_put(struct ocfs2_super *osb, + struct ocfs2_dentry_lock *dl) + { +- int unlock = 0; ++ int unlock; + + BUG_ON(dl->dl_count == 0); + +--- a/fs/ocfs2/dcache.h ++++ b/fs/ocfs2/dcache.h +@@ -29,8 +29,13 @@ + extern struct dentry_operations ocfs2_dentry_ops; + + struct ocfs2_dentry_lock { ++ /* Use count of dentry lock */ + unsigned int dl_count; +- u64 dl_parent_blkno; ++ union { ++ /* Linked list of dentry locks to release */ ++ struct ocfs2_dentry_lock *dl_next; ++ u64 dl_parent_blkno; ++ }; + + /* + * The ocfs2_dentry_lock keeps an inode reference until +@@ -47,6 +52,8 @@ int ocfs2_dentry_attach_lock(struct dent + void ocfs2_dentry_lock_put(struct ocfs2_super *osb, + struct ocfs2_dentry_lock *dl); + ++void ocfs2_drop_dl_inodes(struct work_struct *work); ++ + struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno, + int skip_unhashed); + +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -210,6 +210,7 @@ struct ocfs2_journal; + struct ocfs2_slot_info; + struct ocfs2_recovery_map; + struct ocfs2_quota_recovery; ++struct ocfs2_dentry_lock; + struct ocfs2_super + { + struct task_struct *commit_task; +@@ -325,6 +326,11 @@ struct ocfs2_super + struct list_head blocked_lock_list; + unsigned long blocked_lock_count; + ++ /* List of dentry locks to release. Anyone can add locks to ++ * the list, ocfs2_wq processes the list */ ++ struct ocfs2_dentry_lock *dentry_lock_list; ++ struct work_struct dentry_lock_work; ++ + wait_queue_head_t osb_mount_event; + + /* Truncate log info */ +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -1888,6 +1888,9 @@ static int ocfs2_initialize_super(struct + INIT_WORK(&journal->j_recovery_work, ocfs2_complete_recovery); + journal->j_state = OCFS2_JOURNAL_FREE; + ++ INIT_WORK(&osb->dentry_lock_work, ocfs2_drop_dl_inodes); ++ osb->dentry_lock_list = NULL; ++ + /* get some pseudo constants for clustersize bits */ + osb->s_clustersize_bits = + le32_to_cpu(di->id2.i_super.s_clustersize_bits); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Initialize-blocks-allocated-to-local-quota-fi.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Initialize-blocks-allocated-to-local-quota-fi.patch new file mode 100644 index 000000000..645fb3b39 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Initialize-blocks-allocated-to-local-quota-fi.patch @@ -0,0 +1,149 @@ +From ac60e745d0187b11d9e7f9fcb37e64cc7c02ded0 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 17 Jun 2009 19:09:19 +0200 +Subject: [PATCH 3/6] ocfs2: Initialize blocks allocated to local quota file + +When we extend local quota file, we should initialize data +in newly allocated block. Firstly because on recovery we could +parse bogus data, secondly so that block checksums are properly +computed. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota_local.c | 98 ++++++++++++++++++++++++++++++++++++++++------- + 1 files changed, 83 insertions(+), 15 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_local.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/quota_local.c 2009-07-16 13:26:06.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_local.c 2009-07-16 14:00:23.000000000 +0200 +@@ -930,7 +930,7 @@ + struct ocfs2_local_disk_chunk *dchunk; + int status; + handle_t *handle; +- struct buffer_head *bh = NULL; ++ struct buffer_head *bh = NULL, *dbh = NULL; + u64 p_blkno; + + /* We are protected by dqio_sem so no locking needed */ +@@ -973,7 +973,7 @@ + + dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data; + +- handle = ocfs2_start_trans(OCFS2_SB(sb), 2); ++ handle = ocfs2_start_trans(OCFS2_SB(sb), 3); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); +@@ -998,6 +998,38 @@ + goto out_trans; + } + ++ /* Initialize new block with structures */ ++ down_read(&OCFS2_I(lqinode)->ip_alloc_sem); ++ status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks + 1, ++ &p_blkno, NULL, NULL); ++ up_read(&OCFS2_I(lqinode)->ip_alloc_sem); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ dbh = sb_getblk(sb, p_blkno); ++ if (!dbh) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto out_trans; ++ } ++ ocfs2_set_new_buffer_uptodate(lqinode, dbh); ++ status = ocfs2_journal_access(handle, lqinode, dbh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ lock_buffer(dbh); ++ memset(dbh->b_data, 0, sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE); ++ unlock_buffer(dbh); ++ status = ocfs2_journal_dirty(handle, dbh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ ++ /* Update local quotafile info */ + oinfo->dqi_blocks += 2; + oinfo->dqi_chunks++; + status = ocfs2_local_write_info(sb, type); +@@ -1022,6 +1054,7 @@ + ocfs2_commit_trans(OCFS2_SB(sb), handle); + out: + brelse(bh); ++ brelse(dbh); + kmem_cache_free(ocfs2_qf_chunk_cachep, chunk); + return ERR_PTR(status); + } +@@ -1039,6 +1072,8 @@ + struct ocfs2_local_disk_chunk *dchunk; + int epb = ol_quota_entries_per_block(sb); + unsigned int chunk_blocks; ++ struct buffer_head *bh; ++ u64 p_blkno; + int status; + handle_t *handle; + +@@ -1066,12 +1101,46 @@ + mlog_errno(status); + goto out; + } +- handle = ocfs2_start_trans(OCFS2_SB(sb), 2); ++ ++ /* Get buffer from the just added block */ ++ down_read(&OCFS2_I(lqinode)->ip_alloc_sem); ++ status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks, ++ &p_blkno, NULL, NULL); ++ up_read(&OCFS2_I(lqinode)->ip_alloc_sem); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ bh = sb_getblk(sb, p_blkno); ++ if (!bh) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto out; ++ } ++ ocfs2_set_new_buffer_uptodate(lqinode, bh); ++ ++ handle = ocfs2_start_trans(OCFS2_SB(sb), 3); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); + goto out; + } ++ /* Zero created block */ ++ status = ocfs2_journal_access(handle, lqinode, bh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ lock_buffer(bh); ++ memset(bh->b_data, 0, sb->s_blocksize); ++ unlock_buffer(bh); ++ status = ocfs2_journal_dirty(handle, bh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ /* Update chunk header */ + status = ocfs2_journal_access(handle, lqinode, chunk->qc_headerbh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { +@@ -1088,6 +1157,7 @@ + mlog_errno(status); + goto out_trans; + } ++ /* Update file header */ + oinfo->dqi_blocks++; + status = ocfs2_local_write_info(sb, type); + if (status < 0) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Make-global-quota-files-blocksize-aligned.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Make-global-quota-files-blocksize-aligned.patch new file mode 100644 index 000000000..f2f75631d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Make-global-quota-files-blocksize-aligned.patch @@ -0,0 +1,38 @@ +From 96e8cc43fbecaee5a2b9eee4ec27a765474e7671 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 17 Jun 2009 17:35:07 +0200 +Subject: [PATCH 1/6] ocfs2: Make global quota files blocksize aligned + +Change i_size of global quota files so that it always remains aligned to block +size. This is mainly because the end of quota block may contain checksum (if +checksumming is enabled) and it's a bit awkward for it to be "outside" of quota +file (and it makes life harder for ocfs2-tools). + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota_global.c | 6 ++++-- + 1 files changed, 4 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_global.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/quota_global.c 2009-07-16 13:21:13.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_global.c 2009-07-16 13:25:41.000000000 +0200 +@@ -145,14 +145,16 @@ + } + mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA); + if (gqinode->i_size < off + len) { ++ loff_t rounded_end = ALIGN(off + len, sb->s_blocksize); ++ + down_write(&OCFS2_I(gqinode)->ip_alloc_sem); +- err = ocfs2_extend_no_holes(gqinode, off + len, off); ++ err = ocfs2_extend_no_holes(gqinode, rounded_end, off); + up_write(&OCFS2_I(gqinode)->ip_alloc_sem); + if (err < 0) + goto out; + err = ocfs2_simple_size_update(gqinode, + oinfo->dqi_gqi_bh, +- off + len); ++ rounded_end); + if (err < 0) + goto out; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Mark-buffer-uptodate-before-calling-ocfs2_jou.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Mark-buffer-uptodate-before-calling-ocfs2_jou.patch new file mode 100644 index 000000000..e39726e30 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Mark-buffer-uptodate-before-calling-ocfs2_jou.patch @@ -0,0 +1,42 @@ +From 20ee86b5d0f26117b102012fd33eb05048f0a583 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 17 Jun 2009 19:04:54 +0200 +Subject: [PATCH 2/6] ocfs2: Mark buffer uptodate before calling ocfs2_journal_access() + +In a code path extending local quota files we marked new header +buffer uptodate only after calling ocfs2_journal_access() which +triggers a bug. Fix it and also call ocfs2 variant of the function +marking buffer uptodate. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota_local.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -20,6 +20,7 @@ + #include "sysfile.h" + #include "dlmglue.h" + #include "quota.h" ++#include "uptodate.h" + + /* Number of local quota structures per block */ + static inline unsigned int ol_quota_entries_per_block(struct super_block *sb) +@@ -968,6 +969,8 @@ static struct ocfs2_quota_chunk *ocfs2_l + mlog_errno(status); + goto out; + } ++ ocfs2_set_new_buffer_uptodate(lqinode, bh); ++ + dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data; + + handle = ocfs2_start_trans(OCFS2_SB(sb), 2); +@@ -988,7 +991,6 @@ static struct ocfs2_quota_chunk *ocfs2_l + memset(dchunk->dqc_bitmap, 0, + sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) - + OCFS2_QBLK_RESERVED_SPACE); +- set_buffer_uptodate(bh); + unlock_buffer(bh); + status = ocfs2_journal_dirty(handle, bh); + if (status < 0) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Remove-syncjiff-field-from-quota-info.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Remove-syncjiff-field-from-quota-info.patch new file mode 100644 index 000000000..adc0226c7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-quota-Remove-syncjiff-field-from-quota-info.patch @@ -0,0 +1,77 @@ +From fab7b7090ac16e340e35e2bd0a64afe7a7f068ef Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Wed, 15 Jul 2009 13:21:53 +0200 +Subject: [PATCH 6/6] ocfs2: Remove syncjiff field from quota info + +syncjiff is just a converted value of syncms. Some places which +are updating syncms forgot to update syncjiff as well. Since the +conversion is just a simple division / multiplication and it does +not happen frequently, just remove the syncjiff field to avoid +forgotten conversions. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/aops.c | 4 +++- + fs/ocfs2/quota.h | 1 - + fs/ocfs2/quota_global.c | 5 ++--- + 3 files changed, 5 insertions(+), 5 deletions(-) + +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/aops.c 2009-07-16 13:16:26.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/aops.c 2009-07-16 14:03:35.000000000 +0200 +@@ -145,9 +145,11 @@ + mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode, + (unsigned long long)iblock, bh_result, create); + +- if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) ++ if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) { + mlog(ML_NOTICE, "get_block on system inode 0x%p (%lu)\n", + inode, inode->i_ino); ++ dump_stack(); ++ } + + if (S_ISLNK(inode->i_mode)) { + /* this always does I/O for some reason. */ +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/quota.h 2009-07-16 13:16:26.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota.h 2009-07-16 14:03:35.000000000 +0200 +@@ -55,7 +55,6 @@ + unsigned int dqi_chunks; /* Number of chunks in local quota file */ + unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */ + unsigned int dqi_syncms; /* How often should we sync with other nodes */ +- unsigned int dqi_syncjiff; /* Precomputed dqi_syncms in jiffies */ + struct list_head dqi_chunk; /* List of chunks */ + struct inode *dqi_gqinode; /* Global quota file inode */ + struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */ +Index: linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_global.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/ocfs2/quota_global.c 2009-07-16 13:25:41.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/fs/ocfs2/quota_global.c 2009-07-16 14:04:51.000000000 +0200 +@@ -277,7 +277,6 @@ + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); +- oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms); + oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); + oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); + oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); +@@ -288,7 +287,7 @@ + setup_timer(&oinfo->dqi_sync_timer, qsync_timer_fn, + (unsigned long)oinfo); + mod_timer(&oinfo->dqi_sync_timer, +- round_jiffies(jiffies + oinfo->dqi_syncjiff)); ++ round_jiffies(jiffies+msecs_to_jiffies(oinfo->dqi_syncms))); + out_err: + mlog_exit(status); + return status; +@@ -547,7 +546,7 @@ + + pdflush_operation(ocfs2_do_qsync, oinfo_ptr); + mod_timer(&oinfo->dqi_sync_timer, +- round_jiffies(jiffies + oinfo->dqi_syncjiff)); ++ round_jiffies(jiffies+msecs_to_jiffies(oinfo->dqi_syncms))); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-really-add-ACL-Kconfig.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-really-add-ACL-Kconfig.patch new file mode 100644 index 000000000..ae7cd1a17 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-really-add-ACL-Kconfig.patch @@ -0,0 +1,34 @@ +From: Mark Fasheh +Date: Tue May 19 15:58:33 PDT 2009 +Subject: ocfs2: really add ACL Kconfig +Patch-mainline: 2.6.29 +Refrences: bnc#499278 + +The patch patches.suse/ocfs2-add-mount-option-and-Kconfig-option-for-acl.patch +was supposed to add Kconfig and mount options for ocfs2 ACL support. + +Unfortunately, the Kconfig change got left out. This fixes the problem by adding +the appropriate lines to fs/Kconfig. + +Signed-off-by: Mark Fasheh + +Index: linux-2.6.27-SLE11_BRANCH/fs/Kconfig +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/fs/Kconfig ++++ linux-2.6.27-SLE11_BRANCH/fs/Kconfig +@@ -507,6 +507,15 @@ config OCFS2_COMPAT_JBD + is backwards compatible with JBD. It is safe to say N here. + However, if you really want to use the original JBD, say Y here. + ++config OCFS2_FS_POSIX_ACL ++ bool "OCFS2 POSIX Access Control Lists" ++ depends on OCFS2_FS ++ select FS_POSIX_ACL ++ default n ++ help ++ Posix Access Control Lists (ACLs) support permissions for users and ++ groups beyond the owner/group/world scheme. ++ + endif # BLOCK + + config DNOTIFY diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-duplicate-definition-in-xattr.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-duplicate-definition-in-xattr.patch new file mode 100644 index 000000000..8801e0d6a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-duplicate-definition-in-xattr.patch @@ -0,0 +1,54 @@ +From: Tiger Yang +Date: Thu, 23 Oct 2008 16:34:13 +0800 +Subject: ocfs2: remove duplicate definition in xattr + +Include/linux/xattr.h already has the definition about xattr prefix, +so remove the duplicate definitions in xattr.c. + +Signed-off-by: Tiger Yang +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 11 ++--------- + 1 files changed, 2 insertions(+), 9 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -4740,14 +4740,11 @@ out: + /* + * 'trusted' attributes support + */ +- +-#define XATTR_TRUSTED_PREFIX "trusted." +- + static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, + size_t list_size, const char *name, + size_t name_len) + { +- const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1; ++ const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; + const size_t total_len = prefix_len + name_len + 1; + + if (list && total_len <= list_size) { +@@ -4784,18 +4781,14 @@ struct xattr_handler ocfs2_xattr_trusted + .set = ocfs2_xattr_trusted_set, + }; + +- + /* + * 'user' attributes support + */ +- +-#define XATTR_USER_PREFIX "user." +- + static size_t ocfs2_xattr_user_list(struct inode *inode, char *list, + size_t list_size, const char *name, + size_t name_len) + { +- const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1; ++ const size_t prefix_len = XATTR_USER_PREFIX_LEN; + const size_t total_len = prefix_len + name_len + 1; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-prepare_write-commit_write.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-prepare_write-commit_write.patch new file mode 100644 index 000000000..bac98459c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-prepare_write-commit_write.patch @@ -0,0 +1,32 @@ +From: Nick Piggin +Date: Wed, 29 Oct 2008 14:00:55 -0700 +Subject: fs: remove prepare_write/commit_write + +Nothing uses prepare_write or commit_write. Remove them from the tree +completely. + +[akpm@linux-foundation.org: schedule simple_prepare_write() for unexporting] +Signed-off-by: Nick Piggin +Cc: Christoph Hellwig +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Acked-by: Mark Fasheh + +--- + fs/ocfs2/file.c | 3 +-- + 1 files changed, 1 insertions(+), 2 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.c +@@ -679,8 +679,7 @@ leave: + + /* Some parts of this taken from generic_cont_expand, which turned out + * to be too fragile to do exactly what we need without us having to +- * worry about recursive locking in ->prepare_write() and +- * ->commit_write(). */ ++ * worry about recursive locking in ->write_begin() and ->write_end(). */ + static int ocfs2_write_zero_page(struct inode *inode, + u64 size) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-undefined-xattr-handlers.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-undefined-xattr-handlers.patch new file mode 100644 index 000000000..a195e91db --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-remove-undefined-xattr-handlers.patch @@ -0,0 +1,60 @@ +From: Mark Fasheh +Patch-mainline: 2.6.28 +Subject: Remove un-defined acl handlers + +These handlers aren't actually defined yet. Having them around causes more +trouble than it's worth. The ACL support patches will add them in a proper +fashion. + +Signed-off-by: Mark Fasheh + +diff -pruN suse/trees/linux-2.6.27-ocfs2/fs/ocfs2//xattr.c linux-2.6.git/fs/ocfs2//xattr.c +--- suse/trees/linux-2.6.27-ocfs2/fs/ocfs2/xattr.c 2009-02-05 15:46:43.000000000 -0800 ++++ linux-2.6.git/fs/ocfs2/xattr.c 2009-02-05 15:51:33.000000000 -0800 +@@ -79,29 +79,13 @@ static struct ocfs2_xattr_def_value_root + + struct xattr_handler *ocfs2_xattr_handlers[] = { + &ocfs2_xattr_user_handler, +-#ifdef CONFIG_OCFS2_FS_POSIX_ACL +- &ocfs2_xattr_acl_access_handler, +- &ocfs2_xattr_acl_default_handler, +-#endif + &ocfs2_xattr_trusted_handler, +-#ifdef CONFIG_OCFS2_FS_SECURITY +- &ocfs2_xattr_security_handler, +-#endif + NULL + }; + + static struct xattr_handler *ocfs2_xattr_handler_map[] = { + [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, +-#ifdef CONFIG_OCFS2_FS_POSIX_ACL +- [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS] +- = &ocfs2_xattr_acl_access_handler, +- [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT] +- = &ocfs2_xattr_acl_default_handler, +-#endif + [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, +-#ifdef CONFIG_OCFS2_FS_SECURITY +- [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler, +-#endif + }; + + struct ocfs2_xattr_info { +diff -pruN suse/trees/linux-2.6.27-ocfs2/fs/ocfs2//xattr.h linux-2.6.git/fs/ocfs2//xattr.h +--- suse/trees/linux-2.6.27-ocfs2/fs/ocfs2/xattr.h 2009-02-05 15:46:43.000000000 -0800 ++++ linux-2.6.git/fs/ocfs2/xattr.h 2009-02-05 15:51:33.000000000 -0800 +@@ -40,13 +40,6 @@ enum ocfs2_xattr_type { + + extern struct xattr_handler ocfs2_xattr_user_handler; + extern struct xattr_handler ocfs2_xattr_trusted_handler; +-#ifdef CONFIG_OCFS2_FS_POSIX_ACL +-extern struct xattr_handler ocfs2_xattr_acl_access_handler; +-extern struct xattr_handler ocfs2_xattr_acl_default_handler; +-#endif +-#ifdef CONFIG_OCFS2_FS_SECURITY +-extern struct xattr_handler ocfs2_xattr_security_handler; +-#endif + + extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); + extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-reserve-xattr-block-for-new-directory-with-in.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-reserve-xattr-block-for-new-directory-with-in.patch new file mode 100644 index 000000000..baa8a1fa9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-reserve-xattr-block-for-new-directory-with-in.patch @@ -0,0 +1,33 @@ +From: Tiger Yang +Date: Fri, 6 Mar 2009 10:19:30 +0800 +Subject: [PATCH] ocfs2: reserve xattr block for new directory with inline data +Patch-mainline: 2.6.29 + +If this is a new directory with inline data, we choose to +reserve the entire inline area for directory contents and +force an external xattr block. + +Signed-off-by: Tiger Yang +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/xattr.c +@@ -450,8 +450,12 @@ int ocfs2_calc_xattr_init(struct inode * + * when blocksize = 512, may reserve one more cluser for + * xattr bucket, otherwise reserve one metadata block + * for them is ok. ++ * If this is a new directory with inline data, ++ * we choose to reserve the entire inline area for ++ * directory contents and force an external xattr block. + */ + if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE || ++ (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) || + (s_size + a_size) > OCFS2_XATTR_FREE_IN_IBODY) { + ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac); + if (ret) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-return-0-in-page_mkwrite-to-let-VFS-retry.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-return-0-in-page_mkwrite-to-let-VFS-retry.patch new file mode 100644 index 000000000..6e0b1cef8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-return-0-in-page_mkwrite-to-let-VFS-retry.patch @@ -0,0 +1,34 @@ +From: Tao Ma +Date: Mon, 6 Oct 2008 16:59:55 +0800 +Subject: ocfs2: return 0 in page_mkwrite to let VFS retry. + +In ocfs2_page_mkwrite, we return -EINVAL when we found the page mapping +isn't updated, and it will cause the user space program get SIGBUS and +exit. The reason is that during race writeable mmap, we will do +unmap_mapping_range in ocfs2_data_downconvert_worker. The good thing is +that if we reuturn 0 in page_mkwrite, VFS will retry fault and then +call page_mkwrite again, so it is safe to return 0 here. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/mmap.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/mmap.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/mmap.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/mmap.c +@@ -113,7 +113,11 @@ static int __ocfs2_page_mkwrite(struct i + * ocfs2_write_begin_nolock(). + */ + if (!PageUptodate(page) || page->mapping != inode->i_mapping) { +- ret = -EINVAL; ++ /* ++ * the page has been umapped in ocfs2_data_downconvert_worker. ++ * So return 0 here and let VFS retry. ++ */ ++ ret = 0; + goto out; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-set-gap-to-seperate-entry-and-value-when-xatt.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-set-gap-to-seperate-entry-and-value-when-xatt.patch new file mode 100644 index 000000000..a1ed935c5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-set-gap-to-seperate-entry-and-value-when-xatt.patch @@ -0,0 +1,85 @@ +From: Tiger Yang +Date: Fri, 20 Feb 2009 11:11:50 +0800 +Subject: [PATCH] ocfs2: set gap to seperate entry and value when xattr in bucket +Patch-mainline: 2.6.29 + +This patch set a gap (4 bytes) between xattr entry and +name/value when xattr in bucket. This gap use to seperate +entry and name/value when a bucket is full. It had already +been set when xattr in inode/block. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 18 ++++++++++-------- + 1 files changed, 10 insertions(+), 8 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/xattr.c +@@ -81,13 +81,14 @@ struct ocfs2_xattr_set_ctxt { + + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) + #define OCFS2_XATTR_INLINE_SIZE 80 ++#define OCFS2_XATTR_HEADER_GAP 4 + #define OCFS2_XATTR_FREE_IN_IBODY (OCFS2_MIN_XATTR_INLINE_SIZE \ + - sizeof(struct ocfs2_xattr_header) \ +- - sizeof(__u32)) ++ - OCFS2_XATTR_HEADER_GAP) + #define OCFS2_XATTR_FREE_IN_BLOCK(ptr) ((ptr)->i_sb->s_blocksize \ + - sizeof(struct ocfs2_xattr_block) \ + - sizeof(struct ocfs2_xattr_header) \ +- - sizeof(__u32)) ++ - OCFS2_XATTR_HEADER_GAP) + + static struct ocfs2_xattr_def_value_root def_xv = { + .xv.xr_list.l_count = cpu_to_le16(1), +@@ -1411,7 +1412,7 @@ static int ocfs2_xattr_set_entry(struct + last += 1; + } + +- free = min_offs - ((void *)last - xs->base) - sizeof(__u32); ++ free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP; + if (free < 0) + return -EIO; + +@@ -2101,7 +2102,7 @@ static int ocfs2_xattr_can_be_in_inode(s + last += 1; + } + +- free = min_offs - ((void *)last - xs->base) - sizeof(__u32); ++ free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP; + if (free < 0) + return 0; + +@@ -4919,8 +4920,8 @@ try_again: + xh_free_start = le16_to_cpu(xh->xh_free_start); + header_size = sizeof(struct ocfs2_xattr_header) + + count * sizeof(struct ocfs2_xattr_entry); +- max_free = OCFS2_XATTR_BUCKET_SIZE - +- le16_to_cpu(xh->xh_name_value_len) - header_size; ++ max_free = OCFS2_XATTR_BUCKET_SIZE - header_size - ++ le16_to_cpu(xh->xh_name_value_len) - OCFS2_XATTR_HEADER_GAP; + + mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " + "of %u which exceed block size\n", +@@ -4953,7 +4954,7 @@ try_again: + need = 0; + } + +- free = xh_free_start - header_size; ++ free = xh_free_start - header_size - OCFS2_XATTR_HEADER_GAP; + /* + * We need to make sure the new name/value pair + * can exist in the same block. +@@ -4986,7 +4987,8 @@ try_again: + } + + xh_free_start = le16_to_cpu(xh->xh_free_start); +- free = xh_free_start - header_size; ++ free = xh_free_start - header_size ++ - OCFS2_XATTR_HEADER_GAP; + if (xh_free_start % blocksize < need) + free -= xh_free_start % blocksize; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-truncate-outstanding-block-after-direct-io-fa.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-truncate-outstanding-block-after-direct-io-fa.patch new file mode 100644 index 000000000..cd031d9ac --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-truncate-outstanding-block-after-direct-io-fa.patch @@ -0,0 +1,33 @@ +From: Dmitri Monakhov +Date: Mon, 27 Oct 2008 13:01:49 -0700 +Subject: ocfs2: truncate outstanding block after direct io failure + +Signed-off-by: Dmitri Monakhov +Cc: Jeff Moyer +Cc: Mark Fasheh +Cc: Joel Becker +Cc: Nick Piggin +Signed-off-by: Andrew Morton +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/file.c | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.c +@@ -1866,6 +1866,13 @@ relock: + written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos, + ppos, count, ocount); + if (written < 0) { ++ /* ++ * direct write may have instantiated a few ++ * blocks outside i_size. Trim these off again. ++ * Don't need i_size_read because we hold i_mutex. ++ */ ++ if (*ppos + count > inode->i_size) ++ vmtruncate(inode, inode->i_size); + ret = written; + goto out_dio; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-tweak-to-get-the-maximum-inline-data-size-wit.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-tweak-to-get-the-maximum-inline-data-size-wit.patch new file mode 100644 index 000000000..592e1ff0a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-tweak-to-get-the-maximum-inline-data-size-wit.patch @@ -0,0 +1,80 @@ +From: Tiger Yang +Date: Thu, 5 Mar 2009 11:06:15 +0800 +Subject: [PATCH] ocfs2: tweak to get the maximum inline data size with xattr +Patch-mainline: 2.6.29 + +Replace max_inline_data with max_inline_data_with_xattr +to ensure it correct when xattr inlined. + +Signed-off-by: Tiger Yang +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/aops.c | 7 +++++-- + fs/ocfs2/namei.c | 3 ++- + fs/ocfs2/ocfs2_fs.h | 6 ------ + 3 files changed, 7 insertions(+), 9 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/aops.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/aops.c +@@ -234,7 +234,7 @@ int ocfs2_read_inline_data(struct inode + size = i_size_read(inode); + + if (size > PAGE_CACHE_SIZE || +- size > ocfs2_max_inline_data(inode->i_sb)) { ++ size > ocfs2_max_inline_data_with_xattr(inode->i_sb, di)) { + ocfs2_error(inode->i_sb, + "Inode %llu has with inline data has bad size: %Lu", + (unsigned long long)OCFS2_I(inode)->ip_blkno, +@@ -1575,6 +1575,7 @@ static int ocfs2_try_to_write_inline_dat + int ret, written = 0; + loff_t end = pos + len; + struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_dinode *di = NULL; + + mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n", + (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos, +@@ -1607,7 +1608,9 @@ static int ocfs2_try_to_write_inline_dat + /* + * Check whether the write can fit. + */ +- if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb)) ++ di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; ++ if (mmap_page || ++ end > ocfs2_max_inline_data_with_xattr(inode->i_sb, di)) + return 0; + + do_inline_write: +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/namei.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/namei.c +@@ -532,7 +532,8 @@ static int ocfs2_mknod_locked(struct ocf + + fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); + +- fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb)); ++ fe->id2.i_data.id_count = cpu_to_le16( ++ ocfs2_max_inline_data_with_xattr(osb->sb, fe)); + } else { + fel = &fe->id2.i_list; + fel->l_tree_depth = 0; +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/ocfs2_fs.h +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/ocfs2_fs.h ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/ocfs2_fs.h +@@ -987,12 +987,6 @@ static inline int ocfs2_fast_symlink_cha + offsetof(struct ocfs2_dinode, id2.i_symlink); + } + +-static inline int ocfs2_max_inline_data(struct super_block *sb) +-{ +- return sb->s_blocksize - +- offsetof(struct ocfs2_dinode, id2.i_data.id_data); +-} +- + static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb, + struct ocfs2_dinode *di) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-use-xs-bucket-to-set-xattr-value-outside.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-use-xs-bucket-to-set-xattr-value-outside.patch new file mode 100644 index 000000000..10048a664 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-use-xs-bucket-to-set-xattr-value-outside.patch @@ -0,0 +1,67 @@ +From: Tao Ma +Date: Thu, 12 Mar 2009 08:37:34 +0800 +Subject: [PATCH] ocfs2: Use xs->bucket to set xattr value outside +Patch-mainline: 2.6.29 + +A long time ago, xs->base is allocated a 4K size and all the contents +in the bucket are copied to the it. Now we use ocfs2_xattr_bucket to +abstract xattr bucket and xs->base is initialized to the start of the +bu_bhs[0]. So xs->base + offset will overflow when the value root is +stored outside the first block. + +Then why we can survive the xattr test by now? It is because we always +read the bucket contiguously now and kernel mm allocate continguous +memory for us. We are lucky, but we should fix it. So just get the +right value root as other callers do. + +Signed-off-by: Tao Ma +Acked-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 26 ++++++++++++++++++++------ + 1 files changed, 20 insertions(+), 6 deletions(-) + +Index: linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-sle11_ocfs2_update2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-sle11_ocfs2_update2/fs/ocfs2/xattr.c +@@ -4649,19 +4649,33 @@ static int ocfs2_xattr_bucket_set_value_ + char *val, + int value_len) + { +- int offset; ++ int ret, offset, block_off; + struct ocfs2_xattr_value_root *xv; + struct ocfs2_xattr_entry *xe = xs->here; ++ struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); ++ void *base; + + BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe)); + +- offset = le16_to_cpu(xe->xe_name_offset) + +- OCFS2_XATTR_SIZE(xe->xe_name_len); ++ ret = ocfs2_xattr_bucket_get_name_value(inode, xh, ++ xe - xh->xh_entries, ++ &block_off, ++ &offset); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } + +- xv = (struct ocfs2_xattr_value_root *)(xs->base + offset); ++ base = bucket_block(xs->bucket, block_off); ++ xv = (struct ocfs2_xattr_value_root *)(base + offset + ++ OCFS2_XATTR_SIZE(xe->xe_name_len)); + +- return __ocfs2_xattr_set_value_outside(inode, handle, +- xv, val, value_len); ++ ret = __ocfs2_xattr_set_value_outside(inode, handle, ++ xv, val, value_len); ++ if (ret) ++ mlog_errno(ret); ++out: ++ return ret; + } + + static int ocfs2_rm_xattr_cluster(struct inode *inode, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-wakeup-the-downconvert-thread-after-a-success.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-wakeup-the-downconvert-thread-after-a-success.patch new file mode 100644 index 000000000..4915c00e2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-wakeup-the-downconvert-thread-after-a-success.patch @@ -0,0 +1,34 @@ +From: Sunil Mushran +Date: Thu, 29 Jan 2009 17:12:31 -0800 +Subject: [PATCH] ocfs2: Wakeup the downconvert thread after a successful cancel convert +Patch-mainline: 2.6.29 + +When two nodes holding PR locks on a resource concurrently attempt to +upconvert the locks to EX, the master sends a BAST to one of the nodes. This +message tells that node to first cancel convert the upconvert request, +followed by downconvert to a NL. Only when this lock is downconverted to NL, +can the master upconvert the first node's lock to EX. + +While the fs was doing the cancel convert, it was forgetting to wake up the +dc thread after a successful cancel, leading to a deadlock. + +Reported-and-Tested-by: David Teigland +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dlmglue.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/ocfs2/dlmglue.c ++++ b/fs/ocfs2/dlmglue.c +@@ -2866,6 +2866,10 @@ static void ocfs2_unlock_ast(void *opaqu + case OCFS2_UNLOCK_CANCEL_CONVERT: + mlog(0, "Cancel convert success for %s\n", lockres->l_name); + lockres->l_action = OCFS2_AST_INVALID; ++ /* Downconvert thread may have requeued this lock, we ++ * need to wake it. */ ++ if (lockres->l_flags & OCFS2_LOCK_BLOCKED) ++ ocfs2_wake_downconvert_thread(ocfs2_get_lockres_osb(lockres)); + break; + case OCFS2_UNLOCK_DROP_LOCK: + lockres->l_level = DLM_LOCK_IV; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-xattr-Proper-hash-collision-handle-in-bucket.patch b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-xattr-Proper-hash-collision-handle-in-bucket.patch new file mode 100644 index 000000000..f91fa4d90 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ocfs2-xattr-Proper-hash-collision-handle-in-bucket.patch @@ -0,0 +1,261 @@ +From: Tao Ma +Date: Mon, 27 Oct 2008 06:06:24 +0800 +Subject: ocfs2/xattr: Proper hash collision handle in bucket division + +In ocfs2/xattr, we must make sure the xattrs which have the same hash value +exist in the same bucket so that the search schema can work. But in the old +implementation, when we want to extend a bucket, we just move half number of +xattrs to the new bucket. This works in most cases, but if we are lucky +enough we will move 2 xattrs into 2 different buckets. This means that an +xattr from the previous bucket cannot be found anymore. This patch fix this +problem by finding the right position during extending the bucket and extend +an empty bucket if needed. + +Signed-off-by: Tao Ma +Cc: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 144 +++++++++++++++++++++++++++++++++++++++++++----------- + 1 files changed, 115 insertions(+), 29 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -3110,25 +3110,73 @@ static int ocfs2_read_xattr_bucket(struc + } + + /* +- * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk). ++ * Find the suitable pos when we divide a bucket into 2. ++ * We have to make sure the xattrs with the same hash value exist ++ * in the same bucket. ++ * ++ * If this ocfs2_xattr_header covers more than one hash value, find a ++ * place where the hash value changes. Try to find the most even split. ++ * The most common case is that all entries have different hash values, ++ * and the first check we make will find a place to split. ++ */ ++static int ocfs2_xattr_find_divide_pos(struct ocfs2_xattr_header *xh) ++{ ++ struct ocfs2_xattr_entry *entries = xh->xh_entries; ++ int count = le16_to_cpu(xh->xh_count); ++ int delta, middle = count / 2; ++ ++ /* ++ * We start at the middle. Each step gets farther away in both ++ * directions. We therefore hit the change in hash value ++ * nearest to the middle. Note that this loop does not execute for ++ * count < 2. ++ */ ++ for (delta = 0; delta < middle; delta++) { ++ /* Let's check delta earlier than middle */ ++ if (cmp_xe(&entries[middle - delta - 1], ++ &entries[middle - delta])) ++ return middle - delta; ++ ++ /* For even counts, don't walk off the end */ ++ if ((middle + delta + 1) == count) ++ continue; ++ ++ /* Now try delta past middle */ ++ if (cmp_xe(&entries[middle + delta], ++ &entries[middle + delta + 1])) ++ return middle + delta + 1; ++ } ++ ++ /* Every entry had the same hash */ ++ return count; ++} ++ ++/* ++ * Move some xattrs in old bucket(blk) to new bucket(new_blk). + * first_hash will record the 1st hash of the new bucket. ++ * ++ * Normally half of the xattrs will be moved. But we have to make ++ * sure that the xattrs with the same hash value are stored in the ++ * same bucket. If all the xattrs in this bucket have the same hash ++ * value, the new bucket will be initialized as an empty one and the ++ * first_hash will be initialized as (hash_value+1). + */ +-static int ocfs2_half_xattr_bucket(struct inode *inode, +- handle_t *handle, +- u64 blk, +- u64 new_blk, +- u32 *first_hash, +- int new_bucket_head) ++static int ocfs2_divide_xattr_bucket(struct inode *inode, ++ handle_t *handle, ++ u64 blk, ++ u64 new_blk, ++ u32 *first_hash, ++ int new_bucket_head) + { + int ret, i; +- u16 count, start, len, name_value_len, xe_len, name_offset; ++ int count, start, len, name_value_len = 0, xe_len, name_offset = 0; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + struct buffer_head **s_bhs, **t_bhs = NULL; + struct ocfs2_xattr_header *xh; + struct ocfs2_xattr_entry *xe; + int blocksize = inode->i_sb->s_blocksize; + +- mlog(0, "move half of xattrs from bucket %llu to %llu\n", ++ mlog(0, "move some of xattrs from bucket %llu to %llu\n", + blk, new_blk); + + s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); +@@ -3171,14 +3219,35 @@ static int ocfs2_half_xattr_bucket(struc + } + } + ++ xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; ++ count = le16_to_cpu(xh->xh_count); ++ start = ocfs2_xattr_find_divide_pos(xh); ++ ++ if (start == count) { ++ xe = &xh->xh_entries[start-1]; ++ ++ /* ++ * initialized a new empty bucket here. ++ * The hash value is set as one larger than ++ * that of the last entry in the previous bucket. ++ */ ++ for (i = 0; i < blk_per_bucket; i++) ++ memset(t_bhs[i]->b_data, 0, blocksize); ++ ++ xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; ++ xh->xh_free_start = cpu_to_le16(blocksize); ++ xh->xh_entries[0].xe_name_hash = xe->xe_name_hash; ++ le32_add_cpu(&xh->xh_entries[0].xe_name_hash, 1); ++ ++ goto set_num_buckets; ++ } ++ + /* copy the whole bucket to the new first. */ + for (i = 0; i < blk_per_bucket; i++) + memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); + + /* update the new bucket. */ + xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; +- count = le16_to_cpu(xh->xh_count); +- start = count / 2; + + /* + * Calculate the total name/value len and xh_free_start for +@@ -3235,6 +3304,7 @@ static int ocfs2_half_xattr_bucket(struc + xh->xh_free_start = xe->xe_name_offset; + } + ++set_num_buckets: + /* set xh->xh_num_buckets for the new xh. */ + if (new_bucket_head) + xh->xh_num_buckets = cpu_to_le16(1); +@@ -3252,9 +3322,13 @@ static int ocfs2_half_xattr_bucket(struc + *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash); + + /* +- * Now only update the 1st block of the old bucket. +- * Please note that the entry has been sorted already above. ++ * Now only update the 1st block of the old bucket. If we ++ * just added a new empty bucket, there is no need to modify ++ * it. + */ ++ if (start == count) ++ goto out; ++ + xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; + memset(&xh->xh_entries[start], 0, + sizeof(struct ocfs2_xattr_entry) * (count - start)); +@@ -3439,15 +3513,15 @@ out: + } + + /* +- * Move half of the xattrs in this cluster to the new cluster. ++ * Move some xattrs in this cluster to the new cluster. + * This function should only be called when bucket size == cluster size. + * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead. + */ +-static int ocfs2_half_xattr_cluster(struct inode *inode, +- handle_t *handle, +- u64 prev_blk, +- u64 new_blk, +- u32 *first_hash) ++static int ocfs2_divide_xattr_cluster(struct inode *inode, ++ handle_t *handle, ++ u64 prev_blk, ++ u64 new_blk, ++ u32 *first_hash) + { + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + int ret, credits = 2 * blk_per_bucket; +@@ -3461,8 +3535,8 @@ static int ocfs2_half_xattr_cluster(stru + } + + /* Move half of the xattr in start_blk to the next bucket. */ +- return ocfs2_half_xattr_bucket(inode, handle, prev_blk, +- new_blk, first_hash, 1); ++ return ocfs2_divide_xattr_bucket(inode, handle, prev_blk, ++ new_blk, first_hash, 1); + } + + /* +@@ -3524,9 +3598,9 @@ static int ocfs2_adjust_xattr_cross_clus + last_blk, new_blk, + v_start); + else { +- ret = ocfs2_half_xattr_cluster(inode, handle, +- last_blk, new_blk, +- v_start); ++ ret = ocfs2_divide_xattr_cluster(inode, handle, ++ last_blk, new_blk, ++ v_start); + + if ((*header_bh)->b_blocknr == last_blk && extend) + *extend = 0; +@@ -3743,8 +3817,8 @@ static int ocfs2_extend_xattr_bucket(str + } + + /* Move half of the xattr in start_blk to the next bucket. */ +- ret = ocfs2_half_xattr_bucket(inode, handle, start_blk, +- start_blk + blk_per_bucket, NULL, 0); ++ ret = ocfs2_divide_xattr_bucket(inode, handle, start_blk, ++ start_blk + blk_per_bucket, NULL, 0); + + le16_add_cpu(&first_xh->xh_num_buckets, 1); + ocfs2_journal_dirty(handle, first_bh); +@@ -4435,11 +4509,21 @@ out: + return ret; + } + +-/* check whether the xattr bucket is filled up with the same hash value. */ ++/* ++ * check whether the xattr bucket is filled up with the same hash value. ++ * If we want to insert the xattr with the same hash, return -ENOSPC. ++ * If we want to insert a xattr with different hash value, go ahead ++ * and ocfs2_divide_xattr_bucket will handle this. ++ */ + static int ocfs2_check_xattr_bucket_collision(struct inode *inode, +- struct ocfs2_xattr_bucket *bucket) ++ struct ocfs2_xattr_bucket *bucket, ++ const char *name) + { + struct ocfs2_xattr_header *xh = bucket->xh; ++ u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); ++ ++ if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash)) ++ return 0; + + if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash == + xh->xh_entries[0].xe_name_hash) { +@@ -4562,7 +4646,9 @@ try_again: + * one bucket's worth, so check it here whether we need to + * add a new bucket for the insert. + */ +- ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket); ++ ret = ocfs2_check_xattr_bucket_collision(inode, ++ &xs->bucket, ++ xi->name); + if (ret) { + mlog_errno(ret); + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/oom-warning b/src/patches/suse-2.6.27.31/patches.fixes/oom-warning new file mode 100644 index 000000000..cd9a3a788 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/oom-warning @@ -0,0 +1,30 @@ +From: Andrea Arcangeli +Subject: Tell the end user they should not worry about GFP_ATOMIC failures +Patch-mainline: no +References: SUSE48965 + +x + +Signed-off-by: Andrea Arcangeli + +--- + mm/page_alloc.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1650,7 +1650,13 @@ nofail_alloc: + + nopage: + if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) { +- printk(KERN_WARNING "%s: page allocation failure." ++ if (!wait) { ++ printk(KERN_INFO "The following is only an harmless informational message.\n"); ++ printk(KERN_INFO "Unless you get a _continuous_flood_ of these messages it means\n"); ++ printk(KERN_INFO "everything is working fine. Allocations from irqs cannot be\n"); ++ printk(KERN_INFO "perfectly reliable and the kernel is designed to handle that.\n"); ++ } ++ printk(KERN_INFO "%s: page allocation failure." + " order:%d, mode:0x%x\n", + p->comm, order, gfp_mask); + dump_stack(); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/open-iscsi-git-update b/src/patches/suse-2.6.27.31/patches.fixes/open-iscsi-git-update new file mode 100644 index 000000000..d221e0f95 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/open-iscsi-git-update @@ -0,0 +1,245 @@ +From: Mike Christie +Subject: Open-iSCSI updates +References: FATE#304283 + +This patch updates the open-iscsi stack to include the required +support for bnx2i driver. + +Signed-off-by: Hannes Reinecke + +--- + drivers/infiniband/ulp/iser/iscsi_iser.c | 1 + drivers/scsi/iscsi_tcp.c | 1 + drivers/scsi/libiscsi.c | 72 +++++++++++++++++++++++++++---- + include/scsi/iscsi_if.h | 1 + include/scsi/libiscsi.h | 7 +++ + 5 files changed, 75 insertions(+), 7 deletions(-) + +--- a/drivers/infiniband/ulp/iser/iscsi_iser.c ++++ b/drivers/infiniband/ulp/iser/iscsi_iser.c +@@ -378,6 +378,7 @@ static void iscsi_iser_session_destroy(s + { + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + ++ iscsi_session_teardown(cls_session); + iscsi_host_remove(shost); + iscsi_host_free(shost); + } +--- a/drivers/scsi/iscsi_tcp.c ++++ b/drivers/scsi/iscsi_tcp.c +@@ -1904,6 +1904,7 @@ static void iscsi_tcp_session_destroy(st + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + + iscsi_r2tpool_free(cls_session->dd_data); ++ iscsi_session_teardown(cls_session); + + iscsi_host_remove(shost); + iscsi_host_free(shost); +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -368,11 +368,12 @@ void __iscsi_get_task(struct iscsi_task + } + EXPORT_SYMBOL_GPL(__iscsi_get_task); + +-static void __iscsi_put_task(struct iscsi_task *task) ++void __iscsi_put_task(struct iscsi_task *task) + { + if (atomic_dec_and_test(&task->refcount)) + iscsi_complete_command(task); + } ++EXPORT_SYMBOL_GPL(__iscsi_put_task); + + void iscsi_put_task(struct iscsi_task *task) + { +@@ -711,7 +712,7 @@ static int iscsi_handle_reject(struct is + * + * The session lock must be held. + */ +-static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) ++struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) + { + struct iscsi_session *session = conn->session; + uint32_t i; +@@ -725,6 +726,7 @@ static struct iscsi_task *iscsi_itt_to_t + + return session->cmds[i]; + } ++EXPORT_SYMBOL_GPL(iscsi_itt_to_task); + + /** + * __iscsi_complete_pdu - complete pdu +@@ -954,6 +956,38 @@ struct iscsi_task *iscsi_itt_to_ctask(st + } + EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); + ++void iscsi_session_failure(struct iscsi_cls_session *cls_session, ++ enum iscsi_err err) ++{ ++ struct iscsi_session *session = cls_session->dd_data; ++ struct iscsi_conn *conn; ++ struct device *dev; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&session->lock, flags); ++ conn = session->leadconn; ++ if (session->state == ISCSI_STATE_TERMINATE || !conn) { ++ spin_unlock_irqrestore(&session->lock, flags); ++ return; ++ } ++ ++ dev = get_device(&conn->cls_conn->dev); ++ spin_unlock_irqrestore(&session->lock, flags); ++ if (!dev) ++ return; ++ /* ++ * if the host is being removed bypass the connection ++ * recovery initialization because we are going to kill ++ * the session. ++ */ ++ if (err == ISCSI_ERR_INVALID_HOST) ++ iscsi_conn_error(conn->cls_conn, err); ++ else ++ iscsi_conn_failure(conn, err); ++ put_device(dev); ++} ++EXPORT_SYMBOL_GPL(iscsi_session_failure); ++ + void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) + { + struct iscsi_session *session = conn->session; +@@ -968,6 +1002,7 @@ void iscsi_conn_failure(struct iscsi_con + if (conn->stop_stage == 0) + session->state = ISCSI_STATE_FAILED; + spin_unlock_irqrestore(&session->lock, flags); ++ + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + iscsi_conn_error(conn->cls_conn, err); +@@ -1878,6 +1913,7 @@ struct Scsi_Host *iscsi_host_alloc(struc + int dd_data_size, uint16_t qdepth) + { + struct Scsi_Host *shost; ++ struct iscsi_host *ihost; + + shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); + if (!shost) +@@ -1892,22 +1928,36 @@ struct Scsi_Host *iscsi_host_alloc(struc + qdepth = ISCSI_DEF_CMD_PER_LUN; + } + shost->cmd_per_lun = qdepth; ++ ++ ihost = shost_priv(shost); ++ atomic_set(&ihost->num_sessions, 0); ++ init_waitqueue_head(&ihost->session_removal_wq); + return shost; + } + EXPORT_SYMBOL_GPL(iscsi_host_alloc); + ++static void iscsi_kill_session(struct iscsi_cls_session *cls_session) ++{ ++ iscsi_session_failure(cls_session, ISCSI_ERR_INVALID_HOST); ++} ++ + /** + * iscsi_host_remove - remove host and sessions + * @shost: scsi host + * +- * This will also remove any sessions attached to the host, but if userspace +- * is managing the session at the same time this will break. TODO: add +- * refcounting to the netlink iscsi interface so a rmmod or host hot unplug +- * does not remove the memory from under us. ++ * If there are any sessions left, this will initiate the removal and wait ++ * for the completion. + */ + void iscsi_host_remove(struct Scsi_Host *shost) + { +- iscsi_host_for_each_session(shost, iscsi_session_teardown); ++ struct iscsi_host *ihost = shost_priv(shost); ++ ++ iscsi_host_for_each_session(shost, iscsi_kill_session); ++ wait_event_interruptible(ihost->session_removal_wq, ++ atomic_read(&ihost->num_sessions) == 0); ++ if (signal_pending(current)) ++ flush_signals(current); ++ + scsi_remove_host(shost); + } + EXPORT_SYMBOL_GPL(iscsi_host_remove); +@@ -1943,6 +1993,7 @@ iscsi_session_setup(struct iscsi_transpo + uint16_t cmds_max, int cmd_task_size, + uint32_t initial_cmdsn, unsigned int id) + { ++ struct iscsi_host *ihost = shost_priv(shost); + struct iscsi_session *session; + struct iscsi_cls_session *cls_session; + int cmd_i, scsi_cmds, total_cmds = cmds_max; +@@ -2021,6 +2072,8 @@ iscsi_session_setup(struct iscsi_transpo + + if (iscsi_add_session(cls_session, id)) + goto cls_session_fail; ++ ++ atomic_inc(&ihost->num_sessions); + return cls_session; + + cls_session_fail: +@@ -2043,6 +2096,7 @@ EXPORT_SYMBOL_GPL(iscsi_session_setup); + void iscsi_session_teardown(struct iscsi_cls_session *cls_session) + { + struct iscsi_session *session = cls_session->dd_data; ++ struct iscsi_host *ihost = shost_priv(session->host); + struct module *owner = cls_session->transport->owner; + + iscsi_pool_free(&session->cmdpool); +@@ -2056,6 +2110,10 @@ void iscsi_session_teardown(struct iscsi + kfree(session->ifacename); + + iscsi_destroy_session(cls_session); ++ ++ atomic_dec(&ihost->num_sessions); ++ wake_up(&ihost->session_removal_wq); ++ + module_put(owner); + } + EXPORT_SYMBOL_GPL(iscsi_session_teardown); +--- a/include/scsi/iscsi_if.h ++++ b/include/scsi/iscsi_if.h +@@ -213,6 +213,7 @@ enum iscsi_err { + ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15, + ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16, + ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17, ++ ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18, + }; + + /* +--- a/include/scsi/libiscsi.h ++++ b/include/scsi/libiscsi.h +@@ -295,6 +295,9 @@ struct iscsi_host { + /* local address */ + int local_port; + char local_address[ISCSI_ADDRESS_BUF_LEN]; ++ ++ wait_queue_head_t session_removal_wq; ++ atomic_t num_sessions; + }; + + /* +@@ -351,6 +354,8 @@ extern void iscsi_conn_stop(struct iscsi + extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *, + int); + extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); ++extern void iscsi_session_failure(struct iscsi_cls_session *cls_session, ++ enum iscsi_err err); + extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf); + extern void iscsi_suspend_tx(struct iscsi_conn *conn); +@@ -373,8 +378,10 @@ extern int __iscsi_complete_pdu(struct i + char *, int); + extern int iscsi_verify_itt(struct iscsi_conn *, itt_t); + extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t); ++extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t); + extern void iscsi_requeue_task(struct iscsi_task *task); + extern void iscsi_put_task(struct iscsi_task *task); ++extern void __iscsi_put_task(struct iscsi_task *task); + extern void __iscsi_get_task(struct iscsi_task *task); + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/open-iscsi-mv-transport-eh-setting b/src/patches/suse-2.6.27.31/patches.fixes/open-iscsi-mv-transport-eh-setting new file mode 100644 index 000000000..e52b7b9f6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/open-iscsi-mv-transport-eh-setting @@ -0,0 +1,35 @@ +From: Mike Christie +Subject: Kernel panic on sysReboot of array controller +References: bnc#466846 + +Here is a patch made against upstream. It is simple. The +transportt->eh_timed_out was supposed to go in iscsi_host_add. It used +to be in iscsi_host_alloc because we set the LLD transportt in there +(now the LLD does it after calling iscsi_host_alloc). + +Signed-off-by: Yanling Qi +Signed-off-by: Mike Christie +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/libiscsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -1927,6 +1927,7 @@ int iscsi_host_add(struct Scsi_Host *sho + if (!shost->can_queue) + shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX; + ++ shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; + return scsi_add_host(shost, pdev); + } + EXPORT_SYMBOL_GPL(iscsi_host_add); +@@ -1949,7 +1950,6 @@ struct Scsi_Host *iscsi_host_alloc(struc + shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); + if (!shost) + return NULL; +- shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; + + if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { + if (qdepth != 0) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/parport-mutex b/src/patches/suse-2.6.27.31/patches.fixes/parport-mutex new file mode 100644 index 000000000..908b8fa16 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/parport-mutex @@ -0,0 +1,41 @@ +From: salina@us.ibm.com +Subject: No lp_release_parport while write is going on +References: 62947 - LTC11483 + +This patch was done by IBM a while back, but apparently never made it +into mainline. It fixes a problem in the lp driver that can cause oopses. + +Scenario: + process A: calls lp_write, which in turn calls parport_ieee1284_write_compat, + and that invokes parport_wait_peripheral + process B: meanwhile does an ioctl(LPGETSTATUS), which call lp_release_parport + when done. This function will set physport->cad = NULL. + process A: parport_wait_peripheral tries to dereference physport->cad and + dies + +The patch below simply protects that code with the port_mutex in order to +protect against simultaneous calls to lp_read/lp_write. + +Similar protection is probably required for ioctl(LPRESET). + +Signed-off-by: okir@suse.de + +--- + drivers/char/lp.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/char/lp.c ++++ b/drivers/char/lp.c +@@ -626,9 +626,12 @@ static int lp_ioctl(struct inode *inode, + return -EFAULT; + break; + case LPGETSTATUS: ++ if (mutex_lock_interruptible(&lp_table[minor].port_mutex)) ++ return -EINTR; + lp_claim_parport_or_block (&lp_table[minor]); + status = r_str(minor); + lp_release_parport (&lp_table[minor]); ++ mutex_unlock(&lp_table[minor].port_mutex); + + if (copy_to_user(argp, &status, sizeof(int))) + return -EFAULT; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/pci-amd-813x-b2-devices-do-not-need-quirk.patch b/src/patches/suse-2.6.27.31/patches.fixes/pci-amd-813x-b2-devices-do-not-need-quirk.patch new file mode 100644 index 000000000..cf93778fe --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/pci-amd-813x-b2-devices-do-not-need-quirk.patch @@ -0,0 +1,37 @@ +From: Stefan Assmann +Subject: PCI: AMD 813x B2 devices do not need quirk +References: bnc#477675 +Patch-mainline: 2.6.30 + +Turns out that the new AMD 813x devices do not need the +quirk_disable_amd_813x_boot_interrupt quirk to be run on them, if it is, +no interrupts are seen on the PCI-X adapter. + +From: Stefan Assmann +Reported-by: Jamie Wellnitz +Tested-by: Jamie Wellnitz +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pci/quirks.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -1509,6 +1509,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_S + */ + #define AMD_813X_MISC 0x40 + #define AMD_813X_NOIOAMODE (1<<0) ++#define AMD_813X_REV_B2 0x13 + + static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) + { +@@ -1516,6 +1517,8 @@ static void quirk_disable_amd_813x_boot_ + + if (noioapicquirk) + return; ++ if (dev->revision == AMD_813X_REV_B2) ++ return; + + pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword); + pci_config_dword &= ~AMD_813X_NOIOAMODE; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/percpu_counter_sum_cleanup.patch b/src/patches/suse-2.6.27.31/patches.fixes/percpu_counter_sum_cleanup.patch new file mode 100644 index 000000000..8962ab259 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/percpu_counter_sum_cleanup.patch @@ -0,0 +1,95 @@ +From: Mingming Cao +Subject: percpu counter: clean up percpu_counter_sum_and_set() +References: fate#303783 + +percpu_counter_sum_and_set() and percpu_counter_sum() is the same except +the former update the global counter after accounting. Since we are +taking the fbc->lock to calculate the precise value of the +counter in percpu_counter_sum() anyway, it should simply set fbc->count +too, as the percpu_counter_sum_and_set() dose. + +This patch merge these two interfaces into one. + +Signed-off-by: Mingming Cao +Acked-by: Jan Kara +--- + fs/ext4/balloc.c | 2 +- + include/linux/percpu_counter.h | 12 +++--------- + lib/percpu_counter.c | 8 +++----- + 3 files changed, 7 insertions(+), 15 deletions(-) + +Index: linux-2.6.27-rc3/fs/ext4/balloc.c +=================================================================== +--- linux-2.6.27-rc3.orig/fs/ext4/balloc.c 2008-08-20 17:25:35.000000000 -0700 ++++ linux-2.6.27-rc3/fs/ext4/balloc.c 2008-08-21 14:34:32.000000000 -0700 +@@ -1624,7 +1624,7 @@ + #ifdef CONFIG_SMP + if (free_blocks - root_blocks < FBC_BATCH) + free_blocks = +- percpu_counter_sum_and_set(&sbi->s_freeblocks_counter); ++ percpu_counter_sum(&sbi->s_freeblocks_counter); + #endif + if (free_blocks <= root_blocks) + /* we don't have free space */ +Index: linux-2.6.27-rc3/include/linux/percpu_counter.h +=================================================================== +--- linux-2.6.27-rc3.orig/include/linux/percpu_counter.h 2008-08-20 17:25:35.000000000 -0700 ++++ linux-2.6.27-rc3/include/linux/percpu_counter.h 2008-08-21 14:34:32.000000000 -0700 +@@ -35,7 +35,7 @@ + void percpu_counter_destroy(struct percpu_counter *fbc); + void percpu_counter_set(struct percpu_counter *fbc, s64 amount); + void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch); +-s64 __percpu_counter_sum(struct percpu_counter *fbc, int set); ++s64 __percpu_counter_sum(struct percpu_counter *fbc); + + static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) + { +@@ -44,19 +44,13 @@ + + static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc) + { +- s64 ret = __percpu_counter_sum(fbc, 0); ++ s64 ret = __percpu_counter_sum(fbc); + return ret < 0 ? 0 : ret; + } + +-static inline s64 percpu_counter_sum_and_set(struct percpu_counter *fbc) +-{ +- return __percpu_counter_sum(fbc, 1); +-} +- +- + static inline s64 percpu_counter_sum(struct percpu_counter *fbc) + { +- return __percpu_counter_sum(fbc, 0); ++ return __percpu_counter_sum(fbc); + } + + static inline s64 percpu_counter_read(struct percpu_counter *fbc) +Index: linux-2.6.27-rc3/lib/percpu_counter.c +=================================================================== +--- linux-2.6.27-rc3.orig/lib/percpu_counter.c 2008-08-20 17:25:35.000000000 -0700 ++++ linux-2.6.27-rc3/lib/percpu_counter.c 2008-08-21 14:34:32.000000000 -0700 +@@ -52,7 +52,7 @@ + * Add up all the per-cpu counts, return the result. This is a more accurate + * but much slower version of percpu_counter_read_positive() + */ +-s64 __percpu_counter_sum(struct percpu_counter *fbc, int set) ++s64 __percpu_counter_sum(struct percpu_counter *fbc) + { + s64 ret; + int cpu; +@@ -62,11 +62,9 @@ + for_each_online_cpu(cpu) { + s32 *pcount = per_cpu_ptr(fbc->counters, cpu); + ret += *pcount; +- if (set) +- *pcount = 0; ++ *pcount = 0; + } +- if (set) +- fbc->count = ret; ++ fbc->count = ret; + + spin_unlock(&fbc->lock); + return ret; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/pkt_action-skbedit b/src/patches/suse-2.6.27.31/patches.fixes/pkt_action-skbedit new file mode 100644 index 000000000..2c6b44e6a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/pkt_action-skbedit @@ -0,0 +1,388 @@ +From 1a1cc3a15bba18bae3c29f4eb475aae0df9ef5bd Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:47:10 +0200 +Subject: [PATCH] pkt_action: add new action skbedit + +This new action will have the ability to change the priority and/or +queue_mapping fields on an sk_buff. + +Signed-off-by: Alexander Duyck +Signed-off-by: Hannes Reinecke +--- + Documentation/networking/multiqueue.txt | 9 ++- + include/linux/tc_act/Kbuild | 1 + + include/linux/tc_act/tc_skbedit.h | 44 +++++++ + include/net/tc_act/tc_skbedit.h | 34 +++++ + net/sched/Kconfig | 11 ++ + net/sched/Makefile | 1 + + net/sched/act_skbedit.c | 203 +++++++++++++++++++++++++++++++ + 7 files changed, 302 insertions(+), 1 deletions(-) + create mode 100644 include/linux/tc_act/tc_skbedit.h + create mode 100644 include/net/tc_act/tc_skbedit.h + create mode 100644 net/sched/act_skbedit.c + +diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt +index 5787ee6..10113ff 100644 +--- a/Documentation/networking/multiqueue.txt ++++ b/Documentation/networking/multiqueue.txt +@@ -66,7 +66,14 @@ band 3 => queue 3 + Traffic will begin flowing through each queue if your base device has either + the default simple_tx_hash or a custom netdev->select_queue() defined. + +-The behavior of tc filters remains the same. ++The behavior of tc filters remains the same. However a new tc action, ++skbedit, has been added. Assuming you wanted to route all traffic to a ++specific host, for example 192.168.0.3, though a specific queue you could use ++this action and establish a filter such as: ++ ++tc filter add dev eth0 parent 1: protocol ip prio 1 u32 \ ++ match ip dst 192.168.0.3 \ ++ action skbedit queue_mapping 3 + + Author: Alexander Duyck + Original Author: Peter P. Waskiewicz Jr. +diff --git a/include/linux/tc_act/Kbuild b/include/linux/tc_act/Kbuild +index 6dac0d7..7699093 100644 +--- a/include/linux/tc_act/Kbuild ++++ b/include/linux/tc_act/Kbuild +@@ -3,3 +3,4 @@ header-y += tc_ipt.h + header-y += tc_mirred.h + header-y += tc_pedit.h + header-y += tc_nat.h ++header-y += tc_skbedit.h +diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h +new file mode 100644 +index 0000000..a14e461 +--- /dev/null ++++ b/include/linux/tc_act/tc_skbedit.h +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (c) 2008, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Author: Alexander Duyck ++ */ ++ ++#ifndef __LINUX_TC_SKBEDIT_H ++#define __LINUX_TC_SKBEDIT_H ++ ++#include ++ ++#define TCA_ACT_SKBEDIT 11 ++ ++#define SKBEDIT_F_PRIORITY 0x1 ++#define SKBEDIT_F_QUEUE_MAPPING 0x2 ++ ++struct tc_skbedit { ++ tc_gen; ++}; ++ ++enum { ++ TCA_SKBEDIT_UNSPEC, ++ TCA_SKBEDIT_TM, ++ TCA_SKBEDIT_PARMS, ++ TCA_SKBEDIT_PRIORITY, ++ TCA_SKBEDIT_QUEUE_MAPPING, ++ __TCA_SKBEDIT_MAX ++}; ++#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1) ++ ++#endif +diff --git a/include/net/tc_act/tc_skbedit.h b/include/net/tc_act/tc_skbedit.h +new file mode 100644 +index 0000000..6abb3ed +--- /dev/null ++++ b/include/net/tc_act/tc_skbedit.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2008, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Author: Alexander Duyck ++ */ ++ ++#ifndef __NET_TC_SKBEDIT_H ++#define __NET_TC_SKBEDIT_H ++ ++#include ++ ++struct tcf_skbedit { ++ struct tcf_common common; ++ u32 flags; ++ u32 priority; ++ u16 queue_mapping; ++}; ++#define to_skbedit(pc) \ ++ container_of(pc, struct tcf_skbedit, common) ++ ++#endif /* __NET_TC_SKBEDIT_H */ +diff --git a/net/sched/Kconfig b/net/sched/Kconfig +index efaa7a7..6767e54 100644 +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -485,6 +485,17 @@ config NET_ACT_SIMP + To compile this code as a module, choose M here: the + module will be called simple. + ++config NET_ACT_SKBEDIT ++ tristate "SKB Editing" ++ depends on NET_CLS_ACT ++ ---help--- ++ Say Y here to change skb priority or queue_mapping settings. ++ ++ If unsure, say N. ++ ++ To compile this code as a module, choose M here: the ++ module will be called skbedit. ++ + config NET_CLS_IND + bool "Incoming device classification" + depends on NET_CLS_U32 || NET_CLS_FW +diff --git a/net/sched/Makefile b/net/sched/Makefile +index 3d9b953..e60c992 100644 +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -14,6 +14,7 @@ obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o + obj-$(CONFIG_NET_ACT_NAT) += act_nat.o + obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o + obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o ++obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o + obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o + obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o + obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o +diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c +new file mode 100644 +index 0000000..fe9777e +--- /dev/null ++++ b/net/sched/act_skbedit.c +@@ -0,0 +1,203 @@ ++/* ++ * Copyright (c) 2008, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Author: Alexander Duyck ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define SKBEDIT_TAB_MASK 15 ++static struct tcf_common *tcf_skbedit_ht[SKBEDIT_TAB_MASK + 1]; ++static u32 skbedit_idx_gen; ++static DEFINE_RWLOCK(skbedit_lock); ++ ++static struct tcf_hashinfo skbedit_hash_info = { ++ .htab = tcf_skbedit_ht, ++ .hmask = SKBEDIT_TAB_MASK, ++ .lock = &skbedit_lock, ++}; ++ ++static int tcf_skbedit(struct sk_buff *skb, struct tc_action *a, ++ struct tcf_result *res) ++{ ++ struct tcf_skbedit *d = a->priv; ++ ++ spin_lock(&d->tcf_lock); ++ d->tcf_tm.lastuse = jiffies; ++ d->tcf_bstats.bytes += qdisc_pkt_len(skb); ++ d->tcf_bstats.packets++; ++ ++ if (d->flags & SKBEDIT_F_PRIORITY) ++ skb->priority = d->priority; ++ if (d->flags & SKBEDIT_F_QUEUE_MAPPING && ++ skb->dev->real_num_tx_queues > d->queue_mapping) ++ skb_set_queue_mapping(skb, d->queue_mapping); ++ ++ spin_unlock(&d->tcf_lock); ++ return d->tcf_action; ++} ++ ++static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = { ++ [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) }, ++ [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) }, ++ [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) }, ++}; ++ ++static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est, ++ struct tc_action *a, int ovr, int bind) ++{ ++ struct nlattr *tb[TCA_SKBEDIT_MAX + 1]; ++ struct tc_skbedit *parm; ++ struct tcf_skbedit *d; ++ struct tcf_common *pc; ++ u32 flags = 0, *priority = NULL; ++ u16 *queue_mapping = NULL; ++ int ret = 0, err; ++ ++ if (nla == NULL) ++ return -EINVAL; ++ ++ err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy); ++ if (err < 0) ++ return err; ++ ++ if (tb[TCA_SKBEDIT_PARMS] == NULL) ++ return -EINVAL; ++ ++ if (tb[TCA_SKBEDIT_PRIORITY] != NULL) { ++ flags |= SKBEDIT_F_PRIORITY; ++ priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]); ++ } ++ ++ if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) { ++ flags |= SKBEDIT_F_QUEUE_MAPPING; ++ queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]); ++ } ++ if (!flags) ++ return -EINVAL; ++ ++ parm = nla_data(tb[TCA_SKBEDIT_PARMS]); ++ ++ pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info); ++ if (!pc) { ++ pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, ++ &skbedit_idx_gen, &skbedit_hash_info); ++ if (unlikely(!pc)) ++ return -ENOMEM; ++ ++ d = to_skbedit(pc); ++ ret = ACT_P_CREATED; ++ } else { ++ d = to_skbedit(pc); ++ if (!ovr) { ++ tcf_hash_release(pc, bind, &skbedit_hash_info); ++ return -EEXIST; ++ } ++ } ++ ++ spin_lock_bh(&d->tcf_lock); ++ ++ d->flags = flags; ++ if (flags & SKBEDIT_F_PRIORITY) ++ d->priority = *priority; ++ if (flags & SKBEDIT_F_QUEUE_MAPPING) ++ d->queue_mapping = *queue_mapping; ++ d->tcf_action = parm->action; ++ ++ spin_unlock_bh(&d->tcf_lock); ++ ++ if (ret == ACT_P_CREATED) ++ tcf_hash_insert(pc, &skbedit_hash_info); ++ return ret; ++} ++ ++static inline int tcf_skbedit_cleanup(struct tc_action *a, int bind) ++{ ++ struct tcf_skbedit *d = a->priv; ++ ++ if (d) ++ return tcf_hash_release(&d->common, bind, &skbedit_hash_info); ++ return 0; ++} ++ ++static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, ++ int bind, int ref) ++{ ++ unsigned char *b = skb_tail_pointer(skb); ++ struct tcf_skbedit *d = a->priv; ++ struct tc_skbedit opt; ++ struct tcf_t t; ++ ++ opt.index = d->tcf_index; ++ opt.refcnt = d->tcf_refcnt - ref; ++ opt.bindcnt = d->tcf_bindcnt - bind; ++ opt.action = d->tcf_action; ++ NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt); ++ if (d->flags & SKBEDIT_F_PRIORITY) ++ NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority), ++ &d->priority); ++ if (d->flags & SKBEDIT_F_QUEUE_MAPPING) ++ NLA_PUT(skb, TCA_SKBEDIT_QUEUE_MAPPING, ++ sizeof(d->queue_mapping), &d->queue_mapping); ++ t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); ++ t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); ++ t.expires = jiffies_to_clock_t(d->tcf_tm.expires); ++ NLA_PUT(skb, TCA_SKBEDIT_TM, sizeof(t), &t); ++ return skb->len; ++ ++nla_put_failure: ++ nlmsg_trim(skb, b); ++ return -1; ++} ++ ++static struct tc_action_ops act_skbedit_ops = { ++ .kind = "skbedit", ++ .hinfo = &skbedit_hash_info, ++ .type = TCA_ACT_SKBEDIT, ++ .capab = TCA_CAP_NONE, ++ .owner = THIS_MODULE, ++ .act = tcf_skbedit, ++ .dump = tcf_skbedit_dump, ++ .cleanup = tcf_skbedit_cleanup, ++ .init = tcf_skbedit_init, ++ .walk = tcf_generic_walker, ++}; ++ ++MODULE_AUTHOR("Alexander Duyck, "); ++MODULE_DESCRIPTION("SKB Editing"); ++MODULE_LICENSE("GPL"); ++ ++static int __init skbedit_init_module(void) ++{ ++ return tcf_register_action(&act_skbedit_ops); ++} ++ ++static void __exit skbedit_cleanup_module(void) ++{ ++ tcf_unregister_action(&act_skbedit_ops); ++} ++ ++module_init(skbedit_init_module); ++module_exit(skbedit_cleanup_module); +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/pkt_sched_multiq_support b/src/patches/suse-2.6.27.31/patches.fixes/pkt_sched_multiq_support new file mode 100644 index 000000000..2e1cdc20a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/pkt_sched_multiq_support @@ -0,0 +1,608 @@ +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:45:55 +0200 +Subject: pkt_sched: Add multiqueue scheduler support +References: FATE#303913 + +This patch is intended to add a qdisc to support the new tx multiqueue +architecture by providing a band for each hardware queue. By doing +this it is possible to support a different qdisc per physical hardware +queue. + +This qdisc uses the skb->queue_mapping to select which band to place +the traffic onto. It then uses a round robin w/ a check to see if the +subqueue is stopped to determine which band to dequeue the packet from. + +Signed-off-by: Alexander Duyck +Signed-off-by: Hannes Reinecke +--- + Documentation/networking/multiqueue.txt | 47 +++- + include/linux/pkt_sched.h | 7 + + net/sched/Kconfig | 9 + + net/sched/Makefile | 1 + + net/sched/sch_multiq.c | 469 +++++++++++++++++++++++++++++++ + 5 files changed, 532 insertions(+), 1 deletions(-) + create mode 100644 net/sched/sch_multiq.c + +diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt +index d391ea6..5787ee6 100644 +--- a/Documentation/networking/multiqueue.txt ++++ b/Documentation/networking/multiqueue.txt +@@ -24,4 +24,49 @@ netif_{start|stop|wake}_subqueue() functions to manage each queue while the + device is still operational. netdev->queue_lock is still used when the device + comes online or when it's completely shut down (unregister_netdev(), etc.). + +-Author: Peter P. Waskiewicz Jr. ++ ++Section 2: Qdisc support for multiqueue devices ++ ++----------------------------------------------- ++ ++Currently two qdiscs support multiqueue devices. The first is the default ++pfifo_fast qdisc. This qdisc supports one qdisc per hardware queue. A new ++round-robin qdisc, sch_multiq also supports multiple hardware queues. The ++qdisc is responsible for classifying the skb's and then directing the skb's to ++bands and queues based on the value in skb->queue_mapping. Use this field in ++the base driver to determine which queue to send the skb to. ++ ++sch_multiq has been added for hardware that wishes to avoid unnecessary ++requeuing. It will cycle though the bands and verify that the hardware queue ++associated with the band is not stopped prior to dequeuing a packet. ++ ++On qdisc load, the number of bands is based on the number of queues on the ++hardware. Once the association is made, any skb with skb->queue_mapping set, ++will be queued to the band associated with the hardware queue. ++ ++ ++Section 3: Brief howto using MULTIQ for multiqueue devices ++--------------------------------------------------------------- ++ ++The userspace command 'tc,' part of the iproute2 package, is used to configure ++qdiscs. To add the MULTIQ qdisc to your network device, assuming the device ++is called eth0, run the following command: ++ ++# tc qdisc add dev eth0 root handle 1: multiq ++ ++The qdisc will allocate the number of bands to equal the number of queues that ++the device reports, and bring the qdisc online. Assuming eth0 has 4 Tx ++queues, the band mapping would look like: ++ ++band 0 => queue 0 ++band 1 => queue 1 ++band 2 => queue 2 ++band 3 => queue 3 ++ ++Traffic will begin flowing through each queue if your base device has either ++the default simple_tx_hash or a custom netdev->select_queue() defined. ++ ++The behavior of tc filters remains the same. ++ ++Author: Alexander Duyck ++Original Author: Peter P. Waskiewicz Jr. +diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h +index e5de421..5d921fa 100644 +--- a/include/linux/pkt_sched.h ++++ b/include/linux/pkt_sched.h +@@ -123,6 +123,13 @@ struct tc_prio_qopt + __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ + }; + ++/* MULTIQ section */ ++ ++struct tc_multiq_qopt { ++ __u16 bands; /* Number of bands */ ++ __u16 max_bands; /* Maximum number of queues */ ++}; ++ + /* TBF section */ + + struct tc_tbf_qopt +diff --git a/net/sched/Kconfig b/net/sched/Kconfig +index 9437b27..efaa7a7 100644 +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -106,6 +106,15 @@ config NET_SCH_PRIO + To compile this code as a module, choose M here: the + module will be called sch_prio. + ++config NET_SCH_MULTIQ ++ tristate "Hardware Multiqueue-aware Multi Band Queuing (MULTIQ)" ++ ---help--- ++ Say Y here if you want to use an n-band queue packet scheduler ++ to support devices that have multiple hardware transmit queues. ++ ++ To compile this code as a module, choose M here: the ++ module will be called sch_multiq. ++ + config NET_SCH_RED + tristate "Random Early Detection (RED)" + ---help--- +diff --git a/net/sched/Makefile b/net/sched/Makefile +index 1d2b0f7..3d9b953 100644 +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -26,6 +26,7 @@ obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o + obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o + obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o + obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o ++obj-$(CONFIG_NET_SCH_MULTIQ) += sch_multiq.o + obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o + obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o + obj-$(CONFIG_NET_CLS_U32) += cls_u32.o +diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c +new file mode 100644 +index 0000000..ce00df4 +--- /dev/null ++++ b/net/sched/sch_multiq.c +@@ -0,0 +1,469 @@ ++/* ++ * Copyright (c) 2008, Intel Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ * ++ * Author: Alexander Duyck ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct multiq_sched_data { ++ u16 bands; ++ u16 max_bands; ++ u16 curband; ++ struct tcf_proto *filter_list; ++ struct Qdisc **queues; ++}; ++ ++ ++static struct Qdisc * ++multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ u32 band; ++ struct tcf_result res; ++ int err; ++ ++ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; ++ err = tc_classify(skb, q->filter_list, &res); ++#ifdef CONFIG_NET_CLS_ACT ++ switch (err) { ++ case TC_ACT_STOLEN: ++ case TC_ACT_QUEUED: ++ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; ++ case TC_ACT_SHOT: ++ return NULL; ++ } ++#endif ++ band = skb_get_queue_mapping(skb); ++ ++ if (band >= q->bands) ++ return q->queues[0]; ++ ++ return q->queues[band]; ++} ++ ++static int ++multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch) ++{ ++ struct Qdisc *qdisc; ++ int ret; ++ ++ qdisc = multiq_classify(skb, sch, &ret); ++#ifdef CONFIG_NET_CLS_ACT ++ if (qdisc == NULL) { ++ ++ if (ret & __NET_XMIT_BYPASS) ++ sch->qstats.drops++; ++ kfree_skb(skb); ++ return ret; ++ } ++#endif ++ ++ ret = qdisc_enqueue(skb, qdisc); ++ if (ret == NET_XMIT_SUCCESS) { ++ sch->bstats.bytes += qdisc_pkt_len(skb); ++ sch->bstats.packets++; ++ sch->q.qlen++; ++ return NET_XMIT_SUCCESS; ++ } ++ if (net_xmit_drop_count(ret)) ++ sch->qstats.drops++; ++ return ret; ++} ++ ++ ++static int ++multiq_requeue(struct sk_buff *skb, struct Qdisc *sch) ++{ ++ struct Qdisc *qdisc; ++ int ret; ++ ++ qdisc = multiq_classify(skb, sch, &ret); ++#ifdef CONFIG_NET_CLS_ACT ++ if (qdisc == NULL) { ++ if (ret & __NET_XMIT_BYPASS) ++ sch->qstats.drops++; ++ kfree_skb(skb); ++ return ret; ++ } ++#endif ++ ++ ret = qdisc->ops->requeue(skb, qdisc); ++ if (ret == NET_XMIT_SUCCESS) { ++ sch->q.qlen++; ++ sch->qstats.requeues++; ++ return NET_XMIT_SUCCESS; ++ } ++ if (net_xmit_drop_count(ret)) ++ sch->qstats.drops++; ++ return ret; ++} ++ ++ ++static struct sk_buff *multiq_dequeue(struct Qdisc *sch) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ struct Qdisc *qdisc; ++ struct sk_buff *skb; ++ int band; ++ ++ for (band = 0; band < q->bands; band++) { ++ /* cycle through bands to ensure fairness */ ++ q->curband++; ++ if (q->curband >= q->bands) ++ q->curband = 0; ++ ++ /* Check that target subqueue is available before ++ * pulling an skb to avoid excessive requeues ++ */ ++ if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) { ++ qdisc = q->queues[q->curband]; ++ skb = qdisc->dequeue(qdisc); ++ if (skb) { ++ sch->q.qlen--; ++ return skb; ++ } ++ } ++ } ++ return NULL; ++ ++} ++ ++static unsigned int multiq_drop(struct Qdisc *sch) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ int band; ++ unsigned int len; ++ struct Qdisc *qdisc; ++ ++ for (band = q->bands-1; band >= 0; band--) { ++ qdisc = q->queues[band]; ++ if (qdisc->ops->drop) { ++ len = qdisc->ops->drop(qdisc); ++ if (len != 0) { ++ sch->q.qlen--; ++ return len; ++ } ++ } ++ } ++ return 0; ++} ++ ++ ++static void ++multiq_reset(struct Qdisc *sch) ++{ ++ u16 band; ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ ++ for (band = 0; band < q->bands; band++) ++ qdisc_reset(q->queues[band]); ++ sch->q.qlen = 0; ++ q->curband = 0; ++} ++ ++static void ++multiq_destroy(struct Qdisc *sch) ++{ ++ int band; ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ ++ tcf_destroy_chain(&q->filter_list); ++ for (band = 0; band < q->bands; band++) ++ qdisc_destroy(q->queues[band]); ++ ++ kfree(q->queues); ++} ++ ++static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ struct tc_multiq_qopt *qopt; ++ int i; ++ ++ if (sch->parent != TC_H_ROOT) ++ return -EINVAL; ++ if (!netif_is_multiqueue(qdisc_dev(sch))) ++ return -EINVAL; ++ if (nla_len(opt) < sizeof(*qopt)) ++ return -EINVAL; ++ ++ qopt = nla_data(opt); ++ ++ qopt->bands = qdisc_dev(sch)->real_num_tx_queues; ++ ++ sch_tree_lock(sch); ++ q->bands = qopt->bands; ++ for (i = q->bands; i < q->max_bands; i++) { ++ struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc); ++ if (child != &noop_qdisc) { ++ qdisc_tree_decrease_qlen(child, child->q.qlen); ++ qdisc_destroy(child); ++ } ++ } ++ ++ sch_tree_unlock(sch); ++ ++ for (i = 0; i < q->bands; i++) { ++ if (q->queues[i] == &noop_qdisc) { ++ struct Qdisc *child; ++ child = qdisc_create_dflt(qdisc_dev(sch), ++ sch->dev_queue, ++ &pfifo_qdisc_ops, ++ TC_H_MAKE(sch->handle, ++ i + 1)); ++ if (child) { ++ sch_tree_lock(sch); ++ child = xchg(&q->queues[i], child); ++ ++ if (child != &noop_qdisc) { ++ qdisc_tree_decrease_qlen(child, ++ child->q.qlen); ++ qdisc_destroy(child); ++ } ++ sch_tree_unlock(sch); ++ } ++ } ++ } ++ return 0; ++} ++ ++static int multiq_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ int i; ++ ++ q->queues = NULL; ++ ++ if (opt == NULL) ++ return -EINVAL; ++ ++ q->max_bands = qdisc_dev(sch)->num_tx_queues; ++ ++ q->queues = kcalloc(q->max_bands, sizeof(struct Qdisc *), GFP_KERNEL); ++ if (!q->queues) ++ return -ENOBUFS; ++ for (i = 0; i < q->max_bands; i++) ++ q->queues[i] = &noop_qdisc; ++ ++ return multiq_tune(sch, opt); ++} ++ ++static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ unsigned char *b = skb_tail_pointer(skb); ++ struct tc_multiq_qopt opt; ++ ++ opt.bands = q->bands; ++ opt.max_bands = q->max_bands; ++ ++ NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); ++ ++ return skb->len; ++ ++nla_put_failure: ++ nlmsg_trim(skb, b); ++ return -1; ++} ++ ++static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, ++ struct Qdisc **old) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ unsigned long band = arg - 1; ++ ++ if (band >= q->bands) ++ return -EINVAL; ++ ++ if (new == NULL) ++ new = &noop_qdisc; ++ ++ sch_tree_lock(sch); ++ *old = q->queues[band]; ++ q->queues[band] = new; ++ qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); ++ qdisc_reset(*old); ++ sch_tree_unlock(sch); ++ ++ return 0; ++} ++ ++static struct Qdisc * ++multiq_leaf(struct Qdisc *sch, unsigned long arg) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ unsigned long band = arg - 1; ++ ++ if (band >= q->bands) ++ return NULL; ++ ++ return q->queues[band]; ++} ++ ++static unsigned long multiq_get(struct Qdisc *sch, u32 classid) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ unsigned long band = TC_H_MIN(classid); ++ ++ if (band - 1 >= q->bands) ++ return 0; ++ return band; ++} ++ ++static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent, ++ u32 classid) ++{ ++ return multiq_get(sch, classid); ++} ++ ++ ++static void multiq_put(struct Qdisc *q, unsigned long cl) ++{ ++ return; ++} ++ ++static int multiq_change(struct Qdisc *sch, u32 handle, u32 parent, ++ struct nlattr **tca, unsigned long *arg) ++{ ++ unsigned long cl = *arg; ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ ++ if (cl - 1 > q->bands) ++ return -ENOENT; ++ return 0; ++} ++ ++static int multiq_delete(struct Qdisc *sch, unsigned long cl) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ if (cl - 1 > q->bands) ++ return -ENOENT; ++ return 0; ++} ++ ++ ++static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, ++ struct sk_buff *skb, struct tcmsg *tcm) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ ++ if (cl - 1 > q->bands) ++ return -ENOENT; ++ tcm->tcm_handle |= TC_H_MIN(cl); ++ if (q->queues[cl-1]) ++ tcm->tcm_info = q->queues[cl-1]->handle; ++ return 0; ++} ++ ++static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl, ++ struct gnet_dump *d) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ struct Qdisc *cl_q; ++ ++ cl_q = q->queues[cl - 1]; ++ if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 || ++ gnet_stats_copy_queue(d, &cl_q->qstats) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static void multiq_walk(struct Qdisc *sch, struct qdisc_walker *arg) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ int band; ++ ++ if (arg->stop) ++ return; ++ ++ for (band = 0; band < q->bands; band++) { ++ if (arg->count < arg->skip) { ++ arg->count++; ++ continue; ++ } ++ if (arg->fn(sch, band+1, arg) < 0) { ++ arg->stop = 1; ++ break; ++ } ++ arg->count++; ++ } ++} ++ ++static struct tcf_proto **multiq_find_tcf(struct Qdisc *sch, unsigned long cl) ++{ ++ struct multiq_sched_data *q = qdisc_priv(sch); ++ ++ if (cl) ++ return NULL; ++ return &q->filter_list; ++} ++ ++static const struct Qdisc_class_ops multiq_class_ops = { ++ .graft = multiq_graft, ++ .leaf = multiq_leaf, ++ .get = multiq_get, ++ .put = multiq_put, ++ .change = multiq_change, ++ .delete = multiq_delete, ++ .walk = multiq_walk, ++ .tcf_chain = multiq_find_tcf, ++ .bind_tcf = multiq_bind, ++ .unbind_tcf = multiq_put, ++ .dump = multiq_dump_class, ++ .dump_stats = multiq_dump_class_stats, ++}; ++ ++static struct Qdisc_ops multiq_qdisc_ops __read_mostly = { ++ .next = NULL, ++ .cl_ops = &multiq_class_ops, ++ .id = "multiq", ++ .priv_size = sizeof(struct multiq_sched_data), ++ .enqueue = multiq_enqueue, ++ .dequeue = multiq_dequeue, ++ .requeue = multiq_requeue, ++ .drop = multiq_drop, ++ .init = multiq_init, ++ .reset = multiq_reset, ++ .destroy = multiq_destroy, ++ .change = multiq_tune, ++ .dump = multiq_dump, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init multiq_module_init(void) ++{ ++ return register_qdisc(&multiq_qdisc_ops); ++} ++ ++static void __exit multiq_module_exit(void) ++{ ++ unregister_qdisc(&multiq_qdisc_ops); ++} ++ ++module_init(multiq_module_init) ++module_exit(multiq_module_exit) ++ ++MODULE_LICENSE("GPL"); +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/ptrace-getsiginfo b/src/patches/suse-2.6.27.31/patches.fixes/ptrace-getsiginfo new file mode 100644 index 000000000..a913c4fb6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/ptrace-getsiginfo @@ -0,0 +1,78 @@ +From: Andreas Schwab +Subject: Add compat handler for PTRACE_GETSIGINFO + +Current versions of gdb require a working implementation of +PTRACE_GETSIGINFO for proper watchpoint support. Since struct siginfo +contains pointers it must be converted when passed to a 32-bit debugger. + +Signed-off-by: Andreas Schwab +--- + arch/powerpc/kernel/ppc32.h | 2 ++ + arch/powerpc/kernel/ptrace32.c | 27 +++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +--- a/arch/powerpc/kernel/ppc32.h ++++ b/arch/powerpc/kernel/ppc32.h +@@ -136,4 +136,6 @@ struct ucontext32 { + struct mcontext32 uc_mcontext; + }; + ++extern int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s); ++ + #endif /* _PPC64_PPC32_H */ +--- a/arch/powerpc/kernel/ptrace32.c ++++ b/arch/powerpc/kernel/ptrace32.c +@@ -29,12 +29,15 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include + ++#include "ppc32.h" ++ + /* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. +@@ -69,6 +72,27 @@ static long compat_ptrace_old(struct tas + #define FPRHALF(i) (((i) - PT_FPR0) & 1) + #define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) + FPRHALF(i) + ++static int compat_ptrace_getsiginfo(struct task_struct *child, compat_siginfo_t __user *data) ++{ ++ siginfo_t lastinfo; ++ int error = -ESRCH; ++ ++ read_lock(&tasklist_lock); ++ if (likely(child->sighand != NULL)) { ++ error = -EINVAL; ++ spin_lock_irq(&child->sighand->siglock); ++ if (likely(child->last_siginfo != NULL)) { ++ lastinfo = *child->last_siginfo; ++ error = 0; ++ } ++ spin_unlock_irq(&child->sighand->siglock); ++ } ++ read_unlock(&tasklist_lock); ++ if (!error) ++ return copy_siginfo_to_user32(data, &lastinfo); ++ return error; ++} ++ + long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + compat_ulong_t caddr, compat_ulong_t cdata) + { +@@ -290,6 +314,9 @@ long compat_arch_ptrace(struct task_stru + 0, PT_REGS_COUNT * sizeof(compat_long_t), + compat_ptr(data)); + ++ case PTRACE_GETSIGINFO: ++ return compat_ptrace_getsiginfo(child, compat_ptr(data)); ++ + case PTRACE_GETFPREGS: + case PTRACE_SETFPREGS: + case PTRACE_GETVRREGS: diff --git a/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-check-fc-rport-validity b/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-check-fc-rport-validity new file mode 100644 index 000000000..c58e3ef93 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-check-fc-rport-validity @@ -0,0 +1,51 @@ +From 159c5e2fff12fc75220597fa2434ab0d0c07b337 Mon Sep 17 00:00:00 2001 +From: Seokmann Ju +Date: Thu, 22 Jan 2009 10:25:39 -0800 +Subject: [PATCH] qla2xxx: added to check fcport is valid in qla2x00_terminate_rport_io(). +References: bnc#467624 + +As to follow the recent changes in FC transport layer, qla2xxx module +added a checker to make sure that fcport is being accessed is valid. +- qla2x00_dev_loss_tmo_callbk() +- qla2x00_terminate_rport_io() +Following is SHA # for the FC transport layer changes, +[SCSI] fc transport: pre-emptively terminate i/o upon dev_loss_tmo timeout +(f78badb1ae07e7f8b835ab2ea0b456ed3fc4caf4) +With the FC transport layer change, there is a possibility for qla2xxx +module to take both dev_loss_tmo_callbk() and terminate_rport_io() repeatedly +for a fcport, so that the checker is needed to make sure that the module +won't access fcport if it has done so. + +Signed-off-by: Seokmann Ju +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/qla2xxx/qla_attr.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c +index 6d5210e..34c4016 100644 +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -1284,6 +1284,9 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) + struct Scsi_Host *host = rport_to_shost(rport); + fc_port_t *fcport = *(fc_port_t **)rport->dd_data; + ++ if (!fcport) ++ return; ++ + qla2x00_abort_fcport_cmds(fcport); + + /* +@@ -1301,6 +1304,9 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) + { + fc_port_t *fcport = *(fc_port_t **)rport->dd_data; + ++ if (!fcport) ++ return; ++ + /* + * At this point all fcport's software-states are cleared. Perform any + * final cleanup of firmware resources (PCBs and XCBs). +-- +1.6.0 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-devtbl-fix b/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-devtbl-fix new file mode 100644 index 000000000..0a0735c22 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-devtbl-fix @@ -0,0 +1,23 @@ +From: Shyam Iyer +Subject: Kernel Panic with Qlogic 2472 Card +References: bnc#472804 + +Kernel Panic is observed with a Qlogic 2472 Card is plugged into the +system and the qla2xxx driver is loaded. + +The attached patch fixes the issue. + +Signed-off-by: Shyam Iyer +Signed-off-by: Hannes Reinecke + +--- linux-2.6.27-SLE11_BRANCH/drivers/scsi/qla2xxx/qla_devtbl.h.orig 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/drivers/scsi/qla2xxx/qla_devtbl.h 2009-02-06 14:25:39.014539019 +0100 +@@ -72,7 +72,7 @@ static char *qla2x00_model_name[QLA_MODE + "QLA2462", "Sun PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x141 */ + "QLE2460", "Sun PCI-Express to 2Gb FC, Single Channel", /* 0x142 */ + "QLE2462", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x143 */ +- "QEM2462" "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */ ++ "QEM2462", "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */ + "QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */ + "QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */ + "QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-disable-automatic-queue-tracking b/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-disable-automatic-queue-tracking new file mode 100644 index 000000000..2974b8d5b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/qla2xxx-disable-automatic-queue-tracking @@ -0,0 +1,97 @@ +From: Mike Reed +Subject: qla2xxx: Conditionally disable queue_full tracking +References: bnc#449386 + +Changing a lun's queue depth (/sys/block/sdX/device/queue_depth) isn't +sticky when the device is connected via a QLogic fibre channel adapter. + +The QLogic qla2xxx fibre channel driver dynamically adjusts a lun's queue +depth. If a user has a specific need to limit the number of commands issued +to a lun (say a tape drive, or a shared raid where the total commands issued +to all luns is limited at the controller level, for example) and writes a +limiting value to /sys/block/sdXX/device/queue_depth, the qla2xxx driver will +silently and gradually increase the queue depth back to the driver limit +of ql2xmaxqdepth. While reducing this value (module parameter) or increasing +the interval between ramp ups (ql2xqfullrampup) offers the potential for a +work around it would be better to have the option of just disabling the +dynamic adjustment of queue depth. + +This patch implements an "off switch" as a module parameter. Applies to +2.6.28-rc6-git1. + +Signed-off-by: Michael Reed +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/qla2xxx/qla_gbl.h | 1 + + drivers/scsi/qla2xxx/qla_isr.c | 10 ++++++++++ + drivers/scsi/qla2xxx/qla_os.c | 8 ++++++++ + 3 files changed, 19 insertions(+) + +--- a/drivers/scsi/qla2xxx/qla_gbl.h ++++ b/drivers/scsi/qla2xxx/qla_gbl.h +@@ -63,6 +63,7 @@ extern int ql2xallocfwdump; + extern int ql2xextended_error_logging; + extern int ql2xqfullrampup; + extern int ql2xiidmaenable; ++extern int ql2xqfulltracking; + + extern int qla2x00_loop_reset(scsi_qla_host_t *); + extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); +--- a/drivers/scsi/qla2xxx/qla_isr.c ++++ b/drivers/scsi/qla2xxx/qla_isr.c +@@ -691,6 +691,9 @@ qla2x00_adjust_sdev_qdepth_up(struct scs + { + fc_port_t *fcport = data; + ++ if (!ql2xqfulltracking) ++ return; ++ + if (fcport->ha->max_q_depth <= sdev->queue_depth) + return; + +@@ -729,6 +732,9 @@ qla2x00_ramp_up_queue_depth(scsi_qla_hos + fc_port_t *fcport; + struct scsi_device *sdev; + ++ if (!ql2xqfulltracking) ++ return; ++ + sdev = sp->cmd->device; + if (sdev->queue_depth >= ha->max_q_depth) + return; +@@ -1043,6 +1049,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha + scsi_status)); + + /* Adjust queue depth for all luns on the port. */ ++ if (!ql2xqfulltracking) ++ break; + fcport->last_queue_full = jiffies; + starget_for_each_device(cp->device->sdev_target, + fcport, qla2x00_adjust_sdev_qdepth_down); +@@ -1102,6 +1110,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha + * Adjust queue depth for all luns on the + * port. + */ ++ if (!ql2xqfulltracking) ++ break; + fcport->last_queue_full = jiffies; + starget_for_each_device( + cp->device->sdev_target, fcport, +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -79,6 +79,14 @@ module_param(ql2xmaxqdepth, int, S_IRUGO + MODULE_PARM_DESC(ql2xmaxqdepth, + "Maximum queue depth to report for target devices."); + ++int ql2xqfulltracking = 1; ++module_param(ql2xqfulltracking, int, S_IRUGO|S_IWUSR); ++MODULE_PARM_DESC(ql2xqfulltracking, ++ "Controls whether the driver tracks queue full status " ++ "returns and dynamically adjusts a scsi device's queue " ++ "depth. Default is 1, perform tracking. Set to 0 to " ++ "disable dynamic tracking and adjustment of queue depth."); ++ + int ql2xqfullrampup = 120; + module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR); + MODULE_PARM_DESC(ql2xqfullrampup, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-commit-ids-unsigned-ints b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-commit-ids-unsigned-ints new file mode 100644 index 000000000..49e38a909 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-commit-ids-unsigned-ints @@ -0,0 +1,283 @@ +From: Jeff Mahoney +Subject: [PATCH] reiserfs: audit transaction ids to always be unsigned ints +References: bnc#410847 + + This patch fixes up the reiserfs code such that transaction ids are + always unsigned ints. In places they can currently be signed ints or + unsigned longs. + + The former just causes an annoying clm-2200 warning and may join a + transaction when it should wait. + + The latter is just for correctness since the disk format uses a 32-bit + transaction id. There aren't any runtime problems that result from it + not wrapping at the correct location since the value is truncated + correctly even on big endian systems. The 0 value might make it to disk, + but the mount-time checks will bump it to 10 itself. + +Signed-off-by: Jeff Mahoney + +--- + fs/reiserfs/journal.c | 46 ++++++++++++++++++++--------------------- + fs/reiserfs/procfs.c | 4 +-- + include/linux/reiserfs_fs.h | 2 - + include/linux/reiserfs_fs_i.h | 2 - + include/linux/reiserfs_fs_sb.h | 8 +++---- + 5 files changed, 31 insertions(+), 31 deletions(-) + +--- a/fs/reiserfs/journal.c ++++ b/fs/reiserfs/journal.c +@@ -574,7 +574,7 @@ static inline void put_journal_list(stru + struct reiserfs_journal_list *jl) + { + if (jl->j_refcount < 1) { +- reiserfs_panic(s, "trans id %lu, refcount at %d", ++ reiserfs_panic(s, "trans id %u, refcount at %d", + jl->j_trans_id, jl->j_refcount); + } + if (--jl->j_refcount == 0) +@@ -599,7 +599,7 @@ static void cleanup_freed_for_journal_li + } + + static int journal_list_still_alive(struct super_block *s, +- unsigned long trans_id) ++ unsigned int trans_id) + { + struct reiserfs_journal *journal = SB_JOURNAL(s); + struct list_head *entry = &journal->j_journal_list; +@@ -933,9 +933,9 @@ static int flush_older_commits(struct su + struct reiserfs_journal_list *other_jl; + struct reiserfs_journal_list *first_jl; + struct list_head *entry; +- unsigned long trans_id = jl->j_trans_id; +- unsigned long other_trans_id; +- unsigned long first_trans_id; ++ unsigned int trans_id = jl->j_trans_id; ++ unsigned int other_trans_id; ++ unsigned int first_trans_id; + + find_first: + /* +@@ -1014,7 +1014,7 @@ static int flush_commit_list(struct supe + int i; + b_blocknr_t bn; + struct buffer_head *tbh = NULL; +- unsigned long trans_id = jl->j_trans_id; ++ unsigned int trans_id = jl->j_trans_id; + struct reiserfs_journal *journal = SB_JOURNAL(s); + int barrier = 0; + int retval = 0; +@@ -1275,7 +1275,7 @@ static void remove_all_from_journal_list + */ + static int _update_journal_header_block(struct super_block *p_s_sb, + unsigned long offset, +- unsigned long trans_id) ++ unsigned int trans_id) + { + struct reiserfs_journal_header *jh; + struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); +@@ -1329,7 +1329,7 @@ static int _update_journal_header_block( + + static int update_journal_header_block(struct super_block *p_s_sb, + unsigned long offset, +- unsigned long trans_id) ++ unsigned int trans_id) + { + return _update_journal_header_block(p_s_sb, offset, trans_id); + } +@@ -1344,7 +1344,7 @@ static int flush_older_journal_lists(str + struct list_head *entry; + struct reiserfs_journal_list *other_jl; + struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); +- unsigned long trans_id = jl->j_trans_id; ++ unsigned int trans_id = jl->j_trans_id; + + /* we know we are the only ones flushing things, no extra race + * protection is required. +@@ -1758,13 +1758,13 @@ static int dirty_one_transaction(struct + static int kupdate_transactions(struct super_block *s, + struct reiserfs_journal_list *jl, + struct reiserfs_journal_list **next_jl, +- unsigned long *next_trans_id, ++ unsigned int *next_trans_id, + int num_blocks, int num_trans) + { + int ret = 0; + int written = 0; + int transactions_flushed = 0; +- unsigned long orig_trans_id = jl->j_trans_id; ++ unsigned int orig_trans_id = jl->j_trans_id; + struct buffer_chunk chunk; + struct list_head *entry; + struct reiserfs_journal *journal = SB_JOURNAL(s); +@@ -1833,7 +1833,7 @@ static int flush_used_journal_lists(stru + int limit = 256; + struct reiserfs_journal_list *tjl; + struct reiserfs_journal_list *flush_jl; +- unsigned long trans_id; ++ unsigned int trans_id; + struct reiserfs_journal *journal = SB_JOURNAL(s); + + flush_jl = tjl = jl; +@@ -2023,7 +2023,7 @@ static int journal_compare_desc_commit(s + */ + static int journal_transaction_is_valid(struct super_block *p_s_sb, + struct buffer_head *d_bh, +- unsigned long *oldest_invalid_trans_id, ++ unsigned int *oldest_invalid_trans_id, + unsigned long *newest_mount_id) + { + struct reiserfs_journal_desc *desc; +@@ -2124,18 +2124,18 @@ static void brelse_array(struct buffer_h + static int journal_read_transaction(struct super_block *p_s_sb, + unsigned long cur_dblock, + unsigned long oldest_start, +- unsigned long oldest_trans_id, ++ unsigned int oldest_trans_id, + unsigned long newest_mount_id) + { + struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal_desc *desc; + struct reiserfs_journal_commit *commit; +- unsigned long trans_id = 0; ++ unsigned int trans_id = 0; + struct buffer_head *c_bh; + struct buffer_head *d_bh; + struct buffer_head **log_blocks = NULL; + struct buffer_head **real_blocks = NULL; +- unsigned long trans_offset; ++ unsigned int trans_offset; + int i; + int trans_half; + +@@ -2356,8 +2356,8 @@ static int journal_read(struct super_blo + { + struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal_desc *desc; +- unsigned long oldest_trans_id = 0; +- unsigned long oldest_invalid_trans_id = 0; ++ unsigned int oldest_trans_id = 0; ++ unsigned int oldest_invalid_trans_id = 0; + time_t start; + unsigned long oldest_start = 0; + unsigned long cur_dblock = 0; +@@ -2967,7 +2967,7 @@ static void wake_queued_writers(struct s + wake_up(&journal->j_join_wait); + } + +-static void let_transaction_grow(struct super_block *sb, unsigned long trans_id) ++static void let_transaction_grow(struct super_block *sb, unsigned int trans_id) + { + struct reiserfs_journal *journal = SB_JOURNAL(sb); + unsigned long bcount = journal->j_bcount; +@@ -2998,7 +2998,7 @@ static int do_journal_begin_r(struct rei + int join) + { + time_t now = get_seconds(); +- int old_trans_id; ++ unsigned int old_trans_id; + struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_transaction_handle myth; + int sched_count = 0; +@@ -3821,7 +3821,7 @@ static int __commit_trans_jl(struct inod + + int reiserfs_commit_for_inode(struct inode *inode) + { +- unsigned long id = REISERFS_I(inode)->i_trans_id; ++ unsigned int id = REISERFS_I(inode)->i_trans_id; + struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl; + + /* for the whole inode, assume unset id means it was +@@ -3935,7 +3935,7 @@ static int do_journal_end(struct reiserf + struct reiserfs_journal_list *jl, *temp_jl; + struct list_head *entry, *safe; + unsigned long jindex; +- unsigned long commit_trans_id; ++ unsigned int commit_trans_id; + int trans_half; + + BUG_ON(th->t_refcount > 1); +@@ -3943,7 +3943,7 @@ static int do_journal_end(struct reiserf + + /* protect flush_older_commits from doing mistakes if the + transaction ID counter gets overflowed. */ +- if (th->t_trans_id == ~0UL) ++ if (th->t_trans_id == ~0U) + flags |= FLUSH_ALL | COMMIT_NOW | WAIT; + flush = flags & FLUSH_ALL; + wait_on_commit = flags & WAIT; +--- a/fs/reiserfs/procfs.c ++++ b/fs/reiserfs/procfs.c +@@ -323,7 +323,7 @@ static int show_journal(struct seq_file + /* incore fields */ + "j_1st_reserved_block: \t%i\n" + "j_state: \t%li\n" +- "j_trans_id: \t%lu\n" ++ "j_trans_id: \t%u\n" + "j_mount_id: \t%lu\n" + "j_start: \t%lu\n" + "j_len: \t%lu\n" +@@ -331,7 +331,7 @@ static int show_journal(struct seq_file + "j_wcount: \t%i\n" + "j_bcount: \t%lu\n" + "j_first_unflushed_offset: \t%lu\n" +- "j_last_flush_trans_id: \t%lu\n" ++ "j_last_flush_trans_id: \t%u\n" + "j_trans_start_time: \t%li\n" + "j_list_bitmap_index: \t%i\n" + "j_must_wait: \t%i\n" +--- a/include/linux/reiserfs_fs.h ++++ b/include/linux/reiserfs_fs.h +@@ -1676,7 +1676,7 @@ struct reiserfs_transaction_handle { + int t_refcount; + int t_blocks_logged; /* number of blocks this writer has logged */ + int t_blocks_allocated; /* number of blocks this writer allocated */ +- unsigned long t_trans_id; /* sanity check, equals the current trans id */ ++ unsigned int t_trans_id; /* sanity check, equals the current trans id */ + void *t_handle_save; /* save existing current->journal_info */ + unsigned displace_new_blocks:1; /* if new block allocation occurres, that block + should be displaced from others */ +--- a/include/linux/reiserfs_fs_i.h ++++ b/include/linux/reiserfs_fs_i.h +@@ -51,7 +51,7 @@ struct reiserfs_inode_info { + /* we use these for fsync or O_SYNC to decide which transaction + ** needs to be committed in order for this inode to be properly + ** flushed */ +- unsigned long i_trans_id; ++ unsigned int i_trans_id; + struct reiserfs_journal_list *i_jl; + struct mutex i_mmap; + #ifdef CONFIG_REISERFS_FS_POSIX_ACL +--- a/include/linux/reiserfs_fs_sb.h ++++ b/include/linux/reiserfs_fs_sb.h +@@ -156,7 +156,7 @@ struct reiserfs_journal_list { + atomic_t j_commit_left; + atomic_t j_older_commits_done; /* all commits older than this on disk */ + struct mutex j_commit_mutex; +- unsigned long j_trans_id; ++ unsigned int j_trans_id; + time_t j_timestamp; + struct reiserfs_list_bitmap *j_list_bitmap; + struct buffer_head *j_commit_bh; /* commit buffer head */ +@@ -184,7 +184,7 @@ struct reiserfs_journal { + int j_1st_reserved_block; /* first block on s_dev of reserved area journal */ + + unsigned long j_state; +- unsigned long j_trans_id; ++ unsigned int j_trans_id; + unsigned long j_mount_id; + unsigned long j_start; /* start of current waiting commit (index into j_ap_blocks) */ + unsigned long j_len; /* length of current waiting commit */ +@@ -225,10 +225,10 @@ struct reiserfs_journal { + int j_num_work_lists; /* number that need attention from kreiserfsd */ + + /* debugging to make sure things are flushed in order */ +- int j_last_flush_id; ++ unsigned int j_last_flush_id; + + /* debugging to make sure things are committed in order */ +- int j_last_commit_id; ++ unsigned int j_last_commit_id; + + struct list_head j_bitmap_nodes; + struct list_head j_dirty_buffers; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-debug-1036 b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-debug-1036 new file mode 100644 index 000000000..f7204ef45 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-debug-1036 @@ -0,0 +1,139 @@ +From: Jeff Mahoney +Subject: [PATCH] reiserfs: print more information when an empty journal list is encountered +References: bnc#447406 bnc#399966 +Patch-mainline: Never + + BNC#447406 describes a BUG() at fs/reiserfs/journal.c:1036. This patch + dumps more information regarding the state of the list before failing. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/journal.c | 21 ++++++++++++++++++++- + fs/reiserfs/prints.c | 22 +++++++++++++++++++++- + include/linux/reiserfs_fs_sb.h | 6 ++++++ + 3 files changed, 47 insertions(+), 2 deletions(-) + +--- a/fs/reiserfs/journal.c ++++ b/fs/reiserfs/journal.c +@@ -82,6 +82,8 @@ static struct workqueue_struct *commit_w + #define LIST_TOUCHED 1 + #define LIST_DIRTY 2 + #define LIST_COMMIT_PENDING 4 /* someone will commit this list */ ++#define LIST_DEAD 8 ++#define LIST_CURRENT 16 + + /* flags for do_journal_end */ + #define FLUSH_ALL 1 /* flush commit and real blocks */ +@@ -1031,6 +1033,14 @@ static int flush_commit_list(struct supe + /* before we can put our commit blocks on disk, we have to make sure everyone older than + ** us is on disk too + */ ++ if (jl->j_len <= 0) { ++ reiserfs_warning(s, "journal-d1", "%j; " ++ "trans_id = %u; " ++ "journal->trans_id = %u; " ++ "oldest live jl->j_trans_id = %u\n", ++ jl, trans_id, journal->j_trans_id, ++ JOURNAL_LIST_ENTRY(journal->j_journal_list.next)->j_trans_id); ++ } + BUG_ON(jl->j_len <= 0); + BUG_ON(trans_id == journal->j_trans_id); + +@@ -1636,7 +1646,7 @@ static int flush_journal_list(struct sup + jl->j_realblock = NULL; + jl->j_commit_bh = NULL; + jl->j_trans_id = 0; +- jl->j_state = 0; ++ jl->j_state = LIST_DEAD; + put_journal_list(s, jl); + if (flushall) + mutex_unlock(&journal->j_flush_mutex); +@@ -2561,6 +2571,12 @@ static struct reiserfs_journal_list *all + INIT_LIST_HEAD(&jl->j_bh_list); + mutex_init(&jl->j_commit_mutex); + SB_JOURNAL(s)->j_num_lists++; ++ jl->j_magic1 = 0xa5a5a5a5; ++ jl->j_magic2 = 0xb4b4b4b4; ++ jl->j_magic3 = 0xc3c3c3c3; ++ jl->j_magic4 = 0xd2d2d2d2; ++ jl->j_magic5 = 0xe1e1e1e1; ++ jl->j_magic6 = 0x96969696; + get_journal_list(jl); + return jl; + } +@@ -2824,6 +2840,7 @@ int journal_init(struct super_block *sb, + + journal->j_list_bitmap_index = 0; + journal_list_init(sb); ++ journal->j_current_jl->j_state |= LIST_CURRENT; + + memset(journal->j_list_hash_table, 0, + JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)); +@@ -4162,6 +4179,8 @@ static int do_journal_end(struct reiserf + */ + + journal->j_current_jl = alloc_journal_list(sb); ++ journal->j_current_jl->j_state |= LIST_CURRENT; ++ jl->j_state &= LIST_CURRENT; + + /* now it is safe to insert this transaction on the main list */ + list_add_tail(&jl->j_list, &journal->j_journal_list); +--- a/fs/reiserfs/prints.c ++++ b/fs/reiserfs/prints.c +@@ -157,13 +157,28 @@ static void sprintf_disk_child(char *buf + dc_size(dc)); + } + ++static void sprintf_journal_list(char *buf, struct reiserfs_journal_list *jl) ++{ ++ sprintf(buf, "[j_start=%lu, j_state=%lu, j_len=%lu, j_nonzerolen=%d, " ++ "j_commit_left=%u, j_older_commits_done=%u, j_trans_id=%u, " ++ "j_timestamp=%ld, j_refcount=%d (%08x%08x%08x%08x%08x%08x)]", ++ jl->j_start, jl->j_state, jl->j_len, ++ atomic_read(&jl->j_nonzerolen), ++ atomic_read(&jl->j_commit_left), ++ atomic_read(&jl->j_older_commits_done), ++ jl->j_trans_id, jl->j_timestamp, jl->j_refcount, ++ jl->j_magic1, jl->j_magic2, jl->j_magic3, jl->j_magic4, ++ jl->j_magic5, jl->j_magic6); ++} ++ + static char *is_there_reiserfs_struct(char *fmt, int *what) + { + char *k = fmt; + + while ((k = strchr(k, '%')) != NULL) { + if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' || +- k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') { ++ k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a' || ++ k[1] == 'j') { + *what = k[1]; + break; + } +@@ -233,6 +248,11 @@ static void prepare_error_buf(const char + va_arg(args, + struct reiserfs_de_head *)); + break; ++ case 'j': ++ sprintf_journal_list(p, ++ va_arg(args, ++ struct reiserfs_journal_list *)); ++ break; + } + + p += strlen(p); +--- a/include/linux/reiserfs_fs_sb.h ++++ b/include/linux/reiserfs_fs_sb.h +@@ -149,6 +149,12 @@ struct reiserfs_list_bitmap { + ** and to make sure every real block in a transaction is on disk before allowing the log area + ** to be overwritten */ + struct reiserfs_journal_list { ++ unsigned int j_magic1; ++ unsigned int j_magic2; ++ unsigned int j_magic3; ++ unsigned int j_magic4; ++ unsigned int j_magic5; ++ unsigned int j_magic6; + unsigned long j_start; + unsigned long j_state; + unsigned long j_len; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-error-buffer-locking b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-error-buffer-locking new file mode 100644 index 000000000..d82714d6a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-error-buffer-locking @@ -0,0 +1,41 @@ +From: Jeff Mahoney +Subject: [PATCH] reiserfs: add locking around error buffer + + The formatting of the error buffer is race prone. It uses static buffers + for both formatting and output. While overwriting the error buffer + can product garbled output, overwriting the format buffer with incompatible + % directives can cause crashes. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/prints.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/reiserfs/prints.c ++++ b/fs/reiserfs/prints.c +@@ -184,7 +184,7 @@ static char *is_there_reiserfs_struct(ch + printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid, + key->k_offset, key->k_uniqueness); + */ +- ++static DEFINE_SPINLOCK(error_lock); + static void prepare_error_buf(const char *fmt, va_list args) + { + char *fmt1 = fmt_buf; +@@ -192,6 +192,8 @@ static void prepare_error_buf(const char + char *p = error_buf; + int what; + ++ spin_lock(&error_lock); ++ + strcpy(fmt1, fmt); + + while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) { +@@ -237,6 +239,7 @@ static void prepare_error_buf(const char + fmt1 = k + 2; + } + vsprintf(p, fmt1, args); ++ spin_unlock(&error_lock); + + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-prealloc-fix b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-prealloc-fix new file mode 100644 index 000000000..db84455e5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-prealloc-fix @@ -0,0 +1,47 @@ +From: Jeff Mahoney +Subject: [PATCH] reiserfs: Use list_del_init in use_preallocated_list_if_available +References: bnc#378095 + + __discard_prealloc() calls list_del on ei->i_prealloc_list regardless of + the state of ei->i_prealloc_count. The rest of the action in that function + is safe regardless of if the list is empty or not. + + If the list hasn't been used, then i_prealloc_list will be just initialized. + If it has, and use_preallocated_list_if_available() has been called, and + the prealloc list has been depleted, then the list entry will be poisoned. + + This patch uses list_del_init so the list_head is initialized and we don't + oops on the poisoned value. + +Signed-off-by: Jeff Mahoney + +--- + fs/reiserfs/bitmap.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/fs/reiserfs/bitmap.c ++++ b/fs/reiserfs/bitmap.c +@@ -1145,17 +1145,18 @@ static int use_preallocated_list_if_avai + int amount_needed) + { + struct inode *inode = hint->inode; ++ struct reiserfs_inode_info *ei = REISERFS_I(inode); + +- if (REISERFS_I(inode)->i_prealloc_count > 0) { ++ if (ei->i_prealloc_count > 0) { + while (amount_needed) { + +- *new_blocknrs++ = REISERFS_I(inode)->i_prealloc_block++; +- REISERFS_I(inode)->i_prealloc_count--; ++ *new_blocknrs++ = ei->i_prealloc_block++; ++ ei->i_prealloc_count--; + + amount_needed--; + +- if (REISERFS_I(inode)->i_prealloc_count <= 0) { +- list_del(&REISERFS_I(inode)->i_prealloc_list); ++ if (ei->i_prealloc_count <= 0) { ++ list_del_init(&ei->i_prealloc_list); + break; + } + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-varargs-fix b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-varargs-fix new file mode 100644 index 000000000..4edd5789d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/reiserfs-varargs-fix @@ -0,0 +1,60 @@ +From: Jeff Mahoney +Subject: [PATCH] reiserfs: prepare_error_buf wrongly consumes va_arg + + vsprintf will consume varargs on its own. Skipping them manually + results in garbage in the error buffer, or Oopses in the case of + pointers. + + This patch removes the advancement and fixes a number of bugs where + crashes were observed as side effects of a regular error report. + +Signed-off-by: Jeff Mahoney +--- + + fs/reiserfs/prints.c | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +--- a/fs/reiserfs/prints.c ++++ b/fs/reiserfs/prints.c +@@ -157,19 +157,16 @@ static void sprintf_disk_child(char *buf + dc_size(dc)); + } + +-static char *is_there_reiserfs_struct(char *fmt, int *what, int *skip) ++static char *is_there_reiserfs_struct(char *fmt, int *what) + { + char *k = fmt; + +- *skip = 0; +- + while ((k = strchr(k, '%')) != NULL) { + if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' || + k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') { + *what = k[1]; + break; + } +- (*skip)++; + k++; + } + return k; +@@ -193,18 +190,15 @@ static void prepare_error_buf(const char + char *fmt1 = fmt_buf; + char *k; + char *p = error_buf; +- int i, j, what, skip; ++ int what; + + strcpy(fmt1, fmt); + +- while ((k = is_there_reiserfs_struct(fmt1, &what, &skip)) != NULL) { ++ while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) { + *k = 0; + + p += vsprintf(p, fmt1, args); + +- for (i = 0; i < skip; i++) +- j = va_arg(args, int); +- + switch (what) { + case 'k': + sprintf_le_key(p, va_arg(args, struct reiserfs_key *)); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/remount-no-shrink-dcache b/src/patches/suse-2.6.27.31/patches.fixes/remount-no-shrink-dcache new file mode 100644 index 000000000..555b59a3c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/remount-no-shrink-dcache @@ -0,0 +1,85 @@ +From: Olaf Kirch +Subject: Do not call shrink_dcache_sb when remounting procfs etc +References: 165672 + +Avoid calls to shrink_dcache_sb when mounting a file system that +uses get_sb_single. shrink_dcache_sb is costly. On large ia64 +systems, this will keep the dcache lock for > 60 seconds at +a stretch. + +Signed-off-by: Olaf Kirch + + fs/super.c | 36 +++++++++++++++++++++++------------- + 1 file changed, 23 insertions(+), 13 deletions(-) + +--- a/fs/super.c ++++ b/fs/super.c +@@ -597,16 +597,10 @@ retry: + file_list_unlock(); + } + +-/** +- * do_remount_sb - asks filesystem to change mount options. +- * @sb: superblock in question +- * @flags: numeric part of options +- * @data: the rest of options +- * @force: whether or not to force the change +- * +- * Alters the mount options of a mounted file system. +- */ +-int do_remount_sb(struct super_block *sb, int flags, void *data, int force) ++#define REMOUNT_FORCE 1 ++#define REMOUNT_SHRINK_DCACHE 2 ++ ++static int __do_remount_sb(struct super_block *sb, int flags, void *data, int rflags) + { + int retval; + int remount_rw; +@@ -617,13 +611,14 @@ int do_remount_sb(struct super_block *sb + #endif + if (flags & MS_RDONLY) + acct_auto_close(sb); +- shrink_dcache_sb(sb); ++ if (rflags & REMOUNT_SHRINK_DCACHE) ++ shrink_dcache_sb(sb); + fsync_super(sb); + + /* If we are remounting RDONLY and current sb is read/write, + make sure there are no rw files opened */ + if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { +- if (force) ++ if (rflags & REMOUNT_FORCE) + mark_files_ro(sb); + else if (!fs_may_remount_ro(sb)) + return -EBUSY; +@@ -646,6 +641,21 @@ int do_remount_sb(struct super_block *sb + return 0; + } + ++/** ++ * do_remount_sb - asks filesystem to change mount options. ++ * @sb: superblock in question ++ * @flags: numeric part of options ++ * @data: the rest of options ++ * @force: whether or not to force the change ++ * ++ * Alters the mount options of a mounted file system. ++ */ ++int do_remount_sb(struct super_block *sb, int flags, void *data, int force) ++{ ++ return __do_remount_sb(sb, flags, data, ++ REMOUNT_SHRINK_DCACHE|(force? REMOUNT_FORCE : 0)); ++} ++ + static void do_emergency_remount(unsigned long foo) + { + struct super_block *sb; +@@ -877,7 +887,7 @@ int get_sb_single(struct file_system_typ + } + s->s_flags |= MS_ACTIVE; + } +- do_remount_sb(s, flags, data, 0); ++ __do_remount_sb(s, flags, data, 0); + return simple_set_mnt(mnt, s); + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/remove_kernel_physical_mapping_init_from_init b/src/patches/suse-2.6.27.31/patches.fixes/remove_kernel_physical_mapping_init_from_init new file mode 100644 index 000000000..77612675a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/remove_kernel_physical_mapping_init_from_init @@ -0,0 +1,38 @@ +From: Gary Hade +Subject: move kernel_physical_mapping_init to __meminit +Patch-mainline: 2.6.29 (probably) +References: bnc#467474 + +kernel_physical_mapping_init() is called during memory hotplug +so it does not belong in the init section. + +If the kernel is built with CONFIG_DEBUG_SECTION_MISMATCH=y on +the make command line, arch/x86/mm/init_64.c is compiled with +the -fno-inline-functions-called-once gcc option defeating +inlining of kernel_physical_mapping_init() within init_memory_mapping(). +When kernel_physical_mapping_init() is not inlined it is placed +in the .init.text section according to the __init in it's current +declaration. A later call to kernel_physical_mapping_init() during +a memory hotplug operation encounters an int3 trap because the +.init.text section memory has been freed. This patch eliminates +the crash caused by the int3 trap by moving the non-inlined +kernel_physical_mapping_init() from .init.text to .meminit.text. + +Signed-off-by: Gary Hade +Acked-by: Jeff Mahoney +--- + + arch/x86/mm/init_64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -495,7 +495,7 @@ static void __init init_gbpages(void) + direct_gbpages = 0; + } + +-static unsigned long __init kernel_physical_mapping_init(unsigned long start, ++static unsigned long __meminit kernel_physical_mapping_init(unsigned long start, + unsigned long end, + unsigned long page_size_mask) + { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/round-jiffies-up b/src/patches/suse-2.6.27.31/patches.fixes/round-jiffies-up new file mode 100644 index 000000000..93622969d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/round-jiffies-up @@ -0,0 +1,207 @@ +Subject: Add round_jiffies_up and related routines +From: Alan Stern +Date: Thu Nov 6 08:42:48 2008 +0100: +Git: 9c133c469d38043d5aadaa03f2fb840d88d1cf4f +References: bnc#464155 + +This patch (as1158b) adds round_jiffies_up() and friends. These +routines work like the analogous round_jiffies() functions, except +that they will never round down. + +The new routines will be useful for timeouts where we don't care +exactly when the timer expires, provided it doesn't expire too soon. + +Signed-off-by: Alan Stern +Signed-off-by: Jens Axboe +Signed-off-by: Hannes Reinecke + +diff --git a/include/linux/timer.h b/include/linux/timer.h +index d4ba792..daf9685 100644 +--- a/include/linux/timer.h ++++ b/include/linux/timer.h +@@ -186,4 +186,9 @@ unsigned long __round_jiffies_relative(unsigned long j, int cpu); + unsigned long round_jiffies(unsigned long j); + unsigned long round_jiffies_relative(unsigned long j); + ++unsigned long __round_jiffies_up(unsigned long j, int cpu); ++unsigned long __round_jiffies_up_relative(unsigned long j, int cpu); ++unsigned long round_jiffies_up(unsigned long j); ++unsigned long round_jiffies_up_relative(unsigned long j); ++ + #endif +diff --git a/kernel/timer.c b/kernel/timer.c +index 56becf3..dbd50fa 100644 +--- a/kernel/timer.c ++++ b/kernel/timer.c +@@ -112,27 +112,8 @@ timer_set_base(struct timer_list *timer, struct tvec_base *new_base) + tbase_get_deferrable(timer->base)); + } + +-/** +- * __round_jiffies - function to round jiffies to a full second +- * @j: the time in (absolute) jiffies that should be rounded +- * @cpu: the processor number on which the timeout will happen +- * +- * __round_jiffies() rounds an absolute time in the future (in jiffies) +- * up or down to (approximately) full seconds. This is useful for timers +- * for which the exact time they fire does not matter too much, as long as +- * they fire approximately every X seconds. +- * +- * By rounding these timers to whole seconds, all such timers will fire +- * at the same time, rather than at various times spread out. The goal +- * of this is to have the CPU wake up less, which saves power. +- * +- * The exact rounding is skewed for each processor to avoid all +- * processors firing at the exact same time, which could lead +- * to lock contention or spurious cache line bouncing. +- * +- * The return value is the rounded version of the @j parameter. +- */ +-unsigned long __round_jiffies(unsigned long j, int cpu) ++static unsigned long round_jiffies_common(unsigned long j, int cpu, ++ bool force_up) + { + int rem; + unsigned long original = j; +@@ -154,8 +135,9 @@ unsigned long __round_jiffies(unsigned long j, int cpu) + * due to delays of the timer irq, long irq off times etc etc) then + * we should round down to the whole second, not up. Use 1/4th second + * as cutoff for this rounding as an extreme upper bound for this. ++ * But never round down if @force_up is set. + */ +- if (rem < HZ/4) /* round down */ ++ if (rem < HZ/4 && !force_up) /* round down */ + j = j - rem; + else /* round up */ + j = j - rem + HZ; +@@ -167,6 +149,31 @@ unsigned long __round_jiffies(unsigned long j, int cpu) + return original; + return j; + } ++ ++/** ++ * __round_jiffies - function to round jiffies to a full second ++ * @j: the time in (absolute) jiffies that should be rounded ++ * @cpu: the processor number on which the timeout will happen ++ * ++ * __round_jiffies() rounds an absolute time in the future (in jiffies) ++ * up or down to (approximately) full seconds. This is useful for timers ++ * for which the exact time they fire does not matter too much, as long as ++ * they fire approximately every X seconds. ++ * ++ * By rounding these timers to whole seconds, all such timers will fire ++ * at the same time, rather than at various times spread out. The goal ++ * of this is to have the CPU wake up less, which saves power. ++ * ++ * The exact rounding is skewed for each processor to avoid all ++ * processors firing at the exact same time, which could lead ++ * to lock contention or spurious cache line bouncing. ++ * ++ * The return value is the rounded version of the @j parameter. ++ */ ++unsigned long __round_jiffies(unsigned long j, int cpu) ++{ ++ return round_jiffies_common(j, cpu, false); ++} + EXPORT_SYMBOL_GPL(__round_jiffies); + + /** +@@ -191,13 +198,10 @@ EXPORT_SYMBOL_GPL(__round_jiffies); + */ + unsigned long __round_jiffies_relative(unsigned long j, int cpu) + { +- /* +- * In theory the following code can skip a jiffy in case jiffies +- * increments right between the addition and the later subtraction. +- * However since the entire point of this function is to use approximate +- * timeouts, it's entirely ok to not handle that. +- */ +- return __round_jiffies(j + jiffies, cpu) - jiffies; ++ unsigned long j0 = jiffies; ++ ++ /* Use j0 because jiffies might change while we run */ ++ return round_jiffies_common(j + j0, cpu, false) - j0; + } + EXPORT_SYMBOL_GPL(__round_jiffies_relative); + +@@ -218,7 +222,7 @@ EXPORT_SYMBOL_GPL(__round_jiffies_relative); + */ + unsigned long round_jiffies(unsigned long j) + { +- return __round_jiffies(j, raw_smp_processor_id()); ++ return round_jiffies_common(j, raw_smp_processor_id(), false); + } + EXPORT_SYMBOL_GPL(round_jiffies); + +@@ -243,6 +247,71 @@ unsigned long round_jiffies_relative(unsigned long j) + } + EXPORT_SYMBOL_GPL(round_jiffies_relative); + ++/** ++ * __round_jiffies_up - function to round jiffies up to a full second ++ * @j: the time in (absolute) jiffies that should be rounded ++ * @cpu: the processor number on which the timeout will happen ++ * ++ * This is the same as __round_jiffies() except that it will never ++ * round down. This is useful for timeouts for which the exact time ++ * of firing does not matter too much, as long as they don't fire too ++ * early. ++ */ ++unsigned long __round_jiffies_up(unsigned long j, int cpu) ++{ ++ return round_jiffies_common(j, cpu, true); ++} ++EXPORT_SYMBOL_GPL(__round_jiffies_up); ++ ++/** ++ * __round_jiffies_up_relative - function to round jiffies up to a full second ++ * @j: the time in (relative) jiffies that should be rounded ++ * @cpu: the processor number on which the timeout will happen ++ * ++ * This is the same as __round_jiffies_relative() except that it will never ++ * round down. This is useful for timeouts for which the exact time ++ * of firing does not matter too much, as long as they don't fire too ++ * early. ++ */ ++unsigned long __round_jiffies_up_relative(unsigned long j, int cpu) ++{ ++ unsigned long j0 = jiffies; ++ ++ /* Use j0 because jiffies might change while we run */ ++ return round_jiffies_common(j + j0, cpu, true) - j0; ++} ++EXPORT_SYMBOL_GPL(__round_jiffies_up_relative); ++ ++/** ++ * round_jiffies_up - function to round jiffies up to a full second ++ * @j: the time in (absolute) jiffies that should be rounded ++ * ++ * This is the same as round_jiffies() except that it will never ++ * round down. This is useful for timeouts for which the exact time ++ * of firing does not matter too much, as long as they don't fire too ++ * early. ++ */ ++unsigned long round_jiffies_up(unsigned long j) ++{ ++ return round_jiffies_common(j, raw_smp_processor_id(), true); ++} ++EXPORT_SYMBOL_GPL(round_jiffies_up); ++ ++/** ++ * round_jiffies_up_relative - function to round jiffies up to a full second ++ * @j: the time in (relative) jiffies that should be rounded ++ * ++ * This is the same as round_jiffies_relative() except that it will never ++ * round down. This is useful for timeouts for which the exact time ++ * of firing does not matter too much, as long as they don't fire too ++ * early. ++ */ ++unsigned long round_jiffies_up_relative(unsigned long j) ++{ ++ return __round_jiffies_up_relative(j, raw_smp_processor_id()); ++} ++EXPORT_SYMBOL_GPL(round_jiffies_up_relative); ++ + + static inline void set_running_timer(struct tvec_base *base, + struct timer_list *timer) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/rt2x00-fix-race-conditions.patch b/src/patches/suse-2.6.27.31/patches.fixes/rt2x00-fix-race-conditions.patch new file mode 100644 index 000000000..e50041faf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/rt2x00-fix-race-conditions.patch @@ -0,0 +1,570 @@ +From 0262ab0df64a67d4c0ed7577a29b7d866819cc68 Mon Sep 17 00:00:00 2001 +From: Ivo van Doorn +Date: Fri, 29 Aug 2008 21:04:26 +0200 +Subject: [PATCH] rt2x00: Fix race conditions in flag handling +Patch-mainline: 2.6.28-rc3 +References: bnc#462551 + +Some of the flags should be accessed atomically to +prevent race conditions. The flags that are most important +are those that can change often and indicate the actual +state of the device, queue or queue entry. + +The big flag rename was done to move all state flags to +the same naming type as the other rt2x00dev flags and +made sure all places where the flags were used were changed. ;) + +Thanks to Stephen for most of the queue flags updates, +which fixes some of the most obvious consequences of the +race conditions. Among those the notorious: + +rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. +rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. +rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. + +Signed-off-by: Stephen Blackheath +Signed-off-by: Ivo van Doorn +Signed-off-by: John W. Linville +Signed-off-by: Jiri Slaby +--- + drivers/net/wireless/rt2x00/rt2400pci.c | 2 - + drivers/net/wireless/rt2x00/rt2500pci.c | 2 - + drivers/net/wireless/rt2x00/rt2500usb.c | 2 - + drivers/net/wireless/rt2x00/rt2x00.h | 16 ++++---- + drivers/net/wireless/rt2x00/rt2x00config.c | 4 +- + drivers/net/wireless/rt2x00/rt2x00dev.c | 58 +++++++++++++++-------------- + drivers/net/wireless/rt2x00/rt2x00mac.c | 26 ++++++------- + drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +-- + drivers/net/wireless/rt2x00/rt2x00rfkill.c | 6 +-- + drivers/net/wireless/rt2x00/rt2x00usb.c | 10 ++--- + drivers/net/wireless/rt2x00/rt61pci.c | 2 - + 11 files changed, 68 insertions(+), 66 deletions(-) + +--- a/drivers/net/wireless/rt2x00/rt2400pci.c ++++ b/drivers/net/wireless/rt2x00/rt2400pci.c +@@ -1241,7 +1241,7 @@ static irqreturn_t rt2400pci_interrupt(i + if (!reg) + return IRQ_NONE; + +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* +--- a/drivers/net/wireless/rt2x00/rt2500pci.c ++++ b/drivers/net/wireless/rt2x00/rt2500pci.c +@@ -1377,7 +1377,7 @@ static irqreturn_t rt2500pci_interrupt(i + if (!reg) + return IRQ_NONE; + +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* +--- a/drivers/net/wireless/rt2x00/rt2500usb.c ++++ b/drivers/net/wireless/rt2x00/rt2500usb.c +@@ -1297,7 +1297,7 @@ static void rt2500usb_beacondone(struct + struct queue_entry *entry = (struct queue_entry *)urb->context; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; + +- if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) + return; + + /* +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -599,14 +599,14 @@ enum rt2x00_flags { + /* + * Device state flags + */ +- DEVICE_PRESENT, +- DEVICE_REGISTERED_HW, +- DEVICE_INITIALIZED, +- DEVICE_STARTED, +- DEVICE_STARTED_SUSPEND, +- DEVICE_ENABLED_RADIO, +- DEVICE_DISABLED_RADIO_HW, +- DEVICE_DIRTY_CONFIG, ++ DEVICE_STATE_PRESENT, ++ DEVICE_STATE_REGISTERED_HW, ++ DEVICE_STATE_INITIALIZED, ++ DEVICE_STATE_STARTED, ++ DEVICE_STATE_STARTED_SUSPEND, ++ DEVICE_STATE_ENABLED_RADIO, ++ DEVICE_STATE_DISABLED_RADIO_HW, ++ DEVICE_STATE_DIRTY_CONFIG, + + /* + * Driver features +--- a/drivers/net/wireless/rt2x00/rt2x00config.c ++++ b/drivers/net/wireless/rt2x00/rt2x00config.c +@@ -121,7 +121,7 @@ void rt2x00lib_config_antenna(struct rt2 + * Antenna setup changes require the RX to be disabled, + * else the changes will be ignored by the device. + */ +- if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); + + /* +@@ -136,7 +136,7 @@ void rt2x00lib_config_antenna(struct rt2 + rt2x00dev->link.ant.active.rx = libconf.ant.rx; + rt2x00dev->link.ant.active.tx = libconf.ant.tx; + +- if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); + } + +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -34,7 +34,7 @@ + */ + void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) + { +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + /* +@@ -94,8 +94,8 @@ int rt2x00lib_enable_radio(struct rt2x00 + * Don't enable the radio twice. + * And check if the hardware button has been disabled. + */ +- if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || +- test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || ++ test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags)) + return 0; + + /* +@@ -117,7 +117,7 @@ int rt2x00lib_enable_radio(struct rt2x00 + rt2x00leds_led_radio(rt2x00dev, true); + rt2x00led_led_activity(rt2x00dev, true); + +- __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); + + /* + * Enable RX. +@@ -134,7 +134,7 @@ int rt2x00lib_enable_radio(struct rt2x00 + + void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) + { +- if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_and_clear_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + /* +@@ -354,7 +354,7 @@ static void rt2x00lib_link_tuner(struct + * When the radio is shutting down we should + * immediately cease all link tuning. + */ +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + /* +@@ -431,7 +431,7 @@ static void rt2x00lib_intf_scheduled_ite + * note that in the spinlock protected area above the delayed_flags + * have been cleared correctly. + */ +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + if (delayed_flags & DELAYED_UPDATE_BEACON) +@@ -484,7 +484,7 @@ static void rt2x00lib_beacondone_iter(vo + + void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) + { +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, +@@ -563,7 +563,7 @@ void rt2x00lib_txdone(struct queue_entry + + rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); + +- __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); ++ clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + + /* +@@ -878,7 +878,7 @@ static int rt2x00lib_probe_hw_modes(stru + + static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) + { +- if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) + ieee80211_unregister_hw(rt2x00dev->hw); + + if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) { +@@ -894,6 +894,9 @@ static int rt2x00lib_probe_hw(struct rt2 + struct hw_mode_spec *spec = &rt2x00dev->spec; + int status; + ++ if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) ++ return 0; ++ + /* + * Initialize HW modes. + */ +@@ -915,7 +918,7 @@ static int rt2x00lib_probe_hw(struct rt2 + return status; + } + +- __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags); + + return 0; + } +@@ -925,7 +928,7 @@ static int rt2x00lib_probe_hw(struct rt2 + */ + static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) + { +- if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) ++ if (!test_and_clear_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) + return; + + /* +@@ -948,7 +951,7 @@ static int rt2x00lib_initialize(struct r + { + int status; + +- if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) + return 0; + + /* +@@ -967,7 +970,7 @@ static int rt2x00lib_initialize(struct r + return status; + } + +- __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags); + + /* + * Register the extra components. +@@ -981,7 +984,7 @@ int rt2x00lib_start(struct rt2x00_dev *r + { + int retval; + +- if (test_bit(DEVICE_STARTED, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) + return 0; + + /* +@@ -1012,15 +1015,15 @@ int rt2x00lib_start(struct rt2x00_dev *r + rt2x00dev->intf_sta_count = 0; + rt2x00dev->intf_associated = 0; + +- __set_bit(DEVICE_STARTED, &rt2x00dev->flags); +- __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); + + return 0; + } + + void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) + { +- if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) ++ if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) + return; + + /* +@@ -1032,8 +1035,6 @@ void rt2x00lib_stop(struct rt2x00_dev *r + rt2x00dev->intf_ap_count = 0; + rt2x00dev->intf_sta_count = 0; + rt2x00dev->intf_associated = 0; +- +- __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); + } + + /* +@@ -1088,7 +1089,7 @@ int rt2x00lib_probe_dev(struct rt2x00_de + rt2x00rfkill_allocate(rt2x00dev); + rt2x00debug_register(rt2x00dev); + +- __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); + + return 0; + +@@ -1101,7 +1102,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); + + void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) + { +- __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); ++ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); + + /* + * Disable radio. +@@ -1146,14 +1147,15 @@ int rt2x00lib_suspend(struct rt2x00_dev + int retval; + + NOTICE(rt2x00dev, "Going to sleep.\n"); +- __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + + /* + * Only continue if mac80211 has open interfaces. + */ +- if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) ++ if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || ++ !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) + goto exit; +- __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); ++ ++ set_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags); + + /* + * Disable radio. +@@ -1225,7 +1227,7 @@ int rt2x00lib_resume(struct rt2x00_dev * + /* + * Only continue if mac80211 had open interfaces. + */ +- if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) ++ if (!test_and_clear_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags)) + return 0; + + /* +@@ -1252,7 +1254,7 @@ int rt2x00lib_resume(struct rt2x00_dev * + /* + * We are ready again to receive requests from mac80211. + */ +- __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); + + /* + * It is possible that during that mac80211 has attempted +@@ -1272,7 +1274,7 @@ int rt2x00lib_resume(struct rt2x00_dev * + return 0; + + exit: +- rt2x00lib_disable_radio(rt2x00dev); ++ rt2x00lib_stop(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); + +--- a/drivers/net/wireless/rt2x00/rt2x00mac.c ++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c +@@ -106,7 +106,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw + * Note that we can only stop the TX queues inside the TX path + * due to possible race conditions in mac80211. + */ +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) { + ieee80211_stop_queues(hw); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +@@ -168,7 +168,7 @@ int rt2x00mac_start(struct ieee80211_hw + { + struct rt2x00_dev *rt2x00dev = hw->priv; + +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + + return rt2x00lib_start(rt2x00dev); +@@ -179,7 +179,7 @@ void rt2x00mac_stop(struct ieee80211_hw + { + struct rt2x00_dev *rt2x00dev = hw->priv; + +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + + rt2x00lib_stop(rt2x00dev); +@@ -199,8 +199,8 @@ int rt2x00mac_add_interface(struct ieee8 + * Don't allow interfaces to be added + * the device has disappeared. + */ +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || +- !test_bit(DEVICE_STARTED, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || ++ !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) + return -ENODEV; + + switch (conf->type) { +@@ -249,7 +249,7 @@ int rt2x00mac_add_interface(struct ieee8 + */ + for (i = 0; i < queue->limit; i++) { + entry = &queue->entries[i]; +- if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) ++ if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) + break; + } + +@@ -303,7 +303,7 @@ void rt2x00mac_remove_interface(struct i + * either the device has disappeared or when + * no interface is present. + */ +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || + (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) + return; +@@ -317,7 +317,7 @@ void rt2x00mac_remove_interface(struct i + * Release beacon entry so it is available for + * new interfaces again. + */ +- __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); ++ clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); + + /* + * Make sure the bssid and mac address registers +@@ -337,14 +337,14 @@ int rt2x00mac_config(struct ieee80211_hw + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + */ +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + + /* + * Check if we need to disable the radio, + * if this is not the case, at least the RX must be disabled. + */ +- if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { ++ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { + if (!conf->radio_enabled) + rt2x00lib_disable_radio(rt2x00dev); + else +@@ -359,14 +359,14 @@ int rt2x00mac_config(struct ieee80211_hw + * initialized. + */ + force_reconfig = +- __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); ++ test_and_clear_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); + + rt2x00lib_config(rt2x00dev, conf, force_reconfig); + + /* + * Reenable RX only if the radio should be on. + */ +- if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); + else if (conf->radio_enabled) + return rt2x00lib_enable_radio(rt2x00dev); +@@ -388,7 +388,7 @@ int rt2x00mac_config_interface(struct ie + * Mac80211 might be calling this function while we are trying + * to remove the device or perhaps suspending it. + */ +- if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + + spin_lock(&intf->lock); +--- a/drivers/net/wireless/rt2x00/rt2x00queue.c ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c +@@ -309,7 +309,7 @@ int rt2x00queue_write_tx_frame(struct da + if (unlikely(rt2x00queue_full(queue))) + return -EINVAL; + +- if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ++ if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + ERROR(queue->rt2x00dev, + "Arrived at non-free entry in the non-full queue %d.\n" + "Please file bug report to %s.\n", +@@ -333,14 +333,14 @@ int rt2x00queue_write_tx_frame(struct da + skbdesc->entry = entry; + + if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { +- __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); ++ clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + return -EIO; + } + + if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) + rt2x00queue_map_txskb(queue->rt2x00dev, skb); + +- __set_bit(ENTRY_DATA_PENDING, &entry->flags); ++ set_bit(ENTRY_DATA_PENDING, &entry->flags); + + rt2x00queue_index_inc(queue, Q_INDEX); + rt2x00queue_write_tx_descriptor(entry, &txdesc); +--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c ++++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c +@@ -41,16 +41,16 @@ static int rt2x00rfkill_toggle_radio(voi + /* + * Only continue if there are enabled interfaces. + */ +- if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) + return 0; + + if (state == RFKILL_STATE_UNBLOCKED) { + INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); +- __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); ++ clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); + retval = rt2x00lib_enable_radio(rt2x00dev); + } else if (state == RFKILL_STATE_SOFT_BLOCKED) { + INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); +- __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); ++ set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); + rt2x00lib_disable_radio(rt2x00dev); + } else { + WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", +--- a/drivers/net/wireless/rt2x00/rt2x00usb.c ++++ b/drivers/net/wireless/rt2x00/rt2x00usb.c +@@ -163,7 +163,7 @@ static void rt2x00usb_interrupt_txdone(s + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct txdone_entry_desc txdesc; + +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || + !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; + +@@ -232,7 +232,7 @@ static inline void rt2x00usb_kick_tx_ent + { + struct queue_entry_priv_usb *entry_priv = entry->priv_data; + +- if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) ++ if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + } + +@@ -283,7 +283,7 @@ static void rt2x00usb_interrupt_rxdone(s + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + u8 rxd[32]; + +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || + !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; + +@@ -293,7 +293,7 @@ static void rt2x00usb_interrupt_rxdone(s + * a problem. + */ + if (urb->actual_length < entry->queue->desc_size || urb->status) { +- __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); ++ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(urb, GFP_ATOMIC); + return; + } +@@ -361,7 +361,7 @@ void rt2x00usb_init_rxentry(struct rt2x0 + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); + +- __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); ++ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + } + EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); +--- a/drivers/net/wireless/rt2x00/rt61pci.c ++++ b/drivers/net/wireless/rt2x00/rt61pci.c +@@ -1860,7 +1860,7 @@ static irqreturn_t rt61pci_interrupt(int + if (!reg && !reg_mcu) + return IRQ_NONE; + +- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) ++ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + return IRQ_HANDLED; + + /* diff --git a/src/patches/suse-2.6.27.31/patches.fixes/saa7134-fix-resource-map-sanity-check-conflict.patch b/src/patches/suse-2.6.27.31/patches.fixes/saa7134-fix-resource-map-sanity-check-conflict.patch new file mode 100644 index 000000000..813d39ff0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/saa7134-fix-resource-map-sanity-check-conflict.patch @@ -0,0 +1,93 @@ +Subject: [PATCH] saa7134: fix resource map sanity check conflict +References: bnc#446733 +From: Suresh Siddha + +Note: Patch should use pci_ioremap but this is what upstream has. + +changeset: 9356:33626df3ba2c +user: Mauro Carvalho Chehab +date: Mon Oct 20 13:57:02 2008 -0700 +files: drivers/media/video/saa7134/saa7134-core.c + + + +Impact: driver could possibly stomp on resources outside of its scope + +{mchehab@redhat.com: I got two versions of the same patch (identical, +except for whitespacing). One authored by Andy Burns and another +authored by Suresh Siddha. Due to that, I'm applying the one that has +less CodingStyle errors. I'm also adding both comments and the SOB's for +both patches, since they are both interesting} + +Suresh Siddha commented: + + Alexey Fisher reported: + + > resource map sanity check conflict: 0xcfeff800 0xcff007ff 0xcfe00000 + > 0xcfefffff PCI Bus 0000:01 + + BAR base is located in the middle of the 4K page and the hardcoded + size argument makes the request span two pages causing the conflict. + + Fix the hard coded size argument in ioremap(). + +Andy Burns commented: + + I have already sent this patch on the linux-dvb list, but it didn't get + much attention, so re-sending direct, I hope you all don't mind. + + While attempting to run mythtv in a xen domU, I encountered problems + loading the driver for my saa7134 card, with an error from ioremap(). + + This error was due to the driver allocating an incorrectly sized mmio + area, which was trapped by xen's permission checks, but this would go + un-noticed on a kernel without xen. + + My card has a 1K sized mmio area, I've had information that other cards + have 2K areas, perhaps others have different sizes, yet the driver + always attempts to map 4K. I realise that the granularity of mapping is + the page size, which typically would be 4K, but unless the card's base + address happens to fall on a 4K boundary (mine does not) then the + base+4K will end up spanning two pages, and this is when the error + occurs under xen. + + My patch uses the pci_resource_len macro to determine the size required + for the user's particular card, instead of the hardcoded 4K value. I've + tested with a couple of printk() inside ioremap() that the start address + and size do get rounded to the closest page boundary. + + With this patch I am able to successfully load the saa7134 driver and + run mythtv under xen with my card, subject to correct pollirq settings + in case of shared IRQ, I am still seeing occasional DMA panics, which I + think are related to swiotlb handling by dom0/domU, usually the panic + occurs when changing mux, once tuned to a mux, 12 hour continuous + recordings are possible without errors. + +Reported-by: Alexey Fisher + +Signed-off-by: Suresh Siddha +Signed-off-by: Andy Burns +Tested-by: Alexey Fisher +Signed-off-by: Ingo Molnar +Signed-off-by: Mauro Carvalho Chehab +Acked-by: Brandon Philips + + +--- + drivers/media/video/saa7134/saa7134-core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +Index: linux-2.6.27-SL111_BRANCH/drivers/media/video/saa7134/saa7134-core.c +=================================================================== +--- linux-2.6.27-SL111_BRANCH.orig/drivers/media/video/saa7134/saa7134-core.c ++++ linux-2.6.27-SL111_BRANCH/drivers/media/video/saa7134/saa7134-core.c +@@ -965,7 +965,8 @@ static int __devinit saa7134_initdev(str + dev->name,(unsigned long long)pci_resource_start(pci_dev,0)); + goto fail1; + } +- dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000); ++ dev->lmmio = ioremap(pci_resource_start(pci_dev, 0), ++ pci_resource_len(pci_dev, 0)); + dev->bmmio = (__u8 __iomem *)dev->lmmio; + if (NULL == dev->lmmio) { + err = -EIO; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sched-fix-__load_balance_iterator-for-cfs-with-on.patch b/src/patches/suse-2.6.27.31/patches.fixes/sched-fix-__load_balance_iterator-for-cfs-with-on.patch new file mode 100644 index 000000000..198b0b962 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sched-fix-__load_balance_iterator-for-cfs-with-on.patch @@ -0,0 +1,43 @@ +Subject: fix __load_balance_iterator() for cfs with only one task +From: Gautham R Shenoy +References: 457594 - LTC50544 + +The __load_balance_iterator() returns a NULL when there's only one +sched_entity which is a task. It is caused by the following code-path. + + /* Skip over entities that are not tasks */ + do { + se = list_entry(next, struct sched_entity, group_node); + next = next->next; + } while (next != &cfs_rq->tasks && !entity_is_task(se)); + + if (next == &cfs_rq->tasks) + return NULL; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + This will return NULL even when se is a task. + +As a side-effect, there was a regression in sched_mc behavior since 2.6.25, +since iter_move_one_task() when it calls load_balance_start_fair(), +would not get any tasks to move! + +Fix this by checking if the last entity was a task or not. + +Signed-off-by: Gautham R Shenoy +Acked-by: Peter Zijlstra +Signed-off-by: Ingo Molnar +Signed-off-by: Olaf Hering +--- + kernel/sched_fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/kernel/sched_fair.c ++++ b/kernel/sched_fair.c +@@ -1410,7 +1410,7 @@ __load_balance_iterator(struct cfs_rq *c + next = next->next; + } while (next != &cfs_rq->tasks && !entity_is_task(se)); + +- if (next == &cfs_rq->tasks) ++ if (next == &cfs_rq->tasks && !entity_is_task(se)) + return NULL; + + cfs_rq->balance_iterator = next; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-add-tgps-setting b/src/patches/suse-2.6.27.31/patches.fixes/scsi-add-tgps-setting new file mode 100644 index 000000000..1c9a3edaf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-add-tgps-setting @@ -0,0 +1,293 @@ +Subject: Add TGPS setting to scsi devices +From: Hannes Reinecke + +Some multipath-capable storage arrays are capable of running +in compatible mode, ie supporting both the original vendor-specific +failover mode and the SPC-3 compliant ALUA mode. +This patch stores the TGPS setting in the sdev so that we can directly +match onto it and select the correct device handler automatically. +And we can save code in the ALUA device handler. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/device_handler/scsi_dh.c | 9 ++- + drivers/scsi/device_handler/scsi_dh_alua.c | 67 +++------------------------- + drivers/scsi/device_handler/scsi_dh_emc.c | 8 +-- + drivers/scsi/device_handler/scsi_dh_hp_sw.c | 10 ++-- + drivers/scsi/device_handler/scsi_dh_rdac.c | 34 +++++++------- + drivers/scsi/scsi_scan.c | 1 + drivers/scsi/scsi_sysfs.c | 2 + include/scsi/scsi_device.h | 4 + + 8 files changed, 48 insertions(+), 87 deletions(-) + +--- a/drivers/scsi/device_handler/scsi_dh_alua.c ++++ b/drivers/scsi/device_handler/scsi_dh_alua.c +@@ -118,43 +118,6 @@ static struct request *get_alua_req(stru + } + + /* +- * submit_std_inquiry - Issue a standard INQUIRY command +- * @sdev: sdev the command should be send to +- */ +-static int submit_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) +-{ +- struct request *rq; +- int err = SCSI_DH_RES_TEMP_UNAVAIL; +- +- rq = get_alua_req(sdev, h->inq, ALUA_INQUIRY_SIZE, READ); +- if (!rq) +- goto done; +- +- /* Prepare the command. */ +- rq->cmd[0] = INQUIRY; +- rq->cmd[1] = 0; +- rq->cmd[2] = 0; +- rq->cmd[4] = ALUA_INQUIRY_SIZE; +- rq->cmd_len = COMMAND_SIZE(INQUIRY); +- +- rq->sense = h->sense; +- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); +- rq->sense_len = h->senselen = 0; +- +- err = blk_execute_rq(rq->q, NULL, rq, 1); +- if (err == -EIO) { +- sdev_printk(KERN_INFO, sdev, +- "%s: std inquiry failed with %x\n", +- ALUA_DH_NAME, rq->errors); +- h->senselen = rq->sense_len; +- err = SCSI_DH_IO; +- } +- blk_put_request(rq); +-done: +- return err; +-} +- +-/* + * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command + * @sdev: sdev the command should be sent to + */ +@@ -281,23 +244,19 @@ done: + } + + /* +- * alua_std_inquiry - Evaluate standard INQUIRY command ++ * alua_check_tgps - Evaluate TGPS setting + * @sdev: device to be checked + * +- * Just extract the TPGS setting to find out if ALUA ++ * Just examine the TPGS setting of the device to find out if ALUA + * is supported. + */ +-static int alua_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) ++static int alua_check_tgps(struct scsi_device *sdev, struct alua_dh_data *h) + { +- int err; +- +- err = submit_std_inquiry(sdev, h); +- +- if (err != SCSI_DH_OK) +- return err; ++ int err = SCSI_DH_OK; + + /* Check TPGS setting */ +- h->tpgs = (h->inq[5] >> 4) & 0x3; ++ h->tpgs = sdev->tgps; ++ + switch (h->tpgs) { + case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT: + sdev_printk(KERN_INFO, sdev, +@@ -609,7 +568,7 @@ static int alua_initialize(struct scsi_d + { + int err; + +- err = alua_std_inquiry(sdev, h); ++ err = alua_check_tgps(sdev, h); + if (err != SCSI_DH_OK) + goto out; + +@@ -674,16 +633,8 @@ static int alua_prep_fn(struct scsi_devi + } + + static const struct scsi_dh_devlist alua_dev_list[] = { +- {"HP", "MSA VOLUME" }, +- {"HP", "HSV101" }, +- {"HP", "HSV111" }, +- {"HP", "HSV200" }, +- {"HP", "HSV210" }, +- {"HP", "HSV300" }, +- {"IBM", "2107900" }, +- {"IBM", "2145" }, +- {"Pillar", "Axiom" }, +- {NULL, NULL} ++ {"", "", 3 }, ++ {NULL, NULL, 0} + }; + + static int alua_bus_attach(struct scsi_device *sdev); +--- a/drivers/scsi/device_handler/scsi_dh.c ++++ b/drivers/scsi/device_handler/scsi_dh.c +@@ -28,6 +28,7 @@ struct scsi_dh_devinfo_list { + struct list_head node; + char vendor[9]; + char model[17]; ++ char tgps; + struct scsi_device_handler *handler; + }; + +@@ -60,7 +61,8 @@ scsi_dh_cache_lookup(struct scsi_device + spin_lock(&list_lock); + list_for_each_entry(tmp, &scsi_dh_dev_list, node) { + if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) && +- !strncmp(sdev->model, tmp->model, strlen(tmp->model))) { ++ !strncmp(sdev->model, tmp->model, strlen(tmp->model)) && ++ (!tmp->tgps || (sdev->tgps & tmp->tgps) != 0)) { + found_dh = tmp->handler; + break; + } +@@ -79,7 +81,9 @@ static int scsi_dh_handler_lookup(struct + if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor, + strlen(scsi_dh->devlist[i].vendor)) && + !strncmp(sdev->model, scsi_dh->devlist[i].model, +- strlen(scsi_dh->devlist[i].model))) { ++ strlen(scsi_dh->devlist[i].model)) && ++ (!scsi_dh->devlist[i].tgps || ++ (sdev->tgps & scsi_dh->devlist[i].tgps) != 0)) { + found = 1; + break; + } +@@ -128,6 +132,7 @@ device_handler_match(struct scsi_device_ + strncpy(tmp->model, sdev->model, 16); + tmp->vendor[8] = '\0'; + tmp->model[16] = '\0'; ++ tmp->tgps = sdev->tgps; + tmp->handler = found_dh; + spin_lock(&list_lock); + list_add(&tmp->node, &scsi_dh_dev_list); +--- a/drivers/scsi/device_handler/scsi_dh_emc.c ++++ b/drivers/scsi/device_handler/scsi_dh_emc.c +@@ -563,10 +563,10 @@ done: + } + + static const struct scsi_dh_devlist clariion_dev_list[] = { +- {"DGC", "RAID"}, +- {"DGC", "DISK"}, +- {"DGC", "VRAID"}, +- {NULL, NULL}, ++ {"DGC", "RAID", 0}, ++ {"DGC", "DISK", 0}, ++ {"DGC", "VRAID", 0}, ++ {NULL, NULL, 0}, + }; + + static int clariion_bus_attach(struct scsi_device *sdev); +--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c ++++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c +@@ -283,11 +283,11 @@ static int hp_sw_activate(struct scsi_de + } + + static const struct scsi_dh_devlist hp_sw_dh_data_list[] = { +- {"COMPAQ", "MSA1000 VOLUME"}, +- {"COMPAQ", "HSV110"}, +- {"HP", "HSV100"}, +- {"DEC", "HSG80"}, +- {NULL, NULL}, ++ {"COMPAQ", "MSA1000 VOLUME", 0}, ++ {"COMPAQ", "HSV110", 0}, ++ {"HP", "HSV100", 0}, ++ {"DEC", "HSG80", 0}, ++ {NULL, NULL, 0}, + }; + + static int hp_sw_bus_attach(struct scsi_device *sdev); +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -583,23 +583,23 @@ static int rdac_check_sense(struct scsi_ + } + + static const struct scsi_dh_devlist rdac_dev_list[] = { +- {"IBM", "1722"}, +- {"IBM", "1724"}, +- {"IBM", "1726"}, +- {"IBM", "1742"}, +- {"IBM", "1814"}, +- {"IBM", "1815"}, +- {"IBM", "1818"}, +- {"IBM", "3526"}, +- {"SGI", "TP9400"}, +- {"SGI", "TP9500"}, +- {"SGI", "IS"}, +- {"STK", "OPENstorage D280"}, +- {"SUN", "CSM200_R"}, +- {"SUN", "LCSM100_F"}, +- {"DELL", "MD3000"}, +- {"DELL", "MD3000i"}, +- {NULL, NULL}, ++ {"IBM", "1722", 0}, ++ {"IBM", "1724", 0}, ++ {"IBM", "1726", 0}, ++ {"IBM", "1742", 0}, ++ {"IBM", "1814", 0}, ++ {"IBM", "1815", 0}, ++ {"IBM", "1818", 0}, ++ {"IBM", "3526", 0}, ++ {"SGI", "TP9400", 0}, ++ {"SGI", "TP9500", 0}, ++ {"SGI", "IS", 0}, ++ {"STK", "OPENstorage D280", 0}, ++ {"SUN", "CSM200_R", 0}, ++ {"SUN", "LCSM100_F", 0}, ++ {"DELL", "MD3000", 0}, ++ {"DELL", "MD3000i", 0}, ++ {NULL, NULL, 0}, + }; + + static int rdac_bus_attach(struct scsi_device *sdev); +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -821,6 +821,7 @@ static int scsi_add_lun(struct scsi_devi + sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; + sdev->lockable = sdev->removable; + sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2); ++ sdev->tgps = (inq_result[5] >> 4) & 3; + + if (sdev->scsi_level >= SCSI_3 || + (sdev->inquiry_len > 56 && inq_result[56] & 0x04)) +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -543,6 +543,7 @@ sdev_rd_attr (scsi_level, "%d\n"); + sdev_rd_attr (vendor, "%.8s\n"); + sdev_rd_attr (model, "%.16s\n"); + sdev_rd_attr (rev, "%.4s\n"); ++sdev_rd_attr (tgps, "%d\n"); + + /* + * TODO: can we make these symlinks to the block layer ones? +@@ -728,6 +729,7 @@ static struct attribute *scsi_sdev_attrs + &dev_attr_vendor.attr, + &dev_attr_model.attr, + &dev_attr_rev.attr, ++ &dev_attr_tgps.attr, + &dev_attr_rescan.attr, + &dev_attr_delete.attr, + &dev_attr_state.attr, +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -96,7 +96,8 @@ struct scsi_device { + void *hostdata; /* available to low-level driver */ + char type; + char scsi_level; +- char inq_periph_qual; /* PQ from INQUIRY data */ ++ char inq_periph_qual; /* PQ from INQUIRY data */ ++ char tgps; /* Target port group support */ + unsigned char inquiry_len; /* valid bytes in 'inquiry' */ + unsigned char * inquiry; /* INQUIRY response data */ + const char * vendor; /* [back_compat] point into 'inquiry' ... */ +@@ -174,6 +175,7 @@ struct scsi_device { + struct scsi_dh_devlist { + char *vendor; + char *model; ++ char tgps; + }; + + struct scsi_device_handler { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-call-unprep_request-under-lock b/src/patches/suse-2.6.27.31/patches.fixes/scsi-call-unprep_request-under-lock new file mode 100644 index 000000000..ce8f2b8da --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-call-unprep_request-under-lock @@ -0,0 +1,31 @@ +Subject: [SCSI] scsi_lib: only call scsi_unprep_request() under queue lock +From: James Bottomley +Date: Sat Dec 13 14:31:03 2008 -0600: +Git: 02bd3499a3be984f1e88821c3ed252c8c49c498e +References: bnc#464155 + +It's called under that lock everywhere else and it does alter the +request state, so it should be. + +This one occurance in scsi_requeue_command() could open a window where +req->special is set to NULL while the requests is going through either +timeout or completion processing leading to NULL pointer derefs of the +sort complained of in bugzillas 12020 and 12195. + +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index fa45a1a..148d3af 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -648,8 +648,8 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) + struct request *req = cmd->request; + unsigned long flags; + +- scsi_unprep_request(req); + spin_lock_irqsave(q->queue_lock, flags); ++ scsi_unprep_request(req); + blk_requeue_request(q, req); + spin_unlock_irqrestore(q->queue_lock, flags); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-check-host-lookup-failure b/src/patches/suse-2.6.27.31/patches.fixes/scsi-check-host-lookup-failure new file mode 100644 index 000000000..b1ca72418 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-check-host-lookup-failure @@ -0,0 +1,26 @@ +From: Laurie Barry +Subject: Correct scsi_host_lookup return value +References: bnc#456532 + +In the scsi_generic_msg_handler routine it make a call to scsi_host_lookup and +checks the return value for NULL, but the scsi_host_lookup routine can return +an error when it fails instead of NULL. So when the scsi_host_lookup fails the +scsi_generic_msg_handler crashes the kernel with "BUG: unable to handle kernel +NULL pointer dereference at 00000000000000aa" + +Signed-off-by: Laurie Barry +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c +index b37e133..760bd23 100644 +--- a/drivers/scsi/scsi_netlink.c ++++ b/drivers/scsi/scsi_netlink.c +@@ -261,7 +261,7 @@ scsi_generic_msg_handler(struct sk_buff *skb) + + /* if successful, scsi_host_lookup takes a shost reference */ + shost = scsi_host_lookup(msg->host_no); +- if (!shost) { ++ if (IS_ERR(shost)) { + err = -ENODEV; + goto driver_exit; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-group-id-mask b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-group-id-mask new file mode 100644 index 000000000..142408960 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-group-id-mask @@ -0,0 +1,26 @@ +From: Ilgu Hong +Subject: Incorrect masking for group ID in scsi_dh_alua + + +The buf[i] is a byte but we are only asking 4 bits off the +group_id. This patch has us take off a byte. + +Signed-off-by: Ilgu Hong +Signed-off-by: Mike Christie +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c +index 1000acc..fc7003a 100644 +--- a/drivers/scsi/device_handler/scsi_dh_alua.c ++++ b/drivers/scsi/device_handler/scsi_dh_alua.c +@@ -210,8 +210,8 @@ static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h) + /* Prepare the data buffer */ + memset(h->buff, 0, stpg_len); + h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; +- h->buff[6] = (h->group_id >> 8) & 0x0f; +- h->buff[7] = h->group_id & 0x0f; ++ h->buff[6] = (h->group_id >> 8) & 0xff; ++ h->buff[7] = h->group_id & 0xff; + + rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); + if (!rq) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-retry-UA b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-retry-UA new file mode 100644 index 000000000..b96e50ebe --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-retry-UA @@ -0,0 +1,48 @@ +From: Hannes Reinecke +Subject: Retry ALUA device handler initialization on Unit Attention + +Whenever we receive a UNIT ATTENTION sense code we should just retry +the command. We only should take care to pass through 04/02 as this +is handled later on by the generic code in scsi_check_sense(). + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c +index e356b43..a3660a6 100644 +--- a/drivers/scsi/device_handler/scsi_dh_alua.c ++++ b/drivers/scsi/device_handler/scsi_dh_alua.c +@@ -444,24 +444,16 @@ static int alua_check_sense(struct scsi_device *sdev, + return SUCCESS; + break; + case UNIT_ATTENTION: +- if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) +- /* +- * Power On, Reset, or Bus Device Reset, just retry. +- */ +- return ADD_TO_MLQUEUE; +- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) { +- /* +- * ALUA state changed +- */ +- return ADD_TO_MLQUEUE; +- } +- if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) { +- /* +- * Implicit ALUA state transition failed +- */ +- return ADD_TO_MLQUEUE; +- } +- break; ++ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02) ++ /* ++ * LUN not ready, initialization command required ++ */ ++ return SCSI_RETURN_NOT_HANDLED; ++ ++ /* ++ * Just retry for UNIT_ATTENTION ++ */ ++ return ADD_TO_MLQUEUE; + } + + return SCSI_RETURN_NOT_HANDLED; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-send-stpg b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-send-stpg new file mode 100644 index 000000000..85f420429 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-alua-send-stpg @@ -0,0 +1,32 @@ +From: Hannes Reinecke +Subject: Always send STPG for explicit tgps mode + +When we are in explicit tgps mode we should always send an STPG +command to enable the active/optimized mode. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/device_handler/scsi_dh_alua.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/drivers/scsi/device_handler/scsi_dh_alua.c ++++ b/drivers/scsi/device_handler/scsi_dh_alua.c +@@ -599,13 +599,11 @@ static int alua_activate(struct scsi_dev + struct alua_dh_data *h = get_alua_data(sdev); + int err = SCSI_DH_OK; + +- if (h->group_id != -1) { +- err = alua_rtpg(sdev, h); +- if (err != SCSI_DH_OK) +- goto out; +- } ++ err = alua_rtpg(sdev, h); ++ if (err != SCSI_DH_OK) ++ goto out; + +- if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED) ++ if ((h->tpgs & TPGS_MODE_EXPLICIT) && h->state != TPGS_STATE_OPTIMIZED) + err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h); + + out: diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-emc-mode-select-10-size b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-emc-mode-select-10-size new file mode 100644 index 000000000..da0997db8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-emc-mode-select-10-size @@ -0,0 +1,41 @@ +From: Hannes Reinecke +Subject: DM-MPIO fails to tresspass LUNs on CLARiiON arrays +References: bnc#484529 + +When failing active paths on Clariion arrays, the trespass +command is sent but not process correctly. Reason is that +we're not formatting the command correctly, and the array +just silently ignores the error. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c +index 2505237..822680e 100644 +--- a/drivers/scsi/device_handler/scsi_dh_emc.c ++++ b/drivers/scsi/device_handler/scsi_dh_emc.c +@@ -286,14 +286,17 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, + len = sizeof(short_trespass); + rq->cmd_flags |= REQ_RW; + rq->cmd[1] = 0x10; ++ rq->cmd[4] = len; + break; + case MODE_SELECT_10: + len = sizeof(long_trespass); + rq->cmd_flags |= REQ_RW; + rq->cmd[1] = 0x10; ++ rq->cmd[8] = len; + break; + case INQUIRY: + len = CLARIION_BUFFER_SIZE; ++ rq->cmd[4] = len; + memset(buffer, 0, len); + break; + default: +@@ -301,7 +304,6 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, + break; + } + +- rq->cmd[4] = len; + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-emc-rw-mismatch b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-emc-rw-mismatch new file mode 100644 index 000000000..0c6c48c2b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-emc-rw-mismatch @@ -0,0 +1,27 @@ +From: Hannes Reinecke +Subject: Server crashes when path failures occur against EMC storage +Reference: bnc#474482 + +When cable pulls, SP reboots, or other events take place that would interfere +with IO running to EMC storage the server crashes trying to resolve the path +failure. + +Proglem is that we're latching on MODE_SELECT when deciding the +read/write mode for blk_get_request(). However, for newer arrays +we're using MODE_SELECT_10, thus causing a mismatch. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c +index 436957a..2505237 100644 +--- a/drivers/scsi/device_handler/scsi_dh_emc.c ++++ b/drivers/scsi/device_handler/scsi_dh_emc.c +@@ -272,7 +272,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, + int len = 0; + + rq = blk_get_request(sdev->request_queue, +- (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO); ++ (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO); + if (!rq) { + sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); + return NULL; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-queuedata-accessors b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-queuedata-accessors new file mode 100644 index 000000000..d328896d3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-queuedata-accessors @@ -0,0 +1,97 @@ +From: Hannes Reinecke +Subject: Kernel bug triggered in multipath +References: bnc#486001 + +Starting multipath on a cciss device will cause a kernel +warning to be triggered. Problem is that we're using the +->queuedata field of the request_queue to derefence the +scsi device; however, for other (non-SCSI) devices this +points to a totally different structure. +So we should rather be using accessors here which make +sure we're only returning valid SCSI device structures. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/device_handler/scsi_dh.c | 10 +++++----- + drivers/scsi/scsi_lib.c | 11 +++++++++++ + include/scsi/scsi_device.h | 1 + + 3 files changed, 17 insertions(+), 5 deletions(-) + +--- a/drivers/scsi/device_handler/scsi_dh.c ++++ b/drivers/scsi/device_handler/scsi_dh.c +@@ -427,7 +427,7 @@ int scsi_dh_activate(struct request_queu + struct scsi_device_handler *scsi_dh = NULL; + + spin_lock_irqsave(q->queue_lock, flags); +- sdev = q->queuedata; ++ sdev = scsi_device_from_queue(q); + if (sdev && sdev->scsi_dh_data) + scsi_dh = sdev->scsi_dh_data->scsi_dh; + if (!scsi_dh || !get_device(&sdev->sdev_gendev)) +@@ -456,7 +456,7 @@ int scsi_dh_handler_exist(const char *na + EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); + + /* +- * scsi_dh_handler_attach - Attach device handler ++ * scsi_dh_attach - Attach device handler + * @sdev - sdev the handler should be attached to + * @name - name of the handler to attach + */ +@@ -472,7 +472,7 @@ int scsi_dh_attach(struct request_queue + return -EINVAL; + + spin_lock_irqsave(q->queue_lock, flags); +- sdev = q->queuedata; ++ sdev = scsi_device_from_queue(q); + if (!sdev || !get_device(&sdev->sdev_gendev)) + err = -ENODEV; + spin_unlock_irqrestore(q->queue_lock, flags); +@@ -487,7 +487,7 @@ int scsi_dh_attach(struct request_queue + EXPORT_SYMBOL_GPL(scsi_dh_attach); + + /* +- * scsi_dh_handler_detach - Detach device handler ++ * scsi_dh_detach - Detach device handler + * @sdev - sdev the handler should be detached from + * + * This function will detach the device handler only +@@ -501,7 +501,7 @@ void scsi_dh_detach(struct request_queue + struct scsi_device_handler *scsi_dh = NULL; + + spin_lock_irqsave(q->queue_lock, flags); +- sdev = q->queuedata; ++ sdev = scsi_device_from_queue(q); + if (!sdev || !get_device(&sdev->sdev_gendev)) + sdev = NULL; + spin_unlock_irqrestore(q->queue_lock, flags); +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1696,6 +1696,17 @@ static void scsi_request_fn(struct reque + spin_lock_irq(q->queue_lock); + } + ++struct scsi_device *scsi_device_from_queue(struct request_queue *q) ++{ ++ struct scsi_device *sdev = NULL; ++ ++ if (q->request_fn == scsi_request_fn) ++ sdev = q->queuedata; ++ ++ return sdev; ++} ++EXPORT_SYMBOL_GPL(scsi_device_from_queue); ++ + u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) + { + struct device *host_dev; +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -291,6 +291,7 @@ extern void starget_for_each_device(stru + extern void __starget_for_each_device(struct scsi_target *, void *, + void (*fn)(struct scsi_device *, + void *)); ++extern struct scsi_device *scsi_device_from_queue(struct request_queue *); + + /* only exposed to implement shost_for_each_device */ + extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-add-stk b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-add-stk new file mode 100644 index 000000000..cc392dccb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-add-stk @@ -0,0 +1,24 @@ +From: Goldwyn Rodrigues +Subject: STK arrays missing from rdac devicehandler +References: bnc#503855 + +Some STK arrays are missing from the RDAC device handler, +causing multipath to malfunction. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/device_handler/scsi_dh_rdac.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -607,6 +607,8 @@ static const struct scsi_dh_devlist rdac + {"SGI", "TP9500", 0}, + {"SGI", "IS", 0}, + {"STK", "OPENstorage D280", 0}, ++ {"STK", "FLEXLINE 380", 0}, ++ {"SUN", "STK6580_6780", 0}, + {"SUN", "CSM200_R", 0}, + {"SUN", "LCSM100_F", 0}, + {"DELL", "MD3000", 0}, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-initialize-passive-path b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-initialize-passive-path new file mode 100644 index 000000000..91fa71159 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-initialize-passive-path @@ -0,0 +1,30 @@ +Subject: Initialize path state to be passive when path is not owned +From: Chandra Seetharaman +Date: Thu Nov 20 14:14:39 2008 +0100: +References: bnc#442676 + +Set the path state to be passive when we learn that the controller does +not own the path to the LUN. + +This will avoid sending even a single i/o thru the passive path at the +probe time. + +Signed-off-by: Chandra Seetharaman +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/device_handler/scsi_dh_rdac.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -403,6 +403,9 @@ static int check_ownership(struct scsi_d + } + } + ++ if (h->lun_state == RDAC_LUN_UNOWNED) ++ h->state = RDAC_STATE_PASSIVE; ++ + return err; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-UA b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-UA new file mode 100644 index 000000000..b4876ba77 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-UA @@ -0,0 +1,27 @@ +From: "Chauhan, Vijay" +Subject: Retry for Quiescence in Progress in rdac device handler + +We found one issue related to failback in SLES11 RC2. Please find +the description of the issue in this mail below. I have submitted +a patch as fix to the dm community and likely to be accepted. We +need the same fix in SLES11 too. + + +Signed-off-by: Vijay Chauhan +Signed-off-by: Hannes Reinecke + +--- +--- linux-2.6.27.11-1/drivers/scsi/device_handler/scsi_dh_rdac.c.orig 2009-01-26 19:50:50.000000000 +0530 ++++ linux-2.6.27.11-1/drivers/scsi/device_handler/scsi_dh_rdac.c 2009-01-26 20:09:20.000000000 +0530 +@@ -578,6 +578,11 @@ static int rdac_check_sense(struct scsi_ + * Power On, Reset, or Bus Device Reset, just retry. + */ + return ADD_TO_MLQUEUE; ++ if (sense_hdr->asc == 0x8b && sense_hdr->ascq == 0x02) ++ /* ++ * Quiescence in Progress, just retry. ++ */ ++ return ADD_TO_MLQUEUE; + break; + } + /* success just means we do not care what scsi-ml does */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-for-not-ready b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-for-not-ready new file mode 100644 index 000000000..2f991794d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-for-not-ready @@ -0,0 +1,29 @@ +From: Vijay Chauhan +Subject: Retry NOT READY for rdac device handler +References: bnc#496502 + +During device discovery read capacity fails with 0x020401 and sets the device +size to 0. As a reason any I/O submitted to this path gets killed at sd_prep_fn +with BLKPREP_KILL. This patch is to retry for 0x020401. NEED_RETRY in +scsi_decide_disposition does not give sufficient time for the device to become +ready. + +Signed-off-by: Vijay Chauhan +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c +index 77b724f..4c97279 100644 +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -548,6 +548,11 @@ static int rdac_check_sense(struct scsi_device *sdev, + struct rdac_dh_data *h = get_rdac_data(sdev); + switch (sense_hdr->sense_key) { + case NOT_READY: ++ if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) ++ /* LUN Not Ready - In process of becoming ready ++ * Just retry. ++ */ ++ return ADD_TO_MLQUEUE; + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81) + /* LUN Not Ready - Storage firmware incompatible + * Manual code synchonisation required. diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-mode-select b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-mode-select new file mode 100644 index 000000000..a8416f131 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-retry-mode-select @@ -0,0 +1,58 @@ +Subject: Retry mode select in RDAC device handler +From: Chandra Seetharaman +References: bnc#441337 + +When the mode select sent to the controller fails with the retryable +error, it is better to retry the mode_select from the hardware handler +itself, instead of propagating the failure to dm-multipath. + +Signed-off-by: Chandra Seetharaman +Signed-off-by: Hannes Reinecke + +--- +--- + drivers/scsi/device_handler/scsi_dh_rdac.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -24,6 +24,7 @@ + #include + + #define RDAC_NAME "rdac" ++#define RDAC_RETRY_COUNT 5 + + /* + * LSI mode page stuff +@@ -475,21 +476,27 @@ static int send_mode_select(struct scsi_ + { + struct request *rq; + struct request_queue *q = sdev->request_queue; +- int err = SCSI_DH_RES_TEMP_UNAVAIL; ++ int err, retry_cnt = RDAC_RETRY_COUNT; + ++retry: ++ err = SCSI_DH_RES_TEMP_UNAVAIL; + rq = rdac_failover_get(sdev, h); + if (!rq) + goto done; + +- sdev_printk(KERN_INFO, sdev, "queueing MODE_SELECT command.\n"); ++ sdev_printk(KERN_INFO, sdev, "%s MODE_SELECT command.\n", ++ (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying"); + + err = blk_execute_rq(q, NULL, rq, 1); +- if (err != SCSI_DH_OK) ++ blk_put_request(rq); ++ if (err != SCSI_DH_OK) { + err = mode_select_handle_sense(sdev, h->sense); ++ if (err == SCSI_DH_RETRY && retry_cnt--) ++ goto retry; ++ } + if (err == SCSI_DH_OK) + h->state = RDAC_STATE_ACTIVE; + +- blk_put_request(rq); + done: + return err; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-set-default-ownership b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-set-default-ownership new file mode 100644 index 000000000..232d30a98 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-dh-rdac-set-default-ownership @@ -0,0 +1,29 @@ +Subject: scsi_dh_rdac: make sure the ownership is set correctly +From: Chandra Seetharaman +Patch-Mainline: 2.6.28 +References: bnc#441337 + +When the controller ownership is changed (from passive to active), +check_ownership() doesn't set the state of the device to ACTIVE. + +This patch fixes the problem. + +Signed-off-by: Chandra Seetharaman +Reported and tested by: "Moger, Babu" +Signed-off-by: Hannes Reinecke + +--- +--- + drivers/scsi/device_handler/scsi_dh_rdac.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -386,6 +386,7 @@ static int check_ownership(struct scsi_d + struct c9_inquiry *inqp; + + h->lun_state = RDAC_LUN_UNOWNED; ++ h->state = RDAC_STATE_ACTIVE; + err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); + if (err == SCSI_DH_OK) { + inqp = &h->inq.c9; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-eh-timed-out-missing-braces b/src/patches/suse-2.6.27.31/patches.fixes/scsi-eh-timed-out-missing-braces new file mode 100644 index 000000000..4024ce4fc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-eh-timed-out-missing-braces @@ -0,0 +1,37 @@ +Subject: scsi_error: fix indentation and braces disagreement - add braces +From: Ilpo Järvinen +Date: Fri Nov 7 11:18:27 2008 -0600: +Git: 6ec39f02cf48df89c3cbab4aeef521569fec00e4 + +...and the list of recent breakage goes on and on, this time +it's 242f9dcb8ba6f (block: unify request timeout handling) +which broke it. + +Signed-off-by: Ilpo Järvinen +Acked-by: Jens Axboe +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/scsi_error.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -139,7 +139,7 @@ enum blk_eh_timer_return scsi_times_out( + else + eh_timed_out = NULL; + +- if (eh_timed_out) ++ if (eh_timed_out) { + rtn = eh_timed_out(scmd); + switch (rtn) { + case BLK_EH_NOT_HANDLED: +@@ -147,6 +147,7 @@ enum blk_eh_timer_return scsi_times_out( + default: + return rtn; + } ++ } + + if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { + scmd->result |= DID_TIME_OUT << 16; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-enhance-error-codes b/src/patches/suse-2.6.27.31/patches.fixes/scsi-enhance-error-codes new file mode 100644 index 000000000..73f8986ed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-enhance-error-codes @@ -0,0 +1,1116 @@ +From: Mike Christie +Subject: Separate failfast into multiple bits +References: FATE#303485,FATE#303484 + +This is a combined patch from linux-2.6.git. Commit IDs: + +f0c0a376d0fcd4c5579ecf5e95f88387cba85211 +c5e98e912c5423a0ec2eed7aa1064578d44f8a8e +7b594131c4f38edeb13d8c6c0147949173c47013 +d6d13ee19da6d291c99f980dcb76f6b7dc676804 +a93ce0244f2e94dd48e0b4a2742a4e3bf196ab53 +fff9d40ce0eb4b46f3e186823ceab6bc02c3e5d3 +9cc328f502eacfcc52ab1c1bf9a7729cf12f14be +a4dfaa6f2e55b736adf2719133996f7e7dc309bc +56d7fcfa815564b40a1b0ec7a30ea8cb3bc0713e +f46e307da925a7b71a0018c0510cdc6e588b87fc +056a44834950ffa51fafa6c76a720fa32e86851a +6000a368cd8e6da1caf101411bdb494cd6fb8b09 +4a27446f3e39b06c28d1c8e31d33a5340826ed5c + +Signed-off-by: Hannes Reinecke + +--- + block/blk-core.c | 11 ++ + drivers/md/dm-mpath.c | 2 + drivers/md/multipath.c | 4 - + drivers/s390/block/dasd_diag.c | 2 + drivers/s390/block/dasd_eckd.c | 2 + drivers/s390/block/dasd_fba.c | 2 + drivers/scsi/constants.c | 3 + drivers/scsi/device_handler/scsi_dh_alua.c | 3 + drivers/scsi/device_handler/scsi_dh_emc.c | 3 + drivers/scsi/device_handler/scsi_dh_hp_sw.c | 6 + + drivers/scsi/device_handler/scsi_dh_rdac.c | 3 + drivers/scsi/ibmvscsi/ibmvfc.c | 2 + drivers/scsi/libiscsi.c | 16 ++-- + drivers/scsi/lpfc/lpfc_hbadisc.c | 8 -- + drivers/scsi/lpfc/lpfc_scsi.c | 9 +- + drivers/scsi/qla2xxx/qla_attr.c | 1 + drivers/scsi/qla2xxx/qla_isr.c | 14 +++ + drivers/scsi/qla2xxx/qla_os.c | 26 +++--- + drivers/scsi/qla4xxx/ql4_isr.c | 4 - + drivers/scsi/qla4xxx/ql4_os.c | 2 + drivers/scsi/scsi.c | 10 ++ + drivers/scsi/scsi_error.c | 53 +++++++++++++- + drivers/scsi/scsi_lib.c | 106 +++++++++++++++++++++++----- + drivers/scsi/scsi_priv.h | 1 + drivers/scsi/scsi_scan.c | 1 + drivers/scsi/scsi_transport_fc.c | 47 +++++++----- + drivers/scsi/scsi_transport_iscsi.c | 4 - + drivers/scsi/scsi_transport_spi.c | 4 - + include/linux/bio.h | 38 +++++++--- + include/linux/blkdev.h | 15 +++ + include/scsi/scsi.h | 6 + + include/scsi/scsi_device.h | 10 ++ + include/scsi/scsi_transport_fc.h | 8 +- + 33 files changed, 311 insertions(+), 115 deletions(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -1100,8 +1100,15 @@ void init_request_from_bio(struct reques + /* + * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) + */ +- if (bio_rw_ahead(bio) || bio_failfast(bio)) +- req->cmd_flags |= REQ_FAILFAST; ++ if (bio_rw_ahead(bio)) ++ req->cmd_flags |= (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER); ++ if (bio_failfast_dev(bio)) ++ req->cmd_flags |= REQ_FAILFAST_DEV; ++ if (bio_failfast_transport(bio)) ++ req->cmd_flags |= REQ_FAILFAST_TRANSPORT; ++ if (bio_failfast_driver(bio)) ++ req->cmd_flags |= REQ_FAILFAST_DRIVER; + + /* + * REQ_BARRIER implies no merging, but lets make it explicit +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -857,7 +857,7 @@ static int multipath_map(struct dm_targe + dm_bio_record(&mpio->details, bio); + + map_context->ptr = mpio; +- bio->bi_rw |= (1 << BIO_RW_FAILFAST); ++ bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); + r = map_io(m, bio, mpio, 0); + if (r < 0 || r == DM_MAPIO_REQUEUE) + mempool_free(mpio, m->mpio_pool); +--- a/drivers/md/multipath.c ++++ b/drivers/md/multipath.c +@@ -172,7 +172,7 @@ static int multipath_make_request (struc + mp_bh->bio = *bio; + mp_bh->bio.bi_sector += multipath->rdev->data_offset; + mp_bh->bio.bi_bdev = multipath->rdev->bdev; +- mp_bh->bio.bi_rw |= (1 << BIO_RW_FAILFAST); ++ mp_bh->bio.bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); + mp_bh->bio.bi_end_io = multipath_end_request; + mp_bh->bio.bi_private = mp_bh; + generic_make_request(&mp_bh->bio); +@@ -398,7 +398,7 @@ static void multipathd (mddev_t *mddev) + *bio = *(mp_bh->master_bio); + bio->bi_sector += conf->multipaths[mp_bh->path].rdev->data_offset; + bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev; +- bio->bi_rw |= (1 << BIO_RW_FAILFAST); ++ bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); + bio->bi_end_io = multipath_end_request; + bio->bi_private = mp_bh; + generic_make_request(bio); +--- a/drivers/s390/block/dasd_diag.c ++++ b/drivers/s390/block/dasd_diag.c +@@ -544,7 +544,7 @@ static struct dasd_ccw_req *dasd_diag_bu + } + cqr->retries = DIAG_MAX_RETRIES; + cqr->buildclk = get_clock(); +- if (req->cmd_flags & REQ_FAILFAST) ++ if (blk_noretry_request(req)) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = memdev; + cqr->memdev = memdev; +--- a/drivers/s390/block/dasd_eckd.c ++++ b/drivers/s390/block/dasd_eckd.c +@@ -1700,7 +1700,7 @@ static struct dasd_ccw_req *dasd_eckd_bu + recid++; + } + } +- if (req->cmd_flags & REQ_FAILFAST) ++ if (blk_noretry_request(req)) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = startdev; + cqr->memdev = startdev; +--- a/drivers/s390/block/dasd_fba.c ++++ b/drivers/s390/block/dasd_fba.c +@@ -355,7 +355,7 @@ static struct dasd_ccw_req *dasd_fba_bui + recid++; + } + } +- if (req->cmd_flags & REQ_FAILFAST) ++ if (blk_noretry_request(req)) + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->startdev = memdev; + cqr->memdev = memdev; +--- a/drivers/scsi/constants.c ++++ b/drivers/scsi/constants.c +@@ -1364,7 +1364,8 @@ EXPORT_SYMBOL(scsi_print_sense); + static const char * const hostbyte_table[]={ + "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", + "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +-"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"}; ++"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE", ++"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST" }; + #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) + + static const char * const driverbyte_table[]={ +--- a/drivers/scsi/device_handler/scsi_dh_alua.c ++++ b/drivers/scsi/device_handler/scsi_dh_alua.c +@@ -109,7 +109,8 @@ static struct request *get_alua_req(stru + } + + rq->cmd_type = REQ_TYPE_BLOCK_PC; +- rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; ++ rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER | REQ_NOMERGE; + rq->retries = ALUA_FAILOVER_RETRIES; + rq->timeout = ALUA_FAILOVER_TIMEOUT; + +--- a/drivers/scsi/device_handler/scsi_dh_emc.c ++++ b/drivers/scsi/device_handler/scsi_dh_emc.c +@@ -303,7 +303,8 @@ static struct request *get_req(struct sc + + rq->cmd[4] = len; + rq->cmd_type = REQ_TYPE_BLOCK_PC; +- rq->cmd_flags |= REQ_FAILFAST; ++ rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER; + rq->timeout = CLARIION_TIMEOUT; + rq->retries = CLARIION_RETRIES; + +--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c ++++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c +@@ -112,7 +112,8 @@ static int hp_sw_tur(struct scsi_device + return SCSI_DH_RES_TEMP_UNAVAIL; + + req->cmd_type = REQ_TYPE_BLOCK_PC; +- req->cmd_flags |= REQ_FAILFAST; ++ req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER; + req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); + req->cmd[0] = TEST_UNIT_READY; + req->timeout = HP_SW_TIMEOUT; +@@ -204,7 +205,8 @@ static int hp_sw_start_stop(struct scsi_ + return SCSI_DH_RES_TEMP_UNAVAIL; + + req->cmd_type = REQ_TYPE_BLOCK_PC; +- req->cmd_flags |= REQ_FAILFAST; ++ req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER; + req->cmd_len = COMMAND_SIZE(START_STOP); + req->cmd[0] = START_STOP; + req->cmd[4] = 1; /* Start spin cycle */ +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -226,7 +226,8 @@ static struct request *get_rdac_req(stru + } + + rq->cmd_type = REQ_TYPE_BLOCK_PC; +- rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; ++ rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER; + rq->retries = RDAC_RETRIES; + rq->timeout = RDAC_TIMEOUT; + +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -2032,8 +2032,6 @@ static void ibmvfc_terminate_rport_io(st + spin_unlock_irqrestore(shost->host_lock, flags); + } else + ibmvfc_issue_fc_host_lip(shost); +- +- scsi_target_unblock(&rport->dev); + LEAVE; + } + +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -1194,15 +1194,13 @@ int iscsi_queuecommand(struct scsi_cmnd + switch (session->state) { + case ISCSI_STATE_IN_RECOVERY: + reason = FAILURE_SESSION_IN_RECOVERY; +- sc->result = DID_IMM_RETRY << 16; +- break; ++ goto reject; + case ISCSI_STATE_LOGGING_OUT: + reason = FAILURE_SESSION_LOGGING_OUT; +- sc->result = DID_IMM_RETRY << 16; +- break; ++ goto reject; + case ISCSI_STATE_RECOVERY_FAILED: + reason = FAILURE_SESSION_RECOVERY_TIMEOUT; +- sc->result = DID_NO_CONNECT << 16; ++ sc->result = DID_TRANSPORT_FAILFAST << 16; + break; + case ISCSI_STATE_TERMINATE: + reason = FAILURE_SESSION_TERMINATE; +@@ -1267,7 +1265,7 @@ reject: + spin_unlock(&session->lock); + debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); + spin_lock(host->host_lock); +- return SCSI_MLQUEUE_HOST_BUSY; ++ return SCSI_MLQUEUE_TARGET_BUSY; + + fault: + spin_unlock(&session->lock); +@@ -2337,8 +2335,10 @@ static void iscsi_start_session_recovery + * flush queues. + */ + spin_lock_bh(&session->lock); +- fail_all_commands(conn, -1, +- STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); ++ if (STOP_CONN_RECOVER) ++ fail_all_commands(conn, -1, DID_TRANSPORT_DISRUPTED); ++ else ++ fail_all_commands(conn, -1, DID_ERROR); + flush_control_queues(session, conn); + spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -88,14 +88,6 @@ lpfc_terminate_rport_io(struct fc_rport + &phba->sli.ring[phba->sli.fcp_ring], + ndlp->nlp_sid, 0, LPFC_CTX_TGT); + } +- +- /* +- * A device is normally blocked for rediscovery and unblocked when +- * devloss timeout happens. In case a vport is removed or driver +- * unloaded before devloss timeout happens, we need to unblock here. +- */ +- scsi_target_unblock(&rport->dev); +- return; + } + + /* +--- a/drivers/scsi/lpfc/lpfc_scsi.c ++++ b/drivers/scsi/lpfc/lpfc_scsi.c +@@ -966,10 +966,9 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd + * Catch race where our node has transitioned, but the + * transport is still transitioning. + */ +- if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { +- cmnd->result = ScsiResult(DID_BUS_BUSY, 0); +- goto out_fail_command; +- } ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) ++ goto out_target_busy; ++ + lpfc_cmd = lpfc_get_scsi_buf(phba); + if (lpfc_cmd == NULL) { + lpfc_adjust_queue_depth(phba); +@@ -1014,6 +1013,8 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd + lpfc_release_scsi_buf(phba, lpfc_cmd); + out_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; ++ out_target_busy: ++ return SCSI_MLQUEUE_TARGET_BUSY; + + out_fail_command: + done(cmnd); +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -1005,7 +1005,6 @@ qla2x00_terminate_rport_io(struct fc_rpo + } + + qla2x00_abort_fcport_cmds(fcport); +- scsi_target_unblock(&rport->dev); + } + + static int +--- a/drivers/scsi/qla2xxx/qla_isr.c ++++ b/drivers/scsi/qla2xxx/qla_isr.c +@@ -1184,7 +1184,12 @@ qla2x00_status_entry(scsi_qla_host_t *ha + cp->serial_number, comp_status, + atomic_read(&fcport->state))); + +- cp->result = DID_BUS_BUSY << 16; ++ /* ++ * We are going to have the fc class block the rport ++ * while we try to recover so instruct the mid layer ++ * to requeue until the class decides how to handle this. ++ */ ++ cp->result = DID_TRANSPORT_DISRUPTED << 16; + if (atomic_read(&fcport->state) == FCS_ONLINE) + qla2x00_mark_device_lost(fcport->ha, fcport, 1, 1); + break; +@@ -1211,7 +1216,12 @@ qla2x00_status_entry(scsi_qla_host_t *ha + break; + + case CS_TIMEOUT: +- cp->result = DID_BUS_BUSY << 16; ++ /* ++ * We are going to have the fc class block the rport ++ * while we try to recover so instruct the mid layer ++ * to requeue until the class decides how to handle this. ++ */ ++ cp->result = DID_TRANSPORT_DISRUPTED << 16; + + if (IS_FWI2_CAPABLE(ha)) { + DEBUG2(printk(KERN_INFO +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -394,10 +394,8 @@ qla2x00_queuecommand(struct scsi_cmnd *c + } + + /* Close window on fcport/rport state-transitioning. */ +- if (fcport->drport) { +- cmd->result = DID_IMM_RETRY << 16; +- goto qc_fail_command; +- } ++ if (fcport->drport) ++ goto qc_target_busy; + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || +@@ -405,7 +403,7 @@ qla2x00_queuecommand(struct scsi_cmnd *c + cmd->result = DID_NO_CONNECT << 16; + goto qc_fail_command; + } +- goto qc_host_busy; ++ goto qc_target_busy; + } + + spin_unlock_irq(ha->host->host_lock); +@@ -428,10 +426,11 @@ qc_host_busy_free_sp: + + qc_host_busy_lock: + spin_lock_irq(ha->host->host_lock); +- +-qc_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; + ++qc_target_busy: ++ return SCSI_MLQUEUE_TARGET_BUSY; ++ + qc_fail_command: + done(cmd); + +@@ -461,10 +460,8 @@ qla24xx_queuecommand(struct scsi_cmnd *c + } + + /* Close window on fcport/rport state-transitioning. */ +- if (fcport->drport) { +- cmd->result = DID_IMM_RETRY << 16; +- goto qc24_fail_command; +- } ++ if (fcport->drport) ++ goto qc24_target_busy; + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || +@@ -472,7 +469,7 @@ qla24xx_queuecommand(struct scsi_cmnd *c + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } +- goto qc24_host_busy; ++ goto qc24_target_busy; + } + + spin_unlock_irq(ha->host->host_lock); +@@ -495,10 +492,11 @@ qc24_host_busy_free_sp: + + qc24_host_busy_lock: + spin_lock_irq(ha->host->host_lock); +- +-qc24_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; + ++qc24_target_busy: ++ return SCSI_MLQUEUE_TARGET_BUSY; ++ + qc24_fail_command: + done(cmd); + +--- a/drivers/scsi/qla4xxx/ql4_isr.c ++++ b/drivers/scsi/qla4xxx/ql4_isr.c +@@ -139,7 +139,7 @@ static void qla4xxx_status_entry(struct + ha->host_no, cmd->device->channel, + cmd->device->id, cmd->device->lun)); + +- cmd->result = DID_BUS_BUSY << 16; ++ cmd->result = DID_TRANSPORT_DISRUPTED << 16; + + /* + * Mark device missing so that we won't continue to send +@@ -243,7 +243,7 @@ static void qla4xxx_status_entry(struct + if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) + qla4xxx_mark_device_missing(ha, ddb_entry); + +- cmd->result = DID_BUS_BUSY << 16; ++ cmd->result = DID_TRANSPORT_DISRUPTED << 16; + break; + + case SCS_QUEUE_FULL: +--- a/drivers/scsi/qla4xxx/ql4_os.c ++++ b/drivers/scsi/qla4xxx/ql4_os.c +@@ -439,7 +439,7 @@ static int qla4xxx_queuecommand(struct s + cmd->result = DID_NO_CONNECT << 16; + goto qc_fail_command; + } +- goto qc_host_busy; ++ return SCSI_MLQUEUE_TARGET_BUSY; + } + + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -754,8 +754,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + } + spin_unlock_irqrestore(host->host_lock, flags); + if (rtn) { +- scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? +- rtn : SCSI_MLQUEUE_HOST_BUSY); ++ if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && ++ rtn != SCSI_MLQUEUE_TARGET_BUSY) ++ rtn = SCSI_MLQUEUE_HOST_BUSY; ++ ++ scsi_queue_insert(cmd, rtn); ++ + SCSI_LOG_MLQUEUE(3, + printk("queuecommand : request rejected\n")); + } +@@ -800,6 +804,7 @@ static struct scsi_driver *scsi_cmd_to_d + void scsi_finish_command(struct scsi_cmnd *cmd) + { + struct scsi_device *sdev = cmd->device; ++ struct scsi_target *starget = scsi_target(sdev); + struct Scsi_Host *shost = sdev->host; + struct scsi_driver *drv; + unsigned int good_bytes; +@@ -815,6 +820,7 @@ void scsi_finish_command(struct scsi_cmn + * XXX(hch): What about locking? + */ + shost->host_blocked = 0; ++ starget->target_blocked = 0; + sdev->device_blocked = 0; + + /* +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -1219,6 +1219,40 @@ static void scsi_eh_offline_sdevs(struct + } + + /** ++ * scsi_noretry_cmd - determinte if command should be failed fast ++ * @scmd: SCSI cmd to examine. ++ */ ++int scsi_noretry_cmd(struct scsi_cmnd *scmd) ++{ ++ switch (host_byte(scmd->result)) { ++ case DID_OK: ++ break; ++ case DID_BUS_BUSY: ++ return blk_failfast_transport(scmd->request); ++ case DID_PARITY: ++ return blk_failfast_dev(scmd->request); ++ case DID_ERROR: ++ if (msg_byte(scmd->result) == COMMAND_COMPLETE && ++ status_byte(scmd->result) == RESERVATION_CONFLICT) ++ return 0; ++ /* fall through */ ++ case DID_SOFT_ERROR: ++ return blk_failfast_driver(scmd->request); ++ } ++ ++ switch (status_byte(scmd->result)) { ++ case CHECK_CONDITION: ++ /* ++ * assume caller has checked sense and determinted ++ * the check condition was retryable. ++ */ ++ return blk_failfast_dev(scmd->request); ++ } ++ ++ return 0; ++} ++ ++/** + * scsi_decide_disposition - Disposition a cmd on return from LLD. + * @scmd: SCSI cmd to examine. + * +@@ -1290,7 +1324,20 @@ int scsi_decide_disposition(struct scsi_ + + case DID_REQUEUE: + return ADD_TO_MLQUEUE; +- ++ case DID_TRANSPORT_DISRUPTED: ++ /* ++ * LLD/transport was disrupted during processing of the IO. ++ * The transport class is now blocked/blocking, ++ * and the transport will decide what to do with the IO ++ * based on its timers and recovery capablilities. ++ */ ++ return ADD_TO_MLQUEUE; ++ case DID_TRANSPORT_FAILFAST: ++ /* ++ * The transport decided to failfast the IO (most likely ++ * the fast io fail tmo fired), so send IO directly upwards. ++ */ ++ return SUCCESS; + case DID_ERROR: + if (msg_byte(scmd->result) == COMMAND_COMPLETE && + status_byte(scmd->result) == RESERVATION_CONFLICT) +@@ -1383,7 +1430,7 @@ int scsi_decide_disposition(struct scsi_ + * even if the request is marked fast fail, we still requeue + * for queue congestion conditions (QUEUE_FULL or BUSY) */ + if ((++scmd->retries) <= scmd->allowed +- && !blk_noretry_request(scmd->request)) { ++ && !scsi_noretry_cmd(scmd)) { + return NEEDS_RETRY; + } else { + /* +@@ -1508,7 +1555,7 @@ void scsi_eh_flush_done_q(struct list_he + list_for_each_entry_safe(scmd, next, done_q, eh_entry) { + list_del_init(&scmd->eh_entry); + if (scsi_device_online(scmd->device) && +- !blk_noretry_request(scmd->request) && ++ !scsi_noretry_cmd(scmd) && + (++scmd->retries <= scmd->allowed)) { + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush" + " retry cmd: %p\n", +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -114,6 +114,7 @@ int scsi_queue_insert(struct scsi_cmnd * + { + struct Scsi_Host *host = cmd->device->host; + struct scsi_device *device = cmd->device; ++ struct scsi_target *starget = scsi_target(device); + struct request_queue *q = device->request_queue; + unsigned long flags; + +@@ -133,10 +134,17 @@ int scsi_queue_insert(struct scsi_cmnd * + * if a command is requeued with no other commands outstanding + * either for the device or for the host. + */ +- if (reason == SCSI_MLQUEUE_HOST_BUSY) ++ switch (reason) { ++ case SCSI_MLQUEUE_HOST_BUSY: + host->host_blocked = host->max_host_blocked; +- else if (reason == SCSI_MLQUEUE_DEVICE_BUSY) ++ break; ++ case SCSI_MLQUEUE_DEVICE_BUSY: + device->device_blocked = device->max_device_blocked; ++ break; ++ case SCSI_MLQUEUE_TARGET_BUSY: ++ starget->target_blocked = starget->max_target_blocked; ++ break; ++ } + + /* + * Decrement the counters, since these commands are no longer +@@ -460,10 +468,12 @@ static void scsi_init_cmd_errh(struct sc + void scsi_device_unbusy(struct scsi_device *sdev) + { + struct Scsi_Host *shost = sdev->host; ++ struct scsi_target *starget = scsi_target(sdev); + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + shost->host_busy--; ++ starget->target_busy--; + if (unlikely(scsi_host_in_recovery(shost) && + (shost->host_failed || shost->host_eh_scheduled))) + scsi_eh_wakeup(shost); +@@ -519,6 +529,13 @@ static void scsi_single_lun_run(struct s + spin_unlock_irqrestore(shost->host_lock, flags); + } + ++static inline int scsi_target_is_busy(struct scsi_target *starget) ++{ ++ return ((starget->can_queue > 0 && ++ starget->target_busy >= starget->can_queue) || ++ starget->target_blocked); ++} ++ + /* + * Function: scsi_run_queue() + * +@@ -533,7 +550,7 @@ static void scsi_single_lun_run(struct s + */ + static void scsi_run_queue(struct request_queue *q) + { +- struct scsi_device *sdev = q->queuedata; ++ struct scsi_device *starved_head = NULL, *sdev = q->queuedata; + struct Scsi_Host *shost = sdev->host; + unsigned long flags; + +@@ -560,6 +577,21 @@ static void scsi_run_queue(struct reques + */ + sdev = list_entry(shost->starved_list.next, + struct scsi_device, starved_entry); ++ /* ++ * The *queue_ready functions can add a device back onto the ++ * starved list's tail, so we must check for a infinite loop. ++ */ ++ if (sdev == starved_head) ++ break; ++ if (!starved_head) ++ starved_head = sdev; ++ ++ if (scsi_target_is_busy(scsi_target(sdev))) { ++ list_move_tail(&sdev->starved_entry, ++ &shost->starved_list); ++ continue; ++ } ++ + list_del_init(&sdev->starved_entry); + spin_unlock(shost->host_lock); + +@@ -575,13 +607,6 @@ static void scsi_run_queue(struct reques + spin_unlock(sdev->request_queue->queue_lock); + + spin_lock(shost->host_lock); +- if (unlikely(!list_empty(&sdev->starved_entry))) +- /* +- * sdev lost a race, and was put back on the +- * starved list. This is unlikely but without this +- * in theory we could loop forever. +- */ +- break; + } + spin_unlock_irqrestore(shost->host_lock, flags); + +@@ -681,7 +706,7 @@ static struct scsi_cmnd *scsi_end_reques + leftover = req->data_len; + + /* kill remainder if no retrys */ +- if (error && blk_noretry_request(req)) ++ if (error && scsi_noretry_cmd(cmd)) + blk_end_request(req, error, leftover); + else { + if (requeue) { +@@ -1344,6 +1369,52 @@ static inline int scsi_dev_queue_ready(s + return 1; + } + ++ ++/* ++ * scsi_target_queue_ready: checks if there we can send commands to target ++ * @sdev: scsi device on starget to check. ++ * ++ * Called with the host lock held. ++ */ ++static inline int scsi_target_queue_ready(struct Scsi_Host *shost, ++ struct scsi_device *sdev) ++{ ++ struct scsi_target *starget = scsi_target(sdev); ++ ++ if (starget->single_lun) { ++ if (starget->starget_sdev_user && ++ starget->starget_sdev_user != sdev) ++ return 0; ++ starget->starget_sdev_user = sdev; ++ } ++ ++ if (starget->target_busy == 0 && starget->target_blocked) { ++ /* ++ * unblock after target_blocked iterates to zero ++ */ ++ if (--starget->target_blocked == 0) { ++ SCSI_LOG_MLQUEUE(3, starget_printk(KERN_INFO, starget, ++ "unblocking target at zero depth\n")); ++ } else { ++ blk_plug_device(sdev->request_queue); ++ return 0; ++ } ++ } ++ ++ if (scsi_target_is_busy(starget)) { ++ if (list_empty(&sdev->starved_entry)) { ++ list_add_tail(&sdev->starved_entry, ++ &shost->starved_list); ++ return 0; ++ } ++ } ++ ++ /* We're OK to process the command, so we can't be starved */ ++ if (!list_empty(&sdev->starved_entry)) ++ list_del_init(&sdev->starved_entry); ++ return 1; ++} ++ + /* + * scsi_host_queue_ready: if we can send requests to shost, return 1 else + * return 0. We must end up running the queue again whenever 0 is +@@ -1390,6 +1461,7 @@ static void scsi_kill_request(struct req + { + struct scsi_cmnd *cmd = req->special; + struct scsi_device *sdev = cmd->device; ++ struct scsi_target *starget = scsi_target(sdev); + struct Scsi_Host *shost = sdev->host; + + blkdev_dequeue_request(req); +@@ -1413,6 +1485,7 @@ static void scsi_kill_request(struct req + spin_unlock(sdev->request_queue->queue_lock); + spin_lock(shost->host_lock); + shost->host_busy++; ++ starget->target_busy++; + spin_unlock(shost->host_lock); + spin_lock(sdev->request_queue->queue_lock); + +@@ -1550,14 +1623,13 @@ static void scsi_request_fn(struct reque + goto not_ready; + } + ++ if (!scsi_target_queue_ready(shost, sdev)) ++ goto not_ready; ++ + if (!scsi_host_queue_ready(q, shost, sdev)) + goto not_ready; +- if (scsi_target(sdev)->single_lun) { +- if (scsi_target(sdev)->starget_sdev_user && +- scsi_target(sdev)->starget_sdev_user != sdev) +- goto not_ready; +- scsi_target(sdev)->starget_sdev_user = sdev; +- } ++ ++ scsi_target(sdev)->target_busy++; + shost->host_busy++; + + /* +--- a/drivers/scsi/scsi_priv.h ++++ b/drivers/scsi/scsi_priv.h +@@ -59,6 +59,7 @@ void scsi_eh_ready_devs(struct Scsi_Host + struct list_head *done_q); + int scsi_eh_get_sense(struct list_head *work_q, + struct list_head *done_q); ++int scsi_noretry_cmd(struct scsi_cmnd *scmd); + + /* scsi_lib.c */ + extern int scsi_maybe_unblock_host(struct scsi_device *sdev); +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -419,6 +419,7 @@ static struct scsi_target *scsi_alloc_ta + dev->type = &scsi_target_type; + starget->id = id; + starget->channel = channel; ++ starget->can_queue = 0; + INIT_LIST_HEAD(&starget->siblings); + INIT_LIST_HEAD(&starget->devices); + starget->state = STARGET_CREATED; +--- a/drivers/scsi/scsi_transport_fc.c ++++ b/drivers/scsi/scsi_transport_fc.c +@@ -2133,8 +2133,7 @@ fc_attach_transport(struct fc_function_t + SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles); + SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state); + SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id); +- if (ft->terminate_rport_io) +- SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo); ++ SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo); + + BUG_ON(count > FC_RPORT_NUM_ATTRS); + +@@ -2328,6 +2327,22 @@ fc_remove_host(struct Scsi_Host *shost) + } + EXPORT_SYMBOL(fc_remove_host); + ++static void fc_terminate_rport_io(struct fc_rport *rport) ++{ ++ struct Scsi_Host *shost = rport_to_shost(rport); ++ struct fc_internal *i = to_fc_internal(shost->transportt); ++ ++ /* Involve the LLDD if possible to terminate all io on the rport. */ ++ if (i->f->terminate_rport_io) ++ i->f->terminate_rport_io(rport); ++ ++ /* ++ * must unblock to flush queued IO. The caller will have set ++ * the port_state or flags, so that fc_remote_port_chkready will ++ * fail IO. ++ */ ++ scsi_target_unblock(&rport->dev); ++} + + /** + * fc_starget_delete - called to delete the scsi decendents of an rport +@@ -2340,13 +2355,8 @@ fc_starget_delete(struct work_struct *wo + { + struct fc_rport *rport = + container_of(work, struct fc_rport, stgt_delete_work); +- struct Scsi_Host *shost = rport_to_shost(rport); +- struct fc_internal *i = to_fc_internal(shost->transportt); +- +- /* Involve the LLDD if possible to terminate all io on the rport. */ +- if (i->f->terminate_rport_io) +- i->f->terminate_rport_io(rport); + ++ fc_terminate_rport_io(rport); + scsi_remove_target(&rport->dev); + } + +@@ -2372,10 +2382,7 @@ fc_rport_final_delete(struct work_struct + if (rport->flags & FC_RPORT_SCAN_PENDING) + scsi_flush_work(shost); + +- /* involve the LLDD to terminate all pending i/o */ +- if (i->f->terminate_rport_io) +- i->f->terminate_rport_io(rport); +- ++ fc_terminate_rport_io(rport); + /* + * Cancel any outstanding timers. These should really exist + * only when rmmod'ing the LLDD and we're asking for +@@ -2639,7 +2646,8 @@ fc_remote_port_add(struct Scsi_Host *sho + + spin_lock_irqsave(shost->host_lock, flags); + +- rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; ++ rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | ++ FC_RPORT_DEVLOSS_PENDING); + + /* if target, initiate a scan */ + if (rport->scsi_target_id != -1) { +@@ -2702,6 +2710,7 @@ fc_remote_port_add(struct Scsi_Host *sho + rport->port_id = ids->port_id; + rport->roles = ids->roles; + rport->port_state = FC_PORTSTATE_ONLINE; ++ rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; + + if (fci->f->dd_fcrport_size) + memset(rport->dd_data, 0, +@@ -2784,7 +2793,6 @@ void + fc_remote_port_delete(struct fc_rport *rport) + { + struct Scsi_Host *shost = rport_to_shost(rport); +- struct fc_internal *i = to_fc_internal(shost->transportt); + int timeout = rport->dev_loss_tmo; + unsigned long flags; + +@@ -2830,7 +2838,7 @@ fc_remote_port_delete(struct fc_rport * + + /* see if we need to kill io faster than waiting for device loss */ + if ((rport->fast_io_fail_tmo != -1) && +- (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io)) ++ (rport->fast_io_fail_tmo < timeout)) + fc_queue_devloss_work(shost, &rport->fail_io_work, + rport->fast_io_fail_tmo * HZ); + +@@ -2906,7 +2914,8 @@ fc_remote_port_rolechg(struct fc_rport + fc_flush_devloss(shost); + + spin_lock_irqsave(shost->host_lock, flags); +- rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; ++ rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | ++ FC_RPORT_DEVLOSS_PENDING); + spin_unlock_irqrestore(shost->host_lock, flags); + + /* ensure any stgt delete functions are done */ +@@ -3001,6 +3010,7 @@ fc_timeout_deleted_rport(struct work_str + rport->supported_classes = FC_COS_UNSPECIFIED; + rport->roles = FC_PORT_ROLE_UNKNOWN; + rport->port_state = FC_PORTSTATE_NOTPRESENT; ++ rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; + + /* remove the identifiers that aren't used in the consisting binding */ + switch (fc_host->tgtid_bind_type) { +@@ -3043,13 +3053,12 @@ fc_timeout_fail_rport_io(struct work_str + { + struct fc_rport *rport = + container_of(work, struct fc_rport, fail_io_work.work); +- struct Scsi_Host *shost = rport_to_shost(rport); +- struct fc_internal *i = to_fc_internal(shost->transportt); + + if (rport->port_state != FC_PORTSTATE_BLOCKED) + return; + +- i->f->terminate_rport_io(rport); ++ rport->flags |= FC_RPORT_FAST_FAIL_TIMEDOUT; ++ fc_terminate_rport_io(rport); + } + + /** +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -374,10 +374,10 @@ int iscsi_session_chkready(struct iscsi_ + err = 0; + break; + case ISCSI_SESSION_FAILED: +- err = DID_IMM_RETRY << 16; ++ err = DID_TRANSPORT_DISRUPTED << 16; + break; + case ISCSI_SESSION_FREE: +- err = DID_NO_CONNECT << 16; ++ err = DID_TRANSPORT_FAILFAST << 16; + break; + default: + err = DID_NO_CONNECT << 16; +--- a/drivers/scsi/scsi_transport_spi.c ++++ b/drivers/scsi/scsi_transport_spi.c +@@ -109,7 +109,9 @@ static int spi_execute(struct scsi_devic + for(i = 0; i < DV_RETRIES; i++) { + result = scsi_execute(sdev, cmd, dir, buffer, bufflen, + sense, DV_TIMEOUT, /* retries */ 1, +- REQ_FAILFAST); ++ REQ_FAILFAST_DEV | ++ REQ_FAILFAST_TRANSPORT | ++ REQ_FAILFAST_DRIVER); + if (result & DRIVER_SENSE) { + struct scsi_sense_hdr sshdr_tmp; + if (!sshdr) +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -130,21 +130,36 @@ struct bio { + /* + * bio bi_rw flags + * +- * bit 0 -- read (not set) or write (set) ++ * bit 0 -- data direction ++ * If not set, bio is a read from device. If set, it's a write to device. + * bit 1 -- rw-ahead when set + * bit 2 -- barrier +- * bit 3 -- fail fast, don't want low level driver retries +- * bit 4 -- synchronous I/O hint: the block layer will unplug immediately +- * bit 5 -- metadata request +- * bit 6 -- discard sectors ++ * Insert a serialization point in the IO queue, forcing previously ++ * submitted IO to be completed before this oen is issued. ++ * bit 3 -- synchronous I/O hint: the block layer will unplug immediately ++ * Note that this does NOT indicate that the IO itself is sync, just ++ * that the block layer will not postpone issue of this IO by plugging. ++ * bit 4 -- metadata request ++ * Used for tracing to differentiate metadata and data IO. May also ++ * get some preferential treatment in the IO scheduler ++ * bit 5 -- discard sectors ++ * Informs the lower level device that this range of sectors is no longer ++ * used by the file system and may thus be freed by the device. Used ++ * for flash based storage. ++ * bit 6 -- fail fast device errors ++ * bit 7 -- fail fast transport errors ++ * bit 8 -- fail fast driver errors ++ * Don't want driver retries for any fast fail whatever the reason. + */ + #define BIO_RW 0 /* Must match RW in req flags (blkdev.h) */ + #define BIO_RW_AHEAD 1 /* Must match FAILFAST in req flags */ + #define BIO_RW_BARRIER 2 +-#define BIO_RW_FAILFAST 3 +-#define BIO_RW_SYNC 4 +-#define BIO_RW_META 5 +-#define BIO_RW_DISCARD 6 ++#define BIO_RW_SYNC 3 ++#define BIO_RW_META 4 ++#define BIO_RW_DISCARD 5 ++#define BIO_RW_FAILFAST_DEV 6 ++#define BIO_RW_FAILFAST_TRANSPORT 7 ++#define BIO_RW_FAILFAST_DRIVER 8 + + /* + * upper 16 bits of bi_rw define the io priority of this bio +@@ -171,7 +186,10 @@ struct bio { + #define bio_sectors(bio) ((bio)->bi_size >> 9) + #define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_RW_BARRIER)) + #define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC)) +-#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) ++#define bio_failfast_dev(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST_DEV)) ++#define bio_failfast_transport(bio) \ ++ ((bio)->bi_rw & (1 << BIO_RW_FAILFAST_TRANSPORT)) ++#define bio_failfast_driver(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST_DRIVER)) + #define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) + #define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) + #define bio_discard(bio) ((bio)->bi_rw & (1 << BIO_RW_DISCARD)) +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -86,7 +86,9 @@ enum { + */ + enum rq_flag_bits { + __REQ_RW, /* not set, read. set, write */ +- __REQ_FAILFAST, /* no low level driver retries */ ++ __REQ_FAILFAST_DEV, /* no driver retries of device errors */ ++ __REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */ ++ __REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */ + __REQ_DISCARD, /* request to discard sectors */ + __REQ_SORTED, /* elevator knows about this request */ + __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ +@@ -110,8 +112,10 @@ enum rq_flag_bits { + }; + + #define REQ_RW (1 << __REQ_RW) ++#define REQ_FAILFAST_DEV (1 << __REQ_FAILFAST_DEV) ++#define REQ_FAILFAST_TRANSPORT (1 << __REQ_FAILFAST_TRANSPORT) ++#define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER) + #define REQ_DISCARD (1 << __REQ_DISCARD) +-#define REQ_FAILFAST (1 << __REQ_FAILFAST) + #define REQ_SORTED (1 << __REQ_SORTED) + #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) + #define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER) +@@ -551,7 +555,12 @@ enum { + #define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL) + #define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE) + +-#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST) ++#define blk_failfast_dev(rq) ((rq)->cmd_flags & REQ_FAILFAST_DEV) ++#define blk_failfast_transport(rq) ((rq)->cmd_flags & REQ_FAILFAST_TRANSPORT) ++#define blk_failfast_driver(rq) ((rq)->cmd_flags & REQ_FAILFAST_DRIVER) ++#define blk_noretry_request(rq) (blk_failfast_dev(rq) || \ ++ blk_failfast_transport(rq) || \ ++ blk_failfast_driver(rq)) + #define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED) + + #define blk_account_rq(rq) (blk_rq_started(rq) && (blk_fs_request(rq) || blk_discard_rq(rq))) +--- a/include/scsi/scsi.h ++++ b/include/scsi/scsi.h +@@ -381,6 +381,11 @@ static inline int scsi_is_wlun(unsigned + #define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ + #define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also + * without decrementing the retry count */ ++#define DID_TRANSPORT_DISRUPTED 0x0e /* Transport error disrupted execution ++ * and the driver blocked the port to ++ * recover the link. Transport class will ++ * retry or fail IO */ ++#define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */ + #define DRIVER_OK 0x00 /* Driver status */ + + /* +@@ -426,6 +431,7 @@ static inline int scsi_is_wlun(unsigned + #define SCSI_MLQUEUE_HOST_BUSY 0x1055 + #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 + #define SCSI_MLQUEUE_EH_RETRY 0x1057 ++#define SCSI_MLQUEUE_TARGET_BUSY 0x1058 + + /* + * Use these to separate status msg and our bytes +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -238,6 +238,16 @@ struct scsi_target { + * for the device at a time. */ + unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */ + /* means no lun present */ ++ /* commands actually active on LLD. protected by host lock. */ ++ unsigned int target_busy; ++ /* ++ * LLDs should set this in the slave_alloc host template callout. ++ * If set to zero then there is not limit. ++ */ ++ unsigned int can_queue; ++ unsigned int target_blocked; ++ unsigned int max_target_blocked; ++#define SCSI_DEFAULT_TARGET_BLOCKED 3 + + char scsi_level; + struct execute_work ew; +--- a/include/scsi/scsi_transport_fc.h ++++ b/include/scsi/scsi_transport_fc.h +@@ -357,6 +357,7 @@ struct fc_rport { /* aka fc_starget_attr + /* bit field values for struct fc_rport "flags" field: */ + #define FC_RPORT_DEVLOSS_PENDING 0x01 + #define FC_RPORT_SCAN_PENDING 0x02 ++#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x03 + + #define dev_to_rport(d) \ + container_of(d, struct fc_rport, dev) +@@ -678,12 +679,15 @@ fc_remote_port_chkready(struct fc_rport + if (rport->roles & FC_PORT_ROLE_FCP_TARGET) + result = 0; + else if (rport->flags & FC_RPORT_DEVLOSS_PENDING) +- result = DID_IMM_RETRY << 16; ++ result = DID_TRANSPORT_DISRUPTED << 16; + else + result = DID_NO_CONNECT << 16; + break; + case FC_PORTSTATE_BLOCKED: +- result = DID_IMM_RETRY << 16; ++ if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) ++ result = DID_TRANSPORT_FAILFAST << 16; ++ else ++ result = DID_TRANSPORT_DISRUPTED << 16; + break; + default: + result = DID_NO_CONNECT << 16; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-fix-hang-in-starved-list-processing b/src/patches/suse-2.6.27.31/patches.fixes/scsi-fix-hang-in-starved-list-processing new file mode 100644 index 000000000..89b1dc27d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-fix-hang-in-starved-list-processing @@ -0,0 +1,79 @@ +Subject: [SCSI] Fix hang in starved list processing +From: Mike Christie +Date: Sun Nov 16 08:13:58 2008 -0600: +Git: 2a3a59e5c977654d3aad5bc11cc0aca2303a7f44 +References: bnc#464155 + +Close possible infinite loop with interrupts off when devices are +added back to the starved list. + +Fixes: http://bugzilla.kernel.org/show_bug.cgi?id=11898 + +Reported-by: +Signed-off-by: Mike Christie +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index f5d3b96..fa45a1a 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -567,15 +567,18 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost) + */ + static void scsi_run_queue(struct request_queue *q) + { +- struct scsi_device *starved_head = NULL, *sdev = q->queuedata; ++ struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost = sdev->host; ++ LIST_HEAD(starved_list); + unsigned long flags; + + if (scsi_target(sdev)->single_lun) + scsi_single_lun_run(sdev); + + spin_lock_irqsave(shost->host_lock, flags); +- while (!list_empty(&shost->starved_list) && !scsi_host_is_busy(shost)) { ++ list_splice_init(&shost->starved_list, &starved_list); ++ ++ while (!list_empty(&starved_list)) { + int flagset; + + /* +@@ -588,24 +591,18 @@ static void scsi_run_queue(struct request_queue *q) + * scsi_request_fn must get the host_lock before checking + * or modifying starved_list or starved_entry. + */ +- sdev = list_entry(shost->starved_list.next, +- struct scsi_device, starved_entry); +- /* +- * The *queue_ready functions can add a device back onto the +- * starved list's tail, so we must check for a infinite loop. +- */ +- if (sdev == starved_head) ++ if (scsi_host_is_busy(shost)) + break; +- if (!starved_head) +- starved_head = sdev; + ++ sdev = list_entry(starved_list.next, ++ struct scsi_device, starved_entry); ++ list_del_init(&sdev->starved_entry); + if (scsi_target_is_busy(scsi_target(sdev))) { + list_move_tail(&sdev->starved_entry, + &shost->starved_list); + continue; + } + +- list_del_init(&sdev->starved_entry); + spin_unlock(shost->host_lock); + + spin_lock(sdev->request_queue->queue_lock); +@@ -621,6 +618,8 @@ static void scsi_run_queue(struct request_queue *q) + + spin_lock(shost->host_lock); + } ++ /* put any unprocessed entries back */ ++ list_splice(&starved_list, &shost->starved_list); + spin_unlock_irqrestore(shost->host_lock, flags); + + blk_run_queue(q); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-fixup-failfast-definitions b/src/patches/suse-2.6.27.31/patches.fixes/scsi-fixup-failfast-definitions new file mode 100644 index 000000000..a8e74c82e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-fixup-failfast-definitions @@ -0,0 +1,28 @@ +From: James Smart +Date: Thu, 20 Nov 2008 15:58:01 +0000 (-0500) +Subject: fc_transport: fix old bug on bitflag definitions +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjejb%2Fscsi-rc-fixes-2.6.git;a=commitdiff_plain;h=21098c68df7115554fe041170899bdff709efd08 +References: bnc#447814 + +When the fastfail flag was added, it did not account for the flags +being bit fields. Correct the definition so there is no longer a +conflict. + +Signed-off-by: James Smart +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke +--- + +diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h +index 49d8913..6e04e6f 100644 +--- a/include/scsi/scsi_transport_fc.h ++++ b/include/scsi/scsi_transport_fc.h +@@ -357,7 +357,7 @@ struct fc_rport { /* aka fc_starget_attrs */ + /* bit field values for struct fc_rport "flags" field: */ + #define FC_RPORT_DEVLOSS_PENDING 0x01 + #define FC_RPORT_SCAN_PENDING 0x02 +-#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x03 ++#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x04 + + #define dev_to_rport(d) \ + container_of(d, struct fc_rport, dev) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-fixup-scsi_host_lookup-return-value b/src/patches/suse-2.6.27.31/patches.fixes/scsi-fixup-scsi_host_lookup-return-value new file mode 100644 index 000000000..7d93b8836 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-fixup-scsi_host_lookup-return-value @@ -0,0 +1,31 @@ +From: Hannes Reinecke +Subject: Fixup return value in scsi_host_lookup() +References: bnc#468654 + +scsi_host_lookup should always return an ERR_PTR() value if +it fails. This has changed in mainline where it returns a +NULL pointer on failure, but changing it now would be a +nasty kabi breakage. So stick with the established usage. + +Signed-off-by: Hannes Reinecke + +--- linux-2.6.27-SLE11_BRANCH/drivers/scsi/hosts.c.orig 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH/drivers/scsi/hosts.c 2009-02-05 11:23:43.910605056 +0100 +@@ -464,7 +464,7 @@ static int __scsi_host_match(struct devi + struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) + { + struct device *cdev; +- struct Scsi_Host *shost = ERR_PTR(-ENXIO); ++ struct Scsi_Host *shost = NULL; + + cdev = class_find_device(&shost_class, NULL, &hostnum, + __scsi_host_match); +@@ -472,7 +472,7 @@ struct Scsi_Host *scsi_host_lookup(unsig + shost = scsi_host_get(class_to_shost(cdev)); + put_device(cdev); + } +- return shost; ++ return shost ? shost : ERR_PTR(-ENXIO); + } + EXPORT_SYMBOL(scsi_host_lookup); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-can_queue_fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-can_queue_fix.patch new file mode 100644 index 000000000..8b23dec1b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-can_queue_fix.patch @@ -0,0 +1,90 @@ +Subject: Make max_requests module parameter more accurate +From: Brian King +References: 458499 - LTC50637 + +In a previous patch to fix an issue with error recovery, +the behavior of the max_requests module paramater was also +changed. If, for some reason, max_requests is set to one by +the user, we will end up with a negative number for can_queue. +Fix this by making max_requests not include the two event structs +needed to do error recovery. + +Signed-off-by: Brian King +Signed-off-by: Olaf Hering + +--- + drivers/scsi/ibmvscsi/ibmvscsi.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvscsi.c ++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c +@@ -89,6 +89,8 @@ static int max_id = 64; + static int max_channel = 3; + static int init_timeout = 5; + static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; ++static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2; ++ + /*host data buffer size*/ + #define buff_size 4096 + +@@ -1635,7 +1637,7 @@ static struct scsi_host_template driver_ + static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) + { + /* iu_storage data allocated in initialize_event_pool */ +- unsigned long desired_io = max_requests * sizeof(union viosrp_iu); ++ unsigned long desired_io = max_events * sizeof(union viosrp_iu); + + /* add io space for sg data */ + desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 * +@@ -1659,7 +1661,6 @@ static int ibmvscsi_probe(struct vio_dev + + vdev->dev.driver_data = NULL; + +- driver_template.can_queue = max_requests; + host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); + if (!host) { + dev_err(&vdev->dev, "couldn't allocate host data\n"); +@@ -1675,12 +1676,12 @@ static int ibmvscsi_probe(struct vio_dev + atomic_set(&hostdata->request_limit, -1); + hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT; + +- rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests); ++ rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events); + if (rc != 0 && rc != H_RESOURCE) { + dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); + goto init_crq_failed; + } +- if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) { ++ if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) { + dev_err(&vdev->dev, "couldn't initialize event pool\n"); + goto init_pool_failed; + } +@@ -1732,7 +1733,7 @@ static int ibmvscsi_probe(struct vio_dev + add_host_failed: + release_event_pool(&hostdata->pool, hostdata); + init_pool_failed: +- ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests); ++ ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); + init_crq_failed: + scsi_host_put(host); + scsi_host_alloc_failed: +@@ -1744,7 +1745,7 @@ static int ibmvscsi_remove(struct vio_de + struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; + release_event_pool(&hostdata->pool, hostdata); + ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, +- max_requests); ++ max_events); + + srp_remove_host(hostdata->host); + scsi_remove_host(hostdata->host); +@@ -1781,6 +1782,10 @@ int __init ibmvscsi_module_init(void) + { + int ret; + ++ /* Ensure we have two requests to do error recovery */ ++ driver_template.can_queue = max_requests; ++ max_events = max_requests + 2; ++ + if (firmware_has_feature(FW_FEATURE_ISERIES)) + ibmvscsi_ops = &iseriesvscsi_ops; + else if (firmware_has_feature(FW_FEATURE_VIO)) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-module_alias.patch b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-module_alias.patch new file mode 100644 index 000000000..227831159 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-module_alias.patch @@ -0,0 +1,38 @@ +Subject: map scsi proc_name to module name +From: olh@suse.de +References: 459933 - LTC50724 + +--- + drivers/scsi/ibmvscsi/ibmvscsi.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvscsi.c ++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c +@@ -100,6 +100,9 @@ static struct scsi_transport_template *i + + static struct ibmvscsi_ops *ibmvscsi_ops; + ++#define IBMVSCSI_PROC_NAME "ibmvscsi" ++/* The driver is named ibmvscsic, map ibmvscsi to module name */ ++MODULE_ALIAS(IBMVSCSI_PROC_NAME); + MODULE_DESCRIPTION("IBM Virtual SCSI"); + MODULE_AUTHOR("Dave Boutcher"); + MODULE_LICENSE("GPL"); +@@ -1612,7 +1615,7 @@ static struct device_attribute *ibmvscsi + static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION, +- .proc_name = "ibmvscsi", ++ .proc_name = IBMVSCSI_PROC_NAME, + .queuecommand = ibmvscsi_queuecommand, + .eh_abort_handler = ibmvscsi_eh_abort_handler, + .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, +@@ -1771,7 +1774,7 @@ static struct vio_driver ibmvscsi_driver + .remove = ibmvscsi_remove, + .get_desired_dma = ibmvscsi_get_desired_dma, + .driver = { +- .name = "ibmvscsi", ++ .name = IBMVSCSI_PROC_NAME, + .owner = THIS_MODULE, + } + }; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-show-config.patch b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-show-config.patch new file mode 100644 index 000000000..cf52a78c2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-show-config.patch @@ -0,0 +1,84 @@ +Subject: /sys/class/scsi_host/hostX/config doesn't show any information +From: Linda Xie +References: 439970 - LTC49349 + +This patch changes the size of the buffer used for transfering config +data to 4K. It was tested against 2.6.19-rc2 tree. + +Signed-off-by: lxie@us.ibm.com +Signed-off-by: Olaf Hering + +--- + drivers/scsi/ibmvscsi/ibmvscsi.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/drivers/scsi/ibmvscsi/ibmvscsi.c ++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c +@@ -89,10 +89,12 @@ static int max_id = 64; + static int max_channel = 3; + static int init_timeout = 5; + static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; ++/*host data buffer size*/ ++#define buff_size 4096 + + static struct scsi_transport_template *ibmvscsi_transport_template; + +-#define IBMVSCSI_VERSION "1.5.8" ++#define IBMVSCSI_VERSION "1.5.9" + + static struct ibmvscsi_ops *ibmvscsi_ops; + +@@ -1476,7 +1478,7 @@ static ssize_t show_host_srp_version(str + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + +- len = snprintf(buf, PAGE_SIZE, "%s\n", ++ len = snprintf(buf, buff_size, "%s\n", + hostdata->madapter_info.srp_version); + return len; + } +@@ -1497,7 +1499,7 @@ static ssize_t show_host_partition_name( + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + +- len = snprintf(buf, PAGE_SIZE, "%s\n", ++ len = snprintf(buf, buff_size, "%s\n", + hostdata->madapter_info.partition_name); + return len; + } +@@ -1518,7 +1520,7 @@ static ssize_t show_host_partition_numbe + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + +- len = snprintf(buf, PAGE_SIZE, "%d\n", ++ len = snprintf(buf, buff_size, "%d\n", + hostdata->madapter_info.partition_number); + return len; + } +@@ -1538,7 +1540,7 @@ static ssize_t show_host_mad_version(str + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + +- len = snprintf(buf, PAGE_SIZE, "%d\n", ++ len = snprintf(buf, buff_size, "%d\n", + hostdata->madapter_info.mad_version); + return len; + } +@@ -1558,7 +1560,7 @@ static ssize_t show_host_os_type(struct + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + int len; + +- len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type); ++ len = snprintf(buf, buff_size, "%d\n", hostdata->madapter_info.os_type); + return len; + } + +@@ -1577,7 +1579,7 @@ static ssize_t show_host_config(struct d + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + + /* returns null-terminated host config data */ +- if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0) ++ if (ibmvscsi_do_host_config(hostdata, buf, buff_size) == 0) + return strlen(buf); + else + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-vio_leak.patch b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-vio_leak.patch new file mode 100644 index 000000000..bc41a6d6b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ibmvscsi-vio_leak.patch @@ -0,0 +1,91 @@ +Subject: Correct VIO bus/device CMO accounting problems +From: Robert Jennings +References: 468304 - LTC51205 + +This corrects three entitlement accounting issues that are all small in +scope but at least two of them are critical. + +In the VIO bus code the wrappers for dma alloc_coherent and free_coherent +calls are rounding to IOMMU_PAGE_SIZE. Taking a look at the underlying +calls, the actual mapping is promoted to PAGE_SIZE. Changing the +rounding in these two functions fixes under reporting the entitlement +used. Without this change, the system could run out of entitlement before +it believes it has and incur mapping failures at the firmware level. + +Also in the VIO bus code, the wrapper for dma map_sg is not exiting in +an error path where it should. Rather than fall through to code for the +success case, this patch adds the return that is needed in the error path. + +The ibmvscsi client driver is not unmapping the scsi command after +encountering a dma mapping error while trying to map an indirect +scattergather list. This leads to a leak of dma entitlement that could +result in the device failing future dma operations. + +Signed-off-by: Robert Jennings +Signed-off-by: Olaf Hering + +-- + arch/powerpc/kernel/vio.c | 7 ++++--- + drivers/scsi/ibmvscsi/ibmvfc.c | 4 +++- + drivers/scsi/ibmvscsi/ibmvscsi.c | 1 + + 3 files changed, 8 insertions(+), 4 deletions(-) + +--- a/arch/powerpc/kernel/vio.c ++++ b/arch/powerpc/kernel/vio.c +@@ -492,14 +492,14 @@ static void *vio_dma_iommu_alloc_coheren + struct vio_dev *viodev = to_vio_dev(dev); + void *ret; + +- if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE))) { ++ if (vio_cmo_alloc(viodev, roundup(size, PAGE_SIZE))) { + atomic_inc(&viodev->cmo.allocs_failed); + return NULL; + } + + ret = dma_iommu_ops.alloc_coherent(dev, size, dma_handle, flag); + if (unlikely(ret == NULL)) { +- vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); ++ vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE)); + atomic_inc(&viodev->cmo.allocs_failed); + } + +@@ -513,7 +513,7 @@ static void vio_dma_iommu_free_coherent( + + dma_iommu_ops.free_coherent(dev, size, vaddr, dma_handle); + +- vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); ++ vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE)); + } + + static dma_addr_t vio_dma_iommu_map_single(struct device *dev, void *vaddr, +@@ -572,6 +572,7 @@ static int vio_dma_iommu_map_sg(struct d + if (unlikely(!ret)) { + vio_cmo_dealloc(viodev, alloc_size); + atomic_inc(&viodev->cmo.allocs_failed); ++ return ret; + } + + for (sgl = sglist, count = 0; count < ret; count++, sgl++) +--- a/drivers/scsi/ibmvscsi/ibmvfc.c ++++ b/drivers/scsi/ibmvscsi/ibmvfc.c +@@ -1323,7 +1323,9 @@ static int ibmvfc_map_sg_data(struct scs + &evt->ext_list_token); + + if (!evt->ext_list) { +- scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n"); ++ scsi_dma_unmap(scmd); ++ if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) ++ scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n"); + return -ENOMEM; + } + } +--- a/drivers/scsi/ibmvscsi/ibmvscsi.c ++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c +@@ -435,6 +435,7 @@ static int map_sg_data(struct scsi_cmnd + sdev_printk(KERN_ERR, cmd->device, + "Can't allocate memory " + "for indirect table\n"); ++ scsi_dma_unmap(cmd); + return 0; + } + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-initialize-max_targets_blocked b/src/patches/suse-2.6.27.31/patches.fixes/scsi-initialize-max_targets_blocked new file mode 100644 index 000000000..4da5ae4c7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-initialize-max_targets_blocked @@ -0,0 +1,30 @@ +From: Edward Goggin +Date: Thu Apr 9 10:02:22 2009 -0700 +Subject: initialize max_target_blocked in scsi_alloc_target +Patch-Mainline: Yes +References: bnc#524347 + +This patch initializes the max_target_blocked field of a scsi target +structure so that a queuecommand return value of +SCSI_MLQUEUE_TARGET_BUSY will actually result in having the +scsi_queue_insert blocking the device queue before requeuing the +command and running the queue. Otherwise, can and does cause livelock +on single CPU configurations if/when open-iSCSI software initiator's +command PDU window fills. + +Signed-off-by: Ed Goggin +Signed-off-by: James Bottomley +Acked-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index 6f51ca4..e2b50d8 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -425,6 +425,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, + INIT_LIST_HEAD(&starget->devices); + starget->state = STARGET_CREATED; + starget->scsi_level = SCSI_2; ++ starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED; + retry: + spin_lock_irqsave(shost->host_lock, flags); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-inquiry-too-short-ratelimit b/src/patches/suse-2.6.27.31/patches.fixes/scsi-inquiry-too-short-ratelimit new file mode 100644 index 000000000..c3fba3d77 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-inquiry-too-short-ratelimit @@ -0,0 +1,23 @@ +From: Hannes Reinecke +Subject: INQUIRY result too short (5) message flood +References: bnc#432535 + +During installation with vioserver/vioclient lots of +scsi scan: INQUIRY result too short (5), using 36 +messages are printed. These really should be ratelimited. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index b14dc02..ac46d4b 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -680,7 +680,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, + * and displaying garbage for the Vendor, Product, or Revision + * strings. + */ +- if (sdev->inquiry_len < 36) { ++ if (sdev->inquiry_len < 36 && printk_ratelimit()) { + printk(KERN_INFO "scsi scan: INQUIRY result too short (%d)," + " using 36\n", sdev->inquiry_len); + sdev->inquiry_len = 36; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-ipr-fix-PCI-permanent-error-handler b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ipr-fix-PCI-permanent-error-handler new file mode 100644 index 000000000..a543508b5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-ipr-fix-PCI-permanent-error-handler @@ -0,0 +1,39 @@ +From: Kleber S. Souza +Date: Mon, 4 May 2009 13:41:02 +0000 (-0300) +Subject: [SCSI] ipr: fix PCI permanent error handler +Patch-mainline: 2.6.31, expected +References: bnc#505925 + +[SCSI] ipr: fix PCI permanent error handler + +The ipr driver can hang if it encounters enough PCI errors +to trigger the permanent error handler. The driver will attempt +to initiate a "bringdown" of the adapter and fail all pending +ops back. However, this bringdown is unlike any other bringdown +of the adapter in the code as the driver. In this code path we +end up failing back ops with allow_cmds still set to 1. This results +in some commands, the HCAM commands in particular, getting immediately +re-issued to the adapter on the done call, which results in +an infinite loop in ipr_fail_all_ops. Fix this by setting allow_cmds +to zero in this path. + +Signed-off-by: Kleber S. Souza +[brking@linux.vnet.ibm.com: alternate patch substituted] +Signed-off-by: Brian King +Signed-off-by: James Bottomley +Acked-by: Jeff Mahoney +--- + + drivers/scsi/ipr.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/scsi/ipr.c ++++ b/drivers/scsi/ipr.c +@@ -7007,6 +7007,7 @@ static void ipr_pci_perm_failure(struct + ioa_cfg->sdt_state = ABORT_DUMP; + ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES; + ioa_cfg->in_ioa_bringdown = 1; ++ ioa_cfg->allow_cmds = 0; + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-lib-string_get_size-don-t-hang-on-zero-no-decimals-on-exact.patch b/src/patches/suse-2.6.27.31/patches.fixes/scsi-lib-string_get_size-don-t-hang-on-zero-no-decimals-on-exact.patch new file mode 100644 index 000000000..19798bfd3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-lib-string_get_size-don-t-hang-on-zero-no-decimals-on-exact.patch @@ -0,0 +1,96 @@ +From a8659597bf744b0f8d2560e2a734b5c941569e0e Mon Sep 17 00:00:00 2001 +From: H. Peter Anvin +Date: Tue, 14 Oct 2008 11:34:21 -0700 +Subject: SCSI lib: string_get_size(): don't hang on zero; no decimals on exact +Patch-mainline: 2.6.28 +References: bnc#500429 + +From: H. Peter Anvin + +commit a8659597bf744b0f8d2560e2a734b5c941569e0e upstream. + +We would hang forever when passing a zero to string_get_size(). +Furthermore, string_get_size() would produce decimals on a value small +enough to be exact. Finally, a few formatting issues are inconsistent +with standard SI style guidelines. + +- If the value is less than the divisor, skip the entire rounding + step. This prints out all small values including zero as integers, + without decimals. +- Add a space between the value and the symbol for the unit, + consistent with standard SI practice. +- Lower case k in kB since we are talking about powers of 10. +- Finally, change "int" to "unsigned int" in one place to shut up a + gcc warning when compiling the code out-of-kernel for testing. + +Signed-off-by: H. Peter Anvin +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + lib/string_helpers.c | 38 +++++++++++++++++++++----------------- + 1 file changed, 21 insertions(+), 17 deletions(-) + +--- a/lib/string_helpers.c ++++ b/lib/string_helpers.c +@@ -23,7 +23,7 @@ + int string_get_size(u64 size, const enum string_size_units units, + char *buf, int len) + { +- const char *units_10[] = { "B", "KB", "MB", "GB", "TB", "PB", ++ const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB", + "EB", "ZB", "YB", NULL}; + const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", + "EiB", "ZiB", "YiB", NULL }; +@@ -31,7 +31,7 @@ int string_get_size(u64 size, const enum + [STRING_UNITS_10] = units_10, + [STRING_UNITS_2] = units_2, + }; +- const int divisor[] = { ++ const unsigned int divisor[] = { + [STRING_UNITS_10] = 1000, + [STRING_UNITS_2] = 1024, + }; +@@ -40,23 +40,27 @@ int string_get_size(u64 size, const enum + char tmp[8]; + + tmp[0] = '\0'; +- +- for (i = 0; size > divisor[units] && units_str[units][i]; i++) +- remainder = do_div(size, divisor[units]); +- +- sf_cap = size; +- for (j = 0; sf_cap*10 < 1000; j++) +- sf_cap *= 10; +- +- if (j) { +- remainder *= 1000; +- do_div(remainder, divisor[units]); +- snprintf(tmp, sizeof(tmp), ".%03lld", +- (unsigned long long)remainder); +- tmp[j+1] = '\0'; ++ i = 0; ++ if (size >= divisor[units]) { ++ while (size >= divisor[units] && units_str[units][i]) { ++ remainder = do_div(size, divisor[units]); ++ i++; ++ } ++ ++ sf_cap = size; ++ for (j = 0; sf_cap*10 < 1000; j++) ++ sf_cap *= 10; ++ ++ if (j) { ++ remainder *= 1000; ++ do_div(remainder, divisor[units]); ++ snprintf(tmp, sizeof(tmp), ".%03lld", ++ (unsigned long long)remainder); ++ tmp[j+1] = '\0'; ++ } + } + +- snprintf(buf, len, "%lld%s%s", (unsigned long long)size, ++ snprintf(buf, len, "%lld%s %s", (unsigned long long)size, + tmp, units_str[units][i]); + + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-misc-git-update b/src/patches/suse-2.6.27.31/patches.fixes/scsi-misc-git-update new file mode 100644 index 000000000..2af4c0e90 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-misc-git-update @@ -0,0 +1,1347 @@ +From: James Bottomley +Subject: SCSI misc fixes +References: FATE#303485,FATE#303484 + +This patch pulls in the latest patches from the scsi-misc tree. +The functions are required by the various driver updates. + +Signed-off-by: Hannes Reinecke + +--- + Documentation/scsi/scsi_fc_transport.txt | 36 + + drivers/mmc/card/block.c | 10 + drivers/scsi/device_handler/scsi_dh_emc.c | 1 + drivers/scsi/device_handler/scsi_dh_hp_sw.c | 2 + drivers/scsi/device_handler/scsi_dh_rdac.c | 2 + drivers/scsi/libiscsi.c | 2 + drivers/scsi/scsi.c | 13 + drivers/scsi/scsi_lib.c | 39 +- + drivers/scsi/scsi_netlink.c | 523 +++++++++++++++++++++++++++- + drivers/scsi/scsi_scan.c | 20 - + drivers/scsi/scsi_sysfs.c | 1 + drivers/scsi/scsi_transport_fc.c | 54 +- + drivers/scsi/sd.c | 29 - + include/linux/string_helpers.h | 16 + include/scsi/scsi_device.h | 21 - + include/scsi/scsi_netlink.h | 62 +++ + include/scsi/scsi_transport_fc.h | 23 + + lib/Makefile | 3 + lib/string_helpers.c | 64 +++ + 19 files changed, 834 insertions(+), 87 deletions(-) + +--- a/Documentation/scsi/scsi_fc_transport.txt ++++ b/Documentation/scsi/scsi_fc_transport.txt +@@ -436,6 +436,42 @@ Other: + was updated to remove all vports for the fc_host as well. + + ++Transport supplied functions ++---------------------------- ++ ++The following functions are supplied by the FC-transport for use by LLDs. ++ ++ fc_vport_create - create a vport ++ fc_vport_terminate - detach and remove a vport ++ ++Details: ++ ++/** ++ * fc_vport_create - Admin App or LLDD requests creation of a vport ++ * @shost: scsi host the virtual port is connected to. ++ * @ids: The world wide names, FC4 port roles, etc for ++ * the virtual port. ++ * ++ * Notes: ++ * This routine assumes no locks are held on entry. ++ */ ++struct fc_vport * ++fc_vport_create(struct Scsi_Host *shost, struct fc_vport_identifiers *ids) ++ ++/** ++ * fc_vport_terminate - Admin App or LLDD requests termination of a vport ++ * @vport: fc_vport to be terminated ++ * ++ * Calls the LLDD vport_delete() function, then deallocates and removes ++ * the vport from the shost and object tree. ++ * ++ * Notes: ++ * This routine assumes no locks are held on entry. ++ */ ++int ++fc_vport_terminate(struct fc_vport *vport) ++ ++ + Credits + ======= + The following people have contributed to this document: +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -532,6 +533,8 @@ static int mmc_blk_probe(struct mmc_card + struct mmc_blk_data *md; + int err; + ++ char cap_str[10]; ++ + /* + * Check that the card supports the command class(es) we need. + */ +@@ -546,10 +549,11 @@ static int mmc_blk_probe(struct mmc_card + if (err) + goto out; + +- printk(KERN_INFO "%s: %s %s %lluKiB %s\n", ++ string_get_size(get_capacity(md->disk) << 9, STRING_UNITS_2, ++ cap_str, sizeof(cap_str)); ++ printk(KERN_INFO "%s: %s %s %s %s\n", + md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), +- (unsigned long long)(get_capacity(md->disk) >> 1), +- md->read_only ? "(ro)" : ""); ++ cap_str, md->read_only ? "(ro)" : ""); + + mmc_set_drvdata(card, md); + add_disk(md->disk); +--- a/drivers/scsi/device_handler/scsi_dh_emc.c ++++ b/drivers/scsi/device_handler/scsi_dh_emc.c +@@ -278,7 +278,6 @@ static struct request *get_req(struct sc + return NULL; + } + +- memset(rq->cmd, 0, BLK_MAX_CDB); + rq->cmd_len = COMMAND_SIZE(cmd); + rq->cmd[0] = cmd; + +--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c ++++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c +@@ -114,7 +114,6 @@ static int hp_sw_tur(struct scsi_device + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_FAILFAST; + req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); +- memset(req->cmd, 0, MAX_COMMAND_SIZE); + req->cmd[0] = TEST_UNIT_READY; + req->timeout = HP_SW_TIMEOUT; + req->sense = h->sense; +@@ -207,7 +206,6 @@ static int hp_sw_start_stop(struct scsi_ + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_FAILFAST; + req->cmd_len = COMMAND_SIZE(START_STOP); +- memset(req->cmd, 0, MAX_COMMAND_SIZE); + req->cmd[0] = START_STOP; + req->cmd[4] = 1; /* Start spin cycle */ + req->timeout = HP_SW_TIMEOUT; +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -225,8 +225,6 @@ static struct request *get_rdac_req(stru + return NULL; + } + +- memset(rq->cmd, 0, BLK_MAX_CDB); +- + rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; + rq->retries = RDAC_RETRIES; +--- a/drivers/scsi/libiscsi.c ++++ b/drivers/scsi/libiscsi.c +@@ -1456,7 +1456,7 @@ static void fail_all_commands(struct isc + if (lun == task->sc->device->lun || lun == -1) { + debug_scsi("failing in progress sc %p itt 0x%x\n", + task->sc, task->itt); +- fail_command(conn, task, DID_BUS_BUSY << 16); ++ fail_command(conn, task, error << 16); + } + } + } +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -668,13 +668,14 @@ int scsi_dispatch_cmd(struct scsi_cmnd * + goto out; + } + +- /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */ +- if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) { ++ /* Check to see if the scsi lld made this device blocked. */ ++ if (unlikely(scsi_device_blocked(cmd->device))) { + /* +- * in SDEV_BLOCK, the command is just put back on the device +- * queue. The suspend state has already blocked the queue so +- * future requests should not occur until the device +- * transitions out of the suspend state. ++ * in blocked state, the command is just put back on ++ * the device queue. The suspend state has already ++ * blocked the queue so future requests should not ++ * occur until the device transitions out of the ++ * suspend state. + */ + + scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1250,6 +1250,7 @@ int scsi_prep_state_check(struct scsi_de + break; + case SDEV_QUIESCE: + case SDEV_BLOCK: ++ case SDEV_CREATED_BLOCK: + /* + * If the devices is blocked we defer normal commands. + */ +@@ -2073,10 +2074,13 @@ scsi_device_set_state(struct scsi_device + + switch (state) { + case SDEV_CREATED: +- /* There are no legal states that come back to +- * created. This is the manually initialised start +- * state */ +- goto illegal; ++ switch (oldstate) { ++ case SDEV_CREATED_BLOCK: ++ break; ++ default: ++ goto illegal; ++ } ++ break; + + case SDEV_RUNNING: + switch (oldstate) { +@@ -2114,8 +2118,17 @@ scsi_device_set_state(struct scsi_device + + case SDEV_BLOCK: + switch (oldstate) { +- case SDEV_CREATED: + case SDEV_RUNNING: ++ case SDEV_CREATED_BLOCK: ++ break; ++ default: ++ goto illegal; ++ } ++ break; ++ ++ case SDEV_CREATED_BLOCK: ++ switch (oldstate) { ++ case SDEV_CREATED: + break; + default: + goto illegal; +@@ -2403,8 +2416,12 @@ scsi_internal_device_block(struct scsi_d + int err = 0; + + err = scsi_device_set_state(sdev, SDEV_BLOCK); +- if (err) +- return err; ++ if (err) { ++ err = scsi_device_set_state(sdev, SDEV_CREATED_BLOCK); ++ ++ if (err) ++ return err; ++ } + + /* + * The device has transitioned to SDEV_BLOCK. Stop the +@@ -2447,8 +2464,12 @@ scsi_internal_device_unblock(struct scsi + * and goose the device queue if successful. + */ + err = scsi_device_set_state(sdev, SDEV_RUNNING); +- if (err) +- return err; ++ if (err) { ++ err = scsi_device_set_state(sdev, SDEV_CREATED); ++ ++ if (err) ++ return err; ++ } + + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); +--- a/drivers/scsi/scsi_netlink.c ++++ b/drivers/scsi/scsi_netlink.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -30,6 +31,39 @@ + struct sock *scsi_nl_sock = NULL; + EXPORT_SYMBOL_GPL(scsi_nl_sock); + ++static DEFINE_SPINLOCK(scsi_nl_lock); ++static struct list_head scsi_nl_drivers; ++ ++static u32 scsi_nl_state; ++#define STATE_EHANDLER_BSY 0x00000001 ++ ++struct scsi_nl_transport { ++ int (*msg_handler)(struct sk_buff *); ++ void (*event_handler)(struct notifier_block *, unsigned long, void *); ++ unsigned int refcnt; ++ int flags; ++}; ++ ++/* flags values (bit flags) */ ++#define HANDLER_DELETING 0x1 ++ ++static struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] = ++ { {NULL, }, }; ++ ++ ++struct scsi_nl_drvr { ++ struct list_head next; ++ int (*dmsg_handler)(struct Scsi_Host *shost, void *payload, ++ u32 len, u32 pid); ++ void (*devt_handler)(struct notifier_block *nb, ++ unsigned long event, void *notify_ptr); ++ struct scsi_host_template *hostt; ++ u64 vendor_id; ++ unsigned int refcnt; ++ int flags; ++}; ++ ++ + + /** + * scsi_nl_rcv_msg - Receive message handler. +@@ -45,8 +79,9 @@ scsi_nl_rcv_msg(struct sk_buff *skb) + { + struct nlmsghdr *nlh; + struct scsi_nl_hdr *hdr; +- uint32_t rlen; +- int err; ++ unsigned long flags; ++ u32 rlen; ++ int err, tport; + + while (skb->len >= NLMSG_SPACE(0)) { + err = 0; +@@ -65,7 +100,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) + + if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { + err = -EBADMSG; +- return; ++ goto next_msg; + } + + hdr = NLMSG_DATA(nlh); +@@ -83,12 +118,27 @@ scsi_nl_rcv_msg(struct sk_buff *skb) + if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { + printk(KERN_WARNING "%s: discarding partial message\n", + __func__); +- return; ++ goto next_msg; + } + + /* +- * We currently don't support anyone sending us a message ++ * Deliver message to the appropriate transport + */ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ ++ tport = hdr->transport; ++ if ((tport < SCSI_NL_MAX_TRANSPORTS) && ++ !(transports[tport].flags & HANDLER_DELETING) && ++ (transports[tport].msg_handler)) { ++ transports[tport].refcnt++; ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ err = transports[tport].msg_handler(skb); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ transports[tport].refcnt--; ++ } else ++ err = -ENOENT; ++ ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); + + next_msg: + if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) +@@ -110,14 +160,42 @@ static int + scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) + { + struct netlink_notify *n = ptr; ++ struct scsi_nl_drvr *driver; ++ unsigned long flags; ++ int tport; + + if (n->protocol != NETLINK_SCSITRANSPORT) + return NOTIFY_DONE; + ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ scsi_nl_state |= STATE_EHANDLER_BSY; ++ ++ /* ++ * Pass event on to any transports that may be listening ++ */ ++ for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) { ++ if (!(transports[tport].flags & HANDLER_DELETING) && ++ (transports[tport].event_handler)) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ transports[tport].event_handler(this, event, ptr); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ } ++ + /* +- * Currently, we are not tracking PID's, etc. There is nothing +- * to handle. ++ * Pass event on to any drivers that may be listening + */ ++ list_for_each_entry(driver, &scsi_nl_drivers, next) { ++ if (!(driver->flags & HANDLER_DELETING) && ++ (driver->devt_handler)) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ driver->devt_handler(this, event, ptr); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ } ++ ++ scsi_nl_state &= ~STATE_EHANDLER_BSY; ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); + + return NOTIFY_DONE; + } +@@ -128,7 +206,281 @@ static struct notifier_block scsi_netlin + + + /** +- * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface ++ * GENERIC SCSI transport receive and event handlers ++ **/ ++ ++/** ++ * scsi_generic_msg_handler - receive message handler for GENERIC transport ++ * messages ++ * ++ * @skb: socket receive buffer ++ * ++ **/ ++static int ++scsi_generic_msg_handler(struct sk_buff *skb) ++{ ++ struct nlmsghdr *nlh = nlmsg_hdr(skb); ++ struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh); ++ struct scsi_nl_drvr *driver; ++ struct Scsi_Host *shost; ++ unsigned long flags; ++ int err = 0, match, pid; ++ ++ pid = NETLINK_CREDS(skb)->pid; ++ ++ switch (snlh->msgtype) { ++ case SCSI_NL_SHOST_VENDOR: ++ { ++ struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh); ++ ++ /* Locate the driver that corresponds to the message */ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ match = 0; ++ list_for_each_entry(driver, &scsi_nl_drivers, next) { ++ if (driver->vendor_id == msg->vendor_id) { ++ match = 1; ++ break; ++ } ++ } ++ ++ if ((!match) || (!driver->dmsg_handler)) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ err = -ESRCH; ++ goto rcv_exit; ++ } ++ ++ if (driver->flags & HANDLER_DELETING) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ err = -ESHUTDOWN; ++ goto rcv_exit; ++ } ++ ++ driver->refcnt++; ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ ++ ++ /* if successful, scsi_host_lookup takes a shost reference */ ++ shost = scsi_host_lookup(msg->host_no); ++ if (!shost) { ++ err = -ENODEV; ++ goto driver_exit; ++ } ++ ++ /* is this host owned by the vendor ? */ ++ if (shost->hostt != driver->hostt) { ++ err = -EINVAL; ++ goto vendormsg_put; ++ } ++ ++ /* pass message on to the driver */ ++ err = driver->dmsg_handler(shost, (void *)&msg[1], ++ msg->vmsg_datalen, pid); ++ ++vendormsg_put: ++ /* release reference by scsi_host_lookup */ ++ scsi_host_put(shost); ++ ++driver_exit: ++ /* release our own reference on the registration object */ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ driver->refcnt--; ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ break; ++ } ++ ++ default: ++ err = -EBADR; ++ break; ++ } ++ ++rcv_exit: ++ if (err) ++ printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n", ++ __func__, snlh->msgtype, err); ++ return err; ++} ++ ++ ++/** ++ * scsi_nl_add_transport - ++ * Registers message and event handlers for a transport. Enables ++ * receipt of netlink messages and events to a transport. ++ * ++ * @tport: transport registering handlers ++ * @msg_handler: receive message handler callback ++ * @event_handler: receive event handler callback ++ **/ ++int ++scsi_nl_add_transport(u8 tport, ++ int (*msg_handler)(struct sk_buff *), ++ void (*event_handler)(struct notifier_block *, unsigned long, void *)) ++{ ++ unsigned long flags; ++ int err = 0; ++ ++ if (tport >= SCSI_NL_MAX_TRANSPORTS) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ ++ if (scsi_nl_state & STATE_EHANDLER_BSY) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ msleep(1); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ ++ if (transports[tport].msg_handler || transports[tport].event_handler) { ++ err = -EALREADY; ++ goto register_out; ++ } ++ ++ transports[tport].msg_handler = msg_handler; ++ transports[tport].event_handler = event_handler; ++ transports[tport].flags = 0; ++ transports[tport].refcnt = 0; ++ ++register_out: ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(scsi_nl_add_transport); ++ ++ ++/** ++ * scsi_nl_remove_transport - ++ * Disable transport receiption of messages and events ++ * ++ * @tport: transport deregistering handlers ++ * ++ **/ ++void ++scsi_nl_remove_transport(u8 tport) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ if (scsi_nl_state & STATE_EHANDLER_BSY) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ msleep(1); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ ++ if (tport < SCSI_NL_MAX_TRANSPORTS) { ++ transports[tport].flags |= HANDLER_DELETING; ++ ++ while (transports[tport].refcnt != 0) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ schedule_timeout_uninterruptible(HZ/4); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ transports[tport].msg_handler = NULL; ++ transports[tport].event_handler = NULL; ++ transports[tport].flags = 0; ++ } ++ ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ ++ return; ++} ++EXPORT_SYMBOL_GPL(scsi_nl_remove_transport); ++ ++ ++/** ++ * scsi_nl_add_driver - ++ * A driver is registering its interfaces for SCSI netlink messages ++ * ++ * @vendor_id: A unique identification value for the driver. ++ * @hostt: address of the driver's host template. Used ++ * to verify an shost is bound to the driver ++ * @nlmsg_handler: receive message handler callback ++ * @nlevt_handler: receive event handler callback ++ * ++ * Returns: ++ * 0 on Success ++ * error result otherwise ++ **/ ++int ++scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt, ++ int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload, ++ u32 len, u32 pid), ++ void (*nlevt_handler)(struct notifier_block *nb, ++ unsigned long event, void *notify_ptr)) ++{ ++ struct scsi_nl_drvr *driver; ++ unsigned long flags; ++ ++ driver = kzalloc(sizeof(*driver), GFP_KERNEL); ++ if (unlikely(!driver)) { ++ printk(KERN_ERR "%s: allocation failure\n", __func__); ++ return -ENOMEM; ++ } ++ ++ driver->dmsg_handler = nlmsg_handler; ++ driver->devt_handler = nlevt_handler; ++ driver->hostt = hostt; ++ driver->vendor_id = vendor_id; ++ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ if (scsi_nl_state & STATE_EHANDLER_BSY) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ msleep(1); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ list_add_tail(&driver->next, &scsi_nl_drivers); ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(scsi_nl_add_driver); ++ ++ ++/** ++ * scsi_nl_remove_driver - ++ * An driver is unregistering with the SCSI netlink messages ++ * ++ * @vendor_id: The unique identification value for the driver. ++ **/ ++void ++scsi_nl_remove_driver(u64 vendor_id) ++{ ++ struct scsi_nl_drvr *driver; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ if (scsi_nl_state & STATE_EHANDLER_BSY) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ msleep(1); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ ++ list_for_each_entry(driver, &scsi_nl_drivers, next) { ++ if (driver->vendor_id == vendor_id) { ++ driver->flags |= HANDLER_DELETING; ++ while (driver->refcnt != 0) { ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ schedule_timeout_uninterruptible(HZ/4); ++ spin_lock_irqsave(&scsi_nl_lock, flags); ++ } ++ list_del(&driver->next); ++ kfree(driver); ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ return; ++ } ++ } ++ ++ spin_unlock_irqrestore(&scsi_nl_lock, flags); ++ ++ printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n", ++ __func__, (unsigned long long)vendor_id); ++ return; ++} ++EXPORT_SYMBOL_GPL(scsi_nl_remove_driver); ++ ++ ++/** ++ * scsi_netlink_init - Called by SCSI subsystem to intialize ++ * the SCSI transport netlink interface + * + **/ + void +@@ -136,6 +488,8 @@ scsi_netlink_init(void) + { + int error; + ++ INIT_LIST_HEAD(&scsi_nl_drivers); ++ + error = netlink_register_notifier(&scsi_netlink_notifier); + if (error) { + printk(KERN_ERR "%s: register of event handler failed - %d\n", +@@ -150,8 +504,15 @@ scsi_netlink_init(void) + printk(KERN_ERR "%s: register of recieve handler failed\n", + __func__); + netlink_unregister_notifier(&scsi_netlink_notifier); ++ return; + } + ++ /* Register the entry points for the generic SCSI transport */ ++ error = scsi_nl_add_transport(SCSI_NL_TRANSPORT, ++ scsi_generic_msg_handler, NULL); ++ if (error) ++ printk(KERN_ERR "%s: register of GENERIC transport handler" ++ " failed - %d\n", __func__, error); + return; + } + +@@ -163,6 +524,8 @@ scsi_netlink_init(void) + void + scsi_netlink_exit(void) + { ++ scsi_nl_remove_transport(SCSI_NL_TRANSPORT); ++ + if (scsi_nl_sock) { + netlink_kernel_release(scsi_nl_sock); + netlink_unregister_notifier(&scsi_netlink_notifier); +@@ -172,3 +535,147 @@ scsi_netlink_exit(void) + } + + ++/* ++ * Exported Interfaces ++ */ ++ ++/** ++ * scsi_nl_send_transport_msg - ++ * Generic function to send a single message from a SCSI transport to ++ * a single process ++ * ++ * @pid: receiving pid ++ * @hdr: message payload ++ * ++ **/ ++void ++scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr) ++{ ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ const char *fn; ++ char *datab; ++ u32 len, skblen; ++ int err; ++ ++ if (!scsi_nl_sock) { ++ err = -ENOENT; ++ fn = "netlink socket"; ++ goto msg_fail; ++ } ++ ++ len = NLMSG_SPACE(hdr->msglen); ++ skblen = NLMSG_SPACE(len); ++ ++ skb = alloc_skb(skblen, GFP_KERNEL); ++ if (!skb) { ++ err = -ENOBUFS; ++ fn = "alloc_skb"; ++ goto msg_fail; ++ } ++ ++ nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0); ++ if (!nlh) { ++ err = -ENOBUFS; ++ fn = "nlmsg_put"; ++ goto msg_fail_skb; ++ } ++ datab = NLMSG_DATA(nlh); ++ memcpy(datab, hdr, hdr->msglen); ++ ++ err = nlmsg_unicast(scsi_nl_sock, skb, pid); ++ if (err < 0) { ++ fn = "nlmsg_unicast"; ++ /* nlmsg_unicast already kfree_skb'd */ ++ goto msg_fail; ++ } ++ ++ return; ++ ++msg_fail_skb: ++ kfree_skb(skb); ++msg_fail: ++ printk(KERN_WARNING ++ "%s: Dropped Message : pid %d Transport %d, msgtype x%x, " ++ "msglen %d: %s : err %d\n", ++ __func__, pid, hdr->transport, hdr->msgtype, hdr->msglen, ++ fn, err); ++ return; ++} ++EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg); ++ ++ ++/** ++ * scsi_nl_send_vendor_msg - called to send a shost vendor unique message ++ * to a specific process id. ++ * ++ * @pid: process id of the receiver ++ * @host_no: host # sending the message ++ * @vendor_id: unique identifier for the driver's vendor ++ * @data_len: amount, in bytes, of vendor unique payload data ++ * @data_buf: pointer to vendor unique data buffer ++ * ++ * Returns: ++ * 0 on succesful return ++ * otherwise, failing error code ++ * ++ * Notes: ++ * This routine assumes no locks are held on entry. ++ */ ++int ++scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id, ++ char *data_buf, u32 data_len) ++{ ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ struct scsi_nl_host_vendor_msg *msg; ++ u32 len, skblen; ++ int err; ++ ++ if (!scsi_nl_sock) { ++ err = -ENOENT; ++ goto send_vendor_fail; ++ } ++ ++ len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len); ++ skblen = NLMSG_SPACE(len); ++ ++ skb = alloc_skb(skblen, GFP_KERNEL); ++ if (!skb) { ++ err = -ENOBUFS; ++ goto send_vendor_fail; ++ } ++ ++ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, ++ skblen - sizeof(*nlh), 0); ++ if (!nlh) { ++ err = -ENOBUFS; ++ goto send_vendor_fail_skb; ++ } ++ msg = NLMSG_DATA(nlh); ++ ++ INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT, ++ SCSI_NL_SHOST_VENDOR, len); ++ msg->vendor_id = vendor_id; ++ msg->host_no = host_no; ++ msg->vmsg_datalen = data_len; /* bytes */ ++ memcpy(&msg[1], data_buf, data_len); ++ ++ err = nlmsg_unicast(scsi_nl_sock, skb, pid); ++ if (err) ++ /* nlmsg_multicast already kfree_skb'd */ ++ goto send_vendor_fail; ++ ++ return 0; ++ ++send_vendor_fail_skb: ++ kfree_skb(skb); ++send_vendor_fail: ++ printk(KERN_WARNING ++ "%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n", ++ __func__, host_no, err); ++ return err; ++} ++EXPORT_SYMBOL(scsi_nl_send_vendor_msg); ++ ++ +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -730,6 +730,8 @@ static int scsi_probe_lun(struct scsi_de + static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, + int *bflags, int async) + { ++ int ret; ++ + /* + * XXX do not save the inquiry, since it can change underneath us, + * save just vendor/model/rev. +@@ -885,7 +887,17 @@ static int scsi_add_lun(struct scsi_devi + + /* set the device running here so that slave configure + * may do I/O */ +- scsi_device_set_state(sdev, SDEV_RUNNING); ++ ret = scsi_device_set_state(sdev, SDEV_RUNNING); ++ if (ret) { ++ ret = scsi_device_set_state(sdev, SDEV_BLOCK); ++ ++ if (ret) { ++ sdev_printk(KERN_ERR, sdev, ++ "in wrong state %s to complete scan\n", ++ scsi_device_state_name(sdev->sdev_state)); ++ return SCSI_SCAN_NO_RESPONSE; ++ } ++ } + + if (*bflags & BLIST_MS_192_BYTES_FOR_3F) + sdev->use_192_bytes_for_3f = 1; +@@ -899,7 +911,7 @@ static int scsi_add_lun(struct scsi_devi + transport_configure_device(&sdev->sdev_gendev); + + if (sdev->host->hostt->slave_configure) { +- int ret = sdev->host->hostt->slave_configure(sdev); ++ ret = sdev->host->hostt->slave_configure(sdev); + if (ret) { + /* + * if LLDD reports slave not present, don't clutter +@@ -994,7 +1006,7 @@ static int scsi_probe_and_add_lun(struct + */ + sdev = scsi_device_lookup_by_target(starget, lun); + if (sdev) { +- if (rescan || sdev->sdev_state != SDEV_CREATED) { ++ if (rescan || !scsi_device_created(sdev)) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO + "scsi scan: device exists on %s\n", + sdev->sdev_gendev.bus_id)); +@@ -1467,7 +1479,7 @@ static int scsi_report_lun_scan(struct s + kfree(lun_data); + out: + scsi_device_put(sdev); +- if (sdev->sdev_state == SDEV_CREATED) ++ if (scsi_device_created(sdev)) + /* + * the sdev we used didn't appear in the report luns scan + */ +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -34,6 +34,7 @@ static const struct { + { SDEV_QUIESCE, "quiesce" }, + { SDEV_OFFLINE, "offline" }, + { SDEV_BLOCK, "blocked" }, ++ { SDEV_CREATED_BLOCK, "created-blocked" }, + }; + + const char *scsi_device_state_name(enum scsi_device_state state) +--- a/drivers/scsi/scsi_transport_fc.c ++++ b/drivers/scsi/scsi_transport_fc.c +@@ -40,31 +40,7 @@ + + static int fc_queue_work(struct Scsi_Host *, struct work_struct *); + static void fc_vport_sched_delete(struct work_struct *work); +- +-/* +- * This is a temporary carrier for creating a vport. It will eventually +- * be replaced by a real message definition for sgio or netlink. +- * +- * fc_vport_identifiers: This set of data contains all elements +- * to uniquely identify and instantiate a FC virtual port. +- * +- * Notes: +- * symbolic_name: The driver is to append the symbolic_name string data +- * to the symbolic_node_name data that it generates by default. +- * the resulting combination should then be registered with the switch. +- * It is expected that things like Xen may stuff a VM title into +- * this field. +- */ +-struct fc_vport_identifiers { +- u64 node_name; +- u64 port_name; +- u32 roles; +- bool disable; +- enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */ +- char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN]; +-}; +- +-static int fc_vport_create(struct Scsi_Host *shost, int channel, ++static int fc_vport_setup(struct Scsi_Host *shost, int channel, + struct device *pdev, struct fc_vport_identifiers *ids, + struct fc_vport **vport); + +@@ -1760,7 +1736,7 @@ store_fc_host_vport_create(struct device + vid.disable = false; /* always enabled */ + + /* we only allow support on Channel 0 !!! */ +- stat = fc_vport_create(shost, 0, &shost->shost_gendev, &vid, &vport); ++ stat = fc_vport_setup(shost, 0, &shost->shost_gendev, &vid, &vport); + return stat ? stat : count; + } + static FC_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL, +@@ -3103,7 +3079,7 @@ fc_scsi_scan_rport(struct work_struct *w + + + /** +- * fc_vport_create - allocates and creates a FC virtual port. ++ * fc_vport_setup - allocates and creates a FC virtual port. + * @shost: scsi host the virtual port is connected to. + * @channel: Channel on shost port connected to. + * @pdev: parent device for vport +@@ -3118,7 +3094,7 @@ fc_scsi_scan_rport(struct work_struct *w + * This routine assumes no locks are held on entry. + */ + static int +-fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, ++fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev, + struct fc_vport_identifiers *ids, struct fc_vport **ret_vport) + { + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); +@@ -3231,6 +3207,28 @@ delete_vport: + return error; + } + ++/** ++ * fc_vport_create - Admin App or LLDD requests creation of a vport ++ * @shost: scsi host the virtual port is connected to. ++ * @channel: channel on shost port connected to. ++ * @ids: The world wide names, FC4 port roles, etc for ++ * the virtual port. ++ * ++ * Notes: ++ * This routine assumes no locks are held on entry. ++ */ ++struct fc_vport * ++fc_vport_create(struct Scsi_Host *shost, int channel, ++ struct fc_vport_identifiers *ids) ++{ ++ int stat; ++ struct fc_vport *vport; ++ ++ stat = fc_vport_setup(shost, channel, &shost->shost_gendev, ++ ids, &vport); ++ return stat ? NULL : vport; ++} ++EXPORT_SYMBOL(fc_vport_create); + + /** + * fc_vport_terminate - Admin App or LLDD requests termination of a vport +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1436,27 +1437,21 @@ got_data: + */ + sector_size = 512; + } ++ blk_queue_hardsect_size(sdp->request_queue, sector_size); ++ + { +- /* +- * The msdos fs needs to know the hardware sector size +- * So I have created this table. See ll_rw_blk.c +- * Jacques Gelinas (Jacques@solucorp.qc.ca) +- */ +- int hard_sector = sector_size; +- sector_t sz = (sdkp->capacity/2) * (hard_sector/256); +- struct request_queue *queue = sdp->request_queue; +- sector_t mb = sz; +- +- blk_queue_hardsect_size(queue, hard_sector); +- /* avoid 64-bit division on 32-bit platforms */ +- sector_div(sz, 625); +- mb -= sz - 974; +- sector_div(mb, 1950); ++ char cap_str_2[10], cap_str_10[10]; ++ u64 sz = sdkp->capacity << ffz(~sector_size); ++ ++ string_get_size(sz, STRING_UNITS_2, cap_str_2, ++ sizeof(cap_str_2)); ++ string_get_size(sz, STRING_UNITS_10, cap_str_10, ++ sizeof(cap_str_10)); + + sd_printk(KERN_NOTICE, sdkp, +- "%llu %d-byte hardware sectors (%llu MB)\n", ++ "%llu %d-byte hardware sectors: (%s/%s)\n", + (unsigned long long)sdkp->capacity, +- hard_sector, (unsigned long long)mb); ++ sector_size, cap_str_10, cap_str_2); + } + + /* Rescale capacity to 512-byte units */ +--- /dev/null ++++ b/include/linux/string_helpers.h +@@ -0,0 +1,16 @@ ++#ifndef _LINUX_STRING_HELPERS_H_ ++#define _LINUX_STRING_HELPERS_H_ ++ ++#include ++ ++/* Descriptions of the types of units to ++ * print in */ ++enum string_size_units { ++ STRING_UNITS_10, /* use powers of 10^3 (standard SI) */ ++ STRING_UNITS_2, /* use binary powers of 2^10 */ ++}; ++ ++int string_get_size(u64 size, enum string_size_units units, ++ char *buf, int len); ++ ++#endif +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -42,9 +42,11 @@ enum scsi_device_state { + * originate in the mid-layer) */ + SDEV_OFFLINE, /* Device offlined (by error handling or + * user request */ +- SDEV_BLOCK, /* Device blocked by scsi lld. No scsi +- * commands from user or midlayer should be issued +- * to the scsi lld. */ ++ SDEV_BLOCK, /* Device blocked by scsi lld. No ++ * scsi commands from user or midlayer ++ * should be issued to the scsi ++ * lld. */ ++ SDEV_CREATED_BLOCK, /* same as above but for created devices */ + }; + + enum scsi_device_event { +@@ -384,10 +386,23 @@ static inline unsigned int sdev_id(struc + #define scmd_id(scmd) sdev_id((scmd)->device) + #define scmd_channel(scmd) sdev_channel((scmd)->device) + ++/* ++ * checks for positions of the SCSI state machine ++ */ + static inline int scsi_device_online(struct scsi_device *sdev) + { + return sdev->sdev_state != SDEV_OFFLINE; + } ++static inline int scsi_device_blocked(struct scsi_device *sdev) ++{ ++ return sdev->sdev_state == SDEV_BLOCK || ++ sdev->sdev_state == SDEV_CREATED_BLOCK; ++} ++static inline int scsi_device_created(struct scsi_device *sdev) ++{ ++ return sdev->sdev_state == SDEV_CREATED || ++ sdev->sdev_state == SDEV_CREATED_BLOCK; ++} + + /* accessor functions for the SCSI parameters */ + static inline int scsi_device_sync(struct scsi_device *sdev) +--- a/include/scsi/scsi_netlink.h ++++ b/include/scsi/scsi_netlink.h +@@ -22,6 +22,9 @@ + #ifndef SCSI_NETLINK_H + #define SCSI_NETLINK_H + ++#include ++ ++ + /* + * This file intended to be included by both kernel and user space + */ +@@ -55,7 +58,41 @@ struct scsi_nl_hdr { + #define SCSI_NL_TRANSPORT_FC 1 + #define SCSI_NL_MAX_TRANSPORTS 2 + +-/* scsi_nl_hdr->msgtype values are defined in each transport */ ++/* Transport-based scsi_nl_hdr->msgtype values are defined in each transport */ ++ ++/* ++ * GENERIC SCSI scsi_nl_hdr->msgtype Values ++ */ ++ /* kernel -> user */ ++#define SCSI_NL_SHOST_VENDOR 0x0001 ++ /* user -> kernel */ ++/* SCSI_NL_SHOST_VENDOR msgtype is kernel->user and user->kernel */ ++ ++ ++/* ++ * Message Structures : ++ */ ++ ++/* macro to round up message lengths to 8byte boundary */ ++#define SCSI_NL_MSGALIGN(len) (((len) + 7) & ~7) ++ ++ ++/* ++ * SCSI HOST Vendor Unique messages : ++ * SCSI_NL_SHOST_VENDOR ++ * ++ * Note: The Vendor Unique message payload will begin directly after ++ * this structure, with the length of the payload per vmsg_datalen. ++ * ++ * Note: When specifying vendor_id, be sure to read the Vendor Type and ID ++ * formatting requirements specified below ++ */ ++struct scsi_nl_host_vendor_msg { ++ struct scsi_nl_hdr snlh; /* must be 1st element ! */ ++ uint64_t vendor_id; ++ uint16_t host_no; ++ uint16_t vmsg_datalen; ++} __attribute__((aligned(sizeof(uint64_t)))); + + + /* +@@ -83,5 +120,28 @@ struct scsi_nl_hdr { + } + + ++#ifdef __KERNEL__ ++ ++#include ++ ++/* Exported Kernel Interfaces */ ++int scsi_nl_add_transport(u8 tport, ++ int (*msg_handler)(struct sk_buff *), ++ void (*event_handler)(struct notifier_block *, unsigned long, void *)); ++void scsi_nl_remove_transport(u8 tport); ++ ++int scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt, ++ int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload, ++ u32 len, u32 pid), ++ void (*nlevt_handler)(struct notifier_block *nb, ++ unsigned long event, void *notify_ptr)); ++void scsi_nl_remove_driver(u64 vendor_id); ++ ++void scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr); ++int scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id, ++ char *data_buf, u32 data_len); ++ ++#endif /* __KERNEL__ */ ++ + #endif /* SCSI_NETLINK_H */ + +--- a/include/scsi/scsi_transport_fc.h ++++ b/include/scsi/scsi_transport_fc.h +@@ -167,6 +167,26 @@ enum fc_tgtid_binding_type { + struct device_attribute dev_attr_vport_##_name = \ + __ATTR(_name,_mode,_show,_store) + ++/* ++ * fc_vport_identifiers: This set of data contains all elements ++ * to uniquely identify and instantiate a FC virtual port. ++ * ++ * Notes: ++ * symbolic_name: The driver is to append the symbolic_name string data ++ * to the symbolic_node_name data that it generates by default. ++ * the resulting combination should then be registered with the switch. ++ * It is expected that things like Xen may stuff a VM title into ++ * this field. ++ */ ++#define FC_VPORT_SYMBOLIC_NAMELEN 64 ++struct fc_vport_identifiers { ++ u64 node_name; ++ u64 port_name; ++ u32 roles; ++ bool disable; ++ enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */ ++ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN]; ++}; + + /* + * FC Virtual Port Attributes +@@ -197,7 +217,6 @@ struct device_attribute dev_attr_vport_# + * managed by the transport w/o driver interaction. + */ + +-#define FC_VPORT_SYMBOLIC_NAMELEN 64 + struct fc_vport { + /* Fixed Attributes */ + +@@ -732,6 +751,8 @@ void fc_host_post_vendor_event(struct Sc + * be sure to read the Vendor Type and ID formatting requirements + * specified in scsi_netlink.h + */ ++struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel, ++ struct fc_vport_identifiers *); + int fc_vport_terminate(struct fc_vport *vport); + + #endif /* SCSI_TRANSPORT_FC_H */ +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -19,7 +19,8 @@ lib-$(CONFIG_SMP) += cpumask.o + lib-y += kobject.o kref.o klist.o + + obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ +- bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o ++ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ ++ string_helpers.o + + ifeq ($(CONFIG_DEBUG_KOBJECT),y) + CFLAGS_kobject.o += -DDEBUG +--- /dev/null ++++ b/lib/string_helpers.c +@@ -0,0 +1,64 @@ ++/* ++ * Helpers for formatting and printing strings ++ * ++ * Copyright 31 August 2008 James Bottomley ++ */ ++#include ++#include ++#include ++#include ++ ++/** ++ * string_get_size - get the size in the specified units ++ * @size: The size to be converted ++ * @units: units to use (powers of 1000 or 1024) ++ * @buf: buffer to format to ++ * @len: length of buffer ++ * ++ * This function returns a string formatted to 3 significant figures ++ * giving the size in the required units. Returns 0 on success or ++ * error on failure. @buf is always zero terminated. ++ * ++ */ ++int string_get_size(u64 size, const enum string_size_units units, ++ char *buf, int len) ++{ ++ const char *units_10[] = { "B", "KB", "MB", "GB", "TB", "PB", ++ "EB", "ZB", "YB", NULL}; ++ const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", ++ "EiB", "ZiB", "YiB", NULL }; ++ const char **units_str[] = { ++ [STRING_UNITS_10] = units_10, ++ [STRING_UNITS_2] = units_2, ++ }; ++ const int divisor[] = { ++ [STRING_UNITS_10] = 1000, ++ [STRING_UNITS_2] = 1024, ++ }; ++ int i, j; ++ u64 remainder = 0, sf_cap; ++ char tmp[8]; ++ ++ tmp[0] = '\0'; ++ ++ for (i = 0; size > divisor[units] && units_str[units][i]; i++) ++ remainder = do_div(size, divisor[units]); ++ ++ sf_cap = size; ++ for (j = 0; sf_cap*10 < 1000; j++) ++ sf_cap *= 10; ++ ++ if (j) { ++ remainder *= 1000; ++ do_div(remainder, divisor[units]); ++ snprintf(tmp, sizeof(tmp), ".%03lld", ++ (unsigned long long)remainder); ++ tmp[j+1] = '\0'; ++ } ++ ++ snprintf(buf, len, "%lld%s%s", (unsigned long long)size, ++ tmp, units_str[units][i]); ++ ++ return 0; ++} ++EXPORT_SYMBOL(string_get_size); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-refactor-busy-processing b/src/patches/suse-2.6.27.31/patches.fixes/scsi-refactor-busy-processing new file mode 100644 index 000000000..74c159d88 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-refactor-busy-processing @@ -0,0 +1,94 @@ +Subject: [SCSI] refactor sdev/starget/shost busy checking +From: Kiyoshi Ueda +Date: Thu Oct 23 11:42:16 2008 -0500: +Git: 9d11251709f31d49c8167a619d4475fdf6cd7f73 + +This patch refactors the busy checking codes of scsi_device, +Scsi_Host and scsi_target. There should be no functional change. + +This is a preparation for another patch which exports scsi's busy +state to the block layer for request stacking drivers. + +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/scsi_lib.c | 30 ++++++++++++++++++++---------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -529,6 +529,14 @@ static void scsi_single_lun_run(struct s + spin_unlock_irqrestore(shost->host_lock, flags); + } + ++static inline int scsi_device_is_busy(struct scsi_device *sdev) ++{ ++ if (sdev->device_busy >= sdev->queue_depth || sdev->device_blocked) ++ return 1; ++ ++ return 0; ++} ++ + static inline int scsi_target_is_busy(struct scsi_target *starget) + { + return ((starget->can_queue > 0 && +@@ -536,6 +544,15 @@ static inline int scsi_target_is_busy(st + starget->target_blocked); + } + ++static inline int scsi_host_is_busy(struct Scsi_Host *shost) ++{ ++ if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || ++ shost->host_blocked || shost->host_self_blocked) ++ return 1; ++ ++ return 0; ++} ++ + /* + * Function: scsi_run_queue() + * +@@ -558,11 +575,7 @@ static void scsi_run_queue(struct reques + scsi_single_lun_run(sdev); + + spin_lock_irqsave(shost->host_lock, flags); +- while (!list_empty(&shost->starved_list) && +- !shost->host_blocked && !shost->host_self_blocked && +- !((shost->can_queue > 0) && +- (shost->host_busy >= shost->can_queue))) { +- ++ while (!list_empty(&shost->starved_list) && !scsi_host_is_busy(shost)) { + int flagset; + + /* +@@ -1349,8 +1362,6 @@ EXPORT_SYMBOL(scsi_prep_fn); + static inline int scsi_dev_queue_ready(struct request_queue *q, + struct scsi_device *sdev) + { +- if (sdev->device_busy >= sdev->queue_depth) +- return 0; + if (sdev->device_busy == 0 && sdev->device_blocked) { + /* + * unblock after device_blocked iterates to zero +@@ -1364,7 +1375,7 @@ static inline int scsi_dev_queue_ready(s + return 0; + } + } +- if (sdev->device_blocked) ++ if (scsi_device_is_busy(sdev)) + return 0; + + return 1; +@@ -1441,8 +1452,7 @@ static inline int scsi_host_queue_ready( + return 0; + } + } +- if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || +- shost->host_blocked || shost->host_self_blocked) { ++ if (scsi_host_is_busy(shost)) { + if (list_empty(&sdev->starved_entry)) + list_add_tail(&sdev->starved_entry, &shost->starved_list); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-remove-scmd-timeout b/src/patches/suse-2.6.27.31/patches.fixes/scsi-remove-scmd-timeout new file mode 100644 index 000000000..989fb1718 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-remove-scmd-timeout @@ -0,0 +1,285 @@ +From: James Bottomley +Subject: Fix block timeout residue problems +Date: Fri Dec 5 08:47:58 2008 +0100 +References: bnc#447249,bnc#441335 + +It looks like there was only a partial conversion of the SCSI layer to +the block timeout. The missing piece was killing timeout in struct +scsi_device and leaving it with a zero value. This has already +resulted in a regression: + +http://bugzilla.kernel.org/show_bug.cgi?id=12120 + +But on closer inspection, there were lots of other dangling driver +uses of the timeout value which would likewise have introduced hard to +trace regressions. + +This patch series eliminates the timeout variable from struct +scsi_device and makes everything uniformly use the block timeout. Any +wrong use of the scsi device timeout will now result in a compile +failure. + +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/aacraid/linit.c | 4 +- + drivers/scsi/ibmvscsi/ibmvscsi.c | 2 - + drivers/scsi/megaraid/megaraid_sas.c | 3 +- + drivers/scsi/scsi_error.c | 2 - + drivers/scsi/st.c | 47 ++++++++++++++++++++--------------- + drivers/scsi/stex.c | 2 - + include/scsi/scsi_device.h | 2 - + 7 files changed, 35 insertions(+), 27 deletions(-) + +--- a/drivers/scsi/aacraid/linit.c ++++ b/drivers/scsi/aacraid/linit.c +@@ -427,8 +427,8 @@ static int aac_slave_configure(struct sc + * Firmware has an individual device recovery time typically + * of 35 seconds, give us a margin. + */ +- if (sdev->timeout < (45 * HZ)) +- sdev->timeout = 45 * HZ; ++ if (sdev->request_queue->rq_timeout < (45 * HZ)) ++ blk_queue_rq_timeout(sdev->request_queue, 45*HZ); + for (cid = 0; cid < aac->maximum_num_containers; ++cid) + if (aac->fsa_dev[cid].valid) + ++num_lsu; +--- a/drivers/scsi/ibmvscsi/ibmvscsi.c ++++ b/drivers/scsi/ibmvscsi/ibmvscsi.c +@@ -1442,7 +1442,7 @@ static int ibmvscsi_slave_configure(stru + spin_lock_irqsave(shost->host_lock, lock_flags); + if (sdev->type == TYPE_DISK) { + sdev->allow_restart = 1; +- sdev->timeout = 60 * HZ; ++ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); + } + scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); + spin_unlock_irqrestore(shost->host_lock, lock_flags); +--- a/drivers/scsi/megaraid/megaraid_sas.c ++++ b/drivers/scsi/megaraid/megaraid_sas.c +@@ -1016,7 +1016,8 @@ static int megasas_slave_configure(struc + * The RAID firmware may require extended timeouts. + */ + if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) +- sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ; ++ blk_queue_rq_timeout(sdev->request_queue, ++ MEGASAS_DEFAULT_CMD_TIMEOUT * HZ); + return 0; + } + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -1013,7 +1013,7 @@ static int scsi_eh_try_stu(struct scsi_c + + for (i = 0; rtn == NEEDS_RETRY && i < 2; i++) + rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, +- scmd->device->timeout, 0); ++ scmd->device->request_queue->rq_timeout, 0); + + if (rtn == SUCCESS) + return 0; +--- a/drivers/scsi/st.c ++++ b/drivers/scsi/st.c +@@ -613,7 +613,8 @@ static int cross_eof(struct scsi_tape * + tape_name(STp), forward ? "forward" : "backward")); + + SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, +- STp->device->timeout, MAX_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_RETRIES, 1); + if (!SRpnt) + return (STp->buffer)->syscall_result; + +@@ -657,7 +658,8 @@ static int st_flush_write_buffer(struct + cmd[4] = blks; + + SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE, +- STp->device->timeout, MAX_WRITE_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_WRITE_RETRIES, 1); + if (!SRpnt) + return (STp->buffer)->syscall_result; + +@@ -987,7 +989,8 @@ static int check_tape(struct scsi_tape * + cmd[0] = READ_BLOCK_LIMITS; + + SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE, +- STp->device->timeout, MAX_READY_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_READY_RETRIES, 1); + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; + goto err_out; +@@ -1014,7 +1017,8 @@ static int check_tape(struct scsi_tape * + cmd[4] = 12; + + SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE, +- STp->device->timeout, MAX_READY_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_READY_RETRIES, 1); + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; + goto err_out; +@@ -1247,7 +1251,8 @@ static int st_flush(struct file *filp, f + cmd[4] = 1 + STp->two_fm; + + SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, +- STp->device->timeout, MAX_WRITE_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_WRITE_RETRIES, 1); + if (!SRpnt) { + result = (STp->buffer)->syscall_result; + goto out; +@@ -1634,7 +1639,8 @@ st_write(struct file *filp, const char _ + cmd[4] = blks; + + SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE, +- STp->device->timeout, MAX_WRITE_RETRIES, !async_write); ++ STp->device->request_queue->rq_timeout, ++ MAX_WRITE_RETRIES, !async_write); + if (!SRpnt) { + retval = STbp->syscall_result; + goto out; +@@ -1804,7 +1810,8 @@ static long read_tape(struct scsi_tape * + + SRpnt = *aSRpnt; + SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE, +- STp->device->timeout, MAX_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_RETRIES, 1); + release_buffering(STp, 1); + *aSRpnt = SRpnt; + if (!SRpnt) +@@ -2213,7 +2220,8 @@ static int st_set_options(struct scsi_ta + DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, + (value & ~MT_ST_SET_LONG_TIMEOUT))); + } else { +- STp->device->timeout = value * HZ; ++ blk_queue_rq_timeout(STp->device->request_queue, ++ value * HZ); + DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", + name, value) ); + } +@@ -2321,7 +2329,7 @@ static int read_mode_page(struct scsi_ta + cmd[4] = 255; + + SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, +- STp->device->timeout, 0, 1); ++ STp->device->request_queue->rq_timeout, 0, 1); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; + +@@ -2352,7 +2360,7 @@ static int write_mode_page(struct scsi_t + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR; + + SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, +- (slow ? STp->long_timeout : STp->device->timeout), 0, 1); ++ (slow ? STp->long_timeout : STp->device->request_queue->rq_timeout), 0, 1); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; + +@@ -2464,7 +2472,7 @@ static int do_load_unload(struct scsi_ta + } + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + } + else + timeout = STp->long_timeout; +@@ -2638,7 +2646,7 @@ static int st_int_ioctl(struct scsi_tape + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + DEBC( + if (cmd_in == MTWEOF) + printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name, +@@ -2656,7 +2664,7 @@ static int st_int_ioctl(struct scsi_tape + cmd[0] = REZERO_UNIT; + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + } + DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name)); + fileno = blkno = at_sm = 0; +@@ -2669,7 +2677,7 @@ static int st_int_ioctl(struct scsi_tape + cmd[0] = START_STOP; + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + } + cmd[4] = 3; + DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name)); +@@ -2702,7 +2710,7 @@ static int st_int_ioctl(struct scsi_tape + cmd[1] = (arg ? 1 : 0); /* Long erase with non-zero argument */ + if (STp->immediate) { + cmd[1] |= 2; /* Don't wait for completion */ +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + } + else + timeout = STp->long_timeout * 8; +@@ -2754,7 +2762,7 @@ static int st_int_ioctl(struct scsi_tape + (STp->buffer)->b_data[9] = (ltmp >> 16); + (STp->buffer)->b_data[10] = (ltmp >> 8); + (STp->buffer)->b_data[11] = ltmp; +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + DEBC( + if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) + printk(ST_DEB_MSG +@@ -2944,7 +2952,8 @@ static int get_location(struct scsi_tape + scmd[1] = 1; + } + SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE, +- STp->device->timeout, MAX_READY_RETRIES, 1); ++ STp->device->request_queue->rq_timeout, ++ MAX_READY_RETRIES, 1); + if (!SRpnt) + return (STp->buffer)->syscall_result; + +@@ -3045,7 +3054,7 @@ static int set_location(struct scsi_tape + } + if (STp->immediate) { + scmd[1] |= 1; /* Don't wait for completion */ +- timeout = STp->device->timeout; ++ timeout = STp->device->request_queue->rq_timeout; + } + + SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE, +@@ -4028,7 +4037,7 @@ static int st_probe(struct device *dev) + tpnt->partition = 0; + tpnt->new_partition = 0; + tpnt->nbr_partitions = 0; +- tpnt->device->timeout = ST_TIMEOUT; ++ blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT); + tpnt->long_timeout = ST_LONG_TIMEOUT; + tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma; + +--- a/drivers/scsi/stex.c ++++ b/drivers/scsi/stex.c +@@ -477,7 +477,7 @@ stex_slave_config(struct scsi_device *sd + { + sdev->use_10_for_rw = 1; + sdev->use_10_for_ms = 1; +- sdev->timeout = 60 * HZ; ++ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); + sdev->tagged_supported = 1; + + return 0; +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -160,8 +160,6 @@ struct scsi_device { + atomic_t iodone_cnt; + atomic_t ioerr_cnt; + +- int timeout; +- + struct device sdev_gendev, + sdev_dev; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-restart-lookup-by-target b/src/patches/suse-2.6.27.31/patches.fixes/scsi-restart-lookup-by-target new file mode 100644 index 000000000..1f82fadb4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-restart-lookup-by-target @@ -0,0 +1,38 @@ +From: Hannes Reinecke +Subject: Skip deleted devices in __scsi_device_lookup_by_target() +References: bnc#465346 + +__scsi_device_lookup_by_target() will always return +the first sdev with a matching LUN, regardless of +the state. However, when this sdev is in SDEV_DEL +scsi_device_lookup_by_target() will ignore this +device and so any valid device on the list after +the deleted device will never be found. +So we have to modify __scsi_device_lookup_by_target() +to skip any device in SDEV_DEL. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c +index f8b79d4..537bb92 100644 +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -1099,7 +1099,8 @@ EXPORT_SYMBOL(__starget_for_each_device); + * Description: Looks up the scsi_device with the specified @lun for a given + * @starget. The returned scsi_device does not have an additional + * reference. You must hold the host's host_lock over this call and +- * any access to the returned scsi_device. ++ * any access to the returned scsi_device. A scsi_device in state ++ * SDEV_DEL is skipped. + * + * Note: The only reason why drivers should use this is because + * they need to access the device list in irq context. Otherwise you +@@ -1111,6 +1112,8 @@ struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget, + struct scsi_device *sdev; + + list_for_each_entry(sdev, &starget->devices, same_target_siblings) { ++ if (sdev->sdev_state == SDEV_DEL) ++ continue; + if (sdev->lun ==lun) + return sdev; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-TASK_ABORTED b/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-TASK_ABORTED new file mode 100644 index 000000000..8d5e2b1f9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-TASK_ABORTED @@ -0,0 +1,42 @@ +Subject: scsi_error: TASK ABORTED status handling improvement +From: Vladislav Bolkhovitin +Date: Fri Nov 7 11:21:03 2008 -0600: +Git: ab2d67aa39bc63a60fba748b27cf4d962d0dc7f8 + +This patch improves handling of TASK ABORTED status by Linux SCSI +mid-layer. Currently, command returned with this status considered +failed and returned to upper layers. It leads to additional error +recovery load on file systems and block layer, which sometimes can +cause undesired side effects, like I/O errors and file systems +corruptions. See http://lkml.org/lkml/2008/11/1/38, for instance. + +From other side, TASK ABORTED status is returned by SCSI target if the +corresponding command was aborted by another initiator and the target +has TAS bit set in the control mode page. So, in the majority of cases +commands with TASK ABORTED status should be simply retried. In other +cases, maybe_retry path will not retry if no retries are allowed. + +This patch implement suggestion by James Bottomley from +http://marc.info/?l=linux-scsi&m=121932916906009&w=2. + +Signed-off-by: Vladislav Bolkhovitin +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/scsi_error.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -1486,8 +1486,9 @@ int scsi_decide_disposition(struct scsi_ + return ADD_TO_MLQUEUE; + case GOOD: + case COMMAND_TERMINATED: +- case TASK_ABORTED: + return SUCCESS; ++ case TASK_ABORTED: ++ goto maybe_retry; + case CHECK_CONDITION: + rtn = scsi_check_sense(scmd); + if (rtn == NEEDS_RETRY) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-alua-transition-in-progress b/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-alua-transition-in-progress new file mode 100644 index 000000000..4ce5b3ff9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-alua-transition-in-progress @@ -0,0 +1,32 @@ +From: Rajashekhar M A +Subject: I/O errors for ALUA state transitions +References: bnc#491289 + +When a SLES11 host is configured with a few LUNs and IO is running, +injecting FC faults repeatedly leads to path recovery problems. +The LUNs have 4 paths each and 3 of them come back active after +say an FC fault which makes two of the paths go down, instead of +all 4. This happens after several iterations of continuous FC faults. + +Reason here is that we're returning an I/O error whenever we're +encountering sense code 06/04/0a (LOGICAL UNIT NOT ACCESSIBLE, +ASYMMETRIC ACCESS STATE TRANSITION) instead of retrying. + +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/scsi_error.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -383,7 +383,8 @@ static int scsi_check_sense(struct scsi_ + * if the device is in the process of becoming ready, we + * should retry. + */ +- if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01)) ++ if ((sshdr.asc == 0x04) && ++ (sshdr.ascq == 0x01 || sshdr.ascq == 0x0a)) + return NEEDS_RETRY; + /* + * if the device is not started, we need to wake diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-transport-error b/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-transport-error new file mode 100644 index 000000000..8eb3c3a19 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-retry-transport-error @@ -0,0 +1,37 @@ +Subject: scsi_error regression: Fix idempotent command handling +From: Mike Christie +Date: Wed Nov 5 12:48:23 2008 -0500: +Git: 939c2288c35132fe340b2694c7d02cacf7593723 + +Drivers want to be able to return DID_TRANSPORT_DISRUPTED and +have it do the right thing for commands like tape and passthrouh +as far as retries go. The LLDs previously used DID_BUS_BUSY or DID_ERROR +which followed the cmd->retries limit, but DID_TRANSPORT_DISRUPTED +was skipping that check so it could have caused a problem with tape +commands. + +This patch has DID_TRANSPORT_DISRUPTED check the cmd->retries/cmd->allowed. + +Signed-off-by: Mike Christie +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke + +--- + drivers/scsi/scsi_error.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -1420,9 +1420,10 @@ int scsi_decide_disposition(struct scsi_ + * LLD/transport was disrupted during processing of the IO. + * The transport class is now blocked/blocking, + * and the transport will decide what to do with the IO +- * based on its timers and recovery capablilities. ++ * based on its timers and recovery capablilities if ++ * there are enough retries. + */ +- return ADD_TO_MLQUEUE; ++ goto maybe_retry; + case DID_TRANSPORT_FAILFAST: + /* + * The transport decided to failfast the IO (most likely diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-scan-blist-update b/src/patches/suse-2.6.27.31/patches.fixes/scsi-scan-blist-update new file mode 100644 index 000000000..7d1b78ab9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-scan-blist-update @@ -0,0 +1,25 @@ +From: Kurt Garloff +Subject: Add BLIST_REPORTLUN2 to EMC SYMMETRIX +Patch-mainline: not yet +References: 185164, 191648, 505578 + +All EMC SYMMETRIX support REPORT_LUNS, even if configured to report +SCSI-2 for whatever reason. + +Acked-by: +Signed-off-by: Kurt Garloff +Signed-off-by: Hannes Reinecke + +Index: root/drivers/scsi/scsi_devinfo.c +=================================================================== +--- root.orig/drivers/scsi/scsi_devinfo.c ++++ root/drivers/scsi/scsi_devinfo.c +@@ -152,7 +152,7 @@ static struct { + {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ + {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ + {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, +- {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, ++ {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_REPORTLUN2}, + {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, + {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN}, + {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN}, diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-scan-set-SDEV_DEL-on-destroy b/src/patches/suse-2.6.27.31/patches.fixes/scsi-scan-set-SDEV_DEL-on-destroy new file mode 100644 index 000000000..68e8cb963 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-scan-set-SDEV_DEL-on-destroy @@ -0,0 +1,28 @@ +From: James Smart +Subject: add missing interim SDEV_DEL state if slave_alloc fails +References: bnc#468640 + +We were running i/o and performing a bunch of hba resets in a loop. +This forces a lot of target removes and then rescans. Since the +resets are occuring during scan it's causing the scan i/o to timeout, +invoking error recovery, etc. We end up getting some nasty crashing +in scsi_scan.c due to references to old sdevs that are failing +but had some lingering references that kept them around. + +Fix by setting device state to SDEV_DEL if the LLD's slave_alloc +fails. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index e5777e6..262a7ea 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -314,6 +314,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, + return sdev; + + out_device_destroy: ++ scsi_device_set_state(sdev, SDEV_DEL); + transport_destroy_device(&sdev->sdev_gendev); + put_device(&sdev->sdev_gendev); + out: diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-skip-nonscsi-device-for-dma b/src/patches/suse-2.6.27.31/patches.fixes/scsi-skip-nonscsi-device-for-dma new file mode 100644 index 000000000..7cb75c0f2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-skip-nonscsi-device-for-dma @@ -0,0 +1,106 @@ +From: James Smart +Subject: scsi_lib_dma.c : fix bug w/ dma on virtual fc ports +References: bnc#431294 + +When the updated scsi dma code was introduced recently, it assumed +the physical host/adapter was the parent of the scsi host. +Unfortunately, on FC virtual ports, the parent of the scsi host is +the virtual port, which does not have dma information. + +I have updated the dma routines to use a function that finds the +first non-scsi object. A non-scsi object is defined to be an object +that has a non-NULL type (assumes all transport objects have NULL +types) or a non-scsi_host type. + +-- james s + +Unfortunately the original patch is not correct, as eg the PCI device +doesn't set the 'type' pointer, so the system will crash miserably. +We should rather check for the 'bus' argument, and return the original +argument if we don't find anything. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index 69321e3..208e7df 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1713,7 +1713,7 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, + request_fn_proc *request_fn) + { + struct request_queue *q; +- struct device *dev = shost->shost_gendev.parent; ++ struct device *dev = dev_to_nonscsi_dev(shost->shost_gendev.parent); + + q = blk_init_queue(request_fn, NULL); + if (!q) +diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c +index ac6855c..567cdbc 100644 +--- a/drivers/scsi/scsi_lib_dma.c ++++ b/drivers/scsi/scsi_lib_dma.c +@@ -23,7 +23,8 @@ int scsi_dma_map(struct scsi_cmnd *cmd) + int nseg = 0; + + if (scsi_sg_count(cmd)) { +- struct device *dev = cmd->device->host->shost_gendev.parent; ++ struct device *dev = dev_to_nonscsi_dev( ++ cmd->device->host->shost_gendev.parent); + + nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd), + cmd->sc_data_direction); +@@ -41,10 +42,12 @@ EXPORT_SYMBOL(scsi_dma_map); + void scsi_dma_unmap(struct scsi_cmnd *cmd) + { + if (scsi_sg_count(cmd)) { +- struct device *dev = cmd->device->host->shost_gendev.parent; ++ struct device *dev = dev_to_nonscsi_dev( ++ cmd->device->host->shost_gendev.parent); + + dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd), + cmd->sc_data_direction); + } + } + EXPORT_SYMBOL(scsi_dma_unmap); ++ +diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h +index d123ca8..55d74c8 100644 +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -689,6 +689,10 @@ static inline void *shost_priv(struct Scsi_Host *shost) + + int scsi_is_host_device(const struct device *); + ++/* ++ * walks object list backward, to find the first shost object. ++ * Skips over transport objects that may not be stargets, etc ++ */ + static inline struct Scsi_Host *dev_to_shost(struct device *dev) + { + while (!scsi_is_host_device(dev)) { +@@ -699,6 +703,26 @@ static inline struct Scsi_Host *dev_to_shost(struct device *dev) + return container_of(dev, struct Scsi_Host, shost_gendev); + } + ++/* ++ * walks object list backward, to find the first physical ++ * device object. If none is found return the original device. ++ */ ++static inline struct device *dev_to_nonscsi_dev(struct device *dev) ++{ ++ struct device *orig = dev; ++ ++ while (dev && (dev->bus == NULL || scsi_is_host_device(dev))) { ++ if (dev->dma_parms) { ++ dev_printk(KERN_WARNING, dev, ++ "dma_parms set, bus %p\n", ++ dev->bus); ++ break; ++ } ++ dev = dev->parent; ++ } ++ return dev?dev:orig; ++} ++ + static inline int scsi_host_in_recovery(struct Scsi_Host *shost) + { + return shost->shost_state == SHOST_RECOVERY || diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi-terminate-target-reset b/src/patches/suse-2.6.27.31/patches.fixes/scsi-terminate-target-reset new file mode 100644 index 000000000..b2b6a32e5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi-terminate-target-reset @@ -0,0 +1,78 @@ +From: James Bottomley +Subject: Target reset hangs +Date: Fri, 12 Sep 2008 16:46:51 -0500 +References: bnc#427267 + +Actually, turns out it's nothing to do with block timeouts, it's a +target reset bug. + +This loop: + + for (id = 0; id <= shost->max_id; id++) { + +Never terminates if shost->max_id is set to ~0, like aic94xx does. + +It's also pretty inefficient since you mostly have compact target +numbers, but the max_id can be very high. The best way would be to sort +the recovery list by target id and skip them if they're equal, but even +a worst case O(N^2) traversal is probably OK here. + +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke +--- +diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c +index ad019ec..94ed262 100644 +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -1065,10 +1065,10 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, + struct list_head *done_q) + { + struct scsi_cmnd *scmd, *tgtr_scmd, *next; +- unsigned int id; ++ unsigned int id = 0; + int rtn; + +- for (id = 0; id <= shost->max_id; id++) { ++ do { + tgtr_scmd = NULL; + list_for_each_entry(scmd, work_q, eh_entry) { + if (id == scmd_id(scmd)) { +@@ -1076,8 +1076,18 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, + break; + } + } ++ if (!tgtr_scmd) { ++ /* not one exactly equal; find the next highest */ ++ list_for_each_entry(scmd, work_q, eh_entry) { ++ if (scmd_id(scmd) > id && ++ (!tgtr_scmd || ++ scmd_id(tgtr_scmd) > scmd_id(scmd))) ++ tgtr_scmd = scmd; ++ } ++ } + if (!tgtr_scmd) +- continue; ++ /* no more commands, that's it */ ++ break; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset " + "to target %d\n", +@@ -1096,7 +1106,8 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, + " failed target: " + "%d\n", + current->comm, id)); +- } ++ id++; ++ } while(id != 0); + + return list_empty(work_q); + } + + + + + +-- +To unsubscribe from this list: send the line "unsubscribe linux-scsi" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi_dh-add-lsi-ids-to-rdac b/src/patches/suse-2.6.27.31/patches.fixes/scsi_dh-add-lsi-ids-to-rdac new file mode 100644 index 000000000..1e844c49b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi_dh-add-lsi-ids-to-rdac @@ -0,0 +1,29 @@ +From 3406800934c6602ee7f7ddf5db1ab5f040cbaab3 Mon Sep 17 00:00:00 2001 +From: Hannes Reinecke +Date: Tue, 16 Dec 2008 09:02:47 +0100 +Subject: [PATCH] Adding LSI vendor and product IDs to RDAC device handler + +This patch adds LSI vendor and product ids in rdac device handler. + +Signed-off-by: Babu Moger +Signed-off-by: Hannes Reinecke +--- + drivers/scsi/device_handler/scsi_dh_rdac.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c +index 67e5e52..f25a03e 100644 +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -602,6 +602,8 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { + {"SUN", "LCSM100_F", 0}, + {"DELL", "MD3000", 0}, + {"DELL", "MD3000i", 0}, ++ {"LSI", "INF-01-00"}, ++ {"ENGENIO", "INF-01-00"}, + {NULL, NULL, 0}, + }; + +-- +1.5.3.2 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/scsi_dh-retry-on-UNIT_ATTENTION b/src/patches/suse-2.6.27.31/patches.fixes/scsi_dh-retry-on-UNIT_ATTENTION new file mode 100644 index 000000000..78f86314b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/scsi_dh-retry-on-UNIT_ATTENTION @@ -0,0 +1,29 @@ +From: Hannes Reinecke +Subject: scsi_dh_rdac does not retry MODE SENSE on UNIT ATTENTION +References: bnc#464155 + +When we encounter a UNIT ATTENTION sense code we should always retry +the command; the ASC and ASQ codes are irrelevant here. + +Signed-off-by: Hannes Reinecke +Signed-off-by: Chandra Seetharaman + +diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c +index f25a03e..3ab052d 100644 +--- a/drivers/scsi/device_handler/scsi_dh_rdac.c ++++ b/drivers/scsi/device_handler/scsi_dh_rdac.c +@@ -459,11 +459,10 @@ static int mode_select_handle_sense(struct scsi_device *sdev, + sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) | + sense_hdr.ascq; + /* If it is retryable failure, submit the c9 inquiry again */ +- if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 || +- sense == 0x62900) { ++ if (sense_hdr.sense_key == 6 || sense == 0x59136 || sense == 0xb8b02) { + /* 0x59136 - Command lock contention +- * 0x[6b]8b02 - Quiesense in progress or achieved +- * 0x62900 - Power On, Reset, or Bus Device Reset ++ * 0xb8b02 - Quiescense achieved ++ * 0x6xxxx - Unit Attention + */ + err = SCSI_DH_RETRY; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sd-needs-updating b/src/patches/suse-2.6.27.31/patches.fixes/sd-needs-updating new file mode 100644 index 000000000..1da0a6b8f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sd-needs-updating @@ -0,0 +1,104 @@ +Subject: Driver 'sd' needs updating +From: Hannes Reinecke +Date: Tue Oct 7 16:17:19 2008 +0200: +Git: 2ec147acf8022cc363266fde3e8f5f89149926c8 +References: bnc#406656 + +If a driver sets blk_queue_prep_rq(), it should clean it up itself, and +not from the bus callbacks. This removes the need to hook into bus->remove(), +which should not be used at the same time as driver->remove(). + +Signed-off-by: Hannes Reinecke +Signed-off-by: Kay Sievers + +--- + drivers/scsi/scsi_lib.c | 1 + + drivers/scsi/scsi_priv.h | 1 - + drivers/scsi/scsi_sysfs.c | 17 ----------------- + drivers/scsi/sd.c | 2 ++ + drivers/scsi/sr.c | 1 + + include/scsi/scsi_driver.h | 1 + + 6 files changed, 5 insertions(+), 18 deletions(-) + +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1338,6 +1338,7 @@ int scsi_prep_fn(struct request_queue *q + ret = scsi_setup_blk_pc_cmnd(sdev, req); + return scsi_prep_return(q, req, ret); + } ++EXPORT_SYMBOL(scsi_prep_fn); + + /* + * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else +--- a/drivers/scsi/scsi_priv.h ++++ b/drivers/scsi/scsi_priv.h +@@ -74,7 +74,6 @@ extern int scsi_init_queue(void); + extern void scsi_exit_queue(void); + struct request_queue; + struct request; +-extern int scsi_prep_fn(struct request_queue *, struct request *); + extern struct kmem_cache *scsi_sdb_cache; + + /* scsi_proc.c */ +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -420,29 +420,12 @@ static int scsi_bus_resume(struct device + return err; + } + +-static int scsi_bus_remove(struct device *dev) +-{ +- struct device_driver *drv = dev->driver; +- struct scsi_device *sdev = to_scsi_device(dev); +- int err = 0; +- +- /* reset the prep_fn back to the default since the +- * driver may have altered it and it's being removed */ +- blk_queue_prep_rq(sdev->request_queue, scsi_prep_fn); +- +- if (drv && drv->remove) +- err = drv->remove(dev); +- +- return 0; +-} +- + struct bus_type scsi_bus_type = { + .name = "scsi", + .match = scsi_bus_match, + .uevent = scsi_bus_uevent, + .suspend = scsi_bus_suspend, + .resume = scsi_bus_resume, +- .remove = scsi_bus_remove, + }; + EXPORT_SYMBOL_GPL(scsi_bus_type); + +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -1914,6 +1914,8 @@ static int sd_remove(struct device *dev) + { + struct scsi_disk *sdkp = dev_get_drvdata(dev); + ++ blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); ++ + device_del(&sdkp->dev); + del_gendisk(sdkp->disk); + sd_shutdown(dev); +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -895,6 +895,7 @@ static int sr_remove(struct device *dev) + { + struct scsi_cd *cd = dev_get_drvdata(dev); + ++ blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn); + del_gendisk(cd->disk); + + mutex_lock(&sr_ref_mutex); +--- a/include/scsi/scsi_driver.h ++++ b/include/scsi/scsi_driver.h +@@ -32,5 +32,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_d + int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req); + int scsi_prep_state_check(struct scsi_device *sdev, struct request *req); + int scsi_prep_return(struct request_queue *q, struct request *req, int ret); ++int scsi_prep_fn(struct request_queue *, struct request *); + + #endif /* _SCSI_SCSI_DRIVER_H */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sd-no-spinup-on-standby-ports b/src/patches/suse-2.6.27.31/patches.fixes/sd-no-spinup-on-standby-ports new file mode 100644 index 000000000..43fdd0661 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sd-no-spinup-on-standby-ports @@ -0,0 +1,58 @@ +From: Matthew Wilcox +Date: Fri, 20 Feb 2009 13:53:48 +0000 (-0700) +Subject: sd: Don't try to spin up drives that are connected to an inactive port +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjejb%2Fscsi-rc-fixes-2.6.git;a=commitdiff_plain;h=33dd6f92a1a7ad85c54d47fd9d73371a32c0bde4 +References: bnc#477624 + +We currently try to spin up drives connected to standby and unavailable +ports. This will never succeed and wastes a lot of time. Fail quickly +if the sense data reports the port is in standby or unavailable state. + +Reported-by: Narayanan Rengarajan +Tested-by: Narayanan Rengarajan +Signed-off-by: Matthew Wilcox +Signed-off-by: James Bottomley +Signed-off-by: Hannes Reinecke +--- + +--- + drivers/scsi/sd.c | 26 +++++++++++--------------- + 1 file changed, 11 insertions(+), 15 deletions(-) + +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -1172,23 +1172,19 @@ sd_spinup_disk(struct scsi_disk *sdkp) + /* + * The device does not want the automatic start to be issued. + */ +- if (sdkp->device->no_start_on_add) { ++ if (sdkp->device->no_start_on_add) + break; +- } +- +- /* +- * If manual intervention is required, or this is an +- * absent USB storage device, a spinup is meaningless. +- */ +- if (sense_valid && +- sshdr.sense_key == NOT_READY && +- sshdr.asc == 4 && sshdr.ascq == 3) { +- break; /* manual intervention required */ + +- /* +- * Issue command to spin up drive when not ready +- */ +- } else if (sense_valid && sshdr.sense_key == NOT_READY) { ++ if (sense_valid && sshdr.sense_key == NOT_READY) { ++ if (sshdr.asc == 4 && sshdr.ascq == 3) ++ break; /* manual intervention required */ ++ if (sshdr.asc == 4 && sshdr.ascq == 0xb) ++ break; /* standby */ ++ if (sshdr.asc == 4 && sshdr.ascq == 0xc) ++ break; /* unavailable */ ++ /* ++ * Issue command to spin up drive when not ready ++ */ + if (!spintime) { + sd_printk(KERN_NOTICE, sdkp, "Spinning up disk..."); + cmd[0] = START_STOP; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/seccomp-disable-tsc-option b/src/patches/suse-2.6.27.31/patches.fixes/seccomp-disable-tsc-option new file mode 100644 index 000000000..c0eec8204 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/seccomp-disable-tsc-option @@ -0,0 +1,76 @@ +From: Andrea Arcangeli +Subject: [PATCH seccomp: make tsc disabling optional +Patch-mainline: unknown +References: 191123 + +Make the TSC disable purely paranoid feature optional, so by default seccomp +returns absolutely zerocost. + +Ported from 2.6.19 to 2.6.24-rc7 by Jeff Mahoney. +Addition of x86-64 by Jan Beulich. + +Signed-off-by: Andrea Arcangeli +Acked-by: Jeff Mahoney +--- + arch/x86/Kconfig | 12 ++++++++++++ + arch/x86/kernel/process_32.c | 2 ++ + arch/x86/kernel/process_64.c | 2 ++ + 3 files changed, 16 insertions(+) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1228,6 +1228,18 @@ config SECCOMP + + If unsure, say Y. Only embedded should say N here. + ++config SECCOMP_DISABLE_TSC ++ bool "Disable the TSC for seccomp tasks" ++ depends on SECCOMP ++ default n ++ help ++ This feature mathematically prevents covert channels ++ for tasks running under SECCOMP. This can generate ++ a minuscule overhead in the scheduler. ++ ++ If you care most about performance say N. Say Y only if you're ++ paranoid about covert channels. ++ + config CC_STACKPROTECTOR + bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" + depends on X86_64 && EXPERIMENTAL && BROKEN +--- a/arch/x86/kernel/process_32.c ++++ b/arch/x86/kernel/process_32.c +@@ -387,6 +387,7 @@ static void hard_disable_TSC(void) + + void disable_TSC(void) + { ++#ifdef CONFIG_SECCOMP_DISABLE_TSC + preempt_disable(); + if (!test_and_set_thread_flag(TIF_NOTSC)) + /* +@@ -395,6 +396,7 @@ void disable_TSC(void) + */ + hard_disable_TSC(); + preempt_enable(); ++#endif + } + + static void hard_enable_TSC(void) +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -406,6 +406,7 @@ static void hard_disable_TSC(void) + + void disable_TSC(void) + { ++#ifdef CONFIG_SECCOMP_DISABLE_TSC + preempt_disable(); + if (!test_and_set_thread_flag(TIF_NOTSC)) + /* +@@ -414,6 +415,7 @@ void disable_TSC(void) + */ + hard_disable_TSC(); + preempt_enable(); ++#endif + } + + static void hard_enable_TSC(void) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/slab-alloc_slabmgmt-fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/slab-alloc_slabmgmt-fix.patch new file mode 100644 index 000000000..c11d5ceda --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/slab-alloc_slabmgmt-fix.patch @@ -0,0 +1,38 @@ +From: Pekka Enberg +Date: Tue, 25 Nov 2008 00:33:28 +0200 +Subject: slab: remove GFP_THISNODE clearing from alloc_slabmgmt() +Patch-mainline: 2.6.28? +References: bnc#444597 + +Commit 6cb062296f73e74768cca2f3eaf90deac54de02d ("Categorize GFP flags") +left one call-site in alloc_slabmgmt() to clear GFP_THISNODE instead of +GFP_CONSTRAINT_MASK. Unfortunately, that ends up clearing __GFP_NOWARN +and __GFP_NORETRY as well which is not what we want. As the only caller +of alloc_slabmgmt() already clears GFP_CONSTRAINT_MASK before passing +local_flags to it, we can just remove the clearing of GFP_THISNODE. + +This patch should fix spurious page allocation failure warnings on the +mempool_alloc() path. See the following URL for an example: + + http://lkml.org/lkml/2008/10/27/100 + +Reported-by: Miklos Szeredi +Signed-off-by: Pekka Enberg +Acked-by: Miklos Szeredi +--- + mm/slab.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/mm/slab.c b/mm/slab.c +index 918f04f..98d3024 100644 +--- a/mm/slab.c ++++ b/mm/slab.c +@@ -2608,7 +2608,7 @@ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp, + if (OFF_SLAB(cachep)) { + /* Slab management obj is off-slab. */ + slabp = kmem_cache_alloc_node(cachep->slabp_cache, +- local_flags & ~GFP_THISNODE, nodeid); ++ local_flags, nodeid); + if (!slabp) + return NULL; + } else { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sn-irq-affinity b/src/patches/suse-2.6.27.31/patches.fixes/sn-irq-affinity new file mode 100644 index 000000000..fbb0c8e91 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sn-irq-affinity @@ -0,0 +1,67 @@ +From: Tony Ernst +Subject: sn2: preserve irq affinity set in PROM +Patch-mainline: No, this is a one-off from the mainline fix +References: bnc#457679 + + The latest SLES11 has numerous changes in the + request_irq() path, the one of issue is irq_select_affinity(), + which reassigns an IRQ to a CPU. And, in the case of SN2 Altix, + it assigns every IRQ to the same CPU; CPU0 in most cases, except + on systems like rappel where it's CPU1, due to the Shub1.1 restrictions. + + This is a problem. Unlike most platforms, on Altix, the assignment + of an IRQ to a CPU is determined and setup in the PROM, and the kernel + is not expected to change this, except in the case of a manual + redirect/migration. + +Acked-by: Jeff Mahoney +--- + arch/ia64/sn/kernel/irq.c | 5 +++++ + include/linux/irq.h | 1 + + kernel/irq/manage.c | 11 +++++++++++ + 3 files changed, 17 insertions(+) + +--- a/arch/ia64/sn/kernel/irq.c 2008-10-09 17:13:53.000000000 -0500 ++++ b/arch/ia64/sn/kernel/irq.c 2008-12-18 13:34:46.822283902 -0600 +@@ -391,6 +391,11 @@ + #ifdef CONFIG_SMP + cpuphys = cpu_physical_id(cpu); + set_irq_affinity_info(sn_irq_info->irq_irq, cpuphys, 0); ++ /* ++ * Affinity was set by the PROM, prevent it from ++ * being reset by the request_irq() path. ++ */ ++ irq_desc[sn_irq_info->irq_irq].status |= IRQ_AFFINITY_SET; + #endif + } + +--- a/include/linux/irq.h 2008-12-16 11:27:10.000000000 -0600 ++++ b/include/linux/irq.h 2008-12-18 13:49:23.519706754 -0600 +@@ -63,6 +63,7 @@ + #define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */ + #define IRQ_SPURIOUS_DISABLED 0x00800000 /* IRQ was disabled by the spurious trap */ + #define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */ ++#define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was previously set */ + + #ifdef CONFIG_IRQ_PER_CPU + # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) +--- a/kernel/irq/manage.c 2008-12-16 11:27:10.000000000 -0600 ++++ b/kernel/irq/manage.c 2008-12-18 13:36:15.693395542 -0600 +@@ -117,6 +117,17 @@ + + cpus_and(mask, cpu_online_map, irq_default_affinity); + ++ /* ++ * Preserve the affinity that was previously set, but make ++ * sure one of the targets is online. ++ */ ++ if (irq_desc[irq].status & IRQ_AFFINITY_SET) { ++ if (cpus_intersects(irq_desc[irq].affinity, cpu_online_map)) ++ mask = irq_desc[irq].affinity; ++ else ++ irq_desc[irq].status &= ~IRQ_AFFINITY_SET; ++ } ++ + irq_desc[irq].affinity = mask; + irq_desc[irq].chip->set_affinity(irq, mask); + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sparsemem-maxmem-fix b/src/patches/suse-2.6.27.31/patches.fixes/sparsemem-maxmem-fix new file mode 100644 index 000000000..faf63817c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sparsemem-maxmem-fix @@ -0,0 +1,42 @@ +From: Ingo Molnar +Subject: Limit MAXMEM on 64bit +Patch-Mainline: Yes + +on 64-bit x86 the physical memory limit is controlled by the sparsemem +bits - which are 44 bits right now. But MAXMEM (the max pfn number +e820 parsing will allow to enter our sizing routines) is set to +0x00003fffffffffff, i.e. 46 bits - that's too large because it overlaps +into the vmalloc range. + +So couple MAXMEM to MAX_PHYSMEM_BITS, and add a comment that the +maximum of MAX_PHYSMEM_BITS is 45 bits. + +Signed-off-by: Ingo Molnar +Signed-off-by: Hannes Reinecke + +Index: linux-2.6.27-SLE11_BRANCH/include/asm-x86/pgtable_64.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/include/asm-x86/pgtable_64.h ++++ linux-2.6.27-SLE11_BRANCH/include/asm-x86/pgtable_64.h +@@ -146,7 +146,7 @@ static inline void native_pgd_clear(pgd_ + #define PGDIR_MASK (~(PGDIR_SIZE - 1)) + + +-#define MAXMEM _AC(0x00003fffffffffff, UL) ++#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL) + #define VMALLOC_START _AC(0xffffc20000000000, UL) + #define VMALLOC_END _AC(0xffffe1ffffffffff, UL) + #define VMEMMAP_START _AC(0xffffe20000000000, UL) +Index: linux-2.6.27-SLE11_BRANCH/include/asm-x86/sparsemem.h +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/include/asm-x86/sparsemem.h ++++ linux-2.6.27-SLE11_BRANCH/include/asm-x86/sparsemem.h +@@ -27,7 +27,7 @@ + #else /* CONFIG_X86_32 */ + # define SECTION_SIZE_BITS 27 /* matt - 128 is convenient right now */ + # define MAX_PHYSADDR_BITS 44 +-# define MAX_PHYSMEM_BITS 44 ++# define MAX_PHYSMEM_BITS 44 /* Can be max 45 bits */ + #endif + + #endif /* CONFIG_SPARSEMEM */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sunrpc-fix-oops-not-setup-socket b/src/patches/suse-2.6.27.31/patches.fixes/sunrpc-fix-oops-not-setup-socket new file mode 100644 index 000000000..46ba0eb95 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sunrpc-fix-oops-not-setup-socket @@ -0,0 +1,54 @@ +From: Trond Myklebust +Subject: SUNRPC: Fix an Oops due to socket not set up yet... +References: 474062 +Patch-mainline: v2.6.29-rc7 + +Upstream commit fba91afbec2c004e2c8733ae9e0ca6998e962c64 + + SUNRPC: Fix an Oops due to socket not set up yet... + + We can Oops in both xs_udp_send_request() and xs_tcp_send_request() if the + call to xs_sendpages() returns an error due to the socket not yet being + set up. + Deal with that situation by returning a new error: ENOTSOCK, so that we + know to avoid dereferencing transport->sock. + +Signed-off-by: Trond Myklebust +Signed-off-by: Suresh Jayaraman +--- + +Index: linux-2.6.27-SLE11_BRANCH/net/sunrpc/xprtsock.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/net/sunrpc/xprtsock.c ++++ linux-2.6.27-SLE11_BRANCH/net/sunrpc/xprtsock.c +@@ -469,7 +469,7 @@ static int xs_sendpages(struct socket *s + int err, sent = 0; + + if (unlikely(!sock)) +- return -ENOTCONN; ++ return -ENOTSOCK; + + clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); + if (base != 0) { +@@ -596,6 +596,10 @@ static int xs_udp_send_request(struct rp + } + + switch (status) { ++ case -ENOTSOCK: ++ status = -ENOTCONN; ++ /* Should we call xs_close() here? */ ++ break; + case -EAGAIN: + xs_nospace(task); + break; +@@ -695,6 +699,10 @@ static int xs_tcp_send_request(struct rp + } + + switch (status) { ++ case -ENOTSOCK: ++ status = -ENOTCONN; ++ /* Should we call xs_close() here? */ ++ break; + case -EAGAIN: + xs_nospace(task); + break; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/sunrpc-tcp-reconnect b/src/patches/suse-2.6.27.31/patches.fixes/sunrpc-tcp-reconnect new file mode 100644 index 000000000..49074f4cf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/sunrpc-tcp-reconnect @@ -0,0 +1,50 @@ +From: NeilBrown +Subject: reset TCP connect timeout on successful connection. +Patch-mainline: no - see below +References: bnc#498708 + +Currently, every time an NFS server closes a TCP connection, the +client will double its time out (up to 300 seconds) before attempting +to reconnect. +The timeout should only double while it fails. On success it should +reset the timeout. + +This patch resets the timeout on a successful connection. +It also ensures that we the timeout it doubled, it does not remain at +0. This should fix a behaviour which has been observed where the +client hammers on the server until it accepts a connection. + +Note: this has not been accepted upstream. +The stated reason is that some (Netapp?) servers are prone to accept +a connection and then drop it immediately. This would defeat the backoff. +While this should be fixed there are complexities in getting it right, +and the current patch is at least an improvement. +(there where already cases where the client would retry at a high + rate and the new case is, I think, quite remote). +When things are sorted out with upstream, we can get a better fix. + +Signed-off-by: NeilBrown + +--- + net/sunrpc/xprtsock.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/sunrpc/xprtsock.c ++++ b/net/sunrpc/xprtsock.c +@@ -1143,6 +1143,7 @@ static void xs_tcp_state_change(struct s + TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID; + + xprt_wake_pending_tasks(xprt, 0); ++ xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; + } + spin_unlock_bh(&xprt->transport_lock); + break; +@@ -1785,6 +1786,8 @@ static void xs_connect(struct rpc_task * + &transport->connect_worker, + xprt->reestablish_timeout); + xprt->reestablish_timeout <<= 1; ++ if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO) ++ xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; + if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) + xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; + } else { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/taskstats-alignment b/src/patches/suse-2.6.27.31/patches.fixes/taskstats-alignment new file mode 100644 index 000000000..cee76a1b2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/taskstats-alignment @@ -0,0 +1,52 @@ +From: Raymund Will +Subject: ia64: fill 'struct taskstats' on stack and 'memcpy' result to skb. +References: bnc#448410 + + +Signed-off-by: Raymund Will + +--- + kernel/taskstats.c | 13 +++++++++++-- + 1 files changed, 11 insertions(+), 2 deletions(-) + +--- a/kernel/taskstats.c ++++ b/kernel/taskstats.c +@@ -433,6 +433,12 @@ static int taskstats_user_cmd(struct sk_ + struct taskstats *stats; + size_t size; + cpumask_t mask; ++#ifdef CONFIG_IA64 ++ struct taskstats statn; ++#define statf &statn ++#else ++#define statf stats ++#endif + + rc = parse(info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK], &mask); + if (rc < 0) +@@ -463,7 +469,7 @@ static int taskstats_user_cmd(struct sk_ + if (!stats) + goto err; + +- rc = fill_pid(pid, NULL, stats); ++ rc = fill_pid(pid, NULL, statf); + if (rc < 0) + goto err; + } else if (info->attrs[TASKSTATS_CMD_ATTR_TGID]) { +@@ -472,12 +478,15 @@ static int taskstats_user_cmd(struct sk_ + if (!stats) + goto err; + +- rc = fill_tgid(tgid, NULL, stats); ++ rc = fill_tgid(tgid, NULL, statf); + if (rc < 0) + goto err; + } else + goto err; + ++#ifdef CONFIG_IA64 ++ memcpy(stats, &statn, sizeof(statn)); ++#endif + return send_reply(rep_skb, info->snd_pid); + err: + nlmsg_free(rep_skb); diff --git a/src/patches/suse-2.6.27.31/patches.fixes/tg3-fix-default-wol.patch b/src/patches/suse-2.6.27.31/patches.fixes/tg3-fix-default-wol.patch new file mode 100644 index 000000000..efa8f5dd0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/tg3-fix-default-wol.patch @@ -0,0 +1,46 @@ +From: Rafael J. Wysocki +Subject: net (tg3): Fix failure to enable WoL by default when possible +References: bnc#447371 + +tg3 is supposed to enable WoL by default on adapters which support +that, but it fails to do so unless the adapter's +/sys/devices/.../power/wakeup file contains 'enabled' during the +initialization of the adapter. Fix that by making tg3 update the +device's 'should_wakeup' bit automatically whenever WoL should be +enabled by default. + +Signed-off-by: Rafael J. Wysocki +--- + drivers/net/tg3.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +Index: linux-2.6.27/drivers/net/tg3.c +=================================================================== +--- linux-2.6.27.orig/drivers/net/tg3.c ++++ linux-2.6.27/drivers/net/tg3.c +@@ -11340,9 +11340,10 @@ static void __devinit tg3_get_eeprom_hw_ + if (val & VCPU_CFGSHDW_ASPM_DBNC) + tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; + if ((val & VCPU_CFGSHDW_WOL_ENABLE) && +- (val & VCPU_CFGSHDW_WOL_MAGPKT) && +- device_may_wakeup(&tp->pdev->dev)) ++ (val & VCPU_CFGSHDW_WOL_MAGPKT)) { + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; ++ device_set_wakeup_enable(&tp->pdev->dev, true); ++ } + return; + } + +@@ -11472,9 +11473,10 @@ static void __devinit tg3_get_eeprom_hw_ + tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; + + if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && +- (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) && +- device_may_wakeup(&tp->pdev->dev)) ++ (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) { + tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; ++ device_set_wakeup_enable(&tp->pdev->dev, true); ++ } + + if (cfg2 & (1 << 17)) + tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/tiocgdev b/src/patches/suse-2.6.27.31/patches.fixes/tiocgdev new file mode 100644 index 000000000..2e17bbb33 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/tiocgdev @@ -0,0 +1,154 @@ +Subject: tiocgdev ioctl +Patch-mainline: never, lkml guys don't like it +From: kraxel@suse.de + +add tty ioctl to figure physical device of the console. + + arch/alpha/include/asm/ioctls.h | 1 + + arch/arm/include/asm/ioctls.h | 1 + + arch/ia64/include/asm/ioctls.h | 1 + + arch/powerpc/include/asm/ioctls.h | 1 + + arch/s390/include/asm/ioctls.h | 1 + + arch/sh/include/asm/ioctls.h | 1 + + arch/sparc/include/asm/ioctls.h | 1 + + drivers/char/tty_io.c | 15 +++++++++++++++ + fs/compat_ioctl.c | 1 + + include/asm-m68k/ioctls.h | 1 + + include/asm-mips/ioctls.h | 1 + + include/asm-x86/ioctls.h | 1 + + 12 files changed, 26 insertions(+) + +--- a/arch/alpha/include/asm/ioctls.h ++++ b/arch/alpha/include/asm/ioctls.h +@@ -91,6 +91,7 @@ + #define TIOCGSID 0x5429 /* Return the session ID of FD */ + #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ + #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define TIOCSERCONFIG 0x5453 + #define TIOCSERGWILD 0x5454 +--- a/arch/arm/include/asm/ioctls.h ++++ b/arch/arm/include/asm/ioctls.h +@@ -52,6 +52,7 @@ + #define TCSETSF2 _IOW('T',0x2D, 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 */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ + #define FIOCLEX 0x5451 +--- a/arch/ia64/include/asm/ioctls.h ++++ b/arch/ia64/include/asm/ioctls.h +@@ -59,6 +59,7 @@ + #define TCSETSF2 _IOW('T',0x2D, 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 */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ + #define FIOCLEX 0x5451 +--- a/arch/powerpc/include/asm/ioctls.h ++++ b/arch/powerpc/include/asm/ioctls.h +@@ -91,6 +91,7 @@ + #define TIOCGSID 0x5429 /* Return the session ID of FD */ + #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ + #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define TIOCSERCONFIG 0x5453 + #define TIOCSERGWILD 0x5454 +--- a/arch/s390/include/asm/ioctls.h ++++ b/arch/s390/include/asm/ioctls.h +@@ -60,6 +60,7 @@ + #define TCSETSF2 _IOW('T',0x2D, 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 */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ + #define FIOCLEX 0x5451 +--- a/arch/sh/include/asm/ioctls.h ++++ b/arch/sh/include/asm/ioctls.h +@@ -84,6 +84,7 @@ + #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 */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ + #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ +--- a/arch/sparc/include/asm/ioctls.h ++++ b/arch/sparc/include/asm/ioctls.h +@@ -19,6 +19,7 @@ + #define TCSETS2 _IOW('T', 13, struct termios2) + #define TCSETSW2 _IOW('T', 14, struct termios2) + #define TCSETSF2 _IOW('T', 15, struct termios2) ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + /* Note that all the ioctls that are not available in Linux have a + * double underscore on the front to: a) avoid some programs to +--- a/drivers/char/tty_io.c ++++ b/drivers/char/tty_io.c +@@ -3031,6 +3031,21 @@ long tty_ioctl(struct file *file, unsign + return tioclinux(tty, arg); + #endif + /* ++ * Without the real device to which /dev/console is connected, ++ * blogd can not work. ++ * blogd spawns a pty/tty pair, ++ * set /dev/console to the tty of that pair (ioctl TIOCCONS), ++ * then reads in all input from the current /dev/console, ++ * buffer or write the readed data to /var/log/boot.msg ++ * _and_ to the original real device. ++ */ ++ case TIOCGDEV: ++ { ++ unsigned int ret = new_encode_dev(tty_devnum(real_tty)); ++ return put_user(ret, (unsigned int __user *)p); ++ } ++ ++ /* + * Break handling + */ + case TIOCSBRK: /* Turn break on, unconditionally */ +--- a/fs/compat_ioctl.c ++++ b/fs/compat_ioctl.c +@@ -1871,6 +1871,7 @@ COMPATIBLE_IOCTL(TCSETSW) + COMPATIBLE_IOCTL(TCSETSF) + COMPATIBLE_IOCTL(TIOCLINUX) + COMPATIBLE_IOCTL(TIOCSBRK) ++COMPATIBLE_IOCTL(TIOCGDEV) + COMPATIBLE_IOCTL(TIOCCBRK) + ULONG_IOCTL(TIOCMIWAIT) + COMPATIBLE_IOCTL(TIOCGICOUNT) +--- a/include/asm-m68k/ioctls.h ++++ b/include/asm-m68k/ioctls.h +@@ -52,6 +52,7 @@ + #define TCSETSF2 _IOW('T',0x2D, 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 */ ++#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ + #define FIOCLEX 0x5451 +--- a/include/asm-mips/ioctls.h ++++ b/include/asm-mips/ioctls.h +@@ -83,6 +83,7 @@ + #define TCSETSF2 _IOW('T', 0x2D, 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 */ ++#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get real dev no below /dev/console */ + + /* I hope the range from 0x5480 on is free ... */ + #define TIOCSCTTY 0x5480 /* become controlling tty */ +--- a/include/asm-x86/ioctls.h ++++ b/include/asm-x86/ioctls.h +@@ -54,6 +54,7 @@ + #define TIOCGPTN _IOR('T', 0x30, unsigned int) + /* Get Pty Number (of pty-mux device) */ + #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ ++#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get real dev no below /dev/console */ + + #define FIONCLEX 0x5450 + #define FIOCLEX 0x5451 diff --git a/src/patches/suse-2.6.27.31/patches.fixes/tulip-quad-NIC-ifdown b/src/patches/suse-2.6.27.31/patches.fixes/tulip-quad-NIC-ifdown new file mode 100644 index 000000000..0cae4bc9f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/tulip-quad-NIC-ifdown @@ -0,0 +1,26 @@ +Subject: MCA when shutting down tulip quad-NIC +From: andrew.patterson@hp.com +References: SUSE39204 + +Shutting down the network causes an MCA because of an IO TLB error when +a DEC quad 10/100 card is in any slot. This problem was originally seen +on an HP rx4640. + +Acked-by: Olaf Kirch + + drivers/net/tulip/tulip_core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/tulip/tulip_core.c ++++ b/drivers/net/tulip/tulip_core.c +@@ -1788,6 +1788,10 @@ static void __devexit tulip_remove_one ( + return; + + tp = netdev_priv(dev); ++ ++ /* shoot NIC in the head before deallocating descriptors */ ++ pci_disable_device(tp->pdev); ++ + unregister_netdev(dev); + pci_free_consistent (pdev, + sizeof (struct tulip_rx_desc) * RX_RING_SIZE + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/udf-faster_anchor_detection.patch b/src/patches/suse-2.6.27.31/patches.fixes/udf-faster_anchor_detection.patch new file mode 100644 index 000000000..e562f3c5a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/udf-faster_anchor_detection.patch @@ -0,0 +1,516 @@ +From: Jan Kara +Subject: [PATCH] udf: Try anchor in block 256 first +References: bnc#467174 +Patch-mainline: 2.6.30 + +Anchor block can be located at several places on the medium. Two of the +locations are relative to media end which is problematic to detect. Also +some drives report some block as last but are not able to read it or any +block nearby before it. So let's first try block 256 and if it is all fine, +don't look at other possible locations of anchor blocks to avoid IO errors. +This change required a larger reorganization of code but the new code is +hopefully more readable and definitely shorter. + +Signed-off-by: Jan Kara + +diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/udf/super.c linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection//fs/udf/super.c +--- linux-2.6.27-SLE11_BRANCH/fs/udf/super.c 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection/fs/udf/super.c 2009-03-19 16:44:56.000000000 +0100 +@@ -83,10 +83,7 @@ static int udf_fill_super(struct super_b + static void udf_put_super(struct super_block *); + static void udf_write_super(struct super_block *); + static int udf_remount_fs(struct super_block *, int *, char *); +-static int udf_check_valid(struct super_block *, int, int); +-static int udf_vrs(struct super_block *sb, int silent); + static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); +-static void udf_find_anchor(struct super_block *); + static int udf_find_fileset(struct super_block *, kernel_lb_addr *, + kernel_lb_addr *); + static void udf_load_fileset(struct super_block *, struct buffer_head *, +@@ -286,14 +283,8 @@ static int udf_show_options(struct seq_f + seq_printf(seq, ",session=%u", sbi->s_session); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET)) + seq_printf(seq, ",lastblock=%u", sbi->s_last_block); +- /* +- * s_anchor[2] could be zeroed out in case there is no anchor +- * in the specified block, but then the "anchor=N" option +- * originally given by the user wasn't effective, so it's OK +- * if we don't show it. +- */ +- if (sbi->s_anchor[2] != 0) +- seq_printf(seq, ",anchor=%u", sbi->s_anchor[2]); ++ if (sbi->s_anchor != 0) ++ seq_printf(seq, ",anchor=%u", sbi->s_anchor); + /* + * volume, partition, fileset and rootdir seem to be ignored + * currently +@@ -585,22 +576,19 @@ static int udf_remount_fs(struct super_b + return 0; + } + +-static int udf_vrs(struct super_block *sb, int silent) ++/* Check Volume Structure Descriptors (ECMA 167 2/9.1) */ ++/* We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ ++static loff_t udf_check_vsd(struct super_block *sb) + { + struct volStructDesc *vsd = NULL; + loff_t sector = 32768; + int sectorsize; + struct buffer_head *bh = NULL; +- int iso9660 = 0; + int nsr02 = 0; + int nsr03 = 0; + struct udf_sb_info *sbi; + +- /* Block size must be a multiple of 512 */ +- if (sb->s_blocksize & 511) +- return 0; + sbi = UDF_SB(sb); +- + if (sb->s_blocksize < sizeof(struct volStructDesc)) + sectorsize = sizeof(struct volStructDesc); + else +@@ -627,7 +615,6 @@ static int udf_vrs(struct super_block *s + break; + } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, + VSD_STD_ID_LEN)) { +- iso9660 = sector; + switch (vsd->structType) { + case 0: + udf_debug("ISO9660 Boot Record found\n"); +@@ -679,136 +666,6 @@ static int udf_vrs(struct super_block *s + return 0; + } + +-/* +- * Check whether there is an anchor block in the given block +- */ +-static int udf_check_anchor_block(struct super_block *sb, sector_t block) +-{ +- struct buffer_head *bh; +- uint16_t ident; +- +- if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && +- udf_fixed_to_variable(block) >= +- sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) +- return 0; +- +- bh = udf_read_tagged(sb, block, block, &ident); +- if (!bh) +- return 0; +- brelse(bh); +- +- return ident == TAG_IDENT_AVDP; +-} +- +-/* Search for an anchor volume descriptor pointer */ +-static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock) +-{ +- sector_t last[6]; +- int i; +- struct udf_sb_info *sbi = UDF_SB(sb); +- +- last[0] = lastblock; +- last[1] = last[0] - 1; +- last[2] = last[0] + 1; +- last[3] = last[0] - 2; +- last[4] = last[0] - 150; +- last[5] = last[0] - 152; +- +- /* according to spec, anchor is in either: +- * block 256 +- * lastblock-256 +- * lastblock +- * however, if the disc isn't closed, it could be 512 */ +- +- for (i = 0; i < ARRAY_SIZE(last); i++) { +- if (last[i] < 0) +- continue; +- if (last[i] >= sb->s_bdev->bd_inode->i_size >> +- sb->s_blocksize_bits) +- continue; +- +- if (udf_check_anchor_block(sb, last[i])) { +- sbi->s_anchor[0] = last[i]; +- sbi->s_anchor[1] = last[i] - 256; +- return last[i]; +- } +- +- if (last[i] < 256) +- continue; +- +- if (udf_check_anchor_block(sb, last[i] - 256)) { +- sbi->s_anchor[1] = last[i] - 256; +- return last[i]; +- } +- } +- +- if (udf_check_anchor_block(sb, sbi->s_session + 256)) { +- sbi->s_anchor[0] = sbi->s_session + 256; +- return last[0]; +- } +- if (udf_check_anchor_block(sb, sbi->s_session + 512)) { +- sbi->s_anchor[0] = sbi->s_session + 512; +- return last[0]; +- } +- return 0; +-} +- +-/* +- * Find an anchor volume descriptor. The function expects sbi->s_lastblock to +- * be the last block on the media. +- * +- * Return 1 if not found, 0 if ok +- * +- */ +-static void udf_find_anchor(struct super_block *sb) +-{ +- sector_t lastblock; +- struct buffer_head *bh = NULL; +- uint16_t ident; +- int i; +- struct udf_sb_info *sbi = UDF_SB(sb); +- +- lastblock = udf_scan_anchors(sb, sbi->s_last_block); +- if (lastblock) +- goto check_anchor; +- +- /* No anchor found? Try VARCONV conversion of block numbers */ +- UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); +- /* Firstly, we try to not convert number of the last block */ +- lastblock = udf_scan_anchors(sb, +- udf_variable_to_fixed(sbi->s_last_block)); +- if (lastblock) +- goto check_anchor; +- +- /* Secondly, we try with converted number of the last block */ +- lastblock = udf_scan_anchors(sb, sbi->s_last_block); +- if (!lastblock) { +- /* VARCONV didn't help. Clear it. */ +- UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); +- } +- +-check_anchor: +- /* +- * Check located anchors and the anchor block supplied via +- * mount options +- */ +- for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { +- if (!sbi->s_anchor[i]) +- continue; +- bh = udf_read_tagged(sb, sbi->s_anchor[i], +- sbi->s_anchor[i], &ident); +- if (!bh) +- sbi->s_anchor[i] = 0; +- else { +- brelse(bh); +- if (ident != TAG_IDENT_AVDP) +- sbi->s_anchor[i] = 0; +- } +- } +- +- sbi->s_last_block = lastblock; +-} +- + static int udf_find_fileset(struct super_block *sb, + kernel_lb_addr *fileset, + kernel_lb_addr *root) +@@ -1655,86 +1512,201 @@ static noinline int udf_process_sequence + return 0; + } + ++static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, ++ kernel_lb_addr *fileset) ++{ ++ struct anchorVolDescPtr *anchor; ++ long main_s, main_e, reserve_s, reserve_e; ++ struct udf_sb_info *sbi; ++ ++ sbi = UDF_SB(sb); ++ anchor = (struct anchorVolDescPtr *)bh->b_data; ++ ++ /* Locate the main sequence */ ++ main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); ++ main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); ++ main_e = main_e >> sb->s_blocksize_bits; ++ main_e += main_s; ++ ++ /* Locate the reserve sequence */ ++ reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); ++ reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); ++ reserve_e = reserve_e >> sb->s_blocksize_bits; ++ reserve_e += reserve_s; ++ ++ /* Process the main & reserve sequences */ ++ /* responsible for finding the PartitionDesc(s) */ ++ if (!udf_process_sequence(sb, main_s, main_e, fileset)) ++ return 1; ++ return !udf_process_sequence(sb, reserve_s, reserve_e, fileset); ++} ++ + /* +- * udf_check_valid() ++ * Check whether there is an anchor block in the given block and ++ * load Volume Descriptor Sequence if so. + */ +-static int udf_check_valid(struct super_block *sb, int novrs, int silent) ++static int udf_check_anchor_block(struct super_block *sb, sector_t block, ++ kernel_lb_addr *fileset) + { +- long block; +- struct udf_sb_info *sbi = UDF_SB(sb); ++ struct buffer_head *bh; ++ uint16_t ident; ++ int ret; + +- if (novrs) { +- udf_debug("Validity check skipped because of novrs option\n"); ++ if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && ++ udf_fixed_to_variable(block) >= ++ sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) ++ return 0; ++ ++ bh = udf_read_tagged(sb, block, block, &ident); ++ if (!bh) ++ return 0; ++ if (ident != TAG_IDENT_AVDP) { ++ brelse(bh); + return 0; + } +- /* Check that it is NSR02 compliant */ +- /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ +- block = udf_vrs(sb, silent); +- if (block == -1) +- udf_debug("Failed to read byte 32768. Assuming open " +- "disc. Skipping validity check\n"); +- if (block && !sbi->s_last_block) +- sbi->s_last_block = udf_get_last_block(sb); +- return !block; ++ ret = udf_load_sequence(sb, bh, fileset); ++ brelse(bh); ++ return ret; + } + +-static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset) ++/* Search for an anchor volume descriptor pointer */ ++static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock, ++ kernel_lb_addr *fileset) + { +- struct anchorVolDescPtr *anchor; +- uint16_t ident; +- struct buffer_head *bh; +- long main_s, main_e, reserve_s, reserve_e; ++ sector_t last[6]; + int i; +- struct udf_sb_info *sbi; ++ struct udf_sb_info *sbi = UDF_SB(sb); ++ int last_count = 0; + +- if (!sb) +- return 1; +- sbi = UDF_SB(sb); ++ /* First try user provided anchor */ ++ if (sbi->s_anchor) { ++ if (udf_check_anchor_block(sb, sbi->s_anchor, fileset)) ++ return lastblock; ++ } ++ /* ++ * according to spec, anchor is in either: ++ * block 256 ++ * lastblock-256 ++ * lastblock ++ * however, if the disc isn't closed, it could be 512. ++ */ ++ if (udf_check_anchor_block(sb, sbi->s_session + 256, fileset)) ++ return lastblock; ++ /* ++ * The trouble is which block is the last one. Drives often misreport ++ * this so we try various possibilities. ++ */ ++ last[last_count++] = lastblock; ++ if (lastblock >= 1) ++ last[last_count++] = lastblock - 1; ++ last[last_count++] = lastblock + 1; ++ if (lastblock >= 2) ++ last[last_count++] = lastblock - 2; ++ if (lastblock >= 150) ++ last[last_count++] = lastblock - 150; ++ if (lastblock >= 152) ++ last[last_count++] = lastblock - 152; + +- for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { +- if (!sbi->s_anchor[i]) ++ for (i = 0; i < last_count; i++) { ++ if (last[i] >= sb->s_bdev->bd_inode->i_size >> ++ sb->s_blocksize_bits) + continue; +- +- bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], +- &ident); +- if (!bh) ++ if (udf_check_anchor_block(sb, last[i], fileset)) ++ return last[i]; ++ if (last[i] < 256) + continue; ++ if (udf_check_anchor_block(sb, last[i] - 256, fileset)) ++ return last[i]; ++ } ++ ++ /* Finally try block 512 in case media is open */ ++ if (udf_check_anchor_block(sb, sbi->s_session + 512, fileset)) ++ return last[0]; ++ return 0; ++} + +- anchor = (struct anchorVolDescPtr *)bh->b_data; ++/* ++ * Find an anchor volume descriptor and load Volume Descriptor Sequence from ++ * area specified by it. The function expects sbi->s_lastblock to be the last ++ * block on the media. ++ * ++ * Return 1 if ok, 0 if not found. ++ * ++ */ ++static int udf_find_anchor(struct super_block *sb, ++ kernel_lb_addr *fileset) ++{ ++ sector_t lastblock; ++ struct udf_sb_info *sbi = UDF_SB(sb); + +- /* Locate the main sequence */ +- main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); +- main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); +- main_e = main_e >> sb->s_blocksize_bits; +- main_e += main_s; +- +- /* Locate the reserve sequence */ +- reserve_s = le32_to_cpu( +- anchor->reserveVolDescSeqExt.extLocation); +- reserve_e = le32_to_cpu( +- anchor->reserveVolDescSeqExt.extLength); +- reserve_e = reserve_e >> sb->s_blocksize_bits; +- reserve_e += reserve_s; ++ lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset); ++ if (lastblock) ++ goto out; + +- brelse(bh); ++ /* No anchor found? Try VARCONV conversion of block numbers */ ++ UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); ++ /* Firstly, we try to not convert number of the last block */ ++ lastblock = udf_scan_anchors(sb, ++ udf_variable_to_fixed(sbi->s_last_block), ++ fileset); ++ if (lastblock) ++ goto out; + +- /* Process the main & reserve sequences */ +- /* responsible for finding the PartitionDesc(s) */ +- if (!(udf_process_sequence(sb, main_s, main_e, +- fileset) && +- udf_process_sequence(sb, reserve_s, reserve_e, +- fileset))) +- break; ++ /* Secondly, we try with converted number of the last block */ ++ lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset); ++ if (!lastblock) { ++ /* VARCONV didn't help. Clear it. */ ++ UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); ++ return 0; + } ++out: ++ sbi->s_last_block = lastblock; ++ return 1; ++} + +- if (i == ARRAY_SIZE(sbi->s_anchor)) { +- udf_debug("No Anchor block found\n"); +- return 1; ++/* ++ * Check Volume Structure Descriptor, find Anchor block and load Volume ++ * Descriptor Sequence ++ */ ++static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, ++ int silent, kernel_lb_addr *fileset) ++{ ++ struct udf_sb_info *sbi = UDF_SB(sb); ++ loff_t nsr_off; ++ ++ if (!sb_set_blocksize(sb, uopt->blocksize)) { ++ if (!silent) ++ printk(KERN_WARNING "UDF-fs: Bad block size\n"); ++ return 0; ++ } ++ sbi->s_last_block = uopt->lastblock; ++ if (!uopt->novrs) { ++ /* Check that it is NSR02 compliant */ ++ nsr_off = udf_check_vsd(sb); ++ if (!nsr_off) { ++ if (!silent) ++ printk(KERN_WARNING "UDF-fs: No VRS found\n"); ++ return 0; ++ } ++ if (nsr_off == -1) ++ udf_debug("Failed to read byte 32768. Assuming open " ++ "disc. Skipping validity check\n"); ++ if (!sbi->s_last_block) ++ sbi->s_last_block = udf_get_last_block(sb); ++ } else { ++ udf_debug("Validity check skipped because of novrs option\n"); + } +- udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); + +- return 0; ++ /* Look for anchor block and load Volume Descriptor Sequence */ ++ sbi->s_anchor = uopt->anchor; ++ if (!udf_find_anchor(sb, fileset)) { ++ if (!silent) ++ printk(KERN_WARNING "UDF-fs: No anchor found\n"); ++ return 0; ++ } ++ return 1; + } ++ + + static void udf_open_lvid(struct super_block *sb) + { +@@ -1908,18 +1880,6 @@ static int udf_fill_super(struct super_b + + udf_debug("Multi-session=%d\n", sbi->s_session); + +- sbi->s_last_block = uopt.lastblock; +- sbi->s_anchor[0] = sbi->s_anchor[1] = 0; +- sbi->s_anchor[2] = uopt.anchor; +- +- if (udf_check_valid(sb, uopt.novrs, silent)) { +- /* read volume recognition sequences */ +- printk(KERN_WARNING "UDF-fs: No VRS found\n"); +- goto error_out; +- } +- +- udf_find_anchor(sb); +- + /* Fill in the rest of the superblock */ + sb->s_op = &udf_sb_ops; + sb->s_export_op = &udf_export_ops; +@@ -1928,7 +1888,7 @@ static int udf_fill_super(struct super_b + sb->s_magic = UDF_SUPER_MAGIC; + sb->s_time_gran = 1000; + +- if (udf_load_sequence(sb, &fileset)) { ++ if (!udf_load_vrs(sb, &uopt, silent, &fileset)) { + printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); + goto error_out; + } +diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/udf/udf_sb.h linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection//fs/udf/udf_sb.h +--- linux-2.6.27-SLE11_BRANCH/fs/udf/udf_sb.h 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH-1-udf_anchor_detection/fs/udf/udf_sb.h 2009-03-19 16:33:24.000000000 +0100 +@@ -114,7 +114,7 @@ struct udf_sb_info { + + /* Sector headers */ + __s32 s_session; +- __u32 s_anchor[3]; ++ __u32 s_anchor; + __u32 s_last_block; + + struct buffer_head *s_lvid_bh; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/udf-last_block_fix.patch b/src/patches/suse-2.6.27.31/patches.fixes/udf-last_block_fix.patch new file mode 100644 index 000000000..995933582 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/udf-last_block_fix.patch @@ -0,0 +1,28 @@ +From: Jan Kara +Subject: udf: Use device size when drive reported bogus number of written blocks +References: bnc#501663 +Patch-mainline: 2.6.31 + +Some drives report 0 as the number of written blocks when there are some blocks +recorded. Use device size in such case so that we can automagically mount such +media. + +Signed-off-by: Jan Kara + +diff -rupX /home/jack/.kerndiffexclude linux-2.6.27-SLE11_BRANCH/fs/udf/lowlevel.c linux-2.6.27-SLE11_BRANCH-1-udf_last_block_fix/fs/udf/lowlevel.c +--- linux-2.6.27-SLE11_BRANCH/fs/udf/lowlevel.c 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27-SLE11_BRANCH-1-udf_last_block_fix/fs/udf/lowlevel.c 2009-06-18 12:08:11.000000000 +0200 +@@ -56,7 +56,12 @@ unsigned long udf_get_last_block(struct + struct block_device *bdev = sb->s_bdev; + unsigned long lblock = 0; + +- if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock)) ++ /* ++ * ioctl failed or returned obviously bogus value? ++ * Try using the device size... ++ */ ++ if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) || ++ lblock == 0) + lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; + + if (lblock) diff --git a/src/patches/suse-2.6.27.31/patches.fixes/uv-redundant-creation-of-proc-dir b/src/patches/suse-2.6.27.31/patches.fixes/uv-redundant-creation-of-proc-dir new file mode 100644 index 000000000..be11fc10c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/uv-redundant-creation-of-proc-dir @@ -0,0 +1,55 @@ +Subject: [PATCH] UV: redundant creation of sgi_uv +To: linux-kernel@vger.kernel.org +Cc: mingo@elte.hu +From: Cliff Wickman +Patch-mainline: 2.6.28? +References: bnc#444799 + +There is a collision between two UV functions: + both uv_ptc_init() and gru_proc_init() try to make /proc/sgi_uv + +So move it's creation to a single place: uv_system_init() + +Diffed against 2.6.28-rc3 + +Signed-off-by: Cliff Wickman +Acked-by: Jeff Mahoney +--- + arch/x86/kernel/genx2apic_uv_x.c | 2 ++ + arch/x86/kernel/tlb_uv.c | 4 ---- + 2 files changed, 2 insertions(+), 4 deletions(-) + +--- a/arch/x86/kernel/genx2apic_uv_x.c ++++ b/arch/x86/kernel/genx2apic_uv_x.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -577,5 +578,6 @@ void __init uv_system_init(void) + uv_scir_register_cpu_notifier(); + + uv_cpu_init(); ++ proc_mkdir("sgi_uv", NULL); + } + +--- a/arch/x86/kernel/tlb_uv.c ++++ b/arch/x86/kernel/tlb_uv.c +@@ -566,14 +566,10 @@ static int __init uv_ptc_init(void) + if (!is_uv_system()) + return 0; + +- if (!proc_mkdir("sgi_uv", NULL)) +- return -EINVAL; +- + proc_uv_ptc = create_proc_entry(UV_PTC_BASENAME, 0444, NULL); + if (!proc_uv_ptc) { + printk(KERN_ERR "unable to create %s proc entry\n", + UV_PTC_BASENAME); +- remove_proc_entry("sgi_uv", NULL); + return -EINVAL; + } + proc_uv_ptc->proc_fops = &proc_uv_ptc_operations; diff --git a/src/patches/suse-2.6.27.31/patches.fixes/uv_zalias_support b/src/patches/suse-2.6.27.31/patches.fixes/uv_zalias_support new file mode 100644 index 000000000..69342d292 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/uv_zalias_support @@ -0,0 +1,64 @@ +From: Jack Steiner +Subject: uv: Support for non-nasid 0 systems +References: bnc#458869 + +This fixes a UV bug related to generating global memory addresses +on partitioned systems. Partition systems do not have physical memory +at address 0. Instead, a chunk of high memory is remapped by the chipset +so that it appears to be at address 0. This remapping is INVISIBLE to most +of the OS. The only OS functions that need to be aware of the remaping are +functions that directly interface to the chipset. The GRU is one example. + +Also, delete a couple of unused macros related to global memory addresses. + +Signed-off-by: Jack Steiner +Acked-by: Jeff Mahoney +--- + arch/x86/kernel/genx2apic_uv_x.c | 3 +-- + include/asm-x86/uv/uv_hub.h | 16 ++-------------- + 2 files changed, 3 insertions(+), 16 deletions(-) + +--- a/arch/x86/kernel/genx2apic_uv_x.c ++++ b/arch/x86/kernel/genx2apic_uv_x.c +@@ -535,8 +535,7 @@ void __init uv_system_init(void) + uv_blade_info[blade].nr_possible_cpus++; + + uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base; +- uv_cpu_hub_info(cpu)->lowmem_remap_top = +- lowmem_redir_base + lowmem_redir_size; ++ uv_cpu_hub_info(cpu)->lowmem_remap_top = lowmem_redir_size; + uv_cpu_hub_info(cpu)->m_val = m_val; + uv_cpu_hub_info(cpu)->n_val = m_val; + uv_cpu_hub_info(cpu)->numa_blade_id = blade; +--- a/include/asm-x86/uv/uv_hub.h ++++ b/include/asm-x86/uv/uv_hub.h +@@ -210,7 +210,7 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __ + static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr) + { + if (paddr < uv_hub_info->lowmem_remap_top) +- paddr += uv_hub_info->lowmem_remap_base; ++ paddr |= uv_hub_info->lowmem_remap_base; + return paddr | uv_hub_info->gnode_upper; + } + +@@ -218,19 +218,7 @@ static inline unsigned long uv_soc_phys_ + /* socket virtual --> UV global physical address */ + static inline unsigned long uv_gpa(void *v) + { +- return __pa(v) | uv_hub_info->gnode_upper; +-} +- +-/* socket virtual --> UV global physical address */ +-static inline void *uv_vgpa(void *v) +-{ +- return (void *)uv_gpa(v); +-} +- +-/* UV global physical address --> socket virtual */ +-static inline void *uv_va(unsigned long gpa) +-{ +- return __va(gpa & uv_hub_info->gpa_mask); ++ return uv_soc_phys_ram_to_gpa(__pa(v)); + } + + /* pnode, offset --> socket virtual */ diff --git a/src/patches/suse-2.6.27.31/patches.fixes/video-vesa-bad-mode b/src/patches/suse-2.6.27.31/patches.fixes/video-vesa-bad-mode new file mode 100644 index 000000000..74a0a505b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/video-vesa-bad-mode @@ -0,0 +1,62 @@ +From: Michael Matz +Subject: x86/boot: fix clobbered register in vesa_store_edid +References: bnc#400487 + +The only relevant difference that I can detect in the asm (comparing +the output of gcc42-4.2.1_20070724-17.1 and gcc43-4.3.3_20081022-1.2) is +in vesa_store_edid(), where the constant 0x4f15 is stored in a register +which is reused in the second use after an int 0x10 call that could possibly +clobber that register. + +The asm certainly misses a clobber. So, can you try adding one to this +asm in vesa_store_edid: + + /* Note: The VBE DDC spec is different from the main VESA spec; + we genuinely have to assume all registers are destroyed here. */ + asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" + : "+a" (ax), "+b" (bx) + : "c" (cx), "D" (di) + : "esi"); + +In particular add "edx" to the clobber list (that's the register used +in my case), but the above also misses "ecx", "edi", which have to be added +as in/out constraints (i.e. "+c") probably, not as clobbers. + +Note especially how the comment explicitely warns about assuming that +all regs are destroyed, but how the asm makes no try to cater for that. + +Tested-by: Andreas Schwab +Acked-by: Jeff Mahoney +--- + + arch/x86/boot/video-vesa.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/arch/x86/boot/video-vesa.c ++++ b/arch/x86/boot/video-vesa.c +@@ -270,9 +270,10 @@ void vesa_store_edid(void) + we genuinely have to assume all registers are destroyed here. */ + + asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" +- : "+a" (ax), "+b" (bx) +- : "c" (cx), "D" (di) +- : "esi"); ++ : "+a" (ax), "+b" (bx), ++ "+c" (cx), "+D" (di) ++ : ++ : "esi", "edx"); + + if (ax != 0x004f) + return; /* No EDID */ +@@ -286,8 +287,9 @@ void vesa_store_edid(void) + dx = 0; /* EDID block number */ + di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ + asm(INT10 +- : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info) +- : "c" (cx), "D" (di) ++ : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info), ++ "+c" (cx), "+D" (di) ++ : + : "esi"); + #endif /* CONFIG_FIRMWARE_EDID */ + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/vlan-gso-size-fix b/src/patches/suse-2.6.27.31/patches.fixes/vlan-gso-size-fix new file mode 100644 index 000000000..42fd74ae0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/vlan-gso-size-fix @@ -0,0 +1,46 @@ +From: Hannes Reinecke +Date: Wed, 17 Sep 2008 16:44:46 +0200 +Subject: vlan: device not reading gso max size of parent. +References: FATE#303913 + +The vlan devices are not reading the gso max size of the parent device. As +a result devices that do not support 64K max gso size are currently +failing. + +This issue is seen on 2.6.26 kernels as well and the same patch should be +able to be applied without any issues. + +Signed-off-by: Alexander Duyck +Signed-off-by: Hannes Reinecke +--- + net/8021q/vlan.c | 1 + + net/8021q/vlan_dev.c | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c +index b661f47..f0e335a 100644 +--- a/net/8021q/vlan.c ++++ b/net/8021q/vlan.c +@@ -394,6 +394,7 @@ static void vlan_transfer_features(struct net_device *dev, + + vlandev->features &= ~dev->vlan_features; + vlandev->features |= dev->features & dev->vlan_features; ++ vlandev->gso_max_size = dev->gso_max_size; + + if (old_features != vlandev->features) + netdev_features_change(vlandev); +diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c +index 4bf014e..97688cd 100644 +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -607,6 +607,7 @@ static int vlan_dev_init(struct net_device *dev) + (1<<__LINK_STATE_PRESENT); + + dev->features |= real_dev->features & real_dev->vlan_features; ++ dev->gso_max_size = real_dev->gso_max_size; + + /* ipv6 shared card related stuff */ + dev->dev_id = real_dev->dev_id; +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/x86_cpufreq_powernow-k8_acpi_latency_values.patch b/src/patches/suse-2.6.27.31/patches.fixes/x86_cpufreq_powernow-k8_acpi_latency_values.patch new file mode 100644 index 000000000..78f281225 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/x86_cpufreq_powernow-k8_acpi_latency_values.patch @@ -0,0 +1,86 @@ +From: Mark Langsdorf +Subject: X86 powernow-k8 cpufreq: Get transition latency from acpi _PSS object +References: bnc#464461 +Patch-Mainline: not yet + +The ondemand kernel governor calculates the best sampling rate (how often +to check for CPU load) from the CPU transition latency it gets from the +low level cpufreq drivers. Powernow-k8 returned too high values resulting +in poor performance. + +The transition latency returned from the ACPI _PSS object is also used by +AMD's Windows PowerNow driver (thus should always be sane) and returns more +exact values than the previous, algorithm to guess the transition latency. + +Signed-off-by: Thomas Renninger + +--- + arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 30 ++++++++++++++++++++++++------ + 1 file changed, 24 insertions(+), 6 deletions(-) + +Index: linux-2.6.27/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +=================================================================== +--- linux-2.6.27.orig/arch/x86/kernel/cpu/cpufreq/powernow-k8.c ++++ linux-2.6.27/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +@@ -927,10 +927,23 @@ static void powernow_k8_cpu_exit_acpi(st + acpi_processor_unregister_performance(&data->acpi_data, data->cpu); + } + ++static int get_transition_latency(struct powernow_k8_data *data) ++{ ++ int max_latency = 0; ++ int i; ++ for (i = 0; i < data->acpi_data.state_count; i++) { ++ int cur_latency = data->acpi_data.states[i].transition_latency ++ + data->acpi_data.states[i].bus_master_latency; ++ if (cur_latency > max_latency) ++ max_latency = cur_latency; ++ } ++ return max_latency; ++} + #else + static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { return -ENODEV; } + static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { return; } + static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { return; } ++static int get_transition_latency(struct powernow_k8_data *data) { return 0; } + #endif /* CONFIG_X86_POWERNOW_K8_ACPI */ + + /* Take a frequency, and issue the fid/vid transition command */ +@@ -1030,6 +1043,7 @@ static int powernowk8_target(struct cpuf + unsigned int newstate; + int ret = -EIO; + ++ + if (!data) + return -EINVAL; + +@@ -1161,7 +1175,16 @@ static int __cpuinit powernowk8_cpu_init + kfree(data); + return -ENODEV; + } +- } ++ /* Take a crude guess here. ++ * That guess was in microseconds, so multiply with 1000 */ ++ pol->cpuinfo.transition_latency = ( ++ ( (data->rvo + 8) * data->vstable * VST_UNITS_20US) + ++ ( (1 << data->irt) * 30) ++ ) * 1000; ++ } ++ else /* ACPI _PSS objects available */ ++ pol->cpuinfo.transition_latency = ++ get_transition_latency(data) * 1000; + + /* only run on specific CPU from here on */ + oldmask = current->cpus_allowed; +@@ -1192,11 +1215,6 @@ static int __cpuinit powernowk8_cpu_init + pol->cpus = per_cpu(cpu_core_map, pol->cpu); + data->available_cores = &(pol->cpus); + +- /* Take a crude guess here. +- * That guess was in microseconds, so multiply with 1000 */ +- pol->cpuinfo.transition_latency = (((data->rvo + 8) * data->vstable * VST_UNITS_20US) +- + (3 * (1 << data->irt) * 10)) * 1000; +- + if (cpu_family == CPU_HW_PSTATE) + pol->cur = find_khz_freq_from_pstate(data->powernow_table, data->currpstate); + else diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xfs-dmapi-fixes b/src/patches/suse-2.6.27.31/patches.fixes/xfs-dmapi-fixes new file mode 100644 index 000000000..13f97a69c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xfs-dmapi-fixes @@ -0,0 +1,37 @@ +From: Bill O'Donnel +Subject: xfs/dmapi: fix crash on mount +References: bnc#458027 + + This patch resolves a crash on mount problem with dmapi, relating to an + errant search and replace. + +Acked-by: Jeff Mahoney +--- + + fs/dmapi/dmapi_private.h | 4 ++-- + fs/xfs/xfs_dmops.c | 1 - + 2 files changed, 2 insertions(+), 3 deletions(-) + +--- a/fs/dmapi/dmapi_private.h 2009-01-14 17:19:28.000000000 -0600 ++++ b/fs/dmapi/dmapi_private.h 2009-01-22 10:32:34.344811347 -0600 +@@ -37,8 +37,8 @@ + #include "sv.h" + + #ifdef CONFIG_PROC_FS +-#define DMAPI_PROCFS "orig/fs/dmapi_v2" /* DMAPI device in /proc. */ +-#define DMAPI_DBG_PROCFS "orig/fs/dmapi_d" /* DMAPI debugging dir */ ++#define DMAPI_PROCFS "fs/dmapi_v2" /* DMAPI device in /proc. */ ++#define DMAPI_DBG_PROCFS "fs/dmapi_d" /* DMAPI debugging dir */ + #endif + + extern struct kmem_cache *dm_fsreg_cachep; +--- a/fs/xfs/xfs_dmops.c 2009-01-14 17:19:30.000000000 -0600 ++++ b/fs/xfs/xfs_dmops.c 2009-01-22 10:32:27.888692190 -0600 +@@ -58,7 +58,6 @@ + mp->m_dm_ops = &xfs_dmcore_stub; + } + +- mp->m_dm_ops = &xfs_dmcore_stub; + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xfs-fix-overflow-in-xfs_growfs_data_private b/src/patches/suse-2.6.27.31/patches.fixes/xfs-fix-overflow-in-xfs_growfs_data_private new file mode 100644 index 000000000..8aead037e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xfs-fix-overflow-in-xfs_growfs_data_private @@ -0,0 +1,55 @@ +From: Eric Sandeen +Date: Sat, 23 May 2009 19:30:12 +0000 (-0500) +Subject: xfs: fix overflow in xfs_growfs_data_private +Patch-mainline: 2.6.30-rc8 +Git-commit: e6da7c9fed111ba1243297ee6eda8e24ae11c384 +References: bnc#506361 + +xfs: fix overflow in xfs_growfs_data_private + +In the case where growing a filesystem would leave the last AG +too small, the fixup code has an overflow in the calculation +of the new size with one fewer ag, because "nagcount" is a 32 +bit number. If the new filesystem has > 2^32 blocks in it +this causes a problem resulting in an EINVAL return from growfs: + + # xfs_io -f -c "truncate 19998630180864" fsfile + # mkfs.xfs -f -bsize=4096 -dagsize=76288719b,size=3905982455b fsfile + # mount -o loop fsfile /mnt + # xfs_growfs /mnt + +meta-data=/dev/loop0 isize=256 agcount=52, +agsize=76288719 blks + = sectsz=512 attr=2 +data = bsize=4096 blocks=3905982455, imaxpct=5 + = sunit=0 swidth=0 blks +naming =version 2 bsize=4096 ascii-ci=0 +log =internal bsize=4096 blocks=32768, version=2 + = sectsz=512 sunit=0 blks, lazy-count=0 +realtime =none extsz=4096 blocks=0, rtextents=0 +xfs_growfs: XFS_IOC_FSGROWFSDATA xfsctl failed: Invalid argument + +Reported-by: richard.ems@cape-horn-eng.com +Signed-off-by: Eric Sandeen +Reviewed-by: Christoph Hellwig +Reviewed-by: Felix Blyakher +Signed-off-by: Felix Blyakher +Acked-by: Jeff Mahoney +--- + + fs/xfs/xfs_fsops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c +index 8379e3b..cbd451b 100644 +--- a/fs/xfs/xfs_fsops.c ++++ b/fs/xfs/xfs_fsops.c +@@ -160,7 +160,7 @@ xfs_growfs_data_private( + nagcount = new + (nb_mod != 0); + if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { + nagcount--; +- nb = nagcount * mp->m_sb.sb_agblocks; ++ nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks; + if (nb < mp->m_sb.sb_dblocks) + return XFS_ERROR(EINVAL); + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xfs-kern_32215a_Clean-up-dquot-pincount-code.patch b/src/patches/suse-2.6.27.31/patches.fixes/xfs-kern_32215a_Clean-up-dquot-pincount-code.patch new file mode 100644 index 000000000..edc0bcfc5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xfs-kern_32215a_Clean-up-dquot-pincount-code.patch @@ -0,0 +1,191 @@ +Date: Fri, Sep 26 2008 15:20:10 +1000 +From: Peter Leckie +References: SGI:PV986789 bnc#482148 +Subject: Clean up dquot pincount code +Patch-mainline: 2.6.28 + +Clean up dquot pincount code. + +This is a code cleanup and optimization that removes a per mount point +spinlock from the quota code and cleans up the code. + +The patch changes the pincount from being an int protected by a spinlock +to an atomic_t allowing the pincount to be manipulated without holding +the spinlock. + +This cleanup also protects against random wakup's of both the aild and +xfssyncd by reevaluating the pincount after been woken. Two latter patches +will address the Spurious wakeups. + +Signed-off-by: Peter Leckie +Acked-by: Jan Kara + +Index: linux/fs/xfs/quota/xfs_dquot_item.c +=================================================================== +--- linux.orig/fs/xfs/quota/xfs_dquot_item.c 2008-10-09 17:13:53.000000000 -0500 ++++ linux/fs/xfs/quota/xfs_dquot_item.c 2009-03-09 10:24:24.000000000 -0500 +@@ -88,25 +88,23 @@ xfs_qm_dquot_logitem_format( + + /* + * Increment the pin count of the given dquot. +- * This value is protected by pinlock spinlock in the xQM structure. + */ + STATIC void + xfs_qm_dquot_logitem_pin( + xfs_dq_logitem_t *logitem) + { +- xfs_dquot_t *dqp; ++ xfs_dquot_t *dqp = logitem->qli_dquot; + +- dqp = logitem->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); +- spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); +- dqp->q_pincount++; +- spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); ++ atomic_inc(&dqp->q_pincount); ++ + } + + /* + * Decrement the pin count of the given dquot, and wake up + * anyone in xfs_dqwait_unpin() if the count goes to 0. The +- * dquot must have been previously pinned with a call to xfs_dqpin(). ++ * dquot must have been previously pinned with a call to ++ * xfs_qm_dquot_logitem_pin(). + */ + /* ARGSUSED */ + STATIC void +@@ -114,16 +112,12 @@ xfs_qm_dquot_logitem_unpin( + xfs_dq_logitem_t *logitem, + int stale) + { +- xfs_dquot_t *dqp; ++xfs_dquot_t *dqp = logitem->qli_dquot; ++ ++ ASSERT(atomic_read(&dqp->q_pincount) > 0); ++ if (atomic_dec_and_test(&dqp->q_pincount)) ++ wake_up(&dqp->q_pinwait); + +- dqp = logitem->qli_dquot; +- ASSERT(dqp->q_pincount > 0); +- spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); +- dqp->q_pincount--; +- if (dqp->q_pincount == 0) { +- sv_broadcast(&dqp->q_pinwait); +- } +- spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); + } + + /* ARGSUSED */ +@@ -193,7 +187,7 @@ xfs_qm_dqunpin_wait( + xfs_dquot_t *dqp) + { + ASSERT(XFS_DQ_IS_LOCKED(dqp)); +- if (dqp->q_pincount == 0) { ++ if (atomic_read(&dqp->q_pincount) == 0) { + return; + } + +@@ -201,13 +195,7 @@ xfs_qm_dqunpin_wait( + * Give the log a push so we don't wait here too long. + */ + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE); +- spin_lock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); +- if (dqp->q_pincount == 0) { +- spin_unlock(&(XFS_DQ_TO_QINF(dqp)->qi_pinlock)); +- return; +- } +- sv_wait(&(dqp->q_pinwait), PINOD, +- &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s); ++ wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0)); + } + + /* +@@ -310,7 +298,7 @@ xfs_qm_dquot_logitem_trylock( + uint retval; + + dqp = qip->qli_dquot; +- if (dqp->q_pincount > 0) ++ if (atomic_read(&dqp->q_pincount) > 0) + return (XFS_ITEM_PINNED); + + if (! xfs_qm_dqlock_nowait(dqp)) +Index: linux/fs/xfs/quota/xfs_dquot.h +=================================================================== +--- linux.orig/fs/xfs/quota/xfs_dquot.h 2008-10-09 17:13:53.000000000 -0500 ++++ linux/fs/xfs/quota/xfs_dquot.h 2009-03-09 10:36:25.000000000 -0500 +@@ -83,8 +83,9 @@ typedef struct xfs_dquot { + xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */ + mutex_t q_qlock; /* quota lock */ + struct completion q_flush; /* flush completion queue */ +- uint q_pincount; /* pin count for this dquot */ +- sv_t q_pinwait; /* sync var for pinning */ ++ atomic_t q_pincount; /* dquot pin count */ ++ wait_queue_head_t q_pinwait; /* dquot pinning wait queue */ ++ + #ifdef XFS_DQUOT_TRACE + struct ktrace *q_trace; /* trace header structure */ + #endif +Index: linux/fs/xfs/quota/xfs_dquot.c +=================================================================== +--- linux.orig/fs/xfs/quota/xfs_dquot.c 2008-10-09 17:13:53.000000000 -0500 ++++ linux/fs/xfs/quota/xfs_dquot.c 2009-03-09 10:38:06.000000000 -0500 +@@ -101,7 +101,7 @@ xfs_qm_dqinit( + if (brandnewdquot) { + dqp->dq_flnext = dqp->dq_flprev = dqp; + mutex_init(&dqp->q_qlock); +- sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq"); ++ init_waitqueue_head(&dqp->q_pinwait); + + /* + * Because we want to use a counting completion, complete +@@ -131,7 +131,7 @@ xfs_qm_dqinit( + dqp->q_res_bcount = 0; + dqp->q_res_icount = 0; + dqp->q_res_rtbcount = 0; +- dqp->q_pincount = 0; ++ atomic_set(&dqp->q_pincount, 0); + dqp->q_hash = NULL; + ASSERT(dqp->dq_flnext == dqp->dq_flprev); + +@@ -1489,7 +1489,7 @@ xfs_qm_dqpurge( + "xfs_qm_dqpurge: dquot %p flush failed", dqp); + xfs_dqflock(dqp); + } +- ASSERT(dqp->q_pincount == 0); ++ ASSERT(atomic_read(&dqp->q_pincount) == 0); + ASSERT(XFS_FORCED_SHUTDOWN(mp) || + !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL)); + +Index: linux/fs/xfs/quota/xfs_qm.h +=================================================================== +--- linux.orig/fs/xfs/quota/xfs_qm.h 2008-10-09 17:13:53.000000000 -0500 ++++ linux/fs/xfs/quota/xfs_qm.h 2009-03-09 10:11:15.000000000 -0500 +@@ -106,7 +106,6 @@ typedef struct xfs_qm { + typedef struct xfs_quotainfo { + xfs_inode_t *qi_uquotaip; /* user quota inode */ + xfs_inode_t *qi_gquotaip; /* group quota inode */ +- spinlock_t qi_pinlock; /* dquot pinning lock */ + xfs_dqlist_t qi_dqlist; /* all dquots in filesys */ + int qi_dqreclaims; /* a change here indicates + a removal in the dqlist */ +Index: linux/fs/xfs/quota/xfs_qm.c +=================================================================== +--- linux.orig/fs/xfs/quota/xfs_qm.c 2008-10-09 17:13:53.000000000 -0500 ++++ linux/fs/xfs/quota/xfs_qm.c 2009-03-09 10:12:12.000000000 -0500 +@@ -1137,7 +1137,6 @@ xfs_qm_init_quotainfo( + return error; + } + +- spin_lock_init(&qinf->qi_pinlock); + xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0); + qinf->qi_dqreclaims = 0; + +@@ -1234,7 +1233,6 @@ xfs_qm_destroy_quotainfo( + */ + xfs_qm_rele_quotafs_ref(mp); + +- spinlock_destroy(&qi->qi_pinlock); + xfs_qm_list_destroy(&qi->qi_dqlist); + + if (qi->qi_uquotaip) { diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xfs-more-sb-checks b/src/patches/suse-2.6.27.31/patches.fixes/xfs-more-sb-checks new file mode 100644 index 000000000..495a91cb1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xfs-more-sb-checks @@ -0,0 +1,47 @@ +Date: Thu, May 7 2009 11:15:56 -0500 +From: Felix Blyakher +References: SGI:PV995062 bnc#471396 +Subject: add more checks to superblock validation +Patch-mainline: 2.6.30.5 + +commit 2ac00af7a6d2e65013e6f28bd1f37c0cd98ba134 +Author: Olaf Weber +Date: Fri Apr 17 16:12:45 2009 -0500 + + xfs: add more checks to superblock validation + + There had been reports where xfs filesystem was randomly + corrupted with fsfuzzer, and xfs failed to handle it + gracefully. This patch fixes couple of reported problem + by providing additional checks in the superblock + validation routine. + +Signed-off-by: Olaf Weber +Reviewed-by: Josef 'Jeff' Sipek +Reviewed-by: Christoph Hellwig +Signed-off-by: Felix Blyakher +Acked-by: + +Index: xfs_mount.c +=========================================================================== + +--- a/fs/xfs/xfs_mount.c 2009-05-07 11:16:02.000000000 -0500 ++++ b/fs/xfs/xfs_mount.c 2009-05-07 11:16:02.000000000 -0500 +@@ -215,14 +215,17 @@ xfs_mount_validate_sb( + sbp->sb_sectsize > XFS_MAX_SECTORSIZE || + sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || + sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || ++ sbp->sb_sectsize != (1 << sbp->sb_sectlog) || + sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || + sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || + sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || ++ sbp->sb_blocksize != (1 << sbp->sb_blocklog) || + sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || + sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || + sbp->sb_inodelog < XFS_DINODE_MIN_LOG || + sbp->sb_inodelog > XFS_DINODE_MAX_LOG || ++ sbp->sb_inodesize != (1 << sbp->sb_inodelog) || + (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || + (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || + (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xfs-redirty-ENOSPC.patch b/src/patches/suse-2.6.27.31/patches.fixes/xfs-redirty-ENOSPC.patch new file mode 100644 index 000000000..9f540c32e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xfs-redirty-ENOSPC.patch @@ -0,0 +1,79 @@ +Subject: Re-dirty pages on ENOSPC when converting delayed allocations +From: Lachlan McIlroy +References: 433112 - LTC48749 + +http://oss.sgi.com/archives/xfs/2008-10/msg00058.html + +If we get an error in xfs_page_state_convert() - and it's not EAGAIN - then +we throw away the dirty page without converting the delayed allocation. This +leaves delayed allocations that can never be removed and confuses code that +expects a flush of the file to clear them. We need to re-dirty the page on +error so we can try again later or report that the flush failed. + + +This change is needed to handle the condition where we are at ENOSPC and we +exhaust the reserved block pool (because many transactions are executing +concurrently) and calls to xfs_trans_reserve() start failing with ENOSPC +errors. + + +Version 2 wont return EAGAIN from xfs_vm_writepage() and also converts an +ENOSPC error to an EAGAIN for asynchronous writeback to avoid setting an +error in the inode mapping when we don't need to. + +Signed-off-by: Olaf Hering +--- + fs/xfs/linux-2.6/xfs_aops.c | 21 ++++----------------- + 1 file changed, 4 insertions(+), 17 deletions(-) + +--- a/fs/xfs/linux-2.6/xfs_aops.c ++++ b/fs/xfs/linux-2.6/xfs_aops.c +@@ -1147,16 +1147,6 @@ error: + if (iohead) + xfs_cancel_ioend(iohead); + +- /* +- * If it's delalloc and we have nowhere to put it, +- * throw it away, unless the lower layers told +- * us to try again. +- */ +- if (err != -EAGAIN) { +- if (!unmapped) +- block_invalidatepage(page, 0); +- ClearPageUptodate(page); +- } + return err; + } + +@@ -1185,7 +1175,7 @@ xfs_vm_writepage( + struct page *page, + struct writeback_control *wbc) + { +- int error; ++ int error = 0; + int need_trans; + int delalloc, unmapped, unwritten; + struct inode *inode = page->mapping->host; +@@ -1231,19 +1221,16 @@ xfs_vm_writepage( + * to real space and flush out to disk. + */ + error = xfs_page_state_convert(inode, page, wbc, 1, unmapped); +- if (error == -EAGAIN) +- goto out_fail; + if (unlikely(error < 0)) +- goto out_unlock; ++ goto out_fail; + + return 0; + + out_fail: + redirty_page_for_writepage(wbc, page); + unlock_page(page); +- return 0; +-out_unlock: +- unlock_page(page); ++ if (error == -EAGAIN) ++ error = 0; + return error; + } + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xfs_file_last_byte-needs-to-acquire-ilock.patch b/src/patches/suse-2.6.27.31/patches.fixes/xfs_file_last_byte-needs-to-acquire-ilock.patch new file mode 100644 index 000000000..bb1297771 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xfs_file_last_byte-needs-to-acquire-ilock.patch @@ -0,0 +1,52 @@ +From: Lachlan McIlroy +Date: Fri, 24 Apr 2009 02:18:00 +0000 (-0400) +Subject: xfs_file_last_byte() needs to acquire ilock +Patch-mainline: 2.6.30-rc5 +Git-commit: def6b3ba56b637d58126ef67fc19bab57945fcc4 +References: SGI:PV963454 bnc#487987 + +xfs_file_last_byte() needs to acquire ilock + +We had some systems crash with this stack: + +[] ia64_leave_kernel+0x0/0x280 +[] xfs_bmbt_get_startoff+0x0/0x20 [xfs] +[] xfs_bmap_last_offset+0x210/0x280 [xfs] +[] xfs_file_last_byte+0x70/0x1a0 [xfs] +[] xfs_itruncate_start+0xc0/0x1a0 [xfs] +[] xfs_inactive_free_eofblocks+0x290/0x460 [xfs] +[] xfs_release+0x1b0/0x240 [xfs] +[] xfs_file_release+0x70/0xa0 [xfs] +[] __fput+0x1a0/0x420 +[] fput+0x40/0x60 + +The problem here is that xfs_file_last_byte() does not acquire the +inode lock and can therefore race with another thread that is modifying +the extext list. While xfs_bmap_last_offset() is trying to lookup +what was the last extent some extents were merged and the extent list +shrunk so the index we lookup is now beyond the end of the extent list +and potentially in a freed buffer. + +Signed-off-by: Lachlan McIlroy +Reviewed-by: Christoph Hellwig +Reviewed-by: Felix Blyakher +Signed-off-by: Felix Blyakher +Acked-by: Jeff Mahoney +--- + + fs/xfs/xfs_inode.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/xfs/xfs_inode.c ++++ b/fs/xfs/xfs_inode.c +@@ -1306,8 +1306,10 @@ xfs_file_last_byte( + * necessary. + */ + if (ip->i_df.if_flags & XFS_IFEXTENTS) { ++ xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_bmap_last_offset(NULL, ip, &last_block, + XFS_DATA_FORK); ++ xfs_iunlock(ip, XFS_ILOCK_SHARED); + if (error) { + last_block = 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.fixes/xpc-pass-physical b/src/patches/suse-2.6.27.31/patches.fixes/xpc-pass-physical new file mode 100644 index 000000000..e90ff0367 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/xpc-pass-physical @@ -0,0 +1,86 @@ +From: Russ Anderson +Subject: sgi-xpc: need to pass the physical address, not virtual. +Patch-mainline: c8182f0016fb65a721c4fbe487909a2d56178135 +References: bnc#458811 + +xpc needs to pass the physical address, not virtual. + +Signed-off-by: Russ Anderson +Acked-by: Dean Nelson +Acked-by: Raymund Will + +--- +Testing uncovered this problem. The virtual address happens to work +most of the time due to the way bios was masking off the node bits. +Passing the physical address makes it work all of the time. + +--- +The only difference between the community patch and the sles11 patch is the +path to bios.h is different. In the community it is +arch/x86/include/asm/uv/bios.h and in sles11 it is include/asm-x86/uv/bios.h. + + + include/asm-x86/uv/bios.h | 2 +- + arch/x86/kernel/bios_uv.c | 4 +--- + drivers/misc/sgi-xp/xpc_uv.c | 8 ++++---- + 3 files changed, 6 insertions(+), 8 deletions(-) + +Index: linux/drivers/misc/sgi-xp/xpc_uv.c +=================================================================== +--- linux.orig/drivers/misc/sgi-xp/xpc_uv.c 2008-12-12 10:26:21.000000000 -0800 ++++ linux/drivers/misc/sgi-xp/xpc_uv.c 2008-12-12 11:30:46.207944444 -0800 +@@ -119,16 +119,16 @@ + int ret; + + #if defined CONFIG_X86_64 +- ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, mq->address, mq->order, +- &mq->mmr_offset); ++ ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), ++ mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " + "ret=%d\n", ret); + return ret; + } + #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV +- ret = sn_mq_watchlist_alloc(mq->mmr_blade, mq->address, mq->order, +- &mq->mmr_offset); ++ ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), ++ mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", + ret); +Index: linux/include/asm-x86/uv/bios.h +=================================================================== +--- linux.orig/include/asm-x86/uv/bios.h 2008-12-12 10:26:21.788299688 -0800 ++++ linux/include/asm-x86/uv/bios.h 2008-12-12 11:30:46.219945188 -0800 +@@ -100,7 +100,7 @@ + + extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *); + extern s64 uv_bios_freq_base(u64, u64 *); +-extern int uv_bios_mq_watchlist_alloc(int, void *, unsigned int, ++extern int uv_bios_mq_watchlist_alloc(int, unsigned long, unsigned int, + unsigned long *); + extern int uv_bios_mq_watchlist_free(int, int); + extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect); +Index: linux/arch/x86/kernel/bios_uv.c +=================================================================== +--- linux.orig/arch/x86/kernel/bios_uv.c 2008-12-12 10:26:21.000000000 -0800 ++++ linux/arch/x86/kernel/bios_uv.c 2008-12-12 11:30:46.231945933 -0800 +@@ -101,15 +101,13 @@ + } + + int +-uv_bios_mq_watchlist_alloc(int blade, void *mq, unsigned int mq_size, ++uv_bios_mq_watchlist_alloc(int blade, unsigned long addr, unsigned int mq_size, + unsigned long *intr_mmr_offset) + { + union uv_watchlist_u size_blade; +- unsigned long addr; + u64 watchlist; + s64 ret; + +- addr = (unsigned long)mq; + size_blade.size = mq_size; + size_blade.blade = blade; + diff --git a/src/patches/suse-2.6.27.31/patches.fixes/zfcp-make-queue_depth-adjustable b/src/patches/suse-2.6.27.31/patches.fixes/zfcp-make-queue_depth-adjustable new file mode 100644 index 000000000..aa3293f0f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.fixes/zfcp-make-queue_depth-adjustable @@ -0,0 +1,64 @@ +From: Christof Schmitt +Subject: [SCSI] zfcp: Make queue_depth adjustable +Patch-mainline: 2.6.31-rc1 +Git-commit: a40a1bafe7da0afe61b1c20fc50e18c07ce724f9 +References: bnc#513954 + +[SCSI] zfcp: Make queue_depth adjustable + +zfcp did always set the queue_depth for SCSI devices to 32, not +allowing to change this. Introduce a kernel parameter zfcp.queue_depth +and the change_queue_depth callback to allow changing the queue_depth +when it is required. + +Reviewed-by: Swen Schillig +Signed-off-by: Christof Schmitt +Signed-off-by: James Bottomley +Acked-by: Jeff Mahoney +--- + drivers/s390/scsi/zfcp_scsi.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/s390/scsi/zfcp_scsi.c ++++ b/drivers/s390/scsi/zfcp_scsi.c +@@ -11,6 +11,10 @@ + #include "zfcp_ext.h" + #include + ++static unsigned int default_depth = 32; ++module_param_named(queue_depth, default_depth, uint, 0600); ++MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); ++ + /* Find start of Sense Information in FCP response unit*/ + char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) + { +@@ -23,6 +27,12 @@ char *zfcp_get_fcp_sns_info_ptr(struct f + return fcp_sns_info_ptr; + } + ++static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth) ++{ ++ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); ++ return sdev->queue_depth; ++} ++ + static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) + { + struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; +@@ -34,7 +44,7 @@ static void zfcp_scsi_slave_destroy(stru + static int zfcp_scsi_slave_configure(struct scsi_device *sdp) + { + if (sdp->tagged_supported) +- scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, 32); ++ scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth); + else + scsi_adjust_queue_depth(sdp, 0, 1); + return 0; +@@ -653,6 +663,7 @@ struct zfcp_data zfcp_data = { + .name = "zfcp", + .module = THIS_MODULE, + .proc_name = "zfcp", ++ .change_queue_depth = zfcp_scsi_change_queue_depth, + .slave_alloc = zfcp_scsi_slave_alloc, + .slave_configure = zfcp_scsi_slave_configure, + .slave_destroy = zfcp_scsi_slave_destroy, diff --git a/src/patches/suse-2.6.27.31/patches.kabi/abi-add-back-skb_truesize_bug-and-skb_truesize_check.patch b/src/patches/suse-2.6.27.31/patches.kabi/abi-add-back-skb_truesize_bug-and-skb_truesize_check.patch new file mode 100644 index 000000000..4735276de --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/abi-add-back-skb_truesize_bug-and-skb_truesize_check.patch @@ -0,0 +1,52 @@ +From: Greg Kroah-Hartman +Subject: ABI: add back skb_truesize_bug() and skb_truesize_check() + +These functions were removed in 2.6.27.20 as they are broken and don't +really work properly. + +But, some foolish external modules might actually be using them, so be +safe and put them back in, but do not put back in the internal network +checks that called them, as that's not needed. + +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/skbuff.h | 9 +++++++++ + net/core/skbuff.c | 8 ++++++++ + 2 files changed, 17 insertions(+) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -395,6 +395,15 @@ extern void skb_over_panic(struct + void *here); + extern void skb_under_panic(struct sk_buff *skb, int len, + void *here); ++extern void skb_truesize_bug(struct sk_buff *skb); ++ ++static inline void skb_truesize_check(struct sk_buff *skb) ++{ ++ int len = sizeof(struct sk_buff) + skb->len; ++ ++ if (unlikely((int)skb->truesize < len)) ++ skb_truesize_bug(skb); ++} + + extern int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, + int getfrag(void *from, char *to, int offset, +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -143,6 +143,14 @@ void skb_under_panic(struct sk_buff *skb + BUG(); + } + ++void skb_truesize_bug(struct sk_buff *skb) ++{ ++ printk(KERN_ERR "SKB BUG: Invalid truesize (%u) " ++ "len=%u, sizeof(sk_buff)=%Zd\n", ++ skb->truesize, skb->len, sizeof(struct sk_buff)); ++} ++EXPORT_SYMBOL(skb_truesize_bug); ++ + /* Allocate a new skbuff. We do this ourselves so we can fill in a few + * 'private' fields and also do memory statistics to find all the + * [BEEP] leaks. diff --git a/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-epoll_devs-back-to-struct-user_struct.patch b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-epoll_devs-back-to-struct-user_struct.patch new file mode 100644 index 000000000..6d5d33394 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-epoll_devs-back-to-struct-user_struct.patch @@ -0,0 +1,25 @@ +From: Greg Kroah-Hartman +Subject: ABI fix: add epoll_devs back to struct user_struct + +This is only to keep the ABI stable for now, this patch +needs to be removed next chance we get when the ABI changes +as it's not needed at all. + +This is here because 2.6.27.14 removes this field. + +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/sched.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -589,6 +589,7 @@ struct user_struct { + atomic_t inotify_devs; /* How many inotify devs does this user have opened? */ + #endif + #ifdef CONFIG_EPOLL ++ atomic_t epoll_devs; /* DO NOT USE, ONLY HERE TO KEEP ABI STABLE */ + atomic_t epoll_watches; /* The number of file descriptors currently watched */ + #endif + #ifdef CONFIG_POSIX_MQUEUE diff --git a/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-s_syncing-back-to-struct-super_block.patch b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-s_syncing-back-to-struct-super_block.patch new file mode 100644 index 000000000..ee939f4a7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-s_syncing-back-to-struct-super_block.patch @@ -0,0 +1,28 @@ +From: Greg Kroah-Hartman +Subject: ABI fix: add s_syncing back to struct super_block + +This is only to keep the ABI stable for now, this patch +needs to be removed next chance we get when the ABI changes +as it's not needed at all. + +This is here because 2.6.27.13 removes this field. + +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/fs.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1085,6 +1085,10 @@ struct super_block { + struct rw_semaphore s_umount; + struct mutex s_lock; + int s_count; ++ /*******************************************************/ ++ /* DO NOT USE s_syncing only here to keep API "stable" */ ++ /*******************************************************/ ++ int s_syncing; + int s_need_sync_fs; + atomic_t s_active; + #ifdef CONFIG_SECURITY diff --git a/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-vc_scrl_erase_char-back-to-struct-vc_data.patch b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-vc_scrl_erase_char-back-to-struct-vc_data.patch new file mode 100644 index 000000000..cefc6b871 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-vc_scrl_erase_char-back-to-struct-vc_data.patch @@ -0,0 +1,24 @@ +From: Greg Kroah-Hartman +Subject: ABI fix: add vc_scrl_erase_char back to struct vc_data + +This is only to keep the ABI stable for now, this patch +needs to be removed next chance we get when the ABI changes +as it's not needed at all. + +This is here because 2.6.27.16 removes this field. + +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/console_struct.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/console_struct.h ++++ b/include/linux/console_struct.h +@@ -53,6 +53,7 @@ struct vc_data { + unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */ + struct console_font vc_font; /* Current VC font set */ + unsigned short vc_video_erase_char; /* Background erase character */ ++ unsigned short vc_scrl_erase_char; /* unused, kept for KABI issues */ + /* VT terminal data */ + unsigned int vc_state; /* Escape sequence parser state */ + unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ diff --git a/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-wb_sync_hold-enum-writeback_sync_modes.patch b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-wb_sync_hold-enum-writeback_sync_modes.patch new file mode 100644 index 000000000..0867c3cab --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-add-wb_sync_hold-enum-writeback_sync_modes.patch @@ -0,0 +1,25 @@ +From: Greg Kroah-Hartman +Subject: ABI fix: add WB_SYNC_HOLD enum writeback_sync_modes + +This is only to keep the ABI stable for now, this patch +needs to be removed next chance we get when the ABI changes +as it's not needed at all. + +This is here because 2.6.27.13 removes this enum. + +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/writeback.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/writeback.h ++++ b/include/linux/writeback.h +@@ -30,6 +30,7 @@ static inline int task_is_pdflush(struct + enum writeback_sync_modes { + WB_SYNC_NONE, /* Don't wait on anything */ + WB_SYNC_ALL, /* Wait on every mapping */ ++ WB_SYNC_HOLD, /* DOES NOTHING, DO NOT USE, ONLY HERE FOR ABI issue */ + }; + + /* diff --git a/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-for-struct-seq_file-change.patch b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-for-struct-seq_file-change.patch new file mode 100644 index 000000000..c62513ef9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/abi-fix-for-struct-seq_file-change.patch @@ -0,0 +1,37 @@ +Date: Thu, 19 Mar 2009 09:58:32 -0700 +From: Greg Kroah-Hartman +Subject: KABI: fix for struct seq_file change + +2.6.27.20 changes the seq_file structure, adding the read_pos field. + +No modules "should" be creating the seq_file structure, so moving it to +the end, and taking it out of the kernel symbol check, should resolve +the issue. + +Hopefully. + +Crossing my fingers. + +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/seq_file.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/include/linux/seq_file.h ++++ b/include/linux/seq_file.h +@@ -19,11 +19,13 @@ struct seq_file { + size_t from; + size_t count; + loff_t index; +- loff_t read_pos; + u64 version; + struct mutex lock; + const struct seq_operations *op; + void *private; ++#ifndef __GENKSYMS__ ++ loff_t read_pos; ++#endif + }; + + struct seq_operations { diff --git a/src/patches/suse-2.6.27.31/patches.kabi/export-iwl_rx_allocate b/src/patches/suse-2.6.27.31/patches.kabi/export-iwl_rx_allocate new file mode 100644 index 000000000..863e16a5f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/export-iwl_rx_allocate @@ -0,0 +1,18 @@ +From: Michal Marek +Subject: reintroduce EXPORT_SYMBOL(iwl_rx_allocate) + +2.6.27.12 removed the export with no explanation in the commit message. +Reintroduce the export to keep the SLE11 kabi. This can be removed in SP1. + +Index: b/drivers/net/wireless/iwlwifi/iwl-rx.c +=================================================================== +--- a/drivers/net/wireless/iwlwifi/iwl-rx.c ++++ b/drivers/net/wireless/iwlwifi/iwl-rx.c +@@ -292,6 +292,7 @@ void iwl_rx_allocate(struct iwl_priv *pr + spin_unlock_irqrestore(&rxq->lock, flags); + } + } ++EXPORT_SYMBOL(iwl_rx_allocate); + + void iwl_rx_replenish(struct iwl_priv *priv) + { diff --git a/src/patches/suse-2.6.27.31/patches.kabi/ftrace-dummy-export b/src/patches/suse-2.6.27.31/patches.kabi/ftrace-dummy-export new file mode 100644 index 000000000..446cb60c5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/ftrace-dummy-export @@ -0,0 +1,38 @@ +From: Michal Marek +Subject: Add mcount() dummy export + +Export a stub to avoid changing kabi checksums after CONFIG_FTRACE has been +disabled. + +Signed-off-by: Michal Marek +--- + arch/x86/kernel/i386_ksyms_32.c | 4 ++++ + arch/x86/kernel/x8664_ksyms_64.c | 4 ++++ + 2 files changed, 8 insertions(+) + +--- a/arch/x86/kernel/i386_ksyms_32.c ++++ b/arch/x86/kernel/i386_ksyms_32.c +@@ -8,6 +8,10 @@ + #ifdef CONFIG_FTRACE + /* mcount is defined in assembly */ + EXPORT_SYMBOL(mcount); ++#else ++/* export a stub for kabi compatibility */ ++void mcount(void) { } ++EXPORT_SYMBOL(mcount); + #endif + + /* Networking helper routines. */ +--- a/arch/x86/kernel/x8664_ksyms_64.c ++++ b/arch/x86/kernel/x8664_ksyms_64.c +@@ -15,6 +15,10 @@ + #ifdef CONFIG_FTRACE + /* mcount is defined in assembly */ + EXPORT_SYMBOL(mcount); ++#else ++/* export a stub for kabi compatibility */ ++void mcount(void) { } ++EXPORT_SYMBOL(mcount); + #endif + + EXPORT_SYMBOL(kernel_thread); diff --git a/src/patches/suse-2.6.27.31/patches.kabi/ia64-sn-specific-version-of-dma_get_required_mask-kabi-fix b/src/patches/suse-2.6.27.31/patches.kabi/ia64-sn-specific-version-of-dma_get_required_mask-kabi-fix new file mode 100644 index 000000000..888ebac16 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/ia64-sn-specific-version-of-dma_get_required_mask-kabi-fix @@ -0,0 +1,111 @@ +From: Michal Marek +Subject: preserve the kabi checksum of dma_get_required_mask on ia64 + +Signed-off-by: Michal Marek +Signed-off-by: Jeff Mahoney + +--- + arch/ia64/include/asm/machvec.h | 8 +++++--- + arch/ia64/pci/pci.c | 22 +++++++++++----------- + drivers/base/platform.c | 9 +++++++++ + 3 files changed, 25 insertions(+), 14 deletions(-) + +--- a/arch/ia64/include/asm/machvec.h ++++ b/arch/ia64/include/asm/machvec.h +@@ -210,7 +210,6 @@ struct ia64_machine_vector { + ia64_mv_dma_sync_sg_for_device *dma_sync_sg_for_device; + ia64_mv_dma_mapping_error *dma_mapping_error; + ia64_mv_dma_supported *dma_supported; +- ia64_mv_dma_get_required_mask *dma_get_required_mask; + ia64_mv_irq_to_vector *irq_to_vector; + ia64_mv_local_vector_to_irq *local_vector_to_irq; + ia64_mv_pci_get_legacy_mem_t *pci_get_legacy_mem; +@@ -236,6 +235,9 @@ struct ia64_machine_vector { + ia64_mv_teardown_msi_irq_t *teardown_msi_irq; + ia64_mv_pci_fixup_bus_t *pci_fixup_bus; + ia64_mv_kernel_launch_event_t *kernel_launch_event; ++#ifndef __GENKSYMS__ ++ ia64_mv_dma_get_required_mask *dma_get_required_mask; ++#endif + } __attribute__((__aligned__(16))); /* align attrib? see above comment */ + + #define MACHVEC_INIT(name) \ +@@ -261,7 +263,6 @@ struct ia64_machine_vector { + platform_dma_sync_sg_for_device, \ + platform_dma_mapping_error, \ + platform_dma_supported, \ +- platform_dma_get_required_mask, \ + platform_irq_to_vector, \ + platform_local_vector_to_irq, \ + platform_pci_get_legacy_mem, \ +@@ -286,7 +287,8 @@ struct ia64_machine_vector { + platform_setup_msi_irq, \ + platform_teardown_msi_irq, \ + platform_pci_fixup_bus, \ +- platform_kernel_launch_event \ ++ platform_kernel_launch_event, \ ++ platform_dma_get_required_mask \ + } + + extern struct ia64_machine_vector ia64_mv; +--- a/arch/ia64/pci/pci.c ++++ b/arch/ia64/pci/pci.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -744,6 +743,16 @@ static void __init set_pci_cacheline_siz + pci_cache_line_size = (1 << cci.pcci_line_size) / 4; + } + ++static int __init pcibios_init(void) ++{ ++ set_pci_cacheline_size(); ++ return 0; ++} ++ ++subsys_initcall(pcibios_init); ++ ++#include ++ + u64 ia64_dma_get_required_mask(struct device *dev) + { + u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); +@@ -764,16 +773,7 @@ u64 ia64_dma_get_required_mask(struct de + } + EXPORT_SYMBOL_GPL(ia64_dma_get_required_mask); + +-u64 dma_get_required_mask(struct device *dev) ++u64 ia64_dma_get_required_mask_wrapper(struct device *dev) + { + return platform_dma_get_required_mask(dev); + } +-EXPORT_SYMBOL_GPL(dma_get_required_mask); +- +-static int __init pcibios_init(void) +-{ +- set_pci_cacheline_size(); +- return 0; +-} +- +-subsys_initcall(pcibios_init); +--- a/drivers/base/platform.c ++++ b/drivers/base/platform.c +@@ -931,4 +931,13 @@ u64 dma_get_required_mask(struct device + return mask; + } + EXPORT_SYMBOL_GPL(dma_get_required_mask); ++#else ++#ifdef __ia64__ ++u64 ia64_dma_get_required_mask_wrapper(struct device *dev); ++u64 dma_get_required_mask(struct device *dev) ++{ ++ return ia64_dma_get_required_mask_wrapper(dev); ++} ++EXPORT_SYMBOL_GPL(dma_get_required_mask); ++#endif + #endif diff --git a/src/patches/suse-2.6.27.31/patches.kabi/mm-page_mkwrite-compat.patch b/src/patches/suse-2.6.27.31/patches.kabi/mm-page_mkwrite-compat.patch new file mode 100644 index 000000000..fb989542f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/mm-page_mkwrite-compat.patch @@ -0,0 +1,260 @@ +From: Nick Piggin +Subject: mm: page_mkwrite kABI compat 2 +Patch-upstream: never + +Introduce a new vma flag, VM_PAGE_MKWRITE2, which signals to the mm that the +driver is using page_mkwrite2. Have all in-tree users set this flag because +they use page_mkwrite2. Introduce some fallback paths in the page fault +page_mkwrite callers which calls the old page_mkwrite in case this flag is not +set. In this way, ABI compatibility should be retained for out of tree modules. + +We also now do some extra checking in the fallback case to catch page +invalidations and just retry the fault rather than erroneously causing a +SIGBUS, which was one of the failure cases of the old page_mkwrite ABI (it +still has other problems, but this was one of the worst). + +Signed-off-by: Nick Piggin +--- + drivers/video/fb_defio.c | 2 - + fs/ext4/file.c | 2 - + fs/fuse/file.c | 1 + fs/gfs2/ops_file.c | 1 + fs/nfs/file.c | 2 - + fs/ocfs2/mmap.c | 2 - + fs/ubifs/file.c | 1 + fs/xfs/linux-2.6/xfs_file.c | 2 - + include/linux/mm.h | 1 + mm/memory.c | 77 ++++++++++++++++++++++++++++++++------------ + 10 files changed, 66 insertions(+), 25 deletions(-) + +Index: linux-2.6.27/drivers/video/fb_defio.c +=================================================================== +--- linux-2.6.27.orig/drivers/video/fb_defio.c ++++ linux-2.6.27/drivers/video/fb_defio.c +@@ -129,7 +129,7 @@ static const struct address_space_operat + static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) + { + vma->vm_ops = &fb_deferred_io_vm_ops; +- vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND ); ++ vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND | VM_PAGE_MKWRITE2 ); + vma->vm_private_data = info; + return 0; + } +Index: linux-2.6.27/fs/ext4/file.c +=================================================================== +--- linux-2.6.27.orig/fs/ext4/file.c ++++ linux-2.6.27/fs/ext4/file.c +@@ -136,7 +136,7 @@ static int ext4_file_mmap(struct file *f + return -ENOEXEC; + file_accessed(file); + vma->vm_ops = &ext4_file_vm_ops; +- vma->vm_flags |= VM_CAN_NONLINEAR; ++ vma->vm_flags |= VM_CAN_NONLINEAR | VM_PAGE_MKWRITE2; + return 0; + } + +Index: linux-2.6.27/fs/fuse/file.c +=================================================================== +--- linux-2.6.27.orig/fs/fuse/file.c ++++ linux-2.6.27/fs/fuse/file.c +@@ -1255,6 +1255,7 @@ static int fuse_file_mmap(struct file *f + spin_unlock(&fc->lock); + } + file_accessed(file); ++ vma->vm_flags |= VM_PAGE_MKWRITE2; + vma->vm_ops = &fuse_file_vm_ops; + return 0; + } +Index: linux-2.6.27/fs/gfs2/ops_file.c +=================================================================== +--- linux-2.6.27.orig/fs/gfs2/ops_file.c ++++ linux-2.6.27/fs/gfs2/ops_file.c +@@ -446,6 +446,7 @@ static int gfs2_mmap(struct file *file, + return error; + } + ++ vma->vm_flags |= VM_PAGE_MKWRITE2; + vma->vm_ops = &gfs2_vm_ops; + + gfs2_glock_dq_uninit(&i_gh); +Index: linux-2.6.27/fs/nfs/file.c +=================================================================== +--- linux-2.6.27.orig/fs/nfs/file.c ++++ linux-2.6.27/fs/nfs/file.c +@@ -304,7 +304,7 @@ nfs_file_mmap(struct file * file, struct + status = nfs_revalidate_mapping(inode, file->f_mapping); + if (!status) { + vma->vm_ops = &nfs_file_vm_ops; +- vma->vm_flags |= VM_CAN_NONLINEAR; ++ vma->vm_flags |= VM_CAN_NONLINEAR | VM_PAGE_MKWRITE2; + file_accessed(file); + } + return status; +Index: linux-2.6.27/fs/ocfs2/mmap.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/mmap.c ++++ linux-2.6.27/fs/ocfs2/mmap.c +@@ -216,7 +216,7 @@ int ocfs2_mmap(struct file *file, struct + ocfs2_inode_unlock(file->f_dentry->d_inode, lock_level); + out: + vma->vm_ops = &ocfs2_file_vm_ops; +- vma->vm_flags |= VM_CAN_NONLINEAR; ++ vma->vm_flags |= VM_CAN_NONLINEAR | VM_PAGE_MKWRITE2; + return 0; + } + +Index: linux-2.6.27/fs/ubifs/file.c +=================================================================== +--- linux-2.6.27.orig/fs/ubifs/file.c ++++ linux-2.6.27/fs/ubifs/file.c +@@ -1246,6 +1246,7 @@ static int ubifs_file_mmap(struct file * + if (err) + return err; + vma->vm_ops = &ubifs_file_vm_ops; ++ vma->vm_flags |= VM_PAGE_MKWRITE2; + return 0; + } + +Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_file.c +=================================================================== +--- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_file.c ++++ linux-2.6.27/fs/xfs/linux-2.6/xfs_file.c +@@ -370,7 +370,7 @@ xfs_file_mmap( + struct vm_area_struct *vma) + { + vma->vm_ops = &xfs_file_vm_ops; +- vma->vm_flags |= VM_CAN_NONLINEAR; ++ vma->vm_flags |= VM_CAN_NONLINEAR | VM_PAGE_MKWRITE2; + + file_accessed(filp); + return 0; +Index: linux-2.6.27/include/linux/mm.h +=================================================================== +--- linux-2.6.27.orig/include/linux/mm.h ++++ linux-2.6.27/include/linux/mm.h +@@ -113,6 +113,7 @@ extern unsigned int kobjsize(const void + #define VM_CAN_NONLINEAR 0x08000000 /* Has ->fault & does nonlinear pages */ + #define VM_MIXEDMAP 0x10000000 /* Can contain "struct page" and pure PFN pages */ + #define VM_SAO 0x20000000 /* Strong Access Ordering (powerpc) */ ++#define VM_PAGE_MKWRITE2 0x80000000 /* Uses page_mkwrite2 rather than page_mkwrite */ + + #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ + #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS +Index: linux-2.6.27/mm/memory.c +=================================================================== +--- linux-2.6.27.orig/mm/memory.c ++++ linux-2.6.27/mm/memory.c +@@ -1800,7 +1800,7 @@ static int do_wp_page(struct mm_struct * + * read-only shared pages can get COWed by + * get_user_pages(.write=1, .force=1). + */ +- if (vma->vm_ops && vma->vm_ops->_pmkw.page_mkwrite2) { ++ if (vma->vm_ops && vma->vm_ops->_pmkw.page_mkwrite) { + struct vm_fault vmf; + int tmp; + +@@ -1821,21 +1821,42 @@ static int do_wp_page(struct mm_struct * + page_cache_get(old_page); + pte_unmap_unlock(page_table, ptl); + +- tmp = vma->vm_ops->_pmkw.page_mkwrite2(vma, &vmf); +- if (unlikely(tmp & +- (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) { +- ret = tmp; +- goto unwritable_page; +- } +- if (unlikely(!(tmp & VM_FAULT_LOCKED))) { ++ if (likely(vma->vm_flags & VM_PAGE_MKWRITE2)) { ++ tmp = vma->vm_ops->_pmkw.page_mkwrite2(vma, &vmf); ++ if (unlikely(tmp & ++ (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) { ++ ret = tmp; ++ goto unwritable_page; ++ } ++ if (unlikely(!(tmp & VM_FAULT_LOCKED))) { ++ lock_page(old_page); ++ if (!old_page->mapping) { ++ ret = 0; /* retry the fault */ ++ unlock_page(old_page); ++ goto unwritable_page; ++ } ++ } else ++ VM_BUG_ON(!PageLocked(old_page)); ++ } else { ++ tmp = vma->vm_ops->_pmkw.page_mkwrite(vma, old_page); + lock_page(old_page); + if (!old_page->mapping) { ++ /* ++ * page_mkwrite API is broken, it returns error even ++ * if the page was invalidated. So if it was, then ++ * clear that error here so we don't get a SIGBUS. ++ */ + ret = 0; /* retry the fault */ + unlock_page(old_page); + goto unwritable_page; + } +- } else +- VM_BUG_ON(!PageLocked(old_page)); ++ if (tmp) { ++ /* can't distinguish OOM from SIGBUS, but oh well */ ++ ret = VM_FAULT_SIGBUS; ++ unlock_page(old_page); ++ goto unwritable_page; ++ } ++ } + + /* + * Since we dropped the lock we need to revalidate +@@ -2517,26 +2538,42 @@ static int __do_fault(struct mm_struct * + * address space wants to know that the page is about + * to become writable + */ +- if (vma->vm_ops->_pmkw.page_mkwrite2) { ++ if (vma->vm_ops->_pmkw.page_mkwrite) { + int tmp; + + unlock_page(page); + vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE; +- tmp = vma->vm_ops->_pmkw.page_mkwrite2(vma, &vmf); +- if (unlikely(tmp & +- (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) { +- ret = tmp; +- goto unwritable_page; +- } +- if (unlikely(!(tmp & VM_FAULT_LOCKED))) { ++ ++ if (likely(vma->vm_flags & VM_PAGE_MKWRITE2)) { ++ tmp = vma->vm_ops->_pmkw.page_mkwrite2(vma, &vmf); ++ if (unlikely(tmp & ++ (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) { ++ ret = tmp; ++ goto unwritable_page; ++ } ++ if (unlikely(!(tmp & VM_FAULT_LOCKED))) { ++ lock_page(page); ++ if (!page->mapping) { ++ ret = 0; /* retry the fault */ ++ unlock_page(page); ++ goto unwritable_page; ++ } ++ } else ++ VM_BUG_ON(!PageLocked(page)); ++ } else { ++ tmp = vma->vm_ops->_pmkw.page_mkwrite(vma, page); + lock_page(page); + if (!page->mapping) { + ret = 0; /* retry the fault */ + unlock_page(page); + goto unwritable_page; + } +- } else +- VM_BUG_ON(!PageLocked(page)); ++ if (tmp) { ++ ret = VM_FAULT_SIGBUS; ++ unlock_page(page); ++ goto unwritable_page; ++ } ++ } + page_mkwrite = 1; + } + } diff --git a/src/patches/suse-2.6.27.31/patches.kabi/mm-page_mkwrite-rename.patch b/src/patches/suse-2.6.27.31/patches.kabi/mm-page_mkwrite-rename.patch new file mode 100644 index 000000000..fabdfeed7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/mm-page_mkwrite-rename.patch @@ -0,0 +1,272 @@ +From: Nick Piggin +Subject: mm: page_mkwrite kABI compat 1 +Patch-upstream: never + +Rename page_mkwrite to page_mkwrite2, put it into a union, and in that union +also add a new page_mkwrite which has the same prototype as the old one. Update +all in-tree code to use page_mkwrite2 (can't initialize anonymous unions so +it's a bit ugly :( ). + +[mmarek: added __GENKSYMS__ ifdef: ->_pmkw.page_mkwrite() will be the same + as ->page_mkwrite() in assembly, but for genksyms it's two different things.] + +Signed-off-by: Nick Piggin +--- + drivers/video/fb_defio.c | 2 +- + fs/buffer.c | 38 +++++++++++++++++++++++++++++++++++++- + fs/ext4/file.c | 2 +- + fs/fuse/file.c | 2 +- + fs/gfs2/ops_file.c | 2 +- + fs/nfs/file.c | 2 +- + fs/ocfs2/mmap.c | 2 +- + fs/ubifs/file.c | 2 +- + fs/xfs/linux-2.6/xfs_file.c | 4 ++-- + include/linux/buffer_head.h | 4 +++- + include/linux/mm.h | 19 ++++++++++++++++--- + mm/memory.c | 8 ++++---- + mm/mmap.c | 2 +- + 13 files changed, 70 insertions(+), 19 deletions(-) + +--- a/drivers/video/fb_defio.c ++++ b/drivers/video/fb_defio.c +@@ -112,7 +112,7 @@ page_already_added: + + static struct vm_operations_struct fb_deferred_io_vm_ops = { + .fault = fb_deferred_io_fault, +- .page_mkwrite = fb_deferred_io_mkwrite, ++ ._pmkw.page_mkwrite2 = fb_deferred_io_mkwrite, + }; + + static int fb_deferred_io_set_page_dirty(struct page *page) +--- a/fs/buffer.c ++++ b/fs/buffer.c +@@ -2402,7 +2402,7 @@ int block_commit_write(struct page *page + * unlock the page. + */ + int +-block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, ++block_page_mkwrite2(struct vm_area_struct *vma, struct vm_fault *vmf, + get_block_t get_block) + { + struct page *page = vmf->page; +@@ -2444,6 +2444,41 @@ out: + } + + /* ++ * XXX: ABI hack ++ */ ++int ++block_page_mkwrite(struct vm_area_struct *vma, struct page *page, ++ get_block_t get_block) ++{ ++ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; ++ unsigned long end; ++ loff_t size; ++ int ret = -EINVAL; ++ ++ lock_page(page); ++ size = i_size_read(inode); ++ if ((page->mapping != inode->i_mapping) || ++ (page_offset(page) > size)) { ++ /* page got truncated out from underneath us */ ++ goto out_unlock; ++ } ++ ++ /* page is wholly or partially inside EOF */ ++ if (((page->index + 1) << PAGE_CACHE_SHIFT) > size) ++ end = size & ~PAGE_CACHE_MASK; ++ else ++ end = PAGE_CACHE_SIZE; ++ ++ ret = block_prepare_write(page, 0, end, get_block); ++ if (!ret) ++ ret = block_commit_write(page, 0, end); ++ ++out_unlock: ++ unlock_page(page); ++ return ret; ++} ++ ++/* + * nobh_write_begin()'s prereads are special: the buffer_heads are freed + * immediately, while under the page lock. So it needs a special end_io + * handler which does not touch the bh after unlocking it. +@@ -3362,6 +3397,7 @@ EXPORT_SYMBOL(__wait_on_buffer); + EXPORT_SYMBOL(block_commit_write); + EXPORT_SYMBOL(block_prepare_write); + EXPORT_SYMBOL(block_page_mkwrite); ++EXPORT_SYMBOL(block_page_mkwrite2); + EXPORT_SYMBOL(block_read_full_page); + EXPORT_SYMBOL(block_sync_page); + EXPORT_SYMBOL(block_truncate_page); +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -125,7 +125,7 @@ force_commit: + + static struct vm_operations_struct ext4_file_vm_ops = { + .fault = filemap_fault, +- .page_mkwrite = ext4_page_mkwrite, ++ ._pmkw.page_mkwrite2 = ext4_page_mkwrite, + }; + + static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1235,7 +1235,7 @@ static int fuse_page_mkwrite(struct vm_a + static struct vm_operations_struct fuse_file_vm_ops = { + .close = fuse_vma_close, + .fault = filemap_fault, +- .page_mkwrite = fuse_page_mkwrite, ++ ._pmkw.page_mkwrite2 = fuse_page_mkwrite, + }; + + static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) +--- a/fs/gfs2/ops_file.c ++++ b/fs/gfs2/ops_file.c +@@ -421,7 +421,7 @@ out: + + static struct vm_operations_struct gfs2_vm_ops = { + .fault = filemap_fault, +- .page_mkwrite = gfs2_page_mkwrite, ++ ._pmkw.page_mkwrite2 = gfs2_page_mkwrite, + }; + + +--- a/fs/nfs/file.c ++++ b/fs/nfs/file.c +@@ -486,7 +486,7 @@ out_unlock: + + static struct vm_operations_struct nfs_file_vm_ops = { + .fault = filemap_fault, +- .page_mkwrite = nfs_vm_page_mkwrite, ++ ._pmkw.page_mkwrite2 = nfs_vm_page_mkwrite, + }; + + static int nfs_need_sync_write(struct file *filp, struct inode *inode) +--- a/fs/ocfs2/mmap.c ++++ b/fs/ocfs2/mmap.c +@@ -200,7 +200,7 @@ out: + + static struct vm_operations_struct ocfs2_file_vm_ops = { + .fault = ocfs2_fault, +- .page_mkwrite = ocfs2_page_mkwrite, ++ ._pmkw.page_mkwrite2 = ocfs2_page_mkwrite, + }; + + int ocfs2_mmap(struct file *file, struct vm_area_struct *vma) +--- a/fs/ubifs/file.c ++++ b/fs/ubifs/file.c +@@ -1234,7 +1234,7 @@ out_unlock: + + static struct vm_operations_struct ubifs_file_vm_ops = { + .fault = filemap_fault, +- .page_mkwrite = ubifs_vm_page_mkwrite, ++ ._pmkw.page_mkwrite2 = ubifs_vm_page_mkwrite, + }; + + static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) +--- a/fs/xfs/linux-2.6/xfs_file.c ++++ b/fs/xfs/linux-2.6/xfs_file.c +@@ -429,7 +429,7 @@ xfs_vm_page_mkwrite( + struct vm_area_struct *vma, + struct vm_fault *vmf) + { +- return block_page_mkwrite(vma, vmf, xfs_get_blocks); ++ return block_page_mkwrite2(vma, vmf, xfs_get_blocks); + } + + const struct file_operations xfs_file_operations = { +@@ -485,5 +485,5 @@ const struct file_operations xfs_dir_fil + + static struct vm_operations_struct xfs_file_vm_ops = { + .fault = filemap_fault, +- .page_mkwrite = xfs_vm_page_mkwrite, ++ ._pmkw.page_mkwrite2 = xfs_vm_page_mkwrite, + }; +--- a/include/linux/buffer_head.h ++++ b/include/linux/buffer_head.h +@@ -222,7 +222,9 @@ int cont_write_begin(struct file *, stru + get_block_t *, loff_t *); + int generic_cont_expand_simple(struct inode *inode, loff_t size); + int block_commit_write(struct page *page, unsigned from, unsigned to); +-int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, ++int block_page_mkwrite(struct vm_area_struct *vma, struct page *page, ++ get_block_t get_block); ++int block_page_mkwrite2(struct vm_area_struct *vma, struct vm_fault *vmf, + get_block_t get_block); + void block_sync_page(struct page *); + sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -172,9 +172,22 @@ struct vm_operations_struct { + void (*close)(struct vm_area_struct * area); + int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); + +- /* notification that a previously read-only page is about to become +- * writable, if an error is returned it will cause a SIGBUS */ +- int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); ++#ifdef __GENKSYMS__ ++ int (*page_mkwrite)(struct vm_area_struct *, struct page *); ++#else ++ union { ++ /* ++ * XXX: this is an ABI compatibility hack. ++ * Using the fixed page_mkwrite2 call requires VM_PAGE_MKWRITE2 to be ++ * set in vma->vm_flags ++ */ ++ ++ /* notification that a previously read-only page is about to become ++ * writable, if an error is returned it will cause a SIGBUS */ ++ int (*page_mkwrite)(struct vm_area_struct *, struct page *); ++ int (*page_mkwrite2)(struct vm_area_struct *vma, struct vm_fault *vmf); ++ } _pmkw; ++#endif + + /* called by access_process_vm when get_user_pages() fails, typically + * for use by special VMAs that can switch between memory and hardware +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1800,7 +1800,7 @@ static int do_wp_page(struct mm_struct * + * read-only shared pages can get COWed by + * get_user_pages(.write=1, .force=1). + */ +- if (vma->vm_ops && vma->vm_ops->page_mkwrite) { ++ if (vma->vm_ops && vma->vm_ops->_pmkw.page_mkwrite2) { + struct vm_fault vmf; + int tmp; + +@@ -1821,7 +1821,7 @@ static int do_wp_page(struct mm_struct * + page_cache_get(old_page); + pte_unmap_unlock(page_table, ptl); + +- tmp = vma->vm_ops->page_mkwrite(vma, &vmf); ++ tmp = vma->vm_ops->_pmkw.page_mkwrite2(vma, &vmf); + if (unlikely(tmp & + (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) { + ret = tmp; +@@ -2517,12 +2517,12 @@ static int __do_fault(struct mm_struct * + * address space wants to know that the page is about + * to become writable + */ +- if (vma->vm_ops->page_mkwrite) { ++ if (vma->vm_ops->_pmkw.page_mkwrite2) { + int tmp; + + unlock_page(page); + vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE; +- tmp = vma->vm_ops->page_mkwrite(vma, &vmf); ++ tmp = vma->vm_ops->_pmkw.page_mkwrite2(vma, &vmf); + if (unlikely(tmp & + (VM_FAULT_ERROR | VM_FAULT_NOPAGE))) { + ret = tmp; +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -1074,7 +1074,7 @@ int vma_wants_writenotify(struct vm_area + return 0; + + /* The backer wishes to know when pages are first written to? */ +- if (vma->vm_ops && vma->vm_ops->page_mkwrite) ++ if (vma->vm_ops && vma->vm_ops->_pmkw.page_mkwrite) + return 1; + + /* The open routine did something to the protections already? */ diff --git a/src/patches/suse-2.6.27.31/patches.kabi/sched-kabi-compat-hack.patch b/src/patches/suse-2.6.27.31/patches.kabi/sched-kabi-compat-hack.patch new file mode 100644 index 000000000..6c5378956 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/sched-kabi-compat-hack.patch @@ -0,0 +1,76 @@ +Subject: sched: leave RT_GROUP_SCHED structure components intact to preserve kABI + +From: Gregory Haskins + +We have already commited to a kABI which includes components from +RT_GROUP_SCHED. However, that feature has been found to be broken +so we shouldnt ship with it on. The best short term solution may be +to hack structure components back in (while leaving the actual code +disabled) to preserve compatibility. + +Signed-off-by: Gregory Haskins +--- + + include/linux/sched.h | 3 +-- + kernel/sched.c | 7 +------ + 2 files changed, 2 insertions(+), 8 deletions(-) + + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1021,13 +1021,12 @@ struct sched_rt_entity { + int nr_cpus_allowed; + + struct sched_rt_entity *back; +-#ifdef CONFIG_RT_GROUP_SCHED ++ + struct sched_rt_entity *parent; + /* rq on which this entity is (to be) queued: */ + struct rt_rq *rt_rq; + /* rq "owned" by this entity/group: */ + struct rt_rq *my_q; +-#endif + }; + + struct task_struct { +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -263,12 +263,10 @@ struct task_group { + unsigned long shares; + #endif + +-#ifdef CONFIG_RT_GROUP_SCHED + struct sched_rt_entity **rt_se; + struct rt_rq **rt_rq; + + struct rt_bandwidth rt_bandwidth; +-#endif + + struct rcu_head rcu; + struct list_head list; +@@ -454,14 +452,12 @@ struct rt_rq { + /* Nests inside the rq lock: */ + spinlock_t rt_runtime_lock; + +-#ifdef CONFIG_RT_GROUP_SCHED + unsigned long rt_nr_boosted; + + struct rq *rq; + struct list_head leaf_rt_rq_list; + struct task_group *tg; + struct sched_rt_entity *rt_se; +-#endif + }; + + #ifdef CONFIG_SMP +@@ -533,9 +529,8 @@ struct rq { + /* list of leaf cfs_rq on this cpu: */ + struct list_head leaf_cfs_rq_list; + #endif +-#ifdef CONFIG_RT_GROUP_SCHED ++ + struct list_head leaf_rt_rq_list; +-#endif + + /* + * This is part of a global counter where only the total sum diff --git a/src/patches/suse-2.6.27.31/patches.kabi/splice-kabi-fix.patch b/src/patches/suse-2.6.27.31/patches.kabi/splice-kabi-fix.patch new file mode 100644 index 000000000..8f146923b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/splice-kabi-fix.patch @@ -0,0 +1,262 @@ +From: Miklos Szeredi +Subject: fix kabi breakage from i_mutex locking fix +Patch-mainline: no +References: bnc#495065 + +Splice splice_desc into two structures, splice_desc (the old version) +and splice_desc_ext, containing the new fields. + +Signed-off-by: Miklos Szeredi +--- + fs/ocfs2/file.c | 18 +++++++++-------- + fs/splice.c | 51 ++++++++++++++++++++++++++----------------------- + include/linux/splice.h | 12 +++++++---- + 3 files changed, 46 insertions(+), 35 deletions(-) + +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -2077,9 +2077,10 @@ out_sems: + + static int ocfs2_splice_to_file(struct pipe_inode_info *pipe, + struct file *out, +- struct splice_desc *sd) ++ struct splice_desc_ext *esd) + { + int ret; ++ struct splice_desc *sd = esd->sd; + + ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, &sd->pos, + sd->total_len, 0, NULL); +@@ -2088,7 +2089,7 @@ static int ocfs2_splice_to_file(struct p + return ret; + } + +- return splice_from_pipe_feed(pipe, sd, pipe_to_file); ++ return splice_from_pipe_feed(pipe, esd, pipe_to_file); + } + + static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, +@@ -2106,6 +2107,7 @@ static ssize_t ocfs2_file_splice_write(s + .pos = *ppos, + .u.file = out, + }; ++ struct splice_desc_ext esd = { .sd = &sd }; + + mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe, + (unsigned int)len, +@@ -2115,9 +2117,9 @@ static ssize_t ocfs2_file_splice_write(s + if (pipe->inode) + mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT); + +- splice_from_pipe_begin(&sd); ++ splice_from_pipe_begin(&esd); + do { +- ret = splice_from_pipe_next(pipe, &sd); ++ ret = splice_from_pipe_next(pipe, &esd); + if (ret <= 0) + break; + +@@ -2126,18 +2128,18 @@ static ssize_t ocfs2_file_splice_write(s + if (ret < 0) + mlog_errno(ret); + else { +- ret = ocfs2_splice_to_file(pipe, out, &sd); ++ ret = ocfs2_splice_to_file(pipe, out, &esd); + ocfs2_rw_unlock(inode, 1); + } + mutex_unlock(&inode->i_mutex); + } while (ret > 0); +- splice_from_pipe_end(pipe, &sd); ++ splice_from_pipe_end(pipe, &esd); + + if (pipe->inode) + mutex_unlock(&pipe->inode->i_mutex); + +- if (sd.num_spliced) +- ret = sd.num_spliced; ++ if (esd.num_spliced) ++ ret = esd.num_spliced; + + if (ret > 0) { + unsigned long nr_pages; +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -629,10 +629,11 @@ static void wakeup_pipe_writers(struct p + * locking is required around copying the pipe buffers to the + * destination. + */ +-int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, ++int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc_ext *esd, + splice_actor *actor) + { + int ret; ++ struct splice_desc *sd = esd->sd; + + while (pipe->nrbufs) { + struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; +@@ -651,7 +652,7 @@ int splice_from_pipe_feed(struct pipe_in + buf->offset += ret; + buf->len -= ret; + +- sd->num_spliced += ret; ++ esd->num_spliced += ret; + sd->len -= ret; + sd->pos += ret; + sd->total_len -= ret; +@@ -662,7 +663,7 @@ int splice_from_pipe_feed(struct pipe_in + pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1); + pipe->nrbufs--; + if (pipe->inode) +- sd->need_wakeup = true; ++ esd->need_wakeup = true; + } + + if (!sd->total_len) +@@ -683,13 +684,15 @@ EXPORT_SYMBOL(splice_from_pipe_feed); + * value (one) if pipe buffers are available. It will return zero + * or -errno if no more data needs to be spliced. + */ +-int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) ++int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc_ext *esd) + { ++ struct splice_desc *sd = esd->sd; ++ + while (!pipe->nrbufs) { + if (!pipe->writers) + return 0; + +- if (!pipe->waiting_writers && sd->num_spliced) ++ if (!pipe->waiting_writers && esd->num_spliced) + return 0; + + if (sd->flags & SPLICE_F_NONBLOCK) +@@ -698,9 +701,9 @@ int splice_from_pipe_next(struct pipe_in + if (signal_pending(current)) + return -ERESTARTSYS; + +- if (sd->need_wakeup) { ++ if (esd->need_wakeup) { + wakeup_pipe_writers(pipe); +- sd->need_wakeup = false; ++ esd->need_wakeup = false; + } + + pipe_wait(pipe); +@@ -719,10 +722,10 @@ EXPORT_SYMBOL(splice_from_pipe_next); + * splice_from_pipe_next() and splice_from_pipe_feed() to + * initialize the necessary fields of @sd. + */ +-void splice_from_pipe_begin(struct splice_desc *sd) ++void splice_from_pipe_begin(struct splice_desc_ext *esd) + { +- sd->num_spliced = 0; +- sd->need_wakeup = false; ++ esd->num_spliced = 0; ++ esd->need_wakeup = false; + } + EXPORT_SYMBOL(splice_from_pipe_begin); + +@@ -736,9 +739,9 @@ EXPORT_SYMBOL(splice_from_pipe_begin); + * be called after a loop containing splice_from_pipe_next() and + * splice_from_pipe_feed(). + */ +-void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd) ++void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc_ext *esd) + { +- if (sd->need_wakeup) ++ if (esd->need_wakeup) + wakeup_pipe_writers(pipe); + } + EXPORT_SYMBOL(splice_from_pipe_end); +@@ -760,16 +763,17 @@ ssize_t __splice_from_pipe(struct pipe_i + splice_actor *actor) + { + int ret; ++ struct splice_desc_ext esd = { .sd = sd }; + +- splice_from_pipe_begin(sd); ++ splice_from_pipe_begin(&esd); + do { +- ret = splice_from_pipe_next(pipe, sd); ++ ret = splice_from_pipe_next(pipe, &esd); + if (ret > 0) +- ret = splice_from_pipe_feed(pipe, sd, actor); ++ ret = splice_from_pipe_feed(pipe, &esd, actor); + } while (ret > 0); +- splice_from_pipe_end(pipe, sd); ++ splice_from_pipe_end(pipe, &esd); + +- return sd->num_spliced ? sd->num_spliced : ret; ++ return esd.num_spliced ? esd.num_spliced : ret; + } + EXPORT_SYMBOL(__splice_from_pipe); + +@@ -892,30 +896,31 @@ generic_file_splice_write(struct pipe_in + .pos = *ppos, + .u.file = out, + }; ++ struct splice_desc_ext esd = { .sd = &sd }; + ssize_t ret; + + if (pipe->inode) + mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT); + +- splice_from_pipe_begin(&sd); ++ splice_from_pipe_begin(&esd); + do { +- ret = splice_from_pipe_next(pipe, &sd); ++ ret = splice_from_pipe_next(pipe, &esd); + if (ret <= 0) + break; + + mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); + ret = file_remove_suid(out); + if (!ret) +- ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); ++ ret = splice_from_pipe_feed(pipe, &esd, pipe_to_file); + mutex_unlock(&inode->i_mutex); + } while (ret > 0); +- splice_from_pipe_end(pipe, &sd); ++ splice_from_pipe_end(pipe, &esd); + + if (pipe->inode) + mutex_unlock(&pipe->inode->i_mutex); + +- if (sd.num_spliced) +- ret = sd.num_spliced; ++ if (esd.num_spliced) ++ ret = esd.num_spliced; + + if (ret > 0) { + unsigned long nr_pages; +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -36,6 +36,10 @@ struct splice_desc { + void *data; /* cookie */ + } u; + loff_t pos; /* file position */ ++}; ++ ++struct splice_desc_ext { ++ struct splice_desc *sd; + size_t num_spliced; /* number of bytes already spliced */ + bool need_wakeup; /* need to wake up writer */ + }; +@@ -68,13 +72,13 @@ extern ssize_t splice_from_pipe(struct p + splice_actor *); + extern ssize_t __splice_from_pipe(struct pipe_inode_info *, + struct splice_desc *, splice_actor *); +-extern int splice_from_pipe_feed(struct pipe_inode_info *, struct splice_desc *, ++extern int splice_from_pipe_feed(struct pipe_inode_info *, struct splice_desc_ext *, + splice_actor *); + extern int splice_from_pipe_next(struct pipe_inode_info *, +- struct splice_desc *); +-extern void splice_from_pipe_begin(struct splice_desc *); ++ struct splice_desc_ext *); ++extern void splice_from_pipe_begin(struct splice_desc_ext *); + extern void splice_from_pipe_end(struct pipe_inode_info *, +- struct splice_desc *); ++ struct splice_desc_ext *); + extern int pipe_to_file(struct pipe_inode_info *, struct pipe_buffer *, + struct splice_desc *); + diff --git a/src/patches/suse-2.6.27.31/patches.kabi/xen-x86_64-note-init-p2m b/src/patches/suse-2.6.27.31/patches.kabi/xen-x86_64-note-init-p2m new file mode 100644 index 000000000..48158ddfd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/xen-x86_64-note-init-p2m @@ -0,0 +1,19 @@ +From: jbeulich@novell.com +Subject: fix kABI for patches.xen/xen-x86_64-note-init-p2m.patch +Patch-mainline: obsolete +References: bnc#417417 + +--- sle11-2009-05-14.orig/include/xen/interface/xen.h 2009-03-16 16:40:54.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/xen.h 2009-02-02 10:23:37.000000000 +0100 +@@ -578,9 +578,11 @@ struct start_info { + unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */ + unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ + int8_t cmd_line[MAX_GUEST_CMDLINE]; ++#ifndef __GENKSYMS__ + /* The pfn range here covers both page table and p->m table frames. */ + unsigned long first_p2m_pfn;/* 1st pfn forming initial P->M table. */ + unsigned long nr_p2m_frames;/* # of pfns forming initial P->M table. */ ++#endif + }; + typedef struct start_info start_info_t; + diff --git a/src/patches/suse-2.6.27.31/patches.kabi/xen3-e1000e_Export_set_memory_ro-rw b/src/patches/suse-2.6.27.31/patches.kabi/xen3-e1000e_Export_set_memory_ro-rw new file mode 100644 index 000000000..23e4a0155 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/xen3-e1000e_Export_set_memory_ro-rw @@ -0,0 +1,28 @@ +From: Bruce Allan +Subject: Export set_memory_ro() and set_memory_rw() calls. +References: bnc#425480 +Acked-by: Karsten Keil + +Export set_memory_ro() and set_memory_rw() calls. Soon to be used +by e1000e. + +Signed-off-by: Bruce Allan +Signed-off-by: Jesse Brandeburg +Automatically created from "patches.suse/e1000e_Export_set_memory_ro-rw" by xen-port-patches.py + +--- sle11-2009-03-16.orig/arch/x86/mm/pageattr-xen.c 2009-03-16 16:39:52.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/mm/pageattr-xen.c 2009-03-16 16:40:01.000000000 +0100 +@@ -1007,11 +1007,13 @@ int set_memory_ro(unsigned long addr, in + { + return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_RW)); + } ++EXPORT_SYMBOL(set_memory_ro); + + int set_memory_rw(unsigned long addr, int numpages) + { + return change_page_attr_set(addr, numpages, __pgprot(_PAGE_RW)); + } ++EXPORT_SYMBOL(set_memory_rw); + + /* hack: bypass kernel rodata section static_protections check. */ + int set_memory_rw_force(unsigned long addr, int numpages) diff --git a/src/patches/suse-2.6.27.31/patches.kabi/xen3-patch-2.6.27.18-19 b/src/patches/suse-2.6.27.31/patches.kabi/xen3-patch-2.6.27.18-19 new file mode 100644 index 000000000..79b4ee347 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/xen3-patch-2.6.27.18-19 @@ -0,0 +1,29 @@ +From: jbeulich@novell.com +Subject: fix kABI for patches.xen/xen3-patch-2.6.27.18-19 +Patch-mainline: obsolete + +--- sle11-2009-03-16.orig/arch/x86/mm/hypervisor.c 2009-03-16 16:17:37.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/mm/hypervisor.c 2009-03-16 16:17:45.000000000 +0100 +@@ -113,9 +113,10 @@ static int _xen_multicall_flush(bool ret + return 0; + } + +-void xen_multicall_flush(bool force) { ++int xen_multicall_flush(bool force) { + if (force || use_lazy_mmu_mode()) + _xen_multicall_flush(false); ++ return 0; + } + EXPORT_SYMBOL(xen_multicall_flush); + +--- sle11-2009-03-16.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:17:37.000000000 +0100 ++++ sle11-2009-03-16/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:17:45.000000000 +0100 +@@ -132,7 +132,7 @@ void scrub_pages(void *, unsigned int); + + DECLARE_PER_CPU(bool, xen_lazy_mmu); + +-void xen_multicall_flush(bool); ++int xen_multicall_flush(bool); + + int __must_check xen_multi_update_va_mapping(unsigned long va, pte_t, + unsigned long flags); diff --git a/src/patches/suse-2.6.27.31/patches.kabi/xpc-pass-physical b/src/patches/suse-2.6.27.31/patches.kabi/xpc-pass-physical new file mode 100644 index 000000000..2953031a5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kabi/xpc-pass-physical @@ -0,0 +1,69 @@ +From: Raymund Will +Subject: sgi-xpc: need to pass the physical address, not virtual. +References: bnc#458811 + +This version differs significantly from the community patch, +that breaks kABI after RC2, which is considered worse than +deviating from upstream (at least in this area). + +Instead of actually _passing_ the physical address to +uv_bios_mq_watchlist_alloc() it's converted locally. + +Signed-off-by: Raymund Will + +--- + arch/x86/kernel/bios_uv.c | 4 +++- + drivers/misc/sgi-xp/xpc_uv.c | 4 ++-- + include/asm-x86/uv/bios.h | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +--- a/arch/x86/kernel/bios_uv.c ++++ b/arch/x86/kernel/bios_uv.c +@@ -101,13 +101,15 @@ s64 uv_bios_get_sn_info(int fc, int *uvt + } + + int +-uv_bios_mq_watchlist_alloc(int blade, unsigned long addr, unsigned int mq_size, ++uv_bios_mq_watchlist_alloc(int blade, void *mq, unsigned int mq_size, + unsigned long *intr_mmr_offset) + { + union uv_watchlist_u size_blade; ++ unsigned long addr; + u64 watchlist; + s64 ret; + ++ addr = uv_gpa(mq); + size_blade.size = mq_size; + size_blade.blade = blade; + +--- a/drivers/misc/sgi-xp/xpc_uv.c ++++ b/drivers/misc/sgi-xp/xpc_uv.c +@@ -119,7 +119,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc + int ret; + + #if defined CONFIG_X86_64 +- ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), ++ ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, mq->address, + mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " +@@ -127,7 +127,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc + return ret; + } + #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV +- ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), ++ ret = sn_mq_watchlist_alloc(mq->mmr_blade, mq->address, + mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", +--- a/include/asm-x86/uv/bios.h ++++ b/include/asm-x86/uv/bios.h +@@ -100,7 +100,7 @@ extern s64 uv_bios_call_reentrant(enum u + + extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *); + extern s64 uv_bios_freq_base(u64, u64 *); +-extern int uv_bios_mq_watchlist_alloc(int, unsigned long, unsigned int, ++extern int uv_bios_mq_watchlist_alloc(int, void *, unsigned int, + unsigned long *); + extern int uv_bios_mq_watchlist_free(int, int); + extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect); diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/arch-include-asm-fixes b/src/patches/suse-2.6.27.31/patches.kernel.org/arch-include-asm-fixes new file mode 100644 index 000000000..f9dce943a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/arch-include-asm-fixes @@ -0,0 +1,98 @@ +From: Jeff Mahoney +Subject: [PATCH] kbuild: Properly handle arch/$arch/include/asm +References: bnc#427473 + + Some architectures have moved include/asm-$arch to arch/$arch/include/asm, + but were still placing new files in include/asm-$arch. This causes build + problems with out-of-tree modules. + + This patch properly handles the new locations. + +Signed-off-by: Jeff Mahoney +--- + Makefile | 24 ++++++++++++++++-------- + arch/ia64/Makefile | 2 +- + arch/ia64/include/asm/irq.h | 2 +- + arch/ia64/kernel/Makefile | 6 +++--- + 4 files changed, 21 insertions(+), 13 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -969,8 +969,10 @@ define check-symlink + set -e; \ + if [ -L include/asm ]; then \ + asmlink=`readlink include/asm | cut -d '-' -f 2`; \ +- if [ "$$asmlink" != "$(SRCARCH)" ]; then \ +- echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \ ++ archlink=`readlink include/asm | cut -d '/' -f 3`; \ ++ if [ "$$asmlink" != "$(SRCARCH)" -a \ ++ "$$archlink" != "$(SRCARCH)" ]; then \ ++ echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) or ../arch/$(SRCARCH)/include/asm was expected"; \ + echo " set ARCH or save .config and run 'make mrproper' to fix it"; \ + exit 1; \ + fi; \ +@@ -981,12 +983,18 @@ endef + # not exist so the test in chack-symlink works and we have a + # directory for generated filesas used by some architectures. + define create-symlink +- if [ ! -L include/asm ]; then \ +- echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \ +- if [ ! -d include/asm-$(SRCARCH) ]; then \ +- mkdir -p include/asm-$(SRCARCH); \ +- fi; \ +- ln -fsn asm-$(SRCARCH) $@; \ ++ if [ ! -L include/asm ]; then \ ++ if [ -d $(srctree)/arch/$(SRCARCH)/include/asm ]; then \ ++ echo ' SYMLINK $@ -> arch/$(SRCARCH)/include/asm'; \ ++ mkdir -p arch/$(SRCARCH)/include/asm; \ ++ ln -fsn ../arch/$(SRCARCH)/include/asm $@; \ ++ else \ ++ echo ' SYMLINK $@ -> include/asm-$(SRCARCH)'; \ ++ if [ ! -d include/asm-$(SRCARCH) ]; then \ ++ mkdir -p include/asm-$(SRCARCH); \ ++ fi; \ ++ ln -fsn asm-$(SRCARCH) $@; \ ++ fi; \ + fi + endef + +--- a/arch/ia64/Makefile ++++ b/arch/ia64/Makefile +@@ -105,4 +105,4 @@ archprepare: make_nr_irqs_h FORCE + PHONY += make_nr_irqs_h FORCE + + make_nr_irqs_h: FORCE +- $(Q)$(MAKE) $(build)=arch/ia64/kernel include/asm-ia64/nr-irqs.h ++ $(Q)$(MAKE) $(build)=arch/ia64/kernel arch/ia64/include/asm/nr-irqs.h +--- a/arch/ia64/include/asm/irq.h ++++ b/arch/ia64/include/asm/irq.h +@@ -13,7 +13,7 @@ + + #include + #include +-#include ++#include + + static __inline__ int + irq_canonicalize (int irq) +--- a/arch/ia64/kernel/Makefile ++++ b/arch/ia64/kernel/Makefile +@@ -96,15 +96,15 @@ endef + + # We use internal kbuild rules to avoid the "is up to date" message from make + arch/$(SRCARCH)/kernel/nr-irqs.s: $(srctree)/arch/$(SRCARCH)/kernel/nr-irqs.c \ +- $(wildcard $(srctree)/include/asm-ia64/*/irq.h) ++ $(wildcard $(srctree)/arch/ia64/include/asm/*/irq.h) + $(Q)mkdir -p $(dir $@) + $(call if_changed_dep,cc_s_c) + +-include/asm-ia64/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s ++arch/ia64/include/asm/nr-irqs.h: arch/$(SRCARCH)/kernel/nr-irqs.s + $(Q)mkdir -p $(dir $@) + $(call cmd,nr_irqs) + +-clean-files += $(objtree)/include/asm-ia64/nr-irqs.h ++clean-files += $(objtree)/arch/ia64/include/asm/nr-irqs.h + + # + # native ivt.S and entry.S diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/carmine-section-mismatch b/src/patches/suse-2.6.27.31/patches.kernel.org/carmine-section-mismatch new file mode 100644 index 000000000..767431f48 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/carmine-section-mismatch @@ -0,0 +1,26 @@ +From: Jeff Mahoney +Subject: video: Fix section mismatch in carminefb + + This patch fixes a section mismatch in carminefb. alloc_carmine_fb + accesses carminefb_fix, which is __devinitdata. This is safe since + alloc_carmine_fb is called from carminefb_probe, which is __devinit. + +Signed-off-by: Jeff Mahoney +--- + drivers/video/carminefb.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/video/carminefb.c ++++ b/drivers/video/carminefb.c +@@ -535,8 +535,9 @@ static struct fb_ops carminefb_ops = { + .fb_setcolreg = carmine_setcolreg, + }; + +-static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base, +- int smem_offset, struct device *device, struct fb_info **rinfo) ++static int __devinit alloc_carmine_fb(void __iomem *regs, ++ void __iomem *smem_base, int smem_offset, ++ struct device *device, struct fb_info **rinfo) + { + int ret; + struct fb_info *info; diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/gdth-section-conflict b/src/patches/suse-2.6.27.31/patches.kernel.org/gdth-section-conflict new file mode 100644 index 000000000..77f4989f7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/gdth-section-conflict @@ -0,0 +1,130 @@ +Subject: gdth: Fixup section annotations +From: Hannes Reinecke +Date: Tue Sep 30 12:33:53 2008 +0200: +Git: 833d622ac5002b5bcbcaae4dee335d3e80b84f28 + +Fixup section annotations so that kbuild doesn't complain anymore. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c +index 822d521..273e974 100644 +--- a/drivers/scsi/gdth.c ++++ b/drivers/scsi/gdth.c +@@ -328,7 +328,7 @@ static int irq[MAXHA] __initdata = + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; + /* disable driver flag */ +-static int disable __initdata = 0; ++static int disable = 0; + /* reserve flag */ + static int reserve_mode = 1; + /* reserve list */ +@@ -589,7 +589,7 @@ static struct pci_driver gdth_pci_driver = { + .remove = gdth_pci_remove_one, + }; + +-static void gdth_pci_remove_one(struct pci_dev *pdev) ++static void __devexit gdth_pci_remove_one(struct pci_dev *pdev) + { + gdth_ha_str *ha = pci_get_drvdata(pdev); + +@@ -601,7 +601,7 @@ static void gdth_pci_remove_one(struct pci_dev *pdev) + pci_disable_device(pdev); + } + +-static int gdth_pci_init_one(struct pci_dev *pdev, ++static int __devinit gdth_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + ushort vendor = pdev->vendor; +@@ -659,7 +659,7 @@ static int gdth_pci_init_one(struct pci_dev *pdev, + #endif /* CONFIG_PCI */ + + #ifdef CONFIG_EISA +-static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) ++static int __devinit gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) + { + ulong32 retries,id; + unchar prot_ver,eisacf,i,irq_found; +@@ -753,7 +753,7 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha) + #endif /* CONFIG_EISA */ + + #ifdef CONFIG_ISA +-static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) ++static int __devinit gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) + { + register gdt2_dpram_str __iomem *dp2_ptr; + int i; +@@ -854,7 +854,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) + #endif /* CONFIG_ISA */ + + #ifdef CONFIG_PCI +-static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, ++static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, + gdth_ha_str *ha) + { + register gdt6_dpram_str __iomem *dp6_ptr; +@@ -1238,7 +1238,7 @@ static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, + + /* controller protocol functions */ + +-static void __init gdth_enable_int(gdth_ha_str *ha) ++static void __devinit gdth_enable_int(gdth_ha_str *ha) + { + ulong flags; + gdt2_dpram_str __iomem *dp2_ptr; +@@ -1554,7 +1554,7 @@ static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode, + + /* search for devices */ + +-static int __init gdth_search_drives(gdth_ha_str *ha) ++static int __devinit gdth_search_drives(gdth_ha_str *ha) + { + ushort cdev_cnt, i; + int ok; +@@ -4654,7 +4654,7 @@ static struct scsi_host_template gdth_template = { + }; + + #ifdef CONFIG_ISA +-static int __init gdth_isa_probe_one(ulong32 isa_bios) ++static int __devinit gdth_isa_probe_one(ulong32 isa_bios) + { + struct Scsi_Host *shp; + gdth_ha_str *ha; +@@ -4786,7 +4786,7 @@ static int __init gdth_isa_probe_one(ulong32 isa_bios) + #endif /* CONFIG_ISA */ + + #ifdef CONFIG_EISA +-static int __init gdth_eisa_probe_one(ushort eisa_slot) ++static int __devinit gdth_eisa_probe_one(ushort eisa_slot) + { + struct Scsi_Host *shp; + gdth_ha_str *ha; +@@ -4919,7 +4919,7 @@ static int __init gdth_eisa_probe_one(ushort eisa_slot) + #endif /* CONFIG_EISA */ + + #ifdef CONFIG_PCI +-static int gdth_pci_probe_one(gdth_pci_str *pcistr, ++static int __devinit gdth_pci_probe_one(gdth_pci_str *pcistr, + gdth_ha_str **ha_out) + { + struct Scsi_Host *shp; +@@ -5122,7 +5122,7 @@ static struct notifier_block gdth_notifier = { + gdth_halt, NULL, 0 + }; + +-static int __init gdth_init(void) ++static int __devinit gdth_init(void) + { + if (disable) { + printk("GDT-HA: Controller driver disabled from" +@@ -5176,7 +5176,7 @@ static int __init gdth_init(void) + return 0; + } + +-static void __exit gdth_exit(void) ++static void __devexit gdth_exit(void) + { + gdth_ha_str *ha; + diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/md-section-conflict b/src/patches/suse-2.6.27.31/patches.kernel.org/md-section-conflict new file mode 100644 index 000000000..1888568cd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/md-section-conflict @@ -0,0 +1,30 @@ +From: Jeff Mahoney +Subject: md: Fix section conflicts + + Module parameters can't be static since the module macros explicitly + put those symbols in the __param section. It causes a section conflict + on ia64. This doesn't occur with standard types, since they are global + and exported. + +Signed-off-by: Jeff Mahoney +--- + + drivers/md/md.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -6414,11 +6414,11 @@ static __exit void md_exit(void) + subsys_initcall(md_init); + module_exit(md_exit) + +-static int get_ro(char *buffer, struct kernel_param *kp) ++int get_ro(char *buffer, struct kernel_param *kp) + { + return sprintf(buffer, "%d", start_readonly); + } +-static int set_ro(const char *val, struct kernel_param *kp) ++int set_ro(const char *val, struct kernel_param *kp) + { + char *e; + int num = simple_strtoul(val, &e, 10); diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/revert-ext4-changes-in-2.6.27.19-and-2.6.27.20-and-2.6.27.25.patch b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-ext4-changes-in-2.6.27.19-and-2.6.27.20-and-2.6.27.25.patch new file mode 100644 index 000000000..238243b66 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-ext4-changes-in-2.6.27.19-and-2.6.27.20-and-2.6.27.25.patch @@ -0,0 +1,3152 @@ +From: Greg Kroah-Hartman +Subject: revert ext4 changes in 2.6.27.19 and 2.6.27.20 and 2.6.27.25 +Patch-mainline: no + +As we are already taking a different version of ext4, revert the +changes that were made to ext4 in 2.6.27.19 and 2.6.27.20 and 2.6.27.25 + +Signed-off-by: Greg Kroah-Hartman + +--- b/Documentation/filesystems/ext4.txt ++++ a/Documentation/filesystems/ext4.txt +@@ -73,7 +73,7 @@ + * extent format more robust in face of on-disk corruption due to magics, + * internal redunancy in tree + * improved file allocation (multi-block alloc) ++* fix 32000 subdirectory limit +-* lift 32000 subdirectory limit imposed by i_links_count[1] + * nsec timestamps for mtime, atime, ctime, create time + * inode version field on disk (NFSv4, Lustre) + * reduced e2fsck time via uninit_bg feature +@@ -88,9 +88,6 @@ + * efficent new ordered mode in JBD2 and ext4(avoid using buffer head to force + the ordering) + +-[1] Filesystems with a block size of 1k may see a limit imposed by the +-directory hash tree having a maximum depth of two. +- + 2.2 Candidate features for future inclusion + + * Online defrag (patches available but not well tested) +reverted: +--- b/fs/ext4/balloc.c ++++ a/fs/ext4/balloc.c +@@ -20,7 +20,6 @@ + #include "ext4.h" + #include "ext4_jbd2.h" + #include "group.h" +-#include "mballoc.h" + + /* + * balloc.c contains the blocks allocation and deallocation routines +@@ -319,41 +318,18 @@ + block_group, bitmap_blk); + return NULL; + } ++ if (bh_uptodate_or_lock(bh)) +- +- if (bitmap_uptodate(bh)) + return bh; + +- lock_buffer(bh); +- if (bitmap_uptodate(bh)) { +- unlock_buffer(bh); +- return bh; +- } + spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + ext4_init_block_bitmap(sb, bh, block_group, desc); +- set_bitmap_uptodate(bh); + set_buffer_uptodate(bh); + unlock_buffer(bh); + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); + return bh; + } + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); +- if (buffer_uptodate(bh)) { +- /* +- * if not uninit if bh is uptodate, +- * bitmap is also uptodate +- */ +- set_bitmap_uptodate(bh); +- unlock_buffer(bh); +- return bh; +- } +- /* +- * submit the buffer_head for read. We can +- * safely mark the bitmap as uptodate now. +- * We do it here so the bitmap uptodate bit +- * get set with buffer lock held. +- */ +- set_bitmap_uptodate(bh); + if (bh_submit_read(bh) < 0) { + put_bh(bh); + ext4_error(sb, __func__, +@@ -861,136 +837,6 @@ + } + + /** +- * ext4_add_groupblocks() -- Add given blocks to an existing group +- * @handle: handle to this transaction +- * @sb: super block +- * @block: start physcial block to add to the block group +- * @count: number of blocks to free +- * +- * This marks the blocks as free in the bitmap. We ask the +- * mballoc to reload the buddy after this by setting group +- * EXT4_GROUP_INFO_NEED_INIT_BIT flag +- */ +-void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, +- ext4_fsblk_t block, unsigned long count) +-{ +- struct buffer_head *bitmap_bh = NULL; +- struct buffer_head *gd_bh; +- ext4_group_t block_group; +- ext4_grpblk_t bit; +- unsigned long i; +- struct ext4_group_desc *desc; +- struct ext4_super_block *es; +- struct ext4_sb_info *sbi; +- int err = 0, ret; +- ext4_grpblk_t blocks_freed; +- struct ext4_group_info *grp; +- +- sbi = EXT4_SB(sb); +- es = sbi->s_es; +- ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1); +- +- ext4_get_group_no_and_offset(sb, block, &block_group, &bit); +- grp = ext4_get_group_info(sb, block_group); +- /* +- * Check to see if we are freeing blocks across a group +- * boundary. +- */ +- if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) +- goto error_return; +- +- bitmap_bh = ext4_read_block_bitmap(sb, block_group); +- if (!bitmap_bh) +- goto error_return; +- desc = ext4_get_group_desc(sb, block_group, &gd_bh); +- if (!desc) +- goto error_return; +- +- if (in_range(ext4_block_bitmap(sb, desc), block, count) || +- in_range(ext4_inode_bitmap(sb, desc), block, count) || +- in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) || +- in_range(block + count - 1, ext4_inode_table(sb, desc), +- sbi->s_itb_per_group)) { +- ext4_error(sb, __func__, +- "Adding blocks in system zones - " +- "Block = %llu, count = %lu", +- block, count); +- goto error_return; +- } +- +- /* +- * We are about to add blocks to the bitmap, +- * so we need undo access. +- */ +- BUFFER_TRACE(bitmap_bh, "getting undo access"); +- err = ext4_journal_get_undo_access(handle, bitmap_bh); +- if (err) +- goto error_return; +- +- /* +- * We are about to modify some metadata. Call the journal APIs +- * to unshare ->b_data if a currently-committing transaction is +- * using it +- */ +- BUFFER_TRACE(gd_bh, "get_write_access"); +- err = ext4_journal_get_write_access(handle, gd_bh); +- if (err) +- goto error_return; +- /* +- * make sure we don't allow a parallel init on other groups in the +- * same buddy cache +- */ +- down_write(&grp->alloc_sem); +- for (i = 0, blocks_freed = 0; i < count; i++) { +- BUFFER_TRACE(bitmap_bh, "clear bit"); +- if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), +- bit + i, bitmap_bh->b_data)) { +- ext4_error(sb, __func__, +- "bit already cleared for block %llu", +- (ext4_fsblk_t)(block + i)); +- BUFFER_TRACE(bitmap_bh, "bit already cleared"); +- } else { +- blocks_freed++; +- } +- } +- spin_lock(sb_bgl_lock(sbi, block_group)); +- le16_add_cpu(&desc->bg_free_blocks_count, blocks_freed); +- desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); +- spin_unlock(sb_bgl_lock(sbi, block_group)); +- percpu_counter_add(&sbi->s_freeblocks_counter, blocks_freed); +- +- if (sbi->s_log_groups_per_flex) { +- ext4_group_t flex_group = ext4_flex_group(sbi, block_group); +- spin_lock(sb_bgl_lock(sbi, flex_group)); +- sbi->s_flex_groups[flex_group].free_blocks += blocks_freed; +- spin_unlock(sb_bgl_lock(sbi, flex_group)); +- } +- /* +- * request to reload the buddy with the +- * new bitmap information +- */ +- set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state)); +- ext4_mb_update_group_info(grp, blocks_freed); +- up_write(&grp->alloc_sem); +- +- /* We dirtied the bitmap block */ +- BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); +- err = ext4_journal_dirty_metadata(handle, bitmap_bh); +- +- /* And the group descriptor block */ +- BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); +- ret = ext4_journal_dirty_metadata(handle, gd_bh); +- if (!err) +- err = ret; +- sb->s_dirt = 1; +- +-error_return: +- brelse(bitmap_bh); +- ext4_std_error(sb, err); +- return; +-} +- +-/** + * ext4_free_blocks() -- Free given blocks and update quota + * @handle: handle for this transaction + * @inode: inode +reverted: +--- b/fs/ext4/ext4.h ++++ a/fs/ext4/ext4.h +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include "ext4_i.h" + + /* +@@ -248,30 +247,6 @@ + #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ + #define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ + +-/* Flags that should be inherited by new inodes from their parent. */ +-#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ +- EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |\ +- EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ +- EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\ +- EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL) +- +-/* Flags that are appropriate for regular files (all but dir-specific ones). */ +-#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL)) +- +-/* Flags that are appropriate for non-directories/regular files. */ +-#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL) +- +-/* Mask out flags that are inappropriate for the given type of inode. */ +-static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags) +-{ +- if (S_ISDIR(mode)) +- return flags; +- else if (S_ISREG(mode)) +- return flags & EXT4_REG_FLMASK; +- else +- return flags & EXT4_OTHER_FLMASK; +-} +- + /* + * Inode dynamic state flags + */ +@@ -279,7 +254,6 @@ + #define EXT4_STATE_NEW 0x00000002 /* inode is newly created */ + #define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */ + #define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */ +-#define EXT4_STATE_DA_ALLOC_CLOSE 0x00000010 /* Alloc DA blks on close */ + + /* Used to pass group descriptor data when online resize is done */ + struct ext4_new_group_input { +@@ -327,9 +301,7 @@ + #define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) + #define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input) + #define EXT4_IOC_MIGRATE _IO('f', 9) +- /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ + /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ +-#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) + + /* + * ioctl commands in 32 bit emulation +@@ -887,7 +859,7 @@ + { + unsigned len = le16_to_cpu(dlen); + ++ if (len == EXT4_MAX_REC_LEN) +- if (len == EXT4_MAX_REC_LEN || len == 0) + return 1 << 16; + return len; + } +@@ -917,9 +889,6 @@ + #define DX_HASH_LEGACY 0 + #define DX_HASH_HALF_MD4 1 + #define DX_HASH_TEA 2 +-#define DX_HASH_LEGACY_UNSIGNED 3 +-#define DX_HASH_HALF_MD4_UNSIGNED 4 +-#define DX_HASH_TEA_UNSIGNED 5 + + #ifdef __KERNEL__ + +@@ -1019,11 +988,9 @@ + ext4_fsblk_t nblocks); + extern void ext4_free_blocks (handle_t *handle, struct inode *inode, + ext4_fsblk_t block, unsigned long count, int metadata); ++extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb, ++ ext4_fsblk_t block, unsigned long count, +-extern void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, +- ext4_fsblk_t block, unsigned long count, + unsigned long *pdquot_freed_blocks); +-extern void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, +- ext4_fsblk_t block, unsigned long count); + extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *); + extern void ext4_check_blocks_bitmap (struct super_block *); + extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, +@@ -1071,13 +1038,12 @@ + extern void exit_ext4_mballoc(void); + extern void ext4_mb_free_blocks(handle_t *, struct inode *, + unsigned long, unsigned long, int, unsigned long *); ++extern int ext4_mb_add_more_groupinfo(struct super_block *sb, +-extern int ext4_mb_add_groupinfo(struct super_block *sb, + ext4_group_t i, struct ext4_group_desc *desc); + extern void ext4_mb_update_group_info(struct ext4_group_info *grp, + ext4_grpblk_t add); ++ ++ +-extern int ext4_mb_get_buddy_cache_lock(struct super_block *, ext4_group_t); +-extern void ext4_mb_put_buddy_cache_lock(struct super_block *, +- ext4_group_t, int); + /* inode.c */ + int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, + struct buffer_head *bh, ext4_fsblk_t blocknr); +@@ -1105,14 +1071,13 @@ + extern void ext4_truncate (struct inode *); + extern void ext4_set_inode_flags(struct inode *); + extern void ext4_get_inode_flags(struct ext4_inode_info *); +-extern int ext4_alloc_da_blocks(struct inode *inode); + extern void ext4_set_aops(struct inode *inode); + extern int ext4_writepage_trans_blocks(struct inode *); + extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks); + extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); + extern int ext4_block_truncate_page(handle_t *handle, + struct address_space *mapping, loff_t from); ++extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page); +-extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); + + /* ioctl.c */ + extern long ext4_ioctl(struct file *, unsigned int, unsigned long); +@@ -1202,11 +1167,8 @@ + + static inline loff_t ext4_isize(struct ext4_inode *raw_inode) + { ++ return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | ++ le32_to_cpu(raw_inode->i_size_lo); +- if (S_ISREG(le16_to_cpu(raw_inode->i_mode))) +- return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | +- le32_to_cpu(raw_inode->i_size_lo); +- else +- return (loff_t) le32_to_cpu(raw_inode->i_size_lo); + } + + static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size) +@@ -1282,23 +1244,6 @@ + sector_t block, unsigned long max_blocks, + struct buffer_head *bh, int create, + int extend_disksize, int flag); +-/* +- * Add new method to test wether block and inode bitmaps are properly +- * initialized. With uninit_bg reading the block from disk is not enough +- * to mark the bitmap uptodate. We need to also zero-out the bitmap +- */ +-#define BH_BITMAP_UPTODATE BH_JBDPrivateStart +- +-static inline int bitmap_uptodate(struct buffer_head *bh) +-{ +- return (buffer_uptodate(bh) && +- test_bit(BH_BITMAP_UPTODATE, &(bh)->b_state)); +-} +-static inline void set_bitmap_uptodate(struct buffer_head *bh) +-{ +- set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state); +-} +- + #endif /* __KERNEL__ */ + + #endif /* _EXT4_H */ +reverted: +--- b/fs/ext4/ext4_sb.h ++++ a/fs/ext4/ext4_sb.h +@@ -56,7 +56,6 @@ + u32 s_next_generation; + u32 s_hash_seed[4]; + int s_def_hash_version; +- int s_hash_unsigned; /* 3 if hash should be signed, 0 if not */ + struct percpu_counter s_freeblocks_counter; + struct percpu_counter s_freeinodes_counter; + struct percpu_counter s_dirs_counter; +@@ -103,8 +102,7 @@ + struct list_head s_committed_transaction; + spinlock_t s_md_lock; + tid_t s_last_transaction; ++ unsigned short *s_mb_offsets, *s_mb_maxs; +- unsigned short *s_mb_offsets; +- unsigned int *s_mb_maxs; + + /* tunables */ + unsigned long s_stripe; +reverted: +--- b/fs/ext4/extents.c ++++ a/fs/ext4/extents.c +@@ -1118,8 +1118,7 @@ + struct ext4_extent_idx *ix; + struct ext4_extent *ex; + ext4_fsblk_t block; ++ int depth, ee_len; +- int depth; /* Note, NOT eh_depth; depth from top of tree */ +- int ee_len; + + BUG_ON(path == NULL); + depth = path->p_depth; +@@ -1178,8 +1177,7 @@ + if (bh == NULL) + return -EIO; + eh = ext_block_hdr(bh); ++ if (ext4_ext_check_header(inode, eh, depth)) { +- /* subtract from p_depth to get proper eh_depth */ +- if (ext4_ext_check_header(inode, eh, path->p_depth - depth)) { + put_bh(bh); + return -EIO; + } +@@ -1633,13 +1631,11 @@ + { + struct ext4_ext_cache *cex; + BUG_ON(len == 0); +- spin_lock(&EXT4_I(inode)->i_block_reservation_lock); + cex = &EXT4_I(inode)->i_cached_extent; + cex->ec_type = type; + cex->ec_block = block; + cex->ec_len = len; + cex->ec_start = start; +- spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + } + + /* +@@ -1696,17 +1692,12 @@ + struct ext4_extent *ex) + { + struct ext4_ext_cache *cex; +- int ret = EXT4_EXT_CACHE_NO; + +- /* +- * We borrow i_block_reservation_lock to protect i_cached_extent +- */ +- spin_lock(&EXT4_I(inode)->i_block_reservation_lock); + cex = &EXT4_I(inode)->i_cached_extent; + + /* has cache valid data? */ + if (cex->ec_type == EXT4_EXT_CACHE_NO) ++ return EXT4_EXT_CACHE_NO; +- goto errout; + + BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP && + cex->ec_type != EXT4_EXT_CACHE_EXTENT); +@@ -1717,11 +1708,11 @@ + ext_debug("%u cached by %u:%u:%llu\n", + block, + cex->ec_block, cex->ec_len, cex->ec_start); ++ return cex->ec_type; +- ret = cex->ec_type; + } ++ ++ /* not in cache */ ++ return EXT4_EXT_CACHE_NO; +-errout: +- spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); +- return ret; + } + + /* +@@ -2677,8 +2668,6 @@ + if (allocated > max_blocks) + allocated = max_blocks; + set_buffer_unwritten(bh_result); +- bh_result->b_bdev = inode->i_sb->s_bdev; +- bh_result->b_blocknr = newblock; + goto out2; + } + +reverted: +--- b/fs/ext4/file.c ++++ a/fs/ext4/file.c +@@ -33,14 +33,9 @@ + */ + static int ext4_release_file (struct inode * inode, struct file * filp) + { +- if (EXT4_I(inode)->i_state & EXT4_STATE_DA_ALLOC_CLOSE) { +- ext4_alloc_da_blocks(inode); +- EXT4_I(inode)->i_state &= ~EXT4_STATE_DA_ALLOC_CLOSE; +- } + /* if we are the last writer on the inode, drop the block reservation */ + if ((filp->f_mode & FMODE_WRITE) && ++ (atomic_read(&inode->i_writecount) == 1)) +- (atomic_read(&inode->i_writecount) == 1) && +- !EXT4_I(inode)->i_reserved_data_blocks) + { + down_write(&EXT4_I(inode)->i_data_sem); + ext4_discard_reservation(inode); +reverted: +--- b/fs/ext4/hash.c ++++ a/fs/ext4/hash.c +@@ -35,71 +35,23 @@ + + + /* The old legacy hash */ ++static __u32 dx_hack_hash (const char *name, int len) +-static __u32 dx_hack_hash_unsigned(const char *name, int len) + { ++ __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; +- __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; +- const unsigned char *ucp = (const unsigned char *) name; +- +- while (len--) { +- hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373)); +- +- if (hash & 0x80000000) +- hash -= 0x7fffffff; +- hash1 = hash0; +- hash0 = hash; +- } +- return hash0 << 1; +-} +- +-static __u32 dx_hack_hash_signed(const char *name, int len) +-{ +- __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; +- const signed char *scp = (const signed char *) name; +- + while (len--) { ++ __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373)); +- hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); + ++ if (hash & 0x80000000) hash -= 0x7fffffff; +- if (hash & 0x80000000) +- hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } ++ return (hash0 << 1); +- return hash0 << 1; + } + ++static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) +-static void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num) + { + __u32 pad, val; + int i; +- const signed char *scp = (const signed char *) msg; +- +- pad = (__u32)len | ((__u32)len << 8); +- pad |= pad << 16; +- +- val = pad; +- if (len > num*4) +- len = num * 4; +- for (i = 0; i < len; i++) { +- if ((i % 4) == 0) +- val = pad; +- val = ((int) scp[i]) + (val << 8); +- if ((i % 4) == 3) { +- *buf++ = val; +- val = pad; +- num--; +- } +- } +- if (--num >= 0) +- *buf++ = val; +- while (--num >= 0) +- *buf++ = pad; +-} +- +-static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) +-{ +- __u32 pad, val; +- int i; +- const unsigned char *ucp = (const unsigned char *) msg; + + pad = (__u32)len | ((__u32)len << 8); + pad |= pad << 16; +@@ -110,7 +62,7 @@ + for (i=0; i < len; i++) { + if ((i % 4) == 0) + val = pad; ++ val = msg[i] + (val << 8); +- val = ((int) ucp[i]) + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; +@@ -143,8 +95,6 @@ + const char *p; + int i; + __u32 in[8], buf[4]; +- void (*str2hashbuf)(const char *, int, __u32 *, int) = +- str2hashbuf_signed; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; +@@ -163,18 +113,13 @@ + } + + switch (hinfo->hash_version) { +- case DX_HASH_LEGACY_UNSIGNED: +- hash = dx_hack_hash_unsigned(name, len); +- break; + case DX_HASH_LEGACY: ++ hash = dx_hack_hash(name, len); +- hash = dx_hack_hash_signed(name, len); + break; +- case DX_HASH_HALF_MD4_UNSIGNED: +- str2hashbuf = str2hashbuf_unsigned; + case DX_HASH_HALF_MD4: + p = name; + while (len > 0) { ++ str2hashbuf(p, len, in, 8); +- (*str2hashbuf)(p, len, in, 8); + half_md4_transform(buf, in); + len -= 32; + p += 32; +@@ -182,12 +127,10 @@ + minor_hash = buf[2]; + hash = buf[1]; + break; +- case DX_HASH_TEA_UNSIGNED: +- str2hashbuf = str2hashbuf_unsigned; + case DX_HASH_TEA: + p = name; + while (len > 0) { ++ str2hashbuf(p, len, in, 4); +- (*str2hashbuf)(p, len, in, 4); + TEA_transform(buf, in); + len -= 16; + p += 16; +reverted: +--- b/fs/ext4/ialloc.c ++++ a/fs/ext4/ialloc.c +@@ -84,7 +84,7 @@ + } + + memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); ++ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), +- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, + bh->b_data); + + return EXT4_INODES_PER_GROUP(sb); +@@ -115,40 +115,18 @@ + block_group, bitmap_blk); + return NULL; + } ++ if (bh_uptodate_or_lock(bh)) +- if (bitmap_uptodate(bh)) + return bh; + +- lock_buffer(bh); +- if (bitmap_uptodate(bh)) { +- unlock_buffer(bh); +- return bh; +- } + spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { + ext4_init_inode_bitmap(sb, bh, block_group, desc); +- set_bitmap_uptodate(bh); + set_buffer_uptodate(bh); + unlock_buffer(bh); + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); + return bh; + } + spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); +- if (buffer_uptodate(bh)) { +- /* +- * if not uninit if bh is uptodate, +- * bitmap is also uptodate +- */ +- set_bitmap_uptodate(bh); +- unlock_buffer(bh); +- return bh; +- } +- /* +- * submit the buffer_head for read. We can +- * safely mark the bitmap as uptodate now. +- * We do it here so the bitmap uptodate bit +- * get set with buffer lock held. +- */ +- set_bitmap_uptodate(bh); + if (bh_submit_read(bh) < 0) { + put_bh(bh); + ext4_error(sb, __func__, +@@ -188,7 +166,7 @@ + struct ext4_group_desc * gdp; + struct ext4_super_block * es; + struct ext4_sb_info *sbi; ++ int fatal = 0, err; +- int fatal = 0, err, cleared; + ext4_group_t flex_group; + + if (atomic_read(&inode->i_count) > 1) { +@@ -242,12 +220,10 @@ + goto error_return; + + /* Ok, now we can actually update the inode bitmaps.. */ ++ if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group), ++ bit, bitmap_bh->b_data)) ++ ext4_error (sb, "ext4_free_inode", ++ "bit already cleared for inode %lu", ino); +- spin_lock(sb_bgl_lock(sbi, block_group)); +- cleared = ext4_clear_bit(bit, bitmap_bh->b_data); +- spin_unlock(sb_bgl_lock(sbi, block_group)); +- if (!cleared) +- ext4_error(sb, "ext4_free_inode", +- "bit already cleared for inode %lu", ino); + else { + gdp = ext4_get_group_desc (sb, block_group, &bh2); + +@@ -591,77 +567,6 @@ + } + + /* +- * claim the inode from the inode bitmap. If the group +- * is uninit we need to take the groups's sb_bgl_lock +- * and clear the uninit flag. The inode bitmap update +- * and group desc uninit flag clear should be done +- * after holding sb_bgl_lock so that ext4_read_inode_bitmap +- * doesn't race with the ext4_claim_inode +- */ +-static int ext4_claim_inode(struct super_block *sb, +- struct buffer_head *inode_bitmap_bh, +- unsigned long ino, ext4_group_t group, int mode) +-{ +- int free = 0, retval = 0; +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); +- +- spin_lock(sb_bgl_lock(sbi, group)); +- if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) { +- /* not a free inode */ +- retval = 1; +- goto err_ret; +- } +- ino++; +- if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || +- ino > EXT4_INODES_PER_GROUP(sb)) { +- spin_unlock(sb_bgl_lock(sbi, group)); +- ext4_error(sb, __func__, +- "reserved inode or inode > inodes count - " +- "block_group = %lu, inode=%lu", group, +- ino + group * EXT4_INODES_PER_GROUP(sb)); +- return 1; +- } +- /* If we didn't allocate from within the initialized part of the inode +- * table then we need to initialize up to this inode. */ +- if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { +- +- if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { +- gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); +- /* When marking the block group with +- * ~EXT4_BG_INODE_UNINIT we don't want to depend +- * on the value of bg_itable_unused even though +- * mke2fs could have initialized the same for us. +- * Instead we calculated the value below +- */ +- +- free = 0; +- } else { +- free = EXT4_INODES_PER_GROUP(sb) - +- le16_to_cpu(gdp->bg_itable_unused); +- } +- +- /* +- * Check the relative inode number against the last used +- * relative inode number in this group. if it is greater +- * we need to update the bg_itable_unused count +- * +- */ +- if (ino > free) +- gdp->bg_itable_unused = +- cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino); +- } +- le16_add_cpu(&gdp->bg_free_inodes_count, -1); +- if (S_ISDIR(mode)) { +- le16_add_cpu(&gdp->bg_used_dirs_count, 1); +- } +- gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); +-err_ret: +- spin_unlock(sb_bgl_lock(sbi, group)); +- return retval; +-} +- +-/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of +@@ -687,7 +592,6 @@ + struct inode *ret; + ext4_group_t i; + int free = 0; +- static int once = 1; + ext4_group_t flex_group; + + /* Cannot create files in a deleted directory */ +@@ -705,15 +609,6 @@ + + if (sbi->s_log_groups_per_flex) { + ret2 = find_group_flex(sb, dir, &group); +- if (ret2 == -1) { +- ret2 = find_group_other(sb, dir, &group); +- if (ret2 == 0 && once) { +- once = 0; +- printk(KERN_NOTICE "ext4: find_group_flex " +- "failed, fallback succeeded dir %lu\n", +- dir->i_ino); +- } +- } + goto got_group; + } + +@@ -754,12 +649,8 @@ + if (err) + goto fail; + ++ if (!ext4_set_bit_atomic(sb_bgl_lock(sbi, group), ++ ino, bitmap_bh->b_data)) { +- BUFFER_TRACE(bh2, "get_write_access"); +- err = ext4_journal_get_write_access(handle, bh2); +- if (err) +- goto fail; +- if (!ext4_claim_inode(sb, bitmap_bh, +- ino, group, mode)) { + /* we won it */ + BUFFER_TRACE(bitmap_bh, + "call ext4_journal_dirty_metadata"); +@@ -767,13 +658,10 @@ + bitmap_bh); + if (err) + goto fail; +- /* zero bit is inode number 1*/ +- ino++; + goto got; + } + /* we lost it */ + jbd2_journal_release_buffer(handle, bitmap_bh); +- jbd2_journal_release_buffer(handle, bh2); + + if (++ino < EXT4_INODES_PER_GROUP(sb)) + goto repeat_in_this_group; +@@ -793,6 +681,21 @@ + goto out; + + got: ++ ino++; ++ if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || ++ ino > EXT4_INODES_PER_GROUP(sb)) { ++ ext4_error(sb, __func__, ++ "reserved inode or inode > inodes count - " ++ "block_group = %lu, inode=%lu", group, ++ ino + group * EXT4_INODES_PER_GROUP(sb)); ++ err = -EIO; ++ goto fail; ++ } ++ ++ BUFFER_TRACE(bh2, "get_write_access"); ++ err = ext4_journal_get_write_access(handle, bh2); ++ if (err) goto fail; ++ + /* We may have to initialize the block bitmap if it isn't already */ + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && + gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { +@@ -827,10 +730,47 @@ + if (err) + goto fail; + } ++ ++ spin_lock(sb_bgl_lock(sbi, group)); ++ /* If we didn't allocate from within the initialized part of the inode ++ * table then we need to initialize up to this inode. */ ++ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { ++ if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { ++ gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); ++ ++ /* When marking the block group with ++ * ~EXT4_BG_INODE_UNINIT we don't want to depend ++ * on the value of bg_itable_unused even though ++ * mke2fs could have initialized the same for us. ++ * Instead we calculated the value below ++ */ ++ ++ free = 0; ++ } else { ++ free = EXT4_INODES_PER_GROUP(sb) - ++ le16_to_cpu(gdp->bg_itable_unused); ++ } ++ ++ /* ++ * Check the relative inode number against the last used ++ * relative inode number in this group. if it is greater ++ * we need to update the bg_itable_unused count ++ * ++ */ ++ if (ino > free) ++ gdp->bg_itable_unused = ++ cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino); ++ } ++ ++ le16_add_cpu(&gdp->bg_free_inodes_count, -1); ++ if (S_ISDIR(mode)) { ++ le16_add_cpu(&gdp->bg_used_dirs_count, 1); ++ } ++ gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); ++ spin_unlock(sb_bgl_lock(sbi, group)); ++ BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); +- BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); + err = ext4_journal_dirty_metadata(handle, bh2); ++ if (err) goto fail; +- if (err) +- goto fail; + + percpu_counter_dec(&sbi->s_freeinodes_counter); + if (S_ISDIR(mode)) +@@ -866,12 +806,16 @@ + ei->i_disksize = 0; + + /* ++ * Don't inherit extent flag from directory. We set extent flag on ++ * newly created directory and file only if -o extent mount option is ++ * specified +- * Don't inherit extent flag from directory, amongst others. We set +- * extent flag on newly created directory and file only if -o extent +- * mount option is specified + */ ++ ei->i_flags = EXT4_I(dir)->i_flags & ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL); ++ if (S_ISLNK(mode)) ++ ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL); ++ /* dirsync only applies to directories */ ++ if (!S_ISDIR(mode)) ++ ei->i_flags &= ~EXT4_DIRSYNC_FL; +- ei->i_flags = +- ext4_mask_flags(mode, EXT4_I(dir)->i_flags & EXT4_FL_INHERITED); + ei->i_file_acl = 0; + ei->i_dtime = 0; + ei->i_block_alloc_info = NULL; +reverted: +--- b/fs/ext4/inode.c ++++ a/fs/ext4/inode.c +@@ -46,10 +46,8 @@ + static inline int ext4_begin_ordered_truncate(struct inode *inode, + loff_t new_size) + { ++ return jbd2_journal_begin_ordered_truncate(&EXT4_I(inode)->jinode, ++ new_size); +- return jbd2_journal_begin_ordered_truncate( +- EXT4_SB(inode->i_sb)->s_journal, +- &EXT4_I(inode)->jinode, +- new_size); + } + + static void ext4_invalidatepage(struct page *page, unsigned long offset); +@@ -353,9 +351,9 @@ + final = ptrs; + } else { + ext4_warning(inode->i_sb, "ext4_block_to_path", ++ "block %lu > max", +- "block %lu > max in inode %lu", + i_block + direct_blocks + ++ indirect_blocks + double_blocks); +- indirect_blocks + double_blocks, inode->i_ino); + } + if (boundary) + *boundary = final - 1 - (i_block & (ptrs - 1)); +@@ -1046,14 +1044,6 @@ + EXT4_I(inode)->i_reserved_meta_blocks = mdb; + EXT4_I(inode)->i_allocated_meta_blocks = 0; + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); +- +- /* +- * If we have done all the pending block allocations and if +- * there aren't any writers on the inode, we can discard the +- * inode's preallocations. +- */ +- if (!total && (atomic_read(&inode->i_writecount) == 0)) +- ext4_discard_reservation(inode); + } + + /* +@@ -1085,7 +1075,6 @@ + int retval; + + clear_buffer_mapped(bh); +- clear_buffer_unwritten(bh); + + /* + * Try to see if we can get the block without requesting +@@ -1116,18 +1105,6 @@ + return retval; + + /* +- * When we call get_blocks without the create flag, the +- * BH_Unwritten flag could have gotten set if the blocks +- * requested were part of a uninitialized extent. We need to +- * clear this flag now that we are committed to convert all or +- * part of the uninitialized extent to be an initialized +- * extent. This is because we need to avoid the combination +- * of BH_Unwritten and BH_Mapped flags being simultaneously +- * set on the buffer_head. +- */ +- clear_buffer_unwritten(bh); +- +- /* + * New blocks allocate and/or writing to uninitialized extent + * will possibly result in updating i_data, so we take + * the write lock of i_data_sem, and call get_blocks() +@@ -1393,10 +1370,6 @@ + goto out; + } + +- /* We cannot recurse into the filesystem as the transaction is already +- * started */ +- flags |= AOP_FLAG_NOFS; +- + page = grab_cache_page_write_begin(mapping, index, flags); + if (!page) { + ext4_journal_stop(handle); +@@ -1406,7 +1379,7 @@ + *pagep = page; + + ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, ++ ext4_get_block); +- ext4_get_block); + + if (!ret && ext4_should_journal_data(inode)) { + ret = walk_page_buffers(handle, page_buffers(page), +@@ -1675,25 +1648,18 @@ + */ + static int mpage_da_submit_io(struct mpage_da_data *mpd) + { ++ struct address_space *mapping = mpd->inode->i_mapping; ++ int ret = 0, err, nr_pages, i; ++ unsigned long index, end; +- long pages_skipped; + struct pagevec pvec; +- unsigned long index, end; +- int ret = 0, err, nr_pages, i; +- struct inode *inode = mpd->inode; +- struct address_space *mapping = inode->i_mapping; + + BUG_ON(mpd->next_page <= mpd->first_page); ++ pagevec_init(&pvec, 0); +- /* +- * We need to start from the first_page to the next_page - 1 +- * to make sure we also write the mapped dirty buffer_heads. +- * If we look at mpd->lbh.b_blocknr we would only be looking +- * at the currently mapped buffer_heads. +- */ + index = mpd->first_page; + end = mpd->next_page - 1; + +- pagevec_init(&pvec, 0); + while (index <= end) { ++ /* XXX: optimize tail */ + nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); + if (nr_pages == 0) + break; +@@ -1705,10 +1671,6 @@ + break; + index++; + +- BUG_ON(!PageLocked(page)); +- BUG_ON(PageWriteback(page)); +- +- pages_skipped = mpd->wbc->pages_skipped; + err = mapping->a_ops->writepage(page, mpd->wbc); + if (!err) + mpd->pages_written++; +@@ -2029,29 +1991,11 @@ + bh = head; + do { + BUG_ON(buffer_locked(bh)); +- /* +- * We need to try to allocate +- * unmapped blocks in the same page. +- * Otherwise we won't make progress +- * with the page in ext4_da_writepage +- */ + if (buffer_dirty(bh) && + (!buffer_mapped(bh) || buffer_delay(bh))) { + mpage_add_bh_to_extent(mpd, logical, bh); + if (mpd->io_done) + return MPAGE_DA_EXTENT_TAIL; +- } else if (buffer_dirty(bh) && (buffer_mapped(bh))) { +- /* +- * mapped dirty buffer. We need to update +- * the b_state because we look at +- * b_state in mpage_da_map_blocks. We don't +- * update b_size because if we find an +- * unmapped buffer_head later we need to +- * use the b_state flag of that buffer_head. +- */ +- if (mpd->lbh.b_size == 0) +- mpd->lbh.b_state = +- bh->b_state & BH_FLAGS; + } + logical++; + } while ((bh = bh->b_this_page) != head); +@@ -2118,10 +2062,6 @@ + struct buffer_head *bh_result, int create) + { + int ret = 0; +- sector_t invalid_block = ~((sector_t) 0xffff); +- +- if (invalid_block < ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es)) +- invalid_block = ~0; + + BUG_ON(create == 0); + BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize); +@@ -2143,18 +2083,11 @@ + /* not enough space to reserve */ + return ret; + ++ map_bh(bh_result, inode->i_sb, 0); +- map_bh(bh_result, inode->i_sb, invalid_block); + set_buffer_new(bh_result); + set_buffer_delay(bh_result); + } else if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); +- /* +- * With sub-block writes into unwritten extents +- * we also need to mark the buffer as new so that +- * the unwritten parts of the buffer gets correctly zeroed. +- */ +- if (buffer_unwritten(bh_result)) +- set_buffer_new(bh_result); + ret = 0; + } + +@@ -2365,20 +2298,6 @@ + */ + if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) + return 0; +- +- /* +- * If the filesystem has aborted, it is read-only, so return +- * right away instead of dumping stack traces later on that +- * will obscure the real source of the problem. We test +- * EXT4_MOUNT_ABORT instead of sb->s_flag's MS_RDONLY because +- * the latter could be true if the filesystem is mounted +- * read-only, and in that case, ext4_da_writepages should +- * *never* be called, so if that ever happens, we would want +- * the stack trace. +- */ +- if (unlikely(sbi->s_mount_opt & EXT4_MOUNT_ABORT)) +- return -EROFS; +- + /* + * Make sure nr_to_write is >= sbi->s_mb_stream_request + * This make sure small files blocks are allocated in +@@ -2417,7 +2336,7 @@ + handle = ext4_journal_start(inode, needed_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); ++ printk(KERN_EMERG "%s: jbd2_start: " +- printk(KERN_CRIT "%s: jbd2_start: " + "%ld pages, ino %lu; err %d\n", __func__, + wbc->nr_to_write, inode->i_ino, ret); + dump_stack(); +@@ -2501,9 +2420,6 @@ + ret = PTR_ERR(handle); + goto out; + } +- /* We cannot recurse into the filesystem as the transaction is already +- * started */ +- flags |= AOP_FLAG_NOFS; + + page = grab_cache_page_write_begin(mapping, index, flags); + if (!page) { +@@ -2617,48 +2533,6 @@ + return; + } + +-/* +- * Force all delayed allocation blocks to be allocated for a given inode. +- */ +-int ext4_alloc_da_blocks(struct inode *inode) +-{ +- if (!EXT4_I(inode)->i_reserved_data_blocks && +- !EXT4_I(inode)->i_reserved_meta_blocks) +- return 0; +- +- /* +- * We do something simple for now. The filemap_flush() will +- * also start triggering a write of the data blocks, which is +- * not strictly speaking necessary (and for users of +- * laptop_mode, not even desirable). However, to do otherwise +- * would require replicating code paths in: +- * +- * ext4_da_writepages() -> +- * write_cache_pages() ---> (via passed in callback function) +- * __mpage_da_writepage() --> +- * mpage_add_bh_to_extent() +- * mpage_da_map_blocks() +- * +- * The problem is that write_cache_pages(), located in +- * mm/page-writeback.c, marks pages clean in preparation for +- * doing I/O, which is not desirable if we're not planning on +- * doing I/O at all. +- * +- * We could call write_cache_pages(), and then redirty all of +- * the pages by calling redirty_page_for_writeback() but that +- * would be ugly in the extreme. So instead we would need to +- * replicate parts of the code in the above functions, +- * simplifying them becuase we wouldn't actually intend to +- * write out the pages, but rather only collect contiguous +- * logical block extents, call the multi-block allocator, and +- * then update the buffer heads with the block allocations. +- * +- * For now, though, we'll cheat by calling filemap_flush(), +- * which will map the blocks, and start the I/O, but not +- * actually wait for the I/O to complete. +- */ +- return filemap_flush(inode->i_mapping); +-} + + /* + * bmap() is special. It gets used by applications such as lilo and by +@@ -3668,9 +3542,6 @@ + if (!ext4_can_truncate(inode)) + return; + +- if (inode->i_size == 0) +- ei->i_state |= EXT4_STATE_DA_ALLOC_CLOSE; +- + if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { + ext4_ext_truncate(inode); + return; +@@ -4088,9 +3959,11 @@ + ei->i_flags = le32_to_cpu(raw_inode->i_flags); + inode->i_blocks = ext4_inode_blocks(raw_inode, ei); + ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo); ++ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != ++ cpu_to_le32(EXT4_OS_HURD)) { +- if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) + ei->i_file_acl |= + ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; ++ } + inode->i_size = ext4_isize(raw_inode); + ei->i_disksize = inode->i_size; + inode->i_generation = le32_to_cpu(raw_inode->i_generation); +@@ -4137,18 +4010,6 @@ + (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; + } + +- if (ei->i_file_acl && +- ((ei->i_file_acl < +- (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + +- EXT4_SB(sb)->s_gdb_count)) || +- (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { +- ext4_error(sb, __func__, +- "bad extended attribute block %llu in inode #%lu", +- ei->i_file_acl, inode->i_ino); +- ret = -EIO; +- goto bad_inode; +- } +- + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ext4_file_inode_operations; + inode->i_fop = &ext4_file_operations; +@@ -4163,8 +4024,7 @@ + inode->i_op = &ext4_symlink_inode_operations; + ext4_set_aops(inode); + } ++ } else { +- } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || +- S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { + inode->i_op = &ext4_special_inode_operations; + if (raw_inode->i_block[0]) + init_special_inode(inode, inode->i_mode, +@@ -4172,13 +4032,6 @@ + else + init_special_inode(inode, inode->i_mode, + new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); +- } else { +- brelse(bh); +- ret = -EIO; +- ext4_error(inode->i_sb, __func__, +- "bogus i_mode (%o) for inode=%lu", +- inode->i_mode, inode->i_ino); +- goto bad_inode; + } + brelse (iloc.bh); + ext4_set_inode_flags(inode); +@@ -4956,9 +4809,8 @@ + return !buffer_mapped(bh); + } + ++int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page) +-int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) + { +- struct page *page = vmf->page; + loff_t size; + unsigned long len; + int ret = -EINVAL; +@@ -5009,8 +4861,6 @@ + goto out_unlock; + ret = 0; + out_unlock: +- if (ret) +- ret = VM_FAULT_SIGBUS; + up_read(&inode->i_alloc_sem); + return ret; + } +reverted: +--- b/fs/ext4/ioctl.c ++++ a/fs/ext4/ioctl.c +@@ -49,7 +49,8 @@ + if (err) + return err; + ++ if (!S_ISDIR(inode->i_mode)) ++ flags &= ~EXT4_DIRSYNC_FL; +- flags = ext4_mask_flags(inode->i_mode, flags); + + err = -EPERM; + mutex_lock(&inode->i_mutex); +@@ -287,20 +288,6 @@ + return err; + } + +- case EXT4_IOC_ALLOC_DA_BLKS: +- { +- int err; +- if (!is_owner_or_cap(inode)) +- return -EACCES; +- +- err = mnt_want_write(filp->f_path.mnt); +- if (err) +- return err; +- err = ext4_alloc_da_blocks(inode); +- mnt_drop_write(filp->f_path.mnt); +- return err; +- } +- + default: + return -ENOTTY; + } +reverted: +--- b/fs/ext4/mballoc.c ++++ a/fs/ext4/mballoc.c +@@ -100,7 +100,7 @@ + * inode as: + * + * { page } ++ * [ group 0 buddy][ group 0 bitmap] [group 1][ group 1]... +- * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]... + * + * + * one block each for bitmap and buddy information. So for each group we +@@ -330,18 +330,6 @@ + * object + * + */ +-static struct kmem_cache *ext4_pspace_cachep; +-static struct kmem_cache *ext4_ac_cachep; +-static struct kmem_cache *ext4_free_ext_cachep; +-static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, +- ext4_group_t group); +-static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, +- ext4_group_t group); +-static int ext4_mb_init_per_dev_proc(struct super_block *sb); +-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); +-static void ext4_mb_free_committed_blocks(struct super_block *); +-static void ext4_mb_poll_new_transaction(struct super_block *sb, +- handle_t *handle); + + static inline void *mb_correct_addr_and_bit(int *bit, void *addr) + { +@@ -730,7 +718,7 @@ + * stored in the inode as + * + * { page } ++ * [ group 0 buddy][ group 0 bitmap] [group 1][ group 1]... +- * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]... + * + * + * one block each for bitmap and buddy information. +@@ -796,42 +784,20 @@ + if (bh[i] == NULL) + goto out; + ++ if (bh_uptodate_or_lock(bh[i])) +- if (bitmap_uptodate(bh[i])) + continue; + +- lock_buffer(bh[i]); +- if (bitmap_uptodate(bh[i])) { +- unlock_buffer(bh[i]); +- continue; +- } + spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); + if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + ext4_init_block_bitmap(sb, bh[i], + first_group + i, desc); +- set_bitmap_uptodate(bh[i]); + set_buffer_uptodate(bh[i]); + unlock_buffer(bh[i]); + spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); + continue; + } + spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); +- if (buffer_uptodate(bh[i])) { +- /* +- * if not uninit if bh is uptodate, +- * bitmap is also uptodate +- */ +- set_bitmap_uptodate(bh[i]); +- unlock_buffer(bh[i]); +- continue; +- } + get_bh(bh[i]); +- /* +- * submit the buffer_head for read. We can +- * safely mark the bitmap as uptodate now. +- * We do it here so the bitmap uptodate bit +- * get set with buffer lock held. +- */ +- set_bitmap_uptodate(bh[i]); + bh[i]->b_end_io = end_buffer_read_sync; + submit_bh(READ, bh[i]); + mb_debug("read bitmap for group %lu\n", first_group + i); +@@ -848,8 +814,6 @@ + + err = 0; + first_block = page->index * blocks_per_page; +- /* init the page */ +- memset(page_address(page), 0xff, PAGE_CACHE_SIZE); + for (i = 0; i < blocks_per_page; i++) { + int group; + struct ext4_group_info *grinfo; +@@ -876,6 +840,7 @@ + BUG_ON(incore == NULL); + mb_debug("put buddy for group %u in page %lu/%x\n", + group, page->index, i * blocksize); ++ memset(data, 0xff, blocksize); + grinfo = ext4_get_group_info(sb, group); + grinfo->bb_fragments = 0; + memset(grinfo->bb_counters, 0, +@@ -883,9 +848,7 @@ + /* + * incore got set to the group block bitmap below + */ +- ext4_lock_group(sb, group); + ext4_mb_generate_buddy(sb, data, incore, group); +- ext4_unlock_group(sb, group); + incore = NULL; + } else { + /* this is block of bitmap */ +@@ -899,7 +862,6 @@ + + /* mark all preallocated blks used in in-core bitmap */ + ext4_mb_generate_from_pa(sb, data, group); +- ext4_mb_generate_from_freelist(sb, data, group); + ext4_unlock_group(sb, group); + + /* set incore so that the buddy information can be +@@ -924,20 +886,18 @@ + ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, + struct ext4_buddy *e4b) + { ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct inode *inode = sbi->s_buddy_cache; + int blocks_per_page; + int block; + int pnum; + int poff; + struct page *page; + int ret; +- struct ext4_group_info *grp; +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct inode *inode = sbi->s_buddy_cache; + + mb_debug("load group %lu\n", group); + + blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; +- grp = ext4_get_group_info(sb, group); + + e4b->bd_blkbits = sb->s_blocksize_bits; + e4b->bd_info = ext4_get_group_info(sb, group); +@@ -945,15 +905,6 @@ + e4b->bd_group = group; + e4b->bd_buddy_page = NULL; + e4b->bd_bitmap_page = NULL; +- e4b->alloc_semp = &grp->alloc_sem; +- +- /* Take the read lock on the group alloc +- * sem. This would make sure a parallel +- * ext4_mb_init_group happening on other +- * groups mapped by the page is blocked +- * till we are done with allocation +- */ +- down_read(e4b->alloc_semp); + + /* + * the buddy cache inode stores the block bitmap +@@ -969,14 +920,6 @@ + page = find_get_page(inode->i_mapping, pnum); + if (page == NULL || !PageUptodate(page)) { + if (page) +- /* +- * drop the page reference and try +- * to get the page with lock. If we +- * are not uptodate that implies +- * somebody just created the page but +- * is yet to initialize the same. So +- * wait for it to initialize. +- */ + page_cache_release(page); + page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); + if (page) { +@@ -1042,9 +985,6 @@ + page_cache_release(e4b->bd_buddy_page); + e4b->bd_buddy = NULL; + e4b->bd_bitmap = NULL; +- +- /* Done with the buddy cache */ +- up_read(e4b->alloc_semp); + return ret; + } + +@@ -1054,9 +994,6 @@ + page_cache_release(e4b->bd_bitmap_page); + if (e4b->bd_buddy_page) + page_cache_release(e4b->bd_buddy_page); +- /* Done with the buddy cache */ +- if (e4b->alloc_semp) +- up_read(e4b->alloc_semp); + } + + +@@ -1094,10 +1031,7 @@ + cur += 32; + continue; + } ++ mb_clear_bit_atomic(lock, cur, bm); +- if (lock) +- mb_clear_bit_atomic(lock, cur, bm); +- else +- mb_clear_bit(cur, bm); + cur++; + } + } +@@ -1115,10 +1049,7 @@ + cur += 32; + continue; + } ++ mb_set_bit_atomic(lock, cur, bm); +- if (lock) +- mb_set_bit_atomic(lock, cur, bm); +- else +- mb_set_bit(cur, bm); + cur++; + } + } +@@ -1365,20 +1296,13 @@ + ac->ac_tail = ret & 0xffff; + ac->ac_buddy = ret >> 16; + ++ /* XXXXXXX: SUCH A HORRIBLE **CK */ ++ /*FIXME!! Why ? */ +- /* +- * take the page reference. We want the page to be pinned +- * so that we don't get a ext4_mb_init_cache_call for this +- * group until we update the bitmap. That would mean we +- * double allocate blocks. The reference is dropped +- * in ext4_mb_release_context +- */ + ac->ac_bitmap_page = e4b->bd_bitmap_page; + get_page(ac->ac_bitmap_page); + ac->ac_buddy_page = e4b->bd_buddy_page; + get_page(ac->ac_buddy_page); ++ +- /* on allocation we use ac to track the held semaphore */ +- ac->alloc_semp = e4b->alloc_semp; +- e4b->alloc_semp = NULL; + /* store last allocated for subsequent stream allocation */ + if ((ac->ac_flags & EXT4_MB_HINT_DATA)) { + spin_lock(&sbi->s_md_lock); +@@ -1402,8 +1326,6 @@ + struct ext4_free_extent ex; + int max; + +- if (ac->ac_status == AC_STATUS_FOUND) +- return; + /* + * We don't want to scan for a whole year + */ +@@ -1450,7 +1372,7 @@ + struct ext4_free_extent *gex = &ac->ac_g_ex; + + BUG_ON(ex->fe_len <= 0); ++ BUG_ON(ex->fe_len >= EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); +- BUG_ON(ex->fe_len > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); + BUG_ON(ex->fe_start >= EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); + BUG_ON(ac->ac_status != AC_STATUS_CONTINUE); + +@@ -1770,173 +1692,6 @@ + return 0; + } + +-/* +- * lock the group_info alloc_sem of all the groups +- * belonging to the same buddy cache page. This +- * make sure other parallel operation on the buddy +- * cache doesn't happen whild holding the buddy cache +- * lock +- */ +-int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group) +-{ +- int i; +- int block, pnum; +- int blocks_per_page; +- int groups_per_page; +- ext4_group_t first_group; +- struct ext4_group_info *grp; +- +- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; +- /* +- * the buddy cache inode stores the block bitmap +- * and buddy information in consecutive blocks. +- * So for each group we need two blocks. +- */ +- block = group * 2; +- pnum = block / blocks_per_page; +- first_group = pnum * blocks_per_page / 2; +- +- groups_per_page = blocks_per_page >> 1; +- if (groups_per_page == 0) +- groups_per_page = 1; +- /* read all groups the page covers into the cache */ +- for (i = 0; i < groups_per_page; i++) { +- +- if ((first_group + i) >= EXT4_SB(sb)->s_groups_count) +- break; +- grp = ext4_get_group_info(sb, first_group + i); +- /* take all groups write allocation +- * semaphore. This make sure there is +- * no block allocation going on in any +- * of that groups +- */ +- down_write(&grp->alloc_sem); +- } +- return i; +-} +- +-void ext4_mb_put_buddy_cache_lock(struct super_block *sb, +- ext4_group_t group, int locked_group) +-{ +- int i; +- int block, pnum; +- int blocks_per_page; +- ext4_group_t first_group; +- struct ext4_group_info *grp; +- +- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; +- /* +- * the buddy cache inode stores the block bitmap +- * and buddy information in consecutive blocks. +- * So for each group we need two blocks. +- */ +- block = group * 2; +- pnum = block / blocks_per_page; +- first_group = pnum * blocks_per_page / 2; +- /* release locks on all the groups */ +- for (i = 0; i < locked_group; i++) { +- +- grp = ext4_get_group_info(sb, first_group + i); +- /* take all groups write allocation +- * semaphore. This make sure there is +- * no block allocation going on in any +- * of that groups +- */ +- up_write(&grp->alloc_sem); +- } +- +-} +- +-static int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) +-{ +- +- int ret; +- void *bitmap; +- int blocks_per_page; +- int block, pnum, poff; +- int num_grp_locked = 0; +- struct ext4_group_info *this_grp; +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- struct inode *inode = sbi->s_buddy_cache; +- struct page *page = NULL, *bitmap_page = NULL; +- +- mb_debug("init group %lu\n", group); +- blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; +- this_grp = ext4_get_group_info(sb, group); +- /* +- * This ensures we don't add group +- * to this buddy cache via resize +- */ +- num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, group); +- if (!EXT4_MB_GRP_NEED_INIT(this_grp)) { +- /* +- * somebody initialized the group +- * return without doing anything +- */ +- ret = 0; +- goto err; +- } +- /* +- * the buddy cache inode stores the block bitmap +- * and buddy information in consecutive blocks. +- * So for each group we need two blocks. +- */ +- block = group * 2; +- pnum = block / blocks_per_page; +- poff = block % blocks_per_page; +- page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); +- if (page) { +- BUG_ON(page->mapping != inode->i_mapping); +- ret = ext4_mb_init_cache(page, NULL); +- if (ret) { +- unlock_page(page); +- goto err; +- } +- unlock_page(page); +- } +- if (page == NULL || !PageUptodate(page)) { +- ret = -EIO; +- goto err; +- } +- mark_page_accessed(page); +- bitmap_page = page; +- bitmap = page_address(page) + (poff * sb->s_blocksize); +- +- /* init buddy cache */ +- block++; +- pnum = block / blocks_per_page; +- poff = block % blocks_per_page; +- page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); +- if (page == bitmap_page) { +- /* +- * If both the bitmap and buddy are in +- * the same page we don't need to force +- * init the buddy +- */ +- unlock_page(page); +- } else if (page) { +- BUG_ON(page->mapping != inode->i_mapping); +- ret = ext4_mb_init_cache(page, bitmap); +- if (ret) { +- unlock_page(page); +- goto err; +- } +- unlock_page(page); +- } +- if (page == NULL || !PageUptodate(page)) { +- ret = -EIO; +- goto err; +- } +- mark_page_accessed(page); +-err: +- ext4_mb_put_buddy_cache_lock(sb, group, num_grp_locked); +- if (bitmap_page) +- page_cache_release(bitmap_page); +- if (page) +- page_cache_release(page); +- return ret; +-} +- + static noinline_for_stack int + ext4_mb_regular_allocator(struct ext4_allocation_context *ac) + { +@@ -2020,7 +1775,7 @@ + group = 0; + + /* quick check to skip empty groups */ ++ grp = ext4_get_group_info(ac->ac_sb, group); +- grp = ext4_get_group_info(sb, group); + if (grp->bb_free == 0) + continue; + +@@ -2033,9 +1788,10 @@ + * we need full data about the group + * to make a good selection + */ ++ err = ext4_mb_load_buddy(sb, group, &e4b); +- err = ext4_mb_init_group(sb, group); + if (err) + goto out; ++ ext4_mb_release_desc(&e4b); + } + + /* +@@ -2543,8 +2299,6 @@ + } + + INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list); +- init_rwsem(&meta_group_info[i]->alloc_sem); +- meta_group_info[i]->bb_free_root.rb_node = NULL;; + + #ifdef DOUBLE_CHECK + { +@@ -2571,6 +2325,54 @@ + } /* ext4_mb_add_groupinfo */ + + /* ++ * Add a group to the existing groups. ++ * This function is used for online resize ++ */ ++int ext4_mb_add_more_groupinfo(struct super_block *sb, ext4_group_t group, ++ struct ext4_group_desc *desc) ++{ ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct inode *inode = sbi->s_buddy_cache; ++ int blocks_per_page; ++ int block; ++ int pnum; ++ struct page *page; ++ int err; ++ ++ /* Add group based on group descriptor*/ ++ err = ext4_mb_add_groupinfo(sb, group, desc); ++ if (err) ++ return err; ++ ++ /* ++ * Cache pages containing dynamic mb_alloc datas (buddy and bitmap ++ * datas) are set not up to date so that they will be re-initilaized ++ * during the next call to ext4_mb_load_buddy ++ */ ++ ++ /* Set buddy page as not up to date */ ++ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; ++ block = group * 2; ++ pnum = block / blocks_per_page; ++ page = find_get_page(inode->i_mapping, pnum); ++ if (page != NULL) { ++ ClearPageUptodate(page); ++ page_cache_release(page); ++ } ++ ++ /* Set bitmap page as not up to date */ ++ block++; ++ pnum = block / blocks_per_page; ++ page = find_get_page(inode->i_mapping, pnum); ++ if (page != NULL) { ++ ClearPageUptodate(page); ++ page_cache_release(page); ++ } ++ ++ return 0; ++} ++ ++/* + * Update an existing group. + * This function is used for online resize + */ +@@ -2693,12 +2495,10 @@ + clear_opt(sbi->s_mount_opt, MBALLOC); + return -ENOMEM; + } +- +- i = (sb->s_blocksize_bits + 2) * sizeof(unsigned int); + sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL); + if (sbi->s_mb_maxs == NULL) { + clear_opt(sbi->s_mount_opt, MBALLOC); ++ kfree(sbi->s_mb_maxs); +- kfree(sbi->s_mb_offsets); + return -ENOMEM; + } + +@@ -2858,11 +2658,13 @@ + static noinline_for_stack void + ext4_mb_free_committed_blocks(struct super_block *sb) + { ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ int err; ++ int i; ++ int count = 0; ++ int count2 = 0; ++ struct ext4_free_metadata *md; + struct ext4_buddy e4b; +- struct ext4_group_info *db; +- struct ext4_sb_info *sbi = EXT4_SB(sb); +- int err, count = 0, count2 = 0; +- struct ext4_free_data *entry; + + if (list_empty(&sbi->s_committed_transaction)) + return; +@@ -2870,46 +2672,44 @@ + /* there is committed blocks to be freed yet */ + do { + /* get next array of blocks */ ++ md = NULL; +- entry = NULL; + spin_lock(&sbi->s_md_lock); + if (!list_empty(&sbi->s_committed_transaction)) { ++ md = list_entry(sbi->s_committed_transaction.next, ++ struct ext4_free_metadata, list); ++ list_del(&md->list); +- entry = list_entry(sbi->s_committed_transaction.next, +- struct ext4_free_data, list); +- list_del(&entry->list); + } + spin_unlock(&sbi->s_md_lock); + ++ if (md == NULL) +- if (entry == NULL) + break; + + mb_debug("gonna free %u blocks in group %lu (0x%p):", ++ md->num, md->group, md); +- entry->count, entry->group, entry); + ++ err = ext4_mb_load_buddy(sb, md->group, &e4b); +- err = ext4_mb_load_buddy(sb, entry->group, &e4b); + /* we expect to find existing buddy because it's pinned */ + BUG_ON(err != 0); + +- db = e4b.bd_info; + /* there are blocks to put in buddy to make them really free */ ++ count += md->num; +- count += entry->count; + count2++; ++ ext4_lock_group(sb, md->group); ++ for (i = 0; i < md->num; i++) { ++ mb_debug(" %u", md->blocks[i]); ++ mb_free_blocks(NULL, &e4b, md->blocks[i], 1); +- ext4_lock_group(sb, entry->group); +- /* Take it out of per group rb tree */ +- rb_erase(&entry->node, &(db->bb_free_root)); +- mb_free_blocks(NULL, &e4b, entry->start_blk, entry->count); +- +- if (!db->bb_free_root.rb_node) { +- /* No more items in the per group rb tree +- * balance refcounts from ext4_mb_free_metadata() +- */ +- page_cache_release(e4b.bd_buddy_page); +- page_cache_release(e4b.bd_bitmap_page); + } ++ mb_debug("\n"); ++ ext4_unlock_group(sb, md->group); +- ext4_unlock_group(sb, entry->group); + ++ /* balance refcounts from ext4_mb_free_metadata() */ ++ page_cache_release(e4b.bd_buddy_page); ++ page_cache_release(e4b.bd_bitmap_page); ++ ++ kfree(md); +- kmem_cache_free(ext4_free_ext_cachep, entry); + ext4_mb_release_desc(&e4b); ++ ++ } while (md); +- } while (1); + + mb_debug("freed %u blocks in %u structures\n", count, count2); + } +@@ -3064,16 +2864,6 @@ + kmem_cache_destroy(ext4_pspace_cachep); + return -ENOMEM; + } +- +- ext4_free_ext_cachep = +- kmem_cache_create("ext4_free_block_extents", +- sizeof(struct ext4_free_data), +- 0, SLAB_RECLAIM_ACCOUNT, NULL); +- if (ext4_free_ext_cachep == NULL) { +- kmem_cache_destroy(ext4_pspace_cachep); +- kmem_cache_destroy(ext4_ac_cachep); +- return -ENOMEM; +- } + #ifdef CONFIG_PROC_FS + proc_root_ext4 = proc_mkdir("fs/ext4", NULL); + if (proc_root_ext4 == NULL) +@@ -3090,7 +2880,6 @@ + #ifdef CONFIG_PROC_FS + remove_proc_entry("fs/ext4", NULL); + #endif +- kmem_cache_destroy(ext4_free_ext_cachep); + } + + +@@ -3152,8 +2941,8 @@ + in_range(block + len - 1, ext4_inode_table(sb, gdp), + EXT4_SB(sb)->s_itb_per_group)) { + ext4_error(sb, __func__, ++ "Allocating block in system zone - block = %llu", ++ block); +- "Allocating block %llu in system zone of %lu group\n", +- block, ac->ac_b_ex.fe_group); + /* File system mounted not to panic on error + * Fix the bitmap and repeat the block allocation + * We leak some of the blocks here. +@@ -3175,9 +2964,10 @@ + } + } + #endif ++ mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group), bitmap_bh->b_data, ++ ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len); ++ + spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group)); +- mb_set_bits(NULL, bitmap_bh->b_data, +- ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len); + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); + gdp->bg_free_blocks_count = +@@ -3400,7 +3190,7 @@ + } + BUG_ON(start + size <= ac->ac_o_ex.fe_logical && + start > ac->ac_o_ex.fe_logical); ++ BUG_ON(size <= 0 || size >= EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); +- BUG_ON(size <= 0 || size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); + + /* now prepare goal request */ + +@@ -3610,37 +3400,10 @@ + ac->ac_criteria = 20; + return 1; + } +- + return 0; + } + + /* +- * the function goes through all block freed in the group +- * but not yet committed and marks them used in in-core bitmap. +- * buddy must be generated from this bitmap +- * Need to be called with ext4 group lock (ext4_lock_group) +- */ +-static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, +- ext4_group_t group) +-{ +- struct rb_node *n; +- struct ext4_group_info *grp; +- struct ext4_free_data *entry; +- +- grp = ext4_get_group_info(sb, group); +- n = rb_first(&(grp->bb_free_root)); +- +- while (n) { +- entry = rb_entry(n, struct ext4_free_data, node); +- mb_set_bits(sb_bgl_lock(EXT4_SB(sb), group), +- bitmap, entry->start_blk, +- entry->count); +- n = rb_next(n); +- } +- return; +-} +- +-/* + * the function goes through all preallocation in this group and marks them + * used in in-core bitmap. buddy must be generated from this bitmap + * Need to be called with ext4 group lock (ext4_lock_group) +@@ -3698,7 +3461,6 @@ + struct super_block *sb, struct ext4_prealloc_space *pa) + { + unsigned long grp; +- ext4_fsblk_t grp_blk; + + if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) + return; +@@ -3713,12 +3475,8 @@ + pa->pa_deleted = 1; + spin_unlock(&pa->pa_lock); + ++ /* -1 is to protect from crossing allocation group */ ++ ext4_get_group_no_and_offset(sb, pa->pa_pstart - 1, &grp, NULL); +- grp_blk = pa->pa_pstart; +- /* If linear, pa_pstart may be in the next group when pa is used up */ +- if (pa->pa_linear) +- grp_blk--; +- +- ext4_get_group_no_and_offset(sb, grp_blk, &grp, NULL); + + /* + * possible race: +@@ -3807,8 +3565,6 @@ + pa->pa_free = pa->pa_len; + atomic_set(&pa->pa_count, 1); + spin_lock_init(&pa->pa_lock); +- INIT_LIST_HEAD(&pa->pa_inode_list); +- INIT_LIST_HEAD(&pa->pa_group_list); + pa->pa_deleted = 0; + pa->pa_linear = 0; + +@@ -3867,7 +3623,6 @@ + atomic_set(&pa->pa_count, 1); + spin_lock_init(&pa->pa_lock); + INIT_LIST_HEAD(&pa->pa_inode_list); +- INIT_LIST_HEAD(&pa->pa_group_list); + pa->pa_deleted = 0; + pa->pa_linear = 1; + +@@ -4411,7 +4166,6 @@ + ac->ac_pa = NULL; + ac->ac_bitmap_page = NULL; + ac->ac_buddy_page = NULL; +- ac->alloc_semp = NULL; + ac->ac_lg = NULL; + + /* we have to define context: we'll we work with a file or +@@ -4532,7 +4286,7 @@ + pa_inode_list) { + spin_lock(&tmp_pa->pa_lock); + if (tmp_pa->pa_deleted) { ++ spin_unlock(&pa->pa_lock); +- spin_unlock(&tmp_pa->pa_lock); + continue; + } + if (!added && pa->pa_free < tmp_pa->pa_free) { +@@ -4577,23 +4331,18 @@ + pa->pa_free -= ac->ac_b_ex.fe_len; + pa->pa_len -= ac->ac_b_ex.fe_len; + spin_unlock(&pa->pa_lock); ++ /* ++ * We want to add the pa to the right bucket. ++ * Remove it from the list and while adding ++ * make sure the list to which we are adding ++ * doesn't grow big. ++ */ ++ if (likely(pa->pa_free)) { ++ spin_lock(pa->pa_obj_lock); ++ list_del_rcu(&pa->pa_inode_list); ++ spin_unlock(pa->pa_obj_lock); ++ ext4_mb_add_n_trim(ac); ++ } +- } +- } +- if (ac->alloc_semp) +- up_read(ac->alloc_semp); +- if (pa) { +- /* +- * We want to add the pa to the right bucket. +- * Remove it from the list and while adding +- * make sure the list to which we are adding +- * doesn't grow big. We need to release +- * alloc_semp before calling ext4_mb_add_n_trim() +- */ +- if (pa->pa_linear && likely(pa->pa_free)) { +- spin_lock(pa->pa_obj_lock); +- list_del_rcu(&pa->pa_inode_list); +- spin_unlock(pa->pa_obj_lock); +- ext4_mb_add_n_trim(ac); + } + ext4_mb_put_pa(ac, ac->ac_sb, pa); + } +@@ -4700,14 +4449,10 @@ + ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) + ext4_mb_new_preallocation(ac); + } ++ + if (likely(ac->ac_status == AC_STATUS_FOUND)) { + *errp = ext4_mb_mark_diskspace_used(ac, handle); + if (*errp == -EAGAIN) { +- /* +- * drop the reference that we took +- * in ext4_mb_use_best_found +- */ +- ext4_mb_release_context(ac); + ac->ac_b_ex.fe_group = 0; + ac->ac_b_ex.fe_start = 0; + ac->ac_b_ex.fe_len = 0; +@@ -4772,97 +4517,65 @@ + ext4_mb_free_committed_blocks(sb); + } + +-/* +- * We can merge two free data extents only if the physical blocks +- * are contiguous, AND the extents were freed by the same transaction, +- * AND the blocks are associated with the same group. +- */ +-static int can_merge(struct ext4_free_data *entry1, +- struct ext4_free_data *entry2) +-{ +- if ((entry1->t_tid == entry2->t_tid) && +- (entry1->group == entry2->group) && +- ((entry1->start_blk + entry1->count) == entry2->start_blk)) +- return 1; +- return 0; +-} +- + static noinline_for_stack int + ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, ++ ext4_group_t group, ext4_grpblk_t block, int count) +- struct ext4_free_data *new_entry) + { +- ext4_grpblk_t block; +- struct ext4_free_data *entry; + struct ext4_group_info *db = e4b->bd_info; + struct super_block *sb = e4b->bd_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct ext4_free_metadata *md; ++ int i; +- struct rb_node **n = &db->bb_free_root.rb_node, *node; +- struct rb_node *parent = NULL, *new_node; + + BUG_ON(e4b->bd_bitmap_page == NULL); + BUG_ON(e4b->bd_buddy_page == NULL); + ++ ext4_lock_group(sb, group); ++ for (i = 0; i < count; i++) { ++ md = db->bb_md_cur; ++ if (md && db->bb_tid != handle->h_transaction->t_tid) { ++ db->bb_md_cur = NULL; ++ md = NULL; +- new_node = &new_entry->node; +- block = new_entry->start_blk; +- +- if (!*n) { +- /* first free block exent. We need to +- protect buddy cache from being freed, +- * otherwise we'll refresh it from +- * on-disk bitmap and lose not-yet-available +- * blocks */ +- page_cache_get(e4b->bd_buddy_page); +- page_cache_get(e4b->bd_bitmap_page); +- } +- while (*n) { +- parent = *n; +- entry = rb_entry(parent, struct ext4_free_data, node); +- if (block < entry->start_blk) +- n = &(*n)->rb_left; +- else if (block >= (entry->start_blk + entry->count)) +- n = &(*n)->rb_right; +- else { +- ext4_error(sb, __func__, +- "Double free of blocks %d (%d %d)\n", +- block, entry->start_blk, entry->count); +- return 0; + } +- } + ++ if (md == NULL) { ++ ext4_unlock_group(sb, group); ++ md = kmalloc(sizeof(*md), GFP_NOFS); ++ if (md == NULL) ++ return -ENOMEM; ++ md->num = 0; ++ md->group = group; ++ ++ ext4_lock_group(sb, group); ++ if (db->bb_md_cur == NULL) { ++ spin_lock(&sbi->s_md_lock); ++ list_add(&md->list, &sbi->s_active_transaction); ++ spin_unlock(&sbi->s_md_lock); ++ /* protect buddy cache from being freed, ++ * otherwise we'll refresh it from ++ * on-disk bitmap and lose not-yet-available ++ * blocks */ ++ page_cache_get(e4b->bd_buddy_page); ++ page_cache_get(e4b->bd_bitmap_page); ++ db->bb_md_cur = md; ++ db->bb_tid = handle->h_transaction->t_tid; ++ mb_debug("new md 0x%p for group %lu\n", ++ md, md->group); ++ } else { ++ kfree(md); ++ md = db->bb_md_cur; ++ } +- rb_link_node(new_node, parent, n); +- rb_insert_color(new_node, &db->bb_free_root); +- +- /* Now try to see the extent can be merged to left and right */ +- node = rb_prev(new_node); +- if (node) { +- entry = rb_entry(node, struct ext4_free_data, node); +- if (can_merge(entry, new_entry)) { +- new_entry->start_blk = entry->start_blk; +- new_entry->count += entry->count; +- rb_erase(node, &(db->bb_free_root)); +- spin_lock(&sbi->s_md_lock); +- list_del(&entry->list); +- spin_unlock(&sbi->s_md_lock); +- kmem_cache_free(ext4_free_ext_cachep, entry); + } +- } + ++ BUG_ON(md->num >= EXT4_BB_MAX_BLOCKS); ++ md->blocks[md->num] = block + i; ++ md->num++; ++ if (md->num == EXT4_BB_MAX_BLOCKS) { ++ /* no more space, put full container on a sb's list */ ++ db->bb_md_cur = NULL; +- node = rb_next(new_node); +- if (node) { +- entry = rb_entry(node, struct ext4_free_data, node); +- if (can_merge(new_entry, entry)) { +- new_entry->count += entry->count; +- rb_erase(node, &(db->bb_free_root)); +- spin_lock(&sbi->s_md_lock); +- list_del(&entry->list); +- spin_unlock(&sbi->s_md_lock); +- kmem_cache_free(ext4_free_ext_cachep, entry); + } + } ++ ext4_unlock_group(sb, group); +- /* Add the extent to active_transaction list */ +- spin_lock(&sbi->s_md_lock); +- list_add(&new_entry->list, &sbi->s_active_transaction); +- spin_unlock(&sbi->s_md_lock); + return 0; + } + +@@ -4962,6 +4675,11 @@ + err = ext4_journal_get_write_access(handle, gd_bh); + if (err) + goto error_return; ++ ++ err = ext4_mb_load_buddy(sb, block_group, &e4b); ++ if (err) ++ goto error_return; ++ + #ifdef AGGRESSIVE_CHECK + { + int i; +@@ -4969,6 +4687,13 @@ + BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data)); + } + #endif ++ mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, ++ bit, count); ++ ++ /* We dirtied the bitmap block */ ++ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); ++ err = ext4_journal_dirty_metadata(handle, bitmap_bh); ++ + if (ac) { + ac->ac_b_ex.fe_group = block_group; + ac->ac_b_ex.fe_start = bit; +@@ -4976,33 +4701,12 @@ + ext4_mb_store_history(ac); + } + +- err = ext4_mb_load_buddy(sb, block_group, &e4b); +- if (err) +- goto error_return; + if (metadata) { ++ /* blocks being freed are metadata. these blocks shouldn't ++ * be used until this transaction is committed */ ++ ext4_mb_free_metadata(handle, &e4b, block_group, bit, count); +- struct ext4_free_data *new_entry; +- /* +- * blocks being freed are metadata. these blocks shouldn't +- * be used until this transaction is committed +- */ +- new_entry = kmem_cache_alloc(ext4_free_ext_cachep, GFP_NOFS); +- new_entry->start_blk = bit; +- new_entry->group = block_group; +- new_entry->count = count; +- new_entry->t_tid = handle->h_transaction->t_tid; +- ext4_lock_group(sb, block_group); +- mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, +- bit, count); +- ext4_mb_free_metadata(handle, &e4b, new_entry); +- ext4_unlock_group(sb, block_group); + } else { + ext4_lock_group(sb, block_group); +- /* need to update group_info->bb_free and bitmap +- * with group lock held. generate_buddy look at +- * them with group lock_held +- */ +- mb_clear_bits(sb_bgl_lock(sbi, block_group), bitmap_bh->b_data, +- bit, count); + mb_free_blocks(inode, &e4b, bit, count); + ext4_mb_return_to_preallocation(inode, &e4b, block, count); + ext4_unlock_group(sb, block_group); +@@ -5025,10 +4729,6 @@ + + *freed += count; + +- /* We dirtied the bitmap block */ +- BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); +- err = ext4_journal_dirty_metadata(handle, bitmap_bh); +- + /* And the group descriptor block */ + BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); + ret = ext4_journal_dirty_metadata(handle, gd_bh); +reverted: +--- b/fs/ext4/mballoc.h ++++ a/fs/ext4/mballoc.h +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include "ext4_jbd2.h" + #include "ext4.h" + #include "group.h" +@@ -97,27 +96,25 @@ + */ + #define MB_DEFAULT_GROUP_PREALLOC 512 + ++static struct kmem_cache *ext4_pspace_cachep; ++static struct kmem_cache *ext4_ac_cachep; +-struct ext4_free_data { +- /* this links the free block information from group_info */ +- struct rb_node node; + ++#ifdef EXT4_BB_MAX_BLOCKS ++#undef EXT4_BB_MAX_BLOCKS ++#endif ++#define EXT4_BB_MAX_BLOCKS 30 +- /* this links the free block information from ext4_sb_info */ +- struct list_head list; + ++struct ext4_free_metadata { +- /* group which free block extent belongs */ + ext4_group_t group; ++ unsigned short num; ++ ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS]; ++ struct list_head list; +- +- /* free block extent */ +- ext4_grpblk_t start_blk; +- ext4_grpblk_t count; +- +- /* transaction which freed this extent */ +- tid_t t_tid; + }; + + struct ext4_group_info { + unsigned long bb_state; ++ unsigned long bb_tid; ++ struct ext4_free_metadata *bb_md_cur; +- struct rb_root bb_free_root; + unsigned short bb_first_free; + unsigned short bb_free; + unsigned short bb_fragments; +@@ -125,7 +122,6 @@ + #ifdef DOUBLE_CHECK + void *bb_bitmap; + #endif +- struct rw_semaphore alloc_sem; + unsigned short bb_counters[]; + }; + +@@ -213,11 +209,6 @@ + __u8 ac_op; /* operation, for history only */ + struct page *ac_bitmap_page; + struct page *ac_buddy_page; +- /* +- * pointer to the held semaphore upon successful +- * block allocation +- */ +- struct rw_semaphore *alloc_semp; + struct ext4_prealloc_space *ac_pa; + struct ext4_locality_group *ac_lg; + }; +@@ -251,7 +242,6 @@ + struct super_block *bd_sb; + __u16 bd_blkbits; + ext4_group_t bd_group; +- struct rw_semaphore *alloc_semp; + }; + #define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap) + #define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy) +@@ -261,6 +251,8 @@ + { + return; + } ++#else ++static void ext4_mb_store_history(struct ext4_allocation_context *ac); + #endif + + #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) +@@ -268,6 +260,19 @@ + static struct proc_dir_entry *proc_root_ext4; + struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t); + ++static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, ++ ext4_group_t group); ++static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *); ++static void ext4_mb_free_committed_blocks(struct super_block *); ++static void ext4_mb_return_to_preallocation(struct inode *inode, ++ struct ext4_buddy *e4b, sector_t block, ++ int count); ++static void ext4_mb_put_pa(struct ext4_allocation_context *, ++ struct super_block *, struct ext4_prealloc_space *pa); ++static int ext4_mb_init_per_dev_proc(struct super_block *sb); ++static int ext4_mb_destroy_per_dev_proc(struct super_block *sb); ++ ++ + static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) + { + struct ext4_group_info *grinfo = ext4_get_group_info(sb, group); +@@ -292,7 +297,7 @@ + &(grinfo->bb_state)); + } + ++static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, +-static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, + struct ext4_free_extent *fex) + { + ext4_fsblk_t block; +reverted: +--- b/fs/ext4/migrate.c ++++ a/fs/ext4/migrate.c +@@ -480,7 +480,7 @@ + + 1); + if (IS_ERR(handle)) { + retval = PTR_ERR(handle); ++ goto err_out; +- return retval; + } + tmp_inode = ext4_new_inode(handle, + inode->i_sb->s_root->d_inode, +@@ -488,7 +488,8 @@ + if (IS_ERR(tmp_inode)) { + retval = -ENOMEM; + ext4_journal_stop(handle); ++ tmp_inode = NULL; ++ goto err_out; +- return retval; + } + i_size_write(tmp_inode, i_size_read(inode)); + /* +@@ -616,7 +617,8 @@ + + ext4_journal_stop(handle); + ++ if (tmp_inode) ++ iput(tmp_inode); +- iput(tmp_inode); + + return retval; + } +reverted: +--- b/fs/ext4/namei.c ++++ a/fs/ext4/namei.c +@@ -371,8 +371,6 @@ + goto fail; + } + hinfo->hash_version = root->info.hash_version; +- if (hinfo->hash_version <= DX_HASH_TEA) +- hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; + if (dentry) + ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); +@@ -642,9 +640,6 @@ + dir = dir_file->f_path.dentry->d_inode; + if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) { + hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; +- if (hinfo.hash_version <= DX_HASH_TEA) +- hinfo.hash_version += +- EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; + count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, + start_hash, start_minor_hash); +@@ -1055,16 +1050,8 @@ + return ERR_PTR(-EIO); + } + inode = ext4_iget(dir->i_sb, ino); ++ if (IS_ERR(inode)) ++ return ERR_CAST(inode); +- if (unlikely(IS_ERR(inode))) { +- if (PTR_ERR(inode) == -ESTALE) { +- ext4_error(dir->i_sb, __func__, +- "deleted inode referenced: %u", +- ino); +- return ERR_PTR(-EIO); +- } else { +- return ERR_CAST(inode); +- } +- } + } + return d_splice_alias(inode, dentry); + } +@@ -1390,7 +1377,7 @@ + struct fake_dirent *fde; + + blocksize = dir->i_sb->s_blocksize; ++ dxtrace(printk("Creating index\n")); +- dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); + retval = ext4_journal_get_write_access(handle, bh); + if (retval) { + ext4_std_error(dir->i_sb, retval); +@@ -1399,20 +1386,6 @@ + } + root = (struct dx_root *) bh->b_data; + +- /* The 0th block becomes the root, move the dirents out */ +- fde = &root->dotdot; +- de = (struct ext4_dir_entry_2 *)((char *)fde + +- ext4_rec_len_from_disk(fde->rec_len)); +- if ((char *) de >= (((char *) root) + blocksize)) { +- ext4_error(dir->i_sb, __func__, +- "invalid rec_len for '..' in inode %lu", +- dir->i_ino); +- brelse(bh); +- return -EIO; +- } +- len = ((char *) root) + blocksize - (char *) de; +- +- /* Allocate new block for the 0th block's dirents */ + bh2 = ext4_append (handle, dir, &block, &retval); + if (!(bh2)) { + brelse(bh); +@@ -1421,6 +1394,11 @@ + EXT4_I(dir)->i_flags |= EXT4_INDEX_FL; + data1 = bh2->b_data; + ++ /* The 0th block becomes the root, move the dirents out */ ++ fde = &root->dotdot; ++ de = (struct ext4_dir_entry_2 *)((char *)fde + ++ ext4_rec_len_from_disk(fde->rec_len)); ++ len = ((char *) root) + blocksize - (char *) de; + memcpy (data1, de, len); + de = (struct ext4_dir_entry_2 *) data1; + top = data1 + len; +@@ -1440,8 +1418,6 @@ + + /* Initialize as for dx_probe */ + hinfo.hash_version = root->info.hash_version; +- if (hinfo.hash_version <= DX_HASH_TEA) +- hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; + ext4fs_dirhash(name, namelen, &hinfo); + frame = frames; +@@ -2314,7 +2290,7 @@ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ext4_dir_entry_2 * old_de, * new_de; ++ int retval; +- int retval, force_da_alloc = 0; + + old_bh = new_bh = dir_bh = NULL; + +@@ -2452,7 +2428,6 @@ + ext4_mark_inode_dirty(handle, new_inode); + if (!new_inode->i_nlink) + ext4_orphan_add(handle, new_inode); +- force_da_alloc = 1; + } + retval = 0; + +@@ -2461,8 +2436,6 @@ + brelse (old_bh); + brelse (new_bh); + ext4_journal_stop(handle); +- if (retval == 0 && force_da_alloc) +- ext4_alloc_da_blocks(old_inode); + return retval; + } + +reverted: +--- b/fs/ext4/resize.c ++++ a/fs/ext4/resize.c +@@ -284,9 +284,11 @@ + if ((err = extend_or_restart_transaction(handle, 2, bh))) + goto exit_bh; + ++ mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb), ++ bh->b_data); +- mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8, bh->b_data); + ext4_journal_dirty_metadata(handle, bh); + brelse(bh); ++ + /* Mark unused entries in inode bitmap used */ + ext4_debug("clear inode bitmap %#04llx (+%llu)\n", + input->inode_bitmap, input->inode_bitmap - start); +@@ -295,7 +297,7 @@ + goto exit_journal; + } + ++ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), +- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, + bh->b_data); + ext4_journal_dirty_metadata(handle, bh); + exit_bh: +@@ -745,7 +747,6 @@ + struct inode *inode = NULL; + handle_t *handle; + int gdb_off, gdb_num; +- int num_grp_locked = 0; + int err, err2; + + gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb); +@@ -786,7 +787,6 @@ + } + } + +- + if ((err = verify_group_input(sb, input))) + goto exit_put; + +@@ -855,18 +855,15 @@ + * using the new disk blocks. + */ + +- num_grp_locked = ext4_mb_get_buddy_cache_lock(sb, input->group); + /* Update group descriptor block for new group */ + gdp = (struct ext4_group_desc *)((char *)primary->b_data + + gdb_off * EXT4_DESC_SIZE(sb)); + +- memset(gdp, 0, EXT4_DESC_SIZE(sb)); + ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */ + ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */ + ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */ + gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); + gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb)); +- gdp->bg_flags = cpu_to_le16(EXT4_BG_INODE_ZEROED); + gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp); + + /* +@@ -874,11 +871,9 @@ + * descriptor + */ + if (test_opt(sb, MBALLOC)) { ++ err = ext4_mb_add_more_groupinfo(sb, input->group, gdp); ++ if (err) +- err = ext4_mb_add_groupinfo(sb, input->group, gdp); +- if (err) { +- ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); + goto exit_journal; +- } + } + /* + * Make the new blocks and inodes valid next. We do this before +@@ -920,7 +915,6 @@ + + /* Update the global fs size fields */ + sbi->s_groups_count++; +- ext4_mb_put_buddy_cache_lock(sb, input->group, num_grp_locked); + + ext4_journal_dirty_metadata(handle, primary); + +@@ -982,7 +976,9 @@ + struct buffer_head * bh; + handle_t *handle; + int err; ++ unsigned long freed_blocks; + ext4_group_t group; ++ struct ext4_group_info *grp; + + /* We don't need to worry about locking wrt other resizers just + * yet: we're going to revalidate es->s_blocks_count after +@@ -1081,13 +1077,50 @@ + unlock_super(sb); + ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, + o_blocks_count + add); ++ ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); +- /* We add the blocks to the bitmap and set the group need init bit */ +- ext4_add_groupblocks(handle, sb, o_blocks_count, add); + ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, + o_blocks_count + add); + if ((err = ext4_journal_stop(handle))) + goto exit_put; + ++ /* ++ * Mark mballoc pages as not up to date so that they will be updated ++ * next time they are loaded by ext4_mb_load_buddy. ++ */ ++ if (test_opt(sb, MBALLOC)) { ++ struct ext4_sb_info *sbi = EXT4_SB(sb); ++ struct inode *inode = sbi->s_buddy_cache; ++ int blocks_per_page; ++ int block; ++ int pnum; ++ struct page *page; ++ ++ /* Set buddy page as not up to date */ ++ blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize; ++ block = group * 2; ++ pnum = block / blocks_per_page; ++ page = find_get_page(inode->i_mapping, pnum); ++ if (page != NULL) { ++ ClearPageUptodate(page); ++ page_cache_release(page); ++ } ++ ++ /* Set bitmap page as not up to date */ ++ block++; ++ pnum = block / blocks_per_page; ++ page = find_get_page(inode->i_mapping, pnum); ++ if (page != NULL) { ++ ClearPageUptodate(page); ++ page_cache_release(page); ++ } ++ ++ /* Get the info on the last group */ ++ grp = ext4_get_group_info(sb, group); ++ ++ /* Update free blocks in group info */ ++ ext4_mb_update_group_info(grp, add); ++ } ++ + if (test_opt(sb, DEBUG)) + printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n", + ext4_blocks_count(es)); +reverted: +--- b/fs/ext4/super.c ++++ a/fs/ext4/super.c +@@ -1493,6 +1493,7 @@ + ext4_group_t flex_group_count; + ext4_group_t flex_group; + int groups_per_flex = 0; ++ __u64 block_bitmap = 0; + int i; + + if (!sbi->s_es->s_log_groups_per_flex) { +@@ -1515,6 +1516,9 @@ + goto failed; + } + ++ gdp = ext4_get_group_desc(sb, 1, &bh); ++ block_bitmap = ext4_block_bitmap(sb, gdp) - 1; ++ + for (i = 0; i < sbi->s_groups_count; i++) { + gdp = ext4_get_group_desc(sb, i, &bh); + +@@ -1916,8 +1920,8 @@ + struct inode *root; + int ret = -EINVAL; + int blocksize; ++ int db_count; ++ int i; +- unsigned int db_count; +- unsigned int i; + int needs_recovery; + __le32 features; + __u64 blocks_count; +@@ -2168,18 +2172,6 @@ + for (i = 0; i < 4; i++) + sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); + sbi->s_def_hash_version = es->s_def_hash_version; +- i = le32_to_cpu(es->s_flags); +- if (i & EXT2_FLAGS_UNSIGNED_HASH) +- sbi->s_hash_unsigned = 3; +- else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { +-#ifdef __CHAR_UNSIGNED__ +- es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); +- sbi->s_hash_unsigned = 3; +-#else +- es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); +-#endif +- sb->s_dirt = 1; +- } + + if (sbi->s_blocks_per_group > blocksize * 8) { + printk(KERN_ERR +@@ -2207,30 +2199,20 @@ + if (EXT4_BLOCKS_PER_GROUP(sb) == 0) + goto cantfind_ext4; + ++ /* ensure blocks_count calculation below doesn't sign-extend */ ++ if (ext4_blocks_count(es) + EXT4_BLOCKS_PER_GROUP(sb) < ++ le32_to_cpu(es->s_first_data_block) + 1) { ++ printk(KERN_WARNING "EXT4-fs: bad geometry: block count %llu, " ++ "first data block %u, blocks per group %lu\n", ++ ext4_blocks_count(es), ++ le32_to_cpu(es->s_first_data_block), ++ EXT4_BLOCKS_PER_GROUP(sb)); +- /* +- * It makes no sense for the first data block to be beyond the end +- * of the filesystem. +- */ +- if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) { +- printk(KERN_WARNING "EXT4-fs: bad geometry: first data" +- "block %u is beyond end of filesystem (%llu)\n", +- le32_to_cpu(es->s_first_data_block), +- ext4_blocks_count(es)); + goto failed_mount; + } + blocks_count = (ext4_blocks_count(es) - + le32_to_cpu(es->s_first_data_block) + + EXT4_BLOCKS_PER_GROUP(sb) - 1); + do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); +- if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) { +- printk(KERN_WARNING "EXT4-fs: groups count too large: %u " +- "(block count %llu, first data block %u, " +- "blocks per group %lu)\n", sbi->s_groups_count, +- ext4_blocks_count(es), +- le32_to_cpu(es->s_first_data_block), +- EXT4_BLOCKS_PER_GROUP(sb)); +- goto failed_mount; +- } + sbi->s_groups_count = blocks_count; + db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / + EXT4_DESC_PER_BLOCK(sb); +@@ -2950,14 +2932,14 @@ + + static int ext4_sync_fs(struct super_block *sb, int wait) + { ++ int ret = 0; +- tid_t target; + + sb->s_dirt = 0; ++ if (wait) ++ ret = ext4_force_commit(sb); ++ else ++ jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL); ++ return ret; +- if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { +- if (wait) +- jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); +- } +- return 0; + } + + /* +reverted: +--- b/fs/jbd2/commit.c ++++ a/fs/jbd2/commit.c +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + + /* + * Default IO end handler for temporary BJ_IO buffer_heads. +@@ -171,34 +170,12 @@ + * This function along with journal_submit_commit_record + * allows to write the commit record asynchronously. + */ ++static int journal_wait_on_commit_record(struct buffer_head *bh) +-static int journal_wait_on_commit_record(journal_t *journal, +- struct buffer_head *bh) + { + int ret = 0; + +-retry: + clear_buffer_dirty(bh); + wait_on_buffer(bh); +- if (buffer_eopnotsupp(bh) && (journal->j_flags & JBD2_BARRIER)) { +- printk(KERN_WARNING +- "JBD2: wait_on_commit_record: sync failed on %s - " +- "disabling barriers\n", journal->j_devname); +- spin_lock(&journal->j_state_lock); +- journal->j_flags &= ~JBD2_BARRIER; +- spin_unlock(&journal->j_state_lock); +- +- lock_buffer(bh); +- clear_buffer_dirty(bh); +- set_buffer_uptodate(bh); +- bh->b_end_io = journal_end_buffer_io_sync; +- +- ret = submit_bh(WRITE_SYNC, bh); +- if (ret) { +- unlock_buffer(bh); +- return ret; +- } +- goto retry; +- } + + if (unlikely(!buffer_uptodate(bh))) + ret = -EIO; +@@ -818,7 +795,7 @@ + __jbd2_journal_abort_hard(journal); + } + if (!err && !is_journal_aborted(journal)) ++ err = journal_wait_on_commit_record(cbh); +- err = journal_wait_on_commit_record(journal, cbh); + + if (err) + jbd2_journal_abort(journal, err); +reverted: +--- b/fs/jbd2/journal.c ++++ a/fs/jbd2/journal.c +@@ -430,7 +430,7 @@ + } + + /* ++ * Called under j_state_lock. Returns true if a transaction was started. +- * Called under j_state_lock. Returns true if a transaction commit was started. + */ + int __jbd2_log_start_commit(journal_t *journal, tid_t target) + { +@@ -498,8 +498,7 @@ + + /* + * Start a commit of the current running transaction (if any). Returns true ++ * if a transaction was started, and fills its tid in at *ptid +- * if a transaction is going to be committed (or is currently already +- * committing), and fills its tid in at *ptid + */ + int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid) + { +@@ -509,19 +508,15 @@ + if (journal->j_running_transaction) { + tid_t tid = journal->j_running_transaction->t_tid; + ++ ret = __jbd2_log_start_commit(journal, tid); ++ if (ret && ptid) +- __jbd2_log_start_commit(journal, tid); +- /* There's a running transaction and we've just made sure +- * it's commit has been scheduled. */ +- if (ptid) + *ptid = tid; ++ } else if (journal->j_committing_transaction && ptid) { +- ret = 1; +- } else if (journal->j_committing_transaction) { + /* + * If ext3_write_super() recently started a commit, then we + * have to wait for completion of that transaction + */ ++ *ptid = journal->j_committing_transaction->t_tid; +- if (ptid) +- *ptid = journal->j_committing_transaction->t_tid; + ret = 1; + } + spin_unlock(&journal->j_state_lock); +reverted: +--- b/fs/jbd2/revoke.c ++++ a/fs/jbd2/revoke.c +@@ -55,25 +55,6 @@ + * need do nothing. + * RevokeValid set, Revoked set: + * buffer has been revoked. +- * +- * Locking rules: +- * We keep two hash tables of revoke records. One hashtable belongs to the +- * running transaction (is pointed to by journal->j_revoke), the other one +- * belongs to the committing transaction. Accesses to the second hash table +- * happen only from the kjournald and no other thread touches this table. Also +- * journal_switch_revoke_table() which switches which hashtable belongs to the +- * running and which to the committing transaction is called only from +- * kjournald. Therefore we need no locks when accessing the hashtable belonging +- * to the committing transaction. +- * +- * All users operating on the hash table belonging to the running transaction +- * have a handle to the transaction. Therefore they are safe from kjournald +- * switching hash tables under them. For operations on the lists of entries in +- * the hash table j_revoke_lock is used. +- * +- * Finally, also replay code uses the hash tables but at this moment noone else +- * can touch them (filesystem isn't mounted yet) and hence no locking is +- * needed. + */ + + #ifndef __KERNEL__ +@@ -420,6 +401,8 @@ + * the second time we would still have a pending revoke to cancel. So, + * do not trust the Revoked bit on buffers unless RevokeValid is also + * set. ++ * ++ * The caller must have the journal locked. + */ + int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh) + { +@@ -497,7 +480,10 @@ + /* + * Write revoke records to the journal for all entries in the current + * revoke hash, deleting the entries as we go. ++ * ++ * Called with the journal lock held. + */ ++ + void jbd2_journal_write_revoke_records(journal_t *journal, + transaction_t *transaction) + { +reverted: +--- b/fs/jbd2/transaction.c ++++ a/fs/jbd2/transaction.c +@@ -2049,46 +2049,26 @@ + } + + /* ++ * This function must be called when inode is journaled in ordered mode ++ * before truncation happens. It starts writeout of truncated part in ++ * case it is in the committing transaction so that we stand to ordered ++ * mode consistency guarantees. +- * File truncate and transaction commit interact with each other in a +- * non-trivial way. If a transaction writing data block A is +- * committing, we cannot discard the data by truncate until we have +- * written them. Otherwise if we crashed after the transaction with +- * write has committed but before the transaction with truncate has +- * committed, we could see stale data in block A. This function is a +- * helper to solve this problem. It starts writeout of the truncated +- * part in case it is in the committing transaction. +- * +- * Filesystem code must call this function when inode is journaled in +- * ordered mode before truncation happens and after the inode has been +- * placed on orphan list with the new inode size. The second condition +- * avoids the race that someone writes new data and we start +- * committing the transaction after this function has been called but +- * before a transaction for truncate is started (and furthermore it +- * allows us to optimize the case where the addition to orphan list +- * happens in the same transaction as write --- we don't have to write +- * any data in such case). + */ ++int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode, +-int jbd2_journal_begin_ordered_truncate(journal_t *journal, +- struct jbd2_inode *jinode, + loff_t new_size) + { ++ journal_t *journal; ++ transaction_t *commit_trans; +- transaction_t *inode_trans, *commit_trans; + int ret = 0; + ++ if (!inode->i_transaction && !inode->i_next_transaction) +- /* This is a quick check to avoid locking if not necessary */ +- if (!jinode->i_transaction) + goto out; ++ journal = inode->i_transaction->t_journal; +- /* Locks are here just to force reading of recent values, it is +- * enough that the transaction was not committing before we started +- * a transaction adding the inode to orphan list */ + spin_lock(&journal->j_state_lock); + commit_trans = journal->j_committing_transaction; + spin_unlock(&journal->j_state_lock); ++ if (inode->i_transaction == commit_trans) { ++ ret = filemap_fdatawrite_range(inode->i_vfs_inode->i_mapping, +- spin_lock(&journal->j_list_lock); +- inode_trans = jinode->i_transaction; +- spin_unlock(&journal->j_list_lock); +- if (inode_trans == commit_trans) { +- ret = filemap_fdatawrite_range(jinode->i_vfs_inode->i_mapping, + new_size, LLONG_MAX); + if (ret) + jbd2_journal_abort(journal, ret); +reverted: +--- b/include/linux/jbd2.h ++++ a/include/linux/jbd2.h +@@ -308,8 +308,7 @@ + int val = (expr); \ + if (!val) { \ + printk(KERN_ERR \ ++ "EXT3-fs unexpected failure: %s;\n",# expr); \ +- "JBD2 unexpected failure: %s: %s;\n", \ +- __func__, #expr); \ + printk(KERN_ERR why "\n"); \ + } \ + val; \ +@@ -330,7 +329,6 @@ + BH_State, /* Pins most journal_head state */ + BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ + BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */ +- BH_JBDPrivateStart, /* First bit available for private use by FS */ + }; + + BUFFER_FNS(JBD, jbd) +@@ -1075,8 +1073,7 @@ + extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *); + extern int jbd2_journal_force_commit(journal_t *); + extern int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *inode); ++extern int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode, loff_t new_size); +-extern int jbd2_journal_begin_ordered_truncate(journal_t *journal, +- struct jbd2_inode *inode, loff_t new_size); + extern void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode); + extern void jbd2_journal_release_jbd_inode(journal_t *journal, struct jbd2_inode *jinode); + diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-correct-atmel-flash-part-handling.patch b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-correct-atmel-flash-part-handling.patch new file mode 100644 index 000000000..bd44f936d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-correct-atmel-flash-part-handling.patch @@ -0,0 +1,110 @@ +From 821b3996001508e872582dcafc7575021f122728 Mon Sep 17 00:00:00 2001 +From: Lalit Chandivade +Date: Fri, 24 Oct 2008 15:13:44 -0700 +Subject: revert - SCSI: qla2xxx: Correct Atmel flash-part handling. + +------------------- +This is a revert of this patch that is included in 2.6.27.7 +as a further qla2xxx driver update in the series conflicts with this + - gregkh +------------------- + +From: Lalit Chandivade + +commit 821b3996001508e872582dcafc7575021f122728 upstream. + +Use correct block size (4K) for erase command 0x20 for Atmel +Flash. Use dword addresses for determining sector boundary. + +Signed-off-by: Lalit Chandivade +Signed-off-by: Andrew Vasquez +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + +--- + drivers/scsi/qla2xxx/qla_def.h | 1 + + drivers/scsi/qla2xxx/qla_sup.c | 23 ++++++++++++++--------- + 2 files changed, 15 insertions(+), 9 deletions(-) + +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -2546,6 +2546,7 @@ typedef struct scsi_qla_host { + uint8_t fcode_revision[16]; + uint32_t fw_revision[4]; + ++ uint16_t fdt_odd_index; + uint32_t fdt_wrt_disable; + uint32_t fdt_erase_cmd; + uint32_t fdt_block_size; +--- a/drivers/scsi/qla2xxx/qla_sup.c ++++ b/drivers/scsi/qla2xxx/qla_sup.c +@@ -546,7 +546,6 @@ qla24xx_get_flash_manufacturer(scsi_qla_ + void + qla2xxx_get_flash_info(scsi_qla_host_t *ha) + { +-#define FLASH_BLK_SIZE_4K 0x1000 + #define FLASH_BLK_SIZE_32K 0x8000 + #define FLASH_BLK_SIZE_64K 0x10000 + uint16_t cnt, chksum; +@@ -578,6 +577,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t * + goto no_flash_data; + } + ++ ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; + ha->fdt_wrt_disable = fdt->wrt_disable_bits; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_block_size = le32_to_cpu(fdt->block_size); +@@ -590,10 +590,10 @@ qla2xxx_get_flash_info(scsi_qla_host_t * + } + + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " +- "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", ++ "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", + le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, + ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, +- ha->fdt_wrt_disable, ha->fdt_block_size)); ++ ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); + return; + + no_flash_data: +@@ -614,7 +614,8 @@ no_flash_data: + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + break; + case 0x1f: /* Atmel 26DF081A. */ +- ha->fdt_block_size = FLASH_BLK_SIZE_4K; ++ ha->fdt_odd_index = 1; ++ ha->fdt_block_size = FLASH_BLK_SIZE_64K; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); + ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); +@@ -626,9 +627,9 @@ no_flash_data: + } + + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " +- "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", man_id, flash_id, ++ "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, + ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, +- ha->fdt_unprotect_sec_cmd, ha->fdt_wrt_disable, ++ ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, + ha->fdt_block_size)); + } + +@@ -709,9 +710,13 @@ qla24xx_write_flash_data(scsi_qla_host_t + qla24xx_unprotect_flash(ha); + + for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { +- +- findex = faddr; +- fdata = (findex & sec_mask) << 2; ++ if (ha->fdt_odd_index) { ++ findex = faddr << 2; ++ fdata = findex & sec_mask; ++ } else { ++ findex = faddr; ++ fdata = (findex & sec_mask) << 2; ++ } + + /* Are we at the beginning of a sector? */ + if ((findex & rest_addr) == 0) { diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-do-not-honour-max_vports-from-firmware-for-2g-isps-and-below.patch b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-do-not-honour-max_vports-from-firmware-for-2g-isps-and-below.patch new file mode 100644 index 000000000..086081e78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-do-not-honour-max_vports-from-firmware-for-2g-isps-and-below.patch @@ -0,0 +1,58 @@ +From 680d7db88ace53c673e1c437c9b6abcc053e8d6f Mon Sep 17 00:00:00 2001 +From: Shyam Sundar +Date: Fri, 24 Oct 2008 15:13:46 -0700 +Subject: revert - SCSI: qla2xxx: Do not honour max_vports from firmware for 2G ISPs and below. + +------------------- +This is a revert of this patch that is included in 2.6.27.7 +as a further qla2xxx driver update in the series conflicts with this + - gregkh +------------------- + +From: Shyam Sundar + +commit 680d7db88ace53c673e1c437c9b6abcc053e8d6f upstream. + +For 23XX ISPs, max_vports may return an invalid value. +Do not honour it. + +Signed-off-by: Andrew Vasquez +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + +--- + drivers/scsi/qla2xxx/qla_init.c | 2 +- + drivers/scsi/qla2xxx/qla_mbx.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -974,6 +974,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) + &ha->fw_minor_version, + &ha->fw_subminor_version, + &ha->fw_attributes, &ha->fw_memory_size); ++ qla2x00_resize_request_q(ha); + ha->flags.npiv_supported = 0; + if ((IS_QLA24XX(ha) || IS_QLA25XX(ha) || + IS_QLA84XX(ha)) && +@@ -985,7 +986,6 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) + ha->max_npiv_vports = + MIN_MULTI_ID_FABRIC - 1; + } +- qla2x00_resize_request_q(ha); + + if (ql2xallocfwdump) + qla2x00_alloc_fw_dump(ha); +--- a/drivers/scsi/qla2xxx/qla_mbx.c ++++ b/drivers/scsi/qla2xxx/qla_mbx.c +@@ -1964,7 +1964,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_ + *cur_iocb_cnt = mcp->mb[7]; + if (orig_iocb_cnt) + *orig_iocb_cnt = mcp->mb[10]; +- if (ha->flags.npiv_supported && max_npiv_vports) ++ if (max_npiv_vports) + *max_npiv_vports = mcp->mb[11]; + } + diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-return-a-failed-status-when-abort-mailbox-command-fails.patch b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-return-a-failed-status-when-abort-mailbox-command-fails.patch new file mode 100644 index 000000000..dff1a58ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/revert-scsi-qla2xxx-return-a-failed-status-when-abort-mailbox-command-fails.patch @@ -0,0 +1,46 @@ +From 5bff55db3dc4d659f46b4d2fce2f61c1964c2762 Mon Sep 17 00:00:00 2001 +From: Michael Reed +Date: Fri, 24 Oct 2008 15:13:47 -0700 +Subject: revert - SCSI: qla2xxx: Return a FAILED status when abort mailbox-command fails. + +------------------- +This is a revert of this patch that is included in 2.6.27.7 +as a further qla2xxx driver update in the series conflicts with this + - gregkh +------------------- + +From: Michael Reed + +commit 5bff55db3dc4d659f46b4d2fce2f61c1964c2762 upstream. + +Mike Reed noted +(https://bugzilla.novell.com/show_bug.cgi?id=421330) that the +driver was incorrectly returning a SUCCESS status if the driver's +request to the firmware to abort a command failed. By doing so, +the mid-layer believed, incorrectly, that the command has +completed and has been returned (ultimately clearing +scsi_cmnd.request_buffer) yet the driver still has the command. +What should correctly happen is a mid-layer escalation +(device-reset, etc.) of recovery during which the driver will +eventually return the outstanding commands to the mid-layer. + +Signed-off-by: Andrew Vasquez +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + +--- + drivers/scsi/qla2xxx/qla_os.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -730,7 +730,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) + if (ha->isp_ops->abort_command(ha, sp)) { + DEBUG2(printk("%s(%ld): abort_command " + "mbx failed.\n", __func__, ha->host_no)); +- ret = FAILED; + } else { + DEBUG3(printk("%s(%ld): abort_command " + "mbx success.\n", __func__, ha->host_no)); diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/setup_APIC_timer-section-mismatch b/src/patches/suse-2.6.27.31/patches.kernel.org/setup_APIC_timer-section-mismatch new file mode 100644 index 000000000..b6befcabd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/setup_APIC_timer-section-mismatch @@ -0,0 +1,23 @@ +From: Jeff Mahoney +Subject: x86: Fix section conflict with kvm_setup_secondary_clock + + This patch marks kvm_setup_secondary_clock as __cpuinit to fix + section mismatch warnings. It calls setup_secondary_APIC_clock, which + is marked __cpuinit. + +Signed-off-by: Jeff Mahoney +--- + arch/x86/kernel/kvmclock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/kernel/kvmclock.c ++++ b/arch/x86/kernel/kvmclock.c +@@ -100,7 +100,7 @@ static int kvm_register_clock(char *txt) + } + + #ifdef CONFIG_X86_LOCAL_APIC +-static void kvm_setup_secondary_clock(void) ++static void __cpuinit kvm_setup_secondary_clock(void) + { + /* + * Now that the first cpu already had this clocksource initialized, diff --git a/src/patches/suse-2.6.27.31/patches.kernel.org/spu_profiler-include b/src/patches/suse-2.6.27.31/patches.kernel.org/spu_profiler-include new file mode 100644 index 000000000..5d92f6ce0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.kernel.org/spu_profiler-include @@ -0,0 +1,20 @@ +From: Jeff Mahoney +Subject: [PATCH] powerpc: spu_profiler build fix + + This fixes the following build failure: error: 'ppc_proc_freq' undeclared + +Signed-off-by: Jeff Mahoney +--- + arch/powerpc/oprofile/cell/spu_profiler.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/powerpc/oprofile/cell/spu_profiler.c ++++ b/arch/powerpc/oprofile/cell/spu_profiler.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include "pr_util.h" + + #define TRACE_ARRAY_SIZE 1024 diff --git a/src/patches/suse-2.6.27.31/patches.rpmify/buildhost b/src/patches/suse-2.6.27.31/patches.rpmify/buildhost new file mode 100644 index 000000000..d5b001dd7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.rpmify/buildhost @@ -0,0 +1,33 @@ +From: Andreas Gruenbacher +Subject: Hide the build hostname + +Instead of the real build host and user name, use "buildhost.suse.de" +and "geeko". + +Signed-off-by: Andreas Gruenbacher + + scripts/mkcompile_h | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +--- a/scripts/mkcompile_h ++++ b/scripts/mkcompile_h +@@ -60,16 +60,9 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\} + echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" + + echo \#define LINUX_COMPILE_TIME \"`date +%T`\" +- echo \#define LINUX_COMPILE_BY \"`whoami`\" +- echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\" +- +- if [ -x /bin/dnsdomainname ]; then +- echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\" +- elif [ -x /bin/domainname ]; then +- echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\" +- else +- echo \#define LINUX_COMPILE_DOMAIN +- fi ++ echo \#define LINUX_COMPILE_BY \"geeko\" ++ echo \#define LINUX_COMPILE_HOST \"buildhost\" ++ echo \#define LINUX_COMPILE_DOMAIN \"suse.de\" + + echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\" + ) > .tmpcompile diff --git a/src/patches/suse-2.6.27.31/patches.rpmify/firmware-path b/src/patches/suse-2.6.27.31/patches.rpmify/firmware-path new file mode 100644 index 000000000..3cdfbbb2d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.rpmify/firmware-path @@ -0,0 +1,25 @@ +From: Jeff Mahoney +Subject: [PATCH] firmware: Allow release-specific firmware dir + + Every kernel package trying to provide files under /lib/firmware runs + into problems really quickly with multiple kernels installed. + + This patch moves them to /lib/firmware/$KERNELRELEASE. udev v127's + firmware.sh looks there first before falling back to /lib/firmware. + +Signed-off-by: Jeff Mahoney +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Makefile ++++ b/Makefile +@@ -1037,7 +1037,7 @@ depend dep: + + # --------------------------------------------------------------------------- + # Firmware install +-INSTALL_FW_PATH=$(INSTALL_MOD_PATH)/lib/firmware ++INSTALL_FW_PATH=$(INSTALL_MOD_PATH)/lib/firmware/$(KERNELRELEASE) + export INSTALL_FW_PATH + + PHONY += firmware_install diff --git a/src/patches/suse-2.6.27.31/patches.rpmify/no-include-asm b/src/patches/suse-2.6.27.31/patches.rpmify/no-include-asm new file mode 100644 index 000000000..5fc1aa0cd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.rpmify/no-include-asm @@ -0,0 +1,33 @@ +From: Takashi Iwai +Subject: [PATCH] kbuild: correctly link include/asm in external builds +Patch-mainline: 2.6.27? + +Looking at this problem now, and found that it's likely a bug in the +upstream. The patch below should fix the creation of include2/asm +symlink, which resulted in build errors. + + +Takashi + +Signed-off-by: Takashi Iwai +--- + +--- + Makefile | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/Makefile ++++ b/Makefile +@@ -938,7 +938,11 @@ ifneq ($(KBUILD_SRC),) + fi; + $(Q)if [ ! -d include2 ]; then \ + mkdir -p include2; \ +- ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm; \ ++ if [ -d $(srctree)/arch/$(SRCARCH)/include/asm ]; then \ ++ ln -fsn $(srctree)/arch/$(SRCARCH)/include/asm include2/asm; \ ++ else \ ++ ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm; \ ++ fi; \ + fi + endif + diff --git a/src/patches/suse-2.6.27.31/patches.rpmify/rpm-kernel-config b/src/patches/suse-2.6.27.31/patches.rpmify/rpm-kernel-config new file mode 100644 index 000000000..87150efe9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.rpmify/rpm-kernel-config @@ -0,0 +1,25 @@ +From: Andreas Gruenbacher +Subject: Add the CONFIG_SUSE_KERNEL option + +CONFIG_SUSE_KERNEL is set automatically in our config files. It must +still be added in kconfig so that the option does not disappear +whenever the kernel is reconfigured (e.g., ``make oldconfig''). + +Signed-off-by: Andreas Gruenbacher + + init/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -101,6 +101,10 @@ config LOCALVERSION_AUTO + + which is done within the script "scripts/setlocalversion".) + ++config SUSE_KERNEL ++ bool ++ default y ++ + config SWAP + bool "Support for paging of anonymous memory (swap)" + depends on MMU && BLOCK diff --git a/src/patches/suse-2.6.27.31/patches.suse/8250-sysrq-ctrl_o.patch b/src/patches/suse-2.6.27.31/patches.suse/8250-sysrq-ctrl_o.patch new file mode 100644 index 000000000..e10d2b518 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/8250-sysrq-ctrl_o.patch @@ -0,0 +1,134 @@ +Subject: no sysrq on Cell QS21/QS22 serial console +From: olh@suse.de +References: 422987 - LTC47675, 96313 - LTC16841 + + +a POWER4 system in 'full-system-partition' mode has the console device +on ttyS0. But the user interface to the Linux system console may still +be on the hardware management console (HMC). If this is the case, there +is no way to send a break to trigger a sysrq. +Other setups do already use 'ctrl o' to trigger sysrq. This includes iSeries +virtual console on tty1 or hvc0, and pSeries LPAR console on hvc0 or hvsi0. + +This affects also Cell Blades QS2x. + +To limit the 'ctrl o' only to the affected systems, query the model property +in the device-tree. The patch makes the serial console not-eight-bit-clean. +Booting with 'console=ttyS0' will disable 'ctrl o', it is only enabled +with console autodetection. + +'ctrl o' is currently mapped to 'flush output', see 'stty -a' + +Signed-off-by: Olaf Hering +--- + arch/powerpc/include/asm/serial.h | 6 ++++ + arch/powerpc/kernel/legacy_serial.c | 52 ++++++++++++++++++++++++++++++++++++ + drivers/serial/8250.c | 6 ++++ + 3 files changed, 64 insertions(+) + +--- a/arch/powerpc/include/asm/serial.h ++++ b/arch/powerpc/include/asm/serial.h +@@ -15,6 +15,12 @@ + /* Default baud base if not found in device-tree */ + #define BASE_BAUD ( 1843200 / 16 ) + ++#if defined(SUPPORT_SYSRQ) && defined(CONFIG_PPC_PSERIES) ++#undef arch_8250_sysrq_via_ctrl_o ++extern int do_sysrq_via_ctrl_o; ++#define arch_8250_sysrq_via_ctrl_o(ch, port) ((ch) == '\x0f' && do_sysrq_via_ctrl_o && uart_handle_break((port))) ++#endif ++ + #ifdef CONFIG_PPC_UDBG_16550 + extern void find_legacy_serial_ports(void); + #else +--- a/arch/powerpc/kernel/legacy_serial.c ++++ b/arch/powerpc/kernel/legacy_serial.c +@@ -494,6 +494,55 @@ device_initcall(serial_dev_init); + + + #ifdef CONFIG_SERIAL_8250_CONSOLE ++#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_SERIAL_8250_CONSOLE) ++/* ++ * Handle the SysRq ^O Hack also via ttyS0 on POWER4 systems ++ * but only on the system console, see asm/serial.h ++ * If they run in FullSystemPartition mode, the firmware console comes in via ttyS0 ++ * But BREAK does not work via the HMC, to trigger sysrq. ++ * The same is required for Cell blades ++ */ ++int do_sysrq_via_ctrl_o; ++static const char __initdata *need_ctrl_o[] = { ++ "IBM,079", /* QS2x */ ++ "IBM,0792-32G", /* QS21 */ ++ "IBM,0793-2RZ", /* QS22 */ ++ "IBM,7040-681", /* p690 */ ++ "IBM,7040-671", /* p670 */ ++ "IBM,7039-651", /* p655 */ ++ "IBM,7038-6M2", /* p650 */ ++ "IBM,7028-6E4", /* p630 tower */ ++ "IBM,7028-6C4", /* p630 rack */ ++ "IBM,7029-6E3", /* p615 tower */ ++ "IBM,7029-6C3", /* p615 rack */ ++ NULL ++}; ++static void __init detect_need_for_ctrl_o(void) ++{ ++ struct device_node *root; ++ const char *model, *p; ++ int i; ++ ++ root = of_find_node_by_path("/"); ++ if (!root) ++ return; ++ model = of_get_property(root, "model", NULL); ++ if (model) { ++ i = 0; ++ while (need_ctrl_o[i]) { ++ p = need_ctrl_o[i]; ++ if (strncmp(p, model, strlen(p)) == 0) { ++ do_sysrq_via_ctrl_o = 1; ++ DBG("Enable sysrq via CTRL o on model %s\n", model); ++ break; ++ } ++ i++; ++ } ++ } ++ of_node_put(root); ++} ++#endif ++ + /* + * This is called very early, as part of console_init() (typically just after + * time_init()). This function is respondible for trying to find a good +@@ -562,6 +611,9 @@ static int __init check_legacy_serial_co + if (i >= legacy_serial_count) + goto not_found; + ++#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_SERIAL_8250_CONSOLE) ++ detect_need_for_ctrl_o(); ++#endif + of_node_put(prom_stdout); + + DBG("Found serial console at ttyS%d\n", offset); +--- a/drivers/serial/8250.c ++++ b/drivers/serial/8250.c +@@ -84,6 +84,8 @@ static unsigned int nr_uarts = CONFIG_SE + #define CONFIG_SERIAL_MANY_PORTS 1 + #endif + ++#define arch_8250_sysrq_via_ctrl_o(a,b) 0 ++ + /* + * HUB6 is always on. This will be removed once the header + * files have been cleaned. +@@ -1294,7 +1296,11 @@ receive_chars(struct uart_8250_port *up, + + do { + if (likely(lsr & UART_LSR_DR)) ++ { + ch = serial_inp(up, UART_RX); ++ if (arch_8250_sysrq_via_ctrl_o(ch, &up->port)) ++ goto ignore_char; ++ } + else + /* + * Intel 82571 has a Serial Over Lan device that will diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-01-mm-gfp-to-alloc_flags.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-01-mm-gfp-to-alloc_flags.patch new file mode 100644 index 000000000..606ed3075 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-01-mm-gfp-to-alloc_flags.patch @@ -0,0 +1,148 @@ +From: Peter Zijlstra +Subject: mm: gfp_to_alloc_flags() +Patch-mainline: No +References: FATE#303834 + +Clean up the code by factoring out the gfp to alloc_flags mapping. + +[neilb@suse.de says] +As the test: + +- if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) +- && !in_interrupt()) { +- if (!(gfp_mask & __GFP_NOMEMALLOC)) { + +has been replaced with a slightly weaker one: + ++ if (alloc_flags & ALLOC_NO_WATERMARKS) { + +we need to ensure we don't recurse when PF_MEMALLOC is set + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + mm/page_alloc.c | 87 ++++++++++++++++++++++++++++++++++---------------------- + 1 file changed, 54 insertions(+), 33 deletions(-) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1460,6 +1460,44 @@ try_next_zone: + } + + /* ++ * get the deepest reaching allocation flags for the given gfp_mask ++ */ ++static int gfp_to_alloc_flags(gfp_t gfp_mask) ++{ ++ struct task_struct *p = current; ++ int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET; ++ const gfp_t wait = gfp_mask & __GFP_WAIT; ++ ++ /* ++ * The caller may dip into page reserves a bit more if the caller ++ * cannot run direct reclaim, or if the caller has realtime scheduling ++ * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will ++ * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH). ++ */ ++ if (gfp_mask & __GFP_HIGH) ++ alloc_flags |= ALLOC_HIGH; ++ ++ if (!wait) { ++ alloc_flags |= ALLOC_HARDER; ++ /* ++ * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc. ++ * See also cpuset_zone_allowed() comment in kernel/cpuset.c. ++ */ ++ alloc_flags &= ~ALLOC_CPUSET; ++ } else if (unlikely(rt_task(p)) && !in_interrupt()) ++ alloc_flags |= ALLOC_HARDER; ++ ++ if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) { ++ if (!in_interrupt() && ++ ((p->flags & PF_MEMALLOC) || ++ unlikely(test_thread_flag(TIF_MEMDIE)))) ++ alloc_flags |= ALLOC_NO_WATERMARKS; ++ } ++ ++ return alloc_flags; ++} ++ ++/* + * This is the 'heart' of the zoned buddy allocator. + */ + struct page * +@@ -1517,49 +1555,28 @@ restart: + * OK, we're below the kswapd watermark and have kicked background + * reclaim. Now things get more complex, so set up alloc_flags according + * to how we want to proceed. +- * +- * The caller may dip into page reserves a bit more if the caller +- * cannot run direct reclaim, or if the caller has realtime scheduling +- * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will +- * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH). + */ +- alloc_flags = ALLOC_WMARK_MIN; +- if ((unlikely(rt_task(p)) && !in_interrupt()) || !wait) +- alloc_flags |= ALLOC_HARDER; +- if (gfp_mask & __GFP_HIGH) +- alloc_flags |= ALLOC_HIGH; +- if (wait) +- alloc_flags |= ALLOC_CPUSET; ++ alloc_flags = gfp_to_alloc_flags(gfp_mask); + +- /* +- * Go through the zonelist again. Let __GFP_HIGH and allocations +- * coming from realtime tasks go deeper into reserves. +- * +- * This is the last chance, in general, before the goto nopage. +- * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc. +- * See also cpuset_zone_allowed() comment in kernel/cpuset.c. +- */ ++ /* This is the last chance, in general, before the goto nopage. */ + page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist, +- high_zoneidx, alloc_flags); ++ high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS); + if (page) + goto got_pg; + + /* This allocation should allow future memory freeing. */ +- + rebalance: +- if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE))) +- && !in_interrupt()) { +- if (!(gfp_mask & __GFP_NOMEMALLOC)) { ++ if (alloc_flags & ALLOC_NO_WATERMARKS) { + nofail_alloc: +- /* go through the zonelist yet again, ignoring mins */ +- page = get_page_from_freelist(gfp_mask, nodemask, order, ++ /* go through the zonelist yet again, ignoring mins */ ++ page = get_page_from_freelist(gfp_mask, nodemask, order, + zonelist, high_zoneidx, ALLOC_NO_WATERMARKS); +- if (page) +- goto got_pg; +- if (gfp_mask & __GFP_NOFAIL) { +- congestion_wait(WRITE, HZ/50); +- goto nofail_alloc; +- } ++ if (page) ++ goto got_pg; ++ ++ if (wait && (gfp_mask & __GFP_NOFAIL)) { ++ congestion_wait(WRITE, HZ/50); ++ goto nofail_alloc; + } + goto nopage; + } +@@ -1568,6 +1585,10 @@ nofail_alloc: + if (!wait) + goto nopage; + ++ /* Avoid recursion of direct reclaim */ ++ if (p->flags & PF_MEMALLOC) ++ goto nopage; ++ + cond_resched(); + + /* We now go into synchronous reclaim */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-02-mm-setup_per_zone_pages_min.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-02-mm-setup_per_zone_pages_min.patch new file mode 100644 index 000000000..615b4afcc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-02-mm-setup_per_zone_pages_min.patch @@ -0,0 +1,68 @@ +From: Peter Zijlstra +Subject: mm: serialize access to min_free_kbytes +Patch-mainline: No +References: FATE#303834 + +There is a small race between the procfs caller and the memory hotplug caller +of setup_per_zone_pages_min(). Not a big deal, but the next patch will add yet +another caller. Time to close the gap. + +Signed-off-by: Peter Zijlstra +Reviewed-by: Pekka Enberg +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + mm/page_alloc.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -120,6 +120,7 @@ static char * const zone_names[MAX_NR_ZO + "Movable", + }; + ++static DEFINE_SPINLOCK(min_free_lock); + int min_free_kbytes = 1024; + + unsigned long __meminitdata nr_kernel_pages; +@@ -4265,12 +4266,12 @@ static void setup_per_zone_lowmem_reserv + } + + /** +- * setup_per_zone_pages_min - called when min_free_kbytes changes. ++ * __setup_per_zone_pages_min - called when min_free_kbytes changes. + * + * Ensures that the pages_{min,low,high} values for each zone are set correctly + * with respect to min_free_kbytes. + */ +-void setup_per_zone_pages_min(void) ++static void __setup_per_zone_pages_min(void) + { + unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10); + unsigned long lowmem_pages = 0; +@@ -4325,6 +4326,15 @@ void setup_per_zone_pages_min(void) + calculate_totalreserve_pages(); + } + ++void setup_per_zone_pages_min(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&min_free_lock, flags); ++ __setup_per_zone_pages_min(); ++ spin_unlock_irqrestore(&min_free_lock, flags); ++} ++ + /* + * Initialise min_free_kbytes. + * +@@ -4360,7 +4370,7 @@ static int __init init_per_zone_pages_mi + min_free_kbytes = 128; + if (min_free_kbytes > 65536) + min_free_kbytes = 65536; +- setup_per_zone_pages_min(); ++ __setup_per_zone_pages_min(); + setup_per_zone_lowmem_reserve(); + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-03-net-ipv6-route-cleanup.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-03-net-ipv6-route-cleanup.patch new file mode 100644 index 000000000..c84c5024c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-03-net-ipv6-route-cleanup.patch @@ -0,0 +1,59 @@ +From: Peter Zijlstra +Subject: net: ipv6: clean up ip6_route_net_init() error handling +Patch-mainline: No +References: FATE#303834 + +ip6_route_net_init() error handling looked less than solid, fix 'er up. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + net/ipv6/route.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +Index: linux-2.6.26/net/ipv6/route.c +=================================================================== +--- linux-2.6.26.orig/net/ipv6/route.c ++++ linux-2.6.26/net/ipv6/route.c +@@ -2611,10 +2611,8 @@ static int ip6_route_net_init(struct net + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, + sizeof(*net->ipv6.ip6_prohibit_entry), + GFP_KERNEL); +- if (!net->ipv6.ip6_prohibit_entry) { +- kfree(net->ipv6.ip6_null_entry); +- goto out; +- } ++ if (!net->ipv6.ip6_prohibit_entry) ++ goto out_ip6_null_entry; + net->ipv6.ip6_prohibit_entry->u.dst.path = + (struct dst_entry *)net->ipv6.ip6_prohibit_entry; + net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops; +@@ -2622,11 +2620,8 @@ static int ip6_route_net_init(struct net + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, + sizeof(*net->ipv6.ip6_blk_hole_entry), + GFP_KERNEL); +- if (!net->ipv6.ip6_blk_hole_entry) { +- kfree(net->ipv6.ip6_null_entry); +- kfree(net->ipv6.ip6_prohibit_entry); +- goto out; +- } ++ if (!net->ipv6.ip6_blk_hole_entry) ++ goto out_ip6_prohibit_entry; + net->ipv6.ip6_blk_hole_entry->u.dst.path = + (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; + net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops; +@@ -2642,6 +2637,12 @@ static int ip6_route_net_init(struct net + out: + return ret; + ++#ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_prohibit_entry: ++ kfree(net->ipv6.ip6_prohibit_entry); ++out_ip6_null_entry: ++ kfree(net->ipv6.ip6_null_entry); ++#endif + out_ip6_dst_ops: + release_net(net->ipv6.ip6_dst_ops->dst_net); + kfree(net->ipv6.ip6_dst_ops); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-04-net-ipv6-route-cleanup-sysctl.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-04-net-ipv6-route-cleanup-sysctl.patch new file mode 100644 index 000000000..1cbb21227 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-04-net-ipv6-route-cleanup-sysctl.patch @@ -0,0 +1,57 @@ +From: Peter Zijlstra +Subject: net: ipv6: initialize ip6_route sysctl vars in ip6_route_net_init() +Patch-mainline: No +References: FATE#303834 + +This makes that ip6_route_net_init() does all of the route init code. +There used to be a race between ip6_route_net_init() and ip6_net_init() +and someone relying on the combined result was left out cold. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + net/ipv6/af_inet6.c | 8 -------- + net/ipv6/route.c | 9 +++++++++ + 2 files changed, 9 insertions(+), 8 deletions(-) + +Index: linux-2.6.26/net/ipv6/af_inet6.c +=================================================================== +--- linux-2.6.26.orig/net/ipv6/af_inet6.c ++++ linux-2.6.26/net/ipv6/af_inet6.c +@@ -839,14 +839,6 @@ static int inet6_net_init(struct net *ne + int err = 0; + + net->ipv6.sysctl.bindv6only = 0; +- net->ipv6.sysctl.flush_delay = 0; +- net->ipv6.sysctl.ip6_rt_max_size = 4096; +- net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; +- net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; +- net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ; +- net->ipv6.sysctl.ip6_rt_gc_elasticity = 9; +- net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; +- net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; + net->ipv6.sysctl.icmpv6_time = 1*HZ; + + #ifdef CONFIG_PROC_FS +Index: linux-2.6.26/net/ipv6/route.c +=================================================================== +--- linux-2.6.26.orig/net/ipv6/route.c ++++ linux-2.6.26/net/ipv6/route.c +@@ -2627,6 +2627,15 @@ static int ip6_route_net_init(struct net + net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops; + #endif + ++ net->ipv6.sysctl.flush_delay = 0; ++ net->ipv6.sysctl.ip6_rt_max_size = 4096; ++ net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; ++ net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; ++ net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ; ++ net->ipv6.sysctl.ip6_rt_gc_elasticity = 9; ++ net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; ++ net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; ++ + #ifdef CONFIG_PROC_FS + proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); + proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-05-doc.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-05-doc.patch new file mode 100644 index 000000000..17d2bf4cc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-05-doc.patch @@ -0,0 +1,290 @@ +From: Neil Brown +Subject: swap over network documentation +Patch-mainline: No +References: FATE#303834 + +Document describing the problem and proposed solution + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + Documentation/network-swap.txt | 270 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 270 insertions(+) + +Index: linux-2.6.26/Documentation/network-swap.txt +=================================================================== +--- /dev/null ++++ linux-2.6.26/Documentation/network-swap.txt +@@ -0,0 +1,270 @@ ++ ++Problem: ++ When Linux needs to allocate memory it may find that there is ++ insufficient free memory so it needs to reclaim space that is in ++ use but not needed at the moment. There are several options: ++ ++ 1/ Shrink a kernel cache such as the inode or dentry cache. This ++ is fairly easy but provides limited returns. ++ 2/ Discard 'clean' pages from the page cache. This is easy, and ++ works well as long as there are clean pages in the page cache. ++ Similarly clean 'anonymous' pages can be discarded - if there ++ are any. ++ 3/ Write out some dirty page-cache pages so that they become clean. ++ The VM limits the number of dirty page-cache pages to e.g. 40% ++ of available memory so that (among other reasons) a "sync" will ++ not take excessively long. So there should never be excessive ++ amounts of dirty pagecache. ++ Writing out dirty page-cache pages involves work by the ++ filesystem which may need to allocate memory itself. To avoid ++ deadlock, filesystems use GFP_NOFS when allocating memory on the ++ write-out path. When this is used, cleaning dirty page-cache ++ pages is not an option so if the filesystem finds that memory ++ is tight, another option must be found. ++ 4/ Write out dirty anonymous pages to the "Swap" partition/file. ++ This is the most interesting for a couple of reasons. ++ a/ Unlike dirty page-cache pages, there is no need to write anon ++ pages out unless we are actually short of memory. Thus they ++ tend to be left to last. ++ b/ Anon pages tend to be updated randomly and unpredictably, and ++ flushing them out of memory can have a very significant ++ performance impact on the process using them. This contrasts ++ with page-cache pages which are often written sequentially ++ and often treated as "write-once, read-many". ++ So anon pages tend to be left until last to be cleaned, and may ++ be the only cleanable pages while there are still some dirty ++ page-cache pages (which are waiting on a GFP_NOFS allocation). ++ ++[I don't find the above wholly satisfying. There seems to be too much ++ hand-waving. If someone can provide better text explaining why ++ swapout is a special case, that would be great.] ++ ++So we need to be able to write to the swap file/partition without ++needing to allocate any memory ... or only a small well controlled ++amount. ++ ++The VM reserves a small amount of memory that can only be allocated ++for use as part of the swap-out procedure. It is only available to ++processes with the PF_MEMALLOC flag set, which is typically just the ++memory cleaner. ++ ++Traditionally swap-out is performed directly to block devices (swap ++files on block-device filesystems are supported by examining the ++mapping from file offset to device offset in advance, and then using ++the device offsets to write directly to the device). Block devices ++are (required to be) written to pre-allocate any memory that might be ++needed during write-out, and to block when the pre-allocated memory is ++exhausted and no other memory is available. They can be sure not to ++block forever as the pre-allocated memory will be returned as soon as ++the data it is being used for has been written out. The primary ++mechanism for pre-allocating memory is called "mempools". ++ ++This approach does not work for writing anonymous pages ++(i.e. swapping) over a network, using e.g NFS or NBD or iSCSI. ++ ++ ++The main reason that it does not work is that when data from an anon ++page is written to the network, we must wait for a reply to confirm ++the data is safe. Receiving that reply will consume memory and, ++significantly, we need to allocate memory to an incoming packet before ++we can tell if it is the reply we are waiting for or not. ++ ++The secondary reason is that the network code is not written to use ++mempools and in most cases does not need to use them. Changing all ++allocations in the networking layer to use mempools would be quite ++intrusive, and would waste memory, and probably cause a slow-down in ++the common case of not swapping over the network. ++ ++These problems are addressed by enhancing the system of memory ++reserves used by PF_MEMALLOC and requiring any in-kernel networking ++client that is used for swap-out to indicate which sockets are used ++for swapout so they can be handled specially in low memory situations. ++ ++There are several major parts to this enhancement: ++ ++1/ page->reserve, GFP_MEMALLOC ++ ++ To handle low memory conditions we need to know when those ++ conditions exist. Having a global "low on memory" flag seems easy, ++ but its implementation is problematic. Instead we make it possible ++ to tell if a recent memory allocation required use of the emergency ++ memory pool. ++ For pages returned by alloc_page, the new page->reserve flag ++ can be tested. If this is set, then a low memory condition was ++ current when the page was allocated, so the memory should be used ++ carefully. (Because low memory conditions are transient, this ++ state is kept in an overloaded member instead of in page flags, which ++ would suggest a more permanent state.) ++ ++ For memory allocated using slab/slub: If a page that is added to a ++ kmem_cache is found to have page->reserve set, then a s->reserve ++ flag is set for the whole kmem_cache. Further allocations will only ++ be returned from that page (or any other page in the cache) if they ++ are emergency allocation (i.e. PF_MEMALLOC or GFP_MEMALLOC is set). ++ Non-emergency allocations will block in alloc_page until a ++ non-reserve page is available. Once a non-reserve page has been ++ added to the cache, the s->reserve flag on the cache is removed. ++ ++ Because slab objects have no individual state its hard to pass ++ reserve state along, the current code relies on a regular alloc ++ failing. There are various allocation wrappers help here. ++ ++ This allows us to ++ a/ request use of the emergency pool when allocating memory ++ (GFP_MEMALLOC), and ++ b/ to find out if the emergency pool was used. ++ ++2/ SK_MEMALLOC, sk_buff->emergency. ++ ++ When memory from the reserve is used to store incoming network ++ packets, the memory must be freed (and the packet dropped) as soon ++ as we find out that the packet is not for a socket that is used for ++ swap-out. ++ To achieve this we have an ->emergency flag for skbs, and an ++ SK_MEMALLOC flag for sockets. ++ When memory is allocated for an skb, it is allocated with ++ GFP_MEMALLOC (if we are currently swapping over the network at ++ all). If a subsequent test shows that the emergency pool was used, ++ ->emergency is set. ++ When the skb is finally attached to its destination socket, the ++ SK_MEMALLOC flag on the socket is tested. If the skb has ++ ->emergency set, but the socket does not have SK_MEMALLOC set, then ++ the skb is immediately freed and the packet is dropped. ++ This ensures that reserve memory is never queued on a socket that is ++ not used for swapout. ++ ++ Similarly, if an skb is ever queued for delivery to user-space for ++ example by netfilter, the ->emergency flag is tested and the skb is ++ released if ->emergency is set. (so obviously the storage route may ++ not pass through a userspace helper, otherwise the packets will never ++ arrive and we'll deadlock) ++ ++ This ensures that memory from the emergency reserve can be used to ++ allow swapout to proceed, but will not get caught up in any other ++ network queue. ++ ++ ++3/ pages_emergency ++ ++ The above would be sufficient if the total memory below the lowest ++ memory watermark (i.e the size of the emergency reserve) were known ++ to be enough to hold all transient allocations needed for writeout. ++ I'm a little blurry on how big the current emergency pool is, but it ++ isn't big and certainly hasn't been sized to allow network traffic ++ to consume any. ++ ++ We could simply make the size of the reserve bigger. However in the ++ common case that we are not swapping over the network, that would be ++ a waste of memory. ++ ++ So a new "watermark" is defined: pages_emergency. This is ++ effectively added to the current low water marks, so that pages from ++ this emergency pool can only be allocated if one of PF_MEMALLOC or ++ GFP_MEMALLOC are set. ++ ++ pages_emergency can be changed dynamically based on need. When ++ swapout over the network is required, pages_emergency is increased ++ to cover the maximum expected load. When network swapout is ++ disabled, pages_emergency is decreased. ++ ++ To determine how much to increase it by, we introduce reservation ++ groups.... ++ ++3a/ reservation groups ++ ++ The memory used transiently for swapout can be in a number of ++ different places. e.g. the network route cache, the network ++ fragment cache, in transit between network card and socket, or (in ++ the case of NFS) in sunrpc data structures awaiting a reply. ++ We need to ensure each of these is limited in the amount of memory ++ they use, and that the maximum is included in the reserve. ++ ++ The memory required by the network layer only needs to be reserved ++ once, even if there are multiple swapout paths using the network ++ (e.g. NFS and NDB and iSCSI, though using all three for swapout at ++ the same time would be unusual). ++ ++ So we create a tree of reservation groups. The network might ++ register a collection of reservations, but not mark them as being in ++ use. NFS and sunrpc might similarly register a collection of ++ reservations, and attach it to the network reservations as it ++ depends on them. ++ When swapout over NFS is requested, the NFS/sunrpc reservations are ++ activated which implicitly activates the network reservations. ++ ++ The total new reservation is added to pages_emergency. ++ ++ Provided each memory usage stays beneath the registered limit (at ++ least when allocating memory from reserves), the system will never ++ run out of emergency memory, and swapout will not deadlock. ++ ++ It is worth noting here that it is not critical that each usage ++ stays beneath the limit 100% of the time. Occasional excess is ++ acceptable provided that the memory will be freed again within a ++ short amount of time that does *not* require waiting for any event ++ that itself might require memory. ++ This is because, at all stages of transmit and receive, it is ++ acceptable to discard all transient memory associated with a ++ particular writeout and try again later. On transmit, the page can ++ be re-queued for later transmission. On receive, the packet can be ++ dropped assuming that the peer will resend after a timeout. ++ ++ Thus allocations that are truly transient and will be freed without ++ blocking do not strictly need to be reserved for. Doing so might ++ still be a good idea to ensure forward progress doesn't take too ++ long. ++ ++4/ low-mem accounting ++ ++ Most places that might hold on to emergency memory (e.g. route ++ cache, fragment cache etc) already place a limit on the amount of ++ memory that they can use. This limit can simply be reserved using ++ the above mechanism and no more needs to be done. ++ ++ However some memory usage might not be accounted with sufficient ++ firmness to allow an appropriate emergency reservation. The ++ in-flight skbs for incoming packets is one such example. ++ ++ To support this, a low-overhead mechanism for accounting memory ++ usage against the reserves is provided. This mechanism uses the ++ same data structure that is used to store the emergency memory ++ reservations through the addition of a 'usage' field. ++ ++ Before we attempt allocation from the memory reserves, we much check ++ if the resulting 'usage' is below the reservation. If so, we increase ++ the usage and attempt the allocation (which should succeed). If ++ the projected 'usage' exceeds the reservation we'll either fail the ++ allocation, or wait for 'usage' to decrease enough so that it would ++ succeed, depending on __GFP_WAIT. ++ ++ When memory that was allocated for that purpose is freed, the ++ 'usage' field is checked again. If it is non-zero, then the size of ++ the freed memory is subtracted from the usage, making sure the usage ++ never becomes less than zero. ++ ++ This provides adequate accounting with minimal overheads when not in ++ a low memory condition. When a low memory condition is encountered ++ it does add the cost of a spin lock necessary to serialise updates ++ to 'usage'. ++ ++ ++ ++5/ swapon/swapoff/swap_out/swap_in ++ ++ So that a filesystem (e.g. NFS) can know when to set SK_MEMALLOC on ++ any network socket that it uses, and can know when to account ++ reserve memory carefully, new address_space_operations are ++ available. ++ "swapon" requests that an address space (i.e a file) be make ready ++ for swapout. swap_out and swap_in request the actual IO. They ++ together must ensure that each swap_out request can succeed without ++ allocating more emergency memory that was reserved by swapon. swapoff ++ is used to reverse the state changes caused by swapon when we disable ++ the swap file. ++ ++ ++Thanks for reading this far. I hope it made sense :-) ++ ++Neil Brown (with updates from Peter Zijlstra) ++ ++ diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-06-mm-gfp-to-alloc_flags-expose.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-06-mm-gfp-to-alloc_flags-expose.patch new file mode 100644 index 000000000..72d5678da --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-06-mm-gfp-to-alloc_flags-expose.patch @@ -0,0 +1,62 @@ +From: Peter Zijlstra +Subject: mm: expose gfp_to_alloc_flags() +Patch-mainline: No +References: FATE#303834 + +Expose the gfp to alloc_flags mapping, so we can use it in other parts +of the vm. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + mm/internal.h | 10 ++++++++++ + mm/page_alloc.c | 10 +--------- + 2 files changed, 11 insertions(+), 9 deletions(-) + +--- a/mm/internal.h ++++ b/mm/internal.h +@@ -93,6 +93,16 @@ static inline struct page *mem_map_next( + #define __paginginit __init + #endif + ++#define ALLOC_HARDER 0x01 /* try to alloc harder */ ++#define ALLOC_HIGH 0x02 /* __GFP_HIGH set */ ++#define ALLOC_WMARK_MIN 0x04 /* use pages_min watermark */ ++#define ALLOC_WMARK_LOW 0x08 /* use pages_low watermark */ ++#define ALLOC_WMARK_HIGH 0x10 /* use pages_high watermark */ ++#define ALLOC_NO_WATERMARKS 0x20 /* don't check watermarks at all */ ++#define ALLOC_CPUSET 0x40 /* check for correct cpuset */ ++ ++int gfp_to_alloc_flags(gfp_t gfp_mask); ++ + /* Memory initialisation debug and verification */ + enum mminit_level { + MMINIT_WARNING, +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1129,14 +1129,6 @@ failed: + return NULL; + } + +-#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */ +-#define ALLOC_WMARK_MIN 0x02 /* use pages_min watermark */ +-#define ALLOC_WMARK_LOW 0x04 /* use pages_low watermark */ +-#define ALLOC_WMARK_HIGH 0x08 /* use pages_high watermark */ +-#define ALLOC_HARDER 0x10 /* try to alloc harder */ +-#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */ +-#define ALLOC_CPUSET 0x40 /* check for correct cpuset */ +- + #ifdef CONFIG_FAIL_PAGE_ALLOC + + static struct fail_page_alloc_attr { +@@ -1463,7 +1455,7 @@ try_next_zone: + /* + * get the deepest reaching allocation flags for the given gfp_mask + */ +-static int gfp_to_alloc_flags(gfp_t gfp_mask) ++int gfp_to_alloc_flags(gfp_t gfp_mask) + { + struct task_struct *p = current; + int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET; diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-07-page_alloc-reserve.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-07-page_alloc-reserve.patch new file mode 100644 index 000000000..6b1915a78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-07-page_alloc-reserve.patch @@ -0,0 +1,46 @@ +From: Peter Zijlstra +Subject: mm: tag reseve pages +Patch-mainline: No +References: FATE#303834 + +Tag pages allocated from the reserves with a non-zero page->reserve. +This allows us to distinguish and account reserve pages. + +Since low-memory situations are transient, and unrelated the the actual +page (any page can be on the freelist when we run low), don't mark the +page in any permanent way - just pass along the information to the +allocatee. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/mm_types.h | 1 + + mm/page_alloc.c | 4 +++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -74,6 +74,7 @@ struct page { + union { + pgoff_t index; /* Our offset within mapping. */ + void *freelist; /* SLUB: freelist req. slab lock */ ++ int reserve; /* page_alloc: page is a reserve page */ + }; + struct list_head lru; /* Pageout list, eg. active_list + * protected by zone->lru_lock ! +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1430,8 +1430,10 @@ zonelist_scan: + } + + page = buffered_rmqueue(preferred_zone, zone, order, gfp_mask); +- if (page) ++ if (page) { ++ page->reserve = !!(alloc_flags & ALLOC_NO_WATERMARKS); + break; ++ } + this_zone_full: + if (NUMA_BUILD) + zlc_mark_zone_full(zonelist, z); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-08-reserve-slub.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-08-reserve-slub.patch new file mode 100644 index 000000000..45cc13c96 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-08-reserve-slub.patch @@ -0,0 +1,428 @@ +From: Peter Zijlstra +Subject: mm: sl[au]b: add knowledge of reserve pages +Patch-mainline: No +References: FATE#303834 + +Restrict objects from reserve slabs (ALLOC_NO_WATERMARKS) to allocation +contexts that are entitled to it. This is done to ensure reserve pages don't +leak out and get consumed. + +The basic pattern used for all # allocators is the following, for each active +slab page we store if it came from an emergency allocation. When we find it +did, make sure the current allocation context would have been able to allocate +page from the emergency reserves as well. In that case allow the allocation. If +not, force a new slab allocation. When that works the memory pressure has +lifted enough to allow this context to get an object, otherwise fail the +allocation. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/slub_def.h | 1 + mm/slab.c | 60 +++++++++++++++++++++++++++++++++++++++-------- + mm/slob.c | 16 +++++++++++- + mm/slub.c | 42 +++++++++++++++++++++++++++----- + 4 files changed, 102 insertions(+), 17 deletions(-) + +Index: linux-2.6.26/mm/slub.c +=================================================================== +--- linux-2.6.26.orig/mm/slub.c ++++ linux-2.6.26/mm/slub.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include "internal.h" + + /* + * Lock order: +@@ -1106,7 +1107,8 @@ static void setup_object(struct kmem_cac + s->ctor(object); + } + +-static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) ++static ++struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node, int *reserve) + { + struct page *page; + void *start; +@@ -1120,6 +1122,8 @@ static struct page *new_slab(struct kmem + if (!page) + goto out; + ++ *reserve = page->reserve; ++ + inc_slabs_node(s, page_to_nid(page), page->objects); + page->slab = s; + page->flags |= 1 << PG_slab; +@@ -1503,10 +1507,20 @@ static void *__slab_alloc(struct kmem_ca + { + void **object; + struct page *new; ++ int reserve; + + /* We handle __GFP_ZERO in the caller */ + gfpflags &= ~__GFP_ZERO; + ++ if (unlikely(c->reserve)) { ++ /* ++ * If the current slab is a reserve slab and the current ++ * allocation context does not allow access to the reserves we ++ * must force an allocation to test the current levels. ++ */ ++ if (!(gfp_to_alloc_flags(gfpflags) & ALLOC_NO_WATERMARKS)) ++ goto grow_slab; ++ } + if (!c->page) + goto new_slab; + +@@ -1520,8 +1534,8 @@ load_freelist: + object = c->page->freelist; + if (unlikely(!object)) + goto another_slab; +- if (unlikely(SLABDEBUG && PageSlubDebug(c->page))) +- goto debug; ++ if (unlikely(PageSlubDebug(c->page) || c->reserve)) ++ goto slow_path; + + c->freelist = object[c->offset]; + c->page->inuse = c->page->objects; +@@ -1543,16 +1557,18 @@ new_slab: + goto load_freelist; + } + ++grow_slab: + if (gfpflags & __GFP_WAIT) + local_irq_enable(); + +- new = new_slab(s, gfpflags, node); ++ new = new_slab(s, gfpflags, node, &reserve); + + if (gfpflags & __GFP_WAIT) + local_irq_disable(); + + if (new) { + c = get_cpu_slab(s, smp_processor_id()); ++ c->reserve = reserve; + stat(c, ALLOC_SLAB); + if (c->page) + flush_slab(s, c); +@@ -1562,10 +1578,21 @@ new_slab: + goto load_freelist; + } + return NULL; +-debug: +- if (!alloc_debug_processing(s, c->page, object, addr)) ++ ++slow_path: ++ if (PageSlubDebug(c->page) && ++ !alloc_debug_processing(s, c->page, object, addr)) + goto another_slab; + ++ /* ++ * Avoid the slub fast path in slab_alloc() by not setting ++ * c->freelist and the fast path in slab_free() by making ++ * node_match() fail by setting c->node to -1. ++ * ++ * We use this for for debug and reserve checks which need ++ * to be done for each allocation. ++ */ ++ + c->page->inuse++; + c->page->freelist = object[c->offset]; + c->node = -1; +@@ -2078,10 +2105,11 @@ static struct kmem_cache_node *early_kme + struct page *page; + struct kmem_cache_node *n; + unsigned long flags; ++ int reserve; + + BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node)); + +- page = new_slab(kmalloc_caches, gfpflags, node); ++ page = new_slab(kmalloc_caches, gfpflags, node, &reserve); + + BUG_ON(!page); + if (page_to_nid(page) != node) { +Index: linux-2.6.26/include/linux/slub_def.h +=================================================================== +--- linux-2.6.26.orig/include/linux/slub_def.h ++++ linux-2.6.26/include/linux/slub_def.h +@@ -38,6 +38,7 @@ struct kmem_cache_cpu { + int node; /* The node of the page (or -1 for debug) */ + unsigned int offset; /* Freepointer offset (in word units) */ + unsigned int objsize; /* Size of an object (from kmem_cache) */ ++ int reserve; /* Did the current page come from the reserve */ + #ifdef CONFIG_SLUB_STATS + unsigned stat[NR_SLUB_STAT_ITEMS]; + #endif +Index: linux-2.6.26/mm/slab.c +=================================================================== +--- linux-2.6.26.orig/mm/slab.c ++++ linux-2.6.26/mm/slab.c +@@ -116,6 +116,8 @@ + #include + #include + ++#include "internal.h" ++ + /* + * DEBUG - 1 for kmem_cache_create() to honour; SLAB_RED_ZONE & SLAB_POISON. + * 0 for faster, smaller code (especially in the critical paths). +@@ -264,7 +266,8 @@ struct array_cache { + unsigned int avail; + unsigned int limit; + unsigned int batchcount; +- unsigned int touched; ++ unsigned int touched:1, ++ reserve:1; + spinlock_t lock; + void *entry[]; /* + * Must have this definition in here for the proper +@@ -760,6 +763,27 @@ static inline struct array_cache *cpu_ca + return cachep->array[smp_processor_id()]; + } + ++/* ++ * If the last page came from the reserves, and the current allocation context ++ * does not have access to them, force an allocation to test the watermarks. ++ */ ++static inline int slab_force_alloc(struct kmem_cache *cachep, gfp_t flags) ++{ ++ if (unlikely(cpu_cache_get(cachep)->reserve) && ++ !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) ++ return 1; ++ ++ return 0; ++} ++ ++static inline void slab_set_reserve(struct kmem_cache *cachep, int reserve) ++{ ++ struct array_cache *ac = cpu_cache_get(cachep); ++ ++ if (unlikely(ac->reserve != reserve)) ++ ac->reserve = reserve; ++} ++ + static inline struct kmem_cache *__find_general_cachep(size_t size, + gfp_t gfpflags) + { +@@ -959,6 +983,7 @@ static struct array_cache *alloc_arrayca + nc->limit = entries; + nc->batchcount = batchcount; + nc->touched = 0; ++ nc->reserve = 0; + spin_lock_init(&nc->lock); + } + return nc; +@@ -1661,7 +1686,8 @@ __initcall(cpucache_init); + * did not request dmaable memory, we might get it, but that + * would be relatively rare and ignorable. + */ +-static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid) ++static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid, ++ int *reserve) + { + struct page *page; + int nr_pages; +@@ -1683,6 +1709,7 @@ static void *kmem_getpages(struct kmem_c + if (!page) + return NULL; + ++ *reserve = page->reserve; + nr_pages = (1 << cachep->gfporder); + if (cachep->flags & SLAB_RECLAIM_ACCOUNT) + add_zone_page_state(page_zone(page), +@@ -2103,6 +2130,7 @@ static int __init_refok setup_cpu_cache( + cpu_cache_get(cachep)->limit = BOOT_CPUCACHE_ENTRIES; + cpu_cache_get(cachep)->batchcount = 1; + cpu_cache_get(cachep)->touched = 0; ++ cpu_cache_get(cachep)->reserve = 0; + cachep->batchcount = 1; + cachep->limit = BOOT_CPUCACHE_ENTRIES; + return 0; +@@ -2757,6 +2785,7 @@ static int cache_grow(struct kmem_cache + size_t offset; + gfp_t local_flags; + struct kmem_list3 *l3; ++ int reserve; + + /* + * Be lazy and only check for valid flags here, keeping it out of the +@@ -2795,7 +2824,7 @@ static int cache_grow(struct kmem_cache + * 'nodeid'. + */ + if (!objp) +- objp = kmem_getpages(cachep, local_flags, nodeid); ++ objp = kmem_getpages(cachep, local_flags, nodeid, &reserve); + if (!objp) + goto failed; + +@@ -2812,6 +2841,7 @@ static int cache_grow(struct kmem_cache + if (local_flags & __GFP_WAIT) + local_irq_disable(); + check_irq_off(); ++ slab_set_reserve(cachep, reserve); + spin_lock(&l3->list_lock); + + /* Make slab active. */ +@@ -2946,7 +2976,8 @@ bad: + #define check_slabp(x,y) do { } while(0) + #endif + +-static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags) ++static void *cache_alloc_refill(struct kmem_cache *cachep, ++ gfp_t flags, int must_refill) + { + int batchcount; + struct kmem_list3 *l3; +@@ -2956,6 +2987,8 @@ static void *cache_alloc_refill(struct k + retry: + check_irq_off(); + node = numa_node_id(); ++ if (unlikely(must_refill)) ++ goto force_grow; + ac = cpu_cache_get(cachep); + batchcount = ac->batchcount; + if (!ac->touched && batchcount > BATCHREFILL_LIMIT) { +@@ -3023,11 +3056,14 @@ alloc_done: + + if (unlikely(!ac->avail)) { + int x; ++force_grow: + x = cache_grow(cachep, flags | GFP_THISNODE, node, NULL); + + /* cache_grow can reenable interrupts, then ac could change. */ + ac = cpu_cache_get(cachep); +- if (!x && ac->avail == 0) /* no objects in sight? abort */ ++ ++ /* no objects in sight? abort */ ++ if (!x && (ac->avail == 0 || must_refill)) + return NULL; + + if (!ac->avail) /* objects refilled by interrupt? */ +@@ -3182,17 +3218,18 @@ static inline void *____cache_alloc(stru + { + void *objp; + struct array_cache *ac; ++ int must_refill = slab_force_alloc(cachep, flags); + + check_irq_off(); + + ac = cpu_cache_get(cachep); +- if (likely(ac->avail)) { ++ if (likely(ac->avail && !must_refill)) { + STATS_INC_ALLOCHIT(cachep); + ac->touched = 1; + objp = ac->entry[--ac->avail]; + } else { + STATS_INC_ALLOCMISS(cachep); +- objp = cache_alloc_refill(cachep, flags); ++ objp = cache_alloc_refill(cachep, flags, must_refill); + } + return objp; + } +@@ -3236,7 +3273,7 @@ static void *fallback_alloc(struct kmem_ + struct zone *zone; + enum zone_type high_zoneidx = gfp_zone(flags); + void *obj = NULL; +- int nid; ++ int nid, reserve; + + if (flags & __GFP_THISNODE) + return NULL; +@@ -3272,10 +3309,11 @@ retry: + if (local_flags & __GFP_WAIT) + local_irq_enable(); + kmem_flagcheck(cache, flags); +- obj = kmem_getpages(cache, local_flags, -1); ++ obj = kmem_getpages(cache, local_flags, -1, &reserve); + if (local_flags & __GFP_WAIT) + local_irq_disable(); + if (obj) { ++ slab_set_reserve(cache, reserve); + /* + * Insert into the appropriate per node queues + */ +@@ -3314,6 +3352,9 @@ static void *____cache_alloc_node(struct + l3 = cachep->nodelists[nodeid]; + BUG_ON(!l3); + ++ if (unlikely(slab_force_alloc(cachep, flags))) ++ goto force_grow; ++ + retry: + check_irq_off(); + spin_lock(&l3->list_lock); +@@ -3351,6 +3392,7 @@ retry: + + must_grow: + spin_unlock(&l3->list_lock); ++force_grow: + x = cache_grow(cachep, flags | GFP_THISNODE, nodeid, NULL); + if (x) + goto retry; +Index: linux-2.6.26/mm/slob.c +=================================================================== +--- linux-2.6.26.orig/mm/slob.c ++++ linux-2.6.26/mm/slob.c +@@ -66,6 +66,7 @@ + #include + #include + #include ++#include "internal.h" + + /* + * slob_block has a field 'units', which indicates size of block if +ve, +@@ -183,6 +184,11 @@ struct slob_rcu { + static DEFINE_SPINLOCK(slob_lock); + + /* ++ * tracks the reserve state for the allocator. ++ */ ++static int slob_reserve; ++ ++/* + * Encode the given size and next info into a free slob block s. + */ + static void set_slob(slob_t *s, slobidx_t size, slob_t *next) +@@ -232,7 +238,7 @@ static int slob_last(slob_t *s) + + static void *slob_new_page(gfp_t gfp, int order, int node) + { +- void *page; ++ struct page *page; + + #ifdef CONFIG_NUMA + if (node != -1) +@@ -244,6 +250,8 @@ static void *slob_new_page(gfp_t gfp, in + if (!page) + return NULL; + ++ slob_reserve = page->reserve; ++ + return page_address(page); + } + +@@ -309,6 +317,11 @@ static void *slob_alloc(size_t size, gfp + slob_t *b = NULL; + unsigned long flags; + ++ if (unlikely(slob_reserve)) { ++ if (!(gfp_to_alloc_flags(gfp) & ALLOC_NO_WATERMARKS)) ++ goto grow; ++ } ++ + if (size < SLOB_BREAK1) + slob_list = &free_slob_small; + else if (size < SLOB_BREAK2) +@@ -347,6 +360,7 @@ static void *slob_alloc(size_t size, gfp + } + spin_unlock_irqrestore(&slob_lock, flags); + ++grow: + /* Not enough space: must allocate a new page */ + if (!b) { + b = slob_new_page(gfp & ~__GFP_ZERO, 0, node); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-09-mm-kmem_estimate_pages.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-09-mm-kmem_estimate_pages.patch new file mode 100644 index 000000000..0cb47c48a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-09-mm-kmem_estimate_pages.patch @@ -0,0 +1,303 @@ +From: Peter Zijlstra +Subject: mm: kmem_alloc_estimate() +Patch-mainline: No +References: FATE#303834 + +Provide a method to get the upper bound on the pages needed to allocate +a given number of objects from a given kmem_cache. + +This lays the foundation for a generic reserve framework as presented in +a later patch in this series. This framework needs to convert object demand +(kmalloc() bytes, kmem_cache_alloc() objects) to pages. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/slab.h | 4 ++ + mm/slab.c | 75 +++++++++++++++++++++++++++++++++++++++++++ + mm/slob.c | 67 +++++++++++++++++++++++++++++++++++++++ + mm/slub.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 233 insertions(+) + +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -65,6 +65,8 @@ void kmem_cache_free(struct kmem_cache * + unsigned int kmem_cache_size(struct kmem_cache *); + const char *kmem_cache_name(struct kmem_cache *); + int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr); ++unsigned kmem_alloc_estimate(struct kmem_cache *cachep, ++ gfp_t flags, int objects); + + /* + * Please use this macro to create slab caches. Simply specify the +@@ -100,6 +102,8 @@ void * __must_check __krealloc(const voi + void * __must_check krealloc(const void *, size_t, gfp_t); + void kfree(const void *); + size_t ksize(const void *); ++unsigned kmalloc_estimate_objs(size_t, gfp_t, int); ++unsigned kmalloc_estimate_bytes(gfp_t, size_t); + + /* + * Allocator specific definitions. These are mainly used to establish optimized +--- a/mm/slab.c ++++ b/mm/slab.c +@@ -3846,6 +3846,81 @@ const char *kmem_cache_name(struct kmem_ + EXPORT_SYMBOL_GPL(kmem_cache_name); + + /* ++ * Calculate the upper bound of pages required to sequentially allocate ++ * @objects objects from @cachep. ++ */ ++unsigned kmem_alloc_estimate(struct kmem_cache *cachep, ++ gfp_t flags, int objects) ++{ ++ /* ++ * (1) memory for objects, ++ */ ++ unsigned nr_slabs = DIV_ROUND_UP(objects, cachep->num); ++ unsigned nr_pages = nr_slabs << cachep->gfporder; ++ ++ /* ++ * (2) memory for each per-cpu queue (nr_cpu_ids), ++ * (3) memory for each per-node alien queues (nr_cpu_ids), and ++ * (4) some amount of memory for the slab management structures ++ * ++ * XXX: truely account these ++ */ ++ nr_pages += 1 + ilog2(nr_pages); ++ ++ return nr_pages; ++} ++ ++/* ++ * Calculate the upper bound of pages required to sequentially allocate ++ * @count objects of @size bytes from kmalloc given @flags. ++ */ ++unsigned kmalloc_estimate_objs(size_t size, gfp_t flags, int count) ++{ ++ struct kmem_cache *s = kmem_find_general_cachep(size, flags); ++ if (!s) ++ return 0; ++ ++ return kmem_alloc_estimate(s, flags, count); ++} ++EXPORT_SYMBOL_GPL(kmalloc_estimate_objs); ++ ++/* ++ * Calculate the upper bound of pages requires to sequentially allocate @bytes ++ * from kmalloc in an unspecified number of allocations of nonuniform size. ++ */ ++unsigned kmalloc_estimate_bytes(gfp_t flags, size_t bytes) ++{ ++ unsigned long pages; ++ struct cache_sizes *csizep = malloc_sizes; ++ ++ /* ++ * multiply by two, in order to account the worst case slack space ++ * due to the power-of-two allocation sizes. ++ */ ++ pages = DIV_ROUND_UP(2 * bytes, PAGE_SIZE); ++ ++ /* ++ * add the kmem_cache overhead of each possible kmalloc cache ++ */ ++ for (csizep = malloc_sizes; csizep->cs_cachep; csizep++) { ++ struct kmem_cache *s; ++ ++#ifdef CONFIG_ZONE_DMA ++ if (unlikely(flags & __GFP_DMA)) ++ s = csizep->cs_dmacachep; ++ else ++#endif ++ s = csizep->cs_cachep; ++ ++ if (s) ++ pages += kmem_alloc_estimate(s, flags, 0); ++ } ++ ++ return pages; ++} ++EXPORT_SYMBOL_GPL(kmalloc_estimate_bytes); ++ ++/* + * This initializes kmem_list3 or resizes various caches for all nodes. + */ + static int alloc_kmemlist(struct kmem_cache *cachep) +--- a/mm/slob.c ++++ b/mm/slob.c +@@ -661,3 +661,70 @@ void __init kmem_cache_init(void) + { + slob_ready = 1; + } ++ ++static __slob_estimate(unsigned size, unsigned align, unsigned objects) ++{ ++ unsigned nr_pages; ++ ++ size = SLOB_UNIT * SLOB_UNITS(size + align - 1); ++ ++ if (size <= PAGE_SIZE) { ++ nr_pages = DIV_ROUND_UP(objects, PAGE_SIZE / size); ++ } else { ++ nr_pages = objects << get_order(size); ++ } ++ ++ return nr_pages; ++} ++ ++/* ++ * Calculate the upper bound of pages required to sequentially allocate ++ * @objects objects from @cachep. ++ */ ++unsigned kmem_alloc_estimate(struct kmem_cache *c, gfp_t flags, int objects) ++{ ++ unsigned size = c->size; ++ ++ if (c->flags & SLAB_DESTROY_BY_RCU) ++ size += sizeof(struct slob_rcu); ++ ++ return __slob_estimate(size, c->align, objects); ++} ++ ++/* ++ * Calculate the upper bound of pages required to sequentially allocate ++ * @count objects of @size bytes from kmalloc given @flags. ++ */ ++unsigned kmalloc_estimate_objs(size_t size, gfp_t flags, int count) ++{ ++ unsigned align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); ++ ++ return __slob_estimate(size, align, count); ++} ++EXPORT_SYMBOL_GPL(kmalloc_estimate_objs); ++ ++/* ++ * Calculate the upper bound of pages requires to sequentially allocate @bytes ++ * from kmalloc in an unspecified number of allocations of nonuniform size. ++ */ ++unsigned kmalloc_estimate_bytes(gfp_t flags, size_t bytes) ++{ ++ unsigned long pages; ++ ++ /* ++ * Multiply by two, in order to account the worst case slack space ++ * due to the power-of-two allocation sizes. ++ * ++ * While not true for slob, it cannot do worse than that for sequential ++ * allocations. ++ */ ++ pages = DIV_ROUND_UP(2 * bytes, PAGE_SIZE); ++ ++ /* ++ * Our power of two series starts at PAGE_SIZE, so add one page. ++ */ ++ pages++; ++ ++ return pages; ++} ++EXPORT_SYMBOL_GPL(kmalloc_estimate_bytes); +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2399,6 +2399,42 @@ const char *kmem_cache_name(struct kmem_ + } + EXPORT_SYMBOL(kmem_cache_name); + ++/* ++ * Calculate the upper bound of pages required to sequentially allocate ++ * @objects objects from @cachep. ++ * ++ * We should use s->min_objects because those are the least efficient. ++ */ ++unsigned kmem_alloc_estimate(struct kmem_cache *s, gfp_t flags, int objects) ++{ ++ unsigned long pages; ++ struct kmem_cache_order_objects x; ++ ++ if (WARN_ON(!s) || WARN_ON(!oo_objects(s->min))) ++ return 0; ++ ++ x = s->min; ++ pages = DIV_ROUND_UP(objects, oo_objects(x)) << oo_order(x); ++ ++ /* ++ * Account the possible additional overhead if the slab holds more that ++ * one object. Use s->max_objects because that's the worst case. ++ */ ++ x = s->oo; ++ if (oo_objects(x) > 1) { ++ /* ++ * Account the possible additional overhead if per cpu slabs ++ * are currently empty and have to be allocated. This is very ++ * unlikely but a possible scenario immediately after ++ * kmem_cache_shrink. ++ */ ++ pages += num_possible_cpus() << oo_order(x); ++ } ++ ++ return pages; ++} ++EXPORT_SYMBOL_GPL(kmem_alloc_estimate); ++ + static void list_slab_objects(struct kmem_cache *s, struct page *page, + const char *text) + { +@@ -2778,6 +2814,57 @@ void kfree(const void *x) + EXPORT_SYMBOL(kfree); + + /* ++ * Calculate the upper bound of pages required to sequentially allocate ++ * @count objects of @size bytes from kmalloc given @flags. ++ */ ++unsigned kmalloc_estimate_objs(size_t size, gfp_t flags, int count) ++{ ++ struct kmem_cache *s = get_slab(size, flags); ++ if (!s) ++ return 0; ++ ++ return kmem_alloc_estimate(s, flags, count); ++ ++} ++EXPORT_SYMBOL_GPL(kmalloc_estimate_objs); ++ ++/* ++ * Calculate the upper bound of pages requires to sequentially allocate @bytes ++ * from kmalloc in an unspecified number of allocations of nonuniform size. ++ */ ++unsigned kmalloc_estimate_bytes(gfp_t flags, size_t bytes) ++{ ++ int i; ++ unsigned long pages; ++ ++ /* ++ * multiply by two, in order to account the worst case slack space ++ * due to the power-of-two allocation sizes. ++ */ ++ pages = DIV_ROUND_UP(2 * bytes, PAGE_SIZE); ++ ++ /* ++ * add the kmem_cache overhead of each possible kmalloc cache ++ */ ++ for (i = 1; i < PAGE_SHIFT; i++) { ++ struct kmem_cache *s; ++ ++#ifdef CONFIG_ZONE_DMA ++ if (unlikely(flags & SLUB_DMA)) ++ s = dma_kmalloc_cache(i, flags); ++ else ++#endif ++ s = &kmalloc_caches[i]; ++ ++ if (s) ++ pages += kmem_alloc_estimate(s, flags, 0); ++ } ++ ++ return pages; ++} ++EXPORT_SYMBOL_GPL(kmalloc_estimate_bytes); ++ ++/* + * kmem_cache_shrink removes empty slabs from the partial lists and sorts + * the remaining slabs by the number of items in use. The slabs with the + * most items in use come first. New allocations will then fill those up diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-10-mm-PF_MEMALLOC-softirq.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-10-mm-PF_MEMALLOC-softirq.patch new file mode 100644 index 000000000..b0e5b7f2b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-10-mm-PF_MEMALLOC-softirq.patch @@ -0,0 +1,86 @@ +From: Peter Zijlstra +Subject: mm: allow PF_MEMALLOC from softirq context +Patch-mainline: No +References: FATE#303834 + +This is needed to allow network softirq packet processing to make use of +PF_MEMALLOC. + +Currently softirq context cannot use PF_MEMALLOC due to it not being associated +with a task, and therefore not having task flags to fiddle with - thus the gfp +to alloc flag mapping ignores the task flags when in interrupts (hard or soft) +context. + +Allowing softirqs to make use of PF_MEMALLOC therefore requires some trickery. +We basically borrow the task flags from whatever process happens to be +preempted by the softirq. + +So we modify the gfp to alloc flags mapping to not exclude task flags in +softirq context, and modify the softirq code to save, clear and restore the +PF_MEMALLOC flag. + +The save and clear, ensures the preempted task's PF_MEMALLOC flag doesn't +leak into the softirq. The restore ensures a softirq's PF_MEMALLOC flag cannot +leak back into the preempted process. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/sched.h | 7 +++++++ + kernel/softirq.c | 3 +++ + mm/page_alloc.c | 7 ++++--- + 3 files changed, 14 insertions(+), 3 deletions(-) + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1555,6 +1555,13 @@ extern cputime_t task_gtime(struct task_ + #define tsk_used_math(p) ((p)->flags & PF_USED_MATH) + #define used_math() tsk_used_math(current) + ++static inline void tsk_restore_flags(struct task_struct *p, ++ unsigned long pflags, unsigned long mask) ++{ ++ p->flags &= ~mask; ++ p->flags |= pflags & mask; ++} ++ + #ifdef CONFIG_SMP + extern int set_cpus_allowed_ptr(struct task_struct *p, + const cpumask_t *new_mask); +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -188,6 +188,8 @@ asmlinkage void __do_softirq(void) + __u32 pending; + int max_restart = MAX_SOFTIRQ_RESTART; + int cpu; ++ unsigned long pflags = current->flags; ++ current->flags &= ~PF_MEMALLOC; + + pending = local_softirq_pending(); + account_system_vtime(current); +@@ -228,6 +230,7 @@ restart: + + account_system_vtime(current); + _local_bh_enable(); ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); + } + + #ifndef __ARCH_HAS_DO_SOFTIRQ +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1483,9 +1483,10 @@ int gfp_to_alloc_flags(gfp_t gfp_mask) + alloc_flags |= ALLOC_HARDER; + + if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) { +- if (!in_interrupt() && +- ((p->flags & PF_MEMALLOC) || +- unlikely(test_thread_flag(TIF_MEMDIE)))) ++ if (!in_irq() && (p->flags & PF_MEMALLOC)) ++ alloc_flags |= ALLOC_NO_WATERMARKS; ++ else if (!in_interrupt() && ++ unlikely(test_thread_flag(TIF_MEMDIE))) + alloc_flags |= ALLOC_NO_WATERMARKS; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-11-mm-page_alloc-emerg.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-11-mm-page_alloc-emerg.patch new file mode 100644 index 000000000..12ace2ea0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-11-mm-page_alloc-emerg.patch @@ -0,0 +1,226 @@ +From: Peter Zijlstra +Subject: mm: emergency pool +Patch-mainline: No +References: FATE#303834 + +Provide means to reserve a specific amount of pages. + +The emergency pool is separated from the min watermark because ALLOC_HARDER +and ALLOC_HIGH modify the watermark in a relative way and thus do not ensure +a strict minimum. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/mmzone.h | 6 ++- + mm/page_alloc.c | 86 ++++++++++++++++++++++++++++++++++++++++++------- + mm/vmstat.c | 6 +-- + 3 files changed, 83 insertions(+), 15 deletions(-) + +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -206,7 +206,10 @@ enum zone_type { + + struct zone { + /* Fields commonly accessed by the page allocator */ +- unsigned long pages_min, pages_low, pages_high; ++ unsigned long pages_high; /* we stop kswapd */ ++ unsigned long pages_low; /* we wake up kswapd */ ++ unsigned long pages_min; /* we enter direct reclaim */ ++ unsigned long pages_emerg; /* emergency pool */ + /* + * We don't know if the memory that we're going to allocate will be freeable + * or/and it will be released eventually, so to avoid totally wasting several +@@ -674,6 +677,7 @@ int sysctl_min_unmapped_ratio_sysctl_han + struct file *, void __user *, size_t *, loff_t *); + int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *, int, + struct file *, void __user *, size_t *, loff_t *); ++int adjust_memalloc_reserve(int pages); + + extern int numa_zonelist_order_handler(struct ctl_table *, int, + struct file *, void __user *, size_t *, loff_t *); +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -122,6 +122,8 @@ static char * const zone_names[MAX_NR_ZO + + static DEFINE_SPINLOCK(min_free_lock); + int min_free_kbytes = 1024; ++static DEFINE_MUTEX(var_free_mutex); ++int var_free_kbytes; + + unsigned long __meminitdata nr_kernel_pages; + unsigned long __meminitdata nr_all_pages; +@@ -1241,7 +1243,7 @@ int zone_watermark_ok(struct zone *z, in + if (alloc_flags & ALLOC_HARDER) + min -= min / 4; + +- if (free_pages <= min + z->lowmem_reserve[classzone_idx]) ++ if (free_pages <= min+z->lowmem_reserve[classzone_idx]+z->pages_emerg) + return 0; + for (o = 0; o < order; o++) { + /* At the next order, this order's pages become unavailable */ +@@ -1508,7 +1510,7 @@ __alloc_pages_internal(gfp_t gfp_mask, u + struct reclaim_state reclaim_state; + struct task_struct *p = current; + int do_retry; +- int alloc_flags; ++ int alloc_flags = 0; + unsigned long did_some_progress; + unsigned long pages_reclaimed = 0; + +@@ -1679,9 +1681,9 @@ nopage: + printk(KERN_INFO "everything is working fine. Allocations from irqs cannot be\n"); + printk(KERN_INFO "perfectly reliable and the kernel is designed to handle that.\n"); + } +- printk(KERN_INFO "%s: page allocation failure." +- " order:%d, mode:0x%x\n", +- p->comm, order, gfp_mask); ++ printk(KERN_WARNING "%s: page allocation failure." ++ " order:%d, mode:0x%x, alloc_flags:0x%x, pflags:0x%x\n", ++ p->comm, order, gfp_mask, alloc_flags, p->flags); + dump_stack(); + show_mem(); + } +@@ -1945,9 +1947,9 @@ void show_free_areas(void) + "\n", + zone->name, + K(zone_page_state(zone, NR_FREE_PAGES)), +- K(zone->pages_min), +- K(zone->pages_low), +- K(zone->pages_high), ++ K(zone->pages_emerg + zone->pages_min), ++ K(zone->pages_emerg + zone->pages_low), ++ K(zone->pages_emerg + zone->pages_high), + K(zone_page_state(zone, NR_ACTIVE)), + K(zone_page_state(zone, NR_INACTIVE)), + K(zone->present_pages), +@@ -4211,7 +4213,7 @@ static void calculate_totalreserve_pages + } + + /* we treat pages_high as reserved pages. */ +- max += zone->pages_high; ++ max += zone->pages_high + zone->pages_emerg; + + if (max > zone->present_pages) + max = zone->present_pages; +@@ -4268,7 +4270,8 @@ static void setup_per_zone_lowmem_reserv + */ + static void __setup_per_zone_pages_min(void) + { +- unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10); ++ unsigned pages_min = min_free_kbytes >> (PAGE_SHIFT - 10); ++ unsigned pages_emerg = var_free_kbytes >> (PAGE_SHIFT - 10); + unsigned long lowmem_pages = 0; + struct zone *zone; + unsigned long flags; +@@ -4280,11 +4283,13 @@ static void __setup_per_zone_pages_min(v + } + + for_each_zone(zone) { +- u64 tmp; ++ u64 tmp, tmp_emerg; + + spin_lock_irqsave(&zone->lock, flags); + tmp = (u64)pages_min * zone->present_pages; + do_div(tmp, lowmem_pages); ++ tmp_emerg = (u64)pages_emerg * zone->present_pages; ++ do_div(tmp_emerg, lowmem_pages); + if (is_highmem(zone)) { + /* + * __GFP_HIGH and PF_MEMALLOC allocations usually don't +@@ -4303,12 +4308,14 @@ static void __setup_per_zone_pages_min(v + if (min_pages > 128) + min_pages = 128; + zone->pages_min = min_pages; ++ zone->pages_emerg = 0; + } else { + /* + * If it's a lowmem zone, reserve a number of pages + * proportionate to the zone's size. + */ + zone->pages_min = tmp; ++ zone->pages_emerg = tmp_emerg; + } + + zone->pages_low = zone->pages_min + (tmp >> 2); +@@ -4330,6 +4337,63 @@ void setup_per_zone_pages_min(void) + spin_unlock_irqrestore(&min_free_lock, flags); + } + ++static void __adjust_memalloc_reserve(int pages) ++{ ++ var_free_kbytes += pages << (PAGE_SHIFT - 10); ++ BUG_ON(var_free_kbytes < 0); ++ setup_per_zone_pages_min(); ++} ++ ++static int test_reserve_limits(void) ++{ ++ struct zone *zone; ++ int node; ++ ++ for_each_zone(zone) ++ wakeup_kswapd(zone, 0); ++ ++ for_each_online_node(node) { ++ struct page *page = alloc_pages_node(node, GFP_KERNEL, 0); ++ if (!page) ++ return -ENOMEM; ++ ++ __free_page(page); ++ } ++ ++ return 0; ++} ++ ++/** ++ * adjust_memalloc_reserve - adjust the memalloc reserve ++ * @pages: number of pages to add ++ * ++ * It adds a number of pages to the memalloc reserve; if ++ * the number was positive it kicks reclaim into action to ++ * satisfy the higher watermarks. ++ * ++ * returns -ENOMEM when it failed to satisfy the watermarks. ++ */ ++int adjust_memalloc_reserve(int pages) ++{ ++ int err = 0; ++ ++ mutex_lock(&var_free_mutex); ++ __adjust_memalloc_reserve(pages); ++ if (pages > 0) { ++ err = test_reserve_limits(); ++ if (err) { ++ __adjust_memalloc_reserve(-pages); ++ goto unlock; ++ } ++ } ++ printk(KERN_DEBUG "Emergency reserve: %d\n", var_free_kbytes); ++ ++unlock: ++ mutex_unlock(&var_free_mutex); ++ return err; ++} ++EXPORT_SYMBOL_GPL(adjust_memalloc_reserve); ++ + /* + * Initialise min_free_kbytes. + * +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -692,9 +692,9 @@ static void zoneinfo_show_print(struct s + "\n spanned %lu" + "\n present %lu", + zone_page_state(zone, NR_FREE_PAGES), +- zone->pages_min, +- zone->pages_low, +- zone->pages_high, ++ zone->pages_emerg + zone->pages_min, ++ zone->pages_emerg + zone->pages_low, ++ zone->pages_emerg + zone->pages_high, + zone->pages_scanned, + zone->nr_scan_active, zone->nr_scan_inactive, + zone->spanned_pages, diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-12-global-ALLOC_NO_WATERMARKS.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-12-global-ALLOC_NO_WATERMARKS.patch new file mode 100644 index 000000000..ec5badbe0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-12-global-ALLOC_NO_WATERMARKS.patch @@ -0,0 +1,39 @@ +From: Peter Zijlstra +Subject: mm: system wide ALLOC_NO_WATERMARK +Patch-mainline: No +References: FATE#303834 + +The reserve is proportionally distributed over all (!highmem) zones in the +system. So we need to allow an emergency allocation access to all zones. In +order to do that we need to break out of any mempolicy boundaries we might +have. + +In my opinion that does not break mempolicies as those are user oriented +and not system oriented. That is, system allocations are not guaranteed to be +within mempolicy boundaries. For instance IRQs don't even have a mempolicy. + +So breaking out of mempolicy boundaries for 'rare' emergency allocations, +which are always system allocations (as opposed to user) is ok. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + mm/page_alloc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1566,6 +1566,11 @@ restart: + rebalance: + if (alloc_flags & ALLOC_NO_WATERMARKS) { + nofail_alloc: ++ /* ++ * break out of mempolicy boundaries ++ */ ++ zonelist = node_zonelist(numa_node_id(), gfp_mask); ++ + /* go through the zonelist yet again, ignoring mins */ + page = get_page_from_freelist(gfp_mask, nodemask, order, + zonelist, high_zoneidx, ALLOC_NO_WATERMARKS); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-13-mm-page_alloc-GFP_EMERGENCY.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-13-mm-page_alloc-GFP_EMERGENCY.patch new file mode 100644 index 000000000..a979f6013 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-13-mm-page_alloc-GFP_EMERGENCY.patch @@ -0,0 +1,52 @@ +From: Peter Zijlstra +Subject: mm: __GFP_MEMALLOC +Patch-mainline: No +References: FATE#303834 + +__GFP_MEMALLOC will allow the allocation to disregard the watermarks, +much like PF_MEMALLOC. + +It allows one to pass along the memalloc state in object related allocation +flags as opposed to task related flags, such as sk->sk_allocation. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/gfp.h | 3 ++- + mm/page_alloc.c | 4 +++- + 2 files changed, 5 insertions(+), 2 deletions(-) + +--- a/include/linux/gfp.h ++++ b/include/linux/gfp.h +@@ -43,6 +43,7 @@ struct vm_area_struct; + #define __GFP_REPEAT ((__force gfp_t)0x400u) /* See above */ + #define __GFP_NOFAIL ((__force gfp_t)0x800u) /* See above */ + #define __GFP_NORETRY ((__force gfp_t)0x1000u)/* See above */ ++#define __GFP_MEMALLOC ((__force gfp_t)0x2000u)/* Use emergency reserves */ + #define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */ + #define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */ + #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */ +@@ -88,7 +89,7 @@ struct vm_area_struct; + /* Control page allocator reclaim behavior */ + #define GFP_RECLAIM_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS|\ + __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\ +- __GFP_NORETRY|__GFP_NOMEMALLOC) ++ __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC) + + /* Control allocation constraints */ + #define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE) +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1485,7 +1485,9 @@ int gfp_to_alloc_flags(gfp_t gfp_mask) + alloc_flags |= ALLOC_HARDER; + + if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) { +- if (!in_irq() && (p->flags & PF_MEMALLOC)) ++ if (gfp_mask & __GFP_MEMALLOC) ++ alloc_flags |= ALLOC_NO_WATERMARKS; ++ else if (!in_irq() && (p->flags & PF_MEMALLOC)) + alloc_flags |= ALLOC_NO_WATERMARKS; + else if (!in_interrupt() && + unlikely(test_thread_flag(TIF_MEMDIE))) diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-14-mm-reserve.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-14-mm-reserve.patch new file mode 100644 index 000000000..2134c9065 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-14-mm-reserve.patch @@ -0,0 +1,944 @@ +From: Peter Zijlstra +Subject: mm: memory reserve management +Patch-mainline: No +References: FATE#303834 + +Generic reserve management code. + +It provides methods to reserve and charge. Upon this, generic alloc/free style +reserve pools could be build, which could fully replace mempool_t +functionality. + +It should also allow for a Banker's algorithm replacement of __GFP_NOFAIL. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/reserve.h | 198 ++++++++++++++ + include/linux/slab.h | 20 - + mm/Makefile | 2 + mm/reserve.c | 637 ++++++++++++++++++++++++++++++++++++++++++++++++ + mm/slub.c | 2 + 5 files changed, 848 insertions(+), 11 deletions(-) + +--- /dev/null ++++ b/include/linux/reserve.h +@@ -0,0 +1,198 @@ ++/* ++ * Memory reserve management. ++ * ++ * Copyright (C) 2007-2008 Red Hat, Inc., ++ * Peter Zijlstra ++ * ++ * This file contains the public data structure and API definitions. ++ */ ++ ++#ifndef _LINUX_RESERVE_H ++#define _LINUX_RESERVE_H ++ ++#include ++#include ++#include ++#include ++ ++struct mem_reserve { ++ struct mem_reserve *parent; ++ struct list_head children; ++ struct list_head siblings; ++ ++ const char *name; ++ ++ long pages; ++ long limit; ++ long usage; ++ spinlock_t lock; /* protects limit and usage */ ++ ++ wait_queue_head_t waitqueue; ++}; ++ ++extern struct mem_reserve mem_reserve_root; ++ ++void mem_reserve_init(struct mem_reserve *res, const char *name, ++ struct mem_reserve *parent); ++int mem_reserve_connect(struct mem_reserve *new_child, ++ struct mem_reserve *node); ++void mem_reserve_disconnect(struct mem_reserve *node); ++ ++int mem_reserve_pages_set(struct mem_reserve *res, long pages); ++int mem_reserve_pages_add(struct mem_reserve *res, long pages); ++int mem_reserve_pages_charge(struct mem_reserve *res, long pages); ++ ++int mem_reserve_kmalloc_set(struct mem_reserve *res, long bytes); ++int mem_reserve_kmalloc_charge(struct mem_reserve *res, long bytes); ++ ++struct kmem_cache; ++ ++int mem_reserve_kmem_cache_set(struct mem_reserve *res, ++ struct kmem_cache *s, ++ int objects); ++int mem_reserve_kmem_cache_charge(struct mem_reserve *res, ++ struct kmem_cache *s, long objs); ++ ++void *___kmalloc_reserve(size_t size, gfp_t flags, int node, void *ip, ++ struct mem_reserve *res, int *emerg); ++ ++static inline ++void *__kmalloc_reserve(size_t size, gfp_t flags, int node, void *ip, ++ struct mem_reserve *res, int *emerg) ++{ ++ void *obj; ++ ++ obj = __kmalloc_node_track_caller(size, ++ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, node, ip); ++ if (!obj) ++ obj = ___kmalloc_reserve(size, flags, node, ip, res, emerg); ++ ++ return obj; ++} ++ ++/** ++ * kmalloc_reserve() - kmalloc() and charge against @res for @emerg allocations ++ * @size - size of the requested memory region ++ * @gfp - allocation flags to use for this allocation ++ * @node - preferred memory node for this allocation ++ * @res - reserve to charge emergency allocations against ++ * @emerg - bit 0 is set when the allocation was an emergency allocation ++ * ++ * Returns NULL on failure ++ */ ++#define kmalloc_reserve(size, gfp, node, res, emerg) \ ++ __kmalloc_reserve(size, gfp, node, \ ++ __builtin_return_address(0), res, emerg) ++ ++void __kfree_reserve(void *obj, struct mem_reserve *res, int emerg); ++ ++/** ++ * kfree_reserve() - kfree() and uncharge against @res for @emerg allocations ++ * @obj - memory to free ++ * @res - reserve to uncharge emergency allocations from ++ * @emerg - was this an emergency allocation ++ */ ++static inline ++void kfree_reserve(void *obj, struct mem_reserve *res, int emerg) ++{ ++ if (unlikely(obj && res && emerg)) ++ __kfree_reserve(obj, res, emerg); ++ else ++ kfree(obj); ++} ++ ++void *__kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node, ++ struct mem_reserve *res, int *emerg); ++ ++/** ++ * kmem_cache_alloc_reserve() - kmem_cache_alloc() and charge against @res ++ * @s - kmem_cache to allocate from ++ * @gfp - allocation flags to use for this allocation ++ * @node - preferred memory node for this allocation ++ * @res - reserve to charge emergency allocations against ++ * @emerg - bit 0 is set when the allocation was an emergency allocation ++ * ++ * Returns NULL on failure ++ */ ++static inline ++void *kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node, ++ struct mem_reserve *res, int *emerg) ++{ ++ void *obj; ++ ++ obj = kmem_cache_alloc_node(s, ++ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, node); ++ if (!obj) ++ obj = __kmem_cache_alloc_reserve(s, flags, node, res, emerg); ++ ++ return obj; ++} ++ ++void __kmem_cache_free_reserve(struct kmem_cache *s, void *obj, ++ struct mem_reserve *res, int emerg); ++ ++/** ++ * kmem_cache_free_reserve() - kmem_cache_free() and uncharge against @res ++ * @s - kmem_cache to free to ++ * @obj - memory to free ++ * @res - reserve to uncharge emergency allocations from ++ * @emerg - was this an emergency allocation ++ */ ++static inline ++void kmem_cache_free_reserve(struct kmem_cache *s, void *obj, ++ struct mem_reserve *res, int emerg) ++{ ++ if (unlikely(obj && res && emerg)) ++ __kmem_cache_free_reserve(s, obj, res, emerg); ++ else ++ kmem_cache_free(s, obj); ++} ++ ++struct page *__alloc_pages_reserve(int node, gfp_t flags, int order, ++ struct mem_reserve *res, int *emerg); ++ ++/** ++ * alloc_pages_reserve() - alloc_pages() and charge against @res ++ * @node - preferred memory node for this allocation ++ * @gfp - allocation flags to use for this allocation ++ * @order - page order ++ * @res - reserve to charge emergency allocations against ++ * @emerg - bit 0 is set when the allocation was an emergency allocation ++ * ++ * Returns NULL on failure ++ */ ++static inline ++struct page *alloc_pages_reserve(int node, gfp_t flags, int order, ++ struct mem_reserve *res, int *emerg) ++{ ++ struct page *page; ++ ++ page = alloc_pages_node(node, ++ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, order); ++ if (!page) ++ page = __alloc_pages_reserve(node, flags, order, res, emerg); ++ ++ return page; ++} ++ ++void __free_pages_reserve(struct page *page, int order, ++ struct mem_reserve *res, int emerg); ++ ++/** ++ * free_pages_reserve() - __free_pages() and uncharge against @res ++ * @page - page to free ++ * @order - page order ++ * @res - reserve to uncharge emergency allocations from ++ * @emerg - was this an emergency allocation ++ */ ++static inline ++void free_pages_reserve(struct page *page, int order, ++ struct mem_reserve *res, int emerg) ++{ ++ if (unlikely(page && res && emerg)) ++ __free_pages_reserve(page, order, res, emerg); ++ else ++ __free_pages(page, order); ++} ++ ++#endif /* _LINUX_RESERVE_H */ +--- a/include/linux/slab.h ++++ b/include/linux/slab.h +@@ -230,13 +230,14 @@ static inline void *kmem_cache_alloc_nod + */ + #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) + extern void *__kmalloc_track_caller(size_t, gfp_t, void*); +-#define kmalloc_track_caller(size, flags) \ +- __kmalloc_track_caller(size, flags, __builtin_return_address(0)) + #else +-#define kmalloc_track_caller(size, flags) \ ++#define __kmalloc_track_caller(size, flags, ip) \ + __kmalloc(size, flags) + #endif /* DEBUG_SLAB */ + ++#define kmalloc_track_caller(size, flags) \ ++ __kmalloc_track_caller(size, flags, __builtin_return_address(0)) ++ + #ifdef CONFIG_NUMA + /* + * kmalloc_node_track_caller is a special version of kmalloc_node that +@@ -248,21 +249,22 @@ extern void *__kmalloc_track_caller(size + */ + #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) + extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *); +-#define kmalloc_node_track_caller(size, flags, node) \ +- __kmalloc_node_track_caller(size, flags, node, \ +- __builtin_return_address(0)) + #else +-#define kmalloc_node_track_caller(size, flags, node) \ ++#define __kmalloc_node_track_caller(size, flags, node, ip) \ + __kmalloc_node(size, flags, node) + #endif + + #else /* CONFIG_NUMA */ + +-#define kmalloc_node_track_caller(size, flags, node) \ +- kmalloc_track_caller(size, flags) ++#define __kmalloc_node_track_caller(size, flags, node, ip) \ ++ __kmalloc_track_caller(size, flags, ip) + + #endif /* DEBUG_SLAB */ + ++#define kmalloc_node_track_caller(size, flags, node) \ ++ __kmalloc_node_track_caller(size, flags, node, \ ++ __builtin_return_address(0)) ++ + /* + * Shortcuts + */ +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -11,7 +11,7 @@ obj-y := bootmem.o filemap.o mempool.o + maccess.o page_alloc.o page-writeback.o pdflush.o \ + readahead.o swap.o truncate.o vmscan.o \ + prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ +- page_isolation.o mm_init.o $(mmu-y) ++ page_isolation.o mm_init.o reserve.o $(mmu-y) + + obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o + obj-$(CONFIG_BOUNCE) += bounce.o +--- /dev/null ++++ b/mm/reserve.c +@@ -0,0 +1,637 @@ ++/* ++ * Memory reserve management. ++ * ++ * Copyright (C) 2007-2008, Red Hat, Inc., ++ * Peter Zijlstra ++ * ++ * Description: ++ * ++ * Manage a set of memory reserves. ++ * ++ * A memory reserve is a reserve for a specified number of object of specified ++ * size. Since memory is managed in pages, this reserve demand is then ++ * translated into a page unit. ++ * ++ * So each reserve has a specified object limit, an object usage count and a ++ * number of pages required to back these objects. ++ * ++ * Usage is charged against a reserve, if the charge fails, the resource must ++ * not be allocated/used. ++ * ++ * The reserves are managed in a tree, and the resource demands (pages and ++ * limit) are propagated up the tree. Obviously the object limit will be ++ * meaningless as soon as the unit starts mixing, but the required page reserve ++ * (being of one unit) is still valid at the root. ++ * ++ * It is the page demand of the root node that is used to set the global ++ * reserve (adjust_memalloc_reserve() which sets zone->pages_emerg). ++ * ++ * As long as a subtree has the same usage unit, an aggregate node can be used ++ * to charge against, instead of the leaf nodes. However, do be consistent with ++ * who is charged, resource usage is not propagated up the tree (for ++ * performance reasons). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "internal.h" ++ ++static DEFINE_MUTEX(mem_reserve_mutex); ++ ++/** ++ * @mem_reserve_root - the global reserve root ++ * ++ * The global reserve is empty, and has no limit unit, it merely ++ * acts as an aggregation point for reserves and an interface to ++ * adjust_memalloc_reserve(). ++ */ ++struct mem_reserve mem_reserve_root = { ++ .children = LIST_HEAD_INIT(mem_reserve_root.children), ++ .siblings = LIST_HEAD_INIT(mem_reserve_root.siblings), ++ .name = "total reserve", ++ .lock = __SPIN_LOCK_UNLOCKED(mem_reserve_root.lock), ++ .waitqueue = __WAIT_QUEUE_HEAD_INITIALIZER(mem_reserve_root.waitqueue), ++}; ++EXPORT_SYMBOL_GPL(mem_reserve_root); ++ ++/** ++ * mem_reserve_init() - initialize a memory reserve object ++ * @res - the new reserve object ++ * @name - a name for this reserve ++ * @parent - when non NULL, the parent to connect to. ++ */ ++void mem_reserve_init(struct mem_reserve *res, const char *name, ++ struct mem_reserve *parent) ++{ ++ memset(res, 0, sizeof(*res)); ++ INIT_LIST_HEAD(&res->children); ++ INIT_LIST_HEAD(&res->siblings); ++ res->name = name; ++ spin_lock_init(&res->lock); ++ init_waitqueue_head(&res->waitqueue); ++ ++ if (parent) ++ mem_reserve_connect(res, parent); ++} ++EXPORT_SYMBOL_GPL(mem_reserve_init); ++ ++/* ++ * propagate the pages and limit changes up the (sub)tree. ++ */ ++static void __calc_reserve(struct mem_reserve *res, long pages, long limit) ++{ ++ unsigned long flags; ++ ++ for ( ; res; res = res->parent) { ++ res->pages += pages; ++ ++ if (limit) { ++ spin_lock_irqsave(&res->lock, flags); ++ res->limit += limit; ++ spin_unlock_irqrestore(&res->lock, flags); ++ } ++ } ++} ++ ++/** ++ * __mem_reserve_add() - primitive to change the size of a reserve ++ * @res - reserve to change ++ * @pages - page delta ++ * @limit - usage limit delta ++ * ++ * Returns -ENOMEM when a size increase is not possible atm. ++ */ ++static int __mem_reserve_add(struct mem_reserve *res, long pages, long limit) ++{ ++ int ret = 0; ++ long reserve; ++ ++ /* ++ * This looks more complex than need be, that is because we handle ++ * the case where @res isn't actually connected to mem_reserve_root. ++ * ++ * So, by propagating the new pages up the (sub)tree and computing ++ * the difference in mem_reserve_root.pages we find if this action ++ * affects the actual reserve. ++ * ++ * The (partial) propagation also makes that mem_reserve_connect() ++ * needs only look at the direct child, since each disconnected ++ * sub-tree is fully up-to-date. ++ */ ++ reserve = mem_reserve_root.pages; ++ __calc_reserve(res, pages, 0); ++ reserve = mem_reserve_root.pages - reserve; ++ ++ if (reserve) { ++ ret = adjust_memalloc_reserve(reserve); ++ if (ret) ++ __calc_reserve(res, -pages, 0); ++ } ++ ++ /* ++ * Delay updating the limits until we've acquired the resources to ++ * back it. ++ */ ++ if (!ret) ++ __calc_reserve(res, 0, limit); ++ ++ return ret; ++} ++ ++/** ++ * __mem_reserve_charge() - primitive to charge object usage of a reserve ++ * @res - reserve to charge ++ * @charge - size of the charge ++ * ++ * Returns non-zero on success, zero on failure. ++ */ ++static ++int __mem_reserve_charge(struct mem_reserve *res, long charge) ++{ ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&res->lock, flags); ++ if (charge < 0 || res->usage + charge < res->limit) { ++ res->usage += charge; ++ if (unlikely(res->usage < 0)) ++ res->usage = 0; ++ ret = 1; ++ } ++ if (charge < 0) ++ wake_up_all(&res->waitqueue); ++ spin_unlock_irqrestore(&res->lock, flags); ++ ++ return ret; ++} ++ ++/** ++ * mem_reserve_connect() - connect a reserve to another in a child-parent relation ++ * @new_child - the reserve node to connect (child) ++ * @node - the reserve node to connect to (parent) ++ * ++ * Connecting a node results in an increase of the reserve by the amount of ++ * pages in @new_child->pages if @node has a connection to mem_reserve_root. ++ * ++ * Returns -ENOMEM when the new connection would increase the reserve (parent ++ * is connected to mem_reserve_root) and there is no memory to do so. ++ * ++ * On error, the child is _NOT_ connected. ++ */ ++int mem_reserve_connect(struct mem_reserve *new_child, struct mem_reserve *node) ++{ ++ int ret; ++ ++ WARN_ON(!new_child->name); ++ ++ mutex_lock(&mem_reserve_mutex); ++ if (new_child->parent) { ++ ret = -EEXIST; ++ goto unlock; ++ } ++ new_child->parent = node; ++ list_add(&new_child->siblings, &node->children); ++ ret = __mem_reserve_add(node, new_child->pages, new_child->limit); ++ if (ret) { ++ new_child->parent = NULL; ++ list_del_init(&new_child->siblings); ++ } ++unlock: ++ mutex_unlock(&mem_reserve_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mem_reserve_connect); ++ ++/** ++ * mem_reserve_disconnect() - sever a nodes connection to the reserve tree ++ * @node - the node to disconnect ++ * ++ * Disconnecting a node results in a reduction of the reserve by @node->pages ++ * if node had a connection to mem_reserve_root. ++ */ ++void mem_reserve_disconnect(struct mem_reserve *node) ++{ ++ int ret; ++ ++ BUG_ON(!node->parent); ++ ++ mutex_lock(&mem_reserve_mutex); ++ if (!node->parent) { ++ ret = -ENOENT; ++ goto unlock; ++ } ++ ret = __mem_reserve_add(node->parent, -node->pages, -node->limit); ++ if (!ret) { ++ node->parent = NULL; ++ list_del_init(&node->siblings); ++ } ++unlock: ++ mutex_unlock(&mem_reserve_mutex); ++ ++ /* ++ * We cannot fail to shrink the reserves, can we? ++ */ ++ WARN_ON(ret); ++} ++EXPORT_SYMBOL_GPL(mem_reserve_disconnect); ++ ++#ifdef CONFIG_PROC_FS ++ ++/* ++ * Simple output of the reserve tree in: /proc/reserve_info ++ * Example: ++ * ++ * localhost ~ # cat /proc/reserve_info ++ * 1:0 "total reserve" 6232K 0/278581 ++ * 2:1 "total network reserve" 6232K 0/278581 ++ * 3:2 "network TX reserve" 212K 0/53 ++ * 4:3 "protocol TX pages" 212K 0/53 ++ * 5:2 "network RX reserve" 6020K 0/278528 ++ * 6:5 "IPv4 route cache" 5508K 0/16384 ++ * 7:5 "SKB data reserve" 512K 0/262144 ++ * 8:7 "IPv4 fragment cache" 512K 0/262144 ++ */ ++ ++static void mem_reserve_show_item(struct seq_file *m, struct mem_reserve *res, ++ unsigned int parent, unsigned int *id) ++{ ++ struct mem_reserve *child; ++ unsigned int my_id = ++*id; ++ ++ seq_printf(m, "%d:%d \"%s\" %ldK %ld/%ld\n", ++ my_id, parent, res->name, ++ res->pages << (PAGE_SHIFT - 10), ++ res->usage, res->limit); ++ ++ list_for_each_entry(child, &res->children, siblings) ++ mem_reserve_show_item(m, child, my_id, id); ++} ++ ++static int mem_reserve_show(struct seq_file *m, void *v) ++{ ++ unsigned int ident = 0; ++ ++ mutex_lock(&mem_reserve_mutex); ++ mem_reserve_show_item(m, &mem_reserve_root, ident, &ident); ++ mutex_unlock(&mem_reserve_mutex); ++ ++ return 0; ++} ++ ++static int mem_reserve_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mem_reserve_show, NULL); ++} ++ ++static const struct file_operations mem_reserve_opterations = { ++ .open = mem_reserve_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static __init int mem_reserve_proc_init(void) ++{ ++ proc_create("reserve_info", S_IRUSR, NULL, &mem_reserve_opterations); ++ return 0; ++} ++ ++module_init(mem_reserve_proc_init); ++ ++#endif ++ ++/* ++ * alloc_page helpers ++ */ ++ ++/** ++ * mem_reserve_pages_set() - set reserves size in pages ++ * @res - reserve to set ++ * @pages - size in pages to set it to ++ * ++ * Returns -ENOMEM when it fails to set the reserve. On failure the old size ++ * is preserved. ++ */ ++int mem_reserve_pages_set(struct mem_reserve *res, long pages) ++{ ++ int ret; ++ ++ mutex_lock(&mem_reserve_mutex); ++ pages -= res->pages; ++ ret = __mem_reserve_add(res, pages, pages * PAGE_SIZE); ++ mutex_unlock(&mem_reserve_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mem_reserve_pages_set); ++ ++/** ++ * mem_reserve_pages_add() - change the size in a relative way ++ * @res - reserve to change ++ * @pages - number of pages to add (or subtract when negative) ++ * ++ * Similar to mem_reserve_pages_set, except that the argument is relative ++ * instead of absolute. ++ * ++ * Returns -ENOMEM when it fails to increase. ++ */ ++int mem_reserve_pages_add(struct mem_reserve *res, long pages) ++{ ++ int ret; ++ ++ mutex_lock(&mem_reserve_mutex); ++ ret = __mem_reserve_add(res, pages, pages * PAGE_SIZE); ++ mutex_unlock(&mem_reserve_mutex); ++ ++ return ret; ++} ++ ++/** ++ * mem_reserve_pages_charge() - charge page usage to a reserve ++ * @res - reserve to charge ++ * @pages - size to charge ++ * ++ * Returns non-zero on success. ++ */ ++int mem_reserve_pages_charge(struct mem_reserve *res, long pages) ++{ ++ return __mem_reserve_charge(res, pages * PAGE_SIZE); ++} ++EXPORT_SYMBOL_GPL(mem_reserve_pages_charge); ++ ++/* ++ * kmalloc helpers ++ */ ++ ++/** ++ * mem_reserve_kmalloc_set() - set this reserve to bytes worth of kmalloc ++ * @res - reserve to change ++ * @bytes - size in bytes to reserve ++ * ++ * Returns -ENOMEM on failure. ++ */ ++int mem_reserve_kmalloc_set(struct mem_reserve *res, long bytes) ++{ ++ int ret; ++ long pages; ++ ++ mutex_lock(&mem_reserve_mutex); ++ pages = kmalloc_estimate_bytes(GFP_ATOMIC, bytes); ++ pages -= res->pages; ++ bytes -= res->limit; ++ ret = __mem_reserve_add(res, pages, bytes); ++ mutex_unlock(&mem_reserve_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mem_reserve_kmalloc_set); ++ ++/** ++ * mem_reserve_kmalloc_charge() - charge bytes to a reserve ++ * @res - reserve to charge ++ * @bytes - bytes to charge ++ * ++ * Returns non-zero on success. ++ */ ++int mem_reserve_kmalloc_charge(struct mem_reserve *res, long bytes) ++{ ++ if (bytes < 0) ++ bytes = -roundup_pow_of_two(-bytes); ++ else ++ bytes = roundup_pow_of_two(bytes); ++ ++ return __mem_reserve_charge(res, bytes); ++} ++EXPORT_SYMBOL_GPL(mem_reserve_kmalloc_charge); ++ ++/* ++ * kmem_cache helpers ++ */ ++ ++/** ++ * mem_reserve_kmem_cache_set() - set reserve to @objects worth of kmem_cache_alloc of @s ++ * @res - reserve to set ++ * @s - kmem_cache to reserve from ++ * @objects - number of objects to reserve ++ * ++ * Returns -ENOMEM on failure. ++ */ ++int mem_reserve_kmem_cache_set(struct mem_reserve *res, struct kmem_cache *s, ++ int objects) ++{ ++ int ret; ++ long pages, bytes; ++ ++ mutex_lock(&mem_reserve_mutex); ++ pages = kmem_alloc_estimate(s, GFP_ATOMIC, objects); ++ pages -= res->pages; ++ bytes = objects * kmem_cache_size(s) - res->limit; ++ ret = __mem_reserve_add(res, pages, bytes); ++ mutex_unlock(&mem_reserve_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(mem_reserve_kmem_cache_set); ++ ++/** ++ * mem_reserve_kmem_cache_charge() - charge (or uncharge) usage of objs ++ * @res - reserve to charge ++ * @objs - objects to charge for ++ * ++ * Returns non-zero on success. ++ */ ++int mem_reserve_kmem_cache_charge(struct mem_reserve *res, struct kmem_cache *s, ++ long objs) ++{ ++ return __mem_reserve_charge(res, objs * kmem_cache_size(s)); ++} ++EXPORT_SYMBOL_GPL(mem_reserve_kmem_cache_charge); ++ ++/* ++ * Alloc wrappers. ++ * ++ * Actual usage is commented in linux/reserve.h where the interface functions ++ * live. Furthermore, the code is 3 instances of the same paradigm, hence only ++ * the first contains extensive comments. ++ */ ++ ++/* ++ * kmalloc/kfree ++ */ ++ ++void *___kmalloc_reserve(size_t size, gfp_t flags, int node, void *ip, ++ struct mem_reserve *res, int *emerg) ++{ ++ void *obj; ++ gfp_t gfp; ++ ++ /* ++ * Try a regular allocation, when that fails and we're not entitled ++ * to the reserves, fail. ++ */ ++ gfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN; ++ obj = __kmalloc_node_track_caller(size, gfp, node, ip); ++ ++ if (obj || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) ++ goto out; ++ ++ /* ++ * If we were given a reserve to charge against, try that. ++ */ ++ if (res && !mem_reserve_kmalloc_charge(res, size)) { ++ /* ++ * If we failed to charge and we're not allowed to wait for ++ * it to succeed, bail. ++ */ ++ if (!(flags & __GFP_WAIT)) ++ goto out; ++ ++ /* ++ * Wait for a successfull charge against the reserve. All ++ * uncharge operations against this reserve will wake us up. ++ */ ++ wait_event(res->waitqueue, ++ mem_reserve_kmalloc_charge(res, size)); ++ ++ /* ++ * After waiting for it, again try a regular allocation. ++ * Pressure could have lifted during our sleep. If this ++ * succeeds, uncharge the reserve. ++ */ ++ obj = __kmalloc_node_track_caller(size, gfp, node, ip); ++ if (obj) { ++ mem_reserve_kmalloc_charge(res, -size); ++ goto out; ++ } ++ } ++ ++ /* ++ * Regular allocation failed, and we've successfully charged our ++ * requested usage against the reserve. Do the emergency allocation. ++ */ ++ obj = __kmalloc_node_track_caller(size, flags, node, ip); ++ WARN_ON(!obj); ++ if (emerg) ++ *emerg = 1; ++ ++out: ++ return obj; ++} ++ ++void __kfree_reserve(void *obj, struct mem_reserve *res, int emerg) ++{ ++ /* ++ * ksize gives the full allocated size vs the requested size we used to ++ * charge; however since we round up to the nearest power of two, this ++ * should all work nicely. ++ */ ++ size_t size = ksize(obj); ++ ++ kfree(obj); ++ /* ++ * Free before uncharge, this ensures memory is actually present when ++ * a subsequent charge succeeds. ++ */ ++ mem_reserve_kmalloc_charge(res, -size); ++} ++ ++/* ++ * kmem_cache_alloc/kmem_cache_free ++ */ ++ ++void *__kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node, ++ struct mem_reserve *res, int *emerg) ++{ ++ void *obj; ++ gfp_t gfp; ++ ++ gfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN; ++ obj = kmem_cache_alloc_node(s, gfp, node); ++ ++ if (obj || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) ++ goto out; ++ ++ if (res && !mem_reserve_kmem_cache_charge(res, s, 1)) { ++ if (!(flags & __GFP_WAIT)) ++ goto out; ++ ++ wait_event(res->waitqueue, ++ mem_reserve_kmem_cache_charge(res, s, 1)); ++ ++ obj = kmem_cache_alloc_node(s, gfp, node); ++ if (obj) { ++ mem_reserve_kmem_cache_charge(res, s, -1); ++ goto out; ++ } ++ } ++ ++ obj = kmem_cache_alloc_node(s, flags, node); ++ WARN_ON(!obj); ++ if (emerg) ++ *emerg = 1; ++ ++out: ++ return obj; ++} ++ ++void __kmem_cache_free_reserve(struct kmem_cache *s, void *obj, ++ struct mem_reserve *res, int emerg) ++{ ++ kmem_cache_free(s, obj); ++ mem_reserve_kmem_cache_charge(res, s, -1); ++} ++ ++/* ++ * alloc_pages/free_pages ++ */ ++ ++struct page *__alloc_pages_reserve(int node, gfp_t flags, int order, ++ struct mem_reserve *res, int *emerg) ++{ ++ struct page *page; ++ gfp_t gfp; ++ long pages = 1 << order; ++ ++ gfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN; ++ page = alloc_pages_node(node, gfp, order); ++ ++ if (page || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) ++ goto out; ++ ++ if (res && !mem_reserve_pages_charge(res, pages)) { ++ if (!(flags & __GFP_WAIT)) ++ goto out; ++ ++ wait_event(res->waitqueue, ++ mem_reserve_pages_charge(res, pages)); ++ ++ page = alloc_pages_node(node, gfp, order); ++ if (page) { ++ mem_reserve_pages_charge(res, -pages); ++ goto out; ++ } ++ } ++ ++ page = alloc_pages_node(node, flags, order); ++ WARN_ON(!page); ++ if (emerg) ++ *emerg = 1; ++ ++out: ++ return page; ++} ++ ++void __free_pages_reserve(struct page *page, int order, ++ struct mem_reserve *res, int emerg) ++{ ++ __free_pages(page, order); ++ mem_reserve_pages_charge(res, -(1 << order)); ++} +--- a/mm/slub.c ++++ b/mm/slub.c +@@ -2728,6 +2728,7 @@ void *__kmalloc(size_t size, gfp_t flags + } + EXPORT_SYMBOL(__kmalloc); + ++#ifdef CONFIG_NUMA + static void *kmalloc_large_node(size_t size, gfp_t flags, int node) + { + struct page *page = alloc_pages_node(node, flags | __GFP_COMP, +@@ -2739,7 +2740,6 @@ static void *kmalloc_large_node(size_t s + return NULL; + } + +-#ifdef CONFIG_NUMA + void *__kmalloc_node(size_t size, gfp_t flags, int node) + { + struct kmem_cache *s; diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-15-mm-selinux-emergency.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-15-mm-selinux-emergency.patch new file mode 100644 index 000000000..410fe6ece --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-15-mm-selinux-emergency.patch @@ -0,0 +1,30 @@ +From: Peter Zijlstra +Subject: selinux: tag avc cache alloc as non-critical +Patch-mainline: No +References: FATE#303834 + +Failing to allocate a cache entry will only harm performance not correctness. +Do not consume valuable reserve pages for something like that. + +Signed-off-by: Peter Zijlstra +Acked-by: James Morris +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + security/selinux/avc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: linux-2.6.26/security/selinux/avc.c +=================================================================== +--- linux-2.6.26.orig/security/selinux/avc.c ++++ linux-2.6.26/security/selinux/avc.c +@@ -337,7 +337,7 @@ static struct avc_node *avc_alloc_node(v + { + struct avc_node *node; + +- node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC); ++ node = kmem_cache_zalloc(avc_node_cachep, GFP_ATOMIC|__GFP_NOMEMALLOC); + if (!node) + goto out; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-16-net-backlog.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-16-net-backlog.patch new file mode 100644 index 000000000..fd0b21867 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-16-net-backlog.patch @@ -0,0 +1,87 @@ +From: Peter Zijlstra +Subject: net: wrap sk->sk_backlog_rcv() +Patch-mainline: No +References: FATE#303834 + +Wrap calling sk->sk_backlog_rcv() in a function. This will allow extending the +generic sk_backlog_rcv behaviour. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/net/sock.h | 5 +++++ + include/net/tcp.h | 2 +- + net/core/sock.c | 4 ++-- + net/ipv4/tcp.c | 2 +- + net/ipv4/tcp_timer.c | 2 +- + 5 files changed, 10 insertions(+), 5 deletions(-) + +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -482,6 +482,11 @@ static inline void sk_add_backlog(struct + skb->next = NULL; + } + ++static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) ++{ ++ return sk->sk_backlog_rcv(sk, skb); ++} ++ + #define sk_wait_event(__sk, __timeo, __condition) \ + ({ int __rc; \ + release_sock(__sk); \ +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -894,7 +894,7 @@ static inline int tcp_prequeue(struct so + BUG_ON(sock_owned_by_user(sk)); + + while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { +- sk->sk_backlog_rcv(sk, skb1); ++ sk_backlog_rcv(sk, skb1); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED); + } + +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -324,7 +324,7 @@ int sk_receive_skb(struct sock *sk, stru + */ + mutex_acquire(&sk->sk_lock.dep_map, 0, 1, _RET_IP_); + +- rc = sk->sk_backlog_rcv(sk, skb); ++ rc = sk_backlog_rcv(sk, skb); + + mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); + } else +@@ -1372,7 +1372,7 @@ static void __release_sock(struct sock * + struct sk_buff *next = skb->next; + + skb->next = NULL; +- sk->sk_backlog_rcv(sk, skb); ++ sk_backlog_rcv(sk, skb); + + /* + * We are in process context here with softirqs +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -1165,7 +1165,7 @@ static void tcp_prequeue_process(struct + * necessary */ + local_bh_disable(); + while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) +- sk->sk_backlog_rcv(sk, skb); ++ sk_backlog_rcv(sk, skb); + local_bh_enable(); + + /* Clear memory counter. */ +--- a/net/ipv4/tcp_timer.c ++++ b/net/ipv4/tcp_timer.c +@@ -201,7 +201,7 @@ static void tcp_delack_timer(unsigned lo + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSCHEDULERFAILED); + + while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) +- sk->sk_backlog_rcv(sk, skb); ++ sk_backlog_rcv(sk, skb); + + tp->ucopy.memory = 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-17-net-ps_rx.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-17-net-ps_rx.patch new file mode 100644 index 000000000..05ca9534c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-17-net-ps_rx.patch @@ -0,0 +1,310 @@ +From: Peter Zijlstra +Subject: net: packet split receive api +Patch-mainline: No +References: FATE#303834, bnc#484306 + +Add some packet-split receive hooks. + +For one this allows to do NUMA node affine page allocs. Later on these hooks +will be extended to do emergency reserve allocations for fragments. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +bnx2.c part fixed by Jiri Bohac (bnc#484306) + + + +--- + drivers/net/bnx2.c | 9 +++------ + drivers/net/e1000/e1000_main.c | 8 ++------ + drivers/net/e1000e/netdev.c | 7 ++----- + drivers/net/igb/igb_main.c | 9 ++------- + drivers/net/ixgbe/ixgbe_main.c | 14 ++++++-------- + drivers/net/sky2.c | 16 ++++++---------- + include/linux/skbuff.h | 23 +++++++++++++++++++++++ + net/core/skbuff.c | 20 ++++++++++++++++++++ + 8 files changed, 64 insertions(+), 42 deletions(-) + +--- a/drivers/net/bnx2.c ++++ b/drivers/net/bnx2.c +@@ -2476,7 +2476,7 @@ bnx2_alloc_rx_page(struct bnx2 *bp, stru + struct sw_pg *rx_pg = &rxr->rx_pg_ring[index]; + struct rx_bd *rxbd = + &rxr->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)]; +- struct page *page = alloc_page(GFP_ATOMIC); ++ struct page *page = netdev_alloc_page(bp->dev); + + if (!page) + return -ENOMEM; +@@ -2501,7 +2501,7 @@ bnx2_free_rx_page(struct bnx2 *bp, struc + pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE, + PCI_DMA_FROMDEVICE); + +- __free_page(page); ++ netdev_free_page(bp->dev, page); + rx_pg->page = NULL; + } + +@@ -2819,7 +2819,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2 + if (i == pages - 1) + frag_len -= 4; + +- skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len); ++ skb_add_rx_frag(skb, i, rx_pg->page, 0, frag_len); + rx_pg->page = NULL; + + err = bnx2_alloc_rx_page(bp, rxr, +@@ -2833,9 +2833,6 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2 + } + + frag_size -= frag_len; +- skb->data_len += frag_len; +- skb->truesize += frag_len; +- skb->len += frag_len; + + pg_prod = NEXT_RX_BD(pg_prod); + pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons)); +--- a/drivers/net/e1000/e1000_main.c ++++ b/drivers/net/e1000/e1000_main.c +@@ -4349,12 +4349,8 @@ static bool e1000_clean_rx_irq_ps(struct + pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], + PAGE_SIZE, PCI_DMA_FROMDEVICE); + ps_page_dma->ps_page_dma[j] = 0; +- skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0, +- length); ++ skb_add_rx_frag(skb, j, ps_page->ps_page[j], 0, length); + ps_page->ps_page[j] = NULL; +- skb->len += length; +- skb->data_len += length; +- skb->truesize += length; + } + + /* strip the ethernet crc, problem is we're using pages now so +@@ -4553,7 +4549,7 @@ static void e1000_alloc_rx_buffers_ps(st + if (j < adapter->rx_ps_pages) { + if (likely(!ps_page->ps_page[j])) { + ps_page->ps_page[j] = +- alloc_page(GFP_ATOMIC); ++ netdev_alloc_page(netdev); + if (unlikely(!ps_page->ps_page[j])) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; +--- a/drivers/net/e1000e/netdev.c ++++ b/drivers/net/e1000e/netdev.c +@@ -258,7 +258,7 @@ static void e1000_alloc_rx_buffers_ps(st + continue; + } + if (!ps_page->page) { +- ps_page->page = alloc_page(GFP_ATOMIC); ++ ps_page->page = netdev_alloc_page(netdev); + if (!ps_page->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; +@@ -826,11 +826,8 @@ static bool e1000_clean_rx_irq_ps(struct + pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + ps_page->dma = 0; +- skb_fill_page_desc(skb, j, ps_page->page, 0, length); ++ skb_add_rx_frag(skb, j, ps_page->page, 0, length); + ps_page->page = NULL; +- skb->len += length; +- skb->data_len += length; +- skb->truesize += length; + } + + /* strip the ethernet crc, problem is we're using pages now so +--- a/drivers/net/igb/igb_main.c ++++ b/drivers/net/igb/igb_main.c +@@ -3885,7 +3885,7 @@ static bool igb_clean_rx_irq_adv(struct + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); + buffer_info->page_dma = 0; + +- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++, ++ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags++, + buffer_info->page, + buffer_info->page_offset, + length); +@@ -3895,11 +3895,6 @@ static bool igb_clean_rx_irq_adv(struct + buffer_info->page = NULL; + else + get_page(buffer_info->page); +- +- skb->len += length; +- skb->data_len += length; +- +- skb->truesize += length; + } + send_up: + i++; +@@ -3993,7 +3988,7 @@ static void igb_alloc_rx_buffers_adv(str + + if (adapter->rx_ps_hdr_size && !buffer_info->page_dma) { + if (!buffer_info->page) { +- buffer_info->page = alloc_page(GFP_ATOMIC); ++ buffer_info->page = netdev_alloc_page(netdev); + if (!buffer_info->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; +--- a/drivers/net/ixgbe/ixgbe_main.c ++++ b/drivers/net/ixgbe/ixgbe_main.c +@@ -480,6 +480,7 @@ static void ixgbe_alloc_rx_buffers(struc + int cleaned_count) + { + struct pci_dev *pdev = adapter->pdev; ++ struct net_device *netdev = adapter->netdev; + union ixgbe_adv_rx_desc *rx_desc; + struct ixgbe_rx_buffer *bi; + unsigned int i; +@@ -494,7 +495,7 @@ static void ixgbe_alloc_rx_buffers(struc + if (!bi->page_dma && + (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) { + if (!bi->page) { +- bi->page = alloc_page(GFP_ATOMIC); ++ bi->page = netdev_alloc_page(netdev); + if (!bi->page) { + adapter->alloc_rx_page_failed++; + goto no_buffers; +@@ -628,10 +629,10 @@ static bool ixgbe_clean_rx_irq(struct ix + pci_unmap_page(pdev, rx_buffer_info->page_dma, + PAGE_SIZE / 2, PCI_DMA_FROMDEVICE); + rx_buffer_info->page_dma = 0; +- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, +- rx_buffer_info->page, +- rx_buffer_info->page_offset, +- upper_len); ++ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, ++ rx_buffer_info->page, ++ rx_buffer_info->page_offset, ++ upper_len); + + if ((rx_ring->rx_buf_len > (PAGE_SIZE / 2)) || + (page_count(rx_buffer_info->page) != 1)) +@@ -639,9 +640,6 @@ static bool ixgbe_clean_rx_irq(struct ix + else + get_page(rx_buffer_info->page); + +- skb->len += upper_len; +- skb->data_len += upper_len; +- skb->truesize += upper_len; + } + + i++; +--- a/drivers/net/sky2.c ++++ b/drivers/net/sky2.c +@@ -1272,7 +1272,7 @@ static struct sk_buff *sky2_rx_alloc(str + } + + for (i = 0; i < sky2->rx_nfrags; i++) { +- struct page *page = alloc_page(GFP_ATOMIC); ++ struct page *page = netdev_alloc_page(sky2->netdev); + + if (!page) + goto free_partial; +@@ -2141,8 +2141,8 @@ static struct sk_buff *receive_copy(stru + } + + /* Adjust length of skb with fragments to match received data */ +-static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space, +- unsigned int length) ++static void skb_put_frags(struct sky2_port *sky2, struct sk_buff *skb, ++ unsigned int hdr_space, unsigned int length) + { + int i, num_frags; + unsigned int size; +@@ -2159,15 +2159,11 @@ static void skb_put_frags(struct sk_buff + + if (length == 0) { + /* don't need this page */ +- __free_page(frag->page); ++ netdev_free_page(sky2->netdev, frag->page); + --skb_shinfo(skb)->nr_frags; + } else { + size = min(length, (unsigned) PAGE_SIZE); +- +- frag->size = size; +- skb->data_len += size; +- skb->truesize += size; +- skb->len += size; ++ skb_add_rx_frag(skb, i, frag->page, 0, size); + length -= size; + } + } +@@ -2194,7 +2190,7 @@ static struct sk_buff *receive_new(struc + sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space); + + if (skb_shinfo(skb)->nr_frags) +- skb_put_frags(skb, hdr_space, length); ++ skb_put_frags(sky2, skb, hdr_space, length); + else + skb_put(skb, length); + return skb; +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -829,6 +829,9 @@ static inline void skb_fill_page_desc(st + skb_shinfo(skb)->nr_frags = i + 1; + } + ++extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, ++ int off, int size); ++ + #define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) + #define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list) + #define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) +@@ -1243,6 +1246,26 @@ static inline struct sk_buff *netdev_all + return __netdev_alloc_skb(dev, length, GFP_ATOMIC); + } + ++extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask); ++ ++/** ++ * netdev_alloc_page - allocate a page for ps-rx on a specific device ++ * @dev: network device to receive on ++ * ++ * Allocate a new page node local to the specified device. ++ * ++ * %NULL is returned if there is no free memory. ++ */ ++static inline struct page *netdev_alloc_page(struct net_device *dev) ++{ ++ return __netdev_alloc_page(dev, GFP_ATOMIC); ++} ++ ++static inline void netdev_free_page(struct net_device *dev, struct page *page) ++{ ++ __free_page(page); ++} ++ + /** + * skb_clone_writable - is the header of a clone writable + * @skb: buffer to check +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -259,6 +259,26 @@ struct sk_buff *__netdev_alloc_skb(struc + return skb; + } + ++struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask) ++{ ++ int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; ++ struct page *page; ++ ++ page = alloc_pages_node(node, gfp_mask, 0); ++ return page; ++} ++EXPORT_SYMBOL(__netdev_alloc_page); ++ ++void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, ++ int size) ++{ ++ skb_fill_page_desc(skb, i, page, off, size); ++ skb->len += size; ++ skb->data_len += size; ++ skb->truesize += size; ++} ++EXPORT_SYMBOL(skb_add_rx_frag); ++ + /** + * dev_alloc_skb - allocate an skbuff for receiving + * @length: length to allocate diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-18-net-sk_allocation.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-18-net-sk_allocation.patch new file mode 100644 index 000000000..ecea1dc4e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-18-net-sk_allocation.patch @@ -0,0 +1,161 @@ +From: Peter Zijlstra +Subject: net: sk_allocation() - concentrate socket related allocations +Patch-mainline: No +References: FATE#303834 + +Introduce sk_allocation(), this function allows to inject sock specific +flags to each sock related allocation. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/net/sock.h | 5 +++++ + net/ipv4/tcp.c | 3 ++- + net/ipv4/tcp_output.c | 12 +++++++----- + net/ipv6/tcp_ipv6.c | 17 ++++++++++++----- + 4 files changed, 26 insertions(+), 11 deletions(-) + +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -435,6 +435,11 @@ static inline int sock_flag(struct sock + return test_bit(flag, &sk->sk_flags); + } + ++static inline gfp_t sk_allocation(struct sock *sk, gfp_t gfp_mask) ++{ ++ return gfp_mask; ++} ++ + static inline void sk_acceptq_removed(struct sock *sk) + { + sk->sk_ack_backlog--; +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -643,7 +643,8 @@ struct sk_buff *sk_stream_alloc_skb(stru + /* The TCP header must be at least 32-bit aligned. */ + size = ALIGN(size, 4); + +- skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp); ++ skb = alloc_skb_fclone(size + sk->sk_prot->max_header, ++ sk_allocation(sk, gfp)); + if (skb) { + if (sk_wmem_schedule(sk, skb->truesize)) { + /* +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -2159,7 +2159,8 @@ void tcp_send_fin(struct sock *sk) + } else { + /* Socket is locked, keep trying until memory is available. */ + for (;;) { +- skb = alloc_skb_fclone(MAX_TCP_HEADER, GFP_KERNEL); ++ skb = alloc_skb_fclone(MAX_TCP_HEADER, ++ sk_allocation(sk, GFP_KERNEL)); + if (skb) + break; + yield(); +@@ -2185,7 +2186,7 @@ void tcp_send_active_reset(struct sock * + struct sk_buff *skb; + + /* NOTE: No TCP options attached and we never retransmit this. */ +- skb = alloc_skb(MAX_TCP_HEADER, priority); ++ skb = alloc_skb(MAX_TCP_HEADER, sk_allocation(sk, priority)); + if (!skb) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED); + return; +@@ -2254,7 +2255,8 @@ struct sk_buff *tcp_make_synack(struct s + __u8 *md5_hash_location; + int mss; + +- skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); ++ skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, ++ sk_allocation(sk, GFP_ATOMIC)); + if (skb == NULL) + return NULL; + +@@ -2500,7 +2502,7 @@ void tcp_send_ack(struct sock *sk) + * tcp_transmit_skb() will set the ownership to this + * sock. + */ +- buff = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ++ buff = alloc_skb(MAX_TCP_HEADER, sk_allocation(sk, GFP_ATOMIC)); + if (buff == NULL) { + inet_csk_schedule_ack(sk); + inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN; +@@ -2535,7 +2537,7 @@ static int tcp_xmit_probe_skb(struct soc + struct sk_buff *skb; + + /* We don't queue it, tcp_transmit_skb() sets ownership. */ +- skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ++ skb = alloc_skb(MAX_TCP_HEADER, sk_allocation(sk, GFP_ATOMIC)); + if (skb == NULL) + return -1; + +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -582,7 +582,8 @@ static int tcp_v6_md5_do_add(struct sock + } else { + /* reallocate new list if current one is full. */ + if (!tp->md5sig_info) { +- tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), GFP_ATOMIC); ++ tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), ++ sk_allocation(sk, GFP_ATOMIC)); + if (!tp->md5sig_info) { + kfree(newkey); + return -ENOMEM; +@@ -595,7 +596,8 @@ static int tcp_v6_md5_do_add(struct sock + } + if (tp->md5sig_info->alloced6 == tp->md5sig_info->entries6) { + keys = kmalloc((sizeof (tp->md5sig_info->keys6[0]) * +- (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); ++ (tp->md5sig_info->entries6 + 1)), ++ sk_allocation(sk, GFP_ATOMIC)); + + if (!keys) { + tcp_free_md5sig_pool(); +@@ -719,7 +721,8 @@ static int tcp_v6_parse_md5_keys (struct + struct tcp_sock *tp = tcp_sk(sk); + struct tcp_md5sig_info *p; + +- p = kzalloc(sizeof(struct tcp_md5sig_info), GFP_KERNEL); ++ p = kzalloc(sizeof(struct tcp_md5sig_info), ++ sk_allocation(sk, GFP_KERNEL)); + if (!p) + return -ENOMEM; + +@@ -952,6 +955,7 @@ static void tcp_v6_send_reset(struct soc + #ifdef CONFIG_TCP_MD5SIG + struct tcp_md5sig_key *key; + #endif ++ gfp_t gfp_mask = GFP_ATOMIC; + + if (th->rst) + return; +@@ -969,13 +973,16 @@ static void tcp_v6_send_reset(struct soc + tot_len += TCPOLEN_MD5SIG_ALIGNED; + #endif + ++ if (sk) ++ gfp_mask = sk_allocation(sk, gfp_mask); ++ + /* + * We need to grab some memory, and put together an RST, + * and then put it into the queue to be sent. + */ + + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, +- GFP_ATOMIC); ++ gfp_mask); + if (buff == NULL) + return; + +@@ -1063,7 +1070,7 @@ static void tcp_v6_send_ack(struct sk_bu + #endif + + buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, +- GFP_ATOMIC); ++ sk_allocation(ctl_sk, GFP_ATOMIC)); + if (buff == NULL) + return; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-19-netvm-reserve.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-19-netvm-reserve.patch new file mode 100644 index 000000000..372dfa081 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-19-netvm-reserve.patch @@ -0,0 +1,257 @@ +From: Peter Zijlstra +Subject: netvm: network reserve infrastructure +Patch-mainline: No +References: FATE#303834 + +Provide the basic infrastructure to reserve and charge/account network memory. + +We provide the following reserve tree: + +1) total network reserve +2) network TX reserve +3) protocol TX pages +4) network RX reserve +5) SKB data reserve + +[1] is used to make all the network reserves a single subtree, for easy +manipulation. + +[2] and [4] are merely for eastetic reasons. + +The TX pages reserve [3] is assumed bounded by it being the upper bound of +memory that can be used for sending pages (not quite true, but good enough) + +The SKB reserve [5] is an aggregate reserve, which is used to charge SKB data +against in the fallback path. + +The consumers for these reserves are sockets marked with: + SOCK_MEMALLOC + +Such sockets are to be used to service the VM (iow. to swap over). They +must be handled kernel side, exposing such a socket to user-space is a BUG. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/net/sock.h | 43 ++++++++++++++++++++- + net/Kconfig | 3 + + net/core/sock.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 152 insertions(+), 1 deletion(-) + +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -50,6 +50,7 @@ + #include /* struct sk_buff */ + #include + #include ++#include + + #include + +@@ -413,6 +414,7 @@ enum sock_flags { + SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */ + SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ + SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ ++ SOCK_MEMALLOC, /* the VM depends on us - make sure we're serviced */ + }; + + static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) +@@ -435,9 +437,48 @@ static inline int sock_flag(struct sock + return test_bit(flag, &sk->sk_flags); + } + ++static inline int sk_has_memalloc(struct sock *sk) ++{ ++ return sock_flag(sk, SOCK_MEMALLOC); ++} ++ ++extern struct mem_reserve net_rx_reserve; ++extern struct mem_reserve net_skb_reserve; ++ ++#ifdef CONFIG_NETVM ++/* ++ * Guestimate the per request queue TX upper bound. ++ * ++ * Max packet size is 64k, and we need to reserve that much since the data ++ * might need to bounce it. Double it to be on the safe side. ++ */ ++#define TX_RESERVE_PAGES DIV_ROUND_UP(2*65536, PAGE_SIZE) ++ ++extern int memalloc_socks; ++ ++static inline int sk_memalloc_socks(void) ++{ ++ return memalloc_socks; ++} ++ ++extern int sk_adjust_memalloc(int socks, long tx_reserve_pages); ++extern int sk_set_memalloc(struct sock *sk); ++extern int sk_clear_memalloc(struct sock *sk); ++#else ++static inline int sk_memalloc_socks(void) ++{ ++ return 0; ++} ++ ++static inline int sk_clear_memalloc(struct sock *sk) ++{ ++ return 0; ++} ++#endif ++ + static inline gfp_t sk_allocation(struct sock *sk, gfp_t gfp_mask) + { +- return gfp_mask; ++ return gfp_mask | (sk->sk_allocation & __GFP_MEMALLOC); + } + + static inline void sk_acceptq_removed(struct sock *sk) +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -110,6 +110,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -211,6 +212,105 @@ __u32 sysctl_rmem_default __read_mostly + /* Maximal space eaten by iovec or ancilliary data plus some space */ + int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); + ++static struct mem_reserve net_reserve; ++struct mem_reserve net_rx_reserve; ++EXPORT_SYMBOL_GPL(net_rx_reserve); /* modular ipv6 only */ ++struct mem_reserve net_skb_reserve; ++EXPORT_SYMBOL_GPL(net_skb_reserve); /* modular ipv6 only */ ++static struct mem_reserve net_tx_reserve; ++static struct mem_reserve net_tx_pages; ++ ++#ifdef CONFIG_NETVM ++static DEFINE_MUTEX(memalloc_socks_lock); ++int memalloc_socks; ++ ++/** ++ * sk_adjust_memalloc - adjust the global memalloc reserve for critical RX ++ * @socks: number of new %SOCK_MEMALLOC sockets ++ * @tx_resserve_pages: number of pages to (un)reserve for TX ++ * ++ * This function adjusts the memalloc reserve based on system demand. ++ * The RX reserve is a limit, and only added once, not for each socket. ++ * ++ * NOTE: ++ * @tx_reserve_pages is an upper-bound of memory used for TX hence ++ * we need not account the pages like we do for RX pages. ++ */ ++int sk_adjust_memalloc(int socks, long tx_reserve_pages) ++{ ++ int err; ++ ++ mutex_lock(&memalloc_socks_lock); ++ err = mem_reserve_pages_add(&net_tx_pages, tx_reserve_pages); ++ if (err) ++ goto unlock; ++ ++ /* ++ * either socks is positive and we need to check for 0 -> !0 ++ * transition and connect the reserve tree when we observe it. ++ */ ++ if (!memalloc_socks && socks > 0) { ++ err = mem_reserve_connect(&net_reserve, &mem_reserve_root); ++ if (err) { ++ /* ++ * if we failed to connect the tree, undo the tx ++ * reserve so that failure has no side effects. ++ */ ++ mem_reserve_pages_add(&net_tx_pages, -tx_reserve_pages); ++ goto unlock; ++ } ++ } ++ memalloc_socks += socks; ++ /* ++ * or socks is negative and we must observe the !0 -> 0 transition ++ * and disconnect the reserve tree. ++ */ ++ if (!memalloc_socks && socks) ++ mem_reserve_disconnect(&net_reserve); ++ ++unlock: ++ mutex_unlock(&memalloc_socks_lock); ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(sk_adjust_memalloc); ++ ++/** ++ * sk_set_memalloc - sets %SOCK_MEMALLOC ++ * @sk: socket to set it on ++ * ++ * Set %SOCK_MEMALLOC on a socket and increase the memalloc reserve ++ * accordingly. ++ */ ++int sk_set_memalloc(struct sock *sk) ++{ ++ int set = sock_flag(sk, SOCK_MEMALLOC); ++ ++ if (!set) { ++ int err = sk_adjust_memalloc(1, 0); ++ if (err) ++ return err; ++ ++ sock_set_flag(sk, SOCK_MEMALLOC); ++ sk->sk_allocation |= __GFP_MEMALLOC; ++ } ++ return !set; ++} ++EXPORT_SYMBOL_GPL(sk_set_memalloc); ++ ++int sk_clear_memalloc(struct sock *sk) ++{ ++ int set = sock_flag(sk, SOCK_MEMALLOC); ++ if (set) { ++ sk_adjust_memalloc(-1, 0); ++ sock_reset_flag(sk, SOCK_MEMALLOC); ++ sk->sk_allocation &= ~__GFP_MEMALLOC; ++ } ++ return set; ++} ++EXPORT_SYMBOL_GPL(sk_clear_memalloc); ++#endif ++ + static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) + { + struct timeval tv; +@@ -959,6 +1059,7 @@ void sk_free(struct sock *sk) + { + struct sk_filter *filter; + ++ sk_clear_memalloc(sk); + if (sk->sk_destruct) + sk->sk_destruct(sk); + +@@ -1108,6 +1209,12 @@ void __init sk_init(void) + sysctl_wmem_max = 131071; + sysctl_rmem_max = 131071; + } ++ ++ mem_reserve_init(&net_reserve, "total network reserve", NULL); ++ mem_reserve_init(&net_rx_reserve, "network RX reserve", &net_reserve); ++ mem_reserve_init(&net_skb_reserve, "SKB data reserve", &net_rx_reserve); ++ mem_reserve_init(&net_tx_reserve, "network TX reserve", &net_reserve); ++ mem_reserve_init(&net_tx_pages, "protocol TX pages", &net_tx_reserve); + } + + /* +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -249,4 +249,7 @@ endmenu + source "net/rfkill/Kconfig" + source "net/9p/Kconfig" + ++config NETVM ++ def_bool n ++ + endif # if NET diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-20-netvm-reserve-inet.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-20-netvm-reserve-inet.patch new file mode 100644 index 000000000..744fb96ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-20-netvm-reserve-inet.patch @@ -0,0 +1,613 @@ +From: Peter Zijlstra +Subject: netvm: INET reserves. +Patch-mainline: No +References: FATE#303834 + +Add reserves for INET. + +The two big users seem to be the route cache and ip-fragment cache. + +Reserve the route cache under generic RX reserve, its usage is bounded by +the high reclaim watermark, and thus does not need further accounting. + +Reserve the ip-fragement caches under SKB data reserve, these add to the +SKB RX limit. By ensuring we can at least receive as much data as fits in +the reassmbly line we avoid fragment attack deadlocks. + +Adds to the reserve tree: + + total network reserve + network TX reserve + protocol TX pages + network RX reserve ++ IPv6 route cache ++ IPv4 route cache + SKB data reserve ++ IPv6 fragment cache ++ IPv4 fragment cache + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/net/inet_frag.h | 7 +++ + include/net/netns/ipv6.h | 4 ++ + net/ipv4/inet_fragment.c | 3 + + net/ipv4/ip_fragment.c | 87 +++++++++++++++++++++++++++++++++++++++++++++-- + net/ipv4/route.c | 71 +++++++++++++++++++++++++++++++++++++- + net/ipv6/reassembly.c | 86 +++++++++++++++++++++++++++++++++++++++++++++- + net/ipv6/route.c | 78 +++++++++++++++++++++++++++++++++++++++++- + 7 files changed, 329 insertions(+), 7 deletions(-) + +Index: linux-2.6.26/net/ipv4/ip_fragment.c +=================================================================== +--- linux-2.6.26.orig/net/ipv4/ip_fragment.c ++++ linux-2.6.26/net/ipv4/ip_fragment.c +@@ -42,6 +42,8 @@ + #include + #include + #include ++#include ++#include + + /* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6 + * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c +@@ -599,6 +601,64 @@ int ip_defrag(struct sk_buff *skb, u32 u + } + + #ifdef CONFIG_SYSCTL ++static int proc_dointvec_fragment(struct ctl_table *table, int write, ++ struct file *filp, void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct net *net = container_of(table->data, struct net, ++ ipv4.frags.high_thresh); ++ ctl_table tmp = *table; ++ int new_bytes, ret; ++ ++ mutex_lock(&net->ipv4.frags.lock); ++ if (write) { ++ tmp.data = &new_bytes; ++ table = &tmp; ++ } ++ ++ ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmalloc_set(&net->ipv4.frags.reserve, ++ new_bytes); ++ if (!ret) ++ net->ipv4.frags.high_thresh = new_bytes; ++ } ++ mutex_unlock(&net->ipv4.frags.lock); ++ ++ return ret; ++} ++ ++static int sysctl_intvec_fragment(struct ctl_table *table, ++ int __user *name, int nlen, ++ void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen) ++{ ++ struct net *net = container_of(table->data, struct net, ++ ipv4.frags.high_thresh); ++ int write = (newval && newlen); ++ ctl_table tmp = *table; ++ int new_bytes, ret; ++ ++ mutex_lock(&net->ipv4.frags.lock); ++ if (write) { ++ tmp.data = &new_bytes; ++ table = &tmp; ++ } ++ ++ ret = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmalloc_set(&net->ipv4.frags.reserve, ++ new_bytes); ++ if (!ret) ++ net->ipv4.frags.high_thresh = new_bytes; ++ } ++ mutex_unlock(&net->ipv4.frags.lock); ++ ++ return ret; ++} ++ + static int zero; + + static struct ctl_table ip4_frags_ns_ctl_table[] = { +@@ -608,7 +668,8 @@ static struct ctl_table ip4_frags_ns_ctl + .data = &init_net.ipv4.frags.high_thresh, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &proc_dointvec ++ .proc_handler = &proc_dointvec_fragment, ++ .strategy = &sysctl_intvec_fragment, + }, + { + .ctl_name = NET_IPV4_IPFRAG_LOW_THRESH, +@@ -711,6 +772,8 @@ static inline void ip4_frags_ctl_registe + + static int ipv4_frags_init_net(struct net *net) + { ++ int ret; ++ + /* + * Fragment cache limits. We will commit 256K at one time. Should we + * cross that limit we will prune down to 192K. This should cope with +@@ -728,11 +791,31 @@ static int ipv4_frags_init_net(struct ne + + inet_frags_init_net(&net->ipv4.frags); + +- return ip4_frags_ns_ctl_register(net); ++ ret = ip4_frags_ns_ctl_register(net); ++ if (ret) ++ goto out_reg; ++ ++ mem_reserve_init(&net->ipv4.frags.reserve, "IPv4 fragment cache", ++ &net_skb_reserve); ++ ret = mem_reserve_kmalloc_set(&net->ipv4.frags.reserve, ++ net->ipv4.frags.high_thresh); ++ if (ret) ++ goto out_reserve; ++ ++ return 0; ++ ++out_reserve: ++ mem_reserve_disconnect(&net->ipv4.frags.reserve); ++ ip4_frags_ns_ctl_unregister(net); ++out_reg: ++ inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); ++ ++ return ret; + } + + static void ipv4_frags_exit_net(struct net *net) + { ++ mem_reserve_disconnect(&net->ipv4.frags.reserve); + ip4_frags_ns_ctl_unregister(net); + inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); + } +Index: linux-2.6.26/net/ipv6/reassembly.c +=================================================================== +--- linux-2.6.26.orig/net/ipv6/reassembly.c ++++ linux-2.6.26/net/ipv6/reassembly.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -632,6 +633,64 @@ static struct inet6_protocol frag_protoc + }; + + #ifdef CONFIG_SYSCTL ++static int proc_dointvec_fragment(struct ctl_table *table, int write, ++ struct file *filp, void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct net *net = container_of(table->data, struct net, ++ ipv6.frags.high_thresh); ++ ctl_table tmp = *table; ++ int new_bytes, ret; ++ ++ mutex_lock(&net->ipv6.frags.lock); ++ if (write) { ++ tmp.data = &new_bytes; ++ table = &tmp; ++ } ++ ++ ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmalloc_set(&net->ipv6.frags.reserve, ++ new_bytes); ++ if (!ret) ++ net->ipv6.frags.high_thresh = new_bytes; ++ } ++ mutex_unlock(&net->ipv6.frags.lock); ++ ++ return ret; ++} ++ ++static int sysctl_intvec_fragment(struct ctl_table *table, ++ int __user *name, int nlen, ++ void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen) ++{ ++ struct net *net = container_of(table->data, struct net, ++ ipv6.frags.high_thresh); ++ int write = (newval && newlen); ++ ctl_table tmp = *table; ++ int new_bytes, ret; ++ ++ mutex_lock(&net->ipv6.frags.lock); ++ if (write) { ++ tmp.data = &new_bytes; ++ table = &tmp; ++ } ++ ++ ret = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmalloc_set(&net->ipv6.frags.reserve, ++ new_bytes); ++ if (!ret) ++ net->ipv6.frags.high_thresh = new_bytes; ++ } ++ mutex_unlock(&net->ipv6.frags.lock); ++ ++ return ret; ++} ++ + static struct ctl_table ip6_frags_ns_ctl_table[] = { + { + .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, +@@ -639,7 +698,8 @@ static struct ctl_table ip6_frags_ns_ctl + .data = &init_net.ipv6.frags.high_thresh, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &proc_dointvec ++ .proc_handler = &proc_dointvec_fragment, ++ .strategy = &sysctl_intvec_fragment, + }, + { + .ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH, +@@ -748,17 +808,39 @@ static inline void ip6_frags_sysctl_unre + + static int ipv6_frags_init_net(struct net *net) + { ++ int ret; ++ + net->ipv6.frags.high_thresh = 256 * 1024; + net->ipv6.frags.low_thresh = 192 * 1024; + net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; + + inet_frags_init_net(&net->ipv6.frags); + +- return ip6_frags_ns_sysctl_register(net); ++ ret = ip6_frags_ns_sysctl_register(net); ++ if (ret) ++ goto out_reg; ++ ++ mem_reserve_init(&net->ipv6.frags.reserve, "IPv6 fragment cache", ++ &net_skb_reserve); ++ ret = mem_reserve_kmalloc_set(&net->ipv6.frags.reserve, ++ net->ipv6.frags.high_thresh); ++ if (ret) ++ goto out_reserve; ++ ++ return 0; ++ ++out_reserve: ++ mem_reserve_disconnect(&net->ipv6.frags.reserve); ++ ip6_frags_ns_sysctl_unregister(net); ++out_reg: ++ inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); ++ ++ return ret; + } + + static void ipv6_frags_exit_net(struct net *net) + { ++ mem_reserve_disconnect(&net->ipv6.frags.reserve); + ip6_frags_ns_sysctl_unregister(net); + inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); + } +Index: linux-2.6.26/net/ipv4/route.c +=================================================================== +--- linux-2.6.26.orig/net/ipv4/route.c ++++ linux-2.6.26/net/ipv4/route.c +@@ -107,6 +107,7 @@ + #ifdef CONFIG_SYSCTL + #include + #endif ++#include + + #define RT_FL_TOS(oldflp) \ + ((u32)(oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK))) +@@ -269,6 +270,8 @@ static inline int rt_genid(struct net *n + return atomic_read(&net->ipv4.rt_genid); + } + ++static struct mem_reserve ipv4_route_reserve; ++ + #ifdef CONFIG_PROC_FS + struct rt_cache_iter_state { + struct seq_net_private p; +@@ -393,6 +396,62 @@ static int rt_cache_seq_show(struct seq_ + return 0; + } + ++static struct mutex ipv4_route_lock; ++ ++static int proc_dointvec_route(struct ctl_table *table, int write, ++ struct file *filp, void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ ctl_table tmp = *table; ++ int new_size, ret; ++ ++ mutex_lock(&ipv4_route_lock); ++ if (write) { ++ tmp.data = &new_size; ++ table = &tmp; ++ } ++ ++ ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmem_cache_set(&ipv4_route_reserve, ++ ipv4_dst_ops.kmem_cachep, new_size); ++ if (!ret) ++ ip_rt_max_size = new_size; ++ } ++ mutex_unlock(&ipv4_route_lock); ++ ++ return ret; ++} ++ ++static int sysctl_intvec_route(struct ctl_table *table, ++ int __user *name, int nlen, ++ void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen) ++{ ++ int write = (newval && newlen); ++ ctl_table tmp = *table; ++ int new_size, ret; ++ ++ mutex_lock(&ipv4_route_lock); ++ if (write) { ++ tmp.data = &new_size; ++ table = &tmp; ++ } ++ ++ ret = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmem_cache_set(&ipv4_route_reserve, ++ ipv4_dst_ops.kmem_cachep, new_size); ++ if (!ret) ++ ip_rt_max_size = new_size; ++ } ++ mutex_unlock(&ipv4_route_lock); ++ ++ return ret; ++} ++ + static const struct seq_operations rt_cache_seq_ops = { + .start = rt_cache_seq_start, + .next = rt_cache_seq_next, +@@ -2991,7 +3050,8 @@ static ctl_table ipv4_route_table[] = { + .data = &ip_rt_max_size, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &proc_dointvec, ++ .proc_handler = &proc_dointvec_route, ++ .strategy = &sysctl_intvec_route, + }, + { + /* Deprecated. Use gc_min_interval_ms */ +@@ -3270,6 +3330,15 @@ int __init ip_rt_init(void) + ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); + ip_rt_max_size = (rt_hash_mask + 1) * 16; + ++#ifdef CONFIG_PROCFS ++ mutex_init(&ipv4_route_lock); ++#endif ++ ++ mem_reserve_init(&ipv4_route_reserve, "IPv4 route cache", ++ &net_rx_reserve); ++ mem_reserve_kmem_cache_set(&ipv4_route_reserve, ++ ipv4_dst_ops.kmem_cachep, ip_rt_max_size); ++ + devinet_init(); + ip_fib_init(); + +Index: linux-2.6.26/net/ipv6/route.c +=================================================================== +--- linux-2.6.26.orig/net/ipv6/route.c ++++ linux-2.6.26/net/ipv6/route.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2473,6 +2474,64 @@ int ipv6_sysctl_rtcache_flush(ctl_table + return -EINVAL; + } + ++static int proc_dointvec_route(struct ctl_table *table, int write, ++ struct file *filp, void __user *buffer, size_t *lenp, ++ loff_t *ppos) ++{ ++ struct net *net = container_of(table->data, struct net, ++ ipv6.sysctl.ip6_rt_max_size); ++ ctl_table tmp = *table; ++ int new_size, ret; ++ ++ mutex_lock(&net->ipv6.sysctl.ip6_rt_lock); ++ if (write) { ++ tmp.data = &new_size; ++ table = &tmp; ++ } ++ ++ ret = proc_dointvec(table, write, filp, buffer, lenp, ppos); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmem_cache_set(&net->ipv6.ip6_rt_reserve, ++ net->ipv6.ip6_dst_ops->kmem_cachep, new_size); ++ if (!ret) ++ net->ipv6.sysctl.ip6_rt_max_size = new_size; ++ } ++ mutex_unlock(&net->ipv6.sysctl.ip6_rt_lock); ++ ++ return ret; ++} ++ ++static int sysctl_intvec_route(struct ctl_table *table, ++ int __user *name, int nlen, ++ void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen) ++{ ++ struct net *net = container_of(table->data, struct net, ++ ipv6.sysctl.ip6_rt_max_size); ++ int write = (newval && newlen); ++ ctl_table tmp = *table; ++ int new_size, ret; ++ ++ mutex_lock(&net->ipv6.sysctl.ip6_rt_lock); ++ if (write) { ++ tmp.data = &new_size; ++ table = &tmp; ++ } ++ ++ ret = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen); ++ ++ if (!ret && write) { ++ ret = mem_reserve_kmem_cache_set(&net->ipv6.ip6_rt_reserve, ++ net->ipv6.ip6_dst_ops->kmem_cachep, new_size); ++ if (!ret) ++ net->ipv6.sysctl.ip6_rt_max_size = new_size; ++ } ++ mutex_unlock(&net->ipv6.sysctl.ip6_rt_lock); ++ ++ return ret; ++} ++ + ctl_table ipv6_route_table_template[] = { + { + .procname = "flush", +@@ -2495,7 +2554,8 @@ ctl_table ipv6_route_table_template[] = + .data = &init_net.ipv6.sysctl.ip6_rt_max_size, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = &proc_dointvec, ++ .proc_handler = &proc_dointvec_route, ++ .strategy = &sysctl_intvec_route, + }, + { + .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL, +@@ -2583,6 +2643,8 @@ struct ctl_table *ipv6_route_sysctl_init + table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; + } + ++ mutex_init(&net->ipv6.sysctl.ip6_rt_lock); ++ + return table; + } + #endif +@@ -2636,6 +2698,14 @@ static int ip6_route_net_init(struct net + net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; + net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; + ++ mem_reserve_init(&net->ipv6.ip6_rt_reserve, "IPv6 route cache", ++ &net_rx_reserve); ++ ret = mem_reserve_kmem_cache_set(&net->ipv6.ip6_rt_reserve, ++ net->ipv6.ip6_dst_ops->kmem_cachep, ++ net->ipv6.sysctl.ip6_rt_max_size); ++ if (ret) ++ goto out_reserve_fail; ++ + #ifdef CONFIG_PROC_FS + proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); + proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); +@@ -2646,12 +2716,15 @@ static int ip6_route_net_init(struct net + out: + return ret; + ++out_reserve_fail: ++ mem_reserve_disconnect(&net->ipv6.ip6_rt_reserve); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ kfree(net->ipv6.ip6_blk_hole_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +- kfree(net->ipv6.ip6_null_entry); + #endif ++ kfree(net->ipv6.ip6_null_entry); + out_ip6_dst_ops: + release_net(net->ipv6.ip6_dst_ops->dst_net); + kfree(net->ipv6.ip6_dst_ops); +@@ -2664,6 +2737,7 @@ static void ip6_route_net_exit(struct ne + proc_net_remove(net, "ipv6_route"); + proc_net_remove(net, "rt6_stats"); + #endif ++ mem_reserve_disconnect(&net->ipv6.ip6_rt_reserve); + kfree(net->ipv6.ip6_null_entry); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); +Index: linux-2.6.26/include/net/inet_frag.h +=================================================================== +--- linux-2.6.26.orig/include/net/inet_frag.h ++++ linux-2.6.26/include/net/inet_frag.h +@@ -1,6 +1,9 @@ + #ifndef __NET_FRAG_H__ + #define __NET_FRAG_H__ + ++#include ++#include ++ + struct netns_frags { + int nqueues; + atomic_t mem; +@@ -10,6 +13,10 @@ struct netns_frags { + int timeout; + int high_thresh; + int low_thresh; ++ ++ /* reserves */ ++ struct mutex lock; ++ struct mem_reserve reserve; + }; + + struct inet_frag_queue { +Index: linux-2.6.26/net/ipv4/inet_fragment.c +=================================================================== +--- linux-2.6.26.orig/net/ipv4/inet_fragment.c ++++ linux-2.6.26/net/ipv4/inet_fragment.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + +@@ -74,6 +75,8 @@ void inet_frags_init_net(struct netns_fr + nf->nqueues = 0; + atomic_set(&nf->mem, 0); + INIT_LIST_HEAD(&nf->lru_list); ++ mutex_init(&nf->lock); ++ mem_reserve_init(&nf->reserve, "IP fragement cache", NULL); + } + EXPORT_SYMBOL(inet_frags_init_net); + +Index: linux-2.6.26/include/net/netns/ipv6.h +=================================================================== +--- linux-2.6.26.orig/include/net/netns/ipv6.h ++++ linux-2.6.26/include/net/netns/ipv6.h +@@ -24,6 +24,8 @@ struct netns_sysctl_ipv6 { + int ip6_rt_mtu_expires; + int ip6_rt_min_advmss; + int icmpv6_time; ++ ++ struct mutex ip6_rt_lock; + }; + + struct netns_ipv6 { +@@ -55,5 +57,7 @@ struct netns_ipv6 { + struct sock *ndisc_sk; + struct sock *tcp_sk; + struct sock *igmp_sk; ++ ++ struct mem_reserve ip6_rt_reserve; + }; + #endif diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-20-netvm-reserve-inet.patch-fix b/src/patches/suse-2.6.27.31/patches.suse/SoN-20-netvm-reserve-inet.patch-fix new file mode 100644 index 000000000..0a8e2f288 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-20-netvm-reserve-inet.patch-fix @@ -0,0 +1,22 @@ +From: Jeff Mahoney +Subject: [PATCH] SoN: Fix initialization of ipv4_route_lock +References: bnc#435994 + + It's CONFIG_PROC_FS, not CONFIG_PROCFS. + +Signed-off-by: Jeff Mahoney +--- + net/ipv4/route.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -3330,7 +3330,7 @@ int __init ip_rt_init(void) + ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); + ip_rt_max_size = (rt_hash_mask + 1) * 16; + +-#ifdef CONFIG_PROCFS ++#ifdef CONFIG_PROC_FS + mutex_init(&ipv4_route_lock); + #endif + diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-21-netvm-skbuff-reserve.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-21-netvm-skbuff-reserve.patch new file mode 100644 index 000000000..6ecd80c86 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-21-netvm-skbuff-reserve.patch @@ -0,0 +1,450 @@ +From: Peter Zijlstra +Subject: netvm: hook skb allocation to reserves +Patch-mainline: No +References: FATE#303834 + +Change the skb allocation api to indicate RX usage and use this to fall back to +the reserve when needed. SKBs allocated from the reserve are tagged in +skb->emergency. + +Teach all other skb ops about emergency skbs and the reserve accounting. + +Use the (new) packet split API to allocate and track fragment pages from the +emergency reserve. Do this using an atomic counter in page->index. This is +needed because the fragments have a different sharing semantic than that +indicated by skb_shinfo()->dataref. + +Note that the decision to distinguish between regular and emergency SKBs allows +the accounting overhead to be limited to the later kind. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/mm_types.h | 1 + include/linux/skbuff.h | 27 +++++++-- + net/core/skbuff.c | 135 +++++++++++++++++++++++++++++++++++++---------- + 3 files changed, 132 insertions(+), 31 deletions(-) + +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -75,6 +75,7 @@ struct page { + pgoff_t index; /* Our offset within mapping. */ + void *freelist; /* SLUB: freelist req. slab lock */ + int reserve; /* page_alloc: page is a reserve page */ ++ atomic_t frag_count; /* skb fragment use count */ + }; + struct list_head lru; /* Pageout list, eg. active_list + * protected by zone->lru_lock ! +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -320,7 +320,10 @@ struct sk_buff { + #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) + __u8 do_not_encrypt:1; + #endif +- /* 0/13/14 bit hole */ ++#ifdef CONFIG_NETVM ++ __u8 emergency:1; ++#endif ++ /* 12-16 bit hole */ + + #ifdef CONFIG_NET_DMA + dma_cookie_t dma_cookie; +@@ -353,10 +356,22 @@ struct sk_buff { + + #include + ++#define SKB_ALLOC_FCLONE 0x01 ++#define SKB_ALLOC_RX 0x02 ++ ++static inline bool skb_emergency(const struct sk_buff *skb) ++{ ++#ifdef CONFIG_NETVM ++ return unlikely(skb->emergency); ++#else ++ return false; ++#endif ++} ++ + extern void kfree_skb(struct sk_buff *skb); + extern void __kfree_skb(struct sk_buff *skb); + extern struct sk_buff *__alloc_skb(unsigned int size, +- gfp_t priority, int fclone, int node); ++ gfp_t priority, int flags, int node); + static inline struct sk_buff *alloc_skb(unsigned int size, + gfp_t priority) + { +@@ -366,7 +381,7 @@ static inline struct sk_buff *alloc_skb( + static inline struct sk_buff *alloc_skb_fclone(unsigned int size, + gfp_t priority) + { +- return __alloc_skb(size, priority, 1, -1); ++ return __alloc_skb(size, priority, SKB_ALLOC_FCLONE, -1); + } + + extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src); +@@ -1216,7 +1231,8 @@ static inline void __skb_queue_purge(str + static inline struct sk_buff *__dev_alloc_skb(unsigned int length, + gfp_t gfp_mask) + { +- struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask); ++ struct sk_buff *skb = ++ __alloc_skb(length + NET_SKB_PAD, gfp_mask, SKB_ALLOC_RX, -1); + if (likely(skb)) + skb_reserve(skb, NET_SKB_PAD); + return skb; +@@ -1247,6 +1263,7 @@ static inline struct sk_buff *netdev_all + } + + extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask); ++extern void __netdev_free_page(struct net_device *dev, struct page *page); + + /** + * netdev_alloc_page - allocate a page for ps-rx on a specific device +@@ -1263,7 +1280,7 @@ static inline struct page *netdev_alloc_ + + static inline void netdev_free_page(struct net_device *dev, struct page *page) + { +- __free_page(page); ++ __netdev_free_page(dev, page); + } + + /** +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -173,23 +173,29 @@ EXPORT_SYMBOL(skb_truesize_bug); + * %GFP_ATOMIC. + */ + struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, +- int fclone, int node) ++ int flags, int node) + { + struct kmem_cache *cache; + struct skb_shared_info *shinfo; + struct sk_buff *skb; + u8 *data; ++ int emergency = 0; ++ int memalloc = sk_memalloc_socks(); + +- cache = fclone ? skbuff_fclone_cache : skbuff_head_cache; ++ size = SKB_DATA_ALIGN(size); ++ cache = (flags & SKB_ALLOC_FCLONE) ++ ? skbuff_fclone_cache : skbuff_head_cache; ++ ++ if (memalloc && (flags & SKB_ALLOC_RX)) ++ gfp_mask |= __GFP_MEMALLOC; + + /* Get the HEAD */ + skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node); + if (!skb) + goto out; + +- size = SKB_DATA_ALIGN(size); +- data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info), +- gfp_mask, node); ++ data = kmalloc_reserve(size + sizeof(struct skb_shared_info), ++ gfp_mask, node, &net_skb_reserve, &emergency); + if (!data) + goto nodata; + +@@ -199,6 +205,9 @@ struct sk_buff *__alloc_skb(unsigned int + * the tail pointer in struct sk_buff! + */ + memset(skb, 0, offsetof(struct sk_buff, tail)); ++#ifdef CONFIG_NETVM ++ skb->emergency = emergency; ++#endif + skb->truesize = size + sizeof(struct sk_buff); + atomic_set(&skb->users, 1); + skb->head = data; +@@ -215,7 +224,7 @@ struct sk_buff *__alloc_skb(unsigned int + shinfo->ip6_frag_id = 0; + shinfo->frag_list = NULL; + +- if (fclone) { ++ if (flags & SKB_ALLOC_FCLONE) { + struct sk_buff *child = skb + 1; + atomic_t *fclone_ref = (atomic_t *) (child + 1); + +@@ -223,6 +232,9 @@ struct sk_buff *__alloc_skb(unsigned int + atomic_set(fclone_ref, 1); + + child->fclone = SKB_FCLONE_UNAVAILABLE; ++#ifdef CONFIG_NETVM ++ child->emergency = skb->emergency; ++#endif + } + out: + return skb; +@@ -251,7 +263,7 @@ struct sk_buff *__netdev_alloc_skb(struc + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; + struct sk_buff *skb; + +- skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node); ++ skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, SKB_ALLOC_RX, node); + if (likely(skb)) { + skb_reserve(skb, NET_SKB_PAD); + skb->dev = dev; +@@ -264,11 +276,19 @@ struct page *__netdev_alloc_page(struct + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; + struct page *page; + +- page = alloc_pages_node(node, gfp_mask, 0); ++ page = alloc_pages_reserve(node, gfp_mask | __GFP_MEMALLOC, 0, ++ &net_skb_reserve, NULL); ++ + return page; + } + EXPORT_SYMBOL(__netdev_alloc_page); + ++void __netdev_free_page(struct net_device *dev, struct page *page) ++{ ++ free_pages_reserve(page, 0, &net_skb_reserve, page->reserve); ++} ++EXPORT_SYMBOL(__netdev_free_page); ++ + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, + int size) + { +@@ -276,6 +296,27 @@ void skb_add_rx_frag(struct sk_buff *skb + skb->len += size; + skb->data_len += size; + skb->truesize += size; ++ ++#ifdef CONFIG_NETVM ++ /* ++ * In the rare case that skb_emergency() != page->reserved we'll ++ * skew the accounting slightly, but since its only a 'small' constant ++ * shift its ok. ++ */ ++ if (skb_emergency(skb)) { ++ /* ++ * We need to track fragment pages so that we properly ++ * release their reserve in skb_put_page(). ++ */ ++ atomic_set(&page->frag_count, 1); ++ } else if (unlikely(page->reserve)) { ++ /* ++ * Release the reserve now, because normal skbs don't ++ * do the emergency accounting. ++ */ ++ mem_reserve_pages_charge(&net_skb_reserve, -1); ++ } ++#endif + } + EXPORT_SYMBOL(skb_add_rx_frag); + +@@ -327,21 +368,38 @@ static void skb_clone_fraglist(struct sk + skb_get(list); + } + ++static void skb_get_page(struct sk_buff *skb, struct page *page) ++{ ++ get_page(page); ++ if (skb_emergency(skb)) ++ atomic_inc(&page->frag_count); ++} ++ ++static void skb_put_page(struct sk_buff *skb, struct page *page) ++{ ++ if (skb_emergency(skb) && atomic_dec_and_test(&page->frag_count)) ++ mem_reserve_pages_charge(&net_skb_reserve, -1); ++ put_page(page); ++} ++ + static void skb_release_data(struct sk_buff *skb) + { + if (!skb->cloned || + !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1, + &skb_shinfo(skb)->dataref)) { ++ + if (skb_shinfo(skb)->nr_frags) { + int i; +- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +- put_page(skb_shinfo(skb)->frags[i].page); ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ skb_put_page(skb, ++ skb_shinfo(skb)->frags[i].page); ++ } + } + + if (skb_shinfo(skb)->frag_list) + skb_drop_fraglist(skb); + +- kfree(skb->head); ++ kfree_reserve(skb->head, &net_skb_reserve, skb_emergency(skb)); + } + } + +@@ -462,6 +520,9 @@ static void __copy_skb_header(struct sk_ + #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) + new->ipvs_property = old->ipvs_property; + #endif ++#ifdef CONFIG_NETVM ++ new->emergency = old->emergency; ++#endif + new->protocol = old->protocol; + new->mark = old->mark; + __nf_copy(new, old); +@@ -555,6 +616,9 @@ struct sk_buff *skb_clone(struct sk_buff + n->fclone = SKB_FCLONE_CLONE; + atomic_inc(fclone_ref); + } else { ++ if (skb_emergency(skb)) ++ gfp_mask |= __GFP_MEMALLOC; ++ + n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); + if (!n) + return NULL; +@@ -586,6 +650,14 @@ static void copy_skb_header(struct sk_bu + skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type; + } + ++static inline int skb_alloc_rx_flag(const struct sk_buff *skb) ++{ ++ if (skb_emergency(skb)) ++ return SKB_ALLOC_RX; ++ ++ return 0; ++} ++ + /** + * skb_copy - create private copy of an sk_buff + * @skb: buffer to copy +@@ -606,15 +678,17 @@ static void copy_skb_header(struct sk_bu + struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask) + { + int headerlen = skb->data - skb->head; ++ int size; + /* + * Allocate the copy buffer + */ + struct sk_buff *n; + #ifdef NET_SKBUFF_DATA_USES_OFFSET +- n = alloc_skb(skb->end + skb->data_len, gfp_mask); ++ size = skb->end + skb->data_len; + #else +- n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask); ++ size = skb->end - skb->head + skb->data_len; + #endif ++ n = __alloc_skb(size, gfp_mask, skb_alloc_rx_flag(skb), -1); + if (!n) + return NULL; + +@@ -649,12 +723,14 @@ struct sk_buff *pskb_copy(struct sk_buff + /* + * Allocate the copy buffer + */ ++ int size; + struct sk_buff *n; + #ifdef NET_SKBUFF_DATA_USES_OFFSET +- n = alloc_skb(skb->end, gfp_mask); ++ size = skb->end; + #else +- n = alloc_skb(skb->end - skb->head, gfp_mask); ++ size = skb->end - skb->head; + #endif ++ n = __alloc_skb(size, gfp_mask, skb_alloc_rx_flag(skb), -1); + if (!n) + goto out; + +@@ -673,8 +749,9 @@ struct sk_buff *pskb_copy(struct sk_buff + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { +- skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; +- get_page(skb_shinfo(n)->frags[i].page); ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ skb_shinfo(n)->frags[i] = *frag; ++ skb_get_page(n, frag->page); + } + skb_shinfo(n)->nr_frags = i; + } +@@ -722,7 +799,11 @@ int pskb_expand_head(struct sk_buff *skb + + size = SKB_DATA_ALIGN(size); + +- data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); ++ if (skb_emergency(skb)) ++ gfp_mask |= __GFP_MEMALLOC; ++ ++ data = kmalloc_reserve(size + sizeof(struct skb_shared_info), ++ gfp_mask, -1, &net_skb_reserve, NULL); + if (!data) + goto nodata; + +@@ -737,7 +818,7 @@ int pskb_expand_head(struct sk_buff *skb + sizeof(struct skb_shared_info)); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +- get_page(skb_shinfo(skb)->frags[i].page); ++ skb_get_page(skb, skb_shinfo(skb)->frags[i].page); + + if (skb_shinfo(skb)->frag_list) + skb_clone_fraglist(skb); +@@ -816,8 +897,8 @@ struct sk_buff *skb_copy_expand(const st + /* + * Allocate the copy buffer + */ +- struct sk_buff *n = alloc_skb(newheadroom + skb->len + newtailroom, +- gfp_mask); ++ struct sk_buff *n = __alloc_skb(newheadroom + skb->len + newtailroom, ++ gfp_mask, skb_alloc_rx_flag(skb), -1); + int oldheadroom = skb_headroom(skb); + int head_copy_len, head_copy_off; + int off; +@@ -1006,7 +1087,7 @@ drop_pages: + skb_shinfo(skb)->nr_frags = i; + + for (; i < nfrags; i++) +- put_page(skb_shinfo(skb)->frags[i].page); ++ skb_put_page(skb, skb_shinfo(skb)->frags[i].page); + + if (skb_shinfo(skb)->frag_list) + skb_drop_fraglist(skb); +@@ -1175,7 +1256,7 @@ pull_pages: + k = 0; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size <= eat) { +- put_page(skb_shinfo(skb)->frags[i].page); ++ skb_put_page(skb, skb_shinfo(skb)->frags[i].page); + eat -= skb_shinfo(skb)->frags[i].size; + } else { + skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; +@@ -1925,6 +2006,7 @@ static inline void skb_split_no_header(s + skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i]; + + if (pos < len) { ++ struct page *page = skb_shinfo(skb)->frags[i].page; + /* Split frag. + * We have two variants in this case: + * 1. Move all the frag to the second +@@ -1933,7 +2015,7 @@ static inline void skb_split_no_header(s + * where splitting is expensive. + * 2. Split is accurately. We make this. + */ +- get_page(skb_shinfo(skb)->frags[i].page); ++ skb_get_page(skb1, page); + skb_shinfo(skb1)->frags[0].page_offset += len - pos; + skb_shinfo(skb1)->frags[0].size -= len - pos; + skb_shinfo(skb)->frags[i].size = len - pos; +@@ -2264,7 +2346,8 @@ struct sk_buff *skb_segment(struct sk_bu + if (hsize > len || !sg) + hsize = len; + +- nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC); ++ nskb = __alloc_skb(hsize + doffset + headroom, GFP_ATOMIC, ++ skb_alloc_rx_flag(skb), -1); + if (unlikely(!nskb)) + goto err; + +@@ -2302,7 +2385,7 @@ struct sk_buff *skb_segment(struct sk_bu + BUG_ON(i >= nfrags); + + *frag = skb_shinfo(skb)->frags[i]; +- get_page(frag->page); ++ skb_get_page(nskb, frag->page); + size = frag->size; + + if (pos < offset) { diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-22-netvm-sk_filter.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-22-netvm-sk_filter.patch new file mode 100644 index 000000000..315bedc90 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-22-netvm-sk_filter.patch @@ -0,0 +1,33 @@ +From: Peter Zijlstra +Subject: netvm: filter emergency skbs. +Patch-mainline: No +References: FATE#303834 + +Toss all emergency packets not for a SOCK_MEMALLOC socket. This ensures our +precious memory reserve doesn't get stuck waiting for user-space. + +The correctness of this approach relies on the fact that networks must be +assumed lossy. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + net/core/filter.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6/net/core/filter.c +=================================================================== +--- linux-2.6.orig/net/core/filter.c ++++ linux-2.6/net/core/filter.c +@@ -81,6 +81,9 @@ int sk_filter(struct sock *sk, struct sk + int err; + struct sk_filter *filter; + ++ if (skb_emergency(skb) && !sk_has_memalloc(sk)) ++ return -ENOMEM; ++ + err = security_sock_rcv_skb(sk, skb); + if (err) + return err; diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-23-netvm-tcp-deadlock.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-23-netvm-tcp-deadlock.patch new file mode 100644 index 000000000..c28b75af2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-23-netvm-tcp-deadlock.patch @@ -0,0 +1,108 @@ +From: Peter Zijlstra +Subject: netvm: prevent a stream specific deadlock +Patch-mainline: No +References: FATE#303834 + +It could happen that all !SOCK_MEMALLOC sockets have buffered so much data +that we're over the global rmem limit. This will prevent SOCK_MEMALLOC buffers +from receiving data, which will prevent userspace from running, which is needed +to reduce the buffered data. + +Fix this by exempting the SOCK_MEMALLOC sockets from the rmem limit. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/net/sock.h | 7 ++++--- + net/core/sock.c | 2 +- + net/ipv4/tcp_input.c | 12 ++++++------ + net/sctp/ulpevent.c | 2 +- + 4 files changed, 12 insertions(+), 11 deletions(-) + +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -788,12 +788,13 @@ static inline int sk_wmem_schedule(struc + __sk_mem_schedule(sk, size, SK_MEM_SEND); + } + +-static inline int sk_rmem_schedule(struct sock *sk, int size) ++static inline int sk_rmem_schedule(struct sock *sk, struct sk_buff *skb) + { + if (!sk_has_account(sk)) + return 1; +- return size <= sk->sk_forward_alloc || +- __sk_mem_schedule(sk, size, SK_MEM_RECV); ++ return skb->truesize <= sk->sk_forward_alloc || ++ __sk_mem_schedule(sk, skb->truesize, SK_MEM_RECV) || ++ skb_emergency(skb); + } + + static inline void sk_mem_reclaim(struct sock *sk) +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -381,7 +381,7 @@ int sock_queue_rcv_skb(struct sock *sk, + if (err) + goto out; + +- if (!sk_rmem_schedule(sk, skb->truesize)) { ++ if (!sk_rmem_schedule(sk, skb)) { + err = -ENOBUFS; + goto out; + } +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3939,19 +3939,19 @@ static void tcp_ofo_queue(struct sock *s + static int tcp_prune_ofo_queue(struct sock *sk); + static int tcp_prune_queue(struct sock *sk); + +-static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size) ++static inline int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb) + { + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || +- !sk_rmem_schedule(sk, size)) { ++ !sk_rmem_schedule(sk, skb)) { + + if (tcp_prune_queue(sk) < 0) + return -1; + +- if (!sk_rmem_schedule(sk, size)) { ++ if (!sk_rmem_schedule(sk, skb)) { + if (!tcp_prune_ofo_queue(sk)) + return -1; + +- if (!sk_rmem_schedule(sk, size)) ++ if (!sk_rmem_schedule(sk, skb)) + return -1; + } + } +@@ -4006,7 +4006,7 @@ static void tcp_data_queue(struct sock * + if (eaten <= 0) { + queue_and_out: + if (eaten < 0 && +- tcp_try_rmem_schedule(sk, skb->truesize)) ++ tcp_try_rmem_schedule(sk, skb)) + goto drop; + + skb_set_owner_r(skb, sk); +@@ -4077,7 +4077,7 @@ drop: + + TCP_ECN_check_ce(tp, skb); + +- if (tcp_try_rmem_schedule(sk, skb->truesize)) ++ if (tcp_try_rmem_schedule(sk, skb)) + goto drop; + + /* Disable header prediction. */ +--- a/net/sctp/ulpevent.c ++++ b/net/sctp/ulpevent.c +@@ -701,7 +701,7 @@ struct sctp_ulpevent *sctp_ulpevent_make + if (rx_count >= asoc->base.sk->sk_rcvbuf) { + + if ((asoc->base.sk->sk_userlocks & SOCK_RCVBUF_LOCK) || +- (!sk_rmem_schedule(asoc->base.sk, chunk->skb->truesize))) ++ (!sk_rmem_schedule(asoc->base.sk, chunk->skb))) + goto fail; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-24-emergency-nf_queue.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-24-emergency-nf_queue.patch new file mode 100644 index 000000000..d7a23e776 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-24-emergency-nf_queue.patch @@ -0,0 +1,34 @@ +From: Peter Zijlstra +Subject: netfilter: NF_QUEUE vs emergency skbs +Patch-mainline: No +References: FATE#303834 + +Avoid memory getting stuck waiting for userspace, drop all emergency packets. +This of course requires the regular storage route to not include an NF_QUEUE +target ;-) + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + net/netfilter/core.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: linux-2.6.26/net/netfilter/core.c +=================================================================== +--- linux-2.6.26.orig/net/netfilter/core.c ++++ linux-2.6.26/net/netfilter/core.c +@@ -184,9 +184,12 @@ next_hook: + ret = 1; + goto unlock; + } else if (verdict == NF_DROP) { ++drop: + kfree_skb(skb); + ret = -EPERM; + } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { ++ if (skb_emergency(skb)) ++ goto drop; + if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn, + verdict >> NF_VERDICT_BITS)) + goto next_hook; diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-25-netvm.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-25-netvm.patch new file mode 100644 index 000000000..b5b4b4c77 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-25-netvm.patch @@ -0,0 +1,181 @@ +From: Peter Zijlstra +Subject: netvm: skb processing +Patch-mainline: No +References: FATE#303834 + +In order to make sure emergency packets receive all memory needed to proceed +ensure processing of emergency SKBs happens under PF_MEMALLOC. + +Use the (new) sk_backlog_rcv() wrapper to ensure this for backlog processing. + +Skip taps, since those are user-space again. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/net/sock.h | 5 ++++ + net/core/dev.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++----- + net/core/sock.c | 16 ++++++++++++++ + 3 files changed, 73 insertions(+), 5 deletions(-) + +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -528,8 +528,13 @@ static inline void sk_add_backlog(struct + skb->next = NULL; + } + ++extern int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb); ++ + static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) + { ++ if (skb_emergency(skb)) ++ return __sk_backlog_rcv(sk, skb); ++ + return sk->sk_backlog_rcv(sk, skb); + } + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2170,6 +2170,30 @@ void netif_nit_deliver(struct sk_buff *s + rcu_read_unlock(); + } + ++/* ++ * Filter the protocols for which the reserves are adequate. ++ * ++ * Before adding a protocol make sure that it is either covered by the existing ++ * reserves, or add reserves covering the memory need of the new protocol's ++ * packet processing. ++ */ ++static int skb_emergency_protocol(struct sk_buff *skb) ++{ ++ if (skb_emergency(skb)) ++ switch (skb->protocol) { ++ case __constant_htons(ETH_P_ARP): ++ case __constant_htons(ETH_P_IP): ++ case __constant_htons(ETH_P_IPV6): ++ case __constant_htons(ETH_P_8021Q): ++ break; ++ ++ default: ++ return 0; ++ } ++ ++ return 1; ++} ++ + /** + * netif_receive_skb - process receive buffer from network + * @skb: buffer to process +@@ -2192,13 +2216,26 @@ int netif_receive_skb(struct sk_buff *sk + struct net_device *null_or_orig; + int ret = NET_RX_DROP; + __be16 type; ++ unsigned long pflags = current->flags; + + if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) + return NET_RX_SUCCESS; + ++ /* Emergency skb are special, they should ++ * - be delivered to SOCK_MEMALLOC sockets only ++ * - stay away from userspace ++ * - have bounded memory usage ++ * ++ * Use PF_MEMALLOC as a poor mans memory pool - the grouping kind. ++ * This saves us from propagating the allocation context down to all ++ * allocation sites. ++ */ ++ if (skb_emergency(skb)) ++ current->flags |= PF_MEMALLOC; ++ + /* if we've gotten here through NAPI, check netpoll */ + if (netpoll_receive_skb(skb)) +- return NET_RX_DROP; ++ goto out; + + if (!skb->tstamp.tv64) + net_timestamp(skb); +@@ -2237,6 +2274,9 @@ int netif_receive_skb(struct sk_buff *sk + } + #endif + ++ if (skb_emergency(skb)) ++ goto skip_taps; ++ + list_for_each_entry_rcu(ptype, &ptype_all, list) { + if (ptype->dev == null_or_orig || ptype->dev == skb->dev || + ptype->dev == orig_dev) { +@@ -2246,19 +2286,23 @@ int netif_receive_skb(struct sk_buff *sk + } + } + ++skip_taps: + #ifdef CONFIG_NET_CLS_ACT + skb = handle_ing(skb, &pt_prev, &ret, orig_dev); + if (!skb) +- goto out; ++ goto unlock; + ncls: + #endif + ++ if (!skb_emergency_protocol(skb)) ++ goto drop; ++ + skb = handle_bridge(skb, &pt_prev, &ret, orig_dev); + if (!skb) +- goto out; ++ goto unlock; + skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev); + if (!skb) +- goto out; ++ goto unlock; + + type = skb->protocol; + list_for_each_entry_rcu(ptype, +@@ -2275,6 +2319,7 @@ ncls: + if (pt_prev) { + ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); + } else { ++drop: + kfree_skb(skb); + /* Jamal, now you will not able to escape explaining + * me how you were going to use this. :-) +@@ -2282,8 +2327,10 @@ ncls: + ret = NET_RX_DROP; + } + +-out: ++unlock: + rcu_read_unlock(); ++out: ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); + return ret; + } + +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -309,6 +309,22 @@ int sk_clear_memalloc(struct sock *sk) + return set; + } + EXPORT_SYMBOL_GPL(sk_clear_memalloc); ++ ++int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) ++{ ++ int ret; ++ unsigned long pflags = current->flags; ++ ++ /* these should have been dropped before queueing */ ++ BUG_ON(!sk_has_memalloc(sk)); ++ ++ current->flags |= PF_MEMALLOC; ++ ret = sk->sk_backlog_rcv(sk, skb); ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); ++ ++ return ret; ++} ++EXPORT_SYMBOL(__sk_backlog_rcv); + #endif + + static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-26-mm-swapfile.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-26-mm-swapfile.patch new file mode 100644 index 000000000..7949fb8a7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-26-mm-swapfile.patch @@ -0,0 +1,361 @@ +From: Peter Zijlstra +Subject: mm: add support for non block device backed swap files +Patch-mainline: No +References: FATE#303834 + +New addres_space_operations methods are added: + int swapon(struct file *); + int swapoff(struct file *); + int swap_out(struct file *, struct page *, struct writeback_control *); + int swap_in(struct file *, struct page *); + +When during sys_swapon() the ->swapon() method is found and returns no error +the swapper_space.a_ops will proxy to sis->swap_file->f_mapping->a_ops, and +make use of ->swap_{out,in}() to write/read swapcache pages. + +The ->swapon() method will be used to communicate to the file that the VM +relies on it, and the address_space should take adequate measures (like +reserving memory for mempools or the like). The ->swapoff() method will be +called on sys_swapoff() when ->swapon() was found and returned no error. + +This new interface can be used to obviate the need for ->bmap in the swapfile +code. A filesystem would need to load (and maybe even allocate) the full block +map for a file into memory and pin it there on ->swapon() so that +->swap_{out,in}() have instant access to it. It can be released on ->swapoff(). + +The reason to provide ->swap_{out,in}() over using {write,read}page() is to + 1) make a distinction between swapcache and pagecache pages, and + 2) to provide a struct file * for credential context (normally not needed + in the context of writepage, as the page content is normally dirtied + using either of the following interfaces: + write_{begin,end}() + {prepare,commit}_write() + page_mkwrite() + which do have the file context. + +[miklos@szeredi.hu: cleanups] +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + Documentation/filesystems/Locking | 22 ++++++++++++++++ + Documentation/filesystems/vfs.txt | 18 +++++++++++++ + include/linux/buffer_head.h | 2 - + include/linux/fs.h | 9 ++++++ + include/linux/swap.h | 4 ++ + mm/page_io.c | 52 ++++++++++++++++++++++++++++++++++++++ + mm/swap_state.c | 4 +- + mm/swapfile.c | 32 +++++++++++++++++++++-- + 8 files changed, 137 insertions(+), 6 deletions(-) + +--- a/Documentation/filesystems/Locking ++++ b/Documentation/filesystems/Locking +@@ -169,6 +169,10 @@ prototypes: + int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, + loff_t offset, unsigned long nr_segs); + int (*launder_page) (struct page *); ++ int (*swapon) (struct file *); ++ int (*swapoff) (struct file *); ++ int (*swap_out) (struct file *, struct page *, struct writeback_control *); ++ int (*swap_in) (struct file *, struct page *); + + locking rules: + All except set_page_dirty may block +@@ -190,6 +194,10 @@ invalidatepage: no yes + releasepage: no yes + direct_IO: no + launder_page: no yes ++swapon no ++swapoff no ++swap_out no yes, unlocks ++swap_in no yes, unlocks + + ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() + may be called from the request handler (/dev/loop). +@@ -289,6 +297,20 @@ cleaned, or an error value if not. Note + getting mapped back in and redirtied, it needs to be kept locked + across the entire operation. + ++ ->swapon() will be called with a non-zero argument on files backing ++(non block device backed) swapfiles. A return value of zero indicates success, ++in which case this file can be used for backing swapspace. The swapspace ++operations will be proxied to the address space operations. ++ ++ ->swapoff() will be called in the sys_swapoff() path when ->swapon() ++returned success. ++ ++ ->swap_out() when swapon() returned success, this method is used to ++write the swap page. ++ ++ ->swap_in() when swapon() returned success, this method is used to ++read the swap page. ++ + Note: currently almost all instances of address_space methods are + using BKL for internal serialization and that's one of the worst sources + of contention. Normally they are calling library functions (in fs/buffer.c) +--- a/Documentation/filesystems/vfs.txt ++++ b/Documentation/filesystems/vfs.txt +@@ -539,6 +539,11 @@ struct address_space_operations { + /* migrate the contents of a page to the specified target */ + int (*migratepage) (struct page *, struct page *); + int (*launder_page) (struct page *); ++ int (*swapon)(struct file *); ++ int (*swapoff)(struct file *); ++ int (*swap_out)(struct file *file, struct page *page, ++ struct writeback_control *wbc); ++ int (*swap_in)(struct file *file, struct page *page); + }; + + writepage: called by the VM to write a dirty page to backing store. +@@ -724,6 +729,19 @@ struct address_space_operations { + prevent redirtying the page, it is kept locked during the whole + operation. + ++ swapon: Called when swapon is used on a file. A ++ return value of zero indicates success, in which case this ++ file can be used to back swapspace. The swapspace operations ++ will be proxied to this address space's ->swap_{out,in} methods. ++ ++ swapoff: Called during swapoff on files where swapon was successfull. ++ ++ swap_out: Called to write a swapcache page to a backing store, similar to ++ writepage. ++ ++ swap_in: Called to read a swapcache page from a backing store, similar to ++ readpage. ++ + The File Object + =============== + +--- a/include/linux/buffer_head.h ++++ b/include/linux/buffer_head.h +@@ -347,7 +347,7 @@ static inline void invalidate_inode_buff + static inline int remove_inode_buffers(struct inode *inode) { return 1; } + static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } + static inline void invalidate_bdev(struct block_device *bdev) {} +- ++static inline void block_sync_page(struct page *) { } + + #endif /* CONFIG_BLOCK */ + #endif /* _LINUX_BUFFER_HEAD_H */ +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -525,6 +525,15 @@ struct address_space_operations { + int (*launder_page) (struct page *); + int (*is_partially_uptodate) (struct page *, read_descriptor_t *, + unsigned long); ++ ++ /* ++ * swapfile support ++ */ ++ int (*swapon)(struct file *file); ++ int (*swapoff)(struct file *file); ++ int (*swap_out)(struct file *file, struct page *page, ++ struct writeback_control *wbc); ++ int (*swap_in)(struct file *file, struct page *page); + }; + + /* +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -120,6 +120,7 @@ enum { + SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ + SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */ + SWP_ACTIVE = (SWP_USED | SWP_WRITEOK), ++ SWP_FILE = (1 << 2), /* file swap area */ + /* add others here before... */ + SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */ + }; +@@ -217,6 +218,8 @@ extern void swap_unplug_io_fn(struct bac + /* linux/mm/page_io.c */ + extern int swap_readpage(struct file *, struct page *); + extern int swap_writepage(struct page *page, struct writeback_control *wbc); ++extern void swap_sync_page(struct page *page); ++extern int swap_set_page_dirty(struct page *page); + extern void end_swap_bio_read(struct bio *bio, int err); + + /* linux/mm/swap_state.c */ +@@ -249,6 +252,7 @@ extern unsigned int count_swap_pages(int + extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); + extern sector_t swapdev_block(int, pgoff_t); + extern struct swap_info_struct *get_swap_info_struct(unsigned); ++extern struct swap_info_struct *page_swap_info(struct page *); + extern int can_share_swap_page(struct page *); + extern int remove_exclusive_swap_page(struct page *); + struct backing_dev_info; +--- a/mm/page_io.c ++++ b/mm/page_io.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -98,11 +99,23 @@ int swap_writepage(struct page *page, st + { + struct bio *bio; + int ret = 0, rw = WRITE; ++ struct swap_info_struct *sis = page_swap_info(page); + + if (remove_exclusive_swap_page(page)) { + unlock_page(page); + goto out; + } ++ ++ if (sis->flags & SWP_FILE) { ++ struct file *swap_file = sis->swap_file; ++ struct address_space *mapping = swap_file->f_mapping; ++ ++ ret = mapping->a_ops->swap_out(swap_file, page, wbc); ++ if (!ret) ++ count_vm_event(PSWPOUT); ++ return ret; ++ } ++ + bio = get_swap_bio(GFP_NOIO, page_private(page), page, + end_swap_bio_write); + if (bio == NULL) { +@@ -122,13 +135,52 @@ out: + return ret; + } + ++void swap_sync_page(struct page *page) ++{ ++ struct swap_info_struct *sis = page_swap_info(page); ++ ++ if (sis->flags & SWP_FILE) { ++ struct address_space *mapping = sis->swap_file->f_mapping; ++ ++ if (mapping->a_ops->sync_page) ++ mapping->a_ops->sync_page(page); ++ } else { ++ block_sync_page(page); ++ } ++} ++ ++int swap_set_page_dirty(struct page *page) ++{ ++ struct swap_info_struct *sis = page_swap_info(page); ++ ++ if (sis->flags & SWP_FILE) { ++ struct address_space *mapping = sis->swap_file->f_mapping; ++ ++ return mapping->a_ops->set_page_dirty(page); ++ } else { ++ return __set_page_dirty_nobuffers(page); ++ } ++} ++ + int swap_readpage(struct file *file, struct page *page) + { + struct bio *bio; + int ret = 0; ++ struct swap_info_struct *sis = page_swap_info(page); + + BUG_ON(!PageLocked(page)); + BUG_ON(PageUptodate(page)); ++ ++ if (sis->flags & SWP_FILE) { ++ struct file *swap_file = sis->swap_file; ++ struct address_space *mapping = swap_file->f_mapping; ++ ++ ret = mapping->a_ops->swap_in(swap_file, page); ++ if (!ret) ++ count_vm_event(PSWPIN); ++ return ret; ++ } ++ + bio = get_swap_bio(GFP_KERNEL, page_private(page), page, + end_swap_bio_read); + if (bio == NULL) { +--- a/mm/swap_state.c ++++ b/mm/swap_state.c +@@ -27,8 +27,8 @@ + */ + static const struct address_space_operations swap_aops = { + .writepage = swap_writepage, +- .sync_page = block_sync_page, +- .set_page_dirty = __set_page_dirty_nobuffers, ++ .sync_page = swap_sync_page, ++ .set_page_dirty = swap_set_page_dirty, + .migratepage = migrate_page, + }; + +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -1018,6 +1018,14 @@ static void destroy_swap_extents(struct + list_del(&se->list); + kfree(se); + } ++ ++ if (sis->flags & SWP_FILE) { ++ struct file *swap_file = sis->swap_file; ++ struct address_space *mapping = swap_file->f_mapping; ++ ++ sis->flags &= ~SWP_FILE; ++ mapping->a_ops->swapoff(swap_file); ++ } + } + + /* +@@ -1092,7 +1100,9 @@ add_swap_extent(struct swap_info_struct + */ + static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span) + { +- struct inode *inode; ++ struct file *swap_file = sis->swap_file; ++ struct address_space *mapping = swap_file->f_mapping; ++ struct inode *inode = mapping->host; + unsigned blocks_per_page; + unsigned long page_no; + unsigned blkbits; +@@ -1103,13 +1113,22 @@ static int setup_swap_extents(struct swa + int nr_extents = 0; + int ret; + +- inode = sis->swap_file->f_mapping->host; + if (S_ISBLK(inode->i_mode)) { + ret = add_swap_extent(sis, 0, sis->max, 0); + *span = sis->pages; + goto done; + } + ++ if (mapping->a_ops->swapon) { ++ ret = mapping->a_ops->swapon(swap_file); ++ if (!ret) { ++ sis->flags |= SWP_FILE; ++ ret = add_swap_extent(sis, 0, sis->max, 0); ++ *span = sis->pages; ++ } ++ goto done; ++ } ++ + blkbits = inode->i_blkbits; + blocks_per_page = PAGE_SIZE >> blkbits; + +@@ -1683,7 +1702,7 @@ SYSCALL_DEFINE2(swapon, const char __use + else + p->prio = --least_priority; + p->swap_map = swap_map; +- p->flags = SWP_ACTIVE; ++ p->flags |= SWP_WRITEOK; + nr_swap_pages += nr_good_pages; + total_swap_pages += nr_good_pages; + +@@ -1823,6 +1842,13 @@ get_swap_info_struct(unsigned type) + return &swap_info[type]; + } + ++struct swap_info_struct *page_swap_info(struct page *page) ++{ ++ swp_entry_t swap = { .val = page_private(page) }; ++ BUG_ON(!PageSwapCache(page)); ++ return &swap_info[swp_type(swap)]; ++} ++ + /* + * swap_lock prevents swap_map being freed. Don't grab an extra + * reference on the swaphandle, it doesn't matter if it becomes unused. diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-27-mm-page_file_methods.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-27-mm-page_file_methods.patch new file mode 100644 index 000000000..73670761b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-27-mm-page_file_methods.patch @@ -0,0 +1,115 @@ +From: Peter Zijlstra +Subject: mm: methods for teaching filesystems about PG_swapcache pages +Patch-mainline: No +References: FATE#303834 + +In order to teach filesystems to handle swap cache pages, three new page +functions are introduced: + + pgoff_t page_file_index(struct page *); + loff_t page_file_offset(struct page *); + struct address_space *page_file_mapping(struct page *); + +page_file_index() - gives the offset of this page in the file in +PAGE_CACHE_SIZE blocks. Like page->index is for mapped pages, this function +also gives the correct index for PG_swapcache pages. + +page_file_offset() - uses page_file_index(), so that it will give the expected +result, even for PG_swapcache pages. + +page_file_mapping() - gives the mapping backing the actual page; that is for +swap cache pages it will give swap_file->f_mapping. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + include/linux/mm.h | 25 +++++++++++++++++++++++++ + include/linux/pagemap.h | 5 +++++ + mm/swapfile.c | 19 +++++++++++++++++++ + 3 files changed, 49 insertions(+) + +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -658,6 +658,17 @@ static inline struct address_space *page + return mapping; + } + ++extern struct address_space *__page_file_mapping(struct page *); ++ ++static inline ++struct address_space *page_file_mapping(struct page *page) ++{ ++ if (unlikely(PageSwapCache(page))) ++ return __page_file_mapping(page); ++ ++ return page->mapping; ++} ++ + static inline int PageAnon(struct page *page) + { + return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0; +@@ -674,6 +685,20 @@ static inline pgoff_t page_index(struct + return page->index; + } + ++extern pgoff_t __page_file_index(struct page *page); ++ ++/* ++ * Return the file index of the page. Regular pagecache pages use ->index ++ * whereas swapcache pages use swp_offset(->private) ++ */ ++static inline pgoff_t page_file_index(struct page *page) ++{ ++ if (unlikely(PageSwapCache(page))) ++ return __page_file_index(page); ++ ++ return page->index; ++} ++ + /* + * The atomic page->_mapcount, like _count, starts from -1: + * so that transitions both from it and to it can be tracked, +--- a/include/linux/pagemap.h ++++ b/include/linux/pagemap.h +@@ -259,6 +259,11 @@ static inline loff_t page_offset(struct + return ((loff_t)page->index) << PAGE_CACHE_SHIFT; + } + ++static inline loff_t page_file_offset(struct page *page) ++{ ++ return ((loff_t)page_file_index(page)) << PAGE_CACHE_SHIFT; ++} ++ + static inline pgoff_t linear_page_index(struct vm_area_struct *vma, + unsigned long address) + { +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -1856,6 +1856,25 @@ struct swap_info_struct *page_swap_info( + } + + /* ++ * out-of-line __page_file_ methods to avoid include hell. ++ */ ++ ++struct address_space *__page_file_mapping(struct page *page) ++{ ++ VM_BUG_ON(!PageSwapCache(page)); ++ return page_swap_info(page)->swap_file->f_mapping; ++} ++EXPORT_SYMBOL_GPL(__page_file_mapping); ++ ++pgoff_t __page_file_index(struct page *page) ++{ ++ swp_entry_t swap = { .val = page_private(page) }; ++ VM_BUG_ON(!PageSwapCache(page)); ++ return swp_offset(swap); ++} ++EXPORT_SYMBOL_GPL(__page_file_index); ++ ++/* + * swap_lock prevents swap_map being freed. Don't grab an extra + * reference on the swaphandle, it doesn't matter if it becomes unused. + */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-28-nfs-swapcache.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-28-nfs-swapcache.patch new file mode 100644 index 000000000..78a363119 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-28-nfs-swapcache.patch @@ -0,0 +1,336 @@ +From: Peter Zijlstra +Subject: nfs: teach the NFS client how to treat PG_swapcache pages +Patch-mainline: No +References: FATE#303834 + +Replace all relevant occurences of page->index and page->mapping in the NFS +client with the new page_file_index() and page_file_mapping() functions. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + fs/nfs/file.c | 6 +++--- + fs/nfs/internal.h | 7 ++++--- + fs/nfs/pagelist.c | 6 +++--- + fs/nfs/read.c | 6 +++--- + fs/nfs/write.c | 53 +++++++++++++++++++++++++++-------------------------- + 5 files changed, 40 insertions(+), 38 deletions(-) + +--- a/fs/nfs/file.c ++++ b/fs/nfs/file.c +@@ -413,7 +413,7 @@ static void nfs_invalidate_page(struct p + if (offset != 0) + return; + /* Cancel any unstarted writes on this page */ +- nfs_wb_page_cancel(page->mapping->host, page); ++ nfs_wb_page_cancel(page_file_mapping(page)->host, page); + } + + static int nfs_release_page(struct page *page, gfp_t gfp) +@@ -426,7 +426,7 @@ static int nfs_release_page(struct page + + static int nfs_launder_page(struct page *page) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + + dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", + inode->i_ino, (long long)page_offset(page)); +@@ -463,7 +463,7 @@ static int nfs_vm_page_mkwrite(struct vm + (long long)page_offset(page)); + + lock_page(page); +- mapping = page->mapping; ++ mapping = page_file_mapping(page); + if (mapping != dentry->d_inode->i_mapping) + goto out_unlock; + +--- a/fs/nfs/internal.h ++++ b/fs/nfs/internal.h +@@ -253,13 +253,14 @@ void nfs_super_set_maxbytes(struct super + static inline + unsigned int nfs_page_length(struct page *page) + { +- loff_t i_size = i_size_read(page->mapping->host); ++ loff_t i_size = i_size_read(page_file_mapping(page)->host); + + if (i_size > 0) { ++ pgoff_t page_index = page_file_index(page); + pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; +- if (page->index < end_index) ++ if (page_index < end_index) + return PAGE_CACHE_SIZE; +- if (page->index == end_index) ++ if (page_index == end_index) + return ((i_size - 1) & ~PAGE_CACHE_MASK) + 1; + } + return 0; +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -76,11 +76,11 @@ nfs_create_request(struct nfs_open_conte + * update_nfs_request below if the region is not locked. */ + req->wb_page = page; + atomic_set(&req->wb_complete, 0); +- req->wb_index = page->index; ++ req->wb_index = page_file_index(page); + page_cache_get(page); + BUG_ON(PagePrivate(page)); + BUG_ON(!PageLocked(page)); +- BUG_ON(page->mapping->host != inode); ++ BUG_ON(page_file_mapping(page)->host != inode); + req->wb_offset = offset; + req->wb_pgbase = offset; + req->wb_bytes = count; +@@ -376,7 +376,7 @@ void nfs_pageio_cond_complete(struct nfs + * nfs_scan_list - Scan a list for matching requests + * @nfsi: NFS inode + * @dst: Destination list +- * @idx_start: lower bound of page->index to scan ++ * @idx_start: lower bound of page_file_index(page) to scan + * @npages: idx_start + npages sets the upper bound to scan. + * @tag: tag to scan for + * +--- a/fs/nfs/read.c ++++ b/fs/nfs/read.c +@@ -475,11 +475,11 @@ static const struct rpc_call_ops nfs_rea + int nfs_readpage(struct file *file, struct page *page) + { + struct nfs_open_context *ctx; +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + int error; + + dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", +- page, PAGE_CACHE_SIZE, page->index); ++ page, PAGE_CACHE_SIZE, page_file_index(page)); + nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); + nfs_add_stats(inode, NFSIOS_READPAGES, 1); + +@@ -526,7 +526,7 @@ static int + readpage_async_filler(void *data, struct page *page) + { + struct nfs_readdesc *desc = (struct nfs_readdesc *)data; +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + struct nfs_page *new; + unsigned int len; + int error; +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -118,7 +118,7 @@ static struct nfs_page *nfs_page_find_re + + static struct nfs_page *nfs_page_find_request(struct page *page) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + struct nfs_page *req = NULL; + + spin_lock(&inode->i_lock); +@@ -130,16 +130,16 @@ static struct nfs_page *nfs_page_find_re + /* Adjust the file length if we're writing beyond the end */ + static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + loff_t end, i_size; + pgoff_t end_index; + + spin_lock(&inode->i_lock); + i_size = i_size_read(inode); + end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; +- if (i_size > 0 && page->index < end_index) ++ if (i_size > 0 && page_file_index(page) < end_index) + goto out; +- end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); ++ end = page_file_offset(page) + ((loff_t)offset+count); + if (i_size >= end) + goto out; + i_size_write(inode, end); +@@ -152,7 +152,7 @@ out: + static void nfs_set_pageerror(struct page *page) + { + SetPageError(page); +- nfs_zap_mapping(page->mapping->host, page->mapping); ++ nfs_zap_mapping(page_file_mapping(page)->host, page_file_mapping(page)); + } + + /* We can set the PG_uptodate flag if we see that a write request +@@ -193,7 +193,7 @@ static int nfs_set_page_writeback(struct + int ret = test_set_page_writeback(page); + + if (!ret) { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + struct nfs_server *nfss = NFS_SERVER(inode); + + if (atomic_long_inc_return(&nfss->writeback) > +@@ -205,7 +205,7 @@ static int nfs_set_page_writeback(struct + + static void nfs_end_page_writeback(struct page *page) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + struct nfs_server *nfss = NFS_SERVER(inode); + + end_page_writeback(page); +@@ -220,7 +220,7 @@ static void nfs_end_page_writeback(struc + static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, + struct page *page) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + struct nfs_page *req; + int ret; + +@@ -263,12 +263,12 @@ static int nfs_page_async_flush(struct n + + static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + + nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); + nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); + +- nfs_pageio_cond_complete(pgio, page->index); ++ nfs_pageio_cond_complete(pgio, page_file_index(page)); + return nfs_page_async_flush(pgio, page); + } + +@@ -280,7 +280,7 @@ static int nfs_writepage_locked(struct p + struct nfs_pageio_descriptor pgio; + int err; + +- nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc)); ++ nfs_pageio_init_write(&pgio, page_file_mapping(page)->host, wb_priority(wbc)); + err = nfs_do_writepage(page, wbc, &pgio); + nfs_pageio_complete(&pgio); + if (err < 0) +@@ -409,7 +409,8 @@ nfs_mark_request_commit(struct nfs_page + NFS_PAGE_TAG_COMMIT); + spin_unlock(&inode->i_lock); + inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); +- inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); ++ inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info, ++ BDI_RECLAIMABLE); + __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + } + +@@ -420,7 +421,7 @@ nfs_clear_request_commit(struct nfs_page + + if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) { + dec_zone_page_state(page, NR_UNSTABLE_NFS); +- dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE); ++ dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE); + return 1; + } + return 0; +@@ -526,7 +527,7 @@ static void nfs_cancel_commit_list(struc + * nfs_scan_commit - Scan an inode for commit requests + * @inode: NFS inode to scan + * @dst: destination list +- * @idx_start: lower bound of page->index to scan. ++ * @idx_start: lower bound of page_file_index(page) to scan. + * @npages: idx_start + npages sets the upper bound to scan. + * + * Moves requests from the inode's 'commit' request list. +@@ -637,7 +638,7 @@ out_err: + static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx, + struct page *page, unsigned int offset, unsigned int bytes) + { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + struct nfs_page *req; + int error; + +@@ -692,7 +693,7 @@ int nfs_flush_incompatible(struct file * + nfs_release_request(req); + if (!do_flush) + return 0; +- status = nfs_wb_page(page->mapping->host, page); ++ status = nfs_wb_page(page_file_mapping(page)->host, page); + } while (status == 0); + return status; + } +@@ -718,7 +719,7 @@ int nfs_updatepage(struct file *file, st + unsigned int offset, unsigned int count) + { + struct nfs_open_context *ctx = nfs_file_open_context(file); +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + int status = 0; + + nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); +@@ -726,7 +727,7 @@ int nfs_updatepage(struct file *file, st + dprintk("NFS: nfs_updatepage(%s/%s %d@%lld)\n", + file->f_path.dentry->d_parent->d_name.name, + file->f_path.dentry->d_name.name, count, +- (long long)(page_offset(page) + offset)); ++ (long long)(page_file_offset(page) + offset)); + + /* If we're not using byte range locks, and we know the page + * is up to date, it may be more efficient to extend the write +@@ -1001,7 +1002,7 @@ static void nfs_writeback_release_partia + } + + if (nfs_write_need_commit(data)) { +- struct inode *inode = page->mapping->host; ++ struct inode *inode = page_file_mapping(page)->host; + + spin_lock(&inode->i_lock); + if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) { +@@ -1262,7 +1263,7 @@ nfs_commit_list(struct inode *inode, str + nfs_list_remove_request(req); + nfs_mark_request_commit(req); + dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); +- dec_bdi_stat(req->wb_page->mapping->backing_dev_info, ++ dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info, + BDI_RECLAIMABLE); + nfs_clear_page_tag_locked(req); + } +@@ -1453,10 +1454,10 @@ int nfs_wb_nocommit(struct inode *inode) + int nfs_wb_page_cancel(struct inode *inode, struct page *page) + { + struct nfs_page *req; +- loff_t range_start = page_offset(page); ++ loff_t range_start = page_file_offset(page); + loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + struct writeback_control wbc = { +- .bdi = page->mapping->backing_dev_info, ++ .bdi = page_file_mapping(page)->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_start = range_start, +@@ -1489,7 +1490,7 @@ int nfs_wb_page_cancel(struct inode *ino + } + if (!PagePrivate(page)) + return 0; +- ret = nfs_sync_mapping_wait(page->mapping, &wbc, FLUSH_INVALIDATE); ++ ret = nfs_sync_mapping_wait(page_file_mapping(page), &wbc, FLUSH_INVALIDATE); + out: + return ret; + } +@@ -1497,10 +1498,10 @@ out: + static int nfs_wb_page_priority(struct inode *inode, struct page *page, + int how) + { +- loff_t range_start = page_offset(page); ++ loff_t range_start = page_file_offset(page); + loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); + struct writeback_control wbc = { +- .bdi = page->mapping->backing_dev_info, ++ .bdi = page_file_mapping(page)->backing_dev_info, + .sync_mode = WB_SYNC_ALL, + .nr_to_write = LONG_MAX, + .range_start = range_start, +@@ -1515,7 +1516,7 @@ static int nfs_wb_page_priority(struct i + goto out_error; + } else if (!PagePrivate(page)) + break; +- ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); ++ ret = nfs_sync_mapping_wait(page_file_mapping(page), &wbc, how); + if (ret < 0) + goto out_error; + } while (PagePrivate(page)); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-29-nfs-swapper.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-29-nfs-swapper.patch new file mode 100644 index 000000000..fe029991c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-29-nfs-swapper.patch @@ -0,0 +1,170 @@ +From: Peter Zijlstra +Subject: nfs: disable data cache revalidation for swapfiles +Patch-mainline: No +References: FATE#303834 + +Do as Trond suggested: + http://lkml.org/lkml/2006/8/25/348 + +Disable NFS data cache revalidation on swap files since it doesn't really +make sense to have other clients change the file while you are using it. + +Thereby we can stop setting PG_private on swap pages, since there ought to +be no further races with invalidate_inode_pages2() to deal with. + +And since we cannot set PG_private we cannot use page->private (which is +already used by PG_swapcache pages anyway) to store the nfs_page. Thus +augment the new nfs_page_find_request logic. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + fs/nfs/inode.c | 6 ++++ + fs/nfs/write.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 64 insertions(+), 13 deletions(-) + +--- a/fs/nfs/inode.c ++++ b/fs/nfs/inode.c +@@ -824,6 +824,12 @@ int nfs_revalidate_mapping_nolock(struct + struct nfs_inode *nfsi = NFS_I(inode); + int ret = 0; + ++ /* ++ * swapfiles are not supposed to be shared. ++ */ ++ if (IS_SWAPFILE(inode)) ++ goto out; ++ + if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) + || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { + ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -104,25 +104,62 @@ static void nfs_context_set_write_error( + set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); + } + +-static struct nfs_page *nfs_page_find_request_locked(struct page *page) ++static struct nfs_page * ++__nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page, int get) + { + struct nfs_page *req = NULL; + +- if (PagePrivate(page)) { ++ if (PagePrivate(page)) + req = (struct nfs_page *)page_private(page); +- if (req != NULL) +- kref_get(&req->wb_kref); +- } ++ else if (unlikely(PageSwapCache(page))) ++ req = radix_tree_lookup(&nfsi->nfs_page_tree, page_file_index(page)); ++ ++ if (get && req) ++ kref_get(&req->wb_kref); ++ + return req; + } + ++static inline struct nfs_page * ++nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page) ++{ ++ return __nfs_page_find_request_locked(nfsi, page, 1); ++} ++ ++static int __nfs_page_has_request(struct page *page) ++{ ++ struct inode *inode = page_file_mapping(page)->host; ++ struct nfs_page *req = NULL; ++ ++ spin_lock(&inode->i_lock); ++ req = __nfs_page_find_request_locked(NFS_I(inode), page, 0); ++ spin_unlock(&inode->i_lock); ++ ++ /* ++ * hole here plugged by the caller holding onto PG_locked ++ */ ++ ++ return req != NULL; ++} ++ ++static inline int nfs_page_has_request(struct page *page) ++{ ++ if (PagePrivate(page)) ++ return 1; ++ ++ if (unlikely(PageSwapCache(page))) ++ return __nfs_page_has_request(page); ++ ++ return 0; ++} ++ + static struct nfs_page *nfs_page_find_request(struct page *page) + { + struct inode *inode = page_file_mapping(page)->host; + struct nfs_page *req = NULL; + + spin_lock(&inode->i_lock); +- req = nfs_page_find_request_locked(page); ++ req = nfs_page_find_request_locked(NFS_I(inode), page); + spin_unlock(&inode->i_lock); + return req; + } +@@ -226,7 +263,7 @@ static int nfs_page_async_flush(struct n + + spin_lock(&inode->i_lock); + for(;;) { +- req = nfs_page_find_request_locked(page); ++ req = nfs_page_find_request_locked(NFS_I(inode), page); + if (req == NULL) { + spin_unlock(&inode->i_lock); + return 0; +@@ -349,8 +386,14 @@ static int nfs_inode_add_request(struct + if (nfs_have_delegation(inode, FMODE_WRITE)) + nfsi->change_attr++; + } +- SetPagePrivate(req->wb_page); +- set_page_private(req->wb_page, (unsigned long)req); ++ /* ++ * Swap-space should not get truncated. Hence no need to plug the race ++ * with invalidate/truncate. ++ */ ++ if (likely(!PageSwapCache(req->wb_page))) { ++ SetPagePrivate(req->wb_page); ++ set_page_private(req->wb_page, (unsigned long)req); ++ } + nfsi->npages++; + kref_get(&req->wb_kref); + radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, +@@ -372,8 +415,10 @@ static void nfs_inode_remove_request(str + BUG_ON (!NFS_WBACK_BUSY(req)); + + spin_lock(&inode->i_lock); +- set_page_private(req->wb_page, 0); +- ClearPagePrivate(req->wb_page); ++ if (likely(!PageSwapCache(req->wb_page))) { ++ set_page_private(req->wb_page, 0); ++ ClearPagePrivate(req->wb_page); ++ } + radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); + nfsi->npages--; + if (!nfsi->npages) { +@@ -577,7 +622,7 @@ static struct nfs_page *nfs_try_to_updat + spin_lock(&inode->i_lock); + + for (;;) { +- req = nfs_page_find_request_locked(page); ++ req = nfs_page_find_request_locked(NFS_I(inode), page); + if (req == NULL) + goto out_unlock; + +@@ -1488,7 +1533,7 @@ int nfs_wb_page_cancel(struct inode *ino + if (ret < 0) + goto out; + } +- if (!PagePrivate(page)) ++ if (!nfs_page_has_request(page)) + return 0; + ret = nfs_sync_mapping_wait(page_file_mapping(page), &wbc, FLUSH_INVALIDATE); + out: diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-30-nfs-swap_ops.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-30-nfs-swap_ops.patch new file mode 100644 index 000000000..049b78fbf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-30-nfs-swap_ops.patch @@ -0,0 +1,363 @@ +From: Peter Zijlstra +Subject: nfs: enable swap on NFS +Patch-mainline: No +References: FATE#303834 + +Implement all the new swapfile a_ops for NFS. This will set the NFS socket to +SOCK_MEMALLOC and run socket reconnect under PF_MEMALLOC as well as reset +SOCK_MEMALLOC before engaging the protocol ->connect() method. + +PF_MEMALLOC should allow the allocation of struct socket and related objects +and the early (re)setting of SOCK_MEMALLOC should allow us to receive the +packets required for the TCP connection buildup. + +(swapping continues over a server reset during heavy network traffic) + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + fs/Kconfig | 17 ++++++++++ + fs/nfs/file.c | 18 ++++++++++ + fs/nfs/write.c | 22 +++++++++++++ + include/linux/nfs_fs.h | 2 + + include/linux/sunrpc/xprt.h | 5 ++- + net/sunrpc/sched.c | 9 ++++- + net/sunrpc/xprtsock.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 143 insertions(+), 3 deletions(-) + +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -1748,6 +1748,18 @@ config ROOT_NFS + + Most people say N here. + ++config NFS_SWAP ++ bool "Provide swap over NFS support" ++ default n ++ depends on NFS_FS ++ select SUNRPC_SWAP ++ help ++ This option enables swapon to work on files located on NFS mounts. ++ ++ For more details, see Documentation/network-swap.txt ++ ++ If unsure, say N. ++ + config NFSD + tristate "NFS server support" + depends on INET +@@ -1869,6 +1881,11 @@ config SUNRPC_XPRT_RDMA + + If unsure, say N. + ++config SUNRPC_SWAP ++ def_bool n ++ depends on SUNRPC ++ select NETVM ++ + config RPCSEC_GSS_KRB5 + tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" + depends on SUNRPC && EXPERIMENTAL +--- a/fs/nfs/file.c ++++ b/fs/nfs/file.c +@@ -434,6 +434,18 @@ static int nfs_launder_page(struct page + return nfs_wb_page(inode, page); + } + ++#ifdef CONFIG_NFS_SWAP ++static int nfs_swapon(struct file *file) ++{ ++ return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 1); ++} ++ ++static int nfs_swapoff(struct file *file) ++{ ++ return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 0); ++} ++#endif ++ + const struct address_space_operations nfs_file_aops = { + .readpage = nfs_readpage, + .readpages = nfs_readpages, +@@ -446,6 +458,12 @@ const struct address_space_operations nf + .releasepage = nfs_release_page, + .direct_IO = nfs_direct_IO, + .launder_page = nfs_launder_page, ++#ifdef CONFIG_NFS_SWAP ++ .swapon = nfs_swapon, ++ .swapoff = nfs_swapoff, ++ .swap_out = nfs_swap_out, ++ .swap_in = nfs_readpage, ++#endif + }; + + static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -336,6 +336,28 @@ int nfs_writepage(struct page *page, str + return ret; + } + ++static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, ++ unsigned int offset, unsigned int count); ++ ++int nfs_swap_out(struct file *file, struct page *page, ++ struct writeback_control *wbc) ++{ ++ struct nfs_open_context *ctx = nfs_file_open_context(file); ++ int status; ++ ++ status = nfs_writepage_setup(ctx, page, 0, nfs_page_length(page)); ++ if (status < 0) { ++ nfs_set_pageerror(page); ++ goto out; ++ } ++ ++ status = nfs_writepage_locked(page, wbc); ++ ++out: ++ unlock_page(page); ++ return status; ++} ++ + static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data) + { + int ret; +--- a/include/linux/nfs_fs.h ++++ b/include/linux/nfs_fs.h +@@ -464,6 +464,8 @@ extern int nfs_writepages(struct addres + extern int nfs_flush_incompatible(struct file *file, struct page *page); + extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); + extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); ++extern int nfs_swap_out(struct file *file, struct page *page, ++ struct writeback_control *wbc); + + /* + * Try to write back everything synchronously (but check the +--- a/include/linux/sunrpc/xprt.h ++++ b/include/linux/sunrpc/xprt.h +@@ -147,7 +147,9 @@ struct rpc_xprt { + unsigned int max_reqs; /* total slots */ + unsigned long state; /* transport state */ + unsigned char shutdown : 1, /* being shut down */ +- resvport : 1; /* use a reserved port */ ++ resvport : 1, /* use a reserved port */ ++ swapper : 1; /* we're swapping over this ++ transport */ + unsigned int bind_index; /* bind function index */ + + /* +@@ -249,6 +251,7 @@ void xprt_release_rqst_cong(struct rpc + void xprt_disconnect_done(struct rpc_xprt *xprt); + void xprt_force_disconnect(struct rpc_xprt *xprt); + void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); ++int xs_swapper(struct rpc_xprt *xprt, int enable); + + /* + * Reserved bit positions in xprt->state +--- a/net/sunrpc/sched.c ++++ b/net/sunrpc/sched.c +@@ -729,7 +729,10 @@ struct rpc_buffer { + void *rpc_malloc(struct rpc_task *task, size_t size) + { + struct rpc_buffer *buf; +- gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT; ++ gfp_t gfp = GFP_NOWAIT; ++ ++ if (RPC_IS_SWAPPER(task)) ++ gfp |= __GFP_MEMALLOC; + + size += sizeof(struct rpc_buffer); + if (size <= RPC_BUFFER_MAXSIZE) +@@ -800,6 +803,8 @@ static void rpc_init_task(struct rpc_tas + kref_get(&task->tk_client->cl_kref); + if (task->tk_client->cl_softrtry) + task->tk_flags |= RPC_TASK_SOFT; ++ if (task->tk_client->cl_xprt->swapper) ++ task->tk_flags |= RPC_TASK_SWAPPER; + } + + if (task->tk_ops->rpc_call_prepare != NULL) +@@ -825,7 +830,7 @@ static void rpc_init_task(struct rpc_tas + static struct rpc_task * + rpc_alloc_task(void) + { +- return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); ++ return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOIO); + } + + /* +--- a/net/sunrpc/xprtsock.c ++++ b/net/sunrpc/xprtsock.c +@@ -1454,6 +1454,55 @@ static inline void xs_reclassify_socket6 + } + #endif + ++#ifdef CONFIG_SUNRPC_SWAP ++static void xs_set_memalloc(struct rpc_xprt *xprt) ++{ ++ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); ++ ++ if (xprt->swapper) ++ sk_set_memalloc(transport->inet); ++} ++ ++#define RPC_BUF_RESERVE_PAGES \ ++ kmalloc_estimate_objs(sizeof(struct rpc_rqst), GFP_KERNEL, RPC_MAX_SLOT_TABLE) ++#define RPC_RESERVE_PAGES (RPC_BUF_RESERVE_PAGES + TX_RESERVE_PAGES) ++ ++/** ++ * xs_swapper - Tag this transport as being used for swap. ++ * @xprt: transport to tag ++ * @enable: enable/disable ++ * ++ */ ++int xs_swapper(struct rpc_xprt *xprt, int enable) ++{ ++ struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); ++ int err = 0; ++ ++ if (enable) { ++ /* ++ * keep one extra sock reference so the reserve won't dip ++ * when the socket gets reconnected. ++ */ ++ err = sk_adjust_memalloc(1, RPC_RESERVE_PAGES); ++ if (!err) { ++ xprt->swapper = 1; ++ xs_set_memalloc(xprt); ++ } ++ } else if (xprt->swapper) { ++ xprt->swapper = 0; ++ sk_clear_memalloc(transport->inet); ++ sk_adjust_memalloc(-1, -RPC_RESERVE_PAGES); ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(xs_swapper); ++#else ++static void xs_set_memalloc(struct rpc_xprt *xprt) ++{ ++} ++#endif ++ + static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) + { + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); +@@ -1478,6 +1527,8 @@ static void xs_udp_finish_connecting(str + transport->sock = sock; + transport->inet = sk; + ++ xs_set_memalloc(xprt); ++ + write_unlock_bh(&sk->sk_callback_lock); + } + xs_udp_do_set_buffer_size(xprt); +@@ -1495,11 +1546,15 @@ static void xs_udp_connect_worker4(struc + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; ++ unsigned long pflags = current->flags; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + ++ if (xprt->swapper) ++ current->flags |= PF_MEMALLOC; ++ + /* Start by resetting any existing state */ + xs_close(xprt); + +@@ -1522,6 +1577,7 @@ static void xs_udp_connect_worker4(struc + out: + xprt_wake_pending_tasks(xprt, status); + xprt_clear_connecting(xprt); ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); + } + + /** +@@ -1536,11 +1592,15 @@ static void xs_udp_connect_worker6(struc + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; ++ unsigned long pflags = current->flags; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + ++ if (xprt->swapper) ++ current->flags |= PF_MEMALLOC; ++ + /* Start by resetting any existing state */ + xs_close(xprt); + +@@ -1563,6 +1623,7 @@ static void xs_udp_connect_worker6(struc + out: + xprt_wake_pending_tasks(xprt, status); + xprt_clear_connecting(xprt); ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); + } + + /* +@@ -1632,6 +1693,8 @@ static int xs_tcp_finish_connecting(stru + write_unlock_bh(&sk->sk_callback_lock); + } + ++ xs_set_memalloc(xprt); ++ + /* Tell the socket layer to start connecting... */ + xprt->stat.connect_count++; + xprt->stat.connect_start = jiffies; +@@ -1650,11 +1713,15 @@ static void xs_tcp_connect_worker4(struc + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; ++ unsigned long pflags = current->flags; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + ++ if (xprt->swapper) ++ current->flags |= PF_MEMALLOC; ++ + if (!sock) { + /* start from scratch */ + if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { +@@ -1696,6 +1763,7 @@ out: + xprt_wake_pending_tasks(xprt, status); + out_clear: + xprt_clear_connecting(xprt); ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); + } + + /** +@@ -1710,11 +1778,15 @@ static void xs_tcp_connect_worker6(struc + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; ++ unsigned long pflags = current->flags; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + ++ if (xprt->swapper) ++ current->flags |= PF_MEMALLOC; ++ + if (!sock) { + /* start from scratch */ + if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { +@@ -1755,6 +1827,7 @@ out: + xprt_wake_pending_tasks(xprt, status); + out_clear: + xprt_clear_connecting(xprt); ++ tsk_restore_flags(current, pflags, PF_MEMALLOC); + } + + /** diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-31-nfs-alloc-recursions.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-31-nfs-alloc-recursions.patch new file mode 100644 index 000000000..f3c8da248 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-31-nfs-alloc-recursions.patch @@ -0,0 +1,65 @@ +From: Peter Zijlstra +Subject: nfs: fix various memory recursions possible with swap over NFS. +Patch-mainline: No +References: FATE#303834 + +GFP_NOFS is _more_ permissive than GFP_NOIO in that it will initiate IO, +just not of any filesystem data. + +The problem is that previuosly NOFS was correct because that avoids +recursion into the NFS code, it now is not, because also IO (swap) can +lead to this recursion. + +Signed-off-by: Peter Zijlstra +Acked-by: Neil Brown +Acked-by: Suresh Jayaraman + +--- + fs/nfs/pagelist.c | 2 +- + fs/nfs/write.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +Index: linux-2.6.26/fs/nfs/write.c +=================================================================== +--- linux-2.6.26.orig/fs/nfs/write.c ++++ linux-2.6.26/fs/nfs/write.c +@@ -47,7 +47,7 @@ static mempool_t *nfs_commit_mempool; + + struct nfs_write_data *nfs_commitdata_alloc(void) + { +- struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); ++ struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOIO); + + if (p) { + memset(p, 0, sizeof(*p)); +@@ -65,7 +65,7 @@ void nfs_commit_free(struct nfs_write_da + + struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) + { +- struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); ++ struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO); + + if (p) { + memset(p, 0, sizeof(*p)); +@@ -74,7 +74,7 @@ struct nfs_write_data *nfs_writedata_all + if (pagecount <= ARRAY_SIZE(p->page_array)) + p->pagevec = p->page_array; + else { +- p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); ++ p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOIO); + if (!p->pagevec) { + mempool_free(p, nfs_wdata_mempool); + p = NULL; +Index: linux-2.6.26/fs/nfs/pagelist.c +=================================================================== +--- linux-2.6.26.orig/fs/nfs/pagelist.c ++++ linux-2.6.26/fs/nfs/pagelist.c +@@ -27,7 +27,7 @@ static inline struct nfs_page * + nfs_page_alloc(void) + { + struct nfs_page *p; +- p = kmem_cache_alloc(nfs_page_cachep, GFP_KERNEL); ++ p = kmem_cache_alloc(nfs_page_cachep, GFP_NOIO); + if (p) { + memset(p, 0, sizeof(*p)); + INIT_LIST_HEAD(&p->wb_list); diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-fix-sync b/src/patches/suse-2.6.27.31/patches.suse/SoN-fix-sync new file mode 100644 index 000000000..825bd09ab --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-fix-sync @@ -0,0 +1,52 @@ +References: 441793 +Subject: Cope with racy nature of sync_page in swap_sync_page + +From: NeilBrown + +sync_page is called without that PageLock held. This means that, +for example, PageSwapCache can be cleared at any time. +We need to be careful not to put much trust any any part of the page. + +So allow page_swap_info to return NULL of the page is no longer +in a SwapCache, and handle the NULL gracefully in swap_sync_page. + +No other calls need to handle the NULL as that all hold PageLock, +so PageSwapCache cannot be cleared by surprise. Add a WARN_ON to +document this fact and help find out if I am wrong. + +Acked-By: Miklos Szeredi +Signed-off-by: NeilBrown + +--- + mm/page_io.c | 2 ++ + mm/swapfile.c | 9 ++++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +--- linux-2.6.27.orig/mm/page_io.c ++++ linux-2.6.27/mm/page_io.c +@@ -139,6 +139,8 @@ void swap_sync_page(struct page *page) + { + struct swap_info_struct *sis = page_swap_info(page); + ++ if (!sis) ++ return; + if (sis->flags & SWP_FILE) { + struct address_space *mapping = sis->swap_file->f_mapping; + +--- linux-2.6.27.orig/mm/swapfile.c ++++ linux-2.6.27/mm/swapfile.c +@@ -1845,7 +1845,13 @@ get_swap_info_struct(unsigned type) + struct swap_info_struct *page_swap_info(struct page *page) + { + swp_entry_t swap = { .val = page_private(page) }; +- BUG_ON(!PageSwapCache(page)); ++ if (!PageSwapCache(page) || !swap.val) { ++ /* This should only happen from sync_page. ++ * In other cases the page should be locked and ++ * should be in a SwapCache ++ */ ++ return NULL; ++ } + return &swap_info[swp_type(swap)]; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/SoN-fix-uninitialized-variable.patch b/src/patches/suse-2.6.27.31/patches.suse/SoN-fix-uninitialized-variable.patch new file mode 100644 index 000000000..adeb9b1d8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/SoN-fix-uninitialized-variable.patch @@ -0,0 +1,42 @@ +From: Miklos Szeredi +Subject: Fix use of uninitialized variable in cache_grow() +Patch-mainline: no +References: bnc#444597 + +This fixes a bug in SoN-08-reserve-slub.patch. + +If cache_grow() was called with objp != NULL then the 'reserve' local +variable wasn't initialized. This resulted in ac->reserve being set to +a rubbish value. Due to this in some circumstances huge amounts of +slab pages were allocated (due to slab_force_alloc() returning true), +which caused atomic page allocation failures and slowdown of the +system. + +Signed-off-by: Miklos Szeredi +--- + mm/slab.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +Index: linux-2.6.27/mm/slab.c +=================================================================== +--- linux-2.6.27.orig/mm/slab.c 2008-12-03 22:11:12.000000000 +0100 ++++ linux-2.6.27/mm/slab.c 2008-12-03 22:14:37.000000000 +0100 +@@ -2785,7 +2785,7 @@ static int cache_grow(struct kmem_cache + size_t offset; + gfp_t local_flags; + struct kmem_list3 *l3; +- int reserve; ++ int reserve = -1; + + /* + * Be lazy and only check for valid flags here, keeping it out of the +@@ -2841,7 +2841,8 @@ static int cache_grow(struct kmem_cache + if (local_flags & __GFP_WAIT) + local_irq_disable(); + check_irq_off(); +- slab_set_reserve(cachep, reserve); ++ if (reserve != -1) ++ slab_set_reserve(cachep, reserve); + spin_lock(&l3->list_lock); + + /* Make slab active. */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/acpi-dsdt-initrd-v0.9a-2.6.25.patch b/src/patches/suse-2.6.27.31/patches.suse/acpi-dsdt-initrd-v0.9a-2.6.25.patch new file mode 100644 index 000000000..8be472b78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/acpi-dsdt-initrd-v0.9a-2.6.25.patch @@ -0,0 +1,342 @@ +From: Eric Piel +Subject: [PATCH 1/1] ACPI: initramfs DSDT override support +Patch-mainline: not yet + + +Permits to load of DSDT (the main ACPI table) from initramfs. In case this +option is selected, the initramfs is parsed at ACPI initialization (very early +boot time) to look for a file DSDT.aml . This aims at allowing users to +override the DSDT without recompiling the kernel. This is done by adding a new +feature to the initramfs parser so that one specific file can be directly +copied into memory. + +This is derived from the patch v0.8 from http://gaugusch.at/kernel.shtml but +with kernel inclusion in mind: some clean-up's in the documentation, default +set to No, a kernel parameter to disable it at runtime, and most important, a +different approach for reading the initramfs which avoids using the filesystem +infrastructure. + +It also contains a fix for compilation on non-ACPI platforms provided by Rene Rebe. + +Signed-off-by: Eric Piel +Signed-off-by: Thomas Renninger +Signed-off-by: Len Brown +--- + Documentation/acpi/dsdt-override.txt | 12 ++++ + Documentation/acpi/initramfs-add-dsdt.sh | 43 +++++++++++++++++ + Documentation/kernel-parameters.txt | 3 + + drivers/acpi/Kconfig | 11 ++++ + drivers/acpi/osl.c | 26 ++++++++++ + drivers/acpi/tables/tbxface.c | 7 -- + init/initramfs.c | 76 +++++++++++++++++++++++++++++++ + 7 files changed, 170 insertions(+), 8 deletions(-) + create mode 100644 Documentation/acpi/initramfs-add-dsdt.sh + +--- a/Documentation/acpi/dsdt-override.txt ++++ b/Documentation/acpi/dsdt-override.txt +@@ -1,7 +1,15 @@ +-Linux supports a method of overriding the BIOS DSDT: ++Linux supports two methods of overriding the BIOS DSDT: + + CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel. + +-When to use this method is described in detail on the ++CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd. ++ ++When to use these methods is described in detail on the + Linux/ACPI home page: + http://www.lesswatts.org/projects/acpi/overridingDSDT.php ++ ++Note that if both options are used, the DSDT supplied ++by the INITRD method takes precedence. ++ ++Documentation/initramfs-add-dsdt.sh is provided for convenience ++for use with the CONFIG_ACPI_CUSTOM_DSDT_INITRD method. +--- /dev/null ++++ b/Documentation/acpi/initramfs-add-dsdt.sh +@@ -0,0 +1,43 @@ ++#!/bin/bash ++# Adds a DSDT file to the initrd (if it's an initramfs) ++# first argument is the name of archive ++# second argument is the name of the file to add ++# The file will be copied as /DSDT.aml ++ ++# 20060126: fix "Premature end of file" with some old cpio (Roland Robic) ++# 20060205: this time it should really work ++ ++# check the arguments ++if [ $# -ne 2 ]; then ++ program_name=$(basename $0) ++ echo "\ ++$program_name: too few arguments ++Usage: $program_name initrd-name.img DSDT-to-add.aml ++Adds a DSDT file to an initrd (in initramfs format) ++ ++ initrd-name.img: filename of the initrd in initramfs format ++ DSDT-to-add.aml: filename of the DSDT file to add ++ " 1>&2 ++ exit 1 ++fi ++ ++# we should check it's an initramfs ++ ++tempcpio=$(mktemp -d) ++# cleanup on exit, hangup, interrupt, quit, termination ++trap 'rm -rf $tempcpio' 0 1 2 3 15 ++ ++# extract the archive ++gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1 ++ ++# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml" ++cp -f "$2" "$tempcpio"/DSDT.aml ++ ++# add the file ++cd "$tempcpio" ++(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1 ++cd "$OLDPWD" ++ ++# re-compress the archive ++gzip -c "$tempcpio"/initramfs.cpio > "$1" ++ +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -179,6 +179,9 @@ and is between 256 and 4096 characters. + + acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT + ++ acpi_no_initrd_override [KNL,ACPI] ++ Disable loading custom ACPI tables from the initramfs ++ + acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS + Format: To spoof as Windows 98: ="Microsoft Windows" + +--- a/drivers/acpi/Kconfig ++++ b/drivers/acpi/Kconfig +@@ -301,6 +301,17 @@ config ACPI_CUSTOM_DSDT + bool + default ACPI_CUSTOM_DSDT_FILE != "" + ++config ACPI_CUSTOM_DSDT_INITRD ++ bool "Read Custom DSDT from initramfs" ++ depends on BLK_DEV_INITRD ++ default n ++ help ++ This option supports a custom DSDT by optionally loading it from initrd. ++ See Documentation/acpi/dsdt-override.txt ++ ++ If you are not using this feature now, but may use it later, ++ it is safe to say Y here. ++ + config ACPI_BLACKLIST_YEAR + int "Disable ACPI for systems before Jan 1st this year" if X86_32 + default 0 +--- a/drivers/acpi/osl.c ++++ b/drivers/acpi/osl.c +@@ -96,6 +96,11 @@ static DEFINE_SPINLOCK(acpi_res_lock); + #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ + static char osi_additional_string[OSI_STRING_LENGTH_MAX]; + ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++static int acpi_no_initrd_override; ++extern struct acpi_table_header *acpi_find_dsdt_initrd(void); ++#endif ++ + /* + * "Ode to _OSI(Linux)" + * +@@ -325,7 +330,7 @@ acpi_os_predefined_override(const struct + return AE_OK; + } + +-acpi_status ++acpi_status __init + acpi_os_table_override(struct acpi_table_header * existing_table, + struct acpi_table_header ** new_table) + { +@@ -338,6 +343,16 @@ acpi_os_table_override(struct acpi_table + if (strncmp(existing_table->signature, "DSDT", 4) == 0) + *new_table = (struct acpi_table_header *)AmlCode; + #endif ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++ if ((strncmp(existing_table->signature, "DSDT", 4) == 0) && ++ !acpi_no_initrd_override) { ++ struct acpi_table_header *initrd_table; ++ ++ initrd_table = acpi_find_dsdt_initrd(); ++ if (initrd_table) ++ *new_table = initrd_table; ++ } ++#endif + if (*new_table != NULL) { + printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " + "this is unsafe: tainting kernel\n", +@@ -348,6 +363,15 @@ acpi_os_table_override(struct acpi_table + return AE_OK; + } + ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++static int __init acpi_no_initrd_override_setup(char *s) ++{ ++ acpi_no_initrd_override = 1; ++ return 1; ++} ++__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup); ++#endif ++ + static irqreturn_t acpi_irq(int irq, void *dev_id) + { + u32 handled; +--- a/drivers/acpi/tables/tbxface.c ++++ b/drivers/acpi/tables/tbxface.c +@@ -487,7 +487,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_by_ind + * the RSDT/XSDT. + * + ******************************************************************************/ +-static acpi_status acpi_tb_load_namespace(void) ++static acpi_status __init acpi_tb_load_namespace(void) + { + acpi_status status; + struct acpi_table_header *table; +@@ -612,7 +612,7 @@ static acpi_status acpi_tb_load_namespac + * + ******************************************************************************/ + +-acpi_status acpi_load_tables(void) ++acpi_status __init acpi_load_tables(void) + { + acpi_status status; + +@@ -630,9 +630,6 @@ acpi_status acpi_load_tables(void) + return_ACPI_STATUS(status); + } + +-ACPI_EXPORT_SYMBOL(acpi_load_tables) +- +- + /******************************************************************************* + * + * FUNCTION: acpi_install_table_handler +--- a/init/initramfs.c ++++ b/init/initramfs.c +@@ -6,6 +6,9 @@ + #include + #include + #include ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++#include ++#endif + + static __initdata char *message; + static void __init error(char *x) +@@ -80,6 +83,12 @@ static __initdata unsigned long body_len + static __initdata uid_t uid; + static __initdata gid_t gid; + static __initdata unsigned rdev; ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++static __initdata char *file_looked_for; ++static __initdata struct acpi_table_header *file_mem; ++#else ++const char *file_looked_for = NULL; ++#endif + + static void __init parse_header(char *s) + { +@@ -113,6 +122,7 @@ static __initdata enum state { + SkipIt, + GotName, + CopyFile, ++ CopyFileMem, + GotSymlink, + Reset + } state, next_state; +@@ -257,6 +267,9 @@ static int __init do_name(void) + free_hash(); + return 0; + } ++ if (file_looked_for && S_ISREG(mode) && ++ (strcmp(collected, file_looked_for) == 0)) ++ state = CopyFileMem; + if (dry_run) + return 0; + clean_path(collected, mode); +@@ -289,6 +302,40 @@ static int __init do_name(void) + return 0; + } + ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++static int __init do_copy_mem(void) ++{ ++ static void *file_current; /* current position in the memory */ ++ if (file_mem == NULL) { ++ if (body_len < 4) { /* check especially against empty files */ ++ error("file is less than 4 bytes"); ++ return 1; ++ } ++ file_mem = kmalloc(body_len, GFP_ATOMIC); ++ if (!file_mem) { ++ error("failed to allocate enough memory"); ++ return 1; ++ } ++ file_current = file_mem; ++ } ++ if (count >= body_len) { ++ memcpy(file_current, victim, body_len); ++ eat(body_len); ++ file_looked_for = NULL; /* don't find files with same name */ ++ state = SkipIt; ++ return 0; ++ } else { ++ memcpy(file_current, victim, count); ++ file_current += count; ++ body_len -= count; ++ eat(count); ++ return 1; ++ } ++} ++#else ++#define do_copy_mem NULL ++#endif ++ + static int __init do_copy(void) + { + if (count >= body_len) { +@@ -323,6 +370,7 @@ static __initdata int (*actions[])(void) + [SkipIt] = do_skip, + [GotName] = do_name, + [CopyFile] = do_copy, ++ [CopyFileMem] = do_copy_mem, + [GotSymlink] = do_symlink, + [Reset] = do_reset, + }; +@@ -560,3 +608,31 @@ static int __init populate_rootfs(void) + return 0; + } + rootfs_initcall(populate_rootfs); ++ ++#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD ++struct acpi_table_header * __init acpi_find_dsdt_initrd(void) ++{ ++ char *err, *ramfs_dsdt_name = "DSDT.aml"; ++ ++ printk(KERN_INFO "ACPI: Checking initramfs for custom DSDT\n"); ++ file_mem = NULL; ++ file_looked_for = ramfs_dsdt_name; ++ err = unpack_to_rootfs((char *)initrd_start, ++ initrd_end - initrd_start, 1); ++ file_looked_for = NULL; ++ ++ if (err) { ++ /* ++ * Even if reading the DSDT file was successful, ++ * we give up if the initramfs cannot be entirely read. ++ */ ++ kfree(file_mem); ++ printk(KERN_ERR "ACPI: Aborded because %s.\n", err); ++ return NULL; ++ } ++ if (file_mem) ++ printk(KERN_INFO "ACPI: Found DSDT in %s.\n", ramfs_dsdt_name); ++ ++ return file_mem; ++} ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.suse/acpi_osi_sle11_ident.patch b/src/patches/suse-2.6.27.31/patches.suse/acpi_osi_sle11_ident.patch new file mode 100644 index 000000000..49f19a99d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/acpi_osi_sle11_ident.patch @@ -0,0 +1,31 @@ +From: Thomas Renninger +Subject: Provide possibility for vendors to fix BIOS issues for SLE11 only +References: none +Patch-Mainline: never + +These BIOS issues generally should be solved in the mainine kernel. +But such ACPI interpreter fixes often are very intrusive and impossible to +add as a maintenance update. +This interface should only be used by vendors in emergency case, e.g. +for important pre-loads. Use cases could be: + - BIOS cannot generally be fixed because it's already validated against + Windows OSes, with this patch a SLE11 specific BIOS fix can be added + - Kernel cannot be fixed, because the fix would be too intrusive +In most cases both above scenarios would be valid. + +--- + drivers/acpi/utilities/uteval.c | 1 + + 1 file changed, 1 insertion(+) + +Index: linux-2.6.27/drivers/acpi/utilities/uteval.c +=================================================================== +--- linux-2.6.27.orig/drivers/acpi/utilities/uteval.c ++++ linux-2.6.27/drivers/acpi/utilities/uteval.c +@@ -69,6 +69,7 @@ static char *acpi_interfaces_supported[] + "Windows 2001.1", /* Windows Server 2003 */ + "Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */ + "Windows 2006", /* Windows Vista - Added 03/2006 */ ++ "SLE11", /* SLE11 identification */ + + /* Feature Group Strings */ + diff --git a/src/patches/suse-2.6.27.31/patches.suse/bootsplash b/src/patches/suse-2.6.27.31/patches.suse/bootsplash new file mode 100644 index 000000000..661b76c7b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/bootsplash @@ -0,0 +1,2874 @@ +From: mls@suse.de +Subject: Bootsplash for current kernel +Patch-mainline: no +References: none + +Better support for other VTs. Don't change percent or silent status +when installing a new jpeg. Provide splash_set_percent function. + +Signed-off-by: mls@suse.de + +--- + drivers/char/keyboard.c | 9 + drivers/char/n_tty.c | 9 + drivers/char/vt.c | 25 + drivers/video/Kconfig | 4 + drivers/video/Makefile | 1 + drivers/video/bootsplash/Kconfig | 17 + drivers/video/bootsplash/Makefile | 5 + drivers/video/bootsplash/bootsplash.c | 1017 ++++++++++++++++++++++++++++++++++ + drivers/video/bootsplash/bootsplash.h | 44 + + drivers/video/bootsplash/decode-jpg.c | 957 +++++++++++++++++++++++++++++++ + drivers/video/bootsplash/decode-jpg.h | 35 + + drivers/video/bootsplash/render.c | 328 ++++++++++ + drivers/video/console/bitblit.c | 39 + + drivers/video/console/fbcon.c | 53 + + drivers/video/console/fbcon.h | 28 + drivers/video/vesafb.c | 8 + include/linux/console_struct.h | 3 + include/linux/fb.h | 8 + kernel/panic.c | 12 + 19 files changed, 2601 insertions(+), 1 deletion(-) + +--- a/drivers/char/keyboard.c ++++ b/drivers/char/keyboard.c +@@ -1180,6 +1180,15 @@ static void kbd_keycode(unsigned int key + if (keycode < BTN_MISC && printk_ratelimit()) + printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + ++#ifdef CONFIG_BOOTSPLASH ++ /* This code has to be redone for some non-x86 platforms */ ++ if (down == 1 && (keycode == 0x3c || keycode == 0x01)) { /* F2 and ESC on PC keyboard */ ++ extern int splash_verbose(void); ++ if (splash_verbose()) ++ return; ++ } ++#endif ++ + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { + if (!sysrq_down) { +--- a/drivers/char/n_tty.c ++++ b/drivers/char/n_tty.c +@@ -1325,6 +1325,15 @@ do_it_again: + tty->minimum_to_wake = (minimum - (b - buf)); + + if (!input_available_p(tty, 0)) { ++#ifdef CONFIG_BOOTSPLASH ++ if (file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,0) || ++ file->f_dentry->d_inode->i_rdev == MKDEV(TTY_MAJOR,1) || ++ file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,0) || ++ file->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,1)) { ++ extern int splash_verbose(void); ++ (void)splash_verbose(); ++ } ++#endif + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + retval = -EIO; + break; +--- a/drivers/char/vt.c ++++ b/drivers/char/vt.c +@@ -4092,6 +4092,31 @@ void vcs_scr_writew(struct vc_data *vc, + } + } + ++#ifdef CONFIG_BOOTSPLASH ++void con_remap_def_color(struct vc_data *vc, int new_color) ++{ ++ unsigned short *sbuf = vc->vc_screenbuf; ++ unsigned c, len = vc->vc_screenbuf_size >> 1; ++ int old_color; ++ ++ if (sbuf) { ++ old_color = vc->vc_def_color << 8; ++ new_color <<= 8; ++ while(len--) { ++ c = *sbuf; ++ if (((c ^ old_color) & 0xf000) == 0) ++ *sbuf ^= (old_color ^ new_color) & 0xf000; ++ if (((c ^ old_color) & 0x0f00) == 0) ++ *sbuf ^= (old_color ^ new_color) & 0x0f00; ++ sbuf++; ++ } ++ new_color >>= 8; ++ } ++ vc->vc_def_color = vc->vc_color = new_color; ++ update_attr(vc); ++} ++#endif ++ + /* + * Visible symbols for modules + */ +--- /dev/null ++++ b/drivers/video/bootsplash/bootsplash.c +@@ -0,0 +1,1017 @@ ++/* ++ * linux/drivers/video/bootsplash/bootsplash.c - ++ * splash screen handling functions. ++ * ++ * (w) 2001-2004 by Volker Poplawski, , ++ * Stefan Reinauer, , ++ * Steffen Winterfeldt, , ++ * Michael Schroeder ++ * ++ * Ideas & SuSE screen work by Ken Wimer, ++ * ++ * For more information on this code check http://www.bootsplash.org/ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "../console/fbcon.h" ++#include "bootsplash.h" ++#include "decode-jpg.h" ++ ++extern struct fb_ops vesafb_ops; ++extern signed char con2fb_map[MAX_NR_CONSOLES]; ++ ++#define SPLASH_VERSION "3.1.6-2004/03/31" ++ ++/* These errors have to match fbcon-jpegdec.h */ ++static unsigned char *jpg_errors[] = { ++ "no SOI found", ++ "not 8 bit", ++ "height mismatch", ++ "width mismatch", ++ "bad width or height", ++ "too many COMPPs", ++ "illegal HV", ++ "quant table selector", ++ "picture is not YCBCR 221111", ++ "unknow CID in scan", ++ "dct not sequential", ++ "wrong marker", ++ "no EOI", ++ "bad tables", ++ "depth mismatch" ++}; ++ ++static struct jpeg_decdata *decdata = 0; /* private decoder data */ ++ ++static int splash_registered = 0; ++static int splash_usesilent = 0; /* shall we display the silentjpeg? */ ++int splash_default = 0xf01; ++ ++static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth); ++ ++static int __init splash_setup(char *options) ++{ ++ if(!strncmp("silent", options, 6)) { ++ printk(KERN_INFO "bootsplash: silent mode.\n"); ++ splash_usesilent = 1; ++ /* skip "silent," */ ++ if (strlen(options) == 6) ++ return 0; ++ options += 7; ++ } ++ if(!strncmp("verbose", options, 7)) { ++ printk(KERN_INFO "bootsplash: verbose mode.\n"); ++ splash_usesilent = 0; ++ return 0; ++ } ++ splash_default = simple_strtoul(options, NULL, 0); ++ return 0; ++} ++ ++__setup("splash=", splash_setup); ++ ++ ++static int splash_hasinter(unsigned char *buf, int num) ++{ ++ unsigned char *bufend = buf + num * 12; ++ while(buf < bufend) { ++ if (buf[1] > 127) /* inter? */ ++ return 1; ++ buf += buf[3] > 127 ? 24 : 12; /* blend? */ ++ } ++ return 0; ++} ++ ++static int boxextract(unsigned char *buf, unsigned short *dp, unsigned char *cols, int *blendp) ++{ ++ dp[0] = buf[0] | buf[1] << 8; ++ dp[1] = buf[2] | buf[3] << 8; ++ dp[2] = buf[4] | buf[5] << 8; ++ dp[3] = buf[6] | buf[7] << 8; ++ *(unsigned int *)(cols + 0) = ++ *(unsigned int *)(cols + 4) = ++ *(unsigned int *)(cols + 8) = ++ *(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 8); ++ if (dp[1] > 32767) { ++ dp[1] = ~dp[1]; ++ *(unsigned int *)(cols + 4) = *(unsigned int *)(buf + 12); ++ *(unsigned int *)(cols + 8) = *(unsigned int *)(buf + 16); ++ *(unsigned int *)(cols + 12) = *(unsigned int *)(buf + 20); ++ *blendp = 1; ++ return 24; ++ } ++ return 12; ++} ++ ++static void boxit(unsigned char *pic, int bytes, unsigned char *buf, int num, int percent, int overpaint) ++{ ++ int x, y, i, p, doblend, r, g, b, a, add; ++ unsigned short data1[4]; ++ unsigned char cols1[16]; ++ unsigned short data2[4]; ++ unsigned char cols2[16]; ++ unsigned char *bufend; ++ unsigned short *picp; ++ unsigned int stipple[32], sti, stin, stinn, stixs, stixe, stiys, stiye; ++ int xs, xe, ys, ye, xo, yo; ++ ++ if (num == 0) ++ return; ++ bufend = buf + num * 12; ++ stipple[0] = 0xffffffff; ++ stin = 1; ++ stinn = 0; ++ stixs = stixe = 0; ++ stiys = stiye = 0; ++ while(buf < bufend) { ++ doblend = 0; ++ buf += boxextract(buf, data1, cols1, &doblend); ++ if (data1[0] == 32767 && data1[1] == 32767) { ++ /* box stipple */ ++ if (stinn == 32) ++ continue; ++ if (stinn == 0) { ++ stixs = data1[2]; ++ stixe = data1[3]; ++ stiys = stiye = 0; ++ } else if (stinn == 4) { ++ stiys = data1[2]; ++ stiye = data1[3]; ++ } ++ stipple[stinn++] = (cols1[ 0] << 24) | (cols1[ 1] << 16) | (cols1[ 2] << 8) | cols1[ 3] ; ++ stipple[stinn++] = (cols1[ 4] << 24) | (cols1[ 5] << 16) | (cols1[ 6] << 8) | cols1[ 7] ; ++ stipple[stinn++] = (cols1[ 8] << 24) | (cols1[ 9] << 16) | (cols1[10] << 8) | cols1[11] ; ++ stipple[stinn++] = (cols1[12] << 24) | (cols1[13] << 16) | (cols1[14] << 8) | cols1[15] ; ++ stin = stinn; ++ continue; ++ } ++ stinn = 0; ++ if (data1[0] > 32767) ++ buf += boxextract(buf, data2, cols2, &doblend); ++ if (data1[0] == 32767 && data1[1] == 32766) { ++ /* box copy */ ++ i = 12 * (short)data1[3]; ++ doblend = 0; ++ i += boxextract(buf + i, data1, cols1, &doblend); ++ if (data1[0] > 32767) ++ boxextract(buf + i, data2, cols2, &doblend); ++ } ++ if (data1[0] == 32767) ++ continue; ++ if (data1[2] > 32767) { ++ if (overpaint) ++ continue; ++ data1[2] = ~data1[2]; ++ } ++ if (data1[3] > 32767) { ++ if (percent == 65536) ++ continue; ++ data1[3] = ~data1[3]; ++ } ++ if (data1[0] > 32767) { ++ data1[0] = ~data1[0]; ++ for (i = 0; i < 4; i++) ++ data1[i] = (data1[i] * (65536 - percent) + data2[i] * percent) >> 16; ++ for (i = 0; i < 16; i++) ++ cols1[i] = (cols1[i] * (65536 - percent) + cols2[i] * percent) >> 16; ++ } ++ *(unsigned int *)cols2 = *(unsigned int *)cols1; ++ a = cols2[3]; ++ if (a == 0 && !doblend) ++ continue; ++ ++ if (stixs >= 32768) { ++ xo = xs = (stixs ^ 65535) + data1[0]; ++ xe = stixe ? stixe + data1[0] : data1[2]; ++ } else if (stixe >= 32768) { ++ xs = stixs ? data1[2] - stixs : data1[0]; ++ xe = data1[2] - (stixe ^ 65535); ++ xo = xe + 1; ++ } else { ++ xo = xs = stixs; ++ xe = stixe ? stixe : data1[2]; ++ } ++ if (stiys >= 32768) { ++ yo = ys = (stiys ^ 65535) + data1[1]; ++ ye = stiye ? stiye + data1[1] : data1[3]; ++ } else if (stiye >= 32768) { ++ ys = stiys ? data1[3] - stiys : data1[1]; ++ ye = data1[3] - (stiye ^ 65535); ++ yo = ye + 1; ++ } else { ++ yo = ys = stiys; ++ ye = stiye ? stiye : data1[3]; ++ } ++ xo = 32 - (xo & 31); ++ yo = stin - (yo % stin); ++ if (xs < data1[0]) ++ xs = data1[0]; ++ if (xe > data1[2]) ++ xe = data1[2]; ++ if (ys < data1[1]) ++ ys = data1[1]; ++ if (ye > data1[3]) ++ ye = data1[3]; ++ ++ for (y = ys; y <= ye; y++) { ++ sti = stipple[(y + yo) % stin]; ++ x = (xs + xo) & 31; ++ if (x) ++ sti = (sti << x) | (sti >> (32 - x)); ++ if (doblend) { ++ if ((p = data1[3] - data1[1]) != 0) ++ p = ((y - data1[1]) << 16) / p; ++ for (i = 0; i < 8; i++) ++ cols2[i + 8] = (cols1[i] * (65536 - p) + cols1[i + 8] * p) >> 16; ++ } ++ add = (xs & 1); ++ add ^= (add ^ y) & 1 ? 1 : 3; /* 2x2 ordered dithering */ ++ picp = (unsigned short *)(pic + xs * 2 + y * bytes); ++ for (x = xs; x <= xe; x++) { ++ if (!(sti & 0x80000000)) { ++ sti <<= 1; ++ picp++; ++ add ^= 3; ++ continue; ++ } ++ sti = (sti << 1) | 1; ++ if (doblend) { ++ if ((p = data1[2] - data1[0]) != 0) ++ p = ((x - data1[0]) << 16) / p; ++ for (i = 0; i < 4; i++) ++ cols2[i] = (cols2[i + 8] * (65536 - p) + cols2[i + 12] * p) >> 16; ++ a = cols2[3]; ++ } ++ r = cols2[0]; ++ g = cols2[1]; ++ b = cols2[2]; ++ if (a != 255) { ++ i = *picp; ++ r = ((i >> 8 & 0xf8) * (255 - a) + r * a) / 255; ++ g = ((i >> 3 & 0xfc) * (255 - a) + g * a) / 255; ++ b = ((i << 3 & 0xf8) * (255 - a) + b * a) / 255; ++ } ++ #define CLAMP(x) ((x) >= 256 ? 255 : (x)) ++ i = ((CLAMP(r + add*2+1) & 0xf8) << 8) | ++ ((CLAMP(g + add ) & 0xfc) << 3) | ++ ((CLAMP(b + add*2+1) ) >> 3); ++ *picp++ = i; ++ add ^= 3; ++ } ++ } ++ } ++} ++ ++static int splash_check_jpeg(unsigned char *jpeg, int width, int height, int depth) ++{ ++ int size, err; ++ unsigned char *mem; ++ ++ size = ((width + 15) & ~15) * ((height + 15) & ~15) * (depth >> 3); ++ mem = vmalloc(size); ++ if (!mem) { ++ printk(KERN_INFO "bootsplash: no memory for decoded picture.\n"); ++ return -1; ++ } ++ if (!decdata) ++ decdata = vmalloc(sizeof(*decdata)); ++ if ((err = jpeg_decode(jpeg, mem, ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) ++ printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d)\n",jpg_errors[err - 1], err); ++ vfree(mem); ++ return err ? -1 : 0; ++} ++ ++static void splash_free(struct vc_data *vc, struct fb_info *info) ++{ ++ if (!vc->vc_splash_data) ++ return; ++ if (info->silent_screen_base) ++ info->screen_base = info->silent_screen_base; ++ info->silent_screen_base = 0; ++ if (vc->vc_splash_data->splash_silentjpeg) ++ vfree(vc->vc_splash_data->splash_sboxes); ++ vfree(vc->vc_splash_data); ++ vc->vc_splash_data = 0; ++ info->splash_data = 0; ++} ++ ++static int splash_mkpenguin(struct splash_data *data, int pxo, int pyo, int pwi, int phe, int pr, int pg, int pb) ++{ ++ unsigned char *buf; ++ int i; ++ ++ if (pwi ==0 || phe == 0) ++ return 0; ++ buf = (unsigned char *)data + sizeof(*data); ++ pwi += pxo - 1; ++ phe += pyo - 1; ++ *buf++ = pxo; ++ *buf++ = pxo >> 8; ++ *buf++ = pyo; ++ *buf++ = pyo >> 8; ++ *buf++ = pwi; ++ *buf++ = pwi >> 8; ++ *buf++ = phe; ++ *buf++ = phe >> 8; ++ *buf++ = pr; ++ *buf++ = pg; ++ *buf++ = pb; ++ *buf++ = 0; ++ for (i = 0; i < 12; i++, buf++) ++ *buf = buf[-12]; ++ buf[-24] ^= 0xff; ++ buf[-23] ^= 0xff; ++ buf[-1] = 0xff; ++ return 2; ++} ++ ++static const int splash_offsets[3][16] = { ++ /* len, unit, size, state, fgcol, col, xo, yo, wi, he ++ boxcnt, ssize, sboxcnt, percent, overok, palcnt */ ++ /* V1 */ ++ { 20, -1, 16, -1, -1, -1, 8, 10, 12, 14, ++ -1, -1, -1, -1, -1, -1 }, ++ /* V2 */ ++ { 35, 8, 12, 9, 10, 11, 16, 18, 20, 22, ++ -1, -1, -1, -1, -1, -1 }, ++ /* V3 */ ++ { 38, 8, 12, 9, 10, 11, 16, 18, 20, 22, ++ 24, 28, 32, 34, 36, 37 }, ++}; ++ ++#define SPLASH_OFF_LEN offsets[0] ++#define SPLASH_OFF_UNIT offsets[1] ++#define SPLASH_OFF_SIZE offsets[2] ++#define SPLASH_OFF_STATE offsets[3] ++#define SPLASH_OFF_FGCOL offsets[4] ++#define SPLASH_OFF_COL offsets[5] ++#define SPLASH_OFF_XO offsets[6] ++#define SPLASH_OFF_YO offsets[7] ++#define SPLASH_OFF_WI offsets[8] ++#define SPLASH_OFF_HE offsets[9] ++#define SPLASH_OFF_BOXCNT offsets[10] ++#define SPLASH_OFF_SSIZE offsets[11] ++#define SPLASH_OFF_SBOXCNT offsets[12] ++#define SPLASH_OFF_PERCENT offsets[13] ++#define SPLASH_OFF_OVEROK offsets[14] ++#define SPLASH_OFF_PALCNT offsets[15] ++ ++static inline int splash_getb(unsigned char *pos, int off) ++{ ++ return off == -1 ? 0 : pos[off]; ++} ++ ++static inline int splash_gets(unsigned char *pos, int off) ++{ ++ return off == -1 ? 0 : pos[off] | pos[off + 1] << 8; ++} ++ ++static inline int splash_geti(unsigned char *pos, int off) ++{ ++ return off == -1 ? 0 : ++ pos[off] | pos[off + 1] << 8 | pos[off + 2] << 16 | pos[off + 3] << 24; ++} ++ ++static int splash_getraw(unsigned char *start, unsigned char *end, int *update) ++{ ++ unsigned char *ndata; ++ int version; ++ int splash_size; ++ int unit; ++ int width, height; ++ int silentsize; ++ int boxcnt; ++ int sboxcnt; ++ int palcnt; ++ int i, len; ++ const int *offsets; ++ struct vc_data *vc; ++ struct fb_info *info; ++ struct splash_data *sd; ++ int oldpercent, oldsilent; ++ ++ if (update) ++ *update = -1; ++ ++ if (!update || start[7] < '2' || start[7] > '3' || splash_geti(start, 12) != (int)0xffffffff) ++ printk(KERN_INFO "bootsplash %s: looking for picture...\n", SPLASH_VERSION); ++ ++ for (ndata = start; ndata < end; ndata++) { ++ if (ndata[0] != 'B' || ndata[1] != 'O' || ndata[2] != 'O' || ndata[3] != 'T') ++ continue; ++ if (ndata[4] != 'S' || ndata[5] != 'P' || ndata[6] != 'L' || ndata[7] < '1' || ndata[7] > '3') ++ continue; ++ version = ndata[7] - '0'; ++ offsets = splash_offsets[version - 1]; ++ len = SPLASH_OFF_LEN; ++ unit = splash_getb(ndata, SPLASH_OFF_UNIT); ++ if (unit >= MAX_NR_CONSOLES) ++ continue; ++ if (unit) { ++ vc_allocate(unit); ++ } ++ vc = vc_cons[unit].d; ++ info = registered_fb[(int)con2fb_map[unit]]; ++ width = info->var.xres; ++ height = info->var.yres; ++ splash_size = splash_geti(ndata, SPLASH_OFF_SIZE); ++ if (splash_size == (int)0xffffffff && version > 1) { ++ if ((sd = vc->vc_splash_data) != 0) { ++ int up = 0; ++ i = splash_getb(ndata, SPLASH_OFF_STATE); ++ if (i != 255) { ++ sd->splash_state = i; ++ up = -1; ++ } ++ i = splash_getb(ndata, SPLASH_OFF_FGCOL); ++ if (i != 255) { ++ sd->splash_fg_color = i; ++ up = -1; ++ } ++ i = splash_getb(ndata, SPLASH_OFF_COL); ++ if (i != 255) { ++ sd->splash_color = i; ++ up = -1; ++ } ++ boxcnt = sboxcnt = 0; ++ if (ndata + len <= end) { ++ boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT); ++ sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); ++ } ++ if (boxcnt) { ++ i = splash_gets(ndata, len); ++ if (boxcnt + i <= sd->splash_boxcount && ndata + len + 2 + boxcnt * 12 <= end) { ++ ++ if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_boxes + i * 12, 8)) { ++ ++ memcpy(sd->splash_boxes + i * 12, ndata + len + 2, boxcnt * 12); ++ up |= 1; ++ } ++ } ++ len += boxcnt * 12 + 2; ++ } ++ if (sboxcnt) { ++ i = splash_gets(ndata, len); ++ if (sboxcnt + i <= sd->splash_sboxcount && ndata + len + 2 + sboxcnt * 12 <= end) { ++ if (splash_geti(ndata, len + 2) != 0x7ffd7fff || !memcmp(ndata + len + 2, sd->splash_sboxes + i * 12, 8)) { ++ memcpy(sd->splash_sboxes + i * 12, ndata + len + 2, sboxcnt * 12); ++ up |= 2; ++ } ++ } ++ } ++ if (update) ++ *update = up; ++ } ++ return unit; ++ } ++ if (splash_size == 0) { ++ printk(KERN_INFO "bootsplash: ...found, freeing memory.\n"); ++ if (vc->vc_splash_data) ++ splash_free(vc, info); ++ return unit; ++ } ++ boxcnt = splash_gets(ndata, SPLASH_OFF_BOXCNT); ++ palcnt = 3 * splash_getb(ndata, SPLASH_OFF_PALCNT); ++ if (ndata + len + splash_size > end) { ++ printk(KERN_ERR "bootsplash: ...found, but truncated!\n"); ++ return -1; ++ } ++ if (!jpeg_check_size(ndata + len + boxcnt * 12 + palcnt, width, height)) { ++ ndata += len + splash_size - 1; ++ continue; ++ } ++ if (splash_check_jpeg(ndata + len + boxcnt * 12 + palcnt, width, height, info->var.bits_per_pixel)) ++ return -1; ++ silentsize = splash_geti(ndata, SPLASH_OFF_SSIZE); ++ if (silentsize) ++ printk(KERN_INFO "bootsplash: silentjpeg size %d bytes\n", silentsize); ++ if (silentsize >= splash_size) { ++ printk(KERN_ERR "bootsplash: bigger than splashsize!\n"); ++ return -1; ++ } ++ splash_size -= silentsize; ++ if (!splash_usesilent) ++ silentsize = 0; ++ else if (height * 2 * info->fix.line_length > info->fix.smem_len) { ++ printk(KERN_WARNING "bootsplash: does not fit into framebuffer.\n"); ++ silentsize = 0; ++ } ++ sboxcnt = splash_gets(ndata, SPLASH_OFF_SBOXCNT); ++ if (silentsize) { ++ unsigned char *simage = ndata + len + splash_size + 12 * sboxcnt; ++ if (!jpeg_check_size(simage, width, height) || ++ splash_check_jpeg(simage, width, height, info->var.bits_per_pixel)) { ++ printk(KERN_WARNING "bootsplash: error in silent jpeg.\n"); ++ silentsize = 0; ++ } ++ } ++ oldpercent = -1; ++ oldsilent = -1; ++ if (vc->vc_splash_data) { ++ oldpercent = vc->vc_splash_data->splash_percent; ++ oldsilent = vc->vc_splash_data->splash_dosilent; ++ splash_free(vc, info); ++ } ++ vc->vc_splash_data = sd = vmalloc(sizeof(*sd) + splash_size + (version < 3 ? 2 * 12 : 0)); ++ if (!sd) ++ break; ++ sd->splash_silentjpeg = 0; ++ sd->splash_sboxes = 0; ++ sd->splash_sboxcount = 0; ++ if (silentsize) { ++ sd->splash_silentjpeg = vmalloc(silentsize); ++ if (sd->splash_silentjpeg) { ++ memcpy(sd->splash_silentjpeg, ndata + len + splash_size, silentsize); ++ sd->splash_sboxes = vc->vc_splash_data->splash_silentjpeg; ++ sd->splash_silentjpeg += 12 * sboxcnt; ++ sd->splash_sboxcount = sboxcnt; ++ } ++ } ++ sd->splash_state = splash_getb(ndata, SPLASH_OFF_STATE); ++ sd->splash_fg_color = splash_getb(ndata, SPLASH_OFF_FGCOL); ++ sd->splash_color = splash_getb(ndata, SPLASH_OFF_COL); ++ sd->splash_overpaintok = splash_getb(ndata, SPLASH_OFF_OVEROK); ++ sd->splash_text_xo = splash_gets(ndata, SPLASH_OFF_XO); ++ sd->splash_text_yo = splash_gets(ndata, SPLASH_OFF_YO); ++ sd->splash_text_wi = splash_gets(ndata, SPLASH_OFF_WI); ++ sd->splash_text_he = splash_gets(ndata, SPLASH_OFF_HE); ++ sd->splash_percent = oldpercent == -1 ? splash_gets(ndata, SPLASH_OFF_PERCENT) : oldpercent; ++ if (version == 1) { ++ sd->splash_text_xo *= 8; ++ sd->splash_text_wi *= 8; ++ sd->splash_text_yo *= 16; ++ sd->splash_text_he *= 16; ++ sd->splash_color = (splash_default >> 8) & 0x0f; ++ sd->splash_fg_color = (splash_default >> 4) & 0x0f; ++ sd->splash_state = splash_default & 1; ++ } ++ if (sd->splash_text_xo + sd->splash_text_wi > width || sd->splash_text_yo + sd->splash_text_he > height) { ++ splash_free(vc, info); ++ printk(KERN_ERR "bootsplash: found, but has oversized text area!\n"); ++ return -1; ++ } ++ if (!vc_cons[unit].d || info->fbops->fb_imageblit != cfb_imageblit) { ++ splash_free(vc, info); ++ printk(KERN_ERR "bootsplash: found, but framebuffer can't handle it!\n"); ++ return -1; ++ } ++ printk(KERN_INFO "bootsplash: ...found (%dx%d, %d bytes, v%d).\n", width, height, splash_size, version); ++ if (version == 1) { ++ printk(KERN_WARNING "bootsplash: Using deprecated v1 header. Updating your splash utility recommended.\n"); ++ printk(KERN_INFO "bootsplash: Find the latest version at http://www.bootsplash.org/\n"); ++ } ++ ++ /* fake penguin box for older formats */ ++ if (version == 1) ++ boxcnt = splash_mkpenguin(sd, sd->splash_text_xo + 10, sd->splash_text_yo + 10, sd->splash_text_wi - 20, sd->splash_text_he - 20, 0xf0, 0xf0, 0xf0); ++ else if (version == 2) ++ boxcnt = splash_mkpenguin(sd, splash_gets(ndata, 24), splash_gets(ndata, 26), splash_gets(ndata, 28), splash_gets(ndata, 30), splash_getb(ndata, 32), splash_getb(ndata, 33), splash_getb(ndata, 34)); ++ ++ memcpy((char *)sd + sizeof(*sd) + (version < 3 ? boxcnt * 12 : 0), ndata + len, splash_size); ++ sd->splash_boxcount = boxcnt; ++ sd->splash_boxes = (unsigned char *)sd + sizeof(*sd); ++ sd->splash_palette = sd->splash_boxes + boxcnt * 12; ++ sd->splash_jpeg = sd->splash_palette + palcnt; ++ sd->splash_palcnt = palcnt / 3; ++ sd->splash_dosilent = sd->splash_silentjpeg != 0 ? (oldsilent == -1 ? 1 : oldsilent) : 0; ++ return unit; ++ } ++ printk(KERN_ERR "bootsplash: ...no good signature found.\n"); ++ return -1; ++} ++ ++int splash_verbose(void) ++{ ++ struct vc_data *vc; ++ struct fb_info *info; ++ ++ if (!splash_usesilent) ++ return 0; ++ ++ vc = vc_cons[0].d; ++ ++ if (!vc || !vc->vc_splash_data || !vc->vc_splash_data->splash_state) ++ return 0; ++ if (fg_console != vc->vc_num) ++ return 0; ++ if (!vc->vc_splash_data->splash_silentjpeg || !vc->vc_splash_data->splash_dosilent) ++ return 0; ++ vc->vc_splash_data->splash_dosilent = 0; ++ info = registered_fb[(int)con2fb_map[0]]; ++ if (!info->silent_screen_base) ++ return 0; ++ splashcopy(info->silent_screen_base, info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, info->fix.line_length); ++ info->screen_base = info->silent_screen_base; ++ info->silent_screen_base = 0; ++ return 1; ++} ++ ++static void splash_off(struct fb_info *info) ++{ ++ if (info->silent_screen_base) ++ info->screen_base = info->silent_screen_base; ++ info->silent_screen_base = 0; ++ info->splash_data = 0; ++ if (info->splash_pic) ++ vfree(info->splash_pic); ++ info->splash_pic = 0; ++ info->splash_pic_size = 0; ++} ++ ++int splash_prepare(struct vc_data *vc, struct fb_info *info) ++{ ++ int err; ++ int width, height, depth, size, sbytes; ++ ++ if (!vc->vc_splash_data || !vc->vc_splash_data->splash_state) { ++ if (decdata) ++ vfree(decdata); ++ decdata = 0; ++ splash_off(info); ++ return -1; ++ } ++ ++ width = info->var.xres; ++ height = info->var.yres; ++ depth = info->var.bits_per_pixel; ++ if (depth != 16) { /* Other targets might need fixing */ ++ splash_off(info); ++ return -2; ++ } ++ ++ sbytes = ((width + 15) & ~15) * (depth >> 3); ++ size = sbytes * ((height + 15) & ~15); ++ if (size != info->splash_pic_size) ++ splash_off(info); ++ if (!info->splash_pic) ++ info->splash_pic = vmalloc(size); ++ ++ if (!info->splash_pic) { ++ printk(KERN_INFO "bootsplash: not enough memory.\n"); ++ splash_off(info); ++ return -3; ++ } ++ ++ if (!decdata) ++ decdata = vmalloc(sizeof(*decdata)); ++ ++ if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent) { ++ /* fill area after framebuffer with other jpeg */ ++ if ((err = jpeg_decode(vc->vc_splash_data->splash_silentjpeg, info->splash_pic, ++ ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { ++ printk(KERN_INFO "bootsplash: error while decompressing silent picture: %s (%d)\n", jpg_errors[err - 1], err); ++ if (info->silent_screen_base) ++ info->screen_base = info->silent_screen_base; ++ vc->vc_splash_data->splash_dosilent = 0; ++ } else { ++ if (vc->vc_splash_data->splash_sboxcount) ++ boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_sboxes, ++ vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 0); ++ ++ if (!info->silent_screen_base) ++ info->silent_screen_base = info->screen_base; ++ splashcopy(info->silent_screen_base, info->splash_pic, info->var.yres, info->var.xres, info->fix.line_length, sbytes); ++ info->screen_base = info->silent_screen_base + info->fix.line_length * info->var.yres; ++ } ++ } else if (info->silent_screen_base) ++ info->screen_base = info->silent_screen_base; ++ ++ if ((err = jpeg_decode(vc->vc_splash_data->splash_jpeg, info->splash_pic, ++ ((width + 15) & ~15), ((height + 15) & ~15), depth, decdata))) { ++ printk(KERN_INFO "bootsplash: error while decompressing picture: %s (%d) .\n", jpg_errors[err - 1], err); ++ splash_off(info); ++ return -4; ++ } ++ info->splash_pic_size = size; ++ info->splash_bytes = sbytes; ++ if (vc->vc_splash_data->splash_boxcount) ++ boxit(info->splash_pic, sbytes, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 0); ++ if (vc->vc_splash_data->splash_state) ++ info->splash_data = vc->vc_splash_data; ++ else ++ splash_off(info); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PROC_FS ++ ++#include ++ ++static int splash_read_proc(char *buffer, char **start, off_t offset, int size, ++ int *eof, void *data); ++static int splash_write_proc(struct file *file, const char *buffer, ++ unsigned long count, void *data); ++static int splash_status(struct vc_data *vc); ++static int splash_recolor(struct vc_data *vc); ++static int splash_proc_register(void); ++ ++static struct proc_dir_entry *proc_splash; ++ ++static int splash_recolor(struct vc_data *vc) ++{ ++ if (!vc->vc_splash_data) ++ return -1; ++ if (!vc->vc_splash_data->splash_state) ++ return 0; ++ con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); ++ if (fg_console == vc->vc_num) { ++ update_region(vc, ++ vc->vc_origin + vc->vc_size_row * vc->vc_top, ++ vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); ++ } ++ return 0; ++} ++ ++static int splash_status(struct vc_data *vc) ++{ ++ struct fb_info *info; ++ printk(KERN_INFO "bootsplash: status on console %d changed to %s\n", vc->vc_num, vc->vc_splash_data && vc->vc_splash_data->splash_state ? "on" : "off"); ++ ++ info = registered_fb[(int) con2fb_map[vc->vc_num]]; ++ if (fg_console == vc->vc_num) ++ splash_prepare(vc, info); ++ if (vc->vc_splash_data && vc->vc_splash_data->splash_state) { ++ con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); ++ /* vc_resize also calls con_switch which resets yscroll */ ++ vc_resize(vc, vc->vc_splash_data->splash_text_wi / vc->vc_font.width, vc->vc_splash_data->splash_text_he / vc->vc_font.height); ++ if (fg_console == vc->vc_num) { ++ update_region(vc, ++ vc->vc_origin + vc->vc_size_row * vc->vc_top, ++ vc->vc_size_row * (vc->vc_bottom - vc->vc_top) / 2); ++ splash_clear_margins(vc->vc_splash_data, vc, info, 0); ++ } ++ } else { ++ /* Switch bootsplash off */ ++ con_remap_def_color(vc, 0x07); ++ vc_resize(vc, info->var.xres / vc->vc_font.width, info->var.yres / vc->vc_font.height); ++ } ++ return 0; ++} ++ ++static int splash_read_proc(char *buffer, char **start, off_t offset, int size, ++ int *eof, void *data) ++{ ++ int len = 0; ++ off_t begin = 0; ++ struct vc_data *vc = vc_cons[0].d; ++ struct fb_info *info = registered_fb[(int)con2fb_map[0]]; ++ int color = vc->vc_splash_data ? vc->vc_splash_data->splash_color << 4 | ++ vc->vc_splash_data->splash_fg_color : splash_default >> 4; ++ int status = vc->vc_splash_data ? vc->vc_splash_data->splash_state & 1 : 0; ++ len += sprintf(buffer + len, "Splash screen v%s (0x%02x, %dx%d%s): %s\n", ++ SPLASH_VERSION, color, info->var.xres, info->var.yres, ++ (vc->vc_splash_data ? vc->vc_splash_data->splash_dosilent : 0)? ", silent" : "", ++ status ? "on" : "off"); ++ if (offset >= begin + len) ++ return 0; ++ ++ *start = buffer + (begin - offset); ++ ++ return (size < begin + len - offset ? size : begin + len - offset); ++} ++ ++void splash_set_percent(struct vc_data *vc, int pe) ++{ ++ struct fb_info *info; ++ struct fbcon_ops *ops; ++ int oldpe; ++ ++ if (pe < 0) ++ pe = 0; ++ if (pe > 65535) ++ pe = 65535; ++ pe += pe > 32767;; ++ ++ if (!vc->vc_splash_data || vc->vc_splash_data->splash_percent == pe) ++ return; ++ ++ oldpe = vc->vc_splash_data->splash_percent; ++ vc->vc_splash_data->splash_percent = pe; ++ if (fg_console != vc->vc_num || !vc->vc_splash_data->splash_state) { ++ return; ++ } ++ info = registered_fb[(int) con2fb_map[vc->vc_num]]; ++ ops = info->fbcon_par; ++ if (ops->blank_state) ++ return; ++ if (!vc->vc_splash_data->splash_overpaintok || pe == 65536 || pe < oldpe) { ++ if (splash_hasinter(vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount)) ++ splash_status(vc); ++ else ++ splash_prepare(vc, info); ++ } else { ++ if (vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base) ++ boxit(info->silent_screen_base, info->fix.line_length, vc->vc_splash_data->splash_sboxes, vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 1); ++ boxit(info->screen_base, info->fix.line_length, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 1); ++ } ++} ++ ++static int splash_write_proc(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ int new, unit; ++ struct vc_data *vc; ++ ++ if (!buffer || !splash_default) ++ return count; ++ ++ acquire_console_sem(); ++ unit = 0; ++ if (buffer[0] == '@' && buffer[1] >= '0' && buffer[1] <= '9') { ++ unit = buffer[1] - '0'; ++ buffer += 2; ++ if (*buffer >= '0' && *buffer <= '9') { ++ unit = unit * 10 + *buffer - '0'; ++ buffer++; ++ } ++ if (*buffer == ' ') ++ buffer++; ++ if (unit >= MAX_NR_CONSOLES || !vc_cons[unit].d) { ++ release_console_sem(); ++ return count; ++ } ++ } ++ vc = vc_cons[unit].d; ++ if (!strncmp(buffer, "redraw", 6)) { ++ splash_status(vc); ++ release_console_sem(); ++ return count; ++ } ++ if (!strncmp(buffer, "show", 4) || !strncmp(buffer, "hide", 4)) { ++ int pe; ++ ++ if (buffer[4] == ' ' && buffer[5] == 'p') ++ pe = 0; ++ else if (buffer[4] == '\n') ++ pe = 65535; ++ else ++ pe = simple_strtoul(buffer + 5, NULL, 0); ++ if (pe < 0) ++ pe = 0; ++ if (pe > 65535) ++ pe = 65535; ++ if (*buffer == 'h') ++ pe = 65535 - pe; ++ splash_set_percent(vc, pe); ++ release_console_sem(); ++ return count; ++ } ++ if (!strncmp(buffer,"silent\n",7) || !strncmp(buffer,"verbose\n",8)) { ++ if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { ++ if (vc->vc_splash_data->splash_dosilent != (buffer[0] == 's')) { ++ vc->vc_splash_data->splash_dosilent = buffer[0] == 's'; ++ splash_status(vc); ++ } ++ } ++ release_console_sem(); ++ return count; ++ } ++ if (!strncmp(buffer,"freesilent\n",11)) { ++ if (vc->vc_splash_data && vc->vc_splash_data->splash_silentjpeg) { ++ printk(KERN_INFO "bootsplash: freeing silent jpeg\n"); ++ vc->vc_splash_data->splash_silentjpeg = 0; ++ vfree(vc->vc_splash_data->splash_sboxes); ++ vc->vc_splash_data->splash_sboxes = 0; ++ vc->vc_splash_data->splash_sboxcount = 0; ++ if (vc->vc_splash_data->splash_dosilent) ++ splash_status(vc); ++ vc->vc_splash_data->splash_dosilent = 0; ++ } ++ release_console_sem(); ++ return count; ++ } ++ ++ if (!strncmp(buffer, "BOOTSPL", 7)) { ++ int up = -1; ++ unit = splash_getraw((unsigned char *)buffer, (unsigned char *)buffer + count, &up); ++ if (unit >= 0) { ++ vc = vc_cons[unit].d; ++ if (up == -1) ++ splash_status(vc); ++ else { ++ struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]]; ++ struct fbcon_ops *ops = info->fbcon_par; ++ if (ops->blank_state) ++ up = 0; ++ if ((up & 2) != 0 && vc->vc_splash_data->splash_silentjpeg && vc->vc_splash_data->splash_dosilent && info->silent_screen_base) ++ boxit(info->silent_screen_base, info->fix.line_length, vc->vc_splash_data->splash_sboxes, vc->vc_splash_data->splash_sboxcount, vc->vc_splash_data->splash_percent, 1); ++ if ((up & 1) != 0) ++ boxit(info->screen_base, info->fix.line_length, vc->vc_splash_data->splash_boxes, vc->vc_splash_data->splash_boxcount, vc->vc_splash_data->splash_percent, 1); ++ } ++ } ++ release_console_sem(); ++ return count; ++ } ++ if (!vc->vc_splash_data) { ++ release_console_sem(); ++ return count; ++ } ++ if (buffer[0] == 't') { ++ vc->vc_splash_data->splash_state ^= 1; ++ splash_status(vc); ++ release_console_sem(); ++ return count; ++ } ++ new = simple_strtoul(buffer, NULL, 0); ++ if (new > 1) { ++ /* expert user */ ++ vc->vc_splash_data->splash_color = new >> 8 & 0xff; ++ vc->vc_splash_data->splash_fg_color = new >> 4 & 0x0f; ++ } ++ if ((new & 1) == vc->vc_splash_data->splash_state) ++ splash_recolor(vc); ++ else { ++ vc->vc_splash_data->splash_state = new & 1; ++ splash_status(vc); ++ } ++ release_console_sem(); ++ return count; ++} ++ ++static int splash_proc_register(void) ++{ ++ if ((proc_splash = create_proc_entry("splash", 0, 0))) { ++ proc_splash->read_proc = splash_read_proc; ++ proc_splash->write_proc = splash_write_proc; ++ return 0; ++ } ++ return 1; ++} ++ ++# if 0 ++static int splash_proc_unregister(void) ++{ ++ if (proc_splash) ++ remove_proc_entry("splash", 0); ++ return 0; ++} ++# endif ++#endif /* CONFIG_PROC_FS */ ++ ++void splash_init(void) ++{ ++ struct fb_info *info; ++ struct vc_data *vc; ++ int isramfs = 1; ++ int fd; ++ int len; ++ int max_len = 1024*1024*2; ++ char *mem; ++ ++ if (splash_registered) ++ return; ++ vc = vc_cons[0].d; ++ info = registered_fb[0]; ++ if (!vc || !info || info->var.bits_per_pixel != 16) ++ return; ++#ifdef CONFIG_PROC_FS ++ splash_proc_register(); ++#endif ++ splash_registered = 1; ++ if (vc->vc_splash_data) ++ return; ++ if ((fd = sys_open("/bootsplash", O_RDONLY, 0)) < 0) { ++ isramfs = 0; ++ fd = sys_open("/initrd.image", O_RDONLY, 0); ++ } ++ if (fd < 0) ++ return; ++ if ((len = (int)sys_lseek(fd, (off_t)0, 2)) <= 0) { ++ sys_close(fd); ++ return; ++ } ++ /* Don't look for more than the last 2MB */ ++ if (len > max_len) { ++ printk( KERN_INFO "bootsplash: scanning last %dMB of initrd for signature\n", ++ max_len>>20); ++ sys_lseek(fd, (off_t)(len - max_len), 0); ++ len = max_len; ++ } else { ++ sys_lseek(fd, (off_t)0, 0); ++ } ++ ++ mem = vmalloc(len); ++ if (mem) { ++ acquire_console_sem(); ++ if ((int)sys_read(fd, mem, len) == len && splash_getraw((unsigned char *)mem, (unsigned char *)mem + len, (int *)0) == 0 && vc->vc_splash_data) ++ vc->vc_splash_data->splash_state = splash_default & 1; ++ release_console_sem(); ++ vfree(mem); ++ } ++ sys_close(fd); ++ if (isramfs) ++ sys_unlink("/bootsplash"); ++ return; ++} ++ +--- /dev/null ++++ b/drivers/video/bootsplash/bootsplash.h +@@ -0,0 +1,44 @@ ++/* ++ * linux/drivers/video/bootsplash/bootsplash.h - splash screen definition. ++ * ++ * (w) 2001-2003 by Volker Poplawski, ++ * Stefan Reinauer, ++ * ++ * ++ * idea and SuSE screen work by Ken Wimer, ++ */ ++ ++#ifndef __BOOTSPLASH_H ++#define __BOOTSPLASH_H ++ ++struct fb_info; ++ ++/* splash.c */ ++extern int splash_prepare(struct vc_data *, struct fb_info *); ++extern void splash_init(void); ++ ++/* splash_render.c */ ++extern void splash_putcs(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ const unsigned short *s, int count, int ypos, int xpos); ++extern void splash_putc(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ int c, int ypos, int xpos); ++extern void splashcopy(u8 *dst, u8 *src, int height, int width, int dstbytes, int srcbytes); ++extern void splash_clear(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, ++ int sx, int height, int width); ++extern void splash_bmove(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, ++ int sx, int dy, int dx, int height, int width); ++extern void splash_clear_margins(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ int bottom_only); ++extern int splash_cursor(struct splash_data *sd, struct fb_info *info, struct fb_cursor *cursor); ++extern void splash_bmove_redraw(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ int y, int sx, int dx, int width); ++extern void splash_blank(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ int blank); ++ ++/* vt.c */ ++extern void con_remap_def_color(struct vc_data *vc, int new_color); ++ ++extern void acquire_console_sem(void); ++extern void release_console_sem(void); ++ ++#endif +--- /dev/null ++++ b/drivers/video/bootsplash/decode-jpg.c +@@ -0,0 +1,957 @@ ++/* ++ * linux/drivers/video/bootsplash/decode-jpg.c - a tiny jpeg decoder. ++ * ++ * (w) August 2001 by Michael Schroeder, ++ * ++ */ ++ ++#include ++#include ++ ++#include "decode-jpg.h" ++ ++#define ISHIFT 11 ++ ++#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5)) ++#define IMULT(a, b) (((a) * (b)) >> ISHIFT) ++#define ITOINT(a) ((a) >> ISHIFT) ++ ++#ifndef __P ++# define __P(x) x ++#endif ++ ++/* special markers */ ++#define M_BADHUFF -1 ++#define M_EOF 0x80 ++ ++struct in { ++ unsigned char *p; ++ unsigned int bits; ++ int left; ++ int marker; ++ ++ int (*func) __P((void *)); ++ void *data; ++}; ++ ++/*********************************/ ++struct dec_hufftbl; ++struct enc_hufftbl; ++ ++union hufftblp { ++ struct dec_hufftbl *dhuff; ++ struct enc_hufftbl *ehuff; ++}; ++ ++struct scan { ++ int dc; /* old dc value */ ++ ++ union hufftblp hudc; ++ union hufftblp huac; ++ int next; /* when to switch to next scan */ ++ ++ int cid; /* component id */ ++ int hv; /* horiz/vert, copied from comp */ ++ int tq; /* quant tbl, copied from comp */ ++}; ++ ++/*********************************/ ++ ++#define DECBITS 10 /* seems to be the optimum */ ++ ++struct dec_hufftbl { ++ int maxcode[17]; ++ int valptr[16]; ++ unsigned char vals[256]; ++ unsigned int llvals[1 << DECBITS]; ++}; ++ ++static void decode_mcus __P((struct in *, int *, int, struct scan *, int *)); ++static int dec_readmarker __P((struct in *)); ++static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *)); ++ ++static void setinput __P((struct in *, unsigned char *)); ++/*********************************/ ++ ++#undef PREC ++#define PREC int ++ ++static void idctqtab __P((unsigned char *, PREC *)); ++static void idct __P((int *, int *, PREC *, PREC, int)); ++static void scaleidctqtab __P((PREC *, PREC)); ++ ++/*********************************/ ++ ++static void initcol __P((PREC[][64])); ++ ++static void col221111 __P((int *, unsigned char *, int)); ++static void col221111_16 __P((int *, unsigned char *, int)); ++ ++/*********************************/ ++ ++#define M_SOI 0xd8 ++#define M_APP0 0xe0 ++#define M_DQT 0xdb ++#define M_SOF0 0xc0 ++#define M_DHT 0xc4 ++#define M_DRI 0xdd ++#define M_SOS 0xda ++#define M_RST0 0xd0 ++#define M_EOI 0xd9 ++#define M_COM 0xfe ++ ++static unsigned char *datap; ++ ++static int getbyte(void) ++{ ++ return *datap++; ++} ++ ++static int getword(void) ++{ ++ int c1, c2; ++ c1 = *datap++; ++ c2 = *datap++; ++ return c1 << 8 | c2; ++} ++ ++struct comp { ++ int cid; ++ int hv; ++ int tq; ++}; ++ ++#define MAXCOMP 4 ++struct jpginfo { ++ int nc; /* number of components */ ++ int ns; /* number of scans */ ++ int dri; /* restart interval */ ++ int nm; /* mcus til next marker */ ++ int rm; /* next restart marker */ ++}; ++ ++static struct jpginfo info; ++static struct comp comps[MAXCOMP]; ++ ++static struct scan dscans[MAXCOMP]; ++ ++static unsigned char quant[4][64]; ++ ++static struct dec_hufftbl dhuff[4]; ++ ++#define dec_huffdc (dhuff + 0) ++#define dec_huffac (dhuff + 2) ++ ++static struct in in; ++ ++static int readtables(int till) ++{ ++ int m, l, i, j, lq, pq, tq; ++ int tc, th, tt; ++ ++ for (;;) { ++ if (getbyte() != 0xff) ++ return -1; ++ if ((m = getbyte()) == till) ++ break; ++ ++ switch (m) { ++ case 0xc2: ++ return 0; ++ ++ case M_DQT: ++ lq = getword(); ++ while (lq > 2) { ++ pq = getbyte(); ++ tq = pq & 15; ++ if (tq > 3) ++ return -1; ++ pq >>= 4; ++ if (pq != 0) ++ return -1; ++ for (i = 0; i < 64; i++) ++ quant[tq][i] = getbyte(); ++ lq -= 64 + 1; ++ } ++ break; ++ ++ case M_DHT: ++ l = getword(); ++ while (l > 2) { ++ int hufflen[16], k; ++ unsigned char huffvals[256]; ++ ++ tc = getbyte(); ++ th = tc & 15; ++ tc >>= 4; ++ tt = tc * 2 + th; ++ if (tc > 1 || th > 1) ++ return -1; ++ for (i = 0; i < 16; i++) ++ hufflen[i] = getbyte(); ++ l -= 1 + 16; ++ k = 0; ++ for (i = 0; i < 16; i++) { ++ for (j = 0; j < hufflen[i]; j++) ++ huffvals[k++] = getbyte(); ++ l -= hufflen[i]; ++ } ++ dec_makehuff(dhuff + tt, hufflen, ++ huffvals); ++ } ++ break; ++ ++ case M_DRI: ++ l = getword(); ++ info.dri = getword(); ++ break; ++ ++ default: ++ l = getword(); ++ while (l-- > 2) ++ getbyte(); ++ break; ++ } ++ } ++ return 0; ++} ++ ++static void dec_initscans(void) ++{ ++ int i; ++ ++ info.nm = info.dri + 1; ++ info.rm = M_RST0; ++ for (i = 0; i < info.ns; i++) ++ dscans[i].dc = 0; ++} ++ ++static int dec_checkmarker(void) ++{ ++ int i; ++ ++ if (dec_readmarker(&in) != info.rm) ++ return -1; ++ info.nm = info.dri; ++ info.rm = (info.rm + 1) & ~0x08; ++ for (i = 0; i < info.ns; i++) ++ dscans[i].dc = 0; ++ return 0; ++} ++ ++int jpeg_check_size(unsigned char *buf, int width, int height) ++{ ++ datap = buf; ++ getbyte(); ++ getbyte(); ++ readtables(M_SOF0); ++ getword(); ++ getbyte(); ++ if (height != getword() || width != getword()) ++ return 0; ++ return 1; ++} ++ ++int jpeg_decode(buf, pic, width, height, depth, decdata) ++unsigned char *buf, *pic; ++int width, height, depth; ++struct jpeg_decdata *decdata; ++{ ++ int i, j, m, tac, tdc; ++ int mcusx, mcusy, mx, my; ++ int max[6]; ++ ++ if (!decdata || !buf || !pic) ++ return -1; ++ datap = buf; ++ if (getbyte() != 0xff) ++ return ERR_NO_SOI; ++ if (getbyte() != M_SOI) ++ return ERR_NO_SOI; ++ if (readtables(M_SOF0)) ++ return ERR_BAD_TABLES; ++ getword(); ++ i = getbyte(); ++ if (i != 8) ++ return ERR_NOT_8BIT; ++ if (((getword() + 15) & ~15) != height) ++ return ERR_HEIGHT_MISMATCH; ++ if (((getword() + 15) & ~15) != width) ++ return ERR_WIDTH_MISMATCH; ++ if ((height & 15) || (width & 15)) ++ return ERR_BAD_WIDTH_OR_HEIGHT; ++ info.nc = getbyte(); ++ if (info.nc > MAXCOMP) ++ return ERR_TOO_MANY_COMPPS; ++ for (i = 0; i < info.nc; i++) { ++ int h, v; ++ comps[i].cid = getbyte(); ++ comps[i].hv = getbyte(); ++ v = comps[i].hv & 15; ++ h = comps[i].hv >> 4; ++ comps[i].tq = getbyte(); ++ if (h > 3 || v > 3) ++ return ERR_ILLEGAL_HV; ++ if (comps[i].tq > 3) ++ return ERR_QUANT_TABLE_SELECTOR; ++ } ++ if (readtables(M_SOS)) ++ return ERR_BAD_TABLES; ++ getword(); ++ info.ns = getbyte(); ++ if (info.ns != 3) ++ return ERR_NOT_YCBCR_221111; ++ for (i = 0; i < 3; i++) { ++ dscans[i].cid = getbyte(); ++ tdc = getbyte(); ++ tac = tdc & 15; ++ tdc >>= 4; ++ if (tdc > 1 || tac > 1) ++ return ERR_QUANT_TABLE_SELECTOR; ++ for (j = 0; j < info.nc; j++) ++ if (comps[j].cid == dscans[i].cid) ++ break; ++ if (j == info.nc) ++ return ERR_UNKNOWN_CID_IN_SCAN; ++ dscans[i].hv = comps[j].hv; ++ dscans[i].tq = comps[j].tq; ++ dscans[i].hudc.dhuff = dec_huffdc + tdc; ++ dscans[i].huac.dhuff = dec_huffac + tac; ++ } ++ ++ i = getbyte(); ++ j = getbyte(); ++ m = getbyte(); ++ ++ if (i != 0 || j != 63 || m != 0) ++ return ERR_NOT_SEQUENTIAL_DCT; ++ ++ if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3) ++ return ERR_NOT_YCBCR_221111; ++ ++ if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 || dscans[2].hv != 0x11) ++ return ERR_NOT_YCBCR_221111; ++ ++ mcusx = width >> 4; ++ mcusy = height >> 4; ++ ++ ++ idctqtab(quant[dscans[0].tq], decdata->dquant[0]); ++ idctqtab(quant[dscans[1].tq], decdata->dquant[1]); ++ idctqtab(quant[dscans[2].tq], decdata->dquant[2]); ++ initcol(decdata->dquant); ++ setinput(&in, datap); ++ ++#if 0 ++ /* landing zone */ ++ img[len] = 0; ++ img[len + 1] = 0xff; ++ img[len + 2] = M_EOF; ++#endif ++ ++ dec_initscans(); ++ ++ dscans[0].next = 6 - 4; ++ dscans[1].next = 6 - 4 - 1; ++ dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ ++ for (my = 0; my < mcusy; my++) { ++ for (mx = 0; mx < mcusx; mx++) { ++ if (info.dri && !--info.nm) ++ if (dec_checkmarker()) ++ return ERR_WRONG_MARKER; ++ ++ decode_mcus(&in, decdata->dcts, 6, dscans, max); ++ idct(decdata->dcts, decdata->out, decdata->dquant[0], IFIX(128.5), max[0]); ++ idct(decdata->dcts + 64, decdata->out + 64, decdata->dquant[0], IFIX(128.5), max[1]); ++ idct(decdata->dcts + 128, decdata->out + 128, decdata->dquant[0], IFIX(128.5), max[2]); ++ idct(decdata->dcts + 192, decdata->out + 192, decdata->dquant[0], IFIX(128.5), max[3]); ++ idct(decdata->dcts + 256, decdata->out + 256, decdata->dquant[1], IFIX(0.5), max[4]); ++ idct(decdata->dcts + 320, decdata->out + 320, decdata->dquant[2], IFIX(0.5), max[5]); ++ ++ switch (depth) { ++ case 24: ++ col221111(decdata->out, pic + (my * 16 * mcusx + mx) * 16 * 3, mcusx * 16 * 3); ++ break; ++ case 16: ++ col221111_16(decdata->out, pic + (my * 16 * mcusx + mx) * (16 * 2), mcusx * (16 * 2)); ++ break; ++ default: ++ return ERR_DEPTH_MISMATCH; ++ break; ++ } ++ } ++ } ++ ++ m = dec_readmarker(&in); ++ if (m != M_EOI) ++ return ERR_NO_EOI; ++ ++ return 0; ++} ++ ++/****************************************************************/ ++/************** huffman decoder ***************/ ++/****************************************************************/ ++ ++static int fillbits __P((struct in *, int, unsigned int)); ++static int dec_rec2 ++__P((struct in *, struct dec_hufftbl *, int *, int, int)); ++ ++static void setinput(in, p) ++struct in *in; ++unsigned char *p; ++{ ++ in->p = p; ++ in->left = 0; ++ in->bits = 0; ++ in->marker = 0; ++} ++ ++static int fillbits(in, le, bi) ++struct in *in; ++int le; ++unsigned int bi; ++{ ++ int b, m; ++ ++ if (in->marker) { ++ if (le <= 16) ++ in->bits = bi << 16, le += 16; ++ return le; ++ } ++ while (le <= 24) { ++ b = *in->p++; ++ if (b == 0xff && (m = *in->p++) != 0) { ++ if (m == M_EOF) { ++ if (in->func && (m = in->func(in->data)) == 0) ++ continue; ++ } ++ in->marker = m; ++ if (le <= 16) ++ bi = bi << 16, le += 16; ++ break; ++ } ++ bi = bi << 8 | b; ++ le += 8; ++ } ++ in->bits = bi; /* tmp... 2 return values needed */ ++ return le; ++} ++ ++static int dec_readmarker(in) ++struct in *in; ++{ ++ int m; ++ ++ in->left = fillbits(in, in->left, in->bits); ++ if ((m = in->marker) == 0) ++ return 0; ++ in->left = 0; ++ in->marker = 0; ++ return m; ++} ++ ++#define LEBI_DCL int le, bi ++#define LEBI_GET(in) (le = in->left, bi = in->bits) ++#define LEBI_PUT(in) (in->left = le, in->bits = bi) ++ ++#define GETBITS(in, n) ( \ ++ (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \ ++ (le -= (n)), \ ++ bi >> le & ((1 << (n)) - 1) \ ++) ++ ++#define UNGETBITS(in, n) ( \ ++ le += (n) \ ++) ++ ++ ++static int dec_rec2(in, hu, runp, c, i) ++struct in *in; ++struct dec_hufftbl *hu; ++int *runp; ++int c, i; ++{ ++ LEBI_DCL; ++ ++ LEBI_GET(in); ++ if (i) { ++ UNGETBITS(in, i & 127); ++ *runp = i >> 8 & 15; ++ i >>= 16; ++ } else { ++ for (i = DECBITS; (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++); ++ if (i >= 16) { ++ in->marker = M_BADHUFF; ++ return 0; ++ } ++ i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2]; ++ *runp = i >> 4; ++ i &= 15; ++ } ++ if (i == 0) { /* sigh, 0xf0 is 11 bit */ ++ LEBI_PUT(in); ++ return 0; ++ } ++ /* receive part */ ++ c = GETBITS(in, i); ++ if (c < (1 << (i - 1))) ++ c += (-1 << i) + 1; ++ LEBI_PUT(in); ++ return c; ++} ++ ++#define DEC_REC(in, hu, r, i) ( \ ++ r = GETBITS(in, DECBITS), \ ++ i = hu->llvals[r], \ ++ i & 128 ? \ ++ ( \ ++ UNGETBITS(in, i & 127), \ ++ r = i >> 8 & 15, \ ++ i >> 16 \ ++ ) \ ++ : \ ++ ( \ ++ LEBI_PUT(in), \ ++ i = dec_rec2(in, hu, &r, r, i), \ ++ LEBI_GET(in), \ ++ i \ ++ ) \ ++) ++ ++static void decode_mcus(in, dct, n, sc, maxp) ++struct in *in; ++int *dct; ++int n; ++struct scan *sc; ++int *maxp; ++{ ++ struct dec_hufftbl *hu; ++ int i, r, t; ++ LEBI_DCL; ++ ++ memset(dct, 0, n * 64 * sizeof(*dct)); ++ LEBI_GET(in); ++ while (n-- > 0) { ++ hu = sc->hudc.dhuff; ++ *dct++ = (sc->dc += DEC_REC(in, hu, r, t)); ++ ++ hu = sc->huac.dhuff; ++ i = 63; ++ while (i > 0) { ++ t = DEC_REC(in, hu, r, t); ++ if (t == 0 && r == 0) { ++ dct += i; ++ break; ++ } ++ dct += r; ++ *dct++ = t; ++ i -= r + 1; ++ } ++ *maxp++ = 64 - i; ++ if (n == sc->next) ++ sc++; ++ } ++ LEBI_PUT(in); ++} ++ ++static void dec_makehuff(hu, hufflen, huffvals) ++struct dec_hufftbl *hu; ++int *hufflen; ++unsigned char *huffvals; ++{ ++ int code, k, i, j, d, x, c, v; ++ for (i = 0; i < (1 << DECBITS); i++) ++ hu->llvals[i] = 0; ++ ++/* ++ * llvals layout: ++ * ++ * value v already known, run r, backup u bits: ++ * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu ++ * value unknown, size b bits, run r, backup u bits: ++ * 000000000000bbbb 0000 rrrr 0 uuuuuuu ++ * value and size unknown: ++ * 0000000000000000 0000 0000 0 0000000 ++ */ ++ code = 0; ++ k = 0; ++ for (i = 0; i < 16; i++, code <<= 1) { /* sizes */ ++ hu->valptr[i] = k; ++ for (j = 0; j < hufflen[i]; j++) { ++ hu->vals[k] = *huffvals++; ++ if (i < DECBITS) { ++ c = code << (DECBITS - 1 - i); ++ v = hu->vals[k] & 0x0f; /* size */ ++ for (d = 1 << (DECBITS - 1 - i); --d >= 0;) { ++ if (v + i < DECBITS) { /* both fit in table */ ++ x = d >> (DECBITS - 1 - v - ++ i); ++ if (v && x < (1 << (v - 1))) ++ x += (-1 << v) + 1; ++ x = x << 16 | (hu-> vals[k] & 0xf0) << 4 | ++ (DECBITS - (i + 1 + v)) | 128; ++ } else ++ x = v << 16 | (hu-> vals[k] & 0xf0) << 4 | ++ (DECBITS - (i + 1)); ++ hu->llvals[c | d] = x; ++ } ++ } ++ code++; ++ k++; ++ } ++ hu->maxcode[i] = code; ++ } ++ hu->maxcode[16] = 0x20000; /* always terminate decode */ ++} ++ ++/****************************************************************/ ++/************** idct ***************/ ++/****************************************************************/ ++ ++#define ONE ((PREC)IFIX(1.)) ++#define S2 ((PREC)IFIX(0.382683432)) ++#define C2 ((PREC)IFIX(0.923879532)) ++#define C4 ((PREC)IFIX(0.707106781)) ++ ++#define S22 ((PREC)IFIX(2 * 0.382683432)) ++#define C22 ((PREC)IFIX(2 * 0.923879532)) ++#define IC4 ((PREC)IFIX(1 / 0.707106781)) ++ ++#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */ ++#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */ ++#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */ ++ ++#define XPP(a,b) (t = a + b, b = a - b, a = t) ++#define XMP(a,b) (t = a - b, b = a + b, a = t) ++#define XPM(a,b) (t = a + b, b = b - a, a = t) ++ ++#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \ ++ a = IMULT(a, c - s) + t, \ ++ b = IMULT(b, c + s) - t) ++ ++#define IDCT \ ++( \ ++ XPP(t0, t1), \ ++ XMP(t2, t3), \ ++ t2 = IMULT(t2, IC4) - t3, \ ++ XPP(t0, t3), \ ++ XPP(t1, t2), \ ++ XMP(t4, t7), \ ++ XPP(t5, t6), \ ++ XMP(t5, t7), \ ++ t5 = IMULT(t5, IC4), \ ++ ROT(t4, t6, S22, C22),\ ++ t6 -= t7, \ ++ t5 -= t6, \ ++ t4 -= t5, \ ++ XPP(t0, t7), \ ++ XPP(t1, t6), \ ++ XPP(t2, t5), \ ++ XPP(t3, t4) \ ++) ++ ++static unsigned char zig2[64] = { ++ 0, 2, 3, 9, 10, 20, 21, 35, ++ 14, 16, 25, 31, 39, 46, 50, 57, ++ 5, 7, 12, 18, 23, 33, 37, 48, ++ 27, 29, 41, 44, 52, 55, 59, 62, ++ 15, 26, 30, 40, 45, 51, 56, 58, ++ 1, 4, 8, 11, 19, 22, 34, 36, ++ 28, 42, 43, 53, 54, 60, 61, 63, ++ 6, 13, 17, 24, 32, 38, 47, 49 ++}; ++ ++void idct(in, out, quant, off, max) ++int *in; ++int *out; ++PREC *quant; ++PREC off; ++int max; ++{ ++ PREC t0, t1, t2, t3, t4, t5, t6, t7, t; ++ PREC tmp[64], *tmpp; ++ int i, j; ++ unsigned char *zig2p; ++ ++ t0 = off; ++ if (max == 1) { ++ t0 += in[0] * quant[0]; ++ for (i = 0; i < 64; i++) ++ out[i] = ITOINT(t0); ++ return; ++ } ++ zig2p = zig2; ++ tmpp = tmp; ++ for (i = 0; i < 8; i++) { ++ j = *zig2p++; ++ t0 += in[j] * quant[j]; ++ j = *zig2p++; ++ t5 = in[j] * quant[j]; ++ j = *zig2p++; ++ t2 = in[j] * quant[j]; ++ j = *zig2p++; ++ t7 = in[j] * quant[j]; ++ j = *zig2p++; ++ t1 = in[j] * quant[j]; ++ j = *zig2p++; ++ t4 = in[j] * quant[j]; ++ j = *zig2p++; ++ t3 = in[j] * quant[j]; ++ j = *zig2p++; ++ t6 = in[j] * quant[j]; ++ IDCT; ++ tmpp[0 * 8] = t0; ++ tmpp[1 * 8] = t1; ++ tmpp[2 * 8] = t2; ++ tmpp[3 * 8] = t3; ++ tmpp[4 * 8] = t4; ++ tmpp[5 * 8] = t5; ++ tmpp[6 * 8] = t6; ++ tmpp[7 * 8] = t7; ++ tmpp++; ++ t0 = 0; ++ } ++ for (i = 0; i < 8; i++) { ++ t0 = tmp[8 * i + 0]; ++ t1 = tmp[8 * i + 1]; ++ t2 = tmp[8 * i + 2]; ++ t3 = tmp[8 * i + 3]; ++ t4 = tmp[8 * i + 4]; ++ t5 = tmp[8 * i + 5]; ++ t6 = tmp[8 * i + 6]; ++ t7 = tmp[8 * i + 7]; ++ IDCT; ++ out[8 * i + 0] = ITOINT(t0); ++ out[8 * i + 1] = ITOINT(t1); ++ out[8 * i + 2] = ITOINT(t2); ++ out[8 * i + 3] = ITOINT(t3); ++ out[8 * i + 4] = ITOINT(t4); ++ out[8 * i + 5] = ITOINT(t5); ++ out[8 * i + 6] = ITOINT(t6); ++ out[8 * i + 7] = ITOINT(t7); ++ } ++} ++ ++static unsigned char zig[64] = { ++ 0, 1, 5, 6, 14, 15, 27, 28, ++ 2, 4, 7, 13, 16, 26, 29, 42, ++ 3, 8, 12, 17, 25, 30, 41, 43, ++ 9, 11, 18, 24, 31, 40, 44, 53, ++ 10, 19, 23, 32, 39, 45, 52, 54, ++ 20, 22, 33, 38, 46, 51, 55, 60, ++ 21, 34, 37, 47, 50, 56, 59, 61, ++ 35, 36, 48, 49, 57, 58, 62, 63 ++}; ++ ++static PREC aaidct[8] = { ++ IFIX(0.3535533906), IFIX(0.4903926402), ++ IFIX(0.4619397663), IFIX(0.4157348062), ++ IFIX(0.3535533906), IFIX(0.2777851165), ++ IFIX(0.1913417162), IFIX(0.0975451610) ++}; ++ ++ ++static void idctqtab(qin, qout) ++unsigned char *qin; ++PREC *qout; ++{ ++ int i, j; ++ ++ for (i = 0; i < 8; i++) ++ for (j = 0; j < 8; j++) ++ qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] * ++ IMULT(aaidct[i], aaidct[j]); ++} ++ ++static void scaleidctqtab(q, sc) ++PREC *q; ++PREC sc; ++{ ++ int i; ++ ++ for (i = 0; i < 64; i++) ++ q[i] = IMULT(q[i], sc); ++} ++ ++/****************************************************************/ ++/************** color decoder ***************/ ++/****************************************************************/ ++ ++#define ROUND ++ ++/* ++ * YCbCr Color transformation: ++ * ++ * y:0..255 Cb:-128..127 Cr:-128..127 ++ * ++ * R = Y + 1.40200 * Cr ++ * G = Y - 0.34414 * Cb - 0.71414 * Cr ++ * B = Y + 1.77200 * Cb ++ * ++ * => ++ * Cr *= 1.40200; ++ * Cb *= 1.77200; ++ * Cg = 0.19421 * Cb + .50937 * Cr; ++ * R = Y + Cr; ++ * G = Y - Cg; ++ * B = Y + Cb; ++ * ++ * => ++ * Cg = (50 * Cb + 130 * Cr + 128) >> 8; ++ */ ++ ++static void initcol(q) ++PREC q[][64]; ++{ ++ scaleidctqtab(q[1], IFIX(1.77200)); ++ scaleidctqtab(q[2], IFIX(1.40200)); ++} ++ ++/* This is optimized for the stupid sun SUNWspro compiler. */ ++#define STORECLAMP(a,x) \ ++( \ ++ (a) = (x), \ ++ (unsigned int)(x) >= 256 ? \ ++ ((a) = (x) < 0 ? 0 : 255) \ ++ : \ ++ 0 \ ++) ++ ++#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x)) ++ ++#ifdef ROUND ++ ++#define CBCRCG(yin, xin) \ ++( \ ++ cb = outc[0 +yin*8+xin], \ ++ cr = outc[64+yin*8+xin], \ ++ cg = (50 * cb + 130 * cr + 128) >> 8 \ ++) ++ ++#else ++ ++#define CBCRCG(yin, xin) \ ++( \ ++ cb = outc[0 +yin*8+xin], \ ++ cr = outc[64+yin*8+xin], \ ++ cg = (3 * cb + 8 * cr) >> 4 \ ++) ++ ++#endif ++ ++#define PIC(yin, xin, p, xout) \ ++( \ ++ y = outy[(yin) * 8 + xin], \ ++ STORECLAMP(p[(xout) * 3 + 0], y + cr), \ ++ STORECLAMP(p[(xout) * 3 + 1], y - cg), \ ++ STORECLAMP(p[(xout) * 3 + 2], y + cb) \ ++) ++ ++#ifdef __LITTLE_ENDIAN ++#define PIC_16(yin, xin, p, xout, add) \ ++( \ ++ y = outy[(yin) * 8 + xin], \ ++ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ ++ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ ++ ((CLAMP(y + cb + add*2+1) ) >> 3), \ ++ p[(xout) * 2 + 0] = y & 0xff, \ ++ p[(xout) * 2 + 1] = y >> 8 \ ++) ++#else ++#ifdef CONFIG_PPC ++#define PIC_16(yin, xin, p, xout, add) \ ++( \ ++ y = outy[(yin) * 8 + xin], \ ++ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \ ++ ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \ ++ ((CLAMP(y + cb + add*2+1) ) >> 3), \ ++ p[(xout) * 2 + 0] = y >> 8, \ ++ p[(xout) * 2 + 1] = y & 0xff \ ++) ++#else ++#define PIC_16(yin, xin, p, xout, add) \ ++( \ ++ y = outy[(yin) * 8 + xin], \ ++ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ ++ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ ++ ((CLAMP(y + cb + add*2+1) ) >> 3), \ ++ p[(xout) * 2 + 0] = y >> 8, \ ++ p[(xout) * 2 + 1] = y & 0xff \ ++) ++#endif ++#endif ++ ++#define PIC221111(xin) \ ++( \ ++ CBCRCG(0, xin), \ ++ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \ ++ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \ ++ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \ ++ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \ ++) ++ ++#define PIC221111_16(xin) \ ++( \ ++ CBCRCG(0, xin), \ ++ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \ ++ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \ ++ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \ ++ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \ ++) ++ ++static void col221111(out, pic, width) ++int *out; ++unsigned char *pic; ++int width; ++{ ++ int i, j, k; ++ unsigned char *pic0, *pic1; ++ int *outy, *outc; ++ int cr, cg, cb, y; ++ ++ pic0 = pic; ++ pic1 = pic + width; ++ outy = out; ++ outc = out + 64 * 4; ++ for (i = 2; i > 0; i--) { ++ for (j = 4; j > 0; j--) { ++ for (k = 0; k < 8; k++) { ++ PIC221111(k); ++ } ++ outc += 8; ++ outy += 16; ++ pic0 += 2 * width; ++ pic1 += 2 * width; ++ } ++ outy += 64 * 2 - 16 * 4; ++ } ++} ++ ++static void col221111_16(out, pic, width) ++int *out; ++unsigned char *pic; ++int width; ++{ ++ int i, j, k; ++ unsigned char *pic0, *pic1; ++ int *outy, *outc; ++ int cr, cg, cb, y; ++ ++ pic0 = pic; ++ pic1 = pic + width; ++ outy = out; ++ outc = out + 64 * 4; ++ for (i = 2; i > 0; i--) { ++ for (j = 4; j > 0; j--) { ++ for (k = 0; k < 8; k++) { ++ PIC221111_16(k); ++ } ++ outc += 8; ++ outy += 16; ++ pic0 += 2 * width; ++ pic1 += 2 * width; ++ } ++ outy += 64 * 2 - 16 * 4; ++ } ++} +--- /dev/null ++++ b/drivers/video/bootsplash/decode-jpg.h +@@ -0,0 +1,35 @@ ++/* ++ * linux/drivers/video/bootsplash/decode-jpg.h - a tiny jpeg decoder. ++ * ++ * (w) August 2001 by Michael Schroeder, ++ */ ++ ++#ifndef __DECODE_JPG_H ++#define __DECODE_JPG_H ++ ++#define ERR_NO_SOI 1 ++#define ERR_NOT_8BIT 2 ++#define ERR_HEIGHT_MISMATCH 3 ++#define ERR_WIDTH_MISMATCH 4 ++#define ERR_BAD_WIDTH_OR_HEIGHT 5 ++#define ERR_TOO_MANY_COMPPS 6 ++#define ERR_ILLEGAL_HV 7 ++#define ERR_QUANT_TABLE_SELECTOR 8 ++#define ERR_NOT_YCBCR_221111 9 ++#define ERR_UNKNOWN_CID_IN_SCAN 10 ++#define ERR_NOT_SEQUENTIAL_DCT 11 ++#define ERR_WRONG_MARKER 12 ++#define ERR_NO_EOI 13 ++#define ERR_BAD_TABLES 14 ++#define ERR_DEPTH_MISMATCH 15 ++ ++struct jpeg_decdata { ++ int dcts[6 * 64 + 16]; ++ int out[64 * 6]; ++ int dquant[3][64]; ++}; ++ ++extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int, struct jpeg_decdata *); ++extern int jpeg_check_size(unsigned char *, int, int); ++ ++#endif +--- /dev/null ++++ b/drivers/video/bootsplash/Kconfig +@@ -0,0 +1,17 @@ ++# ++# Bootsplash configuration ++# ++ ++menu "Bootsplash configuration" ++ ++config BOOTSPLASH ++ bool "Bootup splash screen" ++ depends on FRAMEBUFFER_CONSOLE && FB_VESA ++ default n ++ ---help--- ++ This option enables the Linux bootsplash screen. For more ++ information on the bootsplash screen have a look at ++ http://www.bootsplash.org/. ++ If you are unsure, say N ++endmenu ++ +--- /dev/null ++++ b/drivers/video/bootsplash/Makefile +@@ -0,0 +1,5 @@ ++# Makefile for the Linux bootsplash ++ ++obj-$(CONFIG_BOOTSPLASH) += bootsplash.o ++obj-$(CONFIG_BOOTSPLASH) += decode-jpg.o ++obj-$(CONFIG_BOOTSPLASH) += render.o +--- /dev/null ++++ b/drivers/video/bootsplash/render.c +@@ -0,0 +1,328 @@ ++/* ++ * linux/drivers/video/bootsplash/render.c - splash screen render functions. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../console/fbcon.h" ++#include "bootsplash.h" ++ ++void splash_putcs(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ const unsigned short *s, int count, int ypos, int xpos) ++{ ++ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; ++ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; ++ int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; ++ u8 *src; ++ u8 *dst, *splashsrc; ++ unsigned int d, x, y; ++ u32 dd, fgx, bgx; ++ u16 c = scr_readw(s); ++ ++ int fg_color, bg_color, transparent; ++ if (console_blanked) ++ return; ++ fg_color = attr_fgcol(fgshift, c); ++ bg_color = attr_bgcol(bgshift, c); ++ transparent = sd->splash_color == bg_color; ++ xpos = xpos * vc->vc_font.width + sd->splash_text_xo; ++ ypos = ypos * vc->vc_font.height + sd->splash_text_yo; ++ splashsrc = (u8 *)(info->splash_pic + ypos * info->splash_bytes + xpos * 2); ++ dst = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * 2); ++ ++ fgx = ((u32 *)info->pseudo_palette)[fg_color]; ++ if (transparent && sd->splash_color == 15) { ++ if (fgx == 0xffea) ++ fgx = 0xfe4a; ++ else if (fgx == 0x57ea) ++ fgx = 0x0540; ++ else if (fgx == 0xffff) ++ fgx = 0x52aa; ++ } ++ bgx = ((u32 *)info->pseudo_palette)[bg_color]; ++ d = 0; ++ ++ while (count--) { ++ c = scr_readw(s++); ++ src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * ((vc->vc_font.width + 7) >> 3); ++ ++ for (y = 0; y < vc->vc_font.height; y++) { ++ for (x = 0; x < vc->vc_font.width; x += 2) { ++ if ((x & 7) == 0) ++ d = *src++; ++ if (d & 0x80) ++ dd = fgx; ++ else ++ dd = transparent ? *(u16 *)splashsrc : bgx; ++ splashsrc += 2; ++ if (d & 0x40) ++ dd |= fgx << 16; ++ else ++ dd |= (transparent ? *(u16 *)splashsrc : bgx) << 16; ++ splashsrc += 2; ++ d <<= 2; ++ fb_writel(dd, dst); ++ dst += 4; ++ } ++ dst += info->fix.line_length - vc->vc_font.width * 2; ++ splashsrc += info->splash_bytes - vc->vc_font.width * 2; ++ } ++ dst -= info->fix.line_length * vc->vc_font.height - vc->vc_font.width * 2; ++ splashsrc -= info->splash_bytes * vc->vc_font.height - vc->vc_font.width * 2; ++ } ++} ++ ++static void splash_renderc(struct splash_data *sd, struct fb_info *info, int fg_color, int bg_color, u8 *src, int ypos, int xpos, int height, int width) ++{ ++ int transparent = sd->splash_color == bg_color; ++ u32 dd, fgx, bgx; ++ u8 *dst, *splashsrc; ++ unsigned int d, x, y; ++ ++ if (console_blanked) ++ return; ++ splashsrc = (u8 *)(info->splash_pic + ypos * info->splash_bytes + xpos * 2); ++ dst = (u8 *)(info->screen_base + ypos * info->fix.line_length + xpos * 2); ++ fgx = ((u32 *)info->pseudo_palette)[fg_color]; ++ if (transparent && sd->splash_color == 15) { ++ if (fgx == 0xffea) ++ fgx = 0xfe4a; ++ else if (fgx == 0x57ea) ++ fgx = 0x0540; ++ else if (fgx == 0xffff) ++ fgx = 0x52aa; ++ } ++ bgx = ((u32 *)info->pseudo_palette)[bg_color]; ++ d = 0; ++ for (y = 0; y < height; y++) { ++ for (x = 0; x < width; x += 2) { ++ if ((x & 7) == 0) ++ d = *src++; ++ if (d & 0x80) ++ dd = fgx; ++ else ++ dd = transparent ? *(u16 *)splashsrc : bgx; ++ splashsrc += 2; ++ if (d & 0x40) ++ dd |= fgx << 16; ++ else ++ dd |= (transparent ? *(u16 *)splashsrc : bgx) << 16; ++ splashsrc += 2; ++ d <<= 2; ++ fb_writel(dd, dst); ++ dst += 4; ++ } ++ dst += info->fix.line_length - width * 2; ++ splashsrc += info->splash_bytes - width * 2; ++ } ++} ++ ++void splash_putc(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ int c, int ypos, int xpos) ++{ ++ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; ++ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; ++ int fgshift = (vc->vc_hi_font_mask) ? 9 : 8; ++ u8 *src = vc->vc_font.data + (c & charmask) * vc->vc_font.height * ((vc->vc_font.width + 7) >> 3); ++ xpos = xpos * vc->vc_font.width + sd->splash_text_xo; ++ ypos = ypos * vc->vc_font.height + sd->splash_text_yo; ++ splash_renderc(sd, info, attr_fgcol(fgshift, c), attr_bgcol(bgshift, c), src, ypos, xpos, vc->vc_font.height, vc->vc_font.width); ++} ++ ++void splashcopy(u8 *dst, u8 *src, int height, int width, int dstbytes, int srcbytes) ++{ ++ int i; ++ ++ while (height-- > 0) { ++ u32 *p = (u32 *)dst; ++ u32 *q = (u32 *)src; ++ for (i=0; i < width/4; i++) { ++ fb_writel(*q++,p++); ++ fb_writel(*q++,p++); ++ } ++ if (width & 2) ++ fb_writel(*q++,p++); ++ if (width & 1) ++ fb_writew(*(u16*)q,(u16*)p); ++ dst += dstbytes; ++ src += srcbytes; ++ } ++} ++ ++static void splashset(u8 *dst, int height, int width, int dstbytes, u32 bgx) { ++ int i; ++ ++ bgx |= bgx << 16; ++ while (height-- > 0) { ++ u32 *p = (u32 *)dst; ++ for (i=0; i < width/4; i++) { ++ fb_writel(bgx,p++); ++ fb_writel(bgx,p++); ++ } ++ if (width & 2) ++ fb_writel(bgx,p++); ++ if (width & 1) ++ fb_writew(bgx,(u16*)p); ++ dst += dstbytes; ++ } ++} ++ ++static void splashfill(struct fb_info *info, int sy, int sx, int height, int width) { ++ splashcopy((u8 *)(info->screen_base + sy * info->fix.line_length + sx * 2), (u8 *)(info->splash_pic + sy * info->splash_bytes + sx * 2), height, width, info->fix.line_length, info->splash_bytes); ++} ++ ++void splash_clear(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, ++ int sx, int height, int width) ++{ ++ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; ++ int bg_color = attr_bgcol_ec(bgshift, vc, info); ++ int transparent = sd->splash_color == bg_color; ++ u32 bgx; ++ u8 *dst; ++ ++ if (console_blanked) ++ return; ++ sy = sy * vc->vc_font.height + sd->splash_text_yo; ++ sx = sx * vc->vc_font.width + sd->splash_text_xo; ++ height *= vc->vc_font.height; ++ width *= vc->vc_font.width; ++ if (transparent) { ++ splashfill(info, sy, sx, height, width); ++ return; ++ } ++ dst = (u8 *)(info->screen_base + sy * info->fix.line_length + sx * 2); ++ bgx = ((u32 *)info->pseudo_palette)[bg_color]; ++ splashset(dst, height, width, info->fix.line_length, bgx); ++} ++ ++void splash_bmove(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int sy, ++ int sx, int dy, int dx, int height, int width) ++{ ++ struct fb_copyarea area; ++ ++ if (console_blanked) ++ return; ++ area.sx = sx * vc->vc_font.width; ++ area.sy = sy * vc->vc_font.height; ++ area.dx = dx * vc->vc_font.width; ++ area.dy = dy * vc->vc_font.height; ++ area.sx += sd->splash_text_xo; ++ area.sy += sd->splash_text_yo; ++ area.dx += sd->splash_text_xo; ++ area.dy += sd->splash_text_yo; ++ area.height = height * vc->vc_font.height; ++ area.width = width * vc->vc_font.width; ++ ++ info->fbops->fb_copyarea(info, &area); ++} ++ ++void splash_clear_margins(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, ++ int bottom_only) ++{ ++ unsigned int tw = vc->vc_cols*vc->vc_font.width; ++ unsigned int th = vc->vc_rows*vc->vc_font.height; ++ ++ if (console_blanked) ++ return; ++ if (!bottom_only) { ++ /* top margin */ ++ splashfill(info, 0, 0, sd->splash_text_yo, info->var.xres); ++ /* left margin */ ++ splashfill(info, sd->splash_text_yo, 0, th, sd->splash_text_xo); ++ /* right margin */ ++ splashfill(info, sd->splash_text_yo, sd->splash_text_xo + tw, th, info->var.xres - sd->splash_text_xo - tw); ++ ++ } ++ splashfill(info, sd->splash_text_yo + th, 0, info->var.yres - sd->splash_text_yo - th, info->var.xres); ++} ++ ++int splash_cursor(struct splash_data *sd, struct fb_info *info, struct fb_cursor *cursor) ++{ ++ int i; ++ unsigned int dsize, s_pitch; ++ ++ if (info->state != FBINFO_STATE_RUNNING) ++ return 0; ++ ++ s_pitch = (cursor->image.width + 7) >> 3; ++ dsize = s_pitch * cursor->image.height; ++ if (cursor->enable) { ++ switch (cursor->rop) { ++ case ROP_XOR: ++ for (i = 0; i < dsize; i++) ++ info->fb_cursordata[i] = cursor->image.data[i] ^ cursor->mask[i]; ++ break; ++ case ROP_COPY: ++ default: ++ for (i = 0; i < dsize; i++) ++ info->fb_cursordata[i] = cursor->image.data[i] & cursor->mask[i]; ++ break; ++ } ++ } else if (info->fb_cursordata != cursor->image.data) ++ memcpy(info->fb_cursordata, cursor->image.data, dsize); ++ cursor->image.data = info->fb_cursordata; ++ splash_renderc(sd, info, cursor->image.fg_color, cursor->image.bg_color, (u8 *)info->fb_cursordata, cursor->image.dy + sd->splash_text_yo, cursor->image.dx + sd->splash_text_xo, cursor->image.height, cursor->image.width); ++ return 0; ++} ++ ++void splash_bmove_redraw(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int y, int sx, int dx, int width) ++{ ++ unsigned short *d = (unsigned short *) (vc->vc_origin + vc->vc_size_row * y + dx * 2); ++ unsigned short *s = d + (dx - sx); ++ unsigned short *start = d; ++ unsigned short *ls = d; ++ unsigned short *le = d + width; ++ unsigned short c; ++ int x = dx; ++ unsigned short attr = 1; ++ ++ if (console_blanked) ++ return; ++ do { ++ c = scr_readw(d); ++ if (attr != (c & 0xff00)) { ++ attr = c & 0xff00; ++ if (d > start) { ++ splash_putcs(sd, vc, info, start, d - start, y, x); ++ x += d - start; ++ start = d; ++ } ++ } ++ if (s >= ls && s < le && c == scr_readw(s)) { ++ if (d > start) { ++ splash_putcs(sd, vc, info, start, d - start, y, x); ++ x += d - start + 1; ++ start = d + 1; ++ } else { ++ x++; ++ start++; ++ } ++ } ++ s++; ++ d++; ++ } while (d < le); ++ if (d > start) ++ splash_putcs(sd, vc, info, start, d - start, y, x); ++} ++ ++void splash_blank(struct splash_data *sd, struct vc_data *vc, struct fb_info *info, int blank) ++{ ++ if (blank) { ++ if (info->silent_screen_base) ++ splashset((u8 *)info->silent_screen_base, info->var.yres, info->var.xres, info->fix.line_length, 0); ++ splashset((u8 *)info->screen_base, info->var.yres, info->var.xres, info->fix.line_length, 0); ++ } else { ++ if (info->silent_screen_base) ++ splash_prepare(vc, info); ++ splash_clear_margins(vc->vc_splash_data, vc, info, 0); ++ /* no longer needed, done in fbcon_blank */ ++ /* update_screen(vc->vc_num); */ ++ } ++} ++ +--- a/drivers/video/console/bitblit.c ++++ b/drivers/video/console/bitblit.c +@@ -17,6 +17,9 @@ + #include + #include + #include "fbcon.h" ++#ifdef CONFIG_BOOTSPLASH ++#include "../bootsplash/bootsplash.h" ++#endif + + /* + * Accelerated handlers. +@@ -47,6 +50,13 @@ static void bit_bmove(struct vc_data *vc + { + struct fb_copyarea area; + ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ splash_bmove(info->splash_data, vc, info, ++ sy, sx, dy, dx, height, width); ++ return; ++ } ++#endif + area.sx = sx * vc->vc_font.width; + area.sy = sy * vc->vc_font.height; + area.dx = dx * vc->vc_font.width; +@@ -63,6 +73,13 @@ static void bit_clear(struct vc_data *vc + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + struct fb_fillrect region; + ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ splash_clear(info->splash_data, vc, info, ++ sy, sx, height, width); ++ return; ++ } ++#endif + region.color = attr_bgcol_ec(bgshift, vc, info); + region.dx = sx * vc->vc_font.width; + region.dy = sy * vc->vc_font.height; +@@ -160,6 +177,13 @@ static void bit_putcs(struct vc_data *vc + image.height = vc->vc_font.height; + image.depth = 1; + ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ splash_putcs(info->splash_data, vc, info, s, count, yy, xx); ++ return; ++ } ++#endif ++ + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) +@@ -213,6 +237,13 @@ static void bit_clear_margins(struct vc_ + unsigned int bs = info->var.yres - bh; + struct fb_fillrect region; + ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ splash_clear_margins(info->splash_data, vc, info, bottom_only); ++ return; ++ } ++#endif ++ + region.color = attr_bgcol_ec(bgshift, vc, info); + region.rop = ROP_COPY; + +@@ -379,6 +410,14 @@ static void bit_cursor(struct vc_data *v + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ splash_cursor(info->splash_data, info, &cursor); ++ ops->cursor_reset = 0; ++ return; ++ } ++#endif ++ + if (info->fbops->fb_cursor) + err = info->fbops->fb_cursor(info, &cursor); + +--- a/drivers/video/console/fbcon.c ++++ b/drivers/video/console/fbcon.c +@@ -90,6 +90,9 @@ + #endif + + #include "fbcon.h" ++#ifdef CONFIG_BOOTSPLASH ++#include "../bootsplash/bootsplash.h" ++#endif + + #ifdef FBCONDEBUG + # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) +@@ -105,7 +108,11 @@ enum { + + static struct display fb_display[MAX_NR_CONSOLES]; + ++#ifdef CONFIG_BOOTSPLASH ++signed char con2fb_map[MAX_NR_CONSOLES]; ++#else + static signed char con2fb_map[MAX_NR_CONSOLES]; ++#endif + static signed char con2fb_map_boot[MAX_NR_CONSOLES]; + + static int logo_lines; +@@ -578,6 +585,10 @@ static int fbcon_takeover(int show_logo) + for (i = first_fb_vc; i <= last_fb_vc; i++) + con2fb_map[i] = info_idx; + ++#ifdef CONFIG_BOOTSPLASH ++ splash_init(); ++#endif ++ + err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + +@@ -1180,6 +1191,16 @@ static void fbcon_init(struct vc_data *v + new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + new_cols /= vc->vc_font.width; + new_rows /= vc->vc_font.height; ++ ++#ifdef CONFIG_BOOTSPLASH ++ if (vc->vc_splash_data && vc->vc_splash_data->splash_state) { ++ new_cols = vc->vc_splash_data->splash_text_wi / vc->vc_font.width; ++ new_rows = vc->vc_splash_data->splash_text_he / vc->vc_font.height; ++ logo = 0; ++ con_remap_def_color(vc, vc->vc_splash_data->splash_color << 4 | vc->vc_splash_data->splash_fg_color); ++ } ++#endif ++ + vc_resize(vc, new_cols, new_rows); + + /* +@@ -1875,6 +1896,10 @@ static int fbcon_scroll(struct vc_data * + fbcon_softback_note(vc, t, count); + if (logo_shown >= 0) + goto redraw_up; ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) ++ goto redraw_up; ++#endif + switch (p->scrollmode) { + case SCROLL_MOVE: + fbcon_redraw_blit(vc, info, p, t, b - t - count, +@@ -1966,6 +1991,10 @@ static int fbcon_scroll(struct vc_data * + count = vc->vc_rows; + if (logo_shown >= 0) + goto redraw_down; ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) ++ goto redraw_down; ++#endif + switch (p->scrollmode) { + case SCROLL_MOVE: + fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, +@@ -2114,6 +2143,14 @@ static void fbcon_bmove_rec(struct vc_da + } + return; + } ++ ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data && sy == dy && height == 1) { ++ /* must use slower redraw bmove to keep background pic intact */ ++ splash_bmove_redraw(info->splash_data, vc, info, sy, sx, dx, width); ++ return; ++ } ++#endif + ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, + height, width); + } +@@ -2222,6 +2259,10 @@ static int fbcon_switch(struct vc_data * + info = registered_fb[con2fb_map[vc->vc_num]]; + ops = info->fbcon_par; + ++#ifdef CONFIG_BOOTSPLASH ++ splash_prepare(vc, info); ++#endif ++ + if (softback_top) { + if (softback_lines) + fbcon_set_origin(vc); +@@ -2349,6 +2390,12 @@ static void fbcon_generic_blank(struct v + { + struct fb_event event; + ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ splash_blank(info->splash_data, vc, info, blank); ++ return; ++ } ++#endif + if (blank) { + unsigned short charmask = vc->vc_hi_font_mask ? + 0x1ff : 0xff; +@@ -2553,6 +2600,12 @@ static int fbcon_do_set_font(struct vc_d + + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); ++#ifdef CONFIG_BOOTSPLASH ++ if (info->splash_data) { ++ cols = info->splash_data->splash_text_wi; ++ rows = info->splash_data->splash_text_he; ++ } ++#endif + cols /= w; + rows /= h; + vc_resize(vc, cols, rows); +--- a/drivers/video/console/fbcon.h ++++ b/drivers/video/console/fbcon.h +@@ -25,6 +25,34 @@ + * low-level frame buffer device + */ + ++#ifdef CONFIG_BOOTSPLASH ++struct splash_data { ++ int splash_state; /* show splash? */ ++ int splash_color; /* transparent color */ ++ int splash_fg_color; /* foreground color */ ++ int splash_width; /* width of image */ ++ int splash_height; /* height of image */ ++ int splash_text_xo; /* text area origin */ ++ int splash_text_yo; ++ int splash_text_wi; /* text area size */ ++ int splash_text_he; ++ int splash_showtext; /* silent/verbose mode */ ++ int splash_boxcount; ++ int splash_percent; ++ int splash_overpaintok; /* is it ok to overpaint boxes */ ++ int splash_palcnt; ++ char *oldscreen_base; /* pointer to top of virtual screen */ ++ unsigned char *splash_boxes; ++ unsigned char *splash_jpeg; /* jpeg */ ++ unsigned char *splash_palette; /* palette for 8-bit */ ++ ++ int splash_dosilent; /* show silent jpeg */ ++ unsigned char *splash_silentjpeg; ++ unsigned char *splash_sboxes; ++ int splash_sboxcount; ++}; ++#endif ++ + struct display { + /* Filled in by the low-level console driver */ + const u_char *fontdata; +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -2054,4 +2054,8 @@ if FB || SGI_NEWPORT_CONSOLE + source "drivers/video/logo/Kconfig" + endif + ++if FB ++ source "drivers/video/bootsplash/Kconfig" ++endif ++ + endmenu +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -14,6 +14,7 @@ fb-objs := $(f + obj-$(CONFIG_VT) += console/ + obj-$(CONFIG_LOGO) += logo/ + obj-y += backlight/ display/ ++obj-$(CONFIG_BOOTSPLASH) += bootsplash/ + + obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o + obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o +--- a/drivers/video/vesafb.c ++++ b/drivers/video/vesafb.c +@@ -174,7 +174,10 @@ static int vesafb_setcolreg(unsigned reg + return err; + } + +-static struct fb_ops vesafb_ops = { ++#ifndef CONFIG_BOOTSPLASH ++static ++#endif ++struct fb_ops vesafb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = vesafb_setcolreg, + .fb_pan_display = vesafb_pan_display, +@@ -258,6 +261,9 @@ static int __init vesafb_probe(struct pl + * option to simply use size_total as that + * wastes plenty of kernel address space. */ + size_remap = size_vmode * 2; ++#ifdef CONFIG_BOOTSPLASH ++ size_remap *= 2; /* some more for the images */ ++#endif + if (vram_remap) + size_remap = vram_remap * 1024 * 1024; + if (size_remap < size_vmode) +--- a/include/linux/console_struct.h ++++ b/include/linux/console_struct.h +@@ -107,6 +107,9 @@ struct vc_data { + struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ + unsigned long vc_uni_pagedir; + unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ ++#ifdef CONFIG_BOOTSPLASH ++ struct splash_data *vc_splash_data; ++#endif + /* additional information is in vt_kern.h */ + }; + +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -849,6 +849,14 @@ struct fb_info { + void *fbcon_par; /* fbcon use-only private area */ + /* From here on everything is device dependent */ + void *par; ++#ifdef CONFIG_BOOTSPLASH ++ struct splash_data *splash_data; ++ unsigned char *splash_pic; ++ int splash_pic_size; ++ int splash_bytes; ++ char *silent_screen_base; /* real screen base */ ++ char fb_cursordata[64]; ++#endif + }; + + #ifdef MODULE +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -109,6 +109,12 @@ NORET_TYPE void panic(const char * fmt, + * We can't use the "normal" timers since we just panicked.. + */ + printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); ++#ifdef CONFIG_BOOTSPLASH ++ { ++ extern int splash_verbose(void); ++ (void)splash_verbose(); ++ } ++#endif + for (i = 0; i < panic_timeout*1000; ) { + touch_nmi_watchdog(); + i += panic_blink(i); +@@ -133,6 +139,12 @@ NORET_TYPE void panic(const char * fmt, + disabled_wait(caller); + #endif + local_irq_enable(); ++#ifdef CONFIG_BOOTSPLASH ++ { ++ extern int splash_verbose(void); ++ (void)splash_verbose(); ++ } ++#endif + for (i = 0;;) { + touch_softlockup_watchdog(); + i += panic_blink(i); diff --git a/src/patches/suse-2.6.27.31/patches.suse/cfq-ioc-race b/src/patches/suse-2.6.27.31/patches.suse/cfq-ioc-race new file mode 100644 index 000000000..65957ff2e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/cfq-ioc-race @@ -0,0 +1,34 @@ +From: Nikanth Karthikesan +Subject: [PATCH] Exiting queue and task might race to free cic +References: bnc#444346 +Patch-Mainline: No. being discussed. +Signed-off-by: Nikanth Karthikesan + +When a queue exits the queue lock is taken and cfq_exit_queue() would +free all the cic's associated with the queue. But when a task exits, +cfq_exit_io_context() gets cic one by one and then locks the associated +queue to call __cfq_exit_single_io_context. In the window between +getting a cic from the ioc and locking the queue, the queue might have +exited on another cpu. + +Index: b/block/cfq-iosched.c +=================================================================== +--- a/block/cfq-iosched.c ++++ b/block/cfq-iosched.c +@@ -1310,7 +1310,15 @@ static void cfq_exit_single_io_context(s + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); +- __cfq_exit_single_io_context(cfqd, cic); ++ ++ /* ++ * Ensure we get a fresh copy of the ->key to prevent ++ * race between exiting task and queue ++ */ ++ smp_read_barrier_depends(); ++ if (likely(cic->key)) ++ __cfq_exit_single_io_context(cfqd, cic); ++ + spin_unlock_irqrestore(q->queue_lock, flags); + } + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/cgroup-disable-memory.patch b/src/patches/suse-2.6.27.31/patches.suse/cgroup-disable-memory.patch new file mode 100644 index 000000000..a667ee40d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/cgroup-disable-memory.patch @@ -0,0 +1,82 @@ +From: Balbir Singh +Date: Thu, 01 May 2008 02:48:58 -0700 +Subject: memcg: disable the memory controller by default + +Due to the overhead of the memory controller the memory controller is now +disabled by default. This patch adds cgroup_enable. + +[akpm@linux-foundation.org: `inline __init' doesn't make sense] +Signed-off-by: Balbir Singh +Cc: AMAMOTO Takashi +Acked-by: Paul Menage +Cc: Pavel Emelianov +Acked-by: KAMEZAWA Hiroyuki +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Jiri Slaby +--- + + Documentation/kernel-parameters.txt | 3 +++ + kernel/cgroup.c | 17 +++++++++++++---- + mm/memcontrol.c | 1 + + 3 files changed, 17 insertions(+), 4 deletions(-) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -423,8 +423,11 @@ and is between 256 and 4096 characters. + See Documentation/s390/CommonIO for details. + + cgroup_disable= [KNL] Disable a particular controller ++ cgroup_enable= [KNL] Enable a particular controller ++ For both cgroup_enable and cgroup_enable + Format: {name of the controller(s) to disable} + {Currently supported controllers - "memory"} ++ {Memory controller is disabled by default} + + checkreqprot [SELINUX] Set initial checkreqprot flag value. + Format: { "0" | "1" } +--- a/kernel/cgroup.c ++++ b/kernel/cgroup.c +@@ -3099,7 +3099,7 @@ static void cgroup_release_agent(struct + mutex_unlock(&cgroup_mutex); + } + +-static int __init cgroup_disable(char *str) ++static int __init cgroup_turnonoff(char *str, int disable) + { + int i; + char *token; +@@ -3112,13 +3112,22 @@ static int __init cgroup_disable(char *s + struct cgroup_subsys *ss = subsys[i]; + + if (!strcmp(token, ss->name)) { +- ss->disabled = 1; +- printk(KERN_INFO "Disabling %s control group" +- " subsystem\n", ss->name); ++ ss->disabled = disable; + break; + } + } + } + return 1; + } ++ ++static int __init cgroup_disable(char *str) ++{ ++ return cgroup_turnonoff(str, 1); ++} + __setup("cgroup_disable=", cgroup_disable); ++ ++static int __init cgroup_enable(char *str) ++{ ++ return cgroup_turnonoff(str, 0); ++} ++__setup("cgroup_enable=", cgroup_enable); +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -1241,4 +1241,5 @@ struct cgroup_subsys mem_cgroup_subsys = + .populate = mem_cgroup_populate, + .attach = mem_cgroup_move_task, + .early_init = 0, ++ .disabled = 1, + }; diff --git a/src/patches/suse-2.6.27.31/patches.suse/cgroup-freezer.patch b/src/patches/suse-2.6.27.31/patches.suse/cgroup-freezer.patch new file mode 100644 index 000000000..b9b4f73d9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/cgroup-freezer.patch @@ -0,0 +1,2505 @@ +From: Serge E. Hallyn +Subject: cgroup freezer +References: bnc#417294, fate#304191, fate#201036 +Patch-upstream: yes +Git: 68d1a06b440a5df55fb253e1d1113d2e4a7209fc Mon Sep 17 00:00:00 2001 + +Signed-off-by: Serge E. Hallyn +Acked-by: Nick Piggin +--- + Documentation/cgroups.txt | 548 ---------------------------- + Documentation/cgroups/cgroups.txt | 548 ++++++++++++++++++++++++++++ + Documentation/cgroups/freezer-subsystem.txt | 102 +++++ + Documentation/cpusets.txt | 2 + arch/alpha/Kconfig | 1 + arch/alpha/include/asm/thread_info.h | 2 + arch/arm/Kconfig | 2 + arch/avr32/Kconfig | 2 + arch/avr32/include/asm/thread_info.h | 1 + arch/blackfin/Kconfig | 3 + arch/cris/Kconfig | 2 + arch/frv/Kconfig | 2 + arch/h8300/Kconfig | 2 + arch/h8300/include/asm/thread_info.h | 2 + arch/ia64/Kconfig | 2 + arch/m32r/Kconfig | 2 + arch/m68k/Kconfig | 2 + arch/m68knommu/Kconfig | 2 + arch/m68knommu/include/asm/thread_info.h | 2 + arch/mips/Kconfig | 2 + arch/mn10300/Kconfig | 2 + arch/parisc/Kconfig | 2 + arch/powerpc/Kconfig | 2 + arch/s390/Kconfig | 2 + arch/s390/include/asm/thread_info.h | 2 + arch/sh/Kconfig | 2 + arch/sparc/Kconfig | 2 + arch/sparc/include/asm/thread_info_32.h | 2 + arch/sparc64/Kconfig | 1 + arch/um/Kconfig | 2 + arch/x86/Kconfig | 1 + arch/xtensa/Kconfig | 1 + include/asm-cris/thread_info.h | 2 + include/asm-m68k/thread_info.h | 1 + include/asm-parisc/thread_info.h | 2 + include/asm-um/thread_info.h | 2 + include/asm-xtensa/thread_info.h | 2 + include/linux/cgroup_subsys.h | 6 + include/linux/freezer.h | 42 -- + init/Kconfig | 7 + kernel/Kconfig.freezer | 2 + kernel/Makefile | 2 + kernel/cgroup_freezer.c | 379 +++++++++++++++++++ + kernel/freezer.c | 154 +++++++ + kernel/power/process.c | 119 ------ + 45 files changed, 1283 insertions(+), 689 deletions(-) + create mode 100644 include/linux/cgroup_freezer.h + create mode 100644 kernel/cgroup_freezer.c + create mode 100644 kernel/freezer.c + +--- a/Documentation/cgroups.txt ++++ /dev/null +@@ -1,548 +0,0 @@ +- CGROUPS +- ------- +- +-Written by Paul Menage based on Documentation/cpusets.txt +- +-Original copyright statements from cpusets.txt: +-Portions Copyright (C) 2004 BULL SA. +-Portions Copyright (c) 2004-2006 Silicon Graphics, Inc. +-Modified by Paul Jackson +-Modified by Christoph Lameter +- +-CONTENTS: +-========= +- +-1. Control Groups +- 1.1 What are cgroups ? +- 1.2 Why are cgroups needed ? +- 1.3 How are cgroups implemented ? +- 1.4 What does notify_on_release do ? +- 1.5 How do I use cgroups ? +-2. Usage Examples and Syntax +- 2.1 Basic Usage +- 2.2 Attaching processes +-3. Kernel API +- 3.1 Overview +- 3.2 Synchronization +- 3.3 Subsystem API +-4. Questions +- +-1. Control Groups +-================= +- +-1.1 What are cgroups ? +----------------------- +- +-Control Groups provide a mechanism for aggregating/partitioning sets of +-tasks, and all their future children, into hierarchical groups with +-specialized behaviour. +- +-Definitions: +- +-A *cgroup* associates a set of tasks with a set of parameters for one +-or more subsystems. +- +-A *subsystem* is a module that makes use of the task grouping +-facilities provided by cgroups to treat groups of tasks in +-particular ways. A subsystem is typically a "resource controller" that +-schedules a resource or applies per-cgroup limits, but it may be +-anything that wants to act on a group of processes, e.g. a +-virtualization subsystem. +- +-A *hierarchy* is a set of cgroups arranged in a tree, such that +-every task in the system is in exactly one of the cgroups in the +-hierarchy, and a set of subsystems; each subsystem has system-specific +-state attached to each cgroup in the hierarchy. Each hierarchy has +-an instance of the cgroup virtual filesystem associated with it. +- +-At any one time there may be multiple active hierachies of task +-cgroups. Each hierarchy is a partition of all tasks in the system. +- +-User level code may create and destroy cgroups by name in an +-instance of the cgroup virtual file system, specify and query to +-which cgroup a task is assigned, and list the task pids assigned to +-a cgroup. Those creations and assignments only affect the hierarchy +-associated with that instance of the cgroup file system. +- +-On their own, the only use for cgroups is for simple job +-tracking. The intention is that other subsystems hook into the generic +-cgroup support to provide new attributes for cgroups, such as +-accounting/limiting the resources which processes in a cgroup can +-access. For example, cpusets (see Documentation/cpusets.txt) allows +-you to associate a set of CPUs and a set of memory nodes with the +-tasks in each cgroup. +- +-1.2 Why are cgroups needed ? +----------------------------- +- +-There are multiple efforts to provide process aggregations in the +-Linux kernel, mainly for resource tracking purposes. Such efforts +-include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server +-namespaces. These all require the basic notion of a +-grouping/partitioning of processes, with newly forked processes ending +-in the same group (cgroup) as their parent process. +- +-The kernel cgroup patch provides the minimum essential kernel +-mechanisms required to efficiently implement such groups. It has +-minimal impact on the system fast paths, and provides hooks for +-specific subsystems such as cpusets to provide additional behaviour as +-desired. +- +-Multiple hierarchy support is provided to allow for situations where +-the division of tasks into cgroups is distinctly different for +-different subsystems - having parallel hierarchies allows each +-hierarchy to be a natural division of tasks, without having to handle +-complex combinations of tasks that would be present if several +-unrelated subsystems needed to be forced into the same tree of +-cgroups. +- +-At one extreme, each resource controller or subsystem could be in a +-separate hierarchy; at the other extreme, all subsystems +-would be attached to the same hierarchy. +- +-As an example of a scenario (originally proposed by vatsa@in.ibm.com) +-that can benefit from multiple hierarchies, consider a large +-university server with various users - students, professors, system +-tasks etc. The resource planning for this server could be along the +-following lines: +- +- CPU : Top cpuset +- / \ +- CPUSet1 CPUSet2 +- | | +- (Profs) (Students) +- +- In addition (system tasks) are attached to topcpuset (so +- that they can run anywhere) with a limit of 20% +- +- Memory : Professors (50%), students (30%), system (20%) +- +- Disk : Prof (50%), students (30%), system (20%) +- +- Network : WWW browsing (20%), Network File System (60%), others (20%) +- / \ +- Prof (15%) students (5%) +- +-Browsers like firefox/lynx go into the WWW network class, while (k)nfsd go +-into NFS network class. +- +-At the same time firefox/lynx will share an appropriate CPU/Memory class +-depending on who launched it (prof/student). +- +-With the ability to classify tasks differently for different resources +-(by putting those resource subsystems in different hierarchies) then +-the admin can easily set up a script which receives exec notifications +-and depending on who is launching the browser he can +- +- # echo browser_pid > /mnt///tasks +- +-With only a single hierarchy, he now would potentially have to create +-a separate cgroup for every browser launched and associate it with +-approp network and other resource class. This may lead to +-proliferation of such cgroups. +- +-Also lets say that the administrator would like to give enhanced network +-access temporarily to a student's browser (since it is night and the user +-wants to do online gaming :)) OR give one of the students simulation +-apps enhanced CPU power, +- +-With ability to write pids directly to resource classes, it's just a +-matter of : +- +- # echo pid > /mnt/network//tasks +- (after some time) +- # echo pid > /mnt/network//tasks +- +-Without this ability, he would have to split the cgroup into +-multiple separate ones and then associate the new cgroups with the +-new resource classes. +- +- +- +-1.3 How are cgroups implemented ? +---------------------------------- +- +-Control Groups extends the kernel as follows: +- +- - Each task in the system has a reference-counted pointer to a +- css_set. +- +- - A css_set contains a set of reference-counted pointers to +- cgroup_subsys_state objects, one for each cgroup subsystem +- registered in the system. There is no direct link from a task to +- the cgroup of which it's a member in each hierarchy, but this +- can be determined by following pointers through the +- cgroup_subsys_state objects. This is because accessing the +- subsystem state is something that's expected to happen frequently +- and in performance-critical code, whereas operations that require a +- task's actual cgroup assignments (in particular, moving between +- cgroups) are less common. A linked list runs through the cg_list +- field of each task_struct using the css_set, anchored at +- css_set->tasks. +- +- - A cgroup hierarchy filesystem can be mounted for browsing and +- manipulation from user space. +- +- - You can list all the tasks (by pid) attached to any cgroup. +- +-The implementation of cgroups requires a few, simple hooks +-into the rest of the kernel, none in performance critical paths: +- +- - in init/main.c, to initialize the root cgroups and initial +- css_set at system boot. +- +- - in fork and exit, to attach and detach a task from its css_set. +- +-In addition a new file system, of type "cgroup" may be mounted, to +-enable browsing and modifying the cgroups presently known to the +-kernel. When mounting a cgroup hierarchy, you may specify a +-comma-separated list of subsystems to mount as the filesystem mount +-options. By default, mounting the cgroup filesystem attempts to +-mount a hierarchy containing all registered subsystems. +- +-If an active hierarchy with exactly the same set of subsystems already +-exists, it will be reused for the new mount. If no existing hierarchy +-matches, and any of the requested subsystems are in use in an existing +-hierarchy, the mount will fail with -EBUSY. Otherwise, a new hierarchy +-is activated, associated with the requested subsystems. +- +-It's not currently possible to bind a new subsystem to an active +-cgroup hierarchy, or to unbind a subsystem from an active cgroup +-hierarchy. This may be possible in future, but is fraught with nasty +-error-recovery issues. +- +-When a cgroup filesystem is unmounted, if there are any +-child cgroups created below the top-level cgroup, that hierarchy +-will remain active even though unmounted; if there are no +-child cgroups then the hierarchy will be deactivated. +- +-No new system calls are added for cgroups - all support for +-querying and modifying cgroups is via this cgroup file system. +- +-Each task under /proc has an added file named 'cgroup' displaying, +-for each active hierarchy, the subsystem names and the cgroup name +-as the path relative to the root of the cgroup file system. +- +-Each cgroup is represented by a directory in the cgroup file system +-containing the following files describing that cgroup: +- +- - tasks: list of tasks (by pid) attached to that cgroup +- - releasable flag: cgroup currently removeable? +- - notify_on_release flag: run the release agent on exit? +- - release_agent: the path to use for release notifications (this file +- exists in the top cgroup only) +- +-Other subsystems such as cpusets may add additional files in each +-cgroup dir. +- +-New cgroups are created using the mkdir system call or shell +-command. The properties of a cgroup, such as its flags, are +-modified by writing to the appropriate file in that cgroups +-directory, as listed above. +- +-The named hierarchical structure of nested cgroups allows partitioning +-a large system into nested, dynamically changeable, "soft-partitions". +- +-The attachment of each task, automatically inherited at fork by any +-children of that task, to a cgroup allows organizing the work load +-on a system into related sets of tasks. A task may be re-attached to +-any other cgroup, if allowed by the permissions on the necessary +-cgroup file system directories. +- +-When a task is moved from one cgroup to another, it gets a new +-css_set pointer - if there's an already existing css_set with the +-desired collection of cgroups then that group is reused, else a new +-css_set is allocated. Note that the current implementation uses a +-linear search to locate an appropriate existing css_set, so isn't +-very efficient. A future version will use a hash table for better +-performance. +- +-To allow access from a cgroup to the css_sets (and hence tasks) +-that comprise it, a set of cg_cgroup_link objects form a lattice; +-each cg_cgroup_link is linked into a list of cg_cgroup_links for +-a single cgroup on its cgrp_link_list field, and a list of +-cg_cgroup_links for a single css_set on its cg_link_list. +- +-Thus the set of tasks in a cgroup can be listed by iterating over +-each css_set that references the cgroup, and sub-iterating over +-each css_set's task set. +- +-The use of a Linux virtual file system (vfs) to represent the +-cgroup hierarchy provides for a familiar permission and name space +-for cgroups, with a minimum of additional kernel code. +- +-1.4 What does notify_on_release do ? +------------------------------------- +- +-If the notify_on_release flag is enabled (1) in a cgroup, then +-whenever the last task in the cgroup leaves (exits or attaches to +-some other cgroup) and the last child cgroup of that cgroup +-is removed, then the kernel runs the command specified by the contents +-of the "release_agent" file in that hierarchy's root directory, +-supplying the pathname (relative to the mount point of the cgroup +-file system) of the abandoned cgroup. This enables automatic +-removal of abandoned cgroups. The default value of +-notify_on_release in the root cgroup at system boot is disabled +-(0). The default value of other cgroups at creation is the current +-value of their parents notify_on_release setting. The default value of +-a cgroup hierarchy's release_agent path is empty. +- +-1.5 How do I use cgroups ? +--------------------------- +- +-To start a new job that is to be contained within a cgroup, using +-the "cpuset" cgroup subsystem, the steps are something like: +- +- 1) mkdir /dev/cgroup +- 2) mount -t cgroup -ocpuset cpuset /dev/cgroup +- 3) Create the new cgroup by doing mkdir's and write's (or echo's) in +- the /dev/cgroup virtual file system. +- 4) Start a task that will be the "founding father" of the new job. +- 5) Attach that task to the new cgroup by writing its pid to the +- /dev/cgroup tasks file for that cgroup. +- 6) fork, exec or clone the job tasks from this founding father task. +- +-For example, the following sequence of commands will setup a cgroup +-named "Charlie", containing just CPUs 2 and 3, and Memory Node 1, +-and then start a subshell 'sh' in that cgroup: +- +- mount -t cgroup cpuset -ocpuset /dev/cgroup +- cd /dev/cgroup +- mkdir Charlie +- cd Charlie +- /bin/echo 2-3 > cpuset.cpus +- /bin/echo 1 > cpuset.mems +- /bin/echo $$ > tasks +- sh +- # The subshell 'sh' is now running in cgroup Charlie +- # The next line should display '/Charlie' +- cat /proc/self/cgroup +- +-2. Usage Examples and Syntax +-============================ +- +-2.1 Basic Usage +---------------- +- +-Creating, modifying, using the cgroups can be done through the cgroup +-virtual filesystem. +- +-To mount a cgroup hierarchy will all available subsystems, type: +-# mount -t cgroup xxx /dev/cgroup +- +-The "xxx" is not interpreted by the cgroup code, but will appear in +-/proc/mounts so may be any useful identifying string that you like. +- +-To mount a cgroup hierarchy with just the cpuset and numtasks +-subsystems, type: +-# mount -t cgroup -o cpuset,numtasks hier1 /dev/cgroup +- +-To change the set of subsystems bound to a mounted hierarchy, just +-remount with different options: +- +-# mount -o remount,cpuset,ns /dev/cgroup +- +-Note that changing the set of subsystems is currently only supported +-when the hierarchy consists of a single (root) cgroup. Supporting +-the ability to arbitrarily bind/unbind subsystems from an existing +-cgroup hierarchy is intended to be implemented in the future. +- +-Then under /dev/cgroup you can find a tree that corresponds to the +-tree of the cgroups in the system. For instance, /dev/cgroup +-is the cgroup that holds the whole system. +- +-If you want to create a new cgroup under /dev/cgroup: +-# cd /dev/cgroup +-# mkdir my_cgroup +- +-Now you want to do something with this cgroup. +-# cd my_cgroup +- +-In this directory you can find several files: +-# ls +-notify_on_release releasable tasks +-(plus whatever files added by the attached subsystems) +- +-Now attach your shell to this cgroup: +-# /bin/echo $$ > tasks +- +-You can also create cgroups inside your cgroup by using mkdir in this +-directory. +-# mkdir my_sub_cs +- +-To remove a cgroup, just use rmdir: +-# rmdir my_sub_cs +- +-This will fail if the cgroup is in use (has cgroups inside, or +-has processes attached, or is held alive by other subsystem-specific +-reference). +- +-2.2 Attaching processes +------------------------ +- +-# /bin/echo PID > tasks +- +-Note that it is PID, not PIDs. You can only attach ONE task at a time. +-If you have several tasks to attach, you have to do it one after another: +- +-# /bin/echo PID1 > tasks +-# /bin/echo PID2 > tasks +- ... +-# /bin/echo PIDn > tasks +- +-You can attach the current shell task by echoing 0: +- +-# echo 0 > tasks +- +-3. Kernel API +-============= +- +-3.1 Overview +------------- +- +-Each kernel subsystem that wants to hook into the generic cgroup +-system needs to create a cgroup_subsys object. This contains +-various methods, which are callbacks from the cgroup system, along +-with a subsystem id which will be assigned by the cgroup system. +- +-Other fields in the cgroup_subsys object include: +- +-- subsys_id: a unique array index for the subsystem, indicating which +- entry in cgroup->subsys[] this subsystem should be managing. +- +-- name: should be initialized to a unique subsystem name. Should be +- no longer than MAX_CGROUP_TYPE_NAMELEN. +- +-- early_init: indicate if the subsystem needs early initialization +- at system boot. +- +-Each cgroup object created by the system has an array of pointers, +-indexed by subsystem id; this pointer is entirely managed by the +-subsystem; the generic cgroup code will never touch this pointer. +- +-3.2 Synchronization +-------------------- +- +-There is a global mutex, cgroup_mutex, used by the cgroup +-system. This should be taken by anything that wants to modify a +-cgroup. It may also be taken to prevent cgroups from being +-modified, but more specific locks may be more appropriate in that +-situation. +- +-See kernel/cgroup.c for more details. +- +-Subsystems can take/release the cgroup_mutex via the functions +-cgroup_lock()/cgroup_unlock(). +- +-Accessing a task's cgroup pointer may be done in the following ways: +-- while holding cgroup_mutex +-- while holding the task's alloc_lock (via task_lock()) +-- inside an rcu_read_lock() section via rcu_dereference() +- +-3.3 Subsystem API +------------------ +- +-Each subsystem should: +- +-- add an entry in linux/cgroup_subsys.h +-- define a cgroup_subsys object called _subsys +- +-Each subsystem may export the following methods. The only mandatory +-methods are create/destroy. Any others that are null are presumed to +-be successful no-ops. +- +-struct cgroup_subsys_state *create(struct cgroup_subsys *ss, +- struct cgroup *cgrp) +-(cgroup_mutex held by caller) +- +-Called to create a subsystem state object for a cgroup. The +-subsystem should allocate its subsystem state object for the passed +-cgroup, returning a pointer to the new object on success or a +-negative error code. On success, the subsystem pointer should point to +-a structure of type cgroup_subsys_state (typically embedded in a +-larger subsystem-specific object), which will be initialized by the +-cgroup system. Note that this will be called at initialization to +-create the root subsystem state for this subsystem; this case can be +-identified by the passed cgroup object having a NULL parent (since +-it's the root of the hierarchy) and may be an appropriate place for +-initialization code. +- +-void destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +-(cgroup_mutex held by caller) +- +-The cgroup system is about to destroy the passed cgroup; the subsystem +-should do any necessary cleanup and free its subsystem state +-object. By the time this method is called, the cgroup has already been +-unlinked from the file system and from the child list of its parent; +-cgroup->parent is still valid. (Note - can also be called for a +-newly-created cgroup if an error occurs after this subsystem's +-create() method has been called for the new cgroup). +- +-void pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +-(cgroup_mutex held by caller) +- +-Called before checking the reference count on each subsystem. This may +-be useful for subsystems which have some extra references even if +-there are not tasks in the cgroup. +- +-int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, +- struct task_struct *task) +-(cgroup_mutex held by caller) +- +-Called prior to moving a task into a cgroup; if the subsystem +-returns an error, this will abort the attach operation. If a NULL +-task is passed, then a successful result indicates that *any* +-unspecified task can be moved into the cgroup. Note that this isn't +-called on a fork. If this method returns 0 (success) then this should +-remain valid while the caller holds cgroup_mutex. +- +-void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, +- struct cgroup *old_cgrp, struct task_struct *task) +- +-Called after the task has been attached to the cgroup, to allow any +-post-attachment activity that requires memory allocations or blocking. +- +-void fork(struct cgroup_subsy *ss, struct task_struct *task) +- +-Called when a task is forked into a cgroup. +- +-void exit(struct cgroup_subsys *ss, struct task_struct *task) +- +-Called during task exit. +- +-int populate(struct cgroup_subsys *ss, struct cgroup *cgrp) +- +-Called after creation of a cgroup to allow a subsystem to populate +-the cgroup directory with file entries. The subsystem should make +-calls to cgroup_add_file() with objects of type cftype (see +-include/linux/cgroup.h for details). Note that although this +-method can return an error code, the error code is currently not +-always handled well. +- +-void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp) +- +-Called at the end of cgroup_clone() to do any paramater +-initialization which might be required before a task could attach. For +-example in cpusets, no task may attach before 'cpus' and 'mems' are set +-up. +- +-void bind(struct cgroup_subsys *ss, struct cgroup *root) +-(cgroup_mutex held by caller) +- +-Called when a cgroup subsystem is rebound to a different hierarchy +-and root cgroup. Currently this will only involve movement between +-the default hierarchy (which never has sub-cgroups) and a hierarchy +-that is being created/destroyed (and hence has no sub-cgroups). +- +-4. Questions +-============ +- +-Q: what's up with this '/bin/echo' ? +-A: bash's builtin 'echo' command does not check calls to write() against +- errors. If you use it in the cgroup file system, you won't be +- able to tell whether a command succeeded or failed. +- +-Q: When I attach processes, only the first of the line gets really attached ! +-A: We can only return one error code per call to write(). So you should also +- put only ONE pid. +- +--- /dev/null ++++ b/Documentation/cgroups/cgroups.txt +@@ -0,0 +1,548 @@ ++ CGROUPS ++ ------- ++ ++Written by Paul Menage based on Documentation/cpusets.txt ++ ++Original copyright statements from cpusets.txt: ++Portions Copyright (C) 2004 BULL SA. ++Portions Copyright (c) 2004-2006 Silicon Graphics, Inc. ++Modified by Paul Jackson ++Modified by Christoph Lameter ++ ++CONTENTS: ++========= ++ ++1. Control Groups ++ 1.1 What are cgroups ? ++ 1.2 Why are cgroups needed ? ++ 1.3 How are cgroups implemented ? ++ 1.4 What does notify_on_release do ? ++ 1.5 How do I use cgroups ? ++2. Usage Examples and Syntax ++ 2.1 Basic Usage ++ 2.2 Attaching processes ++3. Kernel API ++ 3.1 Overview ++ 3.2 Synchronization ++ 3.3 Subsystem API ++4. Questions ++ ++1. Control Groups ++================= ++ ++1.1 What are cgroups ? ++---------------------- ++ ++Control Groups provide a mechanism for aggregating/partitioning sets of ++tasks, and all their future children, into hierarchical groups with ++specialized behaviour. ++ ++Definitions: ++ ++A *cgroup* associates a set of tasks with a set of parameters for one ++or more subsystems. ++ ++A *subsystem* is a module that makes use of the task grouping ++facilities provided by cgroups to treat groups of tasks in ++particular ways. A subsystem is typically a "resource controller" that ++schedules a resource or applies per-cgroup limits, but it may be ++anything that wants to act on a group of processes, e.g. a ++virtualization subsystem. ++ ++A *hierarchy* is a set of cgroups arranged in a tree, such that ++every task in the system is in exactly one of the cgroups in the ++hierarchy, and a set of subsystems; each subsystem has system-specific ++state attached to each cgroup in the hierarchy. Each hierarchy has ++an instance of the cgroup virtual filesystem associated with it. ++ ++At any one time there may be multiple active hierachies of task ++cgroups. Each hierarchy is a partition of all tasks in the system. ++ ++User level code may create and destroy cgroups by name in an ++instance of the cgroup virtual file system, specify and query to ++which cgroup a task is assigned, and list the task pids assigned to ++a cgroup. Those creations and assignments only affect the hierarchy ++associated with that instance of the cgroup file system. ++ ++On their own, the only use for cgroups is for simple job ++tracking. The intention is that other subsystems hook into the generic ++cgroup support to provide new attributes for cgroups, such as ++accounting/limiting the resources which processes in a cgroup can ++access. For example, cpusets (see Documentation/cpusets.txt) allows ++you to associate a set of CPUs and a set of memory nodes with the ++tasks in each cgroup. ++ ++1.2 Why are cgroups needed ? ++---------------------------- ++ ++There are multiple efforts to provide process aggregations in the ++Linux kernel, mainly for resource tracking purposes. Such efforts ++include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server ++namespaces. These all require the basic notion of a ++grouping/partitioning of processes, with newly forked processes ending ++in the same group (cgroup) as their parent process. ++ ++The kernel cgroup patch provides the minimum essential kernel ++mechanisms required to efficiently implement such groups. It has ++minimal impact on the system fast paths, and provides hooks for ++specific subsystems such as cpusets to provide additional behaviour as ++desired. ++ ++Multiple hierarchy support is provided to allow for situations where ++the division of tasks into cgroups is distinctly different for ++different subsystems - having parallel hierarchies allows each ++hierarchy to be a natural division of tasks, without having to handle ++complex combinations of tasks that would be present if several ++unrelated subsystems needed to be forced into the same tree of ++cgroups. ++ ++At one extreme, each resource controller or subsystem could be in a ++separate hierarchy; at the other extreme, all subsystems ++would be attached to the same hierarchy. ++ ++As an example of a scenario (originally proposed by vatsa@in.ibm.com) ++that can benefit from multiple hierarchies, consider a large ++university server with various users - students, professors, system ++tasks etc. The resource planning for this server could be along the ++following lines: ++ ++ CPU : Top cpuset ++ / \ ++ CPUSet1 CPUSet2 ++ | | ++ (Profs) (Students) ++ ++ In addition (system tasks) are attached to topcpuset (so ++ that they can run anywhere) with a limit of 20% ++ ++ Memory : Professors (50%), students (30%), system (20%) ++ ++ Disk : Prof (50%), students (30%), system (20%) ++ ++ Network : WWW browsing (20%), Network File System (60%), others (20%) ++ / \ ++ Prof (15%) students (5%) ++ ++Browsers like firefox/lynx go into the WWW network class, while (k)nfsd go ++into NFS network class. ++ ++At the same time firefox/lynx will share an appropriate CPU/Memory class ++depending on who launched it (prof/student). ++ ++With the ability to classify tasks differently for different resources ++(by putting those resource subsystems in different hierarchies) then ++the admin can easily set up a script which receives exec notifications ++and depending on who is launching the browser he can ++ ++ # echo browser_pid > /mnt///tasks ++ ++With only a single hierarchy, he now would potentially have to create ++a separate cgroup for every browser launched and associate it with ++approp network and other resource class. This may lead to ++proliferation of such cgroups. ++ ++Also lets say that the administrator would like to give enhanced network ++access temporarily to a student's browser (since it is night and the user ++wants to do online gaming :)) OR give one of the students simulation ++apps enhanced CPU power, ++ ++With ability to write pids directly to resource classes, it's just a ++matter of : ++ ++ # echo pid > /mnt/network//tasks ++ (after some time) ++ # echo pid > /mnt/network//tasks ++ ++Without this ability, he would have to split the cgroup into ++multiple separate ones and then associate the new cgroups with the ++new resource classes. ++ ++ ++ ++1.3 How are cgroups implemented ? ++--------------------------------- ++ ++Control Groups extends the kernel as follows: ++ ++ - Each task in the system has a reference-counted pointer to a ++ css_set. ++ ++ - A css_set contains a set of reference-counted pointers to ++ cgroup_subsys_state objects, one for each cgroup subsystem ++ registered in the system. There is no direct link from a task to ++ the cgroup of which it's a member in each hierarchy, but this ++ can be determined by following pointers through the ++ cgroup_subsys_state objects. This is because accessing the ++ subsystem state is something that's expected to happen frequently ++ and in performance-critical code, whereas operations that require a ++ task's actual cgroup assignments (in particular, moving between ++ cgroups) are less common. A linked list runs through the cg_list ++ field of each task_struct using the css_set, anchored at ++ css_set->tasks. ++ ++ - A cgroup hierarchy filesystem can be mounted for browsing and ++ manipulation from user space. ++ ++ - You can list all the tasks (by pid) attached to any cgroup. ++ ++The implementation of cgroups requires a few, simple hooks ++into the rest of the kernel, none in performance critical paths: ++ ++ - in init/main.c, to initialize the root cgroups and initial ++ css_set at system boot. ++ ++ - in fork and exit, to attach and detach a task from its css_set. ++ ++In addition a new file system, of type "cgroup" may be mounted, to ++enable browsing and modifying the cgroups presently known to the ++kernel. When mounting a cgroup hierarchy, you may specify a ++comma-separated list of subsystems to mount as the filesystem mount ++options. By default, mounting the cgroup filesystem attempts to ++mount a hierarchy containing all registered subsystems. ++ ++If an active hierarchy with exactly the same set of subsystems already ++exists, it will be reused for the new mount. If no existing hierarchy ++matches, and any of the requested subsystems are in use in an existing ++hierarchy, the mount will fail with -EBUSY. Otherwise, a new hierarchy ++is activated, associated with the requested subsystems. ++ ++It's not currently possible to bind a new subsystem to an active ++cgroup hierarchy, or to unbind a subsystem from an active cgroup ++hierarchy. This may be possible in future, but is fraught with nasty ++error-recovery issues. ++ ++When a cgroup filesystem is unmounted, if there are any ++child cgroups created below the top-level cgroup, that hierarchy ++will remain active even though unmounted; if there are no ++child cgroups then the hierarchy will be deactivated. ++ ++No new system calls are added for cgroups - all support for ++querying and modifying cgroups is via this cgroup file system. ++ ++Each task under /proc has an added file named 'cgroup' displaying, ++for each active hierarchy, the subsystem names and the cgroup name ++as the path relative to the root of the cgroup file system. ++ ++Each cgroup is represented by a directory in the cgroup file system ++containing the following files describing that cgroup: ++ ++ - tasks: list of tasks (by pid) attached to that cgroup ++ - releasable flag: cgroup currently removeable? ++ - notify_on_release flag: run the release agent on exit? ++ - release_agent: the path to use for release notifications (this file ++ exists in the top cgroup only) ++ ++Other subsystems such as cpusets may add additional files in each ++cgroup dir. ++ ++New cgroups are created using the mkdir system call or shell ++command. The properties of a cgroup, such as its flags, are ++modified by writing to the appropriate file in that cgroups ++directory, as listed above. ++ ++The named hierarchical structure of nested cgroups allows partitioning ++a large system into nested, dynamically changeable, "soft-partitions". ++ ++The attachment of each task, automatically inherited at fork by any ++children of that task, to a cgroup allows organizing the work load ++on a system into related sets of tasks. A task may be re-attached to ++any other cgroup, if allowed by the permissions on the necessary ++cgroup file system directories. ++ ++When a task is moved from one cgroup to another, it gets a new ++css_set pointer - if there's an already existing css_set with the ++desired collection of cgroups then that group is reused, else a new ++css_set is allocated. Note that the current implementation uses a ++linear search to locate an appropriate existing css_set, so isn't ++very efficient. A future version will use a hash table for better ++performance. ++ ++To allow access from a cgroup to the css_sets (and hence tasks) ++that comprise it, a set of cg_cgroup_link objects form a lattice; ++each cg_cgroup_link is linked into a list of cg_cgroup_links for ++a single cgroup on its cgrp_link_list field, and a list of ++cg_cgroup_links for a single css_set on its cg_link_list. ++ ++Thus the set of tasks in a cgroup can be listed by iterating over ++each css_set that references the cgroup, and sub-iterating over ++each css_set's task set. ++ ++The use of a Linux virtual file system (vfs) to represent the ++cgroup hierarchy provides for a familiar permission and name space ++for cgroups, with a minimum of additional kernel code. ++ ++1.4 What does notify_on_release do ? ++------------------------------------ ++ ++If the notify_on_release flag is enabled (1) in a cgroup, then ++whenever the last task in the cgroup leaves (exits or attaches to ++some other cgroup) and the last child cgroup of that cgroup ++is removed, then the kernel runs the command specified by the contents ++of the "release_agent" file in that hierarchy's root directory, ++supplying the pathname (relative to the mount point of the cgroup ++file system) of the abandoned cgroup. This enables automatic ++removal of abandoned cgroups. The default value of ++notify_on_release in the root cgroup at system boot is disabled ++(0). The default value of other cgroups at creation is the current ++value of their parents notify_on_release setting. The default value of ++a cgroup hierarchy's release_agent path is empty. ++ ++1.5 How do I use cgroups ? ++-------------------------- ++ ++To start a new job that is to be contained within a cgroup, using ++the "cpuset" cgroup subsystem, the steps are something like: ++ ++ 1) mkdir /dev/cgroup ++ 2) mount -t cgroup -ocpuset cpuset /dev/cgroup ++ 3) Create the new cgroup by doing mkdir's and write's (or echo's) in ++ the /dev/cgroup virtual file system. ++ 4) Start a task that will be the "founding father" of the new job. ++ 5) Attach that task to the new cgroup by writing its pid to the ++ /dev/cgroup tasks file for that cgroup. ++ 6) fork, exec or clone the job tasks from this founding father task. ++ ++For example, the following sequence of commands will setup a cgroup ++named "Charlie", containing just CPUs 2 and 3, and Memory Node 1, ++and then start a subshell 'sh' in that cgroup: ++ ++ mount -t cgroup cpuset -ocpuset /dev/cgroup ++ cd /dev/cgroup ++ mkdir Charlie ++ cd Charlie ++ /bin/echo 2-3 > cpuset.cpus ++ /bin/echo 1 > cpuset.mems ++ /bin/echo $$ > tasks ++ sh ++ # The subshell 'sh' is now running in cgroup Charlie ++ # The next line should display '/Charlie' ++ cat /proc/self/cgroup ++ ++2. Usage Examples and Syntax ++============================ ++ ++2.1 Basic Usage ++--------------- ++ ++Creating, modifying, using the cgroups can be done through the cgroup ++virtual filesystem. ++ ++To mount a cgroup hierarchy will all available subsystems, type: ++# mount -t cgroup xxx /dev/cgroup ++ ++The "xxx" is not interpreted by the cgroup code, but will appear in ++/proc/mounts so may be any useful identifying string that you like. ++ ++To mount a cgroup hierarchy with just the cpuset and numtasks ++subsystems, type: ++# mount -t cgroup -o cpuset,numtasks hier1 /dev/cgroup ++ ++To change the set of subsystems bound to a mounted hierarchy, just ++remount with different options: ++ ++# mount -o remount,cpuset,ns /dev/cgroup ++ ++Note that changing the set of subsystems is currently only supported ++when the hierarchy consists of a single (root) cgroup. Supporting ++the ability to arbitrarily bind/unbind subsystems from an existing ++cgroup hierarchy is intended to be implemented in the future. ++ ++Then under /dev/cgroup you can find a tree that corresponds to the ++tree of the cgroups in the system. For instance, /dev/cgroup ++is the cgroup that holds the whole system. ++ ++If you want to create a new cgroup under /dev/cgroup: ++# cd /dev/cgroup ++# mkdir my_cgroup ++ ++Now you want to do something with this cgroup. ++# cd my_cgroup ++ ++In this directory you can find several files: ++# ls ++notify_on_release releasable tasks ++(plus whatever files added by the attached subsystems) ++ ++Now attach your shell to this cgroup: ++# /bin/echo $$ > tasks ++ ++You can also create cgroups inside your cgroup by using mkdir in this ++directory. ++# mkdir my_sub_cs ++ ++To remove a cgroup, just use rmdir: ++# rmdir my_sub_cs ++ ++This will fail if the cgroup is in use (has cgroups inside, or ++has processes attached, or is held alive by other subsystem-specific ++reference). ++ ++2.2 Attaching processes ++----------------------- ++ ++# /bin/echo PID > tasks ++ ++Note that it is PID, not PIDs. You can only attach ONE task at a time. ++If you have several tasks to attach, you have to do it one after another: ++ ++# /bin/echo PID1 > tasks ++# /bin/echo PID2 > tasks ++ ... ++# /bin/echo PIDn > tasks ++ ++You can attach the current shell task by echoing 0: ++ ++# echo 0 > tasks ++ ++3. Kernel API ++============= ++ ++3.1 Overview ++------------ ++ ++Each kernel subsystem that wants to hook into the generic cgroup ++system needs to create a cgroup_subsys object. This contains ++various methods, which are callbacks from the cgroup system, along ++with a subsystem id which will be assigned by the cgroup system. ++ ++Other fields in the cgroup_subsys object include: ++ ++- subsys_id: a unique array index for the subsystem, indicating which ++ entry in cgroup->subsys[] this subsystem should be managing. ++ ++- name: should be initialized to a unique subsystem name. Should be ++ no longer than MAX_CGROUP_TYPE_NAMELEN. ++ ++- early_init: indicate if the subsystem needs early initialization ++ at system boot. ++ ++Each cgroup object created by the system has an array of pointers, ++indexed by subsystem id; this pointer is entirely managed by the ++subsystem; the generic cgroup code will never touch this pointer. ++ ++3.2 Synchronization ++------------------- ++ ++There is a global mutex, cgroup_mutex, used by the cgroup ++system. This should be taken by anything that wants to modify a ++cgroup. It may also be taken to prevent cgroups from being ++modified, but more specific locks may be more appropriate in that ++situation. ++ ++See kernel/cgroup.c for more details. ++ ++Subsystems can take/release the cgroup_mutex via the functions ++cgroup_lock()/cgroup_unlock(). ++ ++Accessing a task's cgroup pointer may be done in the following ways: ++- while holding cgroup_mutex ++- while holding the task's alloc_lock (via task_lock()) ++- inside an rcu_read_lock() section via rcu_dereference() ++ ++3.3 Subsystem API ++----------------- ++ ++Each subsystem should: ++ ++- add an entry in linux/cgroup_subsys.h ++- define a cgroup_subsys object called _subsys ++ ++Each subsystem may export the following methods. The only mandatory ++methods are create/destroy. Any others that are null are presumed to ++be successful no-ops. ++ ++struct cgroup_subsys_state *create(struct cgroup_subsys *ss, ++ struct cgroup *cgrp) ++(cgroup_mutex held by caller) ++ ++Called to create a subsystem state object for a cgroup. The ++subsystem should allocate its subsystem state object for the passed ++cgroup, returning a pointer to the new object on success or a ++negative error code. On success, the subsystem pointer should point to ++a structure of type cgroup_subsys_state (typically embedded in a ++larger subsystem-specific object), which will be initialized by the ++cgroup system. Note that this will be called at initialization to ++create the root subsystem state for this subsystem; this case can be ++identified by the passed cgroup object having a NULL parent (since ++it's the root of the hierarchy) and may be an appropriate place for ++initialization code. ++ ++void destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) ++(cgroup_mutex held by caller) ++ ++The cgroup system is about to destroy the passed cgroup; the subsystem ++should do any necessary cleanup and free its subsystem state ++object. By the time this method is called, the cgroup has already been ++unlinked from the file system and from the child list of its parent; ++cgroup->parent is still valid. (Note - can also be called for a ++newly-created cgroup if an error occurs after this subsystem's ++create() method has been called for the new cgroup). ++ ++void pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); ++(cgroup_mutex held by caller) ++ ++Called before checking the reference count on each subsystem. This may ++be useful for subsystems which have some extra references even if ++there are not tasks in the cgroup. ++ ++int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, ++ struct task_struct *task) ++(cgroup_mutex held by caller) ++ ++Called prior to moving a task into a cgroup; if the subsystem ++returns an error, this will abort the attach operation. If a NULL ++task is passed, then a successful result indicates that *any* ++unspecified task can be moved into the cgroup. Note that this isn't ++called on a fork. If this method returns 0 (success) then this should ++remain valid while the caller holds cgroup_mutex. ++ ++void attach(struct cgroup_subsys *ss, struct cgroup *cgrp, ++ struct cgroup *old_cgrp, struct task_struct *task) ++ ++Called after the task has been attached to the cgroup, to allow any ++post-attachment activity that requires memory allocations or blocking. ++ ++void fork(struct cgroup_subsy *ss, struct task_struct *task) ++ ++Called when a task is forked into a cgroup. ++ ++void exit(struct cgroup_subsys *ss, struct task_struct *task) ++ ++Called during task exit. ++ ++int populate(struct cgroup_subsys *ss, struct cgroup *cgrp) ++ ++Called after creation of a cgroup to allow a subsystem to populate ++the cgroup directory with file entries. The subsystem should make ++calls to cgroup_add_file() with objects of type cftype (see ++include/linux/cgroup.h for details). Note that although this ++method can return an error code, the error code is currently not ++always handled well. ++ ++void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp) ++ ++Called at the end of cgroup_clone() to do any paramater ++initialization which might be required before a task could attach. For ++example in cpusets, no task may attach before 'cpus' and 'mems' are set ++up. ++ ++void bind(struct cgroup_subsys *ss, struct cgroup *root) ++(cgroup_mutex held by caller) ++ ++Called when a cgroup subsystem is rebound to a different hierarchy ++and root cgroup. Currently this will only involve movement between ++the default hierarchy (which never has sub-cgroups) and a hierarchy ++that is being created/destroyed (and hence has no sub-cgroups). ++ ++4. Questions ++============ ++ ++Q: what's up with this '/bin/echo' ? ++A: bash's builtin 'echo' command does not check calls to write() against ++ errors. If you use it in the cgroup file system, you won't be ++ able to tell whether a command succeeded or failed. ++ ++Q: When I attach processes, only the first of the line gets really attached ! ++A: We can only return one error code per call to write(). So you should also ++ put only ONE pid. ++ +--- /dev/null ++++ b/Documentation/cgroups/freezer-subsystem.txt +@@ -0,0 +1,102 @@ ++The cgroup freezer is useful to batch job management system which start ++and stop sets of tasks in order to schedule the resources of a machine ++according to the desires of a system administrator. This sort of program ++is often used on HPC clusters to schedule access to the cluster as a ++whole. The cgroup freezer uses cgroups to describe the set of tasks to ++be started/stopped by the batch job management system. It also provides ++a means to start and stop the tasks composing the job. ++ ++The cgroup freezer will also be useful for checkpointing running groups ++of tasks. The freezer allows the checkpoint code to obtain a consistent ++image of the tasks by attempting to force the tasks in a cgroup into a ++quiescent state. Once the tasks are quiescent another task can ++walk /proc or invoke a kernel interface to gather information about the ++quiesced tasks. Checkpointed tasks can be restarted later should a ++recoverable error occur. This also allows the checkpointed tasks to be ++migrated between nodes in a cluster by copying the gathered information ++to another node and restarting the tasks there. ++ ++Sequences of SIGSTOP and SIGCONT are not always sufficient for stopping ++and resuming tasks in userspace. Both of these signals are observable ++from within the tasks we wish to freeze. While SIGSTOP cannot be caught, ++blocked, or ignored it can be seen by waiting or ptracing parent tasks. ++SIGCONT is especially unsuitable since it can be caught by the task. Any ++programs designed to watch for SIGSTOP and SIGCONT could be broken by ++attempting to use SIGSTOP and SIGCONT to stop and resume tasks. We can ++demonstrate this problem using nested bash shells: ++ ++ $ echo $$ ++ 16644 ++ $ bash ++ $ echo $$ ++ 16690 ++ ++ From a second, unrelated bash shell: ++ $ kill -SIGSTOP 16690 ++ $ kill -SIGCONT 16990 ++ ++ ++ ++This happens because bash can observe both signals and choose how it ++responds to them. ++ ++Another example of a program which catches and responds to these ++signals is gdb. In fact any program designed to use ptrace is likely to ++have a problem with this method of stopping and resuming tasks. ++ ++In contrast, the cgroup freezer uses the kernel freezer code to ++prevent the freeze/unfreeze cycle from becoming visible to the tasks ++being frozen. This allows the bash example above and gdb to run as ++expected. ++ ++The freezer subsystem in the container filesystem defines a file named ++freezer.state. Writing "FROZEN" to the state file will freeze all tasks in the ++cgroup. Subsequently writing "THAWED" will unfreeze the tasks in the cgroup. ++Reading will return the current state. ++ ++Note freezer.state doesn't exist in root cgroup, which means root cgroup ++is non-freezable. ++ ++* Examples of usage : ++ ++ # mkdir /containers ++ # mount -t cgroup -ofreezer freezer /containers ++ # mkdir /containers/0 ++ # echo $some_pid > /containers/0/tasks ++ ++to get status of the freezer subsystem : ++ ++ # cat /containers/0/freezer.state ++ THAWED ++ ++to freeze all tasks in the container : ++ ++ # echo FROZEN > /containers/0/freezer.state ++ # cat /containers/0/freezer.state ++ FREEZING ++ # cat /containers/0/freezer.state ++ FROZEN ++ ++to unfreeze all tasks in the container : ++ ++ # echo THAWED > /containers/0/freezer.state ++ # cat /containers/0/freezer.state ++ THAWED ++ ++This is the basic mechanism which should do the right thing for user space task ++in a simple scenario. ++ ++It's important to note that freezing can be incomplete. In that case we return ++EBUSY. This means that some tasks in the cgroup are busy doing something that ++prevents us from completely freezing the cgroup at this time. After EBUSY, ++the cgroup will remain partially frozen -- reflected by freezer.state reporting ++"FREEZING" when read. The state will remain "FREEZING" until one of these ++things happens: ++ ++ 1) Userspace cancels the freezing operation by writing "THAWED" to ++ the freezer.state file ++ 2) Userspace retries the freezing operation by writing "FROZEN" to ++ the freezer.state file (writing "FREEZING" is not legal ++ and returns EINVAL) ++ 3) The tasks that blocked the cgroup from entering the "FROZEN" ++ state disappear from the cgroup's set of tasks. +--- a/Documentation/cpusets.txt ++++ b/Documentation/cpusets.txt +@@ -48,7 +48,7 @@ hooks, beyond what is already present, r + job placement on large systems. + + Cpusets use the generic cgroup subsystem described in +-Documentation/cgroup.txt. ++Documentation/cgroups/cgroups.txt. + + Requests by a task, using the sched_setaffinity(2) system call to + include CPUs in its CPU affinity mask, and using the mbind(2) and +--- a/arch/alpha/Kconfig ++++ b/arch/alpha/Kconfig +@@ -72,6 +72,7 @@ config ARCH_SUPPORTS_AOUT + def_bool y + + source "init/Kconfig" ++source "kernel/Kconfig.freezer" + + + menu "System setup" +--- a/arch/alpha/include/asm/thread_info.h ++++ b/arch/alpha/include/asm/thread_info.h +@@ -74,12 +74,14 @@ register struct thread_info *__current_t + #define TIF_UAC_SIGBUS 7 + #define TIF_MEMDIE 8 + #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */ ++#define TIF_FREEZE 16 /* is freezing for suspend */ + + #define _TIF_SYSCALL_TRACE (1< + #include + +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_FREEZER + /* + * Check if a process has been frozen + */ +@@ -39,29 +39,14 @@ static inline void clear_freeze_flag(str + clear_tsk_thread_flag(p, TIF_FREEZE); + } + +-/* +- * Wake up a frozen process +- * +- * task_lock() is taken to prevent the race with refrigerator() which may +- * occur if the freezing of tasks fails. Namely, without the lock, if the +- * freezing of tasks failed, thaw_tasks() might have run before a task in +- * refrigerator() could call frozen_process(), in which case the task would be +- * frozen and no one would thaw it. +- */ +-static inline int thaw_process(struct task_struct *p) +-{ +- task_lock(p); +- if (frozen(p)) { +- p->flags &= ~PF_FROZEN; +- task_unlock(p); +- wake_up_process(p); +- return 1; +- } +- clear_freeze_flag(p); +- task_unlock(p); +- return 0; ++static inline bool should_send_signal(struct task_struct *p) ++{ ++ return !(p->flags & PF_FREEZER_NOSIG); + } + ++/* Takes and releases task alloc lock using task_lock() */ ++extern int thaw_process(struct task_struct *p); ++ + extern void refrigerator(void); + extern int freeze_processes(void); + extern void thaw_processes(void); +@@ -75,6 +60,15 @@ static inline int try_to_freeze(void) + return 0; + } + ++extern bool freeze_task(struct task_struct *p, bool sig_only); ++extern void cancel_freezing(struct task_struct *p); ++ ++#ifdef CONFIG_CGROUP_FREEZER ++extern int cgroup_frozen(struct task_struct *task); ++#else /* !CONFIG_CGROUP_FREEZER */ ++static inline int cgroup_frozen(struct task_struct *task) { return 0; } ++#endif /* !CONFIG_CGROUP_FREEZER */ ++ + /* + * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it + * calls wait_for_completion(&vfork) and reset right after it returns from this +@@ -166,7 +160,7 @@ static inline void set_freezable_with_si + } while (try_to_freeze()); \ + __retval; \ + }) +-#else /* !CONFIG_PM_SLEEP */ ++#else /* !CONFIG_FREEZER */ + static inline int frozen(struct task_struct *p) { return 0; } + static inline int freezing(struct task_struct *p) { return 0; } + static inline void set_freeze_flag(struct task_struct *p) {} +@@ -191,6 +185,6 @@ static inline void set_freezable_with_si + #define wait_event_freezable_timeout(wq, condition, timeout) \ + wait_event_interruptible_timeout(wq, condition, timeout) + +-#endif /* !CONFIG_PM_SLEEP */ ++#endif /* !CONFIG_FREEZER */ + + #endif /* FREEZER_H_INCLUDED */ +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -303,6 +303,13 @@ config CGROUP_NS + for instance virtual servers and checkpoint/restart + jobs. + ++config CGROUP_FREEZER ++ bool "control group freezer subsystem" ++ depends on CGROUPS ++ help ++ Provides a way to freeze and unfreeze all tasks in a ++ cgroup. ++ + config CGROUP_DEVICE + bool "Device controller for cgroups" + depends on CGROUPS && EXPERIMENTAL +--- /dev/null ++++ b/kernel/Kconfig.freezer +@@ -0,0 +1,2 @@ ++config FREEZER ++ def_bool PM_SLEEP || CGROUP_FREEZER +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -22,6 +22,7 @@ CFLAGS_REMOVE_sched_clock.o = -pg + CFLAGS_REMOVE_sched.o = -pg + endif + ++obj-$(CONFIG_FREEZER) += freezer.o + obj-$(CONFIG_PROFILING) += profile.o + obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o + obj-$(CONFIG_STACKTRACE) += stacktrace.o +@@ -54,6 +55,7 @@ obj-$(CONFIG_BACKTRACE_SELF_TEST) += bac + obj-$(CONFIG_COMPAT) += compat.o + obj-$(CONFIG_CGROUPS) += cgroup.o + obj-$(CONFIG_CGROUP_DEBUG) += cgroup_debug.o ++obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o + obj-$(CONFIG_CPUSETS) += cpuset.o + obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o + obj-$(CONFIG_UTS_NS) += utsname.o +--- /dev/null ++++ b/kernel/cgroup_freezer.c +@@ -0,0 +1,379 @@ ++/* ++ * cgroup_freezer.c - control group freezer subsystem ++ * ++ * Copyright IBM Corporation, 2007 ++ * ++ * Author : Cedric Le Goater ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2.1 of the GNU Lesser General Public License ++ * as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum freezer_state { ++ CGROUP_THAWED = 0, ++ CGROUP_FREEZING, ++ CGROUP_FROZEN, ++}; ++ ++struct freezer { ++ struct cgroup_subsys_state css; ++ enum freezer_state state; ++ spinlock_t lock; /* protects _writes_ to state */ ++}; ++ ++static inline struct freezer *cgroup_freezer( ++ struct cgroup *cgroup) ++{ ++ return container_of( ++ cgroup_subsys_state(cgroup, freezer_subsys_id), ++ struct freezer, css); ++} ++ ++static inline struct freezer *task_freezer(struct task_struct *task) ++{ ++ return container_of(task_subsys_state(task, freezer_subsys_id), ++ struct freezer, css); ++} ++ ++int cgroup_frozen(struct task_struct *task) ++{ ++ struct freezer *freezer; ++ enum freezer_state state; ++ ++ task_lock(task); ++ freezer = task_freezer(task); ++ state = freezer->state; ++ task_unlock(task); ++ ++ return state == CGROUP_FROZEN; ++} ++ ++/* ++ * cgroups_write_string() limits the size of freezer state strings to ++ * CGROUP_LOCAL_BUFFER_SIZE ++ */ ++static const char *freezer_state_strs[] = { ++ "THAWED", ++ "FREEZING", ++ "FROZEN", ++}; ++ ++/* ++ * State diagram ++ * Transitions are caused by userspace writes to the freezer.state file. ++ * The values in parenthesis are state labels. The rest are edge labels. ++ * ++ * (THAWED) --FROZEN--> (FREEZING) --FROZEN--> (FROZEN) ++ * ^ ^ | | ++ * | \_______THAWED_______/ | ++ * \__________________________THAWED____________/ ++ */ ++ ++struct cgroup_subsys freezer_subsys; ++ ++/* Locks taken and their ordering ++ * ------------------------------ ++ * css_set_lock ++ * cgroup_mutex (AKA cgroup_lock) ++ * task->alloc_lock (AKA task_lock) ++ * freezer->lock ++ * task->sighand->siglock ++ * ++ * cgroup code forces css_set_lock to be taken before task->alloc_lock ++ * ++ * freezer_create(), freezer_destroy(): ++ * cgroup_mutex [ by cgroup core ] ++ * ++ * can_attach(): ++ * cgroup_mutex ++ * ++ * cgroup_frozen(): ++ * task->alloc_lock (to get task's cgroup) ++ * ++ * freezer_fork() (preserving fork() performance means can't take cgroup_mutex): ++ * task->alloc_lock (to get task's cgroup) ++ * freezer->lock ++ * sighand->siglock (if the cgroup is freezing) ++ * ++ * freezer_read(): ++ * cgroup_mutex ++ * freezer->lock ++ * read_lock css_set_lock (cgroup iterator start) ++ * ++ * freezer_write() (freeze): ++ * cgroup_mutex ++ * freezer->lock ++ * read_lock css_set_lock (cgroup iterator start) ++ * sighand->siglock ++ * ++ * freezer_write() (unfreeze): ++ * cgroup_mutex ++ * freezer->lock ++ * read_lock css_set_lock (cgroup iterator start) ++ * task->alloc_lock (to prevent races with freeze_task()) ++ * sighand->siglock ++ */ ++static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, ++ struct cgroup *cgroup) ++{ ++ struct freezer *freezer; ++ ++ freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL); ++ if (!freezer) ++ return ERR_PTR(-ENOMEM); ++ ++ spin_lock_init(&freezer->lock); ++ freezer->state = CGROUP_THAWED; ++ return &freezer->css; ++} ++ ++static void freezer_destroy(struct cgroup_subsys *ss, ++ struct cgroup *cgroup) ++{ ++ kfree(cgroup_freezer(cgroup)); ++} ++ ++/* Task is frozen or will freeze immediately when next it gets woken */ ++static bool is_task_frozen_enough(struct task_struct *task) ++{ ++ return frozen(task) || ++ (task_is_stopped_or_traced(task) && freezing(task)); ++} ++ ++/* ++ * The call to cgroup_lock() in the freezer.state write method prevents ++ * a write to that file racing against an attach, and hence the ++ * can_attach() result will remain valid until the attach completes. ++ */ ++static int freezer_can_attach(struct cgroup_subsys *ss, ++ struct cgroup *new_cgroup, ++ struct task_struct *task) ++{ ++ struct freezer *freezer; ++ ++ /* ++ * Anything frozen can't move or be moved to/from. ++ * ++ * Since orig_freezer->state == FROZEN means that @task has been ++ * frozen, so it's sufficient to check the latter condition. ++ */ ++ ++ if (is_task_frozen_enough(task)) ++ return -EBUSY; ++ ++ freezer = cgroup_freezer(new_cgroup); ++ if (freezer->state == CGROUP_FROZEN) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) ++{ ++ struct freezer *freezer; ++ ++ /* ++ * No lock is needed, since the task isn't on tasklist yet, ++ * so it can't be moved to another cgroup, which means the ++ * freezer won't be removed and will be valid during this ++ * function call. ++ */ ++ freezer = task_freezer(task); ++ ++ /* ++ * The root cgroup is non-freezable, so we can skip the ++ * following check. ++ */ ++ if (!freezer->css.cgroup->parent) ++ return; ++ ++ spin_lock_irq(&freezer->lock); ++ BUG_ON(freezer->state == CGROUP_FROZEN); ++ ++ /* Locking avoids race with FREEZING -> THAWED transitions. */ ++ if (freezer->state == CGROUP_FREEZING) ++ freeze_task(task, true); ++ spin_unlock_irq(&freezer->lock); ++} ++ ++/* ++ * caller must hold freezer->lock ++ */ ++static void update_freezer_state(struct cgroup *cgroup, ++ struct freezer *freezer) ++{ ++ struct cgroup_iter it; ++ struct task_struct *task; ++ unsigned int nfrozen = 0, ntotal = 0; ++ ++ cgroup_iter_start(cgroup, &it); ++ while ((task = cgroup_iter_next(cgroup, &it))) { ++ ntotal++; ++ if (is_task_frozen_enough(task)) ++ nfrozen++; ++ } ++ ++ /* ++ * Transition to FROZEN when no new tasks can be added ensures ++ * that we never exist in the FROZEN state while there are unfrozen ++ * tasks. ++ */ ++ if (nfrozen == ntotal) ++ freezer->state = CGROUP_FROZEN; ++ else if (nfrozen > 0) ++ freezer->state = CGROUP_FREEZING; ++ else ++ freezer->state = CGROUP_THAWED; ++ cgroup_iter_end(cgroup, &it); ++} ++ ++static int freezer_read(struct cgroup *cgroup, struct cftype *cft, ++ struct seq_file *m) ++{ ++ struct freezer *freezer; ++ enum freezer_state state; ++ ++ if (!cgroup_lock_live_group(cgroup)) ++ return -ENODEV; ++ ++ freezer = cgroup_freezer(cgroup); ++ spin_lock_irq(&freezer->lock); ++ state = freezer->state; ++ if (state == CGROUP_FREEZING) { ++ /* We change from FREEZING to FROZEN lazily if the cgroup was ++ * only partially frozen when we exitted write. */ ++ update_freezer_state(cgroup, freezer); ++ state = freezer->state; ++ } ++ spin_unlock_irq(&freezer->lock); ++ cgroup_unlock(); ++ ++ seq_puts(m, freezer_state_strs[state]); ++ seq_putc(m, '\n'); ++ return 0; ++} ++ ++static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) ++{ ++ struct cgroup_iter it; ++ struct task_struct *task; ++ unsigned int num_cant_freeze_now = 0; ++ ++ freezer->state = CGROUP_FREEZING; ++ cgroup_iter_start(cgroup, &it); ++ while ((task = cgroup_iter_next(cgroup, &it))) { ++ if (!freeze_task(task, true)) ++ continue; ++ if (is_task_frozen_enough(task)) ++ continue; ++ if (!freezing(task) && !freezer_should_skip(task)) ++ num_cant_freeze_now++; ++ } ++ cgroup_iter_end(cgroup, &it); ++ ++ return num_cant_freeze_now ? -EBUSY : 0; ++} ++ ++static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) ++{ ++ struct cgroup_iter it; ++ struct task_struct *task; ++ ++ cgroup_iter_start(cgroup, &it); ++ while ((task = cgroup_iter_next(cgroup, &it))) { ++ thaw_process(task); ++ } ++ cgroup_iter_end(cgroup, &it); ++ ++ freezer->state = CGROUP_THAWED; ++} ++ ++static int freezer_change_state(struct cgroup *cgroup, ++ enum freezer_state goal_state) ++{ ++ struct freezer *freezer; ++ int retval = 0; ++ ++ freezer = cgroup_freezer(cgroup); ++ ++ spin_lock_irq(&freezer->lock); ++ ++ update_freezer_state(cgroup, freezer); ++ if (goal_state == freezer->state) ++ goto out; ++ ++ switch (goal_state) { ++ case CGROUP_THAWED: ++ unfreeze_cgroup(cgroup, freezer); ++ break; ++ case CGROUP_FROZEN: ++ retval = try_to_freeze_cgroup(cgroup, freezer); ++ break; ++ default: ++ BUG(); ++ } ++out: ++ spin_unlock_irq(&freezer->lock); ++ ++ return retval; ++} ++ ++static int freezer_write(struct cgroup *cgroup, ++ struct cftype *cft, ++ const char *buffer) ++{ ++ int retval; ++ enum freezer_state goal_state; ++ ++ if (strcmp(buffer, freezer_state_strs[CGROUP_THAWED]) == 0) ++ goal_state = CGROUP_THAWED; ++ else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0) ++ goal_state = CGROUP_FROZEN; ++ else ++ return -EINVAL; ++ ++ if (!cgroup_lock_live_group(cgroup)) ++ return -ENODEV; ++ retval = freezer_change_state(cgroup, goal_state); ++ cgroup_unlock(); ++ return retval; ++} ++ ++static struct cftype files[] = { ++ { ++ .name = "state", ++ .read_seq_string = freezer_read, ++ .write_string = freezer_write, ++ }, ++}; ++ ++static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup) ++{ ++ if (!cgroup->parent) ++ return 0; ++ return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files)); ++} ++ ++struct cgroup_subsys freezer_subsys = { ++ .name = "freezer", ++ .create = freezer_create, ++ .destroy = freezer_destroy, ++ .populate = freezer_populate, ++ .subsys_id = freezer_subsys_id, ++ .can_attach = freezer_can_attach, ++ .attach = NULL, ++ .fork = freezer_fork, ++ .exit = NULL, ++}; +--- /dev/null ++++ b/kernel/freezer.c +@@ -0,0 +1,154 @@ ++/* ++ * kernel/freezer.c - Function to freeze a process ++ * ++ * Originally from kernel/power/process.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * freezing is complete, mark current process as frozen ++ */ ++static inline void frozen_process(void) ++{ ++ if (!unlikely(current->flags & PF_NOFREEZE)) { ++ current->flags |= PF_FROZEN; ++ wmb(); ++ } ++ clear_freeze_flag(current); ++} ++ ++/* Refrigerator is place where frozen processes are stored :-). */ ++void refrigerator(void) ++{ ++ /* Hmm, should we be allowed to suspend when there are realtime ++ processes around? */ ++ long save; ++ ++ task_lock(current); ++ if (freezing(current)) { ++ frozen_process(); ++ task_unlock(current); ++ } else { ++ task_unlock(current); ++ return; ++ } ++ save = current->state; ++ pr_debug("%s entered refrigerator\n", current->comm); ++ ++ spin_lock_irq(¤t->sighand->siglock); ++ recalc_sigpending(); /* We sent fake signal, clean it up */ ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ for (;;) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ if (!frozen(current)) ++ break; ++ schedule(); ++ } ++ pr_debug("%s left refrigerator\n", current->comm); ++ __set_current_state(save); ++} ++EXPORT_SYMBOL(refrigerator); ++ ++static void fake_signal_wake_up(struct task_struct *p) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&p->sighand->siglock, flags); ++ signal_wake_up(p, 0); ++ spin_unlock_irqrestore(&p->sighand->siglock, flags); ++} ++ ++/** ++ * freeze_task - send a freeze request to given task ++ * @p: task to send the request to ++ * @sig_only: if set, the request will only be sent if the task has the ++ * PF_FREEZER_NOSIG flag unset ++ * Return value: 'false', if @sig_only is set and the task has ++ * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise ++ * ++ * The freeze request is sent by setting the tasks's TIF_FREEZE flag and ++ * either sending a fake signal to it or waking it up, depending on whether ++ * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task ++ * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its ++ * TIF_FREEZE flag will not be set. ++ */ ++bool freeze_task(struct task_struct *p, bool sig_only) ++{ ++ /* ++ * We first check if the task is freezing and next if it has already ++ * been frozen to avoid the race with frozen_process() which first marks ++ * the task as frozen and next clears its TIF_FREEZE. ++ */ ++ if (!freezing(p)) { ++ rmb(); ++ if (frozen(p)) ++ return false; ++ ++ if (!sig_only || should_send_signal(p)) ++ set_freeze_flag(p); ++ else ++ return false; ++ } ++ ++ if (should_send_signal(p)) { ++ if (!signal_pending(p)) ++ fake_signal_wake_up(p); ++ } else if (sig_only) { ++ return false; ++ } else { ++ wake_up_state(p, TASK_INTERRUPTIBLE); ++ } ++ ++ return true; ++} ++ ++void cancel_freezing(struct task_struct *p) ++{ ++ unsigned long flags; ++ ++ if (freezing(p)) { ++ pr_debug(" clean up: %s\n", p->comm); ++ clear_freeze_flag(p); ++ spin_lock_irqsave(&p->sighand->siglock, flags); ++ recalc_sigpending_and_wake(p); ++ spin_unlock_irqrestore(&p->sighand->siglock, flags); ++ } ++} ++ ++static int __thaw_process(struct task_struct *p) ++{ ++ if (frozen(p)) { ++ p->flags &= ~PF_FROZEN; ++ return 1; ++ } ++ clear_freeze_flag(p); ++ return 0; ++} ++ ++/* ++ * Wake up a frozen process ++ * ++ * task_lock() is needed to prevent the race with refrigerator() which may ++ * occur if the freezing of tasks fails. Namely, without the lock, if the ++ * freezing of tasks failed, thaw_tasks() might have run before a task in ++ * refrigerator() could call frozen_process(), in which case the task would be ++ * frozen and no one would thaw it. ++ */ ++int thaw_process(struct task_struct *p) ++{ ++ task_lock(p); ++ if (__thaw_process(p) == 1) { ++ task_unlock(p); ++ wake_up_process(p); ++ return 1; ++ } ++ task_unlock(p); ++ return 0; ++} ++EXPORT_SYMBOL(thaw_process); +--- a/kernel/power/process.c ++++ b/kernel/power/process.c +@@ -28,121 +28,6 @@ static inline int freezeable(struct task + return 1; + } + +-/* +- * freezing is complete, mark current process as frozen +- */ +-static inline void frozen_process(void) +-{ +- if (!unlikely(current->flags & PF_NOFREEZE)) { +- current->flags |= PF_FROZEN; +- wmb(); +- } +- clear_freeze_flag(current); +-} +- +-/* Refrigerator is place where frozen processes are stored :-). */ +-void refrigerator(void) +-{ +- /* Hmm, should we be allowed to suspend when there are realtime +- processes around? */ +- long save; +- +- task_lock(current); +- if (freezing(current)) { +- frozen_process(); +- task_unlock(current); +- } else { +- task_unlock(current); +- return; +- } +- save = current->state; +- pr_debug("%s entered refrigerator\n", current->comm); +- +- spin_lock_irq(¤t->sighand->siglock); +- recalc_sigpending(); /* We sent fake signal, clean it up */ +- spin_unlock_irq(¤t->sighand->siglock); +- +- for (;;) { +- set_current_state(TASK_UNINTERRUPTIBLE); +- if (!frozen(current)) +- break; +- schedule(); +- } +- pr_debug("%s left refrigerator\n", current->comm); +- __set_current_state(save); +-} +- +-static void fake_signal_wake_up(struct task_struct *p) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&p->sighand->siglock, flags); +- signal_wake_up(p, 0); +- spin_unlock_irqrestore(&p->sighand->siglock, flags); +-} +- +-static inline bool should_send_signal(struct task_struct *p) +-{ +- return !(p->flags & PF_FREEZER_NOSIG); +-} +- +-/** +- * freeze_task - send a freeze request to given task +- * @p: task to send the request to +- * @sig_only: if set, the request will only be sent if the task has the +- * PF_FREEZER_NOSIG flag unset +- * Return value: 'false', if @sig_only is set and the task has +- * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise +- * +- * The freeze request is sent by setting the tasks's TIF_FREEZE flag and +- * either sending a fake signal to it or waking it up, depending on whether +- * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task +- * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its +- * TIF_FREEZE flag will not be set. +- */ +-static bool freeze_task(struct task_struct *p, bool sig_only) +-{ +- /* +- * We first check if the task is freezing and next if it has already +- * been frozen to avoid the race with frozen_process() which first marks +- * the task as frozen and next clears its TIF_FREEZE. +- */ +- if (!freezing(p)) { +- rmb(); +- if (frozen(p)) +- return false; +- +- if (!sig_only || should_send_signal(p)) +- set_freeze_flag(p); +- else +- return false; +- } +- +- if (should_send_signal(p)) { +- if (!signal_pending(p)) +- fake_signal_wake_up(p); +- } else if (sig_only) { +- return false; +- } else { +- wake_up_state(p, TASK_INTERRUPTIBLE); +- } +- +- return true; +-} +- +-static void cancel_freezing(struct task_struct *p) +-{ +- unsigned long flags; +- +- if (freezing(p)) { +- pr_debug(" clean up: %s\n", p->comm); +- clear_freeze_flag(p); +- spin_lock_irqsave(&p->sighand->siglock, flags); +- recalc_sigpending_and_wake(p); +- spin_unlock_irqrestore(&p->sighand->siglock, flags); +- } +-} +- + static int try_to_freeze_tasks(bool sig_only) + { + struct task_struct *g, *p; +@@ -250,6 +135,9 @@ static void thaw_tasks(bool nosig_only) + if (nosig_only && should_send_signal(p)) + continue; + ++ if (cgroup_frozen(p)) ++ continue; ++ + thaw_process(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); +@@ -264,4 +152,3 @@ void thaw_processes(void) + printk("done.\n"); + } + +-EXPORT_SYMBOL(refrigerator); diff --git a/src/patches/suse-2.6.27.31/patches.suse/connector-read-mostly b/src/patches/suse-2.6.27.31/patches.suse/connector-read-mostly new file mode 100644 index 000000000..2c2020e7a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/connector-read-mostly @@ -0,0 +1,22 @@ +From: Chris Mason +Subject: Make proc_event_num_listeners __read_mostly + +This will lower the fast path costs of the userland connector code. + +Acked-by: Jeff Mahoney + +--- + drivers/connector/cn_proc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/connector/cn_proc.c ++++ b/drivers/connector/cn_proc.c +@@ -34,7 +34,7 @@ + + #define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event)) + +-static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); ++static atomic_t proc_event_num_listeners __read_mostly = ATOMIC_INIT(0); + static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; + + /* proc_event_counts is used as the sequence number of the netlink message */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/convert-novfs-to-open-soure-coding-standards.patch b/src/patches/suse-2.6.27.31/patches.suse/convert-novfs-to-open-soure-coding-standards.patch new file mode 100644 index 000000000..d4cc696ee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/convert-novfs-to-open-soure-coding-standards.patch @@ -0,0 +1,17325 @@ +From rgoldwyn@suse.de Tue Jun 10 15:41:39 2008 +From: Goldwyn Rodrigues +Date: Tue Jun 10 14:22:41 IST 2008 +Subject: Convert novfs to open soure coding standards +Message-ID: <1213088555.4964.9.camel@baloo.junglebook> + + +Convert novfs to open source coding standards. Summary - + - convert structures from typedefs to structures + - change function names + - remove unused functions + - use correct structures in function prototypes instead of void + pointers + - return immediately on error (such as ENOMEM), instead of + creating enclosing in if..else code blocks for better + understanding. + +Signed-off-by: Goldwyn Rodrigues +Signed-off-by: Greg Kroah-Hartman + +--- + fs/novfs/commands.h | 818 ++++++-------- + fs/novfs/daemon.c | 1031 ++++++------------ + fs/novfs/file.c | 894 ++++++++------- + fs/novfs/inode.c | 2950 ++++++++++++++++++---------------------------------- + fs/novfs/nwcapi.c | 2888 ++++++++++++++++++++++---------------------------- + fs/novfs/nwcapi.h | 1019 +---------------- + fs/novfs/proc.c | 85 - + fs/novfs/profile.c | 169 +- + fs/novfs/scope.c | 362 +++--- + fs/novfs/vfs.h | 406 +++---- + 10 files changed, 4133 insertions(+), 6489 deletions(-) + +--- a/fs/novfs/commands.h ++++ b/fs/novfs/commands.h +@@ -126,11 +126,7 @@ + + #pragma pack(push, 1) + +-#ifndef NWHANDLE +-typedef void *NWHANDLE; +-#endif +- +-/*typedef struct _ncl_string ++/*struct _ncl_string + { + unsigned int type; + unsigned char *buffer; +@@ -138,206 +134,127 @@ typedef void *NWHANDLE; + + } NclString, *PNclString; + */ +-typedef struct _ncl_string { ++struct ncl_string { + unsigned int type; + unsigned char *buffer; + u32 len; ++}; + +-} NclString, *PNclString; +- +-typedef struct _nwd_string { ++struct nwd_string { + unsigned int type; + unsigned int len; + unsigned int boffset; ++}; + +-} NwdString, *PNwdString; +- +-typedef struct _COMMAND_REQUEST_HEADER { ++struct novfs_command_request_header { + unsigned int CommandType; + unsigned long SequenceNumber; +- struct schandle SessionId; +-} COMMAND_REQUEST_HEADER, *PCOMMAND_REQUEST_HEADER; ++ struct novfs_schandle SessionId; ++ ++}; + +-typedef struct _COMMAND_REPLY_HEADER { ++struct novfs_command_reply_header { + unsigned long Sequence_Number; + unsigned int ErrorCode; + +-} COMMAND_REPLY_HEADER, *PCOMMAND_REPLY_HEADER; ++}; + +-typedef struct _CLOSE_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- NWHANDLE FileHandle; +-} CLOSE_REQUEST, *PCLOSE_REQUEST; +- +-typedef struct _CLOSE_REPLY { +- COMMAND_REPLY_HEADER Reply; +-} CLOSE_REPLY, *PCLOSE_REPLY; + +-typedef struct _DELETE_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_delete_file_request { ++ struct novfs_command_request_header Command; + unsigned int isDirectory; + unsigned int pathlength; + unsigned char path[1]; +-} DELETE_FILE_REQUEST, *PDELETE_FILE_REQUEST; ++}; + +-typedef struct _DELETE_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; +-} DELETE_FILE_REPLY, *PDELETE_FILE_REPLY; +- +-typedef struct _FLUSH_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- NWHANDLE FileHandle; +-} FLUSH_REQUEST, *PFLUSH_REQUEST; +- +-typedef struct _FLUSH_REPLY { +- COMMAND_REPLY_HEADER Reply; +-} FLUSH_REPLY, *PFLUSH_REPLY; +- +-typedef struct _GET_FILEINFO_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- NWHANDLE FileHandle; +-} GET_FILEINFO_REQUEST, *PGET_FILEINFO_REQUEST; +- +-typedef struct _GET_FILEINFO_REPLY { +- COMMAND_REPLY_HEADER Reply; +-} GET_FILEINFO_REPLY, *PGET_FILEINFO_REPLY; +- +-typedef struct _GET_CONNECTED_SERVER_LIST_REQUEST { +- COMMAND_REQUEST_HEADER Command; +-} GET_CONNECTED_SERVER_LIST_REQUEST, *PGET_CONNECTED_SERVER_LIST_REQUEST; ++struct novfs_delete_file_reply { ++ struct novfs_command_reply_header Reply; ++}; ++ ++struct novfs_get_connected_server_list { ++ struct novfs_command_request_header Command; ++}; + +-typedef struct _GET_CONNECTED_SERVER_LIST_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_get_connected_server_list_reply { ++ struct novfs_command_reply_header Reply; + unsigned char List[1]; +-} GET_CONNECTED_SERVER_LIST_REPLY, *PGET_CONNECTED_SERVER_LIST_REPLY; ++}; ++ ++struct novfs_get_connected_server_list_request_ex { ++ struct novfs_command_request_header Command; ++}; + +-typedef struct _GET_CONNECTED_SERVER_LIST_REQUEST_EX { +- COMMAND_REQUEST_HEADER Command; +-} GET_CONNECTED_SERVER_LIST_REQUEST_EX, *PGET_CONNECTED_SERVER_LIST_REQUEST_EX; ++struct novfs_get_connected_server_list_reply_ex { + +-typedef struct _GET_CONNECTED_SERVER_LIST_REPLY_EX { +- COMMAND_REPLY_HEADER Reply; ++ struct novfs_command_reply_header Reply; + unsigned int bufferLen; + unsigned char List[1]; + +-} GET_CONNECTED_SERVER_LIST_REPLY_EX, *PGET_CONNECTED_SERVER_LIST_REPLY_EX; ++}; + +-typedef struct _GET_SERVER_VOLUME_LIST_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_get_server_volume_list { ++ struct novfs_command_request_header Command; + unsigned int Length; + unsigned char Name[1]; +-} GET_SERVER_VOLUME_LIST_REQUEST, *PGET_SERVER_VOLUME_LIST_REQUEST; ++}; + +-typedef struct _GET_SERVER_VOLUME_LIST_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_get_server_volume_list_reply { ++ struct novfs_command_reply_header Reply; + unsigned char List[1]; +-} GET_SERVER_VOLUME_LIST_REPLY, *PGET_SERVER_VOLUME_LIST_REPLY; +- +-typedef struct _OPEN_CONNECTION_BY_ADDR_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- unsigned int address; +- +-} OPEN_CONNECTION_BY_ADDR_REQUEST, *POPEN_CONNECTION_BY_ADDR_REQUEST; +- +-typedef struct _OPEN_CONNECTION_BY_ADDR_REPLY { +- COMMAND_REPLY_HEADER Reply; +- unsigned char serverName[64]; +- unsigned char treeName[64]; +- NWHANDLE connHandle; +- +-} OPEN_CONNECTION_BY_ADDR_REPLY, *POPEN_CONNECTION_BY_ADDR_REPLY; +- +-typedef struct _OPEN_CONNECTION_BY_NAME_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- unsigned int NameLen; +- unsigned char Name[1]; +- +-} OPEN_CONNECTION_BY_NAME_REQUEST, *POPEN_CONNECTION_BY_NAME_REQUEST; ++}; + +-typedef struct _OPEN_CONNECTION_BY_NAME_REPLY { +- COMMAND_REPLY_HEADER Reply; +- unsigned char treeName[64]; +- NWHANDLE connHandle; +- +-} OPEN_CONNECTION_BY_NAME_REPLY, *POPEN_CONNECTION_BY_NAME_REPLY; +- +-/* +-typedef struct _LOGIN_IDENTITY_REQUEST +-{ +- COMMAND_REQUEST_HEADER Command; +- unsigned int treeFlags; +- unsigned char treeName[64]; +- unsigned int serverFlags; +- unsigned char serverName[64]; +- unsigned int userFlags; +- unsigned char userName[512]; +- unsigned int passwordFlags; +- unsigned char password[128]; +- +-} LOGIN_IDENTITY_REQUEST, *PLOGIN_IDENTITY_REQUEST; +- +-typedef struct _LOGIN_IDENTITY_REPLY +-{ +- COMMAND_REPLY_HEADER Reply; +- unsigned char serverName[64]; +- unsigned char treeName[64]; +- NWHANDLE connHandle; +- +-} LOGIN_IDENTITY_REPLY, *PLOGIN_IDENTITY_REPLY; +-*/ +- +-typedef struct _VERIFY_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_verify_file_request { ++ struct novfs_command_request_header Command; + unsigned int pathLen; + unsigned char path[1]; + +-} VERIFY_FILE_REQUEST, *PVERIFY_FILE_REQUEST; ++}; + +-typedef struct _VERIFY_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_verify_file_reply { ++ struct novfs_command_reply_header Reply; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; + unsigned long long fileSize; + unsigned int fileMode; + +-} VERIFY_FILE_REPLY, *PVERIFY_FILE_REPLY; ++}; + +-typedef struct _BEGIN_ENUMERATE_DIRECTORY_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_begin_enumerate_directory_request { ++ struct novfs_command_request_header Command; + unsigned int pathLen; + unsigned char path[1]; + +-} BEGIN_ENUMERATE_DIRECTORY_REQUEST, *PBEGIN_ENUMERATE_DIRECTORY_REQUEST; ++}; + +-typedef struct _BEGIN_ENUMERATE_DIRECTORY_REPLY { +- COMMAND_REPLY_HEADER Reply; +- HANDLE enumerateHandle; ++struct novfs_begin_enumerate_directory_reply { ++ struct novfs_command_reply_header Reply; ++ void *enumerateHandle; + +-} BEGIN_ENUMERATE_DIRECTORY_REPLY, *PBEGIN_ENUMERATE_DIRECTORY_REPLY; ++}; + +-typedef struct _END_ENUMERATE_DIRECTORY_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE enumerateHandle; ++struct novfs_end_enumerate_directory_request { ++ struct novfs_command_request_header Command; ++ void *enumerateHandle; + +-} END_ENUMERATE_DIRECTORY_REQUEST, *PEND_ENUMERATE_DIRECTORY_REQUEST; ++}; + +-typedef struct _END_ENUMERATE_DIRECTORY_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_end_enumerate_directory_reply { ++ struct novfs_command_reply_header Reply; + +-} END_ENUMERATE_DIRECTORY_REPLY, *PEND_ENUMERATE_DIRECTORY_REPLY; ++}; + +-typedef struct _ENUMERATE_DIRECTORY_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE enumerateHandle; ++struct novfs_enumerate_directory_request { ++ struct novfs_command_request_header Command; ++ void *enumerateHandle; + unsigned int pathLen; + unsigned char path[1]; + +-} ENUMERATE_DIRECTORY_REQUEST, *PENUMERATE_DIRECTORY_REQUEST; ++}; + +-typedef struct _ENUMERATE_DIRECTORY_REPLY { +- COMMAND_REPLY_HEADER Reply; +- HANDLE enumerateHandle; ++struct novfs_enumerate_directory_reply { ++ struct novfs_command_reply_header Reply; ++ void *enumerateHandle; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; +@@ -346,17 +263,17 @@ typedef struct _ENUMERATE_DIRECTORY_REPL + unsigned int nameLen; + unsigned char name[1]; + +-} ENUMERATE_DIRECTORY_REPLY, *PENUMERATE_DIRECTORY_REPLY; ++}; + +-typedef struct _ENUMERATE_DIRECTORY_EX_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE enumerateHandle; ++struct novfs_enumerate_directory_ex_request { ++ struct novfs_command_request_header Command; ++ void *enumerateHandle; + unsigned int pathLen; + unsigned char path[1]; + +-} ENUMERATE_DIRECTORY_EX_REQUEST, *PENUMERATE_DIRECTORY_EX_REQUEST; ++}; + +-typedef struct _ENUMERATE_DIRECTORY_EX_DATA { ++struct novfs_enumerate_directory_ex_data { + unsigned int length; + unsigned int lastAccessTime; + unsigned int modifyTime; +@@ -366,143 +283,130 @@ typedef struct _ENUMERATE_DIRECTORY_EX_D + unsigned int nameLen; + unsigned char name[1]; + +-} ENUMERATE_DIRECTORY_EX_DATA, *PENUMERATE_DIRECTORY_EX_DATA; ++}; + +-typedef struct _ENUMERATE_DIRECTORY_EX_REPLY { +- COMMAND_REPLY_HEADER Reply; +- HANDLE enumerateHandle; ++struct novfs_enumerate_directory_ex_reply { ++ struct novfs_command_reply_header Reply; ++ void *enumerateHandle; + unsigned int enumCount; + +-} ENUMERATE_DIRECTORY_EX_REPLY, *PENUMERATE_DIRECTORY_EX_REPLY; ++}; + +-typedef struct _OPEN_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_open_file_request { ++ struct novfs_command_request_header Command; + unsigned int access; /* File Access */ + unsigned int mode; /* Sharing Mode */ + unsigned int disp; /* Create Disposition */ + unsigned int pathLen; + unsigned char path[1]; + +-} OPEN_FILE_REQUEST, *POPEN_FILE_REQUEST; ++}; + +-typedef struct _OPEN_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; +- HANDLE handle; ++struct novfs_open_file_reply { ++ struct novfs_command_reply_header Reply; ++ void *handle; + unsigned int lastAccessTime; + unsigned int modifyTime; + unsigned int createTime; + unsigned int attributes; + loff_t size; + +-} OPEN_FILE_REPLY, *POPEN_FILE_REPLY; ++}; + +-typedef struct _CREATE_FILE_REQUEST { ++struct novfs_create_file_request { + +- COMMAND_REQUEST_HEADER Command; ++ struct novfs_command_request_header Command; + unsigned int pathlength; + unsigned char path[1]; + +-} CREATE_FILE_REQUEST, *PCREATE_FILE_REQUEST; ++}; + +-typedef struct _CREATE_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_create_file_reply { ++ struct novfs_command_reply_header Reply; + +-} CREATE_FILE_REPLY, *PCREATE_FILE_REPLY; ++}; + +-typedef struct _CLOSE_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE handle; ++struct novfs_close_file_request { ++ struct novfs_command_request_header Command; ++ void *handle; + +-} CLOSE_FILE_REQUEST, *PCLOSE_FILE_REQUEST; ++}; + +-typedef struct _CLOSE_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_close_file_reply { ++ struct novfs_command_reply_header Reply; + +-} CLOSE_FILE_REPLY, *PCLOSE_FILE_REPLY; ++}; + +-typedef struct _READ_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE handle; ++struct novfs_read_file_request { ++ struct novfs_command_request_header Command; ++ void *handle; + loff_t offset; + size_t len; + +-} READ_FILE_REQUEST, *PREAD_FILE_REQUEST; ++}; + +-typedef struct _READ_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_read_file_reply { ++ struct novfs_command_reply_header Reply; + unsigned long long bytesRead; + unsigned char data[1]; + +-} READ_FILE_REPLY, *PREAD_FILE_REPLY; ++}; + +-typedef struct _WRITE_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE handle; ++struct novfs_write_file_request { ++ struct novfs_command_request_header Command; ++ void *handle; + loff_t offset; + size_t len; + unsigned char data[1]; + +-} WRITE_FILE_REQUEST, *PWRITE_FILE_REQUEST; ++}; + +-typedef struct _WRITE_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_write_file_reply { ++ struct novfs_command_reply_header Reply; + unsigned long long bytesWritten; +-} WRITE_FILE_REPLY, *PWRITE_FILE_REPLY; ++}; + +-typedef struct _READ_STREAM_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE connection; ++struct novfs_read_stream_request { ++ struct novfs_command_request_header Command; ++ void *connection; + unsigned char handle[6]; + loff_t offset; + size_t len; +-} READ_STREAM_REQUEST, *PREAD_STREAM_REQUEST; ++}; + +-typedef struct _READ_STREAM_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_read_stream_reply { ++ struct novfs_command_reply_header Reply; + size_t bytesRead; + unsigned char data[1]; +-} READ_STREAM_REPLY, *PREAD_STREAM_REPLY; ++}; + +-typedef struct _WRITE_STREAM_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE connection; ++struct novfs_write_stream_request { ++ struct novfs_command_request_header Command; ++ void *connection; + unsigned char handle[6]; + loff_t offset; + size_t len; + unsigned char data[1]; +-} WRITE_STREAM_REQUEST, *PWRITE_STREAM_REQUEST; ++}; + +-typedef struct _WRITE_STREAM_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_write_stream_reply { ++ struct novfs_command_reply_header Reply; + size_t bytesWritten; +-} WRITE_STREAM_REPLY, *PWRITE_STREAM_REPLY; ++}; + +-typedef struct _CLOSE_STREAM_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE connection; ++struct novfs_close_stream_request { ++ struct novfs_command_request_header Command; ++ void *connection; + unsigned char handle[6]; +-} CLOSE_STREAM_REQUEST, *PCLOSE_STREAM_REQUEST; ++}; + +-typedef struct _CLOSE_STREAM_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_close_stream_reply { ++ struct novfs_command_reply_header Reply; + +-} CLOSE_STREAM_REPLY, *PCLOSE_STREAM_REPLY; ++}; + +-typedef struct _CREATE_DIRECTORY_REQUEST { +- +- COMMAND_REQUEST_HEADER Command; +- unsigned int pathlength; +- unsigned char path[1]; +- +-} CREATE_DIRECTORY_REQUEST, *PCREATE_DIRECTORY_REQUEST; +- +-typedef struct _CREATE_DIRECTORY_REPLY { +- COMMAND_REPLY_HEADER Reply; +- +-} CREATE_DIRECTORY_REPLY, *PCREATE_DIRECTORY_REPLY; +- +-typedef struct _LOGIN_USER_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_login_user_request { ++ struct novfs_command_request_header Command; + unsigned int srvNameType; + unsigned int serverLength; + unsigned int serverOffset; +@@ -513,46 +417,47 @@ typedef struct _LOGIN_USER_REQUEST { + unsigned int passwordLength; + unsigned int passwordOffset; + +-} LOGIN_USER_REQUEST, *PLOGIN_USER_REQUEST; ++}; + +-typedef struct _LOGIN_USER_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_login_user_reply { ++ struct novfs_command_reply_header Reply; + unsigned int connectionHandle; +- HANDLE loginIdentity; ++ void *loginIdentity; + +-} LOGIN_USER_REPLY, *PLOGIN_USER_REPLY; ++}; + +-typedef struct _LOGOUT_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_logout_request { ++ struct novfs_command_request_header Command; + unsigned int length; + unsigned char Name[1]; + +-} LOGOUT_REQUEST, *PLOGOUT_REQUEST; ++}; + +-typedef struct _LOGOUT_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_logout_reply { ++ struct novfs_command_reply_header Reply; + +-} LOGOUT_REPLY, *PLOGOUT_REPLY; ++}; + +-typedef struct _CREATE_CONTEXT_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_create_context_request { ++ struct novfs_command_request_header Command; + +-} CREATE_CONTEXT_REQUEST, *PCREATE_CONTEXT_REQUEST; ++}; + +-typedef struct _CREATE_CONTEXT_REPLY { +- COMMAND_REPLY_HEADER Reply; +- struct schandle SessionId; +-} CREATE_CONTEXT_REPLY, *PCREATE_CONTEXT_REPLY; ++struct novfs_create_context_reply { ++ struct novfs_command_reply_header Reply; ++ struct novfs_schandle SessionId; + +-typedef struct _DESTROY_CONTEXT_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++}; + +-} DESTROY_CONTEXT_REQUEST, *PDESTROY_CONTEXT_REQUEST; ++struct novfs_destroy_context_request { ++ struct novfs_command_request_header Command; + +-typedef struct _DESTROY_CONTEXT_REPLY { +- COMMAND_REPLY_HEADER Reply; ++}; + +-} DESTROY_CONTEXT_REPLY, *PDESTROY_CONTEXT_REPLY; ++struct novfs_destroy_context_reply { ++ struct novfs_command_reply_header Reply; ++ ++}; + + /* + * Attribute flags. These should be or-ed together to figure out what +@@ -572,7 +477,7 @@ typedef struct _DESTROY_CONTEXT_REPLY { + #define ATTR_ATTR_FLAG 1024 + #endif + +-typedef struct _LNX_FILE_INFO { ++struct novfs_lnx_file_info { + unsigned int ia_valid; + unsigned int ia_mode; + uid_t ia_uid; +@@ -582,126 +487,124 @@ typedef struct _LNX_FILE_INFO { + time_t ia_mtime; + time_t ia_ctime; + unsigned int ia_attr_flags; ++}; + +-} LX_FILE_INFO, *PLX_FILE_INFO; +- +-typedef struct _SET_FILE_INFO_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- LX_FILE_INFO fileInfo; ++struct novfs_set_file_info_request { ++ struct novfs_command_request_header Command; ++ struct novfs_lnx_file_info fileInfo; + unsigned int pathlength; + char path[1]; ++}; + +-} SET_FILE_INFO_REQUEST, *PSET_FILE_INFO_REQUEST; +- +-typedef struct _SET_FILE_INFO_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_set_file_info_reply { ++ struct novfs_command_reply_header Reply; + +-} SET_FILE_INFO_REPLY, *PSET_FILE_INFO_REPLY; ++}; + +-typedef struct _TRUNCATE_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_truncate_file_request { ++ struct novfs_command_request_header Command; + unsigned int pathLen; + char path[1]; + +-} TRUNCATE_FILE_REQUEST, *PTRUNCATE_FILE_REQUEST; ++}; + +-typedef struct _TRUNCATE_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_truncate_file_reply { ++ struct novfs_command_reply_header Reply; + +-} TRUNCATE_FILE_REPLY, *PTRUNCATE_FILE_REPLY; ++}; + +-typedef struct _GETPWUID_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_getpwuid_request { ++ struct novfs_command_request_header Command; + unsigned int uid; +-} GETPWUID_REQUEST, *PGETPWUID_REQUEST; ++}; + +-typedef struct _GETPWUID_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_getpwuid_reply { ++ struct novfs_command_reply_header Reply; + unsigned char UserName[1]; +-} GETPWUID_REPLY, *PGETPWUID_REPLY; ++}; + +-typedef struct _GET_VERSION_REQUEST { +- COMMAND_REQUEST_HEADER Command; +-} GET_VERSION_REQUEST, *PGET_VERSION_REQUEST; ++struct novfs_get_version_request { ++ struct novfs_command_request_header Command; ++}; + +-typedef struct _GET_VERSION_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_get_version_reply { ++ struct novfs_command_reply_header Reply; + unsigned char Version[1]; +-} GET_VERSION_REPLY, *PGET_VERSION_REPLY; ++}; + +-typedef struct _SET_MOUNT_PATH { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_set_mount_path { ++ struct novfs_command_request_header Command; + unsigned int PathLength; + unsigned char Path[1]; +-} SET_MOUNT_PATH_REQUEST, *PSET_MOUNT_PATH_REQUEST; ++}; + +-typedef struct _SET_MOUNT_PATH_REPLY { +- COMMAND_REPLY_HEADER Reply; +-} SET_MOUNT_PATH, *PSET_MOUNT_PATH_REPLY; +- +-typedef struct _GET_USER_SPACE { +- COMMAND_REQUEST_HEADER Command; +-} GET_USER_SPACE_REQUEST, *PGET_USER_SPACE_REQUEST; ++struct novfs_set_mount_path_reply { ++ struct novfs_command_reply_header Reply; ++}; ++ ++struct novfs_get_user_space { ++ struct novfs_command_request_header Command; ++}; + +-typedef struct _GET_USER_SPACE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_get_user_space_reply { ++ struct novfs_command_reply_header Reply; + uint64_t TotalSpace; + uint64_t FreeSpace; + uint64_t TotalEnties; + uint64_t FreeEnties; +-} GET_USER_SPACE_REPLY, *PGET_USER_SPACE_REPLY; ++}; + +-typedef struct _XPLAT_CALL_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_xplat_call_request { ++ struct novfs_command_request_header Command; + unsigned int NwcCommand; + unsigned long dataLen; + unsigned char data[1]; + +-} XPLAT_CALL_REQUEST, *PXPLAT_CALL_REQUEST; ++}; + +-typedef struct _XPLAT_CALL_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_xplat_call_reply { ++ struct novfs_command_reply_header Reply; + unsigned long dataLen; + unsigned char data[1]; + +-} XPLAT_CALL_REPLY, *PXPLAT_CALL_REPLY; ++}; + + /* XPlat NWC structures used by the daemon */ + +-typedef struct _NWD_OPEN_CONN_BY_NAME { +- HANDLE ConnHandle; ++struct nwd_open_conn_by_name { ++ void *ConnHandle; + unsigned int nameLen; + unsigned int oName; /* Ofset to the Name */ + unsigned int serviceLen; + unsigned int oServiceType; /* Offset to service Type; */ + unsigned int uConnFlags; + unsigned int uTranType; +- HANDLE newConnHandle; ++ void *newConnHandle; + +-} NwdCOpenConnByName, *PNwdCOpenConnByName; ++}; + +-typedef struct _NWD_TRAN_ADDR { ++struct nwd_tran_addr { + unsigned int uTransportType; + unsigned int uAddressLength; + unsigned int oAddress; + +-} NwdCTranAddr, *PNwdCTranAddr; ++}; + +-typedef struct _NWD_OPEN_CONN_BY_ADDR { +- HANDLE ConnHandle; ++struct nwd_open_conn_by_addr { ++ void *ConnHandle; + unsigned int oServiceType; + unsigned int uConnFlags; +- NwdCTranAddr TranAddr; ++ struct nwd_tran_addr TranAddr; + +-} NwdCOpenConnByAddr, *PNwdCOpenConnByAddr; ++}; + +-typedef struct _NWD_CLOSE_CONN { +- HANDLE ConnHandle; ++struct nwd_close_conn { ++ void *ConnHandle; + +-} NwdCCloseConn, *PNwdCCloseConn; ++}; + +-typedef struct _NWD_NCP_REQ { +- HANDLE ConnHandle; ++struct nwd_ncp_req { ++ void *ConnHandle; + unsigned int replyLen; + unsigned int requestLen; + unsigned int function; +@@ -710,48 +613,37 @@ typedef struct _NWD_NCP_REQ { + unsigned int flags; + unsigned char data[1]; + +-} NwdCNCPReq, *PNwdCNCPReq; ++}; + +-typedef struct _NWD_NCP_REP { ++struct nwd_ncp_rep { + unsigned int replyLen; + unsigned char data[1]; + +-} NwdCNCPRep, *PNwdCNCPRep; ++}; + +-typedef struct _NWC_AUTH_WID { +- HANDLE ConnHandle; ++struct nwc_auth_wid { ++ void *ConnHandle; + u32 AuthenticationId; + +-} NwdCAuthenticateWithId, *PNwdCAuthenticateWithId; ++}; + +-typedef struct _NWC_AUTHENTICATE { +- HANDLE ConnHandle; +- unsigned int uAuthenticationType; +- unsigned int userNameOffset; +- unsigned int passwordOffset; +- unsigned int MaxInfoLength; +- unsigned int InfoLength; +- unsigned int authenInfoOffset; +- +-} NwdCAuthenticate, *PNwdCAuthenticate; +- +-typedef struct _NWC_UNAUTHENTICATE { +- HANDLE ConnHandle; ++struct nwc_unauthenticate { ++ void *ConnHandle; + unsigned int AuthenticationId; + +-} NwdCUnauthenticate, *PNwdCUnauthenticate; ++}; + +-typedef struct _NWC_LISC_ID { +- HANDLE ConnHandle; ++struct nwc_lisc_id { ++ void *ConnHandle; + +-} NwdCLicenseConn, *PNwdCLicenseConn; ++}; + +-typedef struct _NWC_UNLIC_CONN { +- HANDLE ConnHandle; ++struct nwc_unlic_conn { ++ void *ConnHandle; + +-} NwdCUnlicenseConn, *PNwdCUnlicenseConn; ++}; + +-typedef struct _NWC_GET_IDENT_INFO { ++struct nwd_get_id_info { + u32 AuthenticationId; + unsigned int AuthType; + unsigned int NameType; +@@ -762,44 +654,44 @@ typedef struct _NWC_GET_IDENT_INFO { + unsigned int objectLen; + unsigned int pObjectNameOffset; + +-} NwdCGetIdentityInfo, *PNwdCGetIdentityInfo; ++}; + +-typedef struct _NWC_LO_ID { ++struct nwc_lo_id { + u32 AuthenticationId; + +-} NwdCLogoutIdentity, *PNwdCLogoutIdentity; ++}; + +-typedef struct _RENAME_FILE_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_rename_file_request { ++ struct novfs_command_request_header Command; + int directoryFlag; + unsigned int newnameLen; + unsigned char newname[256]; + unsigned int oldnameLen; + unsigned char oldname[256]; +-} RENAME_FILE_REQUEST, *PRENAME_FILE_REQUEST; ++}; + +-typedef struct _RENAME_FILE_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_rename_file_reply { ++ struct novfs_command_reply_header Reply; + +-} RENAME_FILE_REPLY, *PRENAME_FILE_REPLY; ++}; + +-typedef struct __NwdServerVersion { ++struct nwd_server_version { + unsigned int uMajorVersion; + unsigned short int uMinorVersion; + unsigned short int uRevision; ++}; + +-} NwdServerVersion, *PNwdServerVersion; + + #define MAX_ADDRESS_LENGTH 32 + +-typedef struct tagNwdTranAddrEx { ++struct tagNwdTranAddrEx { + unsigned int uTransportType; + unsigned int uAddressLength; + unsigned char Buffer[MAX_ADDRESS_LENGTH]; + +-} NwdTranAddr, *PNwdTranAddr; ++}; + +-typedef struct __NWD_CONN_INFO { ++struct __NWD_CONN_INFO { + unsigned int uInfoVersion; + unsigned int uAuthenticationState; + unsigned int uBroadcastState; +@@ -819,33 +711,31 @@ typedef struct __NWD_CONN_INFO { + unsigned int uDistance; + u32 uAuthId; + unsigned int uDisconnected; +- NwdServerVersion ServerVersion; +- NwdTranAddr TranAddress; +- +-} NwdConnInfo, *PNwdConnInfo; ++ struct nwd_server_version ServerVersion; ++ struct nwd_tran_addr TranAddress; ++}; + +-typedef struct _nwd_conn_info { +- HANDLE ConnHandle; ++struct nwd_conn_info { ++ void *ConnHandle; + unsigned int uInfoLevel; + unsigned int uInfoLength; ++}; + +-} NwdCGetConnInfo, *PNwdCGetConnInfo; +- +-typedef struct nwd_open_conn_by_Ref { +- HANDLE uConnReference; ++struct nwd_open_conn_by_ref { ++ void *uConnReference; + unsigned int uConnFlags; +- HANDLE ConnHandle; ++ void *ConnHandle; + +-} NwdCOpenConnByRef, *PNwdCOpenConnByRef; ++}; + +-typedef struct nwd_get_reqversion { ++struct nwd_get_reqversion { + unsigned int uMajorVersion; + unsigned int uMinorVersion; + unsigned int uRevision; + +-} NwdCGetRequesterVersion, *PNwdCGetRequesterVersion; ++}; + +-typedef struct _nwc_scan_conn_info { ++struct nwd_scan_conn_info { + unsigned int uScanIndex; + unsigned int uScanInfoLevel; + unsigned int uScanInfoLen; +@@ -856,43 +746,43 @@ typedef struct _nwc_scan_conn_info { + unsigned int uConnectionReference; + unsigned int uReturnConnInfoOffset; + +-} NwdCScanConnInfo, *PNwdCScanConnInfo; ++}; + +-typedef struct nwc_get_pref_ds_tree { ++struct nwd_get_pref_ds_tree { + unsigned int uTreeLength; + unsigned int DsTreeNameOffset; + +-} NwdCGetPreferredDsTree, *PNwdCGetPreferredDsTree; ++}; + +-typedef struct nwc_set_pref_ds_tree { ++struct nwd_set_pref_ds_tree { + unsigned int uTreeLength; + unsigned int DsTreeNameOffset; + +-} NwdCSetPreferredDsTree, *PNwdCSetPreferredDsTree; ++}; + +-typedef struct nwc_set_def_name_ctx { ++struct nwd_set_def_name_ctx { + unsigned int uTreeLength; + unsigned int TreeOffset; + unsigned int uNameLength; + unsigned int NameContextOffset; + +-} NwdCSetDefaultNameContext, *PNwdCSetDefaultNameContext; ++}; + +-typedef struct nwc_get_def_name_ctx { ++struct nwd_get_def_name_ctx { + unsigned int uTreeLength; + unsigned int TreeOffset; + unsigned int uNameLength; + unsigned int NameContextOffset; + +-} NwdCGetDefaultNameContext, *PNwdCGetDefaultNameContext; ++}; + +-typedef struct _nwc_get_treemonitored_connref { +- NwdString TreeName; +- HANDLE uConnReference; ++struct nwd_get_tree_monitored_conn_ref { ++ struct nwd_string TreeName; ++ void *uConnReference; + +-} NwdCGetTreeMonitoredConnRef, *PNwdCGetTreeMonitoredConnRef; ++}; + +-typedef struct _nwc_enumerate_identities { ++struct nwd_enum_ids { + unsigned int Iterator; + unsigned int domainNameLen; + unsigned int domainNameOffset; +@@ -904,9 +794,9 @@ typedef struct _nwc_enumerate_identities + unsigned int IdentityFlags; + u32 AuthenticationId; + +-} NwdCDEnumerateIdentities, *PNwdCEnumerateIdentities; ++}; + +-typedef struct nwd_change_key { ++struct nwd_change_key { + unsigned int domainNameOffset; + unsigned int domainNameLen; + unsigned int AuthType; +@@ -919,82 +809,43 @@ typedef struct nwd_change_key { + unsigned int newPasswordOffset; + unsigned int newPasswordLen; + +-} NwdCChangeKey, *PNwdCChangeKey; ++}; + +-typedef struct _nwd_get_primary_conn { +- HANDLE uConnReference; ++struct nwd_set_primary_conn { ++ void *ConnHandle; + +-} NwdCGetPrimaryConnection, *PNwdCGetPrimaryConnection; ++}; + +-typedef struct _nwd_set_primary_conn { +- HANDLE ConnHandle; +- +-} NwdCSetPrimaryConnection, *PNwdCSetPrimaryConnection; +- +-typedef struct _nwd_map_drive_ex { +- u32 ConnHandle; +- u32 localUid; +- u32 linkOffsetLength; +- u32 linkOffset; +- u32 dirPathOffsetLength; +- u32 dirPathOffset; +- +-} NwdCMapDriveEx, *PNwdCMapDriveEx; +- +-typedef struct _nwd_unmap_drive_ex { +- unsigned int linkLen; +- char linkPath[1]; +- +-} NwdCUnmapDriveEx, *PNwdCUnmapDriveEx; +- +-typedef struct _nwd_enum_links { +- unsigned int totalLen; +- unsigned int linkCount; +- +-} NwdCEnumLinks, *PNwdCEnumLinks; +- +-typedef struct nwd_getbroadcastnotification { ++struct nwd_get_bcast_notification { + unsigned int uMessageFlags; +- HANDLE uConnReference; ++ void *uConnReference; + unsigned int messageLen; + char message[1]; + +-} NwdCGetBroadcastNotification, *PNwdCGetBroadcastNotification; +- +-typedef struct _enum_entry { +- unsigned int entryLen; +- u32 connHdl; +- char data[0]; +-} NwdCEnumEntry, *PNwdCEnumEntry; ++}; + +-typedef struct _nwd_set_conn_info { +- HANDLE ConnHandle; ++struct nwd_set_conn_info { ++ void *ConnHandle; + unsigned int uInfoLevel; + unsigned int uInfoLength; + unsigned int offsetConnInfo; + +-} NwdCSetConnInfo, *PNwdCSetConnInfo; +- +-typedef struct _len_string { +- u32 stLen; +- char string[1]; ++}; + +-} LString, *PLString; +- +-typedef struct _DEBUG_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_debug_request { ++ struct novfs_command_request_header Command; + int cmdlen; + char dbgcmd[1]; + +-} DEBUG_REQUEST, *PDEBUG_REQUEST; ++}; + +-typedef struct _DEBUG_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_debug_reply { ++ struct novfs_command_reply_header Reply; + +-} DEBUG_REPLY, *PDEBUG_REPLY; ++}; + +-typedef struct _Nwd_Set_Key { +- HANDLE ConnHandle; ++struct nwd_set_key { ++ void *ConnHandle; + unsigned int AuthenticationId; + unsigned int objectNameLen; + unsigned int objectNameOffset; +@@ -1002,9 +853,9 @@ typedef struct _Nwd_Set_Key { + unsigned int newPasswordLen; + unsigned int newPasswordOffset; + +-} NwdCSetKey, *PNwdCSetKey; ++}; + +-typedef struct _Nwd_Verify_Key { ++struct nwd_verify_key { + unsigned int AuthType; + unsigned int NameType; + unsigned short int ObjectType; +@@ -1015,43 +866,43 @@ typedef struct _Nwd_Verify_Key { + unsigned int verifyPasswordLen; + unsigned int verifyPasswordOffset; + +-} NwdCVerifyKey, *PNwdCVerifyKey; ++}; + +-typedef struct _GET_CACHE_FLAG { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_get_cache_flag { ++ struct novfs_command_request_header Command; + int pathLen; + unsigned char path[0]; + +-} GET_CACHE_FLAG_REQUEST, *PGET_CACHE_FLAG_REQUEST; ++}; + +-typedef struct _GET_CACHE_FLAG_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_get_cache_flag_reply { ++ struct novfs_command_reply_header Reply; + int CacheFlag; + +-} GET_CACHE_FLAG_REPLY, *PGET_CACHE_FLAG_REPLY; ++}; + +-typedef struct _XA_LIST_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_xa_list_reply { ++ struct novfs_command_reply_header Reply; + unsigned char *pData; + +-} XA_LIST_REPLY, *PXA_LIST_REPLY; ++}; + +-typedef struct _XA_GET_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_xa_get_request { ++ struct novfs_command_request_header Command; + unsigned int pathLen; + unsigned int nameLen; + unsigned char data[1]; //hold path, attribute name + +-} XA_GET_REQUEST, *PXA_GET_REQUEST; ++}; + +-typedef struct _XA_GET_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_xa_get_reply { ++ struct novfs_command_reply_header Reply; + unsigned char *pData; + +-} XA_GET_REPLY, *PXA_GET_REPLY; ++}; + +-typedef struct _XA_SET_REQUEST { +- COMMAND_REQUEST_HEADER Command; ++struct novfs_xa_set_request { ++ struct novfs_command_request_header Command; + unsigned int TtlWriteDataSize; + unsigned int WritePosition; + int flags; +@@ -1060,27 +911,44 @@ typedef struct _XA_SET_REQUEST { + unsigned int valueLen; + unsigned char data[1]; //hold path, attribute name, value data + +-} XA_SET_REQUEST, *PXA_SET_REQUEST; ++}; + +-typedef struct _XA_SET_REPLY { +- COMMAND_REPLY_HEADER Reply; ++struct novfs_xa_set_reply { ++ struct novfs_command_reply_header Reply; + unsigned char *pData; + +-} XA_SET_REPLY, *PXA_SET_REPLY; ++}; + +-typedef struct _SET_FILE_LOCK_REQUEST { +- COMMAND_REQUEST_HEADER Command; +- HANDLE handle; ++struct novfs_set_file_lock_request { ++ struct novfs_command_request_header Command; ++ void *handle; + unsigned char fl_type; + loff_t fl_start; + loff_t fl_len; + +-} SET_FILE_LOCK_REQUEST, *PSET_FILE_LOCK_REQUEST; ++}; ++ ++struct novfs_set_file_lock_reply { ++ struct novfs_command_reply_header Reply; ++ ++}; + +-typedef struct _SET_FILE_LOCK_REPLY { +- COMMAND_REPLY_HEADER Reply; + +-} SET_FILE_LOCK_REPLY, *PSET_FILE_LOCK_REPLY; ++struct novfs_scope_list{ ++ struct list_head ScopeList; ++ struct novfs_schandle ScopeId; ++ struct novfs_schandle SessionId; ++ pid_t ScopePid; ++ struct task_struct *ScopeTask; ++ unsigned int ScopeHash; ++ uid_t ScopeUid; ++ uint64_t ScopeUSize; ++ uint64_t ScopeUFree; ++ uint64_t ScopeUTEnties; ++ uint64_t ScopeUAEnties; ++ int ScopeUserNameLength; ++ unsigned char ScopeUserName[32]; ++}; + + #pragma pack(pop) + +--- a/fs/novfs/daemon.c ++++ b/fs/novfs/daemon.c +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -44,14 +43,13 @@ + #define DH_TYPE_STREAM 1 + #define DH_TYPE_CONNECTION 2 + +-/*===[ Type definitions ]=================================================*/ +-typedef struct _DAEMON_QUEUE { ++struct daemon_queue { + struct list_head list; /* Must be first entry */ + spinlock_t lock; /* Used to control access to list */ + struct semaphore semaphore; /* Used to signal when data is available */ +-} daemon_queue_t; ++}; + +-typedef struct _DAEMON_COMMAND { ++struct daemon_cmd { + struct list_head list; /* Must be first entry */ + atomic_t reference; + unsigned int status; +@@ -65,61 +63,44 @@ typedef struct _DAEMON_COMMAND { + int datalen; + void *reply; + unsigned long replen; +-} daemon_command_t; ++}; + +-typedef struct _DAEMON_HANDLE_ { ++struct daemon_handle { + struct list_head list; + rwlock_t lock; +- session_t session; +-} daemon_handle_t; ++ struct novfs_schandle session; ++}; + +-typedef struct _DAEMON_RESOURCE_ { ++struct daemon_resource { + struct list_head list; + int type; +- HANDLE connection; ++ void *connection; + unsigned char handle[6]; + mode_t mode; + loff_t size; +-} daemon_resource_t; ++}; + +-typedef struct _DRIVE_MAP_ { ++struct drive_map { + struct list_head list; /* Must be first item */ +- session_t session; ++ struct novfs_schandle session; + unsigned long hash; + int namelen; + char name[1]; +-} drive_map_t; ++}; ++ ++static void Queue_get(struct daemon_cmd * Que); ++static void Queue_put(struct daemon_cmd * Que); ++static void RemoveDriveMaps(void); ++static int NwdConvertLocalHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle); ++static int NwdConvertNetwareHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle); ++static int set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session); ++static int unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session); ++static int NwdGetMountPath(struct novfs_xplat *pdata); ++static int local_unlink(const char *pathname); + +-/*===[ Function prototypes ]==============================================*/ +-int Daemon_Close_Control(struct inode *Inode, struct file *File); +-int Daemon_Library_close(struct inode *inode, struct file *file); +-int Daemon_Library_open(struct inode *inode, struct file *file); +-loff_t Daemon_Library_llseek(struct file *file, loff_t offset, int origin); +-int Daemon_Open_Control(struct inode *Inode, struct file *File); +-uint Daemon_Poll(struct file *file, struct poll_table_struct *poll_table); +-int Daemon_Remove_Resource(daemon_handle_t * DHandle, int Type, HANDLE CHandle, +- unsigned long FHandle); +- +-int Daemon_SetMountPoint(char *Path); +-void Daemon_Timer(unsigned long data); +-int Daemon_getpwuid(uid_t uid, int unamelen, char *uname); +-int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, int dlen, +- void **reply, unsigned long * replen, int interruptible); +-void Queue_get(daemon_command_t * que); +-void Queue_put(daemon_command_t * que); +-void Uninit_Daemon_Queue(void); +-daemon_command_t *find_queue(unsigned long sequence); +-daemon_command_t *get_next_queue(int Set_Queue_Waiting); +-int NwdConvertNetwareHandle(PXPLAT pdata, daemon_handle_t * DHandle); +-int NwdConvertLocalHandle(PXPLAT pdata, daemon_handle_t * DHandle); +-int NwdGetMountPath(PXPLAT pdata); +-static int NwdSetMapDrive(PXPLAT pdata, session_t Session); +-static int NwdUnMapDrive(PXPLAT pdata, session_t Session); +-void RemoveDriveMaps(void); +-int local_unlink(const char *pathname); + + /*===[ Global variables ]=================================================*/ +-static daemon_queue_t Daemon_Queue; ++static struct daemon_queue Daemon_Queue; + + static DECLARE_WAIT_QUEUE_HEAD(Read_waitqueue); + +@@ -131,51 +112,24 @@ static unsigned long Daemon_Command_Time + static DECLARE_MUTEX(DriveMapLock); + static LIST_HEAD(DriveMapList); + +-int MaxIoSize = PAGE_SIZE; ++int novfs_max_iosize = PAGE_SIZE; + +-void Init_Daemon_Queue(void) ++void novfs_daemon_queue_init() + { + INIT_LIST_HEAD(&Daemon_Queue.list); + spin_lock_init(&Daemon_Queue.lock); + init_MUTEX_LOCKED(&Daemon_Queue.semaphore); + } + +-/*++======================================================================*/ +-void Uninit_Daemon_Queue(void) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++void novfs_daemon_queue_exit(void) + { + /* Does nothing for now but we maybe should clear the queue. */ + } + + /*++======================================================================*/ +-void Daemon_Timer(unsigned long data) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static void novfs_daemon_timer(unsigned long data) + { +- daemon_command_t *que = (daemon_command_t *) data; ++ struct daemon_cmd *que = (struct daemon_cmd *) data; + + if (QUEUE_ACKED != que->status) { + que->status = QUEUE_TIMEOUT; +@@ -183,14 +137,14 @@ void Daemon_Timer(unsigned long data) + up(&que->semaphore); + } + +-int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, int dlen, ++/*++======================================================================*/ ++int Queue_Daemon_Command(void *request, ++ unsigned long reqlen, ++ void *data, ++ int dlen, + void **reply, unsigned long * replen, int interruptible) +-/* +- * Arguments: void *request - pointer to the request that is to be sent. Needs to be kernel memory. +- * int reqlen - length of the request. +- *========================================================================*/ + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + int retCode = 0; + uint64_t ts1, ts2; + +@@ -201,6 +155,7 @@ int Queue_Daemon_Command(void *request, + if (atomic_read(&Daemon_Open_Count)) { + + que = kmalloc(sizeof(*que), GFP_KERNEL); ++ + DbgPrint("Queue_Daemon_Command: que=0x%p\n", que); + if (que) { + atomic_set(&que->reference, 0); +@@ -211,7 +166,7 @@ int Queue_Daemon_Command(void *request, + + que->sequence = atomic_inc_return(&Sequence); + +- ((PCOMMAND_REQUEST_HEADER) request)->SequenceNumber = ++ ((struct novfs_command_request_header *) request)->SequenceNumber = + que->sequence; + + /* +@@ -220,7 +175,7 @@ int Queue_Daemon_Command(void *request, + init_timer(&que->timer); + que->timer.expires = jiffies + (HZ * Daemon_Command_Timeout); + que->timer.data = (unsigned long) que; +- que->timer.function = Daemon_Timer; ++ que->timer.function = novfs_daemon_timer; + add_timer(&que->timer); + + /* +@@ -317,41 +272,13 @@ int Queue_Daemon_Command(void *request, + return (retCode); + } + +-/*++======================================================================*/ +-void Queue_get(daemon_command_t * Que) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static void Queue_get(struct daemon_cmd * Que) + { + DbgPrint("Queue_get: que=0x%p %d\n", Que, atomic_read(&Que->reference)); + atomic_inc(&Que->reference); + } + +-/*++======================================================================*/ +-void Queue_put(daemon_command_t * Que) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static void Queue_put(struct daemon_cmd * Que) + { + + DbgPrint("Queue_put: que=0x%p %d\n", Que, atomic_read(&Que->reference)); +@@ -373,35 +300,21 @@ void Queue_put(daemon_command_t * Que) + } + } + +-/*++======================================================================*/ +-daemon_command_t *get_next_queue(int Set_Queue_Waiting) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++struct daemon_cmd *get_next_queue(int Set_Queue_Waiting) + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + + DbgPrint("get_next_queue: que=0x%p\n", Daemon_Queue.list.next); + + spin_lock(&Daemon_Queue.lock); +- que = (daemon_command_t *) Daemon_Queue.list.next; ++ que = (struct daemon_cmd *) Daemon_Queue.list.next; + +- while (que && (que != (daemon_command_t *) & Daemon_Queue.list.next) ++ while (que && (que != (struct daemon_cmd *) & Daemon_Queue.list.next) + && (que->status != QUEUE_SENDING)) { +- que = (daemon_command_t *) que->list.next; ++ que = (struct daemon_cmd *) que->list.next; + } + +- if ((NULL == que) || (que == (daemon_command_t *) & Daemon_Queue.list) ++ if ((NULL == que) || (que == (struct daemon_cmd *) & Daemon_Queue.list) + || (que->status != QUEUE_SENDING)) { + que = NULL; + } else if (Set_Queue_Waiting) { +@@ -418,36 +331,22 @@ daemon_command_t *get_next_queue(int Set + return (que); + } + +-/*++======================================================================*/ +-daemon_command_t *find_queue(unsigned long sequence) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static struct daemon_cmd *find_queue(unsigned long sequence) + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + + DbgPrint("find_queue: 0x%x\n", sequence); + + spin_lock(&Daemon_Queue.lock); +- que = (daemon_command_t *) Daemon_Queue.list.next; ++ que = (struct daemon_cmd *) Daemon_Queue.list.next; + +- while (que && (que != (daemon_command_t *) & Daemon_Queue.list.next) ++ while (que && (que != (struct daemon_cmd *) & Daemon_Queue.list.next) + && (que->sequence != sequence)) { +- que = (daemon_command_t *) que->list.next; ++ que = (struct daemon_cmd *) que->list.next; + } + + if ((NULL == que) +- || (que == (daemon_command_t *) & Daemon_Queue.list.next) ++ || (que == (struct daemon_cmd *) & Daemon_Queue.list.next) + || (que->sequence != sequence)) { + que = NULL; + } +@@ -462,21 +361,7 @@ daemon_command_t *find_queue(unsigned lo + return (que); + } + +-/*++======================================================================*/ +-int Daemon_Open_Control(struct inode *Inode, struct file *File) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_daemon_open_control(struct inode *Inode, struct file *File) + { + DbgPrint("Daemon_Open_Control: pid=%d Count=%d\n", current->pid, + atomic_read(&Daemon_Open_Count)); +@@ -485,23 +370,9 @@ int Daemon_Open_Control(struct inode *In + return (0); + } + +-/*++======================================================================*/ +-int Daemon_Close_Control(struct inode *Inode, struct file *File) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_daemon_close_control(struct inode *Inode, struct file *File) + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + + DbgPrint("Daemon_Close_Control: pid=%d Count=%d\n", current->pid, + atomic_read(&Daemon_Open_Count)); +@@ -512,39 +383,39 @@ int Daemon_Close_Control(struct inode *I + */ + + spin_lock(&Daemon_Queue.lock); +- que = (daemon_command_t *) Daemon_Queue.list.next; ++ que = (struct daemon_cmd *) Daemon_Queue.list.next; + + while (que +- && (que != (daemon_command_t *) & Daemon_Queue.list.next) ++ && (que != (struct daemon_cmd *) & Daemon_Queue.list.next) + && (que->status != QUEUE_DONE)) { + que->status = QUEUE_TIMEOUT; + up(&que->semaphore); + +- que = (daemon_command_t *) que->list.next; ++ que = (struct daemon_cmd *) que->list.next; + } + spin_unlock(&Daemon_Queue.lock); + + RemoveDriveMaps(); + +- Scope_Cleanup(); ++ novfs_scope_cleanup(); + } + + return (0); + } + +-ssize_t Daemon_Send_Command(struct file *file, char __user *buf, size_t len, loff_t * off) ++ssize_t novfs_daemon_cmd_send(struct file * file, char *buf, size_t len, loff_t * off) + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + size_t retValue = 0; + int Finished = 0; +- struct data_list *dlist; ++ struct novfs_data_list *dlist; + int i, dcnt, bcnt, ccnt, error; + char *vadr; + unsigned long cpylen; + + DbgPrint("Daemon_Send_Command: %u %lld\n", len, *off); +- if (len > MaxIoSize) { +- MaxIoSize = len; ++ if (len > novfs_max_iosize) { ++ novfs_max_iosize = len; + } + + while (!Finished) { +@@ -556,9 +427,9 @@ ssize_t Daemon_Send_Command(struct file + retValue = len; + } + if (retValue > 0x80) +- mydump(0x80, que->request); ++ novfs_dump(0x80, que->request); + else +- mydump(retValue, que->request); ++ novfs_dump(retValue, que->request); + + cpylen = copy_to_user(buf, que->request, retValue); + if (que->datalen && (retValue < len)) { +@@ -599,10 +470,10 @@ ssize_t Daemon_Send_Command(struct file + ("Daemon_Send_Command: Copy %d from 0x%p to 0x%p.\n", + bcnt, vadr, buf); + if (bcnt > 0x80) +- mydump(0x80, ++ novfs_dump(0x80, + vadr); + else +- mydump(bcnt, ++ novfs_dump(bcnt, + vadr); + + if (km_adr) { +@@ -646,14 +517,14 @@ ssize_t Daemon_Send_Command(struct file + return (retValue); + } + +-ssize_t Daemon_Receive_Reply(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) ++ssize_t novfs_daemon_recv_reply(struct file *file, const char *buf, size_t nbytes, loff_t * ppos) + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + size_t retValue = 0; + void *reply; + unsigned long sequence, cpylen; + +- struct data_list *dlist; ++ struct novfs_data_list *dlist; + char *vadr; + int i; + +@@ -727,9 +598,9 @@ ssize_t Daemon_Receive_Reply(struct file + thiscopy); + + if (thiscopy > 0x80) +- mydump(0x80, vadr); ++ novfs_dump(0x80, vadr); + else +- mydump(thiscopy, vadr); ++ novfs_dump(thiscopy, vadr); + + if (km_adr) { + kunmap(dlist->page); +@@ -743,17 +614,20 @@ ssize_t Daemon_Receive_Reply(struct file + que->replen = retValue; + } else { + reply = kmalloc(nbytes, GFP_KERNEL); +- DbgPrint("Daemon_Receive_Reply: reply=0x%p\n", reply); ++ DbgPrint("Daemon_Receive_Reply: reply=0x%p\n", ++ reply); + if (reply) { + retValue = nbytes; + que->reply = reply; + que->replen = nbytes; + +- retValue -= copy_from_user(reply, buf, retValue); ++ retValue -= ++ copy_from_user(reply, buf, ++ retValue); + if (retValue > 0x80) +- mydump(0x80, reply); ++ novfs_dump(0x80, reply); + else +- mydump(retValue, reply); ++ novfs_dump(retValue, reply); + + } else { + retValue = -ENOMEM; +@@ -775,10 +649,11 @@ ssize_t Daemon_Receive_Reply(struct file + return (retValue); + } + +-int do_login(NclString *Server, NclString *Username, NclString *Password, HANDLE *lgnId, struct schandle *Session) ++int novfs_do_login(struct ncl_string *Server, struct ncl_string *Username, ++struct ncl_string *Password, void **lgnId, struct novfs_schandle *Session) + { +- PLOGIN_USER_REQUEST cmd; +- PLOGIN_USER_REPLY reply; ++ struct novfs_login_user_request *cmd; ++ struct novfs_login_user_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, datalen; + unsigned char *data; +@@ -812,8 +687,8 @@ int do_login(NclString *Server, NclStrin + memcpy(data, Password->buffer, Password->len); + data += Password->len; + +- retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, +- &replylen, INTERRUPTIBLE); ++ retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = reply->Reply.ErrorCode; +@@ -827,18 +702,18 @@ int do_login(NclString *Server, NclStrin + } + memset(cmd, 0, cmdlen); + kfree(cmd); +- return retCode; ++ return (retCode); + + } + +-int do_logout(struct qstr *Server, struct schandle *Session) ++int novfs_daemon_logout(struct qstr *Server, struct novfs_schandle *Session) + { +- PLOGOUT_REQUEST cmd; +- PLOGOUT_REPLY reply; ++ struct novfs_logout_request *cmd; ++ struct novfs_logout_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen; + +- cmdlen = offsetof(LOGOUT_REQUEST, Name) + Server->len; ++ cmdlen = offsetof(struct novfs_logout_request, Name) + Server->len; + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; +@@ -849,7 +724,8 @@ int do_logout(struct qstr *Server, struc + cmd->length = Server->len; + memcpy(cmd->Name, Server->name, Server->len); + +- retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); + if (reply) { + if (reply->Reply.ErrorCode) { + retCode = -EIO; +@@ -861,24 +737,10 @@ int do_logout(struct qstr *Server, struc + + } + +-/*++======================================================================*/ +-int Daemon_getpwuid(uid_t uid, int unamelen, char *uname) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_daemon_getpwuid(uid_t uid, int unamelen, char *uname) + { +- GETPWUID_REQUEST cmd; +- PGETPWUID_REPLY reply; ++ struct novfs_getpwuid_request cmd; ++ struct novfs_getpwuid_reply *reply; + unsigned long replylen = 0; + int retCode; + +@@ -896,7 +758,9 @@ int Daemon_getpwuid(uid_t uid, int uname + } else { + retCode = 0; + memset(uname, 0, unamelen); +- replylen = replylen - offsetof(GETPWUID_REPLY, UserName); ++ replylen = ++ replylen - offsetof(struct ++ novfs_getpwuid_reply, UserName); + if (replylen) { + if (replylen > unamelen) { + retCode = -EINVAL; +@@ -911,24 +775,10 @@ int Daemon_getpwuid(uid_t uid, int uname + + } + +-/*++======================================================================*/ +-int Daemon_getversion(char *Buf, int length) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_daemon_getversion(char *Buf, int length) + { +- GET_VERSION_REQUEST cmd; +- PGET_VERSION_REPLY reply; ++ struct novfs_get_version_request cmd; ++ struct novfs_get_version_reply *reply; + unsigned long replylen = 0; + int retVal = 0; + +@@ -942,7 +792,9 @@ int Daemon_getversion(char *Buf, int len + if (reply->Reply.ErrorCode) { + retVal = -EIO; + } else { +- retVal = replylen - offsetof(GET_VERSION_REPLY, Version); ++ retVal = ++ replylen - offsetof(struct ++ novfs_get_version_reply, Version); + if (retVal < length) { + memcpy(Buf, reply->Version, retVal); + Buf[retVal] = '\0'; +@@ -954,13 +806,13 @@ int Daemon_getversion(char *Buf, int len + + } + +-static int daemon_login(struct login *Login, struct schandle *Session) ++static int daemon_login(struct novfs_login *Login, struct novfs_schandle *Session) + { + int retCode = -ENOMEM; +- struct login lLogin; +- NclString server; +- NclString username; +- NclString password; ++ struct novfs_login lLogin; ++ struct ncl_string server; ++ struct ncl_string username; ++ struct ncl_string password; + + if (!copy_from_user(&lLogin, Login, sizeof(lLogin))) { + server.buffer = kmalloc(lLogin.Server.length, GFP_KERNEL); +@@ -968,29 +820,29 @@ static int daemon_login(struct login *Lo + server.len = lLogin.Server.length; + server.type = NWC_STRING_TYPE_ASCII; + if (!copy_from_user((void *)server.buffer, lLogin.Server.data, server.len)) { +- username.buffer = kmalloc(lLogin.UserName.length, GFP_KERNEL); ++ username.buffer = kmalloc(lLogin.UserName.length, GFP_KERNEL); + if (username.buffer) { + username.len = lLogin.UserName.length; + username.type = NWC_STRING_TYPE_ASCII; + if (!copy_from_user((void *)username.buffer, lLogin.UserName.data, username.len)) { +- password.buffer = kmalloc(lLogin.Password.length, GFP_KERNEL); +- if (password.buffer) { ++ password.buffer = kmalloc(lLogin.Password.length, GFP_KERNEL); ++ if (password.buffer) ++ { + password.len = lLogin.Password.length; + password.type = NWC_STRING_TYPE_ASCII; + if (!copy_from_user((void *)password.buffer, lLogin.Password.data, password.len)) { +- retCode = do_login (&server, &username, &password, NULL, Session); ++ retCode = novfs_do_login (&server, &username, &password, NULL, Session); + if (!retCode) { +- char *name; +- name = Scope_Get_UserName(); +- if (name) +- Novfs_Add_to_Root(name); ++ char *username; ++ username = novfs_scope_get_username(); ++ if (username) { ++ novfs_add_to_root(username); ++ } + } + } +- memset(password.buffer, 0, password.len); + kfree(password.buffer); + } + } +- memset(username.buffer, 0, username.len); + kfree(username.buffer); + } + } +@@ -1001,32 +853,30 @@ static int daemon_login(struct login *Lo + return (retCode); + } + +-static int daemon_logout(struct logout *Logout, struct schandle *Session) ++static int daemon_logout(struct novfs_logout *Logout, struct novfs_schandle *Session) + { +- struct logout lLogout; ++ struct novfs_logout lLogout; + struct qstr server; +- int retCode = -ENOMEM; ++ int retCode = 0; + + if (copy_from_user(&lLogout, Logout, sizeof(lLogout))) + return -EFAULT; +- + server.name = kmalloc(lLogout.Server.length, GFP_KERNEL); + if (!server.name) + return -ENOMEM; + server.len = lLogout.Server.length; + if (copy_from_user((void *)server.name, lLogout.Server.data, server.len)) + goto exit; +- +- retCode = do_logout(&server, Session); ++ retCode = novfs_daemon_logout(&server, Session); + exit: + kfree(server.name); +- return retCode; ++ return (retCode); + } + +-int Daemon_CreateSessionId(struct schandle *SessionId) ++int novfs_daemon_create_sessionId(struct novfs_schandle * SessionId) + { +- CREATE_CONTEXT_REQUEST cmd; +- PCREATE_CONTEXT_REPLY reply; ++ struct novfs_create_context_request cmd; ++ struct novfs_create_context_reply *reply; + unsigned long replylen = 0; + int retCode = 0; + +@@ -1041,7 +891,7 @@ int Daemon_CreateSessionId(struct schand + &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode +- && replylen > sizeof(COMMAND_REPLY_HEADER)) { ++ && replylen > sizeof(struct novfs_command_reply_header)) { + *SessionId = reply->SessionId; + retCode = 0; + } else { +@@ -1055,26 +905,26 @@ int Daemon_CreateSessionId(struct schand + return (retCode); + } + +-int Daemon_DestroySessionId(struct schandle *SessionId) ++int novfs_daemon_destroy_sessionId(struct novfs_schandle SessionId) + { +- DESTROY_CONTEXT_REQUEST cmd; +- PDESTROY_CONTEXT_REPLY reply; ++ struct novfs_destroy_context_request cmd; ++ struct novfs_destroy_context_reply *reply; + unsigned long replylen = 0; + int retCode = 0; + +- DbgPrint("Daemon_DestroySessionId: 0x%p:%p\n", +- SessionId->hTypeId, SessionId->hId); ++ DbgPrint("Daemon_DestroySessionId: 0x%p:%p\n", SessionId.hTypeId, ++ SessionId.hId); + + cmd.Command.CommandType = VFS_COMMAND_DESTROY_CONTEXT; + cmd.Command.SequenceNumber = 0; +- memcpy(&cmd.Command.SessionId, SessionId, sizeof (*SessionId)); ++ cmd.Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode) { +- drive_map_t *dm; ++ struct drive_map *dm; + struct list_head *list; + + retCode = 0; +@@ -1085,11 +935,8 @@ int Daemon_DestroySessionId(struct schan + */ + down(&DriveMapLock); + list_for_each(list, &DriveMapList) { +- struct schandle *temp; +- +- dm = list_entry(list, drive_map_t, list); +- temp = &dm->session; +- if (SC_EQUAL(SessionId, temp)) { ++ dm = list_entry(list, struct drive_map, list); ++ if (SC_EQUAL(SessionId, dm->session)) { + local_unlink(dm->name); + list = list->prev; + list_del(&dm->list); +@@ -1107,21 +954,21 @@ int Daemon_DestroySessionId(struct schan + return (retCode); + } + +-int Daemon_Get_UserSpace(struct schandle *SessionId, uint64_t * TotalSize, ++int novfs_daemon_get_userspace(struct novfs_schandle SessionId, uint64_t * TotalSize, + uint64_t * Free, uint64_t * TotalEnties, + uint64_t * FreeEnties) + { +- GET_USER_SPACE_REQUEST cmd; +- PGET_USER_SPACE_REPLY reply; ++ struct novfs_get_user_space cmd; ++ struct novfs_get_user_space_reply *reply; + unsigned long replylen = 0; + int retCode = 0; + +- DbgPrint("Daemon_Get_UserSpace: 0x%p:%p\n", +- SessionId->hTypeId, SessionId->hId); ++ DbgPrint("Daemon_Get_UserSpace: 0x%p:%p\n", SessionId.hTypeId, ++ SessionId.hId); + + cmd.Command.CommandType = VFS_COMMAND_GET_USER_SPACE; + cmd.Command.SequenceNumber = 0; +- memcpy(&cmd.Command.SessionId, SessionId, sizeof (*SessionId)); ++ cmd.Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, +@@ -1151,36 +998,22 @@ int Daemon_Get_UserSpace(struct schandle + return (retCode); + } + +-/*++======================================================================*/ +-int Daemon_SetMountPoint(char *Path) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_daemon_set_mnt_point(char *Path) + { +- PSET_MOUNT_PATH_REQUEST cmd; +- PSET_MOUNT_PATH_REPLY reply; ++ struct novfs_set_mount_path *cmd; ++ struct novfs_set_mount_path_reply *reply; + unsigned long replylen, cmdlen; + int retCode = -ENOMEM; + + DbgPrint("Daemon_SetMountPoint: %s\n", Path); + + replylen = strlen(Path); +- cmdlen = sizeof(SET_MOUNT_PATH_REQUEST) + replylen; ++ ++ cmdlen = sizeof(struct novfs_set_mount_path) + replylen; + + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; +- + cmd->Command.CommandType = VFS_COMMAND_SET_MOUNT_PATH; + cmd->Command.SequenceNumber = 0; + SC_INITIALIZE(cmd->Command.SessionId); +@@ -1190,7 +1023,9 @@ int Daemon_SetMountPoint(char *Path) + + replylen = 0; + +- retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); + if (reply) { + if (!reply->Reply.ErrorCode) { + retCode = 0; +@@ -1203,27 +1038,13 @@ int Daemon_SetMountPoint(char *Path) + return retCode; + } + +-/*++======================================================================*/ +-int Daemon_SendDebugCmd(char *Command) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- DEBUG_REQUEST cmd; +- PDEBUG_REPLY reply; +- DEBUG_REPLY lreply; ++int novfs_daemon_debug_cmd_send(char *Command) ++{ ++ struct novfs_debug_request cmd; ++ struct novfs_debug_reply *reply; ++ struct novfs_debug_reply lreply; + unsigned long replylen, cmdlen; +- struct data_list dlist[2]; ++ struct novfs_data_list dlist[2]; + + int retCode = -ENOMEM; + +@@ -1239,7 +1060,7 @@ int Daemon_SendDebugCmd(char *Command) + dlist[1].len = sizeof(lreply); + dlist[1].rwflag = DLWRITE; + +- cmdlen = offsetof(DEBUG_REQUEST, dbgcmd); ++ cmdlen = offsetof(struct novfs_debug_request, dbgcmd); + + cmd.Command.CommandType = VFS_COMMAND_DBG; + cmd.Command.SequenceNumber = 0; +@@ -1248,7 +1069,9 @@ int Daemon_SendDebugCmd(char *Command) + + replylen = 0; + +- retCode = Queue_Daemon_Command(&cmd, cmdlen, dlist, 2, (void *)&reply, &replylen, INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command(&cmd, cmdlen, dlist, 2, (void *)&reply, ++ &replylen, INTERRUPTIBLE); + if (reply) { + kfree(reply); + } +@@ -1259,21 +1082,20 @@ int Daemon_SendDebugCmd(char *Command) + return (retCode); + } + +-int Daemon_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++int novfs_daemon_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) + { + int retCode = -ENOSYS; + unsigned long cpylen; +- struct schandle session_id; +- +- session_id = Scope_Get_SessionId(NULL); ++ struct novfs_schandle session_id; ++ session_id = novfs_scope_get_sessionId(NULL); + + switch (cmd) { + case IOC_LOGIN: +- retCode = daemon_login((struct login *)arg, &session_id); ++ retCode = daemon_login((struct novfs_login *) arg, &session_id); + break; + + case IOC_LOGOUT: +- retCode = daemon_logout((struct logout *) arg, &session_id); ++ retCode = daemon_logout((struct novfs_logout *)arg, &session_id); + break; + case IOC_DEBUGPRINT: + { +@@ -1302,7 +1124,7 @@ int Daemon_ioctl(struct inode *inode, st + + case IOC_XPLAT: + { +- XPLAT data; ++ struct novfs_xplat data; + + cpylen = + copy_from_user(&data, (void *)arg, sizeof(data)); +@@ -1324,23 +1146,29 @@ int Daemon_ioctl(struct inode *inode, st + return (retCode); + } + +-int Daemon_Added_Resource(daemon_handle_t *DHandle, int Type, HANDLE CHandle, unsigned char *FHandle, unsigned long Mode, unsigned long Size) ++static int daemon_added_resource(struct daemon_handle * DHandle, int Type, void *CHandle, ++ unsigned char * FHandle, unsigned long Mode, u_long Size) + { +- daemon_resource_t *resource; ++ struct daemon_resource *resource; + + if (FHandle) +- DbgPrint("Daemon_Added_Resource: DHandle=0x%p Type=%d CHandle=0x%p FHandle=0x%x Mode=0x%x Size=%d\n", DHandle, Type, CHandle, *(u32 *) & FHandle[2], Mode, Size); ++ DbgPrint ++ ("Daemon_Added_Resource: DHandle=0x%p Type=%d CHandle=0x%p FHandle=0x%x Mode=0x%x Size=%d\n", ++ DHandle, Type, CHandle, *(u32 *) & FHandle[2], Mode, Size); + else +- DbgPrint("Daemon_Added_Resource: DHandle=0x%p Type=%d CHandle=0x%p\n", DHandle, Type, CHandle); ++ DbgPrint ++ ("Daemon_Added_Resource: DHandle=0x%p Type=%d CHandle=0x%p\n", ++ DHandle, Type, CHandle); + +- resource = kmalloc(sizeof(daemon_resource_t), GFP_KERNEL); ++ resource = kmalloc(sizeof(struct daemon_resource), GFP_KERNEL); + if (!resource) + return -ENOMEM; + + resource->type = Type; + resource->connection = CHandle; + if (FHandle) +- memcpy(resource->handle, FHandle, sizeof(resource->handle)); ++ memcpy(resource->handle, FHandle, ++ sizeof(resource->handle)); + else + memset(resource->handle, 0, sizeof(resource->handle)); + resource->mode = Mode; +@@ -1348,29 +1176,15 @@ int Daemon_Added_Resource(daemon_handle_ + write_lock(&DHandle->lock); + list_add(&resource->list, &DHandle->list); + write_unlock(&DHandle->lock); +- DbgPrint("Daemon_Added_Resource: Adding resource=0x%p\n", resource); +- ++ DbgPrint("Daemon_Added_Resource: Adding resource=0x%p\n", ++ resource); + return 0; + } + +-/*++======================================================================*/ +-int Daemon_Remove_Resource(daemon_handle_t * DHandle, int Type, HANDLE CHandle, ++static int daemon_remove_resource(struct daemon_handle * DHandle, int Type, void *CHandle, + unsigned long FHandle) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { +- daemon_resource_t *resource; ++ struct daemon_resource *resource; + struct list_head *l; + int retVal = -ENOMEM; + +@@ -1381,7 +1195,7 @@ int Daemon_Remove_Resource(daemon_handle + write_lock(&DHandle->lock); + + list_for_each(l, &DHandle->list) { +- resource = list_entry(l, daemon_resource_t, list); ++ resource = list_entry(l, struct daemon_resource, list); + + if ((Type == resource->type) && + (resource->connection == CHandle)) { +@@ -1400,76 +1214,59 @@ int Daemon_Remove_Resource(daemon_handle + return (retVal); + } + +-int Daemon_Library_open(struct inode *inode, struct file *file) ++int novfs_daemon_lib_open(struct inode *inode, struct file *file) + { +- daemon_handle_t *dh; ++ struct daemon_handle *dh; + + DbgPrint("Daemon_Library_open: inode=0x%p file=0x%p\n", inode, file); +- +- dh = kmalloc(sizeof(daemon_handle_t), GFP_KERNEL); ++ dh = kmalloc(sizeof(struct daemon_handle), GFP_KERNEL); + if (!dh) + return -ENOMEM; +- + file->private_data = dh; + INIT_LIST_HEAD(&dh->list); + rwlock_init(&dh->lock); +- dh->session = Scope_Get_SessionId(NULL); +- ++ dh->session = novfs_scope_get_sessionId(NULL); + return 0; + } + +-/*++======================================================================*/ +-int Daemon_Library_close(struct inode *inode, struct file *file) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_daemon_lib_close(struct inode *inode, struct file *file) + { +- daemon_handle_t *dh; +- daemon_resource_t *resource; ++ struct daemon_handle *dh; ++ struct daemon_resource *resource; + struct list_head *l; + +- char commanddata[sizeof(XPLAT_CALL_REQUEST) + sizeof(NwdCCloseConn)]; +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCCloseConn nwdClose; ++ char commanddata[sizeof(struct novfs_xplat_call_request) + sizeof(struct nwd_close_conn)]; ++ struct novfs_xplat_call_request *cmd; ++ struct xplat_call_reply *reply; ++ struct nwd_close_conn *nwdClose; + unsigned long cmdlen, replylen; + + DbgPrint("Daemon_Library_close: inode=0x%p file=0x%p\n", inode, file); + if (file->private_data) { +- dh = (daemon_handle_t *) file->private_data; ++ dh = (struct daemon_handle *) file->private_data; + + list_for_each(l, &dh->list) { +- resource = list_entry(l, daemon_resource_t, list); ++ resource = list_entry(l, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { +- Novfs_Close_Stream(resource->connection, ++ novfs_close_stream(resource->connection, + resource->handle, + dh->session); + } else if (DH_TYPE_CONNECTION == resource->type) { +- cmd = (PXPLAT_CALL_REQUEST) commanddata; ++ cmd = (struct novfs_xplat_call_request *) commanddata; + cmdlen = +- offsetof(XPLAT_CALL_REQUEST, +- data) + sizeof(NwdCCloseConn); ++ offsetof(struct novfs_xplat_call_request, ++ data) + sizeof(struct nwd_close_conn); + cmd->Command.CommandType = + VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = dh->session; + cmd->NwcCommand = NWC_CLOSE_CONN; + +- cmd->dataLen = sizeof(NwdCCloseConn); +- nwdClose = (PNwdCCloseConn) cmd->data; ++ cmd->dataLen = sizeof(struct nwd_close_conn); ++ nwdClose = (struct nwd_close_conn *) cmd->data; + nwdClose->ConnHandle = +- (HANDLE) resource->connection; ++ (void *) resource->connection; + + Queue_Daemon_Command((void *)cmd, cmdlen, NULL, + 0, (void **)&reply, +@@ -1488,10 +1285,11 @@ int Daemon_Library_close(struct inode *i + return (0); + } + +-ssize_t Daemon_Library_read(struct file *file, char __user *buf, size_t len, loff_t *off) ++ssize_t novfs_daemon_lib_read(struct file * file, char *buf, size_t len, ++ loff_t * off) + { +- daemon_handle_t *dh; +- daemon_resource_t *resource; ++ struct daemon_handle *dh; ++ struct daemon_resource *resource; + + size_t thisread, totalread = 0; + loff_t offset = *off; +@@ -1504,12 +1302,12 @@ ssize_t Daemon_Library_read(struct file + read_lock(&dh->lock); + if (&dh->list != dh->list.next) { + resource = +- list_entry(dh->list.next, daemon_resource_t, list); ++ list_entry(dh->list.next, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + while (len > 0 && (offset < resource->size)) { + thisread = len; +- if (Novfs_Read_Stream ++ if (novfs_read_stream + (resource->connection, + resource->handle, buf, &thisread, + &offset, 1, dh->session) +@@ -1530,10 +1328,11 @@ ssize_t Daemon_Library_read(struct file + return (totalread); + } + +-ssize_t Daemon_Library_write(struct file *file, const char __user *buf, size_t len, loff_t *off) ++ssize_t novfs_daemon_lib_write(struct file * file, const char *buf, size_t len, ++ loff_t * off) + { +- daemon_handle_t *dh; +- daemon_resource_t *resource; ++ struct daemon_handle *dh; ++ struct daemon_resource *resource; + + size_t thiswrite, totalwrite = -EINVAL; + loff_t offset = *off; +@@ -1547,14 +1346,14 @@ ssize_t Daemon_Library_write(struct file + write_lock(&dh->lock); + if (&dh->list != dh->list.next) { + resource = +- list_entry(dh->list.next, daemon_resource_t, list); ++ list_entry(dh->list.next, struct daemon_resource, list); + + if ((DH_TYPE_STREAM == resource->type) && (len >= 0)) { + totalwrite = 0; + do { + thiswrite = len; + status = +- Novfs_Write_Stream(resource-> ++ novfs_write_stream(resource-> + connection, + resource->handle, + (void *)buf, +@@ -1590,24 +1389,10 @@ ssize_t Daemon_Library_write(struct file + return (totalwrite); + } + +-/*++======================================================================*/ +-loff_t Daemon_Library_llseek(struct file * file, loff_t offset, int origin) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++loff_t novfs_daemon_lib_llseek(struct file * file, loff_t offset, int origin) + { +- daemon_handle_t *dh; +- daemon_resource_t *resource; ++ struct daemon_handle *dh; ++ struct daemon_resource *resource; + + loff_t retVal = -EINVAL; + +@@ -1619,7 +1404,7 @@ loff_t Daemon_Library_llseek(struct file + read_lock(&dh->lock); + if (&dh->list != dh->list.next) { + resource = +- list_entry(dh->list.next, daemon_resource_t, list); ++ list_entry(dh->list.next, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + switch (origin) { +@@ -1646,11 +1431,11 @@ loff_t Daemon_Library_llseek(struct file + return retVal; + } + +-int Daemon_Library_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++int novfs_daemon_lib_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) + { + int retCode = -ENOSYS; +- daemon_handle_t *dh; +- HANDLE handle = NULL; ++ struct daemon_handle *dh; ++ void *handle = NULL; + unsigned long cpylen; + + dh = file->private_data; +@@ -1662,11 +1447,11 @@ int Daemon_Library_ioctl(struct inode *i + + switch (cmd) { + case IOC_LOGIN: +- retCode = daemon_login((struct login *)arg, &dh->session); ++ retCode = daemon_login((struct novfs_login *)arg, &dh->session); + break; + + case IOC_LOGOUT: +- retCode = daemon_logout((struct logout *)arg, &dh->session); ++ retCode = daemon_logout((struct novfs_logout *)arg, &dh->session); + break; + + case IOC_DEBUGPRINT: +@@ -1681,10 +1466,14 @@ int Daemon_Library_ioctl(struct inode *i + copy_from_user(&io, (void *)arg, + sizeof(io)); + if (io.length) { +- buf = kmalloc(io.length + 1, GFP_KERNEL); ++ buf = ++ kmalloc(io.length + 1, ++ GFP_KERNEL); + if (buf) { + buf[0] = 0; +- cpylen = copy_from_user(buf, io.data, io.length); ++ cpylen = ++ copy_from_user(buf, io.data, ++ io.length); + buf[io.length] = '\0'; + DbgPrint("%s", buf); + kfree(buf); +@@ -1696,7 +1485,7 @@ int Daemon_Library_ioctl(struct inode *i + + case IOC_XPLAT: + { +- XPLAT data; ++ struct novfs_xplat data; + + cpylen = + copy_from_user(&data, (void *)arg, +@@ -1707,61 +1496,79 @@ int Daemon_Library_ioctl(struct inode *i + + switch (data.xfunction) { + case NWC_OPEN_CONN_BY_NAME: +- DbgPrint("[VFS XPLAT] Call NwOpenConnByName\n"); +- retCode = NwOpenConnByName(&data, &handle, dh->session); ++ DbgPrint ++ ("[VFS XPLAT] Call NwOpenConnByName\n"); ++ retCode = ++ novfs_open_conn_by_name(&data, ++ &handle, dh->session); + if (!retCode) +- Daemon_Added_Resource(dh, DH_TYPE_CONNECTION, handle, NULL, 0, 0); ++ daemon_added_resource(dh, ++ DH_TYPE_CONNECTION,handle, 0, 0, 0); + break; + + case NWC_OPEN_CONN_BY_ADDRESS: +- DbgPrint("[VFS XPLAT] Call NwOpenConnByAddress\n"); +- retCode = NwOpenConnByAddr(&data, &handle, dh->session); ++ DbgPrint ++ ("[VFS XPLAT] Call NwOpenConnByAddress\n"); ++ retCode = ++ novfs_open_conn_by_addr(&data, &handle, ++ dh->session); + if (!retCode) +- Daemon_Added_Resource(dh, DH_TYPE_CONNECTION, handle, NULL, 0, 0); ++ daemon_added_resource(dh, ++ DH_TYPE_CONNECTION, ++ handle, 0, ++ 0, 0); + break; + + case NWC_OPEN_CONN_BY_REFERENCE: +- DbgPrint("[VFS XPLAT] Call NwOpenConnByReference\n"); +- retCode = NwOpenConnByRef(&data, &handle, dh->session); ++ ++ DbgPrint ++ ("[VFS XPLAT] Call NwOpenConnByReference\n"); ++ retCode = ++ novfs_open_conn_by_ref(&data, &handle, ++ dh->session); + if (!retCode) +- Daemon_Added_Resource(dh, ++ daemon_added_resource(dh, + DH_TYPE_CONNECTION, +- handle, NULL, ++ handle, 0, + 0, 0); + break; + + case NWC_SYS_CLOSE_CONN: + DbgPrint("[VFS XPLAT] Call NwSysCloseConn\n"); +- retCode = NwSysConnClose(&data, (unsigned long *)&handle, dh->session); +- Daemon_Remove_Resource(dh, DH_TYPE_CONNECTION, handle, 0); ++ retCode = ++ novfs_sys_conn_close(&data, (unsigned long *)&handle, dh->session); ++ daemon_remove_resource(dh, DH_TYPE_CONNECTION, handle, 0); + break; + + case NWC_CLOSE_CONN: + DbgPrint + ("[VFS XPLAT] Call NwCloseConn\n"); + retCode = +- NwConnClose(&data, &handle, ++ novfs_conn_close(&data, &handle, + dh->session); +- Daemon_Remove_Resource(dh, ++ daemon_remove_resource(dh, + DH_TYPE_CONNECTION, + handle, 0); + break; + + case NWC_LOGIN_IDENTITY: +- DbgPrint("[VFS XPLAT] Call NwLoginIdentity\n"); +- retCode = NwLoginIdentity(&data, &dh->session); ++ DbgPrint ++ ("[VFS XPLAT] Call NwLoginIdentity\n"); ++ retCode = ++ novfs_login_id(&data, dh->session); + break; + + case NWC_RAW_NCP_REQUEST: +- DbgPrint("[VFS XPLAT] Send Raw NCP Request\n"); +- retCode = NwRawSend(&data, dh->session); ++ DbgPrint ++ ("[VFS XPLAT] Send Raw NCP Request\n"); ++ retCode = novfs_raw_send(&data, dh->session); + break; + + case NWC_AUTHENTICATE_CONN_WITH_ID: + DbgPrint + ("[VFS XPLAT] Authenticate Conn With ID\n"); + retCode = +- NwAuthConnWithId(&data, ++ novfs_auth_conn(&data, + dh->session); + break; + +@@ -1769,21 +1576,21 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] UnAuthenticate Conn With ID\n"); + retCode = +- NwUnAuthenticate(&data, ++ novfs_unauthenticate(&data, + dh->session); + break; + + case NWC_LICENSE_CONN: + DbgPrint("Call NwLicenseConn\n"); + retCode = +- NwLicenseConn(&data, dh->session); ++ novfs_license_conn(&data, dh->session); + break; + + case NWC_LOGOUT_IDENTITY: + DbgPrint + ("[VFS XPLAT] Call NwLogoutIdentity\n"); + retCode = +- NwLogoutIdentity(&data, ++ novfs_logout_id(&data, + dh->session); + break; + +@@ -1791,35 +1598,35 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwUnlicense\n"); + retCode = +- NwUnlicenseConn(&data, dh->session); ++ novfs_unlicense_conn(&data, dh->session); + break; + + case NWC_GET_CONN_INFO: + DbgPrint + ("[VFS XPLAT] Call NwGetConnInfo\n"); + retCode = +- NwGetConnInfo(&data, dh->session); ++ novfs_get_conn_info(&data, dh->session); + break; + + case NWC_SET_CONN_INFO: + DbgPrint + ("[VFS XPLAT] Call NwGetConnInfo\n"); + retCode = +- NwSetConnInfo(&data, dh->session); ++ novfs_set_conn_info(&data, dh->session); + break; + + case NWC_SCAN_CONN_INFO: + DbgPrint + ("[VFS XPLAT] Call NwScanConnInfo\n"); + retCode = +- NwScanConnInfo(&data, dh->session); ++ novfs_scan_conn_info(&data, dh->session); + break; + + case NWC_GET_IDENTITY_INFO: + DbgPrint + ("[VFS XPLAT] Call NwGetIdentityInfo\n"); + retCode = +- NwGetIdentityInfo(&data, ++ novfs_get_id_info(&data, + dh->session); + break; + +@@ -1827,7 +1634,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwGetDaemonVersion\n"); + retCode = +- NwGetDaemonVersion(&data, ++ novfs_get_daemon_ver(&data, + dh->session); + break; + +@@ -1835,7 +1642,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcGetPreferredDsTree\n"); + retCode = +- NwcGetPreferredDSTree(&data, ++ novfs_get_preferred_DS_tree(&data, + dh->session); + break; + +@@ -1843,7 +1650,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcSetPreferredDsTree\n"); + retCode = +- NwcSetPreferredDSTree(&data, ++ novfs_set_preferred_DS_tree(&data, + dh->session); + break; + +@@ -1851,7 +1658,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcGetDefaultNameContext\n"); + retCode = +- NwcGetDefaultNameCtx(&data, ++ novfs_get_default_ctx(&data, + dh->session); + break; + +@@ -1859,7 +1666,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcSetDefaultNameContext\n"); + retCode = +- NwcSetDefaultNameCtx(&data, ++ novfs_set_default_ctx(&data, + dh->session); + break; + +@@ -1867,14 +1674,14 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwQueryFeature\n"); + retCode = +- NwQueryFeature(&data, dh->session); ++ novfs_query_feature(&data, dh->session); + break; + + case NWC_GET_TREE_MONITORED_CONN_REF: + DbgPrint + ("[VFS XPLAT] Call NwcGetTreeMonitoredConn\n"); + retCode = +- NwcGetTreeMonitoredConn(&data, ++ novfs_get_tree_monitored_conn(&data, + dh-> + session); + break; +@@ -1883,7 +1690,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcEnumerateIdentities\n"); + retCode = +- NwcEnumIdentities(&data, ++ novfs_enum_ids(&data, + dh->session); + break; + +@@ -1891,7 +1698,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcChangeAuthKey\n"); + retCode = +- NwcChangeAuthKey(&data, ++ novfs_change_auth_key(&data, + dh->session); + break; + +@@ -1913,7 +1720,7 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcSetPrimaryConn\n"); + retCode = +- NwcSetPrimaryConn(&data, ++ novfs_set_pri_conn(&data, + dh->session); + break; + +@@ -1921,26 +1728,29 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VFS XPLAT] Call NwcGetPrimaryConn\n"); + retCode = +- NwcGetPrimaryConn(&data, ++ novfs_get_pri_conn(&data, + dh->session); + break; + + case NWC_MAP_DRIVE: +- DbgPrint("[VFS XPLAT] Call NwcMapDrive\n"); +- retCode = NwdSetMapDrive(&data, dh->session); ++ DbgPrint ++ ("[VFS XPLAT] Call NwcMapDrive\n"); ++ retCode = ++ set_map_drive(&data, dh->session); + break; + + case NWC_UNMAP_DRIVE: + DbgPrint + ("[VFS XPLAT] Call NwcUnMapDrive\n"); +- retCode = NwdUnMapDrive(&data, dh->session); ++ retCode = ++ unmap_drive(&data, dh->session); + break; + + case NWC_ENUMERATE_DRIVES: + DbgPrint + ("[VFS XPLAT] Call NwcEnumerateDrives\n"); + retCode = +- NwcEnumerateDrives(&data, ++ novfs_enum_drives(&data, + dh->session); + break; + +@@ -1954,21 +1764,21 @@ int Daemon_Library_ioctl(struct inode *i + DbgPrint + ("[VSF XPLAT Call NwdGetBroadcastMessage\n"); + retCode = +- NwcGetBroadcastMessage(&data, ++ novfs_get_bcast_msg(&data, + dh->session); + break; + + case NWC_SET_KEY: + DbgPrint("[VSF XPLAT Call NwdSetKey\n"); + retCode = +- NwdSetKeyValue(&data, dh->session); ++ novfs_set_key_value(&data, dh->session); + break; + + case NWC_VERIFY_KEY: + DbgPrint + ("[VSF XPLAT Call NwdVerifyKey\n"); + retCode = +- NwdVerifyKeyValue(&data, ++ novfs_verify_key_value(&data, + dh->session); + break; + +@@ -1991,9 +1801,10 @@ int Daemon_Library_ioctl(struct inode *i + return (retCode); + } + +-unsigned int Daemon_Poll(struct file *file, struct poll_table_struct *poll_table) ++unsigned int novfs_daemon_poll(struct file *file, ++ struct poll_table_struct *poll_table) + { +- daemon_command_t *que; ++ struct daemon_cmd *que; + unsigned int mask = POLLOUT | POLLWRNORM; + + que = get_next_queue(0); +@@ -2002,43 +1813,32 @@ unsigned int Daemon_Poll(struct file *fi + return mask; + } + +-int NwdConvertNetwareHandle(PXPLAT pdata, daemon_handle_t *DHandle) ++static int NwdConvertNetwareHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle) + { + int retVal; +- NwcConvertNetWareHandle nh; ++ struct nwc_convert_netware_handle nh; + unsigned long cpylen; + + DbgPrint("NwdConvertNetwareHandle: DHandle=0x%p\n", DHandle); + +- cpylen = copy_from_user(&nh, pdata->reqData, sizeof(NwcConvertNetWareHandle)); ++ cpylen = ++ copy_from_user(&nh, pdata->reqData, ++ sizeof(struct nwc_convert_netware_handle)); ++ ++ retVal = ++ daemon_added_resource(DHandle, DH_TYPE_STREAM, ++ Uint32toHandle(nh.ConnHandle), ++ nh.NetWareHandle, nh.uAccessMode, ++ nh.uFileSize); + +- retVal = Daemon_Added_Resource(DHandle, DH_TYPE_STREAM, +- Uint32toHandle(nh.ConnHandle), +- nh.NetWareHandle, nh.uAccessMode, +- nh.uFileSize); +- +- return retVal; ++ return (retVal); + } + +-/*++======================================================================*/ +-int NwdConvertLocalHandle(PXPLAT pdata, daemon_handle_t * DHandle) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static int NwdConvertLocalHandle(struct novfs_xplat *pdata, struct daemon_handle * DHandle) + { + int retVal = NWE_REQUESTER_FAILURE; +- daemon_resource_t *resource; +- NwcConvertLocalHandle lh; ++ struct daemon_resource *resource; ++ struct nwc_convert_local_handle lh; + struct list_head *l; + unsigned long cpylen; + +@@ -2047,7 +1847,7 @@ int NwdConvertLocalHandle(PXPLAT pdata, + read_lock(&DHandle->lock); + + list_for_each(l, &DHandle->list) { +- resource = list_entry(l, daemon_resource_t, list); ++ resource = list_entry(l, struct daemon_resource, list); + + if (DH_TYPE_STREAM == resource->type) { + lh.uConnReference = +@@ -2055,10 +1855,10 @@ int NwdConvertLocalHandle(PXPLAT pdata, + + //sgled memcpy(lh.NwWareHandle, resource->handle, sizeof(resource->handle)); + memcpy(lh.NetWareHandle, resource->handle, sizeof(resource->handle)); //sgled +- if (pdata->repLen >= sizeof(NwcConvertLocalHandle)) { ++ if (pdata->repLen >= sizeof(struct nwc_convert_local_handle)) { + cpylen = + copy_to_user(pdata->repData, &lh, +- sizeof(NwcConvertLocalHandle)); ++ sizeof(struct nwc_convert_local_handle)); + retVal = 0; + } else { + retVal = NWE_BUFFER_OVERFLOW; +@@ -2072,39 +1872,25 @@ int NwdConvertLocalHandle(PXPLAT pdata, + return (retVal); + } + +-/*++======================================================================*/ +-int NwdGetMountPath(PXPLAT pdata) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static int NwdGetMountPath(struct novfs_xplat *pdata) + { + int retVal = NWE_REQUESTER_FAILURE; + int len; + unsigned long cpylen; +- NwcGetMountPath mp; ++ struct nwc_get_mount_path mp; + + cpylen = copy_from_user(&mp, pdata->reqData, pdata->reqLen); + +- if (Novfs_CurrentMount) { ++ if (novfs_current_mnt) { + +- len = strlen(Novfs_CurrentMount) + 1; ++ len = strlen(novfs_current_mnt) + 1; + if ((len > mp.MountPathLen) && mp.pMountPath) { + retVal = NWE_BUFFER_OVERFLOW; + } else { + if (mp.pMountPath) { + cpylen = + copy_to_user(mp.pMountPath, +- Novfs_CurrentMount, len); ++ novfs_current_mnt, len); + } + retVal = 0; + } +@@ -2119,52 +1905,55 @@ int NwdGetMountPath(PXPLAT pdata) + return (retVal); + } + +-static int NwdSetMapDrive(PXPLAT pdata, session_t Session) ++static int set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) + { + int retVal; +- NwcMapDriveEx symInfo; ++ unsigned long cpylen; ++ struct nwc_map_drive_ex symInfo; + char *path; +- drive_map_t *drivemap, *dm; ++ struct drive_map *drivemap, *dm; + struct list_head *list; + +- retVal = NwcSetMapDrive(pdata, Session); ++ retVal = novfs_set_map_drive(pdata, Session); + if (retVal) + return retVal; +- + if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) + return -EFAULT; +- +- drivemap = kmalloc(sizeof(drive_map_t) + symInfo.linkOffsetLength, GFP_KERNEL); ++ drivemap = ++ kmalloc(sizeof(struct drive_map) + symInfo.linkOffsetLength, ++ GFP_KERNEL); + if (!drivemap) + return -ENOMEM; + + path = (char *)pdata->reqData; + path += symInfo.linkOffset; +- if (copy_from_user(drivemap->name, path, symInfo.linkOffsetLength)) { +- kfree(drivemap); +- return -EFAULT; +- } ++ cpylen = ++ copy_from_user(drivemap->name, path, ++ symInfo.linkOffsetLength); + + drivemap->session = Session; +- drivemap->hash = full_name_hash(drivemap->name, symInfo.linkOffsetLength - 1); ++ drivemap->hash = ++ full_name_hash(drivemap->name, ++ symInfo.linkOffsetLength - 1); + drivemap->namelen = symInfo.linkOffsetLength - 1; +- DbgPrint("NwdSetMapDrive: hash=0x%x path=%s\n", drivemap->hash, drivemap->name); ++ DbgPrint("NwdSetMapDrive: hash=0x%x path=%s\n", ++ drivemap->hash, drivemap->name); + +- dm = (drive_map_t *) & DriveMapList.next; ++ dm = (struct drive_map *) & DriveMapList.next; + + down(&DriveMapLock); + + list_for_each(list, &DriveMapList) { +- dm = list_entry(list, drive_map_t, list); ++ dm = list_entry(list, struct drive_map, list); + DbgPrint("NwdSetMapDrive: dm=0x%p\n" +- " hash: 0x%x\n" +- " namelen: %d\n" +- " name: %s\n", +- dm, dm->hash, dm->namelen, dm->name); ++ " hash: 0x%x\n" ++ " namelen: %d\n" ++ " name: %s\n", ++ dm, dm->hash, dm->namelen, dm->name); + + if (drivemap->hash == dm->hash) { + if (0 == +- strcmp(dm->name, drivemap->name)) { ++ strcmp(dm->name, drivemap->name)) { + dm = NULL; + break; + } +@@ -2174,59 +1963,57 @@ static int NwdSetMapDrive(PXPLAT pdata, + } + + if (dm) { +- if ((dm == (drive_map_t *) & DriveMapList) || +- (dm->hash < drivemap->hash)) { ++ if ((dm == (struct drive_map *) & DriveMapList) || ++ (dm->hash < drivemap->hash)) { + list_add(&drivemap->list, &dm->list); + } else { + list_add_tail(&drivemap->list, +- &dm->list); ++ &dm->list); + } +- } else { +- kfree(drivemap); + } ++ kfree(drivemap); + up(&DriveMapLock); +- + return (retVal); + } + +-static int NwdUnMapDrive(PXPLAT pdata, session_t Session) ++static int unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) + { + int retVal = NWE_REQUESTER_FAILURE; +- NwcUnmapDriveEx symInfo; ++ struct nwc_unmap_drive_ex symInfo; + char *path; +- drive_map_t *dm; ++ struct drive_map *dm; + struct list_head *list; + unsigned long hash; + +- retVal = NwcUnMapDrive(pdata, Session); ++ ++ retVal = novfs_unmap_drive(pdata, Session); + if (retVal) + return retVal; +- + if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) + return -EFAULT; + + path = kmalloc(symInfo.linkLen, GFP_KERNEL); + if (!path) + return -ENOMEM; +- +- if (copy_from_user(path, ((NwcUnmapDriveEx *)pdata->reqData)->linkData, symInfo.linkLen)) { ++ if (copy_from_user(path,((struct nwc_unmap_drive_ex *) pdata->reqData)->linkData, symInfo.linkLen)) { + kfree(path); + return -EFAULT; + } + + hash = full_name_hash(path, symInfo.linkLen - 1); +- DbgPrint("NwdUnMapDrive: hash=0x%x path=%s\n", hash, path); ++ DbgPrint("NwdUnMapDrive: hash=0x%x path=%s\n", hash, ++ path); + + dm = NULL; + + down(&DriveMapLock); + + list_for_each(list, &DriveMapList) { +- dm = list_entry(list, drive_map_t, list); ++ dm = list_entry(list, struct drive_map, list); + DbgPrint("NwdUnMapDrive: dm=0x%p %s\n" +- " hash: 0x%x\n" +- " namelen: %d\n", +- dm, dm->name, dm->hash, dm->namelen); ++ " hash: 0x%x\n" ++ " namelen: %d\n", ++ dm, dm->name, dm->hash, dm->namelen); + + if (hash == dm->hash) { + if (0 == strcmp(dm->name, path)) { +@@ -2240,40 +2027,25 @@ static int NwdUnMapDrive(PXPLAT pdata, s + + if (dm) { + DbgPrint("NwdUnMapDrive: Remove dm=0x%p %s\n" +- " hash: 0x%x\n" +- " namelen: %d\n", +- dm, dm->name, dm->hash, dm->namelen); ++ " hash: 0x%x\n" ++ " namelen: %d\n", ++ dm, dm->name, dm->hash, dm->namelen); + list_del(&dm->list); + kfree(dm); + } + + up(&DriveMapLock); +- +- return retVal; ++ return (retVal); + } + +-/*++======================================================================*/ +-void RemoveDriveMaps(void) +-/* +- * +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static void RemoveDriveMaps(void) + { +- drive_map_t *dm; ++ struct drive_map *dm; + struct list_head *list; + + down(&DriveMapLock); + list_for_each(list, &DriveMapList) { +- dm = list_entry(list, drive_map_t, list); ++ dm = list_entry(list, struct drive_map, list); + + DbgPrint("RemoveDriveMap: dm=0x%p\n" + " hash: 0x%x\n" +@@ -2288,9 +2060,7 @@ void RemoveDriveMaps(void) + up(&DriveMapLock); + } + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +-/*++======================================================================*/ +-int local_unlink(const char *pathname) ++static int local_unlink(const char *pathname) + { + int error; + struct dentry *dentry; +@@ -2341,60 +2111,3 @@ int local_unlink(const char *pathname) + return error; + } + +-#else +-/*++======================================================================*/ +-int local_unlink(const char *pathname) +-{ +- int error; +- struct dentry *dentry; +- struct nameidata nd; +- struct inode *inode = NULL; +- +- DbgPrint("local_unlink: %s\n", pathname); +- error = path_lookup(pathname, LOOKUP_PARENT, &nd); +- DbgPrint("local_unlink: path_lookup %d\n", error); +- if (!error) { +- error = -EISDIR; +- if (nd.last_type == LAST_NORM) { +- down(&nd.dentry->d_inode->i_sem); +- dentry = +- lookup_one_len(&nd.last, nd.dentry, +- sizeof(nd.last)); +- DbgPrint("local_unlink: lookup_hash 0x%p\n", dentry); +- +- error = PTR_ERR(dentry); +- if (!IS_ERR(dentry)) { +- if (nd.last.name[nd.last.len]) { +- error = +- !dentry-> +- d_inode ? -ENOENT : S_ISDIR(dentry-> +- d_inode-> +- i_mode) +- ? -EISDIR : -ENOTDIR; +- } else { +- inode = dentry->d_inode; +- if (inode) { +- atomic_inc(&inode->i_count); +- } +- error = +- vfs_unlink(nd.dentry->d_inode, +- dentry); +- DbgPrint +- ("local_unlink: vfs_unlink %d\n", +- error); +- } +- dput(dentry); +- } +- up(&nd.dentry->d_inode->i_sem); +- } +- path_release(&nd); +- } +- +- if (inode) { +- iput(inode); /* truncate the inode here */ +- } +- +- DbgPrint("local_unlink: error=%d\n", error); +- return error; +-} +-#endif +--- a/fs/novfs/file.c ++++ b/fs/novfs/file.c +@@ -27,35 +27,11 @@ + #include "commands.h" + #include "nwerror.h" + +-/*===[ Function prototypes ]==============================================*/ +-int Novfs_get_alltrees(struct dentry *parent); +-ssize_t Novfs_tree_read(struct file *file, char *buf, size_t len, loff_t * off); +- +-int Novfs_Find_Name_In_List(struct qstr *Name, unsigned char * List); +- +-int Novfs_Create(unsigned char * Path, int DirectoryFlag, session_t SessionId); +-int Novfs_Close_File(HANDLE Handle, session_t SessionId); +-int Novfs_Read_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, +- loff_t * Offset, session_t SessionId); +-int Novfs_Write_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, +- loff_t * Offset, session_t SessionId); +-int Novfs_Write_Page(HANDLE Handle, struct page *Page, session_t SessionId); +-int Novfs_Read_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, +- size_t * Bytes, loff_t * Offset, int User, +- session_t SessionId); +-int Novfs_Write_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, +- size_t * Bytes, loff_t * Offset, session_t SessionId); +-int Novfs_Close_Stream(HANDLE ConnHandle, unsigned char * Handle, session_t SessionId); +-int Novfs_Delete(unsigned char * Path, int DirectoryFlag, session_t SessionId); +-int Novfs_Truncate_File(unsigned char * Path, int PathLen, session_t SessionId); +-int Novfs_Truncate_File_Ex(HANDLE Handle, loff_t Offset, session_t SessionId); +-int Novfs_Rename_File(int DirectoryFlag, unsigned char * OldName, int OldLen, +- unsigned char * NewName, int NewLen, session_t SessionId); +-int Novfs_Set_Attr(unsigned char * Path, struct iattr *Attr, session_t SessionId); +-int Novfs_Get_File_Cache_Flag(unsigned char * Path, session_t SessionId); ++static ssize_t novfs_tree_read(struct file * file, char *buf, size_t len, loff_t * off); ++extern struct dentry_operations novfs_dentry_operations; + +-static struct file_operations Novfs_tree_operations = { +- read:Novfs_tree_read, ++static struct file_operations novfs_tree_operations = { ++ read:novfs_tree_read, + }; + + /* +@@ -65,12 +41,12 @@ static struct file_operations Novfs_tree + */ + static int StripTrailingDots = 1; + +-int Novfs_get_alltrees(struct dentry *parent) ++int novfs_get_alltrees(struct dentry *parent) + { + unsigned char *p; +- PCOMMAND_REPLY_HEADER reply = NULL; ++ struct novfs_command_reply_header * reply = NULL; + unsigned long replylen = 0; +- COMMAND_REQUEST_HEADER cmd; ++ struct novfs_command_request_header cmd; + int retCode; + struct dentry *entry; + struct qstr name; +@@ -81,30 +57,30 @@ int Novfs_get_alltrees(struct dentry *pa + //sg ??? cmd.SessionId = 0x1234; + SC_INITIALIZE(cmd.SessionId); + +- DbgPrint("Novfs_get_alltrees:\n"); ++ DbgPrint("novfs_get_alltrees:\n"); + + retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); +- DbgPrint("Novfs_get_alltrees: relpy=0x%p replylen=%d\n", reply, ++ DbgPrint("novfs_get_alltrees: relpy=0x%p replylen=%d\n", reply, + replylen); + if (reply) { +- mydump(replylen, reply); ++ novfs_dump(replylen, reply); + if (!reply->ErrorCode +- && (replylen > sizeof(COMMAND_REPLY_HEADER))) { ++ && (replylen > sizeof(struct novfs_command_reply_header))) { + p = (char *)reply + 8; + while (*p) { +- DbgPrint("Novfs_get_alltrees: %s\n", p); ++ DbgPrint("novfs_get_alltrees: %s\n", p); + name.len = strlen(p); + name.name = p; + name.hash = full_name_hash(name.name, name.len); + entry = d_lookup(parent, &name); + if (NULL == entry) { +- DbgPrint("Novfs_get_alltrees: adding %s\n", p); ++ DbgPrint("novfs_get_alltrees: adding %s\n", p); + entry = d_alloc(parent, &name); + if (entry) { +- entry->d_op = &Novfs_dentry_operations; +- inode = Novfs_get_inode(parent->d_sb, S_IFREG | 0400, 0, 0, 0, &name); ++ entry->d_op = &novfs_dentry_operations; ++ inode = novfs_get_inode(parent->d_sb, S_IFREG | 0400, 0, 0, 0, &name); + if (inode) { +- inode->i_fop = &Novfs_tree_operations; ++ inode->i_fop = &novfs_tree_operations; + d_add(entry, inode); + } + } +@@ -117,7 +93,7 @@ int Novfs_get_alltrees(struct dentry *pa + return (retCode); + } + +-ssize_t Novfs_tree_read(struct file * file, char *buf, size_t len, loff_t * off) ++static ssize_t novfs_tree_read(struct file * file, char *buf, size_t len, loff_t * off) + { + if (file->f_pos != 0) { + return (0); +@@ -128,24 +104,24 @@ ssize_t Novfs_tree_read(struct file * fi + return (5); + } + +-int Novfs_Get_Connected_Server_List(unsigned char ** ServerList, struct schandle *SessionId) ++int novfs_get_servers(unsigned char ** ServerList, struct novfs_schandle SessionId) + { +- GET_CONNECTED_SERVER_LIST_REQUEST req; +- PGET_CONNECTED_SERVER_LIST_REPLY reply = NULL; ++ struct novfs_get_connected_server_list req; ++ struct novfs_get_connected_server_list_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + + *ServerList = NULL; + + req.Command.CommandType = VFS_COMMAND_GET_CONNECTED_SERVER_LIST; +- memcpy(&req.Command.SessionId, SessionId, sizeof(*SessionId)); ++ req.Command.SessionId = SessionId; + + retCode = + Queue_Daemon_Command(&req, sizeof(req), NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + if (reply) { +- DbgPrint("Novfs_Get_Connected_Server_List: reply\n"); +- replylen -= sizeof(COMMAND_REPLY_HEADER); ++ DbgPrint("novfs_Get_Connected_Server_List: reply\n"); ++ replylen -= sizeof(struct novfs_command_reply_header); + if (!reply->Reply.ErrorCode && replylen) { + memcpy(reply, reply->List, replylen); + *ServerList = (unsigned char *) reply; +@@ -158,30 +134,31 @@ int Novfs_Get_Connected_Server_List(unsi + return (retCode); + } + +-int Novfs_Get_Server_Volume_List(struct qstr *Server, unsigned char ** VolumeList, +- struct schandle *SessionId) ++int novfs_get_vols(struct qstr *Server, unsigned char ** VolumeList, ++ struct novfs_schandle SessionId) + { +- PGET_SERVER_VOLUME_LIST_REQUEST req; +- PGET_SERVER_VOLUME_LIST_REPLY reply = NULL; ++ struct novfs_get_server_volume_list *req; ++ struct novfs_get_server_volume_list_reply *reply = NULL; + unsigned long replylen = 0, reqlen; + int retCode; + + *VolumeList = NULL; +- reqlen = sizeof(GET_SERVER_VOLUME_LIST_REQUEST) + Server->len; ++ reqlen = sizeof(struct novfs_get_server_volume_list) + Server->len; + req = kmalloc(reqlen, GFP_KERNEL); + if (!req) + return -ENOMEM; + req->Command.CommandType = VFS_COMMAND_GET_SERVER_VOLUME_LIST; + req->Length = Server->len; + memcpy(req->Name, Server->name, Server->len); +- memcpy(&req->Command.SessionId, SessionId, sizeof(*SessionId)); ++ req->Command.SessionId = SessionId; + +- retCode = Queue_Daemon_Command(req, reqlen, NULL, 0, (void *)&reply, +- &replylen, INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command(req, reqlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); + if (reply) { +- DbgPrint("Novfs_Get_Server_Volume_List: reply\n"); +- mydump(replylen, reply); +- replylen -= sizeof(COMMAND_REPLY_HEADER); ++ DbgPrint("novfs_Get_Server_Volume_List: reply\n"); ++ novfs_dump(replylen, reply); ++ replylen -= sizeof(struct novfs_command_reply_header); + + if (!reply->Reply.ErrorCode && replylen) { + memcpy(reply, reply->List, replylen); +@@ -193,35 +170,19 @@ int Novfs_Get_Server_Volume_List(struct + } + } + kfree(req); +- return retCode; +-} +- +-int Novfs_Find_Name_In_List(struct qstr *Name, unsigned char * List) +-{ +- int len; +- int retCode = 0; +- +- while (*List) { +- len = strlen(List); +- if ((len == Name->len) && !strncmp(Name->name, List, len)) { +- retCode = 1; +- break; +- } +- List += (len + 1); +- } + return (retCode); + } + +-int Novfs_Get_File_Info(unsigned char * Path, struct entry_info *Info, struct schandle *SessionId) ++int novfs_get_file_info(unsigned char * Path, struct novfs_entry_info * Info, struct novfs_schandle SessionId) + { +- PVERIFY_FILE_REPLY reply = NULL; ++ struct novfs_verify_file_reply *reply = NULL; + unsigned long replylen = 0; +- PVERIFY_FILE_REQUEST cmd; ++ struct novfs_verify_file_request * cmd; + int cmdlen; + int retCode = -ENOENT; + int pathlen; + +- DbgPrint("%s: Path = %s\n", __func__, Path); ++ DbgPrint("novfs_Get_File_Info: Path = %s\n", Path); + + Info->mode = S_IFDIR | 0700; + Info->uid = current->uid; +@@ -235,12 +196,12 @@ int Novfs_Get_File_Info(unsigned char * + if ('.' == Path[pathlen - 1]) + pathlen--; + } +- cmdlen = offsetof(VERIFY_FILE_REQUEST, path) + pathlen; +- cmd = (PVERIFY_FILE_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_verify_file_request,path) + pathlen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_VERIFY_FILE; + cmd->Command.SequenceNumber = 0; +- memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->Command.SessionId = SessionId; + cmd->pathLen = pathlen; + memcpy(cmd->path, Path, cmd->pathLen); + +@@ -279,11 +240,18 @@ int Novfs_Get_File_Info(unsigned char * + Info->mtime.tv_nsec = 0; + Info->ctime.tv_sec = reply->createTime; + Info->ctime.tv_nsec = 0; +- DbgPrint("%s: replylen=%d sizeof(VERIFY_FILE_REPLY)=%d\n", __func__, replylen, sizeof(VERIFY_FILE_REPLY)); +- if (replylen > sizeof(VERIFY_FILE_REPLY)) { +- unsigned int *lp = &reply->fileMode; ++ DbgPrint ++ ("novfs_Get_File_Info: replylen=%d sizeof(VERIFY_FILE_REPLY)=%d\n", ++ replylen, ++ sizeof(struct novfs_verify_file_reply)); ++ if (replylen > ++ sizeof(struct novfs_verify_file_reply)) { ++ unsigned int *lp = ++ &reply->fileMode; + lp++; +- DbgPrint("%s: extra data 0x%x\n", __func__, *lp); ++ DbgPrint ++ ("novfs_Get_File_Info: extra data 0x%x\n", ++ *lp); + Info->mtime.tv_nsec = *lp; + } + retCode = 0; +@@ -295,35 +263,37 @@ int Novfs_Get_File_Info(unsigned char * + } + } + +- DbgPrint("%s: return 0x%x\n", __func__, retCode); ++ DbgPrint("novfs_Get_File_Info: return 0x%x\n", retCode); + return (retCode); + } + +-int Novfs_GetX_File_Info(char *Path, const char *Name, char *buffer, ++int novfs_getx_file_info(char *Path, const char *Name, char *buffer, + ssize_t buffer_size, ssize_t * dataLen, +- session_t *SessionId) ++ struct novfs_schandle SessionId) + { +- PXA_GET_REPLY reply = NULL; ++ struct novfs_xa_get_reply *reply = NULL; + unsigned long replylen = 0; +- PXA_GET_REQUEST cmd; ++ struct novfs_xa_get_request *cmd; + int cmdlen; + int retCode = -ENOENT; + + int namelen = strlen(Name); + int pathlen = strlen(Path); + +- DbgPrint("%s: xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i\n", __func__, Path, pathlen, Name, namelen); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i\n", ++ Path, pathlen, Name, namelen); + + if (namelen > MAX_XATTR_NAME_LEN) { + return ENOATTR; + } + +- cmdlen = offsetof(XA_GET_REQUEST, data) + pathlen + 1 + namelen + 1; // two '\0' +- cmd = (PXA_GET_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_xa_get_request, data) + pathlen + 1 + namelen + 1; // two '\0' ++ cmd = (struct novfs_xa_get_request *) kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_GET_EXTENDED_ATTRIBUTE; + cmd->Command.SequenceNumber = 0; +- memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->Command.SessionId = SessionId; + + cmd->pathLen = pathlen; + memcpy(cmd->data, Path, cmd->pathLen + 1); //+ '\0' +@@ -331,14 +301,20 @@ int Novfs_GetX_File_Info(char *Path, con + cmd->nameLen = namelen; + memcpy(cmd->data + cmd->pathLen + 1, Name, cmd->nameLen + 1); + +- DbgPrint("%s xattr: PXA_GET_REQUEST BEGIN\n", __func__); +- DbgPrint("%s xattr: Queue_Daemon_Command %d\n", __func__, cmd->Command.CommandType); +- DbgPrint("%s xattr: Command.SessionId = %d\n", __func__, cmd->Command.SessionId); +- DbgPrint("%s xattr: pathLen = %d\n", __func__, cmd->pathLen); +- DbgPrint("%s xattr: Path = %s\n", __func__, cmd->data); +- DbgPrint("%s xattr: nameLen = %d\n", __func__, cmd->nameLen); +- DbgPrint("%s xattr: name = %s\n", __func__, (cmd->data + cmd->pathLen + 1)); +- DbgPrint("%s xattr: PXA_GET_REQUEST END\n", __func__); ++ DbgPrint("novfs_GetX_File_Info xattr: PXA_GET_REQUEST BEGIN\n"); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: Queue_Daemon_Command %d\n", ++ cmd->Command.CommandType); ++ DbgPrint("novfs_GetX_File_Info xattr: Command.SessionId = %d\n", ++ cmd->Command.SessionId); ++ DbgPrint("novfs_GetX_File_Info xattr: pathLen = %d\n", ++ cmd->pathLen); ++ DbgPrint("novfs_GetX_File_Info xattr: Path = %s\n", cmd->data); ++ DbgPrint("novfs_GetX_File_Info xattr: nameLen = %d\n", ++ cmd->nameLen); ++ DbgPrint("novfs_GetX_File_Info xattr: name = %s\n", ++ (cmd->data + cmd->pathLen + 1)); ++ DbgPrint("novfs_GetX_File_Info xattr: PXA_GET_REQUEST END\n"); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, +@@ -347,8 +323,13 @@ int Novfs_GetX_File_Info(char *Path, con + if (reply) { + + if (reply->Reply.ErrorCode) { +- DbgPrint("%s xattr: reply->Reply.ErrorCode=%d, %X\n", __func__, reply->Reply.ErrorCode, reply->Reply.ErrorCode); +- DbgPrint("%s xattr: replylen=%d\n", __func__, replylen); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: reply->Reply.ErrorCode=%d, %X\n", ++ reply->Reply.ErrorCode, ++ reply->Reply.ErrorCode); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: replylen=%d\n", ++ replylen); + + //0xC9 = EA not found (C9), 0xD1 = EA access denied + if ((reply->Reply.ErrorCode == 0xC9) +@@ -360,26 +341,32 @@ int Novfs_GetX_File_Info(char *Path, con + } else { + + *dataLen = +- replylen - sizeof(COMMAND_REPLY_HEADER); +- DbgPrint("%s xattr: replylen=%u, dataLen=%u\n", __func__, replylen, *dataLen); ++ replylen - sizeof(struct novfs_command_reply_header); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: replylen=%u, dataLen=%u\n", ++ replylen, *dataLen); + + if (buffer_size >= *dataLen) { +- DbgPrint("%s xattr: copying to buffer from &reply->pData\n", __func__); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: copying to buffer from &reply->pData\n"); + memcpy(buffer, &reply->pData, *dataLen); + + retCode = 0; + } else { +- DbgPrint("%s xattr: (!!!) buffer is smaller then reply\n", __func__); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: (!!!) buffer is smaller then reply\n"); + retCode = -ERANGE; + } +- DbgPrint("%s xattr: /dumping buffer\n", __func__); +- mydump(*dataLen, buffer); +- DbgPrint("%s xattr: \\after dumping buffer\n", __func__); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: /dumping buffer\n"); ++ novfs_dump(*dataLen, buffer); ++ DbgPrint ++ ("novfs_GetX_File_Info xattr: \\after dumping buffer\n"); + } + + kfree(reply); + } else { +- DbgPrint("%s xattr: reply = NULL\n", __func__); ++ DbgPrint("novfs_GetX_File_Info xattr: reply = NULL\n"); + } + kfree(cmd); + +@@ -388,32 +375,33 @@ int Novfs_GetX_File_Info(char *Path, con + return retCode; + } + +-int Novfs_SetX_File_Info(char *Path, const char *Name, const void *Value, ++int novfs_setx_file_info(char *Path, const char *Name, const void *Value, + unsigned long valueLen, unsigned long *bytesWritten, +- int flags, struct schandle *SessionId) ++ int flags, struct novfs_schandle SessionId) + { +- PXA_SET_REPLY reply = NULL; ++ struct novfs_xa_set_reply *reply = NULL; + unsigned long replylen = 0; +- PXA_SET_REQUEST cmd; ++ struct novfs_xa_set_request *cmd; + int cmdlen; + int retCode = -ENOENT; + + int namelen = strlen(Name); + int pathlen = strlen(Path); + +- DbgPrint("%s xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i, value len = %u\n", __func__, ++ DbgPrint ++ ("novfs_SetX_File_Info xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i, value len = %u\n", + Path, pathlen, Name, namelen, valueLen); + + if (namelen > MAX_XATTR_NAME_LEN) { + return ENOATTR; + } + +- cmdlen = offsetof(XA_SET_REQUEST, data) + pathlen + 1 + namelen + 1 + valueLen; +- cmd = (PXA_SET_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_xa_set_request, data) + pathlen + 1 + namelen + 1 + valueLen; ++ cmd = (struct novfs_xa_set_request *) kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_SET_EXTENDED_ATTRIBUTE; + cmd->Command.SequenceNumber = 0; +- memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->Command.SessionId = SessionId; + + cmd->flags = flags; + cmd->pathLen = pathlen; +@@ -426,16 +414,22 @@ int Novfs_SetX_File_Info(char *Path, con + memcpy(cmd->data + cmd->pathLen + 1 + cmd->nameLen + 1, Value, + valueLen); + +- DbgPrint("%s xattr: PXA_SET_REQUEST BEGIN\n", __func__); +- DbgPrint("%s xattr: Queue_Daemon_Command %d\n", __func__, cmd->Command.CommandType); +- DbgPrint("%s xattr: Command.SessionId = %d\n", __func__, cmd->Command.SessionId); +- DbgPrint("%s xattr: pathLen = %d\n", __func__, cmd->pathLen); +- DbgPrint("%s xattr: Path = %s\n", __func__, cmd->data); +- DbgPrint("%s xattr: nameLen = %d\n", __func__, cmd->nameLen); +- DbgPrint("%s xattr: name = %s\n", __func__, (cmd->data + cmd->pathLen + 1)); +- mydump(valueLen < 16 ? valueLen : 16, (char *)Value); ++ DbgPrint("novfs_SetX_File_Info xattr: PXA_SET_REQUEST BEGIN\n"); ++ DbgPrint ++ ("novfs_SetX_File_Info xattr: Queue_Daemon_Command %d\n", ++ cmd->Command.CommandType); ++ DbgPrint("novfs_SetX_File_Info xattr: Command.SessionId = %d\n", ++ cmd->Command.SessionId); ++ DbgPrint("novfs_SetX_File_Info xattr: pathLen = %d\n", ++ cmd->pathLen); ++ DbgPrint("novfs_SetX_File_Info xattr: Path = %s\n", cmd->data); ++ DbgPrint("novfs_SetX_File_Info xattr: nameLen = %d\n", ++ cmd->nameLen); ++ DbgPrint("novfs_SetX_File_Info xattr: name = %s\n", ++ (cmd->data + cmd->pathLen + 1)); ++ novfs_dump(valueLen < 16 ? valueLen : 16, (char *)Value); + +- DbgPrint("%s xattr: PXA_SET_REQUEST END\n", __func__); ++ DbgPrint("novfs_SetX_File_Info xattr: PXA_SET_REQUEST END\n"); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, +@@ -444,22 +438,30 @@ int Novfs_SetX_File_Info(char *Path, con + if (reply) { + + if (reply->Reply.ErrorCode) { +- DbgPrint("%s xattr: reply->Reply.ErrorCode=%d, %X\n", __func__, reply->Reply.ErrorCode, reply->Reply.ErrorCode); +- DbgPrint("%s xattr: replylen=%d\n", __func__, replylen); ++ DbgPrint ++ ("novfs_SetX_File_Info xattr: reply->Reply.ErrorCode=%d, %X\n", ++ reply->Reply.ErrorCode, ++ reply->Reply.ErrorCode); ++ DbgPrint ++ ("novfs_SetX_File_Info xattr: replylen=%d\n", ++ replylen); + + retCode = -reply->Reply.ErrorCode; //-ENOENT; + } else { + +- DbgPrint("%s xattr: replylen=%u, real len = %u\n", __func__, replylen, replylen - sizeof(COMMAND_REPLY_HEADER)); ++ DbgPrint ++ ("novfs_SetX_File_Info xattr: replylen=%u, real len = %u\n", ++ replylen, ++ replylen - sizeof(struct novfs_command_reply_header)); + memcpy(bytesWritten, &reply->pData, +- replylen - sizeof(COMMAND_REPLY_HEADER)); ++ replylen - sizeof(struct novfs_command_reply_header)); + + retCode = 0; + } + + kfree(reply); + } else { +- DbgPrint("%s xattr: reply = NULL\n", __func__); ++ DbgPrint("novfs_SetX_File_Info xattr: reply = NULL\n"); + } + kfree(cmd); + +@@ -468,32 +470,41 @@ int Novfs_SetX_File_Info(char *Path, con + return retCode; + } + +-int Novfs_ListX_File_Info(char *Path, char *buffer, ssize_t buffer_size, ssize_t * dataLen, struct schandle *SessionId) ++int novfs_listx_file_info(char *Path, char *buffer, ssize_t buffer_size, ++ ssize_t * dataLen, struct novfs_schandle SessionId) + { +- PXA_LIST_REPLY reply = NULL; ++ struct novfs_xa_list_reply *reply = NULL; + unsigned long replylen = 0; +- PVERIFY_FILE_REQUEST cmd; ++ struct novfs_verify_file_request *cmd; + int cmdlen; + int retCode = -ENOENT; + + int pathlen = strlen(Path); +- DbgPrint("%s xattr: Path = %s, pathlen = %i\n", __func__, Path, pathlen); ++ DbgPrint("novfs_ListX_File_Info xattr: Path = %s, pathlen = %i\n", Path, ++ pathlen); + + *dataLen = 0; +- cmdlen = offsetof(VERIFY_FILE_REQUEST, path) + pathlen; +- cmd = (PVERIFY_FILE_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_verify_file_request, path) + pathlen; ++ cmd = (struct novfs_verify_file_request *) kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_LIST_EXTENDED_ATTRIBUTES; + cmd->Command.SequenceNumber = 0; +- memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->Command.SessionId = SessionId; + cmd->pathLen = pathlen; + memcpy(cmd->path, Path, cmd->pathLen + 1); //+ '\0' +- DbgPrint("%s xattr: PVERIFY_FILE_REQUEST BEGIN\n", __func__); +- DbgPrint("%s xattr: Queue_Daemon_Command %d\n", __func__, cmd->Command.CommandType); +- DbgPrint("%s xattr: Command.SessionId = %d\n", __func__, cmd->Command.SessionId); +- DbgPrint("%s xattr: pathLen = %d\n", __func__, cmd->pathLen); +- DbgPrint("%s xattr: Path = %s\n", __func__, cmd->path); +- DbgPrint("%s xattr: PVERIFY_FILE_REQUEST END\n", __func__); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: PVERIFY_FILE_REQUEST BEGIN\n"); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: Queue_Daemon_Command %d\n", ++ cmd->Command.CommandType); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: Command.SessionId = %d\n", ++ cmd->Command.SessionId); ++ DbgPrint("novfs_ListX_File_Info xattr: pathLen = %d\n", ++ cmd->pathLen); ++ DbgPrint("novfs_ListX_File_Info xattr: Path = %s\n", cmd->path); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: PVERIFY_FILE_REQUEST END\n"); + + retCode = + Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, +@@ -502,31 +513,43 @@ int Novfs_ListX_File_Info(char *Path, ch + if (reply) { + + if (reply->Reply.ErrorCode) { +- DbgPrint("%s xattr: reply->Reply.ErrorCode=%d, %X\n", __func__, reply->Reply.ErrorCode, reply->Reply.ErrorCode); +- DbgPrint("%s xattr: replylen=%d\n", __func__, replylen); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: reply->Reply.ErrorCode=%d, %X\n", ++ reply->Reply.ErrorCode, ++ reply->Reply.ErrorCode); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: replylen=%d\n", ++ replylen); + + retCode = -ENOENT; + } else { +- *dataLen = replylen - sizeof(COMMAND_REPLY_HEADER); +- DbgPrint("%s xattr: replylen=%u, dataLen=%u\n", __func__, replylen, *dataLen); ++ *dataLen = ++ replylen - sizeof(struct novfs_command_reply_header); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: replylen=%u, dataLen=%u\n", ++ replylen, *dataLen); + + if (buffer_size >= *dataLen) { +- DbgPrint("%s xattr: copying to buffer from &reply->pData\n", __func__); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: copying to buffer from &reply->pData\n"); + memcpy(buffer, &reply->pData, *dataLen); + } else { +- DbgPrint("%s xattr: (!!!) buffer is smaller then reply\n", __func__); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: (!!!) buffer is smaller then reply\n"); + retCode = -ERANGE; + } +- DbgPrint("%s xattr: /dumping buffer\n", __func__); +- mydump(*dataLen, buffer); +- DbgPrint("%s xattr: \\after dumping buffer\n", __func__); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: /dumping buffer\n"); ++ novfs_dump(*dataLen, buffer); ++ DbgPrint ++ ("novfs_ListX_File_Info xattr: \\after dumping buffer\n"); + + retCode = 0; + } + + kfree(reply); + } else { +- DbgPrint("%s xattr: reply = NULL\n", __func__); ++ DbgPrint("novfs_ListX_File_Info xattr: reply = NULL\n"); + } + kfree(cmd); + +@@ -535,21 +558,23 @@ int Novfs_ListX_File_Info(char *Path, ch + return retCode; + } + +-static int begin_directory_enumerate(unsigned char *Path, int PathLen, HANDLE *EnumHandle, struct schandle *SessionId) ++static int begin_directory_enumerate(unsigned char * Path, int PathLen, void ** EnumHandle, ++ struct novfs_schandle SessionId) + { +- PBEGIN_ENUMERATE_DIRECTORY_REQUEST cmd; +- PBEGIN_ENUMERATE_DIRECTORY_REPLY reply = NULL; ++ struct novfs_begin_enumerate_directory_request *cmd; ++ struct novfs_begin_enumerate_directory_reply *reply = NULL; + unsigned long replylen = 0; + int retCode, cmdlen; + + *EnumHandle = 0; + +- cmdlen = offsetof(BEGIN_ENUMERATE_DIRECTORY_REQUEST, path) + PathLen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct ++ novfs_begin_enumerate_directory_request, path) + PathLen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_START_ENUMERATE; + cmd->Command.SequenceNumber = 0; +- memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->Command.SessionId = SessionId; + + cmd->pathLen = PathLen; + memcpy(cmd->path, Path, PathLen); +@@ -576,16 +601,16 @@ static int begin_directory_enumerate(uns + return (retCode); + } + +-static int end_directory_enumerate(HANDLE EnumHandle, struct schandle *SessionId) ++static int end_directory_enumerate(void *EnumHandle, struct novfs_schandle SessionId) + { +- END_ENUMERATE_DIRECTORY_REQUEST cmd; +- PEND_ENUMERATE_DIRECTORY_REPLY reply = NULL; ++ struct novfs_end_enumerate_directory_request cmd; ++ struct novfs_end_enumerate_directory_reply *reply = NULL; + unsigned long replylen = 0; + int retCode; + + cmd.Command.CommandType = VFS_COMMAND_END_ENUMERATE; + cmd.Command.SequenceNumber = 0; +- copy_session_id(&cmd.Command.SessionId, SessionId); ++ cmd.Command.SessionId = SessionId; + + cmd.enumerateHandle = EnumHandle; + +@@ -603,95 +628,24 @@ static int end_directory_enumerate(HANDL + return (retCode); + } + +-int directory_enumerate(HANDLE * EnumHandle, struct entry_info *Info, +- session_t SessionId) ++static int directory_enumerate_ex(void ** EnumHandle, struct novfs_schandle SessionId, int *Count, ++ struct novfs_entry_info **PInfo, int Interrupt) + { +- ENUMERATE_DIRECTORY_REQUEST cmd; +- PENUMERATE_DIRECTORY_REPLY reply = NULL; +- unsigned long replylen = 0; +- int retCode; +- +- cmd.Command.CommandType = VFS_COMMAND_ENUMERATE_DIRECTORY; +- cmd.Command.SequenceNumber = 0; +- cmd.Command.SessionId = SessionId; +- +- cmd.enumerateHandle = *EnumHandle; +- cmd.pathLen = 0; +- cmd.path[0] = '\0'; +- +- retCode = +- Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, +- &replylen, INTERRUPTIBLE); +- +- if (reply) { +- /* +- * The VFS_COMMAND_ENUMERATE_DIRECTORY call can return an +- * error but there could still be valid data. +- */ +- if (!reply->Reply.ErrorCode || +- ((replylen > sizeof(COMMAND_REPLY_HEADER)) && +- (reply->nameLen > 0))) { +- Info->type = 3; +- Info->mode = S_IRWXU; +- +- if (reply->mode & NW_ATTRIBUTE_DIRECTORY) { +- Info->mode |= S_IFDIR; +- Info->mode |= S_IXUSR; +- } else { +- Info->mode |= S_IFREG; +- } +- +- if (reply->mode & NW_ATTRIBUTE_READ_ONLY) { +- Info->mode &= ~(S_IWUSR); +- } +- +- if (reply->mode & NW_ATTRIBUTE_EXECUTE) { +- Info->mode |= S_IXUSR; +- } +- +- Info->uid = current->uid; +- Info->gid = current->gid; +- Info->size = reply->size; +- Info->atime.tv_sec = reply->lastAccessTime; +- Info->atime.tv_nsec = 0; +- Info->mtime.tv_sec = reply->modifyTime; +- Info->mtime.tv_nsec = 0; +- Info->ctime.tv_sec = reply->createTime; +- Info->ctime.tv_nsec = 0; +- Info->namelength = reply->nameLen; +- memcpy(Info->name, reply->name, reply->nameLen); +- retCode = 0; +- if (reply->Reply.ErrorCode) { +- retCode = -1; /* Eof of data */ +- } +- *EnumHandle = reply->enumerateHandle; +- } else { +- retCode = -ENODATA; +- } +- kfree(reply); +- } +- +- return (retCode); +-} +- +-static int directory_enumerate_ex(HANDLE *EnumHandle, struct schandle *SessionId, int *Count, struct entry_info **PInfo, int Interrupt) +-{ +- ENUMERATE_DIRECTORY_EX_REQUEST cmd; +- PENUMERATE_DIRECTORY_EX_REPLY reply = NULL; ++ struct novfs_enumerate_directory_ex_request cmd; ++ struct novfs_enumerate_directory_ex_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0; +- struct entry_info *info; +- PENUMERATE_DIRECTORY_EX_DATA data; ++ struct novfs_entry_info * info; ++ struct novfs_enumerate_directory_ex_data *data; + int isize; + +- if (PInfo) { ++ if (PInfo) + *PInfo = NULL; +- } + *Count = 0; + + cmd.Command.CommandType = VFS_COMMAND_ENUMERATE_DIRECTORY_EX; + cmd.Command.SequenceNumber = 0; +- copy_session_id(&cmd.Command.SessionId, SessionId); ++ cmd.Command.SessionId = SessionId; + + cmd.enumerateHandle = *EnumHandle; + cmd.pathLen = 0; +@@ -709,57 +663,92 @@ static int directory_enumerate_ex(HANDLE + */ + + if (!reply->Reply.ErrorCode || +- ((replylen > sizeof(COMMAND_REPLY_HEADER)) && ++ ((replylen > sizeof(struct novfs_command_reply_header)) && + (reply->enumCount > 0))) { + DbgPrint("directory_enumerate_ex: isize=%d\n", + replylen); +- data = (PENUMERATE_DIRECTORY_EX_DATA) ((char *)reply + sizeof(ENUMERATE_DIRECTORY_EX_REPLY)); +- isize = replylen - sizeof(PENUMERATE_DIRECTORY_EX_REPLY) - reply->enumCount * offsetof(ENUMERATE_DIRECTORY_EX_DATA, name); +- isize += (reply->enumCount * offsetof(struct entry_info, name)); ++ data = ++ (struct novfs_enumerate_directory_ex_data *) ((char *)reply + ++ sizeof ++ (struct novfs_enumerate_directory_ex_reply)); ++ isize = ++ replylen - sizeof(struct novfs_enumerate_directory_ex_reply *) - ++ reply->enumCount * ++ offsetof(struct ++ novfs_enumerate_directory_ex_data, name); ++ isize += ++ (reply->enumCount * ++ offsetof(struct novfs_entry_info, name)); + + if (PInfo) { +- *PInfo = info = Novfs_Malloc(isize, GFP_KERNEL); ++ *PInfo = info = kmalloc(isize, GFP_KERNEL); + if (*PInfo) { +- DbgPrint("directory_enumerate_ex1: data=0x%p info=0x%p\n", data, info); ++ DbgPrint ++ ("directory_enumerate_ex1: data=0x%p info=0x%p\n", ++ data, info); + *Count = reply->enumCount; + do { +- DbgPrint("directory_enumerate_ex2: data=0x%p length=%d\n", data); ++ DbgPrint ++ ("directory_enumerate_ex2: data=0x%p length=%d\n", ++ data); + + info->type = 3; + info->mode = S_IRWXU; + +- if (data->mode & NW_ATTRIBUTE_DIRECTORY) { ++ if (data-> ++ mode & ++ NW_ATTRIBUTE_DIRECTORY) { + info->mode |= S_IFDIR; + info->mode |= S_IXUSR; + } else { + info->mode |= S_IFREG; + } + +- if (data->mode & NW_ATTRIBUTE_READ_ONLY) { +- info->mode &= ~(S_IWUSR); ++ if (data-> ++ mode & ++ NW_ATTRIBUTE_READ_ONLY) { ++ info->mode &= ++ ~(S_IWUSR); + } + +- if (data->mode & NW_ATTRIBUTE_EXECUTE) { ++ if (data-> ++ mode & NW_ATTRIBUTE_EXECUTE) ++ { + info->mode |= S_IXUSR; + } + + info->uid = current->euid; + info->gid = current->egid; + info->size = data->size; +- info->atime.tv_sec = data->lastAccessTime; ++ info->atime.tv_sec = ++ data->lastAccessTime; + info->atime.tv_nsec = 0; +- info->mtime.tv_sec = data->modifyTime; ++ info->mtime.tv_sec = ++ data->modifyTime; + info->mtime.tv_nsec = 0; +- info->ctime.tv_sec = data->createTime; ++ info->ctime.tv_sec = ++ data->createTime; + info->ctime.tv_nsec = 0; +- info->namelength = data->nameLen; +- memcpy(info->name, data->name, data->nameLen); +- data = (PENUMERATE_DIRECTORY_EX_DATA)&data->name[data->nameLen]; +- replylen = (int)((char *)&info->name[info->namelength] - (char *)info); +- DbgPrint("directory_enumerate_ex3: info=0x%p\n", info); +- mydump(replylen, info); +- +- info = (struct entry_info *)&info->name[info->namelength]; ++ info->namelength = ++ data->nameLen; ++ memcpy(info->name, data->name, ++ data->nameLen); ++ data = ++ (struct novfs_enumerate_directory_ex_data *) ++ & data->name[data->nameLen]; ++ replylen = ++ (int)((char *)&info-> ++ name[info-> ++ namelength] - ++ (char *)info); ++ DbgPrint ++ ("directory_enumerate_ex3: info=0x%p\n", ++ info); ++ novfs_dump(replylen, info); ++ ++ info = ++ (struct novfs_entry_info *) & info-> ++ name[info->namelength]; + + } while (--reply->enumCount); + } +@@ -778,8 +767,9 @@ static int directory_enumerate_ex(HANDLE + return (retCode); + } + +-int Novfs_Get_Directory_ListEx(unsigned char * Path, HANDLE * EnumHandle, int *Count, +- struct entry_info **Info, struct schandle *SessionId) ++int novfs_get_dir_listex(unsigned char * Path, void ** EnumHandle, int *Count, ++ struct novfs_entry_info **Info, ++ struct novfs_schandle SessionId) + { + int retCode = -ENOENT; + +@@ -788,15 +778,20 @@ int Novfs_Get_Directory_ListEx(unsigned + if (Info) + *Info = NULL; + +- if ((HANDLE) - 1 == *EnumHandle) { ++ if ((void *) - 1 == *EnumHandle) { + return (-ENODATA); + } + +- if (0 == *EnumHandle) +- retCode = begin_directory_enumerate(Path, strlen(Path), EnumHandle, SessionId); ++ if (0 == *EnumHandle) { ++ retCode = ++ begin_directory_enumerate(Path, strlen(Path), EnumHandle, ++ SessionId); ++ } + + if (*EnumHandle) { +- retCode = directory_enumerate_ex(EnumHandle, SessionId, Count, Info, INTERRUPTIBLE); ++ retCode = ++ directory_enumerate_ex(EnumHandle, SessionId, Count, Info, ++ INTERRUPTIBLE); + if (retCode) { + end_directory_enumerate(*EnumHandle, SessionId); + if (-1 == retCode) { +@@ -808,11 +803,12 @@ int Novfs_Get_Directory_ListEx(unsigned + return (retCode); + } + +-int Novfs_Open_File(unsigned char * Path, int Flags, struct entry_info *Info, HANDLE * Handle, +- session_t SessionId) ++int novfs_open_file(unsigned char * Path, int Flags, struct novfs_entry_info * Info, ++ void ** Handle, ++ struct novfs_schandle SessionId) + { +- POPEN_FILE_REQUEST cmd; +- POPEN_FILE_REPLY reply; ++ struct novfs_open_file_request *cmd; ++ struct novfs_open_file_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + +@@ -825,8 +821,8 @@ int Novfs_Open_File(unsigned char * Path + + *Handle = 0; + +- cmdlen = offsetof(OPEN_FILE_REQUEST, path) + pathlen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_open_file_request, path) + pathlen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_OPEN_FILE; + cmd->Command.SequenceNumber = 0; +@@ -903,10 +899,10 @@ int Novfs_Open_File(unsigned char * Path + return (retCode); + } + +-int Novfs_Create(unsigned char * Path, int DirectoryFlag, session_t SessionId) ++int novfs_create(unsigned char * Path, int DirectoryFlag, struct novfs_schandle SessionId) + { +- PCREATE_FILE_REQUEST cmd; +- PCREATE_FILE_REPLY reply; ++ struct novfs_create_file_request *cmd; ++ struct novfs_create_file_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + +@@ -917,8 +913,8 @@ int Novfs_Create(unsigned char * Path, i + pathlen--; + } + +- cmdlen = offsetof(CREATE_FILE_REQUEST, path) + pathlen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_create_file_request, path) + pathlen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_CREATE_FILE; + if (DirectoryFlag) { +@@ -948,10 +944,10 @@ int Novfs_Create(unsigned char * Path, i + return (retCode); + } + +-int Novfs_Close_File(HANDLE Handle, session_t SessionId) ++int novfs_close_file(void *Handle, struct novfs_schandle SessionId) + { +- CLOSE_FILE_REQUEST cmd; +- PCLOSE_FILE_REPLY reply; ++ struct novfs_close_file_request cmd; ++ struct novfs_close_file_reply *reply; + unsigned long replylen = 0; + int retCode; + +@@ -974,11 +970,11 @@ int Novfs_Close_File(HANDLE Handle, sess + return (retCode); + } + +-int Novfs_Read_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, +- loff_t * Offset, session_t SessionId) ++int novfs_read_file(void *Handle, unsigned char * Buffer, size_t * Bytes, ++ loff_t * Offset, struct novfs_schandle SessionId) + { +- READ_FILE_REQUEST cmd; +- PREAD_FILE_REPLY reply = NULL; ++ struct novfs_read_file_request cmd; ++ struct novfs_read_file_reply * reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + size_t len; +@@ -986,8 +982,10 @@ int Novfs_Read_File(HANDLE Handle, unsig + len = *Bytes; + *Bytes = 0; + +- if ((offsetof(READ_FILE_REPLY, data) + len) > MaxIoSize) { +- len = MaxIoSize - offsetof(READ_FILE_REPLY, data); ++ if (offsetof(struct novfs_read_file_reply, data) + len ++ > novfs_max_iosize) { ++ len = novfs_max_iosize - offsetof(struct ++ novfs_read_file_reply, data); + len = (len / PAGE_SIZE) * PAGE_SIZE; + } + +@@ -999,9 +997,12 @@ int Novfs_Read_File(HANDLE Handle, unsig + cmd.len = len; + cmd.offset = *Offset; + +- retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); + +- DbgPrint("Novfs_Read_File: Queue_Daemon_Command 0x%x replylen=%d\n", retCode, replylen); ++ DbgPrint("novfs_Read_File: Queue_Daemon_Command 0x%x replylen=%d\n", ++ retCode, replylen); + + if (!retCode) { + if (reply->Reply.ErrorCode) { +@@ -1011,9 +1012,12 @@ int Novfs_Read_File(HANDLE Handle, unsig + retCode = -EIO; + } + } else { +- replylen -= offsetof(READ_FILE_REPLY, data); ++ replylen -= offsetof(struct ++ novfs_read_file_reply, data); ++ + if (replylen > 0) { +- replylen -= copy_to_user(Buffer, reply->data, replylen); ++ replylen -= ++ copy_to_user(Buffer, reply->data, replylen); + *Bytes = replylen; + } + } +@@ -1023,17 +1027,18 @@ int Novfs_Read_File(HANDLE Handle, unsig + kfree(reply); + } + +- DbgPrint("Novfs_Read_File *Bytes=0x%x retCode=0x%x\n", *Bytes, retCode); ++ DbgPrint("novfs_Read_File *Bytes=0x%x retCode=0x%x\n", *Bytes, retCode); + + return (retCode); + } + +-int Novfs_Read_Pages(HANDLE Handle, struct data_list *DList, int DList_Cnt, +- size_t * Bytes, loff_t * Offset, session_t SessionId) ++int novfs_read_pages(void *Handle, struct novfs_data_list *DList, ++ int DList_Cnt, size_t * Bytes, loff_t * Offset, ++ struct novfs_schandle SessionId) + { +- READ_FILE_REQUEST cmd; +- PREAD_FILE_REPLY reply = NULL; +- READ_FILE_REPLY lreply; ++ struct novfs_read_file_request cmd; ++ struct novfs_read_file_reply * reply = NULL; ++ struct novfs_read_file_reply lreply; + unsigned long replylen = 0; + int retCode = 0; + size_t len; +@@ -1042,7 +1047,7 @@ int Novfs_Read_Pages(HANDLE Handle, stru + *Bytes = 0; + + DbgPrint +- ("Novfs_Read_Pages: Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld SessionId=0x%p:%p\n", ++ ("novfs_Read_Pages: Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld SessionId=0x%p:%p\n", + Handle, DList, DList_Cnt, len, *Offset, SessionId.hTypeId, + SessionId.hId); + +@@ -1059,14 +1064,14 @@ int Novfs_Read_Pages(HANDLE Handle, stru + */ + DList[0].page = NULL; + DList[0].offset = &lreply; +- DList[0].len = offsetof(READ_FILE_REPLY, data); ++ DList[0].len = offsetof(struct novfs_read_file_reply, data); + DList[0].rwflag = DLWRITE; + + retCode = + Queue_Daemon_Command(&cmd, sizeof(cmd), DList, DList_Cnt, + (void *)&reply, &replylen, INTERRUPTIBLE); + +- DbgPrint("Novfs_Read_Pages: Queue_Daemon_Command 0x%x\n", retCode); ++ DbgPrint("novfs_Read_Pages: Queue_Daemon_Command 0x%x\n", retCode); + + if (!retCode) { + if (reply) { +@@ -1080,44 +1085,45 @@ int Novfs_Read_Pages(HANDLE Handle, stru + retCode = -EIO; + } + } +- *Bytes = replylen - offsetof(READ_FILE_REPLY, data); ++ *Bytes = replylen - offsetof(struct ++ novfs_read_file_reply, data); + } + + if (reply) { + kfree(reply); + } + +- DbgPrint("Novfs_Read_Pages: retCode=0x%x\n", retCode); ++ DbgPrint("novfs_Read_Pages: retCode=0x%x\n", retCode); + + return (retCode); + } + +-int Novfs_Write_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, +- loff_t * Offset, session_t SessionId) ++int novfs_write_file(void *Handle, unsigned char * Buffer, size_t * Bytes, ++ loff_t * Offset, struct novfs_schandle SessionId) + { +- WRITE_FILE_REQUEST cmd; +- PWRITE_FILE_REPLY reply = NULL; ++ struct novfs_write_file_request cmd; ++ struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + size_t len; + + unsigned long boff; + struct page **pages; +- struct data_list *dlist; ++ struct novfs_data_list *dlist; + int res = 0, npage, i; +- WRITE_FILE_REPLY lreply; ++ struct novfs_write_file_reply lreply; + + len = *Bytes; +- cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ cmdlen = offsetof(struct novfs_write_file_request, data); + + *Bytes = 0; + + memset(&lreply, 0, sizeof(lreply)); + +- DbgPrint("Novfs_Write_File cmdlen=%ld len=%ld\n", cmdlen, len); ++ DbgPrint("novfs_Write_File cmdlen=%ld len=%ld\n", cmdlen, len); + +- if ((cmdlen + len) > MaxIoSize) { +- len = MaxIoSize - cmdlen; ++ if ((cmdlen + len) > novfs_max_iosize) { ++ len = novfs_max_iosize - cmdlen; + len = (len / PAGE_SIZE) * PAGE_SIZE; + } + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; +@@ -1127,18 +1133,18 @@ int Novfs_Write_File(HANDLE Handle, unsi + cmd.len = len; + cmd.offset = *Offset; + +- DbgPrint("Novfs_Write_File cmdlen=%ld len=%ld\n", cmdlen, len); ++ DbgPrint("novfs_Write_File cmdlen=%ld len=%ld\n", cmdlen, len); + + npage = + (((unsigned long)Buffer & ~PAGE_MASK) + len + + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + +- dlist = Novfs_Malloc(sizeof(struct data_list) * (npage + 1), GFP_KERNEL); ++ dlist = kmalloc(sizeof(struct novfs_data_list) * (npage + 1), GFP_KERNEL); + if (NULL == dlist) { + return (-ENOMEM); + } + +- pages = Novfs_Malloc(sizeof(struct page *) * npage, GFP_KERNEL); ++ pages = kmalloc(sizeof(struct page *) * npage, GFP_KERNEL); + + if (NULL == pages) { + kfree(dlist); +@@ -1153,7 +1159,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + + up_read(¤t->mm->mmap_sem); + +- DbgPrint("Novfs_Write_File res=%d\n", res); ++ DbgPrint("novfs_Write_File res=%d\n", res); + + if (res > 0) { + boff = (unsigned long)Buffer & ~PAGE_MASK; +@@ -1168,12 +1174,12 @@ int Novfs_Write_File(HANDLE Handle, unsi + dlist[0].len = len; + } + +- DbgPrint("Novfs_Write_File0: page=0x%p offset=0x%p len=%d\n", ++ DbgPrint("novfs_Write_File0: page=0x%p offset=0x%p len=%d\n", + dlist[0].page, dlist[0].offset, dlist[0].len); + + boff = dlist[0].len; + +- DbgPrint("Novfs_Write_File len=%d boff=%d\n", len, boff); ++ DbgPrint("novfs_Write_File len=%d boff=%d\n", len, boff); + + for (i = 1; (i < res) && (boff < len); i++) { + flush_dcache_page(pages[i]); +@@ -1188,7 +1194,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + + boff += dlist[i].len; + DbgPrint +- ("Novfs_Write_File%d: page=0x%p offset=0x%p len=%d\n", ++ ("novfs_Write_File%d: page=0x%p offset=0x%p len=%d\n", + i, dlist[i].page, dlist[i].offset, dlist[i].len); + } + +@@ -1198,7 +1204,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + dlist[i].rwflag = DLWRITE; + res++; + +- DbgPrint("Novfs_Write_File Buffer=0x%p boff=0x%x len=%d\n", ++ DbgPrint("novfs_Write_File Buffer=0x%p boff=0x%x len=%d\n", + Buffer, boff, len); + + retCode = +@@ -1211,7 +1217,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + + res = 0; + +- kdata = Novfs_Malloc(len, GFP_KERNEL); ++ kdata = kmalloc(len, GFP_KERNEL); + if (kdata) { + len -= copy_from_user(kdata, Buffer, len); + dlist[0].page = NULL; +@@ -1233,7 +1239,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + } + } + +- DbgPrint("Novfs_Write_File retCode=0x%x reply=0x%p\n", retCode, reply); ++ DbgPrint("novfs_Write_File retCode=0x%x reply=0x%p\n", retCode, reply); + + if (!retCode) { + switch (lreply.Reply.ErrorCode) { +@@ -1267,7 +1273,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + kfree(pages); + kfree(dlist); + +- DbgPrint("Novfs_Write_File *Bytes=0x%x retCode=0x%x\n", *Bytes, ++ DbgPrint("novfs_Write_File *Bytes=0x%x retCode=0x%x\n", *Bytes, + retCode); + + return (retCode); +@@ -1276,7 +1282,7 @@ int Novfs_Write_File(HANDLE Handle, unsi + /* + * Arguments: HANDLE Handle - novfsd file handle + * struct page *Page - Page to be written out +- * session_t SessionId - novfsd session handle ++ * struct novfs_schandle SessionId - novfsd session handle + * + * Returns: 0 - Success + * -ENOSPC - Out of space on server +@@ -1285,17 +1291,17 @@ int Novfs_Write_File(HANDLE Handle, unsi + * + * Abstract: Write page to file. + */ +-int Novfs_Write_Page(HANDLE Handle, struct page *Page, session_t SessionId) ++int novfs_write_page(void *Handle, struct page *Page, struct novfs_schandle SessionId) + { +- WRITE_FILE_REQUEST cmd; +- WRITE_FILE_REPLY lreply; +- PWRITE_FILE_REPLY reply = NULL; ++ struct novfs_write_file_request cmd; ++ struct novfs_write_file_reply lreply; ++ struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; +- struct data_list dlst[2]; ++ struct novfs_data_list dlst[2]; + + DbgPrint +- ("Novfs_Write_Page: Handle=0x%p Page=0x%p Index=%lu SessionId=0x%llx\n", ++ ("novfs_Write_Page: Handle=0x%p Page=0x%p Index=%lu SessionId=0x%llx\n", + Handle, Page, Page->index, SessionId); + + dlst[0].page = NULL; +@@ -1308,7 +1314,7 @@ int Novfs_Write_Page(HANDLE Handle, stru + dlst[1].len = PAGE_CACHE_SIZE; + dlst[1].rwflag = DLREAD; + +- cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ cmdlen = offsetof(struct novfs_write_file_request, data); + + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; + cmd.Command.SequenceNumber = 0; +@@ -1348,23 +1354,23 @@ int Novfs_Write_Page(HANDLE Handle, stru + kfree(reply); + } + +- DbgPrint("Novfs_Write_Page retCode=0x%x\n", retCode); ++ DbgPrint("novfs_Write_Page retCode=0x%x\n", retCode); + + return (retCode); + } + +-int Novfs_Write_Pages(HANDLE Handle, struct data_list *DList, int DList_Cnt, +- size_t Bytes, loff_t Offset, session_t SessionId) ++int novfs_write_pages(void *Handle, struct novfs_data_list *DList, int DList_Cnt, ++ size_t Bytes, loff_t Offset, struct novfs_schandle SessionId) + { +- WRITE_FILE_REQUEST cmd; +- WRITE_FILE_REPLY lreply; +- PWRITE_FILE_REPLY reply = NULL; ++ struct novfs_write_file_request cmd; ++ struct novfs_write_file_reply lreply; ++ struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + size_t len; + + DbgPrint +- ("Novfs_Write_Pages: Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld SessionId=0x%llx\n", ++ ("novfs_Write_Pages: Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld SessionId=0x%llx\n", + Handle, DList, DList_Cnt, Bytes, Offset, SessionId); + + DList[0].page = NULL; +@@ -1373,7 +1379,7 @@ int Novfs_Write_Pages(HANDLE Handle, str + DList[0].rwflag = DLWRITE; + + len = Bytes; +- cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ cmdlen = offsetof(struct novfs_write_file_request, data); + + if (len) { + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; +@@ -1414,17 +1420,17 @@ int Novfs_Write_Pages(HANDLE Handle, str + kfree(reply); + } + } +- DbgPrint("Novfs_Write_Pages retCode=0x%x\n", retCode); ++ DbgPrint("novfs_Write_Pages retCode=0x%x\n", retCode); + + return (retCode); + } + +-int Novfs_Read_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, ++int novfs_read_stream(void *ConnHandle, unsigned char * Handle, u_char * Buffer, + size_t * Bytes, loff_t * Offset, int User, +- session_t SessionId) ++ struct novfs_schandle SessionId) + { +- READ_STREAM_REQUEST cmd; +- PREAD_STREAM_REPLY reply = NULL; ++ struct novfs_read_stream_request cmd; ++ struct novfs_read_stream_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0; + size_t len; +@@ -1432,8 +1438,10 @@ int Novfs_Read_Stream(HANDLE ConnHandle, + len = *Bytes; + *Bytes = 0; + +- if ((offsetof(READ_FILE_REPLY, data) + len) > MaxIoSize) { +- len = MaxIoSize - offsetof(READ_FILE_REPLY, data); ++ if (offsetof(struct novfs_read_file_reply, data) + len ++ > novfs_max_iosize) { ++ len = novfs_max_iosize - offsetof(struct ++ novfs_read_file_reply, data); + len = (len / PAGE_SIZE) * PAGE_SIZE; + } + +@@ -1446,60 +1454,70 @@ int Novfs_Read_Stream(HANDLE ConnHandle, + cmd.len = len; + cmd.offset = *Offset; + +- retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); + +- DbgPrint("Novfs_Read_Stream: Queue_Daemon_Command 0x%x replylen=%d\n", retCode, replylen); ++ DbgPrint("novfs_Read_Stream: Queue_Daemon_Command 0x%x replylen=%d\n", ++ retCode, replylen); + + if (reply) { + retCode = 0; + if (reply->Reply.ErrorCode) { + retCode = -EIO; + } else { +- replylen -= offsetof(READ_STREAM_REPLY, data); ++ replylen -= offsetof(struct ++ novfs_read_stream_reply, data); + if (replylen > 0) { +- if (User) +- replylen -= copy_to_user(Buffer, reply->data, replylen); +- else ++ if (User) { ++ replylen -= ++ copy_to_user(Buffer, reply->data, ++ replylen); ++ } else { + memcpy(Buffer, reply->data, replylen); ++ } ++ + *Bytes = replylen; + } + } + kfree(reply); + } + +- DbgPrint("Novfs_Read_Stream *Bytes=0x%x retCode=0x%x\n", *Bytes, retCode); ++ DbgPrint("novfs_Read_Stream *Bytes=0x%x retCode=0x%x\n", *Bytes, ++ retCode); + + return (retCode); + } + +-int Novfs_Write_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, +- size_t * Bytes, loff_t * Offset, session_t SessionId) ++int novfs_write_stream(void *ConnHandle, unsigned char * Handle, u_char * Buffer, ++ size_t * Bytes, loff_t * Offset, struct novfs_schandle SessionId) + { +- PWRITE_STREAM_REQUEST cmd; +- PWRITE_STREAM_REPLY reply = NULL; ++ struct novfs_write_stream_request * cmd; ++ struct novfs_write_stream_reply * reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + size_t len; + + len = *Bytes; +- cmdlen = len + offsetof(WRITE_STREAM_REQUEST, data); ++ cmdlen = len + offsetof(struct novfs_write_stream_request, data); + *Bytes = 0; + +- if (cmdlen > MaxIoSize) { +- cmdlen = MaxIoSize; +- len = cmdlen - offsetof(WRITE_STREAM_REQUEST, data); ++ if (cmdlen > novfs_max_iosize) { ++ cmdlen = novfs_max_iosize; ++ len = cmdlen - offsetof(struct ++ novfs_write_stream_request, data); + } + +- DbgPrint("Novfs_Write_Stream cmdlen=%d len=%d\n", cmdlen, len); ++ DbgPrint("novfs_Write_Stream cmdlen=%d len=%d\n", cmdlen, len); + +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + + if (cmd) { + if (Buffer && len) { + len -= copy_from_user(cmd->data, Buffer, len); + } + +- DbgPrint("Novfs_Write_Stream len=%d\n", len); ++ DbgPrint("novfs_Write_Stream len=%d\n", len); + + cmd->Command.CommandType = VFS_COMMAND_WRITE_STREAM; + cmd->Command.SequenceNumber = 0; +@@ -1532,23 +1550,23 @@ int Novfs_Write_Stream(HANDLE ConnHandle + break; + } + DbgPrint +- ("Novfs_Write_Stream reply->bytesWritten=0x%lx\n", ++ ("novfs_Write_Stream reply->bytesWritten=0x%lx\n", + reply->bytesWritten); + *Bytes = reply->bytesWritten; + kfree(reply); + } + kfree(cmd); + } +- DbgPrint("Novfs_Write_Stream *Bytes=0x%x retCode=0x%x\n", *Bytes, ++ DbgPrint("novfs_Write_Stream *Bytes=0x%x retCode=0x%x\n", *Bytes, + retCode); + + return (retCode); + } + +-int Novfs_Close_Stream(HANDLE ConnHandle, unsigned char * Handle, session_t SessionId) ++int novfs_close_stream(void *ConnHandle, unsigned char * Handle, struct novfs_schandle SessionId) + { +- CLOSE_STREAM_REQUEST cmd; +- PCLOSE_STREAM_REPLY reply; ++ struct novfs_close_stream_request cmd; ++ struct novfs_close_stream_reply *reply; + unsigned long replylen = 0; + int retCode; + +@@ -1572,10 +1590,10 @@ int Novfs_Close_Stream(HANDLE ConnHandle + return (retCode); + } + +-int Novfs_Delete(unsigned char * Path, int DirectoryFlag, session_t SessionId) ++int novfs_delete(unsigned char * Path, int DirectoryFlag, struct novfs_schandle SessionId) + { +- PDELETE_FILE_REQUEST cmd; +- PDELETE_FILE_REPLY reply; ++ struct novfs_delete_file_request *cmd; ++ struct novfs_delete_file_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + +@@ -1586,8 +1604,8 @@ int Novfs_Delete(unsigned char * Path, i + pathlen--; + } + +- cmdlen = offsetof(DELETE_FILE_REQUEST, path) + pathlen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_delete_file_request, path) + pathlen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_DELETE_FILE; + cmd->Command.SequenceNumber = 0; +@@ -1618,10 +1636,11 @@ int Novfs_Delete(unsigned char * Path, i + return (retCode); + } + +-int Novfs_Truncate_File(unsigned char * Path, int PathLen, session_t SessionId) ++int novfs_trunc(unsigned char * Path, int PathLen, ++ struct novfs_schandle SessionId) + { +- PTRUNCATE_FILE_REQUEST cmd; +- PTRUNCATE_FILE_REPLY reply; ++ struct novfs_truncate_file_request *cmd; ++ struct novfs_truncate_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode, cmdlen; + +@@ -1629,8 +1648,9 @@ int Novfs_Truncate_File(unsigned char * + if ('.' == Path[PathLen - 1]) + PathLen--; + } +- cmdlen = offsetof(TRUNCATE_FILE_REQUEST, path) + PathLen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_truncate_file_request, path) ++ + PathLen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_TRUNCATE_FILE; + cmd->Command.SequenceNumber = 0; +@@ -1655,17 +1675,18 @@ int Novfs_Truncate_File(unsigned char * + return (retCode); + } + +-int Novfs_Truncate_File_Ex(HANDLE Handle, loff_t Offset, session_t SessionId) ++int novfs_trunc_ex(void *Handle, loff_t Offset, ++ struct novfs_schandle SessionId) + { +- WRITE_FILE_REQUEST cmd; +- PWRITE_FILE_REPLY reply = NULL; ++ struct novfs_write_file_request cmd; ++ struct novfs_write_file_reply *reply = NULL; + unsigned long replylen = 0; + int retCode = 0, cmdlen; + +- DbgPrint("Novfs_Truncate_File_Ex Handle=0x%p Offset=%lld\n", Handle, ++ DbgPrint("novfs_Truncate_File_Ex Handle=0x%p Offset=%lld\n", Handle, + Offset); + +- cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ cmdlen = offsetof(struct novfs_write_file_request, data); + + cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; + cmd.Command.SequenceNumber = 0; +@@ -1678,7 +1699,7 @@ int Novfs_Truncate_File_Ex(HANDLE Handle + Queue_Daemon_Command(&cmd, cmdlen, NULL, 0, (void *)&reply, + &replylen, INTERRUPTIBLE); + +- DbgPrint("Novfs_Truncate_File_Ex retCode=0x%x reply=0x%p\n", retCode, ++ DbgPrint("novfs_Truncate_File_Ex retCode=0x%x reply=0x%p\n", retCode, + reply); + + if (!retCode) { +@@ -1709,20 +1730,21 @@ int Novfs_Truncate_File_Ex(HANDLE Handle + kfree(reply); + } + +- DbgPrint("Novfs_Truncate_File_Ex retCode=%d\n", retCode); ++ DbgPrint("novfs_Truncate_File_Ex retCode=%d\n", retCode); + + return (retCode); + } + +-int Novfs_Rename_File(int DirectoryFlag, unsigned char * OldName, int OldLen, +- unsigned char * NewName, int NewLen, session_t SessionId) ++int novfs_rename_file(int DirectoryFlag, unsigned char * OldName, int OldLen, ++ unsigned char * NewName, int NewLen, ++ struct novfs_schandle SessionId) + { +- RENAME_FILE_REQUEST cmd; +- PRENAME_FILE_REPLY reply; ++ struct novfs_rename_file_request cmd; ++ struct novfs_rename_file_reply *reply; + unsigned long replylen = 0; + int retCode; + +- DbgPrint("Novfs_Rename_File:\n" ++ DbgPrint("novfs_Rename_File:\n" + " DirectoryFlag: %d\n" + " OldName: %.*s\n" + " NewName: %.*s\n" +@@ -1761,10 +1783,11 @@ int Novfs_Rename_File(int DirectoryFlag, + return (retCode); + } + +-int Novfs_Set_Attr(unsigned char * Path, struct iattr *Attr, session_t SessionId) ++int novfs_set_attr(unsigned char * Path, struct iattr *Attr, ++ struct novfs_schandle SessionId) + { +- PSET_FILE_INFO_REQUEST cmd; +- PSET_FILE_INFO_REPLY reply; ++ struct novfs_set_file_info_request *cmd; ++ struct novfs_set_file_info_reply *reply; + unsigned long replylen = 0; + int retCode, cmdlen, pathlen; + +@@ -1775,8 +1798,8 @@ int Novfs_Set_Attr(unsigned char * Path, + pathlen--; + } + +- cmdlen = offsetof(SET_FILE_INFO_REQUEST, path) + pathlen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_set_file_info_request,path) + pathlen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_SET_FILE_INFO; + cmd->Command.SequenceNumber = 0; +@@ -1827,16 +1850,17 @@ int Novfs_Set_Attr(unsigned char * Path, + return (retCode); + } + +-int Novfs_Get_File_Cache_Flag(unsigned char * Path, session_t SessionId) ++int novfs_get_file_cache_flag(unsigned char * Path, ++ struct novfs_schandle SessionId) + { +- PGET_CACHE_FLAG_REQUEST cmd; +- PGET_CACHE_FLAG_REPLY reply = NULL; ++ struct novfs_get_cache_flag *cmd; ++ struct novfs_get_cache_flag_reply *reply = NULL; + unsigned long replylen = 0; + int cmdlen; + int retCode = 0; + int pathlen; + +- DbgPrint("Novfs_Get_File_Cache_Flag: Path = %s\n", Path); ++ DbgPrint("novfs_Get_File_Cache_Flag: Path = %s\n", Path); + + if (Path && *Path) { + pathlen = strlen(Path); +@@ -1844,8 +1868,10 @@ int Novfs_Get_File_Cache_Flag(unsigned c + if ('.' == Path[pathlen - 1]) + pathlen--; + } +- cmdlen = offsetof(GET_CACHE_FLAG_REQUEST, path) + pathlen; +- cmd = (PGET_CACHE_FLAG_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmdlen = offsetof(struct novfs_get_cache_flag, path) + ++ pathlen; ++ cmd = (struct novfs_get_cache_flag *) ++ kmalloc(cmdlen, GFP_KERNEL); + if (cmd) { + cmd->Command.CommandType = VFS_COMMAND_GET_CACHE_FLAG; + cmd->Command.SequenceNumber = 0; +@@ -1869,7 +1895,7 @@ int Novfs_Get_File_Cache_Flag(unsigned c + } + } + +- DbgPrint("Novfs_Get_File_Cache_Flag: return %d\n", retCode); ++ DbgPrint("novfs_Get_File_Cache_Flag: return %d\n", retCode); + return (retCode); + } + +@@ -1878,33 +1904,26 @@ int Novfs_Get_File_Cache_Flag(unsigned c + * SessionId, file handle, type of lock (read/write or unlock), + * start of lock area, length of lock area + * +- * Returns: +- * 0 on success +- * negative value on error +- * +- * Abstract: +- * + * Notes: lock type - fcntl + */ +-int Novfs_Set_File_Lock(session_t SessionId, HANDLE Handle, ++int novfs_set_file_lock(struct novfs_schandle SessionId, void *Handle, + unsigned char fl_type, loff_t fl_start, loff_t fl_len) + { +- PSET_FILE_LOCK_REQUEST cmd; +- PSET_FILE_LOCK_REPLY reply = NULL; ++ struct novfs_set_file_lock_request *cmd; ++ struct novfs_set_file_lock_reply *reply = NULL; + unsigned long replylen = 0; + int retCode; + + retCode = -1; + +- DbgPrint("Novfs_Set_File_Lock:\n" ++ DbgPrint("novfs_Set_File_Lock:\n" + " SessionId: 0x%llx\n", SessionId); + + cmd = +- (PSET_FILE_LOCK_REQUEST) Novfs_Malloc(sizeof(SET_FILE_LOCK_REQUEST), +- GFP_KERNEL); ++ (struct novfs_set_file_lock_request *) kmalloc(sizeof(struct novfs_set_file_lock_request), GFP_KERNEL); + + if (cmd) { +- DbgPrint("Novfs_Set_File_Lock 2\n"); ++ DbgPrint("novfs_Set_File_Lock 2\n"); + + cmd->Command.CommandType = VFS_COMMAND_SET_FILE_LOCK; + cmd->Command.SequenceNumber = 0; +@@ -1921,32 +1940,32 @@ int Novfs_Set_File_Lock(session_t Sessio + cmd->fl_start = fl_start; + cmd->fl_len = fl_len; + +- DbgPrint("Novfs_Set_File_Lock 3\n"); ++ DbgPrint("novfs_Set_File_Lock 3\n"); + +- DbgPrint("Novfs_Set_File_Lock: BEGIN dump arguments\n"); +- DbgPrint("Novfs_Set_File_Lock: Queue_Daemon_Command %d\n", ++ DbgPrint("novfs_Set_File_Lock: BEGIN dump arguments\n"); ++ DbgPrint("novfs_Set_File_Lock: Queue_Daemon_Command %d\n", + cmd->Command.CommandType); +- DbgPrint("Novfs_Set_File_Lock: cmd->handle = 0x%p\n", ++ DbgPrint("novfs_Set_File_Lock: cmd->handle = 0x%p\n", + cmd->handle); +- DbgPrint("Novfs_Set_File_Lock: cmd->fl_type = %u\n", ++ DbgPrint("novfs_Set_File_Lock: cmd->fl_type = %u\n", + cmd->fl_type); +- DbgPrint("Novfs_Set_File_Lock: cmd->fl_start = 0x%X\n", ++ DbgPrint("novfs_Set_File_Lock: cmd->fl_start = 0x%X\n", + cmd->fl_start); +- DbgPrint("Novfs_Set_File_Lock: cmd->fl_len = 0x%X\n", ++ DbgPrint("novfs_Set_File_Lock: cmd->fl_len = 0x%X\n", + cmd->fl_len); + DbgPrint +- ("Novfs_Set_File_Lock: sizeof(SET_FILE_LOCK_REQUEST) = %u\n", +- sizeof(SET_FILE_LOCK_REQUEST)); +- DbgPrint("Novfs_Set_File_Lock: END dump arguments\n"); ++ ("novfs_Set_File_Lock: sizeof(SET_FILE_LOCK_REQUEST) = %u\n", ++ sizeof(struct novfs_set_file_lock_request)); ++ DbgPrint("novfs_Set_File_Lock: END dump arguments\n"); + + retCode = +- Queue_Daemon_Command(cmd, sizeof(SET_FILE_LOCK_REQUEST), ++ Queue_Daemon_Command(cmd, sizeof(struct novfs_set_file_lock_request), + NULL, 0, (void *)&reply, &replylen, + INTERRUPTIBLE); +- DbgPrint("Novfs_Set_File_Lock 4\n"); ++ DbgPrint("novfs_Set_File_Lock 4\n"); + + if (reply) { +- DbgPrint("Novfs_Set_File_Lock 5, ErrorCode = %X\n", ++ DbgPrint("novfs_Set_File_Lock 5, ErrorCode = %X\n", + reply->Reply.ErrorCode); + + if (reply->Reply.ErrorCode) { +@@ -1954,11 +1973,10 @@ int Novfs_Set_File_Lock(session_t Sessio + } + kfree(reply); + } +- + kfree(cmd); + } + +- DbgPrint("Novfs_Set_File_Lock 6\n"); ++ DbgPrint("novfs_Set_File_Lock 6\n"); + + return (retCode); + } +--- a/fs/novfs/inode.c ++++ b/fs/novfs/inode.c +@@ -37,14 +37,6 @@ + /*===[ Include files specific to this module ]============================*/ + #include "vfs.h" + +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +-#define FSPRIVATE u.generic_ip +-#else +-#define FSPRIVATE i_private +-#endif +- +- +-#define FILE_UPDATE_TIMEOUT 2 + + struct inode_data { + void *Scope; +@@ -54,285 +46,260 @@ struct inode_data { + unsigned long cntDC; + struct list_head DirCache; + struct semaphore DirCacheLock; +- HANDLE FileHandle; ++ void * FileHandle; + int CacheFlag; + char Name[1]; /* Needs to be last entry */ + }; + +-// FIXME these are wrong, but fake the compiler out for now until the proper people can be flogged... +-extern void *Scope_Get_ScopefromName(struct qstr *Name); +-extern void *Scope_Get_ScopefromPath(struct dentry *Dentry); +- +-/*===[ Function prototypes ]==============================================*/ +-int Novfs_Remove_from_Root(char *RemoveName); +-int Novfs_Add_to_Root(char *); +-char *Novfs_dget_path(struct dentry *d, char *path, unsigned int pathlen); +-int verify_dentry(struct dentry *dentry, int Flags); +-int invalidate_dentry(struct dentry *parent); +-struct dentry *Novfs_d_lookup(struct dentry *Parent, struct qstr *Name); +-int Novfs_d_add(struct dentry *p, struct dentry *d, struct inode *i, int add); +-int Novfs_d_strcmp(struct qstr *s1, struct qstr *s2); +-unsigned long Novfs_internal_hash(struct qstr *name); ++#define FILE_UPDATE_TIMEOUT 2 ++ ++/*===[ Function prototypes ]=============================================*/ ++ ++static unsigned long novfs_internal_hash(struct qstr *name); ++static int novfs_d_add(struct dentry *p, struct dentry *d, struct inode *i, int add); + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +-int Novfs_get_sb(struct file_system_type *Fstype, int Flags, ++static int novfs_get_sb(struct file_system_type *Fstype, int Flags, + const char *Dev_name, void *Data, struct vfsmount *Mnt); +-#else +-struct super_block *Novfs_get_sb(struct file_system_type *Fstype, int Flags, +- const char *Dev_name, void *Data); +-#endif + +-int Novfs_fill_super(struct super_block *SB, void *Data, int Silent); ++static void novfs_kill_sb(struct super_block *SB); ++ + + /* + * Declared dentry_operations + */ +-int Novfs_d_revalidate(struct dentry *, struct nameidata *); +-int Novfs_d_hash(struct dentry *, struct qstr *); +-int Novfs_d_compare(struct dentry *, struct qstr *, struct qstr *); +-int Novfs_d_delete(struct dentry *dentry); +-void Novfs_d_release(struct dentry *dentry); +-void Novfs_d_iput(struct dentry *dentry, struct inode *inode); ++int novfs_d_revalidate(struct dentry *, struct nameidata *); ++int novfs_d_hash(struct dentry *, struct qstr *); ++int novfs_d_compare(struct dentry *, struct qstr *, struct qstr *); ++int novfs_d_delete(struct dentry *dentry); ++void novfs_d_release(struct dentry *dentry); ++void novfs_d_iput(struct dentry *dentry, struct inode *inode); + + /* + * Declared directory operations + */ +-int Novfs_dir_open(struct inode *inode, struct file *file); +-int Novfs_dir_release(struct inode *inode, struct file *file); +-loff_t Novfs_dir_lseek(struct file *file, loff_t offset, int origin); +-ssize_t Novfs_dir_read(struct file *file, char *buf, size_t len, loff_t * off); ++int novfs_dir_open(struct inode *inode, struct file *file); ++int novfs_dir_release(struct inode *inode, struct file *file); ++loff_t novfs_dir_lseek(struct file *file, loff_t offset, int origin); ++ssize_t novfs_dir_read(struct file *file, char *buf, size_t len, loff_t * off); + void addtodentry(struct dentry *Parent, unsigned char *List, int Level); +-int Novfs_filldir(void *data, const char *name, int namelen, loff_t off, ++int novfs_filldir(void *data, const char *name, int namelen, loff_t off, + ino_t ino, unsigned ftype); +-int Novfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir); +-int Novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync); ++int novfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir); ++int novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync); + + /* + * Declared address space operations + */ +-int Novfs_a_writepage(struct page *page, struct writeback_control *wbc); +-int Novfs_a_writepages(struct address_space *mapping, ++int novfs_a_writepage(struct page *page, struct writeback_control *wbc); ++int novfs_a_writepages(struct address_space *mapping, + struct writeback_control *wbc); +-int Novfs_a_prepare_write(struct file *file, struct page *page, unsigned from, ++int novfs_a_prepare_write(struct file *file, struct page *page, unsigned from, + unsigned to); +-int Novfs_a_commit_write(struct file *file, struct page *page, unsigned offset, ++int novfs_a_commit_write(struct file *file, struct page *page, unsigned offset, + unsigned to); +-int Novfs_a_readpage(struct file *file, struct page *page); +-int Novfs_a_readpages(struct file *file, struct address_space *mapping, ++int novfs_a_readpage(struct file *file, struct page *page); ++int novfs_a_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_lst, unsigned nr_pages); +-ssize_t Novfs_a_direct_IO(int rw, struct kiocb *kiocb, const struct iovec *iov, ++ssize_t novfs_a_direct_IO(int rw, struct kiocb *kiocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs); + + /* + * Declared file_operations + */ +-ssize_t Novfs_f_read(struct file *, char *, size_t, loff_t *); +-ssize_t Novfs_f_write(struct file *, const char *, size_t, loff_t *); +-int Novfs_f_readdir(struct file *, void *, filldir_t); +-int Novfs_f_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +-int Novfs_f_mmap(struct file *file, struct vm_area_struct *vma); +-int Novfs_f_open(struct inode *, struct file *); +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) +-int Novfs_f_flush(struct file *); +-#else +-int Novfs_f_flush(struct file *, fl_owner_t); +-#endif +-int Novfs_f_release(struct inode *, struct file *); +-int Novfs_f_fsync(struct file *, struct dentry *, int datasync); +-int Novfs_f_lock(struct file *, int, struct file_lock *); ++ssize_t novfs_f_read(struct file *, char *, size_t, loff_t *); ++ssize_t novfs_f_write(struct file *, const char *, size_t, loff_t *); ++int novfs_f_readdir(struct file *, void *, filldir_t); ++int novfs_f_ioctl(struct inode *, struct file *, unsigned int, unsigned long); ++int novfs_f_mmap(struct file *file, struct vm_area_struct *vma); ++int novfs_f_open(struct inode *, struct file *); ++int novfs_f_flush(struct file *, fl_owner_t); ++int novfs_f_release(struct inode *, struct file *); ++int novfs_f_fsync(struct file *, struct dentry *, int datasync); ++int novfs_f_lock(struct file *, int, struct file_lock *); + + /* + * Declared inode_operations + */ +-int Novfs_i_create(struct inode *, struct dentry *, int, struct nameidata *); +-struct dentry *Novfs_i_lookup(struct inode *, struct dentry *, ++int novfs_i_create(struct inode *, struct dentry *, int, struct nameidata *); ++struct dentry *novfs_i_lookup(struct inode *, struct dentry *, + struct nameidata *); +-int Novfs_i_mkdir(struct inode *, struct dentry *, int); +-int Novfs_i_unlink(struct inode *dir, struct dentry *dentry); +-int Novfs_i_rmdir(struct inode *, struct dentry *); +-int Novfs_i_mknod(struct inode *, struct dentry *, int, dev_t); +-int Novfs_i_rename(struct inode *, struct dentry *, struct inode *, ++int novfs_i_mkdir(struct inode *, struct dentry *, int); ++int novfs_i_unlink(struct inode *dir, struct dentry *dentry); ++int novfs_i_rmdir(struct inode *, struct dentry *); ++int novfs_i_mknod(struct inode *, struct dentry *, int, dev_t); ++int novfs_i_rename(struct inode *, struct dentry *, struct inode *, + struct dentry *); +-int Novfs_i_permission(struct inode *inode, int mask); +-int Novfs_i_setattr(struct dentry *, struct iattr *); +-int Novfs_i_getattr(struct vfsmount *mnt, struct dentry *, struct kstat *); +-int Novfs_i_revalidate(struct dentry *dentry); ++int novfs_i_setattr(struct dentry *, struct iattr *); ++int novfs_i_getattr(struct vfsmount *mnt, struct dentry *, struct kstat *); ++int novfs_i_revalidate(struct dentry *dentry); + + /* + * Extended attributes operations + */ + +-int Novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, ++int novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, + size_t size); +-int Novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, ++int novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t value_size, int flags); +-int Novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); ++int novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); + +-void update_inode(struct inode *Inode, struct entry_info *Info); ++void update_inode(struct inode *Inode, struct novfs_entry_info *Info); + + /* + * Declared super_operations + */ +-void Novfs_read_inode(struct inode *inode); +-void Novfs_write_inode(struct inode *inode); +-int Novfs_notify_change(struct dentry *dentry, struct iattr *attr); +-void Novfs_clear_inode(struct inode *inode); +-int Novfs_show_options(struct seq_file *s, struct vfsmount *m); +- +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +-int Novfs_statfs(struct dentry *de, struct kstatfs *buf); +-#else +-int Novfs_statfs(struct super_block *sb, struct kstatfs *buf); +-#endif ++void novfs_read_inode(struct inode *inode); ++void novfs_write_inode(struct inode *inode); ++int novfs_notify_change(struct dentry *dentry, struct iattr *attr); ++void novfs_clear_inode(struct inode *inode); ++int novfs_show_options(struct seq_file *s, struct vfsmount *m); ++ ++int novfs_statfs(struct dentry *de, struct kstatfs *buf); + + /* + * Declared control interface functions + */ + ssize_t +-Novfs_Control_read(struct file *file, char *buf, size_t nbytes, loff_t * ppos); ++novfs_control_Read(struct file *file, char *buf, size_t nbytes, loff_t * ppos); + + ssize_t +-Novfs_Control_write(struct file *file, const char *buf, size_t nbytes, ++novfs_control_write(struct file *file, const char *buf, size_t nbytes, + loff_t * ppos); + +-int Novfs_Control_ioctl(struct inode *inode, struct file *file, ++int novfs_control_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + + int __init init_novfs(void); + void __exit exit_novfs(void); + +-int Novfs_lock_inode_cache(struct inode *i); +-void Novfs_unlock_inode_cache(struct inode *i); +-int Novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, +- ino_t * ino, struct entry_info *info); +-int Novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, +- struct entry_info *info); +-int Novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, +- struct entry_info *info); +-int Novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, +- struct entry_info *info, u64 * EntryTime); +-int Novfs_get_remove_entry(struct inode *i, ino_t * ino, struct entry_info *info); +-void Novfs_invalidate_inode_cache(struct inode *i); +-static struct dir_cache *Novfs_lookup_inode_cache(struct inode *i, struct qstr *name, ino_t ino); +-int Novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino); +-int Novfs_add_inode_entry(struct inode *i, struct qstr *name, ino_t ino, +- struct entry_info *info); +-int Novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, +- struct entry_info *info); +-void Novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino); +-void Novfs_free_invalid_entries(struct inode *i); +-void Novfs_free_inode_cache(struct inode *i); ++int novfs_lock_inode_cache(struct inode *i); ++void novfs_unlock_inode_cache(struct inode *i); ++int novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, ++ ino_t * ino, struct novfs_entry_info *info); ++int novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, ++ struct novfs_entry_info *info); ++int novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, ++ struct novfs_entry_info *info); ++int novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, ++ struct novfs_entry_info *info, u64 * EntryTime); ++int novfs_get_remove_entry(struct inode *i, ino_t * ino, struct novfs_entry_info *info); ++void novfs_invalidate_inode_cache(struct inode *i); ++struct novfs_dir_cache *novfs_lookup_inode_cache(struct inode *i, struct qstr *name, ++ ino_t ino); ++int novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino); ++int novfs_add_inode_entry(struct inode *i, struct qstr *name, ino_t ino, ++ struct novfs_entry_info *info); ++int novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, ++ struct novfs_entry_info *info); ++void novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino); ++void novfs_free_invalid_entries(struct inode *i); ++void novfs_free_inode_cache(struct inode *i); + + /*===[ Global variables ]=================================================*/ +-struct dentry_operations Novfs_dentry_operations = { +- .d_revalidate = Novfs_d_revalidate, +- .d_hash = Novfs_d_hash, +- .d_compare = Novfs_d_compare, +- //.d_delete = Novfs_d_delete, +- .d_release = Novfs_d_release, +- .d_iput = Novfs_d_iput, ++struct dentry_operations novfs_dentry_operations = { ++ .d_revalidate = novfs_d_revalidate, ++ .d_hash = novfs_d_hash, ++ .d_compare = novfs_d_compare, ++ //.d_delete = novfs_d_delete, ++ .d_release = novfs_d_release, ++ .d_iput = novfs_d_iput, + }; + +-struct file_operations Novfs_dir_operations = { ++struct file_operations novfs_dir_operations = { + .owner = THIS_MODULE, +- .open = Novfs_dir_open, +- .release = Novfs_dir_release, +- .llseek = Novfs_dir_lseek, +- .read = Novfs_dir_read, +- .readdir = Novfs_dir_readdir, +- .fsync = Novfs_dir_fsync, ++ .open = novfs_dir_open, ++ .release = novfs_dir_release, ++ .llseek = novfs_dir_lseek, ++ .read = novfs_dir_read, ++ .readdir = novfs_dir_readdir, ++ .fsync = novfs_dir_fsync, + }; + +-static struct file_operations Novfs_file_operations = { ++static struct file_operations novfs_file_operations = { + .owner = THIS_MODULE, +- .read = Novfs_f_read, +- .write = Novfs_f_write, +- .readdir = Novfs_f_readdir, +- .ioctl = Novfs_f_ioctl, +- .mmap = Novfs_f_mmap, +- .open = Novfs_f_open, +- .flush = Novfs_f_flush, +- .release = Novfs_f_release, +- .fsync = Novfs_f_fsync, ++ .read = novfs_f_read, ++ .write = novfs_f_write, ++ .readdir = novfs_f_readdir, ++ .ioctl = novfs_f_ioctl, ++ .mmap = novfs_f_mmap, ++ .open = novfs_f_open, ++ .flush = novfs_f_flush, ++ .release = novfs_f_release, ++ .fsync = novfs_f_fsync, + .llseek = generic_file_llseek, +- .lock = Novfs_f_lock, ++ .lock = novfs_f_lock, + }; + +-static struct address_space_operations Novfs_nocache_aops = { +- .readpage = Novfs_a_readpage, ++static struct address_space_operations novfs_nocache_aops = { ++ .readpage = novfs_a_readpage, + }; + +-struct backing_dev_info Novfs_backing_dev_info = { ++struct backing_dev_info novfs_backing_dev_info = { + .ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE, + .state = 0, + .capabilities = BDI_CAP_NO_WRITEBACK | BDI_CAP_MAP_COPY, + .unplug_io_fn = default_unplug_io_fn, + }; + +-static struct address_space_operations Novfs_aops = { +- .readpage = Novfs_a_readpage, +- .readpages = Novfs_a_readpages, +- .writepage = Novfs_a_writepage, +- .writepages = Novfs_a_writepages, +- .prepare_write = Novfs_a_prepare_write, +- .commit_write = Novfs_a_commit_write, ++static struct address_space_operations novfs_aops = { ++ .readpage = novfs_a_readpage, ++ .readpages = novfs_a_readpages, ++ .writepage = novfs_a_writepage, ++ .writepages = novfs_a_writepages, ++ .prepare_write = novfs_a_prepare_write, ++ .commit_write = novfs_a_commit_write, + .set_page_dirty = __set_page_dirty_nobuffers, +- .direct_IO = Novfs_a_direct_IO, ++ .direct_IO = novfs_a_direct_IO, + }; + +-static struct inode_operations Novfs_inode_operations = { +- .create = Novfs_i_create, +- .lookup = Novfs_i_lookup, +- .unlink = Novfs_i_unlink, +- .mkdir = Novfs_i_mkdir, +- .rmdir = Novfs_i_rmdir, +- .mknod = Novfs_i_mknod, +- .rename = Novfs_i_rename, +- .setattr = Novfs_i_setattr, +- .getattr = Novfs_i_getattr, +-/* +- .getxattr = Novfs_i_getxattr, +- .setxattr = Novfs_i_setxattr, +- .listxattr = Novfs_i_listxattr, ++static struct inode_operations novfs_inode_operations = { ++ .create = novfs_i_create, ++ .lookup = novfs_i_lookup, ++ .unlink = novfs_i_unlink, ++ .mkdir = novfs_i_mkdir, ++ .rmdir = novfs_i_rmdir, ++ .mknod = novfs_i_mknod, ++ .rename = novfs_i_rename, ++ .setattr = novfs_i_setattr, ++ .getattr = novfs_i_getattr, ++/* ++ .getxattr = novfs_i_getxattr, ++ .setxattr = novfs_i_setxattr, ++ .listxattr = novfs_i_listxattr, + */ + }; + +-static struct inode_operations Novfs_file_inode_operations = { +- .setattr = Novfs_i_setattr, +- .getattr = Novfs_i_getattr, +-/* +- .getxattr = Novfs_i_getxattr, +- .setxattr = Novfs_i_setxattr, +- .listxattr = Novfs_i_listxattr, ++static struct inode_operations novfs_file_inode_operations = { ++ .setattr = novfs_i_setattr, ++ .getattr = novfs_i_getattr, ++/* ++ .getxattr = novfs_i_getxattr, ++ .setxattr = novfs_i_setxattr, ++ .listxattr = novfs_i_listxattr, + */ + }; + +-static struct super_operations Novfs_ops = { +- .statfs = Novfs_statfs, +- .clear_inode = Novfs_clear_inode, ++static struct super_operations novfs_ops = { ++ .statfs = novfs_statfs, ++ .clear_inode = novfs_clear_inode, + .drop_inode = generic_delete_inode, +- .show_options = Novfs_show_options, ++ .show_options = novfs_show_options, + + }; + + /* Not currently used +-static struct file_operations Novfs_Control_operations = { +- .read = Novfs_Control_read, +- .write = Novfs_Control_write, +- .ioctl = Novfs_Control_ioctl, ++static struct file_operations novfs_Control_operations = { ++ .read = novfs_Control_read, ++ .write = novfs_Control_write, ++ .ioctl = novfs_Control_ioctl, + }; + */ + +-static atomic_t Novfs_Inode_Number = ATOMIC_INIT(0); +- +-struct dentry *Novfs_root = NULL; ++static atomic_t novfs_Inode_Number = ATOMIC_INIT(0); + +-int Novfs_Version_Major = NOVFS_VFS_MAJOR; +-int Novfs_Version_Minor = NOVFS_VFS_MINOR; +-int Novfs_Version_Sub = NOVFS_VFS_SUB; +-int Novfs_Version_Release = NOVFS_VFS_RELEASE; + +-char *Novfs_CurrentMount = NULL; ++struct dentry *novfs_root = NULL; ++char *novfs_current_mnt = NULL; + + DECLARE_MUTEX(InodeList_lock); + +@@ -346,18 +313,13 @@ uint64_t inHAXTime; + int inHAX; + + unsigned long InodeCount = 0, DCCount = 0; +-unsigned long File_update_timeout = FILE_UPDATE_TIMEOUT; +-int PageCache = 0; ++unsigned long novfs_update_timeout = FILE_UPDATE_TIMEOUT; ++int novfs_page_cache = 0; + +-typedef struct _Novfs_List2 { +- struct list_head list; +- void *data; +-} Novfs_List2; +- +-typedef struct _File_Private2 { ++struct file_private { + int listedall; +- HANDLE enumHandle; +-} FilePrivate2; ++ void *enumHandle; ++}; + + static void PRINT_DENTRY(const char *s, struct dentry *d) + { +@@ -370,8 +332,8 @@ static void PRINT_DENTRY(const char *s, + " prev: 0x%p\n", &d->d_lru, d->d_lru.next, + d->d_lru.prev); + DbgPrint(" d_child: 0x%p\n" " next: 0x%p\n" +- " prev: 0x%p\n", &d->D_CHILD, d->D_CHILD.next, +- d->D_CHILD.prev); ++ " prev: 0x%p\n", &d->d_u.d_child, ++ d->d_u.d_child.next, d->d_u.d_child.prev); + DbgPrint(" d_subdirs: 0x%p\n" " next: 0x%p\n" + " prev: 0x%p\n", &d->d_subdirs, d->d_subdirs.next, + d->d_subdirs.prev); +@@ -397,144 +359,109 @@ static void PRINT_DENTRY(const char *s, + } + + /*++======================================================================*/ +-int Novfs_Remove_from_Root(char *RemoveName) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_remove_from_root(char *RemoveName) + { + struct qstr name; + struct dentry *dentry; + struct inode *dir; + +- DbgPrint("Novfs_Remove_from_Root: %s\n", RemoveName); ++ DbgPrint("novfs_Remove_from_Root: %s\n", RemoveName); + name.len = strlen(RemoveName); + name.name = RemoveName; +- Novfs_d_hash(Novfs_root, &name); ++ novfs_d_hash(novfs_root, &name); + +- dentry = d_lookup(Novfs_root, &name); ++ dentry = d_lookup(novfs_root, &name); + if (dentry) { +- if (dentry->d_inode && dentry->d_inode->FSPRIVATE) { +- ((struct inode_data *)(dentry->d_inode->FSPRIVATE))->Scope = +- NULL; ++ if (dentry->d_inode && dentry->d_inode->i_private) { ++ struct inode_data *n_inode = ++ dentry->d_inode->i_private; ++ n_inode->Scope = NULL; + } + dput(dentry); + } + +- dir = Novfs_root->d_inode; ++ dir = novfs_root->d_inode; + +- Novfs_lock_inode_cache(dir); +- Novfs_remove_inode_entry(dir, &name, 0); +- Novfs_unlock_inode_cache(dir); ++ novfs_lock_inode_cache(dir); ++ novfs_remove_inode_entry(dir, &name, 0); ++ novfs_unlock_inode_cache(dir); + + return (0); + } + + /*++======================================================================*/ +-int Novfs_Add_to_Root(char *AddName) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_add_to_root(char *AddName) + { + struct qstr name; + struct inode *dir; +- struct entry_info info; ++ struct novfs_entry_info info; + ino_t ino; + +- DbgPrint("Novfs_Add_to_Root: %s\n", AddName); ++ DbgPrint("novfs_Add_to_Root: %s\n", AddName); + name.len = strlen(AddName); + name.name = AddName; +- Novfs_d_hash(Novfs_root, &name); ++ novfs_d_hash(novfs_root, &name); + +- dir = Novfs_root->d_inode; ++ dir = novfs_root->d_inode; + +- Novfs_lock_inode_cache(dir); ++ novfs_lock_inode_cache(dir); + + ino = 0; + +- if (!Novfs_lookup_inode_cache(dir, &name, 0)) { ++ if (!novfs_lookup_inode_cache(dir, &name, 0)) { + info.mode = S_IFDIR | 0700; + info.size = 0; + info.atime = info.ctime = info.mtime = CURRENT_TIME; + +- ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); +- Novfs_add_inode_entry(dir, &name, ino, &info); ++ ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); ++ novfs_add_inode_entry(dir, &name, ino, &info); + } + +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + + return (0); + } + + /*++======================================================================*/ +-int Novfs_Add_to_Root2(char *AddName) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_Add_to_Root2(char *AddName) + { + struct dentry *entry; + struct qstr name; + struct inode *inode; + void *scope; + +- DbgPrint("Novfs_Add_to_Root: %s\n", AddName); ++ DbgPrint("novfs_Add_to_Root: %s\n", AddName); + name.len = strlen(AddName); + name.name = AddName; + +- Novfs_d_hash(Novfs_root, &name); ++ novfs_d_hash(novfs_root, &name); + +- entry = Novfs_d_lookup(Novfs_root, &name); +- DbgPrint("Novfs_Add_to_Root: Novfs_d_lookup 0x%p\n", entry); ++ entry = d_lookup(novfs_root, &name); ++ DbgPrint("novfs_Add_to_Root: novfs_d_lookup 0x%p\n", entry); + if (NULL == entry) { +- scope = Scope_Lookup(); ++ scope = novfs_scope_lookup(); + +- entry = d_alloc(Novfs_root, &name); +- DbgPrint("Novfs_Add_to_Root: d_alloc 0x%p\n", entry); ++ entry = d_alloc(novfs_root, &name); ++ DbgPrint("novfs_Add_to_Root: d_alloc 0x%p\n", entry); + if (entry) { +- entry->d_op = &Novfs_dentry_operations; +- entry->d_time = jiffies + (File_update_timeout * HZ); ++ entry->d_op = &novfs_dentry_operations; ++ entry->d_time = jiffies + (novfs_update_timeout * HZ); + /* +- * done in Novfs_d_add now... entry->d_fsdata = (void *)Novfs_internal_hash( &name ); ++ * done in novfs_d_add now... entry->d_fsdata = (void *)novfs_internal_hash( &name ); + */ + inode = +- Novfs_get_inode(Novfs_root->d_sb, S_IFDIR | 0700, 0, Scope_Get_Uid(scope), 0, &name); +- DbgPrint("Novfs_Add_to_Root: Inode=0x%p\n", inode); ++ novfs_get_inode(novfs_root->d_sb, S_IFDIR | 0700, 0, novfs_scope_get_uid(scope), 0, &name); ++ DbgPrint("novfs_Add_to_Root: Inode=0x%p\n", inode); + if (inode) { + inode->i_atime = + inode->i_ctime = + inode->i_mtime = CURRENT_TIME; +- if (!Novfs_d_add(Novfs_root, entry, inode, 1)) { +- if (inode->FSPRIVATE) { +- ((struct inode_data *) inode-> +- FSPRIVATE)->Flags = USER_INODE; ++ if (!novfs_d_add(novfs_root, entry, inode, 1)) { ++ if (inode->i_private) { ++ struct inode_data *n_inode = inode->i_private; ++ n_inode->Flags = USER_INODE; + } +- PRINT_DENTRY("After Novfs_d_add", ++ PRINT_DENTRY("After novfs_d_add", + entry); + } else { + dput(entry); +@@ -544,27 +471,12 @@ int Novfs_Add_to_Root2(char *AddName) + } + } else { + dput(entry); +- PRINT_DENTRY("Novfs_Add_to_Root: After dput Dentry", entry); ++ PRINT_DENTRY("novfs_Add_to_Root: After dput Dentry", entry); + } + return (0); + } + +-/*++======================================================================*/ +-char *Novfs_dget_path(struct dentry *Dentry, char *Buf, unsigned int Buflen) +-/* +- * Arguments: struct dentry *Dentry - starting entry +- * char *Buf - pointer to memory buffer +- * unsigned int Buflen - size of memory buffer +- * +- * Returns: pointer to path. +- * +- * Abstract: Walks the dentry chain building a path. +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++char *novfs_dget_path(struct dentry *Dentry, char *Buf, unsigned int Buflen) + { + char *retval = &Buf[Buflen]; + struct dentry *p = Dentry; +@@ -591,34 +503,17 @@ char *Novfs_dget_path(struct dentry *Den + } + + if (retval) +- DbgPrint("Novfs_dget_path: %s\n", retval); ++ DbgPrint("novfs_dget_path: %s\n", retval); + return (retval); + } + +-/*++======================================================================*/ + int verify_dentry(struct dentry *dentry, int Flags) +-/* +- * Arguments: struct dentry *dentry - entry to verify +- * +- * Returns: zero - Inode cache has been updated. If not in the cache +- * then file doesn't exist. +- * !zero - Error +- * +- * Abstract: This routine will verify if the file that dentry is pointing +- * at exist and if it does it will put it in the inode cache of +- * the parent. +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + int retVal = -ENOENT; + struct inode *dir; +- struct entry_info *info = NULL; ++ struct novfs_entry_info *info = NULL; + struct inode_data *id; +- session_t session; ++ struct novfs_schandle session; + char *path, *list = NULL, *cp; + ino_t ino = 0; + struct qstr name; +@@ -633,19 +528,19 @@ int verify_dentry(struct dentry *dentry, + } + + if (dentry && dentry->d_parent && +- (dir = dentry->d_parent->d_inode) && (id = dir->FSPRIVATE)) { ++ (dir = dentry->d_parent->d_inode) && (id = dir->i_private)) { + parent = dget_parent(dentry); + +- info = Novfs_Malloc(sizeof(struct entry_info) + PATH_LENGTH_BUFFER, GFP_KERNEL); ++ info = kmalloc(sizeof(struct novfs_entry_info) + PATH_LENGTH_BUFFER, GFP_KERNEL); + + if (info) { +- if (Novfs_lock_inode_cache(dir)) { ++ if (novfs_lock_inode_cache(dir)) { + name.len = dentry->d_name.len; + name.name = dentry->d_name.name; +- name.hash = Novfs_internal_hash(&name); +- if (!Novfs_get_entry_time(dir, &name, &ino, info, &ctime)) { ++ name.hash = novfs_internal_hash(&name); ++ if (!novfs_get_entry_time(dir, &name, &ino, info, &ctime)) { + inode = dentry->d_inode; +- if (inode && inode->FSPRIVATE && ++ if (inode && inode->i_private && + ((inode->i_size != info->size) || + (inode->i_mtime.tv_sec != + info->mtime.tv_sec) +@@ -654,30 +549,31 @@ int verify_dentry(struct dentry *dentry, + /* + * Values don't match so update. + */ +- ((struct inode_data *) inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ struct inode_data *n_inode = inode->i_private; ++ n_inode->Flags |= UPDATE_INODE; + } + + ctime = get_jiffies_64() - ctime; +- if (Flags || ctime < (u64) (File_update_timeout * HZ)) { ++ if (Flags || ctime < (u64) (novfs_update_timeout * HZ)) { + retVal = 0; +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + dput(parent); + kfree(info); + return (0); + } + } +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + } + + if (IS_ROOT(dentry->d_parent)) { +- session = Scope_Get_SessionId(Scope_Get_ScopefromName(&dentry->d_name)); +- } else { +- session = Scope_Get_SessionId(id->Scope); +- } ++ session = novfs_scope_get_sessionId( ++ novfs_get_scope_from_name(&dentry->d_name)); ++ } else ++ session = novfs_scope_get_sessionId(id->Scope); + + if (!SC_PRESENT(session)) { +- id->Scope = Scope_Get_ScopefromPath(dentry); +- session = Scope_Get_SessionId(id->Scope); ++ id->Scope = novfs_get_scope(dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + ino = 0; +@@ -685,62 +581,65 @@ int verify_dentry(struct dentry *dentry, + + if (IS_ROOT(dentry->d_parent)) { + DbgPrint("verify_dentry: parent is Root directory\n"); +- list = Scope_Get_ScopeUsers(); ++ list = novfs_get_scopeusers(); + +- iLock = Novfs_lock_inode_cache(dir); +- Novfs_invalidate_inode_cache(dir); ++ iLock = novfs_lock_inode_cache(dir); ++ novfs_invalidate_inode_cache(dir); + + if (list) { + cp = list; + while (*cp) { + name.name = cp; + name.len = strlen(cp); +- name.hash = Novfs_internal_hash(&name); ++ name.hash = novfs_internal_hash(&name); + cp += (name.len + 1); + ino = 0; +- if (Novfs_get_entry(dir, &name, &ino, info)) { ++ if (novfs_get_entry(dir, &name, &ino, info)) { + info->mode = S_IFDIR | 0700; + info->size = 0; + info->atime = info->ctime = info->mtime = CURRENT_TIME; +- ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); +- Novfs_add_inode_entry(dir, &name, ino, info); ++ ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); ++ novfs_add_inode_entry(dir, &name, ino, info); + } + } + } +- Novfs_free_invalid_entries(dir); ++ novfs_free_invalid_entries(dir); + } else { + + path = +- Novfs_dget_path(dentry, info->name, ++ novfs_dget_path(dentry, info->name, + PATH_LENGTH_BUFFER); + if (path) { + if (dentry->d_name.len <= + NW_MAX_PATH_LENGTH) { + name.hash = +- Novfs_internal_hash ++ novfs_internal_hash + (&dentry->d_name); + name.len = dentry->d_name.len; + name.name = dentry->d_name.name; + +- retVal = Novfs_Get_File_Info(path, info, &session); ++ retVal = ++ novfs_get_file_info(path, ++ info, ++ session); + if (0 == retVal) { + dentry->d_time = + jiffies + +- (File_update_timeout ++ (novfs_update_timeout + * HZ); + iLock = +- Novfs_lock_inode_cache ++ novfs_lock_inode_cache + (dir); +- if (Novfs_update_entry ++ if (novfs_update_entry + (dir, &name, 0, + info)) { + if (dentry-> + d_inode) { + ino = dentry->d_inode->i_ino; + } else { +- ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); + } +- Novfs_add_inode_entry ++ novfs_add_inode_entry + (dir, &name, + ino, info); + } +@@ -758,14 +657,14 @@ int verify_dentry(struct dentry *dentry, + ~S_DEAD; + if (dentry-> + d_inode-> +- FSPRIVATE) { +- ((struct inode_data *) dentry->d_inode->FSPRIVATE)->Scope = id->Scope; ++ i_private) { ++ ((struct inode_data *) dentry->d_inode->i_private)->Scope = id->Scope; + } + } + } else if (-EINTR != retVal) { + retVal = 0; +- iLock = Novfs_lock_inode_cache(dir); +- Novfs_remove_inode_entry(dir, &name, 0); ++ iLock = novfs_lock_inode_cache(dir); ++ novfs_remove_inode_entry(dir, &name, 0); + if (dentry->d_inode + && !(dentry->d_inode->i_flags & S_DEAD)) { + dentry->d_inode->i_flags |= S_DEAD; +@@ -789,7 +688,7 @@ int verify_dentry(struct dentry *dentry, + retVal = -ENOMEM; + } + if (iLock) { +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + } + dput(parent); + } +@@ -804,67 +703,37 @@ int verify_dentry(struct dentry *dentry, + return (retVal); + } + +-/*++======================================================================*/ +-struct dentry *Novfs_d_lookup(struct dentry *Parent, struct qstr *Name) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- return (d_lookup(Parent, Name)); +-} + +-/*++======================================================================*/ +-int Novfs_d_add(struct dentry *Parent, struct dentry *d, struct inode *i, int a) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static int novfs_d_add(struct dentry *Parent, struct dentry *d, struct inode *i, int a) + { + void *scope; + struct inode_data *id = NULL; + + char *path, *buf; + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(d, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(d, buf, PATH_LENGTH_BUFFER); + if (path) { +- DbgPrint("Novfs_d_add: inode=0x%p ino=%d path %s\n", i, ++ DbgPrint("novfs_d_add: inode=0x%p ino=%d path %s\n", i, + i->i_ino, path); + } + kfree(buf); + } + +- if (Parent && Parent->d_inode && Parent->d_inode->FSPRIVATE) { +- id = (struct inode_data *) Parent->d_inode->FSPRIVATE; ++ if (Parent && Parent->d_inode && Parent->d_inode->i_private) { ++ id = (struct inode_data *) Parent->d_inode->i_private; + } + + if (id && id->Scope) { + scope = id->Scope; + } else { +- scope = Scope_Get_ScopefromPath(d); ++ scope = novfs_get_scope(d); + } + +- ((struct inode_data *) i->FSPRIVATE)->Scope = scope; ++ ((struct inode_data *) i->i_private)->Scope = scope; + +- d->d_time = jiffies + (File_update_timeout * HZ); ++ d->d_time = jiffies + (novfs_update_timeout * HZ); + if (a) { + d_add(d, i); + } else { +@@ -874,29 +743,14 @@ int Novfs_d_add(struct dentry *Parent, s + return (0); + } + +-/*++======================================================================*/ +-int Novfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +-/* +- * Arguments: struct dentry *dentry - pointer to dentry to revalidate. +- * struct nameidata *nd - pointer to nameidata. +- * +- * Returns: zero - dentry is not valid. +- * !zero - valid entry +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) + { + int retCode = 0; + struct inode *dir; + struct inode_data *id; + struct qstr name; + +- DbgPrint("Novfs_d_revalidate: 0x%p %.*s\n" ++ DbgPrint("novfs_d_revalidate: 0x%p %.*s\n" + " d_count: %d\n" + " d_inode: 0x%p\n", + dentry, dentry->d_name.len, dentry->d_name.name, +@@ -908,7 +762,7 @@ int Novfs_d_revalidate(struct dentry *de + if (dentry->d_inode && + dentry->d_parent && + (dir = dentry->d_parent->d_inode) && +- (id = dir->FSPRIVATE)) { ++ (id = dir->i_private)) { + /* + * Check timer to see if in valid time limit + */ +@@ -919,20 +773,20 @@ int Novfs_d_revalidate(struct dentry *de + name.len = dentry->d_name.len; + name.name = dentry->d_name.name; + name.hash = +- Novfs_internal_hash(&dentry->d_name); ++ novfs_internal_hash(&dentry->d_name); + dentry->d_time = 0; + + if (0 == verify_dentry(dentry, 0)) { +- if (Novfs_lock_inode_cache(dir)) { +- if (Novfs_lookup_inode_cache ++ if (novfs_lock_inode_cache(dir)) { ++ if (novfs_lookup_inode_cache + (dir, &name, 0)) { + dentry->d_time = + jiffies + +- (File_update_timeout ++ (novfs_update_timeout + * HZ); + retCode = 1; + } +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + } + } + } else { +@@ -949,26 +803,13 @@ int Novfs_d_revalidate(struct dentry *de + */ + } + +- DbgPrint("Novfs_d_revalidate: return 0x%x %.*s\n", retCode, ++ DbgPrint("novfs_d_revalidate: return 0x%x %.*s\n", retCode, + dentry->d_name.len, dentry->d_name.name); + + return (retCode); + } + +-/*++======================================================================*/ +-unsigned long Novfs_internal_hash(struct qstr *name) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++static unsigned long novfs_internal_hash(struct qstr *name) + { + unsigned long hash = 0; + unsigned int len = name->len; +@@ -984,48 +825,22 @@ unsigned long Novfs_internal_hash(struct + return (hash); + } + +-/*++======================================================================*/ +-int Novfs_d_hash(struct dentry *dentry, struct qstr *name) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_d_hash(struct dentry *dentry, struct qstr *name) + { +- DbgPrint("Novfs_d_hash: %.*s\n", name->len, name->name); ++ DbgPrint("novfs_d_hash: %.*s\n", name->len, name->name); + +- name->hash = Novfs_internal_hash(name); ++ name->hash = novfs_internal_hash(name); + + return (0); + } + +-/*++======================================================================*/ +-int Novfs_d_strcmp(struct qstr *s1, struct qstr *s2) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_d_strcmp(struct qstr *s1, struct qstr *s2) + { + int retCode = 1; + unsigned char *str1, *str2; + unsigned int len; + +- DbgPrint("Novfs_d_strcmp: s1=%.*s s2=%.*s\n", s1->len, s1->name, ++ DbgPrint("novfs_d_strcmp: s1=%.*s s2=%.*s\n", s1->len, s1->name, + s2->len, s2->name); + + if (s1->len && (s1->len == s2->len) && (s1->hash == s2->hash)) { +@@ -1042,51 +857,25 @@ int Novfs_d_strcmp(struct qstr *s1, stru + } + } + +- DbgPrint("Novfs_d_strcmp: retCode=0x%x\n", retCode); ++ DbgPrint("novfs_d_strcmp: retCode=0x%x\n", retCode); + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_d_compare(struct dentry *parent, struct qstr *s1, struct qstr *s2) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_d_compare(struct dentry *parent, struct qstr *s1, struct qstr *s2) + { + int retCode; + +- retCode = Novfs_d_strcmp(s1, s2); ++ retCode = novfs_d_strcmp(s1, s2); + +- DbgPrint("Novfs_d_compare: retCode=0x%x\n", retCode); ++ DbgPrint("novfs_d_compare: retCode=0x%x\n", retCode); + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_d_delete(struct dentry *dentry) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_d_delete(struct dentry *dentry) + { + int retVal = 0; + +- DbgPrint("Novfs_d_delete: 0x%p %.*s\n" ++ DbgPrint("novfs_d_delete: 0x%p %.*s\n" + " d_count: %d\n" + " d_inode: 0x%p\n", + dentry, dentry->d_name.len, dentry->d_name.name, +@@ -1101,42 +890,16 @@ int Novfs_d_delete(struct dentry *dentry + return (retVal); + } + +-/*++======================================================================*/ +-void Novfs_d_release(struct dentry *dentry) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++void novfs_d_release(struct dentry *dentry) + { +- DbgPrint("Novfs_d_release: 0x%p %.*s\n", dentry, dentry->d_name.len, ++ DbgPrint("novfs_d_release: 0x%p %.*s\n", dentry, dentry->d_name.len, + dentry->d_name.name); + } + +-/*++======================================================================*/ +-void Novfs_d_iput(struct dentry *dentry, struct inode *inode) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++void novfs_d_iput(struct dentry *dentry, struct inode *inode) + { + DbgPrint +- ("Novfs_d_iput: Inode=0x%p Ino=%d Dentry=0x%p i_state=%d Name=%.*s\n", ++ ("novfs_d_iput: Inode=0x%p Ino=%d Dentry=0x%p i_state=%d Name=%.*s\n", + inode, inode->i_ino, dentry, inode->i_state, dentry->d_name.len, + dentry->d_name.name); + +@@ -1144,37 +907,24 @@ void Novfs_d_iput(struct dentry *dentry, + + } + +-/*++======================================================================*/ +-int Novfs_dir_open(struct inode *dir, struct file *file) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_dir_open(struct inode *dir, struct file *file) + { + char *path, *buf; +- FilePrivate2 *file_private = NULL; ++ struct file_private *file_private = NULL; + +- DbgPrint("Novfs_dir_open: Inode 0x%p %d Name %.*s\n", dir, dir->i_ino, ++ DbgPrint("novfs_dir_open: Inode 0x%p %d Name %.*s\n", dir, dir->i_ino, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); + if (path) { +- DbgPrint("Novfs_dir_open: path %s\n", path); ++ DbgPrint("novfs_dir_open: path %s\n", path); + } + kfree(buf); + } + +- file_private = Novfs_Malloc(sizeof(FilePrivate2), GFP_KERNEL); ++ file_private = kmalloc(sizeof(struct file_private), GFP_KERNEL); + file_private->listedall = 0; + file_private->enumHandle = NULL; + +@@ -1183,25 +933,12 @@ int Novfs_dir_open(struct inode *dir, st + return (0); + } + +-/*++======================================================================*/ +-int Novfs_dir_release(struct inode *dir, struct file *file) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_dir_release(struct inode *dir, struct file *file) + { +- FilePrivate2 *file_private; +- file_private = (FilePrivate2 *) file->private_data; ++ struct file_private *file_private; ++ file_private = (struct file_private *) file->private_data; + +- DbgPrint("Novfs_dir_release: Inode 0x%p %d Name %.*s\n", dir, ++ DbgPrint("novfs_dir_release: Inode 0x%p %d Name %.*s\n", dir, + dir->i_ino, file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + +@@ -1213,24 +950,11 @@ int Novfs_dir_release(struct inode *dir, + return (0); + } + +-/*++======================================================================*/ +-loff_t Novfs_dir_lseek(struct file * file, loff_t offset, int origin) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++loff_t novfs_dir_lseek(struct file * file, loff_t offset, int origin) + { +- FilePrivate2 *file_private = NULL; ++ struct file_private *file_private = NULL; + +- DbgPrint("Novfs_dir_lseek: offset %lld %d Name %.*s\n", offset, origin, ++ DbgPrint("novfs_dir_lseek: offset %lld %d Name %.*s\n", offset, origin, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + //printk("<1> seekdir file = %.*s offset = %i\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name, (int)offset); + +@@ -1240,7 +964,7 @@ loff_t Novfs_dir_lseek(struct file * fil + + file->f_pos = 0; + +- file_private = (FilePrivate2 *) file->private_data; ++ file_private = (struct file_private *) file->private_data; + file_private->listedall = 0; + file_private->enumHandle = NULL; + +@@ -1248,25 +972,12 @@ loff_t Novfs_dir_lseek(struct file * fil + //return(default_llseek(file, offset, origin)); + } + +-/*++======================================================================*/ +-ssize_t Novfs_dir_read(struct file * file, char *buf, size_t len, loff_t * off) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++ssize_t novfs_dir_read(struct file * file, char *buf, size_t len, loff_t * off) + { + /* + int rlen = 0; + +- DbgPrint("Novfs_dir_readdir: dentry path %.*s buf=0x%p len=%d off=%lld\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name, buf, len, *off); ++ DbgPrint("novfs_dir_readdir: dentry path %.*s buf=0x%p len=%d off=%lld\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name, buf, len, *off); + + if (0 == *off) + { +@@ -1276,19 +987,19 @@ ssize_t Novfs_dir_read(struct file * fil + } + return(rlen); + */ +- DbgPrint("Novfs_dir_read: %lld %d Name %.*s\n", *off, len, ++ DbgPrint("novfs_dir_read: %lld %d Name %.*s\n", *off, len, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + return (generic_read_dir(file, buf, len, off)); + } + +-static void Novfs_Dump_Info(struct entry_info *info) ++static void novfs_Dump_Info(struct novfs_entry_info *info) + { + char atime_buf[32], mtime_buf[32], ctime_buf[32]; + char namebuf[512]; + int len = 0; + + if (info == NULL) { +- DbgPrint("Novfs_dir_readdir : Dump_Info info == NULL\n"); ++ DbgPrint("novfs_dir_readdir : Dump_Info info == NULL\n"); + return; + } + +@@ -1304,42 +1015,29 @@ static void Novfs_Dump_Info(struct entry + ctime_r(&info->atime.tv_sec, atime_buf); + ctime_r(&info->mtime.tv_sec, mtime_buf); + ctime_r(&info->ctime.tv_sec, ctime_buf); +- DbgPrint("Novfs_dir_readdir : type = %i\n", info->type); +- DbgPrint("Novfs_dir_readdir : mode = %x\n", info->mode); +- DbgPrint("Novfs_dir_readdir : uid = %d\n", info->uid); +- DbgPrint("Novfs_dir_readdir : gid = %d\n", info->gid); +- DbgPrint("Novfs_dir_readdir : size = %i\n", info->size); +- DbgPrint("Novfs_dir_readdir : atime = %s\n", atime_buf); +- DbgPrint("Novfs_dir_readdir : mtime = %s\n", mtime_buf); +- DbgPrint("Novfs_dir_readdir : ctime = %s\n", ctime_buf); +- DbgPrint("Novfs_dir_readdir : namelength = %i\n", info->namelength); +- DbgPrint("Novfs_dir_readdir : name = %s\n", namebuf); ++ DbgPrint("novfs_dir_readdir : type = %i\n", info->type); ++ DbgPrint("novfs_dir_readdir : mode = %x\n", info->mode); ++ DbgPrint("novfs_dir_readdir : uid = %d\n", info->uid); ++ DbgPrint("novfs_dir_readdir : gid = %d\n", info->gid); ++ DbgPrint("novfs_dir_readdir : size = %i\n", info->size); ++ DbgPrint("novfs_dir_readdir : atime = %s\n", atime_buf); ++ DbgPrint("novfs_dir_readdir : mtime = %s\n", mtime_buf); ++ DbgPrint("novfs_dir_readdir : ctime = %s\n", ctime_buf); ++ DbgPrint("novfs_dir_readdir : namelength = %i\n", info->namelength); ++ DbgPrint("novfs_dir_readdir : name = %s\n", namebuf); + } + +-/*++======================================================================*/ + void processList(struct file *file, void *dirent, filldir_t filldir, char *list, +- int type, session_t SessionId) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++ int type, struct novfs_schandle SessionId) + { + unsigned char *path, *buf = NULL, *cp; + struct qstr name; +- struct entry_info *pinfo = NULL; ++ struct novfs_entry_info *pinfo = NULL; + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + path = buf; + if (buf) { +- path = Novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + strcpy(buf, path); + } +@@ -1351,14 +1049,14 @@ void processList(struct file *file, void + cp = list; + while (*cp) { + name.name = cp; +- DbgPrint("Novfs_dir_readdir : name.name = %s\n", ++ DbgPrint("novfs_dir_readdir : name.name = %s\n", + name.name); + name.len = strlen(cp); +- name.hash = Novfs_internal_hash(&name); ++ name.hash = novfs_internal_hash(&name); + cp += (name.len + 1); + + pinfo = +- Novfs_Malloc(sizeof(struct entry_info) + ++ kmalloc(sizeof(struct novfs_entry_info) + + PATH_LENGTH_BUFFER, GFP_KERNEL); + pinfo->mode = S_IFDIR | 0700; + pinfo->size = 0; +@@ -1367,7 +1065,7 @@ void processList(struct file *file, void + strcpy(pinfo->name, name.name); + pinfo->namelength = name.len; + +- Novfs_Dump_Info(pinfo); ++ novfs_Dump_Info(pinfo); + + filldir(dirent, pinfo->name, pinfo->namelength, + file->f_pos, file->f_pos, pinfo->mode >> 12); +@@ -1383,26 +1081,28 @@ void processList(struct file *file, void + } + + int processEntries(struct file *file, void *dirent, filldir_t filldir, +- HANDLE * enumHandle, session_t sessionId) ++ void ** enumHandle, struct novfs_schandle sessionId) + { + unsigned char *path = NULL, *buf = NULL; + int count = 0, status = 0; +- struct entry_info *pinfo = NULL; +- struct entry_info *pInfoMem = NULL; ++ struct novfs_entry_info *pinfo = NULL; ++ struct novfs_entry_info *pInfoMem = NULL; + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (!buf) { + return -ENOMEM; + } + +- path = Novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); + if (!path) { + kfree(buf); + return -ENOMEM; + } + //NWSearchfiles + count = 0; +- status = Novfs_Get_Directory_ListEx(path, enumHandle, &count, &pinfo, &sessionId); ++ status = ++ novfs_get_dir_listex(path, enumHandle, &count, &pinfo, ++ sessionId); + pInfoMem = pinfo; + + if ((count == -1) || (count == 0) || (status != 0)) { +@@ -1416,7 +1116,7 @@ int processEntries(struct file *file, vo + file->f_pos, pinfo->mode >> 12); + file->f_pos += 1; + +- pinfo = (struct entry_info *)(pinfo->name + pinfo->namelength); ++ pinfo = (struct novfs_entry_info *) (pinfo->name + pinfo->namelength); + } + + kfree(pInfoMem); +@@ -1424,32 +1124,19 @@ int processEntries(struct file *file, vo + return 0; + } + +-/*++======================================================================*/ +-int Novfs_dir_readdir(struct file *file, void *dirent, filldir_t filldir) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_dir_readdir(struct file *file, void *dirent, filldir_t filldir) + { + unsigned char *list = NULL; + int status = 0; //-ENOMEM; + struct inode *inode = file->f_dentry->d_inode; +- session_t sessionId; ++ struct novfs_schandle sessionId; + uid_t uid; + int type = 0; +- FilePrivate2 *file_private = NULL; ++ struct file_private *file_private = NULL; + int lComm; + +- file_private = (FilePrivate2 *) file->private_data; +- DbgPrint("Novfs_dir_readdir: Name %.*s\n", file->f_dentry->d_name.len, ++ file_private = (struct file_private *) file->private_data; ++ DbgPrint("novfs_dir_readdir: Name %.*s\n", file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + + //printk("<1> file = %.*s\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name); +@@ -1510,16 +1197,18 @@ int Novfs_dir_readdir(struct file *file, + } + + inode = file->f_dentry->d_inode; +- if (inode && inode->FSPRIVATE) { ++ if (inode && inode->i_private) { + sessionId = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)-> Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> ++ Scope); + if (0 == SC_PRESENT(sessionId)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(file->f_dentry); + sessionId = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + } +- uid = Scope_Get_Uid(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ uid = novfs_scope_get_uid(((struct inode_data *) inode->i_private)->Scope); + } else { + SC_INITIALIZE(sessionId); + uid = current->euid; +@@ -1530,19 +1219,19 @@ int Novfs_dir_readdir(struct file *file, + IS_ROOT(file->f_dentry->d_parent->d_parent)) // Server + { + if (IS_ROOT(file->f_dentry)) { +- DbgPrint("Novfs_dir_readdir: Root directory\n"); +- list = Scope_Get_ScopeUsers(); ++ DbgPrint("novfs_dir_readdir: Root directory\n"); ++ list = novfs_get_scopeusers(); + type = USER_LIST; + } else if (IS_ROOT(file->f_dentry->d_parent)) { + DbgPrint +- ("Novfs_dir_readdir: Parent is Root directory\n"); +- Novfs_Get_Connected_Server_List(&list, &sessionId); ++ ("novfs_dir_readdir: Parent is Root directory\n"); ++ novfs_get_servers(&list, sessionId); + type = SERVER_LIST; + } else { + DbgPrint +- ("Novfs_dir_readdir: Parent-Parent is Root directory\n"); +- Novfs_Get_Server_Volume_List(&file->f_dentry->d_name, +- &list, &sessionId); ++ ("novfs_dir_readdir: Parent-Parent is Root directory\n"); ++ novfs_get_vols(&file->f_dentry->d_name, ++ &list, sessionId); + type = VOLUME_LIST; + } + +@@ -1580,76 +1269,46 @@ int Novfs_dir_readdir(struct file *file, + return 1; + } + +-/*++======================================================================*/ +-int Novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync) + { +- DbgPrint("Novfs_dir_fsync: Name %.*s\n", file->f_dentry->d_name.len, ++ DbgPrint("novfs_dir_fsync: Name %.*s\n", file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + return (simple_sync_file(file, dentry, datasync)); + } + +-/*++======================================================================*/ +-ssize_t Novfs_f_read(struct file * file, char *buf, size_t len, loff_t * off) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++ssize_t novfs_f_read(struct file * file, char *buf, size_t len, loff_t * off) + { + size_t thisread, totalread = 0; + loff_t offset = *off; + struct inode *inode; +- session_t session; ++ struct novfs_schandle session; + struct inode_data *id; + + if (file->f_dentry && + (inode = file->f_dentry->d_inode) && +- (id = (struct inode_data *)inode->FSPRIVATE)) { ++ (id = (struct inode_data *) inode->i_private)) { + +- DbgPrint("Novfs_f_read(0x%p 0x%p %d %lld %.*s)\n", ++ DbgPrint("novfs_f_read(0x%p 0x%p %d %lld %.*s)\n", + file->private_data, + buf, len, offset, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + +- if (PageCache && !(file->f_flags & O_DIRECT) && id->CacheFlag) { +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +- totalread = generic_file_read(file, buf, len, off); +-#else ++ if (novfs_page_cache && !(file->f_flags & O_DIRECT) && id->CacheFlag) { + totalread = do_sync_read(file, buf, len, off); +-#endif + } else { +- session = Scope_Get_SessionId(id->Scope); ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + while (len > 0 && (offset < i_size_read(inode))) { + int retval; + thisread = len; + retval = +- Novfs_Read_File(file->private_data, buf, ++ novfs_read_file(file->private_data, buf, + &thisread, &offset, + session); + if (retval || !thisread) { +@@ -1658,7 +1317,7 @@ ssize_t Novfs_f_read(struct file * file, + } + break; + } +- DbgPrint("Novfs_f_read thisread = 0x%x\n", ++ DbgPrint("novfs_f_read thisread = 0x%x\n", + thisread); + len -= thisread; + buf += thisread; +@@ -1668,77 +1327,60 @@ ssize_t Novfs_f_read(struct file * file, + *off = offset; + } + } +- DbgPrint("Novfs_f_read return = %d\n", totalread); ++ DbgPrint("novfs_f_read return = %d\n", totalread); + + return (totalread); + } + +-/*++======================================================================*/ +-ssize_t Novfs_f_write(struct file * file, const char *buf, size_t len, ++ssize_t novfs_f_write(struct file * file, const char *buf, size_t len, + loff_t * off) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + ssize_t thiswrite, totalwrite = 0; + loff_t offset = *off; +- session_t session; ++ struct novfs_schandle session; + struct inode *inode; + int status; + struct inode_data *id; + + if (file->f_dentry && + (inode = file->f_dentry->d_inode) && +- (id = file->f_dentry->d_inode->FSPRIVATE)) { +- DbgPrint("Novfs_f_write(0x%p 0x%p 0x%p %d %lld %.*s)\n", ++ (id = file->f_dentry->d_inode->i_private)) { ++ DbgPrint("novfs_f_write(0x%p 0x%p 0x%p %d %lld %.*s)\n", + file->private_data, inode, id->FileHandle, len, offset, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + +- if (PageCache && ++ if (novfs_page_cache && + !(file->f_flags & O_DIRECT) && + id->CacheFlag && !(file->f_flags & O_WRONLY)) { +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +- totalwrite = generic_file_write(file, buf, len, off); +-#else + totalwrite = do_sync_write(file, buf, len, off); +-#endif + } else { + if (file->f_flags & O_APPEND) { + offset = i_size_read(inode); + DbgPrint +- ("Novfs_f_write appending to end %lld %.*s\n", ++ ("novfs_f_write appending to end %lld %.*s\n", + offset, file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + } + +- session = Scope_Get_SessionId(id->Scope); ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + while (len > 0) { + thiswrite = len; + if ((status = +- Novfs_Write_File(file->private_data, ++ novfs_write_file(file->private_data, + (unsigned char *)buf, + &thiswrite, &offset, + session)) || !thiswrite) { + totalwrite = status; + break; + } +- DbgPrint("Novfs_f_write thiswrite = 0x%x\n", ++ DbgPrint("novfs_f_write thiswrite = 0x%x\n", + thiswrite); + len -= thiswrite; + buf += thiswrite; +@@ -1757,69 +1399,43 @@ ssize_t Novfs_f_write(struct file * file + *off = offset; + } + } +- DbgPrint("Novfs_f_write return = 0x%x\n", totalwrite); ++ DbgPrint("novfs_f_write return = 0x%x\n", totalwrite); + + return (totalwrite); + } + +-int Novfs_f_readdir(struct file *file, void *data, filldir_t fill) ++int novfs_f_readdir(struct file *file, void *data, filldir_t fill) + { + return -EISDIR; + } + +-int Novfs_f_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++int novfs_f_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) + { +- DbgPrint("Novfs_f_ioctl: file=0x%p cmd=0x%x arg=0x%p\n", file, cmd, ++ DbgPrint("novfs_f_ioctl: file=0x%p cmd=0x%x arg=0x%p\n", file, cmd, + arg); + + return -ENOSYS; + } + +-/*++======================================================================*/ +-int Novfs_f_mmap(struct file *file, struct vm_area_struct *vma) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_f_mmap(struct file *file, struct vm_area_struct *vma) + { + int retCode = -EINVAL; + +- DbgPrint("Novfs_f_mmap: file=0x%p %.*s\n", file, ++ DbgPrint("novfs_f_mmap: file=0x%p %.*s\n", file, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + + retCode = generic_file_mmap(file, vma); + +- DbgPrint("Novfs_f_mmap: retCode=0x%x\n", retCode); ++ DbgPrint("novfs_f_mmap: retCode=0x%x\n", retCode); + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_f_open(struct inode *inode, struct file *file) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_f_open(struct inode *inode, struct file *file) + { +- struct entry_info *info = NULL; ++ struct novfs_entry_info *info = NULL; + int retCode = -ENOENT; +- session_t session; ++ struct novfs_schandle session; + char *path; + struct dentry *parent; + ino_t ino; +@@ -1827,32 +1443,35 @@ int Novfs_f_open(struct inode *inode, st + int errInfo; + + DbgPrint +- ("Novfs_f_open: inode=0x%p file=0x%p dentry=0x%p dentry->d_inode=0x%p %.*s\n", ++ ("novfs_f_open: inode=0x%p file=0x%p dentry=0x%p dentry->d_inode=0x%p %.*s\n", + inode, file, file->f_dentry, file->f_dentry->d_inode, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + if (file->f_dentry) { + DbgPrint +- ("Novfs_f_open: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", ++ ("novfs_f_open: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", + file->f_dentry->d_name.len, file->f_dentry->d_name.name, + file->f_flags, file->f_mode, inode->i_mode); + } + +- if (inode && inode->FSPRIVATE) { +- id = (struct inode_data *) file->f_dentry->d_inode->FSPRIVATE; +- session = Scope_Get_SessionId(id->Scope); ++ if (inode && inode->i_private) { ++ id = (struct inode_data *) file->f_dentry->d_inode->i_private; ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { +- id->Scope = Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ id->Scope = novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + +- info = Novfs_Malloc(sizeof(struct entry_info) + PATH_LENGTH_BUFFER, GFP_KERNEL); ++ info = kmalloc(sizeof(struct novfs_entry_info) + ++ PATH_LENGTH_BUFFER, GFP_KERNEL); + if (info) { + path = +- Novfs_dget_path(file->f_dentry, info->name, ++ novfs_dget_path(file->f_dentry, info->name, + PATH_LENGTH_BUFFER); + if (path) { + if (file->f_flags & O_TRUNC) { +- errInfo = Novfs_Get_File_Info(path, info, &session); ++ errInfo = ++ novfs_get_file_info(path, info, ++ session); + + if (errInfo || info->size == 0) { + // clear O_TRUNC flag, bug #275366 +@@ -1861,15 +1480,15 @@ int Novfs_f_open(struct inode *inode, st + } + } + +- DbgPrint("Novfs_f_open: %s\n", path); +- retCode = Novfs_Open_File(path, ++ DbgPrint("novfs_f_open: %s\n", path); ++ retCode = novfs_open_file(path, + file-> + f_flags & ~O_EXCL, + info, + &file->private_data, + session); + +- DbgPrint("Novfs_f_open: 0x%x 0x%p\n", retCode, ++ DbgPrint("novfs_f_open: 0x%x 0x%p\n", retCode, + file->private_data); + if (!retCode) { + /* +@@ -1877,28 +1496,31 @@ int Novfs_f_open(struct inode *inode, st + */ + //id->FileHandle = file->private_data; + id->CacheFlag = +- Novfs_Get_File_Cache_Flag(path, ++ novfs_get_file_cache_flag(path, + session); + +- if (!Novfs_Get_File_Info(path, info, &session)) ++ if (!novfs_get_file_info ++ (path, info, session)) { + update_inode(inode, info); ++ } + + parent = dget_parent(file->f_dentry); + + if (parent && parent->d_inode) { + struct inode *dir = + parent->d_inode; +- Novfs_lock_inode_cache(dir); ++ novfs_lock_inode_cache(dir); + ino = 0; +- if (Novfs_get_entry ++ if (novfs_get_entry + (dir, + &file->f_dentry->d_name, + &ino, info)) { +- ((struct inode_data *)inode->FSPRIVATE)->Flags |= ++ ((struct inode_data *) inode-> ++ i_private)->Flags |= + UPDATE_INODE; + } + +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + } + dput(parent); + } +@@ -1906,25 +1528,12 @@ int Novfs_f_open(struct inode *inode, st + kfree(info); + } + } +- DbgPrint("Novfs_f_open: retCode=0x%x\n", retCode); ++ DbgPrint("novfs_f_open: retCode=0x%x\n", retCode); + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_flush_mapping(HANDLE Handle, struct address_space *mapping, +- session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_flush_mapping(void *Handle, struct address_space *mapping, ++ struct novfs_schandle Session) + { + struct pagevec pagevec; + unsigned nrpages; +@@ -1944,20 +1553,20 @@ int Novfs_flush_mapping(HANDLE Handle, s + struct page *page; + int i; + +- DbgPrint("Novfs_flush_mapping: %u\n", nrpages); ++ DbgPrint("novfs_flush_mapping: %u\n", nrpages); + + done = 0; + for (i = 0; !rc && (i < nrpages); i++) { + page = pagevec.pages[i]; + +- DbgPrint("Novfs_flush_mapping: page 0x%p %lu\n", ++ DbgPrint("novfs_flush_mapping: page 0x%p %lu\n", + page, page->index); + + lock_page(page); + page_cache_get(page); + if (page->mapping == mapping) { + if (clear_page_dirty_for_io(page)) { +- rc = Novfs_Write_Page(Handle, ++ rc = novfs_write_page(Handle, + page, + Session); + if (!rc) { +@@ -1978,61 +1587,44 @@ int Novfs_flush_mapping(HANDLE Handle, s + } + } while (!rc && !done); + +- DbgPrint("Novfs_flush_mapping: return %d\n", rc); ++ DbgPrint("novfs_flush_mapping: return %d\n", rc); + + return (rc); + } + +-/*++======================================================================*/ +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) +-int Novfs_f_flush(struct file *file) +-#else +-int Novfs_f_flush(struct file *file, fl_owner_t ownid) +-#endif +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_f_flush(struct file *file, fl_owner_t ownid) + { + + int rc = 0; + #ifdef FLUSH + struct inode *inode; +- session_t session; ++ struct novfs_schandle session; + struct inode_data *id; + +- DbgPrint("Novfs_f_flush: Called from 0x%p\n", ++ DbgPrint("novfs_f_flush: Called from 0x%p\n", + __builtin_return_address(0)); + if (file->f_dentry && (inode = file->f_dentry->d_inode) +- && (id = file->f_dentry->d_inode->FSPRIVATE)) { ++ && (id = file->f_dentry->d_inode->i_private)) { + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + inode = file->f_dentry->d_inode; + DbgPrint +- ("Novfs_f_flush: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", ++ ("novfs_f_flush: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, file->f_flags, + file->f_mode, inode->i_mode); + +- session = Scope_Get_SessionId(id->Scope); ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + if (inode && + inode->i_mapping && inode->i_mapping->nrpages) { + +- DbgPrint("Novfs_f_flush: %.*s pages=%lu\n", ++ DbgPrint("novfs_f_flush: %.*s pages=%lu\n", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, + inode->i_mapping->nrpages); +@@ -2047,7 +1639,7 @@ int Novfs_f_flush(struct file *file, fl_ + d_inode-> + i_mapping); + } else { +- rc = Novfs_flush_mapping(file-> ++ rc = novfs_flush_mapping(file-> + private_data, + file-> + f_dentry-> +@@ -2062,46 +1654,33 @@ int Novfs_f_flush(struct file *file, fl_ + return (rc); + } + +-/*++======================================================================*/ +-int Novfs_f_release(struct inode *inode, struct file *file) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_f_release(struct inode *inode, struct file *file) + { + int retCode = -EACCES; +- session_t session; ++ struct novfs_schandle session; + struct inode_data *id; + +- DbgPrint("Novfs_f_release: path=%.*s handle=%p\n", ++ DbgPrint("novfs_f_release: path=%.*s handle=%p\n", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, file->private_data); + +- if (inode && (id = inode->FSPRIVATE)) { +- session = Scope_Get_SessionId(id->Scope); ++ if (inode && (id = inode->i_private)) { ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { +- id->Scope = Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ id->Scope = novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + DbgPrint +- ("Novfs_f_release: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", ++ ("novfs_f_release: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, file->f_flags, + file->f_mode, inode->i_mode); + + if (inode->i_mapping && inode->i_mapping->nrpages) { + +- DbgPrint("Novfs_f_release: %.*s pages=%lu\n", ++ DbgPrint("novfs_f_release: %.*s pages=%lu\n", + file->f_dentry->d_name.len, + file->f_dentry->d_name.name, + inode->i_mapping->nrpages); +@@ -2111,7 +1690,7 @@ int Novfs_f_release(struct inode *inode, + filemap_fdatawrite(file->f_dentry-> + d_inode->i_mapping); + } else { +- Novfs_flush_mapping(file->private_data, ++ novfs_flush_mapping(file->private_data, + file->f_dentry-> + d_inode->i_mapping, + session); +@@ -2123,40 +1702,27 @@ int Novfs_f_release(struct inode *inode, + invalidate_remote_inode(file->f_dentry->d_inode); + } + +- retCode = Novfs_Close_File(file->private_data, session); ++ retCode = novfs_close_file(file->private_data, session); + //id->FileHandle = 0; + } + return (retCode); + } + +-int Novfs_f_fsync(struct file *file, struct dentry *dentry, int datasync) ++int novfs_f_fsync(struct file *file, struct dentry *dentry, int datasync) + { + return 0; + } + +-/*++======================================================================*/ +-int Novfs_f_llseek(struct file *file, loff_t offset, int origin) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_f_llseek(struct file *file, loff_t offset, int origin) + { +- DbgPrint("Novfs_f_llseek: File=0x%p Name=%.*s offset=%lld origin=%d\n", ++ DbgPrint("novfs_f_llseek: File=0x%p Name=%.*s offset=%lld origin=%d\n", + file, file->f_dentry->d_name.len, file->f_dentry->d_name.name, + offset, origin); + return (generic_file_llseek(file, offset, origin)); + } + + /*++======================================================================*/ +-int Novfs_f_lock(struct file *file, int cmd, struct file_lock *lock) ++int novfs_f_lock(struct file *file, int cmd, struct file_lock *lock) + /* + * Arguments: + * "file" - pointer to file structure - contains file handle in "file->private_data" +@@ -2179,24 +1745,23 @@ int Novfs_f_lock(struct file *file, int + * but xtier functions in novfsd "NCFsdLockFile" and "NCFsdUnlockFile" + * receive arguments in u64 type. + * +- * Environment: + * + *========================================================================*/ + { + int err_code; + + struct inode *inode; +- session_t session; ++ struct novfs_schandle session; + struct inode_data *id; + loff_t len; + +- DbgPrint("Novfs_f_lock(0x%p): begin in Novfs_f_lock 0x%p\n", ++ DbgPrint("novfs_f_lock(0x%p): begin in novfs_f_lock 0x%p\n", + __builtin_return_address(0), file->private_data); + DbgPrint +- ("Novfs_f_lock: cmd = %d, F_GETLK = %d, F_SETLK = %d, F_SETLKW = %d\n", ++ ("novfs_f_lock: cmd = %d, F_GETLK = %d, F_SETLK = %d, F_SETLKW = %d\n", + cmd, F_GETLK, F_SETLK, F_SETLKW); + DbgPrint +- ("Novfs_f_lock: lock->fl_start = 0x%llX, lock->fl_end = 0x%llX\n", ++ ("novfs_f_lock: lock->fl_start = 0x%llX, lock->fl_end = 0x%llX\n", + lock->fl_start, lock->fl_end); + + err_code = -1; +@@ -2209,17 +1774,17 @@ int Novfs_f_lock(struct file *file, int + + if (file->f_dentry && + (inode = file->f_dentry->d_inode) && +- (id = (struct inode_data *)inode->FSPRIVATE)) { +- DbgPrint("Novfs_f_lock: (0x%p 0x%p %.*s)\n", ++ (id = (struct inode_data *) inode->i_private)) { ++ DbgPrint("novfs_f_lock: (0x%p 0x%p %.*s)\n", + file->private_data, inode, + file->f_dentry->d_name.len, + file->f_dentry->d_name.name); + +- session = Scope_Get_SessionId(id->Scope); ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { + id->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + /* fl_type = F_RDLCK, F_WRLCK, F_UNLCK */ +@@ -2230,7 +1795,7 @@ int Novfs_f_lock(struct file *file, int + #endif + + err_code = +- Novfs_Set_File_Lock(session, ++ novfs_set_file_lock(session, + file->private_data, + lock->fl_type, + lock->fl_start, len); +@@ -2241,7 +1806,7 @@ int Novfs_f_lock(struct file *file, int + case F_SETLKW64: + #endif + err_code = +- Novfs_Set_File_Lock(session, ++ novfs_set_file_lock(session, + file->private_data, + lock->fl_type, + lock->fl_start, len); +@@ -2259,16 +1824,16 @@ int Novfs_f_lock(struct file *file, int + + default: + printk +- ("<1> novfs in Novfs_f_lock, not implemented cmd = %d\n", ++ ("<1> novfs in novfs_f_lock, not implemented cmd = %d\n", + cmd); + DbgPrint +- ("Novfs_f_lock: novfs in Novfs_f_lock, not implemented cmd = %d\n", ++ ("novfs_f_lock: novfs in novfs_f_lock, not implemented cmd = %d\n", + cmd); + break; + } + } + +- DbgPrint("Novfs_f_lock: lock->fl_type = %u, err_code 0x%X\n", ++ DbgPrint("novfs_f_lock: lock->fl_type = %u, err_code 0x%X\n", + lock->fl_type, err_code); + + if ((err_code != 0) && (err_code != -1) +@@ -2283,21 +1848,9 @@ int Novfs_f_lock(struct file *file, int + } + + /*++======================================================================*/ +-static void Novfs_copy_cache_pages(struct address_space *mapping, ++static void novfs_copy_cache_pages(struct address_space *mapping, + struct list_head *pages, int bytes_read, + char *data, struct pagevec *plru_pvec) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + struct page *page; + char *target; +@@ -2340,30 +1893,17 @@ static void Novfs_copy_cache_pages(struc + return; + } + +-/*++======================================================================*/ +-int Novfs_a_writepage(struct page *page, struct writeback_control *wbc) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_a_writepage(struct page *page, struct writeback_control *wbc) + { + int retCode = -EFAULT; + struct inode *inode = page->mapping->host; +- struct inode_data *id = inode->FSPRIVATE; ++ struct inode_data *id = inode->i_private; + loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); +- session_t session; +- struct data_list dlst[2]; ++ struct novfs_schandle session; ++ struct novfs_data_list dlst[2]; + size_t len = PAGE_CACHE_SIZE; + +- session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ session = novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)->Scope); + + page_cache_get(page); + +@@ -2384,7 +1924,7 @@ int Novfs_a_writepage(struct page *page, + len = (size_t) (i_size_read(inode) - pos); + } + +- retCode = Novfs_Write_Pages(id->FileHandle, dlst, 2, len, pos, session); ++ retCode = novfs_write_pages(id->FileHandle, dlst, 2, len, pos, session); + if (!retCode) { + SetPageUptodate(page); + } +@@ -2395,32 +1935,18 @@ int Novfs_a_writepage(struct page *page, + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_a_writepages(struct address_space *mapping, ++int novfs_a_writepages(struct address_space *mapping, + struct writeback_control *wbc) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + int retCode = 0; + struct inode *inode = mapping->host; +- session_t session; +- HANDLE fh = 0; ++ struct novfs_schandle session; ++ void *fh = NULL; + struct inode_data *id = NULL; + +- int max_page_lookup = MaxIoSize / PAGE_CACHE_SIZE; ++ int max_page_lookup = novfs_max_iosize / PAGE_CACHE_SIZE; + +- struct data_list *dlist; +- struct data_list *dlptr; ++ struct novfs_data_list *dlist, *dlptr; + struct page **pages; + + int dlist_idx, i = 0; +@@ -2430,31 +1956,32 @@ int Novfs_a_writepages(struct address_sp + + SC_INITIALIZE(session); + DbgPrint +- ("Novfs_a_writepages: inode=0x%p mapping=0x%p wbc=0x%p nr_to_write=%d\n", ++ ("novfs_a_writepages: inode=0x%p mapping=0x%p wbc=0x%p nr_to_write=%d\n", + inode, mapping, wbc, wbc->nr_to_write); + + if (inode) { + DbgPrint(" Inode=0x%p Ino=%d Id=0x%p\n", inode, inode->i_ino, +- inode->FSPRIVATE); ++ inode->i_private); + +- if (NULL != (id = inode->FSPRIVATE)) { ++ if (NULL != (id = inode->i_private)) { + session = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); +- fh = ((struct inode_data *)inode->FSPRIVATE)->FileHandle; ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); ++ fh = ((struct inode_data *) inode->i_private)->FileHandle; + } + } + +- dlist = Novfs_Malloc(sizeof(struct data_list) * max_page_lookup, GFP_KERNEL); ++ dlist = kmalloc(sizeof(struct novfs_data_list) * max_page_lookup, GFP_KERNEL); + pages = +- Novfs_Malloc(sizeof(struct page *) * max_page_lookup, GFP_KERNEL); ++ kmalloc(sizeof(struct page *) * max_page_lookup, GFP_KERNEL); + + if (id) + DbgPrint +- ("Novfs_a_writepages: inode=0x%p fh=0x%p dlist=0x%p pages=0x%p %s\n", ++ ("novfs_a_writepages: inode=0x%p fh=0x%p dlist=0x%p pages=0x%p %s\n", + inode, fh, dlist, pages, id->Name); + else + DbgPrint +- ("Novfs_a_writepages: inode=0x%p fh=0x%p dlist=0x%p pages=0x%p\n", ++ ("novfs_a_writepages: inode=0x%p fh=0x%p dlist=0x%p pages=0x%p\n", + inode, fh, dlist, pages); + + if (dlist && pages) { +@@ -2481,13 +2008,13 @@ int Novfs_a_writepages(struct address_sp + dlist_idx = 0; + dlptr = &dlist[1]; + +- DbgPrint("Novfs_a_writepages1: nr_pages=%d\n", ++ DbgPrint("novfs_a_writepages1: nr_pages=%d\n", + nr_pages); + if (!nr_pages) { + memset(pages, 0, + sizeof(struct page *) * max_page_lookup); + +- AS_TREE_LOCK(&mapping->tree_lock); ++ read_lock_irq(&mapping->tree_lock); + + /* + * Need to ask for one less then max_page_lookup or we +@@ -2503,7 +2030,7 @@ int Novfs_a_writepages(struct address_sp + 1, + PAGECACHE_TAG_DIRTY); + +- DbgPrint("Novfs_a_writepages2: nr_pages=%d\n", ++ DbgPrint("novfs_a_writepages2: nr_pages=%d\n", + nr_pages); + /* + * Check to see if there are dirty pages and there is a valid +@@ -2513,7 +2040,7 @@ int Novfs_a_writepages(struct address_sp + set_bit(AS_EIO, &mapping->flags); + done = 1; + DbgPrint +- ("Novfs_a_writepage: set_bit AS_EIO\n"); ++ ("novfs_a_writepage: set_bit AS_EIO\n"); + break; + } + +@@ -2521,7 +2048,7 @@ int Novfs_a_writepages(struct address_sp + page_cache_get(pages[i]); + } + +- AS_TREE_UNLOCK(&mapping->tree_lock); ++ read_unlock_irq(&mapping->tree_lock); + + if (nr_pages) { + index = pages[nr_pages - 1]->index + 1; +@@ -2561,7 +2088,7 @@ int Novfs_a_writepages(struct address_sp + */ + + DbgPrint +- ("Novfs_a_writepages: pos=0x%llx index=%d page->index=%d next_index=%d\n", ++ ("novfs_a_writepages: pos=0x%llx index=%d page->index=%d next_index=%d\n", + pos, index, page->index, next_index); + + if (page->index != next_index) { +@@ -2588,11 +2115,11 @@ int Novfs_a_writepages(struct address_sp + dlptr[dlist_idx].rwflag = DLREAD; + dlist_idx++; + DbgPrint +- ("Novfs_a_writepages: Add page=0x%p index=0x%lx\n", ++ ("novfs_a_writepages: Add page=0x%p index=0x%lx\n", + page, page->index); + } + +- DbgPrint("Novfs_a_writepages: dlist_idx=%d\n", ++ DbgPrint("novfs_a_writepages: dlist_idx=%d\n", + dlist_idx); + if (dlist_idx) { + tsize = dlist_idx * PAGE_CACHE_SIZE; +@@ -2605,7 +2132,7 @@ int Novfs_a_writepages(struct address_sp + } + + retCode = +- Novfs_Write_Pages(fh, dlist, dlist_idx + 1, ++ novfs_write_pages(fh, dlist, dlist_idx + 1, + tsize, pos, session); + switch (retCode) { + case 0: +@@ -2630,7 +2157,7 @@ int Novfs_a_writepages(struct address_sp + dlptr[dlist_idx - + 1].page); + DbgPrint +- ("Novfs_a_writepages: release page=0x%p index=0x%lx\n", ++ ("novfs_a_writepages: release page=0x%p index=0x%lx\n", + dlptr[dlist_idx - 1].page, + ((struct page *) + dlptr[dlist_idx - +@@ -2649,7 +2176,7 @@ int Novfs_a_writepages(struct address_sp + mapping->writeback_index = index; + + } else { +- DbgPrint("Novfs_a_writepage: set_bit AS_EIO\n"); ++ DbgPrint("novfs_a_writepage: set_bit AS_EIO\n"); + set_bit(AS_EIO, &mapping->flags); + } + if (dlist) +@@ -2657,25 +2184,12 @@ int Novfs_a_writepages(struct address_sp + if (pages) + kfree(pages); + +- DbgPrint("Novfs_a_writepage: retCode=%d\n", retCode); ++ DbgPrint("novfs_a_writepage: retCode=%d\n", retCode); + return (0); + + } + +-/*++======================================================================*/ +-int Novfs_a_readpage(struct file *file, struct page *page) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_a_readpage(struct file *file, struct page *page) + { + int retCode = 0; + void *pbuf; +@@ -2683,10 +2197,10 @@ int Novfs_a_readpage(struct file *file, + struct dentry *dentry = NULL; + loff_t offset; + size_t len; +- session_t session; ++ struct novfs_schandle session; + + SC_INITIALIZE(session); +- DbgPrint("Novfs_a_readpage: File=0x%p Name=%.*s Page=0x%p", file, ++ DbgPrint("novfs_a_readpage: File=0x%p Name=%.*s Page=0x%p", file, + file->f_dentry->d_name.len, file->f_dentry->d_name.name, page); + + dentry = file->f_dentry; +@@ -2702,14 +2216,16 @@ int Novfs_a_readpage(struct file *file, + if (inode) { + DbgPrint(" Inode=0x%p Ino=%d", inode, inode->i_ino); + +- if (inode->FSPRIVATE) { ++ if (inode->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)inode-> +- FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(file->f_dentry); ++ session = ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + } + } + } +@@ -2717,7 +2233,7 @@ int Novfs_a_readpage(struct file *file, + DbgPrint("\n"); + + if (!PageUptodate(page)) { +- struct data_list dlst[2]; ++ struct novfs_data_list dlst[2]; + + offset = page->index << PAGE_CACHE_SHIFT; + len = PAGE_CACHE_SIZE; +@@ -2730,10 +2246,10 @@ int Novfs_a_readpage(struct file *file, + dlst[1].len = PAGE_CACHE_SIZE; + dlst[1].rwflag = DLWRITE; + +- DbgPrint("Novfs_a_readpage: calling= Novfs_Read_Pages %lld\n", ++ DbgPrint("novfs_a_readpage: calling= novfs_Read_Pages %lld\n", + offset); + retCode = +- Novfs_Read_Pages(file->private_data, dlst, 2, &len, &offset, ++ novfs_read_pages(file->private_data, dlst, 2, &len, &offset, + session); + if (len && (len < PAGE_CACHE_SIZE)) { + pbuf = kmap_atomic(page, KM_USER0); +@@ -2746,31 +2262,18 @@ int Novfs_a_readpage(struct file *file, + } + unlock_page(page); + +- DbgPrint("Novfs_a_readpage: retCode=%d\n", retCode); ++ DbgPrint("novfs_a_readpage: retCode=%d\n", retCode); + return (retCode); + + } + +-/*++======================================================================*/ +-int Novfs_a_readpages(struct file *file, struct address_space *mapping, ++int novfs_a_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_lst, unsigned nr_pages) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + int retCode = 0; + struct inode *inode = NULL; + struct dentry *dentry = NULL; +- session_t session; ++ struct novfs_schandle session; + loff_t offset; + size_t len; + +@@ -2781,7 +2284,7 @@ int Novfs_a_readpages(struct file *file, + char *rbuf, done = 0; + SC_INITIALIZE(session); + +- DbgPrint("Novfs_a_readpages: File=0x%p Name=%.*s Pages=%d\n", file, ++ DbgPrint("novfs_a_readpages: File=0x%p Name=%.*s Pages=%d\n", file, + file->f_dentry->d_name.len, file->f_dentry->d_name.name, + nr_pages); + +@@ -2798,21 +2301,21 @@ int Novfs_a_readpages(struct file *file, + if (inode) { + DbgPrint(" Inode=0x%p Ino=%d\n", inode, inode->i_ino); + +- if (inode->FSPRIVATE) { ++ if (inode->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)inode-> +- FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *) inode->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(file->f_dentry); ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(file->f_dentry); + session = +- Scope_Get_SessionId(((struct inode_data *) inode-> +- FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + } + } + } + +- rbuf = (char *)Novfs_Malloc(MaxIoSize, GFP_KERNEL); ++ rbuf = kmalloc(novfs_max_iosize, GFP_KERNEL); + if (rbuf) { + pagevec_init(&lru_pvec, 0); + for (page_idx = 0; page_idx < nr_pages && !done;) { +@@ -2832,7 +2335,7 @@ int Novfs_a_readpages(struct file *file, + */ + list_for_each_entry_reverse(tpage, page_lst, lru) { + if ((next_index != tpage->index) || +- (len >= MaxIoSize - PAGE_SIZE)) { ++ (len >= novfs_max_iosize - PAGE_SIZE)) { + break; + } + len += PAGE_SIZE; +@@ -2840,7 +2343,7 @@ int Novfs_a_readpages(struct file *file, + } + + if (len && !done) { +- struct data_list dllst[2]; ++ struct novfs_data_list dllst[2]; + + dllst[1].page = NULL; + dllst[1].offset = rbuf; +@@ -2848,12 +2351,12 @@ int Novfs_a_readpages(struct file *file, + dllst[1].rwflag = DLWRITE; + + DbgPrint +- ("Novfs_a_readpages: calling Novfs_Read_Pages %lld\n", ++ ("novfs_a_readpages: calling novfs_Read_Pages %lld\n", + offset); +- if (!Novfs_Read_Pages ++ if (!novfs_read_pages + (file->private_data, dllst, 2, &len, + &offset, session)) { +- Novfs_copy_cache_pages(mapping, ++ novfs_copy_cache_pages(mapping, + page_lst, len, + rbuf, &lru_pvec); + page_idx += len >> PAGE_CACHE_SHIFT; +@@ -2886,37 +2389,24 @@ int Novfs_a_readpages(struct file *file, + retCode = -ENOMEM; + } + +- DbgPrint("Novfs_a_readpages: retCode=%d\n", retCode); ++ DbgPrint("novfs_a_readpages: retCode=%d\n", retCode); + return (retCode); + + } + +-/*++======================================================================*/ +-int Novfs_a_prepare_write(struct file *file, struct page *page, unsigned from, ++int novfs_a_prepare_write(struct file *file, struct page *page, unsigned from, + unsigned to) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + int retVal = 0; + loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; + size_t len = PAGE_CACHE_SIZE; +- session_t session; +- struct data_list dllst[2]; ++ struct novfs_schandle session; ++ struct novfs_data_list dllst[2]; + struct inode *inode = file->f_dentry->d_inode; + SC_INITIALIZE(session); + + DbgPrint +- ("Novfs_a_prepare_write: File=0x%p Page=0x%p offset=0x%llx From=%u To=%u filesize=%lld\n", ++ ("novfs_a_prepare_write: File=0x%p Page=0x%p offset=0x%llx From=%u To=%u filesize=%lld\n", + file, page, offset, from, to, + i_size_read(file->f_dentry->d_inode)); + if (!PageUptodate(page)) { +@@ -2935,12 +2425,18 @@ int Novfs_a_prepare_write(struct file *f + * Get session. + */ + if (file->f_dentry && file->f_dentry->d_inode) { +- if (file->f_dentry->d_inode->FSPRIVATE) { ++ if (file->f_dentry->d_inode->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) ++ inode-> ++ i_private)-> ++ Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ ((struct inode_data *) inode-> ++ i_private)->Scope = ++ novfs_get_scope(file->f_dentry); ++ session = ++ novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)->Scope); + } + } + } +@@ -2963,9 +2459,9 @@ int Novfs_a_prepare_write(struct file *f + dllst[1].rwflag = DLWRITE; + + DbgPrint +- ("Novfs_a_prepare_write: calling Novfs_Read_Pages %lld\n", ++ ("novfs_a_prepare_write: calling novfs_Read_Pages %lld\n", + offset); +- Novfs_Read_Pages(file->private_data, dllst, 2, ++ novfs_read_pages(file->private_data, dllst, 2, + &len, &offset, session); + + /* +@@ -2987,50 +2483,37 @@ int Novfs_a_prepare_write(struct file *f + memset(adr + to, 0, PAGE_CACHE_SIZE - to); + kunmap_atomic(adr, KM_USER0); + +- DbgPrint("Novfs_a_prepare_write: memset 0x%p\n", adr); ++ DbgPrint("novfs_a_prepare_write: memset 0x%p\n", adr); + } + flush_dcache_page(page); + SetPageUptodate(page); + } +-// DbgPrint("Novfs_a_prepare_write: return %d\n", retVal); ++// DbgPrint("novfs_a_prepare_write: return %d\n", retVal); + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_a_commit_write(struct file *file, struct page *page, unsigned offset, ++int novfs_a_commit_write(struct file *file, struct page *page, unsigned offset, + unsigned to) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + int retCode = 0; + struct inode *inode = page->mapping->host; + loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; +- session_t session; ++ struct novfs_schandle session; + struct inode_data *id; +- struct data_list dlst[1]; ++ struct novfs_data_list dlst[1]; + size_t len = to - offset; + + SC_INITIALIZE(session); + + DbgPrint +- ("Novfs_a_commit_write: File=0x%p Page=0x%p offset=0x%x To=%u filesize=%lld\n", ++ ("novfs_a_commit_write: File=0x%p Page=0x%p offset=0x%x To=%u filesize=%lld\n", + file, page, offset, to, i_size_read(file->f_dentry->d_inode)); + if (file->f_dentry->d_inode +- && (id = file->f_dentry->d_inode->FSPRIVATE)) { +- session = Scope_Get_SessionId(id->Scope); ++ && (id = file->f_dentry->d_inode->i_private)) { ++ session = novfs_scope_get_sessionId(id->Scope); + if (0 == SC_PRESENT(session)) { +- id->Scope = Scope_Get_ScopefromPath(file->f_dentry); +- session = Scope_Get_SessionId(id->Scope); ++ id->Scope = novfs_get_scope(file->f_dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + + /* +@@ -3055,7 +2538,7 @@ int Novfs_a_commit_write(struct file *fi + dlst[0].rwflag = DLREAD; + + retCode = +- Novfs_Write_Pages(id->FileHandle, dlst, 1, len, pos, ++ novfs_write_pages(id->FileHandle, dlst, 1, len, pos, + session); + + } else { +@@ -3067,51 +2550,32 @@ int Novfs_a_commit_write(struct file *fi + } + + /*++======================================================================*/ +-ssize_t Novfs_a_direct_IO(int rw, struct kiocb * kiocb, ++ssize_t novfs_a_direct_IO(int rw, struct kiocb * kiocb, + const struct iovec * iov, + loff_t offset, unsigned long nr_segs) + /* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: + * + * Notes: This is a dummy function so that we can allow a file +- * to get the direct IO flag set. Novfs_f_read and +- * Novfs_f_write will do the work. Maybe not the best ++ * to get the direct IO flag set. novfs_f_read and ++ * novfs_f_write will do the work. Maybe not the best + * way to do but it was the easiest to implement. + * +- * Environment: +- * + *========================================================================*/ + { + return (-EIO); + } + + /*++======================================================================*/ +-int Novfs_i_create(struct inode *dir, struct dentry *dentry, int mode, ++int novfs_i_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + char *path, *buf; +- struct entry_info info; +- HANDLE handle; +- session_t session; ++ struct novfs_entry_info info; ++ void *handle; ++ struct novfs_schandle session; + int retCode = -EACCES; + +- DbgPrint("Novfs_i_create: mode=0%o flags=0%o %.*s\n", mode, ++ DbgPrint("novfs_i_create: mode=0%o flags=0%o %.*s\n", mode, + nd->NDOPENFLAGS, dentry->d_name.len, dentry->d_name.name); + + if (IS_ROOT(dentry) || /* Root */ +@@ -3122,38 +2586,42 @@ int Novfs_i_create(struct inode *dir, st + } + + if (mode | S_IFREG) { +- if (dir->FSPRIVATE) { ++ if (dir->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)-> ++ novfs_scope_get_sessionId(((struct inode_data *) dir->i_private)-> + Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *) dir->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(dentry); +- session = Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ ((struct inode_data *) dir->i_private)->Scope = ++ novfs_get_scope(dentry); ++ session = ++ novfs_scope_get_sessionId(((struct inode_data *) dir-> ++ i_private)->Scope); + } + +- buf = +- (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, +- GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = +- Novfs_dget_path(dentry, buf, ++ novfs_dget_path(dentry, buf, + PATH_LENGTH_BUFFER); + if (path) { + retCode = +- Novfs_Open_File(path, ++ novfs_open_file(path, + nd-> + NDOPENFLAGS | + O_RDWR, &info, + &handle, session); + if (!retCode && handle) { +- Novfs_Close_File(handle, ++ novfs_close_file(handle, + session); +- if (!Novfs_i_mknod ++ if (!novfs_i_mknod + (dir, dentry, + mode | S_IFREG, 0)) { + if (dentry->d_inode) { +- ((struct inode_data *)dentry->d_inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ ((struct inode_data *) ++ dentry-> ++ d_inode-> ++ i_private)-> ++ Flags |= UPDATE_INODE; + } + } + } +@@ -3165,20 +2633,7 @@ int Novfs_i_create(struct inode *dir, st + return (retCode); + } + +-/*++======================================================================*/ +-void update_inode(struct inode *Inode, struct entry_info *Info) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++void update_inode(struct inode *Inode, struct novfs_entry_info *Info) + { + static char dbuf[128]; + +@@ -3219,35 +2674,24 @@ void update_inode(struct inode *Inode, s + Inode->i_mtime = Info->mtime; + + if (Inode->i_size && Inode->i_sb->s_blocksize) { +- Inode->i_blocks = (unsigned long) (Info->size >> (loff_t) Inode->i_blkbits); ++ Inode->i_blocks = ++ (unsigned long) (Info->size >> (loff_t) Inode->i_blkbits); + Inode->i_bytes = Info->size & (Inode->i_sb->s_blocksize - 1); + +- DbgPrint("update_inode: i_sb->s_blocksize=%d\n", Inode->i_sb->s_blocksize); ++ DbgPrint("update_inode: i_sb->s_blocksize=%d\n", ++ Inode->i_sb->s_blocksize); + DbgPrint("update_inode: i_blkbits=%d\n", Inode->i_blkbits); + DbgPrint("update_inode: i_blocks=%d\n", Inode->i_blocks); + DbgPrint("update_inode: i_bytes=%d\n", Inode->i_bytes); + } + } + +-/*++======================================================================*/ +-struct dentry *Novfs_i_lookup(struct inode *dir, struct dentry *dentry, ++struct dentry *novfs_i_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + struct dentry *retVal = ERR_PTR(-ENOENT); + struct dentry *parent; +- struct entry_info *info = NULL; ++ struct novfs_entry_info *info = NULL; + struct inode_data *id; + struct inode *inode = NULL; + uid_t uid = current->euid; +@@ -3255,49 +2699,49 @@ struct dentry *Novfs_i_lookup(struct ino + struct qstr name; + char *buf; + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + char *path; +- path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + DbgPrint +- ("Novfs_i_lookup: dir 0x%p %d hash %d inode 0x%0p %s\n", ++ ("novfs_i_lookup: dir 0x%p %d hash %d inode 0x%0p %s\n", + dir, dir->i_ino, dentry->d_name.hash, + dentry->d_inode, path); + } + kfree(buf); + } else { + DbgPrint +- ("Novfs_i_lookup: dir 0x%p %d name %.*s hash %d inode 0x%0p\n", ++ ("novfs_i_lookup: dir 0x%p %d name %.*s hash %d inode 0x%0p\n", + dir, dir->i_ino, dentry->d_name.len, dentry->d_name.name, + dentry->d_name.hash, dentry->d_inode); + } + + if ((dentry->d_name.len == 7) + && (0 == strncmp(dentry->d_name.name, " !xover", 7))) { +- dentry->d_op = &Novfs_dentry_operations; ++ dentry->d_op = &novfs_dentry_operations; + igrab(dir); + d_add(dentry, dir); + return NULL; + } + if ((dentry->d_name.len == 7) + && (0 == strncmp(dentry->d_name.name, "z!xover", 7))) { +- dentry->d_op = &Novfs_dentry_operations; ++ dentry->d_op = &novfs_dentry_operations; + igrab(dir); + d_add(dentry, dir); + return NULL; + } + +- if (dir && (id = dir->FSPRIVATE)) { ++ if (dir && (id = dir->i_private)) { + retVal = 0; + if (IS_ROOT(dentry)) { +- DbgPrint("Novfs_i_lookup: Root entry=0x%p\n", +- Novfs_root); +- inode = Novfs_root->d_inode; ++ DbgPrint("novfs_i_lookup: Root entry=0x%p\n", ++ novfs_root); ++ inode = novfs_root->d_inode; + return (0); + } else { + info = +- Novfs_Malloc(sizeof(struct entry_info) + ++ kmalloc(sizeof(struct novfs_entry_info) + + PATH_LENGTH_BUFFER, GFP_KERNEL); + if (info) { + if (NULL == +@@ -3305,10 +2749,10 @@ struct dentry *Novfs_i_lookup(struct ino + ERR_PTR(verify_dentry(dentry, 1)))) { + name.name = dentry->d_name.name; + name.len = dentry->d_name.len; +- name.hash = Novfs_internal_hash(&name); ++ name.hash = novfs_internal_hash(&name); + +- if (Novfs_lock_inode_cache(dir)) { +- if (!Novfs_get_entry ++ if (novfs_lock_inode_cache(dir)) { ++ if (!novfs_get_entry + (dir, &name, &ino, info)) { + inode = + ilookup(dentry-> +@@ -3319,21 +2763,21 @@ struct dentry *Novfs_i_lookup(struct ino + info); + } + } +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + } + + if (!inode && ino) { +- uid = Scope_Get_Uid(id->Scope); +- if (Novfs_lock_inode_cache(dir)) { +- inode = Novfs_get_inode (dentry->d_sb, info->mode, 0, uid, ino, &name); ++ uid = novfs_scope_get_uid(id->Scope); ++ if (novfs_lock_inode_cache(dir)) { ++ inode = novfs_get_inode (dentry->d_sb, info->mode, 0, uid, ino, &name); + if (inode) { +- if (!Novfs_get_entry(dir, &dentry->d_name, &ino, info)) { ++ if (!novfs_get_entry(dir, &dentry->d_name, &ino, info)) { + update_inode + (inode, + info); + } + } +- Novfs_unlock_inode_cache ++ novfs_unlock_inode_cache + (dir); + } + } +@@ -3343,10 +2787,10 @@ struct dentry *Novfs_i_lookup(struct ino + } + + if (!retVal) { +- dentry->d_op = &Novfs_dentry_operations; ++ dentry->d_op = &novfs_dentry_operations; + if (inode) { + parent = dget_parent(dentry); +- Novfs_d_add(dentry->d_parent, dentry, inode, 1); ++ novfs_d_add(dentry->d_parent, dentry, inode, 1); + dput(parent); + } else { + d_add(dentry, inode); +@@ -3357,42 +2801,29 @@ struct dentry *Novfs_i_lookup(struct ino + kfree(info); + + DbgPrint +- ("Novfs_i_lookup: inode=0x%p dentry->d_inode=0x%p return=0x%p\n", ++ ("novfs_i_lookup: inode=0x%p dentry->d_inode=0x%p return=0x%p\n", + dir, dentry->d_inode, retVal); + + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_i_unlink(struct inode *dir, struct dentry *dentry) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_i_unlink(struct inode *dir, struct dentry *dentry) + { + int retCode = -ENOENT; + struct inode *inode; +- session_t session; ++ struct novfs_schandle session; + char *path, *buf; + uint64_t t64; + +- DbgPrint("Novfs_i_unlink: dir=0x%p dir->i_ino=%d %.*s\n", dir, ++ DbgPrint("novfs_i_unlink: dir=0x%p dir->i_ino=%d %.*s\n", dir, + dir->i_ino, dentry->d_name.len, dentry->d_name.name); +- DbgPrint("Novfs_i_unlink: IS_ROOT(dentry)=%d\n", IS_ROOT(dentry)); +- DbgPrint("Novfs_i_unlink: IS_ROOT(dentry->d_parent)=%d\n", ++ DbgPrint("novfs_i_unlink: IS_ROOT(dentry)=%d\n", IS_ROOT(dentry)); ++ DbgPrint("novfs_i_unlink: IS_ROOT(dentry->d_parent)=%d\n", + IS_ROOT(dentry->d_parent)); +- DbgPrint("Novfs_i_unlink: IS_ROOT(dentry->d_parent->d_parent)=%d\n", ++ DbgPrint("novfs_i_unlink: IS_ROOT(dentry->d_parent->d_parent)=%d\n", + IS_ROOT(dentry->d_parent->d_parent)); + DbgPrint +- ("Novfs_i_unlink: IS_ROOT(dentry->d_parent->d_parent->d_parent)=%d\n", ++ ("novfs_i_unlink: IS_ROOT(dentry->d_parent->d_parent->d_parent)=%d\n", + IS_ROOT(dentry->d_parent->d_parent->d_parent)); + + if (IS_ROOT(dentry) || /* Root */ +@@ -3405,44 +2836,46 @@ int Novfs_i_unlink(struct inode *dir, st + inode = dentry->d_inode; + if (inode) { + DbgPrint +- ("Novfs_i_unlink: dir=0x%p dir->i_ino=%d inode=0x%p ino=%d\n", ++ ("novfs_i_unlink: dir=0x%p dir->i_ino=%d inode=0x%p ino=%d\n", + dir, dir->i_ino, inode, inode->i_ino); +- if (inode->FSPRIVATE) { ++ if (inode->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(dentry); +- session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(dentry); ++ session = ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + } + +- buf = +- (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, +- GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = +- Novfs_dget_path(dentry, buf, ++ novfs_dget_path(dentry, buf, + PATH_LENGTH_BUFFER); + if (path) { + DbgPrint +- ("Novfs_i_unlink: path %s mode 0%o\n", ++ ("novfs_i_unlink: path %s mode 0%o\n", + path, inode->i_mode); + if (IS_ROOT(dentry->d_parent->d_parent)) { +- retCode = do_logout(&dentry->d_name, &session); ++ retCode = novfs_daemon_logout(&dentry->d_name, &session); + } else { + retCode = +- Novfs_Delete(path, ++ novfs_delete(path, + S_ISDIR(inode-> + i_mode), + session); + } + if (!retCode || IS_DEADDIR(inode)) { +- Novfs_remove_inode_entry(dir, ++ novfs_remove_inode_entry(dir, + &dentry-> + d_name, + 0); + dentry->d_time = 0; + t64 = 0; +- Scope_Set_UserSpace(&t64, &t64, ++ novfs_scope_set_userspace(&t64, &t64, + &t64, &t64); + retCode = 0; + } +@@ -3452,33 +2885,20 @@ int Novfs_i_unlink(struct inode *dir, st + } + } + +- DbgPrint("Novfs_i_unlink: retCode 0x%x\n", retCode); ++ DbgPrint("novfs_i_unlink: retCode 0x%x\n", retCode); + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_i_mkdir(struct inode *dir, struct dentry *dentry, int mode) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_i_mkdir(struct inode *dir, struct dentry *dentry, int mode) + { + char *path, *buf; +- session_t session; ++ struct novfs_schandle session; + int retCode = 0; + struct inode *inode; +- struct entry_info info; ++ struct novfs_entry_info info; + uid_t uid; + +- DbgPrint("Novfs_i_mkdir: dir=0x%p ino=%d dentry=0x%p %.*s mode=0%lo\n", ++ DbgPrint("novfs_i_mkdir: dir=0x%p ino=%d dentry=0x%p %.*s mode=0%lo\n", + dir, dir->i_ino, dentry, dentry->d_name.len, + dentry->d_name.name, mode); + +@@ -3491,46 +2911,53 @@ int Novfs_i_mkdir(struct inode *dir, str + + mode |= S_IFDIR; + mode &= (S_IFMT | S_IRWXU); +- if (dir->FSPRIVATE) { ++ if (dir->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) dir->i_private)->Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)dir->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(dentry); ++ ((struct inode_data *) dir->i_private)->Scope = ++ novfs_get_scope(dentry); + session = +- Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) dir->i_private)-> ++ Scope); + } + +- uid = Scope_Get_Uid(((struct inode_data *)dir->FSPRIVATE)->Scope); +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ uid = novfs_scope_get_uid(((struct inode_data *) dir->i_private)->Scope); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { +- DbgPrint("Novfs_i_mkdir: path %s\n", path); ++ DbgPrint("novfs_i_mkdir: path %s\n", path); + retCode = +- Novfs_Create(path, S_ISDIR(mode), session); ++ novfs_create(path, S_ISDIR(mode), session); + if (!retCode) { +- retCode = Novfs_Get_File_Info(path, &info, &session); ++ retCode = ++ novfs_get_file_info(path, &info, ++ session); + if (!retCode) { +- retCode = Novfs_i_mknod(dir, dentry, mode, 0); ++ retCode = ++ novfs_i_mknod(dir, dentry, ++ mode, 0); + inode = dentry->d_inode; + if (inode) { + update_inode(inode, + &info); +- ((struct inode_data *)inode->FSPRIVATE)->Flags &= ~UPDATE_INODE; ++ ((struct inode_data *) inode-> ++ i_private)->Flags &= ++ ~UPDATE_INODE; + + dentry->d_time = + jiffies + +- (File_update_timeout ++ (novfs_update_timeout + * HZ); + +- Novfs_lock_inode_cache ++ novfs_lock_inode_cache + (dir); +- if (Novfs_update_entry ++ if (novfs_update_entry + (dir, + &dentry->d_name, 0, + &info)) { +- Novfs_add_inode_entry ++ novfs_add_inode_entry + (dir, + &dentry-> + d_name, +@@ -3538,7 +2965,7 @@ int Novfs_i_mkdir(struct inode *dir, str + i_ino, + &info); + } +- Novfs_unlock_inode_cache ++ novfs_unlock_inode_cache + (dir); + } + +@@ -3551,39 +2978,13 @@ int Novfs_i_mkdir(struct inode *dir, str + + return (retCode); + } +- +-/*++======================================================================*/ +-int Novfs_i_rmdir(struct inode *inode, struct dentry *dentry) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++ ++int novfs_i_rmdir(struct inode *inode, struct dentry *dentry) + { +- return (Novfs_i_unlink(inode, dentry)); ++ return (novfs_i_unlink(inode, dentry)); + } + +-/*++======================================================================*/ +-int Novfs_i_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_i_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) + { + struct inode *inode = NULL; + int retCode = -EACCES; +@@ -3597,44 +2998,44 @@ int Novfs_i_mknod(struct inode *dir, str + return (-EACCES); + } + +- if (((struct inode_data *)dir->FSPRIVATE)) { +- uid = Scope_Get_Uid(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ if (((struct inode_data *) dir->i_private)) { ++ uid = novfs_scope_get_uid(((struct inode_data *) dir->i_private)->Scope); + if (mode & (S_IFREG | S_IFDIR)) { + inode = +- Novfs_get_inode(dir->i_sb, mode, dev, uid, 0, &dentry->d_name); ++ novfs_get_inode(dir->i_sb, mode, dev, uid, 0, &dentry->d_name); + } + } + if (inode) { +- struct entry_info info; ++ struct novfs_entry_info info; + +- dentry->d_op = &Novfs_dentry_operations; ++ dentry->d_op = &novfs_dentry_operations; + parent = dget_parent(dentry); +- Novfs_d_add(parent, dentry, inode, 0); ++ novfs_d_add(parent, dentry, inode, 0); + memset(&info, 0, sizeof(info)); + info.mode = inode->i_mode; +- Novfs_lock_inode_cache(dir); +- Novfs_add_inode_entry(dir, &dentry->d_name, inode->i_ino, ++ novfs_lock_inode_cache(dir); ++ novfs_add_inode_entry(dir, &dentry->d_name, inode->i_ino, + &info); +- Novfs_unlock_inode_cache(dir); ++ novfs_unlock_inode_cache(dir); + + dput(parent); + + retCode = 0; + } +- DbgPrint("Novfs_i_mknod: return 0x%x\n", retCode); ++ DbgPrint("novfs_i_mknod: return 0x%x\n", retCode); + return retCode; + } + +-int Novfs_i_rename(struct inode *odir, struct dentry *od, struct inode *ndir, ++int novfs_i_rename(struct inode *odir, struct dentry *od, struct inode *ndir, + struct dentry *nd) + { + int retCode = -ENOTEMPTY; + char *newpath, *newbuf, *newcon; + char *oldpath, *oldbuf, *oldcon; + struct qstr newname, oldname; +- struct entry_info *info = NULL; ++ struct novfs_entry_info *info = NULL; + int oldlen, newlen; +- session_t session; ++ struct novfs_schandle session; + ino_t ino; + + if (IS_ROOT(od) || /* Root */ +@@ -3644,29 +3045,29 @@ int Novfs_i_rename(struct inode *odir, s + return (-EACCES); + } + +- DbgPrint("Novfs_i_rename: odir=0x%p ino=%d ndir=0x%p ino=%d\n", odir, ++ DbgPrint("novfs_i_rename: odir=0x%p ino=%d ndir=0x%p ino=%d\n", odir, + odir->i_ino, ndir, ndir->i_ino); + +- oldbuf = Novfs_Malloc(PATH_LENGTH_BUFFER * 2, GFP_KERNEL); ++ oldbuf = kmalloc(PATH_LENGTH_BUFFER * 2, GFP_KERNEL); + newbuf = oldbuf + PATH_LENGTH_BUFFER; + if (oldbuf && newbuf) { +- oldpath = Novfs_dget_path(od, oldbuf, PATH_LENGTH_BUFFER); +- newpath = Novfs_dget_path(nd, newbuf, PATH_LENGTH_BUFFER); ++ oldpath = novfs_dget_path(od, oldbuf, PATH_LENGTH_BUFFER); ++ newpath = novfs_dget_path(nd, newbuf, PATH_LENGTH_BUFFER); + if (oldpath && newpath) { + oldlen = PATH_LENGTH_BUFFER - (int)(oldpath - oldbuf); + newlen = PATH_LENGTH_BUFFER - (int)(newpath - newbuf); + + DbgPrint +- ("Novfs_i_rename: od=0x%p od->inode=0x%p od->inode->i_ino=%d %s\n", ++ ("novfs_i_rename: od=0x%p od->inode=0x%p od->inode->i_ino=%d %s\n", + od, od->d_inode, od->d_inode->i_ino, oldpath); + if (nd->d_inode) { + DbgPrint +- ("Novfs_i_rename: nd=0x%p nd->inode=0x%p nd->inode->i_ino=%d %s\n", ++ ("novfs_i_rename: nd=0x%p nd->inode=0x%p nd->inode->i_ino=%d %s\n", + nd, nd->d_inode, nd->d_inode->i_ino, + newpath); + } else { + DbgPrint +- ("Novfs_i_rename: nd=0x%p nd->inode=0x%p %s\n", ++ ("novfs_i_rename: nd=0x%p nd->inode=0x%p %s\n", + nd, nd->d_inode, newpath); + } + +@@ -3675,9 +3076,9 @@ int Novfs_i_rename(struct inode *odir, s + */ + newcon = strchr(newpath + 1, '\\'); + oldcon = strchr(oldpath + 1, '\\'); +- DbgPrint("Novfs_i_rename: newcon=0x%p newpath=0x%p\n", ++ DbgPrint("novfs_i_rename: newcon=0x%p newpath=0x%p\n", + newcon, newpath); +- DbgPrint("Novfs_i_rename: oldcon=0x%p oldpath=0x%p\n", ++ DbgPrint("novfs_i_rename: oldcon=0x%p oldpath=0x%p\n", + oldcon, oldpath); + retCode = -EXDEV; + if (newcon && oldcon +@@ -3685,8 +3086,8 @@ int Novfs_i_rename(struct inode *odir, s + (int)(oldcon - oldpath))) { + newcon = strchr(newcon + 1, '\\'); + oldcon = strchr(oldcon + 1, '\\'); +- DbgPrint("Novfs_i_rename2: newcon=0x%p newpath=0x%p\n", newcon, newpath); +- DbgPrint("Novfs_i_rename2: oldcon=0x%p oldpath=0x%p\n", oldcon, oldpath); ++ DbgPrint("novfs_i_rename2: newcon=0x%p newpath=0x%p\n", newcon, newpath); ++ DbgPrint("novfs_i_rename2: oldcon=0x%p oldpath=0x%p\n", oldcon, oldpath); + if (newcon && oldcon && + ((int)(newcon - newpath) == (int)(oldcon - oldpath))) { + newname.name = newpath; +@@ -3696,43 +3097,58 @@ int Novfs_i_rename(struct inode *odir, s + oldname.name = oldpath; + oldname.len = (int)(oldcon - oldpath); + oldname.hash = 0; +- if (!Novfs_d_strcmp(&newname, &oldname)) { ++ if (!novfs_d_strcmp(&newname, &oldname)) { + + if (od->d_inode +- && od->d_inode->FSPRIVATE) { ++ && od->d_inode->i_private) { + +- if ((nd->d_inode) && +- (nd->d_inode->FSPRIVATE)) { +- session = Scope_Get_SessionId(((struct inode_data *)ndir->FSPRIVATE)->Scope); +- if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)ndir->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(nd); +- session = Scope_Get_SessionId(((struct inode_data *)ndir->FSPRIVATE)->Scope); ++ if (nd->d_inode ++ && nd->d_inode-> ++ i_private) { ++ session = ++ novfs_scope_get_sessionId ++ (((struct inode_data *) ndir->i_private)->Scope); ++ if (0 == ++ SC_PRESENT ++ (session)) { ++ ((struct inode_data *) ndir->i_private)->Scope = novfs_get_scope(nd); ++ session ++ = ++ novfs_scope_get_sessionId ++ (((struct inode_data *) ndir->i_private)->Scope); + } + +- retCode = Novfs_Delete(newpath, S_ISDIR(nd->d_inode->i_mode), session); ++ retCode = ++ novfs_delete ++ (newpath, ++ S_ISDIR ++ (nd-> ++ d_inode-> ++ i_mode), ++ session); + } + +- session = Scope_Get_SessionId(((struct inode_data *) ndir->FSPRIVATE)->Scope); ++ session = novfs_scope_get_sessionId(((struct inode_data *) ndir->i_private)->Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)ndir->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(nd); +- session = Scope_Get_SessionId(((struct inode_data *) ndir->FSPRIVATE)->Scope); ++ ((struct inode_data *)ndir->i_private)->Scope = novfs_get_scope(nd); ++ session = novfs_scope_get_sessionId(((struct inode_data *) ndir->i_private)->Scope); + } +- retCode = Novfs_Rename_File(S_ISDIR(od->d_inode->i_mode), oldpath, oldlen - 1, newpath, newlen - 1, session); ++ retCode = novfs_rename_file(S_ISDIR(od->d_inode->i_mode), oldpath, oldlen - 1, newpath, newlen - 1, session); + + if (!retCode) { +- info = (struct entry_info *) oldbuf; ++ info = (struct novfs_entry_info *) oldbuf; + od->d_time = 0; +- Novfs_remove_inode_entry(odir, &od->d_name, 0); +- Novfs_remove_inode_entry(ndir, &nd->d_name, 0); +- Novfs_Get_File_Info(newpath, info, &session); +- nd->d_time = jiffies + (File_update_timeout * HZ); ++ novfs_remove_inode_entry(odir, &od->d_name, 0); ++ novfs_remove_inode_entry(ndir, &nd->d_name, 0); ++ novfs_get_file_info(newpath, info, session); ++ nd->d_time = jiffies + (novfs_update_timeout * HZ); + + if (od->d_inode && od->d_inode->i_ino) { + ino = od->d_inode-> i_ino; + } else { +- ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ ino = (ino_t)atomic_inc_return(&novfs_Inode_Number); + } +- Novfs_add_inode_entry(ndir, &nd->d_name, ino, info); ++ novfs_add_inode_entry(ndir, &nd->d_name, ino, info); + } + } + } +@@ -3744,44 +3160,12 @@ int Novfs_i_rename(struct inode *odir, s + if (oldbuf) + kfree(oldbuf); + +- DbgPrint("Novfs_i_rename: return %d\n", retCode); ++ DbgPrint("novfs_i_rename: return %d\n", retCode); + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_i_permission(struct inode *inode, int mask) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- int retCode = 0; +- +- return (retCode); +-} + +-/*++======================================================================*/ +-int Novfs_i_setattr(struct dentry *dentry, struct iattr *attr) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_i_setattr(struct dentry *dentry, struct iattr *attr) + { + char *path, *buf; + struct inode *inode = dentry->d_inode; +@@ -3789,7 +3173,7 @@ int Novfs_i_setattr(struct dentry *dentr + char mtime_buf[32]; + char ctime_buf[32]; + unsigned int ia_valid = attr->ia_valid; +- session_t session; ++ struct novfs_schandle session; + int retVal = 0; + struct iattr mattr; + +@@ -3800,20 +3184,21 @@ int Novfs_i_setattr(struct dentry *dentr + return (-EACCES); + } + +- if (inode && inode->FSPRIVATE) { ++ if (inode && inode->i_private) { + session = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> ++ Scope); + if (0 == SC_PRESENT(session)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(dentry); ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(dentry); + session = +- Scope_Get_SessionId(((struct inode_data *) inode-> +- FSPRIVATE)->Scope); ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); + } + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + strcpy(atime_buf, "Unspecified"); + strcpy(mtime_buf, "Unspecified"); +@@ -3831,7 +3216,7 @@ int Novfs_i_setattr(struct dentry *dentr + ctime_buf); + } + /* Removed for Bug 132374. jlt */ +- DbgPrint("Novfs_i_setattr: %s\n" ++ DbgPrint("novfs_i_setattr: %s\n" + " ia_valid: 0x%x\n" + " ia_mode: 0%o\n" + " ia_uid: %d\n" +@@ -3855,19 +3240,28 @@ int Novfs_i_setattr(struct dentry *dentr + ~(ATTR_FILE | ATTR_SIZE); + attr = &mattr; + ia_valid = attr->ia_valid; +-#if 0 // thanks to vfs changes in our tree... +- retVal = Novfs_Truncate_File_Ex(attr->ia_file->private_data, attr->ia_size, session); ++#if 0 // thanks to vfs changes in our tree... ++ retVal = ++ novfs_trunc_ex(attr-> ++ ia_file-> ++ private_data, ++ attr-> ++ ia_size, ++ session); + if (!retVal) { + inode->i_size = attr->ia_size; +- ((struct inode_data *)inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ ((struct inode_data *) inode-> ++ i_private)->Flags |= ++ UPDATE_INODE; + } + #endif + } + + if (ia_valid + && !(retVal = +- Novfs_Set_Attr(path, attr, session))) { +- ((struct inode_data *)inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ novfs_set_attr(path, attr, session))) { ++ ((struct inode_data *) inode->i_private)-> ++ Flags |= UPDATE_INODE; + + if (ia_valid & ATTR_ATIME) + inode->i_atime = attr->ia_atime; +@@ -3886,26 +3280,13 @@ int Novfs_i_setattr(struct dentry *dentr + } + kfree(buf); + } +- DbgPrint("Novfs_i_setattr: return 0x%x\n", retVal); ++ DbgPrint("novfs_i_setattr: return 0x%x\n", retVal); + + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_i_getattr(struct vfsmount *mnt, struct dentry *dentry, ++int novfs_i_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *kstat) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + int retCode = 0; + char atime_buf[32]; +@@ -3913,32 +3294,32 @@ int Novfs_i_getattr(struct vfsmount *mnt + char ctime_buf[32]; + struct inode *inode = dentry->d_inode; + +- struct entry_info info; ++ struct novfs_entry_info info; + char *path, *buf; +- session_t session; ++ struct novfs_schandle session; + struct inode_data *id; + + if (!IS_ROOT(dentry) && !IS_ROOT(dentry->d_parent)) { + SC_INITIALIZE(session); +- id = dentry->d_inode->FSPRIVATE; ++ id = dentry->d_inode->i_private; + + if (id && (id->Flags & UPDATE_INODE)) { +- session = Scope_Get_SessionId(id->Scope); ++ session = novfs_scope_get_sessionId(id->Scope); + + if (0 == SC_PRESENT(session)) { +- id->Scope = Scope_Get_ScopefromPath(dentry); +- session = Scope_Get_SessionId(id->Scope); ++ id->Scope = novfs_get_scope(dentry); ++ session = novfs_scope_get_sessionId(id->Scope); + } + +- buf = +- (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, +- GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + path = +- Novfs_dget_path(dentry, buf, ++ novfs_dget_path(dentry, buf, + PATH_LENGTH_BUFFER); + if (path) { +- retCode = Novfs_Get_File_Info(path, &info, &session); ++ retCode = ++ novfs_get_file_info(path, &info, ++ session); + if (!retCode) { + update_inode(inode, &info); + id->Flags &= ~UPDATE_INODE; +@@ -3969,7 +3350,7 @@ int Novfs_i_getattr(struct vfsmount *mnt + ctime_r(&kstat->mtime.tv_sec, mtime_buf); + ctime_r(&kstat->ctime.tv_sec, ctime_buf); + +- DbgPrint("Novfs_i_getattr: 0x%x 0x%p <%.*s>\n" ++ DbgPrint("novfs_i_getattr: 0x%x 0x%p <%.*s>\n" + " ino: %d\n" + " dev: 0x%x\n" + " mode: 0%o\n" +@@ -3997,24 +3378,11 @@ int Novfs_i_getattr(struct vfsmount *mnt + return (retCode); + } + +-/*++======================================================================*/ +-int Novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, ++int novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, + size_t buffer_size) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + struct inode *inode = dentry->d_inode; +- session_t sessionId; ++ struct novfs_schandle sessionId; + char *path, *buf, *bufRead; + ssize_t dataLen; + +@@ -4022,44 +3390,53 @@ int Novfs_i_getxattr(struct dentry *dent + + SC_INITIALIZE(sessionId); + +- DbgPrint("Novfs_i_getxattr: Ian\n"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ ++ DbgPrint("novfs_i_getxattr: Ian\n"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ + DbgPrint +- ("Novfs_i_getxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", ++ ("novfs_i_getxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", + dentry->d_name.len, dentry->d_name.name); +- DbgPrint("Novfs_i_getxattr: name %s\n", name); +- DbgPrint("Novfs_i_getxattr: size %u\n", buffer_size); ++ DbgPrint("novfs_i_getxattr: name %s\n", name); ++ DbgPrint("novfs_i_getxattr: size %u\n", buffer_size); + +- if (inode && inode->FSPRIVATE) { ++ if (inode && inode->i_private) { + sessionId = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); +- DbgPrint("Novfs_i_getxattr: SessionId = %u\n", sessionId); ++ novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> ++ Scope); ++ DbgPrint("novfs_i_getxattr: SessionId = %u\n", sessionId); + //if (0 == sessionId) + if (0 == SC_PRESENT(sessionId)) { +- ((struct inode_data *) inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(dentry); +- sessionId = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); +- DbgPrint("Novfs_i_getxattr: SessionId = %u\n", ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(dentry); ++ sessionId = ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); ++ DbgPrint("novfs_i_getxattr: SessionId = %u\n", + sessionId); + } + } + + dataLen = 0; +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { +- bufRead = (char *)Novfs_Malloc(XA_BUFFER, GFP_KERNEL); ++ bufRead = kmalloc(XA_BUFFER, GFP_KERNEL); + if (bufRead) { +- retxcode = Novfs_GetX_File_Info(path, name, bufRead, XA_BUFFER, &dataLen, &sessionId); +- DbgPrint("Novfs_i_getxattr: after Novfs_GetX_File_Info retxcode = %d\n", retxcode); ++ retxcode = ++ novfs_getx_file_info(path, name, bufRead, ++ XA_BUFFER, &dataLen, ++ sessionId); ++ DbgPrint ++ ("novfs_i_getxattr: after novfs_GetX_File_Info retxcode = %d\n", ++ retxcode); + if (!retxcode) { +- mydump(64, bufRead); ++ novfs_dump(64, bufRead); + if (buffer_size != 0) { + if (buffer_size >= dataLen) { + memcpy(buffer, bufRead, + dataLen); + } else { + DbgPrint +- ("Novfs_i_getxattr: (!!!) not enough buffer_size. buffer_size = %d, dataLen = %d\n", ++ ("novfs_i_getxattr: (!!!) not enough buffer_size. buffer_size = %d, dataLen = %d\n", + buffer_size, + dataLen); + retxcode = -ERANGE; +@@ -4086,25 +3463,12 @@ int Novfs_i_getxattr(struct dentry *dent + return (dataLen); + } + +-/*++======================================================================*/ +-int Novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, ++int novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t value_size, int flags) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ + { + + struct inode *inode = dentry->d_inode; +- session_t sessionId; ++ struct novfs_schandle sessionId; + char *path, *buf; + unsigned long bytesWritten = 0; + int retError = 0; +@@ -4112,42 +3476,42 @@ int Novfs_i_setxattr(struct dentry *dent + + SC_INITIALIZE(sessionId); + +- DbgPrint("Novfs_i_setxattr: Ian\n"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ ++ DbgPrint("novfs_i_setxattr: Ian\n"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ + DbgPrint +- ("Novfs_i_setxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", ++ ("novfs_i_setxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", + dentry->d_name.len, dentry->d_name.name); +- DbgPrint("Novfs_i_setxattr: name %s\n", name); +- DbgPrint("Novfs_i_setxattr: value_size %u\n", value_size); +- DbgPrint("Novfs_i_setxattr: flags %d\n", flags); ++ DbgPrint("novfs_i_setxattr: name %s\n", name); ++ DbgPrint("novfs_i_setxattr: value_size %u\n", value_size); ++ DbgPrint("novfs_i_setxattr: flags %d\n", flags); + +- if (inode && inode->FSPRIVATE) { ++ if (inode && inode->i_private) { + sessionId = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)-> ++ novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> + Scope); +- DbgPrint("Novfs_i_setxattr: SessionId = %u\n", sessionId); ++ DbgPrint("novfs_i_setxattr: SessionId = %u\n", sessionId); + //if (0 == sessionId) + if (0 == SC_PRESENT(sessionId)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = +- Scope_Get_ScopefromPath(dentry); ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(dentry); + sessionId = +- Scope_Get_SessionId(((struct inode_data *)inode-> +- FSPRIVATE)->Scope); +- DbgPrint("Novfs_i_setxattr: SessionId = %u\n", ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); ++ DbgPrint("novfs_i_setxattr: SessionId = %u\n", + sessionId); + } + } + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { + retxcode = +- Novfs_SetX_File_Info(path, name, value, value_size, ++ novfs_setx_file_info(path, name, value, value_size, + &bytesWritten, flags, +- &sessionId); ++ sessionId); + if (!retxcode) { + DbgPrint +- ("Novfs_i_setxattr: bytesWritten = %u\n", ++ ("novfs_i_setxattr: bytesWritten = %u\n", + bytesWritten); + } + } +@@ -4164,53 +3528,59 @@ int Novfs_i_setxattr(struct dentry *dent + return (retError); + } + +-int Novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) ++int novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) + { + struct inode *inode = dentry->d_inode; +- session_t sessionId; ++ struct novfs_schandle sessionId; + char *path, *buf, *bufList; + ssize_t dataLen; +- + int retxcode = 0; + + SC_INITIALIZE(sessionId); + +- DbgPrint("Novfs_i_listxattr: Ian\n"); //%.*s\n", dentry->d_name.len, dentry->d_name.name); ++ DbgPrint("novfs_i_listxattr: Ian\n"); //%.*s\n", dentry->d_name.len, dentry->d_name.name); + DbgPrint +- ("Novfs_i_listxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", ++ ("novfs_i_listxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", + dentry->d_name.len, dentry->d_name.name); +- DbgPrint("Novfs_i_listxattr: size %u\n", buffer_size); ++ DbgPrint("novfs_i_listxattr: size %u\n", buffer_size); + +- if (inode && inode->FSPRIVATE) { ++ if (inode && inode->i_private) { + sessionId = +- Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)-> Scope); +- DbgPrint("Novfs_i_listxattr: SessionId = %u\n", sessionId); ++ novfs_scope_get_sessionId(((struct inode_data *) inode->i_private)-> ++ Scope); ++ DbgPrint("novfs_i_listxattr: SessionId = %u\n", sessionId); + //if (0 == sessionId) + if (0 == SC_PRESENT(sessionId)) { +- ((struct inode_data *)inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(dentry); +- sessionId = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); +- DbgPrint("Novfs_i_listxattr: SessionId = %u\n", ++ ((struct inode_data *) inode->i_private)->Scope = ++ novfs_get_scope(dentry); ++ sessionId = ++ novfs_scope_get_sessionId(((struct inode_data *) inode-> ++ i_private)->Scope); ++ DbgPrint("novfs_i_listxattr: SessionId = %u\n", + sessionId); + } + } + + dataLen = 0; +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ path = novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); + if (path) { +- bufList = (char *)Novfs_Malloc(XA_BUFFER, GFP_KERNEL); ++ bufList = kmalloc(XA_BUFFER, GFP_KERNEL); + if (bufList) { +- retxcode = Novfs_ListX_File_Info(path, bufList, XA_BUFFER, &dataLen, &sessionId); ++ retxcode = ++ novfs_listx_file_info(path, bufList, ++ XA_BUFFER, &dataLen, ++ sessionId); + +- mydump(64, bufList); ++ novfs_dump(64, bufList); + if (buffer_size != 0) { + if (buffer_size >= dataLen) { + memcpy(buffer, bufList, + dataLen); + } else { + DbgPrint +- ("Novfs_i_listxattr: (!!!) not enough buffer_size. buffer_size = %d, dataLen = %d\n", ++ ("novfs_i_listxattr: (!!!) not enough buffer_size. buffer_size = %d, dataLen = %d\n", + buffer_size, dataLen); + retxcode = -1; + } +@@ -4236,120 +3606,92 @@ int Novfs_i_listxattr(struct dentry *den + return (dataLen); + } + +-int Novfs_i_revalidate(struct dentry *dentry) ++int novfs_i_revalidate(struct dentry *dentry) + { + +- DbgPrint("Novfs_i_revalidate: name %.*s\n", dentry->d_name.len, ++ DbgPrint("novfs_i_revalidate: name %.*s\n", dentry->d_name.len, + dentry->d_name.name); + + return (0); + } + +-void Novfs_read_inode(struct inode *inode) ++void novfs_read_inode(struct inode *inode) + { +- DbgPrint("Novfs_read_inode: 0x%p %d\n", inode, inode->i_ino); ++ DbgPrint("novfs_read_inode: 0x%p %d\n", inode, inode->i_ino); + } + +-void Novfs_write_inode(struct inode *inode) ++void novfs_write_inode(struct inode *inode) + { +- DbgPrint("Novfs_write_inode: Inode=0x%p Ino=%d\n", inode, inode->i_ino); ++ DbgPrint("novfs_write_inode: Inode=0x%p Ino=%d\n", inode, inode->i_ino); + } + +-int Novfs_notify_change(struct dentry *dentry, struct iattr *attr) ++int novfs_notify_change(struct dentry *dentry, struct iattr *attr) + { + struct inode *inode = dentry->d_inode; + + DbgPrint +- ("Novfs_notify_change: Dentry=0x%p Name=%.*s Inode=0x%p Ino=%d ia_valid=0x%x\n", ++ ("novfs_notify_change: Dentry=0x%p Name=%.*s Inode=0x%p Ino=%d ia_valid=0x%x\n", + dentry, dentry->d_name.len, dentry->d_name.name, inode, + inode->i_ino, attr->ia_valid); + return (0); + } + +-/*++======================================================================*/ +-void Novfs_clear_inode(struct inode *inode) +-/* +- * Arguments: sb - pointer to the super_block +- * buf - pointer to the statfs buffer +- * +- * Returns: 0 +- * +- * Abstract: Called when statfs(2) system called. +- * +- * Notes: +- * +- * Environment: Superblock operation +- * +- *========================================================================*/ ++void novfs_clear_inode(struct inode *inode) + { + InodeCount--; + +- if (inode->FSPRIVATE) { +- struct inode_data *id = inode->FSPRIVATE; ++ if (inode->i_private) { ++ struct inode_data *id = inode->i_private; + + DbgPrint +- ("Novfs_clear_inode: inode=0x%p ino=%d Scope=0x%p Name=%s\n", ++ ("novfs_clear_inode: inode=0x%p ino=%d Scope=0x%p Name=%s\n", + inode, inode->i_ino, id->Scope, id->Name); + +- Novfs_free_inode_cache(inode); ++ novfs_free_inode_cache(inode); + + down(&InodeList_lock); + list_del(&id->IList); + up(&InodeList_lock); + +- kfree(inode->FSPRIVATE); +- inode->FSPRIVATE = NULL; ++ kfree(inode->i_private); ++ inode->i_private = NULL; + + remove_inode_hash(inode); + + } else { +- DbgPrint("Novfs_clear_inode: inode=0x%p ino=%d\n", inode, ++ DbgPrint("novfs_clear_inode: inode=0x%p ino=%d\n", inode, + inode->i_ino); + } + } + +-/*++======================================================================*/ +-int Novfs_show_options(struct seq_file *s, struct vfsmount *m) +-/* +- * Arguments: +- * +- * Returns: 0 +- * +- * Abstract: Called when /proc/mounts is read +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++/* Called when /proc/mounts is read */ ++int novfs_show_options(struct seq_file *s, struct vfsmount *m) + { + char *buf, *path, *tmp; + +- buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { + struct path my_path; + my_path.mnt = m; + my_path.dentry = m->mnt_root; + path = d_path(&my_path, buf, PATH_LENGTH_BUFFER); + if (path) { +- if (!Novfs_CurrentMount +- || (Novfs_CurrentMount +- && strcmp(Novfs_CurrentMount, path))) { +- DbgPrint("Novfs_show_options: %.*s %.*s %s\n", ++ if (!novfs_current_mnt ++ || (novfs_current_mnt ++ && strcmp(novfs_current_mnt, path))) { ++ DbgPrint("novfs_show_options: %.*s %.*s %s\n", + m->mnt_root->d_name.len, + m->mnt_root->d_name.name, + m->mnt_mountpoint->d_name.len, + m->mnt_mountpoint->d_name.name, path); +- tmp = +- (char *)Novfs_Malloc(PATH_LENGTH_BUFFER - ++ tmp = kmalloc(PATH_LENGTH_BUFFER - + (int)(path - buf), + GFP_KERNEL); + if (tmp) { + strcpy(tmp, path); +- path = Novfs_CurrentMount; +- Novfs_CurrentMount = tmp; +- Daemon_SetMountPoint +- (Novfs_CurrentMount); ++ path = novfs_current_mnt; ++ novfs_current_mnt = tmp; ++ novfs_daemon_set_mnt_point(novfs_current_mnt); + + if (path) { + kfree(path); +@@ -4362,37 +3704,17 @@ int Novfs_show_options(struct seq_file * + return (0); + } + +-/*++======================================================================*/ +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +-int Novfs_statfs(struct dentry *de, struct kstatfs *buf) +-#else +-int Novfs_statfs(struct super_block *sb, struct kstatfs *buf) +-#endif +-/* +- * Arguments: sb - pointer to the super_block +- * buf - pointer to the statfs buffer +- * +- * Returns: 0 +- * +- * Abstract: Called when statfs(2) system called. +- * +- * Notes: +- * +- * Environment: Superblock operation +- * +- *========================================================================*/ ++/* Called when statfs(2) system called. */ ++int novfs_statfs(struct dentry *de, struct kstatfs *buf) + { + uint64_t td, fd, te, fe; +- +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) + struct super_block *sb = de->d_sb; +-#endif + +- DbgPrint("Novfs_statfs:\n"); ++ DbgPrint("novfs_statfs:\n"); + + td = fd = te = fe = 0; + +- Scope_Get_UserSpace(&td, &fd, &te, &fe); ++ novfs_scope_get_userspace(&td, &fd, &te, &fe); + + DbgPrint("td=%llu\n", td); + DbgPrint("fd=%llu\n", fd); +@@ -4430,7 +3752,7 @@ int Novfs_statfs(struct super_block *sb, + return 0; + } + +-struct inode *Novfs_get_inode(struct super_block *sb, int mode, int dev, ++struct inode *novfs_get_inode(struct super_block *sb, int mode, int dev, + uid_t Uid, ino_t ino, struct qstr *name) + { + struct inode *inode = new_inode(sb); +@@ -4440,37 +3762,32 @@ struct inode *Novfs_get_inode(struct sup + inode->i_mode = mode; + inode->i_uid = Uid; + inode->i_gid = 0; +- /* bug # 340510 tells us to comment this out... */ +-//#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +-// inode->i_blksize = sb->s_blocksize; +-//#else +-// inode->i_sb->s_blocksize = sb->s_blocksize; +-//#endif ++ inode->i_sb->s_blocksize = sb->s_blocksize; + inode->i_blkbits = sb->s_blocksize_bits; + inode->i_blocks = 0; + inode->i_rdev = 0; +- inode->i_ino = (ino) ? ino : (ino_t)atomic_inc_return(&Novfs_Inode_Number); +- if (PageCache) { +- inode->i_mapping->a_ops = &Novfs_aops; ++ inode->i_ino = (ino) ? ino : (ino_t)atomic_inc_return(&novfs_Inode_Number); ++ if (novfs_page_cache) { ++ inode->i_mapping->a_ops = &novfs_aops; + } else { +- inode->i_mapping->a_ops = &Novfs_nocache_aops; ++ inode->i_mapping->a_ops = &novfs_nocache_aops; + } +- inode->i_mapping->backing_dev_info = &Novfs_backing_dev_info; ++ inode->i_mapping->backing_dev_info = &novfs_backing_dev_info; + inode->i_atime.tv_sec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_mtime = inode->i_ctime = inode->i_atime; + +- DbgPrint("Novfs_get_inode: Inode=0x%p I_ino=%d len=%d\n", inode, ++ DbgPrint("novfs_get_inode: Inode=0x%p I_ino=%d len=%d\n", inode, + inode->i_ino, name->len); + + if (NULL != +- (inode->FSPRIVATE = +- Novfs_Malloc(sizeof(struct inode_data) + name->len, ++ (inode->i_private = ++ kmalloc(sizeof(struct inode_data) + name->len, + GFP_KERNEL))) { + struct inode_data *id; +- id = inode->FSPRIVATE; ++ id = inode->i_private; + +- DbgPrint("Novfs_get_inode: FSPRIVATE 0x%p\n", id); ++ DbgPrint("novfs_get_inode: i_private 0x%p\n", id); + + id->Scope = NULL; + id->Flags = 0; +@@ -4494,7 +3811,7 @@ struct inode *Novfs_get_inode(struct sup + memcpy(id->Name, name->name, name->len); + id->Name[name->len] = '\0'; + +- DbgPrint("Novfs_get_inode: name %s\n", id->Name); ++ DbgPrint("novfs_get_inode: name %s\n", id->Name); + } + + insert_inode_hash(inode); +@@ -4502,19 +3819,15 @@ struct inode *Novfs_get_inode(struct sup + switch (mode & S_IFMT) { + + case S_IFREG: +- inode->i_op = &Novfs_file_inode_operations; +- inode->i_fop = &Novfs_file_operations; ++ inode->i_op = &novfs_file_inode_operations; ++ inode->i_fop = &novfs_file_operations; + break; + + case S_IFDIR: +- inode->i_op = &Novfs_inode_operations; +- inode->i_fop = &Novfs_dir_operations; +-// Again bug #340510 +-//#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +-// inode->i_blksize = 0; +-//#else +-// inode->i_sb->s_blocksize = 0; +-//#endif ++ inode->i_op = &novfs_inode_operations; ++ inode->i_fop = &novfs_dir_operations; ++ ++ inode->i_sb->s_blocksize = 0; + inode->i_blkbits = 0; + break; + +@@ -4523,63 +3836,63 @@ struct inode *Novfs_get_inode(struct sup + break; + } + +- DbgPrint("Novfs_get_inode: size=%lld\n", inode->i_size); +- DbgPrint("Novfs_get_inode: mode=0%o\n", inode->i_mode); +- DbgPrint("Novfs_get_inode: i_sb->s_blocksize=%d\n", ++ DbgPrint("novfs_get_inode: size=%lld\n", inode->i_size); ++ DbgPrint("novfs_get_inode: mode=0%o\n", inode->i_mode); ++ DbgPrint("novfs_get_inode: i_sb->s_blocksize=%d\n", + inode->i_sb->s_blocksize); +- DbgPrint("Novfs_get_inode: i_blkbits=%d\n", inode->i_blkbits); +- DbgPrint("Novfs_get_inode: i_blocks=%d\n", inode->i_blocks); +- DbgPrint("Novfs_get_inode: i_bytes=%d\n", inode->i_bytes); ++ DbgPrint("novfs_get_inode: i_blkbits=%d\n", inode->i_blkbits); ++ DbgPrint("novfs_get_inode: i_blocks=%d\n", inode->i_blocks); ++ DbgPrint("novfs_get_inode: i_bytes=%d\n", inode->i_bytes); + } + +- DbgPrint("Novfs_get_inode: 0x%p %d\n", inode, inode->i_ino); ++ DbgPrint("novfs_get_inode: 0x%p %d\n", inode, inode->i_ino); + return (inode); + } + +-int Novfs_fill_super(struct super_block *SB, void *Data, int Silent) ++int novfs_fill_super(struct super_block *SB, void *Data, int Silent) + { + struct inode *inode; + struct dentry *server, *tree; + struct qstr name; +- struct entry_info info; ++ struct novfs_entry_info info; + + SB->s_blocksize = PAGE_CACHE_SIZE; + SB->s_blocksize_bits = PAGE_CACHE_SHIFT; + SB->s_maxbytes = 0xFFFFFFFFFFFFFFFFULL; /* Max file size */ +- SB->s_op = &Novfs_ops; ++ SB->s_op = &novfs_ops; + SB->s_flags |= (MS_NODIRATIME | MS_NODEV | MS_POSIXACL); + SB->s_magic = NOVFS_MAGIC; + + name.len = 1; + name.name = "/"; + +- inode = Novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); ++ inode = novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); + if (!inode) { + return (-ENOMEM); + } + +- Novfs_root = d_alloc_root(inode); ++ novfs_root = d_alloc_root(inode); + +- if (!Novfs_root) { ++ if (!novfs_root) { + iput(inode); + return (-ENOMEM); + } +- Novfs_root->d_time = jiffies + (File_update_timeout * HZ); ++ novfs_root->d_time = jiffies + (novfs_update_timeout * HZ); + + inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; + +- SB->s_root = Novfs_root; ++ SB->s_root = novfs_root; + +- DbgPrint("Novfs_fill_super: root 0x%p\n", Novfs_root); ++ DbgPrint("novfs_fill_super: root 0x%p\n", novfs_root); + +- if (Novfs_root) { +- Novfs_root->d_op = &Novfs_dentry_operations; ++ if (novfs_root) { ++ novfs_root->d_op = &novfs_dentry_operations; + + name.name = SERVER_DIRECTORY_NAME; + name.len = strlen(SERVER_DIRECTORY_NAME); +- name.hash = Novfs_internal_hash(&name); ++ name.hash = novfs_internal_hash(&name); + +- inode = Novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); ++ inode = novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); + if (inode) { + info.mode = inode->i_mode; + info.namelength = 0; +@@ -4590,14 +3903,14 @@ int Novfs_fill_super(struct super_block + inode->i_ctime = info.ctime = + inode->i_mtime = info.mtime = CURRENT_TIME; + +- server = d_alloc(Novfs_root, &name); ++ server = d_alloc(novfs_root, &name); + if (server) { +- server->d_op = &Novfs_dentry_operations; ++ server->d_op = &novfs_dentry_operations; + server->d_time = 0xffffffff; + d_add(server, inode); +- DbgPrint("Novfs_fill_super: d_add %s 0x%p\n", ++ DbgPrint("novfs_fill_super: d_add %s 0x%p\n", + SERVER_DIRECTORY_NAME, server); +- Novfs_add_inode_entry(Novfs_root->d_inode, ++ novfs_add_inode_entry(novfs_root->d_inode, + &name, inode->i_ino, + &info); + } +@@ -4605,9 +3918,9 @@ int Novfs_fill_super(struct super_block + + name.name = TREE_DIRECTORY_NAME; + name.len = strlen(TREE_DIRECTORY_NAME); +- name.hash = Novfs_internal_hash(&name); ++ name.hash = novfs_internal_hash(&name); + +- inode = Novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); ++ inode = novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); + if (inode) { + info.mode = inode->i_mode; + info.namelength = 0; +@@ -4617,15 +3930,15 @@ int Novfs_fill_super(struct super_block + inode->i_atime = info.atime = + inode->i_ctime = info.ctime = + inode->i_mtime = info.mtime = CURRENT_TIME; +- tree = d_alloc(Novfs_root, &name); ++ tree = d_alloc(novfs_root, &name); + if (tree) { +- tree->d_op = &Novfs_dentry_operations; ++ tree->d_op = &novfs_dentry_operations; + tree->d_time = 0xffffffff; + + d_add(tree, inode); +- DbgPrint("Novfs_fill_super: d_add %s 0x%p\n", ++ DbgPrint("novfs_fill_super: d_add %s 0x%p\n", + TREE_DIRECTORY_NAME, tree); +- Novfs_add_inode_entry(Novfs_root->d_inode, ++ novfs_add_inode_entry(novfs_root->d_inode, + &name, inode->i_ino, + &info); + } +@@ -4635,75 +3948,53 @@ int Novfs_fill_super(struct super_block + return (0); + } + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +-int Novfs_get_sb(struct file_system_type *Fstype, int Flags, ++static int novfs_get_sb(struct file_system_type *Fstype, int Flags, + const char *Dev_name, void *Data, struct vfsmount *Mnt) +-#else +-struct super_block *Novfs_get_sb(struct file_system_type *Fstype, int Flags, +- const char *Dev_name, void *Data) +-#endif + { +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +- int sb; +-#else +- struct super_block *sb; +-#endif +- +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +- sb = get_sb_nodev(Fstype, Flags, Data, Novfs_fill_super, Mnt); +-#else +- sb = get_sb_nodev(Fstype, Flags, Data, Novfs_fill_super); +-#endif +- +- DbgPrint("Novfs_get_sb: sb=0x%p Fstype=0x%x Dev_name=%s\n", sb, Fstype, +- Dev_name); +- +- return (sb); ++ DbgPrint("novfs_get_sb: Fstype=0x%x Dev_name=%s\n", Fstype, Dev_name); ++ return get_sb_nodev(Fstype, Flags, Data, novfs_fill_super, Mnt); + } + + static void novfs_kill_sb(struct super_block *super) + { +- /* calling shrink_dcache_sb() fixes novell bugzilla #345179, but I'm +- * not so sure about it... */ +- shrink_dcache_sb(super); + kill_litter_super(super); + } + +-ssize_t Novfs_Control_read(struct file *file, char *buf, size_t nbytes, ++ssize_t novfs_Control_read(struct file *file, char *buf, size_t nbytes, + loff_t * ppos) + { + ssize_t retval = 0; + +- DbgPrint("Novfs_Control_read: kernel_locked 0x%x\n", kernel_locked()); ++ DbgPrint("novfs_Control_read: kernel_locked 0x%x\n", kernel_locked()); + + return retval; + } + +-ssize_t Novfs_Control_write(struct file * file, const char *buf, size_t nbytes, ++ssize_t novfs_Control_write(struct file * file, const char *buf, size_t nbytes, + loff_t * ppos) + { + ssize_t retval = 0; + +- DbgPrint("Novfs_Control_write: kernel_locked 0x%x\n", kernel_locked()); ++ DbgPrint("novfs_Control_write: kernel_locked 0x%x\n", kernel_locked()); + if (buf && nbytes) { + } + + return (retval); + } + +-int Novfs_Control_ioctl(struct inode *inode, struct file *file, ++int novfs_Control_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) + { + int retval = 0; + +- DbgPrint("Novfs_Control_ioctl: kernel_locked 0x%x\n", kernel_locked()); ++ DbgPrint("novfs_Control_ioctl: kernel_locked 0x%x\n", kernel_locked()); + + return (retval); + } + +-static struct file_system_type Novfs_fs_type = { ++static struct file_system_type novfs_fs_type = { + .name = "novfs", +- .get_sb = Novfs_get_sb, ++ .get_sb = novfs_get_sb, + .kill_sb = novfs_kill_sb, + .owner = THIS_MODULE, + }; +@@ -4718,20 +4009,20 @@ int __init init_novfs(void) + inHAX = 0; + inHAXTime = get_nanosecond_time(); + +- retCode = Init_Procfs_Interface(); ++ retCode = novfs_proc_init(); + +- init_profile(); ++ novfs_profile_init(); + + if (!retCode) { + DbgPrint("init_novfs: %s %s %s\n", __DATE__, __TIME__, + NOVFS_VERSION_STRING); +- Init_Daemon_Queue(); +- Scope_Init(); +- retCode = register_filesystem(&Novfs_fs_type); ++ novfs_daemon_queue_init(); ++ novfs_scope_init(); ++ retCode = register_filesystem(&novfs_fs_type); + if (retCode) { +- Uninit_Procfs_Interface(); +- Uninit_Daemon_Queue(); +- Scope_Uninit(); ++ novfs_proc_exit(); ++ novfs_daemon_queue_exit(); ++ novfs_scope_exit(); + } + } + return (retCode); +@@ -4741,80 +4032,52 @@ void __exit exit_novfs(void) + { + printk(KERN_INFO "exit_novfs\n"); + +- Scope_Uninit(); ++ novfs_scope_exit(); + printk(KERN_INFO "exit_novfs after Scope_Uninit\n"); + +- Uninit_Daemon_Queue(); ++ novfs_daemon_queue_exit(); + printk(KERN_INFO "exit_novfs after Uninit_Daemon_Queue\n"); + +- uninit_profile(); +- printk(KERN_INFO "exit_novfs after uninit_profile\n"); ++ novfs_profile_exit(); ++ printk(KERN_INFO "exit_novfs after profile_exit\n"); + +- Uninit_Procfs_Interface(); ++ novfs_proc_exit(); + printk(KERN_INFO "exit_novfs Uninit_Procfs_Interface\n"); + +- unregister_filesystem(&Novfs_fs_type); ++ unregister_filesystem(&novfs_fs_type); + printk(KERN_INFO "exit_novfs: Exit\n"); + +- if (Novfs_CurrentMount) { +- kfree(Novfs_CurrentMount); +- Novfs_CurrentMount = NULL; ++ if (novfs_current_mnt) { ++ kfree(novfs_current_mnt); ++ novfs_current_mnt = NULL; + } + } + +-int Novfs_lock_inode_cache(struct inode *i) +-/* +- * +- * Arguments: struct inode *i - pointer to directory inode +- * +- * Returns: 0 - locked +- * -1 - not locked +- * +- * Abstract: Locks the inode cache. +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_lock_inode_cache(struct inode *i) + { + struct inode_data *id; + int retVal = 0; + +- DbgPrint("Novfs_lock_inode_cache: 0x%p\n", i); +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ DbgPrint("novfs_lock_inode_cache: 0x%p\n", i); ++ if (i && (id = i->i_private) && id->DirCache.next) { + down(&id->DirCacheLock); + retVal = 1; + } +- DbgPrint("Novfs_lock_inode_cache: return %d\n", retVal); ++ DbgPrint("novfs_lock_inode_cache: return %d\n", retVal); + return (retVal); + } + +-/*++======================================================================*/ +-void Novfs_unlock_inode_cache(struct inode *i) +-/* +- * Arguments: struct inode *i - pointer to directory inode +- * +- * Returns: nothing +- * +- * Abstract: Unlocks inode cache. +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++void novfs_unlock_inode_cache(struct inode *i) + { + struct inode_data *id; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + up(&id->DirCacheLock); + } + } + +-/*++======================================================================*/ +-int Novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, +- ino_t * ino, struct entry_info *info) ++int novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, ++ ino_t * ino, struct novfs_entry_info *info) + /* + * Arguments: struct inode *i - pointer to directory inode + * +@@ -4824,17 +4087,14 @@ int Novfs_enumerate_inode_cache(struct i + * Abstract: Unlocks inode cache. + * + * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: +- * + *========================================================================*/ + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + struct list_head *l = NULL; + int retVal = -1; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + if ((NULL == iteration) || (NULL == *iteration)) { + l = id->DirCache.next; + } else { +@@ -4844,7 +4104,7 @@ int Novfs_enumerate_inode_cache(struct i + if (l == &id->DirCache) { + l = NULL; + } else { +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, list); + + *ino = dc->ino; + info->type = 0; +@@ -4865,35 +4125,23 @@ int Novfs_enumerate_inode_cache(struct i + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, +- struct entry_info *info) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: +- * +- *========================================================================*/ ++/* DirCacheLock should be held before calling this routine. */ ++int novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, ++ struct novfs_entry_info *info) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } + +- dc = Novfs_lookup_inode_cache(i, name, *ino); ++ dc = novfs_lookup_inode_cache(i, name, *ino); + if (dc) { + dc->flags |= ENTRY_VALID; + retVal = 0; +@@ -4910,36 +4158,25 @@ int Novfs_get_entry(struct inode *i, str + retVal = 0; + } + +- DbgPrint("Novfs_get_entry:\n" ++ DbgPrint("novfs_get_entry:\n" + " inode: 0x%p\n" + " name: %.*s\n" " ino: %d\n", i, nl, n, *ino); + } +- DbgPrint("Novfs_get_entry: return %d\n", retVal); ++ DbgPrint("novfs_get_entry: return %d\n", retVal); + return (retVal); + } + +-int Novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, +- struct entry_info *info) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: +- * +- *========================================================================*/ ++ /*DirCacheLock should be held before calling this routine. */ ++int novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, ++ struct novfs_entry_info *info) + { + int retVal = -1; + loff_t count = 0; + loff_t i_pos = pos - 2; + struct list_head *inter = NULL; +- while (!Novfs_enumerate_inode_cache(i, &inter, ino, info)) { ++ while (!novfs_enumerate_inode_cache(i, &inter, ino, info)) { + DbgPrint +- ("Novfs_dir_readdir : Novfs_get_entry_by_pos : info->name = %s\n", ++ ("novfs_dir_readdir : novfs_get_entry_by_pos : info->name = %s\n", + info->name); + if (count == i_pos) { + retVal = 0; +@@ -4951,38 +4188,26 @@ int Novfs_get_entry_by_pos(struct inode + return retVal; + } + +-/*++======================================================================*/ +-int Novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, +- struct entry_info *info, u64 * EntryTime) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: +- * +- *========================================================================*/ ++/* DirCacheLock should be held before calling this routine. */ ++int novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, ++ struct novfs_entry_info *info, u64 * EntryTime) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } +- DbgPrint("Novfs_get_entry_time:\n" ++ DbgPrint("novfs_get_entry_time:\n" + " inode: 0x%p\n" + " name: %.*s\n" " ino: %d\n", i, nl, n, *ino); + +- dc = Novfs_lookup_inode_cache(i, name, *ino); ++ dc = novfs_lookup_inode_cache(i, name, *ino); + if (dc) { + retVal = 0; + *ino = dc->ino; +@@ -5001,36 +4226,29 @@ int Novfs_get_entry_time(struct inode *i + retVal = 0; + } + } +- DbgPrint("Novfs_get_entry_time: return %d\n", retVal); ++ DbgPrint("novfs_get_entry_time: return %d\n", retVal); + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_get_remove_entry(struct inode *i, ino_t * ino, struct entry_info *info) + /* +- * Arguments: +- * +- * Returns: +- * + * Abstract: This routine will return the first entry on the list + * and then remove it. + * + * Notes: DirCacheLock should be held before calling this routine. + * +- * Environment: +- * +- *========================================================================*/ ++ */ ++int novfs_get_remove_entry(struct inode *i, ino_t * ino, struct novfs_entry_info *info) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + struct list_head *l = NULL; + int retVal = -1; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + l = id->DirCache.next; + + if (l != &id->DirCache) { +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, list); + + *ino = dc->ino; + info->type = 0; +@@ -5054,41 +4272,31 @@ int Novfs_get_remove_entry(struct inode + return (retVal); + } + +-/*++======================================================================*/ +-void Novfs_invalidate_inode_cache(struct inode *i) + /* +- * Arguments: struct inode *i - pointer to directory inode +- * +- * Returns: nothing +- * + * Abstract: Marks all entries in the directory cache as invalid. + * + * Notes: DirCacheLock should be held before calling this routine. + * +- * Environment: +- * + *========================================================================*/ ++void novfs_invalidate_inode_cache(struct inode *i) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + struct list_head *l; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + list_for_each(l, &id->DirCache) { +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, list); + dc->flags &= ~ENTRY_VALID; + } + } + } + + /*++======================================================================*/ +-static struct dir_cache *Novfs_lookup_inode_cache(struct inode *i, struct qstr *name, ino_t ino) ++struct novfs_dir_cache *novfs_lookup_inode_cache(struct inode *i, struct qstr *name, ++ ino_t ino) + /* +- * Arguments: struct inode *i - pointer to directory inode +- * struct qstr *name - pointer to name +- * ino_t - inode number +- * +- * Returns: struct dir_cache entry if match ++ * Returns: struct novfs_dir_cache entry if match + * NULL - if there is no match. + * + * Abstract: Checks a inode directory to see if there are any enties +@@ -5097,25 +4305,22 @@ static struct dir_cache *Novfs_lookup_in + * + * Notes: DirCacheLock should be held before calling this routine. + * +- * Environment: +- * + *========================================================================*/ + { + struct inode_data *id; +- struct dir_cache *dc; +- struct dir_cache *retVal = NULL; ++ struct novfs_dir_cache *dc, *retVal = NULL; + struct list_head *l; + char *n = ""; + int nl = 6; + int hash = 0; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->name) { + nl = name->len; + n = (char *)name->name; + hash = name->hash; + } +- DbgPrint("Novfs_lookup_inode_cache:\n" ++ DbgPrint("novfs_lookup_inode_cache:\n" + " inode: 0x%p\n" + " name: %.*s\n" + " hash: 0x%x\n" +@@ -5123,10 +4328,10 @@ static struct dir_cache *Novfs_lookup_in + " ino: %d\n", i, nl, n, hash, nl, ino); + + list_for_each(l, &id->DirCache) { +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, list); + if (name) { + +-/* DbgPrint("Novfs_lookup_inode_cache: 0x%p\n" \ ++/* DbgPrint("novfs_lookup_inode_cache: 0x%p\n" \ + " ino: %d\n" \ + " hash: 0x%x\n" \ + " len: %d\n" \ +@@ -5149,46 +4354,34 @@ static struct dir_cache *Novfs_lookup_in + } + } + +- DbgPrint("Novfs_lookup_inode_cache: return 0x%p\n", retVal); ++ DbgPrint("novfs_lookup_inode_cache: return 0x%p\n", retVal); + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino) + /* +- * Arguments: struct inode *i - pointer to directory inode +- * struct qstr *name - pointer to name +- * ino_t - inode number +- * +- * Returns: 0 if found +- * !0 if not found +- * +- * Abstract: Checks a inode directory to see if there are any enties +- * matching name or ino. If entry is found the valid bit +- * is set. ++ * Checks a inode directory to see if there are any enties matching name ++ * or ino. If entry is found the valid bit is set. + * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: +- * +- *========================================================================*/ ++ * DirCacheLock should be held before calling this routine. ++ */ ++int novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + if (name && name->len) { + n = (char *)name->name; + nl = name->len; + } +- DbgPrint("Novfs_update_entry:\n" ++ DbgPrint("novfs_update_entry:\n" + " inode: 0x%p\n" + " name: %.*s\n" " ino: %d\n", i, nl, n, ino); + +- dc = Novfs_lookup_inode_cache(i, name, ino); ++ dc = novfs_lookup_inode_cache(i, name, ino); + if (dc) { + dc->flags |= ENTRY_VALID; + retVal = 0; +@@ -5197,46 +4390,37 @@ int Novfs_lookup_validate(struct inode * + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_add_inode_entry(struct inode *i, +- struct qstr *name, ino_t ino, struct entry_info *info) + /* +- * Arguments: +- * +- * Returns: -ENOMEM - alloc error. +- * 0 - success. +- * +- * Abstract: Added entry to directory cache. +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: ++ * Added entry to directory cache. + * +- *========================================================================*/ ++ * DirCacheLock should be held before calling this routine. ++ */ ++int novfs_add_inode_entry(struct inode *i, ++ struct qstr *name, ino_t ino, struct novfs_entry_info *info) + { + struct inode_data *id; +- struct dir_cache *new; ++ struct novfs_dir_cache *new; + int retVal = -ENOMEM; +- struct dir_cache *todel; ++ struct novfs_dir_cache *todel; + struct list_head *todeltmp; + + //SClark +- DbgPrint("Novfs_add_inode_entry:\n" " i: %u\n", i); +- if ((id = i->FSPRIVATE)) { +- DbgPrint(" i->FSPRIVATE: %p\n", id); ++ DbgPrint("novfs_add_inode_entry:\n" " i: %u\n", i); ++ if ((id = i->i_private)) { ++ DbgPrint(" i->i_private: %p\n", id); + if (id->DirCache.next) + DbgPrint(" id->DirCache.next: %p\n", + id->DirCache.next); + } + //SClark + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { +- new = Novfs_Malloc(sizeof(struct dir_cache) + name->len, GFP_KERNEL); ++ if (i && (id = i->i_private) && id->DirCache.next) { ++ new = kmalloc(sizeof(struct novfs_dir_cache) + name->len, GFP_KERNEL); + if (new) { + id->cntDC++; + + DCCount++; +- DbgPrint("Novfs_add_inode_entry:\n" ++ DbgPrint("novfs_add_inode_entry:\n" + " inode: 0x%p\n" + " id: 0x%p\n" + " DC: 0x%p\n" +@@ -5265,7 +4449,7 @@ int Novfs_add_inode_entry(struct inode * + + if (id->cntDC > 20) { + todeltmp = id->DirCache.prev; +- todel = list_entry(todeltmp, struct dir_cache, list); ++ todel = list_entry(todeltmp, struct novfs_dir_cache, list); + + list_del(&todel->list); + +@@ -5274,29 +4458,20 @@ int Novfs_add_inode_entry(struct inode * + DCCount--; + id->cntDC--; + } ++ + } + } + return (retVal); + } + +-/*++======================================================================*/ +-int Novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, +- struct entry_info *info) + /* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: +- * +- *========================================================================*/ ++ * DirCacheLock should be held before calling this routine. ++ */ ++int novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, ++ struct novfs_entry_info *info) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + int retVal = -1; + char *n = ""; + int nl = 6; +@@ -5304,7 +4479,7 @@ int Novfs_update_entry(struct inode *i, + char mtime_buf[32]; + char ctime_buf[32]; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + + if (name && name->len) { + n = (char *)name->name; +@@ -5313,7 +4488,7 @@ int Novfs_update_entry(struct inode *i, + ctime_r(&info->atime.tv_sec, atime_buf); + ctime_r(&info->mtime.tv_sec, mtime_buf); + ctime_r(&info->ctime.tv_sec, ctime_buf); +- DbgPrint("Novfs_update_entry:\n" ++ DbgPrint("novfs_update_entry:\n" + " inode: 0x%p\n" + " name: %.*s\n" + " ino: %d\n" +@@ -5324,7 +4499,7 @@ int Novfs_update_entry(struct inode *i, + i, nl, n, ino, info->size, atime_buf, mtime_buf, + ctime_buf); + +- dc = Novfs_lookup_inode_cache(i, name, ino); ++ dc = novfs_lookup_inode_cache(i, name, ino); + if (dc) { + retVal = 0; + dc->flags = ENTRY_VALID; +@@ -5338,7 +4513,7 @@ int Novfs_update_entry(struct inode *i, + ctime_r(&dc->atime.tv_sec, atime_buf); + ctime_r(&dc->mtime.tv_sec, mtime_buf); + ctime_r(&dc->ctime.tv_sec, ctime_buf); +- DbgPrint("Novfs_update_entry entry: 0x%p\n" ++ DbgPrint("novfs_update_entry entry: 0x%p\n" + " flags: 0x%x\n" + " jiffies: %lld\n" + " ino: %d\n" +@@ -5356,39 +4531,31 @@ int Novfs_update_entry(struct inode *i, + dc->nameLen, dc->name); + } + } +- DbgPrint("Novfs_update_entry: return %d\n", retVal); ++ DbgPrint("novfs_update_entry: return %d\n", retVal); + return (retVal); + } + +-/*++======================================================================*/ +-void Novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino) + /* +- * Arguments: +- * +- * Returns: nothing +- * +- * Abstract: Removes entry from directory cache. You can specify a name +- * or an inode number. +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: ++ * Removes entry from directory cache. You can specify a name ++ * or an inode number. + * +- *========================================================================*/ ++ * DirCacheLock should be held before calling this routine. ++ */ ++void novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + char *n = ""; + int nl = 6; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { +- dc = Novfs_lookup_inode_cache(i, name, ino); ++ if (i && (id = i->i_private) && id->DirCache.next) { ++ dc = novfs_lookup_inode_cache(i, name, ino); + if (dc) { + if (name && name->name) { + nl = name->len; + n = (char *)name->name; + } +- DbgPrint("Novfs_remove_inode_entry:\n" ++ DbgPrint("novfs_remove_inode_entry:\n" + " inode: 0x%p\n" + " id: 0x%p\n" + " DC: 0x%p\n" +@@ -5411,30 +4578,22 @@ void Novfs_remove_inode_entry(struct ino + } + } + +-/*++======================================================================*/ +-void Novfs_free_invalid_entries(struct inode *i) + /* +- * Arguments: struct inode *i - pointer to directory inode. +- * +- * Returns: nothing +- * +- * Abstract: Frees all invalid entries in the directory cache. +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: ++ * Frees all invalid entries in the directory cache. + * +- *========================================================================*/ ++ * DirCacheLock should be held before calling this routine. ++ */ ++void novfs_free_invalid_entries(struct inode *i) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + struct list_head *l; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + list_for_each(l, &id->DirCache) { +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, list); + if (0 == (dc->flags & ENTRY_VALID)) { +- DbgPrint("Novfs_free_invalid_entries:\n" ++ DbgPrint("novfs_free_invalid_entries:\n" + " inode: 0x%p\n" + " id: 0x%p\n" + " entry: 0x%p\n" +@@ -5453,28 +4612,20 @@ void Novfs_free_invalid_entries(struct i + } + } + +-/*++======================================================================*/ +-void Novfs_free_inode_cache(struct inode *i) + /* +- * Arguments: struct inode *i - pointer to directory inode. +- * +- * Returns: nothing +- * +- * Abstract: Frees all entries in the inode cache. +- * +- * Notes: DirCacheLock should be held before calling this routine. +- * +- * Environment: ++ * Frees all entries in the inode cache. + * +- *========================================================================*/ ++ * DirCacheLock should be held before calling this routine. ++ */ ++void novfs_free_inode_cache(struct inode *i) + { + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + struct list_head *l; + +- if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (i && (id = i->i_private) && id->DirCache.next) { + list_for_each(l, &id->DirCache) { +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, list); + l = l->prev; + list_del(&dc->list); + kfree(dc); +@@ -5485,12 +4636,12 @@ void Novfs_free_inode_cache(struct inode + } + } + +-void Novfs_dump_inode(void *pf) ++void novfs_dump_inode(void *pf) + { + struct inode *inode; + void (*pfunc) (char *Fmt, ...) = pf; + struct inode_data *id; +- struct dir_cache *dc; ++ struct novfs_dir_cache *dc; + struct list_head *il, *l; + char atime_buf[32]; + char mtime_buf[32]; +@@ -5517,13 +4668,14 @@ void Novfs_dump_inode(void *pf) + pfunc(" count=0%o\n", atomic_read(&inode->i_count)); + } + +- pfunc(" inode_data: 0x%p Name=%s Scope=0x%p\n", id, id->Name, ++ pfunc(" nofs_inode_data: 0x%p Name=%s Scope=0x%p\n", id, id->Name, + id->Scope); + + if (id->DirCache.next) { + list_for_each(l, &id->DirCache) { + dccnt++; +- dc = list_entry(l, struct dir_cache, list); ++ dc = list_entry(l, struct novfs_dir_cache, ++ list); + ctime_r(&dc->atime.tv_sec, atime_buf); + ctime_r(&dc->mtime.tv_sec, mtime_buf); + ctime_r(&dc->ctime.tv_sec, ctime_buf); +--- a/fs/novfs/nwcapi.c ++++ b/fs/novfs/nwcapi.c +@@ -27,16 +27,20 @@ + #include "vfs.h" + #include "commands.h" + +-static void GetUserData(NwcScanConnInfo *connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply); +-static void GetConnData(NwcGetConnInfo *connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply); ++#ifndef strlen_user ++#define strlen_user(str) strnlen_user(str, ~0UL >> 1) ++#endif + ++static void GetUserData(struct nwc_scan_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply); ++static void GetConnData(struct nwc_get_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply); + +-int NwOpenConnByName(PXPLAT pdata, HANDLE * Handle, session_t Session) ++/*++======================================================================*/ ++int novfs_open_conn_by_name(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCOpenConnByName openConn, connReply; +- NwcOpenConnByName ocbn; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwd_open_conn_by_name *openConn, *connReply; ++ struct nwc_open_conn_by_name ocbn; + int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + char *data; +@@ -45,15 +49,17 @@ int NwOpenConnByName(PXPLAT pdata, HANDL + datalen = sizeof(*openConn) + strlen_user(ocbn.pName->pString) + strlen_user(ocbn.pServiceType); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); ++ + if (!cmd) + return -ENOMEM; ++ + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_OPEN_CONN_BY_NAME; + + cmd->dataLen = datalen; +- openConn = (PNwdCOpenConnByName) cmd->data; ++ openConn = (struct nwd_open_conn_by_name *) cmd->data; + + openConn->nameLen = strlen_user(ocbn.pName->pString); + openConn->serviceLen = strlen_user(ocbn.pServiceType); +@@ -64,24 +70,29 @@ int NwOpenConnByName(PXPLAT pdata, HANDL + openConn->oName = sizeof(*openConn); + + openConn->oServiceType = openConn->oName + openConn->nameLen; +- cpylen = copy_from_user(data, ocbn.pName->pString, openConn->nameLen); ++ cpylen = ++ copy_from_user(data, ocbn.pName->pString, ++ openConn->nameLen); + data += openConn->nameLen; +- cpylen = copy_from_user(data, ocbn.pServiceType, openConn->serviceLen); ++ cpylen = ++ copy_from_user(data, ocbn.pServiceType, ++ openConn->serviceLen); + +- retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ +- connReply = (PNwdCOpenConnByName) reply->data; ++ connReply = (struct nwd_open_conn_by_name *) reply->data; + retCode = reply->Reply.ErrorCode; + if (!retCode) { + /* + * we got valid data. + */ +- connReply = (PNwdCOpenConnByName) reply->data; ++ connReply = (struct nwd_open_conn_by_name *) reply->data; + ocbn.RetConnHandle = HandletoUint32(connReply->newConnHandle); + *Handle = connReply->newConnHandle; + +@@ -92,18 +103,17 @@ int NwOpenConnByName(PXPLAT pdata, HANDL + } + + kfree(cmd); +- +- return retCode; ++ return ((int)retCode); + + } + +-int NwOpenConnByAddr(PXPLAT pdata, HANDLE * Handle, session_t Session) ++int novfs_open_conn_by_addr(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCOpenConnByAddr openConn, connReply; +- NwcOpenConnByAddr ocba; +- NwcTranAddr tranAddr; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwd_open_conn_by_addr *openConn, *connReply; ++ struct nwc_open_conn_by_addr ocba; ++ struct nwc_tran_addr tranAddr; + int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + char addr[MAX_ADDRESS_LENGTH]; +@@ -112,6 +122,7 @@ int NwOpenConnByAddr(PXPLAT pdata, HANDL + datalen = sizeof(*openConn); + cmdlen = datalen + sizeof(*cmd); + cmd = kmalloc(cmdlen, GFP_KERNEL); ++ + if (!cmd) + return -ENOMEM; + +@@ -120,69 +131,66 @@ int NwOpenConnByAddr(PXPLAT pdata, HANDL + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_OPEN_CONN_BY_ADDRESS; + cmd->dataLen = datalen; +- openConn = (PNwdCOpenConnByAddr) cmd->data; ++ openConn = (struct nwd_open_conn_by_addr *) cmd->data; + +- cpylen = copy_from_user(&tranAddr, ocba.pTranAddr, sizeof(tranAddr)); ++ cpylen = ++ copy_from_user(&tranAddr, ocba.pTranAddr, sizeof(tranAddr)); + + DbgPrint("NwOpenConnByAddr: tranAddr\n"); +- mydump(sizeof(tranAddr), &tranAddr); ++ novfs_dump(sizeof(tranAddr), &tranAddr); + + openConn->TranAddr.uTransportType = tranAddr.uTransportType; + openConn->TranAddr.uAddressLength = tranAddr.uAddressLength; + memset(addr, 0xcc, sizeof(addr) - 1); + +- cpylen = copy_from_user(addr, tranAddr.puAddress, tranAddr.uAddressLength); ++ cpylen = ++ copy_from_user(addr, tranAddr.puAddress, ++ tranAddr.uAddressLength); + + DbgPrint("NwOpenConnByAddr: addr\n"); +- mydump(sizeof(addr), addr); ++ novfs_dump(sizeof(addr), addr); + +- openConn->TranAddr.oAddress = *(unsigned int*) (&addr[2]); ++ openConn->TranAddr.oAddress = *(unsigned int *) (&addr[2]); + +- retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ +- connReply = (PNwdCOpenConnByAddr) reply->data; ++ connReply = (struct nwd_open_conn_by_addr *) reply->data; + retCode = reply->Reply.ErrorCode; + if (!retCode) { + /* + * we got valid data. + */ +- connReply = (PNwdCOpenConnByAddr) reply->data; +- ocba.ConnHandle = HandletoUint32(connReply->ConnHandle); ++ connReply = (struct nwd_open_conn_by_addr *) reply->data; ++ ocba.ConnHandle = ++ HandletoUint32(connReply->ConnHandle); + *Handle = connReply->ConnHandle; +- cpylen = copy_to_user(pdata->reqData, &ocba, sizeof(ocba)); +- DbgPrint("New Conn Handle = %X\n", connReply->ConnHandle); ++ cpylen = ++ copy_to_user(pdata->reqData, &ocba, ++ sizeof(ocba)); ++ DbgPrint("New Conn Handle = %X\n", ++ connReply->ConnHandle); + } + kfree(reply); + } + + kfree(cmd); +- return retCode; ++ ++ return (retCode); ++ + } + +-/*++======================================================================*/ +-int NwOpenConnByRef(PXPLAT pdata, HANDLE * Handle, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCOpenConnByRef openConn; +- NwcOpenConnByReference ocbr; ++int novfs_open_conn_by_ref(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwd_open_conn_by_ref *openConn; ++ struct nwc_open_conn_by_ref ocbr; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + +@@ -198,29 +206,35 @@ int NwOpenConnByRef(PXPLAT pdata, HANDLE + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_OPEN_CONN_BY_REFERENCE; + cmd->dataLen = datalen; +- openConn = (PNwdCOpenConnByRef) cmd->data; ++ openConn = (struct nwd_open_conn_by_ref *) cmd->data; + +- openConn->uConnReference = (HANDLE) (unsigned long) ocbr.uConnReference; ++ openConn->uConnReference = ++ (void *) (unsigned long) ocbr.uConnReference; + openConn->uConnFlags = ocbr.uConnFlags; + +- retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); + if (reply) { + /* + * we got reply data from the daemon + */ +- openConn = (PNwdCOpenConnByRef) reply->data; ++ openConn = (struct nwd_open_conn_by_ref *) reply->data; + retCode = reply->Reply.ErrorCode; + if (!retCode) { + /* + * we got valid data. + */ +- ocbr.ConnHandle = HandletoUint32(openConn->ConnHandle); ++ ocbr.ConnHandle = ++ HandletoUint32(openConn->ConnHandle); + *Handle = openConn->ConnHandle; + +- cpylen = copy_to_user(pdata->reqData, &ocbr, sizeof(ocbr)); +- DbgPrint("New Conn Handle = %X\n", openConn->ConnHandle); ++ cpylen = ++ copy_to_user(pdata->reqData, &ocbr, ++ sizeof(ocbr)); ++ DbgPrint("New Conn Handle = %X\n", ++ openConn->ConnHandle); + } + kfree(reply); + } +@@ -230,19 +244,17 @@ int NwOpenConnByRef(PXPLAT pdata, HANDLE + + } + +-int NwRawSend(PXPLAT pdata, session_t Session) ++int novfs_raw_send(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- NwcRequest xRequest; +- PNwcFrag frag = NULL; +- PNwcFrag cFrag = NULL; +- PNwcFrag reqFrag = NULL; +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++ struct nwc_request xRequest; ++ struct nwc_frag *frag, *cFrag, *reqFrag; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen, totalLen; + unsigned int x; +- PNwdCNCPReq ncpData; +- PNwdCNCPRep ncpReply; ++ struct nwd_ncp_req *ncpData; ++ struct nwd_ncp_rep *ncpReply; + unsigned char *reqData; + unsigned long actualReplyLength = 0; + +@@ -252,13 +264,18 @@ int NwRawSend(PXPLAT pdata, session_t Se + /* + * Figure out the length of the request + */ +- frag = kmalloc(xRequest.uNumReplyFrags * sizeof(NwcFrag), GFP_KERNEL); +- DbgPrint("[XPLAT RawNCP] - Reply Frag Count 0x%X\n", xRequest.uNumReplyFrags); ++ frag = ++ kmalloc(xRequest.uNumReplyFrags * sizeof(struct nwc_frag), GFP_KERNEL); ++ ++ DbgPrint("[XPLAT RawNCP] - Reply Frag Count 0x%X\n", ++ xRequest.uNumReplyFrags); + + if (!frag) +- goto exit; ++ return (retCode); + +- cpylen = copy_from_user(frag, xRequest.pReplyFrags, xRequest.uNumReplyFrags * sizeof(NwcFrag)); ++ cpylen = ++ copy_from_user(frag, xRequest.pReplyFrags, ++ xRequest.uNumReplyFrags * sizeof(struct nwc_frag)); + totalLen = 0; + + cFrag = frag; +@@ -270,11 +287,17 @@ int NwRawSend(PXPLAT pdata, session_t Se + + DbgPrint("[XPLAT - RawNCP] - totalLen = %d\n", totalLen); + datalen = 0; +- reqFrag = kmalloc(xRequest.uNumRequestFrags * sizeof(NwcFrag), GFP_KERNEL); +- if (!reqFrag) +- goto exit; ++ reqFrag = ++ kmalloc(xRequest.uNumRequestFrags * sizeof(struct nwc_frag), ++ GFP_KERNEL); ++ if (!reqFrag) { ++ kfree(frag); ++ return (retCode); ++ } + +- cpylen = copy_from_user(reqFrag, xRequest.pRequestFrags, xRequest.uNumRequestFrags * sizeof(NwcFrag)); ++ cpylen = ++ copy_from_user(reqFrag, xRequest.pRequestFrags, ++ xRequest.uNumRequestFrags * sizeof(struct nwc_frag)); + cFrag = reqFrag; + for (x = 0; x < xRequest.uNumRequestFrags; x++) { + datalen += cFrag->uLength; +@@ -285,12 +308,13 @@ int NwRawSend(PXPLAT pdata, session_t Se + * Allocate the cmd Request + */ + cmdlen = datalen + sizeof(*cmd) + sizeof(*ncpData); +- DbgPrint("[XPLAT RawNCP] - Frag Count 0x%X\n", xRequest.uNumRequestFrags); ++ DbgPrint("[XPLAT RawNCP] - Frag Count 0x%X\n", ++ xRequest.uNumRequestFrags); + DbgPrint("[XPLAT RawNCP] - Total Command Data Len = %x\n", cmdlen); + + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) +- goto exit; ++ return -ENOMEM; + + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; +@@ -301,10 +325,10 @@ int NwRawSend(PXPLAT pdata, session_t Se + * build the NCP Request + */ + cmd->dataLen = cmdlen - sizeof(*cmd); +- ncpData = (PNwdCNCPReq) cmd->data; ++ ncpData = (struct nwd_ncp_req *) cmd->data; + ncpData->replyLen = totalLen; + ncpData->requestLen = datalen; +- ncpData->ConnHandle = (HANDLE) (unsigned long) xRequest.ConnHandle; ++ ncpData->ConnHandle = (void *) (unsigned long) xRequest.ConnHandle; + ncpData->function = xRequest.uFunction; + + reqData = ncpData->data; +@@ -312,15 +336,16 @@ int NwRawSend(PXPLAT pdata, session_t Se + + for (x = 0; x < xRequest.uNumRequestFrags; x++) { + cpylen = +- copy_from_user(reqData, cFrag->pData, +- cFrag->uLength); ++ copy_from_user(reqData, cFrag->pData, ++ cFrag->uLength); + reqData += cFrag->uLength; + cFrag++; + } + +- retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); + DbgPrint("RawNCP - reply = %x\n", reply); + DbgPrint("RawNCP - retCode = %x\n", retCode); + +@@ -328,11 +353,11 @@ int NwRawSend(PXPLAT pdata, session_t Se + /* + * we got reply data from the daemon + */ +- ncpReply = (PNwdCNCPRep) reply->data; ++ ncpReply = (struct nwd_ncp_rep *) reply->data; + retCode = reply->Reply.ErrorCode; + + DbgPrint("RawNCP - Reply Frag Count 0x%X\n", +- xRequest.uNumReplyFrags); ++ xRequest.uNumReplyFrags); + + /* + * We need to copy the reply frags to the packet. +@@ -344,11 +369,14 @@ int NwRawSend(PXPLAT pdata, session_t Se + for (x = 0; x < xRequest.uNumReplyFrags; x++) { + + DbgPrint("RawNCP - Copy Frag %d: 0x%X\n", x, +- cFrag->uLength); ++ cFrag->uLength); + +- datalen = min((unsigned long)cFrag->uLength, totalLen); ++ datalen = ++ min((unsigned long) cFrag->uLength, totalLen); + +- cpylen = copy_to_user(cFrag->pData, reqData, datalen); ++ cpylen = ++ copy_to_user(cFrag->pData, reqData, ++ datalen); + totalLen -= datalen; + reqData += datalen; + actualReplyLength += datalen; +@@ -362,22 +390,21 @@ int NwRawSend(PXPLAT pdata, session_t Se + } + + kfree(cmd); +- + xRequest.uActualReplyLength = actualReplyLength; + cpylen = copy_to_user(pdata->reqData, &xRequest, sizeof(xRequest)); + +-exit: + kfree(reqFrag); + kfree(frag); +- return retCode; ++ ++ return (retCode); + } + +-int NwConnClose(PXPLAT pdata, HANDLE * Handle, session_t Session) ++int novfs_conn_close(struct novfs_xplat *pdata, void ** Handle, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcCloseConn cc; +- PNwdCCloseConn nwdClose; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_close_conn cc; ++ struct nwd_close_conn *nwdClose; + int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + +@@ -388,35 +415,36 @@ int NwConnClose(PXPLAT pdata, HANDLE * H + cmd = kmalloc(cmdlen, GFP_KERNEL); + if (!cmd) + return -ENOMEM; +- + cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; + cmd->Command.SequenceNumber = 0; + cmd->Command.SessionId = Session; + cmd->NwcCommand = NWC_CLOSE_CONN; + +- nwdClose = (PNwdCCloseConn) cmd->data; ++ nwdClose = (struct nwd_close_conn *) cmd->data; + cmd->dataLen = sizeof(*nwdClose); + *Handle = nwdClose->ConnHandle = Uint32toHandle(cc.ConnHandle); + + /* + * send the request + */ +- retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, 0); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, 0); + if (reply) { + retCode = reply->Reply.ErrorCode; + kfree(reply); + } + kfree(cmd); +- return retCode; ++ return (retCode); ++ + } + +-int NwSysConnClose(PXPLAT pdata, unsigned long *Handle, session_t Session) ++int novfs_sys_conn_close(struct novfs_xplat *pdata, unsigned long *Handle, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcCloseConn cc; +- PNwdCCloseConn nwdClose; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_close_conn cc; ++ struct nwd_close_conn *nwdClose; + unsigned int retCode = 0; + unsigned long cmdlen, datalen, replylen, cpylen; + +@@ -424,133 +452,87 @@ int NwSysConnClose(PXPLAT pdata, unsigne + + datalen = sizeof(*nwdClose); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SYS_CLOSE_CONN; +- +- nwdClose = (PNwdCCloseConn) cmd->data; +- cmd->dataLen = sizeof(*nwdClose); +- nwdClose->ConnHandle = (HANDLE) (unsigned long) cc.ConnHandle; +- *Handle = (unsigned long) cc.ConnHandle; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SYS_CLOSE_CONN; + +- /* +- * send the request +- */ +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, 0); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ nwdClose = (struct nwd_close_conn *) cmd->data; ++ cmd->dataLen = sizeof(*nwdClose); ++ nwdClose->ConnHandle = (void *) (unsigned long) cc.ConnHandle; ++ *Handle = (unsigned long) cc.ConnHandle; + ++ /* ++ * send the request ++ */ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, (void **)&reply, &replylen, 0); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } +- ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwLoginIdentity(PXPLAT pdata, struct schandle *Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_login_id(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- NwcLoginIdentity lgn, *plgn; ++ struct nwc_login_id lgn, *plgn; + int retCode = -ENOMEM; +- NclString server; +- NclString username; +- NclString password; ++ struct ncl_string server; ++ struct ncl_string username; ++ struct ncl_string password; + unsigned long cpylen; +- NwcString nwcStr; ++ struct nwc_string nwcStr; + + cpylen = copy_from_user(&lgn, pdata->reqData, sizeof(lgn)); + + DbgPrint("NwLoginIdentity:\n"); +- mydump(sizeof(lgn), &lgn); ++ novfs_dump(sizeof(lgn), &lgn); + + cpylen = copy_from_user(&nwcStr, lgn.pDomainName, sizeof(nwcStr)); + DbgPrint("NwLoginIdentity: DomainName\n"); +- mydump(sizeof(nwcStr), &nwcStr); ++ novfs_dump(sizeof(nwcStr), &nwcStr); + +- if ((server.buffer = Novfs_Malloc(nwcStr.DataLen, GFP_KERNEL))) { ++ if ((server.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { + server.type = nwcStr.DataType; + server.len = nwcStr.DataLen; +- if (!copy_from_user +- ((void *)server.buffer, nwcStr.pBuffer, server.len)) { ++ if (!copy_from_user((void *)server.buffer, nwcStr.pBuffer, server.len)) { + DbgPrint("NwLoginIdentity: Server\n"); +- mydump(server.len, server.buffer); ++ novfs_dump(server.len, server.buffer); + +- cpylen = +- copy_from_user(&nwcStr, lgn.pObjectName, +- sizeof(nwcStr)); ++ cpylen = copy_from_user(&nwcStr, lgn.pObjectName, sizeof(nwcStr)); + DbgPrint("NwLoginIdentity: ObjectName\n"); +- mydump(sizeof(nwcStr), &nwcStr); ++ novfs_dump(sizeof(nwcStr), &nwcStr); + +- if ((username.buffer = +- Novfs_Malloc(nwcStr.DataLen, GFP_KERNEL))) { ++ if ((username.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { + username.type = nwcStr.DataType; + username.len = nwcStr.DataLen; +- if (!copy_from_user +- ((void *)username.buffer, nwcStr.pBuffer, +- username.len)) { ++ if (!copy_from_user((void *)username.buffer, nwcStr.pBuffer, username.len)) { + DbgPrint("NwLoginIdentity: User\n"); +- mydump(username.len, username.buffer); ++ novfs_dump(username.len, username.buffer); + +- cpylen = +- copy_from_user(&nwcStr, +- lgn.pPassword, +- sizeof(nwcStr)); ++ cpylen = copy_from_user(&nwcStr, lgn.pPassword, sizeof(nwcStr)); + DbgPrint("NwLoginIdentity: Password\n"); +- mydump(sizeof(nwcStr), &nwcStr); ++ novfs_dump(sizeof(nwcStr), &nwcStr); + +- if ((password.buffer = +- Novfs_Malloc(nwcStr.DataLen, +- GFP_KERNEL))) { ++ if ((password.buffer = kmalloc(nwcStr.DataLen, GFP_KERNEL))) { + password.type = nwcStr.DataType; + password.len = nwcStr.DataLen; +- if (!copy_from_user +- ((void *)password.buffer, +- nwcStr.pBuffer, +- password.len)) { +- retCode = +- do_login(&server, +- &username, +- &password, +- (HANDLE *)&lgn.AuthenticationId, +- Session); ++ if (!copy_from_user((void *)password.buffer, nwcStr.pBuffer, password.len)) { ++ retCode = novfs_do_login(&server, &username, &password, (void **)&lgn.AuthenticationId, &Session); + if (retCode) { + lgn.AuthenticationId = 0; + } + +- plgn = +- (NwcLoginIdentity *) +- pdata->reqData; +- cpylen = +- copy_to_user(&plgn-> +- AuthenticationId, +- &lgn. +- AuthenticationId, +- sizeof +- (plgn-> +- AuthenticationId)); +- ++ plgn = (struct nwc_login_id *)pdata->reqData; ++ cpylen = copy_to_user(&plgn->AuthenticationId, &lgn.AuthenticationId, sizeof(plgn->AuthenticationId)); + } +- memset(password.buffer, 0, +- password.len); ++ memset(password.buffer, 0, password.len); + kfree(password.buffer); + } + } +@@ -563,633 +545,504 @@ int NwLoginIdentity(PXPLAT pdata, struct + return (retCode); + } + +-/*++======================================================================*/ +-int NwAuthConnWithId(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- NwcAuthenticateWithId pauth; +- PNwdCAuthenticateWithId pDauth; +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++int novfs_auth_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct nwc_auth_with_id pauth; ++ struct nwc_auth_wid *pDauth; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDauth); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_AUTHENTICATE_CONN_WITH_ID; +- +- cpylen = copy_from_user(&pauth, pdata->reqData, sizeof(pauth)); +- +- pDauth = (PNwdCAuthenticateWithId) cmd->data; +- cmd->dataLen = datalen; +- pDauth->AuthenticationId = pauth.AuthenticationId; +- pDauth->ConnHandle = (HANDLE) (unsigned long) pauth.ConnHandle; +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_AUTHENTICATE_CONN_WITH_ID; ++ ++ cpylen = copy_from_user(&pauth, pdata->reqData, sizeof(pauth)); ++ ++ pDauth = (struct nwc_auth_wid *) cmd->data; ++ cmd->dataLen = datalen; ++ pDauth->AuthenticationId = pauth.AuthenticationId; ++ pDauth->ConnHandle = (void *) (unsigned long) pauth.ConnHandle; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } + return (retCode); + } + +-/*++======================================================================*/ +-int NwLicenseConn(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcLicenseConn lisc; +- PNwdCLicenseConn pDLisc; ++int novfs_license_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_license_conn lisc; ++ struct nwc_lisc_id * pDLisc; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDLisc); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_LICENSE_CONN; +- +- cpylen = copy_from_user(&lisc, pdata->reqData, sizeof(lisc)); +- +- pDLisc = (PNwdCLicenseConn) cmd->data; +- cmd->dataLen = datalen; +- pDLisc->ConnHandle = (HANDLE) (unsigned long) lisc.ConnHandle; +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_LICENSE_CONN; ++ ++ cpylen = copy_from_user(&lisc, pdata->reqData, sizeof(lisc)); ++ ++ pDLisc = (struct nwc_lisc_id *) cmd->data; ++ cmd->dataLen = datalen; ++ pDLisc->ConnHandle = (void *) (unsigned long) lisc.ConnHandle; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + } + +-/*++======================================================================*/ +-int NwLogoutIdentity(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcLogoutIdentity logout; +- PNwdCLogoutIdentity pDLogout; ++int novfs_logout_id(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_lo_id logout, *pDLogout; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDLogout); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_LOGOUT_IDENTITY; ++ if (!cmd) ++ return -ENOMEM; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_LOGOUT_IDENTITY; + +- cpylen = +- copy_from_user(&logout, pdata->reqData, sizeof(logout)); ++ cpylen = ++ copy_from_user(&logout, pdata->reqData, sizeof(logout)); + +- pDLogout = (PNwdCLogoutIdentity) cmd->data; +- cmd->dataLen = datalen; +- pDLogout->AuthenticationId = logout.AuthenticationId; +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ pDLogout = (struct nwc_lo_id *) cmd->data; ++ cmd->dataLen = datalen; ++ pDLogout->AuthenticationId = logout.AuthenticationId; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + } + +-/*++======================================================================*/ +-int NwUnlicenseConn(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCUnlicenseConn pUconn; +- NwcUnlicenseConn ulc; ++int novfs_unlicense_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_unlic_conn *pUconn, ulc; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + cpylen = copy_from_user(&ulc, pdata->reqData, sizeof(ulc)); + datalen = sizeof(*pUconn); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_UNLICENSE_CONN; +- cmd->dataLen = datalen; +- pUconn = (PNwdCUnlicenseConn) cmd->data; +- +- pUconn->ConnHandle = (HANDLE) (unsigned long) ulc.ConnHandle; +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- /* +- * we got reply data from the daemon +- */ +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_UNLICENSE_CONN; ++ cmd->dataLen = datalen; ++ pUconn = (struct nwc_unlic_conn *) cmd->data; + +- kfree(cmd); ++ pUconn->ConnHandle = (void *) (unsigned long) ulc.ConnHandle; ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ /* ++ * we got reply data from the daemon ++ */ ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } + return (retCode); + + } + +-/*++======================================================================*/ +-int NwUnAuthenticate(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcUnauthenticate auth; +- PNwdCUnauthenticate pDAuth; ++int novfs_unauthenticate(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_unauthenticate auth, *pDAuth; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDAuth); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = (struct novfs_xplat_call_request *)kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_UNAUTHENTICATE_CONN; +- +- cpylen = copy_from_user(&auth, pdata->reqData, sizeof(auth)); +- +- pDAuth = (PNwdCUnauthenticate) cmd->data; +- cmd->dataLen = datalen; +- pDAuth->AuthenticationId = auth.AuthenticationId; +- pDAuth->ConnHandle = (HANDLE) (unsigned long) auth.ConnHandle; +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ if (!cmd) ++ return -ENOMEM; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_UNAUTHENTICATE_CONN; ++ ++ cpylen = copy_from_user(&auth, pdata->reqData, sizeof(auth)); ++ ++ pDAuth = (struct nwc_unauthenticate *) cmd->data; ++ cmd->dataLen = datalen; ++ pDAuth->AuthenticationId = auth.AuthenticationId; ++ pDAuth->ConnHandle = (void *) (unsigned long) auth.ConnHandle; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwGetConnInfo(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcGetConnInfo connInfo; +- PNwdCGetConnInfo pDConnInfo; ++int novfs_get_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_get_conn_info connInfo; ++ struct nwd_conn_info *pDConnInfo; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + cpylen = +- copy_from_user(&connInfo, pdata->reqData, sizeof(NwcGetConnInfo)); ++ copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_get_conn_info)); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_GET_CONN_INFO; +- +- pDConnInfo = (PNwdCGetConnInfo) cmd->data; +- +- pDConnInfo->ConnHandle = (HANDLE) (unsigned long) connInfo.ConnHandle; +- pDConnInfo->uInfoLevel = connInfo.uInfoLevel; +- pDConnInfo->uInfoLength = connInfo.uInfoLength; +- cmd->dataLen = sizeof(*pDConnInfo); +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- if (!retCode) { +- GetConnData(&connInfo, cmd, reply); +- } ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_CONN_INFO; + +- kfree(reply); ++ pDConnInfo = (struct nwd_conn_info *) cmd->data; ++ ++ pDConnInfo->ConnHandle = (void *) (unsigned long) connInfo.ConnHandle; ++ pDConnInfo->uInfoLevel = connInfo.uInfoLevel; ++ pDConnInfo->uInfoLength = connInfo.uInfoLength; ++ cmd->dataLen = sizeof(*pDConnInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ GetConnData(&connInfo, cmd, reply); + } +- kfree(cmd); + ++ kfree(reply); + } +- ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwSetConnInfo(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcSetConnInfo connInfo; +- PNwdCSetConnInfo pDConnInfo; ++int novfs_set_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_set_conn_info connInfo; ++ struct nwd_set_conn_info *pDConnInfo; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + cpylen = +- copy_from_user(&connInfo, pdata->reqData, sizeof(NwcSetConnInfo)); ++ copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_set_conn_info)); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SET_CONN_INFO; +- +- pDConnInfo = (PNwdCSetConnInfo) cmd->data; +- +- pDConnInfo->ConnHandle = (HANDLE) (unsigned long) connInfo.ConnHandle; +- pDConnInfo->uInfoLevel = connInfo.uInfoLevel; +- pDConnInfo->uInfoLength = connInfo.uInfoLength; +- cmd->dataLen = sizeof(*pDConnInfo); +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ if (!cmd) ++ return -ENOMEM; + +- } ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_CONN_INFO; + ++ pDConnInfo = (struct nwd_set_conn_info *) cmd->data; ++ ++ pDConnInfo->ConnHandle = (void *) (unsigned long) connInfo.ConnHandle; ++ pDConnInfo->uInfoLevel = connInfo.uInfoLevel; ++ pDConnInfo->uInfoLength = connInfo.uInfoLength; ++ cmd->dataLen = sizeof(*pDConnInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwGetIdentityInfo(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcGetIdentityInfo qidInfo, *gId; +- PNwdCGetIdentityInfo idInfo; +- NwcString xferStr; ++int novfs_get_id_info(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_get_id_info qidInfo, *gId; ++ struct nwd_get_id_info *idInfo; ++ struct nwc_string xferStr; + char *str; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cmdlen = sizeof(*cmd) + sizeof(*idInfo); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + cpylen = copy_from_user(&qidInfo, pdata->reqData, sizeof(qidInfo)); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_GET_IDENTITY_INFO; +- +- idInfo = (PNwdCGetIdentityInfo) cmd->data; +- +- idInfo->AuthenticationId = qidInfo.AuthenticationId; +- cmd->dataLen = sizeof(*idInfo); +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- +- if (!reply->Reply.ErrorCode) { +- /* +- * Save the return info to the user structure. +- */ +- gId = pdata->reqData; +- idInfo = (PNwdCGetIdentityInfo) reply->data; +- cpylen = +- copy_to_user(&gId->AuthenticationId, +- &idInfo->AuthenticationId, +- sizeof(idInfo-> ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_IDENTITY_INFO; ++ ++ idInfo = (struct nwd_get_id_info *) cmd->data; ++ ++ idInfo->AuthenticationId = qidInfo.AuthenticationId; ++ cmd->dataLen = sizeof(*idInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ ++ if (!reply->Reply.ErrorCode) { ++ /* ++ * Save the return info to the user structure. ++ */ ++ gId = pdata->reqData; ++ idInfo = (struct nwd_get_id_info *) reply->data; ++ cpylen = ++ copy_to_user(&gId->AuthenticationId, ++ &idInfo->AuthenticationId, ++ sizeof(idInfo-> + AuthenticationId)); +- cpylen = +- copy_to_user(&gId->AuthType, +- &idInfo->AuthType, +- sizeof(idInfo->AuthType)); +- cpylen = +- copy_to_user(&gId->IdentityFlags, +- &idInfo->IdentityFlags, +- sizeof(idInfo->IdentityFlags)); +- cpylen = +- copy_to_user(&gId->NameType, +- &idInfo->NameType, +- sizeof(idInfo->NameType)); +- cpylen = +- copy_to_user(&gId->ObjectType, +- &idInfo->ObjectType, +- sizeof(idInfo->ObjectType)); +- +- cpylen = +- copy_from_user(&xferStr, gId->pDomainName, +- sizeof(NwcString)); +- str = +- (char *)((char *)reply->data + +- idInfo->pDomainNameOffset); +- cpylen = +- copy_to_user(xferStr.pBuffer, str, +- idInfo->domainLen); +- xferStr.DataType = NWC_STRING_TYPE_ASCII; +- xferStr.DataLen = idInfo->domainLen; +- cpylen = +- copy_to_user(gId->pDomainName, &xferStr, +- sizeof(NwcString)); +- +- cpylen = +- copy_from_user(&xferStr, gId->pObjectName, +- sizeof(NwcString)); +- str = +- (char *)((char *)reply->data + +- idInfo->pObjectNameOffset); +- cpylen = +- copy_to_user(xferStr.pBuffer, str, +- idInfo->objectLen); +- xferStr.DataLen = idInfo->objectLen - 1; +- xferStr.DataType = NWC_STRING_TYPE_ASCII; +- cpylen = +- copy_to_user(gId->pObjectName, &xferStr, +- sizeof(NwcString)); +- } ++ cpylen = ++ copy_to_user(&gId->AuthType, ++ &idInfo->AuthType, ++ sizeof(idInfo->AuthType)); ++ cpylen = ++ copy_to_user(&gId->IdentityFlags, ++ &idInfo->IdentityFlags, ++ sizeof(idInfo->IdentityFlags)); ++ cpylen = ++ copy_to_user(&gId->NameType, ++ &idInfo->NameType, ++ sizeof(idInfo->NameType)); ++ cpylen = ++ copy_to_user(&gId->ObjectType, ++ &idInfo->ObjectType, ++ sizeof(idInfo->ObjectType)); + +- kfree(reply); ++ cpylen = ++ copy_from_user(&xferStr, gId->pDomainName, ++ sizeof(struct nwc_string)); ++ str = ++ (char *)((char *)reply->data + ++ idInfo->pDomainNameOffset); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ idInfo->domainLen); ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ xferStr.DataLen = idInfo->domainLen; ++ cpylen = ++ copy_to_user(gId->pDomainName, &xferStr, ++ sizeof(struct nwc_string)); ++ ++ cpylen = ++ copy_from_user(&xferStr, gId->pObjectName, ++ sizeof(struct nwc_string)); ++ str = ++ (char *)((char *)reply->data + ++ idInfo->pObjectNameOffset); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ idInfo->objectLen); ++ xferStr.DataLen = idInfo->objectLen - 1; ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ cpylen = ++ copy_to_user(gId->pObjectName, &xferStr, ++ sizeof(struct nwc_string)); + } +- kfree(cmd); + ++ kfree(reply); + } +- ++ kfree(cmd); + return (retCode); + } + +-/*++======================================================================*/ +-int NwScanConnInfo(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcScanConnInfo connInfo, *rInfo; +- PNwdCScanConnInfo pDConnInfo; ++int novfs_scan_conn_info(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_scan_conn_info connInfo, *rInfo; ++ struct nwd_scan_conn_info *pDConnInfo; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + unsigned char *localData; + + cpylen = +- copy_from_user(&connInfo, pdata->reqData, sizeof(NwcScanConnInfo)); ++ copy_from_user(&connInfo, pdata->reqData, sizeof(struct nwc_scan_conn_info)); + + cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo) + connInfo.uScanInfoLen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SCAN_CONN_INFO; +- +- pDConnInfo = (PNwdCScanConnInfo) cmd->data; +- +- DbgPrint("NwScanConnInfo: Input Data\n"); +- DbgPrint("connInfo.uScanIndex = 0x%X\n", connInfo.uScanIndex); +- DbgPrint("connInfo.uConnectionReference = 0x%X\n", +- connInfo.uConnectionReference); +- DbgPrint("connInfo.uScanInfoLevel = 0x%X\n", +- connInfo.uScanInfoLevel); +- DbgPrint("connInfo.uScanInfoLen = 0x%X\n", +- connInfo.uScanInfoLen); +- DbgPrint("connInfo.uReturnInfoLength = 0x%X\n", +- connInfo.uReturnInfoLength); +- DbgPrint("connInfo.uReturnInfoLevel = 0x%X\n", +- connInfo.uReturnInfoLevel); +- DbgPrint("connInfo.uScanFlags = 0x%X\n", connInfo.uScanFlags); +- +- pDConnInfo->uScanIndex = connInfo.uScanIndex; +- pDConnInfo->uConnectionReference = +- connInfo.uConnectionReference; +- pDConnInfo->uScanInfoLevel = connInfo.uScanInfoLevel; +- pDConnInfo->uScanInfoLen = connInfo.uScanInfoLen; +- pDConnInfo->uReturnInfoLength = connInfo.uReturnInfoLength; +- pDConnInfo->uReturnInfoLevel = connInfo.uReturnInfoLevel; +- pDConnInfo->uScanFlags = connInfo.uScanFlags; +- +- if (pDConnInfo->uScanInfoLen) { +- localData = (unsigned char *) pDConnInfo; +- pDConnInfo->uScanConnInfoOffset = sizeof(*pDConnInfo); +- localData += pDConnInfo->uScanConnInfoOffset; +- cpylen = +- copy_from_user(localData, connInfo.pScanConnInfo, +- connInfo.uScanInfoLen); +- } else { +- pDConnInfo->uScanConnInfoOffset = 0; +- } ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SCAN_CONN_INFO; ++ ++ pDConnInfo = (struct nwd_scan_conn_info *) cmd->data; ++ ++ DbgPrint("NwScanConnInfo: Input Data\n"); ++ DbgPrint("connInfo.uScanIndex = 0x%X\n", connInfo.uScanIndex); ++ DbgPrint("connInfo.uConnectionReference = 0x%X\n", ++ connInfo.uConnectionReference); ++ DbgPrint("connInfo.uScanInfoLevel = 0x%X\n", ++ connInfo.uScanInfoLevel); ++ DbgPrint("connInfo.uScanInfoLen = 0x%X\n", ++ connInfo.uScanInfoLen); ++ DbgPrint("connInfo.uReturnInfoLength = 0x%X\n", ++ connInfo.uReturnInfoLength); ++ DbgPrint("connInfo.uReturnInfoLevel = 0x%X\n", ++ connInfo.uReturnInfoLevel); ++ DbgPrint("connInfo.uScanFlags = 0x%X\n", connInfo.uScanFlags); ++ ++ pDConnInfo->uScanIndex = connInfo.uScanIndex; ++ pDConnInfo->uConnectionReference = ++ connInfo.uConnectionReference; ++ pDConnInfo->uScanInfoLevel = connInfo.uScanInfoLevel; ++ pDConnInfo->uScanInfoLen = connInfo.uScanInfoLen; ++ pDConnInfo->uReturnInfoLength = connInfo.uReturnInfoLength; ++ pDConnInfo->uReturnInfoLevel = connInfo.uReturnInfoLevel; ++ pDConnInfo->uScanFlags = connInfo.uScanFlags; ++ ++ if (pDConnInfo->uScanInfoLen) { ++ localData = (unsigned char *) pDConnInfo; ++ pDConnInfo->uScanConnInfoOffset = sizeof(*pDConnInfo); ++ localData += pDConnInfo->uScanConnInfoOffset; ++ cpylen = ++ copy_from_user(localData, connInfo.pScanConnInfo, ++ connInfo.uScanInfoLen); ++ } else { ++ pDConnInfo->uScanConnInfoOffset = 0; ++ } ++ ++ cmd->dataLen = sizeof(*pDConnInfo); + +- cmd->dataLen = sizeof(*pDConnInfo); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ DbgPrint("NwScanConnInfo: Reply recieved\n"); ++ DbgPrint(" NextIndex = %x\n", connInfo.uScanIndex); ++ DbgPrint(" ErrorCode = %x\n", reply->Reply.ErrorCode); ++ DbgPrint(" data = %x\n", reply->data); + +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- DbgPrint("NwScanConnInfo: Reply recieved\n"); +- DbgPrint(" NextIndex = %x\n", connInfo.uScanIndex); +- DbgPrint(" ErrorCode = %x\n", reply->Reply.ErrorCode); +- DbgPrint(" data = %x\n", reply->data); +- +- pDConnInfo = (PNwdCScanConnInfo) reply->data; +- retCode = (unsigned long) reply->Reply.ErrorCode; +- if (!retCode) { +- GetUserData(&connInfo, cmd, reply); +- rInfo = (NwcScanConnInfo *) pdata->repData; +- cpylen = +- copy_to_user(pdata->repData, +- &pDConnInfo->uScanIndex, +- sizeof(pDConnInfo-> ++ pDConnInfo = (struct nwd_scan_conn_info *) reply->data; ++ retCode = (unsigned long) reply->Reply.ErrorCode; ++ if (!retCode) { ++ GetUserData(&connInfo, cmd, reply); ++ rInfo = (struct nwc_scan_conn_info *) pdata->repData; ++ cpylen = ++ copy_to_user(pdata->repData, ++ &pDConnInfo->uScanIndex, ++ sizeof(pDConnInfo-> + uScanIndex)); +- cpylen = +- copy_to_user(&rInfo->uConnectionReference, +- &pDConnInfo-> +- uConnectionReference, +- sizeof(pDConnInfo-> ++ cpylen = ++ copy_to_user(&rInfo->uConnectionReference, ++ &pDConnInfo-> ++ uConnectionReference, ++ sizeof(pDConnInfo-> + uConnectionReference)); +- } else { +- unsigned long x; ++ } else { ++ unsigned long x; + +- x = 0; +- rInfo = (NwcScanConnInfo *) pdata->reqData; +- cpylen = +- copy_to_user(&rInfo->uConnectionReference, +- &x, +- sizeof(rInfo-> ++ x = 0; ++ rInfo = (struct nwc_scan_conn_info *) pdata->reqData; ++ cpylen = ++ copy_to_user(&rInfo->uConnectionReference, ++ &x, ++ sizeof(rInfo-> + uConnectionReference)); +- } +- +- kfree(reply); +- } else { +- retCode = -EIO; + } +- kfree(cmd); + ++ kfree(reply); ++ } else { ++ retCode = -EIO; + } +- ++ kfree(cmd); + return (retCode); + } + +-/*++======================================================================*/ +-static void GetUserData(NwcScanConnInfo * connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply) + /* +- * Abstract: Copies the user data out of the scan conn info call. +- * +- *========================================================================*/ ++ * Copies the user data out of the scan conn info call. ++ */ ++static void GetUserData(struct nwc_scan_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply) + { + unsigned long uLevel; +- PNwdCScanConnInfo pDConnInfo; ++ struct nwd_scan_conn_info *pDConnInfo; + + unsigned char *srcData = NULL; + unsigned long dataLen = 0, cpylen; + +- pDConnInfo = (PNwdCScanConnInfo) reply->data; ++ pDConnInfo = (struct nwd_scan_conn_info *) reply->data; + uLevel = pDConnInfo->uReturnInfoLevel; + DbgPrint + ("[GetUserData] uLevel = %d, reply = 0x%p, reply->data = 0x%X\n", +@@ -1224,7 +1077,7 @@ static void GetUserData(NwcScanConnInfo + case NWC_CONN_INFO_TRAN_ADDR: + { + unsigned char *dstData = connInfo->pReturnConnInfo; +- NwcTranAddr tranAddr; ++ struct nwc_tran_addr tranAddr; + + srcData = (unsigned char *) reply->data; + dataLen = reply->dataLen; +@@ -1238,20 +1091,20 @@ static void GetUserData(NwcScanConnInfo + sizeof(tranAddr)); + + srcData += +- ((PNwdCScanConnInfo) srcData)-> ++ ((struct nwd_scan_conn_info *) srcData)-> + uReturnConnInfoOffset; + + tranAddr.uTransportType = +- ((PNwdTranAddr) srcData)->uTransportType; ++ ((struct nwd_tran_addr *) srcData)->uTransportType; + tranAddr.uAddressLength = +- ((PNwdTranAddr) srcData)->uAddressLength; ++ ((struct tagNwdTranAddrEx *) srcData)->uAddressLength; + + cpylen = + copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); + cpylen = + copy_to_user(tranAddr.puAddress, +- ((PNwdTranAddr) srcData)->Buffer, +- ((PNwdTranAddr) srcData)-> ++ ((struct tagNwdTranAddrEx *) srcData)->Buffer, ++ ((struct tagNwdTranAddrEx *) srcData)-> + uAddressLength); + dataLen = 0; + break; +@@ -1276,20 +1129,18 @@ static void GetUserData(NwcScanConnInfo + return; + } + +-/*++======================================================================*/ +-static void GetConnData(NwcGetConnInfo * connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply) + /* +- * Abstract: Copies the user data out of the scan conn info call. +- * +- *========================================================================*/ ++ * Copies the user data out of the scan conn info call. ++ */ ++static void GetConnData(struct nwc_get_conn_info * connInfo, struct novfs_xplat_call_request *cmd, struct novfs_xplat_call_reply *reply) + { + unsigned long uLevel; +- PNwdCGetConnInfo pDConnInfo; ++ struct nwd_conn_info * pDConnInfo; + + unsigned char *srcData = NULL; + unsigned long dataLen = 0, cpylen; + +- pDConnInfo = (PNwdCGetConnInfo) cmd->data; ++ pDConnInfo = (struct nwd_conn_info *) cmd->data; + uLevel = pDConnInfo->uInfoLevel; + + switch (uLevel) { +@@ -1305,7 +1156,7 @@ static void GetConnData(NwcGetConnInfo * + case NWC_CONN_INFO_TRAN_ADDR: + { + unsigned char *dstData = connInfo->pConnInfo; +- NwcTranAddr tranAddr; ++ struct nwc_tran_addr tranAddr; + + srcData = (unsigned char *) reply->data; + +@@ -1313,16 +1164,16 @@ static void GetConnData(NwcGetConnInfo * + copy_from_user(&tranAddr, dstData, + sizeof(tranAddr)); + tranAddr.uTransportType = +- ((PNwdTranAddr) srcData)->uTransportType; ++ ((struct tagNwdTranAddrEx *) srcData)->uTransportType; + tranAddr.uAddressLength = +- ((PNwdTranAddr) srcData)->uAddressLength; ++ ((struct tagNwdTranAddrEx *) srcData)->uAddressLength; + + cpylen = + copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); + cpylen = + copy_to_user(tranAddr.puAddress, +- ((PNwdTranAddr) srcData)->Buffer, +- ((PNwdTranAddr) srcData)-> ++ ((struct tagNwdTranAddrEx *) srcData)->Buffer, ++ ((struct tagNwdTranAddrEx *) srcData)-> + uAddressLength); + dataLen = 0; + break; +@@ -1376,343 +1227,282 @@ static void GetConnData(NwcGetConnInfo * + return; + } + +-/*++======================================================================*/ +-int NwGetDaemonVersion(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCGetRequesterVersion pDVersion; ++int novfs_get_daemon_ver(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwd_get_reqversion *pDVersion; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + + datalen = sizeof(*pDVersion); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_GET_REQUESTER_VERSION; +- cmdlen = sizeof(*cmd); +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- pDVersion = (PNwdCGetRequesterVersion) reply->data; +- cpylen = +- copy_to_user(pDVersion, pdata->reqData, +- sizeof(*pDVersion)); +- kfree(reply); +- } +- kfree(cmd); +- } +- return (retCode); +- +-} ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +-/*++======================================================================*/ +-int NwcGetPreferredDSTree(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCGetPreferredDsTree pDGetTree; +- NwcGetPreferredDsTree xplatCall, *p; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_REQUESTER_VERSION; ++ cmdlen = sizeof(*cmd); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ pDVersion = (struct nwd_get_reqversion *) reply->data; ++ cpylen = ++ copy_to_user(pDVersion, pdata->reqData, ++ sizeof(*pDVersion)); ++ kfree(reply); ++ } ++ kfree(cmd); ++ return (retCode); ++ ++} ++ ++int novfs_get_preferred_DS_tree(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwd_get_pref_ds_tree *pDGetTree; ++ struct nwc_get_pref_ds_tree xplatCall, *p; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + unsigned char *dPtr; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcGetPreferredDsTree)); ++ sizeof(struct nwc_get_pref_ds_tree)); + datalen = sizeof(*pDGetTree) + xplatCall.uTreeLength; + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_GET_PREFERRED_DS_TREE; +- cmdlen = sizeof(*cmd); +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- if (!retCode) { +- pDGetTree = +- (PNwdCGetPreferredDsTree) reply->data; +- dPtr = +- reply->data + pDGetTree->DsTreeNameOffset; +- p = (NwcGetPreferredDsTree *) pdata->reqData; +- +- DbgPrint +- ("NwcGetPreferredDSTree: Reply recieved\n"); +- DbgPrint(" TreeLen = %x\n", +- pDGetTree->uTreeLength); +- DbgPrint(" TreeName = %s\n", dPtr); +- +- cpylen = +- copy_to_user(p, &pDGetTree->uTreeLength, 4); +- cpylen = +- copy_to_user(xplatCall.pDsTreeName, dPtr, +- pDGetTree->uTreeLength); +- } +- kfree(reply); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_PREFERRED_DS_TREE; ++ cmdlen = sizeof(*cmd); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ pDGetTree = ++ (struct nwd_get_pref_ds_tree *) reply->data; ++ dPtr = ++ reply->data + pDGetTree->DsTreeNameOffset; ++ p = (struct nwc_get_pref_ds_tree *) pdata->reqData; ++ ++ DbgPrint ++ ("NwcGetPreferredDSTree: Reply recieved\n"); ++ DbgPrint(" TreeLen = %x\n", ++ pDGetTree->uTreeLength); ++ DbgPrint(" TreeName = %s\n", dPtr); ++ ++ cpylen = ++ copy_to_user(p, &pDGetTree->uTreeLength, 4); ++ cpylen = ++ copy_to_user(xplatCall.pDsTreeName, dPtr, ++ pDGetTree->uTreeLength); + } +- kfree(cmd); ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwcSetPreferredDSTree(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- PNwdCSetPreferredDsTree pDSetTree; +- NwcSetPreferredDsTree xplatCall; ++int novfs_set_preferred_DS_tree(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwd_set_pref_ds_tree *pDSetTree; ++ struct nwc_set_pref_ds_tree xplatCall; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + unsigned char *dPtr; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcSetPreferredDsTree)); ++ sizeof(struct nwc_set_pref_ds_tree)); + datalen = sizeof(*pDSetTree) + xplatCall.uTreeLength; + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SET_PREFERRED_DS_TREE; +- +- pDSetTree = (PNwdCSetPreferredDsTree) cmd->data; +- pDSetTree->DsTreeNameOffset = sizeof(*pDSetTree); +- pDSetTree->uTreeLength = xplatCall.uTreeLength; ++ if (!cmd) ++ return -ENOMEM; + +- dPtr = cmd->data + sizeof(*pDSetTree); +- cpylen = +- copy_from_user(dPtr, xplatCall.pDsTreeName, +- xplatCall.uTreeLength); ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_PREFERRED_DS_TREE; + +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ pDSetTree = (struct nwd_set_pref_ds_tree *) cmd->data; ++ pDSetTree->DsTreeNameOffset = sizeof(*pDSetTree); ++ pDSetTree->uTreeLength = xplatCall.uTreeLength; ++ ++ dPtr = cmd->data + sizeof(*pDSetTree); ++ cpylen = ++ copy_from_user(dPtr, xplatCall.pDsTreeName, ++ xplatCall.uTreeLength); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwcSetDefaultNameCtx(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcSetDefaultNameContext xplatCall; +- PNwdCSetDefaultNameContext pDSet; ++int novfs_set_default_ctx(struct novfs_xplat *pdata, ++ struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_set_def_name_ctx xplatCall; ++ struct nwd_set_def_name_ctx * pDSet; + int retCode = -ENOMEM; + unsigned long cmdlen, datalen, replylen, cpylen; + unsigned char *dPtr; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcSetDefaultNameContext)); ++ sizeof(struct nwc_set_def_name_ctx)); + datalen = + sizeof(*pDSet) + xplatCall.uTreeLength + xplatCall.uNameLength; + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SET_DEFAULT_NAME_CONTEXT; +- cmd->dataLen = +- sizeof(NwdCSetDefaultNameContext) + xplatCall.uTreeLength + +- xplatCall.uNameLength; +- +- pDSet = (PNwdCSetDefaultNameContext) cmd->data; +- dPtr = cmd->data; +- +- pDSet->TreeOffset = sizeof(NwdCSetDefaultNameContext); +- pDSet->uTreeLength = xplatCall.uTreeLength; +- pDSet->NameContextOffset = +- pDSet->TreeOffset + xplatCall.uTreeLength; +- pDSet->uNameLength = xplatCall.uNameLength; ++ if (!cmd) ++ return -ENOMEM; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_DEFAULT_NAME_CONTEXT; ++ cmd->dataLen = ++ sizeof(struct nwd_set_def_name_ctx) + ++ xplatCall.uTreeLength + xplatCall.uNameLength; ++ ++ pDSet = (struct nwd_set_def_name_ctx *) cmd->data; ++ dPtr = cmd->data; ++ ++ pDSet->TreeOffset = sizeof(struct nwd_set_def_name_ctx); ++ pDSet->uTreeLength = xplatCall.uTreeLength; ++ pDSet->NameContextOffset = ++ pDSet->TreeOffset + xplatCall.uTreeLength; ++ pDSet->uNameLength = xplatCall.uNameLength; + +-//sgled cpylen = copy_from_user(dPtr+pDSet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); +- cpylen = copy_from_user(dPtr + pDSet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled +- cpylen = +- copy_from_user(dPtr + pDSet->NameContextOffset, +- xplatCall.pNameContext, +- xplatCall.uNameLength); +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ //sgled cpylen = copy_from_user(dPtr+pDSet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); ++ cpylen = copy_from_user(dPtr + pDSet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled ++ cpylen = ++ copy_from_user(dPtr + pDSet->NameContextOffset, ++ xplatCall.pNameContext, ++ xplatCall.uNameLength); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + + } + +-/*++======================================================================*/ +-int NwcGetDefaultNameCtx(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcGetDefaultNameContext xplatCall; +- PNwdCGetDefaultNameContext pGet; ++int novfs_get_default_ctx(struct novfs_xplat *pdata, ++ struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_get_def_name_ctx xplatCall; ++ struct nwd_get_def_name_ctx * pGet; + char *dPtr; + int retCode = -ENOMEM; + unsigned long cmdlen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcGetDefaultNameContext)); ++ sizeof(struct nwc_get_def_name_ctx)); + cmdlen = +- sizeof(*cmd) + sizeof(NwdCGetDefaultNameContext) + ++ sizeof(*cmd) + sizeof(struct nwd_get_def_name_ctx ) + + xplatCall.uTreeLength; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_GET_DEFAULT_NAME_CONTEXT; +- cmd->dataLen = +- sizeof(NwdCGetDefaultNameContext) + xplatCall.uTreeLength; +- +- pGet = (PNwdCGetDefaultNameContext) cmd->data; +- dPtr = cmd->data; +- +- pGet->TreeOffset = sizeof(NwdCGetDefaultNameContext); +- pGet->uTreeLength = xplatCall.uTreeLength; +- +-//sgled cpylen = copy_from_user( dPtr + pGet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); +- cpylen = copy_from_user(dPtr + pGet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled +- dPtr[pGet->TreeOffset + pGet->uTreeLength] = 0; +- +- retCode = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- retCode = reply->Reply.ErrorCode; +- if (!retCode) { +- pGet = (PNwdCGetDefaultNameContext) reply->data; +- +- DbgPrint +- ("NwcGetDefaultNameCtx: retCode=0x%x uNameLength1=%d uNameLength2=%d\n", +- retCode, pGet->uNameLength, +- xplatCall.uNameLength); +- if (xplatCall.uNameLength < pGet->uNameLength) { +- pGet->uNameLength = +- xplatCall.uNameLength; +- retCode = NWE_BUFFER_OVERFLOW; +- } +- dPtr = (char *)pGet + pGet->NameContextOffset; +- cpylen = +- copy_to_user(xplatCall.pNameContext, dPtr, +- pGet->uNameLength); +- } ++ if (!cmd) ++ return -ENOMEM; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_DEFAULT_NAME_CONTEXT; ++ cmd->dataLen = ++ sizeof(struct nwd_get_def_name_ctx) + xplatCall.uTreeLength; ++ ++ pGet = (struct nwd_get_def_name_ctx *) cmd->data; ++ dPtr = cmd->data; ++ ++ pGet->TreeOffset = sizeof(struct nwd_get_def_name_ctx ); ++ pGet->uTreeLength = xplatCall.uTreeLength; ++ ++ //sgled cpylen = copy_from_user( dPtr + pGet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); ++ cpylen = copy_from_user(dPtr + pGet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled ++ dPtr[pGet->TreeOffset + pGet->uTreeLength] = 0; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ pGet = (struct nwd_get_def_name_ctx *) reply->data; + +- kfree(reply); ++ DbgPrint ++ ("NwcGetDefaultNameCtx: retCode=0x%x uNameLength1=%d uNameLength2=%d\n", ++ retCode, pGet->uNameLength, ++ xplatCall.uNameLength); ++ if (xplatCall.uNameLength < pGet->uNameLength) { ++ pGet->uNameLength = ++ xplatCall.uNameLength; ++ retCode = NWE_BUFFER_OVERFLOW; ++ } ++ dPtr = (char *)pGet + pGet->NameContextOffset; ++ cpylen = ++ copy_to_user(xplatCall.pNameContext, dPtr, ++ pGet->uNameLength); + } +- kfree(cmd); ++ ++ kfree(reply); + } ++ kfree(cmd); + return (retCode); + + } + +-int NwQueryFeature(PXPLAT pdata, session_t Session) ++int novfs_query_feature(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- NwcQueryFeature xpCall; ++ struct nwc_query_feature xpCall; + int status = 0; + unsigned long cpylen; + + cpylen = +- copy_from_user(&xpCall, pdata->reqData, sizeof(NwcQueryFeature)); ++ copy_from_user(&xpCall, pdata->reqData, sizeof(struct nwc_query_feature)); + switch (xpCall.Feature) { + case NWC_FEAT_NDS: + case NWC_FEAT_NDS_MTREE: +@@ -1725,372 +1515,306 @@ int NwQueryFeature(PXPLAT pdata, session + return (status); + } + +-/*++======================================================================*/ +-int NwcGetTreeMonitoredConn(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcGetTreeMonitoredConnRef xplatCall, *p; +- PNwdCGetTreeMonitoredConnRef pDConnRef; ++int novfs_get_tree_monitored_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_get_tree_monitored_conn_ref xplatCall, *p; ++ struct nwd_get_tree_monitored_conn_ref *pDConnRef; + char *dPtr; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcGetTreeMonitoredConnRef)); ++ sizeof(struct nwc_get_tree_monitored_conn_ref)); + datalen = sizeof(*pDConnRef) + xplatCall.pTreeName->DataLen; + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_GET_TREE_MONITORED_CONN_REF; +- +- pDConnRef = (PNwdCGetTreeMonitoredConnRef) cmd->data; +- pDConnRef->TreeName.boffset = sizeof(*pDConnRef); +- pDConnRef->TreeName.len = xplatCall.pTreeName->DataLen; +- pDConnRef->TreeName.type = xplatCall.pTreeName->DataType; ++ if (!cmd) ++ return -ENOMEM; + +- dPtr = cmd->data + sizeof(*pDConnRef); +- cpylen = +- copy_from_user(dPtr, xplatCall.pTreeName->pBuffer, +- pDConnRef->TreeName.len); +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- pDConnRef = (PNwdCGetTreeMonitoredConnRef) reply->data; +- dPtr = reply->data + pDConnRef->TreeName.boffset; +- p = (NwcGetTreeMonitoredConnRef *) pdata->reqData; +- cpylen = +- copy_to_user(&p->uConnReference, +- &pDConnRef->uConnReference, 4); ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_TREE_MONITORED_CONN_REF; + +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ pDConnRef = (struct nwd_get_tree_monitored_conn_ref *) cmd->data; ++ pDConnRef->TreeName.boffset = sizeof(*pDConnRef); ++ pDConnRef->TreeName.len = xplatCall.pTreeName->DataLen; ++ pDConnRef->TreeName.type = xplatCall.pTreeName->DataType; + +- } ++ dPtr = cmd->data + sizeof(*pDConnRef); ++ cpylen = ++ copy_from_user(dPtr, xplatCall.pTreeName->pBuffer, ++ pDConnRef->TreeName.len); ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ pDConnRef = (struct nwd_get_tree_monitored_conn_ref *) reply->data; ++ dPtr = reply->data + pDConnRef->TreeName.boffset; ++ p = (struct nwc_get_tree_monitored_conn_ref *) pdata->reqData; ++ cpylen = ++ copy_to_user(&p->uConnReference, ++ &pDConnRef->uConnReference, 4); + ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwcEnumIdentities(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcEnumerateIdentities xplatCall, *eId; +- PNwdCEnumerateIdentities pEnum; +- NwcString xferStr; ++int novfs_enum_ids(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_enum_ids xplatCall, *eId; ++ struct nwd_enum_ids *pEnum; ++ struct nwc_string xferStr; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcEnumerateIdentities)); ++ sizeof(struct nwc_enum_ids)); + datalen = sizeof(*pEnum); + cmdlen = datalen + sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_ENUMERATE_IDENTITIES; +- +- DbgPrint("NwcEnumIdentities: Send Request\n"); +- DbgPrint(" iterator = %x\n", xplatCall.Iterator); +- DbgPrint(" cmdlen = %d\n", cmdlen); +- +- pEnum = (PNwdCEnumerateIdentities) cmd->data; +- pEnum->Iterator = xplatCall.Iterator; +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- status = reply->Reply.ErrorCode; +- +- eId = pdata->repData; +- pEnum = (PNwdCEnumerateIdentities) reply->data; +- cpylen = +- copy_to_user(&eId->Iterator, &pEnum->Iterator, +- sizeof(pEnum->Iterator)); +- DbgPrint("[XPLAT NWCAPI] Found AuthId 0x%X\n", +- pEnum->AuthenticationId); +- cpylen = +- copy_to_user(&eId->AuthenticationId, +- &pEnum->AuthenticationId, +- sizeof(pEnum->AuthenticationId)); +- cpylen = +- copy_to_user(&eId->AuthType, &pEnum->AuthType, +- sizeof(pEnum->AuthType)); +- cpylen = +- copy_to_user(&eId->IdentityFlags, +- &pEnum->IdentityFlags, +- sizeof(pEnum->IdentityFlags)); +- cpylen = +- copy_to_user(&eId->NameType, &pEnum->NameType, +- sizeof(pEnum->NameType)); +- cpylen = +- copy_to_user(&eId->ObjectType, &pEnum->ObjectType, +- sizeof(pEnum->ObjectType)); +- +- if (!status) { +- cpylen = +- copy_from_user(&xferStr, eId->pDomainName, +- sizeof(NwcString)); +- str = +- (char *)((char *)reply->data + +- pEnum->domainNameOffset); +- DbgPrint("[XPLAT NWCAPI] Found Domain %s\n", +- str); +- cpylen = +- copy_to_user(xferStr.pBuffer, str, +- pEnum->domainNameLen); +- xferStr.DataType = NWC_STRING_TYPE_ASCII; +- xferStr.DataLen = pEnum->domainNameLen - 1; +- cpylen = +- copy_to_user(eId->pDomainName, &xferStr, +- sizeof(NwcString)); +- +- cpylen = +- copy_from_user(&xferStr, eId->pObjectName, +- sizeof(NwcString)); +- str = +- (char *)((char *)reply->data + +- pEnum->objectNameOffset); +- DbgPrint("[XPLAT NWCAPI] Found User %s\n", str); +- cpylen = +- copy_to_user(xferStr.pBuffer, str, +- pEnum->objectNameLen); +- xferStr.DataType = NWC_STRING_TYPE_ASCII; +- xferStr.DataLen = pEnum->objectNameLen - 1; +- cpylen = +- copy_to_user(eId->pObjectName, &xferStr, +- sizeof(NwcString)); +- } ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_ENUMERATE_IDENTITIES; ++ ++ DbgPrint("NwcEnumIdentities: Send Request\n"); ++ DbgPrint(" iterator = %x\n", xplatCall.Iterator); ++ DbgPrint(" cmdlen = %d\n", cmdlen); + +- kfree(reply); ++ pEnum = (struct nwd_enum_ids *) cmd->data; ++ pEnum->Iterator = xplatCall.Iterator; ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; + ++ eId = pdata->repData; ++ pEnum = (struct nwd_enum_ids *) reply->data; ++ cpylen = ++ copy_to_user(&eId->Iterator, &pEnum->Iterator, ++ sizeof(pEnum->Iterator)); ++ DbgPrint("[XPLAT NWCAPI] Found AuthId 0x%X\n", ++ pEnum->AuthenticationId); ++ cpylen = ++ copy_to_user(&eId->AuthenticationId, ++ &pEnum->AuthenticationId, ++ sizeof(pEnum->AuthenticationId)); ++ cpylen = ++ copy_to_user(&eId->AuthType, &pEnum->AuthType, ++ sizeof(pEnum->AuthType)); ++ cpylen = ++ copy_to_user(&eId->IdentityFlags, ++ &pEnum->IdentityFlags, ++ sizeof(pEnum->IdentityFlags)); ++ cpylen = ++ copy_to_user(&eId->NameType, &pEnum->NameType, ++ sizeof(pEnum->NameType)); ++ cpylen = ++ copy_to_user(&eId->ObjectType, &pEnum->ObjectType, ++ sizeof(pEnum->ObjectType)); ++ ++ if (!status) { ++ cpylen = ++ copy_from_user(&xferStr, eId->pDomainName, ++ sizeof(struct nwc_string)); ++ str = ++ (char *)((char *)reply->data + ++ pEnum->domainNameOffset); ++ DbgPrint("[XPLAT NWCAPI] Found Domain %s\n", ++ str); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ pEnum->domainNameLen); ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ xferStr.DataLen = pEnum->domainNameLen - 1; ++ cpylen = ++ copy_to_user(eId->pDomainName, &xferStr, ++ sizeof(struct nwc_string)); ++ ++ cpylen = ++ copy_from_user(&xferStr, eId->pObjectName, ++ sizeof(struct nwc_string)); ++ str = ++ (char *)((char *)reply->data + ++ pEnum->objectNameOffset); ++ DbgPrint("[XPLAT NWCAPI] Found User %s\n", str); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ pEnum->objectNameLen); ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ xferStr.DataLen = pEnum->objectNameLen - 1; ++ cpylen = ++ copy_to_user(eId->pObjectName, &xferStr, ++ sizeof(struct nwc_string)); + } +- kfree(cmd); ++ ++ kfree(reply); + + } ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwcChangeAuthKey(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Change the password on the server +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcChangeKey xplatCall; +- PNwdCChangeKey pNewKey; +- NwcString xferStr; ++int novfs_change_auth_key(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_change_key xplatCall; ++ struct nwd_change_key *pNewKey; ++ struct nwc_string xferStr; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = +- copy_from_user(&xplatCall, pdata->reqData, sizeof(NwcChangeKey)); ++ copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_change_key)); + + datalen = +- sizeof(NwdCChangeKey) + xplatCall.pDomainName->DataLen + ++ sizeof(struct nwd_change_key) + xplatCall.pDomainName->DataLen + + xplatCall.pObjectName->DataLen + xplatCall.pNewPassword->DataLen + + xplatCall.pVerifyPassword->DataLen; + + cmdlen = sizeof(*cmd) + datalen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- pNewKey = (PNwdCChangeKey) cmd->data; +- cmd->dataLen = datalen; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_CHANGE_KEY; +- +- pNewKey->NameType = xplatCall.NameType; +- pNewKey->ObjectType = xplatCall.ObjectType; +- pNewKey->AuthType = xplatCall.AuthType; +- str = (char *)pNewKey; ++ if (!cmd) ++ return -ENOMEM; + +- /* +- * Get the tree name +- */ +- str += sizeof(*pNewKey); +- cpylen = +- copy_from_user(&xferStr, xplatCall.pDomainName, +- sizeof(NwcString)); +- pNewKey->domainNameOffset = sizeof(*pNewKey); +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->domainNameLen = xferStr.DataLen; ++ pNewKey = (struct nwd_change_key *) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_CHANGE_KEY; + +- /* +- * Get the User Name +- */ +- str += pNewKey->domainNameLen; +- cpylen = +- copy_from_user(&xferStr, xplatCall.pObjectName, +- sizeof(NwcString)); +- pNewKey->objectNameOffset = +- pNewKey->domainNameOffset + pNewKey->domainNameLen; +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->objectNameLen = xferStr.DataLen; ++ pNewKey->NameType = xplatCall.NameType; ++ pNewKey->ObjectType = xplatCall.ObjectType; ++ pNewKey->AuthType = xplatCall.AuthType; ++ str = (char *)pNewKey; + +- /* +- * Get the New Password +- */ +- str += pNewKey->objectNameLen; +- cpylen = +- copy_from_user(&xferStr, xplatCall.pNewPassword, +- sizeof(NwcString)); +- pNewKey->newPasswordOffset = +- pNewKey->objectNameOffset + pNewKey->objectNameLen; +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->newPasswordLen = xferStr.DataLen; ++ /* ++ * Get the tree name ++ */ ++ str += sizeof(*pNewKey); ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pDomainName, ++ sizeof(struct nwc_string)); ++ pNewKey->domainNameOffset = sizeof(*pNewKey); ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->domainNameLen = xferStr.DataLen; + +- /* +- * Get the Verify Password +- */ +- str += pNewKey->newPasswordLen; +- cpylen = +- copy_from_user(&xferStr, xplatCall.pVerifyPassword, +- sizeof(NwcString)); +- pNewKey->verifyPasswordOffset = +- pNewKey->newPasswordOffset + pNewKey->newPasswordLen; +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->verifyPasswordLen = xferStr.DataLen; +- +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } +- memset(cmd, 0, cmdlen); ++ /* ++ * Get the User Name ++ */ ++ str += pNewKey->domainNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pObjectName, ++ sizeof(struct nwc_string)); ++ pNewKey->objectNameOffset = ++ pNewKey->domainNameOffset + pNewKey->domainNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->objectNameLen = xferStr.DataLen; + +- kfree(cmd); ++ /* ++ * Get the New Password ++ */ ++ str += pNewKey->objectNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pNewPassword, ++ sizeof(struct nwc_string)); ++ pNewKey->newPasswordOffset = ++ pNewKey->objectNameOffset + pNewKey->objectNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->newPasswordLen = xferStr.DataLen; ++ ++ /* ++ * Get the Verify Password ++ */ ++ str += pNewKey->newPasswordLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pVerifyPassword, ++ sizeof(struct nwc_string)); ++ pNewKey->verifyPasswordOffset = ++ pNewKey->newPasswordOffset + pNewKey->newPasswordLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->verifyPasswordLen = xferStr.DataLen; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ memset(cmd, 0, cmdlen); + ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwcSetPrimaryConn(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Set the primary connection Id +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcSetPrimaryConnection xplatCall; +- PNwdCSetPrimaryConnection pConn; ++int novfs_set_pri_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_set_primary_conn xplatCall; ++ struct nwd_set_primary_conn *pConn; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = + copy_from_user(&xplatCall, pdata->reqData, +- sizeof(NwcSetPrimaryConnection)); ++ sizeof(struct nwc_set_primary_conn)); + +- datalen = sizeof(NwdCSetPrimaryConnection); ++ datalen = sizeof(struct nwd_set_primary_conn); + cmdlen = sizeof(*cmd) + datalen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { +- pConn = (PNwdCSetPrimaryConnection) cmd->data; +- cmd->dataLen = datalen; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SET_PRIMARY_CONN; +- pConn->ConnHandle = (HANDLE) (unsigned long) xplatCall.ConnHandle; +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- +- if (reply) { +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +- kfree(cmd); +- } ++ pConn = (struct nwd_set_primary_conn *) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_PRIMARY_CONN; ++ pConn->ConnHandle = (void *) (unsigned long) xplatCall.ConnHandle; ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); + ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwcGetPrimaryConn(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Get the Primary connection +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_get_pri_conn(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- XPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++ struct novfs_xplat_call_request cmd; ++ struct novfs_xplat_call_reply *reply; + unsigned long status = -ENOMEM, cmdlen, replylen, cpylen; + +- cmdlen = (unsigned long) (&((PXPLAT_CALL_REQUEST) 0)->data); ++ cmdlen = (unsigned long) (&((struct novfs_xplat_call_request *) 0)->data); + + cmd.dataLen = 0; + cmd.Command.CommandType = VFS_COMMAND_XPLAT_CALL; +@@ -2099,15 +1823,15 @@ int NwcGetPrimaryConn(PXPLAT pdata, sess + cmd.NwcCommand = NWC_GET_PRIMARY_CONN; + + status = +- Queue_Daemon_Command((void *)&cmd, cmdlen, NULL, 0, (void **)&reply, +- &replylen, INTERRUPTIBLE); ++ Queue_Daemon_Command((void *)&cmd, cmdlen, NULL, 0, (void **)&reply, ++ &replylen, INTERRUPTIBLE); + + if (reply) { + status = reply->Reply.ErrorCode; + if (!status) { + cpylen = +- copy_to_user(pdata->repData, reply->data, +- sizeof(unsigned long)); ++ copy_to_user(pdata->repData, reply->data, ++ sizeof(unsigned long)); + } + + kfree(reply); +@@ -2116,26 +1840,13 @@ int NwcGetPrimaryConn(PXPLAT pdata, sess + return (status); + } + +-/*++======================================================================*/ +-int NwcSetMapDrive(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Get the Primary connection +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) + { + +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; + unsigned long status = 0, datalen, cmdlen, replylen, cpylen; +- NwcMapDriveEx symInfo; ++ struct nwc_map_drive_ex symInfo; + + DbgPrint("Call to NwcSetMapDrive\n"); + cpylen = copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo)); +@@ -2151,53 +1862,41 @@ int NwcSetMapDrive(PXPLAT pdata, session + DbgPrint(" symInfo.linkOffsetLength = %d\n", symInfo.linkOffsetLength); + DbgPrint(" pdata->datalen = %d\n", pdata->reqLen); + +- mydump(sizeof(symInfo), &symInfo); ++ novfs_dump(sizeof(symInfo), &symInfo); + + cmdlen += datalen; + +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { +- cmd->dataLen = datalen; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_MAP_DRIVE; +- +- cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- +- if (reply) { +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_MAP_DRIVE; ++ ++ cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); + } ++ kfree(cmd); + return (status); + + } + +-/*++======================================================================*/ +-int NwcUnMapDrive(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Get the Primary connection +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; + unsigned long status = 0, datalen, cmdlen, replylen, cpylen; +- NwcUnmapDriveEx symInfo; ++ struct nwc_unmap_drive_ex symInfo; + + DbgPrint("Call to NwcUnMapDrive\n"); + +@@ -2206,47 +1905,34 @@ int NwcUnMapDrive(PXPLAT pdata, session_ + datalen = sizeof(symInfo) + symInfo.linkLen; + + cmdlen += datalen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { +- cmd->dataLen = datalen; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_UNMAP_DRIVE; +- +- cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- +- if (reply) { +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } +- kfree(cmd); +- } ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_UNMAP_DRIVE; ++ ++ cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); + ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwcEnumerateDrives(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Get the Primary connection +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_enum_drives(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; + unsigned long status = 0, cmdlen, replylen, cpylen; + unsigned long offset; + char *cp; +@@ -2254,284 +1940,266 @@ int NwcEnumerateDrives(PXPLAT pdata, ses + DbgPrint("Call to NwcEnumerateDrives\n"); + + cmdlen = sizeof(*cmd); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { +- cmd->dataLen = 0; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_ENUMERATE_DRIVES; +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- +- if (reply) { +- status = reply->Reply.ErrorCode; +- DbgPrint("Status Code = 0x%X\n", status); +- if (!status) { +- offset = +- sizeof(((PNwcGetMappedDrives) pdata-> +- repData)->MapBuffLen); +- cp = reply->data; +- replylen = +- ((PNwcGetMappedDrives) pdata->repData)-> +- MapBuffLen; +- cpylen = +- copy_to_user(pdata->repData, cp, offset); +- cp += offset; +- cpylen = +- copy_to_user(((PNwcGetMappedDrives) pdata-> +- repData)->MapBuffer, cp, +- min(replylen - offset, +- reply->dataLen - offset)); +- } ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +- kfree(reply); ++ cmd->dataLen = 0; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_ENUMERATE_DRIVES; ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ DbgPrint("Status Code = 0x%X\n", status); ++ if (!status) { ++ offset = ++ sizeof(((struct nwc_get_mapped_drives *) pdata-> ++ repData)->MapBuffLen); ++ cp = reply->data; ++ replylen = ++ ((struct nwc_get_mapped_drives *) pdata->repData)-> ++ MapBuffLen; ++ cpylen = ++ copy_to_user(pdata->repData, cp, offset); ++ cp += offset; ++ cpylen = ++ copy_to_user(((struct nwc_get_mapped_drives *) pdata-> ++ repData)->MapBuffer, cp, ++ min(replylen - offset, ++ reply->dataLen - offset)); + } +- kfree(cmd); +- } + ++ kfree(reply); ++ } ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwcGetBroadcastMessage(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Get the Primary connection +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++int novfs_get_bcast_msg(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; + unsigned long cmdlen, replylen; + int status = 0x8866, cpylen; +- NwcGetBroadcastNotification msg; +- PNwdCGetBroadcastNotification dmsg; ++ struct nwc_get_bcast_notification msg; ++ struct nwd_get_bcast_notification *dmsg; + + cmdlen = sizeof(*cmd) + sizeof(*dmsg); +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); +- if (cmd) { ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; + +- cpylen = copy_from_user(&msg, pdata->reqData, sizeof(msg)); +- cmd->dataLen = sizeof(*dmsg); +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- +- cmd->NwcCommand = NWC_GET_BROADCAST_MESSAGE; +- dmsg = (PNwdCGetBroadcastNotification) cmd->data; +- dmsg->uConnReference = (HANDLE) (unsigned long) msg.uConnReference; +- +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- +- if (reply) { +- status = reply->Reply.ErrorCode; +- +- if (!status) { +- char *cp = pdata->repData; +- +- dmsg = +- (PNwdCGetBroadcastNotification) reply->data; +- if (pdata->repLen < dmsg->messageLen) { +- dmsg->messageLen = pdata->repLen; +- } +- msg.messageLen = dmsg->messageLen; +- cpylen = offsetof(NwcGetBroadcastNotification, message); +- cp += cpylen; +- cpylen = copy_to_user(pdata->repData, &msg, cpylen); +- cpylen = copy_to_user(cp, dmsg->message, msg.messageLen); +- } else { +- msg.messageLen = 0; +- msg.message[0] = 0; +- cpylen = offsetof(NwcGetBroadcastNotification, message); +- cpylen = copy_to_user(pdata->repData, &msg, sizeof(msg)); +- } ++ cpylen = copy_from_user(&msg, pdata->reqData, sizeof(msg)); ++ cmd->dataLen = sizeof(*dmsg); ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ ++ cmd->NwcCommand = NWC_GET_BROADCAST_MESSAGE; ++ dmsg = (struct nwd_get_bcast_notification *) cmd->data; ++ dmsg->uConnReference = (void *) (unsigned long) msg.uConnReference; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; + +- kfree(reply); ++ if (!status) { ++ char *cp = pdata->repData; ++ ++ dmsg = ++ (struct nwd_get_bcast_notification *) reply->data; ++ if (pdata->repLen < dmsg->messageLen) { ++ dmsg->messageLen = pdata->repLen; ++ } ++ msg.messageLen = dmsg->messageLen; ++ cpylen = ++ offsetof(struct ++ nwc_get_bcast_notification, ++ message); ++ cp += cpylen; ++ cpylen = ++ copy_to_user(pdata->repData, &msg, cpylen); ++ cpylen = ++ copy_to_user(cp, dmsg->message, ++ msg.messageLen); ++ } else { ++ msg.messageLen = 0; ++ msg.message[0] = 0; ++ cpylen = offsetof(struct ++ nwc_get_bcast_notification, ++ message); ++ cpylen = ++ copy_to_user(pdata->repData, &msg, ++ sizeof(msg)); + } +- kfree(cmd); ++ ++ kfree(reply); + } ++ kfree(cmd); + return (status); + } + +-int NwdSetKeyValue(PXPLAT pdata, session_t Session) ++int novfs_set_key_value(struct novfs_xplat *pdata, struct novfs_schandle Session) + { +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcSetKey xplatCall; +- PNwdCSetKey pNewKey; +- NwcString cstrObjectName, cstrPassword; ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_set_key xplatCall; ++ struct nwd_set_key *pNewKey; ++ struct nwc_string cstrObjectName, cstrPassword; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + +- cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(NwcSetKey)); ++ cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_set_key)); + cpylen = + copy_from_user(&cstrObjectName, xplatCall.pObjectName, +- sizeof(NwcString)); ++ sizeof(struct nwc_string)); + cpylen = + copy_from_user(&cstrPassword, xplatCall.pNewPassword, +- sizeof(NwcString)); ++ sizeof(struct nwc_string)); + + datalen = +- sizeof(NwdCSetKey) + cstrObjectName.DataLen + cstrPassword.DataLen; ++ sizeof(struct nwd_set_key ) + cstrObjectName.DataLen + cstrPassword.DataLen; + + cmdlen = sizeof(*cmd) + datalen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- pNewKey = (PNwdCSetKey) cmd->data; +- cmd->dataLen = datalen; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_SET_KEY; +- +- pNewKey->ObjectType = xplatCall.ObjectType; +- pNewKey->AuthenticationId = xplatCall.AuthenticationId; +- pNewKey->ConnHandle = (HANDLE) (unsigned long) xplatCall.ConnHandle; +- str = (char *)pNewKey; ++ if (!cmd) ++ return -ENOMEM; + +- /* +- * Get the User Name +- */ +- str += sizeof(NwdCSetKey); +- cpylen = +- copy_from_user(str, cstrObjectName.pBuffer, +- cstrObjectName.DataLen); ++ pNewKey = (struct nwd_set_key *) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_KEY; + +- str += pNewKey->objectNameLen = cstrObjectName.DataLen; +- pNewKey->objectNameOffset = sizeof(NwdCSetKey); ++ pNewKey->ObjectType = xplatCall.ObjectType; ++ pNewKey->AuthenticationId = xplatCall.AuthenticationId; ++ pNewKey->ConnHandle = (void *) (unsigned long) xplatCall.ConnHandle; ++ str = (char *)pNewKey; + +- /* +- * Get the Verify Password +- */ +- cpylen = +- copy_from_user(str, cstrPassword.pBuffer, +- cstrPassword.DataLen); ++ /* ++ * Get the User Name ++ */ ++ str += sizeof(struct nwd_set_key ); ++ cpylen = ++ copy_from_user(str, cstrObjectName.pBuffer, ++ cstrObjectName.DataLen); + +- pNewKey->newPasswordLen = cstrPassword.DataLen; +- pNewKey->newPasswordOffset = +- pNewKey->objectNameOffset + pNewKey->objectNameLen; +- +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } +- memset(cmd, 0, cmdlen); +- kfree(cmd); +- } ++ str += pNewKey->objectNameLen = cstrObjectName.DataLen; ++ pNewKey->objectNameOffset = sizeof(struct nwd_set_key ); ++ ++ /* ++ * Get the Verify Password ++ */ ++ cpylen = ++ copy_from_user(str, cstrPassword.pBuffer, ++ cstrPassword.DataLen); + ++ pNewKey->newPasswordLen = cstrPassword.DataLen; ++ pNewKey->newPasswordOffset = ++ pNewKey->objectNameOffset + pNewKey->objectNameLen; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); + return (status); + } + +-/*++======================================================================*/ +-int NwdVerifyKeyValue(PXPLAT pdata, session_t Session) +-/* +- * Arguments: +- * +- * Returns: +- * +- * Abstract: Change the password on the server +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ +-{ +- PXPLAT_CALL_REQUEST cmd; +- PXPLAT_CALL_REPLY reply; +- NwcVerifyKey xplatCall; +- PNwdCVerifyKey pNewKey; +- NwcString xferStr; ++int novfs_verify_key_value(struct novfs_xplat *pdata, struct novfs_schandle Session) ++{ ++ struct novfs_xplat_call_request *cmd; ++ struct novfs_xplat_call_reply *reply; ++ struct nwc_verify_key xplatCall; ++ struct nwd_verify_key *pNewKey; ++ struct nwc_string xferStr; + char *str; + unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; + + cpylen = +- copy_from_user(&xplatCall, pdata->reqData, sizeof(NwcVerifyKey)); ++ copy_from_user(&xplatCall, pdata->reqData, sizeof(struct nwc_verify_key)); + + datalen = +- sizeof(NwdCVerifyKey) + xplatCall.pDomainName->DataLen + ++ sizeof(struct nwd_verify_key) + xplatCall.pDomainName->DataLen + + xplatCall.pObjectName->DataLen + xplatCall.pVerifyPassword->DataLen; + + cmdlen = sizeof(*cmd) + datalen; +- cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cmd = (struct novfs_xplat_call_request *)kmalloc(cmdlen, GFP_KERNEL); + +- if (cmd) { +- pNewKey = (PNwdCVerifyKey) cmd->data; +- cmd->dataLen = datalen; +- cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; +- cmd->Command.SequenceNumber = 0; +- cmd->Command.SessionId = Session; +- cmd->NwcCommand = NWC_VERIFY_KEY; +- +- pNewKey->NameType = xplatCall.NameType; +- pNewKey->ObjectType = xplatCall.ObjectType; +- pNewKey->AuthType = xplatCall.AuthType; +- str = (char *)pNewKey; ++ if (!cmd) ++ return -ENOMEM; + +- /* +- * Get the tree name +- */ +- str += sizeof(*pNewKey); +- cpylen = +- copy_from_user(&xferStr, xplatCall.pDomainName, +- sizeof(NwcString)); +- pNewKey->domainNameOffset = sizeof(*pNewKey); +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->domainNameLen = xferStr.DataLen; ++ pNewKey = (struct nwd_verify_key *) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_VERIFY_KEY; + +- /* +- * Get the User Name +- */ +- str += pNewKey->domainNameLen; +- cpylen = +- copy_from_user(&xferStr, xplatCall.pObjectName, +- sizeof(NwcString)); +- pNewKey->objectNameOffset = +- pNewKey->domainNameOffset + pNewKey->domainNameLen; +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->objectNameLen = xferStr.DataLen; ++ pNewKey->NameType = xplatCall.NameType; ++ pNewKey->ObjectType = xplatCall.ObjectType; ++ pNewKey->AuthType = xplatCall.AuthType; ++ str = (char *)pNewKey; + +- /* +- * Get the Verify Password +- */ +- str += pNewKey->objectNameLen; +- cpylen = +- copy_from_user(&xferStr, xplatCall.pVerifyPassword, +- sizeof(NwcString)); +- pNewKey->verifyPasswordOffset = +- pNewKey->objectNameOffset + pNewKey->objectNameLen; +- cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); +- pNewKey->verifyPasswordLen = xferStr.DataLen; +- +- status = +- Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, +- (void **)&reply, &replylen, +- INTERRUPTIBLE); +- if (reply) { +- status = reply->Reply.ErrorCode; +- kfree(reply); +- } +- memset(cmd, 0, cmdlen); +- kfree(cmd); +- } ++ /* ++ * Get the tree name ++ */ ++ str += sizeof(*pNewKey); ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pDomainName, ++ sizeof(struct nwc_string)); ++ pNewKey->domainNameOffset = sizeof(*pNewKey); ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->domainNameLen = xferStr.DataLen; ++ ++ /* ++ * Get the User Name ++ */ ++ str += pNewKey->domainNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pObjectName, ++ sizeof(struct nwc_string)); ++ pNewKey->objectNameOffset = ++ pNewKey->domainNameOffset + pNewKey->domainNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->objectNameLen = xferStr.DataLen; ++ ++ /* ++ * Get the Verify Password ++ */ ++ str += pNewKey->objectNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pVerifyPassword, ++ sizeof(struct nwc_string)); ++ pNewKey->verifyPasswordOffset = ++ pNewKey->objectNameOffset + pNewKey->objectNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->verifyPasswordLen = xferStr.DataLen; + ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); + return (status); + } +--- a/fs/novfs/nwcapi.h ++++ b/fs/novfs/nwcapi.h +@@ -109,14 +109,14 @@ + + #define IOC_XPLAT 0x4a540002 + +-typedef struct _XPLAT_ { ++struct novfs_xplat { + int xfunction; + unsigned long reqLen; + void *reqData; + unsigned long repLen; + void *repData; + +-} XPLAT, *PXPLAT; ++}; + + #if 0 + N_EXTERN_LIBRARY(NWRCODE) +@@ -326,66 +326,30 @@ N_EXTERN_LIBRARY(NWRCODE) + + //===[ Type definitions ]================================================== + +-// +-// Connection Handle returned from all OpenConnByXXXX calls +-// +- +-typedef u32 NW_CONN_HANDLE, *PNW_CONN_HANDLE; +- +-// +-// Authentication Id returned from the NwcCreateAuthenticationId call +-// +- +-typedef u32 AUTHEN_ID, *PAUTHEN_ID; + + // + // Structure for defining what a transport + // address looks like + // + +-typedef struct tagNwcTranAddr { ++struct nwc_tran_addr { + u32 uTransportType; + u32 uAddressLength; + unsigned char *puAddress; ++}; + +-} NwcTranAddr, *PNwcTranAddr; +- +-// +-// Structure for defining what a new transport +-// address looks like +-// +- +-typedef struct tagNwcTranAddrEx { +- u32 uTransportType; +- u32 uAddressLength; +- unsigned char buBuffer[MAX_ADDRESS_LENGTH]; +- +-} NwcTranAddrEx, *PNwcTranAddrEx; + +-typedef struct tagNwcReferral { +- u32 uAddrCnt; +- PNwcTranAddrEx pAddrs; +- +-} NwcReferral, *PNwcReferral; +- +-typedef struct tagNwcServerVersion { +- u32 uMajorVersion; +- u16 uMinorVersion; +- u16 uRevision; +- +-} NwcServerVersion, *PNwcServerVersion; +- +-typedef struct tagNwcConnString { ++struct nwc_conn_string { + char *pString; + u32 uStringType; + u32 uNameFormatType; + +-} NwcConnString, *PNwcConnString; ++}; + + //#if defined(NTYPES_H) + //typedef NWCString NwcString, *PNwcString; + //#else +-typedef struct tagNwcString { ++struct nwc_string { + u32 DataType; + u32 BuffSize; + u32 DataLen; +@@ -393,36 +357,18 @@ typedef struct tagNwcString { + u32 CodePage; + u32 CountryCode; + +-} NwcString, *PNwcString; ++}; + //#endif + + // +-// Structure used in NDS Resolve name +-// +- +-#define RESOLVE_INFO_SVC_V1_00 0x00FE0001 +- +-typedef struct tagNwcResolveInfo { +- u32 uResolveInfoVersion; +- u32 luFlags; +- u32 luReqFlags; +- u32 luReqScope; +- u32 luResolveType; +- u32 luRepFlags; +- u32 luResolvedOffset; +- u32 luDerefNameLen; +- u16 *pDerefName; +-} NwcResolveInfo, *PNwcResolveInfo; +- +-// + // Definition of a fragment for the Raw NCP requests + // + +-typedef struct tagNwcFrag { ++struct nwc_frag { + void *pData; + u32 uLength; + +-} NwcFrag, *PNwcFrag; ++}; + + // + // Current connection information available for +@@ -432,62 +378,6 @@ typedef struct tagNwcFrag { + #define NW_INFO_BUFFER_SIZE NW_MAX_TREE_NAME_LEN + \ + NW_MAX_TREE_NAME_LEN + \ + NW_MAX_SERVICE_TYPE_LEN +- +-typedef struct tagNwcConnInfo { +- u32 uInfoVersion; +- u32 uAuthenticationState; +- u32 uBroadcastState; +- u32 uConnectionReference; +- u32 TreeNameOffset; +- u32 uSecurityState; +- u32 uConnectionNumber; +- u32 uUserId; +- u32 ServerNameOffset; +- u32 uNdsState; +- u32 uMaxPacketSize; +- u32 uLicenseState; +- u32 uPublicState; +- u32 bcastState; +- u32 ServiceTypeOffset; +- u32 uDistance; +- u32 uAuthId; +- u32 uDisconnected; +- NwcServerVersion serverVersion; +- NwcTranAddrEx tranAddress; +- unsigned char buBuffer[NW_INFO_BUFFER_SIZE]; +- +-} NwcConnInfo, *PNwcConnInfo; +- +-// +-// Get Browse Connection References +-// +- +-typedef struct _GetBrowseConnectionsRec { +- +- u32 recordSize; +- u32 numConnectionsReturned; +- u32 numConnectionsAvailable; +- u32 connReferences[1]; +- +-} GetBrowseConnectionRec, *PGetBrowseConnectionRec; +- +-//++======================================================================= +-// API Name: NwcClearBroadcastMessage +-// +-// Arguments In: NONE +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// +-// Abstract: This API is clears the broadcast message buffer. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- + //++======================================================================= + // API Name: NwcCloseConn + // +@@ -514,10 +404,10 @@ typedef struct _GetBrowseConnectionsRec + // + //=======================================================================-- + +-typedef struct tagNwcCloseConn { +- NW_CONN_HANDLE ConnHandle; ++struct nwc_close_conn { ++ u32 ConnHandle; + +-} NwcCloseConn, *PNwcCloseConn; ++}; + + //++======================================================================= + // API Name: NwcConvertLocalFileHandle +@@ -548,11 +438,11 @@ typedef struct tagNwcCloseConn { + // + //=======================================================================-- + +-typedef struct tagNwcConvertLocalHandle { ++struct nwc_convert_local_handle { + u32 uConnReference; + unsigned char NetWareHandle[6]; + +-} NwcConvertLocalHandle, *PNwcConvertLocalHandle; ++}; + + //++======================================================================= + // API Name: NwcConvertNetWareHandle +@@ -592,121 +482,13 @@ typedef struct tagNwcConvertLocalHandle + // Environment: PASSIVE_LEVEL, LINUX + // + //=======================================================================-- +-typedef struct tagNwcConvertNetWareHandle { +- NW_CONN_HANDLE ConnHandle; ++struct nwc_convert_netware_handle { ++ u32 ConnHandle; + u32 uAccessMode; + unsigned char NetWareHandle[6]; + u32 uFileSize; +-} NwcConvertNetWareHandle, *PNwcConvertNetWareHandle; ++}; + +-//++======================================================================= +-// API Name: NwcFragmentRequest +-// +-// Arguments In: ConnHandle +-// The connection handle the request is being +-// directed to. +-// +-// uFunction +-// The NCP function to be called, should be 104 +-// for NDS fragger/defragger requests. +-// +-// uSubFunction +-// The NCP subfunction to be called, should be +-// 2 for NDS fragger/defragger requests. +-// +-// uVerb +-// The actual operation to be completed on the +-// server backend. +-// +-// flags +-// Currently not implemented. Reserved for +-// future use. +-// +-// uNumRequestFrags +-// The number of fragments that the request packet +-// has been broken into. +-// +-// pRequestFrags +-// List of fragments that make up the request packet. +-// Each fragment includes the length of the fragment +-// data and a pointer to the data. +-// +-// uNumReplyFrags +-// The number of fragments the reply packet has been +-// broken into. +-// +-// Arguments Out: pReplyFrags +-// List of fragments that make up the reply packet. +-// Each fragment includes the length of the fragment +-// data and a pointer to the data. +-// +-// uActualReplyLength +-// Total size of the reply packet after any header +-// and tail information is removed. +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// +-// Abstract: API for sending large NCP/NDS packets that are +-// larger than the max MTU size for the underlying +-// network. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +-typedef struct tagNwcFragmentRequest { +- NW_CONN_HANDLE ConnHandle; +- u32 uFunction; +- u32 uSubFunction; +- u32 uVerb; +- u32 flags; +- u32 uNumRequestFrags; +- PNwcFrag pRequestFrags; +- u32 uNumReplyFrags; +- PNwcFrag pReplyFrags; +- u32 uActualReplyLength; +-} NwcFragmentRequest, *PNwcFragmentRequest; +- +-//++======================================================================= +-// API Name: NwcGetBroadcastMessage +-// +-// Arguments In: uMessageFlags - Not currently used. +-// +-// uConnReference - connection reference for +-// pending message. +-// +-// messageLen - length of message buffer. +-// +-// message - message buffer +-// +-// Arguments Out: messageLen - length of the message +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_NO_MORE_ENTRIES +-// +-// Abstract: This API is used for notifying a caller of pending +-// broadcast messages on the server. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-/* jlt +-typedef struct tagNwcGetBroadcastMessage +-{ +- u32 uMessageFlags; +- u32 uConnReference; +- u32 messageLen; +- unsigned char message[255]; +- +-} NwcGetBroadcastMessage, *PNwcGetBroadcastMessage; +-*/ + + //++======================================================================= + // API Name: NwcGetConnInfo +@@ -746,13 +528,13 @@ typedef struct tagNwcGetBroadcastMess + // + //=======================================================================-- + +-typedef struct tagNwcGetConnInfo { +- NW_CONN_HANDLE ConnHandle; ++struct nwc_get_conn_info { ++ u32 ConnHandle; + u32 uInfoLevel; + u32 uInfoLength; + void *pConnInfo; + +-} NwcGetConnInfo, *PNwcGetConnInfo; ++}; + + //++======================================================================= + // API Name: NwcGetDefaultNameContext +@@ -785,14 +567,14 @@ typedef struct tagNwcGetConnInfo { + // + //=======================================================================-- + +-typedef struct tagNwcGetDefaultNameContext { ++struct nwc_get_def_name_ctx { + u32 uTreeLength; + unsigned char *pDsTreeName; + u32 uNameLength; + // unsigned short *pNameContext; + unsigned char *pNameContext; + +-} NwcGetDefaultNameContext, *PNwcGetDefaultNameContext; ++}; + + //++======================================================================= + // API Name: NwcGetTreeMonitoredConnReference +@@ -817,86 +599,12 @@ typedef struct tagNwcGetDefaultNameConte + // + //=======================================================================-- + +-typedef struct tagNwcGetTreeMonitoredConnRef { +- PNwcString pTreeName; ++struct nwc_get_tree_monitored_conn_ref { ++ struct nwc_string *pTreeName; + u32 uConnReference; + +-} NwcGetTreeMonitoredConnRef, *PNwcGetTreeMonitoredConnRef; ++}; + +-//++======================================================================= +-// API Name: NwcGetNumberConns +-// +-// Arguments In: NONE +-// +-// Arguments Out: uMaxConns - The maximum number of connections +-// supported by the redirector. -1 for dynamic. +-// +-// uPublicConns - The current number of public +-// connections. +-// +-// uTasksPrivateConns - The current number of private +-// connections that are owned by the calling process. +-// +-// uOtherPrivateConns - The current number of private +-// connections that are not owned by the calling +-// process. +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_RESOURCE_LOCK +-// +-// Abstract: This API returns the current number of connections +-// as well as the maximum number of supported +-// connections. If the requester/redirector supports +-// a dynamic connection table, -1 will be returned +-// in the uMaxConns field. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcGetNumberConns { +- u32 uMaxConns; +- u32 uPublicConns; +- u32 uTasksPrivateConns; +- u32 uOtherPrivateConns; +- +-} NwcGetNumberConns, *PNwcGetNumberConns; +- +-//++======================================================================= +-// API Name: NwcGetPreferredServer +-// +-// Arguments In: uServerNameLength - On input, this is the length +-// in bytes of the server buffer. On output, this is +-// the actual length of the server name string in bytes. +-// +-// Arguments Out: pServerName - The buffer to copy the preferred server +-// name into. +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_BUFFER_OVERFLOW +-// NWE_OBJECT_NOT_FOUND +-// NWE_PARAM_INVALID +-// NWE_RESOURCE_LOCK +-// +-// Abstract: This API returns the configured preferred bindery +-// server previously set either by configuration or +-// by calling NwcSetPreferredServer. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcGetPreferredServer { +- u32 uServerNameLength; +- char *pServerName; +- +-} NwcGetPreferredServer, *PNwcGetPreferredServer; + + //++======================================================================= + // API Name: NwcGetPreferredDsTree +@@ -923,63 +631,10 @@ typedef struct tagNwcGetPreferredServer + // Environment: PASSIVE_LEVEL, LINUX + // + //=======================================================================-- +-typedef struct tagNwcGetPreferredDsTree { ++struct nwc_get_pref_ds_tree { + u32 uTreeLength; + unsigned char *pDsTreeName; +-} NwcGetPreferredDsTree, *PNwcGetPreferredDsTree; +- +-//++======================================================================= +-// API Name: NwcGetPrimaryConnection +-// +-// Arguments In: NONE +-// +-// Arguments Out: uConnReference - Reference to the primary connection. +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_PRIMARY_NOT_SET +-// +-// Abstract: This API returns the reference to the current primary +-// connection in the redirector. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcGetPrimaryConnection { +- u32 uConnReference; +- +-} NwcGetPrimaryConnection, *PNwcGetPrimaryConnection; +- +-//++======================================================================= +-// API Name: NwcGetRequesterVersion +-// +-// Arguments In: NONE +-// +-// Arguments Out: uMajorVersion +-// uMinorVersion +-// uRevision +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// +-// Abstract: This API returns the major version, minor version and +-// revision of the requester/redirector. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcGetRequesterVersion { +- u32 uMajorVersion; +- u32 uMinorVersion; +- u32 uRevision; +- +-} NwcGetRequesterVersion, *PNwcGetRequesterVersion; ++}; + + //++======================================================================= + // API Name: NwcLicenseConn +@@ -1007,115 +662,10 @@ typedef struct tagNwcGetRequesterVersion + // + //=======================================================================-- + +-typedef struct tagNwcLicenseConn { +- NW_CONN_HANDLE ConnHandle; +- +-} NwcLicenseConn, *PNwcLicenseConn; +- +-//++======================================================================= +-// API Name: NwcMakeConnPermanent +-// +-// Arguments In: ConnHandle - An open connection handle associated +-// with the connection to be made permanent. +-// +-// Arguments Out: NONE +-// +-// Returns: NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// NWE_INVALID_OWNER +-// +-// Abstract: This API is used to keep the connection from being +-// destroyed until a NwcSysCloseConn request is made +-// on the connection. This allows the connection to +-// remain after all processes that have the +-// connection open terminate. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcMakeConnPermanent { +- NW_CONN_HANDLE ConnHandle; +- +-} NwcMakeConnPermanent, *PNwcMakeConnPermanent; +- +-//++======================================================================= +-// API Name: NwcMapDrive +-// +-// Arguments In: ConnHandle - The connection handle of the server +-// to where the drive is to be mapped. +-// +-// LocalUID - Local user ID +-// +-// LocalPathLen - Length of local/link directory path string, +-// including nul terminator. +-// +-// LocalPathOffset - Offset of local directory path that will +-// be mapped to NetWare directory path. +-// +-// NetWarePathLen - Offset of NetWare directory path, +-// including nul terminator. +-// +-// NetWarePathOffset - Offset of NetWare directory path in +-// structure. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// NWE_INSUFFICIENT_RESOURCES +-// NWE_STRING_TRANSLATION +-// +-// Abstract: This API maps the target drive to the specified +-// directory. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcMapDrive { +- NW_CONN_HANDLE ConnHandle; +- u32 LocalUID; +- u32 LinkPathLen; +- u32 LinkPathOffset; +- u32 DestPathLen; +- u32 DestPathOffset; ++struct nwc_license_conn { ++ u32 ConnHandle; ++}; + +-} NwcMapDrive, *PNwcMapDrive; +- +-//++======================================================================= +-// API Name: NwcUnmapDrive +-// +-// Arguments In: LinkPathLen - Length of local/link path string, +-// including nul terminator. +-// +-// LinkPath - Local/link path in structure +-// to be unmapped +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_PARAM_INVALID +-// +-// Abstract: This API deletes a network drive mapping. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcUnmapDrive { +- u32 LinkPathLen; +- unsigned char LinkPath[1]; +- +-} NwcUnmapDrive, *PNwcUnmapDrive; + + //++======================================================================= + // API Name: NWCGetMappedDrives +@@ -1136,26 +686,11 @@ typedef struct tagNwcUnmapDrive { + // + //=======================================================================-- + +-typedef struct tagNwcMapDriveElem { +- u32 ElemLen; // Lenght of drive element +- u32 ConnRefernce; // Connection reference +- u32 LinkPathLen; // Local/link dir path, length includes nul +- unsigned char LinkPath[1]; // LinkPath[LinkPathLen] +-// u32 DirPathLen; // NetWare dir path, length includes nul (vol:path) +-// unsigned char DirPath[DirPathLen]; // NetWarePath[DirPathLen] +-} NwcMapDriveElem, *PNwcMapDriveElem; +- +-typedef struct tagNwcMapDriveBuff { +- u32 MapCount; // Number of mapped drives +- NwcMapDriveElem MapDriveElem[1]; // MapDriveElem[MapCount] +- +-} NwcMapDriveBuff, *PNwcMapDriveBuff; +- +-typedef struct tagNwcGetMappedDrives { ++struct nwc_get_mapped_drives { + u32 MapBuffLen; // Buffer length (actual buffer size returned) +- PNwcMapDriveBuff MapBuffer; // Pointer to map buffer ++ struct nwc_mapped_drive_buf *MapBuffer; // Pointer to map buffer + +-} NwcGetMappedDrives, *PNwcGetMappedDrives; ++}; + + //++======================================================================= + // API Name: NwcGetMountPath +@@ -1178,39 +713,11 @@ typedef struct tagNwcGetMappedDrives { + // + //=======================================================================-- + +-typedef struct tagNwcGetMountPath { ++struct nwc_get_mount_path { + u32 MountPathLen; + unsigned char *pMountPath; + +-} NwcGetMountPath, *PNwcGetMountPath; +- +-//++======================================================================= +-// API Name: NwcMonitorConn +-// +-// Arguments In: ConnHandle - The handle associated with the connection +-// that is to be marked as the monitored connection. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_RESOURCE_LOCK +-// NWE_CONN_INVALID +-// +-// +-// Abstract: This call marks the connection associated with the +-// connection handle as monitored. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcMonitorConn { +- NW_CONN_HANDLE ConnHandle; +- +-} NwcMonitorConn, *PNwcMonitorConn; ++}; + + //++======================================================================= + // API Name: NwcOpenConnByAddr +@@ -1244,13 +751,13 @@ typedef struct tagNwcMonitorConn { + // + //=======================================================================-- + +-typedef struct tagNwcOpenConnByAddr { ++struct nwc_open_conn_by_addr { + char *pServiceType; + u32 uConnFlags; +- PNwcTranAddr pTranAddr; +- NW_CONN_HANDLE ConnHandle; ++ struct nwc_tran_addr *pTranAddr; ++ u32 ConnHandle; + +-} NwcOpenConnByAddr, *PNwcOpenConnByAddr; ++}; + + //++======================================================================= + // API Name: NwcOpenConnByName +@@ -1304,15 +811,15 @@ typedef struct tagNwcOpenConnByAddr { + // + //=======================================================================-- + +-typedef struct tagNwcOpenConnByName { +- NW_CONN_HANDLE ConnHandle; +- PNwcConnString pName; ++struct nwc_open_conn_by_name { ++ u32 ConnHandle; ++ struct nwc_conn_string *pName; + char *pServiceType; + u32 uConnFlags; + u32 uTranType; +- NW_CONN_HANDLE RetConnHandle; ++ u32 RetConnHandle; + +-} NwcOpenConnByName, *PNwcOpenConnByName; ++}; + + //++======================================================================= + // API Name: NwcOpenConnByReference +@@ -1346,12 +853,12 @@ typedef struct tagNwcOpenConnByName { + // + //=======================================================================-- + +-typedef struct tagNwcOpenConnByReference { ++struct nwc_open_conn_by_ref { + u32 uConnReference; + u32 uConnFlags; +- NW_CONN_HANDLE ConnHandle; ++ u32 ConnHandle; + +-} NwcOpenConnByReference, *PNwcOpenConnByReference; ++}; + + //++======================================================================= + // API Name: NwcRawRequest +@@ -1390,55 +897,16 @@ typedef struct tagNwcOpenConnByReference + // + //=======================================================================-- + +-typedef struct tagNwcRequest { +- NW_CONN_HANDLE ConnHandle; ++struct nwc_request { ++ u32 ConnHandle; + u32 uFunction; + u32 uNumRequestFrags; +- PNwcFrag pRequestFrags; ++ struct nwc_frag *pRequestFrags; + u32 uNumReplyFrags; +- PNwcFrag pReplyFrags; ++ struct nwc_frag *pReplyFrags; + u32 uActualReplyLength; + +-} NwcRequest, *PNwcRequest; +- +-//++======================================================================= +-// API Name: NwcRawRequestAll +-// +-// Arguments In: uFunction - The NCP function that is being called. +-// +-// uNumRequestFrags - The number of fragments that the +-// request packet has been broken into. +-// +-// pRequestFrags - List of fragments that make up the +-// request packet. Each fragment includes the length +-// of the fragment data and a pointer to the data. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// +-// Abstract: API for sending the given NCP request to all valid +-// connections. If there is a private connection that +-// is not owned by the caller of this function, that +-// connection will not be included. Also, if the +-// caller has both a private and a public connection +-// to the same server, only the private connection +-// will receive the request. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcRequestAll { +- u32 uFunction; +- u32 uNumRequestFrags; +- PNwcFrag pRequestFrags; +- +-} NwcRequestAll, *PNwcRequestAll; ++}; + + //++======================================================================= + // API Name: NwcScanConnInfo +@@ -1544,7 +1012,7 @@ typedef struct tagNwcRequestAll { + // + //=======================================================================-- + +-typedef struct tagNwcScanConnInfo { ++struct nwc_scan_conn_info { + u32 uScanIndex; + u32 uScanInfoLevel; + u32 uScanInfoLen; +@@ -1555,7 +1023,7 @@ typedef struct tagNwcScanConnInfo { + u32 uConnectionReference; + void *pReturnConnInfo; + +-} NwcScanConnInfo, *PNwcScanConnInfo; ++}; + + //++======================================================================= + // API Name: NwcSetConnInfo +@@ -1589,13 +1057,13 @@ typedef struct tagNwcScanConnInfo { + // + //=======================================================================-- + +-typedef struct tagNwcSetConnInfo { +- NW_CONN_HANDLE ConnHandle; ++struct nwc_set_conn_info { ++ u32 ConnHandle; + u32 uInfoLevel; + u32 uInfoLength; + void *pConnInfo; + +-} NwcSetConnInfo, *PNwcSetConnInfo; ++}; + + //++======================================================================= + // API Name: NwcSetDefaultNameContext +@@ -1626,14 +1094,14 @@ typedef struct tagNwcSetConnInfo { + // + //=======================================================================-- + +-typedef struct tagNwcSetDefaultNameContext { ++struct nwc_set_def_name_ctx { + u32 uTreeLength; + unsigned char *pDsTreeName; + u32 uNameLength; + // unsined short *pNameContext; + unsigned char *pNameContext; + +-} NwcSetDefaultNameContext, *PNwcSetDefaultNameContext; ++}; + + //++======================================================================= + // API Name: NwcSetPreferredDsTree +@@ -1658,41 +1126,11 @@ typedef struct tagNwcSetDefaultNameConte + // + //=======================================================================-- + +-typedef struct tagNwcSetPreferredDsTree { ++struct nwc_set_pref_ds_tree { + u32 uTreeLength; + unsigned char *pDsTreeName; + +-} NwcSetPreferredDsTree, *PNwcSetPreferredDsTree; +- +-//++======================================================================= +-// API Name: NwcSetPreferredServer +-// +-// Arguments In: uServerNameLength - The length in bytes of the +-// preferred server string. +-// +-// pServerName - a pointer to an ASCIIZ string of the +-// preferred bindery server. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_INSUFFICIENT_RESOURCES +-// NWE_RESOURCE_LOCK +-// +-// Abstract: This API sets the preferred server name. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcSetPreferredServer { +- u32 uServerNameLength; +- char *pServerName; +- +-} NwcSetPreferredServer, *PNwcSetPreferredServer; ++}; + + //++======================================================================= + // API Name: NwcSetPrimaryConnection +@@ -1716,69 +1154,11 @@ typedef struct tagNwcSetPreferredServer + // + //=======================================================================-- + +-typedef struct tagNwcSetPrimaryConnection { +- NW_CONN_HANDLE ConnHandle; +- +-} NwcSetPrimaryConnection, *PNwcSetPrimaryConnection; +- +-//++======================================================================= +-// API Name: NwcSysCloseConn +-// +-// Arguments In: ConnHandle - The handle to a connection that is +-// to be destroyed. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// +-// Abstract: This API is similiar to the NwcCloseConn API, except +-// that it forces all handles to the connection closed +-// and destroys the service connection. This is a system +-// level request that will cause all processes that are +-// accessing this connection to lose access to the +-// resources associated to the connection. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcSysCloseConn { +- NW_CONN_HANDLE ConnHandle; +- +-} NwcSysCloseConn, *PNwcSysCloseConn; +- +-//++======================================================================= +-// API Name: NwcUnlicenseConn +-// +-// Arguments In: ConnHandle - Open connection handle that will be +-// accessing the connection in an unlicensed manner. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// NWE_HANDLE_ALREADY_UNLICENSED +-// +-// Abstract: This API is used to change the state of a connection +-// handle from licensed to unlicensed. If all handles +-// to the connection have been changed to the unlicensed +-// state, the unlicensed NCP is sent to the server. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- ++struct nwc_set_primary_conn { ++ u32 ConnHandle; + +-typedef struct tagNwcUnlicenseConn { +- NW_CONN_HANDLE ConnHandle; ++}; + +-} NwcUnlicenseConn, *PNwcUnlicenseConn; + + //++======================================================================= + // API Name: NwcQueryFeature +@@ -1801,10 +1181,10 @@ typedef struct tagNwcUnlicenseConn { + // + //=======================================================================-- + +-typedef struct tagNwcQueryFeature { ++struct nwc_query_feature { + u32 Feature; + +-} NwcQueryFeature, *PNwcQueryFeature; ++}; + + //++======================================================================= + // API Name: NWCChangePassword +@@ -1824,16 +1204,16 @@ typedef struct tagNwcQueryFeature { + // + //=======================================================================-- + +-typedef struct tagNwcChangeKey { +- PNwcString pDomainName; ++struct nwc_change_key { ++ struct nwc_string *pDomainName; + u32 AuthType; +- PNwcString pObjectName; ++ struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; +- PNwcString pVerifyPassword; +- PNwcString pNewPassword; ++ struct nwc_string *pVerifyPassword; ++ struct nwc_string *pNewPassword; + +-} NwcChangeKey, *PNwcChangeKey; ++}; + + //++======================================================================= + // API Name: NWCEnumerateIdentities ` +@@ -1853,17 +1233,17 @@ typedef struct tagNwcChangeKey { + // + //=======================================================================-- + +-typedef struct tagNwcEnumerateIdentities { ++struct nwc_enum_ids { + u32 Iterator; +- PNwcString pDomainName; ++ struct nwc_string *pDomainName; + u32 AuthType; +- PNwcString pObjectName; ++ struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + u32 IdentityFlags; +- AUTHEN_ID AuthenticationId; ++ u32 AuthenticationId; + +-} NwcEnumerateIdentities, *PNwcEnumerateIdentities; ++}; + + //++======================================================================= + // API Name: NWCGetIdentityInfo +@@ -1883,16 +1263,16 @@ typedef struct tagNwcEnumerateIdentities + // + //=======================================================================-- + +-typedef struct tagNwcGetIdentityInfo { +- AUTHEN_ID AuthenticationId; +- PNwcString pDomainName; ++struct nwc_get_id_info { ++ u32 AuthenticationId; ++ struct nwc_string *pDomainName; + u32 AuthType; +- PNwcString pObjectName; ++ struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + u32 IdentityFlags; + +-} NwcGetIdentityInfo, *PNwcGetIdentityInfo; ++}; + + //++======================================================================= + // API Name: NWCLoginIdentity +@@ -1912,41 +1292,18 @@ typedef struct tagNwcGetIdentityInfo { + // + //=======================================================================-- + +-typedef struct tagNwcLoginIdentity { +- PNwcString pDomainName; ++struct nwc_login_id { ++ struct nwc_string *pDomainName; + u32 AuthType; +- PNwcString pObjectName; ++ struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; + u32 IdentityFlags; +- PNwcString pPassword; +- AUTHEN_ID AuthenticationId; +- +-} NwcLoginIdentity, *PNwcLoginIdentity; +- +-//++======================================================================= +-// API Name: NWCLogoutIdentity +-//// +- +-// Arguments In: +-// +-// Arguments Out: +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// +-// Abstract: +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- ++ struct nwc_string *pPassword; ++ u32 AuthenticationId; + +-typedef struct tagNwcLogoutIdentity { +- AUTHEN_ID AuthenticationId; ++}; + +-} NwcLogoutIdentity, *PNwcLogoutIdentity; + + //++======================================================================= + // API Name: NWCSetPassword +@@ -1966,14 +1323,14 @@ typedef struct tagNwcLogoutIdentity { + // + //=======================================================================-- + +-typedef struct tagNwcSetKey { +- NW_CONN_HANDLE ConnHandle; +- AUTHEN_ID AuthenticationId; +- PNwcString pObjectName; ++struct nwc_set_key { ++ u32 ConnHandle; ++ u32 AuthenticationId; ++ struct nwc_string *pObjectName; + u16 ObjectType; +- PNwcString pNewPassword; ++ struct nwc_string *pNewPassword; + +-} NwcSetKey, *PNwcSetKey; ++}; + + //++======================================================================= + // API Name: NWCVerifyPassword +@@ -1993,15 +1350,15 @@ typedef struct tagNwcSetKey { + // + //++======================================================================= + +-typedef struct tagNwcVerifyKey { +- PNwcString pDomainName; ++struct nwc_verify_key { ++ struct nwc_string *pDomainName; + u32 AuthType; +- PNwcString pObjectName; ++ struct nwc_string *pObjectName; + u32 NameType; + u16 ObjectType; +- PNwcString pVerifyPassword; ++ struct nwc_string *pVerifyPassword; + +-} NwcVerifyKey, *PNwcVerifyKey; ++}; + + //++======================================================================= + // API Name: NwcAuthenticateWithId +@@ -2026,188 +1383,34 @@ typedef struct tagNwcVerifyKey { + // + //=======================================================================-- + +-typedef struct tagNwcAuthenticateWithId { +- NW_CONN_HANDLE ConnHandle; +- AUTHEN_ID AuthenticationId; +- +-} NwcAuthenticateWithId, *PNwcAuthenticateWithId; +- +-//++======================================================================= +-// API Name: NwcUnauthenticate +-// +-// Arguments In: ConnHandle - The connection to unauthenticate. +-// +-// Arguments Out: NONE +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// NWE_INVALID_OWNER +-// NWE_RESOURCE_LOCK +-// +-// Abstract: This API removes the authentication for the specified +-// connection. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcUnauthenticate { +- NW_CONN_HANDLE ConnHandle; +- AUTHEN_ID AuthenticationId; +- +-} NwcUnauthenticate, *PNwcUnauthenticate; +- +-//++======================================================================= +-// API Name: NwcGetCfgNameServiceProviders +-// +-// Arguments In: +-// +-// Arguments Out: +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// +-// Abstract: +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct { +- u32 providerCount; +- u32 providers[MAX_NAME_SERVICE_PROVIDERS]; +- +-} NwcGetCfgNameServiceProviders, *PNwcGetCfgNameServiceProviders; +- +-//++======================================================================= +-// API Name: NwcNdsResolveNameToId +-// +-// Arguments In: connHandle +-// Specifies connection to use to resolve name with. +-// +-// pName +-// Points to the name of the NDS entry to resolve. +-// +-// uReqTranType +-// Specifies the preferred or required transport to +-// be used. +-// +-// pResolveInfo +-// Points to the NwcNdsResolveInfo structure +-// containing information on how the entry is to be +-// resolved. +-// +-// Arguments Out: pResolveInfo +-// Points to the NwcNdsResolveInfo structure +-// containing return information on the resolved +-// entry. +-// +-// pluEntryId +-// Points to the resolved name's entry ID. +-// +-// pReferral +-// Points to the NwcReferral structure which describes +-// network addresses that can be used to locate other +-// NDS partitions that contain the entry name. +-// +-// Returns: STATUS_SUCCESS +-// NWE_CONN_INVALID, +-// NWE_BUFFER_OVERFLOW, +-// NWE_TRAN_INVALID_TYPE, +-// NWE_ACCESS_VIOLATION, +-// NWE_UNSUPPORTED_TRAN_TYPE, +-// Nds error code +-// +-// Abstract: This API resolves a NDS entry name. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- +- +-typedef struct tagNwcNdsResolveNameToId { +- NW_CONN_HANDLE connHandle; +- PNwcString pName; +- u32 uReqTranType; +- PNwcResolveInfo pResolveInfo; +- u32 entryId; +- PNwcReferral pReferral; +- +-} NwcNdsResolveNameToId, *PNwcNdsResolveNameToId; +- +-//++======================================================================= +-// API Name: NwcOrderedRequest +-// +-// Arguments In: uFunction - The NCP function that is being called. +-// +-// uNumRequestFrags - The number of fragments that the +-// request packet has been broken into. +-// +-// pRequestFrags - List of fragments that make up the +-// request packet. Each fragment includes the length +-// of the fragment data and a pointer to the data. +-// +-// uInverseReqCode - The NCP function that will be called +-// if the request fails. +-// +-// uNumInverseFrags - The number of fragments the inverse +-// request packet has been broken into. +-// +-// pReplyFrags - List of fragments that make up the +-// inverse request packet. Each fragment includes the length +-// of the fragment data and a pointer to the data. +-// +-// Returns: STATUS_SUCCESS +-// NWE_ACCESS_VIOLATION +-// NWE_CONN_INVALID +-// +-// Abstract: API for sending raw NCP packets directly to a server. +-// +-// Notes: +-// +-// Environment: PASSIVE_LEVEL, LINUX +-// +-//=======================================================================-- ++struct nwc_auth_with_id { ++ u32 ConnHandle; ++ u32 AuthenticationId; + +-typedef struct tagNwcOrderedRequest { +- u32 uReqCode; +- u32 uNumRequestFrags; +- PNwcFrag pRequestFrags; +- u32 uInverseReqCode; +- u32 uNumInverseFrags; +- PNwcFrag pInverseFrags; ++}; + +-} NwcOrderedRequest, *PNwcOrderedRequest; + +-#if 1 //sgled +-typedef struct tagNwcUnmapDriveEx { ++struct nwc_unmap_drive_ex { + // unsigned long connHdl; + unsigned int linkLen; + char linkData[1]; + +-} NwcUnmapDriveEx, *PNwcUnmapDriveEx; ++}; + +-typedef struct tagNwcMapDriveEx { +- NW_CONN_HANDLE ConnHandle; ++struct nwc_map_drive_ex { ++ u32 ConnHandle; + unsigned int localUid; + unsigned int linkOffsetLength; + unsigned int linkOffset; + unsigned int dirPathOffsetLength; + unsigned int dirPathOffset; +-} NwcMapDriveEx, *PNwcMapDriveEx; ++}; + +-typedef struct tagNwcGetBroadcastNotification { ++struct nwc_get_bcast_notification { + u32 uMessageFlags; + u32 uConnReference; + u32 messageLen; + char message[1]; +-} NwcGetBroadcastNotification, *PNwcGetBroadcastNotification; ++}; + +-#endif + #endif /* __NWCLNX_H__ */ +--- a/fs/novfs/proc.c ++++ b/fs/novfs/proc.c +@@ -20,13 +20,13 @@ + + #include "vfs.h" + +-struct proc_dir_entry *Novfs_Procfs_dir; +-static struct proc_dir_entry *Novfs_Control; +-static struct proc_dir_entry *Novfs_Library; +-static struct proc_dir_entry *Novfs_Version; ++struct proc_dir_entry *novfs_procfs_dir; ++struct proc_dir_entry *Novfs_Control; ++struct proc_dir_entry *Novfs_Library; ++struct proc_dir_entry *Novfs_Version; + +-static struct file_operations Daemon_proc_fops; +-static struct file_operations Library_proc_fops; ++static struct file_operations novfs_daemon_proc_fops; ++static struct file_operations novfs_lib_proc_fops; + + /*===[ Code ]=============================================================*/ + +@@ -39,17 +39,17 @@ static int Novfs_Get_Version(char *page, + buf = page + off; + *start = buf; + len = sprintf(buf, "Novfs Version=%s\n", NOVFS_VERSION_STRING); +- i = Daemon_getversion(tbuf, sizeof(tbuf)); ++ i = novfs_daemon_getversion(tbuf, sizeof(tbuf)); + if ((i > 0) && i < (count - len)) { + len += sprintf(buf + len, "Novfsd Version=%s\n", tbuf); + } + +- if (Novfs_CurrentMount) { +- i = strlen(Novfs_CurrentMount); ++ if (novfs_current_mnt) { ++ i = strlen(novfs_current_mnt); + if ((i > 0) && i < (count - len)) { + len += + sprintf(buf + len, "Novfs mount=%s\n", +- Novfs_CurrentMount); ++ novfs_current_mnt); + } + } + DbgPrint("Novfs_Get_Version:\n%s\n", buf); +@@ -58,39 +58,40 @@ static int Novfs_Get_Version(char *page, + return (len); + } + +-int Init_Procfs_Interface(void) ++int novfs_proc_init(void) + { + int retCode = 0; + +- Novfs_Procfs_dir = proc_mkdir(MODULE_NAME, NULL); +- if (Novfs_Procfs_dir) { +- Novfs_Procfs_dir->owner = THIS_MODULE; ++ novfs_procfs_dir = proc_mkdir(MODULE_NAME, NULL); ++ if (novfs_procfs_dir) { ++ novfs_procfs_dir->owner = THIS_MODULE; + +- Novfs_Control = create_proc_entry("Control", 0600, Novfs_Procfs_dir); ++ Novfs_Control = create_proc_entry("Control", 0600, novfs_procfs_dir); + + if (Novfs_Control) { + Novfs_Control->owner = THIS_MODULE; + Novfs_Control->size = 0; +- memcpy(&Daemon_proc_fops, Novfs_Control->proc_fops, +- sizeof(struct file_operations)); ++ memcpy(&novfs_daemon_proc_fops, ++ Novfs_Control->proc_fops, ++ sizeof(struct file_operations)); + + /* + * Setup our functions + */ +- Daemon_proc_fops.owner = THIS_MODULE; +- Daemon_proc_fops.open = Daemon_Open_Control; +- Daemon_proc_fops.release = Daemon_Close_Control; +- Daemon_proc_fops.read = Daemon_Send_Command; +- Daemon_proc_fops.write = Daemon_Receive_Reply; +- Daemon_proc_fops.ioctl = Daemon_ioctl; ++ novfs_daemon_proc_fops.owner = THIS_MODULE; ++ novfs_daemon_proc_fops.open = novfs_daemon_open_control; ++ novfs_daemon_proc_fops.release = novfs_daemon_close_control; ++ novfs_daemon_proc_fops.read = novfs_daemon_cmd_send; ++ novfs_daemon_proc_fops.write = novfs_daemon_recv_reply; ++ novfs_daemon_proc_fops.ioctl = novfs_daemon_ioctl; + +- Novfs_Control->proc_fops = &Daemon_proc_fops; ++ Novfs_Control->proc_fops = &novfs_daemon_proc_fops; + } else { + remove_proc_entry(MODULE_NAME, NULL); + return (-ENOENT); + } + +- Novfs_Library = create_proc_entry("Library", 0666, Novfs_Procfs_dir); ++ Novfs_Library = create_proc_entry("Library", 0666, novfs_procfs_dir); + if (Novfs_Library) { + Novfs_Library->owner = THIS_MODULE; + Novfs_Library->size = 0; +@@ -98,31 +99,31 @@ int Init_Procfs_Interface(void) + /* + * Setup our file functions + */ +- memcpy(&Library_proc_fops, Novfs_Library->proc_fops, ++ memcpy(&novfs_lib_proc_fops, Novfs_Library->proc_fops, + sizeof(struct file_operations)); +- Library_proc_fops.owner = THIS_MODULE; +- Library_proc_fops.open = Daemon_Library_open; +- Library_proc_fops.release = Daemon_Library_close; +- Library_proc_fops.read = Daemon_Library_read; +- Library_proc_fops.write = Daemon_Library_write; +- Library_proc_fops.llseek = Daemon_Library_llseek; +- Library_proc_fops.ioctl = Daemon_Library_ioctl; +- Novfs_Library->proc_fops = &Library_proc_fops; ++ novfs_lib_proc_fops.owner = THIS_MODULE; ++ novfs_lib_proc_fops.open = novfs_daemon_lib_open; ++ novfs_lib_proc_fops.release = novfs_daemon_lib_close; ++ novfs_lib_proc_fops.read = novfs_daemon_lib_read; ++ novfs_lib_proc_fops.write = novfs_daemon_lib_write; ++ novfs_lib_proc_fops.llseek = novfs_daemon_lib_llseek; ++ novfs_lib_proc_fops.ioctl = novfs_daemon_lib_ioctl; ++ Novfs_Library->proc_fops = &novfs_lib_proc_fops; + } else { +- remove_proc_entry("Control", Novfs_Procfs_dir); ++ remove_proc_entry("Control", novfs_procfs_dir); + remove_proc_entry(MODULE_NAME, NULL); + return (-ENOENT); + } + + Novfs_Version = +- create_proc_read_entry("Version", 0444, Novfs_Procfs_dir, ++ create_proc_read_entry("Version", 0444, novfs_procfs_dir, + Novfs_Get_Version, NULL); + if (Novfs_Version) { + Novfs_Version->owner = THIS_MODULE; + Novfs_Version->size = 0; + } else { +- remove_proc_entry("Library", Novfs_Procfs_dir); +- remove_proc_entry("Control", Novfs_Procfs_dir); ++ remove_proc_entry("Library", novfs_procfs_dir); ++ remove_proc_entry("Control", novfs_procfs_dir); + remove_proc_entry(MODULE_NAME, NULL); + retCode = -ENOENT; + } +@@ -132,17 +133,17 @@ int Init_Procfs_Interface(void) + return (retCode); + } + +-void Uninit_Procfs_Interface(void) ++void novfs_proc_exit(void) + { + + DbgPrint("Uninit_Procfs_Interface remove_proc_entry(Version, NULL)\n"); +- remove_proc_entry("Version", Novfs_Procfs_dir); ++ remove_proc_entry("Version", novfs_procfs_dir); + + DbgPrint("Uninit_Procfs_Interface remove_proc_entry(Control, NULL)\n"); +- remove_proc_entry("Control", Novfs_Procfs_dir); ++ remove_proc_entry("Control", novfs_procfs_dir); + + DbgPrint("Uninit_Procfs_Interface remove_proc_entry(Library, NULL)\n"); +- remove_proc_entry("Library", Novfs_Procfs_dir); ++ remove_proc_entry("Library", novfs_procfs_dir); + + DbgPrint("Uninit_Procfs_Interface remove_proc_entry(%s, NULL)\n", + MODULE_NAME); +--- a/fs/novfs/profile.c ++++ b/fs/novfs/profile.c +@@ -17,11 +17,12 @@ + #include + #include + #include ++#include + #include + #include ++ + #include + #include +-#include + + #include "vfs.h" + +@@ -41,10 +42,10 @@ struct local_rtc_time { + int tm_isdst; + }; + +-static char *DbgPrintBuffer = NULL; +-static char DbgPrintOn = 0; +-static char DbgSyslogOn = 0; +-static char DbgProfileOn = 0; ++char *DbgPrintBuffer = NULL; ++char DbgPrintOn = 0; ++char DbgSyslogOn = 0; ++char DbgProfileOn = 0; + + static unsigned long DbgPrintBufferOffset = 0; + static unsigned long DbgPrintBufferReadOffset = 0; +@@ -64,23 +65,22 @@ static DECLARE_MUTEX(LocalPrint_lock); + static ssize_t User_proc_write_DbgBuffer(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) + { + ssize_t retval = nbytes; +- unsigned char *lbuf; +- unsigned char *p; ++ u_char *lbuf, *p; + int i; ++ u_long cpylen; + + lbuf = kmalloc(nbytes + 1, GFP_KERNEL); + if (lbuf) { +- if (copy_from_user(lbuf, buf, nbytes)) +- return -EFAULT; ++ cpylen = copy_from_user(lbuf, buf, nbytes); + + lbuf[nbytes] = 0; + DbgPrint("User_proc_write_DbgBuffer: %s\n", lbuf); + +- for (i = 0; lbuf[i] && lbuf[i] != '\n'; i++) +- ; ++ for (i = 0; lbuf[i] && lbuf[i] != '\n'; i++) ; + +- if ('\n' == lbuf[i]) ++ if ('\n' == lbuf[i]) { + lbuf[i] = '\0'; ++ } + + if (!strcmp("on", lbuf)) { + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; +@@ -99,15 +99,15 @@ static ssize_t User_proc_write_DbgBuffer + DbgSyslogOn = 0; + } + } else if (!strcmp("novfsd", lbuf)) { +- Daemon_SendDebugCmd(p); ++ novfs_daemon_debug_cmd_send(p); + } else if (!strcmp("file_update_timeout", lbuf)) { +- File_update_timeout = ++ novfs_update_timeout = + simple_strtoul(p, NULL, 0); + } else if (!strcmp("cache", lbuf)) { + if (!strcmp("on", p)) { +- PageCache = 1; ++ novfs_page_cache = 1; + } else if (!strcmp("off", p)) { +- PageCache = 0; ++ novfs_page_cache = 0; + } + } else if (!strcmp("profile", lbuf)) { + if (!strcmp("on", p)) { +@@ -123,7 +123,7 @@ static ssize_t User_proc_write_DbgBuffer + return (retval); + } + +-static ssize_t User_proc_read_DbgBuffer(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) ++static ssize_t User_proc_read_DbgBuffer(struct file *file, char *buf, size_t nbytes, loff_t * ppos) + { + ssize_t retval = 0; + size_t count; +@@ -273,7 +273,7 @@ static void doline(unsigned char *b, uns + } + } + +-void mydump(int size, void *dumpptr) ++void novfs_dump(int size, void *dumpptr) + { + unsigned char *ptr = (unsigned char *)dumpptr; + unsigned char *line = NULL, buf[100], *bptr = buf; +@@ -314,7 +314,7 @@ static int month_days[12] = { + /* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +-static void Novfs_GregorianDay(struct local_rtc_time *tm) ++static void GregorianDay(struct local_rtc_time *tm) + { + int leapsToDate; + int lastYear; +@@ -384,14 +384,17 @@ static void private_to_tm(int tim, struc + /* + * Determine the day of week + */ +- Novfs_GregorianDay(tm); ++ GregorianDay(tm); + } + + char *ctime_r(time_t * clock, char *buf) + { + struct local_rtc_time tm; +- static char *DAYOFWEEK[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +- static char *MONTHOFYEAR[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; ++ static char *DAYOFWEEK[] = ++ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; ++ static char *MONTHOFYEAR[] = ++ { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", ++"Oct", "Nov", "Dec" }; + + private_to_tm(*clock, &tm); + +@@ -401,7 +404,7 @@ char *ctime_r(time_t * clock, char *buf) + return (buf); + } + +-static void profile_dump_dt(struct dentry *parent, void *pf) ++static void dump(struct dentry *parent, void *pf) + { + void (*pfunc) (char *Fmt, ...) = pf; + struct l { +@@ -413,9 +416,11 @@ static void profile_dump_dt(struct dentr + char *buf, *path, *sd; + char inode_number[16]; + +- buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); +- if (!buf) ++ buf = (char *)kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ ++ if (NULL == buf) { + return; ++ } + + if (parent) { + pfunc("starting 0x%p %.*s\n", parent, parent->d_name.len, +@@ -432,20 +437,25 @@ static void profile_dump_dt(struct dentr + p = l->dentry->d_subdirs.next; + while (p != &l->dentry->d_subdirs) { + d = list_entry(p, struct dentry, +- D_CHILD); ++ d_u.d_child); + p = p->next; + +- if (d->d_subdirs.next != &d->d_subdirs) { +- n = kmalloc(sizeof(*n), GFP_KERNEL); ++ if (d->d_subdirs.next != ++ &d->d_subdirs) { ++ n = kmalloc(sizeof ++ (*n), ++ GFP_KERNEL); + if (n) { +- n->next = l->next; ++ n->next = ++ l->next; + l->next = n; + n->dentry = d; + } + } else { +- path = Scope_dget_path(d, buf, PATH_LENGTH_BUFFER, 1); ++ path = novfs_scope_dget_path(d, buf, PATH_LENGTH_BUFFER, 1); + if (path) { +- pfunc("1-0x%p %s\n" ++ pfunc ++ ("1-0x%p %s\n" + " d_name: %.*s\n" + " d_parent: 0x%p\n" + " d_count: %d\n" +@@ -453,14 +463,21 @@ static void profile_dump_dt(struct dentr + " d_subdirs: 0x%p\n" + " d_inode: 0x%p\n", + d, path, +- d->d_name.len, +- d->d_name.name, +- d->d_parent, +- atomic_read(&d->d_count), ++ d->d_name. ++ len, ++ d->d_name. ++ name, ++ d-> ++ d_parent, ++ atomic_read ++ (&d-> ++ d_count), + d->d_flags, +- d->d_subdirs. ++ d-> ++ d_subdirs. + next, +- d->d_inode); ++ d-> ++ d_inode); + } + } + } +@@ -469,11 +486,16 @@ static void profile_dump_dt(struct dentr + l = start; + while (l) { + d = l->dentry; +- path = Scope_dget_path(d, buf, PATH_LENGTH_BUFFER, 1); ++ path = ++ novfs_scope_dget_path(d, buf, ++ PATH_LENGTH_BUFFER, ++ 1); + if (path) { + sd = " (None)"; +- if (&d->d_subdirs != d->d_subdirs.next) ++ if (&d->d_subdirs != ++ d->d_subdirs.next) { + sd = ""; ++ } + inode_number[0] = '\0'; + if (d->d_inode) { + sprintf(inode_number, +@@ -506,7 +528,7 @@ static void profile_dump_dt(struct dentr + + } + +-static ssize_t profile_common_read(char __user *buf, size_t len, loff_t *off) ++static ssize_t common_read(char *buf, size_t len, loff_t * off) + { + ssize_t retval = 0; + size_t count; +@@ -530,7 +552,8 @@ static ssize_t profile_common_read(char + + } + +-static ssize_t profile_inode_read(struct file * file, char __user *buf, size_t len, loff_t *off) ++static ssize_t novfs_profile_read_inode(struct file * file, char *buf, size_t len, ++ loff_t * off) + { + ssize_t retval = 0; + unsigned long offset = *off; +@@ -542,10 +565,11 @@ static ssize_t profile_inode_read(struct + DbgPrintOn = 0; + + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; +- Novfs_dump_inode(LocalPrint); ++ novfs_dump_inode(LocalPrint); + } + +- retval = profile_common_read(buf, len, off); ++ ++ retval = common_read(buf, len, off); + + if (0 == retval) { + DbgPrintOn = save_DbgPrintOn; +@@ -558,7 +582,8 @@ static ssize_t profile_inode_read(struct + + } + +-static ssize_t profile_dentry_read(struct file *file, char __user *buf, size_t len, loff_t * off) ++static ssize_t novfs_profile_dentry_read(struct file * file, char *buf, size_t len, ++ loff_t * off) + { + ssize_t retval = 0; + unsigned long offset = *off; +@@ -569,10 +594,10 @@ static ssize_t profile_dentry_read(struc + save_DbgPrintOn = DbgPrintOn; + DbgPrintOn = 0; + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; +- profile_dump_dt(Novfs_root, LocalPrint); ++ dump(novfs_root, LocalPrint); + } + +- retval = profile_common_read(buf, len, off); ++ retval = common_read(buf, len, off); + + if (0 == retval) { + DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; +@@ -585,7 +610,7 @@ static ssize_t profile_dentry_read(struc + + } + +-uint64_t get_nanosecond_time(void) ++uint64_t get_nanosecond_time() + { + struct timespec ts; + uint64_t retVal; +@@ -599,15 +624,12 @@ uint64_t get_nanosecond_time(void) + return (retVal); + } + +-int init_profile(void) ++void novfs_profile_init() + { +- int retCode = 0; +- +- if (Novfs_Procfs_dir) { +- dbg_dir = Novfs_Procfs_dir; +- } else { ++ if (novfs_procfs_dir) ++ dbg_dir = novfs_procfs_dir; ++ else + dbg_dir = proc_mkdir(MODULE_NAME, NULL); +- } + + if (dbg_dir) { + dbg_dir->owner = THIS_MODULE; +@@ -620,8 +642,10 @@ int init_profile(void) + dbg_file->size = DBGBUFFERSIZE; + memcpy(&Dbg_proc_file_operations, dbg_file->proc_fops, + sizeof(struct file_operations)); +- Dbg_proc_file_operations.read = User_proc_read_DbgBuffer; +- Dbg_proc_file_operations.write = User_proc_write_DbgBuffer; ++ Dbg_proc_file_operations.read = ++ User_proc_read_DbgBuffer; ++ Dbg_proc_file_operations.write = ++ User_proc_write_DbgBuffer; + dbg_file->proc_fops = &Dbg_proc_file_operations; + } else { + remove_proc_entry(MODULE_NAME, NULL); +@@ -640,7 +664,8 @@ int init_profile(void) + inode_file->proc_fops, + sizeof(struct file_operations)); + inode_proc_file_ops.owner = THIS_MODULE; +- inode_proc_file_ops.read = profile_inode_read; ++ inode_proc_file_ops.read = ++ novfs_profile_read_inode; + inode_file->proc_fops = &inode_proc_file_ops; + } + +@@ -653,32 +678,30 @@ int init_profile(void) + dentry_file->proc_fops, + sizeof(struct file_operations)); + dentry_proc_file_ops.owner = THIS_MODULE; +- dentry_proc_file_ops.read = profile_dentry_read; ++ dentry_proc_file_ops.read = novfs_profile_dentry_read; + dentry_file->proc_fops = &dentry_proc_file_ops; + } ++ + } else { + vfree(DbgPrintBuffer); + DbgPrintBuffer = NULL; + } + } +- return (retCode); + } + +-void uninit_profile(void) ++void novfs_profile_exit(void) + { +- if (dbg_file) { +- DbgPrint("Calling remove_proc_entry(Debug, NULL)\n"); +- remove_proc_entry("Debug", dbg_dir); +- } +- if (inode_file) { +- DbgPrint("Calling remove_proc_entry(inode, NULL)\n"); +- remove_proc_entry("inode", dbg_dir); +- } +- if (dentry_file) { +- DbgPrint("Calling remove_proc_entry(dentry, NULL)\n"); +- remove_proc_entry("dentry", dbg_dir); +- } +- if (dbg_dir && (dbg_dir != Novfs_Procfs_dir)) { ++ if (dbg_file) ++ DbgPrint("Calling remove_proc_entry(Debug, NULL)\n"), ++ remove_proc_entry("Debug", dbg_dir); ++ if (inode_file) ++ DbgPrint("Calling remove_proc_entry(inode, NULL)\n"), ++ remove_proc_entry("inode", dbg_dir); ++ if (dentry_file) ++ DbgPrint("Calling remove_proc_entry(dentry, NULL)\n"), ++ remove_proc_entry("dentry", dbg_dir); ++ ++ if (dbg_dir && (dbg_dir != novfs_procfs_dir)) { + DbgPrint("Calling remove_proc_entry(%s, NULL)\n", MODULE_NAME); + remove_proc_entry(MODULE_NAME, NULL); + } +--- a/fs/novfs/scope.c ++++ b/fs/novfs/scope.c +@@ -33,55 +33,40 @@ + #define CLEANUP_INTERVAL 10 + #define MAX_USERNAME_LENGTH 32 + +-struct scope_list { +- struct list_head entry; +- struct schandle ScopeId; +- struct schandle SessionId; +- pid_t ScopePid; +- struct task_struct *ScopeTask; +- unsigned int ScopeHash; +- uid_t ScopeUid; +- u64 ScopeUSize; +- u64 ScopeUFree; +- u64 ScopeUTEnties; +- u64 ScopeUAEnties; +- int ScopeUserNameLength; +- unsigned char ScopeUserName[MAX_USERNAME_LENGTH]; +-}; + + static struct list_head Scope_List; + static struct semaphore Scope_Lock; + static struct semaphore Scope_Thread_Delay; +-static int Scope_Thread_Terminate; ++static int Scope_Thread_Terminate = 0; + static struct timer_list Scope_Timer; + static unsigned int Scope_Hash_Val = 1; + +-static struct scope_list *Scope_Search4Scope(struct schandle *Id, bool Session, +- bool Locked) ++static struct novfs_scope_list *Scope_Search4Scope(struct novfs_schandle Id, ++ int Session, int Locked) + { +- struct scope_list *scope; +- struct scope_list *rscope = NULL; +- struct schandle *cur_scope; ++ struct novfs_scope_list *scope, *rscope = NULL; ++ struct novfs_schandle cur_scope; + struct list_head *sl; + int offset; + +- DbgPrint("Scope_Search4Scope: 0x%p:%p 0x%x 0x%x\n", +- Id->hTypeId, Id->hId, Session, Locked); ++ DbgPrint("Scope_Search4Scope: 0x%p:%p 0x%x 0x%x\n", Id.hTypeId, Id.hId, ++ Session, Locked); + + if (Session) +- offset = offsetof(struct scope_list, SessionId); ++ offset = offsetof(struct novfs_scope_list, SessionId); + else +- offset = offsetof(struct scope_list, ScopeId); ++ offset = offsetof(struct novfs_scope_list, ScopeId); + +- if (!Locked) ++ if (!Locked) { + down(&Scope_Lock); ++ } + + sl = Scope_List.next; + DbgPrint("Scope_Search4Scope: 0x%p\n", sl); + while (sl != &Scope_List) { +- scope = list_entry(sl, struct scope_list, entry); ++ scope = list_entry(sl, struct novfs_scope_list, ScopeList); + +- cur_scope = (session_t *) ((char *)scope + offset); ++ cur_scope = *(struct novfs_schandle *) ((char *)scope + offset); + if (SC_EQUAL(Id, cur_scope)) { + rscope = scope; + break; +@@ -90,19 +75,19 @@ static struct scope_list *Scope_Search4S + sl = sl->next; + } + +- if (!Locked) ++ if (!Locked) { + up(&Scope_Lock); ++ } + + DbgPrint("Scope_Search4Scope: return 0x%p\n", rscope); +- return rscope; ++ return (rscope); + } + +-static struct scope_list *Scope_Find_Scope(bool Create) ++static struct novfs_scope_list *Scope_Find_Scope(int Create) + { +- struct scope_list *scope = NULL; +- struct scope_list *pscope = NULL; ++ struct novfs_scope_list *scope = NULL, *pscope = NULL; + struct task_struct *task; +- struct schandle scopeId; ++ struct novfs_schandle scopeId; + int addscope = 0; + + task = current; +@@ -110,84 +95,94 @@ static struct scope_list *Scope_Find_Sco + DbgPrint("Scope_Find_Scope: %d %d %d %d\n", task->uid, task->euid, + task->suid, task->fsuid); + +- /* scopeId = task->euid; */ ++ //scopeId = task->euid; + UID_TO_SCHANDLE(scopeId, task->euid); + +- scope = Scope_Search4Scope(&scopeId, 0, 0); +- if (scope || (!Create)) +- return scope; ++ scope = Scope_Search4Scope(scopeId, 0, 0); + +- scope = kmalloc(sizeof(*pscope), GFP_KERNEL); +- if (!scope) +- return NULL; +- scope->ScopeId = scopeId; +- SC_INITIALIZE(scope->SessionId); +- scope->ScopePid = task->pid; +- scope->ScopeTask = task; +- scope->ScopeHash = 0; +- scope->ScopeUid = task->euid; +- scope->ScopeUserName[0] = '\0'; +- +- if (!Daemon_CreateSessionId(&scope->SessionId)) { +- DbgPrint("Scope_Find_Scope2: %d %d %d %d\n", task->uid, +- task->euid, task->suid, task->fsuid); +- memset(scope->ScopeUserName, 0, sizeof(scope->ScopeUserName)); +- scope->ScopeUserNameLength = 0; +- Daemon_getpwuid(task->euid, sizeof(scope->ScopeUserName), +- scope->ScopeUserName); +- scope->ScopeUserNameLength = strlen(scope->ScopeUserName); +- addscope = 1; +- } +- +- scope->ScopeHash = Scope_Hash_Val++; +- DbgPrint("Scope_Find_Scope: Adding 0x%p\n" +- " ScopeId: 0x%p:%p\n" +- " SessionId: 0x%p:%p\n" +- " ScopePid: %d\n" +- " ScopeTask: 0x%p\n" +- " ScopeHash: %u\n" +- " ScopeUid: %u\n" +- " ScopeUserNameLength: %u\n" +- " ScopeUserName: %s\n", +- scope, +- scope->ScopeId.hTypeId, scope->ScopeId.hId, +- scope->SessionId.hTypeId, scope->SessionId.hId, +- scope->ScopePid, +- scope->ScopeTask, +- scope->ScopeHash, +- scope->ScopeUid, +- scope->ScopeUserNameLength, +- scope->ScopeUserName); ++ if (!scope && Create) { ++ scope = kmalloc(sizeof(*pscope), GFP_KERNEL); ++ if (scope) { ++ scope->ScopeId = scopeId; ++ SC_INITIALIZE(scope->SessionId); ++ scope->ScopePid = task->pid; ++ scope->ScopeTask = task; ++ scope->ScopeHash = 0; ++ scope->ScopeUid = task->euid; ++ scope->ScopeUserName[0] = '\0'; ++ ++ if (!novfs_daemon_create_sessionId(&scope->SessionId)) { ++ DbgPrint("Scope_Find_Scope2: %d %d %d %d\n", ++ task->uid, task->euid, task->suid, ++ task->fsuid); ++ memset(scope->ScopeUserName, 0, ++ sizeof(scope->ScopeUserName)); ++ scope->ScopeUserNameLength = 0; ++ novfs_daemon_getpwuid(task->euid, ++ sizeof(scope->ScopeUserName), ++ scope->ScopeUserName); ++ scope->ScopeUserNameLength = ++ strlen(scope->ScopeUserName); ++ addscope = 1; ++ } + +- if (SC_PRESENT(scope->SessionId)) { +- down(&Scope_Lock); +- pscope = Scope_Search4Scope(&scopeId, 0, 1); +- if (!pscope) +- list_add(&scope->entry, &Scope_List); +- up(&Scope_Lock); ++ scope->ScopeHash = Scope_Hash_Val++; ++ DbgPrint("Scope_Find_Scope: Adding 0x%p\n" ++ " ScopeId: 0x%p:%p\n" ++ " SessionId: 0x%p:%p\n" ++ " ScopePid: %d\n" ++ " ScopeTask: 0x%p\n" ++ " ScopeHash: %u\n" ++ " ScopeUid: %u\n" ++ " ScopeUserNameLength: %u\n" ++ " ScopeUserName: %s\n", ++ scope, ++ scope->ScopeId.hTypeId, scope->ScopeId.hId, ++ scope->SessionId.hTypeId, scope->SessionId.hId, ++ scope->ScopePid, ++ scope->ScopeTask, ++ scope->ScopeHash, ++ scope->ScopeUid, ++ scope->ScopeUserNameLength, ++ scope->ScopeUserName); ++ ++ if (SC_PRESENT(scope->SessionId)) { ++ down(&Scope_Lock); ++ pscope = ++ Scope_Search4Scope(scopeId, 0, 1); ++ ++ if (!pscope) { ++ list_add(&scope->ScopeList, ++ &Scope_List); ++ } ++ up(&Scope_Lock); + +- if (pscope) { +- printk(KERN_ERR "Scope_Find_Scope scope not added " +- "because it was already there...\n"); +- Daemon_DestroySessionId(&scope->SessionId); +- kfree(scope); +- scope = pscope; +- addscope = 0; ++ if (pscope) { ++ printk ++ ("<6>Scope_Find_Scope scope not added because it was already there...\n"); ++ novfs_daemon_destroy_sessionId(scope-> ++ SessionId); ++ kfree(scope); ++ scope = pscope; ++ addscope = 0; ++ } ++ } else { ++ kfree(scope); ++ scope = NULL; ++ } + } +- } else { +- kfree(scope); +- scope = NULL; +- } + +- if (addscope) +- Novfs_Add_to_Root(scope->ScopeUserName); ++ if (addscope) { ++ novfs_add_to_root(scope->ScopeUserName); ++ } ++ } + +- return scope; ++ return (scope); + } + +-static int Scope_Validate_Scope(struct scope_list *Scope) ++static int Scope_Validate_Scope(struct novfs_scope_list *Scope) + { +- struct scope_list *s; ++ struct novfs_scope_list *s; + struct list_head *sl; + int retVal = 0; + +@@ -197,7 +192,7 @@ static int Scope_Validate_Scope(struct s + + sl = Scope_List.next; + while (sl != &Scope_List) { +- s = list_entry(sl, struct scope_list, entry); ++ s = list_entry(sl, struct novfs_scope_list, ScopeList); + + if (s == Scope) { + retVal = 1; +@@ -209,28 +204,24 @@ static int Scope_Validate_Scope(struct s + + up(&Scope_Lock); + +- return retVal; ++ return (retVal); + } + +-/* FIXME void stuff */ +-uid_t Scope_Get_Uid(void *foo) ++uid_t novfs_scope_get_uid(struct novfs_scope_list *scope) + { +- struct scope_list *scope = foo; + uid_t uid = 0; +- + if (!scope) + scope = Scope_Find_Scope(1); + + if (scope && Scope_Validate_Scope(scope)) + uid = scope->ScopeUid; +- + return uid; + } + +-char *Scope_Get_UserName(void) ++char *novfs_scope_get_username(void) + { + char *name = NULL; +- struct scope_list *Scope; ++ struct novfs_scope_list *Scope; + + Scope = Scope_Find_Scope(1); + +@@ -240,12 +231,10 @@ char *Scope_Get_UserName(void) + return name; + } + +-/* FIXME the void * needs to get fixed... */ +-session_t Scope_Get_SessionId(void *foo) ++struct novfs_schandle novfs_scope_get_sessionId(struct novfs_scope_list ++ *Scope) + { +- session_t sessionId; +- struct scope_list *Scope = foo; +- ++ struct novfs_schandle sessionId; + DbgPrint("Scope_Get_SessionId: 0x%p\n", Scope); + SC_INITIALIZE(sessionId); + if (!Scope) +@@ -253,43 +242,43 @@ session_t Scope_Get_SessionId(void *foo) + + if (Scope && Scope_Validate_Scope(Scope)) + sessionId = Scope->SessionId; +- + DbgPrint("Scope_Get_SessionId: return 0x%p:%p\n", sessionId.hTypeId, + sessionId.hId); +- return sessionId; ++ return (sessionId); + } + +-struct scope_list *Scope_Get_ScopefromName(struct qstr *name) ++struct novfs_scope_list *novfs_get_scope_from_name(struct qstr * Name) + { +- struct scope_list *scope; +- struct scope_list *rscope = NULL; ++ struct novfs_scope_list *scope, *rscope = NULL; + struct list_head *sl; + +- DbgPrint("Scope_Get_ScopefromName: %.*s\n", name->len, name->name); ++ DbgPrint("Scope_Get_ScopefromName: %.*s\n", Name->len, Name->name); + + down(&Scope_Lock); + + sl = Scope_List.next; + while (sl != &Scope_List) { +- scope = list_entry(sl, struct scope_list, entry); ++ scope = list_entry(sl, struct novfs_scope_list, ScopeList); + +- if ((name->len == scope->ScopeUserNameLength) && +- (strncmp(scope->ScopeUserName, name->name, name->len) == 0)) { ++ if ((Name->len == scope->ScopeUserNameLength) && ++ (0 == strncmp(scope->ScopeUserName, Name->name, Name->len))) ++ { + rscope = scope; + break; + } ++ + sl = sl->next; + } + + up(&Scope_Lock); + +- return rscope; ++ return (rscope); + } + +-int Scope_Set_UserSpace(u64 *TotalSize, u64 *Free, +- u64 *TotalEnties, u64 *FreeEnties) ++int novfs_scope_set_userspace(uint64_t * TotalSize, uint64_t * Free, ++ uint64_t * TotalEnties, uint64_t * FreeEnties) + { +- struct scope_list *scope; ++ struct novfs_scope_list *scope; + int retVal = 0; + + scope = Scope_Find_Scope(1); +@@ -305,24 +294,24 @@ int Scope_Set_UserSpace(u64 *TotalSize, + scope->ScopeUAEnties = *FreeEnties; + } + +- return retVal; ++ return (retVal); + } + +-int Scope_Get_UserSpace(u64 *TotalSize, u64 *Free, +- u64 *TotalEnties, u64 *FreeEnties) ++int novfs_scope_get_userspace(uint64_t * TotalSize, uint64_t * Free, ++ uint64_t * TotalEnties, uint64_t * FreeEnties) + { +- struct scope_list *scope; ++ struct novfs_scope_list *scope; + int retVal = 0; + +- u64 td, fd, te, fe; ++ uint64_t td, fd, te, fe; + + scope = Scope_Find_Scope(1); + + td = fd = te = fe = 0; + if (scope) { + +- retVal = Daemon_Get_UserSpace(&scope->SessionId, +- &td, &fd, &te, &fe); ++ retVal = ++ novfs_daemon_get_userspace(scope->SessionId, &td, &fd, &te, &fe); + + scope->ScopeUSize = td; + scope->ScopeUFree = fd; +@@ -339,18 +328,18 @@ int Scope_Get_UserSpace(u64 *TotalSize, + if (FreeEnties) + *FreeEnties = fe; + +- return retVal; ++ return (retVal); + } + +-struct scope_list *Scope_Get_ScopefromPath(struct dentry *dentry) ++struct novfs_scope_list *novfs_get_scope(struct dentry * Dentry) + { +- struct scope_list *scope = NULL; ++ struct novfs_scope_list *scope = NULL; + char *buf, *path, *cp; + struct qstr name; + +- buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ buf = (char *)kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); + if (buf) { +- path = Scope_dget_path(dentry, buf, PATH_LENGTH_BUFFER, 0); ++ path = novfs_scope_dget_path(Dentry, buf, PATH_LENGTH_BUFFER, 0); + if (path) { + DbgPrint("Scope_Get_ScopefromPath: %s\n", path); + +@@ -366,29 +355,30 @@ struct scope_list *Scope_Get_ScopefromPa + name.hash = 0; + name.len = (int)(cp - path); + name.name = path; +- scope = Scope_Get_ScopefromName(&name); ++ scope = novfs_get_scope_from_name(&name); + } + } + kfree(buf); + } + +- return scope; ++ return (scope); + } + +-static char *add_to_list(char *name, char *list, char *endoflist) ++static char *add_to_list(char *Name, char *List, char *EndOfList) + { +- while (*name && (list < endoflist)) +- *list++ = *name++; +- +- if (list < endoflist) +- *list++ = '\0'; ++ while (*Name && (List < EndOfList)) { ++ *List++ = *Name++; ++ } + +- return list; ++ if (List < EndOfList) { ++ *List++ = '\0'; ++ } ++ return (List); + } + +-char *Scope_Get_ScopeUsers(void) ++char *novfs_get_scopeusers(void) + { +- struct scope_list *scope; ++ struct novfs_scope_list *scope; + struct list_head *sl; + int asize = 8 * MAX_USERNAME_LENGTH; + char *list, *cp, *ep; +@@ -413,7 +403,7 @@ char *Scope_Get_ScopeUsers(void) + + sl = Scope_List.next; + while ((sl != &Scope_List) && (cp < ep)) { +- scope = list_entry(sl, struct scope_list, entry); ++ scope = list_entry(sl, struct novfs_scope_list, ScopeList); + + DbgPrint("Scope_Get_ScopeUsers found 0x%p %s\n", + scope, scope->ScopeUserName); +@@ -429,6 +419,7 @@ char *Scope_Get_ScopeUsers(void) + *cp++ = '\0'; + asize = 0; + } else { /* Allocation was to small, up size */ ++ + asize *= 4; + kfree(list); + list = NULL; +@@ -437,12 +428,12 @@ char *Scope_Get_ScopeUsers(void) + + break; + } +- } while (!list); /* list was to small try again */ ++ } while (!list); /* List was to small try again */ + +- return list; ++ return (list); + } + +-void *Scope_Lookup(void) ++void *novfs_scope_lookup(void) + { + return Scope_Find_Scope(1); + } +@@ -454,8 +445,7 @@ static void Scope_Timer_Function(unsigne + + static int Scope_Cleanup_Thread(void *Args) + { +- struct scope_list *scope; +- struct scope_list *rscope; ++ struct novfs_scope_list *scope, *rscope; + struct list_head *sl, cleanup; + struct task_struct *task; + +@@ -468,8 +458,9 @@ static int Scope_Cleanup_Thread(void *Ar + + while (0 == Scope_Thread_Terminate) { + DbgPrint("Scope_Cleanup_Thread: looping\n"); +- if (Scope_Thread_Terminate) ++ if (Scope_Thread_Terminate) { + break; ++ } + + /* + * Check scope list for any terminated processes +@@ -480,7 +471,7 @@ static int Scope_Cleanup_Thread(void *Ar + INIT_LIST_HEAD(&cleanup); + + while (sl != &Scope_List) { +- scope = list_entry(sl, struct scope_list, entry); ++ scope = list_entry(sl, struct novfs_scope_list, ScopeList); + sl = sl->next; + + rscope = NULL; +@@ -495,7 +486,7 @@ static int Scope_Cleanup_Thread(void *Ar + rcu_read_unlock(); + + if (!rscope) { +- list_move(&scope->entry, &cleanup); ++ list_move(&scope->ScopeList, &cleanup); + DbgPrint("Scope_Cleanup_Thread: Scope=0x%p\n", + rscope); + } +@@ -505,7 +496,7 @@ static int Scope_Cleanup_Thread(void *Ar + + sl = cleanup.next; + while (sl != &cleanup) { +- scope = list_entry(sl, struct scope_list, entry); ++ scope = list_entry(sl, struct novfs_scope_list, ScopeList); + sl = sl->next; + + DbgPrint("Scope_Cleanup_Thread: Removing 0x%p\n" +@@ -523,9 +514,9 @@ static int Scope_Cleanup_Thread(void *Ar + scope->ScopeTask, + scope->ScopeHash, + scope->ScopeUid, scope->ScopeUserName); +- if (!Scope_Search4Scope(&scope->SessionId, 1, 0)) { +- Novfs_Remove_from_Root(scope->ScopeUserName); +- Daemon_DestroySessionId(&scope->SessionId); ++ if (!Scope_Search4Scope(scope->SessionId, 1, 0)) { ++ novfs_remove_from_root(scope->ScopeUserName); ++ novfs_daemon_destroy_sessionId(scope->SessionId); + } + kfree(scope); + } +@@ -536,21 +527,21 @@ static int Scope_Cleanup_Thread(void *Ar + add_timer(&Scope_Timer); + DbgPrint("Scope_Cleanup_Thread: sleeping\n"); + +- if (down_interruptible(&Scope_Thread_Delay)) ++ if (down_interruptible(&Scope_Thread_Delay)) { + break; +- ++ } + del_timer(&Scope_Timer); + } + Scope_Thread_Terminate = 0; + + printk(KERN_INFO "Scope_Cleanup_Thread: Exit\n"); + DbgPrint("Scope_Cleanup_Thread: Exit\n"); +- return 0; ++ return (0); + } + +-void Scope_Cleanup(void) ++void novfs_scope_cleanup(void) + { +- struct scope_list *scope; ++ struct novfs_scope_list *scope; + struct list_head *sl; + + DbgPrint("Scope_Cleanup:\n"); +@@ -563,10 +554,10 @@ void Scope_Cleanup(void) + sl = Scope_List.next; + + while (sl != &Scope_List) { +- scope = list_entry(sl, struct scope_list, entry); ++ scope = list_entry(sl, struct novfs_scope_list, ScopeList); + sl = sl->next; + +- list_del(&scope->entry); ++ list_del(&scope->ScopeList); + + DbgPrint("Scope_Cleanup: Removing 0x%p\n" + " ScopeId: 0x%p:%p\n" +@@ -583,9 +574,9 @@ void Scope_Cleanup(void) + scope->ScopeTask, + scope->ScopeHash, + scope->ScopeUid, scope->ScopeUserName); +- if (!Scope_Search4Scope(&scope->SessionId, 1, 1)) { +- Novfs_Remove_from_Root(scope->ScopeUserName); +- Daemon_DestroySessionId(&scope->SessionId); ++ if (!Scope_Search4Scope(scope->SessionId, 1, 1)) { ++ novfs_remove_from_root(scope->ScopeUserName); ++ novfs_daemon_destroy_sessionId(scope->SessionId); + } + kfree(scope); + } +@@ -595,19 +586,13 @@ void Scope_Cleanup(void) + } + + /* +- * Arguments: struct dentry *dentry - starting entry +- * char *Buf - pointer to memory buffer +- * unsigned int Buflen - size of memory buffer +- * +- * Returns: pointer to path. +- * +- * Abstract: Walks the dentry chain building a path. ++ * Walks the dentry chain building a path. + */ +-char *Scope_dget_path(struct dentry *dentry, char *Buf, unsigned int Buflen, ++char *novfs_scope_dget_path(struct dentry *Dentry, char *Buf, unsigned int Buflen, + int Flags) + { + char *retval = &Buf[Buflen]; +- struct dentry *p = dentry; ++ struct dentry *p = Dentry; + int len; + + *(--retval) = '\0'; +@@ -627,8 +612,9 @@ char *Scope_dget_path(struct dentry *den + } + } while (!IS_ROOT(p)); + +- if (IS_ROOT(dentry)) ++ if (IS_ROOT(Dentry)) { + retval++; ++ } + + if (Flags) { + len = strlen(p->d_sb->s_type->name); +@@ -641,19 +627,18 @@ char *Scope_dget_path(struct dentry *den + } + } + +- return retval; ++ return (retval); + } + +-void Scope_Init(void) ++void novfs_scope_init(void) + { + INIT_LIST_HEAD(&Scope_List); + init_MUTEX(&Scope_Lock); + init_MUTEX_LOCKED(&Scope_Thread_Delay); +- + kthread_run(Scope_Cleanup_Thread, NULL, "novfs_ST"); + } + +-void Scope_Uninit(void) ++void novfs_scope_exit(void) + { + unsigned long expires = jiffies + HZ * SHUTDOWN_INTERVAL; + +@@ -666,7 +651,6 @@ void Scope_Uninit(void) + mb(); + while (Scope_Thread_Terminate && (jiffies < expires)) + yield(); +- + /* down(&Scope_Thread_Delay); */ + printk(KERN_INFO "Scope_Uninit: Exit\n"); + +--- a/fs/novfs/vfs.h ++++ b/fs/novfs/vfs.h +@@ -20,37 +20,31 @@ + + #include + #include +-#include + + #include "nwcapi.h" + +-typedef void *HANDLE; + +-struct schandle { +- void *hTypeId; +- void *hId; +-}; +- +-static inline void copy_schandle(struct schandle *dest, struct schandle *source) +-{ +- memcpy(dest, source, sizeof(struct schandle)); +-} +-#define copy_session_id copy_schandle ++#ifndef XTIER_SCHANDLE ++struct novfs_schandle { ++ void * hTypeId; ++ void * hId; + +-typedef struct schandle session_t; ++}; + + #include "commands.h" + + #define SC_PRESENT(X) ((X.hTypeId != NULL) || (X.hId != NULL)) ? 1 : 0 +-#define SC_EQUAL(X, Y) ((X->hTypeId == Y->hTypeId) && (X->hId == Y->hId)) ? 1 : 0 ++#define SC_EQUAL(X, Y) ((X.hTypeId == Y.hTypeId) && (X.hId == Y.hId)) ? 1 : 0 + #define SC_INITIALIZE(X) {X.hTypeId = X.hId = NULL;} + + #define UID_TO_SCHANDLE(hSC, uid) \ + { \ + hSC.hTypeId = NULL; \ +- hSC.hId = (HANDLE)(unsigned long)(uid); \ ++ hSC.hId = (void *)(unsigned long)(uid); \ + } + ++#define XTIER_SCHANDLE ++#endif + + + /*===[ Manifest constants ]===============================================*/ +@@ -71,16 +65,6 @@ typedef struct schandle session_t; + #define IOC_SESSION 0x4a540003 + #define IOC_DEBUGPRINT 0x4a540004 + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) +-#define D_CHILD d_u.d_child +-#define AS_TREE_LOCK(l) read_lock_irq(l) +-#define AS_TREE_UNLOCK(l) read_unlock_irq(l) +-#else +-#define D_CHILD d_child +-#define AS_TREE_LOCK(l) spin_lock_irq(l) +-#define AS_TREE_UNLOCK(l) spin_unlock_irq(l) +-#endif +- + /* + * NetWare file attributes + */ +@@ -96,7 +80,7 @@ typedef struct schandle session_t; + #define NW_ATTRIBUTE_SHAREABLE 0x80 + + /* +- * Define READ/WRITE flag for struct data_list ++ * Define READ/WRITE flag for DATA_LIST + */ + #define DLREAD 0 + #define DLWRITE 1 +@@ -156,7 +140,8 @@ typedef struct schandle session_t; + DEFINE_TO_STR(NOVFS_VFS_RELEASE) \ + "\0" + +-struct entry_info { ++/*===[ Type definitions ]=================================================*/ ++struct novfs_entry_info { + int type; + umode_t mode; + uid_t uid; +@@ -174,17 +159,17 @@ struct novfs_string { + unsigned char *data; + }; + +-struct login { ++struct novfs_login { + struct novfs_string Server; + struct novfs_string UserName; + struct novfs_string Password; + }; + +-struct logout { ++struct novfs_logout { + struct novfs_string Server; + }; + +-struct dir_cache { ++struct novfs_dir_cache { + struct list_head list; + int flags; + u64 jiffies; +@@ -199,7 +184,7 @@ struct dir_cache { + char name[1]; + }; + +-struct data_list { ++struct novfs_data_list { + void *page; + void *offset; + int len; +@@ -209,227 +194,256 @@ struct data_list { + + extern char *ctime_r(time_t * clock, char *buf); + +-static inline u32 HandletoUint32(HANDLE h) + /* +- * +- * Arguments: HANDLE h - handle value +- * +- * Returns: u32 - u32 value +- * +- * Abstract: Converts a HANDLE to a u32 type. +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++ * Converts a HANDLE to a u32 type. ++ */ ++static inline u32 HandletoUint32(void * h) + { + return (u32) ((unsigned long) h); + } + +-/*++======================================================================*/ +-static inline HANDLE Uint32toHandle(u32 ui32) + /* +- * +- * Arguments: u32 ui32 +- * +- * Returns: HANDLE - Handle type. +- * +- * Abstract: Converts a u32 to a HANDLE type. +- * +- * Notes: +- * +- * Environment: +- * +- *========================================================================*/ ++ * Converts a u32 to a HANDLE type. ++ */ ++static inline void *Uint32toHandle(u32 ui32) + { +- return ((HANDLE) (unsigned long) ui32); ++ return ((void *) (unsigned long) ui32); + } + + /* Global variables */ + +-extern int Novfs_Version_Major; +-extern int Novfs_Version_Minor; +-extern int Novfs_Version_Sub; +-extern int Novfs_Version_Release; +-extern struct dentry *Novfs_root; +-extern struct proc_dir_entry *Novfs_Procfs_dir; +-extern unsigned long File_update_timeout; +-extern int PageCache; +-extern char *Novfs_CurrentMount; +-extern struct dentry_operations Novfs_dentry_operations; +-extern int MaxIoSize; ++extern struct dentry *novfs_root; ++extern struct proc_dir_entry *novfs_procfs_dir; ++extern unsigned long novfs_update_timeout; ++extern int novfs_page_cache; ++extern char *novfs_current_mnt; ++extern int novfs_max_iosize; + + + /* Global functions */ +-extern int Novfs_Remove_from_Root(char *); +-extern void Novfs_dump_inode(void *pf); ++extern int novfs_remove_from_root(char *); ++extern void novfs_dump_inode(void *pf); + +-extern void mydump(int size, void *dumpptr); ++extern void novfs_dump(int size, void *dumpptr); + + extern int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, + int dlen, void **reply, unsigned long * replen, + int interruptible); ++extern int novfs_do_login(struct ncl_string * Server, struct ncl_string* Username, struct ncl_string * Password, void **lgnId, struct novfs_schandle *Session); + +-extern int Init_Procfs_Interface(void); +-extern void Uninit_Procfs_Interface(void); ++extern int novfs_proc_init(void); ++extern void novfs_proc_exit(void); + + /* + * daemon.c functions + */ +-extern void Init_Daemon_Queue(void); +-extern void Uninit_Daemon_Queue(void); +-extern int do_login(NclString * Server, NclString * Username, NclString * Password, HANDLE * lgnId, struct schandle *Session); +-extern int do_logout(struct qstr *Server, struct schandle *Session); +-extern int Daemon_SetMountPoint(char *Path); +-extern int Daemon_CreateSessionId(struct schandle *SessionId); +-extern int Daemon_DestroySessionId(struct schandle *SessionId); +-extern int Daemon_getpwuid(uid_t uid, int unamelen, char *uname); +-extern int Daemon_Get_UserSpace(struct schandle *session_id, u64 *TotalSize, +- u64 *TotalFree, u64 *TotalDirectoryEnties, +- u64 *FreeDirectoryEnties); +-extern int Daemon_SendDebugCmd(char *Command); +-extern ssize_t Daemon_Receive_Reply(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos); +-extern ssize_t Daemon_Send_Command(struct file *file, char __user *buf, size_t len, loff_t *off); +-extern int Daemon_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +-extern int Daemon_Library_close(struct inode *inode, struct file *file); +-extern int Daemon_Library_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +-extern int Daemon_Library_open(struct inode *inode, struct file *file); +-extern ssize_t Daemon_Library_write(struct file *file, const char __user *buf, size_t len, loff_t * off); +-extern ssize_t Daemon_Library_read(struct file *file, char __user *buf, size_t len, loff_t * off); +-extern loff_t Daemon_Library_llseek(struct file *file, loff_t offset, int origin); +-extern int Daemon_Open_Control(struct inode *Inode, struct file *File); +-extern int Daemon_Close_Control(struct inode *Inode, struct file *File); +-extern int Daemon_getversion(char *Buf, int Length); ++extern void novfs_daemon_queue_init(void); ++extern void novfs_daemon_queue_exit(void); ++extern int novfs_daemon_logout(struct qstr *Server, struct novfs_schandle *Session); ++extern int novfs_daemon_set_mnt_point(char *Path); ++extern int novfs_daemon_create_sessionId(struct novfs_schandle * SessionId); ++extern int novfs_daemon_destroy_sessionId(struct novfs_schandle SessionId); ++extern int novfs_daemon_getpwuid(uid_t uid, int unamelen, char *uname); ++extern int novfs_daemon_get_userspace(struct novfs_schandle SessionId, ++ uint64_t * TotalSize, uint64_t * TotalFree, ++ uint64_t * TotalDirectoryEnties, ++ uint64_t * FreeDirectoryEnties); ++extern int novfs_daemon_debug_cmd_send(char *Command); ++extern ssize_t novfs_daemon_recv_reply(struct file *file, ++ const char *buf, size_t nbytes, loff_t * ppos); ++extern ssize_t novfs_daemon_cmd_send(struct file *file, char *buf, ++ size_t len, loff_t * off); ++extern int novfs_daemon_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++extern int novfs_daemon_lib_close(struct inode *inode, struct file *file); ++extern int novfs_daemon_lib_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++extern int novfs_daemon_lib_open(struct inode *inode, struct file *file); ++extern ssize_t novfs_daemon_lib_read(struct file *file, char *buf, ++ size_t len, loff_t * off); ++extern ssize_t novfs_daemon_lib_write(struct file *file, const char *buf, ++ size_t len, loff_t * off); ++extern loff_t novfs_daemon_lib_llseek(struct file *file, loff_t offset, ++ int origin); ++extern int novfs_daemon_open_control(struct inode *Inode, struct file *File); ++extern int novfs_daemon_close_control(struct inode *Inode, struct file *File); ++extern int novfs_daemon_getversion(char *Buf, int Length); + + + /* + * file.c functions + */ +-extern int Novfs_get_alltrees(struct dentry *parent); +-extern int Novfs_Get_Connected_Server_List(unsigned char **ServerList, struct schandle *SessionId); +-extern int Novfs_Get_Server_Volume_List(struct qstr *Server, unsigned char **VolumeList, struct schandle *SessionId); +-extern int Novfs_Get_File_Info(unsigned char *Path, struct entry_info *Info, struct schandle *SessionId); +-extern int Novfs_GetX_File_Info(char *Path, const char *Name, char *buffer, ssize_t buffer_size, ssize_t *dataLen, struct schandle *SessionId); +-extern int Novfs_ListX_File_Info(char *Path, char *buffer, ssize_t buffer_size, ssize_t * dataLen, struct schandle *SessionId); +-extern int Novfs_SetX_File_Info(char *Path, const char *Name, const void *Value, ++extern int novfs_verify_file(struct qstr *Path, struct novfs_schandle SessionId); ++extern int novfs_get_alltrees(struct dentry *parent); ++extern int novfs_get_servers(unsigned char **ServerList, ++ struct novfs_schandle SessionId); ++extern int novfs_get_vols(struct qstr *Server, ++ unsigned char **VolumeList, struct novfs_schandle SessionId); ++extern int novfs_get_file_info(unsigned char *Path, ++ struct novfs_entry_info *Info, struct novfs_schandle SessionId); ++extern int novfs_getx_file_info(char *Path, const char *Name, ++ char *buffer, ssize_t buffer_size, ssize_t *dataLen, ++ struct novfs_schandle SessionId); ++extern int novfs_listx_file_info(char *Path, char *buffer, ++ ssize_t buffer_size, ssize_t *dataLen, ++ struct novfs_schandle SessionId); ++extern int novfs_setx_file_info(char *Path, const char *Name, const void *Value, + unsigned long valueLen, + unsigned long *bytesWritten, int flags, +- struct schandle *SessionId); ++ struct novfs_schandle SessionId); + +-extern int Novfs_Get_Directory_ListEx(unsigned char *Path, HANDLE *EnumHandle, +- int *Count, struct entry_info **Info, +- struct schandle *SessionId); +-extern int Novfs_Open_File(unsigned char *Path, int Flags, struct entry_info *info, +- HANDLE * Handle, session_t SessionId); +-extern int Novfs_Create(unsigned char *Path, int DirectoryFlag, +- session_t SessionId); +-extern int Novfs_Close_File(HANDLE Handle, session_t SessionId); +-extern int Novfs_Read_File(HANDLE Handle, unsigned char *Buffer, size_t * Bytes, +- loff_t * Offset, session_t SessionId); +-extern int Novfs_Read_Pages(HANDLE Handle, struct data_list *dlist, int DList_Cnt, +- size_t * Bytes, loff_t * Offset, +- session_t SessionId); +-extern int Novfs_Write_File(HANDLE Handle, unsigned char *Buffer, ++extern int novfs_get_dir_listex(unsigned char *Path, void **EnumHandle, ++ int *Count, struct novfs_entry_info **Info, ++ struct novfs_schandle SessionId); ++extern int novfs_open_file(unsigned char *Path, int Flags, ++ struct novfs_entry_info * Info, void **Handle, ++ struct novfs_schandle SessionId); ++extern int novfs_create(unsigned char *Path, int DirectoryFlag, ++ struct novfs_schandle SessionId); ++extern int novfs_close_file(void * Handle, struct novfs_schandle SessionId); ++extern int novfs_read_file(void * Handle, unsigned char *Buffer, ++ size_t * Bytes, loff_t * Offset, ++ struct novfs_schandle SessionId); ++extern int novfs_read_pages(void * Handle, struct novfs_data_list *DList, ++ int DList_Cnt, size_t * Bytes, loff_t * Offset, ++ struct novfs_schandle SessionId); ++extern int novfs_write_file(void * Handle, unsigned char *Buffer, + size_t * Bytes, loff_t * Offset, +- session_t SessionId); +-extern int Novfs_Write_Page(HANDLE Handle, struct page *Page, +- session_t SessionId); +-extern int Novfs_Write_Pages(HANDLE Handle, struct data_list *dlist, int DList_Cnt, +- size_t Bytes, loff_t Offset, session_t SessionId); +-extern int Novfs_Delete(unsigned char *Path, int DirectoryFlag, +- session_t SessionId); +-extern int Novfs_Truncate_File(unsigned char *Path, int PathLen, +- session_t SessionId); +-extern int Novfs_Truncate_File_Ex(HANDLE Handle, loff_t Offset, +- session_t SessionId); +-extern int Novfs_Rename_File(int DirectoryFlag, unsigned char *OldName, ++ struct novfs_schandle SessionId); ++extern int novfs_write_page(void * Handle, struct page *Page, ++ struct novfs_schandle SessionId); ++extern int novfs_write_pages(void * Handle, struct novfs_data_list *DList, ++ int DList_Cnt, size_t Bytes, loff_t Offset, ++ struct novfs_schandle SessionId); ++extern int novfs_delete(unsigned char *Path, int DirectoryFlag, ++ struct novfs_schandle SessionId); ++extern int novfs_trunc(unsigned char *Path, int PathLen, ++ struct novfs_schandle SessionId); ++extern int novfs_trunc_ex(void * Handle, loff_t Offset, ++ struct novfs_schandle SessionId); ++extern int novfs_rename_file(int DirectoryFlag, unsigned char *OldName, + int OldLen, unsigned char *NewName, int NewLen, +- session_t SessionId); +-extern int Novfs_Set_Attr(unsigned char *Path, struct iattr *Attr, +- session_t SessionId); +-extern int Novfs_Get_File_Cache_Flag(unsigned char * Path, session_t SessionId); +-extern int Novfs_Set_File_Lock(session_t SessionId, HANDLE fhandle, ++ struct novfs_schandle SessionId); ++extern int novfs_set_attr(unsigned char *Path, struct iattr *Attr, ++ struct novfs_schandle SessionId); ++extern int novfs_get_file_cache_flag(unsigned char * Path, ++ struct novfs_schandle SessionId); ++extern int novfs_set_file_lock(struct novfs_schandle SessionId, void * fhandle, + unsigned char fl_type, loff_t fl_start, + loff_t len); + +-extern struct inode *Novfs_get_inode(struct super_block *sb, int mode, int dev, uid_t uid, ino_t ino, struct qstr *name); +-extern int Novfs_Read_Stream(HANDLE ConnHandle, unsigned char * Handle, ++extern struct inode *novfs_get_inode(struct super_block *sb, int mode, ++ int dev, uid_t uid, ino_t ino, struct qstr *name); ++extern int novfs_read_stream(void * ConnHandle, unsigned char * Handle, + unsigned char * Buffer, size_t * Bytes, loff_t * Offset, +- int User, session_t SessionId); +-extern int Novfs_Write_Stream(HANDLE ConnHandle, unsigned char * Handle, ++ int User, struct novfs_schandle SessionId); ++extern int novfs_write_stream(void * ConnHandle, unsigned char * Handle, + unsigned char * Buffer, size_t * Bytes, loff_t * Offset, +- session_t SessionId); +-extern int Novfs_Close_Stream(HANDLE ConnHandle, unsigned char * Handle, +- session_t SessionId); ++ struct novfs_schandle SessionId); ++extern int novfs_close_stream(void * ConnHandle, unsigned char * Handle, ++ struct novfs_schandle SessionId); + +-extern int Novfs_Add_to_Root(char *); ++extern int novfs_add_to_root(char *); + + + /* + * scope.c functions + */ +-extern void Scope_Init(void); +-extern void Scope_Uninit(void); +-extern void *Scope_Lookup(void); +-extern uid_t Scope_Get_Uid(void *); +-extern session_t Scope_Get_SessionId(void *Scope); +-//extern session_t Scope_Get_SessionId(PSCOPE_LIST Scope); +-extern char *Scope_Get_ScopeUsers(void); +-extern int Scope_Set_UserSpace(u64 *TotalSize, u64 *Free, +- u64 *TotalEnties, u64 *FreeEnties); +-extern int Scope_Get_UserSpace(u64 *TotalSize, u64 *Free, +- u64 *TotalEnties, u64 *FreeEnties); +-extern char *Scope_dget_path(struct dentry *Dentry, char *Buf, ++extern void novfs_scope_init(void); ++extern void novfs_scope_exit(void); ++extern void *novfs_scope_lookup(void); ++extern uid_t novfs_scope_get_uid(struct novfs_scope_list *); ++extern struct novfs_schandle novfs_scope_get_sessionId(struct ++ novfs_scope_list *); ++extern char *novfs_get_scopeusers(void); ++extern int novfs_scope_set_userspace(uint64_t * TotalSize, uint64_t * Free, ++ uint64_t * TotalEnties, uint64_t * FreeEnties); ++extern int novfs_scope_get_userspace(uint64_t * TotalSize, uint64_t * Free, ++ uint64_t * TotalEnties, uint64_t * FreeEnties); ++extern char *novfs_scope_dget_path(struct dentry *Dentry, char *Buf, + unsigned int Buflen, int Flags); +-extern char *Scope_Get_UserName(void); +-extern void Scope_Cleanup(void); ++extern void novfs_scope_cleanup(void); ++extern struct novfs_scope_list *novfs_get_scope_from_name(struct qstr *); ++extern struct novfs_scope_list *novfs_get_scope(struct dentry *); ++extern char *novfs_scope_get_username(void); + + /* + * profile.c functions + */ + extern u64 get_nanosecond_time(void); +-static inline void *Novfs_Malloc(size_t size, int flags) { return kmalloc(size, flags); } + extern int DbgPrint(char *Fmt, ...); +-extern int init_profile(void); +-extern void uninit_profile(void); ++extern void novfs_profile_init(void); ++extern void novfs_profile_exit(void); + + /* + * nwcapi.c functions + */ +-extern int NwAuthConnWithId(PXPLAT pdata, session_t Session); +-extern int NwConnClose(PXPLAT pdata, HANDLE * Handle, session_t Session); +-extern int NwGetConnInfo(PXPLAT pdata, session_t Session); +-extern int NwSetConnInfo(PXPLAT pdata, session_t Session); +-extern int NwGetDaemonVersion(PXPLAT pdata, session_t Session); +-extern int NwGetIdentityInfo(PXPLAT pdata, session_t Session); +-extern int NwLicenseConn(PXPLAT pdata, session_t Session); +-extern int NwLoginIdentity(PXPLAT pdata, struct schandle *Session); +-extern int NwLogoutIdentity(PXPLAT pdata, session_t Session); +-extern int NwOpenConnByAddr(PXPLAT pdata, HANDLE * Handle, session_t Session); +-extern int NwOpenConnByName(PXPLAT pdata, HANDLE * Handle, session_t Session); +-extern int NwOpenConnByRef(PXPLAT pdata, HANDLE * Handle, session_t Session); +-extern int NwQueryFeature(PXPLAT pdata, session_t Session); +-extern int NwRawSend(PXPLAT pdata, session_t Session); +-extern int NwScanConnInfo(PXPLAT pdata, session_t Session); +-extern int NwSysConnClose(PXPLAT pdata, unsigned long * Handle, session_t Session); +-extern int NwUnAuthenticate(PXPLAT pdata, session_t Session); +-extern int NwUnlicenseConn(PXPLAT pdata, session_t Session); +-extern int NwcChangeAuthKey(PXPLAT pdata, session_t Session); +-extern int NwcEnumIdentities(PXPLAT pdata, session_t Session); +-extern int NwcGetDefaultNameCtx(PXPLAT pdata, session_t Session); +-extern int NwcGetPreferredDSTree(PXPLAT pdata, session_t Session); +-extern int NwcGetTreeMonitoredConn(PXPLAT pdata, session_t Session); +-extern int NwcSetDefaultNameCtx(PXPLAT pdata, session_t Session); +-extern int NwcSetPreferredDSTree(PXPLAT pdata, session_t Session); +-extern int NwcSetPrimaryConn(PXPLAT pdata, session_t Session); +-extern int NwcGetPrimaryConn(PXPLAT pdata, session_t Session); +-extern int NwcSetMapDrive(PXPLAT pdata, session_t Session); +-extern int NwcUnMapDrive(PXPLAT pdata, session_t Session); +-extern int NwcEnumerateDrives(PXPLAT pdata, session_t Session); +-extern int NwcGetBroadcastMessage(PXPLAT pdata, session_t Session); +-extern int NwdSetKeyValue(PXPLAT pdata, session_t Session); +-extern int NwdVerifyKeyValue(PXPLAT pdata, session_t Session); ++extern int novfs_auth_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_conn_close(struct novfs_xplat *pdata, ++ void **Handle, struct novfs_schandle Session); ++extern int novfs_get_conn_info(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_set_conn_info(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_daemon_ver(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_id_info(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_license_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_login_id(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_logout_id(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_open_conn_by_addr(struct novfs_xplat *pdata, ++ void **Handle, struct novfs_schandle Session); ++extern int novfs_open_conn_by_name(struct novfs_xplat *pdata, ++ void **Handle, struct novfs_schandle Session); ++extern int novfs_open_conn_by_ref(struct novfs_xplat *pdata, ++ void **Handle, struct novfs_schandle Session); ++extern int novfs_query_feature(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_raw_send(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_scan_conn_info(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_sys_conn_close(struct novfs_xplat *pdata, ++ unsigned long *Handle, struct novfs_schandle Session); ++extern int novfs_unauthenticate(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_unlicense_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_change_auth_key(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_enum_ids(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_default_ctx(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_preferred_DS_tree(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_tree_monitored_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_set_default_ctx(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_set_preferred_DS_tree(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_set_pri_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_pri_conn(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_set_map_drive(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_unmap_drive(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_enum_drives(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_get_bcast_msg(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_set_key_value(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); ++extern int novfs_verify_key_value(struct novfs_xplat *pdata, ++ struct novfs_schandle Session); + + + #endif /* __NOVFS_H */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/coredump_filter-add-elfhdr-default.patch b/src/patches/suse-2.6.27.31/patches.suse/coredump_filter-add-elfhdr-default.patch new file mode 100644 index 000000000..ccf8d8159 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/coredump_filter-add-elfhdr-default.patch @@ -0,0 +1,28 @@ +From: Jan Blunck +Subject: Dump elf headers to core per default + +This patch changes the default of /proc/self/coredump_filter to write the elf +header of shared objects and the executable itself to the core file. This +change is necessary to read the build-ids generated by GCC from the produced +core files. These core files might not be readable by anncient versions of +GDB. + +Signed-off-by: Jan Blunck +--- + include/linux/sched.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -408,8 +408,9 @@ extern int get_dumpable(struct mm_struct + #define MMF_DUMP_FILTER_BITS 5 + #define MMF_DUMP_FILTER_MASK \ + (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) +-#define MMF_DUMP_FILTER_DEFAULT \ +- ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED)) ++#define MMF_DUMP_FILTER_DEFAULT \ ++ ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED) | \ ++ (1 << MMF_DUMP_ELF_HEADERS)) + + struct sighand_struct { + atomic_t count; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-Change-rwlock-which-is-only-used-in-write-mode-to-a-spinlock.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-Change-rwlock-which-is-only-used-in-write-mode-to-a-spinlock.patch new file mode 100644 index 000000000..2013de6da --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-Change-rwlock-which-is-only-used-in-write-mode-to-a-spinlock.patch @@ -0,0 +1,117 @@ +From: Steven Whitehouse +commit 305a47b17c6efcc0e7b67b0bd41e2c12b7af758b +Author: Steven Whitehouse +Date: Fri Jan 16 16:21:12 2009 +0000 +Subject: dlm: Change rwlock which is only used in write mode to a spinlock + + The ls_dirtbl[].lock was an rwlock, but since it was only used in write + mode a spinlock will suffice. + +Signed-off-by: Steven Whitehouse +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c +index 92969f8..858fba1 100644 +--- a/fs/dlm/dir.c ++++ b/fs/dlm/dir.c +@@ -156,7 +156,7 @@ void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen + + bucket = dir_hash(ls, name, namelen); + +- write_lock(&ls->ls_dirtbl[bucket].lock); ++ spin_lock(&ls->ls_dirtbl[bucket].lock); + + de = search_bucket(ls, name, namelen, bucket); + +@@ -173,7 +173,7 @@ void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen + list_del(&de->list); + kfree(de); + out: +- write_unlock(&ls->ls_dirtbl[bucket].lock); ++ spin_unlock(&ls->ls_dirtbl[bucket].lock); + } + + void dlm_dir_clear(struct dlm_ls *ls) +@@ -185,14 +185,14 @@ void dlm_dir_clear(struct dlm_ls *ls) + DLM_ASSERT(list_empty(&ls->ls_recover_list), ); + + for (i = 0; i < ls->ls_dirtbl_size; i++) { +- write_lock(&ls->ls_dirtbl[i].lock); ++ spin_lock(&ls->ls_dirtbl[i].lock); + head = &ls->ls_dirtbl[i].list; + while (!list_empty(head)) { + de = list_entry(head->next, struct dlm_direntry, list); + list_del(&de->list); + put_free_de(ls, de); + } +- write_unlock(&ls->ls_dirtbl[i].lock); ++ spin_unlock(&ls->ls_dirtbl[i].lock); + } + } + +@@ -307,17 +307,17 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, + + bucket = dir_hash(ls, name, namelen); + +- write_lock(&ls->ls_dirtbl[bucket].lock); ++ spin_lock(&ls->ls_dirtbl[bucket].lock); + de = search_bucket(ls, name, namelen, bucket); + if (de) { + *r_nodeid = de->master_nodeid; +- write_unlock(&ls->ls_dirtbl[bucket].lock); ++ spin_unlock(&ls->ls_dirtbl[bucket].lock); + if (*r_nodeid == nodeid) + return -EEXIST; + return 0; + } + +- write_unlock(&ls->ls_dirtbl[bucket].lock); ++ spin_unlock(&ls->ls_dirtbl[bucket].lock); + + if (namelen > DLM_RESNAME_MAXLEN) + return -EINVAL; +@@ -330,7 +330,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, + de->length = namelen; + memcpy(de->name, name, namelen); + +- write_lock(&ls->ls_dirtbl[bucket].lock); ++ spin_lock(&ls->ls_dirtbl[bucket].lock); + tmp = search_bucket(ls, name, namelen, bucket); + if (tmp) { + kfree(de); +@@ -339,7 +339,7 @@ static int get_entry(struct dlm_ls *ls, int nodeid, char *name, + list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); + } + *r_nodeid = de->master_nodeid; +- write_unlock(&ls->ls_dirtbl[bucket].lock); ++ spin_unlock(&ls->ls_dirtbl[bucket].lock); + return 0; + } + +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index 076e86f..d01ca0a 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -99,7 +99,7 @@ struct dlm_direntry { + + struct dlm_dirtable { + struct list_head list; +- rwlock_t lock; ++ spinlock_t lock; + }; + + struct dlm_rsbtable { +diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c +index aa32e5f..cd8e2df 100644 +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -487,7 +487,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + goto out_lkbfree; + for (i = 0; i < size; i++) { + INIT_LIST_HEAD(&ls->ls_dirtbl[i].list); +- rwlock_init(&ls->ls_dirtbl[i].lock); ++ spin_lock_init(&ls->ls_dirtbl[i].lock); + } + + INIT_LIST_HEAD(&ls->ls_waiters); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-add-new-debugfs-entry.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-add-new-debugfs-entry.patch new file mode 100644 index 000000000..66753a292 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-add-new-debugfs-entry.patch @@ -0,0 +1,465 @@ +From: David Teigland +commit d022509d1c54be4918e7fc8f1195ee8c392e9a57 +Author: David Teigland +Date: Tue Dec 16 14:53:23 2008 -0600 +Subject: dlm: add new debugfs entry + + The new debugfs entry dumps all rsb and lkb structures, and includes + a lot more information than has been available before. This includes + the new timestamps added by a previous patch for debugging callback + issues. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +--- + fs/dlm/debug_fs.c | 296 +++++++++++++++++++++++++++++++++++++++++--------- + fs/dlm/dlm_internal.h | 1 + 2 files changed, 247 insertions(+), 50 deletions(-) + +--- a/fs/dlm/debug_fs.c ++++ b/fs/dlm/debug_fs.c +@@ -1,7 +1,7 @@ + /****************************************************************************** + ******************************************************************************* + ** +-** Copyright (C) 2005 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -27,7 +27,7 @@ static struct dentry *dlm_root; + + struct rsb_iter { + int entry; +- int locks; ++ int format; + int header; + struct dlm_ls *ls; + struct list_head *next; +@@ -60,8 +60,8 @@ static char *print_lockmode(int mode) + } + } + +-static void print_resource_lock(struct seq_file *s, struct dlm_lkb *lkb, +- struct dlm_rsb *res) ++static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, ++ struct dlm_rsb *res) + { + seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); + +@@ -83,7 +83,7 @@ static void print_resource_lock(struct s + seq_printf(s, "\n"); + } + +-static int print_resource(struct dlm_rsb *res, struct seq_file *s) ++static int print_format1(struct dlm_rsb *res, struct seq_file *s) + { + struct dlm_lkb *lkb; + int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; +@@ -134,15 +134,15 @@ static int print_resource(struct dlm_rsb + /* Print the locks attached to this resource */ + seq_printf(s, "Granted Queue\n"); + list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) +- print_resource_lock(s, lkb, res); ++ print_format1_lock(s, lkb, res); + + seq_printf(s, "Conversion Queue\n"); + list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) +- print_resource_lock(s, lkb, res); ++ print_format1_lock(s, lkb, res); + + seq_printf(s, "Waiting Queue\n"); + list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) +- print_resource_lock(s, lkb, res); ++ print_format1_lock(s, lkb, res); + + if (list_empty(&res->res_lookup)) + goto out; +@@ -160,7 +160,8 @@ static int print_resource(struct dlm_rsb + return 0; + } + +-static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb *r) ++static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, ++ struct dlm_rsb *r) + { + u64 xid = 0; + u64 us; +@@ -193,20 +194,108 @@ static void print_lock(struct seq_file * + r->res_name); + } + +-static int print_locks(struct dlm_rsb *r, struct seq_file *s) ++static int print_format2(struct dlm_rsb *r, struct seq_file *s) + { + struct dlm_lkb *lkb; + + lock_rsb(r); + + list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) +- print_lock(s, lkb, r); ++ print_format2_lock(s, lkb, r); + + list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) +- print_lock(s, lkb, r); ++ print_format2_lock(s, lkb, r); + + list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) +- print_lock(s, lkb, r); ++ print_format2_lock(s, lkb, r); ++ ++ unlock_rsb(r); ++ return 0; ++} ++ ++static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, ++ int rsb_lookup) ++{ ++ u64 xid = 0; ++ ++ if (lkb->lkb_flags & DLM_IFL_USER) { ++ if (lkb->lkb_ua) ++ xid = lkb->lkb_ua->xid; ++ } ++ ++ seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", ++ lkb->lkb_id, ++ lkb->lkb_nodeid, ++ lkb->lkb_remid, ++ lkb->lkb_ownpid, ++ (unsigned long long)xid, ++ lkb->lkb_exflags, ++ lkb->lkb_flags, ++ lkb->lkb_status, ++ lkb->lkb_grmode, ++ lkb->lkb_rqmode, ++ lkb->lkb_highbast, ++ rsb_lookup, ++ lkb->lkb_wait_type, ++ lkb->lkb_lvbseq, ++ (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), ++ (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); ++} ++ ++static int print_format3(struct dlm_rsb *r, struct seq_file *s) ++{ ++ struct dlm_lkb *lkb; ++ int i, lvblen = r->res_ls->ls_lvblen; ++ int print_name = 1; ++ ++ lock_rsb(r); ++ ++ seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", ++ r, ++ r->res_nodeid, ++ r->res_first_lkid, ++ r->res_flags, ++ !list_empty(&r->res_root_list), ++ !list_empty(&r->res_recover_list), ++ r->res_recover_locks_count, ++ r->res_length); ++ ++ for (i = 0; i < r->res_length; i++) { ++ if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) ++ print_name = 0; ++ } ++ ++ seq_printf(s, "%s", print_name ? "str " : "hex"); ++ ++ for (i = 0; i < r->res_length; i++) { ++ if (print_name) ++ seq_printf(s, "%c", r->res_name[i]); ++ else ++ seq_printf(s, " %02x", (unsigned char)r->res_name[i]); ++ } ++ seq_printf(s, "\n"); ++ ++ if (!r->res_lvbptr) ++ goto do_locks; ++ ++ seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen); ++ ++ for (i = 0; i < lvblen; i++) ++ seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]); ++ seq_printf(s, "\n"); ++ ++ do_locks: ++ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) ++ print_format3_lock(s, lkb, 0); ++ ++ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) ++ print_format3_lock(s, lkb, 0); ++ ++ list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) ++ print_format3_lock(s, lkb, 0); ++ ++ list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) ++ print_format3_lock(s, lkb, 1); + + unlock_rsb(r); + return 0; +@@ -231,7 +320,7 @@ static int rsb_iter_next(struct rsb_iter + break; + } + read_unlock(&ls->ls_rsbtbl[i].lock); +- } ++ } + ri->entry = i; + + if (ri->entry >= ls->ls_rsbtbl_size) +@@ -248,7 +337,7 @@ static int rsb_iter_next(struct rsb_iter + read_unlock(&ls->ls_rsbtbl[i].lock); + dlm_put_rsb(old); + goto top; +- } ++ } + ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); + dlm_hold_rsb(ri->rsb); + read_unlock(&ls->ls_rsbtbl[i].lock); +@@ -274,6 +363,7 @@ static struct rsb_iter *rsb_iter_init(st + ri->ls = ls; + ri->entry = 0; + ri->next = NULL; ++ ri->format = 1; + + if (rsb_iter_next(ri)) { + rsb_iter_free(ri); +@@ -325,16 +415,26 @@ static int rsb_seq_show(struct seq_file + { + struct rsb_iter *ri = iter_ptr; + +- if (ri->locks) { ++ switch (ri->format) { ++ case 1: ++ print_format1(ri->rsb, file); ++ break; ++ case 2: + if (ri->header) { +- seq_printf(file, "id nodeid remid pid xid exflags flags " +- "sts grmode rqmode time_ms r_nodeid " +- "r_len r_name\n"); ++ seq_printf(file, "id nodeid remid pid xid exflags " ++ "flags sts grmode rqmode time_ms " ++ "r_nodeid r_len r_name\n"); + ri->header = 0; + } +- print_locks(ri->rsb, file); +- } else { +- print_resource(ri->rsb, file); ++ print_format2(ri->rsb, file); ++ break; ++ case 3: ++ if (ri->header) { ++ seq_printf(file, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); ++ ri->header = 0; ++ } ++ print_format3(ri->rsb, file); ++ break; + } + + return 0; +@@ -385,7 +485,7 @@ static struct rsb_iter *locks_iter_init( + ri->ls = ls; + ri->entry = 0; + ri->next = NULL; +- ri->locks = 1; ++ ri->format = 2; + + if (*pos == 0) + ri->header = 1; +@@ -448,6 +548,84 @@ static const struct file_operations lock + }; + + /* ++ * Dump all rsb/lvb/lkb state in compact listing, more complete than _locks ++ * This can replace both formats 1 and 2 eventually. ++ */ ++ ++static struct rsb_iter *all_iter_init(struct dlm_ls *ls, loff_t *pos) ++{ ++ struct rsb_iter *ri; ++ ++ ri = kzalloc(sizeof *ri, GFP_KERNEL); ++ if (!ri) ++ return NULL; ++ ++ ri->ls = ls; ++ ri->entry = 0; ++ ri->next = NULL; ++ ri->format = 3; ++ ++ if (*pos == 0) ++ ri->header = 1; ++ ++ if (rsb_iter_next(ri)) { ++ rsb_iter_free(ri); ++ return NULL; ++ } ++ ++ return ri; ++} ++ ++static void *all_seq_start(struct seq_file *file, loff_t *pos) ++{ ++ struct rsb_iter *ri; ++ loff_t n = *pos; ++ ++ ri = all_iter_init(file->private, pos); ++ if (!ri) ++ return NULL; ++ ++ while (n--) { ++ if (rsb_iter_next(ri)) { ++ rsb_iter_free(ri); ++ return NULL; ++ } ++ } ++ ++ return ri; ++} ++ ++static struct seq_operations all_seq_ops = { ++ .start = all_seq_start, ++ .next = rsb_seq_next, ++ .stop = rsb_seq_stop, ++ .show = rsb_seq_show, ++}; ++ ++static int all_open(struct inode *inode, struct file *file) ++{ ++ struct seq_file *seq; ++ int ret; ++ ++ ret = seq_open(file, &all_seq_ops); ++ if (ret) ++ return ret; ++ ++ seq = file->private_data; ++ seq->private = inode->i_private; ++ ++ return 0; ++} ++ ++static const struct file_operations all_fops = { ++ .owner = THIS_MODULE, ++ .open = all_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release ++}; ++ ++/* + * dump lkb's on the ls_waiters list + */ + +@@ -489,30 +667,33 @@ static const struct file_operations wait + .read = waiters_read + }; + ++void dlm_delete_debug_file(struct dlm_ls *ls) ++{ ++ if (ls->ls_debug_rsb_dentry) ++ debugfs_remove(ls->ls_debug_rsb_dentry); ++ if (ls->ls_debug_waiters_dentry) ++ debugfs_remove(ls->ls_debug_waiters_dentry); ++ if (ls->ls_debug_locks_dentry) ++ debugfs_remove(ls->ls_debug_locks_dentry); ++ if (ls->ls_debug_all_dentry) ++ debugfs_remove(ls->ls_debug_all_dentry); ++} ++ + int dlm_create_debug_file(struct dlm_ls *ls) + { + char name[DLM_LOCKSPACE_LEN+8]; + ++ /* format 1 */ ++ + ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name, + S_IFREG | S_IRUGO, + dlm_root, + ls, + &rsb_fops); + if (!ls->ls_debug_rsb_dentry) +- return -ENOMEM; ++ goto fail; + +- memset(name, 0, sizeof(name)); +- snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); +- +- ls->ls_debug_waiters_dentry = debugfs_create_file(name, +- S_IFREG | S_IRUGO, +- dlm_root, +- ls, +- &waiters_fops); +- if (!ls->ls_debug_waiters_dentry) { +- debugfs_remove(ls->ls_debug_rsb_dentry); +- return -ENOMEM; +- } ++ /* format 2 */ + + memset(name, 0, sizeof(name)); + snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_locks", ls->ls_name); +@@ -522,23 +703,38 @@ int dlm_create_debug_file(struct dlm_ls + dlm_root, + ls, + &locks_fops); +- if (!ls->ls_debug_locks_dentry) { +- debugfs_remove(ls->ls_debug_waiters_dentry); +- debugfs_remove(ls->ls_debug_rsb_dentry); +- return -ENOMEM; +- } ++ if (!ls->ls_debug_locks_dentry) ++ goto fail; ++ ++ /* format 3 */ ++ ++ memset(name, 0, sizeof(name)); ++ snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_all", ls->ls_name); ++ ++ ls->ls_debug_all_dentry = debugfs_create_file(name, ++ S_IFREG | S_IRUGO, ++ dlm_root, ++ ls, ++ &all_fops); ++ if (!ls->ls_debug_all_dentry) ++ goto fail; ++ ++ memset(name, 0, sizeof(name)); ++ snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name); ++ ++ ls->ls_debug_waiters_dentry = debugfs_create_file(name, ++ S_IFREG | S_IRUGO, ++ dlm_root, ++ ls, ++ &waiters_fops); ++ if (!ls->ls_debug_waiters_dentry) ++ goto fail; + + return 0; +-} + +-void dlm_delete_debug_file(struct dlm_ls *ls) +-{ +- if (ls->ls_debug_rsb_dentry) +- debugfs_remove(ls->ls_debug_rsb_dentry); +- if (ls->ls_debug_waiters_dentry) +- debugfs_remove(ls->ls_debug_waiters_dentry); +- if (ls->ls_debug_locks_dentry) +- debugfs_remove(ls->ls_debug_locks_dentry); ++ fail: ++ dlm_delete_debug_file(ls); ++ return -ENOMEM; + } + + int __init dlm_register_debugfs(void) +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -481,6 +481,7 @@ struct dlm_ls { + struct dentry *ls_debug_rsb_dentry; /* debugfs */ + struct dentry *ls_debug_waiters_dentry; /* debugfs */ + struct dentry *ls_debug_locks_dentry; /* debugfs */ ++ struct dentry *ls_debug_all_dentry; /* debugfs */ + + wait_queue_head_t ls_uevent_wait; /* user part of join/leave */ + int ls_uevent_result; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-add-time-stamp-of-blocking-callback.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-add-time-stamp-of-blocking-callback.patch new file mode 100644 index 000000000..4c6f29655 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-add-time-stamp-of-blocking-callback.patch @@ -0,0 +1,38 @@ +From: David Teigland +commit e3a84ad495d1fddb542e0922160f0194a1361950 +Author: David Teigland +Date: Tue Dec 9 14:47:29 2008 -0600 +Subject: dlm: add time stamp of blocking callback + + Record the time the latest blocking callback was queued for + a lock. This will be used for debugging in combination with + lock queue timestamp changes in the previous patch. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index e69135c..0c48829 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -245,6 +245,7 @@ struct dlm_lkb { + struct list_head lkb_astqueue; /* need ast to be sent */ + struct list_head lkb_ownqueue; /* list of locks for a process */ + struct list_head lkb_time_list; ++ ktime_t lkb_time_bast; /* for debugging */ + ktime_t lkb_timestamp; + unsigned long lkb_timeout_cs; + +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index dfc57ae..6cfe65b 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -318,6 +318,8 @@ static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb) + + static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode) + { ++ lkb->lkb_time_bast = ktime_get(); ++ + if (is_master_copy(lkb)) + send_bast(r, lkb, rqmode); + else diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-change-lock-time-stamping.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-change-lock-time-stamping.patch new file mode 100644 index 000000000..3c0d91993 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-change-lock-time-stamping.patch @@ -0,0 +1,156 @@ +From: David Teigland +commit eeda418d8c2646f33f24e9ad33d86c239adc6de7 +Author: David Teigland +Date: Tue Dec 9 14:12:21 2008 -0600 +Subject: dlm: change lock time stamping + + Use ktime instead of jiffies for timestamping lkb's. Also stamp the + time on every lkb whenever it's added to a resource queue, instead of + just stamping locks subject to timeouts. This will allow us to use + timestamps more widely for debugging all locks. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c +index 8fc24f4..19e4f9e 100644 +--- a/fs/dlm/debug_fs.c ++++ b/fs/dlm/debug_fs.c +@@ -162,21 +162,21 @@ static int print_resource(struct dlm_rsb *res, struct seq_file *s) + + static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb *r) + { +- unsigned int waiting = 0; +- uint64_t xid = 0; ++ u64 xid = 0; ++ u64 us; + + if (lkb->lkb_flags & DLM_IFL_USER) { + if (lkb->lkb_ua) + xid = lkb->lkb_ua->xid; + } + +- if (lkb->lkb_timestamp) +- waiting = jiffies_to_msecs(jiffies - lkb->lkb_timestamp); ++ /* microseconds since lkb was added to current queue */ ++ us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp)); + +- /* id nodeid remid pid xid exflags flags sts grmode rqmode time_ms ++ /* id nodeid remid pid xid exflags flags sts grmode rqmode time_us + r_nodeid r_len r_name */ + +- seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %u %u %d \"%s\"\n", ++ seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n", + lkb->lkb_id, + lkb->lkb_nodeid, + lkb->lkb_remid, +@@ -187,7 +187,7 @@ static void print_lock(struct seq_file *s, struct dlm_lkb *lkb, struct dlm_rsb * + lkb->lkb_status, + lkb->lkb_grmode, + lkb->lkb_rqmode, +- waiting, ++ (unsigned long long)us, + r->res_nodeid, + r->res_length, + r->res_name); +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index 868e4c9..e69135c 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -245,7 +245,7 @@ struct dlm_lkb { + struct list_head lkb_astqueue; /* need ast to be sent */ + struct list_head lkb_ownqueue; /* list of locks for a process */ + struct list_head lkb_time_list; +- unsigned long lkb_timestamp; ++ ktime_t lkb_timestamp; + unsigned long lkb_timeout_cs; + + char *lkb_lvbptr; +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 7b758da..dfc57ae 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -742,6 +742,8 @@ static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status) + + DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb);); + ++ lkb->lkb_timestamp = ktime_get(); ++ + lkb->lkb_status = status; + + switch (status) { +@@ -1011,10 +1013,8 @@ static void add_timeout(struct dlm_lkb *lkb) + { + struct dlm_ls *ls = lkb->lkb_resource->res_ls; + +- if (is_master_copy(lkb)) { +- lkb->lkb_timestamp = jiffies; ++ if (is_master_copy(lkb)) + return; +- } + + if (test_bit(LSFL_TIMEWARN, &ls->ls_flags) && + !(lkb->lkb_exflags & DLM_LKF_NODLCKWT)) { +@@ -1029,7 +1029,6 @@ static void add_timeout(struct dlm_lkb *lkb) + DLM_ASSERT(list_empty(&lkb->lkb_time_list), dlm_print_lkb(lkb);); + mutex_lock(&ls->ls_timeout_mutex); + hold_lkb(lkb); +- lkb->lkb_timestamp = jiffies; + list_add_tail(&lkb->lkb_time_list, &ls->ls_timeout); + mutex_unlock(&ls->ls_timeout_mutex); + } +@@ -1057,6 +1056,7 @@ void dlm_scan_timeout(struct dlm_ls *ls) + struct dlm_rsb *r; + struct dlm_lkb *lkb; + int do_cancel, do_warn; ++ s64 wait_us; + + for (;;) { + if (dlm_locking_stopped(ls)) +@@ -1067,14 +1067,15 @@ void dlm_scan_timeout(struct dlm_ls *ls) + mutex_lock(&ls->ls_timeout_mutex); + list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list) { + ++ wait_us = ktime_to_us(ktime_sub(ktime_get(), ++ lkb->lkb_timestamp)); ++ + if ((lkb->lkb_exflags & DLM_LKF_TIMEOUT) && +- time_after_eq(jiffies, lkb->lkb_timestamp + +- lkb->lkb_timeout_cs * HZ/100)) ++ wait_us >= (lkb->lkb_timeout_cs * 10000)) + do_cancel = 1; + + if ((lkb->lkb_flags & DLM_IFL_WATCH_TIMEWARN) && +- time_after_eq(jiffies, lkb->lkb_timestamp + +- dlm_config.ci_timewarn_cs * HZ/100)) ++ wait_us >= dlm_config.ci_timewarn_cs * 10000) + do_warn = 1; + + if (!do_cancel && !do_warn) +@@ -1120,12 +1121,12 @@ void dlm_scan_timeout(struct dlm_ls *ls) + void dlm_adjust_timeouts(struct dlm_ls *ls) + { + struct dlm_lkb *lkb; +- long adj = jiffies - ls->ls_recover_begin; ++ u64 adj_us = jiffies_to_usecs(jiffies - ls->ls_recover_begin); + + ls->ls_recover_begin = 0; + mutex_lock(&ls->ls_timeout_mutex); + list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list) +- lkb->lkb_timestamp += adj; ++ lkb->lkb_timestamp = ktime_add_us(lkb->lkb_timestamp, adj_us); + mutex_unlock(&ls->ls_timeout_mutex); + } + +diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c +index 18bda83..46e582c 100644 +--- a/fs/dlm/netlink.c ++++ b/fs/dlm/netlink.c +@@ -115,7 +115,6 @@ static void fill_data(struct dlm_lock_data *data, struct dlm_lkb *lkb) + data->status = lkb->lkb_status; + data->grmode = lkb->lkb_grmode; + data->rqmode = lkb->lkb_rqmode; +- data->timestamp = lkb->lkb_timestamp; + if (lkb->lkb_ua) + data->xid = lkb->lkb_ua->xid; + if (r) { diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-change-rsbtbl-rwlock-to-spinlock.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-change-rsbtbl-rwlock-to-spinlock.patch new file mode 100644 index 000000000..5758573e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-change-rsbtbl-rwlock-to-spinlock.patch @@ -0,0 +1,282 @@ +From: David Teigland +commit c7be761a8163d2f1ac0b606c21e4316b7abc5af7 +Author: David Teigland +Date: Wed Jan 7 16:50:41 2009 -0600 +Subject: dlm: change rsbtbl rwlock to spinlock + + The rwlock is almost always used in write mode, so there's no reason + to not use a spinlock instead. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c +index bc4af3e..1d1d274 100644 +--- a/fs/dlm/debug_fs.c ++++ b/fs/dlm/debug_fs.c +@@ -416,7 +416,7 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos) + if (seq->op == &format3_seq_ops) + ri->format = 3; + +- read_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { + list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, + res_hashchain) { +@@ -424,12 +424,12 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos) + dlm_hold_rsb(r); + ri->rsb = r; + ri->bucket = bucket; +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + return ri; + } + } + } +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + + /* + * move to the first rsb in the next non-empty bucket +@@ -447,18 +447,18 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos) + return NULL; + } + +- read_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { + r = list_first_entry(&ls->ls_rsbtbl[bucket].list, + struct dlm_rsb, res_hashchain); + dlm_hold_rsb(r); + ri->rsb = r; + ri->bucket = bucket; +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + *pos = n; + return ri; + } +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + } + } + +@@ -477,7 +477,7 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) + * move to the next rsb in the same bucket + */ + +- read_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + rp = ri->rsb; + next = rp->res_hashchain.next; + +@@ -485,12 +485,12 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) + r = list_entry(next, struct dlm_rsb, res_hashchain); + dlm_hold_rsb(r); + ri->rsb = r; +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + dlm_put_rsb(rp); + ++*pos; + return ri; + } +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + dlm_put_rsb(rp); + + /* +@@ -509,18 +509,18 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) + return NULL; + } + +- read_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { + r = list_first_entry(&ls->ls_rsbtbl[bucket].list, + struct dlm_rsb, res_hashchain); + dlm_hold_rsb(r); + ri->rsb = r; + ri->bucket = bucket; +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + *pos = n; + return ri; + } +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + } + } + +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index ef2f1e3..076e86f 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -105,7 +105,7 @@ struct dlm_dirtable { + struct dlm_rsbtable { + struct list_head list; + struct list_head toss; +- rwlock_t lock; ++ spinlock_t lock; + }; + + struct dlm_lkbtable { +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 6cfe65b..01e7d39 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -412,9 +412,9 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b, + unsigned int flags, struct dlm_rsb **r_ret) + { + int error; +- write_lock(&ls->ls_rsbtbl[b].lock); ++ spin_lock(&ls->ls_rsbtbl[b].lock); + error = _search_rsb(ls, name, len, b, flags, r_ret); +- write_unlock(&ls->ls_rsbtbl[b].lock); ++ spin_unlock(&ls->ls_rsbtbl[b].lock); + return error; + } + +@@ -478,16 +478,16 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen, + r->res_nodeid = nodeid; + } + +- write_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + error = _search_rsb(ls, name, namelen, bucket, 0, &tmp); + if (!error) { +- write_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + dlm_free_rsb(r); + r = tmp; + goto out; + } + list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list); +- write_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + error = 0; + out: + *r_ret = r; +@@ -530,9 +530,9 @@ static void put_rsb(struct dlm_rsb *r) + struct dlm_ls *ls = r->res_ls; + uint32_t bucket = r->res_bucket; + +- write_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + kref_put(&r->res_ref, toss_rsb); +- write_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + } + + void dlm_put_rsb(struct dlm_rsb *r) +@@ -967,7 +967,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b) + + for (;;) { + found = 0; +- write_lock(&ls->ls_rsbtbl[b].lock); ++ spin_lock(&ls->ls_rsbtbl[b].lock); + list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss, + res_hashchain) { + if (!time_after_eq(jiffies, r->res_toss_time + +@@ -978,20 +978,20 @@ static int shrink_bucket(struct dlm_ls *ls, int b) + } + + if (!found) { +- write_unlock(&ls->ls_rsbtbl[b].lock); ++ spin_unlock(&ls->ls_rsbtbl[b].lock); + break; + } + + if (kref_put(&r->res_ref, kill_rsb)) { + list_del(&r->res_hashchain); +- write_unlock(&ls->ls_rsbtbl[b].lock); ++ spin_unlock(&ls->ls_rsbtbl[b].lock); + + if (is_master(r)) + dir_remove(r); + dlm_free_rsb(r); + count++; + } else { +- write_unlock(&ls->ls_rsbtbl[b].lock); ++ spin_unlock(&ls->ls_rsbtbl[b].lock); + log_error(ls, "tossed rsb in use %s", r->res_name); + } + } +@@ -4224,7 +4224,7 @@ static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket) + { + struct dlm_rsb *r, *r_ret = NULL; + +- read_lock(&ls->ls_rsbtbl[bucket].lock); ++ spin_lock(&ls->ls_rsbtbl[bucket].lock); + list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) { + if (!rsb_flag(r, RSB_LOCKS_PURGED)) + continue; +@@ -4233,7 +4233,7 @@ static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket) + r_ret = r; + break; + } +- read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ spin_unlock(&ls->ls_rsbtbl[bucket].lock); + return r_ret; + } + +diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c +index 8d86b79..aa32e5f 100644 +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -464,7 +464,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + for (i = 0; i < size; i++) { + INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list); + INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss); +- rwlock_init(&ls->ls_rsbtbl[i].lock); ++ spin_lock_init(&ls->ls_rsbtbl[i].lock); + } + + size = dlm_config.ci_lkbtbl_size; +diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c +index 80aba5b..eda43f3 100644 +--- a/fs/dlm/recover.c ++++ b/fs/dlm/recover.c +@@ -726,7 +726,7 @@ int dlm_create_root_list(struct dlm_ls *ls) + } + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { +- read_lock(&ls->ls_rsbtbl[i].lock); ++ spin_lock(&ls->ls_rsbtbl[i].lock); + list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) { + list_add(&r->res_root_list, &ls->ls_root_list); + dlm_hold_rsb(r); +@@ -737,7 +737,7 @@ int dlm_create_root_list(struct dlm_ls *ls) + but no other recovery steps should do anything with them. */ + + if (dlm_no_directory(ls)) { +- read_unlock(&ls->ls_rsbtbl[i].lock); ++ spin_unlock(&ls->ls_rsbtbl[i].lock); + continue; + } + +@@ -745,7 +745,7 @@ int dlm_create_root_list(struct dlm_ls *ls) + list_add(&r->res_root_list, &ls->ls_root_list); + dlm_hold_rsb(r); + } +- read_unlock(&ls->ls_rsbtbl[i].lock); ++ spin_unlock(&ls->ls_rsbtbl[i].lock); + } + out: + up_write(&ls->ls_root_sem); +@@ -775,7 +775,7 @@ void dlm_clear_toss_list(struct dlm_ls *ls) + int i; + + for (i = 0; i < ls->ls_rsbtbl_size; i++) { +- write_lock(&ls->ls_rsbtbl[i].lock); ++ spin_lock(&ls->ls_rsbtbl[i].lock); + list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss, + res_hashchain) { + if (dlm_no_directory(ls) || !is_master(r)) { +@@ -783,7 +783,7 @@ void dlm_clear_toss_list(struct dlm_ls *ls) + dlm_free_rsb(r); + } + } +- write_unlock(&ls->ls_rsbtbl[i].lock); ++ spin_unlock(&ls->ls_rsbtbl[i].lock); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-choose-better-identifiers.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-choose-better-identifiers.patch new file mode 100644 index 000000000..f0868885f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-choose-better-identifiers.patch @@ -0,0 +1,213 @@ +From: Andrew Morton +commit 27eccf46491e1f77f9af9bbe0778122ce6882890 +Author: Andrew Morton +Date: Fri Sep 5 08:42:08 2008 -0500 +Subject: dlm: choose better identifiers + + sparc32: + + fs/dlm/config.c:397: error: expected identifier or '(' before '{' token + fs/dlm/config.c: In function 'drop_node': + fs/dlm/config.c:589: warning: initialization from incompatible pointer type + fs/dlm/config.c:589: warning: initialization from incompatible pointer type + fs/dlm/config.c: In function 'release_node': + fs/dlm/config.c:601: warning: initialization from incompatible pointer type + fs/dlm/config.c:601: warning: initialization from incompatible pointer type + fs/dlm/config.c: In function 'show_node': + fs/dlm/config.c:717: warning: initialization from incompatible pointer type + fs/dlm/config.c:717: warning: initialization from incompatible pointer type + fs/dlm/config.c: In function 'store_node': + fs/dlm/config.c:726: warning: initialization from incompatible pointer type + fs/dlm/config.c:726: warning: initialization from incompatible pointer type + +Cc: Christine Caulfield +Signed-off-by: Andrew Morton +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/config.c b/fs/dlm/config.c +index 1359be3..fd9859f 100644 +--- a/fs/dlm/config.c ++++ b/fs/dlm/config.c +@@ -380,24 +380,24 @@ static struct config_item_type node_type = { + .ct_owner = THIS_MODULE, + }; + +-static struct dlm_cluster *to_cluster(struct config_item *i) ++static struct dlm_cluster *config_item_to_cluster(struct config_item *i) + { + return i ? container_of(to_config_group(i), struct dlm_cluster, group) : + NULL; + } + +-static struct dlm_space *to_space(struct config_item *i) ++static struct dlm_space *config_item_to_space(struct config_item *i) + { + return i ? container_of(to_config_group(i), struct dlm_space, group) : + NULL; + } + +-static struct dlm_comm *to_comm(struct config_item *i) ++static struct dlm_comm *config_item_to_comm(struct config_item *i) + { + return i ? container_of(i, struct dlm_comm, item) : NULL; + } + +-static struct dlm_node *to_node(struct config_item *i) ++static struct dlm_node *config_item_to_node(struct config_item *i) + { + return i ? container_of(i, struct dlm_node, item) : NULL; + } +@@ -453,7 +453,7 @@ static struct config_group *make_cluster(struct config_group *g, + + static void drop_cluster(struct config_group *g, struct config_item *i) + { +- struct dlm_cluster *cl = to_cluster(i); ++ struct dlm_cluster *cl = config_item_to_cluster(i); + struct config_item *tmp; + int j; + +@@ -471,7 +471,7 @@ static void drop_cluster(struct config_group *g, struct config_item *i) + + static void release_cluster(struct config_item *i) + { +- struct dlm_cluster *cl = to_cluster(i); ++ struct dlm_cluster *cl = config_item_to_cluster(i); + kfree(cl->group.default_groups); + kfree(cl); + } +@@ -510,7 +510,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) + + static void drop_space(struct config_group *g, struct config_item *i) + { +- struct dlm_space *sp = to_space(i); ++ struct dlm_space *sp = config_item_to_space(i); + struct config_item *tmp; + int j; + +@@ -527,7 +527,7 @@ static void drop_space(struct config_group *g, struct config_item *i) + + static void release_space(struct config_item *i) + { +- struct dlm_space *sp = to_space(i); ++ struct dlm_space *sp = config_item_to_space(i); + kfree(sp->group.default_groups); + kfree(sp); + } +@@ -549,7 +549,7 @@ static struct config_item *make_comm(struct config_group *g, const char *name) + + static void drop_comm(struct config_group *g, struct config_item *i) + { +- struct dlm_comm *cm = to_comm(i); ++ struct dlm_comm *cm = config_item_to_comm(i); + if (local_comm == cm) + local_comm = NULL; + dlm_lowcomms_close(cm->nodeid); +@@ -560,13 +560,13 @@ static void drop_comm(struct config_group *g, struct config_item *i) + + static void release_comm(struct config_item *i) + { +- struct dlm_comm *cm = to_comm(i); ++ struct dlm_comm *cm = config_item_to_comm(i); + kfree(cm); + } + + static struct config_item *make_node(struct config_group *g, const char *name) + { +- struct dlm_space *sp = to_space(g->cg_item.ci_parent); ++ struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); + struct dlm_node *nd; + + nd = kzalloc(sizeof(struct dlm_node), GFP_KERNEL); +@@ -588,8 +588,8 @@ static struct config_item *make_node(struct config_group *g, const char *name) + + static void drop_node(struct config_group *g, struct config_item *i) + { +- struct dlm_space *sp = to_space(g->cg_item.ci_parent); +- struct dlm_node *nd = to_node(i); ++ struct dlm_space *sp = config_item_to_space(g->cg_item.ci_parent); ++ struct dlm_node *nd = config_item_to_node(i); + + mutex_lock(&sp->members_lock); + list_del(&nd->list); +@@ -601,7 +601,7 @@ static void drop_node(struct config_group *g, struct config_item *i) + + static void release_node(struct config_item *i) + { +- struct dlm_node *nd = to_node(i); ++ struct dlm_node *nd = config_item_to_node(i); + kfree(nd); + } + +@@ -635,7 +635,7 @@ void dlm_config_exit(void) + static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, + char *buf) + { +- struct dlm_cluster *cl = to_cluster(i); ++ struct dlm_cluster *cl = config_item_to_cluster(i); + struct cluster_attribute *cla = + container_of(a, struct cluster_attribute, attr); + return cla->show ? cla->show(cl, buf) : 0; +@@ -645,7 +645,7 @@ static ssize_t store_cluster(struct config_item *i, + struct configfs_attribute *a, + const char *buf, size_t len) + { +- struct dlm_cluster *cl = to_cluster(i); ++ struct dlm_cluster *cl = config_item_to_cluster(i); + struct cluster_attribute *cla = + container_of(a, struct cluster_attribute, attr); + return cla->store ? cla->store(cl, buf, len) : -EINVAL; +@@ -654,7 +654,7 @@ static ssize_t store_cluster(struct config_item *i, + static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, + char *buf) + { +- struct dlm_comm *cm = to_comm(i); ++ struct dlm_comm *cm = config_item_to_comm(i); + struct comm_attribute *cma = + container_of(a, struct comm_attribute, attr); + return cma->show ? cma->show(cm, buf) : 0; +@@ -663,7 +663,7 @@ static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, + static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, + const char *buf, size_t len) + { +- struct dlm_comm *cm = to_comm(i); ++ struct dlm_comm *cm = config_item_to_comm(i); + struct comm_attribute *cma = + container_of(a, struct comm_attribute, attr); + return cma->store ? cma->store(cm, buf, len) : -EINVAL; +@@ -717,7 +717,7 @@ static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len) + static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, + char *buf) + { +- struct dlm_node *nd = to_node(i); ++ struct dlm_node *nd = config_item_to_node(i); + struct node_attribute *nda = + container_of(a, struct node_attribute, attr); + return nda->show ? nda->show(nd, buf) : 0; +@@ -726,7 +726,7 @@ static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, + static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, + const char *buf, size_t len) + { +- struct dlm_node *nd = to_node(i); ++ struct dlm_node *nd = config_item_to_node(i); + struct node_attribute *nda = + container_of(a, struct node_attribute, attr); + return nda->store ? nda->store(nd, buf, len) : -EINVAL; +@@ -771,7 +771,7 @@ static struct dlm_space *get_space(char *name) + i = config_group_find_item(space_list, name); + mutex_unlock(&space_list->cg_subsys->su_mutex); + +- return to_space(i); ++ return config_item_to_space(i); + } + + static void put_space(struct dlm_space *sp) +@@ -818,7 +818,7 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) + mutex_lock(&clusters_root.subsys.su_mutex); + + list_for_each_entry(i, &comm_list->cg_children, ci_entry) { +- cm = to_comm(i); ++ cm = config_item_to_comm(i); + + if (nodeid) { + if (cm->nodeid != nodeid) diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-clear-defunct-cancel-state.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-clear-defunct-cancel-state.patch new file mode 100644 index 000000000..614cfa5ba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-clear-defunct-cancel-state.patch @@ -0,0 +1,146 @@ +From: David Teigland +commit 43279e5376017c40b4be9af5bc79cbb4ef6f53d7 +Author: David Teigland +Date: Wed Jan 28 14:37:54 2009 -0600 +Subject: dlm: clear defunct cancel state + + When a conversion completes successfully and finds that a cancel + of the convert is still in progress (which is now a moot point), + preemptively clear the state associated with outstanding cancel. + That state could cause a subsequent conversion to be ignored. + + Also, improve the consistency and content of error and debug + messages in this area. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 01e7d39..8cb9204 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -835,7 +835,7 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype) + lkb->lkb_wait_count++; + hold_lkb(lkb); + +- log_debug(ls, "add overlap %x cur %d new %d count %d flags %x", ++ log_debug(ls, "addwait %x cur %d overlap %d count %d f %x", + lkb->lkb_id, lkb->lkb_wait_type, mstype, + lkb->lkb_wait_count, lkb->lkb_flags); + goto out; +@@ -851,7 +851,7 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype) + list_add(&lkb->lkb_wait_reply, &ls->ls_waiters); + out: + if (error) +- log_error(ls, "add_to_waiters %x error %d flags %x %d %d %s", ++ log_error(ls, "addwait error %x %d flags %x %d %d %s", + lkb->lkb_id, error, lkb->lkb_flags, mstype, + lkb->lkb_wait_type, lkb->lkb_resource->res_name); + mutex_unlock(&ls->ls_waiters_mutex); +@@ -863,23 +863,55 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype) + request reply on the requestqueue) between dlm_recover_waiters_pre() which + set RESEND and dlm_recover_waiters_post() */ + +-static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype) ++static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype, ++ struct dlm_message *ms) + { + struct dlm_ls *ls = lkb->lkb_resource->res_ls; + int overlap_done = 0; + + if (is_overlap_unlock(lkb) && (mstype == DLM_MSG_UNLOCK_REPLY)) { ++ log_debug(ls, "remwait %x unlock_reply overlap", lkb->lkb_id); + lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK; + overlap_done = 1; + goto out_del; + } + + if (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL_REPLY)) { ++ log_debug(ls, "remwait %x cancel_reply overlap", lkb->lkb_id); + lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL; + overlap_done = 1; + goto out_del; + } + ++ /* Cancel state was preemptively cleared by a successful convert, ++ see next comment, nothing to do. */ ++ ++ if ((mstype == DLM_MSG_CANCEL_REPLY) && ++ (lkb->lkb_wait_type != DLM_MSG_CANCEL)) { ++ log_debug(ls, "remwait %x cancel_reply wait_type %d", ++ lkb->lkb_id, lkb->lkb_wait_type); ++ return -1; ++ } ++ ++ /* Remove for the convert reply, and premptively remove for the ++ cancel reply. A convert has been granted while there's still ++ an outstanding cancel on it (the cancel is moot and the result ++ in the cancel reply should be 0). We preempt the cancel reply ++ because the app gets the convert result and then can follow up ++ with another op, like convert. This subsequent op would see the ++ lingering state of the cancel and fail with -EBUSY. */ ++ ++ if ((mstype == DLM_MSG_CONVERT_REPLY) && ++ (lkb->lkb_wait_type == DLM_MSG_CONVERT) && ++ is_overlap_cancel(lkb) && ms && !ms->m_result) { ++ log_debug(ls, "remwait %x convert_reply zap overlap_cancel", ++ lkb->lkb_id); ++ lkb->lkb_wait_type = 0; ++ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL; ++ lkb->lkb_wait_count--; ++ goto out_del; ++ } ++ + /* N.B. type of reply may not always correspond to type of original + msg due to lookup->request optimization, verify others? */ + +@@ -888,8 +920,8 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype) + goto out_del; + } + +- log_error(ls, "remove_from_waiters lkid %x flags %x types %d %d", +- lkb->lkb_id, lkb->lkb_flags, mstype, lkb->lkb_wait_type); ++ log_error(ls, "remwait error %x reply %d flags %x no wait_type", ++ lkb->lkb_id, mstype, lkb->lkb_flags); + return -1; + + out_del: +@@ -899,7 +931,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype) + this would happen */ + + if (overlap_done && lkb->lkb_wait_type) { +- log_error(ls, "remove_from_waiters %x reply %d give up on %d", ++ log_error(ls, "remwait error %x reply %d wait_type %d overlap", + lkb->lkb_id, mstype, lkb->lkb_wait_type); + lkb->lkb_wait_count--; + lkb->lkb_wait_type = 0; +@@ -921,7 +953,7 @@ static int remove_from_waiters(struct dlm_lkb *lkb, int mstype) + int error; + + mutex_lock(&ls->ls_waiters_mutex); +- error = _remove_from_waiters(lkb, mstype); ++ error = _remove_from_waiters(lkb, mstype, NULL); + mutex_unlock(&ls->ls_waiters_mutex); + return error; + } +@@ -936,7 +968,7 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms) + + if (ms != &ls->ls_stub_ms) + mutex_lock(&ls->ls_waiters_mutex); +- error = _remove_from_waiters(lkb, ms->m_type); ++ error = _remove_from_waiters(lkb, ms->m_type, ms); + if (ms != &ls->ls_stub_ms) + mutex_unlock(&ls->ls_waiters_mutex); + return error; +@@ -2083,6 +2115,11 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb, + lkb->lkb_timeout_cs = args->timeout; + rv = 0; + out: ++ if (rv) ++ log_debug(ls, "validate_lock_args %d %x %x %x %d %d %s", ++ rv, lkb->lkb_id, lkb->lkb_flags, args->flags, ++ lkb->lkb_status, lkb->lkb_wait_type, ++ lkb->lkb_resource->res_name); + return rv; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-comment-typo-fixes.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-comment-typo-fixes.patch new file mode 100644 index 000000000..2ee7816b3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-comment-typo-fixes.patch @@ -0,0 +1,35 @@ +From: Joe Perches +commit 2cf12c0bf261e19d9641d7b8aa220e2651a03289 +Author: Joe Perches +Date: Thu Jan 22 13:26:47 2009 -0800 +Subject: dlm: comment typo fixes + +Signed-off-by: Joe Perches +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index bf09262..982314c 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -21,7 +21,7 @@ + * + * Cluster nodes are referred to by their nodeids. nodeids are + * simply 32 bit numbers to the locking module - if they need to +- * be expanded for the cluster infrastructure then that is it's ++ * be expanded for the cluster infrastructure then that is its + * responsibility. It is this layer's + * responsibility to resolve these into IP address or + * whatever it needs for inter-node communication. +@@ -36,9 +36,9 @@ + * of high load. Also, this way, the sending thread can collect together + * messages bound for one node and send them in one block. + * +- * lowcomms will choose to use wither TCP or SCTP as its transport layer ++ * lowcomms will choose to use either TCP or SCTP as its transport layer + * depending on the configuration variable 'protocol'. This should be set +- * to 0 (default) for TCP or 1 for SCTP. It shouldbe configured using a ++ * to 0 (default) for TCP or 1 for SCTP. It should be configured using a + * cluster-wide mechanism as it must be the same on all nodes of the cluster + * for the DLM to function. + * diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-detect-available-userspace-daemon.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-detect-available-userspace-daemon.patch new file mode 100644 index 000000000..9807ccab1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-detect-available-userspace-daemon.patch @@ -0,0 +1,194 @@ +From: David Teigland +commit dc68c7ed362a00a48290252573a8eb9f74463c3a +Author: David Teigland +Date: Mon Aug 18 11:43:30 2008 -0500 +Subject: dlm: detect available userspace daemon + + If dlm_controld (the userspace daemon that controls the setup and + recovery of the dlm) fails, the kernel should shut down the lockspaces + in the kernel rather than leaving them running. This is detected by + having dlm_controld hold a misc device open while running, and if + the kernel detects a close while the daemon is still needed, it stops + the lockspaces in the kernel. + + Knowing that the userspace daemon isn't running also allows the + lockspace create/remove routines to avoid waiting on the daemon + for join/leave operations. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c +index 56eae4e..ba672fe 100644 +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -378,6 +378,11 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + if (!try_module_get(THIS_MODULE)) + return -EINVAL; + ++ if (!dlm_user_daemon_available()) { ++ module_put(THIS_MODULE); ++ return -EUNATCH; ++ } ++ + error = 0; + + spin_lock(&lslist_lock); +@@ -669,7 +674,7 @@ static int release_lockspace(struct dlm_ls *ls, int force) + + dlm_device_deregister(ls); + +- if (force < 3) ++ if (force < 3 && dlm_user_daemon_available()) + do_uevent(ls, 0); + + dlm_recoverd_stop(ls); +@@ -791,3 +796,20 @@ int dlm_release_lockspace(void *lockspace, int force) + return error; + } + ++void dlm_stop_lockspaces(void) ++{ ++ struct dlm_ls *ls; ++ ++ restart: ++ spin_lock(&lslist_lock); ++ list_for_each_entry(ls, &lslist, ls_list) { ++ if (!test_bit(LSFL_RUNNING, &ls->ls_flags)) ++ continue; ++ spin_unlock(&lslist_lock); ++ log_error(ls, "no userland control daemon, stopping lockspace"); ++ dlm_ls_stop(ls); ++ goto restart; ++ } ++ spin_unlock(&lslist_lock); ++} ++ +diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h +index 891eabb..f879f87 100644 +--- a/fs/dlm/lockspace.h ++++ b/fs/dlm/lockspace.h +@@ -20,6 +20,7 @@ struct dlm_ls *dlm_find_lockspace_global(uint32_t id); + struct dlm_ls *dlm_find_lockspace_local(void *id); + struct dlm_ls *dlm_find_lockspace_device(int minor); + void dlm_put_lockspace(struct dlm_ls *ls); ++void dlm_stop_lockspaces(void); + + #endif /* __LOCKSPACE_DOT_H__ */ + +diff --git a/fs/dlm/user.c b/fs/dlm/user.c +index 6542110..81627b5 100644 +--- a/fs/dlm/user.c ++++ b/fs/dlm/user.c +@@ -27,6 +27,8 @@ + + static const char name_prefix[] = "dlm"; + static const struct file_operations device_fops; ++static atomic_t dlm_monitor_opened; ++static int dlm_monitor_unused = 1; + + #ifdef CONFIG_COMPAT + +@@ -890,6 +892,26 @@ static unsigned int device_poll(struct file *file, poll_table *wait) + return 0; + } + ++int dlm_user_daemon_available(void) ++{ ++ /* dlm_controld hasn't started (or, has started, but not ++ properly populated configfs) */ ++ ++ if (!dlm_our_nodeid()) ++ return 0; ++ ++ /* This is to deal with versions of dlm_controld that don't ++ know about the monitor device. We assume that if the ++ dlm_controld was started (above), but the monitor device ++ was never opened, that it's an old version. dlm_controld ++ should open the monitor device before populating configfs. */ ++ ++ if (dlm_monitor_unused) ++ return 1; ++ ++ return atomic_read(&dlm_monitor_opened) ? 1 : 0; ++} ++ + static int ctl_device_open(struct inode *inode, struct file *file) + { + cycle_kernel_lock(); +@@ -902,6 +924,20 @@ static int ctl_device_close(struct inode *inode, struct file *file) + return 0; + } + ++static int monitor_device_open(struct inode *inode, struct file *file) ++{ ++ atomic_inc(&dlm_monitor_opened); ++ dlm_monitor_unused = 0; ++ return 0; ++} ++ ++static int monitor_device_close(struct inode *inode, struct file *file) ++{ ++ if (atomic_dec_and_test(&dlm_monitor_opened)) ++ dlm_stop_lockspaces(); ++ return 0; ++} ++ + static const struct file_operations device_fops = { + .open = device_open, + .release = device_close, +@@ -925,19 +961,42 @@ static struct miscdevice ctl_device = { + .minor = MISC_DYNAMIC_MINOR, + }; + ++static const struct file_operations monitor_device_fops = { ++ .open = monitor_device_open, ++ .release = monitor_device_close, ++ .owner = THIS_MODULE, ++}; ++ ++static struct miscdevice monitor_device = { ++ .name = "dlm-monitor", ++ .fops = &monitor_device_fops, ++ .minor = MISC_DYNAMIC_MINOR, ++}; ++ + int __init dlm_user_init(void) + { + int error; + ++ atomic_set(&dlm_monitor_opened, 0); ++ + error = misc_register(&ctl_device); +- if (error) ++ if (error) { + log_print("misc_register failed for control device"); ++ goto out; ++ } + ++ error = misc_register(&monitor_device); ++ if (error) { ++ log_print("misc_register failed for monitor device"); ++ misc_deregister(&ctl_device); ++ } ++ out: + return error; + } + + void dlm_user_exit(void) + { + misc_deregister(&ctl_device); ++ misc_deregister(&monitor_device); + } + +diff --git a/fs/dlm/user.h b/fs/dlm/user.h +index c528b6b..35eb6a1 100644 +--- a/fs/dlm/user.h ++++ b/fs/dlm/user.h +@@ -13,5 +13,6 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type); + int dlm_user_init(void); + void dlm_user_exit(void); + int dlm_device_deregister(struct dlm_ls *ls); ++int dlm_user_daemon_available(void); + + #endif diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-address-compare.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-address-compare.patch new file mode 100644 index 000000000..b47900357 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-address-compare.patch @@ -0,0 +1,70 @@ +From: David Teigland +commit 44be6fdf1056b685eb79e53e42bd2d321b085cfc +Author: David Teigland +Date: Thu Aug 28 11:36:19 2008 -0500 +Subject: dlm: fix address compare + + Compare only the addr and port fields of sockaddr structures. + Fixes a problem with ipv6 where sin6_scope_id does not match. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/config.c b/fs/dlm/config.c +index 89d2fb7..1359be3 100644 +--- a/fs/dlm/config.c ++++ b/fs/dlm/config.c +@@ -14,6 +14,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + + #include "config.h" +@@ -776,6 +779,33 @@ static void put_space(struct dlm_space *sp) + config_item_put(&sp->group.cg_item); + } + ++static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y) ++{ ++ switch (x->ss_family) { ++ case AF_INET: { ++ struct sockaddr_in *sinx = (struct sockaddr_in *)x; ++ struct sockaddr_in *siny = (struct sockaddr_in *)y; ++ if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr) ++ return 0; ++ if (sinx->sin_port != siny->sin_port) ++ return 0; ++ break; ++ } ++ case AF_INET6: { ++ struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x; ++ struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y; ++ if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr)) ++ return 0; ++ if (sinx->sin6_port != siny->sin6_port) ++ return 0; ++ break; ++ } ++ default: ++ return 0; ++ } ++ return 1; ++} ++ + static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) + { + struct config_item *i; +@@ -797,8 +827,7 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) + config_item_get(i); + break; + } else { +- if (!cm->addr_count || +- memcmp(cm->addr[0], addr, sizeof(*addr))) ++ if (!cm->addr_count || !addr_compare(cm->addr[0], addr)) + continue; + found = 1; + config_item_get(i); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-length-calculation-in-compat-code.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-length-calculation-in-compat-code.patch new file mode 100644 index 000000000..1e9aba5c7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-length-calculation-in-compat-code.patch @@ -0,0 +1,87 @@ +From: David Teigland +commit 1fecb1c4b62881e3689ba2dcf93072ae301b597c +Author: David Teigland +Date: Wed Mar 4 11:17:23 2009 -0600 +Subject: dlm: fix length calculation in compat code + + Using offsetof() to calculate name length does not work because + it does not produce consistent results with with structure packing. + This caused memcpy to corrupt memory by copying 4 extra bytes off + the end of the buffer on 64 bit kernels with 32 bit userspace + (the only case where this 32/64 compat code is used). + + The fix is to calculate name length directly from the start instead + of trying to derive it later using count and offsetof. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/user.c b/fs/dlm/user.c +index 065149e..ebce994 100644 +--- a/fs/dlm/user.c ++++ b/fs/dlm/user.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions +@@ -84,7 +84,7 @@ struct dlm_lock_result32 { + + static void compat_input(struct dlm_write_request *kb, + struct dlm_write_request32 *kb32, +- size_t count) ++ int namelen) + { + kb->version[0] = kb32->version[0]; + kb->version[1] = kb32->version[1]; +@@ -96,8 +96,7 @@ static void compat_input(struct dlm_write_request *kb, + kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { + kb->i.lspace.flags = kb32->i.lspace.flags; + kb->i.lspace.minor = kb32->i.lspace.minor; +- memcpy(kb->i.lspace.name, kb32->i.lspace.name, count - +- offsetof(struct dlm_write_request32, i.lspace.name)); ++ memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen); + } else if (kb->cmd == DLM_USER_PURGE) { + kb->i.purge.nodeid = kb32->i.purge.nodeid; + kb->i.purge.pid = kb32->i.purge.pid; +@@ -115,8 +114,7 @@ static void compat_input(struct dlm_write_request *kb, + kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; + kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; + memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); +- memcpy(kb->i.lock.name, kb32->i.lock.name, count - +- offsetof(struct dlm_write_request32, i.lock.name)); ++ memcpy(kb->i.lock.name, kb32->i.lock.name, namelen); + } + } + +@@ -539,9 +537,16 @@ static ssize_t device_write(struct file *file, const char __user *buf, + #ifdef CONFIG_COMPAT + if (!kbuf->is64bit) { + struct dlm_write_request32 *k32buf; ++ int namelen = 0; ++ ++ if (count > sizeof(struct dlm_write_request32)) ++ namelen = count - sizeof(struct dlm_write_request32); ++ + k32buf = (struct dlm_write_request32 *)kbuf; +- kbuf = kmalloc(count + 1 + (sizeof(struct dlm_write_request) - +- sizeof(struct dlm_write_request32)), GFP_KERNEL); ++ ++ /* add 1 after namelen so that the name string is terminated */ ++ kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1, ++ GFP_KERNEL); + if (!kbuf) { + kfree(k32buf); + return -ENOMEM; +@@ -549,7 +554,8 @@ static ssize_t device_write(struct file *file, const char __user *buf, + + if (proc) + set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); +- compat_input(kbuf, k32buf, count + 1); ++ ++ compat_input(kbuf, k32buf, namelen); + kfree(k32buf); + } + #endif diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-locking-of-lockspace-list-in-dlm_scand.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-locking-of-lockspace-list-in-dlm_scand.patch new file mode 100644 index 000000000..06d9c5c7c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-locking-of-lockspace-list-in-dlm_scand.patch @@ -0,0 +1,80 @@ +From: David Teigland +commit c1dcf65ffc5796bf4ff75c13f448e63b3a416fd6 +Author: David Teigland +Date: Mon Aug 18 14:03:25 2008 -0500 +Subject: dlm: fix locking of lockspace list in dlm_scand + + The dlm_scand thread needs to lock the list of lockspaces + when going through it. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h +index 9e0622a..868e4c9 100644 +--- a/fs/dlm/dlm_internal.h ++++ b/fs/dlm/dlm_internal.h +@@ -445,6 +445,7 @@ struct dlm_ls { + the dlm using this ls */ + int ls_create_count; /* create/release refcount */ + unsigned long ls_flags; /* LSFL_ */ ++ unsigned long ls_scan_time; + struct kobject ls_kobj; + + struct dlm_rsbtable *ls_rsbtbl; +diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c +index ba672fe..d910501 100644 +--- a/fs/dlm/lockspace.c ++++ b/fs/dlm/lockspace.c +@@ -212,19 +212,41 @@ void dlm_lockspace_exit(void) + kset_unregister(dlm_kset); + } + ++static struct dlm_ls *find_ls_to_scan(void) ++{ ++ struct dlm_ls *ls; ++ ++ spin_lock(&lslist_lock); ++ list_for_each_entry(ls, &lslist, ls_list) { ++ if (time_after_eq(jiffies, ls->ls_scan_time + ++ dlm_config.ci_scan_secs * HZ)) { ++ spin_unlock(&lslist_lock); ++ return ls; ++ } ++ } ++ spin_unlock(&lslist_lock); ++ return NULL; ++} ++ + static int dlm_scand(void *data) + { + struct dlm_ls *ls; ++ int timeout_jiffies = dlm_config.ci_scan_secs * HZ; + + while (!kthread_should_stop()) { +- list_for_each_entry(ls, &lslist, ls_list) { ++ ls = find_ls_to_scan(); ++ if (ls) { + if (dlm_lock_recovery_try(ls)) { ++ ls->ls_scan_time = jiffies; + dlm_scan_rsbs(ls); + dlm_scan_timeout(ls); + dlm_unlock_recovery(ls); ++ } else { ++ ls->ls_scan_time += HZ; + } ++ } else { ++ schedule_timeout_interruptible(timeout_jiffies); + } +- schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ); + } + return 0; + } +@@ -418,6 +440,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, + ls->ls_lvblen = lvblen; + ls->ls_count = 0; + ls->ls_flags = 0; ++ ls->ls_scan_time = jiffies; + + if (flags & DLM_LSFL_TIMEWARN) + set_bit(LSFL_TIMEWARN, &ls->ls_flags); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-plock-notify-callback-to-lockd.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-plock-notify-callback-to-lockd.patch new file mode 100644 index 000000000..51fc62d69 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-plock-notify-callback-to-lockd.patch @@ -0,0 +1,36 @@ +From: David Teigland +commit 24179f488092267c9a033d7e25ce7a58af50ff79 +Author: David Teigland +Date: Mon Jan 19 13:13:33 2009 -0600 +Subject: dlm: fix plock notify callback to lockd + + We should use the original copy of the file_lock, fl, instead + of the copy, flc in the lockd notify callback. The range in flc has + been modified by posix_lock_file(), so it will not match a copy of the + lock in lockd. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c +index eba87ff..502b1ea 100644 +--- a/fs/dlm/plock.c ++++ b/fs/dlm/plock.c +@@ -168,7 +168,7 @@ static int dlm_plock_callback(struct plock_op *op) + notify = xop->callback; + + if (op->info.rv) { +- notify(flc, NULL, op->info.rv); ++ notify(fl, NULL, op->info.rv); + goto out; + } + +@@ -187,7 +187,7 @@ static int dlm_plock_callback(struct plock_op *op) + (unsigned long long)op->info.number, file, fl); + } + +- rv = notify(flc, NULL, 0); ++ rv = notify(fl, NULL, 0); + if (rv) { + /* XXX: We need to cancel the fs lock here: */ + log_print("dlm_plock_callback: lock granted after lock request " diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-seq_file-usage-in-debugfs-lock-dump.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-seq_file-usage-in-debugfs-lock-dump.patch new file mode 100644 index 000000000..8bb27b62e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-seq_file-usage-in-debugfs-lock-dump.patch @@ -0,0 +1,952 @@ +From: David Teigland +commit 892c4467e335e9050c95e0d8409c136c4dadaca2 +Author: David Teigland +Date: Wed Jan 7 16:48:52 2009 -0600 +Subject: dlm: fix seq_file usage in debugfs lock dump + + The old code would leak iterators and leave reference counts on + rsbs because it was ignoring the "stop" seq callback. The code + followed an example that used the seq operations differently. + This new code is based on actually understanding how the seq + operations work. It also improves things by saving the hash bucket + in the position to avoid cycling through completed buckets in start. + +Siged-off-by: Davd Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c +index 2f107d1..bc4af3e 100644 +--- a/fs/dlm/debug_fs.c ++++ b/fs/dlm/debug_fs.c +@@ -1,7 +1,7 @@ + /****************************************************************************** + ******************************************************************************* + ** +-** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2005-2009 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -25,19 +25,6 @@ static struct mutex debug_buf_lock; + + static struct dentry *dlm_root; + +-struct rsb_iter { +- int entry; +- int format; +- int header; +- struct dlm_ls *ls; +- struct list_head *next; +- struct dlm_rsb *rsb; +-}; +- +-/* +- * dump all rsb's in the lockspace hash table +- */ +- + static char *print_lockmode(int mode) + { + switch (mode) { +@@ -60,13 +47,13 @@ static char *print_lockmode(int mode) + } + } + +-static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, +- struct dlm_rsb *res) ++static int print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, ++ struct dlm_rsb *res) + { + seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode)); + +- if (lkb->lkb_status == DLM_LKSTS_CONVERT +- || lkb->lkb_status == DLM_LKSTS_WAITING) ++ if (lkb->lkb_status == DLM_LKSTS_CONVERT || ++ lkb->lkb_status == DLM_LKSTS_WAITING) + seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode)); + + if (lkb->lkb_nodeid) { +@@ -80,33 +67,42 @@ static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb, + if (lkb->lkb_wait_type) + seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); + +- seq_printf(s, "\n"); ++ return seq_printf(s, "\n"); + } + + static int print_format1(struct dlm_rsb *res, struct seq_file *s) + { + struct dlm_lkb *lkb; + int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list; ++ int rv; + + lock_rsb(res); + +- seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length); ++ rv = seq_printf(s, "\nResource %p Name (len=%d) \"", ++ res, res->res_length); ++ if (rv) ++ goto out; ++ + for (i = 0; i < res->res_length; i++) { + if (isprint(res->res_name[i])) + seq_printf(s, "%c", res->res_name[i]); + else + seq_printf(s, "%c", '.'); + } ++ + if (res->res_nodeid > 0) +- seq_printf(s, "\" \nLocal Copy, Master is node %d\n", +- res->res_nodeid); ++ rv = seq_printf(s, "\" \nLocal Copy, Master is node %d\n", ++ res->res_nodeid); + else if (res->res_nodeid == 0) +- seq_printf(s, "\" \nMaster Copy\n"); ++ rv = seq_printf(s, "\" \nMaster Copy\n"); + else if (res->res_nodeid == -1) +- seq_printf(s, "\" \nLooking up master (lkid %x)\n", +- res->res_first_lkid); ++ rv = seq_printf(s, "\" \nLooking up master (lkid %x)\n", ++ res->res_first_lkid); + else +- seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid); ++ rv = seq_printf(s, "\" \nInvalid master %d\n", ++ res->res_nodeid); ++ if (rv) ++ goto out; + + /* Print the LVB: */ + if (res->res_lvbptr) { +@@ -119,52 +115,66 @@ static int print_format1(struct dlm_rsb *res, struct seq_file *s) + } + if (rsb_flag(res, RSB_VALNOTVALID)) + seq_printf(s, " (INVALID)"); +- seq_printf(s, "\n"); ++ rv = seq_printf(s, "\n"); ++ if (rv) ++ goto out; + } + + root_list = !list_empty(&res->res_root_list); + recover_list = !list_empty(&res->res_recover_list); + + if (root_list || recover_list) { +- seq_printf(s, "Recovery: root %d recover %d flags %lx " +- "count %d\n", root_list, recover_list, +- res->res_flags, res->res_recover_locks_count); ++ rv = seq_printf(s, "Recovery: root %d recover %d flags %lx " ++ "count %d\n", root_list, recover_list, ++ res->res_flags, res->res_recover_locks_count); ++ if (rv) ++ goto out; + } + + /* Print the locks attached to this resource */ + seq_printf(s, "Granted Queue\n"); +- list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) +- print_format1_lock(s, lkb, res); ++ list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) { ++ rv = print_format1_lock(s, lkb, res); ++ if (rv) ++ goto out; ++ } + + seq_printf(s, "Conversion Queue\n"); +- list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) +- print_format1_lock(s, lkb, res); ++ list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) { ++ rv = print_format1_lock(s, lkb, res); ++ if (rv) ++ goto out; ++ } + + seq_printf(s, "Waiting Queue\n"); +- list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) +- print_format1_lock(s, lkb, res); ++ list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) { ++ rv = print_format1_lock(s, lkb, res); ++ if (rv) ++ goto out; ++ } + + if (list_empty(&res->res_lookup)) + goto out; + + seq_printf(s, "Lookup Queue\n"); + list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) { +- seq_printf(s, "%08x %s", lkb->lkb_id, +- print_lockmode(lkb->lkb_rqmode)); ++ rv = seq_printf(s, "%08x %s", lkb->lkb_id, ++ print_lockmode(lkb->lkb_rqmode)); + if (lkb->lkb_wait_type) + seq_printf(s, " wait_type: %d", lkb->lkb_wait_type); +- seq_printf(s, "\n"); ++ rv = seq_printf(s, "\n"); + } + out: + unlock_rsb(res); +- return 0; ++ return rv; + } + +-static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, +- struct dlm_rsb *r) ++static int print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, ++ struct dlm_rsb *r) + { + u64 xid = 0; + u64 us; ++ int rv; + + if (lkb->lkb_flags & DLM_IFL_USER) { + if (lkb->lkb_ua) +@@ -177,69 +187,82 @@ static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb, + /* id nodeid remid pid xid exflags flags sts grmode rqmode time_us + r_nodeid r_len r_name */ + +- seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n", +- lkb->lkb_id, +- lkb->lkb_nodeid, +- lkb->lkb_remid, +- lkb->lkb_ownpid, +- (unsigned long long)xid, +- lkb->lkb_exflags, +- lkb->lkb_flags, +- lkb->lkb_status, +- lkb->lkb_grmode, +- lkb->lkb_rqmode, +- (unsigned long long)us, +- r->res_nodeid, +- r->res_length, +- r->res_name); ++ rv = seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n", ++ lkb->lkb_id, ++ lkb->lkb_nodeid, ++ lkb->lkb_remid, ++ lkb->lkb_ownpid, ++ (unsigned long long)xid, ++ lkb->lkb_exflags, ++ lkb->lkb_flags, ++ lkb->lkb_status, ++ lkb->lkb_grmode, ++ lkb->lkb_rqmode, ++ (unsigned long long)us, ++ r->res_nodeid, ++ r->res_length, ++ r->res_name); ++ return rv; + } + + static int print_format2(struct dlm_rsb *r, struct seq_file *s) + { + struct dlm_lkb *lkb; ++ int rv = 0; + + lock_rsb(r); + +- list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) +- print_format2_lock(s, lkb, r); +- +- list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) +- print_format2_lock(s, lkb, r); ++ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { ++ rv = print_format2_lock(s, lkb, r); ++ if (rv) ++ goto out; ++ } + +- list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) +- print_format2_lock(s, lkb, r); ++ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { ++ rv = print_format2_lock(s, lkb, r); ++ if (rv) ++ goto out; ++ } + ++ list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { ++ rv = print_format2_lock(s, lkb, r); ++ if (rv) ++ goto out; ++ } ++ out: + unlock_rsb(r); +- return 0; ++ return rv; + } + +-static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, +- int rsb_lookup) ++static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb, ++ int rsb_lookup) + { + u64 xid = 0; ++ int rv; + + if (lkb->lkb_flags & DLM_IFL_USER) { + if (lkb->lkb_ua) + xid = lkb->lkb_ua->xid; + } + +- seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", +- lkb->lkb_id, +- lkb->lkb_nodeid, +- lkb->lkb_remid, +- lkb->lkb_ownpid, +- (unsigned long long)xid, +- lkb->lkb_exflags, +- lkb->lkb_flags, +- lkb->lkb_status, +- lkb->lkb_grmode, +- lkb->lkb_rqmode, +- lkb->lkb_highbast, +- rsb_lookup, +- lkb->lkb_wait_type, +- lkb->lkb_lvbseq, +- (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), +- (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); ++ rv = seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n", ++ lkb->lkb_id, ++ lkb->lkb_nodeid, ++ lkb->lkb_remid, ++ lkb->lkb_ownpid, ++ (unsigned long long)xid, ++ lkb->lkb_exflags, ++ lkb->lkb_flags, ++ lkb->lkb_status, ++ lkb->lkb_grmode, ++ lkb->lkb_rqmode, ++ lkb->lkb_highbast, ++ rsb_lookup, ++ lkb->lkb_wait_type, ++ lkb->lkb_lvbseq, ++ (unsigned long long)ktime_to_ns(lkb->lkb_timestamp), ++ (unsigned long long)ktime_to_ns(lkb->lkb_time_bast)); ++ return rv; + } + + static int print_format3(struct dlm_rsb *r, struct seq_file *s) +@@ -247,18 +270,21 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s) + struct dlm_lkb *lkb; + int i, lvblen = r->res_ls->ls_lvblen; + int print_name = 1; ++ int rv; + + lock_rsb(r); + +- seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", +- r, +- r->res_nodeid, +- r->res_first_lkid, +- r->res_flags, +- !list_empty(&r->res_root_list), +- !list_empty(&r->res_recover_list), +- r->res_recover_locks_count, +- r->res_length); ++ rv = seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ", ++ r, ++ r->res_nodeid, ++ r->res_first_lkid, ++ r->res_flags, ++ !list_empty(&r->res_root_list), ++ !list_empty(&r->res_recover_list), ++ r->res_recover_locks_count, ++ r->res_length); ++ if (rv) ++ goto out; + + for (i = 0; i < r->res_length; i++) { + if (!isascii(r->res_name[i]) || !isprint(r->res_name[i])) +@@ -273,7 +299,9 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s) + else + seq_printf(s, " %02x", (unsigned char)r->res_name[i]); + } +- seq_printf(s, "\n"); ++ rv = seq_printf(s, "\n"); ++ if (rv) ++ goto out; + + if (!r->res_lvbptr) + goto do_locks; +@@ -282,344 +310,294 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s) + + for (i = 0; i < lvblen; i++) + seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]); +- seq_printf(s, "\n"); ++ rv = seq_printf(s, "\n"); ++ if (rv) ++ goto out; + + do_locks: +- list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) +- print_format3_lock(s, lkb, 0); +- +- list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) +- print_format3_lock(s, lkb, 0); +- +- list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) +- print_format3_lock(s, lkb, 0); +- +- list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) +- print_format3_lock(s, lkb, 1); +- +- unlock_rsb(r); +- return 0; +-} +- +-static int rsb_iter_next(struct rsb_iter *ri) +-{ +- struct dlm_ls *ls = ri->ls; +- int i; +- +- if (!ri->next) { +- top: +- /* Find the next non-empty hash bucket */ +- for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) { +- read_lock(&ls->ls_rsbtbl[i].lock); +- if (!list_empty(&ls->ls_rsbtbl[i].list)) { +- ri->next = ls->ls_rsbtbl[i].list.next; +- ri->rsb = list_entry(ri->next, struct dlm_rsb, +- res_hashchain); +- dlm_hold_rsb(ri->rsb); +- read_unlock(&ls->ls_rsbtbl[i].lock); +- break; +- } +- read_unlock(&ls->ls_rsbtbl[i].lock); +- } +- ri->entry = i; +- +- if (ri->entry >= ls->ls_rsbtbl_size) +- return 1; +- } else { +- struct dlm_rsb *old = ri->rsb; +- i = ri->entry; +- read_lock(&ls->ls_rsbtbl[i].lock); +- ri->next = ri->next->next; +- if (ri->next->next == ls->ls_rsbtbl[i].list.next) { +- /* End of list - move to next bucket */ +- ri->next = NULL; +- ri->entry++; +- read_unlock(&ls->ls_rsbtbl[i].lock); +- dlm_put_rsb(old); +- goto top; +- } +- ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain); +- dlm_hold_rsb(ri->rsb); +- read_unlock(&ls->ls_rsbtbl[i].lock); +- dlm_put_rsb(old); ++ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) { ++ rv = print_format3_lock(s, lkb, 0); ++ if (rv) ++ goto out; + } + +- return 0; +-} +- +-static void rsb_iter_free(struct rsb_iter *ri) +-{ +- kfree(ri); +-} +- +-static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls) +-{ +- struct rsb_iter *ri; +- +- ri = kzalloc(sizeof *ri, GFP_KERNEL); +- if (!ri) +- return NULL; +- +- ri->ls = ls; +- ri->entry = 0; +- ri->next = NULL; +- ri->format = 1; +- +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); +- return NULL; ++ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) { ++ rv = print_format3_lock(s, lkb, 0); ++ if (rv) ++ goto out; + } + +- return ri; +-} +- +-static void *rsb_seq_start(struct seq_file *file, loff_t *pos) +-{ +- struct rsb_iter *ri; +- loff_t n = *pos; +- +- ri = rsb_iter_init(file->private); +- if (!ri) +- return NULL; +- +- while (n--) { +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); +- return NULL; +- } ++ list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) { ++ rv = print_format3_lock(s, lkb, 0); ++ if (rv) ++ goto out; + } + +- return ri; +-} +- +-static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos) +-{ +- struct rsb_iter *ri = iter_ptr; +- +- (*pos)++; +- +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); +- return NULL; ++ list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) { ++ rv = print_format3_lock(s, lkb, 1); ++ if (rv) ++ goto out; + } +- +- return ri; ++ out: ++ unlock_rsb(r); ++ return rv; + } + +-static void rsb_seq_stop(struct seq_file *file, void *iter_ptr) +-{ +- /* nothing for now */ +-} ++struct rsbtbl_iter { ++ struct dlm_rsb *rsb; ++ unsigned bucket; ++ int format; ++ int header; ++}; + +-static int rsb_seq_show(struct seq_file *file, void *iter_ptr) ++/* seq_printf returns -1 if the buffer is full, and 0 otherwise. ++ If the buffer is full, seq_printf can be called again, but it ++ does nothing and just returns -1. So, the these printing routines ++ periodically check the return value to avoid wasting too much time ++ trying to print to a full buffer. */ ++ ++static int table_seq_show(struct seq_file *seq, void *iter_ptr) + { +- struct rsb_iter *ri = iter_ptr; ++ struct rsbtbl_iter *ri = iter_ptr; ++ int rv = 0; + + switch (ri->format) { + case 1: +- print_format1(ri->rsb, file); ++ rv = print_format1(ri->rsb, seq); + break; + case 2: + if (ri->header) { +- seq_printf(file, "id nodeid remid pid xid exflags " +- "flags sts grmode rqmode time_ms " +- "r_nodeid r_len r_name\n"); ++ seq_printf(seq, "id nodeid remid pid xid exflags " ++ "flags sts grmode rqmode time_ms " ++ "r_nodeid r_len r_name\n"); + ri->header = 0; + } +- print_format2(ri->rsb, file); ++ rv = print_format2(ri->rsb, seq); + break; + case 3: + if (ri->header) { +- seq_printf(file, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); ++ seq_printf(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n"); + ri->header = 0; + } +- print_format3(ri->rsb, file); ++ rv = print_format3(ri->rsb, seq); + break; + } + +- return 0; ++ return rv; + } + +-static struct seq_operations rsb_seq_ops = { +- .start = rsb_seq_start, +- .next = rsb_seq_next, +- .stop = rsb_seq_stop, +- .show = rsb_seq_show, +-}; ++static struct seq_operations format1_seq_ops; ++static struct seq_operations format2_seq_ops; ++static struct seq_operations format3_seq_ops; + +-static int rsb_open(struct inode *inode, struct file *file) ++static void *table_seq_start(struct seq_file *seq, loff_t *pos) + { +- struct seq_file *seq; +- int ret; +- +- ret = seq_open(file, &rsb_seq_ops); +- if (ret) +- return ret; +- +- seq = file->private_data; +- seq->private = inode->i_private; +- +- return 0; +-} +- +-static const struct file_operations rsb_fops = { +- .owner = THIS_MODULE, +- .open = rsb_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = seq_release +-}; ++ struct dlm_ls *ls = seq->private; ++ struct rsbtbl_iter *ri; ++ struct dlm_rsb *r; ++ loff_t n = *pos; ++ unsigned bucket, entry; + +-/* +- * Dump state in compact per-lock listing +- */ ++ bucket = n >> 32; ++ entry = n & ((1LL << 32) - 1); + +-static struct rsb_iter *locks_iter_init(struct dlm_ls *ls, loff_t *pos) +-{ +- struct rsb_iter *ri; ++ if (bucket >= ls->ls_rsbtbl_size) ++ return NULL; + +- ri = kzalloc(sizeof *ri, GFP_KERNEL); ++ ri = kzalloc(sizeof(struct rsbtbl_iter), GFP_KERNEL); + if (!ri) + return NULL; +- +- ri->ls = ls; +- ri->entry = 0; +- ri->next = NULL; +- ri->format = 2; +- +- if (*pos == 0) ++ if (n == 0) + ri->header = 1; +- +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); +- return NULL; ++ if (seq->op == &format1_seq_ops) ++ ri->format = 1; ++ if (seq->op == &format2_seq_ops) ++ ri->format = 2; ++ if (seq->op == &format3_seq_ops) ++ ri->format = 3; ++ ++ read_lock(&ls->ls_rsbtbl[bucket].lock); ++ if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { ++ list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, ++ res_hashchain) { ++ if (!entry--) { ++ dlm_hold_rsb(r); ++ ri->rsb = r; ++ ri->bucket = bucket; ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ return ri; ++ } ++ } + } ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); + +- return ri; +-} ++ /* ++ * move to the first rsb in the next non-empty bucket ++ */ + +-static void *locks_seq_start(struct seq_file *file, loff_t *pos) +-{ +- struct rsb_iter *ri; +- loff_t n = *pos; ++ /* zero the entry */ ++ n &= ~((1LL << 32) - 1); + +- ri = locks_iter_init(file->private, pos); +- if (!ri) +- return NULL; ++ while (1) { ++ bucket++; ++ n += 1LL << 32; + +- while (n--) { +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); ++ if (bucket >= ls->ls_rsbtbl_size) { ++ kfree(ri); + return NULL; + } +- } + +- return ri; ++ read_lock(&ls->ls_rsbtbl[bucket].lock); ++ if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { ++ r = list_first_entry(&ls->ls_rsbtbl[bucket].list, ++ struct dlm_rsb, res_hashchain); ++ dlm_hold_rsb(r); ++ ri->rsb = r; ++ ri->bucket = bucket; ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ *pos = n; ++ return ri; ++ } ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ } + } + +-static struct seq_operations locks_seq_ops = { +- .start = locks_seq_start, +- .next = rsb_seq_next, +- .stop = rsb_seq_stop, +- .show = rsb_seq_show, +-}; +- +-static int locks_open(struct inode *inode, struct file *file) ++static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) + { +- struct seq_file *seq; +- int ret; +- +- ret = seq_open(file, &locks_seq_ops); +- if (ret) +- return ret; +- +- seq = file->private_data; +- seq->private = inode->i_private; +- +- return 0; +-} +- +-static const struct file_operations locks_fops = { +- .owner = THIS_MODULE, +- .open = locks_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = seq_release +-}; +- +-/* +- * Dump all rsb/lvb/lkb state in compact listing, more complete than _locks +- * This can replace both formats 1 and 2 eventually. +- */ ++ struct dlm_ls *ls = seq->private; ++ struct rsbtbl_iter *ri = iter_ptr; ++ struct list_head *next; ++ struct dlm_rsb *r, *rp; ++ loff_t n = *pos; ++ unsigned bucket; ++ ++ bucket = n >> 32; ++ ++ /* ++ * move to the next rsb in the same bucket ++ */ ++ ++ read_lock(&ls->ls_rsbtbl[bucket].lock); ++ rp = ri->rsb; ++ next = rp->res_hashchain.next; ++ ++ if (next != &ls->ls_rsbtbl[bucket].list) { ++ r = list_entry(next, struct dlm_rsb, res_hashchain); ++ dlm_hold_rsb(r); ++ ri->rsb = r; ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ dlm_put_rsb(rp); ++ ++*pos; ++ return ri; ++ } ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ dlm_put_rsb(rp); + +-static struct rsb_iter *all_iter_init(struct dlm_ls *ls, loff_t *pos) +-{ +- struct rsb_iter *ri; ++ /* ++ * move to the first rsb in the next non-empty bucket ++ */ + +- ri = kzalloc(sizeof *ri, GFP_KERNEL); +- if (!ri) +- return NULL; ++ /* zero the entry */ ++ n &= ~((1LL << 32) - 1); + +- ri->ls = ls; +- ri->entry = 0; +- ri->next = NULL; +- ri->format = 3; ++ while (1) { ++ bucket++; ++ n += 1LL << 32; + +- if (*pos == 0) +- ri->header = 1; ++ if (bucket >= ls->ls_rsbtbl_size) { ++ kfree(ri); ++ return NULL; ++ } + +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); +- return NULL; ++ read_lock(&ls->ls_rsbtbl[bucket].lock); ++ if (!list_empty(&ls->ls_rsbtbl[bucket].list)) { ++ r = list_first_entry(&ls->ls_rsbtbl[bucket].list, ++ struct dlm_rsb, res_hashchain); ++ dlm_hold_rsb(r); ++ ri->rsb = r; ++ ri->bucket = bucket; ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); ++ *pos = n; ++ return ri; ++ } ++ read_unlock(&ls->ls_rsbtbl[bucket].lock); + } +- +- return ri; + } + +-static void *all_seq_start(struct seq_file *file, loff_t *pos) ++static void table_seq_stop(struct seq_file *seq, void *iter_ptr) + { +- struct rsb_iter *ri; +- loff_t n = *pos; +- +- ri = all_iter_init(file->private, pos); +- if (!ri) +- return NULL; ++ struct rsbtbl_iter *ri = iter_ptr; + +- while (n--) { +- if (rsb_iter_next(ri)) { +- rsb_iter_free(ri); +- return NULL; +- } ++ if (ri) { ++ dlm_put_rsb(ri->rsb); ++ kfree(ri); + } +- +- return ri; + } + +-static struct seq_operations all_seq_ops = { +- .start = all_seq_start, +- .next = rsb_seq_next, +- .stop = rsb_seq_stop, +- .show = rsb_seq_show, ++static struct seq_operations format1_seq_ops = { ++ .start = table_seq_start, ++ .next = table_seq_next, ++ .stop = table_seq_stop, ++ .show = table_seq_show, + }; + +-static int all_open(struct inode *inode, struct file *file) ++static struct seq_operations format2_seq_ops = { ++ .start = table_seq_start, ++ .next = table_seq_next, ++ .stop = table_seq_stop, ++ .show = table_seq_show, ++}; ++ ++static struct seq_operations format3_seq_ops = { ++ .start = table_seq_start, ++ .next = table_seq_next, ++ .stop = table_seq_stop, ++ .show = table_seq_show, ++}; ++ ++static const struct file_operations format1_fops; ++static const struct file_operations format2_fops; ++static const struct file_operations format3_fops; ++ ++static int table_open(struct inode *inode, struct file *file) + { + struct seq_file *seq; +- int ret; ++ int ret = -1; ++ ++ if (file->f_op == &format1_fops) ++ ret = seq_open(file, &format1_seq_ops); ++ else if (file->f_op == &format2_fops) ++ ret = seq_open(file, &format2_seq_ops); ++ else if (file->f_op == &format3_fops) ++ ret = seq_open(file, &format3_seq_ops); + +- ret = seq_open(file, &all_seq_ops); + if (ret) + return ret; + + seq = file->private_data; +- seq->private = inode->i_private; +- ++ seq->private = inode->i_private; /* the dlm_ls */ + return 0; + } + +-static const struct file_operations all_fops = { ++static const struct file_operations format1_fops = { ++ .owner = THIS_MODULE, ++ .open = table_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release ++}; ++ ++static const struct file_operations format2_fops = { ++ .owner = THIS_MODULE, ++ .open = table_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release ++}; ++ ++static const struct file_operations format3_fops = { + .owner = THIS_MODULE, +- .open = all_open, ++ .open = table_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +@@ -689,7 +667,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) + S_IFREG | S_IRUGO, + dlm_root, + ls, +- &rsb_fops); ++ &format1_fops); + if (!ls->ls_debug_rsb_dentry) + goto fail; + +@@ -702,7 +680,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) + S_IFREG | S_IRUGO, + dlm_root, + ls, +- &locks_fops); ++ &format2_fops); + if (!ls->ls_debug_locks_dentry) + goto fail; + +@@ -715,7 +693,7 @@ int dlm_create_debug_file(struct dlm_ls *ls) + S_IFREG | S_IRUGO, + dlm_root, + ls, +- &all_fops); ++ &format3_fops); + if (!ls->ls_debug_all_dentry) + goto fail; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-up-memory-allocation-flags.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-up-memory-allocation-flags.patch new file mode 100644 index 000000000..5fb84c074 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fix-up-memory-allocation-flags.patch @@ -0,0 +1,72 @@ +From: Steven Whitehouse +commit d6d7b702a3a1ca50f7ca2bebaa79c80425156bac +Author: Steven Whitehouse +Date: Wed Nov 12 16:49:48 2008 -0600 +Subject: dlm: fix up memory allocation flags + + Use ls_allocation for memory allocations, which a cluster fs sets to + GFP_NOFS. Use GFP_NOFS for allocations when no lockspace struct is + available. Taking dlm locks needs to avoid calling back into the + cluster fs because write-out can require taking dlm locks. + +Cc: Christine Caulfield +Signed-off-by: Steven Whitehouse +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 3962262..1e72031 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -295,6 +295,7 @@ static int add_sock(struct socket *sock, struct connection *con) + con->sock->sk->sk_write_space = lowcomms_write_space; + con->sock->sk->sk_state_change = lowcomms_state_change; + con->sock->sk->sk_user_data = con; ++ con->sock->sk->sk_allocation = GFP_NOFS; + return 0; + } + +diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c +index 54c14c6..c1775b8 100644 +--- a/fs/dlm/memory.c ++++ b/fs/dlm/memory.c +@@ -39,7 +39,7 @@ char *dlm_allocate_lvb(struct dlm_ls *ls) + { + char *p; + +- p = kzalloc(ls->ls_lvblen, GFP_KERNEL); ++ p = kzalloc(ls->ls_lvblen, ls->ls_allocation); + return p; + } + +@@ -57,7 +57,7 @@ struct dlm_rsb *dlm_allocate_rsb(struct dlm_ls *ls, int namelen) + + DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,); + +- r = kzalloc(sizeof(*r) + namelen, GFP_KERNEL); ++ r = kzalloc(sizeof(*r) + namelen, ls->ls_allocation); + return r; + } + +@@ -72,7 +72,7 @@ struct dlm_lkb *dlm_allocate_lkb(struct dlm_ls *ls) + { + struct dlm_lkb *lkb; + +- lkb = kmem_cache_zalloc(lkb_cache, GFP_KERNEL); ++ lkb = kmem_cache_zalloc(lkb_cache, ls->ls_allocation); + return lkb; + } + +diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c +index 07ac709..f3396c6 100644 +--- a/fs/dlm/midcomms.c ++++ b/fs/dlm/midcomms.c +@@ -112,7 +112,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, + ordinary messages). */ + + if (msglen > sizeof(__tmp) && p == &__tmp.p) { +- p = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL); ++ p = kmalloc(dlm_config.ci_buffer_size, GFP_NOFS); + if (p == NULL) + return ret; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-fsdlm-ast.c-fix-warning.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-fsdlm-ast.c-fix-warning.patch new file mode 100644 index 000000000..b91e2359b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-fsdlm-ast.c-fix-warning.patch @@ -0,0 +1,75 @@ +From: Andrew Morton +commit 722d74219ea21223c74e5e894b0afcc5e4ca75a7 +Author: Andrew Morton +Date: Tue Dec 23 10:22:56 2008 -0600 +Subject: dlm: fs/dlm/ast.c: fix warning + + fs/dlm/ast.c: In function 'dlm_astd': + fs/dlm/ast.c:64: warning: 'bastmode' may be used uninitialized in this function + + Cleans code up. + +Signed-off-by: Andrew Morton +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c +index fbe840d..dc2ad60 100644 +--- a/fs/dlm/ast.c ++++ b/fs/dlm/ast.c +@@ -61,30 +61,23 @@ static void process_asts(void) + struct dlm_lkb *lkb; + void (*cast) (void *astparam); + void (*bast) (void *astparam, int mode); +- int type = 0, found, bastmode; +- +- for (;;) { +- found = 0; +- spin_lock(&ast_queue_lock); +- list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { +- r = lkb->lkb_resource; +- ls = r->res_ls; +- +- if (dlm_locking_stopped(ls)) +- continue; +- +- list_del(&lkb->lkb_astqueue); +- type = lkb->lkb_ast_type; +- lkb->lkb_ast_type = 0; +- bastmode = lkb->lkb_bastmode; +- found = 1; +- break; +- } +- spin_unlock(&ast_queue_lock); ++ int type = 0, bastmode; ++ ++repeat: ++ spin_lock(&ast_queue_lock); ++ list_for_each_entry(lkb, &ast_queue, lkb_astqueue) { ++ r = lkb->lkb_resource; ++ ls = r->res_ls; + +- if (!found) +- break; ++ if (dlm_locking_stopped(ls)) ++ continue; + ++ list_del(&lkb->lkb_astqueue); ++ type = lkb->lkb_ast_type; ++ lkb->lkb_ast_type = 0; ++ bastmode = lkb->lkb_bastmode; ++ ++ spin_unlock(&ast_queue_lock); + cast = lkb->lkb_astfn; + bast = lkb->lkb_bastfn; + +@@ -99,7 +92,9 @@ static void process_asts(void) + dlm_put_lkb(lkb); + + cond_resched(); ++ goto repeat; + } ++ spin_unlock(&ast_queue_lock); + } + + static inline int no_asts(void) diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-ignore-cancel-on-granted-lock.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-ignore-cancel-on-granted-lock.patch new file mode 100644 index 000000000..7c4d6f103 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-ignore-cancel-on-granted-lock.patch @@ -0,0 +1,30 @@ +From: David Teigland +commit a536e38125fe5da8ed49690f30c30a8f651cf1f5 +Author: David Teigland +Date: Fri Feb 27 15:23:28 2009 -0600 +Subject: dlm: ignore cancel on granted lock + + Return immediately from dlm_unlock(CANCEL) if the lock is + granted and not being converted; there's nothing to cancel. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 8cb9204..205ec95 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -2186,6 +2186,13 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args) + goto out; + } + ++ /* there's nothing to cancel */ ++ if (lkb->lkb_status == DLM_LKSTS_GRANTED && ++ !lkb->lkb_wait_type) { ++ rv = -EBUSY; ++ goto out; ++ } ++ + switch (lkb->lkb_wait_type) { + case DLM_MSG_LOOKUP: + case DLM_MSG_REQUEST: diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-improve-how-bast-mode-handling.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-improve-how-bast-mode-handling.patch new file mode 100644 index 000000000..4c74528a4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-improve-how-bast-mode-handling.patch @@ -0,0 +1,166 @@ +From: David Teigland +commit fd22a51bcc0b7b76fc729b02316214fd979f9fe1 +Author: David Teigland +Date: Tue Dec 9 11:55:46 2008 -0600 +Subject: dlm: improve how bast mode handling + + The lkb bastmode value is set in the context of processing the + lock, and read by the dlm_astd thread. Because it's accessed + in these two separate contexts, the writing/reading ought to + be done under a lock. This is simple to do by setting it and + reading it when the lkb is added to and removed from dlm_astd's + callback list which is properly locked. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c +index 09b167d..fbe840d 100644 +--- a/fs/dlm/ast.c ++++ b/fs/dlm/ast.c +@@ -2,7 +2,7 @@ + ******************************************************************************* + ** + ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -33,10 +33,10 @@ void dlm_del_ast(struct dlm_lkb *lkb) + spin_unlock(&ast_queue_lock); + } + +-void dlm_add_ast(struct dlm_lkb *lkb, int type) ++void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode) + { + if (lkb->lkb_flags & DLM_IFL_USER) { +- dlm_user_add_ast(lkb, type); ++ dlm_user_add_ast(lkb, type, bastmode); + return; + } + +@@ -46,6 +46,8 @@ void dlm_add_ast(struct dlm_lkb *lkb, int type) + list_add_tail(&lkb->lkb_astqueue, &ast_queue); + } + lkb->lkb_ast_type |= type; ++ if (bastmode) ++ lkb->lkb_bastmode = bastmode; + spin_unlock(&ast_queue_lock); + + set_bit(WAKE_ASTS, &astd_wakeflags); +@@ -59,7 +61,7 @@ static void process_asts(void) + struct dlm_lkb *lkb; + void (*cast) (void *astparam); + void (*bast) (void *astparam, int mode); +- int type = 0, found, bmode; ++ int type = 0, found, bastmode; + + for (;;) { + found = 0; +@@ -74,6 +76,7 @@ static void process_asts(void) + list_del(&lkb->lkb_astqueue); + type = lkb->lkb_ast_type; + lkb->lkb_ast_type = 0; ++ bastmode = lkb->lkb_bastmode; + found = 1; + break; + } +@@ -84,13 +87,12 @@ static void process_asts(void) + + cast = lkb->lkb_astfn; + bast = lkb->lkb_bastfn; +- bmode = lkb->lkb_bastmode; + + if ((type & AST_COMP) && cast) + cast(lkb->lkb_astparam); + + if ((type & AST_BAST) && bast) +- bast(lkb->lkb_astparam, bmode); ++ bast(lkb->lkb_astparam, bastmode); + + /* this removes the reference added by dlm_add_ast + and may result in the lkb being freed */ +diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h +index 6ee276c..1b5fc5f 100644 +--- a/fs/dlm/ast.h ++++ b/fs/dlm/ast.h +@@ -1,7 +1,7 @@ + /****************************************************************************** + ******************************************************************************* + ** +-** Copyright (C) 2005 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -13,7 +13,7 @@ + #ifndef __ASTD_DOT_H__ + #define __ASTD_DOT_H__ + +-void dlm_add_ast(struct dlm_lkb *lkb, int type); ++void dlm_add_ast(struct dlm_lkb *lkb, int type, int bastmode); + void dlm_del_ast(struct dlm_lkb *lkb); + + void dlm_astd_wake(void); +diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c +index 724ddac..7b758da 100644 +--- a/fs/dlm/lock.c ++++ b/fs/dlm/lock.c +@@ -307,7 +307,7 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv) + lkb->lkb_lksb->sb_status = rv; + lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags; + +- dlm_add_ast(lkb, AST_COMP); ++ dlm_add_ast(lkb, AST_COMP, 0); + } + + static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb) +@@ -320,10 +320,8 @@ static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode) + { + if (is_master_copy(lkb)) + send_bast(r, lkb, rqmode); +- else { +- lkb->lkb_bastmode = rqmode; +- dlm_add_ast(lkb, AST_BAST); +- } ++ else ++ dlm_add_ast(lkb, AST_BAST, rqmode); + } + + /* +diff --git a/fs/dlm/user.c b/fs/dlm/user.c +index b3832c6..065149e 100644 +--- a/fs/dlm/user.c ++++ b/fs/dlm/user.c +@@ -175,7 +175,7 @@ static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type) + /* we could possibly check if the cancel of an orphan has resulted in the lkb + being removed and then remove that lkb from the orphans list and free it */ + +-void dlm_user_add_ast(struct dlm_lkb *lkb, int type) ++void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode) + { + struct dlm_ls *ls; + struct dlm_user_args *ua; +@@ -208,6 +208,8 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) + + ast_type = lkb->lkb_ast_type; + lkb->lkb_ast_type |= type; ++ if (bastmode) ++ lkb->lkb_bastmode = bastmode; + + if (!ast_type) { + kref_get(&lkb->lkb_ref); +diff --git a/fs/dlm/user.h b/fs/dlm/user.h +index 35eb6a1..1c96864 100644 +--- a/fs/dlm/user.h ++++ b/fs/dlm/user.h +@@ -9,7 +9,7 @@ + #ifndef __USER_DOT_H__ + #define __USER_DOT_H__ + +-void dlm_user_add_ast(struct dlm_lkb *lkb, int type); ++void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode); + int dlm_user_init(void); + void dlm_user_exit(void); + int dlm_device_deregister(struct dlm_ls *ls); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-bkl.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-bkl.patch new file mode 100644 index 000000000..3ae7bbd3d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-bkl.patch @@ -0,0 +1,58 @@ +From: David Teigland +commit f9f2ed486256f3480e4d499ffd6bf730bc5e6fc6 +Author: David Teigland +Date: Thu Sep 4 12:51:20 2008 -0500 +Subject: dlm: remove bkl + + BLK from recent pushdown is not needed. + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/user.c b/fs/dlm/user.c +index 81627b5..b3832c6 100644 +--- a/fs/dlm/user.c ++++ b/fs/dlm/user.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -637,17 +636,13 @@ static int device_open(struct inode *inode, struct file *file) + struct dlm_user_proc *proc; + struct dlm_ls *ls; + +- lock_kernel(); + ls = dlm_find_lockspace_device(iminor(inode)); +- if (!ls) { +- unlock_kernel(); ++ if (!ls) + return -ENOENT; +- } + + proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL); + if (!proc) { + dlm_put_lockspace(ls); +- unlock_kernel(); + return -ENOMEM; + } + +@@ -659,7 +654,6 @@ static int device_open(struct inode *inode, struct file *file) + spin_lock_init(&proc->locks_spin); + init_waitqueue_head(&proc->wait); + file->private_data = proc; +- unlock_kernel(); + + return 0; + } +@@ -914,7 +908,6 @@ int dlm_user_daemon_available(void) + + static int ctl_device_open(struct inode *inode, struct file *file) + { +- cycle_kernel_lock(); + file->private_data = NULL; + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-extra-blocking-callback-check.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-extra-blocking-callback-check.patch new file mode 100644 index 000000000..0ddc504df --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-extra-blocking-callback-check.patch @@ -0,0 +1,41 @@ +From: David Teigland +commit 03339696314fffb95dafb349b84243358e945ce6 +Author: David Teigland +Date: Mon Dec 8 17:14:10 2008 -0600 +Subject: dlm: remove extra blocking callback check + + Just before delivering a blocking callback (bast), the dlm_astd + thread checks again that the granted mode of the lkb actually + blocks the mode requested by the bast. The idea behind this was + originally that the granted mode may have changed since the bast + was queued, making the callback now unnecessary. Reasons for + removing this extra check are: + - dlm_astd doesn't lock the rsb before reading the lkb grmode, so + it's not technically safe (this removes the long standing FIXME) + - after running some tests, it doesn't appear the check ever actually + eliminates a bast + - delivering an unnecessary blocking callback isn't a bad thing and + can happen anyway + +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c +index 30c11f3..09b167d 100644 +--- a/fs/dlm/ast.c ++++ b/fs/dlm/ast.c +@@ -89,13 +89,8 @@ static void process_asts(void) + if ((type & AST_COMP) && cast) + cast(lkb->lkb_astparam); + +- /* FIXME: Is it safe to look at lkb_grmode here +- without doing a lock_rsb() ? +- Look at other checks in v1 to avoid basts. */ +- + if ((type & AST_BAST) && bast) +- if (!dlm_modes_compat(lkb->lkb_grmode, bmode)) +- bast(lkb->lkb_astparam, bmode); ++ bast(lkb->lkb_astparam, bmode); + + /* this removes the reference added by dlm_add_ast + and may result in the lkb being freed */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-kmap-and-kunmap.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-kmap-and-kunmap.patch new file mode 100644 index 000000000..c11c99a73 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-remove-kmap-and-kunmap.patch @@ -0,0 +1,66 @@ +From: Steven Whitehouse +commit 1521848cbb42935a52d11305c054b14461ad061c +Author: Steven Whitehouse +Date: Wed Nov 12 17:00:16 2008 -0600 +Subject: dlm: remove kmap/kunmap + + The pages used in lowcomms are not highmem, so kmap is not necessary. + +Cc: Christine Caulfield +Signed-off-by: Steven Whitehouse +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 1e72031..103a5eb 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -824,7 +824,6 @@ static void sctp_init_assoc(struct connection *con) + len = e->len; + offset = e->offset; + spin_unlock(&con->writequeue_lock); +- kmap(e->page); + + /* Send the first block off the write queue */ + iov[0].iov_base = page_address(e->page)+offset; +@@ -855,7 +854,6 @@ static void sctp_init_assoc(struct connection *con) + + if (e->len == 0 && e->users == 0) { + list_del(&e->list); +- kunmap(e->page); + free_entry(e); + } + spin_unlock(&con->writequeue_lock); +@@ -1204,8 +1202,6 @@ void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc) + + if (e) { + got_one: +- if (users == 0) +- kmap(e->page); + *ppc = page_address(e->page) + offset; + return e; + } +@@ -1234,7 +1230,6 @@ void dlm_lowcomms_commit_buffer(void *mh) + if (users) + goto out; + e->len = e->end - e->offset; +- kunmap(e->page); + spin_unlock(&con->writequeue_lock); + + if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) { +@@ -1273,7 +1268,6 @@ static void send_to_sock(struct connection *con) + offset = e->offset; + BUG_ON(len == 0 && e->users == 0); + spin_unlock(&con->writequeue_lock); +- kmap(e->page); + + ret = 0; + if (len) { +@@ -1295,7 +1289,6 @@ static void send_to_sock(struct connection *con) + + if (e->len == 0 && e->users == 0) { + list_del(&e->list); +- kunmap(e->page); + free_entry(e); + continue; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-replace-idr-with-hash-table-for-connections.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-replace-idr-with-hash-table-for-connections.patch new file mode 100644 index 000000000..961f25df1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-replace-idr-with-hash-table-for-connections.patch @@ -0,0 +1,326 @@ +From: Christine Caulfield +commit 5e9ccc372dc855900c4a75b21286038938e288c7 +Author: Christine Caulfield +Date: Wed Jan 28 12:57:40 2009 -0600 +Subject: dlm: replace idr with hash table for connections + + Integer nodeids can be too large for the idr code; use a hash + table instead. + +Signed-off-by: Christine Caulfield +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 982314c..609108a 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -2,7 +2,7 @@ + ******************************************************************************* + ** + ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +-** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ++** Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. + ** + ** This copyrighted material is made available to anyone wishing to use, + ** modify, copy, or redistribute it subject to the terms and conditions +@@ -48,7 +48,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -61,6 +60,7 @@ + #include "config.h" + + #define NEEDED_RMEM (4*1024*1024) ++#define CONN_HASH_SIZE 32 + + struct cbuf { + unsigned int base; +@@ -115,6 +115,7 @@ struct connection { + int retries; + #define MAX_CONNECT_RETRIES 3 + int sctp_assoc; ++ struct hlist_node list; + struct connection *othercon; + struct work_struct rwork; /* Receive workqueue */ + struct work_struct swork; /* Send workqueue */ +@@ -139,14 +140,37 @@ static int dlm_local_count; + static struct workqueue_struct *recv_workqueue; + static struct workqueue_struct *send_workqueue; + +-static DEFINE_IDR(connections_idr); ++static struct hlist_head connection_hash[CONN_HASH_SIZE]; + static DEFINE_MUTEX(connections_lock); +-static int max_nodeid; + static struct kmem_cache *con_cache; + + static void process_recv_sockets(struct work_struct *work); + static void process_send_sockets(struct work_struct *work); + ++ ++/* This is deliberately very simple because most clusters have simple ++ sequential nodeids, so we should be able to go straight to a connection ++ struct in the array */ ++static inline int nodeid_hash(int nodeid) ++{ ++ return nodeid & (CONN_HASH_SIZE-1); ++} ++ ++static struct connection *__find_con(int nodeid) ++{ ++ int r; ++ struct hlist_node *h; ++ struct connection *con; ++ ++ r = nodeid_hash(nodeid); ++ ++ hlist_for_each_entry(con, h, &connection_hash[r], list) { ++ if (con->nodeid == nodeid) ++ return con; ++ } ++ return NULL; ++} ++ + /* + * If 'allocation' is zero then we don't attempt to create a new + * connection structure for this node. +@@ -155,31 +179,17 @@ static struct connection *__nodeid2con(int nodeid, gfp_t alloc) + { + struct connection *con = NULL; + int r; +- int n; + +- con = idr_find(&connections_idr, nodeid); ++ con = __find_con(nodeid); + if (con || !alloc) + return con; + +- r = idr_pre_get(&connections_idr, alloc); +- if (!r) +- return NULL; +- + con = kmem_cache_zalloc(con_cache, alloc); + if (!con) + return NULL; + +- r = idr_get_new_above(&connections_idr, con, nodeid, &n); +- if (r) { +- kmem_cache_free(con_cache, con); +- return NULL; +- } +- +- if (n != nodeid) { +- idr_remove(&connections_idr, n); +- kmem_cache_free(con_cache, con); +- return NULL; +- } ++ r = nodeid_hash(nodeid); ++ hlist_add_head(&con->list, &connection_hash[r]); + + con->nodeid = nodeid; + mutex_init(&con->sock_mutex); +@@ -190,19 +200,30 @@ static struct connection *__nodeid2con(int nodeid, gfp_t alloc) + + /* Setup action pointers for child sockets */ + if (con->nodeid) { +- struct connection *zerocon = idr_find(&connections_idr, 0); ++ struct connection *zerocon = __find_con(0); + + con->connect_action = zerocon->connect_action; + if (!con->rx_action) + con->rx_action = zerocon->rx_action; + } + +- if (nodeid > max_nodeid) +- max_nodeid = nodeid; +- + return con; + } + ++/* Loop round all connections */ ++static void foreach_conn(void (*conn_func)(struct connection *c)) ++{ ++ int i; ++ struct hlist_node *h, *n; ++ struct connection *con; ++ ++ for (i = 0; i < CONN_HASH_SIZE; i++) { ++ hlist_for_each_entry_safe(con, h, n, &connection_hash[i], list){ ++ conn_func(con); ++ } ++ } ++} ++ + static struct connection *nodeid2con(int nodeid, gfp_t allocation) + { + struct connection *con; +@@ -218,14 +239,17 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation) + static struct connection *assoc2con(int assoc_id) + { + int i; ++ struct hlist_node *h; + struct connection *con; + + mutex_lock(&connections_lock); +- for (i=0; i<=max_nodeid; i++) { +- con = __nodeid2con(i, 0); +- if (con && con->sctp_assoc == assoc_id) { +- mutex_unlock(&connections_lock); +- return con; ++ ++ for (i = 0 ; i < CONN_HASH_SIZE; i++) { ++ hlist_for_each_entry(con, h, &connection_hash[i], list) { ++ if (con && con->sctp_assoc == assoc_id) { ++ mutex_unlock(&connections_lock); ++ return con; ++ } + } + } + mutex_unlock(&connections_lock); +@@ -376,25 +400,23 @@ static void sctp_send_shutdown(sctp_assoc_t associd) + log_print("send EOF to node failed: %d", ret); + } + ++static void sctp_init_failed_foreach(struct connection *con) ++{ ++ con->sctp_assoc = 0; ++ if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { ++ if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) ++ queue_work(send_workqueue, &con->swork); ++ } ++} ++ + /* INIT failed but we don't know which node... + restart INIT on all pending nodes */ + static void sctp_init_failed(void) + { +- int i; +- struct connection *con; +- + mutex_lock(&connections_lock); +- for (i=1; i<=max_nodeid; i++) { +- con = __nodeid2con(i, 0); +- if (!con) +- continue; +- con->sctp_assoc = 0; +- if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { +- if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) { +- queue_work(send_workqueue, &con->swork); +- } +- } +- } ++ ++ foreach_conn(sctp_init_failed_foreach); ++ + mutex_unlock(&connections_lock); + } + +@@ -1313,13 +1335,10 @@ out_connect: + + static void clean_one_writequeue(struct connection *con) + { +- struct list_head *list; +- struct list_head *temp; ++ struct writequeue_entry *e, *safe; + + spin_lock(&con->writequeue_lock); +- list_for_each_safe(list, temp, &con->writequeue) { +- struct writequeue_entry *e = +- list_entry(list, struct writequeue_entry, list); ++ list_for_each_entry_safe(e, safe, &con->writequeue, list) { + list_del(&e->list); + free_entry(e); + } +@@ -1369,14 +1388,7 @@ static void process_send_sockets(struct work_struct *work) + /* Discard all entries on the write queues */ + static void clean_writequeues(void) + { +- int nodeid; +- +- for (nodeid = 1; nodeid <= max_nodeid; nodeid++) { +- struct connection *con = __nodeid2con(nodeid, 0); +- +- if (con) +- clean_one_writequeue(con); +- } ++ foreach_conn(clean_one_writequeue); + } + + static void work_stop(void) +@@ -1406,23 +1418,29 @@ static int work_start(void) + return 0; + } + +-void dlm_lowcomms_stop(void) ++static void stop_conn(struct connection *con) + { +- int i; +- struct connection *con; ++ con->flags |= 0x0F; ++ if (con->sock) ++ con->sock->sk->sk_user_data = NULL; ++} + ++static void free_conn(struct connection *con) ++{ ++ close_connection(con, true); ++ if (con->othercon) ++ kmem_cache_free(con_cache, con->othercon); ++ hlist_del(&con->list); ++ kmem_cache_free(con_cache, con); ++} ++ ++void dlm_lowcomms_stop(void) ++{ + /* Set all the flags to prevent any + socket activity. + */ + mutex_lock(&connections_lock); +- for (i = 0; i <= max_nodeid; i++) { +- con = __nodeid2con(i, 0); +- if (con) { +- con->flags |= 0x0F; +- if (con->sock) +- con->sock->sk->sk_user_data = NULL; +- } +- } ++ foreach_conn(stop_conn); + mutex_unlock(&connections_lock); + + work_stop(); +@@ -1430,25 +1448,20 @@ void dlm_lowcomms_stop(void) + mutex_lock(&connections_lock); + clean_writequeues(); + +- for (i = 0; i <= max_nodeid; i++) { +- con = __nodeid2con(i, 0); +- if (con) { +- close_connection(con, true); +- if (con->othercon) +- kmem_cache_free(con_cache, con->othercon); +- kmem_cache_free(con_cache, con); +- } +- } +- max_nodeid = 0; ++ foreach_conn(free_conn); ++ + mutex_unlock(&connections_lock); + kmem_cache_destroy(con_cache); +- idr_init(&connections_idr); + } + + int dlm_lowcomms_start(void) + { + int error = -EINVAL; + struct connection *con; ++ int i; ++ ++ for (i = 0; i < CONN_HASH_SIZE; i++) ++ INIT_HLIST_HEAD(&connection_hash[i]); + + init_local(); + if (!dlm_local_count) { diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-replace-schedule-with-cond_resched.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-replace-schedule-with-cond_resched.patch new file mode 100644 index 000000000..e8ef6b249 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-replace-schedule-with-cond_resched.patch @@ -0,0 +1,30 @@ +From: Steven Whitehouse +commit d61e9aac96317a43c192f1faabfa95d4d675b7ce +Author: Steven Whitehouse +Date: Wed Dec 10 09:31:02 2008 -0600 +Subject: dlm: replace schedule with cond_resched + + This is a one-liner to use cond_resched() rather than schedule() + in the ast delivery loop. It should not be necessary to schedule + every time, so this will save some cpu time while continuing to + allow scheduling when required. + +Signed-off-by: Steven Whitehouse +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +--- + fs/dlm/ast.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/dlm/ast.c ++++ b/fs/dlm/ast.c +@@ -98,7 +98,7 @@ static void process_asts(void) + and may result in the lkb being freed */ + dlm_put_lkb(lkb); + +- schedule(); ++ cond_resched(); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-trivial-annotation-of-be16-value.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-trivial-annotation-of-be16-value.patch new file mode 100644 index 000000000..01c65a8db --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-trivial-annotation-of-be16-value.patch @@ -0,0 +1,61 @@ +From: Harvey Harrison +commit cd8e4679bdcf9b54564f2cda2389bd0f0457e12d +Author: Harvey Harrison +Date: Wed Nov 12 16:28:43 2008 -0600 +Subject: dlm: trivial annotation of be16 value + + fs/dlm/dir.c:419:14: warning: incorrect type in assignment (different base types) + fs/dlm/dir.c:419:14: expected unsigned short [unsigned] [addressable] [assigned] [usertype] be_namelen + fs/dlm/dir.c:419:14: got restricted __be16 [usertype] + +Signed-off-by: Harvey Harrison +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c +index 85defeb..92969f8 100644 +--- a/fs/dlm/dir.c ++++ b/fs/dlm/dir.c +@@ -374,7 +374,7 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, + struct list_head *list; + struct dlm_rsb *r; + int offset = 0, dir_nodeid; +- uint16_t be_namelen; ++ __be16 be_namelen; + + down_read(&ls->ls_root_sem); + +@@ -410,15 +410,15 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, + + if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) { + /* Write end-of-block record */ +- be_namelen = 0; +- memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); +- offset += sizeof(uint16_t); ++ be_namelen = cpu_to_be16(0); ++ memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); ++ offset += sizeof(__be16); + goto out; + } + + be_namelen = cpu_to_be16(r->res_length); +- memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); +- offset += sizeof(uint16_t); ++ memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); ++ offset += sizeof(__be16); + memcpy(outbuf + offset, r->res_name, r->res_length); + offset += r->res_length; + } +@@ -430,9 +430,9 @@ void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, + + if ((list == &ls->ls_root_list) && + (offset + sizeof(uint16_t) <= outlen)) { +- be_namelen = 0xFFFF; +- memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); +- offset += sizeof(uint16_t); ++ be_namelen = cpu_to_be16(0xFFFF); ++ memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); ++ offset += sizeof(__be16); + } + + out: diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm-use-ipv6_addr_copy.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm-use-ipv6_addr_copy.patch new file mode 100644 index 000000000..05df8a98d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm-use-ipv6_addr_copy.patch @@ -0,0 +1,32 @@ +From: Joe Perches +commit 44ad532b3277f0cae55bfe0625d3140cf73af450 +Author: Joe Perches +Date: Thu Jan 22 13:24:49 2009 -0800 +Subject: dlm: use ipv6_addr_copy + +Signed-off-by: Joe Perches +Signed-off-by: David Teigland +Signed-off-by: Coly Li + +diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c +index 103a5eb..bf09262 100644 +--- a/fs/dlm/lowcomms.c ++++ b/fs/dlm/lowcomms.c +@@ -53,6 +53,7 @@ + #include + #include + #include ++#include + + #include "dlm_internal.h" + #include "lowcomms.h" +@@ -250,8 +251,7 @@ static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr) + } else { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr; + struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr; +- memcpy(&ret6->sin6_addr, &in6->sin6_addr, +- sizeof(in6->sin6_addr)); ++ ipv6_addr_copy(&ret6->sin6_addr, &in6->sin6_addr); + } + + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dlm_lock_data-make-most-exported-headers-use-strict-integer-types.patch b/src/patches/suse-2.6.27.31/patches.suse/dlm_lock_data-make-most-exported-headers-use-strict-integer-types.patch new file mode 100644 index 000000000..bb65d225b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dlm_lock_data-make-most-exported-headers-use-strict-integer-types.patch @@ -0,0 +1,65 @@ +From: Coly Li +Author: Arnd Bergmann +Date: Thu Feb 26 00:51:40 2009 +0100 +Subject: make most exported headers use strict integer types + + This takes care of all files that have only a small number + of non-strict integer type uses. + + Signed-off-by: Arnd Bergmann + Cc: Mauro Carvalho Chehab + Cc: David Airlie + Cc: Arnaldo Carvalho de Melo + Cc: YOSHIFUJI Hideaki + Cc: netdev@vger.kernel.org + Cc: linux-ppp@vger.kernel.org + Cc: Jaroslav Kysela + Cc: Takashi Iwai + Cc: David Woodhouse + Signed-off-by: H. Peter Anvin + Signed-off-by: Ingo Molnar + + This patch is part of commit 9adfbfb611307060db54691bc7e6d53fdc12312b. + The original patch touches too many files which are unnecessary for dlm + fix, therefore I only the dlm related part. + + Signed-off-by: Coly Li + +diff --git a/include/linux/dlm_netlink.h b/include/linux/dlm_netlink.h +index 1927633..647c8ef 100644 +--- a/include/linux/dlm_netlink.h ++++ b/include/linux/dlm_netlink.h +@@ -9,6 +9,8 @@ + #ifndef _DLM_NETLINK_H + #define _DLM_NETLINK_H + ++#include ++ + enum { + DLM_STATUS_WAITING = 1, + DLM_STATUS_GRANTED = 2, +@@ -18,16 +20,16 @@ enum { + #define DLM_LOCK_DATA_VERSION 1 + + struct dlm_lock_data { +- uint16_t version; +- uint32_t lockspace_id; ++ __u16 version; ++ __u32 lockspace_id; + int nodeid; + int ownpid; +- uint32_t id; +- uint32_t remid; +- uint64_t xid; +- int8_t status; +- int8_t grmode; +- int8_t rqmode; ++ __u32 id; ++ __u32 remid; ++ __u64 xid; ++ __s8 status; ++ __s8 grmode; ++ __s8 rqmode; + unsigned long timestamp; + int resource_namelen; + char resource_name[DLM_RESNAME_MAXLEN]; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-barrier-single-device b/src/patches/suse-2.6.27.31/patches.suse/dm-barrier-single-device new file mode 100644 index 000000000..0202e6fad --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-barrier-single-device @@ -0,0 +1,143 @@ +From: Andi Kleen +Subject: Implement barrier support for single device DM devices +Patch-mainline: 2.6.28 +References: FATE#304489 + +This patch implements barrier support in DM for the common case of dm linear +just remapping a single underlying device. In this case we can safely +pass the barrier through because there can be no reordering between +devices. + +Signed-off-by: Andi Kleen + +This patch is slightly different from the one which made it to the mainline. +But this is not replaced by that as it would break kABI. The mainline +commit is ab4c1424882be9cd70b89abf2b484add355712fa + +Acked-by: Nikanth Karthikesan + +--- + drivers/md/dm-linear.c | 1 + + drivers/md/dm-table.c | 26 +++++++++++++++++++++++++- + drivers/md/dm.c | 14 ++++---------- + drivers/md/dm.h | 2 ++ + 4 files changed, 32 insertions(+), 11 deletions(-) + +Index: linux-2.6.27/drivers/md/dm.c +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm.c ++++ linux-2.6.27/drivers/md/dm.c +@@ -1149,7 +1149,11 @@ static int __split_bio(struct mapped_dev + ci.map = dm_get_table(md); + if (unlikely(!ci.map)) + return -EIO; +- ++ if (unlikely(bio_barrier(bio) && !dm_table_barrier_ok(ci.map))) { ++ bio_endio(bio, -EOPNOTSUPP); ++ dm_table_put(ci.map); ++ return 0; ++ } + ci.md = md; + ci.bio = bio; + ci.io = alloc_io(md); +@@ -1232,15 +1236,6 @@ static int _dm_request(struct request_qu + int rw = bio_data_dir(bio); + struct mapped_device *md = q->queuedata; + +- /* +- * There is no use in forwarding any barrier request since we can't +- * guarantee it is (or can be) handled by the targets correctly. +- */ +- if (unlikely(bio_barrier(bio))) { +- bio_endio(bio, -EOPNOTSUPP); +- return 0; +- } +- + down_read(&md->io_lock); + + disk_stat_inc(dm_disk(md), ios[rw]); +Index: linux-2.6.27/drivers/md/dm.h +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm.h ++++ linux-2.6.27/drivers/md/dm.h +@@ -66,6 +66,8 @@ void dm_table_unplug_all(struct dm_table + * To check the return value from dm_table_find_target(). + */ + #define dm_target_is_valid(t) ((t)->table) ++int dm_table_barrier_ok(struct dm_table *t); ++void dm_table_support_barrier(struct dm_table *t); + + /*----------------------------------------------------------------- + * A registry of target types. +Index: linux-2.6.27/drivers/md/dm-linear.c +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm-linear.c ++++ linux-2.6.27/drivers/md/dm-linear.c +@@ -52,6 +52,7 @@ static int linear_ctr(struct dm_target * + ti->error = "dm-linear: Device lookup failed"; + goto bad; + } ++ dm_table_support_barrier(ti->table); + + ti->private = lc; + return 0; +Index: linux-2.6.27/drivers/md/dm-table.c +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm-table.c ++++ linux-2.6.27/drivers/md/dm-table.c +@@ -38,6 +38,9 @@ struct dm_table { + sector_t *highs; + struct dm_target *targets; + ++ unsigned single_device : 1; ++ unsigned barrier_supported : 1; ++ + /* + * Indicates the rw permissions for the new logical + * device. This should be a combination of FMODE_READ +@@ -532,12 +535,21 @@ EXPORT_SYMBOL_GPL(dm_set_device_limits); + int dm_get_device(struct dm_target *ti, const char *path, sector_t start, + sector_t len, int mode, struct dm_dev **result) + { +- int r = __table_get_device(ti->table, ti, path, ++ struct dm_table *t = ti->table; ++ int r = __table_get_device(t, ti, path, + start, len, mode, result); + + if (!r) + dm_set_device_limits(ti, (*result)->bdev); + ++ if (!r) { ++ /* Only got single device? */ ++ if (t->devices.next->next == &t->devices) ++ t->single_device = 1; ++ else ++ t->single_device = 0; ++ } ++ + return r; + } + +@@ -1050,6 +1062,16 @@ struct mapped_device *dm_table_get_md(st + return t->md; + } + ++int dm_table_barrier_ok(struct dm_table *t) ++{ ++ return t->single_device && t->barrier_supported; ++} ++ ++void dm_table_support_barrier(struct dm_table *t) ++{ ++ t->barrier_supported = 1; ++} ++ + EXPORT_SYMBOL(dm_vcalloc); + EXPORT_SYMBOL(dm_get_device); + EXPORT_SYMBOL(dm_put_device); +@@ -1060,3 +1082,5 @@ EXPORT_SYMBOL(dm_table_get_md); + EXPORT_SYMBOL(dm_table_put); + EXPORT_SYMBOL(dm_table_get); + EXPORT_SYMBOL(dm_table_unplug_all); ++EXPORT_SYMBOL(dm_table_barrier_ok); ++EXPORT_SYMBOL(dm_table_support_barrier); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-block-integrity b/src/patches/suse-2.6.27.31/patches.suse/dm-block-integrity new file mode 100644 index 000000000..1fa112172 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-block-integrity @@ -0,0 +1,250 @@ +From: Kiyoshi Ueda +Subject: Block integrity support for DM and MD +References: FATE#304345 + +This patch adds Data integrity support to DM and MD. +It has been reworked to support request-based multipathing. + +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Cc: Martin K. Petersen +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-table.c | 37 +++++++++++++++++++++++++++++++++++++ + drivers/md/dm.c | 22 ++++++++++++++++++++++ + drivers/md/dm.h | 1 + + drivers/md/md.c | 34 ++++++++++++++++++++++++++++++++++ + fs/bio-integrity.c | 5 +++-- + fs/bio.c | 2 +- + include/linux/bio.h | 4 ++-- + 7 files changed, 100 insertions(+), 5 deletions(-) + +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -951,6 +951,43 @@ void dm_table_set_restrictions(struct dm + queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q); + } + ++void dm_table_set_integrity(struct dm_table *t, struct mapped_device *md) ++{ ++ struct list_head *devices = dm_table_get_devices(t); ++ struct dm_dev *prev, *cur; ++ ++ /* ++ * Run through all devices to ensure they have matching ++ * integrity profile ++ */ ++ cur = prev = NULL; ++ ++ list_for_each_entry(cur, devices, list) { ++ ++ if (prev && blk_integrity_compare(prev->bdev->bd_disk, ++ cur->bdev->bd_disk) < 0) { ++ printk(KERN_ERR "%s: %s %s Integrity mismatch!\n", ++ __func__, prev->bdev->bd_disk->disk_name, ++ cur->bdev->bd_disk->disk_name); ++ return; ++ } ++ prev = cur; ++ } ++ ++ /* Register dm device as being integrity capable */ ++ if (prev && bdev_get_integrity(prev->bdev)) { ++ struct gendisk *disk = dm_disk(md); ++ ++ if (blk_integrity_register(dm_disk(md), ++ bdev_get_integrity(prev->bdev))) ++ printk(KERN_ERR "%s: %s Could not register integrity!\n", ++ __func__, disk->disk_name); ++ else ++ printk(KERN_INFO "Enabling data integrity on %s\n", ++ disk->disk_name); ++ } ++} ++ + unsigned int dm_table_get_num_targets(struct dm_table *t) + { + return t->num_targets; +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1022,6 +1022,13 @@ static struct bio *split_bvec(struct bio + clone->bi_size = to_bytes(len); + clone->bi_io_vec->bv_offset = offset; + clone->bi_io_vec->bv_len = clone->bi_size; ++ clone->bi_flags |= 1 << BIO_CLONED; ++ ++ if (bio_integrity(bio)) { ++ bio_integrity_clone(clone, bio, GFP_NOIO, bs); ++ bio_integrity_trim(clone, ++ bio_sector_offset(bio, idx, offset), len); ++ } + + return clone; + } +@@ -1044,6 +1051,14 @@ static struct bio *clone_bio(struct bio + clone->bi_size = to_bytes(len); + clone->bi_flags &= ~(1 << BIO_SEG_VALID); + ++ if (bio_integrity(bio)) { ++ bio_integrity_clone(clone, bio, GFP_NOIO, bs); ++ ++ if (idx != bio->bi_idx || clone->bi_size < bio->bi_size) ++ bio_integrity_trim(clone, ++ bio_sector_offset(bio, idx, 0), len); ++ } ++ + return clone; + } + +@@ -1365,6 +1380,11 @@ static int clone_request_bios(struct req + } + + __bio_clone(clone_bio, bio); ++ if (bio_integrity(bio)) ++ if (bio_integrity_clone(clone_bio, bio, GFP_ATOMIC, ++ md->bs) < 0) ++ goto free_and_out; ++ + clone_bio->bi_destructor = dm_bio_destructor; + clone_bio->bi_end_io = end_clone_bio; + info->rq = clone; +@@ -1835,6 +1855,7 @@ static void free_dev(struct mapped_devic + mempool_destroy(md->io_pool); + if (md->bs) + bioset_free(md->bs); ++ blk_integrity_unregister(md->disk); + del_gendisk(md->disk); + free_minor(minor); + +@@ -1910,6 +1931,7 @@ static int __bind(struct mapped_device * + write_lock(&md->map_lock); + md->map = t; + dm_table_set_restrictions(t, q); ++ dm_table_set_integrity(t, md); + if (!(dm_table_get_mode(t) & FMODE_WRITE)) { + set_disk_ro(md->disk, 1); + } else { +--- a/drivers/md/dm.h ++++ b/drivers/md/dm.h +@@ -51,6 +51,7 @@ void dm_table_event_callback(struct dm_t + struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); + struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); + void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); ++void dm_table_set_integrity(struct dm_table *t, struct mapped_device *md); + struct list_head *dm_table_get_devices(struct dm_table *t); + void dm_table_presuspend_targets(struct dm_table *t); + void dm_table_postsuspend_targets(struct dm_table *t); +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -1411,6 +1411,38 @@ static int match_mddev_units(mddev_t *md + + static LIST_HEAD(pending_raid_disks); + ++static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev) ++{ ++ struct mdk_personality *pers = mddev->pers; ++ struct gendisk *disk = mddev->gendisk; ++ struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev); ++ struct blk_integrity *bi_mddev = blk_get_integrity(disk); ++ ++ /* Data integrity passthrough not supported on RAID 4, 5 and 6 */ ++ if (pers && pers->level >= 4 && pers->level <= 6) ++ return; ++ ++ /* If rdev is integrity capable, register profile for mddev */ ++ if (!bi_mddev && bi_rdev) { ++ if (blk_integrity_register(disk, bi_rdev)) ++ printk(KERN_ERR "%s: %s Could not register integrity!\n", ++ __func__, disk->disk_name); ++ else ++ printk(KERN_NOTICE "Enabling data integrity on %s\n", ++ disk->disk_name); ++ return; ++ } ++ ++ /* Check that mddev and rdev have matching profiles */ ++ if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) { ++ printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__, ++ disk->disk_name, rdev->bdev->bd_disk->disk_name); ++ printk(KERN_NOTICE "Disabling data integrity on %s\n", ++ disk->disk_name); ++ blk_integrity_unregister(disk); ++ } ++} ++ + static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) + { + char b[BDEVNAME_SIZE]; +@@ -1479,6 +1511,7 @@ static int bind_rdev_to_array(mdk_rdev_t + } + list_add_rcu(&rdev->same_set, &mddev->disks); + bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); ++ md_integrity_check(rdev, mddev); + return 0; + + fail: +@@ -3967,6 +4000,7 @@ static int do_md_stop(mddev_t * mddev, i + printk(KERN_INFO "md: %s switched to read-only mode.\n", + mdname(mddev)); + err = 0; ++ blk_integrity_unregister(disk); + md_new_event(mddev); + sysfs_notify(&mddev->kobj, NULL, "array_state"); + out: +--- a/fs/bio-integrity.c ++++ b/fs/bio-integrity.c +@@ -655,19 +655,20 @@ EXPORT_SYMBOL(bio_integrity_split); + * bio_integrity_clone - Callback for cloning bios with integrity metadata + * @bio: New bio + * @bio_src: Original bio ++ * @gfp_mask: Memory allocation mask + * @bs: bio_set to allocate bip from + * + * Description: Called to allocate a bip when cloning a bio + */ + int bio_integrity_clone(struct bio *bio, struct bio *bio_src, +- struct bio_set *bs) ++ gfp_t gfp_mask, struct bio_set *bs) + { + struct bio_integrity_payload *bip_src = bio_src->bi_integrity; + struct bio_integrity_payload *bip; + + BUG_ON(bip_src == NULL); + +- bip = bio_integrity_alloc_bioset(bio, GFP_NOIO, bip_src->bip_vcnt, bs); ++ bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs); + + if (bip == NULL) + return -EIO; +--- a/fs/bio.c ++++ b/fs/bio.c +@@ -256,7 +256,7 @@ struct bio *bio_clone(struct bio *bio, g + if (bio_integrity(bio)) { + int ret; + +- ret = bio_integrity_clone(b, bio, fs_bio_set); ++ ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set); + + if (ret < 0) + return NULL; +--- a/include/linux/bio.h ++++ b/include/linux/bio.h +@@ -501,7 +501,7 @@ extern void bio_integrity_endio(struct b + extern void bio_integrity_advance(struct bio *, unsigned int); + extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); + extern void bio_integrity_split(struct bio *, struct bio_pair *, int); +-extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *); ++extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t, struct bio_set *); + extern int bioset_integrity_create(struct bio_set *, int); + extern void bioset_integrity_free(struct bio_set *); + extern void bio_integrity_init_slab(void); +@@ -512,7 +512,7 @@ extern void bio_integrity_init_slab(void + #define bioset_integrity_create(a, b) (0) + #define bio_integrity_prep(a) (0) + #define bio_integrity_enabled(a) (0) +-#define bio_integrity_clone(a, b, c) (0) ++#define bio_integrity_clone(a, b, c, d) (0) + #define bioset_integrity_free(a) do { } while (0) + #define bio_integrity_free(a, b) do { } while (0) + #define bio_integrity_endio(a, b) do { } while (0) diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-emulate-blkrrpart-ioctl b/src/patches/suse-2.6.27.31/patches.suse/dm-emulate-blkrrpart-ioctl new file mode 100644 index 000000000..0c5e1dc89 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-emulate-blkrrpart-ioctl @@ -0,0 +1,50 @@ +From: Hannes Reinecke +Subject: Emulate BLKRRPART on device-mapper + +Partitions on device-mapper devices are managed by kpartx (if at +all). So if we were just to send out a 'change' event if someone +called BLKRRPART on these devices, kpartx will be triggered via udev +and can manage the partitions accordingly. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -333,19 +333,25 @@ static int dm_blk_ioctl(struct inode *in + if (!map || !dm_table_get_size(map)) + goto out; + +- /* We only support devices that have a single target */ +- if (dm_table_get_num_targets(map) != 1) +- goto out; +- +- tgt = dm_table_get_target(map, 0); +- + if (dm_suspended(md)) { + r = -EAGAIN; + goto out; + } + +- if (tgt->type->ioctl) +- r = tgt->type->ioctl(tgt, inode, file, cmd, arg); ++ if (cmd == BLKRRPART) { ++ /* Emulate Re-read partitions table */ ++ kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE); ++ r = 0; ++ } else { ++ /* We only support devices that have a single target */ ++ if (dm_table_get_num_targets(map) != 1) ++ goto out; ++ ++ tgt = dm_table_get_target(map, 0); ++ ++ if (tgt->type->ioctl) ++ r = tgt->type->ioctl(tgt, inode, file, cmd, arg); ++ } + + out: + dm_table_put(map); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-accept-failed-paths b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-accept-failed-paths new file mode 100644 index 000000000..e1b3a4cb9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-accept-failed-paths @@ -0,0 +1,228 @@ +From: Hannes Reinecke +Subject: Accept failed paths for multipath maps +References: bnc#458037,bnc#458393 + +The multipath kernel module is rejecting any map with an invalid +device. However, as the multipathd is processing the events serially +it will try to push a map with invalid devices if more than one +device failed at the same time. +So we can as well accept those maps and make sure to mark the +paths as down. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-mpath.c | 66 ++++++++++++++++++++++++++++++++++++++++---------- + drivers/md/dm-mpath.h | 1 + drivers/md/dm-table.c | 3 ++ + drivers/md/dm.c | 4 +++ + 4 files changed, 61 insertions(+), 13 deletions(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -141,7 +141,8 @@ static void deactivate_path(struct work_ + struct pgpath *pgpath = + container_of(work, struct pgpath, deactivate_path); + +- blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue); ++ if (pgpath->path.dev) ++ blk_abort_queue(pgpath->path.dev->bdev->bd_disk->queue); + } + + static struct priority_group *alloc_priority_group(void) +@@ -253,6 +254,11 @@ static int __choose_path_in_pg(struct mu + + m->current_pgpath = path_to_pgpath(path); + ++ if (!m->current_pgpath->path.dev) { ++ m->current_pgpath = NULL; ++ return -ENODEV; ++ } ++ + if (m->current_pg != pg) + __switch_pg(m, m->current_pgpath); + +@@ -576,6 +582,7 @@ static struct pgpath *parse_path(struct + { + int r; + struct pgpath *p; ++ char *path; + struct multipath *m = ti->private; + + /* we need at least a path arg */ +@@ -588,14 +595,37 @@ static struct pgpath *parse_path(struct + if (!p) + return NULL; + +- r = dm_get_device(ti, shift(as), ti->begin, ti->len, ++ path = shift(as); ++ r = dm_get_device(ti, path, ti->begin, ti->len, + dm_table_get_mode(ti->table), &p->path.dev); + if (r) { +- ti->error = "error getting device"; +- goto bad; ++ unsigned major, minor; ++ ++ /* Try to add a failed device */ ++ if (r == -ENXIO && sscanf(path, "%u:%u", &major, &minor) == 2) { ++ dev_t dev; ++ ++ /* Extract the major/minor numbers */ ++ dev = MKDEV(major, minor); ++ if (MAJOR(dev) != major || MINOR(dev) != minor) { ++ /* Nice try, didn't work */ ++ DMWARN("Invalid device path %s", path); ++ ti->error = "error converting devnum"; ++ goto bad; ++ } ++ DMWARN("adding disabled device %d:%d", major, minor); ++ p->path.dev = NULL; ++ format_dev_t(p->path.pdev, dev); ++ p->is_active = 0; ++ } else { ++ ti->error = "error getting device"; ++ goto bad; ++ } ++ } else { ++ memcpy(p->path.pdev, p->path.dev->name, 16); + } + +- if (m->hw_handler_name) { ++ if (m->hw_handler_name && p->path.dev) { + struct request_queue *q = bdev_get_queue(p->path.dev->bdev); + + r = scsi_dh_attach(q, m->hw_handler_name); +@@ -891,7 +921,7 @@ static int fail_path(struct pgpath *pgpa + if (!pgpath->is_active) + goto out; + +- DMWARN("Failing path %s.", pgpath->path.dev->name); ++ DMWARN("Failing path %s.", pgpath->path.pdev); + + pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path); + pgpath->is_active = 0; +@@ -903,7 +933,7 @@ static int fail_path(struct pgpath *pgpa + m->current_pgpath = NULL; + + dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti, +- pgpath->path.dev->name, m->nr_valid_paths); ++ pgpath->path.pdev, m->nr_valid_paths); + + queue_work(kmultipathd, &m->trigger_event); + queue_work(kmultipathd, &pgpath->deactivate_path); +@@ -928,6 +958,12 @@ static int reinstate_path(struct pgpath + if (pgpath->is_active) + goto out; + ++ if (!pgpath->path.dev) { ++ DMWARN("Cannot reinstate disabled path %s", pgpath->path.pdev); ++ r = -ENODEV; ++ goto out; ++ } ++ + if (!pgpath->pg->ps.type->reinstate_path) { + DMWARN("Reinstate path not supported by path selector %s", + pgpath->pg->ps.type->name); +@@ -946,7 +982,7 @@ static int reinstate_path(struct pgpath + queue_work(kmultipathd, &m->process_queued_ios); + + dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti, +- pgpath->path.dev->name, m->nr_valid_paths); ++ pgpath->path.pdev, m->nr_valid_paths); + + queue_work(kmultipathd, &m->trigger_event); + +@@ -966,6 +1002,9 @@ static int action_dev(struct multipath * + struct pgpath *pgpath; + struct priority_group *pg; + ++ if (!dev) ++ return 0; ++ + list_for_each_entry(pg, &m->priority_groups, list) { + list_for_each_entry(pgpath, &pg->pgpaths, list) { + if (pgpath->path.dev == dev) +@@ -1135,11 +1174,12 @@ static void pg_init_done(struct dm_path + + static void activate_path(struct work_struct *work) + { +- int ret; ++ int ret = SCSI_DH_DEV_OFFLINED; + struct pgpath *pgpath = + container_of(work, struct pgpath, activate_path); + +- ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev)); ++ if (pgpath->path.dev) ++ ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev)); + pg_init_done(&pgpath->path, ret); + } + +@@ -1306,7 +1346,7 @@ static int multipath_status(struct dm_ta + pg->ps.type->info_args); + + list_for_each_entry(p, &pg->pgpaths, list) { +- DMEMIT("%s %s %u ", p->path.dev->name, ++ DMEMIT("%s %s %u ", p->path.pdev, + p->is_active ? "A" : "F", + p->fail_count); + if (pg->ps.type->status) +@@ -1332,7 +1372,7 @@ static int multipath_status(struct dm_ta + pg->ps.type->table_args); + + list_for_each_entry(p, &pg->pgpaths, list) { +- DMEMIT("%s ", p->path.dev->name); ++ DMEMIT("%s ", p->path.pdev); + if (pg->ps.type->status) + sz += pg->ps.type->status(&pg->ps, + &p->path, type, result + sz, +@@ -1414,7 +1454,7 @@ static int multipath_ioctl(struct dm_tar + if (!m->current_pgpath) + __choose_pgpath(m, 1 << 19); /* Assume 512KB */ + +- if (m->current_pgpath) { ++ if (m->current_pgpath && m->current_pgpath->path.dev) { + bdev = m->current_pgpath->path.dev->bdev; + fake_dentry.d_inode = bdev->bd_inode; + fake_file.f_mode = m->current_pgpath->path.dev->mode; +--- a/drivers/md/dm-mpath.h ++++ b/drivers/md/dm-mpath.h +@@ -12,6 +12,7 @@ + struct dm_dev; + + struct dm_path { ++ char pdev[16]; /* Requested physical device */ + struct dm_dev *dev; /* Read-only */ + void *pscontext; /* For path-selector use */ + }; +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -566,6 +566,9 @@ int dm_get_device(struct dm_target *ti, + */ + void dm_put_device(struct dm_target *ti, struct dm_dev *dd) + { ++ if (!dd) ++ return; ++ + if (atomic_dec_and_test(&dd->count)) { + close_dev(dd, ti->table->md); + list_del(&dd->list); +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1503,6 +1503,9 @@ static void map_request(struct dm_target + tio->ti = ti; + atomic_inc(&md->pending); + ++#if 0 ++ /* This might trigger accidentally */ ++ + /* + * Although submitted requests to the md->queue are checked against + * the table/queue limitations at the submission time, the limitations +@@ -1525,6 +1528,7 @@ static void map_request(struct dm_target + dm_kill_request(clone, r); + return; + } ++#endif + + r = ti->type->map_rq(ti, clone, &tio->info); + switch (r) { diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-add-start-io b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-add-start-io new file mode 100644 index 000000000..aa615e37b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-add-start-io @@ -0,0 +1,45 @@ +From: Kiyoshi Ueda +Subject: dm-mpath: add a path selector interface +References: FATE#303862,FATE#302108 + +This patch adds a new hook for dm path selector: start_io. +Target drivers should call this hook before submitting I/O to +the selected path. +Path selectors can use it to start accounting of the I/O. +(e.g. counting the number of in-flight I/Os.) + +The code is based on the patch posted by Stefan Bader: +https://www.redhat.com/archives/dm-devel/2005-October/msg00050.html + + +Signed-off-by: Stefan Bader +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Signed-off-by: Hannes Reinecke + +Index: linux-2.6.27/drivers/md/dm-mpath.c +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm-mpath.c ++++ linux-2.6.27/drivers/md/dm-mpath.c +@@ -359,6 +359,9 @@ static int map_io(struct multipath *m, s + + mpio->pgpath = pgpath; + ++ if (r == DM_MAPIO_REMAPPED && pgpath->pg->ps.type->start_io) ++ pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path); ++ + spin_unlock_irqrestore(&m->lock, flags); + + return r; +Index: linux-2.6.27/drivers/md/dm-path-selector.h +=================================================================== +--- linux-2.6.27.orig/drivers/md/dm-path-selector.h ++++ linux-2.6.27/drivers/md/dm-path-selector.h +@@ -75,6 +75,7 @@ struct path_selector_type { + int (*status) (struct path_selector *ps, struct dm_path *path, + status_type_t type, char *result, unsigned int maxlen); + ++ int (*start_io) (struct path_selector *ps, struct dm_path *path); + int (*end_io) (struct path_selector *ps, struct dm_path *path); + }; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-check-info-before-access b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-check-info-before-access new file mode 100644 index 000000000..1a934bb78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-check-info-before-access @@ -0,0 +1,54 @@ +From: Hannes Reinecke +Subject: Kernel Oops during path failover +References: bnc#458393 + +I've started a new test run with 10 multipath devices and 100 +testcycles (120sec off, 120 sec on). Test failed with an "Oops": + +Jan 24 00:19:35 z9lp02 kernel: Oops: 0038 [#1] SMP +Jan 24 00:19:35 z9lp02 kernel: Modules linked in: iptable_filter ip_tables +x_tables dm_round_robin sg sd_mod crc_t10dif zfcp scsi_transport_fc scsi_tgt +dm_multipath scsi_dh scsi_mod fuse loop dm_mod qeth_l3 ipv6 qeth qdio ccwgroup +chsc_sch dasd_eckd_mod dasd_mod ext3 mbcache jbd +Jan 24 00:19:35 z9lp02 kernel: Supported: Yes +Jan 24 00:19:35 z9lp02 kernel: CPU: 3 Not tainted 2.6.27.12-2.7-default #1 +Jan 24 00:19:35 z9lp02 kernel: Process kblockd/3 (pid: 24, task: +000000007fad6638, ksp: 000000007fadbd38) +Jan 24 00:19:35 z9lp02 kernel: Krnl PSW : 0404e00180000000 0000000000192216 +(mempool_free+0x2e/0xc4) + +It looks as if we don't check the 'info' field before accessing it; it +might well be NULL if the bio couldn't be initialized. + +Signed-off-by: Hannes Reinecke + +Index: linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/dm.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c +@@ -714,13 +714,14 @@ static void free_bio_clone(struct reques + struct dm_rq_target_io *tio = clone->end_io_data; + struct mapped_device *md = tio->md; + struct bio *bio; +- struct dm_clone_bio_info *info; + + while ((bio = clone->bio) != NULL) { + clone->bio = bio->bi_next; + +- info = bio->bi_private; +- free_bio_info(md, info); ++ if (bio->bi_private) { ++ struct dm_clone_bio_info *info = bio->bi_private; ++ free_bio_info(md, info); ++ } + + bio->bi_private = md->bs; + bio_put(bio); +@@ -1483,6 +1484,7 @@ static int dm_prep_fn(struct request_que + tio->orig = rq; + tio->error = 0; + memset(&tio->info, 0, sizeof(tio->info)); ++ memset(&tio->clone, 0, sizeof(tio->clone)); + + clone = &tio->clone; + if (setup_clone(clone, rq, tio)) { diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-leastpending-path-update b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-leastpending-path-update new file mode 100644 index 000000000..2ed678159 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-leastpending-path-update @@ -0,0 +1,298 @@ +Subject: Update least-pending-IO dynamic load balancer +From: Hannes Reinecke +Date: Wed Jan 7 09:26:30 2009 +0100: +References: bnc#444199 + +Attached patch provides "Least pending IO" dynamic load balancing policy for +bio based device mapper multipath. This load balancing policy considers the +number of unserviced requests pending on a path and selects the path with least +count for pending service request. + +We find this policy more useful especially when the SAN environment has +heterogeneous components. Ex, when there is one 8GB HBA and one 2GB HBA +connected to the same server, 8GB HBA could be utilized better with this +algorithm. + +This patch includes the update as posted in the bugzilla, +based on the review comments received in the dm-devel mailing list. + +Signed-off-by: Sakshi Chaitanya Veni +Signed-off-by: Vijayakumar Balasubramanian +Signed-off-by: Senthil Kumar V +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/md/Makefile b/drivers/md/Makefile +index 42c35fb..24cfd6a 100644 +--- a/drivers/md/Makefile ++++ b/drivers/md/Makefile +@@ -32,7 +32,7 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o + obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o + obj-$(CONFIG_DM_CRYPT) += dm-crypt.o + obj-$(CONFIG_DM_DELAY) += dm-delay.o +-obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o ++obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o dm-least-pending.o + obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o + obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-regions.o dm-log.o + obj-$(CONFIG_DM_RAID45) += dm-raid45.o dm-log.o dm-memcache.o \ +diff --git a/drivers/md/dm-least-pending.c b/drivers/md/dm-least-pending.c +new file mode 100644 +index 0000000..a7aea6d +--- /dev/null ++++ b/drivers/md/dm-least-pending.c +@@ -0,0 +1,256 @@ ++/* ++ * (C) Copyright 2008 Hewlett-Packard Development Company, L.P ++ * ++ * This file is released under the GPL. ++ */ ++ ++#include "dm-path-selector.h" ++ ++#include ++ ++#define DM_MSG_PREFIX "multipath least-pending" ++ ++/*----------------------------------------------------------------- ++* Path-handling code, paths are held in lists ++*---------------------------------------------------------------*/ ++struct path_info { ++ struct list_head list; ++ struct dm_path *path; ++ unsigned repeat_count; ++ atomic_t io_count; ++}; ++ ++static void free_paths(struct list_head *paths) ++{ ++ struct path_info *pi, *next; ++ ++ list_for_each_entry_safe(pi, next, paths, list) { ++ list_del(&pi->list); ++ kfree(pi); ++ } ++} ++ ++/*----------------------------------------------------------------- ++ * Least-pending selector ++ *---------------------------------------------------------------*/ ++ ++#define LPP_MIN_IO 1 ++ ++struct selector { ++ struct list_head valid_paths; ++ struct list_head invalid_paths; ++}; ++ ++static struct selector *alloc_selector(void) ++{ ++ struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL); ++ ++ if (s) { ++ INIT_LIST_HEAD(&s->valid_paths); ++ INIT_LIST_HEAD(&s->invalid_paths); ++ } ++ ++ return s; ++} ++ ++static int lpp_create(struct path_selector *ps, unsigned argc, char **argv) ++{ ++ struct selector *s; ++ ++ s = alloc_selector(); ++ if (!s) ++ return -ENOMEM; ++ ++ ps->context = s; ++ return 0; ++} ++ ++static void lpp_destroy(struct path_selector *ps) ++{ ++ struct selector *s = ps->context; ++ ++ free_paths(&s->valid_paths); ++ free_paths(&s->invalid_paths); ++ kfree(s); ++ ps->context = NULL; ++} ++ ++static int lpp_status(struct path_selector *ps, struct dm_path *path, ++ status_type_t type, char *result, unsigned int maxlen) ++{ ++ struct path_info *pi; ++ int sz = 0; ++ ++ if (!path) ++ switch (type) { ++ case STATUSTYPE_INFO: ++ DMEMIT("1 "); ++ break; ++ case STATUSTYPE_TABLE: ++ DMEMIT("0 "); ++ break; ++ } ++ else { ++ pi = path->pscontext; ++ switch (type) { ++ case STATUSTYPE_INFO: ++ DMEMIT("%u:%u ", pi->repeat_count, ++ atomic_read(&pi->io_count)); ++ break; ++ case STATUSTYPE_TABLE: ++ break; ++ } ++ } ++ ++ return sz; ++} ++ ++/* ++ * Called during initialisation to register each path with an ++ * optional repeat_count. ++ */ ++static int lpp_add_path(struct path_selector *ps, struct dm_path *path, ++ int argc, char **argv, char **error) ++{ ++ struct selector *s = ps->context; ++ struct path_info *pi; ++ unsigned repeat_count = LPP_MIN_IO; ++ ++ if (argc > 1) { ++ *error = "least-pending ps: incorrect number of arguments"; ++ return -EINVAL; ++ } ++ ++ /* First path argument is number of I/Os before switching path */ ++ if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) { ++ *error = "least-pending ps: invalid repeat count"; ++ return -EINVAL; ++ } ++ ++ /* allocate the path */ ++ pi = kmalloc(sizeof(*pi), GFP_KERNEL); ++ if (!pi) { ++ *error = "least-pending ps: Error allocating path context"; ++ return -ENOMEM; ++ } ++ ++ pi->path = path; ++ pi->repeat_count = repeat_count; ++ atomic_set(&pi->io_count, 0); ++ ++ path->pscontext = pi; ++ ++ list_add(&pi->list, &s->valid_paths); ++ ++ return 0; ++} ++ ++static void lpp_fail_path(struct path_selector *ps, struct dm_path *p) ++{ ++ struct selector *s = ps->context; ++ struct path_info *pi = p->pscontext; ++ ++ if (!pi) ++ return; ++ ++ atomic_set(&pi->io_count, 0); ++ ++ list_move(&pi->list, &s->invalid_paths); ++} ++ ++static int lpp_reinstate_path(struct path_selector *ps, struct dm_path *p) ++{ ++ struct selector *s = ps->context; ++ struct path_info *pi = p->pscontext; ++ ++ if (!pi) ++ return 1; ++ ++ list_move(&pi->list, &s->valid_paths); ++ ++ return 0; ++} ++ ++static struct dm_path *lpp_select_path(struct path_selector *ps, ++ unsigned *repeat_count) ++{ ++ struct selector *s = ps->context; ++ struct path_info *pi, *next, *least_io_path = NULL; ++ struct list_head *paths; ++ ++ if (list_empty(&s->valid_paths)) ++ return NULL; ++ ++ paths = &s->valid_paths; ++ ++ list_for_each_entry_safe(pi, next, paths, list) { ++ if (!least_io_path || atomic_read(&least_io_path->io_count) < atomic_read(&pi->io_count)) ++ least_io_path = pi; ++ if (!atomic_read(&least_io_path->io_count)) ++ break; ++ } ++ ++ if (!least_io_path) ++ return NULL; ++ ++ atomic_inc(&least_io_path->io_count); ++ *repeat_count = pi->repeat_count; ++ ++ return least_io_path->path; ++} ++ ++static int lpp_end_io(struct path_selector *ps, struct dm_path *path) ++{ ++ struct path_info *pi = NULL; ++ ++ pi = path->pscontext; ++ if (!pi) ++ return 1; ++ ++ atomic_dec(&pi->io_count); ++ ++ return 0; ++} ++ ++static struct path_selector_type lpp_ps = { ++ .name = "least-pending", ++ .module = THIS_MODULE, ++ .table_args = 0, ++ .info_args = 1, ++ .create = lpp_create, ++ .destroy = lpp_destroy, ++ .status = lpp_status, ++ .add_path = lpp_add_path, ++ .fail_path = lpp_fail_path, ++ .reinstate_path = lpp_reinstate_path, ++ .select_path = lpp_select_path, ++ .end_io = lpp_end_io, ++}; ++ ++static int __init dm_lpp_init(void) ++{ ++ int r = dm_register_path_selector(&lpp_ps); ++ ++ if (r < 0) ++ DMERR("register failed %d", r); ++ ++ DMINFO("version 1.0.0 loaded"); ++ ++ return r; ++} ++ ++static void __exit dm_lpp_exit(void) ++{ ++ int r = dm_unregister_path_selector(&lpp_ps); ++ ++ if (r < 0) ++ DMERR("unregister failed %d", r); ++} ++ ++module_init(dm_lpp_init); ++module_exit(dm_lpp_exit); ++ ++MODULE_DESCRIPTION(DM_NAME " least-pending multipath path selector"); ++MODULE_AUTHOR("Sakshi Chaitanya Veni "); ++MODULE_LICENSE("GPL"); ++ diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-lockdep-irqsave b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-lockdep-irqsave new file mode 100644 index 000000000..b8667b72f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-lockdep-irqsave @@ -0,0 +1,95 @@ +From: Kiyoshi Ueda +Subject: dm: Fix lock dependency warning for request based dm +References: bnc#477927 + +> > From: Christof Schmitt +> > +> > Testing with request based dm multipathing and lock dependency checking +> > revealed this problem. Fix this by disabling interrupts when acquiring the +> > map_lock from the ioctl call in __bind and __unbind. +> > +> > It seems that the problem has been introduced with this patch: +> > http://lkml.indiana.edu/hypermail/linux/kernel/0810.0/1067.html + +Thank you for your testing request-based dm-multipath and the patch. + +Attached is a patch to fix it. +Since request-based dm gets map_lock after taking queue_lock with +interrupt disabled, we have to use save/restore variant. +(By the way, although lockdep warns the deadlock possibility, currently + there should be no such code path in request-based dm where request_fn + is called from the interrupt context.) + +I have done simple build and boot testings, but haven't done other +testings (e.g. stress testing) yet. +I will include this patch to the next update after such testings. + +Thanks, +Kiyoshi Ueda + +Signed-off-by: Nikanth karthikesan + +Index: linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/dm.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c +@@ -525,12 +525,13 @@ static int queue_io(struct mapped_device + struct dm_table *dm_get_table(struct mapped_device *md) + { + struct dm_table *t; ++ unsigned long flags; + +- read_lock(&md->map_lock); ++ read_lock_irqsave(&md->map_lock, flags); + t = md->map; + if (t) + dm_table_get(t); +- read_unlock(&md->map_lock); ++ read_unlock_irqrestore(&md->map_lock, flags); + + return t; + } +@@ -1913,6 +1914,7 @@ static int __bind(struct mapped_device * + { + struct request_queue *q = md->queue; + sector_t size; ++ unsigned long flags; + + size = dm_table_get_size(t); + +@@ -1942,7 +1944,7 @@ static int __bind(struct mapped_device * + if (dm_table_request_based(t) && !blk_queue_stopped(q)) + stop_queue(q); + +- write_lock(&md->map_lock); ++ write_lock_irqsave(&md->map_lock, flags); + md->map = t; + dm_table_set_restrictions(t, q); + dm_table_set_integrity(t, md); +@@ -1951,7 +1953,7 @@ static int __bind(struct mapped_device * + } else { + set_disk_ro(md->disk, 0); + } +- write_unlock(&md->map_lock); ++ write_unlock_irqrestore(&md->map_lock, flags); + + return 0; + } +@@ -1959,14 +1961,15 @@ static int __bind(struct mapped_device * + static void __unbind(struct mapped_device *md) + { + struct dm_table *map = md->map; ++ unsigned long flags; + + if (!map) + return; + + dm_table_event_callback(map, NULL, NULL); +- write_lock(&md->map_lock); ++ write_lock_irqsave(&md->map_lock, flags); + md->map = NULL; +- write_unlock(&md->map_lock); ++ write_unlock_irqrestore(&md->map_lock, flags); + dm_table_destroy(map); + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-no-activate-for-offlined-paths b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-no-activate-for-offlined-paths new file mode 100644 index 000000000..55c77ce36 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-no-activate-for-offlined-paths @@ -0,0 +1,82 @@ +From: Hannes Reinecke +Subject: DM-MPIO fails to tresspass LUNs on CLARiiON arrays +Reference: bnc#484529 + +On Clariion arrays we fail to send the trespass command correctly. +We're trying to send the trespass command to via an disabled path, +causing the device handler to loop trying to send the command on +an invalid path. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-mpath.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -462,6 +462,9 @@ static void process_queued_ios(struct wo + m->pg_init_count++; + m->pg_init_required = 0; + list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) { ++ /* Skip disabled paths */ ++ if (!tmp->path.dev) ++ continue; + queue_work(kmpath_handlerd, &tmp->activate_path); + m->pg_init_in_progress++; + } +@@ -1120,9 +1123,8 @@ static int pg_init_limit_reached(struct + return limit_reached; + } + +-static void pg_init_done(struct dm_path *path, int errors) ++static void pg_init_done(struct pgpath *pgpath, int errors) + { +- struct pgpath *pgpath = path_to_pgpath(path); + struct priority_group *pg = pgpath->pg; + struct multipath *m = pg->m; + unsigned long flags; +@@ -1136,8 +1138,8 @@ static void pg_init_done(struct dm_path + errors = 0; + break; + } +- DMERR("Cannot failover device because scsi_dh_%s was not " +- "loaded.", m->hw_handler_name); ++ DMERR("Cannot failover device %s because scsi_dh_%s was not " ++ "loaded.", pgpath->path.pdev, m->hw_handler_name); + /* + * Fail path for now, so we do not ping pong + */ +@@ -1150,6 +1152,10 @@ static void pg_init_done(struct dm_path + */ + bypass_pg(m, pg, 1); + break; ++ case SCSI_DH_DEV_OFFLINED: ++ DMWARN("Device %s offlined.", pgpath->path.pdev); ++ errors = 0; ++ break; + /* TODO: For SCSI_DH_RETRY we should wait a couple seconds */ + case SCSI_DH_RETRY: + case SCSI_DH_IMM_RETRY: +@@ -1169,7 +1175,8 @@ static void pg_init_done(struct dm_path + + spin_lock_irqsave(&m->lock, flags); + if (errors) { +- DMERR("Could not failover device. Error %d.", errors); ++ DMERR("Could not failover device %s. Error %d.", ++ pgpath->path.pdev, errors); + m->current_pgpath = NULL; + m->current_pg = NULL; + } else if (!m->pg_init_required) { +@@ -1191,7 +1198,10 @@ static void activate_path(struct work_st + + if (pgpath->path.dev) + ret = scsi_dh_activate(bdev_get_queue(pgpath->path.dev->bdev)); +- pg_init_done(&pgpath->path, ret); ++ else ++ DMWARN("Activate offlined path %s", pgpath->path.pdev); ++ ++ pg_init_done(pgpath, ret); + } + + /* diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-no-partitions-feature b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-no-partitions-feature new file mode 100644 index 000000000..0e9efcebc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-no-partitions-feature @@ -0,0 +1,66 @@ +From: Hannes Reinecke +Subject: Disable partitions scan for multipathed devices +References: bnc#402922,bnc#514767 + +When multipath devices are being used as disks for VM Guests +any partition scanning / setup should be done within the VM Guest, +not from host. So we need to switch off partitions scanning via +kpartx there. +For this I've implemented a new feature 'no_partitions' which +just serves as a notifier to kpartx to _not_ create partitions +on these devices. + +Patch ported to SLES11. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-mpath.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -55,6 +55,8 @@ struct priority_group { + struct list_head pgpaths; + }; + ++#define FEATURE_NO_PARTITIONS 1 ++ + /* Multipath context */ + struct multipath { + struct list_head list; +@@ -79,6 +81,7 @@ struct multipath { + unsigned saved_queue_if_no_path;/* Saved state during suspension */ + unsigned pg_init_retries; /* Number of times to retry pg_init */ + unsigned pg_init_count; /* Number of times pg_init called */ ++ unsigned features; /* Additional selected features */ + + struct work_struct process_queued_ios; + struct list_head queued_ios; +@@ -802,6 +805,10 @@ static int parse_features(struct arg_set + continue; + } + ++ if (!strnicmp(param_name, MESG_STR("no_partitions"))) { ++ m->features |= FEATURE_NO_PARTITIONS; ++ continue; ++ } + if (!strnicmp(param_name, MESG_STR("pg_init_retries")) && + (argc >= 1)) { + r = read_param(_params + 1, shift(as), +@@ -1321,11 +1328,14 @@ static int multipath_status(struct dm_ta + DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count); + else { + DMEMIT("%u ", m->queue_if_no_path + +- (m->pg_init_retries > 0) * 2); ++ (m->pg_init_retries > 0) * 2 + ++ (m->features & FEATURE_NO_PARTITIONS)); + if (m->queue_if_no_path) + DMEMIT("queue_if_no_path "); + if (m->pg_init_retries) + DMEMIT("pg_init_retries %u ", m->pg_init_retries); ++ if (m->features & FEATURE_NO_PARTITIONS) ++ DMEMIT("no_partitions "); + } + + if (!m->hw_handler_name || type == STATUSTYPE_INFO) diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-null-pgs b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-null-pgs new file mode 100644 index 000000000..3cece77e7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-null-pgs @@ -0,0 +1,26 @@ +From: Hannes Reinecke +Subject: Allow zero paths for multipath priority groups +References: bnc#372684 + +For correct handling of the all-paths-down scenario we have to +allow zero paths as a valid argument for priority groups. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-mpath.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -779,8 +779,8 @@ static int multipath_ctr(struct dm_targe + { + /* target parameters */ + static struct param _params[] = { +- {1, 1024, "invalid number of priority groups"}, +- {1, 1024, "invalid initial priority group number"}, ++ {0, 1024, "invalid number of priority groups"}, ++ {0, 1024, "invalid initial priority group number"}, + }; + + int r; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-queue-length-load-balancing b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-queue-length-load-balancing new file mode 100644 index 000000000..2003686af --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-queue-length-load-balancing @@ -0,0 +1,292 @@ +From: Kiyoshi Ueda +Subject: dm-mpath: add queue-length dynamic load balancer +References: FATE#303862,FATE#302108 + +This patch adds a dynamic load balancer, dm-queue-length, which +balances the number of in-flight I/Os. + +The code is based on the patch posted by Stefan Bader: +https://www.redhat.com/archives/dm-devel/2005-October/msg00050.html + + +Signed-off-by: Stefan Bader +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Signed-off-by: Hannes Reinecke + +Index: linux-2.6.27/drivers/md/Makefile +=================================================================== +--- linux-2.6.27.orig/drivers/md/Makefile ++++ linux-2.6.27/drivers/md/Makefile +@@ -32,7 +32,8 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o + obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o + obj-$(CONFIG_DM_CRYPT) += dm-crypt.o + obj-$(CONFIG_DM_DELAY) += dm-delay.o +-obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o dm-least-pending.o ++obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o \ ++ dm-least-pending.o dm-queue-length.o + obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o + obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-regions.o dm-log.o + obj-$(CONFIG_DM_RAID45) += dm-raid45.o dm-log.o dm-memcache.o \ +Index: linux-2.6.27/drivers/md/dm-queue-length.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/md/dm-queue-length.c +@@ -0,0 +1,257 @@ ++/* ++ * Copyright (C) 2004-2005 IBM Corp. All Rights Reserved. ++ * Copyright (C) 2006-2008 NEC Corporation. ++ * ++ * dm-queue-length.c ++ * ++ * Module Author: Stefan Bader, IBM ++ * Modified by: Kiyoshi Ueda, NEC ++ * ++ * This file is released under the GPL. ++ * ++ * Load balancing path selector. ++ */ ++ ++#include "dm.h" ++#include "dm-path-selector.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define DM_MSG_PREFIX "multipath queue-length" ++#define QL_MIN_IO 128 ++#define QL_VERSION "0.1.0" ++ ++struct selector { ++ struct list_head valid_paths; ++ struct list_head failed_paths; ++}; ++ ++struct path_info { ++ struct list_head list; ++ struct dm_path *path; ++ unsigned int repeat_count; ++ atomic_t qlen; ++}; ++ ++static struct selector *alloc_selector(void) ++{ ++ struct selector *s = kzalloc(sizeof(*s), GFP_KERNEL); ++ ++ if (s) { ++ INIT_LIST_HEAD(&s->valid_paths); ++ INIT_LIST_HEAD(&s->failed_paths); ++ } ++ ++ return s; ++} ++ ++static int ql_create(struct path_selector *ps, unsigned argc, char **argv) ++{ ++ struct selector *s = alloc_selector(); ++ ++ if (!s) ++ return -ENOMEM; ++ ++ ps->context = s; ++ ++ return 0; ++} ++ ++static void ql_free_paths(struct list_head *paths) ++{ ++ struct path_info *cpi, *npi; ++ ++ list_for_each_entry_safe(cpi, npi, paths, list) { ++ list_del(&cpi->list); ++ cpi->path->pscontext = NULL; ++ kfree(cpi); ++ } ++} ++ ++static void ql_destroy(struct path_selector *ps) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ ++ ql_free_paths(&s->valid_paths); ++ ql_free_paths(&s->failed_paths); ++ kfree(s); ++ ps->context = NULL; ++} ++ ++static int ql_add_path(struct path_selector *ps, struct dm_path *path, ++ int argc, char **argv, char **error) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi; ++ unsigned int repeat_count = QL_MIN_IO; ++ ++ /* Parse the arguments */ ++ if (argc > 1) { ++ *error = "queue-length ps: incorrect number of arguments"; ++ return -EINVAL; ++ } ++ ++ /* First path argument is number of I/Os before switching path. */ ++ if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) { ++ *error = "queue-length ps: invalid repeat count"; ++ return -EINVAL; ++ } ++ ++ /* Allocate the path information structure */ ++ pi = kmalloc(sizeof(*pi), GFP_KERNEL); ++ if (!pi) { ++ *error = "queue-length ps: Error allocating path information"; ++ return -ENOMEM; ++ } ++ ++ pi->path = path; ++ pi->repeat_count = repeat_count; ++ atomic_set(&pi->qlen, 0); ++ path->pscontext = pi; ++ ++ list_add_tail(&pi->list, &s->valid_paths); ++ ++ return 0; ++} ++ ++static void ql_fail_path(struct path_selector *ps, struct dm_path *path) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi = path->pscontext; ++ ++ list_move(&pi->list, &s->failed_paths); ++} ++ ++static int ql_reinstate_path(struct path_selector *ps, struct dm_path *path) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi = path->pscontext; ++ ++ list_move_tail(&pi->list, &s->valid_paths); ++ ++ return 0; ++} ++ ++static inline int ql_compare_qlen(struct path_info *pi1, struct path_info *pi2) ++{ ++ return atomic_read(&pi1->qlen) - atomic_read(&pi2->qlen); ++} ++ ++static struct dm_path *ql_select_path(struct path_selector *ps, ++ unsigned *repeat_count) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *cpi = NULL, *spi = NULL; ++ ++ if (list_empty(&s->valid_paths)) ++ return NULL; ++ ++ /* Change preferred (first in list) path to evenly balance. */ ++ list_move_tail(s->valid_paths.next, &s->valid_paths); ++ ++ list_for_each_entry(cpi, &s->valid_paths, list) { ++ if (!spi) ++ spi = cpi; ++ else if (ql_compare_qlen(cpi, spi) < 0) ++ spi = cpi; ++ } ++ ++ if (spi) ++ *repeat_count = spi->repeat_count; ++ ++ return spi ? spi->path : NULL; ++} ++ ++static int ql_start_io(struct path_selector *ps, struct dm_path *path) ++{ ++ struct path_info *pi = path->pscontext; ++ ++ atomic_inc(&pi->qlen); ++ ++ return 0; ++} ++ ++static int ql_end_io(struct path_selector *ps, struct dm_path *path) ++{ ++ struct path_info *pi = path->pscontext; ++ ++ atomic_dec(&pi->qlen); ++ ++ return 0; ++} ++ ++static int ql_status(struct path_selector *ps, struct dm_path *path, ++ status_type_t type, char *result, unsigned int maxlen) ++{ ++ int sz = 0; ++ struct path_info *pi; ++ ++ /* When called with (path == NULL), return selector status/args. */ ++ if (!path) ++ DMEMIT("0 "); ++ else { ++ pi = path->pscontext; ++ ++ switch (type) { ++ case STATUSTYPE_INFO: ++ DMEMIT("%u ", atomic_read(&pi->qlen)); ++ break; ++ case STATUSTYPE_TABLE: ++ DMEMIT("%u ", pi->repeat_count); ++ break; ++ } ++ } ++ ++ return sz; ++} ++ ++static struct path_selector_type ql_ps = { ++ .name = "queue-length", ++ .module = THIS_MODULE, ++ .table_args = 1, ++ .info_args = 1, ++ .create = ql_create, ++ .destroy = ql_destroy, ++ .status = ql_status, ++ .add_path = ql_add_path, ++ .fail_path = ql_fail_path, ++ .reinstate_path = ql_reinstate_path, ++ .select_path = ql_select_path, ++ .start_io = ql_start_io, ++ .end_io = ql_end_io, ++}; ++ ++static int __init dm_ql_init(void) ++{ ++ int r = dm_register_path_selector(&ql_ps); ++ ++ if (r < 0) ++ DMERR("register failed %d", r); ++ ++ DMINFO("version " QL_VERSION " loaded"); ++ ++ return r; ++} ++ ++static void __exit dm_ql_exit(void) ++{ ++ int r = dm_unregister_path_selector(&ql_ps); ++ ++ if (r < 0) ++ DMERR("unregister failed %d", r); ++} ++ ++module_init(dm_ql_init); ++module_exit(dm_ql_exit); ++ ++MODULE_AUTHOR("Stefan Bader "); ++MODULE_DESCRIPTION( ++ "(C) Copyright IBM Corp. 2004,2005 All Rights Reserved.\n" ++ DM_NAME " load balancing path selector (dm-queue-length.c version " ++ QL_VERSION ")" ++); ++MODULE_LICENSE("GPL"); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-requeue-for-stopped-queue b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-requeue-for-stopped-queue new file mode 100644 index 000000000..7a4c33425 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-requeue-for-stopped-queue @@ -0,0 +1,123 @@ +From: Hannes Reinecke +Subject: Handle I/O on stopped queues correctly +References: bnc#458393 + +The current multipath infrastructure has several issues when I/O is +submitted during a table reload. +The make_request_fn must not fail if no table is present, as I/O +will be queued properly in the request queue. But on the other hand +we should not submit queued I/Os if the queue of the underlying +device is stopped; that queue is undergoing reconfiguration +time and may be in all sort of states. + +And while we're at it, we should detach any hardware handler +if the multipath table doesn't specify one. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-mpath.c | 45 ++++++++++++++++++++++++++++----------------- + drivers/md/dm.c | 6 +++++- + 2 files changed, 33 insertions(+), 18 deletions(-) + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -159,9 +159,7 @@ static struct priority_group *alloc_prio + + static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) + { +- unsigned long flags; + struct pgpath *pgpath, *tmp; +- struct multipath *m = ti->private; + + list_for_each_entry_safe(pgpath, tmp, pgpaths, list) { + list_del(&pgpath->list); +@@ -436,8 +434,8 @@ static void process_queued_ios(struct wo + { + struct multipath *m = + container_of(work, struct multipath, process_queued_ios); +- struct pgpath *pgpath = NULL, *tmp; +- unsigned must_queue = 1; ++ struct pgpath *pgpath = NULL, *tmp; ++ unsigned must_queue = 1; + unsigned long flags; + + spin_lock_irqsave(&m->lock, flags); +@@ -450,6 +448,12 @@ static void process_queued_ios(struct wo + + pgpath = m->current_pgpath; + ++ if (pgpath) { ++ struct block_device *bdev = pgpath->path.dev->bdev; ++ if (unlikely(blk_queue_stopped(bdev_get_queue(bdev)))) ++ goto out; ++ } ++ + if ((pgpath && !m->queue_io) || + (!pgpath && !m->queue_if_no_path)) + must_queue = 0; +@@ -625,22 +629,24 @@ static struct pgpath *parse_path(struct + memcpy(p->path.pdev, p->path.dev->name, 16); + } + +- if (m->hw_handler_name && p->path.dev) { ++ if (p->path.dev) { + struct request_queue *q = bdev_get_queue(p->path.dev->bdev); + +- r = scsi_dh_attach(q, m->hw_handler_name); +- if (r == -EBUSY) { +- /* +- * Already attached to different hw_handler, +- * try to reattach with correct one. +- */ +- scsi_dh_detach(q); ++ if (m->hw_handler_name) { + r = scsi_dh_attach(q, m->hw_handler_name); +- } +- if (r < 0) { +- ti->error = "error attaching hardware handler"; +- dm_put_device(ti, p->path.dev); +- goto bad; ++ if (r == -EBUSY) { ++ /* ++ * Already attached to different hw_handler, ++ * try to reattach with correct one. ++ */ ++ scsi_dh_detach(q); ++ r = scsi_dh_attach(q, m->hw_handler_name); ++ } ++ if (r < 0) { ++ ti->error = "error attaching hardware handler"; ++ dm_put_device(ti, p->path.dev); ++ goto bad; ++ } + } + } + +@@ -650,6 +656,11 @@ static struct pgpath *parse_path(struct + goto bad; + } + ++ if (!p->is_active) { ++ ps->type->fail_path(ps, &p->path); ++ p->fail_count++; ++ m->nr_valid_paths--; ++ } + return p; + + bad: +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1304,7 +1304,11 @@ static int dm_make_request(struct reques + return 0; + } + +- if (unlikely(!md->map)) { ++ /* ++ * Submitting to a stopped queue with no map is okay; ++ * might happen during reconfiguration. ++ */ ++ if (unlikely(!md->map) && !blk_queue_stopped(q)) { + bio_endio(bio, -EIO); + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-service-time-load-balancing b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-service-time-load-balancing new file mode 100644 index 000000000..be227b713 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-service-time-load-balancing @@ -0,0 +1,343 @@ +From: Kiyoshi Ueda +Subject: dm-mpath: add service-time oriented dynamic load balancer +References: FATE#303862,FATE#302108 + +This patch adds a service time oriented dynamic load balancer, +dm-service-time. + + +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Signed-off-by: Hannes Reinecke + +Index: linux-2.6.27/drivers/md/Makefile +=================================================================== +--- linux-2.6.27.orig/drivers/md/Makefile ++++ linux-2.6.27/drivers/md/Makefile +@@ -33,7 +33,8 @@ obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o + obj-$(CONFIG_DM_CRYPT) += dm-crypt.o + obj-$(CONFIG_DM_DELAY) += dm-delay.o + obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o \ +- dm-least-pending.o dm-queue-length.o ++ dm-least-pending.o dm-queue-length.o \ ++ dm-service-time.o + obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o + obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-regions.o dm-log.o + obj-$(CONFIG_DM_RAID45) += dm-raid45.o dm-log.o dm-memcache.o \ +Index: linux-2.6.27/drivers/md/dm-service-time.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/md/dm-service-time.c +@@ -0,0 +1,312 @@ ++/* ++ * Copyright (C) 2007-2008 NEC Corporation. All Rights Reserved. ++ * ++ * Module Author: Kiyoshi Ueda ++ * ++ * This file is released under the GPL. ++ * ++ * Throughput oriented path selector. ++ */ ++ ++#include "dm.h" ++#include "dm-path-selector.h" ++ ++#define DM_MSG_PREFIX "multipath service-time" ++#define ST_MIN_IO 2 ++#define ST_VERSION "0.1.0" ++ ++struct selector { ++ struct list_head valid_paths; ++ struct list_head failed_paths; ++}; ++ ++struct path_info { ++ struct list_head list; ++ struct dm_path *path; ++ unsigned int repeat_count; ++ ++ atomic_t in_flight; /* Total size of in-flight I/Os */ ++ size_t perf; /* Recent performance of the path */ ++ sector_t last_sectors; /* Total sectors of the last disk_stat_read */ ++ size_t last_io_ticks; /* io_ticks of the last disk_stat_read */ ++}; ++ ++static struct selector *alloc_selector(void) ++{ ++ struct selector *s = kzalloc(sizeof(*s), GFP_KERNEL); ++ ++ if (s) { ++ INIT_LIST_HEAD(&s->valid_paths); ++ INIT_LIST_HEAD(&s->failed_paths); ++ } ++ ++ return s; ++} ++ ++static int st_create(struct path_selector *ps, unsigned argc, char **argv) ++{ ++ struct selector *s = alloc_selector(); ++ ++ if (!s) ++ return -ENOMEM; ++ ++ ps->context = s; ++ return 0; ++} ++ ++static void free_paths(struct list_head *paths) ++{ ++ struct path_info *pi, *next; ++ ++ list_for_each_entry_safe(pi, next, paths, list) { ++ list_del(&pi->list); ++ pi->path->pscontext = NULL; ++ kfree(pi); ++ } ++} ++ ++static void st_destroy(struct path_selector *ps) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ ++ free_paths(&s->valid_paths); ++ free_paths(&s->failed_paths); ++ kfree(s); ++ ps->context = NULL; ++} ++ ++static int st_status(struct path_selector *ps, struct dm_path *path, ++ status_type_t type, char *result, unsigned int maxlen) ++{ ++ int sz = 0; ++ struct path_info *pi; ++ ++ if (!path) ++ DMEMIT("0 "); ++ else { ++ pi = path->pscontext; ++ ++ switch (type) { ++ case STATUSTYPE_INFO: ++ DMEMIT("if:%08lu pf:%06lu ", ++ (unsigned long) atomic_read(&pi->in_flight), ++ pi->perf); ++ break; ++ case STATUSTYPE_TABLE: ++ DMEMIT("%u ", pi->repeat_count); ++ break; ++ } ++ } ++ ++ return sz; ++} ++ ++static int st_add_path(struct path_selector *ps, struct dm_path *path, ++ int argc, char **argv, char **error) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi; ++ unsigned int repeat_count = ST_MIN_IO; ++ struct gendisk *disk = path->dev->bdev->bd_disk; ++ ++ if (argc > 1) { ++ *error = "service-time ps: incorrect number of arguments"; ++ return -EINVAL; ++ } ++ ++ /* First path argument is number of I/Os before switching path. */ ++ if ((argc == 1) && (sscanf(argv[0], "%u", &repeat_count) != 1)) { ++ *error = "service-time ps: invalid repeat count"; ++ return -EINVAL; ++ } ++ ++ /* allocate the path */ ++ pi = kmalloc(sizeof(*pi), GFP_KERNEL); ++ if (!pi) { ++ *error = "service-time ps: Error allocating path context"; ++ return -ENOMEM; ++ } ++ ++ pi->path = path; ++ pi->repeat_count = repeat_count; ++ ++ pi->perf = 0; ++ pi->last_sectors = disk_stat_read(disk, sectors[READ]) ++ + disk_stat_read(disk, sectors[WRITE]); ++ pi->last_io_ticks = disk_stat_read(disk, io_ticks); ++ atomic_set(&pi->in_flight, 0); ++ ++ path->pscontext = pi; ++ ++ list_add_tail(&pi->list, &s->valid_paths); ++ ++ return 0; ++} ++ ++static void st_fail_path(struct path_selector *ps, struct dm_path *path) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi = path->pscontext; ++ ++ list_move(&pi->list, &s->failed_paths); ++} ++ ++static int st_reinstate_path(struct path_selector *ps, struct dm_path *path) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi = path->pscontext; ++ ++ list_move_tail(&pi->list, &s->valid_paths); ++ ++ return 0; ++} ++ ++static void stats_update(struct path_info *pi) ++{ ++ sector_t sectors; ++ size_t io_ticks, tmp; ++ struct gendisk *disk = pi->path->dev->bdev->bd_disk; ++ ++ sectors = disk_stat_read(disk, sectors[READ]) ++ + disk_stat_read(disk, sectors[WRITE]); ++ io_ticks = disk_stat_read(disk, io_ticks); ++ ++ if ((sectors != pi->last_sectors) && (io_ticks != pi->last_io_ticks)) { ++ tmp = (sectors - pi->last_sectors) << 9; ++ do_div(tmp, jiffies_to_msecs((io_ticks - pi->last_io_ticks))); ++ pi->perf = tmp; ++ ++ pi->last_sectors = sectors; ++ pi->last_io_ticks = io_ticks; ++ } ++} ++ ++static int st_compare_load(struct path_info *pi1, struct path_info *pi2, ++ size_t new_io) ++{ ++ size_t if1, if2; ++ ++ if1 = atomic_read(&pi1->in_flight); ++ if2 = atomic_read(&pi2->in_flight); ++ ++ /* ++ * Case 1: No performace data available. Choose less loaded path. ++ */ ++ if (!pi1->perf || !pi2->perf) ++ return if1 - if2; ++ ++ /* ++ * Case 2: Calculate service time. Choose faster path. ++ * if ((if1+new_io)/pi1->perf < (if2+new_io)/pi2->perf) pi1. ++ * if ((if1+new_io)/pi1->perf > (if2+new_io)/pi2->perf) pi2. ++ * To avoid do_div(), use ++ * if ((if1+new_io)*pi2->perf < (if2+new_io)*pi1->perf) pi1. ++ * if ((if1+new_io)*pi2->perf > (if2+new_io)*pi1->perf) pi2. ++ */ ++ if1 = (if1 + new_io) << 10; ++ if2 = (if2 + new_io) << 10; ++ do_div(if1, pi1->perf); ++ do_div(if2, pi2->perf); ++ ++ if (if1 != if2) ++ return if1 - if2; ++ ++ /* ++ * Case 3: Service time is equal. Choose faster path. ++ */ ++ return pi2->perf - pi1->perf; ++} ++ ++static struct dm_path *st_select_path(struct path_selector *ps, ++ unsigned *repeat_count, size_t nr_bytes) ++{ ++ struct selector *s = (struct selector *) ps->context; ++ struct path_info *pi = NULL, *best = NULL; ++ ++ if (list_empty(&s->valid_paths)) ++ return NULL; ++ ++ /* Change preferred (first in list) path to evenly balance. */ ++ list_move_tail(s->valid_paths.next, &s->valid_paths); ++ ++ /* Update performance information before best path selection */ ++ list_for_each_entry(pi, &s->valid_paths, list) ++ stats_update(pi); ++ ++ list_for_each_entry(pi, &s->valid_paths, list) { ++ if (!best) ++ best = pi; ++ else if (st_compare_load(pi, best, nr_bytes) < 0) ++ best = pi; ++ } ++ ++ if (best) { ++ *repeat_count = best->repeat_count; ++ return best->path; ++ } ++ ++ return NULL; ++} ++ ++static int st_start_io(struct path_selector *ps, struct dm_path *path, ++ size_t nr_bytes) ++{ ++ struct path_info *pi = path->pscontext; ++ ++ atomic_add(nr_bytes, &pi->in_flight); ++ ++ return 0; ++} ++ ++static int st_end_io(struct path_selector *ps, struct dm_path *path, ++ size_t nr_bytes) ++{ ++ struct path_info *pi = path->pscontext; ++ ++ atomic_sub(nr_bytes, &pi->in_flight); ++ ++ return 0; ++} ++ ++static struct path_selector_type st_ps = { ++ .name = "service-time", ++ .module = THIS_MODULE, ++ .table_args = 1, ++ .info_args = 2, ++ .create = st_create, ++ .destroy = st_destroy, ++ .status = st_status, ++ .add_path = st_add_path, ++ .fail_path = st_fail_path, ++ .reinstate_path = st_reinstate_path, ++ .select_path = st_select_path, ++ .start_io = st_start_io, ++ .end_io = st_end_io, ++}; ++ ++static int __init dm_st_init(void) ++{ ++ int r = dm_register_path_selector(&st_ps); ++ ++ if (r < 0) ++ DMERR("register failed %d", r); ++ ++ DMINFO("version " ST_VERSION " loaded"); ++ ++ return r; ++} ++ ++static void __exit dm_st_exit(void) ++{ ++ int r = dm_unregister_path_selector(&st_ps); ++ ++ if (r < 0) ++ DMERR("unregister failed %d", r); ++} ++ ++module_init(dm_st_init); ++module_exit(dm_st_exit); ++ ++MODULE_DESCRIPTION(DM_NAME " throughput oriented path selector"); ++MODULE_AUTHOR("Kiyoshi Ueda "); ++MODULE_LICENSE("GPL"); diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-tracking-nr-bytes b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-tracking-nr-bytes new file mode 100644 index 000000000..23cf19470 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-mpath-tracking-nr-bytes @@ -0,0 +1,226 @@ +From: Kiyoshi Ueda +Subject: dm-mpath: interface change for service-time dynamic load balancer +References: FATE#303862,FATE#302108 + +This patch changes path selector interfaces for service-time oriented +dynamic load balancer. + +To calculate the service time for an incoming I/O correctly, +the load balancer needs the size of the incoming I/O when selecting +the next path. + + +Signed-off-by: Kiyoshi Ueda +Signed-off-by: Jun'ichi Nomura +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-least-pending.c | 4 ++-- + drivers/md/dm-mpath.c | 27 ++++++++++++++++----------- + drivers/md/dm-path-selector.h | 9 ++++++--- + drivers/md/dm-queue-length.c | 8 +++++--- + drivers/md/dm-round-robin.c | 2 +- + 5 files changed, 30 insertions(+), 20 deletions(-) + +--- a/drivers/md/dm-least-pending.c ++++ b/drivers/md/dm-least-pending.c +@@ -172,7 +172,7 @@ static int lpp_reinstate_path(struct pat + } + + static struct dm_path *lpp_select_path(struct path_selector *ps, +- unsigned *repeat_count) ++ unsigned *repeat_count, size_t nr_bytes) + { + struct selector *s = ps->context; + struct path_info *pi, *next, *least_io_path = NULL; +@@ -199,7 +199,7 @@ static struct dm_path *lpp_select_path(s + return least_io_path->path; + } + +-static int lpp_end_io(struct path_selector *ps, struct dm_path *path) ++static int lpp_end_io(struct path_selector *ps, struct dm_path *path, size_t nr_bytes) + { + struct path_info *pi = NULL; + +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -99,6 +99,7 @@ struct multipath { + */ + struct dm_mpath_io { + struct pgpath *pgpath; ++ size_t nr_bytes; + }; + + typedef int (*action_fn) (struct pgpath *pgpath); +@@ -246,11 +247,12 @@ static void __switch_pg(struct multipath + m->pg_init_count = 0; + } + +-static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) ++static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg, ++ size_t nr_bytes) + { + struct dm_path *path; + +- path = pg->ps.type->select_path(&pg->ps, &m->repeat_count); ++ path = pg->ps.type->select_path(&pg->ps, &m->repeat_count, nr_bytes); + if (!path) + return -ENXIO; + +@@ -262,7 +264,7 @@ static int __choose_path_in_pg(struct mu + return 0; + } + +-static void __choose_pgpath(struct multipath *m) ++static void __choose_pgpath(struct multipath *m, size_t nr_bytes) + { + struct priority_group *pg; + unsigned bypassed = 1; +@@ -274,12 +276,12 @@ static void __choose_pgpath(struct multi + if (m->next_pg) { + pg = m->next_pg; + m->next_pg = NULL; +- if (!__choose_path_in_pg(m, pg)) ++ if (!__choose_path_in_pg(m, pg, nr_bytes)) + return; + } + + /* Don't change PG until it has no remaining paths */ +- if (m->current_pg && !__choose_path_in_pg(m, m->current_pg)) ++ if (m->current_pg && !__choose_path_in_pg(m, m->current_pg, nr_bytes)) + return; + + /* +@@ -291,7 +293,7 @@ static void __choose_pgpath(struct multi + list_for_each_entry(pg, &m->priority_groups, list) { + if (pg->bypassed == bypassed) + continue; +- if (!__choose_path_in_pg(m, pg)) ++ if (!__choose_path_in_pg(m, pg, nr_bytes)) + return; + } + } while (bypassed--); +@@ -322,6 +324,7 @@ static int map_io(struct multipath *m, s + struct dm_mpath_io *mpio, unsigned was_queued) + { + int r = DM_MAPIO_REMAPPED; ++ size_t nr_bytes = blk_rq_bytes(clone); + unsigned long flags; + struct pgpath *pgpath; + struct block_device *bdev; +@@ -331,7 +334,7 @@ static int map_io(struct multipath *m, s + /* Do we need to select a new pgpath? */ + if (!m->current_pgpath || + (!m->queue_io && (m->repeat_count && --m->repeat_count == 0))) +- __choose_pgpath(m); ++ __choose_pgpath(m, nr_bytes); + + pgpath = m->current_pgpath; + +@@ -358,9 +361,11 @@ static int map_io(struct multipath *m, s + r = -EIO; /* Failed */ + + mpio->pgpath = pgpath; ++ mpio->nr_bytes = nr_bytes; + + if (r == DM_MAPIO_REMAPPED && pgpath->pg->ps.type->start_io) +- pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path); ++ pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path, ++ nr_bytes); + + spin_unlock_irqrestore(&m->lock, flags); + +@@ -440,7 +445,7 @@ static void process_queued_ios(struct wo + goto out; + + if (!m->current_pgpath) +- __choose_pgpath(m); ++ __choose_pgpath(m, 1 << 19); /* Assume 512 KB */ + + pgpath = m->current_pgpath; + +@@ -1204,7 +1209,7 @@ static int multipath_end_io(struct dm_ta + if (pgpath) { + ps = &pgpath->pg->ps; + if (ps->type->end_io) +- ps->type->end_io(ps, &pgpath->path); ++ ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes); + } + mempool_free(mpio, m->mpio_pool); + +@@ -1423,7 +1428,7 @@ static int multipath_ioctl(struct dm_tar + spin_lock_irqsave(&m->lock, flags); + + if (!m->current_pgpath) +- __choose_pgpath(m); ++ __choose_pgpath(m, 1 << 19); /* Assume 512KB */ + + if (m->current_pgpath) { + bdev = m->current_pgpath->path.dev->bdev; +--- a/drivers/md/dm-path-selector.h ++++ b/drivers/md/dm-path-selector.h +@@ -56,7 +56,8 @@ struct path_selector_type { + * the path fails. + */ + struct dm_path *(*select_path) (struct path_selector *ps, +- unsigned *repeat_count); ++ unsigned *repeat_count, ++ size_t nr_bytes); + + /* + * Notify the selector that a path has failed. +@@ -75,8 +76,10 @@ struct path_selector_type { + int (*status) (struct path_selector *ps, struct dm_path *path, + status_type_t type, char *result, unsigned int maxlen); + +- int (*start_io) (struct path_selector *ps, struct dm_path *path); +- int (*end_io) (struct path_selector *ps, struct dm_path *path); ++ int (*start_io) (struct path_selector *ps, struct dm_path *path, ++ size_t nr_bytes); ++ int (*end_io) (struct path_selector *ps, struct dm_path *path, ++ size_t nr_bytes); + }; + + /* Register a path selector */ +--- a/drivers/md/dm-queue-length.c ++++ b/drivers/md/dm-queue-length.c +@@ -142,7 +142,7 @@ static inline int ql_compare_qlen(struct + } + + static struct dm_path *ql_select_path(struct path_selector *ps, +- unsigned *repeat_count) ++ unsigned *repeat_count, size_t nr_bytes) + { + struct selector *s = (struct selector *) ps->context; + struct path_info *cpi = NULL, *spi = NULL; +@@ -166,7 +166,8 @@ static struct dm_path *ql_select_path(st + return spi ? spi->path : NULL; + } + +-static int ql_start_io(struct path_selector *ps, struct dm_path *path) ++static int ql_start_io(struct path_selector *ps, struct dm_path *path, ++ size_t nr_bytes) + { + struct path_info *pi = path->pscontext; + +@@ -175,7 +176,8 @@ static int ql_start_io(struct path_selec + return 0; + } + +-static int ql_end_io(struct path_selector *ps, struct dm_path *path) ++static int ql_end_io(struct path_selector *ps, struct dm_path *path, ++ size_t nr_bytes) + { + struct path_info *pi = path->pscontext; + +--- a/drivers/md/dm-round-robin.c ++++ b/drivers/md/dm-round-robin.c +@@ -160,7 +160,7 @@ static int rr_reinstate_path(struct path + } + + static struct dm_path *rr_select_path(struct path_selector *ps, +- unsigned *repeat_count) ++ unsigned *repeat_count, size_t nr_bytes) + { + struct selector *s = (struct selector *) ps->context; + struct path_info *pi = NULL; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-raid45_2.6.27_20081027.patch b/src/patches/suse-2.6.27.31/patches.suse/dm-raid45_2.6.27_20081027.patch new file mode 100644 index 000000000..dde5e830b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-raid45_2.6.27_20081027.patch @@ -0,0 +1,6113 @@ +From: "Heinz Mauelshagen +Subject: DMRAID45 module +X-URL: http://people.redhat.com/~heinzm/sw/dm/dm-raid45/ + + DM-RAID 45 module. + + This driver is used for "Fake RAID" devices. + +Acked-by: Jeff Mahoney + +--- + + drivers/md/Kconfig | 8 + drivers/md/Makefile | 4 + drivers/md/dm-memcache.c | 301 ++ + drivers/md/dm-memcache.h | 68 + drivers/md/dm-message.c | 182 + + drivers/md/dm-message.h | 91 + drivers/md/dm-raid45.c | 4516 +++++++++++++++++++++++++++++++++++++++++++++ + drivers/md/dm-raid45.h | 28 + drivers/md/dm-regions.c | 723 +++++++ + drivers/md/dm.c | 1 + include/linux/dm-regions.h | 115 + + 11 files changed, 6036 insertions(+), 1 deletion(-) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1680,6 +1680,7 @@ struct gendisk *dm_disk(struct mapped_de + { + return md->disk; + } ++EXPORT_SYMBOL_GPL(dm_disk); + + int dm_suspended(struct mapped_device *md) + { +--- /dev/null ++++ b/drivers/md/dm-memcache.c +@@ -0,0 +1,301 @@ ++/* ++ * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. ++ * ++ * Module Author: Heinz Mauelshagen ++ * ++ * Device-mapper memory object handling: ++ * ++ * o allocate/free total_pages in a per client page pool. ++ * ++ * o allocate/free memory objects with chunks (1..n) of ++ * pages_per_chunk pages hanging off. ++ * ++ * This file is released under the GPL. ++ */ ++ ++#define DM_MEM_CACHE_VERSION "0.2" ++ ++#include "dm.h" ++#include "dm-memcache.h" ++#include ++ ++struct dm_mem_cache_client { ++ spinlock_t lock; ++ mempool_t *objs_pool; ++ struct page_list *free_list; ++ unsigned objects; ++ unsigned chunks; ++ unsigned pages_per_chunk; ++ unsigned free_pages; ++ unsigned total_pages; ++}; ++ ++/* ++ * Free pages and page_list elements of client. ++ */ ++static void free_cache_pages(struct page_list *list) ++{ ++ while (list) { ++ struct page_list *pl = list; ++ ++ list = pl->next; ++ BUG_ON(!pl->page); ++ __free_page(pl->page); ++ kfree(pl); ++ } ++} ++ ++/* ++ * Alloc number of pages and page_list elements as required by client. ++ */ ++static struct page_list *alloc_cache_pages(unsigned pages) ++{ ++ struct page_list *pl, *ret = NULL; ++ struct page *page; ++ ++ while (pages--) { ++ page = alloc_page(GFP_NOIO); ++ if (!page) ++ goto err; ++ ++ pl = kmalloc(sizeof(*pl), GFP_NOIO); ++ if (!pl) { ++ __free_page(page); ++ goto err; ++ } ++ ++ pl->page = page; ++ pl->next = ret; ++ ret = pl; ++ } ++ ++ return ret; ++ ++err: ++ free_cache_pages(ret); ++ return NULL; ++} ++ ++/* ++ * Allocate page_list elements from the pool to chunks of the memory object. ++ */ ++static void alloc_chunks(struct dm_mem_cache_client *cl, ++ struct dm_mem_cache_object *obj) ++{ ++ unsigned chunks = cl->chunks; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ local_irq_disable(); ++ while (chunks--) { ++ unsigned p = cl->pages_per_chunk; ++ ++ obj[chunks].pl = NULL; ++ ++ while (p--) { ++ struct page_list *pl; ++ ++ /* Take next element from free list */ ++ spin_lock(&cl->lock); ++ pl = cl->free_list; ++ BUG_ON(!pl); ++ cl->free_list = pl->next; ++ spin_unlock(&cl->lock); ++ ++ pl->next = obj[chunks].pl; ++ obj[chunks].pl = pl; ++ } ++ } ++ ++ local_irq_restore(flags); ++} ++ ++/* ++ * Free page_list elements putting them back onto free list ++ */ ++static void free_chunks(struct dm_mem_cache_client *cl, ++ struct dm_mem_cache_object *obj) ++{ ++ unsigned chunks = cl->chunks; ++ unsigned long flags; ++ struct page_list *next, *pl; ++ ++ local_irq_save(flags); ++ local_irq_disable(); ++ while (chunks--) { ++ for (pl = obj[chunks].pl; pl; pl = next) { ++ next = pl->next; ++ ++ spin_lock(&cl->lock); ++ pl->next = cl->free_list; ++ cl->free_list = pl; ++ cl->free_pages++; ++ spin_unlock(&cl->lock); ++ } ++ } ++ ++ local_irq_restore(flags); ++} ++ ++/* ++ * Create/destroy dm memory cache client resources. ++ */ ++struct dm_mem_cache_client * ++dm_mem_cache_client_create(unsigned objects, unsigned chunks, ++ unsigned pages_per_chunk) ++{ ++ unsigned total_pages = objects * chunks * pages_per_chunk; ++ struct dm_mem_cache_client *client; ++ ++ BUG_ON(!total_pages); ++ client = kzalloc(sizeof(*client), GFP_KERNEL); ++ if (!client) ++ return ERR_PTR(-ENOMEM); ++ ++ client->objs_pool = mempool_create_kmalloc_pool(objects, ++ chunks * sizeof(struct dm_mem_cache_object)); ++ if (!client->objs_pool) ++ goto err; ++ ++ client->free_list = alloc_cache_pages(total_pages); ++ if (!client->free_list) ++ goto err1; ++ ++ spin_lock_init(&client->lock); ++ client->objects = objects; ++ client->chunks = chunks; ++ client->pages_per_chunk = pages_per_chunk; ++ client->free_pages = client->total_pages = total_pages; ++ return client; ++ ++err1: ++ mempool_destroy(client->objs_pool); ++err: ++ kfree(client); ++ return ERR_PTR(-ENOMEM); ++} ++EXPORT_SYMBOL(dm_mem_cache_client_create); ++ ++void dm_mem_cache_client_destroy(struct dm_mem_cache_client *cl) ++{ ++ BUG_ON(cl->free_pages != cl->total_pages); ++ free_cache_pages(cl->free_list); ++ mempool_destroy(cl->objs_pool); ++ kfree(cl); ++} ++EXPORT_SYMBOL(dm_mem_cache_client_destroy); ++ ++/* ++ * Grow a clients cache by an amount of pages. ++ * ++ * Don't call from interrupt context! ++ */ ++int dm_mem_cache_grow(struct dm_mem_cache_client *cl, unsigned objects) ++{ ++ unsigned pages = objects * cl->chunks * cl->pages_per_chunk; ++ struct page_list *pl, *last; ++ ++ BUG_ON(!pages); ++ pl = alloc_cache_pages(pages); ++ if (!pl) ++ return -ENOMEM; ++ ++ last = pl; ++ while (last->next) ++ last = last->next; ++ ++ spin_lock_irq(&cl->lock); ++ last->next = cl->free_list; ++ cl->free_list = pl; ++ cl->free_pages += pages; ++ cl->total_pages += pages; ++ cl->objects++; ++ spin_unlock_irq(&cl->lock); ++ ++ mempool_resize(cl->objs_pool, cl->objects, GFP_NOIO); ++ return 0; ++} ++EXPORT_SYMBOL(dm_mem_cache_grow); ++ ++/* Shrink a clients cache by an amount of pages */ ++int dm_mem_cache_shrink(struct dm_mem_cache_client *cl, unsigned objects) ++{ ++ int r; ++ unsigned pages = objects * cl->chunks * cl->pages_per_chunk, p = pages; ++ unsigned long flags; ++ struct page_list *last = NULL, *pl, *pos; ++ ++ BUG_ON(!pages); ++ ++ spin_lock_irqsave(&cl->lock, flags); ++ pl = pos = cl->free_list; ++ while (p-- && pos->next) { ++ last = pos; ++ pos = pos->next; ++ } ++ ++ if (++p) ++ r = -ENOMEM; ++ else { ++ r = 0; ++ cl->free_list = pos; ++ cl->free_pages -= pages; ++ cl->total_pages -= pages; ++ cl->objects--; ++ last->next = NULL; ++ } ++ spin_unlock_irqrestore(&cl->lock, flags); ++ ++ if (!r) { ++ free_cache_pages(pl); ++ mempool_resize(cl->objs_pool, cl->objects, GFP_NOIO); ++ } ++ ++ return r; ++} ++EXPORT_SYMBOL(dm_mem_cache_shrink); ++ ++/* ++ * Allocate/free a memory object ++ * ++ * Can be called from interrupt context ++ */ ++struct dm_mem_cache_object *dm_mem_cache_alloc(struct dm_mem_cache_client *cl) ++{ ++ int r = 0; ++ unsigned pages = cl->chunks * cl->pages_per_chunk; ++ unsigned long flags; ++ struct dm_mem_cache_object *obj; ++ ++ obj = mempool_alloc(cl->objs_pool, GFP_NOIO); ++ if (!obj) ++ return ERR_PTR(-ENOMEM); ++ ++ spin_lock_irqsave(&cl->lock, flags); ++ if (pages > cl->free_pages) ++ r = -ENOMEM; ++ else ++ cl->free_pages -= pages; ++ spin_unlock_irqrestore(&cl->lock, flags); ++ ++ if (r) { ++ mempool_free(obj, cl->objs_pool); ++ return ERR_PTR(r); ++ } ++ ++ alloc_chunks(cl, obj); ++ return obj; ++} ++EXPORT_SYMBOL(dm_mem_cache_alloc); ++ ++void dm_mem_cache_free(struct dm_mem_cache_client *cl, ++ struct dm_mem_cache_object *obj) ++{ ++ free_chunks(cl, obj); ++ mempool_free(obj, cl->objs_pool); ++} ++EXPORT_SYMBOL(dm_mem_cache_free); ++ ++MODULE_DESCRIPTION(DM_NAME " dm memory cache"); ++MODULE_AUTHOR("Heinz Mauelshagen "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/md/dm-memcache.h +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. ++ * ++ * Module Author: Heinz Mauelshagen ++ * ++ * Device-mapper memory object handling: ++ * ++ * o allocate/free total_pages in a per client page pool. ++ * ++ * o allocate/free memory objects with chunks (1..n) of ++ * pages_per_chunk pages hanging off. ++ * ++ * This file is released under the GPL. ++ */ ++ ++#ifndef _DM_MEM_CACHE_H ++#define _DM_MEM_CACHE_H ++ ++#define DM_MEM_CACHE_H_VERSION "0.1" ++ ++#include "dm.h" ++#include ++ ++static inline struct page_list *pl_elem(struct page_list *pl, unsigned p) ++{ ++ while (pl && p--) ++ pl = pl->next; ++ ++ return pl; ++} ++ ++struct dm_mem_cache_object { ++ struct page_list *pl; /* Dynamically allocated array */ ++ void *private; /* Caller context reference */ ++}; ++ ++struct dm_mem_cache_client; ++ ++/* ++ * Create/destroy dm memory cache client resources. ++ * ++ * On creation, a number of @objects with @chunks of ++ * @pages_per_chunk pages will be allocated. ++ */ ++struct dm_mem_cache_client * ++dm_mem_cache_client_create(unsigned objects, unsigned chunks, ++ unsigned pages_per_chunk); ++void dm_mem_cache_client_destroy(struct dm_mem_cache_client *client); ++ ++/* ++ * Grow/shrink a dm memory cache client resources ++ * by @objetcs amount of objects. ++ */ ++int dm_mem_cache_grow(struct dm_mem_cache_client *client, unsigned objects); ++int dm_mem_cache_shrink(struct dm_mem_cache_client *client, unsigned objects); ++ ++/* ++ * Allocate/free a memory object ++ * ++ * On allocation one object with an amount of chunks and ++ * an amount of pages per chunk will be returned on success. ++ */ ++struct dm_mem_cache_object * ++dm_mem_cache_alloc(struct dm_mem_cache_client *client); ++void dm_mem_cache_free(struct dm_mem_cache_client *client, ++ struct dm_mem_cache_object *object); ++ ++#endif +--- /dev/null ++++ b/drivers/md/dm-message.c +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (C) 2007,2008 Red Hat Inc. All rights reserved. ++ * ++ * Module Author: Heinz Mauelshagen ++ * ++ * General device-mapper message interface argument parser. ++ * ++ * This file is released under the GPL. ++ * ++ * device-mapper message parser. ++ * ++ */ ++ ++#include "dm.h" ++#include "dm-message.h" ++#include ++ ++#define DM_MSG_PREFIX "dm_message" ++ ++/* Basename of a path. */ ++static inline char * ++basename(char *s) ++{ ++ char *p = strrchr(s, '/'); ++ ++ return p ? p + 1 : s; ++} ++ ++/* Get an argument depending on type. */ ++static void ++message_arguments(struct dm_msg *msg, int argc, char **argv) ++{ ++ ++ if (argc) { ++ int i; ++ struct dm_message_argument *args = msg->spec->args; ++ ++ for (i = 0; i < args->num_args; i++) { ++ int r; ++ unsigned long **ptr = args->ptr; ++ enum dm_message_argument_type type = args->types[i]; ++ ++ switch (type) { ++ case dm_msg_base_t: ++ ((char **) ptr)[i] = basename(argv[i]); ++ break; ++ ++ case dm_msg_str_t: ++ ((char **) ptr)[i] = argv[i]; ++ break; ++ ++ case dm_msg_int_t: ++ r = sscanf(argv[i], "%d", ((int **) ptr)[i]); ++ goto check; ++ ++ case dm_msg_uint_t: ++ r = sscanf(argv[i], "%u", ++ ((unsigned **) ptr)[i]); ++ goto check; ++ ++ case dm_msg_uint64_t: ++ r = sscanf(argv[i], "%llu", ++ ((unsigned long long **) ptr)[i]); ++ ++check: ++ if (r != 1) { ++ set_bit(dm_msg_ret_undef, &msg->ret); ++ set_bit(dm_msg_ret_arg, &msg->ret); ++ } ++ } ++ } ++ } ++} ++ ++/* Parse message options. */ ++static void ++message_options_parse(struct dm_msg *msg, int argc, char **argv) ++{ ++ int hit = 0; ++ unsigned long *action; ++ size_t l1 = strlen(*argv), l_hit = 0; ++ struct dm_message_option *o = msg->spec->options; ++ char **option, **option_end = o->options + o->num_options; ++ ++ for (option = o->options, action = o->actions; ++ option < option_end; option++, action++) { ++ size_t l2 = strlen(*option); ++ ++ if (!strnicmp(*argv, *option, min(l1, l2))) { ++ hit++; ++ l_hit = l2; ++ set_bit(*action, &msg->action); ++ } ++ } ++ ++ /* Assume error. */ ++ msg->ret = 0; ++ set_bit(dm_msg_ret_option, &msg->ret); ++ if (!hit || l1 > l_hit) ++ set_bit(dm_msg_ret_undef, &msg->ret); /* Undefined option. */ ++ else if (hit > 1) ++ set_bit(dm_msg_ret_ambiguous, &msg->ret); /* Ambiguous option.*/ ++ else { ++ clear_bit(dm_msg_ret_option, &msg->ret); /* Option OK. */ ++ message_arguments(msg, --argc, ++argv); ++ } ++} ++ ++static inline void ++print_ret(const char *caller, unsigned long ret) ++{ ++ struct { ++ unsigned long err; ++ const char *err_str; ++ } static err_msg[] = { ++ { dm_msg_ret_ambiguous, "message ambiguous" }, ++ { dm_msg_ret_inval, "message invalid" }, ++ { dm_msg_ret_undef, "message undefined" }, ++ { dm_msg_ret_arg, "message argument" }, ++ { dm_msg_ret_argcount, "message argument count" }, ++ { dm_msg_ret_option, "option" }, ++ }, *e = ARRAY_END(err_msg); ++ ++ while (e-- > err_msg) { ++ if (test_bit(e->err, &ret)) ++ DMERR("%s %s", caller, e->err_str); ++ } ++} ++ ++/* Parse a message action. */ ++int ++dm_message_parse(const char *caller, struct dm_msg *msg, void *context, ++ int argc, char **argv) ++{ ++ int hit = 0; ++ size_t l1 = strlen(*argv), l_hit = 0; ++ struct dm_msg_spec *s, *s_hit = NULL, ++ *s_end = msg->specs + msg->num_specs; ++ ++ if (argc < 2) ++ return -EINVAL; ++ ++ for (s = msg->specs; s < s_end; s++) { ++ size_t l2 = strlen(s->cmd); ++ ++ if (!strnicmp(*argv, s->cmd, min(l1, l2))) { ++ hit++; ++ l_hit = l2; ++ s_hit = s; ++ } ++ } ++ ++ msg->ret = 0; ++ if (!hit || l1 > l_hit) /* No hit or message string too long. */ ++ set_bit(dm_msg_ret_undef, &msg->ret); ++ else if (hit > 1) /* Ambiguous message. */ ++ set_bit(dm_msg_ret_ambiguous, &msg->ret); ++ else if (argc - 2 != s_hit->args->num_args) { ++ set_bit(dm_msg_ret_undef, &msg->ret); ++ set_bit(dm_msg_ret_argcount, &msg->ret); ++ } ++ ++ if (msg->ret) ++ goto bad; ++ ++ msg->action = 0; ++ msg->spec = s_hit; ++ set_bit(s_hit->action, &msg->action); ++ message_options_parse(msg, --argc, ++argv); ++ ++ if (!msg->ret) ++ return msg->spec->f(msg, context); ++ ++bad: ++ print_ret(caller, msg->ret); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(dm_message_parse); ++ ++MODULE_DESCRIPTION(DM_NAME " device-mapper target message parser"); ++MODULE_AUTHOR("Heinz Mauelshagen "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/md/dm-message.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (C) 2007,2008 Red Hat, Inc. All rights reserved. ++ * ++ * Module Author: Heinz Mauelshagen ++ * ++ * General device-mapper message interface argument parser. ++ * ++ * This file is released under the GPL. ++ * ++ */ ++ ++#ifndef DM_MESSAGE_H ++#define DM_MESSAGE_H ++ ++/* Factor out to dm.h. */ ++/* Reference to array end. */ ++#define ARRAY_END(a) ((a) + ARRAY_SIZE(a)) ++ ++/* Message return bits. */ ++enum dm_message_return { ++ dm_msg_ret_ambiguous, /* Action ambiguous. */ ++ dm_msg_ret_inval, /* Action invalid. */ ++ dm_msg_ret_undef, /* Action undefined. */ ++ ++ dm_msg_ret_option, /* Option error. */ ++ dm_msg_ret_arg, /* Argument error. */ ++ dm_msg_ret_argcount, /* Argument count error. */ ++}; ++ ++/* Message argument type conversions. */ ++enum dm_message_argument_type { ++ dm_msg_base_t, /* Basename string. */ ++ dm_msg_str_t, /* String. */ ++ dm_msg_int_t, /* Signed int. */ ++ dm_msg_uint_t, /* Unsigned int. */ ++ dm_msg_uint64_t, /* Unsigned int 64. */ ++}; ++ ++/* A message option. */ ++struct dm_message_option { ++ unsigned num_options; ++ char **options; ++ unsigned long *actions; ++}; ++ ++/* Message arguments and types. */ ++struct dm_message_argument { ++ unsigned num_args; ++ unsigned long **ptr; ++ enum dm_message_argument_type types[]; ++}; ++ ++/* Client message. */ ++struct dm_msg { ++ unsigned long action; /* Identified action. */ ++ unsigned long ret; /* Return bits. */ ++ unsigned num_specs; /* # of sepcifications listed. */ ++ struct dm_msg_spec *specs; /* Specification list. */ ++ struct dm_msg_spec *spec; /* Specification selected. */ ++}; ++ ++/* Secification of the message. */ ++struct dm_msg_spec { ++ const char *cmd; /* Name of the command (i.e. 'bandwidth'). */ ++ unsigned long action; ++ struct dm_message_option *options; ++ struct dm_message_argument *args; ++ unsigned long parm; /* Parameter to pass through to callback. */ ++ /* Function to process for action. */ ++ int (*f) (struct dm_msg *msg, void *context); ++}; ++ ++/* Parameter access macros. */ ++#define DM_MSG_PARM(msg) ((msg)->spec->parm) ++ ++#define DM_MSG_STR_ARGS(msg, idx) ((char *) *(msg)->spec->args->ptr[idx]) ++#define DM_MSG_INT_ARGS(msg, idx) ((int) *(msg)->spec->args->ptr[idx]) ++#define DM_MSG_UINT_ARGS(msg, idx) ((unsigned) DM_MSG_INT_ARG(msg, idx)) ++#define DM_MSG_UINT64_ARGS(msg, idx) ((uint64_t) *(msg)->spec->args->ptr[idx]) ++ ++#define DM_MSG_STR_ARG(msg) DM_MSG_STR_ARGS(msg, 0) ++#define DM_MSG_INT_ARG(msg) DM_MSG_INT_ARGS(msg, 0) ++#define DM_MSG_UINT_ARG(msg) DM_MSG_UINT_ARGS(msg, 0) ++#define DM_MSG_UINT64_ARG(msg) DM_MSG_UINT64_ARGS(msg, 0) ++ ++ ++/* Parse a message and its options and optionally call a function back. */ ++int dm_message_parse(const char *caller, struct dm_msg *msg, void *context, ++ int argc, char **argv); ++ ++#endif +--- /dev/null ++++ b/drivers/md/dm-raid45.c +@@ -0,0 +1,4516 @@ ++/* ++ * Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. ++ * ++ * Module Author: Heinz Mauelshagen ++ * ++ * This file is released under the GPL. ++ * ++ * ++ * Linux 2.6 Device Mapper RAID4 and RAID5 target. ++ * ++ * Supports: ++ * o RAID4 with dedicated and selectable parity device ++ * o RAID5 with rotating parity (left+right, symmetric+asymmetric) ++ * o run time optimization of xor algorithm used to calculate parity ++ * ++ * ++ * Thanks to MD for: ++ * o the raid address calculation algorithm ++ * o the base of the biovec <-> page list copier. ++ * ++ * ++ * Uses region hash to keep track of how many writes are in flight to ++ * regions in order to use dirty log to keep state of regions to recover: ++ * ++ * o clean regions (those which are synchronized ++ * and don't have write io in flight) ++ * o dirty regions (those with write io in flight) ++ * ++ * ++ * On startup, any dirty regions are migrated to the 'nosync' state ++ * and are subject to recovery by the daemon. ++ * ++ * See raid_ctr() for table definition. ++ * ++ * ++ * FIXME: ++ * o add virtual interface for locking ++ * o remove instrumentation (REMOVEME:) ++ * ++ */ ++ ++static const char *version = "v0.2431"; ++ ++#include "dm.h" ++#include "dm-bio-list.h" ++#include "dm-memcache.h" ++#include "dm-message.h" ++#include "dm-raid45.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* # of parallel recovered regions */ ++/* FIXME: cope with multiple recovery stripes in raid_set struct. */ ++#define MAX_RECOVER 1 /* needs to be 1! */ ++ ++/* ++ * Configurable parameters ++ */ ++#define INLINE ++ ++/* Default # of stripes if not set in constructor. */ ++#define STRIPES 64 ++ ++/* Minimum/maximum # of selectable stripes. */ ++#define STRIPES_MIN 8 ++#define STRIPES_MAX 16384 ++ ++/* Default chunk size in sectors if not set in constructor. */ ++#define CHUNK_SIZE 64 ++ ++/* Default io size in sectors if not set in constructor. */ ++#define IO_SIZE_MIN SECTORS_PER_PAGE ++#define IO_SIZE IO_SIZE_MIN ++ ++/* Maximum setable chunk size in sectors. */ ++#define CHUNK_SIZE_MAX 16384 ++ ++/* Recover io size default in sectors. */ ++#define RECOVER_IO_SIZE_MIN 64 ++#define RECOVER_IO_SIZE 256 ++ ++/* Default percentage recover io bandwidth. */ ++#define BANDWIDTH 10 ++#define BANDWIDTH_MIN 1 ++#define BANDWIDTH_MAX 100 ++/* ++ * END Configurable parameters ++ */ ++ ++#define TARGET "dm-raid45" ++#define DAEMON "kraid45d" ++#define DM_MSG_PREFIX TARGET ++ ++#define SECTORS_PER_PAGE (PAGE_SIZE >> SECTOR_SHIFT) ++ ++/* Amount/size for __xor(). */ ++#define SECTORS_PER_XOR SECTORS_PER_PAGE ++#define XOR_SIZE PAGE_SIZE ++ ++/* Derive raid_set from stripe_cache pointer. */ ++#define RS(x) container_of(x, struct raid_set, sc) ++ ++/* Check value in range. */ ++#define range_ok(i, min, max) (i >= min && i <= max) ++ ++/* Page reference. */ ++#define PAGE(stripe, p) ((stripe)->obj[p].pl->page) ++ ++/* Bio list reference. */ ++#define BL(stripe, p, rw) (stripe->ss[p].bl + rw) ++ ++/* Page list reference. */ ++#define PL(stripe, p) (stripe->obj[p].pl) ++ ++/* Check argument is power of 2. */ ++#define POWER_OF_2(a) (!(a & (a - 1))) ++ ++/* Factor out to dm-bio-list.h */ ++static inline void bio_list_push(struct bio_list *bl, struct bio *bio) ++{ ++ bio->bi_next = bl->head; ++ bl->head = bio; ++ ++ if (!bl->tail) ++ bl->tail = bio; ++} ++ ++/* Factor out to dm.h */ ++#define TI_ERR_RET(str, ret) \ ++ do { ti->error = DM_MSG_PREFIX ": " str; return ret; } while (0); ++#define TI_ERR(str) TI_ERR_RET(str, -EINVAL) ++ ++/*----------------------------------------------------------------- ++ * Stripe cache ++ * ++ * Cache for all reads and writes to raid sets (operational or degraded) ++ * ++ * We need to run all data to and from a RAID set through this cache, ++ * because parity chunks need to get calculated from data chunks ++ * or, in the degraded/resynchronization case, missing chunks need ++ * to be reconstructed using the other chunks of the stripe. ++ *---------------------------------------------------------------*/ ++/* Protect kmem cache # counter. */ ++static atomic_t _stripe_sc_nr = ATOMIC_INIT(-1); /* kmem cache # counter. */ ++ ++/* A stripe set (holds bios hanging off). */ ++struct stripe_set { ++ struct stripe *stripe; /* Backpointer to stripe for endio(). */ ++ struct bio_list bl[3]; /* Reads, writes, and writes merged. */ ++#define WRITE_MERGED 2 ++}; ++ ++#if READ != 0 || WRITE != 1 ++#error dm-raid45: READ/WRITE != 0/1 used as index!!! ++#endif ++ ++/* ++ * Stripe linked list indexes. Keep order, because the stripe ++ * and the stripe cache rely on the first 3! ++ */ ++enum list_types { ++ LIST_IO = 0, /* Stripes with io pending. */ ++ LIST_ENDIO, /* Stripes to endio. */ ++ LIST_LRU, /* Least recently used stripes. */ ++ LIST_HASH, /* Hashed stripes. */ ++ LIST_RECOVER = LIST_HASH, /* For recovery type stripes only. */ ++ NR_LISTS, /* To size array in struct stripe. */ ++}; ++ ++enum lock_types { ++ LOCK_ENDIO = 0, /* Protect endio list. */ ++ LOCK_LRU, /* Protect lru list. */ ++ NR_LOCKS, /* To size array in struct stripe_cache. */ ++}; ++ ++/* A stripe: the io object to handle all reads and writes to a RAID set. */ ++struct stripe { ++ struct stripe_cache *sc; /* Backpointer to stripe cache. */ ++ ++ sector_t key; /* Hash key. */ ++ sector_t region; /* Region stripe is mapped to. */ ++ ++ /* Reference count. */ ++ atomic_t cnt; ++ ++ struct { ++ unsigned long flags; /* flags (see below). */ ++ ++ /* ++ * Pending ios in flight: ++ * ++ * used as a 'lock' to control move of stripe to endio list ++ */ ++ atomic_t pending; /* Pending ios in flight. */ ++ ++ /* Sectors to read and write for multi page stripe sets. */ ++ unsigned size; ++ } io; ++ ++ /* Lock on stripe (for clustering). */ ++ void *lock; ++ ++ /* ++ * 4 linked lists: ++ * o io list to flush io ++ * o endio list ++ * o LRU list to put stripes w/o reference count on ++ * o stripe cache hash ++ */ ++ struct list_head lists[NR_LISTS]; ++ ++ struct { ++ unsigned short parity; /* Parity chunk index. */ ++ short recover; /* Recovery chunk index. */ ++ } idx; ++ ++ /* This sets memory cache object (dm-mem-cache). */ ++ struct dm_mem_cache_object *obj; ++ ++ /* Array of stripe sets (dynamically allocated). */ ++ struct stripe_set ss[0]; ++}; ++ ++/* States stripes can be in (flags field). */ ++enum stripe_states { ++ STRIPE_ACTIVE, /* Active io on stripe. */ ++ STRIPE_ERROR, /* io error on stripe. */ ++ STRIPE_MERGED, /* Writes got merged. */ ++ STRIPE_READ, /* Read. */ ++ STRIPE_RBW, /* Read-before-write. */ ++ STRIPE_RECONSTRUCT, /* reconstruct of a missing chunk required. */ ++ STRIPE_RECOVER, /* Stripe used for RAID set recovery. */ ++}; ++ ++/* ... and macros to access them. */ ++#define BITOPS(name, what, var, flag) \ ++static inline int TestClear ## name ## what(struct var *v) \ ++{ return test_and_clear_bit(flag, &v->io.flags); } \ ++static inline int TestSet ## name ## what(struct var *v) \ ++{ return test_and_set_bit(flag, &v->io.flags); } \ ++static inline void Clear ## name ## what(struct var *v) \ ++{ clear_bit(flag, &v->io.flags); } \ ++static inline void Set ## name ## what(struct var *v) \ ++{ set_bit(flag, &v->io.flags); } \ ++static inline int name ## what(struct var *v) \ ++{ return test_bit(flag, &v->io.flags); } ++ ++ ++BITOPS(Stripe, Active, stripe, STRIPE_ACTIVE) ++BITOPS(Stripe, Merged, stripe, STRIPE_MERGED) ++BITOPS(Stripe, Error, stripe, STRIPE_ERROR) ++BITOPS(Stripe, Read, stripe, STRIPE_READ) ++BITOPS(Stripe, RBW, stripe, STRIPE_RBW) ++BITOPS(Stripe, Reconstruct, stripe, STRIPE_RECONSTRUCT) ++BITOPS(Stripe, Recover, stripe, STRIPE_RECOVER) ++ ++/* A stripe hash. */ ++struct stripe_hash { ++ struct list_head *hash; ++ unsigned buckets; ++ unsigned mask; ++ unsigned prime; ++ unsigned shift; ++}; ++ ++/* A stripe cache. */ ++struct stripe_cache { ++ /* Stripe hash. */ ++ struct stripe_hash hash; ++ ++ /* Stripes with io to flush, stripes to endio and LRU lists. */ ++ struct list_head lists[3]; ++ ++ /* Locks to protect endio and lru lists. */ ++ spinlock_t locks[NR_LOCKS]; ++ ++ /* Slab cache to allocate stripes from. */ ++ struct { ++ struct kmem_cache *cache; /* Cache itself. */ ++ char name[32]; /* Unique name. */ ++ } kc; ++ ++ struct dm_io_client *dm_io_client; /* dm-io client resource context. */ ++ ++ /* dm-mem-cache client resource context. */ ++ struct dm_mem_cache_client *mem_cache_client; ++ ++ int stripes_parm; /* # stripes parameter from constructor. */ ++ atomic_t stripes; /* actual # of stripes in cache. */ ++ atomic_t stripes_to_shrink; /* # of stripes to shrink cache by. */ ++ atomic_t stripes_last; /* last # of stripes in cache. */ ++ atomic_t active_stripes; /* actual # of active stripes in cache. */ ++ ++ /* REMOVEME: */ ++ atomic_t max_active_stripes; /* actual # of active stripes in cache. */ ++}; ++ ++/* Flag specs for raid_dev */ ; ++enum raid_dev_flags { DEVICE_FAILED, IO_QUEUED }; ++ ++/* The raid device in a set. */ ++struct raid_dev { ++ struct dm_dev *dev; ++ unsigned long flags; /* raid_dev_flags. */ ++ sector_t start; /* offset to map to. */ ++}; ++ ++/* Flags spec for raid_set. */ ++enum raid_set_flags { ++ RS_CHECK_OVERWRITE, /* Check for chunk overwrites. */ ++ RS_DEAD, /* RAID set inoperational. */ ++ RS_DEVEL_STATS, /* REMOVEME: display status information. */ ++ RS_IO_ERROR, /* io error on set. */ ++ RS_RECOVER, /* Do recovery. */ ++ RS_RECOVERY_BANDWIDTH, /* Allow recovery bandwidth (delayed bios). */ ++ RS_REGION_GET, /* get a region to recover. */ ++ RS_SC_BUSY, /* stripe cache busy -> send an event. */ ++ RS_SUSPENDED, /* RAID set suspendedn. */ ++}; ++ ++/* REMOVEME: devel stats counters. */ ++enum stats_types { ++ S_BIOS_READ, ++ S_BIOS_ADDED_READ, ++ S_BIOS_ENDIO_READ, ++ S_BIOS_WRITE, ++ S_BIOS_ADDED_WRITE, ++ S_BIOS_ENDIO_WRITE, ++ S_CAN_MERGE, ++ S_CANT_MERGE, ++ S_CONGESTED, ++ S_DM_IO_READ, ++ S_DM_IO_WRITE, ++ S_ACTIVE_READS, ++ S_BANDWIDTH, ++ S_BARRIER, ++ S_BIO_COPY_PL_NEXT, ++ S_DEGRADED, ++ S_DELAYED_BIOS, ++ S_EVICT, ++ S_FLUSHS, ++ S_HITS_1ST, ++ S_IOS_POST, ++ S_INSCACHE, ++ S_MAX_LOOKUP, ++ S_MERGE_PAGE_LOCKED, ++ S_NO_BANDWIDTH, ++ S_NOT_CONGESTED, ++ S_NO_RW, ++ S_NOSYNC, ++ S_PROHIBITPAGEIO, ++ S_RECONSTRUCT_EI, ++ S_RECONSTRUCT_DEV, ++ S_REDO, ++ S_REQUEUE, ++ S_STRIPE_ERROR, ++ S_SUM_DELAYED_BIOS, ++ S_XORS, ++ S_NR_STATS, /* # of stats counters. */ ++}; ++ ++/* Status type -> string mappings. */ ++struct stats_map { ++ const enum stats_types type; ++ const char *str; ++}; ++ ++static struct stats_map stats_map[] = { ++ { S_BIOS_READ, "r=" }, ++ { S_BIOS_ADDED_READ, "/" }, ++ { S_BIOS_ENDIO_READ, "/" }, ++ { S_BIOS_WRITE, " w=" }, ++ { S_BIOS_ADDED_WRITE, "/" }, ++ { S_BIOS_ENDIO_WRITE, "/" }, ++ { S_DM_IO_READ, " rc=" }, ++ { S_DM_IO_WRITE, " wc=" }, ++ { S_ACTIVE_READS, " active_reads=" }, ++ { S_BANDWIDTH, " bandwidth=" }, ++ { S_NO_BANDWIDTH, " no_bandwidth=" }, ++ { S_BARRIER, " barrier=" }, ++ { S_BIO_COPY_PL_NEXT, " bio_copy_pl_next=" }, ++ { S_CAN_MERGE, " can_merge=" }, ++ { S_MERGE_PAGE_LOCKED, "/page_locked=" }, ++ { S_CANT_MERGE, "/cant_merge=" }, ++ { S_CONGESTED, " congested=" }, ++ { S_NOT_CONGESTED, "/not_congested=" }, ++ { S_DEGRADED, " degraded=" }, ++ { S_DELAYED_BIOS, " delayed_bios=" }, ++ { S_SUM_DELAYED_BIOS, "/sum_delayed_bios=" }, ++ { S_EVICT, " evict=" }, ++ { S_FLUSHS, " flushs=" }, ++ { S_HITS_1ST, " hits_1st=" }, ++ { S_IOS_POST, " ios_post=" }, ++ { S_INSCACHE, " inscache=" }, ++ { S_MAX_LOOKUP, " max_lookup=" }, ++ { S_NO_RW, " no_rw=" }, ++ { S_NOSYNC, " nosync=" }, ++ { S_PROHIBITPAGEIO, " ProhibitPageIO=" }, ++ { S_RECONSTRUCT_EI, " reconstruct_ei=" }, ++ { S_RECONSTRUCT_DEV, " reconstruct_dev=" }, ++ { S_REDO, " redo=" }, ++ { S_REQUEUE, " requeue=" }, ++ { S_STRIPE_ERROR, " stripe_error=" }, ++ { S_XORS, " xors=" }, ++}; ++ ++/* ++ * A RAID set. ++ */ ++typedef void (*xor_function_t)(unsigned count, unsigned long **data); ++struct raid_set { ++ struct dm_target *ti; /* Target pointer. */ ++ ++ struct { ++ unsigned long flags; /* State flags. */ ++ spinlock_t in_lock; /* Protects central input list below. */ ++ struct bio_list in; /* Pending ios (central input list). */ ++ struct bio_list work; /* ios work set. */ ++ wait_queue_head_t suspendq; /* suspend synchronization. */ ++ atomic_t in_process; /* counter of queued bios (suspendq). */ ++ atomic_t in_process_max;/* counter of queued bios max. */ ++ ++ /* io work. */ ++ struct workqueue_struct *wq; ++ struct delayed_work dws; ++ } io; ++ ++ /* External locking. */ ++ struct dm_raid45_locking_type *locking; ++ ++ struct stripe_cache sc; /* Stripe cache for this set. */ ++ ++ /* Xor optimization. */ ++ struct { ++ struct xor_func *f; ++ unsigned chunks; ++ unsigned speed; ++ } xor; ++ ++ /* Recovery parameters. */ ++ struct recover { ++ struct dm_dirty_log *dl; /* Dirty log. */ ++ struct dm_rh_client *rh; /* Region hash. */ ++ ++ /* dm-mem-cache client resource context for recovery stripes. */ ++ struct dm_mem_cache_client *mem_cache_client; ++ ++ struct list_head stripes; /* List of recovery stripes. */ ++ ++ region_t nr_regions; ++ region_t nr_regions_to_recover; ++ region_t nr_regions_recovered; ++ unsigned long start_jiffies; ++ unsigned long end_jiffies; ++ ++ unsigned bandwidth; /* Recovery bandwidth [%]. */ ++ unsigned bandwidth_work; /* Recovery bandwidth [factor]. */ ++ unsigned bandwidth_parm; /* " constructor parm. */ ++ unsigned io_size; /* io size <= chunk size. */ ++ unsigned io_size_parm; /* io size ctr parameter. */ ++ ++ /* recovery io throttling. */ ++ atomic_t io_count[2]; /* counter recover/regular io. */ ++ unsigned long last_jiffies; ++ ++ struct dm_region *reg; /* Actual region to recover. */ ++ sector_t pos; /* Position within region to recover. */ ++ sector_t end; /* End of region to recover. */ ++ } recover; ++ ++ /* RAID set parameters. */ ++ struct { ++ struct raid_type *raid_type; /* RAID type (eg, RAID4). */ ++ unsigned raid_parms; /* # variable raid parameters. */ ++ ++ unsigned chunk_size; /* Sectors per chunk. */ ++ unsigned chunk_size_parm; ++ unsigned chunk_mask; /* Mask for amount. */ ++ unsigned chunk_shift; /* rsector chunk size shift. */ ++ ++ unsigned io_size; /* Sectors per io. */ ++ unsigned io_size_parm; ++ unsigned io_mask; /* Mask for amount. */ ++ unsigned io_shift_mask; /* Mask for raid_address(). */ ++ unsigned io_shift; /* rsector io size shift. */ ++ unsigned pages_per_io; /* Pages per io. */ ++ ++ sector_t sectors_per_dev; /* Sectors per device. */ ++ ++ atomic_t failed_devs; /* Amount of devices failed. */ ++ ++ /* Index of device to initialize. */ ++ int dev_to_init; ++ int dev_to_init_parm; ++ ++ /* Raid devices dynamically allocated. */ ++ unsigned raid_devs; /* # of RAID devices below. */ ++ unsigned data_devs; /* # of RAID data devices. */ ++ ++ int ei; /* index of failed RAID device. */ ++ ++ /* index of dedicated parity device (i.e. RAID4). */ ++ int pi; ++ int pi_parm; /* constructor parm for status output. */ ++ } set; ++ ++ /* REMOVEME: devel stats counters. */ ++ atomic_t stats[S_NR_STATS]; ++ ++ /* Dynamically allocated temporary pointers for xor(). */ ++ unsigned long **data; ++ ++ /* Dynamically allocated RAID devices. Alignment? */ ++ struct raid_dev dev[0]; ++}; ++ ++ ++BITOPS(RS, Bandwidth, raid_set, RS_RECOVERY_BANDWIDTH) ++BITOPS(RS, CheckOverwrite, raid_set, RS_CHECK_OVERWRITE) ++BITOPS(RS, Dead, raid_set, RS_DEAD) ++BITOPS(RS, DevelStats, raid_set, RS_DEVEL_STATS) ++BITOPS(RS, IoError, raid_set, RS_IO_ERROR) ++BITOPS(RS, Recover, raid_set, RS_RECOVER) ++BITOPS(RS, RegionGet, raid_set, RS_REGION_GET) ++BITOPS(RS, ScBusy, raid_set, RS_SC_BUSY) ++BITOPS(RS, Suspended, raid_set, RS_SUSPENDED) ++#undef BITOPS ++ ++#define PageIO(page) PageChecked(page) ++#define AllowPageIO(page) SetPageChecked(page) ++#define ProhibitPageIO(page) ClearPageChecked(page) ++ ++/*----------------------------------------------------------------- ++ * Raid-4/5 set structures. ++ *---------------------------------------------------------------*/ ++/* RAID level definitions. */ ++enum raid_level { ++ raid4, ++ raid5, ++}; ++ ++/* Symmetric/Asymmetric, Left/Right parity rotating algorithms. */ ++enum raid_algorithm { ++ none, ++ left_asym, ++ right_asym, ++ left_sym, ++ right_sym, ++}; ++ ++struct raid_type { ++ const char *name; /* RAID algorithm. */ ++ const char *descr; /* Descriptor text for logging. */ ++ const unsigned parity_devs; /* # of parity devices. */ ++ const unsigned minimal_devs; /* minimal # of devices in set. */ ++ const enum raid_level level; /* RAID level. */ ++ const enum raid_algorithm algorithm; /* RAID algorithm. */ ++}; ++ ++/* Supported raid types and properties. */ ++static struct raid_type raid_types[] = { ++ {"raid4", "RAID4 (dedicated parity disk)", 1, 3, raid4, none}, ++ {"raid5_la", "RAID5 (left asymmetric)", 1, 3, raid5, left_asym}, ++ {"raid5_ra", "RAID5 (right asymmetric)", 1, 3, raid5, right_asym}, ++ {"raid5_ls", "RAID5 (left symmetric)", 1, 3, raid5, left_sym}, ++ {"raid5_rs", "RAID5 (right symmetric)", 1, 3, raid5, right_sym}, ++}; ++ ++/* Address as calculated by raid_address(). */ ++struct address { ++ sector_t key; /* Hash key (start address of stripe). */ ++ unsigned di, pi; /* Data and parity disks index. */ ++}; ++ ++/* REMOVEME: reset statistics counters. */ ++static void stats_reset(struct raid_set *rs) ++{ ++ unsigned s = S_NR_STATS; ++ ++ while (s--) ++ atomic_set(rs->stats + s, 0); ++} ++ ++/*---------------------------------------------------------------- ++ * RAID set management routines. ++ *--------------------------------------------------------------*/ ++/* ++ * Begin small helper functions. ++ */ ++/* Queue (optionally delayed) io work. */ ++static void wake_do_raid_delayed(struct raid_set *rs, unsigned long delay) ++{ ++ struct delayed_work *dws = &rs->io.dws; ++ ++ cancel_delayed_work(dws); ++ queue_delayed_work(rs->io.wq, dws, delay); ++} ++ ++/* Queue io work immediately (called from region hash too). */ ++static INLINE void wake_do_raid(void *context) ++{ ++ wake_do_raid_delayed(context, 0); ++} ++ ++/* Wait until all io has been processed. */ ++static INLINE void wait_ios(struct raid_set *rs) ++{ ++ wait_event(rs->io.suspendq, !atomic_read(&rs->io.in_process)); ++} ++ ++/* Declare io queued to device. */ ++static INLINE void io_dev_queued(struct raid_dev *dev) ++{ ++ set_bit(IO_QUEUED, &dev->flags); ++} ++ ++/* Io on device and reset ? */ ++static inline int io_dev_clear(struct raid_dev *dev) ++{ ++ return test_and_clear_bit(IO_QUEUED, &dev->flags); ++} ++ ++/* Get an io reference. */ ++static INLINE void io_get(struct raid_set *rs) ++{ ++ int p = atomic_inc_return(&rs->io.in_process); ++ ++ if (p > atomic_read(&rs->io.in_process_max)) ++ atomic_set(&rs->io.in_process_max, p); /* REMOVEME: max. */ ++} ++ ++/* Put the io reference and conditionally wake io waiters. */ ++static INLINE void io_put(struct raid_set *rs) ++{ ++ /* Intel: rebuild data corrupter? */ ++ if (!atomic_read(&rs->io.in_process)) { ++ DMERR("%s would go negative!!!", __func__); ++ return; ++ } ++ ++ if (atomic_dec_and_test(&rs->io.in_process)) ++ wake_up(&rs->io.suspendq); ++} ++ ++/* Calculate device sector offset. */ ++static INLINE sector_t _sector(struct raid_set *rs, struct bio *bio) ++{ ++ sector_t sector = bio->bi_sector; ++ ++ sector_div(sector, rs->set.data_devs); ++ return sector; ++} ++ ++/* Test device operational. */ ++static INLINE int dev_operational(struct raid_set *rs, unsigned p) ++{ ++ return !test_bit(DEVICE_FAILED, &rs->dev[p].flags); ++} ++ ++/* Return # of active stripes in stripe cache. */ ++static INLINE int sc_active(struct stripe_cache *sc) ++{ ++ return atomic_read(&sc->active_stripes); ++} ++ ++/* Test io pending on stripe. */ ++static INLINE int stripe_io(struct stripe *stripe) ++{ ++ return atomic_read(&stripe->io.pending); ++} ++ ++static INLINE void stripe_io_inc(struct stripe *stripe) ++{ ++ atomic_inc(&stripe->io.pending); ++} ++ ++static INLINE void stripe_io_dec(struct stripe *stripe) ++{ ++ atomic_dec(&stripe->io.pending); ++} ++ ++/* Wrapper needed by for_each_io_dev(). */ ++static void _stripe_io_inc(struct stripe *stripe, unsigned p) ++{ ++ stripe_io_inc(stripe); ++} ++ ++/* Error a stripe. */ ++static INLINE void stripe_error(struct stripe *stripe, struct page *page) ++{ ++ SetStripeError(stripe); ++ SetPageError(page); ++ atomic_inc(RS(stripe->sc)->stats + S_STRIPE_ERROR); ++} ++ ++/* Page IOed ok. */ ++enum dirty_type { CLEAN, DIRTY }; ++static INLINE void page_set(struct page *page, enum dirty_type type) ++{ ++ switch (type) { ++ case DIRTY: ++ SetPageDirty(page); ++ AllowPageIO(page); ++ break; ++ ++ case CLEAN: ++ ClearPageDirty(page); ++ break; ++ ++ default: ++ BUG(); ++ } ++ ++ SetPageUptodate(page); ++ ClearPageError(page); ++} ++ ++/* Return region state for a sector. */ ++static INLINE int ++region_state(struct raid_set *rs, sector_t sector, unsigned long state) ++{ ++ struct dm_rh_client *rh = rs->recover.rh; ++ ++ return RSRecover(rs) ? ++ (dm_rh_get_state(rh, dm_rh_sector_to_region(rh, sector), 1) & ++ state) : 0; ++} ++ ++/* Check maximum devices which may fail in a raid set. */ ++static inline int raid_set_degraded(struct raid_set *rs) ++{ ++ return RSIoError(rs); ++} ++ ++/* Check # of devices which may fail in a raid set. */ ++static INLINE int raid_set_operational(struct raid_set *rs) ++{ ++ /* Too many failed devices -> BAD. */ ++ return atomic_read(&rs->set.failed_devs) <= ++ rs->set.raid_type->parity_devs; ++} ++ ++/* ++ * Return true in case a page_list should be read/written ++ * ++ * Conditions to read/write: ++ * o 1st page in list not uptodate ++ * o 1st page in list dirty ++ * o if we optimized io away, we flag it using the pages checked bit. ++ */ ++static INLINE unsigned page_io(struct page *page) ++{ ++ /* Optimization: page was flagged to need io during first run. */ ++ if (PagePrivate(page)) { ++ ClearPagePrivate(page); ++ return 1; ++ } ++ ++ /* Avoid io if prohibited or a locked page. */ ++ if (!PageIO(page) || PageLocked(page)) ++ return 0; ++ ++ if (!PageUptodate(page) || PageDirty(page)) { ++ /* Flag page needs io for second run optimization. */ ++ SetPagePrivate(page); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Call a function on each page list needing io. */ ++static INLINE unsigned ++for_each_io_dev(struct raid_set *rs, struct stripe *stripe, ++ void (*f_io)(struct stripe *stripe, unsigned p)) ++{ ++ unsigned p = rs->set.raid_devs, r = 0; ++ ++ while (p--) { ++ if (page_io(PAGE(stripe, p))) { ++ f_io(stripe, p); ++ r++; ++ } ++ } ++ ++ return r; ++} ++ ++/* Reconstruct a particular device ?. */ ++static INLINE int dev_to_init(struct raid_set *rs) ++{ ++ return rs->set.dev_to_init > -1; ++} ++ ++/* ++ * Index of device to calculate parity on. ++ * Either the parity device index *or* the selected device to init ++ * after a spare replacement. ++ */ ++static INLINE unsigned dev_for_parity(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ ++ return dev_to_init(rs) ? rs->set.dev_to_init : stripe->idx.parity; ++} ++ ++/* Return the index of the device to be recovered. */ ++static int idx_get(struct raid_set *rs) ++{ ++ /* Avoid to read in the pages to be reconstructed anyway. */ ++ if (dev_to_init(rs)) ++ return rs->set.dev_to_init; ++ else if (rs->set.raid_type->level == raid4) ++ return rs->set.pi; ++ ++ return -1; ++} ++ ++/* RAID set congested function. */ ++static int raid_set_congested(void *congested_data, int bdi_bits) ++{ ++ struct raid_set *rs = congested_data; ++ int r = 0; /* Assume uncongested. */ ++ unsigned p = rs->set.raid_devs; ++ ++ /* If any of our component devices are overloaded. */ ++ while (p--) { ++ struct request_queue *q = bdev_get_queue(rs->dev[p].dev->bdev); ++ ++ r |= bdi_congested(&q->backing_dev_info, bdi_bits); ++ } ++ ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + (r ? S_CONGESTED : S_NOT_CONGESTED)); ++ return r; ++} ++ ++/* Display RAID set dead message once. */ ++static void raid_set_dead(struct raid_set *rs) ++{ ++ if (!TestSetRSDead(rs)) { ++ unsigned p; ++ char buf[BDEVNAME_SIZE]; ++ ++ DMERR("FATAL: too many devices failed -> RAID set dead"); ++ ++ for (p = 0; p < rs->set.raid_devs; p++) { ++ if (!dev_operational(rs, p)) ++ DMERR("device /dev/%s failed", ++ bdevname(rs->dev[p].dev->bdev, buf)); ++ } ++ } ++} ++ ++/* RAID set degrade check. */ ++static INLINE int ++raid_set_check_and_degrade(struct raid_set *rs, ++ struct stripe *stripe, unsigned p) ++{ ++ if (test_and_set_bit(DEVICE_FAILED, &rs->dev[p].flags)) ++ return -EPERM; ++ ++ /* Through an event in case of member device errors. */ ++ dm_table_event(rs->ti->table); ++ atomic_inc(&rs->set.failed_devs); ++ ++ /* Only log the first member error. */ ++ if (!TestSetRSIoError(rs)) { ++ char buf[BDEVNAME_SIZE]; ++ ++ /* Store index for recovery. */ ++ mb(); ++ rs->set.ei = p; ++ mb(); ++ ++ DMERR("CRITICAL: %sio error on device /dev/%s " ++ "in region=%llu; DEGRADING RAID set", ++ stripe ? "" : "FAKED ", ++ bdevname(rs->dev[p].dev->bdev, buf), ++ (unsigned long long) (stripe ? stripe->key : 0)); ++ DMERR("further device error messages suppressed"); ++ } ++ ++ return 0; ++} ++ ++static void ++raid_set_check_degrade(struct raid_set *rs, struct stripe *stripe) ++{ ++ unsigned p = rs->set.raid_devs; ++ ++ while (p--) { ++ struct page *page = PAGE(stripe, p); ++ ++ if (PageError(page)) { ++ ClearPageError(page); ++ raid_set_check_and_degrade(rs, stripe, p); ++ } ++ } ++} ++ ++/* RAID set upgrade check. */ ++static int raid_set_check_and_upgrade(struct raid_set *rs, unsigned p) ++{ ++ if (!test_and_clear_bit(DEVICE_FAILED, &rs->dev[p].flags)) ++ return -EPERM; ++ ++ if (atomic_dec_and_test(&rs->set.failed_devs)) { ++ ClearRSIoError(rs); ++ rs->set.ei = -1; ++ } ++ ++ return 0; ++} ++ ++/* Lookup a RAID device by name or by major:minor number. */ ++union dev_lookup { ++ const char *dev_name; ++ struct raid_dev *dev; ++}; ++enum lookup_type { byname, bymajmin, bynumber }; ++static int raid_dev_lookup(struct raid_set *rs, enum lookup_type by, ++ union dev_lookup *dl) ++{ ++ unsigned p; ++ ++ /* ++ * Must be an incremental loop, because the device array ++ * can have empty slots still on calls from raid_ctr() ++ */ ++ for (p = 0; p < rs->set.raid_devs; p++) { ++ char buf[BDEVNAME_SIZE]; ++ struct raid_dev *dev = rs->dev + p; ++ ++ if (!dev->dev) ++ break; ++ ++ /* Format dev string appropriately if necessary. */ ++ if (by == byname) ++ bdevname(dev->dev->bdev, buf); ++ else if (by == bymajmin) ++ format_dev_t(buf, dev->dev->bdev->bd_dev); ++ ++ /* Do the actual check. */ ++ if (by == bynumber) { ++ if (dl->dev->dev->bdev->bd_dev == ++ dev->dev->bdev->bd_dev) ++ return p; ++ } else if (!strcmp(dl->dev_name, buf)) ++ return p; ++ } ++ ++ return -ENODEV; ++} ++ ++/* End io wrapper. */ ++static INLINE void ++_bio_endio(struct raid_set *rs, struct bio *bio, int error) ++{ ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + (bio_data_dir(bio) == WRITE ? ++ S_BIOS_ENDIO_WRITE : S_BIOS_ENDIO_READ)); ++ bio_endio(bio, error); ++ io_put(rs); /* Wake any suspend waiters. */ ++} ++ ++/* ++ * End small helper functions. ++ */ ++ ++ ++/* ++ * Stripe hash functions ++ */ ++/* Initialize/destroy stripe hash. */ ++static int hash_init(struct stripe_hash *hash, unsigned stripes) ++{ ++ unsigned buckets = 2, max_buckets = stripes / 4; ++ unsigned hash_primes[] = { ++ /* Table of primes for hash_fn/table size optimization. */ ++ 3, 7, 13, 27, 53, 97, 193, 389, 769, ++ 1543, 3079, 6151, 12289, 24593, ++ }; ++ ++ /* Calculate number of buckets (2^^n <= stripes / 4). */ ++ while (buckets < max_buckets) ++ buckets <<= 1; ++ ++ /* Allocate stripe hash. */ ++ hash->hash = vmalloc(buckets * sizeof(*hash->hash)); ++ if (!hash->hash) ++ return -ENOMEM; ++ ++ hash->buckets = buckets; ++ hash->mask = buckets - 1; ++ hash->shift = ffs(buckets); ++ if (hash->shift > ARRAY_SIZE(hash_primes) + 1) ++ hash->shift = ARRAY_SIZE(hash_primes) + 1; ++ ++ BUG_ON(hash->shift - 2 > ARRAY_SIZE(hash_primes) + 1); ++ hash->prime = hash_primes[hash->shift - 2]; ++ ++ /* Initialize buckets. */ ++ while (buckets--) ++ INIT_LIST_HEAD(hash->hash + buckets); ++ ++ return 0; ++} ++ ++static INLINE void hash_exit(struct stripe_hash *hash) ++{ ++ if (hash->hash) { ++ vfree(hash->hash); ++ hash->hash = NULL; ++ } ++} ++ ++/* List add (head/tail/locked/unlocked) inlines. */ ++enum list_lock_type { LIST_LOCKED, LIST_UNLOCKED }; ++#define LIST_DEL(name, list) \ ++static void stripe_ ## name ## _del(struct stripe *stripe, \ ++ enum list_lock_type lock) { \ ++ struct list_head *lh = stripe->lists + (list); \ ++ spinlock_t *l = NULL; \ ++\ ++ if (lock == LIST_LOCKED) { \ ++ l = stripe->sc->locks + LOCK_LRU; \ ++ spin_lock_irq(l); \ ++ } \ ++\ ++\ ++ if (!list_empty(lh)) \ ++ list_del_init(lh); \ ++\ ++ if (lock == LIST_LOCKED) \ ++ spin_unlock_irq(l); \ ++} ++ ++LIST_DEL(hash, LIST_HASH) ++LIST_DEL(lru, LIST_LRU) ++#undef LIST_DEL ++ ++enum list_pos_type { POS_HEAD, POS_TAIL }; ++#define LIST_ADD(name, list) \ ++static void stripe_ ## name ## _add(struct stripe *stripe, \ ++ enum list_pos_type pos, \ ++ enum list_lock_type lock) { \ ++ struct list_head *lh = stripe->lists + (list); \ ++ struct stripe_cache *sc = stripe->sc; \ ++ spinlock_t *l = NULL; \ ++\ ++ if (lock == LIST_LOCKED) { \ ++ l = sc->locks + LOCK_LRU; \ ++ spin_lock_irq(l); \ ++ } \ ++\ ++ if (list_empty(lh)) { \ ++ if (pos == POS_HEAD) \ ++ list_add(lh, sc->lists + (list)); \ ++ else \ ++ list_add_tail(lh, sc->lists + (list)); \ ++ } \ ++\ ++ if (lock == LIST_LOCKED) \ ++ spin_unlock_irq(l); \ ++} ++ ++LIST_ADD(endio, LIST_ENDIO) ++LIST_ADD(io, LIST_IO) ++LIST_ADD(lru, LIST_LRU) ++#undef LIST_ADD ++ ++#define POP(list) \ ++ do { \ ++ if (list_empty(sc->lists + list)) \ ++ stripe = NULL; \ ++ else { \ ++ stripe = list_first_entry(&sc->lists[list], \ ++ struct stripe, \ ++ lists[list]); \ ++ list_del_init(&stripe->lists[list]); \ ++ } \ ++ } while (0); ++ ++/* Pop an available stripe off the lru list. */ ++static struct stripe *stripe_lru_pop(struct stripe_cache *sc) ++{ ++ struct stripe *stripe; ++ spinlock_t *lock = sc->locks + LOCK_LRU; ++ ++ spin_lock_irq(lock); ++ POP(LIST_LRU); ++ spin_unlock_irq(lock); ++ ++ if (stripe) ++ /* Remove from hash before reuse. */ ++ stripe_hash_del(stripe, LIST_UNLOCKED); ++ ++ return stripe; ++} ++ ++static inline unsigned hash_fn(struct stripe_hash *hash, sector_t key) ++{ ++ return (unsigned) (((key * hash->prime) >> hash->shift) & hash->mask); ++} ++ ++static inline struct list_head * ++hash_bucket(struct stripe_hash *hash, sector_t key) ++{ ++ return hash->hash + hash_fn(hash, key); ++} ++ ++/* Insert an entry into a hash. */ ++static inline void hash_insert(struct stripe_hash *hash, struct stripe *stripe) ++{ ++ list_add(stripe->lists + LIST_HASH, hash_bucket(hash, stripe->key)); ++} ++ ++/* Insert an entry into the stripe hash. */ ++static inline void ++sc_insert(struct stripe_cache *sc, struct stripe *stripe) ++{ ++ hash_insert(&sc->hash, stripe); ++} ++ ++/* Lookup an entry in the stripe hash. */ ++static inline struct stripe * ++stripe_lookup(struct stripe_cache *sc, sector_t key) ++{ ++ unsigned c = 0; ++ struct stripe *stripe; ++ struct list_head *bucket = hash_bucket(&sc->hash, key); ++ ++ list_for_each_entry(stripe, bucket, lists[LIST_HASH]) { ++ /* REMOVEME: statisics. */ ++ if (++c > atomic_read(RS(sc)->stats + S_MAX_LOOKUP)) ++ atomic_set(RS(sc)->stats + S_MAX_LOOKUP, c); ++ ++ if (stripe->key == key) ++ return stripe; ++ } ++ ++ return NULL; ++} ++ ++/* Resize the stripe cache hash on size changes. */ ++static int hash_resize(struct stripe_cache *sc) ++{ ++ /* Resize threshold reached? */ ++ if (atomic_read(&sc->stripes) > 2 * atomic_read(&sc->stripes_last) ++ || atomic_read(&sc->stripes) < atomic_read(&sc->stripes_last) / 4) { ++ int r; ++ struct stripe_hash hash, hash_tmp; ++ spinlock_t *lock; ++ ++ r = hash_init(&hash, atomic_read(&sc->stripes)); ++ if (r) ++ return r; ++ ++ lock = sc->locks + LOCK_LRU; ++ spin_lock_irq(lock); ++ if (sc->hash.hash) { ++ unsigned b = sc->hash.buckets; ++ struct list_head *pos, *tmp; ++ ++ /* Walk old buckets and insert into new. */ ++ while (b--) { ++ list_for_each_safe(pos, tmp, sc->hash.hash + b) ++ hash_insert(&hash, ++ list_entry(pos, struct stripe, ++ lists[LIST_HASH])); ++ } ++ ++ } ++ ++ memcpy(&hash_tmp, &sc->hash, sizeof(hash_tmp)); ++ memcpy(&sc->hash, &hash, sizeof(sc->hash)); ++ atomic_set(&sc->stripes_last, atomic_read(&sc->stripes)); ++ spin_unlock_irq(lock); ++ ++ hash_exit(&hash_tmp); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Stripe cache locking functions ++ */ ++/* Dummy lock function for local RAID4+5. */ ++static void *no_lock(sector_t key, enum dm_lock_type type) ++{ ++ return &no_lock; ++} ++ ++/* Dummy unlock function for local RAID4+5. */ ++static void no_unlock(void *lock_handle) ++{ ++} ++ ++/* No locking (for local RAID 4+5). */ ++static struct dm_raid45_locking_type locking_none = { ++ .lock = no_lock, ++ .unlock = no_unlock, ++}; ++ ++/* Clustered RAID 4+5. */ ++/* FIXME: code this. */ ++static struct dm_raid45_locking_type locking_cluster = { ++ .lock = no_lock, ++ .unlock = no_unlock, ++}; ++ ++/* Lock a stripe (for clustering). */ ++static int ++stripe_lock(struct raid_set *rs, struct stripe *stripe, int rw, sector_t key) ++{ ++ stripe->lock = rs->locking->lock(key, rw == READ ? DM_RAID45_SHARED : ++ DM_RAID45_EX); ++ return stripe->lock ? 0 : -EPERM; ++} ++ ++/* Unlock a stripe (for clustering). */ ++static void stripe_unlock(struct raid_set *rs, struct stripe *stripe) ++{ ++ rs->locking->unlock(stripe->lock); ++ stripe->lock = NULL; ++} ++ ++/* ++ * Stripe cache functions. ++ */ ++/* ++ * Invalidate all page lists pages of a stripe. ++ * ++ * I only keep state for the whole list in the first page. ++ */ ++static INLINE void ++stripe_pages_invalidate(struct stripe *stripe) ++{ ++ unsigned p = RS(stripe->sc)->set.raid_devs; ++ ++ while (p--) { ++ struct page *page = PAGE(stripe, p); ++ ++ ProhibitPageIO(page); ++ ClearPageChecked(page); ++ ClearPageDirty(page); ++ ClearPageError(page); ++ clear_page_locked(page); ++ ClearPagePrivate(page); ++ ClearPageUptodate(page); ++ } ++} ++ ++/* Prepare stripe for (re)use. */ ++static INLINE void stripe_invalidate(struct stripe *stripe) ++{ ++ stripe->io.flags = 0; ++ stripe_pages_invalidate(stripe); ++} ++ ++/* Allow io on all chunks of a stripe. */ ++static INLINE void stripe_allow_io(struct stripe *stripe) ++{ ++ unsigned p = RS(stripe->sc)->set.raid_devs; ++ ++ while (p--) ++ AllowPageIO(PAGE(stripe, p)); ++} ++ ++/* Initialize a stripe. */ ++static void ++stripe_init(struct stripe_cache *sc, struct stripe *stripe) ++{ ++ unsigned p = RS(sc)->set.raid_devs; ++ unsigned i; ++ ++ /* Work all io chunks. */ ++ while (p--) { ++ struct stripe_set *ss = stripe->ss + p; ++ ++ stripe->obj[p].private = ss; ++ ss->stripe = stripe; ++ ++ i = ARRAY_SIZE(ss->bl); ++ while (i--) ++ bio_list_init(ss->bl + i); ++ } ++ ++ stripe->sc = sc; ++ ++ i = ARRAY_SIZE(stripe->lists); ++ while (i--) ++ INIT_LIST_HEAD(stripe->lists + i); ++ ++ atomic_set(&stripe->cnt, 0); ++ atomic_set(&stripe->io.pending, 0); ++ ++ stripe_invalidate(stripe); ++} ++ ++/* Number of pages per chunk. */ ++static inline unsigned chunk_pages(unsigned io_size) ++{ ++ return dm_div_up(io_size, SECTORS_PER_PAGE); ++} ++ ++/* Number of pages per stripe. */ ++static inline unsigned stripe_pages(struct raid_set *rs, unsigned io_size) ++{ ++ return chunk_pages(io_size) * rs->set.raid_devs; ++} ++ ++/* Initialize part of page_list (recovery). */ ++static INLINE void stripe_zero_pl_part(struct stripe *stripe, unsigned p, ++ unsigned start, unsigned count) ++{ ++ unsigned pages = chunk_pages(count); ++ /* Get offset into the page_list. */ ++ struct page_list *pl = pl_elem(PL(stripe, p), start / SECTORS_PER_PAGE); ++ ++ BUG_ON(!pl); ++ while (pl && pages--) { ++ BUG_ON(!pl->page); ++ memset(page_address(pl->page), 0, PAGE_SIZE); ++ pl = pl->next; ++ } ++} ++ ++/* Initialize parity chunk of stripe. */ ++static INLINE void stripe_zero_chunk(struct stripe *stripe, unsigned p) ++{ ++ stripe_zero_pl_part(stripe, p, 0, stripe->io.size); ++} ++ ++/* Return dynamic stripe structure size. */ ++static INLINE size_t stripe_size(struct raid_set *rs) ++{ ++ return sizeof(struct stripe) + ++ rs->set.raid_devs * sizeof(struct stripe_set); ++} ++ ++/* Allocate a stripe and its memory object. */ ++/* XXX adjust to cope with stripe cache and recovery stripe caches. */ ++enum grow { SC_GROW, SC_KEEP }; ++static struct stripe *stripe_alloc(struct stripe_cache *sc, ++ struct dm_mem_cache_client *mc, ++ enum grow grow) ++{ ++ int r; ++ struct stripe *stripe; ++ ++ stripe = kmem_cache_zalloc(sc->kc.cache, GFP_KERNEL); ++ if (stripe) { ++ /* Grow the dm-mem-cache by one object. */ ++ if (grow == SC_GROW) { ++ r = dm_mem_cache_grow(mc, 1); ++ if (r) ++ goto err_free; ++ } ++ ++ stripe->obj = dm_mem_cache_alloc(mc); ++ if (!stripe->obj) ++ goto err_shrink; ++ ++ stripe_init(sc, stripe); ++ } ++ ++ return stripe; ++ ++err_shrink: ++ if (grow == SC_GROW) ++ dm_mem_cache_shrink(mc, 1); ++err_free: ++ kmem_cache_free(sc->kc.cache, stripe); ++ return NULL; ++} ++ ++/* ++ * Free a stripes memory object, shrink the ++ * memory cache and free the stripe itself ++ */ ++static void stripe_free(struct stripe *stripe, struct dm_mem_cache_client *mc) ++{ ++ dm_mem_cache_free(mc, stripe->obj); ++ dm_mem_cache_shrink(mc, 1); ++ kmem_cache_free(stripe->sc->kc.cache, stripe); ++} ++ ++/* Free the recovery stripe. */ ++static void stripe_recover_free(struct raid_set *rs) ++{ ++ struct recover *rec = &rs->recover; ++ struct list_head *stripes = &rec->stripes; ++ ++ while (!list_empty(stripes)) { ++ struct stripe *stripe = list_first_entry(stripes, struct stripe, ++ lists[LIST_RECOVER]); ++ list_del(stripe->lists + LIST_RECOVER); ++ stripe_free(stripe, rec->mem_cache_client); ++ } ++} ++ ++/* Push a stripe safely onto the endio list to be handled by do_endios(). */ ++static INLINE void stripe_endio_push(struct stripe *stripe) ++{ ++ int wake; ++ unsigned long flags; ++ struct stripe_cache *sc = stripe->sc; ++ spinlock_t *lock = sc->locks + LOCK_ENDIO; ++ ++ spin_lock_irqsave(lock, flags); ++ wake = list_empty(sc->lists + LIST_ENDIO); ++ stripe_endio_add(stripe, POS_HEAD, LIST_UNLOCKED); ++ spin_unlock_irqrestore(lock, flags); ++ ++ if (wake) ++ wake_do_raid(RS(sc)); ++} ++ ++/* Protected check for stripe cache endio list empty. */ ++static INLINE int stripe_endio_empty(struct stripe_cache *sc) ++{ ++ int r; ++ spinlock_t *lock = sc->locks + LOCK_ENDIO; ++ ++ spin_lock_irq(lock); ++ r = list_empty(sc->lists + LIST_ENDIO); ++ spin_unlock_irq(lock); ++ ++ return r; ++} ++ ++/* Pop a stripe off safely off the endio list. */ ++static struct stripe *stripe_endio_pop(struct stripe_cache *sc) ++{ ++ struct stripe *stripe; ++ spinlock_t *lock = sc->locks + LOCK_ENDIO; ++ ++ /* This runs in parallel with endio(). */ ++ spin_lock_irq(lock); ++ POP(LIST_ENDIO) ++ spin_unlock_irq(lock); ++ return stripe; ++} ++ ++#undef POP ++ ++/* Evict stripe from cache. */ ++static void stripe_evict(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ stripe_hash_del(stripe, LIST_UNLOCKED); /* Take off hash. */ ++ ++ if (list_empty(stripe->lists + LIST_LRU)) { ++ stripe_lru_add(stripe, POS_TAIL, LIST_LOCKED); ++ atomic_inc(rs->stats + S_EVICT); /* REMOVEME: statistics. */ ++ } ++} ++ ++/* Grow stripe cache. */ ++static int ++sc_grow(struct stripe_cache *sc, unsigned stripes, enum grow grow) ++{ ++ int r = 0; ++ struct raid_set *rs = RS(sc); ++ ++ /* Try to allocate this many (additional) stripes. */ ++ while (stripes--) { ++ struct stripe *stripe = ++ stripe_alloc(sc, sc->mem_cache_client, grow); ++ ++ if (likely(stripe)) { ++ stripe->io.size = rs->set.io_size; ++ stripe_lru_add(stripe, POS_TAIL, LIST_LOCKED); ++ atomic_inc(&sc->stripes); ++ } else { ++ r = -ENOMEM; ++ break; ++ } ++ } ++ ++ ClearRSScBusy(rs); ++ return r ? r : hash_resize(sc); ++} ++ ++/* Shrink stripe cache. */ ++static int sc_shrink(struct stripe_cache *sc, unsigned stripes) ++{ ++ int r = 0; ++ ++ /* Try to get unused stripe from LRU list. */ ++ while (stripes--) { ++ struct stripe *stripe; ++ ++ stripe = stripe_lru_pop(sc); ++ if (stripe) { ++ /* An lru stripe may never have ios pending! */ ++ BUG_ON(stripe_io(stripe)); ++ stripe_free(stripe, sc->mem_cache_client); ++ atomic_dec(&sc->stripes); ++ } else { ++ r = -ENOENT; ++ break; ++ } ++ } ++ ++ /* Check if stats are still sane. */ ++ if (atomic_read(&sc->max_active_stripes) > ++ atomic_read(&sc->stripes)) ++ atomic_set(&sc->max_active_stripes, 0); ++ ++ if (r) ++ return r; ++ ++ ClearRSScBusy(RS(sc)); ++ return hash_resize(sc); ++} ++ ++/* Create stripe cache. */ ++static int sc_init(struct raid_set *rs, unsigned stripes) ++{ ++ unsigned i, nr; ++ struct stripe_cache *sc = &rs->sc; ++ struct stripe *stripe; ++ struct recover *rec = &rs->recover; ++ ++ /* Initialize lists and locks. */ ++ i = ARRAY_SIZE(sc->lists); ++ while (i--) ++ INIT_LIST_HEAD(sc->lists + i); ++ ++ i = NR_LOCKS; ++ while (i--) ++ spin_lock_init(sc->locks + i); ++ ++ /* Initialize atomic variables. */ ++ atomic_set(&sc->stripes, 0); ++ atomic_set(&sc->stripes_last, 0); ++ atomic_set(&sc->stripes_to_shrink, 0); ++ atomic_set(&sc->active_stripes, 0); ++ atomic_set(&sc->max_active_stripes, 0); /* REMOVEME: statistics. */ ++ ++ /* ++ * We need a runtime unique # to suffix the kmem cache name ++ * because we'll have one for each active RAID set. ++ */ ++ nr = atomic_inc_return(&_stripe_sc_nr); ++ sprintf(sc->kc.name, "%s_%d", TARGET, nr); ++ sc->kc.cache = kmem_cache_create(sc->kc.name, stripe_size(rs), ++ 0, 0, NULL); ++ if (!sc->kc.cache) ++ return -ENOMEM; ++ ++ /* Create memory cache client context for RAID stripe cache. */ ++ sc->mem_cache_client = ++ dm_mem_cache_client_create(stripes, rs->set.raid_devs, ++ chunk_pages(rs->set.io_size)); ++ if (IS_ERR(sc->mem_cache_client)) ++ return PTR_ERR(sc->mem_cache_client); ++ ++ /* Create memory cache client context for RAID recovery stripe(s). */ ++ rec->mem_cache_client = ++ dm_mem_cache_client_create(MAX_RECOVER, rs->set.raid_devs, ++ chunk_pages(rec->io_size)); ++ if (IS_ERR(rec->mem_cache_client)) ++ return PTR_ERR(rec->mem_cache_client); ++ ++ /* Allocate stripe for set recovery. */ ++ /* XXX: cope with MAX_RECOVERY. */ ++ INIT_LIST_HEAD(&rec->stripes); ++ for (i = 0; i < MAX_RECOVER; i++) { ++ stripe = stripe_alloc(sc, rec->mem_cache_client, SC_KEEP); ++ if (!stripe) ++ return -ENOMEM; ++ ++ SetStripeRecover(stripe); ++ stripe->io.size = rec->io_size; ++ list_add(stripe->lists + LIST_RECOVER, &rec->stripes); ++ } ++ ++ /* ++ * Allocate the stripe objetcs from the ++ * cache and add them to the LRU list. ++ */ ++ return sc_grow(sc, stripes, SC_KEEP); ++} ++ ++/* Destroy the stripe cache. */ ++static void sc_exit(struct stripe_cache *sc) ++{ ++ if (sc->kc.cache) { ++ BUG_ON(sc_shrink(sc, atomic_read(&sc->stripes))); ++ kmem_cache_destroy(sc->kc.cache); ++ } ++ ++ if (sc->mem_cache_client) ++ dm_mem_cache_client_destroy(sc->mem_cache_client); ++ ++ ClearRSRecover(RS(sc)); ++ stripe_recover_free(RS(sc)); ++ if (RS(sc)->recover.mem_cache_client) ++ dm_mem_cache_client_destroy(RS(sc)->recover.mem_cache_client); ++ ++ hash_exit(&sc->hash); ++} ++ ++/* ++ * Calculate RAID address ++ * ++ * Delivers tuple with the index of the data disk holding the chunk ++ * in the set, the parity disks index and the start of the stripe ++ * within the address space of the set (used as the stripe cache hash key). ++ */ ++/* thx MD. */ ++static struct address * ++raid_address(struct raid_set *rs, sector_t sector, struct address *addr) ++{ ++ unsigned data_devs = rs->set.data_devs, di, pi, ++ raid_devs = rs->set.raid_devs; ++ sector_t stripe, tmp; ++ ++ /* ++ * chunk_number = sector / chunk_size ++ * stripe = chunk_number / data_devs ++ * di = stripe % data_devs; ++ */ ++ stripe = sector >> rs->set.chunk_shift; ++ di = sector_div(stripe, data_devs); ++ ++ switch (rs->set.raid_type->level) { ++ case raid5: ++ tmp = stripe; ++ pi = sector_div(tmp, raid_devs); ++ ++ switch (rs->set.raid_type->algorithm) { ++ case left_asym: /* Left asymmetric. */ ++ pi = data_devs - pi; ++ case right_asym: /* Right asymmetric. */ ++ if (di >= pi) ++ di++; ++ break; ++ ++ case left_sym: /* Left symmetric. */ ++ pi = data_devs - pi; ++ case right_sym: /* Right symmetric. */ ++ di = (pi + di + 1) % raid_devs; ++ break; ++ ++ default: ++ DMERR("Unknown RAID algorithm %d", ++ rs->set.raid_type->algorithm); ++ goto out; ++ } ++ ++ break; ++ ++ case raid4: ++ pi = rs->set.pi; ++ if (di >= pi) ++ di++; ++ break; ++ ++ default: ++ DMERR("Unknown RAID level %d", rs->set.raid_type->level); ++ goto out; ++ } ++ ++ /* ++ * Hash key = start offset on any single device of the RAID set; ++ * adjusted in case io size differs from chunk size. ++ */ ++ addr->key = (stripe << rs->set.chunk_shift) + ++ (sector & rs->set.io_shift_mask); ++ addr->di = di; ++ addr->pi = pi; ++ ++out: ++ return addr; ++} ++ ++/* ++ * Copy data across between stripe pages and bio vectors. ++ * ++ * Pay attention to data alignment in stripe and bio pages. ++ */ ++static void ++bio_copy_page_list(int rw, struct stripe *stripe, ++ struct page_list *pl, struct bio *bio) ++{ ++ unsigned i, page_offset; ++ void *page_addr; ++ struct raid_set *rs = RS(stripe->sc); ++ struct bio_vec *bv; ++ ++ /* Get start page in page list for this sector. */ ++ i = (bio->bi_sector & rs->set.io_mask) / SECTORS_PER_PAGE; ++ pl = pl_elem(pl, i); ++ ++ page_addr = page_address(pl->page); ++ page_offset = to_bytes(bio->bi_sector & (SECTORS_PER_PAGE - 1)); ++ ++ /* Walk all segments and copy data across between bio_vecs and pages. */ ++ bio_for_each_segment(bv, bio, i) { ++ int len = bv->bv_len, size; ++ unsigned bio_offset = 0; ++ void *bio_addr = __bio_kmap_atomic(bio, i, KM_USER0); ++redo: ++ size = (page_offset + len > PAGE_SIZE) ? ++ PAGE_SIZE - page_offset : len; ++ ++ if (rw == READ) ++ memcpy(bio_addr + bio_offset, ++ page_addr + page_offset, size); ++ else ++ memcpy(page_addr + page_offset, ++ bio_addr + bio_offset, size); ++ ++ page_offset += size; ++ if (page_offset == PAGE_SIZE) { ++ /* ++ * We reached the end of the chunk page -> ++ * need refer to the next one to copy more data. ++ */ ++ len -= size; ++ if (len) { ++ /* Get next page. */ ++ pl = pl->next; ++ BUG_ON(!pl); ++ page_addr = page_address(pl->page); ++ page_offset = 0; ++ bio_offset += size; ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_BIO_COPY_PL_NEXT); ++ goto redo; ++ } ++ } ++ ++ __bio_kunmap_atomic(bio_addr, KM_USER0); ++ } ++} ++ ++/* ++ * Xor optimization macros. ++ */ ++/* Xor data pointer declaration and initialization macros. */ ++#define DECLARE_2 unsigned long *d0 = data[0], *d1 = data[1] ++#define DECLARE_3 DECLARE_2, *d2 = data[2] ++#define DECLARE_4 DECLARE_3, *d3 = data[3] ++#define DECLARE_5 DECLARE_4, *d4 = data[4] ++#define DECLARE_6 DECLARE_5, *d5 = data[5] ++#define DECLARE_7 DECLARE_6, *d6 = data[6] ++#define DECLARE_8 DECLARE_7, *d7 = data[7] ++ ++/* Xor unrole macros. */ ++#define D2(n) d0[n] = d0[n] ^ d1[n] ++#define D3(n) D2(n) ^ d2[n] ++#define D4(n) D3(n) ^ d3[n] ++#define D5(n) D4(n) ^ d4[n] ++#define D6(n) D5(n) ^ d5[n] ++#define D7(n) D6(n) ^ d6[n] ++#define D8(n) D7(n) ^ d7[n] ++ ++#define X_2(macro, offset) macro(offset); macro(offset + 1); ++#define X_4(macro, offset) X_2(macro, offset); X_2(macro, offset + 2); ++#define X_8(macro, offset) X_4(macro, offset); X_4(macro, offset + 4); ++#define X_16(macro, offset) X_8(macro, offset); X_8(macro, offset + 8); ++#define X_32(macro, offset) X_16(macro, offset); X_16(macro, offset + 16); ++#define X_64(macro, offset) X_32(macro, offset); X_32(macro, offset + 32); ++ ++/* Define a _xor_#chunks_#xors_per_run() function. */ ++#define _XOR(chunks, xors_per_run) \ ++static void _xor ## chunks ## _ ## xors_per_run(unsigned long **data) \ ++{ \ ++ unsigned end = XOR_SIZE / sizeof(data[0]), i; \ ++ DECLARE_ ## chunks; \ ++\ ++ for (i = 0; i < end; i += xors_per_run) { \ ++ X_ ## xors_per_run(D ## chunks, i); \ ++ } \ ++} ++ ++/* Define xor functions for 2 - 8 chunks. */ ++#define MAKE_XOR_PER_RUN(xors_per_run) \ ++ _XOR(2, xors_per_run); _XOR(3, xors_per_run); \ ++ _XOR(4, xors_per_run); _XOR(5, xors_per_run); \ ++ _XOR(6, xors_per_run); _XOR(7, xors_per_run); \ ++ _XOR(8, xors_per_run); ++ ++MAKE_XOR_PER_RUN(8) /* Define _xor_*_8() functions. */ ++MAKE_XOR_PER_RUN(16) /* Define _xor_*_16() functions. */ ++MAKE_XOR_PER_RUN(32) /* Define _xor_*_32() functions. */ ++MAKE_XOR_PER_RUN(64) /* Define _xor_*_64() functions. */ ++ ++#define MAKE_XOR(xors_per_run) \ ++struct { \ ++ void (*f)(unsigned long **); \ ++} static xor_funcs ## xors_per_run[] = { \ ++ { NULL }, \ ++ { NULL }, \ ++ { _xor2_ ## xors_per_run }, \ ++ { _xor3_ ## xors_per_run }, \ ++ { _xor4_ ## xors_per_run }, \ ++ { _xor5_ ## xors_per_run }, \ ++ { _xor6_ ## xors_per_run }, \ ++ { _xor7_ ## xors_per_run }, \ ++ { _xor8_ ## xors_per_run }, \ ++}; \ ++\ ++static void xor_ ## xors_per_run(unsigned n, unsigned long **data) \ ++{ \ ++ /* Call respective function for amount of chunks. */ \ ++ xor_funcs ## xors_per_run[n].f(data); \ ++} ++ ++/* Define xor_8() - xor_64 functions. */ ++MAKE_XOR(8) ++MAKE_XOR(16) ++MAKE_XOR(32) ++MAKE_XOR(64) ++ ++/* Maximum number of chunks, which can be xor'ed in one go. */ ++#define XOR_CHUNKS_MAX (ARRAY_SIZE(xor_funcs8) - 1) ++ ++struct xor_func { ++ xor_function_t f; ++ const char *name; ++} static xor_funcs[] = { ++ {xor_8, "xor_8"}, ++ {xor_16, "xor_16"}, ++ {xor_32, "xor_32"}, ++ {xor_64, "xor_64"}, ++}; ++ ++/* ++ * Calculate crc. ++ * ++ * This indexes into the page list of the stripe. ++ * ++ * All chunks will be xored into the parity chunk ++ * in maximum groups of xor.chunks. ++ * ++ * FIXME: try mapping the pages on discontiguous memory. ++ */ ++static void xor(struct stripe *stripe, unsigned pi, unsigned sector) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ unsigned max_chunks = rs->xor.chunks, n, p; ++ unsigned o = sector / SECTORS_PER_PAGE; /* Offset into the page_list. */ ++ unsigned long **d = rs->data; ++ xor_function_t xor_f = rs->xor.f->f; ++ ++ /* Address of parity page to xor into. */ ++ d[0] = page_address(pl_elem(PL(stripe, pi), o)->page); ++ ++ /* Preset pointers to data pages. */ ++ for (n = 1, p = rs->set.raid_devs; p--; ) { ++ if (p != pi && PageIO(PAGE(stripe, p))) ++ d[n++] = page_address(pl_elem(PL(stripe, p), o)->page); ++ ++ /* If max chunks -> xor .*/ ++ if (n == max_chunks) { ++ xor_f(n, d); ++ n = 1; ++ } ++ } ++ ++ /* If chunks -> xor. */ ++ if (n > 1) ++ xor_f(n, d); ++ ++ /* Set parity page uptodate and clean. */ ++ page_set(PAGE(stripe, pi), CLEAN); ++} ++ ++/* Common xor loop through all stripe page lists. */ ++static void common_xor(struct stripe *stripe, sector_t count, ++ unsigned off, unsigned p) ++{ ++ unsigned sector; ++ ++ for (sector = off; sector < count; sector += SECTORS_PER_XOR) ++ xor(stripe, p, sector); ++ ++ atomic_inc(RS(stripe->sc)->stats + S_XORS); /* REMOVEME: statistics. */ ++} ++ ++/* ++ * Calculate parity sectors on intact stripes. ++ * ++ * Need to calculate raid address for recover stripe, because its ++ * chunk sizes differs and is typically larger than io chunk size. ++ */ ++static void parity_xor(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ unsigned chunk_size = rs->set.chunk_size, ++ io_size = stripe->io.size, ++ xor_size = chunk_size > io_size ? io_size : chunk_size; ++ sector_t off; ++ ++ /* This can be the recover stripe with a larger io size. */ ++ for (off = 0; off < io_size; off += xor_size) { ++ unsigned pi; ++ ++ /* ++ * Recover stripe likely is bigger than regular io ++ * ones and has no precalculated parity disk index -> ++ * need to calculate RAID address. ++ */ ++ if (unlikely(StripeRecover(stripe))) { ++ struct address addr; ++ ++ raid_address(rs, ++ (stripe->key + off) * rs->set.data_devs, ++ &addr); ++ pi = addr.pi; ++ stripe_zero_pl_part(stripe, pi, off, ++ rs->set.chunk_size); ++ } else ++ pi = stripe->idx.parity; ++ ++ common_xor(stripe, xor_size, off, pi); ++ page_set(PAGE(stripe, pi), DIRTY); ++ } ++} ++ ++/* Reconstruct missing chunk. */ ++static void reconstruct_xor(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ int p = stripe->idx.recover; ++ ++ BUG_ON(p < 0); ++ ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + (raid_set_degraded(rs) ? ++ S_RECONSTRUCT_EI : S_RECONSTRUCT_DEV)); ++ ++ /* Zero chunk to be reconstructed. */ ++ stripe_zero_chunk(stripe, p); ++ common_xor(stripe, stripe->io.size, 0, p); ++} ++ ++/* ++ * Try getting a stripe either from the hash or from the lru list ++ */ ++static inline void _stripe_get(struct stripe *stripe) ++{ ++ atomic_inc(&stripe->cnt); ++} ++ ++static struct stripe *stripe_get(struct raid_set *rs, struct address *addr) ++{ ++ struct stripe_cache *sc = &rs->sc; ++ struct stripe *stripe; ++ ++ stripe = stripe_lookup(sc, addr->key); ++ if (stripe) { ++ _stripe_get(stripe); ++ /* Remove from the lru list if on. */ ++ stripe_lru_del(stripe, LIST_LOCKED); ++ atomic_inc(rs->stats + S_HITS_1ST); /* REMOVEME: statistics. */ ++ } else { ++ /* Second try to get an LRU stripe. */ ++ stripe = stripe_lru_pop(sc); ++ if (stripe) { ++ _stripe_get(stripe); ++ /* Invalidate before reinserting with changed key. */ ++ stripe_invalidate(stripe); ++ stripe->key = addr->key; ++ stripe->region = dm_rh_sector_to_region(rs->recover.rh, ++ addr->key); ++ stripe->idx.parity = addr->pi; ++ sc_insert(sc, stripe); ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_INSCACHE); ++ } ++ } ++ ++ return stripe; ++} ++ ++/* ++ * Decrement reference count on a stripe. ++ * ++ * Move it to list of LRU stripes if zero. ++ */ ++static void stripe_put(struct stripe *stripe) ++{ ++ if (atomic_dec_and_test(&stripe->cnt)) { ++ if (TestClearStripeActive(stripe)) ++ atomic_dec(&stripe->sc->active_stripes); ++ ++ /* Put stripe onto the LRU list. */ ++ stripe_lru_add(stripe, POS_TAIL, LIST_LOCKED); ++ } ++ ++ BUG_ON(atomic_read(&stripe->cnt) < 0); ++} ++ ++/* ++ * Process end io ++ * ++ * I need to do it here because I can't in interrupt ++ * ++ * Read and write functions are split in order to avoid ++ * conditionals in the main loop for performamce reasons. ++ */ ++ ++/* Helper read bios on a page list. */ ++static void _bio_copy_page_list(struct stripe *stripe, struct page_list *pl, ++ struct bio *bio) ++{ ++ bio_copy_page_list(READ, stripe, pl, bio); ++} ++ ++/* Helper write bios on a page list. */ ++static void _rh_dec(struct stripe *stripe, struct page_list *pl, ++ struct bio *bio) ++{ ++ dm_rh_dec(RS(stripe->sc)->recover.rh, stripe->region); ++} ++ ++/* End io all bios on a page list. */ ++static inline int ++page_list_endio(int rw, struct stripe *stripe, unsigned p, unsigned *count) ++{ ++ int r = 0; ++ struct bio_list *bl = BL(stripe, p, rw); ++ ++ if (!bio_list_empty(bl)) { ++ struct page_list *pl = PL(stripe, p); ++ struct page *page = pl->page; ++ ++ if (PageLocked(page)) ++ r = -EBUSY; ++ /* ++ * FIXME: PageUptodate() not cleared ++ * properly for missing chunks ? ++ */ ++ else if (PageUptodate(page)) { ++ struct bio *bio; ++ struct raid_set *rs = RS(stripe->sc); ++ void (*h_f)(struct stripe *, struct page_list *, ++ struct bio *) = ++ (rw == READ) ? _bio_copy_page_list : _rh_dec; ++ ++ while ((bio = bio_list_pop(bl))) { ++ h_f(stripe, pl, bio); ++ _bio_endio(rs, bio, 0); ++ stripe_put(stripe); ++ if (count) ++ (*count)++; ++ } ++ } else ++ r = -EAGAIN; ++ } ++ ++ return r; ++} ++ ++/* ++ * End io all reads/writes on a stripe copying ++ * read date accross from stripe to bios. ++ */ ++static int stripe_endio(int rw, struct stripe *stripe, unsigned *count) ++{ ++ int r = 0; ++ unsigned p = RS(stripe->sc)->set.raid_devs; ++ ++ while (p--) { ++ int rr = page_list_endio(rw, stripe, p, count); ++ ++ if (rr && r != -EIO) ++ r = rr; ++ } ++ ++ return r; ++} ++ ++/* Fail all ios on a bio list and return # of bios. */ ++static unsigned ++bio_list_fail(struct raid_set *rs, struct stripe *stripe, struct bio_list *bl) ++{ ++ unsigned r; ++ struct bio *bio; ++ ++ raid_set_dead(rs); ++ ++ /* Update region counters. */ ++ if (stripe) { ++ struct dm_rh_client *rh = rs->recover.rh; ++ ++ bio_list_for_each(bio, bl) { ++ if (bio_data_dir(bio) == WRITE) ++ dm_rh_dec(rh, stripe->region); ++ } ++ } ++ ++ /* Error end io all bios. */ ++ for (r = 0; (bio = bio_list_pop(bl)); r++) ++ _bio_endio(rs, bio, -EIO); ++ ++ return r; ++} ++ ++/* Fail all ios of a bio list of a stripe and drop io pending count. */ ++static void ++stripe_bio_list_fail(struct raid_set *rs, struct stripe *stripe, ++ struct bio_list *bl) ++{ ++ unsigned put = bio_list_fail(rs, stripe, bl); ++ ++ while (put--) ++ stripe_put(stripe); ++} ++ ++/* Fail all ios hanging off all bio lists of a stripe. */ ++static void stripe_fail_io(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ unsigned p = rs->set.raid_devs; ++ ++ stripe_evict(stripe); ++ ++ while (p--) { ++ struct stripe_set *ss = stripe->ss + p; ++ int i = ARRAY_SIZE(ss->bl); ++ ++ while (i--) ++ stripe_bio_list_fail(rs, stripe, ss->bl + i); ++ } ++} ++ ++/* ++ * Handle all stripes by handing them to the daemon, because we can't ++ * map their pages to copy the data in interrupt context. ++ * ++ * We don't want to handle them here either, while interrupts are disabled. ++ */ ++ ++/* Read/write endio function for dm-io (interrupt context). */ ++static void endio(unsigned long error, void *context) ++{ ++ struct dm_mem_cache_object *obj = context; ++ struct stripe_set *ss = obj->private; ++ struct stripe *stripe = ss->stripe; ++ struct page *page = obj->pl->page; ++ ++ if (unlikely(error)) ++ stripe_error(stripe, page); ++ else ++ page_set(page, CLEAN); ++ ++ clear_page_locked(page); ++ stripe_io_dec(stripe); ++ ++ /* Add stripe to endio list and wake daemon. */ ++ stripe_endio_push(stripe); ++} ++ ++/* ++ * Recovery io throttling ++ */ ++/* Conditionally reset io counters. */ ++enum count_type { IO_WORK = 0, IO_RECOVER }; ++static int recover_io_reset(struct raid_set *rs) ++{ ++ unsigned long j = jiffies; ++ ++ /* Pay attention to jiffies overflows. */ ++ if (j > rs->recover.last_jiffies + HZ ++ || j < rs->recover.last_jiffies) { ++ rs->recover.last_jiffies = j; ++ atomic_set(rs->recover.io_count + IO_WORK, 0); ++ atomic_set(rs->recover.io_count + IO_RECOVER, 0); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Count ios. */ ++static INLINE void ++recover_io_count(struct raid_set *rs, struct stripe *stripe) ++{ ++ if (RSRecover(rs)) { ++ recover_io_reset(rs); ++ atomic_inc(rs->recover.io_count + ++ (StripeRecover(stripe) ? IO_RECOVER : IO_WORK)); ++ } ++} ++ ++/* Read/Write a page_list asynchronously. */ ++static void page_list_rw(struct stripe *stripe, unsigned p) ++{ ++ struct stripe_cache *sc = stripe->sc; ++ struct raid_set *rs = RS(sc); ++ struct dm_mem_cache_object *obj = stripe->obj + p; ++ struct page_list *pl = obj->pl; ++ struct page *page = pl->page; ++ struct raid_dev *dev = rs->dev + p; ++ struct dm_io_region io = { ++ .bdev = dev->dev->bdev, ++ .sector = stripe->key, ++ .count = stripe->io.size, ++ }; ++ struct dm_io_request control = { ++ .bi_rw = PageDirty(page) ? WRITE : READ, ++ .mem.type = DM_IO_PAGE_LIST, ++ .mem.ptr.pl = pl, ++ .mem.offset = 0, ++ .notify.fn = endio, ++ .notify.context = obj, ++ .client = sc->dm_io_client, ++ }; ++ ++ BUG_ON(PageLocked(page)); ++ ++ /* ++ * Don't rw past end of device, which can happen, because ++ * typically sectors_per_dev isn't divisable by io_size. ++ */ ++ if (unlikely(io.sector + io.count > rs->set.sectors_per_dev)) ++ io.count = rs->set.sectors_per_dev - io.sector; ++ ++ io.sector += dev->start; /* Add . */ ++ recover_io_count(rs, stripe); /* Recovery io accounting. */ ++ ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + ++ (PageDirty(page) ? S_DM_IO_WRITE : S_DM_IO_READ)); ++ ++ ClearPageError(page); ++ set_page_locked(page); ++ io_dev_queued(dev); ++ BUG_ON(dm_io(&control, 1, &io, NULL)); ++} ++ ++/* ++ * Write dirty / read not uptodate page lists of a stripe. ++ */ ++static unsigned stripe_page_lists_rw(struct raid_set *rs, struct stripe *stripe) ++{ ++ unsigned r; ++ ++ /* ++ * Increment the pending count on the stripe ++ * first, so that we don't race in endio(). ++ * ++ * An inc (IO) is needed for any page: ++ * ++ * o not uptodate ++ * o dirtied by writes merged ++ * o dirtied by parity calculations ++ */ ++ r = for_each_io_dev(rs, stripe, _stripe_io_inc); ++ if (r) { ++ /* io needed: chunks are not uptodate/dirty. */ ++ int max; /* REMOVEME: */ ++ struct stripe_cache *sc = &rs->sc; ++ ++ if (!TestSetStripeActive(stripe)) ++ atomic_inc(&sc->active_stripes); ++ ++ /* Take off the lru list in case it got added there. */ ++ stripe_lru_del(stripe, LIST_LOCKED); ++ ++ /* Submit actual io. */ ++ for_each_io_dev(rs, stripe, page_list_rw); ++ ++ /* REMOVEME: statistics */ ++ max = sc_active(sc); ++ if (atomic_read(&sc->max_active_stripes) < max) ++ atomic_set(&sc->max_active_stripes, max); ++ ++ atomic_inc(rs->stats + S_FLUSHS); ++ /* END REMOVEME: statistics */ ++ } ++ ++ return r; ++} ++ ++/* Work in all pending writes. */ ++static INLINE void _writes_merge(struct stripe *stripe, unsigned p) ++{ ++ struct bio_list *write = BL(stripe, p, WRITE); ++ ++ if (!bio_list_empty(write)) { ++ struct page_list *pl = stripe->obj[p].pl; ++ struct bio *bio; ++ struct bio_list *write_merged = BL(stripe, p, WRITE_MERGED); ++ ++ /* ++ * We can play with the lists without holding a lock, ++ * because it is just us accessing them anyway. ++ */ ++ bio_list_for_each(bio, write) ++ bio_copy_page_list(WRITE, stripe, pl, bio); ++ ++ bio_list_merge(write_merged, write); ++ bio_list_init(write); ++ page_set(pl->page, DIRTY); ++ } ++} ++ ++/* Merge in all writes hence dirtying respective pages. */ ++static INLINE void writes_merge(struct stripe *stripe) ++{ ++ unsigned p = RS(stripe->sc)->set.raid_devs; ++ ++ while (p--) ++ _writes_merge(stripe, p); ++} ++ ++/* Check, if a chunk gets completely overwritten. */ ++static INLINE int stripe_check_overwrite(struct stripe *stripe, unsigned p) ++{ ++ unsigned sectors = 0; ++ struct bio *bio; ++ struct bio_list *bl = BL(stripe, p, WRITE); ++ ++ bio_list_for_each(bio, bl) ++ sectors += bio_sectors(bio); ++ ++ return sectors == RS(stripe->sc)->set.io_size; ++} ++ ++/* ++ * Prepare stripe to avoid io on broken/reconstructed ++ * drive in order to reconstruct date on endio. ++ */ ++enum prepare_type { IO_ALLOW, IO_PROHIBIT }; ++static void stripe_prepare(struct stripe *stripe, unsigned p, ++ enum prepare_type type) ++{ ++ struct page *page = PAGE(stripe, p); ++ ++ switch (type) { ++ case IO_PROHIBIT: ++ /* ++ * In case we prohibit, we gotta make sure, that ++ * io on all other chunks than the one which failed ++ * or is being reconstructed is allowed and that it ++ * doesn't have state uptodate. ++ */ ++ stripe_allow_io(stripe); ++ ClearPageUptodate(page); ++ ProhibitPageIO(page); ++ ++ /* REMOVEME: statistics. */ ++ atomic_inc(RS(stripe->sc)->stats + S_PROHIBITPAGEIO); ++ stripe->idx.recover = p; ++ SetStripeReconstruct(stripe); ++ break; ++ ++ case IO_ALLOW: ++ AllowPageIO(page); ++ stripe->idx.recover = -1; ++ ClearStripeReconstruct(stripe); ++ break; ++ ++ default: ++ BUG(); ++ } ++} ++ ++/* ++ * Degraded/reconstruction mode. ++ * ++ * Check stripe state to figure which chunks don't need IO. ++ */ ++static INLINE void stripe_check_reconstruct(struct stripe *stripe, ++ int prohibited) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ ++ /* ++ * Degraded mode (device(s) failed) -> ++ * avoid io on the failed device. ++ */ ++ if (unlikely(raid_set_degraded(rs))) { ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_DEGRADED); ++ stripe_prepare(stripe, rs->set.ei, IO_PROHIBIT); ++ return; ++ } else { ++ /* ++ * Reconstruction mode (ie. a particular device or ++ * some (rotating) parity chunk is being resynchronized) -> ++ * o make sure all needed pages are read in ++ * o writes are allowed to go through ++ */ ++ int r = region_state(rs, stripe->key, DM_RH_NOSYNC); ++ ++ if (r) { ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_NOSYNC); ++ stripe_prepare(stripe, dev_for_parity(stripe), ++ IO_PROHIBIT); ++ return; ++ } ++ } ++ ++ /* ++ * All disks good. Avoid reading parity chunk and reconstruct it ++ * unless we have prohibited io to chunk(s). ++ */ ++ if (!prohibited) { ++ if (StripeMerged(stripe)) ++ stripe_prepare(stripe, stripe->idx.parity, IO_ALLOW); ++ else { ++ stripe_prepare(stripe, stripe->idx.parity, IO_PROHIBIT); ++ ++ /* ++ * Overrule stripe_prepare to reconstruct the ++ * parity chunk, because it'll be created new anyway. ++ */ ++ ClearStripeReconstruct(stripe); ++ } ++ } ++} ++ ++/* Check, if stripe is ready to merge writes. */ ++static INLINE int stripe_check_merge(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ int prohibited = 0; ++ unsigned chunks = 0, p = rs->set.raid_devs; ++ ++ /* Walk all chunks. */ ++ while (p--) { ++ struct page *page = PAGE(stripe, p); ++ ++ /* Can't merge active chunks. */ ++ if (PageLocked(page)) { ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_MERGE_PAGE_LOCKED); ++ break; ++ } ++ ++ /* Can merge uptodate chunks and have to count parity chunk. */ ++ if (PageUptodate(page) || p == stripe->idx.parity) { ++ chunks++; ++ continue; ++ } ++ ++ /* Read before write ordering. */ ++ if (RSCheckOverwrite(rs) && ++ bio_list_empty(BL(stripe, p, READ))) { ++ int r = stripe_check_overwrite(stripe, p); ++ ++ if (r) { ++ chunks++; ++ /* REMOVEME: statistics. */ ++ atomic_inc(RS(stripe->sc)->stats + ++ S_PROHIBITPAGEIO); ++ ProhibitPageIO(page); ++ prohibited = 1; ++ } ++ } ++ } ++ ++ if (chunks == rs->set.raid_devs) { ++ /* All pages are uptodate or get written over or mixture. */ ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_CAN_MERGE); ++ return 0; ++ } else ++ /* REMOVEME: statistics.*/ ++ atomic_inc(rs->stats + S_CANT_MERGE); ++ ++ return prohibited ? 1 : -EPERM; ++} ++ ++/* Check, if stripe is ready to merge writes. */ ++static INLINE int stripe_check_read(struct stripe *stripe) ++{ ++ int r = 0; ++ unsigned p = RS(stripe->sc)->set.raid_devs; ++ ++ /* Walk all chunks. */ ++ while (p--) { ++ struct page *page = PAGE(stripe, p); ++ ++ if (!PageLocked(page) && ++ bio_list_empty(BL(stripe, p, READ))) { ++ ProhibitPageIO(page); ++ r = 1; ++ } ++ } ++ ++ return r; ++} ++ ++/* ++ * Read/write a stripe. ++ * ++ * All stripe read/write activity goes through this function. ++ * ++ * States to cover: ++ * o stripe to read and/or write ++ * o stripe with error to reconstruct ++ */ ++static int stripe_rw(struct stripe *stripe) ++{ ++ struct raid_set *rs = RS(stripe->sc); ++ int prohibited = 0, r; ++ ++ /* ++ * Check the state of the RAID set and if degraded (or ++ * resynchronizing for reads), read in all other chunks but ++ * the one on the dead/resynchronizing device in order to be ++ * able to reconstruct the missing one. ++ * ++ * Merge all writes hanging off uptodate pages of the stripe. ++ */ ++ ++ /* Initially allow io on all chunks and prohibit below, if necessary. */ ++ stripe_allow_io(stripe); ++ ++ if (StripeRBW(stripe)) { ++ r = stripe_check_merge(stripe); ++ if (!r) { ++ /* ++ * If I could rely on valid parity (which would only ++ * be sure in case of a full synchronization), ++ * I could xor a fraction of chunks out of ++ * parity and back in. ++ * ++ * For the time being, I got to redo parity... ++ */ ++ /* parity_xor(stripe); */ /* Xor chunks out. */ ++ stripe_zero_chunk(stripe, stripe->idx.parity); ++ writes_merge(stripe); /* Merge writes in. */ ++ parity_xor(stripe); /* Update parity. */ ++ ClearStripeRBW(stripe); /* Disable RBW. */ ++ SetStripeMerged(stripe); /* Writes merged. */ ++ } ++ ++ if (r > 0) ++ prohibited = 1; ++ } else if (!raid_set_degraded(rs)) ++ /* Only allow for read avoidance if not degraded. */ ++ prohibited = stripe_check_read(stripe); ++ ++ /* ++ * Check, if io needs to be allowed/prohibeted on certain chunks ++ * because of a degraded set or reconstruction on a region. ++ */ ++ stripe_check_reconstruct(stripe, prohibited); ++ ++ /* Now submit any reads/writes. */ ++ r = stripe_page_lists_rw(rs, stripe); ++ if (!r) { ++ /* ++ * No io submitted because of chunk io prohibited or ++ * locked pages -> push to end io list for processing. ++ */ ++ atomic_inc(rs->stats + S_NO_RW); /* REMOVEME: statistics. */ ++ stripe_endio_push(stripe); ++ wake_do_raid(rs); /* Wake myself. */ ++ } ++ ++ return 0; ++} ++ ++/* Flush stripe either via flush list or imeediately. */ ++enum flush_type { FLUSH_DELAY, FLUSH_NOW }; ++static int stripe_flush(struct stripe *stripe, enum flush_type type) ++{ ++ int r = 0; ++ ++ stripe_lru_del(stripe, LIST_LOCKED); ++ ++ /* Immediately flush. */ ++ if (type == FLUSH_NOW) { ++ if (likely(raid_set_operational(RS(stripe->sc)))) ++ r = stripe_rw(stripe); /* Read/write stripe. */ ++ else ++ /* Optimization: Fail early on failed sets. */ ++ stripe_fail_io(stripe); ++ /* Delay flush by putting it on io list for later processing. */ ++ } else if (type == FLUSH_DELAY) ++ stripe_io_add(stripe, POS_TAIL, LIST_UNLOCKED); ++ else ++ BUG(); ++ ++ return r; ++} ++ ++/* ++ * Queue reads and writes to a stripe by hanging ++ * their bios off the stripsets read/write lists. ++ * ++ * Endio reads on uptodate chunks. ++ */ ++static INLINE int stripe_queue_bio(struct raid_set *rs, struct bio *bio, ++ struct bio_list *reject) ++{ ++ int r = 0; ++ struct address addr; ++ struct stripe *stripe = ++ stripe_get(rs, raid_address(rs, bio->bi_sector, &addr)); ++ ++ if (stripe) { ++ int rr, rw = bio_data_dir(bio); ++ ++ rr = stripe_lock(rs, stripe, rw, addr.key); /* Lock stripe */ ++ if (rr) { ++ stripe_put(stripe); ++ goto out; ++ } ++ ++ /* Distinguish read and write cases. */ ++ bio_list_add(BL(stripe, addr.di, rw), bio); ++ ++ /* REMOVEME: statistics */ ++ atomic_inc(rs->stats + (rw == WRITE ? ++ S_BIOS_ADDED_WRITE : S_BIOS_ADDED_READ)); ++ ++ if (rw == READ) ++ SetStripeRead(stripe); ++ else { ++ SetStripeRBW(stripe); ++ ++ /* Inrement pending write count on region. */ ++ dm_rh_inc(rs->recover.rh, stripe->region); ++ r = 1; /* Region hash needs a flush. */ ++ } ++ ++ /* ++ * Optimize stripe flushing: ++ * ++ * o directly start io for read stripes. ++ * ++ * o put stripe onto stripe caches io_list for RBW, ++ * so that do_flush() can belabour it after we put ++ * more bios to the stripe for overwrite optimization. ++ */ ++ stripe_flush(stripe, ++ StripeRead(stripe) ? FLUSH_NOW : FLUSH_DELAY); ++ ++ /* Got no stripe from cache -> reject bio. */ ++ } else { ++out: ++ bio_list_add(reject, bio); ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_IOS_POST); ++ } ++ ++ return r; ++} ++ ++/* ++ * Recovery functions ++ */ ++/* Read a stripe off a raid set for recovery. */ ++static int recover_read(struct raid_set *rs, struct stripe *stripe, int idx) ++{ ++ /* Invalidate all pages so that they get read in. */ ++ stripe_pages_invalidate(stripe); ++ ++ /* Allow io on all recovery chunks. */ ++ stripe_allow_io(stripe); ++ ++ if (idx > -1) ++ ProhibitPageIO(PAGE(stripe, idx)); ++ ++ stripe->key = rs->recover.pos; ++ return stripe_page_lists_rw(rs, stripe); ++} ++ ++/* Write a stripe to a raid set for recovery. */ ++static int recover_write(struct raid_set *rs, struct stripe *stripe, int idx) ++{ ++ /* ++ * If this is a reconstruct of a particular device, then ++ * reconstruct the respective page(s), else create parity page(s). ++ */ ++ if (idx > -1) { ++ struct page *page = PAGE(stripe, idx); ++ ++ AllowPageIO(page); ++ stripe_zero_chunk(stripe, idx); ++ common_xor(stripe, stripe->io.size, 0, idx); ++ page_set(page, DIRTY); ++ } else ++ parity_xor(stripe); ++ ++ return stripe_page_lists_rw(rs, stripe); ++} ++ ++/* Recover bandwidth available ?. */ ++static int recover_bandwidth(struct raid_set *rs) ++{ ++ int r, work; ++ ++ /* On reset -> allow recovery. */ ++ r = recover_io_reset(rs); ++ if (r || RSBandwidth(rs)) ++ goto out; ++ ++ work = atomic_read(rs->recover.io_count + IO_WORK); ++ if (work) { ++ /* Pay attention to larger recover stripe size. */ ++ int recover = ++ atomic_read(rs->recover.io_count + IO_RECOVER) * ++ rs->recover.io_size / ++ rs->set.io_size; ++ ++ /* ++ * Don't use more than given bandwidth of ++ * the work io for recovery. ++ */ ++ if (recover > work / rs->recover.bandwidth_work) { ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_NO_BANDWIDTH); ++ return 0; ++ } ++ } ++ ++out: ++ atomic_inc(rs->stats + S_BANDWIDTH); /* REMOVEME: statistics. */ ++ return 1; ++} ++ ++/* Try to get a region to recover. */ ++static int recover_get_region(struct raid_set *rs) ++{ ++ struct recover *rec = &rs->recover; ++ struct dm_rh_client *rh = rec->rh; ++ ++ /* Start quiescing some regions. */ ++ if (!RSRegionGet(rs)) { ++ int r = recover_bandwidth(rs); /* Enough bandwidth ?. */ ++ ++ if (r) { ++ r = dm_rh_recovery_prepare(rh); ++ if (r < 0) { ++ DMINFO("No %sregions to recover", ++ rec->nr_regions_to_recover ? ++ "more " : ""); ++ return -ENOENT; ++ } ++ } else ++ return -EAGAIN; ++ ++ SetRSRegionGet(rs); ++ } ++ ++ if (!rec->reg) { ++ rec->reg = dm_rh_recovery_start(rh); ++ if (rec->reg) { ++ /* ++ * A reference for the the region I'll ++ * keep till I've completely synced it. ++ */ ++ io_get(rs); ++ rec->pos = dm_rh_region_to_sector(rh, ++ dm_rh_get_region_key(rec->reg)); ++ rec->end = rec->pos + dm_rh_get_region_size(rh); ++ return 1; ++ } else ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++ ++/* Read/write a recovery stripe. */ ++static INLINE int recover_stripe_rw(struct raid_set *rs, struct stripe *stripe) ++{ ++ /* Read/write flip-flop. */ ++ if (TestClearStripeRBW(stripe)) { ++ SetStripeRead(stripe); ++ return recover_read(rs, stripe, idx_get(rs)); ++ } else if (TestClearStripeRead(stripe)) ++ return recover_write(rs, stripe, idx_get(rs)); ++ ++ return 0; ++} ++ ++/* Reset recovery variables. */ ++static void recovery_region_reset(struct raid_set *rs) ++{ ++ rs->recover.reg = NULL; ++ ClearRSRegionGet(rs); ++} ++ ++/* Update region hash state. */ ++static void recover_rh_update(struct raid_set *rs, int error) ++{ ++ struct recover *rec = &rs->recover; ++ struct dm_rh_client *rh = rec->rh; ++ struct dm_region *reg = rec->reg; ++ ++ if (reg) { ++ dm_rh_recovery_end(rh, reg, error); ++ if (!error) ++ rec->nr_regions_recovered++; ++ ++ recovery_region_reset(rs); ++ } ++ ++ dm_rh_update_states(rh, 1); ++ dm_rh_flush(rh); ++ io_put(rs); /* Release the io reference for the region. */ ++} ++ ++/* Called by main io daemon to recover regions. */ ++/* FIXME: cope with MAX_RECOVER > 1. */ ++static INLINE void _do_recovery(struct raid_set *rs, struct stripe *stripe) ++{ ++ int r; ++ struct recover *rec = &rs->recover; ++ ++ /* If recovery is active -> return. */ ++ if (StripeActive(stripe)) ++ return; ++ ++ /* io error is fatal for recovery -> stop it. */ ++ if (unlikely(StripeError(stripe))) ++ goto err; ++ ++ /* Get a region to recover. */ ++ r = recover_get_region(rs); ++ switch (r) { ++ case 1: /* Got a new region. */ ++ /* Flag read before write. */ ++ ClearStripeRead(stripe); ++ SetStripeRBW(stripe); ++ break; ++ ++ case 0: ++ /* Got a region in the works. */ ++ r = recover_bandwidth(rs); ++ if (r) /* Got enough bandwidth. */ ++ break; ++ ++ case -EAGAIN: ++ /* No bandwidth/quiesced region yet, try later. */ ++ wake_do_raid_delayed(rs, HZ / 10); ++ return; ++ ++ case -ENOENT: /* No more regions. */ ++ dm_table_event(rs->ti->table); ++ goto free; ++ } ++ ++ /* Read/write a recover stripe. */ ++ r = recover_stripe_rw(rs, stripe); ++ if (r) { ++ /* IO initiated, get another reference for the IO. */ ++ io_get(rs); ++ return; ++ } ++ ++ /* Update recovery position within region. */ ++ rec->pos += stripe->io.size; ++ ++ /* If we're at end of region, update region hash. */ ++ if (rec->pos >= rec->end || ++ rec->pos >= rs->set.sectors_per_dev) ++ recover_rh_update(rs, 0); ++ else ++ SetStripeRBW(stripe); ++ ++ /* Schedule myself for another round... */ ++ wake_do_raid(rs); ++ return; ++ ++err: ++ raid_set_check_degrade(rs, stripe); ++ ++ { ++ char buf[BDEVNAME_SIZE]; ++ ++ DMERR("stopping recovery due to " ++ "ERROR on /dev/%s, stripe at offset %llu", ++ bdevname(rs->dev[rs->set.ei].dev->bdev, buf), ++ (unsigned long long) stripe->key); ++ ++ } ++ ++ /* Make sure, that all quiesced regions get released. */ ++ do { ++ if (rec->reg) ++ dm_rh_recovery_end(rec->rh, rec->reg, -EIO); ++ ++ rec->reg = dm_rh_recovery_start(rec->rh); ++ } while (rec->reg); ++ ++ recover_rh_update(rs, -EIO); ++free: ++ rs->set.dev_to_init = -1; ++ ++ /* Check for jiffies overrun. */ ++ rs->recover.end_jiffies = jiffies; ++ if (rs->recover.end_jiffies < rs->recover.start_jiffies) ++ rs->recover.end_jiffies = ~0; ++ ++ ClearRSRecover(rs); ++} ++ ++static INLINE void do_recovery(struct raid_set *rs) ++{ ++ struct stripe *stripe; ++ ++ list_for_each_entry(stripe, &rs->recover.stripes, lists[LIST_RECOVER]) ++ _do_recovery(rs, stripe); ++ ++ if (!RSRecover(rs)) ++ stripe_recover_free(rs); ++} ++ ++/* ++ * END recovery functions ++ */ ++ ++/* End io process all stripes handed in by endio() callback. */ ++static void do_endios(struct raid_set *rs) ++{ ++ struct stripe_cache *sc = &rs->sc; ++ struct stripe *stripe; ++ ++ while ((stripe = stripe_endio_pop(sc))) { ++ unsigned count; ++ ++ /* Recovery stripe special case. */ ++ if (unlikely(StripeRecover(stripe))) { ++ if (stripe_io(stripe)) ++ continue; ++ ++ io_put(rs); /* Release region io reference. */ ++ ClearStripeActive(stripe); ++ ++ /* REMOVEME: statistics*/ ++ atomic_dec(&sc->active_stripes); ++ continue; ++ } ++ ++ /* Early end io all reads on any uptodate chunks. */ ++ stripe_endio(READ, stripe, (count = 0, &count)); ++ if (stripe_io(stripe)) { ++ if (count) /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_ACTIVE_READS); ++ ++ continue; ++ } ++ ++ /* Set stripe inactive after all io got processed. */ ++ if (TestClearStripeActive(stripe)) ++ atomic_dec(&sc->active_stripes); ++ ++ /* Unlock stripe (for clustering). */ ++ stripe_unlock(rs, stripe); ++ ++ /* ++ * If an io error on a stripe occured and the RAID set ++ * is still operational, requeue the stripe for io. ++ */ ++ if (TestClearStripeError(stripe)) { ++ raid_set_check_degrade(rs, stripe); ++ ClearStripeReconstruct(stripe); ++ ++ if (!StripeMerged(stripe) && ++ raid_set_operational(rs)) { ++ stripe_pages_invalidate(stripe); ++ stripe_flush(stripe, FLUSH_DELAY); ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_REQUEUE); ++ continue; ++ } ++ } ++ ++ /* Check if the RAID set is inoperational to error ios. */ ++ if (!raid_set_operational(rs)) { ++ ClearStripeReconstruct(stripe); ++ stripe_fail_io(stripe); ++ BUG_ON(atomic_read(&stripe->cnt)); ++ continue; ++ } ++ ++ /* Got to reconstruct a missing chunk. */ ++ if (TestClearStripeReconstruct(stripe)) ++ reconstruct_xor(stripe); ++ ++ /* ++ * Now that we've got a complete stripe, we can ++ * process the rest of the end ios on reads. ++ */ ++ BUG_ON(stripe_endio(READ, stripe, NULL)); ++ ClearStripeRead(stripe); ++ ++ /* ++ * Read-before-write stripes need to be flushed again in ++ * order to work the write data into the pages *after* ++ * they were read in. ++ */ ++ if (TestClearStripeMerged(stripe)) ++ /* End io all bios which got merged already. */ ++ BUG_ON(stripe_endio(WRITE_MERGED, stripe, NULL)); ++ ++ /* Got to put on flush list because of new writes. */ ++ if (StripeRBW(stripe)) ++ stripe_flush(stripe, FLUSH_DELAY); ++ } ++} ++ ++/* ++ * Stripe cache shrinking. ++ */ ++static INLINE void do_sc_shrink(struct raid_set *rs) ++{ ++ unsigned shrink = atomic_read(&rs->sc.stripes_to_shrink); ++ ++ if (shrink) { ++ unsigned cur = atomic_read(&rs->sc.stripes); ++ ++ sc_shrink(&rs->sc, shrink); ++ shrink -= cur - atomic_read(&rs->sc.stripes); ++ atomic_set(&rs->sc.stripes_to_shrink, shrink); ++ ++ /* ++ * Wake myself up in case we failed to shrink the ++ * requested amount in order to try again later. ++ */ ++ if (shrink) ++ wake_do_raid(rs); ++ } ++} ++ ++ ++/* ++ * Process all ios ++ * ++ * We do different things with the io depending on the ++ * state of the region that it's in: ++ * ++ * o reads: hang off stripe cache or postpone if full ++ * ++ * o writes: ++ * ++ * CLEAN/DIRTY/NOSYNC: increment pending and hang io off stripe's stripe set. ++ * In case stripe cache is full or busy, postpone the io. ++ * ++ * RECOVERING: delay the io until recovery of the region completes. ++ * ++ */ ++static INLINE void do_ios(struct raid_set *rs, struct bio_list *ios) ++{ ++ int r; ++ unsigned flush = 0; ++ struct dm_rh_client *rh = rs->recover.rh; ++ struct bio *bio; ++ struct bio_list delay, reject; ++ ++ bio_list_init(&delay); ++ bio_list_init(&reject); ++ ++ /* ++ * Classify each io: ++ * o delay to recovering regions ++ * o queue to all other regions ++ */ ++ while ((bio = bio_list_pop(ios))) { ++ /* ++ * In case we get a barrier bio, push it back onto ++ * the input queue unless all work queues are empty ++ * and the stripe cache is inactive. ++ */ ++ if (unlikely(bio_barrier(bio))) { ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + S_BARRIER); ++ if (!list_empty(rs->sc.lists + LIST_IO) || ++ !bio_list_empty(&delay) || ++ !bio_list_empty(&reject) || ++ sc_active(&rs->sc)) { ++ bio_list_push(ios, bio); ++ break; ++ } ++ } ++ ++ r = region_state(rs, _sector(rs, bio), DM_RH_RECOVERING); ++ if (unlikely(r)) { ++ /* Got to wait for recovering regions. */ ++ bio_list_add(&delay, bio); ++ SetRSBandwidth(rs); ++ } else { ++ /* ++ * Process ios to non-recovering regions by queueing ++ * them to stripes (does rh_inc()) for writes). ++ */ ++ flush += stripe_queue_bio(rs, bio, &reject); ++ } ++ } ++ ++ if (flush) { ++ r = dm_rh_flush(rh); /* Writes got queued -> flush dirty log. */ ++ if (r) ++ DMERR("dirty log flush"); ++ } ++ ++ /* Delay ios to regions which are recovering. */ ++ while ((bio = bio_list_pop(&delay))) { ++ /* REMOVEME: statistics.*/ ++ atomic_inc(rs->stats + S_DELAYED_BIOS); ++ atomic_inc(rs->stats + S_SUM_DELAYED_BIOS); ++ dm_rh_delay_by_region(rh, bio, ++ dm_rh_sector_to_region(rh, _sector(rs, bio))); ++ ++ } ++ ++ /* Merge any rejected bios back to the head of the input list. */ ++ bio_list_merge_head(ios, &reject); ++} ++ ++/* Flush any stripes on the io list. */ ++static INLINE void do_flush(struct raid_set *rs) ++{ ++ struct list_head *list = rs->sc.lists + LIST_IO, *pos, *tmp; ++ ++ list_for_each_safe(pos, tmp, list) { ++ int r = stripe_flush(list_entry(pos, struct stripe, ++ lists[LIST_IO]), FLUSH_NOW); ++ ++ /* Remove from the list only if the stripe got processed. */ ++ if (!r) ++ list_del_init(pos); ++ } ++} ++ ++/* Send an event in case we're getting too busy. */ ++static INLINE void do_busy_event(struct raid_set *rs) ++{ ++ if ((sc_active(&rs->sc) > atomic_read(&rs->sc.stripes) * 4 / 5)) { ++ if (!TestSetRSScBusy(rs)) ++ dm_table_event(rs->ti->table); ++ } else ++ ClearRSScBusy(rs); ++} ++ ++/* Unplug: let the io role on the sets devices. */ ++static INLINE void do_unplug(struct raid_set *rs) ++{ ++ struct raid_dev *dev = rs->dev + rs->set.raid_devs; ++ ++ while (dev-- > rs->dev) { ++ /* Only call any device unplug function, if io got queued. */ ++ if (io_dev_clear(dev)) ++ blk_unplug(bdev_get_queue(dev->dev->bdev)); ++ } ++} ++ ++/*----------------------------------------------------------------- ++ * RAID daemon ++ *---------------------------------------------------------------*/ ++/* ++ * o belabour all end ios ++ * o optionally shrink the stripe cache ++ * o update the region hash states ++ * o optionally do recovery ++ * o grab the input queue ++ * o work an all requeued or new ios and perform stripe cache flushs ++ * unless the RAID set is inoperational (when we error ios) ++ * o check, if the stripe cache gets too busy and throw an event if so ++ * o unplug any component raid devices with queued bios ++ */ ++static void do_raid(struct work_struct *ws) ++{ ++ struct raid_set *rs = container_of(ws, struct raid_set, io.dws.work); ++ struct bio_list *ios = &rs->io.work, *ios_in = &rs->io.in; ++ spinlock_t *lock = &rs->io.in_lock; ++ ++ /* ++ * We always need to end io, so that ios ++ * can get errored in case the set failed ++ * and the region counters get decremented ++ * before we update the region hash states. ++ */ ++redo: ++ do_endios(rs); ++ ++ /* ++ * Now that we've end io'd, which may have put stripes on ++ * the LRU list, we shrink the stripe cache if requested. ++ */ ++ do_sc_shrink(rs); ++ ++ /* Update region hash states before we go any further. */ ++ dm_rh_update_states(rs->recover.rh, 1); ++ ++ /* Try to recover regions. */ ++ if (RSRecover(rs)) ++ do_recovery(rs); ++ ++ /* More endios -> process. */ ++ if (!stripe_endio_empty(&rs->sc)) { ++ atomic_inc(rs->stats + S_REDO); ++ goto redo; ++ } ++ ++ /* Quickly grab all new ios queued and add them to the work list. */ ++ spin_lock_irq(lock); ++ bio_list_merge(ios, ios_in); ++ bio_list_init(ios_in); ++ spin_unlock_irq(lock); ++ ++ /* Let's assume we're operational most of the time ;-). */ ++ if (likely(raid_set_operational(rs))) { ++ /* If we got ios, work them into the cache. */ ++ if (!bio_list_empty(ios)) { ++ do_ios(rs, ios); ++ do_unplug(rs); /* Unplug the sets device queues. */ ++ } ++ ++ do_flush(rs); /* Flush any stripes on io list. */ ++ do_unplug(rs); /* Unplug the sets device queues. */ ++ do_busy_event(rs); /* Check if we got too busy. */ ++ ++ /* More endios -> process. */ ++ if (!stripe_endio_empty(&rs->sc)) { ++ atomic_inc(rs->stats + S_REDO); ++ goto redo; ++ } ++ } else ++ /* No way to reconstruct data with too many devices failed. */ ++ bio_list_fail(rs, NULL, ios); ++} ++ ++/* ++ * Callback for region hash to dispatch ++ * delayed bios queued to recovered regions ++ * (Gets called via rh_update_states()). ++ */ ++static void dispatch_delayed_bios(void *context, struct bio_list *bl, int dummy) ++{ ++ struct raid_set *rs = context; ++ struct bio *bio; ++ ++ /* REMOVEME: decrement pending delayed bios counter. */ ++ bio_list_for_each(bio, bl) ++ atomic_dec(rs->stats + S_DELAYED_BIOS); ++ ++ /* Merge region hash private list to work list. */ ++ bio_list_merge_head(&rs->io.work, bl); ++ bio_list_init(bl); ++ ClearRSBandwidth(rs); ++} ++ ++/************************************************************* ++ * Constructor helpers ++ *************************************************************/ ++/* Calculate MB/sec. */ ++static INLINE unsigned mbpers(struct raid_set *rs, unsigned speed) ++{ ++ return to_bytes(speed * rs->set.data_devs * ++ rs->recover.io_size * HZ >> 10) >> 10; ++} ++ ++/* ++ * Discover fastest xor algorithm and # of chunks combination. ++ */ ++/* Calculate speed for algorithm and # of chunks. */ ++static INLINE unsigned xor_speed(struct stripe *stripe) ++{ ++ unsigned r = 0; ++ unsigned long j; ++ ++ /* Wait for next tick. */ ++ for (j = jiffies; j == jiffies;) ++ ; ++ ++ /* Do xors for a full tick. */ ++ for (j = jiffies; j == jiffies;) { ++ mb(); ++ common_xor(stripe, stripe->io.size, 0, 0); ++ mb(); ++ r++; ++ mb(); ++ } ++ ++ return r; ++} ++ ++/* Optimize xor algorithm for this RAID set. */ ++static unsigned xor_optimize(struct raid_set *rs) ++{ ++ unsigned chunks_max = 2, speed_max = 0; ++ struct xor_func *f = ARRAY_END(xor_funcs), *f_max = NULL; ++ struct stripe *stripe; ++ ++ BUG_ON(list_empty(&rs->recover.stripes)); ++ stripe = list_first_entry(&rs->recover.stripes, struct stripe, ++ lists[LIST_RECOVER]); ++ ++ /* ++ * Got to allow io on all chunks, so that ++ * xor() will actually work on them. ++ */ ++ stripe_allow_io(stripe); ++ ++ /* Try all xor functions. */ ++ while (f-- > xor_funcs) { ++ unsigned speed; ++ ++ /* Set actual xor function for common_xor(). */ ++ rs->xor.f = f; ++ rs->xor.chunks = XOR_CHUNKS_MAX + 1; ++ ++ while (rs->xor.chunks-- > 2) { ++ speed = xor_speed(stripe); ++ if (speed > speed_max) { ++ speed_max = speed; ++ chunks_max = rs->xor.chunks; ++ f_max = f; ++ } ++ } ++ } ++ ++ /* Memorize optimum parameters. */ ++ rs->xor.f = f_max; ++ rs->xor.chunks = chunks_max; ++ return speed_max; ++} ++ ++/* ++ * Allocate a RAID context (a RAID set) ++ */ ++static int ++context_alloc(struct raid_set **raid_set, struct raid_type *raid_type, ++ unsigned stripes, unsigned chunk_size, unsigned io_size, ++ unsigned recover_io_size, unsigned raid_devs, ++ sector_t sectors_per_dev, ++ struct dm_target *ti, unsigned dl_parms, char **argv) ++{ ++ int r; ++ unsigned p; ++ size_t len; ++ sector_t region_size, ti_len; ++ struct raid_set *rs = NULL; ++ struct dm_dirty_log *dl; ++ struct recover *rec; ++ ++ /* ++ * Create the dirty log ++ * ++ * We need to change length for the dirty log constructor, ++ * because we want an amount of regions for all stripes derived ++ * from the single device size, so that we can keep region ++ * size = 2^^n independant of the number of devices ++ */ ++ ti_len = ti->len; ++ ti->len = sectors_per_dev; ++ dl = dm_dirty_log_create(argv[0], ti, dl_parms, argv + 2); ++ ti->len = ti_len; ++ if (!dl) ++ goto bad_dirty_log; ++ ++ /* Chunk size *must* be smaller than region size. */ ++ region_size = dl->type->get_region_size(dl); ++ if (chunk_size > region_size) ++ goto bad_chunk_size; ++ ++ /* Recover io size *must* be smaller than region size as well. */ ++ if (recover_io_size > region_size) ++ goto bad_recover_io_size; ++ ++ /* Size and allocate the RAID set structure. */ ++ len = sizeof(*rs->data) + sizeof(*rs->dev); ++ if (array_too_big(sizeof(*rs), len, raid_devs)) ++ goto bad_array; ++ ++ len = sizeof(*rs) + raid_devs * len; ++ rs = kzalloc(len, GFP_KERNEL); ++ if (!rs) ++ goto bad_alloc; ++ ++ rec = &rs->recover; ++ atomic_set(&rs->io.in_process, 0); ++ atomic_set(&rs->io.in_process_max, 0); ++ rec->io_size = recover_io_size; ++ ++ /* Pointer to data array. */ ++ rs->data = (unsigned long **) ++ ((void *) rs->dev + raid_devs * sizeof(*rs->dev)); ++ rec->dl = dl; ++ rs->set.raid_devs = p = raid_devs; ++ rs->set.data_devs = raid_devs - raid_type->parity_devs; ++ rs->set.raid_type = raid_type; ++ ++ /* ++ * Set chunk and io size and respective shifts ++ * (used to avoid divisions) ++ */ ++ rs->set.chunk_size = chunk_size; ++ rs->set.chunk_mask = chunk_size - 1; ++ rs->set.chunk_shift = ffs(chunk_size) - 1; ++ ++ rs->set.io_size = io_size; ++ rs->set.io_mask = io_size - 1; ++ rs->set.io_shift = ffs(io_size) - 1; ++ rs->set.io_shift_mask = rs->set.chunk_mask & ~rs->set.io_mask; ++ ++ rs->set.pages_per_io = chunk_pages(io_size); ++ rs->set.sectors_per_dev = sectors_per_dev; ++ ++ rs->set.ei = -1; /* Indicate no failed device. */ ++ atomic_set(&rs->set.failed_devs, 0); ++ ++ rs->ti = ti; ++ ++ atomic_set(rec->io_count + IO_WORK, 0); ++ atomic_set(rec->io_count + IO_RECOVER, 0); ++ ++ /* Initialize io lock and queues. */ ++ spin_lock_init(&rs->io.in_lock); ++ bio_list_init(&rs->io.in); ++ bio_list_init(&rs->io.work); ++ ++ init_waitqueue_head(&rs->io.suspendq); /* Suspend waiters (dm-io). */ ++ ++ rec->nr_regions = dm_sector_div_up(sectors_per_dev, region_size); ++ rec->rh = dm_rh_client_create(MAX_RECOVER, dispatch_delayed_bios, rs, ++ wake_do_raid, rs, dl, region_size, ++ rs->recover.nr_regions); ++ if (IS_ERR(rec->rh)) ++ goto bad_rh; ++ ++ /* Initialize stripe cache. */ ++ r = sc_init(rs, stripes); ++ if (r) ++ goto bad_sc; ++ ++ /* Create dm-io client context. */ ++ rs->sc.dm_io_client = dm_io_client_create(rs->set.raid_devs * ++ rs->set.pages_per_io); ++ if (IS_ERR(rs->sc.dm_io_client)) ++ goto bad_dm_io_client; ++ ++ /* REMOVEME: statistics. */ ++ stats_reset(rs); ++ ClearRSDevelStats(rs); /* Disnable development status. */ ++ ++ *raid_set = rs; ++ return 0; ++ ++bad_dirty_log: ++ TI_ERR_RET("Error creating dirty log", -ENOMEM); ++ ++ ++bad_chunk_size: ++ dm_dirty_log_destroy(dl); ++ TI_ERR("Chunk size larger than region size"); ++ ++bad_recover_io_size: ++ dm_dirty_log_destroy(dl); ++ TI_ERR("Recover stripe io size larger than region size"); ++ ++bad_array: ++ dm_dirty_log_destroy(dl); ++ TI_ERR("Arry too big"); ++ ++bad_alloc: ++ dm_dirty_log_destroy(dl); ++ TI_ERR_RET("Cannot allocate raid context", -ENOMEM); ++ ++bad_rh: ++ dm_dirty_log_destroy(dl); ++ ti->error = DM_MSG_PREFIX "Error creating dirty region hash"; ++ goto free_rs; ++ ++bad_sc: ++ ti->error = DM_MSG_PREFIX "Error creating stripe cache"; ++ goto free; ++ ++bad_dm_io_client: ++ ti->error = DM_MSG_PREFIX "Error allocating dm-io resources"; ++free: ++ dm_rh_client_destroy(rec->rh); ++ sc_exit(&rs->sc); ++ dm_rh_client_destroy(rec->rh); /* Destroys dirty log as well. */ ++free_rs: ++ kfree(rs); ++ return -ENOMEM; ++} ++ ++/* Free a RAID context (a RAID set). */ ++static void ++context_free(struct raid_set *rs, struct dm_target *ti, unsigned r) ++{ ++ while (r--) ++ dm_put_device(ti, rs->dev[r].dev); ++ ++ dm_io_client_destroy(rs->sc.dm_io_client); ++ sc_exit(&rs->sc); ++ dm_rh_client_destroy(rs->recover.rh); ++ dm_dirty_log_destroy(rs->recover.dl); ++ kfree(rs); ++} ++ ++/* Create work queue and initialize work. */ ++static int rs_workqueue_init(struct raid_set *rs) ++{ ++ struct dm_target *ti = rs->ti; ++ ++ rs->io.wq = create_singlethread_workqueue(DAEMON); ++ if (!rs->io.wq) ++ TI_ERR_RET("failed to create " DAEMON, -ENOMEM); ++ ++ INIT_DELAYED_WORK(&rs->io.dws, do_raid); ++ return 0; ++} ++ ++/* Return pointer to raid_type structure for raid name. */ ++static struct raid_type *get_raid_type(char *name) ++{ ++ struct raid_type *r = ARRAY_END(raid_types); ++ ++ while (r-- > raid_types) { ++ if (!strnicmp(STR_LEN(r->name, name))) ++ return r; ++ } ++ ++ return NULL; ++} ++ ++/* FIXME: factor out to dm core. */ ++static int multiple(sector_t a, sector_t b, sector_t *n) ++{ ++ sector_t r = a; ++ ++ sector_div(r, b); ++ *n = r; ++ return a == r * b; ++} ++ ++/* Log RAID set information to kernel log. */ ++static void raid_set_log(struct raid_set *rs, unsigned speed) ++{ ++ unsigned p; ++ char buf[BDEVNAME_SIZE]; ++ ++ for (p = 0; p < rs->set.raid_devs; p++) ++ DMINFO("/dev/%s is raid disk %u", ++ bdevname(rs->dev[p].dev->bdev, buf), p); ++ ++ DMINFO("%d/%d/%d sectors chunk/io/recovery size, %u stripes", ++ rs->set.chunk_size, rs->set.io_size, rs->recover.io_size, ++ atomic_read(&rs->sc.stripes)); ++ DMINFO("algorithm \"%s\", %u chunks with %uMB/s", rs->xor.f->name, ++ rs->xor.chunks, mbpers(rs, speed)); ++ DMINFO("%s set with net %u/%u devices", rs->set.raid_type->descr, ++ rs->set.data_devs, rs->set.raid_devs); ++} ++ ++/* Get all devices and offsets. */ ++static int ++dev_parms(struct dm_target *ti, struct raid_set *rs, ++ char **argv, int *p) ++{ ++ for (*p = 0; *p < rs->set.raid_devs; (*p)++, argv += 2) { ++ int r; ++ unsigned long long tmp; ++ struct raid_dev *dev = rs->dev + *p; ++ union dev_lookup dl = {.dev = dev }; ++ ++ /* Get offset and device. */ ++ r = sscanf(argv[1], "%llu", &tmp); ++ if (r != 1) ++ TI_ERR("Invalid RAID device offset parameter"); ++ ++ dev->start = tmp; ++ r = dm_get_device(ti, argv[0], dev->start, ++ rs->set.sectors_per_dev, ++ dm_table_get_mode(ti->table), &dev->dev); ++ if (r) ++ TI_ERR_RET("RAID device lookup failure", r); ++ ++ r = raid_dev_lookup(rs, bynumber, &dl); ++ if (r != -ENODEV && r < *p) { ++ (*p)++; /* Ensure dm_put_device() on actual device. */ ++ TI_ERR_RET("Duplicate RAID device", -ENXIO); ++ } ++ } ++ ++ return 0; ++} ++ ++/* Set recovery bandwidth. */ ++static INLINE void ++recover_set_bandwidth(struct raid_set *rs, unsigned bandwidth) ++{ ++ rs->recover.bandwidth = bandwidth; ++ rs->recover.bandwidth_work = 100 / bandwidth; ++} ++ ++/* Handle variable number of RAID parameters. */ ++static int ++raid_variable_parms(struct dm_target *ti, char **argv, ++ unsigned i, int *raid_parms, ++ int *chunk_size, int *chunk_size_parm, ++ int *stripes, int *stripes_parm, ++ int *io_size, int *io_size_parm, ++ int *recover_io_size, int *recover_io_size_parm, ++ int *bandwidth, int *bandwidth_parm) ++{ ++ /* Fetch # of variable raid parameters. */ ++ if (sscanf(argv[i++], "%d", raid_parms) != 1 || ++ !range_ok(*raid_parms, 0, 5)) ++ TI_ERR("Bad variable raid parameters number"); ++ ++ if (*raid_parms) { ++ /* ++ * If we've got variable RAID parameters, ++ * chunk size is the first one ++ */ ++ if (sscanf(argv[i++], "%d", chunk_size) != 1 || ++ (*chunk_size != -1 && ++ (!POWER_OF_2(*chunk_size) || ++ !range_ok(*chunk_size, IO_SIZE_MIN, CHUNK_SIZE_MAX)))) ++ TI_ERR("Invalid chunk size; must be 2^^n and <= 16384"); ++ ++ *chunk_size_parm = *chunk_size; ++ if (*chunk_size == -1) ++ *chunk_size = CHUNK_SIZE; ++ ++ /* ++ * In case we've got 2 or more variable raid ++ * parameters, the number of stripes is the second one ++ */ ++ if (*raid_parms > 1) { ++ if (sscanf(argv[i++], "%d", stripes) != 1 || ++ (*stripes != -1 && ++ !range_ok(*stripes, STRIPES_MIN, ++ STRIPES_MAX))) ++ TI_ERR("Invalid number of stripes: must " ++ "be >= 8 and <= 8192"); ++ } ++ ++ *stripes_parm = *stripes; ++ if (*stripes == -1) ++ *stripes = STRIPES; ++ ++ /* ++ * In case we've got 3 or more variable raid ++ * parameters, the io size is the third one. ++ */ ++ if (*raid_parms > 2) { ++ if (sscanf(argv[i++], "%d", io_size) != 1 || ++ (*io_size != -1 && ++ (!POWER_OF_2(*io_size) || ++ !range_ok(*io_size, IO_SIZE_MIN, ++ min(BIO_MAX_SECTORS / 2, ++ *chunk_size))))) ++ TI_ERR("Invalid io size; must " ++ "be 2^^n and less equal " ++ "min(BIO_MAX_SECTORS/2, chunk size)"); ++ } else ++ *io_size = *chunk_size; ++ ++ *io_size_parm = *io_size; ++ if (*io_size == -1) ++ *io_size = *chunk_size; ++ ++ /* ++ * In case we've got 4 variable raid parameters, ++ * the recovery stripe io_size is the fourth one ++ */ ++ if (*raid_parms > 3) { ++ if (sscanf(argv[i++], "%d", recover_io_size) != 1 || ++ (*recover_io_size != -1 && ++ (!POWER_OF_2(*recover_io_size) || ++ !range_ok(*recover_io_size, RECOVER_IO_SIZE_MIN, ++ BIO_MAX_SECTORS / 2)))) ++ TI_ERR("Invalid recovery io size; must be " ++ "2^^n and less equal BIO_MAX_SECTORS/2"); ++ } ++ ++ *recover_io_size_parm = *recover_io_size; ++ if (*recover_io_size == -1) ++ *recover_io_size = RECOVER_IO_SIZE; ++ ++ /* ++ * In case we've got 5 variable raid parameters, ++ * the recovery io bandwidth is the fifth one ++ */ ++ if (*raid_parms > 4) { ++ if (sscanf(argv[i++], "%d", bandwidth) != 1 || ++ (*bandwidth != -1 && ++ !range_ok(*bandwidth, BANDWIDTH_MIN, ++ BANDWIDTH_MAX))) ++ TI_ERR("Invalid recovery bandwidth " ++ "percentage; must be > 0 and <= 100"); ++ } ++ ++ *bandwidth_parm = *bandwidth; ++ if (*bandwidth == -1) ++ *bandwidth = BANDWIDTH; ++ } ++ ++ return 0; ++} ++ ++/* Parse optional locking parameters. */ ++static int ++raid_locking_parms(struct dm_target *ti, char **argv, ++ unsigned i, int *locking_parms, ++ struct dm_raid45_locking_type **locking_type) ++{ ++ *locking_parms = 0; ++ *locking_type = &locking_none; ++ ++ if (!strnicmp(argv[i], "none", strlen(argv[i]))) ++ *locking_parms = 1; ++ else if (!strnicmp(argv[i + 1], "locking", strlen(argv[i + 1]))) { ++ *locking_type = &locking_none; ++ *locking_parms = 2; ++ } else if (!strnicmp(argv[i + 1], "cluster", strlen(argv[i + 1]))) { ++ *locking_type = &locking_cluster; ++ /* FIXME: namespace. */ ++ *locking_parms = 3; ++ } ++ ++ return *locking_parms == 1 ? -EINVAL : 0; ++} ++ ++/* Set backing device information properties of RAID set. */ ++static void rs_set_bdi(struct raid_set *rs, unsigned stripes, unsigned chunks) ++{ ++ unsigned p, ra_pages; ++ struct mapped_device *md = dm_table_get_md(rs->ti->table); ++ struct backing_dev_info *bdi = &dm_disk(md)->queue->backing_dev_info; ++ ++ /* Set read-ahead for the RAID set and the component devices. */ ++ bdi->ra_pages = stripes * stripe_pages(rs, rs->set.io_size); ++ ra_pages = chunks * chunk_pages(rs->set.io_size); ++ for (p = rs->set.raid_devs; p--; ) { ++ struct request_queue *q = bdev_get_queue(rs->dev[p].dev->bdev); ++ ++ q->backing_dev_info.ra_pages = ra_pages; ++ } ++ ++ /* Set congested function and data. */ ++ bdi->congested_fn = raid_set_congested; ++ bdi->congested_data = rs; ++ ++ dm_put(md); ++} ++ ++/* Get backing device information properties of RAID set. */ ++static void rs_get_ra(struct raid_set *rs, unsigned *stripes, unsigned *chunks) ++{ ++ struct mapped_device *md = dm_table_get_md(rs->ti->table); ++ ++ *stripes = dm_disk(md)->queue->backing_dev_info.ra_pages ++ / stripe_pages(rs, rs->set.io_size); ++ *chunks = bdev_get_queue(rs->dev->dev->bdev)->backing_dev_info.ra_pages ++ / chunk_pages(rs->set.io_size); ++ ++ dm_put(md); ++} ++ ++/* ++ * Construct a RAID4/5 mapping: ++ * ++ * log_type #log_params \ ++ * raid_type [#parity_dev] #raid_variable_params \ ++ * [locking "none"/"cluster"] ++ * #raid_devs #dev_to_initialize [ ]{3,} ++ * ++ * log_type = "core"/"disk", ++ * #log_params = 1-3 (1-2 for core dirty log type, 3 for disk dirty log only) ++ * log_params = [dirty_log_path] region_size [[no]sync]) ++ * ++ * raid_type = "raid4", "raid5_la", "raid5_ra", "raid5_ls", "raid5_rs" ++ * ++ * #parity_dev = N if raid_type = "raid4" ++ * o N = -1: pick default = last device ++ * o N >= 0 and < #raid_devs: parity device index ++ * ++ * #raid_variable_params = 0-5; raid_params (-1 = default): ++ * [chunk_size [#stripes [io_size [recover_io_size [%recovery_bandwidth]]]]] ++ * o chunk_size (unit to calculate drive addresses; must be 2^^n, > 8 ++ * and <= CHUNK_SIZE_MAX) ++ * o #stripes is number of stripes allocated to stripe cache ++ * (must be > 1 and < STRIPES_MAX) ++ * o io_size (io unit size per device in sectors; must be 2^^n and > 8) ++ * o recover_io_size (io unit size per device for recovery in sectors; ++ must be 2^^n, > SECTORS_PER_PAGE and <= region_size) ++ * o %recovery_bandwith is the maximum amount spend for recovery during ++ * application io (1-100%) ++ * If raid_variable_params = 0, defaults will be used. ++ * Any raid_variable_param can be set to -1 to apply a default ++ * ++ * #raid_devs = N (N >= 3) ++ * ++ * #dev_to_initialize = N ++ * -1: initialize parity on all devices ++ * >= 0 and < #raid_devs: initialize raid_path; used to force reconstruction ++ * of a failed devices content after replacement ++ * ++ * = device_path (eg, /dev/sdd1) ++ * = begin at offset on ++ * ++ */ ++#define MIN_PARMS 13 ++static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) ++{ ++ int bandwidth = BANDWIDTH, bandwidth_parm = -1, ++ chunk_size = CHUNK_SIZE, chunk_size_parm = -1, ++ dev_to_init, dl_parms, locking_parms, parity_parm, pi = -1, ++ i, io_size = IO_SIZE, io_size_parm = -1, ++ r, raid_devs, raid_parms, ++ recover_io_size = RECOVER_IO_SIZE, recover_io_size_parm = -1, ++ stripes = STRIPES, stripes_parm = -1; ++ unsigned speed; ++ sector_t tmp, sectors_per_dev; ++ struct dm_raid45_locking_type *locking; ++ struct raid_set *rs; ++ struct raid_type *raid_type; ++ ++ /* Ensure minimum number of parameters. */ ++ if (argc < MIN_PARMS) ++ TI_ERR("Not enough parameters"); ++ ++ /* Fetch # of dirty log parameters. */ ++ if (sscanf(argv[1], "%d", &dl_parms) != 1 ++ || !range_ok(dl_parms, 1, 4711)) ++ TI_ERR("Bad dirty log parameters number"); ++ ++ /* Check raid_type. */ ++ raid_type = get_raid_type(argv[dl_parms + 2]); ++ if (!raid_type) ++ TI_ERR("Bad raid type"); ++ ++ /* In case of RAID4, parity drive is selectable. */ ++ parity_parm = !!(raid_type->level == raid4); ++ ++ /* Handle variable number of RAID parameters. */ ++ r = raid_variable_parms(ti, argv, dl_parms + parity_parm + 3, ++ &raid_parms, ++ &chunk_size, &chunk_size_parm, ++ &stripes, &stripes_parm, ++ &io_size, &io_size_parm, ++ &recover_io_size, &recover_io_size_parm, ++ &bandwidth, &bandwidth_parm); ++ if (r) ++ return r; ++ ++ r = raid_locking_parms(ti, argv, ++ dl_parms + parity_parm + raid_parms + 4, ++ &locking_parms, &locking); ++ if (r) ++ return r; ++ ++ /* # of raid devices. */ ++ i = dl_parms + parity_parm + raid_parms + locking_parms + 4; ++ if (sscanf(argv[i], "%d", &raid_devs) != 1 || ++ raid_devs < raid_type->minimal_devs) ++ TI_ERR("Invalid number of raid devices"); ++ ++ /* In case of RAID4, check parity drive index is in limits. */ ++ if (raid_type->level == raid4) { ++ /* Fetch index of parity device. */ ++ if (sscanf(argv[dl_parms + 3], "%d", &pi) != 1 || ++ !range_ok(pi, 0, raid_devs - 1)) ++ TI_ERR("Invalid RAID4 parity device index"); ++ } ++ ++ /* ++ * Index of device to initialize starts at 0 ++ * ++ * o -1 -> don't initialize a particular device, ++ * o 0..raid_devs-1 -> initialize respective device ++ * (used for reconstruction of a replaced device) ++ */ ++ if (sscanf ++ (argv[dl_parms + parity_parm + raid_parms + locking_parms + 5], ++ "%d", &dev_to_init) != 1 ++ || !range_ok(dev_to_init, -1, raid_devs - 1)) ++ TI_ERR("Invalid number for raid device to initialize"); ++ ++ /* Check # of raid device arguments. */ ++ if (argc - dl_parms - parity_parm - raid_parms - 6 != ++ 2 * raid_devs) ++ TI_ERR("Wrong number of raid device/offset arguments"); ++ ++ /* ++ * Check that the table length is devisable ++ * w/o rest by (raid_devs - parity_devs) ++ */ ++ if (!multiple(ti->len, raid_devs - raid_type->parity_devs, ++ §ors_per_dev)) ++ TI_ERR ++ ("Target length not divisable by number of data devices"); ++ ++ /* ++ * Check that the device size is ++ * devisable w/o rest by chunk size ++ */ ++ if (!multiple(sectors_per_dev, chunk_size, &tmp)) ++ TI_ERR("Device length not divisable by chunk_size"); ++ ++ /**************************************************************** ++ * Now that we checked the constructor arguments -> ++ * let's allocate the RAID set ++ ****************************************************************/ ++ r = context_alloc(&rs, raid_type, stripes, chunk_size, io_size, ++ recover_io_size, raid_devs, sectors_per_dev, ++ ti, dl_parms, argv); ++ if (r) ++ return r; ++ ++ /* ++ * Set these here in order to avoid passing ++ * too many arguments to context_alloc() ++ */ ++ rs->set.dev_to_init_parm = dev_to_init; ++ rs->set.dev_to_init = dev_to_init; ++ rs->set.pi_parm = pi; ++ rs->set.pi = (pi == -1) ? rs->set.data_devs : pi; ++ rs->set.raid_parms = raid_parms; ++ rs->set.chunk_size_parm = chunk_size_parm; ++ rs->set.io_size_parm = io_size_parm; ++ rs->sc.stripes_parm = stripes_parm; ++ rs->recover.io_size_parm = recover_io_size_parm; ++ rs->recover.bandwidth_parm = bandwidth_parm; ++ recover_set_bandwidth(rs, bandwidth); ++ ++ /* Use locking type to lock stripe access. */ ++ rs->locking = locking; ++ ++ /* Get the device/offset tupels. */ ++ argv += dl_parms + 6 + parity_parm + raid_parms; ++ r = dev_parms(ti, rs, argv, &i); ++ if (r) ++ goto err; ++ ++ /* Initialize recovery. */ ++ rs->recover.start_jiffies = jiffies; ++ rs->recover.end_jiffies = 0; ++ recovery_region_reset(rs); ++ ++ /* Allow for recovery of any nosync regions. */ ++ SetRSRecover(rs); ++ ++ /* Set backing device information (eg. read ahead). */ ++ rs_set_bdi(rs, chunk_size * 2, io_size * 4); ++ SetRSCheckOverwrite(rs); /* Allow chunk overwrite checks. */ ++ ++ speed = xor_optimize(rs); /* Select best xor algorithm. */ ++ ++ /* Initialize work queue to handle this RAID set's io. */ ++ r = rs_workqueue_init(rs); ++ if (r) ++ goto err; ++ ++ raid_set_log(rs, speed); /* Log information about RAID set. */ ++ ++ /* ++ * Make sure that dm core only hands maximum io size ++ * length down and pays attention to io boundaries. ++ */ ++ ti->split_io = rs->set.io_size; ++ ti->private = rs; ++ return 0; ++ ++err: ++ context_free(rs, ti, i); ++ return r; ++} ++ ++/* ++ * Destruct a raid mapping ++ */ ++static void raid_dtr(struct dm_target *ti) ++{ ++ struct raid_set *rs = ti->private; ++ ++ /* Indicate recovery end so that ios in flight drain. */ ++ ClearRSRecover(rs); ++ ++ wake_do_raid(rs); /* Wake daemon. */ ++ wait_ios(rs); /* Wait for any io still being processed. */ ++ destroy_workqueue(rs->io.wq); ++ context_free(rs, ti, rs->set.raid_devs); ++} ++ ++/* Queues ios to RAID sets. */ ++static inline void queue_bio(struct raid_set *rs, struct bio *bio) ++{ ++ int wake; ++ struct bio_list *in = &rs->io.in; ++ spinlock_t *in_lock = &rs->io.in_lock; ++ ++ spin_lock_irq(in_lock); ++ wake = bio_list_empty(in); ++ bio_list_add(in, bio); ++ spin_unlock_irq(in_lock); ++ ++ /* Wake daemon if input list was empty. */ ++ if (wake) ++ wake_do_raid(rs); ++} ++ ++/* Raid mapping function. */ ++static int raid_map(struct dm_target *ti, struct bio *bio, ++ union map_info *map_context) ++{ ++ /* I don't want to waste stripe cache capacity. */ ++ if (bio_rw(bio) == READA) ++ return -EIO; ++ else { ++ struct raid_set *rs = ti->private; ++ ++ /* REMOVEME: statistics. */ ++ atomic_inc(rs->stats + ++ (bio_data_dir(bio) == WRITE ? ++ S_BIOS_WRITE : S_BIOS_READ)); ++ ++ /* ++ * Get io reference to be waiting for to drop ++ * to zero on device suspension/destruction. ++ */ ++ io_get(rs); ++ bio->bi_sector -= ti->begin; /* Remap sector. */ ++ queue_bio(rs, bio); /* Queue to the daemon. */ ++ return DM_MAPIO_SUBMITTED; /* Handle later. */ ++ } ++} ++ ++/* Device suspend. */ ++static void raid_postsuspend(struct dm_target *ti) ++{ ++ struct raid_set *rs = ti->private; ++ struct dm_dirty_log *dl = rs->recover.dl; ++ ++ SetRSSuspended(rs); ++ ++ if (RSRecover(rs)) ++ dm_rh_stop_recovery(rs->recover.rh); /* Wakes do_raid(). */ ++ else ++ wake_do_raid(rs); ++ ++ wait_ios(rs); /* Wait for completion of all ios being processed. */ ++ if (dl->type->postsuspend && dl->type->postsuspend(dl)) ++ /* Suspend dirty log. */ ++ /* FIXME: need better error handling. */ ++ DMWARN("log suspend failed"); ++} ++ ++/* Device resume. */ ++static void raid_resume(struct dm_target *ti) ++{ ++ struct raid_set *rs = ti->private; ++ struct recover *rec = &rs->recover; ++ struct dm_dirty_log *dl = rec->dl; ++ ++ if (dl->type->resume && dl->type->resume(dl)) ++ /* Resume dirty log. */ ++ /* FIXME: need better error handling. */ ++ DMWARN("log resume failed"); ++ ++ rec->nr_regions_to_recover = ++ rec->nr_regions - dl->type->get_sync_count(dl); ++ ++ ClearRSSuspended(rs); ++ ++ /* Reset any unfinished recovery. */ ++ if (RSRecover(rs)) { ++ recovery_region_reset(rs); ++ dm_rh_start_recovery(rec->rh);/* Calls wake_do_raid(). */ ++ } else ++ wake_do_raid(rs); ++} ++ ++static INLINE unsigned sc_size(struct raid_set *rs) ++{ ++ return to_sector(atomic_read(&rs->sc.stripes) * ++ (sizeof(struct stripe) + ++ (sizeof(struct stripe_set) + ++ (sizeof(struct page_list) + ++ to_bytes(rs->set.io_size) * ++ rs->set.raid_devs)) + ++ (rs->recover. ++ end_jiffies ? 0 : to_bytes(rs->set.raid_devs * ++ rs->recover. ++ io_size)))); ++} ++ ++/* REMOVEME: status output for development. */ ++static void ++raid_devel_stats(struct dm_target *ti, char *result, ++ unsigned *size, unsigned maxlen) ++{ ++ unsigned chunks, stripes, sz = *size; ++ unsigned long j; ++ char buf[BDEVNAME_SIZE], *p; ++ struct stats_map *sm, *sm_end = ARRAY_END(stats_map); ++ struct raid_set *rs = ti->private; ++ struct recover *rec = &rs->recover; ++ struct timespec ts; ++ ++ DMEMIT("%s ", version); ++ DMEMIT("io_inprocess=%d ", atomic_read(&rs->io.in_process)); ++ DMEMIT("io_inprocess_max=%d ", atomic_read(&rs->io.in_process_max)); ++ ++ for (sm = stats_map; sm < sm_end; sm++) ++ DMEMIT("%s%d", sm->str, atomic_read(rs->stats + sm->type)); ++ ++ DMEMIT(" overwrite=%s ", RSCheckOverwrite(rs) ? "on" : "off"); ++ DMEMIT("sc=%u/%u/%u/%u/%u ", rs->set.chunk_size, rs->set.io_size, ++ atomic_read(&rs->sc.stripes), rs->sc.hash.buckets, ++ sc_size(rs)); ++ ++ j = (rec->end_jiffies ? rec->end_jiffies : jiffies) - ++ rec->start_jiffies; ++ jiffies_to_timespec(j, &ts); ++ sprintf(buf, "%ld.%ld", ts.tv_sec, ts.tv_nsec); ++ p = strchr(buf, '.'); ++ p[3] = 0; ++ ++ DMEMIT("rg=%llu%s/%llu/%llu/%u %s ", ++ (unsigned long long) rec->nr_regions_recovered, ++ RSRegionGet(rs) ? "+" : "", ++ (unsigned long long) rec->nr_regions_to_recover, ++ (unsigned long long) rec->nr_regions, rec->bandwidth, buf); ++ ++ rs_get_ra(rs, &stripes, &chunks); ++ DMEMIT("ra=%u/%u ", stripes, chunks); ++ ++ *size = sz; ++} ++ ++static int ++raid_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned maxlen) ++{ ++ unsigned i, sz = 0; ++ char buf[BDEVNAME_SIZE]; ++ struct raid_set *rs = ti->private; ++ ++ switch (type) { ++ case STATUSTYPE_INFO: ++ /* REMOVEME: statistics. */ ++ if (RSDevelStats(rs)) ++ raid_devel_stats(ti, result, &sz, maxlen); ++ ++ DMEMIT("%u ", rs->set.raid_devs); ++ ++ for (i = 0; i < rs->set.raid_devs; i++) ++ DMEMIT("%s ", ++ format_dev_t(buf, rs->dev[i].dev->bdev->bd_dev)); ++ ++ DMEMIT("1 "); ++ for (i = 0; i < rs->set.raid_devs; i++) { ++ DMEMIT("%c", dev_operational(rs, i) ? 'A' : 'D'); ++ ++ if (rs->set.raid_type->level == raid4 && ++ i == rs->set.pi) ++ DMEMIT("p"); ++ ++ if (rs->set.dev_to_init == i) ++ DMEMIT("i"); ++ } ++ ++ break; ++ ++ case STATUSTYPE_TABLE: ++ sz = rs->recover.dl->type->status(rs->recover.dl, type, ++ result, maxlen); ++ DMEMIT("%s %u ", rs->set.raid_type->name, ++ rs->set.raid_parms); ++ ++ if (rs->set.raid_type->level == raid4) ++ DMEMIT("%d ", rs->set.pi_parm); ++ ++ if (rs->set.raid_parms) ++ DMEMIT("%d ", rs->set.chunk_size_parm); ++ ++ if (rs->set.raid_parms > 1) ++ DMEMIT("%d ", rs->sc.stripes_parm); ++ ++ if (rs->set.raid_parms > 2) ++ DMEMIT("%d ", rs->set.io_size_parm); ++ ++ if (rs->set.raid_parms > 3) ++ DMEMIT("%d ", rs->recover.io_size_parm); ++ ++ if (rs->set.raid_parms > 4) ++ DMEMIT("%d ", rs->recover.bandwidth_parm); ++ ++ DMEMIT("%u %d ", rs->set.raid_devs, rs->set.dev_to_init); ++ ++ for (i = 0; i < rs->set.raid_devs; i++) ++ DMEMIT("%s %llu ", ++ format_dev_t(buf, ++ rs->dev[i].dev->bdev->bd_dev), ++ (unsigned long long) rs->dev[i].start); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Message interface ++ */ ++enum raid_msg_actions { ++ act_bw, /* Recovery bandwidth switch. */ ++ act_dev, /* Device failure switch. */ ++ act_overwrite, /* Stripe overwrite check. */ ++ act_read_ahead, /* Set read ahead. */ ++ act_stats, /* Development statistics switch. */ ++ act_sc, /* Stripe cache switch. */ ++ ++ act_on, /* Set entity on. */ ++ act_off, /* Set entity off. */ ++ act_reset, /* Reset entity. */ ++ ++ act_set = act_on, /* Set # absolute. */ ++ act_grow = act_off, /* Grow # by an amount. */ ++ act_shrink = act_reset, /* Shrink # by an amount. */ ++}; ++ ++/* Turn a delta to absolute. */ ++static int _absolute(unsigned long action, int act, int r) ++{ ++ /* Make delta absolute. */ ++ if (test_bit(act_set, &action)) ++ ; ++ else if (test_bit(act_grow, &action)) ++ r += act; ++ else if (test_bit(act_shrink, &action)) ++ r = act - r; ++ else ++ r = -EINVAL; ++ ++ return r; ++} ++ ++ /* Change recovery io bandwidth. */ ++static int bandwidth_change(struct dm_msg *msg, void *context) ++{ ++ struct raid_set *rs = context; ++ int act = rs->recover.bandwidth; ++ int bandwidth = DM_MSG_INT_ARG(msg); ++ ++ if (range_ok(bandwidth, BANDWIDTH_MIN, BANDWIDTH_MAX)) { ++ /* Make delta bandwidth absolute. */ ++ bandwidth = _absolute(msg->action, act, bandwidth); ++ ++ /* Check range. */ ++ if (range_ok(bandwidth, BANDWIDTH_MIN, BANDWIDTH_MAX)) { ++ recover_set_bandwidth(rs, bandwidth); ++ return 0; ++ } ++ } ++ ++ set_bit(dm_msg_ret_arg, &msg->ret); ++ set_bit(dm_msg_ret_inval, &msg->ret); ++ return -EINVAL; ++} ++ ++/* Change state of a device (running/offline). */ ++/* FIXME: this only works while recovering!. */ ++static int device_state(struct dm_msg *msg, void *context) ++{ ++ int r; ++ const char *str = "is already "; ++ union dev_lookup dl = { .dev_name = DM_MSG_STR_ARG(msg) }; ++ struct raid_set *rs = context; ++ ++ r = raid_dev_lookup(rs, strchr(dl.dev_name, ':') ? ++ bymajmin : byname, &dl); ++ if (r == -ENODEV) { ++ DMERR("device %s is no member of this set", dl.dev_name); ++ return r; ++ } ++ ++ if (test_bit(act_off, &msg->action)) { ++ if (dev_operational(rs, r)) ++ str = ""; ++ } else if (!dev_operational(rs, r)) ++ str = ""; ++ ++ DMINFO("/dev/%s %s%s", dl.dev_name, str, ++ test_bit(act_off, &msg->action) ? "offline" : "running"); ++ ++ return test_bit(act_off, &msg->action) ? ++ raid_set_check_and_degrade(rs, NULL, r) : ++ raid_set_check_and_upgrade(rs, r); ++} ++ ++/* Set/reset development feature flags. */ ++static int devel_flags(struct dm_msg *msg, void *context) ++{ ++ struct raid_set *rs = context; ++ ++ if (test_bit(act_on, &msg->action)) ++ return test_and_set_bit(msg->spec->parm, ++ &rs->io.flags) ? -EPERM : 0; ++ else if (test_bit(act_off, &msg->action)) ++ return test_and_clear_bit(msg->spec->parm, ++ &rs->io.flags) ? 0 : -EPERM; ++ else if (test_bit(act_reset, &msg->action)) { ++ if (test_bit(act_stats, &msg->action)) { ++ stats_reset(rs); ++ goto on; ++ } else if (test_bit(act_overwrite, &msg->action)) { ++on: ++ set_bit(msg->spec->parm, &rs->io.flags); ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++ /* Set stripe and chunk read ahead pages. */ ++static int read_ahead_set(struct dm_msg *msg, void *context) ++{ ++ int stripes = DM_MSG_INT_ARGS(msg, 0); ++ int chunks = DM_MSG_INT_ARGS(msg, 1); ++ ++ if (range_ok(stripes, 1, 512) && ++ range_ok(chunks, 1, 512)) { ++ rs_set_bdi(context, stripes, chunks); ++ return 0; ++ } ++ ++ set_bit(dm_msg_ret_arg, &msg->ret); ++ set_bit(dm_msg_ret_inval, &msg->ret); ++ return -EINVAL; ++} ++ ++/* Resize the stripe cache. */ ++static int stripecache_resize(struct dm_msg *msg, void *context) ++{ ++ int act, stripes; ++ struct raid_set *rs = context; ++ ++ /* Deny permission in case the daemon is still shrinking!. */ ++ if (atomic_read(&rs->sc.stripes_to_shrink)) ++ return -EPERM; ++ ++ stripes = DM_MSG_INT_ARG(msg); ++ if (stripes > 0) { ++ act = atomic_read(&rs->sc.stripes); ++ ++ /* Make delta stripes absolute. */ ++ stripes = _absolute(msg->action, act, stripes); ++ ++ /* ++ * Check range and that the # of stripes changes. ++ * We can grow from gere but need to leave any ++ * shrinking to the worker for synchronization. ++ */ ++ if (range_ok(stripes, STRIPES_MIN, STRIPES_MAX)) { ++ if (stripes > act) ++ return sc_grow(&rs->sc, stripes - act, SC_GROW); ++ else if (stripes < act) { ++ atomic_set(&rs->sc.stripes_to_shrink, ++ act - stripes); ++ wake_do_raid(rs); ++ } ++ ++ return 0; ++ } ++ } ++ ++ set_bit(dm_msg_ret_arg, &msg->ret); ++ set_bit(dm_msg_ret_inval, &msg->ret); ++ return -EINVAL; ++} ++ ++/* Parse the RAID message action. */ ++/* ++ * 'ba[ndwidth] {se[t],g[row],sh[rink]} #' # e.g 'ba se 50' ++ * 'de{vice] o[ffline]/r[unning] DevName/maj:min' # e.g 'device o /dev/sda' ++ * "o[verwrite] {on,of[f],r[eset]}' # e.g. 'o of' ++ * "r[ead_ahead] set #stripes #chunks # e.g. 'r se 3 2' ++ * 'sta[tistics] {on,of[f],r[eset]}' # e.g. 'stat of' ++ * 'str[ipecache] {se[t],g[row],sh[rink]} #' # e.g. 'stripe set 1024' ++ * ++ */ ++static int ++raid_message(struct dm_target *ti, unsigned argc, char **argv) ++{ ++ /* Variables to store the parsed parameters im. */ ++ static int i[2]; ++ static unsigned long *i_arg[] = { ++ (unsigned long *) i + 0, ++ (unsigned long *) i + 1, ++ }; ++ static char *p; ++ static unsigned long *p_arg[] = { (unsigned long *) &p }; ++ ++ /* Declare all message option strings. */ ++ static char *str_sgs[] = { "set", "grow", "shrink" }; ++ static char *str_dev[] = { "running", "offline" }; ++ static char *str_oor[] = { "on", "off", "reset" }; ++ ++ /* Declare all actions. */ ++ static unsigned long act_sgs[] = { act_set, act_grow, act_shrink }; ++ static unsigned long act_oor[] = { act_on, act_off, act_reset }; ++ ++ /* Bandwidth option. */ ++ static struct dm_message_option bw_opt = { 3, str_sgs, act_sgs }; ++ static struct dm_message_argument bw_args = { ++ 1, i_arg, { dm_msg_int_t } ++ }; ++ ++ /* Device option. */ ++ static struct dm_message_option dev_opt = { 2, str_dev, act_oor }; ++ static struct dm_message_argument dev_args = { ++ 1, p_arg, { dm_msg_base_t } ++ }; ++ ++ /* Read ahead option. */ ++ static struct dm_message_option ra_opt = { 1, str_sgs, act_sgs }; ++ static struct dm_message_argument ra_args = { ++ 2, i_arg, { dm_msg_int_t, dm_msg_int_t } ++ }; ++ ++ static struct dm_message_argument null_args = { ++ 0, NULL, { dm_msg_int_t } ++ }; ++ ++ /* Overwrite and statistics option. */ ++ static struct dm_message_option ovr_stats_opt = { 3, str_oor, act_oor }; ++ ++ /* Sripecache option. */ ++ static struct dm_message_option stripe_opt = { 3, str_sgs, act_sgs }; ++ ++ /* Declare messages. */ ++ static struct dm_msg_spec specs[] = { ++ { "bandwidth", act_bw, &bw_opt, &bw_args, ++ 0, bandwidth_change }, ++ { "device", act_dev, &dev_opt, &dev_args, ++ 0, device_state }, ++ { "overwrite", act_overwrite, &ovr_stats_opt, &null_args, ++ RS_CHECK_OVERWRITE, devel_flags }, ++ { "read_ahead", act_read_ahead, &ra_opt, &ra_args, ++ 0, read_ahead_set }, ++ { "statistics", act_stats, &ovr_stats_opt, &null_args, ++ RS_DEVEL_STATS, devel_flags }, ++ { "stripecache", act_sc, &stripe_opt, &bw_args, ++ 0, stripecache_resize }, ++ }; ++ ++ /* The message for the parser. */ ++ struct dm_msg msg = { ++ .num_specs = ARRAY_SIZE(specs), ++ .specs = specs, ++ }; ++ ++ return dm_message_parse(TARGET, &msg, ti->private, argc, argv); ++} ++/* ++ * END message interface ++ */ ++ ++static struct target_type raid_target = { ++ .name = "raid45", ++ .version = {1, 0, 0}, ++ .module = THIS_MODULE, ++ .ctr = raid_ctr, ++ .dtr = raid_dtr, ++ .map = raid_map, ++ .postsuspend = raid_postsuspend, ++ .resume = raid_resume, ++ .status = raid_status, ++ .message = raid_message, ++}; ++ ++static void init_exit(const char *bad_msg, const char *good_msg, int r) ++{ ++ if (r) ++ DMERR("Failed to %sregister target [%d]", bad_msg, r); ++ else ++ DMINFO("%s %s", good_msg, version); ++} ++ ++static int __init dm_raid_init(void) ++{ ++ int r; ++ ++ r = dm_register_target(&raid_target); ++ init_exit("", "initialized", r); ++ return r; ++} ++ ++static void __exit dm_raid_exit(void) ++{ ++ int r; ++ ++ r = dm_unregister_target(&raid_target); ++ init_exit("un", "exit", r); ++} ++ ++/* Module hooks. */ ++module_init(dm_raid_init); ++module_exit(dm_raid_exit); ++ ++MODULE_DESCRIPTION(DM_NAME " raid4/5 target"); ++MODULE_AUTHOR("Heinz Mauelshagen "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/md/dm-raid45.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. ++ * ++ * Module Author: Heinz Mauelshagen (Mauelshagen@RedHat.com) ++ * ++ * Locking definitions for the device-mapper RAID45 target. ++ * ++ * This file is released under the GPL. ++ * ++ */ ++ ++#ifndef _DM_RAID45_H ++#define _DM_RAID45_H ++ ++/* Factor out to dm.h! */ ++#define STR_LEN(ptr, str) (ptr), (str), strlen((ptr)) ++ ++enum dm_lock_type { DM_RAID45_EX, DM_RAID45_SHARED }; ++ ++struct dm_raid45_locking_type { ++ /* Request a lock on a stripe. */ ++ void* (*lock)(sector_t key, enum dm_lock_type type); ++ ++ /* Release a lock on a stripe. */ ++ void (*unlock)(void *lock_handle); ++}; ++ ++#endif +--- /dev/null ++++ b/drivers/md/dm-regions.c +@@ -0,0 +1,723 @@ ++/* ++ * Copyright (C) 2003 Sistina Software Limited. ++ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. ++ * ++ * This file is released under the GPL. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "dm.h" ++#include "dm-bio-list.h" ++ ++#define DM_MSG_PREFIX "region hash" ++ ++/*----------------------------------------------------------------- ++ * Region hash ++ * ++ * A storage set (eg. RAID1, RAID5) splits itself up into discrete regions. ++ * Each region can be in one of three states: ++ * ++ * o clean ++ * o dirty, ++ * o nosync. ++ * ++ * There is no need to put clean regions in the hash. ++ * ++ * ++ * In addition to being present in the hash table a region _may_ ++ * be present on one of three lists. ++ * ++ * clean_regions: Regions on this list have no io pending to ++ * them, they are in sync, we are no longer interested in them, ++ * they are dull. dm_rh_update_states() will remove them from the ++ * hash table. ++ * ++ * quiesced_regions: These regions have been spun down, ready ++ * for recovery. dm_rh_recovery_start() will remove regions from ++ * this list and hand them to the caller, which will schedule the ++ * recovery io. ++ * ++ * recovered_regions: Regions that the caller has successfully ++ * recovered. dm_rh_update_states() will now schedule any delayed ++ * io, up the recovery_count, and remove the region from the hash. ++ * ++ * There are 2 locks: ++ * A rw spin lock 'hash_lock' protects just the hash table, ++ * this is never held in write mode from interrupt context, ++ * which I believe means that we only have to disable irqs when ++ * doing a write lock. ++ * ++ * An ordinary spin lock 'region_lock' that protects the three ++ * lists in the region_hash, with the 'state', 'list' and ++ * 'delayed_bios' fields of the regions. This is used from irq ++ * context, so all other uses will have to suspend local irqs. ++ *---------------------------------------------------------------*/ ++struct region_hash { ++ unsigned max_recovery; /* Max # of regions to recover in parallel */ ++ ++ /* Callback function to dispatch queued writes on recovered regions. */ ++ void (*dispatch)(void *context, struct bio_list *bios, int error); ++ void *dispatch_context; ++ ++ /* Callback function to wakeup callers worker thread. */ ++ void (*wake)(void *context); ++ void *wake_context; ++ ++ uint32_t region_size; ++ unsigned region_shift; ++ ++ /* holds persistent region state */ ++ struct dm_dirty_log *log; ++ ++ /* hash table */ ++ rwlock_t hash_lock; ++ mempool_t *region_pool; ++ unsigned mask; ++ unsigned nr_buckets; ++ unsigned prime; ++ unsigned shift; ++ struct list_head *buckets; ++ ++ spinlock_t region_lock; ++ atomic_t recovery_in_flight; ++ struct semaphore recovery_count; ++ struct list_head clean_regions; ++ struct list_head quiesced_regions; ++ struct list_head recovered_regions; ++ struct list_head failed_recovered_regions; ++}; ++ ++struct region { ++ region_t key; ++ enum dm_rh_region_states state; ++ void *context; /* Caller context. */ ++ ++ struct list_head hash_list; ++ struct list_head list; ++ ++ atomic_t pending; ++ struct bio_list delayed_bios; ++}; ++ ++/* ++ * Conversion fns ++ */ ++region_t dm_rh_sector_to_region(struct dm_rh_client *rh, sector_t sector) ++{ ++ return sector >> ((struct region_hash *) rh)->region_shift; ++} ++EXPORT_SYMBOL_GPL(dm_rh_sector_to_region); ++ ++region_t dm_rh_bio_to_region(struct dm_rh_client *rh, struct bio *bio) ++{ ++ return dm_rh_sector_to_region(rh, bio->bi_sector); ++} ++EXPORT_SYMBOL_GPL(dm_rh_bio_to_region); ++ ++sector_t dm_rh_region_to_sector(struct dm_rh_client *rh, region_t region) ++{ ++ return region << ((struct region_hash *) rh)->region_shift; ++} ++EXPORT_SYMBOL_GPL(dm_rh_region_to_sector); ++ ++/* ++ * Retrival fns. ++ */ ++region_t dm_rh_get_region_key(struct dm_region *reg) ++{ ++ return ((struct region *) reg)->key; ++} ++EXPORT_SYMBOL_GPL(dm_rh_get_region_key); ++ ++sector_t dm_rh_get_region_size(struct dm_rh_client *rh) ++{ ++ return ((struct region_hash *) rh)->region_size; ++} ++EXPORT_SYMBOL_GPL(dm_rh_get_region_size); ++ ++/* Squirrel a context with a region. */ ++void *dm_rh_reg_get_context(struct dm_region *reg) ++{ ++ return ((struct region *) reg)->context; ++} ++EXPORT_SYMBOL_GPL(dm_rh_reg_get_context); ++ ++void dm_rh_reg_set_context(struct dm_region *reg, void *context) ++{ ++ ((struct region *) reg)->context = context; ++} ++EXPORT_SYMBOL_GPL(dm_rh_reg_set_context); ++ ++/* ++ * Create region hash client. ++ */ ++#define MIN_REGIONS 64 ++struct dm_rh_client *dm_rh_client_create( ++ unsigned max_recovery, ++ void (*dispatch)(void *dispatch_context, ++ struct bio_list *bios, int error), ++ void *dispatch_context, ++ void (*wake)(void *wake_context), void *wake_context, ++ struct dm_dirty_log *log, uint32_t region_size, ++ region_t nr_regions) ++{ ++ unsigned i; ++ unsigned nr_buckets, max_buckets; ++ unsigned hash_primes[] = { ++ /* Table of primes for rh_hash/table size optimization. */ ++ 3, 7, 13, 27, 53, 97, 193, 389, 769, ++ 1543, 3079, 6151, 12289, 24593, ++ }; ++ struct region_hash *rh; ++ ++ if (region_size & (region_size - 1)) { ++ DMERR("region size must be 2^^n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ /* Calculate a suitable number of buckets for our hash table. */ ++ max_buckets = nr_regions >> 6; ++ for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1) ++ ; ++ nr_buckets >>= 1; ++ ++ rh = kmalloc(sizeof(*rh), GFP_KERNEL); ++ if (!rh) { ++ DMERR("unable to allocate region hash memory"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ rh->max_recovery = max_recovery; ++ rh->dispatch = dispatch; ++ rh->dispatch_context = dispatch_context; ++ rh->wake = wake; ++ rh->wake_context = wake_context; ++ rh->log = log; ++ rh->region_size = region_size; ++ rh->region_shift = ffs(region_size) - 1; ++ rwlock_init(&rh->hash_lock); ++ rh->mask = nr_buckets - 1; ++ rh->nr_buckets = nr_buckets; ++ rh->shift = ffs(nr_buckets); ++ ++ /* Check prime array limits. */ ++ i = rh->shift - 1 > ARRAY_SIZE(hash_primes) ? ++ ARRAY_SIZE(hash_primes) - 1 : rh->shift - 2; ++ rh->prime = hash_primes[i]; ++ ++ rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets)); ++ if (!rh->buckets) { ++ DMERR("unable to allocate region hash bucket memory"); ++ kfree(rh); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ for (i = 0; i < nr_buckets; i++) ++ INIT_LIST_HEAD(rh->buckets + i); ++ ++ spin_lock_init(&rh->region_lock); ++ sema_init(&rh->recovery_count, 0); ++ atomic_set(&rh->recovery_in_flight, 0); ++ INIT_LIST_HEAD(&rh->clean_regions); ++ INIT_LIST_HEAD(&rh->quiesced_regions); ++ INIT_LIST_HEAD(&rh->recovered_regions); ++ INIT_LIST_HEAD(&rh->failed_recovered_regions); ++ ++ rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS, ++ sizeof(struct region)); ++ if (!rh->region_pool) { ++ vfree(rh->buckets); ++ kfree(rh); ++ rh = ERR_PTR(-ENOMEM); ++ } ++ ++ return (struct dm_rh_client *) rh; ++} ++EXPORT_SYMBOL_GPL(dm_rh_client_create); ++ ++void dm_rh_client_destroy(struct dm_rh_client *rh_in) ++{ ++ unsigned h; ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg, *tmp; ++ ++ BUG_ON(!list_empty(&rh->quiesced_regions)); ++ ++ for (h = 0; h < rh->nr_buckets; h++) { ++ list_for_each_entry_safe(reg, tmp, rh->buckets + h, hash_list) { ++ BUG_ON(atomic_read(®->pending)); ++ mempool_free(reg, rh->region_pool); ++ } ++ } ++ ++ if (rh->region_pool) ++ mempool_destroy(rh->region_pool); ++ ++ vfree(rh->buckets); ++ kfree(rh); ++} ++EXPORT_SYMBOL_GPL(dm_rh_client_destroy); ++ ++static inline unsigned rh_hash(struct region_hash *rh, region_t region) ++{ ++ return (unsigned) ((region * rh->prime) >> rh->shift) & rh->mask; ++} ++ ++static struct region *__rh_lookup(struct region_hash *rh, region_t region) ++{ ++ struct region *reg; ++ struct list_head *bucket = rh->buckets + rh_hash(rh, region); ++ ++ list_for_each_entry(reg, bucket, hash_list) { ++ if (reg->key == region) ++ return reg; ++ } ++ ++ return NULL; ++} ++ ++static void __rh_insert(struct region_hash *rh, struct region *reg) ++{ ++ list_add(®->hash_list, rh->buckets + rh_hash(rh, reg->key)); ++} ++ ++static struct region *__rh_alloc(struct region_hash *rh, region_t region) ++{ ++ struct region *reg, *nreg; ++ ++ read_unlock(&rh->hash_lock); ++ nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC); ++ if (unlikely(!nreg)) ++ nreg = kmalloc(sizeof(*nreg), GFP_NOIO); ++ ++ nreg->state = rh->log->type->in_sync(rh->log, region, 1) ? ++ DM_RH_CLEAN : DM_RH_NOSYNC; ++ nreg->key = region; ++ INIT_LIST_HEAD(&nreg->list); ++ atomic_set(&nreg->pending, 0); ++ bio_list_init(&nreg->delayed_bios); ++ ++ write_lock_irq(&rh->hash_lock); ++ reg = __rh_lookup(rh, region); ++ if (reg) ++ /* We lost the race. */ ++ mempool_free(nreg, rh->region_pool); ++ else { ++ __rh_insert(rh, nreg); ++ if (nreg->state == DM_RH_CLEAN) { ++ spin_lock(&rh->region_lock); ++ list_add(&nreg->list, &rh->clean_regions); ++ spin_unlock(&rh->region_lock); ++ } ++ ++ reg = nreg; ++ } ++ ++ write_unlock_irq(&rh->hash_lock); ++ read_lock(&rh->hash_lock); ++ return reg; ++} ++ ++static inline struct region *__rh_find(struct region_hash *rh, region_t region) ++{ ++ struct region *reg; ++ ++ reg = __rh_lookup(rh, region); ++ return reg ? reg : __rh_alloc(rh, region); ++} ++ ++int dm_rh_get_state(struct dm_rh_client *rh_in, region_t region, int may_block) ++{ ++ int r; ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg; ++ ++ read_lock(&rh->hash_lock); ++ reg = __rh_lookup(rh, region); ++ read_unlock(&rh->hash_lock); ++ ++ if (reg) ++ return reg->state; ++ ++ /* ++ * The region wasn't in the hash, so we fall back to the dirty log. ++ */ ++ r = rh->log->type->in_sync(rh->log, region, may_block); ++ ++ /* ++ * Any error from the dirty log (eg. -EWOULDBLOCK) ++ * gets taken as a DM_RH_NOSYNC ++ */ ++ return r == 1 ? DM_RH_CLEAN : DM_RH_NOSYNC; ++} ++EXPORT_SYMBOL_GPL(dm_rh_get_state); ++ ++void dm_rh_set_state(struct dm_rh_client *rh_in, region_t region, ++ enum dm_rh_region_states state, int may_block) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg; ++ struct dm_dirty_log *log = rh->log; ++ ++ if (state == DM_RH_NOSYNC) ++ log->type->set_region_sync(log, region, 0); ++ else if (state == DM_RH_CLEAN) ++ log->type->clear_region(log, region); ++ else if (state == DM_RH_DIRTY) ++ log->type->mark_region(log, region); ++ ++ read_lock(&rh->hash_lock); ++ reg = __rh_find(rh, region); ++ reg->state = state; ++ read_unlock(&rh->hash_lock); ++} ++EXPORT_SYMBOL_GPL(dm_rh_set_state); ++ ++void dm_rh_update_states(struct dm_rh_client *rh_in, int errors_handled) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg, *next; ++ LIST_HEAD(clean); ++ LIST_HEAD(recovered); ++ LIST_HEAD(failed_recovered); ++ ++ /* ++ * Quickly grab the lists and remove any regions from hash. ++ */ ++ write_lock_irq(&rh->hash_lock); ++ spin_lock(&rh->region_lock); ++ if (!list_empty(&rh->clean_regions)) { ++ list_splice_init(&rh->clean_regions, &clean); ++ ++ list_for_each_entry(reg, &clean, list) ++ list_del(®->hash_list); ++ } ++ ++ if (!list_empty(&rh->recovered_regions)) { ++ list_splice_init(&rh->recovered_regions, &recovered); ++ ++ list_for_each_entry(reg, &recovered, list) ++ list_del(®->hash_list); ++ } ++ ++ if (!list_empty(&rh->failed_recovered_regions)) { ++ list_splice_init(&rh->failed_recovered_regions, ++ &failed_recovered); ++ ++ list_for_each_entry(reg, &recovered, list) ++ list_del(®->hash_list); ++ } ++ ++ spin_unlock(&rh->region_lock); ++ write_unlock_irq(&rh->hash_lock); ++ ++ /* ++ * All the regions on the recovered and clean lists have ++ * now been pulled out of the system, so no need to do ++ * any more locking. ++ */ ++ list_for_each_entry_safe(reg, next, &recovered, list) { ++ rh->log->type->clear_region(rh->log, reg->key); ++ rh->log->type->set_region_sync(rh->log, reg->key, 1); ++ ++ if (reg->delayed_bios.head) ++ rh->dispatch(rh->dispatch_context, ++ ®->delayed_bios, 0); ++ ++ up(&rh->recovery_count); ++ mempool_free(reg, rh->region_pool); ++ } ++ ++ list_for_each_entry_safe(reg, next, &failed_recovered, list) { ++ rh->log->type->set_region_sync(rh->log, reg->key, ++ errors_handled ? 0 : 1); ++ if (reg->delayed_bios.head) ++ rh->dispatch(rh->dispatch_context, ++ ®->delayed_bios, -EIO); ++ ++ up(&rh->recovery_count); ++ mempool_free(reg, rh->region_pool); ++ } ++ ++ list_for_each_entry_safe(reg, next, &clean, list) { ++ rh->log->type->clear_region(rh->log, reg->key); ++ mempool_free(reg, rh->region_pool); ++ } ++ ++ dm_rh_flush(rh_in); ++} ++EXPORT_SYMBOL_GPL(dm_rh_update_states); ++ ++void dm_rh_inc(struct dm_rh_client *rh_in, region_t region) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg; ++ ++ read_lock(&rh->hash_lock); ++ reg = __rh_find(rh, region); ++ if (reg->state == DM_RH_CLEAN) { ++ rh->log->type->mark_region(rh->log, reg->key); ++ ++ spin_lock_irq(&rh->region_lock); ++ reg->state = DM_RH_DIRTY; ++ list_del_init(®->list); /* Take off the clean list. */ ++ spin_unlock_irq(&rh->region_lock); ++ } ++ ++ atomic_inc(®->pending); ++ read_unlock(&rh->hash_lock); ++} ++EXPORT_SYMBOL_GPL(dm_rh_inc); ++ ++void dm_rh_inc_pending(struct dm_rh_client *rh_in, struct bio_list *bios) ++{ ++ struct bio *bio; ++ ++ for (bio = bios->head; bio; bio = bio->bi_next) ++ dm_rh_inc(rh_in, dm_rh_bio_to_region(rh_in, bio)); ++} ++EXPORT_SYMBOL_GPL(dm_rh_inc_pending); ++ ++int dm_rh_dec(struct dm_rh_client *rh_in, region_t region) ++{ ++ int r = 0; ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg; ++ ++ read_lock(&rh->hash_lock); ++ reg = __rh_lookup(rh, region); ++ read_unlock(&rh->hash_lock); ++ ++ BUG_ON(!reg); ++ ++ if (atomic_dec_and_test(®->pending)) { ++ unsigned long flags; ++ ++ /* ++ * There is no pending I/O for this region. ++ * We can move the region to corresponding list for next action. ++ * At this point, the region is not yet connected to any list. ++ * ++ * If the state is DM_RH_NOSYNC, the region should be kept off ++ * from clean list. ++ * The hash entry for DM_RH_NOSYNC will remain in memory ++ * until the region is recovered or the map is reloaded. ++ */ ++ ++ spin_lock_irqsave(&rh->region_lock, flags); ++ if (reg->state == DM_RH_RECOVERING) ++ list_add_tail(®->list, &rh->quiesced_regions); ++ else { ++ reg->state = DM_RH_CLEAN; ++ list_add(®->list, &rh->clean_regions); ++ } ++ spin_unlock_irqrestore(&rh->region_lock, flags); ++ ++ r = 1; ++ } ++ ++ return r; ++} ++EXPORT_SYMBOL_GPL(dm_rh_dec); ++ ++/* ++ * Starts quiescing a region in preparation for recovery. ++ */ ++static int __rh_recovery_prepare(struct region_hash *rh) ++{ ++ int r; ++ region_t region; ++ struct region *reg; ++ ++ /* ++ * Ask the dirty log what's next. ++ */ ++ r = rh->log->type->get_resync_work(rh->log, ®ion); ++ if (r <= 0) ++ return r; ++ ++ /* ++ * Get this region, and start it quiescing ++ * by setting the recovering flag. ++ */ ++ read_lock(&rh->hash_lock); ++ reg = __rh_find(rh, region); ++ read_unlock(&rh->hash_lock); ++ ++ spin_lock_irq(&rh->region_lock); ++ ++ reg->state = DM_RH_RECOVERING; ++ ++ /* Already quiesced ? */ ++ list_del_init(®->list); ++ if (!atomic_read(®->pending)) ++ list_add(®->list, &rh->quiesced_regions); ++ ++ spin_unlock_irq(&rh->region_lock); ++ return 1; ++} ++ ++int dm_rh_recovery_prepare(struct dm_rh_client *rh_in) ++{ ++ int r = 0; ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ ++ /* Extra reference to avoid race with rh_stop_recovery */ ++ atomic_inc(&rh->recovery_in_flight); ++ ++ while (!down_trylock(&rh->recovery_count)) { ++ atomic_inc(&rh->recovery_in_flight); ++ ++ if (__rh_recovery_prepare(rh) <= 0) { ++ atomic_dec(&rh->recovery_in_flight); ++ up(&rh->recovery_count); ++ r = -ENOENT; ++ break; ++ } ++ } ++ ++ /* Drop the extra reference. */ ++ if (atomic_dec_and_test(&rh->recovery_in_flight)) ++ r = -ESRCH; ++ ++ return r; ++} ++EXPORT_SYMBOL_GPL(dm_rh_recovery_prepare); ++ ++/* ++ * Returns any quiesced regions. ++ */ ++struct dm_region *dm_rh_recovery_start(struct dm_rh_client *rh_in) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg = NULL; ++ ++ spin_lock_irq(&rh->region_lock); ++ if (!list_empty(&rh->quiesced_regions)) { ++ reg = list_entry(rh->quiesced_regions.next, ++ struct region, list); ++ list_del_init(®->list); /* Remove from the quiesced list. */ ++ } ++ ++ spin_unlock_irq(&rh->region_lock); ++ return (struct dm_region *) reg; ++} ++EXPORT_SYMBOL_GPL(dm_rh_recovery_start); ++ ++/* ++ * Put region on list of recovered ones. ++ */ ++void dm_rh_recovery_end(struct dm_rh_client *rh_in, struct dm_region *reg_in, ++ int error) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg = (struct region *) reg_in; ++ ++ spin_lock_irq(&rh->region_lock); ++ if (error) { ++ reg->state = DM_RH_NOSYNC; ++ list_add(®->list, &rh->failed_recovered_regions); ++ } else ++ list_add(®->list, &rh->recovered_regions); ++ ++ atomic_dec(&rh->recovery_in_flight); ++ spin_unlock_irq(&rh->region_lock); ++ ++ rh->wake(rh->wake_context); ++ BUG_ON(atomic_read(&rh->recovery_in_flight) < 0); ++} ++EXPORT_SYMBOL_GPL(dm_rh_recovery_end); ++ ++/* Return recovery in flight count. */ ++int dm_rh_recovery_in_flight(struct dm_rh_client *rh_in) ++{ ++ return atomic_read(&((struct region_hash *) rh_in)->recovery_in_flight); ++} ++EXPORT_SYMBOL_GPL(dm_rh_recovery_in_flight); ++ ++int dm_rh_flush(struct dm_rh_client *rh_in) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ ++ return rh->log->type->flush(rh->log); ++} ++EXPORT_SYMBOL_GPL(dm_rh_flush); ++ ++void dm_rh_delay_by_region(struct dm_rh_client *rh_in, ++ struct bio *bio, region_t region) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg; ++ ++ /* FIXME: locking. */ ++ read_lock(&rh->hash_lock); ++ reg = __rh_find(rh, region); ++ bio_list_add(®->delayed_bios, bio); ++ read_unlock(&rh->hash_lock); ++} ++EXPORT_SYMBOL_GPL(dm_rh_delay_by_region); ++ ++void dm_rh_delay(struct dm_rh_client *rh_in, struct bio *bio) ++{ ++ return dm_rh_delay_by_region(rh_in, bio, ++ dm_rh_bio_to_region(rh_in, bio)); ++} ++EXPORT_SYMBOL_GPL(dm_rh_delay); ++ ++void dm_rh_dispatch_bios(struct dm_rh_client *rh_in, ++ region_t region, int error) ++{ ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ struct region *reg; ++ struct bio_list delayed_bios; ++ ++ /* FIXME: locking. */ ++ read_lock(&rh->hash_lock); ++ reg = __rh_find(rh, region); ++ BUG_ON(!reg); ++ delayed_bios = reg->delayed_bios; ++ bio_list_init(®->delayed_bios); ++ read_unlock(&rh->hash_lock); ++ ++ if (delayed_bios.head) ++ rh->dispatch(rh->dispatch_context, &delayed_bios, error); ++ ++ up(&rh->recovery_count); ++} ++EXPORT_SYMBOL_GPL(dm_rh_dispatch_bios); ++ ++void dm_rh_stop_recovery(struct dm_rh_client *rh_in) ++{ ++ int i; ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ ++ rh->wake(rh->wake_context); ++ ++ /* wait for any recovering regions */ ++ for (i = 0; i < rh->max_recovery; i++) ++ down(&rh->recovery_count); ++} ++EXPORT_SYMBOL_GPL(dm_rh_stop_recovery); ++ ++void dm_rh_start_recovery(struct dm_rh_client *rh_in) ++{ ++ int i; ++ struct region_hash *rh = (struct region_hash *) rh_in; ++ ++ for (i = 0; i < rh->max_recovery; i++) ++ up(&rh->recovery_count); ++ ++ rh->wake(rh->wake_context); ++} ++EXPORT_SYMBOL_GPL(dm_rh_start_recovery); ++ ++MODULE_DESCRIPTION(DM_NAME " region hash"); ++MODULE_AUTHOR("Joe Thornber/Heinz Mauelshagen "); ++MODULE_LICENSE("GPL"); +--- a/drivers/md/Kconfig ++++ b/drivers/md/Kconfig +@@ -269,6 +269,14 @@ config DM_DELAY + + If unsure, say N. + ++config DM_RAID45 ++ tristate "RAID 4/5 target (EXPERIMENTAL)" ++ depends on BLK_DEV_DM && EXPERIMENTAL ++ ---help--- ++ A target that supports RAID4 and RAID5 mappings. ++ ++ If unsure, say N. ++ + config DM_UEVENT + bool "DM uevents (EXPERIMENTAL)" + depends on BLK_DEV_DM && EXPERIMENTAL +--- a/drivers/md/Makefile ++++ b/drivers/md/Makefile +@@ -34,7 +34,9 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o + obj-$(CONFIG_DM_DELAY) += dm-delay.o + obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o + obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o +-obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o ++obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-regions.o dm-log.o ++obj-$(CONFIG_DM_RAID45) += dm-raid45.o dm-log.o dm-memcache.o \ ++ dm-regions.o dm-message.o + obj-$(CONFIG_DM_ZERO) += dm-zero.o + + quiet_cmd_unroll = UNROLL $@ +--- /dev/null ++++ b/include/linux/dm-regions.h +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (C) 2003 Sistina Software Limited. ++ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. ++ * ++ * Device-Mapper dirty region hash interface. ++ * ++ * This file is released under the GPL. ++ */ ++ ++#ifndef DM_REGION_HASH_H ++#define DM_REGION_HASH_H ++ ++#include ++ ++/*----------------------------------------------------------------- ++ * Region hash ++ *----------------------------------------------------------------*/ ++struct dm_rh_client; ++struct dm_region; ++ ++/* ++ * States a region can have. ++ */ ++enum dm_rh_region_states { ++ DM_RH_CLEAN = 0x01, /* No writes in flight. */ ++ DM_RH_DIRTY = 0x02, /* Writes in flight. */ ++ DM_RH_NOSYNC = 0x04, /* Out of sync. */ ++ DM_RH_RECOVERING = 0x08, /* Under resynchronization. */ ++}; ++ ++/* ++ * Region hash create/destroy. ++ */ ++struct bio_list; ++struct dm_rh_client *dm_rh_client_create( ++ unsigned max_recovery, ++ void (*dispatch)(void *dispatch_context, ++ struct bio_list *bios, int error), ++ void *dispatch_context, ++ void (*wake)(void *wake_context), void *wake_context, ++ struct dm_dirty_log *log, uint32_t region_size, ++ region_t nr_regions); ++void dm_rh_client_destroy(struct dm_rh_client *rh); ++ ++/* ++ * Conversion fns: ++ * ++ * bio -> region ++ * sector -> region ++ * region -> sector ++ */ ++region_t dm_rh_bio_to_region(struct dm_rh_client *rh, struct bio *bio); ++region_t dm_rh_sector_to_region(struct dm_rh_client *rh, sector_t sector); ++sector_t dm_rh_region_to_sector(struct dm_rh_client *rh, region_t region); ++ ++/* ++ * Functions to set a caller context in a region. ++ */ ++void *dm_rh_reg_get_context(struct dm_region *reg); ++void dm_rh_reg_set_context(struct dm_region *reg, void *context); ++ ++/* ++ * Get region size and key (ie. number of the region). ++ */ ++sector_t dm_rh_get_region_size(struct dm_rh_client *rh); ++sector_t dm_rh_get_region_key(struct dm_region *reg); ++ ++/* ++ * Get/set/update region state (and dirty log). ++ * ++ * dm_rh_update_states ++ * @errors_handled != 0 influences ++ * that the state of the region will be kept NOSYNC ++ */ ++int dm_rh_get_state(struct dm_rh_client *rh, region_t region, int may_block); ++void dm_rh_set_state(struct dm_rh_client *rh, region_t region, ++ enum dm_rh_region_states state, int may_block); ++void dm_rh_update_states(struct dm_rh_client *rh, int errors_handled); ++ ++/* Flush the region hash and dirty log. */ ++int dm_rh_flush(struct dm_rh_client *rh); ++ ++/* Inc/dec pending count on regions. */ ++void dm_rh_inc(struct dm_rh_client *rh, region_t region); ++void dm_rh_inc_pending(struct dm_rh_client *rh, struct bio_list *bios); ++int dm_rh_dec(struct dm_rh_client *rh, region_t region); ++ ++/* Delay bios on regions. */ ++void dm_rh_delay(struct dm_rh_client *rh, struct bio *bio); ++void dm_rh_delay_by_region(struct dm_rh_client *rh, ++ struct bio *bio, region_t region); ++ ++/* ++ * Normally, the region hash will automatically call the dispatch function. ++ * dm_rh_dispatch_bios() is for intentional dispatching of bios. ++ */ ++void dm_rh_dispatch_bios(struct dm_rh_client *rh, region_t region, int error); ++ ++/* ++ * Region recovery control. ++ */ ++/* Prepare some regions for recovery by starting to quiesce them. */ ++int dm_rh_recovery_prepare(struct dm_rh_client *rh); ++/* Try fetching a quiesced region for recovery. */ ++struct dm_region *dm_rh_recovery_start(struct dm_rh_client *rh); ++/* Report recovery end on a region. */ ++void dm_rh_recovery_end(struct dm_rh_client *rh, struct dm_region *reg, ++ int error); ++/* Check for amount of recoveries in flight. */ ++int dm_rh_recovery_in_flight(struct dm_rh_client *rh); ++/* Start/stop recovery. */ ++void dm_rh_stop_recovery(struct dm_rh_client *rh); ++void dm_rh_start_recovery(struct dm_rh_client *rh); ++ ++#endif /* #ifdef DM_REGION_HASH_H */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-table-change-mode-to-ro b/src/patches/suse-2.6.27.31/patches.suse/dm-table-change-mode-to-ro new file mode 100644 index 000000000..889f35132 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-table-change-mode-to-ro @@ -0,0 +1,37 @@ +From: Hannes Reinecke +Subject: Switch device-mapper tables to READ-WRITE +References: bnc#440959 + +Switching a device-mapper table to READ-ONLY works quite well, but +we can't switch back to READ-WRITE as this change will be masked out. +So get rid of this masking and use the flags directly. +And implement a fallback to automatically switch to read-only. + +Signed-off-by: Hannes Reinecke + +--- linux-2.6.27/drivers/md/dm-table.c.orig 2009-02-02 13:09:06.000000000 +0100 ++++ linux-2.6.27/drivers/md/dm-table.c 2009-02-02 14:03:03.000000000 +0100 +@@ -423,9 +423,13 @@ static int upgrade_mode(struct dm_dev *d + + dd_copy = *dd; + +- dd->mode |= new_mode; ++ dd->mode = new_mode; + dd->bdev = NULL; + r = open_dev(dd, dev, md); ++ if (r == -EROFS) { ++ dd->mode &= ~FMODE_WRITE; ++ r = open_dev(dd, dev, md); ++ } + if (!r) + close_dev(&dd_copy, md); + else +@@ -487,7 +491,7 @@ static int __table_get_device(struct dm_ + atomic_set(&dd->count, 0); + list_add(&dd->list, &t->devices); + +- } else if (dd->mode != (mode | dd->mode)) { ++ } else if (dd->mode != mode) { + r = upgrade_mode(dd, mode, t->md); + if (r) + return r; diff --git a/src/patches/suse-2.6.27.31/patches.suse/dm-use-md-for-free_bio_clone b/src/patches/suse-2.6.27.31/patches.suse/dm-use-md-for-free_bio_clone new file mode 100644 index 000000000..bf918abc6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/dm-use-md-for-free_bio_clone @@ -0,0 +1,80 @@ +From: Hannes Reinecke +Subject: Kernel oops in free_bio_clone() +References: bnc#472360 + +Bug is here: + +static int setup_clone(struct request *clone, struct request *rq, + struct dm_rq_target_io *tio) +{ + int r; + + blk_rq_init(NULL, clone); + + r = clone_request_bios(clone, rq, tio->md); + if (r) + return r; + + copy_request_info(clone, rq); + clone->start_time = jiffies; + clone->end_io = end_clone_request; + clone->end_io_data = tio; + + return 0; +} + +clone_request_bios() might end up calling free_bio_clone(), which references: + +static void free_bio_clone(struct request *clone) +{ + struct dm_rq_target_io *tio = clone->end_io_data; + struct mapped_device *md = tio->md; +... + +but end_io_data will be set only _after_ the call to clone_request_bios(). +So we should be passing the 'md' argument directly here to avoid this +bug and several pointless derefencings. + +Signed-off-by: Hannes Reinecke + +--- linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c.orig 2009-02-04 10:33:22.656627650 +0100 ++++ linux-2.6.27-SLE11_BRANCH/drivers/md/dm.c 2009-02-05 11:03:35.843251773 +0100 +@@ -709,10 +709,8 @@ static void end_clone_bio(struct bio *cl + blk_update_request(tio->orig, 0, nr_bytes); + } + +-static void free_bio_clone(struct request *clone) ++static void free_bio_clone(struct request *clone, struct mapped_device *md) + { +- struct dm_rq_target_io *tio = clone->end_io_data; +- struct mapped_device *md = tio->md; + struct bio *bio; + + while ((bio = clone->bio) != NULL) { +@@ -743,7 +741,7 @@ static void dm_unprep_request(struct req + rq->special = NULL; + rq->cmd_flags &= ~REQ_DONTPREP; + +- free_bio_clone(clone); ++ free_bio_clone(clone, tio->md); + dec_rq_pending(tio); + free_rq_tio(tio->md, tio); + } +@@ -820,7 +818,7 @@ static void dm_end_request(struct reques + rq->sense_len = clone->sense_len; + } + +- free_bio_clone(clone); ++ free_bio_clone(clone, tio->md); + dec_rq_pending(tio); + free_rq_tio(tio->md, tio); + +@@ -1406,7 +1404,7 @@ static int clone_request_bios(struct req + return 0; + + free_and_out: +- free_bio_clone(clone); ++ free_bio_clone(clone, md); + + return -ENOMEM; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/e1000e_Export_set_memory_ro-rw b/src/patches/suse-2.6.27.31/patches.suse/e1000e_Export_set_memory_ro-rw new file mode 100644 index 000000000..a7500c9ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/e1000e_Export_set_memory_ro-rw @@ -0,0 +1,31 @@ +From: Bruce Allan +Subject: Export set_memory_ro() and set_memory_rw() calls. +References: bnc#425480 +Acked-by: Karsten Keil + +Export set_memory_ro() and set_memory_rw() calls. Soon to be used +by e1000e. + +Signed-off-by: Bruce Allan +Signed-off-by: Jesse Brandeburg +--- + + arch/x86/mm/pageattr.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/x86/mm/pageattr.c ++++ b/arch/x86/mm/pageattr.c +@@ -949,11 +949,13 @@ int set_memory_ro(unsigned long addr, in + { + return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_RW)); + } ++EXPORT_SYMBOL(set_memory_ro); + + int set_memory_rw(unsigned long addr, int numpages) + { + return change_page_attr_set(addr, numpages, __pgprot(_PAGE_RW)); + } ++EXPORT_SYMBOL(set_memory_rw); + + /* hack: bypass kernel rodata section static_protections check. */ + int set_memory_rw_force(unsigned long addr, int numpages) diff --git a/src/patches/suse-2.6.27.31/patches.suse/export-release_open_intent b/src/patches/suse-2.6.27.31/patches.suse/export-release_open_intent new file mode 100644 index 000000000..a36aec325 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/export-release_open_intent @@ -0,0 +1,22 @@ +From: Jeff Mahoney +Subject: Export release_open_intent for NFS branches with aufs + + aufs requires a way to release an open intent when handling an error + condition after using NFSv4's atomic open. It was using put_filp, + but release_open_intent is more appropriate. + +Signed-off-by: Jeff Mahoney +--- + fs/namei.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -392,6 +392,7 @@ void release_open_intent(struct nameidat + else + fput(nd->intent.open.file); + } ++EXPORT_SYMBOL_GPL(release_open_intent); + + static inline struct dentry * + do_revalidate(struct dentry *dentry, struct nameidata *nd) diff --git a/src/patches/suse-2.6.27.31/patches.suse/ext2-fsync-err b/src/patches/suse-2.6.27.31/patches.suse/ext2-fsync-err new file mode 100644 index 000000000..1e2028e79 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ext2-fsync-err @@ -0,0 +1,52 @@ +From: Chris Mason +Subject: ext2 should force the FS readonly for metadata write errors +References: 65718 + +During fsync we should check for write errors to the block device in order to make +sure all metadata writes have been properly written to the disk. Without this check +writes that happen through the normal async mechanisms might hit errors without +reporting them back to the application. + +Acked-by: Jeff Mahoney + +--- + fs/ext2/fsync.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- a/fs/ext2/fsync.c ++++ b/fs/ext2/fsync.c +@@ -24,6 +24,7 @@ + + #include "ext2.h" + #include /* for sync_mapping_buffers() */ ++#include + + + /* +@@ -34,10 +35,26 @@ + int ext2_sync_file(struct file *file, struct dentry *dentry, int datasync) + { + struct inode *inode = dentry->d_inode; ++ struct super_block *sb = inode->i_sb; + int err; + int ret; + + ret = sync_mapping_buffers(inode->i_mapping); ++ ++ /* it might make more sense to ext2_error on -EIO from ++ * sync_mapping_buffers as well, but those errors are isolated to just ++ * this file. We can safely return -EIO to fsync and let the app know ++ * they have a problem. ++ * ++ * AS_EIO indicates a failure to write a metadata page, but we have no ++ * way of knowing which one. It's best to force readonly and let fsck ++ * figure it all out. ++ */ ++ if (test_and_clear_bit(AS_EIO, &sb->s_bdev->bd_inode->i_mapping->flags)) { ++ ext2_error(sb, "ext2_sync_file", "metadata io error"); ++ if (!ret) ++ ret = -EIO; ++ } + if (!(inode->i_state & I_DIRTY)) + return ret; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) diff --git a/src/patches/suse-2.6.27.31/patches.suse/ext3-Use-sb_any_quota_loaded-instead-of-sb_any_qu.patch b/src/patches/suse-2.6.27.31/patches.suse/ext3-Use-sb_any_quota_loaded-instead-of-sb_any_qu.patch new file mode 100644 index 000000000..822114c51 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ext3-Use-sb_any_quota_loaded-instead-of-sb_any_qu.patch @@ -0,0 +1,57 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 06/28] ext3: Use sb_any_quota_loaded() instead of sb_any_quota_enabled() +Patch-mainline: 2.6.29? + +Signed-off-by: Jan Kara +--- + fs/ext3/super.c | 12 ++++-------- + 1 files changed, 4 insertions(+), 8 deletions(-) + +diff --git a/fs/ext3/super.c b/fs/ext3/super.c +index f38a5af..ff5b789 100644 +--- a/fs/ext3/super.c ++++ b/fs/ext3/super.c +@@ -1018,8 +1018,7 @@ static int parse_options (char *options, struct super_block *sb, + case Opt_grpjquota: + qtype = GRPQUOTA; + set_qf_name: +- if ((sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) && ++ if (sb_any_quota_loaded(sb) && + !sbi->s_qf_names[qtype]) { + printk(KERN_ERR + "EXT3-fs: Cannot change journaled " +@@ -1058,8 +1057,7 @@ set_qf_name: + case Opt_offgrpjquota: + qtype = GRPQUOTA; + clear_qf_name: +- if ((sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) && ++ if (sb_any_quota_loaded(sb) && + sbi->s_qf_names[qtype]) { + printk(KERN_ERR "EXT3-fs: Cannot change " + "journaled quota options when " +@@ -1078,8 +1076,7 @@ clear_qf_name: + case Opt_jqfmt_vfsv0: + qfmt = QFMT_VFS_V0; + set_qf_format: +- if ((sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) && ++ if (sb_any_quota_loaded(sb) && + sbi->s_jquota_fmt != qfmt) { + printk(KERN_ERR "EXT3-fs: Cannot change " + "journaled quota options when " +@@ -1098,8 +1095,7 @@ set_qf_format: + set_opt(sbi->s_mount_opt, GRPQUOTA); + break; + case Opt_noquota: +- if (sb_any_quota_enabled(sb) || +- sb_any_quota_suspended(sb)) { ++ if (sb_any_quota_loaded(sb)) { + printk(KERN_ERR "EXT3-fs: Cannot change quota " + "options when quota turned on.\n"); + return 0; +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ext3-barrier-default b/src/patches/suse-2.6.27.31/patches.suse/ext3-barrier-default new file mode 100644 index 000000000..b97d48395 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ext3-barrier-default @@ -0,0 +1,50 @@ +From: Chris Mason +Subject: make ext3 mount default to barrier=1 + +Hello everyone, + +This patch turns on barriers by default for ext3. mount -o barrier=0 +will turn them off. It also changes the ext3 fsync call to trigger a +barrier when a commit isn't done. + +It should be safe, but some extra review would be appreciated. + +Acked-by: Jeff Mahoney + +--- + fs/ext3/fsync.c | 4 ++++ + fs/ext3/super.c | 2 ++ + 2 files changed, 6 insertions(+) + +--- a/fs/ext3/fsync.c ++++ b/fs/ext3/fsync.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -84,7 +85,10 @@ int ext3_sync_file(struct file * file, s + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, /* sys_fsync did this */ + }; ++ journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; + ret = sync_inode(inode, &wbc); ++ if (journal && (journal->j_flags & JFS_BARRIER)) ++ blkdev_issue_flush(inode->i_sb->s_bdev, NULL); + } + out: + return ret; +--- a/fs/ext3/super.c ++++ b/fs/ext3/super.c +@@ -1603,6 +1603,8 @@ static int ext3_fill_super (struct super + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); + sbi->s_resgid = le16_to_cpu(es->s_def_resgid); + ++ /* enable barriers by default */ ++ set_opt(sbi->s_mount_opt, BARRIER); + set_opt(sbi->s_mount_opt, RESERVATION); + + if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, diff --git a/src/patches/suse-2.6.27.31/patches.suse/fix-warning-in-fsdlm-netlink.c.patch b/src/patches/suse-2.6.27.31/patches.suse/fix-warning-in-fsdlm-netlink.c.patch new file mode 100644 index 000000000..2285b4671 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/fix-warning-in-fsdlm-netlink.c.patch @@ -0,0 +1,34 @@ +From: Ingo Molnar +commit 180b65df7ba1e700e28aabfbddbad84b7beebe4b +Author: Ingo Molnar +Date: Tue Nov 25 16:51:45 2008 -0800 +Subject: fix warning in fs/dlm/netlink.c + + this warning: + + fs/dlm/netlink.c: In function ‘dlm_timeout_warn’: + fs/dlm/netlink.c:131: warning: ‘send_skb’ may be used uninitialized in this function + + triggers because GCC does not recognize the (correct) error flow + between prepare_data() and send_skb. + + Annotate it. + +Signed-off-by: Ingo Molnar +Signed-off-by: David S. Miller +Signed-off-by: Coly Li + +diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c +index 18bda83..aa2a577 100644 +--- a/fs/dlm/netlink.c ++++ b/fs/dlm/netlink.c +@@ -127,8 +127,8 @@ static void fill_data(struct dlm_lock_data *data, struct dlm_lkb *lkb) + + void dlm_timeout_warn(struct dlm_lkb *lkb) + { ++ struct sk_buff *uninitialized_var(send_skb); + struct dlm_lock_data *data; +- struct sk_buff *send_skb; + size_t size; + int rv; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/genhd-disk-ro-uevents b/src/patches/suse-2.6.27.31/patches.suse/genhd-disk-ro-uevents new file mode 100644 index 000000000..447f5587b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/genhd-disk-ro-uevents @@ -0,0 +1,42 @@ +From: Hannes Reinecke +Subject: Send uevents for write_protect changes +References: bnc#440959 + +Whenever a block device changes it's read-only attribute +we should notify the userspace about it. + +Signed-off-by: Hannes Reinecke + +--- + block/genhd.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -813,6 +813,16 @@ void put_disk(struct gendisk *disk) + + EXPORT_SYMBOL(put_disk); + ++static void set_disk_ro_uevent(struct gendisk *gd, int ro) ++{ ++ char event[] = "DISK_RO=1"; ++ char *envp[] = { event, NULL }; ++ ++ if (!ro) ++ event[8] = '0'; ++ kobject_uevent_env(&gd->dev.kobj, KOBJ_CHANGE, envp); ++} ++ + void set_device_ro(struct block_device *bdev, int flag) + { + if (bdev->bd_contains != bdev) +@@ -826,6 +836,9 @@ EXPORT_SYMBOL(set_device_ro); + void set_disk_ro(struct gendisk *disk, int flag) + { + int i; ++ if (disk->policy != flag) ++ set_disk_ro_uevent(disk, flag); ++ + disk->policy = flag; + for (i = 0; i < disk->minors - 1; i++) + if (disk->part[i]) disk->part[i]->policy = flag; diff --git a/src/patches/suse-2.6.27.31/patches.suse/headers_check-fix-linux-dlm_plock.h.patch b/src/patches/suse-2.6.27.31/patches.suse/headers_check-fix-linux-dlm_plock.h.patch new file mode 100644 index 000000000..89b1bfd37 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/headers_check-fix-linux-dlm_plock.h.patch @@ -0,0 +1,26 @@ +From: Jaswinder Singh Rajput +commit 37eb1f4c3320ed505fbe59a916635b2342c740e4 +Author: Jaswinder Singh Rajput +Date: Fri Jan 30 20:51:30 2009 +0530 +Subject: headers_check fix: linux/dlm_plock.h + + fix the following 'make headers_check' warning: + + usr/include/linux/dlm_plock.h:25: found __[us]{8,16,32,64} type without #include + +Signed-off-by: Jaswinder Singh Rajput +Signed-off-by: Coly Li + +diff --git a/include/linux/dlm_plock.h b/include/linux/dlm_plock.h +index 18d5fdb..2dd2124 100644 +--- a/include/linux/dlm_plock.h ++++ b/include/linux/dlm_plock.h +@@ -9,6 +9,8 @@ + #ifndef __DLM_PLOCK_DOT_H__ + #define __DLM_PLOCK_DOT_H__ + ++#include ++ + #define DLM_PLOCK_MISC_NAME "dlm_plock" + + #define DLM_PLOCK_VERSION_MAJOR 1 diff --git a/src/patches/suse-2.6.27.31/patches.suse/hp_backlight_blacklist_6530b.patch b/src/patches/suse-2.6.27.31/patches.suse/hp_backlight_blacklist_6530b.patch new file mode 100644 index 000000000..80ea6e48c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/hp_backlight_blacklist_6530b.patch @@ -0,0 +1,50 @@ +From: Thomas Renninger +Subject: Blacklist HP laptop (6530b) to not use generic ACPI backlight interface +References: bnc#491802 +Patch-Mainline: never, this will be IGD driven which is too risky to backport + + +Signed-off-by: Thomas Renninger + +--- + drivers/acpi/video_detect.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +Index: linux-2.6.27-SLE11_BRANCH/drivers/acpi/video_detect.c +=================================================================== +--- linux-2.6.27-SLE11_BRANCH.orig/drivers/acpi/video_detect.c ++++ linux-2.6.27-SLE11_BRANCH/drivers/acpi/video_detect.c +@@ -142,6 +142,25 @@ find_video(acpi_handle handle, u32 lvl, + return AE_OK; + } + ++static int set_dmi_blacklisting(const struct dmi_system_id *id) ++{ ++ printk(KERN_NOTICE "%s detected - adjusting backlight video\n", ++ id->ident); ++ acpi_video_support |= (long)id->driver_data; ++ return 0; ++} ++ ++static struct dmi_system_id video_backlight_blacklist[] = { ++ { set_dmi_blacklisting, ++ "HP 6530b", { ++ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "6530b") ++ }, ++ (void *) ACPI_VIDEO_BACKLIGHT_DMI_VENDOR ++ }, ++ {}, ++}; ++ + /* + * Returns the video capabilities of a specific ACPI graphics device + * +@@ -176,6 +195,7 @@ long acpi_video_get_capabilities(acpi_ha + * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; + *} + */ ++ dmi_check_system(video_backlight_blacklist); + } else { + status = acpi_bus_get_device(graphics_handle, &tmp_dev); + if (ACPI_FAILURE(status)) { diff --git a/src/patches/suse-2.6.27.31/patches.suse/kbd-ignore-gfx.patch b/src/patches/suse-2.6.27.31/patches.suse/kbd-ignore-gfx.patch new file mode 100644 index 000000000..8fee2a775 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kbd-ignore-gfx.patch @@ -0,0 +1,37 @@ +From: Dirk Mueller +Subject: setfont breaks first Xserver start +References: 302010 +Patch-Mainline: No + +The patch prevents setfont from accessing vga registers on the card when +the card is in graphics mode KD_GRAPHICS as we assume, that someone else (ie. +the Xserver) is in charge of the HW in which case accessing the vga registers +may (at best) have no effect (not even the desired one) or (at worst) interfer +with settings the graphics driver has made. + +Signed-off-by: Hannes Reinecke + +--- + drivers/video/console/vgacon.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/video/console/vgacon.c ++++ b/drivers/video/console/vgacon.c +@@ -1240,7 +1240,7 @@ static int vgacon_font_set(struct vc_dat + unsigned charcount = font->charcount; + int rc; + +- if (vga_video_type < VIDEO_TYPE_EGAM) ++ if (vga_video_type < VIDEO_TYPE_EGAM || vga_is_gfx) + return -EINVAL; + + if (font->width != VGA_FONTWIDTH || +@@ -1258,7 +1258,7 @@ static int vgacon_font_set(struct vc_dat + + static int vgacon_font_get(struct vc_data *c, struct console_font *font) + { +- if (vga_video_type < VIDEO_TYPE_EGAM) ++ if (vga_video_type < VIDEO_TYPE_EGAM || vga_is_gfx) + return -EINVAL; + + font->width = VGA_FONTWIDTH; diff --git a/src/patches/suse-2.6.27.31/patches.suse/kdb-common b/src/patches/suse-2.6.27.31/patches.suse/kdb-common new file mode 100644 index 000000000..8857e10d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kdb-common @@ -0,0 +1,31952 @@ +From: SGI KDB Development +Subject: kdb-v4.4-2.6.27-rc8-common-1.1 +References: FATE#303971 +X-URL: ftp://oss.sgi.com/www/projects/kdb/download/v4.4/ + +The KDB common code. + +Acked-by: Bernhard Walle + +--- + Documentation/kdb/bt_x86 | 1837 ++++++++ + Documentation/kdb/kdb.mm | 492 ++ + Documentation/kdb/kdb_bp.man | 197 + Documentation/kdb/kdb_bt.man | 315 + + Documentation/kdb/kdb_env.man | 46 + Documentation/kdb/kdb_ll.man | 134 + Documentation/kdb/kdb_md.man | 136 + Documentation/kdb/kdb_ps.man | 96 + Documentation/kdb/kdb_rd.man | 170 + Documentation/kdb/kdb_sr.man | 68 + Documentation/kdb/kdb_ss.man | 109 + Documentation/kdb/slides | 1382 ++++++ + Makefile | 1 + drivers/char/keyboard.c | 10 + drivers/hid/usbhid/hid-core.c | 28 + drivers/hid/usbhid/usbkbd.c | 17 + drivers/serial/8250.c | 53 + drivers/serial/8250_early.c | 29 + drivers/serial/sn_console.c | 73 + drivers/usb/core/hcd.c | 14 + drivers/usb/core/hcd.h | 4 + drivers/usb/host/ehci-hcd.c | 42 + drivers/usb/host/ehci-pci.c | 8 + drivers/usb/host/ehci-q.c | 222 + + drivers/usb/host/ohci-hcd.c | 67 + drivers/usb/host/ohci-pci.c | 8 + drivers/usb/host/ohci-q.c | 62 + fs/proc/mmu.c | 16 + fs/proc/proc_misc.c | 114 + include/linux/console.h | 5 + include/linux/dis-asm.h | 347 + + include/linux/kdb.h | 175 + include/linux/kdbprivate.h | 503 ++ + include/linux/reboot.h | 7 + include/linux/sysctl.h | 1 + init/main.c | 32 + kdb/ChangeLog | 2012 +++++++++ + kdb/Makefile | 43 + kdb/kdb_bp.c | 658 +++ + kdb/kdb_bt.c | 180 + kdb/kdb_cmds | 32 + kdb/kdb_id.c | 236 + + kdb/kdb_io.c | 856 ++++ + kdb/kdbdereference.c | 7257 ++++++++++++++++++++++++++++++++++ + kdb/kdbmain.c | 4333 ++++++++++++++++++++ + kdb/kdbsupport.c | 1154 +++++ + kdb/modules/Makefile | 14 + kdb/modules/kdbm_debugtypes.c | 388 + + kdb/modules/kdbm_pg.c | 688 +++ + kdb/modules/kdbm_sched.c | 57 + kdb/modules/kdbm_task.c | 205 + kdb/modules/kdbm_vm.c | 1036 ++++ + kdb/modules/kdbm_x86.c | 1093 +++++ + kdb/modules/lcrash/README | 3 + kdb/modules/lcrash/asm/README | 1 + kdb/modules/lcrash/asm/kl_dump_ia64.h | 199 + kdb/modules/lcrash/asm/kl_types.h | 48 + kdb/modules/lcrash/kl_alloc.h | 124 + kdb/modules/lcrash/kl_bfd.h | 31 + kdb/modules/lcrash/kl_btnode.h | 95 + kdb/modules/lcrash/kl_cmp.h | 102 + kdb/modules/lcrash/kl_copt.h | 29 + kdb/modules/lcrash/kl_debug.h | 168 + kdb/modules/lcrash/kl_dump.h | 511 ++ + kdb/modules/lcrash/kl_dump_arch.h | 124 + kdb/modules/lcrash/kl_dump_ia64.h | 199 + kdb/modules/lcrash/kl_dwarfs.h | 27 + kdb/modules/lcrash/kl_error.h | 266 + + kdb/modules/lcrash/kl_htnode.h | 71 + kdb/modules/lcrash/kl_lib.h | 65 + kdb/modules/lcrash/kl_libutil.h | 40 + kdb/modules/lcrash/kl_mem.h | 104 + kdb/modules/lcrash/kl_mem_ia64.h | 149 + kdb/modules/lcrash/kl_module.h | 69 + kdb/modules/lcrash/kl_queue.h | 89 + kdb/modules/lcrash/kl_stabs.h | 122 + kdb/modules/lcrash/kl_stringtab.h | 68 + kdb/modules/lcrash/kl_sym.h | 131 + kdb/modules/lcrash/kl_task.h | 39 + kdb/modules/lcrash/kl_typeinfo.h | 199 + kdb/modules/lcrash/kl_types.h | 54 + kdb/modules/lcrash/klib.h | 480 ++ + kdb/modules/lcrash/lc_eval.h | 225 + + kernel/exit.c | 3 + kernel/kallsyms.c | 22 + kernel/kexec.c | 16 + kernel/module.c | 19 + kernel/panic.c | 8 + kernel/printk.c | 14 + kernel/sched.c | 93 + kernel/signal.c | 49 + kernel/sysctl_check.c | 1 + lib/bug.c | 8 + mm/hugetlb.c | 22 + mm/mmzone.c | 4 + mm/swapfile.c | 22 + 96 files changed, 31168 insertions(+), 7 deletions(-) + +--- /dev/null ++++ b/Documentation/kdb/bt_x86 +@@ -0,0 +1,1837 @@ ++Copyright Keith Owens, 2007. ++ ++How the KDB backtrace for x86 works, how to diagnose problems and submit a bug ++============================================================================== ++ ++Unlike ia64, x86 architectures do not mandate unwind information in the kernel. ++gcc will include some unwind information for C functions, but not for assembler ++code. Attempts have been made to add unwind information to the assembler code ++by hand, with little success. Eventually Linus rejected the x86 unwind code ++because it was breaking too often and destroying useful debugging data. ++ ++Even if the x86 unwinder worked correctly, it would only give an accurate ++backtrace, it would not give function arguments. Needless to say, function ++arguments are what people really want. To get function arguments requires much ++more support from the compiler than simple unwind data, the compiler has to ++track line by line where each argument is held and make that data available to ++the debugger. Compiling with gcc -g will provide that information, but the ++resulting kernel is several times larger than normal. ++ ++Although the gcc -g data can be stored on another machine, there are constructs ++in the kernel that cannot be tracked by this method. i386 builds with 4K stacks ++and all x86_64 builds have multiple kernel stacks. The compiler knows nothing ++about these extra stacks and cannot backtrace through them correctly. The ++assembler code in arch/{i386,x86_64}/kernel/entry.S is a maze of twisty logic ++paths, some of which eventually jump to common labels. Describing this twisty ++logic to an unwinder is very difficult, expecially when you try to describe ++where arguments and/or registers are held). ++ ++KDB gets an accurate x86 backtrace and extracts the arguments by performing code ++decomposition and analysis at run time. This avoids the need to bloat the ++running kernel to several times its normal size with gcc -g data. KDB (unlike ++gdb) also knows about the additional kernel stacks and twisty assembler code ++paths. ++ ++The x86 backtrace code for i386 is very similar to the x86_64 code, with 80% ++common code and data. Most of the differences between the backtrace for the two ++architectures is due to the assembler code and stack handling. To avoid code ++duplication between KDB patches, the x86 backtrace code is actually stored in ++the kdb common patch, in source kdb/kdba_bt_x86.c. kdb/Makefile only builds ++kdba_bt_x86.o for i386 or x86_64. Most of the code reads as if the architecture ++is x86_64, using register names like rsp and rip. i386 is treated as a subset ++of x86_64, with fewer registers and printing the names as esp and eip. When ++this documentation refers to rsp and rip, read it as esp and eip for i386. The ++20% of code and data that is different in held in two large #ifdef sections, ++scan kdba_bt_x86.c for CONFIG_X86_64. Be careful when changing anything in the ++architecture specific sections, you will need to review the other architecture ++to see if it needs changes as well. ++ ++The idea behind the x86 backtrace is to trace one function at a time, which ++gives us the calling function. Then apply the same algorithm to the calling ++function until you unwind to the first function in the process. The starting ++point for tracing any process is to extract the current stack pointer and ++current instruction pointer (rsp and rip). The way that these values are ++extracted varies between running tasks and blocked tasks, the method is ++described later (Process Starting Point) but ignore it for now, just assume that ++we have a starting rsp and rip. ++ ++Given the instruction pointer (rip), we identify the start and end of the kernel ++or module function it is in, using the kernel symbol table. This is easy for C ++code, it is significantly harder for assembler code because of the twisty code ++paths that branch to common labels. The method of identifying the current ++function is described later (Identifying The Current Function) but ignore it for ++now, just assumes that we have the start and end address of the function plus ++its name. ++ ++After the rip has been mapped to a function name with sensible start and end ++addresses, the next step is to analyse the code paths in that function. KDB ++already has a built in disassembler (copied with slight modifications from ++binutils) which knows how to decode each x86 instruction. Instead of ++duplicating that logic in kdba_bt_x86, it takes advantage of the fact that you ++can override the disassembler's print function, sending the output line to a ++buffer instead of printing it. kdba_bt_x86 stills has to decode the buffer but ++that is a lot easier than decoding the x86 instruction set. ++ ++The code analysis consists of two main passes. There are example below of the ++analysis with basic block (bb) debugging activated (Examples of Basic Block ++Debugging Output). ++ ++The first pass (bb_pass1) identifies all the basic blocks in the function. For ++our purposes, a basic block has a single entry point and one or more exit ++points. The start of the function is the start of basic block 0, all other ++blocks are the target of jump instructions (conditional or unconditional) from ++within the rest of the code. A block ends with an unconditional jump or with a ++terminating instruction such as ret, iret, sysexit, sysret or ud2a (BUG). A ++block can also end because the next instruction is the start of a new block ++(target of jmp or jcc), in this case there is an implied drop through from one ++block to the next. ++ ++Although a call instruction also transfers control, it returns to the next ++instruction so call is not treated as a transfer. Instead call is treated as a ++normal instruction with side effects, the scratch registers are cleared after a ++call. ++ ++At the end of the first pass over the function we have a directed graph that ++starts at bb[0]. The nodes of the graph (bb_list[]) are the basic blocks with ++their start and end address. The vertices are the jmp or jcc instructions ++(bb_jmp_list[]) that transfer control between blocks, plus any implied drop ++through transfers between consecutive blocks. This graph can have cycles, many ++functions have loops in them which transfer control back to earlier in the code ++body. ++ ++The second pass (bb_pass2) runs over the directed graph analysing the effect of ++each instruction on the register and memory state. It is important to ++understand that the analysis in this pass is an abstract one, it does not use ++actual hex values for the register contents, instead it uses symbolic values. ++When the basic block code says that "register rsi contains value rax" it means ++that whatever value was in rax on entry to the function has also been copied to ++register rsi at this point in the logic flow. ++ ++At an abstract level, all C functions start with exactly the same state, each ++register contains its own symbolic value (except for the stack pointer, see ++later) with no local stack variables defined yet. Assembler functions tend to ++have unusual starting points, with some registers and/or memory contents defined ++differently on entry. For example, ret_from_intr on i386 already has a struct ++pt_regs on its stack, ret_from_intr on x86_64 already has a partial struct ++pt_regs plus another two words stacked on top of it. The special starting cases ++are listed in the arch specific bb_special_cases[]. ++ ++Once the input state of bb[0] has been defined (including any special cases), ++bb_pass2_do_changed_blocks() runs over all the nodes in bb_list[]. Each ++instruction in each block is analysed (Tracking the Effects of Instructions) to ++see what effect it has on the abstract register state, the analysis of each ++instruction is done in bb_usage(). An instruction can copy one register to ++another, it can copy a register to stack, move from stack to a register or it ++can invalidate the contents of a register or memory location. A general rule in ++bb_usage() is that any operation whose results cannot be calculated in terms of ++an original input value gives an undefined result. Remember that it is the ++abstract value that becomes undefined, moving a constant to a register gives a ++defined value for the view of the program but it is undefined as far as the ++abstract state is concerned. ++ ++References to data on the stack are a little awkward because the stack pointer ++frequently changes. To overcome this, kdba_bt_x86 defines a pseudo register ++called the 'original stack pointer' (osp). This always represents the stack ++pointer on entry to the function, so on entry rsp contains osp+0x0. As rsp is ++modified, it still points at osp, but its offset from osp changes. Copying rsp ++to another register (e.g. mov %rsp,%rbp) copies the osp offset as well. At the ++point that this function calls the next function down the stack, kdba_bt_x86 ++knows the delta from osp to rsp. Applying that delta to the actual value of the ++stack pointer gives the stack pointer value on input to the current function, ++that location contains the return address so we can go up one stack frame and ++repeat the process. ++ ++After doing basic block analysis on the current function, kdba_bt_x86 knows what ++the abstract register and memory state is at the point this function was ++interrupted or it called the next function down the stack, this is the exit ++state. For an interrupt the actual register values are saved in a struct ++pt_regs, for a call we have unwound from the KDB interrupt back to the called ++function so we have some idea of what the register values are in the called ++function. The abstract exit state is merged with the known actual register ++values to derive the original stack pointer. That in turn gives us any ++registers that were saved on stack. The original stack pointer gives the return ++address from the calling function, go up one stack frame and repeat the ++analysis. ++ ++ ++Process Starting Point ++====================== ++ ++All backtrace code needs a starting point which defines at least the stack ++pointer and instruction pointer, it may define other registers as well. The ++first part of kdba_bt_stack() extracts the starting point. Processes can be in ++one of three states, running (currently on a cpu), blocked (sleeping or ready to ++run but not currently on a cpu) or unknown. ++ ++For running processes, the current rsp and rip are dynamic. Because KDB stops ++the entire machine by sending an interrupt to the other cpus, KDB can save the ++rsp and rip for each cpu at the point where KDB is entered. This data is held ++in array kdb_running_process and is stored by kdb_save_running() and the arch ++specific kdba_save_running() functions. When backtracing a running process, KDB ++uses the data in kdb_running_process as its starting point. ++ ++For blocked processes we always have the saved rsp, it is held in the process's ++thread_info. For i386 blocked processes, thread_info also contains the saved ++rip. For x86_64 blocked processes, rip is no longer saved in thread_info, it is ++assumed that all blocked processes will resume at assembler label thread_return, ++so that rip is used on x86_64. See arch specific kdba_bt_stack_rip(). ++ ++Unknown process state only occurs when the user does 'bt '. ++Unlike other bt commands, 'bt ' does not identify any specific ++process, instead it identifies a kernel stack. must be inside a ++valid kernel stack and must point to a saved rip from a call instruction. ++kdba_bt_x86.c uses the common kdba_get_stack_info() and arch specific ++kdba_get_stack_info_alternate() functions to check that the address falls within ++a valid kernel stack. If the user gives a stack address that does not point to ++a saved rip from a call instruction then the backtrace will be garbage. ++ ++ ++Identifying The Current Function ++================================ ++ ++Given a rip value, KDB uses the kallsyms data to find the start of the function ++(first address <= rip) and the end of the function (next symbol in kallsyms). ++This works for plain C code because gcc only generates one label per function. ++It does not work for assembler code or for assembler code embedded in C ++functions, because the assembler labels appear as global entries in kallsyms. ++For example, arch/i386/kernel/entry.S has function ret_from_exception which ++contains three global labels ret_from_intr, check_userspace and ++resume_userspace. If rip points to any of those global labels, KDB wants the ++start of the real function, i.e. ret_from_exception. In addition, if rip points ++to ret_from_exception, KDB wants the end of the function to be after the last ++global label in that function, i.e. after resume_userspace. ++ ++The simplest way to handle these unwanted global labels is to list the spurious ++assembler labels, which is done in the arch specific array bb_spurious. After ++mapping rip to the nearest start and end labels from kallsyms, kdb_bb() works ++backwards until it finds a non-spurious label then works forwards to the next ++non-spurious label. That gives a real start and end address and a real name for ++the current function. ++ ++Note that this algorithm only applies in kdb_bb() when it maps rip to a suitable ++start and end address. When disassembling the code, you will still see the ++spurious label names, users need to see the extra labels. ret_from_exception on ++i386 disassembles like this (2.6.22) :- ++ ++[0]kdb> id ret_from_exception ++0xc0102554 ret_from_exception: cli ++0xc0102555 ret_from_intr: mov $0xfffff000,%ebp ++0xc010255a ret_from_intr+0x5: and %esp,%ebp ++0xc010255c check_userspace: mov 0x34(%esp),%eax ++0xc0102560 check_userspace+0x4: mov 0x30(%esp),%al ++0xc0102564 check_userspace+0x8: and $0x20003,%eax ++0xc0102569 check_userspace+0xd: cmp $0x3,%eax ++0xc010256c check_userspace+0x10: jb 0xc010258c resume_kernel ++0xc0102572 check_userspace+0x16: mov %esi,%esi ++0xc0102574 resume_userspace: cli ++0xc0102575 resume_userspace+0x1: mov 0x8(%ebp),%ecx ++0xc0102578 resume_userspace+0x4: and $0xfe3e,%ecx ++0xc010257e resume_userspace+0xa: jne 0xc01026f4 work_pending ++0xc0102584 resume_userspace+0x10: jmp 0xc01026a7 restore_all ++0xc0102589 resume_userspace+0x15: lea 0x0(%esi),%esi ++0xc010258c resume_kernel: cli ++ ++For the purposes of kdba_bt_x86.c, any rip from 0xc0102554 to 0xc0102589 needs ++to map to the range 0xc0102554 (start) to 0xc010258c (end) with function name ++ret_from_exception. Therefore ret_from_intr, check_userspace and ++resume_userspace are listed in bb_spurious[] for i386 so those symbols are ++ignored. The comments in bb_spurious[] list the function that encloses each ++spurious label, those comments are only for humans, they do not affect the code. ++ ++Once rip has been mapped to non-spurious labels, the module name, function name, ++start and end address are stored in variables bb_mod_name, bb_func_name, ++bb_func_start, bb_func_end. These variables are used throughout kdba_bt_x86.c ++for processing each function in turn. ++ ++Watch for changes to assembler code, especially in arch/i386/kernel/entry.S, ++arch/x86_64/kernel/entry.S and arch/x86_64/ia32/ia32entry.S. When new labels ++are added you may need to adjust bb_spurious[] for that architecture. Running ++bb_all can help identify assembler labels that have been added or deleted. ++ ++ ++Tracking the Effects of Instructions ++==================================== ++ ++bb_pass2_do_changed_blocks() uses the KDB disassembler to decode the x86 ++instructions to something a human can read. bb_dis_pass2() is used as a print ++routine to store data for a single instruction in a buffer then ++bb_parse_buffer() starts the analysis. Any instruction prefixes like lock or ++rep are stripped out. The opcode string is isolated then up to 3 operands are ++extracted (imul can have 3 operands), these are src, dst and dst2. The operand ++is matched against table bb_opcode_usage_all[] which lists all the instructions ++that actually appear in i386 and x86_64 kernels. A lot of the x86 instrcution ++set is not used by the kernel so instructions such as SSE do not appear in ++bb_opcode_usage_all[]. ++ ++Each operand is decoded by bb_parse_operand() to see whether it has a segment ++prefix, displacement, base, index or scale. An indirect call or jmp is ++identified. Operands consisting only of a register are classified as 'reg' ++type, displacements starting with '$' are immediate values otherwise the operand ++refers to a memory location. Any base or index register name is mapped to the ++abstract register name that contains it, this takes care of mapping (say) %ah to ++rax. ++ ++After decoding the opcode and all its operands, bb_usage() decides what effect ++the instruction will have on the abstract state machine. Some x86 instructions ++list all the affected registers in their operands and these can be handled as ++generic cases. Alas many x86 instructions have side effects and change ++registers that are not listed in the operands, these have to be handled as ++special cases. enum bb_operand_usage lists the generic and special cases. ++ ++bb_usage() is basically one huge switch statement over the special values in ++enum bb_operand_usage. For each special case it tracks the side effects of the ++instruction. Once all the special cases have been handled and converted to ++generic cases then bb_usage() handles the generic cases. ++ ++bb_usage() detects when a register is copied to another register, a register is ++copied to stack or a known stack value is copied to a register and updates the ++state data accordingly. It is particularly important that all stack pointer ++updates and copies of the stack pointer are tracked, much of the saved state is ++on stack and can be accessed via any register that points to the stack, not just ++via rsp. ++ ++i386 built with 4K stacks and all x86_64 builds have multiple kernel stacks. ++bb_usage() knows which instructions or locations are used to switch stacks and ++pretends that these instructions have no effect on the contents of rsp. The ++higher level backtrace code knows how to handle stack switching, it is too ++complicated for basic block analysis. ++ ++ ++Transfer of Control Outside the Current Function ++================================================ ++ ++Ignoring call instructions, most C code does not transfer control outside the ++current function, IOW there are no jump instructions to instructions outside the ++function. There are a few cases that this can occur for C code, inline ++assembler and tail recursion. ++ ++Tail recursion occurs when a function ends by returning the value from a second ++function and that second function has exactly the same arguments and return ++value as the current function. For example, ++ ++ int bar(int i, char *p) ++ { ++ ... do some work and return an int ... ++ } ++ ++ int foo(int i, char *p) ++ { ++ return bar(i, p); ++ } ++ ++If tail recursion is active (gcc -foptimize-sibling-calls) then instead of foo ++calling bar, bar returning to foo then foo returning to its caller, gcc will end ++foo with a direct jmp to bar. The source code says that something called foo ++but the stack trace will show bar is active, with no sign of foo on stack. When ++bar returns it will use the return address from the code that called foo. ++ ++bb_transfer() detects an unconditional jmp to code outside the function body and ++assumes that this represents tail recursion. For tail recursion to work ++correctly, all the preserved registers must contain their original values, ++bb_sanity_check() validates this. Any deviation from the expected state will ++stop basic block analysis and fall back on the old unreliable backtrace code. ++ ++Besides tail recursion in C code, assembler code can jump to labels outside the ++current function. Unfortunately this occurs all the time in the twisty ++assembler code and, to make things worse, many of these transfers are done with ++non-standard register or memory state. bb_special_case() and the arch specific ++bb_special_cases[] handle all the known special cases, including what the ++register and/or memory state should be. Any deviation from the expected state ++will stop basic block analysis and fall back on the old unreliable backtrace ++code. ++ ++ ++Locating Arguments ++================== ++ ++Function arguments can be passed in registers or on stack. The full ABI for ++passing arguments is described in ++ ++ http://www.caldera.com/developers/devspecs/abi386-4.pdf ++ http://www.x86-64.org/documentation/abi.pdf ++ ++The short description, ignoring special cases like passing structures by name ++and floating point arguments which tend not to apply to the kernel, is :- ++ ++i386. With -mpregparm=0, all arguments are passed on stack, except for ++ functions defined as FASTCALL, where the first 3 arguments are passed in ++ registers. ++ ++ With -mregparm=3, the first 3 arguments are passed in registers except ++ for functions defined as asmlinkage or with variable number of ++ arguments, when arguments are still passed on stack. -mpregparm=3 used ++ to be a config option, in recent kernels it is the default. ++ ++ Arguments defined as long long (64 bit) are passed in two registers or ++ in two locations on stack. Being passed in two pieces makes a 64 bit ++ argument look like two 32 bit arguments to KDB, it will be printed as ++ two separate arguments. ++ ++ When compiled with -mregparm=3, if a 64 bit argument is argument number ++ 2 then it will not be split between register and stack, instead it will ++ all be on stack and the third argument register will not be used. This ++ makes it look like there is an extra argument in the list. There is ++ nothing that KDB can do to detect these corner cases with 64 bit ++ arguments on i386, which is a pity because they can confuse users. ++ ++ The preserved registers are ebx, ebp, esp, esi, edi. Arguments are ++ passed in eax, edx, ecx. The return value is in eax. ++ ++x86_64. The first 6 arguments are passed in registers, the 7th and later ++ arguments are passed on stack. Except for functions with a variable ++ number of arguments (e.g. printk) where all arguments are on stack ++ except for rax which contains the number of SSE arguments (always 0 for ++ the kernel). ++ ++ The preserved registers are rbx, rbp, rsp, r12, r13, r14, r15. ++ Arguments are passed in rdi, rsi, rdx, rcx, r8, r9. The return value is ++ in rax. ++ ++For both architectures, kdba_bt detects an argument that is passed in a register ++by the fact that the function code reads from that argument type register while ++it contains its original value. IOW, testing the value of rax, copying rax to ++another register or storing it on stack without first overwriting rax means that ++rax contains a useful input value. Reading from memory which is above the ++original stack pointer means that there is a argument at that location on ++stack. ++ ++There are some functions in the kernel whose definition contains arguments that ++are not actually used. Typically these functions are instantiations of generic ++function definitions where some, but not all, instantiations use all the ++arguments. For example, a filesystem function may take flags that are not used ++by this particular filesystem, but the function definition has to match the ++generic filesystem declarations. If the unused arguments are at the end of the ++list then there is no way of telling from the object code that they exist, the ++function that does not use the trailing aguments will have no code that refers ++to them. KDB will print a truncated argument list for this case. ++ ++If the unused arguments are not at the end of the list then KDB can detect the ++presence of the unused arguments, because there is code that refers to later ++arguments. KDB will print the unused argument, although gcc may have ++overwritten the register it is in, in which case KDB prints "invalid". ++ ++Originally kdba_bt_x86 would detect that there was no reference to arguments in ++registers but there were still references to arguments on stack and assume that ++the function had all its arguments on stack. Unfortunately this did not work ++with the large number of 'pass through' functions in the kernel. A 'pass ++through' function is one which calls another function with roughly the same ++argument list and makes no other reference to the register arguments. For ++example, ipv4_doint_and_flush_strategy() takes 7 arguments, calls ++devinet_conf_sysctl() with those 7 arguments in the same order and has no other ++reference to any of its arguments. ++ ++Pass through functions do not touch the arguments that are passed in registers ++because they are already in the right location for the routine about to be ++called, so the pass through function has no code that references the argument ++registers. No code means that kdba_bt_x86 cannot tell if the function has ++register arguments or not. The arguments passed on stack must always be copied ++to the new stack frame, even for pass through functions, so the arguments on ++stack can always be detected. ++ ++kdba_bt_x86 was changed to assume that if there are any arguments on stack then ++there are always arguments in registers, except for a list of functions that are ++known to be asmlinkage or to have a variable number of arguments. ++bb_assume_pass_through() ignores the known special cases, for other functions ++which have stack arguments but no register arguments it assumes the function is ++pass through and prints a warning about that assumption. ++ ++The above heuristics mean that there is one case that kdba_bt_x86 cannot detect: ++pass through functions where all the arguments are in registers. These have no ++argument references at all in their code, so they are printed with no arguments. ++All they do is call another function so this class of functions never fails, or ++if it does fail then it is due to something that is not argument related. If ++the failure is further down the call stack then the arguments are printed at the ++next function down the stack, so the user still has the arguments. ++ ++This list of limitations on getting the x86 arguments may seem to be a long one, ++but kdba_bt_x86 gives sensible results for most functions. For kernel ++debugging, any arguments are far better than none at all. ++ ++ ++Kernel Stack Switching ++====================== ++ ++Understanding the unusual way that x86 kernel stacks are used is very important ++when diagnosing backtrace problems. Every process has its own normal kernel ++stack, even processes that run entirely within the kernel such as kthread or the ++per cpu migration processes. The normal stacks are 4K or 8K on i386 (depending ++on CONFIG_4KSTACKS) and 8K on x86_64. The normal stacks are global, they are ++not tied to any cpu. ++ ++For i386 with 8K stacks there are no other kernel stacks so there is no stack ++switching to worry about. ++ ++For i386 with 4K process stacks, each cpu also has a 4K soft irq stack and a 4K ++hard irq stack. It is possible for a process to be running on its own process ++stack, for the process to be interrupted by a soft irq which is then interrupted ++by a hard irq. At that point the backtrace is split between the hard irq, the ++soft irq and the normal normal stacks. ++ ++On x86_64, each cpu always has stacks for stackfault, doublefault, nmi, debug, ++mce and interrupts. See Documentation/x86_64/kernel-stacks. ++ ++The arch specific kdba_get_stack_info_alternate() function works out which stack ++the backtrace starts on, how big the stack is and how to switch to the next ++stack. This information is stored in the kdb_activation_record and used by the ++higher level backtrace code to detect a stack switch. ++ ++The normal stack has some padding at the end, this reflects the stack pointer ++when the process was created in the kernel. kdba_bt_x86 cannot backtrace ++through this padding data, mainly because the code that set the nitial stack ++pointer no longer exists after boot. ARCH_NORMAL_PADDING defines how many words ++to ignore at the end of the normal stack. ++ ++ ++Debugging KDB ++============= ++ ++KDB has conditional debugging print statements scattered throughout the code. ++If KDB is not behaving as expected, you can turn on debugging and rerun the ++command. Before debugging KDB, set LINES 10000 and capture the output via a ++serial console. If using minicom, turn on word wrap (control-A W) and capture ++mode (control-A L). If you are using a serial console via a serial to Ethernet ++interface using ssh or telnet, use the 'script' command to start the session. ++ ++The various KDB_DEBUG_FLAG_* flags are listed in include/linux/kdbprivate.h. ++You set debug with 'set KDBDEBUG 0xnn' where nn is the or'd value of the desired ++flags. 'set KDBDEBUG 0' turns off KDB debugging. When diagnosing x86 backtrace ++problems, the most useful debug flags are ++ ++ KDB_DEBUG_FLAG_ARA 0x10 Activation record, arch specific ++ KDB_DEBUG_FLAG_BB_SUMM 0x04 Basic block analysis, summary only ++ KDB_DEBUG_FLAG_BB 0x20 All basic block analysis ++ ++ARA prints information about the different kernel stacks as kdba_bt_x86 unwinds ++through the switched kernel stacks. BB_SUMM prints a summary of the basic block ++analysis for each function, including the abstract exit state and the rollback ++calculations. BB prints a huge amount of basic block debugging, you probably ++only want to turn this for the full backtrace on as a last resort. ++ ++I find 'set KDBDEBUG 0x14' to be best to get an overview of a problem. It gives ++both the kernel stack information plus the abstract state and actual location of ++data for each function. ++ ++Command 'bb1' does a detailed debug session for a single function, bb1 takes a ++single parameter, the address of the exit point from the function, by number, ++not by name. bb1 turns on KDB_DEBUG_FLAG_BB, does basic block analysis for the ++function that contains the exit point then resets the debug flags to their ++previous value. ++ ++Command 'bb_all' runs through every function in the base kernel (not module ++functions) and does a basic block analysis of every function. It also validates ++the various tables in kdba_bt_x86 where possible. bb_all is meant for the KDB ++maintainer to check that all the base kernel function pass the sanity checks, it ++can also be used by end users when reporting a bug. bb_all takes no parameters. ++It prints a '.' for every 100 functions it has analysed and allows for up to 20 ++errors before giving up. The output from bb_all also includes the config ++variables that affect basic block analysis plus any assumptions about 'pass ++through' functions. ++ ++ ++Submitting a Bug Report Against kdba_bt_x86 ++=========================================== ++ ++Capture the KDB output via a serial console. ++ ++set LINES 10000 ++set BTSP 1 ++set KDBDEBUG 0x14 ++Reproduce the problem. ++set KDBDEBUG 0 ++bb_all ++ ++If you can identify the rip/eip where kdba_bt_x86 gets confused, run bb1 with ++that address. ++ ++Find each set of output from kdba_get_stack_info in the trace, extract the last ++two lines and type those lines into KDB. That will give a hex and symbolic dump ++of the raw kernel stacks. For example, if the trace data is ++ ++kdba_get_stack_info: esp=0xc04fbef8 cpu=0 task=c047b3e0 ++kdba_get_stack_info: ar->stack ++ physical_start=0xc04fb000 ++ physical_end=0xc04fc000 ++ logical_start=0xc04fb038 ++ logical_end=0xc04fc000 ++ next=0xc04b4f44 ++ id=hardirq_ctx ++ set MDCOUNT 1024 ++ mds 0xc04fb000 ++ ++then type the last two lines into KDB. Repeat this for each stack listed by ++kdba_get_stack_info on the failing backtrace. ++ ++Send all the console output to the KDB maintainer. ++ ++ ++Examples of Basic Block Debugging Output ++======================================== ++ ++Example of the basic block analysis of fs/namei::getname() on i386. Kernel ++2.6.22, i386, compiled with frame pointers, gcc 4.1.0. ++ ++Basic block debugging is very verbose, so set a high number of output lines. ++You really need a reliable serial console to capture this amount of output. ++ ++ [0]kdb> set LINES 10000 ++ ++A simple disassemble of getname(). This is not required for debugging purposes ++since each instruction is printed as part of basic block debugging, but this can ++be easier to read. ++ ++ [0]kdb> id getname ++ 0xc015cce8 getname: push %ebp ++ 0xc015cce9 getname+0x1: mov %esp,%ebp ++ 0xc015cceb getname+0x3: push %edi ++ 0xc015ccec getname+0x4: push %esi ++ 0xc015cced getname+0x5: push %ebx ++ 0xc015ccee getname+0x6: sub $0x4,%esp ++ 0xc015ccf1 getname+0x9: mov %eax,%edi ++ 0xc015ccf3 getname+0xb: mov $0xd0,%edx ++ 0xc015ccf8 getname+0x10: mov 0xc04b2120,%eax ++ 0xc015ccfd getname+0x15: call 0xc0153009 kmem_cache_alloc ++ 0xc015cd02 getname+0x1a: mov %eax,0xfffffff0(%ebp) ++ 0xc015cd05 getname+0x1d: mov $0xfffffff4,%eax ++ 0xc015cd0a getname+0x22: cmpl $0x0,0xfffffff0(%ebp) ++ 0xc015cd0e getname+0x26: je 0xc015cd7d getname+0x95 ++ 0xc015cd10 getname+0x28: mov %esp,%eax ++ 0xc015cd12 getname+0x2a: and $0xfffff000,%eax ++ 0xc015cd17 getname+0x2f: cmpl $0xffffffff,0x18(%eax) ++ 0xc015cd1b getname+0x33: je 0xc015cd39 getname+0x51 ++ 0xc015cd1d getname+0x35: mov $0xfffffff2,%esi ++ 0xc015cd22 getname+0x3a: cmp $0xbfffffff,%edi ++ 0xc015cd28 getname+0x40: ja 0xc015cd60 getname+0x78 ++ 0xc015cd2a getname+0x42: mov $0xc0000000,%ebx ++ 0xc015cd2f getname+0x47: sub %edi,%ebx ++ 0xc015cd31 getname+0x49: cmp $0xfff,%ebx ++ 0xc015cd37 getname+0x4f: jbe 0xc015cd3e getname+0x56 ++ 0xc015cd39 getname+0x51: mov $0x1000,%ebx ++ 0xc015cd3e getname+0x56: mov %ebx,%ecx ++ 0xc015cd40 getname+0x58: mov %edi,%edx ++ 0xc015cd42 getname+0x5a: mov 0xfffffff0(%ebp),%eax ++ 0xc015cd45 getname+0x5d: call 0xc023dbb4 strncpy_from_user ++ 0xc015cd4a getname+0x62: cmp $0x0,%eax ++ 0xc015cd4d getname+0x65: jle 0xc015cd5a getname+0x72 ++ 0xc015cd4f getname+0x67: mov $0xffffffdc,%esi ++ 0xc015cd54 getname+0x6c: cmp %ebx,%eax ++ 0xc015cd56 getname+0x6e: jae 0xc015cd60 getname+0x78 ++ 0xc015cd58 getname+0x70: jmp 0xc015cd71 getname+0x89 ++ 0xc015cd5a getname+0x72: je 0xc015cd76 getname+0x8e ++ 0xc015cd5c getname+0x74: jge 0xc015cd71 getname+0x89 ++ 0xc015cd5e getname+0x76: mov %eax,%esi ++ 0xc015cd60 getname+0x78: mov 0xfffffff0(%ebp),%edx ++ 0xc015cd63 getname+0x7b: mov 0xc04b2120,%eax ++ 0xc015cd68 getname+0x80: call 0xc01521f1 kmem_cache_free ++ 0xc015cd6d getname+0x85: mov %esi,%eax ++ 0xc015cd6f getname+0x87: jmp 0xc015cd7d getname+0x95 ++ 0xc015cd71 getname+0x89: mov 0xfffffff0(%ebp),%eax ++ 0xc015cd74 getname+0x8c: jmp 0xc015cd7d getname+0x95 ++ 0xc015cd76 getname+0x8e: mov $0xfffffffe,%esi ++ 0xc015cd7b getname+0x93: jmp 0xc015cd60 getname+0x78 ++ 0xc015cd7d getname+0x95: pop %edx ++ 0xc015cd7e getname+0x96: pop %ebx ++ 0xc015cd7f getname+0x97: pop %esi ++ 0xc015cd80 getname+0x98: pop %edi ++ 0xc015cd81 getname+0x99: pop %ebp ++ 0xc015cd82 getname+0x9a: ret ++ ++The bb1 command only one argument which must be an address, not a name. bb1 ++turns on full basic block debugging and analyses the function containing the ++supplied address. Give bb1 the address of the exit point from this function, ++IOW the return address that is stored on stack due to a call from this function ++to the next function down the call stack. Assume that getname() has called ++kmem_cache_free() and something went wrong in kmem_cache_free() or one of the ++functions that it calls. The call to kmem_cache_free is at 0xc015cd68 and the ++return address on stack is the instruction after the call, i.e. 0xc015cd6d, so ++ ++ [0]kdb> bb1 0xc015cd6d ++ bb_pass1: func_name getname func_start 0xc015cce8 func_end 0xc015cd83 ++ ++bb_pass1 has identified the function name and its start and end address. For C ++functions these are just the function start address and the next symbol in ++kallsyms. For Assembler code there may be spurious labels so the function name ++may not match the label prior to the address given to bb1. For an example of ++that on i386, find the address of resume_userspace then pass that address to the ++bb1 KDB command. ++ ++ bb_pass1: end ++ bb[0] start 0xc015cce8 end 0xc015cd38 drop_through 1 ++ bb[1] start 0xc015cd39 end 0xc015cd3d drop_through 1 ++ bb[2] start 0xc015cd3e end 0xc015cd58 drop_through 0 ++ bb[3] start 0xc015cd5a end 0xc015cd5f drop_through 1 ++ bb[4] start 0xc015cd60 end 0xc015cd6f drop_through 0 ++ bb[5] start 0xc015cd71 end 0xc015cd74 drop_through 0 ++ bb[6] start 0xc015cd76 end 0xc015cd7b drop_through 0 ++ bb[7] start 0xc015cd7d end 0xc015cd82 drop_through 0 ++ bb_jmp[0] from 0xc015cd0e to 0xc015cd7d drop_through 0 ++ bb_jmp[1] from 0xc015cd1b to 0xc015cd39 drop_through 0 ++ bb_jmp[2] from 0xc015cd28 to 0xc015cd60 drop_through 0 ++ bb_jmp[3] from 0xc015cd37 to 0xc015cd3e drop_through 0 ++ bb_jmp[4] from 0xc015cd4d to 0xc015cd5a drop_through 0 ++ bb_jmp[5] from 0xc015cd56 to 0xc015cd60 drop_through 0 ++ bb_jmp[6] from 0xc015cd58 to 0xc015cd71 drop_through 0 ++ bb_jmp[7] from 0xc015cd5a to 0xc015cd76 drop_through 0 ++ bb_jmp[8] from 0xc015cd5c to 0xc015cd71 drop_through 0 ++ bb_jmp[9] from 0xc015cd6f to 0xc015cd7d drop_through 0 ++ bb_jmp[10] from 0xc015cd74 to 0xc015cd7d drop_through 0 ++ bb_jmp[11] from 0xc015cd7b to 0xc015cd60 drop_through 0 ++ bb_jmp[12] from 0xc015cd38 to 0xc015cd39 drop_through 1 ++ bb_jmp[13] from 0xc015cd3d to 0xc015cd3e drop_through 1 ++ bb_jmp[14] from 0xc015cd5f to 0xc015cd60 drop_through 1 ++ ++After analysing the logic flow, we can see that getname() consists of 8 basic ++blocks (nodes in bb_list[]). 5 of these blocks end in unconditional jumps, the ++other 3 drop through to the next block. There are 15 transfers of control ++(vertices in bb_jmp_list[]). 12 of these transfers are explicit jmp or jcc ++instructions, the other 3 are implicit transfers when dropping through from one ++block to the next. The node list is sorted by start address, the vertex list is ++not sorted. ++ ++Basic block 0 starts at the function start (0xc015cce8) and ends at 0xc015cd38. ++0xc015cd39 is the target of a jump instruction (0xc015cd1b: je 0xc015cd39) so ++0xc015cd39 starts a new block, which means that 0xc015cd38 becomes the end of ++the previous block. Because bb[0] does not end in an explicit jmp instruction, ++there is a drop through from the end of bb[0] to the start of bb[1], see ++bb_jmp[12]. ++ ++ bb_pass2: start ++ ++To get the most accurate results from pass2, try to scan the directed graph by ++only looking at nodes whose inputs are all defined. Initially only process ++nodes with no missing inputs. ++ ++ bb_pass2_do_changed_blocks: allow_missing 0 ++ ++ bb[0] ++ bb_reg_state c07282e0 ++ rax = rax ++ rbx = rbx ++ rcx = rcx ++ rdx = rdx ++ rdi = rdi ++ rsi = rsi ++ rbp = rbp ++ rsp = osp+0x0 ++ ++The initial state for bb[0] is the same for all C functions. Each register ++contains its own abstract value, except for rsp which is defined in terms of the ++original stack pointer (osp). ++ ++ '0xc015cce8 getname: push %ebp' ++ ++The first instruction of getname() saves the frame pointer. ++ ++ opcode 'push' matched by 'push', usage 44 ++ src R: %ebp base_rc 8 (rbp) ++ ++bb_usage() reports how the instruction was recognised and how its operands were ++decoded. Although this is i386 (ebp), it is reported as rbp. Using the x86_64 ++names for registers throughout makes it easier to create common code for the two ++architecures. ++ ++ rsp osp offset +0x0 -> -0x4 ++ ++A push instruction decrements rsp by 4 (i386) or 8 (x86_64) bytes. rsp ++originally contained the original stack pointer (osp), now it contains the ++original stack pointer - 4. ++ ++ *(rsp+0x0 osp-0x4) = rbp slot 0 ++ ++The stack location pointed to by *rsp now contains the original value of rbp. ++Since rsp contains (osp-0x4), *(osp-0x4) contains rbp. It is slot 0 in the ++memory array associated with the register state. ++ ++ '0xc015cce9 getname+0x1: mov %esp,%ebp' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %esp base_rc 9 (rsp) ++ dst R: %ebp base_rc 8 (rbp) ++ rbp = rsp (osp-0x4) ++ ++Copy esp (rsp) to ebp (rbp). rsp contained (osp-0x4) so rbp also contains ++(osp-0x4). Any reference to data via either rbp or rsp will now be tracked as a ++stack location. ++ ++ '0xc015cceb getname+0x3: push %edi' ++ opcode 'push' matched by 'push', usage 44 ++ src R: %edi base_rc 6 (rdi) ++ rsp osp offset -0x4 -> -0x8 ++ *(rsp+0x0 osp-0x8) = rdi slot 1 ++ '0xc015ccec getname+0x4: push %esi' ++ opcode 'push' matched by 'push', usage 44 ++ src R: %esi base_rc 7 (rsi) ++ rsp osp offset -0x8 -> -0xc ++ *(rsp+0x0 osp-0xc) = rsi slot 2 ++ '0xc015cced getname+0x5: push %ebx' ++ opcode 'push' matched by 'push', usage 44 ++ src R: %ebx base_rc 3 (rbx) ++ rsp osp offset -0xc -> -0x10 ++ *(rsp+0x0 osp-0x10) = rbx slot 3 ++ ++Push 3 registers to stack. rsp is adjusted for each push and stack locations ++are assigned to contain the values of edi, esi and ebx. This sequence is very ++common in i386 C functions. edi, esi and ebx are preserved registers on i386, ++but gcc wants to use them for scratch space. The original contents iof these ++registers must be saved on stack and restored before returning to our caller. ++ ++ '0xc015ccee getname+0x6: sub $0x4,%esp' ++ opcode 'sub' matched by 'sub', usage 51 ++ src I: $0x4 ++ dst R: %esp base_rc 9 (rsp) ++ rsp osp offset -0x10 -> -0x14 ++ ++Subtract 4 bytes from esp. This defines the local stack variables. Sorry, ++names for local stack variables are not available to KDB. ++ ++ '0xc015ccf1 getname+0x9: mov %eax,%edi' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %eax base_rc 2 (rax) ++ dst R: %edi base_rc 6 (rdi) ++ rdi = rax (rax) ++ ++Having saved edi on stack, gcc now overwrites edi with eax. At this point rax ++still contains its original value, so rdi now contains a copy of rax, as well as ++the original value which is still in rax. This is a common sequence in C code. ++rax contains argument 0 but it is also a scratch register. If the code needs to ++use argument 0 later then its value must be saved somewhere before executing any ++instruction that changes rax. edi is a preserved register so its contents will ++not be changed by any function that we call, or if it is changed then it will be ++restored before returning to this function. ++ ++rax is listed in the arch specific bb_param_reg[] list and the code is reading ++from rax while it still contains its original value. The only way that makes ++any sense is when rax is an input argument to getname(). We note that fact in ++bb_reg_read(). ++ ++ '0xc015ccf3 getname+0xb: mov $0xd0,%edx' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0xd0 ++ dst R: %edx base_rc 5 (rdx) ++ rdx = undefined ++ ++Moving an constant value to edx. Although this is a constant, it does not refer ++to any of the original values that were supplied to this function. Therefore ++rdx becomes undefined for the purposes of the code analysis. ++ ++ '0xc015ccf8 getname+0x10: mov 0xc04b2120,%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src M: 0xc04b2120 ++ dst R: %eax base_rc 2 (rax) ++ rax = undefined ++ ++Moving a constant value to eax makes rax undefined. ++ ++ '0xc015ccfd getname+0x15: call 0xc0153009 ' ++ opcode 'call' matched by 'call', usage 17 ++ src M: 0xc0153009 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = rcx ++ rdx = undefined ++ rdi = rax ++ rsi = rsi ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++Basic block debugging prints the register and memory state when transfering ++control between blocks and when issuing call instructions. The call state is ++mainly useful when C code calls assembler routines, especially if you are not ++sure what state the assembler code expects. Not all of our assembler is as well ++documented as it could be :( ++ ++ rax = undefined ++ rcx = undefined ++ rdx = undefined ++ ++The i386 ABI says that some registers are preserved across calls, see the arch ++specific bb_preserved_reg[] list. Any registers not in that list automatically ++become undefined after a call instruction. ++ ++ '0xc015cd02 getname+0x1a: mov %eax,0xfffffff0(%ebp)' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %eax base_rc 2 (rax) ++ dst M: 0xfffffff0(%ebp) base_rc 8 (rbp) ++ ++eax is the return value from the call, it is being saved at offset 0xfffffff0 ++(-0x10) from ebp. Since rbp contains (osp-0x4) the return value is being stored ++at (osp-0x14). This is a stack location but we have no record of any data being ++held at that location, it is part of the local stack variables. ++ ++ '0xc015cd05 getname+0x1d: mov $0xfffffff4,%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0xfffffff4 ++ dst R: %eax base_rc 2 (rax) ++ rax = undefined ++ '0xc015cd0a getname+0x22: cmpl $0x0,0xfffffff0(%ebp)' ++ opcode 'cmpl' matched by 'cmp', usage 3 ++ src I: $0x0 ++ dst M: 0xfffffff0(%ebp) base_rc 8 (rbp) ++ '0xc015cd0e getname+0x26: je 0xc015cd7d ' ++ opcode 'je' matched by 'j', usage 28 ++ src M: 0xc015cd7d ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = rsi ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++Transfer of control, print the register and memory state. ++ ++ matched: from 0xc015cd0e to 0xc015cd7d drop_through 0 bb_jmp[0] ++ ++Which bb_jmp_list[] entry matches this transfer. ++ ++ new state c07286b8 ++ ++The current abstract register and memory state is cloned at address c07286b8. ++This state becomes one of the inputs to the basic block whose start address is ++0xc015cd7d. ++ ++ '0xc015cd10 getname+0x28: mov %esp,%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %esp base_rc 9 (rsp) ++ dst R: %eax base_rc 2 (rax) ++ rax = rsp (osp-0x14) ++ ++Copy rsp which contains (osp-0x14) to rax. rax contains a valid stack pointer. ++ ++ '0xc015cd12 getname+0x2a: and $0xfffff000,%eax' ++ opcode 'and' matched by 'and', usage 11 ++ src I: $0xfffff000 ++ dst R: %eax base_rc 2 (rax) ++ rax = undefined ++ ++But not for long. ++ ++ '0xc015cd17 getname+0x2f: cmpl $0xffffffff,0x18(%eax)' ++ opcode 'cmpl' matched by 'cmp', usage 3 ++ src I: $0xffffffff ++ dst M: 0x18(%eax) base_rc 2 (rax) ++ '0xc015cd1b getname+0x33: je 0xc015cd39 ' ++ opcode 'je' matched by 'j', usage 28 ++ src M: 0xc015cd39 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = rsi ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++Another transfer of control, print the state. ++ ++ matched: from 0xc015cd1b to 0xc015cd39 drop_through 0 bb_jmp[1] ++ ++Which bb_jmp_list[] entry was used. ++ ++ reuse bb_jmp[0] ++ ++To save space, we only clone the state if it is different. Otherwise we reuse ++the state from another vertex and bump the reference count. ++ ++ '0xc015cd1d getname+0x35: mov $0xfffffff2,%esi' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0xfffffff2 ++ dst R: %esi base_rc 7 (rsi) ++ rsi = undefined ++ ++Using esi as a scratch register, even though the i386 ABi says that esi is a ++preserved register. Not to worry, the original value of rsi was saved on stack ++on entry and it will be restored before exit. ++ ++ '0xc015cd22 getname+0x3a: cmp $0xbfffffff,%edi' ++ opcode 'cmp' matched by 'cmp', usage 3 ++ src I: $0xbfffffff ++ dst R: %edi base_rc 6 (rdi) ++ '0xc015cd28 getname+0x40: ja 0xc015cd60 ' ++ opcode 'ja' matched by 'j', usage 28 ++ src M: 0xc015cd60 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd28 to 0xc015cd60 drop_through 0 bb_jmp[2] ++ new state c0728710 ++ ++This state is different from any states already saved, clone to a new entry. ++ ++ '0xc015cd2a getname+0x42: mov $0xc0000000,%ebx' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0xc0000000 ++ dst R: %ebx base_rc 3 (rbx) ++ rbx = undefined ++ '0xc015cd2f getname+0x47: sub %edi,%ebx' ++ opcode 'sub' matched by 'sub', usage 51 ++ src R: %edi base_rc 6 (rdi) ++ dst R: %ebx base_rc 3 (rbx) ++ rbx = undefined ++ '0xc015cd31 getname+0x49: cmp $0xfff,%ebx' ++ opcode 'cmp' matched by 'cmp', usage 3 ++ src I: $0xfff ++ dst R: %ebx base_rc 3 (rbx) ++ '0xc015cd37 getname+0x4f: jbe 0xc015cd3e ' ++ opcode 'jbe' matched by 'j', usage 28 ++ src M: 0xc015cd3e ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd37 to 0xc015cd3e drop_through 0 bb_jmp[3] ++ new state c0728768 ++ ++This state is different from any states already saved, clone to a new entry. ++ ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd38 to 0xc015cd39 drop_through 1 bb_jmp[12] ++ reuse bb_jmp[3] ++ ++Basic block 0 drops through to basic block 1, treat it as an implicit transfer ++of control. The state is the same as the previous jump instruction so reuse it ++and bump the reference count. ++ ++That ends basic block 0, now pick the next block in the list that (a) needs to ++be scanned and (b) has all its input states defined. In this case bb[1]. ++ ++ bb[1] ++ ++bb[1] starts at 0xc015cd39 and has two paths that transfer control to it. ++bb_jmp[1] from an explicit jump at 0xc015cd1b and a drop through at bb_jmp[12]. ++Where there is more than one input state we have to merge them and reconcile the ++final value. ++ ++ first state c07286b8 ++ ++The first input state is stored at c07286b8. Looking back through the trace we ++find that entry associated with bb_jmp[0], not bb_jmp[1] as expected. However ++bb_jmp[1] reused the state that was stored for bb_jmp[0] so all is well. ++ ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = rsi ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++The first state for bb[1]. ++ ++ merging state c0728768 ++ ++Now merge the second state, which is held at c0728768. ++ ++ rbx = undefined ++ rsi = undefined ++ ++The two states disagree on the values being tracked in rbx and rsi. Compiler ++theory 101 says that if two or more paths to a basic block have different values ++for a register then that register cannot be relied on at the start of the block, ++so make it undefined. The same logic applies to memory locations. ++ ++ final state ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++After merging all the input states, this is the final starting state for bb[1]. ++Now track what bb[1] does to the state. ++ ++ '0xc015cd39 getname+0x51: mov $0x1000,%ebx' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0x1000 ++ dst R: %ebx base_rc 3 (rbx) ++ rbx = undefined ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd3d to 0xc015cd3e drop_through 1 bb_jmp[13] ++ reuse bb_jmp[3] ++ ++bb[1] is a single instruction which drops through to bb[2]. ++ ++ bb[2] ++ first state c0728768 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ merging state c0728768 ++ ++bb[2] has two inputs, both vertices are pointing to input state c0728768. ++Merging an entry with itself has no effect. ++ ++ '0xc015cd3e getname+0x56: mov %ebx,%ecx' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %ebx base_rc 3 (rbx) ++ dst R: %ecx base_rc 4 (rcx) ++ rcx = rbx (undefined) ++ '0xc015cd40 getname+0x58: mov %edi,%edx' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %edi base_rc 6 (rdi) ++ dst R: %edx base_rc 5 (rdx) ++ rdx = rdi (rax) ++ '0xc015cd42 getname+0x5a: mov 0xfffffff0(%ebp),%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src M: 0xfffffff0(%ebp) base_rc 8 (rbp) ++ dst R: %eax base_rc 2 (rax) ++ rax = *(rbp-0x10) (osp-0x14) rax = undefined ++ '0xc015cd45 getname+0x5d: call 0xc023dbb4 ' ++ opcode 'call' matched by 'call', usage 17 ++ src M: 0xc023dbb4 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = rax ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ rax = undefined ++ rcx = undefined ++ rdx = undefined ++ '0xc015cd4a getname+0x62: cmp $0x0,%eax' ++ opcode 'cmp' matched by 'cmp', usage 3 ++ src I: $0x0 ++ dst R: %eax base_rc 2 (rax) ++ '0xc015cd4d getname+0x65: jle 0xc015cd5a ' ++ opcode 'jle' matched by 'j', usage 28 ++ src M: 0xc015cd5a ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd4d to 0xc015cd5a drop_through 0 bb_jmp[4] ++ reuse bb_jmp[3] ++ '0xc015cd4f getname+0x67: mov $0xffffffdc,%esi' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0xffffffdc ++ dst R: %esi base_rc 7 (rsi) ++ rsi = undefined ++ '0xc015cd54 getname+0x6c: cmp %ebx,%eax' ++ opcode 'cmp' matched by 'cmp', usage 3 ++ src R: %ebx base_rc 3 (rbx) ++ dst R: %eax base_rc 2 (rax) ++ '0xc015cd56 getname+0x6e: jae 0xc015cd60 ' ++ opcode 'jae' matched by 'j', usage 28 ++ src M: 0xc015cd60 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd56 to 0xc015cd60 drop_through 0 bb_jmp[5] ++ reuse bb_jmp[3] ++ '0xc015cd58 getname+0x70: jmp 0xc015cd71 ' ++ opcode 'jmp' matched by 'j', usage 28 ++ src M: 0xc015cd71 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd58 to 0xc015cd71 drop_through 0 bb_jmp[6] ++ reuse bb_jmp[3] ++ ++ bb[3] ++ first state c0728768 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++bb[3] only has one input, nothing to merge. ++ ++ '0xc015cd5a getname+0x72: je 0xc015cd76 ' ++ opcode 'je' matched by 'j', usage 28 ++ src M: 0xc015cd76 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd5a to 0xc015cd76 drop_through 0 bb_jmp[7] ++ reuse bb_jmp[3] ++ '0xc015cd5c getname+0x74: jge 0xc015cd71 ' ++ opcode 'jge' matched by 'j', usage 28 ++ src M: 0xc015cd71 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd5c to 0xc015cd71 drop_through 0 bb_jmp[8] ++ reuse bb_jmp[3] ++ '0xc015cd5e getname+0x76: mov %eax,%esi' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %eax base_rc 2 (rax) ++ dst R: %esi base_rc 7 (rsi) ++ rsi = rax (undefined) ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd5f to 0xc015cd60 drop_through 1 bb_jmp[14] ++ reuse bb_jmp[3] ++ ++ bb[5] ++ first state c0728768 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ merging state c0728768 ++ '0xc015cd71 getname+0x89: mov 0xfffffff0(%ebp),%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src M: 0xfffffff0(%ebp) base_rc 8 (rbp) ++ dst R: %eax base_rc 2 (rax) ++ rax = *(rbp-0x10) (osp-0x14) rax = undefined ++ '0xc015cd74 getname+0x8c: jmp 0xc015cd7d ' ++ opcode 'jmp' matched by 'j', usage 28 ++ src M: 0xc015cd7d ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd74 to 0xc015cd7d drop_through 0 bb_jmp[10] ++ reuse bb_jmp[3] ++ ++ bb[6] ++ first state c0728768 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ '0xc015cd76 getname+0x8e: mov $0xfffffffe,%esi' ++ opcode 'mov' matched by 'mov', usage 36 ++ src I: $0xfffffffe ++ dst R: %esi base_rc 7 (rsi) ++ rsi = undefined ++ '0xc015cd7b getname+0x93: jmp 0xc015cd60 ' ++ opcode 'jmp' matched by 'j', usage 28 ++ src M: 0xc015cd60 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd7b to 0xc015cd60 drop_through 0 bb_jmp[11] ++ reuse bb_jmp[3] ++ ++ bb[4] ++ first state c0728710 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ merging state c0728768 ++ rbx = undefined ++ merging state c0728768 ++ merging state c0728768 ++ ++bb[4] has 4 inputs, 3 of which have the same state. One one path (state ++c0728710) rbx is defined, on the others (c0728768) rbx is undefined so the final ++state has rbx as undefined. ++ ++ final state ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ '0xc015cd60 getname+0x78: mov 0xfffffff0(%ebp),%edx' ++ opcode 'mov' matched by 'mov', usage 36 ++ src M: 0xfffffff0(%ebp) base_rc 8 (rbp) ++ dst R: %edx base_rc 5 (rdx) ++ rdx = *(rbp-0x10) (osp-0x14) rdx = undefined ++ '0xc015cd63 getname+0x7b: mov 0xc04b2120,%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src M: 0xc04b2120 ++ dst R: %eax base_rc 2 (rax) ++ rax = undefined ++ '0xc015cd68 getname+0x80: call 0xc01521f1 ' ++ opcode 'call' matched by 'call', usage 17 ++ src M: 0xc01521f1 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ rax = undefined ++ rcx = undefined ++ rdx = undefined ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ '0xc015cd6d getname+0x85: mov %esi,%eax' ++ opcode 'mov' matched by 'mov', usage 36 ++ src R: %esi base_rc 7 (rsi) ++ dst R: %eax base_rc 2 (rax) ++ rax = rsi (undefined) ++ '0xc015cd6f getname+0x87: jmp 0xc015cd7d ' ++ opcode 'jmp' matched by 'j', usage 28 ++ src M: 0xc015cd7d ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ matched: from 0xc015cd6f to 0xc015cd7d drop_through 0 bb_jmp[9] ++ reuse bb_jmp[3] ++ ++ bb[7] ++ first state c07286b8 ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = rbx ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = rsi ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ merging state c0728768 ++ rbx = undefined ++ rsi = undefined ++ merging state c0728768 ++ final state ++ bb_reg_state c0728658 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ '0xc015cd7d getname+0x95: pop %edx' ++ opcode 'pop' matched by 'pop', usage 42 ++ src R: %edx base_rc 5 (rdx) ++ rdx = *(rsp+0x0) (osp-0x14) rdx = undefined ++ rsp osp offset -0x14 -> -0x10 ++ ++This instruction is a bit misleading. It looks like gcc is restoring a value ++from the stack *(osp-0x14) to edx, but we have no record of any useful data ++being stored at osp-0x14. In fact gcc is just reducing the stack pointer by 4 ++bytes to reverse the effect of 0xc015ccee: sub $0x4,%esp, the value popped into ++edx contains nothing useful. Why gcc does pop instead of add $0x4,%esp is a ++puzzle, probably some micro optimization. ++ ++ '0xc015cd7e getname+0x96: pop %ebx' ++ opcode 'pop' matched by 'pop', usage 42 ++ src R: %ebx base_rc 3 (rbx) ++ rbx = *(rsp+0x0) (osp-0x10) value rbx ++ rsp osp offset -0x10 -> -0xc ++ delete rbx from osp-0x10 slot 3 ++ ++This pop is doing something useful. It is restoring the original value of the ++preserved register ebx from stack, reversing 0xc015cced: push %ebx. Note that ++incrementing rsp from osp-0x10 to osp-0xc invalidates the data held in memory at ++osp-0x10, so we delete our record of it. ++ ++ '0xc015cd7f getname+0x97: pop %esi' ++ opcode 'pop' matched by 'pop', usage 42 ++ src R: %esi base_rc 7 (rsi) ++ rsi = *(rsp+0x0) (osp-0xc) value rsi ++ rsp osp offset -0xc -> -0x8 ++ delete rsi from osp-0xc slot 2 ++ '0xc015cd80 getname+0x98: pop %edi' ++ opcode 'pop' matched by 'pop', usage 42 ++ src R: %edi base_rc 6 (rdi) ++ rdi = *(rsp+0x0) (osp-0x8) value rdi ++ rsp osp offset -0x8 -> -0x4 ++ delete rdi from osp-0x8 slot 1 ++ ++Pop the other preserved registers, in reverse order to the push sequence at the ++start. ++ ++ '0xc015cd81 getname+0x99: pop %ebp' ++ opcode 'pop' matched by 'pop', usage 42 ++ src R: %ebp base_rc 8 (rbp) ++ rbp = *(rsp+0x0) (osp-0x4) value rbp ++ rsp osp offset -0x4 -> +0x0 ++ delete rbp from osp-0x4 slot 0 ++ ++Pop the previous frame pointer. ++ ++ '0xc015cd82 getname+0x9a: ret ' ++ opcode 'ret' matched by 'ret', usage 48 ++ ++When a ret instruction is executed, all the preserved registers must be back to ++their original value and the stack pointer must contain osp+0. ++bb_sanity_check() will complain and abort the backtrace if this is not true. No ++complaints here. ++ ++ bb_pass2: end bb_reg_params 1 bb_memory_params 0 ++ ++We identified one argument passed in a register (the read of rax at 0xc015ccf1) ++and no reference to memory locations above the stack frame. So we have one ++argument being passed in a register and no arguments being passed on stack. ++This matches ++ ++ char * getname(const char __user * filename) ++ ++ bb_pass2: bb_exit_state at 0xc015cd6d ++ bb_reg_state c07287c0 ++ rax = undefined ++ rbx = undefined ++ rcx = undefined ++ rdx = undefined ++ rdi = rax ++ rsi = undefined ++ rbp = osp-0x4 ++ rsp = osp-0x14 ++ slot 0 offset_address -0x4 rbp ++ slot 1 offset_address -0x8 rdi ++ slot 2 offset_address -0xc rsi ++ slot 3 offset_address -0x10 rbx ++ ++We told bb1 that the exit address from this function is 0xc015cd6d. The ++abstract state at this exit point was saved, it defines how we rollback the ++actual register values from the next function down the stack (kmem_cache_free) ++to get the actual register values on entry to this function (getname). See ++bb_actual_rollback() which updates bb_actual[]. ++ ++Looking at the exit state above, we see that rsp contains the abstracte value ++osp-0x14. It is a given that we have the actual value of rsp after the call ++from getname() to kmem_cache_free(), otherwise we would not have found the ++return address on stack and we would not be analysing getname(). Adding 0x14 ++(the delta from osp to rsp) to our current actual rsp gives us the actual value ++of osp on entry to getname(). ++ ++The main aim of doing all this work is to track the function arguments so we can ++print them if possible. getname() only has one argument which was passed in ++eax. According to the abstract exit state, the original value of rax is ++currently in rdi, so by looking at the actual value of rdi from the next stack ++frame down we are able to get the argument to getname(). ++ ++It is not always possible to get register arguments, gcc will only preserve ++input arguments as long as it needs them so there may be no saved copy of ++arguments that are passed in register. In this case, bt_print_one() prints ++"invalid". ++ ++If basic block analysis detected any arguments were passed on stack, their ++contents can now be extracted based on the known value of the stack pointer. ++bt_print_one() prints the arguments, if BT_ARGS is non-zero then any argument ++that might be a kernel address is printed as a symbol. ++ ++Once rsp has been rolled back to osp, we can calculate that actual address of ++the stack locations that contain useful data. The previous values of rbp, rdi, ++rsi and rbx are then copied from those locations into bb_actual[]. That gives ++the values for those registers at the exit point from the function that called ++getname(). Go up one level and repeat the analysis. ++ ++There are two references to rdi in the exit state, which can be confusing. ++ ++ rdi = rax ++ slot 1 offset_address -0x8 rdi ++ ++The first reference says that "register rdi contains the original value of rax", ++the second reference says that "*(osp-0x8) contains the original value of rdi". ++Do not confuse the two, one is by name, the other is by value. ++ ++getname() is a fairly simple function, it has no loops. __follow_mount is more ++complicated, it has loops as well as BUG() statements. ++ ++ [0]kdb> id __follow_mount ++ 0xc015be76 __follow_mount: push %ebp ++ 0xc015be77 __follow_mount+0x1: mov %esp,%ebp ++ 0xc015be79 __follow_mount+0x3: push %edi ++ 0xc015be7a __follow_mount+0x4: push %esi ++ 0xc015be7b __follow_mount+0x5: push %ebx ++ 0xc015be7c __follow_mount+0x6: mov %eax,%esi ++ 0xc015be7e __follow_mount+0x8: xor %edi,%edi ++ 0xc015be80 __follow_mount+0xa: jmp 0xc015beca __follow_mount+0x54 ++ 0xc015be82 __follow_mount+0xc: mov (%esi),%eax ++ 0xc015be84 __follow_mount+0xe: call 0xc0169664 lookup_mnt ++ 0xc015be89 __follow_mount+0x13: mov %eax,%ebx ++ 0xc015be8b __follow_mount+0x15: test %eax,%eax ++ 0xc015be8d __follow_mount+0x17: je 0xc015bed3 __follow_mount+0x5d ++ 0xc015be8f __follow_mount+0x19: mov 0x4(%esi),%eax ++ 0xc015be92 __follow_mount+0x1c: call 0xc0163de2 dput ++ 0xc015be97 __follow_mount+0x21: test %edi,%edi ++ 0xc015be99 __follow_mount+0x23: je 0xc015bead __follow_mount+0x37 ++ 0xc015be9b __follow_mount+0x25: mov (%esi),%eax ++ 0xc015be9d __follow_mount+0x27: test %eax,%eax ++ 0xc015be9f __follow_mount+0x29: je 0xc015bead __follow_mount+0x37 ++ 0xc015bea1 __follow_mount+0x2b: movl $0x0,0x64(%eax) ++ 0xc015bea8 __follow_mount+0x32: call 0xc016835b mntput_no_expire ++ 0xc015bead __follow_mount+0x37: mov %ebx,(%esi) ++ 0xc015beaf __follow_mount+0x39: mov 0x10(%ebx),%eax ++ 0xc015beb2 __follow_mount+0x3c: test %eax,%eax ++ 0xc015beb4 __follow_mount+0x3e: je 0xc015bec2 __follow_mount+0x4c ++ 0xc015beb6 __follow_mount+0x40: cmpl $0x0,(%eax) ++ 0xc015beb9 __follow_mount+0x43: jne 0xc015bebf __follow_mount+0x49 ++ 0xc015bebb __follow_mount+0x45: ud2a ++ 0xc015bebd __follow_mount+0x47: jmp 0xc015bebd __follow_mount+0x47 ++ 0xc015bebf __follow_mount+0x49: lock incl (%eax) ++ 0xc015bec2 __follow_mount+0x4c: mov %eax,0x4(%esi) ++ 0xc015bec5 __follow_mount+0x4f: mov $0x1,%edi ++ 0xc015beca __follow_mount+0x54: mov 0x4(%esi),%edx ++ 0xc015becd __follow_mount+0x57: cmpl $0x0,0x74(%edx) ++ 0xc015bed1 __follow_mount+0x5b: jne 0xc015be82 __follow_mount+0xc ++ 0xc015bed3 __follow_mount+0x5d: mov %edi,%eax ++ 0xc015bed5 __follow_mount+0x5f: pop %ebx ++ 0xc015bed6 __follow_mount+0x60: pop %esi ++ 0xc015bed7 __follow_mount+0x61: pop %edi ++ 0xc015bed8 __follow_mount+0x62: pop %ebp ++ 0xc015bed9 __follow_mount+0x63: ret ++ ++ [0]kdb> bb1 0xc015bed9 ++ bb_pass1: func_name __follow_mount func_start 0xc015be76 func_end 0xc015beda ++ bb_pass1: end ++ bb[0] start 0xc015be76 end 0xc015be80 drop_through 0 ++ bb[1] start 0xc015be82 end 0xc015beac drop_through 1 ++ bb[2] start 0xc015bead end 0xc015bebb drop_through 0 ++ ++Note that the ud2a (BUG) instruction at 0xc015bebb ends bb[2]. ++ ++ bb[3] start 0xc015bebd end 0xc015bebd drop_through 0 ++ ++bb[3] is peculiar, it is a jmp to itself, nothing else refers to 0xc015bebd and ++you cannot drop through from the previous instruction because ud2a kills the ++kernel. The i386 and x86_64 BUG() macros contain for(;;) after ud2a, for no ++good reason that I can see (is there old hardware that does not abort on ud2a?). ++ia64 and the generic versions of BUG() do not contain for(;;). for(;;) after ++ud2a generates a branch to itself than can never be executed. ++ ++ bb[4] start 0xc015bebf end 0xc015bec1 drop_through 1 ++ bb[5] start 0xc015bec2 end 0xc015bec9 drop_through 1 ++ bb[6] start 0xc015beca end 0xc015bed2 drop_through 1 ++ bb[7] start 0xc015bed3 end 0xc015bed9 drop_through 0 ++ bb_jmp[0] from 0xc015be80 to 0xc015beca drop_through 0 ++ bb_jmp[1] from 0xc015be8d to 0xc015bed3 drop_through 0 ++ bb_jmp[2] from 0xc015be99 to 0xc015bead drop_through 0 ++ bb_jmp[3] from 0xc015be9f to 0xc015bead drop_through 0 ++ bb_jmp[4] from 0xc015beb4 to 0xc015bec2 drop_through 0 ++ bb_jmp[5] from 0xc015beb9 to 0xc015bebf drop_through 0 ++ bb_jmp[6] from 0xc015bebd to 0xc015bebd drop_through 0 ++ bb_jmp[7] from 0xc015bed1 to 0xc015be82 drop_through 0 ++ bb_jmp[8] from 0xc015beac to 0xc015bead drop_through 1 ++ bb_jmp[9] from 0xc015bec1 to 0xc015bec2 drop_through 1 ++ bb_jmp[10] from 0xc015bec9 to 0xc015beca drop_through 1 ++ bb_jmp[11] from 0xc015bed2 to 0xc015bed3 drop_through 1 ++ ++Apart from bb[0] and the special case bb[3], all the other blocks are part of a ++cycle. That cycle goes bb[0] -> bb[6]. bb[6] -> {bb[1], bb[7]}. bb[1] -> ++{bb[2], bb[7]}. bb[2] -> {bb[4], bb[5]}. bb[4] -> bb[5]. bb[5] -> bb[6] and ++back to the start. bb[7] ends with 'ret', it does not feed into other blocks. ++ ++ bb_pass2: start ++ ++ bb_pass2_do_changed_blocks: allow_missing 0 ++ ++ bb[0] ++ [ ... detail snipped ... ] ++ matched: from 0xc015be80 to 0xc015beca drop_through 0 bb_jmp[0] ++ new state c07286d8 ++ ++ bb_pass2_do_changed_blocks: allow_missing 1 ++ ++Because of the cycle, only bb[0] can be processed with 0 missing inputs, all the ++other blocks have at least one missing input. Call bb_pass2_do_changed_blocks() ++again, this time allowing one missing input per blocks. ++ ++ bb[6] ++ first state c07286d8 ++ [ ... detail snipped ... ] ++ matched: from 0xc015bed2 to 0xc015bed3 drop_through 1 bb_jmp[11] ++ reuse bb_jmp[7] ++ ++ bb[7] ++ first state c0728730 ++ [ ... detail snipped ... ] ++ ++ bb[1] ++ first state c0728730 ++ [ ... detail snipped ... ] ++ matched: from 0xc015beac to 0xc015bead drop_through 1 bb_jmp[8] ++ reuse bb_jmp[1] ++ ++ bb[2] ++ first state c0728788 ++ [ ... detail snipped ... ] ++ merging state c0728788 ++ merging state c0728788 ++ [ ... detail snipped ... ] ++ matched: from 0xc015beb9 to 0xc015bebf drop_through 0 bb_jmp[5] ++ reuse bb_jmp[1] ++ ++ bb[4] ++ first state c0728788 ++ [ ... detail snipped ... ] ++ matched: from 0xc015bec1 to 0xc015bec2 drop_through 1 bb_jmp[9] ++ reuse bb_jmp[1] ++ ++ bb[5] ++ first state c0728788 ++ [ ... detail snipped ... ] ++ merging state c0728788 ++ [ ... detail snipped ... ] ++ matched: from 0xc015bec9 to 0xc015beca drop_through 1 bb_jmp[10] ++ reuse bb_jmp[1] ++ ++ bb[6] ++ first state c07286d8 ++ [ ... detail snipped ... ] ++ merging state c0728788 ++ matched: from 0xc015bed2 to 0xc015bed3 drop_through 1 bb_jmp[11] ++ reuse bb_jmp[1] ++ ++Note the rescan of bb[6]. The first scan only had one input from bb[0]. After ++traversing the cycle and getting back from bb[5] to bb[6], bb[6] now has more ++inputs so we need to rescan it. With the additional input, the output state ++from bb[6] has changed since the first scan, which means that every block it ++feeds has to be rescanned. bb[6] feeds bb[1] and bb[7]. ++ ++ bb[7] ++ first state c0728788 ++ [ ... detail snipped ... ] ++ merging state c0728788 ++ [ ... detail snipped ... ] ++ ++bb[7] being rescanned, this time it has data for both its inputs. ++ ++ bb[1] ++ first state c0728788 ++ [ ... detail snipped ... ] ++ matched: from 0xc015beac to 0xc015bead drop_through 1 bb_jmp[8] ++ no state change ++ ++bb[1] is being rescanned because the input from bb[6] has changed, however the ++rescan of bb[1] reports 'no state change', the changed input from bb[6] did not ++affect the final output state from bb[1]. Because the output state from bb[1] ++has not changed since the previous scan, there is no need to rescan bb[2], bb[7] ++or bb[4]. Since bb[4] is not being rescanned, there is no need to rescan bb[5] ++or bb[6] and the cycle is closed. +--- /dev/null ++++ b/Documentation/kdb/kdb.mm +@@ -0,0 +1,492 @@ ++.TH KDB 8 "September 21, 2005" ++.hy 0 ++.SH NAME ++Built-in Kernel Debugger for Linux - v4.4 ++.SH "Overview" ++This document describes the built-in kernel debugger available ++for linux. This debugger allows the programmer to interactively ++examine kernel memory, disassemble kernel functions, set breakpoints ++in the kernel code and display and modify register contents. ++.P ++A symbol table is included in the kernel image and in modules which ++enables all non-stack symbols (including static symbols) to be used as ++arguments to the kernel debugger commands. ++.SH "Getting Started" ++To include the kernel debugger in a linux kernel, use a ++configuration mechanism (e.g. xconfig, menuconfig, et. al.) ++to enable the \fBCONFIG_KDB\fP option. Additionally, for accurate ++stack tracebacks, it is recommended that the \fBCONFIG_FRAME_POINTER\fP ++option be enabled (if present). \fBCONFIG_FRAME_POINTER\fP changes the compiler ++flags so that the frame pointer register will be used as a frame ++pointer rather than a general purpose register. ++.P ++After linux has been configured to include the kernel debugger, ++make a new kernel with the new configuration file (a make clean ++is recommended before making the kernel), and install the kernel ++as normal. ++.P ++You can compile a kernel with kdb support but have kdb off by default, ++select \fBCONFIG_KDB_OFF\fR. Then the user has to explicitly activate ++kdb by booting with the 'kdb=on' flag or, after /proc is mounted, by ++.nf ++ echo "1" > /proc/sys/kernel/kdb ++.fi ++You can also do the reverse, compile a kernel with kdb on and ++deactivate kdb with the boot flag 'kdb=off' or, after /proc is mounted, ++by ++.nf ++ echo "0" > /proc/sys/kernel/kdb ++.fi ++.P ++When booting the new kernel, the 'kdb=early' flag ++may be added after the image name on the boot line to ++force the kernel to stop in the kernel debugger early in the ++kernel initialization process. 'kdb=early' implies 'kdb=on'. ++If the 'kdb=early' flag isn't provided, then kdb will automatically be ++invoked upon system panic or when the \fBPAUSE\fP key is used from the ++keyboard, assuming that kdb is on. Older versions of kdb used just a ++boot flag of 'kdb' to activate kdb early, this is no longer supported. ++.P ++KDB can also be used via the serial port. Set up the system to ++have a serial console (see \fIDocumentation/serial-console.txt\fP), you ++must also have a user space program such as agetty set up to read from ++the serial console. ++The control sequence \fBKDB\fP on the serial port will cause the ++kernel debugger to be entered, assuming that kdb is on, that some ++program is reading from the serial console, at least one cpu is ++accepting interrupts and the serial console driver is still usable. ++.P ++\fBNote:\fR\ When the serial console sequence consists of multiple ++characters such as KDB then all but the last character are passed ++through to the application that is reading from the serial console. ++After exiting from kdb, you should use backspace to delete the rest of ++the control sequence. ++.P ++You can boot with kdb activated but without the ability to enter kdb ++via any keyboard sequence. ++In this mode, kdb will only be entered after a system failure. ++Booting with kdb=on-nokey will activate kdb but ignore keyboard ++sequences that would normally drop you into kdb. ++kdb=on-nokey is mainly useful when you are using a PC keyboard and your ++application needs to use the Pause key. ++You can also activate this mode by ++.nf ++ echo "2" > /proc/sys/kernel/kdb ++.fi ++.P ++If the console is sitting on the login prompt when you enter kdb, then ++the login command may switch into upper case mode. ++This is not a kdb bug, it is a "feature" of login - if the userid is ++all upper case then login assumes that you using a TeleType (circa ++1960) which does not have lower case characters. ++Wait 60 seconds for login to timeout and it will switch back to lower ++case mode. ++.P ++\fBNote:\fR\ Your distributor may have chosen a different kdb ++activation sequence for the serial console. ++Consult your distribution documentation. ++.P ++If you have both a keyboard+video and a serial console, you can use ++either for kdb. ++Define both video and serial consoles with boot parameters ++.P ++.nf ++ console=tty0 console=ttyS0,38400 ++.fi ++.P ++Any kdb data entered on the keyboard or the serial console will be echoed ++to both. ++.P ++If you are using a USB keyboard then kdb commands cannot be entered ++until the kernel has initialised the USB subsystem and recognised the ++keyboard. ++Using kdb=early with a USB keyboard will not work, the USB subsystem is ++initialised too late. ++.P ++While kdb is active, the keyboard (not serial console) indicators may strobe. ++The caps lock and scroll lock lights will turn on and off, num lock is not used ++because it can confuse laptop keyboards where the numeric keypad is mapped over ++the normal keys. ++On exit from kdb the keyboard indicators will probably be wrong, they will not match the kernel state. ++Pressing caps lock twice should get the indicators back in sync with ++the kernel. ++.SH "Basic Commands" ++There are several categories of commands available to the ++kernel debugger user including commands providing memory ++display and modification, register display and modification, ++instruction disassemble, breakpoints and stack tracebacks. ++Any command can be prefixed with '-' which will cause kdb to ignore any ++errors on that command, this is useful when packaging commands using ++defcmd. ++A line whose first non-space character is '#' is printed and ignored. ++.P ++The following table shows the currently implemented standard commands, ++these are always available. Other commands can be added by extra ++debugging modules, type '?' at the kdb prompt to get a list of all ++available commands. ++.DS ++.TS ++box, center; ++l | l ++l | l. ++Command Description ++_ ++bc Clear Breakpoint ++bd Disable Breakpoint ++be Enable Breakpoint ++bl Display breakpoints ++bp Set or Display breakpoint ++bph Set or Display hardware breakpoint ++bpa Set or Display breakpoint globally ++bpha Set or Display hardware breakpoint globally ++bt Stack backtrace for current process ++btp Stack backtrace for specific process ++bta Stack backtrace for all processes ++btc Cycle over all live cpus and backtrace each one ++cpu Display or switch cpus ++dmesg Display system messages ++defcmd Define a command as a set of other commands ++ef Print exception frame ++env Show environment ++go Restart execution ++handlers Control the display of IA64 MCA/INIT handlers ++help Display help message ++id Disassemble Instructions ++kill Send a signal to a process ++ll Follow Linked Lists ++lsmod List loaded modules ++md Display memory contents ++mdWcN Display memory contents with width W and count N. ++mdp Display memory based on a physical address ++mdr Display raw memory contents ++mds Display memory contents symbolically ++mm Modify memory contents, words ++mmW Modify memory contents, bytes ++per_cpu Display per_cpu variables ++pid Change the default process context ++ps Display process status ++reboot Reboot the machine ++rd Display register contents ++rm Modify register contents ++rq Display runqueue for one cpu ++rqa Display runqueue for all cpus ++set Add/change environment variable ++sr Invoke SysReq commands ++ss Single step a cpu ++ssb Single step a cpu until a branch instruction ++stackdepth Print the stack depth for selected processes ++summary Summarize the system ++.TE ++.DE ++.P ++Some commands can be abbreviated, such commands are indicated by a ++non-zero \fIminlen\fP parameter to \fBkdb_register\fP; the value of ++\fIminlen\fP being the minimum length to which the command can be ++abbreviated (for example, the \fBgo\fP command can be abbreviated ++legally to \fBg\fP). ++.P ++If an input string does not match a command in the command table, ++it is treated as an address expression and the corresponding address ++value and nearest symbol are shown. ++.P ++Some of the commands are described here. ++Information on the more complicated commands can be found in the ++appropriate manual pages. ++.TP 8 ++cpu ++With no parameters, it lists the available cpus. ++\&'*' after a cpu number indicates a cpu that did not respond to the kdb ++stop signal. ++\&'+' after a cpu number indicates a cpu for which kdb has some data, but ++that cpu is no longer responding to kdb, so you cannot switch to it. ++This could be a cpu that has failed after entering kdb, or the cpu may ++have saved its state for debugging then entered the prom, this is ++normal for an IA64 MCA event. ++\&'I' after a cpu number means that the cpu was idle before it entered ++kdb, it is unlikely to contain any useful data. ++\&'F' after a cpu number means that the cpu is offline. ++There is currenly no way to distinguish between cpus that used to be ++online but are now offline and cpus that were never online, the kernel ++does not maintain the information required to separate those two cases. ++.I cpu ++followed by a number will switch to that cpu, you cannot switch to ++a cpu marked '*', '+' or 'F'. ++This command is only available if the kernel was configured for SMP. ++.TP 8 ++dmesg [lines] [adjust] ++Displays the system messages from the kernel buffer. ++If kdb logging is on, it is disabled by dmesg and is left as disabled. ++With no parameters or a zero value for 'lines', dmesg dumps the entire ++kernel buffer. ++If lines is specified and is positive, dmesg dumps the last 'lines' ++from the buffer. ++If lines is specified and is negative, dmesg dumps the first 'lines' ++from the buffer. ++If adjust is specified, adjust the starting point for the lines that ++are printed. ++When 'lines' is positive, move the starting point back by 'adjust' ++lines, when 'lines' is negative, move the starting point forward by ++\&'adjust' lines. ++.I dmesg -100 ++will dump 100 lines, from the start of the buffer. ++.I dmesg 100 ++will dump 100 lines, starting 100 lines from the end of the buffer, ++.I dmesg 100 100 ++will dump 100 lines, starting 200 lines from the end of the buffer. ++.I dmesg -100 100 ++will dump 100 lines, starting 100 lines from the start of the buffer. ++.TP 8 ++defcmd ++Defines a new command as a set of other commands, all input until ++.I endefcmd ++is saved and executed as a package. ++.I defcmd ++takes three parameters, the command name to be defined and used to ++invoke the package, a quoted string containing the usage text and a ++quoted string containing the help text for the command. ++When using defcmd, it is a good idea to prefix commands that might fail ++with '-', this ignores errors so the following commands are still ++executed. ++For example, ++.P ++.nf ++ defcmd diag "" "Standard diagnostics" ++ set LINES 2000 ++ set BTAPROMPT 0 ++ -id %eip-0x40 ++ -cpu ++ -ps ++ -dmesg 80 ++ -bt ++ -bta ++ endefcmd ++.fi ++.P ++When used with no parameters, defcmd prints all the defined commands. ++.TP 8 ++go ++Continue normal execution. ++Active breakpoints are reestablished and the processor(s) allowed to ++run normally. ++To continue at a specific address, use ++.I rm ++to change the instruction pointer then go. ++.TP 8 ++handlers ++Control the display of IA64 MCA/INIT handlers. ++The IA64 MCA/INIT handlers run on separate tasks. ++During an MCA/INIT event, the active tasks are typically the handlers, ++rather than the original tasks, which is not very useful for debugging. ++By default, KDB hides the MCA/INIT handlers so commands such as ps and ++btc will display the original task. ++You can change this behaviour by using ++.I handlers show ++to display the MCA/INIT handlers instead of the original tasks or use ++.I handlers hide ++(the default) to hide the MCA/INIT handlers and display the original ++tasks. ++.I handlers status ++will list the address of the handler task and the original task for ++each cpu. ++\fBNote:\fR\ If the original task was running in user space or it ++failed any of the MCA/INIT verification tests then there is no original ++task to display. ++In this case, the handler will be displayed even if ++.I handlers hide ++is set and ++.I handlers status ++will not show an original task. ++.TP 8 ++id ++Disassemble instructions starting at an address. ++Environment variable IDCOUNT controls how many lines of disassembly ++output the command produces. ++.TP 8 ++kill ++Internal command to send a signal (like kill(1)) to a process. ++kill -signal pid. ++.TP 8 ++lsmod ++Internal command to list modules. ++This does not use any kernel nor user space services so can be used at any time. ++.TP 8 ++per_cpu [] [] ++Display the values of a per_cpu variable, the variable_name is ++specified without the \fIper_cpu__\fR prefix. ++Length is the length of the variable, 1-8, if omitted or 0 it defaults ++to the size of the machine's register. ++To display the variable on a specific cpu, the third parameter is the ++cpu number. ++When the third parameter is omitted, the variable's value is printed ++from all cpus, except that zero values are suppressed. ++For each cpu, per_cpu prints the cpu number, the address of the ++variable and its value. ++.TP 8 ++pid ++Change the current process context, with no parameters it displays the ++current process. ++The current process is used to display registers, both kernel and user ++space. ++It is also used when dumping user pages. ++.I pid R ++resets to the original process that was running when kdb was entered. ++This command is useful if you have been looking at other processes and/or ++cpus and you want to get back to the original process. ++It does not switch cpus, it only resets the context to the original process. ++.TP 8 ++reboot ++Reboot the system, with no attempt to do a clean close down. ++.TP 8 ++rq ++Display the runqueues for the specified cpu. ++.TP 8 ++rqa ++Display the runqueues for all cpus. ++.TP 8 ++stackdepth ++Print the stack usage for processes using more than the specified ++percentage of their stack. ++If percentage is not supplied, it defaults to 60. ++This command is only implemented on i386 and ia64 architectures, ++patches for other architectures will be gratefully accepted. ++.TP 8 ++summary ++Print a summary of the system, including the time (no timezone is ++applied), uname information and various critical system counters. ++.SH INITIAL KDB COMMANDS ++kdb/kdb_cmds is a plain text file where you can define kdb commands ++which are to be issued during kdb_init(). One command per line, blank ++lines are ignored, lines starting with '#' are ignored. kdb_cmds is ++intended for per user customization of kdb, you can use it to set ++environment variables to suit your hardware or to set standard ++breakpoints for the problem you are debugging. This file is converted ++to a small C object, compiled and linked into the kernel. You must ++rebuild and reinstall the kernel after changing kdb_cmds. This file ++will never be shipped with any useful data so you can always override ++it with your local copy. Sample kdb_cmds: ++.P ++.nf ++# Initial commands for kdb, alter to suit your needs. ++# These commands are executed in kdb_init() context, no SMP, no ++# processes. Commands that require process data (including stack or ++# registers) are not reliable this early. set and bp commands should ++# be safe. Global breakpoint commands affect each cpu as it is booted. ++ ++set LINES=50 ++set MDCOUNT=25 ++set RECURSE=1 ++bp sys_init_module ++.fi ++.SH INTERRUPTS AND KDB ++When a kdb event occurs, one cpu (the initial cpu) enters kdb state. ++It uses a cross system interrupt to interrupt the ++other cpus and bring them all into kdb state. All cpus run with ++interrupts disabled while they are inside kdb, this prevents most ++external events from disturbing the kernel while kdb is running. ++.B Note: ++Disabled interrupts means that any I/O that relies on interrupts cannot ++proceed while kdb is in control, devices can time out. The clock tick ++is also disabled, machines will lose track of time while they are ++inside kdb. ++.P ++Even with interrupts disabled, some non-maskable interrupt events will ++still occur, these can disturb the kernel while you are debugging it. ++The initial cpu will still accept NMI events, assuming that kdb was not ++entered for an NMI event. Any cpu where you use the SS or SSB commands ++will accept NMI events, even after the instruction has finished and the ++cpu is back in kdb. This is an unavoidable side effect of the fact that ++doing SS[B] requires the cpu to drop all the way out of kdb, including ++exiting from the event that brought the cpu into kdb. Under normal ++circumstances the only NMI event is for the NMI oopser and that is kdb ++aware so it does not disturb the kernel while kdb is running. ++.P ++Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, ++even though the cpu is disabled for interrupts. I have not been able ++to track this one down but I suspect that the interrupt was pending ++when kdb was entered and it runs when kdb exits through IRET even ++though the popped flags are marked as cli(). If any ix86 hardware ++expert can shed some light on this problem, please notify the kdb ++maintainer. ++.SH RECOVERING FROM KDB ERRORS ++If a kdb command breaks and kdb has enough of a recovery environment ++then kdb will abort the command and drop back into mainline kdb code. ++This means that user written kdb commands can follow bad pointers ++without killing kdb. Ideally all code should verify that data areas ++are valid (using kdb_getarea) before accessing it but lots of calls to ++kdb_getarea can be clumsy. ++.P ++The sparc64 port does not currently provide this error recovery. ++If someone would volunteer to write the necessary longjmp/setjmp ++code, their efforts would be greatly appreciated. In the ++meantime, it is possible for kdb to trigger a panic by accessing ++a bad address. ++.SH DEBUGGING THE DEBUGGER ++kdb has limited support for debugging problems within kdb. If you ++suspect that kdb is failing, you can set environment variable KDBDEBUG ++to a bit pattern which will activate kdb_printf statements within kdb. ++See include/linux/kdb.h, KDB_DEBUG_FLAG_xxx defines. For example ++.nf ++ set KDBDEBUG=0x60 ++.fi ++activates the event callbacks into kdb plus state tracing in sections ++of kdb. ++.nf ++ set KDBDEBUG=0x18 ++.fi ++gives lots of tracing as kdb tries to decode the process stack. ++.P ++You can also perform one level of recursion in kdb. If environment ++variable RECURSE is not set or is 0 then kdb will either recover from ++an error (if the recovery environment is satisfactory) or kdb will ++allow the error to percolate, usually resulting in a dead system. When ++RECURSE is 1 then kdb will recover from an error or, if there is no ++satisfactory recovery environment, it will drop into kdb state to let ++you diagnose the problem. When RECURSE is 2 then all errors drop into ++kdb state, kdb does not attempt recovery first. Errors while in ++recursive state all drop through, kdb does not even attempt to recover ++from recursive errors. ++.SH KEYBOARD EDITING ++kdb supports a command history, which can be accessed via keyboard ++sequences. ++It supports the special keys on PC keyboards, control characters and ++vt100 sequences on a serial console or a PC keyboard. ++.P ++.DS ++.TS ++box, center; ++l | l | l l | l ++l | l | l l | l. ++PC Special keys Control VT100 key Codes Action ++_ ++Backspace ctrl-H Backspace 0x7f Delete character to the left of the cursor ++Delete ctrl-D Delete \\e[3~ Delete character to the right of the cursor ++Home ctrl-A Home \\e[1~ Go to start of line ++End ctrl-E End \\e[4~ Go to end of line ++Up arrow ctrl-P Up arrow \\e[A Up one command in history ++Down arrow ctrl-N Down arrow \\e[B Down one command in history ++Left arrow ctrl-B Left arrow \\e[D Left one character in current command ++Right arrow ctrl-F Right arrow \\e[C Right one character in current command ++.TE ++.DE ++.P ++There is no toggle for insert/replace mode, kdb editing is always in ++insert mode. ++Use delete and backspace to delete characters. ++.P ++kdb also supports tab completion for kernel symbols ++Type the start of a kernel symbol and press tab (ctrl-I) to complete ++the name ++If there is more than one possible match, kdb will append any common ++characters and wait for more input, pressing tab a second time will ++display the possible matches ++The number of matches is limited by environment variable DTABCOUNT, ++with a default of 30 if that variable is not set. ++.SH AUTHORS ++Scott Lurndal, Richard Bass, Scott Foehner, Srinivasa Thirumalachar, ++Masahiro Adegawa, Marc Esipovich, Ted Kline, Steve Lord, Andi Kleen, ++Sonic Zhang. ++.br ++Keith Owens - kdb maintainer. ++.SH SEE ALSO ++.P ++linux/Documentation/kdb/kdb_{bp,bt,env,ll,md,ps,rd,sr,ss}.man +--- /dev/null ++++ b/Documentation/kdb/kdb_bp.man +@@ -0,0 +1,197 @@ ++.TH BD 1 "July 12, 2004" ++.SH NAME ++bp, bpa, bph, bpha, bd, bc, be, bl \- breakpoint commands ++.SH SYNOPSIS ++bp \fIaddress-expression\fP ++.LP ++bpa \fIaddress-expression\fP ++.LP ++bph \fIaddress-expression\fP [\f(CWDATAR|DATAW|DATAA|IO\fP [\fIlength\fP]] ++.LP ++bpha \fIaddress-expression\fP [\f(CWDATAR|DATAW|DATAA|IO\fP [\fIlength\fP]] ++.LP ++bd \fIbreakpoint-number\fP ++.LP ++bc \fIbreakpoint-number\fP ++.LP ++be \fIbreakpoint-number\fP ++.LP ++bl ++.SH DESCRIPTION ++.hy 0 ++The ++.B bp ++family of commands are used to establish a breakpoint. ++The \fIaddress-expression\fP may be a numeric value (decimal or ++hexidecimal), a symbol name, a register name preceeded by a ++percent symbol '%', or a simple expression consisting of a ++symbol name, an addition or subtraction character and a numeric ++value (decimal or hexidecimal). ++.P ++\fBbph\fP and \fBbpha\fP will force the use of a hardware register, provided ++the processor architecture supports them. ++.P ++The \fIaddress-expression\fP may also consist of a single ++asterisk '*' symbol which indicates that the command should ++operate on all existing breakpoints (valid only for \fBbc\fP, ++\fBbd\fP and \fBbe\fP). ++.P ++Four different types of ++breakpoints may be set: ++ ++.TP 8 ++Instruction ++Causes the kernel debugger to be invoked from the debug exception ++path when an instruction is fetched from the specified address. This ++is the default if no other type of breakpoint is requested or when ++the \fBbp\fP command is used. ++ ++.TP 8 ++DATAR ++Causes the kernel debugger to be entered when data of length ++\fIlength\fP is read from or written to the specified address. ++This type of breakpoint must use a processor debug register which ++places an architecture dependent limit on the number of data and I/O ++breakpoints that may be established. On arm mode XScale platform ++(thumb mode is not supported yet), ++debugger is triggered by reading from the specified address. ++The \fBbph\fP or \fBbpha\fP commands must be used. ++ ++.TP 8 ++DATAW ++Enters the kernel debugger when data of length \fIlength\fP ++is written to the specified address. \fIlength\fP defaults ++to four bytes if it is not explicitly specified. ++Note that the processor may have already overwritten the prior data at ++the breakpoint location before the kernel debugger is invoked. ++The prior data should be saved before establishing the breakpoint, if ++required. On arm mode XScale platform, the debugger is triggered ++after having overwritten the specified address. ++The \fBbph\fP or \fBbpha\fP commands must be used. ++ ++.TP 8 ++IO ++Enters the kernel debugger when an \fBin\fP or \fBout\fP instruction ++targets the specified I/O address. The \fBbph\fP or \fBbpha\fP ++commands must be used. This type of breakpoint is not valid in ++arm mode XScale platform. This option is not valid in arm ++mode XScale platform. ++ ++.TP 8 ++DATAA ++Enters the kernel debugger after the data in specified address has ++been accessed (read or write), this option is only used in arm ++mode XScale platform. ++ ++.P ++The ++.B bpha ++command will establish a breakpoint on all processors in an ++SMP system. This command is not available in an uniprocessor ++kernel. ++.P ++The ++.B bd ++command will disable a breakpoint without removing it from the kernel ++debugger's breakpoint table. ++This can be used to keep breakpoints in the table without exceeding the ++architecture limit on breakpoint registers. ++A breakpoint-number of \fI*\fR will disable all break points. ++.P ++The ++.B be ++command will re-enable a disabled breakpoint. ++A breakpoint-number of \fI*\fR will enable all break points. ++.P ++The ++.B bc ++command will clear a breakpoint from the breakpoint table. ++A breakpoint-number of \fI*\fR will clear all break points. ++.P ++The ++.B bl ++command will list the existing set of breakpoints. ++.SH LIMITATIONS ++There is a compile time limit of sixteen entries in the ++breakpoint table at any one time. ++.P ++There are architecture dependent limits on the number of hardware ++breakpoints that can be set. ++.IP ix86 8 ++Four. ++.PD 0 ++.IP xscale 8 ++Two for insruction breakpoints and another two for data breakpoint. ++.PD 0 ++.IP ia64 8 ++? ++.PD 0 ++.IP sparc64 8 ++None. ++.PD 1 ++When issuing the "go" command after entering the debugger due to ++a breakpoint, kdb will silently perform a single step in order to ++reapply the breakpoint. The sparc64 port has some limitations on ++single stepping, which may limit where a breakpoint may be safely ++set. Please read the man page for \fBss\fP for more information. ++.SH ENVIRONMENT ++The breakpoint subsystem does not currently use any environment ++variables. ++.SH SMP CONSIDERATIONS ++Using ++.B bc ++is risky on SMP systems. ++If you clear a breakpoint when another cpu has hit that breakpoint but ++has not been processed then it may not be recognised as a kdb ++breakpoint, usually resulting in incorrect program counters and kernel ++panics. ++It is safer to disable the breakpoint with ++.BR bd , ++then ++.B go ++to let any other processors that are waiting on the breakpoint to ++clear. ++After all processors are clear of the disabled breakpoint then it is ++safe to clear it using ++.BR bc . ++.P ++Breakpoints which use the processor breakpoint registers ++are only established on the processor which is ++currently active. If you wish breakpoints to be universal ++use the ++.B bpa ++or ++.B bpha ++commands. ++.SH EXAMPLES ++.TP 8 ++bp schedule ++Sets an instruction breakpoint at the begining of the ++function \fBschedule\fP. ++ ++.TP 8 ++bp schedule+0x12e ++Sets an instruction breakpoint at the instruction located ++at \fBschedule\fP+\fI0x12e\fP. ++ ++.TP 8 ++bph ttybuffer+0x24 dataw ++Sets a data write breakpoint at the location referenced by ++\fBttybuffer\fP+\fI0x24\fP for a length of four bytes. ++ ++.TP 8 ++bph 0xc0254010 datar 1 ++Establishes a data reference breakpoint at address \fB0xc0254010\fP ++for a length of one byte. ++ ++.TP 8 ++bp ++List current breakpoint table. ++ ++.TP 8 ++bd 0 ++Disable breakpoint #0. ++ ++.TP 8 ++bc * ++Clear all breakpoints +--- /dev/null ++++ b/Documentation/kdb/kdb_bt.man +@@ -0,0 +1,315 @@ ++.TH BT 1 "July 20, 2007" ++.SH NAME ++bt \- Stack Traceback command ++.SH SYNOPSIS ++bt [ ] ++.LP ++btp ++.LP ++btt ++.LP ++bta [ DRSTZUIMA ] ++.LP ++btc [] ++.SH DESCRIPTION ++.hy 0 ++The ++.B bt ++command is used to print a stack traceback. It uses the ++current registers (see \fBrd\fP command) to determine ++the starting context and attempts to provide a complete ++stack traceback for the active thread. If \fIstack-frame-address\fP ++is supplied, it is assumed to point to the start of a valid ++stack frame and the stack will be traced back from that ++point. ++On x86 architecture, \fIstack-frame-address\fP must be the stack address of a ++saved \fB%eip\fP (\fB%rip\fP for x86_64) value from a \fBcall\fP instruction. ++.P ++The \fBbtp\fP command will analyze the stack for the given ++process identification (see the \fBps\fP command). ++\fBbtp\fP sets the current process for any following register display or update ++commands. ++.P ++The \fBbtt\fP command will analyze the stack for the given task ++structure. ++It is exactly equivalent to \fBbtp\fR on the pid extracted from the ++task structure. ++\fBbtt\fP sets the current process for any following register display or update ++commands. ++.P ++The \fBbta\fP command lists the stack for all processes in the desired ++state. ++Without any parameters, \fBbta\fP gives a backtrace for all useful processes. ++If a parameter is specified, it is a single string consisting of the ++letters D, R, S, T, Z, U, I, M and A in any order. ++See the kdb \fBps\fR man page for more details. ++\fBbta\fP does not change the current process. ++.P ++The \fBbtc\fP command will analyze the stack for the current process on ++a specified cpu or, if no cpu number is supplied, for the current ++process on all cpus. ++It does not switch to the other cpus, instead it uses the task ++structures to identify and issue \fBbtt\fR against the current task on ++the desired cpus. ++\fBbtc\fP with no arguments does not change the current process. ++\fBbtc\fP with a cpu number sets the current process for any following register ++display or update commands. ++.P ++For each function, the stack trace prints at least two lines. ++The first line contains four or five fields\ :- ++.IP * 3 ++The pointer to the stack frame. ++.PD 0 ++.IP * 3 ++The current address within this frame. ++.IP * 3 ++The address converted to a function name (actually the first non-local ++label which is <= the address). ++.IP * 3 ++The offset of the address within the function. ++.IP * 3 ++Any parameters to the function. ++.PD 1 ++.PP ++If environment variable NOSECT is set to 0 then the next line contains ++five fields which are designed to make it easier to match the trace ++against the kernel code\ :- ++.IP * 3 ++The module name that contains the address, "kernel" if it is in the ++base kernel. ++.PD 0 ++.IP * 3 ++The section name that contains the address (not available on 2.6 kernels). ++.IP * 3 ++The start address of the section (not available on 2.6 kernels). ++.IP * 3 ++The start address of the function. ++.IP * 3 ++The end address of the function (the first non-local label which is > ++the address). ++.PD 1 ++.PP ++If arguments are being converted to symbols, any argument which ++converts to a kernel or module address is printed as\ :- ++.IP * 3 ++Argument address. ++.PD 0 ++.IP * 3 ++The module name that contains the address, "kernel" if it is in the ++base kernel. ++.IP * 3 ++The symbol name the argument maps to. ++.IP * 3 ++The offset of the argument from the symbol, suppressed if 0. ++.PD 1 ++.P ++On architectures that use nested stacks, the backtrace will indicate a ++switch to a new stack by printing a line of equal signs and the type of ++stack. ++.SH MATCHING TRACE TO KERNEL CODE ++The command "objdump\ -S" will disassemble an object and, if the code ++was compiled with debugging (gcc flag -g), objdump will interleave the ++C source lines with the generated object. ++.PP ++A complete objdump of the kernel or a module is too big, normally you ++only want specific functions. ++By default objdump will only print the .text section but Linux uses ++other section names for executable code. ++When objdump prints relocatable objects (modules) it uses an offset of ++0 which is awkward to relate to the stack trace. ++The five fields which are printed for each function are designed to ++make it easier to match the stack trace against the kernel code using ++"objdump\ -S". ++.PP ++If the function is in the kernel then you need the section name, the ++start and end address of the function. The command is ++.PP ++.nf ++ objdump -S -j \\ ++ --start-address= \\ ++ --stop-address= \\ ++ /usr/src/linux/vmlinux ++.fi ++.PP ++If the function is in a module then you need the section name, the ++start address of the section, the start and end address of the ++function, the module name. The command is ++.PP ++.nf ++ objdump -S -j \\ ++ --adjust-vma= \\ ++ --start-address= \\ ++ --stop-address= \\ ++ /path/to/module/.o ++.fi ++.PP ++Unfortunately the 2.6 kernel does not provide the information required ++to locate the start of the section, which makes it very difficult to ++perform a reliable objdump on a module. ++.PP ++All addresses to objdump must be preceded by '0x' if they are in hex, ++objdump does not assume hex. ++The stack trace values are printed with leading '0x' to make it easy to ++run objdump. ++.SH LIMITATIONS ++Some architectures pass parameters in registers; ia64, x86_64 and i386 (with ++gcc flag -mregparm) fall into this category. ++On these architectures, the compiler may reuse input parameter registers as ++scratch space. ++For example, if a function takes a pointer to a structure and only accesses one ++field in that structure, the compiler may calculate the address of the field by ++adding a value to the input register. ++Once the input register has been updated, it no longer points to the ++start of the structure, but to some field within it. ++This also occurs with array pointers, the compiler may update the input pointer ++directly, leaving it pointing to some element of the array instead of the start ++of the array. ++Always treat parameter values that have been passed in registers with extreme ++suspicion, the compiler may have changed the value. ++The x86 backtrace can generally identify register parameters that are no longer ++valid, it prints them as 'invalid' instead of as a misleading number. ++The ia64 backtrace cannot identify parameter registers that have been ++overwritten. ++.P ++x86 architectures do not have full unwind information in the kernel. ++The KDB backtrace on x86 performs code decomposition and analysis to track the ++frames on the call stack (including stack switches) and to locate parameters. ++if this code analysis does not yield a valid result, KDB falls back on the old ++method of scanning the process stack and printing anything that looks like a ++kernel address. ++This old method is unreliable (it produces lots of false positives in the ++trace) and cannot track parameters at all, so no parameters are printed. ++If you get an x86 backtrace that falls back to the old method, read ++Documentation/kdb/bt_x86 and follow the steps listed to get diagnostics and to ++submit a bug report. ++.P ++There are a lot of functions in the kernel which take some arguments then do ++nothing except call another function with the same initial arguments, sometimes ++adding parameters at the end. For example\ :- ++.nf ++.na ++.ft CW ++ ++int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen, ++ void __user *oldval, size_t __user *oldlenp, ++ void __user *newval, size_t newlen) ++{ ++ int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp, ++ newval, newlen); ++ ++ if (ret == 1) ++ rt_cache_flush(0); ++ ++ return ret; ++} ++.ad b ++.fi ++.P ++ipv4_doint_and_flush_strategy() passes all its parameters directly to ++devinet_conf_sysctl() and makes no other use of those parameters, ++so ipv4_doint_and_flush_strategy is a 'pass through' function. ++The x86_64 calling sequence mandates that the first 6 parameters are passed in ++registers, with other parameters being passed on stack. ++The i386 calling sequence with -mregparm=3 (which is the default since about ++2.6.18) passes the first 3 parameters in registers, with other parameters being ++passed on stack. ++The only exceptions to the above calling sequence are for functions declared as ++asmlinkage or functions with a variable number of parameters (e.g. printk). ++.P ++When a pass through function calls another function, the first 3 (i386) or 6 ++(x86) parameters are already in their correct registers so the pass through ++function does not need to access the registers, which means that there are no ++references to these registers in the assembler code for the function. ++Users still want to see those arguments so the x86 backtrace has to assume that ++if\ :- ++.IP * 2 ++There are parameters passed on the stack and ++.IP * ++There are no code references to parameters passed in registers and ++.IP * ++The function is not a known asmlinkage or variadic function, then ++there are pass through register arguments. ++.P ++The x86 backtrace will warn you when it makes this assumption, like this\ :- ++.nf ++.na ++.ft CW ++ ++ has memory parameters but no register parameters. ++ Assuming it is a 'pass through' function that does not refer to its register ++ parameters and setting register parameters ++.ad b ++.fi ++.P ++The above 3 line message is only printed once, any future assumptions will ++print a shorter message. ++.P ++The \fBbt\fP command may print more or less arguments for a function ++than that function accepts. ++For x86, trailing arguments that are passed in but not used by the function ++will not be printed, resulting in fewer arguments than expected. ++For ia64, the hardware does not distinguish between input and local registers, ++some local registers may be printed as function arguments, resulting in more ++arguments than expected. ++.P ++On i386, 64 bit arguments (long long) occupy two adjacent 32 bit fields. ++There is no way for KDB to tell that this has occurred, so 64 bit arguments ++will be printed as two separate 32 bit arguments. ++.SH ENVIRONMENT ++The \fBBTARGS\fP environment variable governs the maximum number ++of arguments that are printed for any single function. ++On IA64 hardware, there is no difference between input and local registers, the ++first \fBBTARGS\fP registers are printed, up to the total limit of input plus ++local registers. ++Use a large value for \fBBTARGS\fP if you want to see the local registers on ++IA64. ++.PP ++If the \fBBTSP\fP environment variable is non-zero then the entire backtrace is ++printed, otherwise only the backtrace to the point of the last interrupt is ++printed. ++Printing the entire backtrace with 'set\ BTSP\ 1' is useful for diagnosing ++problems with the backtrace algorithms. ++In addition, when BTSP is non-zero, each backtrace frame may print extra lines ++giving information about the stack pointers, this is architecture specific. ++.PP ++If the \fBBTSYMARG\fP environment variable is non-zero then any ++arguments that fall within the kernel or modules are converted to symbols. ++.PP ++If the \fBNOSECT\fP environment variable is non-zero then the ++section information is suppressed. ++The default is NOSECT=1 so section data is suppressed; use set\ NOSECT=0 ++to see section information. ++.PP ++The \fBBTAPROMPT\fP environment variable controls the prompt after each ++process is listed by the \fBbta\fP command. If \fBBTAPROMPT\fP is not ++set or is non-zero then \fBbta\fP issues a prompt after each process is ++listed. If \fBBTAPROMPT\fP is set to zero then no prompt is issued and ++all processes are listed without human intervention. ++.PP ++\fBbt\fR with no parameters uses the \fBPS\fR environment variable, see ++the kdb \fBps\fR man page. ++.SH SMP CONSIDERATIONS ++None. ++.SH EXAMPLES ++.nf ++.na ++.ft CW ++[0]kdb> bt ++Stack traceback for pid 2873 ++0xc2efc0f0 2873 2836 1 0 R 0xc2efc2a0 *mount ++esp eip Function (args) ++0xf65a3c88 0xc0201f9f xfs_mount_validate_sb (0xf68bcb08, 0xf68bcb48, 0x0) ++0xf65a3c94 0xc0202f17 xfs_readsb+0x9d (0xf68bcb08, 0x0) ++0xf65a3cc0 0xc020a72e xfs_mount+0x21d (invalid, 0xf68bc2f0, 0x0) ++0xf65a3cf4 0xc021a84a vfs_mount+0x1a (invalid) ++0xf65a3d04 0xc021a721 xfs_fs_fill_super+0x76 (0xf76b6200, invalid, invalid) ++0xf65a3d78 0xc015ad81 get_sb_bdev+0xd4 (invalid, invalid, invalid, 0xf7257000, 0xc021a6ab, 0xf7594b38) ++ xfs_fs_get_sb has memory parameters but no register parameters. ++ Assuming it is a 'pass through' function that does not refer to its register ++ parameters and setting 3 register parameters ++0xf65a3db4 0xc0219a3a xfs_fs_get_sb+0x21 (invalid, invalid, invalid, 0xf7257000, 0xf7594b38) ++0xf65a3dcc 0xc015a992 vfs_kern_mount+0x41 (0xc04847e0, 0x0, 0xf68e9000, 0xf7257000) ++0xf65a3df0 0xc015aa11 do_kern_mount+0x38 (0xf6818000, 0x0, 0xf68e9000, 0xf7257000) ++0xf65a3e10 0xc016c8b0 do_mount+0x5df (0xf68e9000, 0xf65d6000, 0xf6818000, 0xc0ed0000, 0xf7257000) ++0xf65a3f90 0xc016c996 sys_mount+0x6f (0x8069b50, 0x8069b60, 0x8069b70, 0xc0ed0000, 0x8069ba0) ++0xf65a3fb4 0xc0102646 sysenter_past_esp+0x5f (invalid, invalid, invalid, 0x73, 0x246, 0xbfe52f50) +--- /dev/null ++++ b/Documentation/kdb/kdb_env.man +@@ -0,0 +1,46 @@ ++.TH ENV 1 "24 September 2000" ++.SH NAME ++env, set \- Environment manipulation commands ++.SH SYNOPSIS ++env ++.LP ++set \fIenvironment-variable\fP=\fIvalue\fP ++.SH DESCRIPTION ++The kernel debugger contains an environment which contains a series ++of name-value pairs. Some environment variables are known to the ++various kernel debugger commands and have specific meaning to the ++command; such are enumerated on the respective reference material. ++.P ++Arbitrary environment variables may be created and used with ++many commands (those which require an \fIaddress-expression\fP). ++.P ++The ++.B env ++command is used to display the current environment. ++.P ++The ++.B set ++command is used to alter an existing environment variable or ++establish a new environment variable. ++.SH LIMITATIONS ++There is a compile-time limit of 33 environment variables. ++.P ++There is a compile-time limit of 512 bytes (\fBKDB_ENVBUFSIZE\fP) ++of heap space available for new environment variables and for ++environment variables changed from their compile-time values. ++.SH ENVIRONMENT ++These commands explicitly manipulate the environment. ++.SH SMP CONSIDERATIONS ++None. ++.SH USER SETTINGS ++You can include "set" commands in kdb/kdb_cmds (see kdb.mm) to define ++your environment variables at kernel startup. ++.SH EXAMPLES ++.TP 8 ++env ++Display current environment settings. ++ ++.TP 8 ++set IDCOUNT=100 ++Set the number of lines to display for the \fBid\fP command ++to the value \fI100\fP. +--- /dev/null ++++ b/Documentation/kdb/kdb_ll.man +@@ -0,0 +1,134 @@ ++.TH LL 1 "19 April 1999" ++.SH NAME ++ll \- Linked List examination ++.SH SYNOPSIS ++ll ++.SH DESCRIPTION ++The ++.B ll ++command is used to execute a single command repetitively for ++each element of a linked list. ++.P ++The command specified by will be executed with a single ++argument, the address of the current element. ++.SH LIMITATIONS ++Be careful if using this command recursively. ++.SH ENVIRONMENT ++None. ++.SH SMP CONSIDERATIONS ++None. ++.SH EXAMPLES ++.nf ++.na ++.ft CW ++# cd modules ++# insmod kdbm_vm.o ++# Entering kdb on processor 0 due to PAUSE ++kdb> ps ++Task Addr Pid Parent cpu lcpu Tss Command ++0xc03de000 0000000001 0000000000 0000 0000 0xc03de2d4 init ++0xc0090000 0000000002 0000000001 0000 0000 0xc00902d4 kflushd ++0xc000e000 0000000003 0000000001 0000 0000 0xc000e2d4 kpiod ++0xc000c000 0000000004 0000000001 0000 0000 0xc000c2d4 kswapd ++0xc7de2000 0000000056 0000000001 0000 0000 0xc7de22d4 kerneld ++0xc7d3a000 0000000179 0000000001 0000 0000 0xc7d3a2d4 syslogd ++0xc7a7e000 0000000188 0000000001 0000 0000 0xc7a7e2d4 klogd ++0xc7a04000 0000000199 0000000001 0000 0000 0xc7a042d4 atd ++0xc7b84000 0000000210 0000000001 0000 0000 0xc7b842d4 crond ++0xc79d6000 0000000221 0000000001 0000 0000 0xc79d62d4 portmap ++0xc798e000 0000000232 0000000001 0000 0000 0xc798e2d4 snmpd ++0xc7904000 0000000244 0000000001 0000 0000 0xc79042d4 inetd ++0xc78fc000 0000000255 0000000001 0000 0000 0xc78fc2d4 lpd ++0xc77ec000 0000000270 0000000001 0000 0000 0xc77ec2d4 sendmail ++0xc77b8000 0000000282 0000000001 0000 0000 0xc77b82d4 gpm ++0xc7716000 0000000300 0000000001 0000 0000 0xc77162d4 smbd ++0xc7ee2000 0000000322 0000000001 0000 0000 0xc7ee22d4 mingetty ++0xc7d6e000 0000000323 0000000001 0000 0000 0xc7d6e2d4 login ++0xc778c000 0000000324 0000000001 0000 0000 0xc778c2d4 mingetty ++0xc78b6000 0000000325 0000000001 0000 0000 0xc78b62d4 mingetty ++0xc77e8000 0000000326 0000000001 0000 0000 0xc77e82d4 mingetty ++0xc7708000 0000000327 0000000001 0000 0000 0xc77082d4 mingetty ++0xc770e000 0000000328 0000000001 0000 0000 0xc770e2d4 mingetty ++0xc76b0000 0000000330 0000000001 0000 0000 0xc76b02d4 update ++0xc7592000 0000000331 0000000323 0000 0000 0xc75922d4 ksh ++0xc7546000 0000000338 0000000331 0000 0000 0xc75462d4 su ++0xc74dc000 0000000339 0000000338 0000 0000 0xc74dc2d4 ksh ++kdb> md 0xc74dc2d4 ++c74dc2d4: 00000000 c74de000 00000018 00000000 .....`MG........ ++c74dc2e4: 00000000 00000000 00000000 074de000 .............`M. ++c74dc2f4: c01123ff 00000000 00000000 00000000 #.@............ ++c74dc304: 00000000 00000000 c74dded0 00000000 ........P^MG.... ++[omitted] ++c74dc474: 00000000 00000000 00000000 00000000 ................ ++c74dc484: 00000000 c7c15d00 c77b0900 c026fbe0 .....]AG..{G`{&@ ++c74dc494: 00000000 c76c2000 00000000 00000000 ..... lG........ ++c74dc4a4: 00000000 00000000 00000000 c74dc4ac ............,DMG ++kdb> md 0xc026fbe0 ++c026fbe0: c0262b60 00000000 c7594940 c74de000 @HYG....@IYG.`MG ++[omitted] ++kdb> md 0xc0262b60 ++c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G ++kdb> ll c0262b60 12 md ++c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G ++c7bec360: c0266660 0804c000 0804d000 c7becb20 `f&@.@...P.. K>G ++c7becb20: c0266660 0804d000 08050000 c7bec3a0 `f&@.P...... C>G ++c7bec3a0: c0266660 40000000 40009000 c7bec420 `f&@...@...@ D>G ++c7bec420: c0266660 40009000 4000b000 c7bec4a0 `f&@...@.0.@ D>G ++c7bec4a0: c0266660 4000b000 40010000 c7bec8e0 `f&@.0.@...@`H>G ++c7bec8e0: c0266660 40010000 400a1000 c7becbe0 `f&@...@...@`K>G ++c7becbe0: c0266660 400a1000 400a8000 c7becc60 `f&@...@...@`L>G ++c7becc60: c0266660 400a8000 400b4000 c7952300 `f&@...@.@.@.#.G ++c7952300: c0266660 400b5000 400bc000 c79521c0 `f&@.P.@.@.@@!.G ++c79521c0: c0266660 400bc000 400bd000 c7bec6e0 `f&@.@.@.P.@`F>G ++c7bec6e0: c0266660 bffff000 c0000000 00000000 `f&@.p?...@.... ++kdb> ++kdb> ll c0262b60 12 vm ++struct vm_area_struct at 0xc0262b60 for 56 bytes ++vm_start = 0x8048000 vm_end = 0x804c000 ++page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 ++flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE ++struct vm_area_struct at 0xc7bec360 for 56 bytes ++vm_start = 0x804c000 vm_end = 0x804d000 ++page_prot = 0x25 avl_height = -31808 vm_offset = 0x3000 ++flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE ++struct vm_area_struct at 0xc7becb20 for 56 bytes ++vm_start = 0x804d000 vm_end = 0x8050000 ++page_prot = 0x25 avl_height = -28664 vm_offset = 0x0 ++flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc7bec3a0 for 56 bytes ++vm_start = 0x40000000 vm_end = 0x40009000 ++page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 ++flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE ++struct vm_area_struct at 0xc7bec420 for 56 bytes ++vm_start = 0x40009000 vm_end = 0x4000b000 ++page_prot = 0x25 avl_height = 30126 vm_offset = 0x8000 ++flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE ++struct vm_area_struct at 0xc7bec4a0 for 56 bytes ++vm_start = 0x4000b000 vm_end = 0x40010000 ++page_prot = 0x25 avl_height = 26853 vm_offset = 0x0 ++flags: READ MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc7bec8e0 for 56 bytes ++vm_start = 0x40010000 vm_end = 0x400a1000 ++page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 ++flags: READ EXEC MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc7becbe0 for 56 bytes ++vm_start = 0x400a1000 vm_end = 0x400a8000 ++page_prot = 0x25 avl_height = 30126 vm_offset = 0x90000 ++flags: READ WRITE MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc7becc60 for 56 bytes ++vm_start = 0x400a8000 vm_end = 0x400b4000 ++page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 ++flags: READ WRITE MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc7952300 for 56 bytes ++vm_start = 0x400b5000 vm_end = 0x400bc000 ++page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 ++flags: READ EXEC MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc79521c0 for 56 bytes ++vm_start = 0x400bc000 vm_end = 0x400bd000 ++page_prot = 0x25 avl_height = -16344 vm_offset = 0x6000 ++flags: READ WRITE MAYREAD MAYWRITE MAYEXEC ++struct vm_area_struct at 0xc7bec6e0 for 56 bytes ++vm_start = 0xbffff000 vm_end = 0xc0000000 ++page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 ++flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN ++kdb> +--- /dev/null ++++ b/Documentation/kdb/kdb_md.man +@@ -0,0 +1,136 @@ ++.TH MD 1 "August 4, 2004" ++.SH NAME ++md, mdWcN, mdr, mds, mm, mmW\- Memory manipulation commands ++.SH SYNOPSIS ++md [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] ++.LP ++md\fIW\fRc\fIn\fR [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] ++.LP ++mdp \fIphysical-address-expression\fP,\fIbytes\fP ++.LP ++mdr \fIaddress-expression\fP,\fIbytes\fP ++.LP ++mds [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] ++.LP ++mm \fIaddress-expression\fP \fInew-contents\fP ++.LP ++mm\fIW\fR \fIaddress-expression\fP \fInew-contents\fP ++.SH DESCRIPTION ++The ++.B md ++command is used to display the contents of memory. ++The \fIaddress-expression\fP may be a numeric value (decimal or ++hexidecimal), a symbol name, a register name preceeded by one or more ++percent symbols '%', an environment variable name preceeded by ++a currency symbol '$', or a simple expression consisting of a ++symbol name, an addition or subtraction character and a numeric ++value (decimal or hexidecimal). ++.P ++If an address is specified and the \fIline-count\fP or \fIradix\fP arguments ++are omitted, they default to the values of the \fBMDCOUNT\fP and \fBRADIX\fP ++environment variables respectively. If the \fBMDCOUNT\fP or \fBRADIX\fP ++environment variables are unset, the appropriate defaults will be used [see ++\fBENVIRONMENT\fP below]. If no address is specified then md resumes ++after the last address printed, using the previous values of count and ++radix. The start address is rounded down to a multiple of the ++BYTESPERWORD (md) or width (md\fIW\fR). ++.P ++md uses the current value of environment variable \fBBYTESPERWORD\fP to ++read the data. When reading hardware registers that require special ++widths, it is more convenient to use md\fIW\fRc\fIn\fR where \fIW\fR is ++the width for this command and \fRc\fIn\fR is the number of entries to ++read. For example, md1c20 reads 20 bytes, 1 at a time. To continue ++printing just type md, the width and count apply to following md ++commands with no parameters. \fBNote:\fR The count is the number of ++repeats of the width, unlike MDCOUNT which gives the number of md lines ++to print. ++.P ++The ++.B mdp ++command displays the contents of physical memory, starting at the ++specified physical address for the specified number of bytes. ++The address is preceded by 'phys'. ++.P ++The ++.B mdr ++command displays the raw contents of memory, starting at the specified ++address for the specified number of bytes. ++The data is printed in one line without a leading address and no ++trailing character conversion. ++.B mdr ++is intended for interfacing with external debuggers, it is of little ++use to humans. ++.P ++The ++.B mds ++command displays the contents of memory one word per line and ++attempts to correlate the contents of each word with a symbol ++in the symbol table. If no symbol is found, the ascii representation ++of the word is printed, otherwise the symbol name and offset from ++symbol value are printed. ++By default the section data is printed for kernel symbols. ++.P ++The ++.B mm ++and ++\fBmm\fIW\fR ++commands allow modification of memory. The bytes at the address ++represented by \fIaddress-expression\fP are changed to ++\fInew-contents\fP. \fInew-contents\fP is allowed to be an ++\fIaddress-expression\fP. ++.B mm ++changes a machine word, \fBmm\fIW\fR changes \fIW\fR bytes at that ++address. ++.SH LIMITATIONS ++None. ++.SH ENVIRONMENT ++.TP 8 ++MDCOUNT ++This environment variable (default=8) defines the number of lines ++that will be displayed by each invocation of the \fBmd\fP command. ++ ++.TP 8 ++RADIX ++This environment variable (default=16) defines the radix used to ++print the memory contents. ++ ++.TP 8 ++BYTESPERWORD ++This environment variable (default=4) selects the width of output ++data when printing memory contents. Select the value two to get ++16-bit word output, select the value one to get byte output. ++ ++.TP 8 ++LINES ++This environment variable governs the number of lines of output ++that will be presented before the kernel debugger built-in pager ++pauses the output. This variable only affects the functioning ++of the \fBmd\fP and \fBmds\fP if the \fBMDCOUNT\fP variable ++is set to a value greater than the \fBLINES\fP variable. ++ ++.TP 8 ++NOSECT ++If the \fBNOSECT\fP environment variable is non-zero then the ++section information is suppressed. ++The default is NOSECT=1 so section data is suppressed; use set\ NOSECT=0 ++to see section information. ++.SH SMP CONSIDERATIONS ++None. ++.SH EXAMPLES ++.TP 8 ++md %edx ++Display memory starting at the address contained in register \fB%edx\fP. ++ ++.TP 8 ++mds %esp ++Display stack contents symbolically. This command is quite useful ++in manual stack traceback. ++ ++.TP 8 ++mm 0xc0252110 0x25 ++Change the memory location at 0xc0252110 to the value 0x25. ++ ++.TP 8 ++md chrdev_table 15 ++Display 15 lines (at 16 bytes per line) starting at address ++represented by the symbol \fIchrdev_table\fP. +--- /dev/null ++++ b/Documentation/kdb/kdb_ps.man +@@ -0,0 +1,96 @@ ++.TH PS 1 "September 14, 2004" ++.SH NAME ++ps \- Display processes ++.SH SYNOPSIS ++ps [ DRSTCZEUIMA ] ++.SH DESCRIPTION ++The ++.B ps ++command displays the status of all processes in the desired state. ++This command does not take any locks (all cpus should be frozen while ++kdb is running) so it can safely be used to debug lock problems with ++the process table. ++.P ++Without any parameters, \fBps\fP displays all the interesting ++processes, excluding idle tasks and sleeping system daemons. ++If a parameter is specified, it is a single string consisting of the ++letters D, R, S, T, C, Z, E, U, I and M, in any order. ++Each letter selects processes in a specific state, when multiple ++letters are specified, a process will be displayed if it is in any of ++the specified states. ++The states are\ :- ++.P ++.DS ++.TS ++box, center; ++l | l ++l | l. ++D Uninterruptible sleep ++R Running ++S Interruptible sleep ++T Stopped ++C Traced ++Z Zombie ++E Dead ++U Unrunnable ++I Idle task ++M Sleeping system daemon ++A All ++.TE ++.DE ++.P ++For state R (running), the process may not be on a cpu at the moment, ++but it is ready to run. ++The header line above the backtrace contains '1' in the fourth field if ++the process is actually on a cpu. ++.P ++The idle task is run on each cpu when there is no work for that cpu to do. ++Unless the idle task is servicing an interrupt, there is no point in ++printing the idle task. ++An idle task that is not servicing a interrupt is marked as state I, ++while servicing an interrupt it is in state R. ++By default, idle tasks are not printed, use \fBps\ I\fR to print them. ++If the idle tasks are not being printed, the start of the \fBps\R ++output contains a list of which cpus are idle. ++.P ++Each cpu has one or more system daemons to handle per cpu work such as ++soft irqs. ++A system daemon (idenified by a NULL mm pointer) that is sleeping is ++marked as state M. ++These processes rarely have any useful data and generate a lot of ++output on large machines, so sleeping system daemons are not printed by ++default. ++Use \fBps\ M\fR to print them. ++.P ++At the start of the \fBps\fR output is a line giving the cpu status, ++see the kdb \fBcpu\fR command. ++.SH LIMITATIONS ++None. ++.SH ENVIRONMENT ++.TP 8 ++PS ++This environment variable (default=DRSTCZEU) is used when \fBps\fR ++is issued with no parameters. ++ ++.SH SMP CONSIDERATIONS ++None. ++.SH EXAMPLES ++.TP 8 ++\fBps\fR ++displays the useful tasks, suppressing idle tasks and sleeping ++system daemons. ++ ++.TP 8 ++\fBps\ RD\fR ++displays only tasks that are running or are in an uninterruptible ++sleep. ++ ++.TP 8 ++\fBps\ DRSTCZEUIM\fR ++displays all tasks. ++ ++.TP 8 ++\fBps\ A\fR ++displays all tasks. ++This is easier than remembering DRSTCZEUIM. ++ +--- /dev/null ++++ b/Documentation/kdb/kdb_rd.man +@@ -0,0 +1,170 @@ ++.TH RD 1 "September 20, 2005" ++.SH NAME ++rd, rm\- Register manipulation commands ++.SH SYNOPSIS ++rd [[c [n]]|d|u] ++.LP ++rm \fIregister-name\fP \fInew-contents\fP ++.LP ++ef
++.SH DESCRIPTION ++The ++.B rd ++command is used to display the contents of processor and coprocessor registers. ++Without any arguments, the rd command displays the contents of the general ++register set at the point at which the kernel debugger was entered. ++If the bt* or pid commands have been used to change the current process then ++.B rd ++and ++.B rm ++may not be able to display any registers. ++'n' argument is only used for XScale platform to identify the desired ++coprocessor number, while 'd' option is not valid for XScale platform. ++.P ++On IA32 and IA64, with the 'c' argument, the processor control registers ++%cr0, %cr1, %cr2 and %cr4 are displayed, while with the 'd' argument ++the processor debug registers are displayed. If the 'u' argument ++is supplied, the registers for the current task as of the last ++time the current task entered the kernel are displayed. ++.P ++On XScale, 'c' argument is used to display the ++all coprocessor control registers or specified coprocessor registers by ++argumnet 'n'. Argument 'u' is used to display the ++registers for the current task as of the last time the current task ++entered the kernel. Argument 'd' is not supported. ++.P ++On ix86, the ++.B rm ++command allows modification of a register. The following ++register names are valid: \fB%eax\fP, \fB%ebx\fP, \fB%ecx\fP, ++\fB%edx\fP, \fB%esi\fP, \fB%edi\fP, \fB%esp\fP, \fB%eip\fP, ++and \fB%ebp\fP. Note that if two '%' symbols are used ++consecutively, the register set displayed by the 'u' argument ++to the \fBrd\fP command is modified. ++.P ++The debug registers, \fBdr0\fP through \fBdr3\fP and both ++\fBdr6\fP and \fBdr7\fP can also be modified with the \fBrm\fP ++command. ++.P ++On sparc64, the valid registers are named \fB%g0\fP through ++\fB%g7\fP, \fB%l0\fP through \fB%l7\fP, \fB%o0\fP through ++\fB%o7\fP, and \fB%i0\fP through \fB%i7\fP, with the exceptions ++that \fB%o6\fP is called \fB%sp\fP and that \fB%i6\fP is called ++\fB%fp\fP. The registers \fB%tstate\fP, \fB%tpc\fP, \fB%tnpc\fP, ++\fB%y\fP, and \fB%fprs\fP provide state information at the time ++the system entered kdb. Additionally, when viewing registers, two ++convenience names are provided: \fB%®s\fP shows the ++address on the stack of the current registers, and \fB%csp\fP ++shows the current stack pointer within kdb itself. ++.P ++While on XScale, both the cpu registers and most coprocessor ++registers can be be modified. \fIregister-name\fP can be followings like ++r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, ++r15, cpsr to address cpu registers. For the coprocessor registers in XSacle, ++either alias name or \fICpcc[CRndd[CRmbb[Opaa]]]\fP can be used to address ++the register in coprocessor cc with CRn=dd, CRm=bb and opcode2=aa. All aa, bb, cc, dd can be ++1 or 2 decimal digitals, the default value is 0 when any of them is omitted. Name ++acc0_h and acc0_l are used to identify the high byte and ++low word of accumulator in coprocessor 0. ++.P ++On IA64, the parameter to ++.B rd ++can be d (debug registers), u (user registers at most recent entry to kernel), ++i (interrupt registers), %isr (current interrupt status), s (stacked ++registers), k (kernel registers). You can also specify these individual ++registers - ++psr, ++ifs, ++ip, ++unat, ++pfs, ++rsc, ++rnat, ++bsps, ++pr, ++ldrs, ++ccv, ++fpsr, ++b0, ++b6, ++b7, ++r1, ++r2, ++r3, ++r8, ++r9, ++r10, ++r11, ++r12, ++r13, ++r14, ++r15, ++r16, ++r17, ++r18, ++r19, ++r20, ++r21, ++r22, ++r23, ++r24, ++r25, ++r26, ++r27, ++r28, ++r29, ++r30, ++r31. ++.B rm ++can change any of the individual registers or the stacked registers. ++.P ++The ++.B ef ++command displays an exception frame at the specified address. ++.SH LIMITATIONS ++Currently the \fBrm\fP command will not allow modification of the ++control registers. ++.P ++Currently neither the \fBrd\fP command nor the \fBrm\fP command will ++display or modify the model specific registers on the Pentium ++and Pentium Pro families. ++.SH ENVIRONMENT ++None. ++.SH SMP CONSIDERATIONS ++None. ++.SH EXAMPLES ++.TP 8 ++rd ++Display general register set from kdb's current task. ++ ++.TP 8 ++rd c 0 ++Display coprocessor 0 registers. ++ ++.TP 8 ++rm %eax 0 ++Set the contents of \fB%eax\fP to zero. This will be the ++value of %eax when kdb returns from the condition which ++invoked it. ++ ++.TP 8 ++rm %%eax 0 ++Set the value of the \fB%eax\fP register to zero. This will ++be the value the user-mode application will see upon returning ++from the kernel. ++ ++.TP 8 ++rm %acc0_h 0 ++Set the contents of high byte of accumulator to zero. ++ ++.TP 8 ++rm dr0 0xc1287220 ++Set the value of the \fBdr0\fB register to \f(CW0xc1287220\fP. ++ ++.TP 8 ++rm %InVLD_BTB 0 ++Write 0 to coprocessor 15 register with CRn=7, CRm=5, opcode2=6. ++ ++.TP 8 ++rm %CP15CRn7CRm5Op6 0 ++Same with above. +--- /dev/null ++++ b/Documentation/kdb/kdb_sr.man +@@ -0,0 +1,68 @@ ++.TH SR 1 "7 October 2002" ++.SH NAME ++sr \- invoke sysrq commands from kdb ++.SH SYNOPSIS ++sr \fIx\fP ++.SH DESCRIPTION ++.hy 0 ++The ++.B sr ++command invokes the existing sysrq handler code in the kernel. ++This command takes a single character which is passed to sysrq ++processing, as if you had entered the sysrq key sequence followed by ++that character. ++.P ++.B Caveats: ++.P ++kdb will always call the sysrq code but sysrq may be disabled. ++If you expect to use sysrq functions during debugging then ++.IP "" ++echo "1" > /proc/sys/kernel/sysrq ++.P ++before starting the debug session. ++Alternatively issue ++.IP "" ++mm4 sysrq_enabled 1 ++.P ++during debugging. ++.P ++The sysrq code prints a heading using console loglevel 7 then reverts ++to the original loglevel for the rest of the sysrq processing. ++If the rest of the sysrq output is printed at a level below your ++current loglevel then you will not see the output on the kdb console, ++the output will only appear in the printk buffer. ++It is the user's responsibility to set the loglevel correctly if they ++want to see the sysrq output on the console. ++Issue ++.IP "" ++sr 7 ++.P ++before any other ++.B sr ++commands if you want to see the output on the console. ++You may even have to adjust the default message loglevel in order to ++see any output from ++.BR sr . ++See Documentation/sysctl/kernel.txt for details on setting console ++loglevels via /proc. ++You can also adjust the loglevel variables via kdb ++.BR mm ; ++on older kernels there are variables such as default_message_level, on ++newer kernels all the loglevel variables are in array console_printk, ++see kernel/printk.c for your kernel. ++.P ++Operations that require interrupt driven I/O can be invoked from kdb ++.BR sr , ++but they will not do anything until you type 'go' to exit from kdb ++(interrupts are disabled while in kdb). ++There is no guarantee that these operations will work, if the machine ++entered kdb because of an error then interrupt driven I/O may already ++be dead. ++Do not assume that ++.B sr\ s ++does anything useful. ++.P ++The sysrq handler uses locks and calls printk which also uses locks. ++If the sysrq handler or any of the sysrq functions have to wait for a ++lock then they will never return and kdb will appear to hang. ++Invoking sysrq code from kdb is inherently unsafe. +--- /dev/null ++++ b/Documentation/kdb/kdb_ss.man +@@ -0,0 +1,109 @@ ++.TH SS 1 "17 January 2002" ++.SH NAME ++ss, ssb \- Single Step ++.SH SYNOPSIS ++ss ++.LP ++ssb ++.SH DESCRIPTION ++The ++.B ss ++command is used to execute a single instruction and return ++to the kernel debugger. ++.P ++Both the instruction that was single-stepped and the next ++instruction to execute are printed. ++.P ++The \fBssb\fP command will execute instructions from the ++current value of the instruction pointer. Each instruction ++may be printed as it is executed, depending upon architecture; ++execution will stop at any instruction which would cause the flow ++of control to change (e.g. branch, call, interrupt instruction, ++return, etc.) ++.SH LIMITATIONS ++On sparc64, there are some circumstances where single-stepping ++can be dangerous. Do not single-step across an instruction which ++changes the interrupt-enable bit in %tstate. Do not single step ++through code which is invoked when entering or leaving the ++kernel, particularly any kernel entry code before %tl is set to ++0, or any kernel exit code after %tl is set to 1. ++.SH ENVIRONMENT ++None. ++.SH SMP CONSIDERATIONS ++Other processors are held in the kernel debugger when the instruction ++is traced. Single stepping though code that requires a lock which is ++in use by another processor is an exercise in futility, it will never ++succeed. ++.SH INTERRUPT CONSIDERATIONS ++When a kdb event occurs, one cpu (the initial cpu) enters kdb state. ++It uses a cross system interrupt to interrupt the ++other cpus and bring them all into kdb state. All cpus run with ++interrupts disabled while they are inside kdb, this prevents most ++external events from disturbing the kernel while kdb is running. ++.B Note: ++Disabled interrupts means that any I/O that relies on interrupts cannot ++proceed while kdb is in control, devices can time out. The clock tick ++is also disabled, machines will lose track of time while they are ++inside kdb. ++.P ++Even with interrupts disabled, some non-maskable interrupt events ++will still occur, these can disturb the kernel while you are ++debugging it. The initial cpu will still accept NMI events, ++assuming that kdb was not entered for an NMI event. Any cpu ++where you use the SS or SSB commands will accept NMI events, even ++after the instruction has finished and the cpu is back in kdb. ++This is an unavoidable side effect of the fact that doing SS[B] ++requires the cpu to drop all the way out of kdb, including ++exiting from the NMI event that brought the cpu into kdb. Under ++normal circumstances the only NMI event is for the NMI oopser and ++that is kdb aware so it does not disturb the kernel while kdb is ++running. ++.P ++Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, ++even though the cpu is disabled for interrupts. I have not been able ++to track this one down but I suspect that the interrupt was pending ++when kdb was entered and it runs when kdb exits through IRET even ++though the popped flags are marked as cli(). If any ix86 hardware ++expert can shed some light on this problem, please notify the kdb ++maintainer. ++.SH EXAMPLES ++.nf ++.na ++.ft CW ++kdb> bp gendisk_head datar 4 ++Data Access Breakpoint #0 at 0xc024ddf4 (gendisk_head) in dr0 is enabled on cpu 0 ++for 4 bytes ++kdb> go ++... ++[root@host /root]# cat /proc/partitions ++Entering kdb on processor 0 due to Debug Exception @ 0xc01845e3 ++Read/Write breakpoint #0 at 0xc024ddf4 ++[0]kdb> ssb ++sd_finish+0x7b: movzbl 0xc02565d4,%edx ++sd_finish+0x82: leal 0xf(%edx),%eax ++sd_finish+0x85: sarl $0x4,%eax ++sd_finish+0x88: movl 0xc0256654,%ecx ++sd_finish+0x8e: leal (%eax,%eax,4),%edx ++sd_finish+0x91: leal (%eax,%edx,2),%edx ++sd_finish+0x94: movl 0xc0251108,%eax ++sd_finish+0x99: movl %eax,0xffffffc(%ecx,%edx,4) ++sd_finish+0x9d: movl %ecx,0xc0251108 ++sd_finish+0xa3: xorl %ebx,%ebx ++sd_finish+0xa5: cmpb $0x0,0xc02565d4 ++[0]kdb> go ++[root@host /root]# ++ ++[0]kdb> ss ++sys_read: pushl %ebp ++SS trap at 0xc01274c1 ++sys_read+0x1: movl %esp,%ebp ++[0]kdb> ss ++sys_read+0x1: movl %esp,%ebp ++SS trap at 0xc01274c3 ++sys_read+0x3: subl $0xc,%esp ++[0]kdb> ss ++sys_read+0x3: subl $0xc,%esp ++SS trap at 0xc01274c6 ++sys_read+0x6: pushl %edi ++[0]kdb> ++ +--- /dev/null ++++ b/Documentation/kdb/slides +@@ -0,0 +1,1382 @@ ++#! /opt/cpg/bin/do-mgp ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%% ++%deffont "standard" tfont "comic.ttf" ++%deffont "thick" tfont "arialb.ttf" ++%deffont "typewriter" xfont "courier new-bold-r" ++%deffont "type2writer" xfont "arial narrow-bold-r" ++%% ++%% Default settings per each line numbers. ++%% ++#%default 1 leftfill, size 2, fore "black", back "LemonChiffon2", font "thick" ++%default 1 leftfill, size 2, fore "black", back "white", font "thick" ++%default 2 size 10, vgap 10, prefix " ", center ++%default 3 size 2, bar "gray70", vgap 10 ++%default 4 size 6, fore "black", vgap 30, prefix " ", font "standard", left ++%% ++%% Default settings that are applied to TAB-indented lines. ++%% ++%tab 1 size 4, vgap 35, prefix " ", icon arc "red" 40 ++%tab 2 size 4, vgap 20, prefix " ", icon delta3 "blue" 40 ++%tab 3 size 4, vgap 20, prefix " ", icon delta3 "green" 40 ++%% ++%% ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++KDB - Kernel Debugger ++ ++ ++ ++%size 7,center, font "thick" ++Introduction ++ ++And ++ ++Demonstration ++ ++ ++%size 3 ++ ++February 5, 2002 IBM Linux Technology Center Paul Dorwin ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++IBM Legal ++ ++ ++ IBM Legal requires this information: ++ ++%size 3 ++ ++ THE INFORMATION IN THE FOLLOWING PRESENTATION IS PREPARED ++ SOLELY FOR THE INFORMATION OF THE READER, AND COMES "AS IS" ++ AND WITHOUT WARRANTY OR REPRESENATION OF ANY KIND. ++ ++ ANY PARTY USING THE MATERIALS IN THIS PRESENTATION DOES SO ++ AT ITS OWN RISK LIABILITY AND THE PROVIDER OF THE MATERIALS ++ ACCEPTS NO RISK OR LIABILITY FOR SUCH USE OR RESULTING FROM ++ DISSEMINATION TO OR USE BY ANY OTHER PARTY ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Agenda ++ ++%size 5 ++ ++ Installing and Configuring KDB ++ ++ KDB Commands ++ ++ Scull Demo ++ ++ Setting Breakpoints ++ ++ Displaying Data Structures ++ ++ Kernel Data structures ++ ++ Take a walk through an IO operation ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Installing Configuring KDB ++ ++ ++ Install KDB patch. ++ Start with a clean source tree ++ Apply architecture specific patches ++ Obtain patch for your kernel version ++ see http://oss.sgi.com/projects/kdb/ ++ Apply the kdb patch ++ patch -p 1 -N -u -i /path/to/patch ++ Apply any other patches ++ Build and reboot on your kdb enabled kernel ++ Man pages can be found at Documentation/kdb ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Configuring KDB ++ ++ ++ Config kernel with the following options: ++ These are documented in Documentation/Configure.help ++ ++ CONFIG_KDB=y ++ Enable compilation of KDB in the kernel.. ++ Setting this also sets CONFIG_KALLSYMS=y. ++ CONFIG_KDB_MODULES=n ++ KDB may be extended, compiling kdb/modules. ++ CONFIG_KDB_OFF=n ++ y = KDB is disabled by default. ++ boot with kdb=on to enable at boot. ++ /proc/sys/kernel/kdb to enable/disable when system is up. ++ CONFIG_KALLSYMS=y ++ This causes all symbols to be exported. ++ CONFIG_FRAME_POINTER=y ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Invoking KDB ++ ++ ++ KDB can be invoked in the following ways: ++ ++ Early init with "kdb=early" lilo flag ++ Hits breakpoint prior to fork_init() (init/main.c) ++ ++ Serial console with CNTRL-A ++ ++ Console with PAUSE key ++ ++ When a pre-set breakpoint is hit ++ ++ On panic ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++KDB Commands ++ ++ ++ KDB environment ++ env Show environment variables ++ set Set environment variables ++ help Display Help Message ++ ? Display Help Message ++ ++ System related ++ sections List kernel and module sections ++ lsmod List loaded kernel modules ++ reboot Reboot the machine immediately ++ cpu Switch to new cpu ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++KDB Commands ++ ++ ++ Memory Manipulation ++ md Display Memory Contents ++ mdr Display Raw Memory ++ mds Display Symbolically ++ mm Modify Memory Contents ++ id Display Instructions ++ ++ Register Manipulation ++ rd Display Registers ++ rm Modify Registers ++ ef Display exception frame ++ ++ Stack ++ bt [] Stack traceback ++ btp Display stack for ++ bta Display all stacks ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++KDB Commands ++ ++ ++ Breakpoint ++ bc Clear Breakpoint ++ bd Disable Breakpoint ++ be Enable Breakpoint ++ bl [] Display breakpoints ++ bp [] Set/Display breakpoints ++ bpa [] Set/Display global breakpoints ++ bph [] Set hardware breakpoint ++ bpha [] Set global hardware breakpoint ++ bp* modifiers: ++ instruction - break on instruction fetch (default) ++ datar - break on read at vaddr ++ dataw - break on write at vaddr ++ IO - break on in or out op at vaddress ++ ++ Execution control ++ go [] Continue Execution ++ ss [<#steps>] Single Step ++ ssb Single step to branch/call ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++KDB Commands ++ ++ ++ Kernel structures ++ ll Traverse list and execute command ++ ps Display active task list ++ vm Display vm_area_struct ++ dentry Display interesting dentry stuff ++ filp Display interesting filp stuff ++ sh Show scsi_host ++ sd Show scsi_device ++ sc Show scsi_cmnd ++ kiobuf Display kiobuf ++ page Display page ++ inode Display inode ++ bh Display buffer head ++ inode_pages Display pages in an inode ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo ++ ++ ++ Objective ++ Find and display the data associated with a scull device ++ ++ The sequence of events ++ Populate the scull device with data ++ Identify the breakpoints ++ Set breakpoint in the device read function ++ Identify the data structure elements ++ Identify device structures used to track data ++ Display data structures containing the data ++ Show the usage of the filp command ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Populate Device ++ ++ ++ Obtain the code ++ Surf to http://examples.oreilly.com/linuxdrive2/ ++ Download the tarball ++ Untar it to /usr/src ++ ++ Build and install the module ++ cd /usr/src/ldd2-samples-1.0.1/scull ++ make ++ ./scull.init start ++ ++ Populate the scull device ++ cat main.c > /dev/scull0 ++ cat /dev/scull0 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Driver Details ++ ++ ++ cat /dev/scull0 ++ fd = ++%fore "blue", cont ++open ++%fore "black", cont ++("/dev/scull0", O_RDONLY); ++ Kernel finds the file_operations structure ++ Kernel then invokes the open function ++%fore "blue" ++ read ++%fore "black", cont ++(fd, buf, size); ++ Kernel finds the file_operations structure ++ Kernel then invokes the read function ++ ++ Scull device file operations structure ++ ++%font "typewriter", size 3 ++ struct file_operations scull_fops = { ++ llseek: scull_llseek, ++%fore "blue" ++ read: scull_read, ++%fore "black" ++ write: scull_write, ++ ioctl: scull_ioctl, ++%fore "blue" ++ open: scull_open, ++%fore "black" ++ release: scull_release, ++ }; ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Driver Details ++ ++%font "typewriter", size 3 ++ scull_open code ++%font "typewriter", size 3 ++ int ++%fore "blue", cont ++scull_open ++%fore "black", cont ++(struct inode *inode, struct file *filp) ++ { ++ Scull_Dev *dev; /* device information */ ++ int num = NUM(inode->i_rdev); ++ ++ ++ ++ dev = (Scull_Dev *)filp->private_data; ++ if (!dev) { ++ if (num >= scull_nr_devs) return -ENODEV; ++%fore "blue" ++ dev = &scull_devices[num]; ++ filp->private_data = dev; ++%fore "black" ++ } ++ ++ ++ ++ } ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Driver Details ++ ++%font "typewriter", size 3 ++ scull_read code ++%font "typewriter", size 3 ++ ssize_t ++%fore "blue", cont ++scull_read ++%fore "black", cont ++(struct file *filp, char *buf, size_t count, ++ loff_t *f_pos) ++ { ++ ++%fore "blue", cont ++ Scull_Dev *dev = filp->private_data; ++%fore "black", cont ++ /* the first listitem */ ++%fore "blue" ++ Scull_Dev *dptr; ++%fore "black" ++ int quantum = dev->quantum; ++ int qset = dev->qset; ++ int itemsize = quantum * qset; ++ if (down_interruptible(&dev->sem)) ++ return -ERESTARTSYS; ++ if (*f_pos + count > dev->size) ++ count = dev->size - *f_pos; ++ ++ /* find listitem, qset index, and offset in the quantum */ ++ item = (long)*f_pos / itemsize; ++ rest = (long)*f_pos % itemsize; ++ s_pos = rest / quantum; q_pos = rest % quantum; ++ ++ /* follow the list up to the right position */ ++%fore "blue" ++ dptr = scull_follow(dev, item); ++%fore "black" ++ ++ ++ ++ } ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Breakpoints ++ ++ ++%font "typewriter", size 3 ++ Determine where to set breakpoint ++%font "typewriter", size 3 ++%fore "blue" ++ dptr = scull_follow(dev, item); ++%fore "black" ++ ++%font "typewriter", size 3 ++ Disassemble scull_read ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++id scull_read ++%fore "black" ++ 0xf8c083b4 scull_read: push %ebp ++ 0xf8c083b5 scull_read+0x1:mov %esp,%ebp ++ 0xf8c083b7 scull_read+0x3:push %edi ++ ++ 0xf8c08465 scull_read+0xb1:sub $0x8,%esp ++%fore "blue" ++ 0xf8c08468 scull_read+0xb4:push %ecx ++ 0xf8c08469 scull_read+0xb5:push %esi ++ 0xf8c0846a scull_read+0xb6:call 0xf8c08364 scull_follow: ++%fore "black" ++ 0xf8c0846f scull_read+0xbb:mov %eax, ++%fore "blue", cont ++ %edx ++%fore "black" ++ 0xf8c08471 ++%fore "blue", cont ++scull_read+0xbd ++%fore "black", cont ++:add $0x10,%esp ++ ++ ++ Set breakpoint in driver read ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue",cont ++bp scull_read+0xbd ++%fore "black" ++ Instruction(i) BP #0 at 0xf8c08471 ([scull]scull_read+0xbd) ++ is enabled globally adjust 1 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Breakpoints ++ ++ ++%font "typewriter", size 3 ++ Restart the system ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++go ++%fore "black" ++ ++ Hit the Breakpoint ++%font "typewriter", size 3 ++ [root@elm3b77 root]# ++%fore "blue", cont ++cat /dev/scull0 ++%fore "black" ++ Instruction(i) breakpoint #0 at 0xf8c08471 (adjusted) ++ 0xf8c08471 scull_read+0xbd:int3 ++ Entering kdb (current=0xf73ec000, pid 1249) on processor 2 ++ due to Breakpoint @ 0xf8c08471 ++ ++ Display the registers ++%font "typewriter", size 3 ++ [2]kdb> ++%fore "blue", cont ++rd ++%fore "black" ++ eax = 0xf77d7b60 ebx = 0x00000000 ecx = 0x00000000 edx = ++%fore "blue", cont ++0xf77d7b60 ++%fore "black" ++ esi = ++%fore "blue", cont ++0xf77d7b60 ++%fore "black", cont ++ edi = 0x00001000 esp = 0xf7415f40 eip = 0xf8c08471 ++ ebp = 0xf7415f78 xss = 0x00000018 xcs = 0x00000010 eflags = 0x00000246 ++ xds = 0xf7590018 xes = 0x00000018 origeax = 0xffffffff ®s = 0xf7415f0c ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Data Structures ++ ++%font "typewriter", size 3 ++ Display the Scull_Dev structure ++%font "typewriter", size 3 ++ [2]kdb> ++%fore "blue", cont ++md 0xf77d7b60 2 ++%fore "black" ++ 0xf77d7b60 ++%fore "blue", cont ++f7400000 ++%fore "black", cont ++ 00000000 00000fa0 000003e8 ..@w.... ...h... ++ 0xf77d7b70 0000534e 00000000 00000000 00000000 NS.............. ++ ++ Scull Device Structure ++%font "typewriter", size 3 ++ typedef struct Scull_Dev { ++%fore "blue" ++ void **data; ++%fore "black" ++ struct Scull_Dev *next; /* next listitem */ ++ int quantum; /* the current quantum size */ ++ int qset; /* the current array size */ ++ unsigned long size; ++ devfs_handle_t handle; /* only used if devfs is there */ ++ unsigned int access_key; /* used by sculluid and scullpriv */ ++ struct semaphore sem; /* mutual exclusion semaphore */ ++ } Scull_Dev; ++%size 6 ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: Data Structures ++ ++ ++%font "typewriter", size 3 ++ Display the quantum set (dev->data) ++%font "typewriter", size 3 ++ [2]kdb> ++%fore "blue", cont ++md f7400000 2 ++%fore "black" ++ 0xf7400000 ++%fore "blue", cont ++f73ea000 ++%fore "black", cont ++ f73f1000 f740c000 f7ab4000 . >w..?w.@@w.@+w ++ 0xf7400010 f73ef000 f755b000 00000000 00000000 .p>w.0Uw........ ++ ++ Display the first quantum (dev->data[0]) ++%font "typewriter", size 3 ++ [2]kdb> ++%fore "blue", cont ++md f73ea000 ++%fore "black" ++ 0xf73ea000 200a2a2f 616d202a 632e6e69 202d2d20 /*. * main.c -- ++ 0xf73ea010 20656874 65726162 75637320 63206c6c the bare scull c ++ 0xf73ea020 20726168 75646f6d 200a656c 2a200a2a har module. *. * ++ 0xf73ea030 706f4320 67697279 28207468 32202943 Copyright (C) 2 ++ 0xf73ea040 20313030 73656c41 646e6173 52206f72 001 Alessandro R ++ 0xf73ea050 6e696275 6e612069 6f4a2064 6874616e ubini and Jonath ++ 0xf73ea060 43206e61 6562726f 2a200a74 706f4320 an Corbet. * Cop ++ 0xf73ea070 67697279 28207468 32202943 20313030 yright (C) 2001 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: filp command ++ ++ ++%font "typewriter", size 3 ++ Show filp usage - here is the scull_read prototype ++%font "typewriter", size 3 ++ ssize_t scull_read( ++%fore "blue", cont ++struct file *filp ++%fore "black", cont ++, char *buf, ++ size_t count, loff_t *f_pos); ++ Show the stack trace: ++%font "typewriter", size 3 ++[2]kdb> ++%fore "blue", cont ++bt ++%fore "black" ++ EBP EIP Function(args) ++ 0xee9dbf78 0xf8c08471 [scull]scull_read+0xbd ( ++%fore "blue", cont ++0xeaf6c0c0 ++%fore "black", cont ++, 0x804e128, ++ 0x1000, 0xeaf6c0e0, 0x804f000) ++ scull .text 0xf8c08060 0xf8c083b4 0xf8c084dc ++ 0xee9dbfbc 0xc0136278 sys_read+0x98 (0x3, 0x804e128, 0x1000, ... ++ kernel .text 0xc0100000 0xc01361e0 0xc01362b0 ++ 0xc010702b system_call+0x33 ++ kernel .text 0xc0100000 0xc0106ff8 0xc0107030 ++ And show the filp output ++%font "typewriter", size 3 ++ [2]kdb> ++%fore "blue", cont ++filp 0xeaf6c0c0 ++%fore "black" ++ name.name 0xe93889fc name.len 6 ++ File Pointer at 0xeaf6c0c0 ++ f_list.nxt = 0xe42deca0 f_list.prv = 0xf7e69070 ++%fore "blue" ++ f_dentry = 0xe93889a0 ++%fore "black", cont ++ f_op = 0xf8c0a200 ++ f_count = 2 f_flags = 0x8000 f_mode = 0x1 ++ f_pos = 0 f_reada = 0 f_ramax = 0 ++ f_raend = 0 f_ralen = 0 f_rawin = 0 ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Scull Demo: filp command ++ ++ ++%font "typewriter", size 3 ++ filp output - continued ++%font "typewriter", size 3 ++%fore "blue" ++ Directory Entry at 0xe93889a0 ++%fore "black" ++ d_name.len = 6 ++%fore "orange", cont ++d_name.name = 0xe93889fc ++%fore "black", cont ++> ++ d_count = 1 d_flags = 0x0 ++%fore "blue", cont ++d_inode = 0xe827b680 ++%fore "black" ++ d_hash.nxt = 0xc215aec8 d_hash.prv = 0xc215aec8 ++ d_lru.nxt = 0xe93889b8 d_lru.prv = 0xe93889b8 ++ d_child.nxt = 0xe89e1e80 d_child.prv = 0xe9388940 ++ d_subdirs.nxt = 0xe93889c8 d_subdirs.prv = 0xe93889c8 ++ d_alias.nxt = 0xe827b690 d_alias.prv = 0xe827b690 ++ d_op = 0x00000000 d_sb = 0xf7e69000 ++ ++%fore "blue" ++ Inode Entry at 0xe827b680 ++%fore "black" ++ i_mode = 0x21a4 i_nlink = 1 i_rdev = 0xfe00 ++ i_ino = 37182 i_count = 1 i_dev = 0x821 ++ i_hash.nxt = 0xc20e6be8 i_hash.prv = 0xc20e6be8 ++ i_list.nxt = 0xe827b2c8 i_list.prv = 0xe827b868 ++ i_dentry.nxt = 0xe93889d0 i_dentry.prv = 0xe93889d0 ++ ++ Check the filename (display d_name.name) ++%font "typewriter", size 3 ++ [2]kdb> ++%fore "orange", cont ++md 0xe93889fc 1 ++%fore "black" ++ 0xe93889fc 6c756373 0000306c 00000000 00000000 scull0.......... ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Kernel Structures ++ ++ ++ Objective ++ Show output from various kernel related kdb commands ++ ++ Sequence of events ++ Simple Program ++ Write a simple program which allocates memory and hangs ++ Show usage of the ps, vm, and ll commands ++ Walk an IO operation ++ Hit a breakpoint in qlogic driver (isp1020_queuecommand) ++ Show usage of scsi related commands (sc, sh, and sd) ++ Show usage of vm related commands (bh, page, inode, inode_pages) ++ ++ ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Simple program ++ ++%font "typewriter", size 3 ++ simple.c - simple program which allocates memory ++%font "typewriter", size 3 ++%fore "blue" ++ int foo_global[8192]; ++%fore "black" ++ main() ++ { ++ int * ++%fore "blue", cont ++foo_malloc; ++%fore "black" ++ int i; ++ foo_malloc = (int *)malloc(0x8192); ++ for(i = 0; i < 0x100; i++) { ++ foo_global[i] = 0xdead0000 | i; ++ foo_malloc[i] = 0xbeef0000 | i; ++ } ++ printf("foo_global at %x\n", (int)foo_global); ++ printf("foo_malloc at %x\n", (int)foo_malloc); ++ printf("sleep forever\n"); ++ sleep(2000000); ++ } ++ ++ simple output ++%font "typewriter", size 3 ++ [root@elm3b77 scull]# cc -o simple simple.c ++ [root@elm3b77 scull]# ./simple ++ foo_global at ++%fore "blue", cont ++8049780 ++%fore "black" ++ foo_malloc at ++%fore "blue", cont ++8051788 ++%fore "black" ++ sleep forever ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Simple Program ++ ++%font "typewriter", size 3 ++ Show the output of the ps command ++%font "typewriter", size 3 ++ Entering kdb (current=0xc2010000, pid 0) on processor 3 due to ++ Keyboard Entry ++ [3]kdb> ++%fore "blue", cont ++ps ++%fore "black" ++ Task Addr Pid Parent [*] cpu State Thread Command ++ 0xf7efe000 00000001 00000000 0 003 stop 0xf7efe370 init ++ 0xf7ef0000 00000002 00000001 0 001 stop 0xf7ef0370 keventd ++ 0xf7eec000 00000003 00000000 0 000 stop 0xf7eec370 ksoftirqd_CPU0 ++ 0xf7eea000 00000004 00000000 0 001 stop 0xf7eea370 ksoftirqd_CPU1 ++ 0xf7ee8000 00000005 00000000 0 002 stop 0xf7ee8370 ksoftirqd_CPU2 ++ 0xf7ee6000 00000006 00000000 0 003 stop 0xf7ee6370 ksoftirqd_CPU3 ++ ++ ++ ++ 0xf7b46000 00001006 00000737 0 003 stop 0xf7b46370 sshd ++ 0xf7ace000 00001007 00001006 0 000 stop 0xf7ace370 bash ++ 0xef06a000 00001066 00001007 0 003 stop 0xef06a370 su ++ 0xeef88000 00001067 00001066 0 000 stop 0xeef88370 bash ++ 0xeef64000 00001119 00000770 0 001 stop 0xeef64370 in.ftpd ++%fore "blue" ++ 0xeeeac000 ++%fore "black", cont ++ 00001138 00001067 0 001 stop 0xeeeac370 ++%fore "blue", cont ++simple ++%fore "black" ++ [3]kdb> ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Simple Program ++ ++%font "typewriter", size 3 ++ Display the task struct ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++md 0xeeeac000 ++%fore "black" ++ 0xeeeac000 00000001 00000000 00000000 c0000000 ................ ++ 0xeeeac010 c0339880 00000000 00000000 ffffffff ................ ++ 0xeeeac020 0000000a 00000000 00000000 ++%fore "blue", cont ++f7e10f00 ++%fore "black", cont ++ ..............aw ++ 0xeeeac030 00000001 ffffffff ffffffff 00000000 ................ ++ ++%font "typewriter", size 3 ++ Determine offset of mm_struct ptr in task_struct ++%font "typewriter", size 3 ++ struct task_struct { ++ [0] volatile long state; ++ [4] unsigned long flags; ++ [8] int sigpending; ++ [c] mm_segment_t addr_limit; ++ [10] struct exec_domain *exec_domain; ++ [14] volatile long need_resched; ++ [18] unsigned long ptrace; ++ [1c] int lock_depth; ++ [20] long counter; ++ [24] long nice; ++ [28] unsigned long policy; ++%fore "blue" ++ [2c] struct mm_struct *mm; ++%fore "black" ++ [30] int processor; ++ [34] unsigned long cpus_runnable, cpus_allowed; ++ ++ }; ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Simple Program ++ ++ ++%font "typewriter", size 3 ++ Display the mm_struct associated with simple process ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++md f7e10f00 ++%fore "black" ++ 0xf7e10f00 ++%fore "blue", cont ++e8357a80 ++%fore "black", cont ++ e8357978 f7ac77e0 eb15eac0 .z5hxy5h`w,w@j.k ++ 0xf7e10f10 00000001 00000002 0000000b 00000000 ................ ++ 0xf7e10f20 00000001 f7e10f24 f7e10f24 00000001 ................ ++ 0xf7e10f30 f7e35e70 eea7e8f0 08048000 0804862b ................ ++ 0xf7e10f40 0804962c 08049744 08051780 0805a000 ................ ++ 0xf7e10f50 bffffd10 bffffe00 bffffe09 bffffe09 ................ ++ 0xf7e10f60 bffffff3 0000005a 00000168 00000000 ................ ++ 0xf7e10f70 00000000 00000002 00000000 00000001 ................ ++ ++%font "typewriter", size 3 ++ Determine offset of the first vma in the process ++%font "typewriter", size 3 ++ struct mm_struct { ++%fore "blue" ++ struct vm_area_struct * mmap; ++%fore "black" ++ rb_root_t mm_rb; ++ struct vm_area_struct * mmap_cache; ++ ++ }; ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Simple Program ++ ++%font "typewriter", size 3 ++ Display the first vma using md ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++md e8357a80 ++%fore "black" ++ 0xe8357a80 f7e10f00 08048000 08049000 ++%fore "blue", cont ++e8727e00 ++%fore "black",cont ++ ..aw.........~rh ++ 0xe8357a90 00000025 00001875 e8727e18 00000001 %...u....~rh.... ++ ++ Display the first vma using vma ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++vma e8357a80 ++%fore "black" ++ struct vm_area_struct at 0xe8357a80 for 68 bytes ++ vm_start = 0x8048000 vm_end = 0x8049000 ++ page_prot = 0x25 ++ flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE ++%font "typewriter", size 3 ++ ++ Determine the offset to the vma list ++%font "typewriter", size 3 ++ struct vm_area_struct { ++ [0] struct mm_struct * vm_mm; ++ [4] unsigned long vm_start; ++ [8] unsigned long vm_end; ++%fore "blue" ++ [c] struct vm_area_struct *vm_next; ++%fore "black" ++ ++ }; ++ Display the next vma ++%font "typewriter", size 3 ++ [3]kdb> vma e8727e00 ++ struct vm_area_struct at 0xe8727e00 for 68 bytes ++ vm_start = 0x8049000 vm_end = 0x804a000 ++ page_prot = 0x25 ++ flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Simple Program ++ ++%font "typewriter", size 3 ++ Use the ll command to display the list of vma's ++%font "typewriter", size 3 ++ [3]kdb> ll e8357a80 0xc vma ++. ++ struct vm_area_struct at 0xe8357a80 for 68 bytes ++ vm_start = 0x8048000 vm_end = 0x8049000 ++ page_prot = 0x25 ++ flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE ++. ++ struct vm_area_struct at 0xe8727e00 for 68 bytes ++ vm_start = ++%fore "orange", cont ++0x8049000 ++%fore "black", cont ++ vm_end = ++%fore "orange", cont ++0x804a000 ++%fore "black" ++ page_prot = 0x25 ++ flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE ++. ++ struct vm_area_struct at 0xe8727c80 for 68 bytes ++ vm_start = ++%fore "blue", cont ++0x804a000 ++%fore "black", cont ++ vm_end = ++%fore "blue", cont ++0x805a000 ++%fore "black" ++ page_prot = 0x25 ++ flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC ++ ++ struct vm_area_struct at 0xe8357900 for 68 bytes ++ vm_start = 0xbfffe000 vm_end = 0xc0000000 ++ page_prot = 0x25 ++ flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN ++ ++ Match the vma to the displayed addresses ++%font "typewriter", size 3 ++ foo_global at ++%fore "orange", cont ++8049780 ++%fore "black" ++ foo_malloc at ++%fore "blue", cont ++8051788 ++%fore "black" ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++ Objective ++ Show usage of various scsi and vm related kdb commands ++ ++ Sequence: ++ Set a breakpoint in the scsi driver ++ Stops when queueing a command to the controller ++ Cause IO on an idle disk ++ Show various IO stack traces ++ Display the IO data structures ++ Display vm information about the data ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Set the breakpoint ++ ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++bp isp1020_queuecommand ++%fore "black" ++ Instruction(i) BP #0 at 0xc01ecfe0 (isp1020_queuecommand) ++ is enabled globally adjust 1 ++ ++%font "typewriter", size 3 ++ Create some activity on a previously unused disk ++ ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++go ++%fore "black" ++ [root@elm3b77 root]# ++%fore "blue", cont ++ls /rh62 ++%fore "black" ++ ++ Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) ++ 0xc01ecfe0 isp1020_queuecommand:int3 ++ ++ Entering kdb (current=0xf75ba000, pid 1181) on processor 3 due to ++ Breakpoint @ 0xc01ecfe0 ++ ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Show the stack. ++ This is a read of the /rh62 directory ++ ++%font "typewriter", size 3 ++ [1]kdb> ++%fore "blue", cont ++bt ++%fore "black" ++ EBP EIP Function(args) ++ 0xf75bbdf4 0xc01ecfe0 isp1020_queuecommand ++ 0xc01e2c77 scsi_dispatch_cmd+0x1f7 ++ 0xf75bbe24 0xc01e99b1 scsi_request_fn+0x2f1 ++ 0xf75bbe34 0xc01c84fd generic_unplug_device+0x2d ++ 0xf75bbe50 0xc011b3af __run_task_queue+0x5f ++ 0xf75bbe6c 0xc013a63c block_sync_page+0x1c ++ 0xf75bbe98 0xc0128127 __lock_page+0x77 ++ 0xf75bbea4 0xc0128178 lock_page+0x18 ++ 0xf75bbec8 0xc012a4b3 read_cache_page+0xc3 ++ 0xf75bbef4 0xc0168e23 ext2_get_page+0x23 ++ 0xf75bbf48 0xc0168fdd ext2_readdir+0xfd ++ 0xf75bbf68 0xc0143d2e vfs_readdir+0x7e ++ 0xf75bbfbc 0xc01442ed ++%fore "blue", cont ++sys_getdents64+0x4d ++%fore "black" ++ 0xc010702b system_call+0x33 ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Allow the operation to complete ++ ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++go ++%fore "black" ++ bench build etc lib mnt oldsys rh72 spv usr ++ bin data h linux mnt1 opt root test var ++ boot dev home lost+found mnt2 proc sbin tmp ++ ++%font "typewriter", size 3 ++ Force some more activity ++ ++%font "typewriter", size 3 ++ [root@elm3b77 root]# ++%fore "blue", cont ++cd /rh62/tmp ++%fore "black" ++ Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) ++ 0xc01ecfe0 isp1020_queuecommand:int3 ++ ++ Entering kdb (current=0xf768a000, pid 981) on processor 3 due to ++ Breakpoint @ 0xc01ecfe0 ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Show the stack. ++ This is an inode read for /rh62/tmp ++ ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++bt ++%fore "black" ++ EBP EIP Function(args) ++ 0xf768bd68 0xc01ecfe0 isp1020_queuecommand ++ 0xc01e2c77 scsi_dispatch_cmd+0x1f7 ++ 0xf768bd98 0xc01e99b1 scsi_request_fn+0x2f1 ++ 0xf768bda8 0xc01c84fd generic_unplug_device+0x2d ++ 0xf768bdc4 0xc011b3af __run_task_queue+0x5f ++ 0xf768bdfc 0xc0137216 __wait_on_buffer+0x56 ++ 0xf768be1c 0xc0138600 bread+0x50 ++ 0xf768be5c 0xc016b684 ext2_read_inode+0x114 ++ 0xf768bf0c 0xc013fbec real_lookup+0x7c ++ 0xf768bf78 0xc014035d link_path_walk+0x5ad ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Create a new file, causing yet more disk activity ++ ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++go ++%fore "black" ++ ++ [root@elm3b77 tmp]# ++%fore "blue", cont ++echo "Hello linux reading group" > j1;sync ++%fore "black" ++ ++ Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) ++ 0xc01ecfe0 isp1020_queuecommand:int3 ++ ++ Entering kdb (current=0xf768a000, pid 981) on processor 3 due to ++ Breakpoint @ 0xc01ecfe0 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Show the stack ++ This is an inode read in response to the open ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++bt ++%fore "black" ++ EBP EIP Function(args) ++ 0xf768bd78 0xc01ecfe0 isp1020_queuecommand ++ 0xc01e2c77 scsi_dispatch_cmd+0x1f7 ++ 0xf768bda8 0xc01e99b1 scsi_request_fn+0x2f1 ++ 0xf768bdb8 0xc01c84fd generic_unplug_device+0x2d ++ 0xf768bdd4 0xc011b3af __run_task_queue+0x5f ++ 0xf768bdf0 0xc013a63c block_sync_page+0x1c ++ 0xf768be1c 0xc0128127 __lock_page+0x77 ++ 0xf768be28 0xc0128178 lock_page+0x18 ++ 0xf768be4c 0xc012a4b3 read_cache_page+0xc3 ++ 0xf768be78 0xc0168e23 ext2_get_page+0x23 ++ 0xf768beb8 0xc01691ed ext2_find_entry+0x8d ++ 0xf768bed4 0xc016933a ext2_inode_by_name+0x1a ++ 0xf768befc 0xc016c077 ext2_lookup+0x27 ++ 0xf768bf1c 0xc014094a lookup_hash+0x9a ++ 0xf768bf64 0xc0140c4d open_namei+0xfd ++ 0xf768bfa0 0xc0135907 filp_open+0x37 ++ 0xf768bfbc 0xc0135c64 sys_open+0x34 ++ 0xc010702b system_call+0x33 ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Let the operation continue ++%font "typewriter", size 3 ++ [3]kdb> ++%fore "blue", cont ++go ++%fore "black" ++ Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) ++ 0xc01ecfe0 isp1020_queuecommand: int3 ++ Entering kdb (current=0xc0352000, pid 0) on processor 0 due to ++ Breakpoint @ 0xc01ecfe0 ++ Show the stack ++ This is an io completion queuing the next request ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++bt ++%fore "black" ++ EBP EIP Function(args) ++ 0xc0353df4 0xc01ecfe0 isp1020_queuecommand( ++%fore "blue", cont ++0xf7e63a00 ++%fore "black", cont ++,0xc01e7fc0... ++ 0xc01e2c77 scsi_dispatch_cmd+0x1f7 ++ 0xc0353e24 0xc01e99b1 scsi_request_fn+0x2f1 ++ 0xc0353e40 0xc01e8f6a ++%fore "blue", cont ++scsi_queue_next_request+0x4a ++%fore "black" ++ 0xc0353e5c 0xc01e9166 __scsi_end_request+0x116 ++ 0xc0353ea8 0xc01e93e0 ++%fore "blue", cont ++scsi_io_completion+0x170 ++%fore "black" ++ 0xc0353ecc 0xc01f658e rw_intr+0x14e ++ 0xc0353ef8 0xc01e8668 scsi_old_done+0x6a8 ++ 0xc0353fd4 0xc01052c2 cpu_idle+0x52 ++ Function prototype ++%font "typewriter", size 3 ++ int isp1020_queuecommand( ++%fore "blue", cont ++Scsi_Cmnd *Cmnd, ++%fore "black" ++ void (*done)(Scsi_Cmnd *)) ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Show the command being queued ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++sc 0xf7e63a00 ++%fore "black" ++ scsi_cmnd at 0xf7e63a00 ++%fore "blue" ++ host = 0xf7e91400 ++%fore "black", cont ++ state = 4099 owner = 258 ++%fore "blue", cont ++device = 0xf7ed5d80 ++%fore "black" ++ bnext = 0x00000000 reset_chain = 0x00000000 eh_state = 0 ++ done = 0xc01f6440 ++ serial_number = 3402 serial_num_at_to = 0 retries = 0 timeout = 0 ++ id/lun/cmnd = [0/0/0] cmd_len = 10 old_cmd_len = 10 ++ cmnd = [2a/00/00/28/00/3f/00/00/10/00/ef/f7] ++ data_cmnd = [2a/00/00/28/00/3f/00/00/10/00/ef/f7] ++ request_buffer = 0xc03fd000 bh_next = 0x00000000 ++ request_bufflen = 8192 ++ use_sg = 2 old_use_sg = 2 sglist_len = 512 abore_reason = 0 ++ bufflen = 8192 buffer = 0xc03fd000 underflow = 8192 ++ transfersize = 512 ++ tag = 0 pid = 3401 ++ request struct ++ rq_status = RQ_ACTIVE rq_dev = [8/1] errors = 1 cmd = 0 ++ sector = 2621440 nr_sectors = 16 current_nr_sectors = 8 ++ buffer = 0xf7599000 ++%fore "blue", cont ++bh = 0xf75ca300 ++%fore "black", cont ++ bhtail = 0xf75ca3c0 ++ ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Display the host adapter ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++sh 0xf7e91400 ++%fore "black" ++ Scsi_Host at 0xf7e91400 ++ next = 0x00000000 ++%fore "blue", cont ++host_queue = 0xf7ed5d80 ++%fore "black" ++ ehandler = 0x00000000 eh_wait = 0x00000000 en_notify = 0x00000000 ++ eh_action = 0x00000000 ++ h_active = 0x0 host_wait = 0xc0353ac4 hostt = 0xc034bce0 ++ host_busy = 1 ++ host_failed = 0 extra_bytes = 524 host_no = 0 resetting = 0 ++ max id/lun/channel = [16/8/0] this_id = 7 ++ can_queue = 64 cmd_per_lun = 1 sg_tablesize = 427 u_isa_dma = 0 ++ host_blocked = 0 reverse_ordering = 0 ++ ++%font "typewriter", size 3 ++ Display the scsi device ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++sd 0xf7ed5d80 ++%fore "black" ++ scsi_device at 0xf7ed5d80 ++ next = 0xf7ed5c80 prev = 0x00000000 host = 0xf7e91400 ++ device_busy = 1 ++%fore "blue", cont ++device_queue 0xf7e63a00 ++%fore "black" ++ id/lun/chan = [0/0/0] single_lun = 0 device_blocked = 0 ++ queue_depth = 1 current_tag = 0 scsi_level = 4 ++ IBM DGHS18X 0360 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Display the Buffer header associated with the command ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++bh 0xf75ca300 ++%fore "black" ++ buffer_head at 0xf75ca300 ++ next 0x00000000 bno 327680 rsec 2621440 size 4096 ++ dev 0x801 rdev 0x801 ++ count 2 state 0x1d [Uptodate Lock Req Mapped] ftime 0x7695e ++ b_list 1 b_reqnext 0xf75ca3c0 b_data 0xf7599000 ++%fore "blue" ++ b_page 0xc1dd6640 ++%fore "black", cont ++ b_this_page 0xf75ca300 b_private 0x00000000 ++ ++ Display the associated page structure ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++page 0xc1dd6640 ++%fore "black" ++ struct page at 0xc1dd6640 ++ next 0xc1dd7300 prev 0xc1dd6240 ++%fore "blue", cont ++addr space 0xf7af04d0 ++%fore "black" ++ index 327680 (offset 0x50000000) ++ count 2 flags PG_referenced PG_lru virtual 0xf7599000 ++ buffers 0xf75ca300 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Display the Address space associated with the page ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++md 0xf7af04d0 ++%fore "black" ++ 0xf7af04d0 c1dd6240 c1dea740 f7af04d8 f7af04d8 @b]A@'^AX./wX./w ++ 0xf7af04e0 f7af04e0 f7af04e0 00000007 c033b700 `./w`./w.....73@ ++ 0xf7af04f0 ++%fore "blue", cont ++f7af0420 ++%fore "black", cont ++ 00000000 00000000 00000001 ./w............ ++ 0xf7af0500 000001d0 00000000 00000000 f7af050c P............./w ++ 0xf7af0510 f7af050c 00000000 f7a8afa0 00000000 ../w.... /(w.... ++ ++ The structure looks like: ++%size 3 ++ struct address_space { ++ struct list_head clean_pages; /* list of clean pages */ ++ struct list_head dirty_pages; /* list of dirty pages */ ++ struct list_head locked_pages;/* list of locked pages */ ++ unsigned long nrpages; /* number of total pages */ ++ spinlock_t page_lock; /* spinlock protecting them*/ ++ struct address_space_operations *a_ops; /* methods */ ++%fore "blue" ++ struct inode *host; /* owner: inode, block_dev */ ++%fore "black" ++ ++ }; ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Display the inode associated with the address space ++ I think htis is the inode for the block device. ++ ++%font "typewriter", size 3 ++ [1]kdb> ++%fore "blue", cont ++inode f7af0420 ++%fore "black" ++ struct inode at 0xf7af0420 ++ i_ino = 289 i_count = 1 i_dev = 0x801 i_size 4301789184 ++ i_mode = 0x8000 i_nlink = 1 i_rdev = 0x801 ++ i_hash.nxt = 0xf7af0420 i_hash.prv = 0xf7af0420 ++ i_list.nxt = 0xf7af0608 i_list.prv = 0xf7af0068 ++ i_dentry.nxt = 0xf7af0430 i_dentry.prv = 0xf7af0430 ++ i_dirty_buffers.nxt = 0xf7af0438 i_dirty_buffers.prv = 0xf7af0438 ++ i_sb = 0xc201f200 i_op = 0xc03cfdc0 i_data = 0xf7af04d0 nrpages = 6 ++ i_mapping = 0xf7af04d0 ++ i_flags 0x0 i_state 0x0 [] fs specific info @ 0xf7af0540 ++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ++%page ++ ++Walking IO structures ++ ++ ++%font "typewriter", size 3 ++ Display the page list associated with the inode ++%font "typewriter", size 3 ++ [0]kdb> ++%fore "blue", cont ++inode_pages f7af0420 ++%fore "black" ++CLEAN page_struct index cnt flags ++ 0xc1dd6240 327735 2 0x44 bh 0xf75caae0 bno 327735 ++ [Lock Req Mapped] ++%fore "blue" ++ 0xc1dd6640 327680 2 0x44 bh 0xf75ca300 bno 327680 ++ [Uptodate Lock Req Mapped] ++%fore "black" ++ 0xc1dd7300 327681 2 0x44 bh 0xf75ca3c0 bno 327681 ++ [Uptodate Lock Req Mapped] ++ 0xc1dd6e00 327684 2 0x44 bh 0xf75ca420 bno 327684 ++ [Uptodate Req Mapped] ++ 0xc1de8fc0 4 2 0xc0 bh 0xf7b5ade0 bno 4 ++ [Uptodate Req Mapped] ++ 0xc1dea700 1 2 0x44 bh 0xf7e02740 bno 1 ++ [Uptodate Req Mapped] ++ 0xc1dea740 0 2 0x44 bh 0xf7e028c0 bno 0 ++ [Uptodate Req Mapped] ++DIRTY page_struct index cnt flags ++LOCKED page_struct index cnt flags +--- a/Makefile ++++ b/Makefile +@@ -645,6 +645,7 @@ export mod_strip_cmd + + ifeq ($(KBUILD_EXTMOD),) + core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ ++core-$(CONFIG_KDB) += kdb/ + + vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ + $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ +--- a/drivers/char/keyboard.c ++++ b/drivers/char/keyboard.c +@@ -43,6 +43,9 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ + + extern void ctrl_alt_del(void); + +@@ -1189,6 +1192,13 @@ static void kbd_keycode(unsigned int key + } + #endif + ++#ifdef CONFIG_KDB ++ if (down && !rep && keycode == KEY_PAUSE && kdb_on == 1) { ++ kdb(KDB_REASON_KEYBOARD, 0, get_irq_regs()); ++ return; ++ } ++#endif /* CONFIG_KDB */ ++ + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { + if (!sysrq_down) { +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -44,6 +44,10 @@ + #define DRIVER_DESC "USB HID core driver" + #define DRIVER_LICENSE "GPL" + ++#ifdef CONFIG_KDB_USB ++#include ++#endif ++ + static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", + "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; + /* +@@ -940,6 +944,15 @@ static void hid_disconnect(struct usb_in + + usbhid = hid->driver_data; + ++#ifdef CONFIG_KDB_USB ++ /* ++ * If the URB was for a Keyboard, detach it from kdb. ++ * If the URB was for another type of device, just ++ * allow kdb_usb_keyboard_detach() to silently fail. ++ */ ++ kdb_usb_keyboard_detach(usbhid->urbin); ++#endif ++ + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ + usb_set_intfdata(intf, NULL); + set_bit(HID_DISCONNECTED, &usbhid->iofl); +@@ -1037,6 +1050,21 @@ static int hid_probe(struct usb_interfac + printk(": USB HID v%x.%02x %s [%s] on %s\n", + hid->version >> 8, hid->version & 0xff, c, hid->name, path); + ++#ifdef CONFIG_KDB_USB ++ /* Attach USB keyboards to kdb */ ++ if (!strcmp(c, "Keyboard")) { ++ int ret; ++ struct usbhid_device *usbhid = hid->driver_data; ++ extern void * usb_hcd_get_kdb_poll_func(struct usb_device *udev); ++ ret = kdb_usb_keyboard_attach(usbhid->urbin, usbhid->inbuf, ++ usb_hcd_get_kdb_poll_func(interface_to_usbdev(intf))); ++ ++ if (ret == -1) ++ printk(": FAILED to register keyboard (%s) " ++ "with KDB\n", path); ++ } ++#endif /* CONFIG_KDB_USB */ ++ + return 0; + } + +--- a/drivers/hid/usbhid/usbkbd.c ++++ b/drivers/hid/usbhid/usbkbd.c +@@ -30,6 +30,9 @@ + #include + #include + #include ++#ifdef CONFIG_KDB_USB ++#include ++#endif + + /* + * Version Information +@@ -289,6 +292,16 @@ static int usb_kbd_probe(struct usb_inte + usb_fill_int_urb(kbd->irq, dev, pipe, + kbd->new, (maxp > 8 ? 8 : maxp), + usb_kbd_irq, kbd, endpoint->bInterval); ++ ++#ifdef CONFIG_KDB_USB ++ /* Attach keyboard to kdb */ ++ extern void * usb_hcd_get_kdb_poll_func(struct usb_device *udev); ++ ++ kdb_usb_keyboard_attach(kbd->irq, kbd->new, ++ usb_hcd_get_kdb_poll_func(dev)); ++ ++#endif /* CONFIG_KDB_USB */ ++ + kbd->irq->transfer_dma = kbd->new_dma; + kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +@@ -326,6 +339,10 @@ static void usb_kbd_disconnect(struct us + + usb_set_intfdata(intf, NULL); + if (kbd) { ++#ifdef CONFIG_KDB_USB ++ /* Detach the keyboard from kdb */ ++ kdb_usb_keyboard_detach(kbd->irq); ++#endif /* CONFIG_KDB_USB */ + usb_kill_urb(kbd->irq); + input_unregister_device(kbd->dev); + usb_kbd_free_mem(interface_to_usbdev(intf), kbd); +--- a/drivers/serial/8250.c ++++ b/drivers/serial/8250.c +@@ -43,6 +43,19 @@ + #include + + #include "8250.h" ++#include ++#ifdef CONFIG_KDB ++/* ++ * kdb_serial_line records the serial line number of the first serial console. ++ * NOTE: The kernel ignores characters on the serial line unless a user space ++ * program has opened the line first. To enter kdb before user space has opened ++ * the serial line, you can use the 'kdb=early' flag to lilo and set the ++ * appropriate breakpoints. ++ */ ++ ++static int kdb_serial_line = -1; ++static const char *kdb_serial_ptr = kdb_serial_str; ++#endif /* CONFIG_KDB */ + + /* + * Configuration: +@@ -1310,6 +1323,20 @@ receive_chars(struct uart_8250_port *up, + * just force the read character to be 0 + */ + ch = 0; ++#ifdef CONFIG_KDB ++ if ((up->port.line == kdb_serial_line) && kdb_on == 1) { ++ if (ch == *kdb_serial_ptr) { ++ if (!(*++kdb_serial_ptr)) { ++ atomic_inc(&kdb_8250); ++ kdb(KDB_REASON_KEYBOARD, 0, get_irq_regs()); ++ atomic_dec(&kdb_8250); ++ kdb_serial_ptr = kdb_serial_str; ++ break; ++ } ++ } else ++ kdb_serial_ptr = kdb_serial_str; ++ } ++#endif /* CONFIG_KDB */ + + flag = TTY_NORMAL; + up->port.icount.rx++; +@@ -2582,7 +2609,7 @@ serial8250_console_write(struct console + if (up->port.sysrq) { + /* serial8250_handle_port() already took the lock */ + locked = 0; +- } else if (oops_in_progress) { ++ } else if (oops_in_progress || KDB_8250()) { + locked = spin_trylock(&up->port.lock); + } else + spin_lock(&up->port.lock); +@@ -2640,6 +2667,30 @@ static int __init serial8250_console_set + if (!port->iobase && !port->membase) + return -ENODEV; + ++#ifdef CONFIG_KDB ++ /* ++ * Remember the line number of the first serial ++ * console. We'll make this the kdb serial console too. ++ */ ++ if (co && kdb_serial_line == -1) { ++ kdb_serial_line = co->index; ++ kdb_serial.io_type = port->iotype; ++ switch (port->iotype) { ++ case SERIAL_IO_MEM: ++#ifdef SERIAL_IO_MEM32 ++ case SERIAL_IO_MEM32: ++#endif ++ kdb_serial.iobase = (unsigned long)(port->membase); ++ kdb_serial.ioreg_shift = port->regshift; ++ break; ++ default: ++ kdb_serial.iobase = port->iobase; ++ kdb_serial.ioreg_shift = 0; ++ break; ++ } ++ } ++#endif /* CONFIG_KDB */ ++ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + +--- a/drivers/serial/8250_early.c ++++ b/drivers/serial/8250_early.c +@@ -38,6 +38,11 @@ + #include + #endif + ++#ifdef CONFIG_KDB ++#include ++static int kdb_serial_line = -1; ++#endif /* CONFIG_KDB */ ++ + struct early_serial8250_device { + struct uart_port port; + char options[16]; /* e.g., 115200n8 */ +@@ -231,6 +236,30 @@ int __init setup_early_serial8250_consol + + register_console(&early_serial8250_console); + ++#ifdef CONFIG_KDB ++ /* ++ * Remember the line number of the first serial ++ * console. We'll make this the kdb serial console too. ++ */ ++ if (kdb_serial_line == -1) { ++ kdb_serial_line = early_serial8250_console.index; ++ kdb_serial.io_type = early_device.port.iotype; ++ switch (early_device.port.iotype) { ++ case SERIAL_IO_MEM: ++#ifdef SERIAL_IO_MEM32 ++ case SERIAL_IO_MEM32: ++#endif ++ kdb_serial.iobase = (unsigned long)(early_device.port.membase); ++ kdb_serial.ioreg_shift = early_device.port.regshift; ++ break; ++ default: ++ kdb_serial.iobase = early_device.port.iobase; ++ kdb_serial.ioreg_shift = 0; ++ break; ++ } ++ } ++#endif /* CONFIG_KDB */ ++ + return 0; + } + +--- a/drivers/serial/sn_console.c ++++ b/drivers/serial/sn_console.c +@@ -48,6 +48,22 @@ + #include /* for mdelay */ + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include ++#include ++/* ++ * kdb_serial_line records the serial line number of the first serial console. ++ * NOTE: The kernel ignores characters on the serial line unless a user space ++ * program has opened the line first. To enter kdb before user space has opened ++ * the serial line, you can use the 'kdb=early' flag to lilo and set the ++ * appropriate breakpoints. ++ */ ++ ++static int kdb_serial_line = -1; ++static char *kdb_serial_ptr = (char *)kdb_serial_str; ++#endif /* CONFIG_KDB */ ++ + + #include + #include +@@ -485,6 +501,26 @@ sn_receive_chars(struct sn_cons_port *po + "obtaining data from the console (0x%0x)\n", ch); + break; + } ++#ifdef CONFIG_KDB ++ if (kdb_on == 1) { ++ if (ch == *kdb_serial_ptr) { ++ if (!(*++kdb_serial_ptr)) { ++ spin_unlock_irqrestore(&port->sc_port.lock, flags); ++ if (!get_irq_regs()) { ++ KDB_STATE_SET(KEYBOARD); ++ KDB_ENTER(); /* to get some registers */ ++ } else ++ kdb(KDB_REASON_KEYBOARD, 0, get_irq_regs()); ++ kdb_serial_ptr = (char *)kdb_serial_str; ++ spin_lock_irqsave(&port->sc_port.lock, flags); ++ break; ++ } ++ } ++ else ++ kdb_serial_ptr = (char *)kdb_serial_str; ++ } ++#endif /* CONFIG_KDB */ ++ + #ifdef CONFIG_MAGIC_SYSRQ + if (sysrq_requested) { + unsigned long sysrq_timeout = sysrq_requested + HZ*5; +@@ -1008,6 +1044,15 @@ sn_sal_console_write(struct console *co, + */ + static int sn_sal_console_setup(struct console *co, char *options) + { ++#ifdef CONFIG_KDB ++ /* ++ * Remember the line number of the first serial ++ * console. We'll make this the kdb serial console too. ++ */ ++ if (kdb_serial_line == -1) { ++ kdb_serial_line = co->index; ++ } ++#endif /* CONFIG_KDB */ + return 0; + } + +@@ -1083,3 +1128,31 @@ static int __init sn_sal_serial_console_ + } + + console_initcall(sn_sal_serial_console_init); ++ ++#ifdef CONFIG_KDB ++int ++l1_control_in_polled(int offset) ++{ ++ int sal_call_status = 0, input; ++ int ret = 0; ++ if (offset == UART_LSR) { ++ ret = (UART_LSR_THRE | UART_LSR_TEMT); /* can send anytime */ ++ sal_call_status = ia64_sn_console_check(&input); ++ if (!sal_call_status && input) { ++ /* input pending */ ++ ret |= UART_LSR_DR; ++ } ++ } ++ return ret; ++} ++ ++int ++l1_serial_in_polled(void) ++{ ++ int ch; ++ if (!ia64_sn_console_getc(&ch)) ++ return ch; ++ else ++ return 0; ++} ++#endif /* CONFIG_KDB */ +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -2027,6 +2027,20 @@ usb_hcd_platform_shutdown(struct platfor + } + EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); + ++#ifdef CONFIG_KDB_USB ++void * ++usb_hcd_get_kdb_poll_func(struct usb_device *udev) ++{ ++ struct usb_hcd *hcd = bus_to_hcd(udev->bus); ++ ++ if (hcd && hcd->driver) ++ return (void *)(hcd->driver->kdb_poll_char); ++ ++ return NULL; ++} ++EXPORT_SYMBOL_GPL (usb_hcd_get_kdb_poll_func); ++#endif /* CONFIG_KDB_USB */ ++ + /*-------------------------------------------------------------------------*/ + + #if defined(CONFIG_USB_MON) +--- a/drivers/usb/core/hcd.h ++++ b/drivers/usb/core/hcd.h +@@ -217,6 +217,10 @@ struct hc_driver { + void (*relinquish_port)(struct usb_hcd *, int); + /* has a port been handed over to a companion? */ + int (*port_handed_over)(struct usb_hcd *, int); ++#ifdef CONFIG_KDB_USB ++ /* KDB poll function for this HC */ ++ int (*kdb_poll_char)(struct urb *urb); ++#endif /* CONFIG_KDB_USB */ + }; + + extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -993,6 +993,48 @@ static int ehci_get_frame (struct usb_hc + ehci->periodic_size; + } + ++#ifdef CONFIG_KDB_USB ++ ++int ++ehci_kdb_poll_char(struct urb *urb) ++{ ++ struct ehci_hcd *ehci; ++ ++ /* just to make sure */ ++ if (!urb || !urb->dev || !urb->dev->bus) ++ return -1; ++ ++ ehci = (struct ehci_hcd *) hcd_to_ehci(bus_to_hcd(urb->dev->bus)); ++ ++ /* make sure */ ++ if (!ehci) ++ return -1; ++ ++ if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) ++ return -1; ++ ++ /* ++ * If ehci->lock is held coming into this routine, it could ++ * mean KDB was entered while the HC driver was in the midst ++ * of processing URBs. Therefore it could be dangerous to ++ * processes URBs from this poll routine. And, we can't wait on ++ * the lock since we are in KDB and kernel threads (including the ++ * one holding the lock) are suspended. ++ * So, we punt and return an error. Keyboards attached to this ++ * HC will not be useable from KDB at this time. ++ */ ++ if (spin_is_locked(&ehci->lock)) ++ return -EBUSY; ++ ++ /* processes the URB */ ++ if (qh_completions_kdb(ehci, urb->hcpriv, urb)) ++ return 0; ++ ++ return -1; ++} ++ ++#endif /* CONFIG_KDB_USB */ ++ + /*-------------------------------------------------------------------------*/ + + #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC +--- a/drivers/usb/host/ehci-pci.c ++++ b/drivers/usb/host/ehci-pci.c +@@ -22,6 +22,10 @@ + #error "This file is PCI bus glue. CONFIG_PCI must be defined." + #endif + ++#ifdef CONFIG_KDB_USB ++#include ++#endif ++ + /*-------------------------------------------------------------------------*/ + + /* called after powerup, by probe or system-pm "wakeup" */ +@@ -404,6 +408,10 @@ static const struct hc_driver ehci_pci_h + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, ++ ++#ifdef CONFIG_KDB_USB ++ .kdb_poll_char = ehci_kdb_poll_char, ++#endif + }; + + /*-------------------------------------------------------------------------*/ +--- a/drivers/usb/host/ehci-q.c ++++ b/drivers/usb/host/ehci-q.c +@@ -499,6 +499,228 @@ halt: + return count; + } + ++#ifdef CONFIG_KDB_USB ++/* ++ * This routine is basically a copy of qh_completions() for use by KDB. ++ * It is modified to only work on qtds which are associated ++ * with 'kdburb'. Also, there are some fixups related to locking. ++ */ ++unsigned ++qh_completions_kdb(struct ehci_hcd *ehci, struct ehci_qh *qh, struct urb *kdburb) ++{ ++ struct ehci_qtd *last = NULL, *end = qh->dummy; ++ struct list_head *entry, *tmp; ++ int last_status = -EINPROGRESS; ++ int stopped; ++ unsigned count = 0; ++ int do_status = 0; ++ u8 state; ++ u32 halt = HALT_BIT(ehci); ++ ++ /* verify params are valid */ ++ if (!qh || !kdburb) ++ return 0; ++ ++ if (unlikely (list_empty (&qh->qtd_list))) ++ return count; ++ ++ /* completions (or tasks on other cpus) must never clobber HALT ++ * till we've gone through and cleaned everything up, even when ++ * they add urbs to this qh's queue or mark them for unlinking. ++ * ++ * NOTE: unlinking expects to be done in queue order. ++ */ ++ state = qh->qh_state; ++ qh->qh_state = QH_STATE_COMPLETING; ++ stopped = (state == QH_STATE_IDLE); ++ ++ /* remove de-activated QTDs from front of queue. ++ * after faults (including short reads), cleanup this urb ++ * then let the queue advance. ++ * if queue is stopped, handles unlinks. ++ */ ++ list_for_each_safe (entry, tmp, &qh->qtd_list) { ++ struct ehci_qtd *qtd; ++ struct urb *urb; ++ u32 token = 0; ++ int qtd_status; ++ ++ qtd = list_entry (entry, struct ehci_qtd, qtd_list); ++ urb = qtd->urb; ++ ++ if (urb != kdburb) ++ continue; ++ ++ /* clean up any state from previous QTD ...*/ ++ if (last) { ++ if (likely (last->urb != urb)) { ++ /* ++ * Lock hackery here... ++ * ehci_urb_done() makes the assumption ++ * that it's called with ehci->lock held. ++ * So, lock it if it isn't already. ++ */ ++ if (!spin_is_locked(&ehci->lock)) ++ spin_lock(&ehci->lock); ++ ++ ehci_urb_done(ehci, last->urb, last_status); ++ ++ /* ++ * ehci_urb_done() releases and reacquires ++ * ehci->lock, so release it here. ++ */ ++ if (spin_is_locked(&ehci->lock)) ++ spin_unlock (&ehci->lock); ++ ++ count++; ++ } ++ ehci_qtd_free (ehci, last); ++ last = NULL; ++ last_status = -EINPROGRESS; ++ } ++ ++ /* ignore urbs submitted during completions we reported */ ++ if (qtd == end) ++ break; ++ ++ /* hardware copies qtd out of qh overlay */ ++ rmb (); ++ token = hc32_to_cpu(ehci, qtd->hw_token); ++ ++ /* always clean up qtds the hc de-activated */ ++ if ((token & QTD_STS_ACTIVE) == 0) { ++ ++ if ((token & QTD_STS_HALT) != 0) { ++ stopped = 1; ++ ++ /* magic dummy for some short reads; qh won't advance. ++ * that silicon quirk can kick in with this dummy too. ++ */ ++ } else if (IS_SHORT_READ (token) ++ && !(qtd->hw_alt_next ++ & EHCI_LIST_END(ehci))) { ++ stopped = 1; ++ goto halt; ++ } ++ ++ /* stop scanning when we reach qtds the hc is using */ ++ } else if (likely (!stopped ++ && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) { ++ break; ++ ++ } else { ++ stopped = 1; ++ ++ if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) ++ last_status = -ESHUTDOWN; ++ ++ /* ignore active urbs unless some previous qtd ++ * for the urb faulted (including short read) or ++ * its urb was canceled. we may patch qh or qtds. ++ */ ++ if (likely(last_status == -EINPROGRESS && ++ !urb->unlinked)) ++ continue; ++ ++ /* issue status after short control reads */ ++ if (unlikely (do_status != 0) ++ && QTD_PID (token) == 0 /* OUT */) { ++ do_status = 0; ++ continue; ++ } ++ ++ /* token in overlay may be most current */ ++ if (state == QH_STATE_IDLE ++ && cpu_to_hc32(ehci, qtd->qtd_dma) ++ == qh->hw_current) ++ token = hc32_to_cpu(ehci, qh->hw_token); ++ ++ /* force halt for unlinked or blocked qh, so we'll ++ * patch the qh later and so that completions can't ++ * activate it while we "know" it's stopped. ++ */ ++ if ((halt & qh->hw_token) == 0) { ++halt: ++ qh->hw_token |= halt; ++ wmb (); ++ } ++ } ++ ++ /* remove it from the queue */ ++ qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); ++ if (unlikely(qtd_status == -EREMOTEIO)) { ++ do_status = (!urb->unlinked && ++ usb_pipecontrol(urb->pipe)); ++ qtd_status = 0; ++ } ++ if (likely(last_status == -EINPROGRESS)) ++ last_status = qtd_status; ++ ++ if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { ++ last = list_entry (qtd->qtd_list.prev, ++ struct ehci_qtd, qtd_list); ++ last->hw_next = qtd->hw_next; ++ } ++ list_del (&qtd->qtd_list); ++ last = qtd; ++ } ++ ++ /* last urb's completion might still need calling */ ++ if (likely (last != NULL)) { ++ /* ++ * Lock hackery here... ++ * ehci_urb_done() makes the assumption ++ * that it's called with ehci->lock held. ++ * So, lock it if it isn't already. ++ */ ++ if (!spin_is_locked(&ehci->lock)) ++ spin_lock(&ehci->lock); ++ ++ ehci_urb_done(ehci, last->urb, last_status); ++ ++ /* ++ * ehci_urb_done() releases and reacquires ++ * ehci->lock, so release it here. ++ */ ++ if (spin_is_locked(&ehci->lock)) ++ spin_unlock (&ehci->lock); ++ ++ count++; ++ ehci_qtd_free (ehci, last); ++ } ++ ++ /* restore original state; caller must unlink or relink */ ++ qh->qh_state = state; ++ ++ /* be sure the hardware's done with the qh before refreshing ++ * it after fault cleanup, or recovering from silicon wrongly ++ * overlaying the dummy qtd (which reduces DMA chatter). ++ */ ++ if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) { ++ switch (state) { ++ case QH_STATE_IDLE: ++ qh_refresh(ehci, qh); ++ break; ++ case QH_STATE_LINKED: ++ /* should be rare for periodic transfers, ++ * except maybe high bandwidth ... ++ */ ++ if ((cpu_to_hc32(ehci, QH_SMASK) ++ & qh->hw_info2) != 0) { ++ intr_deschedule (ehci, qh); ++ (void) qh_schedule (ehci, qh); ++ } else ++ unlink_async (ehci, qh); ++ break; ++ /* otherwise, unlink already started */ ++ } ++ } ++ ++ return count; ++} ++ ++#endif /* CONFIG_KDB_USB */ ++ + /*-------------------------------------------------------------------------*/ + + // high bandwidth multiplier, as encoded in highspeed endpoint descriptors +--- a/drivers/usb/host/ohci-hcd.c ++++ b/drivers/usb/host/ohci-hcd.c +@@ -984,6 +984,73 @@ static int ohci_restart (struct ohci_hcd + + /*-------------------------------------------------------------------------*/ + ++#ifdef CONFIG_KDB_USB ++ ++int ++ohci_kdb_poll_char(struct urb *urb) ++{ ++ struct ohci_hcd *ohci; ++ struct ohci_regs * regs; ++ ++ /* just to make sure */ ++ if (!urb || !urb->dev || !urb->dev->bus) ++ return -1; ++ ++ ohci = (struct ohci_hcd *) hcd_to_ohci(bus_to_hcd(urb->dev->bus)); ++ ++ /* make sure */ ++ if (!ohci || !ohci->hcca) ++ return -1; ++ ++ if (!HC_IS_RUNNING (ohci_to_hcd(ohci)->state)) ++ return -1; ++ ++ /* ++ * If ohci->lock is held coming into this routine, it could ++ * mean KDB was entered while the HC driver was in the midst ++ * of processing URBs. Therefore it could be dangerous to ++ * processes URBs from this poll routine. And, we can't wait on ++ * the lock since we are in KDB and kernel threads (including the ++ * one holding the lock) are suspended. ++ * So, we punt and return an error. Keyboards attached to this ++ * HC will not be useable from KDB at this time. ++ */ ++ if (spin_is_locked(&ohci->lock)) ++ return -EBUSY; ++ ++ regs = ohci->regs; ++ ++ /* if the urb is not currently in progress resubmit it */ ++ if (urb->status != -EINPROGRESS) { ++ ++ if (usb_submit_urb (urb, GFP_ATOMIC)) ++ return -1; ++ ++ /* make sure the HC registers are set correctly */ ++ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); ++ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus); ++ ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); ++ ++ // flush those pci writes ++ (void) ohci_readl (ohci, &ohci->regs->control); ++ } ++ ++ if (ohci->hcca->done_head) { ++ dl_done_list_kdb (ohci, urb); ++ ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrstatus); ++ // flush the pci write ++ (void) ohci_readl (ohci, &ohci->regs->control); ++ ++ return 0; ++ } ++ ++ return -1; ++} ++ ++#endif /* CONFIG_KDB_USB */ ++ ++/*-------------------------------------------------------------------------*/ ++ + #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC + + MODULE_AUTHOR (DRIVER_AUTHOR); +--- a/drivers/usb/host/ohci-pci.c ++++ b/drivers/usb/host/ohci-pci.c +@@ -21,6 +21,10 @@ + #include + #include + ++#ifdef CONFIG_KDB_USB ++#include ++#endif ++ + + /* constants used to work around PM-related transfer + * glitches in some AMD 700 series southbridges +@@ -367,6 +371,7 @@ static int __devinit ohci_pci_start (str + ohci_err (ohci, "can't start\n"); + ohci_stop (hcd); + } ++ + return ret; + } + +@@ -464,6 +469,9 @@ static const struct hc_driver ohci_pci_h + .bus_resume = ohci_bus_resume, + #endif + .start_port_reset = ohci_start_port_reset, ++#ifdef CONFIG_KDB_USB ++ .kdb_poll_char = ohci_kdb_poll_char, ++#endif + }; + + /*-------------------------------------------------------------------------*/ +--- a/drivers/usb/host/ohci-q.c ++++ b/drivers/usb/host/ohci-q.c +@@ -1127,3 +1127,65 @@ dl_done_list (struct ohci_hcd *ohci) + td = td_next; + } + } ++ ++ ++/*-------------------------------------------------------------------------*/ ++ ++#ifdef CONFIG_KDB_USB ++static void ++dl_done_list_kdb (struct ohci_hcd *ohci, struct urb *kdburb) ++{ ++ struct td *td = dl_reverse_done_list (ohci); ++ ++ while (td) { ++ struct td *td_next = td->next_dl_td; ++ struct urb *urb = td->urb; ++ urb_priv_t *urb_priv = urb->hcpriv; ++ struct ed *ed = td->ed; ++ ++ if (urb != kdburb) { ++ td = td_next; ++ continue; ++ } ++ ++ /* update URB's length and status from TD */ ++ td_done (ohci, urb, td); ++ urb_priv->td_cnt++; ++ ++ /* If all this urb's TDs are done, just resubmit it */ ++ if (urb_priv->td_cnt == urb_priv->length) { ++ urb->actual_length = 0; ++ urb->status = -EINPROGRESS; ++ td_submit_urb (ohci, urb); ++ } ++ ++ /* clean schedule: unlink EDs that are no longer busy */ ++ if (list_empty (&ed->td_list)) { ++ if (ed->state == ED_OPER) ++ start_ed_unlink (ohci, ed); ++ ++ /* ... reenabling halted EDs only after fault cleanup */ ++ } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE)) ++ == cpu_to_hc32 (ohci, ED_SKIP)) { ++ td = list_entry (ed->td_list.next, struct td, td_list); ++ if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { ++ ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); ++ /* ... hc may need waking-up */ ++ switch (ed->type) { ++ case PIPE_CONTROL: ++ ohci_writel (ohci, OHCI_CLF, ++ &ohci->regs->cmdstatus); ++ break; ++ case PIPE_BULK: ++ ohci_writel (ohci, OHCI_BLF, ++ &ohci->regs->cmdstatus); ++ break; ++ } ++ } ++ } ++ ++ td = td_next; ++ } ++} ++ ++#endif /* CONFIG_KDB_USB */ +--- a/fs/proc/mmu.c ++++ b/fs/proc/mmu.c +@@ -14,11 +14,21 @@ + #include + #include "internal.h" + ++#ifdef CONFIG_KDB ++#include ++#endif ++ + void get_vmalloc_info(struct vmalloc_info *vmi) + { + struct vm_struct *vma; + unsigned long free_area_size; + unsigned long prev_end; ++#ifdef CONFIG_KDB ++ int get_lock = !KDB_IS_RUNNING(); ++#else ++#define get_lock 1 ++#endif ++ + + vmi->used = 0; + +@@ -30,7 +40,8 @@ void get_vmalloc_info(struct vmalloc_inf + + prev_end = VMALLOC_START; + +- read_lock(&vmlist_lock); ++ if (get_lock) ++ read_lock(&vmlist_lock); + + for (vma = vmlist; vma; vma = vma->next) { + unsigned long addr = (unsigned long) vma->addr; +@@ -55,6 +66,7 @@ void get_vmalloc_info(struct vmalloc_inf + if (VMALLOC_END - prev_end > vmi->largest_chunk) + vmi->largest_chunk = VMALLOC_END - prev_end; + +- read_unlock(&vmlist_lock); ++ if (get_lock) ++ read_unlock(&vmlist_lock); + } + } +--- a/fs/proc/proc_misc.c ++++ b/fs/proc/proc_misc.c +@@ -239,6 +239,120 @@ static int meminfo_read_proc(char *page, + #undef K + } + ++#ifdef CONFIG_KDB ++#include ++#include ++/* Like meminfo_read_proc() but without the locks and using kdb_printf() */ ++void ++kdb_meminfo_read_proc(void) ++{ ++ struct sysinfo i; ++ unsigned long committed; ++ unsigned long allowed; ++ struct vmalloc_info vmi; ++ long cached; ++ ++/* ++ * display in kilobytes. ++ */ ++#define K(x) ((x) << (PAGE_SHIFT - 10)) ++ si_meminfo(&i); ++ kdb_si_swapinfo(&i); ++ committed = atomic_read(&vm_committed_space); ++ allowed = ((totalram_pages - hugetlb_total_pages()) ++ * sysctl_overcommit_ratio / 100) + total_swap_pages; ++ ++ cached = global_page_state(NR_FILE_PAGES) - ++ total_swapcache_pages - i.bufferram; ++ if (cached < 0) ++ cached = 0; ++ ++ get_vmalloc_info(&vmi); ++ ++ kdb_printf( ++ "MemTotal: %8lu kB\n" ++ "MemFree: %8lu kB\n" ++ "Buffers: %8lu kB\n", ++ K(i.totalram), ++ K(i.freeram), ++ K(i.bufferram) ++ ); ++ kdb_printf( ++ "Cached: %8lu kB\n" ++ "SwapCached: %8lu kB\n" ++ "Active: %8lu kB\n" ++ "Inactive: %8lu kB\n", ++ K(cached), ++ K(total_swapcache_pages), ++ K(global_page_state(NR_ACTIVE)), ++ K(global_page_state(NR_INACTIVE)) ++ ); ++#ifdef CONFIG_HIGHMEM ++ kdb_printf( ++ "HighTotal: %8lu kB\n" ++ "HighFree: %8lu kB\n" ++ "LowTotal: %8lu kB\n" ++ "LowFree: %8lu kB\n", ++ K(i.totalhigh), ++ K(i.freehigh), ++ K(i.totalram-i.totalhigh), ++ K(i.freeram-i.freehigh) ++ ); ++#endif ++ kdb_printf( ++ "SwapTotal: %8lu kB\n" ++ "SwapFree: %8lu kB\n" ++ "Dirty: %8lu kB\n", ++ K(i.totalswap), ++ K(i.freeswap), ++ K(global_page_state(NR_FILE_DIRTY)) ++ ); ++ kdb_printf( ++ "Writeback: %8lu kB\n" ++ "AnonPages: %8lu kB\n" ++ "Mapped: %8lu kB\n", ++ K(global_page_state(NR_WRITEBACK)), ++ K(global_page_state(NR_ANON_PAGES)), ++ K(global_page_state(NR_FILE_MAPPED)) ++ ); ++ kdb_printf( ++ "Slab: %8lu kB\n" ++ "SReclaimable: %8lu kB\n" ++ "SUnreclaim: %8lu kB\n", ++ K(global_page_state(NR_SLAB_RECLAIMABLE) + ++ global_page_state(NR_SLAB_UNRECLAIMABLE)), ++ K(global_page_state(NR_SLAB_RECLAIMABLE)), ++ K(global_page_state(NR_SLAB_UNRECLAIMABLE)) ++ ); ++ kdb_printf( ++ "PageTables: %8lu kB\n" ++ "NFS_Unstable: %8lu kB\n" ++ "Bounce: %8lu kB\n", ++ K(global_page_state(NR_PAGETABLE)), ++ K(global_page_state(NR_UNSTABLE_NFS)), ++ K(global_page_state(NR_BOUNCE)) ++ ); ++ kdb_printf( ++ "CommitLimit: %8lu kB\n" ++ "Committed_AS: %8lu kB\n" ++ "VmallocTotal: %8lu kB\n", ++ K(allowed), ++ K(committed), ++ (unsigned long)VMALLOC_TOTAL >> 10 ++ ); ++ kdb_printf( ++ "VmallocUsed: %8lu kB\n" ++ "VmallocChunk: %8lu kB\n", ++ vmi.used >> 10, ++ vmi.largest_chunk >> 10 ++ ); ++ ++#ifdef CONFIG_HUGETLBFS ++ kdb_hugetlb_report_meminfo(); ++#endif ++} ++#endif /* CONFIG_KDB */ ++ + static int fragmentation_open(struct inode *inode, struct file *file) + { + (void)inode; +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -142,7 +142,12 @@ void vcs_remove_sysfs(struct tty_struct + + /* Some debug stub to catch some of the obvious races in the VT code */ + #if 1 ++#ifdef CONFIG_KDB ++#include ++#define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress && !atomic_read(&kdb_event)) ++#else /* !CONFIG_KDB */ + #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress) ++#endif /* CONFIG_KDB */ + #else + #define WARN_CONSOLE_UNLOCKED() + #endif +--- /dev/null ++++ b/include/linux/dis-asm.h +@@ -0,0 +1,347 @@ ++/* Interface between the opcode library and its callers. ++ ++ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 ++ Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, ++ Boston, MA 02110-1301, USA. ++ ++ Written by Cygnus Support, 1993. ++ ++ The opcode library (libopcodes.a) provides instruction decoders for ++ a large variety of instruction sets, callable with an identical ++ interface, for making instruction-processing programs more independent ++ of the instruction set being processed. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef DIS_ASM_H ++#define DIS_ASM_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef __KERNEL__ ++#include ++#include ++typedef void FILE; ++#else /* __KERNEL__ */ ++#include ++#include "bfd.h" ++#endif /* __KERNEL__ */ ++ ++typedef int (*fprintf_ftype) (void *, const char*, ...) ATTRIBUTE_FPTR_PRINTF_2; ++ ++enum dis_insn_type { ++ dis_noninsn, /* Not a valid instruction */ ++ dis_nonbranch, /* Not a branch instruction */ ++ dis_branch, /* Unconditional branch */ ++ dis_condbranch, /* Conditional branch */ ++ dis_jsr, /* Jump to subroutine */ ++ dis_condjsr, /* Conditional jump to subroutine */ ++ dis_dref, /* Data reference instruction */ ++ dis_dref2 /* Two data references in instruction */ ++}; ++ ++/* This struct is passed into the instruction decoding routine, ++ and is passed back out into each callback. The various fields are used ++ for conveying information from your main routine into your callbacks, ++ for passing information into the instruction decoders (such as the ++ addresses of the callback functions), or for passing information ++ back from the instruction decoders to their callers. ++ ++ It must be initialized before it is first passed; this can be done ++ by hand, or using one of the initialization macros below. */ ++ ++typedef struct disassemble_info { ++ fprintf_ftype fprintf_func; ++ void *stream; ++ void *application_data; ++ ++ /* Target description. We could replace this with a pointer to the bfd, ++ but that would require one. There currently isn't any such requirement ++ so to avoid introducing one we record these explicitly. */ ++ /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ ++ enum bfd_flavour flavour; ++ /* The bfd_arch value. */ ++ enum bfd_architecture arch; ++ /* The bfd_mach value. */ ++ unsigned long mach; ++ /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ ++ enum bfd_endian endian; ++ /* An arch/mach-specific bitmask of selected instruction subsets, mainly ++ for processors with run-time-switchable instruction sets. The default, ++ zero, means that there is no constraint. CGEN-based opcodes ports ++ may use ISA_foo masks. */ ++ unsigned long insn_sets; ++ ++ /* Some targets need information about the current section to accurately ++ display insns. If this is NULL, the target disassembler function ++ will have to make its best guess. */ ++ asection *section; ++ ++ /* An array of pointers to symbols either at the location being disassembled ++ or at the start of the function being disassembled. The array is sorted ++ so that the first symbol is intended to be the one used. The others are ++ present for any misc. purposes. This is not set reliably, but if it is ++ not NULL, it is correct. */ ++ asymbol **symbols; ++ /* Number of symbols in array. */ ++ int num_symbols; ++ ++ /* For use by the disassembler. ++ The top 16 bits are reserved for public use (and are documented here). ++ The bottom 16 bits are for the internal use of the disassembler. */ ++ unsigned long flags; ++#define INSN_HAS_RELOC 0x80000000 ++ void *private_data; ++ ++ /* Function used to get bytes to disassemble. MEMADDR is the ++ address of the stuff to be disassembled, MYADDR is the address to ++ put the bytes in, and LENGTH is the number of bytes to read. ++ INFO is a pointer to this struct. ++ Returns an errno value or 0 for success. */ ++ int (*read_memory_func) ++ (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, ++ struct disassemble_info *info); ++ ++ /* Function which should be called if we get an error that we can't ++ recover from. STATUS is the errno value from read_memory_func and ++ MEMADDR is the address that we were trying to read. INFO is a ++ pointer to this struct. */ ++ void (*memory_error_func) ++ (int status, bfd_vma memaddr, struct disassemble_info *info); ++ ++ /* Function called to print ADDR. */ ++ void (*print_address_func) ++ (bfd_vma addr, struct disassemble_info *info); ++ ++ /* Function called to determine if there is a symbol at the given ADDR. ++ If there is, the function returns 1, otherwise it returns 0. ++ This is used by ports which support an overlay manager where ++ the overlay number is held in the top part of an address. In ++ some circumstances we want to include the overlay number in the ++ address, (normally because there is a symbol associated with ++ that address), but sometimes we want to mask out the overlay bits. */ ++ int (* symbol_at_address_func) ++ (bfd_vma addr, struct disassemble_info * info); ++ ++ /* Function called to check if a SYMBOL is can be displayed to the user. ++ This is used by some ports that want to hide special symbols when ++ displaying debugging outout. */ ++ bfd_boolean (* symbol_is_valid) ++ (asymbol *, struct disassemble_info * info); ++ ++ /* These are for buffer_read_memory. */ ++ bfd_byte *buffer; ++ bfd_vma buffer_vma; ++ unsigned int buffer_length; ++ ++ /* This variable may be set by the instruction decoder. It suggests ++ the number of bytes objdump should display on a single line. If ++ the instruction decoder sets this, it should always set it to ++ the same value in order to get reasonable looking output. */ ++ int bytes_per_line; ++ ++ /* The next two variables control the way objdump displays the raw data. */ ++ /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ ++ /* output will look like this: ++ 00: 00000000 00000000 ++ with the chunks displayed according to "display_endian". */ ++ int bytes_per_chunk; ++ enum bfd_endian display_endian; ++ ++ /* Number of octets per incremented target address ++ Normally one, but some DSPs have byte sizes of 16 or 32 bits. */ ++ unsigned int octets_per_byte; ++ ++ /* The number of zeroes we want to see at the end of a section before we ++ start skipping them. */ ++ unsigned int skip_zeroes; ++ ++ /* The number of zeroes to skip at the end of a section. If the number ++ of zeroes at the end is between SKIP_ZEROES_AT_END and SKIP_ZEROES, ++ they will be disassembled. If there are fewer than ++ SKIP_ZEROES_AT_END, they will be skipped. This is a heuristic ++ attempt to avoid disassembling zeroes inserted by section ++ alignment. */ ++ unsigned int skip_zeroes_at_end; ++ ++ /* Results from instruction decoders. Not all decoders yet support ++ this information. This info is set each time an instruction is ++ decoded, and is only valid for the last such instruction. ++ ++ To determine whether this decoder supports this information, set ++ insn_info_valid to 0, decode an instruction, then check it. */ ++ ++ char insn_info_valid; /* Branch info has been set. */ ++ char branch_delay_insns; /* How many sequential insn's will run before ++ a branch takes effect. (0 = normal) */ ++ char data_size; /* Size of data reference in insn, in bytes */ ++ enum dis_insn_type insn_type; /* Type of instruction */ ++ bfd_vma target; /* Target address of branch or dref, if known; ++ zero if unknown. */ ++ bfd_vma target2; /* Second target address for dref2 */ ++ ++ /* Command line options specific to the target disassembler. */ ++ char * disassembler_options; ++ ++} disassemble_info; ++ ++ ++/* Standard disassemblers. Disassemble one instruction at the given ++ target address. Return number of octets processed. */ ++typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *); ++ ++extern int print_insn_big_mips (bfd_vma, disassemble_info *); ++extern int print_insn_little_mips (bfd_vma, disassemble_info *); ++extern int print_insn_i386 (bfd_vma, disassemble_info *); ++extern int print_insn_i386_att (bfd_vma, disassemble_info *); ++extern int print_insn_i386_intel (bfd_vma, disassemble_info *); ++extern int print_insn_ia64 (bfd_vma, disassemble_info *); ++extern int print_insn_i370 (bfd_vma, disassemble_info *); ++extern int print_insn_m68hc11 (bfd_vma, disassemble_info *); ++extern int print_insn_m68hc12 (bfd_vma, disassemble_info *); ++extern int print_insn_m68k (bfd_vma, disassemble_info *); ++extern int print_insn_z8001 (bfd_vma, disassemble_info *); ++extern int print_insn_z8002 (bfd_vma, disassemble_info *); ++extern int print_insn_h8300 (bfd_vma, disassemble_info *); ++extern int print_insn_h8300h (bfd_vma, disassemble_info *); ++extern int print_insn_h8300s (bfd_vma, disassemble_info *); ++extern int print_insn_h8500 (bfd_vma, disassemble_info *); ++extern int print_insn_alpha (bfd_vma, disassemble_info *); ++extern int print_insn_big_arm (bfd_vma, disassemble_info *); ++extern int print_insn_little_arm (bfd_vma, disassemble_info *); ++extern int print_insn_sparc (bfd_vma, disassemble_info *); ++extern int print_insn_big_a29k (bfd_vma, disassemble_info *); ++extern int print_insn_little_a29k (bfd_vma, disassemble_info *); ++extern int print_insn_avr (bfd_vma, disassemble_info *); ++extern int print_insn_d10v (bfd_vma, disassemble_info *); ++extern int print_insn_d30v (bfd_vma, disassemble_info *); ++extern int print_insn_dlx (bfd_vma, disassemble_info *); ++extern int print_insn_fr30 (bfd_vma, disassemble_info *); ++extern int print_insn_hppa (bfd_vma, disassemble_info *); ++extern int print_insn_i860 (bfd_vma, disassemble_info *); ++extern int print_insn_i960 (bfd_vma, disassemble_info *); ++extern int print_insn_ip2k (bfd_vma, disassemble_info *); ++extern int print_insn_m32r (bfd_vma, disassemble_info *); ++extern int print_insn_m88k (bfd_vma, disassemble_info *); ++extern int print_insn_maxq_little (bfd_vma, disassemble_info *); ++extern int print_insn_maxq_big (bfd_vma, disassemble_info *); ++extern int print_insn_mcore (bfd_vma, disassemble_info *); ++extern int print_insn_mmix (bfd_vma, disassemble_info *); ++extern int print_insn_mn10200 (bfd_vma, disassemble_info *); ++extern int print_insn_mn10300 (bfd_vma, disassemble_info *); ++extern int print_insn_ms1 (bfd_vma, disassemble_info *); ++extern int print_insn_msp430 (bfd_vma, disassemble_info *); ++extern int print_insn_ns32k (bfd_vma, disassemble_info *); ++extern int print_insn_crx (bfd_vma, disassemble_info *); ++extern int print_insn_openrisc (bfd_vma, disassemble_info *); ++extern int print_insn_big_or32 (bfd_vma, disassemble_info *); ++extern int print_insn_little_or32 (bfd_vma, disassemble_info *); ++extern int print_insn_pdp11 (bfd_vma, disassemble_info *); ++extern int print_insn_pj (bfd_vma, disassemble_info *); ++extern int print_insn_big_powerpc (bfd_vma, disassemble_info *); ++extern int print_insn_little_powerpc (bfd_vma, disassemble_info *); ++extern int print_insn_rs6000 (bfd_vma, disassemble_info *); ++extern int print_insn_s390 (bfd_vma, disassemble_info *); ++extern int print_insn_sh (bfd_vma, disassemble_info *); ++extern int print_insn_tic30 (bfd_vma, disassemble_info *); ++extern int print_insn_tic4x (bfd_vma, disassemble_info *); ++extern int print_insn_tic54x (bfd_vma, disassemble_info *); ++extern int print_insn_tic80 (bfd_vma, disassemble_info *); ++extern int print_insn_v850 (bfd_vma, disassemble_info *); ++extern int print_insn_vax (bfd_vma, disassemble_info *); ++extern int print_insn_w65 (bfd_vma, disassemble_info *); ++extern int print_insn_xstormy16 (bfd_vma, disassemble_info *); ++extern int print_insn_xtensa (bfd_vma, disassemble_info *); ++extern int print_insn_sh64 (bfd_vma, disassemble_info *); ++extern int print_insn_sh64x_media (bfd_vma, disassemble_info *); ++extern int print_insn_frv (bfd_vma, disassemble_info *); ++extern int print_insn_iq2000 (bfd_vma, disassemble_info *); ++extern int print_insn_m32c (bfd_vma, disassemble_info *); ++ ++extern disassembler_ftype arc_get_disassembler (void *); ++extern disassembler_ftype cris_get_disassembler (bfd *); ++ ++extern void print_mips_disassembler_options (FILE *); ++extern void print_ppc_disassembler_options (FILE *); ++extern void print_arm_disassembler_options (FILE *); ++extern void parse_arm_disassembler_option (char *); ++extern int get_arm_regname_num_options (void); ++extern int set_arm_regname_option (int); ++extern int get_arm_regnames (int, const char **, const char **, const char *const **); ++extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *); ++ ++/* Fetch the disassembler for a given BFD, if that support is available. */ ++extern disassembler_ftype disassembler (bfd *); ++ ++/* Amend the disassemble_info structure as necessary for the target architecture. ++ Should only be called after initialising the info->arch field. */ ++extern void disassemble_init_for_target (struct disassemble_info * info); ++ ++/* Document any target specific options available from the disassembler. */ ++extern void disassembler_usage (FILE *); ++ ++ ++/* This block of definitions is for particular callers who read instructions ++ into a buffer before calling the instruction decoder. */ ++ ++/* Here is a function which callers may wish to use for read_memory_func. ++ It gets bytes from a buffer. */ ++extern int buffer_read_memory ++ (bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *); ++ ++/* This function goes with buffer_read_memory. ++ It prints a message using info->fprintf_func and info->stream. */ ++extern void perror_memory (int, bfd_vma, struct disassemble_info *); ++ ++ ++/* Just print the address in hex. This is included for completeness even ++ though both GDB and objdump provide their own (to print symbolic ++ addresses). */ ++extern void generic_print_address ++ (bfd_vma, struct disassemble_info *); ++ ++/* Always true. */ ++extern int generic_symbol_at_address ++ (bfd_vma, struct disassemble_info *); ++ ++/* Also always true. */ ++extern bfd_boolean generic_symbol_is_valid ++ (asymbol *, struct disassemble_info *); ++ ++/* Method to initialize a disassemble_info struct. This should be ++ called by all applications creating such a struct. */ ++extern void init_disassemble_info (struct disassemble_info *info, void *stream, ++ fprintf_ftype fprintf_func); ++ ++/* For compatibility with existing code. */ ++#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ ++ init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC)) ++#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ ++ init_disassemble_info (&(INFO), (STREAM), (fprintf_ftype) (FPRINTF_FUNC)) ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ! defined (DIS_ASM_H) */ +--- /dev/null ++++ b/include/linux/kdb.h +@@ -0,0 +1,175 @@ ++#ifndef _KDB_H ++#define _KDB_H ++ ++/* ++ * Kernel Debugger Architecture Independent Global Headers ++ * ++ * 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) 2000-2007 Silicon Graphics, Inc. All Rights Reserved. ++ * Copyright (C) 2000 Stephane Eranian ++ */ ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_KDB ++/* These are really private, but they must be defined before including ++ * asm-$(ARCH)/kdb.h, so make them public and put them here. ++ */ ++extern int kdb_getuserarea_size(void *, unsigned long, size_t); ++extern int kdb_putuserarea_size(unsigned long, void *, size_t); ++ ++#include ++#endif ++ ++#define KDB_MAJOR_VERSION 4 ++#define KDB_MINOR_VERSION 4 ++#define KDB_TEST_VERSION "" ++ ++/* ++ * kdb_initial_cpu is initialized to -1, and is set to the cpu ++ * number whenever the kernel debugger is entered. ++ */ ++extern volatile int kdb_initial_cpu; ++extern atomic_t kdb_event; ++extern atomic_t kdb_8250; ++#ifdef CONFIG_KDB ++#define KDB_IS_RUNNING() (kdb_initial_cpu != -1) ++#define KDB_8250() (atomic_read(&kdb_8250) != 0) ++#else ++#define KDB_IS_RUNNING() (0) ++#define KDB_8250() (0) ++#endif /* CONFIG_KDB */ ++ ++/* ++ * kdb_on ++ * ++ * Defines whether kdb is on or not. Default value ++ * is set by CONFIG_KDB_OFF. Boot with kdb=on/off/on-nokey ++ * or echo "[012]" > /proc/sys/kernel/kdb to change it. ++ */ ++extern int kdb_on; ++ ++#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_SGI_L1_CONSOLE) ++/* ++ * kdb_serial.iobase is initialized to zero, and is set to the I/O ++ * address of the serial port when the console is setup in ++ * serial_console_setup. ++ */ ++extern struct kdb_serial { ++ int io_type; ++ unsigned long iobase; ++ unsigned long ioreg_shift; ++} kdb_serial; ++#endif ++ ++/* ++ * kdb_diemsg ++ * ++ * Contains a pointer to the last string supplied to the ++ * kernel 'die' panic function. ++ */ ++extern const char *kdb_diemsg; ++ ++#define KDB_FLAG_EARLYKDB (1 << 0) /* set from boot parameter kdb=early */ ++#define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */ ++#define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */ ++#define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */ ++#define KDB_FLAG_ONLY_DO_DUMP (1 << 4) /* Only do a dump, used when kdb is off */ ++#define KDB_FLAG_NO_CONSOLE (1 << 5) /* No console is available, kdb is disabled */ ++#define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do not use keyboard */ ++#define KDB_FLAG_NO_I8042 (1 << 7) /* No i8042 chip is available, do not use keyboard */ ++#define KDB_FLAG_RECOVERY (1 << 8) /* kdb is being entered for an error which has been recovered */ ++ ++extern volatile int kdb_flags; /* Global flags, see kdb_state for per cpu state */ ++ ++extern void kdb_save_flags(void); ++extern void kdb_restore_flags(void); ++ ++#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag) ++#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag)) ++#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag)) ++ ++/* ++ * External entry point for the kernel debugger. The pt_regs ++ * at the time of entry are supplied along with the reason for ++ * entry to the kernel debugger. ++ */ ++ ++typedef enum { ++ KDB_REASON_ENTER=1, /* KDB_ENTER() trap/fault - regs valid */ ++ KDB_REASON_ENTER_SLAVE, /* KDB_ENTER_SLAVE() trap/fault - regs valid */ ++ KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */ ++ KDB_REASON_DEBUG, /* Debug Fault - regs valid */ ++ KDB_REASON_OOPS, /* Kernel Oops - regs valid */ ++ KDB_REASON_SWITCH, /* CPU switch - regs valid*/ ++ KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */ ++ KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */ ++ KDB_REASON_RECURSE, /* Recursive entry to kdb; regs probably valid */ ++ KDB_REASON_CPU_UP, /* Add one cpu to kdb; regs invalid */ ++ KDB_REASON_SILENT, /* Silent entry/exit to kdb; regs invalid - internal only */ ++} kdb_reason_t; ++ ++#ifdef CONFIG_KDB ++extern int kdb(kdb_reason_t, int, struct pt_regs *); ++#else ++#define kdb(reason,error_code,frame) (0) ++#endif ++ ++/* Mainly used by kdb code, but this function is sometimes used ++ * by hacked debug code so make it generally available, not private. ++ */ ++extern void kdb_printf(const char *,...) ++ __attribute__ ((format (printf, 1, 2))); ++typedef void (*kdb_printf_t)(const char *, ...) ++ __attribute__ ((format (printf, 1, 2))); ++extern void kdb_init(void); ++ ++#if defined(CONFIG_SMP) ++/* ++ * Kernel debugger non-maskable IPI handler. ++ */ ++extern int kdb_ipi(struct pt_regs *, void (*ack_interrupt)(void)); ++extern void smp_kdb_stop(void); ++#else /* CONFIG_SMP */ ++#define smp_kdb_stop() ++#endif /* CONFIG_SMP */ ++ ++#ifdef CONFIG_KDB_USB ++ ++#include ++ ++extern int kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func); ++extern int kdb_usb_keyboard_detach(struct urb *urb); ++ ++#endif /* CONFIG_KDB_USB */ ++ ++static inline ++int kdb_process_cpu(const struct task_struct *p) ++{ ++ unsigned int cpu = task_thread_info(p)->cpu; ++ if (cpu > NR_CPUS) ++ cpu = 0; ++ return cpu; ++} ++ ++extern const char kdb_serial_str[]; ++ ++#ifdef CONFIG_KDB_KDUMP ++/* Define values for kdb_kdump_state */ ++extern int kdb_kdump_state; /* KDB kdump state */ ++#define KDB_KDUMP_RESET 0 ++#define KDB_KDUMP_KDUMP 1 ++ ++void kdba_kdump_prepare(struct pt_regs *); ++void machine_crash_shutdown(struct pt_regs *); ++void machine_crash_shutdown_begin(void); ++void machine_crash_shutdown_end(struct pt_regs *); ++ ++#endif /* CONFIG_KDB_KDUMP */ ++ ++#endif /* !_KDB_H */ +--- /dev/null ++++ b/include/linux/kdbprivate.h +@@ -0,0 +1,503 @@ ++#ifndef _KDBPRIVATE_H ++#define _KDBPRIVATE_H ++ ++/* ++ * Kernel Debugger Architecture Independent Private Headers ++ * ++ * 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) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++ ++#include ++#include ++#include ++ ++ /* ++ * Kernel Debugger Error codes. Must not overlap with command codes. ++ */ ++ ++#define KDB_NOTFOUND (-1) ++#define KDB_ARGCOUNT (-2) ++#define KDB_BADWIDTH (-3) ++#define KDB_BADRADIX (-4) ++#define KDB_NOTENV (-5) ++#define KDB_NOENVVALUE (-6) ++#define KDB_NOTIMP (-7) ++#define KDB_ENVFULL (-8) ++#define KDB_ENVBUFFULL (-9 ) ++#define KDB_TOOMANYBPT (-10) ++#define KDB_TOOMANYDBREGS (-11) ++#define KDB_DUPBPT (-12) ++#define KDB_BPTNOTFOUND (-13) ++#define KDB_BADMODE (-14) ++#define KDB_BADINT (-15) ++#define KDB_INVADDRFMT (-16) ++#define KDB_BADREG (-17) ++#define KDB_BADCPUNUM (-18) ++#define KDB_BADLENGTH (-19) ++#define KDB_NOBP (-20) ++#define KDB_BADADDR (-21) ++ ++ /* ++ * Kernel Debugger Command codes. Must not overlap with error codes. ++ */ ++#define KDB_CMD_GO (-1001) ++#define KDB_CMD_CPU (-1002) ++#define KDB_CMD_SS (-1003) ++#define KDB_CMD_SSB (-1004) ++ ++ /* ++ * Internal debug flags ++ */ ++/* KDB_DEBUG_FLAG_BT 0x0001 Was Stack traceback debug */ ++#define KDB_DEBUG_FLAG_BP 0x0002 /* Breakpoint subsystem debug */ ++#define KDB_DEBUG_FLAG_BB_SUMM 0x0004 /* Basic block analysis, summary only */ ++#define KDB_DEBUG_FLAG_AR 0x0008 /* Activation record, generic */ ++#define KDB_DEBUG_FLAG_ARA 0x0010 /* Activation record, arch specific */ ++#define KDB_DEBUG_FLAG_BB 0x0020 /* All basic block analysis */ ++#define KDB_DEBUG_FLAG_STATE 0x0040 /* State flags */ ++#define KDB_DEBUG_FLAG_MASK 0xffff /* All debug flags */ ++#define KDB_DEBUG_FLAG_SHIFT 16 /* Shift factor for dbflags */ ++ ++#define KDB_DEBUG(flag) (kdb_flags & (KDB_DEBUG_FLAG_##flag << KDB_DEBUG_FLAG_SHIFT)) ++#define KDB_DEBUG_STATE(text,value) if (KDB_DEBUG(STATE)) kdb_print_state(text, value) ++ ++typedef enum { ++ KDB_REPEAT_NONE = 0, /* Do not repeat this command */ ++ KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */ ++ KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */ ++} kdb_repeat_t; ++ ++typedef int (*kdb_func_t)(int, const char **); ++ ++ /* ++ * Symbol table format returned by kallsyms. ++ */ ++ ++typedef struct __ksymtab { ++ unsigned long value; /* Address of symbol */ ++ const char *mod_name; /* Module containing symbol or "kernel" */ ++ unsigned long mod_start; ++ unsigned long mod_end; ++ const char *sec_name; /* Section containing symbol */ ++ unsigned long sec_start; ++ unsigned long sec_end; ++ const char *sym_name; /* Full symbol name, including any version */ ++ unsigned long sym_start; ++ unsigned long sym_end; ++ } kdb_symtab_t; ++extern int kallsyms_symbol_next(char *prefix_name, int flag); ++extern int kallsyms_symbol_complete(char *prefix_name, int max_len); ++ ++ /* ++ * Exported Symbols for kernel loadable modules to use. ++ */ ++extern int kdb_register(char *, kdb_func_t, char *, char *, short); ++extern int kdb_register_repeat(char *, kdb_func_t, char *, char *, short, kdb_repeat_t); ++extern int kdb_unregister(char *); ++ ++extern int kdb_getarea_size(void *, unsigned long, size_t); ++extern int kdb_putarea_size(unsigned long, void *, size_t); ++ ++/* Like get_user and put_user, kdb_getarea and kdb_putarea take variable ++ * names, not pointers. The underlying *_size functions take pointers. ++ */ ++#define kdb_getarea(x,addr) kdb_getarea_size(&(x), addr, sizeof((x))) ++#define kdb_putarea(addr,x) kdb_putarea_size(addr, &(x), sizeof((x))) ++ ++extern int kdb_getphysword(unsigned long *word, ++ unsigned long addr, size_t size); ++extern int kdb_getword(unsigned long *, unsigned long, size_t); ++extern int kdb_putword(unsigned long, unsigned long, size_t); ++ ++extern int kdbgetularg(const char *, unsigned long *); ++extern char *kdbgetenv(const char *); ++extern int kdbgetintenv(const char *, int *); ++extern int kdbgetaddrarg(int, const char**, int*, unsigned long *, ++ long *, char **); ++extern int kdbgetsymval(const char *, kdb_symtab_t *); ++extern int kdbnearsym(unsigned long, kdb_symtab_t *); ++extern void kdbnearsym_cleanup(void); ++extern char *kdb_read(char *buffer, size_t bufsize); ++extern char *kdb_strdup(const char *str, gfp_t type); ++extern void kdb_symbol_print(kdb_machreg_t, const kdb_symtab_t *, unsigned int); ++ ++ /* ++ * Do we have a set of registers? ++ */ ++ ++#define KDB_NULL_REGS(regs) \ ++ (regs == (struct pt_regs *)NULL ? kdb_printf("%s: null regs - should never happen\n", __FUNCTION__), 1 : 0) ++ ++ /* ++ * Routine for debugging the debugger state. ++ */ ++ ++extern void kdb_print_state(const char *, int); ++ ++ /* ++ * Per cpu kdb state. A cpu can be under kdb control but outside kdb, ++ * for example when doing single step. ++ */ ++volatile extern int kdb_state[ /*NR_CPUS*/ ]; ++#define KDB_STATE_KDB 0x00000001 /* Cpu is inside kdb */ ++#define KDB_STATE_LEAVING 0x00000002 /* Cpu is leaving kdb */ ++#define KDB_STATE_CMD 0x00000004 /* Running a kdb command */ ++#define KDB_STATE_KDB_CONTROL 0x00000008 /* This cpu is under kdb control */ ++#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */ ++#define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */ ++#define KDB_STATE_DOING_SSB 0x00000040 /* Doing ssb command, DOING_SS is also set */ ++#define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint after one ss, independent of DOING_SS */ ++#define KDB_STATE_REENTRY 0x00000100 /* Valid re-entry into kdb */ ++#define KDB_STATE_SUPPRESS 0x00000200 /* Suppress error messages */ ++#define KDB_STATE_LONGJMP 0x00000400 /* longjmp() data is available */ ++#define KDB_STATE_GO_SWITCH 0x00000800 /* go is switching back to initial cpu */ ++#define KDB_STATE_PRINTF_LOCK 0x00001000 /* Holds kdb_printf lock */ ++#define KDB_STATE_WAIT_IPI 0x00002000 /* Waiting for kdb_ipi() NMI */ ++#define KDB_STATE_RECURSE 0x00004000 /* Recursive entry to kdb */ ++#define KDB_STATE_IP_ADJUSTED 0x00008000 /* Restart IP has been adjusted */ ++#define KDB_STATE_GO1 0x00010000 /* go only releases one cpu */ ++#define KDB_STATE_KEYBOARD 0x00020000 /* kdb entered via keyboard on this cpu */ ++#define KDB_STATE_KEXEC 0x00040000 /* kexec issued */ ++#define KDB_STATE_ARCH 0xff000000 /* Reserved for arch specific use */ ++ ++#define KDB_STATE_CPU(flag,cpu) (kdb_state[cpu] & KDB_STATE_##flag) ++#define KDB_STATE_SET_CPU(flag,cpu) ((void)(kdb_state[cpu] |= KDB_STATE_##flag)) ++#define KDB_STATE_CLEAR_CPU(flag,cpu) ((void)(kdb_state[cpu] &= ~KDB_STATE_##flag)) ++ ++#define KDB_STATE(flag) KDB_STATE_CPU(flag,smp_processor_id()) ++#define KDB_STATE_SET(flag) KDB_STATE_SET_CPU(flag,smp_processor_id()) ++#define KDB_STATE_CLEAR(flag) KDB_STATE_CLEAR_CPU(flag,smp_processor_id()) ++ ++ /* ++ * kdb_nextline ++ * ++ * Contains the current line number on the screen. Used ++ * to handle the built-in pager (LINES env variable) ++ */ ++extern volatile int kdb_nextline; ++ ++ /* ++ * Breakpoint state ++ * ++ * Each active and inactive breakpoint is represented by ++ * an instance of the following data structure. ++ */ ++ ++typedef struct _kdb_bp { ++ bfd_vma bp_addr; /* Address breakpoint is present at */ ++ kdb_machinst_t bp_inst; /* Replaced instruction */ ++ ++ unsigned int bp_free:1; /* This entry is available */ ++ ++ unsigned int bp_enabled:1; /* Breakpoint is active in register */ ++ unsigned int bp_global:1; /* Global to all processors */ ++ ++ unsigned int bp_hardtype:1; /* Uses hardware register */ ++ unsigned int bp_forcehw:1; /* Force hardware register */ ++ unsigned int bp_installed:1; /* Breakpoint is installed */ ++ unsigned int bp_delay:1; /* Do delayed bp handling */ ++ unsigned int bp_delayed:1; /* Delayed breakpoint */ ++ ++ int bp_cpu; /* Cpu # (if bp_global == 0) */ ++ kdbhard_bp_t bp_template; /* Hardware breakpoint template */ ++ kdbhard_bp_t *bp_hard[NR_CPUS]; /* Hardware breakpoint structure */ ++ int bp_adjust; /* Adjustment to PC for real instruction */ ++} kdb_bp_t; ++ ++ /* ++ * Breakpoint handling subsystem global variables ++ */ ++extern kdb_bp_t kdb_breakpoints[/* KDB_MAXBPT */]; ++ ++ /* ++ * Breakpoint architecture dependent functions. Must be provided ++ * in some form for all architectures. ++ */ ++extern void kdba_initbp(void); ++extern void kdba_printbp(kdb_bp_t *); ++extern void kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp); ++extern void kdba_free_hwbp(kdb_bp_t *bp); ++extern int kdba_parsebp(int, const char**, int *, kdb_bp_t*); ++extern char *kdba_bptype(kdbhard_bp_t *); ++extern void kdba_setsinglestep(struct pt_regs *); ++extern void kdba_clearsinglestep(struct pt_regs *); ++ ++ /* ++ * Adjust instruction pointer architecture dependent function. Must be ++ * provided in some form for all architectures. ++ */ ++extern void kdba_adjust_ip(kdb_reason_t, int, struct pt_regs *); ++ ++ /* ++ * KDB-only global function prototypes. ++ */ ++extern void kdb_id1(unsigned long); ++extern void kdb_id_init(void); ++ ++ /* ++ * Initialization functions. ++ */ ++extern void kdba_init(void); ++extern void kdb_io_init(void); ++ ++ /* ++ * Architecture specific function to read a string. ++ */ ++typedef int (*get_char_func)(void); ++extern get_char_func poll_funcs[]; ++ ++#ifndef CONFIG_IA64 ++ /* ++ * Data for a single activation record on stack. ++ */ ++ ++struct kdb_stack_info { ++ kdb_machreg_t physical_start; ++ kdb_machreg_t physical_end; ++ kdb_machreg_t logical_start; ++ kdb_machreg_t logical_end; ++ kdb_machreg_t next; ++ const char * id; ++}; ++ ++typedef struct { DECLARE_BITMAP(bits, KDBA_MAXARGS); } valid_t; ++ ++struct kdb_activation_record { ++ struct kdb_stack_info stack; /* information about current stack */ ++ int args; /* number of arguments detected */ ++ kdb_machreg_t arg[KDBA_MAXARGS]; /* -> arguments */ ++ valid_t valid; /* is argument n valid? */ ++}; ++#endif ++ ++ /* ++ * Architecture specific Stack Traceback functions. ++ */ ++ ++struct task_struct; ++ ++extern int kdba_bt_address(kdb_machreg_t, int); ++extern int kdba_bt_process(const struct task_struct *, int); ++ ++ /* ++ * KDB Command Table ++ */ ++ ++typedef struct _kdbtab { ++ char *cmd_name; /* Command name */ ++ kdb_func_t cmd_func; /* Function to execute command */ ++ char *cmd_usage; /* Usage String for this command */ ++ char *cmd_help; /* Help message for this command */ ++ short cmd_flags; /* Parsing flags */ ++ short cmd_minlen; /* Minimum legal # command chars required */ ++ kdb_repeat_t cmd_repeat; /* Does command auto repeat on enter? */ ++} kdbtab_t; ++ ++ /* ++ * External command function declarations ++ */ ++ ++extern int kdb_id(int, const char **); ++extern int kdb_bt(int, const char **); ++ ++ /* ++ * External utility function declarations ++ */ ++extern char* kdb_getstr(char *, size_t, char *); ++ ++ /* ++ * Register contents manipulation ++ */ ++extern int kdba_getregcontents(const char *, struct pt_regs *, kdb_machreg_t *); ++extern int kdba_setregcontents(const char *, struct pt_regs *, kdb_machreg_t); ++extern int kdba_dumpregs(struct pt_regs *, const char *, const char *); ++extern int kdba_setpc(struct pt_regs *, kdb_machreg_t); ++extern kdb_machreg_t kdba_getpc(struct pt_regs *); ++ ++ /* ++ * Debug register handling. ++ */ ++extern void kdba_installdbreg(kdb_bp_t*); ++extern void kdba_removedbreg(kdb_bp_t*); ++ ++ /* ++ * Breakpoint handling - External interfaces ++ */ ++extern void kdb_initbptab(void); ++extern void kdb_bp_install_global(struct pt_regs *); ++extern void kdb_bp_install_local(struct pt_regs *); ++extern void kdb_bp_remove_global(void); ++extern void kdb_bp_remove_local(void); ++ ++ /* ++ * Breakpoint handling - Internal to kdb_bp.c/kdba_bp.c ++ */ ++extern int kdba_installbp(struct pt_regs *regs, kdb_bp_t *); ++extern int kdba_removebp(kdb_bp_t *); ++ ++ ++typedef enum { ++ KDB_DB_BPT, /* Breakpoint */ ++ KDB_DB_SS, /* Single-step trap */ ++ KDB_DB_SSB, /* Single step to branch */ ++ KDB_DB_SSBPT, /* Single step over breakpoint */ ++ KDB_DB_NOBPT /* Spurious breakpoint */ ++} kdb_dbtrap_t; ++ ++extern kdb_dbtrap_t kdba_db_trap(struct pt_regs *, int); /* DEBUG trap/fault handler */ ++extern kdb_dbtrap_t kdba_bp_trap(struct pt_regs *, int); /* Breakpoint trap/fault hdlr */ ++ ++ /* ++ * Interrupt Handling ++ */ ++typedef unsigned long kdb_intstate_t; ++ ++extern void kdba_disableint(kdb_intstate_t *); ++extern void kdba_restoreint(kdb_intstate_t *); ++ ++ /* ++ * SMP and process stack manipulation routines. ++ */ ++extern int kdba_ipi(struct pt_regs *, void (*)(void)); ++extern int kdba_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, struct pt_regs *); ++extern int kdb_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, struct pt_regs *); ++ ++ /* ++ * General Disassembler interfaces ++ */ ++extern int kdb_dis_fprintf(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); ++extern int kdb_dis_fprintf_dummy(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); ++extern disassemble_info kdb_di; ++ ++ /* ++ * Architecture Dependent Disassembler interfaces ++ */ ++extern int kdba_id_printinsn(kdb_machreg_t, disassemble_info *); ++extern int kdba_id_parsemode(const char *, disassemble_info*); ++extern void kdba_id_init(disassemble_info *); ++extern void kdba_check_pc(kdb_machreg_t *); ++ ++ /* ++ * Miscellaneous functions and data areas ++ */ ++extern char *kdb_cmds[]; ++extern void kdb_syslog_data(char *syslog_data[]); ++extern unsigned long kdb_task_state_string(const char *); ++extern char kdb_task_state_char (const struct task_struct *); ++extern unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask); ++extern void kdb_ps_suppressed(void); ++extern void kdb_ps1(const struct task_struct *p); ++extern int kdb_parse(const char *cmdstr); ++extern void kdb_print_nameval(const char *name, unsigned long val); ++extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info, int seqno); ++#ifdef CONFIG_SWAP ++extern void kdb_si_swapinfo(struct sysinfo *); ++#else ++#include ++#define kdb_si_swapinfo(x) si_swapinfo(x) ++#endif ++extern void kdb_meminfo_read_proc(void); ++#ifdef CONFIG_HUGETLB_PAGE ++extern void kdb_hugetlb_report_meminfo(void); ++#endif /* CONFIG_HUGETLB_PAGE */ ++extern const char *kdb_walk_kallsyms(loff_t *pos); ++ ++ /* ++ * Architecture Dependant Local Processor setup & cleanup interfaces ++ */ ++extern void kdba_local_arch_setup(void); ++extern void kdba_local_arch_cleanup(void); ++ ++ /* ++ * Defines for kdb_symbol_print. ++ */ ++#define KDB_SP_SPACEB 0x0001 /* Space before string */ ++#define KDB_SP_SPACEA 0x0002 /* Space after string */ ++#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */ ++#define KDB_SP_VALUE 0x0008 /* Print the value of the address */ ++#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */ ++#define KDB_SP_NEWLINE 0x0020 /* Newline after string */ ++#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN) ++ ++/* Save data about running processes */ ++ ++struct kdb_running_process { ++ struct task_struct *p; ++ struct pt_regs *regs; ++ int seqno; /* kdb sequence number */ ++ int irq_depth; /* irq count */ ++ struct kdba_running_process arch; /* arch dependent save data */ ++}; ++ ++extern struct kdb_running_process kdb_running_process[/* NR_CPUS */]; ++ ++extern int kdb_save_running(struct pt_regs *, kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t); ++extern void kdb_unsave_running(struct pt_regs *); ++extern struct task_struct *kdb_curr_task(int); ++ ++/* Incremented each time the main kdb loop is entered on the initial cpu, ++ * it gives some indication of how old the saved data is. ++ */ ++extern int kdb_seqno; ++ ++#define kdb_task_has_cpu(p) (task_curr(p)) ++extern void kdb_runqueue(unsigned long cpu, kdb_printf_t xxx_printf); ++ ++/* Simplify coexistence with NPTL */ ++#define kdb_do_each_thread(g, p) do_each_thread(g, p) ++#define kdb_while_each_thread(g, p) while_each_thread(g, p) ++ ++#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) ++ ++extern void *debug_kmalloc(size_t size, gfp_t flags); ++extern void debug_kfree(void *); ++extern void debug_kusage(void); ++ ++extern void kdba_set_current_task(const struct task_struct *); ++extern const struct task_struct *kdb_current_task; ++extern struct pt_regs *kdb_current_regs; ++ ++/* Functions to safely read and write kernel areas. The {to,from}_xxx ++ * addresses are not necessarily valid, these functions must check for ++ * validity. If the arch already supports get and put routines with suitable ++ * validation and/or recovery on invalid addresses then use those routines, ++ * otherwise check it yourself. ++ */ ++ ++extern int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size); ++extern int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size); ++extern int kdba_verify_rw(unsigned long addr, size_t size); ++ ++#ifndef KDB_RUNNING_PROCESS_ORIGINAL ++#define KDB_RUNNING_PROCESS_ORIGINAL kdb_running_process ++#endif ++ ++extern int kdb_wait_for_cpus_secs; ++extern void kdba_cpu_up(void); ++extern char kdb_prompt_str[]; ++ ++#define KDB_WORD_SIZE ((int)sizeof(kdb_machreg_t)) ++ ++#ifdef CONFIG_KDB_USB ++#include ++ ++struct kdb_usb_kbd_info { ++ struct urb *urb; /* pointer to the URB */ ++ unsigned char *buffer; /* pointer to the kbd char buffer */ ++ int (*poll_func)(struct urb *urb); /* poll function to retrieve chars */ ++ int poll_ret; /* return val from poll_func */ ++ int caps_lock; /* state of the caps lock for this keyboard */ ++}; ++#endif /* CONFIG_KDB_USB */ ++ ++#ifdef CONFIG_KDB_KDUMP ++#define KDUMP_REASON_RESET 0 ++extern void kdba_kdump_shutdown_slave(struct pt_regs *); ++#endif /* CONFIG_KDB_KDUMP */ ++ ++#endif /* !_KDBPRIVATE_H */ +--- a/include/linux/reboot.h ++++ b/include/linux/reboot.h +@@ -53,7 +53,14 @@ extern void machine_power_off(void); + + extern void machine_shutdown(void); + struct pt_regs; ++#ifdef CONFIG_KDB_KDUMP + extern void machine_crash_shutdown(struct pt_regs *); ++extern void machine_crash_shutdown_begin(void); ++extern void machine_crash_shutdown_other_cpu(struct pt_regs *); ++extern void machine_crash_shutdown_end(struct pt_regs *); ++#else ++extern void machine_crash_shutdown(struct pt_regs *); ++#endif /* !CONFIG_KDB_KDUMP */ + + /* + * Architecture independent implemenations of sys_reboot commands. +--- a/include/linux/sysctl.h ++++ b/include/linux/sysctl.h +@@ -163,6 +163,7 @@ enum + KERN_MAX_LOCK_DEPTH=74, + KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */ + KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */ ++ KERN_KDB=77, /* int: kdb on/off */ + }; + + +--- a/init/main.c ++++ b/init/main.c +@@ -71,6 +71,10 @@ + #include + #endif + ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ ++ + /* + * This is one of the first .c files built. Error out early if we have compiler + * trouble. +@@ -193,6 +197,26 @@ static const char *panic_later, *panic_p + + extern struct obs_kernel_param __setup_start[], __setup_end[]; + ++#ifdef CONFIG_KDB ++static int __init kdb_setup(char *str) ++{ ++ if (strcmp(str, "on") == 0) { ++ kdb_on = 1; ++ } else if (strcmp(str, "on-nokey") == 0) { ++ kdb_on = 2; ++ } else if (strcmp(str, "off") == 0) { ++ kdb_on = 0; ++ } else if (strcmp(str, "early") == 0) { ++ kdb_on = 1; ++ kdb_flags |= KDB_FLAG_EARLYKDB; ++ } else ++ printk("kdb flag %s not recognised\n", str); ++ return 0; ++} ++ ++__setup("kdb=", kdb_setup); ++#endif /* CONFIG_KDB */ ++ + static int __init obsolete_checksetup(char *line) + { + struct obs_kernel_param *p; +@@ -659,6 +683,14 @@ asmlinkage void __init start_kernel(void + pgtable_cache_init(); + prio_tree_init(); + anon_vma_init(); ++ ++#ifdef CONFIG_KDB ++ kdb_init(); ++ if (KDB_FLAG(EARLYKDB)) { ++ KDB_ENTER(); ++ } ++#endif /* CONFIG_KDB */ ++ + #ifdef CONFIG_X86 + if (efi_enabled) + efi_enter_virtual_mode(); +--- /dev/null ++++ b/kdb/ChangeLog +@@ -0,0 +1,2012 @@ ++2008-09-30 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc8-common-1. ++ ++2008-09-22 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc7-common-1. ++ ++2008-09-03 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc5-common-1. ++ ++2008-08-19 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc3-common-1. ++ ++2008-08-15 Jay Lan ++ ++ * mm_online_pgdat_export_symbol, Jay Lan ++ - Fix compilation error by exporting first_online_pgdat & ++ next_online_pgdat for 'pgdat' command. ++ * kdb-v4.4-2.6.27-rc2-common-2.1. ++ ++2008-08-14 Jay Lan ++ ++ * Support 'kdump' command to take a kdump vmcore from KDB, ++ Dan Aloni (da-x@monatomic.org), ++ Jason Xiao (jidong.xiao@gmail.com), ++ Jay Lan (jlan@sgi.com) ++ * kdb-v4.4-2.6.27-rc2-common-2. ++ ++2008-08-06 Jay Lan ++ ++ * Fix up the NULL pointer deference issue in ohci_kdb_poll_char, ++ Jason Xiao ++ * kdb-v4.4-2.6.27-rc2-common-1. ++ ++2008-07-18 Jay Lan ++ ++ * support Hardware Breakpoint (bph/bpha) commands ++ IA64: Greg Banks ++ X86: Konstantin Baydarov ++ * kdb-v4.4-2.6.26-common-2. ++ ++2008-07-14 Jay Lan ++ ++ * kdb-v4.4-2.6.26-common-1. ++ ++2008-07-11 Jay Lan ++ ++ * New commands and some fixups and enhancements, ++ Joe Korty ++ John Blackwood ++ Jim Houston ++ - Use the non-sleeping copy_from_user_atomic. ++ - Enhance kdb_cmderror diagnostic output. ++ - Expand the KDB 'duplicate command' error message. ++ - Touch NMI watchdog in various KDB busy-loops. ++ - Support IMB HS20 Blade 8843 platform. ++ - Display exactly which cpus needed an NMI to get them into kdb. ++ - Better document that kdb's 'ps A' command can be used to show ++ _all_ processes and threads ++ - Suppress KDB boottime INFO messages if quiet boot. ++ - Add a KDB breakpoint to the OOPs path. ++ - Add CONFIG_DISCONTIGMEM support to kdbm_memmap. ++ - Extend the KDB task command to handle CONFIG_NUMA fields. ++ - Extend the KDB vm command to support NUMA stuff. ++ - Create the KDB mempolicy command. ++ - Create a pgdat command for KDB. ++ - Fix a hang on boot on some i386 systems. ++ * kdb-v4.4-2.6.26-rc9-common-1. ++ ++2008-06-30 Jay Lan ++ ++ * compilation warning cleanup, Cliff Wickman ++ * kdb-v4.4-2.6.26-rc8-common-1. ++ ++2008-06-25 Jay Lan ++ ++ * Added John Blackwood to the authors of ++ kdb-v4.4-2.6.26-rc4-common-2. ++ * kdb-v4.4-2.6.26-rc7-common-1. ++ ++2008-06-24 Jay Lan ++ ++ * support lcrash style debug_info file: Cliff Wickman ++ - It adds to kdb the ability to symbolically dereference structure ++ pointers through a lcrash-style debug_info file. ++ - Implements "print", "px", and "pd" print commands. ++ - Implements "walk" command to follow linked lists. ++ - Implements "whatis" to display a structure (with offsets). ++ - Implements "sizeof" for types (structures, typedefs, etc.). ++ * kdb-v4.4-2.6.26-rc5-common-2. ++ ++2008-06-06 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc5-common-1. ++ ++2008-06-05 Jay Lan ++ ++ * fixed 'rq/rqa' command runs off the end of runqueue's rt.active ++ priority bitmap array, John Blackwood & ++ Lachlan McIlroy ++ * kdb-v4.4-2.6.26-rc4-common-2. ++ ++2008-05-30 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc4-common-1. ++ ++2008-05-20 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc3-common-1. ++ ++2008-05-13 Jay Lan ++ ++ * XPC support is removed from KDB due to XPC changes in 2.6.26-rc1. ++ * kdb-v4.4-2.6.26-rc1-common-1. ++ ++2008-04-17 Jay Lan ++ ++ * kdb-v4.4-2.6.25-common-1. ++ ++2008-03-16 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc6-common-1. ++ ++2008-03-03 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc3-common-1. ++ ++2008-02-26 Jay Lan ++ ++ * remove 'fastcall' from kdb code. ++ * kdb-v4.4-2.6.25-rc2-common-1. ++ ++2008-02-19 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc1-common-1. ++ ++2008-02-06 Jay Lan ++ ++ * Backed out USB UHCI support since it caused dropped characters and ++ broke OHCI. ++ * Restored "archkdbcommon" commands for x86. It was lost at the x86 ++ merge. ++ * Detecting if the HC was "busy", Aaron Young ++ * kdb-v4.4-2.6.24-common-2. ++ ++2008-01-29 Jay Lan ++ ++ * kdb-v4.4-2.6.24-common-1. ++ ++2008-01-22 Jay Lan ++ ++ * USB UHCI kdb support, Konstantin Baydarov ++ * kdb-v4.4-2.6.24-rc8-common-3. ++ ++2008-01-18 Jay Lan ++ ++ * USB EHCI kdb support, Aaron Young ++ * kdb-v4.4-2.6.24-rc8-common-2. ++ ++2008-01-18 Jay Lan ++ ++ * kdb-v4.4-2.6.24-rc8-common-1. ++ ++2008-01-07 Jay Lan ++ ++ * kdb-v4.4-2.6.24-rc7-common-1. ++ ++2007-12-21 Jay Lan ++ ++ * Renamed kdb/kdba_bt_x86.c to arch/x86/kdba_bt.c. And thus, the x86 ++ backtrace code is now moved into the kdb x86 patch. ++ * kdb v4.4-2.6.24-rc6-common-1. ++ ++2007-12-12 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc5-common-1. ++ ++2007-12-05 Jay Lan ++ ++ * Fixed a 'sysctl table check failed' problem. ++ * kdb v4.4-2.6.24-rc4-common-1. ++ ++2007-11-26 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc3-common-1. ++ ++2007-11-13 Jay Lan ++ ++ * Back ported "New KDB USB interface" from Aaron Young in ++ v4.4-2.6.23-common-2 to 2.6.24 kdb patchset. ++ * kdb v4.4-2.6.24-rc2-common-2. ++ ++2007-11-12 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc2-common-1. ++ ++2007-11-09 Jay Lan ++ ++ * Rebase to 2.6.24-rc1 kernel ++ * - merged kdb-v4.4-2.6.23-i386-1 and kdb-v4.4-2.6.23-x86_64-1 ++ * into kdb-v4.4-2.6.24-rc1-x86-1 ++ * - Fields "done", "sglist_len", and "pid" are removed from ++ * struct scsi_cmnd. Thus, these fields are no longer displayed ++ * on "sc" command. ++ * kdb v4.4-2.6.24-rc1-common-1. ++ ++2007-11-08 Jay Lan ++ ++ * New KDB USB interface, Aaron Young ++ * 1. This patch allows KDB to work with any Host Contoller driver ++ * and call the correct HC driver poll routine (as long as the ++ * HC driver provides a .kdb_poll_char routine via it's ++ * associated hc_driver struct). ++ * 2. Hotplugged keyboards are now recognized by KDB. ++ * 3. Currently KDB can only make use of 1 USB type keyboard. ++ * New code can handle up to 8 attached keyboards - input is ++ * multiplexed from all of them while in kdb. ++ * kdb v4.4-2.6.23-common-2. ++ ++2007-10-24 Jay Lan ++ ++ * kdb v4.4-2.6.23-common-1. ++ ++2007-09-26 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc8-common-1. ++ ++2007-09-21 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc7-common-1. ++ ++2007-09-12 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc6-common-1. ++ ++2007-09-06 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc5-common-1. ++ ++2007-08-30 Keith Owens ++ ++ * New i386/x86_64 backtrace requires that kdb_save_running() does not ++ exit until after kdb_main_loop() has completed. ++ * List more noret functions in i386/x86_64 backtrace code. ++ * Call to a noret function ends a basic block. ++ * After a call to a noret function, eip/rip may be pointing at the next ++ function or not, depending on function alignment. Jay Lan. ++ * kdb v4.4-2.6.23-rc4-common-2. ++ ++2007-08-30 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc4-common-1. ++ ++2007-08-28 Keith Owens ++ ++ * kdb/kdba_bt_x86.c: ++ * Handle the variable amount of stack data that is pushed by x86_64 ++ * hardware on an interrupt. ++ * Add instruction vmsave. ++ * Handle pop to %rsp. ++ * Cope with return address for functions defined as ATTRIB_NORET. ++ * Include CONFIG_DEBUG_INFO in the summary line of bb_all. ++ * Check for an interrupt that was delivered while user space was in ++ * control. ++ * A return to child_rip ends a backtrace. ++ * Ignore level2_kernel_pgt and level3_kernel_pgt data areas if they ++ * occur within the text segment. ++ * kdb v4.4-2.6.23-rc3-common-2. ++ ++2007-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc3-common-1. ++ ++2007-08-24 Jay Lan ++ ++ * kdb/kdba_bt_x86.c: ++ * retint_kernel is only defined for CONFIG_PREEMPT. ++ * Handle assembler code for CONFIG_HIBERNATION=y. ++ * Handle assembler code for CONFIG_MATH_EMULATION=y. ++ * Handle assembler code for CONFIG_XEN=y. ++ * Handle assembler code for CONFIG_KPROBES=y. ++ * Add CC version to the bb_all header. ++ * Handle spurious label in jprobe_return. ++ * Handle stack switch in jprobe_return. ++ * Prefix register name with '%' in xadd/xchg temporary variable. ++ * Require bb_usage_mov() to handle all the special cases internally. ++ * Handle stack manipulation for kexec. ++ * Handle spurious label in kretprobe_trampoline_holder. ++ * Add instructions clgi, invlpga, rcl, rdpmc, stgi, vmclear, ++ * vmlaunch, vmload, vmptrld, vmread, vmresume, vmrun, vmwrite, ++ * xstore-rng. ++ * Exclude more 16 bit and/or real mode acpi functions from bb_all. ++ * Handle assembler stack switching code in i386 do_softirq. ++ * kdb/kdbmain.c: ++ * Add CC version to the summary output. ++ * Bump debug_kmalloc pool from 128K to 256K, some of the kernel ++ * functions have huge numbers of basic blocks and jumps between them. ++ * Correct reinstallation of breakpoints when exiting KDB. ++ * Keith Owens. ++ * kdb v4.4-2.6.23-rc2-common-2. ++ ++2007-08-07 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc2-common-1. ++ ++2007-08-03 Keith Owens ++ ++ * kdba_bt_x86.c: Rename some variables to make the code more readable. ++ Print more debug information when merging register states and when ++ calculating the new stack pointer. ++ * kdb v4.4-2.6.23-rc1-common-2. ++ ++2007-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc1-common-1. ++ ++2007-07-26 Keith Owens ++ ++ * New x86 backtrace code. ++ * kdb v4.4-2.6.22-common-4. ++ ++2007-07-17 Keith Owens ++ ++ * Make kdb_printf_lock an irq lock to keep lockdep happy. ++ * kdb v4.4-2.6.22-common-3. ++ ++2007-07-13 Keith Owens ++ ++ * Increase the size of the debug_alloc pool. ++ * Add the caller that obtained each entry in the debug_alloc pool. ++ * Poison entries in the debug_alloc pool. ++ * Track current and maximum usage in debug_alloc pool. ++ * Print the debug_alloc entries that are still in use when kdb exits ++ (memory leaks). ++ * Increase the default value of BTARGS to 9. ++ * kdb v4.4-2.6.22-common-2. ++ ++2007-07-09 Keith Owens ++ ++ * kdb v4.4-2.6.22-common-1. ++ ++2007-07-02 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc7-common-1. ++ ++2007-06-20 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc5-common-1. ++ ++2007-06-15 Keith Owens ++ ++ * Do not include asm/kdb.h unless CONFIG_KDB is on. Dave Jiang. ++ * kdb v4.4-2.6.22-rc4-common-2. ++ ++2007-06-08 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc4-common-1. ++ ++2007-05-28 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc3-common-1. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc2-common-1. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc1-common-1. ++ ++2007-05-17 Keith Owens ++ ++ * Add rdmsr and wrmsr commands for i386 and x86_64. Original patch by ++ Bernardo Innocenti for i386, reworked by Keith Owens to make it safe ++ on all cpu models and to handle both i386 and x86_64. ++ * kdb v4.4-2.6.21-common-3. ++ ++2007-05-15 Keith Owens ++ ++ * Correct alignment of debug_alloc_header. ++ * kdb v4.4-2.6.21-common-2. ++ ++2007-04-29 Keith Owens ++ ++ * kdb v4.4-2.6.21-common-1. ++ ++2007-04-16 Keith Owens ++ ++ * Remove dead symbol declarations. ++ * kdb v4.4-2.6.21-rc7-common-2. ++ ++2007-04-16 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc7-common-1. ++ ++2007-04-10 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc6-common-1. ++ ++2007-04-02 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc5-common-1. ++ ++2007-03-19 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc4-common-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc3-common-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc2-common-1. ++ ++2007-03-01 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc1-common-1. ++ ++2007-03-01 Keith Owens ++ ++ * Remove sparse warnings. ++ * kdb v4.4-2.6.20-common-6. ++ ++2007-02-27 Keith Owens ++ ++ * set_irq_regs() on entry to kdb() if they are not already set. ++ * kdb v4.4-2.6.20-common-5. ++ ++2007-02-22 Keith Owens ++ ++ * Initialise struct disassemble_info in kdb_id1(). ++ * kdb v4.4-2.6.20-common-4. ++ ++2007-02-16 Keith Owens ++ ++ * Clean up debug_alloc_pool code. ++ * kdb v4.4-2.6.20-common-3. ++ ++2007-02-16 Keith Owens ++ ++ * Initialise variable bits of struct disassemble_info each time. ++ * kdb v4.4-2.6.20-common-2. ++ ++2007-02-06 Keith Owens ++ ++ * kdb v4.4-2.6.20-common-1. ++ ++2007-02-01 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc7-common-1. ++ ++2007-01-08 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc4-common-1. ++ ++2007-01-02 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc3-common-1. ++ ++2006-12-21 Keith Owens ++ ++ * Initialize the debug_kmalloc pool on the first call, so it can be ++ used at any time. ++ * kdb v4.4-2.6.20-rc1-common-2. ++ ++2006-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc1-common-1. ++ ++2006-11-30 Keith Owens ++ ++ * kdb v4.4-2.6.19-common-1. ++ ++2006-11-30 Keith Owens ++ ++ * Do not access registers if kdb_current_regs is NULL. ++ * kdb v4.4-2.6.19-rc6-common-3. ++ ++2006-11-27 Keith Owens ++ ++ * Only use VT keyboard if the command line allows it and ACPI indicates ++ that there is an i8042. ++ * Optimize kdb_read() to reduce the risk of dropping input characters. ++ * Print cpumasks as lists instead of hex, also cope with long lists. ++ * kdb v4.4-2.6.19-rc6-common-2. ++ ++2006-11-20 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc6-common-1. ++ ++2006-11-09 Keith Owens ++ ++ * Change kdb() to fastcall. ++ * Correct loop in kdb_help(). Georg Nikodym. ++ * Only use VT console if the command line allows it. ++ * kdb v4.4-2.6.19-rc5-common-2. ++ ++2006-11-08 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc5-common-1. ++ ++2006-11-01 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc4-common-1. ++ ++2006-10-24 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc3-common-1. ++ ++2006-10-24 Keith Owens ++ ++ * Remove redundant regs and envp parameters. ++ * kdb v4.4-2.6.19-rc2-common-2. ++ ++2006-10-18 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc2-common-1. ++ ++2006-10-11 Keith Owens ++ ++ * Move kdbm_x86.c from the i386 to the common KDB patch. ++ * Expand kdbm_x86.c to work on x86_64 as well as i386. ++ * kdb v4.4-2.6.19-rc1-common-2. ++ ++2006-10-09 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc1-common-1. ++ ++2006-10-06 Keith Owens ++ ++ * Remove #include ++ * kdb v4.4-2.6.18-common-2. ++ ++2006-09-20 Keith Owens ++ ++ * kdb v4.4-2.6.18-common-1. ++ ++2006-09-15 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc7-common-1. ++ ++2006-08-29 Keith Owens ++ ++ * Rewrite all backtrace code. ++ * kdb v4.4-2.6.18-rc5-common-2. ++ ++2006-08-28 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc5-common-1. ++ ++2006-08-08 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc4-common-1. ++ ++2006-08-04 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc3-common-1. ++ ++2006-07-18 Keith Owens ++ ++ * 8250.c locking has been fixed so there is no need to break spinlocks ++ for keyboard entry. ++ * kdb v4.4-2.6.18-rc2-common-2. ++ ++2006-07-18 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc2-common-1. ++ ++2006-07-12 Keith Owens ++ ++ * Remove dead KDB_REASON codes. ++ * The main kdb() function is now always entered with interrupts ++ disabled, so there is no need to disable bottom halves. ++ * sparse cleanups. ++ * kdb v4.4-2.6.18-rc1-common-2. ++ ++2006-07-07 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc1-common-1. ++ ++2006-07-04 Keith Owens ++ ++ * Add KDB_REASON_CPU_UP and callbacks for cpus coming online. ++ * Relegate KDB_REASON_SILENT to KDB internal use only. ++ * Backout the v4.4-2.6.15-common-3 change that made KDB_REASON_SILENT ++ wait for cpus, the Dell Xeon problem has been fixed. ++ * notify_die() is not called for KDB_REASON_SILENT nor ++ KDB_REASON_CPU_UP, these events do not stay in KDB. ++ * Export kdb_current_task for kdbm_x86. SuSE patch ++ kdb-missing-export.diff ++ * Scale kdb_wait_for_cpus_secs by the number of online cpus. ++ * Delete kdb_enablehwfault, architectures now do their own setup. ++ * Delete kdba_enable_mce, architectures now do their own setup. ++ * Delete kdba_enable_lbr, kdba_disable_lbr, kdba_print_lbr, ++ page_fault_mca. Only ever implemented on x86, difficult to maintain ++ and rarely used in the field. ++ * Replace #ifdef KDB_HAVE_LONGJMP with #ifdef kdba_setjmp. ++ * kdb v4.4-2.6.17-common-2. ++ ++2006-06-19 Keith Owens ++ ++ * kdb v4.4-2.6.17-common-1. ++ ++2006-05-31 Keith Owens ++ ++ * Break spinlocks for keyboard entry. Hopefully a temporary hack while ++ I track down why keyboard entry to KDB is hanging. ++ * kdb v4.4-2.6.17-rc5-common-2. ++ ++2006-05-25 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc5-common-1. ++ ++2006-05-15 Keith Owens ++ ++ * Refresh bfd related files from binutils 2.16.91.0.2. ++ * kdb v4.4-2.6.17-rc4-common-2. ++ ++2006-05-12 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc4-common-1. ++ ++2006-04-28 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc3-common-1. ++ ++2006-04-22 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc2-common-1. ++ ++2006-04-11 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc1-common-1. ++ ++2006-04-05 Keith Owens ++ ++ * More fixes for the timing race with KDB_ENTER_SLAVE. ++ * kdb v4.4-2.6.16-common-5. ++ ++2006-03-30 Keith Owens ++ ++ * Some code was testing KDB_IS_RUNNING() twice, which left it open to ++ races. Cache the result instead. ++ * kdb v4.4-2.6.16-common-4. ++ ++2006-03-30 Keith Owens ++ ++ * Change CONFIG_LKCD to CONFIG_LKCD_DUMP. ++ * kdb v4.4-2.6.16-common-3. ++ ++2006-03-22 Keith Owens ++ ++ * Add some more xpc flags. Dean Nelson, SGI. ++ * Replace open coded counter references with atomic_read(). ++ * Pass early_uart_console to early_uart_setup(). Francois ++ Wellenreiter, Bull. ++ * Replace open code with for_each_online_cpu(). ++ * If cpus do not come into kdb after a few seconds then let ++ architectures send a more forceful interrupt. ++ * Close a timing race with KDB_ENTER_SLAVE. ++ * kdb v4.4-2.6.16-common-2. ++ ++2006-03-21 Keith Owens ++ ++ * kdb v4.4-2.6.16-common-1. ++ ++2006-03-14 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc6-common-1. ++ ++2006-02-28 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc5-common-1. ++ ++2006-02-20 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc4-common-1. ++ ++2006-02-06 Keith Owens ++ ++ * Change CONFIG_CRASH_DUMP to CONFIG_LKCD. ++ * Remove obsolete kdb_notifier_list. ++ * kdb v4.4-2.6.16-rc2-common-2. ++ ++2006-02-06 Keith Owens ++ ++ * Add xpcusers command. Dean Nelson, SGI. ++ * kdb v4.4-2.6.16-rc2-common-1. ++ ++2006-02-02 Keith Owens ++ ++ * Check if we have a console before using it for KDB. ++ * kdb v4.4-2.6.16-rc1-common-3. ++ ++2006-02-01 Keith Owens ++ ++ * Add option 'R' to the pid command to reset to the original task. ++ * Include 'pid R' in archkdb* commands to reset up the original failing ++ task. Users may have switched to other cpus and/or tasks before ++ issuing archkdb. ++ * Compile fix for kdbm_pg.c on i386. ++ * kdb v4.4-2.6.16-rc1-common-2. ++ ++2006-01-18 Keith Owens ++ ++ * kdb v4.4-2.6.16-rc1-common-1. ++ ++2006-01-11 Keith Owens ++ ++ * Plug a timing race between KDB_ENTER_SLAVE and KDB_ENTER, and allow ++ the cpu command to switch to a slave cpu. ++ * KDB_REASON_SILENT now waits for other cpus, to avoid spurious NMI ++ events that were seen on some Xeon systems. ++ * kdb v4.4-2.6.15-common-3. ++ ++2006-01-08 Keith Owens ++ ++ * kdb mainline invokes DIE_KDEBUG_ENTER and DIE_KDEBUG_LEAVE via ++ notify_die. ++ * Move xpc debug support from xpc to mainline kdb. ++ * kdbm_cm.c: check if file_lock_operations or lock_manager_operations ++ are set before dereferencing them. Felix Blyakher, SGI. ++ * kdb v4.4-2.6.15-common-2. ++ ++2006-01-04 Keith Owens ++ ++ * Print all buffers on a page in inode pages and update formatting to be ++ legible, too. David Chinner, SGI. ++ * Update page flags in kdbm_pg. ++ * Remove inline from *.c files. ++ * kdb v4.4-2.6.15-common-1. ++ ++2005-12-25 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc7-common-1. ++ ++2005-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc6-common-1. ++ ++2005-12-10 Keith Owens ++ ++ * Update mapping of flags to strings in kdbm_pg.c and kdbm_vm.c. ++ * kdb v4.4-2.6.15-rc5-common-3. ++ ++2005-12-06 Keith Owens ++ ++ * Add RECOVERY flag to global KDB flags. ++ * Add kdb_{save,restore}_flags. ++ * kdb v4.4-2.6.15-rc5-common-2. ++ ++2005-12-05 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc5-common-1. ++ ++2005-12-02 Keith Owens ++ ++ * kdbm_vm.c: offsets of page macros should be unsigned long. Reported ++ by Dean Nelson, SGI. ++ * kdb v4.4-2.6.15-rc4-common-1. ++ ++2005-11-30 Keith Owens ++ ++ * New follow_page() API. ++ * kdb v4.4-2.6.15-rc3-common-1. ++ ++2005-11-21 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc2-common-1. ++ ++2005-11-15 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc1-common-1. ++ ++2005-11-15 Keith Owens ++ ++ * Allow kdb_printf() to be used outside kdb, in preemptible context. ++ * Build with CONFIG_SWAP=n. Reported by Leo Yuriev. ++ * kdb v4.4-2.6.14-common-2. ++ ++2005-10-28 Keith Owens ++ ++ * kdb v4.4-2.6.14-common-1. ++ ++2005-10-21 Keith Owens ++ ++ * kdb v4.4-2.6.14-rc5-common-1. ++ ++2005-10-11 Keith Owens ++ ++ * Handle removal of USB keyboard. Aaron Young, SGI. ++ * kdb v4.4-2.6.14-rc4-common-1. ++ ++2005-10-05 Keith Owens ++ ++ * Extend kdb_notifier_list() codes to include dumping. ++ * Use emergency_restart() for reboot, it can be called from interrupt ++ context, unlike machine_restart(). ++ * kdb v4.4-2.6.14-rc3-common-1. ++ ++2005-09-21 Keith Owens ++ ++ * Support kdb_current_task in register display and modify commands. ++ * Document what changes kdb's notion of the current task. ++ * Update rd documentation for IA64. ++ * Move some definictions to kdbprivate.h and remove some unused symbol ++ exports. ++ * kdb v4.4-2.6.14-rc2-common-1. ++ ++2005-09-20 Keith Owens ++ ++ * Document IA64 handlers command. ++ * Add more fields to the task command. ++ * Cope with MCA/INIT handlers in the ps command. ++ * Namespace cleanup, delete unused exports, make some functions static. ++ * Add a kdb_notifier_list callback when kdb is about to reboot the ++ system. ++ * kdb v4.4-2.6.14-rc1-common-1. ++ ++2005-08-29 Keith Owens ++ ++ * kdb v4.4-2.6.13-common-1. ++ ++2005-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc7-common-1. ++ ++2005-08-08 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc6-common-1. ++ ++2005-08-02 Keith Owens ++ ++ * Print more fields from filp, dentry. ++ * Add kdb=on-nokey to suppress kdb entry from the keyboard. ++ * kdb v4.4-2.6.13-rc5-common-1. ++ ++2005-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc4-common-1. ++ ++2005-07-26 Keith Owens ++ ++ * Fix compile problem with CONFIG_USB_KBD. ++ * kdb v4.4-2.6.13-rc3-common-3. ++ ++2005-07-22 Keith Owens ++ ++ * The asmlinkage kdb() patch was lost during packaging. Reinstate it. ++ * kdb v4.4-2.6.13-rc3-common-2. ++ ++2005-07-19 Keith Owens ++ ++ * Add support for USB keyboard (OHCI only). Aaron Young, SGI. ++ * kdb v4.4-2.6.13-rc3-common-1. ++ ++2005-07-08 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc2-common-1. ++ ++2005-07-01 Keith Owens ++ ++ * Make kdb() asmlinkage to avoid problems with CONFIG_REGPARM. ++ * Change some uses of smp_processor_id() to be preempt safe. ++ * Use DEFINE_SPINLOCK(). ++ * kdb v4.4-2.6.13-rc1-common-1. ++ ++2005-06-18 Keith Owens ++ ++ * kdb v4.4-2.6.12-common-1. ++ ++2005-06-08 Keith Owens ++ ++ * Correct early exit from bd *. ++ * kdb v4.4-2.6.12-rc6-common-1. ++ ++2005-05-25 Keith Owens ++ ++ * Delete Documentation/kdb/dump.txt. lkcd now has reasonable ++ integration with kdb. ++ * kdb v4.4-2.6.12-rc5-common-1. ++ ++2005-05-08 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc4-common-1. ++ ++2005-04-21 Keith Owens ++ ++ * Add rpte command (find the pte for a physical page). ++ * kdb v4.4-2.6.12-rc3-common-1. ++ ++2005-04-06 Keith Owens ++ ++ * Add rq and rqa commands. John Hawkes, SGI. ++ * kdb v4.4-2.6.12-rc2-common-1. ++ ++2005-03-29 Keith Owens ++ ++ * Use register_sysctl_table() instead of patching kernel/sysctl.c. ++ * Non-ASCII characters are not printable. ++ * kdb v4.4-2.6.12-rc1-common-1. ++ ++2005-03-15 Keith Owens ++ ++ * More coexistence patches for lkcd. Jason Uhlenkott, SGI. ++ * kdb v4.4-2.6.11-common-3. ++ ++2005-03-08 Keith Owens ++ ++ * Coexistence patches for lkcd. Jason Uhlenkott, SGI. ++ * kdb v4.4-2.6.11-common-2. ++ ++2005-03-03 Keith Owens ++ ++ * Add kdb to drivers/serial/8250_early.c. Francois Wellenreiter, Bull. ++ * kdb v4.4-2.6.11-common-1. ++ ++2005-02-14 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc4-common-1. ++ ++2005-02-08 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc3-bk4-common-1. ++ ++2005-02-03 Keith Owens ++ ++ * Print more superblock fields. Nathan Scott, SGI. ++ * Remove kallsyms correction for modules, Linus took it. ++ * kdb v4.4-2.6.11-rc3-common-1. ++ ++2005-01-27 Keith Owens ++ ++ * Add bio command. Nathan Scott, SGI. ++ * kdb v4.4-2.6.11-rc2-common-1. ++ ++2005-01-20 Keith Owens ++ ++ * Include kallsyms correction for modules until Linus takes it. ++ * kdb v4.4-2.6.11-rc1-bk7-common-1. ++ ++2005-01-12 Keith Owens ++ ++ * kallsyms now supports all symbols properly, remove kdb patch. ++ * Add last ditch allocator for debugging. ++ * Update kdb_meminfo_read_proc() for vmalloc changes. ++ * Update kdbm_vm.c for 4 level page tables. ++ * kdb v4.4-2.6.11-rc1-common-1. ++ ++2004-12-25 Keith Owens ++ ++ * Add kobject command. ++ * Ignore low addresses and large offsets in kdbnearsym(). ++ * Console updates for sn2 simulator. ++ * kdb v4.4-2.6.10-common-1. ++ ++2004-12-07 Keith Owens ++ ++ * kdb v4.4-2.6.10-rc3-common-1. ++ ++2004-11-23 Keith Owens ++ ++ * Remove warning message from kdb_get_one_user_page(), it was too noisy. ++ * kdb v4.4-2.6.10-rc2-common-1. ++ ++2004-11-02 Keith Owens ++ ++ * Build with kdb patch applied but CONFIG_KDB=n. ++ * kdb v4.4-2.6.10-rc1-common-2. ++ ++2004-10-29 Keith Owens ++ ++ * Handle new compression scheme for kallsyms. ++ * Handle move of DEAD and ZOMBIE for task->state to task->exit_state. ++ * Tweak the concept of a valid kernel address to get all symbols, ++ including the symbols in the ia64 gate page. ++ * kdb v4.4-2.6.10-rc1-common-1. ++ ++2004-10-21 Keith Owens ++ ++ * Handle variable size for the kernel log buffer. ++ * kdb v4.4-2.6.9-common-2. ++ ++2004-10-19 Keith Owens ++ ++ * kdb v4.4-2.6.9-common-1. ++ ++2004-10-12 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc4-common-1. ++ ++2004-10-01 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc3-common-1. ++ ++2004-09-30 Keith Owens ++ ++ * Add stackdepth command to Documentation/kdb/kdb.mm. stackdepth is ++ only supported on i386 and ia64 at the moment. ++ * Skip kdbm_pg memmap build on x86_64. Scott Lurndal, 3leafnetworks. ++ * Export kdb_serial_str for modular I/O. Bryan Cardillo, UPenn. ++ * Reinstate tab completion for symbols. ++ * kdb v4.4-2.6.9-rc2-common-2. ++ ++2004-09-14 Keith Owens ++ ++ * Add task states C (traCed) and E (dEad). ++ * kdb v4.4-2.6.9-rc2-common-1. ++ ++2004-08-27 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc1-common-1. ++ ++2004-08-14 Keith Owens ++ ++ * kdb v4.4-2.6.8-common-1. ++ ++2004-08-12 Keith Owens ++ ++ * kdb v4.4-2.6.8-rc4-common-1. ++ ++2004-08-05 Keith Owens ++ ++ * Mark kdb_initcall as __attribute_used__ for newer gcc. ++ * kdb v4.4-2.6.8-rc3-common-2. ++ ++2004-08-04 Keith Owens ++ ++ * Add mdp (memory display physical) comnmand. ++ Ananth N Mavinakayanahalli, IBM. ++ * kdb v4.4-2.6.8-rc3-common-1. ++ ++2004-07-18 Keith Owens ++ ++ * Patch for new sn_console. Erik Jacobson. SGI. ++ * kdb v4.4-2.6.8-rc2-common-1. ++ ++2004-07-12 Keith Owens ++ ++ * Convert kdbm_task to standard cpumask_t. ++ * Document '*' (all breakpoints) option on bd/be/bc commands. ++ * kdb v4.4-2.6.8-rc1-common-1. ++ ++2004-06-30 Keith Owens ++ ++ * Common changes to help the x86-64 port. ++ * kdb v4.4-2.6.7-common-3. ++ ++2004-06-20 Keith Owens ++ ++ * Move kdb includes in mm/swapfile.c to reduce conflicts with other ++ SGI patches. ++ * kdb v4.4-2.6.7-common-2. ++ ++2004-06-16 Keith Owens ++ ++ * kdb v4.4-2.6.7-common-1. ++ ++2004-06-09 Keith Owens ++ ++ * kdb v4.4-2.6.7-rc3-common-1. ++ ++2004-06-09 Keith Owens ++ ++ * Namespace clean up. Mark code/variables as static when it is only ++ used in one file, delete dead code/variables. ++ * Saved interrupt state requires long, not int. ++ * kdb v4.4-2.6.7-rc2-common-3. ++ ++2004-06-08 Keith Owens ++ ++ * Whitespace clean up, no code changes. ++ * kdb v4.4-2.6.7-rc2-common-2. ++ ++2004-06-07 Keith Owens ++ ++ * kdb v4.4-2.6.7-rc2-common-1. ++ ++2004-06-06 Keith Owens ++ ++ * Avoid recursion problems in kdb_init(). ++ * Add standard archkdb commands. ++ * Add per_cpu command. ++ * Move kdb_{get,put}userarea_size definitions to linux/kdb.h. ++ * kdb v4.4-2.6.6-common-2. ++ ++2004-05-23 Keith Owens ++ ++ * Shrink the output from the cpu command. ++ * Add cpu state 'I', the cpu is idle. ++ * Add cpu state '+', some kdb data is available but the cpu is not ++ responding. ++ * Do not print tasks in state I or M by default in ps and bta commands. ++ * Add states I (idle task) and M (sleeping system daemon) to ps and ++ bta commands. ++ * Delete unused variables. ++ * Move private kdb fields from kdb.h to kdbprivate.h. ++ * Print 'for keyboard entry' for the special cases when KDB_ENTER() is ++ used to get registers. ++ * Move bfd.h and ansidecl.h from arch/$(ARCH)/kdb to include/asm-$(ARCH) ++ and remove -I arch/$(ARCH)/kdb. ++ * dmesg command now prints from either the start or end of dmesg, or at ++ an arbitrary point in the middle of the kernel log buffer. ++ * Sensible string dump for multi byte md commands. ++ * 'page' command handles ia64 correctly. ++ * Show some activity when waiting for cpus to enter kdb. ++ * Change the KDB entry code to KDB. ++ * Allow comment commands, starting with '#'. ++ * Commands defined using defcmd from kdb_cmds are not printed as they ++ are entered, use defcmd with no parameters to print all the defined ++ commands. ++ * Add summary command. ++ * Update copyright notices. ++ * Zero suppression on md command. ++ * Make set NOSECT=1 the default. ++ * PPC64 uses OF-stdout instead of console. Ananth N Mavinakayanahalli. ++ * kdb v4.4-2.6.6-common-1. ++ ++2004-05-10 Keith Owens ++ ++ * kdb v4.3-2.6.6-common-1. ++ ++2004-05-06 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc3-common-1. ++ ++2004-05-06 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc2-common-1. ++ ++2004-04-30 Keith Owens ++ ++ * Rewrite inode_pages command for new radix code in struct page. ++ * kdb v4.3-2.6.6-rc1-common-1. ++ ++2004-04-11 Keith Owens ++ ++ * Unlock sn_sal_lock before entering kdb from sn_serial. ++ * kdb v4.3-2.6.5-common-2. ++ ++2004-04-05 Keith Owens ++ ++ * kdb v4.3-2.6.5-common-1. ++ ++2004-03-22 Keith Owens ++ ++ * kdb v4.3-2.6.5-rc2-common-1. ++ ++2004-03-12 Keith Owens ++ ++ * More work to avoid spurious messages from WARN_CONSOLE_UNLOCKED(). ++ * bh command bug fixes. Nathan Scott. ++ * kdb v4.3-2.6.4-common-1. ++ ++2004-03-06 Keith Owens ++ ++ * Set KDB_IS_RUNNING() during kdb_init to avoid spurious messages from ++ WARN_CONSOLE_UNLOCKED(). ++ * Correct loss of symbol names in kdbnearsym. ++ * kdb v4.3-2.6.4-rc2-common-1. ++ ++2004-02-29 Keith Owens ++ ++ * kdb v4.3-2.6.4-rc1-common-1. ++ ++2004-02-21 Keith Owens ++ ++ * Correct build of kdb_cmds when using a separate object directory and ++ make it quiet. j-nomura (NEC), Keith Owens. ++ * kdb v4.3-2.6.3-common-2. ++ ++2004-02-18 Keith Owens ++ ++ * kdb v4.3-2.6.3-common-1. ++ ++2004-02-17 Keith Owens ++ ++ * Remove WAR for incorrect console registration patch. ++ * kdb v4.3-2.6.3-rc4-common-1. ++ ++2004-02-17 Keith Owens ++ ++ * Convert longjmp buffers from static to dynamic allocation, for large ++ cpu counts. ++ * Tweak kdbm_task for SMP/UP. ++ * Reconcile with kdb-v4.3 2.4.25-rc1-common-1. ++ * Simplify coexistence with NPTL patches. ++ * Support kill command on new scheduler. ++ * Do not refetch data when printing a value as characters. ++ * Document the pid command. ++ * Work around 2.6 kallsyms 'feature'. ++ * Upgrade to 2.6.3-rc3. ++ * WAR for incorrect console registration patch. ++ * kdb v4.3-2.6.3-rc3-common-1. ++ ++2003-12-03 Keith Owens ++ ++ * Reconcile 2.6-test versions from Xavier Bru (Bull), Greg Banks (SGI), ++ Jim Houston (Concurrent Computer Corp). ++ * Reconcile with kdb v4.3-2.4.23-common-2. ++ * Clean up CONFIG_KDB changes to {scripts,kernel}/kallsyms.c. ++ * Correct handling of kdb command line arguments. ++ * Make hooks into module code less intrusive. ++ * Delete kdb_active_task, not required with O(1) scheduler. ++ * Port kdbm_task.c from 2.4. ++ * Disable debug check in exit.c::next_thread() when kdb is running. ++ * Remove "only bh_disable when interrupts are set". BH must be disabled ++ in kdb to prevent deadlock on breakpoints in interrupt handlers. ++ * Add kdb to drivers/char/sn_serial.c. ++ * kdb v4.3-2.6.0-test11-common-1. ++ ++2003-11-11 Xavier Bru ++ * Merge to 2.6.0-test9 ++2003-10-17 Xavier Bru ++ * fix NUll ptr in kdb_ps at early prompt. ++2003-10-14 Xavier Bru ++ * fix NUll ptr in kdb_ps when cpu not present. ++2003-10-06 Xavier Bru ++ * Merge to 2.6.0-test5 ++ * fix compile error with CONFIG_MODULES not set. ++ ++2003-09-08 Xavier Bru ++ * Merge to 2.6.0-test4 ++ ++2003-07-10 Xavier Bru ++ ++ * Merge kdb v4.3 to 2.5.72 ia64 ++ * don't call local_bh_enable() with interrupts masked. ++ ++2003-04-07 Xavier Bru ++ ++ * Merge kdb v4.1 to 2.5.64 ia64 ++ * new kernel parameters support ++ * new module format ++ * new kallsyms support ++ ++2003-12-02 Keith Owens ++ ++ * Use correct page alignment in kdb_get_one_user_page(). ++ Prasanna S Panchamukhi, IBM. ++ * Split pte command into pte -m and pte -p. Dean Roe, SGI. ++ * kdb v4.3-2.4.23-common-2. ++ ++2003-12-01 Keith Owens ++ ++ * kdb v4.3-2.4.23-common-1. ++ ++2003-11-11 Keith Owens ++ ++ * Make KDB for USB keyboards build. Peter T. Breuer. ++ * Do not use USB keyboard if it has not been probed. ++ * kdb v4.3-2.4.23-rc1-common-1. ++ ++2003-10-10 Keith Owens ++ ++ * Sync with XFS 2.4.22 tree. ++ * kdb v4.3-2.4.22-common-2. ++ ++2003-08-29 Keith Owens ++ ++ * kdb v4.3-2.4.22-common-1. ++ ++2003-07-27 Keith Owens ++ ++ * kdb v4.3-2.4.22-pre8-common-8. ++ ++2003-07-20 Keith Owens ++ ++ * Make kdb_serial_str a common constant, the same for all consoles. ++ * Support SGI L1 console. ++ * kdb v4.3-2.4.21-common-8. ++ ++2003-07-14 Keith Owens ++ ++ * Correct ll command. ++ * kdb v4.3-2.4.21-common-7. ++ ++2003-07-08 Keith Owens ++ ++ * Export more kdb symbols. Vamsi Krishna S., IBM. ++ * kdb v4.3-2.4.21-common-6. ++ ++2003-07-07 Keith Owens ++ ++ * Tweak 'waiting for cpus' message. ++ * kdb v4.3-2.4.21-common-5. ++ ++2003-07-07 Keith Owens ++ ++ * 2.4.21-ia64-030702 patches common code that affects kdb. Workaround ++ this nuisance. ++ * kdb v4.3-2.4.21-common-4. ++ ++2003-06-24 Keith Owens ++ ++ * Add task and sigset commands. Mark Goodwin, SGI. ++ * kdb v4.3-2.4.21-common-3. ++ ++2003-06-23 Keith Owens ++ ++ * Sync with XFS 2.4.21 tree. ++ * kdb v4.3-2.4.21-common-2. ++ ++2003-06-20 Keith Owens ++ ++ * kdb v4.3-2.4.21-common-1. ++ ++2003-06-20 Keith Owens ++ ++ * More details on vm command, add vmp and pte commands. ++ Dean Nelson, Dean Roe, SGI. ++ * YAO1SCF (Yet Another O(1) Scheduler Coexistence Fix). ++ * Changes to common code to build on sparc. Tom Duffy. ++ * Move Tom Duffy's changes to drivers/sbus from the sparc64 ++ patch to the common patch to keep all the serial changes ++ together. ++ * Changes to common code to build on Xscale. Eddie Dong, Intel. ++ * Remove CROSS_COMPILE_INC. ++ * Remove obsolete boot parameter 'kdb', long since replaced by ++ 'kdb=on'. ++ * Remove obsolete kdb_eframe_t casts. ++ * Add CONFIG_KDB_CONTINUE_CATASTROPHIC. ++ * Wait a short interval for cpus to join kdb before proceeding. ++ * Automatically enable sysrq for sr command. ++ * Correct double free of kdb_printf lock, spotted by Richard Sanders. ++ * Add optional cpu parameter to btc command. ++ * kdb v4.3-2.4.20-common-1. ++ ++2003-05-02 Keith Owens ++ ++ * Some architectures have problems with the initial empty kallsyms ++ section so revert to three kallsyms passes. ++ * Flush buffered input at startup and at 'more' prompt. ++ * Only print 'more' prompt when longjmp data is available. ++ * Print more data for buffers and inodes. ++ * Disable kill command when O(1) scheduler is installed, the code ++ needs to be redone for O(1). ++ * The kernel has an undocumented assumption that enable_bh() is ++ always called with interrupts enabled, make it so. ++ * Print trailing punctuation even for symbols that are not in kernel. ++ * Add read/write access to user pages. Vamsi Krishna S., IBM ++ * Rename cpu_is_online to cpu_online, as in 2.5. ++ * O(1) scheduler removes init_task so kdb maintains its own list of ++ active tasks. ++ * Delete btp 0 option, it needed init_tasks. ++ * Clean up USB keyboard support. Steven Dake. ++ * Sync with XFS 2.4.20 tree. ++ * kdb v4.2-2.4.20-common-1. ++ ++2003-04-04 Keith Owens ++ ++ * Remove one kallsyms pass. ++ * Automatic detection of O(1) scheduler. ++ * Rename cpu_online to cpu_is_online. ++ * Workarounds for scheduler bugs. ++ * Tweak algorithm for detecting if cpu process data is available. ++ * Add 'kill' command. Sonic Zhang, Keith Owens. ++ * kdb v4.1-2.4.20-common-1. ++ ++2003-03-16 Keith Owens ++ ++ * Each cpu saves its state as it enters kdb or before it enters code ++ which cannot call kdb. ++ * Allow btp on process 0 for a specified cpu. ++ * Add btt command, backtrace given a struct task address. ++ * btc command no longer switches cpus, instead it uses the saved data. ++ * bta shows the idle task on each cpu as well as real tasks, the idle ++ task could be handling an interrupt. ++ * ps command shows the idle task on each cpu. ++ * ps checks that the saved data for a cpu matches the process running on ++ that cpu and warns about stale saved data or no saved data at all. ++ * Remove special cases for i386 backtrace from common code and simplify ++ common bt code. ++ * Clean up kdb interaction with CONFIG_SERIAL_CONSOLE. ++ * Do not automatically repeat commands after the user typed 'q'. ++ * O(1) scheduler patch changes the process cpu field but does not set ++ any indicator that O(1) is being used. Adjust kdb_process_cpu() by ++ hand after applying O(1). ++ * Add kdb_print_nameval() to common code. ++ * Convert tests of cpu_online_map to cpu_online() macro. ++ * module.h needs errno.h when compiling with CONFIG_MODULES=n. ++ * Correct duplicate breakpoint handling. ++ * Do not try to send IPI during a catastrophic error, send_ipi can hang ++ and take kdb with it. ++ * kdb memmap command is i386 only, restrict it. ++ * Add large block device (LBD) support from XFS tree. Eric Sandeen. ++ * kdb v4.0-2.4.20-common-1. ++ ++2003-02-03 Keith Owens ++ ++ * Register kdb commands early. ++ * Decode oops via kallsyms if it is available. ++ * Update copyright notices to 2003. ++ * Add defcmd/endefcmd to allow users to package their own macros. ++ * kdb commands that fail are ignored when prefixed with '-'. ++ * Add selection options to bta command. ++ * Add btc command (switch to each cpu and backtrace). ++ * Do real time detection of dead cpus. ++ * Clear ip adjusted flag when leaving kdb. ++ * Clean up ps command. ++ * Print ps output for each task when backtracing. ++ * Bump to version v3.0 to reduce confusion between kdb and kernel ++ version numbers. ++ * Add kdba_local_arch_setup/kdba_local_arch_cleanup to correct ++ keyboard freeze. Ashish Kalra. ++ * Refuse multiple breakpoints at the same address. ++ * Add fl (file_lock) command, from XFS development tree. ++ * Correct inode_pages, from XFS development tree. ++ * Add command history and editing. Sonic Zhang. ++ * Extend command history and editing to handle vt100 escape sequences. ++ * Allow tab completion at start of line. ++ * Touch nmi watchdog on long running bta and btc commands. ++ * Clean up ps output and standardize with bta codes. ++ * Correctly handle escaped characters in commands. ++ * Update man pages for btc and command history/editing. ++ * kdb v3.0-2.4.20-common-1. ++ ++2002-11-29 Keith Owens ++ ++ * Upgrade to 2.4.20. ++ * Correct Documentation/kdb/kdb_sr.man. ++ * Remove leading zeroes from pids, they are decimal, not octal. ++ * kdb v2.5-2.4.20-common-1. ++ ++2002-11-14 Keith Owens ++ ++ * Upgrade to 2.4.20-rc1. ++ * kdb v2.5-2.4.20-rc1-common-1. ++ ++2002-11-14 Keith Owens ++ ++ * Fix processing with O(1) scheduler. ++ * 'go' switches back to initial cpu first. ++ * 'go
' only allowed on initial cpu. ++ * 'go' installs the global breakpoints from the initial cpu before ++ releasing the other cpus. ++ * If 'go' has to single step over a breakpoint then it single steps just ++ the initial cpu, installs the global breakpoints then releases the ++ other cpus. ++ * General clean up of handling for breakpoints and single stepping over ++ software breakpoints. ++ * Add kdb_notifier_block so other code can tell when kdb is in control. ++ * kdb v2.5-2.4.19-common-1. ++ ++2002-11-02 Keith Owens ++ ++ * Correct build without CONFIG_KDB. ++ * kdb v2.4-2.4.19-common-3. ++ ++2002-11-01 Keith Owens ++ ++ * Minimize differences from 2.5.44. ++ * kdb v2.4-2.4.19-common-2. ++ ++2002-10-31 Keith Owens ++ ++ * Add defcmd/endefcmd feature. ++ * Remove kdb_eframe_t. ++ * Clear bp data before using. ++ * Sanity check if we have pt_regs. ++ * Force LINES > 1. ++ * Remove special case for KDB_REASON_PANIC, use KDB_ENTER() instead. ++ * Remove kdba_getcurrentframe(). ++ * Coexist with O(1) scheduler. ++ * Add lines option to dmesg, speed up dmesg. ++ * kdb v2.4-2.4.19-common-1. ++ ++2002-10-17 Keith Owens ++ ++ * Add selection critera to ps and bta commands. ++ * kdb v2.3-2.4.19-common-4. ++ ++2002-10-07 Keith Owens ++ ++ * New man page, Documentation/kdb/kdb_sr.man. ++ ++2002-10-04 Keith Owens ++ ++ * Minimize differences between patches for 2.4 and 2.5 kernels. ++ * Add Configure.help for CONFIG_KDB_USB. ++ * Reduce stack usage. ++ * kdb v2.3-2.4.19-common-3. ++ ++2002-08-10 Keith Owens ++ ++ * Replace kdb_port with kdb_serial to support memory mapped I/O. ++ David Mosberger. ++ * kdb v2.3-2.4.19-common-2. ++ ++2002-08-07 Keith Owens ++ ++ * Upgrade to 2.4.19. ++ * Remove individual SGI copyrights, the general SGI copyright applies. ++ * Handle md0. Reported by Hugh Dickins, different fix by Keith Owens. ++ * Use page_address() in kdbm_pg.c. Hugh Dickins. ++ * Remove debugging printk from kdbm_pg.c. Hugh Dickins. ++ * Move breakpoint address verification into arch dependent code. ++ * Dynamically resize kdb command table as required. ++ * Common code to support USB keyboard. Sebastien Lelarge. ++ * kdb v2.3-2.4.19-common-1. ++ ++2002-07-09 Keith Owens ++ ++ * Upgrade to 2.4.19-rc1. ++ * Add dmesg command. ++ * Clean up copyrights, Eric Sandeen. ++ * kdb v2.2-2.4.19-rc1-common-1. ++ ++2002-06-14 Keith Owens ++ ++ * Upgrade to 2.4.19-pre10. ++ * Sync with XFS. ++ * kdb v2.1-2.4.19-pre10-common-1. ++ ++2002-04-09 Keith Owens ++ ++ * Upgrade to 2.4.19-pre6. ++ * kdb v2.1-2.4.19-pre6-common-1. ++ ++2002-03-18 Keith Owens ++ ++ * Syntax check mdWcN commands. ++ ++2002-03-01 Keith Owens ++ ++ * Sync with XFS 2.4.18. ++ * kdb v2.1-2.4.18-common-2. ++ ++2002-02-26 Keith Owens ++ ++ * Upgrade to 2.4.18. ++ * Add Paul Dorwin (IBM) magicpoint slides on using kdb as ++ Documentation/kdb/slides. ++ * kdb v2.1-2.4.18-common-1. ++ ++2002-01-23 Keith Owens ++ ++ * Sync with XFS pagebuf changes. ++ * kdb v2.1-2.4.17-common-2. ++ ++2002-01-18 Keith Owens ++ ++ * Ignore single stepping during panic. ++ * Remove kdba_getword, kdba_putword. Replace with kdb_getword, ++ kdb_putword that rely on copy_xx_user. The new functions return ++ an error code, like copy_xx_user. ++ * New functions kdb_getarea, kdb_putarea for copying areas of data ++ such as structures. These functions also return an error code. ++ * Change all common code to use the new functions. ++ * bp command checks that it can read and write the word at the ++ breakpoint before accepting the address. ++ * Break points are now set FIFO and cleared LIFO so overlapping ++ entries give sensible results. ++ * Verify address before disassembling code. ++ * Common changes for sparc64. Ethan Solomita, Tom Duffy. ++ * Remove ss , never supported. ++ * Remove kallsyms entries from arch vmlinux.lds files. ++ * Specify which commands auto repeat. ++ * kdb v2.1-2.4.17-common-1. ++ ++2002-01-07 Keith Owens ++ ++ * Remove console semaphore code, not good in interrupt. ++ * Remove fragment of ia64 patch that had crept into kdb. ++ * Release as kdb v2.0-2.4.17-common-3. ++ ++2002-01-04 Keith Owens ++ ++ * Sync xfs <-> kdb common code. ++ ++2001-12-22 Keith Owens ++ ++ * Upgrade to 2.4.17. ++ * Clean up ifdef CONFIG_KDB. ++ * Add ifdef CONFIG_KDB around include kdb.h. ++ * Delete dummy kdb.h files for unsupported architectures. ++ * Delete arch i386 and ia64 specific files. This changelog now ++ applies to kdb common code only. ++ * Release as kdb v2.0-2.4.17-common-1. ++ ++2001-12-03 Keith Owens ++ ++ * Upgrade to 2.4.16. ++ * Add include/asm-um/kdb.h stub to allow XFS to be tested under UML. ++ * Check if an interrupt frame on i386 came from user space. ++ * Out of scope bug fix in kdb_id.c. Ethan Solomita. ++ * Changes to common code to support sparc64. Ethan Solomita. ++ * Change GFP_KERNEL to GFP_ATOMIC in disasm. Ethan Solomita. ++ ++2001-11-16 Keith Owens ++ ++ * Upgrade to 2.4.15-pre5. ++ * Wrap () around #define expressions with unary operators. ++ ++2001-11-13 Keith Owens ++ ++ * Upgrade to 2.4.15-pre4. ++ * kbdm_pg.c patch from Hugh Dickins. ++ ++2001-11-07 Keith Owens ++ ++ * Upgrade to 2.4.14-ia64-011105. ++ * Change name of l1 serial I/O routine, add ia64 init command. SGI. ++ * Sync kdbm_pg with XFS. ++ ++2001-11-06 Keith Owens ++ ++ * Upgrade to kernel 2.4.14. ++ ++2001-11-02 Keith Owens ++ ++ * Sync kdbm_pg.c with XFS. ++ ++2001-10-24 Keith Owens ++ ++ * Upgrade to kernel 2.4.13. ++ ++2001-10-14 Keith Owens ++ ++ * More use of TMPPREFIX in top level Makefile to speed up NFS compiles. ++ ++ * Correct repeat calculations in md/mds commands. ++ ++2001-10-10 Keith Owens ++ ++ * Copy bfd.h and ansidecl.h to arch/$(ARCH)/kdb, remove dependecies on ++ user space includes. ++ ++ * Update kdb v1.9 to kernel 2.4.11. ++ ++2001-10-01 Keith Owens ++ ++ * Update kdb v1.9 to kernel 2.4.11-pre1 and 2.4.10-ac1. ++ ++ * Correct loop in kdb_parse, reported by Tachino Nobuhiro. ++ ++2001-09-25 Keith Owens ++ ++ * Update kdb v1.8 to kernel 2.4.10. ++ ++ * kdbm_pg patch from Hugh Dickens. ++ ++ * DProbes patch from Bharata B Rao. ++ ++ * mdWcn and mmW patch from Vamsi Krishna S. ++ ++ * i386 disasm layout patch from Jean-Marc Saffroy. ++ ++ * Work around for 64 bit binutils, Simon Munton. ++ ++ * kdb.mm doc correction by Chris Pascoe. ++ ++ * Enter repeats the last command, IA64 disasm only prints one ++ instruction. Don Dugger. ++ ++ * Allow kdb/modules to be linked into vmlinux. ++ ++ * Remove obsolete code from kdb/modules/kdbm_{pg,vm}.c. ++ ++ * Warn when commands are entered at more prompt. ++ ++ * Add MODULE_AUTHOR, DESCRIPTION, LICENSE. ++ ++ * Release as kdb v1.9. ++ ++2001-02-27 Keith Owens ++ ++ * Update kdb v1.8 to kernel 2.4.2, sync kdb/modules with XFS. ++ ++ * Hook into panic() call. ++ ++2000-12-18 Keith Owens ++ ++ * Update kdb v1.7 to kernel 2.4.0-test13-pre3, sync kdb/modules with ++ XFS. ++ ++2000-11-18 Keith Owens ++ ++ * Update to kernel 2.4.0-test11-pre7, including forward port of ++ bug fixes from WIP 2.4.0-test9 tree. ++ ++ * Update to Cygnus CVS trees for disassembly code. ++ ++ * Bump to kdb v1.6. ++ ++2000-10-19 Keith Owens ++ ++ * Update to kernel 2.4.0-test10-pre4. ++ ++2000-10-15 Keith Owens ++ ++ * kdb/kdbmain.c (kdb_parse): Correctly handle blank input. ++ ++ * kdb/kdbmain.c (kdb_local, kdb): Reason SILENT can have NULL regs. ++ ++2000-10-13 Keith Owens ++ ++ * kdb/kdbmain.c: Reduce CMD_LEN to avoid overflowing kdb_printf buffer. ++ ++2000-10-11 Keith Owens ++ ++ * kdb/kdbmain.c (kdb): Test for userspace breakpoints before driving ++ other cpus into kdb. Speeds up gdb and avoids SMP race. ++ ++ * arch/i386/kdb/kdba_io.c (get_serial_char, get_kbd_char): Ignore ++ unprintable characters. ++ ++ * arch/i386/kdb/kdba_io.c (kdba_read): Better handling of buffer size. ++ ++2000-10-04 Keith Owens ++ ++ * arch/i386/kdb/kdba_bt.c (kdba_bt_process): Verify that esp is inside ++ task_struct. Original patch by Mike Galbraith. ++ ++ * kdb/kdb_io.c (kdb_getstr): Reset output line counter, remove ++ unnecessary prompts. ++ ++ * arch/i386/kdb/kdbasupport.c (kdb_getregcontents): Change " cs" to ++ "xcs", ditto ss, ds, es. gdb2kdb does not like leading spaces. ++ ++ * include/asm-xxx/kdb.h: Add dummy kdb.h for all architectures except ++ ix86. This allows #include to appear in arch independent ++ code without causing compile errors. ++ ++ * kdb/modules/kdbm_pg: Sync with XFS. ++ ++2000-10-03 Keith Owens ++ ++ * kdb/kdb_io.c (kdb_read): Ignore NMI while waiting for input. ++ ++ * kdb/kdb_io.c, kdb/Makefile: Export kdb_read. ++ ++2000-10-02 Keith Owens ++ ++ * arch/i386/kernel/smpboot.c (do_boot_cpu): Set nmi_watchdog_source to 2 ++ to avoid premature NMI oops during cpu bring up. We have to assume that ++ a box with more than 1 cpu has a working IO-APIC. ++ ++ * Documentation/kdb/{kdb.mm,kdb_md.man}: Add mdr command. ++ ++ * kdb/kdbmain.c (kdb_md): Add mdr command. ++ ++ * Release as kdb v1.5 against 2.4.0-test9-pre8. ++ ++ * arch/i386/kdb/kdba_io.c, arch/i386/kdb/kdbasupport.c, kdb/kdbmain.c, ++ kdb/kdb_io.c, kdb/kdb_id.c: Remove zero initializers for static ++ variables. ++ ++2000-09-28 Keith Owens ++ ++ * various: Add nmi_watchdog_source, 1 local APIC, 2 IO-APIC. ++ Test nmi_watchdog_source instead of nr_ioapics so UP works on SMP hardware. ++ ++ * arch/i386/kernel/io_apic.c: Rename setup_nmi to setup_nmi_io for clarity. ++ ++ * kdb/kdbmain.c (kdb_parse): Only set NO_WATCHDOG if it was already set. ++ ++ * kdb/kdbmain.c (kdb): Clear NO_WATCHDOG on all exit paths. ++ ++ * include/linux/kdb.h: Add KDB_REASON_SILENT. ++ ++ * kdb/kdbmain.c (kdb_local): Treat reason SILENT as immediate 'go'. ++ ++ * kdb/kdbmain.c (kdb_init): Invoke kdb with reason SILENT to instantiate ++ any breakpoints on boot cpu. ++ ++ * arch/i386/kernel/smpboot.c (smp_callin): Invoke kdb with reason SILENT ++ to instantiate any global breakpoints on this cpu. ++ ++ * kdb/kdb_cmds: Remove comment that said initial commands only worked on ++ boot cpu. ++ ++2000-09-27 Keith Owens ++ ++ * arch/i386/kernel/msr.c: Move {rd,wr}msr_eio to include/asm-i386/apic.h. ++ ++ * include/asm-i386/apic.h: Define NMI interfaces. ++ ++ * kernel/sysctl.c (kern_table): ++ * kernel/sysctl.c (do_proc_set_nmi_watchdog): ++ Add /proc/sys/kernel/nmi_watchdog. ++ ++ * arch/i386/kernel/apic.c: New routines set_nmi_counter_local, ++ setup_apic_nmi_watchdog. ++ ++ * arch/i386/kernel/traps.c: New routine set_nmi_watchdog(). Call apic ++ routines to set/clear local apic timer. ++ ++2000-09-26 Keith Owens ++ ++ * include/linux/sysctl.h (enum): Add NMI_WATCHDOG. ++ ++ * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check nmi_watchdog is ++ still on. ++ ++ * arch/i386/config.in: Add CONFIG_UP_NMI_WATCHDOG. ++ ++ * Documentation/Configure.help: Add CONFIG_UP_NMI_WATCHDOG. ++ ++ * Documentation/nmi_watchdog.txt: Update for UP NMI watchdog. ++ ++2000-09-25 Keith Owens ++ ++ * arch/i386/kernel/apic.c (init_apic_mappings): ++ * arch/i386/kernel/io_apic.c (IO_APIC_init_uniprocessor): ++ Merge Keir Fraser's local APIC for uniprocessors patch. ++ ++2000-09-24 Keith Owens ++ ++ * Various: Declare initialization routines as __init. ++ ++ * Makefile: Define and export AWK. ++ ++ * kdb/Makefile: Generate gen-kdb_cmds.c from kdb/kdb_cmds. ++ ++ * kdb/kdbmain.c (kdb_init): Call new routine kdb_cmds_init to execute ++ whatever the user put in kdb/kdb_cmds. ++ ++ * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): New parameter to ++ indicate if esp in regs is known to be valid or not. ++ ++ * kdb/kdb_bp.c, arch/i386/kdb/kdba_bp.c: More trace prints for ++ breakpoint handling. ++ ++ * arch/i386/kdb/kdba_bp.c (kdba_installbp): Finally found and fixed the ++ annoying breakpoint bug where breakpoints where not always installed ++ after 'go'. ++ ++ * Documentation/kdb: Update man pages kdb.mm, kdb_env.man, kdb_ss.man. ++ ++ * Released as kdb-v1.5-beta1-2.4.0-test8. ++ ++ * Sync to 2.4.0-test9-pre6 and release as kdb-v1.5-beta1-2.4.0-test9-pre6. ++ ++2000-09-23 Keith Owens ++ ++ * arch/i386/kdb/kdbasupport.c (kdba_getregcontents): New pseudo ++ registers cesp and ceflags to help with debugging the debugger. ++ ++ * kdb/kdbmain.c (kdb_local, kdb): Add KDB_REASON_RECURSE. Add ++ environment variable RECURSE. Add code to cope with some types of ++ recursion. ++ ++ * kdb/kdbmain.c (kdb), arch/i386/kdba/kdba_bp.c: Add ++ kdba_clearsinglestep. ++ ++2000-09-22 Keith Owens ++ ++ * drivers/video/vgacon.c (write_vga): No cli() if kdb is running, avoid ++ console deadlock. ++ ++ * arch/i386/kernel/irq.c (get_irqlock): Warn if kdb is running, may hang. ++ ++ * include/linux/kdb.h: Define KDB_IS_RUNNING as (0) if no CONFIG_KDB. ++ ++ * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): Do not attempt a backtrace if ++ the code segment is not in the kernel. ++ ++ * kdb/modules: Change modules from MX_OBJS to M_OBJS. Remove EXPORT_NOSYMBOLS. ++ ++2000-09-21 Keith Owens ++ ++ * arch/i386/kernel/i386_ksyms.c: Move EXPORT_SYMBOLS for kdb to kdb/kdbmain.c. ++ ++ * kdb/Makefile: Change kdb/kdbmain.o from O_OBJS to OX_OBJS. ++ ++ * arch/i386/kernel/smp.c: Remove some #ifdef CONFIG_KDB. Remove kdbprivate.h. ++ ++ * include/linux/kdb.h: Add kdb_print_state. Add KDB_STATE_WAIT_IPI. ++ ++ * kdb/kdbmain.c (kdb): Only mark cpu as leaving if it is in KDB state. Maintain ++ WAIT_IPI state so a cpu is only driven through NMI once. ++ ++ * arch/i386/kernel/smp.c (smp_kdb_stop): All state fiddling moved to kdb(). ++ ++2000-09-20 Keith Owens ++ ++ * include/linux/kdb.h: #define kdb() as (0) if kdb is not configured. ++ ++ * arch/i386/kernel/traps.c: Remove some #ifdef CONFIG_KDB. ++ ++ * include/linux/kdbprivate.h: Move per cpu state to kdb.h. ++ ++ * include/linux/kdb.h: Add KDB_STATE_NO_WATCHDOG, KDB_STATE_PRINTF_LOCK. ++ Rename KDB_DEBUG_xxx to KDB_DEBUG_FLAG_xxx. Clean up debug flag ++ definitions. ++ ++ * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check no watchdog. ++ ++ * kdb/kdbmain.c (kdb): Set no watchdog in normal kdb code. ++ ++ * kdb/kdbmain.c (kdb_parse): Allow watchdog in commands. ++ ++ * kdb/kdb_io.c (kdb_printf): No watchdog during printing. Clean up lock handling. ++ ++ * kdb/kdbmain.c (kdb_set): Clean up debug flag handling. ++ ++2000-09-19 Juan J. Quintela ++ ++ * kdb/arch/i386/kdb/kdba_io.c: Allow kdb to compile without CONFIG_VT and/or ++ serial console. ++ ++2000-09-19 Keith Owens ++ ++ * include/linux/kdb.h: Define KDB_DEBUG_STATE(). ++ ++ * kdb/kdbmain.c (kdb): Add kdb_print_state(), calls to KDB_DEBUG_STATE(). ++ ++2000-09-16 Keith Owens ++ ++ * Move to finer grained control over individual processors in kdb with ++ per cpu kdb state. Needed to allow ss[b] to only release one processor, ++ previously ss[b] released all processors. Also need to recover from ++ errors inside kdb commands, e.g. oops in kdbm_pg code. ++ ++ * various: ++ Move global flags KDB_FLAG_SSB, KDB_FLAG_SUPRESS, KDB_FLAG_FAULT, ++ KDB_FLAG_SS, KDB_FLAG_SSBPT, kdb_active, to per cpu state and macros ++ KDB_STATE(xxx). ++ Replace kdb_flags & KDB_FLAG_xxx with KDB_FLAG(xxx). ++ Replace kdb_flags & KDB_DEBUG_xxx with KDB_DEBUG(xxx). ++ Replace specific tests with wrapper KDB_IS_RUNNING(). ++ ++ * various: Remove #ifdef CONFIG_SMP from kdb code wherever ++ possible. Simplifies the code and makes it much more readable. ++ ++ * arch/i386/kdb/kdbasupport.c (kdb_setjmp): Record if we have reliable ++ longjmp data instead of assuming it is always set. ++ ++ * various: Replace smp_kdb_wait with per cpu state, HOLD_CPU. ++ ++ * init/main.c : Replace #ifdef KDB_DEBUG with KDB_DEBUG(CALLBACK). ++ ++ * include/linux/kdbprivate.h: Separate command return codes from error ++ codes. Add more detailed command codes. ++ ++ * arch/i386/kernel/traps.c (die): Change spin_lock_irq to ++ spin_lock_irqsave. Why did I do this? ++ ++ * kdb/kdbmain.c (kdb_parse): Set per cpu flag CMD before executing kdb ++ command. More detailed return codes for commands that affect ++ processors. ++ ++ * kdb/kdbmain.c (kdb_previous_event): New, check if any processors are ++ still executing the previous kdb event. Removes a race window where a ++ second event could enter kdb before the first had completely ended. ++ ++ * kdb/kdbmain.c (kdb): Document all the concurrency conditions and how ++ kdb handles them. ss[b] now releases only the current cpu. Do not set ++ breakpoints when releasing for ss[b]. Recover from errors in kdb ++ commands. Check that we have reliable longjmp data before using it. ++ ++ * various: Update return code documentation. ++ ++ * kdb/kdb_bp.c (kdb_ss): Separate ss and ssb return codes. ++ ++ * kdb/kdbsupport.c (kdb_ipi): Finer grained algorithm for deciding ++ whether to call send a stop signal to a cpu. ++ ++ * arch/i386/kdb/kdba_bp.c (kdba_db_trap): Separate ss and ssb return ++ codes. Reinstall delayed software breakpoints per cpu instead of ++ globally. Changed algorithm for handling ss[b]. ++ ++ * arch/i386/kdb/kdba_bp.c (kdba_bp_trap): Match software breakpoints per ++ cpu instead of globally. ++ ++ * include/linux/kdb.h: Bump version to kdb v1.5. ++ ++2000-09-16 Keith Owens ++ ++ * kernel/sysctl.c (kern_table): add /proc/sys/kernel/kdb. ++ ++ * init/main.c (parse_options): add boot flags kdb=on, kdb=off, ++ kdb=early. ++ ++ * include/linux/sysctl.h (enum): add KERN_KDB. ++ ++ * drivers/char/serial.c (receive_chars): check kdb_on. ++ ++ * drivers/char/keyboard.c (handle_scancode): check kdb_on. ++ ++ * arch/i386/kernel/traps.c (nmi_watchdog_tick): check kdb_on. ++ ++ * arch/i386/config.in: add CONFIG_KDB_OFF. ++ ++ * Documentation/Configure.help: add CONFIG_KDB_OFF. ++ ++ * kdb/kdbmain.c: add kdb_initial_cpu, kdb_on. ++ ++ * kdb/kdbmain.c (kdb): check kdb_on, set kdb_initial_cpu. ++ ++ * kdb/kdbmain.c (kdb_init): add Keith Owens to kdb banner. ++ ++ * kdb/kdb_io.c (kdb_printf): serialize kdb_printf output. ++ ++ * kdb/kdb_bt.c (kdb_bt): check environment variable BTAPROMPT. ++ ++ * kdb/kdbsupport.c (kdb_ipi): ignore NMI for kdb_initial_cpu. ++ ++ * kdb/modules/kdbm_pg.c (kdbm_page): merge updates from 2.4.0-test5-xfs. ++ ++ * kdb/kdb_bt.man: add btp, bta, BTAPROMPT. ++ ++ * kdb/kdb.mm: add CONFIG_KDB_OFF, boot flags, btp, bta. ++ ++ * include/linux/kdbprivate.h: add kdb_initial_cpu. ++ ++ * include/linux/kdb.h: add kdb_on, bump version to kdb v1.4. +--- /dev/null ++++ b/kdb/Makefile +@@ -0,0 +1,43 @@ ++# ++# 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++# ++ ++CCVERSION := $(shell $(CC) -v 2>&1 | sed -ne '$$p') ++obj-y := kdb_bt.o kdb_bp.o kdb_id.o kdbsupport.o gen-kdb_cmds.o kdbmain.o kdb_io.o kdbdereference.o ++CFLAGS_kdbmain.o += -DCCVERSION="$(CCVERSION)" ++ ++subdir-$(CONFIG_KDB_MODULES) := modules ++obj-y += $(addsuffix /built-in.o, $(subdir-y)) ++ ++clean-files := gen-kdb_cmds.c ++ ++override CFLAGS := $(CFLAGS:%-pg=% ) ++ ++# define architecture dependent kdb_cmds ++ifeq ($(CONFIG_IA64),y) ++ KDB_CMDS = ia64/kdb/kdb_cmds ++else ++ ifeq ($(CONFIG_X86_64),y) ++ KDB_CMDS = x86/kdb/kdb_cmds_64 ++ else ++ ifeq ($(CONFIG_X86_32),y) ++ KDB_CMDS = x86/kdb/kdb_cmds_32 ++ endif ++ endif ++endif ++ ++quiet_cmd_gen-kdb = GENKDB $@ ++ cmd_gen-kdb = $(AWK) 'BEGIN {print "\#include "; print "\#include "} \ ++ /^\#/{next} \ ++ /^[ \t]*$$/{next} \ ++ {gsub(/"/, "\\\"", $$0); \ ++ print "static __initdata char kdb_cmd" cmds++ "[] = \"" $$0 "\\n\";"} \ ++ END {print "extern char *kdb_cmds[]; char __initdata *kdb_cmds[] = {"; for (i = 0; i < cmds; ++i) {print " kdb_cmd" i ","}; print(" NULL\n};");}' \ ++ $(filter-out %/Makefile,$^) > $@ ++ ++$(obj)/gen-kdb_cmds.c: $(src)/kdb_cmds $(wildcard $(TOPDIR)/arch/$(KDB_CMDS)) $(src)/Makefile ++ $(call cmd,gen-kdb) +--- /dev/null ++++ b/kdb/kdb_bp.c +@@ -0,0 +1,658 @@ ++/* ++ * Kernel Debugger Architecture Independent Breakpoint Handler ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Table of kdb_breakpoints ++ */ ++kdb_bp_t kdb_breakpoints[KDB_MAXBPT]; ++ ++/* ++ * Predicate to test whether a breakpoint should be installed ++ * on this CPU. ++ * ++ * Note that for purposes of installation, hardware breakpoints ++ * are treated as local (even if the global flag is set), on ++ * the assumption that the require per-cpu registers to be set. ++ */ ++ ++static inline int kdb_is_installable_global_bp(const kdb_bp_t *bp) ++{ ++ return (bp->bp_enabled && ++ bp->bp_global && ++ !bp->bp_forcehw); ++} ++ ++static int kdb_is_installable_local_bp(const kdb_bp_t *bp) ++{ ++ if (!bp->bp_enabled) ++ return 0; ++ ++ if (bp->bp_forcehw) { ++ if (bp->bp_cpu == smp_processor_id() || bp->bp_global) ++ return 1; ++ } else { ++ if (bp->bp_cpu == smp_processor_id() && !bp->bp_global) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * kdb_bp_install_global ++ * ++ * Install global kdb_breakpoints prior to returning from the ++ * kernel debugger. This allows the kdb_breakpoints to be set ++ * upon functions that are used internally by kdb, such as ++ * printk(). ++ * ++ * Parameters: ++ * regs Execution frame. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * This function is only called once per kdb session. ++ */ ++ ++void ++kdb_bp_install_global(struct pt_regs *regs) ++{ ++ int i; ++ ++ for(i=0; ibp_enabled, bp->bp_global); ++ } ++ /* HW BP local or global are installed in kdb_bp_install_local*/ ++ if (kdb_is_installable_global_bp(bp)) ++ kdba_installbp(regs, bp); ++ } ++} ++ ++/* ++ * kdb_bp_install_local ++ * ++ * Install local kdb_breakpoints prior to returning from the ++ * kernel debugger. This allows the kdb_breakpoints to be set ++ * upon functions that are used internally by kdb, such as ++ * printk(). ++ * ++ * Parameters: ++ * regs Execution frame. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * This function is called once per processor. ++ */ ++ ++void ++kdb_bp_install_local(struct pt_regs *regs) ++{ ++ int i; ++ ++ for(i=0; ibp_enabled, bp->bp_global, ++ smp_processor_id(), bp->bp_cpu); ++ } ++ if (kdb_is_installable_local_bp(bp)) ++ kdba_installbp(regs, bp); ++ } ++} ++ ++/* ++ * kdb_bp_remove_global ++ * ++ * Remove global kdb_breakpoints upon entry to the kernel debugger. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdb_bp_remove_global(void) ++{ ++ int i; ++ ++ for(i=KDB_MAXBPT-1; i>=0; i--) { ++ kdb_bp_t *bp = &kdb_breakpoints[i]; ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdb_bp_remove_global bp %d bp_enabled %d bp_global %d\n", ++ i, bp->bp_enabled, bp->bp_global); ++ } ++ if (kdb_is_installable_global_bp(bp)) ++ kdba_removebp(bp); ++ } ++} ++ ++ ++/* ++ * kdb_bp_remove_local ++ * ++ * Remove local kdb_breakpoints upon entry to the kernel debugger. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdb_bp_remove_local(void) ++{ ++ int i; ++ ++ for(i=KDB_MAXBPT-1; i>=0; i--) { ++ kdb_bp_t *bp = &kdb_breakpoints[i]; ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdb_bp_remove_local bp %d bp_enabled %d bp_global %d cpu %d bp_cpu %d\n", ++ i, bp->bp_enabled, bp->bp_global, ++ smp_processor_id(), bp->bp_cpu); ++ } ++ if (kdb_is_installable_local_bp(bp)) ++ kdba_removebp(bp); ++ } ++} ++ ++/* ++ * kdb_printbp ++ * ++ * Internal function to format and print a breakpoint entry. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdb_printbp(kdb_bp_t *bp, int i) ++{ ++ if (bp->bp_forcehw) { ++ kdb_printf("Forced "); ++ } ++ ++ if (!bp->bp_template.bph_free) { ++ kdb_printf("%s ", kdba_bptype(&bp->bp_template)); ++ } else { ++ kdb_printf("Instruction(i) "); ++ } ++ ++ kdb_printf("BP #%d at ", i); ++ kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT); ++ ++ if (bp->bp_enabled) { ++ kdba_printbp(bp); ++ if (bp->bp_global) ++ kdb_printf(" globally"); ++ else ++ kdb_printf(" on cpu %d", bp->bp_cpu); ++ if (bp->bp_adjust) ++ kdb_printf(" adjust %d", bp->bp_adjust); ++ } else { ++ kdb_printf("\n is disabled"); ++ } ++ ++ kdb_printf("\taddr at %016lx, hardtype=%d, forcehw=%d, installed=%d, hard=%p\n", ++ bp->bp_addr, bp->bp_hardtype, bp->bp_forcehw, ++ bp->bp_installed, bp->bp_hard); ++ ++ kdb_printf("\n"); ++} ++ ++/* ++ * kdb_bp ++ * ++ * Handle the bp, and bpa commands. ++ * ++ * [bp|bpa|bph] [DATAR|DATAW|IO [length]] ++ * ++ * Parameters: ++ * argc Count of arguments in argv ++ * argv Space delimited command line arguments ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic if failure. ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * bp Set breakpoint. Only use hardware assist if necessary. ++ * bpa Set breakpoint on all cpus, only use hardware regs if necessary ++ * bph Set breakpoint - force hardware register ++ * bpha Set breakpoint on all cpus, force hardware register ++ */ ++ ++static int ++kdb_bp(int argc, const char **argv) ++{ ++ int i, bpno; ++ kdb_bp_t *bp, *bp_check; ++ int diag; ++ int free; ++ char *symname = NULL; ++ long offset = 0ul; ++ int nextarg; ++ kdb_bp_t template = {0}; ++ ++ if (argc == 0) { ++ /* ++ * Display breakpoint table ++ */ ++ for(bpno=0,bp=kdb_breakpoints; bpnobp_free) continue; ++ ++ kdb_printbp(bp, bpno); ++ } ++ ++ return 0; ++ } ++ ++ template.bp_global = ((strcmp(argv[0], "bpa") == 0) ++ || (strcmp(argv[0], "bpha") == 0)); ++ template.bp_forcehw = ((strcmp(argv[0], "bph") == 0) ++ || (strcmp(argv[0], "bpha") == 0)); ++ ++ /* Fix me: "bp" is treated as "bpa" to avoid system freeze. -jlan */ ++ if (strcmp(argv[0], "bp") == 0) ++ template.bp_global = 1; ++ ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &template.bp_addr, ++ &offset, &symname); ++ if (diag) ++ return diag; ++ if (!template.bp_addr) ++ return KDB_BADINT; ++ ++ /* ++ * Find an empty bp structure, to allocate ++ */ ++ free = KDB_MAXBPT; ++ for(bpno=0,bp=kdb_breakpoints; bpnobp_free) { ++ break; ++ } ++ } ++ ++ if (bpno == KDB_MAXBPT) ++ return KDB_TOOMANYBPT; ++ ++ /* ++ * Handle architecture dependent parsing ++ */ ++ diag = kdba_parsebp(argc, argv, &nextarg, &template); ++ if (diag) { ++ return diag; ++ } ++ ++ ++ /* ++ * Check for clashing breakpoints. ++ * ++ * Note, in this design we can't have hardware breakpoints ++ * enabled for both read and write on the same address, even ++ * though ia64 allows this. ++ */ ++ for(i=0,bp_check=kdb_breakpoints; ibp_free && ++ bp_check->bp_addr == template.bp_addr && ++ (bp_check->bp_global || ++ bp_check->bp_cpu == template.bp_cpu)) { ++ kdb_printf("You already have a breakpoint at " kdb_bfd_vma_fmt0 "\n", template.bp_addr); ++ return KDB_DUPBPT; ++ } ++ } ++ ++ template.bp_enabled = 1; ++ ++ /* ++ * Actually allocate the breakpoint found earlier ++ */ ++ *bp = template; ++ bp->bp_free = 0; ++ ++ if (!bp->bp_global) { ++ bp->bp_cpu = smp_processor_id(); ++ } ++ ++ /* ++ * Allocate a hardware breakpoint. If one is not available, ++ * disable the breakpoint, but leave it in the breakpoint ++ * table. When the breakpoint is re-enabled (via 'be'), we'll ++ * attempt to allocate a hardware register for it. ++ */ ++ if (!bp->bp_template.bph_free) { ++ kdba_alloc_hwbp(bp, &diag); ++ if (diag) { ++ bp->bp_enabled = 0; ++ bp->bp_hardtype = 0; ++ kdba_free_hwbp(bp); ++ return diag; ++ } ++ } ++ ++ kdb_printbp(bp, bpno); ++ ++ return 0; ++} ++ ++/* ++ * kdb_bc ++ * ++ * Handles the 'bc', 'be', and 'bd' commands ++ * ++ * [bd|bc|be] ++ * [bd|bc|be] * ++ * ++ * Parameters: ++ * argc Count of arguments in argv ++ * argv Space delimited command line arguments ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++#define KDBCMD_BC 0 ++#define KDBCMD_BE 1 ++#define KDBCMD_BD 2 ++ ++static int ++kdb_bc(int argc, const char **argv) ++{ ++ kdb_machreg_t addr; ++ kdb_bp_t *bp = NULL; ++ int lowbp = KDB_MAXBPT; ++ int highbp = 0; ++ int done = 0; ++ int i; ++ int diag; ++ int cmd; /* KDBCMD_B? */ ++ ++ if (strcmp(argv[0], "be") == 0) { ++ cmd = KDBCMD_BE; ++ } else if (strcmp(argv[0], "bd") == 0) { ++ cmd = KDBCMD_BD; ++ } else ++ cmd = KDBCMD_BC; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ if (strcmp(argv[1], "*") == 0) { ++ lowbp = 0; ++ highbp = KDB_MAXBPT; ++ } else { ++ diag = kdbgetularg(argv[1], &addr); ++ if (diag) ++ return diag; ++ ++ /* ++ * For addresses less than the maximum breakpoint number, ++ * assume that the breakpoint number is desired. ++ */ ++ if (addr < KDB_MAXBPT) { ++ bp = &kdb_breakpoints[addr]; ++ lowbp = highbp = addr; ++ highbp++; ++ } else { ++ for(i=0, bp=kdb_breakpoints; ibp_addr == addr) { ++ lowbp = highbp = i; ++ highbp++; ++ break; ++ } ++ } ++ } ++ } ++ ++ /* ++ * Now operate on the set of breakpoints matching the input ++ * criteria (either '*' for all, or an individual breakpoint). ++ */ ++ for(bp=&kdb_breakpoints[lowbp], i=lowbp; ++ i < highbp; ++ i++, bp++) { ++ if (bp->bp_free) ++ continue; ++ ++ done++; ++ ++ switch (cmd) { ++ case KDBCMD_BC: ++ if (bp->bp_hardtype) ++ kdba_free_hwbp(bp); ++ ++ bp->bp_enabled = 0; ++ bp->bp_global = 0; ++ ++ kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " cleared\n", ++ i, bp->bp_addr); ++ ++ bp->bp_addr = 0; ++ bp->bp_free = 1; ++ ++ break; ++ case KDBCMD_BE: ++ /* ++ * Allocate a hardware breakpoint. If one is not ++ * available, don't enable the breakpoint. ++ */ ++ if (!bp->bp_template.bph_free ++ && !bp->bp_hardtype) { ++ kdba_alloc_hwbp(bp, &diag); ++ if (diag) { ++ bp->bp_enabled = 0; ++ bp->bp_hardtype = 0; ++ kdba_free_hwbp(bp); ++ return diag; ++ } ++ } ++ ++ bp->bp_enabled = 1; ++ ++ kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " enabled", ++ i, bp->bp_addr); ++ ++ kdb_printf("\n"); ++ break; ++ case KDBCMD_BD: ++ if (!bp->bp_enabled) ++ break; ++ ++ /* ++ * Since this breakpoint is now disabled, we can ++ * give up the hardware register which is allocated ++ * to it. ++ */ ++ if (bp->bp_hardtype) ++ kdba_free_hwbp(bp); ++ ++ bp->bp_enabled = 0; ++ ++ kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " disabled\n", ++ i, bp->bp_addr); ++ ++ break; ++ } ++ if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) { ++ bp->bp_delay = 0; ++ KDB_STATE_CLEAR(SSBPT); ++ } ++ } ++ ++ return (!done)?KDB_BPTNOTFOUND:0; ++} ++ ++/* ++ * kdb_ss ++ * ++ * Process the 'ss' (Single Step) and 'ssb' (Single Step to Branch) ++ * commands. ++ * ++ * ss ++ * ssb ++ * ++ * Parameters: ++ * argc Argument count ++ * argv Argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * KDB_CMD_SS[B] for success, a kdb error if failure. ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * Set the arch specific option to trigger a debug trap after the next ++ * instruction. ++ * ++ * For 'ssb', set the trace flag in the debug trap handler ++ * after printing the current insn and return directly without ++ * invoking the kdb command processor, until a branch instruction ++ * is encountered. ++ */ ++ ++static int ++kdb_ss(int argc, const char **argv) ++{ ++ int ssb = 0; ++ struct pt_regs *regs = get_irq_regs(); ++ ++ ssb = (strcmp(argv[0], "ssb") == 0); ++ if (argc != 0) ++ return KDB_ARGCOUNT; ++ ++ if (!regs) { ++ kdb_printf("%s: pt_regs not available\n", __FUNCTION__); ++ return KDB_BADREG; ++ } ++ ++ /* ++ * Set trace flag and go. ++ */ ++ KDB_STATE_SET(DOING_SS); ++ if (ssb) ++ KDB_STATE_SET(DOING_SSB); ++ ++ kdba_setsinglestep(regs); /* Enable single step */ ++ ++ if (ssb) ++ return KDB_CMD_SSB; ++ return KDB_CMD_SS; ++} ++ ++/* ++ * kdb_initbptab ++ * ++ * Initialize the breakpoint table. Register breakpoint commands. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void __init ++kdb_initbptab(void) ++{ ++ int i; ++ kdb_bp_t *bp; ++ ++ /* ++ * First time initialization. ++ */ ++ memset(&kdb_breakpoints, '\0', sizeof(kdb_breakpoints)); ++ ++ for (i=0, bp=kdb_breakpoints; ibp_free = 1; ++ /* ++ * The bph_free flag is architecturally required. It ++ * is set by architecture-dependent code to false (zero) ++ * in the event a hardware breakpoint register is required ++ * for this breakpoint. ++ * ++ * The rest of the template is reserved to the architecture ++ * dependent code and _must_ not be touched by the architecture ++ * independent code. ++ */ ++ bp->bp_template.bph_free = 1; ++ } ++ ++ kdb_register_repeat("bp", kdb_bp, "[]", "Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("bl", kdb_bp, "[]", "Display breakpoints", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("bpa", kdb_bp, "[]", "Set/Display global breakpoints", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("bph", kdb_bp, "[]", "Set hardware breakpoint", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("bpha", kdb_bp, "[]", "Set global hardware breakpoint", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("bc", kdb_bc, "", "Clear Breakpoint", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("be", kdb_bc, "", "Enable Breakpoint", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("bd", kdb_bc, "", "Disable Breakpoint", 0, KDB_REPEAT_NONE); ++ ++ kdb_register_repeat("ss", kdb_ss, "", "Single Step", 1, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("ssb", kdb_ss, "", "Single step to branch/call", 0, KDB_REPEAT_NO_ARGS); ++ /* ++ * Architecture dependent initialization. ++ */ ++ kdba_initbp(); ++} +--- /dev/null ++++ b/kdb/kdb_bt.c +@@ -0,0 +1,180 @@ ++/* ++ * Kernel Debugger Architecture Independent Stack Traceback ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* ++ * kdb_bt ++ * ++ * This function implements the 'bt' command. Print a stack ++ * traceback. ++ * ++ * bt [] (addr-exp is for alternate stacks) ++ * btp Kernel stack for ++ * btt Kernel stack for task structure at ++ * bta [DRSTCZEUIMA] All useful processes, optionally filtered by state ++ * btc [] The current process on one cpu, default is all cpus ++ * ++ * bt refers to a address on the stack, that location ++ * is assumed to contain a return address. ++ * ++ * btt refers to the address of a struct task. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * Backtrack works best when the code uses frame pointers. But even ++ * without frame pointers we should get a reasonable trace. ++ * ++ * mds comes in handy when examining the stack to do a manual traceback or ++ * to get a starting point for bt . ++ */ ++ ++static int ++kdb_bt1(const struct task_struct *p, unsigned long mask, int argcount, int btaprompt) ++{ ++ int diag; ++ char buffer[2]; ++ if (kdb_getarea(buffer[0], (unsigned long)p) || ++ kdb_getarea(buffer[0], (unsigned long)(p+1)-1)) ++ return KDB_BADADDR; ++ if (!kdb_task_state(p, mask)) ++ return 0; ++ kdb_printf("Stack traceback for pid %d\n", p->pid); ++ kdb_ps1(p); ++ diag = kdba_bt_process(p, argcount); ++ if (btaprompt) { ++ kdb_getstr(buffer, sizeof(buffer), "Enter to end, to continue:"); ++ if (buffer[0] == 'q') { ++ kdb_printf("\n"); ++ return 1; ++ } ++ } ++ touch_nmi_watchdog(); ++ return 0; ++} ++ ++int ++kdb_bt(int argc, const char **argv) ++{ ++ int diag; ++ int argcount = 5; ++ int btaprompt = 1; ++ int nextarg; ++ unsigned long addr; ++ long offset; ++ ++ kdbgetintenv("BTARGS", &argcount); /* Arguments to print */ ++ kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each proc in bta */ ++ ++ if (strcmp(argv[0], "bta") == 0) { ++ struct task_struct *g, *p; ++ unsigned long cpu; ++ unsigned long mask = kdb_task_state_string(argc ? argv[1] : NULL); ++ if (argc == 0) ++ kdb_ps_suppressed(); ++ /* Run the active tasks first */ ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (!cpu_online(cpu)) ++ continue; ++ p = kdb_curr_task(cpu); ++ if (kdb_bt1(p, mask, argcount, btaprompt)) ++ return 0; ++ } ++ /* Now the inactive tasks */ ++ kdb_do_each_thread(g, p) { ++ if (task_curr(p)) ++ continue; ++ if (kdb_bt1(p, mask, argcount, btaprompt)) ++ return 0; ++ } kdb_while_each_thread(g, p); ++ } else if (strcmp(argv[0], "btp") == 0) { ++ struct task_struct *p; ++ unsigned long pid; ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ if ((diag = kdbgetularg((char *)argv[1], &pid))) ++ return diag; ++ if ((p = find_task_by_pid_type_ns(PIDTYPE_PID, pid, &init_pid_ns))) { ++ kdba_set_current_task(p); ++ return kdb_bt1(p, ~0UL, argcount, 0); ++ } ++ kdb_printf("No process with pid == %ld found\n", pid); ++ return 0; ++ } else if (strcmp(argv[0], "btt") == 0) { ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ if ((diag = kdbgetularg((char *)argv[1], &addr))) ++ return diag; ++ kdba_set_current_task((struct task_struct *)addr); ++ return kdb_bt1((struct task_struct *)addr, ~0UL, argcount, 0); ++ } else if (strcmp(argv[0], "btc") == 0) { ++ unsigned long cpu = ~0; ++ struct kdb_running_process *krp; ++ const struct task_struct *save_current_task = kdb_current_task; ++ char buf[80]; ++ if (argc > 1) ++ return KDB_ARGCOUNT; ++ if (argc == 1 && (diag = kdbgetularg((char *)argv[1], &cpu))) ++ return diag; ++ /* Recursive use of kdb_parse, do not use argv after this point */ ++ argv = NULL; ++ if (cpu != ~0) { ++ krp = kdb_running_process + cpu; ++ if (cpu >= NR_CPUS || !krp->seqno || !cpu_online(cpu)) { ++ kdb_printf("no process for cpu %ld\n", cpu); ++ return 0; ++ } ++ sprintf(buf, "btt 0x%p\n", krp->p); ++ kdb_parse(buf); ++ return 0; ++ } ++ kdb_printf("btc: cpu status: "); ++ kdb_parse("cpu\n"); ++ for (cpu = 0, krp = kdb_running_process; cpu < NR_CPUS; ++cpu, ++krp) { ++ if (!cpu_online(cpu) || !krp->seqno) ++ continue; ++ sprintf(buf, "btt 0x%p\n", krp->p); ++ kdb_parse(buf); ++ touch_nmi_watchdog(); ++ } ++ kdba_set_current_task(save_current_task); ++ return 0; ++ } else { ++ if (argc) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, ++ &offset, NULL); ++ if (diag) ++ return diag; ++ return kdba_bt_address(addr, argcount); ++ } else { ++ return kdb_bt1(kdb_current_task, ~0UL, argcount, 0); ++ } ++ } ++ ++ /* NOTREACHED */ ++ return 0; ++} +--- /dev/null ++++ b/kdb/kdb_cmds +@@ -0,0 +1,32 @@ ++# Initial commands for kdb, alter to suit your needs. ++# These commands are executed in kdb_init() context, no SMP, no ++# processes. Commands that require process data (including stack or ++# registers) are not reliable this early. set and bp commands should ++# be safe. Global breakpoint commands affect each cpu as it is booted. ++ ++# Standard debugging information for first level support, just type archkdb ++# or archkdbcpu or archkdbshort at the kdb prompt. ++ ++defcmd archkdb "" "First line arch debugging" ++ set BTSYMARG 1 ++ set BTARGS 9 ++ pid R ++ -archkdbcommon ++ -bta ++endefcmd ++ ++defcmd archkdbcpu "" "archkdb with only tasks on cpus" ++ set BTSYMARG 1 ++ set BTARGS 9 ++ pid R ++ -archkdbcommon ++ -btc ++endefcmd ++ ++defcmd archkdbshort "" "archkdb with less detailed backtrace" ++ set BTSYMARG 0 ++ set BTARGS 0 ++ pid R ++ -archkdbcommon ++ -bta ++endefcmd +--- /dev/null ++++ b/kdb/kdb_id.c +@@ -0,0 +1,236 @@ ++/* ++ * Kernel Debugger Architecture Independent Instruction Disassembly ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++disassemble_info kdb_di; ++ ++/* ++ * kdb_id ++ * ++ * Handle the id (instruction display) command. ++ * ++ * id [] ++ * ++ * Parameters: ++ * argc Count of arguments in argv ++ * argv Space delimited command line arguments ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic if failure. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdb_id(int argc, const char **argv) ++{ ++ kdb_machreg_t pc; ++ int icount; ++ int diag; ++ int i; ++ char *mode; ++ int nextarg; ++ long offset = 0; ++ static kdb_machreg_t lastpc; ++ struct disassemble_info *dip = &kdb_di; ++ char lastbuf[50]; ++ unsigned long word; ++ ++ kdb_di.fprintf_func = kdb_dis_fprintf; ++ kdba_id_init(&kdb_di); ++ ++ if (argc != 1) { ++ if (lastpc == 0) { ++ return KDB_ARGCOUNT; ++ } else { ++ sprintf(lastbuf, "0x%lx", lastpc); ++ argv[1] = lastbuf; ++ argc = 1; ++ } ++ } ++ ++ ++ /* ++ * Fetch PC. First, check to see if it is a symbol, if not, ++ * try address. ++ */ ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &pc, &offset, NULL); ++ if (diag) ++ return diag; ++ kdba_check_pc(&pc); ++ if (kdb_getarea(word, pc)) ++ return(0); ++ ++ /* ++ * Number of lines to display ++ */ ++ diag = kdbgetintenv("IDCOUNT", &icount); ++ if (diag) ++ return diag; ++ ++ mode = kdbgetenv("IDMODE"); ++ diag = kdba_id_parsemode(mode, dip); ++ if (diag) { ++ return diag; ++ } ++ ++ for(i=0; i ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++static struct console *kdbcons; ++ ++#ifdef CONFIG_PPC64 ++#include ++#endif ++ ++#define CMD_BUFLEN 256 ++char kdb_prompt_str[CMD_BUFLEN]; ++ ++extern int kdb_grepping_flag; ++extern char kdb_grep_string[]; ++extern int kdb_grep_leading; ++extern int kdb_grep_trailing; ++ ++/* ++ * kdb_read ++ * ++ * This function reads a string of characters, terminated by ++ * a newline, or by reaching the end of the supplied buffer, ++ * from the current kernel debugger console device. ++ * Parameters: ++ * buffer - Address of character buffer to receive input characters. ++ * bufsize - size, in bytes, of the character buffer ++ * Returns: ++ * Returns a pointer to the buffer containing the received ++ * character string. This string will be terminated by a ++ * newline character. ++ * Locking: ++ * No locks are required to be held upon entry to this ++ * function. It is not reentrant - it relies on the fact ++ * that while kdb is running on any one processor all other ++ * processors will be spinning at the kdb barrier. ++ * Remarks: ++ * ++ * Davidm asks, why doesn't kdb use the console abstraction; ++ * here are some reasons: ++ * - you cannot debug the console abstraction with kdb if ++ * kdb uses it. ++ * - you rely on the correct functioning of the abstraction ++ * in the presence of general system failures. ++ * - You must acquire the console spinlock thus restricting ++ * the usability - what if the kernel fails with the spinlock ++ * held - one still wishes to debug such situations. ++ * - How about debugging before the console(s) are registered? ++ * - None of the current consoles (sercons, vt_console_driver) ++ * have read functions defined. ++ * - The standard pc keyboard and terminal drivers are interrupt ++ * driven. We cannot enable interrupts while kdb is active, ++ * so the standard input functions cannot be used by kdb. ++ * ++ * An implementation could be improved by removing the need for ++ * lock acquisition - just keep a 'struct console *kdbconsole;' global ++ * variable which refers to the preferred kdb console. ++ * ++ * The bulk of this function is architecture dependent. ++ * ++ * The buffer size must be >= 2. A buffer size of 2 means that the caller only ++ * wants a single key. ++ * ++ * An escape key could be the start of a vt100 control sequence such as \e[D ++ * (left arrow) or it could be a character in its own right. The standard ++ * method for detecting the difference is to wait for 2 seconds to see if there ++ * are any other characters. kdb is complicated by the lack of a timer service ++ * (interrupts are off), by multiple input sources and by the need to sometimes ++ * return after just one key. Escape sequence processing has to be done as ++ * states in the polling loop. ++ */ ++ ++char * ++kdb_read(char *buffer, size_t bufsize) ++{ ++ char *cp = buffer; ++ char *bufend = buffer+bufsize-2; /* Reserve space for newline and null byte */ ++ ++ char *lastchar; ++ char *p_tmp; ++ char tmp; ++ static char tmpbuffer[CMD_BUFLEN]; ++ int len = strlen(buffer); ++ int len_tmp; ++ int tab=0; ++ int count; ++ int i; ++ int diag, dtab_count; ++ ++#define ESCAPE_UDELAY 1000 ++#define ESCAPE_DELAY 2*1000000/ESCAPE_UDELAY /* 2 seconds worth of udelays */ ++ char escape_data[5]; /* longest vt100 escape sequence is 4 bytes */ ++ char *ped = escape_data; ++ int escape_delay = 0; ++ get_char_func *f, *f_escape = NULL; ++ ++ diag = kdbgetintenv("DTABCOUNT",&dtab_count); ++ if (diag) ++ dtab_count = 30; ++ ++ if (len > 0 ) { ++ cp += len; ++ if (*(buffer+len-1) == '\n') ++ cp--; ++ } ++ ++ lastchar = cp; ++ *cp = '\0'; ++ kdb_printf("%s", buffer); ++ ++ for (;;) { ++ int key; ++ for (f = &poll_funcs[0]; ; ++f) { ++ if (*f == NULL) { ++ /* Reset NMI watchdog once per poll loop */ ++ touch_nmi_watchdog(); ++ f = &poll_funcs[0]; ++ } ++ if (escape_delay == 2) { ++ *ped = '\0'; ++ ped = escape_data; ++ --escape_delay; ++ } ++ if (escape_delay == 1) { ++ key = *ped++; ++ if (!*ped) ++ --escape_delay; ++ break; ++ } ++ key = (*f)(); ++ if (key == -1) { ++ if (escape_delay) { ++ udelay(ESCAPE_UDELAY); ++ --escape_delay; ++ } ++ continue; ++ } ++ if (bufsize <= 2) { ++ if (key == '\r') ++ key = '\n'; ++ kdb_printf("%c", key); ++ *buffer++ = key; ++ *buffer = '\0'; ++ return buffer; ++ } ++ if (escape_delay == 0 && key == '\e') { ++ escape_delay = ESCAPE_DELAY; ++ ped = escape_data; ++ f_escape = f; ++ } ++ if (escape_delay) { ++ *ped++ = key; ++ if (f_escape != f) { ++ escape_delay = 2; ++ continue; ++ } ++ if (ped - escape_data == 1) { ++ /* \e */ ++ continue; ++ } ++ else if (ped - escape_data == 2) { ++ /* \e */ ++ if (key != '[') ++ escape_delay = 2; ++ continue; ++ } else if (ped - escape_data == 3) { ++ /* \e[ */ ++ int mapkey = 0; ++ switch (key) { ++ case 'A': mapkey = 16; break; /* \e[A, up arrow */ ++ case 'B': mapkey = 14; break; /* \e[B, down arrow */ ++ case 'C': mapkey = 6; break; /* \e[C, right arrow */ ++ case 'D': mapkey = 2; break; /* \e[D, left arrow */ ++ case '1': /* dropthrough */ ++ case '3': /* dropthrough */ ++ case '4': mapkey = -1; break; /* \e[<1,3,4>], may be home, del, end */ ++ } ++ if (mapkey != -1) { ++ if (mapkey > 0) { ++ escape_data[0] = mapkey; ++ escape_data[1] = '\0'; ++ } ++ escape_delay = 2; ++ } ++ continue; ++ } else if (ped - escape_data == 4) { ++ /* \e[<1,3,4> */ ++ int mapkey = 0; ++ if (key == '~') { ++ switch (escape_data[2]) { ++ case '1': mapkey = 1; break; /* \e[1~, home */ ++ case '3': mapkey = 4; break; /* \e[3~, del */ ++ case '4': mapkey = 5; break; /* \e[4~, end */ ++ } ++ } ++ if (mapkey > 0) { ++ escape_data[0] = mapkey; ++ escape_data[1] = '\0'; ++ } ++ escape_delay = 2; ++ continue; ++ } ++ } ++ break; /* A key to process */ ++ } ++ ++ if (key != 9) ++ tab = 0; ++ switch (key) { ++ case 8: /* backspace */ ++ if (cp > buffer) { ++ if (cp < lastchar) { ++ memcpy(tmpbuffer, cp, lastchar - cp); ++ memcpy(cp-1, tmpbuffer, lastchar - cp); ++ } ++ *(--lastchar) = '\0'; ++ --cp; ++ kdb_printf("\b%s \r", cp); ++ tmp = *cp; ++ *cp = '\0'; ++ kdb_printf(kdb_prompt_str); ++ kdb_printf("%s", buffer); ++ *cp = tmp; ++ } ++ break; ++ case 13: /* enter */ ++ *lastchar++ = '\n'; ++ *lastchar++ = '\0'; ++ kdb_printf("\n"); ++ return buffer; ++ case 4: /* Del */ ++ if(cp < lastchar) { ++ memcpy(tmpbuffer, cp+1, lastchar - cp -1); ++ memcpy(cp, tmpbuffer, lastchar - cp -1); ++ *(--lastchar) = '\0'; ++ kdb_printf("%s \r", cp); ++ tmp = *cp; ++ *cp = '\0'; ++ kdb_printf(kdb_prompt_str); ++ kdb_printf("%s", buffer); ++ *cp = tmp; ++ } ++ break; ++ case 1: /* Home */ ++ if(cp > buffer) { ++ kdb_printf("\r"); ++ kdb_printf(kdb_prompt_str); ++ cp = buffer; ++ } ++ break; ++ case 5: /* End */ ++ if(cp < lastchar) { ++ kdb_printf("%s", cp); ++ cp = lastchar; ++ } ++ break; ++ case 2: /* Left */ ++ if (cp > buffer) { ++ kdb_printf("\b"); ++ --cp; ++ } ++ break; ++ case 14: /* Down */ ++ memset(tmpbuffer, ' ', strlen(kdb_prompt_str)+(lastchar-buffer)); ++ *(tmpbuffer+strlen(kdb_prompt_str)+(lastchar-buffer)) = '\0'; ++ kdb_printf("\r%s\r", tmpbuffer); ++ *lastchar = (char)key; ++ *(lastchar+1) = '\0'; ++ return lastchar; ++ case 6: /* Right */ ++ if (cp < lastchar) { ++ kdb_printf("%c", *cp); ++ ++cp; ++ } ++ break; ++ case 16: /* Up */ ++ memset(tmpbuffer, ' ', strlen(kdb_prompt_str)+(lastchar-buffer)); ++ *(tmpbuffer+strlen(kdb_prompt_str)+(lastchar-buffer)) = '\0'; ++ kdb_printf("\r%s\r", tmpbuffer); ++ *lastchar = (char)key; ++ *(lastchar+1) = '\0'; ++ return lastchar; ++ case 9: /* Tab */ ++ if (tab < 2) ++ ++tab; ++ p_tmp = buffer; ++ while(*p_tmp==' ') p_tmp++; ++ if (p_tmp<=cp) { ++ memcpy(tmpbuffer, p_tmp, cp-p_tmp); ++ *(tmpbuffer + (cp-p_tmp)) = '\0'; ++ p_tmp = strrchr(tmpbuffer, ' '); ++ if (p_tmp) ++ ++p_tmp; ++ else ++ p_tmp = tmpbuffer; ++ len = strlen(p_tmp); ++ count = kallsyms_symbol_complete(p_tmp, sizeof(tmpbuffer) - (p_tmp - tmpbuffer)); ++ if (tab == 2) { ++ if (count > 0) { ++ kdb_printf("\n%d symbols are found.", count); ++ if(count>dtab_count) { ++ count=dtab_count; ++ kdb_printf(" But only first %d symbols will be printed.\nYou can change the environment variable DTABCOUNT.", count); ++ } ++ kdb_printf("\n"); ++ for(i=0;i=dtab_count)kdb_printf("..."); ++ kdb_printf("\n"); ++ kdb_printf(kdb_prompt_str); ++ kdb_printf("%s", buffer); ++ } ++ } ++ else { ++ if (count > 0) { ++ len_tmp = strlen(p_tmp); ++ strncpy(p_tmp+len_tmp,cp, lastchar-cp+1); ++ len_tmp = strlen(p_tmp); ++ strncpy(cp, p_tmp+len, len_tmp-len+1); ++ len = len_tmp - len; ++ kdb_printf("%s", cp); ++ cp+=len; ++ lastchar+=len; ++ } ++ } ++ kdb_nextline = 1; /* reset output line number */ ++ } ++ break; ++ default: ++ if (key >= 32 &&lastchar < bufend) { ++ if (cp < lastchar) { ++ memcpy(tmpbuffer, cp, lastchar - cp); ++ memcpy(cp+1, tmpbuffer, lastchar - cp); ++ *++lastchar = '\0'; ++ *cp = key; ++ kdb_printf("%s\r", cp); ++ ++cp; ++ tmp = *cp; ++ *cp = '\0'; ++ kdb_printf(kdb_prompt_str); ++ kdb_printf("%s", buffer); ++ *cp = tmp; ++ } else { ++ *++lastchar = '\0'; ++ *cp++ = key; ++ kdb_printf("%c", key); ++ } ++ } ++ break; ++ } ++ } ++} ++ ++/* ++ * kdb_getstr ++ * ++ * Print the prompt string and read a command from the ++ * input device. ++ * ++ * Parameters: ++ * buffer Address of buffer to receive command ++ * bufsize Size of buffer in bytes ++ * prompt Pointer to string to use as prompt string ++ * Returns: ++ * Pointer to command buffer. ++ * Locking: ++ * None. ++ * Remarks: ++ * For SMP kernels, the processor number will be ++ * substituted for %d, %x or %o in the prompt. ++ */ ++ ++char * ++kdb_getstr(char *buffer, size_t bufsize, char *prompt) ++{ ++ if(prompt && kdb_prompt_str!=prompt) ++ strncpy(kdb_prompt_str, prompt, CMD_BUFLEN); ++ kdb_printf(kdb_prompt_str); ++ kdb_nextline = 1; /* Prompt and input resets line number */ ++ return kdb_read(buffer, bufsize); ++} ++ ++/* ++ * kdb_input_flush ++ * ++ * Get rid of any buffered console input. ++ * ++ * Parameters: ++ * none ++ * Returns: ++ * nothing ++ * Locking: ++ * none ++ * Remarks: ++ * Call this function whenever you want to flush input. If there is any ++ * outstanding input, it ignores all characters until there has been no ++ * data for approximately half a second. ++ */ ++ ++#define FLUSH_UDELAY 100 ++#define FLUSH_DELAY 500000/FLUSH_UDELAY /* 0.5 seconds worth of udelays */ ++ ++static void ++kdb_input_flush(void) ++{ ++ get_char_func *f; ++ int flush_delay = 1; ++ while (flush_delay--) { ++ touch_nmi_watchdog(); ++ for (f = &poll_funcs[0]; *f; ++f) { ++ if ((*f)() != -1) { ++ flush_delay = FLUSH_DELAY; ++ break; ++ } ++ } ++ if (flush_delay) ++ udelay(FLUSH_UDELAY); ++ } ++} ++ ++/* ++ * kdb_printf ++ * ++ * Print a string to the output device(s). ++ * ++ * Parameters: ++ * printf-like format and optional args. ++ * Returns: ++ * 0 ++ * Locking: ++ * None. ++ * Remarks: ++ * use 'kdbcons->write()' to avoid polluting 'log_buf' with ++ * kdb output. ++ * ++ * If the user is doing a cmd args | grep srch ++ * then kdb_grepping_flag is set. ++ * In that case we need to accumulate full lines (ending in \n) before ++ * searching for the pattern. ++ */ ++ ++static char kdb_buffer[256]; /* A bit too big to go on stack */ ++static char *next_avail=kdb_buffer; ++static int size_avail; ++static int suspend_grep=0; ++ ++/* ++ * search arg1 to see if it contains arg2 ++ * (kdmain.c provides flags for ^pat and pat$) ++ * ++ * return 1 for found, 0 for not found ++ */ ++int ++kdb_search_string(char *searched, char *searchfor) ++{ ++ char firstchar, *cp; ++ int len1, len2; ++ ++ /* not counting the newline at the end of "searched" */ ++ len1 = strlen(searched)-1; ++ len2 = strlen(searchfor); ++ if (len1 < len2) return 0; ++ if (kdb_grep_leading && kdb_grep_trailing && len1 != len2) return 0; ++ ++ if (kdb_grep_leading) { ++ if (!strncmp(searched, searchfor, len2)) { ++ return 1; ++ } ++ } else if (kdb_grep_trailing) { ++ if (!strncmp(searched+len1-len2, searchfor, len2)) { ++ return 1; ++ } ++ } else { ++ firstchar = *searchfor; ++ cp = searched; ++ while ((cp = strchr(cp,firstchar))) { ++ if (!strncmp(cp, searchfor, len2)) { ++ return 1; ++ } ++ cp++; ++ } ++ } ++ return 0; ++} ++ ++void ++kdb_printf(const char *fmt, ...) ++{ ++ va_list ap; ++ int diag; ++ int linecount; ++ int logging, saved_loglevel = 0; ++ int do_longjmp = 0; ++ int got_printf_lock = 0; ++ int fnd, len; ++ char *cp, *cp2, *cphold = NULL, replaced_byte = ' '; ++ char *moreprompt = "more> "; ++ struct console *c = console_drivers; ++ static DEFINE_SPINLOCK(kdb_printf_lock); ++ unsigned long uninitialized_var(flags); ++ ++ preempt_disable(); ++ /* Serialize kdb_printf if multiple cpus try to write at once. ++ * But if any cpu goes recursive in kdb, just print the output, ++ * even if it is interleaved with any other text. ++ */ ++ if (!KDB_STATE(PRINTF_LOCK)) { ++ KDB_STATE_SET(PRINTF_LOCK); ++ spin_lock_irqsave(&kdb_printf_lock, flags); ++ got_printf_lock = 1; ++ atomic_inc(&kdb_event); ++ } else { ++ __acquire(kdb_printf_lock); ++ } ++ ++ diag = kdbgetintenv("LINES", &linecount); ++ if (diag || linecount <= 1) ++ linecount = 22; ++ ++ diag = kdbgetintenv("LOGGING", &logging); ++ if (diag) ++ logging = 0; ++ ++ if (!kdb_grepping_flag || suspend_grep) { ++ /* normally, every vsnprintf starts a new buffer */ ++ next_avail = kdb_buffer; ++ size_avail = sizeof(kdb_buffer); ++ } ++ va_start(ap, fmt); ++ vsnprintf(next_avail, size_avail, fmt, ap); ++ va_end(ap); ++ ++ /* ++ * If kdb_parse() found that the command was cmd xxx | grep yyy ++ * then kdb_grepping_flag is set, and kdb_grep_string contains yyy ++ * ++ * Accumulate the print data up to a newline before searching it. ++ * (vsnprintf does null-terminate the string that it generates) ++ */ ++ ++ /* skip the search if prints are temporarily unconditional */ ++ if (! suspend_grep) { ++ ++ if (kdb_grepping_flag) { ++ cp = strchr(kdb_buffer, '\n'); ++ if (!cp) { ++ /* ++ * Special cases that don't end with newlines ++ * but should be written without one: ++ * The "[nn]kdb> " prompt should ++ * appear at the front of the buffer. ++ * ++ * The "[nn]more " prompt should also be ++ * (MOREPROMPT -> moreprompt) ++ * written * but we print that ourselves, ++ * we set the suspend_grep flag to make ++ * it unconditional. ++ * ++ */ ++ if (next_avail == kdb_buffer) { ++ /* ++ * these should occur after a newline, ++ * so they will be at the front of ++ * the buffer ++ */ ++ cp2 = kdb_buffer; ++ len = strlen(kdb_prompt_str); ++ if (!strncmp(cp2,kdb_prompt_str, len)) { ++ /* ++ * We're about to start a new ++ * command, so we can go back ++ * to normal mode. ++ */ ++ kdb_grepping_flag = 0; ++ goto kdb_printit; ++ } ++ } ++ /* no newline; don't search/write the buffer ++ until one is there */ ++ len = strlen(kdb_buffer); ++ next_avail = kdb_buffer + len; ++ size_avail = sizeof(kdb_buffer) - len; ++ goto kdb_print_out; ++ } ++ ++ /* ++ * The newline is present; print through it or discard ++ * it, depending on the results of the search. ++ */ ++ cp++; /* to byte after the newline */ ++ replaced_byte = *cp; /* remember what/where it was */ ++ cphold = cp; ++ *cp = '\0'; /* end the string for our search */ ++ ++ /* ++ * We now have a newline at the end of the string ++ * Only continue with this output if it contains the ++ * search string. ++ */ ++ fnd = kdb_search_string(kdb_buffer, kdb_grep_string); ++ if (!fnd) { ++ /* ++ * At this point the complete line at the start ++ * of kdb_buffer can be discarded, as it does ++ * not contain what the user is looking for. ++ * Shift the buffer left. ++ */ ++ *cphold = replaced_byte; ++ strcpy(kdb_buffer, cphold); ++ len = strlen(kdb_buffer); ++ next_avail = kdb_buffer + len; ++ size_avail = sizeof(kdb_buffer) - len; ++ goto kdb_print_out; ++ } ++ /* ++ * at this point the string is a full line and ++ * should be printed, up to the null. ++ */ ++ } ++ } ++kdb_printit: ++ ++ /* ++ * Write to all consoles. ++ */ ++#ifdef CONFIG_SPARC64 ++ if (c == NULL) ++ prom_printf("%s", kdb_buffer); ++ else ++#endif ++ ++#ifdef CONFIG_PPC64 ++ if (udbg_write) ++ udbg_write(kdb_buffer, strlen(kdb_buffer)); ++ else ++#endif ++ ++ while (c) { ++ c->write(c, kdb_buffer, strlen(kdb_buffer)); ++ touch_nmi_watchdog(); ++ c = c->next; ++ } ++ if (logging) { ++ saved_loglevel = console_loglevel; ++ console_loglevel = 0; ++ printk("%s", kdb_buffer); ++ } ++ ++ if (KDB_STATE(LONGJMP) && strchr(kdb_buffer, '\n')) ++ kdb_nextline++; ++ ++ /* check for having reached the LINES number of printed lines */ ++ if (kdb_nextline == linecount) { ++ char buf1[16]=""; ++#if defined(CONFIG_SMP) ++ char buf2[32]; ++#endif ++ ++ /* Watch out for recursion here. Any routine that calls ++ * kdb_printf will come back through here. And kdb_read ++ * uses kdb_printf to echo on serial consoles ... ++ */ ++ kdb_nextline = 1; /* In case of recursion */ ++ ++ /* ++ * Pause until cr. ++ */ ++ moreprompt = kdbgetenv("MOREPROMPT"); ++ if (moreprompt == NULL) { ++ moreprompt = "more> "; ++ } ++ ++#if defined(CONFIG_SMP) ++ if (strchr(moreprompt, '%')) { ++ sprintf(buf2, moreprompt, get_cpu()); ++ put_cpu(); ++ moreprompt = buf2; ++ } ++#endif ++ ++ kdb_input_flush(); ++ c = console_drivers; ++#ifdef CONFIG_SPARC64 ++ if (c == NULL) ++ prom_printf("%s", moreprompt); ++ else ++#endif ++ ++#ifdef CONFIG_PPC64 ++ if (udbg_write) ++ udbg_write(moreprompt, strlen(moreprompt)); ++ else ++#endif ++ ++ while (c) { ++ c->write(c, moreprompt, strlen(moreprompt)); ++ touch_nmi_watchdog(); ++ c = c->next; ++ } ++ ++ if (logging) ++ printk("%s", moreprompt); ++ ++ kdb_read(buf1, 2); /* '2' indicates to return immediately after getting one key. */ ++ kdb_nextline = 1; /* Really set output line 1 */ ++ ++ /* empty and reset the buffer: */ ++ kdb_buffer[0] = '\0'; ++ next_avail = kdb_buffer; ++ size_avail = sizeof(kdb_buffer); ++ if ((buf1[0] == 'q') || (buf1[0] == 'Q')) { ++ /* user hit q or Q */ ++ do_longjmp = 1; ++ KDB_FLAG_SET(CMD_INTERRUPT); /* command was interrupted */ ++ /* end of command output; back to normal mode */ ++ kdb_grepping_flag = 0; ++ kdb_printf("\n"); ++ } else if (buf1[0] && buf1[0] != '\n') { ++ /* user hit something other than enter */ ++ suspend_grep = 1; /* for this recursion */ ++ kdb_printf("\nOnly 'q' or 'Q' are processed at more prompt, input ignored\n"); ++ } else if (kdb_grepping_flag) { ++ /* user hit enter */ ++ suspend_grep = 1; /* for this recursion */ ++ kdb_printf("\n"); ++ } ++ kdb_input_flush(); ++ } ++ ++ /* ++ * For grep searches, shift the printed string left. ++ * replaced_byte contains the character that was overwritten with ++ * the terminating null, and cphold points to the null. ++ * Then adjust the notion of available space in the buffer. ++ */ ++ if (kdb_grepping_flag && !suspend_grep) { ++ *cphold = replaced_byte; ++ strcpy(kdb_buffer, cphold); ++ len = strlen(kdb_buffer); ++ next_avail = kdb_buffer + len; ++ size_avail = sizeof(kdb_buffer) - len; ++ } ++ ++kdb_print_out: ++ suspend_grep = 0; /* end of what may have been a recursive call */ ++ if (logging) { ++ console_loglevel = saved_loglevel; ++ } ++ if (KDB_STATE(PRINTF_LOCK) && got_printf_lock) { ++ got_printf_lock = 0; ++ spin_unlock_irqrestore(&kdb_printf_lock, flags); ++ KDB_STATE_CLEAR(PRINTF_LOCK); ++ atomic_dec(&kdb_event); ++ } else { ++ __release(kdb_printf_lock); ++ } ++ preempt_enable(); ++ if (do_longjmp) ++#ifdef kdba_setjmp ++ kdba_longjmp(&kdbjmpbuf[smp_processor_id()], 1) ++#endif /* kdba_setjmp */ ++ ; ++} ++ ++/* ++ * kdb_io_init ++ * ++ * Initialize kernel debugger output environment. ++ * ++ * Parameters: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * Select a console device. Only use a VT console if the user specified ++ * or defaulted console= /^tty[0-9]*$/ ++ */ ++ ++void __init ++kdb_io_init(void) ++{ ++ /* ++ * Select a console. ++ */ ++ struct console *c = console_drivers; ++ int vt_console = 0; ++ ++ while (c) { ++ if ((c->flags & CON_CONSDEV) && !kdbcons) ++ kdbcons = c; ++ if ((c->flags & CON_ENABLED) && ++ strncmp(c->name, "tty", 3) == 0) { ++ char *p = c->name + 3; ++ while (isdigit(*p)) ++ ++p; ++ if (*p == '\0') ++ vt_console = 1; ++ } ++ c = c->next; ++ } ++ ++ if (kdbcons == NULL) { ++ printk(KERN_ERR "kdb: Initialization failed - no console. kdb is disabled.\n"); ++ KDB_FLAG_SET(NO_CONSOLE); ++ kdb_on = 0; ++ } ++ if (!vt_console) ++ KDB_FLAG_SET(NO_VT_CONSOLE); ++ kdb_input_flush(); ++ return; ++} ++ ++#ifdef CONFIG_KDB_USB ++ ++int kdb_no_usb = 0; ++ ++static int __init opt_kdbnousb(char *str) ++{ ++ kdb_no_usb = 1; ++ return 0; ++} ++ ++early_param("kdbnousb", opt_kdbnousb); ++ ++#endif ++ ++EXPORT_SYMBOL(kdb_read); +--- /dev/null ++++ b/kdb/kdbdereference.c +@@ -0,0 +1,7257 @@ ++/* ++ * ++ * Most of this code is borrowed and adapted from the lkcd command "lcrash" ++ * and its supporting libarary. ++ * ++ * This kdb commands for casting memory structures. ++ * It provides ++ * "print" "px", "pd" * ++ * ++ * Careful of porting the klib KL_XXX functions (they call thru a jump table ++ * that we don't use here) ++ * ++ * The kernel type information is added be insmod'g the kdb debuginfo module ++ * It loads symbolic debugging info (provided from lcrash -o), ++ * (this information originally comes from the lcrash "kerntypes" file) ++ * ++ */ ++ ++#define VMALLOC_START_IA64 0xa000000200000000 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "modules/lcrash/klib.h" ++#include "modules/lcrash/kl_stringtab.h" ++#include "modules/lcrash/kl_btnode.h" ++#include "modules/lcrash/lc_eval.h" ++ ++#undef next_node /* collision with nodemask.h */ ++int have_debug_file = 0; ++dbg_sym_t *types_tree_head; ++dbg_sym_t *typedefs_tree_head; ++kltype_t *kltype_array; ++dbg_sym_t *dsym_types_array; ++ ++ ++EXPORT_SYMBOL(types_tree_head); ++EXPORT_SYMBOL(typedefs_tree_head); ++EXPORT_SYMBOL(kltype_array); ++EXPORT_SYMBOL(dsym_types_array); ++ ++#define C_HEX 0x0002 ++#define C_WHATIS 0x0004 ++#define C_NOVARS 0x0008 ++#define C_SIZEOF 0x0010 ++#define C_SHOWOFFSET 0x0020 ++#define C_LISTHEAD 0x0040 ++#define C_LISTHEAD_N 0x0080 /* walk using list_head.next */ ++#define C_LISTHEAD_P 0x0100 /* walk using list_head.prev */ ++#define C_BINARY 0x0200 ++#define MAX_LONG_LONG 0xffffffffffffffffULL ++klib_t kdb_klib; ++klib_t *KLP = &kdb_klib; ++k_error_t klib_error = 0; ++dbg_sym_t *type_tree = (dbg_sym_t *)NULL; ++dbg_sym_t *typedef_tree = (dbg_sym_t *)NULL; ++dbg_sym_t *func_tree = (dbg_sym_t *)NULL; ++dbg_sym_t *srcfile_tree = (dbg_sym_t *)NULL; ++dbg_sym_t *var_tree = (dbg_sym_t *)NULL; ++dbg_sym_t *xtype_tree = (dbg_sym_t *)NULL; ++dbg_hashrec_t *dbg_hash[TYPE_NUM_SLOTS]; ++int all_count, deall_count; ++void single_type(char *str); ++void sizeof_type(char *str); ++typedef struct chunk_s { ++ struct chunk_s *next; /* Must be first */ ++ struct chunk_s *prev; /* Must be second */ ++ void *addr; ++ struct bucket_s *bucketp; ++ uint32_t chunksz; /* size of memory chunk (via malloc()) */ ++ uint32_t blksz; /* Not including header */ ++ short blkcount; /* Number of blksz blocks in chunk */ ++} chunk_t; ++ ++typedef struct blkhdr_s { ++ struct blkhdr_s *next; ++ union { ++ struct blkhdr_s *prev; ++ chunk_t *chunkp; ++ } b_un; ++ int flg; ++ int size; ++} blkhdr_t; ++ ++int ptrsz64 = ((int)sizeof(void *) == 8); ++alloc_functions_t alloc_functions; ++ ++/* ++ * return 1 if addr is invalid ++ */ ++static int ++invalid_address(kaddr_t addr, int count) ++{ ++ unsigned char c; ++ unsigned long lcount; ++ /* FIXME: untested? */ ++ lcount = count; ++ /* FIXME: use kdb_verify_area */ ++ while (count--) { ++ if (kdb_getarea(c, addr)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * wrappers for calls to kernel-style allocation/deallocation ++ */ ++static void * ++kl_alloc_block(int size) ++{ ++ void *vp; ++ ++ vp = kmalloc(size, GFP_KERNEL); ++ if (!vp) { ++ kdb_printf ("kmalloc of %d bytes failed\n", size); ++ } ++ /* important: the lcrash code sometimes assumes that the ++ * allocation is zeroed out ++ */ ++ memset(vp, 0, size); ++ all_count++; ++ return vp; ++} ++static void ++kl_free_block(void *vp) ++{ ++ kfree(vp); ++ deall_count++; ++ return; ++} ++ ++int ++get_value(char *s, uint64_t *value) ++{ ++ return kl_get_value(s, NULL, 0, value); ++} ++ ++/* ++ * kl_get_block() ++ * ++ * Read a size block from virtual address addr in the system memory image. ++ */ ++k_error_t ++kl_get_block(kaddr_t addr, unsigned size, void *bp, void *mmap) ++{ ++ if (!bp) { ++ return(KLE_NULL_BUFF); ++ } else if (!size) { ++ return(KLE_ZERO_SIZE); ++ } ++ ++ memcpy(bp, (void *)addr, size); ++ ++ return(0); ++} ++ ++/* ++ * print_value() ++ */ ++void ++print_value(char *ldstr, uint64_t value, int width) ++{ ++ int w = 0; ++ char fmtstr[12], f, s[2]="\000\000"; ++ ++ if (ldstr) { ++ kdb_printf("%s", ldstr); ++ } ++ s[0] = '#'; ++ f = 'x'; ++ if (width) { ++ if (ptrsz64) { ++ w = 18; /* due to leading "0x" */ ++ } else { ++ w = 10; /* due to leading "0x" */ ++ } ++ } ++ if (w) { ++ sprintf(fmtstr, "%%%s%d"FMT64"%c", s, w, f); ++ } else { ++ sprintf(fmtstr, "%%%s"FMT64"%c", s, f); ++ } ++ kdb_printf(fmtstr, value); ++} ++ ++/* ++ * print_list_head() ++ */ ++void ++print_list_head(kaddr_t saddr) ++{ ++ print_value("STRUCT ADDR: ", (uint64_t)saddr, 8); ++ kdb_printf("\n"); ++} ++ ++/* ++ * check_prev_ptr() ++ */ ++void ++check_prev_ptr(kaddr_t ptr, kaddr_t prev) ++{ ++ if(ptr != prev) { ++ kdb_printf("\nWARNING: Pointer broken. %#"FMTPTR"x," ++ " SHOULD BE: %#"FMTPTR"x\n", prev, ptr); ++ } ++} ++ ++/* ++ * kl_kaddr() -- Return a kernel virtual address stored in a structure ++ * ++ * Pointer 'p' points to a kernel structure ++ * of type 's.' Get the kernel address located in member 'm.' ++ */ ++kaddr_t ++kl_kaddr(void *p, char *s, char *m) ++{ ++ uint64_t *u64p; ++ int offset; ++ ++ offset = kl_member_offset(s, m); ++ u64p = (uint64_t *)(p + offset); ++ return((kaddr_t)*u64p); ++} ++ ++/* ++ * walk_structs() -- walk linked lists of kernel data structures ++ */ ++int ++walk_structs(char *s, char *f, char *member, kaddr_t addr, int flags) ++{ ++ int size, offset, mem_offset=0; ++ kaddr_t last = 0, next; ++ kltype_t *klt = (kltype_t *)NULL, *memklt=(kltype_t *)NULL; ++ unsigned long long iter_threshold = 10000; ++ ++ int counter = 0; ++ kaddr_t head=0, head_next=0, head_prev=0, entry=0; ++ kaddr_t entry_next=0, entry_prev; ++ ++ /* field name of link pointer, determine its offset in the struct. */ ++ if ((offset = kl_member_offset(s, f)) == -1) { ++ kdb_printf("Could not determine offset for member %s of %s.\n", ++ f, s); ++ return 0; ++ } ++ ++ /* Get the type of the enclosing structure */ ++ if (!(klt = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) { ++ kdb_printf("Could not find the type of %s\n", s); ++ return(1); ++ } ++ ++ /* Get the struct size */ ++ if ((size = kl_struct_len(s)) == 0) { ++ kdb_printf ("could not get the length of %s\n", s); ++ return(1); ++ } ++ ++ /* test for a named member of the structure that should be displayed */ ++ if (member) { ++ memklt = kl_get_member(klt, member); ++ if (!memklt) { ++ kdb_printf ("%s has no member %s\n", s, member); ++ return 1; ++ } ++ mem_offset = kl_get_member_offset(klt, member); ++ } ++ ++ if ((next = addr)) { ++ /* get head of list (anchor) when struct list_head is used */ ++ if (flags & C_LISTHEAD) { ++ head = next; ++ if (invalid_address(head, sizeof(head))) { ++ kdb_printf ("invalid address %#lx\n", ++ head); ++ return 1; ++ } ++ /* get contents of addr struct member */ ++ head_next = kl_kaddr((void *)head, "list_head", "next"); ++ if (invalid_address(head, sizeof(head_next))) { ++ kdb_printf ("invalid address %#lx\n", ++ head_next); ++ return 1; ++ } ++ /* get prev field of anchor */ ++ head_prev = kl_kaddr((void *)head, "list_head", "prev"); ++ if (invalid_address(head, sizeof(head_prev))) { ++ kdb_printf ("invalid address %#lx\n", ++ head_prev); ++ return 1; ++ } ++ entry = 0; ++ } ++ } ++ ++ while(next && counter < iter_threshold) { ++ counter++; ++ if (counter > iter_threshold) { ++ kdb_printf("\nWARNING: Iteration threshold reached.\n"); ++ kdb_printf("Current threshold: %lld\n", iter_threshold); ++ break; ++ } ++ if(flags & C_LISTHEAD) { ++ if(!(entry)){ ++ if(flags & C_LISTHEAD_N){ ++ entry = head_next; ++ } else { ++ entry = head_prev; ++ } ++ last = head; ++ } ++ ++ if(head == entry) { ++ if(flags & C_LISTHEAD_N){ ++ check_prev_ptr(last, head_prev); ++ } else { ++ check_prev_ptr(last, head_next); ++ } ++ break; ++ } ++ ++ next = entry - offset; /* next structure */ ++ /* check that the whole structure can be addressed */ ++ if (invalid_address(next, size)) { ++ kdb_printf( ++ "invalid struct address %#lx\n", next); ++ return 1; ++ } ++ /* and validate that it points to valid addresses */ ++ entry_next = kl_kaddr((void *)entry,"list_head","next"); ++ if (invalid_address(entry_next, sizeof(entry_next))) { ++ kdb_printf("invalid address %#lx\n", ++ entry_next); ++ return 1; ++ } ++ entry_prev = kl_kaddr((void *)entry,"list_head","prev"); ++ if (invalid_address(entry_prev, sizeof(entry_prev))) { ++ kdb_printf("invalid address %#lx\n", ++ entry_prev); ++ return 1; ++ } ++ if(flags & C_LISTHEAD_N){ ++ check_prev_ptr(last, entry_prev); ++ } else { ++ check_prev_ptr(last, entry_next); ++ } ++ print_list_head(next); ++ last = entry; ++ if(flags & C_LISTHEAD_N){ ++ entry = entry_next; /* next list_head */ ++ } else { ++ entry = entry_prev; /* next list_head */ ++ } ++ } ++ ++ if (memklt) { ++ /* print named sub-structure in C-like struct format. */ ++ kl_print_member( ++ (void *)((unsigned long)next+mem_offset), ++ memklt, 0, C_HEX); ++ } else { ++ /* print entire structure in C-like struct format. */ ++ kl_print_type((void *)next, klt, 0, C_HEX); ++ } ++ ++ if(!(flags & C_LISTHEAD)) { ++ last = next; ++ next = (kaddr_t) (*(uint64_t*)(next + offset)); ++ } ++ } ++ ++ return(0); ++} ++ ++/* ++ * Implement the lcrash walk -s command ++ * see lcrash cmd_walk.c ++ */ ++int ++kdb_walk(int argc, const char **argv) ++{ ++ int i, nonoptc=0, optc=0, flags=0, init_len=0; ++ char *cmd, *arg, *structp=NULL, *forwp=NULL, *memberp=NULL; ++ char *addrp=NULL; ++ uint64_t value; ++ kaddr_t start_addr; ++ ++ all_count=0; ++ deall_count=0; ++ if (!have_debug_file) { ++ kdb_printf("no debuginfo file\n"); ++ return 0; ++ } ++ /* If there is nothing to evaluate, just return */ ++ if (argc == 0) { ++ return 0; ++ } ++ cmd = (char *)*argv; /* s/b "walk" */ ++ if (strcmp(cmd,"walk")) { ++ kdb_printf("got %s, not \"walk\"\n", cmd); ++ return 0; ++ } ++ ++ for (i=1; i<=argc; i++) { ++ arg = (char *)*(argv+i); ++ if (*arg == '-') { ++ optc++; ++ if (optc > 2) { ++ kdb_printf("too many options\n"); ++ kdb_printf("see 'walkhelp'\n"); ++ return 0; ++ } ++ if (*(arg+1) == 's') { ++ continue; /* ignore -s */ ++ } else if (*(arg+1) == 'h') { ++ if ((init_len=kl_struct_len("list_head")) ++ == 0) { ++ kdb_printf( ++ "could not find list_head\n"); ++ return 0; ++ } ++ if (*(arg+2) == 'p') { ++ flags = C_LISTHEAD; ++ flags |= C_LISTHEAD_P; ++ } else if (*(arg+2) == 'n') { ++ flags = C_LISTHEAD; ++ flags |= C_LISTHEAD_N; ++ } else { ++ kdb_printf("invalid -h option <%s>\n", ++ arg); ++ kdb_printf("see 'walkhelp'\n"); ++ return 0; ++ } ++ } else { ++ kdb_printf("invalid option <%s>\n", arg); ++ kdb_printf("see 'walkhelp'\n"); ++ return 0; ++ } ++ } else { ++ nonoptc++; ++ if (nonoptc > 4) { ++ kdb_printf("too many arguments\n"); ++ kdb_printf("see 'walkhelp'\n"); ++ return 0; ++ } ++ if (nonoptc == 1) { ++ structp = arg; ++ } else if (nonoptc == 2) { ++ forwp = arg; ++ } else if (nonoptc == 3) { ++ addrp = arg; ++ } else if (nonoptc == 4) { ++ /* the member is optional; if we get ++ a fourth, the previous was the member */ ++ memberp = addrp; ++ addrp = arg; ++ } else { ++ kdb_printf("invalid argument <%s>\n", arg); ++ kdb_printf("see 'walkhelp'\n"); ++ return 0; ++ } ++ } ++ } ++ if (nonoptc < 3) { ++ kdb_printf("too few arguments\n"); ++ kdb_printf("see 'walkhelp'\n"); ++ return 0; ++ } ++ if (!(flags & C_LISTHEAD)) { ++ if ((init_len=kl_struct_len(structp)) == 0) { ++ kdb_printf("could not find %s\n", structp); ++ return 0; ++ } ++ } ++ ++ /* Get the start address of the structure */ ++ if (get_value(addrp, &value)) { ++ kdb_printf ("address %s invalid\n", addrp); ++ return 0; ++ } ++ start_addr = (kaddr_t)value; ++ if (invalid_address(start_addr, init_len)) { ++ kdb_printf ("address %#lx invalid\n", start_addr); ++ return 0; ++ } ++ ++ if (memberp) { ++ } ++ ++ if (walk_structs(structp, forwp, memberp, start_addr, flags)) { ++ kdb_printf ("walk_structs failed\n"); ++ return 0; ++ } ++ /* kdb_printf("ptc allocated:%d deallocated:%d\n", ++ all_count, deall_count); */ ++ return 0; ++} ++ ++/* ++ * Implement the lcrash px (print, pd) command ++ * see lcrash cmd_print.c ++ * ++ * px ++ * e.g. px *(task_struct *)
++ */ ++int ++kdb_debuginfo_print(int argc, const char **argv) ++{ ++ /* argc does not count the command itself, which is argv[0] */ ++ char *cmd, *next, *end, *exp, *cp; ++ unsigned char *buf; ++ int i, j, iflags; ++ node_t *np; ++ uint64_t flags = 0; ++ ++ /* If there is nothing to evaluate, just return */ ++ if (argc == 0) { ++ return 0; ++ } ++ all_count=0; ++ deall_count=0; ++ ++ cmd = (char *)*argv; ++ ++ /* Set up the flags value. If this command was invoked via ++ * "pd" or "px", then make sure the appropriate flag is set. ++ */ ++ flags = 0; ++ if (!strcmp(cmd, "pd") || !strcmp(cmd, "print")) { ++ flags = 0; ++ } else if (!strcmp(cmd, "px")) { ++ flags |= C_HEX; ++ } else if (!strcmp(cmd, "whatis")) { ++ if (argc != 1) { ++ kdb_printf("usage: whatis \n"); ++ return 0; ++ } ++ cp = (char *)*(argv+1); ++ single_type(cp); ++ /* kdb_printf("allocated:%d deallocated:%d\n", ++ all_count, deall_count); */ ++ return 0; ++ } else if (!strcmp(cmd, "sizeof")) { ++ if (!have_debug_file) { ++ kdb_printf("no debuginfo file\n"); ++ return 0; ++ } ++ if (argc != 1) { ++ kdb_printf("usage: sizeof type\n"); ++ return 0; ++ } ++ cp = (char *)*(argv+1); ++ sizeof_type(cp); ++ return 0; ++ } else { ++ kdb_printf("command error: %s\n", cmd); ++ return 0; ++ } ++ ++ /* ++ * Count the number of bytes necessary to hold the entire expression ++ * string. ++ */ ++ for (i=1, j=0; i <= argc; i++) { ++ j += (strlen(*(argv+i)) + 1); ++ } ++ ++ /* ++ * Allocate space for the expression string and copy the individual ++ * arguments into it. ++ */ ++ buf = kl_alloc_block(j); ++ if (!buf) { ++ return 0; ++ } ++ ++ for (i=1; i <= argc; i++) { ++ strcat(buf, *(argv+i)); ++ /* put spaces between arguments */ ++ if (i < argc) { ++ strcat(buf, " "); ++ } ++ } ++ ++ /* Walk through the expression string, expression by expression. ++ * Note that a comma (',') is the delimiting character between ++ * expressions. ++ */ ++ next = buf; ++ while (next) { ++ if ((end = strchr(next, ','))) { ++ *end = (char)0; ++ } ++ ++ /* Copy the next expression to a separate expression string. ++ * A separate expresison string is necessary because it is ++ * likely to get freed up in eval() when variables get expanded. ++ */ ++ i = strlen(next)+1; ++ exp = (char *)kl_alloc_block(i); ++ if (!exp) { ++ return 0; ++ } ++ strcpy(exp, next); ++ ++ /* Evaluate the expression */ ++ np = eval(&exp, 0); ++ if (!np || eval_error) { ++ print_eval_error(cmd, exp, ++ (error_token ? error_token : (char*)NULL), ++ eval_error, CMD_NAME_FLG); ++ if (np) { ++ free_nodes(np); ++ } ++ kl_free_block(buf); ++ kl_free_block(exp); ++ free_eval_memory(); ++ return 0; ++ } ++ iflags = flags; ++ if (print_eval_results(np, iflags)) { ++ free_nodes(np); ++ kl_free_block(buf); ++ free_eval_memory(); ++ return 0; ++ } ++ kl_free_block(exp); ++ ++ if (end) { ++ next = end + 1; ++ kdb_printf(" "); ++ } else { ++ next = (char*)NULL; ++ kdb_printf("\n"); ++ } ++ free_nodes(np); ++ } ++ free_eval_memory(); ++ kl_free_block(buf); ++ /* kdb_printf("allocated:%d deallocated:%d\n", ++ all_count, deall_count); */ ++ return 0; ++} ++ ++/* ++ * Display help for the px command ++ */ ++int ++kdb_pxhelp(int argc, const char **argv) ++{ ++ if (have_debug_file) { ++ kdb_printf ("Some examples of using the px command:\n"); ++ kdb_printf (" the whole structure:\n"); ++ kdb_printf (" px *(task_struct *)0xe0000...\n"); ++ kdb_printf (" one member:\n"); ++ kdb_printf (" px (*(task_struct *)0xe0000...)->comm\n"); ++ kdb_printf (" the address of a member\n"); ++ kdb_printf (" px &((task_struct *)0xe0000...)->children\n"); ++ kdb_printf (" a structure pointed to by a member:\n"); ++ kdb_printf (" px ((*(class_device *)0xe0000...)->class)->name\n"); ++ kdb_printf (" array element:\n"); ++ kdb_printf (" px (cache_sizes *)0xa0000...[0]\n"); ++ kdb_printf (" px (task_struct *)(0xe0000...)->cpus_allowed.bits[0]\n"); ++ } else { ++ kdb_printf ("There is no debug info file.\n"); ++ kdb_printf ("The px/pd/print commands can only evaluate "); ++ kdb_printf ("arithmetic expressions.\n"); ++ } ++ return 0; ++} ++ ++/* ++ * Display help for the walk command ++ */ ++int ++kdb_walkhelp(int argc, const char **argv) ++{ ++ if (!have_debug_file) { ++ kdb_printf("no debuginfo file\n"); ++ return 0; ++ } ++ kdb_printf ("Using the walk command:\n"); ++ kdb_printf (" (only the -s (symbolic) form is supported, so -s is ignored)\n"); ++ kdb_printf ("\n"); ++ kdb_printf (" If the list is not linked with list_head structures:\n"); ++ kdb_printf (" walk [-s] struct name-of-forward-pointer address\n"); ++ kdb_printf (" example: walk xyz_struct next 0xe00....\n"); ++ kdb_printf ("\n"); ++ kdb_printf (" If the list is linked with list_head structures, use -hn\n"); ++ kdb_printf (" to walk the 'next' list, -hp for the 'prev' list\n"); ++ kdb_printf (" walk -h[n|p] struct name-of-forward-pointer [member-to-show] address-of-list-head\n"); ++ kdb_printf (" example, to show the entire task_struct:\n"); ++ kdb_printf (" walk -hn task_struct tasks 0xe000....\n"); ++ kdb_printf (" example, to show the task_struct member comm:\n"); ++ kdb_printf (" walk -hn task_struct tasks comm 0xe000....\n"); ++ kdb_printf (" (address is not the address of first member's list_head, "); ++ kdb_printf ("but of the anchoring list_head\n"); ++ return 0; ++} ++ ++/* ++ * dup_block() ++ */ ++void * ++dup_block(void *b, int len) ++{ ++ void *b2; ++ ++ if ((b2 = kl_alloc_block(len))) { ++ memcpy(b2, b, len); /* dst, src, sz */ ++ } ++ return(b2); ++} ++ ++/* ++ * kl_reset_error() ++ */ ++void ++kl_reset_error(void) ++{ ++ klib_error = 0; ++} ++ ++/* ++ * given a symbol name, look up its address ++ * ++ * in lcrash, this would return a pointer to the syment_t in ++ * a binary tree of them ++ * ++ * In this one, look up the symbol in the standard kdb way, ++ * which fills in the kdb_symtab_t. ++ * Then fill in the global syment_t "lkup_syment" -- assuming ++ * we'll only need one at a time! ++ * ++ * kl_lkup_symname returns the address of syment_t if the symbol is ++ * found, else null. ++ * ++ * Note: we allocate a syment_t the caller should kfree it ++ */ ++syment_t * ++kl_lkup_symname (char *cp) ++{ ++ syment_t *sp; ++ kdb_symtab_t kdb_symtab; ++ ++ if (kdbgetsymval(cp, &kdb_symtab)) { ++ sp = (syment_t *)kl_alloc_block(sizeof(syment_t)); ++ sp->s_addr = (kaddr_t)kdb_symtab.sym_start; ++ KL_ERROR = 0; ++ return (sp); ++ } else { ++ /* returns 0 if the symbol is not found */ ++ KL_ERROR = KLE_INVALID_VALUE; ++ return ((syment_t *)0); ++ } ++} ++ ++/* ++ * kl_get_ra() ++ * ++ * This function returns its own return address. ++ * Usefule when trying to capture where we came from. ++ */ ++void* ++kl_get_ra(void) ++{ ++ return (__builtin_return_address(0)); ++} ++ ++/* start kl_util.c */ ++/* ++ * Definitions for the do_math() routine. ++ */ ++#define M_ADD '+' ++#define M_SUBTRACT '-' ++#define M_MULTIPLY '*' ++#define M_DIVIDE '/' ++ ++/* ++ * do_math() -- Calculate some math values based on a string argument ++ * passed into the function. For example, if you use: ++ * ++ * 0xffffc000*2+6/5-3*19-8 ++ * ++ * And you will get the value 0xffff7fc0 back. I could ++ * probably optimize this a bit more, but right now, it ++ * works, which is good enough for me. ++ */ ++static uint64_t ++do_math(char *str) ++{ ++ int i = 0; ++ char *buf, *loc; ++ uint64_t value1, value2; ++ syment_t *sp; ++ ++ buf = (char *)kl_alloc_block((strlen(str) + 1)); ++ sprintf(buf, "%s", str); ++ for (i = strlen(str); i >= 0; i--) { ++ if ((str[i] == M_ADD) || (str[i] == M_SUBTRACT)) { ++ buf[i] = '\0'; ++ value1 = do_math(buf); ++ value2 = do_math(&str[i+1]); ++ kl_free_block((void *)buf); ++ if (str[i] == M_SUBTRACT) { ++ return value1 - value2; ++ } else { ++ return value1 + value2; ++ } ++ } ++ } ++ ++ for (i = strlen(str); i >= 0; i--) { ++ if ((str[i] == M_MULTIPLY) || (str[i] == M_DIVIDE)) { ++ buf[i] = '\0'; ++ value1 = do_math(buf); ++ value2 = do_math(&str[i+1]); ++ kl_free_block((void *)buf); ++ if (str[i] == M_MULTIPLY) { ++ return (value1 * value2); ++ } else { ++ if (value2 == 0) { ++ /* handle divide by zero */ ++ /* XXX -- set proper error code */ ++ klib_error = 1; ++ return (0); ++ } else { ++ return (value1 / value2); ++ } ++ } ++ } ++ } ++ ++ /* ++ * Otherwise, just process the value, and return it. ++ */ ++ sp = kl_lkup_symname(buf); ++ if (KL_ERROR) { ++ KL_ERROR = 0; ++ value2 = kl_strtoull(buf, &loc, 10); ++ if (((!value2) && (buf[0] != '0')) || (*loc) || ++ (!strncmp(buf, "0x", 2)) || (!strncmp(buf, "0X", 2))) { ++ value1 = (kaddr_t)kl_strtoull(buf, (char**)NULL, 16); ++ } else { ++ value1 = (unsigned)kl_strtoull(buf, (char**)NULL, 10); ++ } ++ } else { ++ value1 = (kaddr_t)sp->s_addr; ++ kl_free_block((void *)sp); ++ } ++ kl_free_block((void *)buf); ++ return (value1); ++} ++/* ++ * kl_get_value() -- Translate numeric input strings ++ * ++ * A generic routine for translating an input string (param) in a ++ * number of dfferent ways. If the input string is an equation ++ * (contains the characters '+', '-', '/', and '*'), then perform ++ * the math evaluation and return one of the following modes (if ++ * mode is passed): ++ * ++ * 0 -- if the resulting value is <= elements, if elements (number ++ * of elements in a table) is passed. ++ * ++ * 1 -- if the first character in param is a pound sign ('#'). ++ * ++ * 3 -- the numeric result of an equation. ++ * ++ * If the input string is NOT an equation, mode (if passed) will be ++ * set in one of the following ways (depending on the contents of ++ * param and elements). ++ * ++ * o When the first character of param is a pound sign ('#'), mode ++ * is set equal to one and the trailing numeric value (assumed to ++ * be decimal) is returned. ++ * ++ * o When the first two characters in param are "0x" or "0X," or ++ * when when param contains one of the characers "abcdef," or when ++ * the length of the input value is eight characters. mode is set ++ * equal to two and the numeric value contained in param is ++ * translated as hexadecimal and returned. ++ * ++ * o The value contained in param is translated as decimal and mode ++ * is set equal to zero. The resulting value is then tested to see ++ * if it exceeds elements (if passed). If it does, then value is ++ * translated as hexadecimal and mode is set equal to two. ++ * ++ * Note that mode is only set when a pointer is passed in the mode ++ * paramater. Also note that when elements is set equal to zero, any ++ * non-hex (as determined above) value not starting with a pound sign ++ * will be translated as hexadecimal (mode will be set equal to two) -- ++ * IF the length of the string of characters is less than 16 (kaddr_t). ++ * ++ */ ++int ++kl_get_value(char *param, int *mode, int elements, uint64_t *value) ++{ ++ char *loc; ++ uint64_t v; ++ ++ kl_reset_error(); ++ ++ /* Check to see if we are going to need to do any math ++ */ ++ if (strpbrk(param, "+-/*")) { ++ if (!strncmp(param, "#", 1)) { ++ v = do_math(¶m[1]); ++ if (mode) { ++ *mode = 1; ++ } ++ } else { ++ v = do_math(param); ++ if (mode) { ++ if (elements && (*value <= elements)) { ++ *mode = 0; ++ } else { ++ *mode = 3; ++ } ++ } ++ } ++ } else { ++ if (!strncmp(param, "#", 1)) { ++ if (!strncmp(param, "0x", 2) ++ || !strncmp(param, "0X", 2) ++ || strpbrk(param, "abcdef")) { ++ v = kl_strtoull(¶m[1], &loc, 16); ++ } else { ++ v = kl_strtoull(¶m[1], &loc, 10); ++ } ++ if (loc) { ++ KL_ERROR = KLE_INVALID_VALUE; ++ return (1); ++ } ++ if (mode) { ++ *mode = 1; ++ } ++ } else if (!strncmp(param, "0x", 2) || !strncmp(param, "0X", 2) ++ || strpbrk(param, "abcdef")) { ++ v = kl_strtoull(param, &loc, 16); ++ if (loc) { ++ KL_ERROR = KLE_INVALID_VALUE; ++ return (1); ++ } ++ if (mode) { ++ *mode = 2; /* HEX VALUE */ ++ } ++ } else if (elements || (strlen(param) < 16) || ++ (strlen(param) > 16)) { ++ v = kl_strtoull(param, &loc, 10); ++ if (loc) { ++ KL_ERROR = KLE_INVALID_VALUE; ++ return (1); ++ } ++ if (elements && (v >= elements)) { ++ v = (kaddr_t)kl_strtoull(param, ++ (char**)NULL, 16); ++ if (mode) { ++ *mode = 2; /* HEX VALUE */ ++ } ++ } else if (mode) { ++ *mode = 0; ++ } ++ } else { ++ v = kl_strtoull(param, &loc, 16); ++ if (loc) { ++ KL_ERROR = KLE_INVALID_VALUE; ++ return (1); ++ } ++ if (mode) { ++ *mode = 2; /* ASSUME HEX VALUE */ ++ } ++ } ++ } ++ *value = v; ++ return (0); ++} ++/* end kl_util.c */ ++ ++/* start kl_libutil.c */ ++static int ++valid_digit(char c, int base) ++{ ++ switch(base) { ++ case 2: ++ if ((c >= '0') && (c <= '1')) { ++ return(1); ++ } else { ++ return(0); ++ } ++ case 8: ++ if ((c >= '0') && (c <= '7')) { ++ return(1); ++ } else { ++ return(0); ++ } ++ case 10: ++ if ((c >= '0') && (c <= '9')) { ++ return(1); ++ } else { ++ return(0); ++ } ++ case 16: ++ if (((c >= '0') && (c <= '9')) ++ || ((c >= 'a') && (c <= 'f')) ++ || ((c >= 'A') && (c <= 'F'))) { ++ return(1); ++ } else { ++ return(0); ++ } ++ } ++ return(0); ++} ++ ++static int ++digit_value(char c, int base, int *val) ++{ ++ if (!valid_digit(c, base)) { ++ return(1); ++ } ++ switch (base) { ++ case 2: ++ case 8: ++ case 10: ++ *val = (int)((int)(c - 48)); ++ break; ++ case 16: ++ if ((c >= 'a') && (c <= 'f')) { ++ *val = ((int)(c - 87)); ++ } else if ((c >= 'A') && (c <= 'F')) { ++ *val = ((int)(c - 55)); ++ } else { ++ *val = ((int)(c - 48)); ++ } ++ } ++ return(0); ++} ++ ++uint64_t ++kl_strtoull(char *str, char **loc, int base) ++{ ++ int dval; ++ uint64_t i = 1, v, value = 0; ++ char *c, *cp = str; ++ ++ *loc = (char *)NULL; ++ if (base == 0) { ++ if (!strncmp(cp, "0x", 2) || !strncmp(cp, "0X", 2)) { ++ base = 16; ++ } else if (cp[0] == '0') { ++ if (cp[1] == 'b') { ++ base = 2; ++ } else { ++ base = 8; ++ } ++ } else if (strpbrk(cp, "abcdefABCDEF")) { ++ base = 16; ++ } else { ++ base = 10; ++ } ++ } ++ if ((base == 8) && (*cp == '0')) { ++ cp += 1; ++ } else if ((base == 2) && !strncmp(cp, "0b", 2)) { ++ cp += 2; ++ } else if ((base == 16) && ++ (!strncmp(cp, "0x", 2) || !strncmp(cp, "0X", 2))) { ++ cp += 2; ++ } ++ c = &cp[strlen(cp) - 1]; ++ while (c >= cp) { ++ ++ if (digit_value(*c, base, &dval)) { ++ if (loc) { ++ *loc = c; ++ } ++ return(value); ++ } ++ v = dval * i; ++ if ((MAX_LONG_LONG - value) < v) { ++ return(MAX_LONG_LONG); ++ } ++ value += v; ++ i *= (uint64_t)base; ++ c--; ++ } ++ return(value); ++} ++/* end kl_libutil.c */ ++ ++/* ++ * dbg_hash_sym() ++ */ ++void ++dbg_hash_sym(uint64_t typenum, dbg_sym_t *stp) ++{ ++ dbg_hashrec_t *shp, *hshp; ++ ++ if ((typenum == 0) || (!stp)) { ++ return; ++ } ++ shp = (dbg_hashrec_t *)kl_alloc_block(sizeof(dbg_hashrec_t)); ++ shp->h_typenum = typenum; ++ shp->h_ptr = stp; ++ shp->h_next = (dbg_hashrec_t *)NULL; ++ if ((hshp = dbg_hash[TYPE_NUM_HASH(typenum)])) { ++ while (hshp->h_next) { ++ hshp = hshp->h_next; ++ } ++ hshp->h_next = shp; ++ } else { ++ dbg_hash[TYPE_NUM_HASH(typenum)] = shp; ++ } ++} ++ ++/* ++ * dbg_find_sym() ++ */ ++dbg_sym_t * ++dbg_find_sym(char *name, int type, uint64_t typenum) ++{ ++ dbg_sym_t *stp = (dbg_sym_t *)NULL; ++ ++ if (name && strlen(name)) { ++ /* Cycle through the type flags and see if any records are ++ * present. Note that if multiple type flags or DBG_ALL is ++ * passed in, only the first occurance of 'name' will be ++ * found and returned. If name exists in multiple trees, ++ * then multiple searches are necessary to find them. ++ */ ++ if (type & DBG_TYPE) { ++ if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *) ++ type_tree, name, (int *)NULL))) { ++ goto found_sym; ++ } ++ } ++ if (type & DBG_TYPEDEF) { ++ if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *) ++ typedef_tree, name, (int *)NULL))) { ++ goto found_sym; ++ } ++ } ++ if (!stp) { ++ return((dbg_sym_t*)NULL); ++ } ++ } ++found_sym: ++ if (typenum) { ++ dbg_hashrec_t *hshp; ++ ++ if (stp) { ++ if (stp->sym_typenum == typenum) { ++ return(stp); ++ } ++ } else if ((hshp = dbg_hash[TYPE_NUM_HASH(typenum)])) { ++ while (hshp) { ++ if (hshp->h_typenum == typenum) { ++ return(hshp->h_ptr); ++ } ++ hshp = hshp->h_next; ++ } ++ } ++ } ++ return(stp); ++} ++ ++/* ++ * kl_find_type() -- find a KLT type by name. ++ */ ++kltype_t * ++kl_find_type(char *name, int tnum) ++{ ++ dbg_sym_t *stp; ++ kltype_t *kltp = (kltype_t *)NULL; ++ ++ if (!have_debug_file) { ++ kdb_printf("no debuginfo file\n"); ++ return kltp; ++ } ++ ++ if (!tnum || IS_TYPE(tnum)) { ++ if ((stp = dbg_find_sym(name, DBG_TYPE, 0))) { ++ kltp = (kltype_t *)stp->sym_kltype; ++ if (tnum && !(kltp->kl_type & tnum)) { ++ /* We have found a type by this name ++ * but it does not have the right ++ * type number (e.g., we're looking ++ * for a struct and we don't find ++ * a KLT_STRUCT type by this name). ++ */ ++ return((kltype_t *)NULL); ++ } ++ } ++ } ++ if (!tnum || IS_TYPEDEF(tnum)) { ++ if ((stp = dbg_find_sym(name, DBG_TYPEDEF, 0))) { ++ kltp = (kltype_t *)stp->sym_kltype; ++ } ++ } ++ return(kltp); ++} ++ ++/* ++ * kl_first_btnode() -- non-recursive implementation. ++ */ ++btnode_t * ++kl_first_btnode(btnode_t *np) ++{ ++ if (!np) { ++ return((btnode_t *)NULL); ++ } ++ ++ /* Walk down the left side 'til the end... ++ */ ++ while (np->bt_left) { ++ np = np->bt_left; ++ } ++ return(np); ++} ++ ++/* ++ * kl_next_btnode() -- non-recursive implementation. ++ */ ++btnode_t * ++kl_next_btnode(btnode_t *node) ++{ ++ btnode_t *np = node, *parent; ++ ++ if (np) { ++ if (np->bt_right) { ++ return(kl_first_btnode(np->bt_right)); ++ } else { ++ parent = np->bt_parent; ++next: ++ if (parent) { ++ if (parent->bt_left == np) { ++ return(parent); ++ } ++ np = parent; ++ parent = parent->bt_parent; ++ goto next; ++ } ++ } ++ } ++ return((btnode_t *)NULL); ++} ++ ++/* ++ * dbg_next_sym() ++ */ ++dbg_sym_t * ++dbg_next_sym(dbg_sym_t *stp) ++{ ++ dbg_sym_t *next_stp; ++ ++ next_stp = (dbg_sym_t *)kl_next_btnode((btnode_t *)stp); ++ return(next_stp); ++} ++ ++/* ++ * kl_prev_btnode() -- non-recursive implementation. ++ */ ++btnode_t * ++kl_prev_btnode(btnode_t *node) ++{ ++ btnode_t *np = node, *parent; ++ ++ if (np) { ++ if (np->bt_left) { ++ np = np->bt_left; ++ while (np->bt_right) { ++ np = np->bt_right; ++ } ++ return(np); ++ } ++ parent = np->bt_parent; ++next: ++ if (parent) { ++ if (parent->bt_right == np) { ++ return(parent); ++ } ++ np = parent; ++ parent = parent->bt_parent; ++ goto next; ++ } ++ } ++ return((btnode_t *)NULL); ++} ++ ++/* ++ * dbg_prev_sym() ++ */ ++dbg_sym_t * ++dbg_prev_sym(dbg_sym_t *stp) ++{ ++ dbg_sym_t *prev_stp; ++ ++ prev_stp = (dbg_sym_t *)kl_prev_btnode((btnode_t *)stp); ++ return(prev_stp); ++} ++ ++/* ++ * kl_find_next_type() -- find next KLT type ++ */ ++kltype_t * ++kl_find_next_type(kltype_t *kltp, int type) ++{ ++ kltype_t *nkltp = NULL; ++ dbg_sym_t *nstp; ++ ++ if (kltp && kltp->kl_ptr) { ++ nstp = (dbg_sym_t *)kltp->kl_ptr; ++ nkltp = (kltype_t *)nstp->sym_kltype; ++ if (type) { ++ while(nkltp && !(nkltp->kl_type & type)) { ++ if ((nstp = dbg_next_sym(nstp))) { ++ nkltp = (kltype_t *)nstp->sym_kltype; ++ } else { ++ nkltp = (kltype_t *)NULL; ++ } ++ } ++ } ++ } ++ return(nkltp); ++} ++ ++/* ++ * dbg_first_sym() ++ */ ++dbg_sym_t * ++dbg_first_sym(int type) ++{ ++ dbg_sym_t *stp = (dbg_sym_t *)NULL; ++ ++ switch(type) { ++ case DBG_TYPE: ++ stp = (dbg_sym_t *) ++ kl_first_btnode((btnode_t *)type_tree); ++ break; ++ case DBG_TYPEDEF: ++ stp = (dbg_sym_t *) ++ kl_first_btnode((btnode_t *)typedef_tree); ++ break; ++ } ++ return(stp); ++} ++ ++/* ++ * kl_first_type() ++ */ ++kltype_t * ++kl_first_type(int tnum) ++{ ++ kltype_t *kltp = NULL; ++ dbg_sym_t *stp; ++ ++ if (IS_TYPE(tnum)) { ++ /* If (tnum == KLT_TYPE), then return the first type ++ * record, regardless of the type. Otherwise, search ++ * for the frst type that mapps into tnum. ++ */ ++ if ((stp = dbg_first_sym(DBG_TYPE))) { ++ kltp = (kltype_t *)stp->sym_kltype; ++ if (tnum != KLT_TYPE) { ++ while (kltp && !(kltp->kl_type & tnum)) { ++ if ((stp = dbg_next_sym(stp))) { ++ kltp = (kltype_t *)stp->sym_kltype; ++ } else { ++ kltp = (kltype_t *)NULL; ++ } ++ } ++ } ++ } ++ } else if (IS_TYPEDEF(tnum)) { ++ if ((stp = dbg_first_sym(DBG_TYPEDEF))) { ++ kltp = (kltype_t *)stp->sym_kltype; ++ } ++ } ++ return(kltp); ++} ++ ++/* ++ * kl_next_type() ++ */ ++kltype_t * ++kl_next_type(kltype_t *kltp) ++{ ++ dbg_sym_t *stp, *nstp; ++ kltype_t *nkltp = (kltype_t *)NULL; ++ ++ if (!kltp) { ++ return((kltype_t *)NULL); ++ } ++ stp = (dbg_sym_t *)kltp->kl_ptr; ++ if ((nstp = dbg_next_sym(stp))) { ++ nkltp = (kltype_t *)nstp->sym_kltype; ++ } ++ return(nkltp); ++} ++ ++/* ++ * kl_prev_type() ++ */ ++kltype_t * ++kl_prev_type(kltype_t *kltp) ++{ ++ dbg_sym_t *stp, *pstp; ++ kltype_t *pkltp = (kltype_t *)NULL; ++ ++ if (!kltp) { ++ return((kltype_t *)NULL); ++ } ++ stp = (dbg_sym_t *)kltp->kl_ptr; ++ if ((pstp = dbg_prev_sym(stp))) { ++ pkltp = (kltype_t *)pstp->sym_kltype; ++ } ++ return(pkltp); ++} ++ ++/* ++ * kl_realtype() ++ */ ++kltype_t * ++kl_realtype(kltype_t *kltp, int tnum) ++{ ++ kltype_t *rkltp = kltp; ++ ++ while (rkltp) { ++ if (tnum && (rkltp->kl_type == tnum)) { ++ break; ++ } ++ if (!rkltp->kl_realtype) { ++ break; ++ } ++ if (rkltp->kl_realtype == rkltp) { ++ break; ++ } ++ rkltp = rkltp->kl_realtype; ++ if (rkltp == kltp) { ++ break; ++ } ++ } ++ return(rkltp); ++} ++ ++/* ++ * dbg_find_typenum() ++ */ ++dbg_type_t * ++dbg_find_typenum(uint64_t typenum) ++{ ++ dbg_sym_t *stp; ++ dbg_type_t *sp = (dbg_type_t *)NULL; ++ ++ if ((stp = dbg_find_sym(0, DBG_TYPE, typenum))) { ++ sp = (dbg_type_t *)stp->sym_kltype; ++ } ++ return(sp); ++} ++ ++/* ++ * find type by typenum ++ */ ++kltype_t * ++kl_find_typenum(uint64_t typenum) ++{ ++ kltype_t *kltp; ++ ++ kltp = (kltype_t *)dbg_find_typenum(typenum); ++ return(kltp); ++} ++ ++/* ++ * kl_find_btnode() -- non-recursive implementation. ++ */ ++btnode_t * ++_kl_find_btnode(btnode_t *np, char *key, int *max_depth, size_t len) ++{ ++ int ret; ++ btnode_t *next, *prev; ++ ++ if (np) { ++ if (max_depth) { ++ (*max_depth)++; ++ } ++ next = np; ++again: ++ if (len) { ++ ret = strncmp(key, next->bt_key, len); ++ } else { ++ ret = strcmp(key, next->bt_key); ++ } ++ if (ret == 0) { ++ if ((prev = kl_prev_btnode(next))) { ++ if (len) { ++ ret = strncmp(key, prev->bt_key, len); ++ } else { ++ ret = strcmp(key, prev->bt_key); ++ } ++ if (ret == 0) { ++ next = prev; ++ goto again; ++ } ++ } ++ return(next); ++ } else if (ret < 0) { ++ if ((next = next->bt_left)) { ++ goto again; ++ } ++ } else { ++ if ((next = next->bt_right)) { ++ goto again; ++ } ++ } ++ } ++ return((btnode_t *)NULL); ++} ++ ++/* ++ * kl_type_size() ++ */ ++int ++kl_type_size(kltype_t *kltp) ++{ ++ kltype_t *rkltp; ++ ++ if (!kltp) { ++ return(0); ++ } ++ if (!(rkltp = kl_realtype(kltp, 0))) { ++ return(0); ++ } ++ return(rkltp->kl_size); ++} ++ ++/* ++ * kl_struct_len() ++ */ ++int ++kl_struct_len(char *s) ++{ ++ kltype_t *kltp; ++ ++ if ((kltp = kl_find_type(s, (KLT_TYPES)))) { ++ return kl_type_size(kltp); ++ } ++ return(0); ++} ++ ++/* ++ * kl_get_member() ++ */ ++kltype_t * ++kl_get_member(kltype_t *kltp, char *f) ++{ ++ kltype_t *mp; ++ ++ if ((mp = kltp->kl_member)) { ++ while (mp) { ++ if (mp->kl_flags & TYP_ANONYMOUS_FLG) { ++ kltype_t *amp; ++ ++ if ((amp = kl_get_member(mp->kl_realtype, f))) { ++ return(amp); ++ } ++ } else if (!strcmp(mp->kl_name, f)) { ++ break; ++ } ++ mp = mp->kl_member; ++ } ++ } ++ return(mp); ++} ++ ++/* ++ * kl_member() ++ */ ++kltype_t * ++kl_member(char *s, char *f) ++{ ++ kltype_t *kltp, *mp = NULL; ++ ++ if (!(kltp = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) { ++ if ((kltp = kl_find_type(s, KLT_TYPEDEF))) { ++ kltp = kl_realtype(kltp, 0); ++ } ++ } ++ if (kltp) { ++ mp = kl_get_member(kltp, f); ++ } ++ return(mp); ++} ++ ++ ++/* ++ * kl_get_member_offset() ++ */ ++int ++kl_get_member_offset(kltype_t *kltp, char *f) ++{ ++ kltype_t *mp; ++ ++ if ((mp = kltp->kl_member)) { ++ while (mp) { ++ if (mp->kl_flags & TYP_ANONYMOUS_FLG) { ++ int off; ++ ++ /* Drill down to see if the member we are looking for is in ++ * an anonymous union or struct. Since this call is recursive, ++ * the drill down may actually be multi-layer. ++ */ ++ off = kl_get_member_offset(mp->kl_realtype, f); ++ if (off >= 0) { ++ return(mp->kl_offset + off); ++ } ++ } else if (!strcmp(mp->kl_name, f)) { ++ return(mp->kl_offset); ++ } ++ mp = mp->kl_member; ++ } ++ } ++ return(-1); ++} ++ ++/* ++ * kl_member_offset() ++ */ ++int ++kl_member_offset(char *s, char *f) ++{ ++ int off = -1; ++ kltype_t *kltp; ++ ++ if (!(kltp = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) { ++ if ((kltp = kl_find_type(s, KLT_TYPEDEF))) { ++ kltp = kl_realtype(kltp, 0); ++ } ++ } ++ if (kltp) { ++ off = kl_get_member_offset(kltp, f); ++ } ++ return(off); ++} ++ ++/* ++ * kl_is_member() ++ */ ++int ++kl_is_member(char *s, char *f) ++{ ++ kltype_t *mp; ++ ++ if ((mp = kl_member(s, f))) { ++ return(1); ++ } ++ return(0); ++} ++ ++/* ++ * kl_member_size() ++ */ ++int ++kl_member_size(char *s, char *f) ++{ ++ kltype_t *mp; ++ ++ if ((mp = kl_member(s, f))) { ++ return(mp->kl_size); ++ } ++ return(0); ++} ++ ++#define TAB_SPACES 8 ++#define LEVEL_INDENT(level, flags) {\ ++ int i, j; \ ++ if (!(flags & NO_INDENT)) { \ ++ for (i = 0; i < level; i++) { \ ++ for (j = 0; j < TAB_SPACES; j++) { \ ++ kdb_printf(" "); \ ++ } \ ++ }\ ++ } \ ++} ++#define PRINT_NL(flags) \ ++ if (!(flags & SUPPRESS_NL)) { \ ++ kdb_printf("\n"); \ ++ } ++#define PRINT_SEMI_COLON(level, flags) \ ++ if (level && (!(flags & SUPPRESS_SEMI_COLON))) { \ ++ kdb_printf(";"); \ ++ } ++ ++/* ++ * print_realtype() ++ */ ++static void ++print_realtype(kltype_t *kltp) ++{ ++ kltype_t *rkltp; ++ ++ if ((rkltp = kltp->kl_realtype)) { ++ while (rkltp && rkltp->kl_realtype) { ++ rkltp = rkltp->kl_realtype; ++ } ++ if (rkltp->kl_type == KLT_BASE) { ++ kdb_printf(" (%s)", rkltp->kl_name); ++ } ++ } ++} ++ ++int align_chk = 0; ++/* ++ * kl_print_uint16() ++ * ++ */ ++void ++kl_print_uint16(void *ptr, int flags) ++{ ++ unsigned long long a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * * dump core) ++ * */ ++ if (align_chk && (uaddr_t)ptr % 16) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(unsigned long long *) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("%#llx", a); ++ } else if (flags & C_BINARY) { ++ kdb_printf("0b"); ++ kl_binary_print(a); ++ } else { ++ kdb_printf("%llu", a); ++ } ++} ++ ++#if 0 ++/* ++ * kl_print_float16() ++ * ++ */ ++void ++kl_print_float16(void *ptr, int flags) ++{ ++ double a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * * dump core) ++ * */ ++ if (align_chk && (uaddr_t)ptr % 16) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(double*) ptr; ++ kdb_printf("%f", a); ++} ++#endif ++ ++/* ++ * kl_print_int16() ++ * ++ */ ++void ++kl_print_int16(void *ptr, int flags) ++{ ++ long long a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * * dump core) ++ * */ ++ if (align_chk && (uaddr_t)ptr % 16) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(long long *) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("%#llx", a); ++ } else if (flags & C_BINARY) { ++ kdb_printf("0b"); ++ kl_binary_print(a); ++ } else { ++ kdb_printf("%lld", a); ++ } ++} ++ ++/* ++ * kl_print_int8() ++ */ ++void ++kl_print_int8(void *ptr, int flags) ++{ ++ long long a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core) ++ */ ++ if (align_chk && (uaddr_t)ptr % 8) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(long long *) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("%#llx", a); ++ } else if (flags & C_BINARY) { ++ kdb_printf("0b"); ++ kl_binary_print(a); ++ } else { ++ kdb_printf("%lld", a); ++ } ++} ++ ++#if 0 ++/* ++ * kl_print_float8() ++ */ ++void ++kl_print_float8(void *ptr, int flags) ++{ ++ double a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core) ++ */ ++ if (align_chk && (uaddr_t)ptr % 8) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(double*) ptr; ++ kdb_printf("%f", a); ++} ++#endif ++ ++/* ++ * kl_print_uint8() ++ */ ++void ++kl_print_uint8(void *ptr, int flags) ++{ ++ unsigned long long a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core) ++ */ ++ if (align_chk && (uaddr_t)ptr % 8) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(unsigned long long *) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("%#llx", a); ++ } else if (flags & C_BINARY) { ++ kdb_printf("0b"); ++ kl_binary_print(a); ++ } else { ++ kdb_printf("%llu", a); ++ } ++} ++ ++/* ++ * kl_print_int4() ++ */ ++void ++kl_print_int4(void *ptr, int flags) ++{ ++ int32_t a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core ++ */ ++ if (align_chk && (uaddr_t)ptr % 4) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(int32_t*) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("0x%x", a); ++ } else if (flags & C_BINARY) { ++ uint64_t value = a & 0xffffffff; ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ kdb_printf("%d", a); ++ } ++} ++ ++#if 0 ++/* ++ * kl_print_float4() ++ */ ++void ++kl_print_float4(void *ptr, int flags) ++{ ++ float a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core) ++ */ ++ if (align_chk && (uaddr_t)ptr % 4) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(float*) ptr; ++ kdb_printf("%f", a); ++} ++#endif ++ ++/* ++ * kl_print_uint4() ++ */ ++void ++kl_print_uint4(void *ptr, int flags) ++{ ++ uint32_t a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core) ++ */ ++ if (align_chk && (uaddr_t)ptr % 4) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(uint32_t*) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("0x%x", a); ++ } else if (flags & C_BINARY) { ++ uint64_t value = a & 0xffffffff; ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ kdb_printf("%u", a); ++ } ++} ++ ++/* ++ * kl_print_int2() ++ */ ++void ++kl_print_int2(void *ptr, int flags) ++{ ++ int16_t a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core ++ */ ++ if (align_chk && (uaddr_t)ptr % 2) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(int16_t*) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("0x%hx", a); ++ } else if (flags & C_BINARY) { ++ uint64_t value = a & 0xffff; ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ kdb_printf("%hd", a); ++ } ++} ++ ++/* ++ * kl_print_uint2() ++ */ ++void ++kl_print_uint2(void *ptr, int flags) ++{ ++ uint16_t a; ++ ++ /* Make sure the pointer is properly aligned (or we will ++ * dump core ++ */ ++ if (align_chk && (uaddr_t)ptr % 2) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ a = *(uint16_t*) ptr; ++ if (flags & C_HEX) { ++ kdb_printf("0x%hx", a); ++ } else if (flags & C_BINARY) { ++ uint64_t value = a & 0xffff; ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ kdb_printf("%hu", a); ++ } ++} ++ ++/* ++ * kl_print_char() ++ */ ++void ++kl_print_char(void *ptr, int flags) ++{ ++ char c; ++ ++ if (flags & C_HEX) { ++ kdb_printf("0x%x", (*(char *)ptr) & 0xff); ++ } else if (flags & C_BINARY) { ++ uint64_t value = (*(char *)ptr) & 0xff; ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ c = *(char *)ptr; ++ ++ kdb_printf("\'\\%03o\'", (unsigned char)c); ++ switch (c) { ++ case '\a' : ++ kdb_printf(" = \'\\a\'"); ++ break; ++ case '\b' : ++ kdb_printf(" = \'\\b\'"); ++ break; ++ case '\t' : ++ kdb_printf(" = \'\\t\'"); ++ break; ++ case '\n' : ++ kdb_printf(" = \'\\n\'"); ++ break; ++ case '\f' : ++ kdb_printf(" = \'\\f\'"); ++ break; ++ case '\r' : ++ kdb_printf(" = \'\\r\'"); ++ break; ++ case '\e' : ++ kdb_printf(" = \'\\e\'"); ++ break; ++ default : ++ if( !iscntrl((unsigned char) c) ) { ++ kdb_printf(" = \'%c\'", c); ++ } ++ break; ++ } ++ } ++} ++ ++/* ++ * kl_print_uchar() ++ */ ++void ++kl_print_uchar(void *ptr, int flags) ++{ ++ if (flags & C_HEX) { ++ kdb_printf("0x%x", *(unsigned char *)ptr); ++ } else if (flags & C_BINARY) { ++ uint64_t value = (*(unsigned char *)ptr) & 0xff; ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ kdb_printf("%u", *(unsigned char *)ptr); ++ } ++} ++ ++/* ++ * kl_print_base() ++ */ ++void ++kl_print_base(void *ptr, int size, int encoding, int flags) ++{ ++ /* FIXME: untested */ ++ if (invalid_address((kaddr_t)ptr, size)) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); ++ return; ++ } ++ switch (size) { ++ ++ case 1: ++ if (encoding == ENC_UNSIGNED) { ++ kl_print_uchar(ptr, flags); ++ } else { ++ kl_print_char(ptr, flags); ++ } ++ break; ++ ++ case 2: ++ if (encoding == ENC_UNSIGNED) { ++ kl_print_uint2(ptr, flags); ++ } else { ++ kl_print_int2(ptr, flags); ++ } ++ break; ++ ++ case 4: ++ if (encoding == ENC_UNSIGNED) { ++ kl_print_uint4(ptr, flags); ++ } else if (encoding == ENC_FLOAT) { ++ printk("error: print of 4-byte float\n"); ++ /* kl_print_float4(ptr, flags); */ ++ } else { ++ kl_print_int4(ptr, flags); ++ } ++ break; ++ ++ case 8: ++ if (encoding == ENC_UNSIGNED) { ++ kl_print_uint8(ptr, flags); ++ } else if (encoding == ENC_FLOAT) { ++ printk("error: print of 8-byte float\n"); ++ /* kl_print_float8(ptr, flags); */ ++ } else { ++ kl_print_int8(ptr, flags); ++ } ++ break; ++ ++ case 16: ++ if (encoding == ENC_UNSIGNED) { ++ /* Ex: unsigned long long */ ++ kl_print_uint16(ptr, flags); ++ } else if (encoding == ENC_FLOAT) { ++ printk("error: print of 16-byte float\n"); ++ /* Ex: long double */ ++ /* kl_print_float16(ptr, flags); */ ++ } else { ++ /* Ex: long long */ ++ kl_print_int16(ptr, flags); ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++/* ++ * kl_print_base_value() ++ */ ++void ++kl_print_base_value(void *ptr, kltype_t *kltp, int flags) ++{ ++ kltype_t *rkltp=NULL; ++ ++ if (kltp->kl_type != KLT_BASE) { ++ if (!(rkltp = kltp->kl_realtype)) { ++ return; ++ } ++ if (rkltp->kl_type != KLT_BASE) { ++ return; ++ } ++ } else { ++ rkltp = kltp; ++ } ++ kl_print_base(ptr, rkltp->kl_size, rkltp->kl_encoding, flags); ++} ++ ++/* ++ * kl_print_typedef_type() ++ */ ++void ++kl_print_typedef_type( ++ void *ptr, ++ kltype_t *kltp, ++ int level, ++ int flags) ++{ ++ char *name; ++ kltype_t *rkltp; ++ ++ if (ptr) { ++ rkltp = kltp->kl_realtype; ++ while (rkltp->kl_type == KLT_TYPEDEF) { ++ if (rkltp->kl_realtype) { ++ rkltp = rkltp->kl_realtype; ++ } ++ } ++ if (rkltp->kl_type == KLT_POINTER) { ++ kl_print_pointer_type(ptr, kltp, level, flags); ++ return; ++ } ++ switch (rkltp->kl_type) { ++ case KLT_BASE: ++ kl_print_base_type(ptr, kltp, ++ level, flags); ++ break; ++ ++ case KLT_UNION: ++ case KLT_STRUCT: ++ kl_print_struct_type(ptr, kltp, ++ level, flags); ++ break; ++ ++ case KLT_ARRAY: ++ kl_print_array_type(ptr, kltp, ++ level, flags); ++ break; ++ ++ case KLT_ENUMERATION: ++ kl_print_enumeration_type(ptr, ++ kltp, level, flags); ++ break; ++ ++ default: ++ kl_print_base_type(ptr, kltp, ++ level, flags); ++ break; ++ } ++ } else { ++ LEVEL_INDENT(level, flags); ++ if (flags & NO_REALTYPE) { ++ rkltp = kltp; ++ } else { ++ rkltp = kltp->kl_realtype; ++ while (rkltp && rkltp->kl_type == KLT_POINTER) { ++ rkltp = rkltp->kl_realtype; ++ } ++ } ++ if (!rkltp) { ++ if (SUPPRESS_NAME) { ++ kdb_printf(""); ++ } else { ++ kdb_printf( "typedef %s;", ++ kltp->kl_name); ++ } ++ return; ++ } ++ if (rkltp->kl_type == KLT_FUNCTION) { ++ if (kltp->kl_realtype->kl_type == KLT_POINTER) { ++ kdb_printf("typedef %s(*%s)();", ++ kltp->kl_typestr, kltp->kl_name); ++ } else { ++ kdb_printf( "typedef %s(%s)();", ++ kltp->kl_typestr, kltp->kl_name); ++ } ++ } else if (rkltp->kl_type == KLT_ARRAY) { ++ kl_print_array_type(ptr, rkltp, level, flags); ++ } else if (rkltp->kl_type == KLT_TYPEDEF) { ++ if (!(name = rkltp->kl_name)) { ++ name = rkltp->kl_typestr; ++ } ++ ++ if (SUPPRESS_NAME) { ++ kdb_printf("%s", name); ++ } else { ++ kdb_printf("typedef %s%s;", ++ name, kltp->kl_name); ++ } ++ print_realtype(rkltp); ++ } else { ++ kl_print_type(ptr, rkltp, level, flags); ++ } ++ PRINT_NL(flags); ++ } ++} ++ ++/* ++ * kl_print_pointer_type() ++ */ ++void ++kl_print_pointer_type( ++ void *ptr, ++ kltype_t *kltp, ++ int level, ++ int flags) ++{ ++ kltype_t *itp; ++ ++ if (kltp->kl_type == KLT_MEMBER) { ++ itp = kltp->kl_realtype; ++ } else { ++ itp = kltp; ++ } ++ ++ /* See if this is a pointer to a function. If it is, then it ++ * has to be handled differently... ++ */ ++ while (itp->kl_type == KLT_POINTER) { ++ if ((itp = itp->kl_realtype)) { ++ if (itp->kl_type == KLT_FUNCTION) { ++ kl_print_function_type(ptr, ++ kltp, level, flags); ++ return; ++ } ++ } else { ++ LEVEL_INDENT(level, flags); ++ kdb_printf("%s%s;\n", ++ kltp->kl_typestr, kltp->kl_name); ++ return; ++ } ++ } ++ ++ LEVEL_INDENT(level, flags); ++ if (ptr) { ++ kaddr_t tmp; ++ tmp = *(kaddr_t *)ptr; ++ flags |= SUPPRESS_SEMI_COLON; ++ if(kltp->kl_name){ ++ if (*(kaddr_t *)ptr) { ++ kdb_printf("%s = 0x%"FMTPTR"x", ++ kltp->kl_name, tmp); ++ } else { ++ kdb_printf("%s = (nil)", kltp->kl_name); ++ } ++ } else { ++ if (tmp != 0) { ++ kdb_printf("0x%"FMTPTR"x", tmp); ++ } else { ++ kdb_printf( "(nil)"); ++ } ++ } ++ } else { ++ if (kltp->kl_typestr) { ++ if (kltp->kl_name && !(flags & SUPPRESS_NAME)) { ++ kdb_printf("%s%s", ++ kltp->kl_typestr, kltp->kl_name); ++ } else { ++ kdb_printf("%s", kltp->kl_typestr); ++ } ++ } else { ++ kdb_printf(""); ++ } ++ } ++ PRINT_SEMI_COLON(level, flags); ++ PRINT_NL(flags); ++} ++ ++/* ++ * kl_print_function_type() ++ */ ++void ++kl_print_function_type( ++ void *ptr, ++ kltype_t *kltp, ++ int level, ++ int flags) ++{ ++ LEVEL_INDENT(level, flags); ++ if (ptr) { ++ kaddr_t a; ++ ++ a = *(kaddr_t *)ptr; ++ kdb_printf("%s = 0x%"FMTPTR"x", kltp->kl_name, a); ++ } else { ++ if (flags & SUPPRESS_NAME) { ++ kdb_printf("%s(*)()", kltp->kl_typestr); ++ } else { ++ kdb_printf("%s(*%s)();", ++ kltp->kl_typestr, kltp->kl_name); ++ } ++ } ++ PRINT_NL(flags); ++} ++ ++/* ++ * kl_print_array_type() ++ */ ++void ++kl_print_array_type(void *ptr, kltype_t *kltp, int level, int flags) ++{ ++ int i, count = 0, anon = 0, size, low, high, multi = 0; ++ char typestr[128], *name, *p; ++ kltype_t *rkltp, *etp, *retp; ++ ++ if (kltp->kl_type != KLT_ARRAY) { ++ if ((rkltp = kltp->kl_realtype)) { ++ while (rkltp->kl_type != KLT_ARRAY) { ++ if (!(rkltp = rkltp->kl_realtype)) { ++ break; ++ } ++ } ++ } ++ if (!rkltp) { ++ LEVEL_INDENT(level, flags); ++ kdb_printf(""); ++ PRINT_SEMI_COLON(level, flags); ++ PRINT_NL(flags); ++ return; ++ } ++ } else { ++ rkltp = kltp; ++ } ++ ++ etp = rkltp->kl_elementtype; ++ if (!etp) { ++ LEVEL_INDENT(level, flags); ++ kdb_printf(" %s", rkltp->kl_name); ++ PRINT_SEMI_COLON(level, flags); ++ PRINT_NL(flags); ++ return; ++ } ++ ++ /* Set retp to point to the actual element type. This is necessary ++ * for multi-dimensional arrays, which link using the kl_elementtype ++ * member. ++ */ ++ retp = etp; ++ while (retp->kl_type == KLT_ARRAY) { ++ retp = retp->kl_elementtype; ++ } ++ low = rkltp->kl_low_bounds + 1; ++ high = rkltp->kl_high_bounds; ++ ++ if (ptr) { ++ ++ p = ptr; ++ ++ if ((retp->kl_size == 1) && (retp->kl_encoding == ENC_CHAR)) { ++ if (kltp->kl_type == KLT_MEMBER) { ++ LEVEL_INDENT(level, flags); ++ } ++ if (flags & SUPPRESS_NAME) { ++ kdb_printf("\""); ++ flags &= ~SUPPRESS_NAME; ++ } else { ++ kdb_printf("%s = \"", kltp->kl_name); ++ } ++ for (i = 0; i < high; i++) { ++ if (*(char*)p == 0) { ++ break; ++ } ++ kdb_printf("%c", *(char *)p); ++ p++; ++ } ++ kdb_printf("\""); ++ PRINT_NL(flags); ++ } else { ++ if (kltp->kl_type == KLT_MEMBER) { ++ LEVEL_INDENT(level, flags); ++ } ++ ++ if (flags & SUPPRESS_NAME) { ++ kdb_printf("{\n"); ++ flags &= ~SUPPRESS_NAME; ++ } else { ++ kdb_printf("%s = {\n", kltp->kl_name); ++ } ++ ++ if (retp->kl_type == KLT_POINTER) { ++ size = sizeof(void *); ++ } else { ++ while (retp->kl_realtype) { ++ retp = retp->kl_realtype; ++ } ++ size = retp->kl_size; ++ } ++ if ((retp->kl_type != KLT_STRUCT) && ++ (retp->kl_type != KLT_UNION)) { ++ /* Turn off the printing of names for all ++ * but structs and unions. ++ */ ++ flags |= SUPPRESS_NAME; ++ } ++ for (i = low; i <= high; i++) { ++ ++ LEVEL_INDENT(level + 1, flags); ++ kdb_printf("[%d] ", i); ++ ++ switch (retp->kl_type) { ++ case KLT_POINTER : ++ kl_print_pointer_type( ++ p, retp, level, ++ flags|NO_INDENT); ++ break; ++ ++ case KLT_TYPEDEF: ++ kl_print_typedef_type( ++ p, retp, level, ++ flags|NO_INDENT); ++ break; ++ ++ case KLT_BASE: ++ kl_print_base_value(p, ++ retp, flags|NO_INDENT); ++ kdb_printf("\n"); ++ break; ++ ++ case KLT_ARRAY: ++ kl_print_array_type(p, retp, ++ level + 1, ++ flags|SUPPRESS_NAME); ++ break; ++ ++ case KLT_STRUCT: ++ case KLT_UNION: ++ kl_print_struct_type(p, ++ retp, level + 1, ++ flags|NO_INDENT); ++ break; ++ ++ default: ++ kl_print_base_value( ++ p, retp, ++ flags|NO_INDENT); ++ kdb_printf("\n"); ++ break; ++ } ++ p = (void *)((uaddr_t)p + size); ++ } ++ LEVEL_INDENT(level, flags); ++ kdb_printf("}"); ++ PRINT_SEMI_COLON(level, flags); ++ PRINT_NL(flags); ++ } ++ } else { ++ if (rkltp) { ++ count = (rkltp->kl_high_bounds - ++ rkltp->kl_low_bounds) + 1; ++ } else { ++ count = 1; ++ } ++ ++ if (!strcmp(retp->kl_typestr, "struct ") || ++ !strcmp(retp->kl_typestr, "union ")) { ++ anon = 1; ++ } ++next_dimension: ++ switch (retp->kl_type) { ++ ++ case KLT_UNION: ++ case KLT_STRUCT: ++ if (anon) { ++ if (multi) { ++ kdb_printf("[%d]", count); ++ break; ++ } ++ kl_print_struct_type(ptr, retp, level, ++ flags| ++ SUPPRESS_NL| ++ SUPPRESS_SEMI_COLON); ++ if (kltp->kl_type == KLT_MEMBER) { ++ kdb_printf(" %s[%d]", ++ kltp->kl_name, count); ++ } else { ++ kdb_printf(" [%d]", count); ++ } ++ break; ++ } ++ /* else drop through */ ++ ++ default: ++ LEVEL_INDENT(level, flags); ++ if (multi) { ++ kdb_printf("[%d]", count); ++ break; ++ } ++ name = kltp->kl_name; ++ if (retp->kl_type == KLT_TYPEDEF) { ++ strcpy(typestr, retp->kl_name); ++ strcat(typestr, " "); ++ } else { ++ strcpy(typestr, retp->kl_typestr); ++ } ++ if (!name || (flags & SUPPRESS_NAME)) { ++ kdb_printf("%s[%d]", typestr, count); ++ } else { ++ kdb_printf("%s%s[%d]", ++ typestr, name, count); ++ } ++ } ++ if (etp->kl_type == KLT_ARRAY) { ++ count = etp->kl_high_bounds - etp->kl_low_bounds + 1; ++ etp = etp->kl_elementtype; ++ multi++; ++ goto next_dimension; ++ } ++ PRINT_SEMI_COLON(level, flags); ++ PRINT_NL(flags); ++ } ++} ++ ++/* ++ * kl_print_enumeration_type() ++ */ ++void ++kl_print_enumeration_type( ++ void *ptr, ++ kltype_t *kltp, ++ int level, ++ int flags) ++{ ++ unsigned long long val = 0; ++ kltype_t *mp, *rkltp; ++ ++ rkltp = kl_realtype(kltp, KLT_ENUMERATION); ++ if (ptr) { ++ switch (kltp->kl_size) { ++ case 1: ++ val = *(unsigned long long *)ptr; ++ break; ++ ++ case 2: ++ val = *(uint16_t *)ptr; ++ break; ++ ++ case 4: ++ val = *(uint32_t *)ptr; ++ break; ++ ++ case 8: ++ val = *(uint64_t *)ptr; ++ break; ++ } ++ mp = rkltp->kl_member; ++ while (mp) { ++ if (mp->kl_value == val) { ++ break; ++ } ++ mp = mp->kl_member; ++ } ++ LEVEL_INDENT(level, flags); ++ if (mp) { ++ kdb_printf("%s = (%s=%lld)", ++ kltp->kl_name, mp->kl_name, val); ++ } else { ++ kdb_printf("%s = %lld", kltp->kl_name, val); ++ } ++ PRINT_NL(flags); ++ } else { ++ LEVEL_INDENT(level, flags); ++ kdb_printf ("%s {", kltp->kl_typestr); ++ mp = rkltp->kl_member; ++ while (mp) { ++ kdb_printf("%s = %d", mp->kl_name, mp->kl_value); ++ if ((mp = mp->kl_member)) { ++ kdb_printf(", "); ++ } ++ } ++ mp = kltp; ++ if (level) { ++ kdb_printf("} %s;", mp->kl_name); ++ } else { ++ kdb_printf("};"); ++ } ++ PRINT_NL(flags); ++ } ++} ++ ++/* ++ * kl_binary_print() ++ */ ++void ++kl_binary_print(uint64_t num) ++{ ++ int i, pre = 1; ++ ++ for (i = 63; i >= 0; i--) { ++ if (num & ((uint64_t)1 << i)) { ++ kdb_printf("1"); ++ if (pre) { ++ pre = 0; ++ } ++ } else { ++ if (!pre) { ++ kdb_printf("0"); ++ } ++ } ++ } ++ if (pre) { ++ kdb_printf("0"); ++ } ++} ++ ++/* ++ * kl_get_bit_value() ++ * ++ * x = byte_size, y = bit_size, z = bit_offset ++ */ ++uint64_t ++kl_get_bit_value(void *ptr, unsigned int x, unsigned int y, unsigned int z) ++{ ++ uint64_t value=0, mask; ++ ++ /* handle x bytes of buffer -- doing just memcpy won't work ++ * on big endian architectures ++ */ ++ switch (x) { ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ x = 8; ++ value = *(uint64_t*) ptr; ++ break; ++ case 3: ++ case 4: ++ x = 4; ++ value = *(uint32_t*) ptr; ++ break; ++ case 2: ++ value = *(uint16_t*) ptr; ++ break; ++ case 1: ++ value = *(uint8_t *)ptr; ++ break; ++ default: ++ /* FIXME: set KL_ERROR */ ++ return(0); ++ } ++ /* ++ o FIXME: correct handling of overlapping fields ++ */ ++ ++ /* goto bit offset */ ++ value = value >> z; ++ ++ /* mask bit size bits */ ++ mask = (((uint64_t)1 << y) - 1); ++ return (value & mask); ++} ++ ++/* ++ * kl_print_bit_value() ++ * ++ * x = byte_size, y = bit_size, z = bit_offset ++ */ ++void ++kl_print_bit_value(void *ptr, int x, int y, int z, int flags) ++{ ++ unsigned long long value; ++ ++ value = kl_get_bit_value(ptr, x, y, z); ++ if (flags & C_HEX) { ++ kdb_printf("%#llx", value); ++ } else if (flags & C_BINARY) { ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ kdb_printf("%lld", value); ++ } ++} ++ ++/* ++ * kl_print_base_type() ++ */ ++void ++kl_print_base_type(void *ptr, kltype_t *kltp, int level, int flags) ++{ ++ LEVEL_INDENT(level, flags); ++ if (ptr) { ++ if (!(flags & SUPPRESS_NAME)) { ++ kdb_printf ("%s = ", kltp->kl_name); ++ } ++ } ++ if (kltp->kl_type == KLT_MEMBER) { ++ if (kltp->kl_bit_size < (kltp->kl_size * 8)) { ++ if (ptr) { ++ kl_print_bit_value(ptr, kltp->kl_size, ++ kltp->kl_bit_size, ++ kltp->kl_bit_offset, flags); ++ } else { ++ if (kltp->kl_name) { ++ kdb_printf ("%s%s :%d;", ++ kltp->kl_typestr, ++ kltp->kl_name, ++ kltp->kl_bit_size); ++ } else { ++ kdb_printf ("%s :%d;", ++ kltp->kl_typestr, ++ kltp->kl_bit_size); ++ } ++ } ++ PRINT_NL(flags); ++ return; ++ } ++ } ++ if (ptr) { ++ kltype_t *rkltp; ++ ++ rkltp = kl_realtype(kltp, 0); ++ if (rkltp->kl_encoding == ENC_UNDEFINED) { ++ /* This is a void value ++ */ ++ kdb_printf(""); ++ } else { ++ kl_print_base(ptr, kltp->kl_size, ++ rkltp->kl_encoding, flags); ++ } ++ } else { ++ if (kltp->kl_type == KLT_MEMBER) { ++ if (flags & SUPPRESS_NAME) { ++ kdb_printf ("%s", kltp->kl_typestr); ++ } else { ++ if (kltp->kl_name) { ++ kdb_printf("%s%s;", kltp->kl_typestr, ++ kltp->kl_name); ++ } else { ++ kdb_printf ("%s :%d;", ++ kltp->kl_typestr, ++ kltp->kl_bit_size); ++ } ++ } ++ } else { ++ if (SUPPRESS_NAME) { ++ kdb_printf("%s", kltp->kl_name); ++ } else { ++ kdb_printf("%s;", kltp->kl_name); ++ } ++ } ++ } ++ PRINT_NL(flags); ++} ++ ++/* ++ * kl_print_member() ++ */ ++void ++kl_print_member(void *ptr, kltype_t *mp, int level, int flags) ++{ ++ int kl_type = 0; ++ kltype_t *rkltp; ++ ++ if (flags & C_SHOWOFFSET) { ++ kdb_printf("%#x ", mp->kl_offset); ++ } ++ ++ if ((rkltp = mp->kl_realtype)) { ++ kl_type = rkltp->kl_type; ++ } else ++ kl_type = mp->kl_type; ++ switch (kl_type) { ++ case KLT_STRUCT: ++ case KLT_UNION: ++ kl_print_struct_type(ptr, mp, level, flags); ++ break; ++ case KLT_ARRAY: ++ kl_print_array_type(ptr, mp, level, flags); ++ break; ++ case KLT_POINTER: ++ kl_print_pointer_type(ptr, mp, level, flags); ++ break; ++ case KLT_FUNCTION: ++ kl_print_function_type(ptr, mp, level, flags); ++ break; ++ case KLT_BASE: ++ kl_print_base_type(ptr, mp, level, flags); ++ break; ++ case KLT_ENUMERATION: ++ kl_print_enumeration_type(ptr, mp, level, flags); ++ break; ++ case KLT_TYPEDEF: ++ while (rkltp && rkltp->kl_realtype) { ++ if (rkltp->kl_realtype == rkltp) { ++ break; ++ } ++ rkltp = rkltp->kl_realtype; ++ } ++ if (ptr) { ++ kl_print_typedef_type(ptr, mp, ++ level, flags); ++ break; ++ } ++ LEVEL_INDENT(level, flags); ++ if (flags & SUPPRESS_NAME) { ++ if (rkltp && (mp->kl_bit_size < ++ (rkltp->kl_size * 8))) { ++ kdb_printf ("%s :%d", ++ mp->kl_typestr, ++ mp->kl_bit_size); ++ } else { ++ kdb_printf("%s", ++ mp->kl_realtype->kl_name); ++ } ++ print_realtype(mp->kl_realtype); ++ } else { ++ if (rkltp && (mp->kl_bit_size < ++ (rkltp->kl_size * 8))) { ++ if (mp->kl_name) { ++ kdb_printf ("%s%s :%d;", ++ mp->kl_typestr, ++ mp->kl_name, ++ mp->kl_bit_size); ++ } else { ++ kdb_printf ("%s :%d;", ++ mp->kl_typestr, ++ mp->kl_bit_size); ++ } ++ } else { ++ kdb_printf("%s %s;", ++ mp->kl_realtype->kl_name, ++ mp->kl_name); ++ } ++ } ++ PRINT_NL(flags); ++ break; ++ ++ default: ++ LEVEL_INDENT(level, flags); ++ if (mp->kl_typestr) { ++ kdb_printf("%s%s;", ++ mp->kl_typestr, mp->kl_name); ++ } else { ++ kdb_printf("<\?\?\? kl_type:%d> %s;", ++ kl_type, mp->kl_name); ++ } ++ PRINT_NL(flags); ++ break; ++ } ++} ++ ++/* ++ * kl_print_struct_type() ++ */ ++void ++kl_print_struct_type(void *buf, kltype_t *kltp, int level, int flags) ++{ ++ int orig_flags = flags; ++ void *ptr = NULL; ++ kltype_t *mp, *rkltp; ++ ++ /* If we are printing out an actual struct, then don't print any ++ * semi colons. ++ */ ++ if (buf) { ++ flags |= SUPPRESS_SEMI_COLON; ++ } ++ ++ LEVEL_INDENT(level, flags); ++ if ((level == 0) || (flags & NO_INDENT)) { ++ kdb_printf("%s{\n", kltp->kl_typestr); ++ } else { ++ if (buf) { ++ if (level && !(kltp->kl_flags & TYP_ANONYMOUS_FLG)) { ++ kdb_printf("%s = %s{\n", ++ kltp->kl_name, kltp->kl_typestr); ++ } else { ++ kdb_printf("%s{\n", kltp->kl_typestr); ++ } ++ flags &= (~SUPPRESS_NL); ++ } else { ++ if (kltp->kl_typestr) { ++ kdb_printf("%s{\n", kltp->kl_typestr); ++ } else { ++ kdb_printf(" {\n"); ++ } ++ } ++ } ++ ++ /* If the SUPPRESS_NL, SUPPRESS_SEMI_COLON, and SUPPRESS_NAME flags ++ * are set and buf is NULL, then turn them off as they only apply ++ * at the end of the struct. We save the original flags for that ++ * purpose. ++ */ ++ if (!buf) { ++ flags &= ~(SUPPRESS_NL|SUPPRESS_SEMI_COLON|SUPPRESS_NAME); ++ } ++ ++ /* If the NO_INDENT is set, we need to turn it off at this ++ * point -- just in case we come across a member of this struct ++ * that is also a struct. ++ */ ++ if (flags & NO_INDENT) { ++ flags &= ~(NO_INDENT); ++ } ++ ++ if (kltp->kl_type == KLT_MEMBER) { ++ rkltp = kl_realtype(kltp, 0); ++ } else { ++ rkltp = kltp; ++ } ++ level++; ++ if ((mp = rkltp->kl_member)) { ++ while (mp) { ++ if (buf) { ++ ptr = buf + mp->kl_offset; ++ } ++ kl_print_member(ptr, mp, level, flags); ++ mp = mp->kl_member; ++ } ++ } else { ++ if (kltp->kl_flags & TYP_INCOMPLETE_FLG) { ++ LEVEL_INDENT(level, flags); ++ kdb_printf("\n"); ++ } ++ } ++ level--; ++ LEVEL_INDENT(level, flags); ++ ++ /* kl_size = 0 for empty structs */ ++ if (ptr || ((kltp->kl_size == 0) && buf)) { ++ kdb_printf("}"); ++ } else if ((kltp->kl_type == KLT_MEMBER) && ++ !(orig_flags & SUPPRESS_NAME) && ++ !(kltp->kl_flags & TYP_ANONYMOUS_FLG)) { ++ kdb_printf("} %s", kltp->kl_name); ++ } else { ++ kdb_printf("}"); ++ } ++ PRINT_SEMI_COLON(level, orig_flags); ++ PRINT_NL(orig_flags); ++} ++ ++/* ++ * kl_print_type() ++ */ ++void ++kl_print_type(void *buf, kltype_t *kltp, int level, int flags) ++{ ++ void *ptr; ++ ++ if (buf) { ++ if (kltp->kl_offset) { ++ ptr = (void *)((uaddr_t)buf + kltp->kl_offset); ++ } else { ++ ptr = buf; ++ } ++ } else { ++ ptr = 0; ++ } ++ ++ /* Only allow binary printing for base types ++ */ ++ if (kltp->kl_type != KLT_BASE) { ++ flags &= (~C_BINARY); ++ } ++ switch (kltp->kl_type) { ++ ++ case KLT_TYPEDEF: ++ kl_print_typedef_type(ptr, kltp, level, flags); ++ break; ++ ++ case KLT_STRUCT: ++ case KLT_UNION: ++ kl_print_struct_type(ptr, kltp, level, flags); ++ break; ++ ++ case KLT_MEMBER: ++ kl_print_member(ptr, kltp, level, flags); ++ break; ++ ++ case KLT_POINTER: ++ kl_print_pointer_type(ptr, kltp, level, flags); ++ break; ++ ++ case KLT_FUNCTION: ++ LEVEL_INDENT(level, flags); ++ kl_print_function_type(ptr, kltp, level, flags); ++ break; ++ ++ case KLT_ARRAY: ++ kl_print_array_type(ptr, kltp, level, flags); ++ break; ++ ++ case KLT_ENUMERATION: ++ kl_print_enumeration_type(ptr, ++ kltp, level, flags); ++ break; ++ ++ case KLT_BASE: ++ kl_print_base_type(ptr, kltp, level, flags); ++ break; ++ ++ default: ++ LEVEL_INDENT(level, flags); ++ if (flags & SUPPRESS_NAME) { ++ kdb_printf ("%s", kltp->kl_name); ++ } else { ++ kdb_printf ("%s %s;", ++ kltp->kl_name, kltp->kl_name); ++ } ++ PRINT_NL(flags); ++ } ++} ++ ++/* ++ * eval is from lcrash eval.c ++ */ ++ ++/* Forward declarations */ ++static void free_node(node_t *); ++static node_t *make_node(token_t *, int); ++static node_t *get_node_list(token_t *, int); ++static node_t *do_eval(int); ++static int is_unary(int); ++static int is_binary(int); ++static int precedence(int); ++static node_t *get_sizeof(void); ++static int replace_cast(node_t *, int); ++static int replace_unary(node_t *, int); ++static node_t *replace(node_t *, int); ++static void array_to_element(node_t*, node_t*); ++static int type_to_number(node_t *); ++kltype_t *number_to_type(node_t *); ++static type_t *eval_type(node_t *); ++static type_t *get_type(char *, int); ++static int add_rchild(node_t *, node_t *); ++static void free_nodelist(node_t *); ++ ++/* Global variables ++ */ ++static int logical_flag; ++static node_t *node_list = (node_t *)NULL; ++uint64_t eval_error; ++char *error_token; ++ ++/* ++ * set_eval_error() ++ */ ++static void ++set_eval_error(uint64_t ecode) ++{ ++ eval_error = ecode; ++} ++ ++/* ++ * is_typestr() ++ * ++ * We check for "struct", "union", etc. separately because they ++ * would not be an actual part of the type name. We also assume ++ * that the string passed in ++ * ++ * - does not have any leading blanks or tabs ++ * - is NULL terminated ++ * - contains only one type name to check ++ * - does not contain any '*' characters ++ */ ++static int ++is_typestr(char *str) ++{ ++ int len; ++ ++ len = strlen(str); ++ if ((len >= 6) && !strncmp(str, "struct", 6)) { ++ return(1); ++ } else if ((len >= 5) &&!strncmp(str, "union", 5)) { ++ return(1); ++ } else if ((len >= 5) &&!strncmp(str, "short", 5)) { ++ return(1); ++ } else if ((len >= 8) &&!strncmp(str, "unsigned", 8)) { ++ return(1); ++ } else if ((len >= 6) &&!strncmp(str, "signed", 6)) { ++ return(1); ++ } else if ((len >= 4) &&!strncmp(str, "long", 4)) { ++ return(1); ++ } ++ /* Strip off any trailing blanks ++ */ ++ while(*str && ((str[strlen(str) - 1] == ' ') ++ || (str[strlen(str) - 1] == '\t'))) { ++ str[strlen(str) - 1] = 0; ++ } ++ if (kl_find_type(str, KLT_TYPES)) { ++ return (1); ++ } ++ return(0); ++} ++ ++/* ++ * free_tokens() ++ */ ++static void ++free_tokens(token_t *tp) ++{ ++ token_t *t, *tnext; ++ ++ t = tp; ++ while (t) { ++ tnext = t->next; ++ if (t->string) { ++ kl_free_block((void *)t->string); ++ } ++ kl_free_block((void *)t); ++ t = tnext; ++ } ++} ++ ++/* ++ * process_text() ++ */ ++static int ++process_text(char **str, token_t *tok) ++{ ++ char *cp = *str; ++ char *s = NULL; ++ int len = 0; ++ ++ /* Check and see if this token is a STRING or CHARACTER ++ * type (beginning with a single or double quote). ++ */ ++ if (*cp == '\'') { ++ /* make sure that only a single character is between ++ * the single quotes (it can be an escaped character ++ * too). ++ */ ++ s = strpbrk((cp + 1), "\'"); ++ if (!s) { ++ set_eval_error(E_SINGLE_QUOTE); ++ error_token = tok->ptr; ++ return(1); ++ } ++ len = (uaddr_t)s - (uaddr_t)cp; ++ if ((*(cp+1) == '\\')) { ++ if (*(cp+2) == '0') { ++ long int val; ++ unsigned long uval; ++ char *ep; ++ ++ uval = kl_strtoull((char*)(cp+2), ++ (char **)&ep, 8); ++ val = uval; ++ if ((val > 255) || (*ep != '\'')) { ++ set_eval_error(E_BAD_CHAR); ++ error_token = tok->ptr; ++ return(1); ++ } ++ } else if (*(cp+3) != '\'') { ++ set_eval_error(E_BAD_CHAR); ++ error_token = tok->ptr; ++ return(1); ++ } ++ tok->type = CHARACTER; ++ } else if (len == 2) { ++ tok->type = CHARACTER; ++ } else { ++ ++ /* Treat as a single token entry. It's possible ++ * that what's between the single quotes is a ++ * type name. That will be determined later on. ++ */ ++ tok->type = STRING; ++ } ++ *str = cp + len; ++ } else if (*cp == '\"') { ++ s = strpbrk((cp + 1), "\""); ++ if (!s) { ++ set_eval_error(E_BAD_STRING); ++ error_token = tok->ptr; ++ return(1); ++ } ++ len = (uaddr_t)s - (uaddr_t)cp; ++ tok->type = TEXT; ++ *str = cp + len; ++ } ++ if ((tok->type == STRING) || (tok->type == TEXT)) { ++ ++ if ((tok->type == TEXT) && (strlen(cp) > (len + 1))) { ++ ++ /* Check to see if there is a comma or semi-colon ++ * directly following the string. If there is, ++ * then the string is OK (the following characters ++ * are part of the next expression). Also, it's OK ++ * to have trailing blanks as long as that's all ++ * threre is. ++ */ ++ char *c; ++ ++ c = s + 1; ++ while (*c) { ++ if ((*c == ',') || (*c == ';')) { ++ break; ++ } else if (*c != ' ') { ++ set_eval_error(E_END_EXPECTED); ++ tok->ptr = c; ++ error_token = tok->ptr; ++ return(1); ++ } ++ c++; ++ } ++ /* Truncate the trailing blanks (they are not ++ * part of the string). ++ */ ++ if (c != (s + 1)) { ++ *(s + 1) = 0; ++ } ++ } ++ tok->string = (char *)kl_alloc_block(len); ++ memcpy(tok->string, (cp + 1), len - 1); ++ tok->string[len - 1] = 0; ++ } ++ return(0); ++} ++ ++/* ++ * get_token_list() ++ */ ++static token_t * ++get_token_list(char *str) ++{ ++ int paren_count = 0; ++ char *cp; ++ token_t *tok = (token_t*)NULL, *tok_head = (token_t*)NULL; ++ token_t *tok_last = (token_t*)NULL; ++ ++ cp = str; ++ eval_error = 0; ++ ++ while (*cp) { ++ ++ /* Skip past any "white space" (spaces and tabs). ++ */ ++ switch (*cp) { ++ case ' ' : ++ case '\t' : ++ case '`' : ++ cp++; ++ continue; ++ default : ++ break; ++ } ++ ++ /* Allocate space for the next token */ ++ tok = (token_t *)kl_alloc_block(sizeof(token_t)); ++ tok->ptr = cp; ++ ++ switch(*cp) { ++ ++ /* Check for operators ++ */ ++ case '+' : ++ if (*((char*)cp + 1) == '+') { ++ ++ /* We aren't doing asignment here, ++ * so the ++ operator is not ++ * considered valid. ++ */ ++ set_eval_error(E_BAD_OPERATOR); ++ error_token = tok_last->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } else if (!tok_last || ++ (tok_last->operator && ++ (tok_last->operator != CLOSE_PAREN))) { ++ tok->operator = UNARY_PLUS; ++ } else { ++ tok->operator = ADD; ++ } ++ break; ++ ++ case '-' : ++ if (*((char*)cp + 1) == '-') { ++ ++ /* We aren't doing asignment here, so ++ * the -- operator is not considered ++ * valid. ++ */ ++ set_eval_error(E_BAD_OPERATOR); ++ error_token = tok_last->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } else if (*((char*)cp + 1) == '>') { ++ tok->operator = RIGHT_ARROW; ++ cp++; ++ } else if (!tok_last || (tok_last->operator && ++ (tok_last->operator != CLOSE_PAREN))) { ++ tok->operator = UNARY_MINUS; ++ } else { ++ tok->operator = SUBTRACT; ++ } ++ break; ++ ++ case '.' : ++ /* XXX - need to check to see if this is a ++ * decimal point in the middle fo a floating ++ * point value. ++ */ ++ tok->operator = DOT; ++ break; ++ ++ case '*' : ++ /* XXX - need a better way to tell if this is ++ * an INDIRECTION. perhaps check the next ++ * token? ++ */ ++ if (!tok_last || (tok_last->operator && ++ ((tok_last->operator != CLOSE_PAREN) && ++ (tok_last->operator != CAST)))) { ++ tok->operator = INDIRECTION; ++ } else { ++ tok->operator = MULTIPLY; ++ } ++ break; ++ ++ case '/' : ++ tok->operator = DIVIDE; ++ break; ++ ++ case '%' : ++ tok->operator = MODULUS; ++ break; ++ ++ case '(' : { ++ char *s, *s1, *s2; ++ int len; ++ ++ /* Make sure the previous token is an operator ++ */ ++ if (tok_last && !tok_last->operator) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = tok_last->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } ++ ++ if (tok_last && ++ ((tok_last->operator == RIGHT_ARROW) || ++ (tok_last->operator == DOT))) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = tok_last->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } ++ ++ /* Check here to see if following tokens ++ * constitute a cast. ++ */ ++ ++ /* Skip past any "white space" (spaces ++ * and tabs) ++ */ ++ while ((*(cp+1) == ' ') || (*(cp+1) == '\t')) { ++ cp++; ++ } ++ if ((*(cp+1) == '(') || isdigit(*(cp+1)) || ++ (*(cp+1) == '+') || (*(cp+1) == '-') || ++ (*(cp+1) == '*') || (*(cp+1) == '&') || ++ (*(cp+1) == ')')){ ++ tok->operator = OPEN_PAREN; ++ paren_count++; ++ break; ++ } ++ ++ /* Make sure we have a CLOSE_PAREN. ++ */ ++ if (!(s1 = strchr(cp+1, ')'))) { ++ set_eval_error(E_OPEN_PAREN); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } ++ /* Check to see if this is NOT a simple ++ * typecast. ++ */ ++ if (!(s2 = strchr(cp+1, '.'))) { ++ s2 = strstr(cp+1, "->"); ++ } ++ if (s2 && (s2 < s1)) { ++ tok->operator = OPEN_PAREN; ++ paren_count++; ++ break; ++ } ++ ++ if ((s = strpbrk(cp+1, "*)"))) { ++ char str[128]; ++ ++ len = (uaddr_t)s - (uaddr_t)(cp+1); ++ strncpy(str, cp+1, len); ++ str[len] = 0; ++ if (!is_typestr(str)) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } ++ if (!(s = strpbrk((cp+1), ")"))) { ++ set_eval_error(E_OPEN_PAREN); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } ++ len = (uaddr_t)s - (uaddr_t)(cp+1); ++ tok->string = (char *) ++ kl_alloc_block(len + 1); ++ memcpy(tok->string, (cp+1), len); ++ tok->string[len] = 0; ++ tok->operator = CAST; ++ cp = (char *)((uaddr_t)(cp+1) + len); ++ break; ++ } ++ tok->operator = OPEN_PAREN; ++ paren_count++; ++ break; ++ } ++ ++ case ')' : ++ if (tok_last && ((tok_last->operator == ++ RIGHT_ARROW) || ++ (tok_last->operator == DOT))) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = tok_last->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return ((token_t*)NULL); ++ } ++ tok->operator = CLOSE_PAREN; ++ paren_count--; ++ break; ++ ++ case '&' : ++ if (*((char*)cp + 1) == '&') { ++ tok->operator = LOGICAL_AND; ++ cp++; ++ } else if (!tok_last || (tok_last && ++ (tok_last->operator && ++ tok_last->operator != ++ CLOSE_PAREN))) { ++ tok->operator = ADDRESS; ++ } else { ++ tok->operator = BITWISE_AND; ++ } ++ break; ++ ++ case '|' : ++ if (*((char*)cp + 1) == '|') { ++ tok->operator = LOGICAL_OR; ++ cp++; ++ } else { ++ tok->operator = BITWISE_OR; ++ } ++ break; ++ ++ case '=' : ++ if (*((char*)cp + 1) == '=') { ++ tok->operator = EQUAL; ++ cp++; ++ } else { ++ /* ASIGNMENT -- NOT IMPLEMENTED ++ */ ++ tok->operator = NOT_YET; ++ } ++ break; ++ ++ case '<' : ++ if (*((char*)cp + 1) == '<') { ++ tok->operator = LEFT_SHIFT; ++ cp++; ++ } else if (*((char*)cp + 1) == '=') { ++ tok->operator = LESS_THAN_OR_EQUAL; ++ cp++; ++ } else { ++ tok->operator = LESS_THAN; ++ } ++ break; ++ ++ case '>' : ++ if (*((char*)(cp + 1)) == '>') { ++ tok->operator = RIGHT_SHIFT; ++ cp++; ++ } else if (*((char*)cp + 1) == '=') { ++ tok->operator = GREATER_THAN_OR_EQUAL; ++ cp++; ++ } else { ++ tok->operator = GREATER_THAN; ++ } ++ break; ++ ++ case '!' : ++ if (*((char*)cp + 1) == '=') { ++ tok->operator = NOT_EQUAL; ++ cp++; ++ } else { ++ tok->operator = LOGICAL_NEGATION; ++ } ++ break; ++ ++ case '$' : ++ set_eval_error(E_NOT_IMPLEMENTED); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return((token_t*)NULL); ++ case '~' : ++ tok->operator = ONES_COMPLEMENT; ++ break; ++ ++ case '^' : ++ tok->operator = BITWISE_EXCLUSIVE_OR; ++ break; ++ ++ case '?' : ++ set_eval_error(E_NOT_IMPLEMENTED); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return((token_t*)NULL); ++ case ':' : ++ set_eval_error(E_NOT_IMPLEMENTED); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return((token_t*)NULL); ++ case '[' : ++ tok->operator = OPEN_SQUARE_BRACKET;; ++ break; ++ ++ case ']' : ++ tok->operator = CLOSE_SQUARE_BRACKET;; ++ break; ++ ++ default: { ++ ++ char *s; ++ int len; ++ ++ /* See if the last token is a RIGHT_ARROW ++ * or a DOT. If it is, then this token must ++ * be the name of a struct/union member. ++ */ ++ if (tok_last && ++ ((tok_last->operator == RIGHT_ARROW) || ++ (tok_last->operator == DOT))) { ++ tok->type = MEMBER; ++ } else if (process_text(&cp, tok)) { ++ free_tokens(tok_head); ++ free_tokens(tok); ++ return((token_t*)NULL); ++ } ++ if (tok->type == TEXT) { ++ return(tok); ++ } else if (tok->type == STRING) { ++ if (is_typestr(tok->string)) { ++ tok->type = TYPE_DEF; ++ } else { ++ tok->operator = TEXT; ++ return(tok); ++ } ++ break; ++ } else if (tok->type == CHARACTER) { ++ break; ++ } ++ ++ /* Check and See if the entire string is ++ * a typename (valid only for whatis case). ++ */ ++ s = strpbrk(cp, ++ ".\t+-*/()[]|~!$&%^<>?:&=^\"\'"); ++ if (!s && !tok->type && is_typestr(cp)) { ++ tok->type = TYPE_DEF; ++ len = strlen(cp) + 1; ++ tok->string = (char *) ++ kl_alloc_block(len); ++ memcpy(tok->string, cp, len - 1); ++ tok->string[len - 1] = 0; ++ cp = (char *)((uaddr_t)cp + len - 2); ++ break; ++ } ++ ++ /* Now check for everything else ++ */ ++ if ((s = strpbrk(cp, ++ " .\t+-*/()[]|~!$&%^<>?:&=^\"\'"))) { ++ len = (uaddr_t)s - (uaddr_t)cp + 1; ++ } else { ++ len = strlen(cp) + 1; ++ } ++ ++ tok->string = ++ (char *)kl_alloc_block(len); ++ memcpy(tok->string, cp, len - 1); ++ tok->string[len - 1] = 0; ++ ++ cp = (char *)((uaddr_t)cp + len - 2); ++ ++ /* Check to see if this is the keyword ++ * "sizeof". If not, then check to see if ++ * the string is a member name. ++ */ ++ if (!strcmp(tok->string, "sizeof")) { ++ tok->operator = SIZEOF; ++ kl_free_block((void *)tok->string); ++ tok->string = 0; ++ } else if (tok_last && ++ ((tok_last->operator == RIGHT_ARROW) || ++ (tok_last->operator == DOT))) { ++ tok->type = MEMBER; ++ } else { ++ tok->type = STRING; ++ } ++ break; ++ } ++ } ++ if (!(tok->type)) { ++ tok->type = OPERATOR; ++ } ++ if (!tok_head) { ++ tok_head = tok_last = tok; ++ } else { ++ tok_last->next = tok; ++ tok_last = tok; ++ } ++ cp++; ++ } ++ if (paren_count < 0) { ++ set_eval_error(E_CLOSE_PAREN); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ return((token_t*)NULL); ++ } else if (paren_count > 0) { ++ set_eval_error(E_OPEN_PAREN); ++ error_token = tok->ptr; ++ free_tokens(tok_head); ++ return((token_t*)NULL); ++ } ++ return(tok_head); ++} ++ ++/* ++ * valid_binary_args() ++ */ ++int ++valid_binary_args(node_t *np, node_t *left, node_t *right) ++{ ++ int op = np->operator; ++ ++ if ((op == RIGHT_ARROW) || (op == DOT)) { ++ if (!left) { ++ set_eval_error(E_MISSING_STRUCTURE); ++ error_token = np->tok_ptr; ++ return(0); ++ } else if (!(left->node_type == TYPE_DEF) && ++ !(left->node_type == MEMBER) && ++ !(left->operator == CLOSE_PAREN) && ++ !(left->operator == CLOSE_SQUARE_BRACKET)) { ++ set_eval_error(E_BAD_STRUCTURE); ++ error_token = left->tok_ptr; ++ return(0); ++ } ++ if (!right || (!(right->node_type == MEMBER))) { ++ set_eval_error(E_BAD_MEMBER); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ return(1); ++ } ++ if (!left || !right) { ++ set_eval_error(E_MISSING_OPERAND); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ switch (left->operator) { ++ case CLOSE_PAREN: ++ case CLOSE_SQUARE_BRACKET: ++ break; ++ default: ++ switch(left->node_type) { ++ case NUMBER: ++ case STRING: ++ case TEXT: ++ case CHARACTER: ++ case EVAL_VAR: ++ case MEMBER: ++ break; ++ default: ++ set_eval_error(E_BAD_OPERAND); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ } ++ switch (right->operator) { ++ case OPEN_PAREN: ++ break; ++ default: ++ switch(right->node_type) { ++ case NUMBER: ++ case STRING: ++ case TEXT: ++ case CHARACTER: ++ case EVAL_VAR: ++ case MEMBER: ++ break; ++ default: ++ set_eval_error(E_BAD_OPERAND); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ } ++ return(1); ++} ++ ++/* ++ * get_node_list() ++ */ ++static node_t * ++get_node_list(token_t *tp, int flags) ++{ ++ node_t *root = (node_t *)NULL; ++ node_t *np = (node_t *)NULL; ++ node_t *last = (node_t *)NULL; ++ ++ /* Loop through the tokens and convert them to nodes. ++ */ ++ while (tp) { ++ np = make_node(tp, flags); ++ if (eval_error) { ++ return((node_t *)NULL); ++ } ++ if (root) { ++ last->next = np; ++ last = np; ++ } else { ++ root = last = np; ++ } ++ tp = tp->next; ++ } ++ last->next = (node_t *)NULL; /* cpw patch */ ++ last = (node_t *)NULL; ++ for (np = root; np; np = np->next) { ++ if (is_binary(np->operator)) { ++ if (!valid_binary_args(np, last, np->next)) { ++ free_nodelist(root); ++ return((node_t *)NULL); ++ } ++ } ++ last = np; ++ } ++ return(root); ++} ++ ++/* ++ * next_node() ++ */ ++static node_t * ++next_node(void) ++{ ++ node_t *np; ++ if ((np = node_list)) { ++ node_list = node_list->next; ++ np->next = (node_t*)NULL; ++ } ++ return(np); ++} ++ ++/* ++ * eval_unary() ++ */ ++static node_t * ++eval_unary(node_t *curnp, int flags) ++{ ++ node_t *n0, *n1; ++ ++ n0 = curnp; ++ ++ /* Peek ahead and make sure there is a next node. ++ * Also check to see if the next node requires ++ * a recursive call to do_eval(). If it does, we'll ++ * let the do_eval() call take care of pulling it ++ * off the list. ++ */ ++ if (!node_list) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ if (n0->operator == CAST) { ++ if (node_list->operator == CLOSE_PAREN) { ++ ++ /* Free the CLOSE_PAREN and return ++ */ ++ free_node(next_node()); ++ return(n0); ++ } ++ if (!(node_list->node_type == NUMBER) && ++ !(node_list->node_type == VADDR) && ++ !((node_list->operator == ADDRESS) || ++ (node_list->operator == CAST) || ++ (node_list->operator == UNARY_MINUS) || ++ (node_list->operator == UNARY_PLUS) || ++ (node_list->operator == INDIRECTION) || ++ (node_list->operator == OPEN_PAREN))) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = node_list->tok_ptr; ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ } ++ if ((n0->operator == INDIRECTION) || ++ (n0->operator == ADDRESS) || ++ (n0->operator == OPEN_PAREN) || ++ is_unary(node_list->operator)) { ++ n1 = do_eval(flags); ++ if (eval_error) { ++ free_nodes(n0); ++ free_nodes(n1); ++ return((node_t*)NULL); ++ } ++ } else { ++ n1 = next_node(); ++ } ++ ++ if (n1->operator == OPEN_PAREN) { ++ /* Get the value contained within the parenthesis. ++ * If there was an error, just return. ++ */ ++ free_node(n1); ++ n1 = do_eval(flags); ++ if (eval_error) { ++ free_nodes(n1); ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ } ++ ++ n0->right = n1; ++ if (replace_unary(n0, flags) == -1) { ++ if (!eval_error) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n0->tok_ptr; ++ } ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ return(n0); ++} ++ ++/* ++ * do_eval() -- Reduces an equation to a single value. ++ * ++ * Any parenthesis (and nested parenthesis) within the equation will ++ * be solved first via recursive calls to do_eval(). ++ */ ++static node_t * ++do_eval(int flags) ++{ ++ node_t *root = (node_t*)NULL, *curnp, *n0, *n1; ++ ++ /* Loop through the list of nodes until we run out of nodes ++ * or we hit a CLOSE_PAREN. If we hit an OPEN_PAREN, make a ++ * recursive call to do_eval(). ++ */ ++ curnp = next_node(); ++ while (curnp) { ++ n0 = n1 = (node_t *)NULL; ++ ++ if (curnp->operator == OPEN_PAREN) { ++ /* Get the value contained within the parenthesis. ++ * If there was an error, just return. ++ */ ++ free_node(curnp); ++ n0 = do_eval(flags); ++ if (eval_error) { ++ free_nodes(n0); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ ++ } else if (curnp->operator == SIZEOF) { ++ /* Free the SIZEOF node and then make a call ++ * to the get_sizeof() function (which will ++ * get the next node off the list). ++ */ ++ n0 = get_sizeof(); ++ if (eval_error) { ++ if (!error_token) { ++ error_token = curnp->tok_ptr; ++ } ++ free_node(curnp); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ free_node(curnp); ++ curnp = (node_t *)NULL; ++ } else if (is_unary(curnp->operator)) { ++ n0 = eval_unary(curnp, flags); ++ } else { ++ n0 = curnp; ++ curnp = (node_t *)NULL; ++ } ++ if (eval_error) { ++ free_nodes(n0); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ ++ /* n0 should now contain a non-operator node. Check to see if ++ * there is a next token. If there isn't, just add the last ++ * rchild and return. ++ */ ++ if (!node_list) { ++ if (root) { ++ add_rchild(root, n0); ++ } else { ++ root = n0; ++ } ++ replace(root, flags); ++ if (eval_error) { ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ return(root); ++ } ++ ++ /* Make sure the next token is an operator. ++ */ ++ if (!node_list->operator) { ++ free_nodes(root); ++ free_node(n0); ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = node_list->tok_ptr; ++ return((node_t *)NULL); ++ } else if ((node_list->operator == CLOSE_PAREN) || ++ (node_list->operator == CLOSE_SQUARE_BRACKET)) { ++ ++ if (root) { ++ add_rchild(root, n0); ++ } else { ++ root = n0; ++ } ++ ++ /* Reduce the resulting tree to a single value ++ */ ++ replace(root, flags); ++ if (eval_error) { ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ ++ /* Step over the CLOSE_PAREN or CLOSE_SQUARE_BRACKET ++ * and then return. ++ */ ++ free_node(next_node()); ++ return(root); ++ } else if (node_list->operator == OPEN_SQUARE_BRACKET) { ++next_dimension1: ++ /* skip over the OPEN_SQUARE_BRACKET token ++ */ ++ free_node(next_node()); ++ ++ /* Get the value contained within the brackets. This ++ * value must represent an array index (value or ++ * equation). ++ */ ++ n1 = do_eval(0); ++ if (eval_error) { ++ free_nodes(root); ++ free_node(n0); ++ free_node(n1); ++ return((node_t *)NULL); ++ } ++ ++ /* Convert the array (or pointer type) to an ++ * element type using the index value obtained ++ * above. Make sure that n0 contains some sort ++ * of type definition first, however. ++ */ ++ if (n0->node_type != TYPE_DEF) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ free_nodes(n1); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ array_to_element(n0, n1); ++ free_node(n1); ++ if (eval_error) { ++ free_nodes(root); ++ free_nodes(n0); ++ return((node_t *)NULL); ++ } ++ ++ /* If there aren't any more nodes, just ++ * return. ++ */ ++ if (!node_list) { ++ return(n0); ++ } ++ if (node_list->operator == OPEN_SQUARE_BRACKET) { ++ goto next_dimension1; ++ } ++ } else if (!is_binary(node_list->operator)) { ++ set_eval_error(E_BAD_OPERATOR); ++ error_token = node_list->tok_ptr; ++ free_nodes(root); ++ free_nodes(n0); ++ return((node_t *)NULL); ++ } ++ ++ /* Now get the operator node ++ */ ++ if (!(n1 = next_node())) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ ++ /* Check to see if this binary operator is RIGHT_ARROW or DOT. ++ * If it is, we need to reduce it to a single value node now. ++ */ ++ while ((n1->operator == RIGHT_ARROW) || (n1->operator == DOT)) { ++ ++ /* The next node must contain the name of the ++ * struct|union member. ++ */ ++ if (!node_list || (node_list->node_type != MEMBER)) { ++ set_eval_error(E_BAD_MEMBER); ++ error_token = n1->tok_ptr; ++ free_nodes(n0); ++ free_nodes(n1); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ n1->left = n0; ++ ++ /* Now get the next node and link it as the ++ * right child. ++ */ ++ if (!(n0 = next_node())) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n1->tok_ptr; ++ free_nodes(n1); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ n1->right = n0; ++ if (!(n0 = replace(n1, flags))) { ++ if (!(eval_error)) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n1->tok_ptr; ++ } ++ free_nodes(n1); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ n1 = (node_t *)NULL; ++ ++ /* Check to see if there is a next node. If there ++ * is, check to see if it is the operator CLOSE_PAREN. ++ * If it is, then return (skipping over the ++ * CLOSE_PAREN first). ++ */ ++ if (node_list && ((node_list->operator == CLOSE_PAREN) ++ || (node_list->operator == ++ CLOSE_SQUARE_BRACKET))) { ++ if (root) { ++ add_rchild(root, n0); ++ } else { ++ root = n0; ++ } ++ ++ /* Reduce the resulting tree to a single ++ * value ++ */ ++ replace(root, flags); ++ if (eval_error) { ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ ++ /* Advance the token pointer past the ++ * CLOSE_PAREN and then return. ++ */ ++ free_node(next_node()); ++ return(root); ++ } ++ ++ /* Check to see if the next node is an ++ * OPEN_SQUARE_BRACKET. If it is, then we have to ++ * reduce the contents of the square brackets to ++ * an index array. ++ */ ++ if (node_list && (node_list->operator ++ == OPEN_SQUARE_BRACKET)) { ++ ++ /* Advance the token pointer and call ++ * do_eval() again. ++ */ ++ free_node(next_node()); ++next_dimension2: ++ n1 = do_eval(0); ++ if (eval_error) { ++ free_node(n0); ++ free_node(n1); ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ ++ /* Convert the array (or pointer type) to ++ * an element type using the index value ++ * obtained above. Make sure that n0 ++ * contains some sort of type definition ++ * first, however. ++ */ ++ if (n0->node_type != TYPE_DEF) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n0->tok_ptr; ++ free_node(n0); ++ free_node(n1); ++ free_node(root); ++ return((node_t *)NULL); ++ } ++ array_to_element(n0, n1); ++ free_node(n1); ++ if (eval_error) { ++ free_node(n0); ++ free_node(root); ++ return((node_t *)NULL); ++ } ++ } ++ ++ /* Now get the next operator node (if there is one). ++ */ ++ if (!node_list) { ++ if (root) { ++ add_rchild(root, n0); ++ } else { ++ root = n0; ++ } ++ return(root); ++ } ++ n1 = next_node(); ++ if (n1->operator == OPEN_SQUARE_BRACKET) { ++ goto next_dimension2; ++ } ++ } ++ ++ if (n1 && ((n1->operator == CLOSE_PAREN) || ++ (n1->operator == CLOSE_SQUARE_BRACKET))) { ++ free_node(n1); ++ if (root) { ++ add_rchild(root, n0); ++ } else { ++ root = n0; ++ } ++ replace(root, flags); ++ if (eval_error) { ++ free_nodes(root); ++ return((node_t *)NULL); ++ } ++ return(root); ++ } ++ ++ if (!root) { ++ root = n1; ++ n1->left = n0; ++ } else if (precedence(root->operator) ++ >= precedence(n1->operator)) { ++ add_rchild(root, n0); ++ n1->left = root; ++ root = n1; ++ } else { ++ if (!root->right) { ++ n1->left = n0; ++ root->right = n1; ++ } else { ++ add_rchild(root, n0); ++ n1->left = root->right; ++ root->right = n1; ++ } ++ } ++ curnp = next_node(); ++ } /* while(curnp) */ ++ return(root); ++} ++ ++/* ++ * is_unary() ++ */ ++static int ++is_unary(int op) ++{ ++ switch (op) { ++ case LOGICAL_NEGATION : ++ case ADDRESS : ++ case INDIRECTION : ++ case UNARY_MINUS : ++ case UNARY_PLUS : ++ case ONES_COMPLEMENT : ++ case CAST : ++ return(1); ++ ++ default : ++ return(0); ++ } ++} ++ ++ ++/* ++ * is_binary() ++ */ ++static int ++is_binary(int op) ++{ ++ switch (op) { ++ ++ case BITWISE_OR : ++ case BITWISE_EXCLUSIVE_OR : ++ case BITWISE_AND : ++ case RIGHT_SHIFT : ++ case LEFT_SHIFT : ++ case ADD : ++ case SUBTRACT : ++ case MULTIPLY : ++ case DIVIDE : ++ case MODULUS : ++ case LOGICAL_OR : ++ case LOGICAL_AND : ++ case EQUAL : ++ case NOT_EQUAL : ++ case LESS_THAN : ++ case GREATER_THAN : ++ case LESS_THAN_OR_EQUAL : ++ case GREATER_THAN_OR_EQUAL : ++ case RIGHT_ARROW : ++ case DOT : ++ return(1); ++ ++ default : ++ return(0); ++ } ++} ++ ++/* ++ * precedence() ++ */ ++static int ++precedence(int a) ++{ ++ if ((a >= CONDITIONAL) && (a <= CONDITIONAL_ELSE)) { ++ return(1); ++ } else if (a == LOGICAL_OR) { ++ return(2); ++ } else if (a == LOGICAL_AND) { ++ return(3); ++ } else if (a == BITWISE_OR) { ++ return(4); ++ } else if (a == BITWISE_EXCLUSIVE_OR) { ++ return(5); ++ } else if (a == BITWISE_AND) { ++ return(6); ++ } else if ((a >= EQUAL) && (a <= NOT_EQUAL)) { ++ return(7); ++ } else if ((a >= LESS_THAN) && (a <= GREATER_THAN_OR_EQUAL)) { ++ return(8); ++ } else if ((a >= RIGHT_SHIFT) && (a <= LEFT_SHIFT)) { ++ return(9); ++ } else if ((a >= ADD) && (a <= SUBTRACT)) { ++ return(10); ++ } else if ((a >= MULTIPLY) && (a <= MODULUS)) { ++ return(11); ++ } else if ((a >= LOGICAL_NEGATION) && (a <= SIZEOF)) { ++ return(12); ++ } else if ((a >= RIGHT_ARROW) && (a <= DOT)) { ++ return(13); ++ } else { ++ return(0); ++ } ++} ++ ++/* ++ * esc_char() ++ */ ++char ++esc_char(char *str) ++{ ++ long int val; ++ unsigned long uval; ++ char ch; ++ ++ if (strlen(str) > 1) { ++ uval = kl_strtoull(str, (char **)NULL, 8); ++ val = uval; ++ ch = (char)val; ++ } else { ++ ch = str[0]; ++ } ++ switch (ch) { ++ case 'a' : ++ return((char)7); ++ case 'b' : ++ return((char)8); ++ case 't' : ++ return((char)9); ++ case 'n' : ++ return((char)10); ++ case 'f' : ++ return((char)12); ++ case 'r' : ++ return((char)13); ++ case 'e' : ++ return((char)27); ++ default: ++ return(ch); ++ } ++} ++ ++/* ++ * make_node() ++ */ ++static node_t * ++make_node(token_t *t, int flags) ++{ ++ node_t *np; ++ ++ set_eval_error(0); ++ np = (node_t*)kl_alloc_block(sizeof(*np)); ++ ++ if (t->type == OPERATOR) { ++ ++ /* Check to see if this token represents a typecast ++ */ ++ if (t->operator == CAST) { ++ type_t *tp; ++ ++ if (!(np->type = get_type(t->string, flags))) { ++ set_eval_error(E_BAD_CAST); ++ error_token = t->ptr; ++ free_nodes(np); ++ return((node_t*)NULL); ++ } ++ ++ /* Determin if this is a pointer to a type ++ */ ++ tp = np->type; ++ if (tp->flag == POINTER_FLAG) { ++ np->flags = POINTER_FLAG; ++ tp = tp->t_next; ++ while (tp->flag == POINTER_FLAG) { ++ tp = tp->t_next; ++ } ++ } ++ switch(tp->flag) { ++ case KLTYPE_FLAG: ++ np->flags |= KLTYPE_FLAG; ++ break; ++ ++ default: ++ free_nodes(np); ++ set_eval_error(E_BAD_CAST); ++ error_token = t->ptr; ++ return((node_t*)NULL); ++ } ++ if (!t->next) { ++ if (flags & C_WHATIS) { ++ np->node_type = TYPE_DEF; ++ } else { ++ set_eval_error(E_BAD_CAST); ++ error_token = t->ptr; ++ return((node_t*)NULL); ++ } ++ } else { ++ np->node_type = OPERATOR; ++ np->operator = CAST; ++ } ++ } else { ++ np->node_type = OPERATOR; ++ np->operator = t->operator; ++ } ++ } else if (t->type == MEMBER) { ++ np->name = (char *)dup_block((void *)t->string, strlen(t->string)+1); ++ np->node_type = MEMBER; ++ } else if ((t->type == STRING) || (t->type == TYPE_DEF)) { ++ syment_t *sp; ++ dbg_sym_t *stp; ++ dbg_type_t *sttp; ++ ++ if ((sp = kl_lkup_symname(t->string))) { ++ if (!(flags & C_NOVARS)) { ++ int has_type = 0; ++ ++ /* The string is a symbol name. We'll treat it as ++ * a global kernel variable and, at least, gather in ++ * the address of the symbol and the value it points ++ * to. ++ */ ++ np->address = sp->s_addr; ++ np->flags |= ADDRESS_FLAG; ++ np->name = t->string; ++ t->string = (char*)NULL; ++ ++ /* Need to see if there is type information available ++ * for this variable. Since this mapping is not ++ * available yet, we will just attach a type struct ++ * for either uint32_t or uint64_t (depending on the ++ * size of a kernel pointer). That will at least let ++ * us do something and will prevent the scenario where ++ * we have a type node with out a pointer to a type ++ * struct! ++ */ ++ np->node_type = TYPE_DEF; ++ np->flags |= KLTYPE_FLAG; ++ np->value = *((kaddr_t *)np->address); ++ /* try to get the actual type info for the variable */ ++ if(((stp = dbg_find_sym(sp->s_name, DBG_VAR, ++ (uint64_t)0)) != NULL)){ ++ if((sttp = (dbg_type_t *) ++ kl_find_typenum(stp->sym_typenum)) ++ != NULL){ ++ /* kl_get_typestring(sttp); */ ++ has_type = 1; ++ if(sttp->st_klt.kl_type == KLT_POINTER){ ++ np->flags ^= KLTYPE_FLAG; ++ np->flags |= POINTER_FLAG; ++ np->type = ++ get_type(sttp->st_typestr, ++ flags); ++ } else { ++ np->type = ++ kl_alloc_block(sizeof(type_t)); ++ np->type->un.kltp = ++ &sttp->st_klt; ++ } ++ } ++ } ++ /* no type info for the variable found */ ++ if(!has_type){ ++ if (ptrsz64) { ++ np->type = get_type("uint64_t", flags); ++ } else { ++ np->type = get_type("uint32_t", flags); ++ } ++ } ++ } ++ kl_free_block((void *)sp); ++ } else if (flags & (C_WHATIS|C_SIZEOF)) { ++ ++ kltype_t *kltp; ++ ++ if ((kltp = kl_find_type(t->string, KLT_TYPES))) { ++ ++ np->node_type = TYPE_DEF; ++ np->flags = KLTYPE_FLAG; ++ np->type = (type_t*) ++ kl_alloc_block(sizeof(type_t)); ++ np->type->flag = KLTYPE_FLAG; ++ np->type->t_kltp = kltp; ++ } else { ++ if (get_value(t->string, ++ (uint64_t *)&np->value)) { ++ set_eval_error(E_BAD_VALUE); ++ error_token = t->ptr; ++ free_nodes(np); ++ return((node_t*)NULL); ++ } ++ if (!strncmp(t->string, "0x", 2) || ++ !strncmp(t->string, "0X", 2)) { ++ np->flags |= UNSIGNED_FLAG; ++ } ++ np->node_type = NUMBER; ++ } ++ np->tok_ptr = t->ptr; ++ return(np); ++ } else { ++ if (get_value(t->string, (uint64_t *)&np->value)) { ++ set_eval_error(E_BAD_VALUE); ++ error_token = t->ptr; ++ free_nodes(np); ++ return((node_t*)NULL); ++ } ++ if (np->value > 0xffffffff) { ++ np->byte_size = 8; ++ } else { ++ np->byte_size = 4; ++ } ++ if (!strncmp(t->string, "0x", 2) || ++ !strncmp(t->string, "0X", 2)) { ++ np->flags |= UNSIGNED_FLAG; ++ } ++ np->node_type = NUMBER; ++ } ++ } else if (t->type == CHARACTER) { ++ char *cp; ++ ++ /* Step over the single quote ++ */ ++ cp = (t->ptr + 1); ++ if (*cp == '\\') { ++ int i = 0; ++ char str[16]; ++ ++ /* Step over the back slash ++ */ ++ cp++; ++ while (*cp != '\'') { ++ str[i++] = *cp++; ++ } ++ str[i] = 0; ++ np->value = esc_char(str); ++ } else { ++ np->value = *cp; ++ } ++ np->type = get_type("char", flags); ++ np->node_type = TYPE_DEF; ++ np->flags |= KLTYPE_FLAG; ++ } else if (t->type == TEXT) { ++ np->node_type = TEXT; ++ np->name = t->string; ++ /* So the block doesn't get freed twice */ ++ t->string = (char*)NULL; ++ } else { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = t->ptr; ++ return((node_t*)NULL); ++ } ++ np->tok_ptr = t->ptr; ++ return(np); ++} ++ ++/* ++ * add_node() ++ */ ++static int ++add_node(node_t *root, node_t *new_node) ++{ ++ node_t *n = root; ++ ++ /* Find the most lower-right node ++ */ ++ while (n->right) { ++ n = n->right; ++ } ++ ++ /* If the node we found is a leaf node, return an error (we will ++ * have to insert the node instead). ++ */ ++ if (n->node_type == NUMBER) { ++ return(-1); ++ } else { ++ n->right = new_node; ++ } ++ return(0); ++} ++ ++/* ++ * add_rchild() ++ */ ++static int ++add_rchild(node_t *root, node_t *new_node) ++{ ++ if (add_node(root, new_node) == -1) { ++ return(-1); ++ } ++ return(0); ++} ++ ++/* ++ * free_type() ++ */ ++static void ++free_type(type_t *head) ++{ ++ type_t *t0, *t1; ++ ++ t0 = head; ++ while(t0) { ++ if (t0->flag == POINTER_FLAG) { ++ t1 = t0->t_next; ++ kl_free_block((void *)t0); ++ t0 = t1; ++ } else { ++ if (t0->flag != KLTYPE_FLAG) { ++ kl_free_block((void *)t0->t_kltp); ++ } ++ kl_free_block((void *)t0); ++ t0 = (type_t *)NULL; ++ } ++ } ++ return; ++} ++ ++/* ++ * get_type() -- Convert a typecast string into a type. ++ * ++ * Returns a pointer to a struct containing type information. ++ * The type of struct returned is indicated by the contents ++ * of type. If the typecast contains an asterisk, set ptr_type ++ * equal to one, otherwise set it equal to zero. ++ */ ++static type_t * ++get_type(char *s, int flags) ++{ ++ int len, type = 0; ++ char *cp, typename[128]; ++ type_t *t, *head, *last; ++ kltype_t *kltp; ++ ++ head = last = (type_t *)NULL; ++ ++ /* Get the type string ++ */ ++ if (!strncmp(s, "struct", 6)) { ++ if ((cp = strpbrk(s + 7, " \t*"))) { ++ len = cp - (s + 7); ++ } else { ++ len = strlen(s + 7); ++ } ++ memcpy(typename, s + 7, len); ++ } else if (!strncmp(s, "union", 5)) { ++ if ((cp = strpbrk(s + 6, " \t*"))) { ++ len = cp - (s + 6); ++ } else { ++ len = strlen(s + 6); ++ } ++ memcpy(typename, s + 6, len); ++ } else { ++ if ((cp = strpbrk(s, "*)"))) { ++ len = cp - s; ++ } else { ++ len = strlen(s); ++ } ++ memcpy(typename, s, len); ++ } ++ ++ /* Strip off any trailing spaces ++ */ ++ while (len && ((typename[len - 1] == ' ') || ++ (typename[len - 1] == '\t'))) { ++ len--; ++ } ++ typename[len] = 0; ++ ++ if (!(kltp = kl_find_type(typename, KLT_TYPES))) { ++ return ((type_t *)NULL); ++ } ++ type = KLTYPE_FLAG; ++ ++ /* check to see if this cast is a pointer to a type, a pointer ++ * to a pointer to a type, etc. ++ */ ++ cp = s; ++ while ((cp = strpbrk(cp, "*"))) { ++ t = (type_t *)kl_alloc_block(sizeof(type_t)); ++ t->flag = POINTER_FLAG; ++ if (last) { ++ last->t_next = t; ++ last = t; ++ } else { ++ head = last = t; ++ } ++ cp++; ++ } ++ ++ /* Allocate a type block that will point to the type specific ++ * record. ++ */ ++ t = (type_t *)kl_alloc_block(sizeof(type_t)); ++ t->flag = type; ++ ++ switch (t->flag) { ++ ++ case KLTYPE_FLAG: ++ t->t_kltp = kltp; ++ break; ++ ++ default: ++ free_type(head); ++ return((type_t*)NULL); ++ } ++ if (last) { ++ last->t_next = t; ++ } else { ++ head = t; ++ } ++ return(head); ++} ++ ++/* ++ * free_node() ++ */ ++static void ++free_node(node_t *np) ++{ ++ /* If there is nothing to free, just return. ++ */ ++ if (!np) { ++ return; ++ } ++ if (np->name) { ++ kl_free_block((void *)np->name); ++ } ++ free_type(np->type); ++ kl_free_block((void *)np); ++} ++ ++/* ++ * free_nodes() ++ */ ++void ++free_nodes(node_t *np) ++{ ++ node_t *q; ++ ++ /* If there is nothing to free, just return. ++ */ ++ if (!np) { ++ return; ++ } ++ if ((q = np->left)) { ++ free_nodes(q); ++ } ++ if ((q = np->right)) { ++ free_nodes(q); ++ } ++ if (np->name) { ++ kl_free_block((void *)np->name); ++ } ++ free_type(np->type); ++ kl_free_block((void *)np); ++} ++ ++/* ++ * free_nodelist() ++ */ ++static void ++free_nodelist(node_t *np) ++{ ++ node_t *nnp; ++ ++ while(np) { ++ nnp = np->next; ++ free_node(np); ++ np = nnp; ++ } ++} ++ ++extern int alloc_debug; ++ ++/* ++ * free_eval_memory() ++ */ ++void ++free_eval_memory(void) ++{ ++ free_nodelist(node_list); ++ node_list = (node_t*)NULL; ++} ++ ++/* ++ * get_sizeof() ++ */ ++static node_t * ++get_sizeof() ++{ ++ node_t *curnp, *n0 = NULL; ++ ++ if (!(curnp = next_node())) { ++ set_eval_error(E_SYNTAX_ERROR); ++ return((node_t*)NULL); ++ } ++ ++ /* The next token should be a CAST or an open paren. ++ * If it's something else, then return an error. ++ */ ++ if (curnp->operator == OPEN_PAREN) { ++ free_nodes(curnp); ++ n0 = do_eval(C_SIZEOF); ++ if (eval_error) { ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ } else if (curnp->operator == CAST) { ++ n0 = curnp; ++ } else { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ ++ if (!n0->type) { ++ set_eval_error(E_NOTYPE); ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ ++ if (n0->type->flag & POINTER_FLAG) { ++ n0->value = sizeof(void *); ++ } else if (n0->type->flag & KLTYPE_FLAG) { ++ kltype_t *kltp; ++ ++ kltp = kl_realtype(n0->type->t_kltp, 0); ++ ++ if (kltp->kl_bit_size) { ++ n0->value = kltp->kl_bit_size / 8; ++ if (kltp->kl_bit_size % 8) { ++ n0->value += 1; ++ } ++ } else { ++ n0->value = kltp->kl_size; ++ } ++ } else { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n0->tok_ptr; ++ free_nodes(n0); ++ return((node_t*)NULL); ++ } ++ n0->node_type = NUMBER; ++ n0->flags = 0; ++ n0->operator = 0; ++ n0->byte_size = 0; ++ n0->address = 0; ++ if (n0->type) { ++ free_type(n0->type); ++ n0->type = 0; ++ } ++ return(n0); ++} ++ ++/* ++ * apply_unary() ++ */ ++static int ++apply_unary(node_t *n, uint64_t *value) ++{ ++ if (!n || !n->right) { ++ return(-1); ++ } ++ ++ switch (n->operator) { ++ ++ case UNARY_MINUS : ++ *value = (0 - n->right->value); ++ break; ++ ++ case UNARY_PLUS : ++ *value = (n->right->value); ++ break; ++ ++ case ONES_COMPLEMENT : ++ *value = ~(n->right->value); ++ break; ++ ++ case LOGICAL_NEGATION : ++ if (n->right->value) { ++ *value = 0; ++ } else { ++ *value = 1; ++ } ++ logical_flag++; ++ break; ++ ++ default : ++ break; ++ } ++ return(0); ++} ++ ++/* ++ * pointer_math() ++ */ ++static int ++pointer_math(node_t *np, uint64_t *value, int type, int flags) ++{ ++ int size; ++ uint64_t lvalue, rvalue; ++ type_t *tp = NULL, *tp1; ++ ++ if (type < 0) { ++ if (np->left->flags & POINTER_FLAG) { ++ ++ /* Since we only allow pointer math, ++ * anything other than a pointer causes ++ * failure. ++ */ ++ tp = (type_t*)np->left->type; ++ if (tp->flag != POINTER_FLAG) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = np->left->tok_ptr; ++ return(-1); ++ } ++ ++ tp = tp->t_next; ++ ++ switch (tp->flag) { ++ ++ case POINTER_FLAG : ++ size = sizeof(void *); ++ break; ++ ++ case KLTYPE_FLAG : { ++ /* Get the size of the real type, ++ * not just the size of a pointer ++ * If there isn't any type info, ++ * then just set size equal to the ++ * size of a pointer. ++ */ ++ kltype_t *kltp, *rkltp; ++ ++ kltp = tp->t_kltp; ++ rkltp = kl_realtype(kltp, 0); ++ if (!(size = rkltp->kl_size)) { ++ if (kltp != rkltp) { ++ size = kltp->kl_size; ++ } else { ++ size = sizeof(void *); ++ } ++ } ++ break; ++ } ++ ++ default : ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = np->left->tok_ptr; ++ return(-1); ++ } ++ lvalue = np->left->value; ++ } else { ++ size = sizeof(void *); ++ lvalue = np->left->address; ++ } ++ switch (np->operator) { ++ case ADD : ++ *value = lvalue + (np->right->value * size); ++ break; ++ ++ case SUBTRACT : ++ *value = lvalue - (np->right->value * size); ++ break; ++ ++ default : ++ set_eval_error(E_BAD_OPERATOR); ++ error_token = np->tok_ptr; ++ return(-1); ++ } ++ } else if (type > 0) { ++ if (np->right->flags & POINTER_FLAG) { ++ ++ /* Since we only allow pointer math, ++ * anything other than a pointer causes ++ * failure. ++ */ ++ tp = (type_t*)np->right->type; ++ if (tp->flag != POINTER_FLAG) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = np->right->tok_ptr; ++ return(-1); ++ } ++ ++ tp = tp->t_next; ++ ++ switch (tp->flag) { ++ ++ case POINTER_FLAG : ++ size = sizeof(void *); ++ break; ++ ++ case KLTYPE_FLAG : ++ size = tp->t_kltp->kl_size; ++ break; ++ ++ default : ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = np->right->tok_ptr; ++ return(-1); ++ } ++ rvalue = np->right->value; ++ } else { ++ size = sizeof(void *); ++ rvalue = np->right->address; ++ } ++ switch (np->operator) { ++ case ADD : ++ *value = rvalue + (np->left->value * size); ++ break; ++ ++ case SUBTRACT : ++ *value = rvalue - (np->left->value * size); ++ break; ++ ++ default : ++ set_eval_error(E_BAD_OPERATOR); ++ error_token = np->tok_ptr; ++ return(-1); ++ } ++ } else { ++ return(-1); ++ } ++ tp1 = (type_t *)kl_alloc_block(sizeof(type_t)); ++ tp1->flag = POINTER_FLAG; ++ np->type = tp1; ++ while (tp->flag == POINTER_FLAG) { ++ tp1->t_next = (type_t *)kl_alloc_block(sizeof(type_t)); ++ tp1->flag = POINTER_FLAG; ++ tp1 = tp1->t_next; ++ tp = tp->t_next; ++ } ++ if (tp) { ++ tp1->t_next = (type_t *)kl_alloc_block(sizeof(type_t)); ++ tp1 = tp1->t_next; ++ tp1->flag = KLTYPE_FLAG; ++ tp1->t_kltp = tp->t_kltp; ++ if (type < 0) { ++ if (np->left->flags & POINTER_FLAG) { ++ np->flags |= POINTER_FLAG; ++ } else { ++ np->flags |= VADDR; ++ } ++ } else { ++ if (np->right->flags & POINTER_FLAG) { ++ np->flags |= POINTER_FLAG; ++ } else { ++ np->flags |= VADDR; ++ } ++ } ++ } ++ return(0); ++} ++ ++/* ++ * check_unsigned() ++ */ ++int ++check_unsigned(node_t *np) ++{ ++ kltype_t *kltp, *rkltp; ++ ++ if (np->flags & UNSIGNED_FLAG) { ++ return(1); ++ } ++ if (!np->type) { ++ return(0); ++ } ++ if (np->type->flag == POINTER_FLAG) { ++ return(0); ++ } ++ kltp = np->type->t_kltp; ++ if ((rkltp = kl_realtype(kltp, 0))) { ++ if (rkltp->kl_encoding == ENC_UNSIGNED) { ++ np->flags |= UNSIGNED_FLAG; ++ return(1); ++ } ++ } ++ return(0); ++} ++ ++/* ++ * apply() ++ */ ++static int ++apply(node_t *np, uint64_t *value, int flags) ++{ ++ int ltype, rtype, do_signed = 0; ++ ++ /* There must be two operands ++ */ ++ if (!np->right || !np->left) { ++ set_eval_error(E_MISSING_OPERAND); ++ error_token = np->tok_ptr; ++ return(-1); ++ } ++ ++ if (np->right->node_type == OPERATOR) { ++ replace(np->right, flags); ++ if (eval_error) { ++ return(-1); ++ } ++ } ++ ++ ltype = np->left->node_type; ++ rtype = np->right->node_type; ++ if ((ltype == TYPE_DEF) || (ltype == VADDR)) { ++ if ((rtype == TYPE_DEF) || (rtype == VADDR)) { ++ set_eval_error(E_NO_VALUE); ++ error_token = np->tok_ptr; ++ return(-1); ++ } ++ if (check_unsigned(np->left)) { ++ np->flags |= UNSIGNED_FLAG; ++ } else { ++ do_signed++; ++ } ++ if (!type_to_number(np->left)) { ++ return(pointer_math(np, value, -1, flags)); ++ } ++ np->byte_size = np->left->byte_size; ++ } else if ((rtype == TYPE_DEF) || (rtype == VADDR)) { ++ if ((ltype == TYPE_DEF) || (ltype == VADDR)) { ++ error_token = np->tok_ptr; ++ set_eval_error(E_NO_VALUE); ++ return(-1); ++ } ++ if (check_unsigned(np->right)) { ++ np->flags |= UNSIGNED_FLAG; ++ } else { ++ do_signed++; ++ } ++ if (!type_to_number(np->right)) { ++ return(pointer_math(np, value, 1, flags)); ++ } ++ np->byte_size = np->right->byte_size; ++ } else if ((np->left->flags & UNSIGNED_FLAG) || ++ (np->right->flags & UNSIGNED_FLAG)) { ++ np->flags |= UNSIGNED_FLAG; ++ } else { ++ do_signed++; ++ } ++ ++ if (do_signed) { ++ switch (np->operator) { ++ case ADD : ++ *value = (int64_t)np->left->value + ++ (int64_t)np->right->value; ++ break; ++ ++ case SUBTRACT : ++ *value = (int64_t)np->left->value - ++ (int64_t)np->right->value; ++ break; ++ ++ case MULTIPLY : ++ *value = (int64_t)np->left->value * ++ (int64_t)np->right->value; ++ break; ++ ++ case DIVIDE : ++ if ((int64_t)np->right->value == 0) { ++ set_eval_error(E_DIVIDE_BY_ZERO); ++ error_token = np->right->tok_ptr; ++ return(-1); ++ } ++ *value = (int64_t)np->left->value / ++ (int64_t)np->right->value; ++ break; ++ ++ case BITWISE_OR : ++ *value = (int64_t)np->left->value | ++ (int64_t)np->right->value; ++ break; ++ ++ case BITWISE_AND : ++ *value = (int64_t)np->left->value & ++ (int64_t)np->right->value; ++ break; ++ ++ case MODULUS : ++ if ((int64_t)np->right->value == 0) { ++ set_eval_error(E_DIVIDE_BY_ZERO); ++ error_token = np->right->tok_ptr; ++ return(-1); ++ } ++ *value = (int64_t)np->left->value % ++ (int64_t)np->right->value; ++ break; ++ ++ case RIGHT_SHIFT : ++ *value = ++ (int64_t)np->left->value >> ++ (int64_t)np->right->value; ++ break; ++ ++ case LEFT_SHIFT : ++ *value = ++ (int64_t)np->left->value << ++ (int64_t)np->right->value; ++ break; ++ ++ case LOGICAL_OR : ++ if ((int64_t)np->left->value || ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case LOGICAL_AND : ++ if ((int64_t)np->left->value && ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case EQUAL : ++ if ((int64_t)np->left->value == ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case NOT_EQUAL : ++ if ((int64_t)np->left->value != ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case LESS_THAN : ++ if ((int64_t)np->left->value < ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case GREATER_THAN : ++ if ((int64_t)np->left->value > ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case LESS_THAN_OR_EQUAL : ++ if ((int64_t)np->left->value <= ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case GREATER_THAN_OR_EQUAL : ++ if ((int64_t)np->left->value >= ++ (int64_t)np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ default : ++ break; ++ } ++ } else { ++ switch (np->operator) { ++ case ADD : ++ *value = np->left->value + np->right->value; ++ break; ++ ++ case SUBTRACT : ++ *value = np->left->value - np->right->value; ++ break; ++ ++ case MULTIPLY : ++ *value = np->left->value * np->right->value; ++ break; ++ ++ case DIVIDE : ++ *value = np->left->value / np->right->value; ++ break; ++ ++ case BITWISE_OR : ++ *value = np->left->value | np->right->value; ++ break; ++ ++ case BITWISE_AND : ++ *value = np->left->value & np->right->value; ++ break; ++ ++ case MODULUS : ++ *value = np->left->value % np->right->value; ++ break; ++ ++ case RIGHT_SHIFT : ++ *value = np->left->value >> np->right->value; ++ break; ++ ++ case LEFT_SHIFT : ++ *value = np->left->value << np->right->value; ++ break; ++ ++ case LOGICAL_OR : ++ if (np->left->value || np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case LOGICAL_AND : ++ if (np->left->value && np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case EQUAL : ++ if (np->left->value == np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case NOT_EQUAL : ++ if (np->left->value != np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case LESS_THAN : ++ if (np->left->value < np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case GREATER_THAN : ++ if (np->left->value > np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case LESS_THAN_OR_EQUAL : ++ if (np->left->value <= np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ case GREATER_THAN_OR_EQUAL : ++ if (np->left->value >= np->right->value) { ++ *value = 1; ++ } else { ++ *value = 0; ++ } ++ logical_flag++; ++ break; ++ ++ default : ++ break; ++ } ++ } ++ return(0); ++} ++ ++/* ++ * member_to_type() ++ */ ++static type_t * ++member_to_type(kltype_t *kltp, int flags) ++{ ++ kltype_t *rkltp; ++ type_t *tp, *head = (type_t *)NULL, *last = (type_t *)NULL; ++ ++ /* Make sure this is a member ++ */ ++ if (kltp->kl_type != KLT_MEMBER) { ++ return((type_t *)NULL); ++ } ++ ++ rkltp = kltp->kl_realtype; ++ while (rkltp && rkltp->kl_type == KLT_POINTER) { ++ tp = (type_t *)kl_alloc_block(sizeof(type_t)); ++ tp->flag = POINTER_FLAG; ++ if (last) { ++ last->t_next = tp; ++ last = tp; ++ } else { ++ head = last = tp; ++ } ++ rkltp = rkltp->kl_realtype; ++ } ++ ++ /* If We step past all the pointer records and don't point ++ * at anything, this must be a void pointer. Setup a VOID ++ * type struct so that we can maintain a pointer to some ++ * type info. ++ */ ++ if (!rkltp) { ++ tp = (type_t *)kl_alloc_block(sizeof(type_t)); ++ tp->flag = VOID_FLAG; ++ tp->t_kltp = kltp; ++ if (last) { ++ last->t_next = tp; ++ last = tp; ++ } else { ++ head = last = tp; ++ } ++ return(head); ++ } ++ ++ tp = (type_t *)kl_alloc_block(sizeof(type_t)); ++ tp->flag = KLTYPE_FLAG; ++ tp->t_kltp = kltp; ++ if (last) { ++ last->t_next = tp; ++ } else { ++ head = tp; ++ } ++ return(head); ++} ++ ++/* ++ * replace() -- ++ * ++ * Replace the tree with a node containing the numerical result of ++ * the equation. If pointer math is performed, the result will have ++ * the same type as the pointer. ++ */ ++static node_t * ++replace(node_t *np, int flags) ++{ ++ int offset; ++ uint64_t value; ++ node_t *q; ++ ++ if (!np) { ++ return((node_t *)NULL); ++ } ++ ++ if (np->node_type == OPERATOR) { ++ if (!(q = np->left)) { ++ return((node_t *)NULL); ++ } ++ while (q) { ++ if (!replace(q, flags)) { ++ return((node_t *)NULL); ++ } ++ q = q->right; ++ } ++ ++ if ((np->operator == RIGHT_ARROW) || (np->operator == DOT)) { ++ kaddr_t addr = 0; ++ type_t *tp; ++ ++ if (!have_debug_file) { ++ kdb_printf("no debuginfo file\n"); ++ return 0; ++ } ++ ++ /* The left node must point to a TYPE_DEF ++ */ ++ if (np->left->node_type != TYPE_DEF) { ++ if (np->left->flags & NOTYPE_FLAG) { ++ set_eval_error(E_NOTYPE); ++ error_token = np->left->tok_ptr; ++ } else { ++ set_eval_error(E_BAD_TYPE); ++ error_token = np->left->tok_ptr; ++ } ++ return((node_t *)NULL); ++ } ++ ++ /* Get the type information. Check to see if we ++ * have a pointer to a type. If we do, we need ++ * to strip off the pointer and get the type info. ++ */ ++ if (np->left->type->flag == POINTER_FLAG) { ++ tp = np->left->type->t_next; ++ kl_free_block((void *)np->left->type); ++ } else { ++ tp = np->left->type; ++ } ++ ++ /* We need to zero out the left child's type pointer ++ * to prevent the type structs from being prematurely ++ * freed (upon success). We have to remember, however, ++ * to the free the type information before we return. ++ */ ++ np->left->type = (type_t*)NULL; ++ ++ /* tp should now point at a type_t struct that ++ * references a kltype_t struct. If it points ++ * to anything else, return failure. ++ * ++ */ ++ if (tp->flag != KLTYPE_FLAG) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = np->left->tok_ptr; ++ free_type(tp); ++ return((node_t *)NULL); ++ } ++ ++ switch (tp->flag) { ++ case KLTYPE_FLAG: { ++ /* Make sure that the type referenced ++ * is a struct, union, or pointer to ++ * a struct or union. If it isn't one ++ * of these, then return failure. ++ */ ++ kltype_t *kltp, *kltmp; ++ ++ kltp = kl_realtype(tp->t_kltp, 0); ++ if ((kltp->kl_type != KLT_STRUCT) && ++ (kltp->kl_type != KLT_UNION)) { ++ error_token = ++ np->left->tok_ptr; ++ set_eval_error(E_BAD_TYPE); ++ free_type(tp); ++ return((node_t *)NULL); ++ } ++ ++ /* Get type information for member. ++ * If member is a pointer to a type, ++ * get the pointer address and load ++ * it into value. In any event, load ++ * the struct/union address plus the ++ * offset of the member. ++ */ ++ kltmp = kl_get_member(kltp, ++ np->right->name); ++ if (!kltmp) { ++ set_eval_error(E_BAD_MEMBER); ++ error_token = ++ np->right->tok_ptr; ++ free_type(tp); ++ return((node_t *)NULL); ++ } ++ ++ /* We can't just use the offset value ++ * for the member. That's because it ++ * may be from an anonymous struct or ++ * union within another struct ++ * definition. ++ */ ++ offset = kl_get_member_offset(kltp, ++ np->right->name); ++ np->type = member_to_type(kltmp, flags); ++ if (!np->type) { ++ set_eval_error(E_BAD_MEMBER); ++ error_token = ++ np->right->tok_ptr; ++ free_type(tp); ++ return((node_t *)NULL); ++ } ++ ++ /* Now free the struct type information ++ */ ++ free_type(tp); ++ np->node_type = TYPE_DEF; ++ np->flags |= KLTYPE_FLAG; ++ np->operator = 0; ++ addr = 0; ++ if (np->left->flags & POINTER_FLAG) { ++ addr = np->left->value + ++ offset; ++ } else if (np->left->flags & ++ ADDRESS_FLAG) { ++ addr = np->left->address + ++ offset; ++ } ++ if (addr) { ++ np->address = addr; ++ np->flags |= ADDRESS_FLAG; ++ } ++ ++ if (np->type->flag == POINTER_FLAG) { ++ np->flags |= POINTER_FLAG; ++ np->value = *((kaddr_t *)addr); ++ } else { ++ np->value = addr; ++ } ++ break; ++ } ++ } ++ free_nodes(np->left); ++ free_nodes(np->right); ++ np->left = np->right = (node_t*)NULL; ++ return(np); ++ } else { ++ if (!np->left || !np->right) { ++ set_eval_error(E_MISSING_OPERAND); ++ error_token = np->tok_ptr; ++ return((node_t *)NULL); ++ } ++ if (np->left->byte_size && np->right->byte_size) { ++ if (np->left->byte_size > ++ np->right->byte_size) { ++ ++ /* Left byte_size is greater than right ++ */ ++ np->byte_size = np->left->byte_size; ++ np->type = np->left->type; ++ np->flags = np->left->flags; ++ free_type(np->right->type); ++ } else if (np->left->byte_size < ++ np->right->byte_size) { ++ ++ /* Right byte_size is greater than left ++ */ ++ np->byte_size = np->right->byte_size; ++ np->type = np->right->type; ++ np->flags = np->right->flags; ++ free_type(np->left->type); ++ } else { ++ ++ /* Left and right byte_size is equal ++ */ ++ if (np->left->flags & UNSIGNED_FLAG) { ++ np->byte_size = ++ np->left->byte_size; ++ np->type = np->left->type; ++ np->flags = np->left->flags; ++ free_type(np->right->type); ++ } else if (np->right->flags & ++ UNSIGNED_FLAG) { ++ np->byte_size = ++ np->right->byte_size; ++ np->type = np->right->type; ++ np->flags = np->right->flags; ++ free_type(np->left->type); ++ } else { ++ np->byte_size = ++ np->left->byte_size; ++ np->type = np->left->type; ++ np->flags = np->left->flags; ++ free_type(np->right->type); ++ } ++ } ++ } else if (np->left->byte_size) { ++ np->byte_size = np->left->byte_size; ++ np->type = np->left->type; ++ np->flags = np->left->flags; ++ free_type(np->right->type); ++ } else if (np->right->byte_size) { ++ np->byte_size = np->right->byte_size; ++ np->type = np->right->type; ++ np->flags = np->right->flags; ++ } else { ++ /* XXX - No byte sizes ++ */ ++ } ++ ++ if (apply(np, &value, flags)) { ++ return((node_t *)NULL); ++ } ++ } ++ np->right->type = np->left->type = (type_t*)NULL; ++ ++ /* Flesh out the rest of the node struct. ++ */ ++ if (np->type) { ++ np->node_type = TYPE_DEF; ++ np->flags |= KLTYPE_FLAG; ++ } else { ++ np->node_type = NUMBER; ++ np->flags &= ~(KLTYPE_FLAG); ++ } ++ np->operator = 0; ++ np->value = value; ++ kl_free_block((void *)np->left); ++ kl_free_block((void *)np->right); ++ np->left = np->right = (node_t*)NULL; ++ } ++ return(np); ++} ++ ++/* ++ * replace_cast() ++ */ ++static int ++replace_cast(node_t *n, int flags) ++{ ++ type_t *t; ++ ++ if (!n) { ++ set_eval_error(E_SYNTAX_ERROR); ++ return(-1); ++ } else if (!n->right) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n->tok_ptr; ++ return(-1); ++ } ++ if (n->flags & POINTER_FLAG) { ++ if (n->right->node_type == VADDR) { ++ if (n->right->flags & ADDRESS_FLAG) { ++ n->value = n->right->address; ++ } else { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ } else { ++ n->value = n->right->value; ++ n->address = 0; ++ } ++ } else if (n->right->flags & ADDRESS_FLAG) { ++ n->flags |= ADDRESS_FLAG; ++ n->address = n->right->address; ++ n->value = n->right->value; ++ } else { ++ kltype_t *kltp; ++ ++ if (!(t = eval_type(n))) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->tok_ptr; ++ return(-1); ++ } ++ if (t->t_kltp->kl_type != KLT_BASE) { ++ ++ kltp = kl_realtype(t->t_kltp, 0); ++ if (kltp->kl_type != KLT_BASE) { ++ set_eval_error(E_BAD_CAST); ++ error_token = n->tok_ptr; ++ return(-1); ++ } ++ } ++ n->value = n->right->value; ++ n->type = t; ++ } ++ n->node_type = TYPE_DEF; ++ n->operator = 0; ++ free_node(n->right); ++ n->right = (node_t *)NULL; ++ return(0); ++} ++ ++/* ++ * replace_indirection() ++ */ ++static int ++replace_indirection(node_t *n, int flags) ++{ ++ kaddr_t addr; ++ type_t *t, *tp, *rtp; ++ ++ /* Make sure there is a right child and that it is a TYPE_DEF. ++ */ ++ if (!n->right) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->tok_ptr; ++ return(-1); ++ } else if (n->right->node_type != TYPE_DEF) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ /* Make sure the right node contains a pointer or address value. ++ * Note that it's possible for the whatis command to generate ++ * this case without any actual pointer/address value. ++ */ ++ if (!(n->right->flags & (POINTER_FLAG|ADDRESS_FLAG))) { ++ set_eval_error(E_BAD_POINTER); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ /* Get the pointer to the first type struct and make sure ++ * it's a pointer. ++ */ ++ if (!(tp = n->right->type) || (tp->flag != POINTER_FLAG)) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ /* Make sure we have a pointer to a type structure. ++ */ ++ if (!(n->right->flags & KLTYPE_FLAG)) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ n->node_type = TYPE_DEF; ++ n->flags = KLTYPE_FLAG; ++ n->operator = 0; ++ ++ if (!(t = tp->t_next)) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ if (!(rtp = eval_type(n->right))) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ ++ /* Zero out the type field in the right child so ++ * it wont accidently be freed when the right child ++ * is freed (upon success). ++ */ ++ n->right->type = (type_t*)NULL; ++ ++ n->type = t; ++ ++ /* Free the pointer struct ++ */ ++ kl_free_block((void *)tp); ++ ++ /* Get the pointer address ++ */ ++ addr = n->address = n->right->value; ++ n->flags |= ADDRESS_FLAG; ++ ++ if (rtp->t_kltp->kl_type == KLT_MEMBER) { ++ /* If this is a member, we have to step over the KLT_MEMBER ++ * struct and then make sure we have a KLT_POINTER struct. ++ * If we do, we step over it too...otherwise return an ++ * error. ++ */ ++ if (rtp->t_kltp->kl_realtype->kl_type != KLT_POINTER) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ rtp->t_kltp = rtp->t_kltp->kl_realtype; ++ } ++ ++ if (rtp->t_kltp->kl_type == KLT_POINTER) { ++ /* Strip off the pointer type record so that ++ * we pick up the actual type definition with ++ * our indirection. ++ */ ++ rtp->t_kltp = rtp->t_kltp->kl_realtype; ++ if (rtp->t_kltp->kl_name && ++ !strcmp(rtp->t_kltp->kl_name, "char")) { ++ n->flags |= STRING_FLAG; ++ } ++ } ++ ++ ++ /* If this is a pointer to a pointer, get the next ++ * pointer value. ++ */ ++ if (n->type->flag == POINTER_FLAG) { ++ n->value = *((kaddr_t *)addr); ++ ++ /* Set the appropriate node flag values ++ */ ++ n->flags |= POINTER_FLAG; ++ free_node(n->right); ++ n->left = n->right = (node_t *)NULL; ++ return(0); ++ } ++ /* Zero out the type field in the right child so it doesn't ++ * accidently get freed up when the right child is freed ++ * (upon success). ++ */ ++ n->right->type = (type_t*)NULL; ++ free_node(n->right); ++ n->left = n->right = (node_t *)NULL; ++ return(0); ++} ++ ++/* ++ * replace_unary() ++ * ++ * Convert a unary operator node that contains a pointer to a value ++ * with a node containing the numerical result. Free the node that ++ * originally contained the value. ++ */ ++static int ++replace_unary(node_t *n, int flags) ++{ ++ uint64_t value; ++ ++ if (!n->right) { ++ set_eval_error(E_MISSING_OPERAND); ++ error_token = n->tok_ptr; ++ return(-1); ++ } ++ if (is_unary(n->right->operator)) { ++ if (replace_unary(n->right, flags) == -1) { ++ return(-1); ++ } ++ } ++ if (n->operator == CAST) { ++ return(replace_cast(n, flags)); ++ } else if (n->operator == INDIRECTION) { ++ return(replace_indirection(n, flags)); ++ } else if (n->operator == ADDRESS) { ++ type_t *t; ++ ++ if (n->right->node_type == TYPE_DEF) { ++ if (!(n->right->flags & ADDRESS_FLAG)) { ++ set_eval_error(E_NO_ADDRESS); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ t = n->right->type; ++ } else { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->right->tok_ptr; ++ return(-1); ++ } ++ n->type = (type_t*)kl_alloc_block(sizeof(type_t)); ++ n->type->flag = POINTER_FLAG; ++ n->type->t_next = t; ++ n->node_type = TYPE_DEF; ++ n->operator = 0; ++ n->value = n->right->address; ++ n->flags = POINTER_FLAG; ++ if (!(t = eval_type(n))) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = n->tok_ptr; ++ return(-1); ++ } ++ n->flags |= t->flag; ++ n->right->type = 0; ++ free_nodes(n->right); ++ n->left = n->right = (node_t *)NULL; ++ return(0); ++ } else if (apply_unary(n, &value) == -1) { ++ return(-1); ++ } ++ free_nodes(n->right); ++ n->node_type = NUMBER; ++ n->operator = 0; ++ n->left = n->right = (node_t *)NULL; ++ memcpy(&n->value, &value, sizeof(uint64_t)); ++ return(0); ++} ++ ++/* ++ * pointer_to_element() ++ */ ++static void ++pointer_to_element(node_t *n0, node_t *n1) ++{ ++ int size; ++ kltype_t *kltp, *rkltp; ++ type_t *tp; ++ ++ if (!(tp = n0->type)) { ++ set_eval_error(E_BAD_INDEX); ++ error_token = n0->tok_ptr; ++ return; ++ } ++ if (tp->t_next->flag == POINTER_FLAG) { ++ size = sizeof(void *); ++ } else { ++ kltp = tp->t_next->t_kltp; ++ if (!(rkltp = kl_realtype(kltp, 0))) { ++ set_eval_error(E_BAD_INDEX); ++ error_token = n0->tok_ptr; ++ return; ++ } ++ size = rkltp->kl_size; ++ } ++ ++ /* Get the details on the array element ++ */ ++ n0->flags |= ADDRESS_FLAG; ++ n0->address = n0->value + (n1->value * size); ++ n0->type = tp->t_next; ++ kl_free_block((char *)tp); ++ if (tp->t_next->flag == POINTER_FLAG) { ++ n0->flags |= POINTER_FLAG; ++ n0->value = *((kaddr_t *)n0->address); ++ } else { ++ n0->flags &= (~POINTER_FLAG); ++ n0->value = 0; ++ } ++} ++ ++/* ++ * array_to_element() ++ */ ++static void ++array_to_element(node_t *n0, node_t *n1) ++{ ++ kltype_t *kltp, *rkltp, *ip, *ep; ++ type_t *tp, *troot = (type_t *)NULL; ++ ++ if (!(tp = n0->type)) { ++ set_eval_error(E_BAD_INDEX); ++ error_token = n0->tok_ptr; ++ return; ++ } ++ ++ /* If we are indexing a pointer, then make a call to the ++ * pointer_to_element() and return. ++ */ ++ if (tp->flag == POINTER_FLAG) { ++ return(pointer_to_element(n0, n1)); ++ } ++ ++ if (!(kltp = n0->type->t_kltp)) { ++ set_eval_error(E_BAD_INDEX); ++ error_token = n0->tok_ptr; ++ return; ++ } ++ if (!(rkltp = kl_realtype(kltp, KLT_ARRAY))) { ++ set_eval_error(E_BAD_INDEX); ++ error_token = n0->tok_ptr; ++ return; ++ } ++ ip = rkltp->kl_indextype; ++ ep = rkltp->kl_elementtype; ++ if (!ip || !ep) { ++ set_eval_error(E_BAD_INDEX); ++ error_token = n1->tok_ptr; ++ return; ++ } ++ /* Get the details on the array element ++ */ ++ n0->address = n0->address + (n1->value * ep->kl_size); ++ if (ep->kl_type == KLT_POINTER) { ++ n0->flags |= POINTER_FLAG; ++ n0->value = *((kaddr_t *)n0->address); ++ } else { ++ n0->value = 0; ++ } ++ n0->flags |= ADDRESS_FLAG; ++ kltp = ep; ++ while (kltp->kl_type == KLT_POINTER) { ++ if (troot) { ++ tp->t_next = (type_t*)kl_alloc_block(sizeof(type_t)); ++ tp = tp->t_next; ++ } else { ++ tp = (type_t*)kl_alloc_block(sizeof(type_t)); ++ troot = tp; ++ } ++ tp->flag = POINTER_FLAG; ++ kltp = kltp->kl_realtype; ++ } ++ if (troot) { ++ tp->t_next = (type_t*)kl_alloc_block(sizeof(type_t)); ++ tp = tp->t_next; ++ n0->type = troot; ++ } else { ++ tp = (type_t*)kl_alloc_block(sizeof(type_t)); ++ n0->type = tp; ++ } ++ tp->flag = KLTYPE_FLAG; ++ tp->t_kltp = ep; ++} ++ ++/* ++ * number_to_size() ++ */ ++int ++number_to_size(node_t *np) ++{ ++ int unsigned_flag = 0; ++ ++ if (np->node_type != NUMBER) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ if (np->flags & UNSIGNED_FLAG) { ++ unsigned_flag = 1; ++ } ++ if ((np->value >= 0) && (np->value <= 0xffffffff)) { ++ return(4); ++ } else if (((np->value >> 32) & 0xffffffff) == 0xffffffff) { ++ if (unsigned_flag) { ++ return(8); ++ } else if (sizeof(void *) == 4) { ++ return(4); ++ } else { ++ return(8); ++ } ++ } ++ return(8); ++} ++ ++/* ++ * number_to_type() ++ */ ++kltype_t * ++number_to_type(node_t *np) ++{ ++ int unsigned_flag = 0; ++ kltype_t *kltp, *rkltp = (kltype_t *)NULL; ++ ++ if (np->node_type != NUMBER) { ++ set_eval_error(E_BAD_TYPE); ++ error_token = np->tok_ptr; ++ return((kltype_t *)NULL); ++ } ++ if (np->flags & UNSIGNED_FLAG) { ++ unsigned_flag = 1; ++ } ++ if ((np->value >= 0) && (np->value <= 0xffffffff)) { ++ if (unsigned_flag) { ++ kltp = kl_find_type("uint32_t", KLT_TYPEDEF); ++ } else { ++ kltp = kl_find_type("int32_t", KLT_TYPEDEF); ++ } ++ } else if (((np->value >> 32) & 0xffffffff) == 0xffffffff) { ++ if (unsigned_flag) { ++ kltp = kl_find_type("uint64_t", KLT_TYPEDEF); ++ } else if (sizeof(void *) == 4) { ++ kltp = kl_find_type("int32_t", KLT_TYPEDEF); ++ } else { ++ kltp = kl_find_type("int64_t", KLT_TYPEDEF); ++ } ++ } else { ++ if (unsigned_flag) { ++ kltp = kl_find_type("uint64_t", KLT_TYPEDEF); ++ } else { ++ kltp = kl_find_type("int64_t", KLT_TYPEDEF); ++ } ++ } ++ if (kltp) { ++ if (!(rkltp = kl_realtype(kltp, 0))) { ++ rkltp = kltp; ++ } ++ } else { ++ set_eval_error(E_BAD_TYPE); ++ error_token = np->tok_ptr; ++ } ++ return(rkltp); ++} ++ ++/* ++ * type_to_number() ++ * ++ * Convert a base type to a numeric value. Return 1 on successful ++ * conversion, 0 if nothing was done. ++ */ ++static int ++type_to_number(node_t *np) ++{ ++ int byte_size, bit_offset, bit_size, encoding; ++ uint64_t value, value1; ++ kltype_t *kltp, *rkltp; ++ ++ /* Sanity check... ++ */ ++ if (np->node_type != TYPE_DEF) { ++ set_eval_error(E_NOTYPE); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ if (!np->type) { ++ set_eval_error(E_NOTYPE); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ if (np->type->flag == POINTER_FLAG) { ++ return(0); ++ } ++ ++ /* Get the real type record and make sure that it is ++ * for a base type. ++ */ ++ kltp = np->type->t_kltp; ++ rkltp = kl_realtype(kltp, 0); ++ if (rkltp->kl_type != KLT_BASE) { ++ set_eval_error(E_NOTYPE); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ ++ byte_size = rkltp->kl_size; ++ bit_offset = rkltp->kl_bit_offset; ++ if (!(bit_size = rkltp->kl_bit_size)) { ++ bit_size = byte_size * 8; ++ } ++ encoding = rkltp->kl_encoding; ++ if (np->flags & ADDRESS_FLAG) { ++ /* FIXME: untested */ ++ if (invalid_address(np->address, byte_size)) { ++ kdb_printf("ILLEGAL ADDRESS (%lx)", ++ (uaddr_t)np->address); ++ return (0); ++ } ++ kl_get_block(np->address, byte_size,(void *)&value1,(void *)0); ++ } else { ++ value1 = np->value; ++ } ++ value = kl_get_bit_value(&value1, byte_size, bit_size, bit_offset); ++ switch (byte_size) { ++ ++ case 1 : ++ if (encoding == ENC_UNSIGNED) { ++ np->value = (unsigned char)value; ++ np->flags |= UNSIGNED_FLAG; ++ } else if (encoding == ENC_SIGNED) { ++ np->value = (signed char)value; ++ } else { ++ np->value = (char)value; ++ } ++ break; ++ ++ case 2 : ++ if (encoding == ENC_UNSIGNED) { ++ np->value = (uint16_t)value; ++ np->flags |= UNSIGNED_FLAG; ++ } else { ++ np->value = (int16_t)value; ++ } ++ break; ++ ++ case 4 : ++ if (encoding == ENC_UNSIGNED) { ++ np->value = (uint32_t)value; ++ np->flags |= UNSIGNED_FLAG; ++ } else { ++ np->value = (int32_t)value; ++ } ++ break; ++ ++ case 8 : ++ if (encoding == ENC_UNSIGNED) { ++ np->value = (uint64_t)value; ++ np->flags |= UNSIGNED_FLAG; ++ } else { ++ np->value = (int64_t)value; ++ } ++ break; ++ ++ default : ++ set_eval_error(E_BAD_TYPE); ++ error_token = np->tok_ptr; ++ return(0); ++ } ++ np->byte_size = byte_size; ++ np->node_type = NUMBER; ++ return(1); ++} ++ ++/* ++ * eval_type() ++ */ ++static type_t * ++eval_type(node_t *n) ++{ ++ type_t *t; ++ ++ if (!(t = n->type)) { ++ return((type_t*)NULL); ++ } ++ while (t->flag == POINTER_FLAG) { ++ t = t->t_next; ++ ++ /* If for some reason, there is no type pointer (this shouldn't ++ * happen but...), we have to make sure that we don't try to ++ * reference a NULL pointer and get a SEGV. Return an error if ++ * 't' is NULL. ++ */ ++ if (!t) { ++ return((type_t*)NULL); ++ } ++ } ++ if (t->flag == KLTYPE_FLAG) { ++ return (t); ++ } ++ return((type_t*)NULL); ++} ++ ++/* ++ * expand_variables() ++ */ ++static char * ++expand_variables(char *exp, int flags) ++{ ++ return((char *)NULL); ++} ++ ++/* ++ * eval() ++ */ ++node_t * ++eval(char **exp, int flags) ++{ ++ token_t *tok; ++ node_t *n, *root; ++ char *e, *s; ++ ++ eval_error = 0; ++ logical_flag = 0; ++ ++ /* Make sure there is an expression to evaluate ++ */ ++ if (!(*exp)) { ++ return ((node_t*)NULL); ++ } ++ ++ /* Expand any variables that are in the expression string. If ++ * a new string is allocated by the expand_variables() function, ++ * we need to make sure the original expression string gets ++ * freed. In any event, point s at the current expression string ++ * so that it gets freed up when we are done. ++ */ ++ if ((e = expand_variables(*exp, 0))) { ++ kl_free_block((void *)*exp); ++ *exp = e; ++ } else if (eval_error) { ++ eval_error |= E_BAD_EVAR; ++ error_token = *exp; ++ } ++ s = *exp; ++ tok = get_token_list(s); ++ if (eval_error) { ++ return((node_t*)NULL); ++ } ++ ++ /* Get the node_list and evaluate the expression. ++ */ ++ node_list = get_node_list(tok, flags); ++ if (eval_error) { ++ free_nodelist(node_list); ++ node_list = (node_t*)NULL; ++ free_tokens(tok); ++ return((node_t*)NULL); ++ } ++ if (!(n = do_eval(flags))) { ++ if (!eval_error) { ++ set_eval_error(E_SYNTAX_ERROR); ++ error_token = s + strlen(s) - 1; ++ } ++ free_nodes(n); ++ free_tokens(tok); ++ return((node_t*)NULL); ++ } ++ ++ if (!(root = replace(n, flags))) { ++ if (eval_error) { ++ free_nodes(n); ++ free_tokens(tok); ++ return((node_t*)NULL); ++ } ++ root = n; ++ } ++ ++ /* Check to see if the the result should ++ * be interpreted as 'true' or 'false' ++ */ ++ if (logical_flag && ((root->value == 0) || (root->value == 1))) { ++ root->flags |= BOOLIAN_FLAG; ++ } ++ free_tokens(tok); ++ return(root); ++} ++ ++/* ++ * print_number() ++ */ ++void ++print_number(node_t *np, int flags) ++{ ++ int size; ++ unsigned long long value; ++ ++ if ((size = number_to_size(np)) && (size != sizeof(uint64_t))) { ++ value = np->value & (((uint64_t)1 << (uint64_t)(size*8))-1); ++ } else { ++ value = np->value; ++ } ++ if (flags & C_HEX) { ++ kdb_printf("0x%llx", value); ++ } else if (flags & C_BINARY) { ++ kdb_printf("0b"); ++ kl_binary_print(value); ++ } else { ++ if (np->flags & UNSIGNED_FLAG) { ++ kdb_printf("%llu", value); ++ } else { ++ kdb_printf("%lld", np->value); ++ } ++ } ++} ++ ++/* ++ * print_string() ++ */ ++void ++print_string(kaddr_t addr, int size) ++{ ++ int i; ++ char *str; ++ ++ if (!size) { ++ size = 255; ++ } ++ /* FIXME: untested */ ++ if (invalid_address(addr, size)) { ++ klib_error = KLE_INVALID_PADDR; ++ return; ++ } ++ str = (char*)kl_alloc_block(size); ++ kl_get_block(addr, size, (void *)str, (void *)0); ++ kdb_printf("\"%s", str); ++ for (i = 0; i < size; i++) { ++ if (!str[i]) { ++ break; ++ } ++ } ++ if (KL_ERROR || (i == size)) { ++ kdb_printf("..."); ++ } ++ kdb_printf("\""); ++ kl_free_block(str); ++} ++ ++/* ++ * kl_print_error() ++ */ ++void ++kl_print_error(void) ++{ ++ int ecode; ++ ++ ecode = klib_error & 0xffffffff; ++ switch(ecode) { ++ ++ /** General klib error codes ++ **/ ++ case KLE_NO_MEMORY: ++ kdb_printf("insufficient memory"); ++ break; ++ case KLE_OPEN_ERROR: ++ kdb_printf("unable to open file"); ++ break; ++ case KLE_ZERO_BLOCK: ++ kdb_printf("tried to allocate a zero-sized block"); ++ break; ++ case KLE_INVALID_VALUE: ++ kdb_printf("invalid input value"); ++ break; ++ case KLE_NULL_BUFF: ++ kdb_printf( "NULL buffer pointer"); ++ break; ++ case KLE_ZERO_SIZE: ++ kdb_printf("zero sized block requested"); ++ break; ++ case KLE_ACTIVE: ++ kdb_printf("operation not supported on a live system"); ++ break; ++ case KLE_UNSUPPORTED_ARCH: ++ kdb_printf("unsupported architecture"); ++ break; ++ case KLE_MISC_ERROR: ++ kdb_printf("KLIB error"); ++ break; ++ case KLE_NOT_SUPPORTED: ++ kdb_printf("operation not supported"); ++ break; ++ case KLE_UNKNOWN_ERROR: ++ kdb_printf("unknown error"); ++ break; ++ ++ /** memory error codes ++ **/ ++ case KLE_BAD_MAP_FILE: ++ kdb_printf("bad map file"); ++ break; ++ case KLE_BAD_DUMP: ++ kdb_printf("bad dump file"); ++ break; ++ case KLE_BAD_DUMPTYPE: ++ kdb_printf("bad dumptype"); ++ break; ++ case KLE_INVALID_LSEEK: ++ kdb_printf("lseek error"); ++ break; ++ case KLE_INVALID_READ: ++ kdb_printf("not found in dump file"); ++ break; ++ case KLE_BAD_KERNINFO: ++ kdb_printf("bad kerninfo struct"); ++ break; ++ case KLE_INVALID_PADDR: ++ kdb_printf("invalid physical address"); ++ break; ++ case KLE_INVALID_VADDR: ++ kdb_printf("invalid virtual address"); ++ break; ++ case KLE_INVALID_VADDR_ALIGN: ++ kdb_printf("invalid vaddr alignment"); ++ break; ++ case KLE_INVALID_MAPPING: ++ kdb_printf("invalid address mapping"); ++ break; ++ case KLE_PAGE_NOT_PRESENT: ++ kdb_printf("page not present"); ++ break; ++ case KLE_BAD_ELF_FILE: ++ kdb_printf("bad elf file"); ++ break; ++ case KLE_ARCHIVE_FILE: ++ kdb_printf("archive file"); ++ break; ++ case KLE_MAP_FILE_PRESENT: ++ kdb_printf("map file present"); ++ break; ++ case KLE_BAD_MAP_FILENAME: ++ kdb_printf("bad map filename"); ++ break; ++ case KLE_BAD_DUMP_FILENAME: ++ kdb_printf("bad dump filename"); ++ break; ++ case KLE_BAD_NAMELIST_FILE: ++ kdb_printf("bad namelist file"); ++ break; ++ case KLE_BAD_NAMELIST_FILENAME: ++ kdb_printf("bad namelist filename"); ++ break; ++ ++ /** symbol error codes ++ **/ ++ case KLE_NO_SYMTAB: ++ kdb_printf("no symtab"); ++ break; ++ case KLE_NO_SYMBOLS: ++ kdb_printf("no symbol information"); ++ break; ++ case KLE_NO_MODULE_LIST: ++ kdb_printf("kernel without module support"); ++ break; ++ ++ /** kernel data error codes ++ **/ ++ case KLE_INVALID_KERNELSTACK: ++ kdb_printf("invalid kernel stack"); ++ break; ++ case KLE_INVALID_STRUCT_SIZE: ++ kdb_printf("invalid struct size"); ++ break; ++ case KLE_BEFORE_RAM_OFFSET: ++ kdb_printf("physical address proceeds start of RAM"); ++ break; ++ case KLE_AFTER_MAXPFN: ++ kdb_printf("PFN exceeds maximum PFN"); ++ break; ++ case KLE_AFTER_PHYSMEM: ++ kdb_printf("address exceeds physical memory"); ++ break; ++ case KLE_AFTER_MAXMEM: ++ kdb_printf("address exceeds maximum physical address"); ++ break; ++ case KLE_PHYSMEM_NOT_INSTALLED: ++ kdb_printf("physical memory not installed"); ++ break; ++ case KLE_NO_DEFTASK: ++ kdb_printf("default task not set"); ++ break; ++ case KLE_PID_NOT_FOUND: ++ kdb_printf("PID not found"); ++ break; ++ case KLE_DEFTASK_NOT_ON_CPU: ++ kdb_printf("default task not running on a cpu"); ++ break; ++ case KLE_NO_CURCPU: ++ kdb_printf("current cpu could not be determined"); ++ break; ++ ++ case KLE_KERNEL_MAGIC_MISMATCH: ++ kdb_printf("kernel_magic mismatch " ++ "of map and memory image"); ++ break; ++ ++ case KLE_INVALID_DUMP_HEADER: ++ kdb_printf("invalid dump header in dump"); ++ break; ++ ++ case KLE_DUMP_INDEX_CREATION: ++ kdb_printf("cannot create index file"); ++ break; ++ ++ case KLE_DUMP_HEADER_ONLY: ++ kdb_printf("dump only has a dump header"); ++ break; ++ ++ case KLE_NO_END_SYMBOL: ++ kdb_printf("no _end symbol in kernel"); ++ break; ++ ++ case KLE_NO_CPU: ++ kdb_printf("CPU not installed"); ++ break; ++ ++ default: ++ break; ++ } ++ kdb_printf("\n"); ++} ++ ++/* ++ * kl_print_string() ++ * ++ * print out a string, translating all embeded control characters ++ * (e.g., '\n' for newline, '\t' for tab, etc.) ++ */ ++void ++kl_print_string(char *s) ++{ ++ char *sp, *cp; ++ ++ kl_reset_error(); ++ ++ if (!(sp = s)) { ++ klib_error = KLE_BAD_STRING; ++ return; ++ } ++ /* FIXME: untested */ ++ if (invalid_address((kaddr_t)sp, 1)) { ++ klib_error = KLE_INVALID_PADDR; ++ return; ++ } ++ ++ while (sp) { ++ if ((cp = strchr(sp, '\\'))) { ++ switch (*(cp + 1)) { ++ ++ case 'n' : ++ *cp++ = '\n'; ++ *cp++ = 0; ++ break; ++ ++ case 't' : ++ *cp++ = '\t'; ++ *cp++ = 0; ++ break; ++ ++ default : ++ if (*(cp + 1) == 0) { ++ klib_error = KLE_BAD_STRING; ++ return; ++ } ++ /* Change the '\' character to a zero ++ * and then print the string (the rest ++ * of the string will be picked ++ * up on the next pass). ++ */ ++ *cp++ = 0; ++ break; ++ } ++ kdb_printf("%s", sp); ++ sp = cp; ++ } else { ++ kdb_printf("%s", sp); ++ sp = 0; ++ } ++ } ++} ++ ++/* ++ * print_eval_results() ++ */ ++int ++print_eval_results(node_t *np, int flags) ++{ ++ int size, i, count, ptr_cnt = 0; ++ kaddr_t addr; ++ char *typestr; ++ kltype_t *kltp, *rkltp = NULL, *nkltp; ++ type_t *tp; ++ ++ /* Print the results ++ */ ++ switch (np->node_type) { ++ ++ case NUMBER: ++ print_number(np, flags); ++ break; ++ ++ case TYPE_DEF: { ++ ++ /* First, determine the number of levels of indirection ++ * by determining the number of pointer type records. ++ */ ++ if ((tp = np->type)) { ++ while (tp && (tp->flag == POINTER_FLAG)) { ++ ptr_cnt++; ++ tp = tp->t_next; ++ } ++ if (tp) { ++ rkltp = tp->t_kltp; ++ } ++ } ++ if (!rkltp) { ++ kdb_printf("Type information not available\n"); ++ return(1); ++ } ++ ++ if (ptr_cnt) { ++ ++ /* If this is a member, we need to get the ++ * first type record. ++ */ ++ if (rkltp->kl_type == KLT_MEMBER) { ++ /* We need to get down to the first ++ * real type record... ++ */ ++ rkltp = rkltp->kl_realtype; ++ } ++ ++ /* step over any KLT_POINTER type records. ++ */ ++ while (rkltp && rkltp->kl_type == KLT_POINTER) { ++ rkltp = rkltp->kl_realtype; ++ } ++ if (!rkltp) { ++ kdb_printf("Bad type information\n"); ++ return(1); ++ } ++ typestr = rkltp->kl_typestr; ++ if (rkltp->kl_type == KLT_FUNCTION) { ++ kdb_printf("%s(", typestr); ++ } else if (rkltp->kl_type == KLT_ARRAY) { ++ kdb_printf("(%s(", typestr); ++ } else { ++ kdb_printf("(%s", typestr); ++ } ++ for (i = 0; i < ptr_cnt; i++) { ++ kdb_printf("*"); ++ } ++ if (rkltp->kl_type == KLT_FUNCTION) { ++ kdb_printf(")("); ++ } else if (rkltp->kl_type == KLT_ARRAY) { ++ kdb_printf(")"); ++ ++ nkltp = rkltp; ++ while (nkltp->kl_type == KLT_ARRAY) { ++ count = nkltp->kl_high_bounds - ++ nkltp->kl_low_bounds + 1; ++ kdb_printf("[%d]", count); ++ nkltp = nkltp->kl_elementtype; ++ } ++ } ++ kdb_printf(") "); ++ kdb_printf("0x%llx", np->value); ++ ++ if (ptr_cnt > 1) { ++ break; ++ } ++ ++ if ((rkltp->kl_type == KLT_BASE) && ++ rkltp->kl_encoding == ENC_CHAR) { ++ kdb_printf(" = "); ++ print_string(np->value, 0); ++ } ++ break; ++ } ++ if (np->flags & KLTYPE_FLAG) { ++ void * ptr; ++ ++ /* Get the type information. It's possible ++ * that the type is a member. In which case, ++ * the size may only be from this record ++ * (which would be the casse if this is an ++ * array). We must check the original type ++ * record first, and try the realtype record ++ * if the value is zero. ++ */ ++ kltp = np->type->t_kltp; ++ ++ if (kltp->kl_type == KLT_MEMBER) { ++ rkltp = kltp->kl_realtype; ++ } else { ++ rkltp = kltp; ++ } ++ ++ /* Check to see if this is a typedef. If ++ * it is, then it might be a typedef for ++ * a pointer type. Don't walk to the last ++ * type record. ++ */ ++ while (rkltp->kl_type == KLT_TYPEDEF) { ++ rkltp = rkltp->kl_realtype; ++ } ++ ++ if (rkltp->kl_type == KLT_POINTER) { ++ kdb_printf("0x%llx", np->value); ++ break; ++ } ++ if((rkltp->kl_name != 0) && ++ !(strcmp(rkltp->kl_name, "void"))) { ++ /* we are about to dereference ++ * a void pointer. ++ */ ++ kdb_printf("Can't dereference a " ++ "generic pointer.\n"); ++ return(1); ++ } ++ ++ size = rkltp->kl_size; ++ if (!size || (size < 0)) { ++ size = kltp->kl_size; ++ } ++ ++ if(rkltp->kl_type==KLT_ARRAY) { ++ size = rkltp->kl_high_bounds - ++ rkltp->kl_low_bounds + 1; ++ if(rkltp->kl_elementtype == NULL){ ++ kdb_printf("Incomplete array" ++ " type.\n"); ++ return(1); ++ } ++ if(rkltp->kl_elementtype->kl_type == ++ KLT_POINTER){ ++ size *= sizeof(void *); ++ } else { ++ size *= rkltp->kl_elementtype->kl_size; ++ } ++ } ++ if(size){ ++ ptr = kl_alloc_block(size); ++ } else { ++ ptr = NULL; ++ } ++ if ((rkltp->kl_type == KLT_BASE) && ++ !(np->flags & ADDRESS_FLAG)) { ++ switch (size) { ++ case 1: ++ *(unsigned char *)ptr = ++ np->value; ++ break; ++ ++ case 2: ++ *(unsigned short *)ptr = ++ np->value; ++ break; ++ ++ case 4: ++ *(unsigned int *)ptr = ++ np->value; ++ break; ++ ++ case 8: ++ *(unsigned long long *) ++ ptr = np->value; ++ break; ++ } ++ kl_print_type(ptr, rkltp, 0, ++ flags|SUPPRESS_NAME); ++ kl_free_block(ptr); ++ return(1); ++ } ++ ++ if(size){ ++ addr = np->address; ++ if (invalid_address(addr, size)) { ++ kdb_printf ( ++ "invalid address %#lx\n", ++ addr); ++ return 1; ++ } ++ kl_get_block(addr, size, (void *)ptr, ++ (void *)0); ++ if (KL_ERROR) { ++ kl_print_error(); ++ kl_free_block(ptr); ++ return(1); ++ } ++ } ++ /* Print out the actual type ++ */ ++ switch (rkltp->kl_type) { ++ case KLT_STRUCT: ++ case KLT_UNION: ++ kl_print_type(ptr, rkltp, 0, ++ flags); ++ break; ++ ++ case KLT_ARRAY: ++ kl_print_type(ptr, rkltp, 0, ++ flags| SUPPRESS_NAME); ++ break; ++ ++ default: ++ kl_print_type(ptr, rkltp, 0, ++ (flags| ++ SUPPRESS_NAME| ++ SUPPRESS_NL)); ++ break; ++ } ++ if(ptr){ ++ kl_free_block(ptr); ++ } ++ } ++ break; ++ } ++ ++ case VADDR: ++ /* If we get here, there was no type info available. ++ * The ADDRESS_FLAG should be set (otherwise we ++ * would have returned an error). So, print out ++ * the address. ++ */ ++ kdb_printf("0x%lx", np->address); ++ break; ++ ++ default: ++ if (np->node_type == TEXT) { ++ kl_print_string(np->name); ++ if (KL_ERROR) { ++ kl_print_error(); ++ return(1); ++ } ++ } else if (np->node_type == CHARACTER) { ++ kdb_printf("\'%c\'", (char)np->value); ++ } ++ break; ++ } ++ return(0); ++} ++ ++/* ++ * print_eval_error() ++ */ ++void ++print_eval_error( ++ char *cmdname, ++ char *s, ++ char *bad_ptr, ++ uint64_t error, ++ int flags) ++{ ++ int i, cmd_len; ++ ++ kdb_printf("%s %s\n", cmdname, s); ++ cmd_len = strlen(cmdname); ++ ++ if (!bad_ptr) { ++ for (i = 0; i < (strlen(s) + cmd_len); i++) { ++ kdb_printf(" "); ++ } ++ } else { ++ for (i = 0; i < (bad_ptr - s + 1 + cmd_len); i++) { ++ kdb_printf(" "); ++ } ++ } ++ kdb_printf("^ "); ++ switch (error) { ++ case E_OPEN_PAREN : ++ kdb_printf("Too many open parenthesis\n"); ++ break; ++ ++ case E_CLOSE_PAREN : ++ kdb_printf("Too many close parenthesis\n"); ++ break; ++ ++ case E_BAD_STRUCTURE : ++ kdb_printf("Invalid structure\n"); ++ break; ++ ++ case E_MISSING_STRUCTURE : ++ kdb_printf("Missing structure\n"); ++ break; ++ ++ case E_BAD_MEMBER : ++ kdb_printf("No such member\n"); ++ break; ++ ++ case E_BAD_OPERATOR : ++ kdb_printf("Invalid operator\n"); ++ break; ++ ++ case E_MISSING_OPERAND : ++ kdb_printf("Missing operand\n"); ++ break; ++ ++ case E_BAD_OPERAND : ++ kdb_printf("Invalid operand\n"); ++ break; ++ ++ case E_BAD_TYPE : ++ kdb_printf("Invalid type\n"); ++ if (!have_debug_file) { ++ kdb_printf("no debuginfo file\n"); ++ return; ++ } ++ break; ++ ++ case E_NOTYPE : ++ kdb_printf("Could not find type information\n"); ++ break; ++ ++ case E_BAD_POINTER : ++ kdb_printf("Invalid pointer\n"); ++ break; ++ ++ case E_BAD_INDEX : ++ kdb_printf("Invalid array index\n"); ++ break; ++ ++ case E_BAD_CHAR : ++ kdb_printf("Invalid character value\n"); ++ break; ++ ++ case E_BAD_STRING : ++ kdb_printf("Non-termining string\n"); ++ break; ++ ++ case E_END_EXPECTED : ++ kdb_printf( ++ "Expected end of print statement\n"); ++ break; ++ ++ case E_BAD_EVAR : ++ kdb_printf("Invalid eval variable\n"); ++ break; ++ ++ case E_BAD_VALUE : ++ kdb_printf("Invalid value\n"); ++ break; ++ ++ case E_NO_VALUE : ++ kdb_printf("No value supplied\n"); ++ break; ++ ++ case E_DIVIDE_BY_ZERO : ++ kdb_printf("Divide by zero\n"); ++ break; ++ ++ case E_BAD_CAST : ++ kdb_printf("Invalid cast\n"); ++ break; ++ ++ case E_NO_ADDRESS : ++ kdb_printf("Not an address\n"); ++ break; ++ ++ case E_SINGLE_QUOTE : ++ kdb_printf("Missing single quote\n"); ++ break; ++ ++ case E_BAD_WHATIS : ++ kdb_printf("Invalid whatis Operation\n"); ++ break; ++ ++ case E_NOT_IMPLEMENTED : ++ kdb_printf("Not implemented\n"); ++ break; ++ ++ default : ++ kdb_printf("Syntax error\n"); ++ break; ++ } ++} ++ ++/* ++ * single_type() ++ */ ++void ++single_type(char *str) ++{ ++ char buffer[256], *type_name; ++ kltype_t *kltp; ++ syment_t *sp; ++ ++ type_name = buffer; ++ strcpy(type_name, str); ++ ++ if (have_debug_file) { ++ if ((kltp = kl_find_type(type_name, KLT_TYPE))) { ++ kl_print_type((void *)NULL, kltp, 0, C_SHOWOFFSET); ++ return; ++ } ++ if ((kltp = kl_find_type(type_name, KLT_TYPEDEF))) { ++ kdb_printf ("typedef %s:\n", type_name); ++ kl_print_type((void *)NULL, kltp, 0, C_SHOWOFFSET); ++ return; ++ } ++ } ++ if ((sp = kl_lkup_symname(type_name))) { ++ kdb_printf ("symbol %s value: %#lx\n", str, sp->s_addr); ++ kl_free_block((void *)sp); ++ return; ++ } ++ kdb_printf("could not find type or symbol information for %s\n", ++ type_name); ++ return; ++} ++ ++/* ++ * sizeof_type() ++ */ ++void ++sizeof_type(char *str) ++{ ++ char buffer[256], *type_name; ++ kltype_t *kltp; ++ ++ type_name = buffer; ++ strcpy(type_name, str); ++ ++ if ((kltp = kl_find_type(type_name, KLT_TYPE))) { ++ kdb_printf ("%s %d %#x\n", kltp->kl_typestr, ++ kltp->kl_size, kltp->kl_size); ++ return; ++ } ++ if ((kltp = kl_find_type(type_name, KLT_TYPEDEF))) { ++ kdb_printf ("%s %d %#x\n", kltp->kl_typestr, ++ kltp->kl_size, kltp->kl_size); ++ return; ++ } ++ kdb_printf("could not find type information for %s\n", type_name); ++} ++ ++EXPORT_SYMBOL(have_debug_file); ++EXPORT_SYMBOL(type_tree); ++EXPORT_SYMBOL(typedef_tree); ++ ++#if defined(CONFIG_X86_32) ++/* needed for i386: */ ++#include ++#include ++/* ++ * Generic C version of full 64 bit by 64 bit division ++ * ++ * 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. ++ * ++ * Code generated for this function might be very inefficient ++ * for some CPUs, can be overridden by linking arch-specific ++ * assembly versions such as arch/sparc/lib/udivdi.S ++ */ ++uint64_t ++__udivdi3(uint64_t dividend, uint64_t divisor) ++{ ++ uint32_t d = divisor; ++ /* Scale divisor to 32 bits */ ++ if (divisor > 0xffffffffULL) { ++ unsigned int shift = fls(divisor >> 32); ++ d = divisor >> shift; ++ dividend >>= shift; ++ } ++ /* avoid 64 bit division if possible */ ++ if (dividend >> 32) ++ do_div(dividend, d); ++ else ++ dividend = (uint32_t) dividend / d; ++ return dividend; ++} ++ ++int64_t ++__divdi3(int64_t dividend, int64_t divisor) ++{ ++ int32_t d = divisor; ++ /* Scale divisor to 32 bits */ ++ if (divisor > 0xffffffffLL) { ++ unsigned int shift = fls(divisor >> 32); ++ d = divisor >> shift; ++ dividend >>= shift; ++ } ++ /* avoid 64 bit division if possible */ ++ if (dividend >> 32) ++ do_div(dividend, d); ++ else ++ dividend = (int32_t) dividend / d; ++ return dividend; ++} ++ ++uint64_t ++__umoddi3(uint64_t dividend, uint64_t divisor) ++{ ++ return dividend - (__udivdi3(dividend, divisor) * divisor); ++} ++ ++int64_t ++__moddi3(int64_t dividend, int64_t divisor) ++{ ++ return dividend - (__divdi3(dividend, divisor) * divisor); ++} ++#endif /* CONFIG_x86_32 */ +--- /dev/null ++++ b/kdb/kdbmain.c +@@ -0,0 +1,4333 @@ ++/* ++ * Kernel Debugger Architecture Independent Main Code ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ * Copyright (C) 2000 Stephane Eranian ++ * Xscale (R) modifications copyright (C) 2003 Intel Corporation. ++ */ ++ ++/* ++ * Updated for Xscale (R) architecture support ++ * Eddie Dong 8 Jan 03 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(CONFIG_LKCD_DUMP) || defined(CONFIG_LKCD_DUMP_MODULE) ++#include ++#endif ++#include ++#include ++#ifdef CONFIG_KDB_KDUMP ++#include ++#endif ++ ++#include ++ ++#include ++#include ++#include ++#include ++char kdb_debug_info_filename[256] = {""}; ++EXPORT_SYMBOL(kdb_debug_info_filename); ++#define GREP_LEN 256 ++char kdb_grep_string[GREP_LEN]; ++int kdb_grepping_flag; ++EXPORT_SYMBOL(kdb_grepping_flag); ++int kdb_grep_leading; ++int kdb_grep_trailing; ++ ++/* ++ * Kernel debugger state flags ++ */ ++volatile int kdb_flags; ++atomic_t kdb_event; ++atomic_t kdb_8250; ++ ++/* ++ * kdb_lock protects updates to kdb_initial_cpu. Used to ++ * single thread processors through the kernel debugger. ++ */ ++static DEFINE_SPINLOCK(kdb_lock); ++volatile int kdb_initial_cpu = -1; /* cpu number that owns kdb */ ++int kdb_seqno = 2; /* how many times kdb has been entered */ ++ ++volatile int kdb_nextline = 1; ++static volatile int kdb_new_cpu; /* Which cpu to switch to */ ++ ++volatile int kdb_state[NR_CPUS]; /* Per cpu state */ ++ ++const struct task_struct *kdb_current_task; ++EXPORT_SYMBOL(kdb_current_task); ++struct pt_regs *kdb_current_regs; ++ ++#ifdef CONFIG_KDB_OFF ++int kdb_on = 0; /* Default is off */ ++#else ++int kdb_on = 1; /* Default is on */ ++#endif /* CONFIG_KDB_OFF */ ++ ++const char *kdb_diemsg; ++static int kdb_go_count; ++#ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC ++static unsigned int kdb_continue_catastrophic = CONFIG_KDB_CONTINUE_CATASTROPHIC; ++#else ++static unsigned int kdb_continue_catastrophic = 0; ++#endif ++ ++#ifdef kdba_setjmp ++ /* ++ * Must have a setjmp buffer per CPU. Switching cpus will ++ * cause the jump buffer to be setup for the new cpu, and ++ * subsequent switches (and pager aborts) will use the ++ * appropriate per-processor values. ++ */ ++kdb_jmp_buf *kdbjmpbuf; ++#endif /* kdba_setjmp */ ++ ++ /* ++ * kdb_commands describes the available commands. ++ */ ++static kdbtab_t *kdb_commands; ++static int kdb_max_commands; ++ ++typedef struct _kdbmsg { ++ int km_diag; /* kdb diagnostic */ ++ char *km_msg; /* Corresponding message text */ ++} kdbmsg_t; ++ ++#define KDBMSG(msgnum, text) \ ++ { KDB_##msgnum, text } ++ ++static kdbmsg_t kdbmsgs[] = { ++ KDBMSG(NOTFOUND,"Command Not Found"), ++ KDBMSG(ARGCOUNT, "Improper argument count, see usage."), ++ KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, 8 is only allowed on 64 bit systems"), ++ KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"), ++ KDBMSG(NOTENV, "Cannot find environment variable"), ++ KDBMSG(NOENVVALUE, "Environment variable should have value"), ++ KDBMSG(NOTIMP, "Command not implemented"), ++ KDBMSG(ENVFULL, "Environment full"), ++ KDBMSG(ENVBUFFULL, "Environment buffer full"), ++ KDBMSG(TOOMANYBPT, "Too many breakpoints defined"), ++#ifdef CONFIG_CPU_XSCALE ++ KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"), ++#else ++ KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"), ++#endif ++ KDBMSG(DUPBPT, "Duplicate breakpoint address"), ++ KDBMSG(BPTNOTFOUND, "Breakpoint not found"), ++ KDBMSG(BADMODE, "Invalid IDMODE"), ++ KDBMSG(BADINT, "Illegal numeric value"), ++ KDBMSG(INVADDRFMT, "Invalid symbolic address format"), ++ KDBMSG(BADREG, "Invalid register name"), ++ KDBMSG(BADCPUNUM, "Invalid cpu number"), ++ KDBMSG(BADLENGTH, "Invalid length field"), ++ KDBMSG(NOBP, "No Breakpoint exists"), ++ KDBMSG(BADADDR, "Invalid address"), ++}; ++#undef KDBMSG ++ ++static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t); ++ ++ ++/* ++ * Initial environment. This is all kept static and local to ++ * this file. We don't want to rely on the memory allocation ++ * mechanisms in the kernel, so we use a very limited allocate-only ++ * heap for new and altered environment variables. The entire ++ * environment is limited to a fixed number of entries (add more ++ * to __env[] if required) and a fixed amount of heap (add more to ++ * KDB_ENVBUFSIZE if required). ++ */ ++ ++static char *__env[] = { ++#if defined(CONFIG_SMP) ++ "PROMPT=[%d]kdb> ", ++ "MOREPROMPT=[%d]more> ", ++#else ++ "PROMPT=kdb> ", ++ "MOREPROMPT=more> ", ++#endif ++ "RADIX=16", ++ "LINES=24", ++ "COLUMNS=80", ++ "MDCOUNT=8", /* lines of md output */ ++ "BTARGS=9", /* 9 possible args in bt */ ++ KDB_PLATFORM_ENV, ++ "DTABCOUNT=30", ++ "NOSECT=1", ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++ (char *)0, ++}; ++ ++static const int __nenv = (sizeof(__env) / sizeof(char *)); ++ ++/* external commands: */ ++int kdb_debuginfo_print(int argc, const char **argv); ++int kdb_pxhelp(int argc, const char **argv); ++int kdb_walkhelp(int argc, const char **argv); ++int kdb_walk(int argc, const char **argv); ++ ++/* ++ * kdb_serial_str is the sequence that the user must enter on a serial ++ * console to invoke kdb. It can be a single character such as "\001" ++ * (control-A) or multiple characters such as "\eKDB". NOTE: All except the ++ * last character are passed through to the application reading from the serial ++ * console. ++ * ++ * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope ++ * with '\' in strings. CML2 would have been able to do it but we lost CML2. ++ * KAO. ++ */ ++const char kdb_serial_str[] = "\eKDB"; ++EXPORT_SYMBOL(kdb_serial_str); ++ ++struct task_struct * ++kdb_curr_task(int cpu) ++{ ++ struct task_struct *p = curr_task(cpu); ++#ifdef _TIF_MCA_INIT ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ if ((task_thread_info(p)->flags & _TIF_MCA_INIT) && krp->p) ++ p = krp->p; ++#endif ++ return p; ++} ++ ++/* ++ * kdbgetenv ++ * ++ * This function will return the character string value of ++ * an environment variable. ++ * ++ * Parameters: ++ * match A character string representing an environment variable. ++ * Outputs: ++ * None. ++ * Returns: ++ * NULL No environment variable matches 'match' ++ * char* Pointer to string value of environment variable. ++ * Locking: ++ * No locking considerations required. ++ * Remarks: ++ */ ++char * ++kdbgetenv(const char *match) ++{ ++ char **ep = __env; ++ int matchlen = strlen(match); ++ int i; ++ ++ for(i=0; i<__nenv; i++) { ++ char *e = *ep++; ++ ++ if (!e) continue; ++ ++ if ((strncmp(match, e, matchlen) == 0) ++ && ((e[matchlen] == '\0') ++ ||(e[matchlen] == '='))) { ++ char *cp = strchr(e, '='); ++ return (cp ? ++cp :""); ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * kdballocenv ++ * ++ * This function is used to allocate bytes for environment entries. ++ * ++ * Parameters: ++ * match A character string representing a numeric value ++ * Outputs: ++ * *value the unsigned long represntation of the env variable 'match' ++ * Returns: ++ * Zero on success, a kdb diagnostic on failure. ++ * Locking: ++ * No locking considerations required. Must be called with all ++ * processors halted. ++ * Remarks: ++ * We use a static environment buffer (envbuffer) to hold the values ++ * of dynamically generated environment variables (see kdb_set). Buffer ++ * space once allocated is never free'd, so over time, the amount of space ++ * (currently 512 bytes) will be exhausted if env variables are changed ++ * frequently. ++ */ ++static char * ++kdballocenv(size_t bytes) ++{ ++#define KDB_ENVBUFSIZE 512 ++ static char envbuffer[KDB_ENVBUFSIZE]; ++ static int envbufsize; ++ char *ep = NULL; ++ ++ if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { ++ ep = &envbuffer[envbufsize]; ++ envbufsize += bytes; ++ } ++ return ep; ++} ++ ++/* ++ * kdbgetulenv ++ * ++ * This function will return the value of an unsigned long-valued ++ * environment variable. ++ * ++ * Parameters: ++ * match A character string representing a numeric value ++ * Outputs: ++ * *value the unsigned long represntation of the env variable 'match' ++ * Returns: ++ * Zero on success, a kdb diagnostic on failure. ++ * Locking: ++ * No locking considerations required. ++ * Remarks: ++ */ ++ ++static int ++kdbgetulenv(const char *match, unsigned long *value) ++{ ++ char *ep; ++ ++ ep = kdbgetenv(match); ++ if (!ep) return KDB_NOTENV; ++ if (strlen(ep) == 0) return KDB_NOENVVALUE; ++ ++ *value = simple_strtoul(ep, NULL, 0); ++ ++ return 0; ++} ++ ++/* ++ * kdbgetintenv ++ * ++ * This function will return the value of an integer-valued ++ * environment variable. ++ * ++ * Parameters: ++ * match A character string representing an integer-valued env variable ++ * Outputs: ++ * *value the integer representation of the environment variable 'match' ++ * Returns: ++ * Zero on success, a kdb diagnostic on failure. ++ * Locking: ++ * No locking considerations required. ++ * Remarks: ++ */ ++ ++int ++kdbgetintenv(const char *match, int *value) { ++ unsigned long val; ++ int diag; ++ ++ diag = kdbgetulenv(match, &val); ++ if (!diag) { ++ *value = (int) val; ++ } ++ return diag; ++} ++ ++/* ++ * kdbgetularg ++ * ++ * This function will convert a numeric string ++ * into an unsigned long value. ++ * ++ * Parameters: ++ * arg A character string representing a numeric value ++ * Outputs: ++ * *value the unsigned long represntation of arg. ++ * Returns: ++ * Zero on success, a kdb diagnostic on failure. ++ * Locking: ++ * No locking considerations required. ++ * Remarks: ++ */ ++ ++int ++kdbgetularg(const char *arg, unsigned long *value) ++{ ++ char *endp; ++ unsigned long val; ++ ++ val = simple_strtoul(arg, &endp, 0); ++ ++ if (endp == arg) { ++ /* ++ * Try base 16, for us folks too lazy to type the ++ * leading 0x... ++ */ ++ val = simple_strtoul(arg, &endp, 16); ++ if (endp == arg) ++ return KDB_BADINT; ++ } ++ ++ *value = val; ++ ++ return 0; ++} ++ ++/* ++ * kdb_set ++ * ++ * This function implements the 'set' command. Alter an existing ++ * environment variable or create a new one. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_set(int argc, const char **argv) ++{ ++ int i; ++ char *ep; ++ size_t varlen, vallen; ++ ++ /* ++ * we can be invoked two ways: ++ * set var=value argv[1]="var", argv[2]="value" ++ * set var = value argv[1]="var", argv[2]="=", argv[3]="value" ++ * - if the latter, shift 'em down. ++ */ ++ if (argc == 3) { ++ argv[2] = argv[3]; ++ argc--; ++ } ++ ++ if (argc != 2) ++ return KDB_ARGCOUNT; ++ ++ /* ++ * Check for internal variables ++ */ ++ if (strcmp(argv[1], "KDBDEBUG") == 0) { ++ unsigned int debugflags; ++ char *cp; ++ ++ debugflags = simple_strtoul(argv[2], &cp, 0); ++ if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) { ++ kdb_printf("kdb: illegal debug flags '%s'\n", ++ argv[2]); ++ return 0; ++ } ++ kdb_flags = (kdb_flags & ~(KDB_DEBUG_FLAG_MASK << KDB_DEBUG_FLAG_SHIFT)) ++ | (debugflags << KDB_DEBUG_FLAG_SHIFT); ++ ++ return 0; ++ } ++ ++ /* ++ * Tokenizer squashed the '=' sign. argv[1] is variable ++ * name, argv[2] = value. ++ */ ++ varlen = strlen(argv[1]); ++ vallen = strlen(argv[2]); ++ ep = kdballocenv(varlen + vallen + 2); ++ if (ep == (char *)0) ++ return KDB_ENVBUFFULL; ++ ++ sprintf(ep, "%s=%s", argv[1], argv[2]); ++ ++ ep[varlen+vallen+1]='\0'; ++ ++ for(i=0; i<__nenv; i++) { ++ if (__env[i] ++ && ((strncmp(__env[i], argv[1], varlen)==0) ++ && ((__env[i][varlen] == '\0') ++ || (__env[i][varlen] == '=')))) { ++ __env[i] = ep; ++ return 0; ++ } ++ } ++ ++ /* ++ * Wasn't existing variable. Fit into slot. ++ */ ++ for(i=0; i<__nenv-1; i++) { ++ if (__env[i] == (char *)0) { ++ __env[i] = ep; ++ return 0; ++ } ++ } ++ ++ return KDB_ENVFULL; ++} ++ ++static int ++kdb_check_regs(void) ++{ ++ if (!kdb_current_regs) { ++ kdb_printf("No current kdb registers." ++ " You may need to select another task\n"); ++ return KDB_BADREG; ++ } ++ return 0; ++} ++ ++/* ++ * kdbgetaddrarg ++ * ++ * This function is responsible for parsing an ++ * address-expression and returning the value of ++ * the expression, symbol name, and offset to the caller. ++ * ++ * The argument may consist of a numeric value (decimal or ++ * hexidecimal), a symbol name, a register name (preceeded ++ * by the percent sign), an environment variable with a numeric ++ * value (preceeded by a dollar sign) or a simple arithmetic ++ * expression consisting of a symbol name, +/-, and a numeric ++ * constant value (offset). ++ * ++ * Parameters: ++ * argc - count of arguments in argv ++ * argv - argument vector ++ * *nextarg - index to next unparsed argument in argv[] ++ * regs - Register state at time of KDB entry ++ * Outputs: ++ * *value - receives the value of the address-expression ++ * *offset - receives the offset specified, if any ++ * *name - receives the symbol name, if any ++ * *nextarg - index to next unparsed argument in argv[] ++ * ++ * Returns: ++ * zero is returned on success, a kdb diagnostic code is ++ * returned on error. ++ * ++ * Locking: ++ * No locking requirements. ++ * ++ * Remarks: ++ * ++ */ ++ ++int ++kdbgetaddrarg(int argc, const char **argv, int *nextarg, ++ kdb_machreg_t *value, long *offset, ++ char **name) ++{ ++ kdb_machreg_t addr; ++ unsigned long off = 0; ++ int positive; ++ int diag; ++ int found = 0; ++ char *symname; ++ char symbol = '\0'; ++ char *cp; ++ kdb_symtab_t symtab; ++ ++ /* ++ * Process arguments which follow the following syntax: ++ * ++ * symbol | numeric-address [+/- numeric-offset] ++ * %register ++ * $environment-variable ++ */ ++ ++ if (*nextarg > argc) { ++ return KDB_ARGCOUNT; ++ } ++ ++ symname = (char *)argv[*nextarg]; ++ ++ /* ++ * If there is no whitespace between the symbol ++ * or address and the '+' or '-' symbols, we ++ * remember the character and replace it with a ++ * null so the symbol/value can be properly parsed ++ */ ++ if ((cp = strpbrk(symname, "+-")) != NULL) { ++ symbol = *cp; ++ *cp++ = '\0'; ++ } ++ ++ if (symname[0] == '$') { ++ diag = kdbgetulenv(&symname[1], &addr); ++ if (diag) ++ return diag; ++ } else if (symname[0] == '%') { ++ if ((diag = kdb_check_regs())) ++ return diag; ++ diag = kdba_getregcontents(&symname[1], kdb_current_regs, &addr); ++ if (diag) ++ return diag; ++ } else { ++ found = kdbgetsymval(symname, &symtab); ++ if (found) { ++ addr = symtab.sym_start; ++ } else { ++ diag = kdbgetularg(argv[*nextarg], &addr); ++ if (diag) ++ return diag; ++ } ++ } ++ ++ if (!found) ++ found = kdbnearsym(addr, &symtab); ++ ++ (*nextarg)++; ++ ++ if (name) ++ *name = symname; ++ if (value) ++ *value = addr; ++ if (offset && name && *name) ++ *offset = addr - symtab.sym_start; ++ ++ if ((*nextarg > argc) ++ && (symbol == '\0')) ++ return 0; ++ ++ /* ++ * check for +/- and offset ++ */ ++ ++ if (symbol == '\0') { ++ if ((argv[*nextarg][0] != '+') ++ && (argv[*nextarg][0] != '-')) { ++ /* ++ * Not our argument. Return. ++ */ ++ return 0; ++ } else { ++ positive = (argv[*nextarg][0] == '+'); ++ (*nextarg)++; ++ } ++ } else ++ positive = (symbol == '+'); ++ ++ /* ++ * Now there must be an offset! ++ */ ++ if ((*nextarg > argc) ++ && (symbol == '\0')) { ++ return KDB_INVADDRFMT; ++ } ++ ++ if (!symbol) { ++ cp = (char *)argv[*nextarg]; ++ (*nextarg)++; ++ } ++ ++ diag = kdbgetularg(cp, &off); ++ if (diag) ++ return diag; ++ ++ if (!positive) ++ off = -off; ++ ++ if (offset) ++ *offset += off; ++ ++ if (value) ++ *value += off; ++ ++ return 0; ++} ++ ++static void ++kdb_cmderror(int diag) ++{ ++ int i; ++ ++ if (diag >= 0) { ++ kdb_printf("no error detected (diagnostic is %d)\n", diag); ++ return; ++ } ++ ++ for(i=0; i<__nkdb_err; i++) { ++ if (kdbmsgs[i].km_diag == diag) { ++ kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg); ++ return; ++ } ++ } ++ ++ kdb_printf("Unknown diag %d\n", -diag); ++} ++ ++/* ++ * kdb_defcmd, kdb_defcmd2 ++ * ++ * This function implements the 'defcmd' command which defines one ++ * command as a set of other commands, terminated by endefcmd. ++ * kdb_defcmd processes the initial 'defcmd' command, kdb_defcmd2 ++ * is invoked from kdb_parse for the following commands until ++ * 'endefcmd'. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++struct defcmd_set { ++ int count; ++ int usable; ++ char *name; ++ char *usage; ++ char *help; ++ char **command; ++}; ++static struct defcmd_set *defcmd_set; ++static int defcmd_set_count; ++static int defcmd_in_progress; ++ ++/* Forward references */ ++static int kdb_exec_defcmd(int argc, const char **argv); ++ ++static int ++kdb_defcmd2(const char *cmdstr, const char *argv0) ++{ ++ struct defcmd_set *s = defcmd_set + defcmd_set_count - 1; ++ char **save_command = s->command; ++ if (strcmp(argv0, "endefcmd") == 0) { ++ defcmd_in_progress = 0; ++ if (!s->count) ++ s->usable = 0; ++ if (s->usable) ++ kdb_register(s->name, kdb_exec_defcmd, s->usage, s->help, 0); ++ return 0; ++ } ++ if (!s->usable) ++ return KDB_NOTIMP; ++ s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB); ++ if (!s->command) { ++ kdb_printf("Could not allocate new kdb_defcmd table for %s\n", cmdstr); ++ s->usable = 0; ++ return KDB_NOTIMP; ++ } ++ memcpy(s->command, save_command, s->count * sizeof(*(s->command))); ++ s->command[s->count++] = kdb_strdup(cmdstr, GFP_KDB); ++ kfree(save_command); ++ return 0; ++} ++ ++static int ++kdb_defcmd(int argc, const char **argv) ++{ ++ struct defcmd_set *save_defcmd_set = defcmd_set, *s; ++ if (defcmd_in_progress) { ++ kdb_printf("kdb: nested defcmd detected, assuming missing endefcmd\n"); ++ kdb_defcmd2("endefcmd", "endefcmd"); ++ } ++ if (argc == 0) { ++ int i; ++ for (s = defcmd_set; s < defcmd_set + defcmd_set_count; ++s) { ++ kdb_printf("defcmd %s \"%s\" \"%s\"\n", s->name, s->usage, s->help); ++ for (i = 0; i < s->count; ++i) ++ kdb_printf("%s", s->command[i]); ++ kdb_printf("endefcmd\n"); ++ } ++ return 0; ++ } ++ if (argc != 3) ++ return KDB_ARGCOUNT; ++ defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set), GFP_KDB); ++ if (!defcmd_set) { ++ kdb_printf("Could not allocate new defcmd_set entry for %s\n", argv[1]); ++ defcmd_set = save_defcmd_set; ++ return KDB_NOTIMP; ++ } ++ memcpy(defcmd_set, save_defcmd_set, defcmd_set_count * sizeof(*defcmd_set)); ++ kfree(save_defcmd_set); ++ s = defcmd_set + defcmd_set_count; ++ memset(s, 0, sizeof(*s)); ++ s->usable = 1; ++ s->name = kdb_strdup(argv[1], GFP_KDB); ++ s->usage = kdb_strdup(argv[2], GFP_KDB); ++ s->help = kdb_strdup(argv[3], GFP_KDB); ++ if (s->usage[0] == '"') { ++ strcpy(s->usage, s->usage+1); ++ s->usage[strlen(s->usage)-1] = '\0'; ++ } ++ if (s->help[0] == '"') { ++ strcpy(s->help, s->help+1); ++ s->help[strlen(s->help)-1] = '\0'; ++ } ++ ++defcmd_set_count; ++ defcmd_in_progress = 1; ++ return 0; ++} ++ ++/* ++ * kdb_exec_defcmd ++ * ++ * Execute the set of commands associated with this defcmd name. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_exec_defcmd(int argc, const char **argv) ++{ ++ int i, ret; ++ struct defcmd_set *s; ++ if (argc != 0) ++ return KDB_ARGCOUNT; ++ for (s = defcmd_set, i = 0; i < defcmd_set_count; ++i, ++s) { ++ if (strcmp(s->name, argv[0]) == 0) ++ break; ++ } ++ if (i == defcmd_set_count) { ++ kdb_printf("kdb_exec_defcmd: could not find commands for %s\n", argv[0]); ++ return KDB_NOTIMP; ++ } ++ for (i = 0; i < s->count; ++i) { ++ /* Recursive use of kdb_parse, do not use argv after this point */ ++ argv = NULL; ++ kdb_printf("[%s]kdb> %s\n", s->name, s->command[i]); ++ if ((ret = kdb_parse(s->command[i]))) ++ return ret; ++ } ++ return 0; ++} ++ ++/* Command history */ ++#define KDB_CMD_HISTORY_COUNT 32 ++#define CMD_BUFLEN 200 /* kdb_printf: max printline size == 256 */ ++static unsigned int cmd_head=0, cmd_tail=0; ++static unsigned int cmdptr; ++static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN]; ++static char cmd_cur[CMD_BUFLEN]; ++ ++/* ++ * The "str" argument may point to something like | grep xyz ++ * ++ */ ++static void ++parse_grep(const char *str) ++{ ++ int len; ++ char *cp = (char *)str, *cp2; ++ ++ /* sanity check: we should have been called with the \ first */ ++ if (*cp != '|') ++ return; ++ cp++; ++ while (isspace(*cp)) cp++; ++ if (strncmp(cp,"grep ",5)) { ++ kdb_printf ("invalid 'pipe', see grephelp\n"); ++ return; ++ } ++ cp += 5; ++ while (isspace(*cp)) cp++; ++ cp2 = strchr(cp, '\n'); ++ if (cp2) ++ *cp2 = '\0'; /* remove the trailing newline */ ++ len = strlen(cp); ++ if (len == 0) { ++ kdb_printf ("invalid 'pipe', see grephelp\n"); ++ return; ++ } ++ /* now cp points to a nonzero length search string */ ++ if (*cp == '"') { ++ /* allow it be "x y z" by removing the "'s - there must ++ be two of them */ ++ cp++; ++ cp2 = strchr(cp, '"'); ++ if (!cp2) { ++ kdb_printf ("invalid quoted string, see grephelp\n"); ++ return; ++ } ++ *cp2 = '\0'; /* end the string where the 2nd " was */ ++ } ++ kdb_grep_leading = 0; ++ if (*cp == '^') { ++ kdb_grep_leading = 1; ++ cp++; ++ } ++ len = strlen(cp); ++ kdb_grep_trailing = 0; ++ if (*(cp+len-1) == '$') { ++ kdb_grep_trailing = 1; ++ *(cp+len-1) = '\0'; ++ } ++ len = strlen(cp); ++ if (!len) return; ++ if (len >= GREP_LEN) { ++ kdb_printf ("search string too long\n"); ++ return; ++ } ++ strcpy(kdb_grep_string, cp); ++ kdb_grepping_flag++; ++ return; ++} ++ ++/* ++ * kdb_parse ++ * ++ * Parse the command line, search the command table for a ++ * matching command and invoke the command function. ++ * This function may be called recursively, if it is, the second call ++ * will overwrite argv and cbuf. It is the caller's responsibility to ++ * save their argv if they recursively call kdb_parse(). ++ * ++ * Parameters: ++ * cmdstr The input command line to be parsed. ++ * regs The registers at the time kdb was entered. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic if failure. ++ * Locking: ++ * None. ++ * Remarks: ++ * Limited to 20 tokens. ++ * ++ * Real rudimentary tokenization. Basically only whitespace ++ * is considered a token delimeter (but special consideration ++ * is taken of the '=' sign as used by the 'set' command). ++ * ++ * The algorithm used to tokenize the input string relies on ++ * there being at least one whitespace (or otherwise useless) ++ * character between tokens as the character immediately following ++ * the token is altered in-place to a null-byte to terminate the ++ * token string. ++ */ ++ ++#define MAXARGC 20 ++ ++int ++kdb_parse(const char *cmdstr) ++{ ++ static char *argv[MAXARGC]; ++ static int argc = 0; ++ static char cbuf[CMD_BUFLEN+2]; ++ char *cp; ++ char *cpp, quoted; ++ kdbtab_t *tp; ++ int i, escaped, ignore_errors = 0, check_grep; ++ ++ /* ++ * First tokenize the command string. ++ */ ++ cp = (char *)cmdstr; ++ kdb_grepping_flag = check_grep = 0; ++ ++ if (KDB_FLAG(CMD_INTERRUPT)) { ++ /* Previous command was interrupted, newline must not repeat the command */ ++ KDB_FLAG_CLEAR(CMD_INTERRUPT); ++ argc = 0; /* no repeat */ ++ } ++ ++ if (*cp != '\n' && *cp != '\0') { ++ argc = 0; ++ cpp = cbuf; ++ while (*cp) { ++ /* skip whitespace */ ++ while (isspace(*cp)) cp++; ++ if ((*cp == '\0') || (*cp == '\n') || (*cp == '#' && !defcmd_in_progress)) ++ break; ++ /* special case: check for | grep pattern */ ++ if (*cp == '|') { ++ check_grep++; ++ break; ++ } ++ if (cpp >= cbuf + CMD_BUFLEN) { ++ kdb_printf("kdb_parse: command buffer overflow, command ignored\n%s\n", cmdstr); ++ return KDB_NOTFOUND; ++ } ++ if (argc >= MAXARGC - 1) { ++ kdb_printf("kdb_parse: too many arguments, command ignored\n%s\n", cmdstr); ++ return KDB_NOTFOUND; ++ } ++ argv[argc++] = cpp; ++ escaped = 0; ++ quoted = '\0'; ++ /* Copy to next unquoted and unescaped whitespace or '=' */ ++ while (*cp && *cp != '\n' && (escaped || quoted || !isspace(*cp))) { ++ if (cpp >= cbuf + CMD_BUFLEN) ++ break; ++ if (escaped) { ++ escaped = 0; ++ *cpp++ = *cp++; ++ continue; ++ } ++ if (*cp == '\\') { ++ escaped = 1; ++ ++cp; ++ continue; ++ } ++ if (*cp == quoted) { ++ quoted = '\0'; ++ } else if (*cp == '\'' || *cp == '"') { ++ quoted = *cp; ++ } ++ if ((*cpp = *cp++) == '=' && !quoted) ++ break; ++ ++cpp; ++ } ++ *cpp++ = '\0'; /* Squash a ws or '=' character */ ++ } ++ } ++ if (!argc) ++ return 0; ++ if (check_grep) ++ parse_grep(cp); ++ if (defcmd_in_progress) { ++ int result = kdb_defcmd2(cmdstr, argv[0]); ++ if (!defcmd_in_progress) { ++ argc = 0; /* avoid repeat on endefcmd */ ++ *(argv[0]) = '\0'; ++ } ++ return result; ++ } ++ if (argv[0][0] == '-' && argv[0][1] && (argv[0][1] < '0' || argv[0][1] > '9')) { ++ ignore_errors = 1; ++ ++argv[0]; ++ } ++ ++ for(tp=kdb_commands, i=0; i < kdb_max_commands; i++,tp++) { ++ if (tp->cmd_name) { ++ /* ++ * If this command is allowed to be abbreviated, ++ * check to see if this is it. ++ */ ++ ++ if (tp->cmd_minlen ++ && (strlen(argv[0]) <= tp->cmd_minlen)) { ++ if (strncmp(argv[0], ++ tp->cmd_name, ++ tp->cmd_minlen) == 0) { ++ break; ++ } ++ } ++ ++ if (strcmp(argv[0], tp->cmd_name)==0) { ++ break; ++ } ++ } ++ } ++ ++ /* ++ * If we don't find a command by this name, see if the first ++ * few characters of this match any of the known commands. ++ * e.g., md1c20 should match md. ++ */ ++ if (i == kdb_max_commands) { ++ for(tp=kdb_commands, i=0; i < kdb_max_commands; i++,tp++) { ++ if (tp->cmd_name) { ++ if (strncmp(argv[0], ++ tp->cmd_name, ++ strlen(tp->cmd_name))==0) { ++ break; ++ } ++ } ++ } ++ } ++ ++ if (i < kdb_max_commands) { ++ int result; ++ KDB_STATE_SET(CMD); ++ result = (*tp->cmd_func)(argc-1, ++ (const char**)argv); ++ if (result && ignore_errors && result > KDB_CMD_GO) ++ result = 0; ++ KDB_STATE_CLEAR(CMD); ++ switch (tp->cmd_repeat) { ++ case KDB_REPEAT_NONE: ++ argc = 0; ++ if (argv[0]) ++ *(argv[0]) = '\0'; ++ break; ++ case KDB_REPEAT_NO_ARGS: ++ argc = 1; ++ if (argv[1]) ++ *(argv[1]) = '\0'; ++ break; ++ case KDB_REPEAT_WITH_ARGS: ++ break; ++ } ++ return result; ++ } ++ ++ /* ++ * If the input with which we were presented does not ++ * map to an existing command, attempt to parse it as an ++ * address argument and display the result. Useful for ++ * obtaining the address of a variable, or the nearest symbol ++ * to an address contained in a register. ++ */ ++ { ++ kdb_machreg_t value; ++ char *name = NULL; ++ long offset; ++ int nextarg = 0; ++ ++ if (kdbgetaddrarg(0, (const char **)argv, &nextarg, ++ &value, &offset, &name)) { ++ return KDB_NOTFOUND; ++ } ++ ++ kdb_printf("%s = ", argv[0]); ++ kdb_symbol_print(value, NULL, KDB_SP_DEFAULT); ++ kdb_printf("\n"); ++ return 0; ++ } ++} ++ ++ ++static int ++handle_ctrl_cmd(char *cmd) ++{ ++#define CTRL_P 16 ++#define CTRL_N 14 ++ ++ /* initial situation */ ++ if (cmd_head == cmd_tail) return 0; ++ ++ switch(*cmd) { ++ case CTRL_P: ++ if (cmdptr != cmd_tail) ++ cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT; ++ strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN); ++ return 1; ++ case CTRL_N: ++ if (cmdptr != cmd_head) ++ cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT; ++ strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN); ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * kdb_do_dump ++ * ++ * Call the dump() function if the kernel is configured for LKCD. ++ * Inputs: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. dump() may or may not return. ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static void ++kdb_do_dump(void) ++{ ++#if defined(CONFIG_LKCD_DUMP) || defined(CONFIG_LKCD_DUMP_MODULE) ++ kdb_printf("Forcing dump (if configured)\n"); ++ console_loglevel = 8; /* to see the dump messages */ ++ dump("kdb_do_dump"); ++#endif ++} ++ ++/* ++ * kdb_reboot ++ * ++ * This function implements the 'reboot' command. Reboot the system ++ * immediately. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * Shouldn't return from this function. ++ */ ++ ++static int ++kdb_reboot(int argc, const char **argv) ++{ ++ emergency_restart(); ++ kdb_printf("Hmm, kdb_reboot did not reboot, spinning here\n"); ++ while (1) {}; ++ /* NOTREACHED */ ++ return 0; ++} ++ ++#ifdef CONFIG_KDB_KDUMP ++ ++int kdb_kdump_state = KDB_KDUMP_RESET; /* KDB kdump state */ ++ ++static int kdb_cpu(int argc, const char **argv); ++ ++/* ++ * kdb_kdump_check ++ * ++ * This is where the kdump on monarch cpu is handled. ++ * ++ */ ++void kdb_kdump_check(struct pt_regs *regs) ++{ ++ if (kdb_kdump_state != KDB_KDUMP_RESET) { ++ crash_kexec(regs); ++ ++ /* If the call above returned then something ++ didn't work */ ++ kdb_printf("kdb_kdump_check: crash_kexec failed!\n"); ++ kdb_printf(" Please check if the kdump kernel has been properly loaded\n"); ++ kdb_kdump_state = KDB_KDUMP_RESET; ++ } ++} ++ ++ ++/* ++ * kdb_kdump ++ * ++ * This function implements the 'kdump' command. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * envp environment vector ++ * regs registers at time kdb was entered. ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * Shouldn't return from this function. ++ */ ++ ++static int ++kdb_kdump(int argc, const char **argv) ++{ ++ char cpu_id[6]; /* up to 99,999 cpus */ ++ const char *cpu_argv[] = {NULL, cpu_id, NULL}; ++ int ret; ++ ++ kdb_kdump_state = KDB_KDUMP_KDUMP; ++ /* Switch back to the initial cpu before process kdump command */ ++ if (smp_processor_id() != kdb_initial_cpu) { ++ sprintf(cpu_id, "%d", kdb_initial_cpu); ++ ret = kdb_cpu(1, cpu_argv); ++ if (ret != KDB_CMD_CPU) { ++ kdb_printf("kdump: Failed to switch to initial cpu %d;" ++ " aborted\n", kdb_initial_cpu); ++ kdb_kdump_state = KDB_KDUMP_RESET; ++ } ++ } else ++ ret = KDB_CMD_CPU; ++ ++ return ret; ++} ++ ++#endif /* CONFIG_KDB_KDUMP */ ++ ++static int ++kdb_quiet(int reason) ++{ ++ return (reason == KDB_REASON_CPU_UP || reason == KDB_REASON_SILENT); ++} ++ ++/* ++ * kdb_local ++ * ++ * The main code for kdb. This routine is invoked on a specific ++ * processor, it is not global. The main kdb() routine ensures ++ * that only one processor at a time is in this routine. This ++ * code is called with the real reason code on the first entry ++ * to a kdb session, thereafter it is called with reason SWITCH, ++ * even if the user goes back to the original cpu. ++ * ++ * Inputs: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * regs The exception frame at time of fault/breakpoint. NULL ++ * for reason SILENT or CPU_UP, otherwise valid. ++ * db_result Result code from the break or debug point. ++ * Returns: ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * KDB_CMD_GO User typed 'go'. ++ * KDB_CMD_CPU User switched to another cpu. ++ * KDB_CMD_SS Single step. ++ * KDB_CMD_SSB Single step until branch. ++ * Locking: ++ * none ++ * Remarks: ++ * none ++ */ ++ ++static int ++kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, kdb_dbtrap_t db_result) ++{ ++ char *cmdbuf; ++ int diag; ++ struct task_struct *kdb_current = kdb_curr_task(smp_processor_id()); ++ ++#ifdef CONFIG_KDB_KDUMP ++ kdb_kdump_check(regs); ++#endif ++ ++ /* If kdb has been entered for an event which has been/will be ++ * recovered then silently return. We have to get this far into kdb in ++ * order to synchronize all the cpus, typically only one cpu (monarch) ++ * knows that the event is recoverable but the other cpus (slaves) may ++ * also be driven into kdb before that decision is made by the monarch. ++ * ++ * To pause in kdb even for recoverable events, 'set RECOVERY_PAUSE 1' ++ */ ++ KDB_DEBUG_STATE("kdb_local 1", reason); ++ if (reason == KDB_REASON_ENTER ++ && KDB_FLAG(RECOVERY) ++ && !KDB_FLAG(CATASTROPHIC)) { ++ int recovery_pause = 0; ++ kdbgetintenv("RECOVERY_PAUSE", &recovery_pause); ++ if (recovery_pause == 0) ++ reason = KDB_REASON_SILENT; ++ else ++ kdb_printf("%s: Recoverable error detected but" ++ " RECOVERY_PAUSE is set, staying in KDB\n", ++ __FUNCTION__); ++ } ++ ++ KDB_DEBUG_STATE("kdb_local 2", reason); ++ kdb_go_count = 0; ++ if (kdb_quiet(reason)) { ++ /* no message */ ++ } else if (reason == KDB_REASON_DEBUG) { ++ /* special case below */ ++ } else { ++ kdb_printf("\nEntering kdb (current=0x%p, pid %d) ", kdb_current, kdb_current->pid); ++#if defined(CONFIG_SMP) ++ kdb_printf("on processor %d ", smp_processor_id()); ++#endif ++ } ++ ++ switch (reason) { ++ case KDB_REASON_DEBUG: ++ { ++ /* ++ * If re-entering kdb after a single step ++ * command, don't print the message. ++ */ ++ switch(db_result) { ++ case KDB_DB_BPT: ++ kdb_printf("\nEntering kdb (0x%p, pid %d) ", kdb_current, kdb_current->pid); ++#if defined(CONFIG_SMP) ++ kdb_printf("on processor %d ", smp_processor_id()); ++#endif ++ kdb_printf("due to Debug @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); ++ break; ++ case KDB_DB_SSB: ++ /* ++ * In the midst of ssb command. Just return. ++ */ ++ KDB_DEBUG_STATE("kdb_local 3", reason); ++ return KDB_CMD_SSB; /* Continue with SSB command */ ++ ++ break; ++ case KDB_DB_SS: ++ break; ++ case KDB_DB_SSBPT: ++ KDB_DEBUG_STATE("kdb_local 4", reason); ++ return 1; /* kdba_db_trap did the work */ ++ default: ++ kdb_printf("kdb: Bad result from kdba_db_trap: %d\n", ++ db_result); ++ break; ++ } ++ ++ } ++ break; ++ case KDB_REASON_ENTER: ++ if (KDB_STATE(KEYBOARD)) ++ kdb_printf("due to Keyboard Entry\n"); ++ else { ++ kdb_printf("due to KDB_ENTER()\n"); ++ } ++ break; ++ case KDB_REASON_KEYBOARD: ++ KDB_STATE_SET(KEYBOARD); ++ kdb_printf("due to Keyboard Entry\n"); ++ break; ++ case KDB_REASON_ENTER_SLAVE: /* drop through, slaves only get released via cpu switch */ ++ case KDB_REASON_SWITCH: ++ kdb_printf("due to cpu switch\n"); ++ if (KDB_STATE(GO_SWITCH)) { ++ KDB_STATE_CLEAR(GO_SWITCH); ++ KDB_DEBUG_STATE("kdb_local 5", reason); ++ return KDB_CMD_GO; ++ } ++ break; ++ case KDB_REASON_OOPS: ++ kdb_printf("Oops: %s\n", kdb_diemsg); ++ kdb_printf("due to oops @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); ++ kdba_dumpregs(regs, NULL, NULL); ++ break; ++ case KDB_REASON_NMI: ++ kdb_printf("due to NonMaskable Interrupt @ " kdb_machreg_fmt "\n", ++ kdba_getpc(regs)); ++ kdba_dumpregs(regs, NULL, NULL); ++ break; ++ case KDB_REASON_BREAK: ++ kdb_printf("due to Breakpoint @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); ++ /* ++ * Determine if this breakpoint is one that we ++ * are interested in. ++ */ ++ if (db_result != KDB_DB_BPT) { ++ kdb_printf("kdb: error return from kdba_bp_trap: %d\n", db_result); ++ KDB_DEBUG_STATE("kdb_local 6", reason); ++ return 0; /* Not for us, dismiss it */ ++ } ++ break; ++ case KDB_REASON_RECURSE: ++ kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); ++ break; ++ case KDB_REASON_CPU_UP: ++ case KDB_REASON_SILENT: ++ KDB_DEBUG_STATE("kdb_local 7", reason); ++ if (reason == KDB_REASON_CPU_UP) ++ kdba_cpu_up(); ++ return KDB_CMD_GO; /* Silent entry, silent exit */ ++ break; ++ default: ++ kdb_printf("kdb: unexpected reason code: %d\n", reason); ++ KDB_DEBUG_STATE("kdb_local 8", reason); ++ return 0; /* Not for us, dismiss it */ ++ } ++ ++ kdba_local_arch_setup(); ++ ++ kdba_set_current_task(kdb_current); ++ ++ while (1) { ++ /* ++ * Initialize pager context. ++ */ ++ kdb_nextline = 1; ++ KDB_STATE_CLEAR(SUPPRESS); ++#ifdef kdba_setjmp ++ /* ++ * Use kdba_setjmp/kdba_longjmp to break out of ++ * the pager early and to attempt to recover from kdb errors. ++ */ ++ KDB_STATE_CLEAR(LONGJMP); ++ if (kdbjmpbuf) { ++ if (kdba_setjmp(&kdbjmpbuf[smp_processor_id()])) { ++ /* Command aborted (usually in pager) */ ++ continue; ++ } ++ else ++ KDB_STATE_SET(LONGJMP); ++ } ++#endif /* kdba_setjmp */ ++ ++ cmdbuf = cmd_cur; ++ *cmdbuf = '\0'; ++ *(cmd_hist[cmd_head])='\0'; ++ ++ if (KDB_FLAG(ONLY_DO_DUMP)) { ++ /* kdb is off but a catastrophic error requires a dump. ++ * Take the dump and reboot. ++ * Turn on logging so the kdb output appears in the log ++ * buffer in the dump. ++ */ ++ const char *setargs[] = { "set", "LOGGING", "1" }; ++ kdb_set(2, setargs); ++ kdb_do_dump(); ++ kdb_reboot(0, NULL); ++ /*NOTREACHED*/ ++ } ++ ++do_full_getstr: ++#if defined(CONFIG_SMP) ++ snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"), smp_processor_id()); ++#else ++ snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT")); ++#endif ++ if (defcmd_in_progress) ++ strncat(kdb_prompt_str, "[defcmd]", CMD_BUFLEN); ++ ++ /* ++ * Fetch command from keyboard ++ */ ++ cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str); ++ if (*cmdbuf != '\n') { ++ if (*cmdbuf < 32) { ++ if(cmdptr == cmd_head) { ++ strncpy(cmd_hist[cmd_head], cmd_cur, CMD_BUFLEN); ++ *(cmd_hist[cmd_head]+strlen(cmd_hist[cmd_head])-1) = '\0'; ++ } ++ if(!handle_ctrl_cmd(cmdbuf)) ++ *(cmd_cur+strlen(cmd_cur)-1) = '\0'; ++ cmdbuf = cmd_cur; ++ goto do_full_getstr; ++ } ++ else ++ strncpy(cmd_hist[cmd_head], cmd_cur, CMD_BUFLEN); ++ ++ cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT; ++ if (cmd_head == cmd_tail) cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT; ++ ++ } ++ ++ cmdptr = cmd_head; ++ diag = kdb_parse(cmdbuf); ++ if (diag == KDB_NOTFOUND) { ++ kdb_printf("Unknown kdb command: '%s'\n", cmdbuf); ++ diag = 0; ++ } ++ if (diag == KDB_CMD_GO ++ || diag == KDB_CMD_CPU ++ || diag == KDB_CMD_SS ++ || diag == KDB_CMD_SSB) ++ break; ++ ++ if (diag) ++ kdb_cmderror(diag); ++ } ++ ++ kdba_local_arch_cleanup(); ++ ++ KDB_DEBUG_STATE("kdb_local 9", diag); ++ return diag; ++} ++ ++ ++/* ++ * kdb_print_state ++ * ++ * Print the state data for the current processor for debugging. ++ * ++ * Inputs: ++ * text Identifies the debug point ++ * value Any integer value to be printed, e.g. reason code. ++ * Returns: ++ * None. ++ * Locking: ++ * none ++ * Remarks: ++ * none ++ */ ++ ++void kdb_print_state(const char *text, int value) ++{ ++ kdb_printf("state: %s cpu %d value %d initial %d state %x\n", ++ text, smp_processor_id(), value, kdb_initial_cpu, kdb_state[smp_processor_id()]); ++} ++ ++/* ++ * kdb_previous_event ++ * ++ * Return a count of cpus that are leaving kdb, i.e. the number ++ * of processors that are still handling the previous kdb event. ++ * ++ * Inputs: ++ * None. ++ * Returns: ++ * Count of cpus in previous event. ++ * Locking: ++ * none ++ * Remarks: ++ * none ++ */ ++ ++static int ++kdb_previous_event(void) ++{ ++ int i, leaving = 0; ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (KDB_STATE_CPU(LEAVING, i)) ++ ++leaving; ++ } ++ return leaving; ++} ++ ++/* ++ * kdb_wait_for_cpus ++ * ++ * Invoked once at the start of a kdb event, from the controlling cpu. Wait a ++ * short period for the other cpus to enter kdb state. ++ * ++ * Inputs: ++ * none ++ * Returns: ++ * none ++ * Locking: ++ * none ++ * Remarks: ++ * none ++ */ ++ ++int kdb_wait_for_cpus_secs; ++ ++static void ++kdb_wait_for_cpus(void) ++{ ++#ifdef CONFIG_SMP ++ int online = 0, kdb_data = 0, prev_kdb_data = 0, c, time; ++ mdelay(100); ++ for (time = 0; time < kdb_wait_for_cpus_secs; ++time) { ++ online = 0; ++ kdb_data = 0; ++ for_each_online_cpu(c) { ++ ++online; ++ if (kdb_running_process[c].seqno >= kdb_seqno - 1) ++ ++kdb_data; ++ } ++ if (online == kdb_data) ++ break; ++ if (prev_kdb_data != kdb_data) { ++ kdb_nextline = 0; /* no prompt yet */ ++ kdb_printf(" %d out of %d cpus in kdb, waiting for the rest, timeout in %d second(s)\n", ++ kdb_data, online, kdb_wait_for_cpus_secs - time); ++ prev_kdb_data = kdb_data; ++ } ++ touch_nmi_watchdog(); ++ mdelay(1000); ++ /* Architectures may want to send a more forceful interrupt */ ++ if (time == min(kdb_wait_for_cpus_secs / 2, 5)) ++ kdba_wait_for_cpus(); ++ if (time % 4 == 0) ++ kdb_printf("."); ++ } ++ if (time) { ++ int wait = online - kdb_data; ++ if (wait == 0) ++ kdb_printf("All cpus are now in kdb\n"); ++ else ++ kdb_printf("%d cpu%s not in kdb, %s state is unknown\n", ++ wait, ++ wait == 1 ? " is" : "s are", ++ wait == 1 ? "its" : "their"); ++ } ++#endif /* CONFIG_SMP */ ++} ++ ++/* ++ * kdb_main_loop ++ * ++ * The main kdb loop. After initial setup and assignment of the controlling ++ * cpu, all cpus are in this loop. One cpu is in control and will issue the kdb ++ * prompt, the others will spin until 'go' or cpu switch. ++ * ++ * To get a consistent view of the kernel stacks for all processes, this routine ++ * is invoked from the main kdb code via an architecture specific routine. ++ * kdba_main_loop is responsible for making the kernel stacks consistent for all ++ * processes, there should be no difference between a blocked process and a ++ * running process as far as kdb is concerned. ++ * ++ * Inputs: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * reason2 kdb's current reason code. Initially error but can change ++ * acording to kdb state. ++ * db_result Result code from break or debug point. ++ * regs The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it ++ * should always be valid. ++ * Returns: ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * Locking: ++ * none ++ * Remarks: ++ * none ++ */ ++ ++int ++kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, ++ kdb_dbtrap_t db_result, struct pt_regs *regs) ++{ ++ int result = 1; ++ /* Stay in kdb() until 'go', 'ss[b]' or an error */ ++ while (1) { ++ /* ++ * All processors except the one that is in control ++ * will spin here. ++ */ ++ KDB_DEBUG_STATE("kdb_main_loop 1", reason); ++ while (KDB_STATE(HOLD_CPU)) { ++ /* state KDB is turned off by kdb_cpu to see if the ++ * other cpus are still live, each cpu in this loop ++ * turns it back on. ++ */ ++ if (!KDB_STATE(KDB)) { ++ KDB_STATE_SET(KDB); ++ } ++ ++#if defined(CONFIG_KDB_KDUMP) ++ if (KDB_STATE(KEXEC)) { ++ struct pt_regs r; ++ if (regs == NULL) ++ regs = &r; ++ ++ kdba_kdump_shutdown_slave(regs); ++ return 0; ++ } ++#endif ++ } ++ ++ KDB_STATE_CLEAR(SUPPRESS); ++ KDB_DEBUG_STATE("kdb_main_loop 2", reason); ++ if (KDB_STATE(LEAVING)) ++ break; /* Another cpu said 'go' */ ++ ++ if (!kdb_quiet(reason)) ++ kdb_wait_for_cpus(); ++ /* Still using kdb, this processor is in control */ ++ result = kdb_local(reason2, error, regs, db_result); ++ KDB_DEBUG_STATE("kdb_main_loop 3", result); ++ ++ if (result == KDB_CMD_CPU) { ++ /* Cpu switch, hold the current cpu, release the target one. */ ++ reason2 = KDB_REASON_SWITCH; ++ KDB_STATE_SET(HOLD_CPU); ++ KDB_STATE_CLEAR_CPU(HOLD_CPU, kdb_new_cpu); ++ continue; ++ } ++ ++ if (result == KDB_CMD_SS) { ++ KDB_STATE_SET(DOING_SS); ++ break; ++ } ++ ++ if (result == KDB_CMD_SSB) { ++ KDB_STATE_SET(DOING_SS); ++ KDB_STATE_SET(DOING_SSB); ++ break; ++ } ++ ++ if (result && result != 1 && result != KDB_CMD_GO) ++ kdb_printf("\nUnexpected kdb_local return code %d\n", result); ++ ++ KDB_DEBUG_STATE("kdb_main_loop 4", reason); ++ break; ++ } ++ if (KDB_STATE(DOING_SS)) ++ KDB_STATE_CLEAR(SSBPT); ++ return result; ++} ++ ++/* iapc_boot_arch was defined in ACPI 2.0, FADT revision 3 onwards. For any ++ * FADT prior to revision 3, we have to assume that we have an i8042 I/O ++ * device. ACPI initialises after KDB initialises but before using KDB, so ++ * check iapc_boot_arch on each entry to KDB. ++ */ ++static void ++kdb_check_i8042(void) ++{ ++ KDB_FLAG_CLEAR(NO_I8042); ++#ifdef CONFIG_ACPI ++ if (acpi_gbl_FADT.header.revision >= 3 && ++ (acpi_gbl_FADT.boot_flags & BAF_8042_KEYBOARD_CONTROLLER) == 0) ++ KDB_FLAG_SET(NO_I8042); ++#endif /* CONFIG_ACPI */ ++} ++ ++/* ++ * kdb ++ * ++ * This function is the entry point for the kernel debugger. It ++ * provides a command parser and associated support functions to ++ * allow examination and control of an active kernel. ++ * ++ * The breakpoint trap code should invoke this function with ++ * one of KDB_REASON_BREAK (int 03) or KDB_REASON_DEBUG (debug register) ++ * ++ * the die_if_kernel function should invoke this function with ++ * KDB_REASON_OOPS. ++ * ++ * In single step mode, one cpu is released to run without ++ * breakpoints. Interrupts and NMI are reset to their original values, ++ * the cpu is allowed to do one instruction which causes a trap ++ * into kdb with KDB_REASON_DEBUG. ++ * ++ * Inputs: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * regs The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it ++ * should always be valid. ++ * Returns: ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * Locking: ++ * none ++ * Remarks: ++ * No assumptions of system state. This function may be invoked ++ * with arbitrary locks held. It will stop all other processors ++ * in an SMP environment, disable all interrupts and does not use ++ * the operating systems keyboard driver. ++ * ++ * This code is reentrant but only for cpu switch. Any other ++ * reentrancy is an error, although kdb will attempt to recover. ++ * ++ * At the start of a kdb session the initial processor is running ++ * kdb() and the other processors can be doing anything. When the ++ * initial processor calls smp_kdb_stop() the other processors are ++ * driven through kdb_ipi which calls kdb() with reason SWITCH. ++ * That brings all processors into this routine, one with a "real" ++ * reason code, the other with SWITCH. ++ * ++ * Because the other processors are driven via smp_kdb_stop(), ++ * they enter here from the NMI handler. Until the other ++ * processors exit from here and exit from kdb_ipi, they will not ++ * take any more NMI requests. The initial cpu will still take NMI. ++ * ++ * Multiple race and reentrancy conditions, each with different ++ * advoidance mechanisms. ++ * ++ * Two cpus hit debug points at the same time. ++ * ++ * kdb_lock and kdb_initial_cpu ensure that only one cpu gets ++ * control of kdb. The others spin on kdb_initial_cpu until ++ * they are driven through NMI into kdb_ipi. When the initial ++ * cpu releases the others from NMI, they resume trying to get ++ * kdb_initial_cpu to start a new event. ++ * ++ * A cpu is released from kdb and starts a new event before the ++ * original event has completely ended. ++ * ++ * kdb_previous_event() prevents any cpu from entering ++ * kdb_initial_cpu state until the previous event has completely ++ * ended on all cpus. ++ * ++ * An exception occurs inside kdb. ++ * ++ * kdb_initial_cpu detects recursive entry to kdb and attempts ++ * to recover. The recovery uses longjmp() which means that ++ * recursive calls to kdb never return. Beware of assumptions ++ * like ++ * ++ * ++depth; ++ * kdb(); ++ * --depth; ++ * ++ * If the kdb call is recursive then longjmp takes over and ++ * --depth is never executed. ++ * ++ * NMI handling. ++ * ++ * NMI handling is tricky. The initial cpu is invoked by some kdb event, ++ * this event could be NMI driven but usually is not. The other cpus are ++ * driven into kdb() via kdb_ipi which uses NMI so at the start the other ++ * cpus will not accept NMI. Some operations such as SS release one cpu ++ * but hold all the others. Releasing a cpu means it drops back to ++ * whatever it was doing before the kdb event, this means it drops out of ++ * kdb_ipi and hence out of NMI status. But the software watchdog uses ++ * NMI and we do not want spurious watchdog calls into kdb. kdba_read() ++ * resets the watchdog counters in its input polling loop, when a kdb ++ * command is running it is subject to NMI watchdog events. ++ * ++ * Another problem with NMI handling is the NMI used to drive the other ++ * cpus into kdb cannot be distinguished from the watchdog NMI. State ++ * flag WAIT_IPI indicates that a cpu is waiting for NMI via kdb_ipi, ++ * if not set then software NMI is ignored by kdb_ipi. ++ * ++ * Cpu switching. ++ * ++ * All cpus are in kdb (or they should be), all but one are ++ * spinning on KDB_STATE(HOLD_CPU). Only one cpu is not in ++ * HOLD_CPU state, only that cpu can handle commands. ++ * ++ * Go command entered. ++ * ++ * If necessary, go will switch to the initial cpu first. If the event ++ * was caused by a software breakpoint (assumed to be global) that ++ * requires single-step to get over the breakpoint then only release the ++ * initial cpu, after the initial cpu has single-stepped the breakpoint ++ * then release the rest of the cpus. If SSBPT is not required then ++ * release all the cpus at once. ++ */ ++ ++int ++kdb(kdb_reason_t reason, int error, struct pt_regs *regs) ++{ ++ kdb_intstate_t int_state; /* Interrupt state */ ++ kdb_reason_t reason2 = reason; ++ int result = 0; /* Default is kdb did not handle it */ ++ int ss_event, old_regs_saved = 0; ++ struct pt_regs *old_regs = NULL; ++ kdb_dbtrap_t db_result=KDB_DB_NOBPT; ++ preempt_disable(); ++ atomic_inc(&kdb_event); ++ ++ switch(reason) { ++ case KDB_REASON_OOPS: ++ case KDB_REASON_NMI: ++ KDB_FLAG_SET(CATASTROPHIC); /* kernel state is dubious now */ ++ break; ++ default: ++ break; ++ } ++ switch(reason) { ++ case KDB_REASON_ENTER: ++ case KDB_REASON_ENTER_SLAVE: ++ case KDB_REASON_BREAK: ++ case KDB_REASON_DEBUG: ++ case KDB_REASON_OOPS: ++ case KDB_REASON_SWITCH: ++ case KDB_REASON_KEYBOARD: ++ case KDB_REASON_NMI: ++ if (regs && regs != get_irq_regs()) { ++ old_regs = set_irq_regs(regs); ++ old_regs_saved = 1; ++ } ++ break; ++ default: ++ break; ++ } ++ if (kdb_continue_catastrophic > 2) { ++ kdb_printf("kdb_continue_catastrophic is out of range, setting to 2\n"); ++ kdb_continue_catastrophic = 2; ++ } ++ if (!kdb_on && KDB_FLAG(CATASTROPHIC) && kdb_continue_catastrophic == 2) { ++ KDB_FLAG_SET(ONLY_DO_DUMP); ++ } ++ if (!kdb_on && !KDB_FLAG(ONLY_DO_DUMP)) ++ goto out; ++ ++ KDB_DEBUG_STATE("kdb 1", reason); ++ KDB_STATE_CLEAR(SUPPRESS); ++ ++ /* Filter out userspace breakpoints first, no point in doing all ++ * the kdb smp fiddling when it is really a gdb trap. ++ * Save the single step status first, kdba_db_trap clears ss status. ++ * kdba_b[dp]_trap sets SSBPT if required. ++ */ ++ ss_event = KDB_STATE(DOING_SS) || KDB_STATE(SSBPT); ++#ifdef CONFIG_CPU_XSCALE ++ if ( KDB_STATE(A_XSC_ICH) ) { ++ /* restore changed I_BIT */ ++ KDB_STATE_CLEAR(A_XSC_ICH); ++ kdba_restore_retirq(regs, KDB_STATE(A_XSC_IRQ)); ++ if ( !ss_event ) { ++ kdb_printf("Stranger!!! Why IRQ bit is changed====\n"); ++ } ++ } ++#endif ++ if (reason == KDB_REASON_BREAK) { ++ db_result = kdba_bp_trap(regs, error); /* Only call this once */ ++ } ++ if (reason == KDB_REASON_DEBUG) { ++ db_result = kdba_db_trap(regs, error); /* Only call this once */ ++ } ++ ++ if ((reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) ++ && db_result == KDB_DB_NOBPT) { ++ KDB_DEBUG_STATE("kdb 2", reason); ++ goto out; /* Not one of mine */ ++ } ++ ++ /* Turn off single step if it was being used */ ++ if (ss_event) { ++ kdba_clearsinglestep(regs); ++ /* Single step after a breakpoint removes the need for a delayed reinstall */ ++ if (reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) ++ KDB_STATE_CLEAR(SSBPT); ++ } ++ ++ /* kdb can validly reenter but only for certain well defined conditions */ ++ if (reason == KDB_REASON_DEBUG ++ && !KDB_STATE(HOLD_CPU) ++ && ss_event) ++ KDB_STATE_SET(REENTRY); ++ else ++ KDB_STATE_CLEAR(REENTRY); ++ ++ /* Wait for previous kdb event to completely exit before starting ++ * a new event. ++ */ ++ while (kdb_previous_event()) ++ ; ++ KDB_DEBUG_STATE("kdb 3", reason); ++ ++ /* ++ * If kdb is already active, print a message and try to recover. ++ * If recovery is not possible and recursion is allowed or ++ * forced recursion without recovery is set then try to recurse ++ * in kdb. Not guaranteed to work but it makes an attempt at ++ * debugging the debugger. ++ */ ++ if (reason != KDB_REASON_SWITCH && ++ reason != KDB_REASON_ENTER_SLAVE) { ++ if (KDB_IS_RUNNING() && !KDB_STATE(REENTRY)) { ++ int recover = 1; ++ unsigned long recurse = 0; ++ kdb_printf("kdb: Debugger re-entered on cpu %d, new reason = %d\n", ++ smp_processor_id(), reason); ++ /* Should only re-enter from released cpu */ ++ ++ if (KDB_STATE(HOLD_CPU)) { ++ kdb_printf(" Strange, cpu %d should not be running\n", smp_processor_id()); ++ recover = 0; ++ } ++ if (!KDB_STATE(CMD)) { ++ kdb_printf(" Not executing a kdb command\n"); ++ recover = 0; ++ } ++ if (!KDB_STATE(LONGJMP)) { ++ kdb_printf(" No longjmp available for recovery\n"); ++ recover = 0; ++ } ++ kdbgetulenv("RECURSE", &recurse); ++ if (recurse > 1) { ++ kdb_printf(" Forced recursion is set\n"); ++ recover = 0; ++ } ++ if (recover) { ++ kdb_printf(" Attempting to abort command and recover\n"); ++#ifdef kdba_setjmp ++ kdba_longjmp(&kdbjmpbuf[smp_processor_id()], 0); ++#endif /* kdba_setjmp */ ++ } ++ if (recurse) { ++ if (KDB_STATE(RECURSE)) { ++ kdb_printf(" Already in recursive mode\n"); ++ } else { ++ kdb_printf(" Attempting recursive mode\n"); ++ KDB_STATE_SET(RECURSE); ++ KDB_STATE_SET(REENTRY); ++ reason2 = KDB_REASON_RECURSE; ++ recover = 1; ++ } ++ } ++ if (!recover) { ++ kdb_printf(" Cannot recover, allowing event to proceed\n"); ++ /*temp*/ ++ while (KDB_IS_RUNNING()) ++ cpu_relax(); ++ goto out; ++ } ++ } ++ } else if (reason == KDB_REASON_SWITCH && !KDB_IS_RUNNING()) { ++ kdb_printf("kdb: CPU switch without kdb running, I'm confused\n"); ++ goto out; ++ } ++ ++ /* ++ * Disable interrupts, breakpoints etc. on this processor ++ * during kdb command processing ++ */ ++ KDB_STATE_SET(KDB); ++ kdba_disableint(&int_state); ++ if (!KDB_STATE(KDB_CONTROL)) { ++ kdb_bp_remove_local(); ++ KDB_STATE_SET(KDB_CONTROL); ++ } ++ ++ /* ++ * If not entering the debugger due to CPU switch or single step ++ * reentry, serialize access here. ++ * The processors may race getting to this point - if, ++ * for example, more than one processor hits a breakpoint ++ * at the same time. We'll serialize access to kdb here - ++ * other processors will loop here, and the NMI from the stop ++ * IPI will take them into kdb as switch candidates. Once ++ * the initial processor releases the debugger, the rest of ++ * the processors will race for it. ++ * ++ * The above describes the normal state of affairs, where two or more ++ * cpus that are entering kdb at the "same" time are assumed to be for ++ * separate events. However some processes such as ia64 MCA/INIT will ++ * drive all the cpus into error processing at the same time. For that ++ * case, all of the cpus entering kdb at the "same" time are really a ++ * single event. ++ * ++ * That case is handled by the use of KDB_ENTER by one cpu (the ++ * monarch) and KDB_ENTER_SLAVE on the other cpus (the slaves). ++ * KDB_ENTER_SLAVE maps to KDB_REASON_ENTER_SLAVE. The slave events ++ * will be treated as if they had just responded to the kdb IPI, i.e. ++ * as if they were KDB_REASON_SWITCH. ++ * ++ * Because of races across multiple cpus, ENTER_SLAVE can occur before ++ * the main ENTER. Hold up ENTER_SLAVE here until the main ENTER ++ * arrives. ++ */ ++ ++ if (reason == KDB_REASON_ENTER_SLAVE) { ++ spin_lock(&kdb_lock); ++ while (!KDB_IS_RUNNING()) { ++ spin_unlock(&kdb_lock); ++ while (!KDB_IS_RUNNING()) ++ cpu_relax(); ++ spin_lock(&kdb_lock); ++ } ++ reason = KDB_REASON_SWITCH; ++ KDB_STATE_SET(HOLD_CPU); ++ spin_unlock(&kdb_lock); ++ } ++ ++ if (reason == KDB_REASON_SWITCH || KDB_STATE(REENTRY)) ++ ; /* drop through */ ++ else { ++ KDB_DEBUG_STATE("kdb 4", reason); ++ spin_lock(&kdb_lock); ++ while (KDB_IS_RUNNING() || kdb_previous_event()) { ++ spin_unlock(&kdb_lock); ++ while (KDB_IS_RUNNING() || kdb_previous_event()) ++ cpu_relax(); ++ spin_lock(&kdb_lock); ++ } ++ KDB_DEBUG_STATE("kdb 5", reason); ++ ++ kdb_initial_cpu = smp_processor_id(); ++ ++kdb_seqno; ++ spin_unlock(&kdb_lock); ++ if (!kdb_quiet(reason)) ++ notify_die(DIE_KDEBUG_ENTER, "KDEBUG ENTER", regs, error, 0, 0); ++ } ++ ++ if (smp_processor_id() == kdb_initial_cpu ++ && !KDB_STATE(REENTRY)) { ++ KDB_STATE_CLEAR(HOLD_CPU); ++ KDB_STATE_CLEAR(WAIT_IPI); ++ kdb_check_i8042(); ++ /* ++ * Remove the global breakpoints. This is only done ++ * once from the initial processor on initial entry. ++ */ ++ if (!kdb_quiet(reason) || smp_processor_id() == 0) ++ kdb_bp_remove_global(); ++ ++ /* ++ * If SMP, stop other processors. The other processors ++ * will enter kdb() with KDB_REASON_SWITCH and spin in ++ * kdb_main_loop(). ++ */ ++ KDB_DEBUG_STATE("kdb 6", reason); ++ if (NR_CPUS > 1 && !kdb_quiet(reason)) { ++ int i; ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ if (i != kdb_initial_cpu) { ++ KDB_STATE_SET_CPU(HOLD_CPU, i); ++ KDB_STATE_SET_CPU(WAIT_IPI, i); ++ } ++ } ++ KDB_DEBUG_STATE("kdb 7", reason); ++ smp_kdb_stop(); ++ KDB_DEBUG_STATE("kdb 8", reason); ++ } ++ } ++ ++ if (KDB_STATE(GO1)) { ++ kdb_bp_remove_global(); /* They were set for single-step purposes */ ++ KDB_STATE_CLEAR(GO1); ++ reason = KDB_REASON_SILENT; /* Now silently go */ ++ } ++ ++ /* Set up a consistent set of process stacks before talking to the user */ ++ KDB_DEBUG_STATE("kdb 9", result); ++ result = kdba_main_loop(reason, reason2, error, db_result, regs); ++ reason = reason2; /* back to original event type */ ++ ++ KDB_DEBUG_STATE("kdb 10", result); ++ kdba_adjust_ip(reason, error, regs); ++ KDB_STATE_CLEAR(LONGJMP); ++ KDB_DEBUG_STATE("kdb 11", result); ++ /* go which requires single-step over a breakpoint must only release ++ * one cpu. ++ */ ++ if (result == KDB_CMD_GO && KDB_STATE(SSBPT)) ++ KDB_STATE_SET(GO1); ++ ++ if (smp_processor_id() == kdb_initial_cpu && ++ !KDB_STATE(DOING_SS) && ++ !KDB_STATE(RECURSE)) { ++ /* ++ * (Re)install the global breakpoints and cleanup the cached ++ * symbol table. This is only done once from the initial ++ * processor on go. ++ */ ++ KDB_DEBUG_STATE("kdb 12", reason); ++ if (!kdb_quiet(reason) || smp_processor_id() == 0) { ++ kdb_bp_install_global(regs); ++ kdbnearsym_cleanup(); ++ debug_kusage(); ++ } ++ if (!KDB_STATE(GO1)) { ++ /* ++ * Release all other cpus which will see KDB_STATE(LEAVING) is set. ++ */ ++ int i; ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (KDB_STATE_CPU(KDB, i)) ++ KDB_STATE_SET_CPU(LEAVING, i); ++ KDB_STATE_CLEAR_CPU(WAIT_IPI, i); ++ KDB_STATE_CLEAR_CPU(HOLD_CPU, i); ++ } ++ /* Wait until all the other processors leave kdb */ ++ while (kdb_previous_event() != 1) ++ ; ++ if (!kdb_quiet(reason)) ++ notify_die(DIE_KDEBUG_LEAVE, "KDEBUG LEAVE", regs, error, 0, 0); ++ kdb_initial_cpu = -1; /* release kdb control */ ++ KDB_DEBUG_STATE("kdb 13", reason); ++ } ++ } ++ ++ KDB_DEBUG_STATE("kdb 14", result); ++ kdba_restoreint(&int_state); ++#ifdef CONFIG_CPU_XSCALE ++ if ( smp_processor_id() == kdb_initial_cpu && ++ ( KDB_STATE(SSBPT) | KDB_STATE(DOING_SS) ) ++ ) { ++ kdba_setsinglestep(regs); ++ // disable IRQ in stack frame ++ KDB_STATE_SET(A_XSC_ICH); ++ if ( kdba_disable_retirq(regs) ) { ++ KDB_STATE_SET(A_XSC_IRQ); ++ } ++ else { ++ KDB_STATE_CLEAR(A_XSC_IRQ); ++ } ++ } ++#endif ++ ++ /* Only do this work if we are really leaving kdb */ ++ if (!(KDB_STATE(DOING_SS) || KDB_STATE(SSBPT) || KDB_STATE(RECURSE))) { ++ KDB_DEBUG_STATE("kdb 15", result); ++ kdb_bp_install_local(regs); ++ if (old_regs_saved) ++ set_irq_regs(old_regs); ++ KDB_STATE_CLEAR(KDB_CONTROL); ++ } ++ ++ KDB_DEBUG_STATE("kdb 16", result); ++ KDB_FLAG_CLEAR(CATASTROPHIC); ++ KDB_STATE_CLEAR(IP_ADJUSTED); /* Re-adjust ip next time in */ ++ KDB_STATE_CLEAR(KEYBOARD); ++ KDB_STATE_CLEAR(KDB); /* Main kdb state has been cleared */ ++ KDB_STATE_CLEAR(RECURSE); ++ KDB_STATE_CLEAR(LEAVING); /* No more kdb work after this */ ++ KDB_DEBUG_STATE("kdb 17", reason); ++out: ++ atomic_dec(&kdb_event); ++ preempt_enable(); ++ return result != 0; ++} ++ ++/* ++ * kdb_mdr ++ * ++ * This function implements the guts of the 'mdr' command. ++ * ++ * mdr , ++ * ++ * Inputs: ++ * addr Start address ++ * count Number of bytes ++ * Outputs: ++ * None. ++ * Returns: ++ * Always 0. Any errors are detected and printed by kdb_getarea. ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_mdr(kdb_machreg_t addr, unsigned int count) ++{ ++ unsigned char c; ++ while (count--) { ++ if (kdb_getarea(c, addr)) ++ return 0; ++ kdb_printf("%02x", c); ++ addr++; ++ } ++ kdb_printf("\n"); ++ return 0; ++} ++ ++/* ++ * kdb_md ++ * ++ * This function implements the 'md', 'md1', 'md2', 'md4', 'md8' ++ * 'mdr' and 'mds' commands. ++ * ++ * md|mds [ [ []]] ++ * mdWcN [ [ []]] ++ * where W = is the width (1, 2, 4 or 8) and N is the count. ++ * for eg., md1c20 reads 20 bytes, 1 at a time. ++ * mdr , ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static void ++kdb_md_line(const char *fmtstr, kdb_machreg_t addr, ++ int symbolic, int nosect, int bytesperword, ++ int num, int repeat, int phys) ++{ ++ /* print just one line of data */ ++ kdb_symtab_t symtab; ++ char cbuf[32]; ++ char *c = cbuf; ++ int i; ++ unsigned long word; ++ ++ memset(cbuf, '\0', sizeof(cbuf)); ++ if (phys) ++ kdb_printf("phys " kdb_machreg_fmt0 " ", addr); ++ else ++ kdb_printf(kdb_machreg_fmt0 " ", addr); ++ ++ for (i = 0; i < num && repeat--; i++) { ++ if (phys) { ++ if (kdb_getphysword(&word, addr, bytesperword)) ++ break; ++ } else if (kdb_getword(&word, addr, bytesperword)) ++ break; ++ kdb_printf(fmtstr, word); ++ if (symbolic) ++ kdbnearsym(word, &symtab); ++ else ++ memset(&symtab, 0, sizeof(symtab)); ++ if (symtab.sym_name) { ++ kdb_symbol_print(word, &symtab, 0); ++ if (!nosect) { ++ kdb_printf("\n"); ++ kdb_printf(" %s %s " ++ kdb_machreg_fmt " " kdb_machreg_fmt " " kdb_machreg_fmt, ++ symtab.mod_name, ++ symtab.sec_name, ++ symtab.sec_start, ++ symtab.sym_start, ++ symtab.sym_end); ++ } ++ addr += bytesperword; ++ } else { ++ union { ++ u64 word; ++ unsigned char c[8]; ++ } wc; ++ unsigned char *cp; ++#ifdef __BIG_ENDIAN ++ cp = wc.c + 8 - bytesperword; ++#else ++ cp = wc.c; ++#endif ++ wc.word = word; ++#define printable_char(c) ({unsigned char __c = c; isascii(__c) && isprint(__c) ? __c : '.';}) ++ switch (bytesperword) { ++ case 8: ++ *c++ = printable_char(*cp++); ++ *c++ = printable_char(*cp++); ++ *c++ = printable_char(*cp++); ++ *c++ = printable_char(*cp++); ++ addr += 4; ++ case 4: ++ *c++ = printable_char(*cp++); ++ *c++ = printable_char(*cp++); ++ addr += 2; ++ case 2: ++ *c++ = printable_char(*cp++); ++ addr++; ++ case 1: ++ *c++ = printable_char(*cp++); ++ addr++; ++ break; ++ } ++#undef printable_char ++ } ++ } ++ kdb_printf("%*s %s\n", (int)((num-i)*(2*bytesperword + 1)+1), " ", cbuf); ++} ++ ++static int ++kdb_md(int argc, const char **argv) ++{ ++ static kdb_machreg_t last_addr; ++ static int last_radix, last_bytesperword, last_repeat; ++ int radix = 16, mdcount = 8, bytesperword = KDB_WORD_SIZE, repeat; ++ int nosect = 0; ++ char fmtchar, fmtstr[64]; ++ kdb_machreg_t addr; ++ unsigned long word; ++ long offset = 0; ++ int symbolic = 0; ++ int valid = 0; ++ int phys = 0; ++ ++ kdbgetintenv("MDCOUNT", &mdcount); ++ kdbgetintenv("RADIX", &radix); ++ kdbgetintenv("BYTESPERWORD", &bytesperword); ++ ++ /* Assume 'md ' and start with environment values */ ++ repeat = mdcount * 16 / bytesperword; ++ ++ if (strcmp(argv[0], "mdr") == 0) { ++ if (argc != 2) ++ return KDB_ARGCOUNT; ++ valid = 1; ++ } else if (isdigit(argv[0][2])) { ++ bytesperword = (int)(argv[0][2] - '0'); ++ if (bytesperword == 0) { ++ bytesperword = last_bytesperword; ++ if (bytesperword == 0) { ++ bytesperword = 4; ++ } ++ } ++ last_bytesperword = bytesperword; ++ repeat = mdcount * 16 / bytesperword; ++ if (!argv[0][3]) ++ valid = 1; ++ else if (argv[0][3] == 'c' && argv[0][4]) { ++ char *p; ++ repeat = simple_strtoul(argv[0]+4, &p, 10); ++ mdcount = ((repeat * bytesperword) + 15) / 16; ++ valid = !*p; ++ } ++ last_repeat = repeat; ++ } else if (strcmp(argv[0], "md") == 0) ++ valid = 1; ++ else if (strcmp(argv[0], "mds") == 0) ++ valid = 1; ++ else if (strcmp(argv[0], "mdp") == 0) { ++ phys = valid = 1; ++ } ++ if (!valid) ++ return KDB_NOTFOUND; ++ ++ if (argc == 0) { ++ if (last_addr == 0) ++ return KDB_ARGCOUNT; ++ addr = last_addr; ++ radix = last_radix; ++ bytesperword = last_bytesperword; ++ repeat = last_repeat; ++ mdcount = ((repeat * bytesperword) + 15) / 16; ++ } ++ ++ if (argc) { ++ kdb_machreg_t val; ++ int diag, nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ if (argc > nextarg+2) ++ return KDB_ARGCOUNT; ++ ++ if (argc >= nextarg) { ++ diag = kdbgetularg(argv[nextarg], &val); ++ if (!diag) { ++ mdcount = (int) val; ++ repeat = mdcount * 16 / bytesperword; ++ } ++ } ++ if (argc >= nextarg+1) { ++ diag = kdbgetularg(argv[nextarg+1], &val); ++ if (!diag) ++ radix = (int) val; ++ } ++ } ++ ++ if (strcmp(argv[0], "mdr") == 0) { ++ return kdb_mdr(addr, mdcount); ++ } ++ ++ switch (radix) { ++ case 10: ++ fmtchar = 'd'; ++ break; ++ case 16: ++ fmtchar = 'x'; ++ break; ++ case 8: ++ fmtchar = 'o'; ++ break; ++ default: ++ return KDB_BADRADIX; ++ } ++ ++ last_radix = radix; ++ ++ if (bytesperword > KDB_WORD_SIZE) ++ return KDB_BADWIDTH; ++ ++ switch (bytesperword) { ++ case 8: ++ sprintf(fmtstr, "%%16.16l%c ", fmtchar); ++ break; ++ case 4: ++ sprintf(fmtstr, "%%8.8l%c ", fmtchar); ++ break; ++ case 2: ++ sprintf(fmtstr, "%%4.4l%c ", fmtchar); ++ break; ++ case 1: ++ sprintf(fmtstr, "%%2.2l%c ", fmtchar); ++ break; ++ default: ++ return KDB_BADWIDTH; ++ } ++ ++ last_repeat = repeat; ++ last_bytesperword = bytesperword; ++ ++ if (strcmp(argv[0], "mds") == 0) { ++ symbolic = 1; ++ /* Do not save these changes as last_*, they are temporary mds ++ * overrides. ++ */ ++ bytesperword = KDB_WORD_SIZE; ++ repeat = mdcount; ++ kdbgetintenv("NOSECT", &nosect); ++ } ++ ++ /* Round address down modulo BYTESPERWORD */ ++ ++ addr &= ~(bytesperword-1); ++ ++ while (repeat > 0) { ++ unsigned long a; ++ int n, z, num = (symbolic ? 1 : (16 / bytesperword)); ++ ++ for (a = addr, z = 0; z < repeat; a += bytesperword, ++z) { ++ if (phys) { ++ if (kdb_getphysword(&word, a, bytesperword) ++ || word) ++ break; ++ } else if (kdb_getword(&word, a, bytesperword) || word) ++ break; ++ } ++ n = min(num, repeat); ++ kdb_md_line(fmtstr, addr, symbolic, nosect, bytesperword, num, repeat, phys); ++ addr += bytesperword * n; ++ repeat -= n; ++ z = (z + num - 1) / num; ++ if (z > 2) { ++ int s = num * (z-2); ++ kdb_printf(kdb_machreg_fmt0 "-" kdb_machreg_fmt0 " zero suppressed\n", ++ addr, addr + bytesperword * s - 1); ++ addr += bytesperword * s; ++ repeat -= s; ++ } ++ } ++ last_addr = addr; ++ ++ return 0; ++} ++ ++/* ++ * kdb_mm ++ * ++ * This function implements the 'mm' command. ++ * ++ * mm address-expression new-value ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * mm works on machine words, mmW works on bytes. ++ */ ++ ++static int ++kdb_mm(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ unsigned long contents; ++ int nextarg; ++ int width; ++ ++ if (argv[0][2] && !isdigit(argv[0][2])) ++ return KDB_NOTFOUND; ++ ++ if (argc < 2) { ++ return KDB_ARGCOUNT; ++ } ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL))) ++ return diag; ++ ++ if (nextarg > argc) ++ return KDB_ARGCOUNT; ++ ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL))) ++ return diag; ++ ++ if (nextarg != argc + 1) ++ return KDB_ARGCOUNT; ++ ++ width = argv[0][2] ? (argv[0][2] - '0') : (KDB_WORD_SIZE); ++ if ((diag = kdb_putword(addr, contents, width))) ++ return diag; ++ ++ kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents); ++ ++ return 0; ++} ++ ++/* ++ * kdb_go ++ * ++ * This function implements the 'go' command. ++ * ++ * go [address-expression] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * KDB_CMD_GO for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_go(int argc, const char **argv) ++{ ++ kdb_machreg_t addr; ++ int diag; ++ int nextarg; ++ long offset; ++ struct pt_regs *regs = get_irq_regs(); ++ ++ if (argc == 1) { ++ if (smp_processor_id() != kdb_initial_cpu) { ++ kdb_printf("go
must be issued from the initial cpu, do cpu %d first\n", kdb_initial_cpu); ++ return KDB_ARGCOUNT; ++ } ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, ++ &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ ++ kdba_setpc(regs, addr); ++ } else if (argc) ++ return KDB_ARGCOUNT; ++ ++ diag = KDB_CMD_GO; ++ if (KDB_FLAG(CATASTROPHIC)) { ++ kdb_printf("Catastrophic error detected\n"); ++ kdb_printf("kdb_continue_catastrophic=%d, ", ++ kdb_continue_catastrophic); ++ if (kdb_continue_catastrophic == 0 && kdb_go_count++ == 0) { ++ kdb_printf("type go a second time if you really want to continue\n"); ++ return 0; ++ } ++ if (kdb_continue_catastrophic == 2) { ++ kdb_do_dump(); ++ kdb_printf("forcing reboot\n"); ++ kdb_reboot(0, NULL); ++ } ++ kdb_printf("attempting to continue\n"); ++ } ++ if (smp_processor_id() != kdb_initial_cpu) { ++ char buf[80]; ++ kdb_printf("go was not issued from initial cpu, switching back to cpu %d\n", kdb_initial_cpu); ++ sprintf(buf, "cpu %d\n", kdb_initial_cpu); ++ /* Recursive use of kdb_parse, do not use argv after this point */ ++ argv = NULL; ++ diag = kdb_parse(buf); ++ if (diag == KDB_CMD_CPU) ++ KDB_STATE_SET_CPU(GO_SWITCH, kdb_initial_cpu); ++ } ++ return diag; ++} ++ ++/* ++ * kdb_rd ++ * ++ * This function implements the 'rd' command. ++ * ++ * rd display all general registers. ++ * rd c display all control registers. ++ * rd d display all debug registers. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_rd(int argc, const char **argv) ++{ ++ int diag; ++ if (argc == 0) { ++ if ((diag = kdb_check_regs())) ++ return diag; ++ return kdba_dumpregs(kdb_current_regs, NULL, NULL); ++ } ++ ++ if (argc > 2) { ++ return KDB_ARGCOUNT; ++ } ++ ++ if ((diag = kdb_check_regs())) ++ return diag; ++ return kdba_dumpregs(kdb_current_regs, argv[1], argc==2 ? argv[2]: NULL); ++} ++ ++/* ++ * kdb_rm ++ * ++ * This function implements the 'rm' (register modify) command. ++ * ++ * rm register-name new-contents ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * Currently doesn't allow modification of control or ++ * debug registers. ++ */ ++ ++static int ++kdb_rm(int argc, const char **argv) ++{ ++ int diag; ++ int ind = 0; ++ kdb_machreg_t contents; ++ ++ if (argc != 2) { ++ return KDB_ARGCOUNT; ++ } ++ ++ /* ++ * Allow presence or absence of leading '%' symbol. ++ */ ++ ++ if (argv[1][0] == '%') ++ ind = 1; ++ ++ diag = kdbgetularg(argv[2], &contents); ++ if (diag) ++ return diag; ++ ++ if ((diag = kdb_check_regs())) ++ return diag; ++ diag = kdba_setregcontents(&argv[1][ind], kdb_current_regs, contents); ++ if (diag) ++ return diag; ++ ++ return 0; ++} ++ ++#if defined(CONFIG_MAGIC_SYSRQ) ++/* ++ * kdb_sr ++ * ++ * This function implements the 'sr' (SYSRQ key) command which ++ * interfaces to the soi-disant MAGIC SYSRQ functionality. ++ * ++ * sr ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * None. ++ */ ++static int ++kdb_sr(int argc, const char **argv) ++{ ++ extern int __sysrq_enabled; ++ if (argc != 1) { ++ return KDB_ARGCOUNT; ++ } ++ if (!__sysrq_enabled) { ++ kdb_printf("Auto activating sysrq\n"); ++ __sysrq_enabled = 1; ++ } ++ ++ handle_sysrq(*argv[1], NULL); ++ ++ return 0; ++} ++#endif /* CONFIG_MAGIC_SYSRQ */ ++ ++/* ++ * kdb_ef ++ * ++ * This function implements the 'regs' (display exception frame) ++ * command. This command takes an address and expects to find ++ * an exception frame at that address, formats and prints it. ++ * ++ * regs address-expression ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * Not done yet. ++ */ ++ ++static int ++kdb_ef(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset; ++ int nextarg; ++ ++ if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ ++ return kdba_dumpregs((struct pt_regs *)addr, NULL, NULL); ++ } ++ ++ return KDB_ARGCOUNT; ++} ++ ++#if defined(CONFIG_MODULES) ++extern struct list_head *kdb_modules; ++extern void free_module(struct module *); ++ ++/* modules using other modules */ ++struct module_use ++{ ++ struct list_head list; ++ struct module *module_which_uses; ++}; ++ ++/* ++ * kdb_lsmod ++ * ++ * This function implements the 'lsmod' command. Lists currently ++ * loaded kernel modules. ++ * ++ * Mostly taken from userland lsmod. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * ++ */ ++ ++static int ++kdb_lsmod(int argc, const char **argv) ++{ ++ struct module *mod; ++ ++ if (argc != 0) ++ return KDB_ARGCOUNT; ++ ++ kdb_printf("Module Size modstruct Used by\n"); ++ list_for_each_entry(mod, kdb_modules, list) { ++ ++ kdb_printf("%-20s%8u 0x%p ", mod->name, ++ mod->core_size, (void *)mod); ++#ifdef CONFIG_MODULE_UNLOAD ++ kdb_printf("%4d ", module_refcount(mod)); ++#endif ++ if (mod->state == MODULE_STATE_GOING) ++ kdb_printf(" (Unloading)"); ++ else if (mod->state == MODULE_STATE_COMING) ++ kdb_printf(" (Loading)"); ++ else ++ kdb_printf(" (Live)"); ++ ++#ifdef CONFIG_MODULE_UNLOAD ++ { ++ struct module_use *use; ++ kdb_printf(" [ "); ++ list_for_each_entry(use, &mod->modules_which_use_me, list) ++ kdb_printf("%s ", use->module_which_uses->name); ++ kdb_printf("]\n"); ++ } ++#endif ++ } ++ ++ return 0; ++} ++ ++#endif /* CONFIG_MODULES */ ++ ++/* ++ * kdb_env ++ * ++ * This function implements the 'env' command. Display the current ++ * environment variables. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_env(int argc, const char **argv) ++{ ++ int i; ++ ++ for(i=0; i<__nenv; i++) { ++ if (__env[i]) { ++ kdb_printf("%s\n", __env[i]); ++ } ++ } ++ ++ if (KDB_DEBUG(MASK)) ++ kdb_printf("KDBFLAGS=0x%x\n", kdb_flags); ++ ++ return 0; ++} ++ ++/* ++ * kdb_dmesg ++ * ++ * This function implements the 'dmesg' command to display the contents ++ * of the syslog buffer. ++ * ++ * dmesg [lines] [adjust] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * None. ++ */ ++ ++static int ++kdb_dmesg(int argc, const char **argv) ++{ ++ char *syslog_data[4], *start, *end, c = '\0', *p; ++ int diag, logging, logsize, lines = 0, adjust = 0, n; ++ ++ if (argc > 2) ++ return KDB_ARGCOUNT; ++ if (argc) { ++ char *cp; ++ lines = simple_strtol(argv[1], &cp, 0); ++ if (*cp) ++ lines = 0; ++ if (argc > 1) { ++ adjust = simple_strtoul(argv[2], &cp, 0); ++ if (*cp || adjust < 0) ++ adjust = 0; ++ } ++ } ++ ++ /* disable LOGGING if set */ ++ diag = kdbgetintenv("LOGGING", &logging); ++ if (!diag && logging) { ++ const char *setargs[] = { "set", "LOGGING", "0" }; ++ kdb_set(2, setargs); ++ } ++ ++ /* syslog_data[0,1] physical start, end+1. syslog_data[2,3] logical start, end+1. */ ++ kdb_syslog_data(syslog_data); ++ if (syslog_data[2] == syslog_data[3]) ++ return 0; ++ logsize = syslog_data[1] - syslog_data[0]; ++ start = syslog_data[2]; ++ end = syslog_data[3]; ++#define KDB_WRAP(p) (((p - syslog_data[0]) % logsize) + syslog_data[0]) ++ for (n = 0, p = start; p < end; ++p) { ++ if ((c = *KDB_WRAP(p)) == '\n') ++ ++n; ++ } ++ if (c != '\n') ++ ++n; ++ if (lines < 0) { ++ if (adjust >= n) ++ kdb_printf("buffer only contains %d lines, nothing printed\n", n); ++ else if (adjust - lines >= n) ++ kdb_printf("buffer only contains %d lines, last %d lines printed\n", ++ n, n - adjust); ++ if (adjust) { ++ for (; start < end && adjust; ++start) { ++ if (*KDB_WRAP(start) == '\n') ++ --adjust; ++ } ++ if (start < end) ++ ++start; ++ } ++ for (p = start; p < end && lines; ++p) { ++ if (*KDB_WRAP(p) == '\n') ++ ++lines; ++ } ++ end = p; ++ } else if (lines > 0) { ++ int skip = n - (adjust + lines); ++ if (adjust >= n) { ++ kdb_printf("buffer only contains %d lines, nothing printed\n", n); ++ skip = n; ++ } else if (skip < 0) { ++ lines += skip; ++ skip = 0; ++ kdb_printf("buffer only contains %d lines, first %d lines printed\n", ++ n, lines); ++ } ++ for (; start < end && skip; ++start) { ++ if (*KDB_WRAP(start) == '\n') ++ --skip; ++ } ++ for (p = start; p < end && lines; ++p) { ++ if (*KDB_WRAP(p) == '\n') ++ --lines; ++ } ++ end = p; ++ } ++ /* Do a line at a time (max 200 chars) to reduce protocol overhead */ ++ c = '\n'; ++ while (start != end) { ++ char buf[201]; ++ p = buf; ++ while (start < end && (c = *KDB_WRAP(start)) && (p - buf) < sizeof(buf)-1) { ++ ++start; ++ *p++ = c; ++ if (c == '\n') ++ break; ++ } ++ *p = '\0'; ++ kdb_printf("%s", buf); ++ } ++ if (c != '\n') ++ kdb_printf("\n"); ++ ++ return 0; ++} ++ ++/* ++ * kdb_cpu ++ * ++ * This function implements the 'cpu' command. ++ * ++ * cpu [] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * KDB_CMD_CPU for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * All cpu's should be spinning in kdb(). However just in case ++ * a cpu did not take the smp_kdb_stop NMI, check that a cpu ++ * entered kdb() before passing control to it. ++ */ ++ ++static void ++kdb_cpu_status(void) ++{ ++ int i, start_cpu, first_print = 1; ++ char state, prev_state = '?'; ++ ++ kdb_printf("Currently on cpu %d\n", smp_processor_id()); ++ kdb_printf("Available cpus: "); ++ for (start_cpu = -1, i = 0; i < NR_CPUS; i++) { ++ if (!cpu_online(i)) ++ state = 'F'; /* cpu is offline */ ++ else { ++ struct kdb_running_process *krp = kdb_running_process+i; ++ if (KDB_STATE_CPU(KDB, i)) { ++ state = ' '; /* cpu is responding to kdb */ ++ if (kdb_task_state_char(krp->p) == 'I') ++ state = 'I'; /* running the idle task */ ++ } else if (krp->seqno && krp->p && krp->seqno >= kdb_seqno - 1) ++ state = '+'; /* some kdb data, but not responding */ ++ else ++ state = '*'; /* no kdb data */ ++ } ++ if (state != prev_state) { ++ if (prev_state != '?') { ++ if (!first_print) ++ kdb_printf(", "); ++ first_print = 0; ++ kdb_printf("%d", start_cpu); ++ if (start_cpu < i-1) ++ kdb_printf("-%d", i-1); ++ if (prev_state != ' ') ++ kdb_printf("(%c)", prev_state); ++ } ++ prev_state = state; ++ start_cpu = i; ++ } ++ } ++ /* print the trailing cpus, ignoring them if they are all offline */ ++ if (prev_state != 'F') { ++ if (!first_print) ++ kdb_printf(", "); ++ kdb_printf("%d", start_cpu); ++ if (start_cpu < i-1) ++ kdb_printf("-%d", i-1); ++ if (prev_state != ' ') ++ kdb_printf("(%c)", prev_state); ++ } ++ kdb_printf("\n"); ++} ++ ++static int ++kdb_cpu(int argc, const char **argv) ++{ ++ unsigned long cpunum; ++ int diag, i; ++ ++ /* ask the other cpus if they are still active */ ++ for (i=0; i NR_CPUS) ++ || !cpu_online(cpunum) ++ || !KDB_STATE_CPU(KDB, cpunum)) ++ return KDB_BADCPUNUM; ++ ++ kdb_new_cpu = cpunum; ++ ++ /* ++ * Switch to other cpu ++ */ ++ return KDB_CMD_CPU; ++} ++ ++/* The user may not realize that ps/bta with no parameters does not print idle ++ * or sleeping system daemon processes, so tell them how many were suppressed. ++ */ ++void ++kdb_ps_suppressed(void) ++{ ++ int idle = 0, daemon = 0; ++ unsigned long mask_I = kdb_task_state_string("I"), ++ mask_M = kdb_task_state_string("M"); ++ unsigned long cpu; ++ const struct task_struct *p, *g; ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (!cpu_online(cpu)) ++ continue; ++ p = kdb_curr_task(cpu); ++ if (kdb_task_state(p, mask_I)) ++ ++idle; ++ } ++ kdb_do_each_thread(g, p) { ++ if (kdb_task_state(p, mask_M)) ++ ++daemon; ++ } kdb_while_each_thread(g, p); ++ if (idle || daemon) { ++ if (idle) ++ kdb_printf("%d idle process%s (state I)%s\n", ++ idle, idle == 1 ? "" : "es", ++ daemon ? " and " : ""); ++ if (daemon) ++ kdb_printf("%d sleeping system daemon (state M) process%s", ++ daemon, daemon == 1 ? "" : "es"); ++ kdb_printf(" suppressed,\nuse 'ps A' to see all.\n"); ++ } ++} ++ ++/* ++ * kdb_ps ++ * ++ * This function implements the 'ps' command which shows ++ * a list of the active processes. ++ * ++ * ps [DRSTCZEUIMA] All processes, optionally filtered by state ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++void ++kdb_ps1(const struct task_struct *p) ++{ ++ struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p); ++ kdb_printf("0x%p %8d %8d %d %4d %c 0x%p %c%s\n", ++ (void *)p, p->pid, p->parent->pid, ++ kdb_task_has_cpu(p), kdb_process_cpu(p), ++ kdb_task_state_char(p), ++ (void *)(&p->thread), ++ p == kdb_curr_task(smp_processor_id()) ? '*': ' ', ++ p->comm); ++ if (kdb_task_has_cpu(p)) { ++ if (!krp->seqno || !krp->p) ++ kdb_printf(" Error: no saved data for this cpu\n"); ++ else { ++ if (krp->seqno < kdb_seqno - 1) ++ kdb_printf(" Warning: process state is stale\n"); ++ if (krp->p != p) ++ kdb_printf(" Error: does not match running process table (0x%p)\n", krp->p); ++ } ++ } ++} ++ ++static int ++kdb_ps(int argc, const char **argv) ++{ ++ struct task_struct *g, *p; ++ unsigned long mask, cpu; ++ ++ if (argc == 0) ++ kdb_ps_suppressed(); ++ kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n", ++ (int)(2*sizeof(void *))+2, "Task Addr", ++ (int)(2*sizeof(void *))+2, "Thread"); ++ mask = kdb_task_state_string(argc ? argv[1] : NULL); ++ /* Run the active tasks first */ ++ for (cpu = 0; cpu < NR_CPUS; ++cpu) { ++ if (!cpu_online(cpu)) ++ continue; ++ p = kdb_curr_task(cpu); ++ if (kdb_task_state(p, mask)) ++ kdb_ps1(p); ++ } ++ kdb_printf("\n"); ++ /* Now the real tasks */ ++ kdb_do_each_thread(g, p) { ++ if (kdb_task_state(p, mask)) ++ kdb_ps1(p); ++ } kdb_while_each_thread(g, p); ++ ++ return 0; ++} ++ ++/* ++ * kdb_pid ++ * ++ * This function implements the 'pid' command which switches ++ * the currently active process. ++ * ++ * pid [ | R] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++ ++static int ++kdb_pid(int argc, const char **argv) ++{ ++ struct task_struct *p; ++ unsigned long val; ++ int diag; ++ ++ if (argc > 1) ++ return KDB_ARGCOUNT; ++ ++ if (argc) { ++ if (strcmp(argv[1], "R") == 0) { ++ p = KDB_RUNNING_PROCESS_ORIGINAL[kdb_initial_cpu].p; ++ } else { ++ diag = kdbgetularg(argv[1], &val); ++ if (diag) ++ return KDB_BADINT; ++ ++ p = find_task_by_pid_type_ns(PIDTYPE_PID, (pid_t)val, ++ &init_pid_ns); ++ if (!p) { ++ kdb_printf("No task with pid=%d\n", (pid_t)val); ++ return 0; ++ } ++ } ++ ++ kdba_set_current_task(p); ++ } ++ ++ kdb_printf("KDB current process is %s(pid=%d)\n", kdb_current_task->comm, ++ kdb_current_task->pid); ++ ++ return 0; ++} ++ ++/* ++ * kdb_ll ++ * ++ * This function implements the 'll' command which follows a linked ++ * list and executes an arbitrary command for each element. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_ll(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ kdb_machreg_t va; ++ unsigned long linkoffset; ++ int nextarg; ++ const char *command; ++ ++ if (argc != 3) { ++ return KDB_ARGCOUNT; ++ } ++ ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ ++ diag = kdbgetularg(argv[2], &linkoffset); ++ if (diag) ++ return diag; ++ ++ /* ++ * Using the starting address as ++ * the first element in the list, and assuming that ++ * the list ends with a null pointer. ++ */ ++ ++ va = addr; ++ if (!(command = kdb_strdup(argv[3], GFP_KDB))) { ++ kdb_printf("%s: cannot duplicate command\n", __FUNCTION__); ++ return 0; ++ } ++ /* Recursive use of kdb_parse, do not use argv after this point */ ++ argv = NULL; ++ ++ while (va) { ++ char buf[80]; ++ ++ sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va); ++ diag = kdb_parse(buf); ++ if (diag) ++ return diag; ++ ++ addr = va + linkoffset; ++ if (kdb_getword(&va, addr, sizeof(va))) ++ return 0; ++ } ++ kfree(command); ++ ++ return 0; ++} ++ ++/* ++ * kdb_help ++ * ++ * This function implements the 'help' and '?' commands. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_help(int argc, const char **argv) ++{ ++ kdbtab_t *kt; ++ int i; ++ ++ kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description"); ++ kdb_printf("----------------------------------------------------------\n"); ++ for(i=0, kt=kdb_commands; icmd_name) ++ kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name, ++ kt->cmd_usage, kt->cmd_help); ++ } ++ return 0; ++} ++ ++extern int kdb_wake_up_process(struct task_struct * p); ++ ++/* ++ * kdb_kill ++ * ++ * This function implements the 'kill' commands. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_kill(int argc, const char **argv) ++{ ++ long sig, pid; ++ char *endp; ++ struct task_struct *p; ++ struct siginfo info; ++ ++ if (argc!=2) ++ return KDB_ARGCOUNT; ++ ++ sig = simple_strtol(argv[1], &endp, 0); ++ if (*endp) ++ return KDB_BADINT; ++ if (sig >= 0 ) { ++ kdb_printf("Invalid signal parameter.<-signal>\n"); ++ return 0; ++ } ++ sig=-sig; ++ ++ pid = simple_strtol(argv[2], &endp, 0); ++ if (*endp) ++ return KDB_BADINT; ++ if (pid <=0 ) { ++ kdb_printf("Process ID must be large than 0.\n"); ++ return 0; ++ } ++ ++ /* Find the process. */ ++ if (!(p = find_task_by_pid_type_ns(PIDTYPE_PID, pid, &init_pid_ns))) { ++ kdb_printf("The specified process isn't found.\n"); ++ return 0; ++ } ++ p = p->group_leader; ++ info.si_signo = sig; ++ info.si_errno = 0; ++ info.si_code = SI_USER; ++ info.si_pid = pid; /* use same capabilities as process being signalled */ ++ info.si_uid = 0; /* kdb has root authority */ ++ kdb_send_sig_info(p, &info, kdb_seqno); ++ return 0; ++} ++ ++struct kdb_tm { ++ int tm_sec; /* seconds */ ++ int tm_min; /* minutes */ ++ int tm_hour; /* hours */ ++ int tm_mday; /* day of the month */ ++ int tm_mon; /* month */ ++ int tm_year; /* year */ ++}; ++ ++static void ++kdb_gmtime(struct timespec *tv, struct kdb_tm *tm) ++{ ++ /* This will work from 1970-2099, 2100 is not a leap year */ ++ static int mon_day[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; ++ memset(tm, 0, sizeof(*tm)); ++ tm->tm_sec = tv->tv_sec % (24 * 60 * 60); ++ tm->tm_mday = tv->tv_sec / (24 * 60 * 60) + (2 * 365 + 1); /* shift base from 1970 to 1968 */ ++ tm->tm_min = tm->tm_sec / 60 % 60; ++ tm->tm_hour = tm->tm_sec / 60 / 60; ++ tm->tm_sec = tm->tm_sec % 60; ++ tm->tm_year = 68 + 4*(tm->tm_mday / (4*365+1)); ++ tm->tm_mday %= (4*365+1); ++ mon_day[1] = 29; ++ while (tm->tm_mday >= mon_day[tm->tm_mon]) { ++ tm->tm_mday -= mon_day[tm->tm_mon]; ++ if (++tm->tm_mon == 12) { ++ tm->tm_mon = 0; ++ ++tm->tm_year; ++ mon_day[1] = 28; ++ } ++ } ++ ++tm->tm_mday; ++} ++ ++/* ++ * Most of this code has been lifted from kernel/timer.c::sys_sysinfo(). ++ * I cannot call that code directly from kdb, it has an unconditional ++ * cli()/sti() and calls routines that take locks which can stop the debugger. ++ */ ++ ++static void ++kdb_sysinfo(struct sysinfo *val) ++{ ++ struct timespec uptime; ++ do_posix_clock_monotonic_gettime(&uptime); ++ memset(val, 0, sizeof(*val)); ++ val->uptime = uptime.tv_sec; ++ val->loads[0] = avenrun[0]; ++ val->loads[1] = avenrun[1]; ++ val->loads[2] = avenrun[2]; ++ val->procs = nr_threads-1; ++ si_meminfo(val); ++ kdb_si_swapinfo(val); ++ ++ return; ++} ++ ++/* ++ * kdb_summary ++ * ++ * This function implements the 'summary' command. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_summary(int argc, const char **argv) ++{ ++ extern struct timespec xtime; ++ extern struct timezone sys_tz; ++ struct kdb_tm tm; ++ struct sysinfo val; ++ ++ if (argc) ++ return KDB_ARGCOUNT; ++ ++ kdb_printf("sysname %s\n", init_uts_ns.name.sysname); ++ kdb_printf("release %s\n", init_uts_ns.name.release); ++ kdb_printf("version %s\n", init_uts_ns.name.version); ++ kdb_printf("machine %s\n", init_uts_ns.name.machine); ++ kdb_printf("nodename %s\n", init_uts_ns.name.nodename); ++ kdb_printf("domainname %s\n", init_uts_ns.name.domainname); ++ kdb_printf("ccversion %s\n", __stringify(CCVERSION)); ++ ++ kdb_gmtime(&xtime, &tm); ++ kdb_printf("date %04d-%02d-%02d %02d:%02d:%02d tz_minuteswest %d\n", ++ 1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday, ++ tm.tm_hour, tm.tm_min, tm.tm_sec, ++ sys_tz.tz_minuteswest); ++ ++ kdb_sysinfo(&val); ++ kdb_printf("uptime "); ++ if (val.uptime > (24*60*60)) { ++ int days = val.uptime / (24*60*60); ++ val.uptime %= (24*60*60); ++ kdb_printf("%d day%s ", days, days == 1 ? "" : "s"); ++ } ++ kdb_printf("%02ld:%02ld\n", val.uptime/(60*60), (val.uptime/60)%60); ++ ++ /* lifted from fs/proc/proc_misc.c::loadavg_read_proc() */ ++ ++#define LOAD_INT(x) ((x) >> FSHIFT) ++#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) ++ kdb_printf("load avg %ld.%02ld %ld.%02ld %ld.%02ld\n", ++ LOAD_INT(val.loads[0]), LOAD_FRAC(val.loads[0]), ++ LOAD_INT(val.loads[1]), LOAD_FRAC(val.loads[1]), ++ LOAD_INT(val.loads[2]), LOAD_FRAC(val.loads[2])); ++ kdb_printf("\n"); ++#undef LOAD_INT ++#undef LOAD_FRAC ++ ++ kdb_meminfo_read_proc(); /* in fs/proc/proc_misc.c */ ++ ++ return 0; ++} ++ ++/* ++ * kdb_per_cpu ++ * ++ * This function implements the 'per_cpu' command. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdb_per_cpu(int argc, const char **argv) ++{ ++ char buf[256], fmtstr[64]; ++ kdb_symtab_t symtab; ++ cpumask_t suppress = CPU_MASK_NONE; ++ int cpu, diag; ++ unsigned long addr, val, bytesperword = 0, whichcpu = ~0UL; ++ ++ if (argc < 1 || argc > 3) ++ return KDB_ARGCOUNT; ++ ++ snprintf(buf, sizeof(buf), "per_cpu__%s", argv[1]); ++ if (!kdbgetsymval(buf, &symtab)) { ++ kdb_printf("%s is not a per_cpu variable\n", argv[1]); ++ return KDB_BADADDR; ++ } ++ if (argc >=2 && (diag = kdbgetularg(argv[2], &bytesperword))) ++ return diag; ++ if (!bytesperword) ++ bytesperword = KDB_WORD_SIZE; ++ else if (bytesperword > KDB_WORD_SIZE) ++ return KDB_BADWIDTH; ++ sprintf(fmtstr, "%%0%dlx ", (int)(2*bytesperword)); ++ if (argc >= 3) { ++ if ((diag = kdbgetularg(argv[3], &whichcpu))) ++ return diag; ++ if (!cpu_online(whichcpu)) { ++ kdb_printf("cpu %ld is not online\n", whichcpu); ++ return KDB_BADCPUNUM; ++ } ++ } ++ ++ /* Most architectures use __per_cpu_offset[cpu], some use ++ * __per_cpu_offset(cpu), smp has no __per_cpu_offset. ++ */ ++#ifdef __per_cpu_offset ++#define KDB_PCU(cpu) __per_cpu_offset(cpu) ++#else ++#ifdef CONFIG_SMP ++#define KDB_PCU(cpu) __per_cpu_offset[cpu] ++#else ++#define KDB_PCU(cpu) 0 ++#endif ++#endif ++ ++ for_each_online_cpu(cpu) { ++ if (whichcpu != ~0UL && whichcpu != cpu) ++ continue; ++ addr = symtab.sym_start + KDB_PCU(cpu); ++ if ((diag = kdb_getword(&val, addr, bytesperword))) { ++ kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to read, diag=%d\n", ++ cpu, addr, diag); ++ continue; ++ } ++#ifdef CONFIG_SMP ++ if (!val) { ++ cpu_set(cpu, suppress); ++ continue; ++ } ++#endif /* CONFIG_SMP */ ++ kdb_printf("%5d ", cpu); ++ kdb_md_line(fmtstr, addr, ++ bytesperword == KDB_WORD_SIZE, ++ 1, bytesperword, 1, 1, 0); ++ } ++ if (cpus_weight(suppress) == 0) ++ return 0; ++ kdb_printf("Zero suppressed cpu(s):"); ++ for (cpu = first_cpu(suppress); cpu < NR_CPUS; cpu = next_cpu(cpu, suppress)) { ++ kdb_printf(" %d", cpu); ++ if (cpu == NR_CPUS-1 || next_cpu(cpu, suppress) != cpu + 1) ++ continue; ++ while (cpu < NR_CPUS && next_cpu(cpu, suppress) == cpu + 1) ++ ++cpu; ++ kdb_printf("-%d", cpu); ++ } ++ kdb_printf("\n"); ++ ++#undef KDB_PCU ++ ++ return 0; ++} ++ ++/* ++ * display help for the use of cmd | grep pattern ++ */ ++static int ++kdb_grep_help(int argc, const char **argv) ++{ ++ kdb_printf ("Usage of cmd args | grep pattern:\n"); ++ kdb_printf (" Any command's output may be filtered through an "); ++ kdb_printf ("emulated 'pipe'.\n"); ++ kdb_printf (" 'grep' is just a key word.\n"); ++ kdb_printf ++ (" The pattern may include a very limited set of metacharacters:\n"); ++ kdb_printf (" pattern or ^pattern or pattern$ or ^pattern$\n"); ++ kdb_printf ++ (" And if there are spaces in the pattern, you may quote it:\n"); ++ kdb_printf ++ (" \"pat tern\" or \"^pat tern\" or \"pat tern$\" or \"^pat tern$\"\n"); ++ return 0; ++} ++ ++/* ++ * kdb_register_repeat ++ * ++ * This function is used to register a kernel debugger command. ++ * ++ * Inputs: ++ * cmd Command name ++ * func Function to execute the command ++ * usage A simple usage string showing arguments ++ * help A simple help string describing command ++ * repeat Does the command auto repeat on enter? ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, one if a duplicate command. ++ * Locking: ++ * none. ++ * Remarks: ++ * ++ */ ++ ++#define kdb_command_extend 50 /* arbitrary */ ++int ++kdb_register_repeat(char *cmd, ++ kdb_func_t func, ++ char *usage, ++ char *help, ++ short minlen, ++ kdb_repeat_t repeat) ++{ ++ int i; ++ kdbtab_t *kp; ++ ++ /* ++ * Brute force method to determine duplicates ++ */ ++ for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { ++ kdb_printf("Duplicate kdb command registered: " ++ "%s, func %p help %s\n", cmd, func, help); ++ return 1; ++ } ++ } ++ ++ /* ++ * Insert command into first available location in table ++ */ ++ for (i=0, kp=kdb_commands; icmd_name == NULL) { ++ break; ++ } ++ } ++ ++ if (i >= kdb_max_commands) { ++ kdbtab_t *new = kmalloc((kdb_max_commands + kdb_command_extend) * sizeof(*new), GFP_KDB); ++ if (!new) { ++ kdb_printf("Could not allocate new kdb_command table\n"); ++ return 1; ++ } ++ if (kdb_commands) { ++ memcpy(new, kdb_commands, kdb_max_commands * sizeof(*new)); ++ kfree(kdb_commands); ++ } ++ memset(new + kdb_max_commands, 0, kdb_command_extend * sizeof(*new)); ++ kdb_commands = new; ++ kp = kdb_commands + kdb_max_commands; ++ kdb_max_commands += kdb_command_extend; ++ } ++ ++ kp->cmd_name = cmd; ++ kp->cmd_func = func; ++ kp->cmd_usage = usage; ++ kp->cmd_help = help; ++ kp->cmd_flags = 0; ++ kp->cmd_minlen = minlen; ++ kp->cmd_repeat = repeat; ++ ++ return 0; ++} ++ ++/* ++ * kdb_register ++ * ++ * Compatibility register function for commands that do not need to ++ * specify a repeat state. Equivalent to kdb_register_repeat with ++ * KDB_REPEAT_NONE. ++ * ++ * Inputs: ++ * cmd Command name ++ * func Function to execute the command ++ * usage A simple usage string showing arguments ++ * help A simple help string describing command ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, one if a duplicate command. ++ * Locking: ++ * none. ++ * Remarks: ++ * ++ */ ++ ++int ++kdb_register(char *cmd, ++ kdb_func_t func, ++ char *usage, ++ char *help, ++ short minlen) ++{ ++ return kdb_register_repeat(cmd, func, usage, help, minlen, KDB_REPEAT_NONE); ++} ++ ++/* ++ * kdb_unregister ++ * ++ * This function is used to unregister a kernel debugger command. ++ * It is generally called when a module which implements kdb ++ * commands is unloaded. ++ * ++ * Inputs: ++ * cmd Command name ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, one command not registered. ++ * Locking: ++ * none. ++ * Remarks: ++ * ++ */ ++ ++int ++kdb_unregister(char *cmd) ++{ ++ int i; ++ kdbtab_t *kp; ++ ++ /* ++ * find the command. ++ */ ++ for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { ++ kp->cmd_name = NULL; ++ return 0; ++ } ++ } ++ ++ /* ++ * Couldn't find it. ++ */ ++ return 1; ++} ++ ++/* ++ * kdb_inittab ++ * ++ * This function is called by the kdb_init function to initialize ++ * the kdb command table. It must be called prior to any other ++ * call to kdb_register_repeat. ++ * ++ * Inputs: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ */ ++ ++static void __init ++kdb_inittab(void) ++{ ++ int i; ++ kdbtab_t *kp; ++ ++ for(i=0, kp=kdb_commands; i < kdb_max_commands; i++,kp++) { ++ kp->cmd_name = NULL; ++ } ++ ++ kdb_register_repeat("md", kdb_md, "", "Display Memory Contents, also mdWcN, e.g. md8c1", 1, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("mdr", kdb_md, " ", "Display Raw Memory", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("mdp", kdb_md, " ", "Display Physical Memory", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("mds", kdb_md, "", "Display Memory Symbolically", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("mm", kdb_mm, " ", "Modify Memory Contents", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("id", kdb_id, "", "Display Instructions", 1, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("go", kdb_go, "[]", "Continue Execution", 1, KDB_REPEAT_NONE); ++ kdb_register_repeat("rd", kdb_rd, "", "Display Registers", 1, KDB_REPEAT_NONE); ++ kdb_register_repeat("rm", kdb_rm, " ", "Modify Registers", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("ef", kdb_ef, "", "Display exception frame", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("bt", kdb_bt, "[]", "Stack traceback", 1, KDB_REPEAT_NONE); ++ kdb_register_repeat("btp", kdb_bt, "", "Display stack for process ", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("bta", kdb_bt, "[DRSTCZEUIMA]", "Display stack all processes", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("btc", kdb_bt, "", "Backtrace current process on each cpu", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("btt", kdb_bt, "", "Backtrace process given its struct task address", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("ll", kdb_ll, " ", "Execute cmd for each element in linked list", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("env", kdb_env, "", "Show environment variables", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("set", kdb_set, "", "Set environment variables", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("help", kdb_help, "", "Display Help Message", 1, KDB_REPEAT_NONE); ++ kdb_register_repeat("?", kdb_help, "", "Display Help Message", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("cpu", kdb_cpu, "","Switch to new cpu", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("ps", kdb_ps, "[|A]", "Display active task list", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("pid", kdb_pid, "", "Switch to another task", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("reboot", kdb_reboot, "", "Reboot the machine immediately", 0, KDB_REPEAT_NONE); ++#if defined(CONFIG_KDB_KDUMP) ++ kdb_register_repeat("kdump", kdb_kdump, "", "Calls kdump mode", 0, KDB_REPEAT_NONE); ++#endif ++#if defined(CONFIG_MODULES) ++ kdb_register_repeat("lsmod", kdb_lsmod, "", "List loaded kernel modules", 0, KDB_REPEAT_NONE); ++#endif ++#if defined(CONFIG_MAGIC_SYSRQ) ++ kdb_register_repeat("sr", kdb_sr, "", "Magic SysRq key", 0, KDB_REPEAT_NONE); ++#endif ++ kdb_register_repeat("dmesg", kdb_dmesg, "[lines]", "Display syslog buffer", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"", "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("kill", kdb_kill, "<-signal> ", "Send a signal to a process", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("summary", kdb_summary, "", "Summarize the system", 4, KDB_REPEAT_NONE); ++ kdb_register_repeat("per_cpu", kdb_per_cpu, "", "Display per_cpu variables", 3, KDB_REPEAT_NONE); ++ kdb_register_repeat("grephelp", kdb_grep_help, "", ++ "Display help on | grep", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("print", kdb_debuginfo_print, "", ++ "Type casting, as in lcrash", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("px", kdb_debuginfo_print, "", ++ "Print in hex (type casting) (see 'pxhelp')", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("pxhelp", kdb_pxhelp, "", ++ "Display help for the px command", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("pd", kdb_debuginfo_print, "", ++ "Print in decimal (type casting)", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("whatis", kdb_debuginfo_print,"", ++ "Display the type, or the address for a symbol", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("sizeof", kdb_debuginfo_print, "", ++ "Display the size of a structure, typedef, etc.", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("walk", kdb_walk, "", ++ "Walk a linked list (see 'walkhelp')", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("walkhelp", kdb_walkhelp, "", ++ "Display help for the walk command", 0, KDB_REPEAT_NONE); ++} ++ ++/* ++ * The user has written to our "file" ++ * file: the /proc file ++ * buffer: user address of the data he is writing ++ * count: number of bytes in the user's buffer ++ */ ++static int ++kdb_write_proc_filename(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ int ret_count; ++ ++ /* our buffer is kdb_debug_info_filename[256] */ ++ if (count > 256) { ++ return 0; ++ } ++ if (copy_from_user(kdb_debug_info_filename, buffer, count)) { ++ return 0; ++ } ++ ret_count = count; /* actual count */ ++ /* remove any newline from the end of the file name */ ++ if (kdb_debug_info_filename[count-1] == '\n') count--; ++ kdb_debug_info_filename[count] = '\0'; ++ ++ return ret_count; ++} ++ ++/* ++ * The user is reading from our "file" ++ * page: the beginning of the user's buffer ++ * start: pointer to the user's pointer (tells him where we put the data) ++ * off: offset into the resource to be read ++ * count: length of the read ++ */ ++static int ++kdb_read_proc_filename(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ /* give him kdb_debug_info_filename[]; */ ++ return snprintf(page, count, "%s\n", kdb_debug_info_filename); ++} ++ ++/* ++ * kdb_proc_filename ++ * ++ * create /proc/kdb/debug_info_name ++ */ ++static void ++kdb_proc_filename(void) ++{ ++ struct proc_dir_entry *kdb_dir_entry, *kdb_file_entry; ++ ++ /* create /proc/kdb */ ++ kdb_dir_entry = proc_mkdir("kdb", NULL); ++ if (!kdb_dir_entry) { ++ printk ("kdb could not create /proc/kdb\n"); ++ return; ++ } ++ ++ /* read/write by owner (root) only */ ++ kdb_file_entry = create_proc_entry("debug_info_name", ++ S_IRUSR | S_IWUSR, kdb_dir_entry); ++ if (!kdb_file_entry) { ++ printk ("kdb could not create /proc/kdb/kdb_dir_entry\n"); ++ return; ++ } ++ kdb_file_entry->nlink = 1; ++ kdb_file_entry->data = (void *)NULL; ++ kdb_file_entry->read_proc = kdb_read_proc_filename; ++ kdb_file_entry->write_proc = kdb_write_proc_filename; ++ return; ++} ++ ++/* ++ * kdb_cmd_init ++ * ++ * This function is called by the kdb_init function to execute any ++ * commands defined in kdb_cmds. ++ * ++ * Inputs: ++ * Commands in *kdb_cmds[]; ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ */ ++ ++static void __init ++kdb_cmd_init(void) ++{ ++ int i, diag; ++ for (i = 0; kdb_cmds[i]; ++i) { ++ if (!defcmd_in_progress) ++ if (console_loglevel >= 6 /* KERN_INFO */) ++ kdb_printf("kdb_cmd[%d]: %s", i, kdb_cmds[i]); ++ diag = kdb_parse(kdb_cmds[i]); ++ if (diag) ++ kdb_printf("kdb command %s failed, kdb diag %d\n", ++ kdb_cmds[i], diag); ++ } ++ if (defcmd_in_progress) { ++ kdb_printf("Incomplete 'defcmd' set, forcing endefcmd\n"); ++ kdb_parse("endefcmd"); ++ } ++} ++ ++/* ++ * kdb_panic ++ * ++ * Invoked via the panic_notifier_list. ++ * ++ * Inputs: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero. ++ * Locking: ++ * None. ++ * Remarks: ++ * When this function is called from panic(), the other cpus have already ++ * been stopped. ++ * ++ */ ++ ++static int ++kdb_panic(struct notifier_block *self, unsigned long command, void *ptr) ++{ ++ KDB_FLAG_SET(CATASTROPHIC); /* kernel state is dubious now */ ++ KDB_ENTER(); ++ return 0; ++} ++ ++static struct notifier_block kdb_block = { kdb_panic, NULL, 0 }; ++ ++#ifdef CONFIG_SYSCTL ++static int proc_do_kdb(ctl_table *table, int write, struct file *filp, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ if (KDB_FLAG(NO_CONSOLE) && write) { ++ printk(KERN_ERR "kdb has no working console and has switched itself off\n"); ++ return -EINVAL; ++ } ++ return proc_dointvec(table, write, filp, buffer, lenp, ppos); ++} ++ ++static ctl_table kdb_kern_table[] = { ++ { ++ .ctl_name = KERN_KDB, ++ .procname = "kdb", ++ .data = &kdb_on, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_do_kdb, ++ .strategy = &sysctl_intvec, ++ }, ++ {} ++}; ++ ++static ctl_table kdb_root_table[] = { ++ { ++ .ctl_name = CTL_KERN, ++ .procname = "kernel", ++ .mode = 0555, ++ .child = kdb_kern_table, ++ }, ++ {} ++}; ++#endif /* CONFIG_SYSCTL */ ++ ++static int ++kdb_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) ++{ ++ if (action == CPU_ONLINE) { ++ int cpu =(unsigned long)hcpu; ++ cpumask_t save_cpus_allowed = current->cpus_allowed; ++ cpumask_t new_cpus_allowed = cpumask_of_cpu(cpu); ++ set_cpus_allowed(current, new_cpus_allowed); ++ kdb(KDB_REASON_CPU_UP, 0, NULL); /* do kdb setup on this cpu */ ++ set_cpus_allowed(current, save_cpus_allowed); ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block kdb_cpu_nfb = { ++ .notifier_call = kdb_cpu_callback ++}; ++ ++/* ++ * kdb_init ++ * ++ * Initialize the kernel debugger environment. ++ * ++ * Parameters: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * None. ++ */ ++ ++void __init ++kdb_init(void) ++{ ++ kdb_initial_cpu = smp_processor_id(); ++ /* ++ * This must be called before any calls to kdb_printf. ++ */ ++ kdb_io_init(); ++ ++ kdb_inittab(); /* Initialize Command Table */ ++ kdb_initbptab(); /* Initialize Breakpoint Table */ ++ kdb_id_init(); /* Initialize Disassembler */ ++ kdba_init(); /* Architecture Dependent Initialization */ ++ ++ /* ++ * Use printk() to get message in log_buf[]; ++ */ ++ printk("kdb version %d.%d%s by Keith Owens, Scott Lurndal. "\ ++ "Copyright SGI, All Rights Reserved\n", ++ KDB_MAJOR_VERSION, KDB_MINOR_VERSION, KDB_TEST_VERSION); ++ ++ kdb_cmd_init(); /* Preset commands from kdb_cmds */ ++ kdb_initial_cpu = -1; /* Avoid recursion problems */ ++ kdb(KDB_REASON_CPU_UP, 0, NULL); /* do kdb setup on boot cpu */ ++ kdb_initial_cpu = smp_processor_id(); ++ atomic_notifier_chain_register(&panic_notifier_list, &kdb_block); ++ register_cpu_notifier(&kdb_cpu_nfb); ++ ++#ifdef kdba_setjmp ++ kdbjmpbuf = vmalloc(NR_CPUS * sizeof(*kdbjmpbuf)); ++ if (!kdbjmpbuf) ++ printk(KERN_ERR "Cannot allocate kdbjmpbuf, no kdb recovery will be possible\n"); ++#endif /* kdba_setjmp */ ++ ++ kdb_initial_cpu = -1; ++ kdb_wait_for_cpus_secs = max(10, 2*num_online_cpus()); ++} ++ ++#ifdef CONFIG_SYSCTL ++static int __init ++kdb_late_init(void) ++{ ++ register_sysctl_table(kdb_root_table); ++ /* seems that we cannot allocate with kmalloc until now */ ++ kdb_proc_filename(); ++ return 0; ++} ++ ++__initcall(kdb_late_init); ++#endif ++ ++EXPORT_SYMBOL(kdb_register); ++EXPORT_SYMBOL(kdb_register_repeat); ++EXPORT_SYMBOL(kdb_unregister); ++EXPORT_SYMBOL(kdb_getarea_size); ++EXPORT_SYMBOL(kdb_putarea_size); ++EXPORT_SYMBOL(kdb_getuserarea_size); ++EXPORT_SYMBOL(kdb_putuserarea_size); ++EXPORT_SYMBOL(kdbgetularg); ++EXPORT_SYMBOL(kdbgetenv); ++EXPORT_SYMBOL(kdbgetintenv); ++EXPORT_SYMBOL(kdbgetaddrarg); ++EXPORT_SYMBOL(kdb); ++EXPORT_SYMBOL(kdb_on); ++EXPORT_SYMBOL(kdb_seqno); ++EXPORT_SYMBOL(kdb_initial_cpu); ++EXPORT_SYMBOL(kdbnearsym); ++EXPORT_SYMBOL(kdb_printf); ++EXPORT_SYMBOL(kdb_symbol_print); ++EXPORT_SYMBOL(kdb_running_process); +--- /dev/null ++++ b/kdb/kdbsupport.c +@@ -0,0 +1,1154 @@ ++/* ++ * Kernel Debugger Architecture Independent Support Functions ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ * 03/02/13 added new 2.5 kallsyms ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++/* ++ * Symbol table functions. ++ */ ++ ++/* ++ * kdbgetsymval ++ * ++ * Return the address of the given symbol. ++ * ++ * Parameters: ++ * symname Character string containing symbol name ++ * symtab Structure to receive results ++ * Outputs: ++ * Returns: ++ * 0 Symbol not found, symtab zero filled ++ * 1 Symbol mapped to module/symbol/section, data in symtab ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdbgetsymval(const char *symname, kdb_symtab_t *symtab) ++{ ++ if (KDB_DEBUG(AR)) ++ kdb_printf("kdbgetsymval: symname=%s, symtab=%p\n", symname, symtab); ++ memset(symtab, 0, sizeof(*symtab)); ++ ++ if ((symtab->sym_start = kallsyms_lookup_name(symname))) { ++ if (KDB_DEBUG(AR)) ++ kdb_printf("kdbgetsymval: returns 1, symtab->sym_start=0x%lx\n", symtab->sym_start); ++ return 1; ++ } ++ if (KDB_DEBUG(AR)) ++ kdb_printf("kdbgetsymval: returns 0\n"); ++ return 0; ++} ++EXPORT_SYMBOL(kdbgetsymval); ++ ++/* ++ * kdbnearsym ++ * ++ * Return the name of the symbol with the nearest address ++ * less than 'addr'. ++ * ++ * Parameters: ++ * addr Address to check for symbol near ++ * symtab Structure to receive results ++ * Outputs: ++ * Returns: ++ * 0 No sections contain this address, symtab zero filled ++ * 1 Address mapped to module/symbol/section, data in symtab ++ * Locking: ++ * None. ++ * Remarks: ++ * 2.6 kallsyms has a "feature" where it unpacks the name into a string. ++ * If that string is reused before the caller expects it then the caller ++ * sees its string change without warning. To avoid cluttering up the ++ * main kdb code with lots of kdb_strdup, tests and kfree calls, kdbnearsym ++ * maintains an LRU list of the last few unique strings. The list is sized ++ * large enough to hold active strings, no kdb caller of kdbnearsym makes ++ * more than ~20 later calls before using a saved value. ++ */ ++ ++static char *kdb_name_table[100]; /* arbitrary size */ ++ ++int ++kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) ++{ ++ int ret = 0; ++ unsigned long symbolsize; ++ unsigned long offset; ++#define knt1_size 128 /* must be >= kallsyms table size */ ++ char *knt1 = NULL; ++ ++ if (KDB_DEBUG(AR)) ++ kdb_printf("kdbnearsym: addr=0x%lx, symtab=%p\n", addr, symtab); ++ memset(symtab, 0, sizeof(*symtab)); ++ ++ if (addr < 4096) ++ goto out; ++ knt1 = debug_kmalloc(knt1_size, GFP_ATOMIC); ++ if (!knt1) { ++ kdb_printf("kdbnearsym: addr=0x%lx cannot kmalloc knt1\n", addr); ++ goto out; ++ } ++ symtab->sym_name = kallsyms_lookup(addr, &symbolsize , &offset, (char **)(&symtab->mod_name), knt1); ++ if (offset > 8*1024*1024) { ++ symtab->sym_name = NULL; ++ addr = offset = symbolsize = 0; ++ } ++ symtab->sym_start = addr - offset; ++ symtab->sym_end = symtab->sym_start + symbolsize; ++ ret = symtab->sym_name != NULL && *(symtab->sym_name) != '\0'; ++ ++ if (ret) { ++ int i; ++ /* Another 2.6 kallsyms "feature". Sometimes the sym_name is ++ * set but the buffer passed into kallsyms_lookup is not used, ++ * so it contains garbage. The caller has to work out which ++ * buffer needs to be saved. ++ * ++ * What was Rusty smoking when he wrote that code? ++ */ ++ if (symtab->sym_name != knt1) { ++ strncpy(knt1, symtab->sym_name, knt1_size); ++ knt1[knt1_size-1] = '\0'; ++ } ++ for (i = 0; i < ARRAY_SIZE(kdb_name_table); ++i) { ++ if (kdb_name_table[i] && strcmp(kdb_name_table[i], knt1) == 0) ++ break; ++ } ++ if (i >= ARRAY_SIZE(kdb_name_table)) { ++ debug_kfree(kdb_name_table[0]); ++ memcpy(kdb_name_table, kdb_name_table+1, ++ sizeof(kdb_name_table[0])*(ARRAY_SIZE(kdb_name_table)-1)); ++ } else { ++ debug_kfree(knt1); ++ knt1 = kdb_name_table[i]; ++ memcpy(kdb_name_table+i, kdb_name_table+i+1, ++ sizeof(kdb_name_table[0])*(ARRAY_SIZE(kdb_name_table)-i-1)); ++ } ++ i = ARRAY_SIZE(kdb_name_table) - 1; ++ kdb_name_table[i] = knt1; ++ symtab->sym_name = kdb_name_table[i]; ++ knt1 = NULL; ++ } ++ ++ if (symtab->mod_name == NULL) ++ symtab->mod_name = "kernel"; ++ if (KDB_DEBUG(AR)) ++ kdb_printf("kdbnearsym: returns %d symtab->sym_start=0x%lx, symtab->mod_name=%p, symtab->sym_name=%p (%s)\n", ret, symtab->sym_start, symtab->mod_name, symtab->sym_name, symtab->sym_name); ++ ++out: ++ debug_kfree(knt1); ++ return ret; ++} ++ ++void ++kdbnearsym_cleanup(void) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(kdb_name_table); ++i) { ++ if (kdb_name_table[i]) { ++ debug_kfree(kdb_name_table[i]); ++ kdb_name_table[i] = NULL; ++ } ++ } ++} ++ ++/* ++ * kallsyms_symbol_complete ++ * ++ * Parameters: ++ * prefix_name prefix of a symbol name to lookup ++ * max_len maximum length that can be returned ++ * Returns: ++ * Number of symbols which match the given prefix. ++ * Notes: ++ * prefix_name is changed to contain the longest unique prefix that ++ * starts with this prefix (tab completion). ++ */ ++ ++static char ks_namebuf[KSYM_NAME_LEN+1], ks_namebuf_prev[KSYM_NAME_LEN+1]; ++ ++int kallsyms_symbol_complete(char *prefix_name, int max_len) ++{ ++ loff_t pos = 0; ++ int prefix_len = strlen(prefix_name), prev_len = 0; ++ int i, number = 0; ++ const char *name; ++ ++ while ((name = kdb_walk_kallsyms(&pos))) { ++ if (strncmp(name, prefix_name, prefix_len) == 0) { ++ strcpy(ks_namebuf, name); ++ /* Work out the longest name that matches the prefix */ ++ if (++number == 1) { ++ prev_len = min_t(int, max_len-1, strlen(ks_namebuf)); ++ memcpy(ks_namebuf_prev, ks_namebuf, prev_len); ++ ks_namebuf_prev[prev_len] = '\0'; ++ } else for (i = 0; i < prev_len; ++i) { ++ if (ks_namebuf[i] != ks_namebuf_prev[i]) { ++ prev_len = i; ++ ks_namebuf_prev[i] = '\0'; ++ break; ++ } ++ } ++ } ++ } ++ if (prev_len > prefix_len) ++ memcpy(prefix_name, ks_namebuf_prev, prev_len+1); ++ return number; ++} ++ ++/* ++ * kallsyms_symbol_next ++ * ++ * Parameters: ++ * prefix_name prefix of a symbol name to lookup ++ * flag 0 means search from the head, 1 means continue search. ++ * Returns: ++ * 1 if a symbol matches the given prefix. ++ * 0 if no string found ++ */ ++ ++int kallsyms_symbol_next(char *prefix_name, int flag) ++{ ++ int prefix_len = strlen(prefix_name); ++ static loff_t pos; ++ const char *name; ++ ++ if (!flag) ++ pos = 0; ++ ++ while ((name = kdb_walk_kallsyms(&pos))) { ++ if (strncmp(name, prefix_name, prefix_len) == 0) { ++ strncpy(prefix_name, name, strlen(name)+1); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++#if defined(CONFIG_SMP) ++/* ++ * kdb_ipi ++ * ++ * This function is called from the non-maskable interrupt ++ * handler to handle a kdb IPI instruction. ++ * ++ * Inputs: ++ * regs = Exception frame pointer ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 - Did not handle NMI ++ * 1 - Handled NMI ++ * Locking: ++ * None. ++ * Remarks: ++ * Initially one processor is invoked in the kdb() code. That ++ * processor sends an ipi which drives this routine on the other ++ * processors. All this does is call kdb() with reason SWITCH. ++ * This puts all processors into the kdb() routine and all the ++ * code for breakpoints etc. is in one place. ++ * One problem with the way the kdb NMI is sent, the NMI has no ++ * identification that says it came from kdb. If the cpu's kdb state is ++ * marked as "waiting for kdb_ipi" then the NMI is treated as coming from ++ * kdb, otherwise it is assumed to be for another reason and is ignored. ++ */ ++ ++int ++kdb_ipi(struct pt_regs *regs, void (*ack_interrupt)(void)) ++{ ++ /* Do not print before checking and clearing WAIT_IPI, IPIs are ++ * going all the time. ++ */ ++ if (KDB_STATE(WAIT_IPI)) { ++ /* ++ * Stopping other processors via smp_kdb_stop(). ++ */ ++ if (ack_interrupt) ++ (*ack_interrupt)(); /* Acknowledge the interrupt */ ++ KDB_STATE_CLEAR(WAIT_IPI); ++ KDB_DEBUG_STATE("kdb_ipi 1", 0); ++ kdb(KDB_REASON_SWITCH, 0, regs); /* Spin in kdb() */ ++ KDB_DEBUG_STATE("kdb_ipi 2", 0); ++ return 1; ++ } ++ return 0; ++} ++#endif /* CONFIG_SMP */ ++ ++/* ++ * kdb_symbol_print ++ * ++ * Standard method for printing a symbol name and offset. ++ * Inputs: ++ * addr Address to be printed. ++ * symtab Address of symbol data, if NULL this routine does its ++ * own lookup. ++ * punc Punctuation for string, bit field. ++ * Outputs: ++ * None. ++ * Returns: ++ * Always 0. ++ * Locking: ++ * none. ++ * Remarks: ++ * The string and its punctuation is only printed if the address ++ * is inside the kernel, except that the value is always printed ++ * when requested. ++ */ ++ ++void ++kdb_symbol_print(kdb_machreg_t addr, const kdb_symtab_t *symtab_p, unsigned int punc) ++{ ++ kdb_symtab_t symtab, *symtab_p2; ++ if (symtab_p) { ++ symtab_p2 = (kdb_symtab_t *)symtab_p; ++ } ++ else { ++ symtab_p2 = &symtab; ++ kdbnearsym(addr, symtab_p2); ++ } ++ if (symtab_p2->sym_name || (punc & KDB_SP_VALUE)) { ++ ; /* drop through */ ++ } ++ else { ++ return; ++ } ++ if (punc & KDB_SP_SPACEB) { ++ kdb_printf(" "); ++ } ++ if (punc & KDB_SP_VALUE) { ++ kdb_printf(kdb_machreg_fmt0, addr); ++ } ++ if (symtab_p2->sym_name) { ++ if (punc & KDB_SP_VALUE) { ++ kdb_printf(" "); ++ } ++ if (punc & KDB_SP_PAREN) { ++ kdb_printf("("); ++ } ++ if (strcmp(symtab_p2->mod_name, "kernel")) { ++ kdb_printf("[%s]", symtab_p2->mod_name); ++ } ++ kdb_printf("%s", symtab_p2->sym_name); ++ if (addr != symtab_p2->sym_start) { ++ kdb_printf("+0x%lx", addr - symtab_p2->sym_start); ++ } ++ if (punc & KDB_SP_SYMSIZE) { ++ kdb_printf("/0x%lx", symtab_p2->sym_end - symtab_p2->sym_start); ++ } ++ if (punc & KDB_SP_PAREN) { ++ kdb_printf(")"); ++ } ++ } ++ if (punc & KDB_SP_SPACEA) { ++ kdb_printf(" "); ++ } ++ if (punc & KDB_SP_NEWLINE) { ++ kdb_printf("\n"); ++ } ++} ++ ++/* ++ * kdb_strdup ++ * ++ * kdb equivalent of strdup, for disasm code. ++ * Inputs: ++ * str The string to duplicate. ++ * type Flags to kmalloc for the new string. ++ * Outputs: ++ * None. ++ * Returns: ++ * Address of the new string, NULL if storage could not be allocated. ++ * Locking: ++ * none. ++ * Remarks: ++ * This is not in lib/string.c because it uses kmalloc which is not ++ * available when string.o is used in boot loaders. ++ */ ++ ++char *kdb_strdup(const char *str, gfp_t type) ++{ ++ int n = strlen(str)+1; ++ char *s = kmalloc(n, type); ++ if (!s) return NULL; ++ return strcpy(s, str); ++} ++ ++/* ++ * kdb_getarea_size ++ * ++ * Read an area of data. The kdb equivalent of copy_from_user, with ++ * kdb messages for invalid addresses. ++ * Inputs: ++ * res Pointer to the area to receive the result. ++ * addr Address of the area to copy. ++ * size Size of the area. ++ * Outputs: ++ * none. ++ * Returns: ++ * 0 for success, < 0 for error. ++ * Locking: ++ * none. ++ */ ++ ++int kdb_getarea_size(void *res, unsigned long addr, size_t size) ++{ ++ int ret = kdba_getarea_size(res, addr, size); ++ if (ret) { ++ if (!KDB_STATE(SUPPRESS)) { ++ kdb_printf("kdb_getarea: Bad address 0x%lx\n", addr); ++ KDB_STATE_SET(SUPPRESS); ++ } ++ ret = KDB_BADADDR; ++ } ++ else { ++ KDB_STATE_CLEAR(SUPPRESS); ++ } ++ return(ret); ++} ++ ++/* ++ * kdb_putarea_size ++ * ++ * Write an area of data. The kdb equivalent of copy_to_user, with ++ * kdb messages for invalid addresses. ++ * Inputs: ++ * addr Address of the area to write to. ++ * res Pointer to the area holding the data. ++ * size Size of the area. ++ * Outputs: ++ * none. ++ * Returns: ++ * 0 for success, < 0 for error. ++ * Locking: ++ * none. ++ */ ++ ++int kdb_putarea_size(unsigned long addr, void *res, size_t size) ++{ ++ int ret = kdba_putarea_size(addr, res, size); ++ if (ret) { ++ if (!KDB_STATE(SUPPRESS)) { ++ kdb_printf("kdb_putarea: Bad address 0x%lx\n", addr); ++ KDB_STATE_SET(SUPPRESS); ++ } ++ ret = KDB_BADADDR; ++ } ++ else { ++ KDB_STATE_CLEAR(SUPPRESS); ++ } ++ return(ret); ++} ++ ++/* ++ * kdb_getphys ++ * ++ * Read data from a physical address. Validate the address is in range, ++ * use kmap_atomic() to get data ++ * ++ * Similar to kdb_getarea() - but for phys addresses ++ * ++ * Inputs: ++ * res Pointer to the word to receive the result ++ * addr Physical address of the area to copy ++ * size Size of the area ++ * Outputs: ++ * none. ++ * Returns: ++ * 0 for success, < 0 for error. ++ * Locking: ++ * none. ++ */ ++static int kdb_getphys(void *res, unsigned long addr, size_t size) ++{ ++ unsigned long pfn; ++ void *vaddr; ++ struct page *page; ++ ++ pfn = (addr >> PAGE_SHIFT); ++ if (!pfn_valid(pfn)) ++ return 1; ++ page = pfn_to_page(pfn); ++ vaddr = kmap_atomic(page, KM_KDB); ++ memcpy(res, vaddr + (addr & (PAGE_SIZE -1)), size); ++ kunmap_atomic(vaddr, KM_KDB); ++ ++ return 0; ++} ++ ++/* ++ * kdb_getphysword ++ * ++ * Inputs: ++ * word Pointer to the word to receive the result. ++ * addr Address of the area to copy. ++ * size Size of the area. ++ * Outputs: ++ * none. ++ * Returns: ++ * 0 for success, < 0 for error. ++ * Locking: ++ * none. ++ */ ++int kdb_getphysword(unsigned long *word, unsigned long addr, size_t size) ++{ ++ int diag; ++ __u8 w1; ++ __u16 w2; ++ __u32 w4; ++ __u64 w8; ++ *word = 0; /* Default value if addr or size is invalid */ ++ ++ switch (size) { ++ case 1: ++ if (!(diag = kdb_getphys(&w1, addr, sizeof(w1)))) ++ *word = w1; ++ break; ++ case 2: ++ if (!(diag = kdb_getphys(&w2, addr, sizeof(w2)))) ++ *word = w2; ++ break; ++ case 4: ++ if (!(diag = kdb_getphys(&w4, addr, sizeof(w4)))) ++ *word = w4; ++ break; ++ case 8: ++ if (size <= sizeof(*word)) { ++ if (!(diag = kdb_getphys(&w8, addr, sizeof(w8)))) ++ *word = w8; ++ break; ++ } ++ /* drop through */ ++ default: ++ diag = KDB_BADWIDTH; ++ kdb_printf("kdb_getphysword: bad width %ld\n", (long) size); ++ } ++ return(diag); ++} ++ ++/* ++ * kdb_getword ++ * ++ * Read a binary value. Unlike kdb_getarea, this treats data as numbers. ++ * Inputs: ++ * word Pointer to the word to receive the result. ++ * addr Address of the area to copy. ++ * size Size of the area. ++ * Outputs: ++ * none. ++ * Returns: ++ * 0 for success, < 0 for error. ++ * Locking: ++ * none. ++ */ ++ ++int kdb_getword(unsigned long *word, unsigned long addr, size_t size) ++{ ++ int diag; ++ __u8 w1; ++ __u16 w2; ++ __u32 w4; ++ __u64 w8; ++ *word = 0; /* Default value if addr or size is invalid */ ++ switch (size) { ++ case 1: ++ if (!(diag = kdb_getarea(w1, addr))) ++ *word = w1; ++ break; ++ case 2: ++ if (!(diag = kdb_getarea(w2, addr))) ++ *word = w2; ++ break; ++ case 4: ++ if (!(diag = kdb_getarea(w4, addr))) ++ *word = w4; ++ break; ++ case 8: ++ if (size <= sizeof(*word)) { ++ if (!(diag = kdb_getarea(w8, addr))) ++ *word = w8; ++ break; ++ } ++ /* drop through */ ++ default: ++ diag = KDB_BADWIDTH; ++ kdb_printf("kdb_getword: bad width %ld\n", (long) size); ++ } ++ return(diag); ++} ++ ++/* ++ * kdb_putword ++ * ++ * Write a binary value. Unlike kdb_putarea, this treats data as numbers. ++ * Inputs: ++ * addr Address of the area to write to.. ++ * word The value to set. ++ * size Size of the area. ++ * Outputs: ++ * none. ++ * Returns: ++ * 0 for success, < 0 for error. ++ * Locking: ++ * none. ++ */ ++ ++int kdb_putword(unsigned long addr, unsigned long word, size_t size) ++{ ++ int diag; ++ __u8 w1; ++ __u16 w2; ++ __u32 w4; ++ __u64 w8; ++ switch (size) { ++ case 1: ++ w1 = word; ++ diag = kdb_putarea(addr, w1); ++ break; ++ case 2: ++ w2 = word; ++ diag = kdb_putarea(addr, w2); ++ break; ++ case 4: ++ w4 = word; ++ diag = kdb_putarea(addr, w4); ++ break; ++ case 8: ++ if (size <= sizeof(word)) { ++ w8 = word; ++ diag = kdb_putarea(addr, w8); ++ break; ++ } ++ /* drop through */ ++ default: ++ diag = KDB_BADWIDTH; ++ kdb_printf("kdb_putword: bad width %ld\n", (long) size); ++ } ++ return(diag); ++} ++ ++/* ++ * kdb_task_state_string ++ * ++ * Convert a string containing any of the letters DRSTCZEUIMA to a mask ++ * for the process state field and return the value. If no argument is ++ * supplied, return the mask that corresponds to environment variable PS, ++ * DRSTCZEU by default. ++ * Inputs: ++ * s String to convert ++ * Outputs: ++ * none. ++ * Returns: ++ * Mask for process state. ++ * Locking: ++ * none. ++ * Notes: ++ * The mask folds data from several sources into a single long value, so ++ * be carefull not to overlap the bits. TASK_* bits are in the LSB, ++ * special cases like UNRUNNABLE are in the MSB. As of 2.6.10-rc1 there ++ * is no overlap between TASK_* and EXIT_* but that may not always be ++ * true, so EXIT_* bits are shifted left 16 bits before being stored in ++ * the mask. ++ */ ++ ++#define UNRUNNABLE (1UL << (8*sizeof(unsigned long) - 1)) /* unrunnable is < 0 */ ++#define RUNNING (1UL << (8*sizeof(unsigned long) - 2)) ++#define IDLE (1UL << (8*sizeof(unsigned long) - 3)) ++#define DAEMON (1UL << (8*sizeof(unsigned long) - 4)) ++ ++unsigned long ++kdb_task_state_string(const char *s) ++{ ++ long res = 0; ++ if (!s && !(s = kdbgetenv("PS"))) { ++ s = "DRSTCZEU"; /* default value for ps */ ++ } ++ while (*s) { ++ switch (*s) { ++ case 'D': res |= TASK_UNINTERRUPTIBLE; break; ++ case 'R': res |= RUNNING; break; ++ case 'S': res |= TASK_INTERRUPTIBLE; break; ++ case 'T': res |= TASK_STOPPED; break; ++ case 'C': res |= TASK_TRACED; break; ++ case 'Z': res |= EXIT_ZOMBIE << 16; break; ++ case 'E': res |= EXIT_DEAD << 16; break; ++ case 'U': res |= UNRUNNABLE; break; ++ case 'I': res |= IDLE; break; ++ case 'M': res |= DAEMON; break; ++ case 'A': res = ~0UL; break; ++ default: ++ kdb_printf("%s: unknown flag '%c' ignored\n", __FUNCTION__, *s); ++ break; ++ } ++ ++s; ++ } ++ return res; ++} ++ ++/* ++ * kdb_task_state_char ++ * ++ * Return the character that represents the task state. ++ * Inputs: ++ * p struct task for the process ++ * Outputs: ++ * none. ++ * Returns: ++ * One character to represent the task state. ++ * Locking: ++ * none. ++ */ ++ ++char ++kdb_task_state_char (const struct task_struct *p) ++{ ++ int cpu = kdb_process_cpu(p); ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ char state = (p->state == 0) ? 'R' : ++ (p->state < 0) ? 'U' : ++ (p->state & TASK_UNINTERRUPTIBLE) ? 'D' : ++ (p->state & TASK_STOPPED) ? 'T' : ++ (p->state & TASK_TRACED) ? 'C' : ++ (p->exit_state & EXIT_ZOMBIE) ? 'Z' : ++ (p->exit_state & EXIT_DEAD) ? 'E' : ++ (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?'; ++ if (p->pid == 0) { ++ /* Idle task. Is it really idle, apart from the kdb interrupt? */ ++ if (!kdb_task_has_cpu(p) || krp->irq_depth == 1) { ++ /* There is a corner case when the idle task takes an ++ * interrupt and dies in the interrupt code. It has an ++ * interrupt count of 1 but that did not come from kdb. ++ * This corner case can only occur on the initial cpu, ++ * all the others were entered via the kdb IPI. ++ */ ++ if (cpu != kdb_initial_cpu || KDB_STATE_CPU(KEYBOARD, cpu)) ++ state = 'I'; /* idle task */ ++ } ++ } ++ else if (!p->mm && state == 'S') { ++ state = 'M'; /* sleeping system daemon */ ++ } ++ return state; ++} ++ ++/* ++ * kdb_task_state ++ * ++ * Return true if a process has the desired state given by the mask. ++ * Inputs: ++ * p struct task for the process ++ * mask mask from kdb_task_state_string to select processes ++ * Outputs: ++ * none. ++ * Returns: ++ * True if the process matches at least one criteria defined by the mask. ++ * Locking: ++ * none. ++ */ ++ ++unsigned long ++kdb_task_state(const struct task_struct *p, unsigned long mask) ++{ ++ char state[] = { kdb_task_state_char(p), '\0' }; ++ return (mask & kdb_task_state_string(state)) != 0; ++} ++ ++struct kdb_running_process kdb_running_process[NR_CPUS]; ++ ++/* Save the state of a running process and invoke kdb_main_loop. This is ++ * invoked on the current process on each cpu (assuming the cpu is responding). ++ */ ++ ++int ++kdb_save_running(struct pt_regs *regs, kdb_reason_t reason, ++ kdb_reason_t reason2, int error, kdb_dbtrap_t db_result) ++{ ++ struct kdb_running_process *krp = kdb_running_process + smp_processor_id(); ++ krp->p = current; ++ krp->regs = regs; ++ krp->seqno = kdb_seqno; ++ krp->irq_depth = hardirq_count() >> HARDIRQ_SHIFT; ++ kdba_save_running(&(krp->arch), regs); ++ return kdb_main_loop(reason, reason2, error, db_result, regs); ++} ++ ++/* ++ * kdb_unsave_running ++ * ++ * Reverse the effect of kdb_save_running. ++ * Inputs: ++ * regs struct pt_regs for the process ++ * Outputs: ++ * Updates kdb_running_process[] for this cpu. ++ * Returns: ++ * none. ++ * Locking: ++ * none. ++ */ ++ ++void ++kdb_unsave_running(struct pt_regs *regs) ++{ ++ struct kdb_running_process *krp = kdb_running_process + smp_processor_id(); ++ kdba_unsave_running(&(krp->arch), regs); ++ krp->seqno = 0; ++} ++ ++ ++/* ++ * kdb_print_nameval ++ * ++ * Print a name and its value, converting the value to a symbol lookup ++ * if possible. ++ * Inputs: ++ * name field name to print ++ * val value of field ++ * Outputs: ++ * none. ++ * Returns: ++ * none. ++ * Locking: ++ * none. ++ */ ++ ++void ++kdb_print_nameval(const char *name, unsigned long val) ++{ ++ kdb_symtab_t symtab; ++ kdb_printf(" %-11.11s ", name); ++ if (kdbnearsym(val, &symtab)) ++ kdb_symbol_print(val, &symtab, KDB_SP_VALUE|KDB_SP_SYMSIZE|KDB_SP_NEWLINE); ++ else ++ kdb_printf("0x%lx\n", val); ++} ++ ++static struct page * kdb_get_one_user_page(const struct task_struct *tsk, unsigned long start, ++ int len, int write) ++{ ++ struct mm_struct *mm = tsk->mm; ++ unsigned int flags; ++ struct vm_area_struct * vma; ++ ++ /* shouldn't cross a page boundary. */ ++ if ((start & PAGE_MASK) != ((start+len) & PAGE_MASK)) ++ return NULL; ++ ++ /* we need to align start address to the current page boundy, PAGE_ALIGN ++ * aligns to next page boundry. ++ * FIXME: What about hugetlb? ++ */ ++ start = start & PAGE_MASK; ++ flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD); ++ ++ vma = find_extend_vma(mm, start); ++ ++ /* may be we can allow access to VM_IO pages inside KDB? */ ++ if (!vma || (vma->vm_flags & VM_IO) || !(flags & vma->vm_flags)) ++ return NULL; ++ ++ return follow_page(vma, start, write ? FOLL_WRITE : 0); ++} ++ ++int kdb_getuserarea_size(void *to, unsigned long from, size_t size) ++{ ++ struct page *page; ++ void *vaddr; ++ ++ page = kdb_get_one_user_page(kdb_current_task, from, size, 0); ++ if (!page) ++ return size; ++ ++ vaddr = kmap_atomic(page, KM_KDB); ++ memcpy(to, vaddr+ (from & (PAGE_SIZE - 1)), size); ++ kunmap_atomic(vaddr, KM_KDB); ++ ++ return 0; ++} ++ ++int kdb_putuserarea_size(unsigned long to, void *from, size_t size) ++{ ++ struct page *page; ++ void *vaddr; ++ ++ page = kdb_get_one_user_page(kdb_current_task, to, size, 1); ++ if (!page) ++ return size; ++ ++ vaddr = kmap_atomic(page, KM_KDB); ++ memcpy(vaddr+ (to & (PAGE_SIZE - 1)), from, size); ++ kunmap_atomic(vaddr, KM_KDB); ++ ++ return 0; ++} ++ ++/* Last ditch allocator for debugging, so we can still debug even when the ++ * GFP_ATOMIC pool has been exhausted. The algorithms are tuned for space ++ * usage, not for speed. One smallish memory pool, the free chain is always in ++ * ascending address order to allow coalescing, allocations are done in brute ++ * force best fit. ++ */ ++ ++struct debug_alloc_header { ++ u32 next; /* offset of next header from start of pool */ ++ u32 size; ++ void *caller; ++}; ++ ++/* The memory returned by this allocator must be aligned, which means so must ++ * the header size. Do not assume that sizeof(struct debug_alloc_header) is a ++ * multiple of the alignment, explicitly calculate the overhead of this header, ++ * including the alignment. The rest of this code must not use sizeof() on any ++ * header or pointer to a header. ++ */ ++#define dah_align 8 ++#define dah_overhead ALIGN(sizeof(struct debug_alloc_header), dah_align) ++ ++static u64 debug_alloc_pool_aligned[256*1024/dah_align]; /* 256K pool */ ++static char *debug_alloc_pool = (char *)debug_alloc_pool_aligned; ++static u32 dah_first, dah_first_call = 1, dah_used = 0, dah_used_max = 0; ++ ++/* Locking is awkward. The debug code is called from all contexts, including ++ * non maskable interrupts. A normal spinlock is not safe in NMI context. Try ++ * to get the debug allocator lock, if it cannot be obtained after a second ++ * then give up. If the lock could not be previously obtained on this cpu then ++ * only try once. ++ * ++ * sparse has no annotation for "this function _sometimes_ acquires a lock", so ++ * fudge the acquire/release notation. ++ */ ++static DEFINE_SPINLOCK(dap_lock); ++static int ++get_dap_lock(void) ++ __acquires(dap_lock) ++{ ++ static int dap_locked = -1; ++ int count; ++ if (dap_locked == smp_processor_id()) ++ count = 1; ++ else ++ count = 1000; ++ while (1) { ++ if (spin_trylock(&dap_lock)) { ++ dap_locked = -1; ++ return 1; ++ } ++ if (!count--) ++ break; ++ udelay(1000); ++ } ++ dap_locked = smp_processor_id(); ++ __acquire(dap_lock); ++ return 0; ++} ++ ++void ++*debug_kmalloc(size_t size, gfp_t flags) ++{ ++ unsigned int rem, h_offset; ++ struct debug_alloc_header *best, *bestprev, *prev, *h; ++ void *p = NULL; ++ if (!get_dap_lock()) { ++ __release(dap_lock); /* we never actually got it */ ++ return NULL; ++ } ++ h = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); ++ if (dah_first_call) { ++ h->size = sizeof(debug_alloc_pool_aligned) - dah_overhead; ++ dah_first_call = 0; ++ } ++ size = ALIGN(size, dah_align); ++ prev = best = bestprev = NULL; ++ while (1) { ++ if (h->size >= size && (!best || h->size < best->size)) { ++ best = h; ++ bestprev = prev; ++ if (h->size == size) ++ break; ++ } ++ if (!h->next) ++ break; ++ prev = h; ++ h = (struct debug_alloc_header *)(debug_alloc_pool + h->next); ++ } ++ if (!best) ++ goto out; ++ rem = best->size - size; ++ /* The pool must always contain at least one header */ ++ if (best->next == 0 && bestprev == NULL && rem < dah_overhead) ++ goto out; ++ if (rem >= dah_overhead) { ++ best->size = size; ++ h_offset = ((char *)best - debug_alloc_pool) + ++ dah_overhead + best->size; ++ h = (struct debug_alloc_header *)(debug_alloc_pool + h_offset); ++ h->size = rem - dah_overhead; ++ h->next = best->next; ++ } else ++ h_offset = best->next; ++ best->caller = __builtin_return_address(0); ++ dah_used += best->size; ++ dah_used_max = max(dah_used, dah_used_max); ++ if (bestprev) ++ bestprev->next = h_offset; ++ else ++ dah_first = h_offset; ++ p = (char *)best + dah_overhead; ++ memset(p, POISON_INUSE, best->size - 1); ++ *((char *)p + best->size - 1) = POISON_END; ++out: ++ spin_unlock(&dap_lock); ++ return p; ++} ++ ++void ++debug_kfree(void *p) ++{ ++ struct debug_alloc_header *h; ++ unsigned int h_offset; ++ if (!p) ++ return; ++ if ((char *)p < debug_alloc_pool || ++ (char *)p >= debug_alloc_pool + sizeof(debug_alloc_pool_aligned)) { ++ kfree(p); ++ return; ++ } ++ if (!get_dap_lock()) { ++ __release(dap_lock); /* we never actually got it */ ++ return; /* memory leak, cannot be helped */ ++ } ++ h = (struct debug_alloc_header *)((char *)p - dah_overhead); ++ memset(p, POISON_FREE, h->size - 1); ++ *((char *)p + h->size - 1) = POISON_END; ++ h->caller = NULL; ++ dah_used -= h->size; ++ h_offset = (char *)h - debug_alloc_pool; ++ if (h_offset < dah_first) { ++ h->next = dah_first; ++ dah_first = h_offset; ++ } else { ++ struct debug_alloc_header *prev; ++ unsigned int prev_offset; ++ prev = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); ++ while (1) { ++ if (!prev->next || prev->next > h_offset) ++ break; ++ prev = (struct debug_alloc_header *) ++ (debug_alloc_pool + prev->next); ++ } ++ prev_offset = (char *)prev - debug_alloc_pool; ++ if (prev_offset + dah_overhead + prev->size == h_offset) { ++ prev->size += dah_overhead + h->size; ++ memset(h, POISON_FREE, dah_overhead - 1); ++ *((char *)h + dah_overhead - 1) = POISON_END; ++ h = prev; ++ h_offset = prev_offset; ++ } else { ++ h->next = prev->next; ++ prev->next = h_offset; ++ } ++ } ++ if (h_offset + dah_overhead + h->size == h->next) { ++ struct debug_alloc_header *next; ++ next = (struct debug_alloc_header *) ++ (debug_alloc_pool + h->next); ++ h->size += dah_overhead + next->size; ++ h->next = next->next; ++ memset(next, POISON_FREE, dah_overhead - 1); ++ *((char *)next + dah_overhead - 1) = POISON_END; ++ } ++ spin_unlock(&dap_lock); ++} ++ ++void ++debug_kusage(void) ++{ ++ struct debug_alloc_header *h_free, *h_used; ++#ifdef CONFIG_IA64 ++ /* FIXME: using dah for ia64 unwind always results in a memory leak. ++ * Fix that memory leak first, then set debug_kusage_one_time = 1 for ++ * all architectures. ++ */ ++ static int debug_kusage_one_time = 0; ++#else ++ static int debug_kusage_one_time = 1; ++#endif ++ if (!get_dap_lock()) { ++ __release(dap_lock); /* we never actually got it */ ++ return; ++ } ++ h_free = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); ++ if (dah_first == 0 && ++ (h_free->size == sizeof(debug_alloc_pool_aligned) - dah_overhead || ++ dah_first_call)) ++ goto out; ++ if (!debug_kusage_one_time) ++ goto out; ++ debug_kusage_one_time = 0; ++ kdb_printf("%s: debug_kmalloc memory leak dah_first %d\n", ++ __FUNCTION__, dah_first); ++ if (dah_first) { ++ h_used = (struct debug_alloc_header *)debug_alloc_pool; ++ kdb_printf("%s: h_used %p size %d\n", __FUNCTION__, h_used, h_used->size); ++ } ++ do { ++ h_used = (struct debug_alloc_header *) ++ ((char *)h_free + dah_overhead + h_free->size); ++ kdb_printf("%s: h_used %p size %d caller %p\n", ++ __FUNCTION__, h_used, h_used->size, h_used->caller); ++ h_free = (struct debug_alloc_header *) ++ (debug_alloc_pool + h_free->next); ++ } while (h_free->next); ++ h_used = (struct debug_alloc_header *) ++ ((char *)h_free + dah_overhead + h_free->size); ++ if ((char *)h_used - debug_alloc_pool != ++ sizeof(debug_alloc_pool_aligned)) ++ kdb_printf("%s: h_used %p size %d caller %p\n", ++ __FUNCTION__, h_used, h_used->size, h_used->caller); ++out: ++ spin_unlock(&dap_lock); ++} ++ ++/* Maintain a small stack of kdb_flags to allow recursion without disturbing ++ * the global kdb state. ++ */ ++ ++static int kdb_flags_stack[4], kdb_flags_index; ++ ++void ++kdb_save_flags(void) ++{ ++ BUG_ON(kdb_flags_index >= ARRAY_SIZE(kdb_flags_stack)); ++ kdb_flags_stack[kdb_flags_index++] = kdb_flags; ++} ++ ++void ++kdb_restore_flags(void) ++{ ++ BUG_ON(kdb_flags_index <= 0); ++ kdb_flags = kdb_flags_stack[--kdb_flags_index]; ++} +--- /dev/null ++++ b/kdb/modules/Makefile +@@ -0,0 +1,14 @@ ++# ++# 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++# ++ ++obj-$(CONFIG_KDB_MODULES) += kdbm_pg.o kdbm_task.o kdbm_vm.o kdbm_sched.o ++obj-m += kdbm_debugtypes.o ++ifdef CONFIG_X86 ++obj-$(CONFIG_KDB_MODULES) += kdbm_x86.o ++endif ++CFLAGS_kdbm_vm.o += -I $(srctree)/drivers/scsi +--- /dev/null ++++ b/kdb/modules/kdbm_debugtypes.c +@@ -0,0 +1,388 @@ ++/* this one has some additional address validation - untested */ ++/* ++ * 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) 2008 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * ++ * Most of this code is borrowed and adapted from the lkcd command "lcrash" ++ * and its supporting libarary. ++ * ++ * This module provides kdb commands for casting memory structures. ++ * It loads symbolic debugging info (provided from lcrash -o), and provides ++ * "print" "px", "pd" ++ * (this information originally comes from the lcrash "kerntypes" file) ++ * ++ * A key here is tacking a file of debug info onto this module, for ++ * load with it at insmod time. ++ * ++ * Careful of porting the klib KL_XXX functions (they call thru a jump table ++ * that we don't use here) ++ * ++ * Usage: ++ * in order for the insmod kdbm_debugtypes.ko to succeed in loading types ++ * you must first use lcrash -t kerntypes.xxxx -o debug_info ++ * and echo debug_info > /proc/kdb/debug_info_name ++ */ ++ ++#define VMALLOC_START_IA64 0xa000000200000000 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "lcrash/klib.h" ++#include "lcrash/kl_stringtab.h" ++#include "lcrash/kl_btnode.h" ++#include "lcrash/lc_eval.h" ++ ++MODULE_AUTHOR("SGI"); ++MODULE_DESCRIPTION("Load symbolic debugging information"); ++MODULE_LICENSE("GPL"); ++ ++#undef next_node /* collision with nodemask.h */ ++static char *stringstorage, **stringp_array; ++static void *filestorage; ++static long num_strings, num_kltypes, num_dsyms, stringstorage_size; ++extern int have_debug_file; ++extern dbg_sym_t *types_tree_head; ++extern dbg_sym_t *typedefs_tree_head; ++extern kltype_t *kltype_array; ++extern dbg_sym_t *dsym_types_array; ++extern dbg_sym_t *type_tree; ++extern dbg_sym_t *typedef_tree; ++ ++/* ++ * use a pointer's value as an index in the stringp_array (num_strings) and ++ * translate it to string address ++ * ++ * Return 0 for success, 1 for failure ++ */ ++static int ++index_to_char_ptr(char **ptrp) ++{ ++ long i; ++ ++ i = (long)*ptrp; ++ /* we use a value of -1 to mean this was a null pointer */ ++ if (i == -1) { ++ *ptrp = NULL; ++ return 0; ++ } ++ if (i > num_strings-1) { ++ printk("Could not translate character string index %#lx\n", i); ++ return 1; ++ } ++ *ptrp = *(stringp_array+i); ++ return 0; ++} ++ ++/* ++ * use a pointer's value as an index in the kltype_array (num_kltypes) and ++ * translate it to the kltype_t address ++ * ++ * return 0 for success, 1 for failure ++ */ ++static int ++index_to_kltype_ptr(kltype_t **ptrp) ++{ ++ long i; ++ ++ i = (long)*ptrp; ++ /* we use a value of -1 to mean this was a null pointer */ ++ if (i == -1) { ++ *ptrp = NULL; ++ return 0; ++ } ++ if (i > num_kltypes-1) { ++ printk("Could not translate kl_type string index %#lx\n", i); ++ return 1; ++ } ++ *ptrp = kltype_array+i; ++ return 0; ++} ++ ++/* ++ * look up a pointer in the dsym_types_array (num_dsyms) and ++ * translate it to the index in the array ++ * ++ * return 0 for success, 1 for failure ++ */ ++static int ++index_to_dbg_ptr(dbg_sym_t **ptrp) ++{ ++ long i; ++ ++ i = (long)*ptrp; ++ /* we use a value of -1 to mean this was a null pointer */ ++ if (i == -1) { ++ *ptrp = NULL; ++ return 0; ++ } ++ if (i > num_dsyms-1) { ++ printk("Could not translate dbg_sym_t index %#lx\n", i); ++ return 1; ++ } ++ *ptrp = dsym_types_array+i; ++ return 0; ++} ++ ++ ++/* ++ * Work on the image of the file built by lcrash. ++ * Unpack the strings, and resolve the pointers in the arrays of kltype_t's ++ * and dbg_sym_t's to pointers. ++ * ++ * see lcrash's lib/libklib/kl_debug.c, which generates this file ++ * ++ * Return the pointers to the heads of the two binary trees by means of ++ * pointer arguments. ++ * ++ * Return 0 for sucess, 1 for any error. ++ */ ++static int ++trans_file_image(void *file_storage, long file_size, dbg_sym_t **type_treepp, ++ dbg_sym_t **typedef_treepp) ++{ ++ int len; ++ long i, section_size, *lp, element_size; ++ long head_types_tree, head_typedefs_tree; ++ char *ptr, *stringsection, *kltypesection, *dbgsection; ++ void *kltypestorage, *dbgstorage; ++ kltype_t *klp; ++ dbg_sym_t *dbgp; ++ ++ /* 1) the strings */ ++ lp = (long *)file_storage; ++ stringsection = (char *)lp; ++ section_size = *lp++; ++ num_strings = *lp++; ++ lp++; /* element size does not apply the strings section */ ++ ++ stringstorage_size = section_size - (3*sizeof(long)); ++ stringstorage = (char *)lp; ++ ++ stringp_array = (char **)vmalloc(num_strings * sizeof(char *)); ++ if (! stringp_array) { ++ printk("vmalloc of %ld string pointers failed\n", num_strings); ++ return 1; ++ } ++ ptr = stringstorage; ++ for (i=0; ikl_name)) ++ goto bad; ++ if (index_to_char_ptr(&klp->kl_typestr)) ++ goto bad; ++ if (index_to_kltype_ptr(&klp->kl_member)) ++ goto bad; ++ if (index_to_kltype_ptr(&klp->kl_next)) ++ goto bad; ++ if (index_to_kltype_ptr(&klp->kl_realtype)) ++ goto bad; ++ if (index_to_kltype_ptr(&klp->kl_indextype)) ++ goto bad; ++ if (index_to_kltype_ptr(&klp->kl_elementtype)) ++ goto bad; ++ if (index_to_dbg_ptr((dbg_sym_t **)&klp->kl_ptr)) ++ goto bad; ++ } ++ ++ /* translate the indices in our our array of dbg_sym_t's to pointers */ ++ /* (see write_dbgtype() for the fields that can be translated) */ ++ dbgp = dsym_types_array; ++ for (i=0; isym_bt.bt_key)) ++ goto bad; ++ if (index_to_dbg_ptr((dbg_sym_t **)&dbgp->sym_bt.bt_left)) ++ goto bad; ++ if (index_to_dbg_ptr((dbg_sym_t **)&dbgp->sym_bt.bt_right)) ++ goto bad; ++ if (index_to_dbg_ptr((dbg_sym_t **)&dbgp->sym_bt.bt_parent)) ++ goto bad; ++ if (index_to_dbg_ptr((dbg_sym_t **)&dbgp->sym_next)) ++ goto bad; ++ if (index_to_dbg_ptr((dbg_sym_t **)&dbgp->sym_link)) ++ goto bad; ++ if (index_to_kltype_ptr(&dbgp->sym_kltype)) ++ goto bad; ++ } ++ ++ vfree(stringp_array); ++ return 0; ++bad: ++ printk("trans_file_image() returning an error\n"); ++ vfree(stringp_array); ++ return 1; ++} ++ ++/* there is /proc interface to this string */ ++extern char kdb_debug_info_filename[]; ++/* ++ * This is the module initialization function. ++ */ ++static int __init ++kdbm_debuginfo_init(void) ++{ ++ int len; ++ long ret, file_size; ++ ssize_t sizeread; ++ mm_segment_t fs; ++ struct file *file; ++ loff_t inode_size, pos; ++ ++ len = strlen(kdb_debug_info_filename); ++ if (!len) { ++ printk("kdb: no file name in /proc/kdb/debug_info_name\n"); ++ return -ENODEV; ++ } ++ ++ fs = get_fs(); /* save previous value of address limits */ ++ set_fs (get_ds()); /* use kernel limit */ ++ ++ file = filp_open(kdb_debug_info_filename, O_RDONLY, 0); ++ if (IS_ERR(file)) { ++ set_fs(fs); ++ printk ( ++ "kdb: open of %s (from /proc/kdb/debug_info_name) failed\n", ++ kdb_debug_info_filename); ++ return -ENODEV; ++ } ++ if (!file->f_op || (!file->f_op->read && !file->f_op->llseek)) { ++ printk ("file has no operation for read or seek\n"); ++ set_fs(fs); ++ return -ENODEV; ++ } ++ inode_size = file->f_dentry->d_inode->i_size; ++ ++ /* ++ * File has a header word on it that contains the size of the ++ * file. We don't need it, but can use it as a sanity check. ++ */ ++ pos = 0; ++ sizeread = file->f_op->read(file, (char *)&file_size, ++ sizeof(file_size), &pos); ++ if (sizeread != sizeof(file_size)) { ++ printk("could not read %d bytes from %s\n", ++ (int)sizeof(file_size), kdb_debug_info_filename); ++ ret = filp_close(file, NULL); ++ set_fs(fs); ++ return -ENODEV; ++ } ++ if (inode_size != file_size) { ++ printk("file says %ld, inode says %lld\n", ++ file_size, inode_size); ++ ret = filp_close(file, NULL); ++ set_fs(fs); ++ return -ENODEV; ++ } ++ ++ /* space for the rest of the file: */ ++ file_size -= sizeof(long); ++ filestorage = (void *)vmalloc(file_size); ++ ++ pos = sizeof(file_size); /* position after the header word */ ++ sizeread = file->f_op->read(file, (char *)filestorage, ++ file_size, &pos); ++ if (sizeread != file_size) { ++ printk("could not read %ld bytes from %s\n", ++ file_size, kdb_debug_info_filename); ++ ret = filp_close(file, NULL); ++ set_fs(fs); ++ vfree (filestorage); ++ return -ENODEV; ++ } ++ ++ ret = filp_close(file, NULL); ++ set_fs(fs); /* restore address limits before returning to user space */ ++ ++ if (trans_file_image(filestorage, file_size, &types_tree_head, ++ &typedefs_tree_head)){ ++ vfree (filestorage); ++ return -ENODEV; ++ } ++ printk("kdbm_debuginfo loaded %s\n", kdb_debug_info_filename); ++ /* set the lcrash code's binary tree head nodes */ ++ type_tree = types_tree_head; ++ typedef_tree = typedefs_tree_head; ++ ++ have_debug_file = 1; ++ ++ return 0; ++} ++ ++/* ++ * This is the module exit function. ++ */ ++static void __exit ++kdbm_debuginfo_exit(void) ++{ ++ printk("kdbm_debuginfo unloaded %s\n", kdb_debug_info_filename); ++ vfree (filestorage); ++ have_debug_file = 0; ++ return; ++} ++ ++module_init(kdbm_debuginfo_init); ++module_exit(kdbm_debuginfo_exit); +--- /dev/null ++++ b/kdb/modules/kdbm_pg.c +@@ -0,0 +1,688 @@ ++/* ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("SGI"); ++MODULE_DESCRIPTION("Debug page information"); ++MODULE_LICENSE("GPL"); ++ ++/* Standard Linux page stuff */ ++ ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++/* From include/linux/page-flags.h */ ++static char *pg_flag_vals[] = { ++ "PG_locked", "PG_error", "PG_referenced", "PG_uptodate", ++ "PG_dirty", "PG_lru", "PG_active", "PG_slab", ++ "PG_owner_priv_1", "PG_arch_1", "PG_reserved", "PG_private", ++ "PG_writeback", ++#ifdef CONFIG_PAGEFLAGS_EXTENDED ++ "PG_head", "PG_tail", ++#else ++ "PG_compound", ++#endif ++ "PG_swapcache", "PG_mappedtodisk", "PG_reclaim", "PG_buddy", ++#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR ++ "PG_uncached", ++#endif ++ NULL }; ++#endif ++ ++/* From include/linux/buffer_head.h */ ++static char *bh_state_vals[] = { ++ "Uptodate", "Dirty", "Lock", "Req", ++ "Uptodate_Lock", "Mapped", "New", "Async_read", ++ "Async_write", "Delay", "Boundary", "Write_EIO", ++ "Ordered", "Eopnotsupp", "Unwritten", "PriavateStart", ++ NULL }; ++ ++/* From include/linux/bio.h */ ++static char *bio_flag_vals[] = { ++ "Uptodate", "RW_block", "EOF", "Seg_valid", ++ "Cloned", "Bounced", "User_mapped", "Eopnotsupp", ++ NULL }; ++ ++/* From include/linux/fs.h */ ++static char *inode_flag_vals[] = { ++ "I_DIRTY_SYNC", "I_DIRTY_DATASYNC", "I_DIRTY_PAGES", "I_NEW", ++ "I_WILL_FREE", "I_FREEING", "I_CLEAR", "I_LOCK", ++ "I_SYNC", NULL }; ++ ++static char *map_flags(unsigned long flags, char *mapping[]) ++{ ++ static char buffer[256]; ++ int index; ++ int offset = 12; ++ ++ buffer[0] = '\0'; ++ ++ for (index = 0; flags && mapping[index]; flags >>= 1, index++) { ++ if (flags & 1) { ++ if ((offset + strlen(mapping[index]) + 1) >= 80) { ++ strcat(buffer, "\n "); ++ offset = 12; ++ } else if (offset > 12) { ++ strcat(buffer, " "); ++ offset++; ++ } ++ strcat(buffer, mapping[index]); ++ offset += strlen(mapping[index]); ++ } ++ } ++ ++ return (buffer); ++} ++ ++static int ++kdbm_buffers(int argc, const char **argv) ++{ ++ struct buffer_head bh; ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(bh, addr))) ++ return(diag); ++ ++ kdb_printf("buffer_head at 0x%lx\n", addr); ++ kdb_printf(" bno %llu size %llu dev 0x%x\n", ++ (unsigned long long)bh.b_blocknr, ++ (unsigned long long)bh.b_size, ++ bh.b_bdev ? bh.b_bdev->bd_dev : 0); ++ kdb_printf(" count %d state 0x%lx [%s]\n", ++ bh.b_count.counter, bh.b_state, ++ map_flags(bh.b_state, bh_state_vals)); ++ kdb_printf(" b_data 0x%p\n", ++ bh.b_data); ++ kdb_printf(" b_page 0x%p b_this_page 0x%p b_private 0x%p\n", ++ bh.b_page, bh.b_this_page, bh.b_private); ++ kdb_printf(" b_end_io "); ++ if (bh.b_end_io) ++ kdb_symbol_print(kdba_funcptr_value(bh.b_end_io), NULL, KDB_SP_VALUE); ++ else ++ kdb_printf("(NULL)"); ++ kdb_printf("\n"); ++ ++ return 0; ++} ++ ++static int ++print_biovec(struct bio_vec *vec, int vcount) ++{ ++ struct bio_vec bvec; ++ unsigned long addr; ++ int diag; ++ int i; ++ ++ if (vcount < 1 || vcount > BIO_MAX_PAGES) { ++ kdb_printf(" [skipped iovecs, vcnt is %d]\n", vcount); ++ return 0; ++ } ++ ++ addr = (unsigned long)vec; ++ for (i = 0; i < vcount; i++) { ++ if ((diag = kdb_getarea(bvec, addr))) ++ return(diag); ++ addr += sizeof(bvec); ++ kdb_printf(" [%d] page 0x%p length=%u offset=%u\n", ++ i, bvec.bv_page, bvec.bv_len, bvec.bv_offset); ++ } ++ return 0; ++} ++ ++static int ++kdbm_bio(int argc, const char **argv) ++{ ++ struct bio bio; ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(bio, addr))) ++ return(diag); ++ ++ kdb_printf("bio at 0x%lx\n", addr); ++ kdb_printf(" bno %llu next 0x%p dev 0x%x\n", ++ (unsigned long long)bio.bi_sector, ++ bio.bi_next, bio.bi_bdev ? bio.bi_bdev->bd_dev : 0); ++ kdb_printf(" vcnt %u vec 0x%p rw 0x%lx flags 0x%lx [%s]\n", ++ bio.bi_vcnt, bio.bi_io_vec, bio.bi_rw, bio.bi_flags, ++ map_flags(bio.bi_flags, bio_flag_vals)); ++ print_biovec(bio.bi_io_vec, bio.bi_vcnt); ++ kdb_printf(" count %d private 0x%p\n", ++ atomic_read(&bio.bi_cnt), bio.bi_private); ++ kdb_printf(" bi_end_io "); ++ if (bio.bi_end_io) ++ kdb_symbol_print(kdba_funcptr_value(bio.bi_end_io), NULL, KDB_SP_VALUE); ++ else ++ kdb_printf("(NULL)"); ++ kdb_printf("\n"); ++ ++ return 0; ++} ++ ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++static char *page_flags(unsigned long flags) ++{ ++ return(map_flags(flags, pg_flag_vals)); ++} ++ ++static int ++kdbm_page(int argc, const char **argv) ++{ ++ struct page page; ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ ++#ifdef __ia64__ ++ if (rgn_index(addr) == 0) ++ addr = (unsigned long) &mem_map[addr]; /* assume region 0 is a page index, not an address */ ++#else ++ if (addr < PAGE_OFFSET) ++ addr = (unsigned long) &mem_map[addr]; ++#endif ++ ++ if ((diag = kdb_getarea(page, addr))) ++ return(diag); ++ ++ kdb_printf("struct page at 0x%lx\n", addr); ++ kdb_printf(" addr space 0x%p index %lu (offset 0x%llx)\n", ++ page.mapping, page.index, ++ (unsigned long long)page.index << PAGE_CACHE_SHIFT); ++ kdb_printf(" count %d flags %s\n", ++ page._count.counter, page_flags(page.flags)); ++ kdb_printf(" virtual 0x%p\n", page_address((struct page *)addr)); ++ if (page_has_buffers(&page)) ++ kdb_printf(" buffers 0x%p\n", page_buffers(&page)); ++ else ++ kdb_printf(" private 0x%lx\n", page_private(&page)); ++ ++ return 0; ++} ++#endif /* !CONFIG_DISCONTIGMEM && !NUMA */ ++ ++static unsigned long ++print_request(unsigned long addr) ++{ ++ struct request rq; ++ ++ if (kdb_getarea(rq, addr)) ++ return(0); ++ ++ kdb_printf("struct request at 0x%lx\n", addr); ++ kdb_printf(" errors %d sector %llu nr_sectors %lu\n", ++ rq.errors, ++ (unsigned long long)rq.sector, rq.nr_sectors); ++ ++ kdb_printf(" hsect %llu hnrsect %lu nrseg %u currnrsect %u\n", ++ (unsigned long long)rq.hard_sector, rq.hard_nr_sectors, ++ rq.nr_phys_segments, rq.current_nr_sectors); ++ ++ return (unsigned long) rq.queuelist.next; ++} ++ ++static int ++kdbm_request(int argc, const char **argv) ++{ ++ long offset = 0; ++ unsigned long addr; ++ int nextarg; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ ++ print_request(addr); ++ return 0; ++} ++ ++ ++static int ++kdbm_rqueue(int argc, const char **argv) ++{ ++ struct request_queue rq; ++ unsigned long addr, head_addr, next; ++ long offset = 0; ++ int nextarg; ++ int i, diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(rq, addr))) ++ return(diag); ++ ++ kdb_printf("struct request_queue at 0x%lx\n", addr); ++ i = 0; ++ next = (unsigned long)rq.queue_head.next; ++ head_addr = addr + offsetof(struct request_queue, queue_head); ++ kdb_printf(" request queue: %s\n", next == head_addr ? ++ "empty" : ""); ++ while (next != head_addr) { ++ i++; ++ next = print_request(next); ++ } ++ ++ if (i) ++ kdb_printf("%d requests found\n", i); ++ ++ return 0; ++} ++ ++ ++static void ++do_buffer(unsigned long addr) ++{ ++ struct buffer_head bh; ++ ++ if (kdb_getarea(bh, addr)) ++ return; ++ ++ kdb_printf("\tbh 0x%lx bno %8llu [%s]\n", addr, ++ (unsigned long long)bh.b_blocknr, ++ map_flags(bh.b_state, bh_state_vals)); ++} ++ ++static void ++kdbm_show_page(struct page *page, int first) ++{ ++ if (first) ++ kdb_printf("page_struct index cnt zone nid flags\n"); ++ kdb_printf("%p%s %6lu %5d %3d %3d 0x%lx", ++ page_address(page), sizeof(void *) == 4 ? " " : "", ++ page->index, atomic_read(&(page->_count)), ++ page_zonenum(page), page_to_nid(page), ++ page->flags & (~0UL >> ZONES_SHIFT)); ++#define kdb_page_flags(page, type) if (Page ## type(page)) kdb_printf(" " #type); ++ kdb_page_flags(page, Locked); ++ kdb_page_flags(page, Error); ++ kdb_page_flags(page, Referenced); ++ kdb_page_flags(page, Uptodate); ++ kdb_page_flags(page, Dirty); ++ kdb_page_flags(page, LRU); ++ kdb_page_flags(page, Active); ++ kdb_page_flags(page, Slab); ++ kdb_page_flags(page, Checked); ++ if (page->flags & (1UL << PG_arch_1)) ++ kdb_printf(" arch_1"); ++ kdb_page_flags(page, Reserved); ++ kdb_page_flags(page, Private); ++ kdb_page_flags(page, Writeback); ++ kdb_page_flags(page, Compound); ++ kdb_page_flags(page, SwapCache); ++ kdb_page_flags(page, MappedToDisk); ++ kdb_page_flags(page, Reclaim); ++ kdb_page_flags(page, Buddy); ++ ++ /* PageHighMem is not a flag any more, but treat it as one */ ++ kdb_page_flags(page, HighMem); ++ ++ if (page_has_buffers(page)) { ++ struct buffer_head *head, *bh; ++ kdb_printf("\n"); ++ head = bh = page_buffers(page); ++ do { ++ do_buffer((unsigned long) bh); ++ } while ((bh = bh->b_this_page) != head); ++ } else if (page_private(page)) { ++ kdb_printf(" private= 0x%lx", page_private(page)); ++ } ++ /* Cannot use page_mapping(page) here, it needs swapper_space which is ++ * not exported. ++ */ ++ if (page->mapping) ++ kdb_printf(" mapping= %p", page->mapping); ++ kdb_printf("\n"); ++#undef kdb_page_flags ++} ++ ++static int ++kdbm_inode_pages(int argc, const char **argv) ++{ ++ struct inode *inode = NULL; ++ struct address_space *ap = NULL; ++ unsigned long addr, addr1 = 0; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ pgoff_t next = 0; ++ struct page *page; ++ int first; ++ ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ goto out; ++ ++ if (argc == 2) { ++ nextarg = 2; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr1, ++ &offset, NULL); ++ if (diag) ++ goto out; ++ kdb_printf("Looking for page index 0x%lx ... \n", addr1); ++ next = addr1; ++ } ++ ++ if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) { ++ kdb_printf("kdbm_inode_pages: cannot kmalloc inode\n"); ++ goto out; ++ } ++ if (!(ap = kmalloc(sizeof(*ap), GFP_ATOMIC))) { ++ kdb_printf("kdbm_inode_pages: cannot kmalloc ap\n"); ++ goto out; ++ } ++ if ((diag = kdb_getarea(*inode, addr))) ++ goto out; ++ if (!inode->i_mapping) { ++ kdb_printf("inode has no mapping\n"); ++ goto out; ++ } ++ if ((diag = kdb_getarea(*ap, (unsigned long) inode->i_mapping))) ++ goto out; ++ ++ /* Run the pages in the radix tree, printing the state of each page */ ++ first = 1; ++ while (radix_tree_gang_lookup(&ap->page_tree, (void **)&page, next, 1)) { ++ kdbm_show_page(page, first); ++ if (addr1) ++ break; ++ first = 0; ++ next = page->index + 1; ++ } ++ ++out: ++ if (inode) ++ kfree(inode); ++ if (ap) ++ kfree(ap); ++ return diag; ++} ++ ++static int ++kdbm_inode(int argc, const char **argv) ++{ ++ struct inode *inode = NULL; ++ unsigned long addr; ++ unsigned char *iaddr; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL))) ++ goto out; ++ if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) { ++ kdb_printf("kdbm_inode: cannot kmalloc inode\n"); ++ goto out; ++ } ++ if ((diag = kdb_getarea(*inode, addr))) ++ goto out; ++ ++ kdb_printf("struct inode at 0x%lx\n", addr); ++ ++ kdb_printf(" i_ino = %lu i_count = %u i_size %Ld\n", ++ inode->i_ino, atomic_read(&inode->i_count), ++ inode->i_size); ++ ++ kdb_printf(" i_mode = 0%o i_nlink = %d i_rdev = 0x%x\n", ++ inode->i_mode, inode->i_nlink, ++ inode->i_rdev); ++ ++ kdb_printf(" i_hash.nxt = 0x%p i_hash.pprev = 0x%p\n", ++ inode->i_hash.next, ++ inode->i_hash.pprev); ++ ++ kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", ++ list_entry(inode->i_list.next, struct inode, i_list), ++ list_entry(inode->i_list.prev, struct inode, i_list)); ++ ++ kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", ++ list_entry(inode->i_dentry.next, struct dentry, d_alias), ++ list_entry(inode->i_dentry.prev, struct dentry, d_alias)); ++ ++ kdb_printf(" i_sb = 0x%p i_op = 0x%p i_data = 0x%lx nrpages = %lu\n", ++ inode->i_sb, inode->i_op, ++ addr + offsetof(struct inode, i_data), ++ inode->i_data.nrpages); ++ kdb_printf(" i_fop= 0x%p i_flock = 0x%p i_mapping = 0x%p\n", ++ inode->i_fop, inode->i_flock, inode->i_mapping); ++ ++ kdb_printf(" i_flags 0x%x i_state 0x%lx [%s]", ++ inode->i_flags, inode->i_state, ++ map_flags(inode->i_state, inode_flag_vals)); ++ ++ iaddr = (char *)addr; ++ iaddr += offsetof(struct inode, i_private); ++ ++ kdb_printf(" fs specific info @ 0x%p\n", iaddr); ++out: ++ if (inode) ++ kfree(inode); ++ return diag; ++} ++ ++static int ++kdbm_sb(int argc, const char **argv) ++{ ++ struct super_block *sb = NULL; ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL))) ++ goto out; ++ if (!(sb = kmalloc(sizeof(*sb), GFP_ATOMIC))) { ++ kdb_printf("kdbm_sb: cannot kmalloc sb\n"); ++ goto out; ++ } ++ if ((diag = kdb_getarea(*sb, addr))) ++ goto out; ++ ++ kdb_printf("struct super_block at 0x%lx\n", addr); ++ kdb_printf(" s_dev 0x%x blocksize 0x%lx\n", sb->s_dev, sb->s_blocksize); ++ kdb_printf(" s_flags 0x%lx s_root 0x%p\n", sb->s_flags, sb->s_root); ++ kdb_printf(" s_dirt %d s_dirty.next 0x%p s_dirty.prev 0x%p\n", ++ sb->s_dirt, sb->s_dirty.next, sb->s_dirty.prev); ++ kdb_printf(" s_frozen %d s_id [%s]\n", sb->s_frozen, sb->s_id); ++out: ++ if (sb) ++ kfree(sb); ++ return diag; ++} ++ ++ ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++/* According to Steve Lord, this code is ix86 specific. Patches to extend it to ++ * other architectures will be greatefully accepted. ++ */ ++static int ++kdbm_memmap(int argc, const char **argv) ++{ ++ struct page page; ++ int i, page_count; ++ int slab_count = 0; ++ int dirty_count = 0; ++ int locked_count = 0; ++ int page_counts[10]; /* [8] = large counts, [9] = -1 counts */ ++ int buffered_count = 0; ++#ifdef buffer_delay ++ int delay_count = 0; ++#endif ++ int diag; ++ unsigned long addr; ++#ifdef CONFIG_DISCONTIGMEM ++ int node_id = -1, found_node = 0; ++ int tot_page_count = 0; ++ unsigned long unode_id; ++ pg_data_t *pgdat; ++ ++ if (argc == 1) { /* node_id was specified */ ++ diag = kdbgetularg(argv[argc], &unode_id); ++ if (diag) ++ return diag; ++ node_id = (int)unode_id; ++ } ++ else if (argc) ++ return KDB_ARGCOUNT; ++ ++ tot_page_count = 0; ++ memset(page_counts, 0, sizeof(page_counts)); ++ ++ for_each_online_pgdat(pgdat) { ++ if ((node_id != -1) && (pgdat->node_id != node_id)) ++ continue; ++ found_node = 1; ++ addr = (unsigned long)pgdat->node_mem_map; ++ page_count = pgdat->node_spanned_pages; ++ tot_page_count += page_count; ++#else ++ addr = (unsigned long)mem_map; ++ page_count = max_mapnr; ++ memset(page_counts, 0, sizeof(page_counts)); ++#endif ++ for (i = 0; i < page_count; i++) { ++ if ((diag = kdb_getarea(page, addr))) ++ return(diag); ++ addr += sizeof(page); ++ ++ if (PageSlab(&page)) ++ slab_count++; ++ if (PageDirty(&page)) ++ dirty_count++; ++ if (PageLocked(&page)) ++ locked_count++; ++ if (page._count.counter == -1) ++ page_counts[9]++; ++ else if (page._count.counter < 8) ++ page_counts[page._count.counter]++; ++ else ++ page_counts[8]++; ++ if (page_has_buffers(&page)) { ++ buffered_count++; ++#ifdef buffer_delay ++ if (buffer_delay(page.buffers)) ++ delay_count++; ++#endif ++ } ++ } ++#ifdef CONFIG_DISCONTIGMEM ++ } ++ page_count = tot_page_count; ++ if (node_id != -1) { ++ if (!found_node) { ++ kdb_printf("Node %d does not exist.\n", node_id); ++ return 0; ++ } ++ kdb_printf("Node %d pages:\n", node_id); ++ } ++#endif ++ kdb_printf(" Total pages: %6d\n", page_count); ++ kdb_printf(" Slab pages: %6d\n", slab_count); ++ kdb_printf(" Dirty pages: %6d\n", dirty_count); ++ kdb_printf(" Locked pages: %6d\n", locked_count); ++ kdb_printf(" Buffer pages: %6d\n", buffered_count); ++#ifdef buffer_delay ++ kdb_printf(" Delalloc pages: %6d\n", delay_count); ++#endif ++ kdb_printf(" -1 page count: %6d\n", page_counts[9]); ++ for (i = 0; i < 8; i++) { ++ kdb_printf(" %d page count: %6d\n", ++ i, page_counts[i]); ++ } ++ kdb_printf(" high page count: %6d\n", page_counts[8]); ++ return 0; ++} ++#endif /* !CONFIG_DISCONTIGMEM && !NUMA */ ++ ++static int __init kdbm_pg_init(void) ++{ ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++ kdb_register("page", kdbm_page, "", "Display page", 0); ++#endif ++ kdb_register("inode", kdbm_inode, "", "Display inode", 0); ++ kdb_register("sb", kdbm_sb, "", "Display super_block", 0); ++ kdb_register("bh", kdbm_buffers, "", "Display buffer", 0); ++ kdb_register("bio", kdbm_bio, "", "Display bio", 0); ++ kdb_register("inode_pages", kdbm_inode_pages, "", "Display pages in an inode", 0); ++ kdb_register("req", kdbm_request, "", "dump request struct", 0); ++ kdb_register("rqueue", kdbm_rqueue, "", "dump request queue", 0); ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++ kdb_register("memmap", kdbm_memmap, "", "page table summary", 0); ++#endif ++ ++ return 0; ++} ++ ++ ++static void __exit kdbm_pg_exit(void) ++{ ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++ kdb_unregister("page"); ++#endif ++ kdb_unregister("inode"); ++ kdb_unregister("sb"); ++ kdb_unregister("bh"); ++ kdb_unregister("bio"); ++ kdb_unregister("inode_pages"); ++ kdb_unregister("req"); ++ kdb_unregister("rqueue"); ++#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_NUMA) ++ kdb_unregister("memmap"); ++#endif ++} ++ ++module_init(kdbm_pg_init) ++module_exit(kdbm_pg_exit) +--- /dev/null ++++ b/kdb/modules/kdbm_sched.c +@@ -0,0 +1,57 @@ ++/* ++ * 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) 2005 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("SGI"); ++MODULE_DESCRIPTION("Debug scheduler information"); ++MODULE_LICENSE("GPL"); ++ ++static int ++kdbm_runqueues(int argc, const char **argv) ++{ ++ unsigned long cpu; ++ int ret = 0; ++ ++ if (argc == 1) { ++ ret = kdbgetularg((char *)argv[1], &cpu); ++ if (!ret) { ++ if (!cpu_online(cpu)) { ++ kdb_printf("Invalid cpu number\n"); ++ } else ++ kdb_runqueue(cpu, kdb_printf); ++ } ++ } else if (argc == 0) { ++ for_each_online_cpu(cpu) ++ kdb_runqueue(cpu, kdb_printf); ++ } else { ++ /* More than one arg */ ++ kdb_printf("Specify one cpu number\n"); ++ } ++ return ret; ++} ++ ++static int __init kdbm_sched_init(void) ++{ ++ kdb_register("rq", kdbm_runqueues, "", "Display runqueue for ", 0); ++ kdb_register("rqa", kdbm_runqueues, "", "Display all runqueues", 0); ++ return 0; ++} ++ ++static void __exit kdbm_sched_exit(void) ++{ ++ kdb_unregister("rq"); ++ kdb_unregister("rqa"); ++} ++ ++module_init(kdbm_sched_init) ++module_exit(kdbm_sched_exit) +--- /dev/null ++++ b/kdb/modules/kdbm_task.c +@@ -0,0 +1,205 @@ ++/* ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("SGI"); ++MODULE_DESCRIPTION("Debug struct task and sigset information"); ++MODULE_LICENSE("GPL"); ++ ++static char * ++kdb_cpus_allowed_string(struct task_struct *tp) ++{ ++ static char maskbuf[NR_CPUS * 8]; ++ if (cpus_equal(tp->cpus_allowed, cpu_online_map)) ++ strcpy(maskbuf, "ALL"); ++ else if (cpus_full(tp->cpus_allowed)) ++ strcpy(maskbuf, "ALL(NR_CPUS)"); ++ else if (cpus_empty(tp->cpus_allowed)) ++ strcpy(maskbuf, "NONE"); ++ else if (cpus_weight(tp->cpus_allowed) == 1) ++ snprintf(maskbuf, sizeof(maskbuf), "ONLY(%d)", first_cpu(tp->cpus_allowed)); ++ else ++ cpulist_scnprintf(maskbuf, sizeof(maskbuf), tp->cpus_allowed); ++ return maskbuf; ++} ++ ++static int ++kdbm_task(int argc, const char **argv) ++{ ++ unsigned long addr; ++ long offset=0; ++ int nextarg; ++ int e = 0; ++ struct task_struct *tp = NULL, *tp1; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((e = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) != 0) ++ return(e); ++ ++ if (!(tp = kmalloc(sizeof(*tp), GFP_ATOMIC))) { ++ kdb_printf("%s: cannot kmalloc tp\n", __FUNCTION__); ++ goto out; ++ } ++ if ((e = kdb_getarea(*tp, addr))) { ++ kdb_printf("%s: invalid task address\n", __FUNCTION__); ++ goto out; ++ } ++ ++ tp1 = (struct task_struct *)addr; ++ kdb_printf( ++ "struct task at 0x%lx, pid=%d flags=0x%x state=%ld comm=\"%s\"\n", ++ addr, tp->pid, tp->flags, tp->state, tp->comm); ++ ++ kdb_printf(" cpu=%d policy=%u ", kdb_process_cpu(tp), tp->policy); ++ kdb_printf( ++ "prio=%d static_prio=%d cpus_allowed=", ++ tp->prio, tp->static_prio); ++ { ++ /* The cpus allowed string may be longer than kdb_printf() can ++ * handle. Print it in chunks. ++ */ ++ char c, *p; ++ p = kdb_cpus_allowed_string(tp); ++ while (1) { ++ if (strlen(p) < 100) { ++ kdb_printf("%s", p); ++ break; ++ } ++ c = p[100]; ++ p[100] = '\0'; ++ kdb_printf("%s", p); ++ p[100] = c; ++ p += 100; ++ } ++ } ++ kdb_printf(" &thread=0x%p\n", &tp1->thread); ++ ++ kdb_printf(" need_resched=%d ", ++ test_tsk_thread_flag(tp, TIF_NEED_RESCHED)); ++ kdb_printf( ++ "time_slice=%u", ++ tp->rt.time_slice); ++ kdb_printf(" lock_depth=%d\n", tp->lock_depth); ++ ++ kdb_printf( ++ " fs=0x%p files=0x%p mm=0x%p\n", ++ tp->fs, tp->files, tp->mm); ++ ++ kdb_printf( ++ " uid=%d euid=%d suid=%d fsuid=%d gid=%d egid=%d sgid=%d fsgid=%d\n", ++ tp->uid, tp->euid, tp->suid, tp->fsuid, tp->gid, tp->egid, tp->sgid, tp->fsgid); ++ ++ kdb_printf( ++ " user=0x%p\n", ++ tp->user); ++ ++ if (tp->sysvsem.undo_list) ++ kdb_printf( ++ " sysvsem.sem_undo refcnt %d list_proc=0x%p\n", ++ atomic_read(&tp->sysvsem.undo_list->refcnt), ++ &tp->sysvsem.undo_list->list_proc); ++ ++ kdb_printf( ++ " signal=0x%p &blocked=0x%p &pending=0x%p\n", ++ tp->signal, &tp1->blocked, &tp1->pending); ++ ++ kdb_printf( ++ " utime=%ld stime=%ld cutime=%ld cstime=%ld\n", ++ tp->utime, tp->stime, ++ tp->signal ? tp->signal->cutime : 0L, ++ tp->signal ? tp->signal->cstime : 0L); ++ ++ kdb_printf(" thread_info=0x%p\n", task_thread_info(tp)); ++ kdb_printf(" ti flags=0x%lx\n", (unsigned long)task_thread_info(tp)->flags); ++ ++#ifdef CONFIG_NUMA ++ kdb_printf( ++ " mempolicy=0x%p il_next=%d\n", ++ tp->mempolicy, tp->il_next); ++#endif ++ ++out: ++ if (tp) ++ kfree(tp); ++ return e; ++} ++ ++static int ++kdbm_sigset(int argc, const char **argv) ++{ ++ sigset_t *sp = NULL; ++ unsigned long addr; ++ long offset=0; ++ int nextarg; ++ int e = 0; ++ int i; ++ char fmt[32]; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++#ifndef _NSIG_WORDS ++ kdb_printf("unavailable on this platform, _NSIG_WORDS not defined.\n"); ++#else ++ nextarg = 1; ++ if ((e = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) != 0) ++ return(e); ++ ++ if (!(sp = kmalloc(sizeof(*sp), GFP_ATOMIC))) { ++ kdb_printf("%s: cannot kmalloc sp\n", __FUNCTION__); ++ goto out; ++ } ++ if ((e = kdb_getarea(*sp, addr))) { ++ kdb_printf("%s: invalid sigset address\n", __FUNCTION__); ++ goto out; ++ } ++ ++ sprintf(fmt, "[%%d]=0x%%0%dlx ", (int)sizeof(sp->sig[0])*2); ++ kdb_printf("sigset at 0x%p : ", sp); ++ for (i=_NSIG_WORDS-1; i >= 0; i--) { ++ if (i == 0 || sp->sig[i]) { ++ kdb_printf(fmt, i, sp->sig[i]); ++ } ++ } ++ kdb_printf("\n"); ++#endif /* _NSIG_WORDS */ ++ ++out: ++ if (sp) ++ kfree(sp); ++ return e; ++} ++ ++static int __init kdbm_task_init(void) ++{ ++ kdb_register("task", kdbm_task, "", "Display task_struct", 0); ++ kdb_register("sigset", kdbm_sigset, "", "Display sigset_t", 0); ++ ++ return 0; ++} ++ ++static void __exit kdbm_task_exit(void) ++{ ++ kdb_unregister("task"); ++ kdb_unregister("sigset"); ++} ++ ++module_init(kdbm_task_init) ++module_exit(kdbm_task_exit) +--- /dev/null ++++ b/kdb/modules/kdbm_vm.c +@@ -0,0 +1,1036 @@ ++/* ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("SGI"); ++MODULE_DESCRIPTION("Debug VM information"); ++MODULE_LICENSE("GPL"); ++ ++struct __vmflags { ++ unsigned long mask; ++ char *name; ++}; ++ ++static struct __vmflags vmflags[] = { ++ { VM_READ, "VM_READ " }, ++ { VM_WRITE, "VM_WRITE " }, ++ { VM_EXEC, "VM_EXEC " }, ++ { VM_SHARED, "VM_SHARED " }, ++ { VM_MAYREAD, "VM_MAYREAD " }, ++ { VM_MAYWRITE, "VM_MAYWRITE " }, ++ { VM_MAYEXEC, "VM_MAYEXEC " }, ++ { VM_MAYSHARE, "VM_MAYSHARE " }, ++ { VM_GROWSDOWN, "VM_GROWSDOWN " }, ++ { VM_GROWSUP, "VM_GROWSUP " }, ++ { VM_PFNMAP, "VM_PFNMAP " }, ++ { VM_DENYWRITE, "VM_DENYWRITE " }, ++ { VM_EXECUTABLE, "VM_EXECUTABLE " }, ++ { VM_LOCKED, "VM_LOCKED " }, ++ { VM_IO, "VM_IO " }, ++ { VM_SEQ_READ, "VM_SEQ_READ " }, ++ { VM_RAND_READ, "VM_RAND_READ " }, ++ { VM_DONTCOPY, "VM_DONTCOPY " }, ++ { VM_DONTEXPAND, "VM_DONTEXPAND " }, ++ { VM_RESERVED, "VM_RESERVED " }, ++ { VM_ACCOUNT, "VM_ACCOUNT " }, ++ { VM_HUGETLB, "VM_HUGETLB " }, ++ { VM_NONLINEAR, "VM_NONLINEAR " }, ++ { VM_MAPPED_COPY, "VM_MAPPED_COPY " }, ++ { VM_INSERTPAGE, "VM_INSERTPAGE " }, ++ { 0, "" } ++}; ++ ++static int ++kdbm_print_vm(struct vm_area_struct *vp, unsigned long addr, int verbose_flg) ++{ ++ struct __vmflags *tp; ++ ++ kdb_printf("struct vm_area_struct at 0x%lx for %d bytes\n", ++ addr, (int) sizeof (struct vm_area_struct)); ++ ++ kdb_printf("vm_start = 0x%p vm_end = 0x%p\n", (void *) vp->vm_start, ++ (void *) vp->vm_end); ++ kdb_printf("vm_page_prot = 0x%llx\n", ++ (unsigned long long)pgprot_val(vp->vm_page_prot)); ++ ++ kdb_printf("vm_flags: "); ++ for (tp = vmflags; tp->mask; tp++) { ++ if (vp->vm_flags & tp->mask) { ++ kdb_printf(" %s", tp->name); ++ } ++ } ++ kdb_printf("\n"); ++ ++ if (!verbose_flg) ++ return 0; ++ ++ kdb_printf("vm_mm = 0x%p\n", (void *) vp->vm_mm); ++ kdb_printf("vm_next = 0x%p\n", (void *) vp->vm_next); ++ kdb_printf("shared.vm_set.list.next = 0x%p\n", (void *) vp->shared.vm_set.list.next); ++ kdb_printf("shared.vm_set.list.prev = 0x%p\n", (void *) vp->shared.vm_set.list.prev); ++ kdb_printf("shared.vm_set.parent = 0x%p\n", (void *) vp->shared.vm_set.parent); ++ kdb_printf("shared.vm_set.head = 0x%p\n", (void *) vp->shared.vm_set.head); ++ kdb_printf("anon_vma_node.next = 0x%p\n", (void *) vp->anon_vma_node.next); ++ kdb_printf("anon_vma_node.prev = 0x%p\n", (void *) vp->anon_vma_node.prev); ++ kdb_printf("vm_ops = 0x%p\n", (void *) vp->vm_ops); ++ if (vp->vm_ops != NULL) { ++ kdb_printf("vm_ops->open = 0x%p\n", vp->vm_ops->open); ++ kdb_printf("vm_ops->close = 0x%p\n", vp->vm_ops->close); ++ kdb_printf("vm_ops->fault = 0x%p\n", vp->vm_ops->fault); ++#ifdef HAVE_VMOP_MPROTECT ++ kdb_printf("vm_ops->mprotect = 0x%p\n", vp->vm_ops->mprotect); ++#endif ++#ifdef CONFIG_NUMA ++ kdb_printf("vm_ops->set_policy = 0x%p\n", vp->vm_ops->set_policy); ++ kdb_printf("vm_ops->get_policy = 0x%p\n", vp->vm_ops->get_policy); ++#endif ++ } ++ kdb_printf("vm_pgoff = 0x%lx\n", vp->vm_pgoff); ++ kdb_printf("vm_file = 0x%p\n", (void *) vp->vm_file); ++ kdb_printf("vm_private_data = 0x%p\n", vp->vm_private_data); ++#ifdef CONFIG_NUMA ++ kdb_printf("vm_policy = 0x%p\n", vp->vm_policy); ++#endif ++ ++ return 0; ++} ++ ++static int ++kdbm_print_vmp(struct vm_area_struct *vp, int verbose_flg) ++{ ++ struct __vmflags *tp; ++ ++ if (verbose_flg) { ++ kdb_printf("0x%lx: ", (unsigned long) vp); ++ } ++ ++ kdb_printf("0x%p 0x%p ", (void *) vp->vm_start, (void *) vp->vm_end); ++ ++ for (tp = vmflags; tp->mask; tp++) { ++ if (vp->vm_flags & tp->mask) { ++ kdb_printf(" %s", tp->name); ++ } ++ } ++ kdb_printf("\n"); ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_NUMA ++#include ++ ++/* ++ * kdbm_mpol ++ * ++ * This function implements the 'mempolicy' command. ++ * Print a struct mempolicy. ++ * ++ * mempolicy
Print struct mempolicy at
++ */ ++static int ++kdbm_mpol(int argc, const char **argv) ++{ ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ int err = 0; ++ struct mempolicy *mp = NULL; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((err = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, ++ NULL)) != 0) ++ return(err); ++ ++ if (!(mp = kmalloc(sizeof(*mp), GFP_ATOMIC))) { ++ kdb_printf("%s: cannot kmalloc mp\n", __FUNCTION__); ++ goto out; ++ } ++ ++ if ((err = kdb_getarea(*mp, addr))) { ++ kdb_printf("%s: invalid mempolicy address\n", __FUNCTION__); ++ goto out; ++ } ++ ++ kdb_printf("struct mempolicy at 0x%p\n", (struct mempolicy *)addr); ++ kdb_printf(" refcnt %d\n", atomic_read(&mp->refcnt)); ++ ++ switch (mp->mode) { ++ case MPOL_DEFAULT: ++ kdb_printf(" mode %d (MPOL_DEFAULT)\n", mp->mode); ++ break; ++ ++ case MPOL_PREFERRED: ++ kdb_printf(" mode %d (MPOL_PREFERRED)\n", mp->mode); ++ kdb_printf(" preferred_node %d\n", mp->v.preferred_node); ++ break; ++ ++ case MPOL_BIND: ++ case MPOL_INTERLEAVE: ++ { ++ int i, nlongs; ++ unsigned long *longp; ++ ++ kdb_printf(" mode %d (%s)\n", mp->mode, ++ mp->mode == MPOL_INTERLEAVE ++ ? "MPOL_INTERLEAVE" ++ : "MPOL_BIND"); ++ nlongs = (int)BITS_TO_LONGS(MAX_NUMNODES); ++ kdb_printf(" nodes:"); ++ longp = mp->v.nodes.bits; ++ for (i = 0; i < nlongs; i++, longp++) ++ kdb_printf(" 0x%lx ", *longp); ++ kdb_printf("\n"); ++ break; ++ } ++ ++ default: ++ kdb_printf(" mode %d (unknown)\n", mp->mode); ++ break; ++ } ++out: ++ if (mp) ++ kfree(mp); ++ return err; ++} ++ ++#endif /* CONFIG_NUMA */ ++ ++/* ++ * kdbm_pgdat ++ * ++ * This function implements the 'pgdat' command. ++ * Print a struct pglist_data (pg_dat_t). ++ * ++ * pgdat Print struct pglist_data for node . ++ * ++ * Print pglist_data for node 0 if node_id not specified, ++ * or print the one pglist_data structure if !CONFIG_NUMA. ++ */ ++static int ++kdbm_pgdat(int argc, const char **argv) ++{ ++ int err = 0, node_id = 0, i; ++ pg_data_t *pgdatp = NULL; ++ ++#ifdef CONFIG_NUMA ++ if (argc > 1) ++ return KDB_ARGCOUNT; ++ if (argc == 1) { ++ int nextarg; ++ long offset = 0; ++ unsigned long node_id_ul; ++ ++ nextarg = 1; ++ if ((err = kdbgetaddrarg(argc, argv, &nextarg, &node_id_ul, ++ &offset, NULL)) != 0) { ++ return(err); ++ } ++ node_id = (int)node_id_ul; ++ } ++#endif ++ for_each_online_pgdat(pgdatp) { ++ if (pgdatp->node_id == node_id) ++ break; ++ } ++ if (!pgdatp) { ++ kdb_printf("%s: specified node not found\n", __FUNCTION__); ++ return 0; ++ } ++ kdb_printf("struct pglist_data at 0x%p node_id = %d\n", ++ pgdatp, pgdatp->node_id); ++ ++ for (i = 0; i < MAX_ZONELISTS; i++) { ++ int zr; ++ struct zoneref *zonerefp; ++ struct zone *zonep; ++ ++ zonerefp = pgdatp->node_zonelists[i]._zonerefs; ++ kdb_printf(" _zonerefs[%d] at 0x%p\n", i, zonerefp); ++ ++ for (zr = 0; zr <= MAX_ZONES_PER_ZONELIST; zr++, zonerefp++) { ++ int z; ++ pg_data_t *tmp_pgdatp; ++ ++ zonep = zonelist_zone(zonerefp); ++ if (!zonep) ++ break; ++ ++ kdb_printf(" 0x%p", zonep); ++ ++ for_each_online_pgdat(tmp_pgdatp) { ++ for (z = 0; z < MAX_NR_ZONES; z++) { ++ if (zonep == &tmp_pgdatp->node_zones[z]) { ++ kdb_printf (" (node %d node_zones[%d])", ++ tmp_pgdatp->node_id, z); ++ break; ++ } ++ } ++ if (z != MAX_NR_ZONES) ++ break; /* found it */ ++ } ++ kdb_printf("\n"); ++ } ++ } ++ ++ kdb_printf(" nr_zones = %d", pgdatp->nr_zones); ++#ifdef CONFIG_FLAT_NODE_MEM_MAP ++ kdb_printf(" node_mem_map = 0x%p\n", pgdatp->node_mem_map); ++#endif ++ kdb_printf(" bdata = 0x%p", pgdatp->bdata); ++ kdb_printf(" node_start_pfn = 0x%lx\n", pgdatp->node_start_pfn); ++ kdb_printf(" node_present_pages = %ld (0x%lx)\n", ++ pgdatp->node_present_pages, pgdatp->node_present_pages); ++ kdb_printf(" node_spanned_pages = %ld (0x%lx)\n", ++ pgdatp->node_spanned_pages, pgdatp->node_spanned_pages); ++ kdb_printf(" kswapd = 0x%p\n", pgdatp->kswapd); ++ ++ return err; ++} ++ ++/* ++ * kdbm_vm ++ * ++ * This function implements the 'vm' command. Print a vm_area_struct. ++ * ++ * vm [-v]
Print vm_area_struct at
++ * vmp [-v] Print all vm_area_structs for ++ */ ++ ++static int ++kdbm_vm(int argc, const char **argv) ++{ ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ int diag; ++ int verbose_flg = 0; ++ ++ if (argc == 2) { ++ if (strcmp(argv[1], "-v") != 0) { ++ return KDB_ARGCOUNT; ++ } ++ verbose_flg = 1; ++ } else if (argc != 1) { ++ return KDB_ARGCOUNT; ++ } ++ ++ if (strcmp(argv[0], "vmp") == 0) { ++ struct task_struct *g, *tp; ++ struct vm_area_struct *vp; ++ pid_t pid; ++ ++ if ((diag = kdbgetularg(argv[argc], (unsigned long *) &pid))) ++ return diag; ++ ++ kdb_do_each_thread(g, tp) { ++ if (tp->pid == pid) { ++ if (tp->mm != NULL) { ++ if (verbose_flg) ++ kdb_printf ++ ("vm_area_struct "); ++ kdb_printf ++ ("vm_start vm_end vm_flags\n"); ++ vp = tp->mm->mmap; ++ while (vp != NULL) { ++ kdbm_print_vmp(vp, verbose_flg); ++ vp = vp->vm_next; ++ } ++ } ++ return 0; ++ } ++ } kdb_while_each_thread(g, tp); ++ ++ kdb_printf("No process with pid == %d found\n", pid); ++ ++ } else { ++ struct vm_area_struct v; ++ ++ nextarg = argc; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, ++ NULL)) ++ || (diag = kdb_getarea(v, addr))) ++ return (diag); ++ ++ kdbm_print_vm(&v, addr, verbose_flg); ++ } ++ ++ return 0; ++} ++ ++static int ++kdbm_print_pte(pte_t * pte) ++{ ++ kdb_printf("0x%lx (", (unsigned long) pte_val(*pte)); ++ ++ if (pte_present(*pte)) { ++#ifdef pte_exec ++ if (pte_exec(*pte)) ++ kdb_printf("X"); ++#endif ++ if (pte_write(*pte)) ++ kdb_printf("W"); ++#ifdef pte_read ++ if (pte_read(*pte)) ++ kdb_printf("R"); ++#endif ++ if (pte_young(*pte)) ++ kdb_printf("A"); ++ if (pte_dirty(*pte)) ++ kdb_printf("D"); ++ ++ } else { ++ kdb_printf("OFFSET=0x%lx ", swp_offset(pte_to_swp_entry(*pte))); ++ kdb_printf("TYPE=0x%ulx", swp_type(pte_to_swp_entry(*pte))); ++ } ++ ++ kdb_printf(")"); ++ ++ /* final newline is output by caller of kdbm_print_pte() */ ++ ++ return 0; ++} ++ ++/* ++ * kdbm_pte ++ * ++ * This function implements the 'pte' command. Print all pte_t structures ++ * that map to the given virtual address range (
through
++ * plus ) for the given process. The default value for nbytes is ++ * one. ++ * ++ * pte -m
[] Print all pte_t structures for ++ * virtual
in address space ++ * of which is a pointer to a ++ * mm_struct ++ * pte -p
[] Print all pte_t structures for ++ * virtual
in address space ++ * of ++ */ ++ ++static int ++kdbm_pte(int argc, const char **argv) ++{ ++ unsigned long addr; ++ long offset = 0; ++ int nextarg; ++ unsigned long nbytes = 1; ++ long npgs; ++ int diag; ++ int found; ++ pid_t pid; ++ struct task_struct *tp; ++ struct mm_struct *mm, copy_of_mm; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ if (argc < 3 || argc > 4) { ++ return KDB_ARGCOUNT; ++ } ++ ++ if (strcmp(argv[1], "-p") == 0) { ++ if ((diag = kdbgetularg(argv[2], (unsigned long *) &pid))) { ++ return diag; ++ } ++ ++ found = 0; ++ for_each_process(tp) { ++ if (tp->pid == pid) { ++ if (tp->mm != NULL) { ++ found = 1; ++ break; ++ } ++ kdb_printf("task structure's mm field is NULL\n"); ++ return 0; ++ } ++ } ++ ++ if (!found) { ++ kdb_printf("No process with pid == %d found\n", pid); ++ return 0; ++ } ++ mm = tp->mm; ++ } else if (strcmp(argv[1], "-m") == 0) { ++ ++ ++ nextarg = 2; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, ++ NULL)) ++ || (diag = kdb_getarea(copy_of_mm, addr))) ++ return (diag); ++ mm = ©_of_mm; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ if ((diag = kdbgetularg(argv[3], &addr))) { ++ return diag; ++ } ++ ++ if (argc == 4) { ++ if ((diag = kdbgetularg(argv[4], &nbytes))) { ++ return diag; ++ } ++ } ++ ++ kdb_printf("vaddr pte\n"); ++ ++ npgs = ((((addr & ~PAGE_MASK) + nbytes) + ~PAGE_MASK) >> PAGE_SHIFT); ++ while (npgs-- > 0) { ++ ++ kdb_printf("0x%p ", (void *) (addr & PAGE_MASK)); ++ ++ pgd = pgd_offset(mm, addr); ++ if (pgd_present(*pgd)) { ++ pud = pud_offset(pgd, addr); ++ if (pud_present(*pud)) { ++ pmd = pmd_offset(pud, addr); ++ if (pmd_present(*pmd)) { ++ pte = pte_offset_map(pmd, addr); ++ if (pte_present(*pte)) { ++ kdbm_print_pte(pte); ++ } ++ } ++ } ++ } ++ ++ kdb_printf("\n"); ++ addr += PAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++/* ++ * kdbm_rpte ++ * ++ * This function implements the 'rpte' command. Print all pte_t structures ++ * that contain the given physical page range ( through ++ * plus ) for the given process. The default value for npages is ++ * one. ++ * ++ * rpte -m [] Print all pte_t structures for ++ * physical page in address space ++ * of which is a pointer to a ++ * mm_struct ++ * rpte -p [] Print all pte_t structures for ++ * physical page in address space ++ * of ++ */ ++ ++static int ++kdbm_rpte(int argc, const char **argv) ++{ ++ unsigned long addr; ++ unsigned long pfn; ++ long offset = 0; ++ int nextarg; ++ unsigned long npages = 1; ++ int diag; ++ int found; ++ pid_t pid; ++ struct task_struct *tp; ++ struct mm_struct *mm, copy_of_mm; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long g, u, m, t; ++ ++ if (argc < 3 || argc > 4) { ++ return KDB_ARGCOUNT; ++ } ++ ++ if (strcmp(argv[1], "-p") == 0) { ++ if ((diag = kdbgetularg(argv[2], (unsigned long *) &pid))) { ++ return diag; ++ } ++ ++ found = 0; ++ for_each_process(tp) { ++ if (tp->pid == pid) { ++ if (tp->mm != NULL) { ++ found = 1; ++ break; ++ } ++ kdb_printf("task structure's mm field is NULL\n"); ++ return 0; ++ } ++ } ++ ++ if (!found) { ++ kdb_printf("No process with pid == %d found\n", pid); ++ return 0; ++ } ++ mm = tp->mm; ++ } else if (strcmp(argv[1], "-m") == 0) { ++ ++ ++ nextarg = 2; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, ++ NULL)) ++ || (diag = kdb_getarea(copy_of_mm, addr))) ++ return (diag); ++ mm = ©_of_mm; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ if ((diag = kdbgetularg(argv[3], &pfn))) { ++ return diag; ++ } ++ ++ if (argc == 4) { ++ if ((diag = kdbgetularg(argv[4], &npages))) { ++ return diag; ++ } ++ } ++ ++ /* spaces after vaddr depends on sizeof(unsigned long) */ ++ kdb_printf("pfn vaddr%*s pte\n", ++ (int)(2*sizeof(unsigned long) + 2 - 5), " "); ++ ++ for (g = 0, pgd = pgd_offset(mm, 0UL); g < PTRS_PER_PGD; ++g, ++pgd) { ++ if (pgd_none(*pgd) || pgd_bad(*pgd)) ++ continue; ++ for (u = 0, pud = pud_offset(pgd, 0UL); u < PTRS_PER_PUD; ++u, ++pud) { ++ if (pud_none(*pud) || pud_bad(*pud)) ++ continue; ++ for (m = 0, pmd = pmd_offset(pud, 0UL); m < PTRS_PER_PMD; ++m, ++pmd) { ++ if (pmd_none(*pmd) || pmd_bad(*pmd)) ++ continue; ++ for (t = 0, pte = pte_offset_map(pmd, 0UL); t < PTRS_PER_PTE; ++t, ++pte) { ++ if (pte_none(*pte)) ++ continue; ++ if (pte_pfn(*pte) < pfn || pte_pfn(*pte) >= (pfn + npages)) ++ continue; ++ addr = g << PGDIR_SHIFT; ++#ifdef __ia64__ ++ /* IA64 plays tricks with the pgd mapping to save space. ++ * This reverses pgd_index(). ++ */ ++ { ++ unsigned long region = g >> (PAGE_SHIFT - 6); ++ unsigned long l1index = g - (region << (PAGE_SHIFT - 6)); ++ addr = (region << 61) + (l1index << PGDIR_SHIFT); ++ } ++#endif ++ addr += (m << PMD_SHIFT) + (t << PAGE_SHIFT); ++ kdb_printf("0x%-14lx " kdb_bfd_vma_fmt0 " ", ++ pte_pfn(*pte), addr); ++ kdbm_print_pte(pte); ++ kdb_printf("\n"); ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++kdbm_print_dentry(unsigned long daddr) ++{ ++ struct dentry d; ++ int diag; ++ char buf[256]; ++ ++ kdb_printf("Dentry at 0x%lx\n", daddr); ++ if ((diag = kdb_getarea(d, (unsigned long)daddr))) ++ return diag; ++ ++ if ((d.d_name.len > sizeof(buf)) || (diag = kdb_getarea_size(buf, (unsigned long)(d.d_name.name), d.d_name.len))) ++ kdb_printf(" d_name.len = %d d_name.name = 0x%p\n", ++ d.d_name.len, d.d_name.name); ++ else ++ kdb_printf(" d_name.len = %d d_name.name = 0x%p <%.*s>\n", ++ d.d_name.len, d.d_name.name, ++ (int)(d.d_name.len), d.d_name.name); ++ ++ kdb_printf(" d_count = %d d_flags = 0x%x d_inode = 0x%p\n", ++ atomic_read(&d.d_count), d.d_flags, d.d_inode); ++ ++ kdb_printf(" d_parent = 0x%p\n", d.d_parent); ++ ++ kdb_printf(" d_hash.nxt = 0x%p d_hash.prv = 0x%p\n", ++ d.d_hash.next, d.d_hash.pprev); ++ ++ kdb_printf(" d_lru.nxt = 0x%p d_lru.prv = 0x%p\n", ++ d.d_lru.next, d.d_lru.prev); ++ ++ kdb_printf(" d_child.nxt = 0x%p d_child.prv = 0x%p\n", ++ d.d_u.d_child.next, d.d_u.d_child.prev); ++ ++ kdb_printf(" d_subdirs.nxt = 0x%p d_subdirs.prv = 0x%p\n", ++ d.d_subdirs.next, d.d_subdirs.prev); ++ ++ kdb_printf(" d_alias.nxt = 0x%p d_alias.prv = 0x%p\n", ++ d.d_alias.next, d.d_alias.prev); ++ ++ kdb_printf(" d_op = 0x%p d_sb = 0x%p d_fsdata = 0x%p\n", ++ d.d_op, d.d_sb, d.d_fsdata); ++ ++ kdb_printf(" d_iname = %s\n", ++ d.d_iname); ++ ++ if (d.d_inode) { ++ struct inode i; ++ kdb_printf("\nInode Entry at 0x%p\n", d.d_inode); ++ if ((diag = kdb_getarea(i, (unsigned long)d.d_inode))) ++ return diag; ++ kdb_printf(" i_mode = 0%o i_nlink = %d i_rdev = 0x%x\n", ++ i.i_mode, i.i_nlink, i.i_rdev); ++ ++ kdb_printf(" i_ino = %ld i_count = %d\n", ++ i.i_ino, atomic_read(&i.i_count)); ++ ++ kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", ++ i.i_hash.next, i.i_hash.pprev); ++ ++ kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", ++ i.i_list.next, i.i_list.prev); ++ ++ kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", ++ i.i_dentry.next, i.i_dentry.prev); ++ ++ } ++ kdb_printf("\n"); ++ return 0; ++} ++ ++static int ++kdbm_filp(int argc, const char **argv) ++{ ++ struct file f; ++ int nextarg; ++ unsigned long addr; ++ long offset; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(f, addr))) ++ return diag; ++ ++ kdb_printf("File Pointer at 0x%lx\n", addr); ++ ++ kdb_printf(" fu_list.nxt = 0x%p fu_list.prv = 0x%p\n", ++ f.f_u.fu_list.next, f.f_u.fu_list.prev); ++ ++ kdb_printf(" f_dentry = 0x%p f_vfsmnt = 0x%p f_op = 0x%p\n", ++ f.f_dentry, f.f_vfsmnt, f.f_op); ++ ++ kdb_printf(" f_count = %lld f_flags = 0x%x f_mode = 0x%x\n", ++ atomic_read(&f.f_count), f.f_flags, f.f_mode); ++ ++ kdb_printf(" f_pos = %Ld\n", f.f_pos); ++#ifdef CONFIG_SECURITY ++ kdb_printf(" security = 0x%p\n", f.f_security); ++#endif ++ ++ kdb_printf(" private_data = 0x%p f_mapping = 0x%p\n\n", ++ f.private_data, f.f_mapping); ++ ++ return kdbm_print_dentry((unsigned long)f.f_dentry); ++} ++ ++static int ++kdbm_fl(int argc, const char **argv) ++{ ++ struct file_lock fl; ++ int nextarg; ++ unsigned long addr; ++ long offset; ++ int diag; ++ ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(fl, addr))) ++ return diag; ++ ++ kdb_printf("File_lock at 0x%lx\n", addr); ++ ++ kdb_printf(" fl_next = 0x%p fl_link.nxt = 0x%p fl_link.prv = 0x%p\n", ++ fl.fl_next, fl.fl_link.next, fl.fl_link.prev); ++ kdb_printf(" fl_block.nxt = 0x%p fl_block.prv = 0x%p\n", ++ fl.fl_block.next, fl.fl_block.prev); ++ kdb_printf(" fl_owner = 0x%p fl_pid = %d fl_wait = 0x%p\n", ++ fl.fl_owner, fl.fl_pid, &fl.fl_wait); ++ kdb_printf(" fl_file = 0x%p fl_flags = 0x%x\n", ++ fl.fl_file, fl.fl_flags); ++ kdb_printf(" fl_type = %d fl_start = 0x%llx fl_end = 0x%llx\n", ++ fl.fl_type, fl.fl_start, fl.fl_end); ++ ++ kdb_printf(" file_lock_operations"); ++ if (fl.fl_ops) ++ kdb_printf("\n fl_copy_lock = 0x%p fl_release_private = 0x%p\n", ++ fl.fl_ops->fl_copy_lock, fl.fl_ops->fl_release_private); ++ else ++ kdb_printf(" empty\n"); ++ ++ kdb_printf(" lock_manager_operations"); ++ if (fl.fl_lmops) ++ kdb_printf("\n fl_compare_owner = 0x%p fl_notify = 0x%p\n", ++ fl.fl_lmops->fl_compare_owner, fl.fl_lmops->fl_notify); ++ else ++ kdb_printf(" empty\n"); ++ ++ kdb_printf(" fl_fasync = 0x%p fl_break 0x%lx\n", ++ fl.fl_fasync, fl.fl_break_time); ++ ++ return 0; ++} ++ ++ ++static int ++kdbm_dentry(int argc, const char **argv) ++{ ++ int nextarg; ++ unsigned long addr; ++ long offset; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL))) ++ return diag; ++ ++ return kdbm_print_dentry(addr); ++} ++ ++static int ++kdbm_kobject(int argc, const char **argv) ++{ ++ struct kobject k; ++ int nextarg; ++ unsigned long addr; ++ long offset; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(k, addr))) ++ return diag; ++ ++ ++ kdb_printf("kobject at 0x%lx\n", addr); ++ ++ if (k.name) { ++ char c; ++ kdb_printf(" name 0x%p", k.name); ++ if (kdb_getarea(c, (unsigned long)k.name) == 0) ++ kdb_printf(" '%s'", k.name); ++ kdb_printf("\n"); ++ } ++ ++ if (k.name != kobject_name((struct kobject *)addr)) ++ kdb_printf(" name '%.20s'\n", k.name); ++ ++ kdb_printf(" kref.refcount %d'\n", atomic_read(&k.kref.refcount)); ++ ++ kdb_printf(" entry.next = 0x%p entry.prev = 0x%p\n", ++ k.entry.next, k.entry.prev); ++ ++ kdb_printf(" parent = 0x%p kset = 0x%p ktype = 0x%p sd = 0x%p\n", ++ k.parent, k.kset, k.ktype, k.sd); ++ ++ return 0; ++} ++ ++static int ++kdbm_sh(int argc, const char **argv) ++{ ++ int diag; ++ int nextarg; ++ unsigned long addr; ++ long offset = 0L; ++ struct Scsi_Host sh; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL)) || ++ (diag = kdb_getarea(sh, addr))) ++ return diag; ++ ++ kdb_printf("Scsi_Host at 0x%lx\n", addr); ++ kdb_printf("host_queue = 0x%p\n", sh.__devices.next); ++ kdb_printf("ehandler = 0x%p eh_action = 0x%p\n", ++ sh.ehandler, sh.eh_action); ++ kdb_printf("host_wait = 0x%p hostt = 0x%p\n", ++ &sh.host_wait, sh.hostt); ++ kdb_printf("host_failed = %d host_no = %d resetting = %d\n", ++ sh.host_failed, sh.host_no, sh.resetting); ++ kdb_printf("max id/lun/channel = [%d/%d/%d] this_id = %d\n", ++ sh.max_id, sh.max_lun, sh.max_channel, sh.this_id); ++ kdb_printf("can_queue = %d cmd_per_lun = %d sg_tablesize = %d u_isa_dma = %d\n", ++ sh.can_queue, sh.cmd_per_lun, sh.sg_tablesize, sh.unchecked_isa_dma); ++ kdb_printf("host_blocked = %d reverse_ordering = %d \n", ++ sh.host_blocked, sh.reverse_ordering); ++ ++ return 0; ++} ++ ++static int ++kdbm_sd(int argc, const char **argv) ++{ ++ int diag; ++ int nextarg; ++ unsigned long addr; ++ long offset = 0L; ++ struct scsi_device *sd = NULL; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL))) ++ goto out; ++ if (!(sd = kmalloc(sizeof(*sd), GFP_ATOMIC))) { ++ kdb_printf("kdbm_sd: cannot kmalloc sd\n"); ++ goto out; ++ } ++ if ((diag = kdb_getarea(*sd, addr))) ++ goto out; ++ ++ kdb_printf("scsi_device at 0x%lx\n", addr); ++ kdb_printf("next = 0x%p prev = 0x%p host = 0x%p\n", ++ sd->siblings.next, sd->siblings.prev, sd->host); ++ kdb_printf("device_busy = %d current_cmnd 0x%p\n", ++ sd->device_busy, sd->current_cmnd); ++ kdb_printf("id/lun/chan = [%d/%d/%d] single_lun = %d device_blocked = %d\n", ++ sd->id, sd->lun, sd->channel, sd->sdev_target->single_lun, sd->device_blocked); ++ kdb_printf("queue_depth = %d current_tag = %d scsi_level = %d\n", ++ sd->queue_depth, sd->current_tag, sd->scsi_level); ++ kdb_printf("%8.8s %16.16s %4.4s\n", sd->vendor, sd->model, sd->rev); ++out: ++ if (sd) ++ kfree(sd); ++ return diag; ++} ++ ++static int ++kdbm_sc(int argc, const char **argv) ++{ ++ int diag; ++ int nextarg; ++ unsigned long addr; ++ long offset = 0L; ++ struct scsi_cmnd *sc = NULL; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ nextarg = 1; ++ if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL))) ++ goto out; ++ if (!(sc = kmalloc(sizeof(*sc), GFP_ATOMIC))) { ++ kdb_printf("kdbm_sc: cannot kmalloc sc\n"); ++ goto out; ++ } ++ if ((diag = kdb_getarea(*sc, addr))) ++ goto out; ++ ++ kdb_printf("scsi_cmnd at 0x%lx\n", addr); ++ kdb_printf("device = 0x%p next = 0x%p\n", ++ sc->device, sc->list.next); ++ kdb_printf("serial_number = %ld retries = %d\n", ++ sc->serial_number, sc->retries); ++ kdb_printf("cmd_len = %d\n", sc->cmd_len); ++ kdb_printf("cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", ++ sc->cmnd[0], sc->cmnd[1], sc->cmnd[2], sc->cmnd[3], sc->cmnd[4], ++ sc->cmnd[5], sc->cmnd[6], sc->cmnd[7], sc->cmnd[8], sc->cmnd[9], ++ sc->cmnd[10], sc->cmnd[11]); ++ kdb_printf("request_buffer = 0x%p request_bufflen = %d\n", ++ scsi_sglist(sc), scsi_bufflen(sc)); ++ kdb_printf("use_sg = %d\n", scsi_sg_count(sc)); ++ kdb_printf("underflow = %d transfersize = %d\n", ++ sc->underflow, sc->transfersize); ++ kdb_printf("tag = %d\n", sc->tag); ++ ++out: ++ if (sc) ++ kfree(sc); ++ return diag; ++} ++ ++static int __init kdbm_vm_init(void) ++{ ++ kdb_register("vm", kdbm_vm, "[-v] ", "Display vm_area_struct", 0); ++ kdb_register("vmp", kdbm_vm, "[-v] ", "Display all vm_area_struct for ", 0); ++#ifdef CONFIG_NUMA ++ kdb_register("mempolicy", kdbm_mpol, "", "Display mempolicy structure", 0); ++ kdb_register("pgdat", kdbm_pgdat, "", "Display pglist_data node structure", 0); ++#else ++ kdb_register("pgdat", kdbm_pgdat, "", "Display pglist_data node structure", 0); ++#endif ++ kdb_register("pte", kdbm_pte, "( -m | -p ) []", "Display pte_t for mm_struct or pid", 0); ++ kdb_register("rpte", kdbm_rpte, "( -m | -p ) []", "Find pte_t containing pfn for mm_struct or pid", 0); ++ kdb_register("dentry", kdbm_dentry, "", "Display interesting dentry stuff", 0); ++ kdb_register("kobject", kdbm_kobject, "", "Display interesting kobject stuff", 0); ++ kdb_register("filp", kdbm_filp, "", "Display interesting filp stuff", 0); ++ kdb_register("fl", kdbm_fl, "", "Display interesting file_lock stuff", 0); ++ kdb_register("sh", kdbm_sh, "", "Show scsi_host", 0); ++ kdb_register("sd", kdbm_sd, "", "Show scsi_device", 0); ++ kdb_register("sc", kdbm_sc, "", "Show scsi_cmnd", 0); ++ ++ return 0; ++} ++ ++static void __exit kdbm_vm_exit(void) ++{ ++ kdb_unregister("vm"); ++ kdb_unregister("vmp"); ++#ifdef CONFIG_NUMA ++ kdb_unregister("mempolicy"); ++#endif ++ kdb_unregister("pgdat"); ++ kdb_unregister("pte"); ++ kdb_unregister("rpte"); ++ kdb_unregister("dentry"); ++ kdb_unregister("kobject"); ++ kdb_unregister("filp"); ++ kdb_unregister("fl"); ++ kdb_unregister("sh"); ++ kdb_unregister("sd"); ++ kdb_unregister("sc"); ++} ++ ++module_init(kdbm_vm_init) ++module_exit(kdbm_vm_exit) +--- /dev/null ++++ b/kdb/modules/kdbm_x86.c +@@ -0,0 +1,1093 @@ ++/* ++ * 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. ++ * ++ * Author: Vamsi Krishna S. ++ * (C) 2003 IBM Corporation. ++ * 2006-10-10 Keith Owens ++ * Reworked to include x86_64 support ++ * Copyright (c) 2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#if 0 ++#include ++#endif ++ ++MODULE_AUTHOR("Vamsi Krishna S./IBM"); ++MODULE_DESCRIPTION("x86 specific information (gdt/idt/ldt/page tables)"); ++MODULE_LICENSE("GPL"); ++ ++/* Isolate as many of the i386/x86_64 differences as possible in one spot */ ++ ++#ifdef CONFIG_X86_64 ++ ++#define KDB_X86_64 1 ++#define MOVLQ "movq" ++ ++typedef struct desc_struct kdb_desc_t; ++typedef struct gate_struct64 kdb_gate_desc_t; ++ ++#define KDB_SYS_DESC_OFFSET(d) ((unsigned long)d->offset_high << 32 | d->offset_middle << 16 | d->offset_low) ++#define KDB_SYS_DESC_CALLG_COUNT(d) 0 ++ ++#else /* !CONFIG_X86_64 */ ++ ++#define KDB_X86_64 0 ++#define MOVLQ "movl" ++ ++/* i386 has no detailed mapping for the 8 byte segment descriptor, copy the ++ * x86_64 one and merge the l and avl bits. ++ */ ++struct kdb_desc { ++ u16 limit0; ++ u16 base0; ++ unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1; ++ unsigned limit : 4, avl : 2, d : 1, g : 1, base2 : 8; ++} __attribute__((packed)); ++typedef struct kdb_desc kdb_desc_t; ++ ++/* i386 has no detailed mapping for the 8 byte gate descriptor, base it on the ++ * x86_64 one. ++ */ ++struct kdb_gate_desc { ++ u16 offset_low; ++ u16 segment; ++ unsigned res : 8, type : 4, s : 1, dpl : 2, p : 1; ++ u16 offset_middle; ++} __attribute__((packed)); ++typedef struct kdb_gate_desc kdb_gate_desc_t; ++ ++#define KDB_SYS_DESC_OFFSET(d) ((unsigned long)(d->offset_middle << 16 | d->offset_low)) ++#define KDB_SYS_DESC_CALLG_COUNT(d) ((unsigned int)(d->res & 0x0F)) ++ ++#endif /* CONFIG_X86_64 */ ++ ++#define KDB_SEL_MAX 0x2000 ++#define KDB_IDT_MAX 0x100 ++#define KDB_SYS_DESC_TYPE_TSS16 0x01 ++#define KDB_SYS_DESC_TYPE_LDT 0x02 ++#define KDB_SYS_DESC_TYPE_TSSB16 0x03 ++#define KDB_SYS_DESC_TYPE_CALLG16 0x04 ++#define KDB_SYS_DESC_TYPE_TASKG 0x05 ++#define KDB_SYS_DESC_TYPE_INTG16 0x06 ++#define KDB_SYS_DESC_TYPE_TRAP16 0x07 ++ ++#define KDB_SYS_DESC_TYPE_TSS 0x09 ++#define KDB_SYS_DESC_TYPE_TSSB 0x0b ++#define KDB_SYS_DESC_TYPE_CALLG 0x0c ++#define KDB_SYS_DESC_TYPE_INTG 0x0e ++#define KDB_SYS_DESC_TYPE_TRAPG 0x0f ++ ++#define KDB_SEG_DESC_TYPE_CODE 0x08 ++#define KDB_SEG_DESC_TYPE_CODE_R 0x02 ++#define KDB_SEG_DESC_TYPE_DATA_W 0x02 ++#define KDB_SEG_DESC_TYPE_CODE_C 0x02 /* conforming */ ++#define KDB_SEG_DESC_TYPE_DATA_D 0x02 /* expand-down */ ++#define KDB_SEG_DESC_TYPE_A 0x01 /* accessed */ ++ ++#define _LIMIT(d) ((unsigned long)((d)->limit << 16 | (d)->limit0)) ++#define KDB_SEG_DESC_LIMIT(d) ((d)->g ? ((_LIMIT(d)+1) << 12) -1 : _LIMIT(d)) ++ ++static unsigned long kdb_seg_desc_base(kdb_desc_t *d) ++{ ++ unsigned long base = d->base2 << 24 | d->base1 << 16 | d->base0; ++#ifdef CONFIG_X86_64 ++ switch (d->type) { ++ case KDB_SYS_DESC_TYPE_TSS: ++ case KDB_SYS_DESC_TYPE_TSSB: ++ case KDB_SYS_DESC_TYPE_LDT: ++ base += (unsigned long)(((struct ldttss_desc64 *)d)->base3) << 32; ++ break; ++ } ++#endif ++ return base; ++} ++ ++/* helper functions to display system registers in verbose mode */ ++static void display_gdtr(void) ++{ ++ struct desc_ptr gdtr; ++ ++ __asm__ __volatile__ ("sgdt %0\n\t" : "=m"(gdtr)); ++ kdb_printf("gdtr.address = " kdb_machreg_fmt0 ", gdtr.size = 0x%x\n", ++ gdtr.address, gdtr.size); ++ ++ return; ++} ++ ++static void display_ldtr(void) ++{ ++ struct desc_ptr gdtr; ++ unsigned long ldtr; ++ ++ __asm__ __volatile__ ("sgdt %0\n\t" : "=m"(gdtr)); ++ __asm__ __volatile__ ("sldt %0\n\t" : "=m"(ldtr)); ++ ldtr &= 0xfff8; /* extract the index */ ++ ++ kdb_printf("ldtr = " kdb_machreg_fmt0 " ", ldtr); ++ ++ if (ldtr < gdtr.size) { ++ kdb_desc_t *ldt_desc = ++ (kdb_desc_t *)(gdtr.address + ldtr); ++ kdb_printf("base=" kdb_machreg_fmt0 ++ ", limit=" kdb_machreg_fmt "\n", ++ kdb_seg_desc_base(ldt_desc), ++ KDB_SEG_DESC_LIMIT(ldt_desc)); ++ } else { ++ kdb_printf("invalid\n"); ++ } ++ ++ return; ++} ++ ++static void display_idtr(void) ++{ ++ struct desc_ptr idtr; ++ __asm__ __volatile__ ("sidt %0\n\t" : "=m"(idtr)); ++ kdb_printf("idtr.address = " kdb_machreg_fmt0 ", idtr.size = 0x%x\n", ++ idtr.address, idtr.size); ++ return; ++} ++ ++static const char *cr0_flags[] = { ++ "pe", "mp", "em", "ts", "et", "ne", NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ "wp", NULL, "am", NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, "nw", "cd", "pg"}; ++ ++static void display_cr0(void) ++{ ++ kdb_machreg_t cr0; ++ int i; ++ __asm__ (MOVLQ " %%cr0,%0\n\t":"=r"(cr0)); ++ kdb_printf("cr0 = " kdb_machreg_fmt0, cr0); ++ for (i = 0; i < ARRAY_SIZE(cr0_flags); i++) { ++ if (test_bit(i, &cr0) && cr0_flags[i]) ++ kdb_printf(" %s", cr0_flags[i]); ++ } ++ kdb_printf("\n"); ++ return; ++} ++ ++static void display_cr3(void) ++{ ++ kdb_machreg_t cr3; ++ __asm__ (MOVLQ " %%cr3,%0\n\t":"=r"(cr3)); ++ kdb_printf("cr3 = " kdb_machreg_fmt0 " ", cr3); ++ if (cr3 & 0x08) ++ kdb_printf("pwt "); ++ if (cr3 & 0x10) ++ kdb_printf("pcd "); ++ kdb_printf("%s=" kdb_machreg_fmt0 "\n", ++ KDB_X86_64 ? "pml4" : "pgdir", cr3 & PAGE_MASK); ++ return; ++} ++ ++static const char *cr4_flags[] = { ++ "vme", "pvi", "tsd", "de", ++ "pse", "pae", "mce", "pge", ++ "pce", "osfxsr" "osxmmexcpt"}; ++ ++static void display_cr4(void) ++{ ++ kdb_machreg_t cr4; ++ int i; ++ __asm__ (MOVLQ " %%cr4,%0\n\t":"=r"(cr4)); ++ kdb_printf("cr4 = " kdb_machreg_fmt0, cr4); ++ for (i = 0; i < ARRAY_SIZE(cr4_flags); i++) { ++ if (test_bit(i, &cr4)) ++ kdb_printf(" %s", cr4_flags[i]); ++ } ++ kdb_printf("\n"); ++ return; ++} ++ ++static void display_cr8(void) ++{ ++#ifdef CONFIG_X86_64 ++ kdb_machreg_t cr8; ++ __asm__ (MOVLQ " %%cr8,%0\n\t":"=r"(cr8)); ++ kdb_printf("cr8 = " kdb_machreg_fmt0 "\n", cr8); ++ return; ++#endif /* CONFIG_X86_64 */ ++} ++ ++static char *dr_type_name[] = { "exec", "write", "io", "rw" }; ++ ++static void display_dr_status(int nr, int enabled, int local, int len, int type) ++{ ++ if (!enabled) { ++ kdb_printf("\tdebug register %d: not enabled\n", nr); ++ return; ++ } ++ ++ kdb_printf(" debug register %d: %s, len = %d, type = %s\n", ++ nr, ++ local? " local":"global", ++ len, ++ dr_type_name[type]); ++} ++ ++static void display_dr(void) ++{ ++ kdb_machreg_t dr0, dr1, dr2, dr3, dr6, dr7; ++ int dbnr, set; ++ ++ __asm__ (MOVLQ " %%db0,%0\n\t":"=r"(dr0)); ++ __asm__ (MOVLQ " %%db1,%0\n\t":"=r"(dr1)); ++ __asm__ (MOVLQ " %%db2,%0\n\t":"=r"(dr2)); ++ __asm__ (MOVLQ " %%db3,%0\n\t":"=r"(dr3)); ++ __asm__ (MOVLQ " %%db6,%0\n\t":"=r"(dr6)); ++ __asm__ (MOVLQ " %%db7,%0\n\t":"=r"(dr7)); ++ ++ kdb_printf("dr0 = " kdb_machreg_fmt0 " dr1 = " kdb_machreg_fmt0 ++ " dr2 = " kdb_machreg_fmt0 " dr3 = " kdb_machreg_fmt0 "\n", ++ dr0, dr1, dr2, dr3); ++ kdb_printf("dr6 = " kdb_machreg_fmt0 " ", dr6); ++ dbnr = dr6 & DR6_DR_MASK; ++ if (dbnr) { ++ int nr; ++ switch(dbnr) { ++ case 1: ++ nr = 0; break; ++ case 2: ++ nr = 1; break; ++ case 4: ++ nr = 2; break; ++ default: ++ nr = 3; break; ++ } ++ kdb_printf("debug register hit = %d", nr); ++ } else if (dr6 & DR_STEP) { ++ kdb_printf("single step"); ++ } else if (dr6 & DR_SWITCH) { ++ kdb_printf("task switch"); ++ } ++ kdb_printf("\n"); ++ ++ kdb_printf("dr7 = " kdb_machreg_fmt0 "\n", dr7); ++ set = DR7_L0(dr7) || DR7_G0(dr7); ++ display_dr_status(0, set, DR7_L0(dr7), DR7_LEN0(dr7), DR7_RW0(dr7)); ++ set = DR7_L1(dr7) || DR7_G1(dr7); ++ display_dr_status(1, set, DR7_L1(dr7), DR7_LEN1(dr7), DR7_RW1(dr7)); ++ set = DR7_L2(dr7) || DR7_G2(dr7); ++ display_dr_status(2, set, DR7_L2(dr7), DR7_LEN2(dr7), DR7_RW2(dr7)); ++ set = DR7_L3(dr7) || DR7_G3(dr7); ++ display_dr_status(3, set, DR7_L3(dr7), DR7_LEN3(dr7), DR7_RW3(dr7)); ++} ++ ++static char *set_eflags[] = { ++ "carry", NULL, "parity", NULL, "adjust", NULL, "zero", "sign", ++ "trace", "intr-on", "dir", "overflow", NULL, NULL, "nestedtask", NULL, ++ "resume", "vm", "align", "vif", "vip", "id"}; ++ ++static void display_eflags(unsigned long ef) ++{ ++ int i, iopl; ++ kdb_printf("eflags = " kdb_machreg_fmt0 " ", ef); ++ for (i = 0; i < ARRAY_SIZE(set_eflags); i++) { ++ if (test_bit(i, &ef) && set_eflags[i]) ++ kdb_printf("%s ", set_eflags[i]); ++ } ++ ++ iopl = (ef & 0x00003000) >> 12; ++ kdb_printf("iopl=%d\n", iopl); ++ return; ++} ++ ++static void display_tss(struct tss_struct *t) ++{ ++#ifdef CONFIG_X86_64 ++ int i; ++ kdb_printf(" sp0 = 0x%016Lx, sp1 = 0x%016Lx\n", ++ t->x86_tss.sp0, t->x86_tss.sp1); ++ kdb_printf(" sp2 = 0x%016Lx\n", t->x86_tss.sp2); ++ for (i = 0; i < ARRAY_SIZE(t->x86_tss.ist); ++i) ++ kdb_printf(" ist[%d] = 0x%016Lx\n", ++ i, t->x86_tss.ist[i]); ++ kdb_printf(" iomap = 0x%04x\n", t->x86_tss.io_bitmap_base); ++#else /* !CONFIG_X86_64 */ ++ kdb_printf(" cs = %04x, ip = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.es, t->x86_tss.ip); ++ kdb_printf(" ss = %04x, sp = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.ss, t->x86_tss.sp); ++ kdb_printf(" ss0 = %04x, sp0 = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.ss0, t->x86_tss.sp0); ++ kdb_printf(" ss1 = %04x, sp1 = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.ss1, t->x86_tss.sp1); ++ kdb_printf(" ss2 = %04x, sp2 = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.ss2, t->x86_tss.sp2); ++ kdb_printf(" ldt = %04x, cr3 = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.ldt, t->x86_tss.__cr3); ++ kdb_printf(" ds = %04x, es = %04x fs = %04x gs = %04x\n", ++ t->x86_tss.ds, t->x86_tss.es, t->x86_tss.fs, t->x86_tss.gs); ++ kdb_printf(" ax = " kdb_machreg_fmt0 ", bx = " kdb_machreg_fmt0 ++ " cx = " kdb_machreg_fmt0 " dx = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.ax, t->x86_tss.bx, t->x86_tss.cx, t->x86_tss.dx); ++ kdb_printf(" si = " kdb_machreg_fmt0 ", di = " kdb_machreg_fmt0 ++ " bp = " kdb_machreg_fmt0 "\n", ++ t->x86_tss.si, t->x86_tss.di, t->x86_tss.bp); ++ kdb_printf(" trace = %d, iomap = 0x%04x\n", t->x86_tss.trace, t->x86_tss.io_bitmap_base); ++#endif /* CONFIG_X86_64 */ ++} ++ ++static char *gate_desc_types[] = { ++#ifdef CONFIG_X86_64 ++ "reserved-0", "reserved-1", "ldt", "reserved-3", ++ "reserved-4", "reserved-5", "reserved-6", "reserved-7", ++ "reserved-8", "tss-avlb", "reserved-10", "tss-busy", ++ "callgate", "reserved-13", "intgate", "trapgate", ++#else /* CONFIG_X86_64 */ ++ "reserved-0", "tss16-avlb", "ldt", "tss16-busy", ++ "callgate16", "taskgate", "intgate16", "trapgate16", ++ "reserved-8", "tss-avlb", "reserved-10", "tss-busy", ++ "callgate", "reserved-13", "intgate", "trapgate", ++#endif /* CONFIG_X86_64 */ ++}; ++ ++static void ++display_gate_desc(kdb_gate_desc_t *d) ++{ ++ kdb_printf("%-11s ", gate_desc_types[d->type]); ++ ++ switch(d->type) { ++ case KDB_SYS_DESC_TYPE_LDT: ++ kdb_printf("base="); ++ kdb_symbol_print(kdb_seg_desc_base((kdb_desc_t *)d), NULL, ++ KDB_SP_DEFAULT); ++ kdb_printf(" limit=" kdb_machreg_fmt " dpl=%d\n", ++ KDB_SEG_DESC_LIMIT((kdb_desc_t *)d), d->dpl); ++ break; ++ case KDB_SYS_DESC_TYPE_TSS: ++ case KDB_SYS_DESC_TYPE_TSS16: ++ case KDB_SYS_DESC_TYPE_TSSB: ++ case KDB_SYS_DESC_TYPE_TSSB16: ++ { ++ struct tss_struct *tss = ++ (struct tss_struct *) ++ kdb_seg_desc_base((kdb_desc_t *)d); ++ kdb_printf("base="); ++ kdb_symbol_print((unsigned long)tss, NULL, KDB_SP_DEFAULT); ++ kdb_printf(" limit=" kdb_machreg_fmt " dpl=%d\n", ++ KDB_SEG_DESC_LIMIT((kdb_desc_t *)d), d->dpl); ++ display_tss(tss); ++ break; ++ } ++ case KDB_SYS_DESC_TYPE_CALLG16: ++ kdb_printf("segment=0x%4.4x off=", d->segment); ++ kdb_symbol_print(KDB_SYS_DESC_OFFSET(d), NULL, KDB_SP_DEFAULT); ++ kdb_printf(" dpl=%d wc=%d\n", ++ d->dpl, KDB_SYS_DESC_CALLG_COUNT(d)); ++ break; ++ case KDB_SYS_DESC_TYPE_CALLG: ++ kdb_printf("segment=0x%4.4x off=", d->segment); ++ kdb_symbol_print(KDB_SYS_DESC_OFFSET(d), NULL, KDB_SP_DEFAULT); ++ kdb_printf(" dpl=%d\n", d->dpl); ++ break; ++ default: ++ kdb_printf("segment=0x%4.4x off=", d->segment); ++ if (KDB_SYS_DESC_OFFSET(d)) ++ kdb_symbol_print(KDB_SYS_DESC_OFFSET(d), NULL, ++ KDB_SP_DEFAULT); ++ else ++ kdb_printf(kdb_machreg_fmt0, KDB_SYS_DESC_OFFSET(d)); ++ kdb_printf(" dpl=%d", d->dpl); ++#ifdef CONFIG_X86_64 ++ if (d->ist) ++ kdb_printf(" ist=%d", d->ist); ++#endif /* CONFIG_X86_64 */ ++ kdb_printf("\n"); ++ break; ++ } ++} ++ ++static void ++display_seg_desc(kdb_desc_t *d) ++{ ++ unsigned char type = d->type; ++ ++ if (type & KDB_SEG_DESC_TYPE_CODE) { ++ kdb_printf("%-11s base=" kdb_machreg_fmt0 " limit=" ++ kdb_machreg_fmt " dpl=%d %c%c%c %s %s %s \n", ++ "code", ++ kdb_seg_desc_base(d), KDB_SEG_DESC_LIMIT(d), ++ d->dpl, ++ (type & KDB_SEG_DESC_TYPE_CODE_R)?'r':'-', ++ '-', 'x', ++#ifdef CONFIG_X86_64 ++ d->l ? "64b" : d->d ? "32b" : "16b", ++#else /* !CONFIG_X86_64 */ ++ d->d ? "32b" : "16b", ++#endif /* CONFIG_X86_64 */ ++ (type & KDB_SEG_DESC_TYPE_A)?"ac":"", ++ (type & KDB_SEG_DESC_TYPE_CODE_C)?"conf":""); ++ } else { ++ kdb_printf("%-11s base=" kdb_machreg_fmt0 " limit=" ++ kdb_machreg_fmt " dpl=%d %c%c%c %s %s %s \n", ++ "data", ++ kdb_seg_desc_base(d), KDB_SEG_DESC_LIMIT(d), ++ d->dpl, ++ 'r', ++ (type & KDB_SEG_DESC_TYPE_DATA_W)?'w':'-', ++ '-', ++ d->d ? "32b" : "16b", ++ (type & KDB_SEG_DESC_TYPE_A)?"ac":"", ++ (type & KDB_SEG_DESC_TYPE_DATA_D)?"down":""); ++ } ++} ++ ++static int ++kdb_parse_two_numbers(int argc, const char **argv, int *sel, int *count, ++ int *last_sel, int *last_count) ++{ ++ int diag; ++ ++ if (argc > 2) ++ return KDB_ARGCOUNT; ++ ++ kdbgetintenv("MDCOUNT", count); ++ ++ if (argc == 0) { ++ *sel = *last_sel; ++ if (*last_count) ++ *count = *last_count; ++ } else { ++ unsigned long val; ++ ++ if (argc >= 1) { ++ diag = kdbgetularg(argv[1], &val); ++ if (diag) ++ return diag; ++ *sel = val; ++ } ++ if (argc >= 2) { ++ diag = kdbgetularg(argv[2], &val); ++ if (diag) ++ return diag; ++ *count = (int) val; ++ *last_count = (int) val; ++ } else if (*last_count) { ++ *count = *last_count; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * kdb_gdt ++ * ++ * This function implements the 'gdt' command. ++ * ++ * gdt [ []] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++static int ++kdb_gdt(int argc, const char **argv) ++{ ++ int sel = 0; ++ struct desc_ptr gdtr; ++ int diag, count = 8; ++ kdb_desc_t *gdt; ++ unsigned int max_sel; ++ static int last_sel = 0, last_count = 0; ++ ++ diag = kdb_parse_two_numbers(argc, argv, &sel, &count, ++ &last_sel, &last_count); ++ if (diag) ++ return diag; ++ ++ __asm__ __volatile__ ("sgdt %0\n\t" : "=m"(gdtr)); ++ gdt = (kdb_desc_t *) gdtr.address; ++ ++ max_sel = (gdtr.size + 1) / sizeof(kdb_desc_t); ++ if (sel >= max_sel) { ++ kdb_printf("Maximum selector (%d) reached\n", max_sel); ++ return 0; ++ } ++ ++ if (sel + count > max_sel) ++ count = max_sel - sel; ++ ++ while (count--) { ++ kdb_desc_t *d = &gdt[sel]; ++ kdb_printf("0x%4.4x ", sel++); ++ ++ if (!d->p) { ++ kdb_printf("not present\n"); ++ continue; ++ } ++ if (d->s) { ++ display_seg_desc(d); ++ } else { ++ display_gate_desc((kdb_gate_desc_t *)d); ++ if (KDB_X86_64 && count) { ++ ++sel; /* this descriptor occupies two slots */ ++ --count; ++ } ++ } ++ } ++ ++ last_sel = sel; ++ return 0; ++} ++ ++/* ++ * kdb_ldt ++ * ++ * This function implements the 'ldt' command. ++ * ++ * ldt [ []] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++static int ++kdb_ldt(int argc, const char **argv) ++{ ++ int sel = 0; ++ struct desc_ptr gdtr; ++ unsigned long ldtr = 0; ++ int diag, count = 8; ++ kdb_desc_t *ldt, *ldt_desc; ++ unsigned int max_sel; ++ static int last_sel = 0, last_count = 0; ++ ++ diag = kdb_parse_two_numbers(argc, argv, &sel, &count, ++ &last_sel, &last_count); ++ if (diag) ++ return diag; ++ ++ if (strcmp(argv[0], "ldtp") == 0) { ++ kdb_printf("pid=%d, process=%s\n", ++ kdb_current_task->pid, kdb_current_task->comm); ++ if (!kdb_current_task->mm || ++ !kdb_current_task->mm->context.ldt) { ++ kdb_printf("no special LDT for this process\n"); ++ return 0; ++ } ++ ldt = kdb_current_task->mm->context.ldt; ++ max_sel = kdb_current_task->mm->context.size; ++ } else { ++ ++ /* sldt gives the GDT selector for the segment containing LDT */ ++ __asm__ __volatile__ ("sgdt %0\n\t" : "=m"(gdtr)); ++ __asm__ __volatile__ ("sldt %0\n\t" : "=m"(ldtr)); ++ ldtr &= 0xfff8; /* extract the index */ ++ ++ if (ldtr > gdtr.size+1) { ++ kdb_printf("invalid ldtr\n"); ++ return 0; ++ } ++ ++ ldt_desc = (kdb_desc_t *)(gdtr.address + ldtr); ++ ldt = (kdb_desc_t *)kdb_seg_desc_base(ldt_desc); ++ max_sel = (KDB_SEG_DESC_LIMIT(ldt_desc)+1) / sizeof(kdb_desc_t); ++ } ++ ++ if (sel >= max_sel) { ++ kdb_printf("Maximum selector (%d) reached\n", max_sel); ++ return 0; ++ } ++ ++ if (sel + count > max_sel) ++ count = max_sel - sel; ++ ++ while (count--) { ++ kdb_desc_t *d = &ldt[sel]; ++ kdb_printf("0x%4.4x ", sel++); ++ ++ if (!d->p) { ++ kdb_printf("not present\n"); ++ continue; ++ } ++ if (d->s) { ++ display_seg_desc(d); ++ } else { ++ display_gate_desc((kdb_gate_desc_t *)d); ++ if (KDB_X86_64 && count) { ++ ++sel; /* this descriptor occupies two slots */ ++ --count; ++ } ++ } ++ } ++ ++ last_sel = sel; ++ return 0; ++} ++ ++/* ++ * kdb_idt ++ * ++ * This function implements the 'idt' command. ++ * ++ * idt [ []] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++static int ++kdb_idt(int argc, const char **argv) ++{ ++ int vec = 0; ++ struct desc_ptr idtr; ++ int diag, count = 8; ++ kdb_gate_desc_t *idt; ++ unsigned int max_entries; ++ static int last_vec = 0, last_count = 0; ++ ++ diag = kdb_parse_two_numbers(argc, argv, &vec, &count, ++ &last_vec, &last_count); ++ if (diag) ++ return diag; ++ ++ __asm__ __volatile__ ("sidt %0\n\t" : "=m"(idtr)); ++ idt = (kdb_gate_desc_t *)idtr.address; ++ ++ max_entries = (idtr.size+1) / sizeof(kdb_gate_desc_t); ++ if (vec >= max_entries) { ++ kdb_printf("Maximum vector (%d) reached\n", max_entries); ++ return 0; ++ } ++ ++ if (vec + count > max_entries) ++ count = max_entries - vec; ++ ++ while (count--) { ++ kdb_gate_desc_t *d = &idt[vec]; ++ kdb_printf("0x%4.4x ", vec++); ++ if (!d->p) { ++ kdb_printf("not present\n"); ++ continue; ++ } ++#ifndef CONFIG_X86_64 ++ if (d->s) { ++ kdb_printf("invalid\n"); ++ continue; ++ } ++#endif /* CONFIG_X86_64 */ ++ display_gate_desc(d); ++ } ++ ++ last_vec = vec; ++ ++ return 0; ++} ++ ++#if 0 ++static int ++get_pagetables(unsigned long addr, pgd_t **pgdir, pmd_t **pgmiddle, pte_t **pte) ++{ ++ pgd_t *d; ++ pmd_t *m; ++ pte_t *t; ++ ++ if (addr > PAGE_OFFSET) { ++ d = pgd_offset_k(addr); ++ } else { ++ kdb_printf("pid=%d, process=%s\n", kdb_current_task->pid, kdb_current_task->comm); ++ d = pgd_offset(kdb_current_task->mm, addr); ++ } ++ ++ if (pgd_none(*d) || pgd_bad(*d)) { ++ *pgdir = NULL; ++ *pgmiddle = NULL; ++ *pte = NULL; ++ return 0; ++ } else { ++ *pgdir = d; ++ } ++ ++ /* if _PAGE_PSE is set, pgdir points directly to the page. */ ++ if (pgd_val(*d) & _PAGE_PSE) { ++ *pgmiddle = NULL; ++ *pte = NULL; ++ return 0; ++ } ++ ++ m = pmd_offset(d, addr); ++ if (pmd_none(*m) || pmd_bad(*m)) { ++ *pgmiddle = NULL; ++ *pte = NULL; ++ return 0; ++ } else { ++ *pgmiddle = m; ++ } ++ ++ t = pte_offset(m, addr); ++ if (pte_none(*t)) { ++ *pte = NULL; ++ return 0; ++ } else { ++ *pte = t; ++ } ++ kdb_printf("\naddr=%08lx, pgd=%08lx, pmd=%08lx, pte=%08lx\n", ++ addr, ++ (unsigned long) pgd_val(*d), ++ (unsigned long) pmd_val(*m), ++ (unsigned long) pte_val(*t)); ++ return 0; ++} ++#endif ++ ++#define FORMAT_PGDIR(entry) \ ++ kdb_printf("frame=%05lx %c %s %c %c %c %s %c %s %s \n",\ ++ (entry >> PAGE_SHIFT), \ ++ (entry & _PAGE_PRESENT)?'p':'n', \ ++ (entry & _PAGE_RW)?"rw":"ro", \ ++ (entry & _PAGE_USER)?'u':'s', \ ++ (entry & _PAGE_ACCESSED)?'a':' ', \ ++ ' ', \ ++ (entry & _PAGE_PSE)?"4M":"4K", \ ++ (entry & _PAGE_GLOBAL)?'g':' ', \ ++ (entry & _PAGE_PWT)?"wt":"wb", \ ++ (entry & _PAGE_PCD)?"cd":" "); ++ ++#define FORMAT_PTE(p, entry) \ ++ kdb_printf("frame=%05lx %c%c%c %c %c %c %s %c %s %s\n", \ ++ (entry >> PAGE_SHIFT), \ ++ (pte_read(p))? 'r':'-', \ ++ (pte_write(p))? 'w':'-', \ ++ (pte_exec(p))? 'x':'-', \ ++ (pte_dirty(p))? 'd':' ', \ ++ (pte_young(p))? 'a':' ', \ ++ (entry & _PAGE_USER)? 'u':'s', \ ++ " ", \ ++ (entry & _PAGE_GLOBAL)? 'g':' ', \ ++ (entry & _PAGE_PWT)? "wt":"wb", \ ++ (entry & _PAGE_PCD)? "cd":" "); ++#if 0 ++static int ++display_pgdir(unsigned long addr, pgd_t *pgdir, int count) ++{ ++ unsigned long entry; ++ int i; ++ int index = pgdir - ((pgd_t *)(((unsigned long)pgdir) & PAGE_MASK)); ++ ++ count = min(count, PTRS_PER_PGD - index); ++ addr &= ~(PGDIR_SIZE-1); ++ ++ for (i = 0; i < count; i++, pgdir++) { ++ entry = pgd_val(*pgdir); ++ kdb_printf("pgd: addr=%08lx ", addr); ++ if (pgd_none(*pgdir)) { ++ kdb_printf("pgdir not present\n"); ++ } else { ++ FORMAT_PGDIR(entry); ++ } ++ addr += PGDIR_SIZE; ++ } ++ return i; ++} ++#endif ++ ++#if 0 /* for now, let's not print pgmiddle. */ ++static int ++display_pgmiddle(unsigned long addr, pmd_t *pgmiddle, int count) ++{ ++ unsigned long entry; ++ int i; ++ int index = pgmiddle - ((pmd_t *)(((unsigned long)pgmiddle) & PAGE_MASK)); ++ ++ count = min(count, PTRS_PER_PMD - index); ++ addr &= ~(PMD_SIZE-1); ++ ++ for (i = 0; i < count; i++, pgmiddle++) { ++ entry = pmd_val(*pgmiddle); ++ kdb_printf("pmd: addr=%08lx ", addr); ++ if (pmd_none(*pgmiddle)) { ++ kdb_printf("pgmiddle not present\n"); ++ } else { ++ FORMAT_PGDIR(entry); ++ } ++ addr += PMD_SIZE; ++ } ++ return i; ++} ++#endif ++ ++#if 0 ++static int ++display_pte(unsigned long addr, pte_t *pte, int count) ++{ ++ unsigned long entry; ++ int i; ++ int index = pte - ((pte_t *)(((unsigned long)pte) & PAGE_MASK)); ++ ++ count = min(count, PTRS_PER_PTE - index); ++ addr &= PAGE_MASK; ++ ++ for (i = 0; i < count; i++, pte++) { ++ entry = pte_val(*pte); ++ kdb_printf("pte: addr=%08lx ", addr); ++ if (pte_none(*pte)) { ++ kdb_printf("pte not present\n"); ++ } else if (!pte_present(*pte)) { ++ kdb_printf("page swapped out. swp_offset=%08lx ", SWP_OFFSET(pte_to_swp_entry(*pte))); ++ kdb_printf("swp_type=%8lx", SWP_TYPE(pte_to_swp_entry(*pte))); ++ } else { ++ FORMAT_PTE(*pte, entry); ++ } ++ addr += PAGE_SIZE; ++ } ++ return i; ++} ++ ++ ++/* ++ * kdb_pte ++ * ++ * This function implements the 'pte' command. ++ * ++ * pte [] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++static int ++kdb_pte(int argc, const char **argv) ++{ ++ static unsigned long last_addr = 0, last_count = 0; ++ int count = 8; ++ unsigned long addr; ++ long offset = 0; ++ pgd_t *pgdir; ++ pmd_t *pgmiddle; ++ pte_t *pte; ++ ++#ifdef CONFIG_X86_PAE ++ kdb_printf("This kernel is compiled with PAE support."); ++ return KDB_NOTIMP; ++#endif ++ kdbgetintenv("MDCOUNT", &count); ++ ++ if (argc == 0) { ++ if (last_addr == 0) ++ return KDB_ARGCOUNT; ++ addr = last_addr; ++ if (last_count) ++ count = last_count; ++ } else { ++ kdb_machreg_t val; ++ int diag, nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ if (argc > nextarg+1) ++ return KDB_ARGCOUNT; ++ ++ if (argc >= nextarg) { ++ diag = kdbgetularg(argv[nextarg], &val); ++ if (!diag) { ++ count = (int) val; ++ last_count = count; ++ } else if (last_count) { ++ count = last_count; ++ } ++ } ++ } ++ ++ /* ++ * round off the addr to a page boundary. ++ */ ++ addr &= PAGE_MASK; ++ ++ get_pagetables(addr, &pgdir, &pgmiddle, &pte); ++ ++ if (pgdir) ++ display_pgdir(addr, pgdir, 1); ++#if 0 /* for now, let's not print pgmiddle. */ ++ if (pgmiddle) ++ display_pgmiddle(addr, pgmiddle, 1); ++#endif ++ if (pte) { ++ int displayed; ++ displayed = display_pte(addr, pte, count); ++ addr += (displayed << PAGE_SHIFT); ++ } ++ last_addr = addr; ++ return 0; ++} ++#else ++/* ++ * Todo - In 2.5 the pte_offset macro in asm/pgtable.h seems to be ++ * renamed to pte_offset_kernel. ++ */ ++static int ++kdb_pte(int argc, const char **argv) ++{ ++ kdb_printf("not supported."); ++ return KDB_NOTIMP; ++} ++#endif ++ ++/* ++ * kdb_rdv ++ * ++ * This function implements the 'rdv' command. ++ * It displays all registers of the current processor ++ * included control registers in verbose mode. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * This should have been an option to rd command say "rd v", ++ * but it is here as it is a non-essential x86-only command, ++ * that need not clutter arch/i386/kdb/kdbasupport.c. ++ */ ++static int ++kdb_rdv(int argc, const char **argv) ++{ ++ struct pt_regs *regs = get_irq_regs(); ++ kdba_dumpregs(regs, NULL, NULL); ++ kdb_printf("\n"); ++ display_eflags(regs->flags); ++ kdb_printf("\n"); ++ display_gdtr(); ++ display_idtr(); ++ display_ldtr(); ++ kdb_printf("\n"); ++ display_cr0(); ++ display_cr3(); ++ display_cr4(); ++ display_cr8(); ++ kdb_printf("\n"); ++ display_dr(); ++ return 0; ++} ++ ++static int ++kdb_rdmsr(int argc, const char **argv) ++{ ++ unsigned long addr; ++ uint32_t l, h; ++ int diag; ++ struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ if ((diag = kdbgetularg(argv[1], &addr))) ++ return diag; ++ ++ if (!cpu_has(c, X86_FEATURE_MSR)) ++ return KDB_NOTIMP; ++ ++ kdb_printf("msr(0x%lx) = ", addr); ++ if ((diag = rdmsr_safe(addr, &l, &h))) { ++ kdb_printf("error %d\n", diag); ++ return KDB_BADINT; ++ } else { ++ kdb_printf("0x%08x_%08x\n", h, l); ++ } ++ ++ return 0; ++} ++ ++static int ++kdb_wrmsr(int argc, const char **argv) ++{ ++ unsigned long addr; ++ unsigned long l, h; ++ int diag; ++ struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); ++ ++ if (argc != 3) ++ return KDB_ARGCOUNT; ++ ++ if ((diag = kdbgetularg(argv[1], &addr)) ++ || (diag = kdbgetularg(argv[2], &h)) ++ || (diag = kdbgetularg(argv[3], &l))) ++ return diag; ++ ++ if (!cpu_has(c, X86_FEATURE_MSR)) ++ return KDB_NOTIMP; ++ ++ if ((diag = wrmsr_safe(addr, l, h))) { ++ kdb_printf("error %d\n", diag); ++ return KDB_BADINT; ++ } ++ ++ return 0; ++} ++ ++static int __init kdbm_x86_init(void) ++{ ++ kdb_register("rdv", kdb_rdv, NULL, "Display registers in verbose mode", 0); ++ kdb_register_repeat("gdt", kdb_gdt, " []", "Display GDT", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("idt", kdb_idt, " []", "Display IDT", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("ldt", kdb_ldt, " []", "Display LDT", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("ptex", kdb_pte, " []", "Display pagetables", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register_repeat("ldtp", kdb_ldt, " []", "Display Process LDT", 0, KDB_REPEAT_NO_ARGS); ++ kdb_register("rdmsr", kdb_rdmsr, "", "Display Model Specific Register", 0); ++ kdb_register("wrmsr", kdb_wrmsr, " ", "Modify Model Specific Register", 0); ++ return 0; ++} ++ ++static void __exit kdbm_x86_exit(void) ++{ ++ kdb_unregister("rdv"); ++ kdb_unregister("gdt"); ++ kdb_unregister("ldt"); ++ kdb_unregister("idt"); ++ kdb_unregister("ptex"); ++ kdb_unregister("ldtp"); ++ kdb_unregister("rdmsr"); ++ kdb_unregister("wrmsr"); ++} ++ ++module_init(kdbm_x86_init) ++module_exit(kdbm_x86_exit) +--- /dev/null ++++ b/kdb/modules/lcrash/README +@@ -0,0 +1,3 @@ ++ ++ These files are copied from lcrash. ++ The only changes are flagged with "cpw". +--- /dev/null ++++ b/kdb/modules/lcrash/asm/README +@@ -0,0 +1 @@ ++This kl_types.h is asm-ia64 version. +--- /dev/null ++++ b/kdb/modules/lcrash/asm/kl_dump_ia64.h +@@ -0,0 +1,199 @@ ++/* ++ * $Id: kl_dump_ia64.h 1151 2005-02-23 01:09:12Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++/* This header file holds the architecture specific crash dump header */ ++#ifndef __KL_DUMP_IA64_H ++#define __KL_DUMP_IA64_H ++ ++/* definitions */ ++#ifndef KL_NR_CPUS ++# define KL_NR_CPUS 128 /* max number CPUs */ ++#endif ++ ++#define KL_DUMP_MAGIC_NUMBER_IA64 0xdeaddeadULL /* magic number */ ++#define KL_DUMP_VERSION_NUMBER_IA64 0x4 /* version number */ ++ ++ ++/* ++ * mkswap.c calls getpagesize() to get the system page size, ++ * which is not necessarily the same as the hardware page size. ++ * ++ * For ia64 the kernel PAGE_SIZE can be configured from 4KB ... 16KB. ++ * ++ * The physical memory is layed out out in the hardware/minimal pages. ++ * This is the size we need to use for dumping physical pages. ++ * ++ * Note ths hardware/minimal page size being use in; ++ * arch/ia64/kernel/efi.c`efi_memmap_walk(): ++ * curr.end = curr.start + (md->num_pages << 12); ++ * ++ * Since the system page size could change between the kernel we boot ++ * on the the kernel that cause the core dume we may want to have something ++ * more constant like the maximum system page size (See include/asm-ia64/page.h). ++ */ ++#define DUMP_MIN_PAGE_SHIFT 12 ++#define DUMP_MIN_PAGE_SIZE (1UL << DUMP_MIN_PAGE_SHIFT) ++#define DUMP_MIN_PAGE_MASK (~(DUMP_MIN_PAGE_SIZE - 1)) ++#define DUMP_MIN_PAGE_ALIGN(addr) (((addr) + DUMP_MIN_PAGE_SIZE - 1) & DUMP_MIN_PAGE_MASK) ++ ++#define DUMP_MAX_PAGE_SHIFT 16 ++#define DUMP_MAX_PAGE_SIZE (1UL << DUMP_MAX_PAGE_SHIFT) ++#define DUMP_MAX_PAGE_MASK (~(DUMP_MAX_PAGE_SIZE - 1)) ++#define DUMP_MAX_PAGE_ALIGN(addr) (((addr) + DUMP_MAX_PAGE_SIZE - 1) & DUMP_MAX_PAGE_MASK) ++ ++#define DUMP_HEADER_OFFSET DUMP_MAX_PAGE_SIZE ++ ++#define DUMP_EF_PAGE_SHIFT DUMP_MIN_PAGE_SHIFT ++ ++#define DUMP_PAGE_SHIFT DUMP_MIN_PAGE_SHIFT ++#define DUMP_PAGE_SIZE DUMP_MIN_PAGE_SIZE ++#define DUMP_PAGE_MASK DUMP_MIN_PAGE_MASK ++#define DUMP_PAGE_ALIGN(addr) DUMP_MIN_PAGE_ALIGN(addr) ++ ++struct kl_ia64_fpreg { ++ union { ++ unsigned long bits[2]; ++ long double __dummy; /* force 16-byte alignment */ ++ } u; ++}; ++ ++struct kl_pt_regs_ia64 { ++ /* for 2.6 kernels only. This structure was totally different in 2.4 kernels */ ++ unsigned long b6; /* scratch */ ++ unsigned long b7; /* scratch */ ++ ++ unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ ++ unsigned long ar_ssd; /* reserved for future use (scratch) */ ++ ++ unsigned long r8; /* scratch (return value register 0) */ ++ unsigned long r9; /* scratch (return value register 1) */ ++ unsigned long r10; /* scratch (return value register 2) */ ++ unsigned long r11; /* scratch (return value register 3) */ ++ ++ unsigned long cr_ipsr; /* interrupted task's psr */ ++ unsigned long cr_iip; /* interrupted task's instruction pointer */ ++ unsigned long cr_ifs; /* interrupted task's function state */ ++ ++ unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ ++ unsigned long ar_pfs; /* prev function state */ ++ unsigned long ar_rsc; /* RSE configuration */ ++ /* The following two are valid only if cr_ipsr.cpl > 0: */ ++ unsigned long ar_rnat; /* RSE NaT */ ++ unsigned long ar_bspstore; /* RSE bspstore */ ++ ++ unsigned long pr; /* 64 predicate registers (1 bit each) */ ++ unsigned long b0; /* return pointer (bp) */ ++ unsigned long loadrs; /* size of dirty partition << 16 */ ++ ++ unsigned long r1; /* the gp pointer */ ++ unsigned long r12; /* interrupted task's memory stack pointer */ ++ unsigned long r13; /* thread pointer */ ++ ++ unsigned long ar_fpsr; /* floating point status (preserved) */ ++ unsigned long r15; /* scratch */ ++ ++ /* The remaining registers are NOT saved for system calls. */ ++ ++ unsigned long r14; /* scratch */ ++ unsigned long r2; /* scratch */ ++ unsigned long r3; /* scratch */ ++ ++ /* The following registers are saved by SAVE_REST: */ ++ unsigned long r16; /* scratch */ ++ unsigned long r17; /* scratch */ ++ unsigned long r18; /* scratch */ ++ unsigned long r19; /* scratch */ ++ unsigned long r20; /* scratch */ ++ unsigned long r21; /* scratch */ ++ unsigned long r22; /* scratch */ ++ unsigned long r23; /* scratch */ ++ unsigned long r24; /* scratch */ ++ unsigned long r25; /* scratch */ ++ unsigned long r26; /* scratch */ ++ unsigned long r27; /* scratch */ ++ unsigned long r28; /* scratch */ ++ unsigned long r29; /* scratch */ ++ unsigned long r30; /* scratch */ ++ unsigned long r31; /* scratch */ ++ ++ unsigned long ar_ccv; /* compare/exchange value (scratch) */ ++ ++ /* ++ * * Floating point registers that the kernel considers scratch: ++ * */ ++ struct kl_ia64_fpreg f6; /* scratch */ ++ struct kl_ia64_fpreg f7; /* scratch */ ++ struct kl_ia64_fpreg f8; /* scratch */ ++ struct kl_ia64_fpreg f9; /* scratch */ ++ struct kl_ia64_fpreg f10; /* scratch */ ++ struct kl_ia64_fpreg f11; /* scratch */ ++} __attribute__((packed)); ++ ++/* ++ * Structure: dump_header_asm_t ++ * Function: This is the header for architecture-specific stuff. It ++ * follows right after the dump header. ++ */ ++typedef struct kl_dump_header_ia64_s { ++ /* the dump magic number -- unique to verify dump is valid */ ++ uint64_t magic_number; ++ /* the version number of this dump */ ++ uint32_t version; ++ /* the size of this header (in case we can't read it) */ ++ uint32_t header_size; ++ /* pointer to pt_regs */ ++ uint64_t pt_regs; ++ /* the dump registers */ ++ struct kl_pt_regs_ia64 regs; ++ /* the rnat register saved after flushrs */ ++ uint64_t rnat; ++ /* the pfs register saved after flushrs */ ++ uint64_t pfs; ++ /* the bspstore register saved after flushrs */ ++ uint64_t bspstore; ++ ++ /* smp specific */ ++ uint32_t smp_num_cpus; ++ uint32_t dumping_cpu; ++ struct kl_pt_regs_ia64 smp_regs[KL_NR_CPUS]; ++ uint64_t smp_current_task[KL_NR_CPUS]; ++ uint64_t stack[KL_NR_CPUS]; ++} __attribute__((packed)) kl_dump_header_ia64_t; ++ ++/* The following struct is used just to calculate the size needed ++ * to store per CPU info. (Make sure it is sync with the above struct) ++ */ ++struct kl_dump_CPU_info_ia64 { ++ struct kl_pt_regs_ia64 smp_regs; ++ uint64_t smp_current_task; ++ uint64_t stack; ++} __attribute__((packed)); ++ ++/* function declarations ++ */ ++int kl_set_dumparch_ia64(void); ++uint32_t dha_num_cpus_ia64(void); ++kaddr_t dha_current_task_ia64(int cpuid); ++int dha_cpuid_ia64(kaddr_t); ++kaddr_t dha_stack_ia64(int); ++kaddr_t dha_stack_ptr_ia64(int); ++int kl_read_dump_header_ia64(void); ++ ++#endif /* __KL_DUMP_IA64_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/asm/kl_types.h +@@ -0,0 +1,48 @@ ++/* ++ * $Id: kl_types.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __ASMIA64_KL_TYPES_H ++#define __ASMIA64_KL_TYPES_H ++ ++/* cpw */ ++/* was #include */ ++#include "kl_dump_ia64.h" ++ ++#define HOST_ARCH_IA64 ++/* cpw: add this, as otherwise comes from makefile */ ++#define DUMP_ARCH_IA64 ++ ++/* Format string that allows a single fprintf() call to work for both ++ * 32-bit and 64-bit pointer values (architecture specific). ++ */ ++#ifdef CONFIG_X86_32 ++#define FMT64 "ll" ++#else ++#define FMT64 "l" ++#endif ++#define FMTPTR "l" ++ ++/* for usage in common code where host architecture ++ * specific type/macro is needed ++ */ ++typedef kl_dump_header_ia64_t kl_dump_header_asm_t; ++#define KL_DUMP_ASM_MAGIC_NUMBER KL_DUMP_MAGIC_NUMBER_IA64 ++ ++#endif /* __ASMIA64_KL_TYPES_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_alloc.h +@@ -0,0 +1,124 @@ ++/* ++ * $Id: kl_alloc.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_ALLOC_H ++#define __KL_ALLOC_H ++ ++/** ++ ** Header file for kl_alloc.c module ++ ** ++ **/ ++ ++#define K_TEMP 1 ++#define K_PERM 2 ++ ++/** function prototypes for register functions ++ **/ ++ ++/* Memory block allocator. Returns a pointer to an allocated block ++ * of size bytes. In case of error, a NULL pointer will be returned ++ * and errno will be set to indicate exactly what error occurred. ++ * Note that the flag value will determine if the block allocated is ++ * temporary (can be freed via a call to kl_free_temp_blks()) or ++ * permenant (must be freed with a call to kl_free_block()).. ++ */ ++typedef void * (*klib_block_alloc_func) ( ++ int /* size of block required */, ++ int /* flag value */, ++ void * /* return address */); ++ ++/* Memory block reallocator. Returns a pointer to a block of new_size ++ * bytes. In case of error, a NULL pointer will be returned and ++ * errno will be set to indicate exactly what error occurred. ++ * Note that the flag value will determine if the block allocated is ++ * temporary (can be free via a call to kl_free_temp_blks()) or ++ * permenant. ++ */ ++typedef void * (*klib_block_realloc_func) ( ++ void * /* pointer to block to realloc */, ++ int /* size of new block required */, ++ int /* flag value */, ++ void * /* return address */); ++ ++/* Memory block duplicator. Returns a pointer to a block that is ++ * a copy of the block passed in via pointer. In case of error, a ++ * NULL pointer will be returned and errno will be set to indicate ++ * exactly what error occurred. Note that the flag value will ++ * determine if the block allocated is temporary (will be freed ++ * via a call to kl_free_temp_blks()) or permenant. Note that this ++ * function is only supported when liballoc is used (there is no ++ * way to tell the size of a malloced block. ++ */ ++typedef void * (*klib_block_dup_func) ( ++ void * /* pointer to block to dup */, ++ int /* flag value */, ++ void * /* return address */); ++ ++/* Allocates a block large enough to hold a string (plus the terminating ++ * NULL character). ++ */ ++typedef void * (*klib_str_to_block_func) ( ++ char * /* pointer to character string */, ++ int /* flag value */, ++ void * /* return address */); ++ ++/* Frees blocks that were previously allocated. ++ */ ++typedef void (*klib_block_free_func) ( ++ void * /* pointer to block */); ++ ++/* alloc block wrapper function table structure ++ */ ++typedef struct alloc_functions_s { ++ int flag; /* Functions initialized? */ ++ klib_block_alloc_func block_alloc; /* Returns ptr to block */ ++ klib_block_realloc_func block_realloc; /* Returns ptr to new blk */ ++ klib_block_dup_func block_dup; /* Returns ptr to new blk */ ++ klib_str_to_block_func str_to_block; /* Returns ptr to new blk */ ++ klib_block_free_func block_free; /* Frees memory block */ ++} alloc_functions_t; ++ ++extern alloc_functions_t alloc_functions; ++ ++/* Macros for accessing functions in alloc_functions table ++ */ ++#define KL_BLOCK_ALLOC() (alloc_functions.block_alloc) ++#define KL_BLOCK_REALLOC() (alloc_functions.block_realloc) ++#define KL_BLOCK_DUP() (alloc_functions.block_dup) ++#define KL_STR_TO_BLOCK() (alloc_functions.str_to_block) ++#define KL_BLOCK_FREE() (alloc_functions.block_free) ++ ++void *_kl_alloc_block(int, int, void *); ++void *_kl_realloc_block(void *, int, int, void *); ++void *_kl_dup_block(void *, int, void *); ++void *_kl_str_to_block(char *, int, void *); ++#if 0 ++cpw: we create a new wrappers for these: ++void kl_free_block(void *); ++ ++#define kl_alloc_block(size, flags) _kl_alloc_block(size, flags, kl_get_ra()) ++#endif ++#define kl_realloc_block(b, new_size, flags) \ ++ _kl_realloc_block(b, new_size, flags, kl_get_ra()) ++#define kl_dup_block(b, flags) _kl_dup_block(b, flags, kl_get_ra()) ++#define kl_str_to_block(s, flags) _kl_str_to_block(s, flags, kl_get_ra()) ++ ++#endif /* __KL_ALLOC_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_bfd.h +@@ -0,0 +1,31 @@ ++/* ++ * $Id: kl_bfd.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_BFD_H ++#define __KL_BFD_H ++ ++/* cpw: " " form: */ ++#include "klib.h" ++ ++int kl_check_bfd_error(bfd_error_type); ++int kl_open_elf(char*, bfd**, bfd**); ++int kl_read_bfd_syminfo(maplist_t*); ++ ++#endif /* __KL_BFD_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_btnode.h +@@ -0,0 +1,95 @@ ++/* ++ * $Id: kl_btnode.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_BTNODE_H ++#define __KL_BTNODE_H ++ ++/* ++ * Node header struct for use in binary search tree routines ++ */ ++typedef struct btnode_s { ++ struct btnode_s *bt_left; ++ struct btnode_s *bt_right; ++ struct btnode_s *bt_parent; ++ char *bt_key; ++ int bt_height; ++} btnode_t; ++ ++#define DUPLICATES_OK 1 ++ ++/** ++ ** btnode operation function prototypes ++ **/ ++ ++/* Return the hight of a given btnode_s struct in a tree. In the ++ * event of an error (a NULL btnode_s pointer was passed in), a ++ * value of -1 will be returned. ++ */ ++int kl_btnode_height( ++ btnode_t* /* pointer to btnode_s struct */); ++ ++/* Insert a btnode_s struct into a tree. After the insertion, the ++ * tree will be left in a reasonibly ballanced state. Note that, if ++ * the DUPLICATES_OK flag is set, duplicate keys will be inserted ++ * into the tree (otherwise return an error). In the event of an ++ * error, a value of -1 will be returned. ++ */ ++int kl_insert_btnode( ++ btnode_t** /* pointer to root of tree */, ++ btnode_t* /* pointer to btnode_s struct to insert */, ++ int /* flags (DUPLICATES_OK) */); ++ ++/* Finds a btnode in a tree and removes it, making sure to keep ++ * the tree in a reasonably balanced state. As part of the ++ * delete_btnode() operation, a call will be made to the free ++ * function (passed in as a parameter) to free any application ++ * specific data. ++ */ ++int kl_delete_btnode( ++ btnode_t** /* pointer to the root of the btree */, ++ btnode_t* /* pointer to btnode_s struct to delete */, ++ void(*)(void*) /* pointer to function to actually free the node */, ++ int /* flags */); ++ ++/* Traverse a tree looking for a particular key. In the event that ++ * duplicate keys are allowed in the tree, returns the first occurance ++ * of the search key found. A pointer to an int should be passed in ++ * to hold the maximum depth reached in the search. Upon success, ++ * returns a pointer to a btnode_s struct. Otherwise, a NULL pointer ++ * will be returned. ++ */ ++btnode_t *_kl_find_btnode( ++ btnode_t* /* pointer to btnode_s struct to start search with */, ++ char* /* key we are looking for */, ++ int* /* pointer to where max depth vlaue will be placed */, ++ size_t /* if nonzero compare only first n chars of key */); ++#define kl_find_btnode(A, B, C) _kl_find_btnode(A, B, C, 0) ++ ++btnode_t *kl_first_btnode( ++ btnode_t * /* pointer to any btnode in a btree */); ++ ++btnode_t *kl_next_btnode( ++ btnode_t * /* pointer to current btnode */); ++ ++btnode_t *kl_prev_btnode( ++ btnode_t * /* Pointer to current btnode */); ++ ++#endif /* __KL_BTNODE_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_cmp.h +@@ -0,0 +1,102 @@ ++/* ++ * $Id: kl_cmp.h 1216 2005-07-06 10:03:13Z holzheu $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_CMP_H ++#define __KL_CMP_H ++ ++#define DUMP_INDEX_MAGIC 0xdeadbeef ++#define DUMP_INDEX_VERSION 31900 ++#define NUM_BUCKETS 65535 ++ ++/* ++ * Definitions for compressed cached reads. I've recently lowered ++ * these ... If they need to be increased later, I'll do so. ++ */ ++#define CMP_HIGH_WATER_MARK 25 ++#define CMP_LOW_WATER_MARK 10 ++ ++#define CMP_VM_CACHED 0x01 ++#define CMP_VM_UNCACHED 0x02 ++ ++ ++/* ++ * This structure defines a page table entry, what each value will ++ * contain. Since these can be cached or uncached, we have a flags ++ * variable to specify this. ++ */ ++typedef struct _ptableentry { ++ int flags; /* flags for page in cache */ ++ int length; /* length of page */ ++ int cached; /* cached (1 = yes, cached) */ ++ kaddr_t addr; /* addr of page */ ++ char *data; /* data in page */ ++ struct _ptableentry *next; /* ptr to next dump page */ ++ struct _ptableentry *prev; /* ptr to prev dump page */ ++ struct _ptableentry *nextcache; /* ptr to next cached page */ ++ struct _ptableentry *prevcache; /* ptr to prev cached page */ ++} ptableentry; ++ ++/* ++ * This is for the page table index from the compressed core dump. ++ * This is separate from the page table entries because these are ++ * simply addresses off of the compressed core dump, and not the ++ * actual data from the core dump. If we hash these values, we gain ++ * a lot of performance because we only have 1 to search for the ++ * page data, 1 to search for the index, and return if both searches ++ * failed. ++ */ ++typedef struct _ptableindex { ++ kl_dump_page_t dir; /* directory entry of page */ ++ kaddr_t addr; /* address of page offset */ ++ kaddr_t coreaddr; /* address of page in core */ ++ unsigned int hash; /* hash value for this index item */ ++ struct _ptableindex *next; /* next pointer */ ++} ptableindex; ++ ++typedef struct dump_index_s { ++ unsigned int magic_number; /* dump index magic number */ ++ unsigned int version_number; /* dump index version number */ ++ /* struct timeval depends on machine, use two long values here */ ++ struct {uint64_t tv_sec; ++ uint64_t tv_usec; ++ } timebuf; /* the time of the dump */ ++} __attribute__((packed)) dump_index_t; ++ ++/* Compression function */ ++typedef int (*kl_compress_fn_t)(const unsigned char *old, uint32_t old_size, unsigned char *new, uint32_t size); ++ ++/* function declarations ++ */ ++int kl_cmpreadmem(int, kaddr_t, char*, unsigned int, unsigned int); ++int kl_cmpinit( ++ int /* fd */, ++ char * /* indexname */, ++ int /* flags */); ++ ++/* Compression routine: No compression */ ++int kl_compress_none(const char *old, uint32_t old_size, char *new, uint32_t new_size); ++ ++/* Compression routine: Run length encoding */ ++int kl_compress_rle(const char *old, uint32_t old_size, char *new, uint32_t new_size); ++ ++/* Compression routine: GZIP */ ++int kl_compress_gzip(const unsigned char *old, uint32_t old_size, unsigned char *new, uint32_t new_size); ++ ++#endif /* __KL_CMP_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_copt.h +@@ -0,0 +1,29 @@ ++/* ++ * $Id: kl_copt.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * ++ * Copyright (C) 2003, 2004 Silicon Graphics, Inc. All rights reserved. ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++#ifndef __KL_COPT_H ++#define __KL_COPT_H ++ ++extern int copt_ind; ++extern char *copt_arg; ++extern int copt_error; ++ ++void reset_copt(void); ++int is_copt(char *); ++int get_copt(int, char **, const char *, char **); ++ ++#endif /* __KL_COPT_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_debug.h +@@ -0,0 +1,168 @@ ++/* ++ * $Id: kl_debug.h 1196 2005-05-17 18:34:12Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_DEBUG_H ++#define __KL_DEBUG_H ++ ++/* generic functions for reading kerntypes in stabs and dwarf2 formats */ ++ ++#define DBG_NONE 0 ++#define DBG_STABS 1 ++#define DBG_DWARF2 2 ++ ++extern int debug_format; ++ ++#define TYPE_NUM(X) ((uint64_t)(X) & 0xffffffff) ++#define SRC_FILE(X) (((uint64_t)(X) >> 48) & 0xfff) ++#define TYPE_NUM_SLOTS (255) ++#define TYPE_NUM_HASH(X) \ ++ (((SRC_FILE(X)<<1)+TYPE_NUM(X)) % (TYPE_NUM_SLOTS - 1)) ++ ++typedef struct dbg_type_s { ++ kltype_t st_klt; /* must be first */ ++ ++ int st_bit_offset; /* from start of struct/union */ ++ uint64_t st_type_num; /* DBG type_num */ ++ uint64_t st_real_type; /* real type type_num */ ++ uint64_t st_index_type; /* type_num of array index */ ++ uint64_t st_element_type; /* type_num of array element */ ++} dbg_type_t; ++ ++#define st_name st_klt.kl_name ++#define st_type st_klt.kl_type ++#define st_ptr st_klt.kl_ptr ++#define st_flags st_klt.kl_flags ++#define st_typestr st_klt.kl_typestr ++#define st_size st_klt.kl_size ++#define st_offset st_klt.kl_offset ++#define st_low_bounds st_klt.kl_low_bounds ++#define st_high_bounds st_klt.kl_high_bounds ++#define st_value st_klt.kl_value ++#define st_bit_size st_klt.kl_bit_size ++#define st_next st_klt.kl_next ++#define st_member st_klt.kl_member ++#define st_realtype st_klt.kl_realtype ++#define st_indextype st_klt.kl_indextype ++#define st_elementtype st_klt.kl_elementtype ++#define st_encoding st_klt.kl_encoding ++ ++/* Structure containing information about a symbol entry ++ */ ++/* this must match the definition in lkcd's libklib/include/kl_debug.h */ ++typedef struct dbg_sym_s { ++ btnode_t sym_bt; /* must be first */ ++ short sym_dbgtyp; /* STABS, DWARF2, ... */ ++ short sym_state; /* current state */ ++ short sym_flag; /* current flag value */ ++ short sym_type; /* symbol type */ ++ short sym_pvttype; /* private type */ ++ short sym_nmlist; /* namelist index */ ++ short sym_srcfile; /* source file index */ ++ short sym_incfile; /* include file index */ ++ int sym_num; /* symbol number */ ++ int sym_off; /* symbol table offset */ ++ int sym_stroff; /* symbol offset in string table */ ++ uint64_t sym_typenum; /* arbitrary type number */ ++ kltype_t *sym_kltype; /* Full type information */ ++ struct dbg_sym_s *sym_next; /* next pointer for chaining */ ++ struct dbg_sym_s *sym_link; /* another pointer for chaining */ ++ int sym_dup; /* duplicate symbol */ ++} dbg_sym_t; ++#define sym_name sym_bt.bt_key ++ ++extern dbg_sym_t *type_tree; ++extern dbg_sym_t *typedef_tree; ++extern dbg_sym_t *func_tree; ++extern dbg_sym_t *srcfile_tree; ++extern dbg_sym_t *var_tree; ++extern dbg_sym_t *xtype_tree; ++extern dbg_sym_t *symlist; ++extern dbg_sym_t *symlist_end; ++ ++/* State flags ++ */ ++#define DBG_SETUP 0x1 ++#define DBG_SETUP_DONE 0x2 ++#define DBG_SETUP_FAILED 0x4 ++ ++/* Flags for identifying individual symbol types ++ */ ++#define DBG_SRCFILE 0x0001 ++#define DBG_TYPE 0x0002 ++#define DBG_TYPEDEF 0x0004 ++#define DBG_FUNC 0x0008 ++#define DBG_PARAM 0x0010 ++#define DBG_LINE 0x0020 ++#define DBG_VAR 0x0040 ++#define DBG_XTYPE 0x0100 ++#define DBG_ALL 0xffff ++ ++/* Structure for cross referencing one type number to another ++ */ ++typedef struct dbg_hashrec_s { ++ uint64_t h_typenum; /* type number */ ++ dbg_sym_t *h_ptr; /* pointer to actual type */ ++ struct dbg_hashrec_s *h_next; /* next pointer (for hashing) */ ++} dbg_hashrec_t; ++ ++extern dbg_hashrec_t *dbg_hash[]; ++ ++#define HASH_SYM 1 ++#define HASH_XREF 2 ++ ++/* DBG function prototypes ++ */ ++dbg_sym_t *dbg_alloc_sym( ++ int /* format */); ++ ++void dbg_free_sym( ++ dbg_sym_t * /* dbg_sym_s pointer */); ++ ++int dbg_setup_typeinfo( ++ dbg_sym_t * /* dbg_sym_s pointer */); ++ ++int dbg_insert_sym( ++ dbg_sym_t * /* dbg_sym_s pointer */); ++ ++void dbg_hash_sym( ++ uint64_t /* typenum */, ++ dbg_sym_t * /* dbg_sym_s pointer */); ++ ++dbg_type_t *dbg_walk_hash( ++ int * /* pointer to hash index */, ++ void ** /* pointer to hash record pointer */); ++ ++dbg_sym_t *dbg_find_sym( ++ char * /* name */, ++ int /* type number */, ++ uint64_t /* typenum */); ++ ++dbg_sym_t *dbg_first_sym( ++ int /* type number */); ++ ++dbg_sym_t *dbg_next_sym( ++ dbg_sym_t * /* dbg_sym_s pointer */); ++ ++dbg_sym_t *dbg_prev_sym( ++ dbg_sym_t * /* dbg_sym_s pointer */); ++ ++dbg_type_t *dbg_find_typenum( ++ uint64_t /* typenum */); ++ ++#endif /* __KL_DEBUG_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_dump.h +@@ -0,0 +1,511 @@ ++/* ++ * $Id: kl_dump.h 1336 2006-10-23 23:27:06Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_DUMP_H ++#define __KL_DUMP_H ++ ++#if 0 ++cpw: dont need: ++#include ++#include ++#endif ++ ++/* ++ * DUMP_DEBUG: a debug level for the kernel dump code and ++ * the supporting lkcd libraries in user space. ++ * ++ * 0: FALSE: No Debug Added ++ * 1: TRUE: Break Points ++ * . ++ * . ++ * . ++ * 6: Add Debug Data to Structures ++ * . ++ * . ++ * 9: Max ++ */ ++#define DUMP_DEBUG FALSE ++ ++#if DUMP_DEBUG ++void dump_bp(void); /* Called when something exceptional occures */ ++# define DUMP_BP() dump_bp() /* BreakPoint */ ++#else ++# define DUMP_BP() ++#endif ++ ++ ++#define KL_UTS_LEN 65 /* do not change ... */ ++ ++extern int SN2_24X; ++ ++/* ++ * Size of the buffer that's used to hold: ++ * ++ * 1. the dump header (paded to fill the complete buffer) ++ * 2. the possibly compressed page headers and data ++ */ ++extern uint64_t KL_DUMP_BUFFER_SIZE; ++extern uint64_t KL_DUMP_HEADER_SIZE; ++ ++#if 0 ++/* Variables that contain page size, mask etc. used in dump format ++ * (this is not the system page size stored in the dump header) ++ */ ++uint64_t KL_DUMP_PAGE_SIZE; ++uint64_t KL_DUMP_PAGE_MASK; ++uint64_t KL_DUMP_PAGE_SHIFT; ++#endif ++ ++/* Dump header offset changed from 4k to 64k to support multiple page sizes */ ++#define KL_DUMP_HEADER_OFFSET (1ULL << 16) ++ ++ ++/* header definitions for dumps from s390 standalone dump tools */ ++#define KL_DUMP_MAGIC_S390SA 0xa8190173618f23fdULL /* s390sa magic number */ ++#define KL_DUMP_HEADER_SZ_S390SA 4096 ++ ++/* standard header definitions */ ++#define KL_DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */ ++#define KL_DUMP_MAGIC_LIVE 0xa8190173618f23cdULL /* live magic number */ ++#define KL_DUMP_MAGIC_ASM 0xdeaddeadULL /* generic arch magic number */ ++#define KL_DUMP_VERSION_NUMBER 0x8 /* dump version number */ ++#define KL_DUMP_PANIC_LEN 0x100 /* dump panic string length */ ++ ++/* dump levels - type specific stuff added later -- add as necessary */ ++#define KL_DUMP_LEVEL_NONE 0x0 /* no dumping at all -- just bail */ ++#define KL_DUMP_LEVEL_HEADER 0x1 /* kernel dump header only */ ++#define KL_DUMP_LEVEL_KERN 0x2 /* dump header and kernel pages */ ++#define KL_DUMP_LEVEL_USED 0x4 /* dump header, kernel/user pages */ ++#define KL_DUMP_LEVEL_ALL_RAM 0x8 /* dump header, all RAM pages */ ++#define KL_DUMP_LEVEL_ALL 0x10 /* dump all memory RAM and firmware */ ++ ++/* dump compression options -- add as necessary */ ++#define KL_DUMP_COMPRESS_NONE 0x0 /* don't compress this dump */ ++#define KL_DUMP_COMPRESS_RLE 0x1 /* use RLE compression */ ++#define KL_DUMP_COMPRESS_GZIP 0x2 /* use GZIP compression */ ++ ++/* dump flags - any dump-type specific flags -- add as necessary */ ++#define KL_DUMP_FLAGS_NONE 0x0 /* no flags are set for this dump */ ++#define KL_DUMP_FLAGS_NONDISRUPT 0x1 /* try to keep running after dump */ ++#define KL_DUMP_FLAGS_DISKDUMP 0x80000000 /* dump to local disk */ ++#define KL_DUMP_FLAGS_NETDUMP 0x40000000 /* dump to network device */ ++ ++/* dump header flags -- add as necessary */ ++#define KL_DUMP_DH_FLAGS_NONE 0x0 /* no flags set (error condition!) */ ++#define KL_DUMP_DH_RAW 0x1 /* raw page (no compression) */ ++#define KL_DUMP_DH_COMPRESSED 0x2 /* page is compressed */ ++#define KL_DUMP_DH_END 0x4 /* end marker on a full dump */ ++#define KL_DUMP_DH_TRUNCATED 0x8 /* dump is incomplete */ ++#define KL_DUMP_DH_TEST_PATTERN 0x10 /* dump page is a test pattern */ ++#define KL_DUMP_DH_NOT_USED 0x20 /* 1st bit not used in flags */ ++ ++/* dump ioctl() control options */ ++#ifdef IOCTL26 ++#define DIOSDUMPDEV _IOW('p', 0xA0, unsigned int) /* set the dump device */ ++#define DIOGDUMPDEV _IOR('p', 0xA1, unsigned int) /* get the dump device */ ++#define DIOSDUMPLEVEL _IOW('p', 0xA2, unsigned int) /* set the dump level */ ++#define DIOGDUMPLEVEL _IOR('p', 0xA3, unsigned int) /* get the dump level */ ++#define DIOSDUMPFLAGS _IOW('p', 0xA4, unsigned int) /* set the dump flag parameters */ ++#define DIOGDUMPFLAGS _IOR('p', 0xA5, unsigned int) /* get the dump flag parameters */ ++#define DIOSDUMPCOMPRESS _IOW('p', 0xA6, unsigned int) /* set the dump compress level */ ++#define DIOGDUMPCOMPRESS _IOR('p', 0xA7, unsigned int) /* get the dump compress level */ ++ ++/* these ioctls are used only by netdump module */ ++#define DIOSTARGETIP _IOW('p', 0xA8, unsigned int) /* set the target m/c's ip */ ++#define DIOGTARGETIP _IOR('p', 0xA9, unsigned int) /* get the target m/c's ip */ ++#define DIOSTARGETPORT _IOW('p', 0xAA, unsigned int) /* set the target m/c's port */ ++#define DIOGTARGETPORT _IOR('p', 0xAB, unsigned int) /* get the target m/c's port */ ++#define DIOSSOURCEPORT _IOW('p', 0xAC, unsigned int) /* set the source m/c's port */ ++#define DIOGSOURCEPORT _IOR('p', 0xAD, unsigned int) /* get the source m/c's port */ ++#define DIOSETHADDR _IOW('p', 0xAE, unsigned int) /* set ethernet address */ ++#define DIOGETHADDR _IOR('p', 0xAF, unsigned int) /* get ethernet address */ ++#define DIOGDUMPOKAY _IOR('p', 0xB0, unsigned int) /* check if dump is configured */ ++#define DIOSDUMPTAKE _IOW('p', 0xB1, unsigned int) /* take a manual dump */ ++#else ++#define DIOSDUMPDEV 1 /* set the dump device */ ++#define DIOGDUMPDEV 2 /* get the dump device */ ++#define DIOSDUMPLEVEL 3 /* set the dump level */ ++#define DIOGDUMPLEVEL 4 /* get the dump level */ ++#define DIOSDUMPFLAGS 5 /* set the dump flag parameters */ ++#define DIOGDUMPFLAGS 6 /* get the dump flag parameters */ ++#define DIOSDUMPCOMPRESS 7 /* set the dump compress level */ ++#define DIOGDUMPCOMPRESS 8 /* get the dump compress level */ ++#define DIOSTARGETIP 9 /* set the target m/c's ip */ ++#define DIOGTARGETIP 10 /* get the target m/c's ip */ ++#define DIOSTARGETPORT 11 /* set the target m/c's port */ ++#define DIOGTARGETPORT 12 /* get the target m/c's port */ ++#define DIOSSOURCEPORT 13 /* set the source m/c's port */ ++#define DIOGSOURCEPORT 14 /* get the source m/c's port */ ++#define DIOSETHADDR 15 /* set ethernet address */ ++#define DIOGETHADDR 16 /* get ethernet address */ ++#define DIOGDUMPOKAY 17 /* check if dump is configured */ ++#define DIOSDUMPTAKE 18 /* take a manual dump */ ++#endif ++ ++/* ++ * structures ++ */ ++ ++/* This is the header dumped at the top of every valid crash dump. ++ */ ++typedef struct kl_dump_header_s { ++ uint64_t magic_number; /* dump magic number, unique to verify dump */ ++ uint32_t version; /* version number of this dump */ ++ uint32_t header_size; /* size of this header */ ++ uint32_t dump_level; /* level of this dump */ ++ /* FIXME: rename page_size to dump_page_size ++ * The size of a hardware/physical memory page (DUMP_PAGE_SIZE). ++ * NB: Not the configurable system page (PAGE_SIZE) (4K, 8K, 16K, etc.) ++ */ ++/* uint32_t dh_dump_page_size; */ ++ uint32_t page_size; /* page size (e.g. 4K, 8K, 16K, etc.) */ ++ uint64_t memory_size; /* size of entire physical memory */ ++ uint64_t memory_start; /* start of physical memory */ ++ uint64_t memory_end; /* end of physical memory */ ++#if DUMP_DEBUG >= 6 ++ uint64_t num_bytes; /* number of bytes in this dump */ ++#endif ++ /* the number of dump pages in this dump specifically */ ++ uint32_t num_dump_pages; ++ char panic_string[KL_DUMP_PANIC_LEN]; /* panic string, if available*/ ++ ++ /* timeval depends on machine, two long values */ ++ struct {uint64_t tv_sec; ++ uint64_t tv_usec; ++ } time; /* the time of the system crash */ ++ ++ /* the NEW utsname (uname) information -- in character form */ ++ /* we do this so we don't have to include utsname.h */ ++ /* plus it helps us be more architecture independent */ ++ char utsname_sysname[KL_UTS_LEN]; ++ char utsname_nodename[KL_UTS_LEN]; ++ char utsname_release[KL_UTS_LEN]; ++ char utsname_version[KL_UTS_LEN]; ++ char utsname_machine[KL_UTS_LEN]; ++ char utsname_domainname[KL_UTS_LEN]; ++ ++ uint64_t current_task; /* fixme: better use uint64_t here */ ++ uint32_t dump_compress; /* compression type used in this dump */ ++ uint32_t dump_flags; /* any additional flags */ ++ uint32_t dump_device; /* any additional flags */ ++ uint64_t dump_buffer_size; /* version >= 9 */ ++} __attribute__((packed)) kl_dump_header_t; ++ ++/* This is the header used by the s390 standalone dump tools ++ */ ++typedef struct kl_dump_header_s390sa_s { ++ uint64_t magic_number; /* magic number for this dump (unique)*/ ++ uint32_t version; /* version number of this dump */ ++ uint32_t header_size; /* size of this header */ ++ uint32_t dump_level; /* the level of this dump (just a header?) */ ++ uint32_t page_size; /* page size of dumped Linux (4K,8K,16K etc.) */ ++ uint64_t memory_size; /* the size of all physical memory */ ++ uint64_t memory_start; /* the start of physical memory */ ++ uint64_t memory_end; /* the end of physical memory */ ++ uint32_t num_pages; /* number of pages in this dump */ ++ uint32_t pad; /* ensure 8 byte alignment for tod and cpu_id */ ++ uint64_t tod; /* the time of the dump generation */ ++ uint64_t cpu_id; /* cpu id */ ++ uint32_t arch_id; ++ uint32_t build_arch_id; ++#define KL_DH_ARCH_ID_S390X 2 ++#define KL_DH_ARCH_ID_S390 1 ++} __attribute__((packed)) kl_dump_header_s390sa_t; ++ ++/* Header associated to each physical page of memory saved in the system ++ * crash dump. ++ */ ++typedef struct kl_dump_page_s { ++#if DUMP_DEBUG >= 6 ++ uint64_t byte_offset; /* byte offset */ ++ uint64_t page_index; /* page index */ ++#endif ++ uint64_t address; /* the address of this dump page */ ++ uint32_t size; /* the size of this dump page */ ++ uint32_t flags; /* flags (DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */ ++} __attribute__((packed)) kl_dump_page_t; ++ ++/* CORE_TYPE indicating type of dump ++ */ ++typedef enum { ++ dev_kmem, /* image of /dev/kmem, a running kernel */ ++ reg_core, /* Regular (uncompressed) core file */ ++ s390_core, /* s390 core file */ ++ cmp_core, /* compressed core file */ ++ unk_core /* unknown core type */ ++} CORE_TYPE; ++ ++/* function to determine kernel stack for task */ ++typedef kaddr_t(*kl_kernelstack_t) (kaddr_t); ++/* map virtual address to physical one */ ++typedef int(*kl_virtop_t)(kaddr_t, void*, kaddr_t*); ++/* function to perform page-table traversal */ ++typedef kaddr_t(*kl_mmap_virtop_t)(kaddr_t, void*); ++/* XXX description */ ++typedef int(*kl_valid_physmem_t)(kaddr_t, int); ++/* XXX description */ ++typedef kaddr_t(*kl_next_valid_physaddr_t)(kaddr_t); ++/* write a dump-header-asm, if analyzing a live system */ ++typedef int(*kl_write_dump_header_asm_t)(void*); ++/* redirect addresses pointing into task_union areas for running tasks */ ++typedef kaddr_t(*kl_fix_vaddr_t)(kaddr_t, size_t); ++/* initialize mapping of virtual to physical addresses */ ++typedef int (*kl_init_virtop_t)(void); ++ ++/* struct storing dump architecture specific values ++ */ ++typedef struct kl_dumparch_s { ++ int arch; /* KL_ARCH_ */ ++ int ptrsz; /* 32 or 64 bit */ ++ int byteorder; /* KL_LITTLE_ENDIAN or KL_BIG_ENDIAN */ ++ uint64_t pageoffset; /* PAGE_OFFSET */ ++ uint64_t kstacksize; /* size of kernel stack */ ++ uint64_t pgdshift; /* PGDIR_SHIFT */ ++ uint64_t pgdsize; /* PGDIR_SIZE */ ++ uint64_t pgdmask; /* PGDIR_MASK */ ++ uint64_t pmdshift; /* PMD_SHIFT */ ++ uint64_t pmdsize; /* PMD_SIZE */ ++ uint64_t pmdmask; /* PMD_MASK */ ++ uint64_t pageshift; /* PAGE_SHIFT */ ++ uint64_t pagesize; /* PAGE_SIZE */ ++ uint64_t pagemask; /* PAGE_MASK */ ++ uint32_t ptrsperpgd; /* PTRS_PER_PGD */ ++ uint32_t ptrsperpmd; /* PTRS_PER_PMD */ ++ uint32_t ptrsperpte; /* PTRS_PER_PTE */ ++ kl_kernelstack_t kernelstack; /* determine kernel stack for task */ ++ kl_virtop_t virtop; /* map virtual address to physical */ ++ kl_mmap_virtop_t mmap_virtop; /* traverse page table */ ++ kl_valid_physmem_t valid_physmem; /* XXX description */ ++ kl_next_valid_physaddr_t next_valid_physaddr; /* XXX description */ ++ kl_fix_vaddr_t fix_vaddr; /* XXX description */ ++ uint32_t dha_size; /* size of kl_dump_header_xxx_t */ ++ kl_write_dump_header_asm_t write_dha; /* XXX description */ ++ kl_init_virtop_t init_virtop; /* init address translation */ ++} kl_dumparch_t; ++ ++/* function types for dumpaccess */ ++typedef kaddr_t (*kl_get_ptr_t) (void*); ++typedef uint8_t (*kl_get_uint8_t) (void*); ++typedef uint16_t(*kl_get_uint16_t)(void*); ++typedef uint32_t(*kl_get_uint32_t)(void*); ++typedef uint64_t(*kl_get_uint64_t)(void*); ++/* function types for dumpaccess */ ++typedef kaddr_t (*kl_read_ptr_t) (kaddr_t); ++typedef uint8_t (*kl_read_uint8_t) (kaddr_t); ++typedef uint16_t (*kl_read_uint16_t)(kaddr_t); ++typedef uint32_t (*kl_read_uint32_t)(kaddr_t); ++typedef uint64_t (*kl_read_uint64_t)(kaddr_t); ++ ++/* struct to store dump architecture specific functions ++ */ ++typedef struct kl_dumpaccess_s { ++ /* get integer value from memory, previously read from dump */ ++ kl_get_ptr_t get_ptr; ++ kl_get_uint8_t get_uint8; ++ kl_get_uint16_t get_uint16; ++ kl_get_uint32_t get_uint32; ++ kl_get_uint64_t get_uint64; ++ /* read integer value from dump (from physical address) */ ++ kl_read_ptr_t read_ptr; ++ kl_read_uint8_t read_uint8; ++ kl_read_uint16_t read_uint16; ++ kl_read_uint32_t read_uint32; ++ kl_read_uint64_t read_uint64; ++ /* read integer value from dump (from virtual address) */ ++ kl_read_ptr_t vread_ptr; ++ kl_read_uint8_t vread_uint8; ++ kl_read_uint16_t vread_uint16; ++ kl_read_uint32_t vread_uint32; ++ kl_read_uint64_t vread_uint64; ++} kl_dumpaccess_t; ++ ++/* Struct containing sizes of frequently used kernel structures. ++ */ ++typedef struct struct_sizes_s { ++ int task_struct_sz; ++ int mm_struct_sz; ++ int page_sz; ++ int module_sz; ++ int new_utsname_sz; ++ int switch_stack_sz; ++ int pt_regs_sz; ++ int pglist_data_sz; ++ int runqueue_sz; ++} struct_sizes_t; ++ ++/* struct storing memory specifc values of the dumped Linux system ++ */ ++typedef struct kl_kerninfo_s{ ++ kaddr_t num_physpages; /* number of physical pages */ ++ kaddr_t mem_map; /* XXX description */ ++ kaddr_t high_memory; /* physical memory size */ ++ kaddr_t init_mm; /* address of mm_struct init_mm */ ++ uint64_t kernel_flags; /* to indicate kernel features ++ * e.g. KL_IS_PAE_I386 on i386 */ ++ int num_cpus; /* number of cpus */ ++ kaddr_t pgdat_list; /* pgdat_list value. used as MEM_MAP */ ++ /* not defined for DISCONTIG memory */ ++ int linux_release; /* kernel release of dump */ ++ struct_sizes_t struct_sizes; /* frequently needed struct sizes */ ++} kl_kerninfo_t; ++ ++/* various flags to indicate Linux kernel compile switches */ ++#define KL_IS_PAE_I386 0x0020 /* i386 kernel with PAE support */ ++ ++/* struct where to keep whole information about the dump ++ */ ++typedef struct kl_dumpinfo_s { ++ CORE_TYPE core_type; /* type of core file */ ++ char *dump; /* pathname for dump */ ++ char *map; /* pathname for map file */ ++ int core_fd; /* file descriptor for dump file */ ++ int rw_flag; /* O_RDONLY/O_RDWR (/dev/kmem only) */ ++ kl_dumparch_t arch; /* dump arch info */ ++ kl_dumpaccess_t func; /* dump access functions */ ++ kl_kerninfo_t mem; /* mem info for dump */ ++} kl_dumpinfo_t; ++ ++/* External declarations ++ */ ++extern char *dh_typename; ++extern char *dha_typename; ++extern void *G_dump_header; ++extern void *G_dump_header_asm; ++extern kl_dump_header_t *KL_DUMP_HEADER; ++extern void *KL_DUMP_HEADER_ASM; ++ ++/* function declarations ++ */ ++ ++/* open dump */ ++int kl_open_dump(void); ++ ++/* init sizes for some structures */ ++void kl_init_struct_sizes(void); ++ ++/* init host architecture information */ ++int kl_setup_hostinfo(void); ++ ++/* init dumpinfo structure */ ++int kl_setup_dumpinfo(char * /* map file */, ++ char * /* dump */, ++ int /* rwflag */); ++ ++ ++/* init dumpinfo structure */ ++int kl_set_dumpinfo(char * /* map file */, ++ char * /* dump */, ++ int /* arch of dump */, ++ int /* rwflag */); ++ ++/* free dumpinfo structure */ ++void kl_free_dumpinfo(kl_dumpinfo_t *); ++ ++/* set memory related characteristics of dump */ ++int kl_set_kerninfo(void); ++ ++/* set function pointers for dump access (depends on host and dump arch) */ ++int kl_set_dumpaccess(void); ++ ++/* print contents of kl_dumpinfo_t etc. */ ++int kl_print_dumpinfo(int); ++#define KL_INFO_ALL 0 ++#define KL_INFO_ENDIAN 1 ++#define KL_INFO_ARCH 2 ++#define KL_INFO_PTRSZ 3 ++#define KL_INFO_KRELEASE 4 ++#define KL_INFO_MEMSIZE 5 ++#define KL_INFO_NUMCPUS 6 ++ ++/* Functions that read data from generic dump_header */ ++int kl_valid_dump_magic(uint64_t); ++int kl_header_swap(void *); ++uint64_t kl_header_magic(void *); ++int kl_valid_header(void *); ++uint32_t kl_header_version(void *); ++int kl_header_size(void *); ++void *kl_read_header(int fd, void *); ++ ++/* init common lkcd dump header from dump */ ++void kl_init_dump_header(int); ++ ++/* try to evalutate arch from lkcd 4.1 (version <= 7) dump header */ ++int kl_dump_arch_4_1(void *); ++ ++/* swap dump header values if necessary */ ++void kl_swap_dump_header_reg(kl_dump_header_t* dh); ++void kl_swap_dump_header_s390sa(kl_dump_header_s390sa_t* dh); ++ ++/* Read dump header in from dump */ ++int kl_read_dump_header(void); ++int kl_read_dump_header_asm(void); ++ ++/* Determine the architecure of dump */ ++int kl_set_dumparch(int); ++ ++/* Finish setting up for access to dump */ ++int kl_setup_dumpaccess(int); ++ ++/* get the raw dump header */ ++int kl_get_raw_dh(int); ++int kl_get_raw_asm_dh(int); ++ ++/* get common lkcd dump header */ ++int kl_get_dump_header(kl_dump_header_t*); ++ ++/* get older style dump headers */ ++kl_dump_header_t *get_dump_header_4_1(void *); ++kl_dump_header_t *get_dump_header_SN2_24X(void *); ++ ++/* get task that was running when dump was started */ ++kaddr_t kl_dumptask(void); ++ ++/* Print dump header */ ++int kl_print_dump_header(const char* dump); ++ ++/* Print dump regular header */ ++void kl_print_dump_header_reg(kl_dump_header_t *); ++ ++/* Print s390 dump header */ ++void kl_print_dump_header_s390(char*); ++ ++/* Convert s390 to reg header */ ++void kl_s390sa_to_reg_header(kl_dump_header_s390sa_t*, kl_dump_header_t*); ++ ++/* Byte swapping functions needed for Xclrash */ ++/* get integer value from buffer and swap bytes */ ++kaddr_t kl_get_swap_ptr(void*); ++uint16_t kl_get_swap_uint16(void*); ++uint32_t kl_get_swap_uint32(void*); ++uint64_t kl_get_swap_uint64(void*); ++ ++/* read integer value from dump (physical address) and swap bytes */ ++kaddr_t kl_read_swap_ptr(kaddr_t); ++uint16_t kl_read_swap_uint16(kaddr_t); ++uint32_t kl_read_swap_uint32(kaddr_t); ++uint64_t kl_read_swap_uint64(kaddr_t); ++ ++/* read integer value from dump (virtual address) and swap bytes */ ++kaddr_t kl_vread_swap_ptr(kaddr_t); ++uint16_t kl_vread_swap_uint16(kaddr_t); ++uint32_t kl_vread_swap_uint32(kaddr_t); ++uint64_t kl_vread_swap_uint64(kaddr_t); ++ ++#endif /* __KL_DUMP_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_dump_arch.h +@@ -0,0 +1,124 @@ ++/* ++ * $Id: kl_dump_arch.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_DUMP_ARCH_H ++#define __KL_DUMP_ARCH_H ++ ++/* check for valid configuration ++ */ ++#if !(defined(HOST_ARCH_ALPHA) || defined(HOST_ARCH_I386) || \ ++ defined(HOST_ARCH_IA64) || defined(HOST_ARCH_S390) || \ ++ defined(HOST_ARCH_S390X) || defined(HOST_ARCH_ARM) || \ ++ defined(HOST_ARCH_PPC64) || defined(HOST_ARCH_X86_64)) ++# error "No valid host architecture defined." ++#endif ++#if ((defined(HOST_ARCH_ALPHA) && \ ++ (defined(HOST_ARCH_I386) || defined(HOST_ARCH_IA64) || \ ++ defined(HOST_ARCH_S390) || defined(HOST_ARCH_S390X) || \ ++ defined(HOST_ARCH_ARM) || defined(HOST_ARCH_PPC64) || \ ++ defined(HOST_ARCH_X86_64))) || \ ++ (defined(HOST_ARCH_I386) && \ ++ (defined(HOST_ARCH_IA64) || defined(HOST_ARCH_S390) || \ ++ defined(HOST_ARCH_S390X)|| defined(HOST_ARCH_ARM) || \ ++ defined(HOST_ARCH_PPC64)|| defined(HOST_ARCH_X86_64))) || \ ++ (defined(HOST_ARCH_IA64) && \ ++ (defined(HOST_ARCH_S390)|| defined(HOST_ARCH_S390X) || \ ++ defined(HOST_ARCH_ARM) || defined(HOST_ARCH_PPC64) || \ ++ defined(HOST_ARCH_X86_64))) || \ ++ (defined(HOST_ARCH_S390) && \ ++ (defined(HOST_ARCH_S390X) || defined(HOST_ARCH_ARM) || \ ++ defined(HOST_ARCH_PPC64) || defined(HOST_ARCH_X86_64))) || \ ++ (defined(HOST_ARCH_S390X) && \ ++ (defined(HOST_ARCH_ARM) || defined(HOST_ARCH_PPC64) || \ ++ defined(HOST_ARCH_X86_64))) || \ ++ (defined(HOST_ARCH_ARM) && \ ++ (defined(HOST_ARCH_PPC64) || defined(HOST_ARCH_X86_64))) || \ ++ (defined(HOST_ARCH_PPC64) && defined(HOST_ARCH_X86_64))) ++# error "More than one valid host architectures defined." ++#endif ++#if !(defined(DUMP_ARCH_ALPHA) || defined(DUMP_ARCH_I386) || \ ++ defined(DUMP_ARCH_IA64) || defined(DUMP_ARCH_S390) || \ ++ defined(DUMP_ARCH_S390X) || defined(DUMP_ARCH_ARM) || \ ++ defined(DUMP_ARCH_PPC64) || defined(DUMP_ARCH_X86_64)) ++# error "No valid dump architecture defined." ++#endif ++ ++/* optional: check that host arch equals one supported dump arch ++ */ ++#ifdef SUPPORT_HOST_ARCH ++# if (defined(HOST_ARCH_ALPHA) && !defined(DUMP_ARCH_ALPHA)) || \ ++ (defined(HOST_ARCH_I386) && !defined(DUMP_ARCH_I386)) || \ ++ (defined(HOST_ARCH_IA64) && !defined(DUMP_ARCH_IA64)) || \ ++ (defined(HOST_ARCH_S390) && !defined(DUMP_ARCH_S390)) || \ ++ (defined(HOST_ARCH_S390X) && !defined(DUMP_ARCH_S390X)) || \ ++ (defined(HOST_ARCH_ARM) && !defined(DUMP_ARCH_ARM)) || \ ++ (defined(HOST_ARCH_PPC64) && !defined(DUMP_ARCH_PPC64)) || \ ++ (defined(HOST_ARCH_X86_64) && !defined(DUMP_ARCH_X86_64)) ++# error "Host architecture not supported as dump architecture." ++# endif ++#endif ++ ++/* include dump architecture specific stuff ++ */ ++#ifdef DUMP_ARCH_ALPHA ++# include ++# include ++#endif ++/* cpw: use the " " form: */ ++#ifdef DUMP_ARCH_IA64 ++# include "kl_mem_ia64.h" ++# include "kl_dump_ia64.h" ++#endif ++#ifdef DUMP_ARCH_I386 ++# include ++# include ++#endif ++#ifdef DUMP_ARCH_S390 ++# include ++# include ++#endif ++#ifdef DUMP_ARCH_S390X ++# include ++# include ++#endif ++#ifdef DUMP_ARCH_ARM ++# include ++# include ++#endif ++#ifdef DUMP_ARCH_PPC64 ++#include ++#include ++#endif ++#ifdef DUMP_ARCH_X86_64 ++#include ++#include ++#endif ++ ++/** Function prototypes ++ **/ ++int kl_init_kern_info(void); ++ ++int kl_get_struct( ++ kaddr_t /* address */, ++ int /* size of struct */, ++ void * /* ptr to buffer */, ++ char * /* name of struct */); ++ ++#endif /* __KL_DUMP_ARCH_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_dump_ia64.h +@@ -0,0 +1,199 @@ ++/* ++ * $Id: kl_dump_ia64.h 1151 2005-02-23 01:09:12Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++/* This header file holds the architecture specific crash dump header */ ++#ifndef __KL_DUMP_IA64_H ++#define __KL_DUMP_IA64_H ++ ++/* definitions */ ++#ifndef KL_NR_CPUS ++# define KL_NR_CPUS 128 /* max number CPUs */ ++#endif ++ ++#define KL_DUMP_MAGIC_NUMBER_IA64 0xdeaddeadULL /* magic number */ ++#define KL_DUMP_VERSION_NUMBER_IA64 0x4 /* version number */ ++ ++ ++/* ++ * mkswap.c calls getpagesize() to get the system page size, ++ * which is not necessarily the same as the hardware page size. ++ * ++ * For ia64 the kernel PAGE_SIZE can be configured from 4KB ... 16KB. ++ * ++ * The physical memory is layed out out in the hardware/minimal pages. ++ * This is the size we need to use for dumping physical pages. ++ * ++ * Note ths hardware/minimal page size being use in; ++ * arch/ia64/kernel/efi.c`efi_memmap_walk(): ++ * curr.end = curr.start + (md->num_pages << 12); ++ * ++ * Since the system page size could change between the kernel we boot ++ * on the the kernel that cause the core dume we may want to have something ++ * more constant like the maximum system page size (See include/asm-ia64/page.h). ++ */ ++#define DUMP_MIN_PAGE_SHIFT 12 ++#define DUMP_MIN_PAGE_SIZE (1UL << DUMP_MIN_PAGE_SHIFT) ++#define DUMP_MIN_PAGE_MASK (~(DUMP_MIN_PAGE_SIZE - 1)) ++#define DUMP_MIN_PAGE_ALIGN(addr) (((addr) + DUMP_MIN_PAGE_SIZE - 1) & DUMP_MIN_PAGE_MASK) ++ ++#define DUMP_MAX_PAGE_SHIFT 16 ++#define DUMP_MAX_PAGE_SIZE (1UL << DUMP_MAX_PAGE_SHIFT) ++#define DUMP_MAX_PAGE_MASK (~(DUMP_MAX_PAGE_SIZE - 1)) ++#define DUMP_MAX_PAGE_ALIGN(addr) (((addr) + DUMP_MAX_PAGE_SIZE - 1) & DUMP_MAX_PAGE_MASK) ++ ++#define DUMP_HEADER_OFFSET DUMP_MAX_PAGE_SIZE ++ ++#define DUMP_EF_PAGE_SHIFT DUMP_MIN_PAGE_SHIFT ++ ++#define DUMP_PAGE_SHIFT DUMP_MIN_PAGE_SHIFT ++#define DUMP_PAGE_SIZE DUMP_MIN_PAGE_SIZE ++#define DUMP_PAGE_MASK DUMP_MIN_PAGE_MASK ++#define DUMP_PAGE_ALIGN(addr) DUMP_MIN_PAGE_ALIGN(addr) ++ ++struct kl_ia64_fpreg { ++ union { ++ unsigned long bits[2]; ++ long double __dummy; /* force 16-byte alignment */ ++ } u; ++}; ++ ++struct kl_pt_regs_ia64 { ++ /* for 2.6 kernels only. This structure was totally different in 2.4 kernels */ ++ unsigned long b6; /* scratch */ ++ unsigned long b7; /* scratch */ ++ ++ unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ ++ unsigned long ar_ssd; /* reserved for future use (scratch) */ ++ ++ unsigned long r8; /* scratch (return value register 0) */ ++ unsigned long r9; /* scratch (return value register 1) */ ++ unsigned long r10; /* scratch (return value register 2) */ ++ unsigned long r11; /* scratch (return value register 3) */ ++ ++ unsigned long cr_ipsr; /* interrupted task's psr */ ++ unsigned long cr_iip; /* interrupted task's instruction pointer */ ++ unsigned long cr_ifs; /* interrupted task's function state */ ++ ++ unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ ++ unsigned long ar_pfs; /* prev function state */ ++ unsigned long ar_rsc; /* RSE configuration */ ++ /* The following two are valid only if cr_ipsr.cpl > 0: */ ++ unsigned long ar_rnat; /* RSE NaT */ ++ unsigned long ar_bspstore; /* RSE bspstore */ ++ ++ unsigned long pr; /* 64 predicate registers (1 bit each) */ ++ unsigned long b0; /* return pointer (bp) */ ++ unsigned long loadrs; /* size of dirty partition << 16 */ ++ ++ unsigned long r1; /* the gp pointer */ ++ unsigned long r12; /* interrupted task's memory stack pointer */ ++ unsigned long r13; /* thread pointer */ ++ ++ unsigned long ar_fpsr; /* floating point status (preserved) */ ++ unsigned long r15; /* scratch */ ++ ++ /* The remaining registers are NOT saved for system calls. */ ++ ++ unsigned long r14; /* scratch */ ++ unsigned long r2; /* scratch */ ++ unsigned long r3; /* scratch */ ++ ++ /* The following registers are saved by SAVE_REST: */ ++ unsigned long r16; /* scratch */ ++ unsigned long r17; /* scratch */ ++ unsigned long r18; /* scratch */ ++ unsigned long r19; /* scratch */ ++ unsigned long r20; /* scratch */ ++ unsigned long r21; /* scratch */ ++ unsigned long r22; /* scratch */ ++ unsigned long r23; /* scratch */ ++ unsigned long r24; /* scratch */ ++ unsigned long r25; /* scratch */ ++ unsigned long r26; /* scratch */ ++ unsigned long r27; /* scratch */ ++ unsigned long r28; /* scratch */ ++ unsigned long r29; /* scratch */ ++ unsigned long r30; /* scratch */ ++ unsigned long r31; /* scratch */ ++ ++ unsigned long ar_ccv; /* compare/exchange value (scratch) */ ++ ++ /* ++ * * Floating point registers that the kernel considers scratch: ++ * */ ++ struct kl_ia64_fpreg f6; /* scratch */ ++ struct kl_ia64_fpreg f7; /* scratch */ ++ struct kl_ia64_fpreg f8; /* scratch */ ++ struct kl_ia64_fpreg f9; /* scratch */ ++ struct kl_ia64_fpreg f10; /* scratch */ ++ struct kl_ia64_fpreg f11; /* scratch */ ++} __attribute__((packed)); ++ ++/* ++ * Structure: dump_header_asm_t ++ * Function: This is the header for architecture-specific stuff. It ++ * follows right after the dump header. ++ */ ++typedef struct kl_dump_header_ia64_s { ++ /* the dump magic number -- unique to verify dump is valid */ ++ uint64_t magic_number; ++ /* the version number of this dump */ ++ uint32_t version; ++ /* the size of this header (in case we can't read it) */ ++ uint32_t header_size; ++ /* pointer to pt_regs */ ++ uint64_t pt_regs; ++ /* the dump registers */ ++ struct kl_pt_regs_ia64 regs; ++ /* the rnat register saved after flushrs */ ++ uint64_t rnat; ++ /* the pfs register saved after flushrs */ ++ uint64_t pfs; ++ /* the bspstore register saved after flushrs */ ++ uint64_t bspstore; ++ ++ /* smp specific */ ++ uint32_t smp_num_cpus; ++ uint32_t dumping_cpu; ++ struct kl_pt_regs_ia64 smp_regs[KL_NR_CPUS]; ++ uint64_t smp_current_task[KL_NR_CPUS]; ++ uint64_t stack[KL_NR_CPUS]; ++} __attribute__((packed)) kl_dump_header_ia64_t; ++ ++/* The following struct is used just to calculate the size needed ++ * to store per CPU info. (Make sure it is sync with the above struct) ++ */ ++struct kl_dump_CPU_info_ia64 { ++ struct kl_pt_regs_ia64 smp_regs; ++ uint64_t smp_current_task; ++ uint64_t stack; ++} __attribute__((packed)); ++ ++/* function declarations ++ */ ++int kl_set_dumparch_ia64(void); ++uint32_t dha_num_cpus_ia64(void); ++kaddr_t dha_current_task_ia64(int cpuid); ++int dha_cpuid_ia64(kaddr_t); ++kaddr_t dha_stack_ia64(int); ++kaddr_t dha_stack_ptr_ia64(int); ++int kl_read_dump_header_ia64(void); ++ ++#endif /* __KL_DUMP_IA64_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_dwarfs.h +@@ -0,0 +1,27 @@ ++/* ++ * $Id: kl_dwarfs.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by: Prashanth Tamraparni (prasht@in.ibm.com) ++ * Contributions by SGI ++ * ++ * Copyright (C) 2004 International Business Machines Corp. ++ * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++#ifndef __KL_DWARFS_H ++#define __KL_DWARFS_H ++ ++/* Dwarf function declarations */ ++ ++int dw_open_namelist(char*, int); ++int dw_setup_typeinfo(void); ++ ++#endif /* __KL_DWARFS_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_error.h +@@ -0,0 +1,266 @@ ++/* ++ * $Id: kl_error.h 1169 2005-03-02 21:38:01Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_ERROR_H ++#define __KL_ERROR_H ++ ++extern uint64_t klib_error; ++extern FILE *kl_stdout; ++extern FILE *kl_stderr; ++ ++/* Error Classes ++ */ ++#define KLEC_APP 0 ++#define KLEC_KLIB 1 ++#define KLEC_MEM 2 ++#define KLEC_SYM 3 ++#define KLEC_KERN 4 ++ ++#define KLEC_CLASS_MASK 0x00000000ff000000ULL ++#define KLEC_CLASS_SHIFT 24 ++#define KLEC_ECODE_MASK 0x0000000000ffffffULL ++#define KLEC_TYPE_MASK 0xffffffff00000000ULL ++#define KLEC_TYPE_SHIFT 32 ++#define KLEC_CLASS(e) ((e & KLEC_CLASS_MASK) >> KLEC_CLASS_SHIFT) ++#define KLEC_ECODE(e) (e & KLEC_ECODE_MASK) ++#define KLEC_TYPE(e) ((e & KLEC_TYPE_MASK) >> KLEC_TYPE_SHIFT) ++ ++void kl_reset_error(void); /* reset klib_error */ ++void kl_print_error(void); /* print warning/error messages */ ++void kl_check_error(char*); /* check for/handle errors, generate messages */ ++ ++/* FIXME: not used yet -- for changes in future, improve error handling ++ */ ++typedef struct klib_error_s{ ++ uint32_t code; /* error code */ ++ uint16_t class; /* error class */ ++ uint16_t severity; /* severity of error: e.g. warning or fatal error */ ++ uint32_t datadesc; /* description of data which caused the error */ ++ FILE *fp; /* fp where to place warning and error messages */ ++} klib_error_t; ++ ++/* ++ * Some macros for accessing data in klib_error ++ */ ++#define KL_ERROR klib_error ++#define KL_ERRORFP kl_stderr ++ ++/* Error codes ++ * ++ * There are basically two types of error codes -- with each type ++ * residing in a single word in a two word error code value. The lower ++ * 32-bits contains an error class and code that represents exactly ++ * WHAT error occurred (e.g., non-numeric text in a numeric value ++ * entered by a user, bad virtual address, etc.). ++ * ++ * The upper 32-bits represents what type of data was being referenced ++ * when the error occurred (e.g., bad proc struct). Having two tiers of ++ * error codes makes it easier to generate useful and specific error ++ * messages. Note that is possible to have situations where one or the ++ * other type of error codes is not set. This is OK as long as at least ++ * one type s set. ++ */ ++ ++/* General klib error codes ++ */ ++#define KLE_KLIB (KLEC_KLIB << KLEC_CLASS_SHIFT) ++#define KLE_NO_MEMORY (KLE_KLIB|1) ++#define KLE_OPEN_ERROR (KLE_KLIB|2) ++#define KLE_ZERO_BLOCK (KLE_KLIB|3) ++#define KLE_INVALID_VALUE (KLE_KLIB|4) ++#define KLE_NULL_BUFF (KLE_KLIB|5) ++#define KLE_ZERO_SIZE (KLE_KLIB|6) ++#define KLE_ACTIVE (KLE_KLIB|7) ++#define KLE_NULL_POINTER (KLE_KLIB|8) ++#define KLE_UNSUPPORTED_ARCH (KLE_KLIB|9) ++ ++#define KLE_MISC_ERROR (KLE_KLIB|97) ++#define KLE_NOT_SUPPORTED (KLE_KLIB|98) ++#define KLE_UNKNOWN_ERROR (KLE_KLIB|99) ++ ++/* memory error codes ++ */ ++#define KLE_MEM (KLEC_MEM << KLEC_CLASS_SHIFT) ++#define KLE_BAD_MAP_FILE (KLE_MEM|1) ++#define KLE_BAD_DUMP (KLE_MEM|2) ++#define KLE_BAD_DUMPTYPE (KLE_MEM|3) ++#define KLE_INVALID_LSEEK (KLE_MEM|4) ++#define KLE_INVALID_READ (KLE_MEM|5) ++#define KLE_BAD_KERNINFO (KLE_MEM|6) ++#define KLE_INVALID_PADDR (KLE_MEM|7) ++#define KLE_INVALID_VADDR (KLE_MEM|8) ++#define KLE_INVALID_VADDR_ALIGN (KLE_MEM|9) ++#define KLE_INVALID_MAPPING (KLE_MEM|10) ++#define KLE_CMP_ERROR (KLE_MEM|11) ++#define KLE_INVALID_DUMP_MAGIC (KLE_MEM|12) ++#define KLE_KERNEL_MAGIC_MISMATCH (KLE_MEM|13) ++#define KLE_NO_END_SYMBOL (KLE_MEM|14) ++#define KLE_INVALID_DUMP_HEADER (KLE_MEM|15) ++#define KLE_DUMP_INDEX_CREATION (KLE_MEM|16) ++#define KLE_DUMP_HEADER_ONLY (KLE_MEM|17) ++#define KLE_PAGE_NOT_PRESENT (KLE_MEM|18) ++#define KLE_BAD_ELF_FILE (KLE_MEM|19) ++#define KLE_ARCHIVE_FILE (KLE_MEM|20) ++#define KLE_MAP_FILE_PRESENT (KLE_MEM|21) ++#define KLE_BAD_MAP_FILENAME (KLE_MEM|22) ++#define KLE_BAD_DUMP_FILENAME (KLE_MEM|23) ++#define KLE_BAD_NAMELIST_FILE (KLE_MEM|24) ++#define KLE_BAD_NAMELIST_FILENAME (KLE_MEM|25) ++#define KLE_LIVE_SYSTEM (KLE_MEM|26) ++#define KLE_NOT_INITIALIZED (KLE_MEM|27) ++ ++/* symbol error codes ++ */ ++#define KLE_SYM (KLEC_SYM << KLEC_CLASS_SHIFT) ++#define KLE_NO_SYMTAB (KLE_SYM|1) ++#define KLE_NO_SYMBOLS (KLE_SYM|2) ++#define KLE_INVALID_TYPE (KLE_SYM|3) ++#define KLE_NO_MODULE_LIST (KLE_SYM|4) ++ ++/* kernel data error codes ++ */ ++#define KLE_KERN (KLEC_KERN << KLEC_CLASS_SHIFT) ++#define KLE_INVALID_KERNELSTACK (KLE_KERN|1) ++#define KLE_INVALID_STRUCT_SIZE (KLE_KERN|2) ++#define KLE_BEFORE_RAM_OFFSET (KLE_KERN|3) ++#define KLE_AFTER_MAXPFN (KLE_KERN|4) ++#define KLE_AFTER_PHYSMEM (KLE_KERN|5) ++#define KLE_AFTER_MAXMEM (KLE_KERN|6) ++#define KLE_PHYSMEM_NOT_INSTALLED (KLE_KERN|7) ++#define KLE_NO_DEFTASK (KLE_KERN|8) ++#define KLE_PID_NOT_FOUND (KLE_KERN|9) ++#define KLE_DEFTASK_NOT_ON_CPU (KLE_KERN|10) ++#define KLE_NO_CURCPU (KLE_KERN|11) ++#define KLE_NO_CPU (KLE_KERN|12) ++#define KLE_SIG_ERROR (KLE_KERN|13) ++#define KLE_TASK_RUNNING (KLE_KERN|14) ++#define KLE_NO_SWITCH_STACK (KLE_KERN|15) ++ ++/* Error codes that indicate what type of data was bad. These are ++ * placed in the upper 32-bits of klib_error. ++ */ ++#define KLE_BAD_TASK_STRUCT (((uint64_t)1)<<32) ++#define KLE_BAD_SYMNAME (((uint64_t)2)<<32) ++#define KLE_BAD_SYMADDR (((uint64_t)3)<<32) ++#define KLE_BAD_FUNCADDR (((uint64_t)4)<<32) ++#define KLE_BAD_STRUCT (((uint64_t)5)<<32) ++#define KLE_BAD_FIELD (((uint64_t)6)<<32) ++#define KLE_BAD_PC (((uint64_t)7)<<32) ++#define KLE_BAD_RA (((uint64_t)8)<<32) ++#define KLE_BAD_SP (((uint64_t)9)<<32) ++#define KLE_BAD_EP (((uint64_t)10)<<32) ++#define KLE_BAD_SADDR (((uint64_t)11)<<32) ++#define KLE_BAD_KERNELSTACK (((uint64_t)12)<<32) ++#define KLE_BAD_LINENO (((uint64_t)13)<<32) ++#define KLE_MAP_FILE (((uint64_t)14)<<32) ++#define KLE_DUMP (((uint64_t)15)<<32) ++#define KLE_BAD_STRING (((uint64_t)16)<<32) ++#define KLE_ELF_FILE (((uint64_t)17)<<32) ++ ++/* flags for function kl_msg() ++ * First 3 bits define trace levels. Minimum trace threshold is trace level 1. ++ * So maximal 7 trace levels are possible. We are using only KLE_TRACELEVEL_MAX. ++ * If no trace level bits are set, it is normal output. ++ */ ++#define _KLE_TRACEBIT1 0x00000001 /* trace bit 1 */ ++#define _KLE_TRACEBIT2 0x00000002 /* trace bit 2 */ ++#define _KLE_TRACEBIT3 0x00000004 /* trace bit 3 */ ++#define _KLE_TRACENUM 8 /* used in _KLE_TRACENUM */ ++#define _KLE_TRACEMASK (_KLE_TRACENUM-1) /* mask for trace bits */ ++/* further flags */ ++#define KLE_F_NOORIGIN 0x00001000 /* do not print origin for this msg */ ++#define KLE_F_ERRORMSG 0x00002000 /* treat message as error message */ ++/* trace levels := predefined combinations of trace bits */ ++#define KLE_F_TRACELEVEL1 (_KLE_TRACEBIT1) ++#define KLE_F_TRACELEVEL2 (_KLE_TRACEBIT2) ++#define KLE_F_TRACELEVEL3 (_KLE_TRACEBIT1|_KLE_TRACEBIT2) ++#define KLE_F_TRACELEVEL4 (_KLE_TRACEBIT3) ++#define KLE_TRACELEVELMAX 4 ++#define KLE_TRACELEVEL(flg) (flg & _KLE_TRACEMASK) ++#define KLE_GETTRACELEVEL(flg) \ ++ ((KLE_TRACELEVEL(flg) > KLE_TRACELEVELMAX) ? KLE_TRACELEVELMAX : \ ++ KLE_TRACELEVEL(flg)) ++ ++/* define debug components of libklib (64 components possible) ++ * used by kl_msg() ++ */ ++#define KL_DBGCOMP_ALLOC 0x0000000001 /* liballoc */ ++#define KL_DBGCOMP_BFD 0x0000000002 /* general bfd support */ ++#define KL_DBGCOMP_BTREE 0x0000000004 /* btree implementation */ ++#define KL_DBGCOMP_COMPRESS 0x0000000008 /* gzip/rle (de)compression */ ++#define KL_DBGCOMP_INIT 0x0000000010 /* klib initialization */ ++#define KL_DBGCOMP_MEMMAP 0x0000000020 /* memory mapping */ ++#define KL_DBGCOMP_MODULE 0x0000000040 /* kernel module handling */ ++#define KL_DBGCOMP_SIGNAL 0x0000000080 /* signal handling */ ++#define KL_DBGCOMP_STABS 0x0000000100 /* stabs format support */ ++#define KL_DBGCOMP_SYMBOL 0x0000000200 /* symbol handling */ ++#define KL_DBGCOMP_TYPE 0x0000000400 /* type information handling */ ++#define KL_DBGCOMP_ALL ((uint64_t) -1) /* all components */ ++ ++/* central output routine, shouldn't be used directly, but ++ * by following macros ++ */ ++void kl_msg(uint64_t, uint32_t, const char*, const char*, int, ++ const char*, ...); ++ ++/* vararg macros that should be used instead of kl_msg() ++ */ ++/* used within libklib to print non-error messages (e.g. progress indication) ++ */ ++#define KL_MSG(fmt, args...) \ ++kl_msg(0, 0, NULL, NULL, 0, fmt, ## args) ++/* Can be used by application to print error messages; ++ * not used by libklib itself. ++ */ ++#define kl_error(fmt, args...) \ ++kl_msg(0, KLE_F_ERRORMSG, __FUNCTION__, __FILE__, __LINE__, fmt, ## args) ++/* Generate trace messages. Used for libklib debugging. Might be used ++ * by an application, too. ++ * A macro _DBG_COMPONENT has to be defined locally in the module where ++ * any trace macro is used. See above debug components. ++ * Trace messages are only printed iff _DBG_COMPONENT was set before with a ++ * call to kl_set_dbg_component(). ++ */ ++#define kl_trace1(flg, fmt, args...) \ ++kl_msg(_DBG_COMPONENT, KLE_F_TRACELEVEL1|(flg), \ ++ __FUNCTION__, __FILE__, __LINE__, fmt, ## args) ++#define kl_trace2(flg, fmt, args...) \ ++kl_msg(_DBG_COMPONENT, KLE_F_TRACELEVEL2|(flg), \ ++ __FUNCTION__, __FILE__, __LINE__, fmt, ## args) ++#define kl_trace3(flg, fmt, args...) \ ++kl_msg(_DBG_COMPONENT, KLE_F_TRACELEVEL3|(flg), \ ++ __FUNCTION__, __FILE__, __LINE__, fmt, ## args) ++#define kl_trace4(flg, fmt, args...) \ ++kl_msg(_DBG_COMPONENT, KLE_F_TRACELEVEL4|(flg), \ ++ __FUNCTION__, __FILE__, __LINE__, fmt, ## args) ++ ++/* functions to set some global variables for libklib debugging ++ */ ++int kl_set_trace_threshold(uint32_t); ++void kl_set_dbg_component(uint64_t); ++void kl_set_stdout(FILE *); ++void kl_set_stderr(FILE *); ++ ++/* functions to get contents of global variables for libklib debugging ++ */ ++uint32_t kl_get_trace_threshold(void); ++uint64_t kl_get_dbg_component(void); ++ ++#endif /* __KL_ERROR_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_htnode.h +@@ -0,0 +1,71 @@ ++/* ++ * $Id: kl_htnode.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_HTNODE_H ++#define __KL_HTNODE_H ++ ++/* Node structure for use in hierarchical trees (htrees). ++ */ ++typedef struct htnode_s { ++ struct htnode_s *next; ++ struct htnode_s *prev; ++ struct htnode_s *parent; ++ struct htnode_s *children; ++ int seq; ++ int level; ++ int key; ++} htnode_t; ++ ++/* Flag values ++ */ ++#define HT_BEFORE 0x1 ++#define HT_AFTER 0x2 ++#define HT_CHILD 0x4 ++#define HT_PEER 0x8 ++ ++/* Function prototypes ++ */ ++htnode_t *kl_next_htnode( ++ htnode_t * /* htnode pointer */); ++ ++htnode_t *kl_prev_htnode( ++ htnode_t * /* htnode pointer */); ++ ++void ht_insert_peer( ++ htnode_t * /* htnode pointer */, ++ htnode_t * /* new htnode pointer*/, ++ int /* flags */); ++ ++void ht_insert_child( ++ htnode_t * /* htnode pointer */, ++ htnode_t * /* new htnode pointer*/, ++ int /* flags */); ++ ++int ht_insert( ++ htnode_t * /* htnode pointer */, ++ htnode_t * /* new htnode pointer*/, ++ int /* flags */); ++ ++void ht_insert_next_htnode( ++ htnode_t * /* htnode pointer */, ++ htnode_t * /* new htnode pointer*/); ++ ++#endif /* __KL_HTNODE_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_lib.h +@@ -0,0 +1,65 @@ ++/* ++ * $Id: kl_lib.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_LIB_H ++#define __KL_LIB_H ++ ++/* Include system header files ++ */ ++ ++#if 0 ++/* cpw: we don't need this userland stuff: */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++/* Include lkcd library header files ++ */ ++/* cpw: change these from the < > form to the " " form: */ ++#include "kl_types.h" ++#include "kl_alloc.h" ++#include "kl_libutil.h" ++#include "kl_btnode.h" ++#include "kl_htnode.h" ++#include "kl_queue.h" ++#include "kl_stringtab.h" ++ ++#endif /* __KL_LIB_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_libutil.h +@@ -0,0 +1,40 @@ ++/* ++ * $Id: kl_libutil.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2004 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_LIBUTIL_H ++#define __KL_LIBUTIL_H ++ ++/* cpw: change all these from the < > form to the " " form: */ ++#include "kl_alloc.h" ++#include "kl_btnode.h" ++#include "kl_copt.h" ++#include "kl_htnode.h" ++#include "kl_queue.h" ++#include "kl_stringtab.h" ++ ++int kl_shift_value(uint64_t ); ++int kl_string_compare(char *, char *); ++int kl_string_match(char *, char *); ++uint64_t kl_strtoull(char *, char **, int); ++time_t kl_str_to_ctime(char *); ++void *kl_get_ra(void); ++ ++#endif /* __KL_LIBUTIL_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_mem.h +@@ -0,0 +1,104 @@ ++/* ++ * $Id: kl_mem.h 1157 2005-02-25 22:04:05Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_MEM_H ++#define __KL_MEM_H ++ ++#if 0 ++cpw: skip: ++extern kaddr_t VMALLOC_START; ++extern kaddr_t VMALLOC_END; ++#endif ++ ++/* ++ * Function prototypes ++ */ ++ ++int kl_linux_release(void); ++ ++k_error_t kl_readmem( ++ kaddr_t /* physical address to start reading from */, ++ unsigned /* number of bytes to read */, ++ void * /* pointer to buffer */); ++ ++k_error_t kl_readkmem( ++ kaddr_t /* virtual address to start reading from */, ++ unsigned /* number of bytes to read */, ++ void * /* pointer to buffer */); ++ ++int kl_virtop( ++ kaddr_t /* virtual address to translate */, ++ void * /* pointer to mem_map for address translation */, ++ kaddr_t * /* pointer to physical address to return */); ++ ++k_error_t kl_get_block( ++ kaddr_t /* virtual address */, ++ unsigned /* size of block to read in */, ++ void * /* pointer to buffer */, ++ void * /* pointer to mmap */); ++ ++/* Wrapper that eliminates the mmap parameter ++ */ ++#define GET_BLOCK(a, s, b) kl_get_block(a, s, (void *)b, (void *)0) ++ ++uint64_t kl_uint( ++ void * /* pointer to buffer containing struct */, ++ char * /* name of struct */, ++ char * /* name of member */, ++ unsigned /* offset */); ++ ++int64_t kl_int( ++ void * /* pointer to buffer containing struct */, ++ char * /* name of struct */, ++ char * /* name of member */, ++ unsigned /* offset */); ++ ++kaddr_t kl_kaddr( ++ void * /* pointer to buffer containing struct */, ++ char * /* name of struct */, ++ char * /* name of member */); ++ ++/* XXX deprecated use KL_READ_PTR() instead */ ++kaddr_t kl_kaddr_to_ptr( ++ kaddr_t /* Address to dereference */); ++ ++int kl_is_valid_kaddr( ++ kaddr_t /* Address to test */, ++ void * /* pointer to mmap */, ++ int /* flags */); ++ ++/* REMIND: ++ * Likely not right for ia64 ++ */ ++#define KL_KADDR_IS_PHYSICAL(vaddr) ((vaddr >= KL_PAGE_OFFSET) && \ ++ (vaddr <= KL_HIGH_MEMORY)) ++ ++#define PGNO_TO_PADDR(pgno) (pgno << KL_PAGE_SHIFT) ++ ++/* ++ * declaration of some defaults that are used in kl_set_dumparch() ++ */ ++int kl_valid_physaddr(kaddr_t); ++int kl_valid_physmem(kaddr_t, int); ++kaddr_t kl_next_valid_physaddr(kaddr_t); ++kaddr_t kl_fix_vaddr(kaddr_t, size_t); ++int kl_init_virtop(void); ++ ++#endif /* __KL_MEM_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_mem_ia64.h +@@ -0,0 +1,149 @@ ++/* ++ * $Id: kl_mem_ia64.h 1250 2006-04-18 18:23:44Z cliffpwickman $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_MEM_IA64_H ++#define __KL_MEM_IA64_H ++ ++/* XXX - the following macros are used by functions in kl_page.c and in */ ++/* function kl_virtop, they still have to be defined properly, */ ++/* all the following macros have first to be set with correct values. */ ++/* I don't have a clue what values to use for ia64 architecture!!! */ ++ ++/* KSTACK_SIZE depends on page size (see kernel headers ptrace.h and page.h) ++ * #define IA64_STK_OFFSET ((1 << IA64_TASK_STRUCT_LOG_NUM_PAGES)*PAGE_SIZE) ++ * and ++ * #define PAGE_SIZE 1UL<= KL_HIGH_MEMORY))) ++ ++uint32_t dha_num_cpus_ia64(void); ++kaddr_t dha_current_task_ia64(int); ++int dha_cpuid_ia64(kaddr_t); ++kaddr_t dha_stack_ia64(int); ++kaddr_t dha_stack_ptr_ia64(int); ++kaddr_t kl_kernelstack_ia64(kaddr_t); ++kaddr_t kl_mmap_virtop_ia64(kaddr_t, void*); ++int kl_init_virtop_ia64(void); ++int kl_virtop_ia64(kaddr_t, void*, kaddr_t*); ++int kl_vtop_ia64(kaddr_t, kaddr_t*); ++int kl_valid_physmem_ia64(kaddr_t, int); ++kaddr_t kl_next_valid_physaddr_ia64(kaddr_t); ++kaddr_t kl_fix_vaddr_ia64(kaddr_t, size_t); ++ ++/* Structure containing key data for ia64 virtual memory mapping. ++ * Note that a number of fields are SN system specific. ++ */ ++typedef struct ia64_vminfo_s { ++ int flags; ++ kaddr_t vpernode_base; ++ kaddr_t vglobal_base; ++ kaddr_t to_phys_mask; ++ kaddr_t kernphysbase; ++ int nasid_shift; /* SN specific */ ++ int nasid_mask; /* SN specific */ ++} ia64_vminfo_t; ++ ++extern ia64_vminfo_t ia64_vminfo; ++ ++/* Some vminfo flags ++ */ ++#define MAPPED_KERN_FLAG 0x1 ++#define SN2_FLAG 0x2 ++ ++/* Some vminfo macros ++ */ ++#define IS_MAPPED_KERN (ia64_vminfo.flags & MAPPED_KERN_FLAG) ++#define IS_SN2 (ia64_vminfo.flags & SN2_FLAG) ++#define KL_VPERNODE_BASE ia64_vminfo.vpernode_base ++#define KL_VGLOBAL_BASE ia64_vminfo.vglobal_base ++#define KL_TO_PHYS_MASK ia64_vminfo.to_phys_mask ++#define KL_KERNPHYSBASE ia64_vminfo.kernphysbase ++#define KL_NASID_SHIFT ia64_vminfo.nasid_shift ++#define KL_NASID_MASK ia64_vminfo.nasid_mask ++ ++#define ADDR_TO_NASID(A) (((A) >> (long)(KL_NASID_SHIFT)) & KL_NASID_MASK) ++ ++#endif /* __KL_MEM_IA64_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_module.h +@@ -0,0 +1,69 @@ ++/* ++ * $Id: kl_module.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_MODULE_H ++#define __KL_MODULE_H ++ ++/* ++ * insmod generates ksymoops ++ * ++ */ ++ ++typedef struct kl_modinfo_s { ++ char *modname; /* name of module as loaded in dump */ ++ /* store ksym info for all modules in a linked list */ ++ struct kl_modinfo_s *next; ++ char *object_file; /* name of file that module was loaded from*/ ++ /* ? possibly store modtime and version here ? */ ++ uint64_t header; /* address of module header */ ++ uint64_t mtime; /* time of last modification of object_file */ ++ uint32_t version; /* kernel version that module was compiled for */ ++ uint64_t text_sec; /* address of text section */ ++ uint64_t text_len; /* length of text section */ ++ uint64_t data_sec; /* address of data section */ ++ uint64_t data_len; /* length of data section */ ++ uint64_t rodata_sec; /* address of rodata section */ ++ uint64_t rodata_len; /* length of rodata section */ ++ uint64_t bss_sec; /* address of rodata section */ ++ uint64_t bss_len; /* length of rodata section */ ++ char *ksym_object; /* ksym for object */ ++ char *ksym_text_sec; /* ksym for its text section */ ++ char *ksym_data_sec; /* ksym for its data section */ ++ char *ksym_rodata_sec; /* ksym for its rodata section */ ++ char *ksym_bss_sec; /* ksym for its bss sectio */ ++} kl_modinfo_t; ++ ++int kl_get_module(char*, kaddr_t*, void**); ++int kl_get_module_2_6(char*, kaddr_t*, void**); ++int kl_get_modname(char**, void*); ++int kl_new_get_modname(char**, void*); ++void kl_free_modinfo(kl_modinfo_t**); ++int kl_new_modinfo(kl_modinfo_t**, void*); ++int kl_set_modinfo(kaddr_t, char*, kl_modinfo_t*); ++int kl_complete_modinfo(kl_modinfo_t*); ++int kl_load_ksyms(int); ++int kl_load_ksyms_2_6(int); ++int kl_unload_ksyms(void); ++int kl_load_module_sym(char*, char*, char*); ++int kl_unload_module_sym(char*); ++int kl_autoload_module_info(char*); ++kl_modinfo_t * kl_lkup_modinfo(char*); ++ ++#endif /* __KL_MODULE_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_queue.h +@@ -0,0 +1,89 @@ ++/* ++ * $Id: kl_queue.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_QUEUE_H ++#define __KL_QUEUE_H ++ ++/* List element header ++ */ ++typedef struct element_s { ++ struct element_s *next; ++ struct element_s *prev; ++} element_t; ++ ++/* Some useful macros ++ */ ++#define ENQUEUE(list, elem) \ ++ kl_enqueue((element_t **)list, (element_t *)elem) ++#define DEQUEUE(list) kl_dequeue((element_t **)list) ++#define FINDQUEUE(list, elem) \ ++ kl_findqueue((element_t **)list, (element_t *)elem) ++#define REMQUEUE(list, elem) kl_remqueue((element_t **)list, (element_t *)elem) ++ ++typedef struct list_of_ptrs { ++ element_t elem; ++ unsigned long long val64; ++} list_of_ptrs_t; ++ ++#define FINDLIST_QUEUE(list, elem, compare) \ ++ kl_findlist_queue((list_of_ptrs_t **)list, \ ++ (list_of_ptrs_t *)elem, compare) ++ ++/** ++ ** Function prototypes ++ **/ ++ ++/* Add a new element to the tail of a doubly linked list. ++ */ ++void kl_enqueue( ++ element_t** /* ptr to head of list */, ++ element_t* /* ptr to element to add to the list */); ++ ++/* Remove an element from the head of a doubly linked list. A pointer ++ * to the element will be returned. In the event that the list is ++ * empty, a NULL pointer will be returned. ++ */ ++element_t *kl_dequeue( ++ element_t** /* ptr to list head (first item removed) */); ++ ++/* Checks to see if a particular element is in a list. If it is, a ++ * value of one (1) will be returned. Otherwise, a value of zero (0) ++ * will be returned. ++ */ ++int kl_findqueue( ++ element_t** /* ptr to head of list */, ++ element_t* /* ptr to element to find on list */); ++ ++/* Walks through a list of pointers to queues and looks for a ++ * particular list. ++ */ ++int kl_findlist_queue( ++ list_of_ptrs_t** /* ptr to list of lists */, ++ list_of_ptrs_t* /* ptr to list to look for */, ++ int(*)(void *, void *) /* ptr to compare function */); ++ ++/* Remove specified element from doubly linked list. ++ */ ++void kl_remqueue( ++ element_t** /* ptr to head of list */, ++ element_t* /* ptr to element to remove from list */); ++ ++#endif /* __KL_QUEUE_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_stabs.h +@@ -0,0 +1,122 @@ ++/* ++ * $Id: kl_stabs.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2004 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_STABS_H ++#define __KL_STABS_H ++ ++/* STABS specific types ++ */ ++#define STAB_XSTRUCT 100 /* Cross referense to STAB_STRUCT */ ++#define STAB_XUNION 101 /* Cross referense to STAB_UNIONB */ ++#define STAB_XENUM 102 /* Cross referense to STAB_ENUM */ ++ ++/* Structure allocated for every namelist. A namelist can be either an ++ * object file (.o or executible), or it can be an archive (.a). ++ */ ++typedef struct st_nmlist_s { ++ char *sts_filename; /* disk file name */ ++ short sts_type; /* ST_OBJ or ST_AR */ ++ short sts_nfiles; /* number of source/object files */ ++} st_nmlist_t; ++ ++/* Values for type field ++ */ ++#define ST_OBJ 1 /* object file (.o or executible) */ ++#define ST_AR 2 /* archive */ ++ ++/* Stab entry type Flags. For determining which stab entries to ++ * capture from the symbol table. ++ */ ++#define ST_UNDF 0x0001 ++#define ST_SO 0x0002 ++#define ST_LSYM 0x0004 ++#define ST_GSYM 0x0008 ++#define ST_PSYM 0x0010 ++#define ST_STSYM 0x0020 ++#define ST_LCSYM 0x0040 ++#define ST_FUN 0x0080 ++#define ST_BINCL 0x0100 ++#define ST_EINCL 0x0200 ++#define ST_EXCL 0x0400 ++#define ST_SLINE 0x0800 ++#define ST_RSYM 0x2000 ++#define ST_ALL 0xffff ++#define ST_DEFAULT (ST_LSYM|ST_GSYM|ST_FUN) ++ ++#define N_UNDF 0 ++ ++/* Structures that allow us to selectively cycle through only those BFD ++ * sections containing STAB data. ++ */ ++typedef struct stab_sect_s { ++ char *stabsect_name; ++ char *strsect_name; ++} stab_sect_t; ++ ++/* Local structure that contains the current type string (which may be ++ * just a part of the complete type defenition string) and the character ++ * index (current) pointer. ++ */ ++typedef struct stab_str_s { ++ char *str; ++ char *ptr; ++} stab_str_t; ++ ++/* Local structure containing global values that allow us to cycle ++ * through multiple object files without reinitializing. ++ */ ++typedef struct st_global_s { ++ bfd *abfd; /* current bfd pointer */ ++ int type; /* symbol entry type */ ++ int flags; /* want flags */ ++ int flag; /* current ST flag */ ++ int nmlist; /* current namelist index */ ++ int srcfile; /* current source file number */ ++ int incfile; /* current include file */ ++ int symnum; /* symbol entry number */ ++ bfd_byte *stabp; /* beg of current string table */ ++ bfd_byte *stabs_end; /* end of current string table */ ++ int staboff; /* current stab table offset */ ++ unsigned int value; /* value (e.g., function addr) */ ++ int stroffset; /* offset in stab string table */ ++ short desc; /* desc value (e.g, line number) */ ++ stab_str_t stab_str; /* current stab string */ ++} st_global_t; ++ ++/* Macros for accessing the current global values ++ */ ++#define G_abfd G_values.abfd ++#define G_type G_values.type ++#define G_flags G_values.flags ++#define G_flag G_values.flag ++#define G_nmlist G_values.nmlist ++#define G_srcfile G_values.srcfile ++#define G_incfile G_values.incfile ++#define G_symnum G_values.symnum ++#define G_stabp G_values.stabp ++#define G_stabs_end G_values.stabs_end ++#define G_staboff G_values.staboff ++#define G_value G_values.value ++#define G_stroffset G_values.stroffset ++#define G_desc G_values.desc ++#define G_stab_str G_values.stab_str ++#define CUR_CHAR G_stab_str.ptr ++ ++#endif /* __KL_STABS_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_stringtab.h +@@ -0,0 +1,68 @@ ++/* ++ * $Id: kl_stringtab.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libutil. ++ * A library which provides auxiliary functions. ++ * libutil is part of lkcdutils -- utilities for Linux kernel crash dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_STRINGTAB_H ++#define __KL_STRINGTAB_H ++ ++/* The string table structure ++ * ++ * String space is allocated from 4K blocks which are allocated ++ * as needed. The first four bytes of each block are reserved so ++ * that the blocks can be chained together (to make it easy to free ++ * them when the string table is no longer necessary). ++ */ ++typedef struct string_table_s { ++ int num_strings; ++ void *block_list; ++} string_table_t; ++ ++#define NO_STRINGTAB 0 ++#define USE_STRINGTAB 1 ++ ++/** ++ ** Function prototypes ++ **/ ++ ++/* Initialize a string table. Depending on the value of the flag ++ * parameter, either temporary or permenent blocks will be used. ++ * Upon success, a pointer to a string table will be returned. ++ * Otherwise, a NULL pointer will be returned. ++ */ ++string_table_t *kl_init_string_table( ++ int /* flag (K_TEMP/K_PERM)*/); ++ ++/* Free all memory blocks allocated for a particular string table ++ * and then free the table itself. ++ */ ++void kl_free_string_table( ++ string_table_t* /* pointer to string table */); ++ ++/* Search for a string in a string table. If the string does not ++ * exist, allocate space from the string table and add the string. ++ * In either event, a pointer to the string (from the table) will ++ * be returned. ++ */ ++char *kl_get_string( ++ string_table_t* /* pointer to string table */, ++ char* /* string to get/add from/to string table */, ++ int /* flag (K_TEMP/K_PERM)*/); ++ ++#endif /* __KL_STRINGTAB_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_sym.h +@@ -0,0 +1,131 @@ ++/* ++ * $Id: kl_sym.h 1233 2005-09-10 08:01:11Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_SYM_H ++#define __KL_SYM_H ++ ++/* The syment struct contains information about kernel symbols (text, ++ * data, etc.). The first field in syment_t is a btnode_s sruct. This ++ * allows the generic binary search tree routines, insert_tnode() and ++ * find_tnode(), to be used. ++ */ ++typedef struct syment_s { ++ btnode_t s_bt; /* Must be first */ ++ struct syment_s *s_next; /* For linked lists */ ++ struct syment_s *s_prev; /* For linked lists */ ++ kaddr_t s_addr; /* vaddr of symbol */ ++ kaddr_t s_end; /* end address of symbol */ ++ int s_type; /* text, data */ ++ struct syment_s *s_forward; /* For linked lists */ ++} syment_t; ++ ++#define s_name s_bt.bt_key ++ ++#define SYM_GLOBAL_TEXT 1 ++#define SYM_LOCAL_TEXT 2 ++#define SYM_LOCORE_TEXT 3 ++#define SYM_GLOBAL_DATA 4 ++#define SYM_LOCAL_DATA 5 ++#define SYM_ABS 6 ++#define SYM_UNK 9 ++#define SYM_KSYM 10 ++#define SYM_KSYM_TEXT 11 ++#define SYM_KALLSYMS 12 ++ ++#define SYM_MAP_ANY 0 ++#define SYM_MAP_FILE 1 ++#define SYM_MAP_KSYM 2 ++#define SYM_MAP_MODULE 3 ++#define SYM_MAP_KALLSYMS 4 ++ ++#define KL_KERNEL_MODULE "kernel_module" ++#define KL_S_BSS ".bss.start" ++#define KL_E_BSS ".bss.end" ++#define KL_S_DATA ".data.start" ++#define KL_E_DATA ".data.end" ++#define KL_S_RODATA ".rodata.start" ++#define KL_E_RODATA ".rodata.end" ++#define KL_S_TEXT ".text.start" ++#define KL_E_TEXT ".text.end" ++#define KL_SYM_END "__end__" ++ ++ ++#define KL_SYMBOL_NAME_LEN 256 ++ ++/* ++ * Struct containing symbol table information ++ */ ++typedef struct symtab_s { ++ int symcnt; /* Number of symbols */ ++ int symaddrcnt; /* Number of symbol addrs to track */ ++ syment_t **symaddrs; /* Table of symbols by address */ ++ btnode_t *symnames; /* tree of symbols by name */ ++ syment_t *text_list; /* Linked list of text symbols */ ++ syment_t *data_list; /* Linked list of data symbols */ ++} symtab_t; ++ ++ ++/* support of further mapfiles besides System.map */ ++typedef struct maplist_s { ++ struct maplist_s *next; ++ int maplist_type; /* type of maplist */ ++ char *mapfile; /* name of mapfile */ ++ char *modname; /* set if map belongs to a module */ ++ symtab_t *syminfo; ++} maplist_t; ++ ++ ++/* API Function prototypes ++ */ ++int kl_read_syminfo(maplist_t*); ++int kl_free_syminfo(char*); ++void kl_free_symtab(symtab_t*); ++void kl_free_syment_list(syment_t*); ++void kl_free_maplist(maplist_t*); ++syment_t *kl_get_similar_name(char*, char*, int*, int*); ++syment_t *kl_lkup_symname(char*); ++syment_t *_kl_lkup_symname(char*, int, size_t len); ++#define KL_LKUP_SYMNAME(NAME, TYPE, LEN) _kl_lkup_symname(NAME, TYPE, LEN) ++syment_t *kl_lkup_funcaddr(kaddr_t); ++syment_t *kl_lkup_symaddr(kaddr_t); ++syment_t *kl_lkup_symaddr_text(kaddr_t); ++syment_t *_kl_lkup_symaddr(kaddr_t, int); ++#define KL_LKUP_SYMADDR(KADDR, TYPE) _kl_lkup_symaddr(KADDR, TYPE) ++kaddr_t kl_symaddr(char * /* symbol name */); ++kaddr_t kl_symptr(char * /* symbol name */); ++kaddr_t kl_funcaddr(kaddr_t /* pc value */); ++char *kl_funcname(kaddr_t /* pc value */); ++int kl_funcsize(kaddr_t /* pc value */); ++int kl_symsize(syment_t*); ++syment_t *kl_alloc_syment(kaddr_t, kaddr_t, int, const char*); ++void kl_insert_symbols(symtab_t*, syment_t*); ++int kl_insert_artificial_symbols(symtab_t*, syment_t**, kl_modinfo_t*); ++int kl_convert_symbol(kaddr_t*, int*, char, kl_modinfo_t*); ++int kl_load_sym(char*); ++int kl_print_symtables(char*, char*, int, int); ++void kl_print_symbol(kaddr_t, syment_t*, int); ++ ++/* flag for use by kl_print_symbol() and kl_print_syminfo() ++ */ ++#define KL_SYMWOFFSET (0x01) /* with offset field */ ++#define KL_SYMFULL (0x02) /* print detailed syminfo */ ++#define KL_SYMBYNAME (0x04) /* print symbol sorted by name */ ++ ++#endif /* __KL_SYM_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_task.h +@@ -0,0 +1,39 @@ ++/* ++ * $Id: kl_task.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002, 2004 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_TASK_H ++#define __KL_TASK_H ++ ++extern kaddr_t deftask; ++ ++/* Function prototypes ++ */ ++k_error_t kl_set_deftask(kaddr_t); ++int kl_parent_pid(void *); ++kaddr_t kl_pid_to_task(kaddr_t); ++k_error_t kl_get_task_struct(kaddr_t, int, void *); ++kaddr_t kl_kernelstack(kaddr_t); ++kaddr_t kl_first_task(void); ++kaddr_t kl_next_task(void *); ++kaddr_t kl_prev_task(void *); ++kaddr_t kl_pid_to_task(kaddr_t); ++int kl_task_size(kaddr_t); ++ ++#endif /* __KL_TASK_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_typeinfo.h +@@ -0,0 +1,199 @@ ++/* ++ * $Id: kl_typeinfo.h 1259 2006-04-25 18:33:20Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2006 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_TYPEINFO_H ++#define __KL_TYPEINFO_H ++ ++#define KLT_BASE 0x001 ++#define KLT_STRUCT 0x002 ++#define KLT_UNION 0x004 ++#define KLT_ENUMERATION 0x008 ++#define KLT_MEMBER 0x010 ++#define KLT_ARRAY 0x020 ++#define KLT_POINTER 0x040 ++#define KLT_TYPEDEF 0x080 ++#define KLT_FUNCTION 0x100 ++#define KLT_VARIABLE 0x200 ++#define KLT_SRCFILE 0x400 ++#define KLT_SUBRANGE 0x800 ++#define KLT_INCOMPLETE 0x4000 ++#define KLT_UNKNOWN 0x8000 ++#define KLT_TYPE (KLT_BASE|KLT_STRUCT|KLT_UNION|KLT_ENUMERATION) ++#define KLT_TYPES (KLT_BASE|KLT_STRUCT|KLT_UNION|KLT_ENUMERATION|KLT_TYPEDEF) ++ ++#define IS_TYPE(T) ((T) & KLT_TYPE) ++#define IS_STRUCT(T) ((T) & KLT_STRUCT) ++#define IS_UNION(T) ((T) & KLT_UNION) ++#define IS_ENUM(T) ((T) & KLT_ENUM) ++#define IS_MEMBER(T) ((T) & KLT_MEMBER) ++#define IS_POINTER(T) ((T) & KLT_POINTER) ++#define IS_TYPEDEF(T) ((T) & KLT_TYPEDEF) ++ ++#define TYP_SETUP_FLG 0x01 ++#define TYP_TYPESTRING_FLG 0x02 ++#define TYP_INCOMPLETE_FLG 0x04 ++#define TYP_XREFERENCE_FLG 0x08 ++#define TYP_ANONYMOUS_FLG 0x10 /* Denotes anonymous union or struct */ ++ ++#define NO_INDENT 0x01000000 ++#define SUPPRESS_NAME 0x02000000 ++#define SUPPRESS_NL 0x04000000 ++#define SUPPRESS_SEMI_COLON 0x08000000 ++#define NO_REALTYPE 0x10000000 ++ ++extern int numnmlist; ++ ++#define KL_TYPEINFO() (numnmlist) ++ ++typedef struct kltype_s { ++ char *kl_name; /* type name */ ++ char *kl_typestr; /* 'typecast' string */ ++ void *kl_ptr; /* ptr to arch typeinfo */ ++ int kl_flags; /* (e.g., STAB_FLG) */ ++ int kl_type; /* (e.g., KLT_TYPEDEF) */ ++ int kl_offset; /* offset to 1st byte */ ++ int kl_size; /* number of bytes */ ++ int kl_bit_offset; /* offset to 1st data bit */ ++ int kl_bit_size; /* total num of data bits */ ++ int kl_encoding; /* for base value types */ ++ int kl_low_bounds; /* for arrays */ ++ int kl_high_bounds; /* for arrays */ ++ unsigned int kl_value; /* enum value, etc. */ ++ struct kltype_s *kl_member; /* struct/union member list */ ++ struct kltype_s *kl_next; /* hash lists, etc. */ ++ struct kltype_s *kl_realtype; /* pointer to real type */ ++ struct kltype_s *kl_indextype; /* pointer to index_type */ ++ struct kltype_s *kl_elementtype; /* pointer to element_type */ ++} kltype_t; ++ ++/* Flag values ++ */ ++#define K_HEX 0x1 ++#define K_OCTAL 0x2 ++#define K_BINARY 0x4 ++#define K_NO_SWAP 0x8 ++ ++/* Base type encoding values ++ */ ++#define ENC_CHAR 0x01 ++#define ENC_SIGNED 0x02 ++#define ENC_UNSIGNED 0x04 ++#define ENC_FLOAT 0x08 ++#define ENC_ADDRESS 0x10 ++#define ENC_UNDEFINED 0x20 ++ ++/* Maximum number of open namelists ++ */ ++#define MAXNMLIST 10 ++ ++typedef struct nmlist_s { ++ int index; ++ char *namelist; ++ void *private; /* pointer to private control struct */ ++ string_table_t *stringtab; ++} nmlist_t; ++ ++extern nmlist_t nmlist[]; ++extern int numnmlist; ++extern int curnmlist; ++ ++#define KL_TYPESTR_STRUCT "struct" ++#define KL_TYPESTR_UNION "union" ++#define KL_TYPESTR_ENUM "enum" ++#define KL_TYPESTR_VOID "void" ++ ++/* Function prototypes ++ */ ++kltype_t *kl_find_type( ++ char * /* type name */, ++ int /* type number */); ++ ++kltype_t *kl_find_next_type( ++ kltype_t * /* kltype_t pointer */, ++ int /* type number */); ++ ++kltype_t *kl_first_type( ++ int /* type number */); ++ ++kltype_t *kl_next_type( ++ kltype_t * /* kltype_t pointer */); ++ ++kltype_t *kl_prev_type( ++ kltype_t * /* kltype_t pointer */); ++ ++kltype_t *kl_realtype( ++ kltype_t * /* kltype_t pointer */, ++ int /* type number */); ++ ++kltype_t *kl_find_typenum( ++ uint64_t /* private typenumber */); ++ ++int kl_get_first_similar_typedef( ++ char * /* type name */, ++ char * /* fullname */); ++ ++int kl_type_size( ++ kltype_t * /* kltype_t pointer */); ++ ++int kl_struct_len( ++ char * /* struct name */); ++ ++kltype_t *kl_get_member( ++ kltype_t * /* kltype_t pointer */, ++ char * /* member name */); ++ ++int kl_get_member_offset( ++ kltype_t * /* kltype_t pointer */, ++ char * /* member name */); ++ ++int kl_is_member( ++ char * /* struct name */, ++ char * /* member name */); ++ ++kltype_t *kl_member( ++ char * /* struct name */, ++ char * /* member name */); ++ ++int kl_member_offset( ++ char * /* struct name */, ++ char * /* member name */); ++ ++int kl_member_size( ++ char * /* struct name */, ++ char * /* member name */); ++ ++/* cpw: get rid of last arguent FILE * */ ++void kl_print_member(void *, kltype_t *, int, int); ++void kl_print_pointer_type(void *, kltype_t *, int, int); ++void kl_print_function_type(void *, kltype_t *, int, int); ++void kl_print_array_type(void *, kltype_t *, int, int); ++void kl_print_enumeration_type(void *, kltype_t *, int, int); ++void kl_print_base_type(void *, kltype_t *, int, int); ++void kl_print_type(void *, kltype_t *, int, int); ++void kl_print_struct_type(void *, kltype_t *, int, int); ++void kl_print_base_value(void *, kltype_t *, int); ++ ++void kl_print_type( ++ void * /* pointer to data */, ++ kltype_t * /* pointer to type information */, ++ int /* indent level */, ++ int /* flags */); ++ ++#endif /* __KL_TYPEINFO_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/kl_types.h +@@ -0,0 +1,54 @@ ++/* ++ * $Id: kl_types.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __KL_TYPES_H ++#define __KL_TYPES_H ++ ++/* The following typedef should be used for variables or return values ++ * that contain kernel virtual or physical addresses. It should be sized ++ * such that it can hold both pointers of 64 bit architectures as well as ++ * pointers from 32 bit architectures. ++ */ ++typedef unsigned long kaddr_t; ++ ++/* The following typedef should be used when converting a pointer value ++ * (either kernel or application) to an unsigned value for pointer ++ * calculations. ++ */ ++typedef unsigned long uaddr_t; ++ ++/* KLIB error type ++ */ ++typedef uint64_t k_error_t; ++ ++/* Typedef that allows a single fprintf() call to work for both ++ * 32-bit and 64-bit pointer values. ++ */ ++#define UADDR(X) ((kaddr_t)X) ++#define UADDR64(X) ((kaddr_t)X)) ++/* #define UADDR(X) ((uaddr_t)X) */ ++/* #define UADDR64(X) ((uint64_t)((uaddr_t)X)) */ ++ ++ ++/* cpw */ ++/* was: #include */ ++#include "asm/kl_types.h" ++ ++#endif /* __KL_TYPES_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/klib.h +@@ -0,0 +1,480 @@ ++/* ++ * $Id: klib.h 1336 2006-10-23 23:27:06Z tjm $ ++ * ++ * This file is part of libklib. ++ * A library which provides access to Linux system kernel dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, NEC, and others ++ * ++ * Copyright (C) 1999 - 2005 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * Copyright 2000 Junichi Nomura, NEC Solutions ++ * ++ * This code is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. See the file COPYING for more ++ * information. ++ */ ++ ++/* ++ * klib.h -- Interface of the klib library, a library for access to ++ * Linux system memory dumps. ++ */ ++ ++#ifndef __KLIB_H ++#define __KLIB_H ++ ++/* Include header files ++ */ ++#if 0 ++ /* cpw: don't include all this: */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++/* cpw: change all the below includes form the < > form to " " */ ++ ++/* Include libutil header ++ */ ++#include "kl_lib.h" ++ ++/* Include libklib header files ++ */ ++#include "kl_types.h" ++#include "kl_error.h" ++#include "kl_dump.h" ++#include "kl_mem.h" ++#include "kl_cmp.h" ++#include "kl_typeinfo.h" ++#include "kl_module.h" ++#include "kl_sym.h" ++#include "kl_bfd.h" ++#include "kl_debug.h" ++#include "kl_stabs.h" ++#include "kl_dwarfs.h" ++#include "kl_task.h" ++#include "kl_dump_arch.h" ++ ++ ++#ifndef TRUE ++# define TRUE 1 ++#endif ++#ifndef FALSE ++# define FALSE 0 ++#endif ++ ++#ifndef MIN ++#define MIN(x,y) (((x)<(y))?(x):(y)) ++#endif ++#ifndef MAX ++#define MAX(x,y) (((x)>(y))?(x):(y)) ++#endif ++ ++#define KL_NR_CPUS 128 ++ ++/* We have to distinc between HOST_ARCH_* and DUMP_ARCH_*. These two classes of ++ * macros are used througout the code for conditional compilation. ++ * Additional we have following macros for comparison and switch statements. ++ */ ++#define KL_ARCH_UNKNOWN 0 ++#define KL_ARCH_ALPHA 1 ++#define KL_ARCH_ARM 2 ++#define KL_ARCH_I386 3 ++#define KL_ARCH_IA64 4 ++#define KL_ARCH_M68K 5 ++#define KL_ARCH_MIPS 6 ++#define KL_ARCH_MIPS64 7 ++#define KL_ARCH_PPC 8 ++#define KL_ARCH_S390 9 ++#define KL_ARCH_SH 10 ++#define KL_ARCH_SPARK 11 ++#define KL_ARCH_SPARK64 12 ++#define KL_ARCH_S390X 13 ++#define KL_ARCH_PPC64 14 ++#define KL_ARCH_X86_64 15 ++#define KL_ARCH_IA64_SN2 16 ++#define KL_ARCH_IA64_DIG 17 ++#define KL_ARCH_IA64_HPSIM 18 ++#define KL_ARCH_IA64_HPZX1 19 ++#define KL_ARCH_S390SA 20 ++ ++#define KL_LIVE_SYSTEM 1000 ++ ++#define ARCH_IS_IA64(A) \ ++ ((A==KL_ARCH_IA64)|| \ ++ (A==KL_ARCH_IA64_SN2)|| \ ++ (A==KL_ARCH_IA64_DIG)|| \ ++ (A==KL_ARCH_IA64_HPSIM)|| \ ++ (A==KL_ARCH_IA64_HPZX1)) ++ ++#ifdef HOST_ARCH_ALPHA ++# define KL_HOST_ARCH KL_ARCH_ALPHA ++#endif ++#ifdef HOST_ARCH_ARM ++# define KL_HOST_ARCH KL_ARCH_ARM ++#endif ++#ifdef HOST_ARCH_I386 ++# define KL_HOST_ARCH KL_ARCH_I386 ++#endif ++#ifdef HOST_ARCH_IA64 ++# define KL_HOST_ARCH KL_ARCH_IA64 ++#endif ++#ifdef HOST_ARCH_S390 ++# define KL_HOST_ARCH KL_ARCH_S390 ++#endif ++#ifdef HOST_ARCH_S390X ++# define KL_HOST_ARCH KL_ARCH_S390X ++#endif ++#ifdef HOST_ARCH_PPC64 ++#define KL_HOST_ARCH KL_ARCH_PPC64 ++#endif ++#ifdef HOST_ARCH_X86_64 ++#define KL_HOST_ARCH KL_ARCH_X86_64 ++#endif ++ ++#define KL_ARCH_STR_ALPHA "alpha" ++#define KL_ARCH_STR_ARM "arm" ++#define KL_ARCH_STR_I386 "i386" ++#define KL_ARCH_STR_IA64 "ia64" ++#define KL_ARCH_STR_S390 "s390" ++#define KL_ARCH_STR_S390X "s390x" ++#define KL_ARCH_STR_PPC64 "ppc64" ++#define KL_ARCH_STR_X86_64 "x86_64" ++#define KL_ARCH_STR_IA64_SN2 "sn2" ++#define KL_ARCH_STR_UNKNOWN "unknown" ++ ++/* for endianess of dump and host arch ++ */ ++#define KL_UNKNOWN_ENDIAN 0x00 ++#define KL_LITTLE_ENDIAN 0x01 ++#define KL_BIG_ENDIAN 0x02 ++ ++/* macros for handling of different Kernel versions ++ */ ++#define LINUX_2_2_X(R) (((R) & 0xffff00) == 0x020200) ++#define LINUX_2_2_16 0x020210 ++#define LINUX_2_2_17 0x020211 ++#define LINUX_2_4_X(R) (((R) & 0xffff00) == 0x020400) ++#define LINUX_2_4_0 0x020400 ++#define LINUX_2_4_4 0x020404 ++#define LINUX_2_4_15 0x02040f ++#define LINUX_2_6_X(R) (((R) & 0xffff00) == 0x020600) ++#define LINUX_2_6_0 0x020600 ++ ++/* libklib flags ++ */ ++#define KL_FAILSAFE_FLG 0x0001 ++#define KL_NOVERIFY_FLG 0x0002 ++#define KL_SILENT_FLG 0x0004 ++#define KL_SAVETYPES_FLG 0x0008 ++#define KL_USETYPES_FLG 0x0010 ++ ++/* macros for backward compatibility ++ */ ++#define NUM_PHYSPAGES KLP->dump->mem.num_physpages ++#define MEM_MAP KLP->dump->mem.mem_map ++#define KL_HIGH_MEMORY KLP->dump->mem.high_memory ++#define KL_INIT_MM KLP->dump->mem.init_mm ++#define KL_NUM_CPUS KLP->dump->mem.num_cpus ++#define KL_PGDAT_LIST KLP->dump->mem.pgdat_list ++ ++/* macros for better use of dump architecture dependent functions ++ */ ++ ++/* read integer value from buffer */ ++#define KL_GET_PTR(ptr) (*KLP->dump->func.get_ptr)(ptr) ++#define KL_GET_LONG(ptr) ((int64_t) KL_GET_PTR(ptr)) ++#define KL_GET_ULONG(ptr) KL_GET_PTR(ptr) ++#define KL_GET_UINT8(ptr) (*KLP->dump->func.get_uint8)(ptr) ++#define KL_GET_UINT16(ptr) (*KLP->dump->func.get_uint16)(ptr) ++#define KL_GET_UINT32(ptr) (*KLP->dump->func.get_uint32)(ptr) ++#define KL_GET_UINT64(ptr) (*KLP->dump->func.get_uint64)(ptr) ++#define KL_GET_INT8(ptr) ((int8_t) KL_GET_UINT8(ptr)) ++#define KL_GET_INT16(ptr) ((int16_t) KL_GET_UINT16(ptr)) ++#define KL_GET_INT32(ptr) ((int32_t) KL_GET_UINT32(ptr)) ++#define KL_GET_INT64(ptr) ((int64_t) KL_GET_UINT64(ptr)) ++ ++/* read integer value from dump (without address mapping) ++ * Use these functions sparsely, e.g. before address translation ++ * is properly set up. ++ */ ++#define KL_READ_PTR(addr) (*KLP->dump->func.read_ptr)(addr) ++#define KL_READ_LONG(addr) ((int64_t) KL_READ_PTR(addr)) ++#define KL_READ_ULONG(addr) KL_READ_PTR(addr) ++#define KL_READ_UINT8(addr) (*KLP->dump->func.read_uint8)(addr) ++#define KL_READ_UINT16(addr) (*KLP->dump->func.read_uint16)(addr) ++#define KL_READ_UINT32(addr) (*KLP->dump->func.read_uint32)(addr) ++#define KL_READ_UINT64(addr) (*KLP->dump->func.read_uint64)(addr) ++#define KL_READ_INT8(addr) ((int8_t) KL_READ_UINT8(addr)) ++#define KL_READ_INT16(addr) ((int16_t) KL_READ_UINT16(addr)) ++#define KL_READ_INT32(addr) ((int32_t) KL_READ_UINT32(addr)) ++#define KL_READ_INT64(addr) ((int64_t) KL_READ_UINT64(addr)) ++ ++/* read integer value from dump (from virtual address) doing address mapping */ ++#define KL_VREAD_PTR(addr) (*KLP->dump->func.vread_ptr)(addr) ++#define KL_VREAD_LONG(addr) ((int64_t) KL_VREAD_PTR(addr)) ++#define KL_VREAD_ULONG(addr) KL_VREAD_PTR(addr) ++#define KL_VREAD_UINT8(addr) (*KLP->dump->func.vread_uint8)(addr) ++#define KL_VREAD_UINT16(addr) (*KLP->dump->func.vread_uint16)(addr) ++#define KL_VREAD_UINT32(addr) (*KLP->dump->func.vread_uint32)(addr) ++#define KL_VREAD_UINT64(addr) (*KLP->dump->func.vread_uint64)(addr) ++#define KL_VREAD_INT8(addr) ((int8_t) KL_VREAD_UINT8(addr)) ++#define KL_VREAD_INT16(addr) ((int16_t) KL_VREAD_UINT16(addr)) ++#define KL_VREAD_INT32(addr) ((int32_t) KL_VREAD_UINT32(addr)) ++#define KL_VREAD_INT64(addr) ((int64_t) KL_VREAD_UINT64(addr)) ++ ++/* determine start of stack */ ++#define KL_KERNELSTACK_UINT64 (*KLP->dump->arch.kernelstack) ++/* map virtual adress to physical one */ ++#define KL_VIRTOP (*KLP->dump->arch.virtop) ++/* travers page table */ ++#define KL_MMAP_VIRTOP (*KLP->dump->arch.mmap_virtop) ++/* check whether address points to valid physical memory */ ++#define KL_VALID_PHYSMEM (*KLP->dump->arch.valid_physmem) ++/* determine next valid physical address */ ++#define KL_NEXT_VALID_PHYSADDR (*KLP->dump->arch.next_valid_physaddr) ++/* XXX */ ++#define KL_FIX_VADDR (*KLP->dump->arch.fix_vaddr) ++/* write dump_header_asm_t */ ++#define KL_WRITE_DHA (*KLP->dump->arch.write_dha) ++/* size of dump_header_asm_t */ ++#define KL_DHA_SIZE (KLP->dump->arch.dha_size) ++/* init virtual to physical address mapping */ ++#define KL_INIT_VIRTOP (KLP->dump->arch.init_virtop) ++ ++ ++/* macros for easier access to dump specific values */ ++#define KL_CORE_TYPE KLP->dump->core_type ++#define KL_CORE_FD KLP->dump->core_fd ++#define KL_ARCH KLP->dump->arch.arch ++#define KL_PTRSZ KLP->dump->arch.ptrsz ++#define KL_NBPW (KL_PTRSZ/8) ++#define KL_BYTE_ORDER KLP->dump->arch.byteorder ++#define KL_PAGE_SHIFT KLP->dump->arch.pageshift ++#define KL_PAGE_SIZE KLP->dump->arch.pagesize ++#define KL_PAGE_MASK KLP->dump->arch.pagemask ++#define KL_PAGE_OFFSET KLP->dump->arch.pageoffset ++#define KL_STACK_OFFSET KLP->dump->arch.kstacksize ++#define IS_BIG_ENDIAN() (KL_BYTE_ORDER == KL_BIG_ENDIAN) ++#define IS_LITTLE_ENDIAN() (KL_BYTE_ORDER == KL_LITTLE_ENDIAN) ++#define KL_LINUX_RELEASE KLP->dump->mem.linux_release ++#define KL_KERNEL_FLAGS KLP->dump->mem.kernel_flags ++ ++#if 0 ++/* cpw: don't need all this dump file stuff: */ ++/* macros to access input files */ ++#define KL_MAP_FILE KLP->dump->map ++#define KL_DUMP_FILE KLP->dump->dump ++#define KL_KERNTYPES_FILE KLP->kerntypes ++ ++#define CORE_IS_KMEM (KL_CORE_TYPE == dev_kmem) ++#define CORE_IS_DUMP ((KL_CORE_TYPE > dev_kmem) && (KL_CORE_TYPE <= unk_core)) ++ ++ ++/* Generic dump header structure (the first three members of ++ * dump_header and dump_header_asm are the same). ++ */ ++typedef struct generic_dump_header_s { ++ uint64_t magic_number; ++ uint32_t version; ++ uint32_t header_size; ++} generic_dump_header_t; ++ ++/* Some macros for making it easier to access the generic header ++ * information in a dump_header or dump_header_asm stuct. ++ */ ++#define DHP(dh) ((generic_dump_header_t*)(dh)) ++#define DH_MAGIC(dh) DHP(dh)->magic_number ++#define DH_VERSION(dh) DHP(dh)->version ++#define DH_HEADER_SIZE(dh) DHP(dh)->header_size ++ ++extern kl_dump_header_t *DUMP_HEADER; ++extern void *DUMP_HEADER_ASM; ++#endif ++ ++/* Struct to store some host architecture specific values ++ */ ++typedef struct kl_hostarch_s { ++ int arch; /* KL_ARCH_ */ ++ int ptrsz; /* 32 or 64 bit */ ++ int byteorder; /* KL_LITTLE_ENDIAN or KL_BIG_ENDIAN */ ++} kl_hostarch_t; ++ ++/* Struct klib_s, contains all the information necessary for accessing ++ * information in the kernel. A pointer to a klib_t struct will be ++ * returned from libkern_init() if core dump analysis (or live system ++ * analysis) is possible. ++ * ++ */ ++typedef struct klib_s { ++ int k_flags; /* Flags pertaining to klib_s struct */ ++ kl_hostarch_t *host; /* host arch info */ ++ kl_dumpinfo_t *dump; /* dump information */ ++ maplist_t *k_symmap; /* symbol information */ ++ kltype_t *k_typeinfo; /* type information */ ++ char *kerntypes; /* pathname for kerntypes file */ ++} klib_t; ++ ++/* Structure to accomodate all debug formats */ ++struct namelist_format_opns { ++ /* to open/setup the namelist file */ ++ int (*open_namelist) (char *filename , int flags); ++ int (*setup_typeinfo)(void); ++}; ++ ++/* ++ * global variables ++ */ ++ ++/* Here we store almost everything, we need to know about a dump. */ ++extern klib_t *KLP; ++ ++/* macros to make live easier */ ++#define MIP KLP->dump ++#define STP KLP->k_symmap ++#define TASK_STRUCT_SZ (KLP->dump->mem.struct_sizes.task_struct_sz) ++#define MM_STRUCT_SZ (KLP->dump->mem.struct_sizes.mm_struct_sz) ++#define PAGE_SZ (KLP->dump->mem.struct_sizes.page_sz) ++#define MODULE_SZ (KLP->dump->mem.struct_sizes.module_sz) ++#define NEW_UTSNAME_SZ (KLP->dump->mem.struct_sizes.new_utsname_sz) ++#define SWITCH_STACK_SZ (KLP->dump->mem.struct_sizes.switch_stack_sz) ++#define PT_REGS_SZ (KLP->dump->mem.struct_sizes.pt_regs_sz) ++#define PGLIST_DATA_SZ (KLP->dump->mem.struct_sizes.pglist_data_sz) ++#define RUNQUEUE_SZ (KLP->dump->mem.struct_sizes.runqueue_sz) ++ ++#if 0 ++cpw: used for sial? ++/* klib_jbuf has to be defined outside libklib. ++ * Make sure to call setjmp(klib_jbuf) BEFORE kl_sig_setup() is called! */ ++extern jmp_buf klib_jbuf; ++#endif ++ ++/* Macros that eliminate the offset paramaters to the kl_uint() and kl_int() ++ * functions (just makes things cleaner looking) ++ */ ++#define KL_UINT(p, s, m) kl_uint(p, s, m, 0) ++#define KL_INT(p, s, m) kl_int(p, s, m, 0) ++ ++/* Macros for translating strings into long numeric values depending ++ * on the base of 's'. ++ */ ++#define GET_VALUE(s, value) kl_get_value(s, NULL, 0, value) ++#define GET_HEX_VALUE(s) (kaddr_t)strtoull(s, (char**)NULL, 16) ++#define GET_DEC_VALUE(s) (unsigned)strtoull(s, (char**)NULL, 10) ++#define GET_OCT_VALUE(s) (unsigned)strtoull(s, (char**)NULL, 8) ++ ++#define KL_SIGFLG_CORE 0x1 ++#define KL_SIGFLG_SILENT 0x2 ++#define KL_SIGFLG_LNGJMP 0x4 ++ ++/* Flag that tells kl_is_valid_kaddr() to perform a word aligned check ++ */ ++#define WORD_ALIGN_FLAG 1 ++ ++#define ADDR_TO_PGNO(addr) ((addr - KL_PAGE_OFFSET) >> KL_PAGE_SHIFT); ++ ++/* Generalized macros for pointing at different data types at particular ++ * offsets in kernel structs. ++ */ ++/* #define K_ADDR(p, s, f) ((uaddr_t)(p) + kl_member_offset(s, f)) */ ++#define K_ADDR(p, s, f) ((p) + kl_member_offset(s, f)) ++#define K_PTR(p, s, f) (K_ADDR((void*)p, s, f)) ++#define CHAR(p, s, f) (K_ADDR((char*)p, s, f)) ++ ++#define PTRSZ32 ((KL_PTRSZ == 32) ? 1 : 0) ++#define PTRSZ64 ((KL_PTRSZ == 64) ? 1 : 0) ++ ++/* Function prototypes ++ */ ++/* cpw: remove the last argument FILE * */ ++void kl_binary_print(uint64_t); ++void kl_print_bit_value(void *, int, int, int, int); ++void kl_print_char(void *, int); ++void kl_print_uchar(void *, int); ++void kl_print_int2(void *, int); ++void kl_print_uint2(void *, int); ++void kl_print_int4(void *, int); ++void kl_print_uint4(void *, int); ++void kl_print_float4(void *, int); ++void kl_print_int8(void *, int); ++void kl_print_uint8(void *, int); ++void kl_print_float8(void *, int); ++void kl_print_base(void *, int, int, int); ++void kl_print_string(char *); ++ ++int kl_get_live_filenames( ++ char * /* pointer to buffer for map filename */, ++ char * /* pointer to buffer for dump filename */, ++ char * /* pointer to buffer for namelist filename */); ++ ++int kl_init_klib( ++ char * /* map file name */, ++ char * /* dump file name */, ++ char * /* namelist file name */, ++ int /* system arch of memory in dump */, ++ int /* rwflag flag (/dev/mem only) */, ++ int /* Linux release */); ++ ++void kl_free_klib( ++ klib_t * /* Pointer to klib_s struct */); ++ ++ ++int kl_dump_retrieve( ++ char * /* dumpdev name */, ++ char * /* dumpdir name */, ++ int /* progress flag (zero or non-zero) */, ++ int /* debug flag (zero or non-zero) */); ++ ++int kl_dump_erase( ++ char * /* dumpdev name */); ++ ++uint64_t kl_strtoull( ++ char * /* string containing numeric value */, ++ char ** /* pointer to pointer to bad char */, ++ int /* base */); ++ ++int kl_get_value( ++ char * /* param */, ++ int * /* mode pointer */, ++ int /* number of elements */, ++ uint64_t * /* pointer to value */); ++ ++/* Functions for working with list_head structs ++ */ ++kaddr_t kl_list_entry(kaddr_t, char *, char *); ++kaddr_t kl_list_next(kaddr_t); ++kaddr_t kl_list_prev(kaddr_t); ++ ++int kl_sig_setup(int); ++ ++void kl_set_curnmlist( ++ int /* index of namelist */); ++ ++int kl_open_namelist( ++ char * /* name of namelist */, ++ int /* flags */, ++ int /* kl_flags */); ++ ++int kl_get_structure(kaddr_t, char*, size_t*, void**); ++uint64_t kl_get_bit_value(void*, unsigned int, unsigned int, unsigned int); ++void kl_s390tod_to_timeval(uint64_t, struct timeval*); ++ ++#endif /* __KLIB_H */ +--- /dev/null ++++ b/kdb/modules/lcrash/lc_eval.h +@@ -0,0 +1,225 @@ ++/* ++ * $Id: lc_eval.h 1122 2004-12-21 23:26:23Z tjm $ ++ * ++ * This file is part of lcrash, an analysis tool for Linux memory dumps. ++ * ++ * Created by Silicon Graphics, Inc. ++ * Contributions by IBM, and others ++ * ++ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved. ++ * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation ++ * ++ * 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. See the file COPYING for more ++ * information. ++ */ ++ ++#ifndef __LC_EVAL_H ++#define __LC_EVAL_H ++ ++typedef struct type_s { ++ int flag; ++ union { ++ struct type_s *next; ++ kltype_t *kltp; ++ } un; ++} type_t; ++ ++#define t_next un.next ++#define t_kltp un.kltp ++ ++/* Structure to hold info on "tokens" extracted from eval and print ++ * command input strings. ++ */ ++typedef struct token_s { ++ short type; ++ short operator; /* if token is an operator */ ++ char *string; /* string holding value or identifier */ ++ char *ptr; /* pointer to start of token */ ++ struct token_s *next; /* next token in the chain */ ++} token_t; ++ ++/* Structure returned by the eval() function containing the result ++ * of an expression evaluation. This struct is also used to build the ++ * parse tree for the expression. ++ */ ++typedef struct node_s { ++ struct node_s *next; /* linked list pointer */ ++ unsigned char node_type; /* type of node */ ++ unsigned short flags; /* see below */ ++ unsigned char operator; /* operator if node is type OPERATOR */ ++ unsigned char byte_size; /* byte_size of base_type values */ ++ char *name; /* name of variable or struct member */ ++ /* value and address are uint64_t in lcrash, but for ia32 ... */ ++ unsigned long long value; /* numeric value or pointer */ ++ unsigned long address; /* address (could be same as pointer) */ ++ type_t *type; /* pointer to type related info */ ++ char *tok_ptr; /* pointer to token in cmd string */ ++ struct node_s *left; /* pointer to left child */ ++ struct node_s *right; /* pointer to right child */ ++} node_t; ++ ++/* Token and Node types ++ */ ++#define OPERATOR 1 ++#define NUMBER 2 ++#define INDEX 3 ++#define TYPE_DEF 4 ++#define VADDR 5 ++#define MEMBER 6 ++#define STRING 7 ++#define TEXT 8 ++#define CHARACTER 9 ++#define EVAL_VAR 10 ++ ++/* Flag values ++ */ ++#define STRING_FLAG 0x001 ++#define ADDRESS_FLAG 0x002 ++#define INDIRECTION_FLAG 0x004 ++#define POINTER_FLAG 0x008 ++#define MEMBER_FLAG 0x010 ++#define BOOLIAN_FLAG 0x020 ++#define KLTYPE_FLAG 0x040 ++#define NOTYPE_FLAG 0x080 ++#define UNSIGNED_FLAG 0x100 ++#define VOID_FLAG 0x200 ++ ++/* Flag value for print_eval_error() function ++ */ ++#define CMD_NAME_FLG 1 /* cmdname is not name of a command */ ++#define CMD_STRING_FLG 2 /* cmdname is not name of a command */ ++ ++/* Expression operators in order of precedence. ++ */ ++#define CONDITIONAL 1 ++#define CONDITIONAL_ELSE 2 ++#define LOGICAL_OR 3 ++#define LOGICAL_AND 4 ++#define BITWISE_OR 5 ++#define BITWISE_EXCLUSIVE_OR 6 ++#define BITWISE_AND 7 ++#define EQUAL 8 ++#define NOT_EQUAL 9 ++#define LESS_THAN 10 ++#define GREATER_THAN 11 ++#define LESS_THAN_OR_EQUAL 12 ++#define GREATER_THAN_OR_EQUAL 13 ++#define RIGHT_SHIFT 14 ++#define LEFT_SHIFT 15 ++#define ADD 16 ++#define SUBTRACT 17 ++#define MULTIPLY 18 ++#define DIVIDE 19 ++#define MODULUS 20 ++#define LOGICAL_NEGATION 21 ++#define ONES_COMPLEMENT 22 ++#define PREFIX_INCREMENT 23 ++#define PREFIX_DECREMENT 24 ++#define POSTFIX_INCREMENT 25 ++#define POSTFIX_DECREMENT 26 ++#define CAST 27 ++#define UNARY_MINUS 28 ++#define UNARY_PLUS 29 ++#define INDIRECTION 30 ++#define ADDRESS 31 ++#define SIZEOF 32 ++#define RIGHT_ARROW 33 ++#define DOT 34 ++#define OPEN_PAREN 100 ++#define CLOSE_PAREN 101 ++#define OPEN_SQUARE_BRACKET 102 ++#define CLOSE_SQUARE_BRACKET 103 ++#define SEMI_COLON 104 ++#define NOT_YET -1 ++ ++/* Errors codes primarily for use with eval (print) functions ++ */ ++#define E_OPEN_PAREN 1100 ++#define E_CLOSE_PAREN 1101 ++#define E_BAD_STRUCTURE 1102 ++#define E_MISSING_STRUCTURE 1103 ++#define E_BAD_MEMBER 1104 ++#define E_BAD_OPERATOR 1105 ++#define E_BAD_OPERAND 1106 ++#define E_MISSING_OPERAND 1107 ++#define E_BAD_TYPE 1108 ++#define E_NOTYPE 1109 ++#define E_BAD_POINTER 1110 ++#define E_BAD_INDEX 1111 ++#define E_BAD_CHAR 1112 ++#define E_BAD_STRING 1113 ++#define E_END_EXPECTED 1114 ++#define E_BAD_EVAR 1115 /* Bad eval variable */ ++#define E_BAD_VALUE 1116 ++#define E_NO_VALUE 1117 ++#define E_DIVIDE_BY_ZERO 1118 ++#define E_BAD_CAST 1119 ++#define E_NO_ADDRESS 1120 ++#define E_SINGLE_QUOTE 1121 ++ ++#define E_BAD_WHATIS 1197 ++#define E_NOT_IMPLEMENTED 1198 ++#define E_SYNTAX_ERROR 1199 ++ ++extern uint64_t eval_error; ++extern char *error_token; ++ ++/* Function prototypes ++ */ ++node_t *eval(char **, int); ++void print_eval_error(char *, char *, char *, uint64_t, int); ++void free_nodes(node_t *); ++ ++/* Struct to hold information about eval variables ++ */ ++typedef struct variable_s { ++ btnode_t v_bt; /* Must be first */ ++ int v_flags; ++ char *v_exp; /* What was entered on command line */ ++ char *v_typestr; /* Actual type string after eval() call */ ++ node_t *v_node; ++} variable_t; ++ ++#define v_left v_bt.bt_left ++#define v_right v_bt.bt_right ++#define v_name v_bt.bt_key ++ ++/* Flag values ++ */ ++#define V_PERM 0x001 /* can't be unset - can be modified */ ++#define V_DEFAULT 0x002 /* set at startup */ ++#define V_NOMOD 0x004 /* cannot be modified */ ++#define V_TYPEDEF 0x008 /* contains typed data */ ++#define V_REC_STRUCT 0x010 /* direct ref to struct/member (not pointer) */ ++#define V_STRING 0x020 /* contains ASCII string (no type) */ ++#define V_COMMAND 0x040 /* contains command string (no type) */ ++#define V_OPTION 0x080 /* contains option flag (e.g., $hexints) */ ++#define V_PERM_NODE 0x100 /* Don't free node after setting variable */ ++ ++/* Variable table struct ++ */ ++typedef struct vtab_s { ++ variable_t *vt_root; ++ int vt_count; ++} vtab_t; ++ ++extern vtab_t *vtab; /* Pointer to table of eval variable info */ ++ ++/* Function Prototypes ++ */ ++variable_t *make_variable(char *, char *, node_t *, int); ++void clean_variable(variable_t *); ++void free_variable(variable_t *); ++void init_variables(vtab_t *); ++int set_variable(vtab_t *, char *, char *, node_t *, int); ++int unset_variable(vtab_t *, variable_t *); ++variable_t *find_variable(vtab_t *, char *, int); ++kltype_t *number_to_type(node_t *); ++void free_eval_memory(void); ++/* cpw: was int print_eval_results(node_t *, FILE *, int); */ ++int print_eval_results(node_t *, int); ++ ++#endif /* __LC_EVAL_H */ +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -4,6 +4,9 @@ + * Copyright (C) 1991, 1992 Linus Torvalds + */ + ++#ifdef CONFIG_KDB ++#include ++#endif + #include + #include + #include +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -479,3 +479,25 @@ __initcall(kallsyms_init); + + EXPORT_SYMBOL(__print_symbol); + EXPORT_SYMBOL_GPL(sprint_symbol); ++ ++#ifdef CONFIG_KDB ++#include ++#include ++ ++const char *kdb_walk_kallsyms(loff_t *pos) ++{ ++ static struct kallsym_iter kdb_walk_kallsyms_iter; ++ if (*pos == 0) { ++ memset(&kdb_walk_kallsyms_iter, 0, sizeof(kdb_walk_kallsyms_iter)); ++ reset_iter(&kdb_walk_kallsyms_iter, 0); ++ } ++ while (1) { ++ if (!update_iter(&kdb_walk_kallsyms_iter, *pos)) ++ return NULL; ++ ++*pos; ++ /* Some debugging symbols have no name. Ignore them. */ ++ if (kdb_walk_kallsyms_iter.name[0]) ++ return kdb_walk_kallsyms_iter.name; ++ } ++} ++#endif /* CONFIG_KDB */ +--- a/kernel/kexec.c ++++ b/kernel/kexec.c +@@ -37,6 +37,12 @@ + #include + #include + ++#ifdef CONFIG_KDB_KDUMP ++#include ++#include ++#include ++#endif ++ + /* Per cpu memory for storing cpu states in case of system crash. */ + note_buf_t* crash_notes; + +@@ -1072,9 +1078,19 @@ void crash_kexec(struct pt_regs *regs) + if (mutex_trylock(&kexec_mutex)) { + if (kexec_crash_image) { + struct pt_regs fixed_regs; ++ + crash_setup_regs(&fixed_regs, regs); + crash_save_vmcoreinfo(); ++ /* ++ * If we enabled KDB, we don't want to automatically ++ * perform a kdump since KDB will be responsible for ++ * executing kdb through a special 'kdump' command. ++ */ ++#ifdef CONFIG_KDB_KDUMP ++ kdba_kdump_prepare(&fixed_regs); ++#else + machine_crash_shutdown(&fixed_regs); ++#endif + machine_kexec(kexec_crash_image); + } + mutex_unlock(&kexec_mutex); +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2576,12 +2576,23 @@ out: + return -ERANGE; + } + ++#ifdef CONFIG_KDB ++#include ++struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ ++#endif /* CONFIG_KDB */ ++ + int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + char *name, char *module_name, int *exported) + { + struct module *mod; ++#ifdef CONFIG_KDB ++ int get_lock = !KDB_IS_RUNNING(); ++#else ++#define get_lock 1 ++#endif + +- preempt_disable(); ++ if (get_lock) ++ preempt_disable(); + list_for_each_entry(mod, &modules, list) { + if (symnum < mod->num_symtab) { + *value = mod->symtab[symnum].st_value; +@@ -2590,12 +2601,14 @@ int module_get_kallsym(unsigned int symn + KSYM_NAME_LEN); + strlcpy(module_name, mod->name, MODULE_NAME_LEN); + *exported = is_exported(name, mod); +- preempt_enable(); ++ if (get_lock) ++ preempt_enable(); + return 0; + } + symnum -= mod->num_symtab; + } +- preempt_enable(); ++ if (get_lock) ++ preempt_enable(); + return -ERANGE; + } + +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -21,6 +21,9 @@ + #include + #include + #include ++#ifdef CONFIG_KDB_KDUMP ++#include ++#endif + + int panic_on_oops; + int tainted; +@@ -82,6 +85,11 @@ NORET_TYPE void panic(const char * fmt, + printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf); + bust_spinlocks(0); + ++#ifdef CONFIG_KDB_KDUMP ++ if (kdb_kdump_state == KDB_KDUMP_RESET) { ++ (void)kdb(KDB_REASON_OOPS, 999, get_irq_regs()); ++ } ++#endif + /* + * If we have crashed and we have a crash kernel loaded let it handle + * everything else. +--- a/kernel/printk.c ++++ b/kernel/printk.c +@@ -443,6 +443,20 @@ void debugger_syslog_data(char *syslog_d + } + #endif /* CONFIG_DEBUG_KERNEL */ + ++#ifdef CONFIG_KDB ++/* kdb dmesg command needs access to the syslog buffer. do_syslog() uses locks ++ * so it cannot be used during debugging. Just tell kdb where the start and ++ * end of the physical and logical logs are. This is equivalent to do_syslog(3). ++ */ ++void kdb_syslog_data(char *syslog_data[4]) ++{ ++ syslog_data[0] = log_buf; ++ syslog_data[1] = log_buf + log_buf_len; ++ syslog_data[2] = log_buf + log_end - (logged_chars < log_buf_len ? logged_chars : log_buf_len); ++ syslog_data[3] = log_buf + log_end; ++} ++#endif /* CONFIG_KDB */ ++ + /* + * Call the console drivers on a range of log_buf + */ +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -8358,7 +8358,7 @@ void normalize_rt_tasks(void) + + #endif /* CONFIG_MAGIC_SYSRQ */ + +-#ifdef CONFIG_IA64 ++#if defined(CONFIG_IA64) || defined(CONFIG_KDB) + /* + * These functions are only useful for the IA64 MCA handling. + * +@@ -9299,3 +9299,94 @@ struct cgroup_subsys cpuacct_subsys = { + .subsys_id = cpuacct_subsys_id, + }; + #endif /* CONFIG_CGROUP_CPUACCT */ ++ ++#ifdef CONFIG_KDB ++ ++#include ++ ++static void ++kdb_prio(char *name, struct rt_prio_array *array, kdb_printf_t xxx_printf, ++ unsigned int cpu) ++{ ++ int pri, printed_header = 0; ++ struct task_struct *p; ++ ++ xxx_printf(" %s rt bitmap: 0x%lx 0x%lx 0x%lx\n", ++ name, ++ array->bitmap[0], array->bitmap[1], array->bitmap[2]); ++ ++ pri = sched_find_first_bit(array->bitmap); ++ if (pri < MAX_RT_PRIO) { ++ xxx_printf(" rt bitmap priorities:"); ++ while (pri < MAX_RT_PRIO) { ++ xxx_printf(" %d", pri); ++ pri++; ++ pri = find_next_bit(array->bitmap, MAX_RT_PRIO, pri); ++ } ++ xxx_printf("\n"); ++ } ++ ++ for (pri = 0; pri < MAX_RT_PRIO; pri++) { ++ int printed_hdr = 0; ++ struct list_head *head, *curr; ++ ++ head = array->queue + pri; ++ curr = head->next; ++ while(curr != head) { ++ struct task_struct *task; ++ if (!printed_hdr) { ++ xxx_printf(" queue at priority=%d\n", pri); ++ printed_hdr = 1; ++ } ++ task = list_entry(curr, struct task_struct, rt.run_list); ++ if (task) ++ xxx_printf(" 0x%p %d %s time_slice:%d\n", ++ task, task->pid, task->comm, ++ task->rt.time_slice); ++ curr = curr->next; ++ } ++ } ++ for_each_process(p) { ++ if (p->se.on_rq && (task_cpu(p) == cpu) && ++ (p->policy == SCHED_NORMAL)) { ++ if (!printed_header) { ++ xxx_printf(" sched_normal queue:\n"); ++ printed_header = 1; ++ } ++ xxx_printf(" 0x%p %d %s pri:%d spri:%d npri:%d\n", ++ p, p->pid, p->comm, p->prio, ++ p->static_prio, p->normal_prio); ++ } ++ } ++} ++ ++/* This code must be in sched.c because struct rq is only defined in this ++ * source. To allow most of kdb to be modular, this code cannot call any kdb ++ * functions directly, any external functions that it needs must be passed in ++ * as parameters. ++ */ ++ ++void ++kdb_runqueue(unsigned long cpu, kdb_printf_t xxx_printf) ++{ ++ struct rq *rq; ++ ++ rq = cpu_rq(cpu); ++ ++ xxx_printf("CPU%ld lock:%s curr:0x%p(%d)(%s)", ++ cpu, (spin_is_locked(&rq->lock))?"LOCKED":"free", ++ rq->curr, rq->curr->pid, rq->curr->comm); ++ if (rq->curr == rq->idle) ++ xxx_printf(" is idle"); ++ xxx_printf("\n "); ++#ifdef CONFIG_SMP ++ xxx_printf(" cpu_load:%lu %lu %lu", ++ rq->cpu_load[0], rq->cpu_load[1], rq->cpu_load[2]); ++#endif ++ xxx_printf(" nr_running:%lu nr_switches:%llu\n", ++ rq->nr_running, (long long)rq->nr_switches); ++ kdb_prio("active", &rq->rt.active, xxx_printf, (unsigned int)cpu); ++} ++EXPORT_SYMBOL(kdb_runqueue); ++ ++#endif /* CONFIG_KDB */ +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -2596,3 +2596,52 @@ void __init signals_init(void) + { + sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); + } ++ ++#ifdef CONFIG_KDB ++#include ++/* ++ * kdb_send_sig_info ++ * ++ * Allows kdb to send signals without exposing signal internals. ++ * ++ * Inputs: ++ * t task ++ * siginfo signal information ++ * seqno current kdb sequence number (avoid including kdbprivate.h) ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * Checks if the required locks are available before calling the main ++ * signal code, to avoid kdb deadlocks. ++ * Remarks: ++ */ ++void ++kdb_send_sig_info(struct task_struct *t, struct siginfo *info, int seqno) ++{ ++ static struct task_struct *kdb_prev_t; ++ static int kdb_prev_seqno; ++ int sig, new_t; ++ if (!spin_trylock(&t->sighand->siglock)) { ++ kdb_printf("Can't do kill command now.\n" ++ "The sigmask lock is held somewhere else in kernel, try again later\n"); ++ return; ++ } ++ spin_unlock(&t->sighand->siglock); ++ new_t = kdb_prev_t != t || kdb_prev_seqno != seqno; ++ kdb_prev_t = t; ++ kdb_prev_seqno = seqno; ++ if (t->state != TASK_RUNNING && new_t) { ++ kdb_printf("Process is not RUNNING, sending a signal from kdb risks deadlock\n" ++ "on the run queue locks. The signal has _not_ been sent.\n" ++ "Reissue the kill command if you want to risk the deadlock.\n"); ++ return; ++ } ++ sig = info->si_signo; ++ if (send_sig_info(sig, info, t)) ++ kdb_printf("Fail to deliver Signal %d to process %d.\n", sig, t->pid); ++ else ++ kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid); ++} ++#endif /* CONFIG_KDB */ +--- a/kernel/sysctl_check.c ++++ b/kernel/sysctl_check.c +@@ -105,6 +105,7 @@ static const struct trans_ctl_table tran + { KERN_NMI_WATCHDOG, "nmi_watchdog" }, + { KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" }, + { KERN_SETUID_DUMPABLE, "suid_dumpable" }, ++ { KERN_KDB, "kdb" }, + {} + }; + +--- a/lib/bug.c ++++ b/lib/bug.c +@@ -41,6 +41,10 @@ + #include + #include + ++#ifdef CONFIG_KDB ++#include ++#endif ++ + extern const struct bug_entry __start___bug_table[], __stop___bug_table[]; + + #ifdef CONFIG_MODULES +@@ -162,5 +166,9 @@ enum bug_trap_type report_bug(unsigned l + "[verbose debug info unavailable]\n", + (void *)bugaddr); + ++#ifdef CONFIG_KDB ++ kdb(KDB_REASON_ENTER, 0, regs); ++#endif ++ + return BUG_TRAP_TYPE_BUG; + } +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -1500,6 +1500,28 @@ int hugetlb_overcommit_handler(struct ct + + #endif /* CONFIG_SYSCTL */ + ++#ifdef CONFIG_KDB ++#include ++#include ++/* Like hugetlb_report_meminfo() but using kdb_printf() */ ++void ++kdb_hugetlb_report_meminfo(void) ++{ ++ struct hstate *h = &default_hstate; ++ kdb_printf( ++ "HugePages_Total: %5lu\n" ++ "HugePages_Free: %5lu\n" ++ "HugePages_Rsvd: %5lu\n" ++ "HugePages_Surp: %5lu\n" ++ "Hugepagesize: %5lu kB\n", ++ h->nr_huge_pages, ++ h->free_huge_pages, ++ h->resv_huge_pages, ++ h->surplus_huge_pages, ++ 1UL << (huge_page_order(h) + PAGE_SHIFT - 10)); ++} ++#endif /* CONFIG_KDB */ ++ + int hugetlb_report_meminfo(char *buf) + { + struct hstate *h = &default_hstate; +--- a/mm/mmzone.c ++++ b/mm/mmzone.c +@@ -22,6 +22,10 @@ struct pglist_data *next_online_pgdat(st + return NULL; + return NODE_DATA(nid); + } ++#ifdef CONFIG_KDB ++EXPORT_SYMBOL(first_online_pgdat); ++EXPORT_SYMBOL(next_online_pgdat); ++#endif + + /* + * next_zone - helper magic for for_each_zone() +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -13,6 +13,10 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include ++#endif /* CONFIG_KDB */ + #include + #include + #include +@@ -1750,6 +1754,24 @@ void si_swapinfo(struct sysinfo *val) + spin_unlock(&swap_lock); + } + ++#ifdef CONFIG_KDB ++/* Like si_swapinfo() but without the locks */ ++void kdb_si_swapinfo(struct sysinfo *val) ++{ ++ unsigned int i; ++ unsigned long nr_to_be_unused = 0; ++ ++ for (i = 0; i < nr_swapfiles; i++) { ++ if (!(swap_info[i].flags & SWP_USED) || ++ (swap_info[i].flags & SWP_WRITEOK)) ++ continue; ++ nr_to_be_unused += swap_info[i].inuse_pages; ++ } ++ val->freeswap = nr_swap_pages + nr_to_be_unused; ++ val->totalswap = total_swap_pages + nr_to_be_unused; ++} ++#endif /* CONFIG_KDB */ ++ + /* + * Verify that a swap entry is valid and increment its swap map count. + * diff --git a/src/patches/suse-2.6.27.31/patches.suse/kdb-ia64 b/src/patches/suse-2.6.27.31/patches.suse/kdb-ia64 new file mode 100644 index 000000000..ff177d30e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kdb-ia64 @@ -0,0 +1,22892 @@ +From: SGI KDB Development +Subject:/kdb-v4.4-2.6.27-rc8-ia64-1 +References: FATE#303971 +X-URL: ftp://oss.sgi.com/www/projects/kdb/download/v4.4/ + +The KDB IA64 code. + +Acked-by: Bernhard Walle + +--- + arch/ia64/Kconfig.debug | 97 + arch/ia64/Makefile | 1 + arch/ia64/include/asm/ansidecl.h | 383 + + arch/ia64/include/asm/bfd.h | 5089 +++++++++++++++++++++ + arch/ia64/include/asm/kdb.h | 45 + arch/ia64/include/asm/kdb_break.h | 24 + arch/ia64/include/asm/kdbprivate.h | 124 + arch/ia64/include/asm/kmap_types.h | 3 + arch/ia64/include/asm/kregs.h | 2 + arch/ia64/kdb/ChangeLog | 1085 ++++ + arch/ia64/kdb/Makefile | 21 + arch/ia64/kdb/cpu-ia64-opc.c | 598 ++ + arch/ia64/kdb/ia64-asmtab.c | 8585 +++++++++++++++++++++++++++++++++++++ + arch/ia64/kdb/ia64-asmtab.h | 158 + arch/ia64/kdb/ia64-dis.c | 312 + + arch/ia64/kdb/ia64-opc.c | 749 +++ + arch/ia64/kdb/ia64-opc.h | 141 + arch/ia64/kdb/ia64.h | 402 + + arch/ia64/kdb/kdb_cmds | 17 + arch/ia64/kdb/kdba_bp.c | 841 +++ + arch/ia64/kdb/kdba_bt.c | 285 + + arch/ia64/kdb/kdba_fru.c | 65 + arch/ia64/kdb/kdba_id.c | 529 ++ + arch/ia64/kdb/kdba_io.c | 661 ++ + arch/ia64/kdb/kdba_jmp.S | 394 + + arch/ia64/kdb/kdba_pod.c | 64 + arch/ia64/kdb/kdba_support.c | 1720 +++++++ + arch/ia64/kernel/head.S | 7 + arch/ia64/kernel/mca.c | 72 + arch/ia64/kernel/smp.c | 23 + arch/ia64/kernel/traps.c | 22 + arch/ia64/kernel/unwind.c | 33 + 32 files changed, 22539 insertions(+), 13 deletions(-) + +--- a/arch/ia64/Kconfig.debug ++++ b/arch/ia64/Kconfig.debug +@@ -56,9 +56,106 @@ config IA64_DEBUG_IRQ + and restore instructions. It's useful for tracking down spinlock + problems, but slow! If you're unsure, select N. + ++config KDB ++ bool "Built-in Kernel Debugger support" ++ depends on DEBUG_KERNEL ++ select KALLSYMS ++ select KALLSYMS_ALL ++ help ++ This option provides a built-in kernel debugger. The built-in ++ kernel debugger contains commands which allow memory to be examined, ++ instructions to be disassembled and breakpoints to be set. For details, ++ see Documentation/kdb/kdb.mm and the manual pages kdb_bt, kdb_ss, etc. ++ Kdb can also be used via the serial port. Set up the system to ++ have a serial console (see Documentation/serial-console.txt). ++ The key sequence KDB on the serial port will cause the ++ kernel debugger to be entered with input from the serial port and ++ output to the serial console. If unsure, say N. ++ ++config KDB_MODULES ++ tristate "KDB modules" ++ depends on KDB ++ help ++ KDB can be extended by adding your own modules, in directory ++ kdb/modules. This option selects the way that these modules should ++ be compiled, as free standing modules (select M) or built into the ++ kernel (select Y). If unsure say M. ++ ++config KDB_OFF ++ bool "KDB off by default" ++ depends on KDB ++ help ++ Normally kdb is activated by default, as long as CONFIG_KDB is set. ++ If you want to ship a kernel with kdb support but only have kdb ++ turned on when the user requests it then select this option. When ++ compiled with CONFIG_KDB_OFF, kdb ignores all events unless you boot ++ with kdb=on or you echo "1" > /proc/sys/kernel/kdb. This option also ++ works in reverse, if kdb is normally activated, you can boot with ++ kdb=off or echo "0" > /proc/sys/kernel/kdb to deactivate kdb. If ++ unsure, say N. ++ ++config KDB_CONTINUE_CATASTROPHIC ++ int "KDB continues after catastrophic errors" ++ depends on KDB ++ default "0" ++ help ++ This integer controls the behaviour of kdb when the kernel gets a ++ catastrophic error, i.e. for a panic, oops, NMI or other watchdog ++ tripping. CONFIG_KDB_CONTINUE_CATASTROPHIC interacts with ++ /proc/sys/kernel/kdb and CONFIG_LKCD_DUMP (if your kernel has the ++ LKCD patch). ++ When KDB is active (/proc/sys/kernel/kdb == 1) and a catastrophic ++ error occurs, nothing extra happens until you type 'go'. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default). The first time ++ you type 'go', kdb warns you. The second time you type 'go', KDB ++ tries to continue - no guarantees that the kernel is still usable. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 1. KDB tries to continue - no ++ guarantees that the kernel is still usable. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD ++ patch and LKCD is configured to take a dump then KDB forces a dump. ++ Whether or not a dump is taken, KDB forces a reboot. ++ When KDB is not active (/proc/sys/kernel/kdb == 0) and a catastrophic ++ error occurs, the following steps are automatic, no human ++ intervention is required. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default) or 1. KDB attempts ++ to continue - no guarantees that the kernel is still usable. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD ++ patch and LKCD is configured to take a dump then KDB automatically ++ forces a dump. Whether or not a dump is taken, KDB forces a ++ reboot. ++ If you are not sure, say 0. Read Documentation/kdb/dump.txt before ++ setting to 2. ++ ++config KDB_USB ++ bool "Support for USB Keyboard in KDB (OHCI and/or EHCI only)" ++ depends on KDB && (USB_OHCI_HCD || USB_UHCI_HCD) ++ help ++ If you want to use kdb from USB keyboards then say Y here. If you ++ say N then kdb can only be used from a PC (AT) keyboard or a serial ++ console. ++ ++config KDB_HARDWARE_BREAKPOINTS ++ bool "Enable hardware breakpoints in KDB" ++ depends on KDB ++ default y ++ help ++ If you say Y here, KDB will allow you to use the IA64 ++ hardware watchpoint feature (via the bph and bpha ++ commands). Currently, only data breakpoints are ++ implemented. ++ + config SYSVIPC_COMPAT + bool + depends on COMPAT && SYSVIPC + default y + ++config KDB_KDUMP ++ bool "Support for Kdump in KDB" ++ depends on KDB ++ select KEXEC ++ default N ++ help ++ If you want to take Kdump kernel vmcore from KDB then say Y here. ++ Of imsire. say N. ++ + endmenu +--- a/arch/ia64/Makefile ++++ b/arch/ia64/Makefile +@@ -60,6 +60,7 @@ core-$(CONFIG_IA64_SGI_SN2) += arch/ia64 + core-$(CONFIG_IA64_SGI_UV) += arch/ia64/uv/ + core-$(CONFIG_KVM) += arch/ia64/kvm/ + ++drivers-$(CONFIG_KDB) += arch/$(ARCH)/kdb/ + drivers-$(CONFIG_PCI) += arch/ia64/pci/ + drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ + drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ +--- /dev/null ++++ b/arch/ia64/include/asm/ansidecl.h +@@ -0,0 +1,383 @@ ++/* ANSI and traditional C compatability macros ++ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 ++ Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++/* ANSI and traditional C compatibility macros ++ ++ ANSI C is assumed if __STDC__ is #defined. ++ ++ Macro ANSI C definition Traditional C definition ++ ----- ---- - ---------- ----------- - ---------- ++ ANSI_PROTOTYPES 1 not defined ++ PTR `void *' `char *' ++ PTRCONST `void *const' `char *' ++ LONG_DOUBLE `long double' `double' ++ const not defined `' ++ volatile not defined `' ++ signed not defined `' ++ VA_START(ap, var) va_start(ap, var) va_start(ap) ++ ++ Note that it is safe to write "void foo();" indicating a function ++ with no return value, in all K+R compilers we have been able to test. ++ ++ For declaring functions with prototypes, we also provide these: ++ ++ PARAMS ((prototype)) ++ -- for functions which take a fixed number of arguments. Use this ++ when declaring the function. When defining the function, write a ++ K+R style argument list. For example: ++ ++ char *strcpy PARAMS ((char *dest, char *source)); ++ ... ++ char * ++ strcpy (dest, source) ++ char *dest; ++ char *source; ++ { ... } ++ ++ ++ VPARAMS ((prototype, ...)) ++ -- for functions which take a variable number of arguments. Use ++ PARAMS to declare the function, VPARAMS to define it. For example: ++ ++ int printf PARAMS ((const char *format, ...)); ++ ... ++ int ++ printf VPARAMS ((const char *format, ...)) ++ { ++ ... ++ } ++ ++ For writing functions which take variable numbers of arguments, we ++ also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These ++ hide the differences between K+R and C89 more ++ thoroughly than the simple VA_START() macro mentioned above. ++ ++ VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. ++ Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls ++ corresponding to the list of fixed arguments. Then use va_arg ++ normally to get the variable arguments, or pass your va_list object ++ around. You do not declare the va_list yourself; VA_OPEN does it ++ for you. ++ ++ Here is a complete example: ++ ++ int ++ printf VPARAMS ((const char *format, ...)) ++ { ++ int result; ++ ++ VA_OPEN (ap, format); ++ VA_FIXEDARG (ap, const char *, format); ++ ++ result = vfprintf (stdout, format, ap); ++ VA_CLOSE (ap); ++ ++ return result; ++ } ++ ++ ++ You can declare variables either before or after the VA_OPEN, ++ VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning ++ and end of a block. They must appear at the same nesting level, ++ and any variables declared after VA_OPEN go out of scope at ++ VA_CLOSE. Unfortunately, with a K+R compiler, that includes the ++ argument list. You can have multiple instances of VA_OPEN/VA_CLOSE ++ pairs in a single function in case you need to traverse the ++ argument list more than once. ++ ++ For ease of writing code which uses GCC extensions but needs to be ++ portable to other compilers, we provide the GCC_VERSION macro that ++ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various ++ wrappers around __attribute__. Also, __extension__ will be #defined ++ to nothing if it doesn't work. See below. ++ ++ This header also defines a lot of obsolete macros: ++ CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID, ++ AND, DOTS, NOARGS. Don't use them. */ ++ ++#ifndef _ANSIDECL_H ++#define _ANSIDECL_H 1 ++ ++/* Every source file includes this file, ++ so they will all get the switch for lint. */ ++/* LINTLIBRARY */ ++ ++/* Using MACRO(x,y) in cpp #if conditionals does not work with some ++ older preprocessors. Thus we can't define something like this: ++ ++#define HAVE_GCC_VERSION(MAJOR, MINOR) \ ++ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) ++ ++and then test "#if HAVE_GCC_VERSION(2,7)". ++ ++So instead we use the macro below and test it against specific values. */ ++ ++/* This macro simplifies testing whether we are using gcc, and if it ++ is of a particular minimum version. (Both major & minor numbers are ++ significant.) This macro will evaluate to 0 if we are not using ++ gcc at all. */ ++#ifndef GCC_VERSION ++#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) ++#endif /* GCC_VERSION */ ++ ++#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus)) ++/* All known AIX compilers implement these things (but don't always ++ define __STDC__). The RISC/OS MIPS compiler defines these things ++ in SVR4 mode, but does not define __STDC__. */ ++/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other ++ C++ compilers, does not define __STDC__, though it acts as if this ++ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ ++ ++#define ANSI_PROTOTYPES 1 ++#define PTR void * ++#define PTRCONST void *const ++#define LONG_DOUBLE long double ++ ++/* PARAMS is often defined elsewhere (e.g. by libintl.h), so wrap it in ++ a #ifndef. */ ++#ifndef PARAMS ++#define PARAMS(ARGS) ARGS ++#endif ++ ++#define VPARAMS(ARGS) ARGS ++#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR) ++ ++/* variadic function helper macros */ ++/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's ++ use without inhibiting further decls and without declaring an ++ actual variable. */ ++#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy ++#define VA_CLOSE(AP) } va_end(AP); } ++#define VA_FIXEDARG(AP, T, N) struct Qdmy ++ ++#undef const ++#undef volatile ++#undef signed ++ ++#ifdef __KERNEL__ ++#ifndef __STDC_VERSION__ ++#define __STDC_VERSION__ 0 ++#endif ++#endif /* __KERNEL__ */ ++ ++/* inline requires special treatment; it's in C99, and GCC >=2.7 supports ++ it too, but it's not in C89. */ ++#undef inline ++#if __STDC_VERSION__ > 199901L ++/* it's a keyword */ ++#else ++# if GCC_VERSION >= 2007 ++# define inline __inline__ /* __inline__ prevents -pedantic warnings */ ++# else ++# define inline /* nothing */ ++# endif ++#endif ++ ++/* These are obsolete. Do not use. */ ++#ifndef IN_GCC ++#define CONST const ++#define VOLATILE volatile ++#define SIGNED signed ++ ++#define PROTO(type, name, arglist) type name arglist ++#define EXFUN(name, proto) name proto ++#define DEFUN(name, arglist, args) name(args) ++#define DEFUN_VOID(name) name(void) ++#define AND , ++#define DOTS , ... ++#define NOARGS void ++#endif /* ! IN_GCC */ ++ ++#else /* Not ANSI C. */ ++ ++#undef ANSI_PROTOTYPES ++#define PTR char * ++#define PTRCONST PTR ++#define LONG_DOUBLE double ++ ++#define PARAMS(args) () ++#define VPARAMS(args) (va_alist) va_dcl ++#define VA_START(va_list, var) va_start(va_list) ++ ++#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy ++#define VA_CLOSE(AP) } va_end(AP); } ++#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE) ++ ++/* some systems define these in header files for non-ansi mode */ ++#undef const ++#undef volatile ++#undef signed ++#undef inline ++#define const ++#define volatile ++#define signed ++#define inline ++ ++#ifndef IN_GCC ++#define CONST ++#define VOLATILE ++#define SIGNED ++ ++#define PROTO(type, name, arglist) type name () ++#define EXFUN(name, proto) name() ++#define DEFUN(name, arglist, args) name arglist args; ++#define DEFUN_VOID(name) name() ++#define AND ; ++#define DOTS ++#define NOARGS ++#endif /* ! IN_GCC */ ++ ++#endif /* ANSI C. */ ++ ++/* Define macros for some gcc attributes. This permits us to use the ++ macros freely, and know that they will come into play for the ++ version of gcc in which they are supported. */ ++ ++#if (GCC_VERSION < 2007) ++# define __attribute__(x) ++#endif ++ ++/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ ++#ifndef ATTRIBUTE_MALLOC ++# if (GCC_VERSION >= 2096) ++# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) ++# else ++# define ATTRIBUTE_MALLOC ++# endif /* GNUC >= 2.96 */ ++#endif /* ATTRIBUTE_MALLOC */ ++ ++/* Attributes on labels were valid as of gcc 2.93. */ ++#ifndef ATTRIBUTE_UNUSED_LABEL ++# if (!defined (__cplusplus) && GCC_VERSION >= 2093) ++# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ++# else ++# define ATTRIBUTE_UNUSED_LABEL ++# endif /* !__cplusplus && GNUC >= 2.93 */ ++#endif /* ATTRIBUTE_UNUSED_LABEL */ ++ ++#ifndef ATTRIBUTE_UNUSED ++#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) ++#endif /* ATTRIBUTE_UNUSED */ ++ ++/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the ++ identifier name. */ ++#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) ++# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED ++#else /* !__cplusplus || GNUC >= 3.4 */ ++# define ARG_UNUSED(NAME) NAME ++#endif /* !__cplusplus || GNUC >= 3.4 */ ++ ++#ifndef ATTRIBUTE_NORETURN ++#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) ++#endif /* ATTRIBUTE_NORETURN */ ++ ++/* Attribute `nonnull' was valid as of gcc 3.3. */ ++#ifndef ATTRIBUTE_NONNULL ++# if (GCC_VERSION >= 3003) ++# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) ++# else ++# define ATTRIBUTE_NONNULL(m) ++# endif /* GNUC >= 3.3 */ ++#endif /* ATTRIBUTE_NONNULL */ ++ ++/* Attribute `pure' was valid as of gcc 3.0. */ ++#ifndef ATTRIBUTE_PURE ++# if (GCC_VERSION >= 3000) ++# define ATTRIBUTE_PURE __attribute__ ((__pure__)) ++# else ++# define ATTRIBUTE_PURE ++# endif /* GNUC >= 3.0 */ ++#endif /* ATTRIBUTE_PURE */ ++ ++/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. ++ This was the case for the `printf' format attribute by itself ++ before GCC 3.3, but as of 3.3 we need to add the `nonnull' ++ attribute to retain this behavior. */ ++#ifndef ATTRIBUTE_PRINTF ++#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) ++#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) ++#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) ++#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) ++#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) ++#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) ++#endif /* ATTRIBUTE_PRINTF */ ++ ++/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on ++ a function pointer. Format attributes were allowed on function ++ pointers as of gcc 3.1. */ ++#ifndef ATTRIBUTE_FPTR_PRINTF ++# if (GCC_VERSION >= 3001) ++# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) ++# else ++# define ATTRIBUTE_FPTR_PRINTF(m, n) ++# endif /* GNUC >= 3.1 */ ++# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) ++# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) ++# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) ++# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) ++# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) ++#endif /* ATTRIBUTE_FPTR_PRINTF */ ++ ++/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A ++ NULL format specifier was allowed as of gcc 3.3. */ ++#ifndef ATTRIBUTE_NULL_PRINTF ++# if (GCC_VERSION >= 3003) ++# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ++# else ++# define ATTRIBUTE_NULL_PRINTF(m, n) ++# endif /* GNUC >= 3.3 */ ++# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) ++# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) ++# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) ++# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) ++# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) ++#endif /* ATTRIBUTE_NULL_PRINTF */ ++ ++/* Attribute `sentinel' was valid as of gcc 3.5. */ ++#ifndef ATTRIBUTE_SENTINEL ++# if (GCC_VERSION >= 3005) ++# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) ++# else ++# define ATTRIBUTE_SENTINEL ++# endif /* GNUC >= 3.5 */ ++#endif /* ATTRIBUTE_SENTINEL */ ++ ++ ++#ifndef ATTRIBUTE_ALIGNED_ALIGNOF ++# if (GCC_VERSION >= 3000) ++# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) ++# else ++# define ATTRIBUTE_ALIGNED_ALIGNOF(m) ++# endif /* GNUC >= 3.0 */ ++#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ ++ ++/* We use __extension__ in some places to suppress -pedantic warnings ++ about GCC extensions. This feature didn't work properly before ++ gcc 2.8. */ ++#if GCC_VERSION < 2008 ++#define __extension__ ++#endif ++ ++#endif /* ansidecl.h */ +--- /dev/null ++++ b/arch/ia64/include/asm/bfd.h +@@ -0,0 +1,5089 @@ ++/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically ++ generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", ++ "bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", ++ "syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c", ++ "linker.c" and "simple.c". ++ Run "make headers" in your build bfd/ to regenerate. */ ++ ++/* Main header file for the bfd library -- portable access to object files. ++ ++ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, ++ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ Contributed by Cygnus Support. ++ ++ This file is part of BFD, the Binary File Descriptor library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef __BFD_H_SEEN__ ++#define __BFD_H_SEEN__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef __KERNEL__ ++#include ++#else /* __KERNEL__ */ ++#include "ansidecl.h" ++#include "symcat.h" ++#endif /* __KERNEL__ */ ++#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) ++#ifndef SABER ++/* This hack is to avoid a problem with some strict ANSI C preprocessors. ++ The problem is, "32_" is not a valid preprocessing token, and we don't ++ want extra underscores (e.g., "nlm_32_"). The XCONCAT2 macro will ++ cause the inner CONCAT2 macros to be evaluated first, producing ++ still-valid pp-tokens. Then the final concatenation can be done. */ ++#undef CONCAT4 ++#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d)) ++#endif ++#endif ++ ++/* The word size used by BFD on the host. This may be 64 with a 32 ++ bit target if the host is 64 bit, or if other 64 bit targets have ++ been selected with --enable-targets, or if --enable-64-bit-bfd. */ ++#define BFD_ARCH_SIZE 64 ++ ++/* The word size of the default bfd target. */ ++#define BFD_DEFAULT_TARGET_SIZE 64 ++ ++#define BFD_HOST_64BIT_LONG 1 ++#define BFD_HOST_LONG_LONG 1 ++#if 1 ++#define BFD_HOST_64_BIT long ++#define BFD_HOST_U_64_BIT unsigned long ++typedef BFD_HOST_64_BIT bfd_int64_t; ++typedef BFD_HOST_U_64_BIT bfd_uint64_t; ++#endif ++ ++#if BFD_ARCH_SIZE >= 64 ++#define BFD64 ++#endif ++ ++#ifndef INLINE ++#if __GNUC__ >= 2 ++#define INLINE __inline__ ++#else ++#define INLINE ++#endif ++#endif ++ ++/* Forward declaration. */ ++typedef struct bfd bfd; ++ ++/* Boolean type used in bfd. Too many systems define their own ++ versions of "boolean" for us to safely typedef a "boolean" of ++ our own. Using an enum for "bfd_boolean" has its own set of ++ problems, with strange looking casts required to avoid warnings ++ on some older compilers. Thus we just use an int. ++ ++ General rule: Functions which are bfd_boolean return TRUE on ++ success and FALSE on failure (unless they're a predicate). */ ++ ++typedef int bfd_boolean; ++#undef FALSE ++#undef TRUE ++#define FALSE 0 ++#define TRUE 1 ++ ++#ifdef BFD64 ++ ++#ifndef BFD_HOST_64_BIT ++ #error No 64 bit integer type available ++#endif /* ! defined (BFD_HOST_64_BIT) */ ++ ++typedef BFD_HOST_U_64_BIT bfd_vma; ++typedef BFD_HOST_64_BIT bfd_signed_vma; ++typedef BFD_HOST_U_64_BIT bfd_size_type; ++typedef BFD_HOST_U_64_BIT symvalue; ++ ++#ifndef fprintf_vma ++#if BFD_HOST_64BIT_LONG ++#define sprintf_vma(s,x) sprintf (s, "%016lx", x) ++#define fprintf_vma(f,x) fprintf (f, "%016lx", x) ++#else ++#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) ++#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) ++#define fprintf_vma(s,x) \ ++ fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) ++#define sprintf_vma(s,x) \ ++ sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) ++#endif ++#endif ++ ++#else /* not BFD64 */ ++ ++/* Represent a target address. Also used as a generic unsigned type ++ which is guaranteed to be big enough to hold any arithmetic types ++ we need to deal with. */ ++typedef unsigned long bfd_vma; ++ ++/* A generic signed type which is guaranteed to be big enough to hold any ++ arithmetic types we need to deal with. Can be assumed to be compatible ++ with bfd_vma in the same way that signed and unsigned ints are compatible ++ (as parameters, in assignment, etc). */ ++typedef long bfd_signed_vma; ++ ++typedef unsigned long symvalue; ++typedef unsigned long bfd_size_type; ++ ++/* Print a bfd_vma x on stream s. */ ++#define fprintf_vma(s,x) fprintf (s, "%08lx", x) ++#define sprintf_vma(s,x) sprintf (s, "%08lx", x) ++ ++#endif /* not BFD64 */ ++ ++#define HALF_BFD_SIZE_TYPE \ ++ (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) ++ ++#ifndef BFD_HOST_64_BIT ++/* Fall back on a 32 bit type. The idea is to make these types always ++ available for function return types, but in the case that ++ BFD_HOST_64_BIT is undefined such a function should abort or ++ otherwise signal an error. */ ++typedef bfd_signed_vma bfd_int64_t; ++typedef bfd_vma bfd_uint64_t; ++#endif ++ ++/* An offset into a file. BFD always uses the largest possible offset ++ based on the build time availability of fseek, fseeko, or fseeko64. */ ++typedef BFD_HOST_64_BIT file_ptr; ++typedef unsigned BFD_HOST_64_BIT ufile_ptr; ++ ++extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); ++extern void bfd_fprintf_vma (bfd *, void *, bfd_vma); ++ ++#define printf_vma(x) fprintf_vma(stdout,x) ++#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x) ++ ++typedef unsigned int flagword; /* 32 bits of flags */ ++typedef unsigned char bfd_byte; ++ ++typedef int (*bfd_qsort_closure_func) (const void *, const void *, const void *); ++extern void bfd_qsort (void *base, bfd_size_type nmemb, bfd_size_type size, ++ bfd_qsort_closure_func cmp, void *closure); ++ ++/* File formats. */ ++ ++typedef enum bfd_format ++{ ++ bfd_unknown = 0, /* File format is unknown. */ ++ bfd_object, /* Linker/assembler/compiler output. */ ++ bfd_archive, /* Object archive file. */ ++ bfd_core, /* Core dump. */ ++ bfd_type_end /* Marks the end; don't use it! */ ++} ++bfd_format; ++ ++/* Values that may appear in the flags field of a BFD. These also ++ appear in the object_flags field of the bfd_target structure, where ++ they indicate the set of flags used by that backend (not all flags ++ are meaningful for all object file formats) (FIXME: at the moment, ++ the object_flags values have mostly just been copied from backend ++ to another, and are not necessarily correct). */ ++ ++/* No flags. */ ++#define BFD_NO_FLAGS 0x00 ++ ++/* BFD contains relocation entries. */ ++#define HAS_RELOC 0x01 ++ ++/* BFD is directly executable. */ ++#define EXEC_P 0x02 ++ ++/* BFD has line number information (basically used for F_LNNO in a ++ COFF header). */ ++#define HAS_LINENO 0x04 ++ ++/* BFD has debugging information. */ ++#define HAS_DEBUG 0x08 ++ ++/* BFD has symbols. */ ++#define HAS_SYMS 0x10 ++ ++/* BFD has local symbols (basically used for F_LSYMS in a COFF ++ header). */ ++#define HAS_LOCALS 0x20 ++ ++/* BFD is a dynamic object. */ ++#define DYNAMIC 0x40 ++ ++/* Text section is write protected (if D_PAGED is not set, this is ++ like an a.out NMAGIC file) (the linker sets this by default, but ++ clears it for -r or -N). */ ++#define WP_TEXT 0x80 ++ ++/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the ++ linker sets this by default, but clears it for -r or -n or -N). */ ++#define D_PAGED 0x100 ++ ++/* BFD is relaxable (this means that bfd_relax_section may be able to ++ do something) (sometimes bfd_relax_section can do something even if ++ this is not set). */ ++#define BFD_IS_RELAXABLE 0x200 ++ ++/* This may be set before writing out a BFD to request using a ++ traditional format. For example, this is used to request that when ++ writing out an a.out object the symbols not be hashed to eliminate ++ duplicates. */ ++#define BFD_TRADITIONAL_FORMAT 0x400 ++ ++/* This flag indicates that the BFD contents are actually cached in ++ memory. If this is set, iostream points to a bfd_in_memory struct. */ ++#define BFD_IN_MEMORY 0x800 ++ ++/* The sections in this BFD specify a memory page. */ ++#define HAS_LOAD_PAGE 0x1000 ++ ++/* This BFD has been created by the linker and doesn't correspond ++ to any input file. */ ++#define BFD_LINKER_CREATED 0x2000 ++ ++/* Symbols and relocation. */ ++ ++/* A count of carsyms (canonical archive symbols). */ ++typedef unsigned long symindex; ++ ++/* How to perform a relocation. */ ++typedef const struct reloc_howto_struct reloc_howto_type; ++ ++#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) ++ ++/* General purpose part of a symbol X; ++ target specific parts are in libcoff.h, libaout.h, etc. */ ++ ++#define bfd_get_section(x) ((x)->section) ++#define bfd_get_output_section(x) ((x)->section->output_section) ++#define bfd_set_section(x,y) ((x)->section) = (y) ++#define bfd_asymbol_base(x) ((x)->section->vma) ++#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) ++#define bfd_asymbol_name(x) ((x)->name) ++/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ ++#define bfd_asymbol_bfd(x) ((x)->the_bfd) ++#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) ++ ++/* A canonical archive symbol. */ ++/* This is a type pun with struct ranlib on purpose! */ ++typedef struct carsym ++{ ++ char *name; ++ file_ptr file_offset; /* Look here to find the file. */ ++} ++carsym; /* To make these you call a carsymogen. */ ++ ++/* Used in generating armaps (archive tables of contents). ++ Perhaps just a forward definition would do? */ ++struct orl /* Output ranlib. */ ++{ ++ char **name; /* Symbol name. */ ++ union ++ { ++ file_ptr pos; ++ bfd *abfd; ++ } u; /* bfd* or file position. */ ++ int namidx; /* Index into string table. */ ++}; ++ ++/* Linenumber stuff. */ ++typedef struct lineno_cache_entry ++{ ++ unsigned int line_number; /* Linenumber from start of function. */ ++ union ++ { ++ struct bfd_symbol *sym; /* Function name. */ ++ bfd_vma offset; /* Offset into section. */ ++ } u; ++} ++alent; ++ ++/* Object and core file sections. */ ++ ++#define align_power(addr, align) \ ++ (((addr) + ((bfd_vma) 1 << (align)) - 1) & ((bfd_vma) -1 << (align))) ++ ++typedef struct bfd_section *sec_ptr; ++ ++#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) ++#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) ++#define bfd_get_section_lma(bfd, ptr) ((ptr)->lma + 0) ++#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) ++#define bfd_section_name(bfd, ptr) ((ptr)->name) ++#define bfd_section_size(bfd, ptr) ((ptr)->size) ++#define bfd_get_section_size(ptr) ((ptr)->size) ++#define bfd_section_vma(bfd, ptr) ((ptr)->vma) ++#define bfd_section_lma(bfd, ptr) ((ptr)->lma) ++#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) ++#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) ++#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) ++ ++#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) ++ ++#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) ++#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) ++#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) ++/* Find the address one past the end of SEC. */ ++#define bfd_get_section_limit(bfd, sec) \ ++ (((sec)->rawsize ? (sec)->rawsize : (sec)->size) \ ++ / bfd_octets_per_byte (bfd)) ++ ++typedef struct stat stat_type; ++ ++typedef enum bfd_print_symbol ++{ ++ bfd_print_symbol_name, ++ bfd_print_symbol_more, ++ bfd_print_symbol_all ++} bfd_print_symbol_type; ++ ++/* Information about a symbol that nm needs. */ ++ ++typedef struct _symbol_info ++{ ++ symvalue value; ++ char type; ++ const char *name; /* Symbol name. */ ++ unsigned char stab_type; /* Stab type. */ ++ char stab_other; /* Stab other. */ ++ short stab_desc; /* Stab desc. */ ++ const char *stab_name; /* String for stab type. */ ++} symbol_info; ++ ++/* Get the name of a stabs type code. */ ++ ++extern const char *bfd_get_stab_name (int); ++ ++/* Hash table routines. There is no way to free up a hash table. */ ++ ++/* An element in the hash table. Most uses will actually use a larger ++ structure, and an instance of this will be the first field. */ ++ ++struct bfd_hash_entry ++{ ++ /* Next entry for this hash code. */ ++ struct bfd_hash_entry *next; ++ /* String being hashed. */ ++ const char *string; ++ /* Hash code. This is the full hash code, not the index into the ++ table. */ ++ unsigned long hash; ++}; ++ ++/* A hash table. */ ++ ++struct bfd_hash_table ++{ ++ /* The hash array. */ ++ struct bfd_hash_entry **table; ++ /* The number of slots in the hash table. */ ++ unsigned int size; ++ /* A function used to create new elements in the hash table. The ++ first entry is itself a pointer to an element. When this ++ function is first invoked, this pointer will be NULL. However, ++ having the pointer permits a hierarchy of method functions to be ++ built each of which calls the function in the superclass. Thus ++ each function should be written to allocate a new block of memory ++ only if the argument is NULL. */ ++ struct bfd_hash_entry *(*newfunc) ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++ /* An objalloc for this hash table. This is a struct objalloc *, ++ but we use void * to avoid requiring the inclusion of objalloc.h. */ ++ void *memory; ++}; ++ ++/* Initialize a hash table. */ ++extern bfd_boolean bfd_hash_table_init ++ (struct bfd_hash_table *, ++ struct bfd_hash_entry *(*) (struct bfd_hash_entry *, ++ struct bfd_hash_table *, ++ const char *)); ++ ++/* Initialize a hash table specifying a size. */ ++extern bfd_boolean bfd_hash_table_init_n ++ (struct bfd_hash_table *, ++ struct bfd_hash_entry *(*) (struct bfd_hash_entry *, ++ struct bfd_hash_table *, ++ const char *), ++ unsigned int size); ++ ++/* Free up a hash table. */ ++extern void bfd_hash_table_free ++ (struct bfd_hash_table *); ++ ++/* Look up a string in a hash table. If CREATE is TRUE, a new entry ++ will be created for this string if one does not already exist. The ++ COPY argument must be TRUE if this routine should copy the string ++ into newly allocated memory when adding an entry. */ ++extern struct bfd_hash_entry *bfd_hash_lookup ++ (struct bfd_hash_table *, const char *, bfd_boolean create, ++ bfd_boolean copy); ++ ++/* Replace an entry in a hash table. */ ++extern void bfd_hash_replace ++ (struct bfd_hash_table *, struct bfd_hash_entry *old, ++ struct bfd_hash_entry *nw); ++ ++/* Base method for creating a hash table entry. */ ++extern struct bfd_hash_entry *bfd_hash_newfunc ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++ ++/* Grab some space for a hash table entry. */ ++extern void *bfd_hash_allocate ++ (struct bfd_hash_table *, unsigned int); ++ ++/* Traverse a hash table in a random order, calling a function on each ++ element. If the function returns FALSE, the traversal stops. The ++ INFO argument is passed to the function. */ ++extern void bfd_hash_traverse ++ (struct bfd_hash_table *, ++ bfd_boolean (*) (struct bfd_hash_entry *, void *), ++ void *info); ++ ++/* Allows the default size of a hash table to be configured. New hash ++ tables allocated using bfd_hash_table_init will be created with ++ this size. */ ++extern void bfd_hash_set_default_size (bfd_size_type); ++ ++/* This structure is used to keep track of stabs in sections ++ information while linking. */ ++ ++struct stab_info ++{ ++ /* A hash table used to hold stabs strings. */ ++ struct bfd_strtab_hash *strings; ++ /* The header file hash table. */ ++ struct bfd_hash_table includes; ++ /* The first .stabstr section. */ ++ struct bfd_section *stabstr; ++}; ++ ++#define COFF_SWAP_TABLE (void *) &bfd_coff_std_swap_table ++ ++/* User program access to BFD facilities. */ ++ ++/* Direct I/O routines, for programs which know more about the object ++ file than BFD does. Use higher level routines if possible. */ ++ ++extern bfd_size_type bfd_bread (void *, bfd_size_type, bfd *); ++extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); ++extern int bfd_seek (bfd *, file_ptr, int); ++extern file_ptr bfd_tell (bfd *); ++extern int bfd_flush (bfd *); ++extern int bfd_stat (bfd *, struct stat *); ++ ++/* Deprecated old routines. */ ++#if __GNUC__ ++#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ ++ bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ ++ bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#else ++#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ ++ bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ ++ bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#endif ++extern void warn_deprecated (const char *, const char *, int, const char *); ++ ++/* Cast from const char * to char * so that caller can assign to ++ a char * without a warning. */ ++#define bfd_get_filename(abfd) ((char *) (abfd)->filename) ++#define bfd_get_cacheable(abfd) ((abfd)->cacheable) ++#define bfd_get_format(abfd) ((abfd)->format) ++#define bfd_get_target(abfd) ((abfd)->xvec->name) ++#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) ++#define bfd_family_coff(abfd) \ ++ (bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ ++ bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) ++#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) ++#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) ++#define bfd_header_big_endian(abfd) \ ++ ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) ++#define bfd_header_little_endian(abfd) \ ++ ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) ++#define bfd_get_file_flags(abfd) ((abfd)->flags) ++#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) ++#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) ++#define bfd_my_archive(abfd) ((abfd)->my_archive) ++#define bfd_has_map(abfd) ((abfd)->has_armap) ++ ++#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) ++#define bfd_usrdata(abfd) ((abfd)->usrdata) ++ ++#define bfd_get_start_address(abfd) ((abfd)->start_address) ++#define bfd_get_symcount(abfd) ((abfd)->symcount) ++#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) ++#define bfd_count_sections(abfd) ((abfd)->section_count) ++ ++#define bfd_get_dynamic_symcount(abfd) ((abfd)->dynsymcount) ++ ++#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) ++ ++#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) ++ ++extern bfd_boolean bfd_cache_close ++ (bfd *abfd); ++/* NB: This declaration should match the autogenerated one in libbfd.h. */ ++ ++extern bfd_boolean bfd_cache_close_all (void); ++ ++extern bfd_boolean bfd_record_phdr ++ (bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, ++ bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); ++ ++/* Byte swapping routines. */ ++ ++bfd_uint64_t bfd_getb64 (const void *); ++bfd_uint64_t bfd_getl64 (const void *); ++bfd_int64_t bfd_getb_signed_64 (const void *); ++bfd_int64_t bfd_getl_signed_64 (const void *); ++bfd_vma bfd_getb32 (const void *); ++bfd_vma bfd_getl32 (const void *); ++bfd_signed_vma bfd_getb_signed_32 (const void *); ++bfd_signed_vma bfd_getl_signed_32 (const void *); ++bfd_vma bfd_getb16 (const void *); ++bfd_vma bfd_getl16 (const void *); ++bfd_signed_vma bfd_getb_signed_16 (const void *); ++bfd_signed_vma bfd_getl_signed_16 (const void *); ++void bfd_putb64 (bfd_uint64_t, void *); ++void bfd_putl64 (bfd_uint64_t, void *); ++void bfd_putb32 (bfd_vma, void *); ++void bfd_putl32 (bfd_vma, void *); ++void bfd_putb16 (bfd_vma, void *); ++void bfd_putl16 (bfd_vma, void *); ++ ++/* Byte swapping routines which take size and endiannes as arguments. */ ++ ++bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); ++void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); ++ ++extern bfd_boolean bfd_section_already_linked_table_init (void); ++extern void bfd_section_already_linked_table_free (void); ++ ++/* Externally visible ECOFF routines. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++struct ecoff_debug_info; ++struct ecoff_debug_swap; ++struct ecoff_extr; ++struct bfd_symbol; ++struct bfd_link_info; ++struct bfd_link_hash_entry; ++struct bfd_elf_version_tree; ++#endif ++extern bfd_vma bfd_ecoff_get_gp_value ++ (bfd * abfd); ++extern bfd_boolean bfd_ecoff_set_gp_value ++ (bfd *abfd, bfd_vma gp_value); ++extern bfd_boolean bfd_ecoff_set_regmasks ++ (bfd *abfd, unsigned long gprmask, unsigned long fprmask, ++ unsigned long *cprmask); ++extern void *bfd_ecoff_debug_init ++ (bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); ++extern void bfd_ecoff_debug_free ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_accumulate ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, bfd *input_bfd, ++ struct ecoff_debug_info *input_debug, ++ const struct ecoff_debug_swap *input_swap, struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_accumulate_other ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, bfd *input_bfd, ++ struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_externals ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, bfd_boolean relocatable, ++ bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), ++ void (*set_index) (struct bfd_symbol *, bfd_size_type)); ++extern bfd_boolean bfd_ecoff_debug_one_external ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, const char *name, ++ struct ecoff_extr *esym); ++extern bfd_size_type bfd_ecoff_debug_size ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap); ++extern bfd_boolean bfd_ecoff_write_debug ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, file_ptr where); ++extern bfd_boolean bfd_ecoff_write_accumulated_debug ++ (void *handle, bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, ++ struct bfd_link_info *info, file_ptr where); ++ ++/* Externally visible ELF routines. */ ++ ++struct bfd_link_needed_list ++{ ++ struct bfd_link_needed_list *next; ++ bfd *by; ++ const char *name; ++}; ++ ++enum dynamic_lib_link_class { ++ DYN_NORMAL = 0, ++ DYN_AS_NEEDED = 1, ++ DYN_DT_NEEDED = 2, ++ DYN_NO_ADD_NEEDED = 4, ++ DYN_NO_NEEDED = 8 ++}; ++ ++extern bfd_boolean bfd_elf_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *, bfd_boolean, ++ bfd_boolean); ++extern struct bfd_link_needed_list *bfd_elf_get_needed_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_get_bfd_needed_list ++ (bfd *, struct bfd_link_needed_list **); ++extern bfd_boolean bfd_elf_size_dynamic_sections ++ (bfd *, const char *, const char *, const char *, const char * const *, ++ struct bfd_link_info *, struct bfd_section **, ++ struct bfd_elf_version_tree *); ++extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr ++ (bfd *, struct bfd_link_info *); ++extern void bfd_elf_set_dt_needed_name ++ (bfd *, const char *); ++extern const char *bfd_elf_get_dt_soname ++ (bfd *); ++extern void bfd_elf_set_dyn_lib_class ++ (bfd *, int); ++extern int bfd_elf_get_dyn_lib_class ++ (bfd *); ++extern struct bfd_link_needed_list *bfd_elf_get_runpath_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_discard_info ++ (bfd *, struct bfd_link_info *); ++extern unsigned int _bfd_elf_default_action_discarded ++ (struct bfd_section *); ++ ++/* Return an upper bound on the number of bytes required to store a ++ copy of ABFD's program header table entries. Return -1 if an error ++ occurs; bfd_get_error will return an appropriate code. */ ++extern long bfd_get_elf_phdr_upper_bound ++ (bfd *abfd); ++ ++/* Copy ABFD's program header table entries to *PHDRS. The entries ++ will be stored as an array of Elf_Internal_Phdr structures, as ++ defined in include/elf/internal.h. To find out how large the ++ buffer needs to be, call bfd_get_elf_phdr_upper_bound. ++ ++ Return the number of program header table entries read, or -1 if an ++ error occurs; bfd_get_error will return an appropriate code. */ ++extern int bfd_get_elf_phdrs ++ (bfd *abfd, void *phdrs); ++ ++/* Create a new BFD as if by bfd_openr. Rather than opening a file, ++ reconstruct an ELF file by reading the segments out of remote memory ++ based on the ELF file header at EHDR_VMA and the ELF program headers it ++ points to. If not null, *LOADBASEP is filled in with the difference ++ between the VMAs from which the segments were read, and the VMAs the ++ file headers (and hence BFD's idea of each section's VMA) put them at. ++ ++ The function TARGET_READ_MEMORY is called to copy LEN bytes from the ++ remote memory at target address VMA into the local buffer at MYADDR; it ++ should return zero on success or an `errno' code on failure. TEMPL must ++ be a BFD for an ELF target with the word size and byte order found in ++ the remote memory. */ ++extern bfd *bfd_elf_bfd_from_remote_memory ++ (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, ++ int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); ++ ++/* Return the arch_size field of an elf bfd, or -1 if not elf. */ ++extern int bfd_get_arch_size ++ (bfd *); ++ ++/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ ++extern int bfd_get_sign_extend_vma ++ (bfd *); ++ ++extern struct bfd_section *_bfd_elf_tls_setup ++ (bfd *, struct bfd_link_info *); ++ ++extern void _bfd_fix_excluded_sec_syms ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, ++ char **); ++ ++extern bfd_boolean bfd_bfin_elf32_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, ++ char **); ++ ++/* SunOS shared library support routines for the linker. */ ++ ++extern struct bfd_link_needed_list *bfd_sunos_get_needed_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_sunos_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_sunos_size_dynamic_sections ++ (bfd *, struct bfd_link_info *, struct bfd_section **, ++ struct bfd_section **, struct bfd_section **); ++ ++/* Linux shared library support routines for the linker. */ ++ ++extern bfd_boolean bfd_i386linux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_m68klinux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_sparclinux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++ ++/* mmap hacks */ ++ ++struct _bfd_window_internal; ++typedef struct _bfd_window_internal bfd_window_internal; ++ ++typedef struct _bfd_window ++{ ++ /* What the user asked for. */ ++ void *data; ++ bfd_size_type size; ++ /* The actual window used by BFD. Small user-requested read-only ++ regions sharing a page may share a single window into the object ++ file. Read-write versions shouldn't until I've fixed things to ++ keep track of which portions have been claimed by the ++ application; don't want to give the same region back when the ++ application wants two writable copies! */ ++ struct _bfd_window_internal *i; ++} ++bfd_window; ++ ++extern void bfd_init_window ++ (bfd_window *); ++extern void bfd_free_window ++ (bfd_window *); ++extern bfd_boolean bfd_get_file_window ++ (bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); ++ ++/* XCOFF support routines for the linker. */ ++ ++extern bfd_boolean bfd_xcoff_link_record_set ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); ++extern bfd_boolean bfd_xcoff_import_symbol ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, ++ const char *, const char *, const char *, unsigned int); ++extern bfd_boolean bfd_xcoff_export_symbol ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); ++extern bfd_boolean bfd_xcoff_link_count_reloc ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_xcoff_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_xcoff_size_dynamic_sections ++ (bfd *, struct bfd_link_info *, const char *, const char *, ++ unsigned long, unsigned long, unsigned long, bfd_boolean, ++ int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean); ++extern bfd_boolean bfd_xcoff_link_generate_rtinit ++ (bfd *, const char *, const char *, bfd_boolean); ++ ++/* XCOFF support routines for ar. */ ++extern bfd_boolean bfd_xcoff_ar_archive_set_magic ++ (bfd *, char *); ++ ++/* Externally visible COFF routines. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++struct internal_syment; ++union internal_auxent; ++#endif ++ ++extern bfd_boolean bfd_coff_get_syment ++ (bfd *, struct bfd_symbol *, struct internal_syment *); ++ ++extern bfd_boolean bfd_coff_get_auxent ++ (bfd *, struct bfd_symbol *, int, union internal_auxent *); ++ ++extern bfd_boolean bfd_coff_set_symbol_class ++ (bfd *, struct bfd_symbol *, unsigned int); ++ ++extern bfd_boolean bfd_m68k_coff_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); ++ ++/* ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_arm_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_arm_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++extern bfd_boolean bfd_arm_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++/* PE ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_arm_pe_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_arm_pe_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++/* ELF ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_elf32_arm_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++void bfd_elf32_arm_set_target_relocs ++ (struct bfd_link_info *, int, char *, int, int); ++ ++extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd ++ (bfd *, struct bfd_link_info *); ++ ++/* ELF ARM mapping symbol support */ ++extern bfd_boolean bfd_is_arm_mapping_symbol_name ++ (const char * name); ++ ++/* ARM Note section processing. */ ++extern bfd_boolean bfd_arm_merge_machines ++ (bfd *, bfd *); ++ ++extern bfd_boolean bfd_arm_update_notes ++ (bfd *, const char *); ++ ++extern unsigned int bfd_arm_get_mach_from_notes ++ (bfd *, const char *); ++ ++/* TI COFF load page support. */ ++extern void bfd_ticoff_set_section_load_page ++ (struct bfd_section *, int); ++ ++extern int bfd_ticoff_get_section_load_page ++ (struct bfd_section *); ++ ++/* H8/300 functions. */ ++extern bfd_vma bfd_h8300_pad_address ++ (bfd *, bfd_vma); ++ ++/* IA64 Itanium code generation. Called from linker. */ ++extern void bfd_elf32_ia64_after_parse ++ (int); ++ ++extern void bfd_elf64_ia64_after_parse ++ (int); ++ ++/* This structure is used for a comdat section, as in PE. A comdat ++ section is associated with a particular symbol. When the linker ++ sees a comdat section, it keeps only one of the sections with a ++ given name and associated with a given symbol. */ ++ ++struct coff_comdat_info ++{ ++ /* The name of the symbol associated with a comdat section. */ ++ const char *name; ++ ++ /* The local symbol table index of the symbol associated with a ++ comdat section. This is only meaningful to the object file format ++ specific code; it is not an index into the list returned by ++ bfd_canonicalize_symtab. */ ++ long symbol; ++}; ++ ++extern struct coff_comdat_info *bfd_coff_get_comdat_section ++ (bfd *, struct bfd_section *); ++ ++/* Extracted from init.c. */ ++void bfd_init (void); ++ ++/* Extracted from opncls.c. */ ++bfd *bfd_fopen (const char *filename, const char *target, ++ const char *mode, int fd); ++ ++bfd *bfd_openr (const char *filename, const char *target); ++ ++bfd *bfd_fdopenr (const char *filename, const char *target, int fd); ++ ++bfd *bfd_openstreamr (const char *, const char *, void *); ++ ++bfd *bfd_openr_iovec (const char *filename, const char *target, ++ void *(*open) (struct bfd *nbfd, ++ void *open_closure), ++ void *open_closure, ++ file_ptr (*pread) (struct bfd *nbfd, ++ void *stream, ++ void *buf, ++ file_ptr nbytes, ++ file_ptr offset), ++ int (*close) (struct bfd *nbfd, ++ void *stream)); ++ ++bfd *bfd_openw (const char *filename, const char *target); ++ ++bfd_boolean bfd_close (bfd *abfd); ++ ++bfd_boolean bfd_close_all_done (bfd *); ++ ++bfd *bfd_create (const char *filename, bfd *templ); ++ ++bfd_boolean bfd_make_writable (bfd *abfd); ++ ++bfd_boolean bfd_make_readable (bfd *abfd); ++ ++unsigned long bfd_calc_gnu_debuglink_crc32 ++ (unsigned long crc, const unsigned char *buf, bfd_size_type len); ++ ++char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); ++ ++struct bfd_section *bfd_create_gnu_debuglink_section ++ (bfd *abfd, const char *filename); ++ ++bfd_boolean bfd_fill_in_gnu_debuglink_section ++ (bfd *abfd, struct bfd_section *sect, const char *filename); ++ ++/* Extracted from libbfd.c. */ ++ ++/* Byte swapping macros for user section data. */ ++ ++#define bfd_put_8(abfd, val, ptr) \ ++ ((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) ++#define bfd_put_signed_8 \ ++ bfd_put_8 ++#define bfd_get_8(abfd, ptr) \ ++ (*(unsigned char *) (ptr) & 0xff) ++#define bfd_get_signed_8(abfd, ptr) \ ++ (((*(unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) ++ ++#define bfd_put_16(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx16, ((val),(ptr))) ++#define bfd_put_signed_16 \ ++ bfd_put_16 ++#define bfd_get_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx16, (ptr)) ++#define bfd_get_signed_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) ++ ++#define bfd_put_32(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx32, ((val),(ptr))) ++#define bfd_put_signed_32 \ ++ bfd_put_32 ++#define bfd_get_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx32, (ptr)) ++#define bfd_get_signed_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_32, (ptr)) ++ ++#define bfd_put_64(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx64, ((val), (ptr))) ++#define bfd_put_signed_64 \ ++ bfd_put_64 ++#define bfd_get_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx64, (ptr)) ++#define bfd_get_signed_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_64, (ptr)) ++ ++#define bfd_get(bits, abfd, ptr) \ ++ ((bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ ++ : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ ++ : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ ++ : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ ++ : (abort (), (bfd_vma) - 1)) ++ ++#define bfd_put(bits, abfd, val, ptr) \ ++ ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ ++ : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ ++ : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ ++ : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ ++ : (abort (), (void) 0)) ++ ++ ++/* Byte swapping macros for file header data. */ ++ ++#define bfd_h_put_8(abfd, val, ptr) \ ++ bfd_put_8 (abfd, val, ptr) ++#define bfd_h_put_signed_8(abfd, val, ptr) \ ++ bfd_put_8 (abfd, val, ptr) ++#define bfd_h_get_8(abfd, ptr) \ ++ bfd_get_8 (abfd, ptr) ++#define bfd_h_get_signed_8(abfd, ptr) \ ++ bfd_get_signed_8 (abfd, ptr) ++ ++#define bfd_h_put_16(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) ++#define bfd_h_put_signed_16 \ ++ bfd_h_put_16 ++#define bfd_h_get_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx16, (ptr)) ++#define bfd_h_get_signed_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) ++ ++#define bfd_h_put_32(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) ++#define bfd_h_put_signed_32 \ ++ bfd_h_put_32 ++#define bfd_h_get_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx32, (ptr)) ++#define bfd_h_get_signed_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) ++ ++#define bfd_h_put_64(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) ++#define bfd_h_put_signed_64 \ ++ bfd_h_put_64 ++#define bfd_h_get_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx64, (ptr)) ++#define bfd_h_get_signed_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) ++ ++/* Aliases for the above, which should eventually go away. */ ++ ++#define H_PUT_64 bfd_h_put_64 ++#define H_PUT_32 bfd_h_put_32 ++#define H_PUT_16 bfd_h_put_16 ++#define H_PUT_8 bfd_h_put_8 ++#define H_PUT_S64 bfd_h_put_signed_64 ++#define H_PUT_S32 bfd_h_put_signed_32 ++#define H_PUT_S16 bfd_h_put_signed_16 ++#define H_PUT_S8 bfd_h_put_signed_8 ++#define H_GET_64 bfd_h_get_64 ++#define H_GET_32 bfd_h_get_32 ++#define H_GET_16 bfd_h_get_16 ++#define H_GET_8 bfd_h_get_8 ++#define H_GET_S64 bfd_h_get_signed_64 ++#define H_GET_S32 bfd_h_get_signed_32 ++#define H_GET_S16 bfd_h_get_signed_16 ++#define H_GET_S8 bfd_h_get_signed_8 ++ ++ ++/* Extracted from bfdio.c. */ ++long bfd_get_mtime (bfd *abfd); ++ ++long bfd_get_size (bfd *abfd); ++ ++/* Extracted from bfdwin.c. */ ++/* Extracted from section.c. */ ++typedef struct bfd_section ++{ ++ /* The name of the section; the name isn't a copy, the pointer is ++ the same as that passed to bfd_make_section. */ ++ const char *name; ++ ++ /* A unique sequence number. */ ++ int id; ++ ++ /* Which section in the bfd; 0..n-1 as sections are created in a bfd. */ ++ int index; ++ ++ /* The next section in the list belonging to the BFD, or NULL. */ ++ struct bfd_section *next; ++ ++ /* The previous section in the list belonging to the BFD, or NULL. */ ++ struct bfd_section *prev; ++ ++ /* The field flags contains attributes of the section. Some ++ flags are read in from the object file, and some are ++ synthesized from other information. */ ++ flagword flags; ++ ++#define SEC_NO_FLAGS 0x000 ++ ++ /* Tells the OS to allocate space for this section when loading. ++ This is clear for a section containing debug information only. */ ++#define SEC_ALLOC 0x001 ++ ++ /* Tells the OS to load the section from the file when loading. ++ This is clear for a .bss section. */ ++#define SEC_LOAD 0x002 ++ ++ /* The section contains data still to be relocated, so there is ++ some relocation information too. */ ++#define SEC_RELOC 0x004 ++ ++ /* A signal to the OS that the section contains read only data. */ ++#define SEC_READONLY 0x008 ++ ++ /* The section contains code only. */ ++#define SEC_CODE 0x010 ++ ++ /* The section contains data only. */ ++#define SEC_DATA 0x020 ++ ++ /* The section will reside in ROM. */ ++#define SEC_ROM 0x040 ++ ++ /* The section contains constructor information. This section ++ type is used by the linker to create lists of constructors and ++ destructors used by <>. When a back end sees a symbol ++ which should be used in a constructor list, it creates a new ++ section for the type of name (e.g., <<__CTOR_LIST__>>), attaches ++ the symbol to it, and builds a relocation. To build the lists ++ of constructors, all the linker has to do is catenate all the ++ sections called <<__CTOR_LIST__>> and relocate the data ++ contained within - exactly the operations it would peform on ++ standard data. */ ++#define SEC_CONSTRUCTOR 0x080 ++ ++ /* The section has contents - a data section could be ++ <> | <>; a debug section could be ++ <> */ ++#define SEC_HAS_CONTENTS 0x100 ++ ++ /* An instruction to the linker to not output the section ++ even if it has information which would normally be written. */ ++#define SEC_NEVER_LOAD 0x200 ++ ++ /* The section contains thread local data. */ ++#define SEC_THREAD_LOCAL 0x400 ++ ++ /* The section has GOT references. This flag is only for the ++ linker, and is currently only used by the elf32-hppa back end. ++ It will be set if global offset table references were detected ++ in this section, which indicate to the linker that the section ++ contains PIC code, and must be handled specially when doing a ++ static link. */ ++#define SEC_HAS_GOT_REF 0x800 ++ ++ /* The section contains common symbols (symbols may be defined ++ multiple times, the value of a symbol is the amount of ++ space it requires, and the largest symbol value is the one ++ used). Most targets have exactly one of these (which we ++ translate to bfd_com_section_ptr), but ECOFF has two. */ ++#define SEC_IS_COMMON 0x1000 ++ ++ /* The section contains only debugging information. For ++ example, this is set for ELF .debug and .stab sections. ++ strip tests this flag to see if a section can be ++ discarded. */ ++#define SEC_DEBUGGING 0x2000 ++ ++ /* The contents of this section are held in memory pointed to ++ by the contents field. This is checked by bfd_get_section_contents, ++ and the data is retrieved from memory if appropriate. */ ++#define SEC_IN_MEMORY 0x4000 ++ ++ /* The contents of this section are to be excluded by the ++ linker for executable and shared objects unless those ++ objects are to be further relocated. */ ++#define SEC_EXCLUDE 0x8000 ++ ++ /* The contents of this section are to be sorted based on the sum of ++ the symbol and addend values specified by the associated relocation ++ entries. Entries without associated relocation entries will be ++ appended to the end of the section in an unspecified order. */ ++#define SEC_SORT_ENTRIES 0x10000 ++ ++ /* When linking, duplicate sections of the same name should be ++ discarded, rather than being combined into a single section as ++ is usually done. This is similar to how common symbols are ++ handled. See SEC_LINK_DUPLICATES below. */ ++#define SEC_LINK_ONCE 0x20000 ++ ++ /* If SEC_LINK_ONCE is set, this bitfield describes how the linker ++ should handle duplicate sections. */ ++#define SEC_LINK_DUPLICATES 0x40000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that duplicate ++ sections with the same name should simply be discarded. */ ++#define SEC_LINK_DUPLICATES_DISCARD 0x0 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if there are any duplicate sections, although ++ it should still only link one copy. */ ++#define SEC_LINK_DUPLICATES_ONE_ONLY 0x80000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if any duplicate sections are a different size. */ ++#define SEC_LINK_DUPLICATES_SAME_SIZE 0x100000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if any duplicate sections contain different ++ contents. */ ++#define SEC_LINK_DUPLICATES_SAME_CONTENTS \ ++ (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) ++ ++ /* This section was created by the linker as part of dynamic ++ relocation or other arcane processing. It is skipped when ++ going through the first-pass output, trusting that someone ++ else up the line will take care of it later. */ ++#define SEC_LINKER_CREATED 0x200000 ++ ++ /* This section should not be subject to garbage collection. */ ++#define SEC_KEEP 0x400000 ++ ++ /* This section contains "short" data, and should be placed ++ "near" the GP. */ ++#define SEC_SMALL_DATA 0x800000 ++ ++ /* Attempt to merge identical entities in the section. ++ Entity size is given in the entsize field. */ ++#define SEC_MERGE 0x1000000 ++ ++ /* If given with SEC_MERGE, entities to merge are zero terminated ++ strings where entsize specifies character size instead of fixed ++ size entries. */ ++#define SEC_STRINGS 0x2000000 ++ ++ /* This section contains data about section groups. */ ++#define SEC_GROUP 0x4000000 ++ ++ /* The section is a COFF shared library section. This flag is ++ only for the linker. If this type of section appears in ++ the input file, the linker must copy it to the output file ++ without changing the vma or size. FIXME: Although this ++ was originally intended to be general, it really is COFF ++ specific (and the flag was renamed to indicate this). It ++ might be cleaner to have some more general mechanism to ++ allow the back end to control what the linker does with ++ sections. */ ++#define SEC_COFF_SHARED_LIBRARY 0x10000000 ++ ++ /* This section contains data which may be shared with other ++ executables or shared objects. This is for COFF only. */ ++#define SEC_COFF_SHARED 0x20000000 ++ ++ /* When a section with this flag is being linked, then if the size of ++ the input section is less than a page, it should not cross a page ++ boundary. If the size of the input section is one page or more, ++ it should be aligned on a page boundary. This is for TI ++ TMS320C54X only. */ ++#define SEC_TIC54X_BLOCK 0x40000000 ++ ++ /* Conditionally link this section; do not link if there are no ++ references found to any symbol in the section. This is for TI ++ TMS320C54X only. */ ++#define SEC_TIC54X_CLINK 0x80000000 ++ ++ /* End of section flags. */ ++ ++ /* Some internal packed boolean fields. */ ++ ++ /* See the vma field. */ ++ unsigned int user_set_vma : 1; ++ ++ /* A mark flag used by some of the linker backends. */ ++ unsigned int linker_mark : 1; ++ ++ /* Another mark flag used by some of the linker backends. Set for ++ output sections that have an input section. */ ++ unsigned int linker_has_input : 1; ++ ++ /* Mark flags used by some linker backends for garbage collection. */ ++ unsigned int gc_mark : 1; ++ unsigned int gc_mark_from_eh : 1; ++ ++ /* The following flags are used by the ELF linker. */ ++ ++ /* Mark sections which have been allocated to segments. */ ++ unsigned int segment_mark : 1; ++ ++ /* Type of sec_info information. */ ++ unsigned int sec_info_type:3; ++#define ELF_INFO_TYPE_NONE 0 ++#define ELF_INFO_TYPE_STABS 1 ++#define ELF_INFO_TYPE_MERGE 2 ++#define ELF_INFO_TYPE_EH_FRAME 3 ++#define ELF_INFO_TYPE_JUST_SYMS 4 ++ ++ /* Nonzero if this section uses RELA relocations, rather than REL. */ ++ unsigned int use_rela_p:1; ++ ++ /* Bits used by various backends. The generic code doesn't touch ++ these fields. */ ++ ++ /* Nonzero if this section has TLS related relocations. */ ++ unsigned int has_tls_reloc:1; ++ ++ /* Nonzero if this section has a gp reloc. */ ++ unsigned int has_gp_reloc:1; ++ ++ /* Nonzero if this section needs the relax finalize pass. */ ++ unsigned int need_finalize_relax:1; ++ ++ /* Whether relocations have been processed. */ ++ unsigned int reloc_done : 1; ++ ++ /* End of internal packed boolean fields. */ ++ ++ /* The virtual memory address of the section - where it will be ++ at run time. The symbols are relocated against this. The ++ user_set_vma flag is maintained by bfd; if it's not set, the ++ backend can assign addresses (for example, in <>, where ++ the default address for <<.data>> is dependent on the specific ++ target and various flags). */ ++ bfd_vma vma; ++ ++ /* The load address of the section - where it would be in a ++ rom image; really only used for writing section header ++ information. */ ++ bfd_vma lma; ++ ++ /* The size of the section in octets, as it will be output. ++ Contains a value even if the section has no contents (e.g., the ++ size of <<.bss>>). */ ++ bfd_size_type size; ++ ++ /* For input sections, the original size on disk of the section, in ++ octets. This field is used by the linker relaxation code. It is ++ currently only set for sections where the linker relaxation scheme ++ doesn't cache altered section and reloc contents (stabs, eh_frame, ++ SEC_MERGE, some coff relaxing targets), and thus the original size ++ needs to be kept to read the section multiple times. ++ For output sections, rawsize holds the section size calculated on ++ a previous linker relaxation pass. */ ++ bfd_size_type rawsize; ++ ++ /* If this section is going to be output, then this value is the ++ offset in *bytes* into the output section of the first byte in the ++ input section (byte ==> smallest addressable unit on the ++ target). In most cases, if this was going to start at the ++ 100th octet (8-bit quantity) in the output section, this value ++ would be 100. However, if the target byte size is 16 bits ++ (bfd_octets_per_byte is "2"), this value would be 50. */ ++ bfd_vma output_offset; ++ ++ /* The output section through which to map on output. */ ++ struct bfd_section *output_section; ++ ++ /* The alignment requirement of the section, as an exponent of 2 - ++ e.g., 3 aligns to 2^3 (or 8). */ ++ unsigned int alignment_power; ++ ++ /* If an input section, a pointer to a vector of relocation ++ records for the data in this section. */ ++ struct reloc_cache_entry *relocation; ++ ++ /* If an output section, a pointer to a vector of pointers to ++ relocation records for the data in this section. */ ++ struct reloc_cache_entry **orelocation; ++ ++ /* The number of relocation records in one of the above. */ ++ unsigned reloc_count; ++ ++ /* Information below is back end specific - and not always used ++ or updated. */ ++ ++ /* File position of section data. */ ++ file_ptr filepos; ++ ++ /* File position of relocation info. */ ++ file_ptr rel_filepos; ++ ++ /* File position of line data. */ ++ file_ptr line_filepos; ++ ++ /* Pointer to data for applications. */ ++ void *userdata; ++ ++ /* If the SEC_IN_MEMORY flag is set, this points to the actual ++ contents. */ ++ unsigned char *contents; ++ ++ /* Attached line number information. */ ++ alent *lineno; ++ ++ /* Number of line number records. */ ++ unsigned int lineno_count; ++ ++ /* Entity size for merging purposes. */ ++ unsigned int entsize; ++ ++ /* Points to the kept section if this section is a link-once section, ++ and is discarded. */ ++ struct bfd_section *kept_section; ++ ++ /* When a section is being output, this value changes as more ++ linenumbers are written out. */ ++ file_ptr moving_line_filepos; ++ ++ /* What the section number is in the target world. */ ++ int target_index; ++ ++ void *used_by_bfd; ++ ++ /* If this is a constructor section then here is a list of the ++ relocations created to relocate items within it. */ ++ struct relent_chain *constructor_chain; ++ ++ /* The BFD which owns the section. */ ++ bfd *owner; ++ ++ /* A symbol which points at this section only. */ ++ struct bfd_symbol *symbol; ++ struct bfd_symbol **symbol_ptr_ptr; ++ ++ /* Early in the link process, map_head and map_tail are used to build ++ a list of input sections attached to an output section. Later, ++ output sections use these fields for a list of bfd_link_order ++ structs. */ ++ union { ++ struct bfd_link_order *link_order; ++ struct bfd_section *s; ++ } map_head, map_tail; ++} asection; ++ ++/* These sections are global, and are managed by BFD. The application ++ and target back end are not permitted to change the values in ++ these sections. New code should use the section_ptr macros rather ++ than referring directly to the const sections. The const sections ++ may eventually vanish. */ ++#define BFD_ABS_SECTION_NAME "*ABS*" ++#define BFD_UND_SECTION_NAME "*UND*" ++#define BFD_COM_SECTION_NAME "*COM*" ++#define BFD_IND_SECTION_NAME "*IND*" ++ ++/* The absolute section. */ ++extern asection bfd_abs_section; ++#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) ++#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) ++/* Pointer to the undefined section. */ ++extern asection bfd_und_section; ++#define bfd_und_section_ptr ((asection *) &bfd_und_section) ++#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) ++/* Pointer to the common section. */ ++extern asection bfd_com_section; ++#define bfd_com_section_ptr ((asection *) &bfd_com_section) ++/* Pointer to the indirect section. */ ++extern asection bfd_ind_section; ++#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) ++#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) ++ ++#define bfd_is_const_section(SEC) \ ++ ( ((SEC) == bfd_abs_section_ptr) \ ++ || ((SEC) == bfd_und_section_ptr) \ ++ || ((SEC) == bfd_com_section_ptr) \ ++ || ((SEC) == bfd_ind_section_ptr)) ++ ++extern const struct bfd_symbol * const bfd_abs_symbol; ++extern const struct bfd_symbol * const bfd_com_symbol; ++extern const struct bfd_symbol * const bfd_und_symbol; ++extern const struct bfd_symbol * const bfd_ind_symbol; ++ ++/* Macros to handle insertion and deletion of a bfd's sections. These ++ only handle the list pointers, ie. do not adjust section_count, ++ target_index etc. */ ++#define bfd_section_list_remove(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ asection *_next = _s->next; \ ++ asection *_prev = _s->prev; \ ++ if (_prev) \ ++ _prev->next = _next; \ ++ else \ ++ (ABFD)->sections = _next; \ ++ if (_next) \ ++ _next->prev = _prev; \ ++ else \ ++ (ABFD)->section_last = _prev; \ ++ } \ ++ while (0) ++#define bfd_section_list_append(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ bfd *_abfd = ABFD; \ ++ _s->next = NULL; \ ++ if (_abfd->section_last) \ ++ { \ ++ _s->prev = _abfd->section_last; \ ++ _abfd->section_last->next = _s; \ ++ } \ ++ else \ ++ { \ ++ _s->prev = NULL; \ ++ _abfd->sections = _s; \ ++ } \ ++ _abfd->section_last = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_prepend(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ bfd *_abfd = ABFD; \ ++ _s->prev = NULL; \ ++ if (_abfd->sections) \ ++ { \ ++ _s->next = _abfd->sections; \ ++ _abfd->sections->prev = _s; \ ++ } \ ++ else \ ++ { \ ++ _s->next = NULL; \ ++ _abfd->section_last = _s; \ ++ } \ ++ _abfd->sections = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_insert_after(ABFD, A, S) \ ++ do \ ++ { \ ++ asection *_a = A; \ ++ asection *_s = S; \ ++ asection *_next = _a->next; \ ++ _s->next = _next; \ ++ _s->prev = _a; \ ++ _a->next = _s; \ ++ if (_next) \ ++ _next->prev = _s; \ ++ else \ ++ (ABFD)->section_last = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_insert_before(ABFD, B, S) \ ++ do \ ++ { \ ++ asection *_b = B; \ ++ asection *_s = S; \ ++ asection *_prev = _b->prev; \ ++ _s->prev = _prev; \ ++ _s->next = _b; \ ++ _b->prev = _s; \ ++ if (_prev) \ ++ _prev->next = _s; \ ++ else \ ++ (ABFD)->sections = _s; \ ++ } \ ++ while (0) ++#define bfd_section_removed_from_list(ABFD, S) \ ++ ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) ++ ++#define BFD_FAKE_SECTION(SEC, FLAGS, SYM, SYM_PTR, NAME, IDX) \ ++ /* name, id, index, next, prev, flags, user_set_vma, */ \ ++ { NAME, IDX, 0, NULL, NULL, FLAGS, 0, \ ++ \ ++ /* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh, */ \ ++ 0, 0, 1, 0, \ ++ \ ++ /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc, */ \ ++ 0, 0, 0, 0, \ ++ \ ++ /* has_gp_reloc, need_finalize_relax, reloc_done, */ \ ++ 0, 0, 0, \ ++ \ ++ /* vma, lma, size, rawsize */ \ ++ 0, 0, 0, 0, \ ++ \ ++ /* output_offset, output_section, alignment_power, */ \ ++ 0, (struct bfd_section *) &SEC, 0, \ ++ \ ++ /* relocation, orelocation, reloc_count, filepos, rel_filepos, */ \ ++ NULL, NULL, 0, 0, 0, \ ++ \ ++ /* line_filepos, userdata, contents, lineno, lineno_count, */ \ ++ 0, NULL, NULL, NULL, 0, \ ++ \ ++ /* entsize, kept_section, moving_line_filepos, */ \ ++ 0, NULL, 0, \ ++ \ ++ /* target_index, used_by_bfd, constructor_chain, owner, */ \ ++ 0, NULL, NULL, NULL, \ ++ \ ++ /* symbol, */ \ ++ (struct bfd_symbol *) SYM, \ ++ \ ++ /* symbol_ptr_ptr, */ \ ++ (struct bfd_symbol **) SYM_PTR, \ ++ \ ++ /* map_head, map_tail */ \ ++ { NULL }, { NULL } \ ++ } ++ ++void bfd_section_list_clear (bfd *); ++ ++asection *bfd_get_section_by_name (bfd *abfd, const char *name); ++ ++asection *bfd_get_section_by_name_if ++ (bfd *abfd, ++ const char *name, ++ bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++char *bfd_get_unique_section_name ++ (bfd *abfd, const char *templat, int *count); ++ ++asection *bfd_make_section_old_way (bfd *abfd, const char *name); ++ ++asection *bfd_make_section_anyway_with_flags ++ (bfd *abfd, const char *name, flagword flags); ++ ++asection *bfd_make_section_anyway (bfd *abfd, const char *name); ++ ++asection *bfd_make_section_with_flags ++ (bfd *, const char *name, flagword flags); ++ ++asection *bfd_make_section (bfd *, const char *name); ++ ++bfd_boolean bfd_set_section_flags ++ (bfd *abfd, asection *sec, flagword flags); ++ ++void bfd_map_over_sections ++ (bfd *abfd, ++ void (*func) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++asection *bfd_sections_find_if ++ (bfd *abfd, ++ bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++bfd_boolean bfd_set_section_size ++ (bfd *abfd, asection *sec, bfd_size_type val); ++ ++bfd_boolean bfd_set_section_contents ++ (bfd *abfd, asection *section, const void *data, ++ file_ptr offset, bfd_size_type count); ++ ++bfd_boolean bfd_get_section_contents ++ (bfd *abfd, asection *section, void *location, file_ptr offset, ++ bfd_size_type count); ++ ++bfd_boolean bfd_malloc_and_get_section ++ (bfd *abfd, asection *section, bfd_byte **buf); ++ ++bfd_boolean bfd_copy_private_section_data ++ (bfd *ibfd, asection *isec, bfd *obfd, asection *osec); ++ ++#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ ++ BFD_SEND (obfd, _bfd_copy_private_section_data, \ ++ (ibfd, isection, obfd, osection)) ++bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); ++ ++bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); ++ ++/* Extracted from archures.c. */ ++enum bfd_architecture ++{ ++ bfd_arch_unknown, /* File arch not known. */ ++ bfd_arch_obscure, /* Arch known, not one of these. */ ++ bfd_arch_m68k, /* Motorola 68xxx */ ++#define bfd_mach_m68000 1 ++#define bfd_mach_m68008 2 ++#define bfd_mach_m68010 3 ++#define bfd_mach_m68020 4 ++#define bfd_mach_m68030 5 ++#define bfd_mach_m68040 6 ++#define bfd_mach_m68060 7 ++#define bfd_mach_cpu32 8 ++#define bfd_mach_mcf5200 9 ++#define bfd_mach_mcf5206e 10 ++#define bfd_mach_mcf5307 11 ++#define bfd_mach_mcf5407 12 ++#define bfd_mach_mcf528x 13 ++#define bfd_mach_mcfv4e 14 ++#define bfd_mach_mcf521x 15 ++#define bfd_mach_mcf5249 16 ++#define bfd_mach_mcf547x 17 ++#define bfd_mach_mcf548x 18 ++ bfd_arch_vax, /* DEC Vax */ ++ bfd_arch_i960, /* Intel 960 */ ++ /* The order of the following is important. ++ lower number indicates a machine type that ++ only accepts a subset of the instructions ++ available to machines with higher numbers. ++ The exception is the "ca", which is ++ incompatible with all other machines except ++ "core". */ ++ ++#define bfd_mach_i960_core 1 ++#define bfd_mach_i960_ka_sa 2 ++#define bfd_mach_i960_kb_sb 3 ++#define bfd_mach_i960_mc 4 ++#define bfd_mach_i960_xa 5 ++#define bfd_mach_i960_ca 6 ++#define bfd_mach_i960_jx 7 ++#define bfd_mach_i960_hx 8 ++ ++ bfd_arch_or32, /* OpenRISC 32 */ ++ ++ bfd_arch_sparc, /* SPARC */ ++#define bfd_mach_sparc 1 ++/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ ++#define bfd_mach_sparc_sparclet 2 ++#define bfd_mach_sparc_sparclite 3 ++#define bfd_mach_sparc_v8plus 4 ++#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ ++#define bfd_mach_sparc_sparclite_le 6 ++#define bfd_mach_sparc_v9 7 ++#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ ++#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ ++#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ ++/* Nonzero if MACH has the v9 instruction set. */ ++#define bfd_mach_sparc_v9_p(mach) \ ++ ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ ++ && (mach) != bfd_mach_sparc_sparclite_le) ++/* Nonzero if MACH is a 64 bit sparc architecture. */ ++#define bfd_mach_sparc_64bit_p(mach) \ ++ ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) ++ bfd_arch_mips, /* MIPS Rxxxx */ ++#define bfd_mach_mips3000 3000 ++#define bfd_mach_mips3900 3900 ++#define bfd_mach_mips4000 4000 ++#define bfd_mach_mips4010 4010 ++#define bfd_mach_mips4100 4100 ++#define bfd_mach_mips4111 4111 ++#define bfd_mach_mips4120 4120 ++#define bfd_mach_mips4300 4300 ++#define bfd_mach_mips4400 4400 ++#define bfd_mach_mips4600 4600 ++#define bfd_mach_mips4650 4650 ++#define bfd_mach_mips5000 5000 ++#define bfd_mach_mips5400 5400 ++#define bfd_mach_mips5500 5500 ++#define bfd_mach_mips6000 6000 ++#define bfd_mach_mips7000 7000 ++#define bfd_mach_mips8000 8000 ++#define bfd_mach_mips9000 9000 ++#define bfd_mach_mips10000 10000 ++#define bfd_mach_mips12000 12000 ++#define bfd_mach_mips16 16 ++#define bfd_mach_mips5 5 ++#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ ++#define bfd_mach_mipsisa32 32 ++#define bfd_mach_mipsisa32r2 33 ++#define bfd_mach_mipsisa64 64 ++#define bfd_mach_mipsisa64r2 65 ++ bfd_arch_i386, /* Intel 386 */ ++#define bfd_mach_i386_i386 1 ++#define bfd_mach_i386_i8086 2 ++#define bfd_mach_i386_i386_intel_syntax 3 ++#define bfd_mach_x86_64 64 ++#define bfd_mach_x86_64_intel_syntax 65 ++ bfd_arch_we32k, /* AT&T WE32xxx */ ++ bfd_arch_tahoe, /* CCI/Harris Tahoe */ ++ bfd_arch_i860, /* Intel 860 */ ++ bfd_arch_i370, /* IBM 360/370 Mainframes */ ++ bfd_arch_romp, /* IBM ROMP PC/RT */ ++ bfd_arch_convex, /* Convex */ ++ bfd_arch_m88k, /* Motorola 88xxx */ ++ bfd_arch_m98k, /* Motorola 98xxx */ ++ bfd_arch_pyramid, /* Pyramid Technology */ ++ bfd_arch_h8300, /* Renesas H8/300 (formerly Hitachi H8/300) */ ++#define bfd_mach_h8300 1 ++#define bfd_mach_h8300h 2 ++#define bfd_mach_h8300s 3 ++#define bfd_mach_h8300hn 4 ++#define bfd_mach_h8300sn 5 ++#define bfd_mach_h8300sx 6 ++#define bfd_mach_h8300sxn 7 ++ bfd_arch_pdp11, /* DEC PDP-11 */ ++ bfd_arch_powerpc, /* PowerPC */ ++#define bfd_mach_ppc 32 ++#define bfd_mach_ppc64 64 ++#define bfd_mach_ppc_403 403 ++#define bfd_mach_ppc_403gc 4030 ++#define bfd_mach_ppc_505 505 ++#define bfd_mach_ppc_601 601 ++#define bfd_mach_ppc_602 602 ++#define bfd_mach_ppc_603 603 ++#define bfd_mach_ppc_ec603e 6031 ++#define bfd_mach_ppc_604 604 ++#define bfd_mach_ppc_620 620 ++#define bfd_mach_ppc_630 630 ++#define bfd_mach_ppc_750 750 ++#define bfd_mach_ppc_860 860 ++#define bfd_mach_ppc_a35 35 ++#define bfd_mach_ppc_rs64ii 642 ++#define bfd_mach_ppc_rs64iii 643 ++#define bfd_mach_ppc_7400 7400 ++#define bfd_mach_ppc_e500 500 ++ bfd_arch_rs6000, /* IBM RS/6000 */ ++#define bfd_mach_rs6k 6000 ++#define bfd_mach_rs6k_rs1 6001 ++#define bfd_mach_rs6k_rsc 6003 ++#define bfd_mach_rs6k_rs2 6002 ++ bfd_arch_hppa, /* HP PA RISC */ ++#define bfd_mach_hppa10 10 ++#define bfd_mach_hppa11 11 ++#define bfd_mach_hppa20 20 ++#define bfd_mach_hppa20w 25 ++ bfd_arch_d10v, /* Mitsubishi D10V */ ++#define bfd_mach_d10v 1 ++#define bfd_mach_d10v_ts2 2 ++#define bfd_mach_d10v_ts3 3 ++ bfd_arch_d30v, /* Mitsubishi D30V */ ++ bfd_arch_dlx, /* DLX */ ++ bfd_arch_m68hc11, /* Motorola 68HC11 */ ++ bfd_arch_m68hc12, /* Motorola 68HC12 */ ++#define bfd_mach_m6812_default 0 ++#define bfd_mach_m6812 1 ++#define bfd_mach_m6812s 2 ++ bfd_arch_z8k, /* Zilog Z8000 */ ++#define bfd_mach_z8001 1 ++#define bfd_mach_z8002 2 ++ bfd_arch_h8500, /* Renesas H8/500 (formerly Hitachi H8/500) */ ++ bfd_arch_sh, /* Renesas / SuperH SH (formerly Hitachi SH) */ ++#define bfd_mach_sh 1 ++#define bfd_mach_sh2 0x20 ++#define bfd_mach_sh_dsp 0x2d ++#define bfd_mach_sh2a 0x2a ++#define bfd_mach_sh2a_nofpu 0x2b ++#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 ++#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 ++#define bfd_mach_sh2a_or_sh4 0x2a3 ++#define bfd_mach_sh2a_or_sh3e 0x2a4 ++#define bfd_mach_sh2e 0x2e ++#define bfd_mach_sh3 0x30 ++#define bfd_mach_sh3_nommu 0x31 ++#define bfd_mach_sh3_dsp 0x3d ++#define bfd_mach_sh3e 0x3e ++#define bfd_mach_sh4 0x40 ++#define bfd_mach_sh4_nofpu 0x41 ++#define bfd_mach_sh4_nommu_nofpu 0x42 ++#define bfd_mach_sh4a 0x4a ++#define bfd_mach_sh4a_nofpu 0x4b ++#define bfd_mach_sh4al_dsp 0x4d ++#define bfd_mach_sh5 0x50 ++ bfd_arch_alpha, /* Dec Alpha */ ++#define bfd_mach_alpha_ev4 0x10 ++#define bfd_mach_alpha_ev5 0x20 ++#define bfd_mach_alpha_ev6 0x30 ++ bfd_arch_arm, /* Advanced Risc Machines ARM. */ ++#define bfd_mach_arm_unknown 0 ++#define bfd_mach_arm_2 1 ++#define bfd_mach_arm_2a 2 ++#define bfd_mach_arm_3 3 ++#define bfd_mach_arm_3M 4 ++#define bfd_mach_arm_4 5 ++#define bfd_mach_arm_4T 6 ++#define bfd_mach_arm_5 7 ++#define bfd_mach_arm_5T 8 ++#define bfd_mach_arm_5TE 9 ++#define bfd_mach_arm_XScale 10 ++#define bfd_mach_arm_ep9312 11 ++#define bfd_mach_arm_iWMMXt 12 ++ bfd_arch_ns32k, /* National Semiconductors ns32000 */ ++ bfd_arch_w65, /* WDC 65816 */ ++ bfd_arch_tic30, /* Texas Instruments TMS320C30 */ ++ bfd_arch_tic4x, /* Texas Instruments TMS320C3X/4X */ ++#define bfd_mach_tic3x 30 ++#define bfd_mach_tic4x 40 ++ bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ ++ bfd_arch_tic80, /* TI TMS320c80 (MVP) */ ++ bfd_arch_v850, /* NEC V850 */ ++#define bfd_mach_v850 1 ++#define bfd_mach_v850e 'E' ++#define bfd_mach_v850e1 '1' ++ bfd_arch_arc, /* ARC Cores */ ++#define bfd_mach_arc_5 5 ++#define bfd_mach_arc_6 6 ++#define bfd_mach_arc_7 7 ++#define bfd_mach_arc_8 8 ++ bfd_arch_m32c, /* Renesas M16C/M32C. */ ++#define bfd_mach_m16c 0x75 ++#define bfd_mach_m32c 0x78 ++ bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ ++#define bfd_mach_m32r 1 /* For backwards compatibility. */ ++#define bfd_mach_m32rx 'x' ++#define bfd_mach_m32r2 '2' ++ bfd_arch_mn10200, /* Matsushita MN10200 */ ++ bfd_arch_mn10300, /* Matsushita MN10300 */ ++#define bfd_mach_mn10300 300 ++#define bfd_mach_am33 330 ++#define bfd_mach_am33_2 332 ++ bfd_arch_fr30, ++#define bfd_mach_fr30 0x46523330 ++ bfd_arch_frv, ++#define bfd_mach_frv 1 ++#define bfd_mach_frvsimple 2 ++#define bfd_mach_fr300 300 ++#define bfd_mach_fr400 400 ++#define bfd_mach_fr450 450 ++#define bfd_mach_frvtomcat 499 /* fr500 prototype */ ++#define bfd_mach_fr500 500 ++#define bfd_mach_fr550 550 ++ bfd_arch_mcore, ++ bfd_arch_ia64, /* HP/Intel ia64 */ ++#define bfd_mach_ia64_elf64 64 ++#define bfd_mach_ia64_elf32 32 ++ bfd_arch_ip2k, /* Ubicom IP2K microcontrollers. */ ++#define bfd_mach_ip2022 1 ++#define bfd_mach_ip2022ext 2 ++ bfd_arch_iq2000, /* Vitesse IQ2000. */ ++#define bfd_mach_iq2000 1 ++#define bfd_mach_iq10 2 ++ bfd_arch_mt, ++#define bfd_mach_ms1 1 ++#define bfd_mach_mrisc2 2 ++#define bfd_mach_ms2 3 ++ bfd_arch_pj, ++ bfd_arch_avr, /* Atmel AVR microcontrollers. */ ++#define bfd_mach_avr1 1 ++#define bfd_mach_avr2 2 ++#define bfd_mach_avr3 3 ++#define bfd_mach_avr4 4 ++#define bfd_mach_avr5 5 ++ bfd_arch_bfin, /* ADI Blackfin */ ++#define bfd_mach_bfin 1 ++ bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ ++#define bfd_mach_cr16c 1 ++ bfd_arch_crx, /* National Semiconductor CRX. */ ++#define bfd_mach_crx 1 ++ bfd_arch_cris, /* Axis CRIS */ ++#define bfd_mach_cris_v0_v10 255 ++#define bfd_mach_cris_v32 32 ++#define bfd_mach_cris_v10_v32 1032 ++ bfd_arch_s390, /* IBM s390 */ ++#define bfd_mach_s390_31 31 ++#define bfd_mach_s390_64 64 ++ bfd_arch_openrisc, /* OpenRISC */ ++ bfd_arch_mmix, /* Donald Knuth's educational processor. */ ++ bfd_arch_xstormy16, ++#define bfd_mach_xstormy16 1 ++ bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ ++#define bfd_mach_msp11 11 ++#define bfd_mach_msp110 110 ++#define bfd_mach_msp12 12 ++#define bfd_mach_msp13 13 ++#define bfd_mach_msp14 14 ++#define bfd_mach_msp15 15 ++#define bfd_mach_msp16 16 ++#define bfd_mach_msp21 21 ++#define bfd_mach_msp31 31 ++#define bfd_mach_msp32 32 ++#define bfd_mach_msp33 33 ++#define bfd_mach_msp41 41 ++#define bfd_mach_msp42 42 ++#define bfd_mach_msp43 43 ++#define bfd_mach_msp44 44 ++ bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ ++#define bfd_mach_xtensa 1 ++ bfd_arch_maxq, /* Dallas MAXQ 10/20 */ ++#define bfd_mach_maxq10 10 ++#define bfd_mach_maxq20 20 ++ bfd_arch_z80, ++#define bfd_mach_z80strict 1 /* No undocumented opcodes. */ ++#define bfd_mach_z80 3 /* With ixl, ixh, iyl, and iyh. */ ++#define bfd_mach_z80full 7 /* All undocumented instructions. */ ++#define bfd_mach_r800 11 /* R800: successor with multiplication. */ ++ bfd_arch_last ++ }; ++ ++typedef struct bfd_arch_info ++{ ++ int bits_per_word; ++ int bits_per_address; ++ int bits_per_byte; ++ enum bfd_architecture arch; ++ unsigned long mach; ++ const char *arch_name; ++ const char *printable_name; ++ unsigned int section_align_power; ++ /* TRUE if this is the default machine for the architecture. ++ The default arch should be the first entry for an arch so that ++ all the entries for that arch can be accessed via <>. */ ++ bfd_boolean the_default; ++ const struct bfd_arch_info * (*compatible) ++ (const struct bfd_arch_info *a, const struct bfd_arch_info *b); ++ ++ bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); ++ ++ const struct bfd_arch_info *next; ++} ++bfd_arch_info_type; ++ ++const char *bfd_printable_name (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_scan_arch (const char *string); ++ ++const char **bfd_arch_list (void); ++ ++const bfd_arch_info_type *bfd_arch_get_compatible ++ (const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); ++ ++void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); ++ ++enum bfd_architecture bfd_get_arch (bfd *abfd); ++ ++unsigned long bfd_get_mach (bfd *abfd); ++ ++unsigned int bfd_arch_bits_per_byte (bfd *abfd); ++ ++unsigned int bfd_arch_bits_per_address (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_lookup_arch ++ (enum bfd_architecture arch, unsigned long machine); ++ ++const char *bfd_printable_arch_mach ++ (enum bfd_architecture arch, unsigned long machine); ++ ++unsigned int bfd_octets_per_byte (bfd *abfd); ++ ++unsigned int bfd_arch_mach_octets_per_byte ++ (enum bfd_architecture arch, unsigned long machine); ++ ++/* Extracted from reloc.c. */ ++typedef enum bfd_reloc_status ++{ ++ /* No errors detected. */ ++ bfd_reloc_ok, ++ ++ /* The relocation was performed, but there was an overflow. */ ++ bfd_reloc_overflow, ++ ++ /* The address to relocate was not within the section supplied. */ ++ bfd_reloc_outofrange, ++ ++ /* Used by special functions. */ ++ bfd_reloc_continue, ++ ++ /* Unsupported relocation size requested. */ ++ bfd_reloc_notsupported, ++ ++ /* Unused. */ ++ bfd_reloc_other, ++ ++ /* The symbol to relocate against was undefined. */ ++ bfd_reloc_undefined, ++ ++ /* The relocation was performed, but may not be ok - presently ++ generated only when linking i960 coff files with i960 b.out ++ symbols. If this type is returned, the error_message argument ++ to bfd_perform_relocation will be set. */ ++ bfd_reloc_dangerous ++ } ++ bfd_reloc_status_type; ++ ++ ++typedef struct reloc_cache_entry ++{ ++ /* A pointer into the canonical table of pointers. */ ++ struct bfd_symbol **sym_ptr_ptr; ++ ++ /* offset in section. */ ++ bfd_size_type address; ++ ++ /* addend for relocation value. */ ++ bfd_vma addend; ++ ++ /* Pointer to how to perform the required relocation. */ ++ reloc_howto_type *howto; ++ ++} ++arelent; ++ ++enum complain_overflow ++{ ++ /* Do not complain on overflow. */ ++ complain_overflow_dont, ++ ++ /* Complain if the value overflows when considered as a signed ++ number one bit larger than the field. ie. A bitfield of N bits ++ is allowed to represent -2**n to 2**n-1. */ ++ complain_overflow_bitfield, ++ ++ /* Complain if the value overflows when considered as a signed ++ number. */ ++ complain_overflow_signed, ++ ++ /* Complain if the value overflows when considered as an ++ unsigned number. */ ++ complain_overflow_unsigned ++}; ++ ++struct reloc_howto_struct ++{ ++ /* The type field has mainly a documentary use - the back end can ++ do what it wants with it, though normally the back end's ++ external idea of what a reloc number is stored ++ in this field. For example, a PC relative word relocation ++ in a coff environment has the type 023 - because that's ++ what the outside world calls a R_PCRWORD reloc. */ ++ unsigned int type; ++ ++ /* The value the final relocation is shifted right by. This drops ++ unwanted data from the relocation. */ ++ unsigned int rightshift; ++ ++ /* The size of the item to be relocated. This is *not* a ++ power-of-two measure. To get the number of bytes operated ++ on by a type of relocation, use bfd_get_reloc_size. */ ++ int size; ++ ++ /* The number of bits in the item to be relocated. This is used ++ when doing overflow checking. */ ++ unsigned int bitsize; ++ ++ /* Notes that the relocation is relative to the location in the ++ data section of the addend. The relocation function will ++ subtract from the relocation value the address of the location ++ being relocated. */ ++ bfd_boolean pc_relative; ++ ++ /* The bit position of the reloc value in the destination. ++ The relocated value is left shifted by this amount. */ ++ unsigned int bitpos; ++ ++ /* What type of overflow error should be checked for when ++ relocating. */ ++ enum complain_overflow complain_on_overflow; ++ ++ /* If this field is non null, then the supplied function is ++ called rather than the normal function. This allows really ++ strange relocation methods to be accommodated (e.g., i960 callj ++ instructions). */ ++ bfd_reloc_status_type (*special_function) ++ (bfd *, arelent *, struct bfd_symbol *, void *, asection *, ++ bfd *, char **); ++ ++ /* The textual name of the relocation type. */ ++ char *name; ++ ++ /* Some formats record a relocation addend in the section contents ++ rather than with the relocation. For ELF formats this is the ++ distinction between USE_REL and USE_RELA (though the code checks ++ for USE_REL == 1/0). The value of this field is TRUE if the ++ addend is recorded with the section contents; when performing a ++ partial link (ld -r) the section contents (the data) will be ++ modified. The value of this field is FALSE if addends are ++ recorded with the relocation (in arelent.addend); when performing ++ a partial link the relocation will be modified. ++ All relocations for all ELF USE_RELA targets should set this field ++ to FALSE (values of TRUE should be looked on with suspicion). ++ However, the converse is not true: not all relocations of all ELF ++ USE_REL targets set this field to TRUE. Why this is so is peculiar ++ to each particular target. For relocs that aren't used in partial ++ links (e.g. GOT stuff) it doesn't matter what this is set to. */ ++ bfd_boolean partial_inplace; ++ ++ /* src_mask selects the part of the instruction (or data) to be used ++ in the relocation sum. If the target relocations don't have an ++ addend in the reloc, eg. ELF USE_REL, src_mask will normally equal ++ dst_mask to extract the addend from the section contents. If ++ relocations do have an addend in the reloc, eg. ELF USE_RELA, this ++ field should be zero. Non-zero values for ELF USE_RELA targets are ++ bogus as in those cases the value in the dst_mask part of the ++ section contents should be treated as garbage. */ ++ bfd_vma src_mask; ++ ++ /* dst_mask selects which parts of the instruction (or data) are ++ replaced with a relocated value. */ ++ bfd_vma dst_mask; ++ ++ /* When some formats create PC relative instructions, they leave ++ the value of the pc of the place being relocated in the offset ++ slot of the instruction, so that a PC relative relocation can ++ be made just by adding in an ordinary offset (e.g., sun3 a.out). ++ Some formats leave the displacement part of an instruction ++ empty (e.g., m88k bcs); this flag signals the fact. */ ++ bfd_boolean pcrel_offset; ++}; ++ ++#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ ++ { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } ++#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ ++ HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ ++ NAME, FALSE, 0, 0, IN) ++ ++#define EMPTY_HOWTO(C) \ ++ HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ ++ NULL, FALSE, 0, 0, FALSE) ++ ++#define HOWTO_PREPARE(relocation, symbol) \ ++ { \ ++ if (symbol != NULL) \ ++ { \ ++ if (bfd_is_com_section (symbol->section)) \ ++ { \ ++ relocation = 0; \ ++ } \ ++ else \ ++ { \ ++ relocation = symbol->value; \ ++ } \ ++ } \ ++ } ++ ++unsigned int bfd_get_reloc_size (reloc_howto_type *); ++ ++typedef struct relent_chain ++{ ++ arelent relent; ++ struct relent_chain *next; ++} ++arelent_chain; ++ ++bfd_reloc_status_type bfd_check_overflow ++ (enum complain_overflow how, ++ unsigned int bitsize, ++ unsigned int rightshift, ++ unsigned int addrsize, ++ bfd_vma relocation); ++ ++bfd_reloc_status_type bfd_perform_relocation ++ (bfd *abfd, ++ arelent *reloc_entry, ++ void *data, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message); ++ ++bfd_reloc_status_type bfd_install_relocation ++ (bfd *abfd, ++ arelent *reloc_entry, ++ void *data, bfd_vma data_start, ++ asection *input_section, ++ char **error_message); ++ ++enum bfd_reloc_code_real { ++ _dummy_first_bfd_reloc_code_real, ++ ++ ++/* Basic absolute relocations of N bits. */ ++ BFD_RELOC_64, ++ BFD_RELOC_32, ++ BFD_RELOC_26, ++ BFD_RELOC_24, ++ BFD_RELOC_16, ++ BFD_RELOC_14, ++ BFD_RELOC_8, ++ ++/* PC-relative relocations. Sometimes these are relative to the address ++of the relocation itself; sometimes they are relative to the start of ++the section containing the relocation. It depends on the specific target. ++ ++The 24-bit relocation is used in some Intel 960 configurations. */ ++ BFD_RELOC_64_PCREL, ++ BFD_RELOC_32_PCREL, ++ BFD_RELOC_24_PCREL, ++ BFD_RELOC_16_PCREL, ++ BFD_RELOC_12_PCREL, ++ BFD_RELOC_8_PCREL, ++ ++/* Section relative relocations. Some targets need this for DWARF2. */ ++ BFD_RELOC_32_SECREL, ++ ++/* For ELF. */ ++ BFD_RELOC_32_GOT_PCREL, ++ BFD_RELOC_16_GOT_PCREL, ++ BFD_RELOC_8_GOT_PCREL, ++ BFD_RELOC_32_GOTOFF, ++ BFD_RELOC_16_GOTOFF, ++ BFD_RELOC_LO16_GOTOFF, ++ BFD_RELOC_HI16_GOTOFF, ++ BFD_RELOC_HI16_S_GOTOFF, ++ BFD_RELOC_8_GOTOFF, ++ BFD_RELOC_64_PLT_PCREL, ++ BFD_RELOC_32_PLT_PCREL, ++ BFD_RELOC_24_PLT_PCREL, ++ BFD_RELOC_16_PLT_PCREL, ++ BFD_RELOC_8_PLT_PCREL, ++ BFD_RELOC_64_PLTOFF, ++ BFD_RELOC_32_PLTOFF, ++ BFD_RELOC_16_PLTOFF, ++ BFD_RELOC_LO16_PLTOFF, ++ BFD_RELOC_HI16_PLTOFF, ++ BFD_RELOC_HI16_S_PLTOFF, ++ BFD_RELOC_8_PLTOFF, ++ ++/* Relocations used by 68K ELF. */ ++ BFD_RELOC_68K_GLOB_DAT, ++ BFD_RELOC_68K_JMP_SLOT, ++ BFD_RELOC_68K_RELATIVE, ++ ++/* Linkage-table relative. */ ++ BFD_RELOC_32_BASEREL, ++ BFD_RELOC_16_BASEREL, ++ BFD_RELOC_LO16_BASEREL, ++ BFD_RELOC_HI16_BASEREL, ++ BFD_RELOC_HI16_S_BASEREL, ++ BFD_RELOC_8_BASEREL, ++ BFD_RELOC_RVA, ++ ++/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ ++ BFD_RELOC_8_FFnn, ++ ++/* These PC-relative relocations are stored as word displacements -- ++i.e., byte displacements shifted right two bits. The 30-bit word ++displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the ++SPARC. (SPARC tools generally refer to this as <>.) The ++signed 16-bit displacement is used on the MIPS, and the 23-bit ++displacement is used on the Alpha. */ ++ BFD_RELOC_32_PCREL_S2, ++ BFD_RELOC_16_PCREL_S2, ++ BFD_RELOC_23_PCREL_S2, ++ ++/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of ++the target word. These are used on the SPARC. */ ++ BFD_RELOC_HI22, ++ BFD_RELOC_LO10, ++ ++/* For systems that allocate a Global Pointer register, these are ++displacements off that register. These relocation types are ++handled specially, because the value the register will have is ++decided relatively late. */ ++ BFD_RELOC_GPREL16, ++ BFD_RELOC_GPREL32, ++ ++/* Reloc types used for i960/b.out. */ ++ BFD_RELOC_I960_CALLJ, ++ ++/* SPARC ELF relocations. There is probably some overlap with other ++relocation types already defined. */ ++ BFD_RELOC_NONE, ++ BFD_RELOC_SPARC_WDISP22, ++ BFD_RELOC_SPARC22, ++ BFD_RELOC_SPARC13, ++ BFD_RELOC_SPARC_GOT10, ++ BFD_RELOC_SPARC_GOT13, ++ BFD_RELOC_SPARC_GOT22, ++ BFD_RELOC_SPARC_PC10, ++ BFD_RELOC_SPARC_PC22, ++ BFD_RELOC_SPARC_WPLT30, ++ BFD_RELOC_SPARC_COPY, ++ BFD_RELOC_SPARC_GLOB_DAT, ++ BFD_RELOC_SPARC_JMP_SLOT, ++ BFD_RELOC_SPARC_RELATIVE, ++ BFD_RELOC_SPARC_UA16, ++ BFD_RELOC_SPARC_UA32, ++ BFD_RELOC_SPARC_UA64, ++ ++/* I think these are specific to SPARC a.out (e.g., Sun 4). */ ++ BFD_RELOC_SPARC_BASE13, ++ BFD_RELOC_SPARC_BASE22, ++ ++/* SPARC64 relocations */ ++#define BFD_RELOC_SPARC_64 BFD_RELOC_64 ++ BFD_RELOC_SPARC_10, ++ BFD_RELOC_SPARC_11, ++ BFD_RELOC_SPARC_OLO10, ++ BFD_RELOC_SPARC_HH22, ++ BFD_RELOC_SPARC_HM10, ++ BFD_RELOC_SPARC_LM22, ++ BFD_RELOC_SPARC_PC_HH22, ++ BFD_RELOC_SPARC_PC_HM10, ++ BFD_RELOC_SPARC_PC_LM22, ++ BFD_RELOC_SPARC_WDISP16, ++ BFD_RELOC_SPARC_WDISP19, ++ BFD_RELOC_SPARC_7, ++ BFD_RELOC_SPARC_6, ++ BFD_RELOC_SPARC_5, ++#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL ++ BFD_RELOC_SPARC_PLT32, ++ BFD_RELOC_SPARC_PLT64, ++ BFD_RELOC_SPARC_HIX22, ++ BFD_RELOC_SPARC_LOX10, ++ BFD_RELOC_SPARC_H44, ++ BFD_RELOC_SPARC_M44, ++ BFD_RELOC_SPARC_L44, ++ BFD_RELOC_SPARC_REGISTER, ++ ++/* SPARC little endian relocation */ ++ BFD_RELOC_SPARC_REV32, ++ ++/* SPARC TLS relocations */ ++ BFD_RELOC_SPARC_TLS_GD_HI22, ++ BFD_RELOC_SPARC_TLS_GD_LO10, ++ BFD_RELOC_SPARC_TLS_GD_ADD, ++ BFD_RELOC_SPARC_TLS_GD_CALL, ++ BFD_RELOC_SPARC_TLS_LDM_HI22, ++ BFD_RELOC_SPARC_TLS_LDM_LO10, ++ BFD_RELOC_SPARC_TLS_LDM_ADD, ++ BFD_RELOC_SPARC_TLS_LDM_CALL, ++ BFD_RELOC_SPARC_TLS_LDO_HIX22, ++ BFD_RELOC_SPARC_TLS_LDO_LOX10, ++ BFD_RELOC_SPARC_TLS_LDO_ADD, ++ BFD_RELOC_SPARC_TLS_IE_HI22, ++ BFD_RELOC_SPARC_TLS_IE_LO10, ++ BFD_RELOC_SPARC_TLS_IE_LD, ++ BFD_RELOC_SPARC_TLS_IE_LDX, ++ BFD_RELOC_SPARC_TLS_IE_ADD, ++ BFD_RELOC_SPARC_TLS_LE_HIX22, ++ BFD_RELOC_SPARC_TLS_LE_LOX10, ++ BFD_RELOC_SPARC_TLS_DTPMOD32, ++ BFD_RELOC_SPARC_TLS_DTPMOD64, ++ BFD_RELOC_SPARC_TLS_DTPOFF32, ++ BFD_RELOC_SPARC_TLS_DTPOFF64, ++ BFD_RELOC_SPARC_TLS_TPOFF32, ++ BFD_RELOC_SPARC_TLS_TPOFF64, ++ ++/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or ++"addend" in some special way. ++For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when ++writing; when reading, it will be the absolute section symbol. The ++addend is the displacement in bytes of the "lda" instruction from ++the "ldah" instruction (which is at the address of this reloc). */ ++ BFD_RELOC_ALPHA_GPDISP_HI16, ++ ++/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as ++with GPDISP_HI16 relocs. The addend is ignored when writing the ++relocations out, and is filled in with the file's GP value on ++reading, for convenience. */ ++ BFD_RELOC_ALPHA_GPDISP_LO16, ++ ++/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 ++relocation except that there is no accompanying GPDISP_LO16 ++relocation. */ ++ BFD_RELOC_ALPHA_GPDISP, ++ ++/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; ++the assembler turns it into a LDQ instruction to load the address of ++the symbol, and then fills in a register in the real instruction. ++ ++The LITERAL reloc, at the LDQ instruction, refers to the .lita ++section symbol. The addend is ignored when writing, but is filled ++in with the file's GP value on reading, for convenience, as with the ++GPDISP_LO16 reloc. ++ ++The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. ++It should refer to the symbol to be referenced, as with 16_GOTOFF, ++but it generates output not based on the position within the .got ++section, but relative to the GP value chosen for the file during the ++final link stage. ++ ++The LITUSE reloc, on the instruction using the loaded address, gives ++information to the linker that it might be able to use to optimize ++away some literal section references. The symbol is ignored (read ++as the absolute section symbol), and the "addend" indicates the type ++of instruction using the register: ++1 - "memory" fmt insn ++2 - byte-manipulation (byte offset reg) ++3 - jsr (target of branch) */ ++ BFD_RELOC_ALPHA_LITERAL, ++ BFD_RELOC_ALPHA_ELF_LITERAL, ++ BFD_RELOC_ALPHA_LITUSE, ++ ++/* The HINT relocation indicates a value that should be filled into the ++"hint" field of a jmp/jsr/ret instruction, for possible branch- ++prediction logic which may be provided on some processors. */ ++ BFD_RELOC_ALPHA_HINT, ++ ++/* The LINKAGE relocation outputs a linkage pair in the object file, ++which is filled by the linker. */ ++ BFD_RELOC_ALPHA_LINKAGE, ++ ++/* The CODEADDR relocation outputs a STO_CA in the object file, ++which is filled by the linker. */ ++ BFD_RELOC_ALPHA_CODEADDR, ++ ++/* The GPREL_HI/LO relocations together form a 32-bit offset from the ++GP register. */ ++ BFD_RELOC_ALPHA_GPREL_HI16, ++ BFD_RELOC_ALPHA_GPREL_LO16, ++ ++/* Like BFD_RELOC_23_PCREL_S2, except that the source and target must ++share a common GP, and the target address is adjusted for ++STO_ALPHA_STD_GPLOAD. */ ++ BFD_RELOC_ALPHA_BRSGP, ++ ++/* Alpha thread-local storage relocations. */ ++ BFD_RELOC_ALPHA_TLSGD, ++ BFD_RELOC_ALPHA_TLSLDM, ++ BFD_RELOC_ALPHA_DTPMOD64, ++ BFD_RELOC_ALPHA_GOTDTPREL16, ++ BFD_RELOC_ALPHA_DTPREL64, ++ BFD_RELOC_ALPHA_DTPREL_HI16, ++ BFD_RELOC_ALPHA_DTPREL_LO16, ++ BFD_RELOC_ALPHA_DTPREL16, ++ BFD_RELOC_ALPHA_GOTTPREL16, ++ BFD_RELOC_ALPHA_TPREL64, ++ BFD_RELOC_ALPHA_TPREL_HI16, ++ BFD_RELOC_ALPHA_TPREL_LO16, ++ BFD_RELOC_ALPHA_TPREL16, ++ ++/* Bits 27..2 of the relocation address shifted right 2 bits; ++simple reloc otherwise. */ ++ BFD_RELOC_MIPS_JMP, ++ ++/* The MIPS16 jump instruction. */ ++ BFD_RELOC_MIPS16_JMP, ++ ++/* MIPS16 GP relative reloc. */ ++ BFD_RELOC_MIPS16_GPREL, ++ ++/* High 16 bits of 32-bit value; simple reloc. */ ++ BFD_RELOC_HI16, ++ ++/* High 16 bits of 32-bit value but the low 16 bits will be sign ++extended and added to form the final result. If the low 16 ++bits form a negative number, we need to add one to the high value ++to compensate for the borrow when the low bits are added. */ ++ BFD_RELOC_HI16_S, ++ ++/* Low 16 bits. */ ++ BFD_RELOC_LO16, ++ ++/* High 16 bits of 32-bit pc-relative value */ ++ BFD_RELOC_HI16_PCREL, ++ ++/* High 16 bits of 32-bit pc-relative value, adjusted */ ++ BFD_RELOC_HI16_S_PCREL, ++ ++/* Low 16 bits of pc-relative value */ ++ BFD_RELOC_LO16_PCREL, ++ ++/* MIPS16 high 16 bits of 32-bit value. */ ++ BFD_RELOC_MIPS16_HI16, ++ ++/* MIPS16 high 16 bits of 32-bit value but the low 16 bits will be sign ++extended and added to form the final result. If the low 16 ++bits form a negative number, we need to add one to the high value ++to compensate for the borrow when the low bits are added. */ ++ BFD_RELOC_MIPS16_HI16_S, ++ ++/* MIPS16 low 16 bits. */ ++ BFD_RELOC_MIPS16_LO16, ++ ++/* Relocation against a MIPS literal section. */ ++ BFD_RELOC_MIPS_LITERAL, ++ ++/* MIPS ELF relocations. */ ++ BFD_RELOC_MIPS_GOT16, ++ BFD_RELOC_MIPS_CALL16, ++ BFD_RELOC_MIPS_GOT_HI16, ++ BFD_RELOC_MIPS_GOT_LO16, ++ BFD_RELOC_MIPS_CALL_HI16, ++ BFD_RELOC_MIPS_CALL_LO16, ++ BFD_RELOC_MIPS_SUB, ++ BFD_RELOC_MIPS_GOT_PAGE, ++ BFD_RELOC_MIPS_GOT_OFST, ++ BFD_RELOC_MIPS_GOT_DISP, ++ BFD_RELOC_MIPS_SHIFT5, ++ BFD_RELOC_MIPS_SHIFT6, ++ BFD_RELOC_MIPS_INSERT_A, ++ BFD_RELOC_MIPS_INSERT_B, ++ BFD_RELOC_MIPS_DELETE, ++ BFD_RELOC_MIPS_HIGHEST, ++ BFD_RELOC_MIPS_HIGHER, ++ BFD_RELOC_MIPS_SCN_DISP, ++ BFD_RELOC_MIPS_REL16, ++ BFD_RELOC_MIPS_RELGOT, ++ BFD_RELOC_MIPS_JALR, ++ BFD_RELOC_MIPS_TLS_DTPMOD32, ++ BFD_RELOC_MIPS_TLS_DTPREL32, ++ BFD_RELOC_MIPS_TLS_DTPMOD64, ++ BFD_RELOC_MIPS_TLS_DTPREL64, ++ BFD_RELOC_MIPS_TLS_GD, ++ BFD_RELOC_MIPS_TLS_LDM, ++ BFD_RELOC_MIPS_TLS_DTPREL_HI16, ++ BFD_RELOC_MIPS_TLS_DTPREL_LO16, ++ BFD_RELOC_MIPS_TLS_GOTTPREL, ++ BFD_RELOC_MIPS_TLS_TPREL32, ++ BFD_RELOC_MIPS_TLS_TPREL64, ++ BFD_RELOC_MIPS_TLS_TPREL_HI16, ++ BFD_RELOC_MIPS_TLS_TPREL_LO16, ++ ++ ++/* Fujitsu Frv Relocations. */ ++ BFD_RELOC_FRV_LABEL16, ++ BFD_RELOC_FRV_LABEL24, ++ BFD_RELOC_FRV_LO16, ++ BFD_RELOC_FRV_HI16, ++ BFD_RELOC_FRV_GPREL12, ++ BFD_RELOC_FRV_GPRELU12, ++ BFD_RELOC_FRV_GPREL32, ++ BFD_RELOC_FRV_GPRELHI, ++ BFD_RELOC_FRV_GPRELLO, ++ BFD_RELOC_FRV_GOT12, ++ BFD_RELOC_FRV_GOTHI, ++ BFD_RELOC_FRV_GOTLO, ++ BFD_RELOC_FRV_FUNCDESC, ++ BFD_RELOC_FRV_FUNCDESC_GOT12, ++ BFD_RELOC_FRV_FUNCDESC_GOTHI, ++ BFD_RELOC_FRV_FUNCDESC_GOTLO, ++ BFD_RELOC_FRV_FUNCDESC_VALUE, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFF12, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFFHI, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFFLO, ++ BFD_RELOC_FRV_GOTOFF12, ++ BFD_RELOC_FRV_GOTOFFHI, ++ BFD_RELOC_FRV_GOTOFFLO, ++ BFD_RELOC_FRV_GETTLSOFF, ++ BFD_RELOC_FRV_TLSDESC_VALUE, ++ BFD_RELOC_FRV_GOTTLSDESC12, ++ BFD_RELOC_FRV_GOTTLSDESCHI, ++ BFD_RELOC_FRV_GOTTLSDESCLO, ++ BFD_RELOC_FRV_TLSMOFF12, ++ BFD_RELOC_FRV_TLSMOFFHI, ++ BFD_RELOC_FRV_TLSMOFFLO, ++ BFD_RELOC_FRV_GOTTLSOFF12, ++ BFD_RELOC_FRV_GOTTLSOFFHI, ++ BFD_RELOC_FRV_GOTTLSOFFLO, ++ BFD_RELOC_FRV_TLSOFF, ++ BFD_RELOC_FRV_TLSDESC_RELAX, ++ BFD_RELOC_FRV_GETTLSOFF_RELAX, ++ BFD_RELOC_FRV_TLSOFF_RELAX, ++ BFD_RELOC_FRV_TLSMOFF, ++ ++ ++/* This is a 24bit GOT-relative reloc for the mn10300. */ ++ BFD_RELOC_MN10300_GOTOFF24, ++ ++/* This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT32, ++ ++/* This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT24, ++ ++/* This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT16, ++ ++/* Copy symbol at runtime. */ ++ BFD_RELOC_MN10300_COPY, ++ ++/* Create GOT entry. */ ++ BFD_RELOC_MN10300_GLOB_DAT, ++ ++/* Create PLT entry. */ ++ BFD_RELOC_MN10300_JMP_SLOT, ++ ++/* Adjust by program base. */ ++ BFD_RELOC_MN10300_RELATIVE, ++ ++ ++/* i386/elf relocations */ ++ BFD_RELOC_386_GOT32, ++ BFD_RELOC_386_PLT32, ++ BFD_RELOC_386_COPY, ++ BFD_RELOC_386_GLOB_DAT, ++ BFD_RELOC_386_JUMP_SLOT, ++ BFD_RELOC_386_RELATIVE, ++ BFD_RELOC_386_GOTOFF, ++ BFD_RELOC_386_GOTPC, ++ BFD_RELOC_386_TLS_TPOFF, ++ BFD_RELOC_386_TLS_IE, ++ BFD_RELOC_386_TLS_GOTIE, ++ BFD_RELOC_386_TLS_LE, ++ BFD_RELOC_386_TLS_GD, ++ BFD_RELOC_386_TLS_LDM, ++ BFD_RELOC_386_TLS_LDO_32, ++ BFD_RELOC_386_TLS_IE_32, ++ BFD_RELOC_386_TLS_LE_32, ++ BFD_RELOC_386_TLS_DTPMOD32, ++ BFD_RELOC_386_TLS_DTPOFF32, ++ BFD_RELOC_386_TLS_TPOFF32, ++ ++/* x86-64/elf relocations */ ++ BFD_RELOC_X86_64_GOT32, ++ BFD_RELOC_X86_64_PLT32, ++ BFD_RELOC_X86_64_COPY, ++ BFD_RELOC_X86_64_GLOB_DAT, ++ BFD_RELOC_X86_64_JUMP_SLOT, ++ BFD_RELOC_X86_64_RELATIVE, ++ BFD_RELOC_X86_64_GOTPCREL, ++ BFD_RELOC_X86_64_32S, ++ BFD_RELOC_X86_64_DTPMOD64, ++ BFD_RELOC_X86_64_DTPOFF64, ++ BFD_RELOC_X86_64_TPOFF64, ++ BFD_RELOC_X86_64_TLSGD, ++ BFD_RELOC_X86_64_TLSLD, ++ BFD_RELOC_X86_64_DTPOFF32, ++ BFD_RELOC_X86_64_GOTTPOFF, ++ BFD_RELOC_X86_64_TPOFF32, ++ BFD_RELOC_X86_64_GOTOFF64, ++ BFD_RELOC_X86_64_GOTPC32, ++ BFD_RELOC_X86_64_GOT64, ++ BFD_RELOC_X86_64_GOTPCREL64, ++ BFD_RELOC_X86_64_GOTPC64, ++ BFD_RELOC_X86_64_GOTPLT64, ++ BFD_RELOC_X86_64_PLTOFF64, ++ ++/* ns32k relocations */ ++ BFD_RELOC_NS32K_IMM_8, ++ BFD_RELOC_NS32K_IMM_16, ++ BFD_RELOC_NS32K_IMM_32, ++ BFD_RELOC_NS32K_IMM_8_PCREL, ++ BFD_RELOC_NS32K_IMM_16_PCREL, ++ BFD_RELOC_NS32K_IMM_32_PCREL, ++ BFD_RELOC_NS32K_DISP_8, ++ BFD_RELOC_NS32K_DISP_16, ++ BFD_RELOC_NS32K_DISP_32, ++ BFD_RELOC_NS32K_DISP_8_PCREL, ++ BFD_RELOC_NS32K_DISP_16_PCREL, ++ BFD_RELOC_NS32K_DISP_32_PCREL, ++ ++/* PDP11 relocations */ ++ BFD_RELOC_PDP11_DISP_8_PCREL, ++ BFD_RELOC_PDP11_DISP_6_PCREL, ++ ++/* Picojava relocs. Not all of these appear in object files. */ ++ BFD_RELOC_PJ_CODE_HI16, ++ BFD_RELOC_PJ_CODE_LO16, ++ BFD_RELOC_PJ_CODE_DIR16, ++ BFD_RELOC_PJ_CODE_DIR32, ++ BFD_RELOC_PJ_CODE_REL16, ++ BFD_RELOC_PJ_CODE_REL32, ++ ++/* Power(rs6000) and PowerPC relocations. */ ++ BFD_RELOC_PPC_B26, ++ BFD_RELOC_PPC_BA26, ++ BFD_RELOC_PPC_TOC16, ++ BFD_RELOC_PPC_B16, ++ BFD_RELOC_PPC_B16_BRTAKEN, ++ BFD_RELOC_PPC_B16_BRNTAKEN, ++ BFD_RELOC_PPC_BA16, ++ BFD_RELOC_PPC_BA16_BRTAKEN, ++ BFD_RELOC_PPC_BA16_BRNTAKEN, ++ BFD_RELOC_PPC_COPY, ++ BFD_RELOC_PPC_GLOB_DAT, ++ BFD_RELOC_PPC_JMP_SLOT, ++ BFD_RELOC_PPC_RELATIVE, ++ BFD_RELOC_PPC_LOCAL24PC, ++ BFD_RELOC_PPC_EMB_NADDR32, ++ BFD_RELOC_PPC_EMB_NADDR16, ++ BFD_RELOC_PPC_EMB_NADDR16_LO, ++ BFD_RELOC_PPC_EMB_NADDR16_HI, ++ BFD_RELOC_PPC_EMB_NADDR16_HA, ++ BFD_RELOC_PPC_EMB_SDAI16, ++ BFD_RELOC_PPC_EMB_SDA2I16, ++ BFD_RELOC_PPC_EMB_SDA2REL, ++ BFD_RELOC_PPC_EMB_SDA21, ++ BFD_RELOC_PPC_EMB_MRKREF, ++ BFD_RELOC_PPC_EMB_RELSEC16, ++ BFD_RELOC_PPC_EMB_RELST_LO, ++ BFD_RELOC_PPC_EMB_RELST_HI, ++ BFD_RELOC_PPC_EMB_RELST_HA, ++ BFD_RELOC_PPC_EMB_BIT_FLD, ++ BFD_RELOC_PPC_EMB_RELSDA, ++ BFD_RELOC_PPC64_HIGHER, ++ BFD_RELOC_PPC64_HIGHER_S, ++ BFD_RELOC_PPC64_HIGHEST, ++ BFD_RELOC_PPC64_HIGHEST_S, ++ BFD_RELOC_PPC64_TOC16_LO, ++ BFD_RELOC_PPC64_TOC16_HI, ++ BFD_RELOC_PPC64_TOC16_HA, ++ BFD_RELOC_PPC64_TOC, ++ BFD_RELOC_PPC64_PLTGOT16, ++ BFD_RELOC_PPC64_PLTGOT16_LO, ++ BFD_RELOC_PPC64_PLTGOT16_HI, ++ BFD_RELOC_PPC64_PLTGOT16_HA, ++ BFD_RELOC_PPC64_ADDR16_DS, ++ BFD_RELOC_PPC64_ADDR16_LO_DS, ++ BFD_RELOC_PPC64_GOT16_DS, ++ BFD_RELOC_PPC64_GOT16_LO_DS, ++ BFD_RELOC_PPC64_PLT16_LO_DS, ++ BFD_RELOC_PPC64_SECTOFF_DS, ++ BFD_RELOC_PPC64_SECTOFF_LO_DS, ++ BFD_RELOC_PPC64_TOC16_DS, ++ BFD_RELOC_PPC64_TOC16_LO_DS, ++ BFD_RELOC_PPC64_PLTGOT16_DS, ++ BFD_RELOC_PPC64_PLTGOT16_LO_DS, ++ ++/* PowerPC and PowerPC64 thread-local storage relocations. */ ++ BFD_RELOC_PPC_TLS, ++ BFD_RELOC_PPC_DTPMOD, ++ BFD_RELOC_PPC_TPREL16, ++ BFD_RELOC_PPC_TPREL16_LO, ++ BFD_RELOC_PPC_TPREL16_HI, ++ BFD_RELOC_PPC_TPREL16_HA, ++ BFD_RELOC_PPC_TPREL, ++ BFD_RELOC_PPC_DTPREL16, ++ BFD_RELOC_PPC_DTPREL16_LO, ++ BFD_RELOC_PPC_DTPREL16_HI, ++ BFD_RELOC_PPC_DTPREL16_HA, ++ BFD_RELOC_PPC_DTPREL, ++ BFD_RELOC_PPC_GOT_TLSGD16, ++ BFD_RELOC_PPC_GOT_TLSGD16_LO, ++ BFD_RELOC_PPC_GOT_TLSGD16_HI, ++ BFD_RELOC_PPC_GOT_TLSGD16_HA, ++ BFD_RELOC_PPC_GOT_TLSLD16, ++ BFD_RELOC_PPC_GOT_TLSLD16_LO, ++ BFD_RELOC_PPC_GOT_TLSLD16_HI, ++ BFD_RELOC_PPC_GOT_TLSLD16_HA, ++ BFD_RELOC_PPC_GOT_TPREL16, ++ BFD_RELOC_PPC_GOT_TPREL16_LO, ++ BFD_RELOC_PPC_GOT_TPREL16_HI, ++ BFD_RELOC_PPC_GOT_TPREL16_HA, ++ BFD_RELOC_PPC_GOT_DTPREL16, ++ BFD_RELOC_PPC_GOT_DTPREL16_LO, ++ BFD_RELOC_PPC_GOT_DTPREL16_HI, ++ BFD_RELOC_PPC_GOT_DTPREL16_HA, ++ BFD_RELOC_PPC64_TPREL16_DS, ++ BFD_RELOC_PPC64_TPREL16_LO_DS, ++ BFD_RELOC_PPC64_TPREL16_HIGHER, ++ BFD_RELOC_PPC64_TPREL16_HIGHERA, ++ BFD_RELOC_PPC64_TPREL16_HIGHEST, ++ BFD_RELOC_PPC64_TPREL16_HIGHESTA, ++ BFD_RELOC_PPC64_DTPREL16_DS, ++ BFD_RELOC_PPC64_DTPREL16_LO_DS, ++ BFD_RELOC_PPC64_DTPREL16_HIGHER, ++ BFD_RELOC_PPC64_DTPREL16_HIGHERA, ++ BFD_RELOC_PPC64_DTPREL16_HIGHEST, ++ BFD_RELOC_PPC64_DTPREL16_HIGHESTA, ++ ++/* IBM 370/390 relocations */ ++ BFD_RELOC_I370_D12, ++ ++/* The type of reloc used to build a constructor table - at the moment ++probably a 32 bit wide absolute relocation, but the target can choose. ++It generally does map to one of the other relocation types. */ ++ BFD_RELOC_CTOR, ++ ++/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are ++not stored in the instruction. */ ++ BFD_RELOC_ARM_PCREL_BRANCH, ++ ++/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is ++not stored in the instruction. The 2nd lowest bit comes from a 1 bit ++field in the instruction. */ ++ BFD_RELOC_ARM_PCREL_BLX, ++ ++/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is ++not stored in the instruction. The 2nd lowest bit comes from a 1 bit ++field in the instruction. */ ++ BFD_RELOC_THUMB_PCREL_BLX, ++ ++/* ARM 26-bit pc-relative branch for an unconditional BL or BLX instruction. */ ++ BFD_RELOC_ARM_PCREL_CALL, ++ ++/* ARM 26-bit pc-relative branch for B or conditional BL instruction. */ ++ BFD_RELOC_ARM_PCREL_JUMP, ++ ++/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. ++The lowest bit must be zero and is not stored in the instruction. ++Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an ++"nn" one smaller in all cases. Note further that BRANCH23 ++corresponds to R_ARM_THM_CALL. */ ++ BFD_RELOC_THUMB_PCREL_BRANCH7, ++ BFD_RELOC_THUMB_PCREL_BRANCH9, ++ BFD_RELOC_THUMB_PCREL_BRANCH12, ++ BFD_RELOC_THUMB_PCREL_BRANCH20, ++ BFD_RELOC_THUMB_PCREL_BRANCH23, ++ BFD_RELOC_THUMB_PCREL_BRANCH25, ++ ++/* 12-bit immediate offset, used in ARM-format ldr and str instructions. */ ++ BFD_RELOC_ARM_OFFSET_IMM, ++ ++/* 5-bit immediate offset, used in Thumb-format ldr and str instructions. */ ++ BFD_RELOC_ARM_THUMB_OFFSET, ++ ++/* Pc-relative or absolute relocation depending on target. Used for ++entries in .init_array sections. */ ++ BFD_RELOC_ARM_TARGET1, ++ ++/* Read-only segment base relative address. */ ++ BFD_RELOC_ARM_ROSEGREL32, ++ ++/* Data segment base relative address. */ ++ BFD_RELOC_ARM_SBREL32, ++ ++/* This reloc is used for references to RTTI data from exception handling ++tables. The actual definition depends on the target. It may be a ++pc-relative or some form of GOT-indirect relocation. */ ++ BFD_RELOC_ARM_TARGET2, ++ ++/* 31-bit PC relative address. */ ++ BFD_RELOC_ARM_PREL31, ++ ++/* Relocations for setting up GOTs and PLTs for shared libraries. */ ++ BFD_RELOC_ARM_JUMP_SLOT, ++ BFD_RELOC_ARM_GLOB_DAT, ++ BFD_RELOC_ARM_GOT32, ++ BFD_RELOC_ARM_PLT32, ++ BFD_RELOC_ARM_RELATIVE, ++ BFD_RELOC_ARM_GOTOFF, ++ BFD_RELOC_ARM_GOTPC, ++ ++/* ARM thread-local storage relocations. */ ++ BFD_RELOC_ARM_TLS_GD32, ++ BFD_RELOC_ARM_TLS_LDO32, ++ BFD_RELOC_ARM_TLS_LDM32, ++ BFD_RELOC_ARM_TLS_DTPOFF32, ++ BFD_RELOC_ARM_TLS_DTPMOD32, ++ BFD_RELOC_ARM_TLS_TPOFF32, ++ BFD_RELOC_ARM_TLS_IE32, ++ BFD_RELOC_ARM_TLS_LE32, ++ ++/* These relocs are only used within the ARM assembler. They are not ++(at present) written to any object files. */ ++ BFD_RELOC_ARM_IMMEDIATE, ++ BFD_RELOC_ARM_ADRL_IMMEDIATE, ++ BFD_RELOC_ARM_T32_IMMEDIATE, ++ BFD_RELOC_ARM_T32_IMM12, ++ BFD_RELOC_ARM_T32_ADD_PC12, ++ BFD_RELOC_ARM_SHIFT_IMM, ++ BFD_RELOC_ARM_SMC, ++ BFD_RELOC_ARM_SWI, ++ BFD_RELOC_ARM_MULTI, ++ BFD_RELOC_ARM_CP_OFF_IMM, ++ BFD_RELOC_ARM_CP_OFF_IMM_S2, ++ BFD_RELOC_ARM_T32_CP_OFF_IMM, ++ BFD_RELOC_ARM_T32_CP_OFF_IMM_S2, ++ BFD_RELOC_ARM_ADR_IMM, ++ BFD_RELOC_ARM_LDR_IMM, ++ BFD_RELOC_ARM_LITERAL, ++ BFD_RELOC_ARM_IN_POOL, ++ BFD_RELOC_ARM_OFFSET_IMM8, ++ BFD_RELOC_ARM_T32_OFFSET_U8, ++ BFD_RELOC_ARM_T32_OFFSET_IMM, ++ BFD_RELOC_ARM_HWLITERAL, ++ BFD_RELOC_ARM_THUMB_ADD, ++ BFD_RELOC_ARM_THUMB_IMM, ++ BFD_RELOC_ARM_THUMB_SHIFT, ++ ++/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ ++ BFD_RELOC_SH_PCDISP8BY2, ++ BFD_RELOC_SH_PCDISP12BY2, ++ BFD_RELOC_SH_IMM3, ++ BFD_RELOC_SH_IMM3U, ++ BFD_RELOC_SH_DISP12, ++ BFD_RELOC_SH_DISP12BY2, ++ BFD_RELOC_SH_DISP12BY4, ++ BFD_RELOC_SH_DISP12BY8, ++ BFD_RELOC_SH_DISP20, ++ BFD_RELOC_SH_DISP20BY8, ++ BFD_RELOC_SH_IMM4, ++ BFD_RELOC_SH_IMM4BY2, ++ BFD_RELOC_SH_IMM4BY4, ++ BFD_RELOC_SH_IMM8, ++ BFD_RELOC_SH_IMM8BY2, ++ BFD_RELOC_SH_IMM8BY4, ++ BFD_RELOC_SH_PCRELIMM8BY2, ++ BFD_RELOC_SH_PCRELIMM8BY4, ++ BFD_RELOC_SH_SWITCH16, ++ BFD_RELOC_SH_SWITCH32, ++ BFD_RELOC_SH_USES, ++ BFD_RELOC_SH_COUNT, ++ BFD_RELOC_SH_ALIGN, ++ BFD_RELOC_SH_CODE, ++ BFD_RELOC_SH_DATA, ++ BFD_RELOC_SH_LABEL, ++ BFD_RELOC_SH_LOOP_START, ++ BFD_RELOC_SH_LOOP_END, ++ BFD_RELOC_SH_COPY, ++ BFD_RELOC_SH_GLOB_DAT, ++ BFD_RELOC_SH_JMP_SLOT, ++ BFD_RELOC_SH_RELATIVE, ++ BFD_RELOC_SH_GOTPC, ++ BFD_RELOC_SH_GOT_LOW16, ++ BFD_RELOC_SH_GOT_MEDLOW16, ++ BFD_RELOC_SH_GOT_MEDHI16, ++ BFD_RELOC_SH_GOT_HI16, ++ BFD_RELOC_SH_GOTPLT_LOW16, ++ BFD_RELOC_SH_GOTPLT_MEDLOW16, ++ BFD_RELOC_SH_GOTPLT_MEDHI16, ++ BFD_RELOC_SH_GOTPLT_HI16, ++ BFD_RELOC_SH_PLT_LOW16, ++ BFD_RELOC_SH_PLT_MEDLOW16, ++ BFD_RELOC_SH_PLT_MEDHI16, ++ BFD_RELOC_SH_PLT_HI16, ++ BFD_RELOC_SH_GOTOFF_LOW16, ++ BFD_RELOC_SH_GOTOFF_MEDLOW16, ++ BFD_RELOC_SH_GOTOFF_MEDHI16, ++ BFD_RELOC_SH_GOTOFF_HI16, ++ BFD_RELOC_SH_GOTPC_LOW16, ++ BFD_RELOC_SH_GOTPC_MEDLOW16, ++ BFD_RELOC_SH_GOTPC_MEDHI16, ++ BFD_RELOC_SH_GOTPC_HI16, ++ BFD_RELOC_SH_COPY64, ++ BFD_RELOC_SH_GLOB_DAT64, ++ BFD_RELOC_SH_JMP_SLOT64, ++ BFD_RELOC_SH_RELATIVE64, ++ BFD_RELOC_SH_GOT10BY4, ++ BFD_RELOC_SH_GOT10BY8, ++ BFD_RELOC_SH_GOTPLT10BY4, ++ BFD_RELOC_SH_GOTPLT10BY8, ++ BFD_RELOC_SH_GOTPLT32, ++ BFD_RELOC_SH_SHMEDIA_CODE, ++ BFD_RELOC_SH_IMMU5, ++ BFD_RELOC_SH_IMMS6, ++ BFD_RELOC_SH_IMMS6BY32, ++ BFD_RELOC_SH_IMMU6, ++ BFD_RELOC_SH_IMMS10, ++ BFD_RELOC_SH_IMMS10BY2, ++ BFD_RELOC_SH_IMMS10BY4, ++ BFD_RELOC_SH_IMMS10BY8, ++ BFD_RELOC_SH_IMMS16, ++ BFD_RELOC_SH_IMMU16, ++ BFD_RELOC_SH_IMM_LOW16, ++ BFD_RELOC_SH_IMM_LOW16_PCREL, ++ BFD_RELOC_SH_IMM_MEDLOW16, ++ BFD_RELOC_SH_IMM_MEDLOW16_PCREL, ++ BFD_RELOC_SH_IMM_MEDHI16, ++ BFD_RELOC_SH_IMM_MEDHI16_PCREL, ++ BFD_RELOC_SH_IMM_HI16, ++ BFD_RELOC_SH_IMM_HI16_PCREL, ++ BFD_RELOC_SH_PT_16, ++ BFD_RELOC_SH_TLS_GD_32, ++ BFD_RELOC_SH_TLS_LD_32, ++ BFD_RELOC_SH_TLS_LDO_32, ++ BFD_RELOC_SH_TLS_IE_32, ++ BFD_RELOC_SH_TLS_LE_32, ++ BFD_RELOC_SH_TLS_DTPMOD32, ++ BFD_RELOC_SH_TLS_DTPOFF32, ++ BFD_RELOC_SH_TLS_TPOFF32, ++ ++/* ARC Cores relocs. ++ARC 22 bit pc-relative branch. The lowest two bits must be zero and are ++not stored in the instruction. The high 20 bits are installed in bits 26 ++through 7 of the instruction. */ ++ BFD_RELOC_ARC_B22_PCREL, ++ ++/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not ++stored in the instruction. The high 24 bits are installed in bits 23 ++through 0. */ ++ BFD_RELOC_ARC_B26, ++ ++/* ADI Blackfin 16 bit immediate absolute reloc. */ ++ BFD_RELOC_BFIN_16_IMM, ++ ++/* ADI Blackfin 16 bit immediate absolute reloc higher 16 bits. */ ++ BFD_RELOC_BFIN_16_HIGH, ++ ++/* ADI Blackfin 'a' part of LSETUP. */ ++ BFD_RELOC_BFIN_4_PCREL, ++ ++/* ADI Blackfin. */ ++ BFD_RELOC_BFIN_5_PCREL, ++ ++/* ADI Blackfin 16 bit immediate absolute reloc lower 16 bits. */ ++ BFD_RELOC_BFIN_16_LOW, ++ ++/* ADI Blackfin. */ ++ BFD_RELOC_BFIN_10_PCREL, ++ ++/* ADI Blackfin 'b' part of LSETUP. */ ++ BFD_RELOC_BFIN_11_PCREL, ++ ++/* ADI Blackfin. */ ++ BFD_RELOC_BFIN_12_PCREL_JUMP, ++ ++/* ADI Blackfin Short jump, pcrel. */ ++ BFD_RELOC_BFIN_12_PCREL_JUMP_S, ++ ++/* ADI Blackfin Call.x not implemented. */ ++ BFD_RELOC_BFIN_24_PCREL_CALL_X, ++ ++/* ADI Blackfin Long Jump pcrel. */ ++ BFD_RELOC_BFIN_24_PCREL_JUMP_L, ++ ++/* ADI Blackfin GOT relocation. */ ++ BFD_RELOC_BFIN_GOT, ++ ++/* ADI Blackfin PLTPC relocation. */ ++ BFD_RELOC_BFIN_PLTPC, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_PUSH, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_CONST, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_ADD, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_SUB, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_MULT, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_DIV, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_MOD, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_LSHIFT, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_RSHIFT, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_AND, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_OR, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_XOR, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_LAND, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_LOR, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_LEN, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_NEG, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_COMP, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_PAGE, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_HWPAGE, ++ ++/* ADI Blackfin arithmetic relocation. */ ++ BFD_ARELOC_BFIN_ADDR, ++ ++/* Mitsubishi D10V relocs. ++This is a 10-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_10_PCREL_R, ++ ++/* Mitsubishi D10V relocs. ++This is a 10-bit reloc with the right 2 bits ++assumed to be 0. This is the same as the previous reloc ++except it is in the left container, i.e., ++shifted left 15 bits. */ ++ BFD_RELOC_D10V_10_PCREL_L, ++ ++/* This is an 18-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_18, ++ ++/* This is an 18-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_18_PCREL, ++ ++/* Mitsubishi D30V relocs. ++This is a 6-bit absolute reloc. */ ++ BFD_RELOC_D30V_6, ++ ++/* This is a 6-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_9_PCREL, ++ ++/* This is a 6-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_9_PCREL_R, ++ ++/* This is a 12-bit absolute reloc with the ++right 3 bitsassumed to be 0. */ ++ BFD_RELOC_D30V_15, ++ ++/* This is a 12-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_15_PCREL, ++ ++/* This is a 12-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_15_PCREL_R, ++ ++/* This is an 18-bit absolute reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_21, ++ ++/* This is an 18-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_21_PCREL, ++ ++/* This is an 18-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_21_PCREL_R, ++ ++/* This is a 32-bit absolute reloc. */ ++ BFD_RELOC_D30V_32, ++ ++/* This is a 32-bit pc-relative reloc. */ ++ BFD_RELOC_D30V_32_PCREL, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_HI16_S, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_LO16, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_JMP26, ++ ++/* Renesas M16C/M32C Relocations. */ ++ BFD_RELOC_M32C_HI8, ++ ++/* Renesas M32R (formerly Mitsubishi M32R) relocs. ++This is a 24 bit absolute address. */ ++ BFD_RELOC_M32R_24, ++ ++/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_10_PCREL, ++ ++/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_18_PCREL, ++ ++/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_26_PCREL, ++ ++/* This is a 16-bit reloc containing the high 16 bits of an address ++used when the lower 16 bits are treated as unsigned. */ ++ BFD_RELOC_M32R_HI16_ULO, ++ ++/* This is a 16-bit reloc containing the high 16 bits of an address ++used when the lower 16 bits are treated as signed. */ ++ BFD_RELOC_M32R_HI16_SLO, ++ ++/* This is a 16-bit reloc containing the lower 16 bits of an address. */ ++ BFD_RELOC_M32R_LO16, ++ ++/* This is a 16-bit reloc containing the small data area offset for use in ++add3, load, and store instructions. */ ++ BFD_RELOC_M32R_SDA16, ++ ++/* For PIC. */ ++ BFD_RELOC_M32R_GOT24, ++ BFD_RELOC_M32R_26_PLTREL, ++ BFD_RELOC_M32R_COPY, ++ BFD_RELOC_M32R_GLOB_DAT, ++ BFD_RELOC_M32R_JMP_SLOT, ++ BFD_RELOC_M32R_RELATIVE, ++ BFD_RELOC_M32R_GOTOFF, ++ BFD_RELOC_M32R_GOTOFF_HI_ULO, ++ BFD_RELOC_M32R_GOTOFF_HI_SLO, ++ BFD_RELOC_M32R_GOTOFF_LO, ++ BFD_RELOC_M32R_GOTPC24, ++ BFD_RELOC_M32R_GOT16_HI_ULO, ++ BFD_RELOC_M32R_GOT16_HI_SLO, ++ BFD_RELOC_M32R_GOT16_LO, ++ BFD_RELOC_M32R_GOTPC_HI_ULO, ++ BFD_RELOC_M32R_GOTPC_HI_SLO, ++ BFD_RELOC_M32R_GOTPC_LO, ++ ++/* This is a 9-bit reloc */ ++ BFD_RELOC_V850_9_PCREL, ++ ++/* This is a 22-bit reloc */ ++ BFD_RELOC_V850_22_PCREL, ++ ++/* This is a 16 bit offset from the short data area pointer. */ ++ BFD_RELOC_V850_SDA_16_16_OFFSET, ++ ++/* This is a 16 bit offset (of which only 15 bits are used) from the ++short data area pointer. */ ++ BFD_RELOC_V850_SDA_15_16_OFFSET, ++ ++/* This is a 16 bit offset from the zero data area pointer. */ ++ BFD_RELOC_V850_ZDA_16_16_OFFSET, ++ ++/* This is a 16 bit offset (of which only 15 bits are used) from the ++zero data area pointer. */ ++ BFD_RELOC_V850_ZDA_15_16_OFFSET, ++ ++/* This is an 8 bit offset (of which only 6 bits are used) from the ++tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_6_8_OFFSET, ++ ++/* This is an 8bit offset (of which only 7 bits are used) from the tiny ++data area pointer. */ ++ BFD_RELOC_V850_TDA_7_8_OFFSET, ++ ++/* This is a 7 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_7_7_OFFSET, ++ ++/* This is a 16 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_16_16_OFFSET, ++ ++/* This is a 5 bit offset (of which only 4 bits are used) from the tiny ++data area pointer. */ ++ BFD_RELOC_V850_TDA_4_5_OFFSET, ++ ++/* This is a 4 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_4_4_OFFSET, ++ ++/* This is a 16 bit offset from the short data area pointer, with the ++bits placed non-contiguously in the instruction. */ ++ BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, ++ ++/* This is a 16 bit offset from the zero data area pointer, with the ++bits placed non-contiguously in the instruction. */ ++ BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, ++ ++/* This is a 6 bit offset from the call table base pointer. */ ++ BFD_RELOC_V850_CALLT_6_7_OFFSET, ++ ++/* This is a 16 bit offset from the call table base pointer. */ ++ BFD_RELOC_V850_CALLT_16_16_OFFSET, ++ ++/* Used for relaxing indirect function calls. */ ++ BFD_RELOC_V850_LONGCALL, ++ ++/* Used for relaxing indirect jumps. */ ++ BFD_RELOC_V850_LONGJUMP, ++ ++/* Used to maintain alignment whilst relaxing. */ ++ BFD_RELOC_V850_ALIGN, ++ ++/* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu ++instructions. */ ++ BFD_RELOC_V850_LO16_SPLIT_OFFSET, ++ ++/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the ++instruction. */ ++ BFD_RELOC_MN10300_32_PCREL, ++ ++/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the ++instruction. */ ++ BFD_RELOC_MN10300_16_PCREL, ++ ++/* This is a 8bit DP reloc for the tms320c30, where the most ++significant 8 bits of a 24 bit word are placed into the least ++significant 8 bits of the opcode. */ ++ BFD_RELOC_TIC30_LDP, ++ ++/* This is a 7bit reloc for the tms320c54x, where the least ++significant 7 bits of a 16 bit word are placed into the least ++significant 7 bits of the opcode. */ ++ BFD_RELOC_TIC54X_PARTLS7, ++ ++/* This is a 9bit DP reloc for the tms320c54x, where the most ++significant 9 bits of a 16 bit word are placed into the least ++significant 9 bits of the opcode. */ ++ BFD_RELOC_TIC54X_PARTMS9, ++ ++/* This is an extended address 23-bit reloc for the tms320c54x. */ ++ BFD_RELOC_TIC54X_23, ++ ++/* This is a 16-bit reloc for the tms320c54x, where the least ++significant 16 bits of a 23-bit extended address are placed into ++the opcode. */ ++ BFD_RELOC_TIC54X_16_OF_23, ++ ++/* This is a reloc for the tms320c54x, where the most ++significant 7 bits of a 23-bit extended address are placed into ++the opcode. */ ++ BFD_RELOC_TIC54X_MS7_OF_23, ++ ++/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ ++ BFD_RELOC_FR30_48, ++ ++/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into ++two sections. */ ++ BFD_RELOC_FR30_20, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in ++4 bits. */ ++ BFD_RELOC_FR30_6_IN_4, ++ ++/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset ++into 8 bits. */ ++ BFD_RELOC_FR30_8_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset ++into 8 bits. */ ++ BFD_RELOC_FR30_9_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset ++into 8 bits. */ ++ BFD_RELOC_FR30_10_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative ++short offset into 8 bits. */ ++ BFD_RELOC_FR30_9_PCREL, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative ++short offset into 11 bits. */ ++ BFD_RELOC_FR30_12_PCREL, ++ ++/* Motorola Mcore relocations. */ ++ BFD_RELOC_MCORE_PCREL_IMM8BY4, ++ BFD_RELOC_MCORE_PCREL_IMM11BY2, ++ BFD_RELOC_MCORE_PCREL_IMM4BY2, ++ BFD_RELOC_MCORE_PCREL_32, ++ BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, ++ BFD_RELOC_MCORE_RVA, ++ ++/* These are relocations for the GETA instruction. */ ++ BFD_RELOC_MMIX_GETA, ++ BFD_RELOC_MMIX_GETA_1, ++ BFD_RELOC_MMIX_GETA_2, ++ BFD_RELOC_MMIX_GETA_3, ++ ++/* These are relocations for a conditional branch instruction. */ ++ BFD_RELOC_MMIX_CBRANCH, ++ BFD_RELOC_MMIX_CBRANCH_J, ++ BFD_RELOC_MMIX_CBRANCH_1, ++ BFD_RELOC_MMIX_CBRANCH_2, ++ BFD_RELOC_MMIX_CBRANCH_3, ++ ++/* These are relocations for the PUSHJ instruction. */ ++ BFD_RELOC_MMIX_PUSHJ, ++ BFD_RELOC_MMIX_PUSHJ_1, ++ BFD_RELOC_MMIX_PUSHJ_2, ++ BFD_RELOC_MMIX_PUSHJ_3, ++ BFD_RELOC_MMIX_PUSHJ_STUBBABLE, ++ ++/* These are relocations for the JMP instruction. */ ++ BFD_RELOC_MMIX_JMP, ++ BFD_RELOC_MMIX_JMP_1, ++ BFD_RELOC_MMIX_JMP_2, ++ BFD_RELOC_MMIX_JMP_3, ++ ++/* This is a relocation for a relative address as in a GETA instruction or ++a branch. */ ++ BFD_RELOC_MMIX_ADDR19, ++ ++/* This is a relocation for a relative address as in a JMP instruction. */ ++ BFD_RELOC_MMIX_ADDR27, ++ ++/* This is a relocation for an instruction field that may be a general ++register or a value 0..255. */ ++ BFD_RELOC_MMIX_REG_OR_BYTE, ++ ++/* This is a relocation for an instruction field that may be a general ++register. */ ++ BFD_RELOC_MMIX_REG, ++ ++/* This is a relocation for two instruction fields holding a register and ++an offset, the equivalent of the relocation. */ ++ BFD_RELOC_MMIX_BASE_PLUS_OFFSET, ++ ++/* This relocation is an assertion that the expression is not allocated as ++a global register. It does not modify contents. */ ++ BFD_RELOC_MMIX_LOCAL, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative ++short offset into 7 bits. */ ++ BFD_RELOC_AVR_7_PCREL, ++ ++/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative ++short offset into 12 bits. */ ++ BFD_RELOC_AVR_13_PCREL, ++ ++/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually ++program memory address) into 16 bits. */ ++ BFD_RELOC_AVR_16_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually ++data memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_LO8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit ++of data memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HI8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit ++of program memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HH8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(usually data memory address) into 8 bit immediate value of SUBI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 8 bit of data memory address) into 8 bit immediate value of ++SUBI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(most high 8 bit of program memory address) into 8 bit immediate value ++of LDI or SUBI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually ++command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit ++of command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit ++of command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(usually command address) into 8 bit immediate value of SUBI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_PM_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 8 bit of 16 bit command address) into 8 bit immediate value ++of SUBI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_PM_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 6 bit of 22 bit command address) into 8 bit immediate ++value of SUBI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_PM_NEG, ++ ++/* This is a 32 bit reloc for the AVR that stores 23 bit value ++into 22 bits. */ ++ BFD_RELOC_AVR_CALL, ++ ++/* This is a 16 bit reloc for the AVR that stores all needed bits ++for absolute addressing with ldi with overflow check to linktime */ ++ BFD_RELOC_AVR_LDI, ++ ++/* This is a 6 bit reloc for the AVR that stores offset for ldd/std ++instructions */ ++ BFD_RELOC_AVR_6, ++ ++/* This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw ++instructions */ ++ BFD_RELOC_AVR_6_ADIW, ++ ++/* Direct 12 bit. */ ++ BFD_RELOC_390_12, ++ ++/* 12 bit GOT offset. */ ++ BFD_RELOC_390_GOT12, ++ ++/* 32 bit PC relative PLT address. */ ++ BFD_RELOC_390_PLT32, ++ ++/* Copy symbol at runtime. */ ++ BFD_RELOC_390_COPY, ++ ++/* Create GOT entry. */ ++ BFD_RELOC_390_GLOB_DAT, ++ ++/* Create PLT entry. */ ++ BFD_RELOC_390_JMP_SLOT, ++ ++/* Adjust by program base. */ ++ BFD_RELOC_390_RELATIVE, ++ ++/* 32 bit PC relative offset to GOT. */ ++ BFD_RELOC_390_GOTPC, ++ ++/* 16 bit GOT offset. */ ++ BFD_RELOC_390_GOT16, ++ ++/* PC relative 16 bit shifted by 1. */ ++ BFD_RELOC_390_PC16DBL, ++ ++/* 16 bit PC rel. PLT shifted by 1. */ ++ BFD_RELOC_390_PLT16DBL, ++ ++/* PC relative 32 bit shifted by 1. */ ++ BFD_RELOC_390_PC32DBL, ++ ++/* 32 bit PC rel. PLT shifted by 1. */ ++ BFD_RELOC_390_PLT32DBL, ++ ++/* 32 bit PC rel. GOT shifted by 1. */ ++ BFD_RELOC_390_GOTPCDBL, ++ ++/* 64 bit GOT offset. */ ++ BFD_RELOC_390_GOT64, ++ ++/* 64 bit PC relative PLT address. */ ++ BFD_RELOC_390_PLT64, ++ ++/* 32 bit rel. offset to GOT entry. */ ++ BFD_RELOC_390_GOTENT, ++ ++/* 64 bit offset to GOT. */ ++ BFD_RELOC_390_GOTOFF64, ++ ++/* 12-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT12, ++ ++/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT16, ++ ++/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT32, ++ ++/* 64-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT64, ++ ++/* 32-bit rel. offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLTENT, ++ ++/* 16-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF16, ++ ++/* 32-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF32, ++ ++/* 64-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF64, ++ ++/* s390 tls relocations. */ ++ BFD_RELOC_390_TLS_LOAD, ++ BFD_RELOC_390_TLS_GDCALL, ++ BFD_RELOC_390_TLS_LDCALL, ++ BFD_RELOC_390_TLS_GD32, ++ BFD_RELOC_390_TLS_GD64, ++ BFD_RELOC_390_TLS_GOTIE12, ++ BFD_RELOC_390_TLS_GOTIE32, ++ BFD_RELOC_390_TLS_GOTIE64, ++ BFD_RELOC_390_TLS_LDM32, ++ BFD_RELOC_390_TLS_LDM64, ++ BFD_RELOC_390_TLS_IE32, ++ BFD_RELOC_390_TLS_IE64, ++ BFD_RELOC_390_TLS_IEENT, ++ BFD_RELOC_390_TLS_LE32, ++ BFD_RELOC_390_TLS_LE64, ++ BFD_RELOC_390_TLS_LDO32, ++ BFD_RELOC_390_TLS_LDO64, ++ BFD_RELOC_390_TLS_DTPMOD, ++ BFD_RELOC_390_TLS_DTPOFF, ++ BFD_RELOC_390_TLS_TPOFF, ++ ++/* Long displacement extension. */ ++ BFD_RELOC_390_20, ++ BFD_RELOC_390_GOT20, ++ BFD_RELOC_390_GOTPLT20, ++ BFD_RELOC_390_TLS_GOTIE20, ++ ++/* Scenix IP2K - 9-bit register number / data address */ ++ BFD_RELOC_IP2K_FR9, ++ ++/* Scenix IP2K - 4-bit register/data bank number */ ++ BFD_RELOC_IP2K_BANK, ++ ++/* Scenix IP2K - low 13 bits of instruction word address */ ++ BFD_RELOC_IP2K_ADDR16CJP, ++ ++/* Scenix IP2K - high 3 bits of instruction word address */ ++ BFD_RELOC_IP2K_PAGE3, ++ ++/* Scenix IP2K - ext/low/high 8 bits of data address */ ++ BFD_RELOC_IP2K_LO8DATA, ++ BFD_RELOC_IP2K_HI8DATA, ++ BFD_RELOC_IP2K_EX8DATA, ++ ++/* Scenix IP2K - low/high 8 bits of instruction word address */ ++ BFD_RELOC_IP2K_LO8INSN, ++ BFD_RELOC_IP2K_HI8INSN, ++ ++/* Scenix IP2K - even/odd PC modifier to modify snb pcl.0 */ ++ BFD_RELOC_IP2K_PC_SKIP, ++ ++/* Scenix IP2K - 16 bit word address in text section. */ ++ BFD_RELOC_IP2K_TEXT, ++ ++/* Scenix IP2K - 7-bit sp or dp offset */ ++ BFD_RELOC_IP2K_FR_OFFSET, ++ ++/* Scenix VPE4K coprocessor - data/insn-space addressing */ ++ BFD_RELOC_VPE4KMATH_DATA, ++ BFD_RELOC_VPE4KMATH_INSN, ++ ++/* These two relocations are used by the linker to determine which of ++the entries in a C++ virtual function table are actually used. When ++the --gc-sections option is given, the linker will zero out the entries ++that are not used, so that the code for those functions need not be ++included in the output. ++ ++VTABLE_INHERIT is a zero-space relocation used to describe to the ++linker the inheritance tree of a C++ virtual function table. The ++relocation's symbol should be the parent class' vtable, and the ++relocation should be located at the child vtable. ++ ++VTABLE_ENTRY is a zero-space relocation that describes the use of a ++virtual function table entry. The reloc's symbol should refer to the ++table of the class mentioned in the code. Off of that base, an offset ++describes the entry that is being used. For Rela hosts, this offset ++is stored in the reloc's addend. For Rel hosts, we are forced to put ++this offset in the reloc's section offset. */ ++ BFD_RELOC_VTABLE_INHERIT, ++ BFD_RELOC_VTABLE_ENTRY, ++ ++/* Intel IA64 Relocations. */ ++ BFD_RELOC_IA64_IMM14, ++ BFD_RELOC_IA64_IMM22, ++ BFD_RELOC_IA64_IMM64, ++ BFD_RELOC_IA64_DIR32MSB, ++ BFD_RELOC_IA64_DIR32LSB, ++ BFD_RELOC_IA64_DIR64MSB, ++ BFD_RELOC_IA64_DIR64LSB, ++ BFD_RELOC_IA64_GPREL22, ++ BFD_RELOC_IA64_GPREL64I, ++ BFD_RELOC_IA64_GPREL32MSB, ++ BFD_RELOC_IA64_GPREL32LSB, ++ BFD_RELOC_IA64_GPREL64MSB, ++ BFD_RELOC_IA64_GPREL64LSB, ++ BFD_RELOC_IA64_LTOFF22, ++ BFD_RELOC_IA64_LTOFF64I, ++ BFD_RELOC_IA64_PLTOFF22, ++ BFD_RELOC_IA64_PLTOFF64I, ++ BFD_RELOC_IA64_PLTOFF64MSB, ++ BFD_RELOC_IA64_PLTOFF64LSB, ++ BFD_RELOC_IA64_FPTR64I, ++ BFD_RELOC_IA64_FPTR32MSB, ++ BFD_RELOC_IA64_FPTR32LSB, ++ BFD_RELOC_IA64_FPTR64MSB, ++ BFD_RELOC_IA64_FPTR64LSB, ++ BFD_RELOC_IA64_PCREL21B, ++ BFD_RELOC_IA64_PCREL21BI, ++ BFD_RELOC_IA64_PCREL21M, ++ BFD_RELOC_IA64_PCREL21F, ++ BFD_RELOC_IA64_PCREL22, ++ BFD_RELOC_IA64_PCREL60B, ++ BFD_RELOC_IA64_PCREL64I, ++ BFD_RELOC_IA64_PCREL32MSB, ++ BFD_RELOC_IA64_PCREL32LSB, ++ BFD_RELOC_IA64_PCREL64MSB, ++ BFD_RELOC_IA64_PCREL64LSB, ++ BFD_RELOC_IA64_LTOFF_FPTR22, ++ BFD_RELOC_IA64_LTOFF_FPTR64I, ++ BFD_RELOC_IA64_LTOFF_FPTR32MSB, ++ BFD_RELOC_IA64_LTOFF_FPTR32LSB, ++ BFD_RELOC_IA64_LTOFF_FPTR64MSB, ++ BFD_RELOC_IA64_LTOFF_FPTR64LSB, ++ BFD_RELOC_IA64_SEGREL32MSB, ++ BFD_RELOC_IA64_SEGREL32LSB, ++ BFD_RELOC_IA64_SEGREL64MSB, ++ BFD_RELOC_IA64_SEGREL64LSB, ++ BFD_RELOC_IA64_SECREL32MSB, ++ BFD_RELOC_IA64_SECREL32LSB, ++ BFD_RELOC_IA64_SECREL64MSB, ++ BFD_RELOC_IA64_SECREL64LSB, ++ BFD_RELOC_IA64_REL32MSB, ++ BFD_RELOC_IA64_REL32LSB, ++ BFD_RELOC_IA64_REL64MSB, ++ BFD_RELOC_IA64_REL64LSB, ++ BFD_RELOC_IA64_LTV32MSB, ++ BFD_RELOC_IA64_LTV32LSB, ++ BFD_RELOC_IA64_LTV64MSB, ++ BFD_RELOC_IA64_LTV64LSB, ++ BFD_RELOC_IA64_IPLTMSB, ++ BFD_RELOC_IA64_IPLTLSB, ++ BFD_RELOC_IA64_COPY, ++ BFD_RELOC_IA64_LTOFF22X, ++ BFD_RELOC_IA64_LDXMOV, ++ BFD_RELOC_IA64_TPREL14, ++ BFD_RELOC_IA64_TPREL22, ++ BFD_RELOC_IA64_TPREL64I, ++ BFD_RELOC_IA64_TPREL64MSB, ++ BFD_RELOC_IA64_TPREL64LSB, ++ BFD_RELOC_IA64_LTOFF_TPREL22, ++ BFD_RELOC_IA64_DTPMOD64MSB, ++ BFD_RELOC_IA64_DTPMOD64LSB, ++ BFD_RELOC_IA64_LTOFF_DTPMOD22, ++ BFD_RELOC_IA64_DTPREL14, ++ BFD_RELOC_IA64_DTPREL22, ++ BFD_RELOC_IA64_DTPREL64I, ++ BFD_RELOC_IA64_DTPREL32MSB, ++ BFD_RELOC_IA64_DTPREL32LSB, ++ BFD_RELOC_IA64_DTPREL64MSB, ++ BFD_RELOC_IA64_DTPREL64LSB, ++ BFD_RELOC_IA64_LTOFF_DTPREL22, ++ ++/* Motorola 68HC11 reloc. ++This is the 8 bit high part of an absolute address. */ ++ BFD_RELOC_M68HC11_HI8, ++ ++/* Motorola 68HC11 reloc. ++This is the 8 bit low part of an absolute address. */ ++ BFD_RELOC_M68HC11_LO8, ++ ++/* Motorola 68HC11 reloc. ++This is the 3 bit of a value. */ ++ BFD_RELOC_M68HC11_3B, ++ ++/* Motorola 68HC11 reloc. ++This reloc marks the beginning of a jump/call instruction. ++It is used for linker relaxation to correctly identify beginning ++of instruction and change some branches to use PC-relative ++addressing mode. */ ++ BFD_RELOC_M68HC11_RL_JUMP, ++ ++/* Motorola 68HC11 reloc. ++This reloc marks a group of several instructions that gcc generates ++and for which the linker relaxation pass can modify and/or remove ++some of them. */ ++ BFD_RELOC_M68HC11_RL_GROUP, ++ ++/* Motorola 68HC11 reloc. ++This is the 16-bit lower part of an address. It is used for 'call' ++instruction to specify the symbol address without any special ++transformation (due to memory bank window). */ ++ BFD_RELOC_M68HC11_LO16, ++ ++/* Motorola 68HC11 reloc. ++This is a 8-bit reloc that specifies the page number of an address. ++It is used by 'call' instruction to specify the page number of ++the symbol. */ ++ BFD_RELOC_M68HC11_PAGE, ++ ++/* Motorola 68HC11 reloc. ++This is a 24-bit reloc that represents the address with a 16-bit ++value and a 8-bit page number. The symbol address is transformed ++to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ ++ BFD_RELOC_M68HC11_24, ++ ++/* Motorola 68HC12 reloc. ++This is the 5 bits of a value. */ ++ BFD_RELOC_M68HC12_5B, ++ ++/* NS CR16C Relocations. */ ++ BFD_RELOC_16C_NUM08, ++ BFD_RELOC_16C_NUM08_C, ++ BFD_RELOC_16C_NUM16, ++ BFD_RELOC_16C_NUM16_C, ++ BFD_RELOC_16C_NUM32, ++ BFD_RELOC_16C_NUM32_C, ++ BFD_RELOC_16C_DISP04, ++ BFD_RELOC_16C_DISP04_C, ++ BFD_RELOC_16C_DISP08, ++ BFD_RELOC_16C_DISP08_C, ++ BFD_RELOC_16C_DISP16, ++ BFD_RELOC_16C_DISP16_C, ++ BFD_RELOC_16C_DISP24, ++ BFD_RELOC_16C_DISP24_C, ++ BFD_RELOC_16C_DISP24a, ++ BFD_RELOC_16C_DISP24a_C, ++ BFD_RELOC_16C_REG04, ++ BFD_RELOC_16C_REG04_C, ++ BFD_RELOC_16C_REG04a, ++ BFD_RELOC_16C_REG04a_C, ++ BFD_RELOC_16C_REG14, ++ BFD_RELOC_16C_REG14_C, ++ BFD_RELOC_16C_REG16, ++ BFD_RELOC_16C_REG16_C, ++ BFD_RELOC_16C_REG20, ++ BFD_RELOC_16C_REG20_C, ++ BFD_RELOC_16C_ABS20, ++ BFD_RELOC_16C_ABS20_C, ++ BFD_RELOC_16C_ABS24, ++ BFD_RELOC_16C_ABS24_C, ++ BFD_RELOC_16C_IMM04, ++ BFD_RELOC_16C_IMM04_C, ++ BFD_RELOC_16C_IMM16, ++ BFD_RELOC_16C_IMM16_C, ++ BFD_RELOC_16C_IMM20, ++ BFD_RELOC_16C_IMM20_C, ++ BFD_RELOC_16C_IMM24, ++ BFD_RELOC_16C_IMM24_C, ++ BFD_RELOC_16C_IMM32, ++ BFD_RELOC_16C_IMM32_C, ++ ++/* NS CRX Relocations. */ ++ BFD_RELOC_CRX_REL4, ++ BFD_RELOC_CRX_REL8, ++ BFD_RELOC_CRX_REL8_CMP, ++ BFD_RELOC_CRX_REL16, ++ BFD_RELOC_CRX_REL24, ++ BFD_RELOC_CRX_REL32, ++ BFD_RELOC_CRX_REGREL12, ++ BFD_RELOC_CRX_REGREL22, ++ BFD_RELOC_CRX_REGREL28, ++ BFD_RELOC_CRX_REGREL32, ++ BFD_RELOC_CRX_ABS16, ++ BFD_RELOC_CRX_ABS32, ++ BFD_RELOC_CRX_NUM8, ++ BFD_RELOC_CRX_NUM16, ++ BFD_RELOC_CRX_NUM32, ++ BFD_RELOC_CRX_IMM16, ++ BFD_RELOC_CRX_IMM32, ++ BFD_RELOC_CRX_SWITCH8, ++ BFD_RELOC_CRX_SWITCH16, ++ BFD_RELOC_CRX_SWITCH32, ++ ++/* These relocs are only used within the CRIS assembler. They are not ++(at present) written to any object files. */ ++ BFD_RELOC_CRIS_BDISP8, ++ BFD_RELOC_CRIS_UNSIGNED_5, ++ BFD_RELOC_CRIS_SIGNED_6, ++ BFD_RELOC_CRIS_UNSIGNED_6, ++ BFD_RELOC_CRIS_SIGNED_8, ++ BFD_RELOC_CRIS_UNSIGNED_8, ++ BFD_RELOC_CRIS_SIGNED_16, ++ BFD_RELOC_CRIS_UNSIGNED_16, ++ BFD_RELOC_CRIS_LAPCQ_OFFSET, ++ BFD_RELOC_CRIS_UNSIGNED_4, ++ ++/* Relocs used in ELF shared libraries for CRIS. */ ++ BFD_RELOC_CRIS_COPY, ++ BFD_RELOC_CRIS_GLOB_DAT, ++ BFD_RELOC_CRIS_JUMP_SLOT, ++ BFD_RELOC_CRIS_RELATIVE, ++ ++/* 32-bit offset to symbol-entry within GOT. */ ++ BFD_RELOC_CRIS_32_GOT, ++ ++/* 16-bit offset to symbol-entry within GOT. */ ++ BFD_RELOC_CRIS_16_GOT, ++ ++/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_CRIS_32_GOTPLT, ++ ++/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_CRIS_16_GOTPLT, ++ ++/* 32-bit offset to symbol, relative to GOT. */ ++ BFD_RELOC_CRIS_32_GOTREL, ++ ++/* 32-bit offset to symbol with PLT entry, relative to GOT. */ ++ BFD_RELOC_CRIS_32_PLT_GOTREL, ++ ++/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ ++ BFD_RELOC_CRIS_32_PLT_PCREL, ++ ++/* Intel i860 Relocations. */ ++ BFD_RELOC_860_COPY, ++ BFD_RELOC_860_GLOB_DAT, ++ BFD_RELOC_860_JUMP_SLOT, ++ BFD_RELOC_860_RELATIVE, ++ BFD_RELOC_860_PC26, ++ BFD_RELOC_860_PLT26, ++ BFD_RELOC_860_PC16, ++ BFD_RELOC_860_LOW0, ++ BFD_RELOC_860_SPLIT0, ++ BFD_RELOC_860_LOW1, ++ BFD_RELOC_860_SPLIT1, ++ BFD_RELOC_860_LOW2, ++ BFD_RELOC_860_SPLIT2, ++ BFD_RELOC_860_LOW3, ++ BFD_RELOC_860_LOGOT0, ++ BFD_RELOC_860_SPGOT0, ++ BFD_RELOC_860_LOGOT1, ++ BFD_RELOC_860_SPGOT1, ++ BFD_RELOC_860_LOGOTOFF0, ++ BFD_RELOC_860_SPGOTOFF0, ++ BFD_RELOC_860_LOGOTOFF1, ++ BFD_RELOC_860_SPGOTOFF1, ++ BFD_RELOC_860_LOGOTOFF2, ++ BFD_RELOC_860_LOGOTOFF3, ++ BFD_RELOC_860_LOPC, ++ BFD_RELOC_860_HIGHADJ, ++ BFD_RELOC_860_HAGOT, ++ BFD_RELOC_860_HAGOTOFF, ++ BFD_RELOC_860_HAPC, ++ BFD_RELOC_860_HIGH, ++ BFD_RELOC_860_HIGOT, ++ BFD_RELOC_860_HIGOTOFF, ++ ++/* OpenRISC Relocations. */ ++ BFD_RELOC_OPENRISC_ABS_26, ++ BFD_RELOC_OPENRISC_REL_26, ++ ++/* H8 elf Relocations. */ ++ BFD_RELOC_H8_DIR16A8, ++ BFD_RELOC_H8_DIR16R8, ++ BFD_RELOC_H8_DIR24A8, ++ BFD_RELOC_H8_DIR24R8, ++ BFD_RELOC_H8_DIR32A16, ++ ++/* Sony Xstormy16 Relocations. */ ++ BFD_RELOC_XSTORMY16_REL_12, ++ BFD_RELOC_XSTORMY16_12, ++ BFD_RELOC_XSTORMY16_24, ++ BFD_RELOC_XSTORMY16_FPTR16, ++ ++/* Relocations used by VAX ELF. */ ++ BFD_RELOC_VAX_GLOB_DAT, ++ BFD_RELOC_VAX_JMP_SLOT, ++ BFD_RELOC_VAX_RELATIVE, ++ ++/* Morpho MT - 16 bit immediate relocation. */ ++ BFD_RELOC_MT_PC16, ++ ++/* Morpho MT - Hi 16 bits of an address. */ ++ BFD_RELOC_MT_HI16, ++ ++/* Morpho MT - Low 16 bits of an address. */ ++ BFD_RELOC_MT_LO16, ++ ++/* Morpho MT - Used to tell the linker which vtable entries are used. */ ++ BFD_RELOC_MT_GNU_VTINHERIT, ++ ++/* Morpho MT - Used to tell the linker which vtable entries are used. */ ++ BFD_RELOC_MT_GNU_VTENTRY, ++ ++/* Morpho MT - 8 bit immediate relocation. */ ++ BFD_RELOC_MT_PCINSN8, ++ ++/* msp430 specific relocation codes */ ++ BFD_RELOC_MSP430_10_PCREL, ++ BFD_RELOC_MSP430_16_PCREL, ++ BFD_RELOC_MSP430_16, ++ BFD_RELOC_MSP430_16_PCREL_BYTE, ++ BFD_RELOC_MSP430_16_BYTE, ++ BFD_RELOC_MSP430_2X_PCREL, ++ BFD_RELOC_MSP430_RL_PCREL, ++ ++/* IQ2000 Relocations. */ ++ BFD_RELOC_IQ2000_OFFSET_16, ++ BFD_RELOC_IQ2000_OFFSET_21, ++ BFD_RELOC_IQ2000_UHI16, ++ ++/* Special Xtensa relocation used only by PLT entries in ELF shared ++objects to indicate that the runtime linker should set the value ++to one of its own internal functions or data structures. */ ++ BFD_RELOC_XTENSA_RTLD, ++ ++/* Xtensa relocations for ELF shared objects. */ ++ BFD_RELOC_XTENSA_GLOB_DAT, ++ BFD_RELOC_XTENSA_JMP_SLOT, ++ BFD_RELOC_XTENSA_RELATIVE, ++ ++/* Xtensa relocation used in ELF object files for symbols that may require ++PLT entries. Otherwise, this is just a generic 32-bit relocation. */ ++ BFD_RELOC_XTENSA_PLT, ++ ++/* Xtensa relocations to mark the difference of two local symbols. ++These are only needed to support linker relaxation and can be ignored ++when not relaxing. The field is set to the value of the difference ++assuming no relaxation. The relocation encodes the position of the ++first symbol so the linker can determine whether to adjust the field ++value. */ ++ BFD_RELOC_XTENSA_DIFF8, ++ BFD_RELOC_XTENSA_DIFF16, ++ BFD_RELOC_XTENSA_DIFF32, ++ ++/* Generic Xtensa relocations for instruction operands. Only the slot ++number is encoded in the relocation. The relocation applies to the ++last PC-relative immediate operand, or if there are no PC-relative ++immediates, to the last immediate operand. */ ++ BFD_RELOC_XTENSA_SLOT0_OP, ++ BFD_RELOC_XTENSA_SLOT1_OP, ++ BFD_RELOC_XTENSA_SLOT2_OP, ++ BFD_RELOC_XTENSA_SLOT3_OP, ++ BFD_RELOC_XTENSA_SLOT4_OP, ++ BFD_RELOC_XTENSA_SLOT5_OP, ++ BFD_RELOC_XTENSA_SLOT6_OP, ++ BFD_RELOC_XTENSA_SLOT7_OP, ++ BFD_RELOC_XTENSA_SLOT8_OP, ++ BFD_RELOC_XTENSA_SLOT9_OP, ++ BFD_RELOC_XTENSA_SLOT10_OP, ++ BFD_RELOC_XTENSA_SLOT11_OP, ++ BFD_RELOC_XTENSA_SLOT12_OP, ++ BFD_RELOC_XTENSA_SLOT13_OP, ++ BFD_RELOC_XTENSA_SLOT14_OP, ++ ++/* Alternate Xtensa relocations. Only the slot is encoded in the ++relocation. The meaning of these relocations is opcode-specific. */ ++ BFD_RELOC_XTENSA_SLOT0_ALT, ++ BFD_RELOC_XTENSA_SLOT1_ALT, ++ BFD_RELOC_XTENSA_SLOT2_ALT, ++ BFD_RELOC_XTENSA_SLOT3_ALT, ++ BFD_RELOC_XTENSA_SLOT4_ALT, ++ BFD_RELOC_XTENSA_SLOT5_ALT, ++ BFD_RELOC_XTENSA_SLOT6_ALT, ++ BFD_RELOC_XTENSA_SLOT7_ALT, ++ BFD_RELOC_XTENSA_SLOT8_ALT, ++ BFD_RELOC_XTENSA_SLOT9_ALT, ++ BFD_RELOC_XTENSA_SLOT10_ALT, ++ BFD_RELOC_XTENSA_SLOT11_ALT, ++ BFD_RELOC_XTENSA_SLOT12_ALT, ++ BFD_RELOC_XTENSA_SLOT13_ALT, ++ BFD_RELOC_XTENSA_SLOT14_ALT, ++ ++/* Xtensa relocations for backward compatibility. These have all been ++replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ ++ BFD_RELOC_XTENSA_OP0, ++ BFD_RELOC_XTENSA_OP1, ++ BFD_RELOC_XTENSA_OP2, ++ ++/* Xtensa relocation to mark that the assembler expanded the ++instructions from an original target. The expansion size is ++encoded in the reloc size. */ ++ BFD_RELOC_XTENSA_ASM_EXPAND, ++ ++/* Xtensa relocation to mark that the linker should simplify ++assembler-expanded instructions. This is commonly used ++internally by the linker after analysis of a ++BFD_RELOC_XTENSA_ASM_EXPAND. */ ++ BFD_RELOC_XTENSA_ASM_SIMPLIFY, ++ ++/* 8 bit signed offset in (ix+d) or (iy+d). */ ++ BFD_RELOC_Z80_DISP8, ++ ++/* DJNZ offset. */ ++ BFD_RELOC_Z8K_DISP7, ++ ++/* CALR offset. */ ++ BFD_RELOC_Z8K_CALLR, ++ ++/* 4 bit value. */ ++ BFD_RELOC_Z8K_IMM4L, ++ BFD_RELOC_UNUSED }; ++typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; ++reloc_howto_type *bfd_reloc_type_lookup ++ (bfd *abfd, bfd_reloc_code_real_type code); ++ ++const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); ++ ++/* Extracted from syms.c. */ ++ ++typedef struct bfd_symbol ++{ ++ /* A pointer to the BFD which owns the symbol. This information ++ is necessary so that a back end can work out what additional ++ information (invisible to the application writer) is carried ++ with the symbol. ++ ++ This field is *almost* redundant, since you can use section->owner ++ instead, except that some symbols point to the global sections ++ bfd_{abs,com,und}_section. This could be fixed by making ++ these globals be per-bfd (or per-target-flavor). FIXME. */ ++ struct bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ ++ ++ /* The text of the symbol. The name is left alone, and not copied; the ++ application may not alter it. */ ++ const char *name; ++ ++ /* The value of the symbol. This really should be a union of a ++ numeric value with a pointer, since some flags indicate that ++ a pointer to another symbol is stored here. */ ++ symvalue value; ++ ++ /* Attributes of a symbol. */ ++#define BSF_NO_FLAGS 0x00 ++ ++ /* The symbol has local scope; <> in <>. The value ++ is the offset into the section of the data. */ ++#define BSF_LOCAL 0x01 ++ ++ /* The symbol has global scope; initialized data in <>. The ++ value is the offset into the section of the data. */ ++#define BSF_GLOBAL 0x02 ++ ++ /* The symbol has global scope and is exported. The value is ++ the offset into the section of the data. */ ++#define BSF_EXPORT BSF_GLOBAL /* No real difference. */ ++ ++ /* A normal C symbol would be one of: ++ <>, <>, <> or ++ <>. */ ++ ++ /* The symbol is a debugging record. The value has an arbitrary ++ meaning, unless BSF_DEBUGGING_RELOC is also set. */ ++#define BSF_DEBUGGING 0x08 ++ ++ /* The symbol denotes a function entry point. Used in ELF, ++ perhaps others someday. */ ++#define BSF_FUNCTION 0x10 ++ ++ /* Used by the linker. */ ++#define BSF_KEEP 0x20 ++#define BSF_KEEP_G 0x40 ++ ++ /* A weak global symbol, overridable without warnings by ++ a regular global symbol of the same name. */ ++#define BSF_WEAK 0x80 ++ ++ /* This symbol was created to point to a section, e.g. ELF's ++ STT_SECTION symbols. */ ++#define BSF_SECTION_SYM 0x100 ++ ++ /* The symbol used to be a common symbol, but now it is ++ allocated. */ ++#define BSF_OLD_COMMON 0x200 ++ ++ /* The default value for common data. */ ++#define BFD_FORT_COMM_DEFAULT_VALUE 0 ++ ++ /* In some files the type of a symbol sometimes alters its ++ location in an output file - ie in coff a <> symbol ++ which is also <> symbol appears where it was ++ declared and not at the end of a section. This bit is set ++ by the target BFD part to convey this information. */ ++#define BSF_NOT_AT_END 0x400 ++ ++ /* Signal that the symbol is the label of constructor section. */ ++#define BSF_CONSTRUCTOR 0x800 ++ ++ /* Signal that the symbol is a warning symbol. The name is a ++ warning. The name of the next symbol is the one to warn about; ++ if a reference is made to a symbol with the same name as the next ++ symbol, a warning is issued by the linker. */ ++#define BSF_WARNING 0x1000 ++ ++ /* Signal that the symbol is indirect. This symbol is an indirect ++ pointer to the symbol with the same name as the next symbol. */ ++#define BSF_INDIRECT 0x2000 ++ ++ /* BSF_FILE marks symbols that contain a file name. This is used ++ for ELF STT_FILE symbols. */ ++#define BSF_FILE 0x4000 ++ ++ /* Symbol is from dynamic linking information. */ ++#define BSF_DYNAMIC 0x8000 ++ ++ /* The symbol denotes a data object. Used in ELF, and perhaps ++ others someday. */ ++#define BSF_OBJECT 0x10000 ++ ++ /* This symbol is a debugging symbol. The value is the offset ++ into the section of the data. BSF_DEBUGGING should be set ++ as well. */ ++#define BSF_DEBUGGING_RELOC 0x20000 ++ ++ /* This symbol is thread local. Used in ELF. */ ++#define BSF_THREAD_LOCAL 0x40000 ++ ++ flagword flags; ++ ++ /* A pointer to the section to which this symbol is ++ relative. This will always be non NULL, there are special ++ sections for undefined and absolute symbols. */ ++ struct bfd_section *section; ++ ++ /* Back end special data. */ ++ union ++ { ++ void *p; ++ bfd_vma i; ++ } ++ udata; ++} ++asymbol; ++ ++#define bfd_get_symtab_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) ++ ++bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); ++ ++bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); ++ ++#define bfd_is_local_label_name(abfd, name) \ ++ BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) ++ ++bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); ++ ++#define bfd_is_target_special_symbol(abfd, sym) \ ++ BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) ++ ++#define bfd_canonicalize_symtab(abfd, location) \ ++ BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) ++ ++bfd_boolean bfd_set_symtab ++ (bfd *abfd, asymbol **location, unsigned int count); ++ ++void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); ++ ++#define bfd_make_empty_symbol(abfd) \ ++ BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) ++ ++asymbol *_bfd_generic_make_empty_symbol (bfd *); ++ ++#define bfd_make_debug_symbol(abfd,ptr,size) \ ++ BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) ++ ++int bfd_decode_symclass (asymbol *symbol); ++ ++bfd_boolean bfd_is_undefined_symclass (int symclass); ++ ++void bfd_symbol_info (asymbol *symbol, symbol_info *ret); ++ ++bfd_boolean bfd_copy_private_symbol_data ++ (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); ++ ++#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ ++ BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ ++ (ibfd, isymbol, obfd, osymbol)) ++ ++/* Extracted from bfd.c. */ ++struct bfd ++{ ++ /* A unique identifier of the BFD */ ++ unsigned int id; ++ ++ /* The filename the application opened the BFD with. */ ++ const char *filename; ++ ++ /* A pointer to the target jump table. */ ++ const struct bfd_target *xvec; ++ ++ /* The IOSTREAM, and corresponding IO vector that provide access ++ to the file backing the BFD. */ ++ void *iostream; ++ const struct bfd_iovec *iovec; ++ ++ /* Is the file descriptor being cached? That is, can it be closed as ++ needed, and re-opened when accessed later? */ ++ bfd_boolean cacheable; ++ ++ /* Marks whether there was a default target specified when the ++ BFD was opened. This is used to select which matching algorithm ++ to use to choose the back end. */ ++ bfd_boolean target_defaulted; ++ ++ /* The caching routines use these to maintain a ++ least-recently-used list of BFDs. */ ++ struct bfd *lru_prev, *lru_next; ++ ++ /* When a file is closed by the caching routines, BFD retains ++ state information on the file here... */ ++ ufile_ptr where; ++ ++ /* ... and here: (``once'' means at least once). */ ++ bfd_boolean opened_once; ++ ++ /* Set if we have a locally maintained mtime value, rather than ++ getting it from the file each time. */ ++ bfd_boolean mtime_set; ++ ++ /* File modified time, if mtime_set is TRUE. */ ++ long mtime; ++ ++ /* Reserved for an unimplemented file locking extension. */ ++ int ifd; ++ ++ /* The format which belongs to the BFD. (object, core, etc.) */ ++ bfd_format format; ++ ++ /* The direction with which the BFD was opened. */ ++ enum bfd_direction ++ { ++ no_direction = 0, ++ read_direction = 1, ++ write_direction = 2, ++ both_direction = 3 ++ } ++ direction; ++ ++ /* Format_specific flags. */ ++ flagword flags; ++ ++ /* Currently my_archive is tested before adding origin to ++ anything. I believe that this can become always an add of ++ origin, with origin set to 0 for non archive files. */ ++ ufile_ptr origin; ++ ++ /* Remember when output has begun, to stop strange things ++ from happening. */ ++ bfd_boolean output_has_begun; ++ ++ /* A hash table for section names. */ ++ struct bfd_hash_table section_htab; ++ ++ /* Pointer to linked list of sections. */ ++ struct bfd_section *sections; ++ ++ /* The last section on the section list. */ ++ struct bfd_section *section_last; ++ ++ /* The number of sections. */ ++ unsigned int section_count; ++ ++ /* Stuff only useful for object files: ++ The start address. */ ++ bfd_vma start_address; ++ ++ /* Used for input and output. */ ++ unsigned int symcount; ++ ++ /* Symbol table for output BFD (with symcount entries). */ ++ struct bfd_symbol **outsymbols; ++ ++ /* Used for slurped dynamic symbol tables. */ ++ unsigned int dynsymcount; ++ ++ /* Pointer to structure which contains architecture information. */ ++ const struct bfd_arch_info *arch_info; ++ ++ /* Flag set if symbols from this BFD should not be exported. */ ++ bfd_boolean no_export; ++ ++ /* Stuff only useful for archives. */ ++ void *arelt_data; ++ struct bfd *my_archive; /* The containing archive BFD. */ ++ struct bfd *next; /* The next BFD in the archive. */ ++ struct bfd *archive_head; /* The first BFD in the archive. */ ++ bfd_boolean has_armap; ++ ++ /* A chain of BFD structures involved in a link. */ ++ struct bfd *link_next; ++ ++ /* A field used by _bfd_generic_link_add_archive_symbols. This will ++ be used only for archive elements. */ ++ int archive_pass; ++ ++ /* Used by the back end to hold private data. */ ++ union ++ { ++ struct aout_data_struct *aout_data; ++ struct artdata *aout_ar_data; ++ struct _oasys_data *oasys_obj_data; ++ struct _oasys_ar_data *oasys_ar_data; ++ struct coff_tdata *coff_obj_data; ++ struct pe_tdata *pe_obj_data; ++ struct xcoff_tdata *xcoff_obj_data; ++ struct ecoff_tdata *ecoff_obj_data; ++ struct ieee_data_struct *ieee_data; ++ struct ieee_ar_data_struct *ieee_ar_data; ++ struct srec_data_struct *srec_data; ++ struct ihex_data_struct *ihex_data; ++ struct tekhex_data_struct *tekhex_data; ++ struct elf_obj_tdata *elf_obj_data; ++ struct nlm_obj_tdata *nlm_obj_data; ++ struct bout_data_struct *bout_data; ++ struct mmo_data_struct *mmo_data; ++ struct sun_core_struct *sun_core_data; ++ struct sco5_core_struct *sco5_core_data; ++ struct trad_core_struct *trad_core_data; ++ struct som_data_struct *som_data; ++ struct hpux_core_struct *hpux_core_data; ++ struct hppabsd_core_struct *hppabsd_core_data; ++ struct sgi_core_struct *sgi_core_data; ++ struct lynx_core_struct *lynx_core_data; ++ struct osf_core_struct *osf_core_data; ++ struct cisco_core_struct *cisco_core_data; ++ struct versados_data_struct *versados_data; ++ struct netbsd_core_struct *netbsd_core_data; ++ struct mach_o_data_struct *mach_o_data; ++ struct mach_o_fat_data_struct *mach_o_fat_data; ++ struct bfd_pef_data_struct *pef_data; ++ struct bfd_pef_xlib_data_struct *pef_xlib_data; ++ struct bfd_sym_data_struct *sym_data; ++ void *any; ++ } ++ tdata; ++ ++ /* Used by the application to hold private data. */ ++ void *usrdata; ++ ++ /* Where all the allocated stuff under this BFD goes. This is a ++ struct objalloc *, but we use void * to avoid requiring the inclusion ++ of objalloc.h. */ ++ void *memory; ++}; ++ ++typedef enum bfd_error ++{ ++ bfd_error_no_error = 0, ++ bfd_error_system_call, ++ bfd_error_invalid_target, ++ bfd_error_wrong_format, ++ bfd_error_wrong_object_format, ++ bfd_error_invalid_operation, ++ bfd_error_no_memory, ++ bfd_error_no_symbols, ++ bfd_error_no_armap, ++ bfd_error_no_more_archived_files, ++ bfd_error_malformed_archive, ++ bfd_error_file_not_recognized, ++ bfd_error_file_ambiguously_recognized, ++ bfd_error_no_contents, ++ bfd_error_nonrepresentable_section, ++ bfd_error_no_debug_section, ++ bfd_error_bad_value, ++ bfd_error_file_truncated, ++ bfd_error_file_too_big, ++ bfd_error_invalid_error_code ++} ++bfd_error_type; ++ ++bfd_error_type bfd_get_error (void); ++ ++void bfd_set_error (bfd_error_type error_tag); ++ ++const char *bfd_errmsg (bfd_error_type error_tag); ++ ++void bfd_perror (const char *message); ++ ++typedef void (*bfd_error_handler_type) (const char *, ...); ++ ++bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); ++ ++void bfd_set_error_program_name (const char *); ++ ++bfd_error_handler_type bfd_get_error_handler (void); ++ ++long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); ++ ++long bfd_canonicalize_reloc ++ (bfd *abfd, asection *sec, arelent **loc, asymbol **syms); ++ ++void bfd_set_reloc ++ (bfd *abfd, asection *sec, arelent **rel, unsigned int count); ++ ++bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); ++ ++int bfd_get_arch_size (bfd *abfd); ++ ++int bfd_get_sign_extend_vma (bfd *abfd); ++ ++bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); ++ ++unsigned int bfd_get_gp_size (bfd *abfd); ++ ++void bfd_set_gp_size (bfd *abfd, unsigned int i); ++ ++bfd_vma bfd_scan_vma (const char *string, const char **end, int base); ++ ++bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_copy_private_header_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_copy_private_header_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_copy_private_bfd_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_merge_private_bfd_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); ++ ++#define bfd_set_private_flags(abfd, flags) \ ++ BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) ++#define bfd_sizeof_headers(abfd, reloc) \ ++ BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) ++ ++#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ ++ BFD_SEND (abfd, _bfd_find_nearest_line, \ ++ (abfd, sec, syms, off, file, func, line)) ++ ++#define bfd_find_line(abfd, syms, sym, file, line) \ ++ BFD_SEND (abfd, _bfd_find_line, \ ++ (abfd, syms, sym, file, line)) ++ ++#define bfd_find_inliner_info(abfd, file, func, line) \ ++ BFD_SEND (abfd, _bfd_find_inliner_info, \ ++ (abfd, file, func, line)) ++ ++#define bfd_debug_info_start(abfd) \ ++ BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) ++ ++#define bfd_debug_info_end(abfd) \ ++ BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) ++ ++#define bfd_debug_info_accumulate(abfd, section) \ ++ BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) ++ ++#define bfd_stat_arch_elt(abfd, stat) \ ++ BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) ++ ++#define bfd_update_armap_timestamp(abfd) \ ++ BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) ++ ++#define bfd_set_arch_mach(abfd, arch, mach)\ ++ BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) ++ ++#define bfd_relax_section(abfd, section, link_info, again) \ ++ BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) ++ ++#define bfd_gc_sections(abfd, link_info) \ ++ BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) ++ ++#define bfd_merge_sections(abfd, link_info) \ ++ BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) ++ ++#define bfd_is_group_section(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) ++ ++#define bfd_discard_group(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) ++ ++#define bfd_link_hash_table_create(abfd) \ ++ BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) ++ ++#define bfd_link_hash_table_free(abfd, hash) \ ++ BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) ++ ++#define bfd_link_add_symbols(abfd, info) \ ++ BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) ++ ++#define bfd_link_just_syms(abfd, sec, info) \ ++ BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) ++ ++#define bfd_final_link(abfd, info) \ ++ BFD_SEND (abfd, _bfd_final_link, (abfd, info)) ++ ++#define bfd_free_cached_info(abfd) \ ++ BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) ++ ++#define bfd_get_dynamic_symtab_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) ++ ++#define bfd_print_private_bfd_data(abfd, file)\ ++ BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) ++ ++#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ ++ BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) ++ ++#define bfd_get_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ ++ BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ ++ dyncount, dynsyms, ret)) ++ ++#define bfd_get_dynamic_reloc_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) ++ ++#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ ++ BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) ++ ++extern bfd_byte *bfd_get_relocated_section_contents ++ (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, ++ bfd_boolean, asymbol **); ++ ++bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); ++ ++struct bfd_preserve ++{ ++ void *marker; ++ void *tdata; ++ flagword flags; ++ const struct bfd_arch_info *arch_info; ++ struct bfd_section *sections; ++ struct bfd_section *section_last; ++ unsigned int section_count; ++ struct bfd_hash_table section_htab; ++}; ++ ++bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); ++ ++void bfd_preserve_restore (bfd *, struct bfd_preserve *); ++ ++void bfd_preserve_finish (bfd *, struct bfd_preserve *); ++ ++/* Extracted from archive.c. */ ++symindex bfd_get_next_mapent ++ (bfd *abfd, symindex previous, carsym **sym); ++ ++bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); ++ ++bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); ++ ++/* Extracted from corefile.c. */ ++const char *bfd_core_file_failing_command (bfd *abfd); ++ ++int bfd_core_file_failing_signal (bfd *abfd); ++ ++bfd_boolean core_file_matches_executable_p ++ (bfd *core_bfd, bfd *exec_bfd); ++ ++/* Extracted from targets.c. */ ++#define BFD_SEND(bfd, message, arglist) \ ++ ((*((bfd)->xvec->message)) arglist) ++ ++#ifdef DEBUG_BFD_SEND ++#undef BFD_SEND ++#define BFD_SEND(bfd, message, arglist) \ ++ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ ++ ((*((bfd)->xvec->message)) arglist) : \ ++ (bfd_assert (__FILE__,__LINE__), NULL)) ++#endif ++#define BFD_SEND_FMT(bfd, message, arglist) \ ++ (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) ++ ++#ifdef DEBUG_BFD_SEND ++#undef BFD_SEND_FMT ++#define BFD_SEND_FMT(bfd, message, arglist) \ ++ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ ++ (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ ++ (bfd_assert (__FILE__,__LINE__), NULL)) ++#endif ++ ++enum bfd_flavour ++{ ++ bfd_target_unknown_flavour, ++ bfd_target_aout_flavour, ++ bfd_target_coff_flavour, ++ bfd_target_ecoff_flavour, ++ bfd_target_xcoff_flavour, ++ bfd_target_elf_flavour, ++ bfd_target_ieee_flavour, ++ bfd_target_nlm_flavour, ++ bfd_target_oasys_flavour, ++ bfd_target_tekhex_flavour, ++ bfd_target_srec_flavour, ++ bfd_target_ihex_flavour, ++ bfd_target_som_flavour, ++ bfd_target_os9k_flavour, ++ bfd_target_versados_flavour, ++ bfd_target_msdos_flavour, ++ bfd_target_ovax_flavour, ++ bfd_target_evax_flavour, ++ bfd_target_mmo_flavour, ++ bfd_target_mach_o_flavour, ++ bfd_target_pef_flavour, ++ bfd_target_pef_xlib_flavour, ++ bfd_target_sym_flavour ++}; ++ ++enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; ++ ++/* Forward declaration. */ ++typedef struct bfd_link_info _bfd_link_info; ++ ++typedef struct bfd_target ++{ ++ /* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */ ++ char *name; ++ ++ /* The "flavour" of a back end is a general indication about ++ the contents of a file. */ ++ enum bfd_flavour flavour; ++ ++ /* The order of bytes within the data area of a file. */ ++ enum bfd_endian byteorder; ++ ++ /* The order of bytes within the header parts of a file. */ ++ enum bfd_endian header_byteorder; ++ ++ /* A mask of all the flags which an executable may have set - ++ from the set <>, <>, ...<>. */ ++ flagword object_flags; ++ ++ /* A mask of all the flags which a section may have set - from ++ the set <>, <>, ...<>. */ ++ flagword section_flags; ++ ++ /* The character normally found at the front of a symbol. ++ (if any), perhaps `_'. */ ++ char symbol_leading_char; ++ ++ /* The pad character for file names within an archive header. */ ++ char ar_pad_char; ++ ++ /* The maximum number of characters in an archive header. */ ++ unsigned short ar_max_namelen; ++ ++ /* Entries for byte swapping for data. These are different from the ++ other entry points, since they don't take a BFD as the first argument. ++ Certain other handlers could do the same. */ ++ bfd_uint64_t (*bfd_getx64) (const void *); ++ bfd_int64_t (*bfd_getx_signed_64) (const void *); ++ void (*bfd_putx64) (bfd_uint64_t, void *); ++ bfd_vma (*bfd_getx32) (const void *); ++ bfd_signed_vma (*bfd_getx_signed_32) (const void *); ++ void (*bfd_putx32) (bfd_vma, void *); ++ bfd_vma (*bfd_getx16) (const void *); ++ bfd_signed_vma (*bfd_getx_signed_16) (const void *); ++ void (*bfd_putx16) (bfd_vma, void *); ++ ++ /* Byte swapping for the headers. */ ++ bfd_uint64_t (*bfd_h_getx64) (const void *); ++ bfd_int64_t (*bfd_h_getx_signed_64) (const void *); ++ void (*bfd_h_putx64) (bfd_uint64_t, void *); ++ bfd_vma (*bfd_h_getx32) (const void *); ++ bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); ++ void (*bfd_h_putx32) (bfd_vma, void *); ++ bfd_vma (*bfd_h_getx16) (const void *); ++ bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); ++ void (*bfd_h_putx16) (bfd_vma, void *); ++ ++ /* Format dependent routines: these are vectors of entry points ++ within the target vector structure, one for each format to check. */ ++ ++ /* Check the format of a file being read. Return a <> or zero. */ ++ const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); ++ ++ /* Set the format of a file being written. */ ++ bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); ++ ++ /* Write cached information into a file being written, at <>. */ ++ bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); ++ ++ ++ /* Generic entry points. */ ++#define BFD_JUMP_TABLE_GENERIC(NAME) \ ++ NAME##_close_and_cleanup, \ ++ NAME##_bfd_free_cached_info, \ ++ NAME##_new_section_hook, \ ++ NAME##_get_section_contents, \ ++ NAME##_get_section_contents_in_window ++ ++ /* Called when the BFD is being closed to do any necessary cleanup. */ ++ bfd_boolean (*_close_and_cleanup) (bfd *); ++ /* Ask the BFD to free all cached information. */ ++ bfd_boolean (*_bfd_free_cached_info) (bfd *); ++ /* Called when a new section is created. */ ++ bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); ++ /* Read the contents of a section. */ ++ bfd_boolean (*_bfd_get_section_contents) ++ (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); ++ bfd_boolean (*_bfd_get_section_contents_in_window) ++ (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); ++ ++ /* Entry points to copy private data. */ ++#define BFD_JUMP_TABLE_COPY(NAME) \ ++ NAME##_bfd_copy_private_bfd_data, \ ++ NAME##_bfd_merge_private_bfd_data, \ ++ _bfd_generic_init_private_section_data, \ ++ NAME##_bfd_copy_private_section_data, \ ++ NAME##_bfd_copy_private_symbol_data, \ ++ NAME##_bfd_copy_private_header_data, \ ++ NAME##_bfd_set_private_flags, \ ++ NAME##_bfd_print_private_bfd_data ++ ++ /* Called to copy BFD general private data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_bfd_data) (bfd *, bfd *); ++ /* Called to merge BFD general private data from one object file ++ to a common output file when linking. */ ++ bfd_boolean (*_bfd_merge_private_bfd_data) (bfd *, bfd *); ++ /* Called to initialize BFD private section data from one object file ++ to another. */ ++#define bfd_init_private_section_data(ibfd, isec, obfd, osec, link_info) \ ++ BFD_SEND (obfd, _bfd_init_private_section_data, (ibfd, isec, obfd, osec, link_info)) ++ bfd_boolean (*_bfd_init_private_section_data) ++ (bfd *, sec_ptr, bfd *, sec_ptr, struct bfd_link_info *); ++ /* Called to copy BFD private section data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_section_data) ++ (bfd *, sec_ptr, bfd *, sec_ptr); ++ /* Called to copy BFD private symbol data from one symbol ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_symbol_data) ++ (bfd *, asymbol *, bfd *, asymbol *); ++ /* Called to copy BFD private header data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_header_data) ++ (bfd *, bfd *); ++ /* Called to set private backend flags. */ ++ bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); ++ ++ /* Called to print private BFD data. */ ++ bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); ++ ++ /* Core file entry points. */ ++#define BFD_JUMP_TABLE_CORE(NAME) \ ++ NAME##_core_file_failing_command, \ ++ NAME##_core_file_failing_signal, \ ++ NAME##_core_file_matches_executable_p ++ ++ char * (*_core_file_failing_command) (bfd *); ++ int (*_core_file_failing_signal) (bfd *); ++ bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); ++ ++ /* Archive entry points. */ ++#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ ++ NAME##_slurp_armap, \ ++ NAME##_slurp_extended_name_table, \ ++ NAME##_construct_extended_name_table, \ ++ NAME##_truncate_arname, \ ++ NAME##_write_armap, \ ++ NAME##_read_ar_hdr, \ ++ NAME##_openr_next_archived_file, \ ++ NAME##_get_elt_at_index, \ ++ NAME##_generic_stat_arch_elt, \ ++ NAME##_update_armap_timestamp ++ ++ bfd_boolean (*_bfd_slurp_armap) (bfd *); ++ bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); ++ bfd_boolean (*_bfd_construct_extended_name_table) ++ (bfd *, char **, bfd_size_type *, const char **); ++ void (*_bfd_truncate_arname) (bfd *, const char *, char *); ++ bfd_boolean (*write_armap) ++ (bfd *, unsigned int, struct orl *, unsigned int, int); ++ void * (*_bfd_read_ar_hdr_fn) (bfd *); ++ bfd * (*openr_next_archived_file) (bfd *, bfd *); ++#define bfd_get_elt_at_index(b,i) BFD_SEND (b, _bfd_get_elt_at_index, (b,i)) ++ bfd * (*_bfd_get_elt_at_index) (bfd *, symindex); ++ int (*_bfd_stat_arch_elt) (bfd *, struct stat *); ++ bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); ++ ++ /* Entry points used for symbols. */ ++#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ ++ NAME##_get_symtab_upper_bound, \ ++ NAME##_canonicalize_symtab, \ ++ NAME##_make_empty_symbol, \ ++ NAME##_print_symbol, \ ++ NAME##_get_symbol_info, \ ++ NAME##_bfd_is_local_label_name, \ ++ NAME##_bfd_is_target_special_symbol, \ ++ NAME##_get_lineno, \ ++ NAME##_find_nearest_line, \ ++ _bfd_generic_find_line, \ ++ NAME##_find_inliner_info, \ ++ NAME##_bfd_make_debug_symbol, \ ++ NAME##_read_minisymbols, \ ++ NAME##_minisymbol_to_symbol ++ ++ long (*_bfd_get_symtab_upper_bound) (bfd *); ++ long (*_bfd_canonicalize_symtab) ++ (bfd *, struct bfd_symbol **); ++ struct bfd_symbol * ++ (*_bfd_make_empty_symbol) (bfd *); ++ void (*_bfd_print_symbol) ++ (bfd *, void *, struct bfd_symbol *, bfd_print_symbol_type); ++#define bfd_print_symbol(b,p,s,e) BFD_SEND (b, _bfd_print_symbol, (b,p,s,e)) ++ void (*_bfd_get_symbol_info) ++ (bfd *, struct bfd_symbol *, symbol_info *); ++#define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) ++ bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); ++ bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); ++ alent * (*_get_lineno) (bfd *, struct bfd_symbol *); ++ bfd_boolean (*_bfd_find_nearest_line) ++ (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, ++ const char **, const char **, unsigned int *); ++ bfd_boolean (*_bfd_find_line) ++ (bfd *, struct bfd_symbol **, struct bfd_symbol *, ++ const char **, unsigned int *); ++ bfd_boolean (*_bfd_find_inliner_info) ++ (bfd *, const char **, const char **, unsigned int *); ++ /* Back-door to allow format-aware applications to create debug symbols ++ while using BFD for everything else. Currently used by the assembler ++ when creating COFF files. */ ++ asymbol * (*_bfd_make_debug_symbol) ++ (bfd *, void *, unsigned long size); ++#define bfd_read_minisymbols(b, d, m, s) \ ++ BFD_SEND (b, _read_minisymbols, (b, d, m, s)) ++ long (*_read_minisymbols) ++ (bfd *, bfd_boolean, void **, unsigned int *); ++#define bfd_minisymbol_to_symbol(b, d, m, f) \ ++ BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) ++ asymbol * (*_minisymbol_to_symbol) ++ (bfd *, bfd_boolean, const void *, asymbol *); ++ ++ /* Routines for relocs. */ ++#define BFD_JUMP_TABLE_RELOCS(NAME) \ ++ NAME##_get_reloc_upper_bound, \ ++ NAME##_canonicalize_reloc, \ ++ NAME##_bfd_reloc_type_lookup ++ ++ long (*_get_reloc_upper_bound) (bfd *, sec_ptr); ++ long (*_bfd_canonicalize_reloc) ++ (bfd *, sec_ptr, arelent **, struct bfd_symbol **); ++ /* See documentation on reloc types. */ ++ reloc_howto_type * ++ (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); ++ ++ /* Routines used when writing an object file. */ ++#define BFD_JUMP_TABLE_WRITE(NAME) \ ++ NAME##_set_arch_mach, \ ++ NAME##_set_section_contents ++ ++ bfd_boolean (*_bfd_set_arch_mach) ++ (bfd *, enum bfd_architecture, unsigned long); ++ bfd_boolean (*_bfd_set_section_contents) ++ (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); ++ ++ /* Routines used by the linker. */ ++#define BFD_JUMP_TABLE_LINK(NAME) \ ++ NAME##_sizeof_headers, \ ++ NAME##_bfd_get_relocated_section_contents, \ ++ NAME##_bfd_relax_section, \ ++ NAME##_bfd_link_hash_table_create, \ ++ NAME##_bfd_link_hash_table_free, \ ++ NAME##_bfd_link_add_symbols, \ ++ NAME##_bfd_link_just_syms, \ ++ NAME##_bfd_final_link, \ ++ NAME##_bfd_link_split_section, \ ++ NAME##_bfd_gc_sections, \ ++ NAME##_bfd_merge_sections, \ ++ NAME##_bfd_is_group_section, \ ++ NAME##_bfd_discard_group, \ ++ NAME##_section_already_linked \ ++ ++ int (*_bfd_sizeof_headers) (bfd *, bfd_boolean); ++ bfd_byte * (*_bfd_get_relocated_section_contents) ++ (bfd *, struct bfd_link_info *, struct bfd_link_order *, ++ bfd_byte *, bfd_boolean, struct bfd_symbol **); ++ ++ bfd_boolean (*_bfd_relax_section) ++ (bfd *, struct bfd_section *, struct bfd_link_info *, bfd_boolean *); ++ ++ /* Create a hash table for the linker. Different backends store ++ different information in this table. */ ++ struct bfd_link_hash_table * ++ (*_bfd_link_hash_table_create) (bfd *); ++ ++ /* Release the memory associated with the linker hash table. */ ++ void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); ++ ++ /* Add symbols from this object file into the hash table. */ ++ bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); ++ ++ /* Indicate that we are only retrieving symbol values from this section. */ ++ void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); ++ ++ /* Do a link based on the link_order structures attached to each ++ section of the BFD. */ ++ bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); ++ ++ /* Should this section be split up into smaller pieces during linking. */ ++ bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); ++ ++ /* Remove sections that are not referenced from the output. */ ++ bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); ++ ++ /* Attempt to merge SEC_MERGE sections. */ ++ bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); ++ ++ /* Is this section a member of a group? */ ++ bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); ++ ++ /* Discard members of a group. */ ++ bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); ++ ++ /* Check if SEC has been already linked during a reloceatable or ++ final link. */ ++ void (*_section_already_linked) (bfd *, struct bfd_section *); ++ ++ /* Routines to handle dynamic symbols and relocs. */ ++#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ ++ NAME##_get_dynamic_symtab_upper_bound, \ ++ NAME##_canonicalize_dynamic_symtab, \ ++ NAME##_get_synthetic_symtab, \ ++ NAME##_get_dynamic_reloc_upper_bound, \ ++ NAME##_canonicalize_dynamic_reloc ++ ++ /* Get the amount of memory required to hold the dynamic symbols. */ ++ long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); ++ /* Read in the dynamic symbols. */ ++ long (*_bfd_canonicalize_dynamic_symtab) ++ (bfd *, struct bfd_symbol **); ++ /* Create synthetized symbols. */ ++ long (*_bfd_get_synthetic_symtab) ++ (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, ++ struct bfd_symbol **); ++ /* Get the amount of memory required to hold the dynamic relocs. */ ++ long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); ++ /* Read in the dynamic relocs. */ ++ long (*_bfd_canonicalize_dynamic_reloc) ++ (bfd *, arelent **, struct bfd_symbol **); ++ ++ /* Opposite endian version of this target. */ ++ const struct bfd_target * alternative_target; ++ ++ /* Data for use by back-end routines, which isn't ++ generic enough to belong in this structure. */ ++ const void *backend_data; ++ ++} bfd_target; ++ ++bfd_boolean bfd_set_default_target (const char *name); ++ ++const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); ++ ++const char ** bfd_target_list (void); ++ ++const bfd_target *bfd_search_for_target ++ (int (*search_func) (const bfd_target *, void *), ++ void *); ++ ++/* Extracted from format.c. */ ++bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); ++ ++bfd_boolean bfd_check_format_matches ++ (bfd *abfd, bfd_format format, char ***matching); ++ ++bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); ++ ++const char *bfd_format_string (bfd_format format); ++ ++/* Extracted from linker.c. */ ++bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); ++ ++#define bfd_link_split_section(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) ++ ++void bfd_section_already_linked (bfd *abfd, asection *sec); ++ ++#define bfd_section_already_linked(abfd, sec) \ ++ BFD_SEND (abfd, _section_already_linked, (abfd, sec)) ++ ++/* Extracted from simple.c. */ ++bfd_byte *bfd_simple_get_relocated_section_contents ++ (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif +--- /dev/null ++++ b/arch/ia64/include/asm/kdb.h +@@ -0,0 +1,45 @@ ++#ifndef _ASM_KDB_H ++#define _ASM_KDB_H ++ ++/* ++ * Kernel Debugger Architecture Dependent Global Headers ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * KDB_ENTER() is a macro which causes entry into the kernel ++ * debugger from any point in the kernel code stream. If it ++ * is intended to be used from interrupt level, it must use ++ * a non-maskable entry method. ++ */ ++#include /* break numbers are separated for CONFIG_KDB_LOCK */ ++#define __KDB_ENTER2(b) asm("\tbreak.m "#b"\n") ++#define __KDB_ENTER1(b) __KDB_ENTER2(b) ++#define KDB_ENTER() do {if (kdb_on && !KDB_IS_RUNNING()) { __KDB_ENTER1(KDB_BREAK_ENTER); }} while(0) ++#define KDB_ENTER_SLAVE() do {if (kdb_on) { __KDB_ENTER1(KDB_BREAK_ENTER_SLAVE); }} while(0) ++ ++ /* ++ * Needed for exported symbols. ++ */ ++typedef unsigned long kdb_machreg_t; ++ ++#define kdb_machreg_fmt "0x%lx" ++#define kdb_machreg_fmt0 "0x%016lx" ++#define kdb_bfd_vma_fmt "0x%lx" ++#define kdb_bfd_vma_fmt0 "0x%016lx" ++#define kdb_elfw_addr_fmt "0x%lx" ++#define kdb_elfw_addr_fmt0 "0x%016lx" ++ ++static inline unsigned long ++kdba_funcptr_value(void *fp) ++{ ++ /* ia64 function descriptor, first word is address of code */ ++ return *(unsigned long *)fp; ++} ++ ++#endif /* !_ASM_KDB_H */ +--- /dev/null ++++ b/arch/ia64/include/asm/kdb_break.h +@@ -0,0 +1,24 @@ ++#ifndef _ASM_KDB_BREAK_H ++#define _ASM_KDB_BREAK_H ++ ++/* ++ * Kernel Debugger Architecture Dependent Global Headers ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * Break numbers are used by CONFIG_KDB_LOCK code. They need to be seperated ++ * from asm/kdb.h to let spinlock code build without pulling in all of the kdb ++ * headers. ++ */ ++ ++#define KDB_BREAK_BREAK 0x80100 /* kdb breakpoint in kernel */ ++#define KDB_BREAK_ENTER 0x80101 /* KDB_ENTER(), single event or monarch */ ++#define KDB_BREAK_ENTER_SLAVE 0x80102 /* KDB_ENTER_SLAVE(), concurrent slave events */ ++ ++#endif /* !_ASM_KDB_BREAK_H */ +--- /dev/null ++++ b/arch/ia64/include/asm/kdbprivate.h +@@ -0,0 +1,124 @@ ++#ifndef _ASM_KDBPRIVATE_H ++#define _ASM_KDBPRIVATE_H ++ ++/* ++ * Kernel Debugger Architecture Dependent Private Headers ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++/* Definition of an machine instruction. ++ * Takes care of VLIW processors like Itanium ++ */ ++ ++typedef struct { ++ unsigned long inst[2]; ++} kdb_machinst_t; ++ ++/* ++ * KDB_MAXBPT describes the total number of breakpoints ++ * supported by this architecure. ++ */ ++#define KDB_MAXBPT 16 ++ ++/* ++ * KDB_MAXHARDBPT describes the total number of hardware ++ * breakpoint registers that exist. ++ */ ++#define KDB_MAXHARDBPT 4 ++ ++/* ++ * Platform specific environment entries ++ */ ++#define KDB_PLATFORM_ENV "IDMODE=ia64", "BYTESPERWORD=4", "IDCOUNT=8" ++ ++/* ++ * Support for IA64 debug registers ++ */ ++typedef struct _kdbhard_bp { ++ kdb_machreg_t bph_reg; /* Register this breakpoint uses */ ++ ++ unsigned int bph_free:1; /* Register available for use */ ++ unsigned int bph_data:1; /* Data Access breakpoint */ ++ ++ unsigned int bph_write:1; /* Write Data breakpoint */ ++ unsigned int bph_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ ++ unsigned int bph_length:2; /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */ ++} kdbhard_bp_t; ++ ++#define getprsregs(regs) ((struct switch_stack *)regs -1) ++ ++/* bkpt support using break inst instead of IBP reg */ ++ ++/* ++ * Define certain specific instructions ++ */ ++#define BREAK_INSTR (long)(KDB_BREAK_BREAK << (5+6)) ++#define INST_SLOT0_MASK (0x1ffffffffffL << 5) ++ ++#define BKPTMODE_DATAR 3 ++#define BKPTMODE_IO 2 ++#define BKPTMODE_DATAW 1 ++#define BKPTMODE_INST 0 ++ ++/* Some of the fault registers needed by kdb but not passed with ++ * regs or switch stack. ++ */ ++typedef struct fault_regs { ++ unsigned long isr ; ++ unsigned long ifa ; ++ unsigned long iim ; ++ unsigned long itir ; ++} fault_regs_t ; ++ ++/* ++ * Support for setjmp/longjmp ++ */ ++ ++/* __jmp_buf definition copied from libc/sysdeps/unix/sysv/linux/ia64/bits/setjmp.h */ ++ ++#define _JBLEN 70 ++ ++typedef struct __kdb_jmp_buf { ++ unsigned long __jmp_buf[_JBLEN]; ++} kdb_jmp_buf __attribute__ ((aligned (16))); ++ ++extern int kdba_setjmp(kdb_jmp_buf *); ++extern void kdba_longjmp(kdb_jmp_buf *, int); ++#define kdba_setjmp kdba_setjmp ++ ++extern kdb_jmp_buf *kdbjmpbuf; ++ ++/* Arch specific data saved for running processes */ ++ ++struct kdba_running_process { ++ struct switch_stack *sw; ++}; ++ ++extern void kdba_save_running(struct kdba_running_process *, struct pt_regs *); ++extern void kdba_unsave_running(struct kdba_running_process *, struct pt_regs *); ++ ++/* kdba wrappers which want to save switch stack will call unw_init_running(). ++ * That routine only takes a void* so pack the interrupt data into a structure. ++ */ ++ ++#include /* for irqreturn_t */ ++ ++enum kdba_serial_console { ++ KDBA_SC_NONE = 0, ++ KDBA_SC_STANDARD, ++ KDBA_SC_SGI_L1, ++}; ++ ++extern enum kdba_serial_console kdba_serial_console; ++ ++#define KDB_RUNNING_PROCESS_ORIGINAL kdb_running_process_save ++extern struct kdb_running_process *kdb_running_process_save; /* [NR_CPUS] */ ++ ++extern void kdba_wait_for_cpus(void); ++ ++#endif /* !_ASM_KDBPRIVATE_H */ +--- a/arch/ia64/include/asm/kmap_types.h ++++ b/arch/ia64/include/asm/kmap_types.h +@@ -22,7 +22,8 @@ D(9) KM_IRQ0, + D(10) KM_IRQ1, + D(11) KM_SOFTIRQ0, + D(12) KM_SOFTIRQ1, +-D(13) KM_TYPE_NR ++D(13) KM_KDB, ++D(14) KM_TYPE_NR + }; + + #undef D +--- a/arch/ia64/include/asm/kregs.h ++++ b/arch/ia64/include/asm/kregs.h +@@ -72,7 +72,7 @@ + /* A mask of PSR bits that we generally don't want to inherit across a clone2() or an + execve(). Only list flags here that need to be cleared/set for BOTH clone2() and + execve(). */ +-#define IA64_PSR_BITS_TO_CLEAR (IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_DB | IA64_PSR_LP | \ ++#define IA64_PSR_BITS_TO_CLEAR (IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_LP | \ + IA64_PSR_TB | IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ + IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA) + #define IA64_PSR_BITS_TO_SET (IA64_PSR_DFH | IA64_PSR_SP) +--- /dev/null ++++ b/arch/ia64/kdb/ChangeLog +@@ -0,0 +1,1085 @@ ++2008-09-30 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc8-ia64-1. ++ ++2008-09-22 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc7-ia64-1. ++ ++2008-09-03 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc5-ia64-1. ++ ++2008-08-19 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc3-ia64-1. ++ ++2008-08-15 Jay Lan ++ ++ * Fix a problem that slave cpus panic'ed during NMI. ++ Jay Lan ++ * kdb-v4.4-2.6.27-rc2-ia64-2.1. ++ ++2008-08-14 Jay Lan ++ ++ * Support 'kdump' command to take a kdump vmcore from KDB, ++ Dan Aloni (da-x@monatomic.org), ++ Jason Xiao (jidong.xiao@gmail.com), ++ Jay Lan (jlan@sgi.com) ++ * kdb-v4.4-2.6.27-rc2-ia64-2. ++ ++2008-08-06 Jay Lan ++ ++ * Fix up the NULL pointer deference issue in ohci_kdb_poll_char, ++ Jason Xiao ++ * kdb-v4.4-2.6.27-rc2-ia64-1. ++ ++2008-07-18 Jay Lan ++ ++ * support Hardware Breakpoint (bph/bpha) commands ++ IA64: Greg Banks ++ X86: Konstantin Baydarov ++ * kdb-v4.4-2.6.26-ia64-2. ++ ++2008-07-14 Jay Lan ++ ++ * kdb-v4.4-2.6.26-ia64-1. ++ ++2008-07-11 Jay Lan ++ ++ * New commands and some fixups and enhancements, ++ Joe Korty ++ John Blackwood ++ Jim Houston ++ - Use the non-sleeping copy_from_user_atomic. ++ - Enhance kdb_cmderror diagnostic output. ++ - Expand the KDB 'duplicate command' error message. ++ - Touch NMI watchdog in various KDB busy-loops. ++ - Support IMB HS20 Blade 8843 platform. ++ - Display exactly which cpus needed an NMI to get them into kdb. ++ - Better document that kdb's 'ps A' command can be used to show ++ _all_ processes and threads ++ - Suppress KDB boottime INFO messages if quiet boot. ++ - Add a KDB breakpoint to the OOPs path. ++ - Add CONFIG_DISCONTIGMEM support to kdbm_memmap. ++ - Extend the KDB task command to handle CONFIG_NUMA fields. ++ - Extend the KDB vm command to support NUMA stuff. ++ - Create the KDB mempolicy command. ++ - Create a pgdat command for KDB. ++ - Fix a hang on boot on some i386 systems. ++ * kdb-v4.4-2.6.26-rc9-ia64-1. ++ ++2008-06-30 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc8-ia64-1. ++ ++2008-06-25 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc7-ia64-1. ++ ++2008-06-06 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc5-ia64-1. ++ ++2008-05-30 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc4-ia64-1. ++ ++2008-05-20 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc3-ia64-1. ++ ++2008-05-13 Jay Lan ++ ++ * XPC support removed from KDB due to XPC changes to 2.6.26-rc1. ++ * kdb-v4.4-2.6.26-rc1-ia64-1. ++ ++2008-04-17 Jay Lan ++ ++ * kdb-v4.4-2.6.25-ia64-1. ++ ++2008-03-16 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc6-ia64-1. ++ ++2008-03-03 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc3-ia64-1. ++ ++2008-02-26 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc2-ia64-1. ++ ++2008-02-19 Jay Lan ++ ++ * kdb-v4.4-2.6.25-rc1-ia64-1. ++ ++2008-02-01 Jay Lan ++ ++ * Backed out USB UHCI support since it caused dropped characters and ++ broke OHCI. ++ * Restored "archkdbcommon" commands for x86. It was lost at the x86 ++ merge. ++ * Detecting if the HC was "busy", Aaron Young ++ * kdb-v4.4-2.6.24-ia64-2. ++ ++2008-01-29 Jay Lan ++ ++ * kdb-v4.4-2.6.24-ia64-1. ++ ++2008-01-22 Jay Lan ++ ++ * USB UHCI kdb support, Konstantin Baydarov ++ * kdb-v4.4-2.6.24-rc8-ia64-3. ++ ++2008-01-18 Jay Lan ++ ++ * USB EHCI kdb support, Aaron Young ++ * kdb-v4.4-2.6.24-rc8-ia64-2. ++ ++2008-01-18 Jay Lan ++ ++ * kdb-v4.4-2.6.24-rc8-ia64-1. ++ ++2008-01-07 Jay Lan ++ ++ * kdb-v4.4-2.6.24-rc7-ia64-1. ++ ++2007-12-21 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc6-ia64-1. ++ ++2007-12-12 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc5-ia64-1. ++ ++2007-12-05 Jay Lan ++ ++ * Fixed a 'sysctl table check failed' problem. ++ * kdb v4.4-2.6.24-rc4-ia64-1. ++ ++2007-11-26 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc3-ia64-1. ++ ++2007-11-13 Jay Lan ++ ++ * Back ported "New KDB USB interface" from Aaron Young in ++ v4.4-2.6.23-ia64-2 to 2.6.24 kdb patchset. ++ * kdb v4.4-2.6.24-rc2-ia64-2. ++ ++2007-11-12 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc2-ia64-1. ++ ++2007-11-09 Jay Lan ++ ++ * Rebase to 2.6.24-rc1 kernel ++ * - merged kdb-v4.4-2.6.23-i386-1 and kdb-v4.4-2.6.23-x86_64-1 ++ * into kdb-v4.4-2.6.24-rc1-x86-1 ++ * - Fields "done", "sglist_len", and "pid" are removed from ++ * struct scsi_cmnd. Thus, these fields are no longer displayed ++ * on "sc" command. ++ * kdb v4.4-2.6.24-rc1-ia64-1. ++ ++2007-11-08 Jay Lan ++ ++ * New KDB USB interface, Aaron Young ++ * 1. This patch allows KDB to work with any Host Contoller driver ++ * and call the correct HC driver poll routine (as long as the ++ * HC driver provides a .kdb_poll_char routine via it's ++ * associated hc_driver struct). ++ * 2. Hotplugged keyboards are now recognized by KDB. ++ * 3. Currently KDB can only make use of 1 USB type keyboard. ++ * New code can handle up to 8 attached keyboards - input is ++ * multiplexed from all of them while in kdb. ++ * kdb v4.4-2.6.23-ia64-2. ++ ++2007-10-24 Jay Lan ++ ++ * kdb v4.4-2.6.23-ia64-1. ++ ++2007-09-26 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc8-ia64-1. ++ ++2007-09-21 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc7-ia64-1. ++ ++2007-09-19 Jay Lan ++ ++ * Get into KDB successfully if multiple cpus are in MCA. ++ * kdb v4.4-2.6.23-rc6-ia64-2. ++ ++2007-09-12 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc6-ia64-1. ++ ++2007-09-06 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc5-ia64-1. ++ ++2007-08-30 Keith Owens ++ ++ * New i386/x86_64 backtrace requires that kdb_save_running() does not ++ exit until after kdb_main_loop() has completed. ++ * kdb v4.4-2.6.23-rc4-ia64-2. ++ ++2007-08-30 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc4-ia64-1. ++ ++2007-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc3-ia64-1. ++ ++2007-08-07 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc2-ia64-1. ++ ++2007-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc1-ia64-1. ++ ++2007-07-09 Keith Owens ++ ++ * kdb v4.4-2.6.22-ia64-1. ++ ++2007-07-02 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc7-ia64-1. ++ ++2007-06-20 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc5-ia64-1. ++ ++2007-06-08 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc4-ia64-1. ++ ++2007-05-28 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc3-ia64-1. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc2-ia64-1. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc1-ia64-1. ++ ++2007-04-29 Keith Owens ++ ++ * kdb v4.4-2.6.21-ia64-1. ++ ++2007-04-16 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc7-ia64-1. ++ ++2007-04-10 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc6-ia64-1. ++ ++2007-04-02 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc5-ia64-1. ++ ++2007-03-19 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc4-ia64-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc3-ia64-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc2-ia64-1. ++ ++2007-03-01 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc1-ia64-1. ++ ++2007-03-01 Keith Owens ++ ++ * Remove sparse warnings. ++ * kdb v4.4-2.6.20-ia64-3. ++ ++2007-02-16 Keith Owens ++ ++ * Initialise variable bits of struct disassemble_info each time. ++ * kdb v4.4-2.6.20-ia64-2. ++ ++2007-02-06 Keith Owens ++ ++ * kdb v4.4-2.6.20-ia64-1. ++ ++2007-02-01 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc7-ia64-1. ++ ++2007-01-08 Keith Owens ++ ++ * Detect calls via PLT and decode the target address. ++ * kdb v4.4-2.6.20-rc4-ia64-2. ++ ++2007-01-08 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc4-ia64-1. ++ ++2007-01-02 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc3-ia64-1. ++ ++2006-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc1-ia64-1. ++ ++2006-12-07 Keith Owens ++ ++ * Export kdba_dumpregs. ++ * kdb v4.4-2.6.19-ia64-2. ++ ++2006-11-30 Keith Owens ++ ++ * kdb v4.4-2.6.19-ia64-1. ++ ++2006-11-27 Keith Owens ++ ++ * Only use VT keyboard if the command line allows it and ACPI indicates ++ that there is an i8042. ++ * kdb v4.4-2.6.19-rc6-ia64-2. ++ ++2006-11-20 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc6-ia64-1. ++ ++2006-11-09 Keith Owens ++ ++ * Only use VT console if the command line allows it. ++ * kdb v4.4-2.6.19-rc5-ia64-2. ++ ++2006-11-08 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc5-ia64-1. ++ ++2006-11-01 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc4-ia64-1. ++ ++2006-10-24 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc3-ia64-1. ++ ++2006-10-24 Keith Owens ++ ++ * Remove redundant regs and envp parameters. ++ * kdb v4.4-2.6.19-rc2-ia64-2. ++ ++2006-10-18 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc2-ia64-1. ++ ++2006-10-09 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc1-ia64-1. ++ ++2006-10-06 Keith Owens ++ ++ * Remove #include ++ * kdb v4.4-2.6.18-ia64-2. ++ ++2006-09-20 Keith Owens ++ ++ * kdb v4.4-2.6.18-ia64-1. ++ ++2006-09-15 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc7-ia64-1. ++ ++2006-08-29 Keith Owens ++ ++ * Rewrite all backtrace code. ++ * kdb v4.4-2.6.18-rc5-ia64-2. ++ ++2006-08-28 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc5-ia64-1. ++ ++2006-08-08 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc4-ia64-1. ++ ++2006-08-04 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc3-ia64-1. ++ ++2006-07-18 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc2-ia64-1. ++ ++2006-07-12 Keith Owens ++ ++ * Remove dead KDB_REASON codes. ++ * sparse cleanups. ++ * kdb v4.4-2.6.18-rc1-ia64-2. ++ ++2006-07-07 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc1-ia64-1. ++ ++2006-07-04 Keith Owens ++ ++ * Delete kdba_enable_lbr, kdba_disable_lbr, kdba_print_lbr, ++ page_fault_mca. Only ever implemented on x86, difficult to maintain ++ and rarely used in the field. ++ * Replace #ifdef KDB_HAVE_LONGJMP with #ifdef kdba_setjmp. ++ * kdb v4.4-2.6.17-ia64-2. ++ ++2006-06-19 Keith Owens ++ ++ * kdb v4.4-2.6.17-ia64-1. ++ ++2006-05-25 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc5-ia64-1. ++ ++2006-05-15 Keith Owens ++ ++ * Refresh bfd related files from binutils 2.16.91.0.2. ++ * kdb v4.4-2.6.17-rc4-ia64-2. ++ ++2006-05-12 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc4-ia64-1. ++ ++2006-04-28 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc3-ia64-1. ++ ++2006-04-22 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc2-ia64-1. ++ ++2006-04-11 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc1-ia64-1. ++ ++2006-03-30 Keith Owens ++ ++ * Change CONFIG_LKCD to CONFIG_LKCD_DUMP. ++ * kdb v4.4-2.6.16-ia64-3. ++ ++2006-03-24 Keith Owens ++ ++ * Use INIT to interrupt cpus that do not respond to a normal kdb IPI. ++ * Remove KDBA_MCA_TRACE from arch/ia64/kernel/mca.c. ++ * kdb v4.4-2.6.16-ia64-2. ++ ++2006-03-21 Keith Owens ++ ++ * kdb v4.4-2.6.16-ia64-1. ++ ++2006-03-14 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc6-ia64-1. ++ ++2006-02-28 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc5-ia64-1. ++ ++2006-02-20 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc4-ia64-1. ++ ++2006-02-07 Keith Owens ++ ++ * Change kdb_running_process_save from a static array to a pointer. ++ gcc 4.0 objects to forward declarations for arrays with an incomplete ++ type. ++ * kdb v4.4-2.6.16-rc2-ia64-3. ++ ++2006-02-06 Keith Owens ++ ++ * Change CONFIG_CRASH_DUMP to CONFIG_LKCD. ++ * kdb v4.4-2.6.16-rc2-ia64-2. ++ ++2006-02-06 Keith Owens ++ ++ * kdb v4.4-2.6.16-rc2-ia64-1. ++ ++2006-02-01 Keith Owens ++ ++ * Handlers: check that the task is in kernel space before looking at ++ the thread_info bits. ++ * Expose kdb_running_process_save[] so 'pid R' can get the original ++ process, even when the MCA/INIT handlers are being used. ++ * kdb v4.4-2.6.16-rc1-ia64-3. ++ ++2006-01-19 Keith Owens ++ ++ * Add back some kdb changes to xpc_main that were lost due to a patch ++ conflict. ++ * kdb v4.4-2.6.16-rc1-ia64-2. ++ ++2006-01-18 Keith Owens ++ ++ * kdb v4.4-2.6.16-rc1-ia64-1. ++ ++2006-01-10 Keith Owens ++ ++ * Build kdba_pod for generic as well as sn2 kernels and test at run ++ time if the platform is sn2. ++ * kdb v4.4-2.6.15-ia64-3. ++ ++2006-01-08 Keith Owens ++ ++ * Convert xpc to use DIE_KDEBUG_ENTER and DIE_KDEBUG_LEAVE. ++ * Add debug option for xpc. ++ * break.b always sets a debug trap number of 0 , so pass that to kdb as ++ well as the normal kdb traaps. ++ * kdb v4.4-2.6.15-ia64-2. ++ ++2006-01-04 Keith Owens ++ ++ * Remove some inlines and the last vestige of CONFIG_NUMA_REPLICATE. ++ * Read the keyboard acknowledgment after sending a character. SuSE ++ Bugzilla 60240. ++ * kdb v4.4-2.6.15-ia64-1. ++ ++2005-12-25 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc7-ia64-1. ++ ++2005-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc6-ia64-1. ++ ++2005-12-06 Keith Owens ++ ++ * Use RECOVERY flag in MCA handler. ++ * kdb v4.4-2.6.15-rc5-ia64-2. ++ ++2005-12-05 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc5-ia64-1. ++ ++2005-12-02 Keith Owens ++ ++ * Reinstate hook for debug trap, the patch chunk was accidentally ++ dropped in 2.6.15-rc1. ++ * kdb v4.4-2.6.15-rc4-ia64-1. ++ ++2005-11-30 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc3-ia64-1. ++ ++2005-11-21 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc2-ia64-1. ++ ++2005-11-15 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc1-ia64-1. ++ ++2005-10-28 Keith Owens ++ ++ * kdb v4.4-2.6.14-ia64-1. ++ ++2005-10-21 Keith Owens ++ ++ * kdb v4.4-2.6.14-rc5-ia64-1. ++ ++2005-10-11 Keith Owens ++ ++ * Handle removal of USB keyboard. Aaron Young, SGI ++ * kdb v4.4-2.6.14-rc4-ia64-1. ++ ++2005-10-04 Keith Owens ++ ++ * kdb v4.4-2.6.14-rc3-ia64-1. ++ ++2005-09-21 Keith Owens ++ ++ * Support kdb_current_task in register display and modify commands. ++ * kdb v4.4-2.6.14-rc2-ia64-1. ++ ++2005-09-20 Keith Owens ++ ++ * Coexist with kprobes. ++ * Coexist with MCA/INIT rewrite. ++ * Add KDB_ENTER_SLAVE to handle concurrent entry to kdb from multiple ++ cpus. ++ * Add handlers command to control whether the MCA/INIT task or the ++ original task is displayed. ++ * Namespace clean up, remove unused kdba_sw_interrupt. ++ * kdb v4.4-2.6.14-rc1-ia64-1. ++ ++2005-08-29 Keith Owens ++ ++ * kdb v4.4-2.6.13-ia64-1. ++ ++2005-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc7-ia64-1. ++ ++2005-08-08 Keith Owens ++ ++ * Add minstate command. ++ * kdb v4.4-2.6.13-rc6-ia64-1. ++ ++2005-08-02 Keith Owens ++ ++ * Replace hard coded kdb declarations with #include . ++ * kdb v4.4-2.6.13-rc5-ia64-1. ++ ++2005-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc4-ia64-1. ++ ++2005-07-22 Keith Owens ++ ++ * Handle INIT delivered while in physical mode. ++ * kdb v4.4-2.6.13-rc3-ia64-2. ++ ++2005-07-19 Keith Owens ++ ++ * Add support for USB keyboard (OHCI only). Aaron Young, SGI. ++ * kdb v4.4-2.6.13-rc3-ia64-1. ++ ++2005-07-08 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc2-ia64-1. ++ ++2005-07-01 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc1-ia64-1. ++ ++2005-06-18 Keith Owens ++ ++ * Standard IA64 code now works around break.b setting cr.iim to 0 ++ instead of the break number. Remove the kdb workaround. ++ * kdb v4.4-2.6.12-ia64-1. ++ ++2005-06-08 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc6-ia64-1. ++ ++2005-05-25 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc5-ia64-1. ++ ++2005-05-24 Keith Owens ++ ++ * break.b sets cr.iim to 0 instead of the break number. Deal with it. ++ * kdb v4.4-2.6.12-rc4-ia64-3. ++ ++2005-05-14 Keith Owens ++ ++ * Correct MCA path after calling kdba_mca_bspstore_fixup(). ++ Mark Larson, SGI. ++ * Tell the user that MCA/INIT is recoverable so kdb is not entered. ++ * kdb v4.4-2.6.12-rc4-ia64-2. ++ ++2005-05-08 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc4-ia64-1. ++ ++2005-04-21 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc3-ia64-1. ++ ++2005-04-06 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc2-ia64-1. ++ ++2005-04-04 Keith Owens ++ ++ * More tweaks to cope with invalid old bspstore in MCA handler. ++ * kdb v4.4-2.6.12-rc1-ia64-2. ++ ++2005-03-29 Keith Owens ++ ++ * Replace __copy_to_user with __copy_to_user_inatomic. ++ * MCA handler, do not use old_bspstore if it is in region 4 or below. ++ * kdb v4.4-2.6.12-rc1-ia64-1. ++ ++2005-03-08 Keith Owens ++ ++ * Coexistence patches for lkcd. Jason Uhlenkott, SGI. ++ * kdb v4.4-2.6.11-ia64-2. ++ ++2005-03-03 Keith Owens ++ ++ * kdb-v4.4-2.6.11-ia64-1. ++ ++2005-02-14 Keith Owens ++ ++ * kdb-v4.4-2.6.11-rc4-ia64-1. ++ ++2005-02-08 Keith Owens ++ ++ * kdb-v4.4-2.6.11-rc3-bk4-ia64-1. ++ ++2005-02-03 Keith Owens ++ ++ * kdb-v4.4-2.6.11-rc3-ia64-1. ++ ++2005-01-27 Keith Owens ++ ++ * kdb-v4.4-2.6.11-rc2-ia64-1. ++ ++2005-01-20 Keith Owens ++ ++ * MCA and INIT stacks moved to per-cpu area. ++ * kdb-v4.4-2.6.11-rc1-bk7-ia64-1. ++ ++2005-01-12 Keith Owens ++ ++ * ia64_spinlock_contention_pre3_4_end is in base kernel, remove from kdb. ++ * Use last ditch allocator if unwind cannot allocate memory. ++ * kdb-v4.4-2.6.11-rc1-ia64-1. ++ ++2004-12-25 Keith Owens ++ ++ * Add cpuinfo command. ++ * kdb-v4.4-2.6.10-ia64-1. ++ ++2004-12-07 Keith Owens ++ ++ * Clean up error path in kdba_mca_init. ++ * kdb-v4.4-2.6.10-rc3-ia64-1. ++ ++2004-11-15 Keith Owens ++ ++ * kdb-v4.4-2.6.10-rc2-ia64-1. ++ ++2004-10-29 Keith Owens ++ ++ * kdb-v4.4-2.6.10-rc1-ia64-1. ++ ++2004-10-19 Keith Owens ++ ++ * kdb-v4.4-2.6.9-ia64-1. ++ ++2004-10-12 Keith Owens ++ ++ * kdb-v4.4-2.6.9-rc4-ia64-1. ++ ++2004-10-01 Keith Owens ++ ++ * kdb-v4.4-2.6.9-rc3-ia64-1. ++ ++2004-09-30 Keith Owens ++ ++ * Add stackdepth command. ++ * kdb-v4.4-2.6.9-rc2-ia64-3. ++ ++2004-09-16 Keith Owens ++ ++ * Fixes for current in region 5 instead of 7 (idle task on cpu 0). ++ * kdb-v4.4-2.6.9-rc2-ia64-2. ++ ++2004-09-14 Keith Owens ++ ++ * kdb-v4.4-2.6.9-rc2-ia64-1. ++ ++2004-08-27 Keith Owens ++ ++ * kdb-v4.4-2.6.9-rc1-ia64-1. ++ ++2004-08-14 Keith Owens ++ ++ * kdb-v4.4-2.6.8-ia64-1. ++ ++2004-08-12 Keith Owens ++ ++ * kdb-v4.4-2.6.8-rc4-ia64-1. ++ ++2004-08-04 Keith Owens ++ ++ * kdb-v4.4-2.6.8-rc3-ia64-1. ++ ++2004-07-18 Keith Owens ++ ++ * New config name for SN serial console. ++ * kdb-v4.4-2.6.8-rc2-ia64-1. ++ ++2004-07-12 Keith Owens ++ ++ * kdb-v4.4-2.6.8-rc1-ia64-1. ++ ++2004-06-30 Keith Owens ++ ++ * kdb-v4.4-2.6.7-ia64-040629-1. ++ ++2004-06-16 Keith Owens ++ ++ * Coexist with 2.6.7-ia64-040619. ++ * kdb-v4.4-2.6.7-ia64-040619-1. ++ ++2004-06-16 Keith Owens ++ ++ * kdb v4.4-2.6.7-ia64-1. ++ ++2004-06-10 Keith Owens ++ ++ * kdb v4.4-2.6.7-rc3-ia64-1. ++ ++2004-06-09 Keith Owens ++ ++ * Namespace clean up. Mark code/variables as static when it is only ++ used in one file, delete dead code/variables. ++ * Saved interrupt state requires long, not int. ++ * kdb v4.4-2.6.7-rc2-ia64-3. ++ ++2004-06-08 Keith Owens ++ ++ * Whitespace clean up, no code changes. ++ * kdb v4.4-2.6.7-rc2-2. ++ ++2004-06-07 Keith Owens ++ ++ * Force KALLSYMS and KALLSYMS_ALL for CONFIG_KDB. ++ * kdb v4.4-2.6.7-rc2-1. ++ ++2004-06-06 Keith Owens ++ ++ * Add standard archkdb commands. ++ * Move kdb_{get,put}userarea_size definitions to linux/kdb.h. ++ * kdb v4.4-2.6.6-ia64-040521-2. ++ ++2004-05-25 Keith Owens ++ ++ * Update Kconfig text. ++ * kdb v4.4-2.6.6-ia64-040521-1. ++ ++2004-05-23 Keith Owens ++ ++ * Move bfd.h and ansidecl.h from arch/$(ARCH)/kdb to include/asm-$(ARCH). ++ * ia64-opc.c needs kdbprivate.h after common reorganisation. ++ * Update copyright notices. ++ * kdb v4.4-2.6.6-ia64-1. ++ ++2004-05-60 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc3-ia64-1. ++ ++2004-05-60 Keith Owens ++ ++ * Tweak WAR for backtrace through contended spinlocks. ++ * kdb v4.3-2.6.6-rc2-ia64-1. ++ ++2004-04-30 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc1-ia64-1. ++ ++2004-04-15 Keith Owens ++ ++ * kdb v4.3-2.6.5-ia64-040413-1. ++ ++2004-03-06 Keith Owens ++ ++ * Use kdb_print for unwind debugging. ++ * kdb v4.3-2.6.4-rc2-ia64-1. ++ ++2004-02-29 Keith Owens ++ ++ * kdb v4.3-2.6.4-rc1-ia64-1. ++ ++2004-02-18 Keith Owens ++ ++ * kdb v4.3-2.6.3-ia64-1. ++ ++2004-02-17 Keith Owens ++ ++ * Reconcile 2.6-test versions from Xavier Bru (Bull), Greg Banks (SGI), ++ Jim Houston (Concurrent Computer Corp). ++ * Reconcile with kdb v4.3-2.4.23-ia64-0312??-1. ++ * Reconcile with salinfo changes. ++ * Port WAR for backtrace from spinlock contention from 2.4 to 2.6. ++ * Merge PGS FIFO tweak with SERIAL_IO_MEM and concurrent support for ++ multiple consoles (no USB consoles yet). ++ * Update pt_regs output to match the order of struct pt_regs. ++ * KDB wrappers for interrupts handlers now return the handler's return code. ++ * tpa and tpav commands from Anonymous. ++ * Reconcile with mca changes. ++ * Upgrade to 2.6.3-rc3. ++ * kdb v4.3-2.6.3-rc3-ia64-1. ++ ++2003-10-22 Xavier Bru ++ * Merge to 2.6.0-test7 ++2003-10-20 Philippe Garrigues ++ * Enable FIFO in UART ++2003-09-08 Xavier Bru ++ * Merge to 2.6.0-test4 ++2003-03-21 Xavier Bru ++ * Merge kdb v4.0 on 2.5.64 ia64 ++ * new kernel parameters support ++ * new kallsyms support ++ ++2003-10-24 Keith Owens ++ ++ * kdb v4.3-2.4.23-pre8-cset-1.1069.1.143-to-1.1108-ia64-1. ++ ++2003-10-03 Keith Owens ++ ++ * After MCA, copy the saved RSE registers from ia64_mca_bspstore to the ++ stack of the failing process. ++ * Abort backtrace when we hit IVT, no unwind data which confuses ++ unw_unwind(). ++ * Workaround for backtrace through spinlock contention called from leaf ++ functions. ++ * kdb v4.3-2.4.22-ia64-030909-1. ++ ++2003-07-20 Keith Owens ++ ++ * MCA rendezvous timeout affects kdb_wait_for_cpus_secs. ++ * Support SGI L1 console. ++ * kdb v4.3-2.4.21-ia64-030702-2. ++ ++2003-07-08 Keith Owens ++ ++ * print_symbol() in mca.c does something useful when kdb is installed. ++ * Unwind and SAL changes removed from kdb, they are in the base kernel. ++ * kdb v4.3-2.4.21-ia64-030702-1. ++ ++2003-06-20 Keith Owens ++ ++ * Add CONFIG_KDB_CONTINUE_CATASTROPHIC. ++ * Do not send IPI if the machine state does not require them. ++ * Correct definition of KDB_ENTER(). ++ * Workaround for broken init monarch handler. ++ * Monarch cpu must get to kdb, even if it was interrupted in user space. ++ * Unwind fixes. ++ * Generalize ia64_spinlock_contention name. ++ * Add kdba_fru for SN machines. ++ * Correct test for cpu number. ++ * kdb v4.3-2.4.20-ia64-020821-1. ++ ++2003-05-02 Keith Owens ++ ++ * Add kdba_fp_value(). ++ * Limit backtrace size to catch loops. ++ * Print spinlock name in ia64_spinlock_contention. ++ * Tweak INIT slave stack lock and handler. ++ * Add read/write access to user pages. Vamsi Krishna S., IBM ++ * Rename cpu_is_online to cpu_online, as in 2.5. ++ * Clean up USB keyboard support. ++ * Clean up serial console support. ++ * kdb v4.2-2.4.20-ia64-020821-1. ++ ++2003-04-04 Keith Owens ++ ++ * Add support for INIT slave interrupts. ++ * Tell SAL to always rendezvous on MCA. ++ * No lock on SAL rendezvous call. ++ * Include unwind.c from 2.4.21-pre5. ++ * Rename cpu_online to cpu_is_online. ++ * Workarounds for scheduler bugs. ++ * kdb v4.1-2.4.20-ia64-020821-1. ++ ++2003-03-16 Keith Owens ++ ++ * Each cpu saves its state as it enters kdb or before it enters code ++ which cannot call kdb, converting kdb from a pull to a push model. ++ * Clean up kdb interaction with CONFIG_SERIAL_CONSOLE. ++ * Removal of special cases for i386 backtrace from common code ++ simplifies the architecture code. ++ * Add support for MCA events (both main and rendezvous) plus INIT ++ monarch event. ++ * Correct decode of brl. ++ * Move kdba_print_nameval to common code. ++ * Generalize kdba unwind handlers. ++ * Fix decode of sal records (fix included in later ia64 kernels). ++ * Handle multiple pt_regs in stack (fix included in later ia64 kernels). ++ * Clean up debug code in unwind (fix included in later ia64 kernels). ++ * Move kdb break numbers to their own file so it can be used in asm. ++ * kdb v4.0-2.4.20-ia64-021210-1. ++ ++2003-02-03 Keith Owens ++ ++ * Register kdb commands early. ++ * Handle KDB_ENTER() when kdb=off. ++ * Optimize __kdba_getarea_size when width is a constant. ++ * Decode oops via kallsyms if it is available. ++ * Update copyright notices to 2003. ++ * Add commands to dump struct pt_regs and switch_stack. ++ * Handle padding from unw_init_running for switch_stack. ++ * Add dummy kdba_local_arch_setup/kdba_local_arch_cleanup. ++ * Warning for pod mode. ++ * Add command history and editing. Sonic Zhang. ++ * kdb_toggleled is conditional on KDB_BLINK_LED. Bernhard Fischer. ++ * Allow tab on serial line for symbol completion. ++ * Ignore KDB_ENTER() when kdb is already running. ++ * kdb v3.0-2.4.20-ia64-021210-1. ++ ++2003-01-23 Keith Owens ++ ++ * Upgrade to 2.4.20-ia64-021210. ++ * kdb v2.5-2.4.20-ia64-021210-1. ++ ++2002-11-14 Keith Owens ++ ++ * General clean up of handling for breakpoints and single stepping over ++ software breakpoints. ++ * kdb v2.5-2.4.19-ia64-020821-1. ++ ++2002-10-31 Keith Owens ++ ++ * Remove kdb_eframe_t. ++ * Sanity check if we have pt_regs. ++ * Remove kdba_getcurrentframe(). ++ * Comments for coexistence with O(1) scheduler. ++ * kdb v2.4-2.4.19-ia64-020821-1. ++ ++2002-10-15 Keith Owens ++ ++ * Minimize differences between patches for 2.4 and 2.5 kernels. ++ * kdb v2.3-2.4.19-ia64-020821-2. ++ ++2002-08-10 Keith Owens ++ ++ * Verify rw address for instruction breakpoint. ++ * Replace kdb_port with kdb_serial to support memory mapped I/O. ++ David Mosberger. ++ Note: This needs kdb v2.3-2.4.18-common-2 or later. ++ * kdb v2.3-2.4.18-ia64-020722-2. ++ ++2002-08-07 Keith Owens ++ ++ * Upgrade to 2.4.18-ia64-020722. ++ * Remove individual SGI copyrights, the general SGI copyright applies. ++ * Clean up disassembly layout. Hugh Dickins, Keith Owens. ++ * Remove fixed KDB_MAX_COMMANDS size. ++ * Add set_fs() around __copy_to_user on kernel addresses. ++ Randolph Chung. ++ * Position ia64 for CONFIG_NUMA_REPLICATE. ++ * Stacked registers modification support. Sebastien Lelarge. ++ * USB keyboard support. Sebastien Lelarge. ++ * kdb v2.3-2.4.18-ia64-020722-1. ++ ++2002-03-20 Keith Owens ++ ++ * Sync with 2.4.17-sn2. ++ * Add pod command. ++ ++2002-02-20 Keith Owens ++ ++ * Call kdb from mca handler. Jenna S. Hall, Intel. ++ * kdb v2.1-2.4.17-ia64-011226-2. ++ ++2002-01-18 Keith Owens ++ ++ * Replace kdb_get/putword with kdb_get/putarea functions. ++ * Wrap kdb references in #ifdef CONFIG_KDB. ++ * Delete sample i386 code. ++ * Refuse to update kernel text on NUMA systems. ++ * Reject hardware breakpoints, not supported yet. ++ * kdb v2.1-2.4.17-ia64-011226-1. ++ ++2002-01-07 Keith Owens ++ ++ * Split kdb for ia64 as kdb v2.0-2.4.17-ia64-011226-1. +--- /dev/null ++++ b/arch/ia64/kdb/Makefile +@@ -0,0 +1,21 @@ ++# ++# 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++# ++ ++obj-y := kdba_bt.o kdba_bp.o kdba_io.o kdba_support.o \ ++ cpu-ia64-opc.o ia64-dis.o ia64-opc.o kdba_id.o kdba_jmp.o ++ ++# fru does not compile on 2.6. ++# obj-$(CONFIG_IA64_SGI_SN2) += kdba_fru.o ++obj-$(CONFIG_IA64_SGI_SN2) += kdba_pod.o ++obj-$(CONFIG_IA64_GENERIC) += kdba_pod.o ++ ++override CFLAGS := $(CFLAGS:%-pg=% ) ++ ++AFLAGS_kdba_jmp.o += $(AFLAGS_KERNEL) ++ ++USE_STANDARD_AS_RULE := true +--- /dev/null ++++ b/arch/ia64/kdb/cpu-ia64-opc.c +@@ -0,0 +1,598 @@ ++/* Copyright 1998, 1999, 2000, 2001, 2002, 2003 ++ Free Software Foundation, Inc. ++ Contributed by David Mosberger-Tang ++ ++This file is part of BFD, the Binary File Descriptor library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++/* Logically, this code should be part of libopcode but since some of ++ the operand insertion/extraction functions help bfd to implement ++ relocations, this code is included as part of cpu-ia64.c. This ++ avoids circular dependencies between libopcode and libbfd and also ++ obviates the need for applications to link in libopcode when all ++ they really want is libbfd. ++ ++ --davidm Mon Apr 13 22:14:02 1998 */ ++ ++#ifdef __KERNEL__ ++#include "ia64-opc.h" ++#else /* __KERNEL__ */ ++#include "../opcodes/ia64-opc.h" ++#endif /* __KERNEL__ */ ++ ++#define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) ++ ++static const char* ++ins_rsvd (const struct ia64_operand *self ATTRIBUTE_UNUSED, ++ ia64_insn value ATTRIBUTE_UNUSED, ia64_insn *code ATTRIBUTE_UNUSED) ++{ ++ return "internal error---this shouldn't happen"; ++} ++ ++static const char* ++ext_rsvd (const struct ia64_operand *self ATTRIBUTE_UNUSED, ++ ia64_insn code ATTRIBUTE_UNUSED, ia64_insn *valuep ATTRIBUTE_UNUSED) ++{ ++ return "internal error---this shouldn't happen"; ++} ++ ++static const char* ++ins_const (const struct ia64_operand *self ATTRIBUTE_UNUSED, ++ ia64_insn value ATTRIBUTE_UNUSED, ia64_insn *code ATTRIBUTE_UNUSED) ++{ ++ return 0; ++} ++ ++static const char* ++ext_const (const struct ia64_operand *self ATTRIBUTE_UNUSED, ++ ia64_insn code ATTRIBUTE_UNUSED, ia64_insn *valuep ATTRIBUTE_UNUSED) ++{ ++ return 0; ++} ++ ++static const char* ++ins_reg (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ if (value >= 1u << self->field[0].bits) ++ return "register number out of range"; ++ ++ *code |= value << self->field[0].shift; ++ return 0; ++} ++ ++static const char* ++ext_reg (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ *valuep = ((code >> self->field[0].shift) ++ & ((1u << self->field[0].bits) - 1)); ++ return 0; ++} ++ ++static const char* ++ins_immu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ ia64_insn new = 0; ++ int i; ++ ++ for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) ++ { ++ new |= ((value & ((((ia64_insn) 1) << self->field[i].bits) - 1)) ++ << self->field[i].shift); ++ value >>= self->field[i].bits; ++ } ++ if (value) ++ return "integer operand out of range"; ++ ++ *code |= new; ++ return 0; ++} ++ ++static const char* ++ext_immu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ BFD_HOST_U_64_BIT value = 0; ++ int i, bits = 0, total = 0; ++ ++ for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) ++ { ++ bits = self->field[i].bits; ++ value |= ((code >> self->field[i].shift) ++ & ((((BFD_HOST_U_64_BIT) 1) << bits) - 1)) << total; ++ total += bits; ++ } ++ *valuep = value; ++ return 0; ++} ++ ++static const char* ++ins_immus8 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ if (value & 0x7) ++ return "value not an integer multiple of 8"; ++ return ins_immu (self, value >> 3, code); ++} ++ ++static const char* ++ext_immus8 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ const char *result; ++ ++ result = ext_immu (self, code, valuep); ++ if (result) ++ return result; ++ ++ *valuep = *valuep << 3; ++ return 0; ++} ++ ++static const char* ++ins_imms_scaled (const struct ia64_operand *self, ia64_insn value, ++ ia64_insn *code, int scale) ++{ ++ BFD_HOST_64_BIT svalue = value, sign_bit = 0; ++ ia64_insn new = 0; ++ int i; ++ ++ svalue >>= scale; ++ ++ for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) ++ { ++ new |= ((svalue & ((((ia64_insn) 1) << self->field[i].bits) - 1)) ++ << self->field[i].shift); ++ sign_bit = (svalue >> (self->field[i].bits - 1)) & 1; ++ svalue >>= self->field[i].bits; ++ } ++ if ((!sign_bit && svalue != 0) || (sign_bit && svalue != -1)) ++ return "integer operand out of range"; ++ ++ *code |= new; ++ return 0; ++} ++ ++static const char* ++ext_imms_scaled (const struct ia64_operand *self, ia64_insn code, ++ ia64_insn *valuep, int scale) ++{ ++ int i, bits = 0, total = 0; ++ BFD_HOST_64_BIT val = 0, sign; ++ ++ for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) ++ { ++ bits = self->field[i].bits; ++ val |= ((code >> self->field[i].shift) ++ & ((((BFD_HOST_U_64_BIT) 1) << bits) - 1)) << total; ++ total += bits; ++ } ++ /* sign extend: */ ++ sign = (BFD_HOST_64_BIT) 1 << (total - 1); ++ val = (val ^ sign) - sign; ++ ++ *valuep = (val << scale); ++ return 0; ++} ++ ++static const char* ++ins_imms (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ return ins_imms_scaled (self, value, code, 0); ++} ++ ++static const char* ++ins_immsu4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ value = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000; ++ ++ return ins_imms_scaled (self, value, code, 0); ++} ++ ++static const char* ++ext_imms (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ return ext_imms_scaled (self, code, valuep, 0); ++} ++ ++static const char* ++ins_immsm1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ --value; ++ return ins_imms_scaled (self, value, code, 0); ++} ++ ++static const char* ++ins_immsm1u4 (const struct ia64_operand *self, ia64_insn value, ++ ia64_insn *code) ++{ ++ value = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000; ++ ++ --value; ++ return ins_imms_scaled (self, value, code, 0); ++} ++ ++static const char* ++ext_immsm1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ const char *res = ext_imms_scaled (self, code, valuep, 0); ++ ++ ++*valuep; ++ return res; ++} ++ ++static const char* ++ins_imms1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ return ins_imms_scaled (self, value, code, 1); ++} ++ ++static const char* ++ext_imms1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ return ext_imms_scaled (self, code, valuep, 1); ++} ++ ++static const char* ++ins_imms4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ return ins_imms_scaled (self, value, code, 4); ++} ++ ++static const char* ++ext_imms4 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ return ext_imms_scaled (self, code, valuep, 4); ++} ++ ++static const char* ++ins_imms16 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ return ins_imms_scaled (self, value, code, 16); ++} ++ ++static const char* ++ext_imms16 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ return ext_imms_scaled (self, code, valuep, 16); ++} ++ ++static const char* ++ins_cimmu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ ia64_insn mask = (((ia64_insn) 1) << self->field[0].bits) - 1; ++ return ins_immu (self, value ^ mask, code); ++} ++ ++static const char* ++ext_cimmu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ const char *result; ++ ia64_insn mask; ++ ++ mask = (((ia64_insn) 1) << self->field[0].bits) - 1; ++ result = ext_immu (self, code, valuep); ++ if (!result) ++ { ++ mask = (((ia64_insn) 1) << self->field[0].bits) - 1; ++ *valuep ^= mask; ++ } ++ return result; ++} ++ ++static const char* ++ins_cnt (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ --value; ++ if (value >= ((BFD_HOST_U_64_BIT) 1) << self->field[0].bits) ++ return "count out of range"; ++ ++ *code |= value << self->field[0].shift; ++ return 0; ++} ++ ++static const char* ++ext_cnt (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ *valuep = ((code >> self->field[0].shift) ++ & ((((BFD_HOST_U_64_BIT) 1) << self->field[0].bits) - 1)) + 1; ++ return 0; ++} ++ ++static const char* ++ins_cnt2b (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ --value; ++ ++ if (value > 2) ++ return "count must be in range 1..3"; ++ ++ *code |= value << self->field[0].shift; ++ return 0; ++} ++ ++static const char* ++ext_cnt2b (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ *valuep = ((code >> self->field[0].shift) & 0x3) + 1; ++ return 0; ++} ++ ++static const char* ++ins_cnt2c (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ switch (value) ++ { ++ case 0: value = 0; break; ++ case 7: value = 1; break; ++ case 15: value = 2; break; ++ case 16: value = 3; break; ++ default: return "count must be 0, 7, 15, or 16"; ++ } ++ *code |= value << self->field[0].shift; ++ return 0; ++} ++ ++static const char* ++ext_cnt2c (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ ia64_insn value; ++ ++ value = (code >> self->field[0].shift) & 0x3; ++ switch (value) ++ { ++ case 0: value = 0; break; ++ case 1: value = 7; break; ++ case 2: value = 15; break; ++ case 3: value = 16; break; ++ } ++ *valuep = value; ++ return 0; ++} ++ ++static const char* ++ins_inc3 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) ++{ ++ BFD_HOST_64_BIT val = value; ++ BFD_HOST_U_64_BIT sign = 0; ++ ++ if (val < 0) ++ { ++ sign = 0x4; ++ value = -value; ++ } ++ switch (value) ++ { ++ case 1: value = 3; break; ++ case 4: value = 2; break; ++ case 8: value = 1; break; ++ case 16: value = 0; break; ++ default: return "count must be +/- 1, 4, 8, or 16"; ++ } ++ *code |= (sign | value) << self->field[0].shift; ++ return 0; ++} ++ ++static const char* ++ext_inc3 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) ++{ ++ BFD_HOST_64_BIT val; ++ int negate; ++ ++ val = (code >> self->field[0].shift) & 0x7; ++ negate = val & 0x4; ++ switch (val & 0x3) ++ { ++ case 0: val = 16; break; ++ case 1: val = 8; break; ++ case 2: val = 4; break; ++ case 3: val = 1; break; ++ } ++ if (negate) ++ val = -val; ++ ++ *valuep = val; ++ return 0; ++} ++ ++#define CST IA64_OPND_CLASS_CST ++#define REG IA64_OPND_CLASS_REG ++#define IND IA64_OPND_CLASS_IND ++#define ABS IA64_OPND_CLASS_ABS ++#define REL IA64_OPND_CLASS_REL ++ ++#define SDEC IA64_OPND_FLAG_DECIMAL_SIGNED ++#define UDEC IA64_OPND_FLAG_DECIMAL_UNSIGNED ++ ++const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] = ++ { ++ /* constants: */ ++ { CST, ins_const, ext_const, "NIL", {{ 0, 0}}, 0, "" }, ++ { CST, ins_const, ext_const, "ar.csd", {{ 0, 0}}, 0, "ar.csd" }, ++ { CST, ins_const, ext_const, "ar.ccv", {{ 0, 0}}, 0, "ar.ccv" }, ++ { CST, ins_const, ext_const, "ar.pfs", {{ 0, 0}}, 0, "ar.pfs" }, ++ { CST, ins_const, ext_const, "1", {{ 0, 0}}, 0, "1" }, ++ { CST, ins_const, ext_const, "8", {{ 0, 0}}, 0, "8" }, ++ { CST, ins_const, ext_const, "16", {{ 0, 0}}, 0, "16" }, ++ { CST, ins_const, ext_const, "r0", {{ 0, 0}}, 0, "r0" }, ++ { CST, ins_const, ext_const, "ip", {{ 0, 0}}, 0, "ip" }, ++ { CST, ins_const, ext_const, "pr", {{ 0, 0}}, 0, "pr" }, ++ { CST, ins_const, ext_const, "pr.rot", {{ 0, 0}}, 0, "pr.rot" }, ++ { CST, ins_const, ext_const, "psr", {{ 0, 0}}, 0, "psr" }, ++ { CST, ins_const, ext_const, "psr.l", {{ 0, 0}}, 0, "psr.l" }, ++ { CST, ins_const, ext_const, "psr.um", {{ 0, 0}}, 0, "psr.um" }, ++ ++ /* register operands: */ ++ { REG, ins_reg, ext_reg, "ar", {{ 7, 20}}, 0, /* AR3 */ ++ "an application register" }, ++ { REG, ins_reg, ext_reg, "b", {{ 3, 6}}, 0, /* B1 */ ++ "a branch register" }, ++ { REG, ins_reg, ext_reg, "b", {{ 3, 13}}, 0, /* B2 */ ++ "a branch register"}, ++ { REG, ins_reg, ext_reg, "cr", {{ 7, 20}}, 0, /* CR */ ++ "a control register"}, ++ { REG, ins_reg, ext_reg, "f", {{ 7, 6}}, 0, /* F1 */ ++ "a floating-point register" }, ++ { REG, ins_reg, ext_reg, "f", {{ 7, 13}}, 0, /* F2 */ ++ "a floating-point register" }, ++ { REG, ins_reg, ext_reg, "f", {{ 7, 20}}, 0, /* F3 */ ++ "a floating-point register" }, ++ { REG, ins_reg, ext_reg, "f", {{ 7, 27}}, 0, /* F4 */ ++ "a floating-point register" }, ++ { REG, ins_reg, ext_reg, "p", {{ 6, 6}}, 0, /* P1 */ ++ "a predicate register" }, ++ { REG, ins_reg, ext_reg, "p", {{ 6, 27}}, 0, /* P2 */ ++ "a predicate register" }, ++ { REG, ins_reg, ext_reg, "r", {{ 7, 6}}, 0, /* R1 */ ++ "a general register" }, ++ { REG, ins_reg, ext_reg, "r", {{ 7, 13}}, 0, /* R2 */ ++ "a general register" }, ++ { REG, ins_reg, ext_reg, "r", {{ 7, 20}}, 0, /* R3 */ ++ "a general register" }, ++ { REG, ins_reg, ext_reg, "r", {{ 2, 20}}, 0, /* R3_2 */ ++ "a general register r0-r3" }, ++ ++ /* indirect operands: */ ++ { IND, ins_reg, ext_reg, "cpuid", {{7, 20}}, 0, /* CPUID_R3 */ ++ "a cpuid register" }, ++ { IND, ins_reg, ext_reg, "dbr", {{7, 20}}, 0, /* DBR_R3 */ ++ "a dbr register" }, ++ { IND, ins_reg, ext_reg, "dtr", {{7, 20}}, 0, /* DTR_R3 */ ++ "a dtr register" }, ++ { IND, ins_reg, ext_reg, "itr", {{7, 20}}, 0, /* ITR_R3 */ ++ "an itr register" }, ++ { IND, ins_reg, ext_reg, "ibr", {{7, 20}}, 0, /* IBR_R3 */ ++ "an ibr register" }, ++ { IND, ins_reg, ext_reg, "", {{7, 20}}, 0, /* MR3 */ ++ "an indirect memory address" }, ++ { IND, ins_reg, ext_reg, "msr", {{7, 20}}, 0, /* MSR_R3 */ ++ "an msr register" }, ++ { IND, ins_reg, ext_reg, "pkr", {{7, 20}}, 0, /* PKR_R3 */ ++ "a pkr register" }, ++ { IND, ins_reg, ext_reg, "pmc", {{7, 20}}, 0, /* PMC_R3 */ ++ "a pmc register" }, ++ { IND, ins_reg, ext_reg, "pmd", {{7, 20}}, 0, /* PMD_R3 */ ++ "a pmd register" }, ++ { IND, ins_reg, ext_reg, "rr", {{7, 20}}, 0, /* RR_R3 */ ++ "an rr register" }, ++ ++ /* immediate operands: */ ++ { ABS, ins_cimmu, ext_cimmu, 0, {{ 5, 20 }}, UDEC, /* CCNT5 */ ++ "a 5-bit count (0-31)" }, ++ { ABS, ins_cnt, ext_cnt, 0, {{ 2, 27 }}, UDEC, /* CNT2a */ ++ "a 2-bit count (1-4)" }, ++ { ABS, ins_cnt2b, ext_cnt2b, 0, {{ 2, 27 }}, UDEC, /* CNT2b */ ++ "a 2-bit count (1-3)" }, ++ { ABS, ins_cnt2c, ext_cnt2c, 0, {{ 2, 30 }}, UDEC, /* CNT2c */ ++ "a count (0, 7, 15, or 16)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 5, 14}}, UDEC, /* CNT5 */ ++ "a 5-bit count (0-31)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 6, 27}}, UDEC, /* CNT6 */ ++ "a 6-bit count (0-63)" }, ++ { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 20}}, UDEC, /* CPOS6a */ ++ "a 6-bit bit pos (0-63)" }, ++ { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 14}}, UDEC, /* CPOS6b */ ++ "a 6-bit bit pos (0-63)" }, ++ { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 31}}, UDEC, /* CPOS6c */ ++ "a 6-bit bit pos (0-63)" }, ++ { ABS, ins_imms, ext_imms, 0, {{ 1, 36}}, SDEC, /* IMM1 */ ++ "a 1-bit integer (-1, 0)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 2, 13}}, UDEC, /* IMMU2 */ ++ "a 2-bit unsigned (0-3)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 7, 13}}, 0, /* IMMU7a */ ++ "a 7-bit unsigned (0-127)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 7, 20}}, 0, /* IMMU7b */ ++ "a 7-bit unsigned (0-127)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 7, 13}}, UDEC, /* SOF */ ++ "a frame size (register count)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 7, 20}}, UDEC, /* SOL */ ++ "a local register count" }, ++ { ABS, ins_immus8,ext_immus8,0, {{ 4, 27}}, UDEC, /* SOR */ ++ "a rotating register count (integer multiple of 8)" }, ++ { ABS, ins_imms, ext_imms, 0, /* IMM8 */ ++ {{ 7, 13}, { 1, 36}}, SDEC, ++ "an 8-bit integer (-128-127)" }, ++ { ABS, ins_immsu4, ext_imms, 0, /* IMM8U4 */ ++ {{ 7, 13}, { 1, 36}}, SDEC, ++ "an 8-bit signed integer for 32-bit unsigned compare (-128-127)" }, ++ { ABS, ins_immsm1, ext_immsm1, 0, /* IMM8M1 */ ++ {{ 7, 13}, { 1, 36}}, SDEC, ++ "an 8-bit integer (-127-128)" }, ++ { ABS, ins_immsm1u4, ext_immsm1, 0, /* IMM8M1U4 */ ++ {{ 7, 13}, { 1, 36}}, SDEC, ++ "an 8-bit integer for 32-bit unsigned compare (-127-(-1),1-128,0x100000000)" }, ++ { ABS, ins_immsm1, ext_immsm1, 0, /* IMM8M1U8 */ ++ {{ 7, 13}, { 1, 36}}, SDEC, ++ "an 8-bit integer for 64-bit unsigned compare (-127-(-1),1-128,0x10000000000000000)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 2, 33}, { 7, 20}}, 0, /* IMMU9 */ ++ "a 9-bit unsigned (0-511)" }, ++ { ABS, ins_imms, ext_imms, 0, /* IMM9a */ ++ {{ 7, 6}, { 1, 27}, { 1, 36}}, SDEC, ++ "a 9-bit integer (-256-255)" }, ++ { ABS, ins_imms, ext_imms, 0, /* IMM9b */ ++ {{ 7, 13}, { 1, 27}, { 1, 36}}, SDEC, ++ "a 9-bit integer (-256-255)" }, ++ { ABS, ins_imms, ext_imms, 0, /* IMM14 */ ++ {{ 7, 13}, { 6, 27}, { 1, 36}}, SDEC, ++ "a 14-bit integer (-8192-8191)" }, ++ { ABS, ins_imms1, ext_imms1, 0, /* IMM17 */ ++ {{ 7, 6}, { 8, 24}, { 1, 36}}, 0, ++ "a 17-bit integer (-65536-65535)" }, ++ { ABS, ins_immu, ext_immu, 0, {{20, 6}, { 1, 36}}, 0, /* IMMU21 */ ++ "a 21-bit unsigned" }, ++ { ABS, ins_imms, ext_imms, 0, /* IMM22 */ ++ {{ 7, 13}, { 9, 27}, { 5, 22}, { 1, 36}}, SDEC, ++ "a 22-bit signed integer" }, ++ { ABS, ins_immu, ext_immu, 0, /* IMMU24 */ ++ {{21, 6}, { 2, 31}, { 1, 36}}, 0, ++ "a 24-bit unsigned" }, ++ { ABS, ins_imms16,ext_imms16,0, {{27, 6}, { 1, 36}}, 0, /* IMM44 */ ++ "a 44-bit unsigned (least 16 bits ignored/zeroes)" }, ++ { ABS, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* IMMU62 */ ++ "a 62-bit unsigned" }, ++ { ABS, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* IMMU64 */ ++ "a 64-bit unsigned" }, ++ { ABS, ins_inc3, ext_inc3, 0, {{ 3, 13}}, SDEC, /* INC3 */ ++ "an increment (+/- 1, 4, 8, or 16)" }, ++ { ABS, ins_cnt, ext_cnt, 0, {{ 4, 27}}, UDEC, /* LEN4 */ ++ "a 4-bit length (1-16)" }, ++ { ABS, ins_cnt, ext_cnt, 0, {{ 6, 27}}, UDEC, /* LEN6 */ ++ "a 6-bit length (1-64)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 4, 20}}, 0, /* MBTYPE4 */ ++ "a mix type (@rev, @mix, @shuf, @alt, or @brcst)" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 8, 20}}, 0, /* MBTYPE8 */ ++ "an 8-bit mix type" }, ++ { ABS, ins_immu, ext_immu, 0, {{ 6, 14}}, UDEC, /* POS6 */ ++ "a 6-bit bit pos (0-63)" }, ++ { REL, ins_imms4, ext_imms4, 0, {{ 7, 6}, { 2, 33}}, 0, /* TAG13 */ ++ "a branch tag" }, ++ { REL, ins_imms4, ext_imms4, 0, {{ 9, 24}}, 0, /* TAG13b */ ++ "a branch tag" }, ++ { REL, ins_imms4, ext_imms4, 0, {{20, 6}, { 1, 36}}, 0, /* TGT25 */ ++ "a branch target" }, ++ { REL, ins_imms4, ext_imms4, 0, /* TGT25b */ ++ {{ 7, 6}, {13, 20}, { 1, 36}}, 0, ++ "a branch target" }, ++ { REL, ins_imms4, ext_imms4, 0, {{20, 13}, { 1, 36}}, 0, /* TGT25c */ ++ "a branch target" }, ++ { REL, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* TGT64 */ ++ "a branch target" }, ++ ++ { ABS, ins_const, ext_const, 0, {{0, 0}}, 0, /* LDXMOV */ ++ "ldxmov target" }, ++ }; +--- /dev/null ++++ b/arch/ia64/kdb/ia64-asmtab.c +@@ -0,0 +1,8585 @@ ++/* This file is automatically generated by ia64-gen. Do not edit! */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++static const char * const ia64_strings[] = { ++ "", "0", "1", "a", "acq", "add", "addl", "addp4", "adds", "alloc", "and", ++ "andcm", "b", "bias", "br", "break", "brl", "brp", "bsw", "c", "call", ++ "cexit", "chk", "cloop", "clr", "clrrrb", "cmp", "cmp4", "cmp8xchg16", ++ "cmpxchg1", "cmpxchg2", "cmpxchg4", "cmpxchg8", "cond", "cover", "ctop", ++ "czx1", "czx2", "d", "dep", "dpnt", "dptk", "e", "epc", "eq", "excl", ++ "exit", "exp", "extr", "f", "fabs", "fadd", "famax", "famin", "fand", ++ "fandcm", "fault", "fc", "fchkf", "fclass", "fclrf", "fcmp", "fcvt", ++ "fetchadd4", "fetchadd8", "few", "fill", "flushrs", "fma", "fmax", ++ "fmerge", "fmin", "fmix", "fmpy", "fms", "fneg", "fnegabs", "fnma", ++ "fnmpy", "fnorm", "for", "fpabs", "fpack", "fpamax", "fpamin", "fpcmp", ++ "fpcvt", "fpma", "fpmax", "fpmerge", "fpmin", "fpmpy", "fpms", "fpneg", ++ "fpnegabs", "fpnma", "fpnmpy", "fprcpa", "fprsqrta", "frcpa", "frsqrta", ++ "fselect", "fsetc", "fsub", "fswap", "fsxt", "fwb", "fx", "fxor", "fxu", ++ "g", "ga", "ge", "getf", "geu", "gt", "gtu", "h", "hint", "hu", "i", "ia", ++ "imp", "invala", "itc", "itr", "l", "ld1", "ld16", "ld2", "ld4", "ld8", ++ "ldf", "ldf8", "ldfd", "ldfe", "ldfp8", "ldfpd", "ldfps", "ldfs", "le", ++ "leu", "lfetch", "loadrs", "loop", "lr", "lt", "ltu", "lu", "m", "many", ++ "mf", "mix1", "mix2", "mix4", "mov", "movl", "mux1", "mux2", "nc", "ne", ++ "neq", "nge", "ngt", "nl", "nle", "nlt", "nm", "nop", "nr", "ns", "nt1", ++ "nt2", "nta", "nz", "or", "orcm", "ord", "pack2", "pack4", "padd1", ++ "padd2", "padd4", "pavg1", "pavg2", "pavgsub1", "pavgsub2", "pcmp1", ++ "pcmp2", "pcmp4", "pmax1", "pmax2", "pmin1", "pmin2", "pmpy2", "pmpyshr2", ++ "popcnt", "pr", "probe", "psad1", "pshl2", "pshl4", "pshladd2", "pshr2", ++ "pshr4", "pshradd2", "psub1", "psub2", "psub4", "ptc", "ptr", "r", "raz", ++ "rel", "ret", "rfi", "rsm", "rum", "rw", "s", "s0", "s1", "s2", "s3", ++ "sa", "se", "setf", "shl", "shladd", "shladdp4", "shr", "shrp", "sig", ++ "spill", "spnt", "sptk", "srlz", "ssm", "sss", "st1", "st16", "st2", ++ "st4", "st8", "stf", "stf8", "stfd", "stfe", "stfs", "sub", "sum", "sxt1", ++ "sxt2", "sxt4", "sync", "tak", "tbit", "thash", "tnat", "tpa", "trunc", ++ "ttag", "u", "unc", "unord", "unpack1", "unpack2", "unpack4", "uss", ++ "uus", "uuu", "w", "wexit", "wtop", "x", "xchg1", "xchg2", "xchg4", ++ "xchg8", "xf", "xma", "xmpy", "xor", "xuf", "z", "zxt1", "zxt2", "zxt4", ++}; ++ ++static const struct ia64_dependency ++dependencies[] = { ++ { "ALAT", 0, 0, 0, -1, NULL, }, ++ { "AR[BSP]", 26, 0, 2, 17, NULL, }, ++ { "AR[BSPSTORE]", 26, 0, 2, 18, NULL, }, ++ { "AR[CFLG]", 26, 0, 2, 27, NULL, }, ++ { "AR[CCV]", 26, 0, 2, 32, NULL, }, ++ { "AR[CSD]", 26, 0, 2, 25, NULL, }, ++ { "AR[EC]", 26, 0, 2, 66, NULL, }, ++ { "AR[EFLAG]", 26, 0, 2, 24, NULL, }, ++ { "AR[FCR]", 26, 0, 2, 21, NULL, }, ++ { "AR[FDR]", 26, 0, 2, 30, NULL, }, ++ { "AR[FIR]", 26, 0, 2, 29, NULL, }, ++ { "AR[FPSR].sf0.controls", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf1.controls", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf2.controls", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf3.controls", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf0.flags", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf1.flags", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf2.flags", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].sf3.flags", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].traps", 30, 0, 2, -1, NULL, }, ++ { "AR[FPSR].rv", 30, 0, 2, -1, NULL, }, ++ { "AR[FSR]", 26, 0, 2, 28, NULL, }, ++ { "AR[ITC]", 26, 0, 2, 44, NULL, }, ++ { "AR[K%], % in 0 - 7", 1, 0, 2, -1, NULL, }, ++ { "AR[LC]", 26, 0, 2, 65, NULL, }, ++ { "AR[PFS]", 26, 0, 2, 64, NULL, }, ++ { "AR[PFS]", 26, 0, 2, 64, NULL, }, ++ { "AR[PFS]", 26, 0, 0, 64, NULL, }, ++ { "AR[RNAT]", 26, 0, 2, 19, NULL, }, ++ { "AR[RSC]", 26, 0, 2, 16, NULL, }, ++ { "AR[SSD]", 26, 0, 2, 26, NULL, }, ++ { "AR[UNAT]{%}, % in 0 - 63", 2, 0, 2, -1, NULL, }, ++ { "AR%, % in 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111", 3, 0, 0, -1, NULL, }, ++ { "AR%, % in 48-63, 112-127", 4, 0, 2, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 0, 2, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 0, 0, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 0, 2, -1, NULL, }, ++ { "CFM", 6, 0, 2, -1, NULL, }, ++ { "CFM", 6, 0, 2, -1, NULL, }, ++ { "CFM", 6, 0, 2, -1, NULL, }, ++ { "CFM", 6, 0, 2, -1, NULL, }, ++ { "CFM", 6, 0, 0, -1, NULL, }, ++ { "CPUID#", 7, 0, 5, -1, NULL, }, ++ { "CR[CMCV]", 27, 0, 3, 74, NULL, }, ++ { "CR[DCR]", 27, 0, 3, 0, NULL, }, ++ { "CR[EOI]", 27, 0, 7, 67, "SC Section 10.8.3.4", }, ++ { "CR[GPTA]", 27, 0, 3, 9, NULL, }, ++ { "CR[IFA]", 27, 0, 1, 20, NULL, }, ++ { "CR[IFA]", 27, 0, 3, 20, NULL, }, ++ { "CR[IFS]", 27, 0, 3, 23, NULL, }, ++ { "CR[IFS]", 27, 0, 1, 23, NULL, }, ++ { "CR[IFS]", 27, 0, 1, 23, NULL, }, ++ { "CR[IHA]", 27, 0, 3, 25, NULL, }, ++ { "CR[IIM]", 27, 0, 3, 24, NULL, }, ++ { "CR[IIP]", 27, 0, 3, 19, NULL, }, ++ { "CR[IIP]", 27, 0, 1, 19, NULL, }, ++ { "CR[IIPA]", 27, 0, 3, 22, NULL, }, ++ { "CR[IPSR]", 27, 0, 3, 16, NULL, }, ++ { "CR[IPSR]", 27, 0, 1, 16, NULL, }, ++ { "CR[IRR%], % in 0 - 3", 8, 0, 3, -1, NULL, }, ++ { "CR[ISR]", 27, 0, 3, 17, NULL, }, ++ { "CR[ITIR]", 27, 0, 3, 21, NULL, }, ++ { "CR[ITIR]", 27, 0, 1, 21, NULL, }, ++ { "CR[ITM]", 27, 0, 3, 1, NULL, }, ++ { "CR[ITV]", 27, 0, 3, 72, NULL, }, ++ { "CR[IVA]", 27, 0, 4, 2, NULL, }, ++ { "CR[IVR]", 27, 0, 7, 65, "SC Section 10.8.3.2", }, ++ { "CR[LID]", 27, 0, 7, 64, "SC Section 10.8.3.1", }, ++ { "CR[LRR%], % in 0 - 1", 9, 0, 3, -1, NULL, }, ++ { "CR[PMV]", 27, 0, 3, 73, NULL, }, ++ { "CR[PTA]", 27, 0, 3, 8, NULL, }, ++ { "CR[TPR]", 27, 0, 3, 66, NULL, }, ++ { "CR[TPR]", 27, 0, 7, 66, "SC Section 10.8.3.3", }, ++ { "CR%, % in 3-7, 10-15, 18, 26-63, 75-79, 82-127", 10, 0, 0, -1, NULL, }, ++ { "DBR#", 11, 0, 2, -1, NULL, }, ++ { "DBR#", 11, 0, 3, -1, NULL, }, ++ { "DTC", 0, 0, 3, -1, NULL, }, ++ { "DTC", 0, 0, 2, -1, NULL, }, ++ { "DTC", 0, 0, 0, -1, NULL, }, ++ { "DTC", 0, 0, 2, -1, NULL, }, ++ { "DTC_LIMIT*", 0, 0, 2, -1, NULL, }, ++ { "DTR", 0, 0, 3, -1, NULL, }, ++ { "DTR", 0, 0, 2, -1, NULL, }, ++ { "DTR", 0, 0, 3, -1, NULL, }, ++ { "DTR", 0, 0, 0, -1, NULL, }, ++ { "DTR", 0, 0, 2, -1, NULL, }, ++ { "FR%, % in 0 - 1", 12, 0, 0, -1, NULL, }, ++ { "FR%, % in 2 - 127", 13, 0, 2, -1, NULL, }, ++ { "FR%, % in 2 - 127", 13, 0, 0, -1, NULL, }, ++ { "GR0", 14, 0, 0, -1, NULL, }, ++ { "GR%, % in 1 - 127", 15, 0, 0, -1, NULL, }, ++ { "GR%, % in 1 - 127", 15, 0, 2, -1, NULL, }, ++ { "IBR#", 16, 0, 2, -1, NULL, }, ++ { "InService*", 17, 0, 3, -1, NULL, }, ++ { "InService*", 17, 0, 2, -1, NULL, }, ++ { "InService*", 17, 0, 2, -1, NULL, }, ++ { "IP", 0, 0, 0, -1, NULL, }, ++ { "ITC", 0, 0, 4, -1, NULL, }, ++ { "ITC", 0, 0, 2, -1, NULL, }, ++ { "ITC", 0, 0, 0, -1, NULL, }, ++ { "ITC", 0, 0, 4, -1, NULL, }, ++ { "ITC", 0, 0, 2, -1, NULL, }, ++ { "ITC_LIMIT*", 0, 0, 2, -1, NULL, }, ++ { "ITR", 0, 0, 2, -1, NULL, }, ++ { "ITR", 0, 0, 4, -1, NULL, }, ++ { "ITR", 0, 0, 2, -1, NULL, }, ++ { "ITR", 0, 0, 0, -1, NULL, }, ++ { "ITR", 0, 0, 4, -1, NULL, }, ++ { "memory", 0, 0, 0, -1, NULL, }, ++ { "MSR#", 18, 0, 5, -1, NULL, }, ++ { "PKR#", 19, 0, 3, -1, NULL, }, ++ { "PKR#", 19, 0, 0, -1, NULL, }, ++ { "PKR#", 19, 0, 2, -1, NULL, }, ++ { "PKR#", 19, 0, 2, -1, NULL, }, ++ { "PMC#", 20, 0, 2, -1, NULL, }, ++ { "PMC#", 20, 0, 7, -1, "SC+3 Section 12.1.1", }, ++ { "PMD#", 21, 0, 2, -1, NULL, }, ++ { "PR0", 0, 0, 0, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 0, 2, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 0, 2, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 0, 0, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 0, 2, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 0, 2, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 0, 0, -1, NULL, }, ++ { "PR63", 24, 0, 2, -1, NULL, }, ++ { "PR63", 24, 0, 2, -1, NULL, }, ++ { "PR63", 24, 0, 0, -1, NULL, }, ++ { "PSR.ac", 28, 0, 1, 3, NULL, }, ++ { "PSR.ac", 28, 0, 3, 3, NULL, }, ++ { "PSR.ac", 28, 0, 2, 3, NULL, }, ++ { "PSR.be", 28, 0, 1, 1, NULL, }, ++ { "PSR.be", 28, 0, 3, 1, NULL, }, ++ { "PSR.be", 28, 0, 2, 1, NULL, }, ++ { "PSR.bn", 28, 0, 2, 44, NULL, }, ++ { "PSR.cpl", 28, 0, 1, 32, NULL, }, ++ { "PSR.da", 28, 0, 3, 38, NULL, }, ++ { "PSR.db", 28, 0, 3, 24, NULL, }, ++ { "PSR.db", 28, 0, 2, 24, NULL, }, ++ { "PSR.db", 28, 0, 3, 24, NULL, }, ++ { "PSR.dd", 28, 0, 3, 39, NULL, }, ++ { "PSR.dfh", 28, 0, 3, 19, NULL, }, ++ { "PSR.dfh", 28, 0, 2, 19, NULL, }, ++ { "PSR.dfl", 28, 0, 3, 18, NULL, }, ++ { "PSR.dfl", 28, 0, 2, 18, NULL, }, ++ { "PSR.di", 28, 0, 3, 22, NULL, }, ++ { "PSR.di", 28, 0, 2, 22, NULL, }, ++ { "PSR.dt", 28, 0, 3, 17, NULL, }, ++ { "PSR.dt", 28, 0, 2, 17, NULL, }, ++ { "PSR.ed", 28, 0, 3, 43, NULL, }, ++ { "PSR.i", 28, 0, 2, 14, NULL, }, ++ { "PSR.i", 28, 0, 3, 14, NULL, }, ++ { "PSR.ia", 28, 0, 0, 14, NULL, }, ++ { "PSR.ic", 28, 0, 2, 13, NULL, }, ++ { "PSR.ic", 28, 0, 3, 13, NULL, }, ++ { "PSR.id", 28, 0, 0, 14, NULL, }, ++ { "PSR.is", 28, 0, 0, 14, NULL, }, ++ { "PSR.it", 28, 0, 3, 14, NULL, }, ++ { "PSR.lp", 28, 0, 2, 25, NULL, }, ++ { "PSR.lp", 28, 0, 3, 25, NULL, }, ++ { "PSR.lp", 28, 0, 3, 25, NULL, }, ++ { "PSR.mc", 28, 0, 0, 35, NULL, }, ++ { "PSR.mfh", 28, 0, 2, 5, NULL, }, ++ { "PSR.mfl", 28, 0, 2, 4, NULL, }, ++ { "PSR.pk", 28, 0, 3, 15, NULL, }, ++ { "PSR.pk", 28, 0, 2, 15, NULL, }, ++ { "PSR.pp", 28, 0, 2, 21, NULL, }, ++ { "PSR.ri", 28, 0, 0, 41, NULL, }, ++ { "PSR.rt", 28, 0, 2, 27, NULL, }, ++ { "PSR.rt", 28, 0, 3, 27, NULL, }, ++ { "PSR.rt", 28, 0, 3, 27, NULL, }, ++ { "PSR.si", 28, 0, 2, 23, NULL, }, ++ { "PSR.si", 28, 0, 3, 23, NULL, }, ++ { "PSR.sp", 28, 0, 2, 20, NULL, }, ++ { "PSR.sp", 28, 0, 3, 20, NULL, }, ++ { "PSR.ss", 28, 0, 3, 40, NULL, }, ++ { "PSR.tb", 28, 0, 3, 26, NULL, }, ++ { "PSR.tb", 28, 0, 2, 26, NULL, }, ++ { "PSR.up", 28, 0, 2, 2, NULL, }, ++ { "RR#", 25, 0, 3, -1, NULL, }, ++ { "RR#", 25, 0, 2, -1, NULL, }, ++ { "RSE", 29, 0, 2, -1, NULL, }, ++ { "ALAT", 0, 1, 0, -1, NULL, }, ++ { "AR[BSP]", 26, 1, 2, 17, NULL, }, ++ { "AR[BSPSTORE]", 26, 1, 2, 18, NULL, }, ++ { "AR[CCV]", 26, 1, 2, 32, NULL, }, ++ { "AR[CFLG]", 26, 1, 2, 27, NULL, }, ++ { "AR[CSD]", 26, 1, 2, 25, NULL, }, ++ { "AR[EC]", 26, 1, 2, 66, NULL, }, ++ { "AR[EFLAG]", 26, 1, 2, 24, NULL, }, ++ { "AR[FCR]", 26, 1, 2, 21, NULL, }, ++ { "AR[FDR]", 26, 1, 2, 30, NULL, }, ++ { "AR[FIR]", 26, 1, 2, 29, NULL, }, ++ { "AR[FPSR].sf0.controls", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf1.controls", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf2.controls", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf3.controls", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf0.flags", 30, 1, 0, -1, NULL, }, ++ { "AR[FPSR].sf0.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf0.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf1.flags", 30, 1, 0, -1, NULL, }, ++ { "AR[FPSR].sf1.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf1.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf2.flags", 30, 1, 0, -1, NULL, }, ++ { "AR[FPSR].sf2.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf2.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf3.flags", 30, 1, 0, -1, NULL, }, ++ { "AR[FPSR].sf3.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].sf3.flags", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].rv", 30, 1, 2, -1, NULL, }, ++ { "AR[FPSR].traps", 30, 1, 2, -1, NULL, }, ++ { "AR[FSR]", 26, 1, 2, 28, NULL, }, ++ { "AR[ITC]", 26, 1, 2, 44, NULL, }, ++ { "AR[K%], % in 0 - 7", 1, 1, 2, -1, NULL, }, ++ { "AR[LC]", 26, 1, 2, 65, NULL, }, ++ { "AR[PFS]", 26, 1, 0, 64, NULL, }, ++ { "AR[PFS]", 26, 1, 2, 64, NULL, }, ++ { "AR[PFS]", 26, 1, 2, 64, NULL, }, ++ { "AR[RNAT]", 26, 1, 2, 19, NULL, }, ++ { "AR[RSC]", 26, 1, 2, 16, NULL, }, ++ { "AR[UNAT]{%}, % in 0 - 63", 2, 1, 2, -1, NULL, }, ++ { "AR%, % in 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111", 3, 1, 0, -1, NULL, }, ++ { "AR%, % in 48 - 63, 112-127", 4, 1, 2, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 1, 2, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 1, 2, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 1, 2, -1, NULL, }, ++ { "BR%, % in 0 - 7", 5, 1, 0, -1, NULL, }, ++ { "CFM", 6, 1, 2, -1, NULL, }, ++ { "CPUID#", 7, 1, 0, -1, NULL, }, ++ { "CR[CMCV]", 27, 1, 2, 74, NULL, }, ++ { "CR[DCR]", 27, 1, 2, 0, NULL, }, ++ { "CR[EOI]", 27, 1, 7, 67, "SC Section 10.8.3.4", }, ++ { "CR[GPTA]", 27, 1, 2, 9, NULL, }, ++ { "CR[IFA]", 27, 1, 2, 20, NULL, }, ++ { "CR[IFS]", 27, 1, 2, 23, NULL, }, ++ { "CR[IHA]", 27, 1, 2, 25, NULL, }, ++ { "CR[IIM]", 27, 1, 2, 24, NULL, }, ++ { "CR[IIP]", 27, 1, 2, 19, NULL, }, ++ { "CR[IIPA]", 27, 1, 2, 22, NULL, }, ++ { "CR[IPSR]", 27, 1, 2, 16, NULL, }, ++ { "CR[IRR%], % in 0 - 3", 8, 1, 2, -1, NULL, }, ++ { "CR[ISR]", 27, 1, 2, 17, NULL, }, ++ { "CR[ITIR]", 27, 1, 2, 21, NULL, }, ++ { "CR[ITM]", 27, 1, 2, 1, NULL, }, ++ { "CR[ITV]", 27, 1, 2, 72, NULL, }, ++ { "CR[IVA]", 27, 1, 2, 2, NULL, }, ++ { "CR[IVR]", 27, 1, 7, 65, "SC", }, ++ { "CR[LID]", 27, 1, 7, 64, "SC", }, ++ { "CR[LRR%], % in 0 - 1", 9, 1, 2, -1, NULL, }, ++ { "CR[PMV]", 27, 1, 2, 73, NULL, }, ++ { "CR[PTA]", 27, 1, 2, 8, NULL, }, ++ { "CR[TPR]", 27, 1, 2, 66, NULL, }, ++ { "CR%, % in 3-7, 10-15, 18, 26-63, 75-79, 82-127", 10, 1, 0, -1, NULL, }, ++ { "DBR#", 11, 1, 2, -1, NULL, }, ++ { "DTC", 0, 1, 0, -1, NULL, }, ++ { "DTC", 0, 1, 2, -1, NULL, }, ++ { "DTC", 0, 1, 2, -1, NULL, }, ++ { "DTC_LIMIT*", 0, 1, 2, -1, NULL, }, ++ { "DTR", 0, 1, 2, -1, NULL, }, ++ { "DTR", 0, 1, 2, -1, NULL, }, ++ { "DTR", 0, 1, 2, -1, NULL, }, ++ { "DTR", 0, 1, 0, -1, NULL, }, ++ { "FR%, % in 0 - 1", 12, 1, 0, -1, NULL, }, ++ { "FR%, % in 2 - 127", 13, 1, 2, -1, NULL, }, ++ { "GR0", 14, 1, 0, -1, NULL, }, ++ { "GR%, % in 1 - 127", 15, 1, 2, -1, NULL, }, ++ { "IBR#", 16, 1, 2, -1, NULL, }, ++ { "InService*", 17, 1, 7, -1, "SC", }, ++ { "IP", 0, 1, 0, -1, NULL, }, ++ { "ITC", 0, 1, 0, -1, NULL, }, ++ { "ITC", 0, 1, 2, -1, NULL, }, ++ { "ITC", 0, 1, 2, -1, NULL, }, ++ { "ITR", 0, 1, 2, -1, NULL, }, ++ { "ITR", 0, 1, 2, -1, NULL, }, ++ { "ITR", 0, 1, 0, -1, NULL, }, ++ { "memory", 0, 1, 0, -1, NULL, }, ++ { "MSR#", 18, 1, 7, -1, "SC", }, ++ { "PKR#", 19, 1, 0, -1, NULL, }, ++ { "PKR#", 19, 1, 0, -1, NULL, }, ++ { "PKR#", 19, 1, 2, -1, NULL, }, ++ { "PMC#", 20, 1, 2, -1, NULL, }, ++ { "PMD#", 21, 1, 2, -1, NULL, }, ++ { "PR0", 0, 1, 0, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 1, 0, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 1, 0, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 1, 2, -1, NULL, }, ++ { "PR%, % in 1 - 15", 22, 1, 2, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 1, 0, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 1, 0, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 1, 2, -1, NULL, }, ++ { "PR%, % in 16 - 62", 23, 1, 2, -1, NULL, }, ++ { "PR63", 24, 1, 0, -1, NULL, }, ++ { "PR63", 24, 1, 0, -1, NULL, }, ++ { "PR63", 24, 1, 2, -1, NULL, }, ++ { "PR63", 24, 1, 2, -1, NULL, }, ++ { "PSR.ac", 28, 1, 2, 3, NULL, }, ++ { "PSR.be", 28, 1, 2, 1, NULL, }, ++ { "PSR.bn", 28, 1, 2, 44, NULL, }, ++ { "PSR.cpl", 28, 1, 2, 32, NULL, }, ++ { "PSR.da", 28, 1, 2, 38, NULL, }, ++ { "PSR.db", 28, 1, 2, 24, NULL, }, ++ { "PSR.dd", 28, 1, 2, 39, NULL, }, ++ { "PSR.dfh", 28, 1, 2, 19, NULL, }, ++ { "PSR.dfl", 28, 1, 2, 18, NULL, }, ++ { "PSR.di", 28, 1, 2, 22, NULL, }, ++ { "PSR.dt", 28, 1, 2, 17, NULL, }, ++ { "PSR.ed", 28, 1, 2, 43, NULL, }, ++ { "PSR.i", 28, 1, 2, 14, NULL, }, ++ { "PSR.ia", 28, 1, 2, 14, NULL, }, ++ { "PSR.ic", 28, 1, 2, 13, NULL, }, ++ { "PSR.id", 28, 1, 2, 14, NULL, }, ++ { "PSR.is", 28, 1, 2, 14, NULL, }, ++ { "PSR.it", 28, 1, 2, 14, NULL, }, ++ { "PSR.lp", 28, 1, 2, 25, NULL, }, ++ { "PSR.mc", 28, 1, 2, 35, NULL, }, ++ { "PSR.mfh", 28, 1, 0, 5, NULL, }, ++ { "PSR.mfh", 28, 1, 2, 5, NULL, }, ++ { "PSR.mfh", 28, 1, 2, 5, NULL, }, ++ { "PSR.mfl", 28, 1, 0, 4, NULL, }, ++ { "PSR.mfl", 28, 1, 2, 4, NULL, }, ++ { "PSR.mfl", 28, 1, 2, 4, NULL, }, ++ { "PSR.pk", 28, 1, 2, 15, NULL, }, ++ { "PSR.pp", 28, 1, 2, 21, NULL, }, ++ { "PSR.ri", 28, 1, 2, 41, NULL, }, ++ { "PSR.rt", 28, 1, 2, 27, NULL, }, ++ { "PSR.si", 28, 1, 2, 23, NULL, }, ++ { "PSR.sp", 28, 1, 2, 20, NULL, }, ++ { "PSR.ss", 28, 1, 2, 40, NULL, }, ++ { "PSR.tb", 28, 1, 2, 26, NULL, }, ++ { "PSR.up", 28, 1, 2, 2, NULL, }, ++ { "RR#", 25, 1, 2, -1, NULL, }, ++ { "RSE", 29, 1, 2, -1, NULL, }, ++ { "PR63", 24, 2, 6, -1, NULL, }, ++}; ++ ++static const unsigned short dep0[] = { ++ 96, 267, 2139, 2312, ++}; ++ ++static const unsigned short dep1[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, 4135, ++ 20613, ++}; ++ ++static const unsigned short dep2[] = { ++ 96, 267, 2165, 2166, 2168, 2169, 2171, 2172, 2174, 2329, 2332, 2333, 2336, ++ 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep3[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2329, 2332, ++ 2333, 2336, 2337, 2340, 2341, 4135, 20613, ++}; ++ ++static const unsigned short dep4[] = { ++ 96, 267, 22645, 22646, 22648, 22649, 22651, 22652, 22654, 22809, 22812, 22813, ++ 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep5[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++ 22809, 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep6[] = { ++ 96, 267, 2165, 2166, 2168, 2169, 2171, 2172, 2174, 2329, 2330, 2332, 2334, ++ 2336, 2338, 2340, ++}; ++ ++static const unsigned short dep7[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2329, 2330, ++ 2333, 2334, 2337, 2338, 2341, 4135, 20613, ++}; ++ ++static const unsigned short dep8[] = { ++ 96, 267, 2165, 2166, 2168, 2169, 2171, 2172, 2174, 2329, 2331, 2333, 2335, ++ 2337, 2339, 2341, ++}; ++ ++static const unsigned short dep9[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2329, 2331, ++ 2332, 2335, 2336, 2339, 2340, 4135, 20613, ++}; ++ ++static const unsigned short dep10[] = { ++ 96, 267, 2165, 2166, 2168, 2169, 2171, 2172, 2174, 2329, 2330, 2331, 2332, ++ 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341, ++}; ++ ++static const unsigned short dep11[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2329, 2330, ++ 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341, 4135, 20613, ++ ++}; ++ ++static const unsigned short dep12[] = { ++ 96, 267, 2379, ++}; ++ ++static const unsigned short dep13[] = { ++ 40, 41, 96, 156, 174, 175, 267, 2082, 2083, 2165, 2167, 2168, 2170, 2171, ++ 2173, 2174, 4135, ++}; ++ ++static const unsigned short dep14[] = { ++ 96, 155, 267, 310, 2379, 28852, 29002, ++}; ++ ++static const unsigned short dep15[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ++ 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 40, 41, 96, 144, 156, 174, 175, ++ 267, 310, 2082, 2083, 2165, 2167, 2168, 2170, 2171, 2173, 2174, 4135, 28852, ++ 29002, ++}; ++ ++static const unsigned short dep16[] = { ++ 1, 6, 40, 96, 134, 182, 187, 226, 267, 297, 2379, 28852, 29002, ++}; ++ ++static const unsigned short dep17[] = { ++ 1, 25, 27, 38, 40, 41, 96, 156, 158, 159, 174, 175, 182, 187, 226, 267, 297, ++ 2082, 2083, 2165, 2167, 2168, 2170, 2171, 2173, 2174, 4135, 28852, 29002, ++ ++}; ++ ++static const unsigned short dep18[] = { ++ 1, 40, 51, 96, 182, 226, 233, 267, 28852, 29002, ++}; ++ ++static const unsigned short dep19[] = { ++ 1, 38, 40, 41, 96, 153, 174, 182, 226, 233, 267, 4135, 28852, 29002, ++}; ++ ++static const unsigned short dep20[] = { ++ 40, 96, 226, 267, ++}; ++ ++static const unsigned short dep21[] = { ++ 96, 174, 226, 267, ++}; ++ ++static const unsigned short dep22[] = { ++ 1, 40, 96, 128, 129, 131, 132, 133, 134, 135, 138, 139, 140, 141, 142, 143, ++ 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 155, 156, 159, 160, 161, ++ 162, 163, 164, 165, 166, 169, 170, 171, 172, 173, 174, 175, 176, 177, 182, ++ 226, 267, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, ++ 307, 308, 309, 310, 311, 312, 313, 315, 316, 318, 319, 320, 321, 322, 323, ++ 324, 325, 326, 327, 328, 28852, 29002, ++}; ++ ++static const unsigned short dep23[] = { ++ 1, 38, 40, 41, 50, 51, 55, 58, 72, 96, 134, 174, 182, 226, 267, 294, 295, ++ 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, ++ 311, 312, 313, 315, 316, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, ++ 328, 4135, 28852, 29002, ++}; ++ ++static const unsigned short dep24[] = { ++ 96, 133, 267, 296, ++}; ++ ++static const unsigned short dep25[] = { ++ 96, 134, 174, 267, 296, ++}; ++ ++static const unsigned short dep26[] = { ++ 96, 134, 267, 297, ++}; ++ ++static const unsigned short dep27[] = { ++ 25, 26, 96, 97, 100, 104, 107, 134, 156, 174, 267, 297, ++}; ++ ++static const unsigned short dep28[] = { ++ 40, 41, 96, 174, 267, 2165, 2167, 2168, 2170, 2171, 2173, 2174, 4135, ++}; ++ ++static const unsigned short dep29[] = { ++ 1, 25, 40, 96, 182, 214, 215, 226, 267, 2082, 2270, 2273, 2379, 28852, 29002, ++ ++}; ++ ++static const unsigned short dep30[] = { ++ 1, 6, 38, 40, 41, 96, 134, 156, 174, 175, 182, 214, 216, 226, 267, 2082, 2083, ++ 2165, 2167, 2168, 2170, 2171, 2173, 2174, 2271, 2273, 4135, 28852, 29002, ++ ++}; ++ ++static const unsigned short dep31[] = { ++ 96, 267, ++}; ++ ++static const unsigned short dep32[] = { ++ 96, 174, 267, 2082, 2084, ++}; ++ ++static const unsigned short dep33[] = { ++ 40, 41, 96, 156, 174, 175, 267, 2165, 2167, 2168, 2170, 2171, 2173, 2174, ++ 4135, ++}; ++ ++static const unsigned short dep34[] = { ++ 6, 37, 38, 39, 96, 124, 125, 187, 226, 267, 292, 293, 2379, ++}; ++ ++static const unsigned short dep35[] = { ++ 6, 37, 40, 41, 96, 156, 174, 175, 187, 226, 267, 292, 293, 331, 2165, 2167, ++ 2168, 2170, 2171, 2173, 2174, 4135, ++}; ++ ++static const unsigned short dep36[] = { ++ 24, 96, 213, 267, 2379, ++}; ++ ++static const unsigned short dep37[] = { ++ 24, 40, 41, 96, 156, 174, 175, 213, 267, 2165, 2167, 2168, 2170, 2171, 2173, ++ 2174, 4135, ++}; ++ ++static const unsigned short dep38[] = { ++ 6, 24, 37, 38, 39, 96, 124, 125, 187, 213, 226, 267, 292, 293, 2379, ++}; ++ ++static const unsigned short dep39[] = { ++ 6, 24, 37, 40, 41, 96, 156, 174, 175, 187, 213, 226, 267, 292, 293, 331, 2165, ++ 2167, 2168, 2170, 2171, 2173, 2174, 4135, ++}; ++ ++static const unsigned short dep40[] = { ++ 1, 6, 38, 40, 41, 96, 134, 156, 174, 175, 182, 214, 216, 226, 267, 2165, 2167, ++ 2168, 2170, 2171, 2173, 2174, 2271, 2273, 4135, 28852, 29002, ++}; ++ ++static const unsigned short dep41[] = { ++ 96, 174, 267, ++}; ++ ++static const unsigned short dep42[] = { ++ 15, 96, 196, 197, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, 22812, 22813, 22816, ++ 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep43[] = { ++ 11, 19, 20, 40, 41, 96, 174, 196, 198, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 22809, 22812, ++ 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep44[] = { ++ 15, 16, 17, 18, 96, 196, 197, 199, 200, 202, 203, 205, 206, 267, 2135, 2310, ++ 18593, 18594, 18746, 18747, 18749, 18750, 22645, 22646, 22647, 22649, 22650, ++ 22652, 22653, 22809, 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep45[] = { ++ 11, 12, 13, 14, 19, 20, 40, 41, 96, 174, 196, 198, 199, 201, 202, 204, 205, ++ 207, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2310, 4135, 16524, 16526, ++ 18746, 18748, 18749, 18751, 22809, 22812, 22813, 22816, 22817, 22820, 22821, ++ ++}; ++ ++static const unsigned short dep46[] = { ++ 16, 96, 199, 200, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, 22812, 22813, 22816, ++ 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep47[] = { ++ 12, 19, 20, 40, 41, 96, 174, 199, 201, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 22809, 22812, ++ 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep48[] = { ++ 17, 96, 202, 203, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, 22812, 22813, 22816, ++ 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep49[] = { ++ 13, 19, 20, 40, 41, 96, 174, 202, 204, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 22809, 22812, ++ 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep50[] = { ++ 18, 96, 205, 206, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, 22812, 22813, 22816, ++ 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep51[] = { ++ 14, 19, 20, 40, 41, 96, 174, 205, 207, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 22809, 22812, ++ 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep52[] = { ++ 15, 96, 196, 197, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ ++}; ++ ++static const unsigned short dep53[] = { ++ 11, 19, 20, 40, 41, 96, 174, 196, 198, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep54[] = { ++ 15, 16, 17, 18, 96, 196, 197, 199, 200, 202, 203, 205, 206, 267, 2135, 2310, ++ 18593, 18594, 18746, 18747, 18749, 18750, ++}; ++ ++static const unsigned short dep55[] = { ++ 11, 12, 13, 14, 19, 20, 40, 41, 96, 174, 196, 198, 199, 201, 202, 204, 205, ++ 207, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2310, 4135, 16524, 16526, ++ 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep56[] = { ++ 16, 96, 199, 200, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ ++}; ++ ++static const unsigned short dep57[] = { ++ 12, 19, 20, 40, 41, 96, 174, 199, 201, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep58[] = { ++ 17, 96, 202, 203, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ ++}; ++ ++static const unsigned short dep59[] = { ++ 13, 19, 20, 40, 41, 96, 174, 202, 204, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep60[] = { ++ 18, 96, 205, 206, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++ ++}; ++ ++static const unsigned short dep61[] = { ++ 14, 19, 20, 40, 41, 96, 174, 205, 207, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep62[] = { ++ 96, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++}; ++ ++static const unsigned short dep63[] = { ++ 40, 41, 96, 174, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2310, 4135, ++ 16524, 16526, 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep64[] = { ++ 11, 96, 192, 267, ++}; ++ ++static const unsigned short dep65[] = { ++ 11, 40, 41, 96, 174, 192, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep66[] = { ++ 11, 40, 41, 96, 174, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep67[] = { ++ 12, 96, 193, 267, ++}; ++ ++static const unsigned short dep68[] = { ++ 11, 40, 41, 96, 174, 193, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep69[] = { ++ 13, 96, 194, 267, ++}; ++ ++static const unsigned short dep70[] = { ++ 11, 40, 41, 96, 174, 194, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep71[] = { ++ 14, 96, 195, 267, ++}; ++ ++static const unsigned short dep72[] = { ++ 11, 40, 41, 96, 174, 195, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep73[] = { ++ 15, 96, 197, 198, 267, ++}; ++ ++static const unsigned short dep74[] = { ++ 40, 41, 96, 174, 197, 198, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep75[] = { ++ 40, 41, 96, 174, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep76[] = { ++ 16, 96, 200, 201, 267, ++}; ++ ++static const unsigned short dep77[] = { ++ 40, 41, 96, 174, 200, 201, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep78[] = { ++ 17, 96, 203, 204, 267, ++}; ++ ++static const unsigned short dep79[] = { ++ 40, 41, 96, 174, 203, 204, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep80[] = { ++ 18, 96, 206, 207, 267, ++}; ++ ++static const unsigned short dep81[] = { ++ 40, 41, 96, 174, 206, 207, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep82[] = { ++ 15, 19, 20, 40, 41, 96, 156, 174, 175, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep83[] = { ++ 15, 16, 19, 20, 40, 41, 96, 156, 174, 175, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep84[] = { ++ 15, 17, 19, 20, 40, 41, 96, 156, 174, 175, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep85[] = { ++ 15, 18, 19, 20, 40, 41, 96, 156, 174, 175, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep86[] = { ++ 15, 96, 196, 197, 267, ++}; ++ ++static const unsigned short dep87[] = { ++ 11, 19, 20, 40, 41, 96, 174, 196, 198, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep88[] = { ++ 15, 16, 17, 18, 96, 196, 197, 199, 200, 202, 203, 205, 206, 267, ++}; ++ ++static const unsigned short dep89[] = { ++ 11, 12, 13, 14, 19, 20, 40, 41, 96, 174, 196, 198, 199, 201, 202, 204, 205, ++ 207, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep90[] = { ++ 16, 96, 199, 200, 267, ++}; ++ ++static const unsigned short dep91[] = { ++ 12, 19, 20, 40, 41, 96, 174, 199, 201, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep92[] = { ++ 17, 96, 202, 203, 267, ++}; ++ ++static const unsigned short dep93[] = { ++ 13, 19, 20, 40, 41, 96, 174, 202, 204, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep94[] = { ++ 18, 96, 205, 206, 267, ++}; ++ ++static const unsigned short dep95[] = { ++ 14, 19, 20, 40, 41, 96, 174, 205, 207, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep96[] = { ++ 15, 96, 196, 197, 267, 2165, 2166, 2167, 2169, 2170, 2172, 2173, 2329, 2332, ++ 2333, 2336, 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep97[] = { ++ 11, 19, 20, 40, 41, 96, 174, 196, 198, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2329, 2332, 2333, 2336, 2337, 2340, 2341, 4135, 16524, 16526, ++ ++}; ++ ++static const unsigned short dep98[] = { ++ 15, 16, 17, 18, 96, 196, 197, 199, 200, 202, 203, 205, 206, 267, 2165, 2166, ++ 2167, 2169, 2170, 2172, 2173, 2329, 2332, 2333, 2336, 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep99[] = { ++ 11, 12, 13, 14, 19, 20, 40, 41, 96, 174, 196, 198, 199, 201, 202, 204, 205, ++ 207, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2329, 2332, 2333, 2336, ++ 2337, 2340, 2341, 4135, 16524, 16526, ++}; ++ ++static const unsigned short dep100[] = { ++ 16, 96, 199, 200, 267, 2165, 2166, 2167, 2169, 2170, 2172, 2173, 2329, 2332, ++ 2333, 2336, 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep101[] = { ++ 12, 19, 20, 40, 41, 96, 174, 199, 201, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2329, 2332, 2333, 2336, 2337, 2340, 2341, 4135, 16524, 16526, ++ ++}; ++ ++static const unsigned short dep102[] = { ++ 17, 96, 202, 203, 267, 2165, 2166, 2167, 2169, 2170, 2172, 2173, 2329, 2332, ++ 2333, 2336, 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep103[] = { ++ 13, 19, 20, 40, 41, 96, 174, 202, 204, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2329, 2332, 2333, 2336, 2337, 2340, 2341, 4135, 16524, 16526, ++ ++}; ++ ++static const unsigned short dep104[] = { ++ 18, 96, 205, 206, 267, 2165, 2166, 2167, 2169, 2170, 2172, 2173, 2329, 2332, ++ 2333, 2336, 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep105[] = { ++ 14, 19, 20, 40, 41, 96, 174, 205, 207, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 2329, 2332, 2333, 2336, 2337, 2340, 2341, 4135, 16524, 16526, ++ ++}; ++ ++static const unsigned short dep106[] = { ++ 15, 96, 196, 197, 267, 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, ++ 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep107[] = { ++ 11, 19, 20, 40, 41, 96, 174, 196, 198, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 4135, 16524, 16526, 22809, 22812, 22813, 22816, 22817, 22820, ++ 22821, ++}; ++ ++static const unsigned short dep108[] = { ++ 15, 16, 17, 18, 96, 196, 197, 199, 200, 202, 203, 205, 206, 267, 22645, 22646, ++ 22647, 22649, 22650, 22652, 22653, 22809, 22812, 22813, 22816, 22817, 22820, ++ 22821, ++}; ++ ++static const unsigned short dep109[] = { ++ 11, 12, 13, 14, 19, 20, 40, 41, 96, 174, 196, 198, 199, 201, 202, 204, 205, ++ 207, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 4135, 16524, 16526, 22809, ++ 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep110[] = { ++ 16, 96, 199, 200, 267, 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, ++ 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep111[] = { ++ 12, 19, 20, 40, 41, 96, 174, 199, 201, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 4135, 16524, 16526, 22809, 22812, 22813, 22816, 22817, 22820, ++ 22821, ++}; ++ ++static const unsigned short dep112[] = { ++ 17, 96, 202, 203, 267, 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, ++ 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep113[] = { ++ 13, 19, 20, 40, 41, 96, 174, 202, 204, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 4135, 16524, 16526, 22809, 22812, 22813, 22816, 22817, 22820, ++ 22821, ++}; ++ ++static const unsigned short dep114[] = { ++ 18, 96, 205, 206, 267, 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, ++ 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep115[] = { ++ 14, 19, 20, 40, 41, 96, 174, 205, 207, 267, 2134, 2135, 2136, 2165, 2166, ++ 2169, 2172, 4135, 16524, 16526, 22809, 22812, 22813, 22816, 22817, 22820, ++ 22821, ++}; ++ ++static const unsigned short dep116[] = { ++ 96, 267, 2165, 2166, 2167, 2169, 2170, 2172, 2173, 2329, 2332, 2333, 2336, ++ 2337, 2340, 2341, ++}; ++ ++static const unsigned short dep117[] = { ++ 40, 41, 96, 174, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2329, 2332, ++ 2333, 2336, 2337, 2340, 2341, 4135, 16524, 16526, ++}; ++ ++static const unsigned short dep118[] = { ++ 96, 267, 22645, 22646, 22647, 22649, 22650, 22652, 22653, 22809, 22812, 22813, ++ 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep119[] = { ++ 40, 41, 96, 174, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 4135, 16524, ++ 16526, 22809, 22812, 22813, 22816, 22817, 22820, 22821, ++}; ++ ++static const unsigned short dep120[] = { ++ 19, 20, 40, 41, 96, 174, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2310, ++ 4135, 16524, 16526, 18746, 18748, 18749, 18751, ++}; ++ ++static const unsigned short dep121[] = { ++ 40, 41, 96, 156, 174, 175, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 4135, 20613, ++}; ++ ++static const unsigned short dep122[] = { ++ 96, 267, 2083, 2084, 2271, 2272, ++}; ++ ++static const unsigned short dep123[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2270, 2272, ++ 4135, 20613, ++}; ++ ++static const unsigned short dep124[] = { ++ 40, 41, 96, 174, 267, 2082, 2084, 2165, 2166, 2169, 2172, 2312, 4135, 20613, ++ ++}; ++ ++static const unsigned short dep125[] = { ++ 96, 267, 14454, 14456, 14457, 14459, 14460, 14462, 14620, 14621, 14624, 14625, ++ 14628, 14629, ++}; ++ ++static const unsigned short dep126[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 4135, 14620, 14621, 14624, 14625, ++ 14628, 14629, 20613, 24693, 24694, 24697, 24700, ++}; ++ ++static const unsigned short dep127[] = { ++ 96, 121, 123, 124, 126, 267, 288, 289, 292, 293, ++}; ++ ++static const unsigned short dep128[] = { ++ 40, 41, 96, 174, 267, 288, 289, 292, 293, 4135, 24693, 24694, 24697, 24700, ++ ++}; ++ ++static const unsigned short dep129[] = { ++ 40, 41, 96, 174, 267, 2165, 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep130[] = { ++ 40, 41, 96, 118, 121, 124, 174, 267, 2312, 4135, 20613, 24693, ++}; ++ ++static const unsigned short dep131[] = { ++ 6, 24, 26, 27, 96, 187, 213, 216, 267, 2081, 2269, ++}; ++ ++static const unsigned short dep132[] = { ++ 40, 41, 96, 174, 187, 213, 215, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 2269, 4135, 20613, ++}; ++ ++static const unsigned short dep133[] = { ++ 6, 24, 25, 26, 40, 41, 96, 174, 267, 2081, 2165, 2166, 2169, 2172, 2312, 4135, ++ 20613, ++}; ++ ++static const unsigned short dep134[] = { ++ 0, 40, 41, 96, 156, 174, 175, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep135[] = { ++ 0, 96, 181, 267, ++}; ++ ++static const unsigned short dep136[] = { ++ 0, 40, 41, 96, 156, 174, 175, 181, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep137[] = { ++ 40, 41, 96, 174, 181, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep138[] = { ++ 2, 28, 96, 183, 217, 267, 28852, 29002, ++}; ++ ++static const unsigned short dep139[] = { ++ 1, 2, 28, 29, 96, 168, 169, 174, 183, 217, 267, 28852, 29002, ++}; ++ ++static const unsigned short dep140[] = { ++ 1, 28, 29, 38, 40, 41, 96, 168, 169, 174, 183, 217, 267, 4135, 28852, 29002, ++ ++}; ++ ++static const unsigned short dep141[] = { ++ 0, 40, 41, 96, 174, 181, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep142[] = { ++ 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, ++ 28, 29, 30, 31, 96, 182, 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, ++ 194, 195, 197, 198, 200, 201, 203, 204, 206, 207, 208, 209, 210, 211, 217, ++ 218, 219, 267, 2071, 2081, 2260, 2269, 28852, 29002, ++}; ++ ++static const unsigned short dep143[] = { ++ 29, 40, 41, 96, 134, 174, 182, 183, 184, 185, 186, 188, 189, 190, 191, 192, ++ 193, 194, 195, 197, 198, 200, 201, 203, 204, 206, 207, 208, 209, 210, 211, ++ 217, 218, 219, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2260, 2269, ++ 4135, 20613, 28852, 29002, ++}; ++ ++static const unsigned short dep144[] = { ++ 96, 267, 14463, 14465, 14466, 14468, 14497, 14498, 14513, 14630, 14631, 14651, ++ 14652, 14654, 14655, 14664, ++}; ++ ++static const unsigned short dep145[] = { ++ 40, 41, 96, 173, 174, 267, 2165, 2166, 2169, 2172, 4135, 14630, 14631, 14651, ++ 14652, 14654, 14655, 14664, ++}; ++ ++static const unsigned short dep146[] = { ++ 14463, 14465, 14466, 14468, 14497, 14498, 14513, 14630, 14631, 14651, 14652, ++ 14654, 14655, 14664, ++}; ++ ++static const unsigned short dep147[] = { ++ 173, 14630, 14631, 14651, 14652, 14654, 14655, 14664, ++}; ++ ++static const unsigned short dep148[] = { ++ 96, 267, 14464, 14465, 14467, 14468, 14476, 14477, 14478, 14479, 14480, 14481, ++ 14482, 14483, 14485, 14488, 14489, 14497, 14498, 14499, 14500, 14501, 14506, ++ 14507, 14508, 14509, 14513, 14630, 14631, 14637, 14638, 14639, 14640, 14642, ++ 14644, 14651, 14652, 14654, 14655, 14656, 14657, 14660, 14661, 14664, ++}; ++ ++static const unsigned short dep149[] = { ++ 40, 41, 72, 96, 134, 174, 267, 2165, 2166, 2169, 2172, 4135, 14630, 14631, ++ 14637, 14638, 14639, 14640, 14642, 14644, 14651, 14652, 14654, 14655, 14656, ++ 14657, 14660, 14661, 14664, ++}; ++ ++static const unsigned short dep150[] = { ++ 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, ++ 28, 29, 30, 31, 40, 41, 96, 134, 171, 174, 267, 2071, 2081, 2165, 2166, 2169, ++ 2172, 2312, 4135, 20613, 28852, ++}; ++ ++static const unsigned short dep151[] = { ++ 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, ++ 64, 65, 67, 69, 70, 71, 72, 93, 95, 96, 228, 229, 230, 231, 232, 233, 234, ++ 235, 236, 237, 238, 240, 241, 242, 243, 244, 246, 248, 249, 250, 266, 267, ++ 2116, 2295, ++}; ++ ++static const unsigned short dep152[] = { ++ 40, 41, 95, 96, 134, 153, 174, 228, 229, 230, 231, 232, 233, 234, 235, 236, ++ 237, 238, 240, 241, 242, 243, 244, 246, 248, 249, 250, 266, 267, 2137, 2138, ++ 2139, 2165, 2166, 2169, 2172, 2295, 4135, 20613, ++}; ++ ++static const unsigned short dep153[] = { ++ 59, 94, 96, 239, 266, 267, 2139, 2312, ++}; ++ ++static const unsigned short dep154[] = { ++ 40, 41, 43, 44, 46, 48, 49, 51, 52, 53, 54, 56, 57, 60, 61, 63, 64, 65, 66, ++ 67, 69, 70, 71, 93, 94, 96, 134, 153, 174, 239, 266, 267, 2107, 2116, 2165, ++ 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep155[] = { ++ 2, 28, 41, 96, 183, 217, 226, 267, 2139, 2312, 28852, 29002, ++}; ++ ++static const unsigned short dep156[] = { ++ 2, 25, 26, 28, 29, 38, 40, 41, 96, 168, 169, 174, 183, 217, 226, 267, 2312, ++ 4135, 20613, 28852, 29002, ++}; ++ ++static const unsigned short dep157[] = { ++ 96, 128, 129, 131, 132, 136, 137, 140, 141, 142, 143, 144, 145, 146, 147, ++ 149, 152, 153, 157, 158, 161, 162, 163, 164, 165, 167, 168, 170, 171, 172, ++ 173, 175, 176, 177, 267, 294, 295, 299, 301, 302, 303, 304, 306, 308, 312, ++ 315, 316, 318, 319, 320, 321, 323, 324, 325, 327, 328, ++}; ++ ++static const unsigned short dep158[] = { ++ 40, 41, 72, 96, 134, 174, 267, 294, 295, 299, 301, 302, 303, 304, 306, 308, ++ 312, 315, 316, 318, 319, 320, 321, 323, 324, 325, 327, 328, 2137, 2138, 2139, ++ 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep159[] = { ++ 96, 127, 129, 130, 132, 161, 162, 177, 267, 294, 295, 315, 316, 318, 319, ++ 328, ++}; ++ ++static const unsigned short dep160[] = { ++ 40, 41, 96, 173, 174, 267, 294, 295, 315, 316, 318, 319, 328, 2137, 2138, ++ 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep161[] = { ++ 40, 41, 96, 129, 132, 134, 137, 138, 141, 143, 145, 147, 149, 150, 152, 156, ++ 157, 159, 160, 161, 162, 164, 165, 167, 169, 170, 172, 174, 176, 177, 267, ++ 2165, 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep162[] = { ++ 40, 41, 96, 129, 132, 161, 162, 174, 177, 267, 2165, 2166, 2169, 2172, 2312, ++ 4135, 20613, ++}; ++ ++static const unsigned short dep163[] = { ++ 40, 41, 75, 76, 81, 83, 96, 110, 134, 163, 174, 178, 267, 2137, 2138, 2139, ++ 2165, 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep164[] = { ++ 40, 41, 75, 76, 81, 83, 96, 110, 134, 135, 136, 138, 139, 163, 174, 178, 267, ++ 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep165[] = { ++ 76, 77, 96, 100, 101, 254, 255, 267, 269, 270, ++}; ++ ++static const unsigned short dep166[] = { ++ 40, 41, 47, 62, 77, 79, 85, 96, 98, 101, 134, 153, 174, 178, 254, 255, 267, ++ 269, 270, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep167[] = { ++ 40, 41, 47, 62, 77, 79, 96, 98, 101, 103, 105, 134, 153, 174, 178, 254, 255, ++ 267, 269, 270, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep168[] = { ++ 96, 267, 12466, 12467, 12617, ++}; ++ ++static const unsigned short dep169[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 12617, 20613, ++}; ++ ++static const unsigned short dep170[] = { ++ 96, 267, 6218, 6219, 6396, ++}; ++ ++static const unsigned short dep171[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 6396, 20613, ++}; ++ ++static const unsigned short dep172[] = { ++ 96, 267, 6236, 6409, ++}; ++ ++static const unsigned short dep173[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 6409, 20613, ++}; ++ ++static const unsigned short dep174[] = { ++ 96, 267, 6254, 6255, 6256, 6257, 6420, 6422, 8469, ++}; ++ ++static const unsigned short dep175[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 6257, 6421, 6422, 8303, 8468, 20613, ++}; ++ ++static const unsigned short dep176[] = { ++ 96, 267, 6258, 6259, 6423, ++}; ++ ++static const unsigned short dep177[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 6423, 20613, ++}; ++ ++static const unsigned short dep178[] = { ++ 96, 267, 6260, 6424, ++}; ++ ++static const unsigned short dep179[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 6424, 20613, ++}; ++ ++static const unsigned short dep180[] = { ++ 96, 267, 10349, 10515, ++}; ++ ++static const unsigned short dep181[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, ++ 10515, 20613, ++}; ++ ++static const unsigned short dep182[] = { ++ 76, 77, 81, 82, 96, 100, 101, 254, 255, 257, 258, 267, 269, 270, ++}; ++ ++static const unsigned short dep183[] = { ++ 40, 41, 47, 62, 77, 79, 82, 85, 96, 98, 101, 134, 153, 174, 178, 254, 255, ++ 257, 259, 267, 269, 270, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++ ++}; ++ ++static const unsigned short dep184[] = { ++ 76, 77, 96, 100, 101, 103, 104, 254, 255, 267, 269, 270, 271, 272, ++}; ++ ++static const unsigned short dep185[] = { ++ 40, 41, 47, 62, 77, 79, 96, 98, 101, 103, 105, 134, 153, 174, 178, 254, 255, ++ 267, 269, 270, 271, 272, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++ ++}; ++ ++static const unsigned short dep186[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 12467, 20613, ++}; ++ ++static const unsigned short dep187[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 6218, 20613, ++}; ++ ++static const unsigned short dep188[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 6236, 20613, ++}; ++ ++static const unsigned short dep189[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 6256, 8302, 20613, ++}; ++ ++static const unsigned short dep190[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 6258, 20613, ++}; ++ ++static const unsigned short dep191[] = { ++ 40, 41, 96, 134, 173, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 2312, 4135, 6259, 6260, 20613, ++}; ++ ++static const unsigned short dep192[] = { ++ 40, 41, 96, 134, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 10349, 20613, ++}; ++ ++static const unsigned short dep193[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, 4135, ++ 6186, 20613, ++}; ++ ++static const unsigned short dep194[] = { ++ 76, 78, 79, 96, 97, 98, 99, 253, 254, 267, 268, 269, ++}; ++ ++static const unsigned short dep195[] = { ++ 40, 41, 77, 78, 82, 84, 96, 99, 101, 103, 106, 134, 174, 178, 253, 255, 267, ++ 268, 270, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep196[] = { ++ 76, 78, 79, 80, 96, 97, 98, 99, 102, 253, 254, 256, 267, 268, 269, ++}; ++ ++static const unsigned short dep197[] = { ++ 40, 41, 77, 78, 80, 82, 84, 96, 99, 101, 102, 103, 106, 134, 174, 178, 253, ++ 255, 256, 267, 268, 270, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++ ++}; ++ ++static const unsigned short dep198[] = { ++ 76, 78, 79, 83, 84, 85, 96, 97, 98, 99, 253, 254, 259, 260, 267, 268, 269, ++ ++}; ++ ++static const unsigned short dep199[] = { ++ 40, 41, 77, 78, 82, 84, 96, 99, 101, 134, 174, 178, 253, 255, 258, 260, 267, ++ 268, 270, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep200[] = { ++ 76, 78, 79, 96, 97, 98, 99, 105, 106, 107, 253, 254, 267, 268, 269, 272, 273, ++ ++}; ++ ++static const unsigned short dep201[] = { ++ 40, 41, 77, 78, 96, 99, 101, 103, 106, 134, 174, 178, 253, 255, 267, 268, ++ 270, 271, 273, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep202[] = { ++ 40, 41, 46, 70, 96, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep203[] = { ++ 40, 41, 96, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 20613, ++}; ++ ++static const unsigned short dep204[] = { ++ 40, 41, 76, 81, 83, 96, 134, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, ++ 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep205[] = { ++ 40, 41, 96, 156, 174, 175, 267, 2134, 2135, 2136, 2137, 2138, 2139, 2165, ++ 2166, 2169, 2172, 4135, 16524, 16526, 20613, ++}; ++ ++static const unsigned short dep206[] = { ++ 40, 41, 76, 81, 83, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 4135, 20613, ++}; ++ ++static const unsigned short dep207[] = { ++ 40, 41, 77, 78, 96, 99, 134, 174, 253, 255, 267, 268, 270, 2137, 2138, 2139, ++ 2165, 2166, 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep208[] = { ++ 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2312, ++ 4135, 20613, ++}; ++ ++static const unsigned short dep209[] = { ++ 5, 96, 186, 267, 2139, 2312, ++}; ++ ++static const unsigned short dep210[] = { ++ 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 186, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep211[] = { ++ 40, 41, 44, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 148, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep212[] = { ++ 0, 96, 181, 267, 2139, 2312, ++}; ++ ++static const unsigned short dep213[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 163, 174, 178, 181, 267, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep214[] = { ++ 0, 40, 41, 44, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, ++ 136, 138, 139, 146, 148, 163, 174, 178, 181, 267, 2137, 2138, 2139, 2165, ++ 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep215[] = { ++ 31, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep216[] = { ++ 0, 96, 181, 267, 2312, 26714, ++}; ++ ++static const unsigned short dep217[] = { ++ 0, 96, 108, 181, 267, 274, ++}; ++ ++static const unsigned short dep218[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 181, 267, 274, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep219[] = { ++ 0, 5, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 163, 174, 178, 181, 267, 274, 2137, 2138, 2139, 2165, 2166, ++ 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep220[] = { ++ 0, 31, 96, 108, 181, 219, 267, 274, ++}; ++ ++static const unsigned short dep221[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 181, 219, 267, 274, 2137, 2138, 2139, 2165, 2166, ++ 2169, 2172, 4135, 20613, ++}; ++ ++static const unsigned short dep222[] = { ++ 0, 96, 108, 181, 267, 274, 2139, 2312, ++}; ++ ++static const unsigned short dep223[] = { ++ 0, 4, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, ++ 136, 138, 139, 146, 163, 174, 178, 181, 267, 274, 2137, 2138, 2139, 2165, ++ 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep224[] = { ++ 0, 4, 5, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, ++ 136, 138, 139, 146, 163, 174, 178, 181, 267, 274, 2137, 2138, 2139, 2165, ++ 2166, 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep225[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 163, 174, 178, 181, 267, 274, 2137, 2138, 2139, 2165, 2166, ++ 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep226[] = { ++ 40, 41, 96, 174, 267, 2134, 2135, 2136, 2165, 2166, 2169, 2172, 2312, 4135, ++ 16524, 16526, 20613, ++}; ++ ++static const unsigned short dep227[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 181, 267, 274, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep228[] = { ++ 0, 31, 96, 108, 181, 219, 267, 274, 2139, 2312, ++}; ++ ++static const unsigned short dep229[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 181, 219, 267, 274, 2137, 2138, 2139, 2165, 2166, ++ 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep230[] = { ++ 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2310, ++ 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep231[] = { ++ 40, 41, 44, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 148, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep232[] = { ++ 0, 96, 181, 267, 2135, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++}; ++ ++static const unsigned short dep233[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 163, 174, 178, 181, 267, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep234[] = { ++ 0, 40, 41, 44, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, ++ 136, 138, 139, 146, 148, 163, 174, 178, 181, 267, 2137, 2138, 2139, 2165, ++ 2166, 2169, 2172, 2310, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++ ++}; ++ ++static const unsigned short dep235[] = { ++ 0, 96, 181, 267, 2136, 2310, 18593, 18594, 18746, 18747, 18749, 18750, ++}; ++ ++static const unsigned short dep236[] = { ++ 96, 267, 2135, 2139, 2310, 2312, 18593, 18594, 18746, 18747, 18749, 18750, ++ ++}; ++ ++static const unsigned short dep237[] = { ++ 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2310, ++ 2312, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep238[] = { ++ 40, 41, 44, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 148, 163, 174, 178, 267, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2310, 2312, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep239[] = { ++ 0, 96, 181, 267, 2135, 2139, 2310, 2312, 18593, 18594, 18746, 18747, 18749, ++ 18750, ++}; ++ ++static const unsigned short dep240[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, 136, ++ 138, 139, 146, 163, 174, 178, 181, 267, 2137, 2138, 2139, 2165, 2166, 2169, ++ 2172, 2310, 2312, 4135, 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep241[] = { ++ 0, 40, 41, 44, 75, 76, 81, 83, 96, 108, 110, 127, 128, 130, 131, 134, 135, ++ 136, 138, 139, 146, 148, 163, 174, 178, 181, 267, 2137, 2138, 2139, 2165, ++ 2166, 2169, 2172, 2310, 2312, 4135, 16524, 16526, 18746, 18748, 18749, 18751, ++ 20613, ++}; ++ ++static const unsigned short dep242[] = { ++ 0, 96, 181, 267, 2136, 2139, 2310, 2312, 18593, 18594, 18746, 18747, 18749, ++ 18750, ++}; ++ ++static const unsigned short dep243[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 181, 267, 274, 2134, 2135, 2136, 2137, 2138, 2139, ++ 2165, 2166, 2169, 2172, 4135, 16524, 16526, 20613, ++}; ++ ++static const unsigned short dep244[] = { ++ 40, 41, 75, 96, 134, 148, 174, 267, 2165, 2166, 2169, 2172, 4135, ++}; ++ ++static const unsigned short dep245[] = { ++ 40, 41, 75, 96, 134, 135, 139, 148, 174, 267, 2165, 2166, 2169, 2172, 4135, ++ ++}; ++ ++static const unsigned short dep246[] = { ++ 40, 41, 75, 96, 134, 148, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, ++ 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep247[] = { ++ 40, 41, 75, 96, 134, 135, 139, 148, 174, 267, 2137, 2138, 2139, 2165, 2166, ++ 2169, 2172, 2312, 4135, 20613, ++}; ++ ++static const unsigned short dep248[] = { ++ 40, 41, 96, 174, 267, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2310, 4135, ++ 16524, 16526, 18746, 18748, 18749, 18751, 20613, ++}; ++ ++static const unsigned short dep249[] = { ++ 0, 40, 41, 75, 76, 81, 83, 96, 110, 127, 128, 130, 131, 134, 135, 136, 138, ++ 139, 146, 163, 174, 178, 181, 267, 274, 2134, 2135, 2136, 2137, 2138, 2139, ++ 2165, 2166, 2169, 2172, 2312, 4135, 16524, 16526, 20613, ++}; ++ ++static const unsigned short dep250[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ++ 22, 24, 26, 27, 28, 29, 30, 31, 96, 182, 183, 184, 185, 186, 187, 188, 189, ++ 190, 191, 192, 193, 194, 195, 197, 198, 200, 201, 203, 204, 206, 207, 208, ++ 209, 210, 211, 213, 216, 217, 218, 219, 267, 2071, 2081, 2139, 2260, 2269, ++ 2312, 28852, 29002, ++}; ++ ++static const unsigned short dep251[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ++ 22, 24, 25, 26, 28, 29, 30, 31, 40, 41, 96, 134, 171, 174, 182, 183, 184, ++ 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 197, 198, 200, 201, ++ 203, 204, 206, 207, 208, 209, 210, 211, 213, 215, 217, 218, 219, 267, 2071, ++ 2081, 2137, 2138, 2139, 2165, 2166, 2169, 2172, 2260, 2269, 2312, 4135, 20613, ++ 28852, 29002, ++}; ++ ++#define NELS(X) (sizeof(X)/sizeof(X[0])) ++static const struct ia64_opcode_dependency ++op_dependencies[] = { ++ { NELS(dep1), dep1, NELS(dep0), dep0, }, ++ { NELS(dep3), dep3, NELS(dep2), dep2, }, ++ { NELS(dep5), dep5, NELS(dep4), dep4, }, ++ { NELS(dep7), dep7, NELS(dep6), dep6, }, ++ { NELS(dep9), dep9, NELS(dep8), dep8, }, ++ { NELS(dep11), dep11, NELS(dep10), dep10, }, ++ { NELS(dep13), dep13, NELS(dep12), dep12, }, ++ { NELS(dep15), dep15, NELS(dep14), dep14, }, ++ { NELS(dep17), dep17, NELS(dep16), dep16, }, ++ { NELS(dep19), dep19, NELS(dep18), dep18, }, ++ { NELS(dep21), dep21, NELS(dep20), dep20, }, ++ { NELS(dep23), dep23, NELS(dep22), dep22, }, ++ { NELS(dep25), dep25, NELS(dep24), dep24, }, ++ { NELS(dep27), dep27, NELS(dep26), dep26, }, ++ { NELS(dep28), dep28, NELS(dep12), dep12, }, ++ { NELS(dep30), dep30, NELS(dep29), dep29, }, ++ { NELS(dep32), dep32, NELS(dep31), dep31, }, ++ { NELS(dep33), dep33, NELS(dep12), dep12, }, ++ { NELS(dep35), dep35, NELS(dep34), dep34, }, ++ { NELS(dep37), dep37, NELS(dep36), dep36, }, ++ { NELS(dep39), dep39, NELS(dep38), dep38, }, ++ { NELS(dep40), dep40, NELS(dep29), dep29, }, ++ { NELS(dep41), dep41, NELS(dep31), dep31, }, ++ { NELS(dep43), dep43, NELS(dep42), dep42, }, ++ { NELS(dep45), dep45, NELS(dep44), dep44, }, ++ { NELS(dep47), dep47, NELS(dep46), dep46, }, ++ { NELS(dep49), dep49, NELS(dep48), dep48, }, ++ { NELS(dep51), dep51, NELS(dep50), dep50, }, ++ { NELS(dep53), dep53, NELS(dep52), dep52, }, ++ { NELS(dep55), dep55, NELS(dep54), dep54, }, ++ { NELS(dep57), dep57, NELS(dep56), dep56, }, ++ { NELS(dep59), dep59, NELS(dep58), dep58, }, ++ { NELS(dep61), dep61, NELS(dep60), dep60, }, ++ { NELS(dep63), dep63, NELS(dep62), dep62, }, ++ { NELS(dep65), dep65, NELS(dep64), dep64, }, ++ { NELS(dep66), dep66, NELS(dep31), dep31, }, ++ { NELS(dep68), dep68, NELS(dep67), dep67, }, ++ { NELS(dep70), dep70, NELS(dep69), dep69, }, ++ { NELS(dep72), dep72, NELS(dep71), dep71, }, ++ { NELS(dep74), dep74, NELS(dep73), dep73, }, ++ { NELS(dep75), dep75, NELS(dep31), dep31, }, ++ { NELS(dep77), dep77, NELS(dep76), dep76, }, ++ { NELS(dep79), dep79, NELS(dep78), dep78, }, ++ { NELS(dep81), dep81, NELS(dep80), dep80, }, ++ { NELS(dep82), dep82, NELS(dep31), dep31, }, ++ { NELS(dep83), dep83, NELS(dep31), dep31, }, ++ { NELS(dep84), dep84, NELS(dep31), dep31, }, ++ { NELS(dep85), dep85, NELS(dep31), dep31, }, ++ { NELS(dep87), dep87, NELS(dep86), dep86, }, ++ { NELS(dep89), dep89, NELS(dep88), dep88, }, ++ { NELS(dep91), dep91, NELS(dep90), dep90, }, ++ { NELS(dep93), dep93, NELS(dep92), dep92, }, ++ { NELS(dep95), dep95, NELS(dep94), dep94, }, ++ { NELS(dep97), dep97, NELS(dep96), dep96, }, ++ { NELS(dep99), dep99, NELS(dep98), dep98, }, ++ { NELS(dep101), dep101, NELS(dep100), dep100, }, ++ { NELS(dep103), dep103, NELS(dep102), dep102, }, ++ { NELS(dep105), dep105, NELS(dep104), dep104, }, ++ { NELS(dep107), dep107, NELS(dep106), dep106, }, ++ { NELS(dep109), dep109, NELS(dep108), dep108, }, ++ { NELS(dep111), dep111, NELS(dep110), dep110, }, ++ { NELS(dep113), dep113, NELS(dep112), dep112, }, ++ { NELS(dep115), dep115, NELS(dep114), dep114, }, ++ { NELS(dep117), dep117, NELS(dep116), dep116, }, ++ { NELS(dep119), dep119, NELS(dep118), dep118, }, ++ { NELS(dep120), dep120, NELS(dep62), dep62, }, ++ { NELS(dep121), dep121, NELS(dep31), dep31, }, ++ { NELS(dep123), dep123, NELS(dep122), dep122, }, ++ { NELS(dep124), dep124, NELS(dep0), dep0, }, ++ { NELS(dep126), dep126, NELS(dep125), dep125, }, ++ { NELS(dep128), dep128, NELS(dep127), dep127, }, ++ { NELS(dep129), dep129, NELS(dep0), dep0, }, ++ { NELS(dep130), dep130, NELS(dep0), dep0, }, ++ { NELS(dep132), dep132, NELS(dep131), dep131, }, ++ { NELS(dep133), dep133, NELS(dep0), dep0, }, ++ { NELS(dep134), dep134, NELS(dep31), dep31, }, ++ { NELS(dep136), dep136, NELS(dep135), dep135, }, ++ { NELS(dep137), dep137, NELS(dep135), dep135, }, ++ { NELS(dep139), dep139, NELS(dep138), dep138, }, ++ { NELS(dep140), dep140, NELS(dep138), dep138, }, ++ { NELS(dep141), dep141, NELS(dep135), dep135, }, ++ { NELS(dep143), dep143, NELS(dep142), dep142, }, ++ { NELS(dep145), dep145, NELS(dep144), dep144, }, ++ { NELS(dep147), dep147, NELS(dep146), dep146, }, ++ { NELS(dep149), dep149, NELS(dep148), dep148, }, ++ { NELS(dep150), dep150, NELS(dep0), dep0, }, ++ { NELS(dep152), dep152, NELS(dep151), dep151, }, ++ { NELS(dep154), dep154, NELS(dep153), dep153, }, ++ { NELS(dep156), dep156, NELS(dep155), dep155, }, ++ { NELS(dep158), dep158, NELS(dep157), dep157, }, ++ { NELS(dep160), dep160, NELS(dep159), dep159, }, ++ { NELS(dep161), dep161, NELS(dep0), dep0, }, ++ { NELS(dep162), dep162, NELS(dep0), dep0, }, ++ { NELS(dep163), dep163, NELS(dep0), dep0, }, ++ { NELS(dep164), dep164, NELS(dep31), dep31, }, ++ { NELS(dep166), dep166, NELS(dep165), dep165, }, ++ { NELS(dep167), dep167, NELS(dep165), dep165, }, ++ { NELS(dep169), dep169, NELS(dep168), dep168, }, ++ { NELS(dep171), dep171, NELS(dep170), dep170, }, ++ { NELS(dep173), dep173, NELS(dep172), dep172, }, ++ { NELS(dep175), dep175, NELS(dep174), dep174, }, ++ { NELS(dep177), dep177, NELS(dep176), dep176, }, ++ { NELS(dep179), dep179, NELS(dep178), dep178, }, ++ { NELS(dep181), dep181, NELS(dep180), dep180, }, ++ { NELS(dep183), dep183, NELS(dep182), dep182, }, ++ { NELS(dep185), dep185, NELS(dep184), dep184, }, ++ { NELS(dep186), dep186, NELS(dep0), dep0, }, ++ { NELS(dep187), dep187, NELS(dep0), dep0, }, ++ { NELS(dep188), dep188, NELS(dep0), dep0, }, ++ { NELS(dep189), dep189, NELS(dep0), dep0, }, ++ { NELS(dep190), dep190, NELS(dep0), dep0, }, ++ { NELS(dep191), dep191, NELS(dep0), dep0, }, ++ { NELS(dep192), dep192, NELS(dep0), dep0, }, ++ { NELS(dep193), dep193, NELS(dep0), dep0, }, ++ { NELS(dep195), dep195, NELS(dep194), dep194, }, ++ { NELS(dep197), dep197, NELS(dep196), dep196, }, ++ { NELS(dep199), dep199, NELS(dep198), dep198, }, ++ { NELS(dep201), dep201, NELS(dep200), dep200, }, ++ { NELS(dep202), dep202, NELS(dep0), dep0, }, ++ { NELS(dep203), dep203, NELS(dep0), dep0, }, ++ { NELS(dep204), dep204, NELS(dep0), dep0, }, ++ { NELS(dep205), dep205, NELS(dep31), dep31, }, ++ { NELS(dep206), dep206, NELS(dep31), dep31, }, ++ { NELS(dep207), dep207, NELS(dep194), dep194, }, ++ { NELS(dep208), dep208, NELS(dep0), dep0, }, ++ { NELS(dep210), dep210, NELS(dep209), dep209, }, ++ { NELS(dep211), dep211, NELS(dep0), dep0, }, ++ { NELS(dep213), dep213, NELS(dep212), dep212, }, ++ { NELS(dep214), dep214, NELS(dep212), dep212, }, ++ { NELS(dep215), dep215, NELS(dep0), dep0, }, ++ { NELS(dep213), dep213, NELS(dep216), dep216, }, ++ { NELS(dep218), dep218, NELS(dep217), dep217, }, ++ { NELS(dep219), dep219, NELS(dep217), dep217, }, ++ { NELS(dep221), dep221, NELS(dep220), dep220, }, ++ { NELS(dep223), dep223, NELS(dep222), dep222, }, ++ { NELS(dep224), dep224, NELS(dep222), dep222, }, ++ { NELS(dep225), dep225, NELS(dep222), dep222, }, ++ { NELS(dep226), dep226, NELS(dep0), dep0, }, ++ { NELS(dep227), dep227, NELS(dep222), dep222, }, ++ { NELS(dep229), dep229, NELS(dep228), dep228, }, ++ { NELS(dep230), dep230, NELS(dep62), dep62, }, ++ { NELS(dep231), dep231, NELS(dep62), dep62, }, ++ { NELS(dep233), dep233, NELS(dep232), dep232, }, ++ { NELS(dep234), dep234, NELS(dep232), dep232, }, ++ { NELS(dep233), dep233, NELS(dep235), dep235, }, ++ { NELS(dep237), dep237, NELS(dep236), dep236, }, ++ { NELS(dep238), dep238, NELS(dep236), dep236, }, ++ { NELS(dep240), dep240, NELS(dep239), dep239, }, ++ { NELS(dep241), dep241, NELS(dep239), dep239, }, ++ { NELS(dep240), dep240, NELS(dep242), dep242, }, ++ { NELS(dep243), dep243, NELS(dep217), dep217, }, ++ { NELS(dep244), dep244, NELS(dep31), dep31, }, ++ { NELS(dep245), dep245, NELS(dep31), dep31, }, ++ { NELS(dep246), dep246, NELS(dep0), dep0, }, ++ { NELS(dep247), dep247, NELS(dep0), dep0, }, ++ { NELS(dep248), dep248, NELS(dep62), dep62, }, ++ { NELS(dep249), dep249, NELS(dep222), dep222, }, ++ { 0, NULL, 0, NULL, }, ++ { NELS(dep251), dep251, NELS(dep250), dep250, }, ++}; ++ ++static const struct ia64_completer_table ++completer_table[] = { ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 88 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 88 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 576, -1, 0, 1, 6 }, ++ { 0x0, 0x0, 0, 639, -1, 0, 1, 17 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 157 }, ++ { 0x0, 0x0, 0, 738, -1, 0, 1, 17 }, ++ { 0x0, 0x0, 0, 2164, -1, 0, 1, 10 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 9 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 13 }, ++ { 0x1, 0x1, 0, -1, -1, 13, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, 2372, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, 1122, -1, 0, 1, 122 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 44 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 78 }, ++ { 0x0, 0x0, 0, 2212, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 2439, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 2216, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, 2218, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 2448, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 2451, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 2473, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 2476, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 24 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 24 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 24 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 24 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 35 }, ++ { 0x0, 0x0, 0, 2484, -1, 0, 1, 29 }, ++ { 0x0, 0x0, 0, 1391, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 157 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 77 }, ++ { 0x0, 0x0, 0, 1439, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1448, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1457, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1459, -1, 0, 1, 125 }, ++ { 0x0, 0x0, 0, 1461, -1, 0, 1, 125 }, ++ { 0x0, 0x0, 0, 1470, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1479, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1488, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1497, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1506, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1515, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1525, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1535, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1545, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 0, 1554, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1560, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1566, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1572, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1578, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1584, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1590, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1596, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1602, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1608, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1614, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1620, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1626, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1632, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1638, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1644, -1, 0, 1, 140 }, ++ { 0x0, 0x0, 0, 1650, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1656, -1, 0, 1, 145 }, ++ { 0x0, 0x0, 0, 1660, -1, 0, 1, 151 }, ++ { 0x0, 0x0, 0, 1664, -1, 0, 1, 153 }, ++ { 0x0, 0x0, 0, 1668, -1, 0, 1, 153 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 79 }, ++ { 0x0, 0x0, 0, 256, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 67 }, ++ { 0x1, 0x1, 0, 1148, -1, 20, 1, 67 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 68 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 69 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 69 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 70 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 71 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 72 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 86 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 87 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 89 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 90 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 91 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 92 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 97 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 98 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 99 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 100 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 101 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 102 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 103 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 106 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 107 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 108 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 109 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 110 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 111 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 112 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 113 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 158 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 158 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 158 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 71 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 157 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2824, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2825, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2176, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2177, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2839, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2840, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2841, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2842, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2843, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2826, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, 2827, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 11 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 84 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 83 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x1, 0x1, 0, -1, -1, 13, 1, 0 }, ++ { 0x0, 0x0, 0, 2845, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 84 }, ++ { 0x0, 0x0, 0, 1948, -1, 0, 1, 131 }, ++ { 0x0, 0x0, 0, 1950, -1, 0, 1, 138 }, ++ { 0x0, 0x0, 0, 1952, -1, 0, 1, 132 }, ++ { 0x0, 0x0, 0, 1954, -1, 0, 1, 132 }, ++ { 0x0, 0x0, 0, 1956, -1, 0, 1, 131 }, ++ { 0x0, 0x0, 0, 1958, -1, 0, 1, 138 }, ++ { 0x0, 0x0, 0, 1960, -1, 0, 1, 131 }, ++ { 0x0, 0x0, 0, 1962, -1, 0, 1, 138 }, ++ { 0x0, 0x0, 0, 1965, -1, 0, 1, 131 }, ++ { 0x0, 0x0, 0, 1968, -1, 0, 1, 138 }, ++ { 0x0, 0x0, 0, 1971, -1, 0, 1, 150 }, ++ { 0x0, 0x0, 0, 1972, -1, 0, 1, 156 }, ++ { 0x0, 0x0, 0, 1973, -1, 0, 1, 150 }, ++ { 0x0, 0x0, 0, 1974, -1, 0, 1, 156 }, ++ { 0x0, 0x0, 0, 1975, -1, 0, 1, 150 }, ++ { 0x0, 0x0, 0, 1976, -1, 0, 1, 156 }, ++ { 0x0, 0x0, 0, 1977, -1, 0, 1, 150 }, ++ { 0x0, 0x0, 0, 1978, -1, 0, 1, 156 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 82 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 120 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 118 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 120 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 119 }, ++ { 0x0, 0x0, 0, 1669, -1, 0, 1, 136 }, ++ { 0x0, 0x0, 0, 1670, -1, 0, 1, 136 }, ++ { 0x0, 0x0, 0, 1671, -1, 0, 1, 136 }, ++ { 0x0, 0x0, 0, 1672, -1, 0, 1, 136 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 0, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 1, 223, -1, 0, 1, 12 }, ++ { 0x1, 0x1, 2, -1, -1, 27, 1, 12 }, ++ { 0x0, 0x0, 3, -1, 1322, 0, 0, -1 }, ++ { 0x0, 0x0, 3, -1, 1323, 0, 0, -1 }, ++ { 0x1, 0x1, 3, 2715, 1432, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2716, 1441, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2717, 1450, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2718, 1463, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2719, 1472, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2720, 1481, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2721, 1490, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2722, 1499, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2723, 1508, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2724, 1517, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2725, 1527, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2726, 1537, 33, 1, 127 }, ++ { 0x1, 0x1, 3, 2727, 1550, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2728, 1556, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2729, 1562, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2730, 1568, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2731, 1574, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2732, 1580, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2733, 1586, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2734, 1592, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2735, 1598, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2736, 1604, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2737, 1610, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2738, 1616, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2739, 1622, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2740, 1628, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2741, 1634, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2742, 1640, 33, 1, 142 }, ++ { 0x1, 0x1, 3, 2743, 1646, 33, 1, 147 }, ++ { 0x1, 0x1, 3, 2744, 1652, 33, 1, 147 }, ++ { 0x1, 0x1, 3, -1, -1, 27, 1, 40 }, ++ { 0x0, 0x0, 4, 2178, 1407, 0, 1, 135 }, ++ { 0x0, 0x0, 4, 2179, 1409, 0, 1, 135 }, ++ { 0x0, 0x0, 4, 2180, 1411, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2181, 1413, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2182, 1415, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2183, 1417, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2184, 1419, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2185, 1421, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2186, 1423, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2187, 1425, 0, 1, 134 }, ++ { 0x0, 0x0, 4, 2188, 1427, 0, 1, 136 }, ++ { 0x0, 0x0, 4, 2189, 1429, 0, 1, 136 }, ++ { 0x1, 0x1, 4, -1, 1436, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 534, 1435, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1445, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 535, 1444, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1454, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 536, 1453, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1458, 32, 1, 125 }, ++ { 0x1, 0x1, 4, -1, 1460, 32, 1, 125 }, ++ { 0x1, 0x1, 4, -1, 1467, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 537, 1466, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1476, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 538, 1475, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1485, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 539, 1484, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1494, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 540, 1493, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1503, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 541, 1502, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1512, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 542, 1511, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1522, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 1018, 1520, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1532, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 1019, 1530, 32, 1, 124 }, ++ { 0x1, 0x1, 4, -1, 1542, 33, 1, 130 }, ++ { 0x5, 0x5, 4, 1020, 1540, 32, 1, 124 }, ++ { 0x1, 0x21, 10, 1991, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 1992, -1, 12, 1, 3 }, ++ { 0x1, 0x21, 10, 410, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2048, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, -1, 2049, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2050, 0, 0, -1 }, ++ { 0x0, 0x0, 10, 1995, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 1996, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 1997, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 1998, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, 420, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2054, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 424, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2056, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, 428, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2058, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 432, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2060, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, 436, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2062, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 440, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2064, -1, 12, 1, 3 }, ++ { 0x1, 0x21, 10, 2011, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2012, -1, 12, 1, 3 }, ++ { 0x1, 0x21, 10, 450, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2070, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, -1, 2071, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2072, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2075, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2076, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2077, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2078, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2079, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2080, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2081, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2082, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2083, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2084, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2085, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2086, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2087, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2088, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2089, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2090, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2091, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2092, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2093, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2094, 0, 0, -1 }, ++ { 0x1, 0x21, 10, 2015, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2016, -1, 12, 1, 3 }, ++ { 0x1, 0x21, 10, 458, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2096, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, -1, 2097, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2098, 0, 0, -1 }, ++ { 0x0, 0x0, 10, 2019, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2020, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 2021, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2022, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, 468, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2102, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 472, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2104, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, 476, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2106, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 480, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2108, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, 484, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 10, 2110, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 488, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2112, -1, 12, 1, 3 }, ++ { 0x1, 0x21, 10, 2035, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2036, -1, 12, 1, 3 }, ++ { 0x1, 0x21, 10, 498, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 10, 2118, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, -1, 2119, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2120, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2123, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2124, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2125, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2126, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2127, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2128, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2129, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2130, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2131, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2132, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2133, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2134, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2135, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2136, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2137, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2138, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2139, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2140, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2141, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2142, 0, 0, -1 }, ++ { 0x1, 0x1, 10, 2039, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 10, 2040, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 2041, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 10, 2042, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, -1, 2143, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2145, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2147, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2149, 0, 0, -1 }, ++ { 0x1, 0x1, 10, 2043, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 10, 2044, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 10, 2045, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 10, 2046, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 10, -1, 2151, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2153, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2155, 0, 0, -1 }, ++ { 0x0, 0x0, 10, -1, 2157, 0, 0, -1 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x4200001, 11, 1993, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 298, -1, 33, 1, 3 }, ++ { 0x0, 0x0, 11, 2051, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 11, 2052, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 1999, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x0, 0x0, 11, 306, -1, 0, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x200001, 11, 2001, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 308, -1, 33, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 2003, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x0, 0x0, 11, 310, -1, 0, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x200001, 11, 2005, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 312, -1, 33, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 2007, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x0, 0x0, 11, 314, -1, 0, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x200001, 11, 2009, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 316, -1, 33, 1, 3 }, ++ { 0x0, 0x0, 11, 2065, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 11, 2066, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 11, 2067, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 11, 2068, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x4200001, 11, 2013, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 320, -1, 33, 1, 3 }, ++ { 0x0, 0x0, 11, 2073, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 11, 2074, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x4200001, 11, 2017, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 346, -1, 33, 1, 3 }, ++ { 0x0, 0x0, 11, 2099, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 11, 2100, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 2023, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x0, 0x0, 11, 354, -1, 0, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x200001, 11, 2025, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 356, -1, 33, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 2027, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x0, 0x0, 11, 358, -1, 0, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x200001, 11, 2029, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 360, -1, 33, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 2031, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x0, 0x0, 11, 362, -1, 0, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x200001, 11, 2033, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 364, -1, 33, 1, 3 }, ++ { 0x0, 0x0, 11, 2113, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 11, 2114, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 11, 2115, -1, 33, 1, 3 }, ++ { 0x200001, 0x200001, 11, 2116, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x200001, 0x4200001, 11, 2037, -1, 12, 1, 3 }, ++ { 0x2, 0x3, 11, -1, -1, 37, 1, 5 }, ++ { 0x1, 0x1, 11, 368, -1, 33, 1, 3 }, ++ { 0x0, 0x0, 11, 2121, -1, 0, 1, 3 }, ++ { 0x1, 0x1, 11, 2122, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, 2144, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 11, 2146, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 11, 2148, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 11, 2150, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, -1, -1, 36, 1, 5 }, ++ { 0x1, 0x1, 11, 2152, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 11, 2154, -1, 12, 1, 3 }, ++ { 0x1, 0x1, 11, 2156, -1, 36, 1, 3 }, ++ { 0x1000001, 0x1000001, 11, 2158, -1, 12, 1, 3 }, ++ { 0x0, 0x0, 12, -1, -1, 0, 1, 14 }, ++ { 0x0, 0x0, 12, -1, -1, 0, 1, 14 }, ++ { 0x0, 0x0, 12, -1, -1, 0, 1, 14 }, ++ { 0x1, 0x1, 13, 270, 1434, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 272, 1443, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 274, 1452, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 278, 1465, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 280, 1474, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 282, 1483, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 284, 1492, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 286, 1501, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 288, 1510, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 290, 1519, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 292, 1529, 34, 1, 124 }, ++ { 0x1, 0x1, 13, 294, 1539, 34, 1, 124 }, ++ { 0x0, 0x0, 19, -1, 777, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 778, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 779, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 780, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 781, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 782, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 783, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 784, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 785, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 786, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 787, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 788, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 789, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 790, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 791, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 792, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 793, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 794, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 795, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 796, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 797, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 798, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 799, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 800, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 801, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 802, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 803, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 804, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 805, 0, 0, -1 }, ++ { 0x0, 0x0, 19, -1, 806, 0, 0, -1 }, ++ { 0x0, 0x0, 20, -1, 2793, 0, 0, -1 }, ++ { 0x0, 0x0, 20, -1, 2794, 0, 0, -1 }, ++ { 0x0, 0x0, 20, -1, 2809, 0, 0, -1 }, ++ { 0x0, 0x0, 20, -1, 2810, 0, 0, -1 }, ++ { 0x0, 0x0, 20, -1, 2815, 0, 0, -1 }, ++ { 0x0, 0x0, 20, -1, 2816, 0, 0, -1 }, ++ { 0x0, 0x0, 21, 813, 2805, 0, 0, -1 }, ++ { 0x0, 0x0, 21, 814, 2807, 0, 0, -1 }, ++ { 0x0, 0x0, 23, -1, 2803, 0, 0, -1 }, ++ { 0x0, 0x0, 23, -1, 2804, 0, 0, -1 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, 1254, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 6 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 7 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 8 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 15 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, 1275, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 18 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 19 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 20 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, 1308, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 17 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 35, 1, 21 }, ++ { 0x1, 0x1, 24, -1, -1, 33, 1, 76 }, ++ { 0x1, 0x1, 24, -1, -1, 33, 1, 76 }, ++ { 0x1, 0x1, 24, 1324, 1437, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1325, 1446, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1326, 1455, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1327, 1468, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1328, 1477, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1329, 1486, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1330, 1495, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1331, 1504, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1332, 1513, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1333, 1523, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1334, 1533, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1335, 1543, 35, 1, 130 }, ++ { 0x1, 0x1, 24, 1336, 1552, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1337, 1558, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1338, 1564, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1339, 1570, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1340, 1576, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1341, 1582, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1342, 1588, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1343, 1594, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1344, 1600, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1345, 1606, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1346, 1612, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1347, 1618, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1348, 1624, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1349, 1630, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1350, 1636, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1351, 1642, 35, 1, 144 }, ++ { 0x1, 0x1, 24, 1352, 1648, 35, 1, 149 }, ++ { 0x1, 0x1, 24, 1353, 1654, 35, 1, 149 }, ++ { 0x0, 0x0, 33, 2787, 2785, 0, 0, -1 }, ++ { 0x0, 0x0, 33, 2790, 2788, 0, 0, -1 }, ++ { 0x0, 0x0, 33, 2796, 2795, 0, 0, -1 }, ++ { 0x0, 0x0, 33, 2798, 2797, 0, 0, -1 }, ++ { 0x0, 0x0, 33, 2812, 2811, 0, 0, -1 }, ++ { 0x0, 0x0, 33, 2814, 2813, 0, 0, -1 }, ++ { 0x0, 0x0, 35, -1, 2806, 0, 0, -1 }, ++ { 0x0, 0x0, 35, -1, 2808, 0, 0, -1 }, ++ { 0x1, 0x1, 38, -1, 2256, 37, 1, 29 }, ++ { 0x1, 0x1, 38, -1, 2315, 37, 1, 29 }, ++ { 0x0, 0x0, 38, -1, 2318, 0, 0, -1 }, ++ { 0x1, 0x1, 38, -1, -1, 37, 1, 29 }, ++ { 0x1, 0x1, 38, -1, 2323, 37, 1, 29 }, ++ { 0x0, 0x0, 38, -1, 2326, 0, 0, -1 }, ++ { 0x1, 0x1, 38, -1, -1, 37, 1, 29 }, ++ { 0x0, 0x0, 38, -1, 2329, 0, 0, -1 }, ++ { 0x1, 0x1, 38, -1, -1, 37, 1, 29 }, ++ { 0x1, 0x1, 38, -1, 2332, 37, 1, 29 }, ++ { 0x1, 0x1, 38, -1, 2335, 37, 1, 29 }, ++ { 0x1, 0x1, 38, -1, 2368, 37, 1, 29 }, ++ { 0x3, 0x3, 38, -1, -1, 30, 1, 137 }, ++ { 0x0, 0x0, 38, 1124, -1, 0, 1, 95 }, ++ { 0x0, 0x0, 38, -1, -1, 0, 1, 104 }, ++ { 0x0, 0x0, 38, 1130, -1, 0, 1, 116 }, ++ { 0x3, 0x3, 38, -1, -1, 30, 1, 155 }, ++ { 0x0, 0x0, 38, 1131, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 40, -1, 955, 0, 0, -1 }, ++ { 0x0, 0x0, 40, -1, 963, 0, 0, -1 }, ++ { 0x0, 0x0, 40, 1133, 959, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 604, 33, 1, 6 }, ++ { 0x18000001, 0x18000001, 40, -1, 612, 6, 1, 7 }, ++ { 0x3, 0x3, 40, 1134, 608, 33, 1, 6 }, ++ { 0x0, 0x0, 40, -1, 967, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 624, 33, 1, 8 }, ++ { 0x0, 0x0, 40, -1, 971, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 636, 33, 1, 15 }, ++ { 0x0, 0x0, 40, -1, 976, 0, 0, -1 }, ++ { 0x0, 0x0, 40, -1, 980, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 659, 33, 1, 17 }, ++ { 0x3, 0x3, 40, -1, 663, 33, 1, 17 }, ++ { 0x0, 0x0, 40, -1, 984, 0, 0, -1 }, ++ { 0x0, 0x0, 40, -1, 988, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 683, 33, 1, 18 }, ++ { 0x18000001, 0x18000001, 40, -1, 687, 6, 1, 18 }, ++ { 0x0, 0x0, 40, -1, 992, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 699, 33, 1, 19 }, ++ { 0x0, 0x0, 40, -1, 996, 0, 0, -1 }, ++ { 0x0, 0x0, 40, -1, 1000, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 719, 33, 1, 20 }, ++ { 0x18000001, 0x18000001, 40, -1, 723, 6, 1, 20 }, ++ { 0x0, 0x0, 40, -1, 1004, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 735, 33, 1, 21 }, ++ { 0x0, 0x0, 40, -1, 1009, 0, 0, -1 }, ++ { 0x0, 0x0, 40, -1, 1013, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 758, 33, 1, 17 }, ++ { 0x3, 0x3, 40, -1, 762, 33, 1, 17 }, ++ { 0x0, 0x0, 40, -1, 1017, 0, 0, -1 }, ++ { 0x3, 0x3, 40, -1, 774, 33, 1, 21 }, ++ { 0x0, 0x0, 41, 833, 954, 0, 0, -1 }, ++ { 0x0, 0x0, 41, 834, 962, 0, 0, -1 }, ++ { 0x0, 0x0, 41, 835, 958, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 836, 603, 34, 1, 6 }, ++ { 0x10000001, 0x10000001, 41, 837, 611, 6, 1, 7 }, ++ { 0x1, 0x1, 41, 838, 607, 34, 1, 6 }, ++ { 0x0, 0x0, 41, 839, 966, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 840, 623, 34, 1, 8 }, ++ { 0x0, 0x0, 41, 841, 970, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 842, 635, 34, 1, 15 }, ++ { 0x0, 0x0, 41, 843, 975, 0, 0, -1 }, ++ { 0x0, 0x0, 41, 844, 979, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 845, 658, 34, 1, 17 }, ++ { 0x1, 0x1, 41, 846, 662, 34, 1, 17 }, ++ { 0x0, 0x0, 41, 847, 983, 0, 0, -1 }, ++ { 0x0, 0x0, 41, 848, 987, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 849, 682, 34, 1, 18 }, ++ { 0x10000001, 0x10000001, 41, 850, 686, 6, 1, 18 }, ++ { 0x0, 0x0, 41, 851, 991, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 852, 698, 34, 1, 19 }, ++ { 0x0, 0x0, 41, 853, 995, 0, 0, -1 }, ++ { 0x0, 0x0, 41, 854, 999, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 855, 718, 34, 1, 20 }, ++ { 0x10000001, 0x10000001, 41, 856, 722, 6, 1, 20 }, ++ { 0x0, 0x0, 41, 857, 1003, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 858, 734, 34, 1, 21 }, ++ { 0x0, 0x0, 41, 859, 1008, 0, 0, -1 }, ++ { 0x0, 0x0, 41, 860, 1012, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 861, 757, 34, 1, 17 }, ++ { 0x1, 0x1, 41, 862, 761, 34, 1, 17 }, ++ { 0x0, 0x0, 41, 863, 1016, 0, 0, -1 }, ++ { 0x1, 0x1, 41, 864, 773, 34, 1, 21 }, ++ { 0x800001, 0x800001, 41, -1, 1138, 4, 1, 16 }, ++ { 0x1, 0x1, 41, 2202, 1136, 4, 1, 16 }, ++ { 0x1, 0x1, 41, 939, 1141, 4, 1, 22 }, ++ { 0x2, 0x3, 41, -1, 1146, 20, 1, 67 }, ++ { 0x1, 0x1, 41, 2203, 1144, 21, 1, 67 }, ++ { 0x0, 0x0, 42, -1, -1, 0, 1, 80 }, ++ { 0x0, 0x0, 42, -1, -1, 0, 1, 80 }, ++ { 0x0, 0x0, 42, -1, -1, 0, 1, 123 }, ++ { 0x1, 0x1, 44, 1354, 295, 38, 1, 1 }, ++ { 0x1, 0x1, 44, 1355, 297, 38, 1, 1 }, ++ { 0x0, 0x0, 44, -1, 300, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 414, 0, 0, -1 }, ++ { 0x1, 0x1, 44, 1359, 317, 38, 1, 1 }, ++ { 0x1, 0x1, 44, 1360, 319, 38, 1, 1 }, ++ { 0x0, 0x0, 44, -1, 322, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 454, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 324, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 342, 0, 0, -1 }, ++ { 0x1, 0x1, 44, 1366, 343, 38, 1, 1 }, ++ { 0x1, 0x1, 44, 1367, 345, 38, 1, 1 }, ++ { 0x0, 0x0, 44, -1, 348, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 462, 0, 0, -1 }, ++ { 0x1, 0x1, 44, 1371, 365, 38, 1, 1 }, ++ { 0x1, 0x1, 44, 1372, 367, 38, 1, 1 }, ++ { 0x0, 0x0, 44, -1, 370, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 502, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 372, 0, 0, -1 }, ++ { 0x0, 0x0, 44, -1, 390, 0, 0, -1 }, ++ { 0x0, 0x0, 44, 1230, 2263, 0, 0, -1 }, ++ { 0x0, 0x0, 44, 1231, 2271, 0, 1, 54 }, ++ { 0x0, 0x0, 44, 1232, 2938, 0, 1, 54 }, ++ { 0x0, 0x0, 44, 1233, 2339, 0, 0, -1 }, ++ { 0x0, 0x0, 44, 1234, -1, 0, 1, 49 }, ++ { 0x0, 0x0, 44, 1102, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 44, 1103, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 44, 1104, -1, 0, 1, 0 }, ++ { 0x1, 0x1, 45, -1, 1658, 30, 1, 152 }, ++ { 0x1, 0x1, 45, 945, 1657, 30, 1, 151 }, ++ { 0x1, 0x1, 45, -1, 1662, 30, 1, 154 }, ++ { 0x1, 0x1, 45, 946, 1661, 30, 1, 153 }, ++ { 0x1, 0x1, 45, -1, 1666, 30, 1, 154 }, ++ { 0x1, 0x1, 45, 947, 1665, 30, 1, 153 }, ++ { 0x3, 0x3, 46, -1, 1142, 3, 1, 22 }, ++ { 0x1, 0x1, 47, 2223, -1, 30, 1, 137 }, ++ { 0x1, 0x1, 47, 2254, -1, 30, 1, 155 }, ++ { 0x0, 0x0, 49, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 49, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 49, -1, -1, 0, 1, 40 }, ++ { 0x1, 0x1, 56, -1, 1659, 31, 1, 152 }, ++ { 0x1, 0x1, 56, -1, 1663, 31, 1, 154 }, ++ { 0x1, 0x1, 56, -1, 1667, 31, 1, 154 }, ++ { 0x0, 0x0, 56, -1, -1, 0, 1, 94 }, ++ { 0x2, 0x3, 56, -1, -1, 27, 1, 94 }, ++ { 0x1, 0x1, 56, -1, -1, 28, 1, 94 }, ++ { 0x0, 0x0, 65, 14, 574, 0, 1, 6 }, ++ { 0x0, 0x0, 65, 1255, 577, 0, 1, 6 }, ++ { 0x1, 0x1, 65, 1256, 579, 33, 1, 6 }, ++ { 0x1, 0x1, 65, 1257, 581, 34, 1, 6 }, ++ { 0x3, 0x3, 65, 1258, 583, 33, 1, 6 }, ++ { 0x0, 0x0, 65, 1259, 585, 0, 1, 6 }, ++ { 0x1, 0x1, 65, 1260, 587, 33, 1, 6 }, ++ { 0x1, 0x1, 65, 1261, 589, 34, 1, 6 }, ++ { 0x3, 0x3, 65, 1262, 591, 33, 1, 6 }, ++ { 0x1, 0x1, 65, 1263, 593, 6, 1, 7 }, ++ { 0x8000001, 0x8000001, 65, 1264, 595, 6, 1, 7 }, ++ { 0x10000001, 0x10000001, 65, 1265, 597, 6, 1, 7 }, ++ { 0x18000001, 0x18000001, 65, 1266, 599, 6, 1, 7 }, ++ { 0x0, 0x0, 65, 1267, 613, 0, 1, 8 }, ++ { 0x1, 0x1, 65, 1268, 615, 33, 1, 8 }, ++ { 0x1, 0x1, 65, 1269, 617, 34, 1, 8 }, ++ { 0x3, 0x3, 65, 1270, 619, 33, 1, 8 }, ++ { 0x0, 0x0, 65, 1271, 625, 0, 1, 15 }, ++ { 0x1, 0x1, 65, 1272, 627, 33, 1, 15 }, ++ { 0x1, 0x1, 65, 1273, 629, 34, 1, 15 }, ++ { 0x3, 0x3, 65, 1274, 631, 33, 1, 15 }, ++ { 0x0, 0x0, 65, 15, 637, 0, 1, 17 }, ++ { 0x0, 0x0, 65, 1276, 640, 0, 1, 17 }, ++ { 0x1, 0x1, 65, 1277, 642, 33, 1, 17 }, ++ { 0x1, 0x1, 65, 1278, 644, 34, 1, 17 }, ++ { 0x3, 0x3, 65, 1279, 646, 33, 1, 17 }, ++ { 0x0, 0x0, 65, 1280, 648, 0, 1, 17 }, ++ { 0x1, 0x1, 65, 1281, 650, 33, 1, 17 }, ++ { 0x1, 0x1, 65, 1282, 652, 34, 1, 17 }, ++ { 0x3, 0x3, 65, 1283, 654, 33, 1, 17 }, ++ { 0x0, 0x0, 65, 1284, 664, 0, 1, 18 }, ++ { 0x1, 0x1, 65, 1285, 666, 33, 1, 18 }, ++ { 0x1, 0x1, 65, 1286, 668, 34, 1, 18 }, ++ { 0x3, 0x3, 65, 1287, 670, 33, 1, 18 }, ++ { 0x1, 0x1, 65, 1288, 672, 6, 1, 18 }, ++ { 0x8000001, 0x8000001, 65, 1289, 674, 6, 1, 18 }, ++ { 0x10000001, 0x10000001, 65, 1290, 676, 6, 1, 18 }, ++ { 0x18000001, 0x18000001, 65, 1291, 678, 6, 1, 18 }, ++ { 0x0, 0x0, 65, 1292, 688, 0, 1, 19 }, ++ { 0x1, 0x1, 65, 1293, 690, 33, 1, 19 }, ++ { 0x1, 0x1, 65, 1294, 692, 34, 1, 19 }, ++ { 0x3, 0x3, 65, 1295, 694, 33, 1, 19 }, ++ { 0x0, 0x0, 65, 1296, 700, 0, 1, 20 }, ++ { 0x1, 0x1, 65, 1297, 702, 33, 1, 20 }, ++ { 0x1, 0x1, 65, 1298, 704, 34, 1, 20 }, ++ { 0x3, 0x3, 65, 1299, 706, 33, 1, 20 }, ++ { 0x1, 0x1, 65, 1300, 708, 6, 1, 20 }, ++ { 0x8000001, 0x8000001, 65, 1301, 710, 6, 1, 20 }, ++ { 0x10000001, 0x10000001, 65, 1302, 712, 6, 1, 20 }, ++ { 0x18000001, 0x18000001, 65, 1303, 714, 6, 1, 20 }, ++ { 0x0, 0x0, 65, 1304, 724, 0, 1, 21 }, ++ { 0x1, 0x1, 65, 1305, 726, 33, 1, 21 }, ++ { 0x1, 0x1, 65, 1306, 728, 34, 1, 21 }, ++ { 0x3, 0x3, 65, 1307, 730, 33, 1, 21 }, ++ { 0x0, 0x0, 65, 17, 736, 0, 1, 17 }, ++ { 0x0, 0x0, 65, 1309, 739, 0, 1, 17 }, ++ { 0x1, 0x1, 65, 1310, 741, 33, 1, 17 }, ++ { 0x1, 0x1, 65, 1311, 743, 34, 1, 17 }, ++ { 0x3, 0x3, 65, 1312, 745, 33, 1, 17 }, ++ { 0x0, 0x0, 65, 1313, 747, 0, 1, 17 }, ++ { 0x1, 0x1, 65, 1314, 749, 33, 1, 17 }, ++ { 0x1, 0x1, 65, 1315, 751, 34, 1, 17 }, ++ { 0x3, 0x3, 65, 1316, 753, 33, 1, 17 }, ++ { 0x0, 0x0, 65, 1317, 763, 0, 1, 21 }, ++ { 0x1, 0x1, 65, 1318, 765, 33, 1, 21 }, ++ { 0x1, 0x1, 65, 1319, 767, 34, 1, 21 }, ++ { 0x3, 0x3, 65, 1320, 769, 33, 1, 21 }, ++ { 0x3, 0x3, 66, 543, 1521, 33, 1, 129 }, ++ { 0x3, 0x3, 66, 544, 1531, 33, 1, 129 }, ++ { 0x3, 0x3, 66, 545, 1541, 33, 1, 129 }, ++ { 0x0, 0x0, 66, -1, 1546, 0, 1, 140 }, ++ { 0x0, 0x0, 66, -1, 1547, 0, 1, 145 }, ++ { 0x0, 0x0, 66, -1, 1548, 0, 1, 145 }, ++ { 0x0, 0x0, 107, 1028, 2311, 0, 0, -1 }, ++ { 0x0, 0x0, 107, 1029, 2830, 0, 1, 29 }, ++ { 0x0, 0x0, 107, 1030, 2352, 0, 0, -1 }, ++ { 0x0, 0x0, 107, 1031, 2834, 0, 1, 29 }, ++ { 0x0, 0x0, 109, -1, 2313, 0, 0, -1 }, ++ { 0x1, 0x1, 109, -1, 2831, 27, 1, 29 }, ++ { 0x0, 0x0, 109, -1, 2354, 0, 0, -1 }, ++ { 0x1, 0x1, 109, -1, 2835, 27, 1, 29 }, ++ { 0x0, 0x0, 110, 1033, -1, 0, 1, 115 }, ++ { 0x1, 0x1, 111, -1, -1, 27, 1, 115 }, ++ { 0x0, 0x0, 112, 1064, 2860, 0, 1, 1 }, ++ { 0x0, 0x0, 112, 1065, 2863, 0, 1, 1 }, ++ { 0x0, 0x0, 112, 1206, 303, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1207, 307, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1167, 430, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1168, 438, 0, 0, -1 }, ++ { 0x0, 0x0, 112, -1, 446, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1066, 2876, 0, 1, 1 }, ++ { 0x0, 0x0, 112, 1067, 2879, 0, 1, 1 }, ++ { 0x0, 0x0, 112, -1, 328, 0, 0, -1 }, ++ { 0x0, 0x0, 112, -1, 332, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1215, 333, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1216, 337, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1068, 2900, 0, 1, 1 }, ++ { 0x0, 0x0, 112, 1069, 2903, 0, 1, 1 }, ++ { 0x0, 0x0, 112, 1219, 351, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1220, 355, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1180, 478, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1181, 486, 0, 0, -1 }, ++ { 0x0, 0x0, 112, -1, 494, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1373, 2914, 0, 1, 1 }, ++ { 0x0, 0x0, 112, 1374, 2916, 0, 1, 1 }, ++ { 0x0, 0x0, 112, -1, 376, 0, 0, -1 }, ++ { 0x0, 0x0, 112, -1, 380, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1228, 381, 0, 0, -1 }, ++ { 0x0, 0x0, 112, 1229, 385, 0, 0, -1 }, ++ { 0x0, 0x0, 112, -1, 2281, 0, 0, -1 }, ++ { 0x1, 0x9, 112, -1, 2285, 33, 1, 54 }, ++ { 0x1, 0x9, 112, -1, 2947, 33, 1, 54 }, ++ { 0x2, 0x3, 112, 1390, 2348, 27, 1, 49 }, ++ { 0x1, 0x1, 114, 1356, 2861, 37, 1, 1 }, ++ { 0x1, 0x1, 114, 1357, 2864, 37, 1, 1 }, ++ { 0x1, 0x1, 114, 1361, 2877, 37, 1, 1 }, ++ { 0x1, 0x1, 114, 1362, 2880, 37, 1, 1 }, ++ { 0x1, 0x1, 114, 1368, 2901, 37, 1, 1 }, ++ { 0x1, 0x1, 114, 1369, 2904, 37, 1, 1 }, ++ { 0x0, 0x0, 114, -1, 2924, 0, 1, 1 }, ++ { 0x0, 0x0, 114, -1, 2925, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1105, 2856, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1106, 2858, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1165, 301, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1166, 305, 0, 0, -1 }, ++ { 0x0, 0x0, 115, -1, 434, 0, 0, -1 }, ++ { 0x0, 0x0, 115, -1, 442, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1210, 444, 0, 0, -1 }, ++ { 0x0, 0x0, 115, -1, 2874, 0, 1, 1 }, ++ { 0x0, 0x0, 115, -1, 2875, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1213, 326, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1214, 330, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1174, 335, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1175, 339, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1109, 2896, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1110, 2898, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1178, 349, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1179, 353, 0, 0, -1 }, ++ { 0x0, 0x0, 115, -1, 482, 0, 0, -1 }, ++ { 0x0, 0x0, 115, -1, 490, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1223, 492, 0, 0, -1 }, ++ { 0x0, 0x0, 115, -1, 2912, 0, 1, 1 }, ++ { 0x0, 0x0, 115, -1, 2913, 0, 1, 1 }, ++ { 0x0, 0x0, 115, 1226, 374, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1227, 378, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1187, 383, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1188, 387, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1060, 2279, 0, 0, -1 }, ++ { 0x0, 0x0, 115, 1061, 2283, 0, 1, 54 }, ++ { 0x0, 0x0, 115, 1062, 2946, 0, 1, 54 }, ++ { 0x0, 0x0, 115, 1063, 2347, 0, 1, 49 }, ++ { 0x1, 0x1, 115, -1, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 115, -1, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 115, -1, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 116, -1, 2857, 37, 1, 1 }, ++ { 0x1, 0x1, 116, -1, 2859, 37, 1, 1 }, ++ { 0x0, 0x0, 116, -1, 2884, 0, 1, 1 }, ++ { 0x0, 0x0, 116, -1, 2885, 0, 1, 1 }, ++ { 0x1, 0x1, 116, -1, 2897, 37, 1, 1 }, ++ { 0x1, 0x1, 116, -1, 2899, 37, 1, 1 }, ++ { 0x0, 0x0, 116, -1, 2922, 0, 1, 1 }, ++ { 0x0, 0x0, 116, -1, 2923, 0, 1, 1 }, ++ { 0x0, 0x0, 117, 1158, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 117, 1159, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 117, 1160, -1, 0, 1, 0 }, ++ { 0x3, 0x3, 117, 1118, -1, 34, 1, 33 }, ++ { 0x3, 0x3, 117, 1119, -1, 34, 1, 40 }, ++ { 0x1, 0x1, 119, -1, -1, 35, 1, 33 }, ++ { 0x1, 0x1, 119, -1, -1, 35, 1, 40 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 66 }, ++ { 0x1, 0x1, 120, -1, -1, 36, 1, 122 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 40 }, ++ { 0x1, 0x1, 120, -1, -1, 27, 1, 96 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 105 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 73 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 73 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 74 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 40 }, ++ { 0x1, 0x1, 120, -1, -1, 27, 1, 117 }, ++ { 0x1, 0x1, 120, -1, -1, 27, 1, 40 }, ++ { 0x0, 0x0, 120, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 121, -1, 2786, 0, 0, -1 }, ++ { 0x0, 0x0, 121, -1, 2789, 0, 0, -1 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 16 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 16 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 16 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 16 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 22 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 22 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 22 }, ++ { 0x1, 0x1, 122, -1, -1, 35, 1, 22 }, ++ { 0x1, 0x1, 122, -1, -1, 23, 1, 67 }, ++ { 0x1, 0x1, 122, -1, -1, 23, 1, 67 }, ++ { 0x1, 0x1, 122, -1, -1, 23, 1, 67 }, ++ { 0x1, 0x1, 122, -1, -1, 23, 1, 67 }, ++ { 0x1, 0x1, 122, 900, -1, 23, 1, 67 }, ++ { 0x9, 0x9, 122, 901, -1, 20, 1, 67 }, ++ { 0x0, 0x0, 126, 2165, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 126, 2166, -1, 0, 1, 0 }, ++ { 0x1, 0x1, 126, -1, -1, 28, 1, 33 }, ++ { 0x1, 0x1, 126, -1, -1, 27, 1, 33 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x0, 126, -1, -1, 0, 1, 114 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 126, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x0, 126, 1116, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 126, 1244, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 140, 1194, 2852, 0, 1, 1 }, ++ { 0x0, 0x0, 140, 1195, 2854, 0, 1, 1 }, ++ { 0x0, 0x0, 140, 1036, 302, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1037, 422, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1076, 311, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1077, 315, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1078, 443, 0, 0, -1 }, ++ { 0x0, 0x0, 140, -1, 2872, 0, 1, 1 }, ++ { 0x0, 0x0, 140, -1, 2873, 0, 1, 1 }, ++ { 0x0, 0x0, 140, 1081, 325, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1082, 329, 0, 0, -1 }, ++ { 0x0, 0x0, 140, -1, 336, 0, 0, -1 }, ++ { 0x0, 0x0, 140, -1, 340, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1198, 2892, 0, 1, 1 }, ++ { 0x0, 0x0, 140, 1199, 2894, 0, 1, 1 }, ++ { 0x0, 0x0, 140, 1049, 350, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1050, 470, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1089, 359, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1090, 363, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1091, 491, 0, 0, -1 }, ++ { 0x0, 0x0, 140, -1, 2910, 0, 1, 1 }, ++ { 0x0, 0x0, 140, -1, 2911, 0, 1, 1 }, ++ { 0x0, 0x0, 140, 1094, 373, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 1095, 377, 0, 0, -1 }, ++ { 0x0, 0x0, 140, -1, 384, 0, 0, -1 }, ++ { 0x0, 0x0, 140, -1, 388, 0, 0, -1 }, ++ { 0x0, 0x0, 140, 2974, 2267, 0, 0, -1 }, ++ { 0x1, 0x1, 140, 2975, 2275, 33, 1, 54 }, ++ { 0x1, 0x1, 140, 2976, 2940, 33, 1, 54 }, ++ { 0x0, 0x0, 140, 2977, 2341, 0, 0, -1 }, ++ { 0x1, 0x1, 140, 2978, -1, 28, 1, 49 }, ++ { 0x1, 0x1, 141, -1, 2853, 37, 1, 1 }, ++ { 0x1, 0x1, 141, -1, 2855, 37, 1, 1 }, ++ { 0x0, 0x0, 141, -1, 2882, 0, 1, 1 }, ++ { 0x0, 0x0, 141, -1, 2883, 0, 1, 1 }, ++ { 0x1, 0x1, 141, -1, 2893, 37, 1, 1 }, ++ { 0x1, 0x1, 141, -1, 2895, 37, 1, 1 }, ++ { 0x0, 0x0, 141, -1, 2920, 0, 1, 1 }, ++ { 0x0, 0x0, 141, -1, 2921, 0, 1, 1 }, ++ { 0x1, 0x1, 144, 899, 1140, 3, 1, 22 }, ++ { 0x0, 0x0, 145, 2167, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 146, 905, 2846, 0, 1, 1 }, ++ { 0x0, 0x0, 146, 906, 2849, 0, 1, 1 }, ++ { 0x0, 0x0, 146, -1, 304, 0, 0, -1 }, ++ { 0x0, 0x0, 146, -1, 426, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1038, 309, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1039, 313, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1040, 445, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 909, 2866, 0, 1, 1 }, ++ { 0x0, 0x0, 146, 910, 2869, 0, 1, 1 }, ++ { 0x0, 0x0, 146, 1043, 327, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1044, 331, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1083, 334, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1084, 338, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 915, 2886, 0, 1, 1 }, ++ { 0x0, 0x0, 146, 916, 2889, 0, 1, 1 }, ++ { 0x0, 0x0, 146, -1, 352, 0, 0, -1 }, ++ { 0x0, 0x0, 146, -1, 474, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1051, 357, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1052, 361, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1053, 493, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 919, 2906, 0, 1, 1 }, ++ { 0x0, 0x0, 146, 920, 2908, 0, 1, 1 }, ++ { 0x0, 0x0, 146, 1056, 375, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1057, 379, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1096, 382, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1097, 386, 0, 0, -1 }, ++ { 0x0, 0x0, 146, 1189, 2265, 0, 0, -1 }, ++ { 0x1, 0x1, 146, 1190, 2273, 36, 1, 54 }, ++ { 0x1, 0x1, 146, 1191, 2939, 36, 1, 54 }, ++ { 0x0, 0x0, 146, 1192, 2340, 0, 0, -1 }, ++ { 0x1, 0x1, 146, 1193, -1, 27, 1, 49 }, ++ { 0x1, 0x1, 147, -1, 2848, 37, 1, 1 }, ++ { 0x1, 0x1, 147, -1, 2851, 37, 1, 1 }, ++ { 0x1, 0x1, 147, -1, 2868, 37, 1, 1 }, ++ { 0x1, 0x1, 147, -1, 2871, 37, 1, 1 }, ++ { 0x1, 0x1, 147, -1, 2888, 37, 1, 1 }, ++ { 0x1, 0x1, 147, -1, 2891, 37, 1, 1 }, ++ { 0x0, 0x0, 147, -1, 2918, 0, 1, 1 }, ++ { 0x0, 0x0, 147, -1, 2919, 0, 1, 1 }, ++ { 0x0, 0x0, 148, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 148, 1117, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 66 }, ++ { 0x0, 0x0, 149, -1, 2926, 0, 1, 63 }, ++ { 0x0, 0x0, 149, -1, 2927, 0, 1, 63 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 81 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 81 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 85 }, ++ { 0x0, 0x0, 149, -1, -1, 0, 1, 40 }, ++ { 0x1, 0x1, 150, -1, 575, 12, 1, 6 }, ++ { 0x1, 0x1, 150, -1, 578, 12, 1, 6 }, ++ { 0x200001, 0x200001, 150, -1, 580, 12, 1, 6 }, ++ { 0x400001, 0x400001, 150, -1, 582, 12, 1, 6 }, ++ { 0x600001, 0x600001, 150, -1, 584, 12, 1, 6 }, ++ { 0x1, 0x1, 150, -1, 586, 12, 1, 6 }, ++ { 0x200001, 0x200001, 150, -1, 588, 12, 1, 6 }, ++ { 0x400001, 0x400001, 150, -1, 590, 12, 1, 6 }, ++ { 0x600001, 0x600001, 150, -1, 592, 12, 1, 6 }, ++ { 0x41, 0x41, 150, -1, 594, 6, 1, 7 }, ++ { 0x8000041, 0x8000041, 150, -1, 596, 6, 1, 7 }, ++ { 0x10000041, 0x10000041, 150, -1, 598, 6, 1, 7 }, ++ { 0x18000041, 0x18000041, 150, -1, 600, 6, 1, 7 }, ++ { 0x1, 0x1, 150, -1, 614, 12, 1, 8 }, ++ { 0x200001, 0x200001, 150, -1, 616, 12, 1, 8 }, ++ { 0x400001, 0x400001, 150, -1, 618, 12, 1, 8 }, ++ { 0x600001, 0x600001, 150, -1, 620, 12, 1, 8 }, ++ { 0x1, 0x1, 150, -1, 626, 12, 1, 15 }, ++ { 0x200001, 0x200001, 150, -1, 628, 12, 1, 15 }, ++ { 0x400001, 0x400001, 150, -1, 630, 12, 1, 15 }, ++ { 0x600001, 0x600001, 150, -1, 632, 12, 1, 15 }, ++ { 0x1, 0x1, 150, -1, 638, 12, 1, 17 }, ++ { 0x1, 0x1, 150, -1, 641, 12, 1, 17 }, ++ { 0x200001, 0x200001, 150, -1, 643, 12, 1, 17 }, ++ { 0x400001, 0x400001, 150, -1, 645, 12, 1, 17 }, ++ { 0x600001, 0x600001, 150, -1, 647, 12, 1, 17 }, ++ { 0x1, 0x1, 150, -1, 649, 12, 1, 17 }, ++ { 0x200001, 0x200001, 150, -1, 651, 12, 1, 17 }, ++ { 0x400001, 0x400001, 150, -1, 653, 12, 1, 17 }, ++ { 0x600001, 0x600001, 150, -1, 655, 12, 1, 17 }, ++ { 0x1, 0x1, 150, -1, 665, 12, 1, 18 }, ++ { 0x200001, 0x200001, 150, -1, 667, 12, 1, 18 }, ++ { 0x400001, 0x400001, 150, -1, 669, 12, 1, 18 }, ++ { 0x600001, 0x600001, 150, -1, 671, 12, 1, 18 }, ++ { 0x41, 0x41, 150, -1, 673, 6, 1, 18 }, ++ { 0x8000041, 0x8000041, 150, -1, 675, 6, 1, 18 }, ++ { 0x10000041, 0x10000041, 150, -1, 677, 6, 1, 18 }, ++ { 0x18000041, 0x18000041, 150, -1, 679, 6, 1, 18 }, ++ { 0x1, 0x1, 150, -1, 689, 12, 1, 19 }, ++ { 0x200001, 0x200001, 150, -1, 691, 12, 1, 19 }, ++ { 0x400001, 0x400001, 150, -1, 693, 12, 1, 19 }, ++ { 0x600001, 0x600001, 150, -1, 695, 12, 1, 19 }, ++ { 0x1, 0x1, 150, -1, 701, 12, 1, 20 }, ++ { 0x200001, 0x200001, 150, -1, 703, 12, 1, 20 }, ++ { 0x400001, 0x400001, 150, -1, 705, 12, 1, 20 }, ++ { 0x600001, 0x600001, 150, -1, 707, 12, 1, 20 }, ++ { 0x41, 0x41, 150, -1, 709, 6, 1, 20 }, ++ { 0x8000041, 0x8000041, 150, -1, 711, 6, 1, 20 }, ++ { 0x10000041, 0x10000041, 150, -1, 713, 6, 1, 20 }, ++ { 0x18000041, 0x18000041, 150, -1, 715, 6, 1, 20 }, ++ { 0x1, 0x1, 150, -1, 725, 12, 1, 21 }, ++ { 0x200001, 0x200001, 150, -1, 727, 12, 1, 21 }, ++ { 0x400001, 0x400001, 150, -1, 729, 12, 1, 21 }, ++ { 0x600001, 0x600001, 150, -1, 731, 12, 1, 21 }, ++ { 0x1, 0x1, 150, -1, 737, 12, 1, 17 }, ++ { 0x1, 0x1, 150, -1, 740, 12, 1, 17 }, ++ { 0x200001, 0x200001, 150, -1, 742, 12, 1, 17 }, ++ { 0x400001, 0x400001, 150, -1, 744, 12, 1, 17 }, ++ { 0x600001, 0x600001, 150, -1, 746, 12, 1, 17 }, ++ { 0x1, 0x1, 150, -1, 748, 12, 1, 17 }, ++ { 0x200001, 0x200001, 150, -1, 750, 12, 1, 17 }, ++ { 0x400001, 0x400001, 150, -1, 752, 12, 1, 17 }, ++ { 0x600001, 0x600001, 150, -1, 754, 12, 1, 17 }, ++ { 0x1, 0x1, 150, -1, 764, 12, 1, 21 }, ++ { 0x200001, 0x200001, 150, -1, 766, 12, 1, 21 }, ++ { 0x400001, 0x400001, 150, -1, 768, 12, 1, 21 }, ++ { 0x600001, 0x600001, 150, -1, 770, 12, 1, 21 }, ++ { 0x0, 0x0, 155, -1, -1, 0, 1, 124 }, ++ { 0x0, 0x0, 159, 775, -1, 0, 1, 75 }, ++ { 0x0, 0x0, 159, 776, -1, 0, 1, 75 }, ++ { 0x9, 0x9, 159, -1, 1438, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1447, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1456, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1469, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1478, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1487, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1496, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1505, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1514, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1524, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1534, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1544, 32, 1, 130 }, ++ { 0x9, 0x9, 159, -1, 1553, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1559, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1565, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1571, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1577, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1583, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1589, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1595, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1601, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1607, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1613, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1619, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1625, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1631, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1637, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1643, 32, 1, 144 }, ++ { 0x9, 0x9, 159, -1, 1649, 32, 1, 149 }, ++ { 0x9, 0x9, 159, -1, 1655, 32, 1, 149 }, ++ { 0x0, 0x0, 160, 1235, 296, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 1236, 412, 0, 0, -1 }, ++ { 0x1, 0x1, 160, -1, 2862, 38, 1, 1 }, ++ { 0x1, 0x1, 160, 907, 2865, 38, 1, 1 }, ++ { 0x0, 0x0, 160, 908, 413, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 1237, 318, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 1238, 452, 0, 0, -1 }, ++ { 0x1, 0x1, 160, -1, 2878, 38, 1, 1 }, ++ { 0x1, 0x1, 160, 911, 2881, 38, 1, 1 }, ++ { 0x0, 0x0, 160, 912, 453, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 913, 323, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 914, 341, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 1239, 344, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 1240, 460, 0, 0, -1 }, ++ { 0x1, 0x1, 160, -1, 2902, 38, 1, 1 }, ++ { 0x1, 0x1, 160, 917, 2905, 38, 1, 1 }, ++ { 0x0, 0x0, 160, 918, 461, 0, 0, -1 }, ++ { 0x0, 0x0, 160, -1, 366, 0, 0, -1 }, ++ { 0x0, 0x0, 160, -1, 500, 0, 0, -1 }, ++ { 0x1, 0x1, 160, -1, 2915, 38, 1, 1 }, ++ { 0x1, 0x1, 160, 921, 2917, 38, 1, 1 }, ++ { 0x0, 0x0, 160, 922, 501, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 923, 371, 0, 0, -1 }, ++ { 0x0, 0x0, 160, 924, 389, 0, 0, -1 }, ++ { 0x0, 0x0, 161, 1397, 2287, 0, 0, -1 }, ++ { 0x0, 0x0, 161, 1398, 2295, 0, 1, 54 }, ++ { 0x0, 0x0, 161, 1399, 2956, 0, 1, 54 }, ++ { 0x0, 0x0, 161, 1400, 2343, 0, 0, -1 }, ++ { 0x1, 0x1, 161, 1401, -1, 29, 1, 49 }, ++ { 0x0, 0x0, 162, -1, 2305, 0, 0, -1 }, ++ { 0x1, 0x9, 162, -1, 2309, 33, 1, 54 }, ++ { 0x1, 0x9, 162, -1, 2965, 33, 1, 54 }, ++ { 0x6, 0x7, 162, -1, 2350, 27, 1, 49 }, ++ { 0x0, 0x0, 163, 1383, 2303, 0, 0, -1 }, ++ { 0x0, 0x0, 163, 1384, 2307, 0, 1, 54 }, ++ { 0x0, 0x0, 163, 1385, 2964, 0, 1, 54 }, ++ { 0x1, 0x1, 163, 1386, 2349, 29, 1, 49 }, ++ { 0x1, 0x1, 164, 1404, -1, 27, 1, 33 }, ++ { 0x0, 0x0, 165, 2159, 2291, 0, 0, -1 }, ++ { 0x1, 0x1, 165, 2160, 2299, 33, 1, 54 }, ++ { 0x1, 0x1, 165, 2161, 2958, 33, 1, 54 }, ++ { 0x0, 0x0, 165, 2162, 2345, 0, 0, -1 }, ++ { 0x3, 0x3, 165, 2163, -1, 28, 1, 49 }, ++ { 0x0, 0x0, 166, 1392, 2289, 0, 0, -1 }, ++ { 0x1, 0x1, 166, 1393, 2297, 36, 1, 54 }, ++ { 0x1, 0x1, 166, 1394, 2957, 36, 1, 54 }, ++ { 0x0, 0x0, 166, 1395, 2344, 0, 0, -1 }, ++ { 0x5, 0x5, 166, 1396, -1, 27, 1, 49 }, ++ { 0x0, 0x0, 167, -1, 2928, 0, 1, 63 }, ++ { 0x0, 0x0, 167, -1, 2929, 0, 1, 63 }, ++ { 0x1, 0x1, 169, -1, -1, 28, 1, 33 }, ++ { 0x1, 0x1, 170, 2745, -1, 27, 1, 33 }, ++ { 0x1, 0x1, 170, 2746, -1, 27, 1, 33 }, ++ { 0x1, 0x1, 171, 1685, -1, 28, 1, 135 }, ++ { 0x1, 0x1, 171, 1686, -1, 28, 1, 135 }, ++ { 0x1, 0x1, 171, 1687, -1, 28, 1, 135 }, ++ { 0x1, 0x1, 171, 1688, -1, 28, 1, 135 }, ++ { 0x1, 0x1, 171, 1689, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1690, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1691, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1692, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1693, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1694, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1695, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1696, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1697, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1698, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1699, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1700, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1701, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1702, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1703, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1704, -1, 28, 1, 134 }, ++ { 0x1, 0x1, 171, 1705, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1706, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1707, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1708, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1709, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1710, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1711, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1712, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1713, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1714, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1715, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1716, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1717, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1718, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1719, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1720, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1721, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1722, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1723, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1724, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1725, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1726, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1727, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1728, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1729, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1730, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1731, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1732, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1733, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1734, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1735, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1736, -1, 28, 1, 125 }, ++ { 0x1, 0x1, 171, 1737, -1, 28, 1, 125 }, ++ { 0x1, 0x1, 171, 1738, -1, 28, 1, 125 }, ++ { 0x1, 0x1, 171, 1739, -1, 28, 1, 125 }, ++ { 0x1, 0x1, 171, 1740, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1741, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1742, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1743, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1744, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1745, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1746, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1747, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1748, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1749, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1750, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1751, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1752, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1753, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1754, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1755, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1756, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1757, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1758, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1759, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1760, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1761, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1762, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1763, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1764, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1765, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1766, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1767, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1768, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1769, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1770, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1771, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1772, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1773, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1774, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1775, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1776, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1777, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1778, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1779, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1780, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1781, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1782, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1783, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1784, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1785, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1786, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1787, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1788, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1789, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1790, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1791, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1792, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1793, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1794, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1795, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1796, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1797, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1798, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1799, -1, 28, 1, 129 }, ++ { 0x1, 0x1, 171, 1800, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1801, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1802, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1803, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1804, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1805, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1806, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1807, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1808, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1809, -1, 28, 1, 129 }, ++ { 0x1, 0x1, 171, 1810, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1811, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1812, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1813, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1814, -1, 28, 1, 126 }, ++ { 0x1, 0x1, 171, 1815, -1, 28, 1, 127 }, ++ { 0x1, 0x1, 171, 1816, -1, 28, 1, 128 }, ++ { 0x1, 0x1, 171, 1817, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1818, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1819, -1, 28, 1, 129 }, ++ { 0x1, 0x1, 171, 1820, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1821, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1822, -1, 28, 1, 130 }, ++ { 0x1, 0x1, 171, 1823, -1, 28, 1, 124 }, ++ { 0x1, 0x1, 171, 1824, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1825, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1826, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1827, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1828, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1829, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1830, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1831, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1832, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1833, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1834, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1835, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1836, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1837, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1838, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1839, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1840, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1841, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1842, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1843, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1844, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1845, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1846, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1847, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1848, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1849, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1850, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1851, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1852, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1853, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1854, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1855, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1856, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1857, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1858, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1859, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1860, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1861, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1862, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1863, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1864, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1865, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1866, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1867, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1868, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1869, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1870, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1871, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1872, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1873, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1874, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1875, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1876, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1877, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1878, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1879, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1880, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1881, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1882, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1883, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1884, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1885, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1886, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1887, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1888, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1889, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1890, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1891, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1892, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1893, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1894, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1895, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1896, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1897, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1898, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1899, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1900, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1901, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1902, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1903, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1904, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1905, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1906, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1907, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1908, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1909, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1910, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1911, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1912, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1913, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1914, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1915, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1916, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1917, -1, 28, 1, 141 }, ++ { 0x1, 0x1, 171, 1918, -1, 28, 1, 142 }, ++ { 0x1, 0x1, 171, 1919, -1, 28, 1, 143 }, ++ { 0x1, 0x1, 171, 1920, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1921, -1, 28, 1, 144 }, ++ { 0x1, 0x1, 171, 1922, -1, 28, 1, 140 }, ++ { 0x1, 0x1, 171, 1923, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1924, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1925, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1926, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1927, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1928, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1929, -1, 28, 1, 146 }, ++ { 0x1, 0x1, 171, 1930, -1, 28, 1, 147 }, ++ { 0x1, 0x1, 171, 1931, -1, 28, 1, 148 }, ++ { 0x1, 0x1, 171, 1932, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1933, -1, 28, 1, 149 }, ++ { 0x1, 0x1, 171, 1934, -1, 28, 1, 145 }, ++ { 0x1, 0x1, 171, 1673, -1, 28, 1, 151 }, ++ { 0x1, 0x1, 171, 1674, -1, 28, 1, 152 }, ++ { 0x1, 0x1, 171, 1675, -1, 28, 1, 152 }, ++ { 0x1, 0x1, 171, 1676, -1, 28, 1, 151 }, ++ { 0x1, 0x1, 171, 1677, -1, 28, 1, 153 }, ++ { 0x1, 0x1, 171, 1678, -1, 28, 1, 154 }, ++ { 0x1, 0x1, 171, 1679, -1, 28, 1, 154 }, ++ { 0x1, 0x1, 171, 1680, -1, 28, 1, 153 }, ++ { 0x1, 0x1, 171, 1681, -1, 28, 1, 153 }, ++ { 0x1, 0x1, 171, 1682, -1, 28, 1, 154 }, ++ { 0x1, 0x1, 171, 1683, -1, 28, 1, 154 }, ++ { 0x1, 0x1, 171, 1684, -1, 28, 1, 153 }, ++ { 0x1, 0x1, 171, 1979, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1980, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1981, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 171, 1982, -1, 28, 1, 136 }, ++ { 0x1, 0x1, 172, 1935, -1, 29, 1, 151 }, ++ { 0x1, 0x1, 172, 1936, -1, 29, 1, 152 }, ++ { 0x1, 0x1, 172, 1937, -1, 29, 1, 152 }, ++ { 0x1, 0x1, 172, 1938, -1, 29, 1, 151 }, ++ { 0x1, 0x1, 172, 1939, -1, 29, 1, 153 }, ++ { 0x1, 0x1, 172, 1940, -1, 29, 1, 154 }, ++ { 0x1, 0x1, 172, 1941, -1, 29, 1, 154 }, ++ { 0x1, 0x1, 172, 1942, -1, 29, 1, 153 }, ++ { 0x1, 0x1, 172, 1943, -1, 29, 1, 153 }, ++ { 0x1, 0x1, 172, 1944, -1, 29, 1, 154 }, ++ { 0x1, 0x1, 172, 1945, -1, 29, 1, 154 }, ++ { 0x1, 0x1, 172, 1946, -1, 29, 1, 153 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 135 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 135 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 135 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 135 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 134 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 269, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2224, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 271, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2225, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 273, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2226, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 125 }, ++ { 0x3, 0x3, 173, 275, -1, 28, 1, 125 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 125 }, ++ { 0x3, 0x3, 173, 276, -1, 28, 1, 125 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 277, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2227, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 279, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2228, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 281, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2229, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 283, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2230, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 285, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2231, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 287, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2232, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 129 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 289, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2233, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 129 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 291, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2234, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 126 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 127 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 128 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 129 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 293, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 130 }, ++ { 0x3, 0x3, 173, 2235, -1, 28, 1, 124 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2236, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2237, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2238, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2239, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2240, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2241, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2242, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2243, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2244, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2245, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2246, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2247, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2248, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2249, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2250, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 141 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 142 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 143 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 144 }, ++ { 0x3, 0x3, 173, 2251, -1, 28, 1, 140 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2252, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 146 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 147 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 148 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 149 }, ++ { 0x3, 0x3, 173, 2253, -1, 28, 1, 145 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 151 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 152 }, ++ { 0x3, 0x3, 173, 933, -1, 28, 1, 152 }, ++ { 0x3, 0x3, 173, 934, -1, 28, 1, 151 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 153 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 154 }, ++ { 0x3, 0x3, 173, 935, -1, 28, 1, 154 }, ++ { 0x3, 0x3, 173, 936, -1, 28, 1, 153 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 153 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 154 }, ++ { 0x3, 0x3, 173, 937, -1, 28, 1, 154 }, ++ { 0x3, 0x3, 173, 938, -1, 28, 1, 153 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, 2190, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, 2191, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 132 }, ++ { 0x3, 0x3, 173, 2192, -1, 28, 1, 132 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 132 }, ++ { 0x3, 0x3, 173, 2193, -1, 28, 1, 132 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, 2194, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, 2195, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, 2196, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, 2197, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 133 }, ++ { 0x3, 0x3, 173, 2198, -1, 28, 1, 131 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 139 }, ++ { 0x3, 0x3, 173, 2199, -1, 28, 1, 138 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 150 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 156 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 150 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 156 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 150 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 156 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 150 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 156 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 150 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 156 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x3, 0x3, 173, -1, -1, 28, 1, 136 }, ++ { 0x0, 0x0, 174, -1, 392, 0, 0, -1 }, ++ { 0x0, 0x0, 174, -1, 394, 0, 0, -1 }, ++ { 0x0, 0x0, 174, 3004, 2968, 0, 1, 1 }, ++ { 0x0, 0x0, 174, 3005, 2969, 0, 1, 1 }, ++ { 0x0, 0x0, 174, -1, 400, 0, 0, -1 }, ++ { 0x0, 0x0, 174, -1, 402, 0, 0, -1 }, ++ { 0x0, 0x0, 174, 3008, 2972, 0, 1, 1 }, ++ { 0x0, 0x0, 174, 3009, 2973, 0, 1, 1 }, ++ { 0x11, 0x31, 175, 2847, 407, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 408, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2047, 409, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 411, 12, 1, 4 }, ++ { 0x1, 0x1, 175, -1, 415, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 416, 12, 1, 4 }, ++ { 0x11, 0x11, 175, -1, 417, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 418, 12, 1, 4 }, ++ { 0x1, 0x1, 175, 2053, 419, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 421, 12, 1, 4 }, ++ { 0x11, 0x11, 175, 2055, 423, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 425, 12, 1, 4 }, ++ { 0x1, 0x1, 175, 2057, 427, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 429, 12, 1, 4 }, ++ { 0x11, 0x11, 175, 2059, 431, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 433, 12, 1, 4 }, ++ { 0x1, 0x1, 175, 2061, 435, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 437, 12, 1, 4 }, ++ { 0x11, 0x11, 175, 2063, 439, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 441, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2867, 447, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 448, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2069, 449, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 451, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2887, 455, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 456, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2095, 457, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 459, 12, 1, 4 }, ++ { 0x1, 0x1, 175, -1, 463, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 464, 12, 1, 4 }, ++ { 0x11, 0x11, 175, -1, 465, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 466, 12, 1, 4 }, ++ { 0x1, 0x1, 175, 2101, 467, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 469, 12, 1, 4 }, ++ { 0x11, 0x11, 175, 2103, 471, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 473, 12, 1, 4 }, ++ { 0x1, 0x1, 175, 2105, 475, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 477, 12, 1, 4 }, ++ { 0x11, 0x11, 175, 2107, 479, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 481, 12, 1, 4 }, ++ { 0x1, 0x1, 175, 2109, 483, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 175, -1, 485, 12, 1, 4 }, ++ { 0x11, 0x11, 175, 2111, 487, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 489, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2907, 495, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 496, 12, 1, 4 }, ++ { 0x11, 0x31, 175, 2117, 497, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 175, -1, 499, 12, 1, 4 }, ++ { 0x1, 0x1, 175, -1, 503, 33, 1, 4 }, ++ { 0x200001, 0x200001, 175, -1, 504, 12, 1, 4 }, ++ { 0x1, 0x1, 175, -1, 505, 33, 1, 4 }, ++ { 0x200001, 0x200001, 175, -1, 506, 12, 1, 4 }, ++ { 0x1, 0x1, 175, -1, 511, 33, 1, 4 }, ++ { 0x200001, 0x200001, 175, -1, 512, 12, 1, 4 }, ++ { 0x1, 0x1, 175, -1, 513, 33, 1, 4 }, ++ { 0x200001, 0x200001, 175, -1, 514, 12, 1, 4 }, ++ { 0x2200001, 0x6200001, 176, 2850, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 1994, -1, 33, 1, 4 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x1, 0x1, 176, 2000, -1, 37, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2002, -1, 33, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x1, 0x1, 176, 2004, -1, 37, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2006, -1, 33, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x1, 0x1, 176, 2008, -1, 37, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2010, -1, 33, 1, 4 }, ++ { 0x1, 0x1, 176, -1, -1, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, -1, -1, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x2200001, 0x6200001, 176, 2870, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2014, -1, 33, 1, 4 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x2200001, 0x6200001, 176, 2890, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2018, -1, 33, 1, 4 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x1, 0x1, 176, 2024, -1, 37, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2026, -1, 33, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x1, 0x1, 176, 2028, -1, 37, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2030, -1, 33, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x1, 0x1, 176, 2032, -1, 37, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2034, -1, 33, 1, 4 }, ++ { 0x1, 0x1, 176, -1, -1, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, -1, -1, 33, 1, 4 }, ++ { 0x2200001, 0x2200001, 176, -1, -1, 12, 1, 4 }, ++ { 0x2200001, 0x6200001, 176, 2909, -1, 12, 1, 4 }, ++ { 0x11, 0x11, 176, 2038, -1, 33, 1, 4 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x4200001, 0x4200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 37, 1, 4 }, ++ { 0x2000001, 0x2000001, 176, -1, -1, 12, 1, 4 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 33, 1, 5 }, ++ { 0x200001, 0x200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x0, 0x0, 176, -1, -1, 0, 1, 5 }, ++ { 0x1, 0x1, 176, -1, -1, 12, 1, 5 }, ++ { 0x9, 0x9, 176, -1, -1, 33, 1, 5 }, ++ { 0x1, 0x1, 176, 395, -1, 33, 1, 4 }, ++ { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x200001, 0x200001, 176, 396, -1, 12, 1, 4 }, ++ { 0x9, 0x9, 176, -1, -1, 33, 1, 5 }, ++ { 0x1, 0x1, 176, 397, -1, 33, 1, 4 }, ++ { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x200001, 0x200001, 176, 398, -1, 12, 1, 4 }, ++ { 0x9, 0x9, 176, -1, -1, 33, 1, 5 }, ++ { 0x1, 0x1, 176, 403, -1, 33, 1, 4 }, ++ { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x200001, 0x200001, 176, 404, -1, 12, 1, 4 }, ++ { 0x9, 0x9, 176, -1, -1, 33, 1, 5 }, ++ { 0x1, 0x1, 176, 405, -1, 33, 1, 4 }, ++ { 0x1200001, 0x1200001, 176, -1, -1, 12, 1, 5 }, ++ { 0x200001, 0x200001, 176, 406, -1, 12, 1, 4 }, ++ { 0x0, 0x0, 177, -1, 2293, 0, 0, -1 }, ++ { 0x9, 0x9, 177, -1, 2301, 33, 1, 49 }, ++ { 0x9, 0x9, 177, -1, 2959, 33, 1, 49 }, ++ { 0x0, 0x0, 177, -1, 2346, 0, 0, -1 }, ++ { 0x7, 0x7, 177, -1, -1, 27, 1, 49 }, ++ { 0x1, 0x1, 197, -1, -1, 27, 1, 10 }, ++ { 0x1, 0x1, 211, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 211, -1, -1, 29, 1, 0 }, ++ { 0x2, 0x3, 211, 1151, -1, 27, 1, 33 }, ++ { 0x0, 0x0, 211, 1152, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 211, 1153, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 211, 1154, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 211, 1155, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 211, 1156, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 211, 2988, -1, 0, 1, 93 }, ++ { 0x0, 0x0, 211, 2989, -1, 0, 1, 93 }, ++ { 0x0, 0x0, 211, 2990, 949, 0, 0, -1 }, ++ { 0x1, 0x1, 212, -1, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 212, -1, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 213, -1, 1408, 32, 1, 135 }, ++ { 0x1, 0x1, 213, -1, 1410, 32, 1, 135 }, ++ { 0x1, 0x1, 213, -1, 1412, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1414, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1416, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1418, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1420, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1422, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1424, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1426, 32, 1, 134 }, ++ { 0x1, 0x1, 213, -1, 1428, 32, 1, 136 }, ++ { 0x1, 0x1, 213, -1, 1430, 32, 1, 136 }, ++ { 0x1, 0x1, 213, -1, 1947, 32, 1, 131 }, ++ { 0x1, 0x1, 213, -1, 1949, 32, 1, 138 }, ++ { 0x1, 0x1, 213, -1, 1951, 32, 1, 132 }, ++ { 0x1, 0x1, 213, -1, 1953, 32, 1, 132 }, ++ { 0x1, 0x1, 213, -1, 1955, 32, 1, 131 }, ++ { 0x1, 0x1, 213, -1, 1957, 32, 1, 138 }, ++ { 0x1, 0x1, 213, -1, 1959, 32, 1, 131 }, ++ { 0x1, 0x1, 213, -1, 1961, 32, 1, 138 }, ++ { 0x1, 0x1, 213, 2749, 1963, 32, 1, 131 }, ++ { 0x1, 0x1, 213, 2750, 1966, 32, 1, 138 }, ++ { 0x0, 0x0, 214, -1, 2791, 0, 0, -1 }, ++ { 0x0, 0x0, 214, -1, 2792, 0, 0, -1 }, ++ { 0x0, 0x0, 214, -1, 2817, 0, 0, -1 }, ++ { 0x5, 0x5, 214, -1, 2820, 20, 1, 67 }, ++ { 0x0, 0x0, 218, 2175, 948, 0, 0, -1 }, ++ { 0x0, 0x0, 219, -1, 1121, 0, 0, -1 }, ++ { 0x0, 0x0, 219, -1, 1246, 0, 0, -1 }, ++ { 0x0, 0x0, 219, -1, -1, 0, 1, 121 }, ++ { 0x0, 0x0, 219, -1, -1, 0, 1, 66 }, ++ { 0x1, 0x1, 219, 815, 2255, 36, 1, 65 }, ++ { 0x1, 0x1, 219, 816, 2314, 36, 1, 65 }, ++ { 0x0, 0x0, 219, 817, 2317, 0, 0, -1 }, ++ { 0x1, 0x1, 219, 818, -1, 36, 1, 65 }, ++ { 0x0, 0x0, 219, 1405, -1, 0, 1, 33 }, ++ { 0x1, 0x1, 219, 819, 2322, 36, 1, 65 }, ++ { 0x0, 0x0, 219, 820, 2325, 0, 0, -1 }, ++ { 0x1, 0x1, 219, 821, -1, 36, 1, 65 }, ++ { 0x0, 0x0, 219, 822, 2328, 0, 0, -1 }, ++ { 0x1, 0x1, 219, 823, -1, 36, 1, 65 }, ++ { 0x1, 0x1, 219, 824, 2331, 36, 1, 65 }, ++ { 0x1, 0x1, 219, 825, 2334, 36, 1, 65 }, ++ { 0x0, 0x0, 219, 1406, -1, 0, 1, 33 }, ++ { 0x1, 0x1, 219, 826, 2367, 36, 1, 65 }, ++ { 0x1, 0x1, 219, 827, -1, 31, 1, 137 }, ++ { 0x1, 0x1, 219, 226, 1431, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 227, 1440, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 228, 1449, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 229, 1462, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 230, 1471, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 231, 1480, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 232, 1489, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 233, 1498, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 234, 1507, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 235, 1516, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 236, 1526, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 237, 1536, 32, 1, 126 }, ++ { 0x1, 0x1, 219, 238, 1549, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 239, 1555, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 240, 1561, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 241, 1567, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 242, 1573, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 243, 1579, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 244, 1585, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 245, 1591, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 246, 1597, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 247, 1603, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 248, 1609, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 249, 1615, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 250, 1621, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 251, 1627, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 252, 1633, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 253, 1639, 32, 1, 141 }, ++ { 0x1, 0x1, 219, 254, 1645, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 255, 1651, 32, 1, 146 }, ++ { 0x1, 0x1, 219, 831, -1, 31, 1, 155 }, ++ { 0x0, 0x0, 220, 2370, -1, 0, 1, 65 }, ++ { 0x0, 0x0, 220, 2371, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 25, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2373, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2374, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2375, -1, 0, 1, 44 }, ++ { 0x0, 0x0, 220, 2376, -1, 0, 1, 39 }, ++ { 0x1, 0x1, 220, 2377, -1, 12, 1, 58 }, ++ { 0x0, 0x0, 220, 2378, -1, 0, 1, 53 }, ++ { 0x1000001, 0x1000001, 220, 2379, -1, 12, 1, 58 }, ++ { 0x1, 0x1, 220, 2380, -1, 36, 1, 53 }, ++ { 0x200001, 0x200001, 220, 2381, -1, 12, 1, 58 }, ++ { 0x1, 0x1, 220, 2382, -1, 33, 1, 53 }, ++ { 0x1200001, 0x1200001, 220, 2383, -1, 12, 1, 48 }, ++ { 0x9, 0x9, 220, 2384, -1, 33, 1, 48 }, ++ { 0x0, 0x0, 220, 2385, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2386, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2387, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2388, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2389, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2390, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2391, -1, 0, 1, 48 }, ++ { 0x0, 0x0, 220, 2392, -1, 0, 1, 48 }, ++ { 0x1, 0x1, 220, 2393, -1, 12, 1, 58 }, ++ { 0x0, 0x0, 220, 2394, -1, 0, 1, 53 }, ++ { 0x200001, 0x1200001, 220, 2395, -1, 12, 1, 58 }, ++ { 0x1, 0x9, 220, 2396, -1, 33, 1, 53 }, ++ { 0x0, 0x0, 220, 2397, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2398, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2399, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2400, -1, 0, 1, 53 }, ++ { 0x1, 0x1, 220, 2401, -1, 12, 1, 58 }, ++ { 0x0, 0x0, 220, 2402, -1, 0, 1, 53 }, ++ { 0x1000001, 0x1000001, 220, 2403, -1, 12, 1, 58 }, ++ { 0x1, 0x1, 220, 2404, -1, 36, 1, 53 }, ++ { 0x200001, 0x200001, 220, 2405, -1, 12, 1, 58 }, ++ { 0x1, 0x1, 220, 2406, -1, 33, 1, 53 }, ++ { 0x1200001, 0x1200001, 220, 2407, -1, 12, 1, 48 }, ++ { 0x9, 0x9, 220, 2408, -1, 33, 1, 48 }, ++ { 0x0, 0x0, 220, 2409, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2410, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2411, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2412, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2413, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2414, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2415, -1, 0, 1, 48 }, ++ { 0x0, 0x0, 220, 2416, -1, 0, 1, 48 }, ++ { 0x1, 0x1, 220, 2417, -1, 12, 1, 58 }, ++ { 0x0, 0x0, 220, 2418, -1, 0, 1, 53 }, ++ { 0x200001, 0x1200001, 220, 2419, -1, 12, 1, 58 }, ++ { 0x1, 0x9, 220, 2420, -1, 33, 1, 53 }, ++ { 0x0, 0x0, 220, 2421, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2422, -1, 0, 1, 53 }, ++ { 0x0, 0x0, 220, 2423, -1, 0, 1, 58 }, ++ { 0x0, 0x0, 220, 2424, -1, 0, 1, 53 }, ++ { 0x1, 0x1, 220, 2425, -1, 28, 1, 28 }, ++ { 0x0, 0x0, 220, 2426, -1, 0, 1, 28 }, ++ { 0x3, 0x3, 220, 2427, -1, 27, 1, 28 }, ++ { 0x1, 0x1, 220, 2428, -1, 27, 1, 28 }, ++ { 0x0, 0x0, 220, 2429, -1, 0, 1, 65 }, ++ { 0x0, 0x0, 220, 2430, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2431, -1, 0, 1, 28 }, ++ { 0x1, 0x1, 220, 2432, -1, 36, 1, 65 }, ++ { 0x1, 0x1, 220, 2433, -1, 37, 1, 28 }, ++ { 0x0, 0x0, 220, 2434, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2435, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2436, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2437, -1, 0, 1, 65 }, ++ { 0x0, 0x0, 220, 2438, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 37, -1, 0, 1, 28 }, ++ { 0x1, 0x1, 220, 2440, -1, 36, 1, 65 }, ++ { 0x1, 0x1, 220, 2441, -1, 37, 1, 28 }, ++ { 0x0, 0x0, 220, 2442, -1, 0, 1, 28 }, ++ { 0x1, 0x1, 220, 2443, -1, 36, 1, 65 }, ++ { 0x1, 0x1, 220, 2444, -1, 37, 1, 28 }, ++ { 0x0, 0x0, 220, 2445, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2446, -1, 0, 1, 65 }, ++ { 0x0, 0x0, 220, 2447, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 42, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2449, -1, 0, 1, 65 }, ++ { 0x0, 0x0, 220, 2450, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 43, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2452, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2453, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2454, -1, 0, 1, 48 }, ++ { 0x1, 0x1, 220, 2455, -1, 27, 1, 48 }, ++ { 0x1, 0x1, 220, 2456, -1, 28, 1, 48 }, ++ { 0x3, 0x3, 220, 2457, -1, 27, 1, 48 }, ++ { 0x1, 0x1, 220, 2458, -1, 29, 1, 48 }, ++ { 0x5, 0x5, 220, 2459, -1, 27, 1, 48 }, ++ { 0x3, 0x3, 220, 2460, -1, 28, 1, 48 }, ++ { 0x7, 0x7, 220, 2461, -1, 27, 1, 48 }, ++ { 0x0, 0x0, 220, 2462, -1, 0, 1, 48 }, ++ { 0x0, 0x0, 220, 2463, -1, 0, 1, 48 }, ++ { 0x0, 0x0, 220, 2464, -1, 0, 1, 48 }, ++ { 0x0, 0x0, 220, 2465, -1, 0, 1, 48 }, ++ { 0x1, 0x1, 220, 2466, -1, 28, 1, 28 }, ++ { 0x0, 0x0, 220, 2467, -1, 0, 1, 28 }, ++ { 0x3, 0x3, 220, 2468, -1, 27, 1, 28 }, ++ { 0x1, 0x1, 220, 2469, -1, 27, 1, 28 }, ++ { 0x0, 0x0, 220, 2470, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2471, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2472, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 52, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2474, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2475, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 57, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 2477, -1, 0, 1, 23 }, ++ { 0x0, 0x0, 220, 2478, -1, 0, 1, 23 }, ++ { 0x0, 0x0, 220, 2479, -1, 0, 1, 23 }, ++ { 0x0, 0x0, 220, 2480, -1, 0, 1, 23 }, ++ { 0x0, 0x0, 220, 2481, -1, 0, 1, 34 }, ++ { 0x0, 0x0, 220, 2482, -1, 0, 1, 65 }, ++ { 0x0, 0x0, 220, 2483, -1, 0, 1, 28 }, ++ { 0x0, 0x0, 220, 64, -1, 0, 1, 28 }, ++ { 0x1, 0x1, 221, 2485, -1, 34, 1, 65 }, ++ { 0x1, 0x1, 221, 2486, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2487, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2488, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2489, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2490, -1, 34, 1, 45 }, ++ { 0x1, 0x1, 221, 2491, -1, 34, 1, 41 }, ++ { 0x400001, 0x400001, 221, 2492, -1, 12, 1, 60 }, ++ { 0x1, 0x1, 221, 2493, -1, 34, 1, 55 }, ++ { 0x1400001, 0x1400001, 221, 2494, -1, 12, 1, 60 }, ++ { 0x5, 0x5, 221, 2495, -1, 34, 1, 55 }, ++ { 0x600001, 0x600001, 221, 2496, -1, 12, 1, 60 }, ++ { 0x3, 0x3, 221, 2497, -1, 33, 1, 55 }, ++ { 0x1600001, 0x1600001, 221, 2498, -1, 12, 1, 50 }, ++ { 0xb, 0xb, 221, 2499, -1, 33, 1, 50 }, ++ { 0x1, 0x1, 221, 2500, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2501, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2502, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2503, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2504, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2505, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2506, -1, 34, 1, 50 }, ++ { 0x1, 0x1, 221, 2507, -1, 34, 1, 50 }, ++ { 0x400001, 0x400001, 221, 2508, -1, 12, 1, 60 }, ++ { 0x1, 0x1, 221, 2509, -1, 34, 1, 55 }, ++ { 0x600001, 0x1600001, 221, 2510, -1, 12, 1, 60 }, ++ { 0x3, 0xb, 221, 2511, -1, 33, 1, 55 }, ++ { 0x1, 0x1, 221, 2512, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2513, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2514, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2515, -1, 34, 1, 55 }, ++ { 0x400001, 0x400001, 221, 2516, -1, 12, 1, 60 }, ++ { 0x1, 0x1, 221, 2517, -1, 34, 1, 55 }, ++ { 0x1400001, 0x1400001, 221, 2518, -1, 12, 1, 60 }, ++ { 0x5, 0x5, 221, 2519, -1, 34, 1, 55 }, ++ { 0x600001, 0x600001, 221, 2520, -1, 12, 1, 60 }, ++ { 0x3, 0x3, 221, 2521, -1, 33, 1, 55 }, ++ { 0x1600001, 0x1600001, 221, 2522, -1, 12, 1, 50 }, ++ { 0xb, 0xb, 221, 2523, -1, 33, 1, 50 }, ++ { 0x1, 0x1, 221, 2524, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2525, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2526, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2527, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2528, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2529, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2530, -1, 34, 1, 50 }, ++ { 0x1, 0x1, 221, 2531, -1, 34, 1, 50 }, ++ { 0x400001, 0x400001, 221, 2532, -1, 12, 1, 60 }, ++ { 0x1, 0x1, 221, 2533, -1, 34, 1, 55 }, ++ { 0x600001, 0x1600001, 221, 2534, -1, 12, 1, 60 }, ++ { 0x3, 0xb, 221, 2535, -1, 33, 1, 55 }, ++ { 0x1, 0x1, 221, 2536, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2537, -1, 34, 1, 55 }, ++ { 0x1, 0x1, 221, 2538, -1, 34, 1, 60 }, ++ { 0x1, 0x1, 221, 2539, -1, 34, 1, 55 }, ++ { 0x41, 0x41, 221, 2540, -1, 28, 1, 30 }, ++ { 0x1, 0x1, 221, 2541, -1, 34, 1, 30 }, ++ { 0x83, 0x83, 221, 2542, -1, 27, 1, 30 }, ++ { 0x81, 0x81, 221, 2543, -1, 27, 1, 30 }, ++ { 0x1, 0x1, 221, 2544, -1, 34, 1, 65 }, ++ { 0x1, 0x1, 221, 2545, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2546, -1, 34, 1, 30 }, ++ { 0x5, 0x5, 221, 2547, -1, 34, 1, 65 }, ++ { 0x9, 0x9, 221, 2548, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2549, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2550, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2551, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2552, -1, 34, 1, 65 }, ++ { 0x1, 0x1, 221, 2553, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2554, -1, 34, 1, 30 }, ++ { 0x5, 0x5, 221, 2555, -1, 34, 1, 65 }, ++ { 0x9, 0x9, 221, 2556, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2557, -1, 34, 1, 30 }, ++ { 0x5, 0x5, 221, 2558, -1, 34, 1, 65 }, ++ { 0x9, 0x9, 221, 2559, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2560, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2561, -1, 34, 1, 65 }, ++ { 0x1, 0x1, 221, 2562, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2563, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2564, -1, 34, 1, 65 }, ++ { 0x1, 0x1, 221, 2565, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2566, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2567, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2568, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2569, -1, 34, 1, 50 }, ++ { 0x81, 0x81, 221, 2570, -1, 27, 1, 50 }, ++ { 0x41, 0x41, 221, 2571, -1, 28, 1, 50 }, ++ { 0x83, 0x83, 221, 2572, -1, 27, 1, 50 }, ++ { 0x21, 0x21, 221, 2573, -1, 29, 1, 50 }, ++ { 0x85, 0x85, 221, 2574, -1, 27, 1, 50 }, ++ { 0x43, 0x43, 221, 2575, -1, 28, 1, 50 }, ++ { 0x87, 0x87, 221, 2576, -1, 27, 1, 50 }, ++ { 0x1, 0x1, 221, 2577, -1, 34, 1, 50 }, ++ { 0x1, 0x1, 221, 2578, -1, 34, 1, 50 }, ++ { 0x1, 0x1, 221, 2579, -1, 34, 1, 50 }, ++ { 0x1, 0x1, 221, 2580, -1, 34, 1, 50 }, ++ { 0x41, 0x41, 221, 2581, -1, 28, 1, 30 }, ++ { 0x1, 0x1, 221, 2582, -1, 34, 1, 30 }, ++ { 0x83, 0x83, 221, 2583, -1, 27, 1, 30 }, ++ { 0x81, 0x81, 221, 2584, -1, 27, 1, 30 }, ++ { 0x1, 0x1, 221, 2585, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2586, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2587, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2588, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2589, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2590, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2591, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2592, -1, 34, 1, 25 }, ++ { 0x1, 0x1, 221, 2593, -1, 34, 1, 25 }, ++ { 0x1, 0x1, 221, 2594, -1, 34, 1, 25 }, ++ { 0x1, 0x1, 221, 2595, -1, 34, 1, 25 }, ++ { 0x1, 0x1, 221, 2596, -1, 34, 1, 36 }, ++ { 0x1, 0x1, 221, 2597, -1, 34, 1, 65 }, ++ { 0x1, 0x1, 221, 2598, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 221, 2599, -1, 34, 1, 30 }, ++ { 0x1, 0x1, 222, 2600, -1, 35, 1, 65 }, ++ { 0x1, 0x1, 222, 2601, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2602, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2603, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2604, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2605, -1, 35, 1, 46 }, ++ { 0x1, 0x1, 222, 2606, -1, 35, 1, 42 }, ++ { 0x800001, 0x800001, 222, 2607, -1, 12, 1, 61 }, ++ { 0x1, 0x1, 222, 2608, -1, 35, 1, 56 }, ++ { 0x1800001, 0x1800001, 222, 2609, -1, 12, 1, 61 }, ++ { 0x3, 0x3, 222, 2610, -1, 35, 1, 56 }, ++ { 0xa00001, 0xa00001, 222, 2611, -1, 12, 1, 61 }, ++ { 0x5, 0x5, 222, 2612, -1, 33, 1, 56 }, ++ { 0x1a00001, 0x1a00001, 222, 2613, -1, 12, 1, 51 }, ++ { 0xd, 0xd, 222, 2614, -1, 33, 1, 51 }, ++ { 0x1, 0x1, 222, 2615, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2616, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2617, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2618, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2619, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2620, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2621, -1, 35, 1, 51 }, ++ { 0x1, 0x1, 222, 2622, -1, 35, 1, 51 }, ++ { 0x800001, 0x800001, 222, 2623, -1, 12, 1, 61 }, ++ { 0x1, 0x1, 222, 2624, -1, 35, 1, 56 }, ++ { 0xa00001, 0x1a00001, 222, 2625, -1, 12, 1, 61 }, ++ { 0x5, 0xd, 222, 2626, -1, 33, 1, 56 }, ++ { 0x1, 0x1, 222, 2627, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2628, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2629, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2630, -1, 35, 1, 56 }, ++ { 0x800001, 0x800001, 222, 2631, -1, 12, 1, 61 }, ++ { 0x1, 0x1, 222, 2632, -1, 35, 1, 56 }, ++ { 0x1800001, 0x1800001, 222, 2633, -1, 12, 1, 61 }, ++ { 0x3, 0x3, 222, 2634, -1, 35, 1, 56 }, ++ { 0xa00001, 0xa00001, 222, 2635, -1, 12, 1, 61 }, ++ { 0x5, 0x5, 222, 2636, -1, 33, 1, 56 }, ++ { 0x1a00001, 0x1a00001, 222, 2637, -1, 12, 1, 51 }, ++ { 0xd, 0xd, 222, 2638, -1, 33, 1, 51 }, ++ { 0x1, 0x1, 222, 2639, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2640, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2641, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2642, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2643, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2644, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2645, -1, 35, 1, 51 }, ++ { 0x1, 0x1, 222, 2646, -1, 35, 1, 51 }, ++ { 0x800001, 0x800001, 222, 2647, -1, 12, 1, 61 }, ++ { 0x1, 0x1, 222, 2648, -1, 35, 1, 56 }, ++ { 0xa00001, 0x1a00001, 222, 2649, -1, 12, 1, 61 }, ++ { 0x5, 0xd, 222, 2650, -1, 33, 1, 56 }, ++ { 0x1, 0x1, 222, 2651, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2652, -1, 35, 1, 56 }, ++ { 0x1, 0x1, 222, 2653, -1, 35, 1, 61 }, ++ { 0x1, 0x1, 222, 2654, -1, 35, 1, 56 }, ++ { 0x81, 0x81, 222, 2655, -1, 28, 1, 31 }, ++ { 0x1, 0x1, 222, 2656, -1, 35, 1, 31 }, ++ { 0x103, 0x103, 222, 2657, -1, 27, 1, 31 }, ++ { 0x101, 0x101, 222, 2658, -1, 27, 1, 31 }, ++ { 0x1, 0x1, 222, 2659, -1, 35, 1, 65 }, ++ { 0x1, 0x1, 222, 2660, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2661, -1, 35, 1, 31 }, ++ { 0x3, 0x3, 222, 2662, -1, 35, 1, 65 }, ++ { 0x5, 0x5, 222, 2663, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2664, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2665, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2666, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2667, -1, 35, 1, 65 }, ++ { 0x1, 0x1, 222, 2668, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2669, -1, 35, 1, 31 }, ++ { 0x3, 0x3, 222, 2670, -1, 35, 1, 65 }, ++ { 0x5, 0x5, 222, 2671, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2672, -1, 35, 1, 31 }, ++ { 0x3, 0x3, 222, 2673, -1, 35, 1, 65 }, ++ { 0x5, 0x5, 222, 2674, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2675, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2676, -1, 35, 1, 65 }, ++ { 0x1, 0x1, 222, 2677, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2678, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2679, -1, 35, 1, 65 }, ++ { 0x1, 0x1, 222, 2680, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2681, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2682, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2683, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2684, -1, 35, 1, 51 }, ++ { 0x101, 0x101, 222, 2685, -1, 27, 1, 51 }, ++ { 0x81, 0x81, 222, 2686, -1, 28, 1, 51 }, ++ { 0x103, 0x103, 222, 2687, -1, 27, 1, 51 }, ++ { 0x41, 0x41, 222, 2688, -1, 29, 1, 51 }, ++ { 0x105, 0x105, 222, 2689, -1, 27, 1, 51 }, ++ { 0x83, 0x83, 222, 2690, -1, 28, 1, 51 }, ++ { 0x107, 0x107, 222, 2691, -1, 27, 1, 51 }, ++ { 0x1, 0x1, 222, 2692, -1, 35, 1, 51 }, ++ { 0x1, 0x1, 222, 2693, -1, 35, 1, 51 }, ++ { 0x1, 0x1, 222, 2694, -1, 35, 1, 51 }, ++ { 0x1, 0x1, 222, 2695, -1, 35, 1, 51 }, ++ { 0x81, 0x81, 222, 2696, -1, 28, 1, 31 }, ++ { 0x1, 0x1, 222, 2697, -1, 35, 1, 31 }, ++ { 0x103, 0x103, 222, 2698, -1, 27, 1, 31 }, ++ { 0x101, 0x101, 222, 2699, -1, 27, 1, 31 }, ++ { 0x1, 0x1, 222, 2700, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2701, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2702, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2703, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2704, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2705, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2706, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2707, -1, 35, 1, 26 }, ++ { 0x1, 0x1, 222, 2708, -1, 35, 1, 26 }, ++ { 0x1, 0x1, 222, 2709, -1, 35, 1, 26 }, ++ { 0x1, 0x1, 222, 2710, -1, 35, 1, 26 }, ++ { 0x1, 0x1, 222, 2711, -1, 35, 1, 37 }, ++ { 0x1, 0x1, 222, 2712, -1, 35, 1, 65 }, ++ { 0x1, 0x1, 222, 2713, -1, 35, 1, 31 }, ++ { 0x1, 0x1, 222, 2714, -1, 35, 1, 31 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 65 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2209, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 47 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 43 }, ++ { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x3, 0x3, 223, 2930, -1, 34, 1, 57 }, ++ { 0x1c00001, 0x1c00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x7, 0x7, 223, 2931, -1, 34, 1, 57 }, ++ { 0xe00001, 0xe00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x7, 0x7, 223, 2932, -1, 33, 1, 57 }, ++ { 0x1e00001, 0x1e00001, 223, -1, -1, 12, 1, 52 }, ++ { 0xf, 0xf, 223, 2933, -1, 33, 1, 52 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2934, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2935, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2936, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0x3, 0x3, 223, 2937, -1, 34, 1, 52 }, ++ { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x3, 0x3, 223, 2942, -1, 34, 1, 57 }, ++ { 0xe00001, 0x1e00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x7, 0xf, 223, 2943, -1, 33, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2944, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2945, -1, 34, 1, 57 }, ++ { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x3, 0x3, 223, 2948, -1, 34, 1, 57 }, ++ { 0x1c00001, 0x1c00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x7, 0x7, 223, 2949, -1, 34, 1, 57 }, ++ { 0xe00001, 0xe00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x7, 0x7, 223, 2950, -1, 33, 1, 57 }, ++ { 0x1e00001, 0x1e00001, 223, -1, -1, 12, 1, 52 }, ++ { 0xf, 0xf, 223, 2951, -1, 33, 1, 52 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2952, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2953, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2954, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0x3, 0x3, 223, 2955, -1, 34, 1, 52 }, ++ { 0xc00001, 0xc00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x3, 0x3, 223, 2960, -1, 34, 1, 57 }, ++ { 0xe00001, 0x1e00001, 223, -1, -1, 12, 1, 62 }, ++ { 0x7, 0xf, 223, 2961, -1, 33, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2962, -1, 34, 1, 57 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 62 }, ++ { 0x3, 0x3, 223, 2963, -1, 34, 1, 57 }, ++ { 0xc1, 0xc1, 223, -1, -1, 28, 1, 32 }, ++ { 0x3, 0x3, 223, 2828, -1, 34, 1, 32 }, ++ { 0x183, 0x183, 223, -1, -1, 27, 1, 32 }, ++ { 0x181, 0x181, 223, 2829, -1, 27, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 65 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2210, -1, 34, 1, 32 }, ++ { 0x7, 0x7, 223, -1, -1, 34, 1, 65 }, ++ { 0xb, 0xb, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2211, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 65 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2214, -1, 34, 1, 32 }, ++ { 0x7, 0x7, 223, -1, -1, 34, 1, 65 }, ++ { 0xb, 0xb, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2215, -1, 34, 1, 32 }, ++ { 0x7, 0x7, 223, -1, -1, 34, 1, 65 }, ++ { 0xb, 0xb, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2217, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 65 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2219, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 65 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2220, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0x181, 0x181, 223, -1, -1, 27, 1, 52 }, ++ { 0xc1, 0xc1, 223, -1, -1, 28, 1, 52 }, ++ { 0x183, 0x183, 223, -1, -1, 27, 1, 52 }, ++ { 0x61, 0x61, 223, -1, -1, 29, 1, 52 }, ++ { 0x185, 0x185, 223, -1, -1, 27, 1, 52 }, ++ { 0xc3, 0xc3, 223, -1, -1, 28, 1, 52 }, ++ { 0x187, 0x187, 223, -1, -1, 27, 1, 52 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 52 }, ++ { 0xc1, 0xc1, 223, -1, -1, 28, 1, 32 }, ++ { 0x3, 0x3, 223, 2832, -1, 34, 1, 32 }, ++ { 0x183, 0x183, 223, -1, -1, 27, 1, 32 }, ++ { 0x181, 0x181, 223, 2833, -1, 27, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 27 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 27 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 27 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 27 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 38 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 65 }, ++ { 0x3, 0x3, 223, -1, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 223, 2222, -1, 34, 1, 32 }, ++ { 0x3, 0x3, 224, 522, 1433, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 523, 1442, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 524, 1451, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 525, 1464, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 526, 1473, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 527, 1482, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 528, 1491, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 529, 1500, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 530, 1509, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 531, 1518, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 532, 1528, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 533, 1538, 32, 1, 128 }, ++ { 0x3, 0x3, 224, 546, 1551, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 547, 1557, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 548, 1563, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 549, 1569, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 550, 1575, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 551, 1581, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 552, 1587, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 553, 1593, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 554, 1599, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 555, 1605, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 556, 1611, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 557, 1617, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 558, 1623, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 559, 1629, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 560, 1635, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 561, 1641, 32, 1, 143 }, ++ { 0x3, 0x3, 224, 562, 1647, 32, 1, 148 }, ++ { 0x3, 0x3, 224, 563, 1653, 32, 1, 148 }, ++ { 0x1, 0x1, 225, -1, -1, 28, 1, 33 }, ++ { 0x1, 0x1, 225, -1, -1, 28, 1, 33 }, ++ { 0x0, 0x0, 232, 940, -1, 0, 1, 137 }, ++ { 0x0, 0x0, 232, 941, -1, 0, 1, 155 }, ++ { 0x1, 0x1, 233, -1, 1964, 33, 1, 133 }, ++ { 0x1, 0x1, 233, -1, 1967, 33, 1, 139 }, ++ { 0x0, 0x0, 233, -1, 1969, 0, 1, 150 }, ++ { 0x0, 0x0, 233, -1, 1970, 0, 1, 156 }, ++ { 0x0, 0x0, 234, 865, 953, 0, 0, -1 }, ++ { 0x0, 0x0, 234, 866, 961, 0, 0, -1 }, ++ { 0x0, 0x0, 234, 867, 957, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 868, 602, 33, 1, 6 }, ++ { 0x8000001, 0x8000001, 234, 869, 610, 6, 1, 7 }, ++ { 0x1, 0x1, 234, 870, 606, 33, 1, 6 }, ++ { 0x0, 0x0, 234, 871, 965, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 872, 622, 33, 1, 8 }, ++ { 0x0, 0x0, 234, 873, 969, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 874, 634, 33, 1, 15 }, ++ { 0x0, 0x0, 234, 875, 974, 0, 0, -1 }, ++ { 0x0, 0x0, 234, 876, 978, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 877, 657, 33, 1, 17 }, ++ { 0x1, 0x1, 234, 878, 661, 33, 1, 17 }, ++ { 0x0, 0x0, 234, 879, 982, 0, 0, -1 }, ++ { 0x0, 0x0, 234, 880, 986, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 881, 681, 33, 1, 18 }, ++ { 0x8000001, 0x8000001, 234, 882, 685, 6, 1, 18 }, ++ { 0x0, 0x0, 234, 883, 990, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 884, 697, 33, 1, 19 }, ++ { 0x0, 0x0, 234, 885, 994, 0, 0, -1 }, ++ { 0x0, 0x0, 234, 886, 998, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 887, 717, 33, 1, 20 }, ++ { 0x8000001, 0x8000001, 234, 888, 721, 6, 1, 20 }, ++ { 0x0, 0x0, 234, 889, 1002, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 890, 733, 33, 1, 21 }, ++ { 0x0, 0x0, 234, 891, 1007, 0, 0, -1 }, ++ { 0x0, 0x0, 234, 892, 1011, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 893, 756, 33, 1, 17 }, ++ { 0x1, 0x1, 234, 894, 760, 33, 1, 17 }, ++ { 0x0, 0x0, 234, 895, 1015, 0, 0, -1 }, ++ { 0x1, 0x1, 234, 896, 772, 33, 1, 21 }, ++ { 0x0, 0x0, 235, 2753, 952, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2754, 960, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2755, 956, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2756, 601, 0, 1, 6 }, ++ { 0x1, 0x1, 235, 2757, 609, 6, 1, 7 }, ++ { 0x0, 0x0, 235, 2758, 605, 0, 1, 6 }, ++ { 0x0, 0x0, 235, 2759, 964, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2760, 621, 0, 1, 8 }, ++ { 0x0, 0x0, 235, 2761, 968, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2762, 633, 0, 1, 15 }, ++ { 0x0, 0x0, 235, 2763, 973, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2764, 977, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2765, 656, 0, 1, 17 }, ++ { 0x0, 0x0, 235, 2766, 660, 0, 1, 17 }, ++ { 0x0, 0x0, 235, 2767, 981, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2768, 985, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2769, 680, 0, 1, 18 }, ++ { 0x1, 0x1, 235, 2770, 684, 6, 1, 18 }, ++ { 0x0, 0x0, 235, 2771, 989, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2772, 696, 0, 1, 19 }, ++ { 0x0, 0x0, 235, 2773, 993, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2774, 997, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2775, 716, 0, 1, 20 }, ++ { 0x1, 0x1, 235, 2776, 720, 6, 1, 20 }, ++ { 0x0, 0x0, 235, 2777, 1001, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2778, 732, 0, 1, 21 }, ++ { 0x0, 0x0, 235, 2779, 1006, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2780, 1010, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2781, 755, 0, 1, 17 }, ++ { 0x0, 0x0, 235, 2782, 759, 0, 1, 17 }, ++ { 0x0, 0x0, 235, 2783, 1014, 0, 0, -1 }, ++ { 0x0, 0x0, 235, 2784, 771, 0, 1, 21 }, ++ { 0x1, 0x1, 235, 897, 1137, 27, 1, 16 }, ++ { 0x0, 0x0, 235, 898, 1135, 0, 1, 16 }, ++ { 0x0, 0x0, 235, 1202, 1139, 0, 1, 22 }, ++ { 0x0, 0x1, 235, 1147, 1145, 20, 1, 67 }, ++ { 0x0, 0x0, 235, 111, 1143, 0, 1, 67 }, ++ { 0x1, 0x1, 238, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x0, 238, -1, -1, 0, 1, 0 }, ++ { 0x1, 0x1, 238, 2984, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 238, 2985, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 238, 2986, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 238, 2987, -1, 27, 1, 0 }, ++ { 0x0, 0x0, 260, -1, 2310, 0, 0, -1 }, ++ { 0x0, 0x0, 260, -1, 2312, 0, 0, -1 }, ++ { 0x1, 0x1, 260, -1, -1, 28, 1, 29 }, ++ { 0x1, 0x1, 260, -1, -1, 28, 1, 29 }, ++ { 0x0, 0x0, 260, -1, 2351, 0, 0, -1 }, ++ { 0x0, 0x0, 260, -1, 2353, 0, 0, -1 }, ++ { 0x1, 0x1, 260, -1, -1, 28, 1, 29 }, ++ { 0x1, 0x1, 260, -1, -1, 28, 1, 29 }, ++ { 0x0, 0x0, 262, 23, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 262, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 262, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x1, 262, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x1, 262, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x1, 262, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x1, 262, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x1, 262, -1, -1, 29, 1, 0 }, ++ { 0x0, 0x0, 262, 180, -1, 0, 1, 0 }, ++ { 0x0, 0x1, 262, -1, -1, 29, 1, 0 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 299, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 321, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 347, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 369, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 64 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 64 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 64 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 64 }, ++ { 0x0, 0x0, 263, -1, 2262, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2264, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2266, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2268, 0, 0, -1 }, ++ { 0x1, 0x1, 263, -1, 2270, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2272, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2274, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2276, 12, 1, 49 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 49 }, ++ { 0x0, 0x0, 263, -1, 2278, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2280, 0, 0, -1 }, ++ { 0x1, 0x1, 263, -1, 2282, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2284, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x0, 0x0, 263, -1, 2286, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2288, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2290, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2292, 0, 0, -1 }, ++ { 0x1, 0x1, 263, -1, 2294, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2296, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2298, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2300, 12, 1, 49 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 49 }, ++ { 0x0, 0x0, 263, -1, 2302, 0, 0, -1 }, ++ { 0x0, 0x0, 263, -1, 2304, 0, 0, -1 }, ++ { 0x1, 0x1, 263, -1, 2306, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, 2308, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, -1, -1, 12, 1, 59 }, ++ { 0x1, 0x1, 263, 391, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 393, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 507, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 509, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 399, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 401, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 515, -1, 12, 1, 2 }, ++ { 0x1, 0x1, 263, 517, -1, 12, 1, 2 }, ++ { 0x0, 0x0, 264, -1, 2269, 0, 0, -1 }, ++ { 0x9, 0x9, 264, -1, 2277, 33, 1, 49 }, ++ { 0x9, 0x9, 264, -1, 2941, 33, 1, 49 }, ++ { 0x0, 0x0, 264, 1381, 2342, 0, 0, -1 }, ++ { 0x3, 0x3, 264, 1382, -1, 27, 1, 49 }, ++ { 0x0, 0x0, 268, 2822, -1, 0, 1, 0 }, ++ { 0x3, 0x3, 269, -1, -1, 27, 1, 0 }, ++ { 0x3, 0x3, 269, -1, -1, 27, 1, 0 }, ++ { 0x3, 0x3, 269, -1, -1, 27, 1, 0 }, ++ { 0x3, 0x3, 269, -1, -1, 27, 1, 0 }, ++ { 0x1, 0x1, 270, 2980, -1, 28, 1, 0 }, ++ { 0x1, 0x1, 270, 2981, -1, 28, 1, 0 }, ++ { 0x1, 0x1, 270, 2982, -1, 28, 1, 0 }, ++ { 0x1, 0x1, 270, 2983, -1, 28, 1, 0 }, ++ { 0x1, 0x1, 271, -1, -1, 27, 1, 93 }, ++ { 0x1, 0x1, 271, -1, -1, 27, 1, 93 }, ++ { 0x0, 0x0, 271, -1, 950, 0, 0, -1 }, ++ { 0x0, 0x0, 272, 2993, 2799, 0, 0, -1 }, ++ { 0x0, 0x0, 272, 2994, 2801, 0, 0, -1 }, ++ { 0x0, 0x0, 273, -1, 2800, 0, 0, -1 }, ++ { 0x0, 0x0, 273, -1, 2802, 0, 0, -1 }, ++ { 0x0, 0x0, 274, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 274, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 274, -1, -1, 0, 1, 40 }, ++ { 0x0, 0x0, 279, -1, -1, 0, 1, 33 }, ++ { 0x0, 0x0, 283, -1, 2316, 0, 1, 29 }, ++ { 0x0, 0x0, 284, -1, -1, 0, 1, 0 }, ++ { 0x0, 0x0, 284, -1, -1, 0, 1, 71 }, ++ { 0x0, 0x0, 284, 1983, 2966, 0, 1, 1 }, ++ { 0x0, 0x0, 284, 1984, 2967, 0, 1, 1 }, ++ { 0x0, 0x0, 284, -1, 508, 0, 0, -1 }, ++ { 0x0, 0x0, 284, -1, 510, 0, 0, -1 }, ++ { 0x0, 0x0, 284, 1987, 2970, 0, 1, 1 }, ++ { 0x0, 0x0, 284, 1988, 2971, 0, 1, 1 }, ++ { 0x0, 0x0, 284, -1, 516, 0, 0, -1 }, ++ { 0x0, 0x0, 284, -1, 518, 0, 0, -1 }, ++}; ++ ++static const struct ia64_main_table ++main_table[] = { ++ { 5, 1, 1, 0x0000010000000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 0, }, ++ { 5, 1, 1, 0x0000010008000000ull, 0x000001eff8000000ull, { 24, 25, 26, 4, 0 }, 0x0, 1, }, ++ { 5, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 24, 66, 27, 0, 0 }, 0x0, 2, }, ++ { 5, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 24, 63, 26, 0, 0 }, 0x0, 3, }, ++ { 6, 1, 1, 0x0000012000000000ull, 0x000001e000000000ull, { 24, 66, 27, 0, 0 }, 0x0, 4, }, ++ { 7, 1, 1, 0x0000010040000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 5, }, ++ { 7, 1, 1, 0x0000010c00000000ull, 0x000001ee00000000ull, { 24, 63, 26, 0, 0 }, 0x0, 6, }, ++ { 8, 1, 1, 0x0000010800000000ull, 0x000001ee00000000ull, { 24, 63, 26, 0, 0 }, 0x0, 7, }, ++ { 9, 3, 1, 0x0000002c00000000ull, 0x000001ee00000000ull, { 24, 3, 52, 53, 54 }, 0x221, 8, }, ++ { 9, 3, 1, 0x0000002c00000000ull, 0x000001ee00000000ull, { 24, 52, 53, 54, 0 }, 0x261, 9, }, ++ { 10, 1, 1, 0x0000010060000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 10, }, ++ { 10, 1, 1, 0x0000010160000000ull, 0x000001eff8000000ull, { 24, 55, 26, 0, 0 }, 0x0, 11, }, ++ { 11, 1, 1, 0x0000010068000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 12, }, ++ { 11, 1, 1, 0x0000010168000000ull, 0x000001eff8000000ull, { 24, 55, 26, 0, 0 }, 0x0, 13, }, ++ { 14, 4, 0, 0x0000000100000000ull, 0x000001eff80011ffull, { 16, 0, 0, 0, 0 }, 0x40, 951, }, ++ { 14, 4, 0, 0x0000000100000000ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x0, 807, }, ++ { 14, 4, 0, 0x0000000100000000ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x40, 808, }, ++ { 14, 4, 0, 0x0000000108000100ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x200, 2200, }, ++ { 14, 4, 0, 0x0000000108000100ull, 0x000001eff80011c0ull, { 16, 0, 0, 0, 0 }, 0x240, 2201, }, ++ { 14, 4, 1, 0x0000002100000000ull, 0x000001ef00001000ull, { 15, 16, 0, 0, 0 }, 0x0, 564, }, ++ { 14, 4, 1, 0x0000002100000000ull, 0x000001ef00001000ull, { 15, 16, 0, 0, 0 }, 0x40, 565, }, ++ { 14, 4, 0, 0x0000008000000000ull, 0x000001ee000011ffull, { 81, 0, 0, 0, 0 }, 0x40, 972, }, ++ { 14, 4, 0, 0x0000008000000000ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x0, 809, }, ++ { 14, 4, 0, 0x0000008000000000ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x40, 810, }, ++ { 14, 4, 0, 0x0000008000000080ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x210, 2991, }, ++ { 14, 4, 0, 0x0000008000000080ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x250, 2992, }, ++ { 14, 4, 0, 0x0000008000000140ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x30, 572, }, ++ { 14, 4, 0, 0x0000008000000140ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x70, 573, }, ++ { 14, 4, 0, 0x0000008000000180ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x230, 570, }, ++ { 14, 4, 0, 0x0000008000000180ull, 0x000001ee000011c0ull, { 81, 0, 0, 0, 0 }, 0x270, 571, }, ++ { 14, 4, 1, 0x000000a000000000ull, 0x000001ee00001000ull, { 15, 81, 0, 0, 0 }, 0x0, 566, }, ++ { 14, 4, 1, 0x000000a000000000ull, 0x000001ee00001000ull, { 15, 81, 0, 0, 0 }, 0x40, 567, }, ++ { 15, 4, 0, 0x0000000000000000ull, 0x000001e1f8000000ull, { 65, 0, 0, 0, 0 }, 0x0, 519, }, ++ { 15, 5, 0, 0x0000000000000000ull, 0x000001e3f8000000ull, { 65, 0, 0, 0, 0 }, 0x0, 942, }, ++ { 15, 2, 0, 0x0000000000000000ull, 0x000001eff8000000ull, { 65, 0, 0, 0, 0 }, 0x2, 1120, }, ++ { 15, 3, 0, 0x0000000000000000ull, 0x000001eff8000000ull, { 65, 0, 0, 0, 0 }, 0x0, 1245, }, ++ { 15, 6, 0, 0x0000000000000000ull, 0x000001eff8000000ull, { 69, 0, 0, 0, 0 }, 0x0, 2995, }, ++ { 15, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 65, 0, 0, 0, 0 }, 0x0, 16, }, ++ { 16, 6, 0, 0x0000018000000000ull, 0x000001ee000011ffull, { 82, 0, 0, 0, 0 }, 0x40, 1005, }, ++ { 16, 6, 0, 0x0000018000000000ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x0, 811, }, ++ { 16, 6, 0, 0x0000018000000000ull, 0x000001ee000011c0ull, { 82, 0, 0, 0, 0 }, 0x40, 812, }, ++ { 16, 6, 1, 0x000001a000000000ull, 0x000001ee00001000ull, { 15, 82, 0, 0, 0 }, 0x0, 568, }, ++ { 16, 6, 1, 0x000001a000000000ull, 0x000001ee00001000ull, { 15, 82, 0, 0, 0 }, 0x40, 569, }, ++ { 17, 4, 0, 0x0000004080000000ull, 0x000001e9f8000018ull, { 16, 77, 0, 0, 0 }, 0x20, 2818, }, ++ { 17, 4, 0, 0x000000e000000000ull, 0x000001e800000018ull, { 81, 77, 0, 0, 0 }, 0x20, 2819, }, ++ { 18, 4, 0, 0x0000000060000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x2c, 222, }, ++ { 22, 2, 0, 0x0000000200000000ull, 0x000001ee00000000ull, { 25, 80, 0, 0, 0 }, 0x0, 2205, }, ++ { 22, 3, 0, 0x0000000800000000ull, 0x000001ee00000000ull, { 24, 81, 0, 0, 0 }, 0x0, 224, }, ++ { 22, 3, 0, 0x0000000c00000000ull, 0x000001ee00000000ull, { 18, 81, 0, 0, 0 }, 0x0, 225, }, ++ { 22, 3, 0, 0x0000002200000000ull, 0x000001ee00000000ull, { 25, 80, 0, 0, 0 }, 0x0, 2206, }, ++ { 22, 3, 0, 0x0000002600000000ull, 0x000001ee00000000ull, { 19, 80, 0, 0, 0 }, 0x0, 2207, }, ++ { 22, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 25, 80, 0, 0, 0 }, 0x0, 2208, }, ++ { 25, 4, 0, 0x0000000020000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x224, 18, }, ++ { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x0, 1204, }, ++ { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 25, 26, 0, 0 }, 0x40, 1205, }, ++ { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 22, 26, 25, 0 }, 0x0, 1163, }, ++ { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 26, 25, 0, 0 }, 0x40, 1164, }, ++ { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 23, 26, 25, 0 }, 0x0, 1072, }, ++ { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 22, 26, 25, 0, 0 }, 0x40, 1073, }, ++ { 26, 1, 2, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x0, 1034, }, ++ { 26, 1, 1, 0x0000018000000000ull, 0x000001fe00001000ull, { 23, 25, 26, 0, 0 }, 0x40, 1035, }, ++ { 26, 1, 2, 0x0000018200000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x40, 1358, }, ++ { 26, 1, 2, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x0, 1074, }, ++ { 26, 1, 1, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 7, 26, 0, 0 }, 0x40, 1075, }, ++ { 26, 1, 2, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 23, 26, 7, 0 }, 0x40, 1208, }, ++ { 26, 1, 1, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 26, 7, 0, 0 }, 0x40, 1209, }, ++ { 26, 1, 2, 0x0000019000000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x40, 1169, }, ++ { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 23, 55, 26, 0 }, 0x0, 1211, }, ++ { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 55, 26, 0, 0 }, 0x40, 1212, }, ++ { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 23, 57, 26, 0 }, 0x0, 1170, }, ++ { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 22, 57, 26, 0, 0 }, 0x40, 1171, }, ++ { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 22, 57, 26, 0 }, 0x0, 1079, }, ++ { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 57, 26, 0, 0 }, 0x40, 1080, }, ++ { 26, 1, 2, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 22, 55, 26, 0 }, 0x0, 1041, }, ++ { 26, 1, 1, 0x0000018800000000ull, 0x000001ee00001000ull, { 23, 55, 26, 0, 0 }, 0x40, 1042, }, ++ { 26, 1, 2, 0x0000018a00000000ull, 0x000001ee00001000ull, { 22, 23, 55, 26, 0 }, 0x40, 1363, }, ++ { 26, 1, 2, 0x000001a800000000ull, 0x000001ee00001000ull, { 22, 23, 59, 26, 0 }, 0x0, 1196, }, ++ { 26, 1, 1, 0x000001a800000000ull, 0x000001ee00001000ull, { 22, 59, 26, 0, 0 }, 0x40, 1197, }, ++ { 26, 1, 2, 0x000001a800000000ull, 0x000001ee00001000ull, { 23, 22, 59, 26, 0 }, 0x0, 1107, }, ++ { 26, 1, 1, 0x000001a800000000ull, 0x000001ee00001000ull, { 23, 59, 26, 0, 0 }, 0x40, 1108, }, ++ { 26, 1, 2, 0x000001c200000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x40, 1364, }, ++ { 26, 1, 2, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 22, 7, 26, 0 }, 0x40, 1172, }, ++ { 26, 1, 1, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 7, 26, 0, 0 }, 0x40, 1173, }, ++ { 26, 1, 2, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 22, 26, 7, 0 }, 0x40, 1045, }, ++ { 26, 1, 1, 0x000001d000000000ull, 0x000001fe00001000ull, { 23, 26, 7, 0, 0 }, 0x40, 1046, }, ++ { 26, 1, 2, 0x000001ca00000000ull, 0x000001ee00001000ull, { 23, 22, 55, 26, 0 }, 0x40, 1365, }, ++ { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x0, 1217, }, ++ { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 25, 26, 0, 0 }, 0x40, 1218, }, ++ { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 22, 26, 25, 0 }, 0x0, 1176, }, ++ { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 26, 25, 0, 0 }, 0x40, 1177, }, ++ { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 23, 26, 25, 0 }, 0x0, 1085, }, ++ { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 22, 26, 25, 0, 0 }, 0x40, 1086, }, ++ { 27, 1, 2, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x0, 1047, }, ++ { 27, 1, 1, 0x0000018400000000ull, 0x000001fe00001000ull, { 23, 25, 26, 0, 0 }, 0x40, 1048, }, ++ { 27, 1, 2, 0x0000018600000000ull, 0x000001fe00001000ull, { 22, 23, 25, 26, 0 }, 0x40, 1370, }, ++ { 27, 1, 2, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x0, 1087, }, ++ { 27, 1, 1, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 7, 26, 0, 0 }, 0x40, 1088, }, ++ { 27, 1, 2, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 23, 26, 7, 0 }, 0x40, 1221, }, ++ { 27, 1, 1, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 26, 7, 0, 0 }, 0x40, 1222, }, ++ { 27, 1, 2, 0x0000019400000000ull, 0x000001fe00001000ull, { 22, 23, 7, 26, 0 }, 0x40, 1182, }, ++ { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 23, 55, 26, 0 }, 0x0, 1224, }, ++ { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 55, 26, 0, 0 }, 0x40, 1225, }, ++ { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 23, 57, 26, 0 }, 0x0, 1183, }, ++ { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 22, 57, 26, 0, 0 }, 0x40, 1184, }, ++ { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 22, 57, 26, 0 }, 0x0, 1092, }, ++ { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 57, 26, 0, 0 }, 0x40, 1093, }, ++ { 27, 1, 2, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 22, 55, 26, 0 }, 0x0, 1054, }, ++ { 27, 1, 1, 0x0000018c00000000ull, 0x000001ee00001000ull, { 23, 55, 26, 0, 0 }, 0x40, 1055, }, ++ { 27, 1, 2, 0x0000018e00000000ull, 0x000001ee00001000ull, { 22, 23, 55, 26, 0 }, 0x40, 1375, }, ++ { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 23, 56, 26, 0 }, 0x0, 1241, }, ++ { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 56, 26, 0, 0 }, 0x40, 1242, }, ++ { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 23, 58, 26, 0 }, 0x0, 1200, }, ++ { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 22, 58, 26, 0, 0 }, 0x40, 1201, }, ++ { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 22, 58, 26, 0 }, 0x0, 1111, }, ++ { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 58, 26, 0, 0 }, 0x40, 1112, }, ++ { 27, 1, 2, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 22, 56, 26, 0 }, 0x0, 1070, }, ++ { 27, 1, 1, 0x000001ac00000000ull, 0x000001ee00001000ull, { 23, 56, 26, 0, 0 }, 0x40, 1071, }, ++ { 27, 1, 2, 0x000001c600000000ull, 0x000001fe00001000ull, { 23, 22, 25, 26, 0 }, 0x40, 1376, }, ++ { 27, 1, 2, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 22, 7, 26, 0 }, 0x40, 1185, }, ++ { 27, 1, 1, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 7, 26, 0, 0 }, 0x40, 1186, }, ++ { 27, 1, 2, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 22, 26, 7, 0 }, 0x40, 1058, }, ++ { 27, 1, 1, 0x000001d400000000ull, 0x000001fe00001000ull, { 23, 26, 7, 0, 0 }, 0x40, 1059, }, ++ { 27, 1, 2, 0x000001ce00000000ull, 0x000001ee00001000ull, { 23, 22, 55, 26, 0 }, 0x40, 1377, }, ++ { 28, 3, 1, 0x0000008808000000ull, 0x000001fff8000000ull, { 24, 33, 25, 1, 2 }, 0x0, 257, }, ++ { 28, 3, 1, 0x0000008808000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x40, 258, }, ++ { 29, 3, 1, 0x0000008008000000ull, 0x000001fff8000000ull, { 24, 33, 25, 2, 0 }, 0x0, 259, }, ++ { 29, 3, 1, 0x0000008008000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x40, 260, }, ++ { 30, 3, 1, 0x0000008048000000ull, 0x000001fff8000000ull, { 24, 33, 25, 2, 0 }, 0x0, 261, }, ++ { 30, 3, 1, 0x0000008048000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x40, 262, }, ++ { 31, 3, 1, 0x0000008088000000ull, 0x000001fff8000000ull, { 24, 33, 25, 2, 0 }, 0x0, 263, }, ++ { 31, 3, 1, 0x0000008088000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x40, 264, }, ++ { 32, 3, 1, 0x00000080c8000000ull, 0x000001fff8000000ull, { 24, 33, 25, 2, 0 }, 0x0, 265, }, ++ { 32, 3, 1, 0x00000080c8000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x40, 266, }, ++ { 34, 4, 0, 0x0000000010000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x224, 19, }, ++ { 36, 2, 1, 0x00000000c0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 1149, }, ++ { 37, 2, 1, 0x00000000c8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 1150, }, ++ { 39, 2, 1, 0x0000008000000000ull, 0x000001e000000000ull, { 24, 25, 26, 47, 72 }, 0x0, 20, }, ++ { 39, 2, 1, 0x000000a600000000ull, 0x000001ee04000000ull, { 24, 25, 45, 73, 0 }, 0x0, 3000, }, ++ { 39, 2, 1, 0x000000a604000000ull, 0x000001ee04000000ull, { 24, 55, 45, 73, 0 }, 0x0, 3001, }, ++ { 39, 2, 1, 0x000000ae00000000ull, 0x000001ee00000000ull, { 24, 48, 26, 46, 73 }, 0x0, 21, }, ++ { 43, 4, 0, 0x0000000080000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x20, 22, }, ++ { 48, 2, 1, 0x000000a400000000ull, 0x000001ee00002000ull, { 24, 26, 76, 73, 0 }, 0x0, 2836, }, ++ { 50, 5, 1, 0x0000000080000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 24, }, ++ { 51, 5, 1, 0x0000010008000000ull, 0x000001fff8000000ull, { 18, 20, 19, 0, 0 }, 0x40, 2257, }, ++ { 52, 5, 1, 0x00000000b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2258, }, ++ { 52, 5, 1, 0x00000000b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 26, }, ++ { 53, 5, 1, 0x00000000b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2259, }, ++ { 53, 5, 1, 0x00000000b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 27, }, ++ { 54, 5, 1, 0x0000000160000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 28, }, ++ { 55, 5, 1, 0x0000000168000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 29, }, ++ { 57, 3, 0, 0x0000002180000000ull, 0x000001fff8000000ull, { 26, 0, 0, 0, 0 }, 0x0, 30, }, ++ { 58, 5, 0, 0x0000000040000000ull, 0x000001eff8000000ull, { 79, 0, 0, 0, 0 }, 0x0, 2260, }, ++ { 58, 5, 0, 0x0000000040000000ull, 0x000001eff8000000ull, { 79, 0, 0, 0, 0 }, 0x40, 31, }, ++ { 59, 5, 2, 0x000000a000000000ull, 0x000001e000001000ull, { 22, 23, 19, 60, 0 }, 0x0, 1247, }, ++ { 59, 5, 1, 0x000000a000000000ull, 0x000001e000001000ull, { 22, 19, 60, 0, 0 }, 0x40, 1248, }, ++ { 59, 5, 2, 0x000000a000000000ull, 0x000001e000001000ull, { 23, 22, 19, 60, 0 }, 0x40, 1402, }, ++ { 59, 5, 1, 0x000000a000000000ull, 0x000001e000001000ull, { 23, 19, 60, 0, 0 }, 0x40, 1403, }, ++ { 60, 5, 0, 0x0000000028000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 2261, }, ++ { 60, 5, 0, 0x0000000028000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x40, 32, }, ++ { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 22, 23, 19, 20, 0 }, 0x0, 925, }, ++ { 61, 5, 1, 0x0000008000000000ull, 0x000001fe00001000ull, { 22, 19, 20, 0, 0 }, 0x40, 926, }, ++ { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 22, 23, 19, 20, 0 }, 0x40, 927, }, ++ { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 22, 23, 20, 19, 0 }, 0x0, 1098, }, ++ { 61, 5, 1, 0x0000009000000000ull, 0x000001fe00001000ull, { 22, 20, 19, 0, 0 }, 0x40, 1099, }, ++ { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 22, 23, 20, 19, 0 }, 0x40, 1100, }, ++ { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 23, 22, 19, 20, 0 }, 0x0, 1378, }, ++ { 61, 5, 1, 0x0000008000000000ull, 0x000001fe00001000ull, { 23, 19, 20, 0, 0 }, 0x40, 1379, }, ++ { 61, 5, 2, 0x0000008000000000ull, 0x000001fe00001000ull, { 23, 22, 19, 20, 0 }, 0x40, 1380, }, ++ { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 23, 22, 20, 19, 0 }, 0x0, 1387, }, ++ { 61, 5, 1, 0x0000009000000000ull, 0x000001fe00001000ull, { 23, 20, 19, 0, 0 }, 0x40, 1388, }, ++ { 61, 5, 2, 0x0000009000000000ull, 0x000001fe00001000ull, { 23, 22, 20, 19, 0 }, 0x40, 1389, }, ++ { 62, 5, 1, 0x00000000c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x0, 1024, }, ++ { 62, 5, 1, 0x00000000c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x40, 1025, }, ++ { 62, 5, 1, 0x00000000e0000000ull, 0x000001e3f8000000ull, { 18, 19, 0, 0, 0 }, 0x0, 2998, }, ++ { 62, 5, 1, 0x0000010008000000ull, 0x000001fff80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 2999, }, ++ { 63, 3, 1, 0x0000008488000000ull, 0x000001fff8000000ull, { 24, 33, 71, 0, 0 }, 0x0, 267, }, ++ { 64, 3, 1, 0x00000084c8000000ull, 0x000001fff8000000ull, { 24, 33, 71, 0, 0 }, 0x0, 268, }, ++ { 67, 3, 0, 0x0000000060000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x21, 33, }, ++ { 68, 5, 1, 0x0000010000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2319, }, ++ { 68, 5, 1, 0x0000010000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 34, }, ++ { 69, 5, 1, 0x00000000a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2320, }, ++ { 69, 5, 1, 0x00000000a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 35, }, ++ { 70, 5, 1, 0x0000000080000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2213, }, ++ { 71, 5, 1, 0x00000000a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2321, }, ++ { 71, 5, 1, 0x00000000a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 36, }, ++ { 72, 5, 1, 0x00000001c8000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 1203, }, ++ { 73, 5, 1, 0x0000010000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2324, }, ++ { 74, 5, 1, 0x0000014000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2327, }, ++ { 74, 5, 1, 0x0000014000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 38, }, ++ { 75, 5, 1, 0x0000000088000000ull, 0x000001e3f8000000ull, { 18, 20, 0, 0, 0 }, 0xc0, 39, }, ++ { 76, 5, 1, 0x0000000088000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 40, }, ++ { 77, 5, 1, 0x0000018000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2330, }, ++ { 77, 5, 1, 0x0000018000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 41, }, ++ { 78, 5, 1, 0x0000018000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2333, }, ++ { 79, 5, 1, 0x0000010008000000ull, 0x000001fff80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 2336, }, ++ { 80, 5, 1, 0x0000000170000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 44, }, ++ { 81, 5, 1, 0x0000002080000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 45, }, ++ { 82, 5, 1, 0x0000000140000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 46, }, ++ { 83, 5, 1, 0x00000020b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2337, }, ++ { 83, 5, 1, 0x00000020b8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 47, }, ++ { 84, 5, 1, 0x00000020b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2338, }, ++ { 84, 5, 1, 0x00000020b0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 48, }, ++ { 85, 5, 1, 0x0000002180000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 928, }, ++ { 85, 5, 1, 0x0000002180000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 929, }, ++ { 85, 5, 1, 0x0000002188000000ull, 0x000001eff8000000ull, { 18, 20, 19, 0, 0 }, 0x40, 1101, }, ++ { 86, 5, 1, 0x00000020c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x0, 1026, }, ++ { 86, 5, 1, 0x00000020c0000000ull, 0x000001eff8000000ull, { 18, 19, 0, 0, 0 }, 0x40, 1027, }, ++ { 87, 5, 1, 0x0000013000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2355, }, ++ { 87, 5, 1, 0x0000013000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 49, }, ++ { 88, 5, 1, 0x00000020a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2356, }, ++ { 88, 5, 1, 0x00000020a8000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 50, }, ++ { 89, 5, 1, 0x0000002080000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2221, }, ++ { 90, 5, 1, 0x00000020a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2357, }, ++ { 90, 5, 1, 0x00000020a0000000ull, 0x000001eff8000000ull, { 18, 19, 20, 0, 0 }, 0x40, 51, }, ++ { 91, 5, 1, 0x0000013000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2358, }, ++ { 92, 5, 1, 0x0000017000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2359, }, ++ { 92, 5, 1, 0x0000017000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 53, }, ++ { 93, 5, 1, 0x0000002088000000ull, 0x000001e3f8000000ull, { 18, 20, 0, 0, 0 }, 0xc0, 54, }, ++ { 94, 5, 1, 0x0000002088000000ull, 0x000001e3f80fe000ull, { 18, 20, 0, 0, 0 }, 0x40, 55, }, ++ { 95, 5, 1, 0x000001b000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 2360, }, ++ { 95, 5, 1, 0x000001b000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 56, }, ++ { 96, 5, 1, 0x000001b000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 2361, }, ++ { 97, 5, 2, 0x0000002200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x0, 2362, }, ++ { 97, 5, 2, 0x0000002200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x40, 58, }, ++ { 98, 5, 2, 0x0000003200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x0, 2363, }, ++ { 98, 5, 2, 0x0000003200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x40, 59, }, ++ { 99, 5, 2, 0x0000000200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x0, 2364, }, ++ { 99, 5, 2, 0x0000000200000000ull, 0x000001fe00000000ull, { 18, 23, 19, 20, 0 }, 0x40, 60, }, ++ { 100, 5, 2, 0x0000001200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x0, 2365, }, ++ { 100, 5, 2, 0x0000001200000000ull, 0x000001fe00000000ull, { 18, 23, 20, 0, 0 }, 0x40, 61, }, ++ { 101, 5, 1, 0x000001c000000000ull, 0x000001f000000000ull, { 18, 20, 21, 19, 0 }, 0x0, 62, }, ++ { 102, 5, 0, 0x0000000020000000ull, 0x000001eff8000000ull, { 50, 51, 0, 0, 0 }, 0x0, 2366, }, ++ { 102, 5, 0, 0x0000000020000000ull, 0x000001eff8000000ull, { 50, 51, 0, 0, 0 }, 0x40, 63, }, ++ { 103, 5, 1, 0x0000014008000000ull, 0x000001fff8000000ull, { 18, 20, 19, 0, 0 }, 0x40, 2369, }, ++ { 104, 5, 1, 0x00000001a0000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 65, }, ++ { 105, 5, 1, 0x00000001e0000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 2168, }, ++ { 106, 3, 0, 0x0000000100000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 66, }, ++ { 108, 5, 1, 0x0000000178000000ull, 0x000001e3f8000000ull, { 18, 19, 20, 0, 0 }, 0x0, 67, }, ++ { 113, 3, 1, 0x0000008708000000ull, 0x000001ffc8000000ull, { 24, 19, 0, 0, 0 }, 0x0, 2747, }, ++ { 118, 4, 0, 0x0000004008000000ull, 0x000001e1f8000000ull, { 65, 0, 0, 0, 0 }, 0x0, 520, }, ++ { 118, 5, 0, 0x000000000c000000ull, 0x000001e3fc000000ull, { 65, 0, 0, 0, 0 }, 0x0, 943, }, ++ { 118, 2, 0, 0x000000000c000000ull, 0x000001effc000000ull, { 65, 0, 0, 0, 0 }, 0x2, 1123, }, ++ { 118, 3, 0, 0x000000000c000000ull, 0x000001effc000000ull, { 65, 0, 0, 0, 0 }, 0x0, 1249, }, ++ { 118, 6, 0, 0x000000000c000000ull, 0x000001effc000000ull, { 69, 0, 0, 0, 0 }, 0x0, 2996, }, ++ { 118, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 65, 0, 0, 0, 0 }, 0x0, 68, }, ++ { 123, 3, 0, 0x0000000080000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 69, }, ++ { 123, 3, 0, 0x0000000090000000ull, 0x000001eff8000000ull, { 24, 0, 0, 0, 0 }, 0x0, 902, }, ++ { 123, 3, 0, 0x0000000098000000ull, 0x000001eff8000000ull, { 18, 0, 0, 0, 0 }, 0x0, 903, }, ++ { 124, 3, 0, 0x0000002170000000ull, 0x000001eff8000000ull, { 25, 0, 0, 0, 0 }, 0xc, 828, }, ++ { 125, 3, 1, 0x0000002070000000ull, 0x000001eff8000000ull, { 30, 25, 0, 0, 0 }, 0x8, 829, }, ++ { 125, 3, 1, 0x0000002078000000ull, 0x000001eff8000000ull, { 31, 25, 0, 0, 0 }, 0x8, 1125, }, ++ { 127, 3, 1, 0x0000008000000000ull, 0x000001fff8000000ull, { 24, 33, 0, 0, 0 }, 0x0, 70, }, ++ { 127, 3, 1, 0x0000009000000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x400, 71, }, ++ { 127, 3, 1, 0x000000a000000000ull, 0x000001eff0000000ull, { 24, 33, 62, 0, 0 }, 0x400, 72, }, ++ { 128, 3, 2, 0x0000008a08000000ull, 0x000001fff8000000ull, { 24, 1, 33, 0, 0 }, 0x0, 73, }, ++ { 128, 3, 1, 0x0000008a08000000ull, 0x000001fff8000000ull, { 24, 33, 0, 0, 0 }, 0x40, 74, }, ++ { 129, 3, 1, 0x0000008040000000ull, 0x000001fff8000000ull, { 24, 33, 0, 0, 0 }, 0x0, 75, }, ++ { 129, 3, 1, 0x0000009040000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x400, 76, }, ++ { 129, 3, 1, 0x000000a040000000ull, 0x000001eff0000000ull, { 24, 33, 62, 0, 0 }, 0x400, 77, }, ++ { 130, 3, 1, 0x0000008080000000ull, 0x000001fff8000000ull, { 24, 33, 0, 0, 0 }, 0x0, 78, }, ++ { 130, 3, 1, 0x0000009080000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x400, 79, }, ++ { 130, 3, 1, 0x000000a080000000ull, 0x000001eff0000000ull, { 24, 33, 62, 0, 0 }, 0x400, 80, }, ++ { 131, 3, 1, 0x00000080c0000000ull, 0x000001fff8000000ull, { 24, 33, 0, 0, 0 }, 0x0, 81, }, ++ { 131, 3, 1, 0x00000080c0000000ull, 0x000001fff8000000ull, { 24, 33, 83, 0, 0 }, 0x0, 1321, }, ++ { 131, 3, 1, 0x00000090c0000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x400, 82, }, ++ { 131, 3, 1, 0x000000a0c0000000ull, 0x000001eff0000000ull, { 24, 33, 62, 0, 0 }, 0x400, 83, }, ++ { 132, 3, 1, 0x000000c6c0000000ull, 0x000001fff8000000ull, { 18, 33, 0, 0, 0 }, 0x0, 1021, }, ++ { 132, 3, 1, 0x000000d6c0000000ull, 0x000001fff8000000ull, { 18, 33, 25, 0, 0 }, 0x400, 1022, }, ++ { 132, 3, 1, 0x000000e6c0000000ull, 0x000001eff0000000ull, { 18, 33, 62, 0, 0 }, 0x400, 1023, }, ++ { 133, 3, 1, 0x000000c040000000ull, 0x000001fff8000000ull, { 18, 33, 0, 0, 0 }, 0x0, 84, }, ++ { 133, 3, 1, 0x000000d040000000ull, 0x000001fff8000000ull, { 18, 33, 25, 0, 0 }, 0x400, 85, }, ++ { 133, 3, 1, 0x000000e040000000ull, 0x000001eff0000000ull, { 18, 33, 62, 0, 0 }, 0x400, 86, }, ++ { 134, 3, 1, 0x000000c0c0000000ull, 0x000001fff8000000ull, { 18, 33, 0, 0, 0 }, 0x0, 87, }, ++ { 134, 3, 1, 0x000000d0c0000000ull, 0x000001fff8000000ull, { 18, 33, 25, 0, 0 }, 0x400, 88, }, ++ { 134, 3, 1, 0x000000e0c0000000ull, 0x000001eff0000000ull, { 18, 33, 62, 0, 0 }, 0x400, 89, }, ++ { 135, 3, 1, 0x000000c000000000ull, 0x000001fff8000000ull, { 18, 33, 0, 0, 0 }, 0x0, 90, }, ++ { 135, 3, 1, 0x000000d000000000ull, 0x000001fff8000000ull, { 18, 33, 25, 0, 0 }, 0x400, 91, }, ++ { 135, 3, 1, 0x000000e000000000ull, 0x000001eff0000000ull, { 18, 33, 62, 0, 0 }, 0x400, 92, }, ++ { 136, 3, 2, 0x000000c048000000ull, 0x000001fff8000000ull, { 18, 19, 33, 0, 0 }, 0x0, 93, }, ++ { 136, 3, 2, 0x000000d048000000ull, 0x000001fff8000000ull, { 18, 19, 33, 6, 0 }, 0x400, 94, }, ++ { 137, 3, 2, 0x000000c0c8000000ull, 0x000001fff8000000ull, { 18, 19, 33, 0, 0 }, 0x0, 95, }, ++ { 137, 3, 2, 0x000000d0c8000000ull, 0x000001fff8000000ull, { 18, 19, 33, 6, 0 }, 0x400, 96, }, ++ { 138, 3, 2, 0x000000c088000000ull, 0x000001fff8000000ull, { 18, 19, 33, 0, 0 }, 0x0, 97, }, ++ { 138, 3, 2, 0x000000d088000000ull, 0x000001fff8000000ull, { 18, 19, 33, 5, 0 }, 0x400, 98, }, ++ { 139, 3, 1, 0x000000c080000000ull, 0x000001fff8000000ull, { 18, 33, 0, 0, 0 }, 0x0, 99, }, ++ { 139, 3, 1, 0x000000d080000000ull, 0x000001fff8000000ull, { 18, 33, 25, 0, 0 }, 0x400, 100, }, ++ { 139, 3, 1, 0x000000e080000000ull, 0x000001eff0000000ull, { 18, 33, 62, 0, 0 }, 0x400, 101, }, ++ { 142, 3, 0, 0x000000cb00000000ull, 0x000001fff8000000ull, { 33, 0, 0, 0, 0 }, 0x0, 102, }, ++ { 142, 3, 0, 0x000000db00000000ull, 0x000001fff8000000ull, { 33, 25, 0, 0, 0 }, 0x400, 103, }, ++ { 142, 3, 0, 0x000000eb00000000ull, 0x000001eff0000000ull, { 33, 62, 0, 0, 0 }, 0x400, 104, }, ++ { 143, 3, 0, 0x0000000050000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x21, 105, }, ++ { 151, 3, 0, 0x0000000110000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 106, }, ++ { 152, 2, 1, 0x000000e880000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2169, }, ++ { 153, 2, 1, 0x000000ea80000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2170, }, ++ { 154, 2, 1, 0x000000f880000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2171, }, ++ { 155, 1, 1, 0x0000010800000000ull, 0x000001fff80fe000ull, { 24, 26, 0, 0, 0 }, 0x0, 107, }, ++ { 155, 1, 1, 0x0000012000000000ull, 0x000001e000300000ull, { 24, 66, 0, 0, 0 }, 0x40, 108, }, ++ { 155, 5, 1, 0x0000000080000000ull, 0x000001e3f8000000ull, { 18, 20, 0, 0, 0 }, 0xc0, 109, }, ++ { 155, 2, 1, 0x0000000e00100000ull, 0x000001ee00f00000ull, { 15, 25, 0, 0, 0 }, 0x40, 110, }, ++ { 155, 2, 1, 0x0000000e00000000ull, 0x000001ee00f00000ull, { 15, 25, 78, 0, 0 }, 0x0, 2821, }, ++ { 155, 2, 1, 0x0000000188000000ull, 0x000001eff8000000ull, { 24, 16, 0, 0, 0 }, 0x0, 112, }, ++ { 155, 2, 1, 0x0000000600000000ull, 0x000001ee00000000ull, { 9, 25, 64, 0, 0 }, 0x0, 113, }, ++ { 155, 2, 1, 0x00000016ff001fc0ull, 0x000001feff001fc0ull, { 9, 25, 0, 0, 0 }, 0x40, 114, }, ++ { 155, 2, 1, 0x0000000400000000ull, 0x000001ee00000000ull, { 10, 68, 0, 0, 0 }, 0x0, 115, }, ++ { 155, 2, 1, 0x0000000180000000ull, 0x000001eff8000000ull, { 24, 8, 0, 0, 0 }, 0x0, 116, }, ++ { 155, 2, 1, 0x0000000198000000ull, 0x000001eff8000000ull, { 24, 9, 0, 0, 0 }, 0x0, 117, }, ++ { 155, 2, 1, 0x0000000150000000ull, 0x000001eff8000000ull, { 14, 25, 0, 0, 0 }, 0x0, 1126, }, ++ { 155, 2, 1, 0x0000000050000000ull, 0x000001eff8000000ull, { 14, 55, 0, 0, 0 }, 0x0, 1127, }, ++ { 155, 2, 1, 0x0000000190000000ull, 0x000001eff8000000ull, { 24, 14, 0, 0, 0 }, 0x0, 1128, }, ++ { 155, 3, 1, 0x0000000140000000ull, 0x000001eff8000000ull, { 14, 55, 0, 0, 0 }, 0x0, 1250, }, ++ { 155, 3, 1, 0x0000002150000000ull, 0x000001eff8000000ull, { 14, 25, 0, 0, 0 }, 0x0, 1251, }, ++ { 155, 3, 1, 0x0000002110000000ull, 0x000001eff8000000ull, { 24, 14, 0, 0, 0 }, 0x0, 1252, }, ++ { 155, 3, 1, 0x0000002160000000ull, 0x000001eff8000000ull, { 17, 25, 0, 0, 0 }, 0x8, 118, }, ++ { 155, 3, 1, 0x0000002120000000ull, 0x000001eff8000000ull, { 24, 17, 0, 0, 0 }, 0x8, 119, }, ++ { 155, 3, 1, 0x0000002168000000ull, 0x000001eff8000000ull, { 12, 25, 0, 0, 0 }, 0x8, 120, }, ++ { 155, 3, 1, 0x0000002148000000ull, 0x000001eff8000000ull, { 13, 25, 0, 0, 0 }, 0x0, 121, }, ++ { 155, 3, 1, 0x0000002128000000ull, 0x000001eff8000000ull, { 24, 11, 0, 0, 0 }, 0x8, 122, }, ++ { 155, 3, 1, 0x0000002108000000ull, 0x000001eff8000000ull, { 24, 13, 0, 0, 0 }, 0x0, 123, }, ++ { 155, 3, 1, 0x0000002000000000ull, 0x000001eff8000000ull, { 38, 25, 0, 0, 0 }, 0x8, 124, }, ++ { 155, 3, 1, 0x0000002008000000ull, 0x000001eff8000000ull, { 29, 25, 0, 0, 0 }, 0x8, 125, }, ++ { 155, 3, 1, 0x0000002010000000ull, 0x000001eff8000000ull, { 32, 25, 0, 0, 0 }, 0x8, 126, }, ++ { 155, 3, 1, 0x0000002018000000ull, 0x000001eff8000000ull, { 35, 25, 0, 0, 0 }, 0x8, 127, }, ++ { 155, 3, 1, 0x0000002020000000ull, 0x000001eff8000000ull, { 36, 25, 0, 0, 0 }, 0x8, 128, }, ++ { 155, 3, 1, 0x0000002028000000ull, 0x000001eff8000000ull, { 37, 25, 0, 0, 0 }, 0x8, 129, }, ++ { 155, 3, 1, 0x0000002030000000ull, 0x000001eff8000000ull, { 34, 25, 0, 0, 0 }, 0x8, 130, }, ++ { 155, 3, 1, 0x0000002080000000ull, 0x000001eff8000000ull, { 24, 38, 0, 0, 0 }, 0x8, 131, }, ++ { 155, 3, 1, 0x0000002088000000ull, 0x000001eff8000000ull, { 24, 29, 0, 0, 0 }, 0x8, 132, }, ++ { 155, 3, 1, 0x0000002090000000ull, 0x000001eff8000000ull, { 24, 32, 0, 0, 0 }, 0x8, 133, }, ++ { 155, 3, 1, 0x0000002098000000ull, 0x000001eff8000000ull, { 24, 35, 0, 0, 0 }, 0x8, 134, }, ++ { 155, 3, 1, 0x00000020a0000000ull, 0x000001eff8000000ull, { 24, 36, 0, 0, 0 }, 0x8, 135, }, ++ { 155, 3, 1, 0x00000020a8000000ull, 0x000001eff8000000ull, { 24, 37, 0, 0, 0 }, 0x0, 136, }, ++ { 155, 3, 1, 0x00000020b0000000ull, 0x000001eff8000000ull, { 24, 34, 0, 0, 0 }, 0x8, 137, }, ++ { 155, 3, 1, 0x00000020b8000000ull, 0x000001eff8000000ull, { 24, 28, 0, 0, 0 }, 0x0, 138, }, ++ { 155, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 24, 14, 0, 0, 0 }, 0x0, 139, }, ++ { 155, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 14, 55, 0, 0, 0 }, 0x0, 140, }, ++ { 155, 7, 1, 0x0000000000000000ull, 0x0000000000000000ull, { 14, 25, 0, 0, 0 }, 0x0, 141, }, ++ { 156, 6, 1, 0x000000c000000000ull, 0x000001e000100000ull, { 24, 70, 0, 0, 0 }, 0x0, 142, }, ++ { 157, 2, 1, 0x000000eca0000000ull, 0x000001fff0000000ull, { 24, 25, 74, 0, 0 }, 0x0, 143, }, ++ { 158, 2, 1, 0x000000eea0000000ull, 0x000001fff0000000ull, { 24, 25, 75, 0, 0 }, 0x0, 144, }, ++ { 168, 4, 0, 0x0000004000000000ull, 0x000001e1f8000000ull, { 65, 0, 0, 0, 0 }, 0x0, 521, }, ++ { 168, 5, 0, 0x0000000008000000ull, 0x000001e3fc000000ull, { 65, 0, 0, 0, 0 }, 0x0, 944, }, ++ { 168, 2, 0, 0x0000000008000000ull, 0x000001effc000000ull, { 65, 0, 0, 0, 0 }, 0x2, 1129, }, ++ { 168, 3, 0, 0x0000000008000000ull, 0x000001effc000000ull, { 65, 0, 0, 0, 0 }, 0x0, 1253, }, ++ { 168, 6, 0, 0x0000000008000000ull, 0x000001effc000000ull, { 69, 0, 0, 0, 0 }, 0x0, 2997, }, ++ { 168, 7, 0, 0x0000000000000000ull, 0x0000000000000000ull, { 65, 0, 0, 0, 0 }, 0x0, 145, }, ++ { 175, 1, 1, 0x0000010070000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 146, }, ++ { 175, 1, 1, 0x0000010170000000ull, 0x000001eff8000000ull, { 24, 55, 26, 0, 0 }, 0x0, 147, }, ++ { 178, 2, 1, 0x000000ea00000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2979, }, ++ { 179, 2, 1, 0x000000f820000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2823, }, ++ { 180, 1, 1, 0x0000010400000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 148, }, ++ { 181, 1, 1, 0x0000010600000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 149, }, ++ { 182, 1, 1, 0x0000011400000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 150, }, ++ { 183, 1, 1, 0x0000010450000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 151, }, ++ { 184, 1, 1, 0x0000010650000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 152, }, ++ { 185, 1, 1, 0x0000010470000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 153, }, ++ { 186, 1, 1, 0x0000010670000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 154, }, ++ { 187, 1, 1, 0x0000010520000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 930, }, ++ { 188, 1, 1, 0x0000010720000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 931, }, ++ { 189, 1, 1, 0x0000011520000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 932, }, ++ { 190, 2, 1, 0x000000e850000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2837, }, ++ { 191, 2, 1, 0x000000ea70000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 155, }, ++ { 192, 2, 1, 0x000000e810000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2838, }, ++ { 193, 2, 1, 0x000000ea30000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 156, }, ++ { 194, 2, 1, 0x000000ead0000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 2172, }, ++ { 195, 2, 1, 0x000000e230000000ull, 0x000001ff30000000ull, { 24, 25, 26, 42, 0 }, 0x0, 157, }, ++ { 196, 2, 1, 0x000000e690000000ull, 0x000001fff0000000ull, { 24, 26, 0, 0, 0 }, 0x0, 158, }, ++ { 198, 3, 1, 0x00000021c0000000ull, 0x000001eff8000000ull, { 24, 26, 25, 0, 0 }, 0x0, 2173, }, ++ { 198, 3, 1, 0x00000020c0000000ull, 0x000001eff8000000ull, { 24, 26, 49, 0, 0 }, 0x0, 2174, }, ++ { 198, 3, 0, 0x0000002188000000ull, 0x000001eff8000000ull, { 26, 49, 0, 0, 0 }, 0x0, 2204, }, ++ { 199, 2, 1, 0x000000e8b0000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 159, }, ++ { 200, 2, 1, 0x000000e240000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 160, }, ++ { 200, 2, 1, 0x000000ee50000000ull, 0x000001fff0000000ull, { 24, 25, 39, 0, 0 }, 0x0, 161, }, ++ { 201, 2, 1, 0x000000f040000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 162, }, ++ { 201, 2, 1, 0x000000fc50000000ull, 0x000001fff0000000ull, { 24, 25, 39, 0, 0 }, 0x0, 163, }, ++ { 202, 1, 1, 0x0000010680000000ull, 0x000001ffe0000000ull, { 24, 25, 41, 26, 0 }, 0x0, 164, }, ++ { 203, 2, 1, 0x000000e220000000ull, 0x000001fff0000000ull, { 24, 26, 25, 0, 0 }, 0x0, 165, }, ++ { 203, 2, 1, 0x000000e630000000ull, 0x000001fff0000000ull, { 24, 26, 43, 0, 0 }, 0x0, 166, }, ++ { 204, 2, 1, 0x000000f020000000ull, 0x000001fff0000000ull, { 24, 26, 25, 0, 0 }, 0x0, 167, }, ++ { 204, 2, 1, 0x000000f430000000ull, 0x000001fff0000000ull, { 24, 26, 43, 0, 0 }, 0x0, 168, }, ++ { 205, 1, 1, 0x00000106c0000000ull, 0x000001ffe0000000ull, { 24, 25, 41, 26, 0 }, 0x0, 169, }, ++ { 206, 1, 1, 0x0000010420000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 170, }, ++ { 207, 1, 1, 0x0000010620000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 171, }, ++ { 208, 1, 1, 0x0000011420000000ull, 0x000001fff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 172, }, ++ { 209, 3, 0, 0x0000002048000000ull, 0x000001eff8000000ull, { 26, 25, 0, 0, 0 }, 0x8, 1157, }, ++ { 209, 3, 0, 0x0000002050000000ull, 0x000001eff8000000ull, { 26, 25, 0, 0, 0 }, 0xc, 1032, }, ++ { 209, 3, 0, 0x00000021a0000000ull, 0x000001eff8000000ull, { 26, 0, 0, 0, 0 }, 0x8, 904, }, ++ { 210, 3, 0, 0x0000002060000000ull, 0x000001eff8000000ull, { 26, 25, 0, 0, 0 }, 0x8, 830, }, ++ { 215, 4, 0, 0x0000000040000000ull, 0x000001e1f8000000ull, { 0, 0, 0, 0, 0 }, 0x22c, 173, }, ++ { 216, 3, 0, 0x0000000038000000ull, 0x000001ee78000000ull, { 67, 0, 0, 0, 0 }, 0x8, 174, }, ++ { 217, 3, 0, 0x0000000028000000ull, 0x000001ee78000000ull, { 67, 0, 0, 0, 0 }, 0x0, 175, }, ++ { 226, 3, 1, 0x000000c708000000ull, 0x000001ffc8000000ull, { 18, 25, 0, 0, 0 }, 0x0, 2748, }, ++ { 227, 2, 1, 0x000000a600000000ull, 0x000001ee04000000ull, { 24, 25, 45, 0, 0 }, 0x140, 176, }, ++ { 227, 2, 1, 0x000000f240000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 177, }, ++ { 228, 1, 1, 0x0000010080000000ull, 0x000001efe0000000ull, { 24, 25, 40, 26, 0 }, 0x0, 178, }, ++ { 229, 1, 1, 0x00000100c0000000ull, 0x000001efe0000000ull, { 24, 25, 40, 26, 0 }, 0x0, 179, }, ++ { 230, 2, 1, 0x000000a400000000ull, 0x000001ee00002000ull, { 24, 26, 76, 0, 0 }, 0x140, 2844, }, ++ { 230, 2, 1, 0x000000f220000000ull, 0x000001fff0000000ull, { 24, 26, 25, 0, 0 }, 0x0, 181, }, ++ { 231, 2, 1, 0x000000ac00000000ull, 0x000001ee00000000ull, { 24, 25, 26, 44, 0 }, 0x0, 182, }, ++ { 236, 3, 0, 0x0000000180000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 832, }, ++ { 237, 3, 0, 0x0000000030000000ull, 0x000001ee78000000ull, { 67, 0, 0, 0, 0 }, 0x8, 183, }, ++ { 239, 3, 1, 0x0000008c00000000ull, 0x000001fff8000000ull, { 33, 25, 0, 0, 0 }, 0x0, 184, }, ++ { 239, 3, 1, 0x000000ac00000000ull, 0x000001eff0000000ull, { 33, 25, 61, 0, 0 }, 0x400, 185, }, ++ { 240, 3, 1, 0x0000008c08000000ull, 0x000001fff8000000ull, { 33, 25, 1, 0, 0 }, 0x0, 186, }, ++ { 240, 3, 1, 0x0000008c08000000ull, 0x000001fff8000000ull, { 33, 25, 0, 0, 0 }, 0x40, 187, }, ++ { 241, 3, 1, 0x0000008c40000000ull, 0x000001fff8000000ull, { 33, 25, 0, 0, 0 }, 0x0, 188, }, ++ { 241, 3, 1, 0x000000ac40000000ull, 0x000001eff0000000ull, { 33, 25, 61, 0, 0 }, 0x400, 189, }, ++ { 242, 3, 1, 0x0000008c80000000ull, 0x000001fff8000000ull, { 33, 25, 0, 0, 0 }, 0x0, 190, }, ++ { 242, 3, 1, 0x000000ac80000000ull, 0x000001eff0000000ull, { 33, 25, 61, 0, 0 }, 0x400, 191, }, ++ { 243, 3, 1, 0x0000008cc0000000ull, 0x000001fff8000000ull, { 33, 25, 0, 0, 0 }, 0x0, 192, }, ++ { 243, 3, 1, 0x000000acc0000000ull, 0x000001eff0000000ull, { 33, 25, 61, 0, 0 }, 0x400, 193, }, ++ { 244, 3, 1, 0x000000cec0000000ull, 0x000001fff8000000ull, { 33, 19, 0, 0, 0 }, 0x0, 2751, }, ++ { 244, 3, 1, 0x000000eec0000000ull, 0x000001eff0000000ull, { 33, 19, 61, 0, 0 }, 0x400, 2752, }, ++ { 245, 3, 1, 0x000000cc40000000ull, 0x000001fff8000000ull, { 33, 19, 0, 0, 0 }, 0x0, 194, }, ++ { 245, 3, 1, 0x000000ec40000000ull, 0x000001eff0000000ull, { 33, 19, 61, 0, 0 }, 0x400, 195, }, ++ { 246, 3, 1, 0x000000ccc0000000ull, 0x000001fff8000000ull, { 33, 19, 0, 0, 0 }, 0x0, 196, }, ++ { 246, 3, 1, 0x000000ecc0000000ull, 0x000001eff0000000ull, { 33, 19, 61, 0, 0 }, 0x400, 197, }, ++ { 247, 3, 1, 0x000000cc00000000ull, 0x000001fff8000000ull, { 33, 19, 0, 0, 0 }, 0x0, 198, }, ++ { 247, 3, 1, 0x000000ec00000000ull, 0x000001eff0000000ull, { 33, 19, 61, 0, 0 }, 0x400, 199, }, ++ { 248, 3, 1, 0x000000cc80000000ull, 0x000001fff8000000ull, { 33, 19, 0, 0, 0 }, 0x0, 200, }, ++ { 248, 3, 1, 0x000000ec80000000ull, 0x000001eff0000000ull, { 33, 19, 61, 0, 0 }, 0x400, 201, }, ++ { 249, 1, 1, 0x0000010028000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 202, }, ++ { 249, 1, 1, 0x0000010020000000ull, 0x000001eff8000000ull, { 24, 25, 26, 4, 0 }, 0x0, 203, }, ++ { 249, 1, 1, 0x0000010128000000ull, 0x000001eff8000000ull, { 24, 55, 26, 0, 0 }, 0x0, 204, }, ++ { 250, 3, 0, 0x0000000020000000ull, 0x000001ee78000000ull, { 67, 0, 0, 0, 0 }, 0x0, 205, }, ++ { 251, 2, 1, 0x00000000a0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 206, }, ++ { 252, 2, 1, 0x00000000a8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 207, }, ++ { 253, 2, 1, 0x00000000b0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 208, }, ++ { 254, 3, 0, 0x0000000198000000ull, 0x000001eff8000000ull, { 0, 0, 0, 0, 0 }, 0x0, 1132, }, ++ { 255, 3, 1, 0x00000020f8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x8, 209, }, ++ { 256, 2, 2, 0x000000a000000000ull, 0x000001fe00003000ull, { 22, 23, 26, 76, 0 }, 0x0, 3002, }, ++ { 256, 2, 1, 0x000000a000000000ull, 0x000001fe00003000ull, { 22, 26, 76, 0, 0 }, 0x40, 3003, }, ++ { 256, 2, 2, 0x000000a000000000ull, 0x000001fe00003000ull, { 23, 22, 26, 76, 0 }, 0x40, 1985, }, ++ { 256, 2, 1, 0x000000a000000000ull, 0x000001fe00003000ull, { 23, 26, 76, 0, 0 }, 0x40, 1986, }, ++ { 257, 3, 1, 0x00000020d0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 210, }, ++ { 258, 2, 2, 0x000000a000002000ull, 0x000001fe00003000ull, { 22, 23, 26, 0, 0 }, 0x0, 3006, }, ++ { 258, 2, 1, 0x000000a000002000ull, 0x000001fe00003000ull, { 22, 26, 0, 0, 0 }, 0x40, 3007, }, ++ { 258, 2, 2, 0x000000a000002000ull, 0x000001fe00003000ull, { 23, 22, 26, 0, 0 }, 0x40, 1989, }, ++ { 258, 2, 1, 0x000000a000002000ull, 0x000001fe00003000ull, { 23, 26, 0, 0, 0 }, 0x40, 1990, }, ++ { 259, 3, 1, 0x00000020f0000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x8, 211, }, ++ { 261, 3, 1, 0x00000020d8000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 212, }, ++ { 265, 2, 1, 0x000000e840000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 1113, }, ++ { 266, 2, 1, 0x000000ea40000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 1114, }, ++ { 267, 2, 1, 0x000000f840000000ull, 0x000001fff0000000ull, { 24, 25, 26, 0, 0 }, 0x0, 1115, }, ++ { 275, 3, 1, 0x0000008208000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x0, 213, }, ++ { 276, 3, 1, 0x0000008248000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x0, 214, }, ++ { 277, 3, 1, 0x0000008288000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x0, 215, }, ++ { 278, 3, 1, 0x00000082c8000000ull, 0x000001fff8000000ull, { 24, 33, 25, 0, 0 }, 0x0, 216, }, ++ { 280, 5, 1, 0x000001d000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x0, 1161, }, ++ { 280, 5, 1, 0x000001d000000000ull, 0x000001fc00000000ull, { 18, 20, 21, 19, 0 }, 0x40, 1243, }, ++ { 281, 5, 1, 0x000001d000000000ull, 0x000001fc000fe000ull, { 18, 20, 21, 0, 0 }, 0x40, 1162, }, ++ { 282, 1, 1, 0x0000010078000000ull, 0x000001eff8000000ull, { 24, 25, 26, 0, 0 }, 0x0, 217, }, ++ { 282, 1, 1, 0x0000010178000000ull, 0x000001eff8000000ull, { 24, 55, 26, 0, 0 }, 0x0, 218, }, ++ { 285, 2, 1, 0x0000000080000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 219, }, ++ { 286, 2, 1, 0x0000000088000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 220, }, ++ { 287, 2, 1, 0x0000000090000000ull, 0x000001eff8000000ull, { 24, 26, 0, 0, 0 }, 0x0, 221, }, ++}; ++ ++static const char dis_table[] = { ++0xa0, 0xc5, 0xe8, 0xa0, 0x2e, 0x98, 0xa0, 0x2c, 0x80, 0xa0, 0x1b, 0xc0, ++0x98, 0xb0, 0x02, 0x50, 0x90, 0x50, 0x90, 0x28, 0x24, 0x38, 0x28, 0x24, ++0x38, 0x20, 0x90, 0x28, 0x24, 0x38, 0x18, 0x24, 0x38, 0x10, 0x91, 0x60, ++0x90, 0x28, 0x24, 0x38, 0x00, 0x10, 0x10, 0x58, 0x41, 0x61, 0xbf, 0xc0, ++0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, ++0x10, 0x10, 0x52, 0xc0, 0xc0, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, ++0x10, 0x10, 0x10, 0x24, 0x23, 0x70, 0x90, 0x28, 0x24, 0x37, 0xf0, 0x24, ++0x37, 0xe8, 0xa8, 0x0b, 0x48, 0x15, 0x20, 0x97, 0x20, 0x95, 0xc8, 0x9a, ++0xb8, 0x05, 0x38, 0x91, 0x18, 0x90, 0xa0, 0x90, 0x60, 0x80, 0x90, 0x20, ++0x34, 0x86, 0xa4, 0x24, 0x00, 0x34, 0x83, 0x80, 0xa4, 0x35, 0xa0, 0x36, ++0xb9, 0x90, 0x50, 0x90, 0x28, 0x80, 0x36, 0xaf, 0x80, 0x34, 0x66, 0x81, ++0x33, 0xe2, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x23, 0x10, 0x34, ++0x63, 0xa4, 0x1f, 0x08, 0x34, 0x60, 0x90, 0x38, 0xa4, 0x37, 0xa0, 0x36, ++0xfa, 0xa4, 0x37, 0x48, 0x36, 0xee, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x36, ++0x20, 0x36, 0xcf, 0xa4, 0x35, 0xf8, 0x36, 0xca, 0x80, 0xa4, 0x22, 0xf0, ++0x34, 0x5f, 0x92, 0x18, 0x91, 0xc0, 0x80, 0x91, 0x80, 0x90, 0xf8, 0xdb, ++0x84, 0x60, 0xf9, 0x40, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x58, 0x8c, 0x42, ++0xb8, 0x84, 0x38, 0x61, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x48, 0x8c, 0x42, ++0x98, 0x84, 0x38, 0x5f, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, ++0x13, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x11, 0xa4, 0x1f, 0x18, 0x33, 0xe4, ++0x80, 0x90, 0x28, 0x80, 0x33, 0xe0, 0x80, 0x34, 0x68, 0x81, 0x90, 0x38, ++0xa4, 0x23, 0x80, 0x34, 0x6b, 0xa4, 0x23, 0x48, 0x34, 0x65, 0xc0, 0x40, ++0x10, 0x10, 0x90, 0x38, 0xa4, 0x1e, 0xf0, 0x33, 0xdf, 0xa4, 0x1e, 0xe0, ++0x33, 0xdd, 0x18, 0x24, 0x23, 0xf8, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, ++0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x28, 0x38, 0x4b, 0xc0, 0xc0, 0x80, 0xa4, ++0x41, 0x18, 0x38, 0x47, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, ++0x0d, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x0b, 0x92, 0xb8, 0x99, 0x84, 0x23, ++0x68, 0x90, 0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x35, 0x98, 0x36, ++0xb8, 0x82, 0x36, 0xae, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x37, ++0x98, 0x36, 0xf9, 0xa4, 0x37, 0x40, 0x36, 0xed, 0x80, 0x90, 0x38, 0xa4, ++0x36, 0x18, 0x36, 0xce, 0xa4, 0x35, 0xf0, 0x36, 0xc9, 0x83, 0x90, 0xa8, ++0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x40, 0xf8, 0x38, 0x3f, 0xc0, ++0xc0, 0x80, 0xa4, 0x40, 0xe8, 0x38, 0x3b, 0xd3, 0x82, 0x40, 0x50, 0xc0, ++0xc0, 0x81, 0x38, 0x07, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x05, 0x18, 0x24, ++0x23, 0x78, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, ++0x40, 0xc8, 0x38, 0x33, 0xc0, 0xc0, 0x80, 0xa4, 0x40, 0xb8, 0x38, 0x2f, ++0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x01, 0x50, 0xc0, 0xc0, ++0x81, 0x37, 0xff, 0x94, 0x50, 0x92, 0xf8, 0x99, 0x84, 0x1f, 0x48, 0x90, ++0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x35, 0x90, 0x36, 0xb7, 0x82, ++0x36, 0xad, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x37, 0x90, 0x36, ++0xf8, 0xa4, 0x37, 0x38, 0x36, 0xec, 0x80, 0x90, 0x38, 0xa4, 0x36, 0x10, ++0x36, 0xcd, 0xa4, 0x35, 0xe8, 0x36, 0xc8, 0x83, 0x90, 0xe8, 0xd3, 0x83, ++0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x68, 0x8c, 0x42, 0xd8, 0x84, 0x38, ++0x63, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x50, 0x8c, 0x42, 0xa8, 0x84, 0x38, ++0x60, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x15, 0x50, 0xc0, ++0xc0, 0x81, 0x38, 0x12, 0x18, 0x24, 0x1f, 0x40, 0x83, 0x90, 0xa8, 0xd3, ++0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x38, 0x38, 0x4f, 0xc0, 0xc0, ++0x80, 0xa4, 0x41, 0x20, 0x38, 0x49, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, ++0x81, 0x38, 0x0f, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x0c, 0x92, 0xb8, 0x99, ++0x84, 0x1f, 0x38, 0x90, 0x78, 0x90, 0x50, 0x10, 0x10, 0x80, 0xa4, 0x35, ++0x88, 0x36, 0xb6, 0x82, 0x36, 0xac, 0x90, 0x80, 0x10, 0x10, 0x90, 0x38, ++0xa4, 0x37, 0x88, 0x36, 0xf7, 0xa4, 0x37, 0x30, 0x36, 0xeb, 0x80, 0x90, ++0x38, 0xa4, 0x36, 0x08, 0x36, 0xcc, 0xa4, 0x35, 0xe0, 0x36, 0xc7, 0x83, ++0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, 0x80, 0xa4, 0x41, 0x08, 0x38, ++0x43, 0xc0, 0xc0, 0x80, 0xa4, 0x40, 0xf0, 0x38, 0x3d, 0xd3, 0x82, 0x40, ++0x50, 0xc0, 0xc0, 0x81, 0x38, 0x09, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x06, ++0x18, 0x20, 0x01, 0x48, 0x83, 0x90, 0xa8, 0xd3, 0x82, 0xc0, 0xc0, 0xc0, ++0x80, 0xa4, 0x40, 0xd8, 0x38, 0x37, 0xc0, 0xc0, 0x80, 0xa4, 0x40, 0xc0, ++0x38, 0x31, 0xd3, 0x82, 0x40, 0x50, 0xc0, 0xc0, 0x81, 0x38, 0x03, 0x50, ++0xc0, 0xc0, 0x81, 0x38, 0x00, 0xda, 0x06, 0xe0, 0xf9, 0x80, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x23, 0xe8, 0x34, 0x7b, 0x80, 0x34, 0x78, 0x90, 0x38, ++0xa4, 0x23, 0x90, 0x34, 0x76, 0x80, 0x34, 0x73, 0x90, 0x60, 0x90, 0x38, ++0xa4, 0x23, 0xd0, 0x34, 0x7c, 0x80, 0x34, 0x79, 0x90, 0x38, 0xa4, 0x23, ++0xa8, 0x34, 0x77, 0x80, 0x34, 0x74, 0xc8, 0x40, 0x19, 0x00, 0x91, 0x58, ++0x90, 0x60, 0x82, 0x90, 0x20, 0x36, 0xab, 0xa4, 0x35, 0x48, 0x36, 0xaa, ++0x90, 0xc0, 0x80, 0x90, 0x90, 0x90, 0x48, 0xc9, 0xe1, 0xb9, 0x00, 0x85, ++0x36, 0xe3, 0xc9, 0xe1, 0xb8, 0x40, 0x85, 0x36, 0xe0, 0x80, 0x36, 0xdf, ++0x10, 0x10, 0x81, 0x36, 0xbb, 0x90, 0xa8, 0x10, 0x10, 0x90, 0x28, 0x81, ++0x36, 0xd9, 0x90, 0x38, 0xa4, 0x36, 0xa0, 0x36, 0xd5, 0xa4, 0x36, 0x90, ++0x36, 0xd3, 0x90, 0x70, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x36, 0xb8, 0x36, ++0xd8, 0x80, 0x36, 0xd6, 0x90, 0x60, 0x90, 0x28, 0x24, 0x36, 0xf0, 0xa4, ++0x36, 0xe0, 0x36, 0xdd, 0x80, 0xa4, 0x36, 0xd0, 0x36, 0xdb, 0x80, 0x90, ++0xf8, 0x90, 0x90, 0x90, 0x50, 0x90, 0x28, 0x80, 0x37, 0xf7, 0x80, 0x37, ++0xfe, 0x80, 0xa4, 0x3f, 0xe0, 0x37, 0xfd, 0x90, 0x28, 0x81, 0x37, 0xfb, ++0x80, 0xa4, 0x3f, 0xc8, 0x37, 0xfa, 0x83, 0x37, 0xf8, 0x98, 0xe8, 0x01, ++0xb0, 0x90, 0x88, 0x90, 0x60, 0xa4, 0x35, 0x38, 0x10, 0x10, 0x10, 0x10, ++0x83, 0x33, 0xb7, 0x24, 0x35, 0x30, 0x90, 0x28, 0x24, 0x35, 0x28, 0x24, ++0x35, 0x20, 0x90, 0x88, 0x90, 0x60, 0xa4, 0x35, 0x10, 0x10, 0x10, 0x10, ++0x10, 0x83, 0x33, 0xb6, 0x24, 0x35, 0x08, 0x90, 0x28, 0x24, 0x35, 0x00, ++0x24, 0x34, 0xf8, 0xa8, 0x09, 0x00, 0x0e, 0x20, 0x96, 0x48, 0x95, 0xe8, ++0x93, 0x38, 0x91, 0xa0, 0x90, 0xd0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x1e, ++0x60, 0x33, 0xcd, 0xa4, 0x1e, 0x50, 0x33, 0xcb, 0x90, 0x38, 0xa4, 0x1e, ++0x40, 0x33, 0xc9, 0x80, 0x33, 0xc7, 0x90, 0x60, 0x90, 0x28, 0x24, 0x1e, ++0x00, 0xa4, 0x1d, 0xf0, 0x33, 0xbf, 0x90, 0x38, 0xa4, 0x1d, 0xe0, 0x33, ++0xbd, 0xa4, 0x1e, 0x28, 0x33, 0xc6, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x1e, 0x18, 0x33, 0xc4, 0xa4, 0x1e, 0x08, 0x33, 0xc2, 0x90, 0x38, ++0xa4, 0x34, 0xb0, 0x36, 0x9c, 0xa4, 0x34, 0x50, 0x36, 0x90, 0x90, 0x70, ++0x90, 0x38, 0xa4, 0x31, 0x90, 0x36, 0x3e, 0xa4, 0x31, 0x60, 0x36, 0x38, ++0x10, 0x10, 0xa4, 0x1d, 0xd0, 0x33, 0xbb, 0x99, 0x60, 0x02, 0x70, 0x90, ++0x90, 0x90, 0x50, 0x90, 0x28, 0x24, 0x1e, 0x90, 0x80, 0x33, 0xda, 0x80, ++0xa4, 0x1e, 0x98, 0x33, 0xd8, 0x90, 0x50, 0x90, 0x28, 0x24, 0x1e, 0xa0, ++0x80, 0x33, 0xdb, 0x90, 0x38, 0xa4, 0x1e, 0xa8, 0x33, 0xd9, 0xa4, 0x1e, ++0x70, 0x33, 0xcf, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x33, 0xe8, ++0x36, 0x85, 0xa4, 0x33, 0x48, 0x36, 0x72, 0x90, 0x38, 0xa4, 0x32, 0xe0, ++0x36, 0x63, 0xa4, 0x32, 0x50, 0x36, 0x52, 0x81, 0xa4, 0x1e, 0x80, 0x33, ++0xd1, 0xe4, 0xa1, 0xfc, 0x40, 0x37, 0xf3, 0x18, 0x24, 0x1d, 0xc8, 0xe4, ++0xe1, 0xfa, 0xc0, 0x37, 0xed, 0x92, 0x40, 0x91, 0x08, 0x10, 0x10, 0x90, ++0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x34, 0xa8, 0x36, 0x9b, 0xa4, 0x34, ++0x48, 0x36, 0x8f, 0x80, 0x90, 0x38, 0xa4, 0x31, 0x88, 0x36, 0x3d, 0xa4, ++0x31, 0x58, 0x36, 0x37, 0x18, 0x20, 0x00, 0xf8, 0x80, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x33, 0xd8, 0x36, 0x84, 0xa4, 0x33, 0x40, 0x36, 0x70, 0x90, ++0x38, 0xa4, 0x32, 0xd0, 0x36, 0x62, 0xa4, 0x32, 0x48, 0x36, 0x50, 0xe4, ++0xa1, 0xf9, 0x40, 0x37, 0xe7, 0x18, 0x24, 0x1d, 0xc0, 0xe4, 0xe1, 0xf7, ++0xc0, 0x37, 0xe1, 0x92, 0x90, 0x92, 0x40, 0x91, 0x08, 0x10, 0x10, 0x90, ++0x80, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x34, 0xa0, 0x36, 0x9a, 0xa4, 0x34, ++0x40, 0x36, 0x8e, 0x80, 0x90, 0x38, 0xa4, 0x31, 0x80, 0x36, 0x3c, 0xa4, ++0x31, 0x50, 0x36, 0x36, 0x18, 0x20, 0x00, 0xf8, 0x80, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x33, 0xc8, 0x36, 0x83, 0xa4, 0x33, 0x38, 0x36, 0x6e, 0x90, ++0x38, 0xa4, 0x32, 0xc0, 0x36, 0x61, 0xa4, 0x32, 0x40, 0x36, 0x4e, 0xe4, ++0xa1, 0xfc, 0x80, 0x37, 0xf5, 0x10, 0x10, 0xe4, 0xe1, 0xfb, 0x00, 0x37, ++0xef, 0x92, 0x50, 0x99, 0x1c, 0x1e, 0xb0, 0x10, 0x10, 0x90, 0x80, 0x10, ++0x10, 0x90, 0x38, 0xa4, 0x34, 0x98, 0x36, 0x99, 0xa4, 0x34, 0x38, 0x36, ++0x8d, 0x80, 0x90, 0x38, 0xa4, 0x31, 0x78, 0x36, 0x3b, 0xa4, 0x31, 0x48, ++0x36, 0x35, 0x18, 0x20, 0x00, 0xf8, 0x80, 0x90, 0x70, 0x90, 0x38, 0xa4, ++0x33, 0xb8, 0x36, 0x82, 0xa4, 0x33, 0x30, 0x36, 0x6c, 0x90, 0x38, 0xa4, ++0x32, 0xb0, 0x36, 0x60, 0xa4, 0x32, 0x38, 0x36, 0x4c, 0xe4, 0xa1, 0xf9, ++0x80, 0x37, 0xe9, 0x10, 0x10, 0xe4, 0xe1, 0xf8, 0x00, 0x37, 0xe3, 0xc0, ++0x40, 0x80, 0x10, 0x10, 0x81, 0x90, 0x90, 0x90, 0x48, 0xc9, 0xe1, 0x90, ++0x80, 0x85, 0x36, 0x46, 0xc9, 0xe1, 0x91, 0x00, 0x85, 0x36, 0x43, 0x80, ++0x36, 0x41, 0x80, 0xd8, 0x47, 0x80, 0x0d, 0xc0, 0xc0, 0x80, 0x10, 0x10, ++0x82, 0x90, 0x58, 0xd5, 0x81, 0x80, 0x80, 0x37, 0xdd, 0x80, 0x37, 0xdb, ++0xd5, 0x81, 0x80, 0x80, 0x37, 0xd9, 0x80, 0x37, 0xd7, 0xc0, 0x80, 0x10, ++0x10, 0x82, 0x90, 0x58, 0xd5, 0x81, 0x80, 0x80, 0x37, 0xde, 0x80, 0x37, ++0xdc, 0xd5, 0x81, 0x80, 0x80, 0x37, 0xda, 0x80, 0x37, 0xd8, 0xc0, 0x80, ++0x83, 0xa4, 0x3e, 0xa8, 0x37, 0xd6, 0xa0, 0x57, 0xc0, 0xa0, 0x41, 0xe0, ++0xa8, 0x1e, 0xb0, 0x34, 0x88, 0xa0, 0x12, 0x38, 0xa0, 0x0b, 0x48, 0x96, ++0x00, 0x9a, 0xf0, 0x05, 0xc0, 0x91, 0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x15, 0x58, 0x33, 0xb5, 0xa4, 0x15, 0x78, 0x33, 0xb4, 0x10, ++0x10, 0xa4, 0x15, 0x68, 0x33, 0xb3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, ++0xf8, 0x33, 0x9a, 0xa4, 0x15, 0x18, 0x33, 0x99, 0x10, 0x10, 0xa4, 0x15, ++0x08, 0x33, 0x98, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x98, ++0x33, 0x7f, 0xa4, 0x14, 0xb8, 0x33, 0x7e, 0x10, 0x10, 0xa4, 0x14, 0xa8, ++0x33, 0x7d, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0x38, 0x33, 0x63, 0xa4, ++0x14, 0x58, 0x33, 0x62, 0x10, 0x10, 0xa4, 0x14, 0x48, 0x33, 0x61, 0x91, ++0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x15, 0x28, 0x33, 0xb0, ++0xa4, 0x15, 0x48, 0x33, 0xb2, 0x10, 0x10, 0xa4, 0x15, 0x38, 0x33, 0xb1, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x14, 0xc8, 0x33, 0x95, 0xa4, 0x14, 0xe8, ++0x33, 0x97, 0x10, 0x10, 0xa4, 0x14, 0xd8, 0x33, 0x96, 0x90, 0xb8, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x14, 0x68, 0x33, 0x7a, 0xa4, 0x14, 0x88, 0x33, ++0x7c, 0x10, 0x10, 0xa4, 0x14, 0x78, 0x33, 0x7b, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x14, 0x08, 0x33, 0x5e, 0xa4, 0x14, 0x28, 0x33, 0x60, 0x10, 0x10, ++0xa4, 0x14, 0x18, 0x33, 0x5f, 0xe4, 0xe1, 0x83, 0x40, 0x36, 0x21, 0x9a, ++0xf0, 0x05, 0x00, 0x91, 0x70, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, ++0x13, 0xa0, 0x33, 0xad, 0xa4, 0x13, 0x98, 0x33, 0xaf, 0x10, 0x10, 0xa4, ++0x13, 0x90, 0x33, 0xae, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x88, 0x33, ++0x92, 0xa4, 0x13, 0x80, 0x33, 0x94, 0x10, 0x10, 0xa4, 0x13, 0x78, 0x33, ++0x93, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x70, 0x33, 0x77, ++0xa4, 0x13, 0x68, 0x33, 0x79, 0x10, 0x10, 0xa4, 0x13, 0x60, 0x33, 0x78, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x58, 0x33, 0x5b, 0xa4, 0x13, 0x50, ++0x33, 0x5d, 0x10, 0x10, 0xa4, 0x13, 0x48, 0x33, 0x5c, 0x91, 0x10, 0x90, ++0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xaa, 0x80, 0x33, 0xac, 0x10, ++0x10, 0x80, 0x33, 0xab, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x8f, 0x80, ++0x33, 0x91, 0x10, 0x10, 0x80, 0x33, 0x90, 0x90, 0x88, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x33, 0x74, 0x80, 0x33, 0x76, 0x10, 0x10, 0x80, 0x33, 0x75, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x58, 0x80, 0x33, 0x5a, 0x10, 0x10, ++0x80, 0x33, 0x59, 0xe4, 0xe1, 0x5e, 0x40, 0x35, 0xa1, 0x95, 0x40, 0x9a, ++0x90, 0x05, 0x00, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, ++0x33, 0xa7, 0x80, 0x33, 0xa9, 0x10, 0x10, 0x80, 0x33, 0xa8, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x33, 0x8c, 0x80, 0x33, 0x8e, 0x10, 0x10, 0x80, 0x33, ++0x8d, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x30, 0x33, 0x71, ++0xa4, 0x13, 0x40, 0x33, 0x73, 0x10, 0x10, 0xa4, 0x13, 0x38, 0x33, 0x72, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0x00, 0x33, 0x55, 0xa4, 0x13, 0x10, ++0x33, 0x57, 0x10, 0x10, 0xa4, 0x13, 0x08, 0x33, 0x56, 0x91, 0x10, 0x90, ++0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xa4, 0x80, 0x33, 0xa6, 0x10, ++0x10, 0x80, 0x33, 0xa5, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x89, 0x80, ++0x33, 0x8b, 0x10, 0x10, 0x80, 0x33, 0x8a, 0x90, 0xb8, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x13, 0x18, 0x33, 0x6e, 0xa4, 0x13, 0x28, 0x33, 0x70, 0x10, ++0x10, 0xa4, 0x13, 0x20, 0x33, 0x6f, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x12, ++0xe8, 0x33, 0x52, 0xa4, 0x12, 0xf8, 0x33, 0x54, 0x10, 0x10, 0xa4, 0x12, ++0xf0, 0x33, 0x53, 0xe4, 0xe1, 0x82, 0x40, 0x36, 0x1d, 0x98, 0xb8, 0x01, ++0x68, 0x10, 0x10, 0x10, 0x10, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x4f, ++0x80, 0x33, 0x51, 0x10, 0x10, 0x80, 0x33, 0x50, 0x90, 0x60, 0x90, 0x30, ++0x60, 0xa0, 0x97, 0x00, 0x60, 0xa0, 0x96, 0xc0, 0x90, 0x30, 0x60, 0xa0, ++0x96, 0x80, 0x60, 0xa0, 0x96, 0x40, 0xe4, 0xe1, 0x5c, 0x40, 0x35, 0x99, ++0xa0, 0x08, 0x08, 0x94, 0xe0, 0x9a, 0x60, 0x04, 0xa0, 0x91, 0x40, 0x90, ++0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0xd8, 0x33, 0x9e, 0xa4, 0x13, ++0xf8, 0x33, 0xa3, 0x10, 0x10, 0xa4, 0x13, 0xe8, 0x33, 0xa2, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x33, 0x83, 0x80, 0x33, 0x88, 0x10, 0x10, 0x80, 0x33, ++0x87, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x68, 0x80, 0x33, ++0x6d, 0x10, 0x10, 0x80, 0x33, 0x6c, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0x49, 0x80, 0x33, 0x4e, 0x10, 0x10, 0x80, 0x33, 0x4d, 0x91, 0x40, 0x90, ++0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x13, 0xa8, 0x33, 0x9b, 0xa4, 0x13, ++0xc8, 0x33, 0x9d, 0x10, 0x10, 0xa4, 0x13, 0xb8, 0x33, 0x9c, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x33, 0x80, 0x80, 0x33, 0x82, 0x10, 0x10, 0x80, 0x33, ++0x81, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x65, 0x80, 0x33, ++0x67, 0x10, 0x10, 0x80, 0x33, 0x66, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0x46, 0x80, 0x33, 0x48, 0x10, 0x10, 0x80, 0x33, 0x47, 0xe4, 0xe1, 0x81, ++0x40, 0x36, 0x19, 0x9a, 0x60, 0x02, 0xe0, 0x91, 0x40, 0x90, 0xb8, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x1a, 0x20, 0x33, 0x9f, 0xa4, 0x1a, 0x10, 0x33, ++0xa1, 0x10, 0x10, 0xa4, 0x1a, 0x00, 0x33, 0xa0, 0x90, 0x50, 0x90, 0x28, ++0x80, 0x33, 0x84, 0x80, 0x33, 0x86, 0x10, 0x10, 0x80, 0x33, 0x85, 0x90, ++0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x69, 0x80, 0x33, 0x6b, 0x10, ++0x10, 0x80, 0x33, 0x6a, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x4a, 0x80, ++0x33, 0x4c, 0x10, 0x10, 0x80, 0x33, 0x4b, 0x81, 0x90, 0x50, 0x90, 0x28, ++0x24, 0x19, 0xd0, 0x24, 0x19, 0xf0, 0x10, 0x10, 0x24, 0x19, 0xe0, 0xe4, ++0xe1, 0x5a, 0x40, 0x35, 0x91, 0x93, 0x90, 0x99, 0xb8, 0x03, 0x50, 0x90, ++0xe8, 0x90, 0x88, 0x90, 0x40, 0x80, 0xa4, 0x15, 0xb8, 0x32, 0xca, 0x10, ++0x10, 0xa4, 0x15, 0xa8, 0x32, 0xc9, 0x90, 0x28, 0x81, 0x32, 0xc6, 0x10, ++0x10, 0x80, 0x32, 0xc5, 0x90, 0x60, 0x90, 0x28, 0x81, 0x32, 0xc2, 0x10, ++0x10, 0x80, 0x32, 0xc1, 0x90, 0x28, 0x81, 0x32, 0xbe, 0x10, 0x10, 0x80, ++0x32, 0xbd, 0x90, 0xe8, 0x90, 0x88, 0x90, 0x40, 0x80, 0xa4, 0x15, 0x88, ++0x32, 0xc7, 0x10, 0x10, 0xa4, 0x15, 0x98, 0x32, 0xc8, 0x90, 0x28, 0x81, ++0x32, 0xc3, 0x10, 0x10, 0x80, 0x32, 0xc4, 0x90, 0x60, 0x90, 0x28, 0x81, ++0x32, 0xbf, 0x10, 0x10, 0x80, 0x32, 0xc0, 0x90, 0x28, 0x81, 0x32, 0xbb, ++0x10, 0x10, 0x80, 0x32, 0xbc, 0xe4, 0xe1, 0x80, 0x40, 0x36, 0x15, 0x88, ++0x00, 0x88, 0x10, 0x10, 0x10, 0x10, 0x90, 0x28, 0x81, 0x32, 0xb9, 0x10, ++0x10, 0x80, 0x32, 0xba, 0xe4, 0xe1, 0x58, 0x40, 0x35, 0x89, 0xa0, 0x0e, ++0x80, 0xa0, 0x09, 0x08, 0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, ++0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x39, 0x80, 0x33, 0x38, ++0x10, 0x10, 0x80, 0x33, 0x37, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x1e, ++0x80, 0x33, 0x1d, 0x10, 0x10, 0x80, 0x33, 0x1c, 0x90, 0x88, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x33, 0x03, 0x80, 0x33, 0x02, 0x10, 0x10, 0x80, 0x33, ++0x01, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xe8, 0x80, 0x32, 0xe7, 0x10, ++0x10, 0x80, 0x32, 0xe6, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, ++0x80, 0x33, 0x34, 0x80, 0x33, 0x36, 0x10, 0x10, 0x80, 0x33, 0x35, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x33, 0x19, 0x80, 0x33, 0x1b, 0x10, 0x10, 0x80, ++0x33, 0x1a, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xfe, 0x80, ++0x33, 0x00, 0x10, 0x10, 0x80, 0x32, 0xff, 0x90, 0x50, 0x90, 0x28, 0x80, ++0x32, 0xe3, 0x80, 0x32, 0xe5, 0x10, 0x10, 0x80, 0x32, 0xe4, 0xe4, 0xe1, ++0x72, 0x40, 0x35, 0xf1, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, 0x90, 0x88, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x31, 0x80, 0x33, 0x33, 0x10, 0x10, ++0x80, 0x33, 0x32, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x16, 0x80, 0x33, ++0x18, 0x10, 0x10, 0x80, 0x33, 0x17, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, ++0x80, 0x32, 0xfb, 0x80, 0x32, 0xfd, 0x10, 0x10, 0x80, 0x32, 0xfc, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x32, 0xe0, 0x80, 0x32, 0xe2, 0x10, 0x10, 0x80, ++0x32, 0xe1, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0x2e, 0x80, 0x33, 0x30, 0x10, 0x10, 0x80, 0x33, 0x2f, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x33, 0x13, 0x80, 0x33, 0x15, 0x10, 0x10, 0x80, 0x33, 0x14, ++0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xf8, 0x80, 0x32, 0xfa, ++0x10, 0x10, 0x80, 0x32, 0xf9, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xdd, ++0x80, 0x32, 0xdf, 0x10, 0x10, 0x80, 0x32, 0xde, 0xe4, 0xe1, 0x51, 0x40, ++0x35, 0x59, 0x94, 0x80, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x10, 0x90, 0x88, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x2b, 0x80, 0x33, 0x2d, 0x10, 0x10, ++0x80, 0x33, 0x2c, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x10, 0x80, 0x33, ++0x12, 0x10, 0x10, 0x80, 0x33, 0x11, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, ++0x80, 0x32, 0xf5, 0x80, 0x32, 0xf7, 0x10, 0x10, 0x80, 0x32, 0xf6, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x32, 0xda, 0x80, 0x32, 0xdc, 0x10, 0x10, 0x80, ++0x32, 0xdb, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0x28, 0x80, 0x33, 0x2a, 0x10, 0x10, 0x80, 0x33, 0x29, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x33, 0x0d, 0x80, 0x33, 0x0f, 0x10, 0x10, 0x80, 0x33, 0x0e, ++0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xf2, 0x80, 0x32, 0xf4, ++0x10, 0x10, 0x80, 0x32, 0xf3, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xd7, ++0x80, 0x32, 0xd9, 0x10, 0x10, 0x80, 0x32, 0xd8, 0xe4, 0xe1, 0x70, 0x40, ++0x35, 0xe9, 0x88, 0x00, 0xb0, 0x10, 0x10, 0x10, 0x10, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x32, 0xd4, 0x80, 0x32, 0xd6, 0x10, 0x10, 0x80, 0x32, 0xd5, ++0xe4, 0xe1, 0x50, 0x40, 0x35, 0x55, 0x96, 0xe8, 0x94, 0x80, 0x9a, 0x30, ++0x04, 0x40, 0x91, 0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0x22, 0x80, 0x33, 0x27, 0x10, 0x10, 0x80, 0x33, 0x26, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x33, 0x07, 0x80, 0x33, 0x0c, 0x10, 0x10, 0x80, 0x33, 0x0b, ++0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xec, 0x80, 0x32, 0xf1, ++0x10, 0x10, 0x80, 0x32, 0xf0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xce, ++0x80, 0x32, 0xd3, 0x10, 0x10, 0x80, 0x32, 0xd2, 0x91, 0x10, 0x90, 0x88, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x1f, 0x80, 0x33, 0x21, 0x10, 0x10, ++0x80, 0x33, 0x20, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x04, 0x80, 0x33, ++0x06, 0x10, 0x10, 0x80, 0x33, 0x05, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, ++0x80, 0x32, 0xe9, 0x80, 0x32, 0xeb, 0x10, 0x10, 0x80, 0x32, 0xea, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x32, 0xcb, 0x80, 0x32, 0xcd, 0x10, 0x10, 0x80, ++0x32, 0xcc, 0xe4, 0xe1, 0x6e, 0x40, 0x35, 0xe1, 0x88, 0x02, 0x28, 0x91, ++0x10, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0x23, 0x80, 0x33, ++0x25, 0x10, 0x10, 0x80, 0x33, 0x24, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0x08, 0x80, 0x33, 0x0a, 0x10, 0x10, 0x80, 0x33, 0x09, 0x90, 0x88, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x32, 0xed, 0x80, 0x32, 0xef, 0x10, 0x10, 0x80, ++0x32, 0xee, 0x90, 0x50, 0x90, 0x28, 0x80, 0x32, 0xcf, 0x80, 0x32, 0xd1, ++0x10, 0x10, 0x80, 0x32, 0xd0, 0xe4, 0xe1, 0x4f, 0x40, 0x35, 0x51, 0x90, ++0x40, 0xe5, 0x21, 0x6c, 0x40, 0x35, 0xd9, 0xe5, 0x21, 0x4e, 0x40, 0x35, ++0x4d, 0x9e, 0xb4, 0x22, 0xe8, 0x93, 0x70, 0x91, 0xd8, 0xd5, 0x07, 0x80, ++0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c, 0x3e, 0x38, 0x84, 0x37, 0xd1, ++0xa4, 0x3c, 0x18, 0x37, 0x9b, 0x90, 0x28, 0x24, 0x3b, 0x58, 0xa4, 0x39, ++0xd8, 0x37, 0x53, 0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, 0x8c, 0x3e, 0x18, ++0x84, 0x37, 0xcf, 0xa4, 0x3c, 0x08, 0x37, 0x99, 0x90, 0x28, 0x24, 0x3b, ++0x48, 0xa4, 0x39, 0xc8, 0x37, 0x51, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, ++0x90, 0x28, 0x80, 0x37, 0xbb, 0xa4, 0x3b, 0xe8, 0x37, 0x95, 0x90, 0x28, ++0x24, 0x3b, 0x28, 0xa4, 0x39, 0xa8, 0x37, 0x4d, 0xd0, 0xc3, 0x40, 0x90, ++0x28, 0x80, 0x37, 0xb7, 0xa4, 0x3b, 0xd8, 0x37, 0x93, 0x90, 0x28, 0x24, ++0x3b, 0x18, 0xa4, 0x39, 0x98, 0x37, 0x4b, 0x91, 0x98, 0xd5, 0x06, 0x80, ++0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xaf, 0xa4, 0x3b, 0xb8, 0x37, ++0x8f, 0x90, 0x28, 0x24, 0x3a, 0xf8, 0xa4, 0x39, 0x78, 0x37, 0x47, 0xd0, ++0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xab, 0xa4, 0x3b, 0xa8, 0x37, 0x8d, ++0x90, 0x28, 0x24, 0x3a, 0xe8, 0xa4, 0x39, 0x68, 0x37, 0x45, 0xd5, 0x06, ++0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xa3, 0xa4, 0x3b, 0x88, ++0x37, 0x89, 0x90, 0x28, 0x24, 0x3a, 0xc8, 0xa4, 0x39, 0x48, 0x37, 0x41, ++0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0x9f, 0xa4, 0x3b, 0x78, 0x37, ++0x87, 0x90, 0x28, 0x24, 0x3a, 0xb8, 0xa4, 0x39, 0x38, 0x37, 0x3f, 0x93, ++0x70, 0x91, 0xd8, 0xd5, 0x07, 0x80, 0xd0, 0xc4, 0x40, 0x90, 0x48, 0x80, ++0x8c, 0x3e, 0x58, 0x84, 0x37, 0xd3, 0xa4, 0x3c, 0x28, 0x37, 0x9d, 0x90, ++0x28, 0x24, 0x3b, 0x68, 0xa4, 0x39, 0xe8, 0x37, 0x55, 0xd0, 0xc4, 0x40, ++0x90, 0x48, 0x80, 0x8c, 0x3e, 0x28, 0x84, 0x37, 0xd0, 0xa4, 0x3c, 0x10, ++0x37, 0x9a, 0x90, 0x28, 0x24, 0x3b, 0x50, 0xa4, 0x39, 0xd0, 0x37, 0x52, ++0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xbf, 0xa4, ++0x3b, 0xf8, 0x37, 0x97, 0x90, 0x28, 0x24, 0x3b, 0x38, 0xa4, 0x39, 0xb8, ++0x37, 0x4f, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, 0xb9, 0xa4, 0x3b, ++0xe0, 0x37, 0x94, 0x90, 0x28, 0x24, 0x3b, 0x20, 0xa4, 0x39, 0xa0, 0x37, ++0x4c, 0x91, 0x98, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, ++0x37, 0xb3, 0xa4, 0x3b, 0xc8, 0x37, 0x91, 0x90, 0x28, 0x24, 0x3b, 0x08, ++0xa4, 0x39, 0x88, 0x37, 0x49, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, 0x37, ++0xad, 0xa4, 0x3b, 0xb0, 0x37, 0x8e, 0x90, 0x28, 0x24, 0x3a, 0xf0, 0xa4, ++0x39, 0x70, 0x37, 0x46, 0xd5, 0x06, 0x80, 0xd0, 0xc3, 0x40, 0x90, 0x28, ++0x80, 0x37, 0xa7, 0xa4, 0x3b, 0x98, 0x37, 0x8b, 0x90, 0x28, 0x24, 0x3a, ++0xd8, 0xa4, 0x39, 0x58, 0x37, 0x43, 0xd0, 0xc3, 0x40, 0x90, 0x28, 0x80, ++0x37, 0xa1, 0xa4, 0x3b, 0x80, 0x37, 0x88, 0x90, 0x28, 0x24, 0x3a, 0xc0, ++0xa4, 0x39, 0x40, 0x37, 0x40, 0x99, 0x08, 0x01, 0xf0, 0x81, 0x90, 0x78, ++0xd4, 0xc2, 0x00, 0xa4, 0x22, 0x80, 0x34, 0x40, 0xa4, 0x21, 0x80, 0x34, ++0x20, 0xd4, 0xc2, 0x00, 0xa4, 0x21, 0xa0, 0x34, 0x44, 0xa4, 0x20, 0xa0, ++0x34, 0x24, 0x81, 0x90, 0x78, 0xd4, 0xc2, 0x00, 0xa4, 0x21, 0xe0, 0x34, ++0x4c, 0xa4, 0x20, 0xe0, 0x34, 0x2c, 0xd4, 0xc2, 0x00, 0xa4, 0x21, 0xc0, ++0x34, 0x48, 0xa4, 0x20, 0xc0, 0x34, 0x28, 0xa8, 0x0b, 0x18, 0x13, 0xa8, ++0x96, 0x80, 0x93, 0x40, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x12, 0xb8, 0x32, 0x58, 0x24, 0x12, 0xb0, 0x90, 0x38, ++0xa4, 0x11, 0xe0, 0x32, 0x3d, 0x24, 0x11, 0xd8, 0x90, 0x60, 0x90, 0x38, ++0xa4, 0x11, 0x08, 0x32, 0x22, 0x24, 0x11, 0x00, 0x90, 0x38, 0xa4, 0x10, ++0x30, 0x32, 0x07, 0x24, 0x10, 0x28, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, ++0xa4, 0x12, 0xa8, 0x32, 0x53, 0x24, 0x12, 0xa0, 0x90, 0x38, 0xa4, 0x11, ++0xd0, 0x32, 0x38, 0x24, 0x11, 0xc8, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, ++0xf8, 0x32, 0x1d, 0x24, 0x10, 0xf0, 0x90, 0x38, 0xa4, 0x10, 0x20, 0x32, ++0x02, 0x24, 0x10, 0x18, 0xe4, 0xe1, 0xc8, 0x40, 0x37, 0x23, 0x99, 0x90, ++0x03, 0x00, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x90, 0x32, ++0x50, 0x24, 0x12, 0x88, 0x90, 0x38, 0xa4, 0x11, 0xb8, 0x32, 0x35, 0x24, ++0x11, 0xb0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, 0xe0, 0x32, 0x1a, 0x24, ++0x10, 0xd8, 0x90, 0x38, 0xa4, 0x10, 0x08, 0x31, 0xff, 0x24, 0x10, 0x00, ++0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x78, 0x32, 0x4d, 0x24, ++0x12, 0x70, 0x90, 0x38, 0xa4, 0x11, 0xa0, 0x32, 0x32, 0x24, 0x11, 0x98, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, 0xc8, 0x32, 0x17, 0x24, 0x10, 0xc0, ++0x90, 0x38, 0xa4, 0x0f, 0xf0, 0x31, 0xfc, 0x24, 0x0f, 0xe8, 0xe4, 0xe1, ++0xc6, 0xc0, 0x37, 0x1d, 0x93, 0x78, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x60, 0x32, 0x4a, 0x24, 0x12, 0x58, ++0x90, 0x38, 0xa4, 0x11, 0x88, 0x32, 0x2f, 0x24, 0x11, 0x80, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x10, 0xb0, 0x32, 0x14, 0x24, 0x10, 0xa8, 0x90, 0x38, ++0xa4, 0x0f, 0xd8, 0x31, 0xf9, 0x24, 0x0f, 0xd0, 0x90, 0xc0, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x12, 0x48, 0x32, 0x47, 0x24, 0x12, 0x40, 0x90, 0x38, ++0xa4, 0x11, 0x70, 0x32, 0x2c, 0x24, 0x11, 0x68, 0x90, 0x60, 0x90, 0x38, ++0xa4, 0x10, 0x98, 0x32, 0x11, 0x24, 0x10, 0x90, 0x90, 0x38, 0xa4, 0x0f, ++0xc0, 0x31, 0xf6, 0x24, 0x0f, 0xb8, 0xec, 0xa1, 0x16, 0x00, 0x02, 0x00, ++0x34, 0x5a, 0xa4, 0x38, 0xa8, 0x37, 0x17, 0x88, 0x00, 0x88, 0x10, 0x10, ++0x10, 0x10, 0x90, 0x38, 0xa4, 0x0f, 0xa8, 0x31, 0xf3, 0x24, 0x0f, 0xa0, ++0xe9, 0x61, 0x15, 0x40, 0x02, 0x00, 0x34, 0x56, 0xe3, 0x61, 0xc3, 0xc0, ++0x37, 0x11, 0x95, 0x08, 0x93, 0x40, 0x99, 0x90, 0x03, 0x00, 0x90, 0xc0, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x30, 0x32, 0x41, 0x24, 0x12, 0x28, ++0x90, 0x38, 0xa4, 0x11, 0x58, 0x32, 0x26, 0x24, 0x11, 0x50, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x10, 0x80, 0x32, 0x0b, 0x24, 0x10, 0x78, 0x90, 0x38, ++0xa4, 0x0f, 0x90, 0x31, 0xed, 0x24, 0x0f, 0x88, 0x90, 0xc0, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x12, 0x00, 0x32, 0x3e, 0x24, 0x11, 0xf8, 0x90, 0x38, ++0xa4, 0x11, 0x28, 0x32, 0x23, 0x24, 0x11, 0x20, 0x90, 0x60, 0x90, 0x38, ++0xa4, 0x10, 0x50, 0x32, 0x08, 0x24, 0x10, 0x48, 0x90, 0x38, 0xa4, 0x0f, ++0x60, 0x31, 0xea, 0x24, 0x0f, 0x58, 0xe4, 0xe1, 0xc8, 0x80, 0x37, 0x25, ++0x88, 0x01, 0x88, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x12, 0x20, ++0x32, 0x42, 0x24, 0x12, 0x18, 0x90, 0x38, 0xa4, 0x11, 0x48, 0x32, 0x27, ++0x24, 0x11, 0x40, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x10, 0x70, 0x32, 0x0c, ++0x24, 0x10, 0x68, 0x90, 0x38, 0xa4, 0x0f, 0x80, 0x31, 0xee, 0x24, 0x0f, ++0x78, 0xe4, 0xe1, 0xc7, 0x00, 0x37, 0x1f, 0x92, 0xd0, 0x99, 0x50, 0x02, ++0x80, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xe9, 0x24, 0x0f, ++0x40, 0x90, 0x28, 0x80, 0x31, 0xe5, 0x24, 0x0f, 0x20, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x31, 0xe1, 0x24, 0x0f, 0x00, 0x90, 0x28, 0x80, 0x31, 0xdd, ++0x24, 0x0e, 0xe0, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xe6, ++0x24, 0x0f, 0x38, 0x90, 0x28, 0x80, 0x31, 0xe2, 0x24, 0x0f, 0x18, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x31, 0xde, 0x24, 0x0e, 0xf8, 0x90, 0x28, 0x80, ++0x31, 0xda, 0x24, 0x0e, 0xd8, 0xec, 0xe1, 0xc5, 0xa1, 0x17, 0x00, 0x37, ++0x19, 0x88, 0x00, 0x78, 0x10, 0x10, 0x10, 0x10, 0x90, 0x28, 0x80, 0x31, ++0xd8, 0x24, 0x0e, 0xc8, 0xec, 0xe1, 0xc4, 0x21, 0x15, 0x00, 0x37, 0x13, ++0xe5, 0xa1, 0x4d, 0x40, 0x35, 0x31, 0xa0, 0x2a, 0x10, 0xa8, 0x16, 0x60, ++0x29, 0xd8, 0xa0, 0x0c, 0x48, 0xa0, 0x0a, 0xc8, 0x95, 0x60, 0x92, 0xb0, ++0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0xa1, 0x80, ++0x31, 0xa0, 0x10, 0x10, 0x80, 0x31, 0x9f, 0x90, 0x70, 0x90, 0x38, 0xa4, ++0x08, 0x98, 0x31, 0xb3, 0xa4, 0x08, 0x90, 0x31, 0xb2, 0x10, 0x10, 0xa4, ++0x08, 0x88, 0x31, 0xb1, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, ++0xb8, 0x31, 0xd7, 0xa4, 0x09, 0xb0, 0x31, 0xd6, 0x10, 0x10, 0xa4, 0x09, ++0xa8, 0x31, 0xd5, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, 0x28, 0x31, 0xc5, ++0xa4, 0x09, 0x20, 0x31, 0xc4, 0x10, 0x10, 0xa4, 0x09, 0x18, 0x31, 0xc3, ++0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x9c, 0x80, ++0x31, 0x9e, 0x10, 0x10, 0x80, 0x31, 0x9d, 0x90, 0x70, 0x90, 0x38, 0xa4, ++0x08, 0x70, 0x31, 0xae, 0xa4, 0x08, 0x80, 0x31, 0xb0, 0x10, 0x10, 0xa4, ++0x08, 0x78, 0x31, 0xaf, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, ++0x90, 0x31, 0xd2, 0xa4, 0x09, 0xa0, 0x31, 0xd4, 0x10, 0x10, 0xa4, 0x09, ++0x98, 0x31, 0xd3, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x09, 0x00, 0x31, 0xc0, ++0xa4, 0x09, 0x10, 0x31, 0xc2, 0x10, 0x10, 0xa4, 0x09, 0x08, 0x31, 0xc1, ++0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, ++0x99, 0x80, 0x31, 0x9b, 0x10, 0x10, 0x80, 0x31, 0x9a, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x08, 0x58, 0x31, 0xab, 0xa4, 0x08, 0x68, 0x31, 0xad, 0x10, ++0x10, 0xa4, 0x08, 0x60, 0x31, 0xac, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x09, 0x78, 0x31, 0xcf, 0xa4, 0x09, 0x88, 0x31, 0xd1, 0x10, 0x10, ++0xa4, 0x09, 0x80, 0x31, 0xd0, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0xe8, ++0x31, 0xbd, 0xa4, 0x08, 0xf8, 0x31, 0xbf, 0x10, 0x10, 0xa4, 0x08, 0xf0, ++0x31, 0xbe, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, 0x31, ++0x96, 0x80, 0x31, 0x98, 0x10, 0x10, 0x80, 0x31, 0x97, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x08, 0x40, 0x31, 0xa8, 0xa4, 0x08, 0x50, 0x31, 0xaa, 0x10, ++0x10, 0xa4, 0x08, 0x48, 0x31, 0xa9, 0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x09, 0x60, 0x31, 0xcc, 0xa4, 0x09, 0x70, 0x31, 0xce, 0x10, 0x10, ++0xa4, 0x09, 0x68, 0x31, 0xcd, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0xd0, ++0x31, 0xba, 0xa4, 0x08, 0xe0, 0x31, 0xbc, 0x10, 0x10, 0xa4, 0x08, 0xd8, ++0x31, 0xbb, 0x10, 0x10, 0x90, 0xa8, 0x10, 0x10, 0x10, 0x10, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x31, 0x8d, 0x80, 0x31, 0x8f, 0x10, 0x10, 0x80, 0x31, ++0x8e, 0x90, 0x60, 0x90, 0x30, 0x60, 0xa0, 0x2a, 0xc0, 0x60, 0xa0, 0x2a, ++0x80, 0x90, 0x30, 0x60, 0xa0, 0x2a, 0x40, 0x60, 0xa0, 0x2a, 0x00, 0x97, ++0xf0, 0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x31, 0x93, 0x80, 0x31, 0x95, 0x10, 0x10, 0x80, 0x31, 0x94, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0x28, 0x31, 0xa5, 0xa4, 0x08, 0x38, ++0x31, 0xa7, 0x10, 0x10, 0xa4, 0x08, 0x30, 0x31, 0xa6, 0x90, 0xb8, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x09, 0x48, 0x31, 0xc9, 0xa4, 0x09, 0x58, 0x31, ++0xcb, 0x10, 0x10, 0xa4, 0x09, 0x50, 0x31, 0xca, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x08, 0xb8, 0x31, 0xb7, 0xa4, 0x08, 0xc8, 0x31, 0xb9, 0x10, 0x10, ++0xa4, 0x08, 0xc0, 0x31, 0xb8, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x31, 0x90, 0x80, 0x31, 0x92, 0x10, 0x10, 0x80, 0x31, 0x91, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x08, 0x10, 0x31, 0xa2, 0xa4, 0x08, 0x20, ++0x31, 0xa4, 0x10, 0x10, 0xa4, 0x08, 0x18, 0x31, 0xa3, 0x90, 0xb8, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x09, 0x30, 0x31, 0xc6, 0xa4, 0x09, 0x40, 0x31, ++0xc8, 0x10, 0x10, 0xa4, 0x09, 0x38, 0x31, 0xc7, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x08, 0xa0, 0x31, 0xb4, 0xa4, 0x08, 0xb0, 0x31, 0xb6, 0x10, 0x10, ++0xa4, 0x08, 0xa8, 0x31, 0xb5, 0x10, 0x10, 0x91, 0x40, 0x90, 0xa0, 0x90, ++0x50, 0x90, 0x28, 0x80, 0x30, 0xcb, 0x80, 0x30, 0xca, 0x90, 0x28, 0x80, ++0x30, 0xc9, 0x80, 0x30, 0xc8, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xc4, ++0x80, 0x30, 0xc7, 0x90, 0x28, 0x80, 0x30, 0xc6, 0x80, 0x30, 0xc5, 0x90, ++0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xbc, 0x80, 0x30, 0xc3, 0x90, ++0x28, 0x80, 0x30, 0xc2, 0x80, 0x30, 0xc1, 0x90, 0x50, 0x90, 0x28, 0x80, ++0x30, 0xbd, 0x80, 0x30, 0xc0, 0x90, 0x28, 0x80, 0x30, 0xbf, 0x80, 0x30, ++0xbe, 0x91, 0x88, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x28, 0x81, 0x31, ++0x3b, 0x10, 0x10, 0x80, 0x31, 0x3a, 0x90, 0x28, 0x81, 0x31, 0x3d, 0x10, ++0x10, 0x80, 0x31, 0x3c, 0x90, 0x60, 0x90, 0x28, 0x81, 0x31, 0x41, 0x10, ++0x10, 0x80, 0x31, 0x40, 0x90, 0x28, 0x81, 0x31, 0x3f, 0x10, 0x10, 0x80, ++0x31, 0x3e, 0x80, 0x10, 0x10, 0x10, 0x10, 0x90, 0x28, 0x81, 0x31, 0x38, ++0x10, 0x10, 0x80, 0x31, 0x39, 0xa0, 0x0b, 0x90, 0xa0, 0x0a, 0xc8, 0x95, ++0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, ++0x31, 0x56, 0x80, 0x31, 0x55, 0x10, 0x10, 0x80, 0x31, 0x54, 0x90, 0x70, ++0x90, 0x38, 0xa4, 0x06, 0xe8, 0x31, 0x68, 0xa4, 0x06, 0xe0, 0x31, 0x67, ++0x10, 0x10, 0xa4, 0x06, 0xd8, 0x31, 0x66, 0x90, 0xb8, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x08, 0x08, 0x31, 0x8c, 0xa4, 0x08, 0x00, 0x31, 0x8b, 0x10, ++0x10, 0xa4, 0x07, 0xf8, 0x31, 0x8a, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, ++0x78, 0x31, 0x7a, 0xa4, 0x07, 0x70, 0x31, 0x79, 0x10, 0x10, 0xa4, 0x07, ++0x68, 0x31, 0x78, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, 0x28, 0x80, ++0x31, 0x51, 0x80, 0x31, 0x53, 0x10, 0x10, 0x80, 0x31, 0x52, 0x90, 0x70, ++0x90, 0x38, 0xa4, 0x06, 0xc0, 0x31, 0x63, 0xa4, 0x06, 0xd0, 0x31, 0x65, ++0x10, 0x10, 0xa4, 0x06, 0xc8, 0x31, 0x64, 0x90, 0xb8, 0x90, 0x70, 0x90, ++0x38, 0xa4, 0x07, 0xe0, 0x31, 0x87, 0xa4, 0x07, 0xf0, 0x31, 0x89, 0x10, ++0x10, 0xa4, 0x07, 0xe8, 0x31, 0x88, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, ++0x50, 0x31, 0x75, 0xa4, 0x07, 0x60, 0x31, 0x77, 0x10, 0x10, 0xa4, 0x07, ++0x58, 0x31, 0x76, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x31, 0x4e, 0x80, 0x31, 0x50, 0x10, 0x10, 0x80, 0x31, 0x4f, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0xa8, 0x31, 0x60, 0xa4, 0x06, 0xb8, ++0x31, 0x62, 0x10, 0x10, 0xa4, 0x06, 0xb0, 0x31, 0x61, 0x90, 0xb8, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x07, 0xc8, 0x31, 0x84, 0xa4, 0x07, 0xd8, 0x31, ++0x86, 0x10, 0x10, 0xa4, 0x07, 0xd0, 0x31, 0x85, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x07, 0x38, 0x31, 0x72, 0xa4, 0x07, 0x48, 0x31, 0x74, 0x10, 0x10, ++0xa4, 0x07, 0x40, 0x31, 0x73, 0x91, 0x40, 0x90, 0x88, 0x90, 0x50, 0x90, ++0x28, 0x80, 0x31, 0x4b, 0x80, 0x31, 0x4d, 0x10, 0x10, 0x80, 0x31, 0x4c, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x90, 0x31, 0x5d, 0xa4, 0x06, 0xa0, ++0x31, 0x5f, 0x10, 0x10, 0xa4, 0x06, 0x98, 0x31, 0x5e, 0x90, 0xb8, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x07, 0xb0, 0x31, 0x81, 0xa4, 0x07, 0xc0, 0x31, ++0x83, 0x10, 0x10, 0xa4, 0x07, 0xb8, 0x31, 0x82, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x07, 0x20, 0x31, 0x6f, 0xa4, 0x07, 0x30, 0x31, 0x71, 0x10, 0x10, ++0xa4, 0x07, 0x28, 0x31, 0x70, 0x10, 0x10, 0x80, 0x10, 0x10, 0x10, 0x10, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x42, 0x80, 0x31, 0x44, 0x10, 0x10, ++0x80, 0x31, 0x43, 0x80, 0x95, 0x60, 0x92, 0xb0, 0x91, 0x40, 0x90, 0x88, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x48, 0x80, 0x31, 0x4a, 0x10, 0x10, ++0x80, 0x31, 0x49, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x78, 0x31, 0x5a, ++0xa4, 0x06, 0x88, 0x31, 0x5c, 0x10, 0x10, 0xa4, 0x06, 0x80, 0x31, 0x5b, ++0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, 0x98, 0x31, 0x7e, 0xa4, ++0x07, 0xa8, 0x31, 0x80, 0x10, 0x10, 0xa4, 0x07, 0xa0, 0x31, 0x7f, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x07, 0x08, 0x31, 0x6c, 0xa4, 0x07, 0x18, 0x31, ++0x6e, 0x10, 0x10, 0xa4, 0x07, 0x10, 0x31, 0x6d, 0x91, 0x40, 0x90, 0x88, ++0x90, 0x50, 0x90, 0x28, 0x80, 0x31, 0x45, 0x80, 0x31, 0x47, 0x10, 0x10, ++0x80, 0x31, 0x46, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x06, 0x60, 0x31, 0x57, ++0xa4, 0x06, 0x70, 0x31, 0x59, 0x10, 0x10, 0xa4, 0x06, 0x68, 0x31, 0x58, ++0x90, 0xb8, 0x90, 0x70, 0x90, 0x38, 0xa4, 0x07, 0x80, 0x31, 0x7b, 0xa4, ++0x07, 0x90, 0x31, 0x7d, 0x10, 0x10, 0xa4, 0x07, 0x88, 0x31, 0x7c, 0x90, ++0x70, 0x90, 0x38, 0xa4, 0x06, 0xf0, 0x31, 0x69, 0xa4, 0x07, 0x00, 0x31, ++0x6b, 0x10, 0x10, 0xa4, 0x06, 0xf8, 0x31, 0x6a, 0x10, 0x10, 0x91, 0x40, ++0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xbb, 0x80, 0x30, 0xba, ++0x90, 0x28, 0x80, 0x30, 0xb9, 0x80, 0x30, 0xb8, 0x90, 0x50, 0x90, 0x28, ++0x80, 0x30, 0xb4, 0x80, 0x30, 0xb7, 0x90, 0x28, 0x80, 0x30, 0xb6, 0x80, ++0x30, 0xb5, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0xac, 0x80, ++0x30, 0xb3, 0x90, 0x28, 0x80, 0x30, 0xb2, 0x80, 0x30, 0xb1, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x30, 0xad, 0x80, 0x30, 0xb0, 0x90, 0x28, 0x80, 0x30, ++0xaf, 0x80, 0x30, 0xae, 0xc3, 0xc0, 0x30, 0x42, 0x9c, 0xe8, 0x07, 0x60, ++0x91, 0x90, 0x90, 0xf0, 0x10, 0x10, 0x80, 0x88, 0x00, 0x80, 0x90, 0x50, ++0x90, 0x28, 0x80, 0x33, 0xf8, 0x80, 0x33, 0xf9, 0x81, 0x33, 0xef, 0xd0, ++0x41, 0x80, 0x24, 0x20, 0x90, 0x24, 0x20, 0x98, 0x10, 0x10, 0x80, 0x90, ++0x58, 0x80, 0x90, 0x28, 0x24, 0x1f, 0x90, 0x24, 0x1f, 0x98, 0x81, 0x24, ++0x1f, 0x50, 0x92, 0x68, 0x91, 0x00, 0x80, 0x90, 0x90, 0x90, 0x30, 0x80, ++0x24, 0x20, 0x00, 0x90, 0x38, 0xa4, 0x1f, 0xf8, 0x34, 0x06, 0x80, 0x34, ++0x05, 0x80, 0x90, 0x28, 0x80, 0x34, 0x0f, 0xa4, 0x1f, 0xe0, 0x34, 0x0e, ++0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x28, 0x80, 0x34, 0x09, 0xa4, 0x1f, ++0xf0, 0x34, 0x08, 0x90, 0x28, 0x80, 0x34, 0x04, 0xa4, 0x1f, 0xe8, 0x34, ++0x03, 0x90, 0x50, 0x90, 0x28, 0x80, 0x34, 0x0d, 0x80, 0x34, 0x0c, 0x90, ++0x28, 0x24, 0x20, 0x88, 0x24, 0x20, 0x80, 0x90, 0x58, 0x80, 0x10, 0x10, ++0x80, 0x10, 0x10, 0x80, 0x33, 0xfb, 0x80, 0x90, 0x40, 0x10, 0x10, 0x80, ++0x24, 0x1f, 0x60, 0x80, 0x10, 0x10, 0x80, 0x33, 0xfa, 0x91, 0x58, 0x91, ++0x00, 0x90, 0x80, 0x81, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, 0xf6, 0x80, ++0x33, 0xf7, 0x81, 0x33, 0xee, 0x81, 0x90, 0x50, 0x90, 0x28, 0x80, 0x33, ++0xf4, 0x80, 0x33, 0xf5, 0x81, 0x33, 0xed, 0x83, 0x90, 0x28, 0x24, 0x1f, ++0x80, 0x24, 0x1f, 0x88, 0x90, 0xe8, 0x81, 0x90, 0x88, 0x90, 0x38, 0x10, ++0x10, 0x80, 0x34, 0x07, 0x90, 0x28, 0x80, 0x34, 0x02, 0x80, 0x34, 0x01, ++0x80, 0x90, 0x28, 0x80, 0x34, 0x0b, 0x80, 0x34, 0x0a, 0x82, 0x10, 0x10, ++0x80, 0x24, 0x1f, 0x58, 0x97, 0x10, 0x9e, 0x10, 0x06, 0x98, 0x93, 0x00, ++0x91, 0x80, 0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x80, 0x30, ++0x71, 0x24, 0x03, 0x78, 0x90, 0x38, 0xa4, 0x04, 0x10, 0x30, 0x83, 0x24, ++0x04, 0x08, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x05, 0x30, 0x30, 0xa7, 0x24, ++0x05, 0x28, 0x90, 0x38, 0xa4, 0x04, 0xa0, 0x30, 0x95, 0x24, 0x04, 0x98, ++0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x70, 0x30, 0x6c, 0x24, ++0x03, 0x68, 0x90, 0x38, 0xa4, 0x04, 0x00, 0x30, 0x7e, 0x24, 0x03, 0xf8, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x05, 0x20, 0x30, 0xa2, 0x24, 0x05, 0x18, ++0x90, 0x38, 0xa4, 0x04, 0x90, 0x30, 0x90, 0x24, 0x04, 0x88, 0x91, 0x80, ++0x90, 0xc0, 0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x58, 0x30, 0x69, 0x24, ++0x03, 0x50, 0x90, 0x38, 0xa4, 0x03, 0xe8, 0x30, 0x7b, 0x24, 0x03, 0xe0, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x05, 0x08, 0x30, 0x9f, 0x24, 0x05, 0x00, ++0x90, 0x38, 0xa4, 0x04, 0x78, 0x30, 0x8d, 0x24, 0x04, 0x70, 0x90, 0xc0, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x40, 0x30, 0x66, 0x24, 0x03, 0x38, ++0x90, 0x38, 0xa4, 0x03, 0xd0, 0x30, 0x78, 0x24, 0x03, 0xc8, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x04, 0xf0, 0x30, 0x9c, 0x24, 0x04, 0xe8, 0x90, 0x38, ++0xa4, 0x04, 0x60, 0x30, 0x8a, 0x24, 0x04, 0x58, 0x10, 0x10, 0x80, 0x10, ++0x10, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x02, 0xf8, 0x30, 0x5d, 0x24, 0x02, ++0xf0, 0xd7, 0x42, 0x00, 0xa4, 0x38, 0x58, 0x37, 0x0d, 0xa4, 0x38, 0x38, ++0x37, 0x09, 0x9c, 0xe0, 0x06, 0x90, 0x93, 0x00, 0x91, 0x80, 0x90, 0xc0, ++0x90, 0x60, 0x90, 0x38, 0xa4, 0x03, 0x28, 0x30, 0x63, 0x24, 0x03, 0x20, ++0x90, 0x38, 0xa4, 0x03, 0xb8, 0x30, 0x75, 0x24, 0x03, 0xb0, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x04, 0xd8, 0x30, 0x99, 0x24, 0x04, 0xd0, 0x90, 0x38, ++0xa4, 0x04, 0x48, 0x30, 0x87, 0x24, 0x04, 0x40, 0x90, 0xc0, 0x90, 0x60, ++0x90, 0x38, 0xa4, 0x03, 0x10, 0x30, 0x60, 0x24, 0x03, 0x08, 0x90, 0x38, ++0xa4, 0x03, 0xa0, 0x30, 0x72, 0x24, 0x03, 0x98, 0x90, 0x60, 0x90, 0x38, ++0xa4, 0x04, 0xc0, 0x30, 0x96, 0x24, 0x04, 0xb8, 0x90, 0x38, 0xa4, 0x04, ++0x30, 0x30, 0x84, 0x24, 0x04, 0x28, 0x10, 0x10, 0x90, 0xe0, 0x90, 0x70, ++0x90, 0x38, 0xa4, 0x02, 0x88, 0x30, 0x52, 0xa4, 0x02, 0x78, 0x30, 0x50, ++0x90, 0x38, 0xa4, 0x02, 0x70, 0x30, 0x4b, 0xa4, 0x02, 0x60, 0x30, 0x4d, ++0x90, 0x70, 0x90, 0x38, 0xa4, 0x02, 0x50, 0x30, 0x43, 0xa4, 0x02, 0x40, ++0x30, 0x49, 0x90, 0x38, 0xa4, 0x02, 0x38, 0x30, 0x44, 0xa4, 0x02, 0x28, ++0x30, 0x46, 0x91, 0x48, 0x80, 0x90, 0xa0, 0x90, 0x50, 0x90, 0x28, 0x80, ++0x30, 0x56, 0x24, 0x02, 0xa8, 0x90, 0x28, 0x80, 0x30, 0x58, 0x24, 0x02, ++0xb8, 0x90, 0x50, 0x90, 0x28, 0x80, 0x30, 0x5c, 0x24, 0x02, 0xd8, 0x90, ++0x28, 0x80, 0x30, 0x5a, 0x24, 0x02, 0xc8, 0x80, 0x10, 0x10, 0x10, 0x10, ++0x90, 0x28, 0x80, 0x30, 0x53, 0x24, 0x02, 0xa0, 0xd7, 0x42, 0x00, 0xa4, ++0x38, 0x60, 0x37, 0x0e, 0xa4, 0x38, 0x40, 0x37, 0x0a, 0xa0, 0x14, 0x68, ++0xa0, 0x10, 0x90, 0xa0, 0x0c, 0x60, 0x9e, 0x88, 0x09, 0xd0, 0x94, 0xf0, ++0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x44, 0x40, ++0x85, 0x35, 0x2d, 0xcb, 0x61, 0x3d, 0x00, 0x85, 0x35, 0x03, 0x9a, 0x00, ++0x03, 0xf8, 0x91, 0x98, 0x80, 0x91, 0x10, 0x90, 0xa0, 0x90, 0x68, 0x90, ++0x20, 0x3a, 0x53, 0xc9, 0xe2, 0x94, 0x40, 0x85, 0x35, 0x2b, 0xa4, 0x52, ++0x78, 0x3a, 0x50, 0x90, 0x38, 0xa4, 0x52, 0x40, 0x3a, 0x49, 0xa4, 0x52, ++0x30, 0x3a, 0x47, 0x90, 0x48, 0x10, 0x10, 0xa4, 0x51, 0xf8, 0x3a, 0x40, ++0x10, 0x10, 0x80, 0x3a, 0x3c, 0x81, 0x10, 0x10, 0x80, 0xa4, 0x51, 0xc8, ++0x3a, 0x3a, 0x91, 0xb0, 0x91, 0x60, 0x90, 0xe0, 0x90, 0x70, 0x90, 0x38, ++0xa4, 0x52, 0x68, 0x3a, 0x4e, 0xa4, 0x52, 0x58, 0x3a, 0x4c, 0x90, 0x38, ++0xa4, 0x52, 0x20, 0x3a, 0x45, 0xa4, 0x52, 0x10, 0x3a, 0x43, 0x90, 0x48, ++0x10, 0x10, 0xa4, 0x51, 0xe8, 0x3a, 0x3e, 0x10, 0x10, 0x80, 0x3a, 0x3b, ++0x90, 0x28, 0x80, 0x3a, 0x34, 0x80, 0x3a, 0x33, 0x81, 0x10, 0x10, 0x80, ++0xa4, 0x51, 0xb8, 0x3a, 0x38, 0xcb, 0x61, 0x3c, 0xc0, 0x85, 0x35, 0x02, ++0x90, 0xd8, 0x88, 0x00, 0x90, 0x84, 0x90, 0x38, 0xc1, 0xc0, 0x85, 0x3a, ++0x56, 0xc9, 0xe1, 0x44, 0x00, 0x85, 0x35, 0x29, 0xcb, 0x61, 0x3c, 0x80, ++0x85, 0x35, 0x01, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x43, ++0xc0, 0x85, 0x35, 0x27, 0xcb, 0x61, 0x3c, 0x40, 0x85, 0x35, 0x00, 0x91, ++0xf8, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x43, ++0x40, 0x85, 0x35, 0x23, 0xcb, 0x61, 0x3b, 0xc0, 0x85, 0x34, 0xfe, 0x88, ++0x01, 0x00, 0x90, 0xa0, 0x81, 0x90, 0x70, 0x80, 0x90, 0x20, 0x3a, 0x4a, ++0xc9, 0xe1, 0x43, 0x00, 0x85, 0x35, 0x21, 0x81, 0x3a, 0x41, 0x81, 0x10, ++0x10, 0x80, 0xa4, 0x51, 0xa8, 0x3a, 0x36, 0xcb, 0x61, 0x3b, 0x80, 0x85, ++0x34, 0xfd, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, ++0x42, 0xc0, 0x85, 0x35, 0x1f, 0xcb, 0x61, 0x3b, 0x40, 0x85, 0x34, 0xfc, ++0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x42, 0x80, 0x85, 0x35, ++0x1d, 0xcb, 0x61, 0x3b, 0x00, 0x85, 0x34, 0xfb, 0x92, 0x38, 0x81, 0x91, ++0x68, 0x91, 0x18, 0x90, 0x80, 0x90, 0x40, 0x80, 0xa4, 0x53, 0x28, 0x3a, ++0x66, 0x80, 0xa4, 0x53, 0x20, 0x3a, 0x63, 0x90, 0x28, 0x81, 0x3a, 0x62, ++0x90, 0x38, 0xa4, 0x53, 0x00, 0x3a, 0x61, 0xa4, 0x52, 0xf0, 0x3a, 0x5f, ++0x90, 0x28, 0x80, 0x3a, 0x5d, 0x80, 0x3a, 0x5c, 0x80, 0x90, 0x40, 0x10, ++0x10, 0x80, 0x24, 0x52, 0xd8, 0x10, 0x10, 0x90, 0x38, 0xa4, 0x52, 0xc8, ++0x3a, 0x5a, 0xa4, 0x52, 0xb8, 0x3a, 0x58, 0x90, 0x28, 0x80, 0x3a, 0x55, ++0x80, 0x3a, 0x54, 0x9a, 0xd0, 0x03, 0xe0, 0x91, 0x60, 0x90, 0xb0, 0x88, ++0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x42, 0x00, 0x85, 0x35, 0x19, ++0xcb, 0x61, 0x3a, 0x80, 0x85, 0x34, 0xf9, 0x88, 0x00, 0x68, 0x84, 0x10, ++0x10, 0xc9, 0xe1, 0x41, 0xc0, 0x85, 0x35, 0x17, 0xcb, 0x61, 0x3a, 0x40, ++0x85, 0x34, 0xf8, 0x90, 0xb0, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, ++0xe1, 0x41, 0x80, 0x85, 0x35, 0x15, 0xcb, 0x61, 0x3a, 0x00, 0x85, 0x34, ++0xf7, 0x88, 0x00, 0x68, 0x84, 0x10, 0x10, 0xc9, 0xe1, 0x41, 0x40, 0x85, ++0x35, 0x13, 0xcb, 0x61, 0x39, 0xc0, 0x85, 0x34, 0xf6, 0x90, 0x90, 0x90, ++0x48, 0xcb, 0xa1, 0x38, 0x00, 0x85, 0x34, 0xe5, 0xcb, 0xa1, 0x37, 0xc0, ++0x85, 0x34, 0xe4, 0x90, 0x48, 0xcb, 0xa1, 0x37, 0x80, 0x85, 0x34, 0xe3, ++0xcb, 0xa1, 0x37, 0x40, 0x85, 0x34, 0xe2, 0xcb, 0xa2, 0x8c, 0x40, 0x80, ++0x3a, 0x32, 0x92, 0x40, 0x91, 0x20, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x26, ++0x60, 0x84, 0x24, 0x26, 0xd8, 0x8c, 0x26, 0x58, 0x84, 0x24, 0x26, 0xd0, ++0x90, 0x48, 0x8c, 0x26, 0x50, 0x84, 0x24, 0x26, 0xc8, 0x8c, 0x26, 0x48, ++0x84, 0x24, 0x26, 0xc0, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x26, 0x38, 0x84, ++0x24, 0x26, 0xb0, 0x8c, 0x26, 0x30, 0x84, 0x24, 0x26, 0xa8, 0x90, 0x48, ++0x8c, 0x26, 0x28, 0x84, 0x24, 0x26, 0xa0, 0x8c, 0x26, 0x20, 0x84, 0x24, ++0x26, 0x98, 0x91, 0x20, 0x90, 0x90, 0x90, 0x48, 0x8c, 0x26, 0x10, 0x84, ++0x24, 0x26, 0x88, 0x8c, 0x26, 0x08, 0x84, 0x24, 0x26, 0x80, 0x90, 0x48, ++0x8c, 0x26, 0x00, 0x84, 0x24, 0x26, 0x78, 0x8c, 0x25, 0xf8, 0x84, 0x24, ++0x26, 0x70, 0x90, 0x38, 0xa4, 0x25, 0xe0, 0x34, 0xbd, 0xa4, 0x25, 0xd0, ++0x34, 0xbb, 0xa0, 0x0f, 0x50, 0xa0, 0x09, 0x08, 0x9a, 0x30, 0x04, 0x40, ++0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x8a, 0x40, ++0x3a, 0x21, 0xe5, 0x22, 0x82, 0x40, 0x3a, 0x1d, 0xcb, 0x61, 0x2a, 0x40, ++0x85, 0x34, 0xb8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x7a, 0x40, 0x39, ++0xe1, 0xe5, 0x22, 0x72, 0x40, 0x39, 0xdd, 0xcb, 0x61, 0x2a, 0x00, 0x85, ++0x34, 0xb7, 0x90, 0x48, 0xcb, 0xa1, 0x29, 0xc0, 0x85, 0x34, 0xb6, 0xcb, ++0xa1, 0x29, 0x80, 0x85, 0x34, 0xb5, 0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, ++0x00, 0x80, 0xe5, 0x22, 0x64, 0x40, 0x39, 0xa9, 0xe5, 0x22, 0x58, 0x40, ++0x39, 0x79, 0xcb, 0x61, 0x29, 0x00, 0x85, 0x34, 0xb3, 0x98, 0x50, 0x00, ++0x80, 0xe5, 0x22, 0x4c, 0x40, 0x39, 0x49, 0xe5, 0x22, 0x40, 0x40, 0x39, ++0x19, 0xcb, 0x61, 0x28, 0xc0, 0x85, 0x34, 0xb2, 0x90, 0x48, 0xcb, 0xa1, ++0x28, 0x80, 0x85, 0x34, 0xb1, 0xcb, 0xa1, 0x28, 0x40, 0x85, 0x34, 0xb0, ++0x92, 0x20, 0x91, 0x30, 0x90, 0xb8, 0xd5, 0x03, 0x00, 0xc0, 0xc0, 0x81, ++0x8c, 0x01, 0xa0, 0x84, 0x30, 0x3e, 0xc0, 0xc0, 0x81, 0x8c, 0x01, 0x80, ++0x84, 0x30, 0x3c, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81, 0x30, 0x28, 0xc0, ++0xc0, 0x81, 0x30, 0x24, 0x90, 0x78, 0xd5, 0x02, 0x00, 0xc0, 0xc0, 0x81, ++0x30, 0x1c, 0xc0, 0xc0, 0x81, 0x30, 0x18, 0xd5, 0x02, 0x00, 0xc0, 0xc0, ++0x81, 0x30, 0x10, 0xc0, 0xc0, 0x81, 0x30, 0x0c, 0x91, 0x70, 0x90, 0xd8, ++0xd5, 0x03, 0x80, 0xc8, 0xe2, 0x38, 0x40, 0x81, 0x8c, 0x01, 0xc0, 0x84, ++0x30, 0x40, 0xc8, 0xe2, 0x3a, 0x40, 0x81, 0x8c, 0x01, 0x90, 0x84, 0x30, ++0x3d, 0xd5, 0x02, 0x80, 0xc8, 0xe2, 0x37, 0x40, 0x81, 0x30, 0x2c, 0xc8, ++0xe2, 0x31, 0xc0, 0x81, 0x30, 0x26, 0x90, 0x98, 0xd5, 0x02, 0x80, 0xc8, ++0xe2, 0x26, 0xc0, 0x81, 0x30, 0x20, 0xc8, 0xe2, 0x28, 0xc0, 0x81, 0x30, ++0x1a, 0xd5, 0x02, 0x80, 0xc8, 0xe2, 0x25, 0xc0, 0x81, 0x30, 0x14, 0xc8, ++0xe2, 0x20, 0x40, 0x81, 0x30, 0x0e, 0x9a, 0x30, 0x04, 0x40, 0x91, 0x90, ++0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x7e, 0x40, 0x39, 0xf1, ++0xe5, 0x22, 0x80, 0x40, 0x3a, 0x15, 0xcb, 0x61, 0x27, 0xc0, 0x85, 0x34, ++0xae, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, 0x6e, 0x40, 0x39, 0xb1, 0xe5, ++0x22, 0x70, 0x40, 0x39, 0xd5, 0xcb, 0x61, 0x27, 0x80, 0x85, 0x34, 0xad, ++0x90, 0x48, 0xcb, 0xa1, 0x27, 0x40, 0x85, 0x34, 0xac, 0xcb, 0xa1, 0x27, ++0x00, 0x85, 0x34, 0xab, 0x91, 0x90, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, ++0xe5, 0x22, 0x60, 0x40, 0x39, 0x99, 0xe5, 0x22, 0x54, 0x40, 0x39, 0x69, ++0xcb, 0x61, 0x25, 0x40, 0x85, 0x34, 0x9a, 0x98, 0x50, 0x00, 0x80, 0xe5, ++0x22, 0x48, 0x40, 0x39, 0x39, 0xe5, 0x22, 0x3c, 0x40, 0x39, 0x09, 0xcb, ++0x61, 0x25, 0x00, 0x85, 0x34, 0x99, 0x90, 0x48, 0xcb, 0xa1, 0x24, 0xc0, ++0x85, 0x34, 0x98, 0xcb, 0xa1, 0x24, 0x80, 0x85, 0x34, 0x97, 0x91, 0x00, ++0x90, 0x80, 0x90, 0x40, 0xe5, 0x20, 0x02, 0x40, 0x30, 0x0a, 0xe5, 0x20, ++0x01, 0x80, 0x30, 0x07, 0x90, 0x40, 0xe5, 0x20, 0x00, 0xc0, 0x30, 0x04, ++0xe5, 0x20, 0x00, 0x00, 0x30, 0x01, 0x90, 0x80, 0x90, 0x40, 0xe5, 0x22, ++0x2d, 0x40, 0x38, 0xab, 0xe5, 0x22, 0x2f, 0x80, 0x38, 0xd3, 0x90, 0x40, ++0xe5, 0x22, 0x1b, 0xc0, 0x38, 0x65, 0xe5, 0x22, 0x1e, 0x00, 0x38, 0x8d, ++0x80, 0x99, 0x28, 0x02, 0xf0, 0x8c, 0x24, 0x48, 0x90, 0x80, 0x90, 0x40, ++0xe5, 0x22, 0x84, 0x40, 0x3a, 0x0d, 0xe5, 0x22, 0x81, 0x40, 0x3a, 0x19, ++0x90, 0x40, 0xe5, 0x22, 0x74, 0x40, 0x39, 0xcd, 0xe5, 0x22, 0x71, 0x40, ++0x39, 0xd9, 0x91, 0x48, 0x90, 0xc8, 0x98, 0x50, 0x00, 0x80, 0xe5, 0x22, ++0x62, 0x40, 0x39, 0xa1, 0xe5, 0x22, 0x56, 0x40, 0x39, 0x71, 0xcb, 0x61, ++0x23, 0x00, 0x85, 0x34, 0x90, 0x90, 0x40, 0xe5, 0x22, 0x4a, 0x40, 0x39, ++0x41, 0xe5, 0x22, 0x3e, 0x40, 0x39, 0x11, 0x90, 0x48, 0xcb, 0xa1, 0x22, ++0x80, 0x85, 0x34, 0x8e, 0xcb, 0xa1, 0x22, 0xc0, 0x85, 0x34, 0x8f, 0x10, ++0x10, 0x90, 0x80, 0x90, 0x40, 0xe5, 0x22, 0x33, 0xc0, 0x38, 0xcb, 0xe5, ++0x22, 0x30, 0xc0, 0x38, 0xd9, 0x90, 0x40, 0xe5, 0x22, 0x22, 0x40, 0x38, ++0x85, 0xe5, 0x22, 0x1f, 0x40, 0x38, 0x93, ++}; ++ ++static const struct ia64_dis_names ia64_dis_names[] = { ++{ 0x51, 41, 0, 10 }, ++{ 0x31, 41, 1, 20 }, ++{ 0x11, 42, 0, 19 }, ++{ 0x29, 41, 0, 12 }, ++{ 0x19, 41, 1, 24 }, ++{ 0x9, 42, 0, 23 }, ++{ 0x15, 41, 0, 14 }, ++{ 0xd, 41, 1, 28 }, ++{ 0x5, 42, 0, 27 }, ++{ 0xb, 41, 0, 16 }, ++{ 0x7, 41, 1, 32 }, ++{ 0x3, 42, 0, 31 }, ++{ 0x51, 39, 1, 58 }, ++{ 0x50, 39, 0, 34 }, ++{ 0xd1, 39, 1, 57 }, ++{ 0xd0, 39, 0, 33 }, ++{ 0x31, 39, 1, 68 }, ++{ 0x30, 39, 1, 44 }, ++{ 0x11, 40, 1, 67 }, ++{ 0x10, 40, 0, 43 }, ++{ 0x71, 39, 1, 66 }, ++{ 0x70, 39, 1, 42 }, ++{ 0x31, 40, 1, 65 }, ++{ 0x30, 40, 0, 41 }, ++{ 0x29, 39, 1, 60 }, ++{ 0x28, 39, 0, 36 }, ++{ 0x69, 39, 1, 59 }, ++{ 0x68, 39, 0, 35 }, ++{ 0x19, 39, 1, 72 }, ++{ 0x18, 39, 1, 48 }, ++{ 0x9, 40, 1, 71 }, ++{ 0x8, 40, 0, 47 }, ++{ 0x39, 39, 1, 70 }, ++{ 0x38, 39, 1, 46 }, ++{ 0x19, 40, 1, 69 }, ++{ 0x18, 40, 0, 45 }, ++{ 0x15, 39, 1, 62 }, ++{ 0x14, 39, 0, 38 }, ++{ 0x35, 39, 1, 61 }, ++{ 0x34, 39, 0, 37 }, ++{ 0xd, 39, 1, 76 }, ++{ 0xc, 39, 1, 52 }, ++{ 0x5, 40, 1, 75 }, ++{ 0x4, 40, 0, 51 }, ++{ 0x1d, 39, 1, 74 }, ++{ 0x1c, 39, 1, 50 }, ++{ 0xd, 40, 1, 73 }, ++{ 0xc, 40, 0, 49 }, ++{ 0xb, 39, 1, 64 }, ++{ 0xa, 39, 0, 40 }, ++{ 0x1b, 39, 1, 63 }, ++{ 0x1a, 39, 0, 39 }, ++{ 0x7, 39, 1, 80 }, ++{ 0x6, 39, 1, 56 }, ++{ 0x3, 40, 1, 79 }, ++{ 0x2, 40, 0, 55 }, ++{ 0xf, 39, 1, 78 }, ++{ 0xe, 39, 1, 54 }, ++{ 0x7, 40, 1, 77 }, ++{ 0x6, 40, 0, 53 }, ++{ 0x8, 38, 0, 82 }, ++{ 0x18, 38, 0, 81 }, ++{ 0x1, 38, 1, 86 }, ++{ 0x2, 38, 0, 85 }, ++{ 0x3, 38, 1, 84 }, ++{ 0x4, 38, 0, 83 }, ++{ 0x1, 336, 0, 87 }, ++{ 0x20, 289, 0, 98 }, ++{ 0x220, 289, 0, 94 }, ++{ 0x1220, 289, 0, 91 }, ++{ 0xa20, 289, 0, 92 }, ++{ 0x620, 289, 0, 93 }, ++{ 0x120, 289, 0, 95 }, ++{ 0xa0, 289, 0, 96 }, ++{ 0x60, 289, 0, 97 }, ++{ 0x10, 289, 0, 102 }, ++{ 0x90, 289, 0, 99 }, ++{ 0x50, 289, 0, 100 }, ++{ 0x30, 289, 0, 101 }, ++{ 0x8, 289, 0, 103 }, ++{ 0x4, 289, 0, 104 }, ++{ 0x2, 289, 0, 105 }, ++{ 0x1, 289, 0, 106 }, ++{ 0x1, 411, 0, 108 }, ++{ 0x3, 411, 0, 107 }, ++{ 0x2, 417, 0, 109 }, ++{ 0x1, 417, 0, 110 }, ++{ 0x2, 413, 0, 111 }, ++{ 0x1, 413, 0, 112 }, ++{ 0x2, 415, 0, 113 }, ++{ 0x1, 415, 0, 114 }, ++{ 0x2, 419, 0, 115 }, ++{ 0x1, 419, 0, 116 }, ++{ 0x1, 268, 0, 143 }, ++{ 0x5, 268, 0, 141 }, ++{ 0x3, 268, 0, 142 }, ++{ 0x140, 277, 0, 119 }, ++{ 0x540, 277, 0, 117 }, ++{ 0x340, 277, 0, 118 }, ++{ 0xc0, 277, 0, 131 }, ++{ 0x2c0, 277, 0, 129 }, ++{ 0x1c0, 277, 0, 130 }, ++{ 0x20, 277, 0, 146 }, ++{ 0xa0, 277, 0, 144 }, ++{ 0x60, 277, 0, 145 }, ++{ 0x10, 277, 0, 158 }, ++{ 0x50, 277, 0, 156 }, ++{ 0x30, 277, 0, 157 }, ++{ 0x8, 277, 0, 170 }, ++{ 0x28, 277, 0, 168 }, ++{ 0x18, 277, 0, 169 }, ++{ 0x4, 277, 0, 180 }, ++{ 0x2, 277, 0, 181 }, ++{ 0x1, 277, 0, 182 }, ++{ 0x140, 271, 0, 122 }, ++{ 0x540, 271, 0, 120 }, ++{ 0x340, 271, 0, 121 }, ++{ 0xc0, 271, 0, 134 }, ++{ 0x2c0, 271, 0, 132 }, ++{ 0x1c0, 271, 0, 133 }, ++{ 0x20, 271, 0, 149 }, ++{ 0xa0, 271, 0, 147 }, ++{ 0x60, 271, 0, 148 }, ++{ 0x10, 271, 0, 161 }, ++{ 0x50, 271, 0, 159 }, ++{ 0x30, 271, 0, 160 }, ++{ 0x8, 271, 0, 173 }, ++{ 0x28, 271, 0, 171 }, ++{ 0x18, 271, 0, 172 }, ++{ 0x4, 271, 0, 183 }, ++{ 0x2, 271, 0, 184 }, ++{ 0x1, 271, 0, 185 }, ++{ 0x140, 274, 0, 125 }, ++{ 0x540, 274, 0, 123 }, ++{ 0x340, 274, 0, 124 }, ++{ 0xc0, 274, 0, 137 }, ++{ 0x2c0, 274, 0, 135 }, ++{ 0x1c0, 274, 0, 136 }, ++{ 0x20, 274, 0, 152 }, ++{ 0xa0, 274, 0, 150 }, ++{ 0x60, 274, 0, 151 }, ++{ 0x10, 274, 0, 164 }, ++{ 0x50, 274, 0, 162 }, ++{ 0x30, 274, 0, 163 }, ++{ 0x8, 274, 0, 176 }, ++{ 0x28, 274, 0, 174 }, ++{ 0x18, 274, 0, 175 }, ++{ 0x4, 274, 0, 186 }, ++{ 0x2, 274, 0, 187 }, ++{ 0x1, 274, 0, 188 }, ++{ 0x140, 286, 0, 128 }, ++{ 0x540, 286, 0, 126 }, ++{ 0x340, 286, 0, 127 }, ++{ 0xc0, 286, 0, 140 }, ++{ 0x2c0, 286, 0, 138 }, ++{ 0x1c0, 286, 0, 139 }, ++{ 0x20, 286, 0, 155 }, ++{ 0xa0, 286, 0, 153 }, ++{ 0x60, 286, 0, 154 }, ++{ 0x10, 286, 0, 167 }, ++{ 0x50, 286, 0, 165 }, ++{ 0x30, 286, 0, 166 }, ++{ 0x8, 286, 0, 179 }, ++{ 0x28, 286, 0, 177 }, ++{ 0x18, 286, 0, 178 }, ++{ 0x4, 286, 0, 189 }, ++{ 0x2, 286, 0, 190 }, ++{ 0x1, 286, 0, 191 }, ++{ 0x8, 390, 0, 192 }, ++{ 0x4, 390, 0, 193 }, ++{ 0x2, 390, 0, 194 }, ++{ 0x1, 390, 0, 195 }, ++{ 0x20, 288, 0, 203 }, ++{ 0x220, 288, 0, 199 }, ++{ 0x1220, 288, 0, 196 }, ++{ 0xa20, 288, 0, 197 }, ++{ 0x620, 288, 0, 198 }, ++{ 0x120, 288, 0, 200 }, ++{ 0xa0, 288, 0, 201 }, ++{ 0x60, 288, 0, 202 }, ++{ 0x10, 288, 0, 207 }, ++{ 0x90, 288, 0, 204 }, ++{ 0x50, 288, 0, 205 }, ++{ 0x30, 288, 0, 206 }, ++{ 0x8, 288, 0, 208 }, ++{ 0x4, 288, 0, 209 }, ++{ 0x2, 288, 0, 210 }, ++{ 0x1, 288, 0, 211 }, ++{ 0x20, 287, 0, 219 }, ++{ 0x220, 287, 0, 215 }, ++{ 0x1220, 287, 0, 212 }, ++{ 0xa20, 287, 0, 213 }, ++{ 0x620, 287, 0, 214 }, ++{ 0x120, 287, 0, 216 }, ++{ 0xa0, 287, 0, 217 }, ++{ 0x60, 287, 0, 218 }, ++{ 0x10, 287, 0, 223 }, ++{ 0x90, 287, 0, 220 }, ++{ 0x50, 287, 0, 221 }, ++{ 0x30, 287, 0, 222 }, ++{ 0x8, 287, 0, 224 }, ++{ 0x4, 287, 0, 225 }, ++{ 0x2, 287, 0, 226 }, ++{ 0x1, 287, 0, 227 }, ++{ 0x140, 279, 0, 230 }, ++{ 0x540, 279, 0, 228 }, ++{ 0x340, 279, 0, 229 }, ++{ 0xc0, 279, 0, 239 }, ++{ 0x2c0, 279, 0, 237 }, ++{ 0x1c0, 279, 0, 238 }, ++{ 0x20, 279, 0, 248 }, ++{ 0xa0, 279, 0, 246 }, ++{ 0x60, 279, 0, 247 }, ++{ 0x10, 279, 0, 257 }, ++{ 0x50, 279, 0, 255 }, ++{ 0x30, 279, 0, 256 }, ++{ 0x8, 279, 0, 266 }, ++{ 0x28, 279, 0, 264 }, ++{ 0x18, 279, 0, 265 }, ++{ 0x4, 279, 0, 273 }, ++{ 0x2, 279, 0, 274 }, ++{ 0x1, 279, 0, 275 }, ++{ 0x140, 281, 0, 233 }, ++{ 0x540, 281, 0, 231 }, ++{ 0x340, 281, 0, 232 }, ++{ 0xc0, 281, 0, 242 }, ++{ 0x2c0, 281, 0, 240 }, ++{ 0x1c0, 281, 0, 241 }, ++{ 0x20, 281, 0, 251 }, ++{ 0xa0, 281, 0, 249 }, ++{ 0x60, 281, 0, 250 }, ++{ 0x10, 281, 0, 260 }, ++{ 0x50, 281, 0, 258 }, ++{ 0x30, 281, 0, 259 }, ++{ 0x8, 281, 0, 269 }, ++{ 0x28, 281, 0, 267 }, ++{ 0x18, 281, 0, 268 }, ++{ 0x4, 281, 0, 276 }, ++{ 0x2, 281, 0, 277 }, ++{ 0x1, 281, 0, 278 }, ++{ 0x140, 283, 0, 236 }, ++{ 0x540, 283, 0, 234 }, ++{ 0x340, 283, 0, 235 }, ++{ 0xc0, 283, 0, 245 }, ++{ 0x2c0, 283, 0, 243 }, ++{ 0x1c0, 283, 0, 244 }, ++{ 0x20, 283, 0, 254 }, ++{ 0xa0, 283, 0, 252 }, ++{ 0x60, 283, 0, 253 }, ++{ 0x10, 283, 0, 263 }, ++{ 0x50, 283, 0, 261 }, ++{ 0x30, 283, 0, 262 }, ++{ 0x8, 283, 0, 272 }, ++{ 0x28, 283, 0, 270 }, ++{ 0x18, 283, 0, 271 }, ++{ 0x4, 283, 0, 279 }, ++{ 0x2, 283, 0, 280 }, ++{ 0x1, 283, 0, 281 }, ++{ 0x140, 278, 0, 284 }, ++{ 0x540, 278, 0, 282 }, ++{ 0x340, 278, 0, 283 }, ++{ 0xc0, 278, 0, 293 }, ++{ 0x2c0, 278, 0, 291 }, ++{ 0x1c0, 278, 0, 292 }, ++{ 0x20, 278, 0, 302 }, ++{ 0xa0, 278, 0, 300 }, ++{ 0x60, 278, 0, 301 }, ++{ 0x10, 278, 0, 311 }, ++{ 0x50, 278, 0, 309 }, ++{ 0x30, 278, 0, 310 }, ++{ 0x8, 278, 0, 320 }, ++{ 0x28, 278, 0, 318 }, ++{ 0x18, 278, 0, 319 }, ++{ 0x4, 278, 0, 327 }, ++{ 0x2, 278, 0, 328 }, ++{ 0x1, 278, 0, 329 }, ++{ 0x140, 280, 0, 287 }, ++{ 0x540, 280, 0, 285 }, ++{ 0x340, 280, 0, 286 }, ++{ 0xc0, 280, 0, 296 }, ++{ 0x2c0, 280, 0, 294 }, ++{ 0x1c0, 280, 0, 295 }, ++{ 0x20, 280, 0, 305 }, ++{ 0xa0, 280, 0, 303 }, ++{ 0x60, 280, 0, 304 }, ++{ 0x10, 280, 0, 314 }, ++{ 0x50, 280, 0, 312 }, ++{ 0x30, 280, 0, 313 }, ++{ 0x8, 280, 0, 323 }, ++{ 0x28, 280, 0, 321 }, ++{ 0x18, 280, 0, 322 }, ++{ 0x4, 280, 0, 330 }, ++{ 0x2, 280, 0, 331 }, ++{ 0x1, 280, 0, 332 }, ++{ 0x140, 282, 0, 290 }, ++{ 0x540, 282, 0, 288 }, ++{ 0x340, 282, 0, 289 }, ++{ 0xc0, 282, 0, 299 }, ++{ 0x2c0, 282, 0, 297 }, ++{ 0x1c0, 282, 0, 298 }, ++{ 0x20, 282, 0, 308 }, ++{ 0xa0, 282, 0, 306 }, ++{ 0x60, 282, 0, 307 }, ++{ 0x10, 282, 0, 317 }, ++{ 0x50, 282, 0, 315 }, ++{ 0x30, 282, 0, 316 }, ++{ 0x8, 282, 0, 326 }, ++{ 0x28, 282, 0, 324 }, ++{ 0x18, 282, 0, 325 }, ++{ 0x4, 282, 0, 333 }, ++{ 0x2, 282, 0, 334 }, ++{ 0x1, 282, 0, 335 }, ++{ 0x1, 410, 0, 337 }, ++{ 0x3, 410, 0, 336 }, ++{ 0x2, 416, 0, 338 }, ++{ 0x1, 416, 0, 339 }, ++{ 0x2, 412, 0, 340 }, ++{ 0x1, 412, 0, 341 }, ++{ 0x2, 414, 0, 342 }, ++{ 0x1, 414, 0, 343 }, ++{ 0x2, 418, 0, 344 }, ++{ 0x1, 418, 0, 345 }, ++{ 0x1, 267, 0, 372 }, ++{ 0x5, 267, 0, 370 }, ++{ 0x3, 267, 0, 371 }, ++{ 0x140, 276, 0, 348 }, ++{ 0x540, 276, 0, 346 }, ++{ 0x340, 276, 0, 347 }, ++{ 0xc0, 276, 0, 360 }, ++{ 0x2c0, 276, 0, 358 }, ++{ 0x1c0, 276, 0, 359 }, ++{ 0x20, 276, 0, 375 }, ++{ 0xa0, 276, 0, 373 }, ++{ 0x60, 276, 0, 374 }, ++{ 0x10, 276, 0, 387 }, ++{ 0x50, 276, 0, 385 }, ++{ 0x30, 276, 0, 386 }, ++{ 0x8, 276, 0, 399 }, ++{ 0x28, 276, 0, 397 }, ++{ 0x18, 276, 0, 398 }, ++{ 0x4, 276, 0, 409 }, ++{ 0x2, 276, 0, 410 }, ++{ 0x1, 276, 0, 411 }, ++{ 0x140, 270, 0, 351 }, ++{ 0x540, 270, 0, 349 }, ++{ 0x340, 270, 0, 350 }, ++{ 0xc0, 270, 0, 363 }, ++{ 0x2c0, 270, 0, 361 }, ++{ 0x1c0, 270, 0, 362 }, ++{ 0x20, 270, 0, 378 }, ++{ 0xa0, 270, 0, 376 }, ++{ 0x60, 270, 0, 377 }, ++{ 0x10, 270, 0, 390 }, ++{ 0x50, 270, 0, 388 }, ++{ 0x30, 270, 0, 389 }, ++{ 0x8, 270, 0, 402 }, ++{ 0x28, 270, 0, 400 }, ++{ 0x18, 270, 0, 401 }, ++{ 0x4, 270, 0, 412 }, ++{ 0x2, 270, 0, 413 }, ++{ 0x1, 270, 0, 414 }, ++{ 0x140, 273, 0, 354 }, ++{ 0x540, 273, 0, 352 }, ++{ 0x340, 273, 0, 353 }, ++{ 0xc0, 273, 0, 366 }, ++{ 0x2c0, 273, 0, 364 }, ++{ 0x1c0, 273, 0, 365 }, ++{ 0x20, 273, 0, 381 }, ++{ 0xa0, 273, 0, 379 }, ++{ 0x60, 273, 0, 380 }, ++{ 0x10, 273, 0, 393 }, ++{ 0x50, 273, 0, 391 }, ++{ 0x30, 273, 0, 392 }, ++{ 0x8, 273, 0, 405 }, ++{ 0x28, 273, 0, 403 }, ++{ 0x18, 273, 0, 404 }, ++{ 0x4, 273, 0, 415 }, ++{ 0x2, 273, 0, 416 }, ++{ 0x1, 273, 0, 417 }, ++{ 0x140, 285, 0, 357 }, ++{ 0x540, 285, 0, 355 }, ++{ 0x340, 285, 0, 356 }, ++{ 0xc0, 285, 0, 369 }, ++{ 0x2c0, 285, 0, 367 }, ++{ 0x1c0, 285, 0, 368 }, ++{ 0x20, 285, 0, 384 }, ++{ 0xa0, 285, 0, 382 }, ++{ 0x60, 285, 0, 383 }, ++{ 0x10, 285, 0, 396 }, ++{ 0x50, 285, 0, 394 }, ++{ 0x30, 285, 0, 395 }, ++{ 0x8, 285, 0, 408 }, ++{ 0x28, 285, 0, 406 }, ++{ 0x18, 285, 0, 407 }, ++{ 0x4, 285, 0, 418 }, ++{ 0x2, 285, 0, 419 }, ++{ 0x1, 285, 0, 420 }, ++{ 0x1, 266, 0, 447 }, ++{ 0x5, 266, 0, 445 }, ++{ 0x3, 266, 0, 446 }, ++{ 0x140, 275, 0, 423 }, ++{ 0x540, 275, 0, 421 }, ++{ 0x340, 275, 0, 422 }, ++{ 0xc0, 275, 0, 435 }, ++{ 0x2c0, 275, 0, 433 }, ++{ 0x1c0, 275, 0, 434 }, ++{ 0x20, 275, 0, 450 }, ++{ 0xa0, 275, 0, 448 }, ++{ 0x60, 275, 0, 449 }, ++{ 0x10, 275, 0, 462 }, ++{ 0x50, 275, 0, 460 }, ++{ 0x30, 275, 0, 461 }, ++{ 0x8, 275, 0, 474 }, ++{ 0x28, 275, 0, 472 }, ++{ 0x18, 275, 0, 473 }, ++{ 0x4, 275, 0, 484 }, ++{ 0x2, 275, 0, 485 }, ++{ 0x1, 275, 0, 486 }, ++{ 0x140, 269, 0, 426 }, ++{ 0x540, 269, 0, 424 }, ++{ 0x340, 269, 0, 425 }, ++{ 0xc0, 269, 0, 438 }, ++{ 0x2c0, 269, 0, 436 }, ++{ 0x1c0, 269, 0, 437 }, ++{ 0x20, 269, 0, 453 }, ++{ 0xa0, 269, 0, 451 }, ++{ 0x60, 269, 0, 452 }, ++{ 0x10, 269, 0, 465 }, ++{ 0x50, 269, 0, 463 }, ++{ 0x30, 269, 0, 464 }, ++{ 0x8, 269, 0, 477 }, ++{ 0x28, 269, 0, 475 }, ++{ 0x18, 269, 0, 476 }, ++{ 0x4, 269, 0, 487 }, ++{ 0x2, 269, 0, 488 }, ++{ 0x1, 269, 0, 489 }, ++{ 0x140, 272, 0, 429 }, ++{ 0x540, 272, 0, 427 }, ++{ 0x340, 272, 0, 428 }, ++{ 0xc0, 272, 0, 441 }, ++{ 0x2c0, 272, 0, 439 }, ++{ 0x1c0, 272, 0, 440 }, ++{ 0x20, 272, 0, 456 }, ++{ 0xa0, 272, 0, 454 }, ++{ 0x60, 272, 0, 455 }, ++{ 0x10, 272, 0, 468 }, ++{ 0x50, 272, 0, 466 }, ++{ 0x30, 272, 0, 467 }, ++{ 0x8, 272, 0, 480 }, ++{ 0x28, 272, 0, 478 }, ++{ 0x18, 272, 0, 479 }, ++{ 0x4, 272, 0, 490 }, ++{ 0x2, 272, 0, 491 }, ++{ 0x1, 272, 0, 492 }, ++{ 0x140, 284, 0, 432 }, ++{ 0x540, 284, 0, 430 }, ++{ 0x340, 284, 0, 431 }, ++{ 0xc0, 284, 0, 444 }, ++{ 0x2c0, 284, 0, 442 }, ++{ 0x1c0, 284, 0, 443 }, ++{ 0x20, 284, 0, 459 }, ++{ 0xa0, 284, 0, 457 }, ++{ 0x60, 284, 0, 458 }, ++{ 0x10, 284, 0, 471 }, ++{ 0x50, 284, 0, 469 }, ++{ 0x30, 284, 0, 470 }, ++{ 0x8, 284, 0, 483 }, ++{ 0x28, 284, 0, 481 }, ++{ 0x18, 284, 0, 482 }, ++{ 0x4, 284, 0, 493 }, ++{ 0x2, 284, 0, 494 }, ++{ 0x1, 284, 0, 495 }, ++{ 0x8, 409, 0, 497 }, ++{ 0x18, 409, 0, 496 }, ++{ 0x4, 409, 0, 499 }, ++{ 0xc, 409, 0, 498 }, ++{ 0x2, 409, 0, 506 }, ++{ 0x1, 409, 0, 507 }, ++{ 0x4, 407, 0, 501 }, ++{ 0xc, 407, 0, 500 }, ++{ 0x2, 407, 0, 508 }, ++{ 0x1, 407, 0, 509 }, ++{ 0x4, 405, 0, 503 }, ++{ 0xc, 405, 0, 502 }, ++{ 0x2, 405, 0, 510 }, ++{ 0x1, 405, 0, 511 }, ++{ 0x4, 401, 0, 505 }, ++{ 0xc, 401, 0, 504 }, ++{ 0x2, 401, 0, 512 }, ++{ 0x1, 401, 0, 513 }, ++{ 0xa00, 265, 0, 528 }, ++{ 0x2a00, 265, 0, 526 }, ++{ 0x1a00, 265, 0, 527 }, ++{ 0x600, 265, 0, 540 }, ++{ 0x2600, 265, 0, 516 }, ++{ 0xa600, 265, 0, 514 }, ++{ 0x6600, 265, 0, 515 }, ++{ 0x1600, 265, 0, 538 }, ++{ 0xe00, 265, 0, 539 }, ++{ 0x100, 265, 0, 552 }, ++{ 0x500, 265, 0, 550 }, ++{ 0x300, 265, 0, 551 }, ++{ 0x80, 265, 0, 555 }, ++{ 0x280, 265, 0, 553 }, ++{ 0x180, 265, 0, 554 }, ++{ 0x40, 265, 0, 567 }, ++{ 0x140, 265, 0, 565 }, ++{ 0xc0, 265, 0, 566 }, ++{ 0x20, 265, 0, 579 }, ++{ 0xa0, 265, 0, 577 }, ++{ 0x60, 265, 0, 578 }, ++{ 0x10, 265, 0, 591 }, ++{ 0x50, 265, 0, 589 }, ++{ 0x30, 265, 0, 590 }, ++{ 0x8, 265, 0, 603 }, ++{ 0x28, 265, 0, 601 }, ++{ 0x18, 265, 0, 602 }, ++{ 0x4, 265, 0, 613 }, ++{ 0x2, 265, 0, 614 }, ++{ 0x1, 265, 0, 615 }, ++{ 0x500, 261, 0, 531 }, ++{ 0x1500, 261, 0, 529 }, ++{ 0xd00, 261, 0, 530 }, ++{ 0x300, 261, 0, 543 }, ++{ 0x1300, 261, 0, 519 }, ++{ 0x5300, 261, 0, 517 }, ++{ 0x3300, 261, 0, 518 }, ++{ 0xb00, 261, 0, 541 }, ++{ 0x700, 261, 0, 542 }, ++{ 0x80, 261, 0, 558 }, ++{ 0x280, 261, 0, 556 }, ++{ 0x180, 261, 0, 557 }, ++{ 0x40, 261, 0, 570 }, ++{ 0x140, 261, 0, 568 }, ++{ 0xc0, 261, 0, 569 }, ++{ 0x20, 261, 0, 582 }, ++{ 0xa0, 261, 0, 580 }, ++{ 0x60, 261, 0, 581 }, ++{ 0x10, 261, 0, 594 }, ++{ 0x50, 261, 0, 592 }, ++{ 0x30, 261, 0, 593 }, ++{ 0x8, 261, 0, 606 }, ++{ 0x28, 261, 0, 604 }, ++{ 0x18, 261, 0, 605 }, ++{ 0x4, 261, 0, 616 }, ++{ 0x2, 261, 0, 617 }, ++{ 0x1, 261, 0, 618 }, ++{ 0x500, 258, 0, 534 }, ++{ 0x1500, 258, 0, 532 }, ++{ 0xd00, 258, 0, 533 }, ++{ 0x300, 258, 0, 546 }, ++{ 0x1300, 258, 0, 522 }, ++{ 0x5300, 258, 0, 520 }, ++{ 0x3300, 258, 0, 521 }, ++{ 0xb00, 258, 0, 544 }, ++{ 0x700, 258, 0, 545 }, ++{ 0x80, 258, 0, 561 }, ++{ 0x280, 258, 0, 559 }, ++{ 0x180, 258, 0, 560 }, ++{ 0x40, 258, 0, 573 }, ++{ 0x140, 258, 0, 571 }, ++{ 0xc0, 258, 0, 572 }, ++{ 0x20, 258, 0, 585 }, ++{ 0xa0, 258, 0, 583 }, ++{ 0x60, 258, 0, 584 }, ++{ 0x10, 258, 0, 597 }, ++{ 0x50, 258, 0, 595 }, ++{ 0x30, 258, 0, 596 }, ++{ 0x8, 258, 0, 609 }, ++{ 0x28, 258, 0, 607 }, ++{ 0x18, 258, 0, 608 }, ++{ 0x4, 258, 0, 619 }, ++{ 0x2, 258, 0, 620 }, ++{ 0x1, 258, 0, 621 }, ++{ 0x500, 253, 0, 537 }, ++{ 0x1500, 253, 0, 535 }, ++{ 0xd00, 253, 0, 536 }, ++{ 0x300, 253, 0, 549 }, ++{ 0x1300, 253, 0, 525 }, ++{ 0x5300, 253, 0, 523 }, ++{ 0x3300, 253, 0, 524 }, ++{ 0xb00, 253, 0, 547 }, ++{ 0x700, 253, 0, 548 }, ++{ 0x80, 253, 0, 564 }, ++{ 0x280, 253, 0, 562 }, ++{ 0x180, 253, 0, 563 }, ++{ 0x40, 253, 0, 576 }, ++{ 0x140, 253, 0, 574 }, ++{ 0xc0, 253, 0, 575 }, ++{ 0x20, 253, 0, 588 }, ++{ 0xa0, 253, 0, 586 }, ++{ 0x60, 253, 0, 587 }, ++{ 0x10, 253, 0, 600 }, ++{ 0x50, 253, 0, 598 }, ++{ 0x30, 253, 0, 599 }, ++{ 0x8, 253, 0, 612 }, ++{ 0x28, 253, 0, 610 }, ++{ 0x18, 253, 0, 611 }, ++{ 0x4, 253, 0, 622 }, ++{ 0x2, 253, 0, 623 }, ++{ 0x1, 253, 0, 624 }, ++{ 0x8, 238, 0, 625 }, ++{ 0x4, 238, 0, 626 }, ++{ 0x2, 238, 0, 627 }, ++{ 0x1, 238, 0, 628 }, ++{ 0x2, 176, 0, 631 }, ++{ 0xa, 176, 0, 629 }, ++{ 0x6, 176, 0, 630 }, ++{ 0x1, 176, 0, 637 }, ++{ 0x5, 176, 0, 635 }, ++{ 0x3, 176, 0, 636 }, ++{ 0x2, 175, 0, 634 }, ++{ 0xa, 175, 0, 632 }, ++{ 0x6, 175, 0, 633 }, ++{ 0x1, 175, 0, 640 }, ++{ 0x5, 175, 0, 638 }, ++{ 0x3, 175, 0, 639 }, ++{ 0x4, 446, 0, 641 }, ++{ 0x2, 446, 0, 642 }, ++{ 0x1, 446, 0, 643 }, ++{ 0x4, 445, 0, 644 }, ++{ 0x2, 445, 0, 645 }, ++{ 0x1, 445, 0, 646 }, ++{ 0x4, 444, 0, 647 }, ++{ 0x2, 444, 0, 648 }, ++{ 0x1, 444, 0, 649 }, ++{ 0x4, 443, 0, 650 }, ++{ 0x2, 443, 0, 651 }, ++{ 0x1, 443, 0, 652 }, ++{ 0x2, 123, 1, 658 }, ++{ 0x2, 124, 0, 657 }, ++{ 0xa, 123, 1, 654 }, ++{ 0xa, 124, 0, 653 }, ++{ 0x6, 123, 1, 656 }, ++{ 0x6, 124, 0, 655 }, ++{ 0x1, 123, 1, 688 }, ++{ 0x1, 124, 0, 687 }, ++{ 0x5, 123, 1, 684 }, ++{ 0x5, 124, 0, 683 }, ++{ 0x3, 123, 1, 686 }, ++{ 0x3, 124, 0, 685 }, ++{ 0x2, 131, 1, 664 }, ++{ 0x2, 132, 0, 663 }, ++{ 0xa, 131, 1, 660 }, ++{ 0xa, 132, 0, 659 }, ++{ 0x6, 131, 1, 662 }, ++{ 0x6, 132, 0, 661 }, ++{ 0x1, 131, 1, 694 }, ++{ 0x1, 132, 0, 693 }, ++{ 0x5, 131, 1, 690 }, ++{ 0x5, 132, 0, 689 }, ++{ 0x3, 131, 1, 692 }, ++{ 0x3, 132, 0, 691 }, ++{ 0x2, 129, 1, 670 }, ++{ 0x2, 130, 0, 669 }, ++{ 0xa, 129, 1, 666 }, ++{ 0xa, 130, 0, 665 }, ++{ 0x6, 129, 1, 668 }, ++{ 0x6, 130, 0, 667 }, ++{ 0x1, 129, 1, 700 }, ++{ 0x1, 130, 0, 699 }, ++{ 0x5, 129, 1, 696 }, ++{ 0x5, 130, 0, 695 }, ++{ 0x3, 129, 1, 698 }, ++{ 0x3, 130, 0, 697 }, ++{ 0x2, 127, 1, 676 }, ++{ 0x2, 128, 0, 675 }, ++{ 0xa, 127, 1, 672 }, ++{ 0xa, 128, 0, 671 }, ++{ 0x6, 127, 1, 674 }, ++{ 0x6, 128, 0, 673 }, ++{ 0x1, 127, 1, 706 }, ++{ 0x1, 128, 0, 705 }, ++{ 0x5, 127, 1, 702 }, ++{ 0x5, 128, 0, 701 }, ++{ 0x3, 127, 1, 704 }, ++{ 0x3, 128, 0, 703 }, ++{ 0x2, 125, 1, 682 }, ++{ 0x2, 126, 0, 681 }, ++{ 0xa, 125, 1, 678 }, ++{ 0xa, 126, 0, 677 }, ++{ 0x6, 125, 1, 680 }, ++{ 0x6, 126, 0, 679 }, ++{ 0x1, 125, 1, 712 }, ++{ 0x1, 126, 0, 711 }, ++{ 0x5, 125, 1, 708 }, ++{ 0x5, 126, 0, 707 }, ++{ 0x3, 125, 1, 710 }, ++{ 0x3, 126, 0, 709 }, ++{ 0x4, 402, 1, 718 }, ++{ 0x4, 403, 0, 717 }, ++{ 0xc, 402, 1, 716 }, ++{ 0xc, 403, 0, 715 }, ++{ 0x2, 402, 1, 728 }, ++{ 0x2, 403, 0, 727 }, ++{ 0x1, 402, 1, 730 }, ++{ 0x1, 403, 0, 729 }, ++{ 0x8, 408, 0, 714 }, ++{ 0x18, 408, 0, 713 }, ++{ 0x4, 408, 0, 720 }, ++{ 0xc, 408, 0, 719 }, ++{ 0x2, 408, 0, 731 }, ++{ 0x1, 408, 0, 732 }, ++{ 0x4, 406, 0, 722 }, ++{ 0xc, 406, 0, 721 }, ++{ 0x2, 406, 0, 733 }, ++{ 0x1, 406, 0, 734 }, ++{ 0x4, 404, 0, 724 }, ++{ 0xc, 404, 0, 723 }, ++{ 0x2, 404, 0, 735 }, ++{ 0x1, 404, 0, 736 }, ++{ 0x4, 400, 0, 726 }, ++{ 0xc, 400, 0, 725 }, ++{ 0x2, 400, 0, 737 }, ++{ 0x1, 400, 0, 738 }, ++{ 0xa00, 264, 0, 753 }, ++{ 0x2a00, 264, 0, 751 }, ++{ 0x1a00, 264, 0, 752 }, ++{ 0x600, 264, 0, 765 }, ++{ 0x2600, 264, 0, 741 }, ++{ 0xa600, 264, 0, 739 }, ++{ 0x6600, 264, 0, 740 }, ++{ 0x1600, 264, 0, 763 }, ++{ 0xe00, 264, 0, 764 }, ++{ 0x100, 264, 0, 777 }, ++{ 0x500, 264, 0, 775 }, ++{ 0x300, 264, 0, 776 }, ++{ 0x80, 264, 0, 780 }, ++{ 0x280, 264, 0, 778 }, ++{ 0x180, 264, 0, 779 }, ++{ 0x40, 264, 0, 792 }, ++{ 0x140, 264, 0, 790 }, ++{ 0xc0, 264, 0, 791 }, ++{ 0x20, 264, 0, 804 }, ++{ 0xa0, 264, 0, 802 }, ++{ 0x60, 264, 0, 803 }, ++{ 0x10, 264, 0, 816 }, ++{ 0x50, 264, 0, 814 }, ++{ 0x30, 264, 0, 815 }, ++{ 0x8, 264, 0, 828 }, ++{ 0x28, 264, 0, 826 }, ++{ 0x18, 264, 0, 827 }, ++{ 0x4, 264, 0, 838 }, ++{ 0x2, 264, 0, 839 }, ++{ 0x1, 264, 0, 840 }, ++{ 0x500, 260, 0, 756 }, ++{ 0x1500, 260, 0, 754 }, ++{ 0xd00, 260, 0, 755 }, ++{ 0x300, 260, 0, 768 }, ++{ 0x1300, 260, 0, 744 }, ++{ 0x5300, 260, 0, 742 }, ++{ 0x3300, 260, 0, 743 }, ++{ 0xb00, 260, 0, 766 }, ++{ 0x700, 260, 0, 767 }, ++{ 0x80, 260, 0, 783 }, ++{ 0x280, 260, 0, 781 }, ++{ 0x180, 260, 0, 782 }, ++{ 0x40, 260, 0, 795 }, ++{ 0x140, 260, 0, 793 }, ++{ 0xc0, 260, 0, 794 }, ++{ 0x20, 260, 0, 807 }, ++{ 0xa0, 260, 0, 805 }, ++{ 0x60, 260, 0, 806 }, ++{ 0x10, 260, 0, 819 }, ++{ 0x50, 260, 0, 817 }, ++{ 0x30, 260, 0, 818 }, ++{ 0x8, 260, 0, 831 }, ++{ 0x28, 260, 0, 829 }, ++{ 0x18, 260, 0, 830 }, ++{ 0x4, 260, 0, 841 }, ++{ 0x2, 260, 0, 842 }, ++{ 0x1, 260, 0, 843 }, ++{ 0x500, 257, 0, 759 }, ++{ 0x1500, 257, 0, 757 }, ++{ 0xd00, 257, 0, 758 }, ++{ 0x300, 257, 0, 771 }, ++{ 0x1300, 257, 0, 747 }, ++{ 0x5300, 257, 0, 745 }, ++{ 0x3300, 257, 0, 746 }, ++{ 0xb00, 257, 0, 769 }, ++{ 0x700, 257, 0, 770 }, ++{ 0x80, 257, 0, 786 }, ++{ 0x280, 257, 0, 784 }, ++{ 0x180, 257, 0, 785 }, ++{ 0x40, 257, 0, 798 }, ++{ 0x140, 257, 0, 796 }, ++{ 0xc0, 257, 0, 797 }, ++{ 0x20, 257, 0, 810 }, ++{ 0xa0, 257, 0, 808 }, ++{ 0x60, 257, 0, 809 }, ++{ 0x10, 257, 0, 822 }, ++{ 0x50, 257, 0, 820 }, ++{ 0x30, 257, 0, 821 }, ++{ 0x8, 257, 0, 834 }, ++{ 0x28, 257, 0, 832 }, ++{ 0x18, 257, 0, 833 }, ++{ 0x4, 257, 0, 844 }, ++{ 0x2, 257, 0, 845 }, ++{ 0x1, 257, 0, 846 }, ++{ 0x500, 252, 0, 762 }, ++{ 0x1500, 252, 0, 760 }, ++{ 0xd00, 252, 0, 761 }, ++{ 0x300, 252, 0, 774 }, ++{ 0x1300, 252, 0, 750 }, ++{ 0x5300, 252, 0, 748 }, ++{ 0x3300, 252, 0, 749 }, ++{ 0xb00, 252, 0, 772 }, ++{ 0x700, 252, 0, 773 }, ++{ 0x80, 252, 0, 789 }, ++{ 0x280, 252, 0, 787 }, ++{ 0x180, 252, 0, 788 }, ++{ 0x40, 252, 0, 801 }, ++{ 0x140, 252, 0, 799 }, ++{ 0xc0, 252, 0, 800 }, ++{ 0x20, 252, 0, 813 }, ++{ 0xa0, 252, 0, 811 }, ++{ 0x60, 252, 0, 812 }, ++{ 0x10, 252, 0, 825 }, ++{ 0x50, 252, 0, 823 }, ++{ 0x30, 252, 0, 824 }, ++{ 0x8, 252, 0, 837 }, ++{ 0x28, 252, 0, 835 }, ++{ 0x18, 252, 0, 836 }, ++{ 0x4, 252, 0, 847 }, ++{ 0x2, 252, 0, 848 }, ++{ 0x1, 252, 0, 849 }, ++{ 0x8, 254, 1, 895 }, ++{ 0x8, 255, 0, 894 }, ++{ 0x28, 254, 1, 891 }, ++{ 0x28, 255, 0, 890 }, ++{ 0x18, 254, 1, 893 }, ++{ 0x18, 255, 0, 892 }, ++{ 0x4, 254, 1, 957 }, ++{ 0x4, 255, 0, 956 }, ++{ 0x2, 254, 1, 959 }, ++{ 0x2, 255, 0, 958 }, ++{ 0x1, 254, 1, 961 }, ++{ 0x1, 255, 0, 960 }, ++{ 0xa00, 262, 0, 865 }, ++{ 0x2a00, 262, 0, 863 }, ++{ 0x1a00, 262, 0, 864 }, ++{ 0x600, 262, 0, 877 }, ++{ 0x2600, 262, 0, 853 }, ++{ 0xa600, 262, 0, 851 }, ++{ 0x6600, 262, 0, 852 }, ++{ 0x1600, 262, 0, 875 }, ++{ 0xe00, 262, 0, 876 }, ++{ 0x100, 262, 0, 889 }, ++{ 0x500, 262, 0, 887 }, ++{ 0x300, 262, 0, 888 }, ++{ 0x80, 262, 0, 898 }, ++{ 0x280, 262, 0, 896 }, ++{ 0x180, 262, 0, 897 }, ++{ 0x40, 262, 0, 910 }, ++{ 0x140, 262, 0, 908 }, ++{ 0xc0, 262, 0, 909 }, ++{ 0x20, 262, 0, 922 }, ++{ 0xa0, 262, 0, 920 }, ++{ 0x60, 262, 0, 921 }, ++{ 0x10, 262, 0, 934 }, ++{ 0x50, 262, 0, 932 }, ++{ 0x30, 262, 0, 933 }, ++{ 0x8, 262, 0, 946 }, ++{ 0x28, 262, 0, 944 }, ++{ 0x18, 262, 0, 945 }, ++{ 0x4, 262, 0, 962 }, ++{ 0x2, 262, 0, 963 }, ++{ 0x1, 262, 1, 964 }, ++{ 0x1, 263, 0, 850 }, ++{ 0x500, 259, 0, 868 }, ++{ 0x1500, 259, 0, 866 }, ++{ 0xd00, 259, 0, 867 }, ++{ 0x300, 259, 0, 880 }, ++{ 0x1300, 259, 0, 856 }, ++{ 0x5300, 259, 0, 854 }, ++{ 0x3300, 259, 0, 855 }, ++{ 0xb00, 259, 0, 878 }, ++{ 0x700, 259, 0, 879 }, ++{ 0x80, 259, 0, 901 }, ++{ 0x280, 259, 0, 899 }, ++{ 0x180, 259, 0, 900 }, ++{ 0x40, 259, 0, 913 }, ++{ 0x140, 259, 0, 911 }, ++{ 0xc0, 259, 0, 912 }, ++{ 0x20, 259, 0, 925 }, ++{ 0xa0, 259, 0, 923 }, ++{ 0x60, 259, 0, 924 }, ++{ 0x10, 259, 0, 937 }, ++{ 0x50, 259, 0, 935 }, ++{ 0x30, 259, 0, 936 }, ++{ 0x8, 259, 0, 949 }, ++{ 0x28, 259, 0, 947 }, ++{ 0x18, 259, 0, 948 }, ++{ 0x4, 259, 0, 965 }, ++{ 0x2, 259, 0, 966 }, ++{ 0x1, 259, 0, 967 }, ++{ 0x500, 256, 0, 871 }, ++{ 0x1500, 256, 0, 869 }, ++{ 0xd00, 256, 0, 870 }, ++{ 0x300, 256, 0, 883 }, ++{ 0x1300, 256, 0, 859 }, ++{ 0x5300, 256, 0, 857 }, ++{ 0x3300, 256, 0, 858 }, ++{ 0xb00, 256, 0, 881 }, ++{ 0x700, 256, 0, 882 }, ++{ 0x80, 256, 0, 904 }, ++{ 0x280, 256, 0, 902 }, ++{ 0x180, 256, 0, 903 }, ++{ 0x40, 256, 0, 916 }, ++{ 0x140, 256, 0, 914 }, ++{ 0xc0, 256, 0, 915 }, ++{ 0x20, 256, 0, 928 }, ++{ 0xa0, 256, 0, 926 }, ++{ 0x60, 256, 0, 927 }, ++{ 0x10, 256, 0, 940 }, ++{ 0x50, 256, 0, 938 }, ++{ 0x30, 256, 0, 939 }, ++{ 0x8, 256, 0, 952 }, ++{ 0x28, 256, 0, 950 }, ++{ 0x18, 256, 0, 951 }, ++{ 0x4, 256, 0, 968 }, ++{ 0x2, 256, 0, 969 }, ++{ 0x1, 256, 0, 970 }, ++{ 0x500, 251, 0, 874 }, ++{ 0x1500, 251, 0, 872 }, ++{ 0xd00, 251, 0, 873 }, ++{ 0x300, 251, 0, 886 }, ++{ 0x1300, 251, 0, 862 }, ++{ 0x5300, 251, 0, 860 }, ++{ 0x3300, 251, 0, 861 }, ++{ 0xb00, 251, 0, 884 }, ++{ 0x700, 251, 0, 885 }, ++{ 0x80, 251, 0, 907 }, ++{ 0x280, 251, 0, 905 }, ++{ 0x180, 251, 0, 906 }, ++{ 0x40, 251, 0, 919 }, ++{ 0x140, 251, 0, 917 }, ++{ 0xc0, 251, 0, 918 }, ++{ 0x20, 251, 0, 931 }, ++{ 0xa0, 251, 0, 929 }, ++{ 0x60, 251, 0, 930 }, ++{ 0x10, 251, 0, 943 }, ++{ 0x50, 251, 0, 941 }, ++{ 0x30, 251, 0, 942 }, ++{ 0x8, 251, 0, 955 }, ++{ 0x28, 251, 0, 953 }, ++{ 0x18, 251, 0, 954 }, ++{ 0x4, 251, 0, 971 }, ++{ 0x2, 251, 0, 972 }, ++{ 0x1, 251, 0, 973 }, ++{ 0x2, 150, 0, 975 }, ++{ 0x1, 150, 0, 976 }, ++{ 0x1, 50, 0, 977 }, ++{ 0x3, 49, 0, 978 }, ++{ 0x1, 428, 0, 979 }, ++{ 0x1, 438, 0, 980 }, ++{ 0x2, 386, 0, 983 }, ++{ 0x1, 386, 0, 984 }, ++{ 0x2, 384, 0, 985 }, ++{ 0x1, 384, 0, 986 }, ++{ 0x1, 383, 0, 987 }, ++{ 0x1, 328, 0, 992 }, ++{ 0x1, 327, 0, 993 }, ++{ 0x1, 326, 0, 994 }, ++{ 0x1, 325, 0, 995 }, ++{ 0x1, 250, 0, 996 }, ++{ 0x1, 249, 0, 997 }, ++{ 0x1, 324, 0, 998 }, ++{ 0x1, 323, 0, 999 }, ++{ 0x1, 322, 0, 1000 }, ++{ 0x1, 321, 0, 1001 }, ++{ 0x1, 320, 0, 1002 }, ++{ 0x1, 319, 0, 1003 }, ++{ 0x1, 318, 0, 1004 }, ++{ 0x2, 248, 0, 1005 }, ++{ 0x1, 248, 0, 1006 }, ++{ 0x2, 366, 0, 1012 }, ++{ 0x1, 366, 0, 1013 }, ++{ 0x1, 317, 0, 1014 }, ++{ 0x1, 316, 0, 1015 }, ++{ 0x1, 315, 0, 1016 }, ++{ 0x1, 314, 0, 1017 }, ++{ 0x1, 8, 1, 1019 }, ++{ 0x1, 9, 0, 1018 }, ++{ 0x1, 313, 0, 1020 }, ++{ 0x1, 312, 0, 1021 }, ++{ 0x1, 311, 0, 1022 }, ++{ 0x1, 310, 0, 1023 }, ++{ 0x1, 388, 0, 1024 }, ++{ 0x1, 399, 0, 1025 }, ++{ 0x1, 389, 0, 1026 }, ++{ 0x1, 423, 0, 1027 }, ++{ 0x1, 309, 0, 1031 }, ++{ 0x1, 247, 0, 1032 }, ++{ 0x1, 177, 0, 1035 }, ++{ 0x2, 291, 0, 1039 }, ++{ 0x1, 291, 0, 1040 }, ++{ 0x1, 236, 0, 1041 }, ++{ 0x5, 48, 0, 1043 }, ++{ 0x3, 48, 0, 1044 }, ++{ 0x5, 47, 0, 1045 }, ++{ 0x3, 47, 0, 1046 }, ++{ 0x1, 365, 0, 1047 }, ++{ 0x1, 373, 0, 1048 }, ++{ 0x1, 371, 0, 1049 }, ++{ 0x1, 392, 0, 1050 }, ++{ 0x1, 372, 0, 1051 }, ++{ 0x1, 370, 0, 1052 }, ++{ 0x2, 378, 0, 1053 }, ++{ 0x1, 378, 0, 1055 }, ++{ 0x2, 376, 0, 1054 }, ++{ 0x1, 376, 0, 1056 }, ++{ 0x2, 396, 0, 1057 }, ++{ 0x1, 396, 0, 1060 }, ++{ 0x2, 377, 0, 1058 }, ++{ 0x1, 377, 0, 1061 }, ++{ 0x2, 375, 0, 1059 }, ++{ 0x1, 375, 0, 1062 }, ++{ 0x1, 338, 0, 1063 }, ++{ 0x1, 337, 0, 1064 }, ++{ 0x1, 369, 0, 1065 }, ++{ 0x1, 360, 0, 1066 }, ++{ 0x1, 362, 0, 1067 }, ++{ 0x1, 359, 0, 1068 }, ++{ 0x1, 361, 0, 1069 }, ++{ 0x2, 442, 0, 1070 }, ++{ 0x1, 442, 0, 1073 }, ++{ 0x2, 441, 0, 1071 }, ++{ 0x1, 441, 0, 1074 }, ++{ 0x2, 440, 0, 1072 }, ++{ 0x1, 440, 0, 1075 }, ++{ 0x1, 348, 0, 1076 }, ++{ 0x2, 347, 0, 1077 }, ++{ 0x1, 347, 0, 1078 }, ++{ 0x2, 294, 0, 1079 }, ++{ 0x1, 294, 0, 1082 }, ++{ 0x2, 293, 0, 1080 }, ++{ 0x1, 293, 0, 1083 }, ++{ 0x2, 292, 0, 1081 }, ++{ 0x1, 292, 0, 1084 }, ++{ 0x2, 363, 0, 1085 }, ++{ 0x1, 363, 0, 1086 }, ++{ 0x2, 364, 0, 1087 }, ++{ 0x1, 364, 0, 1088 }, ++{ 0xa, 434, 1, 1100 }, ++{ 0xa, 435, 1, 1099 }, ++{ 0xa, 436, 1, 1098 }, ++{ 0xa, 437, 0, 1097 }, ++{ 0x1a, 434, 1, 1092 }, ++{ 0x1a, 435, 1, 1091 }, ++{ 0x32, 436, 1, 1090 }, ++{ 0x32, 437, 0, 1089 }, ++{ 0x6, 434, 1, 1108 }, ++{ 0x6, 435, 1, 1107 }, ++{ 0x6, 436, 1, 1106 }, ++{ 0x6, 437, 0, 1105 }, ++{ 0x1, 434, 1, 1120 }, ++{ 0x1, 435, 1, 1119 }, ++{ 0x1, 436, 1, 1118 }, ++{ 0x1, 437, 0, 1117 }, ++{ 0x9, 434, 1, 1104 }, ++{ 0x9, 435, 1, 1103 }, ++{ 0x9, 436, 1, 1102 }, ++{ 0x9, 437, 0, 1101 }, ++{ 0x19, 434, 1, 1096 }, ++{ 0x19, 435, 1, 1095 }, ++{ 0x31, 436, 1, 1094 }, ++{ 0x31, 437, 0, 1093 }, ++{ 0x5, 434, 1, 1112 }, ++{ 0x5, 435, 1, 1111 }, ++{ 0x5, 436, 1, 1110 }, ++{ 0x5, 437, 0, 1109 }, ++{ 0x3, 434, 1, 1116 }, ++{ 0x3, 435, 1, 1115 }, ++{ 0x3, 436, 1, 1114 }, ++{ 0x3, 437, 0, 1113 }, ++{ 0xa, 429, 1, 1132 }, ++{ 0xa, 430, 1, 1131 }, ++{ 0xa, 431, 1, 1130 }, ++{ 0xa, 432, 0, 1129 }, ++{ 0x1a, 429, 1, 1124 }, ++{ 0x1a, 430, 1, 1123 }, ++{ 0x32, 431, 1, 1122 }, ++{ 0x32, 432, 0, 1121 }, ++{ 0x6, 429, 1, 1140 }, ++{ 0x6, 430, 1, 1139 }, ++{ 0x6, 431, 1, 1138 }, ++{ 0x6, 432, 0, 1137 }, ++{ 0x1, 429, 1, 1152 }, ++{ 0x1, 430, 1, 1151 }, ++{ 0x1, 431, 1, 1150 }, ++{ 0x1, 432, 0, 1149 }, ++{ 0x9, 429, 1, 1136 }, ++{ 0x9, 430, 1, 1135 }, ++{ 0x9, 431, 1, 1134 }, ++{ 0x9, 432, 0, 1133 }, ++{ 0x19, 429, 1, 1128 }, ++{ 0x19, 430, 1, 1127 }, ++{ 0x31, 431, 1, 1126 }, ++{ 0x31, 432, 0, 1125 }, ++{ 0x5, 429, 1, 1144 }, ++{ 0x5, 430, 1, 1143 }, ++{ 0x5, 431, 1, 1142 }, ++{ 0x5, 432, 0, 1141 }, ++{ 0x3, 429, 1, 1148 }, ++{ 0x3, 430, 1, 1147 }, ++{ 0x3, 431, 1, 1146 }, ++{ 0x3, 432, 0, 1145 }, ++{ 0x1, 139, 0, 1153 }, ++{ 0x1, 138, 0, 1154 }, ++{ 0x1, 391, 1, 1156 }, ++{ 0x1, 137, 0, 1155 }, ++{ 0x2, 395, 1, 1158 }, ++{ 0x2, 141, 0, 1157 }, ++{ 0x1, 395, 1, 1160 }, ++{ 0x1, 141, 0, 1159 }, ++{ 0x1, 397, 0, 1161 }, ++{ 0x1, 136, 0, 1162 }, ++{ 0x2, 135, 0, 1163 }, ++{ 0x2, 134, 0, 1164 }, ++{ 0x1, 454, 1, 1170 }, ++{ 0x1, 246, 0, 1033 }, ++{ 0x1, 453, 0, 1171 }, ++{ 0x1, 452, 1, 1172 }, ++{ 0x1, 245, 0, 1042 }, ++{ 0x1, 308, 0, 1173 }, ++{ 0x1, 307, 1, 1174 }, ++{ 0x1, 290, 0, 1034 }, ++{ 0x1, 306, 0, 1175 }, ++{ 0x1, 305, 1, 1176 }, ++{ 0x1, 427, 0, 1036 }, ++{ 0x1, 304, 1, 1177 }, ++{ 0x1, 398, 0, 1038 }, ++{ 0x1, 303, 0, 1178 }, ++{ 0x1, 302, 0, 1179 }, ++{ 0x1, 301, 0, 1180 }, ++{ 0x1, 300, 1, 1181 }, ++{ 0x2, 398, 0, 1037 }, ++{ 0x10, 299, 0, 1185 }, ++{ 0x90, 299, 0, 1183 }, ++{ 0x190, 299, 0, 1182 }, ++{ 0x50, 299, 0, 1184 }, ++{ 0x30, 299, 0, 1187 }, ++{ 0x70, 299, 0, 1186 }, ++{ 0x8, 299, 0, 1189 }, ++{ 0x18, 299, 0, 1188 }, ++{ 0x4, 299, 0, 1190 }, ++{ 0x1, 299, 0, 1193 }, ++{ 0x3, 299, 0, 1192 }, ++{ 0x1, 298, 1, 1194 }, ++{ 0x2, 299, 0, 1191 }, ++{ 0x3, 46, 0, 1195 }, ++{ 0x1, 241, 1, 1196 }, ++{ 0x1, 242, 1, 1028 }, ++{ 0x1, 243, 0, 88 }, ++{ 0x1, 341, 1, 1197 }, ++{ 0x1, 342, 1, 1029 }, ++{ 0x1, 343, 0, 89 }, ++{ 0x1, 34, 1, 1198 }, ++{ 0x1, 35, 1, 1030 }, ++{ 0x1, 36, 0, 90 }, ++{ 0x1, 230, 0, 1199 }, ++{ 0x4, 447, 0, 1200 }, ++{ 0x2, 447, 0, 1201 }, ++{ 0x1, 447, 1, 1203 }, ++{ 0x1, 448, 0, 1202 }, ++{ 0x8, 449, 0, 1204 }, ++{ 0x4, 449, 0, 1205 }, ++{ 0x1, 449, 1, 1207 }, ++{ 0x2, 449, 0, 1206 }, ++{ 0x8, 219, 0, 1208 }, ++{ 0x4, 219, 0, 1209 }, ++{ 0x2, 219, 0, 1210 }, ++{ 0x1, 219, 1, 1212 }, ++{ 0x1, 220, 0, 1211 }, ++{ 0x10, 221, 0, 1213 }, ++{ 0x8, 221, 0, 1214 }, ++{ 0x4, 221, 0, 1215 }, ++{ 0x1, 221, 1, 1217 }, ++{ 0x2, 221, 0, 1216 }, ++{ 0x220, 191, 0, 1218 }, ++{ 0x120, 191, 0, 1219 }, ++{ 0xa0, 191, 0, 1220 }, ++{ 0x60, 191, 1, 1222 }, ++{ 0x4, 192, 0, 1221 }, ++{ 0x110, 191, 0, 1228 }, ++{ 0x90, 191, 0, 1229 }, ++{ 0x50, 191, 0, 1230 }, ++{ 0x30, 191, 1, 1232 }, ++{ 0x2, 192, 0, 1231 }, ++{ 0x8, 191, 0, 1233 }, ++{ 0x4, 191, 0, 1234 }, ++{ 0x2, 191, 0, 1235 }, ++{ 0x1, 191, 1, 1237 }, ++{ 0x1, 192, 0, 1236 }, ++{ 0x440, 193, 0, 1223 }, ++{ 0x240, 193, 0, 1224 }, ++{ 0x140, 193, 0, 1225 }, ++{ 0xc0, 193, 1, 1227 }, ++{ 0x40, 193, 0, 1226 }, ++{ 0x220, 193, 0, 1238 }, ++{ 0x120, 193, 0, 1239 }, ++{ 0xa0, 193, 0, 1240 }, ++{ 0x60, 193, 1, 1242 }, ++{ 0x20, 193, 0, 1241 }, ++{ 0x10, 193, 0, 1243 }, ++{ 0x8, 193, 0, 1244 }, ++{ 0x4, 193, 0, 1245 }, ++{ 0x1, 193, 1, 1247 }, ++{ 0x2, 193, 0, 1246 }, ++{ 0x8, 215, 0, 1248 }, ++{ 0x4, 215, 0, 1249 }, ++{ 0x2, 215, 0, 1250 }, ++{ 0x1, 215, 1, 1252 }, ++{ 0x1, 216, 0, 1251 }, ++{ 0x220, 187, 0, 1253 }, ++{ 0x120, 187, 0, 1254 }, ++{ 0xa0, 187, 0, 1255 }, ++{ 0x60, 187, 1, 1257 }, ++{ 0x4, 188, 0, 1256 }, ++{ 0x110, 187, 0, 1263 }, ++{ 0x90, 187, 0, 1264 }, ++{ 0x50, 187, 0, 1265 }, ++{ 0x30, 187, 1, 1267 }, ++{ 0x2, 188, 0, 1266 }, ++{ 0x8, 187, 0, 1268 }, ++{ 0x4, 187, 0, 1269 }, ++{ 0x2, 187, 0, 1270 }, ++{ 0x1, 187, 1, 1272 }, ++{ 0x1, 188, 0, 1271 }, ++{ 0x440, 233, 0, 1258 }, ++{ 0x240, 233, 0, 1259 }, ++{ 0x140, 233, 0, 1260 }, ++{ 0xc0, 233, 1, 1262 }, ++{ 0x40, 233, 0, 1261 }, ++{ 0x220, 233, 0, 1273 }, ++{ 0x120, 233, 0, 1274 }, ++{ 0xa0, 233, 0, 1275 }, ++{ 0x60, 233, 1, 1277 }, ++{ 0x20, 233, 0, 1276 }, ++{ 0x10, 233, 0, 1278 }, ++{ 0x8, 233, 0, 1279 }, ++{ 0x4, 233, 0, 1280 }, ++{ 0x1, 233, 1, 1282 }, ++{ 0x2, 233, 0, 1281 }, ++{ 0x8, 207, 0, 1283 }, ++{ 0x4, 207, 0, 1284 }, ++{ 0x2, 207, 0, 1285 }, ++{ 0x1, 207, 1, 1287 }, ++{ 0x1, 208, 0, 1286 }, ++{ 0x10, 214, 0, 1288 }, ++{ 0x8, 214, 0, 1289 }, ++{ 0x4, 214, 0, 1290 }, ++{ 0x1, 214, 1, 1292 }, ++{ 0x2, 214, 0, 1291 }, ++{ 0x220, 178, 0, 1293 }, ++{ 0x120, 178, 0, 1294 }, ++{ 0xa0, 178, 0, 1295 }, ++{ 0x60, 178, 1, 1297 }, ++{ 0x4, 179, 0, 1296 }, ++{ 0x110, 178, 0, 1318 }, ++{ 0x90, 178, 0, 1319 }, ++{ 0x50, 178, 0, 1320 }, ++{ 0x30, 178, 1, 1322 }, ++{ 0x2, 179, 0, 1321 }, ++{ 0x8, 178, 0, 1323 }, ++{ 0x4, 178, 0, 1324 }, ++{ 0x2, 178, 0, 1325 }, ++{ 0x1, 178, 1, 1327 }, ++{ 0x1, 179, 0, 1326 }, ++{ 0x440, 186, 0, 1298 }, ++{ 0x240, 186, 0, 1299 }, ++{ 0x140, 186, 0, 1300 }, ++{ 0xc0, 186, 1, 1302 }, ++{ 0x40, 186, 0, 1301 }, ++{ 0x220, 186, 0, 1328 }, ++{ 0x120, 186, 0, 1329 }, ++{ 0xa0, 186, 0, 1330 }, ++{ 0x60, 186, 1, 1332 }, ++{ 0x20, 186, 0, 1331 }, ++{ 0x10, 186, 0, 1333 }, ++{ 0x8, 186, 0, 1334 }, ++{ 0x4, 186, 0, 1335 }, ++{ 0x1, 186, 1, 1337 }, ++{ 0x2, 186, 0, 1336 }, ++{ 0x440, 143, 0, 1303 }, ++{ 0x240, 143, 0, 1304 }, ++{ 0x140, 143, 0, 1305 }, ++{ 0xc0, 143, 1, 1307 }, ++{ 0x40, 143, 0, 1306 }, ++{ 0x220, 143, 0, 1338 }, ++{ 0x120, 143, 0, 1339 }, ++{ 0xa0, 143, 0, 1340 }, ++{ 0x60, 143, 1, 1342 }, ++{ 0x20, 143, 0, 1341 }, ++{ 0x10, 143, 0, 1343 }, ++{ 0x8, 143, 0, 1344 }, ++{ 0x1, 143, 1, 1347 }, ++{ 0x2, 143, 0, 1346 }, ++{ 0x440, 194, 1, 1313 }, ++{ 0x441, 174, 0, 1308 }, ++{ 0x240, 194, 1, 1314 }, ++{ 0x241, 174, 0, 1309 }, ++{ 0x140, 194, 1, 1315 }, ++{ 0x141, 174, 0, 1310 }, ++{ 0xc0, 194, 1, 1317 }, ++{ 0x40, 194, 1, 1316 }, ++{ 0xc1, 174, 1, 1312 }, ++{ 0x41, 174, 0, 1311 }, ++{ 0x220, 194, 1, 1358 }, ++{ 0x221, 174, 0, 1348 }, ++{ 0x120, 194, 1, 1359 }, ++{ 0x121, 174, 0, 1349 }, ++{ 0xa0, 194, 1, 1360 }, ++{ 0xa1, 174, 0, 1350 }, ++{ 0x60, 194, 1, 1362 }, ++{ 0x20, 194, 1, 1361 }, ++{ 0x61, 174, 1, 1352 }, ++{ 0x21, 174, 0, 1351 }, ++{ 0x10, 194, 1, 1363 }, ++{ 0x11, 174, 0, 1353 }, ++{ 0x8, 194, 1, 1364 }, ++{ 0x9, 174, 0, 1354 }, ++{ 0x4, 194, 1, 1365 }, ++{ 0x5, 174, 0, 1355 }, ++{ 0x1, 194, 1, 1367 }, ++{ 0x2, 194, 1, 1366 }, ++{ 0x3, 174, 1, 1357 }, ++{ 0x1, 174, 0, 1356 }, ++{ 0x1, 153, 1, 1375 }, ++{ 0x1, 154, 1, 1374 }, ++{ 0x1, 155, 1, 1373 }, ++{ 0x1, 156, 0, 1372 }, ++{ 0x3, 153, 1, 1371 }, ++{ 0x3, 154, 1, 1370 }, ++{ 0x3, 155, 1, 1369 }, ++{ 0x3, 156, 0, 1368 }, ++{ 0x1108, 159, 1, 1537 }, ++{ 0x1108, 160, 1, 1536 }, ++{ 0x1108, 165, 1, 1377 }, ++{ 0x1108, 166, 0, 1376 }, ++{ 0x908, 159, 1, 1539 }, ++{ 0x908, 160, 1, 1538 }, ++{ 0x908, 165, 1, 1379 }, ++{ 0x908, 166, 0, 1378 }, ++{ 0x508, 159, 1, 1541 }, ++{ 0x508, 160, 1, 1540 }, ++{ 0x508, 165, 1, 1381 }, ++{ 0x508, 166, 0, 1380 }, ++{ 0x308, 159, 1, 1545 }, ++{ 0x308, 160, 1, 1544 }, ++{ 0x108, 160, 1, 1542 }, ++{ 0x18, 161, 1, 1543 }, ++{ 0x308, 165, 1, 1385 }, ++{ 0x308, 166, 1, 1384 }, ++{ 0x108, 166, 1, 1382 }, ++{ 0x18, 167, 0, 1383 }, ++{ 0x88, 159, 1, 1577 }, ++{ 0x88, 160, 1, 1576 }, ++{ 0x88, 165, 1, 1457 }, ++{ 0x88, 166, 0, 1456 }, ++{ 0x48, 159, 1, 1579 }, ++{ 0x48, 160, 1, 1578 }, ++{ 0x48, 165, 1, 1459 }, ++{ 0x48, 166, 0, 1458 }, ++{ 0x28, 159, 1, 1581 }, ++{ 0x28, 160, 1, 1580 }, ++{ 0x28, 165, 1, 1461 }, ++{ 0x28, 166, 0, 1460 }, ++{ 0x18, 159, 1, 1585 }, ++{ 0x18, 160, 1, 1584 }, ++{ 0x8, 160, 1, 1582 }, ++{ 0x8, 161, 1, 1583 }, ++{ 0x18, 165, 1, 1465 }, ++{ 0x18, 166, 1, 1464 }, ++{ 0x8, 166, 1, 1462 }, ++{ 0x8, 167, 0, 1463 }, ++{ 0x884, 159, 1, 1547 }, ++{ 0x884, 160, 1, 1546 }, ++{ 0x442, 162, 1, 1437 }, ++{ 0x442, 163, 1, 1436 }, ++{ 0x884, 165, 1, 1407 }, ++{ 0x884, 166, 1, 1406 }, ++{ 0x442, 168, 1, 1387 }, ++{ 0x442, 169, 0, 1386 }, ++{ 0x484, 159, 1, 1549 }, ++{ 0x484, 160, 1, 1548 }, ++{ 0x242, 162, 1, 1439 }, ++{ 0x242, 163, 1, 1438 }, ++{ 0x484, 165, 1, 1409 }, ++{ 0x484, 166, 1, 1408 }, ++{ 0x242, 168, 1, 1389 }, ++{ 0x242, 169, 0, 1388 }, ++{ 0x284, 159, 1, 1551 }, ++{ 0x284, 160, 1, 1550 }, ++{ 0x142, 162, 1, 1441 }, ++{ 0x142, 163, 1, 1440 }, ++{ 0x284, 165, 1, 1411 }, ++{ 0x284, 166, 1, 1410 }, ++{ 0x142, 168, 1, 1391 }, ++{ 0x142, 169, 0, 1390 }, ++{ 0x184, 159, 1, 1555 }, ++{ 0x184, 160, 1, 1554 }, ++{ 0x84, 160, 1, 1552 }, ++{ 0xc, 161, 1, 1553 }, ++{ 0xc2, 162, 1, 1445 }, ++{ 0xc2, 163, 1, 1444 }, ++{ 0x42, 163, 1, 1442 }, ++{ 0x6, 164, 1, 1443 }, ++{ 0x184, 165, 1, 1415 }, ++{ 0x184, 166, 1, 1414 }, ++{ 0x84, 166, 1, 1412 }, ++{ 0xc, 167, 1, 1413 }, ++{ 0xc2, 168, 1, 1395 }, ++{ 0xc2, 169, 1, 1394 }, ++{ 0x42, 169, 1, 1392 }, ++{ 0x6, 170, 0, 1393 }, ++{ 0x44, 159, 1, 1587 }, ++{ 0x44, 160, 1, 1586 }, ++{ 0x22, 162, 1, 1517 }, ++{ 0x22, 163, 1, 1516 }, ++{ 0x44, 165, 1, 1487 }, ++{ 0x44, 166, 1, 1486 }, ++{ 0x22, 168, 1, 1467 }, ++{ 0x22, 169, 0, 1466 }, ++{ 0x24, 159, 1, 1589 }, ++{ 0x24, 160, 1, 1588 }, ++{ 0x12, 162, 1, 1519 }, ++{ 0x12, 163, 1, 1518 }, ++{ 0x24, 165, 1, 1489 }, ++{ 0x24, 166, 1, 1488 }, ++{ 0x12, 168, 1, 1469 }, ++{ 0x12, 169, 0, 1468 }, ++{ 0x14, 159, 1, 1591 }, ++{ 0x14, 160, 1, 1590 }, ++{ 0xa, 162, 1, 1521 }, ++{ 0xa, 163, 1, 1520 }, ++{ 0x14, 165, 1, 1491 }, ++{ 0x14, 166, 1, 1490 }, ++{ 0xa, 168, 1, 1471 }, ++{ 0xa, 169, 0, 1470 }, ++{ 0xc, 159, 1, 1595 }, ++{ 0xc, 160, 1, 1594 }, ++{ 0x4, 160, 1, 1592 }, ++{ 0x4, 161, 1, 1593 }, ++{ 0x6, 162, 1, 1525 }, ++{ 0x6, 163, 1, 1524 }, ++{ 0x2, 163, 1, 1522 }, ++{ 0x2, 164, 1, 1523 }, ++{ 0xc, 165, 1, 1495 }, ++{ 0xc, 166, 1, 1494 }, ++{ 0x4, 166, 1, 1492 }, ++{ 0x4, 167, 1, 1493 }, ++{ 0x6, 168, 1, 1475 }, ++{ 0x6, 169, 1, 1474 }, ++{ 0x2, 169, 1, 1472 }, ++{ 0x2, 170, 0, 1473 }, ++{ 0x442, 159, 1, 1557 }, ++{ 0x442, 160, 1, 1556 }, ++{ 0x221, 162, 1, 1447 }, ++{ 0x221, 163, 1, 1446 }, ++{ 0x442, 165, 1, 1417 }, ++{ 0x442, 166, 1, 1416 }, ++{ 0x221, 168, 1, 1397 }, ++{ 0x221, 169, 0, 1396 }, ++{ 0x242, 159, 1, 1559 }, ++{ 0x242, 160, 1, 1558 }, ++{ 0x121, 162, 1, 1449 }, ++{ 0x121, 163, 1, 1448 }, ++{ 0x242, 165, 1, 1419 }, ++{ 0x242, 166, 1, 1418 }, ++{ 0x121, 168, 1, 1399 }, ++{ 0x121, 169, 0, 1398 }, ++{ 0x142, 159, 1, 1561 }, ++{ 0x142, 160, 1, 1560 }, ++{ 0xa1, 162, 1, 1451 }, ++{ 0xa1, 163, 1, 1450 }, ++{ 0x142, 165, 1, 1421 }, ++{ 0x142, 166, 1, 1420 }, ++{ 0xa1, 168, 1, 1401 }, ++{ 0xa1, 169, 0, 1400 }, ++{ 0xc2, 159, 1, 1565 }, ++{ 0xc2, 160, 1, 1564 }, ++{ 0x42, 160, 1, 1562 }, ++{ 0x6, 161, 1, 1563 }, ++{ 0x61, 162, 1, 1455 }, ++{ 0x61, 163, 1, 1454 }, ++{ 0x21, 163, 1, 1452 }, ++{ 0x3, 164, 1, 1453 }, ++{ 0xc2, 165, 1, 1425 }, ++{ 0xc2, 166, 1, 1424 }, ++{ 0x42, 166, 1, 1422 }, ++{ 0x6, 167, 1, 1423 }, ++{ 0x61, 168, 1, 1405 }, ++{ 0x61, 169, 1, 1404 }, ++{ 0x21, 169, 1, 1402 }, ++{ 0x3, 170, 0, 1403 }, ++{ 0x22, 159, 1, 1597 }, ++{ 0x22, 160, 1, 1596 }, ++{ 0x11, 162, 1, 1527 }, ++{ 0x11, 163, 1, 1526 }, ++{ 0x22, 165, 1, 1497 }, ++{ 0x22, 166, 1, 1496 }, ++{ 0x11, 168, 1, 1477 }, ++{ 0x11, 169, 0, 1476 }, ++{ 0x12, 159, 1, 1599 }, ++{ 0x12, 160, 1, 1598 }, ++{ 0x9, 162, 1, 1529 }, ++{ 0x9, 163, 1, 1528 }, ++{ 0x12, 165, 1, 1499 }, ++{ 0x12, 166, 1, 1498 }, ++{ 0x9, 168, 1, 1479 }, ++{ 0x9, 169, 0, 1478 }, ++{ 0xa, 159, 1, 1601 }, ++{ 0xa, 160, 1, 1600 }, ++{ 0x5, 162, 1, 1531 }, ++{ 0x5, 163, 1, 1530 }, ++{ 0xa, 165, 1, 1501 }, ++{ 0xa, 166, 1, 1500 }, ++{ 0x5, 168, 1, 1481 }, ++{ 0x5, 169, 0, 1480 }, ++{ 0x6, 159, 1, 1605 }, ++{ 0x6, 160, 1, 1604 }, ++{ 0x2, 160, 1, 1602 }, ++{ 0x2, 161, 1, 1603 }, ++{ 0x3, 162, 1, 1535 }, ++{ 0x3, 163, 1, 1534 }, ++{ 0x1, 163, 1, 1532 }, ++{ 0x1, 164, 1, 1533 }, ++{ 0x6, 165, 1, 1505 }, ++{ 0x6, 166, 1, 1504 }, ++{ 0x2, 166, 1, 1502 }, ++{ 0x2, 167, 1, 1503 }, ++{ 0x3, 168, 1, 1485 }, ++{ 0x3, 169, 1, 1484 }, ++{ 0x1, 169, 1, 1482 }, ++{ 0x1, 170, 0, 1483 }, ++{ 0x221, 159, 1, 1567 }, ++{ 0x221, 160, 1, 1566 }, ++{ 0x221, 165, 1, 1427 }, ++{ 0x221, 166, 0, 1426 }, ++{ 0x121, 159, 1, 1569 }, ++{ 0x121, 160, 1, 1568 }, ++{ 0x121, 165, 1, 1429 }, ++{ 0x121, 166, 0, 1428 }, ++{ 0xa1, 159, 1, 1571 }, ++{ 0xa1, 160, 1, 1570 }, ++{ 0xa1, 165, 1, 1431 }, ++{ 0xa1, 166, 0, 1430 }, ++{ 0x61, 159, 1, 1575 }, ++{ 0x61, 160, 1, 1574 }, ++{ 0x21, 160, 1, 1572 }, ++{ 0x3, 161, 1, 1573 }, ++{ 0x61, 165, 1, 1435 }, ++{ 0x61, 166, 1, 1434 }, ++{ 0x21, 166, 1, 1432 }, ++{ 0x3, 167, 0, 1433 }, ++{ 0x11, 159, 1, 1607 }, ++{ 0x11, 160, 1, 1606 }, ++{ 0x11, 165, 1, 1507 }, ++{ 0x11, 166, 0, 1506 }, ++{ 0x9, 159, 1, 1609 }, ++{ 0x9, 160, 1, 1608 }, ++{ 0x9, 165, 1, 1509 }, ++{ 0x9, 166, 0, 1508 }, ++{ 0x5, 159, 1, 1611 }, ++{ 0x5, 160, 1, 1610 }, ++{ 0x5, 165, 1, 1511 }, ++{ 0x5, 166, 0, 1510 }, ++{ 0x3, 159, 1, 1615 }, ++{ 0x3, 160, 1, 1614 }, ++{ 0x1, 160, 1, 1612 }, ++{ 0x1, 161, 1, 1613 }, ++{ 0x3, 165, 1, 1515 }, ++{ 0x3, 166, 1, 1514 }, ++{ 0x1, 166, 1, 1512 }, ++{ 0x1, 167, 0, 1513 }, ++{ 0x442, 205, 0, 1616 }, ++{ 0x242, 205, 0, 1617 }, ++{ 0x142, 205, 0, 1618 }, ++{ 0xc2, 205, 1, 1620 }, ++{ 0x6, 206, 1, 1619 }, ++{ 0x1, 439, 0, 981 }, ++{ 0x22, 205, 0, 1626 }, ++{ 0x12, 205, 0, 1627 }, ++{ 0xa, 205, 0, 1628 }, ++{ 0x6, 205, 1, 1630 }, ++{ 0x2, 206, 1, 1629 }, ++{ 0x2, 367, 0, 1010 }, ++{ 0x221, 205, 0, 1621 }, ++{ 0x121, 205, 0, 1622 }, ++{ 0xa1, 205, 0, 1623 }, ++{ 0x61, 205, 1, 1625 }, ++{ 0x3, 206, 1, 1624 }, ++{ 0x1, 433, 0, 982 }, ++{ 0x11, 205, 0, 1631 }, ++{ 0x9, 205, 0, 1632 }, ++{ 0x5, 205, 0, 1633 }, ++{ 0x3, 205, 1, 1635 }, ++{ 0x1, 206, 1, 1634 }, ++{ 0x1, 367, 0, 1011 }, ++{ 0x4, 211, 0, 1636 }, ++{ 0x1, 211, 0, 1638 }, ++{ 0x1, 218, 0, 1639 }, ++{ 0x1, 217, 1, 1640 }, ++{ 0x2, 211, 0, 1637 }, ++{ 0x1, 196, 0, 1641 }, ++{ 0x880, 202, 0, 1642 }, ++{ 0x480, 202, 0, 1643 }, ++{ 0x280, 202, 0, 1644 }, ++{ 0x180, 202, 1, 1646 }, ++{ 0x80, 203, 0, 1645 }, ++{ 0x440, 202, 1, 1657 }, ++{ 0x88, 204, 0, 1647 }, ++{ 0x240, 202, 1, 1658 }, ++{ 0x48, 204, 0, 1648 }, ++{ 0x140, 202, 1, 1659 }, ++{ 0x28, 204, 0, 1649 }, ++{ 0xc0, 202, 1, 1661 }, ++{ 0x40, 203, 1, 1660 }, ++{ 0x18, 204, 1, 1651 }, ++{ 0x8, 204, 0, 1650 }, ++{ 0x220, 202, 1, 1662 }, ++{ 0x44, 204, 0, 1652 }, ++{ 0x120, 202, 1, 1663 }, ++{ 0x24, 204, 0, 1653 }, ++{ 0xa0, 202, 1, 1664 }, ++{ 0x14, 204, 0, 1654 }, ++{ 0x60, 202, 1, 1666 }, ++{ 0x20, 203, 1, 1665 }, ++{ 0xc, 204, 1, 1656 }, ++{ 0x4, 204, 0, 1655 }, ++{ 0x110, 202, 0, 1667 }, ++{ 0x90, 202, 0, 1668 }, ++{ 0x50, 202, 0, 1669 }, ++{ 0x30, 202, 1, 1671 }, ++{ 0x10, 203, 1, 1670 }, ++{ 0x1, 385, 0, 974 }, ++{ 0x88, 202, 0, 1672 }, ++{ 0x48, 202, 0, 1673 }, ++{ 0x28, 202, 0, 1674 }, ++{ 0x18, 202, 1, 1676 }, ++{ 0x8, 203, 1, 1675 }, ++{ 0xc, 368, 0, 1007 }, ++{ 0x44, 202, 1, 1687 }, ++{ 0x22, 204, 0, 1677 }, ++{ 0x24, 202, 1, 1688 }, ++{ 0x12, 204, 0, 1678 }, ++{ 0x14, 202, 1, 1689 }, ++{ 0xa, 204, 0, 1679 }, ++{ 0xc, 202, 1, 1691 }, ++{ 0x4, 203, 1, 1690 }, ++{ 0x6, 204, 1, 1681 }, ++{ 0x2, 204, 1, 1680 }, ++{ 0x6, 368, 0, 1008 }, ++{ 0x22, 202, 1, 1692 }, ++{ 0x11, 204, 0, 1682 }, ++{ 0x12, 202, 1, 1693 }, ++{ 0x9, 204, 0, 1683 }, ++{ 0xa, 202, 1, 1694 }, ++{ 0x5, 204, 0, 1684 }, ++{ 0x6, 202, 1, 1696 }, ++{ 0x2, 203, 1, 1695 }, ++{ 0x3, 204, 1, 1686 }, ++{ 0x1, 204, 1, 1685 }, ++{ 0x3, 368, 0, 1009 }, ++{ 0x11, 202, 0, 1697 }, ++{ 0x9, 202, 0, 1698 }, ++{ 0x5, 202, 0, 1699 }, ++{ 0x3, 202, 1, 1701 }, ++{ 0x1, 203, 0, 1700 }, ++{ 0x8, 198, 0, 1702 }, ++{ 0x4, 198, 0, 1703 }, ++{ 0x2, 198, 0, 1704 }, ++{ 0x1, 198, 1, 1706 }, ++{ 0x1, 199, 1, 1705 }, ++{ 0x1, 332, 0, 988 }, ++{ 0x8, 200, 0, 1707 }, ++{ 0x4, 200, 0, 1708 }, ++{ 0x2, 200, 0, 1709 }, ++{ 0x1, 200, 1, 1711 }, ++{ 0x1, 201, 1, 1710 }, ++{ 0x1, 331, 0, 989 }, ++{ 0x8, 209, 0, 1712 }, ++{ 0x4, 209, 0, 1713 }, ++{ 0x2, 209, 0, 1714 }, ++{ 0x1, 209, 1, 1716 }, ++{ 0x1, 210, 1, 1715 }, ++{ 0x1, 330, 0, 990 }, ++{ 0x8, 212, 0, 1717 }, ++{ 0x4, 212, 0, 1718 }, ++{ 0x2, 212, 0, 1719 }, ++{ 0x1, 212, 1, 1721 }, ++{ 0x1, 213, 1, 1720 }, ++{ 0x1, 329, 0, 991 }, ++{ 0x8, 224, 0, 1722 }, ++{ 0x4, 224, 0, 1723 }, ++{ 0x2, 224, 0, 1724 }, ++{ 0x1, 224, 1, 1726 }, ++{ 0x1, 225, 0, 1725 }, ++{ 0x8, 222, 0, 1727 }, ++{ 0x4, 222, 0, 1728 }, ++{ 0x2, 222, 0, 1729 }, ++{ 0x1, 222, 1, 1731 }, ++{ 0x1, 223, 0, 1730 }, ++{ 0x1, 240, 0, 1732 }, ++{ 0x1, 340, 0, 1733 }, ++{ 0x1, 33, 0, 1734 }, ++{ 0x8, 151, 0, 1735 }, ++{ 0x4, 151, 0, 1736 }, ++{ 0x2, 151, 0, 1737 }, ++{ 0x1, 151, 1, 1739 }, ++{ 0x1, 152, 0, 1738 }, ++{ 0x8, 157, 0, 1740 }, ++{ 0x4, 157, 0, 1741 }, ++{ 0x2, 157, 0, 1742 }, ++{ 0x1, 157, 1, 1744 }, ++{ 0x1, 158, 0, 1743 }, ++{ 0x8, 231, 0, 1745 }, ++{ 0x4, 231, 0, 1746 }, ++{ 0x2, 231, 0, 1747 }, ++{ 0x1, 231, 1, 1749 }, ++{ 0x1, 232, 0, 1748 }, ++{ 0x1, 173, 0, 1750 }, ++{ 0x442, 171, 0, 1751 }, ++{ 0x242, 171, 0, 1752 }, ++{ 0x142, 171, 0, 1753 }, ++{ 0xc2, 171, 1, 1755 }, ++{ 0x6, 172, 0, 1754 }, ++{ 0x22, 171, 0, 1761 }, ++{ 0x12, 171, 0, 1762 }, ++{ 0xa, 171, 0, 1763 }, ++{ 0x6, 171, 1, 1765 }, ++{ 0x2, 172, 1, 1764 }, ++{ 0x1, 135, 0, 1165 }, ++{ 0x221, 171, 0, 1756 }, ++{ 0x121, 171, 0, 1757 }, ++{ 0xa1, 171, 0, 1758 }, ++{ 0x61, 171, 1, 1760 }, ++{ 0x3, 172, 0, 1759 }, ++{ 0x11, 171, 0, 1766 }, ++{ 0x9, 171, 0, 1767 }, ++{ 0x5, 171, 0, 1768 }, ++{ 0x3, 171, 1, 1770 }, ++{ 0x1, 172, 1, 1769 }, ++{ 0x1, 134, 0, 1166 }, ++{ 0x1, 237, 0, 1771 }, ++{ 0x1, 195, 0, 1772 }, ++{ 0x1, 149, 0, 1773 }, ++{ 0x1, 148, 0, 1774 }, ++{ 0x4, 234, 0, 1775 }, ++{ 0x2, 234, 0, 1776 }, ++{ 0x1, 234, 0, 1777 }, ++{ 0x1, 197, 0, 1778 }, ++{ 0x2, 235, 0, 1779 }, ++{ 0x1, 235, 0, 1780 }, ++{ 0x4, 185, 0, 1781 }, ++{ 0x2, 185, 0, 1782 }, ++{ 0x1, 185, 0, 1783 }, ++{ 0x4, 182, 0, 1784 }, ++{ 0x1, 190, 0, 1787 }, ++{ 0x1, 189, 1, 1788 }, ++{ 0x2, 182, 0, 1785 }, ++{ 0x1, 142, 0, 1789 }, ++{ 0x1, 297, 1, 1790 }, ++{ 0x1, 182, 0, 1786 }, ++{ 0x8, 144, 0, 1791 }, ++{ 0x4, 144, 0, 1792 }, ++{ 0x2, 144, 0, 1793 }, ++{ 0x1, 144, 1, 1795 }, ++{ 0x1, 145, 0, 1794 }, ++{ 0x8, 146, 0, 1796 }, ++{ 0x4, 146, 0, 1797 }, ++{ 0x2, 146, 0, 1798 }, ++{ 0x1, 146, 1, 1800 }, ++{ 0x1, 147, 1, 1799 }, ++{ 0x1, 426, 0, 1167 }, ++{ 0x8, 180, 0, 1801 }, ++{ 0x4, 180, 0, 1802 }, ++{ 0x2, 180, 0, 1803 }, ++{ 0x1, 180, 1, 1805 }, ++{ 0x1, 181, 1, 1804 }, ++{ 0x1, 425, 0, 1168 }, ++{ 0x8, 183, 0, 1806 }, ++{ 0x4, 183, 0, 1807 }, ++{ 0x2, 183, 0, 1808 }, ++{ 0x1, 183, 1, 1810 }, ++{ 0x1, 184, 1, 1809 }, ++{ 0x1, 424, 0, 1169 }, ++{ 0x8, 228, 0, 1811 }, ++{ 0x4, 228, 0, 1812 }, ++{ 0x2, 228, 0, 1813 }, ++{ 0x1, 228, 1, 1815 }, ++{ 0x1, 229, 0, 1814 }, ++{ 0x8, 226, 0, 1816 }, ++{ 0x4, 226, 0, 1817 }, ++{ 0x2, 226, 0, 1818 }, ++{ 0x1, 226, 1, 1820 }, ++{ 0x1, 227, 0, 1819 }, ++{ 0x8, 44, 0, 1825 }, ++{ 0x18, 44, 0, 1821 }, ++{ 0x4, 44, 0, 1826 }, ++{ 0xc, 44, 0, 1822 }, ++{ 0x2, 44, 0, 1827 }, ++{ 0x6, 44, 0, 1823 }, ++{ 0x1, 44, 0, 1828 }, ++{ 0x3, 44, 0, 1824 }, ++{ 0x51, 30, 0, 1830 }, ++{ 0xd1, 30, 0, 1829 }, ++{ 0x31, 30, 1, 1840 }, ++{ 0x11, 31, 0, 1839 }, ++{ 0x71, 30, 1, 1838 }, ++{ 0x31, 31, 0, 1837 }, ++{ 0x29, 30, 0, 1832 }, ++{ 0x69, 30, 0, 1831 }, ++{ 0x19, 30, 1, 1844 }, ++{ 0x9, 31, 0, 1843 }, ++{ 0x39, 30, 1, 1842 }, ++{ 0x19, 31, 0, 1841 }, ++{ 0x15, 30, 0, 1834 }, ++{ 0x35, 30, 0, 1833 }, ++{ 0xd, 30, 1, 1848 }, ++{ 0x5, 31, 0, 1847 }, ++{ 0x1d, 30, 1, 1846 }, ++{ 0xd, 31, 0, 1845 }, ++{ 0xb, 30, 0, 1836 }, ++{ 0x1b, 30, 0, 1835 }, ++{ 0x7, 30, 1, 1852 }, ++{ 0x3, 31, 0, 1851 }, ++{ 0xf, 30, 1, 1850 }, ++{ 0x7, 31, 0, 1849 }, ++{ 0xa2, 28, 0, 1854 }, ++{ 0x1a2, 28, 0, 1853 }, ++{ 0x62, 28, 1, 1864 }, ++{ 0x22, 29, 0, 1863 }, ++{ 0xe2, 28, 1, 1862 }, ++{ 0x62, 29, 0, 1861 }, ++{ 0x52, 28, 0, 1856 }, ++{ 0xd2, 28, 0, 1855 }, ++{ 0x32, 28, 1, 1868 }, ++{ 0x12, 29, 0, 1867 }, ++{ 0x72, 28, 1, 1866 }, ++{ 0x32, 29, 0, 1865 }, ++{ 0x2a, 28, 0, 1858 }, ++{ 0x6a, 28, 0, 1857 }, ++{ 0x1a, 28, 1, 1872 }, ++{ 0xa, 29, 0, 1871 }, ++{ 0x3a, 28, 1, 1870 }, ++{ 0x1a, 29, 0, 1869 }, ++{ 0x16, 28, 0, 1860 }, ++{ 0x36, 28, 0, 1859 }, ++{ 0xe, 28, 1, 1876 }, ++{ 0x6, 29, 0, 1875 }, ++{ 0x1e, 28, 1, 1874 }, ++{ 0xe, 29, 0, 1873 }, ++{ 0x51, 28, 0, 1878 }, ++{ 0xd1, 28, 0, 1877 }, ++{ 0x31, 28, 1, 1888 }, ++{ 0x11, 29, 0, 1887 }, ++{ 0x71, 28, 1, 1886 }, ++{ 0x31, 29, 0, 1885 }, ++{ 0x29, 28, 0, 1880 }, ++{ 0x69, 28, 0, 1879 }, ++{ 0x19, 28, 1, 1892 }, ++{ 0x9, 29, 0, 1891 }, ++{ 0x39, 28, 1, 1890 }, ++{ 0x19, 29, 0, 1889 }, ++{ 0x15, 28, 0, 1882 }, ++{ 0x35, 28, 0, 1881 }, ++{ 0xd, 28, 1, 1896 }, ++{ 0x5, 29, 0, 1895 }, ++{ 0x1d, 28, 1, 1894 }, ++{ 0xd, 29, 0, 1893 }, ++{ 0xb, 28, 0, 1884 }, ++{ 0x1b, 28, 0, 1883 }, ++{ 0x7, 28, 1, 1900 }, ++{ 0x3, 29, 0, 1899 }, ++{ 0xf, 28, 1, 1898 }, ++{ 0x7, 29, 0, 1897 }, ++{ 0x51, 26, 0, 1902 }, ++{ 0xd1, 26, 0, 1901 }, ++{ 0x31, 26, 1, 1912 }, ++{ 0x11, 27, 0, 1911 }, ++{ 0x71, 26, 1, 1910 }, ++{ 0x31, 27, 0, 1909 }, ++{ 0x29, 26, 0, 1904 }, ++{ 0x69, 26, 0, 1903 }, ++{ 0x19, 26, 1, 1916 }, ++{ 0x9, 27, 0, 1915 }, ++{ 0x39, 26, 1, 1914 }, ++{ 0x19, 27, 0, 1913 }, ++{ 0x15, 26, 0, 1906 }, ++{ 0x35, 26, 0, 1905 }, ++{ 0xd, 26, 1, 1920 }, ++{ 0x5, 27, 0, 1919 }, ++{ 0x1d, 26, 1, 1918 }, ++{ 0xd, 27, 0, 1917 }, ++{ 0xb, 26, 0, 1908 }, ++{ 0x1b, 26, 0, 1907 }, ++{ 0x7, 26, 1, 1924 }, ++{ 0x3, 27, 0, 1923 }, ++{ 0xf, 26, 1, 1922 }, ++{ 0x7, 27, 0, 1921 }, ++{ 0xa2, 24, 0, 1926 }, ++{ 0x1a2, 24, 0, 1925 }, ++{ 0x62, 24, 1, 1936 }, ++{ 0x22, 25, 0, 1935 }, ++{ 0xe2, 24, 1, 1934 }, ++{ 0x62, 25, 0, 1933 }, ++{ 0x52, 24, 0, 1928 }, ++{ 0xd2, 24, 0, 1927 }, ++{ 0x32, 24, 1, 1940 }, ++{ 0x12, 25, 0, 1939 }, ++{ 0x72, 24, 1, 1938 }, ++{ 0x32, 25, 0, 1937 }, ++{ 0x2a, 24, 0, 1930 }, ++{ 0x6a, 24, 0, 1929 }, ++{ 0x1a, 24, 1, 1944 }, ++{ 0xa, 25, 0, 1943 }, ++{ 0x3a, 24, 1, 1942 }, ++{ 0x1a, 25, 0, 1941 }, ++{ 0x16, 24, 0, 1932 }, ++{ 0x36, 24, 0, 1931 }, ++{ 0xe, 24, 1, 1948 }, ++{ 0x6, 25, 0, 1947 }, ++{ 0x1e, 24, 1, 1946 }, ++{ 0xe, 25, 0, 1945 }, ++{ 0x51, 24, 0, 1950 }, ++{ 0xd1, 24, 0, 1949 }, ++{ 0x31, 24, 1, 1960 }, ++{ 0x11, 25, 0, 1959 }, ++{ 0x71, 24, 1, 1958 }, ++{ 0x31, 25, 0, 1957 }, ++{ 0x29, 24, 0, 1952 }, ++{ 0x69, 24, 0, 1951 }, ++{ 0x19, 24, 1, 1964 }, ++{ 0x9, 25, 0, 1963 }, ++{ 0x39, 24, 1, 1962 }, ++{ 0x19, 25, 0, 1961 }, ++{ 0x15, 24, 0, 1954 }, ++{ 0x35, 24, 0, 1953 }, ++{ 0xd, 24, 1, 1968 }, ++{ 0x5, 25, 0, 1967 }, ++{ 0x1d, 24, 1, 1966 }, ++{ 0xd, 25, 0, 1965 }, ++{ 0xb, 24, 0, 1956 }, ++{ 0x1b, 24, 0, 1955 }, ++{ 0x7, 24, 1, 1972 }, ++{ 0x3, 25, 0, 1971 }, ++{ 0xf, 24, 1, 1970 }, ++{ 0x7, 25, 0, 1969 }, ++{ 0x51, 22, 1, 1998 }, ++{ 0x50, 22, 0, 1974 }, ++{ 0xd1, 22, 1, 1997 }, ++{ 0xd0, 22, 0, 1973 }, ++{ 0x31, 22, 1, 2008 }, ++{ 0x30, 22, 1, 1984 }, ++{ 0x11, 23, 1, 2007 }, ++{ 0x10, 23, 0, 1983 }, ++{ 0x71, 22, 1, 2006 }, ++{ 0x70, 22, 1, 1982 }, ++{ 0x31, 23, 1, 2005 }, ++{ 0x30, 23, 0, 1981 }, ++{ 0x29, 22, 1, 2000 }, ++{ 0x28, 22, 0, 1976 }, ++{ 0x69, 22, 1, 1999 }, ++{ 0x68, 22, 0, 1975 }, ++{ 0x19, 22, 1, 2012 }, ++{ 0x18, 22, 1, 1988 }, ++{ 0x9, 23, 1, 2011 }, ++{ 0x8, 23, 0, 1987 }, ++{ 0x39, 22, 1, 2010 }, ++{ 0x38, 22, 1, 1986 }, ++{ 0x19, 23, 1, 2009 }, ++{ 0x18, 23, 0, 1985 }, ++{ 0x15, 22, 1, 2002 }, ++{ 0x14, 22, 0, 1978 }, ++{ 0x35, 22, 1, 2001 }, ++{ 0x34, 22, 0, 1977 }, ++{ 0xd, 22, 1, 2016 }, ++{ 0xc, 22, 1, 1992 }, ++{ 0x5, 23, 1, 2015 }, ++{ 0x4, 23, 0, 1991 }, ++{ 0x1d, 22, 1, 2014 }, ++{ 0x1c, 22, 1, 1990 }, ++{ 0xd, 23, 1, 2013 }, ++{ 0xc, 23, 0, 1989 }, ++{ 0xb, 22, 1, 2004 }, ++{ 0xa, 22, 0, 1980 }, ++{ 0x1b, 22, 1, 2003 }, ++{ 0x1a, 22, 0, 1979 }, ++{ 0x7, 22, 1, 2020 }, ++{ 0x6, 22, 1, 1996 }, ++{ 0x3, 23, 1, 2019 }, ++{ 0x2, 23, 0, 1995 }, ++{ 0xf, 22, 1, 2018 }, ++{ 0xe, 22, 1, 1994 }, ++{ 0x7, 23, 1, 2017 }, ++{ 0x6, 23, 0, 1993 }, ++{ 0x8, 21, 0, 2022 }, ++{ 0x18, 21, 0, 2021 }, ++{ 0x1, 21, 1, 2026 }, ++{ 0x2, 21, 0, 2025 }, ++{ 0x3, 21, 1, 2024 }, ++{ 0x4, 21, 0, 2023 }, ++{ 0x1, 239, 0, 2027 }, ++{ 0x1, 339, 0, 2028 }, ++{ 0x14, 43, 0, 2031 }, ++{ 0x34, 43, 0, 2029 }, ++{ 0xc, 43, 0, 2032 }, ++{ 0x1c, 43, 0, 2030 }, ++{ 0x2, 43, 0, 2035 }, ++{ 0x6, 43, 0, 2033 }, ++{ 0x1, 43, 0, 2036 }, ++{ 0x3, 43, 0, 2034 }, ++{ 0x51, 19, 0, 2038 }, ++{ 0xd1, 19, 0, 2037 }, ++{ 0x31, 19, 1, 2048 }, ++{ 0x11, 20, 0, 2047 }, ++{ 0x71, 19, 1, 2046 }, ++{ 0x31, 20, 0, 2045 }, ++{ 0x29, 19, 0, 2040 }, ++{ 0x69, 19, 0, 2039 }, ++{ 0x19, 19, 1, 2052 }, ++{ 0x9, 20, 0, 2051 }, ++{ 0x39, 19, 1, 2050 }, ++{ 0x19, 20, 0, 2049 }, ++{ 0x15, 19, 0, 2042 }, ++{ 0x35, 19, 0, 2041 }, ++{ 0xd, 19, 1, 2056 }, ++{ 0x5, 20, 0, 2055 }, ++{ 0x1d, 19, 1, 2054 }, ++{ 0xd, 20, 0, 2053 }, ++{ 0xb, 19, 0, 2044 }, ++{ 0x1b, 19, 0, 2043 }, ++{ 0x7, 19, 1, 2060 }, ++{ 0x3, 20, 0, 2059 }, ++{ 0xf, 19, 1, 2058 }, ++{ 0x7, 20, 0, 2057 }, ++{ 0x1, 32, 0, 2061 }, ++{ 0x1, 140, 0, 2062 }, ++{ 0x2, 45, 0, 2063 }, ++{ 0x1, 45, 0, 2064 }, ++{ 0x1, 387, 0, 2065 }, ++{ 0x2, 52, 0, 2066 }, ++{ 0x1, 52, 0, 2067 }, ++{ 0x1, 133, 0, 2068 }, ++{ 0x51, 17, 0, 2070 }, ++{ 0xd1, 17, 0, 2069 }, ++{ 0x31, 17, 1, 2080 }, ++{ 0x11, 18, 0, 2079 }, ++{ 0x71, 17, 1, 2078 }, ++{ 0x31, 18, 0, 2077 }, ++{ 0x29, 17, 0, 2072 }, ++{ 0x69, 17, 0, 2071 }, ++{ 0x19, 17, 1, 2084 }, ++{ 0x9, 18, 0, 2083 }, ++{ 0x39, 17, 1, 2082 }, ++{ 0x19, 18, 0, 2081 }, ++{ 0x15, 17, 0, 2074 }, ++{ 0x35, 17, 0, 2073 }, ++{ 0xd, 17, 1, 2088 }, ++{ 0x5, 18, 0, 2087 }, ++{ 0x1d, 17, 1, 2086 }, ++{ 0xd, 18, 0, 2085 }, ++{ 0xb, 17, 0, 2076 }, ++{ 0x1b, 17, 0, 2075 }, ++{ 0x7, 17, 1, 2092 }, ++{ 0x3, 18, 0, 2091 }, ++{ 0xf, 17, 1, 2090 }, ++{ 0x7, 18, 0, 2089 }, ++{ 0xa20, 15, 0, 2094 }, ++{ 0x1a20, 15, 0, 2093 }, ++{ 0x620, 15, 1, 2104 }, ++{ 0x220, 16, 0, 2103 }, ++{ 0xe20, 15, 1, 2102 }, ++{ 0x620, 16, 0, 2101 }, ++{ 0x520, 15, 0, 2096 }, ++{ 0xd20, 15, 0, 2095 }, ++{ 0x320, 15, 1, 2108 }, ++{ 0x120, 16, 0, 2107 }, ++{ 0x720, 15, 1, 2106 }, ++{ 0x320, 16, 0, 2105 }, ++{ 0x2a0, 15, 0, 2098 }, ++{ 0x6a0, 15, 0, 2097 }, ++{ 0x1a0, 15, 1, 2112 }, ++{ 0xa0, 16, 0, 2111 }, ++{ 0x3a0, 15, 1, 2110 }, ++{ 0x1a0, 16, 0, 2109 }, ++{ 0x160, 15, 0, 2100 }, ++{ 0x360, 15, 0, 2099 }, ++{ 0xe0, 15, 1, 2116 }, ++{ 0x60, 16, 0, 2115 }, ++{ 0x1e0, 15, 1, 2114 }, ++{ 0xe0, 16, 0, 2113 }, ++{ 0x51, 15, 1, 2142 }, ++{ 0x50, 15, 0, 2118 }, ++{ 0xd1, 15, 1, 2141 }, ++{ 0xd0, 15, 0, 2117 }, ++{ 0x31, 15, 1, 2152 }, ++{ 0x30, 15, 1, 2128 }, ++{ 0x11, 16, 1, 2151 }, ++{ 0x10, 16, 0, 2127 }, ++{ 0x71, 15, 1, 2150 }, ++{ 0x70, 15, 1, 2126 }, ++{ 0x31, 16, 1, 2149 }, ++{ 0x30, 16, 0, 2125 }, ++{ 0x29, 15, 1, 2144 }, ++{ 0x28, 15, 0, 2120 }, ++{ 0x69, 15, 1, 2143 }, ++{ 0x68, 15, 0, 2119 }, ++{ 0x19, 15, 1, 2156 }, ++{ 0x18, 15, 1, 2132 }, ++{ 0x9, 16, 1, 2155 }, ++{ 0x8, 16, 0, 2131 }, ++{ 0x39, 15, 1, 2154 }, ++{ 0x38, 15, 1, 2130 }, ++{ 0x19, 16, 1, 2153 }, ++{ 0x18, 16, 0, 2129 }, ++{ 0x15, 15, 1, 2146 }, ++{ 0x14, 15, 0, 2122 }, ++{ 0x35, 15, 1, 2145 }, ++{ 0x34, 15, 0, 2121 }, ++{ 0xd, 15, 1, 2160 }, ++{ 0xc, 15, 1, 2136 }, ++{ 0x5, 16, 1, 2159 }, ++{ 0x4, 16, 0, 2135 }, ++{ 0x1d, 15, 1, 2158 }, ++{ 0x1c, 15, 1, 2134 }, ++{ 0xd, 16, 1, 2157 }, ++{ 0xc, 16, 0, 2133 }, ++{ 0xb, 15, 1, 2148 }, ++{ 0xa, 15, 0, 2124 }, ++{ 0x1b, 15, 1, 2147 }, ++{ 0x1a, 15, 0, 2123 }, ++{ 0x7, 15, 1, 2164 }, ++{ 0x6, 15, 1, 2140 }, ++{ 0x3, 16, 1, 2163 }, ++{ 0x2, 16, 0, 2139 }, ++{ 0xf, 15, 1, 2162 }, ++{ 0xe, 15, 1, 2138 }, ++{ 0x7, 16, 1, 2161 }, ++{ 0x6, 16, 0, 2137 }, ++{ 0x8, 14, 0, 2166 }, ++{ 0x18, 14, 0, 2165 }, ++{ 0x1, 14, 1, 2170 }, ++{ 0x2, 14, 0, 2169 }, ++{ 0x3, 14, 1, 2168 }, ++{ 0x4, 14, 0, 2167 }, ++{ 0x1, 109, 1, 2322 }, ++{ 0x1, 110, 1, 2321 }, ++{ 0x1, 111, 1, 2320 }, ++{ 0x1, 112, 1, 2319 }, ++{ 0x1, 113, 1, 2318 }, ++{ 0x1, 114, 1, 2317 }, ++{ 0x1, 115, 1, 2316 }, ++{ 0x1, 116, 1, 2315 }, ++{ 0x39, 41, 1, 22 }, ++{ 0x19, 42, 0, 21 }, ++{ 0x3, 109, 1, 2314 }, ++{ 0x3, 110, 1, 2313 }, ++{ 0x3, 111, 1, 2312 }, ++{ 0x3, 112, 1, 2311 }, ++{ 0x3, 113, 1, 2310 }, ++{ 0x3, 114, 1, 2309 }, ++{ 0x3, 115, 1, 2308 }, ++{ 0x3, 116, 1, 2307 }, ++{ 0x69, 41, 0, 11 }, ++{ 0x14, 100, 1, 2302 }, ++{ 0x22, 101, 1, 2299 }, ++{ 0x44, 101, 1, 2301 }, ++{ 0xa, 108, 1, 2300 }, ++{ 0xd1, 41, 0, 9 }, ++{ 0x34, 100, 1, 2174 }, ++{ 0xc4, 101, 1, 2173 }, ++{ 0x1c, 107, 1, 2171 }, ++{ 0xe, 122, 0, 2172 }, ++{ 0xc, 100, 1, 2462 }, ++{ 0xa, 101, 1, 2459 }, ++{ 0x14, 101, 1, 2461 }, ++{ 0x6, 108, 0, 2460 }, ++{ 0x2, 100, 1, 2186 }, ++{ 0x2, 101, 1, 2185 }, ++{ 0x2, 106, 1, 2184 }, ++{ 0x2, 107, 0, 2183 }, ++{ 0x12, 100, 1, 2182 }, ++{ 0x42, 101, 1, 2181 }, ++{ 0x6, 106, 1, 2180 }, ++{ 0x6, 107, 0, 2179 }, ++{ 0xa, 100, 1, 2306 }, ++{ 0x12, 101, 1, 2305 }, ++{ 0x24, 101, 1, 2303 }, ++{ 0x5, 108, 1, 2304 }, ++{ 0x71, 41, 1, 18 }, ++{ 0x31, 42, 0, 17 }, ++{ 0x1a, 100, 1, 2178 }, ++{ 0x32, 101, 1, 2177 }, ++{ 0x1a, 107, 1, 2175 }, ++{ 0x7, 122, 0, 2176 }, ++{ 0x6, 100, 1, 2466 }, ++{ 0x6, 101, 1, 2465 }, ++{ 0xc, 101, 1, 2463 }, ++{ 0x3, 108, 0, 2464 }, ++{ 0x1, 100, 1, 2482 }, ++{ 0x1, 101, 1, 2481 }, ++{ 0x1, 102, 1, 2480 }, ++{ 0x1, 103, 1, 2479 }, ++{ 0x1, 104, 1, 2478 }, ++{ 0x1, 105, 1, 2477 }, ++{ 0x1, 106, 1, 2476 }, ++{ 0x1, 107, 0, 2475 }, ++{ 0x3, 100, 1, 2474 }, ++{ 0x3, 101, 1, 2473 }, ++{ 0x3, 102, 1, 2472 }, ++{ 0x3, 103, 1, 2471 }, ++{ 0x3, 104, 1, 2470 }, ++{ 0x3, 105, 1, 2469 }, ++{ 0x3, 106, 1, 2468 }, ++{ 0x3, 107, 0, 2467 }, ++{ 0x8, 67, 1, 2346 }, ++{ 0x8, 68, 1, 2345 }, ++{ 0x2, 73, 1, 2340 }, ++{ 0x2, 74, 1, 2339 }, ++{ 0x1, 76, 1, 2344 }, ++{ 0x1, 77, 1, 2343 }, ++{ 0x1, 78, 1, 2342 }, ++{ 0x1, 79, 1, 2341 }, ++{ 0xf, 41, 1, 30 }, ++{ 0x7, 42, 0, 29 }, ++{ 0x18, 67, 1, 2338 }, ++{ 0x18, 68, 1, 2337 }, ++{ 0x6, 73, 1, 2332 }, ++{ 0x6, 74, 1, 2331 }, ++{ 0x3, 76, 1, 2336 }, ++{ 0x3, 77, 1, 2335 }, ++{ 0x3, 78, 1, 2334 }, ++{ 0x3, 79, 1, 2333 }, ++{ 0x1b, 41, 0, 15 }, ++{ 0x14, 67, 1, 2326 }, ++{ 0x22, 68, 1, 2323 }, ++{ 0x44, 68, 1, 2325 }, ++{ 0xa, 75, 1, 2324 }, ++{ 0x35, 41, 0, 13 }, ++{ 0x34, 67, 1, 2190 }, ++{ 0xc4, 68, 1, 2189 }, ++{ 0x38, 74, 1, 2187 }, ++{ 0xe, 85, 0, 2188 }, ++{ 0xc, 67, 1, 2486 }, ++{ 0xa, 68, 1, 2483 }, ++{ 0x14, 68, 1, 2485 }, ++{ 0x6, 75, 0, 2484 }, ++{ 0x2, 67, 1, 2202 }, ++{ 0x2, 68, 1, 2201 }, ++{ 0x4, 73, 1, 2200 }, ++{ 0x4, 74, 0, 2199 }, ++{ 0x12, 67, 1, 2198 }, ++{ 0x42, 68, 1, 2197 }, ++{ 0xc, 73, 1, 2196 }, ++{ 0xc, 74, 0, 2195 }, ++{ 0xa, 67, 1, 2330 }, ++{ 0x12, 68, 1, 2329 }, ++{ 0x24, 68, 1, 2327 }, ++{ 0x5, 75, 1, 2328 }, ++{ 0x1d, 41, 1, 26 }, ++{ 0xd, 42, 0, 25 }, ++{ 0x1a, 67, 1, 2194 }, ++{ 0x32, 68, 1, 2193 }, ++{ 0x34, 74, 1, 2191 }, ++{ 0x7, 85, 0, 2192 }, ++{ 0x6, 67, 1, 2490 }, ++{ 0x6, 68, 1, 2489 }, ++{ 0xc, 68, 1, 2487 }, ++{ 0x3, 75, 0, 2488 }, ++{ 0x1, 67, 1, 2506 }, ++{ 0x1, 68, 1, 2505 }, ++{ 0x1, 69, 1, 2504 }, ++{ 0x1, 70, 1, 2503 }, ++{ 0x1, 71, 1, 2502 }, ++{ 0x1, 72, 1, 2501 }, ++{ 0x1, 73, 1, 2500 }, ++{ 0x1, 74, 0, 2499 }, ++{ 0x3, 67, 1, 2498 }, ++{ 0x3, 68, 1, 2497 }, ++{ 0x3, 69, 1, 2496 }, ++{ 0x3, 70, 1, 2495 }, ++{ 0x3, 71, 1, 2494 }, ++{ 0x3, 72, 1, 2493 }, ++{ 0x3, 73, 1, 2492 }, ++{ 0x3, 74, 0, 2491 }, ++{ 0x28, 95, 1, 2354 }, ++{ 0x44, 96, 1, 2349 }, ++{ 0x88, 96, 1, 2353 }, ++{ 0x44, 97, 1, 2348 }, ++{ 0x88, 97, 1, 2352 }, ++{ 0x44, 98, 1, 2347 }, ++{ 0x88, 98, 1, 2351 }, ++{ 0x28, 99, 0, 2350 }, ++{ 0x68, 95, 1, 2210 }, ++{ 0x188, 96, 1, 2209 }, ++{ 0x188, 97, 1, 2208 }, ++{ 0x188, 98, 1, 2207 }, ++{ 0x38, 118, 1, 2206 }, ++{ 0x38, 119, 1, 2205 }, ++{ 0x38, 120, 1, 2204 }, ++{ 0x38, 121, 0, 2203 }, ++{ 0x18, 95, 1, 2514 }, ++{ 0x14, 96, 1, 2509 }, ++{ 0x28, 96, 1, 2513 }, ++{ 0x14, 97, 1, 2508 }, ++{ 0x28, 97, 1, 2512 }, ++{ 0x14, 98, 1, 2507 }, ++{ 0x28, 98, 1, 2511 }, ++{ 0x18, 99, 0, 2510 }, ++{ 0x14, 95, 1, 2362 }, ++{ 0x24, 96, 1, 2361 }, ++{ 0x48, 96, 1, 2357 }, ++{ 0x24, 97, 1, 2360 }, ++{ 0x48, 97, 1, 2356 }, ++{ 0x24, 98, 1, 2359 }, ++{ 0x48, 98, 1, 2355 }, ++{ 0x14, 99, 0, 2358 }, ++{ 0x34, 95, 1, 2218 }, ++{ 0x64, 96, 1, 2217 }, ++{ 0x64, 97, 1, 2216 }, ++{ 0x64, 98, 1, 2215 }, ++{ 0x1c, 118, 1, 2214 }, ++{ 0x1c, 119, 1, 2213 }, ++{ 0x1c, 120, 1, 2212 }, ++{ 0x1c, 121, 0, 2211 }, ++{ 0xc, 95, 1, 2522 }, ++{ 0xc, 96, 1, 2521 }, ++{ 0x18, 96, 1, 2517 }, ++{ 0xc, 97, 1, 2520 }, ++{ 0x18, 97, 1, 2516 }, ++{ 0xc, 98, 1, 2519 }, ++{ 0x18, 98, 1, 2515 }, ++{ 0xc, 99, 0, 2518 }, ++{ 0xa, 95, 1, 2370 }, ++{ 0x11, 96, 1, 2365 }, ++{ 0x22, 96, 1, 2369 }, ++{ 0x11, 97, 1, 2364 }, ++{ 0x22, 97, 1, 2368 }, ++{ 0x11, 98, 1, 2363 }, ++{ 0x22, 98, 1, 2367 }, ++{ 0xa, 99, 0, 2366 }, ++{ 0x1a, 95, 1, 2226 }, ++{ 0x62, 96, 1, 2225 }, ++{ 0x62, 97, 1, 2224 }, ++{ 0x62, 98, 1, 2223 }, ++{ 0xe, 118, 1, 2222 }, ++{ 0xe, 119, 1, 2221 }, ++{ 0xe, 120, 1, 2220 }, ++{ 0xe, 121, 0, 2219 }, ++{ 0x6, 95, 1, 2530 }, ++{ 0x5, 96, 1, 2525 }, ++{ 0xa, 96, 1, 2529 }, ++{ 0x5, 97, 1, 2524 }, ++{ 0xa, 97, 1, 2528 }, ++{ 0x5, 98, 1, 2523 }, ++{ 0xa, 98, 1, 2527 }, ++{ 0x6, 99, 0, 2526 }, ++{ 0x5, 95, 1, 2378 }, ++{ 0x9, 96, 1, 2377 }, ++{ 0x12, 96, 1, 2373 }, ++{ 0x9, 97, 1, 2376 }, ++{ 0x12, 97, 1, 2372 }, ++{ 0x9, 98, 1, 2375 }, ++{ 0x12, 98, 1, 2371 }, ++{ 0x5, 99, 0, 2374 }, ++{ 0xd, 95, 1, 2234 }, ++{ 0x19, 96, 1, 2233 }, ++{ 0x19, 97, 1, 2232 }, ++{ 0x19, 98, 1, 2231 }, ++{ 0x7, 118, 1, 2230 }, ++{ 0x7, 119, 1, 2229 }, ++{ 0x7, 120, 1, 2228 }, ++{ 0x7, 121, 0, 2227 }, ++{ 0x3, 95, 1, 2538 }, ++{ 0x3, 96, 1, 2537 }, ++{ 0x6, 96, 1, 2533 }, ++{ 0x3, 97, 1, 2536 }, ++{ 0x6, 97, 1, 2532 }, ++{ 0x3, 98, 1, 2535 }, ++{ 0x6, 98, 1, 2531 }, ++{ 0x3, 99, 0, 2534 }, ++{ 0x28, 62, 1, 2386 }, ++{ 0x44, 63, 1, 2381 }, ++{ 0x88, 63, 1, 2385 }, ++{ 0x44, 64, 1, 2380 }, ++{ 0x88, 64, 1, 2384 }, ++{ 0x44, 65, 1, 2379 }, ++{ 0x88, 65, 1, 2383 }, ++{ 0x28, 66, 0, 2382 }, ++{ 0x68, 62, 1, 2242 }, ++{ 0x188, 63, 1, 2241 }, ++{ 0x188, 64, 1, 2240 }, ++{ 0x188, 65, 1, 2239 }, ++{ 0x38, 81, 1, 2238 }, ++{ 0x38, 82, 1, 2237 }, ++{ 0x38, 83, 1, 2236 }, ++{ 0x38, 84, 0, 2235 }, ++{ 0x18, 62, 1, 2546 }, ++{ 0x14, 63, 1, 2541 }, ++{ 0x28, 63, 1, 2545 }, ++{ 0x14, 64, 1, 2540 }, ++{ 0x28, 64, 1, 2544 }, ++{ 0x14, 65, 1, 2539 }, ++{ 0x28, 65, 1, 2543 }, ++{ 0x18, 66, 0, 2542 }, ++{ 0x14, 62, 1, 2394 }, ++{ 0x24, 63, 1, 2393 }, ++{ 0x48, 63, 1, 2389 }, ++{ 0x24, 64, 1, 2392 }, ++{ 0x48, 64, 1, 2388 }, ++{ 0x24, 65, 1, 2391 }, ++{ 0x48, 65, 1, 2387 }, ++{ 0x14, 66, 0, 2390 }, ++{ 0x34, 62, 1, 2250 }, ++{ 0x64, 63, 1, 2249 }, ++{ 0x64, 64, 1, 2248 }, ++{ 0x64, 65, 1, 2247 }, ++{ 0x1c, 81, 1, 2246 }, ++{ 0x1c, 82, 1, 2245 }, ++{ 0x1c, 83, 1, 2244 }, ++{ 0x1c, 84, 0, 2243 }, ++{ 0xc, 62, 1, 2554 }, ++{ 0xc, 63, 1, 2553 }, ++{ 0x18, 63, 1, 2549 }, ++{ 0xc, 64, 1, 2552 }, ++{ 0x18, 64, 1, 2548 }, ++{ 0xc, 65, 1, 2551 }, ++{ 0x18, 65, 1, 2547 }, ++{ 0xc, 66, 0, 2550 }, ++{ 0xa, 62, 1, 2402 }, ++{ 0x11, 63, 1, 2397 }, ++{ 0x22, 63, 1, 2401 }, ++{ 0x11, 64, 1, 2396 }, ++{ 0x22, 64, 1, 2400 }, ++{ 0x11, 65, 1, 2395 }, ++{ 0x22, 65, 1, 2399 }, ++{ 0xa, 66, 0, 2398 }, ++{ 0x1a, 62, 1, 2258 }, ++{ 0x62, 63, 1, 2257 }, ++{ 0x62, 64, 1, 2256 }, ++{ 0x62, 65, 1, 2255 }, ++{ 0xe, 81, 1, 2254 }, ++{ 0xe, 82, 1, 2253 }, ++{ 0xe, 83, 1, 2252 }, ++{ 0xe, 84, 0, 2251 }, ++{ 0x6, 62, 1, 2562 }, ++{ 0x5, 63, 1, 2557 }, ++{ 0xa, 63, 1, 2561 }, ++{ 0x5, 64, 1, 2556 }, ++{ 0xa, 64, 1, 2560 }, ++{ 0x5, 65, 1, 2555 }, ++{ 0xa, 65, 1, 2559 }, ++{ 0x6, 66, 0, 2558 }, ++{ 0x5, 62, 1, 2410 }, ++{ 0x9, 63, 1, 2409 }, ++{ 0x12, 63, 1, 2405 }, ++{ 0x9, 64, 1, 2408 }, ++{ 0x12, 64, 1, 2404 }, ++{ 0x9, 65, 1, 2407 }, ++{ 0x12, 65, 1, 2403 }, ++{ 0x5, 66, 0, 2406 }, ++{ 0xd, 62, 1, 2266 }, ++{ 0x19, 63, 1, 2265 }, ++{ 0x19, 64, 1, 2264 }, ++{ 0x19, 65, 1, 2263 }, ++{ 0x7, 81, 1, 2262 }, ++{ 0x7, 82, 1, 2261 }, ++{ 0x7, 83, 1, 2260 }, ++{ 0x7, 84, 0, 2259 }, ++{ 0x3, 62, 1, 2570 }, ++{ 0x3, 63, 1, 2569 }, ++{ 0x6, 63, 1, 2565 }, ++{ 0x3, 64, 1, 2568 }, ++{ 0x6, 64, 1, 2564 }, ++{ 0x3, 65, 1, 2567 }, ++{ 0x6, 65, 1, 2563 }, ++{ 0x3, 66, 0, 2566 }, ++{ 0x8, 86, 1, 2434 }, ++{ 0x8, 87, 1, 2433 }, ++{ 0x2, 88, 1, 2432 }, ++{ 0x2, 89, 1, 2431 }, ++{ 0x2, 90, 1, 2430 }, ++{ 0x2, 91, 1, 2429 }, ++{ 0x2, 92, 1, 2428 }, ++{ 0x2, 93, 0, 2427 }, ++{ 0x18, 86, 1, 2426 }, ++{ 0x18, 87, 1, 2425 }, ++{ 0x6, 88, 1, 2424 }, ++{ 0x6, 89, 1, 2423 }, ++{ 0x6, 90, 1, 2422 }, ++{ 0x6, 91, 1, 2421 }, ++{ 0x6, 92, 1, 2420 }, ++{ 0x6, 93, 0, 2419 }, ++{ 0x14, 86, 1, 2414 }, ++{ 0x22, 87, 1, 2411 }, ++{ 0x44, 87, 1, 2413 }, ++{ 0xa, 94, 0, 2412 }, ++{ 0x34, 86, 1, 2270 }, ++{ 0xc4, 87, 1, 2269 }, ++{ 0x38, 93, 1, 2267 }, ++{ 0xe, 117, 0, 2268 }, ++{ 0xc, 86, 1, 2574 }, ++{ 0xa, 87, 1, 2571 }, ++{ 0x14, 87, 1, 2573 }, ++{ 0x6, 94, 0, 2572 }, ++{ 0x2, 86, 1, 2282 }, ++{ 0x2, 87, 1, 2281 }, ++{ 0x4, 92, 1, 2280 }, ++{ 0x4, 93, 0, 2279 }, ++{ 0x12, 86, 1, 2278 }, ++{ 0x42, 87, 1, 2277 }, ++{ 0xc, 92, 1, 2276 }, ++{ 0xc, 93, 0, 2275 }, ++{ 0xa, 86, 1, 2418 }, ++{ 0x12, 87, 1, 2417 }, ++{ 0x24, 87, 1, 2415 }, ++{ 0x5, 94, 0, 2416 }, ++{ 0x1a, 86, 1, 2274 }, ++{ 0x32, 87, 1, 2273 }, ++{ 0x34, 93, 1, 2271 }, ++{ 0x7, 117, 0, 2272 }, ++{ 0x6, 86, 1, 2578 }, ++{ 0x6, 87, 1, 2577 }, ++{ 0xc, 87, 1, 2575 }, ++{ 0x3, 94, 0, 2576 }, ++{ 0x1, 86, 1, 2594 }, ++{ 0x1, 87, 1, 2593 }, ++{ 0x1, 88, 1, 2592 }, ++{ 0x1, 89, 1, 2591 }, ++{ 0x1, 90, 1, 2590 }, ++{ 0x1, 91, 1, 2589 }, ++{ 0x1, 92, 1, 2588 }, ++{ 0x1, 93, 0, 2587 }, ++{ 0x3, 86, 1, 2586 }, ++{ 0x3, 87, 1, 2585 }, ++{ 0x3, 88, 1, 2584 }, ++{ 0x3, 89, 1, 2583 }, ++{ 0x3, 90, 1, 2582 }, ++{ 0x3, 91, 1, 2581 }, ++{ 0x3, 92, 1, 2580 }, ++{ 0x3, 93, 0, 2579 }, ++{ 0x8, 53, 1, 2458 }, ++{ 0x8, 54, 1, 2457 }, ++{ 0x2, 55, 1, 2456 }, ++{ 0x2, 56, 1, 2455 }, ++{ 0x2, 57, 1, 2454 }, ++{ 0x2, 58, 1, 2453 }, ++{ 0x2, 59, 1, 2452 }, ++{ 0x2, 60, 0, 2451 }, ++{ 0x18, 53, 1, 2450 }, ++{ 0x18, 54, 1, 2449 }, ++{ 0x6, 55, 1, 2448 }, ++{ 0x6, 56, 1, 2447 }, ++{ 0x6, 57, 1, 2446 }, ++{ 0x6, 58, 1, 2445 }, ++{ 0x6, 59, 1, 2444 }, ++{ 0x6, 60, 0, 2443 }, ++{ 0x14, 53, 1, 2438 }, ++{ 0x22, 54, 1, 2435 }, ++{ 0x44, 54, 1, 2437 }, ++{ 0xa, 61, 0, 2436 }, ++{ 0x34, 53, 1, 2286 }, ++{ 0xc4, 54, 1, 2285 }, ++{ 0x38, 60, 1, 2283 }, ++{ 0xe, 80, 0, 2284 }, ++{ 0xc, 53, 1, 2598 }, ++{ 0xa, 54, 1, 2595 }, ++{ 0x14, 54, 1, 2597 }, ++{ 0x6, 61, 0, 2596 }, ++{ 0x2, 53, 1, 2298 }, ++{ 0x2, 54, 1, 2297 }, ++{ 0x4, 59, 1, 2296 }, ++{ 0x4, 60, 0, 2295 }, ++{ 0x12, 53, 1, 2294 }, ++{ 0x42, 54, 1, 2293 }, ++{ 0xc, 59, 1, 2292 }, ++{ 0xc, 60, 0, 2291 }, ++{ 0xa, 53, 1, 2442 }, ++{ 0x12, 54, 1, 2441 }, ++{ 0x24, 54, 1, 2439 }, ++{ 0x5, 61, 0, 2440 }, ++{ 0x1a, 53, 1, 2290 }, ++{ 0x32, 54, 1, 2289 }, ++{ 0x34, 60, 1, 2287 }, ++{ 0x7, 80, 0, 2288 }, ++{ 0x6, 53, 1, 2602 }, ++{ 0x6, 54, 1, 2601 }, ++{ 0xc, 54, 1, 2599 }, ++{ 0x3, 61, 0, 2600 }, ++{ 0x1, 53, 1, 2618 }, ++{ 0x1, 54, 1, 2617 }, ++{ 0x1, 55, 1, 2616 }, ++{ 0x1, 56, 1, 2615 }, ++{ 0x1, 57, 1, 2614 }, ++{ 0x1, 58, 1, 2613 }, ++{ 0x1, 59, 1, 2612 }, ++{ 0x1, 60, 0, 2611 }, ++{ 0x3, 53, 1, 2610 }, ++{ 0x3, 54, 1, 2609 }, ++{ 0x3, 55, 1, 2608 }, ++{ 0x3, 56, 1, 2607 }, ++{ 0x3, 57, 1, 2606 }, ++{ 0x3, 58, 1, 2605 }, ++{ 0x3, 59, 1, 2604 }, ++{ 0x3, 60, 0, 2603 }, ++{ 0x1, 4, 0, 2619 }, ++{ 0x1, 296, 0, 2620 }, ++{ 0x1, 379, 0, 2621 }, ++{ 0x1, 374, 0, 2622 }, ++{ 0x2, 358, 0, 2623 }, ++{ 0x1, 358, 0, 2626 }, ++{ 0x2, 357, 0, 2624 }, ++{ 0x1, 357, 0, 2627 }, ++{ 0x2, 356, 0, 2625 }, ++{ 0x1, 356, 0, 2628 }, ++{ 0x1, 355, 0, 2629 }, ++{ 0x1, 354, 0, 2630 }, ++{ 0x2, 353, 0, 2631 }, ++{ 0x1, 353, 0, 2633 }, ++{ 0x2, 352, 0, 2632 }, ++{ 0x1, 352, 0, 2634 }, ++{ 0x1, 382, 0, 2641 }, ++{ 0x8, 381, 0, 2635 }, ++{ 0x4, 381, 0, 2637 }, ++{ 0x2, 381, 0, 2639 }, ++{ 0x1, 381, 0, 2642 }, ++{ 0x8, 380, 0, 2636 }, ++{ 0x4, 380, 0, 2638 }, ++{ 0x2, 380, 0, 2640 }, ++{ 0x1, 380, 0, 2643 }, ++{ 0x1, 351, 0, 2650 }, ++{ 0x8, 350, 0, 2644 }, ++{ 0x4, 350, 0, 2646 }, ++{ 0x2, 350, 0, 2648 }, ++{ 0x1, 350, 0, 2651 }, ++{ 0x8, 349, 0, 2645 }, ++{ 0x4, 349, 0, 2647 }, ++{ 0x2, 349, 1, 2649 }, ++{ 0x4, 143, 0, 1345 }, ++{ 0x1, 349, 0, 2652 }, ++{ 0x1, 6, 0, 2653 }, ++{ 0x1, 7, 0, 2654 }, ++{ 0x1, 295, 0, 2655 }, ++{ 0x1, 451, 0, 2656 }, ++{ 0x1, 346, 0, 2657 }, ++{ 0x1, 13, 0, 2658 }, ++{ 0x1, 11, 0, 2659 }, ++{ 0x1, 422, 0, 2660 }, ++{ 0x1, 394, 0, 2661 }, ++{ 0x1, 393, 0, 2662 }, ++{ 0x1, 450, 0, 2663 }, ++{ 0x1, 345, 0, 2664 }, ++{ 0x1, 12, 0, 2665 }, ++{ 0x1, 10, 0, 2666 }, ++{ 0x1, 5, 0, 2667 }, ++{ 0x1, 421, 0, 2668 }, ++{ 0x1, 420, 0, 2669 }, ++{ 0x1, 1, 0, 2670 }, ++{ 0x1, 0, 0, 2671 }, ++}; ++ +--- /dev/null ++++ b/arch/ia64/kdb/ia64-asmtab.h +@@ -0,0 +1,158 @@ ++/* ia64-asmtab.h -- Header for compacted IA-64 opcode tables. ++ Copyright 1999, 2000 Free Software Foundation, Inc. ++ Contributed by Bob Manson of Cygnus Support ++ ++ This file is part of GDB, GAS, and the GNU binutils. ++ ++ GDB, GAS, and the GNU binutils are free software; you can redistribute ++ them and/or modify them under the terms of the GNU General Public ++ License as published by the Free Software Foundation; either version ++ 2, or (at your option) any later version. ++ ++ GDB, GAS, and the GNU binutils are distributed in the hope that they ++ will be useful, but WITHOUT ANY WARRANTY; without even the implied ++ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ the GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this file; see the file COPYING. If not, write to the ++ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA ++ 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef IA64_ASMTAB_H ++#define IA64_ASMTAB_H ++ ++#ifdef __KERNEL__ ++#include "ia64.h" ++#else /* __KERNEL__ */ ++#include "opcode/ia64.h" ++#endif /* __KERNEL__ */ ++ ++/* The primary opcode table is made up of the following: */ ++struct ia64_main_table ++{ ++ /* The entry in the string table that corresponds to the name of this ++ opcode. */ ++ unsigned short name_index; ++ ++ /* The type of opcode; corresponds to the TYPE field in ++ struct ia64_opcode. */ ++ unsigned char opcode_type; ++ ++ /* The number of outputs for this opcode. */ ++ unsigned char num_outputs; ++ ++ /* The base insn value for this opcode. It may be modified by completers. */ ++ ia64_insn opcode; ++ ++ /* The mask of valid bits in OPCODE. Zeros indicate operand fields. */ ++ ia64_insn mask; ++ ++ /* The operands of this instruction. Corresponds to the OPERANDS field ++ in struct ia64_opcode. */ ++ unsigned char operands[5]; ++ ++ /* The flags for this instruction. Corresponds to the FLAGS field in ++ struct ia64_opcode. */ ++ short flags; ++ ++ /* The tree of completers for this instruction; this is an offset into ++ completer_table. */ ++ short completers; ++}; ++ ++/* Each instruction has a set of possible "completers", or additional ++ suffixes that can alter the instruction's behavior, and which has ++ potentially different dependencies. ++ ++ The completer entries modify certain bits in the instruction opcode. ++ Which bits are to be modified are marked by the BITS, MASK and ++ OFFSET fields. The completer entry may also note dependencies for the ++ opcode. ++ ++ These completers are arranged in a DAG; the pointers are indexes ++ into the completer_table array. The completer DAG is searched by ++ find_completer () and ia64_find_matching_opcode (). ++ ++ Note that each completer needs to be applied in turn, so that if we ++ have the instruction ++ cmp.lt.unc ++ the completer entries for both "lt" and "unc" would need to be applied ++ to the opcode's value. ++ ++ Some instructions do not require any completers; these contain an ++ empty completer entry. Instructions that require a completer do ++ not contain an empty entry. ++ ++ Terminal completers (those completers that validly complete an ++ instruction) are marked by having the TERMINAL_COMPLETER flag set. ++ ++ Only dependencies listed in the terminal completer for an opcode are ++ considered to apply to that opcode instance. */ ++ ++struct ia64_completer_table ++{ ++ /* The bit value that this completer sets. */ ++ unsigned int bits; ++ ++ /* And its mask. 1s are bits that are to be modified in the ++ instruction. */ ++ unsigned int mask; ++ ++ /* The entry in the string table that corresponds to the name of this ++ completer. */ ++ unsigned short name_index; ++ ++ /* An alternative completer, or -1 if this is the end of the chain. */ ++ short alternative; ++ ++ /* A pointer to the DAG of completers that can potentially follow ++ this one, or -1. */ ++ short subentries; ++ ++ /* The bit offset in the instruction where BITS and MASK should be ++ applied. */ ++ unsigned char offset : 7; ++ ++ unsigned char terminal_completer : 1; ++ ++ /* Index into the dependency list table */ ++ short dependencies; ++}; ++ ++/* This contains sufficient information for the disassembler to resolve ++ the complete name of the original instruction. */ ++struct ia64_dis_names ++{ ++ /* COMPLETER_INDEX represents the tree of completers that make up ++ the instruction. The LSB represents the top of the tree for the ++ specified instruction. ++ ++ A 0 bit indicates to go to the next alternate completer via the ++ alternative field; a 1 bit indicates that the current completer ++ is part of the instruction, and to go down the subentries index. ++ We know we've reached the final completer when we run out of 1 ++ bits. ++ ++ There is always at least one 1 bit. */ ++ unsigned int completer_index : 20; ++ ++ /* The index in the main_table[] array for the instruction. */ ++ unsigned short insn_index : 11; ++ ++ /* If set, the next entry in this table is an alternate possibility ++ for this instruction encoding. Which one to use is determined by ++ the instruction type and other factors (see opcode_verify ()). */ ++ unsigned int next_flag : 1; ++ ++ /* The disassembly priority of this entry among instructions. */ ++ unsigned short priority; ++}; ++ ++#endif +--- /dev/null ++++ b/arch/ia64/kdb/ia64-dis.c +@@ -0,0 +1,312 @@ ++/* ia64-dis.c -- Disassemble ia64 instructions ++ Copyright 1998, 1999, 2000, 2002 Free Software Foundation, Inc. ++ Contributed by David Mosberger-Tang ++ ++ This file is part of GDB, GAS, and the GNU binutils. ++ ++ GDB, GAS, and the GNU binutils are free software; you can redistribute ++ them and/or modify them under the terms of the GNU General Public ++ License as published by the Free Software Foundation; either version ++ 2, or (at your option) any later version. ++ ++ GDB, GAS, and the GNU binutils are distributed in the hope that they ++ will be useful, but WITHOUT ANY WARRANTY; without even the implied ++ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ the GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this file; see the file COPYING. If not, write to the ++ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA ++ 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include "ia64.h" ++ ++/* imported from bfd/libbfd.c for kernel */ ++bfd_uint64_t ++bfd_getl64 (const void *p ATTRIBUTE_UNUSED) ++{ ++#ifdef BFD_HOST_64_BIT ++ const bfd_byte *addr = p; ++ bfd_uint64_t v; ++ ++ v = addr[7]; v <<= 8; ++ v |= addr[6]; v <<= 8; ++ v |= addr[5]; v <<= 8; ++ v |= addr[4]; v <<= 8; ++ v |= addr[3]; v <<= 8; ++ v |= addr[2]; v <<= 8; ++ v |= addr[1]; v <<= 8; ++ v |= addr[0]; ++ ++ return v; ++#else ++ BFD_FAIL(); ++ return 0; ++#endif ++ ++} ++ ++#else /* __KERNEL__ */ ++#include ++#include ++ ++#include "dis-asm.h" ++#include "opcode/ia64.h" ++#endif /* __KERNEL__ */ ++ ++#define NELEMS(a) ((int) (sizeof (a) / sizeof (a[0]))) ++ ++/* Disassemble ia64 instruction. */ ++ ++/* Return the instruction type for OPCODE found in unit UNIT. */ ++ ++static enum ia64_insn_type ++unit_to_type (ia64_insn opcode, enum ia64_unit unit) ++{ ++ enum ia64_insn_type type; ++ int op; ++ ++ op = IA64_OP (opcode); ++ ++ if (op >= 8 && (unit == IA64_UNIT_I || unit == IA64_UNIT_M)) ++ { ++ type = IA64_TYPE_A; ++ } ++ else ++ { ++ switch (unit) ++ { ++ case IA64_UNIT_I: ++ type = IA64_TYPE_I; break; ++ case IA64_UNIT_M: ++ type = IA64_TYPE_M; break; ++ case IA64_UNIT_B: ++ type = IA64_TYPE_B; break; ++ case IA64_UNIT_F: ++ type = IA64_TYPE_F; break; ++ case IA64_UNIT_L: ++ case IA64_UNIT_X: ++ type = IA64_TYPE_X; break; ++ default: ++ type = -1; ++ } ++ } ++ return type; ++} ++ ++int ++print_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info) ++{ ++ ia64_insn t0, t1, slot[3], template, s_bit, insn; ++ int slotnum, j, status, need_comma, retval, slot_multiplier; ++ const struct ia64_operand *odesc; ++ const struct ia64_opcode *idesc; ++ const char *err, *str, *tname; ++ BFD_HOST_U_64_BIT value; ++ bfd_byte bundle[16]; ++ enum ia64_unit unit; ++ char regname[16]; ++ ++ if (info->bytes_per_line == 0) ++ info->bytes_per_line = 6; ++ info->display_endian = info->endian; ++ ++ slot_multiplier = info->bytes_per_line; ++ retval = slot_multiplier; ++ ++ slotnum = (((long) memaddr) & 0xf) / slot_multiplier; ++ if (slotnum > 2) ++ return -1; ++ ++ memaddr -= (memaddr & 0xf); ++ status = (*info->read_memory_func) (memaddr, bundle, sizeof (bundle), info); ++ if (status != 0) ++ { ++ (*info->memory_error_func) (status, memaddr, info); ++ return -1; ++ } ++ /* bundles are always in little-endian byte order */ ++ t0 = bfd_getl64 (bundle); ++ t1 = bfd_getl64 (bundle + 8); ++ s_bit = t0 & 1; ++ template = (t0 >> 1) & 0xf; ++ slot[0] = (t0 >> 5) & 0x1ffffffffffLL; ++ slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18); ++ slot[2] = (t1 >> 23) & 0x1ffffffffffLL; ++ ++ tname = ia64_templ_desc[template].name; ++ if (slotnum == 0) ++ (*info->fprintf_func) (info->stream, "[%s] ", tname); ++ else ++ (*info->fprintf_func) (info->stream, " "); ++ ++ unit = ia64_templ_desc[template].exec_unit[slotnum]; ++ ++ if (template == 2 && slotnum == 1) ++ { ++ /* skip L slot in MLI template: */ ++ slotnum = 2; ++ retval += slot_multiplier; ++ } ++ ++ insn = slot[slotnum]; ++ ++ if (unit == IA64_UNIT_NIL) ++ goto decoding_failed; ++ ++ idesc = ia64_dis_opcode (insn, unit_to_type (insn, unit)); ++ if (idesc == NULL) ++ goto decoding_failed; ++ ++ /* print predicate, if any: */ ++ ++ if ((idesc->flags & IA64_OPCODE_NO_PRED) ++ || (insn & 0x3f) == 0) ++ (*info->fprintf_func) (info->stream, " "); ++ else ++ (*info->fprintf_func) (info->stream, "(p%02d) ", (int)(insn & 0x3f)); ++ ++ /* now the actual instruction: */ ++ ++ (*info->fprintf_func) (info->stream, "%s", idesc->name); ++ if (idesc->operands[0]) ++ (*info->fprintf_func) (info->stream, " "); ++ ++ need_comma = 0; ++ for (j = 0; j < NELEMS (idesc->operands) && idesc->operands[j]; ++j) ++ { ++ odesc = elf64_ia64_operands + idesc->operands[j]; ++ ++ if (need_comma) ++ (*info->fprintf_func) (info->stream, ","); ++ ++ if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64) ++ { ++ /* special case of 64 bit immediate load: */ ++ value = ((insn >> 13) & 0x7f) | (((insn >> 27) & 0x1ff) << 7) ++ | (((insn >> 22) & 0x1f) << 16) | (((insn >> 21) & 0x1) << 21) ++ | (slot[1] << 22) | (((insn >> 36) & 0x1) << 63); ++ } ++ else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62) ++ { ++ /* 62-bit immediate for nop.x/break.x */ ++ value = ((slot[1] & 0x1ffffffffffLL) << 21) ++ | (((insn >> 36) & 0x1) << 20) ++ | ((insn >> 6) & 0xfffff); ++ } ++ else if (odesc - elf64_ia64_operands == IA64_OPND_TGT64) ++ { ++ /* 60-bit immediate for long branches. */ ++ value = (((insn >> 13) & 0xfffff) ++ | (((insn >> 36) & 1) << 59) ++ | (((slot[1] >> 2) & 0x7fffffffffLL) << 20)) << 4; ++ } ++ else ++ { ++ err = (*odesc->extract) (odesc, insn, &value); ++ if (err) ++ { ++ (*info->fprintf_func) (info->stream, "%s", err); ++ goto done; ++ } ++ } ++ ++ switch (odesc->class) ++ { ++ case IA64_OPND_CLASS_CST: ++ (*info->fprintf_func) (info->stream, "%s", odesc->str); ++ break; ++ ++ case IA64_OPND_CLASS_REG: ++ if (odesc->str[0] == 'a' && odesc->str[1] == 'r') ++ { ++ switch (value) ++ { ++ case 0: case 1: case 2: case 3: ++ case 4: case 5: case 6: case 7: ++ sprintf (regname, "ar.k%u", (unsigned int) value); ++ break; ++ case 16: strcpy (regname, "ar.rsc"); break; ++ case 17: strcpy (regname, "ar.bsp"); break; ++ case 18: strcpy (regname, "ar.bspstore"); break; ++ case 19: strcpy (regname, "ar.rnat"); break; ++ case 32: strcpy (regname, "ar.ccv"); break; ++ case 36: strcpy (regname, "ar.unat"); break; ++ case 40: strcpy (regname, "ar.fpsr"); break; ++ case 44: strcpy (regname, "ar.itc"); break; ++ case 64: strcpy (regname, "ar.pfs"); break; ++ case 65: strcpy (regname, "ar.lc"); break; ++ case 66: strcpy (regname, "ar.ec"); break; ++ default: ++ sprintf (regname, "ar%u", (unsigned int) value); ++ break; ++ } ++ (*info->fprintf_func) (info->stream, "%s", regname); ++ } ++ else ++ (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value); ++ break; ++ ++ case IA64_OPND_CLASS_IND: ++ (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value); ++ break; ++ ++ case IA64_OPND_CLASS_ABS: ++ str = 0; ++ if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4) ++ switch (value) ++ { ++ case 0x0: str = "@brcst"; break; ++ case 0x8: str = "@mix"; break; ++ case 0x9: str = "@shuf"; break; ++ case 0xa: str = "@alt"; break; ++ case 0xb: str = "@rev"; break; ++ } ++ ++ if (str) ++ (*info->fprintf_func) (info->stream, "%s", str); ++ else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED) ++ (*info->fprintf_func) (info->stream, "%lld", (long long) value); ++ else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED) ++ (*info->fprintf_func) (info->stream, "%llu", (long long) value); ++ else ++ (*info->fprintf_func) (info->stream, "0x%llx", (long long) value); ++ break; ++ ++ case IA64_OPND_CLASS_REL: ++ (*info->print_address_func) (memaddr + value, info); ++ break; ++ } ++ ++ need_comma = 1; ++ if (j + 1 == idesc->num_outputs) ++ { ++ (*info->fprintf_func) (info->stream, "="); ++ need_comma = 0; ++ } ++ } ++ if (slotnum + 1 == ia64_templ_desc[template].group_boundary ++ || ((slotnum == 2) && s_bit)) ++ (*info->fprintf_func) (info->stream, ";;"); ++ ++ done: ++ ia64_free_opcode ((struct ia64_opcode *)idesc); ++ failed: ++ if (slotnum == 2) ++ retval += 16 - 3*slot_multiplier; ++ return retval; ++ ++ decoding_failed: ++ (*info->fprintf_func) (info->stream, " data8 %#011llx", (long long) insn); ++ goto failed; ++} +--- /dev/null ++++ b/arch/ia64/kdb/ia64-opc.c +@@ -0,0 +1,749 @@ ++/* ia64-opc.c -- Functions to access the compacted opcode table ++ Copyright 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. ++ Written by Bob Manson of Cygnus Solutions, ++ ++ This file is part of GDB, GAS, and the GNU binutils. ++ ++ GDB, GAS, and the GNU binutils are free software; you can redistribute ++ them and/or modify them under the terms of the GNU General Public ++ License as published by the Free Software Foundation; either version ++ 2, or (at your option) any later version. ++ ++ GDB, GAS, and the GNU binutils are distributed in the hope that they ++ will be useful, but WITHOUT ANY WARRANTY; without even the implied ++ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ the GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this file; see the file COPYING. If not, write to the ++ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA ++ 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++ ++#define xstrdup(string) ({ char *res = kdb_strdup(string, GFP_ATOMIC); if (!res) BUG(); res; }) ++#define xmalloc(size) ({ void *res = debug_kmalloc(size, GFP_ATOMIC); if (!res) BUG(); res; }) ++#define free(address) debug_kfree(address) ++#define abort() BUG() ++ ++#else /* __KERNEL__ */ ++#include "ansidecl.h" ++#include "sysdep.h" ++#include "libiberty.h" ++#endif /* __KERNEL__ */ ++#include "ia64-asmtab.h" ++#include "ia64-asmtab.c" ++ ++static void get_opc_prefix (const char **, char *); ++static short int find_string_ent (const char *); ++static short int find_main_ent (short int); ++static short int find_completer (short int, short int, const char *); ++static ia64_insn apply_completer (ia64_insn, int); ++static int extract_op_bits (int, int, int); ++static int extract_op (int, int *, unsigned int *); ++static int opcode_verify (ia64_insn, int, enum ia64_insn_type); ++static int locate_opcode_ent (ia64_insn, enum ia64_insn_type); ++static struct ia64_opcode *make_ia64_opcode ++ (ia64_insn, const char *, int, int); ++static struct ia64_opcode *ia64_find_matching_opcode ++ (const char *, short int); ++ ++const struct ia64_templ_desc ia64_templ_desc[16] = ++ { ++ { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" }, /* 0 */ ++ { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" }, ++ { 0, { 0, }, "-3-" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" }, /* 4 */ ++ { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" }, /* 8 */ ++ { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" }, ++ { 0, { 0, }, "-a-" }, ++ { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" }, /* c */ ++ { 0, { 0, }, "-d-" }, ++ { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" }, ++ { 0, { 0, }, "-f-" }, ++ }; ++ ++ ++/* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST. ++ PTR will be adjusted to point to the start of the next portion ++ of the opcode, or at the NUL character. */ ++ ++static void ++get_opc_prefix (const char **ptr, char *dest) ++{ ++ char *c = strchr (*ptr, '.'); ++ if (c != NULL) ++ { ++ memcpy (dest, *ptr, c - *ptr); ++ dest[c - *ptr] = '\0'; ++ *ptr = c + 1; ++ } ++ else ++ { ++ int l = strlen (*ptr); ++ memcpy (dest, *ptr, l); ++ dest[l] = '\0'; ++ *ptr += l; ++ } ++} ++ ++/* Find the index of the entry in the string table corresponding to ++ STR; return -1 if one does not exist. */ ++ ++static short ++find_string_ent (const char *str) ++{ ++ short start = 0; ++ short end = sizeof (ia64_strings) / sizeof (const char *); ++ short i = (start + end) / 2; ++ ++ if (strcmp (str, ia64_strings[end - 1]) > 0) ++ { ++ return -1; ++ } ++ while (start <= end) ++ { ++ int c = strcmp (str, ia64_strings[i]); ++ if (c < 0) ++ { ++ end = i - 1; ++ } ++ else if (c == 0) ++ { ++ return i; ++ } ++ else ++ { ++ start = i + 1; ++ } ++ i = (start + end) / 2; ++ } ++ return -1; ++} ++ ++/* Find the opcode in the main opcode table whose name is STRINGINDEX, or ++ return -1 if one does not exist. */ ++ ++static short ++find_main_ent (short nameindex) ++{ ++ short start = 0; ++ short end = sizeof (main_table) / sizeof (struct ia64_main_table); ++ short i = (start + end) / 2; ++ ++ if (nameindex < main_table[0].name_index ++ || nameindex > main_table[end - 1].name_index) ++ { ++ return -1; ++ } ++ while (start <= end) ++ { ++ if (nameindex < main_table[i].name_index) ++ { ++ end = i - 1; ++ } ++ else if (nameindex == main_table[i].name_index) ++ { ++ while (i > 0 && main_table[i - 1].name_index == nameindex) ++ { ++ i--; ++ } ++ return i; ++ } ++ else ++ { ++ start = i + 1; ++ } ++ i = (start + end) / 2; ++ } ++ return -1; ++} ++ ++/* Find the index of the entry in the completer table that is part of ++ MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or ++ return -1 if one does not exist. */ ++ ++static short ++find_completer (short main_ent, short prev_completer, const char *name) ++{ ++ short name_index = find_string_ent (name); ++ ++ if (name_index < 0) ++ { ++ return -1; ++ } ++ ++ if (prev_completer == -1) ++ { ++ prev_completer = main_table[main_ent].completers; ++ } ++ else ++ { ++ prev_completer = completer_table[prev_completer].subentries; ++ } ++ ++ while (prev_completer != -1) ++ { ++ if (completer_table[prev_completer].name_index == name_index) ++ { ++ return prev_completer; ++ } ++ prev_completer = completer_table[prev_completer].alternative; ++ } ++ return -1; ++} ++ ++/* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and ++ return the result. */ ++ ++static ia64_insn ++apply_completer (ia64_insn opcode, int completer_index) ++{ ++ ia64_insn mask = completer_table[completer_index].mask; ++ ia64_insn bits = completer_table[completer_index].bits; ++ int shiftamt = (completer_table[completer_index].offset & 63); ++ ++ mask = mask << shiftamt; ++ bits = bits << shiftamt; ++ opcode = (opcode & ~mask) | bits; ++ return opcode; ++} ++ ++/* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in ++ the dis_table array, and return its value. (BITOFFSET is numbered ++ starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the ++ first byte in OP_POINTER.) */ ++ ++static int ++extract_op_bits (int op_pointer, int bitoffset, int bits) ++{ ++ int res = 0; ++ ++ op_pointer += (bitoffset / 8); ++ ++ if (bitoffset % 8) ++ { ++ unsigned int op = dis_table[op_pointer++]; ++ int numb = 8 - (bitoffset % 8); ++ int mask = (1 << numb) - 1; ++ int bata = (bits < numb) ? bits : numb; ++ int delta = numb - bata; ++ ++ res = (res << bata) | ((op & mask) >> delta); ++ bitoffset += bata; ++ bits -= bata; ++ } ++ while (bits >= 8) ++ { ++ res = (res << 8) | (dis_table[op_pointer++] & 255); ++ bits -= 8; ++ } ++ if (bits > 0) ++ { ++ unsigned int op = (dis_table[op_pointer++] & 255); ++ res = (res << bits) | (op >> (8 - bits)); ++ } ++ return res; ++} ++ ++/* Examine the state machine entry at OP_POINTER in the dis_table ++ array, and extract its values into OPVAL and OP. The length of the ++ state entry in bits is returned. */ ++ ++static int ++extract_op (int op_pointer, int *opval, unsigned int *op) ++{ ++ int oplen = 5; ++ ++ *op = dis_table[op_pointer]; ++ ++ if ((*op) & 0x40) ++ { ++ opval[0] = extract_op_bits (op_pointer, oplen, 5); ++ oplen += 5; ++ } ++ switch ((*op) & 0x30) ++ { ++ case 0x10: ++ { ++ opval[1] = extract_op_bits (op_pointer, oplen, 8); ++ oplen += 8; ++ opval[1] += op_pointer; ++ break; ++ } ++ case 0x20: ++ { ++ opval[1] = extract_op_bits (op_pointer, oplen, 16); ++ if (! (opval[1] & 32768)) ++ { ++ opval[1] += op_pointer; ++ } ++ oplen += 16; ++ break; ++ } ++ case 0x30: ++ { ++ oplen--; ++ opval[2] = extract_op_bits (op_pointer, oplen, 12); ++ oplen += 12; ++ opval[2] |= 32768; ++ break; ++ } ++ } ++ if (((*op) & 0x08) && (((*op) & 0x30) != 0x30)) ++ { ++ opval[2] = extract_op_bits (op_pointer, oplen, 16); ++ oplen += 16; ++ if (! (opval[2] & 32768)) ++ { ++ opval[2] += op_pointer; ++ } ++ } ++ return oplen; ++} ++ ++/* Returns a non-zero value if the opcode in the main_table list at ++ PLACE matches OPCODE and is of type TYPE. */ ++ ++static int ++opcode_verify (ia64_insn opcode, int place, enum ia64_insn_type type) ++{ ++ if (main_table[place].opcode_type != type) ++ { ++ return 0; ++ } ++ if (main_table[place].flags ++ & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT)) ++ { ++ const struct ia64_operand *o1, *o2; ++ ia64_insn f2, f3; ++ ++ if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3) ++ { ++ o1 = elf64_ia64_operands + IA64_OPND_F2; ++ o2 = elf64_ia64_operands + IA64_OPND_F3; ++ (*o1->extract) (o1, opcode, &f2); ++ (*o2->extract) (o2, opcode, &f3); ++ if (f2 != f3) ++ return 0; ++ } ++ else ++ { ++ ia64_insn len, count; ++ ++ /* length must equal 64-count: */ ++ o1 = elf64_ia64_operands + IA64_OPND_LEN6; ++ o2 = elf64_ia64_operands + main_table[place].operands[2]; ++ (*o1->extract) (o1, opcode, &len); ++ (*o2->extract) (o2, opcode, &count); ++ if (len != 64 - count) ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++/* Find an instruction entry in the ia64_dis_names array that matches ++ opcode OPCODE and is of type TYPE. Returns either a positive index ++ into the array, or a negative value if an entry for OPCODE could ++ not be found. Checks all matches and returns the one with the highest ++ priority. */ ++ ++static int ++locate_opcode_ent (ia64_insn opcode, enum ia64_insn_type type) ++{ ++ int currtest[41]; ++ int bitpos[41]; ++ int op_ptr[41]; ++ int currstatenum = 0; ++ short found_disent = -1; ++ short found_priority = -1; ++ ++ currtest[currstatenum] = 0; ++ op_ptr[currstatenum] = 0; ++ bitpos[currstatenum] = 40; ++ ++ while (1) ++ { ++ int op_pointer = op_ptr[currstatenum]; ++ unsigned int op; ++ int currbitnum = bitpos[currstatenum]; ++ int oplen; ++ int opval[3] = {0}; ++ int next_op; ++ int currbit; ++ ++ oplen = extract_op (op_pointer, opval, &op); ++ ++ bitpos[currstatenum] = currbitnum; ++ ++ /* Skip opval[0] bits in the instruction. */ ++ if (op & 0x40) ++ { ++ currbitnum -= opval[0]; ++ } ++ ++ /* The value of the current bit being tested. */ ++ currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0; ++ next_op = -1; ++ ++ /* We always perform the tests specified in the current state in ++ a particular order, falling through to the next test if the ++ previous one failed. */ ++ switch (currtest[currstatenum]) ++ { ++ case 0: ++ currtest[currstatenum]++; ++ if (currbit == 0 && (op & 0x80)) ++ { ++ /* Check for a zero bit. If this test solely checks for ++ a zero bit, we can check for up to 8 consecutive zero ++ bits (the number to check is specified by the lower 3 ++ bits in the state code.) ++ ++ If the state instruction matches, we go to the very ++ next state instruction; otherwise, try the next test. */ ++ ++ if ((op & 0xf8) == 0x80) ++ { ++ int count = op & 0x7; ++ int x; ++ ++ for (x = 0; x <= count; x++) ++ { ++ int i = ++ opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0; ++ if (i) ++ { ++ break; ++ } ++ } ++ if (x > count) ++ { ++ next_op = op_pointer + ((oplen + 7) / 8); ++ currbitnum -= count; ++ break; ++ } ++ } ++ else if (! currbit) ++ { ++ next_op = op_pointer + ((oplen + 7) / 8); ++ break; ++ } ++ } ++ /* FALLTHROUGH */ ++ case 1: ++ /* If the bit in the instruction is one, go to the state ++ instruction specified by opval[1]. */ ++ currtest[currstatenum]++; ++ if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30)) ++ { ++ next_op = opval[1]; ++ break; ++ } ++ /* FALLTHROUGH */ ++ case 2: ++ /* Don't care. Skip the current bit and go to the state ++ instruction specified by opval[2]. ++ ++ An encoding of 0x30 is special; this means that a 12-bit ++ offset into the ia64_dis_names[] array is specified. */ ++ currtest[currstatenum]++; ++ if ((op & 0x08) || ((op & 0x30) == 0x30)) ++ { ++ next_op = opval[2]; ++ break; ++ } ++ } ++ ++ /* If bit 15 is set in the address of the next state, an offset ++ in the ia64_dis_names array was specified instead. We then ++ check to see if an entry in the list of opcodes matches the ++ opcode we were given; if so, we have succeeded. */ ++ ++ if ((next_op >= 0) && (next_op & 32768)) ++ { ++ short disent = next_op & 32767; ++ short priority = -1; ++ ++ if (next_op > 65535) ++ { ++ abort (); ++ } ++ ++ /* Run through the list of opcodes to check, trying to find ++ one that matches. */ ++ while (disent >= 0) ++ { ++ int place = ia64_dis_names[disent].insn_index; ++ ++ priority = ia64_dis_names[disent].priority; ++ ++ if (opcode_verify (opcode, place, type) ++ && priority > found_priority) ++ { ++ break; ++ } ++ if (ia64_dis_names[disent].next_flag) ++ { ++ disent++; ++ } ++ else ++ { ++ disent = -1; ++ } ++ } ++ ++ if (disent >= 0) ++ { ++ found_disent = disent; ++ found_priority = priority; ++ } ++ /* Try the next test in this state, regardless of whether a match ++ was found. */ ++ next_op = -2; ++ } ++ ++ /* next_op == -1 is "back up to the previous state". ++ next_op == -2 is "stay in this state and try the next test". ++ Otherwise, transition to the state indicated by next_op. */ ++ ++ if (next_op == -1) ++ { ++ currstatenum--; ++ if (currstatenum < 0) ++ { ++ return found_disent; ++ } ++ } ++ else if (next_op >= 0) ++ { ++ currstatenum++; ++ bitpos[currstatenum] = currbitnum - 1; ++ op_ptr[currstatenum] = next_op; ++ currtest[currstatenum] = 0; ++ } ++ } ++} ++ ++/* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */ ++ ++static struct ia64_opcode * ++make_ia64_opcode (ia64_insn opcode, const char *name, int place, int depind) ++{ ++ struct ia64_opcode *res = ++ (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode)); ++ res->name = xstrdup (name); ++ res->type = main_table[place].opcode_type; ++ res->num_outputs = main_table[place].num_outputs; ++ res->opcode = opcode; ++ res->mask = main_table[place].mask; ++ res->operands[0] = main_table[place].operands[0]; ++ res->operands[1] = main_table[place].operands[1]; ++ res->operands[2] = main_table[place].operands[2]; ++ res->operands[3] = main_table[place].operands[3]; ++ res->operands[4] = main_table[place].operands[4]; ++ res->flags = main_table[place].flags; ++ res->ent_index = place; ++ res->dependencies = &op_dependencies[depind]; ++ return res; ++} ++ ++/* Determine the ia64_opcode entry for the opcode specified by INSN ++ and TYPE. If a valid entry is not found, return NULL. */ ++struct ia64_opcode * ++ia64_dis_opcode (ia64_insn insn, enum ia64_insn_type type) ++{ ++ int disent = locate_opcode_ent (insn, type); ++ ++ if (disent < 0) ++ { ++ return NULL; ++ } ++ else ++ { ++ unsigned int cb = ia64_dis_names[disent].completer_index; ++ static char name[128]; ++ int place = ia64_dis_names[disent].insn_index; ++ int ci = main_table[place].completers; ++ ia64_insn tinsn = main_table[place].opcode; ++ ++ strcpy (name, ia64_strings [main_table[place].name_index]); ++ ++ while (cb) ++ { ++ if (cb & 1) ++ { ++ int cname = completer_table[ci].name_index; ++ ++ tinsn = apply_completer (tinsn, ci); ++ ++ if (ia64_strings[cname][0] != '\0') ++ { ++ strcat (name, "."); ++ strcat (name, ia64_strings[cname]); ++ } ++ if (cb != 1) ++ { ++ ci = completer_table[ci].subentries; ++ } ++ } ++ else ++ { ++ ci = completer_table[ci].alternative; ++ } ++ if (ci < 0) ++ { ++ abort (); ++ } ++ cb = cb >> 1; ++ } ++ if (tinsn != (insn & main_table[place].mask)) ++ { ++ abort (); ++ } ++ return make_ia64_opcode (insn, name, place, ++ completer_table[ci].dependencies); ++ } ++} ++ ++/* Search the main_opcode table starting from PLACE for an opcode that ++ matches NAME. Return NULL if one is not found. */ ++ ++static struct ia64_opcode * ++ia64_find_matching_opcode (const char *name, short place) ++{ ++ char op[129]; ++ const char *suffix; ++ short name_index; ++ ++ if (strlen (name) > 128) ++ { ++ return NULL; ++ } ++ suffix = name; ++ get_opc_prefix (&suffix, op); ++ name_index = find_string_ent (op); ++ if (name_index < 0) ++ { ++ return NULL; ++ } ++ ++ while (main_table[place].name_index == name_index) ++ { ++ const char *curr_suffix = suffix; ++ ia64_insn curr_insn = main_table[place].opcode; ++ short completer = -1; ++ ++ do { ++ if (suffix[0] == '\0') ++ { ++ completer = find_completer (place, completer, suffix); ++ } ++ else ++ { ++ get_opc_prefix (&curr_suffix, op); ++ completer = find_completer (place, completer, op); ++ } ++ if (completer != -1) ++ { ++ curr_insn = apply_completer (curr_insn, completer); ++ } ++ } while (completer != -1 && curr_suffix[0] != '\0'); ++ ++ if (completer != -1 && curr_suffix[0] == '\0' ++ && completer_table[completer].terminal_completer) ++ { ++ int depind = completer_table[completer].dependencies; ++ return make_ia64_opcode (curr_insn, name, place, depind); ++ } ++ else ++ { ++ place++; ++ } ++ } ++ return NULL; ++} ++ ++/* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL ++ if one does not exist. ++ ++ It is the caller's responsibility to invoke ia64_free_opcode () to ++ release any resources used by the returned entry. */ ++ ++struct ia64_opcode * ++ia64_find_next_opcode (struct ia64_opcode *prev_ent) ++{ ++ return ia64_find_matching_opcode (prev_ent->name, ++ prev_ent->ent_index + 1); ++} ++ ++/* Find the first opcode that matches NAME, or return NULL if it does ++ not exist. ++ ++ It is the caller's responsibility to invoke ia64_free_opcode () to ++ release any resources used by the returned entry. */ ++ ++struct ia64_opcode * ++ia64_find_opcode (const char *name) ++{ ++ char op[129]; ++ const char *suffix; ++ short place; ++ short name_index; ++ ++ if (strlen (name) > 128) ++ { ++ return NULL; ++ } ++ suffix = name; ++ get_opc_prefix (&suffix, op); ++ name_index = find_string_ent (op); ++ if (name_index < 0) ++ { ++ return NULL; ++ } ++ ++ place = find_main_ent (name_index); ++ ++ if (place < 0) ++ { ++ return NULL; ++ } ++ return ia64_find_matching_opcode (name, place); ++} ++ ++/* Free any resources used by ENT. */ ++void ++ia64_free_opcode (struct ia64_opcode *ent) ++{ ++ free ((void *)ent->name); ++ free (ent); ++} ++ ++const struct ia64_dependency * ++ia64_find_dependency (int index) ++{ ++ index = DEP(index); ++ ++ if (index < 0 ++ || index >= (int)(sizeof(dependencies) / sizeof(dependencies[0]))) ++ return NULL; ++ ++ return &dependencies[index]; ++} +--- /dev/null ++++ b/arch/ia64/kdb/ia64-opc.h +@@ -0,0 +1,141 @@ ++/* ia64-opc.h -- IA-64 opcode table. ++ Copyright 1998, 1999, 2000, 2002 Free Software Foundation, Inc. ++ Contributed by David Mosberger-Tang ++ ++ This file is part of GDB, GAS, and the GNU binutils. ++ ++ GDB, GAS, and the GNU binutils are free software; you can redistribute ++ them and/or modify them under the terms of the GNU General Public ++ License as published by the Free Software Foundation; either version ++ 2, or (at your option) any later version. ++ ++ GDB, GAS, and the GNU binutils are distributed in the hope that they ++ will be useful, but WITHOUT ANY WARRANTY; without even the implied ++ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ the GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this file; see the file COPYING. If not, write to the ++ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA ++ 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef IA64_OPC_H ++#define IA64_OPC_H ++ ++#ifdef __KERNEL__ ++#include "ia64.h" ++#else /* __KERNEL__ */ ++#include "opcode/ia64.h" ++#endif /* __KERNEL__ */ ++ ++/* define a couple of abbreviations: */ ++ ++#define bOp(x) (((ia64_insn) ((x) & 0xf)) << 37) ++#define mOp bOp (-1) ++#define Op(x) bOp (x), mOp ++ ++#define FIRST IA64_OPCODE_FIRST ++#define X_IN_MLX IA64_OPCODE_X_IN_MLX ++#define LAST IA64_OPCODE_LAST ++#define PRIV IA64_OPCODE_PRIV ++#define NO_PRED IA64_OPCODE_NO_PRED ++#define SLOT2 IA64_OPCODE_SLOT2 ++#define PSEUDO IA64_OPCODE_PSEUDO ++#define F2_EQ_F3 IA64_OPCODE_F2_EQ_F3 ++#define LEN_EQ_64MCNT IA64_OPCODE_LEN_EQ_64MCNT ++#define MOD_RRBS IA64_OPCODE_MOD_RRBS ++#define POSTINC IA64_OPCODE_POSTINC ++ ++#define AR_CCV IA64_OPND_AR_CCV ++#define AR_PFS IA64_OPND_AR_PFS ++#define AR_CSD IA64_OPND_AR_CSD ++#define C1 IA64_OPND_C1 ++#define C8 IA64_OPND_C8 ++#define C16 IA64_OPND_C16 ++#define GR0 IA64_OPND_GR0 ++#define IP IA64_OPND_IP ++#define PR IA64_OPND_PR ++#define PR_ROT IA64_OPND_PR_ROT ++#define PSR IA64_OPND_PSR ++#define PSR_L IA64_OPND_PSR_L ++#define PSR_UM IA64_OPND_PSR_UM ++ ++#define AR3 IA64_OPND_AR3 ++#define B1 IA64_OPND_B1 ++#define B2 IA64_OPND_B2 ++#define CR3 IA64_OPND_CR3 ++#define F1 IA64_OPND_F1 ++#define F2 IA64_OPND_F2 ++#define F3 IA64_OPND_F3 ++#define F4 IA64_OPND_F4 ++#define P1 IA64_OPND_P1 ++#define P2 IA64_OPND_P2 ++#define R1 IA64_OPND_R1 ++#define R2 IA64_OPND_R2 ++#define R3 IA64_OPND_R3 ++#define R3_2 IA64_OPND_R3_2 ++ ++#define CPUID_R3 IA64_OPND_CPUID_R3 ++#define DBR_R3 IA64_OPND_DBR_R3 ++#define DTR_R3 IA64_OPND_DTR_R3 ++#define ITR_R3 IA64_OPND_ITR_R3 ++#define IBR_R3 IA64_OPND_IBR_R3 ++#define MR3 IA64_OPND_MR3 ++#define MSR_R3 IA64_OPND_MSR_R3 ++#define PKR_R3 IA64_OPND_PKR_R3 ++#define PMC_R3 IA64_OPND_PMC_R3 ++#define PMD_R3 IA64_OPND_PMD_R3 ++#define RR_R3 IA64_OPND_RR_R3 ++ ++#define CCNT5 IA64_OPND_CCNT5 ++#define CNT2a IA64_OPND_CNT2a ++#define CNT2b IA64_OPND_CNT2b ++#define CNT2c IA64_OPND_CNT2c ++#define CNT5 IA64_OPND_CNT5 ++#define CNT6 IA64_OPND_CNT6 ++#define CPOS6a IA64_OPND_CPOS6a ++#define CPOS6b IA64_OPND_CPOS6b ++#define CPOS6c IA64_OPND_CPOS6c ++#define IMM1 IA64_OPND_IMM1 ++#define IMM14 IA64_OPND_IMM14 ++#define IMM17 IA64_OPND_IMM17 ++#define IMM22 IA64_OPND_IMM22 ++#define IMM44 IA64_OPND_IMM44 ++#define SOF IA64_OPND_SOF ++#define SOL IA64_OPND_SOL ++#define SOR IA64_OPND_SOR ++#define IMM8 IA64_OPND_IMM8 ++#define IMM8U4 IA64_OPND_IMM8U4 ++#define IMM8M1 IA64_OPND_IMM8M1 ++#define IMM8M1U4 IA64_OPND_IMM8M1U4 ++#define IMM8M1U8 IA64_OPND_IMM8M1U8 ++#define IMM9a IA64_OPND_IMM9a ++#define IMM9b IA64_OPND_IMM9b ++#define IMMU2 IA64_OPND_IMMU2 ++#define IMMU21 IA64_OPND_IMMU21 ++#define IMMU24 IA64_OPND_IMMU24 ++#define IMMU62 IA64_OPND_IMMU62 ++#define IMMU64 IA64_OPND_IMMU64 ++#define IMMU7a IA64_OPND_IMMU7a ++#define IMMU7b IA64_OPND_IMMU7b ++#define IMMU9 IA64_OPND_IMMU9 ++#define INC3 IA64_OPND_INC3 ++#define LEN4 IA64_OPND_LEN4 ++#define LEN6 IA64_OPND_LEN6 ++#define MBTYPE4 IA64_OPND_MBTYPE4 ++#define MHTYPE8 IA64_OPND_MHTYPE8 ++#define POS6 IA64_OPND_POS6 ++#define TAG13 IA64_OPND_TAG13 ++#define TAG13b IA64_OPND_TAG13b ++#define TGT25 IA64_OPND_TGT25 ++#define TGT25b IA64_OPND_TGT25b ++#define TGT25c IA64_OPND_TGT25c ++#define TGT64 IA64_OPND_TGT64 ++ ++#endif +--- /dev/null ++++ b/arch/ia64/kdb/ia64.h +@@ -0,0 +1,402 @@ ++/* ia64.h -- Header file for ia64 opcode table ++ Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc. ++ Contributed by David Mosberger-Tang */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef opcode_ia64_h ++#define opcode_ia64_h ++ ++#ifdef __KERNEL__ ++#include ++#else /* __KERNEL__ */ ++#include ++ ++#include "bfd.h" ++#endif /* __KERNEL__ */ ++ ++ ++typedef BFD_HOST_U_64_BIT ia64_insn; ++ ++enum ia64_insn_type ++ { ++ IA64_TYPE_NIL = 0, /* illegal type */ ++ IA64_TYPE_A, /* integer alu (I- or M-unit) */ ++ IA64_TYPE_I, /* non-alu integer (I-unit) */ ++ IA64_TYPE_M, /* memory (M-unit) */ ++ IA64_TYPE_B, /* branch (B-unit) */ ++ IA64_TYPE_F, /* floating-point (F-unit) */ ++ IA64_TYPE_X, /* long encoding (X-unit) */ ++ IA64_TYPE_DYN, /* Dynamic opcode */ ++ IA64_NUM_TYPES ++ }; ++ ++enum ia64_unit ++ { ++ IA64_UNIT_NIL = 0, /* illegal unit */ ++ IA64_UNIT_I, /* integer unit */ ++ IA64_UNIT_M, /* memory unit */ ++ IA64_UNIT_B, /* branching unit */ ++ IA64_UNIT_F, /* floating-point unit */ ++ IA64_UNIT_L, /* long "unit" */ ++ IA64_UNIT_X, /* may be integer or branch unit */ ++ IA64_NUM_UNITS ++ }; ++ ++/* Changes to this enumeration must be propagated to the operand table in ++ bfd/cpu-ia64-opc.c ++ */ ++enum ia64_opnd ++ { ++ IA64_OPND_NIL, /* no operand---MUST BE FIRST!*/ ++ ++ /* constants */ ++ IA64_OPND_AR_CSD, /* application register csd (ar.csd) */ ++ IA64_OPND_AR_CCV, /* application register ccv (ar.ccv) */ ++ IA64_OPND_AR_PFS, /* application register pfs (ar.pfs) */ ++ IA64_OPND_C1, /* the constant 1 */ ++ IA64_OPND_C8, /* the constant 8 */ ++ IA64_OPND_C16, /* the constant 16 */ ++ IA64_OPND_GR0, /* gr0 */ ++ IA64_OPND_IP, /* instruction pointer (ip) */ ++ IA64_OPND_PR, /* predicate register (pr) */ ++ IA64_OPND_PR_ROT, /* rotating predicate register (pr.rot) */ ++ IA64_OPND_PSR, /* processor status register (psr) */ ++ IA64_OPND_PSR_L, /* processor status register L (psr.l) */ ++ IA64_OPND_PSR_UM, /* processor status register UM (psr.um) */ ++ ++ /* register operands: */ ++ IA64_OPND_AR3, /* third application register # (bits 20-26) */ ++ IA64_OPND_B1, /* branch register # (bits 6-8) */ ++ IA64_OPND_B2, /* branch register # (bits 13-15) */ ++ IA64_OPND_CR3, /* third control register # (bits 20-26) */ ++ IA64_OPND_F1, /* first floating-point register # */ ++ IA64_OPND_F2, /* second floating-point register # */ ++ IA64_OPND_F3, /* third floating-point register # */ ++ IA64_OPND_F4, /* fourth floating-point register # */ ++ IA64_OPND_P1, /* first predicate # */ ++ IA64_OPND_P2, /* second predicate # */ ++ IA64_OPND_R1, /* first register # */ ++ IA64_OPND_R2, /* second register # */ ++ IA64_OPND_R3, /* third register # */ ++ IA64_OPND_R3_2, /* third register # (limited to gr0-gr3) */ ++ ++ /* indirect operands: */ ++ IA64_OPND_CPUID_R3, /* cpuid[reg] */ ++ IA64_OPND_DBR_R3, /* dbr[reg] */ ++ IA64_OPND_DTR_R3, /* dtr[reg] */ ++ IA64_OPND_ITR_R3, /* itr[reg] */ ++ IA64_OPND_IBR_R3, /* ibr[reg] */ ++ IA64_OPND_MR3, /* memory at addr of third register # */ ++ IA64_OPND_MSR_R3, /* msr[reg] */ ++ IA64_OPND_PKR_R3, /* pkr[reg] */ ++ IA64_OPND_PMC_R3, /* pmc[reg] */ ++ IA64_OPND_PMD_R3, /* pmd[reg] */ ++ IA64_OPND_RR_R3, /* rr[reg] */ ++ ++ /* immediate operands: */ ++ IA64_OPND_CCNT5, /* 5-bit count (31 - bits 20-24) */ ++ IA64_OPND_CNT2a, /* 2-bit count (1 + bits 27-28) */ ++ IA64_OPND_CNT2b, /* 2-bit count (bits 27-28): 1, 2, 3 */ ++ IA64_OPND_CNT2c, /* 2-bit count (bits 30-31): 0, 7, 15, or 16 */ ++ IA64_OPND_CNT5, /* 5-bit count (bits 14-18) */ ++ IA64_OPND_CNT6, /* 6-bit count (bits 27-32) */ ++ IA64_OPND_CPOS6a, /* 6-bit count (63 - bits 20-25) */ ++ IA64_OPND_CPOS6b, /* 6-bit count (63 - bits 14-19) */ ++ IA64_OPND_CPOS6c, /* 6-bit count (63 - bits 31-36) */ ++ IA64_OPND_IMM1, /* signed 1-bit immediate (bit 36) */ ++ IA64_OPND_IMMU2, /* unsigned 2-bit immediate (bits 13-14) */ ++ IA64_OPND_IMMU7a, /* unsigned 7-bit immediate (bits 13-19) */ ++ IA64_OPND_IMMU7b, /* unsigned 7-bit immediate (bits 20-26) */ ++ IA64_OPND_SOF, /* 8-bit stack frame size */ ++ IA64_OPND_SOL, /* 8-bit size of locals */ ++ IA64_OPND_SOR, /* 6-bit number of rotating registers (scaled by 8) */ ++ IA64_OPND_IMM8, /* signed 8-bit immediate (bits 13-19 & 36) */ ++ IA64_OPND_IMM8U4, /* cmp4*u signed 8-bit immediate (bits 13-19 & 36) */ ++ IA64_OPND_IMM8M1, /* signed 8-bit immediate -1 (bits 13-19 & 36) */ ++ IA64_OPND_IMM8M1U4, /* cmp4*u signed 8-bit immediate -1 (bits 13-19 & 36)*/ ++ IA64_OPND_IMM8M1U8, /* cmp*u signed 8-bit immediate -1 (bits 13-19 & 36) */ ++ IA64_OPND_IMMU9, /* unsigned 9-bit immediate (bits 33-34, 20-26) */ ++ IA64_OPND_IMM9a, /* signed 9-bit immediate (bits 6-12, 27, 36) */ ++ IA64_OPND_IMM9b, /* signed 9-bit immediate (bits 13-19, 27, 36) */ ++ IA64_OPND_IMM14, /* signed 14-bit immediate (bits 13-19, 27-32, 36) */ ++ IA64_OPND_IMM17, /* signed 17-bit immediate (2*bits 6-12, 24-31, 36) */ ++ IA64_OPND_IMMU21, /* unsigned 21-bit immediate (bits 6-25, 36) */ ++ IA64_OPND_IMM22, /* signed 22-bit immediate (bits 13-19, 22-36) */ ++ IA64_OPND_IMMU24, /* unsigned 24-bit immediate (bits 6-26, 31-32, 36) */ ++ IA64_OPND_IMM44, /* signed 44-bit immediate (2^16*bits 6-32, 36) */ ++ IA64_OPND_IMMU62, /* unsigned 62-bit immediate */ ++ IA64_OPND_IMMU64, /* unsigned 64-bit immediate (lotsa bits...) */ ++ IA64_OPND_INC3, /* signed 3-bit (bits 13-15): +/-1, 4, 8, 16 */ ++ IA64_OPND_LEN4, /* 4-bit count (bits 27-30 + 1) */ ++ IA64_OPND_LEN6, /* 6-bit count (bits 27-32 + 1) */ ++ IA64_OPND_MBTYPE4, /* 4-bit mux type (bits 20-23) */ ++ IA64_OPND_MHTYPE8, /* 8-bit mux type (bits 20-27) */ ++ IA64_OPND_POS6, /* 6-bit count (bits 14-19) */ ++ IA64_OPND_TAG13, /* signed 13-bit tag (ip + 16*bits 6-12, 33-34) */ ++ IA64_OPND_TAG13b, /* signed 13-bit tag (ip + 16*bits 24-32) */ ++ IA64_OPND_TGT25, /* signed 25-bit (ip + 16*bits 6-25, 36) */ ++ IA64_OPND_TGT25b, /* signed 25-bit (ip + 16*bits 6-12, 20-32, 36) */ ++ IA64_OPND_TGT25c, /* signed 25-bit (ip + 16*bits 13-32, 36) */ ++ IA64_OPND_TGT64, /* 64-bit (ip + 16*bits 13-32, 36, 2-40(L)) */ ++ IA64_OPND_LDXMOV, /* any symbol, generates R_IA64_LDXMOV. */ ++ ++ IA64_OPND_COUNT /* # of operand types (MUST BE LAST!) */ ++ }; ++ ++enum ia64_dependency_mode ++{ ++ IA64_DV_RAW, ++ IA64_DV_WAW, ++ IA64_DV_WAR, ++}; ++ ++enum ia64_dependency_semantics ++{ ++ IA64_DVS_NONE, ++ IA64_DVS_IMPLIED, ++ IA64_DVS_IMPLIEDF, ++ IA64_DVS_DATA, ++ IA64_DVS_INSTR, ++ IA64_DVS_SPECIFIC, ++ IA64_DVS_STOP, ++ IA64_DVS_OTHER, ++}; ++ ++enum ia64_resource_specifier ++{ ++ IA64_RS_ANY, ++ IA64_RS_AR_K, ++ IA64_RS_AR_UNAT, ++ IA64_RS_AR, /* 8-15, 20, 22-23, 31, 33-35, 37-39, 41-43, 45-47, 67-111 */ ++ IA64_RS_ARb, /* 48-63, 112-127 */ ++ IA64_RS_BR, ++ IA64_RS_CFM, ++ IA64_RS_CPUID, ++ IA64_RS_CR_IRR, ++ IA64_RS_CR_LRR, ++ IA64_RS_CR, /* 3-7,10-15,18,26-63,75-79,82-127 */ ++ IA64_RS_DBR, ++ IA64_RS_FR, ++ IA64_RS_FRb, ++ IA64_RS_GR0, ++ IA64_RS_GR, ++ IA64_RS_IBR, ++ IA64_RS_INSERVICE, /* CR[EOI] or CR[IVR] */ ++ IA64_RS_MSR, ++ IA64_RS_PKR, ++ IA64_RS_PMC, ++ IA64_RS_PMD, ++ IA64_RS_PR, /* non-rotating, 1-15 */ ++ IA64_RS_PRr, /* rotating, 16-62 */ ++ IA64_RS_PR63, ++ IA64_RS_RR, ++ ++ IA64_RS_ARX, /* ARs not in RS_AR or RS_ARb */ ++ IA64_RS_CRX, /* CRs not in RS_CR */ ++ IA64_RS_PSR, /* PSR bits */ ++ IA64_RS_RSE, /* implementation-specific RSE resources */ ++ IA64_RS_AR_FPSR, ++}; ++ ++enum ia64_rse_resource ++{ ++ IA64_RSE_N_STACKED_PHYS, ++ IA64_RSE_BOF, ++ IA64_RSE_STORE_REG, ++ IA64_RSE_LOAD_REG, ++ IA64_RSE_BSPLOAD, ++ IA64_RSE_RNATBITINDEX, ++ IA64_RSE_CFLE, ++ IA64_RSE_NDIRTY, ++}; ++ ++/* Information about a given resource dependency */ ++struct ia64_dependency ++{ ++ /* Name of the resource */ ++ const char *name; ++ /* Does this dependency need further specification? */ ++ enum ia64_resource_specifier specifier; ++ /* Mode of dependency */ ++ enum ia64_dependency_mode mode; ++ /* Dependency semantics */ ++ enum ia64_dependency_semantics semantics; ++ /* Register index, if applicable (distinguishes AR, CR, and PSR deps) */ ++#define REG_NONE (-1) ++ int regindex; ++ /* Special info on semantics */ ++ const char *info; ++}; ++ ++/* Two arrays of indexes into the ia64_dependency table. ++ chks are dependencies to check for conflicts when an opcode is ++ encountered; regs are dependencies to register (mark as used) when an ++ opcode is used. chks correspond to readers (RAW) or writers (WAW or ++ WAR) of a resource, while regs correspond to writers (RAW or WAW) and ++ readers (WAR) of a resource. */ ++struct ia64_opcode_dependency ++{ ++ int nchks; ++ const unsigned short *chks; ++ int nregs; ++ const unsigned short *regs; ++}; ++ ++/* encode/extract the note/index for a dependency */ ++#define RDEP(N,X) (((N)<<11)|(X)) ++#define NOTE(X) (((X)>>11)&0x1F) ++#define DEP(X) ((X)&0x7FF) ++ ++/* A template descriptor describes the execution units that are active ++ for each of the three slots. It also specifies the location of ++ instruction group boundaries that may be present between two slots. */ ++struct ia64_templ_desc ++ { ++ int group_boundary; /* 0=no boundary, 1=between slot 0 & 1, etc. */ ++ enum ia64_unit exec_unit[3]; ++ const char *name; ++ }; ++ ++/* The opcode table is an array of struct ia64_opcode. */ ++ ++struct ia64_opcode ++ { ++ /* The opcode name. */ ++ const char *name; ++ ++ /* The type of the instruction: */ ++ enum ia64_insn_type type; ++ ++ /* Number of output operands: */ ++ int num_outputs; ++ ++ /* The opcode itself. Those bits which will be filled in with ++ operands are zeroes. */ ++ ia64_insn opcode; ++ ++ /* The opcode mask. This is used by the disassembler. This is a ++ mask containing ones indicating those bits which must match the ++ opcode field, and zeroes indicating those bits which need not ++ match (and are presumably filled in by operands). */ ++ ia64_insn mask; ++ ++ /* An array of operand codes. Each code is an index into the ++ operand table. They appear in the order which the operands must ++ appear in assembly code, and are terminated by a zero. */ ++ enum ia64_opnd operands[5]; ++ ++ /* One bit flags for the opcode. These are primarily used to ++ indicate specific processors and environments support the ++ instructions. The defined values are listed below. */ ++ unsigned int flags; ++ ++ /* Used by ia64_find_next_opcode (). */ ++ short ent_index; ++ ++ /* Opcode dependencies. */ ++ const struct ia64_opcode_dependency *dependencies; ++ }; ++ ++/* Values defined for the flags field of a struct ia64_opcode. */ ++ ++#define IA64_OPCODE_FIRST (1<<0) /* must be first in an insn group */ ++#define IA64_OPCODE_X_IN_MLX (1<<1) /* insn is allowed in X slot of MLX */ ++#define IA64_OPCODE_LAST (1<<2) /* must be last in an insn group */ ++#define IA64_OPCODE_PRIV (1<<3) /* privileged instruct */ ++#define IA64_OPCODE_SLOT2 (1<<4) /* insn allowed in slot 2 only */ ++#define IA64_OPCODE_NO_PRED (1<<5) /* insn cannot be predicated */ ++#define IA64_OPCODE_PSEUDO (1<<6) /* insn is a pseudo-op */ ++#define IA64_OPCODE_F2_EQ_F3 (1<<7) /* constraint: F2 == F3 */ ++#define IA64_OPCODE_LEN_EQ_64MCNT (1<<8) /* constraint: LEN == 64-CNT */ ++#define IA64_OPCODE_MOD_RRBS (1<<9) /* modifies all rrbs in CFM */ ++#define IA64_OPCODE_POSTINC (1<<10) /* postincrement MR3 operand */ ++ ++/* A macro to extract the major opcode from an instruction. */ ++#define IA64_OP(i) (((i) >> 37) & 0xf) ++ ++enum ia64_operand_class ++ { ++ IA64_OPND_CLASS_CST, /* constant */ ++ IA64_OPND_CLASS_REG, /* register */ ++ IA64_OPND_CLASS_IND, /* indirect register */ ++ IA64_OPND_CLASS_ABS, /* absolute value */ ++ IA64_OPND_CLASS_REL, /* IP-relative value */ ++ }; ++ ++/* The operands table is an array of struct ia64_operand. */ ++ ++struct ia64_operand ++{ ++ enum ia64_operand_class class; ++ ++ /* Set VALUE as the operand bits for the operand of type SELF in the ++ instruction pointed to by CODE. If an error occurs, *CODE is not ++ modified and the returned string describes the cause of the ++ error. If no error occurs, NULL is returned. */ ++ const char *(*insert) (const struct ia64_operand *self, ia64_insn value, ++ ia64_insn *code); ++ ++ /* Extract the operand bits for an operand of type SELF from ++ instruction CODE store them in *VALUE. If an error occurs, the ++ cause of the error is described by the string returned. If no ++ error occurs, NULL is returned. */ ++ const char *(*extract) (const struct ia64_operand *self, ia64_insn code, ++ ia64_insn *value); ++ ++ /* A string whose meaning depends on the operand class. */ ++ ++ const char *str; ++ ++ struct bit_field ++ { ++ /* The number of bits in the operand. */ ++ int bits; ++ ++ /* How far the operand is left shifted in the instruction. */ ++ int shift; ++ } ++ field[4]; /* no operand has more than this many bit-fields */ ++ ++ unsigned int flags; ++ ++ const char *desc; /* brief description */ ++}; ++ ++/* Values defined for the flags field of a struct ia64_operand. */ ++ ++/* Disassemble as signed decimal (instead of hex): */ ++#define IA64_OPND_FLAG_DECIMAL_SIGNED (1<<0) ++/* Disassemble as unsigned decimal (instead of hex): */ ++#define IA64_OPND_FLAG_DECIMAL_UNSIGNED (1<<1) ++ ++extern const struct ia64_templ_desc ia64_templ_desc[16]; ++ ++/* The tables are sorted by major opcode number and are otherwise in ++ the order in which the disassembler should consider instructions. */ ++extern struct ia64_opcode ia64_opcodes_a[]; ++extern struct ia64_opcode ia64_opcodes_i[]; ++extern struct ia64_opcode ia64_opcodes_m[]; ++extern struct ia64_opcode ia64_opcodes_b[]; ++extern struct ia64_opcode ia64_opcodes_f[]; ++extern struct ia64_opcode ia64_opcodes_d[]; ++ ++ ++extern struct ia64_opcode *ia64_find_opcode (const char *name); ++extern struct ia64_opcode *ia64_find_next_opcode (struct ia64_opcode *ent); ++ ++extern struct ia64_opcode *ia64_dis_opcode (ia64_insn insn, ++ enum ia64_insn_type type); ++ ++extern void ia64_free_opcode (struct ia64_opcode *ent); ++extern const struct ia64_dependency *ia64_find_dependency (int index); ++ ++/* To avoid circular library dependencies, this array is implemented ++ in bfd/cpu-ia64-opc.c: */ ++extern const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT]; ++ ++#endif /* opcode_ia64_h */ +--- /dev/null ++++ b/arch/ia64/kdb/kdb_cmds +@@ -0,0 +1,17 @@ ++# Standard architecture specific commands for kdb. ++# These commands are appended to those in kdb/kdb_cmds, see that file for ++# restrictions. ++ ++# Standard debugging information for first level support, invoked from archkdb* ++# commands that are defined in kdb/kdb_cmds. ++ ++defcmd archkdbcommon "" "Common arch debugging" ++ set LINES 2000000 ++ set BTAPROMPT 0 ++ -summary ++ -id %ip-0x40 ++ -cpu ++ -ps ++ -dmesg 600 ++ -bt ++endefcmd +--- /dev/null ++++ b/arch/ia64/kdb/kdba_bp.c +@@ -0,0 +1,841 @@ ++/* ++ * Kernel Debugger Architecture Dependent Breakpoint Handling ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write", ++ "I/O", "Data Access"}; ++ ++/* ++ * Table describing processor architecture hardware ++ * breakpoint registers. ++ */ ++ ++static kdbhard_bp_t kdb_hardbreaks[KDB_MAXHARDBPT]; ++ ++#ifdef CONFIG_KDB_HARDWARE_BREAKPOINTS ++/* ++ * Counters for number of debug registers used on each CPU. ++ * Used to detect when to enable and disable debug traps. ++ */ ++static unsigned char kdb_dbrs_used[NR_CPUS]; ++#endif /* CONFIG_KDB_HARDWARE_BREAKPOINTS */ ++ ++/* ++ * kdba_db_trap ++ * ++ * Perform breakpoint processing upon entry to the ++ * processor debugger fault. Determine and print ++ * the active breakpoint. ++ * ++ * Parameters: ++ * regs Exception frame containing machine register state ++ * error Error number passed to kdb. ++ * Outputs: ++ * None. ++ * Returns: ++ * KDB_DB_BPT Standard instruction or data breakpoint encountered ++ * KDB_DB_SS Single Step fault ('ss' command or end of 'ssb' command) ++ * KDB_DB_SSB Single Step fault, caller should continue ('ssb' command) ++ * KDB_DB_SSBPT Single step over breakpoint ++ * KDB_DB_NOBPT No existing kdb breakpoint matches this debug exception ++ * Locking: ++ * None. ++ * Remarks: ++ * Yup, there be goto's here. ++ * ++ * If multiple processors receive debug exceptions simultaneously, ++ * one may be waiting at the kdb fence in kdb() while the user ++ * issues a 'bc' command to clear the breakpoint the processor ++ * which is waiting has already encountered. If this is the case, ++ * the debug registers will no longer match any entry in the ++ * breakpoint table, and we'll return the value KDB_DB_NOBPT. ++ * This can cause a panic in die_if_kernel(). It is safer to ++ * disable the breakpoint (bd), go until all processors are past ++ * the breakpoint then clear the breakpoint (bc). This code ++ * recognises a breakpoint even when disabled but not when it has ++ * been cleared. ++ * ++ * WARNING: This routine clears the debug state. It should be called ++ * once per debug and the result cached. ++ */ ++ ++kdb_dbtrap_t ++kdba_db_trap(struct pt_regs *regs, int error) ++{ ++ int i; ++ kdb_dbtrap_t rv = KDB_DB_BPT; ++ kdb_bp_t *bp; ++ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_DB_NOBPT; ++ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_db_trap: error %d\n", error); ++ ++ if (error == 36) { ++ /* Single step */ ++ if (KDB_STATE(SSBPT)) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("ssbpt\n"); ++ KDB_STATE_CLEAR(SSBPT); ++ for(i=0,bp=kdb_breakpoints; ++ i < KDB_MAXBPT; ++ i++, bp++) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", ++ bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); ++ if (!bp->bp_enabled) ++ continue; ++ if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) ++ continue; ++ if (KDB_DEBUG(BP)) ++ kdb_printf("bp for this cpu\n"); ++ if (bp->bp_delayed) { ++ bp->bp_delayed = 0; ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp\n"); ++ kdba_installbp(regs, bp); ++ if (!KDB_STATE(DOING_SS)) { ++ kdba_clearsinglestep(regs); ++ return(KDB_DB_SSBPT); ++ } ++ break; ++ } ++ } ++ if (i == KDB_MAXBPT) { ++ kdb_printf("kdb: Unable to find delayed breakpoint\n"); ++ } ++ if (!KDB_STATE(DOING_SS)) { ++ kdba_clearsinglestep(regs); ++ return(KDB_DB_NOBPT); ++ } ++ /* FALLTHROUGH */ ++ } ++ ++ /* ++ * KDB_STATE_DOING_SS is set when the kernel debugger is using ++ * the processor trap flag to single-step a processor. If a ++ * single step trap occurs and this flag is clear, the SS trap ++ * will be ignored by KDB and the kernel will be allowed to deal ++ * with it as necessary (e.g. for ptrace). ++ */ ++ if (!KDB_STATE(DOING_SS)) ++ return(KDB_DB_NOBPT); ++ ++ /* single step */ ++ rv = KDB_DB_SS; /* Indicate single step */ ++ if (KDB_STATE(DOING_SSB)) /* No ia64 ssb support yet */ ++ KDB_STATE_CLEAR(DOING_SSB); /* No ia64 ssb support yet */ ++ if (KDB_STATE(DOING_SSB)) { ++ /* No IA64 ssb support yet */ ++ } else { ++ /* ++ * Print current insn ++ */ ++ kdb_machreg_t pc = regs->cr_iip + ia64_psr(regs)->ri * 6; ++ kdb_printf("SS trap at "); ++ kdb_symbol_print(pc, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); ++ kdb_id1(pc); ++ KDB_STATE_CLEAR(DOING_SS); ++ } ++ ++ if (rv != KDB_DB_SSB) ++ kdba_clearsinglestep(regs); ++ } ++ ++ return(rv); ++} ++ ++/* ++ * kdba_bp_trap ++ * ++ * Perform breakpoint processing upon entry to the ++ * processor breakpoint instruction fault. Determine and print ++ * the active breakpoint. ++ * ++ * Parameters: ++ * regs Exception frame containing machine register state ++ * error Error number passed to kdb. ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 Standard instruction or data breakpoint encountered ++ * 1 Single Step fault ('ss' command) ++ * 2 Single Step fault, caller should continue ('ssb' command) ++ * 3 No existing kdb breakpoint matches this debug exception ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * If multiple processors receive debug exceptions simultaneously, ++ * one may be waiting at the kdb fence in kdb() while the user ++ * issues a 'bc' command to clear the breakpoint the processor which ++ * is waiting has already encountered. If this is the case, the ++ * debug registers will no longer match any entry in the breakpoint ++ * table, and we'll return the value '3'. This can cause a panic ++ * in die_if_kernel(). It is safer to disable the breakpoint (bd), ++ * 'go' until all processors are past the breakpoint then clear the ++ * breakpoint (bc). This code recognises a breakpoint even when ++ * disabled but not when it has been cleared. ++ * ++ * WARNING: This routine resets the ip. It should be called ++ * once per breakpoint and the result cached. ++ */ ++ ++kdb_dbtrap_t ++kdba_bp_trap(struct pt_regs *regs, int error) ++{ ++ int i; ++ kdb_dbtrap_t rv; ++ kdb_bp_t *bp; ++ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_DB_NOBPT; ++ ++ /* ++ * Determine which breakpoint was encountered. ++ */ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_bp_trap: ip=0x%lx " ++ "regs=0x%p sp=0x%lx\n", ++ regs->cr_iip, regs, regs->r12); ++ ++ rv = KDB_DB_NOBPT; /* Cause kdb() to return */ ++ ++ for(i=0, bp=kdb_breakpoints; ibp_free) ++ continue; ++ if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) ++ continue; ++ if (bp->bp_addr == regs->cr_iip) { ++ /* Hit this breakpoint. */ ++ kdb_printf("Instruction(i) breakpoint #%d at 0x%lx\n", ++ i, regs->cr_iip); ++ kdb_id1(regs->cr_iip); ++ rv = KDB_DB_BPT; ++ bp->bp_delay = 1; ++ /* SSBPT is set when the kernel debugger must single ++ * step a task in order to re-establish an instruction ++ * breakpoint which uses the instruction replacement ++ * mechanism. It is cleared by any action that removes ++ * the need to single-step the breakpoint. ++ */ ++ KDB_STATE_SET(SSBPT); ++ break; ++ } ++ } ++ ++ return rv; ++} ++ ++/* ++ * kdba_handle_bp ++ * ++ * Handle an instruction-breakpoint trap. Called when re-installing ++ * an enabled breakpoint which has has the bp_delay bit set. ++ * ++ * Parameters: ++ * Returns: ++ * Locking: ++ * Remarks: ++ * ++ * Ok, we really need to: ++ * 1) Restore the original instruction byte(s) ++ * 2) Single Step ++ * 3) Restore breakpoint instruction ++ * 4) Continue. ++ * ++ * ++ */ ++ ++static void ++kdba_handle_bp(struct pt_regs *regs, kdb_bp_t *bp) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("regs->cr_iip = 0x%lx\n", regs->cr_iip); ++ ++ /* ++ * Setup single step ++ */ ++ kdba_setsinglestep(regs); ++ ++ /* ++ * Reset delay attribute ++ */ ++ bp->bp_delay = 0; ++ bp->bp_delayed = 1; ++} ++ ++ ++/* ++ * kdba_bptype ++ * ++ * Return a string describing type of breakpoint. ++ * ++ * Parameters: ++ * bph Pointer to hardware breakpoint description ++ * Outputs: ++ * None. ++ * Returns: ++ * Character string. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++char * ++kdba_bptype(kdbhard_bp_t *bph) ++{ ++ char *mode; ++ ++ mode = kdba_rwtypes[bph->bph_mode]; ++ ++ return mode; ++} ++ ++/* ++ * kdba_printbpreg ++ * ++ * Print register name assigned to breakpoint ++ * ++ * Parameters: ++ * bph Pointer hardware breakpoint structure ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdba_printbpreg(kdbhard_bp_t *bph) ++{ ++ kdb_printf(" in dr%ld", bph->bph_reg); ++} ++ ++/* ++ * kdba_printbp ++ * ++ * Print string describing hardware breakpoint. ++ * ++ * Parameters: ++ * bph Pointer to hardware breakpoint description ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdba_printbp(kdb_bp_t *bp) ++{ ++ kdb_printf("\n is enabled"); ++ if (bp->bp_hardtype) { ++ /* Note that bp->bp_hard[NR_CPU] is for x86. ++ * The ia64 uses bp->bp_hard[0] only. ++ */ ++ kdba_printbpreg(bp->bp_hard[0]); ++ if (bp->bp_hard[0]->bph_mode != 0) { ++ kdb_printf(" for %d bytes", ++ bp->bp_hard[0]->bph_length+1); ++ } ++ } ++} ++ ++/* ++ * kdba_parsebp ++ * ++ * Parse architecture dependent portion of the ++ * breakpoint command. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ * for IA64 architure, data access, data write and ++ * I/O breakpoints are supported in addition to instruction ++ * breakpoints. ++ * ++ * {datar|dataw|io|inst} [length] ++ */ ++ ++int ++kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp) ++{ ++ int nextarg = *nextargp; ++ int diag; ++ kdbhard_bp_t *bph = &bp->bp_template; ++ ++ bph->bph_mode = 0; /* Default to instruction breakpoint */ ++ bph->bph_length = 0; /* Length must be zero for insn bp */ ++ if ((argc + 1) != nextarg) { ++ if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { ++ bph->bph_mode = 3; ++ } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { ++ bph->bph_mode = 1; ++ } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { ++ bph->bph_mode = 2; ++ } else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) { ++ bph->bph_mode = 0; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ if (bph->bph_mode == 0) ++ kdba_check_pc(&bp->bp_addr); ++ ++ bph->bph_length = 3; /* Default to 4 byte */ ++ ++ nextarg++; ++ ++ if ((argc + 1) != nextarg) { ++ unsigned long len; ++ ++ diag = kdbgetularg((char *)argv[nextarg], ++ &len); ++ if (diag) ++ return diag; ++ ++ ++ if ((len > 4) || (len == 3)) ++ return KDB_BADLENGTH; ++ ++ bph->bph_length = len; ++ bph->bph_length--; /* Normalize for debug register */ ++ nextarg++; ++ } ++ ++ if ((argc + 1) != nextarg) ++ return KDB_ARGCOUNT; ++ ++ /* ++ * Indicate to architecture independent level that ++ * a hardware register assignment is required to enable ++ * this breakpoint. ++ */ ++ ++ bph->bph_free = 0; ++ } else { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw); ++ if (bp->bp_forcehw) { ++ /* ++ * We are forced to use a hardware register for this ++ * breakpoint because either the bph or bpha ++ * commands were used to establish this breakpoint. ++ */ ++ bph->bph_free = 0; ++ } else { ++ /* ++ * Indicate to architecture dependent level that ++ * the instruction replacement breakpoint technique ++ * should be used for this breakpoint. ++ */ ++ bph->bph_free = 1; ++ bp->bp_adjust = 0; /* software, break is fault, not trap */ ++ } ++ } ++ ++ if (bph->bph_mode == 0 && kdba_verify_rw(bp->bp_addr, bph->bph_length+1)) { ++ kdb_printf("Invalid address for breakpoint, ignoring bp command\n"); ++ return KDB_BADADDR; ++ } ++ ++ *nextargp = nextarg; ++#ifndef CONFIG_KDB_HARDWARE_BREAKPOINTS ++ if (!bph->bph_free) { ++ kdb_printf("kdba_parsebp hardware breakpoints are not supported yet\n"); ++ return KDB_NOTIMP; ++ } ++#endif /* CONFIG_KDB_HARDWARE_BREAKPOINTS */ ++ return 0; ++} ++ ++/* ++ * kdba_allocbp ++ * ++ * Associate a hardware register with a breakpoint. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * A pointer to the allocated register kdbhard_bp_t structure for ++ * success, Null and a non-zero diagnostic for failure. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static kdbhard_bp_t * ++kdba_allocbp(kdbhard_bp_t *bph, int *diagp) ++{ ++ int i; ++ kdbhard_bp_t *newbph; ++ ++ for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) { ++ if (newbph->bph_free) { ++ break; ++ } ++ } ++ ++ if (i == KDB_MAXHARDBPT) { ++ *diagp = KDB_TOOMANYDBREGS; ++ return NULL; ++ } ++ ++ *diagp = 0; ++ ++ /* ++ * Copy data from template. Can't just copy the entire template ++ * here because the register number in kdb_hardbreaks must be ++ * preserved. ++ */ ++ newbph->bph_data = bph->bph_data; ++ newbph->bph_write = bph->bph_write; ++ newbph->bph_mode = bph->bph_mode; ++ newbph->bph_length = bph->bph_length; ++ ++ /* ++ * Mark entry allocated. ++ */ ++ newbph->bph_free = 0; ++ ++ return newbph; ++} ++ ++/* ++ * kdba_alloc_hwbp ++ * ++ * Associate a hardware registers with a breakpoint. ++ * If hw bp is global hw registers descriptor will be allocated ++ * on every CPU. ++ * ++ * Parameters: ++ * bp - hardware bp ++ * diagp - pointer to variable that will store error when ++ * function complete ++ * Outputs: ++ * None. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Should be called with correct bp->bp_template. ++ */ ++ ++void ++kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp) ++{ ++ /* Note that bp->bp_hard[NR_CPU] is for x86. ++ * The ia64 uses bp->bp_hard[0] only. ++ */ ++ bp->bp_hard[0] = kdba_allocbp(&bp->bp_template, diagp); ++ bp->bp_hardtype = 1; ++} ++ ++ ++ ++/* ++ * kdba_freebp ++ * ++ * Deallocate a hardware breakpoint ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdba_freebp(kdbhard_bp_t *bph) ++{ ++ bph->bph_free = 1; ++} ++ ++/* ++ * kdba_free_hwbp ++ * ++ * Frees allocated hw registers descriptors for bp. ++ * If hw bp is global, hw registers descriptors will be freed ++ * on every CPU. ++ * ++ * Parameters: ++ * bp - hardware bp ++ * Outputs: ++ * None. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Should be called with correct bp->bp_template ++ */ ++ ++void ++kdba_free_hwbp(kdb_bp_t *bp) ++{ ++ /* When kernel enters KDB, first, all local bps ++ * are removed, so here we don't need to clear ++ * debug registers. ++ */ ++ ++ kdba_freebp(bp->bp_hard[0]); ++ bp->bp_hard[0] = NULL; ++ bp->bp_hardtype = 0; ++} ++ ++ ++/* ++ * kdba_initbp ++ * ++ * Initialize the breakpoint table for the hardware breakpoint ++ * register. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * There is one entry per register. On the ia64 architecture ++ * all the registers are interchangeable, so no special allocation ++ * criteria are required. ++ */ ++ ++void ++kdba_initbp(void) ++{ ++ int i; ++ kdbhard_bp_t *bph; ++ ++ /* ++ * Clear the hardware breakpoint table ++ */ ++ ++ memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks)); ++ ++ for(i=0,bph=kdb_hardbreaks; ibph_reg = i; ++ bph->bph_free = 1; ++ } ++} ++ ++#ifdef CONFIG_KDB_HARDWARE_BREAKPOINTS ++/* ++ * Enable Instruction Debug & Data Debug faults on this CPU now. ++ */ ++static inline void kdba_enable_debug_faults(void) ++{ ++ unsigned long tmp; ++ ++ tmp = ia64_getreg(_IA64_REG_PSR); ++ ia64_stop(); ++ tmp |= IA64_PSR_DB; ++ ia64_stop(); ++ ia64_setreg(_IA64_REG_PSR_L, tmp); ++ ia64_srlz_i(); ++ if (KDB_DEBUG(BP)) ++ kdb_printf("enabling debug faults: [%d]PSR.L=%08x\n", ++ smp_processor_id(), (unsigned int)tmp); ++} ++ ++/* ++ * Disable Instruction Debug & Data Debug faults on this CPU now. ++ */ ++static inline void kdba_disable_debug_faults(void) ++{ ++ unsigned long tmp; ++ ++ tmp = ia64_getreg(_IA64_REG_PSR); ++ ia64_stop(); ++ tmp &= ~IA64_PSR_DB; ++ ia64_stop(); ++ ia64_setreg(_IA64_REG_PSR_L, tmp); ++ ia64_srlz_i(); ++ if (KDB_DEBUG(BP)) ++ kdb_printf("disabling debug faults: [%d]PSR.L=%08x\n", ++ smp_processor_id(), (unsigned int)tmp); ++} ++#endif /* CONFIG_KDB_HARDWARE_BREAKPOINTS */ ++ ++/* ++ * kdba_installbp ++ * ++ * Install a breakpoint ++ * ++ * Parameters: ++ * regs Exception frame ++ * bp Breakpoint structure for the breakpoint to be installed ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 if breakpoint set, otherwise error. ++ * Locking: ++ * None. ++ * Remarks: ++ * For hardware breakpoints, a debug register is allocated ++ * and assigned to the breakpoint. If no debug register is ++ * available, a warning message is printed and the breakpoint ++ * is disabled. ++ * ++ * For instruction replacement breakpoints, we must single-step ++ * over the replaced instruction at this point so we can re-install ++ * the breakpoint instruction after the single-step. SSBPT is set ++ * when the breakpoint is initially hit and is cleared by any action ++ * that removes the need for single-step over the breakpoint. ++ */ ++ ++int ++kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp) ++{ ++ /* ++ * Install the breakpoint, if it is not already installed. ++ */ ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed); ++ } ++ if (!KDB_STATE(SSBPT)) ++ bp->bp_delay = 0; ++ ++ if (bp->bp_hardtype) { ++#ifdef CONFIG_KDB_HARDWARE_BREAKPOINTS ++ /* ++ * Hardware breakpoints are always local for the ++ * purposes of installation (i.e. they use per-cpu ++ * registers), so we don't need to check bp_installed ++ */ ++ kdba_installdbreg(bp); ++ if (++kdb_dbrs_used[smp_processor_id()] == 1) ++ kdba_enable_debug_faults(); ++ bp->bp_installed = 1; ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt0 "\n", ++ bp->bp_hard[0]->bph_reg, bp->bp_addr); ++ } ++#endif /* CONFIG_KDB_HARDWARE_BREAKPOINTS */ ++ ++ } else if (bp->bp_delay) { ++ if (!bp->bp_installed) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp delayed bp\n"); ++ kdba_handle_bp(regs, bp); ++ } ++ } else { ++ if (!bp->bp_installed) { ++ /* Software breakpoints always use slot 0 in the 128 bit ++ * bundle. The template type does not matter, slot 0 ++ * can only be M or B and the encodings for break.m and ++ * break.b are the same. ++ */ ++ unsigned long break_inst; ++ if (kdb_getarea_size(bp->bp_inst.inst, bp->bp_addr, sizeof(bp->bp_inst.inst))) { ++ kdb_printf("kdba_installbp failed to read software breakpoint at 0x%lx\n", bp->bp_addr); ++ return(1); ++ } ++ break_inst = (bp->bp_inst.inst[0] & ~INST_SLOT0_MASK) | BREAK_INSTR; ++ if (kdb_putarea_size(bp->bp_addr, &break_inst, sizeof(break_inst))) { ++ kdb_printf("kdba_installbp failed to set software breakpoint at 0x%lx\n", bp->bp_addr); ++ return(1); ++ } ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp instruction 0x%lx at " kdb_bfd_vma_fmt0 "\n", ++ BREAK_INSTR, bp->bp_addr); ++ bp->bp_installed = 1; ++ flush_icache_range(bp->bp_addr, bp->bp_addr+16); ++ } ++ } ++ return(0); ++} ++ ++/* ++ * kdba_removebp ++ * ++ * Make a breakpoint ineffective. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 if breakpoint removed, otherwise error. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdba_removebp(kdb_bp_t *bp) ++{ ++ /* ++ * For hardware breakpoints, remove it from the active register, ++ * for software breakpoints, restore the instruction stream. ++ */ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed); ++ } ++ ++ if (bp->bp_hardtype) { ++#ifdef CONFIG_KDB_HARDWARE_BREAKPOINTS ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt0 "\n", ++ bp->bp_hard[0]->bph_reg, bp->bp_addr); ++ } ++ if (--kdb_dbrs_used[smp_processor_id()] == 0) ++ kdba_disable_debug_faults(); ++ kdba_removedbreg(bp); ++#endif /* CONFIG_KDB_HARDWARE_BREAKPOINTS */ ++ } else { ++ if (bp->bp_installed) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdb: restoring instruction 0x%016lx%016lx at " kdb_bfd_vma_fmt0 "\n", ++ bp->bp_inst.inst[0], bp->bp_inst.inst[1], bp->bp_addr); ++ if (kdba_putarea_size(bp->bp_addr, bp->bp_inst.inst, sizeof(bp->bp_inst.inst))) ++ return(1); ++ } ++ bp->bp_installed = 0; ++ flush_icache_range(bp->bp_addr, bp->bp_addr+16); ++ } ++ return(0); ++} +--- /dev/null ++++ b/arch/ia64/kdb/kdba_bt.c +@@ -0,0 +1,285 @@ ++/* ++ * Kernel Debugger Architecture Dependent Stack Traceback ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * bt_print_one ++ * ++ * Print one back trace entry. ++ * ++ * Inputs: ++ * ip Current program counter. ++ * symtab Information about symbol that ip falls within. ++ * argcount Maximum number of arguments to print. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * None. ++ */ ++ ++static void ++bt_print_one(kdb_machreg_t ip, ++ const kdb_symtab_t *symtab, int argcount, ++ struct unw_frame_info *info) ++{ ++ int btsymarg = 0; /* Convert arguments to symbols */ ++ int btsp = 0; /* Print stack and backing store pointers */ ++ int nosect = 0; /* Suppress section data */ ++ int args; ++ kdb_machreg_t sp, bsp, cfm; ++ ++ kdbgetintenv("BTSYMARG", &btsymarg); ++ kdbgetintenv("BTSP", &btsp); ++ kdbgetintenv("NOSECT", &nosect); ++ ++ unw_get_sp(info, &sp); ++ unw_get_bsp(info, &bsp); ++ unw_get_cfm(info, &cfm); ++ kdb_symbol_print(ip, symtab, KDB_SP_VALUE|KDB_SP_NEWLINE); ++ args = (cfm >> 7) & 0x7f; /* sol */ ++ if (!args) ++ args = cfm & 0x7f; /* no in/local, use sof instead */ ++ if (argcount && args) { ++ int i, argc = args; ++ ++ kdb_printf(" args ("); ++ if (argc > argcount) ++ argc = argcount; ++ ++ for(i = 0; i < argc; i++){ ++ kdb_machreg_t arg; ++ char nat; ++ if (unw_access_gr(info, i+32, &arg, &nat, 0)) ++ arg = 0; ++ ++ if (i) ++ kdb_printf(", "); ++ kdb_printf("0x%lx", arg); ++ } ++ kdb_printf(")\n"); ++ if (btsymarg) { ++ kdb_symtab_t arg_symtab; ++ kdb_machreg_t arg; ++ for(i = 0; i < argc; i++){ ++ char nat; ++ if (unw_access_gr(info, i+32, &arg, &nat, 0)) ++ arg = 0; ++ if (kdbnearsym(arg, &arg_symtab)) { ++ kdb_printf(" arg %d ", i); ++ kdb_symbol_print(arg, &arg_symtab, KDB_SP_DEFAULT|KDB_SP_NEWLINE); ++ } ++ } ++ } ++ } ++ if (symtab->sym_name) { ++ if (!nosect) { ++ kdb_printf(" %s", symtab->mod_name); ++ if (symtab->sec_name) ++ kdb_printf(" %s 0x%lx", symtab->sec_name, symtab->sec_start); ++ kdb_printf(" 0x%lx", symtab->sym_start); ++ if (symtab->sym_end) ++ kdb_printf(" 0x%lx", symtab->sym_end); ++ kdb_printf("\n"); ++ } ++ if (strncmp(symtab->sym_name, "ia64_spinlock_contention", 24) == 0) { ++ kdb_machreg_t r31; ++ char nat; ++ kdb_printf(" r31 (spinlock address) "); ++ if (unw_access_gr(info, 31, &r31, &nat, 0)) ++ r31 = 0; ++ kdb_symbol_print(r31, NULL, KDB_SP_VALUE|KDB_SP_NEWLINE); ++ } ++ } ++ if (btsp) ++ kdb_printf(" sp 0x%016lx bsp 0x%016lx cfm 0x%016lx info->pfs_loc 0x%016lx 0x%016lx\n", ++ sp, bsp, cfm, (u64) info->pfs_loc, info->pfs_loc ? *(info->pfs_loc) : 0); ++} ++ ++/* ++ * kdba_bt_stack ++ * ++ * Unwind the ia64 backtrace for a specified process. ++ * ++ * Inputs: ++ * argcount ++ * p Pointer to task structure to unwind. ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * none. ++ */ ++ ++static int ++kdba_bt_stack(int argcount, const struct task_struct *p) ++{ ++ kdb_symtab_t symtab; ++ struct unw_frame_info info; ++ struct switch_stack *sw; ++ struct pt_regs *regs = NULL; ++ int count = 0; ++ int btsp = 0; /* Backtrace the kdb code as well */ ++ u64 *prev_pfs_loc = NULL; ++ extern char __attribute__ ((weak)) ia64_spinlock_contention_pre3_4[]; ++ extern char __attribute__ ((weak)) ia64_spinlock_contention_pre3_4_end[]; ++ ++ /* ++ * Upon entering kdb_main_loop, the stack frame looks like this: ++ * ++ * +---------------------+ ++ * | struct pt_regs | ++ * +---------------------+ ++ * | | ++ * | kernel stack | ++ * | | ++ * +=====================+ <--- top of stack upon entering kdb ++ * | struct pt_regs | ++ * +---------------------+ ++ * | | ++ * | kdb stack | ++ * | | ++ * +---------------------+ ++ * | struct switch_stack | ++ * +=====================+ <--- kdb_running_process[cpu].arch.sw from do_kdba_main_loop ++ * ++ * When looking at another process, we do not have the address of the ++ * current pt_regs, it is NULL. If the process has saved its state, use ++ * that pt_regs instead. ++ */ ++ ++ kdbgetintenv("BTSP", &btsp); ++ ++ if (kdb_task_has_cpu(p)) { ++ struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p); ++ if (krp->seqno) { ++ sw = krp->arch.sw; ++ regs = krp->regs; ++ } ++ else ++ sw = NULL; ++ } ++ else { ++ /* Not running, assume blocked */ ++ sw = (struct switch_stack *) (p->thread.ksp + 16); ++ } ++ if (!sw) { ++ kdb_printf("Process does not have a switch_stack, cannot backtrace\n"); ++ kdb_ps1(p); ++ return 0; ++ } ++ ++ unw_init_frame_info(&info, (struct task_struct *)p, sw); ++ ++ /* If we have the address of pt_regs, suppress backtrace on the frames below ++ * pt_regs. No point in displaying kdb itself, unless the user is debugging ++ * the unwinder using set BTSP=1. ++ */ ++ if (regs && !btsp) { ++ kdb_machreg_t sp; ++ if (user_mode(regs)) { ++ kdb_printf("Process was interrupted in user mode, no backtrace available\n"); ++ return 0; ++ } ++ do { ++ unw_get_sp(&info, &sp); ++ if (sp >= (kdb_machreg_t)regs) ++ break; ++ } while (unw_unwind(&info) >= 0 && count++ < 200); ++ } ++ ++ do { ++ kdb_machreg_t ip; ++ ++ /* Avoid unsightly console message from unw_unwind() when attempting ++ * to unwind through the Interrupt Vector Table which has no unwind ++ * information. dispatch_illegal_op_fault() is an exception, it sits ++ * in the 0x3c00 slot. ++ */ ++ if (info.ip >= (u64)__start_ivt_text && info.ip < (u64)__end_ivt_text) { ++ if (info.ip < (u64)__start_ivt_text + 0x3c00 || ++ info.ip >= (u64)__start_ivt_text + 0x4000) ++ return 0; ++ } ++ ++ /* WAR for spinlock contention from leaf functions. ia64_spinlock_contention_pre3_4 ++ * has ar.pfs == r0. Leaf functions do not modify ar.pfs so ar.pfs remains ++ * as 0, stopping the backtrace. Record the previous ar.pfs when the current ++ * IP is in ia64_spinlock_contention_pre3_4 then unwind, if pfs_loc has not changed ++ * after unwind then use pt_regs.ar_pfs which is where the real ar.pfs is for ++ * leaf functions. ++ */ ++ if (prev_pfs_loc && regs && info.pfs_loc == prev_pfs_loc) ++ info.pfs_loc = ®s->ar_pfs; ++ prev_pfs_loc = (info.ip >= (u64)ia64_spinlock_contention_pre3_4 && ++ info.ip < (u64)ia64_spinlock_contention_pre3_4_end) ? ++ info.pfs_loc : NULL; ++ ++ unw_get_ip(&info, &ip); ++ if (ip == 0) ++ break; ++ ++ kdbnearsym(ip, &symtab); ++ if (!symtab.sym_name) { ++ kdb_printf("0x%0*lx - No name. May be an area that has no unwind data\n", ++ (int)(2*sizeof(ip)), ip); ++ return 0; ++ } ++ bt_print_one(ip, &symtab, argcount, &info); ++ } while (unw_unwind(&info) >= 0 && count++ < 200); ++ if (count >= 200) ++ kdb_printf("bt truncated, count limit reached\n"); ++ ++ return 0; ++} ++ ++int ++kdba_bt_address(kdb_machreg_t addr, int argcount) ++{ ++ kdb_printf("Backtrace from a stack address is not supported on ia64\n"); ++ return KDB_NOTIMP; ++} ++ ++/* ++ * kdba_bt_process ++ * ++ * Do a backtrace for a specified process. ++ * ++ * Inputs: ++ * p Struct task pointer extracted by 'bt' command. ++ * argcount ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ */ ++ ++int ++kdba_bt_process(const struct task_struct *p, int argcount) ++{ ++ return kdba_bt_stack(argcount, p); ++} +--- /dev/null ++++ b/arch/ia64/kdb/kdba_fru.c +@@ -0,0 +1,65 @@ ++/* ++ * Kernel Debugger Architecture Dependent FRU functions. ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jesse Barnes"); ++MODULE_DESCRIPTION("Capture FRU data"); ++MODULE_LICENSE("GPL"); ++ ++/** ++ * kdba_fru - capture FRU data ++ * @argc: arg count ++ * @argv: arg values ++ * ++ * Tell the system contollers to capture FRU data ++ */ ++static int ++kdba_fru(int argc, const char **argv) ++{ ++ u64 ret; ++ ++ kdb_printf("Capturing FRU data..."); ++ ret = ia64_sn_fru_capture(); ++ kdb_printf("done.\n"); ++ return ret; ++} ++ ++/** ++ * kdba_fru_init - register 'fru' command with kdb ++ * ++ * Register the 'fru' command with kdb at load time. ++ */ ++static int __init ++kdba_fru_init(void) ++{ ++ kdb_register("fru", kdba_fru, 0, "Capture FRU data", 0); ++ ++ return 0; ++} ++ ++/** ++ * kdba_fru_exit - unregister the 'fru' command ++ * ++ * Tell kdb that the 'fru' command is no longer available. ++ */ ++static void __exit ++kdba_fru_exit(void) ++{ ++ kdb_unregister("fru"); ++} ++ ++module_init(kdba_fru_init) ++module_exit(kdba_fru_exit) +--- /dev/null ++++ b/arch/ia64/kdb/kdba_id.c +@@ -0,0 +1,529 @@ ++/* ++ * Kernel Debugger Architecture Dependent Instruction Disassembly ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define KDBA_PRINTBUF_LEN 64 /* buffer len to print a single instr */ ++#define KDBA_READBUFFER_LEN 256 /* buffer for BFD disassembler */ ++ ++#define BUNDLE_MULTIPLIER 3 /* how many instr/bundle */ ++#define BUNDLE_SIZE 16 /* how many bytes/bundle */ ++#define KDBA_DEFAULT_IDLEN 3 /* default number of bundles to disassemble */ ++ ++/* ++ * kdba_dis_getsym ++ * ++ * Get a symbol for the disassembler. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * dip Pointer to disassemble_info ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * Not used for kdb. ++ */ ++ ++/* ARGSUSED */ ++static int ++kdba_dis_getsym(bfd_vma addr, disassemble_info *dip) ++{ ++ ++ return 0; ++} ++ ++/* ++ * kdba_printaddress ++ * ++ * Print (symbolically) an address. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * dip Pointer to disassemble_info ++ * flag True if a ":" sequence should follow the address ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * ++ */ ++ ++/* ARGSUSED */ ++static void ++kdba_printaddress(kdb_machreg_t addr, disassemble_info *dip, int flag) ++{ ++ kdb_symtab_t symtab; ++ int spaces = 5; ++ unsigned int offset; ++ int slot; ++ ++ /* Some code prints slot number, some prints "byte" offset ++ * from start of bundle. Standardise on "byte" offset. ++ */ ++ slot = addr & 0x0f; ++ if (slot < 3) ++ slot *= 6; ++ addr = (addr & ~0x0f) + slot; ++ ++ /* ++ * Print a symbol name or address as necessary. ++ */ ++ dip->fprintf_func(dip->stream, "0x%0*lx ", (int)(2*sizeof(addr)), addr); ++ kdbnearsym(addr, &symtab); ++ if (symtab.sym_name) { ++ /* Do not use kdb_symbol_print here, it always does ++ * kdb_printf but we want dip->fprintf_func. ++ */ ++ dip->fprintf_func(dip->stream, "%s", symtab.sym_name); ++ if ((offset = addr - symtab.sym_start) == 0) { ++ spaces += 4; ++ } ++ else { ++ unsigned int o = offset; ++ while (o >>= 4) ++ --spaces; ++ dip->fprintf_func(dip->stream, "+0x%x", offset); ++ } ++ } ++ ++ if (flag) { ++ if (spaces < 1) { ++ spaces = 1; ++ } ++ dip->fprintf_func(dip->stream, ":%*s", spaces, " "); ++ } ++} ++ ++/* Calls outside the current kernel module use a PLT */ ++ ++static int addr_maybe_plt; ++ ++/* The templates below were extracted from arch/ia64/kernel/module.c. The ++ * masks were generated by this quick and dirty program: ++ */ ++ ++#if 0 /* mask program */ ++#include ++ ++#define u64 unsigned long ++ ++/* routines copied from arch/ia64/kernel/patch.c */ ++ ++static void ++ia64_patch (u64 insn_addr, u64 mask, u64 val) ++{ ++ u64 m0, m1, v0, v1, b0, b1, *b = (u64 *) (insn_addr & -16); ++# define insn_mask ((1UL << 41) - 1) ++ unsigned long shift; ++ ++ b0 = b[0]; b1 = b[1]; ++ shift = 5 + 41 * (insn_addr % 16); /* 5 bits of template, then 3 x 41-bit instructions */ ++ if (shift >= 64) { ++ m1 = mask << (shift - 64); ++ v1 = val << (shift - 64); ++ } else { ++ m0 = mask << shift; m1 = mask >> (64 - shift); ++ v0 = val << shift; v1 = val >> (64 - shift); ++ b[0] = (b0 & ~m0) | (v0 & m0); ++ } ++ b[1] = (b1 & ~m1) | (v1 & m1); ++} ++ ++static void ++ia64_patch_imm64 (u64 insn_addr, u64 val) ++{ ++ /* The assembler may generate offset pointing to either slot 1 ++ or slot 2 for a long (2-slot) instruction, occupying slots 1 ++ and 2. */ ++ insn_addr &= -16UL; ++ ia64_patch(insn_addr + 2, ++ 0x01fffefe000UL, ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ ++ | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ ++ | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ ++ | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ ++ | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)); ++ ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); ++} ++ ++static void ++ia64_patch_imm60 (u64 insn_addr, u64 val) ++{ ++ /* The assembler may generate offset pointing to either slot 1 ++ or slot 2 for a long (2-slot) instruction, occupying slots 1 ++ and 2. */ ++ insn_addr &= -16UL; ++ ia64_patch(insn_addr + 2, ++ 0x011ffffe000UL, ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ ++ | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); ++ ia64_patch(insn_addr + 1, 0x1fffffffffcUL, val >> 18); ++} ++ ++struct plt_entry { ++ unsigned char bundle[3][16]; ++}; ++static struct plt_entry ia64_plt_mask; ++ ++int main(void) ++{ ++ int i, j; ++ printf("2 bundle\n"); ++ for (i = 0; i < 2; ++i) ++ for (j = 0; j < 16; ++j) ++ ia64_plt_mask.bundle[i][j] = 0xff; ++ ia64_patch_imm64((u64) (ia64_plt_mask.bundle + 0), 0); ++ ia64_patch_imm60((u64) (ia64_plt_mask.bundle + 1), 0); ++ for (i = 0; i < 2; ++i) { ++ for (j = 0; j < 16; ++j) { ++ printf("0x%02x", ia64_plt_mask.bundle[i][j]); ++ if (j != 15) ++ printf(", "); ++ if (j % 6 == 5 || j == 15) ++ printf("\n"); ++ } ++ } ++ printf("\n3 bundle\n"); ++ for (i = 0; i < 3; ++i) ++ for (j = 0; j < 16; ++j) ++ ia64_plt_mask.bundle[i][j] = 0xff; ++ ia64_patch_imm64((u64) (ia64_plt_mask.bundle + 0), 0); ++ ia64_patch_imm64((u64) (ia64_plt_mask.bundle + 1), 0); ++ for (i = 0; i < 3; ++i) { ++ for (j = 0; j < 16; ++j) { ++ printf("0x%02x", ia64_plt_mask.bundle[i][j]); ++ if (j != 15) ++ printf(", "); ++ if (j % 6 == 5 || j == 15) ++ printf("\n"); ++ } ++ } ++ return 0; ++} ++#endif /* mask program */ ++ ++#ifdef CONFIG_IA64_BRL_EMU ++#define PLT_BUNDLES 3 ++struct plt_entry { ++ unsigned char bundle[PLT_BUNDLES][16]; ++}; ++static const struct plt_entry ia64_plt_template = { ++ { ++ { ++ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* movl r16=TARGET_IP */ ++ 0x02, 0x00, 0x00, 0x60 ++ }, ++ { ++ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /* movl gp=TARGET_GP */ ++ 0x00, 0x00, 0x00, 0x60 ++ }, ++ { ++ 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0 */ ++ 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ ++ 0x60, 0x00, 0x80, 0x00 /* br.few b6 */ ++ } ++ } ++}; ++static const struct plt_entry ia64_plt_mask = { ++ { ++ { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, /* movl r16=TARGET_IP */ ++ 0x0f, 0x08, 0x00, 0xf0 ++ }, ++ { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, /* movl gp=TARGET_GP */ ++ 0x0f, 0x08, 0x00, 0xf0 ++ }, ++ { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* [MIB] nop.m 0 */ ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* mov b6=r16 */ ++ 0xff, 0xff, 0xff, 0xff /* br.few b6 */ ++ } ++}; ++ ++#else /* !CONFIG_IA64_BRL_EMU */ ++ ++#define PLT_BUNDLES 2 ++struct plt_entry { ++ unsigned char bundle[PLT_BUNDLES][16]; ++}; ++static const struct plt_entry ia64_plt_template = { ++ { ++ { ++ 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, /* movl gp=TARGET_GP */ ++ 0x00, 0x00, 0x00, 0x60 ++ }, ++ { ++ 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* brl.many TARGET_IP */ ++ 0x08, 0x00, 0x00, 0xc0 ++ } ++ } ++}; ++static const struct plt_entry ia64_plt_mask = { ++ { ++ { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, /* movl gp=TARGET_GP */ ++ 0x0f, 0x08, 0x00, 0xf0 ++ }, ++ { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* [MLX] nop.m 0 */ ++ 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, /* brl.many TARGET_IP */ ++ 0x0f, 0x00, 0x00, 0xf7 ++ } ++ } ++}; ++#endif /* CONFIG_IA64_BRL_EMU */ ++ ++static inline u64 ++get_slot(u64 bundle, int slot) ++{ ++ switch (slot) { ++ case 0: ++ return (((u64 *)bundle)[0] >> 5) & 0x1ffffffffffLL; ++ case 1: ++ return ((((u64 *)bundle)[0] >> 46) & 0x3ffff) | ++ ((((u64 *)bundle)[1] & 0x7fffff) << 18); ++ default: ++ return (((u64 *)bundle)[1] >> 23) & 0x1ffffffffffLL; ++ } ++} ++ ++static inline u64 ++get_movl (u64 addr) ++{ ++ /* X2 format */ ++ u64 slot1 = get_slot(addr, 1), slot2 = get_slot(addr, 2); ++ u64 i, imm9d, imm5c, ic, imm7b, imm41; ++ i = (slot2 >> 36) & 0x1UL; ++ imm9d = (slot2 >> 27) & 0xfffUL; ++ imm5c = (slot2 >> 22) & 0x1fUL; ++ ic = (slot2 >> 21) & 0x1UL; ++ imm7b = (slot2 >> 13) & 0x7fUL; ++ imm41 = slot1; ++ return (i << 63) | (imm41 << 22) | (ic << 21) | (imm5c << 16) | ++ (imm9d << 7) | imm7b; ++} ++ ++static inline u64 ++get_brl (u64 addr) ++{ ++ /* X3 format */ ++ u64 slot1 = get_slot(addr, 1), slot2 = get_slot(addr, 2); ++ u64 i, imm20b, imm39; ++ i = (slot2 >> 36) & 0x1UL; ++ imm20b = (slot2 >> 13) & 0xfffffUL; ++ imm39 = slot1 >> 2; ++ return ((i << 59) | (imm39 << 20) | imm20b) << 4; ++} ++ ++static bfd_vma ++is_plt(bfd_vma addr) { ++ int i, j; ++ u64 target; ++ struct plt_entry plt; ++ if (kdb_getarea_size(&plt, addr, sizeof(plt))) ++ return 0; ++ for (i = 0; i < PLT_BUNDLES; ++i) { ++ for (j = 0; j < 16; ++j) { ++ if ((plt.bundle[i][j] & ia64_plt_mask.bundle[i][j]) != ++ ia64_plt_template.bundle[i][j]) ++ return 0; ++ } ++ } ++ if (PLT_BUNDLES == 2) { ++ /* brl is IP relative, in second bundle */ ++ target = get_brl(addr + 16) + addr + 16; ++ } else { ++ /* movl is absolute, in first bundle */ ++ target = get_movl(addr); ++ } ++ return target; ++} ++ ++/* ++ * kdba_dis_printaddr ++ * ++ * Print (symbolically) an address. Called by GNU disassembly ++ * code via disassemble_info structure. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * dip Pointer to disassemble_info ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * This function will never append ":" to the printed ++ * symbolic address. If the address may be a PLT entry then try to decode ++ * the PLT information. ++ */ ++ ++static void ++kdba_dis_printaddr(bfd_vma addr, disassemble_info *dip) ++{ ++ bfd_vma target; ++ kdba_printaddress(addr, dip, 0); ++ if (!addr_maybe_plt) ++ return; ++ if (!(target = is_plt(addr))) ++ return; ++ kdb_printf(" PLT --> "); ++ kdba_printaddress(target, dip, 0); ++} ++ ++/* ++ * kdba_dis_getmem ++ * ++ * Fetch 'length' bytes from 'addr' into 'buf'. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * buf Address of buffer to fill with bytes from 'addr' ++ * length Number of bytes to fetch ++ * dip Pointer to disassemble_info ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * ++ */ ++ ++/* ARGSUSED */ ++static int ++kdba_dis_getmem(bfd_vma addr, bfd_byte *buf, unsigned int length, disassemble_info *dip) ++{ ++ return kdb_getarea_size(buf, addr, length); ++} ++ ++/* ++ * kdba_id_parsemode ++ * ++ * Parse IDMODE environment variable string and ++ * set appropriate value into "disassemble_info" structure. ++ * ++ * Parameters: ++ * mode Mode string ++ * dip Disassemble_info structure pointer ++ * Returns: ++ * Locking: ++ * Remarks: ++ * No mode supported yet. ++ */ ++ ++int ++kdba_id_parsemode(const char *mode, disassemble_info *dip) ++{ ++ if (mode && strcmp(mode, "ia64")) ++ return KDB_BADMODE; ++ return 0; ++} ++ ++/* ++ * kdba_check_pc ++ * ++ * Check that the pc is satisfactory. ++ * ++ * Parameters: ++ * pc Program Counter Value. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Can change pc. ++ */ ++ ++void ++kdba_check_pc(kdb_machreg_t *pc) ++{ ++ (*pc) &= ~0xf; /* pc must be 16 byte aligned */ ++} ++ ++/* ++ * kdba_id_printinsn ++ * ++ * Format and print a single bundle at 'pc'. Return the ++ * length of the bundle. ++ * ++ * Parameters: ++ * pc Program Counter Value. ++ * dip Disassemble_info structure pointer ++ * Returns: ++ * Length of instruction, -1 for error. ++ * Locking: ++ * None. ++ * Remarks: ++ * None. ++ */ ++ ++int ++kdba_id_printinsn(kdb_machreg_t pc, disassemble_info *dip) ++{ ++ int ret; ++ int byte = 0; ++ ++ kdba_check_pc(&pc); ++ while (byte < 16) { ++ kdba_dis_printaddr(pc+byte, dip); ++ addr_maybe_plt = 1; ++ ret = print_insn_ia64((kdb_machreg_t)(pc+byte), dip); ++ addr_maybe_plt = 0; ++ dip->fprintf_func(dip->stream, "\n"); ++ if (ret < 0) ++ break; ++ byte += ret; ++ } ++ return(byte); ++} ++ ++/* ++ * kdba_id_init ++ * ++ * Initialize the architecture dependent elements of ++ * the disassembly information structure ++ * for the GNU disassembler. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdba_id_init(disassemble_info *dip) ++{ ++ dip->read_memory_func = kdba_dis_getmem; ++ dip->print_address_func = kdba_dis_printaddr; ++ dip->symbol_at_address_func = kdba_dis_getsym; ++ ++ dip->flavour = bfd_target_elf_flavour; ++ dip->arch = bfd_arch_ia64; ++ dip->endian = BFD_ENDIAN_LITTLE; ++ ++ dip->display_endian = BFD_ENDIAN_LITTLE; ++} +--- /dev/null ++++ b/arch/ia64/kdb/kdba_io.c +@@ -0,0 +1,661 @@ ++/* ++ * Kernel Debugger Architecture Dependent Console I/O handler ++ * ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_SGI_L1_CONSOLE) ++#define HAVE_KDBA_SERIAL_CONSOLE ++#endif ++ ++/* from include/linux/pc_keyb.h on 2.4 */ ++#define KBD_STATUS_REG 0x64 /* Status register (R) */ ++#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ ++#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ ++#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ ++#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ ++#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ ++ ++#ifdef CONFIG_VT_CONSOLE ++#define KDB_BLINK_LED 1 ++#else ++#undef KDB_BLINK_LED ++#endif ++ ++#ifdef CONFIG_KDB_USB ++ ++/* support up to 8 USB keyboards (probably excessive, but...) */ ++#define KDB_USB_NUM_KEYBOARDS 8 ++struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS]; ++ ++extern int kdb_no_usb; ++ ++static unsigned char kdb_usb_keycode[256] = { ++ 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, ++ 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, ++ 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, ++ 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, ++ 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, ++ 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, ++ 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, ++ 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, ++ 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, ++ 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, ++ 150,158,159,128,136,177,178,176,142,152,173,140 ++}; ++ ++/* ++ * kdb_usb_keyboard_attach() ++ * Attach a USB keyboard to kdb. ++ */ ++int ++kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) ++{ ++ int i; ++ int rc = -1; ++ ++ if (kdb_no_usb) ++ return 0; ++ ++ /* ++ * Search through the array of KDB USB keyboards (kdb_usb_kbds) ++ * looking for a free index. If found, assign the keyboard to ++ * the array index. ++ */ ++ ++ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { ++ if (kdb_usb_kbds[i].urb) /* index is already assigned */ ++ continue; ++ ++ /* found a free array index */ ++ kdb_usb_kbds[i].urb = urb; ++ kdb_usb_kbds[i].buffer = buffer; ++ kdb_usb_kbds[i].poll_func = poll_func; ++ ++ rc = 0; /* success */ ++ ++ break; ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); ++ ++/* ++ * kdb_usb_keyboard_detach() ++ * Detach a USB keyboard from kdb. ++ */ ++int ++kdb_usb_keyboard_detach(struct urb *urb) ++{ ++ int i; ++ int rc = -1; ++ ++ if (kdb_no_usb) ++ return 0; ++ ++ /* ++ * Search through the array of KDB USB keyboards (kdb_usb_kbds) ++ * looking for the index with the matching URB. If found, ++ * clear the array index. ++ */ ++ ++ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { ++ if (kdb_usb_kbds[i].urb != urb) ++ continue; ++ ++ /* found it, clear the index */ ++ kdb_usb_kbds[i].urb = NULL; ++ kdb_usb_kbds[i].buffer = NULL; ++ kdb_usb_kbds[i].poll_func = NULL; ++ kdb_usb_kbds[i].caps_lock = 0; ++ ++ rc = 0; /* success */ ++ ++ break; ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); ++ ++/* ++ * get_usb_char ++ * This function drives the USB attached keyboards. ++ * Fetch the USB scancode and decode it. ++ */ ++static int ++get_usb_char(void) ++{ ++ int i; ++ int ret; ++ unsigned char keycode, spec; ++ extern u_short plain_map[], shift_map[], ctrl_map[]; ++ ++ if (kdb_no_usb) ++ return -1; ++ ++ /* ++ * Loop through all the USB keyboard(s) and return ++ * the first character obtained from them. ++ */ ++ ++ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { ++ /* skip uninitialized keyboard array entries */ ++ if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || ++ !kdb_usb_kbds[i].poll_func) ++ continue; ++ ++ /* Transfer char */ ++ ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); ++ ++ if (ret == -EBUSY && kdb_usb_kbds[i].poll_ret != -EBUSY) ++ kdb_printf("NOTICE: USB HC driver BUSY. " ++ "USB keyboard has been disabled.\n"); ++ ++ kdb_usb_kbds[i].poll_ret = ret; ++ ++ if (ret < 0) /* error or no characters, try the next kbd */ ++ continue; ++ ++ spec = kdb_usb_kbds[i].buffer[0]; ++ keycode = kdb_usb_kbds[i].buffer[2]; ++ kdb_usb_kbds[i].buffer[0] = (char)0; ++ kdb_usb_kbds[i].buffer[2] = (char)0; ++ ++ if(kdb_usb_kbds[i].buffer[3]) { ++ kdb_usb_kbds[i].buffer[3] = (char)0; ++ continue; ++ } ++ ++ /* A normal key is pressed, decode it */ ++ if(keycode) ++ keycode = kdb_usb_keycode[keycode]; ++ ++ /* 2 Keys pressed at one time ? */ ++ if (spec && keycode) { ++ switch(spec) ++ { ++ case 0x2: ++ case 0x20: /* Shift */ ++ return shift_map[keycode]; ++ case 0x1: ++ case 0x10: /* Ctrl */ ++ return ctrl_map[keycode]; ++ case 0x4: ++ case 0x40: /* Alt */ ++ break; ++ } ++ } else if (keycode) { /* If only one key pressed */ ++ switch(keycode) ++ { ++ case 0x1C: /* Enter */ ++ return 13; ++ ++ case 0x3A: /* Capslock */ ++ kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); ++ break; ++ case 0x0E: /* Backspace */ ++ return 8; ++ case 0x0F: /* TAB */ ++ return 9; ++ case 0x77: /* Pause */ ++ break ; ++ default: ++ if(!kdb_usb_kbds[i].caps_lock) { ++ return plain_map[keycode]; ++ } ++ else { ++ return shift_map[keycode]; ++ } ++ } ++ } ++ } ++ ++ /* no chars were returned from any of the USB keyboards */ ++ ++ return -1; ++} ++#endif /* CONFIG_KDB_USB */ ++ ++/* ++ * This module contains code to read characters from the keyboard or a serial ++ * port. ++ * ++ * It is used by the kernel debugger, and is polled, not interrupt driven. ++ * ++ */ ++ ++#ifdef KDB_BLINK_LED ++/* ++ * send: Send a byte to the keyboard controller. Used primarily to ++ * alter LED settings. ++ */ ++ ++static void ++kdb_kbdsend(unsigned char byte) ++{ ++ int timeout; ++ for (timeout = 200 * 1000; timeout && (inb(KBD_STATUS_REG) & KBD_STAT_IBF); timeout--); ++ outb(byte, KBD_DATA_REG); ++ udelay(40); ++ for (timeout = 200 * 1000; timeout && (~inb(KBD_STATUS_REG) & KBD_STAT_OBF); timeout--); ++ inb(KBD_DATA_REG); ++ udelay(40); ++} ++ ++static void ++kdb_toggleled(int led) ++{ ++ static int leds; ++ ++ leds ^= led; ++ ++ kdb_kbdsend(KBD_CMD_SET_LEDS); ++ kdb_kbdsend((unsigned char)leds); ++} ++#endif /* KDB_BLINK_LED */ ++ ++#ifdef HAVE_KDBA_SERIAL_CONSOLE ++ ++struct kdb_serial kdb_serial; ++enum kdba_serial_console kdba_serial_console; ++static int get_serial_char(void); ++ ++/* There must be a serial_inp_xxx() and get_serial_char_xxx() for each type ++ * of console. See enum kdba_serial_console in include/asm-$(ARCH)/kdbprivate.h. ++ */ ++ ++#ifdef CONFIG_SERIAL_8250_CONSOLE ++ ++static unsigned int ++serial_inp_standard(const struct kdb_serial *kdb_serial, int offset) ++{ ++ offset <<= kdb_serial->ioreg_shift; ++ ++ switch (kdb_serial->io_type) { ++ case SERIAL_IO_MEM: ++ return readb((void __iomem *)(kdb_serial->iobase + offset)); ++ break; ++ default: ++ return inb(kdb_serial->iobase + offset); ++ break; ++ } ++} ++ ++/* Check if there is a byte ready at the serial port */ ++static int ++get_serial_char_standard(void) ++{ ++ unsigned char ch; ++ static unsigned long fifon; ++ if (fifon == 0) { ++ /* try to set the FIFO */ ++ fifon = kdb_serial.iobase + ++ (UART_FCR << kdb_serial.ioreg_shift); ++ switch (kdb_serial.io_type) { ++ case SERIAL_IO_MEM: ++ writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | ++ UART_FCR_CLEAR_XMIT), (void __iomem *)fifon); ++ break; ++ default: ++ outb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | ++ UART_FCR_CLEAR_XMIT), fifon); ++ break; ++ } ++ } ++ ++ if (kdb_serial.iobase == 0) ++ return -1; ++ ++ if (serial_inp_standard(&kdb_serial, UART_LSR) & UART_LSR_DR) { ++ ch = serial_inp_standard(&kdb_serial, UART_RX); ++ if (ch == 0x7f) ++ ch = 8; ++ return ch; ++ } ++ return -1; ++} ++ ++#else /* !CONFIG_SERIAL_8250_CONSOLE */ ++ ++#define get_serial_char_standard() -1 ++ ++#endif /* CONFIG_SERIAL_8250_CONSOLE */ ++ ++#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE ++ ++extern u64 master_node_bedrock_address; ++ ++/* UART registers on the Bedrock start at 0x80 */ ++ ++extern int l1_serial_in_polled(void); ++extern int l1_control_in_polled(int); ++ ++/* Read a byte from the L1 port. kdb_serial is ignored */ ++static unsigned int ++serial_inp_sgi_l1(const struct kdb_serial *kdb_serial, int offset) ++{ ++ if (offset & 0x80) { ++ int counter = 10000; ++ unsigned int value; ++ while ( counter-- ) { ++ value = l1_serial_in_polled(); ++ /* Gobble up the 0's */ ++ if ( value ) ++ return(value); ++ } ++ return(0); ++ } ++ else { ++ return l1_control_in_polled(offset); ++ } ++} ++ ++/* Check if there is a byte ready at the L1 port. */ ++static int ++get_serial_char_sgi_l1(void) ++{ ++ unsigned char ch; ++ int status; ++ ++ if ((status = serial_inp_sgi_l1(&kdb_serial, UART_LSR)) & UART_LSR_DR) { ++ ch = serial_inp_sgi_l1(&kdb_serial, UART_RX | 0x80); /* bedrock offset */ ++ if (ch == 0x7f) ++ ch = 8; ++ return ch; ++ } ++ return -1; ++} ++ ++#else /* !CONFIG_SERIAL_SGI_L1_CONSOLE */ ++ ++#define get_serial_char_sgi_l1() -1 ++ ++#endif /* CONFIG_SERIAL_SGI_L1_CONSOLE */ ++ ++/* Select the serial console input at run time, to handle generic kernels */ ++ ++static int ++get_serial_char(void) ++{ ++ switch (kdba_serial_console) { ++ case KDBA_SC_NONE: ++ return -1; ++ case KDBA_SC_STANDARD: ++ return get_serial_char_standard(); ++ case KDBA_SC_SGI_L1: ++ return get_serial_char_sgi_l1(); ++ } ++ /* gcc is not smart enough to realize that all paths return before here :( */ ++ return -1; ++} ++ ++#endif /* HAVE_KDBA_SERIAL_CONSOLE */ ++ ++#ifdef CONFIG_VT_CONSOLE ++ ++static int kbd_exists; ++ ++/* ++ * Check if the keyboard controller has a keypress for us. ++ * Some parts (Enter Release, LED change) are still blocking polled here, ++ * but hopefully they are all short. ++ */ ++static int get_kbd_char(void) ++{ ++ int scancode, scanstatus; ++ static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ ++ static int shift_key; /* Shift next keypress */ ++ static int ctrl_key; ++ u_short keychar; ++ extern u_short plain_map[], shift_map[], ctrl_map[]; ++ ++ if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) || ++ (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) { ++ kbd_exists = 0; ++ return -1; ++ } ++ kbd_exists = 1; ++ ++ if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ++ return -1; ++ ++ /* ++ * Fetch the scancode ++ */ ++ scancode = inb(KBD_DATA_REG); ++ scanstatus = inb(KBD_STATUS_REG); ++ ++ /* ++ * Ignore mouse events. ++ */ ++ if (scanstatus & KBD_STAT_MOUSE_OBF) ++ return -1; ++ ++ /* ++ * Ignore release, trigger on make ++ * (except for shift keys, where we want to ++ * keep the shift state so long as the key is ++ * held down). ++ */ ++ ++ if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { ++ /* ++ * Next key may use shift table ++ */ ++ if ((scancode & 0x80) == 0) { ++ shift_key=1; ++ } else { ++ shift_key=0; ++ } ++ return -1; ++ } ++ ++ if ((scancode&0x7f) == 0x1d) { ++ /* ++ * Left ctrl key ++ */ ++ if ((scancode & 0x80) == 0) { ++ ctrl_key = 1; ++ } else { ++ ctrl_key = 0; ++ } ++ return -1; ++ } ++ ++ if ((scancode & 0x80) != 0) ++ return -1; ++ ++ scancode &= 0x7f; ++ ++ /* ++ * Translate scancode ++ */ ++ ++ if (scancode == 0x3a) { ++ /* ++ * Toggle caps lock ++ */ ++ shift_lock ^= 1; ++ ++#ifdef KDB_BLINK_LED ++ kdb_toggleled(0x4); ++#endif ++ return -1; ++ } ++ ++ if (scancode == 0x0e) { ++ /* ++ * Backspace ++ */ ++ return 8; ++ } ++ ++ /* Special Key */ ++ switch (scancode) { ++ case 0xF: /* Tab */ ++ return 9; ++ case 0x53: /* Del */ ++ return 4; ++ case 0x47: /* Home */ ++ return 1; ++ case 0x4F: /* End */ ++ return 5; ++ case 0x4B: /* Left */ ++ return 2; ++ case 0x48: /* Up */ ++ return 16; ++ case 0x50: /* Down */ ++ return 14; ++ case 0x4D: /* Right */ ++ return 6; ++ } ++ ++ if (scancode == 0xe0) { ++ return -1; ++ } ++ ++ /* ++ * For Japanese 86/106 keyboards ++ * See comment in drivers/char/pc_keyb.c. ++ * - Masahiro Adegawa ++ */ ++ if (scancode == 0x73) { ++ scancode = 0x59; ++ } else if (scancode == 0x7d) { ++ scancode = 0x7c; ++ } ++ ++ if (!shift_lock && !shift_key && !ctrl_key) { ++ keychar = plain_map[scancode]; ++ } else if (shift_lock || shift_key) { ++ keychar = shift_map[scancode]; ++ } else if (ctrl_key) { ++ keychar = ctrl_map[scancode]; ++ } else { ++ keychar = 0x0020; ++ kdb_printf("Unknown state/scancode (%d)\n", scancode); ++ } ++ keychar &= 0x0fff; ++ switch (KTYP(keychar)) { ++ case KT_LETTER: ++ case KT_LATIN: ++ if (isprint(keychar)) ++ break; /* printable characters */ ++ /* drop through */ ++ case KT_SPEC: ++ if (keychar == K_ENTER) ++ break; ++ /* drop through */ ++ default: ++ return(-1); /* ignore unprintables */ ++ } ++ ++ if ((scancode & 0x7f) == 0x1c) { ++ /* ++ * enter key. All done. Absorb the release scancode. ++ */ ++ while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ++ ; ++ ++ /* ++ * Fetch the scancode ++ */ ++ scancode = inb(KBD_DATA_REG); ++ scanstatus = inb(KBD_STATUS_REG); ++ ++ while (scanstatus & KBD_STAT_MOUSE_OBF) { ++ scancode = inb(KBD_DATA_REG); ++ scanstatus = inb(KBD_STATUS_REG); ++ } ++ ++ if (scancode != 0x9c) { ++ /* ++ * Wasn't an enter-release, why not? ++ */ ++ kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", ++ scancode, scanstatus); ++ } ++ ++ kdb_printf("\n"); ++ return 13; ++ } ++ ++ return keychar & 0xff; ++} ++#endif /* CONFIG_VT_CONSOLE */ ++ ++#ifdef KDB_BLINK_LED ++ ++/* Leave numlock alone, setting it messes up laptop keyboards with the keypad ++ * mapped over normal keys. ++ */ ++static int kdba_blink_mask = 0x1 | 0x4; ++ ++#ifdef CONFIG_SMP ++#define BOGOMIPS (local_cpu_data->loops_per_jiffy/(500000/HZ)) ++#else ++#define BOGOMIPS (loops_per_jiffy/(500000/HZ)) ++#endif ++static int blink_led(void) ++{ ++ static long delay; ++ ++ if (kbd_exists == 0) ++ return -1; ++ ++ if (--delay < 0) { ++ if (BOGOMIPS == 0) /* early kdb */ ++ delay = 150000000/1000; /* arbitrary bogomips */ ++ else ++ delay = 150000000/BOGOMIPS; /* Roughly 1 second when polling */ ++ kdb_toggleled(kdba_blink_mask); ++ } ++ return -1; ++} ++#endif ++ ++get_char_func poll_funcs[] = { ++#if defined(CONFIG_VT_CONSOLE) ++ get_kbd_char, ++#endif ++#ifdef HAVE_KDBA_SERIAL_CONSOLE ++ get_serial_char, ++#endif ++#ifdef KDB_BLINK_LED ++ blink_led, ++#endif ++#ifdef CONFIG_KDB_USB ++ get_usb_char, ++#endif ++ NULL ++}; ++ ++/* Dummy versions of kdba_local_arch_setup, kdba_local_arch_cleanup. ++ * FIXME: ia64 with legacy keyboard might need the same code as i386. ++ */ ++ ++void kdba_local_arch_setup(void) {} ++void kdba_local_arch_cleanup(void) {} +--- /dev/null ++++ b/arch/ia64/kdb/kdba_jmp.S +@@ -0,0 +1,394 @@ ++/* ++ * Kernel Debugger Architecture Dependent Longjump Support. ++ */ ++ ++/* setjmp() and longjmp() assembler support for kdb on ia64. ++ ++ This code was copied from glibc CVS as of 2001-06-27 and modified where ++ necessary to fit the kernel. No glibc lines were changed or deleted, all ++ adjustments are wrapped in #ifdef __KERNEL__, except for the added ++ .mem.offset lines, they work in or out of the kenrel. The original code is ++ in sysdeps/unix/sysv/linux/ia64/{setjmp.S,__longjmp.S}. ++ ++ glibc has setjmp (save signals) and _setjmp (do not save signals). Kernel ++ code does not have signals, only kdba_setjmp_asm() is used. ++ ++ Keith Owens 2001-06-27 ++ */ ++ ++/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. ++ Contributed by David Mosberger-Tang . ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Library General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, write to the Free Software Foundation, Inc., ++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ The layout of the jmp_buf is as follows. This is subject to change ++ and user-code should never depend on the particular layout of ++ jmp_buf! ++ ++ ++ offset: description: ++ ------- ------------ ++ 0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS) ++ 0x008 r1 (gp) ++ 0x010 caller's unat ++ 0x018 fpsr ++ 0x020 r4 ++ 0x028 r5 ++ 0x030 r6 ++ 0x038 r7 ++ 0x040 rp (b0) ++ 0x048 b1 ++ 0x050 b2 ++ 0x058 b3 ++ 0x060 b4 ++ 0x068 b5 ++ 0x070 ar.pfs ++ 0x078 ar.lc ++ 0x080 pr ++ 0x088 ar.bsp ; unchangeable (see __longjmp.S) ++ 0x090 ar.unat ++ 0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat) ++ 0x0a0 f2 ++ 0x0b0 f3 ++ 0x0c0 f4 ++ 0x0d0 f5 ++ 0x0e0 f16 ++ 0x0f0 f17 ++ 0x100 f18 ++ 0x110 f19 ++ 0x120 f20 ++ 0x130 f21 ++ 0x130 f22 ++ 0x140 f23 ++ 0x150 f24 ++ 0x160 f25 ++ 0x170 f26 ++ 0x180 f27 ++ 0x190 f28 ++ 0x1a0 f29 ++ 0x1b0 f30 ++ 0x1c0 f31 */ ++ ++#ifndef __KERNEL__ ++ ++#include ++#include ++ ++ /* The following two entry points are the traditional entry points: */ ++ ++LEAF(setjmp) ++ alloc r8=ar.pfs,2,0,0,0 ++ mov in1=1 ++ br.cond.sptk.many __sigsetjmp ++END(setjmp) ++ ++LEAF(_setjmp) ++ alloc r8=ar.pfs,2,0,0,0 ++ mov in1=0 ++ br.cond.sptk.many __sigsetjmp ++END(_setjmp) ++ ++ /* __sigsetjmp(__jmp_buf buf, int savemask) */ ++ ++ENTRY(__sigsetjmp) ++ ++#else /* __KERNEL __ */ ++#include ++#define ret br.ret.sptk.few rp ++GLOBAL_ENTRY(kdba_setjmp) ++#endif /* !__KERNEL__ */ ++ ++ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) ++ alloc loc1=ar.pfs,2,2,2,0 ++ mov r16=ar.unat ++ ;; ++ mov r17=ar.fpsr ++ mov r2=in0 ++ add r3=8,in0 ++ ;; ++.mem.offset 0,0; ++ st8.spill.nta [r2]=sp,16 // r12 (sp) ++.mem.offset 8,0; ++ st8.spill.nta [r3]=gp,16 // r1 (gp) ++ ;; ++ st8.nta [r2]=r16,16 // save caller's unat ++ st8.nta [r3]=r17,16 // save fpsr ++ add r8=0xa0,in0 ++ ;; ++.mem.offset 160,0; ++ st8.spill.nta [r2]=r4,16 // r4 ++.mem.offset 168,0; ++ st8.spill.nta [r3]=r5,16 // r5 ++ add r9=0xb0,in0 ++ ;; ++ stf.spill.nta [r8]=f2,32 ++ stf.spill.nta [r9]=f3,32 ++ mov loc0=rp ++ .body ++ ;; ++ stf.spill.nta [r8]=f4,32 ++ stf.spill.nta [r9]=f5,32 ++ mov r17=b1 ++ ;; ++ stf.spill.nta [r8]=f16,32 ++ stf.spill.nta [r9]=f17,32 ++ mov r18=b2 ++ ;; ++ stf.spill.nta [r8]=f18,32 ++ stf.spill.nta [r9]=f19,32 ++ mov r19=b3 ++ ;; ++ stf.spill.nta [r8]=f20,32 ++ stf.spill.nta [r9]=f21,32 ++ mov r20=b4 ++ ;; ++ stf.spill.nta [r8]=f22,32 ++ stf.spill.nta [r9]=f23,32 ++ mov r21=b5 ++ ;; ++ stf.spill.nta [r8]=f24,32 ++ stf.spill.nta [r9]=f25,32 ++ mov r22=ar.lc ++ ;; ++ stf.spill.nta [r8]=f26,32 ++ stf.spill.nta [r9]=f27,32 ++ mov r24=pr ++ ;; ++ stf.spill.nta [r8]=f28,32 ++ stf.spill.nta [r9]=f29,32 ++ ;; ++ stf.spill.nta [r8]=f30 ++ stf.spill.nta [r9]=f31 ++ ++.mem.offset 0,0; ++ st8.spill.nta [r2]=r6,16 // r6 ++.mem.offset 8,0; ++ st8.spill.nta [r3]=r7,16 // r7 ++ ;; ++ mov r23=ar.bsp ++ mov r25=ar.unat ++#ifndef __KERNEL__ ++ mov out0=in0 ++#endif /* !__KERNEL__ */ ++ ++ st8.nta [r2]=loc0,16 // b0 ++ st8.nta [r3]=r17,16 // b1 ++#ifndef __KERNEL__ ++ mov out1=in1 ++#endif /* !__KERNEL__ */ ++ ;; ++ st8.nta [r2]=r18,16 // b2 ++ st8.nta [r3]=r19,16 // b3 ++ ;; ++ st8.nta [r2]=r20,16 // b4 ++ st8.nta [r3]=r21,16 // b5 ++ ;; ++ st8.nta [r2]=loc1,16 // ar.pfs ++ st8.nta [r3]=r22,16 // ar.lc ++ ;; ++ st8.nta [r2]=r24,16 // pr ++ st8.nta [r3]=r23,16 // ar.bsp ++ ;; ++ st8.nta [r2]=r25 // ar.unat ++ st8.nta [r3]=in0 // &__jmp_buf ++#ifndef __KERNEL__ ++ br.call.dpnt.few rp=__sigjmp_save ++.ret0: // force a new bundle ::q ++#endif /* !_KERNEL__ */ ++ mov r8=0 ++ mov rp=loc0 ++ mov ar.pfs=loc1 ++ ret ++#ifndef __KERNEL__ ++END(__sigsetjmp) ++ ++weak_extern(_setjmp) ++weak_extern(setjmp) ++ ++#else /* __KERNEL__ */ ++END(kdba_setjmp) ++#endif /* !_KERNEL__ */ ++ ++/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. ++ Contributed by David Mosberger-Tang . ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Library General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, write to the Free Software Foundation, Inc., ++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++ Note that __sigsetjmp() did NOT flush the register stack. Instead, ++ we do it here since __longjmp() is usually much less frequently ++ invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp() ++ didn't (and wouldn't be able to) save ar.rnat either. This is a problem ++ because if we're not careful, we could end up loading random NaT bits. ++ There are two cases: ++ ++ (i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp) ++ ar.rnat contains the desired bits---preserve ar.rnat ++ across loadrs and write to ar.bspstore ++ ++ (ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp) ++ The desired ar.rnat is stored in ++ ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those ++ bits into ar.rnat after setting ar.bspstore. */ ++ ++#ifndef __KERNEL__ ++#include ++#include ++#endif /* !__KERNEL__ */ ++ ++# define pPos p6 /* is rotate count positive? */ ++# define pNeg p7 /* is rotate count negative? */ ++ ++ ++ /* __longjmp(__jmp_buf buf, int val) */ ++ ++#ifndef __KERNEL__ ++LEAF(__longjmp) ++#else /* __KERNEL__ */ ++GLOBAL_ENTRY(kdba_longjmp) ++#endif /* !__KERNEL__ */ ++ alloc r8=ar.pfs,2,1,0,0 ++ mov r27=ar.rsc ++ add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr ++ ;; ++ ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr ++ mov r10=ar.bsp ++ and r11=~0x3,r27 // clear ar.rsc.mode ++ ;; ++ flushrs // flush dirty regs to backing store (must be first in insn grp) ++ ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp ++ sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf ++ ;; ++ ld8 r25=[r2] // r25 <- jmpbuf.ar_unat ++ extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f ++ ;; ++ cmp.lt pNeg,pPos=r8,r0 ++ mov r2=in0 ++ ;; ++(pPos) mov r16=r8 ++(pNeg) add r16=64,r8 ++(pPos) sub r17=64,r8 ++(pNeg) sub r17=r0,r8 ++ ;; ++ mov ar.rsc=r11 // put RSE in enforced lazy mode ++ shr.u r8=r25,r16 ++ add r3=8,in0 // r3 <- &jmpbuf.r1 ++ shl r9=r25,r17 ++ ;; ++ or r25=r8,r9 ++ ;; ++ mov r26=ar.rnat ++ mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12) ++ ;; ++ ld8.fill.nta sp=[r2],16 // r12 (sp) ++ ld8.fill.nta gp=[r3],16 // r1 (gp) ++ dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp) ++ ;; ++ ld8.nta r16=[r2],16 // caller's unat ++ ld8.nta r17=[r3],16 // fpsr ++ ;; ++ ld8.fill.nta r4=[r2],16 // r4 ++ ld8.fill.nta r5=[r3],16 // r5 (gp) ++ cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp) ++ ;; ++ ld8.fill.nta r6=[r2],16 // r6 ++ ld8.fill.nta r7=[r3],16 // r7 ++ ;; ++ mov ar.unat=r16 // restore caller's unat ++ mov ar.fpsr=r17 // restore fpsr ++ ;; ++ ld8.nta r16=[r2],16 // b0 ++ ld8.nta r17=[r3],16 // b1 ++ ;; ++(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp) ++ mov ar.bspstore=r23 // restore ar.bspstore ++ ;; ++ ld8.nta r18=[r2],16 // b2 ++ ld8.nta r19=[r3],16 // b3 ++ ;; ++ ld8.nta r20=[r2],16 // b4 ++ ld8.nta r21=[r3],16 // b5 ++ ;; ++ ld8.nta r11=[r2],16 // ar.pfs ++ ld8.nta r22=[r3],56 // ar.lc ++ ;; ++ ld8.nta r24=[r2],32 // pr ++ mov b0=r16 ++ ;; ++ ldf.fill.nta f2=[r2],32 ++ ldf.fill.nta f3=[r3],32 ++ mov b1=r17 ++ ;; ++ ldf.fill.nta f4=[r2],32 ++ ldf.fill.nta f5=[r3],32 ++ mov b2=r18 ++ ;; ++ ldf.fill.nta f16=[r2],32 ++ ldf.fill.nta f17=[r3],32 ++ mov b3=r19 ++ ;; ++ ldf.fill.nta f18=[r2],32 ++ ldf.fill.nta f19=[r3],32 ++ mov b4=r20 ++ ;; ++ ldf.fill.nta f20=[r2],32 ++ ldf.fill.nta f21=[r3],32 ++ mov b5=r21 ++ ;; ++ ldf.fill.nta f22=[r2],32 ++ ldf.fill.nta f23=[r3],32 ++ mov ar.lc=r22 ++ ;; ++ ldf.fill.nta f24=[r2],32 ++ ldf.fill.nta f25=[r3],32 ++ cmp.eq p8,p9=0,in1 ++ ;; ++ ldf.fill.nta f26=[r2],32 ++ ldf.fill.nta f27=[r3],32 ++ mov ar.pfs=r11 ++ ;; ++ ldf.fill.nta f28=[r2],32 ++ ldf.fill.nta f29=[r3],32 ++ ;; ++ ldf.fill.nta f30=[r2] ++ ldf.fill.nta f31=[r3] ++(p8) mov r8=1 ++ ++ mov ar.rnat=r26 // restore ar.rnat ++ ;; ++ mov ar.rsc=r27 // restore ar.rsc ++(p9) mov r8=in1 ++ ++ invala // virt. -> phys. regnum mapping may change ++ mov pr=r24,-1 ++ ret ++#ifndef __KERNEL__ ++END(__longjmp) ++#else /* __KERNEL__ */ ++END(kdba_longjmp) ++#endif /* !_KERNEL__ */ +--- /dev/null ++++ b/arch/ia64/kdb/kdba_pod.c +@@ -0,0 +1,64 @@ ++/* ++ * Kernel Debugger Architecture Dependent POD functions. ++ * ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jesse Barnes"); ++MODULE_DESCRIPTION("Enter POD through KDB"); ++MODULE_LICENSE("GPL"); ++ ++/** ++ * kdba_pod - enter POD mode from kdb ++ * @argc: arg count ++ * @argv: arg values ++ * ++ * Enter POD mode from kdb using SGI SN specific SAL function call. ++ */ ++static int ++kdba_pod(int argc, const char **argv) ++{ ++ kdb_printf("WARNING: pod commands are dangerous unless you know exactly\n" ++ "what you are doing. If in doubt, type exit immediately.\n"); ++ return ia64_sn_pod_mode(); ++} ++ ++/** ++ * kdba_pod_init - register 'pod' command with kdb ++ * ++ * Register the 'pod' command with kdb at load time. ++ */ ++static int __init ++kdba_pod_init(void) ++{ ++ if (ia64_platform_is("sn2")) ++ kdb_register("pod", kdba_pod, NULL, "Enter POD", 0); ++ ++ return 0; ++} ++ ++/** ++ * kdba_pod_exit - unregister the 'pod' command ++ * ++ * Tell kdb that the 'pod' command is no longer available. ++ */ ++static void __exit ++kdba_pod_exit(void) ++{ ++ if (ia64_platform_is("sn2")) ++ kdb_unregister("pod"); ++} ++ ++module_init(kdba_pod_init) ++module_exit(kdba_pod_exit) +--- /dev/null ++++ b/arch/ia64/kdb/kdba_support.c +@@ -0,0 +1,1720 @@ ++/* ++ * Kernel Debugger Architecture Independent Support Functions ++ * ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ * Copyright (C) David Mosberger-Tang ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_KDB_KDUMP ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_SMP ++#include ++#endif ++#include ++ ++struct kdb_running_process *kdb_running_process_save; /* [NR_CPUS] */ ++static int kdba_show_handlers = 0; ++ ++static int ++kdba_itm (int argc, const char **argv) ++{ ++ int diag; ++ unsigned long val; ++ ++ diag = kdbgetularg(argv[1], &val); ++ if (diag) ++ return diag; ++ kdb_printf("new itm=" kdb_machreg_fmt "\n", val); ++ ++ ia64_set_itm(val); ++ return 0; ++} ++ ++static void ++kdba_show_intregs(void) ++{ ++ u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv; ++ ++ asm ("mov %0=cr.lid" : "=r"(lid)); ++ asm ("mov %0=cr.tpr" : "=r"(tpr)); ++ asm ("mov %0=cr.lrr0" : "=r"(lrr0)); ++ asm ("mov %0=cr.lrr1" : "=r"(lrr1)); ++ kdb_printf("lid=" kdb_machreg_fmt ", tpr=" kdb_machreg_fmt ", lrr0=" kdb_machreg_fmt ", llr1=" kdb_machreg_fmt "\n", lid, tpr, lrr0, lrr1); ++ ++ asm ("mov %0=cr.itv" : "=r"(itv)); ++ asm ("mov %0=cr.pmv" : "=r"(pmv)); ++ asm ("mov %0=cr.cmcv" : "=r"(cmcv)); ++ kdb_printf("itv=" kdb_machreg_fmt ", pmv=" kdb_machreg_fmt ", cmcv=" kdb_machreg_fmt "\n", itv, pmv, cmcv); ++ ++ kdb_printf("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", ++ ia64_getreg(_IA64_REG_CR_IRR0), ia64_getreg(_IA64_REG_CR_IRR1), ia64_getreg(_IA64_REG_CR_IRR2), ia64_getreg(_IA64_REG_CR_IRR3)); ++ ++ kdb_printf("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm()); ++} ++ ++static int ++kdba_sir (int argc, const char **argv) ++{ ++ kdba_show_intregs(); ++ ++ return 0; ++} ++ ++/* ++ * kdba_pt_regs ++ * ++ * Format a struct pt_regs ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no address is supplied, it uses the current irq pt_regs. ++ */ ++ ++static int ++kdba_pt_regs(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ int nextarg; ++ struct pt_regs *p; ++ ++ if (argc == 0) { ++ addr = (kdb_machreg_t) get_irq_regs(); ++ } else if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ p = (struct pt_regs *) addr; ++ kdb_printf("struct pt_regs %p-%p\n", p, (unsigned char *)p + sizeof(*p) - 1); ++ kdb_print_nameval("b6", p->b6); ++ kdb_print_nameval("b7", p->b7); ++ kdb_printf(" ar_csd 0x%lx\n", p->ar_csd); ++ kdb_printf(" ar_ssd 0x%lx\n", p->ar_ssd); ++ kdb_print_nameval("r8", p->r8); ++ kdb_print_nameval("r9", p->r9); ++ kdb_print_nameval("r10", p->r10); ++ kdb_print_nameval("r11", p->r11); ++ kdb_printf(" cr_ipsr 0x%lx\n", p->cr_ipsr); ++ kdb_print_nameval("cr_iip", p->cr_iip); ++ kdb_printf(" cr_ifs 0x%lx\n", p->cr_ifs); ++ kdb_printf(" ar_unat 0x%lx\n", p->ar_unat); ++ kdb_printf(" ar_pfs 0x%lx\n", p->ar_pfs); ++ kdb_printf(" ar_rsc 0x%lx\n", p->ar_rsc); ++ kdb_printf(" ar_rnat 0x%lx\n", p->ar_rnat); ++ kdb_printf(" ar_bspstore 0x%lx\n", p->ar_bspstore); ++ kdb_printf(" pr 0x%lx\n", p->pr); ++ kdb_print_nameval("b0", p->b0); ++ kdb_printf(" loadrs 0x%lx\n", p->loadrs); ++ kdb_print_nameval("r1", p->r1); ++ kdb_print_nameval("r12", p->r12); ++ kdb_print_nameval("r13", p->r13); ++ kdb_printf(" ar_fpsr 0x%lx\n", p->ar_fpsr); ++ kdb_print_nameval("r15", p->r15); ++ kdb_print_nameval("r14", p->r14); ++ kdb_print_nameval("r2", p->r2); ++ kdb_print_nameval("r3", p->r3); ++ kdb_print_nameval("r16", p->r16); ++ kdb_print_nameval("r17", p->r17); ++ kdb_print_nameval("r18", p->r18); ++ kdb_print_nameval("r19", p->r19); ++ kdb_print_nameval("r20", p->r20); ++ kdb_print_nameval("r21", p->r21); ++ kdb_print_nameval("r22", p->r22); ++ kdb_print_nameval("r23", p->r23); ++ kdb_print_nameval("r24", p->r24); ++ kdb_print_nameval("r25", p->r25); ++ kdb_print_nameval("r26", p->r26); ++ kdb_print_nameval("r27", p->r27); ++ kdb_print_nameval("r28", p->r28); ++ kdb_print_nameval("r29", p->r29); ++ kdb_print_nameval("r30", p->r30); ++ kdb_print_nameval("r31", p->r31); ++ kdb_printf(" ar_ccv 0x%lx\n", p->ar_ccv); ++ kdb_printf(" f6 0x%lx 0x%lx\n", p->f6.u.bits[0], p->f6.u.bits[1]); ++ kdb_printf(" f7 0x%lx 0x%lx\n", p->f7.u.bits[0], p->f7.u.bits[1]); ++ kdb_printf(" f8 0x%lx 0x%lx\n", p->f8.u.bits[0], p->f8.u.bits[1]); ++ kdb_printf(" f9 0x%lx 0x%lx\n", p->f9.u.bits[0], p->f9.u.bits[1]); ++ kdb_printf(" f10 0x%lx 0x%lx\n", p->f10.u.bits[0], p->f10.u.bits[1]); ++ kdb_printf(" f11 0x%lx 0x%lx\n", p->f11.u.bits[0], p->f11.u.bits[1]); ++ ++ return 0; ++} ++ ++/* ++ * kdba_stackdepth ++ * ++ * Print processes that are using more than a specific percentage of their ++ * stack. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no percentage is supplied, it uses 60. ++ */ ++ ++static int ++kdba_stackdepth(int argc, const char **argv) ++{ ++ int diag, threshold, used; ++ unsigned long percentage; ++ unsigned long esp; ++ long offset = 0; ++ int nextarg; ++ struct task_struct *p, *g; ++ struct switch_stack *sw; ++ ++ if (argc == 0) { ++ percentage = 60; ++ } else if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &percentage, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ percentage = max_t(int, percentage, 1); ++ percentage = min_t(int, percentage, 100); ++ threshold = ((2 * THREAD_SIZE * percentage) / 100 + 1) >> 1; ++ kdb_printf("stackdepth: processes using more than %ld%% (%d bytes) of stack\n", ++ percentage, threshold); ++ kdb_do_each_thread(g, p) { ++ if (kdb_task_has_cpu(p)) { ++ struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p); ++ if (krp->seqno) ++ sw = krp->arch.sw; ++ else ++ sw = NULL; ++ } else ++ sw = (struct switch_stack *) (p->thread.ksp + 16); ++ if (!sw) ++ continue; ++ esp = (unsigned long) sw; ++ used = THREAD_SIZE - (esp - sw->ar_bspstore); ++ if (used >= threshold) { ++ kdb_ps1(p); ++ kdb_printf(" esp %lx bsp %lx used %d\n", esp, sw->ar_bspstore, used); ++ } ++ } kdb_while_each_thread(g, p); ++ ++ return 0; ++} ++ ++/* ++ * kdb_switch_stack ++ * ++ * Format a struct switch_stack ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no address is supplied, it uses kdb_running_process[smp_processor_id()].arch.sw. ++ */ ++ ++static int ++kdba_switch_stack(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ int nextarg; ++ struct switch_stack *p; ++ ++ if (argc == 0) { ++ addr = (kdb_machreg_t) kdb_running_process[smp_processor_id()].arch.sw; ++ } else if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ p = (struct switch_stack *) addr; ++ kdb_printf("struct switch_stack %p-%p\n", p, (unsigned char *)p + sizeof(*p) - 1); ++ kdb_printf(" caller_unat 0x%lx\n", p->caller_unat); ++ kdb_printf(" ar_fpsr 0x%lx\n", p->ar_fpsr); ++ kdb_printf(" f2 0x%lx 0x%lx\n", p->f2.u.bits[0], p->f2.u.bits[1]); ++ kdb_printf(" f3 0x%lx 0x%lx\n", p->f3.u.bits[0], p->f3.u.bits[1]); ++ kdb_printf(" f4 0x%lx 0x%lx\n", p->f4.u.bits[0], p->f4.u.bits[1]); ++ kdb_printf(" f5 0x%lx 0x%lx\n", p->f5.u.bits[0], p->f5.u.bits[1]); ++ kdb_printf(" f12 0x%lx 0x%lx\n", p->f12.u.bits[0], p->f12.u.bits[1]); ++ kdb_printf(" f13 0x%lx 0x%lx\n", p->f13.u.bits[0], p->f13.u.bits[1]); ++ kdb_printf(" f14 0x%lx 0x%lx\n", p->f14.u.bits[0], p->f14.u.bits[1]); ++ kdb_printf(" f15 0x%lx 0x%lx\n", p->f15.u.bits[0], p->f15.u.bits[1]); ++ kdb_printf(" f16 0x%lx 0x%lx\n", p->f16.u.bits[0], p->f16.u.bits[1]); ++ kdb_printf(" f17 0x%lx 0x%lx\n", p->f17.u.bits[0], p->f17.u.bits[1]); ++ kdb_printf(" f18 0x%lx 0x%lx\n", p->f18.u.bits[0], p->f18.u.bits[1]); ++ kdb_printf(" f19 0x%lx 0x%lx\n", p->f19.u.bits[0], p->f19.u.bits[1]); ++ kdb_printf(" f20 0x%lx 0x%lx\n", p->f20.u.bits[0], p->f20.u.bits[1]); ++ kdb_printf(" f21 0x%lx 0x%lx\n", p->f21.u.bits[0], p->f21.u.bits[1]); ++ kdb_printf(" f22 0x%lx 0x%lx\n", p->f22.u.bits[0], p->f22.u.bits[1]); ++ kdb_printf(" f23 0x%lx 0x%lx\n", p->f23.u.bits[0], p->f23.u.bits[1]); ++ kdb_printf(" f24 0x%lx 0x%lx\n", p->f24.u.bits[0], p->f24.u.bits[1]); ++ kdb_printf(" f25 0x%lx 0x%lx\n", p->f25.u.bits[0], p->f25.u.bits[1]); ++ kdb_printf(" f26 0x%lx 0x%lx\n", p->f26.u.bits[0], p->f26.u.bits[1]); ++ kdb_printf(" f27 0x%lx 0x%lx\n", p->f27.u.bits[0], p->f27.u.bits[1]); ++ kdb_printf(" f28 0x%lx 0x%lx\n", p->f28.u.bits[0], p->f28.u.bits[1]); ++ kdb_printf(" f29 0x%lx 0x%lx\n", p->f29.u.bits[0], p->f29.u.bits[1]); ++ kdb_printf(" f30 0x%lx 0x%lx\n", p->f30.u.bits[0], p->f30.u.bits[1]); ++ kdb_printf(" f31 0x%lx 0x%lx\n", p->f31.u.bits[0], p->f31.u.bits[1]); ++ kdb_print_nameval("r4", p->r4); ++ kdb_print_nameval("r5", p->r5); ++ kdb_print_nameval("r6", p->r6); ++ kdb_print_nameval("r7", p->r7); ++ kdb_print_nameval("b0", p->b0); ++ kdb_print_nameval("b1", p->b1); ++ kdb_print_nameval("b2", p->b2); ++ kdb_print_nameval("b3", p->b3); ++ kdb_print_nameval("b4", p->b4); ++ kdb_print_nameval("b5", p->b5); ++ kdb_printf(" ar_pfs 0x%lx\n", p->ar_pfs); ++ kdb_printf(" ar_lc 0x%lx\n", p->ar_lc); ++ kdb_printf(" ar_unat 0x%lx\n", p->ar_unat); ++ kdb_printf(" ar_rnat 0x%lx\n", p->ar_rnat); ++ kdb_printf(" ar_bspstore 0x%lx\n", p->ar_bspstore); ++ kdb_printf(" pr 0x%lx\n", p->pr); ++ ++ return 0; ++} ++ ++/* ++ * kdb_minstate ++ * ++ * Format the PAL minstate area. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * None. ++ */ ++ ++static int ++kdba_minstate(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ int nextarg; ++ pal_min_state_area_t *p; ++ ++ if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ p = (pal_min_state_area_t *) addr; ++ kdb_printf("PAL minstate %p-%p\n", p, (unsigned char *)p + sizeof(*p) - 1); ++ kdb_printf(" pmsa_nat_bits 0x%lx\n", p->pmsa_nat_bits); ++ kdb_print_nameval("r1", p->pmsa_gr[1-1]); ++ kdb_print_nameval("r2", p->pmsa_gr[2-1]); ++ kdb_print_nameval("r3", p->pmsa_gr[3-1]); ++ kdb_print_nameval("r4", p->pmsa_gr[4-1]); ++ kdb_print_nameval("r5", p->pmsa_gr[5-1]); ++ kdb_print_nameval("r6", p->pmsa_gr[6-1]); ++ kdb_print_nameval("r7", p->pmsa_gr[7-1]); ++ kdb_print_nameval("r8", p->pmsa_gr[8-1]); ++ kdb_print_nameval("r9", p->pmsa_gr[9-1]); ++ kdb_print_nameval("r10", p->pmsa_gr[10-1]); ++ kdb_print_nameval("r11", p->pmsa_gr[11-1]); ++ kdb_print_nameval("r12", p->pmsa_gr[12-1]); ++ kdb_print_nameval("r13", p->pmsa_gr[13-1]); ++ kdb_print_nameval("r14", p->pmsa_gr[14-1]); ++ kdb_print_nameval("r15", p->pmsa_gr[15-1]); ++ kdb_printf(" Bank 0\n"); ++ kdb_print_nameval("r16", p->pmsa_bank0_gr[16-16]); ++ kdb_print_nameval("r17", p->pmsa_bank0_gr[17-16]); ++ kdb_print_nameval("r18", p->pmsa_bank0_gr[18-16]); ++ kdb_print_nameval("r19", p->pmsa_bank0_gr[19-16]); ++ kdb_print_nameval("r20", p->pmsa_bank0_gr[20-16]); ++ kdb_print_nameval("r21", p->pmsa_bank0_gr[21-16]); ++ kdb_print_nameval("r22", p->pmsa_bank0_gr[22-16]); ++ kdb_print_nameval("r23", p->pmsa_bank0_gr[23-16]); ++ kdb_print_nameval("r24", p->pmsa_bank0_gr[24-16]); ++ kdb_print_nameval("r25", p->pmsa_bank0_gr[25-16]); ++ kdb_print_nameval("r26", p->pmsa_bank0_gr[26-16]); ++ kdb_print_nameval("r27", p->pmsa_bank0_gr[27-16]); ++ kdb_print_nameval("r28", p->pmsa_bank0_gr[28-16]); ++ kdb_print_nameval("r29", p->pmsa_bank0_gr[29-16]); ++ kdb_print_nameval("r30", p->pmsa_bank0_gr[30-16]); ++ kdb_print_nameval("r31", p->pmsa_bank0_gr[31-16]); ++ kdb_printf(" Bank 1\n"); ++ kdb_print_nameval("r16", p->pmsa_bank1_gr[16-16]); ++ kdb_print_nameval("r17", p->pmsa_bank1_gr[17-16]); ++ kdb_print_nameval("r18", p->pmsa_bank1_gr[18-16]); ++ kdb_print_nameval("r19", p->pmsa_bank1_gr[19-16]); ++ kdb_print_nameval("r20", p->pmsa_bank1_gr[20-16]); ++ kdb_print_nameval("r21", p->pmsa_bank1_gr[21-16]); ++ kdb_print_nameval("r22", p->pmsa_bank1_gr[22-16]); ++ kdb_print_nameval("r23", p->pmsa_bank1_gr[23-16]); ++ kdb_print_nameval("r24", p->pmsa_bank1_gr[24-16]); ++ kdb_print_nameval("r25", p->pmsa_bank1_gr[25-16]); ++ kdb_print_nameval("r26", p->pmsa_bank1_gr[26-16]); ++ kdb_print_nameval("r27", p->pmsa_bank1_gr[27-16]); ++ kdb_print_nameval("r28", p->pmsa_bank1_gr[28-16]); ++ kdb_print_nameval("r29", p->pmsa_bank1_gr[29-16]); ++ kdb_print_nameval("r30", p->pmsa_bank1_gr[30-16]); ++ kdb_print_nameval("r31", p->pmsa_bank1_gr[31-16]); ++ kdb_printf(" pr 0x%lx\n", p->pmsa_pr); ++ kdb_print_nameval("b0", p->pmsa_br0); ++ kdb_printf(" ar.rsc 0x%lx\n", p->pmsa_rsc); ++ kdb_print_nameval("cr.iip", p->pmsa_iip); ++ kdb_printf(" cr.ipsr 0x%lx\n", p->pmsa_ipsr); ++ kdb_printf(" cr.ifs 0x%lx\n", p->pmsa_ifs); ++ kdb_print_nameval("cr.xip", p->pmsa_xip); ++ kdb_printf(" cr.xpsr 0x%lx\n", p->pmsa_xpsr); ++ kdb_printf(" cr.xfs 0x%lx\n", p->pmsa_xfs); ++ kdb_print_nameval("b1", p->pmsa_br1); ++ ++ return 0; ++} ++ ++/* ++ * kdba_cpuinfo ++ * ++ * Format struct cpuinfo_ia64. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no cpu is supplied, it prints cpuinfo for all online cpus. ++ */ ++ ++static int ++kdba_cpuinfo(int argc, const char **argv) ++{ ++ int diag; ++ unsigned long cpunum = -1; ++ long offset = 0; ++ int nextarg, c, i; ++ struct cpuinfo_ia64 *cpuinfo; ++ ++ if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &cpunum, &offset, NULL); ++ if (diag) ++ return diag; ++ if (cpunum >= NR_CPUS || !cpu_online(cpunum)) ++ return KDB_BADCPUNUM; ++ } else if (argc > 1) { ++ return KDB_ARGCOUNT; ++ } ++ ++ for (c = (cpunum == -1 ? 0 : cpunum); ++ c < (cpunum == -1 ? NR_CPUS : cpunum+1); ++ ++c) { ++ if (!cpu_online(c)) ++ continue; ++ cpuinfo = cpu_data(c); ++ kdb_printf("struct cpuinfo_ia64 for cpu %d is at 0x%p\n", c, cpuinfo); ++ kdb_printf(" softirq_pending 0x%x\n", cpuinfo->softirq_pending); ++ kdb_printf(" itm_delta %ld\n", cpuinfo->itm_delta); ++ kdb_printf(" itm_next %ld\n", cpuinfo->itm_next); ++ kdb_printf(" nsec_per_cyc %ld\n", cpuinfo->nsec_per_cyc); ++ kdb_printf(" unimpl_va_mask 0x%lx\n", cpuinfo->unimpl_va_mask); ++ kdb_printf(" unimpl_pa_mask 0x%lx\n", cpuinfo->unimpl_pa_mask); ++ kdb_printf(" itc_freq %ld\n", cpuinfo->itc_freq); ++ kdb_printf(" proc_freq %ld\n", cpuinfo->proc_freq); ++ kdb_printf(" cyc_per_usec %ld\n", cpuinfo->cyc_per_usec); ++ kdb_printf(" cyc_per_usec %ld\n", cpuinfo->cyc_per_usec); ++#if 0 /* RJA per-cpu MCA */ ++ kdb_printf(" percpu_paddr 0x%lx\n", cpuinfo->percpu_paddr); ++#endif ++ kdb_printf(" ptce_base 0x%lx\n", cpuinfo->ptce_base); ++ kdb_printf(" ptce_count %d %d\n", cpuinfo->ptce_count[0], cpuinfo->ptce_count[1]); ++ kdb_printf(" ptce_stride %d %d\n", cpuinfo->ptce_stride[0], cpuinfo->ptce_stride[1]); ++#if 0 /* RJA per-cpu MCA */ ++ kdb_printf(" pal_paddr 0x%lx\n", cpuinfo->pal_paddr); ++ kdb_printf(" pal_base 0x%lx\n", cpuinfo->pal_base); ++#endif ++ kdb_printf(" ksoftirqd 0x%p\n", cpuinfo->ksoftirqd); ++#ifdef CONFIG_SMP ++ kdb_printf(" loops_per_jiffy %ld\n", cpuinfo->loops_per_jiffy); ++ kdb_printf(" cpu %d\n", cpuinfo->cpu); ++ kdb_printf(" socket_id %d\n", cpuinfo->socket_id); ++ kdb_printf(" core_id %d\n", cpuinfo->core_id); ++ kdb_printf(" thread_id %d\n", cpuinfo->thread_id); ++ kdb_printf(" num_log %d\n", cpuinfo->num_log); ++ kdb_printf(" cores_per_socket %d\n", cpuinfo->cores_per_socket); ++ kdb_printf(" threads_per_core %d\n", cpuinfo->threads_per_core); ++#endif ++ kdb_printf(" ppn 0x%lx\n", cpuinfo->ppn); ++ kdb_printf(" features 0x%lx\n", cpuinfo->features); ++ kdb_printf(" number %d\n", cpuinfo->number); ++ kdb_printf(" revision %d\n", cpuinfo->revision); ++ kdb_printf(" model %d\n", cpuinfo->model); ++ kdb_printf(" family %d\n", cpuinfo->family); ++ kdb_printf(" archrev %d\n", cpuinfo->archrev); ++ kdb_printf(" vendor "); ++ for (i = 0; i < sizeof(cpuinfo->vendor); ++i) ++ kdb_printf(" 0x%02x", cpuinfo->vendor[i]); ++ kdb_printf("\n"); ++#ifdef CONFIG_NUMA ++ kdb_printf(" node_data 0x%p\n", cpuinfo->node_data); ++#endif ++#if 0 /* RJA per-cpu MCA */ ++ kdb_printf(" ia64_pa_mca_data 0x%p\n", cpuinfo->ia64_pa_mca_data); ++#endif ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_KDB_HARDWARE_BREAKPOINTS ++void ++kdba_installdbreg(kdb_bp_t *bp) ++{ ++ unsigned long mask; ++ unsigned int regbase; ++ static unsigned long masks[] = { ++ 0x00FFFFFFFFFFFFFFUL, // 1 byte long ++ 0x00FFFFFFFFFFFFFEUL, // 2 bytes long ++ 0x0000000000000000UL, // invalid ++ 0x00FFFFFFFFFFFFFCUL // 4 bytes long ++ }; ++ static unsigned char modes[] = { ++ 0x81, // instruction => x, plm=priv level 0 only ++ 0x41, // write => w, plm=priv level 0 only ++ 0x00, // io ++ 0x81 // read => r, plm=priv level 0 only ++ }; ++ ++ /* Note that bp->bp_hard[NR_CPU] is for x86. ++ * The ia64 uses bp->bp_hard[0] only. ++ */ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installdbreg:\n"); ++ mask = masks[bp->bp_hard[0]->bph_length] | ++ (((unsigned long)(modes[bp->bp_hard[0]->bph_mode])) << 56); ++ regbase = 2*bp->bp_hard[0]->bph_reg; ++ ++ switch (bp->bp_hard[0]->bph_mode) ++ { ++ case 1: ++ case 3: ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installdbreg: dbr[%u]=%016lx\n", ++ regbase, bp->bp_addr); ++ kdb_printf("kdba_installdbreg: dbr[%u]=%016lx\n", ++ regbase+1, mask); ++ } ++ ++ ia64_set_dbr(regbase, bp->bp_addr); ++ ia64_set_dbr(regbase+1, mask); ++ ia64_srlz_d(); ++ break; ++ ++ case 0: /* instruction */ ++#if 0 ++ ia64_set_ibr(regbase, bp->bp_addr); ++ ia64_set_ibr(regbase+1, mask); ++ ia64_srlz_d(); ++#else ++ kdb_printf("\"instr\" mode not implemented\n"); ++#endif ++ break; ++ ++ case 2: /* io */ ++ kdb_printf("\"io\" mode not implemented\n"); ++ break; ++ } ++} ++ ++void ++kdba_removedbreg(kdb_bp_t *bp) ++{ ++ unsigned int regbase = 2*bp->bp_hard[0]->bph_reg; ++ ++ /* Note that bp->bp_hard[NR_CPU] is for x86. ++ * The ia64 uses bp->bp_hard[0] only. ++ */ ++ switch (bp->bp_hard[0]->bph_mode) ++ { ++ case 1: ++ case 3: ++ ia64_set_dbr(regbase, 0); ++ ia64_set_dbr(regbase+1, 0); ++ ia64_srlz_d(); ++ break; ++ ++ case 0: /* instruction */ ++#if 0 ++ ia64_set_ibr(regbase, 0); ++ ia64_set_ibr(regbase+1, 0); ++ ia64_srlz_d(); ++#else ++ kdb_printf("\"instr\" mode not implemented\n"); ++#endif ++ break; ++ ++ case 2: /* io */ ++ kdb_printf("\"io\" mode not implemented\n"); ++ break; ++ } ++} ++#endif /* CONFIG_KDB_HARDWARE_BREAKPOINTS */ ++ ++ ++static kdb_machreg_t ++kdba_getdr(int regnum) ++{ ++ kdb_machreg_t contents = 0; ++ unsigned long reg = (unsigned long)regnum; ++ ++ __asm__ ("mov %0=ibr[%1]"::"r"(contents),"r"(reg)); ++// __asm__ ("mov ibr[%0]=%1"::"r"(dbreg_cond),"r"(value)); ++ ++ return contents; ++} ++ ++ ++static void ++get_fault_regs(fault_regs_t *fr) ++{ ++ fr->ifa = 0 ; ++ fr->isr = 0 ; ++ ++ __asm__ ("rsm psr.ic;;") ; ++ ia64_srlz_d(); ++ __asm__ ("mov %0=cr.ifa" : "=r"(fr->ifa)); ++ __asm__ ("mov %0=cr.isr" : "=r"(fr->isr)); ++ __asm__ ("ssm psr.ic;;") ; ++ ia64_srlz_d(); ++} ++ ++static void ++show_kernel_regs (void) ++{ ++ unsigned long kr[8]; ++ int i; ++ ++ asm ("mov %0=ar.k0" : "=r"(kr[0])); asm ("mov %0=ar.k1" : "=r"(kr[1])); ++ asm ("mov %0=ar.k2" : "=r"(kr[2])); asm ("mov %0=ar.k3" : "=r"(kr[3])); ++ asm ("mov %0=ar.k4" : "=r"(kr[4])); asm ("mov %0=ar.k5" : "=r"(kr[5])); ++ asm ("mov %0=ar.k6" : "=r"(kr[6])); asm ("mov %0=ar.k7" : "=r"(kr[7])); ++ ++ for (i = 0; i < 4; ++i) ++ kdb_printf(" kr%d: %016lx kr%d: %016lx\n", 2*i, kr[2*i], 2*i+1, kr[2*i+1]); ++ kdb_printf("\n"); ++} ++ ++static int ++change_cur_stack_frame(int regno, unsigned long *contents) ++{ ++ unsigned long sof, i, cfm, sp, *bsp, __user *ubsp; ++ struct unw_frame_info info; ++ mm_segment_t old_fs; ++ int cpu = kdb_process_cpu(kdb_current_task); ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ ++ if (kdb_current_task != krp->p) { ++ kdb_printf("Stacked registers are not available for tasks that are not running.\n"); ++ kdb_printf("Use bt with a large BTARGS value instead\n"); ++ return 0; ++ } ++ unw_init_frame_info(&info, krp->p, krp->arch.sw); ++ do { ++ if (unw_unwind(&info) < 0) { ++ kdb_printf("Failed to unwind\n"); ++ return 0; ++ } ++ unw_get_sp(&info, &sp); ++ } while (sp <= (unsigned long) kdb_current_regs); ++ unw_get_bsp(&info, (unsigned long *) &bsp); ++ unw_get_cfm(&info, &cfm); ++ ++ if (!bsp) { ++ kdb_printf("Unable to get Current Stack Frame\n"); ++ return 0; ++ } ++ ++ sof = (cfm & 0x7f); ++ ++ if(((unsigned long)regno - 32) >= (sof - 2)) return 1; ++ ++ old_fs = set_fs(KERNEL_DS); ++ for (i = 0; i < (regno - 32); ++i) ++ bsp = ia64_rse_skip_regs(bsp, 1); ++ ubsp = (unsigned long __user *) bsp; ++ put_user(*contents, ubsp); ++ set_fs(old_fs); ++ ++ return 0 ; ++} ++ ++static int ++show_cur_stack_frame(int regno, unsigned long *contents) ++{ ++ unsigned long sof, i, cfm, val, sp, *bsp, __user *ubsp; ++ struct unw_frame_info info; ++ mm_segment_t old_fs; ++ int cpu = kdb_process_cpu(kdb_current_task); ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ ++ if (kdb_current_task != krp->p) { ++ kdb_printf("Stacked registers are not available for tasks that are not running.\n"); ++ kdb_printf("Use bt with a large BTARGS value instead\n"); ++ return 0; ++ } ++ unw_init_frame_info(&info, krp->p, krp->arch.sw); ++ do { ++ if (unw_unwind(&info) < 0) { ++ kdb_printf("Failed to unwind\n"); ++ return 0; ++ } ++ unw_get_sp(&info, &sp); ++ } while (sp <= (unsigned long) kdb_current_regs); ++ unw_get_bsp(&info, (unsigned long *) &bsp); ++ unw_get_cfm(&info, &cfm); ++ ++ if (!bsp) { ++ kdb_printf("Unable to display Current Stack Frame\n"); ++ return 0; ++ } ++ ++ sof = (cfm & 0x7f); ++ ++ if (regno) { ++ if ((unsigned) regno - 32 >= sof) ++ return 0; ++ bsp = ia64_rse_skip_regs(bsp, regno - 32); ++ old_fs = set_fs(KERNEL_DS); ++ ubsp = (unsigned long __user *) bsp; ++ get_user(val, ubsp); ++ set_fs(old_fs); ++ *contents = val; ++ return 1; ++ } ++ ++ old_fs = set_fs(KERNEL_DS); ++ for (i = 0; i < sof; ++i) { ++ ubsp = (unsigned long __user *) bsp; ++ get_user(val, ubsp); ++ kdb_printf(" r%lu: %016lx ", 32 + i, val); ++ if (!((i + 1) % 3)) ++ kdb_printf("\n"); ++ bsp = ia64_rse_skip_regs(bsp, 1); ++ } ++ kdb_printf("\n"); ++ set_fs(old_fs); ++ ++ return 0 ; ++} ++ ++/* ++ * kdba_getregcontents ++ * ++ * Return the contents of the register specified by the ++ * input string argument. Return an error if the string ++ * does not match a machine register. ++ * ++ * The following pseudo register names are supported: ++ * ®s - Prints address of exception frame ++ * kesp - Prints kernel stack pointer at time of fault ++ * sstk - Prints switch stack for ia64 ++ * % - Uses the value of the registers at the ++ * last time the user process entered kernel ++ * mode, instead of the registers at the time ++ * kdb was entered. ++ * ++ * Parameters: ++ * regname Pointer to string naming register ++ * regs Pointer to structure containing registers. ++ * Outputs: ++ * *contents Pointer to unsigned long to recieve register contents ++ * Returns: ++ * 0 Success ++ * KDB_BADREG Invalid register name ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * Note that this function is really machine independent. The kdb ++ * register list is not, however. ++ */ ++ ++static struct kdbregs { ++ char *reg_name; ++ size_t reg_offset; ++} kdbreglist[] = { ++ { "psr", offsetof(struct pt_regs, cr_ipsr) }, ++ { "ifs", offsetof(struct pt_regs, cr_ifs) }, ++ { "ip", offsetof(struct pt_regs, cr_iip) }, ++ ++ { "unat", offsetof(struct pt_regs, ar_unat) }, ++ { "pfs", offsetof(struct pt_regs, ar_pfs) }, ++ { "rsc", offsetof(struct pt_regs, ar_rsc) }, ++ ++ { "rnat", offsetof(struct pt_regs, ar_rnat) }, ++ { "bsps", offsetof(struct pt_regs, ar_bspstore) }, ++ { "pr", offsetof(struct pt_regs, pr) }, ++ ++ { "ldrs", offsetof(struct pt_regs, loadrs) }, ++ { "ccv", offsetof(struct pt_regs, ar_ccv) }, ++ { "fpsr", offsetof(struct pt_regs, ar_fpsr) }, ++ ++ { "b0", offsetof(struct pt_regs, b0) }, ++ { "b6", offsetof(struct pt_regs, b6) }, ++ { "b7", offsetof(struct pt_regs, b7) }, ++ ++ { "r1",offsetof(struct pt_regs, r1) }, ++ { "r2",offsetof(struct pt_regs, r2) }, ++ { "r3",offsetof(struct pt_regs, r3) }, ++ ++ { "r8",offsetof(struct pt_regs, r8) }, ++ { "r9",offsetof(struct pt_regs, r9) }, ++ { "r10",offsetof(struct pt_regs, r10) }, ++ ++ { "r11",offsetof(struct pt_regs, r11) }, ++ { "r12",offsetof(struct pt_regs, r12) }, ++ { "r13",offsetof(struct pt_regs, r13) }, ++ ++ { "r14",offsetof(struct pt_regs, r14) }, ++ { "r15",offsetof(struct pt_regs, r15) }, ++ { "r16",offsetof(struct pt_regs, r16) }, ++ ++ { "r17",offsetof(struct pt_regs, r17) }, ++ { "r18",offsetof(struct pt_regs, r18) }, ++ { "r19",offsetof(struct pt_regs, r19) }, ++ ++ { "r20",offsetof(struct pt_regs, r20) }, ++ { "r21",offsetof(struct pt_regs, r21) }, ++ { "r22",offsetof(struct pt_regs, r22) }, ++ ++ { "r23",offsetof(struct pt_regs, r23) }, ++ { "r24",offsetof(struct pt_regs, r24) }, ++ { "r25",offsetof(struct pt_regs, r25) }, ++ ++ { "r26",offsetof(struct pt_regs, r26) }, ++ { "r27",offsetof(struct pt_regs, r27) }, ++ { "r28",offsetof(struct pt_regs, r28) }, ++ ++ { "r29",offsetof(struct pt_regs, r29) }, ++ { "r30",offsetof(struct pt_regs, r30) }, ++ { "r31",offsetof(struct pt_regs, r31) }, ++ ++}; ++ ++static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); ++ ++int ++kdba_getregcontents(const char *regname, struct pt_regs *regs, unsigned long *contents) ++{ ++ int i; ++ ++ if (strcmp(regname, "isr") == 0) { ++ fault_regs_t fr ; ++ get_fault_regs(&fr) ; ++ *contents = fr.isr ; ++ return 0 ; ++ } ++ ++ if (!regs) { ++ kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__); ++ return KDB_BADREG; ++ } ++ ++ if (strcmp(regname, "®s") == 0) { ++ *contents = (unsigned long)regs; ++ return 0; ++ } ++ ++ if (strcmp(regname, "sstk") == 0) { ++ *contents = (unsigned long)getprsregs(regs) ; ++ return 0; ++ } ++ ++ if (strcmp(regname, "ksp") == 0) { ++ *contents = (unsigned long) (regs + 1); ++ return 0; ++ } ++ ++ for (i=0; i ++ * ++ * Parameters: ++ * regname Pointer to string naming register ++ * regs Pointer to structure containing registers. ++ * contents Unsigned long containing new register contents ++ * Outputs: ++ * Returns: ++ * 0 Success ++ * KDB_BADREG Invalid register name ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdba_setregcontents(const char *regname, ++ struct pt_regs *regs, ++ unsigned long contents) ++{ ++ int i, ret = 0, fixed = 0; ++ char *endp; ++ unsigned long regno; ++ ++ if (regname[0] == '%') { ++ regname++; ++ regs = (struct pt_regs *) ++ (kdb_current_task->thread.ksp - sizeof(struct pt_regs)); ++ } ++ ++ if (!regs) { ++ kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__); ++ return KDB_BADREG; ++ } ++ ++ /* fixed registers */ ++ for (i=0; i (unsigned long)31) { ++ ret = change_cur_stack_frame(regno, &contents); ++ if(!ret) return 0; ++ } ++ } ++ ++ if ((i == nkdbreglist) ++ || (strlen(kdbreglist[i].reg_name) != strlen(regname)) ++ || ret) { ++ return KDB_BADREG; ++ } ++ ++ /* just in case of "standard" register */ ++ *(unsigned long *)((unsigned long)regs + kdbreglist[i].reg_offset) = ++ contents; ++ ++ return 0; ++} ++ ++/* ++ * kdba_dumpregs ++ * ++ * Dump the specified register set to the display. ++ * ++ * Parameters: ++ * regs Pointer to structure containing registers. ++ * type Character string identifying register set to dump ++ * extra string further identifying register (optional) ++ * Outputs: ++ * Returns: ++ * 0 Success ++ * Locking: ++ * None. ++ * Remarks: ++ * This function will dump the general register set if the type ++ * argument is NULL (struct pt_regs). The alternate register ++ * set types supported by this function: ++ * ++ * d Debug registers ++ * c Control registers ++ * u User registers at most recent entry to kernel ++ * i Interrupt registers -- same as "irr" command ++ * Following not yet implemented: ++ * m Model Specific Registers (extra defines register #) ++ * r Memory Type Range Registers (extra defines register) ++ * ++ * For now, all registers are covered as follows: ++ * ++ * rd - dumps all regs ++ * rd %isr - current interrupt status reg, read freshly ++ * rd s - valid stacked regs ++ * rd %sstk - gets switch stack addr. dump memory and search ++ * rd d - debug regs, may not be too useful ++ * rd k - dump kernel regs ++ * ++ * ARs TB Done ++ * OTHERS TB Decided ?? ++ * ++ * Intel wish list ++ * These will be implemented later - Srinivasa ++ * ++ * type action ++ * ---- ------ ++ * g dump all General static registers ++ * s dump all general Stacked registers ++ * f dump all Floating Point registers ++ * p dump all Predicate registers ++ * b dump all Branch registers ++ * a dump all Application registers ++ * c dump all Control registers ++ * ++ */ ++ ++int ++kdba_dumpregs(struct pt_regs *regs, ++ const char *type, ++ const char *extra) ++ ++{ ++ int i; ++ int count = 0; ++ ++ if (type ++ && (type[0] == 'u')) { ++ type = NULL; ++ regs = (struct pt_regs *) ++ (kdb_current_task->thread.ksp - sizeof(struct pt_regs)); ++ } ++ ++ if (type == NULL) { ++ if (!regs) { ++ kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__); ++ return KDB_BADREG; ++ } ++ for (i=0; icr_iip + ia64_psr(regs)->ri : 0; ++} ++ ++int ++kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_BADREG; ++ regs->cr_iip = newpc & ~0xf; ++ ia64_psr(regs)->ri = newpc & 0x3; ++ KDB_STATE_SET(IP_ADJUSTED); ++ return 0; ++} ++ ++struct kdba_main_loop_data { ++ kdb_reason_t reason; ++ kdb_reason_t reason2; ++ int error; ++ kdb_dbtrap_t db_result; ++ struct pt_regs *regs; ++ int ret; ++}; ++ ++/* ++ * do_kdba_main_loop ++ * ++ * Invoked from kdba_main_loop via unw_init_running() after that routine ++ * has pushed a struct switch_stack. ++ * ++ * Inputs: ++ * info Unwind information. ++ * data kdb data passed as void * to unw_init_running. ++ * Returns: ++ * none (unw_init_running requires void). vdata->ret is set to ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * Outputs: ++ * none ++ * Locking: ++ * None. ++ * Remarks: ++ * unw_init_running() creates struct switch_stack then struct ++ * unw_frame_info. We get the address of the info so step over ++ * that to get switch_stack. Just hope that unw_init_running ++ * does not change its stack usage. unw_init_running adds padding ++ * to put switch_stack on a 16 byte boundary. ++ */ ++ ++static void ++do_kdba_main_loop(struct unw_frame_info *info, void *vdata) ++{ ++ struct kdba_main_loop_data *data = vdata; ++ struct switch_stack *sw, *prev_sw; ++ struct pt_regs *prev_regs; ++ struct kdb_running_process *krp = ++ kdb_running_process + smp_processor_id(); ++ KDB_DEBUG_STATE(__FUNCTION__, data->reason); ++ prev_sw = krp->arch.sw; ++ sw = (struct switch_stack *)(info+1); ++ /* padding from unw_init_running */ ++ sw = (struct switch_stack *)(((unsigned long)sw + 15) & ~15); ++ krp->arch.sw = sw; ++ prev_regs = krp->regs; ++ data->ret = kdb_save_running(data->regs, data->reason, data->reason2, ++ data->error, data->db_result); ++ kdb_unsave_running(data->regs); ++ krp->regs = prev_regs; ++ krp->arch.sw = prev_sw; ++} ++ ++/* ++ * kdba_main_loop ++ * ++ * Do any architecture specific set up before entering the main kdb loop. ++ * The primary function of this routine is to make all processes look the ++ * same to kdb, kdb must be able to list a process without worrying if the ++ * process is running or blocked, so make all processes look as though they ++ * are blocked. ++ * ++ * Inputs: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * error2 kdb's current reason code. Initially error but can change ++ * acording to kdb state. ++ * db_result Result from break or debug point. ++ * regs The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it should ++ * always be valid. ++ * Returns: ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * Outputs: ++ * Builds a switch_stack structure before calling the main loop. ++ * Locking: ++ * None. ++ * Remarks: ++ * none. ++ */ ++ ++int ++kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, ++ kdb_dbtrap_t db_result, struct pt_regs *regs) ++{ ++ struct kdba_main_loop_data data; ++ KDB_DEBUG_STATE("kdba_main_loop", reason); ++ data.reason = reason; ++ data.reason2 = reason2; ++ data.error = error; ++ data.db_result = db_result; ++ data.regs = regs; ++ unw_init_running(do_kdba_main_loop, &data); ++ return(data.ret); ++} ++ ++void ++kdba_disableint(kdb_intstate_t *state) ++{ ++ unsigned long *fp = (unsigned long *)state; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ *fp = flags; ++} ++ ++void ++kdba_restoreint(kdb_intstate_t *state) ++{ ++ unsigned long flags = *(unsigned long *)state; ++ local_irq_restore(flags); ++} ++ ++void ++kdba_setsinglestep(struct pt_regs *regs) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ ia64_psr(regs)->ss = 1; ++} ++ ++void ++kdba_clearsinglestep(struct pt_regs *regs) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ ia64_psr(regs)->ss = 0; ++} ++ ++/* ++ * kdb_tpa ++ * ++ * Virtual to Physical address translation command. ++ * ++ * tpa ++ * ++ * Parameters: ++ * argc Count of arguments in argv ++ * argv Space delimited command line arguments ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic if failure. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++#define __xtpa(x) ({ia64_va _v; asm("tpa %0=%1" : "=r"(_v.l) : "r"(x)); _v.l;}) ++static int ++kdba_tpa(int argc, const char **argv) ++{ ++ kdb_machreg_t addr; ++ int diag; ++ long offset = 0; ++ int nextarg; ++ char c; ++ ++ nextarg = 1; ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ if (kdb_getarea(c, addr)) ++ return(0); ++ kdb_printf("vaddr: 0x%lx , paddr: 0x%lx\n", addr, __xtpa(addr)); ++ return(0); ++} ++#if defined(CONFIG_NUMA) ++static int ++kdba_tpav(int argc, const char **argv) ++{ ++ kdb_machreg_t addr, end, paddr; ++ int diag; ++ long offset = 0; ++ int nextarg, nid, nid_old; ++ char c; ++ ++ nextarg = 1; ++ if (argc != 2) ++ return KDB_ARGCOUNT; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &end, &offset, NULL); ++ if (diag) ++ return diag; ++ if (kdb_getarea(c, addr)) ++ return(0); ++ if (kdb_getarea(c, end)) ++ return(0); ++ paddr=__xtpa(addr); ++ nid = paddr_to_nid(paddr); ++ kdb_printf("begin: 0x%lx , paddr: 0x%lx , nid: %d\n", addr, __xtpa(addr), nid); ++ for(;addr] ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ */ ++ ++static int ++kdba_sendinit(int argc, const char **argv) ++{ ++ unsigned long cpunum; ++ int diag; ++ ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ ++ diag = kdbgetularg(argv[1], &cpunum); ++ if (diag) ++ return diag; ++ ++ if (cpunum >= NR_CPUS || !cpu_online(cpunum)) ++ return KDB_BADCPUNUM; ++ ++ platform_send_ipi(cpunum, 0, IA64_IPI_DM_INIT, 0); ++ return 0; ++} ++ ++/* Invoked once from kdb_wait_for_cpus when waiting for cpus. For those cpus ++ * that have not responded to the normal KDB interrupt yet, hit them with an ++ * INIT event. ++ */ ++void ++kdba_wait_for_cpus(void) ++{ ++ int c; ++ if (KDB_FLAG(CATASTROPHIC)) ++ return; ++ kdb_printf(" Sending INIT to cpus that have not responded yet\n"); ++ for_each_online_cpu(c) ++ if (kdb_running_process[c].seqno < kdb_seqno - 1) ++ platform_send_ipi(c, 0, IA64_IPI_DM_INIT, 0); ++} ++ ++#endif /* CONFIG_SMP */ ++ ++/* This code is sensitive to the layout of the MCA/INIT stack (see mca_asm.h) ++ * and to the stack layout that ia64_mca_modify_original_stack() creates when ++ * it makes the original task look blocked. ++ */ ++static void ++kdba_handlers_modify(struct task_struct *task, int cpu) ++{ ++ struct kdb_running_process *work, *save; ++ work = kdb_running_process + cpu; ++ save = kdb_running_process_save + cpu; ++ *work = *save; ++ if (!kdba_show_handlers && REGION_NUMBER(task) >= RGN_GATE && ++ (task_thread_info(task)->flags & _TIF_MCA_INIT)) { ++ struct ia64_sal_os_state *sos = (struct ia64_sal_os_state *) ++ ((unsigned long)save->p + MCA_SOS_OFFSET); ++ char *p; ++ if (!sos->prev_task) ++ return; ++ work->p = sos->prev_task; ++ p = (char *)sos->prev_task->thread.ksp; ++ p += 16; ++ work->arch.sw = (struct switch_stack *)p; ++ p += sizeof(struct switch_stack); ++ work->regs = (struct pt_regs *)p; ++ work->irq_depth = 2; /* any value >1 will do */ ++ } ++} ++ ++/* Turn the display of the MCA/INIT handlers on or off, or display the status ++ * of the MCA/INIT handlers. ++ */ ++static int ++kdba_handlers(int argc, const char **argv) ++{ ++ int cpu; ++ struct kdb_running_process *krp; ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ if (strcmp(argv[1], "show") == 0) ++ kdba_show_handlers = 1; ++ else if (strcmp(argv[1], "hide") == 0) ++ kdba_show_handlers = 0; ++ else if (strcmp(argv[1], "status") != 0) { ++ kdb_printf("handlers \n"); ++ return 0; ++ } ++ for (cpu = 0, krp = kdb_running_process_save; cpu < NR_CPUS; ++cpu, ++krp) { ++ if (krp->p) ++ kdba_handlers_modify(krp->p, cpu); ++ } ++ if (strcmp(argv[1], "status") != 0) ++ return 0; ++ kdb_printf("handlers status is %s\n", kdba_show_handlers ? "'show'" : "'hide'"); ++ kdb_printf(" cpu handler task command original task command\n"); ++ for (cpu = 0, krp = kdb_running_process_save; cpu < NR_CPUS; ++cpu, ++krp) { ++ struct task_struct *p = krp->p; ++ if (!p) ++ continue; ++ kdb_printf("%4d", cpu); ++ if (task_thread_info(p)->flags & _TIF_MCA_INIT) { ++ struct ia64_sal_os_state *sos; ++ kdb_printf(" " kdb_machreg_fmt0 " %-*s ", ++ (unsigned long)p, (int)sizeof(p->comm), p->comm); ++ sos = (struct ia64_sal_os_state *)((unsigned long)p + MCA_SOS_OFFSET); ++ p = sos->prev_task; ++ } else ++ kdb_printf("%*s", (int)(1+2+16+1+sizeof(p->comm)+2), " "); ++ if (p) ++ kdb_printf(" " kdb_machreg_fmt0 " %-*s", ++ (unsigned long)p, (int)sizeof(p->comm), p->comm); ++ kdb_printf("\n"); ++ } ++ return 0; ++} ++ ++/* Executed once on each cpu at startup. */ ++void ++kdba_cpu_up(void) ++{ ++} ++ ++/* ++ * kdba_init ++ * ++ * Architecture specific initialization. ++ * ++ * Parameters: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * None. ++ */ ++ ++void ++kdba_init(void) ++{ ++ kdb_running_process_save = kzalloc( ++ sizeof(*kdb_running_process_save) * NR_CPUS, GFP_KERNEL); ++ BUG_ON(!kdb_running_process_save); ++ kdb_register("irr", kdba_sir, "", "Show interrupt registers", 0); ++ kdb_register("itm", kdba_itm, "", "Set new ITM value", 0); ++#if defined(CONFIG_SMP) ++ kdb_register("init", kdba_sendinit, "", "Send INIT to cpu", 0); ++#endif ++ kdb_register("pt_regs", kdba_pt_regs, "address", "Format struct pt_regs", 0); ++ kdb_register("switch_stack", kdba_switch_stack, "address", "Format struct switch_stack", 0); ++ kdb_register("minstate", kdba_minstate, "address", "Format PAL minstate", 0); ++ kdb_register("tpa", kdba_tpa, "", "Translate virtual to physical address", 0); ++#if defined(CONFIG_NUMA) ++ kdb_register("tpav", kdba_tpav, " ", "Verify that physical addresses corresponding to virtual addresses from to are in same node", 0); ++#endif ++ kdb_register("stackdepth", kdba_stackdepth, "[percentage]", "Print processes using >= stack percentage", 0); ++ kdb_register("cpuinfo", kdba_cpuinfo, "[cpu]", "Print struct cpuinfo_ia64", 0); ++ kdb_register("handlers", kdba_handlers, "", "Control the display of MCA/INIT handlers", 0); ++ ++#ifdef CONFIG_SERIAL_8250_CONSOLE ++ kdba_serial_console = KDBA_SC_STANDARD; ++#endif ++#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE ++ if (ia64_platform_is("sn2")) ++ kdba_serial_console = KDBA_SC_SGI_L1; ++#endif ++ return; ++} ++ ++/* ++ * kdba_adjust_ip ++ * ++ * Architecture specific adjustment of instruction pointer before leaving ++ * kdb. ++ * ++ * Parameters: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * regs The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it should ++ * always be valid. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * On IA64, KDB_ENTER() and KDB_ENTER_SLAVE() use break which is a fault, ++ * not a trap. The instruction pointer must be stepped before leaving ++ * kdb, otherwise we get a loop. ++ */ ++ ++void ++kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *regs) ++{ ++ if ((reason == KDB_REASON_ENTER || reason == KDB_REASON_ENTER_SLAVE) && ++ !KDB_STATE(IP_ADJUSTED)) { ++ if (KDB_NULL_REGS(regs)) ++ return; ++ if (ia64_psr(regs)->ri < 2) ++ kdba_setpc(regs, regs->cr_iip + ia64_psr(regs)->ri + 1); ++ else ++ kdba_setpc(regs, regs->cr_iip + 16); ++ } ++} ++ ++void ++kdba_save_running(struct kdba_running_process *k, struct pt_regs *regs) ++{ ++ struct kdb_running_process *work, *save; ++ int cpu = smp_processor_id(); ++ work = kdb_running_process + cpu; ++ save = kdb_running_process_save + cpu; ++ *save = *work; ++ if (!regs) ++ return; ++ kdba_handlers_modify((struct task_struct *)regs->r13, cpu); ++} ++ ++void ++kdba_unsave_running(struct kdba_running_process *k, struct pt_regs *regs) ++{ ++ memset(kdb_running_process_save + smp_processor_id(), 0, ++ sizeof(*kdb_running_process_save)); ++} ++ ++void ++kdba_set_current_task(const struct task_struct *p) ++{ ++ int cpu = kdb_process_cpu(p); ++ struct kdb_running_process *work, *save; ++ work = kdb_running_process + cpu; ++ save = kdb_running_process_save + cpu; ++ kdb_current_task = p; ++ if (kdb_task_has_cpu(p)) { ++ kdb_current_regs = work->regs; ++ return; ++ } ++ kdb_current_regs = NULL; ++ /* For most blocked tasks we cannot get the pt_regs without doing an ++ * unwind, which is not worth doing. For tasks interrupted by ++ * MCA/INIT, when the user is not working on the handlers, we must use ++ * the registers at the time of interrupt. ++ */ ++ if (work->p == save->p || work->p != p) ++ return; ++ kdb_current_regs = (struct pt_regs *)(work->p->thread.ksp + 16 + ++ sizeof(struct switch_stack)); ++} ++ ++/* ++ * asm-ia64 uaccess.h supplies __copy_to_user which relies on MMU to ++ * trap invalid addresses in the _xxx fields. Verify the other address ++ * of the pair is valid by accessing the first and last byte ourselves, ++ * then any access violations should only be caused by the _xxx ++ * addresses, ++ */ ++ ++int ++kdba_putarea_size(unsigned long to_xxx, void *from, size_t size) ++{ ++ mm_segment_t oldfs = get_fs(); ++ int r; ++ char c; ++ c = *((volatile char *)from); ++ c = *((volatile char *)from + size - 1); ++ ++ if (to_xxx >> 61 <= 4) { ++ return kdb_putuserarea_size(to_xxx, from, size); ++ } ++ ++ set_fs(KERNEL_DS); ++ r = __copy_to_user_inatomic((void __user *)to_xxx, from, size); ++ set_fs(oldfs); ++ return r; ++} ++ ++int ++kdba_getarea_size(void *to, unsigned long from_xxx, size_t size) ++{ ++ mm_segment_t oldfs = get_fs(); ++ int r; ++ *((volatile char *)to) = '\0'; ++ *((volatile char *)to + size - 1) = '\0'; ++ ++ if (from_xxx >> 61 <= 4) ++ return kdb_getuserarea_size(to, from_xxx, size); ++ ++ set_fs(KERNEL_DS); ++ switch (size) { ++ case 1: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 1); ++ break; ++ case 2: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 2); ++ break; ++ case 4: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 4); ++ break; ++ case 8: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 8); ++ break; ++ default: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, size); ++ break; ++ } ++ set_fs(oldfs); ++ return r; ++} ++ ++int ++kdba_verify_rw(unsigned long addr, size_t size) ++{ ++ unsigned char data[(__force size_t) size]; ++ return(kdba_getarea_size(data, addr, size) || kdba_putarea_size(addr, data, size)); ++} ++ ++#ifdef CONFIG_KDB_KDUMP ++void ++kdba_kdump_prepare(struct pt_regs *fixed_regs) ++{ ++ int i; ++ ++ /* Set on KEXEC bit on all onlinr cpus */ ++ for (i = 1; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ ++ KDB_STATE_SET_CPU(KEXEC, i); ++ } ++ ++ machine_crash_shutdown(fixed_regs); ++} ++ ++void kdba_kdump_shutdown_slave(struct pt_regs *regs) ++{ ++ if (kdb_kdump_state != KDB_KDUMP_RESET) { ++ unw_init_running(kdump_cpu_freeze, NULL); ++ } ++} ++#endif +--- a/arch/ia64/kernel/head.S ++++ b/arch/ia64/kernel/head.S +@@ -259,8 +259,13 @@ start_ap: + /* + * Switch into virtual mode: + */ ++#ifdef CONFIG_KDB_HARDWARE_BREAKPOINTS ++#define IA64_PSR_KDB_FLAGS IA64_PSR_DB ++#else ++#define IA64_PSR_KDB_FLAGS 0 ++#endif + movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN \ +- |IA64_PSR_DI) ++ |IA64_PSR_DI|IA64_PSR_KDB_FLAGS) + ;; + mov cr.ipsr=r16 + movl r17=1f +--- a/arch/ia64/kernel/mca.c ++++ b/arch/ia64/kernel/mca.c +@@ -88,6 +88,10 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include /* for switch state wrappers */ ++#endif /* CONFIG_KDB */ + + #include + #include +@@ -824,6 +828,14 @@ ia64_mca_rendez_int_handler(int rendez_i + */ + ia64_sal_mc_rendez(); + ++#ifdef CONFIG_KDB ++ /* We get here when the MCA monarch has entered and has woken up the ++ * slaves. Do a KDB rendezvous to meet the monarch cpu. ++ */ ++ if (monarch_cpu != -1) ++ KDB_ENTER_SLAVE(); ++#endif ++ + NOTIFY_MCA(DIE_MCA_RENDZVOUS_PROCESS, get_irq_regs(), (long)&nd, 1); + + /* Wait for the monarch cpu to exit. */ +@@ -1361,6 +1373,19 @@ ia64_mca_handler(struct pt_regs *regs, s + mca_insert_tr(0x2); /*Reload dynamic itrs*/ + } + ++#ifdef CONFIG_KDB ++ kdb_save_flags(); ++ KDB_FLAG_CLEAR(CATASTROPHIC); ++ KDB_FLAG_CLEAR(RECOVERY); ++ if (recover) ++ KDB_FLAG_SET(RECOVERY); ++ else ++ KDB_FLAG_SET(CATASTROPHIC); ++ KDB_FLAG_SET(NOIPI); /* do not send IPI for MCA/INIT events */ ++ KDB_ENTER(); ++ kdb_restore_flags(); ++#endif /* CONFIG_KDB */ ++ + NOTIFY_MCA(DIE_MCA_MONARCH_LEAVE, regs, (long)&nd, 1); + + if (atomic_dec_return(&mca_count) > 0) { +@@ -1373,6 +1398,12 @@ ia64_mca_handler(struct pt_regs *regs, s + if (cpu_isset(i, mca_cpu)) { + monarch_cpu = i; + cpu_clear(i, mca_cpu); /* wake next cpu */ ++#ifdef CONFIG_KDB ++ /* ++ * No longer a monarch, report in as a slave. ++ */ ++ KDB_ENTER_SLAVE(); ++#endif + while (monarch_cpu != -1) + cpu_relax(); /* spin until last cpu leaves */ + set_curr_task(cpu, previous_current); +@@ -1382,6 +1413,7 @@ ia64_mca_handler(struct pt_regs *regs, s + } + } + } ++ + set_curr_task(cpu, previous_current); + ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; + monarch_cpu = -1; /* This frees the slaves and previous monarchs */ +@@ -1642,6 +1674,11 @@ default_monarch_init_process(struct noti + } + } + printk("\n\n"); ++#ifdef CONFIG_KDB ++ KDB_FLAG_SET(NOIPI); /* do not send IPI for MCA/INIT events */ ++ KDB_ENTER(); ++ KDB_FLAG_CLEAR(NOIPI); ++#else /* !CONFIG_KDB */ + if (read_trylock(&tasklist_lock)) { + do_each_thread (g, t) { + printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); +@@ -1649,6 +1686,7 @@ default_monarch_init_process(struct noti + } while_each_thread (g, t); + read_unlock(&tasklist_lock); + } ++#endif /* CONFIG_KDB */ + /* FIXME: This will not restore zapped printk locks. */ + RESTORE_LOGLEVEL(console_loglevel); + return NOTIFY_DONE; +@@ -1681,6 +1719,20 @@ ia64_init_handler(struct pt_regs *regs, + int cpu = smp_processor_id(); + struct ia64_mca_notify_die nd = + { .sos = sos, .monarch_cpu = &monarch_cpu }; ++#ifdef CONFIG_KDB ++ int kdba_recalcitrant = 0; ++ /* kdba_wait_for_cpus() sends INIT to recalcitrant cpus which ends up ++ * calling this routine. If KDB is waiting for the IPI to be processed ++ * then treat all INIT events as slaves, kdb_initial_cpu is the ++ * monarch. ++ */ ++ if (KDB_STATE(WAIT_IPI)) { ++ monarch_cpu = kdb_initial_cpu; ++ sos->monarch = 0; ++ KDB_STATE_CLEAR(WAIT_IPI); ++ kdba_recalcitrant = 1; ++ } ++#endif /* CONFIG_KDB */ + + NOTIFY_INIT(DIE_INIT_ENTER, regs, (long)&nd, 0); + +@@ -1719,6 +1771,11 @@ ia64_init_handler(struct pt_regs *regs, + ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; + while (monarch_cpu == -1) + cpu_relax(); /* spin until monarch enters */ ++#ifdef CONFIG_KDB ++ KDB_ENTER_SLAVE(); ++ if (kdba_recalcitrant) ++ monarch_cpu = -1; ++#endif /* CONFIG_KDB */ + + NOTIFY_INIT(DIE_INIT_SLAVE_ENTER, regs, (long)&nd, 1); + NOTIFY_INIT(DIE_INIT_SLAVE_PROCESS, regs, (long)&nd, 1); +@@ -1747,6 +1804,14 @@ ia64_init_handler(struct pt_regs *regs, + mprintk("Delaying for 5 seconds...\n"); + udelay(5*1000000); + ia64_wait_for_slaves(cpu, "INIT"); ++ ++#ifdef CONFIG_KDB ++ kdb_save_flags(); ++ KDB_FLAG_SET(NOIPI); /* do not send IPI for MCA/INIT events */ ++ KDB_ENTER(); ++ kdb_restore_flags(); ++#endif /* CONFIG_KDB */ ++ + /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through + * to default_monarch_init_process() above and just print all the + * tasks. +@@ -1985,6 +2050,13 @@ ia64_mca_init(void) + printk(KERN_INFO "Increasing MCA rendezvous timeout from " + "%ld to %ld milliseconds\n", timeout, isrv.v0); + timeout = isrv.v0; ++#ifdef CONFIG_KDB ++ /* kdb must wait long enough for the MCA timeout to trip ++ * and process. The MCA timeout is in milliseconds. ++ */ ++ kdb_wait_for_cpus_secs = max(kdb_wait_for_cpus_secs, ++ (int)(timeout/1000) + 10); ++#endif /* CONFIG_KDB */ + NOTIFY_MCA(DIE_MCA_NEW_TIMEOUT, NULL, timeout, 0); + continue; + } +--- a/arch/ia64/kernel/smp.c ++++ b/arch/ia64/kernel/smp.c +@@ -36,6 +36,11 @@ + #include + #include + #include ++ ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ ++ + #include + #include + #include +@@ -64,6 +69,9 @@ static DEFINE_PER_CPU(unsigned short, sh + #define IPI_CPU_STOP 1 + #define IPI_CALL_FUNC_SINGLE 2 + #define IPI_KDUMP_CPU_STOP 3 ++#ifdef CONFIG_KDB ++#define IPI_KDB_INTERRUPT 4 ++#endif /* CONFIG_KDB */ + + /* This needs to be cacheline aligned because it is written to by *other* CPUs. */ + static DEFINE_PER_CPU_SHARED_ALIGNED(u64, ipi_operation); +@@ -124,6 +132,12 @@ handle_IPI (int irq, void *dev_id) + unw_init_running(kdump_cpu_freeze, NULL); + break; + #endif ++#ifdef CONFIG_KDB ++ case IPI_KDB_INTERRUPT: ++ if (!kdb_ipi(get_irq_regs(), NULL)) ++ printk(KERN_ERR "kdb_ipi() rejected IPI_KDB_INTERRUPT\n"); ++ break; ++#endif + default: + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", + this_cpu, which); +@@ -332,3 +346,12 @@ setup_profiling_timer (unsigned int mult + { + return -EINVAL; + } ++ ++#if defined(CONFIG_KDB) ++void ++smp_kdb_stop(void) ++{ ++ if (!KDB_FLAG(NOIPI)) ++ send_IPI_allbutself(IPI_KDB_INTERRUPT); ++} ++#endif /* CONFIG_KDB */ +--- a/arch/ia64/kernel/traps.c ++++ b/arch/ia64/kernel/traps.c +@@ -13,6 +13,9 @@ + #include + #include /* For unblank_screen() */ + #include /* for EXPORT_SYMBOL */ ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ + #include + #include + #include /* for ssleep() */ +@@ -78,6 +81,10 @@ die (const char *str, struct pt_regs *re + if (!regs) + return 1; + ++#ifdef CONFIG_KDB ++ (void)kdb(KDB_REASON_OOPS, err, regs); ++#endif /* CONFIG_KDB */ ++ + if (panic_on_oops) + panic("Fatal exception"); + +@@ -171,6 +178,17 @@ __kprobes ia64_bad_break (unsigned long + if (break_num < 0x80000) { + sig = SIGILL; code = __ILL_BREAK; + } else { ++#ifdef CONFIG_KDB ++ if (break_num == KDB_BREAK_ENTER && ++ kdb(KDB_REASON_ENTER, break_num, regs)) ++ return; /* kdb handled it */ ++ if (break_num == KDB_BREAK_ENTER_SLAVE && ++ kdb(KDB_REASON_ENTER_SLAVE, break_num, regs)) ++ return; /* kdb handled it */ ++ if (break_num == KDB_BREAK_BREAK && ++ kdb(KDB_REASON_BREAK, break_num, regs)) ++ return; /* kdb handled it */ ++#endif /* CONFIG_KDB */ + if (notify_die(DIE_BREAK, "bad break", regs, break_num, TRAP_BRKPT, SIGTRAP) + == NOTIFY_STOP) + return; +@@ -565,6 +583,10 @@ ia64_fault (unsigned long vector, unsign + if (notify_die(DIE_FAULT, "ia64_fault", ®s, vector, siginfo.si_code, SIGTRAP) + == NOTIFY_STOP) + return; ++#ifdef CONFIG_KDB ++ if (!user_mode(®s) && kdb(KDB_REASON_DEBUG, vector, ®s)) ++ return; /* kdb handled this */ ++#endif /* CONFIG_KDB */ + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = 0; + siginfo.si_addr = (void __user *) ifa; +--- a/arch/ia64/kernel/unwind.c ++++ b/arch/ia64/kernel/unwind.c +@@ -57,14 +57,27 @@ + + #ifdef UNW_DEBUG + static unsigned int unw_debug_level = UNW_DEBUG; +-# define UNW_DEBUG_ON(n) unw_debug_level >= n +- /* Do not code a printk level, not all debug lines end in newline */ +-# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) ++# ifdef CONFIG_KDB ++# include ++# include ++# define UNW_KMALLOC(s, f) debug_kmalloc(s, f) ++# define UNW_KFREE(p) debug_kfree(p) ++# define UNW_DEBUG_ON(n) (unw_debug_level >= n && !KDB_IS_RUNNING()) ++# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) kdb_printf(__VA_ARGS__) ++# else /* !CONFIG_KDB */ ++# define UNW_DEBUG_ON(n) unw_debug_level >= n ++ /* Do not code a printk level, not all debug lines end in newline */ ++# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) ++# define UNW_KMALLOC(s, f) kmalloc(s, f) ++# define UNW_KFREE(p) kfree(p) ++# endif /* CONFIG_KDB */ + # undef inline + # define inline + #else /* !UNW_DEBUG */ + # define UNW_DEBUG_ON(n) 0 + # define UNW_DPRINT(n, ...) ++# define UNW_KMALLOC(s, f) kmalloc(s, f) ++# define UNW_KFREE(p) kfree(p) + #endif /* UNW_DEBUG */ + + #if UNW_STATS +@@ -73,10 +86,10 @@ + # define STAT(x...) + #endif + +-#define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) +-#define free_reg_state(usr) kfree(usr) +-#define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) +-#define free_labeled_state(usr) kfree(usr) ++#define alloc_reg_state() UNW_KMALLOC(sizeof(struct unw_reg_state), GFP_ATOMIC) ++#define free_reg_state(usr) UNW_KFREE(usr) ++#define alloc_labeled_state() UNW_KMALLOC(sizeof(struct unw_labeled_state), GFP_ATOMIC) ++#define free_labeled_state(usr) UNW_KFREE(usr) + + typedef unsigned long unw_word; + typedef unsigned char unw_hash_index_t; +@@ -2092,7 +2105,7 @@ unw_add_unwind_table (const char *name, + return NULL; + } + +- table = kmalloc(sizeof(*table), GFP_USER); ++ table = UNW_KMALLOC(sizeof(*table), GFP_USER); + if (!table) + return NULL; + +@@ -2165,7 +2178,7 @@ unw_remove_unwind_table (void *handle) + write_unlock(&tmp->lock); + } + +- kfree(table); ++ UNW_KFREE(table); + } + + static int __init +@@ -2199,7 +2212,7 @@ create_gate_table (void) + size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); + size += 8; /* reserve space for "end of table" marker */ + +- unw.gate_table = kmalloc(size, GFP_KERNEL); ++ unw.gate_table = UNW_KMALLOC(size, GFP_KERNEL); + if (!unw.gate_table) { + unw.gate_table_size = 0; + printk(KERN_ERR "%s: unable to create unwind data for gate page!\n", __func__); diff --git a/src/patches/suse-2.6.27.31/patches.suse/kdb-serial-8250 b/src/patches/suse-2.6.27.31/patches.suse/kdb-serial-8250 new file mode 100644 index 000000000..e1c579c45 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kdb-serial-8250 @@ -0,0 +1,29 @@ +Subject: Don't use outside CONFIG_KDB +From: schwab@suse.de +Patch-mainline: never + +--- + drivers/serial/8250.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/serial/8250.c ++++ b/drivers/serial/8250.c +@@ -43,8 +43,8 @@ + #include + + #include "8250.h" +-#include + #ifdef CONFIG_KDB ++#include + /* + * kdb_serial_line records the serial line number of the first serial console. + * NOTE: The kernel ignores characters on the serial line unless a user space +@@ -55,6 +55,8 @@ + + static int kdb_serial_line = -1; + static const char *kdb_serial_ptr = kdb_serial_str; ++#else ++#define KDB_8250() 0 + #endif /* CONFIG_KDB */ + + /* diff --git a/src/patches/suse-2.6.27.31/patches.suse/kdb-x86 b/src/patches/suse-2.6.27.31/patches.suse/kdb-x86 new file mode 100644 index 000000000..44a2bdb1c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kdb-x86 @@ -0,0 +1,33331 @@ +From: SGI KDB Development +Subject: kdb-v4.4-2.6.27-rc8-x86-1 +References: FATE#303971 +X-URL: ftp://oss.sgi.com/www/projects/kdb/download/v4.4/ + +The KDB x86 code. + +Acked-by: Bernhard Walle + +--- + arch/x86/Kconfig.debug | 88 + arch/x86/Makefile | 3 + arch/x86/kdb/ChangeLog | 230 + + arch/x86/kdb/ChangeLog_32 | 865 ++++++ + arch/x86/kdb/ChangeLog_64 | 447 +++ + arch/x86/kdb/Makefile | 5 + arch/x86/kdb/Makefile_32 | 25 + arch/x86/kdb/Makefile_64 | 25 + arch/x86/kdb/i386-dis.c | 4686 +++++++++++++++++++++++++++++++++++ + arch/x86/kdb/kdb_cmds_32 | 17 + arch/x86/kdb/kdb_cmds_64 | 18 + arch/x86/kdb/kdba_bp_32.c | 914 ++++++ + arch/x86/kdb/kdba_bp_64.c | 912 ++++++ + arch/x86/kdb/kdba_bt.c | 5597 ++++++++++++++++++++++++++++++++++++++++++ + arch/x86/kdb/kdba_id.c | 261 + + arch/x86/kdb/kdba_io.c | 609 ++++ + arch/x86/kdb/kdba_support.c | 59 + arch/x86/kdb/kdbasupport_32.c | 1072 ++++++++ + arch/x86/kdb/kdbasupport_64.c | 1022 +++++++ + arch/x86/kdb/pc_keyb.h | 137 + + arch/x86/kdb/x86_64-dis.c | 4686 +++++++++++++++++++++++++++++++++++ + arch/x86/kernel/crash.c | 110 + arch/x86/kernel/entry_32.S | 20 + arch/x86/kernel/entry_64.S | 27 + arch/x86/kernel/io_apic_32.c | 8 + arch/x86/kernel/io_apic_64.c | 8 + arch/x86/kernel/reboot.c | 11 + arch/x86/kernel/traps_32.c | 48 + arch/x86/kernel/traps_64.c | 2 + include/asm-x86/ansidecl.h | 5 + include/asm-x86/ansidecl_32.h | 383 ++ + include/asm-x86/ansidecl_64.h | 383 ++ + include/asm-x86/bfd.h | 5 + include/asm-x86/bfd_32.h | 4921 ++++++++++++++++++++++++++++++++++++ + include/asm-x86/bfd_64.h | 4917 ++++++++++++++++++++++++++++++++++++ + include/asm-x86/irq_vectors.h | 6 + include/asm-x86/kdb.h | 134 + + include/asm-x86/kdbprivate.h | 241 + + include/asm-x86/kdebug.h | 2 + include/asm-x86/kmap_types.h | 3 + include/asm-x86/ptrace.h | 23 + 41 files changed, 32930 insertions(+), 5 deletions(-) + +--- a/arch/x86/Kconfig.debug ++++ b/arch/x86/Kconfig.debug +@@ -302,5 +302,91 @@ config OPTIMIZE_INLINING + + If unsure, say N. + +-endmenu ++config KDB ++ bool "Built-in Kernel Debugger support" ++ depends on DEBUG_KERNEL ++ select KALLSYMS ++ select KALLSYMS_ALL ++ help ++ This option provides a built-in kernel debugger. The built-in ++ kernel debugger contains commands which allow memory to be examined, ++ instructions to be disassembled and breakpoints to be set. For details, ++ see Documentation/kdb/kdb.mm and the manual pages kdb_bt, kdb_ss, etc. ++ Kdb can also be used via the serial port. Set up the system to ++ have a serial console (see Documentation/serial-console.txt). ++ The key sequence KDB on the serial port will cause the ++ kernel debugger to be entered with input from the serial port and ++ output to the serial console. If unsure, say N. ++ ++config KDB_MODULES ++ tristate "KDB modules" ++ depends on KDB ++ help ++ KDB can be extended by adding your own modules, in directory ++ kdb/modules. This option selects the way that these modules should ++ be compiled, as free standing modules (select M) or built into the ++ kernel (select Y). If unsure say M. ++ ++config KDB_OFF ++ bool "KDB off by default" ++ depends on KDB ++ help ++ Normally kdb is activated by default, as long as CONFIG_KDB is set. ++ If you want to ship a kernel with kdb support but only have kdb ++ turned on when the user requests it then select this option. When ++ compiled with CONFIG_KDB_OFF, kdb ignores all events unless you boot ++ with kdb=on or you echo "1" > /proc/sys/kernel/kdb. This option also ++ works in reverse, if kdb is normally activated, you can boot with ++ kdb=off or echo "0" > /proc/sys/kernel/kdb to deactivate kdb. If ++ unsure, say N. ++ ++config KDB_CONTINUE_CATASTROPHIC ++ int "KDB continues after catastrophic errors" ++ depends on KDB ++ default "0" ++ help ++ This integer controls the behaviour of kdb when the kernel gets a ++ catastrophic error, i.e. for a panic, oops, NMI or other watchdog ++ tripping. CONFIG_KDB_CONTINUE_CATASTROPHIC interacts with ++ /proc/sys/kernel/kdb and CONFIG_LKCD_DUMP (if your kernel has the ++ LKCD patch). ++ When KDB is active (/proc/sys/kernel/kdb == 1) and a catastrophic ++ error occurs, nothing extra happens until you type 'go'. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default). The first time ++ you type 'go', kdb warns you. The second time you type 'go', KDB ++ tries to continue - no guarantees that the kernel is still usable. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 1. KDB tries to continue - no ++ guarantees that the kernel is still usable. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD ++ patch and LKCD is configured to take a dump then KDB forces a dump. ++ Whether or not a dump is taken, KDB forces a reboot. ++ When KDB is not active (/proc/sys/kernel/kdb == 0) and a catastrophic ++ error occurs, the following steps are automatic, no human ++ intervention is required. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default) or 1. KDB attempts ++ to continue - no guarantees that the kernel is still usable. ++ CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD ++ patch and LKCD is configured to take a dump then KDB automatically ++ forces a dump. Whether or not a dump is taken, KDB forces a ++ reboot. ++ If you are not sure, say 0. Read Documentation/kdb/dump.txt before ++ setting to 2. + ++config KDB_USB ++ bool "Support for USB Keyboard in KDB (OHCI and/or EHCI only)" ++ depends on KDB && (USB_OHCI_HCD || USB_EHCI_HCD) ++ help ++ If you want to use kdb from USB keyboards then say Y here. If you ++ say N then kdb can only be used from a PC (AT) keyboard or a serial ++ console. ++ ++config KDB_KDUMP ++ bool "Support for Kdump in KDB" ++ depends on KDB ++ select KEXEC ++ default N ++ help ++ If you want to take Kdump kernel vmcore from KDB then say Y here. ++ Of imsire. say N. ++ ++endmenu +--- /dev/null ++++ b/arch/x86/kdb/ChangeLog +@@ -0,0 +1,230 @@ ++2008-09-30 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc8-x86-1. ++ ++2008-09-22 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc7-x86-1. ++ ++2008-09-03 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc5-x86-1. ++ ++2008-08-19 Jay Lan ++ ++ * kdb-v4.4-2.6.27-rc3-x86-1. ++ ++2008-08-14 Jay Lan ++ ++ * Support 'kdump' command to take a kdump vmcore from KDB, ++ Dan Aloni (da-x@monatomic.org), ++ Jason Xiao (jidong.xiao@gmail.com), ++ Jay Lan (jlan@sgi.com) ++ * kdb-v4.4-2.6.27-rc2-x86-2. ++ ++2008-08-06 Jay Lan ++ ++ * Fix up the NULL pointer deference issue in ohci_kdb_poll_char, ++ Jason Xiao ++ * Backtrace on x86_64 and i386 were incomplete since 2.6.27-rc2. ++ * kdb-v4.4-2.6.27-rc2-x86-1. ++ ++2008-07-18 Jay Lan ++ ++ * support Hardware Breakpoint (bph/bpha) commands ++ IA64: Greg Banks ++ X86: Konstantin Baydarov ++ * kdb-v4.4-2.6.26-x86-2. ++ ++2008-07-14 Jay Lan ++ ++ * kdb-v4.4-2.6.26-x86-1. ++ ++2008-07-11 Jay Lan ++ ++ * New commands and some fixups and enhancements, ++ Joe Korty ++ John Blackwood ++ Jim Houston ++ - Use the non-sleeping copy_from_user_atomic. ++ - Enhance kdb_cmderror diagnostic output. ++ - Expand the KDB 'duplicate command' error message. ++ - Touch NMI watchdog in various KDB busy-loops. ++ - Support IMB HS20 Blade 8843 platform. ++ - Display exactly which cpus needed an NMI to get them into kdb. ++ - Better document that kdb's 'ps A' command can be used to show ++ _all_ processes and threads ++ - Suppress KDB boottime INFO messages if quiet boot. ++ - Add a KDB breakpoint to the OOPs path. ++ - Add CONFIG_DISCONTIGMEM support to kdbm_memmap. ++ - Extend the KDB task command to handle CONFIG_NUMA fields. ++ - Extend the KDB vm command to support NUMA stuff. ++ - Create the KDB mempolicy command. ++ - Create a pgdat command for KDB. ++ - Fix a hang on boot on some i386 systems. ++ * kdb-v4.4-2.6.26-rc9-x86-1. ++ ++2008-06-30 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc8-x86-1. ++ ++2008-06-25 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc7-x86-1. ++ ++2008-06-06 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc5-x86-1. ++ ++2008-05-30 Jay Lan ++ ++ * kdb-v4.4-2.6.26-rc4-x86-1. ++ ++2008-05-20 Jay Lan ++ ++ * Merged and to . ++ * Merged and to ++ . ++ * kdb-v4.4-2.6.26-rc3-x86-1. ++ ++2008-05-15 Jay Lan ++ ++ * Fixed the i386 backtrace problem where KDB failed to find stacks ++ in the kernel space. ++ * kdb-v4.4-2.6.26-rc1-x86-3. ++ ++2008-05-14 Jay Lan ++ ++ * Fixed a bug that bb_all scans only odd number entries of kallsyms. ++ * kdb-v4.4-2.6.26-rc1-x86-2. ++ ++2008-05-13 Jay Lan ++ ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * kdb-v4.4-2.6.26-rc1-x86-1. ++ ++2008-05-13 Jay Lan ++ ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * Fixed a couple of x86_64 problems: ++ - "iret_label" are replaced by "irq_return". ++ - bb1 failure on ia32_sysenter_target() & ia32_cstar_target() ++ * kdb-v4.4-2.6.25-x86-2. ++ ++2008-04-17 Jay Lan ++ ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * kdb-v4.4-2.6.25-x86-1. ++ ++2008-03-19 Jay Lan ++ ++ * i386: systenter_entry was replaced with ia32_sysenter_target since ++ 2.6.25-rc1, Jay Lan ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * kdb-v4.4-2.6.25-rc6-x86-2. ++ ++2008-03-16 Jay Lan ++ ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * kdb-v4.4-2.6.25-rc6-x86-1. ++ ++2008-03-03 Jay Lan ++ ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * kdb-v4.4-2.6.25-rc3-x86-1. ++ ++2008-02-26 Jay Lan ++ ++ * remove 'fastcall' from kdb code. ++ * Known problem: backtrace for i386 is broken since 2.6.25-rc1. ++ * kdb-v4.4-2.6.25-rc2-x86-1. ++ ++2008-02-19 Jay Lan ++ ++ * Known problem: backtrace for i386 is broken. ++ * kdb-v4.4-2.6.25-rc1-x86-1. ++ ++2008-02-01 Jay Lan ++ ++ * Backed out USB UHCI support since it caused dropped characters and ++ broke OHCI. ++ * Restored "archkdbcommon" commands for x86. It was lost at the x86 ++ merge. ++ * Detecting if the HC was "busy", Aaron Young ++ * kdb-v4.4-2.6.24-x86-2. ++ ++2008-01-29 Jay Lan ++ ++ * kdb-v4.4-2.6.24-x86-1. ++ ++2008-01-22 Jay Lan ++ ++ * USB UHCI kdb support, Konstantin Baydarov ++ * kdb-v4.4-2.6.24-rc8-x86-3. ++ ++2008-01-18 Jay Lan ++ ++ * USB EHCI kdb support, Aaron Young ++ * kdb-v4.4-2.6.24-rc8-x86-2. ++ ++2008-01-18 Jay Lan ++ ++ * kdb-v4.4-2.6.24-rc8-x86-1. ++ ++2008-01-09 Jay Lan ++ ++ * Merge arch/x86/kdb/kdba_io_64.c and arch/x86/kdb/kdba_io_32.c to ++ arch/x86/kdb/kdba_io.c ++ * Merge arch/x86/kdb/kdba_id_64.c and arch/x86/kdb/kdba_id_32.c to ++ arch/x86/kdb/kdba_id.c ++ * Merge arch/x86/kdb/pc_keyb_64.h and arch/x86/kdb/pc_keyb_32.h to ++ arch/x86/kdb/pc_keyb.h ++ * kdb-v4.4-2.6.24-rc7-x86-2. ++ ++2008-01-07 Jay Lan ++ ++ * kdb-v4.4-2.6.24-rc7-x86-1. ++ ++2007-12-21 Jay Lan ++ ++ * Renamed kdb/kdba_bt_x86.c to arch/x86/kdba_bt.c. ++ * Find gcc options 'no-optimize-sibling-calls' & 'regparm' from ++ $(KBUILD_CFLAGS) in arch/x86/kdb/Makefile_{32,64}. We used to ++ get them from $(CFLAGS). ++ * Default regparm to 3 on x86_32 if not defined. ++ * kdb v4.4-2.6.24-rc6-x86-1. ++ ++2007-12-12 Jay Lan ++ ++ * Fixed a Makefile_32 error. ++ * kdb v4.4-2.6.24-rc5-x86-1. ++ ++2007-12-05 Jay Lan ++ ++ * Fixed a 'sysctl table check failed' problem. ++ * kdb v4.4-2.6.24-rc4-x86-1. ++ ++2007-11-26 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc3-x86-1. ++ ++2007-11-13 Jay Lan ++ ++ * Back ported "New KDB USB interface" from Aaron Young in ++ v4.4-2.6.23-{i386,x86_64}-2 to 2.6.24 kdb patchset. ++ * Fixed a make problem at arch/x86/Makefile_{32,64}. ++ * kdb v4.4-2.6.24-rc2-x86-2. ++ ++2007-11-12 Jay Lan ++ ++ * kdb v4.4-2.6.24-rc2-x86-1. ++ ++2007-11-09 Jay Lan ++ ++ * Rebase to 2.6.24-rc1 kernel ++ * - merged kdb-v4.4-2.6.23-i386-1 and kdb-v4.4-2.6.23-x86_64-1 ++ * into kdb-v4.4-2.6.24-rc1-x86-1 ++ * - Fields "done", "sglist_len", and "pid" are removed from ++ * struct scsi_cmnd. Thus, these fields are no longer displayed ++ * on "sc" command. ++ * kdb v4.4-2.6.24-rc1-x86-1. +--- /dev/null ++++ b/arch/x86/kdb/ChangeLog_32 +@@ -0,0 +1,865 @@ ++2007-11-08 Jay Lan ++ ++ * New KDB USB interface, Aaron Young ++ * 1. This patch allows KDB to work with any Host Contoller driver ++ * and call the correct HC driver poll routine (as long as the ++ * HC driver provides a .kdb_poll_char routine via it's ++ * associated hc_driver struct). ++ * 2. Hotplugged keyboards are now recognized by KDB. ++ * 3. Currently KDB can only make use of 1 USB type keyboard. ++ * New code can handle up to 8 attached keyboards - input is ++ * multiplexed from all of them while in kdb. ++ * kdb v4.4-2.6.23-common-2. ++ ++2007-10-24 Jay Lan ++ ++ * kdb v4.4-2.6.23-i386-1. ++ ++2007-09-26 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc8-i386-1. ++ ++2007-09-21 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc7-i386-1. ++ ++2007-09-12 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc6-i386-1. ++ ++2007-09-06 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc5-i386-1. ++ ++2007-08-30 Keith Owens ++ ++ * New i386/x86_64 backtrace requires that kdb_save_running() does not ++ exit until after kdb_main_loop() has completed. ++ * kdb v4.4-2.6.23-rc4-i386-2. ++ ++2007-08-30 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc4-i386-1. ++ ++2007-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc3-i386-1. ++ ++2007-08-07 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc2-i386-1. ++ ++2007-07-31 Keith Owens ++ ++ * Delete obsolete kdba_bt.c. ++ * kdb v4.4-2.6.23-rc1-i386-2. ++ ++2007-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc1-i386-1. ++ ++2007-07-26 Keith Owens ++ ++ * New x86 backtrace code. ++ * kdb v4.4-2.6.22-i386-2. ++ ++2007-07-09 Keith Owens ++ ++ * kdb v4.4-2.6.22-i386-1. ++ ++2007-07-02 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc7-i386-1. ++ ++2007-06-20 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc5-i386-1. ++ ++2007-06-08 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc4-i386-1. ++ ++2007-05-28 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc3-i386-1. ++ ++2007-05-22 Keith Owens ++ ++ * Register KDBENTER_VECTOR early on the boot cpu. ++ * kdb v4.4-2.6.22-rc2-i386-2. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc2-i386-1. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc1-i386-1. ++ ++2007-05-17 Keith Owens ++ ++ * Update dumpregs comments for rdmsr and wrmsr commands. ++ Bernardo Innocenti. ++ * kdb v4.4-2.6.21-i386-3. ++ ++2007-05-15 Keith Owens ++ ++ * Change kdba_late_init to kdba_arch_init so KDB_ENTER() can be used ++ earlier. ++ * kdb v4.4-2.6.21-i386-2. ++ ++2007-04-29 Keith Owens ++ ++ * kdb v4.4-2.6.21-i386-1. ++ ++2007-04-16 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc7-i386-1. ++ ++2007-04-10 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc6-i386-1. ++ ++2007-04-02 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc5-i386-1. ++ ++2007-03-19 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc4-i386-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc3-i386-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc2-i386-1. ++ ++2007-03-01 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc1-i386-1. ++ ++2007-03-01 Keith Owens ++ ++ * Remove sparse warnings. ++ * kdb v4.4-2.6.20-i386-3. ++ ++2007-02-16 Keith Owens ++ ++ * Initialise variable bits of struct disassemble_info each time. ++ * kdb v4.4-2.6.20-i386-2. ++ ++2007-02-06 Keith Owens ++ ++ * kdb v4.4-2.6.20-i386-1. ++ ++2007-02-01 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc7-i386-1. ++ ++2007-01-08 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc4-i386-1. ++ ++2007-01-02 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc3-i386-1. ++ ++2006-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc1-i386-1. ++ ++2006-11-30 Keith Owens ++ ++ * kdb v4.4-2.6.19-i386-1. ++ ++2006-11-27 Keith Owens ++ ++ * Only use VT keyboard if the command line allows it and ACPI indicates ++ that there is an i8042. ++ * kdb v4.4-2.6.19-rc6-i386-2. ++ ++2006-11-20 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc6-i386-1. ++ ++2006-11-09 Keith Owens ++ ++ * Change kdb() to fastcall. ++ * Add unwind info to kdb_call(). Steve Lord. ++ * Only use VT console if the command line allows it. ++ * kdb v4.4-2.6.19-rc5-i386-2. ++ ++2006-11-08 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc5-i386-1. ++ ++2006-11-01 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc4-i386-1. ++ ++2006-10-24 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc3-i386-1. ++ ++2006-10-24 Keith Owens ++ ++ * Remove redundant regs and envp parameters. ++ * kdb v4.4-2.6.19-rc2-i386-2. ++ ++2006-10-18 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc2-i386-1. ++ ++2006-10-11 Keith Owens ++ ++ * Move kdbm_x86.c from the i386 to the common KDB patch. ++ * Make the KDBENTER_VECTOR an interrupt gate instead of a trap gate, it ++ simplifies the code and disables interrupts on KDBENTER(). ++ * Exclude the KDBENTER_VECTOR from irq assignment. ++ * kdb v4.4-2.6.19-rc1-i386-2. ++ ++2006-10-09 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc1-i386-1. ++ ++2006-10-06 Keith Owens ++ ++ * Remove #include ++ * kdb v4.4-2.6.18-i386-2. ++ ++2006-09-20 Keith Owens ++ ++ * kdb v4.4-2.6.18-i386-1. ++ ++2006-09-15 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc7-i386-1. ++ ++2006-08-30 Keith Owens ++ ++ * Add warning for problems when following alternate stacks. ++ * kdb v4.4-2.6.18-rc5-i386-3. ++ ++2006-08-29 Keith Owens ++ ++ * Rewrite all backtrace code. ++ * kdb v4.4-2.6.18-rc5-i386-2. ++ ++2006-08-28 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc5-i386-1. ++ ++2006-08-08 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc4-i386-1. ++ ++2006-08-04 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc3-i386-1. ++ ++2006-07-18 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc2-i386-1. ++ ++2006-07-12 Keith Owens ++ ++ * Remove dead KDB_REASON codes. ++ * sparse cleanups. ++ * kdb v4.4-2.6.18-rc1-i386-2. ++ ++2006-07-07 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc1-i386-1. ++ ++2006-07-04 Keith Owens ++ ++ * Make KDB rendezvous on i386 a two stage approach. ++ * Clean up generation of KDB interrupt code. ++ * Move smp_kdb_stop() and smp_kdb_interrupt() to kdbasupport.c. ++ * Move setting of interrupt traps to kdbasupport.c. ++ * Remove KDB hooks from arch/i386/kernel smp.c, smpboot.c, i8259.c, ++ io_apic.c. ++ * Add KDB_REASON_CPU_UP support. ++ * Move per cpu setup to kdba_cpu_up(). ++ * Rework support for 4K stacks to make backtrace more accurate. ++ * Add BTSP option to get the full backtrace, including kdb routines. ++ * Delete kdba_enable_mce, architectures now do their own setup. ++ * Delete kdba_enable_lbr, kdba_disable_lbr, kdba_print_lbr, ++ page_fault_mca. Only ever implemented on x86, difficult to maintain ++ and rarely used in the field. ++ * Replace #ifdef KDB_HAVE_LONGJMP with #ifdef kdba_setjmp. ++ * kdb v4.4-2.6.17-i386-2. ++ ++2006-06-19 Keith Owens ++ ++ * kdb v4.4-2.6.17-i386-1. ++ ++2006-05-25 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc5-i386-1. ++ ++2006-05-15 Keith Owens ++ ++ * Refresh bfd related files from binutils 2.16.91.0.2. ++ * kdb v4.4-2.6.17-rc4-i386-2. ++ ++2006-05-12 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc4-i386-1. ++ ++2006-04-28 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc3-i386-1. ++ ++2006-04-22 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc2-i386-1. ++ ++2006-04-11 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc1-i386-1. ++ ++2006-03-30 Keith Owens ++ ++ * Change CONFIG_LKCD to CONFIG_LKCD_DUMP. ++ * kdb v4.4-2.6.16-i386-3. ++ ++2006-03-24 Keith Owens ++ ++ * Define a dummy kdba_wait_for_cpus(). ++ * kdb v4.4-2.6.16-i386-2. ++ ++2006-03-21 Keith Owens ++ ++ * kdb v4.4-2.6.16-i386-1. ++ ++2006-03-14 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc6-i386-1. ++ ++2006-02-28 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc5-i386-1. ++ ++2006-02-20 Nathan Scott ++ ++ * kdb v4.4-2.6.16-rc4-i386-1. ++ ++2006-02-06 Keith Owens ++ ++ * Change CONFIG_CRASH_DUMP to CONFIG_LKCD. ++ * kdb v4.4-2.6.16-rc2-i386-2. ++ ++2006-02-06 Keith Owens ++ ++ * kdb v4.4-2.6.16-rc2-i386-1. ++ ++2006-01-18 Keith Owens ++ ++ * kdb v4.4-2.6.16-rc1-i386-1. ++ ++2006-01-08 Keith Owens ++ ++ * Add DIE_KDEBUG_ENTER and DIE_KDEBUG_LEAVE to notify_die. ++ * kdb v4.4-2.6.15-i386-2. ++ ++2006-01-04 Keith Owens ++ ++ * Remove some inlines and the last vestige of CONFIG_NUMA_REPLICATE. ++ * Read the keyboard acknowledgment after sending a character. SuSE ++ Bugzilla 60240. ++ * kdb v4.4-2.6.15-i386-1. ++ ++2005-12-25 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc7-i386-1. ++ ++2005-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc6-i386-1. ++ ++2005-12-05 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc5-i386-1. ++ ++2005-12-02 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc4-i386-1. ++ ++2005-11-30 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc3-i386-1. ++ ++2005-11-21 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc2-i386-1. ++ ++2005-11-15 Keith Owens ++ ++ * kdb v4.4-2.6.15-rc1-i386-1. ++ ++2005-10-28 Keith Owens ++ ++ * kdb v4.4-2.6.14-i386-1. ++ ++2005-10-21 Keith Owens ++ ++ * kdb v4.4-2.6.14-rc5-i386-1. ++ ++2005-10-11 Keith Owens ++ ++ * kdb v4.4-2.6.14-rc4-i386-1. ++ ++2005-10-04 Keith Owens ++ ++ * kdb v4.4-2.6.14-rc3-i386-1. ++ ++2005-09-21 Keith Owens ++ ++ * Support kdb_current_task in register display and modify commands. ++ * kdb v4.4-2.6.14-rc2-i386-1. ++ ++2005-09-20 Keith Owens ++ ++ * Remove use of __STDC_VERSION__ in ansidecl.h. ++ * kdb v4.4-2.6.14-rc1-i386-1. ++ ++2005-08-29 Keith Owens ++ ++ * kdb v4.4-2.6.13-i386-1. ++ ++2005-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc7-i386-1. ++ ++2005-08-08 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc6-i386-1. ++ ++2005-08-02 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc5-i386-1. ++ ++2005-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc4-i386-1. ++ ++2005-07-22 Keith Owens ++ ++ * Compile fix for kprobes. ++ * kdb v4.4-2.6.13-rc3-i386-2. ++ ++2005-07-19 Keith Owens ++ ++ * Add support for USB keyboard (OHCI only). Aaron Young, SGI. ++ * kdb v4.4-2.6.13-rc3-i386-1. ++ ++2005-07-08 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc2-i386-1. ++ ++2005-07-01 Keith Owens ++ ++ * kdb v4.4-2.6.13-rc1-i386-1. ++ ++2005-06-19 Keith Owens ++ ++ * gcc 4 compile fix, remove extern kdb_hardbreaks. Steve Lord. ++ * kdb v4.4-2.6.12-i386-2. ++ ++2005-06-18 Keith Owens ++ ++ * kdb v4.4-2.6.12-i386-1. ++ ++2005-06-08 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc6-i386-1. ++ ++2005-05-25 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc5-i386-1. ++ ++2005-05-08 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc4-i386-1. ++ ++2005-04-21 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc3-i386-1. ++ ++2005-04-06 Keith Owens ++ ++ * kdb v4.4-2.6.12-rc2-i386-1. ++ ++2005-03-29 Keith Owens ++ ++ * Replace __copy_to_user with __copy_to_user_inatomic. ++ * kdb v4.4-2.6.12-rc1-i386-1. ++ ++2005-03-08 Keith Owens ++ ++ * Coexistence patches for lkcd. ++ * kdb v4.4-2.6.11-i386-2. ++ ++2005-03-03 Keith Owens ++ ++ * kdb v4.4-2.6.11-i386-1. ++ ++2005-02-14 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc4-i386-1. ++ ++2005-02-08 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc3-bk4-i386-1. ++ ++2005-02-03 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc3-i386-1. ++ ++2005-01-27 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc2-i386-1. ++ ++2005-01-12 Keith Owens ++ ++ * kdb v4.4-2.6.11-rc1-i386-1. ++ ++2004-12-25 Keith Owens ++ ++ * kdb v4.4-2.6.10-i386-1. ++ ++2004-12-07 Keith Owens ++ ++ * kdb v4.4-2.6.10-rc3-i386-1. ++ ++2004-11-23 Keith Owens ++ ++ * Coexist with asmlinkage/fastcall changes. ++ * kdb v4.4-2.6.10-rc2-i386-1. ++ ++2004-10-29 Keith Owens ++ ++ * Handle change defintions for hard and soft irq context. ++ * Make stack switch in kdb backtrace look more like the oops output. ++ * kdb v4.4-2.6.10-rc1-i386-1. ++ ++2004-10-19 Keith Owens ++ ++ * kdb v4.4-2.6.9-i386-1. ++ ++2004-10-12 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc4-i386-1. ++ ++2004-10-01 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc3-i386-1. ++ ++2004-09-30 Keith Owens ++ ++ * Add stackdepth command. ++ * Handle backtrace with separate soft and hard irq stacks ++ (CONFIG_4KSTACKS). ++ * Work around RESTORE_ALL macro, which can only be used once. ++ * Export kdba_dumpregs. Bryan Cardillo, UPenn. ++ * kdb v4.4-2.6.9-rc2-i386-2. ++ ++2004-09-14 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc2-i386-1. ++ ++2004-08-27 Keith Owens ++ ++ * kdb v4.4-2.6.9-rc1-i386-1. ++ ++2004-08-14 Keith Owens ++ ++ * kdb v4.4-2.6.8-i386-1. ++ ++2004-08-12 Keith Owens ++ ++ * kdb v4.4-2.6.8-rc4-i386-1. ++ ++2004-08-04 Keith Owens ++ ++ * kdb v4.4-2.6.8-rc3-i386-1. ++ ++2004-07-18 Keith Owens ++ ++ * kdb v4.4-2.6.8-rc2-i386-1. ++ ++2004-07-12 Keith Owens ++ ++ * kdb v4.4-2.6.8-rc1-i386-1. ++ ++2004-06-16 Keith Owens ++ ++ * kdb v4.4-2.6.7-i386-1. ++ ++2004-06-10 Keith Owens ++ ++ * kdb v4.4-2.6.7-rc3-i386-1. ++ ++2004-06-09 Keith Owens ++ ++ * Namespace clean up. Mark code/variables as static when it is only ++ used in one file, delete dead code/variables. ++ * kdb v4.4-2.6.7-rc2-i386-3. ++ ++2004-06-08 Keith Owens ++ ++ * Whitespace clean up, no code changes. ++ * kdb v4.4-2.6.7-rc2-i386-2. ++ ++2004-06-07 Keith Owens ++ ++ * Force KALLSYMS and KALLSYMS_ALL for CONFIG_KDB. ++ * kdb v4.4-2.6.7-rc2-i386-1. ++ ++2004-06-06 Keith Owens ++ ++ * Correct Kconfig help text. ++ * Coexist with CONFIG_REGPARM. ++ * Add standard archkdb commands. ++ * Move kdb_{get,put}userarea_size definitions to linux/kdb.h. ++ * kdb v4.4-2.6.6-i386-2. ++ ++2004-05-23 Keith Owens ++ ++ * Move bfd.h and ansidecl.h from arch/$(ARCH)/kdb to include/asm-$(ARCH). ++ * Update copyright notices. ++ * kdb v4.4-2.6.6-i386-1. ++ ++2004-05-10 Keith Owens ++ ++ * kdb v4.3-2.6.6-i386-1. ++ ++2004-05-06 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc3-i386-1. ++ ++2004-05-06 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc2-i386-1. ++ ++2004-04-30 Keith Owens ++ ++ * kdb v4.3-2.6.6-rc1-i386-1. ++ ++2004-04-05 Keith Owens ++ ++ * kdb v4.3-2.6-5-i386-1. ++ ++2004-02-29 Keith Owens ++ ++ * kdb v4.3-2.6-4-rc1-i386-1. ++ ++2004-02-18 Keith Owens ++ ++ * kdb v4.3-2.6-3-i386-1. ++ ++2004-02-17 Keith Owens ++ ++ * Pick up changes from Jim Houston for 2.6. ++ * Sync with kdb v4.3-2.4.25-rc1-i386-1. ++ * Adjust for LDT changes in i386 mainline. ++ * Convert longjmp buffers from static to dynamic allocation, for large ++ cpu counts. ++ * Do not use USB keyboard if it has not been probed. ++ * Do not print section data, 2.6 kallsyms does not support sections :(. ++ * kdb v4.3-2.6-3-rc3-i386-1. ++ ++2003-08-29 Keith Owens ++ ++ * kdb v4.3-2.4.22-i386-1. ++ ++2003-08-05 Keith Owens ++ ++ * Remove duplicate setting of trap for machine_check. ++ * Only reset keyboard when CONFIG_VT_CONSOLE is defined. ++ ++2003-07-27 Keith Owens ++ ++ * kdb v4.3-2.4.22-pre8-i386-5. ++ ++2003-07-20 Keith Owens ++ ++ * Remove compile warning on x86 commands. ++ * kdb v4.3-2.4.21-i386-5. ++ ++2003-07-08 Keith Owens ++ ++ * Add new x86 commands - rdv, gdt, idt, ldt, ldtp, ptex. ++ Vamsi Krishna S., IBM. ++ * kdb v4.3-2.4.21-i386-4. ++ ++2003-07-01 Keith Owens ++ ++ * Convert kdba_find_return() to two passes to reduce false positives. ++ * Correct jmp disp8 offset calculation for out of line lock code. ++ * Use NMI for kdb IPI in clustered APIC mode. Sachin Sant, IBM. ++ * kdb v4.3-2.4.21-i386-3. ++ ++2003-06-23 Keith Owens ++ ++ * Sync with XFS 2.4.21 tree. ++ * kdb v4.3-2.4.21-i386-2. ++ ++2003-06-20 Keith Owens ++ ++ * kdb v4.3-2.4.21-i386-1. ++ ++2003-06-20 Keith Owens ++ ++ * Add CONFIG_KDB_CONTINUE_CATASTROPHIC. ++ * Correct KDB_ENTER() definition. ++ * kdb v4.3-2.4.20-i386-1. ++ ++2003-05-02 Keith Owens ++ ++ * Add kdba_fp_value(). ++ * Limit backtrace size to catch loops. ++ * Add read/write access to user pages. Vamsi Krishna S., IBM ++ * Clean up USB keyboard support. Steven Dake. ++ * kdb v4.2-2.4.20-i386-1. ++ ++2003-04-04 Keith Owens ++ ++ * Workarounds for scheduler bugs. ++ * kdb v4.1-2.4.20-i386-1. ++ ++2003-03-16 Keith Owens ++ ++ * Each cpu saves its state as it enters kdb or before it enters code ++ which cannot call kdb, converting kdb from a pull to a push model. ++ * Clean up kdb interaction with CONFIG_SERIAL_CONSOLE. ++ * Removal of special cases for i386 backtrace from common code ++ simplifies the architecture code. ++ * Add command to dump i386 struct pt_regs. ++ * kdb v4.0-2.4.20-i386-1. ++ ++2003-02-03 Keith Owens ++ ++ * Register kdb commands early. ++ * Handle KDB_ENTER() when kdb=off. ++ * Optimize __kdba_getarea_size when width is a constant. ++ * Decode oops via kallsyms if it is available. ++ * Update copyright notices to 2003. ++ * Handle call *disp32(%reg) in backtrace. ++ * Correct keyboard freeze. Ashish Kalra. ++ * Add command history and editing. Sonic Zhang. ++ * kdb_toggleled is conditional on KDB_BLINK_LED. Bernhard Fischer. ++ * Allow tab on serial line for symbol completion. ++ * Ignore KDB_ENTER() when kdb is already running. ++ * kdb v3.0-2.4.20-i386-1. ++ ++2002-11-29 Keith Owens ++ ++ * Upgrade to 2.4.20. ++ * kdb v2.5-2.4.20-i386-1. ++ ++2002-11-14 Keith Owens ++ ++ * Upgrade to 2.4.20-rc1. ++ * kdb v2.5-2.4.20-rc1-i386-1. ++ ++2002-11-14 Keith Owens ++ ++ * General clean up of handling for breakpoints and single stepping over ++ software breakpoints. ++ * Accept ff 1x as well as ff dx for call *(%reg) in backtrace. ++ * kdb v2.5-2.4.19-i386-1. ++ ++2002-11-01 Keith Owens ++ ++ * Prevent SMP IRQ overwriting KDB_ENTER(). ++ * kdb v2.4-2.4.19-i386-2. ++ ++2002-10-31 Keith Owens ++ ++ * Avoid KDB_VECTOR conflict with DUMP_VECTOR. ++ * Remove kdb_eframe_t. ++ * Sanity check if we have pt_regs. ++ * Remove kdba_getcurrentframe(). ++ * Reinstate missing nmi_watchdog/kdb hook. ++ * kdb v2.4-2.4.19-i386-1. ++ ++2002-10-17 Keith Owens ++ ++ * Correct compile with CONFIG_VT_CONSOLE=n. ++ * kdb v2.3-2.4.19-i386-5. ++ ++2002-10-04 Keith Owens ++ ++ * Add USB keyboard option. ++ * Minimize differences between patches for 2.4 and 2.5 kernels. ++ * kdb v2.3-2.4.19-i386-4. ++ ++2002-08-10 Keith Owens ++ ++ * Replace kdb_port with kdb_serial to support memory mapped I/O. ++ Note: This needs kdb v2.3-2.4.19-common-2 or later. ++ * kdb v2.3-2.4.19-i386-3. ++ ++2002-08-09 Keith Owens ++ ++ * Use -fno-optimize-sibling-calls for kdb if gcc supports it. ++ * .text.lock does not consume an activation frame. ++ * kdb v2.3-2.4.19-i386-2. ++ ++2002-08-07 Keith Owens ++ ++ * Upgrade to 2.4.19. ++ * Remove individual SGI copyrights, the general SGI copyright applies. ++ * New .text.lock name. Hugh Dickins. ++ * Set KERNEL_CS in kdba_getcurrentframe. Hugh Dickins. ++ * Clean up disassembly layout. Hugh Dickins, Keith Owens. ++ * Replace hard coded stack size with THREAD_SIZE. Hugh Dickins. ++ * Better stack layout on bt with no frame pointers. Hugh Dickins. ++ * Make i386 IO breakpoints (bpha
IO) work again. ++ Martin Wilck, Keith Owens. ++ * Remove fixed KDB_MAX_COMMANDS size. ++ * Add set_fs() around __copy_to_user on kernel addresses. ++ Randolph Chung. ++ * Position i386 for CONFIG_NUMA_REPLICATE. ++ * kdb v2.3-2.4.19-i386-1. ++ ++2002-07-09 Keith Owens ++ ++ * Upgrade to 2.4.19-rc1. ++ ++2002-06-14 Keith Owens ++ ++ * Upgrade to 2.4.19-pre10. ++ * kdb v2.1-2.4.19-pre10-i386-1. ++ ++2002-04-09 Keith Owens ++ ++ * Upgrade to 2.4.19-pre6. ++ * kdb v2.1-2.4.19-pre6-i386-1. ++ ++2002-02-26 Keith Owens ++ ++ * Upgrade to 2.4.18. ++ * kdb v2.1-2.4.18-i386-1. ++ ++2002-01-18 Keith Owens ++ ++ * Use new kdb_get/put functions. ++ * Define kdba_{get,put}area_size functions for i386. ++ * Remove over-engineered dblist callback functions. ++ * Correctly handle failing call disp32 in backtrace. ++ * Remove bp_instvalid flag, redundant code. ++ * Remove dead code. ++ * kdb v2.1-2.4.17-i386-1. ++ ++2002-01-04 Keith Owens ++ ++ * Sync xfs <-> kdb i386 code. ++ ++2001-12-22 Keith Owens ++ ++ * Split kdb for i386 as kdb v2.0-2.4.17-i386-1. +--- /dev/null ++++ b/arch/x86/kdb/ChangeLog_64 +@@ -0,0 +1,447 @@ ++2007-11-08 Jay Lan ++ ++ * New KDB USB interface, Aaron Young ++ * 1. This patch allows KDB to work with any Host Contoller driver ++ * and call the correct HC driver poll routine (as long as the ++ * HC driver provides a .kdb_poll_char routine via it's ++ * associated hc_driver struct). ++ * 2. Hotplugged keyboards are now recognized by KDB. ++ * 3. Currently KDB can only make use of 1 USB type keyboard. ++ * New code can handle up to 8 attached keyboards - input is ++ * multiplexed from all of them while in kdb. ++ * kdb v4.4-2.6.23-common-2. ++ ++2007-10-24 Jay Lan ++ ++ * kdb v4.4-2.6.23-x86_64-1. ++ ++2007-09-26 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc8-x86_64-1. ++ ++2007-09-21 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc7-x86_64-1. ++ ++2007-09-12 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc6-x86_64-1. ++ ++2007-09-06 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc5-x86_64-1. ++ ++2007-08-30 Keith Owens ++ ++ * New i386/x86_64 backtrace requires that kdb_save_running() does not ++ exit until after kdb_main_loop() has completed. ++ * kdb v4.4-2.6.23-rc4-x86_64-2. ++ ++2007-08-30 Jay Lan ++ ++ * kdb v4.4-2.6.23-rc4-x86_64-1. ++ ++2007-08-24 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc3-x86_64-1. ++ ++2007-08-07 Jay Lan ++ ++ * v4.4-2.6.23-rc2-x86_64-1. ++ ++2007-07-31 Keith Owens ++ ++ * Delete obsolete kdba_bt.c. ++ * kdb v4.4-2.6.23-rc1-x86_64-2. ++ ++2007-07-30 Keith Owens ++ ++ * kdb v4.4-2.6.23-rc1-x86_64-1. ++ ++2007-07-26 Keith Owens ++ ++ * New x86 backtrace code. ++ * kdb v4.4-2.6.22-x86_64-2. ++ ++2007-07-09 Keith Owens ++ ++ * kdb v4.4-2.6.22-x86_64-1. ++ ++2007-07-02 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc7-x86_64-1. ++ ++2007-06-25 Keith Owens ++ ++ * Hook into DIE_NMIWATCHDOG. ++ * kdb v4.4-2.6.22-rc5-x86_64-2. ++ ++2007-06-20 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc5-x86_64-1. ++ ++2007-06-08 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc4-x86_64-1. ++ ++2007-05-28 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc3-x86_64-1. ++ ++2007-05-22 Keith Owens ++ ++ * Register KDBENTER_VECTOR early on the boot cpu. ++ * kdb v4.4-2.6.22-rc2-x86_64-2. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc2-x86_64-1. ++ ++2007-05-22 Keith Owens ++ ++ * kdb v4.4-2.6.22-rc1-x86_64-1. ++ ++2007-05-17 Keith Owens ++ ++ * Update dumpregs comments for rdmsr and wrmsr commands. ++ Bernardo Innocenti. ++ * kdb v4.4-2.6.21-x86_64-3. ++ ++2007-05-15 Keith Owens ++ ++ * Change kdba_late_init to kdba_arch_init so KDB_ENTER() can be used ++ earlier. ++ * kdb v4.4-2.6.21-x86_64-2. ++ ++2007-04-29 Keith Owens ++ ++ * kdb v4.4-2.6.21-x86_64-1. ++ ++2007-04-16 Keith Owens ++ ++ * Select KALLSYMS and KALLSYMS_ALL when KDB is selected. ++ * kdb v4.4-2.6.21-rc7-x86_64-2. ++ ++2007-04-16 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc7-x86_64-1. ++ ++2007-04-10 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc6-x86_64-1. ++ ++2007-04-02 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc5-x86_64-1. ++ ++2007-03-19 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc4-x86_64-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc3-x86_64-1. ++ ++2007-03-14 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc2-x86_64-1. ++ ++2007-03-01 Keith Owens ++ ++ * kdb v4.4-2.6.21-rc1-x86_64-1. ++ ++2007-03-01 Keith Owens ++ ++ * Remove sparse warnings. ++ * kdb v4.4-2.6.20-x86_64-3. ++ ++2007-02-16 Keith Owens ++ ++ * Initialise variable bits of struct disassemble_info each time. ++ * kdb v4.4-2.6.20-x86_64-2. ++ ++2007-02-06 Keith Owens ++ ++ * kdb v4.4-2.6.20-x86_64-1. ++ ++2007-02-01 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc7-x86_64-1. ++ ++2007-01-10 Keith Owens ++ ++ * Correct setjmp for the FRAME_POINTER=y case. ++ * Remove duplicate longjmp code for FRAME_POINTER=n/y. ++ * kdb v4.4-2.6.20-rc4-x86_64-2. ++ ++2007-01-08 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc4-x86_64-1. ++ ++2007-01-02 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc3-x86_64-1. ++ ++2006-12-20 Keith Owens ++ ++ * kdb v4.4-2.6.20-rc1-x86_64-1. ++ ++2006-12-07 Keith Owens ++ ++ * Export kdba_dumpregs. ++ * kdb v4.4-2.6.19-x86_64-2. ++ ++2006-11-30 Keith Owens ++ ++ * kdb v4.4-2.6.19-x86_64-1. ++ ++2006-11-27 Keith Owens ++ ++ * Only use VT keyboard if the command line allows it and ACPI indicates ++ that there is an i8042. ++ * kdb v4.4-2.6.19-rc6-x86_64-2. ++ ++2006-11-20 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc6-x86_64-1. ++ ++2006-11-09 Keith Owens ++ ++ * Only use VT console if the command line allows it. ++ * kdb v4.4-2.6.19-rc5-x86_64-2. ++ ++2006-11-08 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc5-x86_64-1. ++ ++2006-11-01 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc4-x86_64-1. ++ ++2006-10-24 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc3-x86_64-1. ++ ++2006-10-24 Keith Owens ++ ++ * Remove redundant regs and envp parameters. ++ * kdb v4.4-2.6.19-rc2-x86_64-2. ++ ++2006-10-18 Keith Owens ++ ++ * kdb v4.4-2.6.19-rc2-x86_64-1. ++ ++2006-10-11 Keith Owens ++ ++ * Make the KDBENTER_VECTOR an interrupt gate instead of a trap gate, it ++ simplifies the code and disables interrupts on KDB_ENTER(). ++ * Exclude the KDBENTER_VECTOR from irq assignment. ++ * Enable KDB_ENTER() again. ++ * kdb v4.4-2.6.19-rc1-x86_64-2. ++ ++2006-10-09 Keith Owens ++ ++ * KDB_ENTER() is getting spurious activations on some x86_64 hardware. ++ Deactivate KDB_ENTER() until it is fixed. ++ * kdb v4.4-2.6.19-rc1-x86_64-1. ++ ++2006-10-06 Keith Owens ++ ++ * Remove #include ++ * kdb v4.4-2.6.18-x86_64-2. ++ ++2006-09-20 Keith Owens ++ ++ * kdb v4.4-2.6.18-x86_64-1. ++ ++2006-09-15 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc7-x86_64-1. ++ ++2006-08-30 Keith Owens ++ ++ * Do not print debugstackptr in cpu_pda, it will be deleted soon. ++ * Add KDB_ENTER(). ++ * Add warning for problems when following alternate stacks. ++ * kdb v4.4-2.6.18-rc5-x86_64-3. ++ ++2006-08-29 Keith Owens ++ ++ * Rewrite all backtrace code. ++ * Add pt_regs and cpu_pda commands. ++ * Include patch to define orig_ist, to be removed once that patch is in ++ the community tree. ++ * kdb v4.4-2.6.18-rc5-x86_64-2. ++ ++2006-08-28 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc5-x86_64-1. ++ ++2006-08-08 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc4-x86_64-1. ++ ++2006-08-04 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc3-x86_64-1. ++ ++2006-07-18 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc2-x86_64-1. ++ ++2006-07-12 Keith Owens ++ ++ * sparse cleanups ++ * kdb v4.4-2.6.18-rc1-x86_64-2. ++ ++2006-07-07 Keith Owens ++ ++ * kdb v4.4-2.6.18-rc1-x86_64-1. ++ ++2006-07-04 Keith Owens ++ ++ * Make KDB rendezvous on x86_64 a two stage approach. ++ * Move smp_kdb_stop() and smp_kdb_interrupt() to kdbasupport.c. ++ * Move setting of interrupt traps to kdbasupport.c. ++ * Add KDB_REASON_CPU_UP support. ++ * Move per cpu setup to kdba_cpu_up(). ++ * Delete kdba_enable_mce, architectures now do their own setup. ++ * Delete kdba_enable_lbr, kdba_disable_lbr, kdba_print_lbr, ++ page_fault_mca. Only ever implemented on x86, difficult to maintain ++ and rarely used in the field. ++ * Replace #ifdef KDB_HAVE_LONGJMP with #ifdef kdba_setjmp. ++ * kdb v4.4-2.6.17-x86_64-2. ++ ++2006-06-19 Keith Owens ++ ++ * kdb v4.4-2.6.17-x86_64-1. ++ ++2006-05-31 Keith Owens ++ ++ * Define arch/x86_64/kdb/kdb_cmds. ++ * kdb v4.4-2.6.17-rc5-x86_64-2. ++ ++2006-05-25 Keith Owens ++ ++ * kdb v4.4-2.6.17-rc5-x86_64-1. ++ ++2006-05-15 Keith Owens ++ ++ * Refresh bfd related files from binutils 2.16.91.0.2. ++ * kdb v4.4-2.6.17-rc4-x86_64-2. ++ ++2006-05-12 Keith Owens ++ ++ * kdb v4.4-2.6-17-rc4-x86_64-1. ++ ++2006-04-22 Keith Owens ++ ++ * kdb v4.4-2.6-17-rc2-x86_64-1. ++ ++2006-04-13 Keith Owens ++ ++ * Remove trailing white space. ++ * kdb v4.4-2.6-17-rc1-x86_64-1. ++ ++2006-03-25 Jack F. Vogel ++ * Sync with Keith's changes for 2.6.16 ++ * code from Andi Kleen to support above ++ ++2005-09-30 Jack F. Vogel ++ * Port to 2.6.14-rc2 ++ * sync with a couple changes from Keith ++ * Add backtrace code from Jim Houston ++ (thanks Jim) ++ ++2005-08-31 Jack F. Vogel ++ * Change to linker script for kexec ++ thanks to Steven Dake ++ ++2005-08-30 Jack F. Vogel ++ * Notify struct should not be devinit ++ thanks IWAMOTO Toshihiro ++ ++2005-08-25 Jack F. Vogel ++ * Update to 2.6.11 ++ * Fix to synchronize with the notify changes ++ thanks to Jim Houston. ++ ++2004-09-30 Keith Owens ++ * Port to 2.6.9-rc2 ++ * Fix line editting characters. Jim Houston, Comcast. ++ * kdb v4.4-2.6.9-rc2-x86-64-1. ++ ++2004-08-15 Jack F. Vogel ++ * Port to 2.6.8 ++ * tighten up the code, using the built-in ++ die_chain notify interface, thanks to ++ Andi Kleen for pointing this out. ++ ++2004-05-15 Jack F. Vogel ++ * port to 2.6.6 for x86_64 ++ ++2003-12-15 Cliff Neighbors ++ * initial port from i386 to x86_64 ++ ++2002-08-10 Keith Owens ++ ++ * Replace kdb_port with kdb_serial to support memory mapped I/O. ++ Note: This needs kdb v2.3-2.4.19-common-2 or later. ++ * kdb v2.3-2.4.19-i386-3. ++ ++2002-08-09 Keith Owens ++ ++ * Use -fno-optimize-sibling-calls for kdb if gcc supports it. ++ * .text.lock does not consume an activation frame. ++ * kdb v2.3-2.4.19-i386-2. ++ ++2002-08-07 Keith Owens ++ ++ * Upgrade to 2.4.19. ++ * Remove individual SGI copyrights, the general SGI copyright applies. ++ * New .text.lock name. Hugh Dickins. ++ * Set KERNEL_CS in kdba_getcurrentframe. Hugh Dickins. ++ * Clean up disassembly layout. Hugh Dickins, Keith Owens. ++ * Replace hard coded stack size with THREAD_SIZE. Hugh Dickins. ++ * Better stack layout on bt with no frame pointers. Hugh Dickins. ++ * Make i386 IO breakpoints (bpha
IO) work again. ++ Martin Wilck, Keith Owens. ++ * Remove fixed KDB_MAX_COMMANDS size. ++ * Add set_fs() around __copy_to_user on kernel addresses. ++ Randolph Chung. ++ * Position i386 for CONFIG_NUMA_REPLICATE. ++ * kdb v2.3-2.4.19-i386-1. ++ ++2002-07-09 Keith Owens ++ ++ * Upgrade to 2.4.19-rc1. ++ ++2002-06-14 Keith Owens ++ ++ * Upgrade to 2.4.19-pre10. ++ * kdb v2.1-2.4.19-pre10-i386-1. ++ ++2002-04-09 Keith Owens ++ ++ * Upgrade to 2.4.19-pre6. ++ * kdb v2.1-2.4.19-pre6-i386-1. ++ ++2002-02-26 Keith Owens ++ ++ * Upgrade to 2.4.18. ++ * kdb v2.1-2.4.18-i386-1. ++ ++2002-01-18 Keith Owens ++ ++ * Use new kdb_get/put functions. ++ * Define kdba_{get,put}area_size functions for i386. ++ * Remove over-engineered dblist callback functions. ++ * Correctly handle failing call disp32 in backtrace. ++ * Remove bp_instvalid flag, redundant code. ++ * Remove dead code. ++ * kdb v2.1-2.4.17-i386-1. ++ ++2002-01-04 Keith Owens ++ ++ * Sync xfs <-> kdb i386 code. ++ +--- /dev/null ++++ b/arch/x86/kdb/i386-dis.c +@@ -0,0 +1,4686 @@ ++/* Print i386 instructions for GDB, the GNU debugger. ++ Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, ++ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) ++ July 1988 ++ modified by John Hassey (hassey@dg-rtp.dg.com) ++ x86-64 support added by Jan Hubicka (jh@suse.cz) ++ VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ ++ ++/* The main tables describing the instructions is essentially a copy ++ of the "Opcode Map" chapter (Appendix A) of the Intel 80386 ++ Programmers Manual. Usually, there is a capital letter, followed ++ by a small letter. The capital letter tell the addressing mode, ++ and the small letter tells about the operand size. Refer to ++ the Intel manual for details. */ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++#define abort() BUG() ++#else /* __KERNEL__ */ ++#include "dis-asm.h" ++#include "sysdep.h" ++#include "opintl.h" ++#endif /* __KERNEL__ */ ++ ++#define MAXLEN 20 ++ ++#ifndef __KERNEL__ ++#include ++#endif /* __KERNEL__ */ ++ ++#ifndef UNIXWARE_COMPAT ++/* Set non-zero for broken, compatible instructions. Set to zero for ++ non-broken opcodes. */ ++#define UNIXWARE_COMPAT 1 ++#endif ++ ++static int fetch_data (struct disassemble_info *, bfd_byte *); ++static void ckprefix (void); ++static const char *prefix_name (int, int); ++static int print_insn (bfd_vma, disassemble_info *); ++static void dofloat (int); ++static void OP_ST (int, int); ++static void OP_STi (int, int); ++static int putop (const char *, int); ++static void oappend (const char *); ++static void append_seg (void); ++static void OP_indirE (int, int); ++static void print_operand_value (char *, int, bfd_vma); ++static void OP_E (int, int); ++static void OP_G (int, int); ++static bfd_vma get64 (void); ++static bfd_signed_vma get32 (void); ++static bfd_signed_vma get32s (void); ++static int get16 (void); ++static void set_op (bfd_vma, int); ++static void OP_REG (int, int); ++static void OP_IMREG (int, int); ++static void OP_I (int, int); ++static void OP_I64 (int, int); ++static void OP_sI (int, int); ++static void OP_J (int, int); ++static void OP_SEG (int, int); ++static void OP_DIR (int, int); ++static void OP_OFF (int, int); ++static void OP_OFF64 (int, int); ++static void ptr_reg (int, int); ++static void OP_ESreg (int, int); ++static void OP_DSreg (int, int); ++static void OP_C (int, int); ++static void OP_D (int, int); ++static void OP_T (int, int); ++static void OP_Rd (int, int); ++static void OP_MMX (int, int); ++static void OP_XMM (int, int); ++static void OP_EM (int, int); ++static void OP_EX (int, int); ++static void OP_MS (int, int); ++static void OP_XS (int, int); ++static void OP_M (int, int); ++static void OP_VMX (int, int); ++static void OP_0fae (int, int); ++static void OP_0f07 (int, int); ++static void NOP_Fixup (int, int); ++static void OP_3DNowSuffix (int, int); ++static void OP_SIMD_Suffix (int, int); ++static void SIMD_Fixup (int, int); ++static void PNI_Fixup (int, int); ++static void SVME_Fixup (int, int); ++static void INVLPG_Fixup (int, int); ++static void BadOp (void); ++static void SEG_Fixup (int, int); ++static void VMX_Fixup (int, int); ++ ++struct dis_private { ++ /* Points to first byte not fetched. */ ++ bfd_byte *max_fetched; ++ bfd_byte the_buffer[MAXLEN]; ++ bfd_vma insn_start; ++ int orig_sizeflag; ++#ifndef __KERNEL__ ++ jmp_buf bailout; ++#endif /* __KERNEL__ */ ++}; ++ ++/* The opcode for the fwait instruction, which we treat as a prefix ++ when we can. */ ++#define FWAIT_OPCODE (0x9b) ++ ++/* Set to 1 for 64bit mode disassembly. */ ++static int mode_64bit; ++ ++/* Flags for the prefixes for the current instruction. See below. */ ++static int prefixes; ++ ++/* REX prefix the current instruction. See below. */ ++static int rex; ++/* Bits of REX we've already used. */ ++static int rex_used; ++#define REX_MODE64 8 ++#define REX_EXTX 4 ++#define REX_EXTY 2 ++#define REX_EXTZ 1 ++/* Mark parts used in the REX prefix. When we are testing for ++ empty prefix (for 8bit register REX extension), just mask it ++ out. Otherwise test for REX bit is excuse for existence of REX ++ only in case value is nonzero. */ ++#define USED_REX(value) \ ++ { \ ++ if (value) \ ++ rex_used |= (rex & value) ? (value) | 0x40 : 0; \ ++ else \ ++ rex_used |= 0x40; \ ++ } ++ ++/* Flags for prefixes which we somehow handled when printing the ++ current instruction. */ ++static int used_prefixes; ++ ++/* Flags stored in PREFIXES. */ ++#define PREFIX_REPZ 1 ++#define PREFIX_REPNZ 2 ++#define PREFIX_LOCK 4 ++#define PREFIX_CS 8 ++#define PREFIX_SS 0x10 ++#define PREFIX_DS 0x20 ++#define PREFIX_ES 0x40 ++#define PREFIX_FS 0x80 ++#define PREFIX_GS 0x100 ++#define PREFIX_DATA 0x200 ++#define PREFIX_ADDR 0x400 ++#define PREFIX_FWAIT 0x800 ++ ++/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) ++ to ADDR (exclusive) are valid. Returns 1 for success, longjmps ++ on error. */ ++#define FETCH_DATA(info, addr) \ ++ ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ ++ ? 1 : fetch_data ((info), (addr))) ++ ++static int ++fetch_data (struct disassemble_info *info, bfd_byte *addr) ++{ ++ int status; ++ struct dis_private *priv = (struct dis_private *) info->private_data; ++ bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); ++ ++ status = (*info->read_memory_func) (start, ++ priv->max_fetched, ++ addr - priv->max_fetched, ++ info); ++ if (status != 0) ++ { ++ /* If we did manage to read at least one byte, then ++ print_insn_i386 will do something sensible. Otherwise, print ++ an error. We do that here because this is where we know ++ STATUS. */ ++ if (priv->max_fetched == priv->the_buffer) ++ (*info->memory_error_func) (status, start, info); ++#ifndef __KERNEL__ ++ longjmp (priv->bailout, 1); ++#else /* __KERNEL__ */ ++ /* XXX - what to do? */ ++ kdb_printf("Hmm. longjmp.\n"); ++#endif /* __KERNEL__ */ ++ } ++ else ++ priv->max_fetched = addr; ++ return 1; ++} ++ ++#define XX NULL, 0 ++ ++#define Eb OP_E, b_mode ++#define Ev OP_E, v_mode ++#define Ed OP_E, d_mode ++#define Eq OP_E, q_mode ++#define Edq OP_E, dq_mode ++#define Edqw OP_E, dqw_mode ++#define indirEv OP_indirE, branch_v_mode ++#define indirEp OP_indirE, f_mode ++#define Em OP_E, m_mode ++#define Ew OP_E, w_mode ++#define Ma OP_E, v_mode ++#define M OP_M, 0 /* lea, lgdt, etc. */ ++#define Mp OP_M, f_mode /* 32 or 48 bit memory operand for LDS, LES etc */ ++#define Gb OP_G, b_mode ++#define Gv OP_G, v_mode ++#define Gd OP_G, d_mode ++#define Gdq OP_G, dq_mode ++#define Gm OP_G, m_mode ++#define Gw OP_G, w_mode ++#define Rd OP_Rd, d_mode ++#define Rm OP_Rd, m_mode ++#define Ib OP_I, b_mode ++#define sIb OP_sI, b_mode /* sign extened byte */ ++#define Iv OP_I, v_mode ++#define Iq OP_I, q_mode ++#define Iv64 OP_I64, v_mode ++#define Iw OP_I, w_mode ++#define I1 OP_I, const_1_mode ++#define Jb OP_J, b_mode ++#define Jv OP_J, v_mode ++#define Cm OP_C, m_mode ++#define Dm OP_D, m_mode ++#define Td OP_T, d_mode ++#define Sv SEG_Fixup, v_mode ++ ++#define RMeAX OP_REG, eAX_reg ++#define RMeBX OP_REG, eBX_reg ++#define RMeCX OP_REG, eCX_reg ++#define RMeDX OP_REG, eDX_reg ++#define RMeSP OP_REG, eSP_reg ++#define RMeBP OP_REG, eBP_reg ++#define RMeSI OP_REG, eSI_reg ++#define RMeDI OP_REG, eDI_reg ++#define RMrAX OP_REG, rAX_reg ++#define RMrBX OP_REG, rBX_reg ++#define RMrCX OP_REG, rCX_reg ++#define RMrDX OP_REG, rDX_reg ++#define RMrSP OP_REG, rSP_reg ++#define RMrBP OP_REG, rBP_reg ++#define RMrSI OP_REG, rSI_reg ++#define RMrDI OP_REG, rDI_reg ++#define RMAL OP_REG, al_reg ++#define RMAL OP_REG, al_reg ++#define RMCL OP_REG, cl_reg ++#define RMDL OP_REG, dl_reg ++#define RMBL OP_REG, bl_reg ++#define RMAH OP_REG, ah_reg ++#define RMCH OP_REG, ch_reg ++#define RMDH OP_REG, dh_reg ++#define RMBH OP_REG, bh_reg ++#define RMAX OP_REG, ax_reg ++#define RMDX OP_REG, dx_reg ++ ++#define eAX OP_IMREG, eAX_reg ++#define eBX OP_IMREG, eBX_reg ++#define eCX OP_IMREG, eCX_reg ++#define eDX OP_IMREG, eDX_reg ++#define eSP OP_IMREG, eSP_reg ++#define eBP OP_IMREG, eBP_reg ++#define eSI OP_IMREG, eSI_reg ++#define eDI OP_IMREG, eDI_reg ++#define AL OP_IMREG, al_reg ++#define AL OP_IMREG, al_reg ++#define CL OP_IMREG, cl_reg ++#define DL OP_IMREG, dl_reg ++#define BL OP_IMREG, bl_reg ++#define AH OP_IMREG, ah_reg ++#define CH OP_IMREG, ch_reg ++#define DH OP_IMREG, dh_reg ++#define BH OP_IMREG, bh_reg ++#define AX OP_IMREG, ax_reg ++#define DX OP_IMREG, dx_reg ++#define indirDX OP_IMREG, indir_dx_reg ++ ++#define Sw OP_SEG, w_mode ++#define Ap OP_DIR, 0 ++#define Ob OP_OFF, b_mode ++#define Ob64 OP_OFF64, b_mode ++#define Ov OP_OFF, v_mode ++#define Ov64 OP_OFF64, v_mode ++#define Xb OP_DSreg, eSI_reg ++#define Xv OP_DSreg, eSI_reg ++#define Yb OP_ESreg, eDI_reg ++#define Yv OP_ESreg, eDI_reg ++#define DSBX OP_DSreg, eBX_reg ++ ++#define es OP_REG, es_reg ++#define ss OP_REG, ss_reg ++#define cs OP_REG, cs_reg ++#define ds OP_REG, ds_reg ++#define fs OP_REG, fs_reg ++#define gs OP_REG, gs_reg ++ ++#define MX OP_MMX, 0 ++#define XM OP_XMM, 0 ++#define EM OP_EM, v_mode ++#define EX OP_EX, v_mode ++#define MS OP_MS, v_mode ++#define XS OP_XS, v_mode ++#define VM OP_VMX, q_mode ++#define OPSUF OP_3DNowSuffix, 0 ++#define OPSIMD OP_SIMD_Suffix, 0 ++ ++#define cond_jump_flag NULL, cond_jump_mode ++#define loop_jcxz_flag NULL, loop_jcxz_mode ++ ++/* bits in sizeflag */ ++#define SUFFIX_ALWAYS 4 ++#define AFLAG 2 ++#define DFLAG 1 ++ ++#define b_mode 1 /* byte operand */ ++#define v_mode 2 /* operand size depends on prefixes */ ++#define w_mode 3 /* word operand */ ++#define d_mode 4 /* double word operand */ ++#define q_mode 5 /* quad word operand */ ++#define t_mode 6 /* ten-byte operand */ ++#define x_mode 7 /* 16-byte XMM operand */ ++#define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ ++#define cond_jump_mode 9 ++#define loop_jcxz_mode 10 ++#define dq_mode 11 /* operand size depends on REX prefixes. */ ++#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ ++#define f_mode 13 /* 4- or 6-byte pointer operand */ ++#define const_1_mode 14 ++#define branch_v_mode 15 /* v_mode for branch. */ ++ ++#define es_reg 100 ++#define cs_reg 101 ++#define ss_reg 102 ++#define ds_reg 103 ++#define fs_reg 104 ++#define gs_reg 105 ++ ++#define eAX_reg 108 ++#define eCX_reg 109 ++#define eDX_reg 110 ++#define eBX_reg 111 ++#define eSP_reg 112 ++#define eBP_reg 113 ++#define eSI_reg 114 ++#define eDI_reg 115 ++ ++#define al_reg 116 ++#define cl_reg 117 ++#define dl_reg 118 ++#define bl_reg 119 ++#define ah_reg 120 ++#define ch_reg 121 ++#define dh_reg 122 ++#define bh_reg 123 ++ ++#define ax_reg 124 ++#define cx_reg 125 ++#define dx_reg 126 ++#define bx_reg 127 ++#define sp_reg 128 ++#define bp_reg 129 ++#define si_reg 130 ++#define di_reg 131 ++ ++#define rAX_reg 132 ++#define rCX_reg 133 ++#define rDX_reg 134 ++#define rBX_reg 135 ++#define rSP_reg 136 ++#define rBP_reg 137 ++#define rSI_reg 138 ++#define rDI_reg 139 ++ ++#define indir_dx_reg 150 ++ ++#define FLOATCODE 1 ++#define USE_GROUPS 2 ++#define USE_PREFIX_USER_TABLE 3 ++#define X86_64_SPECIAL 4 ++ ++#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 ++ ++#define GRP1b NULL, NULL, USE_GROUPS, NULL, 0, NULL, 0 ++#define GRP1S NULL, NULL, USE_GROUPS, NULL, 1, NULL, 0 ++#define GRP1Ss NULL, NULL, USE_GROUPS, NULL, 2, NULL, 0 ++#define GRP2b NULL, NULL, USE_GROUPS, NULL, 3, NULL, 0 ++#define GRP2S NULL, NULL, USE_GROUPS, NULL, 4, NULL, 0 ++#define GRP2b_one NULL, NULL, USE_GROUPS, NULL, 5, NULL, 0 ++#define GRP2S_one NULL, NULL, USE_GROUPS, NULL, 6, NULL, 0 ++#define GRP2b_cl NULL, NULL, USE_GROUPS, NULL, 7, NULL, 0 ++#define GRP2S_cl NULL, NULL, USE_GROUPS, NULL, 8, NULL, 0 ++#define GRP3b NULL, NULL, USE_GROUPS, NULL, 9, NULL, 0 ++#define GRP3S NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0 ++#define GRP4 NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0 ++#define GRP5 NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0 ++#define GRP6 NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0 ++#define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0 ++#define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0 ++#define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0 ++#define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0 ++#define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0 ++#define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0 ++#define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0 ++#define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0 ++#define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0 ++#define GRPPADLCK1 NULL, NULL, USE_GROUPS, NULL, 23, NULL, 0 ++#define GRPPADLCK2 NULL, NULL, USE_GROUPS, NULL, 24, NULL, 0 ++ ++#define PREGRP0 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 0, NULL, 0 ++#define PREGRP1 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 1, NULL, 0 ++#define PREGRP2 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 2, NULL, 0 ++#define PREGRP3 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 3, NULL, 0 ++#define PREGRP4 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 4, NULL, 0 ++#define PREGRP5 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 5, NULL, 0 ++#define PREGRP6 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 6, NULL, 0 ++#define PREGRP7 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 7, NULL, 0 ++#define PREGRP8 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 8, NULL, 0 ++#define PREGRP9 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 9, NULL, 0 ++#define PREGRP10 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0 ++#define PREGRP11 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0 ++#define PREGRP12 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0 ++#define PREGRP13 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0 ++#define PREGRP14 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0 ++#define PREGRP15 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0 ++#define PREGRP16 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0 ++#define PREGRP17 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0 ++#define PREGRP18 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0 ++#define PREGRP19 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0 ++#define PREGRP20 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0 ++#define PREGRP21 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0 ++#define PREGRP22 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0 ++#define PREGRP23 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0 ++#define PREGRP24 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0 ++#define PREGRP25 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0 ++#define PREGRP26 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0 ++#define PREGRP27 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 27, NULL, 0 ++#define PREGRP28 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 28, NULL, 0 ++#define PREGRP29 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 29, NULL, 0 ++#define PREGRP30 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 30, NULL, 0 ++#define PREGRP31 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 31, NULL, 0 ++#define PREGRP32 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 32, NULL, 0 ++ ++#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0 ++ ++typedef void (*op_rtn) (int bytemode, int sizeflag); ++ ++struct dis386 { ++ const char *name; ++ op_rtn op1; ++ int bytemode1; ++ op_rtn op2; ++ int bytemode2; ++ op_rtn op3; ++ int bytemode3; ++}; ++ ++/* Upper case letters in the instruction names here are macros. ++ 'A' => print 'b' if no register operands or suffix_always is true ++ 'B' => print 'b' if suffix_always is true ++ 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand ++ . size prefix ++ 'E' => print 'e' if 32-bit form of jcxz ++ 'F' => print 'w' or 'l' depending on address size prefix (loop insns) ++ 'H' => print ",pt" or ",pn" branch hint ++ 'I' => honor following macro letter even in Intel mode (implemented only ++ . for some of the macro letters) ++ 'J' => print 'l' ++ 'L' => print 'l' if suffix_always is true ++ 'N' => print 'n' if instruction has no wait "prefix" ++ 'O' => print 'd', or 'o' ++ 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, ++ . or suffix_always is true. print 'q' if rex prefix is present. ++ 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always ++ . is true ++ 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) ++ 'S' => print 'w', 'l' or 'q' if suffix_always is true ++ 'T' => print 'q' in 64bit mode and behave as 'P' otherwise ++ 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise ++ 'W' => print 'b' or 'w' ("w" or "de" in intel mode) ++ 'X' => print 's', 'd' depending on data16 prefix (for XMM) ++ 'Y' => 'q' if instruction has an REX 64bit overwrite prefix ++ ++ Many of the above letters print nothing in Intel mode. See "putop" ++ for the details. ++ ++ Braces '{' and '}', and vertical bars '|', indicate alternative ++ mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel ++ modes. In cases where there are only two alternatives, the X86_64 ++ instruction is reserved, and "(bad)" is printed. ++*/ ++ ++static const struct dis386 dis386[] = { ++ /* 00 */ ++ { "addB", Eb, Gb, XX }, ++ { "addS", Ev, Gv, XX }, ++ { "addB", Gb, Eb, XX }, ++ { "addS", Gv, Ev, XX }, ++ { "addB", AL, Ib, XX }, ++ { "addS", eAX, Iv, XX }, ++ { "push{T|}", es, XX, XX }, ++ { "pop{T|}", es, XX, XX }, ++ /* 08 */ ++ { "orB", Eb, Gb, XX }, ++ { "orS", Ev, Gv, XX }, ++ { "orB", Gb, Eb, XX }, ++ { "orS", Gv, Ev, XX }, ++ { "orB", AL, Ib, XX }, ++ { "orS", eAX, Iv, XX }, ++ { "push{T|}", cs, XX, XX }, ++ { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ ++ /* 10 */ ++ { "adcB", Eb, Gb, XX }, ++ { "adcS", Ev, Gv, XX }, ++ { "adcB", Gb, Eb, XX }, ++ { "adcS", Gv, Ev, XX }, ++ { "adcB", AL, Ib, XX }, ++ { "adcS", eAX, Iv, XX }, ++ { "push{T|}", ss, XX, XX }, ++ { "popT|}", ss, XX, XX }, ++ /* 18 */ ++ { "sbbB", Eb, Gb, XX }, ++ { "sbbS", Ev, Gv, XX }, ++ { "sbbB", Gb, Eb, XX }, ++ { "sbbS", Gv, Ev, XX }, ++ { "sbbB", AL, Ib, XX }, ++ { "sbbS", eAX, Iv, XX }, ++ { "push{T|}", ds, XX, XX }, ++ { "pop{T|}", ds, XX, XX }, ++ /* 20 */ ++ { "andB", Eb, Gb, XX }, ++ { "andS", Ev, Gv, XX }, ++ { "andB", Gb, Eb, XX }, ++ { "andS", Gv, Ev, XX }, ++ { "andB", AL, Ib, XX }, ++ { "andS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG ES prefix */ ++ { "daa{|}", XX, XX, XX }, ++ /* 28 */ ++ { "subB", Eb, Gb, XX }, ++ { "subS", Ev, Gv, XX }, ++ { "subB", Gb, Eb, XX }, ++ { "subS", Gv, Ev, XX }, ++ { "subB", AL, Ib, XX }, ++ { "subS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG CS prefix */ ++ { "das{|}", XX, XX, XX }, ++ /* 30 */ ++ { "xorB", Eb, Gb, XX }, ++ { "xorS", Ev, Gv, XX }, ++ { "xorB", Gb, Eb, XX }, ++ { "xorS", Gv, Ev, XX }, ++ { "xorB", AL, Ib, XX }, ++ { "xorS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG SS prefix */ ++ { "aaa{|}", XX, XX, XX }, ++ /* 38 */ ++ { "cmpB", Eb, Gb, XX }, ++ { "cmpS", Ev, Gv, XX }, ++ { "cmpB", Gb, Eb, XX }, ++ { "cmpS", Gv, Ev, XX }, ++ { "cmpB", AL, Ib, XX }, ++ { "cmpS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG DS prefix */ ++ { "aas{|}", XX, XX, XX }, ++ /* 40 */ ++ { "inc{S|}", RMeAX, XX, XX }, ++ { "inc{S|}", RMeCX, XX, XX }, ++ { "inc{S|}", RMeDX, XX, XX }, ++ { "inc{S|}", RMeBX, XX, XX }, ++ { "inc{S|}", RMeSP, XX, XX }, ++ { "inc{S|}", RMeBP, XX, XX }, ++ { "inc{S|}", RMeSI, XX, XX }, ++ { "inc{S|}", RMeDI, XX, XX }, ++ /* 48 */ ++ { "dec{S|}", RMeAX, XX, XX }, ++ { "dec{S|}", RMeCX, XX, XX }, ++ { "dec{S|}", RMeDX, XX, XX }, ++ { "dec{S|}", RMeBX, XX, XX }, ++ { "dec{S|}", RMeSP, XX, XX }, ++ { "dec{S|}", RMeBP, XX, XX }, ++ { "dec{S|}", RMeSI, XX, XX }, ++ { "dec{S|}", RMeDI, XX, XX }, ++ /* 50 */ ++ { "pushS", RMrAX, XX, XX }, ++ { "pushS", RMrCX, XX, XX }, ++ { "pushS", RMrDX, XX, XX }, ++ { "pushS", RMrBX, XX, XX }, ++ { "pushS", RMrSP, XX, XX }, ++ { "pushS", RMrBP, XX, XX }, ++ { "pushS", RMrSI, XX, XX }, ++ { "pushS", RMrDI, XX, XX }, ++ /* 58 */ ++ { "popS", RMrAX, XX, XX }, ++ { "popS", RMrCX, XX, XX }, ++ { "popS", RMrDX, XX, XX }, ++ { "popS", RMrBX, XX, XX }, ++ { "popS", RMrSP, XX, XX }, ++ { "popS", RMrBP, XX, XX }, ++ { "popS", RMrSI, XX, XX }, ++ { "popS", RMrDI, XX, XX }, ++ /* 60 */ ++ { "pusha{P|}", XX, XX, XX }, ++ { "popa{P|}", XX, XX, XX }, ++ { "bound{S|}", Gv, Ma, XX }, ++ { X86_64_0 }, ++ { "(bad)", XX, XX, XX }, /* seg fs */ ++ { "(bad)", XX, XX, XX }, /* seg gs */ ++ { "(bad)", XX, XX, XX }, /* op size prefix */ ++ { "(bad)", XX, XX, XX }, /* adr size prefix */ ++ /* 68 */ ++ { "pushT", Iq, XX, XX }, ++ { "imulS", Gv, Ev, Iv }, ++ { "pushT", sIb, XX, XX }, ++ { "imulS", Gv, Ev, sIb }, ++ { "ins{b||b|}", Yb, indirDX, XX }, ++ { "ins{R||R|}", Yv, indirDX, XX }, ++ { "outs{b||b|}", indirDX, Xb, XX }, ++ { "outs{R||R|}", indirDX, Xv, XX }, ++ /* 70 */ ++ { "joH", Jb, XX, cond_jump_flag }, ++ { "jnoH", Jb, XX, cond_jump_flag }, ++ { "jbH", Jb, XX, cond_jump_flag }, ++ { "jaeH", Jb, XX, cond_jump_flag }, ++ { "jeH", Jb, XX, cond_jump_flag }, ++ { "jneH", Jb, XX, cond_jump_flag }, ++ { "jbeH", Jb, XX, cond_jump_flag }, ++ { "jaH", Jb, XX, cond_jump_flag }, ++ /* 78 */ ++ { "jsH", Jb, XX, cond_jump_flag }, ++ { "jnsH", Jb, XX, cond_jump_flag }, ++ { "jpH", Jb, XX, cond_jump_flag }, ++ { "jnpH", Jb, XX, cond_jump_flag }, ++ { "jlH", Jb, XX, cond_jump_flag }, ++ { "jgeH", Jb, XX, cond_jump_flag }, ++ { "jleH", Jb, XX, cond_jump_flag }, ++ { "jgH", Jb, XX, cond_jump_flag }, ++ /* 80 */ ++ { GRP1b }, ++ { GRP1S }, ++ { "(bad)", XX, XX, XX }, ++ { GRP1Ss }, ++ { "testB", Eb, Gb, XX }, ++ { "testS", Ev, Gv, XX }, ++ { "xchgB", Eb, Gb, XX }, ++ { "xchgS", Ev, Gv, XX }, ++ /* 88 */ ++ { "movB", Eb, Gb, XX }, ++ { "movS", Ev, Gv, XX }, ++ { "movB", Gb, Eb, XX }, ++ { "movS", Gv, Ev, XX }, ++ { "movQ", Sv, Sw, XX }, ++ { "leaS", Gv, M, XX }, ++ { "movQ", Sw, Sv, XX }, ++ { "popU", Ev, XX, XX }, ++ /* 90 */ ++ { "nop", NOP_Fixup, 0, XX, XX }, ++ { "xchgS", RMeCX, eAX, XX }, ++ { "xchgS", RMeDX, eAX, XX }, ++ { "xchgS", RMeBX, eAX, XX }, ++ { "xchgS", RMeSP, eAX, XX }, ++ { "xchgS", RMeBP, eAX, XX }, ++ { "xchgS", RMeSI, eAX, XX }, ++ { "xchgS", RMeDI, eAX, XX }, ++ /* 98 */ ++ { "cW{tR||tR|}", XX, XX, XX }, ++ { "cR{tO||tO|}", XX, XX, XX }, ++ { "Jcall{T|}", Ap, XX, XX }, ++ { "(bad)", XX, XX, XX }, /* fwait */ ++ { "pushfT", XX, XX, XX }, ++ { "popfT", XX, XX, XX }, ++ { "sahf{|}", XX, XX, XX }, ++ { "lahf{|}", XX, XX, XX }, ++ /* a0 */ ++ { "movB", AL, Ob64, XX }, ++ { "movS", eAX, Ov64, XX }, ++ { "movB", Ob64, AL, XX }, ++ { "movS", Ov64, eAX, XX }, ++ { "movs{b||b|}", Yb, Xb, XX }, ++ { "movs{R||R|}", Yv, Xv, XX }, ++ { "cmps{b||b|}", Xb, Yb, XX }, ++ { "cmps{R||R|}", Xv, Yv, XX }, ++ /* a8 */ ++ { "testB", AL, Ib, XX }, ++ { "testS", eAX, Iv, XX }, ++ { "stosB", Yb, AL, XX }, ++ { "stosS", Yv, eAX, XX }, ++ { "lodsB", AL, Xb, XX }, ++ { "lodsS", eAX, Xv, XX }, ++ { "scasB", AL, Yb, XX }, ++ { "scasS", eAX, Yv, XX }, ++ /* b0 */ ++ { "movB", RMAL, Ib, XX }, ++ { "movB", RMCL, Ib, XX }, ++ { "movB", RMDL, Ib, XX }, ++ { "movB", RMBL, Ib, XX }, ++ { "movB", RMAH, Ib, XX }, ++ { "movB", RMCH, Ib, XX }, ++ { "movB", RMDH, Ib, XX }, ++ { "movB", RMBH, Ib, XX }, ++ /* b8 */ ++ { "movS", RMeAX, Iv64, XX }, ++ { "movS", RMeCX, Iv64, XX }, ++ { "movS", RMeDX, Iv64, XX }, ++ { "movS", RMeBX, Iv64, XX }, ++ { "movS", RMeSP, Iv64, XX }, ++ { "movS", RMeBP, Iv64, XX }, ++ { "movS", RMeSI, Iv64, XX }, ++ { "movS", RMeDI, Iv64, XX }, ++ /* c0 */ ++ { GRP2b }, ++ { GRP2S }, ++ { "retT", Iw, XX, XX }, ++ { "retT", XX, XX, XX }, ++ { "les{S|}", Gv, Mp, XX }, ++ { "ldsS", Gv, Mp, XX }, ++ { "movA", Eb, Ib, XX }, ++ { "movQ", Ev, Iv, XX }, ++ /* c8 */ ++ { "enterT", Iw, Ib, XX }, ++ { "leaveT", XX, XX, XX }, ++ { "lretP", Iw, XX, XX }, ++ { "lretP", XX, XX, XX }, ++ { "int3", XX, XX, XX }, ++ { "int", Ib, XX, XX }, ++ { "into{|}", XX, XX, XX }, ++ { "iretP", XX, XX, XX }, ++ /* d0 */ ++ { GRP2b_one }, ++ { GRP2S_one }, ++ { GRP2b_cl }, ++ { GRP2S_cl }, ++ { "aam{|}", sIb, XX, XX }, ++ { "aad{|}", sIb, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "xlat", DSBX, XX, XX }, ++ /* d8 */ ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ /* e0 */ ++ { "loopneFH", Jb, XX, loop_jcxz_flag }, ++ { "loopeFH", Jb, XX, loop_jcxz_flag }, ++ { "loopFH", Jb, XX, loop_jcxz_flag }, ++ { "jEcxzH", Jb, XX, loop_jcxz_flag }, ++ { "inB", AL, Ib, XX }, ++ { "inS", eAX, Ib, XX }, ++ { "outB", Ib, AL, XX }, ++ { "outS", Ib, eAX, XX }, ++ /* e8 */ ++ { "callT", Jv, XX, XX }, ++ { "jmpT", Jv, XX, XX }, ++ { "Jjmp{T|}", Ap, XX, XX }, ++ { "jmp", Jb, XX, XX }, ++ { "inB", AL, indirDX, XX }, ++ { "inS", eAX, indirDX, XX }, ++ { "outB", indirDX, AL, XX }, ++ { "outS", indirDX, eAX, XX }, ++ /* f0 */ ++ { "(bad)", XX, XX, XX }, /* lock prefix */ ++ { "icebp", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, /* repne */ ++ { "(bad)", XX, XX, XX }, /* repz */ ++ { "hlt", XX, XX, XX }, ++ { "cmc", XX, XX, XX }, ++ { GRP3b }, ++ { GRP3S }, ++ /* f8 */ ++ { "clc", XX, XX, XX }, ++ { "stc", XX, XX, XX }, ++ { "cli", XX, XX, XX }, ++ { "sti", XX, XX, XX }, ++ { "cld", XX, XX, XX }, ++ { "std", XX, XX, XX }, ++ { GRP4 }, ++ { GRP5 }, ++}; ++ ++static const struct dis386 dis386_twobyte[] = { ++ /* 00 */ ++ { GRP6 }, ++ { GRP7 }, ++ { "larS", Gv, Ew, XX }, ++ { "lslS", Gv, Ew, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "syscall", XX, XX, XX }, ++ { "clts", XX, XX, XX }, ++ { "sysretP", XX, XX, XX }, ++ /* 08 */ ++ { "invd", XX, XX, XX }, ++ { "wbinvd", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "ud2a", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { GRPAMD }, ++ { "femms", XX, XX, XX }, ++ { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix. */ ++ /* 10 */ ++ { PREGRP8 }, ++ { PREGRP9 }, ++ { PREGRP30 }, ++ { "movlpX", EX, XM, SIMD_Fixup, 'h' }, ++ { "unpcklpX", XM, EX, XX }, ++ { "unpckhpX", XM, EX, XX }, ++ { PREGRP31 }, ++ { "movhpX", EX, XM, SIMD_Fixup, 'l' }, ++ /* 18 */ ++ { GRP14 }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 20 */ ++ { "movL", Rm, Cm, XX }, ++ { "movL", Rm, Dm, XX }, ++ { "movL", Cm, Rm, XX }, ++ { "movL", Dm, Rm, XX }, ++ { "movL", Rd, Td, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "movL", Td, Rd, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 28 */ ++ { "movapX", XM, EX, XX }, ++ { "movapX", EX, XM, XX }, ++ { PREGRP2 }, ++ { "movntpX", Ev, XM, XX }, ++ { PREGRP4 }, ++ { PREGRP3 }, ++ { "ucomisX", XM,EX, XX }, ++ { "comisX", XM,EX, XX }, ++ /* 30 */ ++ { "wrmsr", XX, XX, XX }, ++ { "rdtsc", XX, XX, XX }, ++ { "rdmsr", XX, XX, XX }, ++ { "rdpmc", XX, XX, XX }, ++ { "sysenter", XX, XX, XX }, ++ { "sysexit", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 38 */ ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 40 */ ++ { "cmovo", Gv, Ev, XX }, ++ { "cmovno", Gv, Ev, XX }, ++ { "cmovb", Gv, Ev, XX }, ++ { "cmovae", Gv, Ev, XX }, ++ { "cmove", Gv, Ev, XX }, ++ { "cmovne", Gv, Ev, XX }, ++ { "cmovbe", Gv, Ev, XX }, ++ { "cmova", Gv, Ev, XX }, ++ /* 48 */ ++ { "cmovs", Gv, Ev, XX }, ++ { "cmovns", Gv, Ev, XX }, ++ { "cmovp", Gv, Ev, XX }, ++ { "cmovnp", Gv, Ev, XX }, ++ { "cmovl", Gv, Ev, XX }, ++ { "cmovge", Gv, Ev, XX }, ++ { "cmovle", Gv, Ev, XX }, ++ { "cmovg", Gv, Ev, XX }, ++ /* 50 */ ++ { "movmskpX", Gdq, XS, XX }, ++ { PREGRP13 }, ++ { PREGRP12 }, ++ { PREGRP11 }, ++ { "andpX", XM, EX, XX }, ++ { "andnpX", XM, EX, XX }, ++ { "orpX", XM, EX, XX }, ++ { "xorpX", XM, EX, XX }, ++ /* 58 */ ++ { PREGRP0 }, ++ { PREGRP10 }, ++ { PREGRP17 }, ++ { PREGRP16 }, ++ { PREGRP14 }, ++ { PREGRP7 }, ++ { PREGRP5 }, ++ { PREGRP6 }, ++ /* 60 */ ++ { "punpcklbw", MX, EM, XX }, ++ { "punpcklwd", MX, EM, XX }, ++ { "punpckldq", MX, EM, XX }, ++ { "packsswb", MX, EM, XX }, ++ { "pcmpgtb", MX, EM, XX }, ++ { "pcmpgtw", MX, EM, XX }, ++ { "pcmpgtd", MX, EM, XX }, ++ { "packuswb", MX, EM, XX }, ++ /* 68 */ ++ { "punpckhbw", MX, EM, XX }, ++ { "punpckhwd", MX, EM, XX }, ++ { "punpckhdq", MX, EM, XX }, ++ { "packssdw", MX, EM, XX }, ++ { PREGRP26 }, ++ { PREGRP24 }, ++ { "movd", MX, Edq, XX }, ++ { PREGRP19 }, ++ /* 70 */ ++ { PREGRP22 }, ++ { GRP10 }, ++ { GRP11 }, ++ { GRP12 }, ++ { "pcmpeqb", MX, EM, XX }, ++ { "pcmpeqw", MX, EM, XX }, ++ { "pcmpeqd", MX, EM, XX }, ++ { "emms", XX, XX, XX }, ++ /* 78 */ ++ { "vmread", Em, Gm, XX }, ++ { "vmwrite", Gm, Em, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { PREGRP28 }, ++ { PREGRP29 }, ++ { PREGRP23 }, ++ { PREGRP20 }, ++ /* 80 */ ++ { "joH", Jv, XX, cond_jump_flag }, ++ { "jnoH", Jv, XX, cond_jump_flag }, ++ { "jbH", Jv, XX, cond_jump_flag }, ++ { "jaeH", Jv, XX, cond_jump_flag }, ++ { "jeH", Jv, XX, cond_jump_flag }, ++ { "jneH", Jv, XX, cond_jump_flag }, ++ { "jbeH", Jv, XX, cond_jump_flag }, ++ { "jaH", Jv, XX, cond_jump_flag }, ++ /* 88 */ ++ { "jsH", Jv, XX, cond_jump_flag }, ++ { "jnsH", Jv, XX, cond_jump_flag }, ++ { "jpH", Jv, XX, cond_jump_flag }, ++ { "jnpH", Jv, XX, cond_jump_flag }, ++ { "jlH", Jv, XX, cond_jump_flag }, ++ { "jgeH", Jv, XX, cond_jump_flag }, ++ { "jleH", Jv, XX, cond_jump_flag }, ++ { "jgH", Jv, XX, cond_jump_flag }, ++ /* 90 */ ++ { "seto", Eb, XX, XX }, ++ { "setno", Eb, XX, XX }, ++ { "setb", Eb, XX, XX }, ++ { "setae", Eb, XX, XX }, ++ { "sete", Eb, XX, XX }, ++ { "setne", Eb, XX, XX }, ++ { "setbe", Eb, XX, XX }, ++ { "seta", Eb, XX, XX }, ++ /* 98 */ ++ { "sets", Eb, XX, XX }, ++ { "setns", Eb, XX, XX }, ++ { "setp", Eb, XX, XX }, ++ { "setnp", Eb, XX, XX }, ++ { "setl", Eb, XX, XX }, ++ { "setge", Eb, XX, XX }, ++ { "setle", Eb, XX, XX }, ++ { "setg", Eb, XX, XX }, ++ /* a0 */ ++ { "pushT", fs, XX, XX }, ++ { "popT", fs, XX, XX }, ++ { "cpuid", XX, XX, XX }, ++ { "btS", Ev, Gv, XX }, ++ { "shldS", Ev, Gv, Ib }, ++ { "shldS", Ev, Gv, CL }, ++ { GRPPADLCK2 }, ++ { GRPPADLCK1 }, ++ /* a8 */ ++ { "pushT", gs, XX, XX }, ++ { "popT", gs, XX, XX }, ++ { "rsm", XX, XX, XX }, ++ { "btsS", Ev, Gv, XX }, ++ { "shrdS", Ev, Gv, Ib }, ++ { "shrdS", Ev, Gv, CL }, ++ { GRP13 }, ++ { "imulS", Gv, Ev, XX }, ++ /* b0 */ ++ { "cmpxchgB", Eb, Gb, XX }, ++ { "cmpxchgS", Ev, Gv, XX }, ++ { "lssS", Gv, Mp, XX }, ++ { "btrS", Ev, Gv, XX }, ++ { "lfsS", Gv, Mp, XX }, ++ { "lgsS", Gv, Mp, XX }, ++ { "movz{bR|x|bR|x}", Gv, Eb, XX }, ++ { "movz{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movzww ! */ ++ /* b8 */ ++ { "(bad)", XX, XX, XX }, ++ { "ud2b", XX, XX, XX }, ++ { GRP8 }, ++ { "btcS", Ev, Gv, XX }, ++ { "bsfS", Gv, Ev, XX }, ++ { "bsrS", Gv, Ev, XX }, ++ { "movs{bR|x|bR|x}", Gv, Eb, XX }, ++ { "movs{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movsww ! */ ++ /* c0 */ ++ { "xaddB", Eb, Gb, XX }, ++ { "xaddS", Ev, Gv, XX }, ++ { PREGRP1 }, ++ { "movntiS", Ev, Gv, XX }, ++ { "pinsrw", MX, Edqw, Ib }, ++ { "pextrw", Gdq, MS, Ib }, ++ { "shufpX", XM, EX, Ib }, ++ { GRP9 }, ++ /* c8 */ ++ { "bswap", RMeAX, XX, XX }, ++ { "bswap", RMeCX, XX, XX }, ++ { "bswap", RMeDX, XX, XX }, ++ { "bswap", RMeBX, XX, XX }, ++ { "bswap", RMeSP, XX, XX }, ++ { "bswap", RMeBP, XX, XX }, ++ { "bswap", RMeSI, XX, XX }, ++ { "bswap", RMeDI, XX, XX }, ++ /* d0 */ ++ { PREGRP27 }, ++ { "psrlw", MX, EM, XX }, ++ { "psrld", MX, EM, XX }, ++ { "psrlq", MX, EM, XX }, ++ { "paddq", MX, EM, XX }, ++ { "pmullw", MX, EM, XX }, ++ { PREGRP21 }, ++ { "pmovmskb", Gdq, MS, XX }, ++ /* d8 */ ++ { "psubusb", MX, EM, XX }, ++ { "psubusw", MX, EM, XX }, ++ { "pminub", MX, EM, XX }, ++ { "pand", MX, EM, XX }, ++ { "paddusb", MX, EM, XX }, ++ { "paddusw", MX, EM, XX }, ++ { "pmaxub", MX, EM, XX }, ++ { "pandn", MX, EM, XX }, ++ /* e0 */ ++ { "pavgb", MX, EM, XX }, ++ { "psraw", MX, EM, XX }, ++ { "psrad", MX, EM, XX }, ++ { "pavgw", MX, EM, XX }, ++ { "pmulhuw", MX, EM, XX }, ++ { "pmulhw", MX, EM, XX }, ++ { PREGRP15 }, ++ { PREGRP25 }, ++ /* e8 */ ++ { "psubsb", MX, EM, XX }, ++ { "psubsw", MX, EM, XX }, ++ { "pminsw", MX, EM, XX }, ++ { "por", MX, EM, XX }, ++ { "paddsb", MX, EM, XX }, ++ { "paddsw", MX, EM, XX }, ++ { "pmaxsw", MX, EM, XX }, ++ { "pxor", MX, EM, XX }, ++ /* f0 */ ++ { PREGRP32 }, ++ { "psllw", MX, EM, XX }, ++ { "pslld", MX, EM, XX }, ++ { "psllq", MX, EM, XX }, ++ { "pmuludq", MX, EM, XX }, ++ { "pmaddwd", MX, EM, XX }, ++ { "psadbw", MX, EM, XX }, ++ { PREGRP18 }, ++ /* f8 */ ++ { "psubb", MX, EM, XX }, ++ { "psubw", MX, EM, XX }, ++ { "psubd", MX, EM, XX }, ++ { "psubq", MX, EM, XX }, ++ { "paddb", MX, EM, XX }, ++ { "paddw", MX, EM, XX }, ++ { "paddd", MX, EM, XX }, ++ { "(bad)", XX, XX, XX } ++}; ++ ++static const unsigned char onebyte_has_modrm[256] = { ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++ /* ------------------------------- */ ++ /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ ++ /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ ++ /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ ++ /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ ++ /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ ++ /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ ++ /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ ++ /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ ++ /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ ++ /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ ++ /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ ++ /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ ++ /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ ++ /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ ++ /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ ++ /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ ++ /* ------------------------------- */ ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++}; ++ ++static const unsigned char twobyte_has_modrm[256] = { ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++ /* ------------------------------- */ ++ /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ ++ /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ ++ /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ ++ /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ ++ /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ ++ /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ ++ /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ ++ /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */ ++ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ ++ /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ ++ /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ ++ /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ ++ /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ ++ /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ ++ /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ ++ /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ ++ /* ------------------------------- */ ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++}; ++ ++static const unsigned char twobyte_uses_SSE_prefix[256] = { ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++ /* ------------------------------- */ ++ /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ ++ /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ ++ /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ ++ /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ ++ /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ ++ /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ ++ /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ ++ /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, /* 7f */ ++ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ ++ /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ ++ /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ ++ /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ ++ /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ ++ /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ ++ /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ ++ /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ ++ /* ------------------------------- */ ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++}; ++ ++static char obuf[100]; ++static char *obufp; ++static char scratchbuf[100]; ++static unsigned char *start_codep; ++static unsigned char *insn_codep; ++static unsigned char *codep; ++static disassemble_info *the_info; ++static int mod; ++static int rm; ++static int reg; ++static unsigned char need_modrm; ++ ++/* If we are accessing mod/rm/reg without need_modrm set, then the ++ values are stale. Hitting this abort likely indicates that you ++ need to update onebyte_has_modrm or twobyte_has_modrm. */ ++#define MODRM_CHECK if (!need_modrm) abort () ++ ++static const char **names64; ++static const char **names32; ++static const char **names16; ++static const char **names8; ++static const char **names8rex; ++static const char **names_seg; ++static const char **index16; ++ ++static const char *intel_names64[] = { ++ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", ++ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" ++}; ++static const char *intel_names32[] = { ++ "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", ++ "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" ++}; ++static const char *intel_names16[] = { ++ "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", ++ "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" ++}; ++static const char *intel_names8[] = { ++ "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", ++}; ++static const char *intel_names8rex[] = { ++ "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", ++ "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" ++}; ++static const char *intel_names_seg[] = { ++ "es", "cs", "ss", "ds", "fs", "gs", "?", "?", ++}; ++static const char *intel_index16[] = { ++ "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" ++}; ++ ++static const char *att_names64[] = { ++ "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", ++ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" ++}; ++static const char *att_names32[] = { ++ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", ++ "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" ++}; ++static const char *att_names16[] = { ++ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", ++ "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" ++}; ++static const char *att_names8[] = { ++ "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", ++}; ++static const char *att_names8rex[] = { ++ "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", ++ "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" ++}; ++static const char *att_names_seg[] = { ++ "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", ++}; ++static const char *att_index16[] = { ++ "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" ++}; ++ ++static const struct dis386 grps[][8] = { ++ /* GRP1b */ ++ { ++ { "addA", Eb, Ib, XX }, ++ { "orA", Eb, Ib, XX }, ++ { "adcA", Eb, Ib, XX }, ++ { "sbbA", Eb, Ib, XX }, ++ { "andA", Eb, Ib, XX }, ++ { "subA", Eb, Ib, XX }, ++ { "xorA", Eb, Ib, XX }, ++ { "cmpA", Eb, Ib, XX } ++ }, ++ /* GRP1S */ ++ { ++ { "addQ", Ev, Iv, XX }, ++ { "orQ", Ev, Iv, XX }, ++ { "adcQ", Ev, Iv, XX }, ++ { "sbbQ", Ev, Iv, XX }, ++ { "andQ", Ev, Iv, XX }, ++ { "subQ", Ev, Iv, XX }, ++ { "xorQ", Ev, Iv, XX }, ++ { "cmpQ", Ev, Iv, XX } ++ }, ++ /* GRP1Ss */ ++ { ++ { "addQ", Ev, sIb, XX }, ++ { "orQ", Ev, sIb, XX }, ++ { "adcQ", Ev, sIb, XX }, ++ { "sbbQ", Ev, sIb, XX }, ++ { "andQ", Ev, sIb, XX }, ++ { "subQ", Ev, sIb, XX }, ++ { "xorQ", Ev, sIb, XX }, ++ { "cmpQ", Ev, sIb, XX } ++ }, ++ /* GRP2b */ ++ { ++ { "rolA", Eb, Ib, XX }, ++ { "rorA", Eb, Ib, XX }, ++ { "rclA", Eb, Ib, XX }, ++ { "rcrA", Eb, Ib, XX }, ++ { "shlA", Eb, Ib, XX }, ++ { "shrA", Eb, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarA", Eb, Ib, XX }, ++ }, ++ /* GRP2S */ ++ { ++ { "rolQ", Ev, Ib, XX }, ++ { "rorQ", Ev, Ib, XX }, ++ { "rclQ", Ev, Ib, XX }, ++ { "rcrQ", Ev, Ib, XX }, ++ { "shlQ", Ev, Ib, XX }, ++ { "shrQ", Ev, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarQ", Ev, Ib, XX }, ++ }, ++ /* GRP2b_one */ ++ { ++ { "rolA", Eb, I1, XX }, ++ { "rorA", Eb, I1, XX }, ++ { "rclA", Eb, I1, XX }, ++ { "rcrA", Eb, I1, XX }, ++ { "shlA", Eb, I1, XX }, ++ { "shrA", Eb, I1, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarA", Eb, I1, XX }, ++ }, ++ /* GRP2S_one */ ++ { ++ { "rolQ", Ev, I1, XX }, ++ { "rorQ", Ev, I1, XX }, ++ { "rclQ", Ev, I1, XX }, ++ { "rcrQ", Ev, I1, XX }, ++ { "shlQ", Ev, I1, XX }, ++ { "shrQ", Ev, I1, XX }, ++ { "(bad)", XX, XX, XX}, ++ { "sarQ", Ev, I1, XX }, ++ }, ++ /* GRP2b_cl */ ++ { ++ { "rolA", Eb, CL, XX }, ++ { "rorA", Eb, CL, XX }, ++ { "rclA", Eb, CL, XX }, ++ { "rcrA", Eb, CL, XX }, ++ { "shlA", Eb, CL, XX }, ++ { "shrA", Eb, CL, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarA", Eb, CL, XX }, ++ }, ++ /* GRP2S_cl */ ++ { ++ { "rolQ", Ev, CL, XX }, ++ { "rorQ", Ev, CL, XX }, ++ { "rclQ", Ev, CL, XX }, ++ { "rcrQ", Ev, CL, XX }, ++ { "shlQ", Ev, CL, XX }, ++ { "shrQ", Ev, CL, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarQ", Ev, CL, XX } ++ }, ++ /* GRP3b */ ++ { ++ { "testA", Eb, Ib, XX }, ++ { "(bad)", Eb, XX, XX }, ++ { "notA", Eb, XX, XX }, ++ { "negA", Eb, XX, XX }, ++ { "mulA", Eb, XX, XX }, /* Don't print the implicit %al register, */ ++ { "imulA", Eb, XX, XX }, /* to distinguish these opcodes from other */ ++ { "divA", Eb, XX, XX }, /* mul/imul opcodes. Do the same for div */ ++ { "idivA", Eb, XX, XX } /* and idiv for consistency. */ ++ }, ++ /* GRP3S */ ++ { ++ { "testQ", Ev, Iv, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "notQ", Ev, XX, XX }, ++ { "negQ", Ev, XX, XX }, ++ { "mulQ", Ev, XX, XX }, /* Don't print the implicit register. */ ++ { "imulQ", Ev, XX, XX }, ++ { "divQ", Ev, XX, XX }, ++ { "idivQ", Ev, XX, XX }, ++ }, ++ /* GRP4 */ ++ { ++ { "incA", Eb, XX, XX }, ++ { "decA", Eb, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP5 */ ++ { ++ { "incQ", Ev, XX, XX }, ++ { "decQ", Ev, XX, XX }, ++ { "callT", indirEv, XX, XX }, ++ { "JcallT", indirEp, XX, XX }, ++ { "jmpT", indirEv, XX, XX }, ++ { "JjmpT", indirEp, XX, XX }, ++ { "pushU", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP6 */ ++ { ++ { "sldtQ", Ev, XX, XX }, ++ { "strQ", Ev, XX, XX }, ++ { "lldt", Ew, XX, XX }, ++ { "ltr", Ew, XX, XX }, ++ { "verr", Ew, XX, XX }, ++ { "verw", Ew, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX } ++ }, ++ /* GRP7 */ ++ { ++ { "sgdtIQ", VMX_Fixup, 0, XX, XX }, ++ { "sidtIQ", PNI_Fixup, 0, XX, XX }, ++ { "lgdt{Q|Q||}", M, XX, XX }, ++ { "lidt{Q|Q||}", SVME_Fixup, 0, XX, XX }, ++ { "smswQ", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "lmsw", Ew, XX, XX }, ++ { "invlpg", INVLPG_Fixup, w_mode, XX, XX }, ++ }, ++ /* GRP8 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "btQ", Ev, Ib, XX }, ++ { "btsQ", Ev, Ib, XX }, ++ { "btrQ", Ev, Ib, XX }, ++ { "btcQ", Ev, Ib, XX }, ++ }, ++ /* GRP9 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "cmpxchg8b", Eq, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "", VM, XX, XX }, /* See OP_VMX. */ ++ { "vmptrst", Eq, XX, XX }, ++ }, ++ /* GRP10 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrlw", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psraw", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psllw", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP11 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrld", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrad", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "pslld", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP12 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrlq", MS, Ib, XX }, ++ { "psrldq", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psllq", MS, Ib, XX }, ++ { "pslldq", MS, Ib, XX }, ++ }, ++ /* GRP13 */ ++ { ++ { "fxsave", Ev, XX, XX }, ++ { "fxrstor", Ev, XX, XX }, ++ { "ldmxcsr", Ev, XX, XX }, ++ { "stmxcsr", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "lfence", OP_0fae, 0, XX, XX }, ++ { "mfence", OP_0fae, 0, XX, XX }, ++ { "clflush", OP_0fae, 0, XX, XX }, ++ }, ++ /* GRP14 */ ++ { ++ { "prefetchnta", Ev, XX, XX }, ++ { "prefetcht0", Ev, XX, XX }, ++ { "prefetcht1", Ev, XX, XX }, ++ { "prefetcht2", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRPAMD */ ++ { ++ { "prefetch", Eb, XX, XX }, ++ { "prefetchw", Eb, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRPPADLCK1 */ ++ { ++ { "xstore-rng", OP_0f07, 0, XX, XX }, ++ { "xcrypt-ecb", OP_0f07, 0, XX, XX }, ++ { "xcrypt-cbc", OP_0f07, 0, XX, XX }, ++ { "xcrypt-ctr", OP_0f07, 0, XX, XX }, ++ { "xcrypt-cfb", OP_0f07, 0, XX, XX }, ++ { "xcrypt-ofb", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ }, ++ /* GRPPADLCK2 */ ++ { ++ { "montmul", OP_0f07, 0, XX, XX }, ++ { "xsha1", OP_0f07, 0, XX, XX }, ++ { "xsha256", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ } ++}; ++ ++static const struct dis386 prefix_user_table[][4] = { ++ /* PREGRP0 */ ++ { ++ { "addps", XM, EX, XX }, ++ { "addss", XM, EX, XX }, ++ { "addpd", XM, EX, XX }, ++ { "addsd", XM, EX, XX }, ++ }, ++ /* PREGRP1 */ ++ { ++ { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX. */ ++ { "", XM, EX, OPSIMD }, ++ { "", XM, EX, OPSIMD }, ++ { "", XM, EX, OPSIMD }, ++ }, ++ /* PREGRP2 */ ++ { ++ { "cvtpi2ps", XM, EM, XX }, ++ { "cvtsi2ssY", XM, Ev, XX }, ++ { "cvtpi2pd", XM, EM, XX }, ++ { "cvtsi2sdY", XM, Ev, XX }, ++ }, ++ /* PREGRP3 */ ++ { ++ { "cvtps2pi", MX, EX, XX }, ++ { "cvtss2siY", Gv, EX, XX }, ++ { "cvtpd2pi", MX, EX, XX }, ++ { "cvtsd2siY", Gv, EX, XX }, ++ }, ++ /* PREGRP4 */ ++ { ++ { "cvttps2pi", MX, EX, XX }, ++ { "cvttss2siY", Gv, EX, XX }, ++ { "cvttpd2pi", MX, EX, XX }, ++ { "cvttsd2siY", Gv, EX, XX }, ++ }, ++ /* PREGRP5 */ ++ { ++ { "divps", XM, EX, XX }, ++ { "divss", XM, EX, XX }, ++ { "divpd", XM, EX, XX }, ++ { "divsd", XM, EX, XX }, ++ }, ++ /* PREGRP6 */ ++ { ++ { "maxps", XM, EX, XX }, ++ { "maxss", XM, EX, XX }, ++ { "maxpd", XM, EX, XX }, ++ { "maxsd", XM, EX, XX }, ++ }, ++ /* PREGRP7 */ ++ { ++ { "minps", XM, EX, XX }, ++ { "minss", XM, EX, XX }, ++ { "minpd", XM, EX, XX }, ++ { "minsd", XM, EX, XX }, ++ }, ++ /* PREGRP8 */ ++ { ++ { "movups", XM, EX, XX }, ++ { "movss", XM, EX, XX }, ++ { "movupd", XM, EX, XX }, ++ { "movsd", XM, EX, XX }, ++ }, ++ /* PREGRP9 */ ++ { ++ { "movups", EX, XM, XX }, ++ { "movss", EX, XM, XX }, ++ { "movupd", EX, XM, XX }, ++ { "movsd", EX, XM, XX }, ++ }, ++ /* PREGRP10 */ ++ { ++ { "mulps", XM, EX, XX }, ++ { "mulss", XM, EX, XX }, ++ { "mulpd", XM, EX, XX }, ++ { "mulsd", XM, EX, XX }, ++ }, ++ /* PREGRP11 */ ++ { ++ { "rcpps", XM, EX, XX }, ++ { "rcpss", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP12 */ ++ { ++ { "rsqrtps", XM, EX, XX }, ++ { "rsqrtss", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP13 */ ++ { ++ { "sqrtps", XM, EX, XX }, ++ { "sqrtss", XM, EX, XX }, ++ { "sqrtpd", XM, EX, XX }, ++ { "sqrtsd", XM, EX, XX }, ++ }, ++ /* PREGRP14 */ ++ { ++ { "subps", XM, EX, XX }, ++ { "subss", XM, EX, XX }, ++ { "subpd", XM, EX, XX }, ++ { "subsd", XM, EX, XX }, ++ }, ++ /* PREGRP15 */ ++ { ++ { "(bad)", XM, EX, XX }, ++ { "cvtdq2pd", XM, EX, XX }, ++ { "cvttpd2dq", XM, EX, XX }, ++ { "cvtpd2dq", XM, EX, XX }, ++ }, ++ /* PREGRP16 */ ++ { ++ { "cvtdq2ps", XM, EX, XX }, ++ { "cvttps2dq",XM, EX, XX }, ++ { "cvtps2dq",XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP17 */ ++ { ++ { "cvtps2pd", XM, EX, XX }, ++ { "cvtss2sd", XM, EX, XX }, ++ { "cvtpd2ps", XM, EX, XX }, ++ { "cvtsd2ss", XM, EX, XX }, ++ }, ++ /* PREGRP18 */ ++ { ++ { "maskmovq", MX, MS, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "maskmovdqu", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP19 */ ++ { ++ { "movq", MX, EM, XX }, ++ { "movdqu", XM, EX, XX }, ++ { "movdqa", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP20 */ ++ { ++ { "movq", EM, MX, XX }, ++ { "movdqu", EX, XM, XX }, ++ { "movdqa", EX, XM, XX }, ++ { "(bad)", EX, XM, XX }, ++ }, ++ /* PREGRP21 */ ++ { ++ { "(bad)", EX, XM, XX }, ++ { "movq2dq", XM, MS, XX }, ++ { "movq", EX, XM, XX }, ++ { "movdq2q", MX, XS, XX }, ++ }, ++ /* PREGRP22 */ ++ { ++ { "pshufw", MX, EM, Ib }, ++ { "pshufhw", XM, EX, Ib }, ++ { "pshufd", XM, EX, Ib }, ++ { "pshuflw", XM, EX, Ib }, ++ }, ++ /* PREGRP23 */ ++ { ++ { "movd", Edq, MX, XX }, ++ { "movq", XM, EX, XX }, ++ { "movd", Edq, XM, XX }, ++ { "(bad)", Ed, XM, XX }, ++ }, ++ /* PREGRP24 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "punpckhqdq", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP25 */ ++ { ++ { "movntq", EM, MX, XX }, ++ { "(bad)", EM, XM, XX }, ++ { "movntdq", EM, XM, XX }, ++ { "(bad)", EM, XM, XX }, ++ }, ++ /* PREGRP26 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "punpcklqdq", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP27 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "addsubpd", XM, EX, XX }, ++ { "addsubps", XM, EX, XX }, ++ }, ++ /* PREGRP28 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "haddpd", XM, EX, XX }, ++ { "haddps", XM, EX, XX }, ++ }, ++ /* PREGRP29 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "hsubpd", XM, EX, XX }, ++ { "hsubps", XM, EX, XX }, ++ }, ++ /* PREGRP30 */ ++ { ++ { "movlpX", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ ++ { "movsldup", XM, EX, XX }, ++ { "movlpd", XM, EX, XX }, ++ { "movddup", XM, EX, XX }, ++ }, ++ /* PREGRP31 */ ++ { ++ { "movhpX", XM, EX, SIMD_Fixup, 'l' }, ++ { "movshdup", XM, EX, XX }, ++ { "movhpd", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP32 */ ++ { ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "lddqu", XM, M, XX }, ++ }, ++}; ++ ++static const struct dis386 x86_64_table[][2] = { ++ { ++ { "arpl", Ew, Gw, XX }, ++ { "movs{||lq|xd}", Gv, Ed, XX }, ++ }, ++}; ++ ++#ifdef __KERNEL__ ++#define INTERNAL_DISASSEMBLER_ERROR "" ++#else /* __KERNEL__ */ ++#define INTERNAL_DISASSEMBLER_ERROR _("") ++#endif /* __KERNEL__ */ ++ ++static void ++ckprefix (void) ++{ ++ int newrex; ++ rex = 0; ++ prefixes = 0; ++ used_prefixes = 0; ++ rex_used = 0; ++ while (1) ++ { ++ FETCH_DATA (the_info, codep + 1); ++ newrex = 0; ++ switch (*codep) ++ { ++ /* REX prefixes family. */ ++ case 0x40: ++ case 0x41: ++ case 0x42: ++ case 0x43: ++ case 0x44: ++ case 0x45: ++ case 0x46: ++ case 0x47: ++ case 0x48: ++ case 0x49: ++ case 0x4a: ++ case 0x4b: ++ case 0x4c: ++ case 0x4d: ++ case 0x4e: ++ case 0x4f: ++ if (mode_64bit) ++ newrex = *codep; ++ else ++ return; ++ break; ++ case 0xf3: ++ prefixes |= PREFIX_REPZ; ++ break; ++ case 0xf2: ++ prefixes |= PREFIX_REPNZ; ++ break; ++ case 0xf0: ++ prefixes |= PREFIX_LOCK; ++ break; ++ case 0x2e: ++ prefixes |= PREFIX_CS; ++ break; ++ case 0x36: ++ prefixes |= PREFIX_SS; ++ break; ++ case 0x3e: ++ prefixes |= PREFIX_DS; ++ break; ++ case 0x26: ++ prefixes |= PREFIX_ES; ++ break; ++ case 0x64: ++ prefixes |= PREFIX_FS; ++ break; ++ case 0x65: ++ prefixes |= PREFIX_GS; ++ break; ++ case 0x66: ++ prefixes |= PREFIX_DATA; ++ break; ++ case 0x67: ++ prefixes |= PREFIX_ADDR; ++ break; ++ case FWAIT_OPCODE: ++ /* fwait is really an instruction. If there are prefixes ++ before the fwait, they belong to the fwait, *not* to the ++ following instruction. */ ++ if (prefixes) ++ { ++ prefixes |= PREFIX_FWAIT; ++ codep++; ++ return; ++ } ++ prefixes = PREFIX_FWAIT; ++ break; ++ default: ++ return; ++ } ++ /* Rex is ignored when followed by another prefix. */ ++ if (rex) ++ { ++ oappend (prefix_name (rex, 0)); ++ oappend (" "); ++ } ++ rex = newrex; ++ codep++; ++ } ++} ++ ++/* Return the name of the prefix byte PREF, or NULL if PREF is not a ++ prefix byte. */ ++ ++static const char * ++prefix_name (int pref, int sizeflag) ++{ ++ switch (pref) ++ { ++ /* REX prefixes family. */ ++ case 0x40: ++ return "rex"; ++ case 0x41: ++ return "rexZ"; ++ case 0x42: ++ return "rexY"; ++ case 0x43: ++ return "rexYZ"; ++ case 0x44: ++ return "rexX"; ++ case 0x45: ++ return "rexXZ"; ++ case 0x46: ++ return "rexXY"; ++ case 0x47: ++ return "rexXYZ"; ++ case 0x48: ++ return "rex64"; ++ case 0x49: ++ return "rex64Z"; ++ case 0x4a: ++ return "rex64Y"; ++ case 0x4b: ++ return "rex64YZ"; ++ case 0x4c: ++ return "rex64X"; ++ case 0x4d: ++ return "rex64XZ"; ++ case 0x4e: ++ return "rex64XY"; ++ case 0x4f: ++ return "rex64XYZ"; ++ case 0xf3: ++ return "repz"; ++ case 0xf2: ++ return "repnz"; ++ case 0xf0: ++ return "lock"; ++ case 0x2e: ++ return "cs"; ++ case 0x36: ++ return "ss"; ++ case 0x3e: ++ return "ds"; ++ case 0x26: ++ return "es"; ++ case 0x64: ++ return "fs"; ++ case 0x65: ++ return "gs"; ++ case 0x66: ++ return (sizeflag & DFLAG) ? "data16" : "data32"; ++ case 0x67: ++ if (mode_64bit) ++ return (sizeflag & AFLAG) ? "addr32" : "addr64"; ++ else ++ return (sizeflag & AFLAG) ? "addr16" : "addr32"; ++ case FWAIT_OPCODE: ++ return "fwait"; ++ default: ++ return NULL; ++ } ++} ++ ++static char op1out[100], op2out[100], op3out[100]; ++static int op_ad, op_index[3]; ++static int two_source_ops; ++static bfd_vma op_address[3]; ++static bfd_vma op_riprel[3]; ++static bfd_vma start_pc; ++ ++/* ++ * On the 386's of 1988, the maximum length of an instruction is 15 bytes. ++ * (see topic "Redundant prefixes" in the "Differences from 8086" ++ * section of the "Virtual 8086 Mode" chapter.) ++ * 'pc' should be the address of this instruction, it will ++ * be used to print the target address if this is a relative jump or call ++ * The function returns the length of this instruction in bytes. ++ */ ++ ++static char intel_syntax; ++static char open_char; ++static char close_char; ++static char separator_char; ++static char scale_char; ++ ++/* Here for backwards compatibility. When gdb stops using ++ print_insn_i386_att and print_insn_i386_intel these functions can ++ disappear, and print_insn_i386 be merged into print_insn. */ ++int ++print_insn_i386_att (bfd_vma pc, disassemble_info *info) ++{ ++ intel_syntax = 0; ++ ++ return print_insn (pc, info); ++} ++ ++int ++print_insn_i386_intel (bfd_vma pc, disassemble_info *info) ++{ ++ intel_syntax = 1; ++ ++ return print_insn (pc, info); ++} ++ ++int ++print_insn_i386 (bfd_vma pc, disassemble_info *info) ++{ ++ intel_syntax = -1; ++ ++ return print_insn (pc, info); ++} ++ ++static int ++print_insn (bfd_vma pc, disassemble_info *info) ++{ ++ const struct dis386 *dp; ++ int i; ++ char *first, *second, *third; ++ int needcomma; ++ unsigned char uses_SSE_prefix, uses_LOCK_prefix; ++ int sizeflag; ++ const char *p; ++ struct dis_private priv; ++ ++ mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax ++ || info->mach == bfd_mach_x86_64); ++ ++ if (intel_syntax == (char) -1) ++ intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax ++ || info->mach == bfd_mach_x86_64_intel_syntax); ++ ++ if (info->mach == bfd_mach_i386_i386 ++ || info->mach == bfd_mach_x86_64 ++ || info->mach == bfd_mach_i386_i386_intel_syntax ++ || info->mach == bfd_mach_x86_64_intel_syntax) ++ priv.orig_sizeflag = AFLAG | DFLAG; ++ else if (info->mach == bfd_mach_i386_i8086) ++ priv.orig_sizeflag = 0; ++ else ++ abort (); ++ ++ for (p = info->disassembler_options; p != NULL; ) ++ { ++ if (strncmp (p, "x86-64", 6) == 0) ++ { ++ mode_64bit = 1; ++ priv.orig_sizeflag = AFLAG | DFLAG; ++ } ++ else if (strncmp (p, "i386", 4) == 0) ++ { ++ mode_64bit = 0; ++ priv.orig_sizeflag = AFLAG | DFLAG; ++ } ++ else if (strncmp (p, "i8086", 5) == 0) ++ { ++ mode_64bit = 0; ++ priv.orig_sizeflag = 0; ++ } ++ else if (strncmp (p, "intel", 5) == 0) ++ { ++ intel_syntax = 1; ++ } ++ else if (strncmp (p, "att", 3) == 0) ++ { ++ intel_syntax = 0; ++ } ++ else if (strncmp (p, "addr", 4) == 0) ++ { ++ if (p[4] == '1' && p[5] == '6') ++ priv.orig_sizeflag &= ~AFLAG; ++ else if (p[4] == '3' && p[5] == '2') ++ priv.orig_sizeflag |= AFLAG; ++ } ++ else if (strncmp (p, "data", 4) == 0) ++ { ++ if (p[4] == '1' && p[5] == '6') ++ priv.orig_sizeflag &= ~DFLAG; ++ else if (p[4] == '3' && p[5] == '2') ++ priv.orig_sizeflag |= DFLAG; ++ } ++ else if (strncmp (p, "suffix", 6) == 0) ++ priv.orig_sizeflag |= SUFFIX_ALWAYS; ++ ++ p = strchr (p, ','); ++ if (p != NULL) ++ p++; ++ } ++ ++ if (intel_syntax) ++ { ++ names64 = intel_names64; ++ names32 = intel_names32; ++ names16 = intel_names16; ++ names8 = intel_names8; ++ names8rex = intel_names8rex; ++ names_seg = intel_names_seg; ++ index16 = intel_index16; ++ open_char = '['; ++ close_char = ']'; ++ separator_char = '+'; ++ scale_char = '*'; ++ } ++ else ++ { ++ names64 = att_names64; ++ names32 = att_names32; ++ names16 = att_names16; ++ names8 = att_names8; ++ names8rex = att_names8rex; ++ names_seg = att_names_seg; ++ index16 = att_index16; ++ open_char = '('; ++ close_char = ')'; ++ separator_char = ','; ++ scale_char = ','; ++ } ++ ++ /* The output looks better if we put 7 bytes on a line, since that ++ puts most long word instructions on a single line. */ ++ info->bytes_per_line = 7; ++ ++ info->private_data = &priv; ++ priv.max_fetched = priv.the_buffer; ++ priv.insn_start = pc; ++ ++ obuf[0] = 0; ++ op1out[0] = 0; ++ op2out[0] = 0; ++ op3out[0] = 0; ++ ++ op_index[0] = op_index[1] = op_index[2] = -1; ++ ++ the_info = info; ++ start_pc = pc; ++ start_codep = priv.the_buffer; ++ codep = priv.the_buffer; ++ ++#ifndef __KERNEL__ ++ if (setjmp (priv.bailout) != 0) ++ { ++ const char *name; ++ ++ /* Getting here means we tried for data but didn't get it. That ++ means we have an incomplete instruction of some sort. Just ++ print the first byte as a prefix or a .byte pseudo-op. */ ++ if (codep > priv.the_buffer) ++ { ++ name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); ++ if (name != NULL) ++ (*info->fprintf_func) (info->stream, "%s", name); ++ else ++ { ++ /* Just print the first byte as a .byte instruction. */ ++ (*info->fprintf_func) (info->stream, ".byte 0x%x", ++ (unsigned int) priv.the_buffer[0]); ++ } ++ ++ return 1; ++ } ++ ++ return -1; ++ } ++#endif /* __KERNEL__ */ ++ ++ obufp = obuf; ++ ckprefix (); ++ ++ insn_codep = codep; ++ sizeflag = priv.orig_sizeflag; ++ ++ FETCH_DATA (info, codep + 1); ++ two_source_ops = (*codep == 0x62) || (*codep == 0xc8); ++ ++ if ((prefixes & PREFIX_FWAIT) ++ && ((*codep < 0xd8) || (*codep > 0xdf))) ++ { ++ const char *name; ++ ++ /* fwait not followed by floating point instruction. Print the ++ first prefix, which is probably fwait itself. */ ++ name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); ++ if (name == NULL) ++ name = INTERNAL_DISASSEMBLER_ERROR; ++ (*info->fprintf_func) (info->stream, "%s", name); ++ return 1; ++ } ++ ++ if (*codep == 0x0f) ++ { ++ FETCH_DATA (info, codep + 2); ++ dp = &dis386_twobyte[*++codep]; ++ need_modrm = twobyte_has_modrm[*codep]; ++ uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; ++ uses_LOCK_prefix = (*codep & ~0x02) == 0x20; ++ } ++ else ++ { ++ dp = &dis386[*codep]; ++ need_modrm = onebyte_has_modrm[*codep]; ++ uses_SSE_prefix = 0; ++ uses_LOCK_prefix = 0; ++ } ++ codep++; ++ ++ if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ)) ++ { ++ oappend ("repz "); ++ used_prefixes |= PREFIX_REPZ; ++ } ++ if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ)) ++ { ++ oappend ("repnz "); ++ used_prefixes |= PREFIX_REPNZ; ++ } ++ if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) ++ { ++ oappend ("lock "); ++ used_prefixes |= PREFIX_LOCK; ++ } ++ ++ if (prefixes & PREFIX_ADDR) ++ { ++ sizeflag ^= AFLAG; ++ if (dp->bytemode3 != loop_jcxz_mode || intel_syntax) ++ { ++ if ((sizeflag & AFLAG) || mode_64bit) ++ oappend ("addr32 "); ++ else ++ oappend ("addr16 "); ++ used_prefixes |= PREFIX_ADDR; ++ } ++ } ++ ++ if (!uses_SSE_prefix && (prefixes & PREFIX_DATA)) ++ { ++ sizeflag ^= DFLAG; ++ if (dp->bytemode3 == cond_jump_mode ++ && dp->bytemode1 == v_mode ++ && !intel_syntax) ++ { ++ if (sizeflag & DFLAG) ++ oappend ("data32 "); ++ else ++ oappend ("data16 "); ++ used_prefixes |= PREFIX_DATA; ++ } ++ } ++ ++ if (need_modrm) ++ { ++ FETCH_DATA (info, codep + 1); ++ mod = (*codep >> 6) & 3; ++ reg = (*codep >> 3) & 7; ++ rm = *codep & 7; ++ } ++ ++ if (dp->name == NULL && dp->bytemode1 == FLOATCODE) ++ { ++ dofloat (sizeflag); ++ } ++ else ++ { ++ int index; ++ if (dp->name == NULL) ++ { ++ switch (dp->bytemode1) ++ { ++ case USE_GROUPS: ++ dp = &grps[dp->bytemode2][reg]; ++ break; ++ ++ case USE_PREFIX_USER_TABLE: ++ index = 0; ++ used_prefixes |= (prefixes & PREFIX_REPZ); ++ if (prefixes & PREFIX_REPZ) ++ index = 1; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ index = 2; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_REPNZ); ++ if (prefixes & PREFIX_REPNZ) ++ index = 3; ++ } ++ } ++ dp = &prefix_user_table[dp->bytemode2][index]; ++ break; ++ ++ case X86_64_SPECIAL: ++ dp = &x86_64_table[dp->bytemode2][mode_64bit]; ++ break; ++ ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ break; ++ } ++ } ++ ++ if (putop (dp->name, sizeflag) == 0) ++ { ++ obufp = op1out; ++ op_ad = 2; ++ if (dp->op1) ++ (*dp->op1) (dp->bytemode1, sizeflag); ++ ++ obufp = op2out; ++ op_ad = 1; ++ if (dp->op2) ++ (*dp->op2) (dp->bytemode2, sizeflag); ++ ++ obufp = op3out; ++ op_ad = 0; ++ if (dp->op3) ++ (*dp->op3) (dp->bytemode3, sizeflag); ++ } ++ } ++ ++ /* See if any prefixes were not used. If so, print the first one ++ separately. If we don't do this, we'll wind up printing an ++ instruction stream which does not precisely correspond to the ++ bytes we are disassembling. */ ++ if ((prefixes & ~used_prefixes) != 0) ++ { ++ const char *name; ++ ++ name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); ++ if (name == NULL) ++ name = INTERNAL_DISASSEMBLER_ERROR; ++ (*info->fprintf_func) (info->stream, "%s", name); ++ return 1; ++ } ++ if (rex & ~rex_used) ++ { ++ const char *name; ++ name = prefix_name (rex | 0x40, priv.orig_sizeflag); ++ if (name == NULL) ++ name = INTERNAL_DISASSEMBLER_ERROR; ++ (*info->fprintf_func) (info->stream, "%s ", name); ++ } ++ ++ obufp = obuf + strlen (obuf); ++ for (i = strlen (obuf); i < 6; i++) ++ oappend (" "); ++ oappend (" "); ++ (*info->fprintf_func) (info->stream, "%s", obuf); ++ ++ /* The enter and bound instructions are printed with operands in the same ++ order as the intel book; everything else is printed in reverse order. */ ++ if (intel_syntax || two_source_ops) ++ { ++ first = op1out; ++ second = op2out; ++ third = op3out; ++ op_ad = op_index[0]; ++ op_index[0] = op_index[2]; ++ op_index[2] = op_ad; ++ } ++ else ++ { ++ first = op3out; ++ second = op2out; ++ third = op1out; ++ } ++ needcomma = 0; ++ if (*first) ++ { ++ if (op_index[0] != -1 && !op_riprel[0]) ++ (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); ++ else ++ (*info->fprintf_func) (info->stream, "%s", first); ++ needcomma = 1; ++ } ++ if (*second) ++ { ++ if (needcomma) ++ (*info->fprintf_func) (info->stream, ","); ++ if (op_index[1] != -1 && !op_riprel[1]) ++ (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); ++ else ++ (*info->fprintf_func) (info->stream, "%s", second); ++ needcomma = 1; ++ } ++ if (*third) ++ { ++ if (needcomma) ++ (*info->fprintf_func) (info->stream, ","); ++ if (op_index[2] != -1 && !op_riprel[2]) ++ (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); ++ else ++ (*info->fprintf_func) (info->stream, "%s", third); ++ } ++ for (i = 0; i < 3; i++) ++ if (op_index[i] != -1 && op_riprel[i]) ++ { ++ (*info->fprintf_func) (info->stream, " # "); ++ (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep ++ + op_address[op_index[i]]), info); ++ } ++ return codep - priv.the_buffer; ++} ++ ++static const char *float_mem[] = { ++ /* d8 */ ++ "fadd{s||s|}", ++ "fmul{s||s|}", ++ "fcom{s||s|}", ++ "fcomp{s||s|}", ++ "fsub{s||s|}", ++ "fsubr{s||s|}", ++ "fdiv{s||s|}", ++ "fdivr{s||s|}", ++ /* d9 */ ++ "fld{s||s|}", ++ "(bad)", ++ "fst{s||s|}", ++ "fstp{s||s|}", ++ "fldenvIC", ++ "fldcw", ++ "fNstenvIC", ++ "fNstcw", ++ /* da */ ++ "fiadd{l||l|}", ++ "fimul{l||l|}", ++ "ficom{l||l|}", ++ "ficomp{l||l|}", ++ "fisub{l||l|}", ++ "fisubr{l||l|}", ++ "fidiv{l||l|}", ++ "fidivr{l||l|}", ++ /* db */ ++ "fild{l||l|}", ++ "fisttp{l||l|}", ++ "fist{l||l|}", ++ "fistp{l||l|}", ++ "(bad)", ++ "fld{t||t|}", ++ "(bad)", ++ "fstp{t||t|}", ++ /* dc */ ++ "fadd{l||l|}", ++ "fmul{l||l|}", ++ "fcom{l||l|}", ++ "fcomp{l||l|}", ++ "fsub{l||l|}", ++ "fsubr{l||l|}", ++ "fdiv{l||l|}", ++ "fdivr{l||l|}", ++ /* dd */ ++ "fld{l||l|}", ++ "fisttp{ll||ll|}", ++ "fst{l||l|}", ++ "fstp{l||l|}", ++ "frstorIC", ++ "(bad)", ++ "fNsaveIC", ++ "fNstsw", ++ /* de */ ++ "fiadd", ++ "fimul", ++ "ficom", ++ "ficomp", ++ "fisub", ++ "fisubr", ++ "fidiv", ++ "fidivr", ++ /* df */ ++ "fild", ++ "fisttp", ++ "fist", ++ "fistp", ++ "fbld", ++ "fild{ll||ll|}", ++ "fbstp", ++ "fistp{ll||ll|}", ++}; ++ ++static const unsigned char float_mem_mode[] = { ++ /* d8 */ ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ /* d9 */ ++ d_mode, ++ 0, ++ d_mode, ++ d_mode, ++ 0, ++ w_mode, ++ 0, ++ w_mode, ++ /* da */ ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ /* db */ ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ 0, ++ t_mode, ++ 0, ++ t_mode, ++ /* dc */ ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ /* dd */ ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ 0, ++ 0, ++ 0, ++ w_mode, ++ /* de */ ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ /* df */ ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ t_mode, ++ q_mode, ++ t_mode, ++ q_mode ++}; ++ ++#define ST OP_ST, 0 ++#define STi OP_STi, 0 ++ ++#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 ++#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 ++#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 ++#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 ++#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 ++#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 ++#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 ++#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 ++#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 ++ ++static const struct dis386 float_reg[][8] = { ++ /* d8 */ ++ { ++ { "fadd", ST, STi, XX }, ++ { "fmul", ST, STi, XX }, ++ { "fcom", STi, XX, XX }, ++ { "fcomp", STi, XX, XX }, ++ { "fsub", ST, STi, XX }, ++ { "fsubr", ST, STi, XX }, ++ { "fdiv", ST, STi, XX }, ++ { "fdivr", ST, STi, XX }, ++ }, ++ /* d9 */ ++ { ++ { "fld", STi, XX, XX }, ++ { "fxch", STi, XX, XX }, ++ { FGRPd9_2 }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPd9_4 }, ++ { FGRPd9_5 }, ++ { FGRPd9_6 }, ++ { FGRPd9_7 }, ++ }, ++ /* da */ ++ { ++ { "fcmovb", ST, STi, XX }, ++ { "fcmove", ST, STi, XX }, ++ { "fcmovbe",ST, STi, XX }, ++ { "fcmovu", ST, STi, XX }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPda_5 }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* db */ ++ { ++ { "fcmovnb",ST, STi, XX }, ++ { "fcmovne",ST, STi, XX }, ++ { "fcmovnbe",ST, STi, XX }, ++ { "fcmovnu",ST, STi, XX }, ++ { FGRPdb_4 }, ++ { "fucomi", ST, STi, XX }, ++ { "fcomi", ST, STi, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* dc */ ++ { ++ { "fadd", STi, ST, XX }, ++ { "fmul", STi, ST, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++#if UNIXWARE_COMPAT ++ { "fsub", STi, ST, XX }, ++ { "fsubr", STi, ST, XX }, ++ { "fdiv", STi, ST, XX }, ++ { "fdivr", STi, ST, XX }, ++#else ++ { "fsubr", STi, ST, XX }, ++ { "fsub", STi, ST, XX }, ++ { "fdivr", STi, ST, XX }, ++ { "fdiv", STi, ST, XX }, ++#endif ++ }, ++ /* dd */ ++ { ++ { "ffree", STi, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "fst", STi, XX, XX }, ++ { "fstp", STi, XX, XX }, ++ { "fucom", STi, XX, XX }, ++ { "fucomp", STi, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* de */ ++ { ++ { "faddp", STi, ST, XX }, ++ { "fmulp", STi, ST, XX }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPde_3 }, ++#if UNIXWARE_COMPAT ++ { "fsubp", STi, ST, XX }, ++ { "fsubrp", STi, ST, XX }, ++ { "fdivp", STi, ST, XX }, ++ { "fdivrp", STi, ST, XX }, ++#else ++ { "fsubrp", STi, ST, XX }, ++ { "fsubp", STi, ST, XX }, ++ { "fdivrp", STi, ST, XX }, ++ { "fdivp", STi, ST, XX }, ++#endif ++ }, ++ /* df */ ++ { ++ { "ffreep", STi, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPdf_4 }, ++ { "fucomip",ST, STi, XX }, ++ { "fcomip", ST, STi, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++}; ++ ++static char *fgrps[][8] = { ++ /* d9_2 0 */ ++ { ++ "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* d9_4 1 */ ++ { ++ "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", ++ }, ++ ++ /* d9_5 2 */ ++ { ++ "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", ++ }, ++ ++ /* d9_6 3 */ ++ { ++ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", ++ }, ++ ++ /* d9_7 4 */ ++ { ++ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", ++ }, ++ ++ /* da_5 5 */ ++ { ++ "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* db_4 6 */ ++ { ++ "feni(287 only)","fdisi(287 only)","fNclex","fNinit", ++ "fNsetpm(287 only)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* de_3 7 */ ++ { ++ "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* df_4 8 */ ++ { ++ "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++}; ++ ++static void ++dofloat (int sizeflag) ++{ ++ const struct dis386 *dp; ++ unsigned char floatop; ++ ++ floatop = codep[-1]; ++ ++ if (mod != 3) ++ { ++ int fp_indx = (floatop - 0xd8) * 8 + reg; ++ ++ putop (float_mem[fp_indx], sizeflag); ++ obufp = op1out; ++ OP_E (float_mem_mode[fp_indx], sizeflag); ++ return; ++ } ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ ++ dp = &float_reg[floatop - 0xd8][reg]; ++ if (dp->name == NULL) ++ { ++ putop (fgrps[dp->bytemode1][rm], sizeflag); ++ ++ /* Instruction fnstsw is only one with strange arg. */ ++ if (floatop == 0xdf && codep[-1] == 0xe0) ++ strcpy (op1out, names16[0]); ++ } ++ else ++ { ++ putop (dp->name, sizeflag); ++ ++ obufp = op1out; ++ if (dp->op1) ++ (*dp->op1) (dp->bytemode1, sizeflag); ++ obufp = op2out; ++ if (dp->op2) ++ (*dp->op2) (dp->bytemode2, sizeflag); ++ } ++} ++ ++static void ++OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ oappend ("%st"); ++} ++ ++static void ++OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ sprintf (scratchbuf, "%%st(%d)", rm); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++/* Capital letters in template are macros. */ ++static int ++putop (const char *template, int sizeflag) ++{ ++ const char *p; ++ int alt = 0; ++ ++ for (p = template; *p; p++) ++ { ++ switch (*p) ++ { ++ default: ++ *obufp++ = *p; ++ break; ++ case '{': ++ alt = 0; ++ if (intel_syntax) ++ alt += 1; ++ if (mode_64bit) ++ alt += 2; ++ while (alt != 0) ++ { ++ while (*++p != '|') ++ { ++ if (*p == '}') ++ { ++ /* Alternative not valid. */ ++ strcpy (obuf, "(bad)"); ++ obufp = obuf + 5; ++ return 1; ++ } ++ else if (*p == '\0') ++ abort (); ++ } ++ alt--; ++ } ++ /* Fall through. */ ++ case 'I': ++ alt = 1; ++ continue; ++ case '|': ++ while (*++p != '}') ++ { ++ if (*p == '\0') ++ abort (); ++ } ++ break; ++ case '}': ++ break; ++ case 'A': ++ if (intel_syntax) ++ break; ++ if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) ++ *obufp++ = 'b'; ++ break; ++ case 'B': ++ if (intel_syntax) ++ break; ++ if (sizeflag & SUFFIX_ALWAYS) ++ *obufp++ = 'b'; ++ break; ++ case 'C': ++ if (intel_syntax && !alt) ++ break; ++ if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = intel_syntax ? 'd' : 'l'; ++ else ++ *obufp++ = intel_syntax ? 'w' : 's'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ break; ++ case 'E': /* For jcxz/jecxz */ ++ if (mode_64bit) ++ { ++ if (sizeflag & AFLAG) ++ *obufp++ = 'r'; ++ else ++ *obufp++ = 'e'; ++ } ++ else ++ if (sizeflag & AFLAG) ++ *obufp++ = 'e'; ++ used_prefixes |= (prefixes & PREFIX_ADDR); ++ break; ++ case 'F': ++ if (intel_syntax) ++ break; ++ if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ if (sizeflag & AFLAG) ++ *obufp++ = mode_64bit ? 'q' : 'l'; ++ else ++ *obufp++ = mode_64bit ? 'l' : 'w'; ++ used_prefixes |= (prefixes & PREFIX_ADDR); ++ } ++ break; ++ case 'H': ++ if (intel_syntax) ++ break; ++ if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS ++ || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) ++ { ++ used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); ++ *obufp++ = ','; ++ *obufp++ = 'p'; ++ if (prefixes & PREFIX_DS) ++ *obufp++ = 't'; ++ else ++ *obufp++ = 'n'; ++ } ++ break; ++ case 'J': ++ if (intel_syntax) ++ break; ++ *obufp++ = 'l'; ++ break; ++ case 'L': ++ if (intel_syntax) ++ break; ++ if (sizeflag & SUFFIX_ALWAYS) ++ *obufp++ = 'l'; ++ break; ++ case 'N': ++ if ((prefixes & PREFIX_FWAIT) == 0) ++ *obufp++ = 'n'; ++ else ++ used_prefixes |= PREFIX_FWAIT; ++ break; ++ case 'O': ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ *obufp++ = 'o'; ++ else ++ *obufp++ = 'd'; ++ break; ++ case 'T': ++ if (intel_syntax) ++ break; ++ if (mode_64bit) ++ { ++ *obufp++ = 'q'; ++ break; ++ } ++ /* Fall through. */ ++ case 'P': ++ if (intel_syntax) ++ break; ++ if ((prefixes & PREFIX_DATA) ++ || (rex & REX_MODE64) ++ || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = 'l'; ++ else ++ *obufp++ = 'w'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ } ++ break; ++ case 'U': ++ if (intel_syntax) ++ break; ++ if (mode_64bit) ++ { ++ *obufp++ = 'q'; ++ break; ++ } ++ /* Fall through. */ ++ case 'Q': ++ if (intel_syntax && !alt) ++ break; ++ USED_REX (REX_MODE64); ++ if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = intel_syntax ? 'd' : 'l'; ++ else ++ *obufp++ = 'w'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ } ++ break; ++ case 'R': ++ USED_REX (REX_MODE64); ++ if (intel_syntax) ++ { ++ if (rex & REX_MODE64) ++ { ++ *obufp++ = 'q'; ++ *obufp++ = 't'; ++ } ++ else if (sizeflag & DFLAG) ++ { ++ *obufp++ = 'd'; ++ *obufp++ = 'q'; ++ } ++ else ++ { ++ *obufp++ = 'w'; ++ *obufp++ = 'd'; ++ } ++ } ++ else ++ { ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else if (sizeflag & DFLAG) ++ *obufp++ = 'l'; ++ else ++ *obufp++ = 'w'; ++ } ++ if (!(rex & REX_MODE64)) ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case 'S': ++ if (intel_syntax) ++ break; ++ if (sizeflag & SUFFIX_ALWAYS) ++ { ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = 'l'; ++ else ++ *obufp++ = 'w'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ } ++ break; ++ case 'X': ++ if (prefixes & PREFIX_DATA) ++ *obufp++ = 'd'; ++ else ++ *obufp++ = 's'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case 'Y': ++ if (intel_syntax) ++ break; ++ if (rex & REX_MODE64) ++ { ++ USED_REX (REX_MODE64); ++ *obufp++ = 'q'; ++ } ++ break; ++ /* implicit operand size 'l' for i386 or 'q' for x86-64 */ ++ case 'W': ++ /* operand size flag for cwtl, cbtw */ ++ USED_REX (0); ++ if (rex) ++ *obufp++ = 'l'; ++ else if (sizeflag & DFLAG) ++ *obufp++ = 'w'; ++ else ++ *obufp++ = 'b'; ++ if (intel_syntax) ++ { ++ if (rex) ++ { ++ *obufp++ = 'q'; ++ *obufp++ = 'e'; ++ } ++ if (sizeflag & DFLAG) ++ { ++ *obufp++ = 'd'; ++ *obufp++ = 'e'; ++ } ++ else ++ { ++ *obufp++ = 'w'; ++ } ++ } ++ if (!rex) ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ } ++ alt = 0; ++ } ++ *obufp = 0; ++ return 0; ++} ++ ++static void ++oappend (const char *s) ++{ ++ strcpy (obufp, s); ++ obufp += strlen (s); ++} ++ ++static void ++append_seg (void) ++{ ++ if (prefixes & PREFIX_CS) ++ { ++ used_prefixes |= PREFIX_CS; ++ oappend ("%cs:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_DS) ++ { ++ used_prefixes |= PREFIX_DS; ++ oappend ("%ds:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_SS) ++ { ++ used_prefixes |= PREFIX_SS; ++ oappend ("%ss:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_ES) ++ { ++ used_prefixes |= PREFIX_ES; ++ oappend ("%es:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_FS) ++ { ++ used_prefixes |= PREFIX_FS; ++ oappend ("%fs:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_GS) ++ { ++ used_prefixes |= PREFIX_GS; ++ oappend ("%gs:" + intel_syntax); ++ } ++} ++ ++static void ++OP_indirE (int bytemode, int sizeflag) ++{ ++ if (!intel_syntax) ++ oappend ("*"); ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++print_operand_value (char *buf, int hex, bfd_vma disp) ++{ ++ if (mode_64bit) ++ { ++ if (hex) ++ { ++ char tmp[30]; ++ int i; ++ buf[0] = '0'; ++ buf[1] = 'x'; ++ sprintf_vma (tmp, disp); ++ for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); ++ strcpy (buf + 2, tmp + i); ++ } ++ else ++ { ++ bfd_signed_vma v = disp; ++ char tmp[30]; ++ int i; ++ if (v < 0) ++ { ++ *(buf++) = '-'; ++ v = -disp; ++ /* Check for possible overflow on 0x8000000000000000. */ ++ if (v < 0) ++ { ++ strcpy (buf, "9223372036854775808"); ++ return; ++ } ++ } ++ if (!v) ++ { ++ strcpy (buf, "0"); ++ return; ++ } ++ ++ i = 0; ++ tmp[29] = 0; ++ while (v) ++ { ++ tmp[28 - i] = (v % 10) + '0'; ++ v /= 10; ++ i++; ++ } ++ strcpy (buf, tmp + 29 - i); ++ } ++ } ++ else ++ { ++ if (hex) ++ sprintf (buf, "0x%x", (unsigned int) disp); ++ else ++ sprintf (buf, "%d", (int) disp); ++ } ++} ++ ++static void ++OP_E (int bytemode, int sizeflag) ++{ ++ bfd_vma disp; ++ int add = 0; ++ int riprel = 0; ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add += 8; ++ ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ ++ if (mod == 3) ++ { ++ switch (bytemode) ++ { ++ case b_mode: ++ USED_REX (0); ++ if (rex) ++ oappend (names8rex[rm + add]); ++ else ++ oappend (names8[rm + add]); ++ break; ++ case w_mode: ++ oappend (names16[rm + add]); ++ break; ++ case d_mode: ++ oappend (names32[rm + add]); ++ break; ++ case q_mode: ++ oappend (names64[rm + add]); ++ break; ++ case m_mode: ++ if (mode_64bit) ++ oappend (names64[rm + add]); ++ else ++ oappend (names32[rm + add]); ++ break; ++ case branch_v_mode: ++ if (mode_64bit) ++ oappend (names64[rm + add]); ++ else ++ { ++ if ((sizeflag & DFLAG) || bytemode != branch_v_mode) ++ oappend (names32[rm + add]); ++ else ++ oappend (names16[rm + add]); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ break; ++ case v_mode: ++ case dq_mode: ++ case dqw_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ oappend (names64[rm + add]); ++ else if ((sizeflag & DFLAG) || bytemode != v_mode) ++ oappend (names32[rm + add]); ++ else ++ oappend (names16[rm + add]); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case 0: ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ break; ++ } ++ return; ++ } ++ ++ disp = 0; ++ append_seg (); ++ ++ if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */ ++ { ++ int havesib; ++ int havebase; ++ int base; ++ int index = 0; ++ int scale = 0; ++ ++ havesib = 0; ++ havebase = 1; ++ base = rm; ++ ++ if (base == 4) ++ { ++ havesib = 1; ++ FETCH_DATA (the_info, codep + 1); ++ index = (*codep >> 3) & 7; ++ if (mode_64bit || index != 0x4) ++ /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ ++ scale = (*codep >> 6) & 3; ++ base = *codep & 7; ++ USED_REX (REX_EXTY); ++ if (rex & REX_EXTY) ++ index += 8; ++ codep++; ++ } ++ base += add; ++ ++ switch (mod) ++ { ++ case 0: ++ if ((base & 7) == 5) ++ { ++ havebase = 0; ++ if (mode_64bit && !havesib) ++ riprel = 1; ++ disp = get32s (); ++ } ++ break; ++ case 1: ++ FETCH_DATA (the_info, codep + 1); ++ disp = *codep++; ++ if ((disp & 0x80) != 0) ++ disp -= 0x100; ++ break; ++ case 2: ++ disp = get32s (); ++ break; ++ } ++ ++ if (!intel_syntax) ++ if (mod != 0 || (base & 7) == 5) ++ { ++ print_operand_value (scratchbuf, !riprel, disp); ++ oappend (scratchbuf); ++ if (riprel) ++ { ++ set_op (disp, 1); ++ oappend ("(%rip)"); ++ } ++ } ++ ++ if (havebase || (havesib && (index != 4 || scale != 0))) ++ { ++ if (intel_syntax) ++ { ++ switch (bytemode) ++ { ++ case b_mode: ++ oappend ("BYTE PTR "); ++ break; ++ case w_mode: ++ case dqw_mode: ++ oappend ("WORD PTR "); ++ break; ++ case branch_v_mode: ++ case v_mode: ++ case dq_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ oappend ("QWORD PTR "); ++ else if ((sizeflag & DFLAG) || bytemode == dq_mode) ++ oappend ("DWORD PTR "); ++ else ++ oappend ("WORD PTR "); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case d_mode: ++ oappend ("DWORD PTR "); ++ break; ++ case q_mode: ++ oappend ("QWORD PTR "); ++ break; ++ case m_mode: ++ if (mode_64bit) ++ oappend ("QWORD PTR "); ++ else ++ oappend ("DWORD PTR "); ++ break; ++ case f_mode: ++ if (sizeflag & DFLAG) ++ { ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ oappend ("FWORD PTR "); ++ } ++ else ++ oappend ("DWORD PTR "); ++ break; ++ case t_mode: ++ oappend ("TBYTE PTR "); ++ break; ++ case x_mode: ++ oappend ("XMMWORD PTR "); ++ break; ++ default: ++ break; ++ } ++ } ++ *obufp++ = open_char; ++ if (intel_syntax && riprel) ++ oappend ("rip + "); ++ *obufp = '\0'; ++ if (havebase) ++ oappend (mode_64bit && (sizeflag & AFLAG) ++ ? names64[base] : names32[base]); ++ if (havesib) ++ { ++ if (index != 4) ++ { ++ if (!intel_syntax || havebase) ++ { ++ *obufp++ = separator_char; ++ *obufp = '\0'; ++ } ++ oappend (mode_64bit && (sizeflag & AFLAG) ++ ? names64[index] : names32[index]); ++ } ++ if (scale != 0 || (!intel_syntax && index != 4)) ++ { ++ *obufp++ = scale_char; ++ *obufp = '\0'; ++ sprintf (scratchbuf, "%d", 1 << scale); ++ oappend (scratchbuf); ++ } ++ } ++ if (intel_syntax && disp) ++ { ++ if ((bfd_signed_vma) disp > 0) ++ { ++ *obufp++ = '+'; ++ *obufp = '\0'; ++ } ++ else if (mod != 1) ++ { ++ *obufp++ = '-'; ++ *obufp = '\0'; ++ disp = - (bfd_signed_vma) disp; ++ } ++ ++ print_operand_value (scratchbuf, mod != 1, disp); ++ oappend (scratchbuf); ++ } ++ ++ *obufp++ = close_char; ++ *obufp = '\0'; ++ } ++ else if (intel_syntax) ++ { ++ if (mod != 0 || (base & 7) == 5) ++ { ++ if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS)) ++ ; ++ else ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ print_operand_value (scratchbuf, 1, disp); ++ oappend (scratchbuf); ++ } ++ } ++ } ++ else ++ { /* 16 bit address mode */ ++ switch (mod) ++ { ++ case 0: ++ if (rm == 6) ++ { ++ disp = get16 (); ++ if ((disp & 0x8000) != 0) ++ disp -= 0x10000; ++ } ++ break; ++ case 1: ++ FETCH_DATA (the_info, codep + 1); ++ disp = *codep++; ++ if ((disp & 0x80) != 0) ++ disp -= 0x100; ++ break; ++ case 2: ++ disp = get16 (); ++ if ((disp & 0x8000) != 0) ++ disp -= 0x10000; ++ break; ++ } ++ ++ if (!intel_syntax) ++ if (mod != 0 || rm == 6) ++ { ++ print_operand_value (scratchbuf, 0, disp); ++ oappend (scratchbuf); ++ } ++ ++ if (mod != 0 || rm != 6) ++ { ++ *obufp++ = open_char; ++ *obufp = '\0'; ++ oappend (index16[rm]); ++ if (intel_syntax && disp) ++ { ++ if ((bfd_signed_vma) disp > 0) ++ { ++ *obufp++ = '+'; ++ *obufp = '\0'; ++ } ++ else if (mod != 1) ++ { ++ *obufp++ = '-'; ++ *obufp = '\0'; ++ disp = - (bfd_signed_vma) disp; ++ } ++ ++ print_operand_value (scratchbuf, mod != 1, disp); ++ oappend (scratchbuf); ++ } ++ ++ *obufp++ = close_char; ++ *obufp = '\0'; ++ } ++ else if (intel_syntax) ++ { ++ if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS)) ++ ; ++ else ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ print_operand_value (scratchbuf, 1, disp & 0xffff); ++ oappend (scratchbuf); ++ } ++ } ++} ++ ++static void ++OP_G (int bytemode, int sizeflag) ++{ ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add += 8; ++ switch (bytemode) ++ { ++ case b_mode: ++ USED_REX (0); ++ if (rex) ++ oappend (names8rex[reg + add]); ++ else ++ oappend (names8[reg + add]); ++ break; ++ case w_mode: ++ oappend (names16[reg + add]); ++ break; ++ case d_mode: ++ oappend (names32[reg + add]); ++ break; ++ case q_mode: ++ oappend (names64[reg + add]); ++ break; ++ case v_mode: ++ case dq_mode: ++ case dqw_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ oappend (names64[reg + add]); ++ else if ((sizeflag & DFLAG) || bytemode != v_mode) ++ oappend (names32[reg + add]); ++ else ++ oappend (names16[reg + add]); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case m_mode: ++ if (mode_64bit) ++ oappend (names64[reg + add]); ++ else ++ oappend (names32[reg + add]); ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ break; ++ } ++} ++ ++static bfd_vma ++get64 (void) ++{ ++ bfd_vma x; ++#ifdef BFD64 ++ unsigned int a; ++ unsigned int b; ++ ++ FETCH_DATA (the_info, codep + 8); ++ a = *codep++ & 0xff; ++ a |= (*codep++ & 0xff) << 8; ++ a |= (*codep++ & 0xff) << 16; ++ a |= (*codep++ & 0xff) << 24; ++ b = *codep++ & 0xff; ++ b |= (*codep++ & 0xff) << 8; ++ b |= (*codep++ & 0xff) << 16; ++ b |= (*codep++ & 0xff) << 24; ++ x = a + ((bfd_vma) b << 32); ++#else ++ abort (); ++ x = 0; ++#endif ++ return x; ++} ++ ++static bfd_signed_vma ++get32 (void) ++{ ++ bfd_signed_vma x = 0; ++ ++ FETCH_DATA (the_info, codep + 4); ++ x = *codep++ & (bfd_signed_vma) 0xff; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; ++ return x; ++} ++ ++static bfd_signed_vma ++get32s (void) ++{ ++ bfd_signed_vma x = 0; ++ ++ FETCH_DATA (the_info, codep + 4); ++ x = *codep++ & (bfd_signed_vma) 0xff; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; ++ ++ x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); ++ ++ return x; ++} ++ ++static int ++get16 (void) ++{ ++ int x = 0; ++ ++ FETCH_DATA (the_info, codep + 2); ++ x = *codep++ & 0xff; ++ x |= (*codep++ & 0xff) << 8; ++ return x; ++} ++ ++static void ++set_op (bfd_vma op, int riprel) ++{ ++ op_index[op_ad] = op_ad; ++ if (mode_64bit) ++ { ++ op_address[op_ad] = op; ++ op_riprel[op_ad] = riprel; ++ } ++ else ++ { ++ /* Mask to get a 32-bit address. */ ++ op_address[op_ad] = op & 0xffffffff; ++ op_riprel[op_ad] = riprel & 0xffffffff; ++ } ++} ++ ++static void ++OP_REG (int code, int sizeflag) ++{ ++ const char *s; ++ int add = 0; ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add = 8; ++ ++ switch (code) ++ { ++ case indir_dx_reg: ++ if (intel_syntax) ++ s = "[dx]"; ++ else ++ s = "(%dx)"; ++ break; ++ case ax_reg: case cx_reg: case dx_reg: case bx_reg: ++ case sp_reg: case bp_reg: case si_reg: case di_reg: ++ s = names16[code - ax_reg + add]; ++ break; ++ case es_reg: case ss_reg: case cs_reg: ++ case ds_reg: case fs_reg: case gs_reg: ++ s = names_seg[code - es_reg + add]; ++ break; ++ case al_reg: case ah_reg: case cl_reg: case ch_reg: ++ case dl_reg: case dh_reg: case bl_reg: case bh_reg: ++ USED_REX (0); ++ if (rex) ++ s = names8rex[code - al_reg + add]; ++ else ++ s = names8[code - al_reg]; ++ break; ++ case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: ++ case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: ++ if (mode_64bit) ++ { ++ s = names64[code - rAX_reg + add]; ++ break; ++ } ++ code += eAX_reg - rAX_reg; ++ /* Fall through. */ ++ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: ++ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ s = names64[code - eAX_reg + add]; ++ else if (sizeflag & DFLAG) ++ s = names32[code - eAX_reg + add]; ++ else ++ s = names16[code - eAX_reg + add]; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ default: ++ s = INTERNAL_DISASSEMBLER_ERROR; ++ break; ++ } ++ oappend (s); ++} ++ ++static void ++OP_IMREG (int code, int sizeflag) ++{ ++ const char *s; ++ ++ switch (code) ++ { ++ case indir_dx_reg: ++ if (intel_syntax) ++ s = "[dx]"; ++ else ++ s = "(%dx)"; ++ break; ++ case ax_reg: case cx_reg: case dx_reg: case bx_reg: ++ case sp_reg: case bp_reg: case si_reg: case di_reg: ++ s = names16[code - ax_reg]; ++ break; ++ case es_reg: case ss_reg: case cs_reg: ++ case ds_reg: case fs_reg: case gs_reg: ++ s = names_seg[code - es_reg]; ++ break; ++ case al_reg: case ah_reg: case cl_reg: case ch_reg: ++ case dl_reg: case dh_reg: case bl_reg: case bh_reg: ++ USED_REX (0); ++ if (rex) ++ s = names8rex[code - al_reg]; ++ else ++ s = names8[code - al_reg]; ++ break; ++ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: ++ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ s = names64[code - eAX_reg]; ++ else if (sizeflag & DFLAG) ++ s = names32[code - eAX_reg]; ++ else ++ s = names16[code - eAX_reg]; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ default: ++ s = INTERNAL_DISASSEMBLER_ERROR; ++ break; ++ } ++ oappend (s); ++} ++ ++static void ++OP_I (int bytemode, int sizeflag) ++{ ++ bfd_signed_vma op; ++ bfd_signed_vma mask = -1; ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ op = *codep++; ++ mask = 0xff; ++ break; ++ case q_mode: ++ if (mode_64bit) ++ { ++ op = get32s (); ++ break; ++ } ++ /* Fall through. */ ++ case v_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ op = get32s (); ++ else if (sizeflag & DFLAG) ++ { ++ op = get32 (); ++ mask = 0xffffffff; ++ } ++ else ++ { ++ op = get16 (); ++ mask = 0xfffff; ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case w_mode: ++ mask = 0xfffff; ++ op = get16 (); ++ break; ++ case const_1_mode: ++ if (intel_syntax) ++ oappend ("1"); ++ return; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ ++ op &= mask; ++ scratchbuf[0] = '$'; ++ print_operand_value (scratchbuf + 1, 1, op); ++ oappend (scratchbuf + intel_syntax); ++ scratchbuf[0] = '\0'; ++} ++ ++static void ++OP_I64 (int bytemode, int sizeflag) ++{ ++ bfd_signed_vma op; ++ bfd_signed_vma mask = -1; ++ ++ if (!mode_64bit) ++ { ++ OP_I (bytemode, sizeflag); ++ return; ++ } ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ op = *codep++; ++ mask = 0xff; ++ break; ++ case v_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ op = get64 (); ++ else if (sizeflag & DFLAG) ++ { ++ op = get32 (); ++ mask = 0xffffffff; ++ } ++ else ++ { ++ op = get16 (); ++ mask = 0xfffff; ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case w_mode: ++ mask = 0xfffff; ++ op = get16 (); ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ ++ op &= mask; ++ scratchbuf[0] = '$'; ++ print_operand_value (scratchbuf + 1, 1, op); ++ oappend (scratchbuf + intel_syntax); ++ scratchbuf[0] = '\0'; ++} ++ ++static void ++OP_sI (int bytemode, int sizeflag) ++{ ++ bfd_signed_vma op; ++ bfd_signed_vma mask = -1; ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ op = *codep++; ++ if ((op & 0x80) != 0) ++ op -= 0x100; ++ mask = 0xffffffff; ++ break; ++ case v_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ op = get32s (); ++ else if (sizeflag & DFLAG) ++ { ++ op = get32s (); ++ mask = 0xffffffff; ++ } ++ else ++ { ++ mask = 0xffffffff; ++ op = get16 (); ++ if ((op & 0x8000) != 0) ++ op -= 0x10000; ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case w_mode: ++ op = get16 (); ++ mask = 0xffffffff; ++ if ((op & 0x8000) != 0) ++ op -= 0x10000; ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ ++ scratchbuf[0] = '$'; ++ print_operand_value (scratchbuf + 1, 1, op); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_J (int bytemode, int sizeflag) ++{ ++ bfd_vma disp; ++ bfd_vma mask = -1; ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ disp = *codep++; ++ if ((disp & 0x80) != 0) ++ disp -= 0x100; ++ break; ++ case v_mode: ++ if (sizeflag & DFLAG) ++ disp = get32s (); ++ else ++ { ++ disp = get16 (); ++ /* For some reason, a data16 prefix on a jump instruction ++ means that the pc is masked to 16 bits after the ++ displacement is added! */ ++ mask = 0xffff; ++ } ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ disp = (start_pc + codep - start_codep + disp) & mask; ++ set_op (disp, 0); ++ print_operand_value (scratchbuf, 1, disp); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_SEG (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ oappend (names_seg[reg]); ++} ++ ++static void ++OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ int seg, offset; ++ ++ if (sizeflag & DFLAG) ++ { ++ offset = get32 (); ++ seg = get16 (); ++ } ++ else ++ { ++ offset = get16 (); ++ seg = get16 (); ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (intel_syntax) ++ sprintf (scratchbuf, "0x%x,0x%x", seg, offset); ++ else ++ sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_OFF (int bytemode ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ bfd_vma off; ++ ++ append_seg (); ++ ++ if ((sizeflag & AFLAG) || mode_64bit) ++ off = get32 (); ++ else ++ off = get16 (); ++ ++ if (intel_syntax) ++ { ++ if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS))) ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ } ++ print_operand_value (scratchbuf, 1, off); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_OFF64 (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ bfd_vma off; ++ ++ if (!mode_64bit) ++ { ++ OP_OFF (bytemode, sizeflag); ++ return; ++ } ++ ++ append_seg (); ++ ++ off = get64 (); ++ ++ if (intel_syntax) ++ { ++ if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS))) ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ } ++ print_operand_value (scratchbuf, 1, off); ++ oappend (scratchbuf); ++} ++ ++static void ++ptr_reg (int code, int sizeflag) ++{ ++ const char *s; ++ ++ *obufp++ = open_char; ++ used_prefixes |= (prefixes & PREFIX_ADDR); ++ if (mode_64bit) ++ { ++ if (!(sizeflag & AFLAG)) ++ s = names32[code - eAX_reg]; ++ else ++ s = names64[code - eAX_reg]; ++ } ++ else if (sizeflag & AFLAG) ++ s = names32[code - eAX_reg]; ++ else ++ s = names16[code - eAX_reg]; ++ oappend (s); ++ *obufp++ = close_char; ++ *obufp = 0; ++} ++ ++static void ++OP_ESreg (int code, int sizeflag) ++{ ++ if (intel_syntax) ++ { ++ if (codep[-1] & 1) ++ { ++ USED_REX (REX_MODE64); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (rex & REX_MODE64) ++ oappend ("QWORD PTR "); ++ else if ((sizeflag & DFLAG)) ++ oappend ("DWORD PTR "); ++ else ++ oappend ("WORD PTR "); ++ } ++ else ++ oappend ("BYTE PTR "); ++ } ++ ++ oappend ("%es:" + intel_syntax); ++ ptr_reg (code, sizeflag); ++} ++ ++static void ++OP_DSreg (int code, int sizeflag) ++{ ++ if (intel_syntax) ++ { ++ if (codep[-1] != 0xd7 && (codep[-1] & 1)) ++ { ++ USED_REX (REX_MODE64); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (rex & REX_MODE64) ++ oappend ("QWORD PTR "); ++ else if ((sizeflag & DFLAG)) ++ oappend ("DWORD PTR "); ++ else ++ oappend ("WORD PTR "); ++ } ++ else ++ oappend ("BYTE PTR "); ++ } ++ ++ if ((prefixes ++ & (PREFIX_CS ++ | PREFIX_DS ++ | PREFIX_SS ++ | PREFIX_ES ++ | PREFIX_FS ++ | PREFIX_GS)) == 0) ++ prefixes |= PREFIX_DS; ++ append_seg (); ++ ptr_reg (code, sizeflag); ++} ++ ++static void ++OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ int add = 0; ++ if (rex & REX_EXTX) ++ { ++ USED_REX (REX_EXTX); ++ add = 8; ++ } ++ else if (!mode_64bit && (prefixes & PREFIX_LOCK)) ++ { ++ used_prefixes |= PREFIX_LOCK; ++ add = 8; ++ } ++ sprintf (scratchbuf, "%%cr%d", reg + add); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add = 8; ++ if (intel_syntax) ++ sprintf (scratchbuf, "db%d", reg + add); ++ else ++ sprintf (scratchbuf, "%%db%d", reg + add); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ sprintf (scratchbuf, "%%tr%d", reg); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_Rd (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ OP_E (bytemode, sizeflag); ++ else ++ BadOp (); ++} ++ ++static void ++OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ { ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add = 8; ++ sprintf (scratchbuf, "%%xmm%d", reg + add); ++ } ++ else ++ sprintf (scratchbuf, "%%mm%d", reg); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add = 8; ++ sprintf (scratchbuf, "%%xmm%d", reg + add); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_EM (int bytemode, int sizeflag) ++{ ++ if (mod != 3) ++ { ++ if (intel_syntax && bytemode == v_mode) ++ { ++ bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ OP_E (bytemode, sizeflag); ++ return; ++ } ++ ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ { ++ int add = 0; ++ ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add = 8; ++ sprintf (scratchbuf, "%%xmm%d", rm + add); ++ } ++ else ++ sprintf (scratchbuf, "%%mm%d", rm); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_EX (int bytemode, int sizeflag) ++{ ++ int add = 0; ++ if (mod != 3) ++ { ++ if (intel_syntax && bytemode == v_mode) ++ { ++ switch (prefixes & (PREFIX_DATA|PREFIX_REPZ|PREFIX_REPNZ)) ++ { ++ case 0: bytemode = x_mode; break; ++ case PREFIX_REPZ: bytemode = d_mode; used_prefixes |= PREFIX_REPZ; break; ++ case PREFIX_DATA: bytemode = x_mode; used_prefixes |= PREFIX_DATA; break; ++ case PREFIX_REPNZ: bytemode = q_mode; used_prefixes |= PREFIX_REPNZ; break; ++ default: bytemode = 0; break; ++ } ++ } ++ OP_E (bytemode, sizeflag); ++ return; ++ } ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add = 8; ++ ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ sprintf (scratchbuf, "%%xmm%d", rm + add); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_MS (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ OP_EM (bytemode, sizeflag); ++ else ++ BadOp (); ++} ++ ++static void ++OP_XS (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ OP_EX (bytemode, sizeflag); ++ else ++ BadOp (); ++} ++ ++static void ++OP_M (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ BadOp (); /* bad lea,lds,les,lfs,lgs,lss modrm */ ++ else ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++OP_0f07 (int bytemode, int sizeflag) ++{ ++ if (mod != 3 || rm != 0) ++ BadOp (); ++ else ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++OP_0fae (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ { ++ if (reg == 7) ++ strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); ++ ++ if (reg < 5 || rm != 0) ++ { ++ BadOp (); /* bad sfence, mfence, or lfence */ ++ return; ++ } ++ } ++ else if (reg != 7) ++ { ++ BadOp (); /* bad clflush */ ++ return; ++ } ++ ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++NOP_Fixup (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ /* NOP with REPZ prefix is called PAUSE. */ ++ if (prefixes == PREFIX_REPZ) ++ strcpy (obuf, "pause"); ++} ++ ++static const char *const Suffix3DNow[] = { ++/* 00 */ NULL, NULL, NULL, NULL, ++/* 04 */ NULL, NULL, NULL, NULL, ++/* 08 */ NULL, NULL, NULL, NULL, ++/* 0C */ "pi2fw", "pi2fd", NULL, NULL, ++/* 10 */ NULL, NULL, NULL, NULL, ++/* 14 */ NULL, NULL, NULL, NULL, ++/* 18 */ NULL, NULL, NULL, NULL, ++/* 1C */ "pf2iw", "pf2id", NULL, NULL, ++/* 20 */ NULL, NULL, NULL, NULL, ++/* 24 */ NULL, NULL, NULL, NULL, ++/* 28 */ NULL, NULL, NULL, NULL, ++/* 2C */ NULL, NULL, NULL, NULL, ++/* 30 */ NULL, NULL, NULL, NULL, ++/* 34 */ NULL, NULL, NULL, NULL, ++/* 38 */ NULL, NULL, NULL, NULL, ++/* 3C */ NULL, NULL, NULL, NULL, ++/* 40 */ NULL, NULL, NULL, NULL, ++/* 44 */ NULL, NULL, NULL, NULL, ++/* 48 */ NULL, NULL, NULL, NULL, ++/* 4C */ NULL, NULL, NULL, NULL, ++/* 50 */ NULL, NULL, NULL, NULL, ++/* 54 */ NULL, NULL, NULL, NULL, ++/* 58 */ NULL, NULL, NULL, NULL, ++/* 5C */ NULL, NULL, NULL, NULL, ++/* 60 */ NULL, NULL, NULL, NULL, ++/* 64 */ NULL, NULL, NULL, NULL, ++/* 68 */ NULL, NULL, NULL, NULL, ++/* 6C */ NULL, NULL, NULL, NULL, ++/* 70 */ NULL, NULL, NULL, NULL, ++/* 74 */ NULL, NULL, NULL, NULL, ++/* 78 */ NULL, NULL, NULL, NULL, ++/* 7C */ NULL, NULL, NULL, NULL, ++/* 80 */ NULL, NULL, NULL, NULL, ++/* 84 */ NULL, NULL, NULL, NULL, ++/* 88 */ NULL, NULL, "pfnacc", NULL, ++/* 8C */ NULL, NULL, "pfpnacc", NULL, ++/* 90 */ "pfcmpge", NULL, NULL, NULL, ++/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", ++/* 98 */ NULL, NULL, "pfsub", NULL, ++/* 9C */ NULL, NULL, "pfadd", NULL, ++/* A0 */ "pfcmpgt", NULL, NULL, NULL, ++/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", ++/* A8 */ NULL, NULL, "pfsubr", NULL, ++/* AC */ NULL, NULL, "pfacc", NULL, ++/* B0 */ "pfcmpeq", NULL, NULL, NULL, ++/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", ++/* B8 */ NULL, NULL, NULL, "pswapd", ++/* BC */ NULL, NULL, NULL, "pavgusb", ++/* C0 */ NULL, NULL, NULL, NULL, ++/* C4 */ NULL, NULL, NULL, NULL, ++/* C8 */ NULL, NULL, NULL, NULL, ++/* CC */ NULL, NULL, NULL, NULL, ++/* D0 */ NULL, NULL, NULL, NULL, ++/* D4 */ NULL, NULL, NULL, NULL, ++/* D8 */ NULL, NULL, NULL, NULL, ++/* DC */ NULL, NULL, NULL, NULL, ++/* E0 */ NULL, NULL, NULL, NULL, ++/* E4 */ NULL, NULL, NULL, NULL, ++/* E8 */ NULL, NULL, NULL, NULL, ++/* EC */ NULL, NULL, NULL, NULL, ++/* F0 */ NULL, NULL, NULL, NULL, ++/* F4 */ NULL, NULL, NULL, NULL, ++/* F8 */ NULL, NULL, NULL, NULL, ++/* FC */ NULL, NULL, NULL, NULL, ++}; ++ ++static void ++OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ const char *mnemonic; ++ ++ FETCH_DATA (the_info, codep + 1); ++ /* AMD 3DNow! instructions are specified by an opcode suffix in the ++ place where an 8-bit immediate would normally go. ie. the last ++ byte of the instruction. */ ++ obufp = obuf + strlen (obuf); ++ mnemonic = Suffix3DNow[*codep++ & 0xff]; ++ if (mnemonic) ++ oappend (mnemonic); ++ else ++ { ++ /* Since a variable sized modrm/sib chunk is between the start ++ of the opcode (0x0f0f) and the opcode suffix, we need to do ++ all the modrm processing first, and don't know until now that ++ we have a bad opcode. This necessitates some cleaning up. */ ++ op1out[0] = '\0'; ++ op2out[0] = '\0'; ++ BadOp (); ++ } ++} ++ ++static const char *simd_cmp_op[] = { ++ "eq", ++ "lt", ++ "le", ++ "unord", ++ "neq", ++ "nlt", ++ "nle", ++ "ord" ++}; ++ ++static void ++OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ unsigned int cmp_type; ++ ++ FETCH_DATA (the_info, codep + 1); ++ obufp = obuf + strlen (obuf); ++ cmp_type = *codep++ & 0xff; ++ if (cmp_type < 8) ++ { ++ char suffix1 = 'p', suffix2 = 's'; ++ used_prefixes |= (prefixes & PREFIX_REPZ); ++ if (prefixes & PREFIX_REPZ) ++ suffix1 = 's'; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ suffix2 = 'd'; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_REPNZ); ++ if (prefixes & PREFIX_REPNZ) ++ suffix1 = 's', suffix2 = 'd'; ++ } ++ } ++ sprintf (scratchbuf, "cmp%s%c%c", ++ simd_cmp_op[cmp_type], suffix1, suffix2); ++ used_prefixes |= (prefixes & PREFIX_REPZ); ++ oappend (scratchbuf); ++ } ++ else ++ { ++ /* We have a bad extension byte. Clean up. */ ++ op1out[0] = '\0'; ++ op2out[0] = '\0'; ++ BadOp (); ++ } ++} ++ ++static void ++SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ /* Change movlps/movhps to movhlps/movlhps for 2 register operand ++ forms of these instructions. */ ++ if (mod == 3) ++ { ++ char *p = obuf + strlen (obuf); ++ *(p + 1) = '\0'; ++ *p = *(p - 1); ++ *(p - 1) = *(p - 2); ++ *(p - 2) = *(p - 3); ++ *(p - 3) = extrachar; ++ } ++} ++ ++static void ++PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ if (mod == 3 && reg == 1 && rm <= 1) ++ { ++ /* Override "sidt". */ ++ char *p = obuf + strlen (obuf) - 4; ++ ++ /* We might have a suffix when disassembling with -Msuffix. */ ++ if (*p == 'i') ++ --p; ++ ++ if (rm) ++ { ++ /* mwait %eax,%ecx */ ++ strcpy (p, "mwait"); ++ if (!intel_syntax) ++ strcpy (op1out, names32[0]); ++ } ++ else ++ { ++ /* monitor %eax,%ecx,%edx" */ ++ strcpy (p, "monitor"); ++ if (!intel_syntax) ++ { ++ if (!mode_64bit) ++ strcpy (op1out, names32[0]); ++ else if (!(prefixes & PREFIX_ADDR)) ++ strcpy (op1out, names64[0]); ++ else ++ { ++ strcpy (op1out, names32[0]); ++ used_prefixes |= PREFIX_ADDR; ++ } ++ strcpy (op3out, names32[2]); ++ } ++ } ++ if (!intel_syntax) ++ { ++ strcpy (op2out, names32[1]); ++ two_source_ops = 1; ++ } ++ ++ codep++; ++ } ++ else ++ OP_M (0, sizeflag); ++} ++ ++static void ++SVME_Fixup (int bytemode, int sizeflag) ++{ ++ const char *alt; ++ char *p; ++ ++ switch (*codep) ++ { ++ case 0xd8: ++ alt = "vmrun"; ++ break; ++ case 0xd9: ++ alt = "vmmcall"; ++ break; ++ case 0xda: ++ alt = "vmload"; ++ break; ++ case 0xdb: ++ alt = "vmsave"; ++ break; ++ case 0xdc: ++ alt = "stgi"; ++ break; ++ case 0xdd: ++ alt = "clgi"; ++ break; ++ case 0xde: ++ alt = "skinit"; ++ break; ++ case 0xdf: ++ alt = "invlpga"; ++ break; ++ default: ++ OP_M (bytemode, sizeflag); ++ return; ++ } ++ /* Override "lidt". */ ++ p = obuf + strlen (obuf) - 4; ++ /* We might have a suffix. */ ++ if (*p == 'i') ++ --p; ++ strcpy (p, alt); ++ if (!(prefixes & PREFIX_ADDR)) ++ { ++ ++codep; ++ return; ++ } ++ used_prefixes |= PREFIX_ADDR; ++ switch (*codep++) ++ { ++ case 0xdf: ++ strcpy (op2out, names32[1]); ++ two_source_ops = 1; ++ /* Fall through. */ ++ case 0xd8: ++ case 0xda: ++ case 0xdb: ++ *obufp++ = open_char; ++ if (mode_64bit || (sizeflag & AFLAG)) ++ alt = names32[0]; ++ else ++ alt = names16[0]; ++ strcpy (obufp, alt); ++ obufp += strlen (alt); ++ *obufp++ = close_char; ++ *obufp = '\0'; ++ break; ++ } ++} ++ ++static void ++INVLPG_Fixup (int bytemode, int sizeflag) ++{ ++ const char *alt; ++ ++ switch (*codep) ++ { ++ case 0xf8: ++ alt = "swapgs"; ++ break; ++ case 0xf9: ++ alt = "rdtscp"; ++ break; ++ default: ++ OP_M (bytemode, sizeflag); ++ return; ++ } ++ /* Override "invlpg". */ ++ strcpy (obuf + strlen (obuf) - 6, alt); ++ codep++; ++} ++ ++static void ++BadOp (void) ++{ ++ /* Throw away prefixes and 1st. opcode byte. */ ++ codep = insn_codep + 1; ++ oappend ("(bad)"); ++} ++ ++static void ++SEG_Fixup (int extrachar, int sizeflag) ++{ ++ if (mod == 3) ++ { ++ /* We need to add a proper suffix with ++ ++ movw %ds,%ax ++ movl %ds,%eax ++ movq %ds,%rax ++ movw %ax,%ds ++ movl %eax,%ds ++ movq %rax,%ds ++ */ ++ const char *suffix; ++ ++ if (prefixes & PREFIX_DATA) ++ suffix = "w"; ++ else ++ { ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ suffix = "q"; ++ else ++ suffix = "l"; ++ } ++ strcat (obuf, suffix); ++ } ++ else ++ { ++ /* We need to fix the suffix for ++ ++ movw %ds,(%eax) ++ movw %ds,(%rax) ++ movw (%eax),%ds ++ movw (%rax),%ds ++ ++ Override "mov[l|q]". */ ++ char *p = obuf + strlen (obuf) - 1; ++ ++ /* We might not have a suffix. */ ++ if (*p == 'v') ++ ++p; ++ *p = 'w'; ++ } ++ ++ OP_E (extrachar, sizeflag); ++} ++ ++static void ++VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ if (mod == 3 && reg == 0 && rm >=1 && rm <= 4) ++ { ++ /* Override "sgdt". */ ++ char *p = obuf + strlen (obuf) - 4; ++ ++ /* We might have a suffix when disassembling with -Msuffix. */ ++ if (*p == 'g') ++ --p; ++ ++ switch (rm) ++ { ++ case 1: ++ strcpy (p, "vmcall"); ++ break; ++ case 2: ++ strcpy (p, "vmlaunch"); ++ break; ++ case 3: ++ strcpy (p, "vmresume"); ++ break; ++ case 4: ++ strcpy (p, "vmxoff"); ++ break; ++ } ++ ++ codep++; ++ } ++ else ++ OP_E (0, sizeflag); ++} ++ ++static void ++OP_VMX (int bytemode, int sizeflag) ++{ ++ used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ)); ++ if (prefixes & PREFIX_DATA) ++ strcpy (obuf, "vmclear"); ++ else if (prefixes & PREFIX_REPZ) ++ strcpy (obuf, "vmxon"); ++ else ++ strcpy (obuf, "vmptrld"); ++ OP_E (bytemode, sizeflag); ++} +--- /dev/null ++++ b/arch/x86/kdb/kdba_bp_32.c +@@ -0,0 +1,914 @@ ++/* ++ * Kernel Debugger Architecture Dependent Breakpoint Handling ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write", ++ "I/O", "Data Access"}; ++ ++/* ++ * Table describing processor architecture hardware ++ * breakpoint registers for every CPU. ++ */ ++ ++static kdbhard_bp_t kdb_hardbreaks[NR_CPUS][KDB_MAXHARDBPT]; ++ ++/* ++ * kdba_db_trap ++ * ++ * Perform breakpoint processing upon entry to the ++ * processor debugger fault. Determine and print ++ * the active breakpoint. ++ * ++ * Parameters: ++ * regs Exception frame containing machine register state ++ * error Error number passed to kdb. ++ * Outputs: ++ * None. ++ * Returns: ++ * KDB_DB_BPT Standard instruction or data breakpoint encountered ++ * KDB_DB_SS Single Step fault ('ss' command or end of 'ssb' command) ++ * KDB_DB_SSB Single Step fault, caller should continue ('ssb' command) ++ * KDB_DB_SSBPT Single step over breakpoint ++ * KDB_DB_NOBPT No existing kdb breakpoint matches this debug exception ++ * Locking: ++ * None. ++ * Remarks: ++ * Yup, there be goto's here. ++ * ++ * If multiple processors receive debug exceptions simultaneously, ++ * one may be waiting at the kdb fence in kdb() while the user ++ * issues a 'bc' command to clear the breakpoint the processor ++ * which is waiting has already encountered. If this is the case, ++ * the debug registers will no longer match any entry in the ++ * breakpoint table, and we'll return the value KDB_DB_NOBPT. ++ * This can cause a panic in die_if_kernel(). It is safer to ++ * disable the breakpoint (bd), go until all processors are past ++ * the breakpoint then clear the breakpoint (bc). This code ++ * recognises a breakpoint even when disabled but not when it has ++ * been cleared. ++ * ++ * WARNING: This routine clears the debug state. It should be called ++ * once per debug and the result cached. ++ */ ++ ++kdb_dbtrap_t ++kdba_db_trap(struct pt_regs *regs, int error_unused) ++{ ++ kdb_machreg_t dr6; ++ kdb_machreg_t dr7; ++ int rw, reg; ++ int i; ++ kdb_dbtrap_t rv = KDB_DB_BPT; ++ kdb_bp_t *bp; ++ int cpu = smp_processor_id(); ++ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_DB_NOBPT; ++ ++ dr6 = kdba_getdr6(); ++ dr7 = kdba_getdr7(); ++ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdb: dr6 0x%lx dr7 0x%lx\n", dr6, dr7); ++ if (dr6 & DR6_BS) { ++ if (KDB_STATE(SSBPT)) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("ssbpt\n"); ++ KDB_STATE_CLEAR(SSBPT); ++ for(i=0,bp=kdb_breakpoints; ++ i < KDB_MAXBPT; ++ i++, bp++) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", ++ bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); ++ if (!bp->bp_enabled) ++ continue; ++ if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) ++ continue; ++ if (KDB_DEBUG(BP)) ++ kdb_printf("bp for this cpu\n"); ++ if (bp->bp_delayed) { ++ bp->bp_delayed = 0; ++ if (KDB_DEBUG(BP)){ ++ /* Can't be hw breakpoint */ ++ if (bp->bp_hardtype) ++ kdb_printf("kdb: Error - hw bp delayed\n"); ++ kdb_printf("kdba_installbp\n"); ++ } ++ kdba_installbp(regs, bp); ++ if (!KDB_STATE(DOING_SS)) { ++ regs->flags &= ~EF_TF; ++ return(KDB_DB_SSBPT); ++ } ++ break; ++ } ++ } ++ if (i == KDB_MAXBPT) { ++ kdb_printf("kdb: Unable to find delayed breakpoint\n"); ++ } ++ if (!KDB_STATE(DOING_SS)) { ++ regs->flags &= ~EF_TF; ++ return(KDB_DB_NOBPT); ++ } ++ /* FALLTHROUGH */ ++ } ++ ++ /* ++ * KDB_STATE_DOING_SS is set when the kernel debugger is using ++ * the processor trap flag to single-step a processor. If a ++ * single step trap occurs and this flag is clear, the SS trap ++ * will be ignored by KDB and the kernel will be allowed to deal ++ * with it as necessary (e.g. for ptrace). ++ */ ++ if (!KDB_STATE(DOING_SS)) ++ goto unknown; ++ ++ /* single step */ ++ rv = KDB_DB_SS; /* Indicate single step */ ++ if (KDB_STATE(DOING_SSB)) { ++ unsigned char instruction[2]; ++ ++ kdb_id1(regs->ip); ++ if (kdb_getarea(instruction, regs->ip) || ++ (instruction[0]&0xf0) == 0xe0 || /* short disp jumps */ ++ (instruction[0]&0xf0) == 0x70 || /* Misc. jumps */ ++ instruction[0] == 0xc2 || /* ret */ ++ instruction[0] == 0x9a || /* call */ ++ (instruction[0]&0xf8) == 0xc8 || /* enter, leave, iret, int, */ ++ ((instruction[0] == 0x0f) && ++ ((instruction[1]&0xf0)== 0x80)) ++ ) { ++ /* ++ * End the ssb command here. ++ */ ++ KDB_STATE_CLEAR(DOING_SSB); ++ KDB_STATE_CLEAR(DOING_SS); ++ } else { ++ rv = KDB_DB_SSB; /* Indicate ssb - dismiss immediately */ ++ } ++ } else { ++ /* ++ * Print current insn ++ */ ++ kdb_printf("SS trap at "); ++ kdb_symbol_print(regs->ip, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); ++ kdb_id1(regs->ip); ++ KDB_STATE_CLEAR(DOING_SS); ++ } ++ ++ if (rv != KDB_DB_SSB) ++ regs->flags &= ~EF_TF; ++ } ++ ++ if (dr6 & DR6_B0) { ++ rw = DR7_RW0(dr7); ++ reg = 0; ++ goto handle; ++ } ++ ++ if (dr6 & DR6_B1) { ++ rw = DR7_RW1(dr7); ++ reg = 1; ++ goto handle; ++ } ++ ++ if (dr6 & DR6_B2) { ++ rw = DR7_RW2(dr7); ++ reg = 2; ++ goto handle; ++ } ++ ++ if (dr6 & DR6_B3) { ++ rw = DR7_RW3(dr7); ++ reg = 3; ++ goto handle; ++ } ++ ++ if (rv > 0) ++ goto handled; ++ ++ goto unknown; /* dismiss */ ++ ++handle: ++ /* ++ * Set Resume Flag ++ */ ++ regs->flags |= EF_RF; ++ ++ /* ++ * Determine which breakpoint was encountered. ++ */ ++ for(i=0, bp=kdb_breakpoints; ibp_free) ++ && (bp->bp_global || bp->bp_cpu == smp_processor_id()) ++ && (bp->bp_hard[cpu]) ++ && (bp->bp_hard[cpu]->bph_reg == reg)) { ++ /* ++ * Hit this breakpoint. ++ */ ++ kdb_printf("%s breakpoint #%d at " kdb_bfd_vma_fmt "\n", ++ kdba_rwtypes[rw], ++ i, bp->bp_addr); ++ ++ /* ++ * For an instruction breakpoint, disassemble ++ * the current instruction. ++ */ ++ if (rw == 0) { ++ kdb_id1(regs->ip); ++ } ++ ++ goto handled; ++ } ++ } ++ ++unknown: ++ regs->flags |= EF_RF; /* Supress further faults */ ++ rv = KDB_DB_NOBPT; /* Cause kdb() to return */ ++ ++handled: ++ ++ /* ++ * Clear the pending exceptions. ++ */ ++ kdba_putdr6(0); ++ ++ return rv; ++} ++ ++/* ++ * kdba_bp_trap ++ * ++ * Perform breakpoint processing upon entry to the ++ * processor breakpoint instruction fault. Determine and print ++ * the active breakpoint. ++ * ++ * Parameters: ++ * regs Exception frame containing machine register state ++ * error Error number passed to kdb. ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 Standard instruction or data breakpoint encountered ++ * 1 Single Step fault ('ss' command) ++ * 2 Single Step fault, caller should continue ('ssb' command) ++ * 3 No existing kdb breakpoint matches this debug exception ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * If multiple processors receive debug exceptions simultaneously, ++ * one may be waiting at the kdb fence in kdb() while the user ++ * issues a 'bc' command to clear the breakpoint the processor which ++ * is waiting has already encountered. If this is the case, the ++ * debug registers will no longer match any entry in the breakpoint ++ * table, and we'll return the value '3'. This can cause a panic ++ * in die_if_kernel(). It is safer to disable the breakpoint (bd), ++ * 'go' until all processors are past the breakpoint then clear the ++ * breakpoint (bc). This code recognises a breakpoint even when ++ * disabled but not when it has been cleared. ++ * ++ * WARNING: This routine resets the ip. It should be called ++ * once per breakpoint and the result cached. ++ */ ++ ++kdb_dbtrap_t ++kdba_bp_trap(struct pt_regs *regs, int error_unused) ++{ ++ int i; ++ kdb_dbtrap_t rv; ++ kdb_bp_t *bp; ++ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_DB_NOBPT; ++ ++ /* ++ * Determine which breakpoint was encountered. ++ */ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_bp_trap: ip=0x%lx (not adjusted) " ++ "flags=0x%lx regs=0x%p sp=0x%lx\n", ++ regs->ip, regs->flags, regs, regs->sp); ++ ++ rv = KDB_DB_NOBPT; /* Cause kdb() to return */ ++ ++ for(i=0, bp=kdb_breakpoints; ibp_free) ++ continue; ++ if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) ++ continue; ++ if ((void *)bp->bp_addr == (void *)(regs->ip - bp->bp_adjust)) { ++ /* Hit this breakpoint. */ ++ regs->ip -= bp->bp_adjust; ++ kdb_printf("Instruction(i) breakpoint #%d at 0x%lx (adjusted)\n", ++ i, regs->ip); ++ kdb_id1(regs->ip); ++ rv = KDB_DB_BPT; ++ bp->bp_delay = 1; ++ /* SSBPT is set when the kernel debugger must single ++ * step a task in order to re-establish an instruction ++ * breakpoint which uses the instruction replacement ++ * mechanism. It is cleared by any action that removes ++ * the need to single-step the breakpoint. ++ */ ++ KDB_STATE_SET(SSBPT); ++ break; ++ } ++ } ++ ++ return rv; ++} ++ ++/* ++ * kdba_handle_bp ++ * ++ * Handle an instruction-breakpoint trap. Called when re-installing ++ * an enabled breakpoint which has has the bp_delay bit set. ++ * ++ * Parameters: ++ * Returns: ++ * Locking: ++ * Remarks: ++ * ++ * Ok, we really need to: ++ * 1) Restore the original instruction byte ++ * 2) Single Step ++ * 3) Restore breakpoint instruction ++ * 4) Continue. ++ * ++ * ++ */ ++ ++static void ++kdba_handle_bp(struct pt_regs *regs, kdb_bp_t *bp) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("regs->ip = 0x%lx\n", regs->ip); ++ ++ /* ++ * Setup single step ++ */ ++ kdba_setsinglestep(regs); ++ ++ /* ++ * Reset delay attribute ++ */ ++ bp->bp_delay = 0; ++ bp->bp_delayed = 1; ++} ++ ++ ++/* ++ * kdba_bptype ++ * ++ * Return a string describing type of breakpoint. ++ * ++ * Parameters: ++ * bph Pointer to hardware breakpoint description ++ * Outputs: ++ * None. ++ * Returns: ++ * Character string. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++char * ++kdba_bptype(kdbhard_bp_t *bph) ++{ ++ char *mode; ++ ++ mode = kdba_rwtypes[bph->bph_mode]; ++ ++ return mode; ++} ++ ++/* ++ * kdba_printbpreg ++ * ++ * Print register name assigned to breakpoint ++ * ++ * Parameters: ++ * bph Pointer hardware breakpoint structure ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdba_printbpreg(kdbhard_bp_t *bph) ++{ ++ kdb_printf(" in dr%ld", bph->bph_reg); ++} ++ ++/* ++ * kdba_printbp ++ * ++ * Print string describing hardware breakpoint. ++ * ++ * Parameters: ++ * bph Pointer to hardware breakpoint description ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdba_printbp(kdb_bp_t *bp) ++{ ++ int cpu; ++ ++ kdb_printf("\n is enabled"); ++ if (bp->bp_hardtype) { ++ if (bp->bp_global) ++ cpu = smp_processor_id(); ++ else ++ cpu = bp->bp_cpu; ++ kdba_printbpreg(bp->bp_hard[cpu]); ++ if (bp->bp_hard[cpu]->bph_mode != 0) { ++ kdb_printf(" for %d bytes", ++ bp->bp_hard[cpu]->bph_length+1); ++ } ++ } ++} ++ ++/* ++ * kdba_parsebp ++ * ++ * Parse architecture dependent portion of the ++ * breakpoint command. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ * for Ia32 architure, data access, data write and ++ * I/O breakpoints are supported in addition to instruction ++ * breakpoints. ++ * ++ * {datar|dataw|io|inst} [length] ++ */ ++ ++int ++kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp) ++{ ++ int nextarg = *nextargp; ++ int diag; ++ kdbhard_bp_t *bph = &bp->bp_template; ++ ++ bph->bph_mode = 0; /* Default to instruction breakpoint */ ++ bph->bph_length = 0; /* Length must be zero for insn bp */ ++ if ((argc + 1) != nextarg) { ++ if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { ++ bph->bph_mode = 3; ++ } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { ++ bph->bph_mode = 1; ++ } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { ++ bph->bph_mode = 2; ++ } else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) { ++ bph->bph_mode = 0; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ bph->bph_length = 3; /* Default to 4 byte */ ++ ++ nextarg++; ++ ++ if ((argc + 1) != nextarg) { ++ unsigned long len; ++ ++ diag = kdbgetularg((char *)argv[nextarg], ++ &len); ++ if (diag) ++ return diag; ++ ++ ++ if ((len > 4) || (len == 3)) ++ return KDB_BADLENGTH; ++ ++ bph->bph_length = len; ++ bph->bph_length--; /* Normalize for debug register */ ++ nextarg++; ++ } ++ ++ if ((argc + 1) != nextarg) ++ return KDB_ARGCOUNT; ++ ++ /* ++ * Indicate to architecture independent level that ++ * a hardware register assignment is required to enable ++ * this breakpoint. ++ */ ++ ++ bph->bph_free = 0; ++ } else { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw); ++ if (bp->bp_forcehw) { ++ /* ++ * We are forced to use a hardware register for this ++ * breakpoint because either the bph or bpha ++ * commands were used to establish this breakpoint. ++ */ ++ bph->bph_free = 0; ++ } else { ++ /* ++ * Indicate to architecture dependent level that ++ * the instruction replacement breakpoint technique ++ * should be used for this breakpoint. ++ */ ++ bph->bph_free = 1; ++ bp->bp_adjust = 1; /* software, int 3 is one byte */ ++ } ++ } ++ ++ if (bph->bph_mode != 2 && kdba_verify_rw(bp->bp_addr, bph->bph_length+1)) { ++ kdb_printf("Invalid address for breakpoint, ignoring bp command\n"); ++ return KDB_BADADDR; ++ } ++ ++ *nextargp = nextarg; ++ return 0; ++} ++ ++/* ++ * kdba_allocbp ++ * ++ * Allocate hw register for bp on specific CPU ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * A pointer to the allocated register kdbhard_bp_t structure for ++ * success, Null and a non-zero diagnostic for failure. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static kdbhard_bp_t * ++kdba_allocbp(kdbhard_bp_t *bph, int *diagp, unsigned int cpu) ++{ ++ int i; ++ kdbhard_bp_t *newbph; ++ ++ for(i=0; i < KDB_MAXHARDBPT; i++) { ++ newbph=&(kdb_hardbreaks[cpu][i]); ++ if (newbph->bph_free) { ++ break; ++ } ++ } ++ ++ if (i == KDB_MAXHARDBPT) { ++ *diagp = KDB_TOOMANYDBREGS; ++ return NULL; ++ } ++ ++ *diagp = 0; ++ ++ /* ++ * Copy data from template. Can't just copy the entire template ++ * here because the register number in kdb_hardbreaks must be ++ * preserved. ++ */ ++ newbph->bph_data = bph->bph_data; ++ newbph->bph_write = bph->bph_write; ++ newbph->bph_mode = bph->bph_mode; ++ newbph->bph_length = bph->bph_length; ++ ++ /* ++ * Mark entry allocated. ++ */ ++ newbph->bph_free = 0; ++ ++ return newbph; ++} ++ ++/* ++ * kdba_alloc_hwbp ++ * ++ * Associate a hardware registers with a breakpoint. ++ * If hw bp is global hw registers descriptor will be allocated ++ * on every CPU. ++ * ++ * Parameters: ++ * bp - hardware bp ++ * diagp - pointer to variable that will store error when ++ * function complete ++ * Outputs: ++ * None. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Should be called with correct bp->bp_template ++ */ ++ ++void ++kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp) ++{ ++ int i; ++ ++ if (bp->bp_global){ ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ bp->bp_hard[i] = kdba_allocbp(&bp->bp_template, diagp, i); ++ if (*diagp) ++ break; ++ } ++ } else { ++ bp->bp_hard[bp->bp_cpu] = kdba_allocbp(&bp->bp_template, diagp, bp->bp_cpu); ++ } ++ bp->bp_hardtype = 1; ++} ++ ++/* ++ * kdba_freebp ++ * ++ * Deallocate hw registers descriptor for bp on specific CPU ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdba_freebp(kdbhard_bp_t *bph) ++{ ++ bph->bph_free = 1; ++} ++ ++/* ++ * kdba_free_hwbp ++ * ++ * Frees allocated hw registers descriptors for bp. ++ * If hw bp is global, hw registers descriptors will be freed ++ * on every CPU. ++ * ++ * Parameters: ++ * bp - hardware bp ++ * Outputs: ++ * None. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Should be called with correct bp->bp_template ++ */ ++ ++void ++kdba_free_hwbp(kdb_bp_t *bp) ++{ ++ int i; ++ ++ /* When kernel enters KDB, first, all local bps ++ * are removed, so here we don't need to clear ++ * debug registers. ++ */ ++ ++ if (bp->bp_global){ ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ if (bp->bp_hard[i]) ++ kdba_freebp(bp->bp_hard[i]); ++ bp->bp_hard[i] = 0; ++ } ++ } else { ++ kdba_freebp(bp->bp_hard[bp->bp_cpu]); ++ bp->bp_hard[bp->bp_cpu] = NULL; ++ } ++ bp->bp_hardtype = 0; ++} ++ ++/* ++ * kdba_initbp ++ * ++ * Initialize the breakpoint table for the hardware breakpoint ++ * register. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * There is one entry per register. On the ia32 architecture ++ * all the registers are interchangeable, so no special allocation ++ * criteria are required. ++ */ ++ ++void ++kdba_initbp(void) ++{ ++ int i,j; ++ kdbhard_bp_t *bph; ++ ++ /* ++ * Clear the hardware breakpoint table ++ */ ++ ++ memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks)); ++ ++ for (i = 0; i < NR_CPUS; ++i) { ++ /* Called early so we don't know actual ++ * ammount of CPUs ++ */ ++ for(j=0; j < KDB_MAXHARDBPT; j++) { ++ bph=&(kdb_hardbreaks[i][j]); ++ bph->bph_reg = j; ++ bph->bph_free = 1; ++ } ++ } ++} ++ ++/* ++ * kdba_installbp ++ * ++ * Install a breakpoint ++ * ++ * Parameters: ++ * regs Exception frame ++ * bp Breakpoint structure for the breakpoint to be installed ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 if breakpoint installed. ++ * Locking: ++ * None. ++ * Remarks: ++ * For hardware breakpoints, a debug register is allocated ++ * and assigned to the breakpoint. If no debug register is ++ * available, a warning message is printed and the breakpoint ++ * is disabled. ++ * ++ * For instruction replacement breakpoints, we must single-step ++ * over the replaced instruction at this point so we can re-install ++ * the breakpoint instruction after the single-step. SSBPT is set ++ * when the breakpoint is initially hit and is cleared by any action ++ * that removes the need for single-step over the breakpoint. ++ */ ++ ++int ++kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp) ++{ ++ int cpu = smp_processor_id(); ++ ++ /* ++ * Install the breakpoint, if it is not already installed. ++ */ ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed); ++ } ++ if (!KDB_STATE(SSBPT)) ++ bp->bp_delay = 0; ++ ++ if (bp->bp_hardtype) { ++ if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){ ++ kdb_printf("kdba_installbp: cpu != bp->bp_cpu for local hw bp\n"); ++ } ++ ++ if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){ ++ kdb_printf("kdba_installbp: Error - bp_hard[smp_processor_id()] is emply\n"); ++ return 1; ++ } ++ ++ if (!bp->bp_hard[cpu]->bph_installed){ ++ kdba_installdbreg(bp); ++ bp->bp_hard[cpu]->bph_installed = 1; ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n", ++ bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ } ++ } ++ } else if (!bp->bp_installed) { ++ if (bp->bp_delay) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp delayed bp\n"); ++ kdba_handle_bp(regs, bp); ++ } else { ++ if (kdb_getarea_size(&(bp->bp_inst), bp->bp_addr, 1) || ++ kdb_putword(bp->bp_addr, IA32_BREAKPOINT_INSTRUCTION, 1)) { ++ kdb_printf("kdba_installbp failed to set software breakpoint at 0x%lx\n", bp->bp_addr); ++ return(1); ++ } ++ bp->bp_installed = 1; ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp instruction 0x%x at " kdb_bfd_vma_fmt "\n", ++ IA32_BREAKPOINT_INSTRUCTION, bp->bp_addr); ++ } ++ } ++ return(0); ++} ++ ++/* ++ * kdba_removebp ++ * ++ * Make a breakpoint ineffective. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdba_removebp(kdb_bp_t *bp) ++{ ++ int cpu = smp_processor_id(); ++ ++ /* ++ * For hardware breakpoints, remove it from the active register, ++ * for software breakpoints, restore the instruction stream. ++ */ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed); ++ } ++ ++ if (bp->bp_hardtype) { ++ if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){ ++ kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local hw bp\n"); ++ } ++ ++ if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){ ++ kdb_printf("kdba_removebp: Error - bp_hard[smp_processor_id()] is emply\n"); ++ return 1; ++ } ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt "\n", ++ bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ } ++ ++ if (bp->bp_hard[cpu]->bph_installed){ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n", ++ bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ } ++ kdba_removedbreg(bp); ++ bp->bp_hard[cpu]->bph_installed = 0; ++ } ++ } else if (bp->bp_installed) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdb: restoring instruction 0x%x at " kdb_bfd_vma_fmt "\n", ++ bp->bp_inst, bp->bp_addr); ++ if (kdb_putword(bp->bp_addr, bp->bp_inst, 1)) ++ return(1); ++ bp->bp_installed = 0; ++ } ++ return(0); ++} +--- /dev/null ++++ b/arch/x86/kdb/kdba_bp_64.c +@@ -0,0 +1,912 @@ ++/* ++ * Kernel Debugger Architecture Dependent Breakpoint Handling ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write", ++ "I/O", "Data Access"}; ++ ++/* ++ * Table describing processor architecture hardware ++ * breakpoint registers for every CPU. ++ */ ++ ++static kdbhard_bp_t kdb_hardbreaks[NR_CPUS][KDB_MAXHARDBPT]; ++ ++/* ++ * kdba_db_trap ++ * ++ * Perform breakpoint processing upon entry to the ++ * processor debugger fault. Determine and print ++ * the active breakpoint. ++ * ++ * Parameters: ++ * regs Exception frame containing machine register state ++ * error Error number passed to kdb. ++ * Outputs: ++ * None. ++ * Returns: ++ * KDB_DB_BPT Standard instruction or data breakpoint encountered ++ * KDB_DB_SS Single Step fault ('ss' command or end of 'ssb' command) ++ * KDB_DB_SSB Single Step fault, caller should continue ('ssb' command) ++ * KDB_DB_SSBPT Single step over breakpoint ++ * KDB_DB_NOBPT No existing kdb breakpoint matches this debug exception ++ * Locking: ++ * None. ++ * Remarks: ++ * Yup, there be goto's here. ++ * ++ * If multiple processors receive debug exceptions simultaneously, ++ * one may be waiting at the kdb fence in kdb() while the user ++ * issues a 'bc' command to clear the breakpoint the processor ++ * which is waiting has already encountered. If this is the case, ++ * the debug registers will no longer match any entry in the ++ * breakpoint table, and we'll return the value KDB_DB_NOBPT. ++ * This can cause a panic in die_if_kernel(). It is safer to ++ * disable the breakpoint (bd), go until all processors are past ++ * the breakpoint then clear the breakpoint (bc). This code ++ * recognises a breakpoint even when disabled but not when it has ++ * been cleared. ++ * ++ * WARNING: This routine clears the debug state. It should be called ++ * once per debug and the result cached. ++ */ ++ ++kdb_dbtrap_t ++kdba_db_trap(struct pt_regs *regs, int error_unused) ++{ ++ kdb_machreg_t dr6; ++ kdb_machreg_t dr7; ++ int rw, reg; ++ int i; ++ kdb_dbtrap_t rv = KDB_DB_BPT; ++ kdb_bp_t *bp; ++ int cpu = smp_processor_id(); ++ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_DB_NOBPT; ++ ++ dr6 = kdba_getdr6(); ++ dr7 = kdba_getdr7(); ++ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdb: dr6 0x%lx dr7 0x%lx\n", dr6, dr7); ++ if (dr6 & DR6_BS) { ++ if (KDB_STATE(SSBPT)) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("ssbpt\n"); ++ KDB_STATE_CLEAR(SSBPT); ++ for(i=0,bp=kdb_breakpoints; ++ i < KDB_MAXBPT; ++ i++, bp++) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", ++ bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); ++ if (!bp->bp_enabled) ++ continue; ++ if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) ++ continue; ++ if (KDB_DEBUG(BP)) ++ kdb_printf("bp for this cpu\n"); ++ if (bp->bp_delayed) { ++ bp->bp_delayed = 0; ++ if (KDB_DEBUG(BP)){ ++ /* Can't be hw breakpoint */ ++ if (bp->bp_hardtype) ++ kdb_printf("kdb: Error - hw bp delayed\n"); ++ kdb_printf("kdba_installbp\n"); ++ } ++ kdba_installbp(regs, bp); ++ if (!KDB_STATE(DOING_SS)) { ++ regs->flags &= ~X86_EFLAGS_TF; ++ return(KDB_DB_SSBPT); ++ } ++ break; ++ } ++ } ++ if (i == KDB_MAXBPT) { ++ kdb_printf("kdb: Unable to find delayed breakpoint\n"); ++ } ++ if (!KDB_STATE(DOING_SS)) { ++ regs->flags &= ~X86_EFLAGS_TF; ++ return(KDB_DB_NOBPT); ++ } ++ /* FALLTHROUGH */ ++ } ++ ++ /* ++ * KDB_STATE_DOING_SS is set when the kernel debugger is using ++ * the processor trap flag to single-step a processor. If a ++ * single step trap occurs and this flag is clear, the SS trap ++ * will be ignored by KDB and the kernel will be allowed to deal ++ * with it as necessary (e.g. for ptrace). ++ */ ++ if (!KDB_STATE(DOING_SS)) ++ goto unknown; ++ ++ /* single step */ ++ rv = KDB_DB_SS; /* Indicate single step */ ++ if (KDB_STATE(DOING_SSB)) { ++ unsigned char instruction[2]; ++ ++ kdb_id1(regs->ip); ++ if (kdb_getarea(instruction, regs->ip) || ++ (instruction[0]&0xf0) == 0xe0 || /* short disp jumps */ ++ (instruction[0]&0xf0) == 0x70 || /* Misc. jumps */ ++ instruction[0] == 0xc2 || /* ret */ ++ instruction[0] == 0x9a || /* call */ ++ (instruction[0]&0xf8) == 0xc8 || /* enter, leave, iret, int, */ ++ ((instruction[0] == 0x0f) && ++ ((instruction[1]&0xf0)== 0x80)) ++ ) { ++ /* ++ * End the ssb command here. ++ */ ++ KDB_STATE_CLEAR(DOING_SSB); ++ KDB_STATE_CLEAR(DOING_SS); ++ } else { ++ rv = KDB_DB_SSB; /* Indicate ssb - dismiss immediately */ ++ } ++ } else { ++ /* ++ * Print current insn ++ */ ++ kdb_printf("SS trap at "); ++ kdb_symbol_print(regs->ip, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); ++ kdb_id1(regs->ip); ++ KDB_STATE_CLEAR(DOING_SS); ++ } ++ ++ if (rv != KDB_DB_SSB) ++ regs->flags &= ~X86_EFLAGS_TF; ++ } ++ ++ if (dr6 & DR6_B0) { ++ rw = DR7_RW0(dr7); ++ reg = 0; ++ goto handle; ++ } ++ ++ if (dr6 & DR6_B1) { ++ rw = DR7_RW1(dr7); ++ reg = 1; ++ goto handle; ++ } ++ ++ if (dr6 & DR6_B2) { ++ rw = DR7_RW2(dr7); ++ reg = 2; ++ goto handle; ++ } ++ ++ if (dr6 & DR6_B3) { ++ rw = DR7_RW3(dr7); ++ reg = 3; ++ goto handle; ++ } ++ ++ if (rv > 0) ++ goto handled; ++ ++ goto unknown; /* dismiss */ ++ ++handle: ++ /* ++ * Set Resume Flag ++ */ ++ regs->flags |= X86_EFLAGS_RF; ++ ++ /* ++ * Determine which breakpoint was encountered. ++ */ ++ for(i=0, bp=kdb_breakpoints; ibp_free) ++ && (bp->bp_global || bp->bp_cpu == smp_processor_id()) ++ && (bp->bp_hard[cpu]) ++ && (bp->bp_hard[cpu]->bph_reg == reg)) { ++ /* ++ * Hit this breakpoint. ++ */ ++ kdb_printf("%s breakpoint #%d at " kdb_bfd_vma_fmt "\n", ++ kdba_rwtypes[rw], ++ i, bp->bp_addr); ++ ++ /* ++ * For an instruction breakpoint, disassemble ++ * the current instruction. ++ */ ++ if (rw == 0) { ++ kdb_id1(regs->ip); ++ } ++ ++ goto handled; ++ } ++ } ++ ++unknown: ++ regs->flags |= X86_EFLAGS_RF; /* Supress further faults */ ++ rv = KDB_DB_NOBPT; /* Cause kdb() to return */ ++ ++handled: ++ ++ /* ++ * Clear the pending exceptions. ++ */ ++ kdba_putdr6(0); ++ ++ return rv; ++} ++ ++/* ++ * kdba_bp_trap ++ * ++ * Perform breakpoint processing upon entry to the ++ * processor breakpoint instruction fault. Determine and print ++ * the active breakpoint. ++ * ++ * Parameters: ++ * regs Exception frame containing machine register state ++ * error Error number passed to kdb. ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 Standard instruction or data breakpoint encountered ++ * 1 Single Step fault ('ss' command) ++ * 2 Single Step fault, caller should continue ('ssb' command) ++ * 3 No existing kdb breakpoint matches this debug exception ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * If multiple processors receive debug exceptions simultaneously, ++ * one may be waiting at the kdb fence in kdb() while the user ++ * issues a 'bc' command to clear the breakpoint the processor which ++ * is waiting has already encountered. If this is the case, the ++ * debug registers will no longer match any entry in the breakpoint ++ * table, and we'll return the value '3'. This can cause a panic ++ * in die_if_kernel(). It is safer to disable the breakpoint (bd), ++ * 'go' until all processors are past the breakpoint then clear the ++ * breakpoint (bc). This code recognises a breakpoint even when ++ * disabled but not when it has been cleared. ++ * ++ * WARNING: This routine resets the ip. It should be called ++ * once per breakpoint and the result cached. ++ */ ++ ++kdb_dbtrap_t ++kdba_bp_trap(struct pt_regs *regs, int error_unused) ++{ ++ int i; ++ kdb_dbtrap_t rv; ++ kdb_bp_t *bp; ++ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_DB_NOBPT; ++ ++ /* ++ * Determine which breakpoint was encountered. ++ */ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_bp_trap: ip=0x%lx (not adjusted) " ++ "flags=0x%lx ef=0x%p sp=0x%lx\n", ++ regs->ip, regs->flags, regs, regs->sp); ++ ++ rv = KDB_DB_NOBPT; /* Cause kdb() to return */ ++ ++ for(i=0, bp=kdb_breakpoints; ibp_free) ++ continue; ++ if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) ++ continue; ++ if ((void *)bp->bp_addr == (void *)(regs->ip - bp->bp_adjust)) { ++ /* Hit this breakpoint. */ ++ regs->ip -= bp->bp_adjust; ++ kdb_printf("Instruction(i) breakpoint #%d at 0x%lx (adjusted)\n", ++ i, regs->ip); ++ kdb_id1(regs->ip); ++ rv = KDB_DB_BPT; ++ bp->bp_delay = 1; ++ /* SSBPT is set when the kernel debugger must single ++ * step a task in order to re-establish an instruction ++ * breakpoint which uses the instruction replacement ++ * mechanism. It is cleared by any action that removes ++ * the need to single-step the breakpoint. ++ */ ++ KDB_STATE_SET(SSBPT); ++ break; ++ } ++ } ++ ++ return rv; ++} ++ ++/* ++ * kdba_handle_bp ++ * ++ * Handle an instruction-breakpoint trap. Called when re-installing ++ * an enabled breakpoint which has has the bp_delay bit set. ++ * ++ * Parameters: ++ * Returns: ++ * Locking: ++ * Remarks: ++ * ++ * Ok, we really need to: ++ * 1) Restore the original instruction byte ++ * 2) Single Step ++ * 3) Restore breakpoint instruction ++ * 4) Continue. ++ * ++ * ++ */ ++ ++static void ++kdba_handle_bp(struct pt_regs *regs, kdb_bp_t *bp) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ ++ if (KDB_DEBUG(BP)) ++ kdb_printf("regs->ip = 0x%lx\n", regs->ip); ++ ++ /* ++ * Setup single step ++ */ ++ kdba_setsinglestep(regs); ++ ++ /* ++ * Reset delay attribute ++ */ ++ bp->bp_delay = 0; ++ bp->bp_delayed = 1; ++} ++ ++ ++/* ++ * kdba_bptype ++ * ++ * Return a string describing type of breakpoint. ++ * ++ * Parameters: ++ * bph Pointer to hardware breakpoint description ++ * Outputs: ++ * None. ++ * Returns: ++ * Character string. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++char * ++kdba_bptype(kdbhard_bp_t *bph) ++{ ++ char *mode; ++ ++ mode = kdba_rwtypes[bph->bph_mode]; ++ ++ return mode; ++} ++ ++/* ++ * kdba_printbpreg ++ * ++ * Print register name assigned to breakpoint ++ * ++ * Parameters: ++ * bph Pointer hardware breakpoint structure ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdba_printbpreg(kdbhard_bp_t *bph) ++{ ++ kdb_printf(" in dr%ld", bph->bph_reg); ++} ++ ++/* ++ * kdba_printbp ++ * ++ * Print string describing hardware breakpoint. ++ * ++ * Parameters: ++ * bph Pointer to hardware breakpoint description ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdba_printbp(kdb_bp_t *bp) ++{ ++ int cpu; ++ ++ kdb_printf("\n is enabled"); ++ if (bp->bp_hardtype) { ++ if (bp->bp_global) ++ cpu = smp_processor_id(); ++ else ++ cpu = bp->bp_cpu; ++ kdba_printbpreg(bp->bp_hard[cpu]); ++ if (bp->bp_hard[cpu]->bph_mode != 0) { ++ kdb_printf(" for %d bytes", ++ bp->bp_hard[cpu]->bph_length+1); ++ } ++ } ++} ++ ++/* ++ * kdba_parsebp ++ * ++ * Parse architecture dependent portion of the ++ * breakpoint command. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ * for Ia32 architure, data access, data write and ++ * I/O breakpoints are supported in addition to instruction ++ * breakpoints. ++ * ++ * {datar|dataw|io|inst} [length] ++ */ ++ ++int ++kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp) ++{ ++ int nextarg = *nextargp; ++ int diag; ++ kdbhard_bp_t *bph = &bp->bp_template; ++ ++ bph->bph_mode = 0; /* Default to instruction breakpoint */ ++ bph->bph_length = 0; /* Length must be zero for insn bp */ ++ if ((argc + 1) != nextarg) { ++ if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { ++ bph->bph_mode = 3; ++ } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { ++ bph->bph_mode = 1; ++ } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { ++ bph->bph_mode = 2; ++ } else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) { ++ bph->bph_mode = 0; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ bph->bph_length = 3; /* Default to 4 byte */ ++ ++ nextarg++; ++ ++ if ((argc + 1) != nextarg) { ++ unsigned long len; ++ ++ diag = kdbgetularg((char *)argv[nextarg], ++ &len); ++ if (diag) ++ return diag; ++ ++ ++ if ((len > 4) || (len == 3)) ++ return KDB_BADLENGTH; ++ ++ bph->bph_length = len; ++ bph->bph_length--; /* Normalize for debug register */ ++ nextarg++; ++ } ++ ++ if ((argc + 1) != nextarg) ++ return KDB_ARGCOUNT; ++ ++ /* ++ * Indicate to architecture independent level that ++ * a hardware register assignment is required to enable ++ * this breakpoint. ++ */ ++ ++ bph->bph_free = 0; ++ } else { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw); ++ if (bp->bp_forcehw) { ++ /* ++ * We are forced to use a hardware register for this ++ * breakpoint because either the bph or bpha ++ * commands were used to establish this breakpoint. ++ */ ++ bph->bph_free = 0; ++ } else { ++ /* ++ * Indicate to architecture dependent level that ++ * the instruction replacement breakpoint technique ++ * should be used for this breakpoint. ++ */ ++ bph->bph_free = 1; ++ bp->bp_adjust = 1; /* software, int 3 is one byte */ ++ } ++ } ++ ++ if (bph->bph_mode != 2 && kdba_verify_rw(bp->bp_addr, bph->bph_length+1)) { ++ kdb_printf("Invalid address for breakpoint, ignoring bp command\n"); ++ return KDB_BADADDR; ++ } ++ ++ *nextargp = nextarg; ++ return 0; ++} ++ ++/* ++ * kdba_allocbp ++ * ++ * Allocate hw register for bp on specific CPU ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * A pointer to the allocated register kdbhard_bp_t structure for ++ * success, Null and a non-zero diagnostic for failure. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static kdbhard_bp_t * ++kdba_allocbp(kdbhard_bp_t *bph, int *diagp, unsigned int cpu) ++{ ++ int i; ++ kdbhard_bp_t *newbph; ++ ++ for(i=0; i < KDB_MAXHARDBPT; i++) { ++ newbph=&(kdb_hardbreaks[cpu][i]); ++ if (newbph->bph_free) { ++ break; ++ } ++ } ++ ++ if (i == KDB_MAXHARDBPT) { ++ *diagp = KDB_TOOMANYDBREGS; ++ return NULL; ++ } ++ ++ *diagp = 0; ++ ++ /* ++ * Copy data from template. Can't just copy the entire template ++ * here because the register number in kdb_hardbreaks must be ++ * preserved. ++ */ ++ newbph->bph_data = bph->bph_data; ++ newbph->bph_write = bph->bph_write; ++ newbph->bph_mode = bph->bph_mode; ++ newbph->bph_length = bph->bph_length; ++ ++ /* ++ * Mark entry allocated. ++ */ ++ newbph->bph_free = 0; ++ ++ return newbph; ++} ++ ++/* ++ * kdba_alloc_hwbp ++ * ++ * Associate a hardware registers with a breakpoint. ++ * If hw bp is global hw registers descriptor will be allocated ++ * on every CPU. ++ * ++ * Parameters: ++ * bp - hardware bp ++ * diagp - pointer to variable that will store error when ++ * function complete ++ * Outputs: ++ * None. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Should be called with correct bp->bp_template ++ */ ++ ++void ++kdba_alloc_hwbp(kdb_bp_t *bp, int *diagp) ++{ ++ int i; ++ ++ if (bp->bp_global){ ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ bp->bp_hard[i] = kdba_allocbp(&bp->bp_template, diagp, i); ++ if (*diagp) ++ break; ++ } ++ } else { ++ bp->bp_hard[bp->bp_cpu] = kdba_allocbp(&bp->bp_template, diagp, bp->bp_cpu); ++ } ++ bp->bp_hardtype = 1; ++} ++ ++/* ++ * kdba_freebp ++ * ++ * Deallocate hw registers descriptor for bp on specific CPU ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++static void ++kdba_freebp(kdbhard_bp_t *bph) ++{ ++ bph->bph_free = 1; ++} ++ ++/* ++ * kdba_free_hwbp ++ * ++ * Frees allocated hw registers descriptors for bp. ++ * If hw bp is global, hw registers descriptors will be freed ++ * on every CPU. ++ * ++ * Parameters: ++ * bp - hardware bp ++ * Outputs: ++ * None. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Should be called with correct bp->bp_template ++ */ ++ ++void ++kdba_free_hwbp(kdb_bp_t *bp) ++{ ++ int i; ++ ++ /* When kernel enters KDB, first, all local bps ++ * are removed, so here we don't need to clear ++ * debug registers. ++ */ ++ ++ if (bp->bp_global){ ++ for (i = 0; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ if (bp->bp_hard[i]) ++ kdba_freebp(bp->bp_hard[i]); ++ bp->bp_hard[i] = 0; ++ } ++ } else { ++ kdba_freebp(bp->bp_hard[bp->bp_cpu]); ++ bp->bp_hard[bp->bp_cpu] = NULL; ++ } ++ bp->bp_hardtype = 0; ++} ++ ++/* ++ * kdba_initbp ++ * ++ * Initialize the breakpoint table for the hardware breakpoint ++ * register. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * Zero for success, a kdb diagnostic for failure ++ * Locking: ++ * None. ++ * Remarks: ++ * ++ * There is one entry per register. On the ia32 architecture ++ * all the registers are interchangeable, so no special allocation ++ * criteria are required. ++ */ ++ ++void ++kdba_initbp(void) ++{ ++ int i,j; ++ kdbhard_bp_t *bph; ++ ++ /* ++ * Clear the hardware breakpoint table ++ */ ++ ++ memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks)); ++ ++ for (i = 0; i < NR_CPUS; ++i) { ++ /* Called early so we don't know actual ++ * ammount of CPUs ++ */ ++ for(j=0; j < KDB_MAXHARDBPT; j++) { ++ bph=&(kdb_hardbreaks[i][j]); ++ bph->bph_reg = j; ++ bph->bph_free = 1; ++ } ++ } ++} ++ ++/* ++ * kdba_installbp ++ * ++ * Install a breakpoint ++ * ++ * Parameters: ++ * regs Exception frame ++ * bp Breakpoint structure for the breakpoint to be installed ++ * Outputs: ++ * None. ++ * Returns: ++ * 0 if breakpoint installed. ++ * Locking: ++ * None. ++ * Remarks: ++ * For hardware breakpoints, a debug register is allocated ++ * and assigned to the breakpoint. If no debug register is ++ * available, a warning message is printed and the breakpoint ++ * is disabled. ++ * ++ * For instruction replacement breakpoints, we must single-step ++ * over the replaced instruction at this point so we can re-install ++ * the breakpoint instruction after the single-step. ++ */ ++ ++int ++kdba_installbp(struct pt_regs *regs, kdb_bp_t *bp) ++{ ++ int cpu = smp_processor_id(); ++ ++ /* ++ * Install the breakpoint, if it is not already installed. ++ */ ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed); ++ } ++ if (!KDB_STATE(SSBPT)) ++ bp->bp_delay = 0; ++ ++ if (bp->bp_hardtype) { ++ if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){ ++ kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local hw bp\n"); ++ } ++ ++ if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){ ++ kdb_printf("kdba_removebp: Error - bp_hard[smp_processor_id()] is emply\n"); ++ return 1; ++ } ++ ++ if (!bp->bp_hard[cpu]->bph_installed){ ++ kdba_installdbreg(bp); ++ bp->bp_hard[cpu]->bph_installed = 1; ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n", ++ bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ } ++ } ++ } else if (!bp->bp_installed) { ++ if (bp->bp_delay) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp delayed bp\n"); ++ kdba_handle_bp(regs, bp); ++ } else { ++ if (kdb_getarea_size(&(bp->bp_inst), bp->bp_addr, 1) || ++ kdb_putword(bp->bp_addr, IA32_BREAKPOINT_INSTRUCTION, 1)) { ++ kdb_printf("kdba_installbp failed to set software breakpoint at " kdb_bfd_vma_fmt "\n", bp->bp_addr); ++ return(1); ++ } ++ bp->bp_installed = 1; ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdba_installbp instruction 0x%x at " kdb_bfd_vma_fmt "\n", ++ IA32_BREAKPOINT_INSTRUCTION, bp->bp_addr); ++ } ++ } ++ return(0); ++} ++ ++/* ++ * kdba_removebp ++ * ++ * Make a breakpoint ineffective. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdba_removebp(kdb_bp_t *bp) ++{ ++ int cpu = smp_processor_id(); ++ ++ /* ++ * For hardware breakpoints, remove it from the active register, ++ * for software breakpoints, restore the instruction stream. ++ */ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed); ++ } ++ ++ if (bp->bp_hardtype) { ++ if (KDB_DEBUG(BP) && !bp->bp_global && cpu != bp->bp_cpu){ ++ kdb_printf("kdba_removebp: cpu != bp->bp_cpu for local hw bp\n"); ++ } ++ ++ if (KDB_DEBUG(BP) && !bp->bp_hard[cpu]){ ++ kdb_printf("kdba_removebp: Error - bp_hard[smp_processor_id()] is emply\n"); ++ return 1; ++ } ++ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt "\n", ++ bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ } ++ ++ if (bp->bp_hard[cpu]->bph_installed){ ++ if (KDB_DEBUG(BP)) { ++ kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n", ++ bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ } ++ kdba_removedbreg(bp); ++ bp->bp_hard[cpu]->bph_installed = 0; ++ } ++ } else if (bp->bp_installed) { ++ if (KDB_DEBUG(BP)) ++ kdb_printf("kdb: restoring instruction 0x%x at " kdb_bfd_vma_fmt "\n", ++ bp->bp_inst, bp->bp_addr); ++ if (kdb_putword(bp->bp_addr, bp->bp_inst, 1)) ++ return(1); ++ bp->bp_installed = 0; ++ } ++ return(0); ++} +--- /dev/null ++++ b/arch/x86/kdb/kdba_bt.c +@@ -0,0 +1,5597 @@ ++/* ++ * 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) 2006, 2007-2008 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * Common code for doing accurate backtraces on i386 and x86_64, including ++ * printing the values of arguments. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define KDB_DEBUG_BB(fmt, ...) \ ++ {if (KDB_DEBUG(BB)) kdb_printf(fmt, ## __VA_ARGS__);} ++#define KDB_DEBUG_BB_OFFSET_PRINTF(offset, prefix, suffix) \ ++ kdb_printf(prefix "%c0x%x" suffix, \ ++ offset >= 0 ? '+' : '-', \ ++ offset >= 0 ? offset : -offset) ++#define KDB_DEBUG_BB_OFFSET(offset, prefix, suffix) \ ++ {if (KDB_DEBUG(BB)) KDB_DEBUG_BB_OFFSET_PRINTF(offset, prefix, suffix);} ++ ++#define BB_CHECK(expr, val, ret) \ ++({ \ ++ if (unlikely(expr)) { \ ++ kdb_printf("%s, line %d: BB_CHECK(" #expr ") failed " \ ++ #val "=%lx\n", \ ++ __FUNCTION__, __LINE__, (long)val); \ ++ bb_giveup = 1; \ ++ return ret; \ ++ } \ ++}) ++ ++static int bb_giveup; ++ ++/* Use BBRG_Rxx for both i386 and x86_64. RAX through R15 must be at the end, ++ * starting with RAX. Some of these codes do not reflect actual registers, ++ * such codes are special cases when parsing the record of register changes. ++ * When updating BBRG_ entries, update bbrg_name as well. ++ */ ++ ++enum bb_reg_code ++{ ++ BBRG_UNDEFINED = 0, /* Register contents are undefined */ ++ BBRG_OSP, /* original stack pointer on entry to function */ ++ BBRG_RAX, ++ BBRG_RBX, ++ BBRG_RCX, ++ BBRG_RDX, ++ BBRG_RDI, ++ BBRG_RSI, ++ BBRG_RBP, ++ BBRG_RSP, ++ BBRG_R8, ++ BBRG_R9, ++ BBRG_R10, ++ BBRG_R11, ++ BBRG_R12, ++ BBRG_R13, ++ BBRG_R14, ++ BBRG_R15, ++}; ++ ++const static char *bbrg_name[] = { ++ [BBRG_UNDEFINED] = "undefined", ++ [BBRG_OSP] = "osp", ++ [BBRG_RAX] = "rax", ++ [BBRG_RBX] = "rbx", ++ [BBRG_RCX] = "rcx", ++ [BBRG_RDX] = "rdx", ++ [BBRG_RDI] = "rdi", ++ [BBRG_RSI] = "rsi", ++ [BBRG_RBP] = "rbp", ++ [BBRG_RSP] = "rsp", ++ [BBRG_R8] = "r8", ++ [BBRG_R9] = "r9", ++ [BBRG_R10] = "r10", ++ [BBRG_R11] = "r11", ++ [BBRG_R12] = "r12", ++ [BBRG_R13] = "r13", ++ [BBRG_R14] = "r14", ++ [BBRG_R15] = "r15", ++}; ++ ++/* Map a register name to its register code. This includes the sub-register ++ * addressable fields, e.g. parts of rax can be addressed as ax, al, ah, eax. ++ * The list is sorted so it can be binary chopped, sort command is: ++ * LANG=C sort -t '"' -k2 ++ */ ++ ++struct bb_reg_code_map { ++ enum bb_reg_code reg; ++ const char *name; ++}; ++ ++const static struct bb_reg_code_map ++bb_reg_code_map[] = { ++ { BBRG_RAX, "ah" }, ++ { BBRG_RAX, "al" }, ++ { BBRG_RAX, "ax" }, ++ { BBRG_RBX, "bh" }, ++ { BBRG_RBX, "bl" }, ++ { BBRG_RBP, "bp" }, ++ { BBRG_RBP, "bpl" }, ++ { BBRG_RBX, "bx" }, ++ { BBRG_RCX, "ch" }, ++ { BBRG_RCX, "cl" }, ++ { BBRG_RCX, "cx" }, ++ { BBRG_RDX, "dh" }, ++ { BBRG_RDI, "di" }, ++ { BBRG_RDI, "dil" }, ++ { BBRG_RDX, "dl" }, ++ { BBRG_RDX, "dx" }, ++ { BBRG_RAX, "eax" }, ++ { BBRG_RBP, "ebp" }, ++ { BBRG_RBX, "ebx" }, ++ { BBRG_RCX, "ecx" }, ++ { BBRG_RDI, "edi" }, ++ { BBRG_RDX, "edx" }, ++ { BBRG_RSI, "esi" }, ++ { BBRG_RSP, "esp" }, ++ { BBRG_R10, "r10" }, ++ { BBRG_R10, "r10d" }, ++ { BBRG_R10, "r10l" }, ++ { BBRG_R10, "r10w" }, ++ { BBRG_R11, "r11" }, ++ { BBRG_R11, "r11d" }, ++ { BBRG_R11, "r11l" }, ++ { BBRG_R11, "r11w" }, ++ { BBRG_R12, "r12" }, ++ { BBRG_R12, "r12d" }, ++ { BBRG_R12, "r12l" }, ++ { BBRG_R12, "r12w" }, ++ { BBRG_R13, "r13" }, ++ { BBRG_R13, "r13d" }, ++ { BBRG_R13, "r13l" }, ++ { BBRG_R13, "r13w" }, ++ { BBRG_R14, "r14" }, ++ { BBRG_R14, "r14d" }, ++ { BBRG_R14, "r14l" }, ++ { BBRG_R14, "r14w" }, ++ { BBRG_R15, "r15" }, ++ { BBRG_R15, "r15d" }, ++ { BBRG_R15, "r15l" }, ++ { BBRG_R15, "r15w" }, ++ { BBRG_R8, "r8" }, ++ { BBRG_R8, "r8d" }, ++ { BBRG_R8, "r8l" }, ++ { BBRG_R8, "r8w" }, ++ { BBRG_R9, "r9" }, ++ { BBRG_R9, "r9d" }, ++ { BBRG_R9, "r9l" }, ++ { BBRG_R9, "r9w" }, ++ { BBRG_RAX, "rax" }, ++ { BBRG_RBP, "rbp" }, ++ { BBRG_RBX, "rbx" }, ++ { BBRG_RCX, "rcx" }, ++ { BBRG_RDI, "rdi" }, ++ { BBRG_RDX, "rdx" }, ++ { BBRG_RSI, "rsi" }, ++ { BBRG_RSP, "rsp" }, ++ { BBRG_RSI, "si" }, ++ { BBRG_RSI, "sil" }, ++ { BBRG_RSP, "sp" }, ++ { BBRG_RSP, "spl" }, ++}; ++ ++/* Record register contents in terms of the values that were passed to this ++ * function, IOW track which registers contain an input value. A register's ++ * contents can be undefined, it can contain an input register value or it can ++ * contain an offset from the original stack pointer. ++ * ++ * This structure is used to represent the current contents of the integer ++ * registers, it is held in an array that is indexed by BBRG_xxx. The element ++ * for BBRG_xxx indicates what input value is currently in BBRG_xxx. When ++ * 'value' is BBRG_OSP then register BBRG_xxx contains a stack pointer, ++ * pointing at 'offset' from the original stack pointer on entry to the ++ * function. When 'value' is not BBRG_OSP then element BBRG_xxx contains the ++ * original contents of an input register and offset is ignored. ++ * ++ * An input register 'value' can be stored in more than one register and/or in ++ * more than one memory location. ++ */ ++ ++struct bb_reg_contains ++{ ++ enum bb_reg_code value: 8; ++ short offset; ++}; ++ ++/* Note: the offsets in struct bb_mem_contains in this code are _NOT_ offsets ++ * from OSP, they are offsets from current RSP. It fits better with the way ++ * that struct pt_regs is built, some code pushes extra data before pt_regs so ++ * working with OSP relative offsets gets messy. struct bb_mem_contains ++ * entries must be in descending order of RSP offset. ++ */ ++ ++typedef struct { DECLARE_BITMAP(bits, BBRG_R15+1); } bbrgmask_t; ++#define BB_SKIP(reg) (1 << (BBRG_ ## reg)) ++struct bb_mem_contains { ++ short offset_address; ++ enum bb_reg_code value: 8; ++}; ++ ++/* Transfer of control to a label outside the current function. If the ++ * transfer is to a known common restore path that expects known registers ++ * and/or a known memory state (e.g. struct pt_regs) then do a sanity check on ++ * the state at this point. ++ */ ++ ++struct bb_name_state { ++ const char *name; /* target function */ ++ bfd_vma address; /* Address of target function */ ++ const char *fname; /* optional from function name */ ++ const struct bb_mem_contains *mem; /* expected memory state */ ++ const struct bb_reg_contains *regs; /* expected register state */ ++ const unsigned short mem_size; /* ARRAY_SIZE(mem) */ ++ const unsigned short regs_size; /* ARRAY_SIZE(regs) */ ++ const short osp_offset; /* RSP in regs == OSP+osp_offset */ ++ const bbrgmask_t skip_mem; /* Some slots in mem may be undefined */ ++ const bbrgmask_t skip_regs; /* Some slots in regs may be undefined */ ++}; ++ ++/* NS (NAME_STATE) macros define the register and memory state when we transfer ++ * control to or start decoding a special case name. Use NS when the target ++ * label always has the same state. Use NS_FROM and specify the source label ++ * if the target state is slightly different depending on where it is branched ++ * from. This gives better state checking, by isolating the special cases. ++ * ++ * Note: for the same target label, NS_FROM entries must be followed by a ++ * single NS entry. ++ */ ++ ++#define NS_FROM(iname, ifname, imem, iregs, iskip_mem, iskip_regs, iosp_offset) \ ++ { \ ++ .name = iname, \ ++ .fname = ifname, \ ++ .mem = imem, \ ++ .regs = iregs, \ ++ .mem_size = ARRAY_SIZE(imem), \ ++ .regs_size = ARRAY_SIZE(iregs), \ ++ .skip_mem.bits[0] = iskip_mem, \ ++ .skip_regs.bits[0] = iskip_regs, \ ++ .osp_offset = iosp_offset, \ ++ .address = 0 \ ++ } ++ ++/* Shorter forms for the common cases */ ++#define NS(iname, imem, iregs, iskip_mem, iskip_regs, iosp_offset) \ ++ NS_FROM(iname, NULL, imem, iregs, iskip_mem, iskip_regs, iosp_offset) ++#define NS_MEM(iname, imem, iskip_mem) \ ++ NS_FROM(iname, NULL, imem, no_regs, iskip_mem, 0, 0) ++#define NS_MEM_FROM(iname, ifname, imem, iskip_mem) \ ++ NS_FROM(iname, ifname, imem, no_regs, iskip_mem, 0, 0) ++#define NS_REG(iname, iregs, iskip_regs) \ ++ NS_FROM(iname, NULL, no_memory, iregs, 0, iskip_regs, 0) ++#define NS_REG_FROM(iname, ifname, iregs, iskip_regs) \ ++ NS_FROM(iname, ifname, no_memory, iregs, 0, iskip_regs, 0) ++ ++static void ++bb_reg_code_set_value(enum bb_reg_code dst, enum bb_reg_code src); ++ ++static const char *bb_mod_name, *bb_func_name; ++ ++static int ++bb_noret(const char *name) ++{ ++ if (strcmp(name, "panic") == 0 || ++ strcmp(name, "do_exit") == 0 || ++ strcmp(name, "do_group_exit") == 0 || ++ strcmp(name, "complete_and_exit") == 0) ++ return 1; ++ return 0; ++} ++ ++/*============================================================================*/ ++/* */ ++/* Most of the basic block code and data is common to x86_64 and i386. This */ ++/* large ifdef contains almost all of the differences between the two */ ++/* architectures. */ ++/* */ ++/* Make sure you update the correct section of this ifdef. */ ++/* */ ++/*============================================================================*/ ++ ++#ifdef CONFIG_X86_64 ++ ++/* Registers that can be used to pass parameters, in the order that parameters ++ * are passed. ++ */ ++ ++const static enum bb_reg_code ++bb_param_reg[] = { ++ BBRG_RDI, ++ BBRG_RSI, ++ BBRG_RDX, ++ BBRG_RCX, ++ BBRG_R8, ++ BBRG_R9, ++}; ++ ++const static enum bb_reg_code ++bb_preserved_reg[] = { ++ BBRG_RBX, ++ BBRG_RBP, ++ BBRG_RSP, ++ BBRG_R12, ++ BBRG_R13, ++ BBRG_R14, ++ BBRG_R15, ++}; ++ ++static const struct bb_mem_contains full_pt_regs[] = { ++ { 0x70, BBRG_RDI }, ++ { 0x68, BBRG_RSI }, ++ { 0x60, BBRG_RDX }, ++ { 0x58, BBRG_RCX }, ++ { 0x50, BBRG_RAX }, ++ { 0x48, BBRG_R8 }, ++ { 0x40, BBRG_R9 }, ++ { 0x38, BBRG_R10 }, ++ { 0x30, BBRG_R11 }, ++ { 0x28, BBRG_RBX }, ++ { 0x20, BBRG_RBP }, ++ { 0x18, BBRG_R12 }, ++ { 0x10, BBRG_R13 }, ++ { 0x08, BBRG_R14 }, ++ { 0x00, BBRG_R15 }, ++}; ++static const struct bb_mem_contains partial_pt_regs[] = { ++ { 0x40, BBRG_RDI }, ++ { 0x38, BBRG_RSI }, ++ { 0x30, BBRG_RDX }, ++ { 0x28, BBRG_RCX }, ++ { 0x20, BBRG_RAX }, ++ { 0x18, BBRG_R8 }, ++ { 0x10, BBRG_R9 }, ++ { 0x08, BBRG_R10 }, ++ { 0x00, BBRG_R11 }, ++}; ++static const struct bb_mem_contains partial_pt_regs_plus_1[] = { ++ { 0x48, BBRG_RDI }, ++ { 0x40, BBRG_RSI }, ++ { 0x38, BBRG_RDX }, ++ { 0x30, BBRG_RCX }, ++ { 0x28, BBRG_RAX }, ++ { 0x20, BBRG_R8 }, ++ { 0x18, BBRG_R9 }, ++ { 0x10, BBRG_R10 }, ++ { 0x08, BBRG_R11 }, ++}; ++static const struct bb_mem_contains partial_pt_regs_plus_2[] = { ++ { 0x50, BBRG_RDI }, ++ { 0x48, BBRG_RSI }, ++ { 0x40, BBRG_RDX }, ++ { 0x38, BBRG_RCX }, ++ { 0x30, BBRG_RAX }, ++ { 0x28, BBRG_R8 }, ++ { 0x20, BBRG_R9 }, ++ { 0x18, BBRG_R10 }, ++ { 0x10, BBRG_R11 }, ++}; ++static const struct bb_mem_contains no_memory[] = { ++}; ++/* Hardware has already pushed an error_code on the stack. Use undefined just ++ * to set the initial stack offset. ++ */ ++static const struct bb_mem_contains error_code[] = { ++ { 0x0, BBRG_UNDEFINED }, ++}; ++/* error_code plus original rax */ ++static const struct bb_mem_contains error_code_rax[] = { ++ { 0x8, BBRG_UNDEFINED }, ++ { 0x0, BBRG_RAX }, ++}; ++ ++static const struct bb_reg_contains all_regs[] = { ++ [BBRG_RAX] = { BBRG_RAX, 0 }, ++ [BBRG_RBX] = { BBRG_RBX, 0 }, ++ [BBRG_RCX] = { BBRG_RCX, 0 }, ++ [BBRG_RDX] = { BBRG_RDX, 0 }, ++ [BBRG_RDI] = { BBRG_RDI, 0 }, ++ [BBRG_RSI] = { BBRG_RSI, 0 }, ++ [BBRG_RBP] = { BBRG_RBP, 0 }, ++ [BBRG_RSP] = { BBRG_OSP, 0 }, ++ [BBRG_R8 ] = { BBRG_R8, 0 }, ++ [BBRG_R9 ] = { BBRG_R9, 0 }, ++ [BBRG_R10] = { BBRG_R10, 0 }, ++ [BBRG_R11] = { BBRG_R11, 0 }, ++ [BBRG_R12] = { BBRG_R12, 0 }, ++ [BBRG_R13] = { BBRG_R13, 0 }, ++ [BBRG_R14] = { BBRG_R14, 0 }, ++ [BBRG_R15] = { BBRG_R15, 0 }, ++}; ++static const struct bb_reg_contains no_regs[] = { ++}; ++ ++static struct bb_name_state bb_special_cases[] = { ++ ++ /* First the cases that pass data only in memory. We do not check any ++ * register state for these cases. ++ */ ++ ++ /* Simple cases, no exceptions */ ++ NS_MEM("ia32_ptregs_common", partial_pt_regs_plus_1, 0), ++ NS_MEM("ia32_sysret", partial_pt_regs, 0), ++ NS_MEM("int_careful", partial_pt_regs, 0), ++ NS_MEM("int_restore_rest", full_pt_regs, 0), ++ NS_MEM("int_signal", full_pt_regs, 0), ++ NS_MEM("int_very_careful", partial_pt_regs, 0), ++ NS_MEM("int_with_check", partial_pt_regs, 0), ++#ifdef CONFIG_TRACE_IRQFLAGS ++ NS_MEM("paranoid_exit0", full_pt_regs, 0), ++#endif /* CONFIG_TRACE_IRQFLAGS */ ++ NS_MEM("paranoid_exit1", full_pt_regs, 0), ++ NS_MEM("ptregscall_common", partial_pt_regs_plus_1, 0), ++ NS_MEM("restore_norax", partial_pt_regs, 0), ++ NS_MEM("restore", partial_pt_regs, 0), ++ NS_MEM("ret_from_intr", partial_pt_regs_plus_2, 0), ++ NS_MEM("stub32_clone", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_execve", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_fork", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_iopl", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_rt_sigreturn", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_rt_sigsuspend", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_sigaltstack", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_sigreturn", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_sigsuspend", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub32_vfork", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_clone", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_execve", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_fork", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_iopl", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_rt_sigreturn", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_rt_sigsuspend", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_sigaltstack", partial_pt_regs_plus_1, 0), ++ NS_MEM("stub_vfork", partial_pt_regs_plus_1, 0), ++ ++ NS_MEM_FROM("ia32_badsys", "ia32_sysenter_target", ++ partial_pt_regs, ++ /* ia32_sysenter_target uses CLEAR_RREGS to clear R8-R11 on ++ * some paths. It also stomps on RAX. ++ */ ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX)), ++ NS_MEM_FROM("ia32_badsys", "ia32_cstar_target", ++ partial_pt_regs, ++ /* ia32_cstar_target uses CLEAR_RREGS to clear R8-R11 on some ++ * paths. It also stomps on RAX. Even more confusing, instead ++ * of storing RCX it stores RBP. WTF? ++ */ ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ NS_MEM("ia32_badsys", partial_pt_regs, 0), ++ ++ /* Various bits of code branch to int_ret_from_sys_call, with slightly ++ * different missing values in pt_regs. ++ */ ++ NS_MEM_FROM("int_ret_from_sys_call", "ret_from_fork", ++ partial_pt_regs, ++ BB_SKIP(R11)), ++ NS_MEM_FROM("int_ret_from_sys_call", "stub_execve", ++ partial_pt_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ NS_MEM_FROM("int_ret_from_sys_call", "stub_rt_sigreturn", ++ partial_pt_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ NS_MEM_FROM("int_ret_from_sys_call", "kernel_execve", ++ partial_pt_regs, ++ BB_SKIP(RAX)), ++ NS_MEM_FROM("int_ret_from_sys_call", "ia32_syscall", ++ partial_pt_regs, ++ /* ia32_syscall only saves RDI through RCX. */ ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX)), ++ NS_MEM_FROM("int_ret_from_sys_call", "ia32_sysenter_target", ++ partial_pt_regs, ++ /* ia32_sysenter_target uses CLEAR_RREGS to clear R8-R11 on ++ * some paths. It also stomps on RAX. ++ */ ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX)), ++ NS_MEM_FROM("int_ret_from_sys_call", "ia32_cstar_target", ++ partial_pt_regs, ++ /* ia32_cstar_target uses CLEAR_RREGS to clear R8-R11 on some ++ * paths. It also stomps on RAX. Even more confusing, instead ++ * of storing RCX it stores RBP. WTF? ++ */ ++ BB_SKIP(R8) | BB_SKIP(R9) | BB_SKIP(R10) | BB_SKIP(R11) | ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ NS_MEM("int_ret_from_sys_call", partial_pt_regs, 0), ++ ++#ifdef CONFIG_PREEMPT ++ NS_MEM("retint_kernel", partial_pt_regs, BB_SKIP(RAX)), ++#endif /* CONFIG_PREEMPT */ ++ ++ NS_MEM("retint_careful", partial_pt_regs, BB_SKIP(RAX)), ++ ++ /* Horrible hack: For a brand new x86_64 task, switch_to() branches to ++ * ret_from_fork with a totally different stack state from all the ++ * other tasks that come out of switch_to(). This non-standard state ++ * cannot be represented so just ignore the branch from switch_to() to ++ * ret_from_fork. Due to inlining and linker labels, switch_to() can ++ * appear as several different function labels, including schedule, ++ * context_switch and __sched_text_start. ++ */ ++ NS_MEM_FROM("ret_from_fork", "schedule", no_memory, 0), ++ NS_MEM_FROM("ret_from_fork", "__sched_text_start", no_memory, 0), ++ NS_MEM_FROM("ret_from_fork", "context_switch", no_memory, 0), ++ NS_MEM("ret_from_fork", full_pt_regs, 0), ++ ++ ++ NS_MEM_FROM("ret_from_sys_call", "ret_from_fork", ++ partial_pt_regs, ++ BB_SKIP(R11)), ++ NS_MEM("ret_from_sys_call", partial_pt_regs, 0), ++ ++ NS_MEM("retint_restore_args", ++ partial_pt_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ ++ NS_MEM("retint_swapgs", ++ partial_pt_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ ++ /* Now the cases that pass data in registers. We do not check any ++ * memory state for these cases. ++ */ ++ ++ NS_REG("bad_put_user", ++ all_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX) | BB_SKIP(R8)), ++ ++ NS_REG("bad_get_user", ++ all_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX) | BB_SKIP(R8)), ++ ++ NS_REG("bad_to_user", ++ all_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ ++ NS_REG("ia32_ptregs_common", ++ all_regs, ++ 0), ++ ++ NS_REG("copy_user_generic_unrolled", ++ all_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ ++ NS_REG("copy_user_generic_string", ++ all_regs, ++ BB_SKIP(RAX) | BB_SKIP(RCX)), ++ ++ NS_REG("irq_return", ++ all_regs, ++ 0), ++ ++ /* Finally the cases that pass data in both registers and memory. ++ */ ++ ++ NS("invalid_TSS", error_code, all_regs, 0, 0, 0), ++ NS("segment_not_present", error_code, all_regs, 0, 0, 0), ++ NS("alignment_check", error_code, all_regs, 0, 0, 0), ++ NS("page_fault", error_code, all_regs, 0, 0, 0), ++ NS("general_protection", error_code, all_regs, 0, 0, 0), ++ NS("error_entry", error_code_rax, all_regs, 0, BB_SKIP(RAX), -0x10), ++ NS("common_interrupt", error_code, all_regs, 0, 0, -0x8), ++}; ++ ++static const char *bb_spurious[] = { ++ /* schedule */ ++ "thread_return", ++ /* ret_from_fork */ ++ "rff_action", ++ "rff_trace", ++ /* system_call */ ++ "ret_from_sys_call", ++ "sysret_check", ++ "sysret_careful", ++ "sysret_signal", ++ "badsys", ++ "tracesys", ++ "int_ret_from_sys_call", ++ "int_with_check", ++ "int_careful", ++ "int_very_careful", ++ "int_signal", ++ "int_restore_rest", ++ /* common_interrupt */ ++ "ret_from_intr", ++ "exit_intr", ++ "retint_with_reschedule", ++ "retint_check", ++ "retint_swapgs", ++ "retint_restore_args", ++ "restore_args", ++ "irq_return", ++ "bad_iret", ++ "retint_careful", ++ "retint_signal", ++#ifdef CONFIG_PREEMPT ++ "retint_kernel", ++#endif /* CONFIG_PREEMPT */ ++ /* .macro paranoidexit */ ++#ifdef CONFIG_TRACE_IRQFLAGS ++ "paranoid_exit0", ++ "paranoid_userspace0", ++ "paranoid_restore0", ++ "paranoid_swapgs0", ++ "paranoid_schedule0", ++#endif /* CONFIG_TRACE_IRQFLAGS */ ++ "paranoid_exit1", ++ "paranoid_swapgs1", ++ "paranoid_restore1", ++ "paranoid_userspace1", ++ "paranoid_schedule1", ++ /* error_entry */ ++ "error_swapgs", ++ "error_sti", ++ "error_exit", ++ "error_kernelspace", ++ /* load_gs_index */ ++ "gs_change", ++ "bad_gs", ++ /* ia32_sysenter_target */ ++ "sysenter_do_call", ++ "sysenter_tracesys", ++ /* ia32_cstar_target */ ++ "cstar_do_call", ++ "cstar_tracesys", ++ "ia32_badarg", ++ /* ia32_syscall */ ++ "ia32_do_syscall", ++ "ia32_sysret", ++ "ia32_tracesys", ++ "ia32_badsys", ++#ifdef CONFIG_HIBERNATION ++ /* restore_image */ ++ "loop", ++ "done", ++#endif /* CONFIG_HIBERNATION */ ++#ifdef CONFIG_KPROBES ++ /* jprobe_return */ ++ "jprobe_return_end", ++ /* kretprobe_trampoline_holder */ ++ "kretprobe_trampoline", ++#endif /* CONFIG_KPROBES */ ++#ifdef CONFIG_KEXEC ++ /* relocate_kernel */ ++ "relocate_new_kernel", ++#endif /* CONFIG_KEXEC */ ++#ifdef CONFIG_XEN ++ /* arch/i386/xen/xen-asm.S */ ++ "xen_irq_enable_direct_end", ++ "xen_irq_disable_direct_end", ++ "xen_save_fl_direct_end", ++ "xen_restore_fl_direct_end", ++ "xen_iret_start_crit", ++ "iret_restore_end", ++ "xen_iret_end_crit", ++ "hyper_iret", ++#endif /* CONFIG_XEN */ ++}; ++ ++static const char *bb_hardware_handlers[] = { ++ "system_call", ++ "common_interrupt", ++ "error_entry", ++ "debug", ++ "nmi", ++ "int3", ++ "double_fault", ++ "stack_segment", ++ "machine_check", ++ "kdb_call", ++}; ++ ++static int ++bb_hardware_pushed_arch(kdb_machreg_t rsp, ++ const struct kdb_activation_record *ar) ++{ ++ /* x86_64 interrupt stacks are 16 byte aligned and you must get the ++ * next rsp from stack, it cannot be statically calculated. Do not ++ * include the word at rsp, it is pushed by hardware but is treated as ++ * a normal software return value. ++ * ++ * When an IST switch occurs (e.g. NMI) then the saved rsp points to ++ * another stack entirely. Assume that the IST stack is 16 byte ++ * aligned and just return the size of the hardware data on this stack. ++ * The stack unwind code will take care of the stack switch. ++ */ ++ kdb_machreg_t saved_rsp = *((kdb_machreg_t *)rsp + 3); ++ int hardware_pushed = saved_rsp - rsp - KDB_WORD_SIZE; ++ if (hardware_pushed < 4 * KDB_WORD_SIZE || ++ saved_rsp < ar->stack.logical_start || ++ saved_rsp >= ar->stack.logical_end) ++ return 4 * KDB_WORD_SIZE; ++ else ++ return hardware_pushed; ++} ++ ++static void ++bb_start_block0(void) ++{ ++ bb_reg_code_set_value(BBRG_RAX, BBRG_RAX); ++ bb_reg_code_set_value(BBRG_RBX, BBRG_RBX); ++ bb_reg_code_set_value(BBRG_RCX, BBRG_RCX); ++ bb_reg_code_set_value(BBRG_RDX, BBRG_RDX); ++ bb_reg_code_set_value(BBRG_RDI, BBRG_RDI); ++ bb_reg_code_set_value(BBRG_RSI, BBRG_RSI); ++ bb_reg_code_set_value(BBRG_RBP, BBRG_RBP); ++ bb_reg_code_set_value(BBRG_RSP, BBRG_OSP); ++ bb_reg_code_set_value(BBRG_R8, BBRG_R8); ++ bb_reg_code_set_value(BBRG_R9, BBRG_R9); ++ bb_reg_code_set_value(BBRG_R10, BBRG_R10); ++ bb_reg_code_set_value(BBRG_R11, BBRG_R11); ++ bb_reg_code_set_value(BBRG_R12, BBRG_R12); ++ bb_reg_code_set_value(BBRG_R13, BBRG_R13); ++ bb_reg_code_set_value(BBRG_R14, BBRG_R14); ++ bb_reg_code_set_value(BBRG_R15, BBRG_R15); ++} ++ ++/* x86_64 does not have a special case for __switch_to */ ++ ++static void ++bb_fixup_switch_to(char *p) ++{ ++} ++ ++static int ++bb_asmlinkage_arch(void) ++{ ++ return strncmp(bb_func_name, "__down", 6) == 0 || ++ strncmp(bb_func_name, "__up", 4) == 0 || ++ strncmp(bb_func_name, "stub_", 5) == 0 || ++ strcmp(bb_func_name, "ret_from_fork") == 0 || ++ strcmp(bb_func_name, "ptregscall_common") == 0; ++} ++ ++#else /* !CONFIG_X86_64 */ ++ ++/* Registers that can be used to pass parameters, in the order that parameters ++ * are passed. ++ */ ++ ++const static enum bb_reg_code ++bb_param_reg[] = { ++ BBRG_RAX, ++ BBRG_RDX, ++ BBRG_RCX, ++}; ++ ++const static enum bb_reg_code ++bb_preserved_reg[] = { ++ BBRG_RBX, ++ BBRG_RBP, ++ BBRG_RSP, ++ BBRG_RSI, ++ BBRG_RDI, ++}; ++ ++static const struct bb_mem_contains full_pt_regs[] = { ++ { 0x18, BBRG_RAX }, ++ { 0x14, BBRG_RBP }, ++ { 0x10, BBRG_RDI }, ++ { 0x0c, BBRG_RSI }, ++ { 0x08, BBRG_RDX }, ++ { 0x04, BBRG_RCX }, ++ { 0x00, BBRG_RBX }, ++}; ++static const struct bb_mem_contains no_memory[] = { ++}; ++/* Hardware has already pushed an error_code on the stack. Use undefined just ++ * to set the initial stack offset. ++ */ ++static const struct bb_mem_contains error_code[] = { ++ { 0x0, BBRG_UNDEFINED }, ++}; ++/* rbx already pushed */ ++static const struct bb_mem_contains rbx_pushed[] = { ++ { 0x0, BBRG_RBX }, ++}; ++#ifdef CONFIG_MATH_EMULATION ++static const struct bb_mem_contains mem_fpu_reg_round[] = { ++ { 0xc, BBRG_RBP }, ++ { 0x8, BBRG_RSI }, ++ { 0x4, BBRG_RDI }, ++ { 0x0, BBRG_RBX }, ++}; ++#endif /* CONFIG_MATH_EMULATION */ ++ ++static const struct bb_reg_contains all_regs[] = { ++ [BBRG_RAX] = { BBRG_RAX, 0 }, ++ [BBRG_RBX] = { BBRG_RBX, 0 }, ++ [BBRG_RCX] = { BBRG_RCX, 0 }, ++ [BBRG_RDX] = { BBRG_RDX, 0 }, ++ [BBRG_RDI] = { BBRG_RDI, 0 }, ++ [BBRG_RSI] = { BBRG_RSI, 0 }, ++ [BBRG_RBP] = { BBRG_RBP, 0 }, ++ [BBRG_RSP] = { BBRG_OSP, 0 }, ++}; ++static const struct bb_reg_contains no_regs[] = { ++}; ++#ifdef CONFIG_MATH_EMULATION ++static const struct bb_reg_contains reg_fpu_reg_round[] = { ++ [BBRG_RBP] = { BBRG_OSP, -0x4 }, ++ [BBRG_RSP] = { BBRG_OSP, -0x10 }, ++}; ++#endif /* CONFIG_MATH_EMULATION */ ++ ++static struct bb_name_state bb_special_cases[] = { ++ ++ /* First the cases that pass data only in memory. We do not check any ++ * register state for these cases. ++ */ ++ ++ /* Simple cases, no exceptions */ ++ NS_MEM("check_userspace", full_pt_regs, 0), ++ NS_MEM("device_not_available_emulate", full_pt_regs, 0), ++ NS_MEM("ldt_ss", full_pt_regs, 0), ++ NS_MEM("no_singlestep", full_pt_regs, 0), ++ NS_MEM("restore_all", full_pt_regs, 0), ++ NS_MEM("restore_nocheck", full_pt_regs, 0), ++ NS_MEM("restore_nocheck_notrace", full_pt_regs, 0), ++ NS_MEM("ret_from_exception", full_pt_regs, 0), ++ NS_MEM("ret_from_fork", full_pt_regs, 0), ++ NS_MEM("ret_from_intr", full_pt_regs, 0), ++ NS_MEM("work_notifysig", full_pt_regs, 0), ++ NS_MEM("work_pending", full_pt_regs, 0), ++ ++#ifdef CONFIG_PREEMPT ++ NS_MEM("resume_kernel", full_pt_regs, 0), ++#endif /* CONFIG_PREEMPT */ ++ ++ NS_MEM("common_interrupt", error_code, 0), ++ NS_MEM("error_code", error_code, 0), ++ ++ NS_MEM("bad_put_user", rbx_pushed, 0), ++ ++ NS_MEM_FROM("resume_userspace", "syscall_badsys", ++ full_pt_regs, BB_SKIP(RAX)), ++ NS_MEM_FROM("resume_userspace", "syscall_fault", ++ full_pt_regs, BB_SKIP(RAX)), ++ NS_MEM_FROM("resume_userspace", "syscall_trace_entry", ++ full_pt_regs, BB_SKIP(RAX)), ++ /* Too difficult to trace through the various vm86 functions for now. ++ * They are C functions that start off with some memory state, fiddle ++ * the registers then jmp directly to resume_userspace. For the ++ * moment, just assume that they are valid and do no checks. ++ */ ++ NS_FROM("resume_userspace", "do_int", ++ no_memory, no_regs, 0, 0, 0), ++ NS_FROM("resume_userspace", "do_sys_vm86", ++ no_memory, no_regs, 0, 0, 0), ++ NS_FROM("resume_userspace", "handle_vm86_fault", ++ no_memory, no_regs, 0, 0, 0), ++ NS_FROM("resume_userspace", "handle_vm86_trap", ++ no_memory, no_regs, 0, 0, 0), ++ NS_MEM("resume_userspace", full_pt_regs, 0), ++ ++ NS_MEM_FROM("syscall_badsys", "ia32_sysenter_target", ++ full_pt_regs, BB_SKIP(RBP)), ++ NS_MEM("syscall_badsys", full_pt_regs, 0), ++ ++ NS_MEM_FROM("syscall_call", "syscall_trace_entry", ++ full_pt_regs, BB_SKIP(RAX)), ++ NS_MEM("syscall_call", full_pt_regs, 0), ++ ++ NS_MEM_FROM("syscall_exit", "syscall_trace_entry", ++ full_pt_regs, BB_SKIP(RAX)), ++ NS_MEM("syscall_exit", full_pt_regs, 0), ++ ++ NS_MEM_FROM("syscall_exit_work", "ia32_sysenter_target", ++ full_pt_regs, BB_SKIP(RAX) | BB_SKIP(RBP)), ++ NS_MEM_FROM("syscall_exit_work", "system_call", ++ full_pt_regs, BB_SKIP(RAX)), ++ NS_MEM("syscall_exit_work", full_pt_regs, 0), ++ ++ NS_MEM_FROM("syscall_trace_entry", "ia32_sysenter_target", ++ full_pt_regs, BB_SKIP(RBP)), ++ NS_MEM_FROM("syscall_trace_entry", "system_call", ++ full_pt_regs, BB_SKIP(RAX)), ++ NS_MEM("syscall_trace_entry", full_pt_regs, 0), ++ ++ /* Now the cases that pass data in registers. We do not check any ++ * memory state for these cases. ++ */ ++ ++ NS_REG("syscall_fault", all_regs, 0), ++ ++ NS_REG("bad_get_user", all_regs, ++ BB_SKIP(RAX) | BB_SKIP(RDX)), ++ ++ /* Finally the cases that pass data in both registers and memory. ++ */ ++ ++ /* This entry is redundant now because bb_fixup_switch_to() hides the ++ * jmp __switch_to case, however the entry is left here as ++ * documentation. ++ * ++ * NS("__switch_to", no_memory, no_regs, 0, 0, 0), ++ */ ++ ++ NS("iret_exc", no_memory, all_regs, 0, 0, 0x20), ++ ++#ifdef CONFIG_MATH_EMULATION ++ NS("fpu_reg_round", mem_fpu_reg_round, reg_fpu_reg_round, 0, 0, 0), ++#endif /* CONFIG_MATH_EMULATION */ ++}; ++ ++static const char *bb_spurious[] = { ++ /* ret_from_exception */ ++ "ret_from_intr", ++ "check_userspace", ++ "resume_userspace", ++ /* resume_kernel */ ++#ifdef CONFIG_PREEMPT ++ "need_resched", ++#endif /* CONFIG_PREEMPT */ ++ /* ia32_sysenter_target */ ++ "sysenter_past_esp", ++ /* system_call */ ++ "no_singlestep", ++ "syscall_call", ++ "syscall_exit", ++ "restore_all", ++ "restore_nocheck", ++ "restore_nocheck_notrace", ++ "ldt_ss", ++ /* do not include iret_exc, it is in a .fixup section */ ++ /* work_pending */ ++ "work_resched", ++ "work_notifysig", ++#ifdef CONFIG_VM86 ++ "work_notifysig_v86", ++#endif /* CONFIG_VM86 */ ++ /* page_fault */ ++ "error_code", ++ /* device_not_available */ ++ "device_not_available_emulate", ++ /* debug */ ++ "debug_esp_fix_insn", ++ "debug_stack_correct", ++ /* nmi */ ++ "nmi_stack_correct", ++ "nmi_stack_fixup", ++ "nmi_debug_stack_check", ++ "nmi_espfix_stack", ++#ifdef CONFIG_HIBERNATION ++ /* restore_image */ ++ "copy_loop", ++ "done", ++#endif /* CONFIG_HIBERNATION */ ++#ifdef CONFIG_KPROBES ++ /* jprobe_return */ ++ "jprobe_return_end", ++#endif /* CONFIG_KPROBES */ ++#ifdef CONFIG_KEXEC ++ /* relocate_kernel */ ++ "relocate_new_kernel", ++#endif /* CONFIG_KEXEC */ ++#ifdef CONFIG_MATH_EMULATION ++ /* assorted *.S files in arch/i386/math_emu */ ++ "Denorm_done", ++ "Denorm_shift_more_than_32", ++ "Denorm_shift_more_than_63", ++ "Denorm_shift_more_than_64", ++ "Do_unmasked_underflow", ++ "Exp_not_underflow", ++ "fpu_Arith_exit", ++ "fpu_reg_round", ++ "fpu_reg_round_signed_special_exit", ++ "fpu_reg_round_special_exit", ++ "L_accum_done", ++ "L_accum_loaded", ++ "L_accum_loop", ++ "L_arg1_larger", ++ "L_bugged", ++ "L_bugged_1", ++ "L_bugged_2", ++ "L_bugged_3", ++ "L_bugged_4", ++ "L_bugged_denorm_486", ++ "L_bugged_round24", ++ "L_bugged_round53", ++ "L_bugged_round64", ++ "LCheck_24_round_up", ++ "LCheck_53_round_up", ++ "LCheck_Round_Overflow", ++ "LCheck_truncate_24", ++ "LCheck_truncate_53", ++ "LCheck_truncate_64", ++ "LDenormal_adj_exponent", ++ "L_deNormalised", ++ "LDo_24_round_up", ++ "LDo_2nd_32_bits", ++ "LDo_2nd_div", ++ "LDo_3rd_32_bits", ++ "LDo_3rd_div", ++ "LDo_53_round_up", ++ "LDo_64_round_up", ++ "L_done", ++ "LDo_truncate_24", ++ "LDown_24", ++ "LDown_53", ++ "LDown_64", ++ "L_entry_bugged", ++ "L_error_exit", ++ "L_exactly_32", ++ "L_exception_exit", ++ "L_exit", ++ "L_exit_nuo_valid", ++ "L_exit_nuo_zero", ++ "L_exit_valid", ++ "L_extent_zero", ++ "LFirst_div_done", ++ "LFirst_div_not_1", ++ "L_Full_Division", ++ "LGreater_Half_24", ++ "LGreater_Half_53", ++ "LGreater_than_1", ++ "LLess_than_1", ++ "L_Make_denorm", ++ "L_more_31_no_low", ++ "L_more_63_no_low", ++ "L_more_than_31", ++ "L_more_than_63", ++ "L_more_than_64", ++ "L_more_than_65", ++ "L_more_than_95", ++ "L_must_be_zero", ++ "L_n_exit", ++ "L_no_adjust", ++ "L_no_bit_lost", ++ "L_no_overflow", ++ "L_no_precision_loss", ++ "L_Normalised", ++ "L_norm_bugged", ++ "L_n_shift_1", ++ "L_nuo_shift_1", ++ "L_overflow", ++ "L_precision_lost_down", ++ "L_precision_lost_up", ++ "LPrevent_2nd_overflow", ++ "LPrevent_3rd_overflow", ++ "LPseudoDenormal", ++ "L_Re_normalise", ++ "LResult_Normalised", ++ "L_round", ++ "LRound_large", ++ "LRound_nearest_24", ++ "LRound_nearest_53", ++ "LRound_nearest_64", ++ "LRound_not_small", ++ "LRound_ovfl", ++ "LRound_precision", ++ "LRound_prep", ++ "L_round_the_result", ++ "LRound_To_24", ++ "LRound_To_53", ++ "LRound_To_64", ++ "LSecond_div_done", ++ "LSecond_div_not_1", ++ "L_shift_1", ++ "L_shift_32", ++ "L_shift_65_nc", ++ "L_shift_done", ++ "Ls_less_than_32", ++ "Ls_more_than_63", ++ "Ls_more_than_95", ++ "L_Store_significand", ++ "L_subtr", ++ "LTest_over", ++ "LTruncate_53", ++ "LTruncate_64", ++ "L_underflow", ++ "L_underflow_to_zero", ++ "LUp_24", ++ "LUp_53", ++ "LUp_64", ++ "L_zero", ++ "Normalise_result", ++ "Signal_underflow", ++ "sqrt_arg_ge_2", ++ "sqrt_get_more_precision", ++ "sqrt_more_prec_large", ++ "sqrt_more_prec_ok", ++ "sqrt_more_prec_small", ++ "sqrt_near_exact", ++ "sqrt_near_exact_large", ++ "sqrt_near_exact_ok", ++ "sqrt_near_exact_small", ++ "sqrt_near_exact_x", ++ "sqrt_prelim_no_adjust", ++ "sqrt_round_result", ++ "sqrt_stage_2_done", ++ "sqrt_stage_2_error", ++ "sqrt_stage_2_finish", ++ "sqrt_stage_2_positive", ++ "sqrt_stage_3_error", ++ "sqrt_stage_3_finished", ++ "sqrt_stage_3_no_error", ++ "sqrt_stage_3_positive", ++ "Unmasked_underflow", ++ "xExp_not_underflow", ++#endif /* CONFIG_MATH_EMULATION */ ++}; ++ ++static const char *bb_hardware_handlers[] = { ++ "ret_from_exception", ++ "system_call", ++ "work_pending", ++ "syscall_fault", ++ "page_fault", ++ "coprocessor_error", ++ "simd_coprocessor_error", ++ "device_not_available", ++ "debug", ++ "nmi", ++ "int3", ++ "overflow", ++ "bounds", ++ "invalid_op", ++ "coprocessor_segment_overrun", ++ "invalid_TSS", ++ "segment_not_present", ++ "stack_segment", ++ "general_protection", ++ "alignment_check", ++ "kdb_call", ++ "divide_error", ++ "machine_check", ++ "spurious_interrupt_bug", ++}; ++ ++static int ++bb_hardware_pushed_arch(kdb_machreg_t rsp, ++ const struct kdb_activation_record *ar) ++{ ++ return (2 * KDB_WORD_SIZE); ++} ++ ++static void ++bb_start_block0(void) ++{ ++ bb_reg_code_set_value(BBRG_RAX, BBRG_RAX); ++ bb_reg_code_set_value(BBRG_RBX, BBRG_RBX); ++ bb_reg_code_set_value(BBRG_RCX, BBRG_RCX); ++ bb_reg_code_set_value(BBRG_RDX, BBRG_RDX); ++ bb_reg_code_set_value(BBRG_RDI, BBRG_RDI); ++ bb_reg_code_set_value(BBRG_RSI, BBRG_RSI); ++ bb_reg_code_set_value(BBRG_RBP, BBRG_RBP); ++ bb_reg_code_set_value(BBRG_RSP, BBRG_OSP); ++} ++ ++/* The i386 code that switches stack in a context switch is an extremely ++ * special case. It saves the rip pointing to a label that is not otherwise ++ * referenced, saves the current rsp then pushes a word. The magic code that ++ * resumes the new task picks up the saved rip and rsp, effectively referencing ++ * a label that otherwise is not used and ignoring the pushed word. ++ * ++ * The simplest way to handle this very strange case is to recognise jmp ++ * address <__switch_to> and treat it as a popfl instruction. This avoids ++ * terminating the block on this jmp and removes one word from the stack state, ++ * which is the end effect of all the magic code. ++ * ++ * Called with the instruction line, starting after the first ':'. ++ */ ++ ++static void ++bb_fixup_switch_to(char *p) ++{ ++ char *p1 = p; ++ p += strspn(p, " \t"); /* start of instruction */ ++ if (strncmp(p, "jmp", 3)) ++ return; ++ p += strcspn(p, " \t"); /* end of instruction */ ++ p += strspn(p, " \t"); /* start of address */ ++ p += strcspn(p, " \t"); /* end of address */ ++ p += strspn(p, " \t"); /* start of comment */ ++ if (strcmp(p, "<__switch_to>") == 0) ++ strcpy(p1, "popfl"); ++} ++ ++static int ++bb_asmlinkage_arch(void) ++{ ++ return strcmp(bb_func_name, "ret_from_exception") == 0 || ++ strcmp(bb_func_name, "syscall_trace_entry") == 0; ++} ++ ++#endif /* CONFIG_X86_64 */ ++ ++ ++/*============================================================================*/ ++/* */ ++/* Common code and data. */ ++/* */ ++/*============================================================================*/ ++ ++ ++/* Tracking registers by decoding the instructions is quite a bit harder than ++ * doing the same tracking using compiler generated information. Register ++ * contents can remain in the same register, they can be copied to other ++ * registers, they can be stored on stack or they can be modified/overwritten. ++ * At any one time, there are 0 or more copies of the original value that was ++ * supplied in each register on input to the current function. If a register ++ * exists in multiple places, one copy of that register is the master version, ++ * the others are temporary copies which may or may not be destroyed before the ++ * end of the function. ++ * ++ * The compiler knows which copy of a register is the master and which are ++ * temporary copies, which makes it relatively easy to track register contents ++ * as they are saved and restored. Without that compiler based knowledge, this ++ * code has to track _every_ possible copy of each register, simply because we ++ * do not know which is the master copy and which are temporary copies which ++ * may be destroyed later. ++ * ++ * It gets worse: registers that contain parameters can be copied to other ++ * registers which are then saved on stack in a lower level function. Also the ++ * stack pointer may be held in multiple registers (typically RSP and RBP) ++ * which contain different offsets from the base of the stack on entry to this ++ * function. All of which means that we have to track _all_ register ++ * movements, or at least as much as possible. ++ * ++ * Start with the basic block that contains the start of the function, by ++ * definition all registers contain their initial value. Track each ++ * instruction's effect on register contents, this includes reading from a ++ * parameter register before any write to that register, IOW the register ++ * really does contain a parameter. The register state is represented by a ++ * dynamically sized array with each entry containing :- ++ * ++ * Register name ++ * Location it is copied to (another register or stack + offset) ++ * ++ * Besides the register tracking array, we track which parameter registers are ++ * read before being written, to determine how many parameters are passed in ++ * registers. We also track which registers contain stack pointers, including ++ * their offset from the original stack pointer on entry to the function. ++ * ++ * At each exit from the current basic block (via JMP instruction or drop ++ * through), the register state is cloned to form the state on input to the ++ * target basic block and the target is marked for processing using this state. ++ * When there are multiple ways to enter a basic block (e.g. several JMP ++ * instructions referencing the same target) then there will be multiple sets ++ * of register state to form the "input" for that basic block, there is no ++ * guarantee that all paths to that block will have the same register state. ++ * ++ * As each target block is processed, all the known sets of register state are ++ * merged to form a suitable subset of the state which agrees with all the ++ * inputs. The most common case is where one path to this block copies a ++ * register to another register but another path does not, therefore the copy ++ * is only a temporary and should not be propogated into this block. ++ * ++ * If the target block already has an input state from the current transfer ++ * point and the new input state is identical to the previous input state then ++ * we have reached a steady state for the arc from the current location to the ++ * target block. Therefore there is no need to process the target block again. ++ * ++ * The steps of "process a block, create state for target block(s), pick a new ++ * target block, merge state for target block, process target block" will ++ * continue until all the state changes have propogated all the way down the ++ * basic block tree, including round any cycles in the tree. The merge step ++ * only deletes tracking entries from the input state(s), it never adds a ++ * tracking entry. Therefore the overall algorithm is guaranteed to converge ++ * to a steady state, the worst possible case is that every tracking entry into ++ * a block is deleted, which will result in an empty output state. ++ * ++ * As each instruction is decoded, it is checked to see if this is the point at ++ * which execution left this function. This can be a call to another function ++ * (actually the return address to this function) or is the instruction which ++ * was about to be executed when an interrupt occurred (including an oops). ++ * Save the register state at this point. ++ * ++ * We always know what the registers contain when execution left this function. ++ * For an interrupt, the registers are in struct pt_regs. For a call to ++ * another function, we have already deduced the register state on entry to the ++ * other function by unwinding to the start of that function. Given the ++ * register state on exit from this function plus the known register contents ++ * on entry to the next function, we can determine the stack pointer value on ++ * input to this function. That in turn lets us calculate the address of input ++ * registers that have been stored on stack, giving us the input parameters. ++ * Finally the stack pointer gives us the return address which is the exit ++ * point from the calling function, repeat the unwind process on that function. ++ * ++ * The data that tracks which registers contain input parameters is function ++ * global, not local to any basic block. To determine which input registers ++ * contain parameters, we have to decode the entire function. Otherwise an ++ * exit early in the function might not have read any parameters yet. ++ */ ++ ++/* Record memory contents in terms of the values that were passed to this ++ * function, IOW track which memory locations contain an input value. A memory ++ * location's contents can be undefined, it can contain an input register value ++ * or it can contain an offset from the original stack pointer. ++ * ++ * This structure is used to record register contents that have been stored in ++ * memory. Location (BBRG_OSP + 'offset_address') contains the input value ++ * from register 'value'. When 'value' is BBRG_OSP then offset_value contains ++ * the offset from the original stack pointer that was stored in this memory ++ * location. When 'value' is not BBRG_OSP then the memory location contains ++ * the original contents of an input register and offset_value is ignored. ++ * ++ * An input register 'value' can be stored in more than one register and/or in ++ * more than one memory location. ++ */ ++ ++struct bb_memory_contains ++{ ++ short offset_address; ++ enum bb_reg_code value: 8; ++ short offset_value; ++}; ++ ++/* Track the register state in each basic block. */ ++ ++struct bb_reg_state ++{ ++ /* Indexed by register value 'reg - BBRG_RAX' */ ++ struct bb_reg_contains contains[KDB_INT_REGISTERS]; ++ int ref_count; ++ int mem_count; ++ /* dynamic size for memory locations, see mem_count */ ++ struct bb_memory_contains memory[0]; ++}; ++ ++static struct bb_reg_state *bb_reg_state, *bb_exit_state; ++static int bb_reg_state_max, bb_reg_params, bb_memory_params; ++ ++struct bb_actual ++{ ++ bfd_vma value; ++ int valid; ++}; ++ ++/* Contains the actual hex value of a register, plus a valid bit. Indexed by ++ * register value 'reg - BBRG_RAX' ++ */ ++static struct bb_actual bb_actual[KDB_INT_REGISTERS]; ++ ++static bfd_vma bb_func_start, bb_func_end; ++static bfd_vma bb_common_interrupt, bb_error_entry, bb_ret_from_intr, ++ bb_thread_return, bb_sync_regs, bb_save_v86_state, ++ bb__sched_text_start, bb__sched_text_end; ++ ++/* Record jmp instructions, both conditional and unconditional. These form the ++ * arcs between the basic blocks. This is also used to record the state when ++ * one block drops through into the next. ++ * ++ * A bb can have multiple associated bb_jmp entries, one for each jcc ++ * instruction plus at most one bb_jmp for the drop through case. If a bb ++ * drops through to the next bb then the drop through bb_jmp entry will be the ++ * last entry in the set of bb_jmp's that are associated with the bb. This is ++ * enforced by the fact that jcc entries are added during the disassembly phase ++ * of pass 1, the drop through entries are added near the end of pass 1. ++ * ++ * At address 'from' in this block, we have a jump to address 'to'. The ++ * register state at 'from' is copied to the target block. ++ */ ++ ++struct bb_jmp ++{ ++ bfd_vma from; ++ bfd_vma to; ++ struct bb_reg_state *state; ++ unsigned int drop_through: 1; ++}; ++ ++struct bb ++{ ++ bfd_vma start; ++ /* The end address of a basic block is sloppy. It can be the first ++ * byte of the last instruction in the block or it can be the last byte ++ * of the block. ++ */ ++ bfd_vma end; ++ unsigned int changed: 1; ++ unsigned int drop_through: 1; ++}; ++ ++static struct bb **bb_list, *bb_curr; ++static int bb_max, bb_count; ++ ++static struct bb_jmp *bb_jmp_list; ++static int bb_jmp_max, bb_jmp_count; ++ ++/* Add a new bb entry to the list. This does an insert sort. */ ++ ++static struct bb * ++bb_new(bfd_vma order) ++{ ++ int i, j; ++ struct bb *bb, *p; ++ if (bb_giveup) ++ return NULL; ++ if (bb_count == bb_max) { ++ struct bb **bb_list_new; ++ bb_max += 10; ++ bb_list_new = debug_kmalloc(bb_max*sizeof(*bb_list_new), ++ GFP_ATOMIC); ++ if (!bb_list_new) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", __FUNCTION__); ++ bb_giveup = 1; ++ return NULL; ++ } ++ memcpy(bb_list_new, bb_list, bb_count*sizeof(*bb_list)); ++ debug_kfree(bb_list); ++ bb_list = bb_list_new; ++ } ++ bb = debug_kmalloc(sizeof(*bb), GFP_ATOMIC); ++ if (!bb) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", __FUNCTION__); ++ bb_giveup = 1; ++ return NULL; ++ } ++ memset(bb, 0, sizeof(*bb)); ++ for (i = 0; i < bb_count; ++i) { ++ p = bb_list[i]; ++ if ((p->start && p->start > order) || ++ (p->end && p->end > order)) ++ break; ++ } ++ for (j = bb_count-1; j >= i; --j) ++ bb_list[j+1] = bb_list[j]; ++ bb_list[i] = bb; ++ ++bb_count; ++ return bb; ++} ++ ++/* Add a new bb_jmp entry to the list. This list is not sorted. */ ++ ++static struct bb_jmp * ++bb_jmp_new(bfd_vma from, bfd_vma to, unsigned int drop_through) ++{ ++ struct bb_jmp *bb_jmp; ++ if (bb_giveup) ++ return NULL; ++ if (bb_jmp_count == bb_jmp_max) { ++ struct bb_jmp *bb_jmp_list_new; ++ bb_jmp_max += 10; ++ bb_jmp_list_new = ++ debug_kmalloc(bb_jmp_max*sizeof(*bb_jmp_list_new), ++ GFP_ATOMIC); ++ if (!bb_jmp_list_new) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", ++ __FUNCTION__); ++ bb_giveup = 1; ++ return NULL; ++ } ++ memcpy(bb_jmp_list_new, bb_jmp_list, ++ bb_jmp_count*sizeof(*bb_jmp_list)); ++ debug_kfree(bb_jmp_list); ++ bb_jmp_list = bb_jmp_list_new; ++ } ++ bb_jmp = bb_jmp_list + bb_jmp_count++; ++ bb_jmp->from = from; ++ bb_jmp->to = to; ++ bb_jmp->drop_through = drop_through; ++ bb_jmp->state = NULL; ++ return bb_jmp; ++} ++ ++static void ++bb_delete(int i) ++{ ++ struct bb *bb = bb_list[i]; ++ memcpy(bb_list+i, bb_list+i+1, (bb_count-i-1)*sizeof(*bb_list)); ++ bb_list[--bb_count] = NULL; ++ debug_kfree(bb); ++} ++ ++static struct bb * ++bb_add(bfd_vma start, bfd_vma end) ++{ ++ int i; ++ struct bb *bb; ++ /* Ignore basic blocks whose start address is outside the current ++ * function. These occur for call instructions and for tail recursion. ++ */ ++ if (start && ++ (start < bb_func_start || start >= bb_func_end)) ++ return NULL; ++ for (i = 0; i < bb_count; ++i) { ++ bb = bb_list[i]; ++ if ((start && bb->start == start) || ++ (end && bb->end == end)) ++ return bb; ++ } ++ bb = bb_new(start ? start : end); ++ if (bb) { ++ bb->start = start; ++ bb->end = end; ++ } ++ return bb; ++} ++ ++static struct bb_jmp * ++bb_jmp_add(bfd_vma from, bfd_vma to, unsigned int drop_through) ++{ ++ int i; ++ struct bb_jmp *bb_jmp; ++ for (i = 0, bb_jmp = bb_jmp_list; i < bb_jmp_count; ++i, ++bb_jmp) { ++ if (bb_jmp->from == from && ++ bb_jmp->to == to && ++ bb_jmp->drop_through == drop_through) ++ return bb_jmp; ++ } ++ bb_jmp = bb_jmp_new(from, to, drop_through); ++ return bb_jmp; ++} ++ ++static unsigned long bb_curr_addr, bb_exit_addr; ++static char bb_buffer[256]; /* A bit too big to go on stack */ ++ ++/* Computed jmp uses 'jmp *addr(,%reg,[48])' where 'addr' is the start of a ++ * table of addresses that point into the current function. Run the table and ++ * generate bb starts for each target address plus a bb_jmp from this address ++ * to the target address. ++ * ++ * Only called for 'jmp' instructions, with the pointer starting at 'jmp'. ++ */ ++ ++static void ++bb_pass1_computed_jmp(char *p) ++{ ++ unsigned long table, scale; ++ kdb_machreg_t addr; ++ struct bb* bb; ++ p += strcspn(p, " \t"); /* end of instruction */ ++ p += strspn(p, " \t"); /* start of address */ ++ if (*p++ != '*') ++ return; ++ table = simple_strtoul(p, &p, 0); ++ if (strncmp(p, "(,%", 3) != 0) ++ return; ++ p += 3; ++ p += strcspn(p, ","); /* end of reg */ ++ if (*p++ != ',') ++ return; ++ scale = simple_strtoul(p, &p, 0); ++ if (scale != KDB_WORD_SIZE || strcmp(p, ")")) ++ return; ++ while (!bb_giveup) { ++ if (kdb_getword(&addr, table, sizeof(addr))) ++ return; ++ if (addr < bb_func_start || addr >= bb_func_end) ++ return; ++ bb = bb_add(addr, 0); ++ if (bb) ++ bb_jmp_add(bb_curr_addr, addr, 0); ++ table += KDB_WORD_SIZE; ++ } ++} ++ ++/* Pass 1, identify the start and end of each basic block */ ++ ++static int ++bb_dis_pass1(PTR file, const char *fmt, ...) ++{ ++ int l = strlen(bb_buffer); ++ char *p; ++ va_list ap; ++ va_start(ap, fmt); ++ vsnprintf(bb_buffer + l, sizeof(bb_buffer) - l, fmt, ap); ++ va_end(ap); ++ if ((p = strchr(bb_buffer, '\n'))) { ++ *p = '\0'; ++ /* ret[q], iret[q], sysexit, sysret, ud2a or jmp[q] end a ++ * block. As does a call to a function marked noret. ++ */ ++ p = bb_buffer; ++ p += strcspn(p, ":"); ++ if (*p++ == ':') { ++ bb_fixup_switch_to(p); ++ p += strspn(p, " \t"); /* start of instruction */ ++ if (strncmp(p, "ret", 3) == 0 || ++ strncmp(p, "iret", 4) == 0 || ++ strncmp(p, "sysexit", 7) == 0 || ++ strncmp(p, "sysret", 6) == 0 || ++ strncmp(p, "ud2a", 4) == 0 || ++ strncmp(p, "jmp", 3) == 0) { ++ if (strncmp(p, "jmp", 3) == 0) ++ bb_pass1_computed_jmp(p); ++ bb_add(0, bb_curr_addr); ++ }; ++ if (strncmp(p, "call", 4) == 0) { ++ strsep(&p, " \t"); /* end of opcode */ ++ if (p) ++ p += strspn(p, " \t"); /* operand(s) */ ++ if (p && strchr(p, '<')) { ++ p = strchr(p, '<') + 1; ++ *strchr(p, '>') = '\0'; ++ if (bb_noret(p)) ++ bb_add(0, bb_curr_addr); ++ } ++ }; ++ } ++ bb_buffer[0] = '\0'; ++ } ++ return 0; ++} ++ ++static void ++bb_printaddr_pass1(bfd_vma addr, disassemble_info *dip) ++{ ++ kdb_symtab_t symtab; ++ unsigned int offset; ++ struct bb* bb; ++ /* disasm only calls the printaddr routine for the target of jmp, loop ++ * or call instructions, i.e. the start of a basic block. call is ++ * ignored by bb_add because the target address is outside the current ++ * function. ++ */ ++ dip->fprintf_func(dip->stream, "0x%lx", addr); ++ kdbnearsym(addr, &symtab); ++ if (symtab.sym_name) { ++ dip->fprintf_func(dip->stream, " <%s", symtab.sym_name); ++ if ((offset = addr - symtab.sym_start)) ++ dip->fprintf_func(dip->stream, "+0x%x", offset); ++ dip->fprintf_func(dip->stream, ">"); ++ } ++ bb = bb_add(addr, 0); ++ if (bb) ++ bb_jmp_add(bb_curr_addr, addr, 0); ++} ++ ++static void ++bb_pass1(void) ++{ ++ int i; ++ unsigned long addr; ++ struct bb *bb; ++ struct bb_jmp *bb_jmp; ++ ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf("%s: func_name %s func_start " kdb_bfd_vma_fmt0 ++ " func_end " kdb_bfd_vma_fmt0 "\n", ++ __FUNCTION__, ++ bb_func_name, ++ bb_func_start, ++ bb_func_end); ++ kdb_di.fprintf_func = bb_dis_pass1; ++ kdb_di.print_address_func = bb_printaddr_pass1; ++ ++ bb_add(bb_func_start, 0); ++ for (bb_curr_addr = bb_func_start; ++ bb_curr_addr < bb_func_end; ++ ++bb_curr_addr) { ++ unsigned char c; ++ if (kdb_getarea(c, bb_curr_addr)) { ++ kdb_printf("%s: unreadable function code at ", ++ __FUNCTION__); ++ kdb_symbol_print(bb_curr_addr, NULL, KDB_SP_DEFAULT); ++ kdb_printf(", giving up\n"); ++ bb_giveup = 1; ++ return; ++ } ++ } ++ for (addr = bb_func_start; addr < bb_func_end; ) { ++ bb_curr_addr = addr; ++ addr += kdba_id_printinsn(addr, &kdb_di); ++ kdb_di.fprintf_func(NULL, "\n"); ++ } ++ if (bb_giveup) ++ goto out; ++ ++ /* Special case: a block consisting of a single instruction which is ++ * both the target of a jmp and is also an ending instruction, so we ++ * add two blocks using the same address, one as a start and one as an ++ * end, in no guaranteed order. The end must be ordered after the ++ * start. ++ */ ++ for (i = 0; i < bb_count-1; ++i) { ++ struct bb *bb1 = bb_list[i], *bb2 = bb_list[i+1]; ++ if (bb1->end && bb1->end == bb2->start) { ++ bb = bb_list[i+1]; ++ bb_list[i+1] = bb_list[i]; ++ bb_list[i] = bb; ++ } ++ } ++ ++ /* Some bb have a start address, some have an end address. Collapse ++ * them into entries that have both start and end addresses. The first ++ * entry is guaranteed to have a start address. ++ */ ++ for (i = 0; i < bb_count-1; ++i) { ++ struct bb *bb1 = bb_list[i], *bb2 = bb_list[i+1]; ++ if (bb1->end) ++ continue; ++ if (bb2->start) { ++ bb1->end = bb2->start - 1; ++ bb1->drop_through = 1; ++ bb_jmp_add(bb1->end, bb2->start, 1); ++ } else { ++ bb1->end = bb2->end; ++ bb_delete(i+1); ++ } ++ } ++ bb = bb_list[bb_count-1]; ++ if (!bb->end) ++ bb->end = bb_func_end - 1; ++ ++ /* It would be nice to check that all bb have a valid start and end ++ * address but there is just too much garbage code in the kernel to do ++ * that check. Aligned functions in assembler code mean that there is ++ * space between the end of one function and the start of the next and ++ * that space contains previous code from the assembler's buffers. It ++ * looks like dead code with nothing that branches to it, so no start ++ * address. do_sys_vm86() ends with 'jmp resume_userspace' which the C ++ * compiler does not know about so gcc appends the normal exit code, ++ * again nothing branches to this dangling code. ++ * ++ * The best we can do is delete bb entries with no start address. ++ */ ++ for (i = 0; i < bb_count; ++i) { ++ struct bb *bb = bb_list[i]; ++ if (!bb->start) ++ bb_delete(i--); ++ } ++ for (i = 0; i < bb_count; ++i) { ++ struct bb *bb = bb_list[i]; ++ if (!bb->end) { ++ kdb_printf("%s: incomplete bb state\n", __FUNCTION__); ++ bb_giveup = 1; ++ goto debug; ++ } ++ } ++ ++out: ++ if (!KDB_DEBUG(BB)) ++ return; ++debug: ++ kdb_printf("%s: end\n", __FUNCTION__); ++ for (i = 0; i < bb_count; ++i) { ++ bb = bb_list[i]; ++ kdb_printf(" bb[%d] start " ++ kdb_bfd_vma_fmt0 ++ " end " kdb_bfd_vma_fmt0 ++ " drop_through %d", ++ i, bb->start, bb->end, bb->drop_through); ++ kdb_printf("\n"); ++ } ++ for (i = 0; i < bb_jmp_count; ++i) { ++ bb_jmp = bb_jmp_list + i; ++ kdb_printf(" bb_jmp[%d] from " ++ kdb_bfd_vma_fmt0 ++ " to " kdb_bfd_vma_fmt0 ++ " drop_through %d\n", ++ i, bb_jmp->from, bb_jmp->to, bb_jmp->drop_through); ++ } ++} ++ ++/* Pass 2, record register changes in each basic block */ ++ ++/* For each opcode that we care about, indicate how it uses its operands. Most ++ * opcodes can be handled generically because they completely specify their ++ * operands in the instruction, however many opcodes have side effects such as ++ * reading or writing rax or updating rsp. Instructions that change registers ++ * that are not listed in the operands must be handled as special cases. In ++ * addition, instructions that copy registers while preserving their contents ++ * (push, pop, mov) or change the contents in a well defined way (add with an ++ * immediate, lea) must be handled as special cases in order to track the ++ * register contents. ++ * ++ * The tables below only list opcodes that are actually used in the Linux ++ * kernel, so they omit most of the floating point and all of the SSE type ++ * instructions. The operand usage entries only cater for accesses to memory ++ * and to the integer registers, accesses to floating point registers and flags ++ * are not relevant for kernel backtraces. ++ */ ++ ++enum bb_operand_usage { ++ BBOU_UNKNOWN = 0, ++ /* generic entries. because xchg can do any combinations of ++ * read src, write src, read dst and write dst we need to ++ * define all 16 possibilities. These are ordered by rs = 1, ++ * rd = 2, ws = 4, wd = 8, bb_usage_x*() functions rely on this ++ * order. ++ */ ++ BBOU_RS = 1, /* read src */ /* 1 */ ++ BBOU_RD, /* read dst */ /* 2 */ ++ BBOU_RSRD, /* 3 */ ++ BBOU_WS, /* write src */ /* 4 */ ++ BBOU_RSWS, /* 5 */ ++ BBOU_RDWS, /* 6 */ ++ BBOU_RSRDWS, /* 7 */ ++ BBOU_WD, /* write dst */ /* 8 */ ++ BBOU_RSWD, /* 9 */ ++ BBOU_RDWD, /* 10 */ ++ BBOU_RSRDWD, /* 11 */ ++ BBOU_WSWD, /* 12 */ ++ BBOU_RSWSWD, /* 13 */ ++ BBOU_RDWSWD, /* 14 */ ++ BBOU_RSRDWSWD, /* 15 */ ++ /* opcode specific entries */ ++ BBOU_ADD, ++ BBOU_CALL, ++ BBOU_CBW, ++ BBOU_CMOV, ++ BBOU_CMPXCHG, ++ BBOU_CMPXCHGD, ++ BBOU_CPUID, ++ BBOU_CWD, ++ BBOU_DIV, ++ BBOU_IDIV, ++ BBOU_IMUL, ++ BBOU_IRET, ++ BBOU_JMP, ++ BBOU_LAHF, ++ BBOU_LEA, ++ BBOU_LEAVE, ++ BBOU_LODS, ++ BBOU_LOOP, ++ BBOU_LSS, ++ BBOU_MONITOR, ++ BBOU_MOV, ++ BBOU_MOVS, ++ BBOU_MUL, ++ BBOU_MWAIT, ++ BBOU_NOP, ++ BBOU_OUTS, ++ BBOU_POP, ++ BBOU_POPF, ++ BBOU_PUSH, ++ BBOU_PUSHF, ++ BBOU_RDMSR, ++ BBOU_RDTSC, ++ BBOU_RET, ++ BBOU_SAHF, ++ BBOU_SCAS, ++ BBOU_SUB, ++ BBOU_SYSEXIT, ++ BBOU_SYSRET, ++ BBOU_WRMSR, ++ BBOU_XADD, ++ BBOU_XCHG, ++ BBOU_XOR, ++}; ++ ++struct bb_opcode_usage { ++ int length; ++ enum bb_operand_usage usage; ++ const char *opcode; ++}; ++ ++/* This table is sorted in alphabetical order of opcode, except that the ++ * trailing '"' is treated as a high value. For example, 'in' sorts after ++ * 'inc', 'bt' after 'btc'. This modified sort order ensures that shorter ++ * opcodes come after long ones. A normal sort would put 'in' first, so 'in' ++ * would match both 'inc' and 'in'. When adding any new entries to this table, ++ * be careful to put shorter entries last in their group. ++ * ++ * To automatically sort the table (in vi) ++ * Mark the first and last opcode line with 'a and 'b ++ * 'a ++ * !'bsed -e 's/"}/}}/' | LANG=C sort -t '"' -k2 | sed -e 's/}}/"}/' ++ * ++ * If a new instruction has to be added, first consider if it affects registers ++ * other than those listed in the operands. Also consider if you want to track ++ * the results of issuing the instruction, IOW can you extract useful ++ * information by looking in detail at the modified registers or memory. If ++ * either test is true then you need a special case to handle the instruction. ++ * ++ * The generic entries at the start of enum bb_operand_usage all have one thing ++ * in common, if a register or memory location is updated then that location ++ * becomes undefined, i.e. we lose track of anything that was previously saved ++ * in that location. So only use a generic BBOU_* value when the result of the ++ * instruction cannot be calculated exactly _and_ when all the affected ++ * registers are listed in the operands. ++ * ++ * Examples: ++ * ++ * 'call' does not generate a known result, but as a side effect of call, ++ * several scratch registers become undefined, so it needs a special BBOU_CALL ++ * entry. ++ * ++ * 'adc' generates a variable result, it depends on the carry flag, so 'adc' ++ * gets a generic entry. 'add' can generate an exact result (add with ++ * immediate on a register that points to the stack) or it can generate an ++ * unknown result (add a variable, or add immediate to a register that does not ++ * contain a stack pointer) so 'add' has its own BBOU_ADD entry. ++ */ ++ ++static const struct bb_opcode_usage ++bb_opcode_usage_all[] = { ++ {3, BBOU_RSRDWD, "adc"}, ++ {3, BBOU_ADD, "add"}, ++ {3, BBOU_RSRDWD, "and"}, ++ {3, BBOU_RSWD, "bsf"}, ++ {3, BBOU_RSWD, "bsr"}, ++ {5, BBOU_RSWS, "bswap"}, ++ {3, BBOU_RSRDWD, "btc"}, ++ {3, BBOU_RSRDWD, "btr"}, ++ {3, BBOU_RSRDWD, "bts"}, ++ {2, BBOU_RSRD, "bt"}, ++ {4, BBOU_CALL, "call"}, ++ {4, BBOU_CBW, "cbtw"}, /* Intel cbw */ ++ {3, BBOU_NOP, "clc"}, ++ {3, BBOU_NOP, "cld"}, ++ {7, BBOU_RS, "clflush"}, ++ {4, BBOU_NOP, "clgi"}, ++ {3, BBOU_NOP, "cli"}, ++ {4, BBOU_CWD, "cltd"}, /* Intel cdq */ ++ {4, BBOU_CBW, "cltq"}, /* Intel cdqe */ ++ {4, BBOU_NOP, "clts"}, ++ {4, BBOU_CMOV, "cmov"}, ++ {9, BBOU_CMPXCHGD,"cmpxchg16"}, ++ {8, BBOU_CMPXCHGD,"cmpxchg8"}, ++ {7, BBOU_CMPXCHG, "cmpxchg"}, ++ {3, BBOU_RSRD, "cmp"}, ++ {5, BBOU_CPUID, "cpuid"}, ++ {4, BBOU_CWD, "cqto"}, /* Intel cdo */ ++ {4, BBOU_CWD, "cwtd"}, /* Intel cwd */ ++ {4, BBOU_CBW, "cwtl"}, /* Intel cwde */ ++ {4, BBOU_NOP, "data"}, /* alternative ASM_NOP generates data16 on x86_64 */ ++ {3, BBOU_RSWS, "dec"}, ++ {3, BBOU_DIV, "div"}, ++ {5, BBOU_RS, "fdivl"}, ++ {5, BBOU_NOP, "finit"}, ++ {6, BBOU_RS, "fistpl"}, ++ {4, BBOU_RS, "fldl"}, ++ {4, BBOU_RS, "fmul"}, ++ {6, BBOU_NOP, "fnclex"}, ++ {6, BBOU_NOP, "fninit"}, ++ {6, BBOU_RS, "fnsave"}, ++ {7, BBOU_NOP, "fnsetpm"}, ++ {6, BBOU_RS, "frstor"}, ++ {5, BBOU_WS, "fstsw"}, ++ {5, BBOU_RS, "fsubp"}, ++ {5, BBOU_NOP, "fwait"}, ++ {7, BBOU_RS, "fxrstor"}, ++ {6, BBOU_RS, "fxsave"}, ++ {3, BBOU_NOP, "hlt"}, ++ {4, BBOU_IDIV, "idiv"}, ++ {4, BBOU_IMUL, "imul"}, ++ {3, BBOU_RSWS, "inc"}, ++ {3, BBOU_NOP, "int"}, ++ {7, BBOU_RSRD, "invlpga"}, ++ {6, BBOU_RS, "invlpg"}, ++ {2, BBOU_RSWD, "in"}, ++ {4, BBOU_IRET, "iret"}, ++ {1, BBOU_JMP, "j"}, ++ {4, BBOU_LAHF, "lahf"}, ++ {3, BBOU_RSWD, "lar"}, ++ {5, BBOU_RS, "lcall"}, ++ {5, BBOU_LEAVE, "leave"}, ++ {3, BBOU_LEA, "lea"}, ++ {6, BBOU_NOP, "lfence"}, ++ {4, BBOU_RS, "lgdt"}, ++ {4, BBOU_RS, "lidt"}, ++ {4, BBOU_RS, "ljmp"}, ++ {4, BBOU_RS, "lldt"}, ++ {4, BBOU_RS, "lmsw"}, ++ {4, BBOU_LODS, "lods"}, ++ {4, BBOU_LOOP, "loop"}, ++ {4, BBOU_NOP, "lret"}, ++ {3, BBOU_RSWD, "lsl"}, ++ {3, BBOU_LSS, "lss"}, ++ {3, BBOU_RS, "ltr"}, ++ {6, BBOU_NOP, "mfence"}, ++ {7, BBOU_MONITOR, "monitor"}, ++ {4, BBOU_MOVS, "movs"}, ++ {3, BBOU_MOV, "mov"}, ++ {3, BBOU_MUL, "mul"}, ++ {5, BBOU_MWAIT, "mwait"}, ++ {3, BBOU_RSWS, "neg"}, ++ {3, BBOU_NOP, "nop"}, ++ {3, BBOU_RSWS, "not"}, ++ {2, BBOU_RSRDWD, "or"}, ++ {4, BBOU_OUTS, "outs"}, ++ {3, BBOU_RSRD, "out"}, ++ {5, BBOU_NOP, "pause"}, ++ {4, BBOU_POPF, "popf"}, ++ {3, BBOU_POP, "pop"}, ++ {8, BBOU_RS, "prefetch"}, ++ {5, BBOU_PUSHF, "pushf"}, ++ {4, BBOU_PUSH, "push"}, ++ {3, BBOU_RSRDWD, "rcl"}, ++ {3, BBOU_RSRDWD, "rcr"}, ++ {5, BBOU_RDMSR, "rdmsr"}, ++ {5, BBOU_RDMSR, "rdpmc"}, /* same side effects as rdmsr */ ++ {5, BBOU_RDTSC, "rdtsc"}, ++ {3, BBOU_RET, "ret"}, ++ {3, BBOU_RSRDWD, "rol"}, ++ {3, BBOU_RSRDWD, "ror"}, ++ {4, BBOU_SAHF, "sahf"}, ++ {3, BBOU_RSRDWD, "sar"}, ++ {3, BBOU_RSRDWD, "sbb"}, ++ {4, BBOU_SCAS, "scas"}, ++ {3, BBOU_WS, "set"}, ++ {6, BBOU_NOP, "sfence"}, ++ {4, BBOU_WS, "sgdt"}, ++ {3, BBOU_RSRDWD, "shl"}, ++ {3, BBOU_RSRDWD, "shr"}, ++ {4, BBOU_WS, "sidt"}, ++ {4, BBOU_WS, "sldt"}, ++ {3, BBOU_NOP, "stc"}, ++ {3, BBOU_NOP, "std"}, ++ {4, BBOU_NOP, "stgi"}, ++ {3, BBOU_NOP, "sti"}, ++ {4, BBOU_SCAS, "stos"}, ++ {4, BBOU_WS, "strl"}, ++ {3, BBOU_WS, "str"}, ++ {3, BBOU_SUB, "sub"}, ++ {6, BBOU_NOP, "swapgs"}, ++ {7, BBOU_SYSEXIT, "sysexit"}, ++ {6, BBOU_SYSRET, "sysret"}, ++ {4, BBOU_NOP, "test"}, ++ {4, BBOU_NOP, "ud2a"}, ++ {7, BBOU_RS, "vmclear"}, ++ {8, BBOU_NOP, "vmlaunch"}, ++ {6, BBOU_RS, "vmload"}, ++ {7, BBOU_RS, "vmptrld"}, ++ {6, BBOU_WD, "vmread"}, /* vmread src is an encoding, not a register */ ++ {8, BBOU_NOP, "vmresume"}, ++ {5, BBOU_RS, "vmrun"}, ++ {6, BBOU_RS, "vmsave"}, ++ {7, BBOU_WD, "vmwrite"}, /* vmwrite src is an encoding, not a register */ ++ {6, BBOU_NOP, "wbinvd"}, ++ {5, BBOU_WRMSR, "wrmsr"}, ++ {4, BBOU_XADD, "xadd"}, ++ {4, BBOU_XCHG, "xchg"}, ++ {3, BBOU_XOR, "xor"}, ++ {10, BBOU_WS, "xstore-rng"}, ++}; ++ ++/* To speed up searching, index bb_opcode_usage_all by the first letter of each ++ * opcode. ++ */ ++static struct { ++ const struct bb_opcode_usage *opcode; ++ int size; ++} bb_opcode_usage[26]; ++ ++struct bb_operand { ++ char *base; ++ char *index; ++ char *segment; ++ long disp; ++ unsigned int scale; ++ enum bb_reg_code base_rc; /* UNDEFINED or RAX through R15 */ ++ enum bb_reg_code index_rc; /* UNDEFINED or RAX through R15 */ ++ unsigned int present :1; ++ unsigned int disp_present :1; ++ unsigned int indirect :1; /* must be combined with reg or memory */ ++ unsigned int immediate :1; /* exactly one of these 3 must be set */ ++ unsigned int reg :1; ++ unsigned int memory :1; ++}; ++ ++struct bb_decode { ++ char *prefix; ++ char *opcode; ++ const struct bb_opcode_usage *match; ++ struct bb_operand src; ++ struct bb_operand dst; ++ struct bb_operand dst2; ++}; ++ ++static struct bb_decode bb_decode; ++ ++static enum bb_reg_code ++bb_reg_map(const char *reg) ++{ ++ int lo, hi, c; ++ const struct bb_reg_code_map *p; ++ lo = 0; ++ hi = ARRAY_SIZE(bb_reg_code_map) - 1; ++ while (lo <= hi) { ++ int mid = (hi + lo) / 2; ++ p = bb_reg_code_map + mid; ++ c = strcmp(p->name, reg+1); ++ if (c == 0) ++ return p->reg; ++ else if (c > 0) ++ hi = mid - 1; ++ else ++ lo = mid + 1; ++ } ++ return BBRG_UNDEFINED; ++} ++ ++static void ++bb_parse_operand(char *str, struct bb_operand *operand) ++{ ++ char *p = str; ++ int sign = 1; ++ operand->present = 1; ++ /* extract any segment prefix */ ++ if (p[0] == '%' && p[1] && p[2] == 's' && p[3] == ':') { ++ operand->memory = 1; ++ operand->segment = p; ++ p[3] = '\0'; ++ p += 4; ++ } ++ /* extract displacement, base, index, scale */ ++ if (*p == '*') { ++ /* jmp/call *disp(%reg), *%reg or *0xnnn */ ++ operand->indirect = 1; ++ ++p; ++ } ++ if (*p == '-') { ++ sign = -1; ++ ++p; ++ } ++ if (*p == '$') { ++ operand->immediate = 1; ++ operand->disp_present = 1; ++ operand->disp = simple_strtoul(p+1, &p, 0); ++ } else if (isdigit(*p)) { ++ operand->memory = 1; ++ operand->disp_present = 1; ++ operand->disp = simple_strtoul(p, &p, 0) * sign; ++ } ++ if (*p == '%') { ++ operand->reg = 1; ++ operand->base = p; ++ } else if (*p == '(') { ++ operand->memory = 1; ++ operand->base = ++p; ++ p += strcspn(p, ",)"); ++ if (p == operand->base) ++ operand->base = NULL; ++ if (*p == ',') { ++ *p = '\0'; ++ operand->index = ++p; ++ p += strcspn(p, ",)"); ++ if (p == operand->index) ++ operand->index = NULL; ++ } ++ if (*p == ',') { ++ *p = '\0'; ++ operand->scale = simple_strtoul(p+1, &p, 0); ++ } ++ *p = '\0'; ++ } else if (*p) { ++ kdb_printf("%s: unexpected token '%c' after disp '%s'\n", ++ __FUNCTION__, *p, str); ++ bb_giveup = 1; ++ } ++ if ((operand->immediate + operand->reg + operand->memory != 1) || ++ (operand->indirect && operand->immediate)) { ++ kdb_printf("%s: incorrect decode '%s' N %d I %d R %d M %d\n", ++ __FUNCTION__, str, ++ operand->indirect, operand->immediate, operand->reg, ++ operand->memory); ++ bb_giveup = 1; ++ } ++ if (operand->base) ++ operand->base_rc = bb_reg_map(operand->base); ++ if (operand->index) ++ operand->index_rc = bb_reg_map(operand->index); ++} ++ ++static void ++bb_print_operand(const char *type, const struct bb_operand *operand) ++{ ++ if (!operand->present) ++ return; ++ kdb_printf(" %s %c%c: ", ++ type, ++ operand->indirect ? 'N' : ' ', ++ operand->immediate ? 'I' : ++ operand->reg ? 'R' : ++ operand->memory ? 'M' : ++ '?' ++ ); ++ if (operand->segment) ++ kdb_printf("%s:", operand->segment); ++ if (operand->immediate) { ++ kdb_printf("$0x%lx", operand->disp); ++ } else if (operand->reg) { ++ if (operand->indirect) ++ kdb_printf("*"); ++ kdb_printf("%s", operand->base); ++ } else if (operand->memory) { ++ if (operand->indirect && (operand->base || operand->index)) ++ kdb_printf("*"); ++ if (operand->disp_present) { ++ kdb_printf("0x%lx", operand->disp); ++ } ++ if (operand->base || operand->index || operand->scale) { ++ kdb_printf("("); ++ if (operand->base) ++ kdb_printf("%s", operand->base); ++ if (operand->index || operand->scale) ++ kdb_printf(","); ++ if (operand->index) ++ kdb_printf("%s", operand->index); ++ if (operand->scale) ++ kdb_printf(",%d", operand->scale); ++ kdb_printf(")"); ++ } ++ } ++ if (operand->base_rc) ++ kdb_printf(" base_rc %d (%s)", ++ operand->base_rc, bbrg_name[operand->base_rc]); ++ if (operand->index_rc) ++ kdb_printf(" index_rc %d (%s)", ++ operand->index_rc, ++ bbrg_name[operand->index_rc]); ++ kdb_printf("\n"); ++} ++ ++static void ++bb_print_opcode(void) ++{ ++ const struct bb_opcode_usage *o = bb_decode.match; ++ kdb_printf(" "); ++ if (bb_decode.prefix) ++ kdb_printf("%s ", bb_decode.prefix); ++ kdb_printf("opcode '%s' matched by '%s', usage %d\n", ++ bb_decode.opcode, o->opcode, o->usage); ++} ++ ++static int ++bb_parse_opcode(void) ++{ ++ int c, i; ++ const struct bb_opcode_usage *o; ++ static int bb_parse_opcode_error_limit = 5; ++ c = bb_decode.opcode[0] - 'a'; ++ if (c < 0 || c >= ARRAY_SIZE(bb_opcode_usage)) ++ goto nomatch; ++ o = bb_opcode_usage[c].opcode; ++ if (!o) ++ goto nomatch; ++ for (i = 0; i < bb_opcode_usage[c].size; ++i, ++o) { ++ if (strncmp(bb_decode.opcode, o->opcode, o->length) == 0) { ++ bb_decode.match = o; ++ if (KDB_DEBUG(BB)) ++ bb_print_opcode(); ++ return 0; ++ } ++ } ++nomatch: ++ if (!bb_parse_opcode_error_limit) ++ return 1; ++ --bb_parse_opcode_error_limit; ++ kdb_printf("%s: no match at [%s]%s " kdb_bfd_vma_fmt0 " - '%s'\n", ++ __FUNCTION__, ++ bb_mod_name, bb_func_name, bb_curr_addr, ++ bb_decode.opcode); ++ return 1; ++} ++ ++static bool ++bb_is_int_reg(enum bb_reg_code reg) ++{ ++ return reg >= BBRG_RAX && reg < (BBRG_RAX + KDB_INT_REGISTERS); ++} ++ ++static bool ++bb_is_simple_memory(const struct bb_operand *operand) ++{ ++ return operand->memory && ++ bb_is_int_reg(operand->base_rc) && ++ !operand->index_rc && ++ operand->scale == 0 && ++ !operand->segment; ++} ++ ++static bool ++bb_is_static_disp(const struct bb_operand *operand) ++{ ++ return operand->memory && ++ !operand->base_rc && ++ !operand->index_rc && ++ operand->scale == 0 && ++ !operand->segment && ++ !operand->indirect; ++} ++ ++static enum bb_reg_code ++bb_reg_code_value(enum bb_reg_code reg) ++{ ++ BB_CHECK(!bb_is_int_reg(reg), reg, 0); ++ return bb_reg_state->contains[reg - BBRG_RAX].value; ++} ++ ++static short ++bb_reg_code_offset(enum bb_reg_code reg) ++{ ++ BB_CHECK(!bb_is_int_reg(reg), reg, 0); ++ return bb_reg_state->contains[reg - BBRG_RAX].offset; ++} ++ ++static void ++bb_reg_code_set_value(enum bb_reg_code dst, enum bb_reg_code src) ++{ ++ BB_CHECK(!bb_is_int_reg(dst), dst, ); ++ bb_reg_state->contains[dst - BBRG_RAX].value = src; ++} ++ ++static void ++bb_reg_code_set_offset(enum bb_reg_code dst, short offset) ++{ ++ BB_CHECK(!bb_is_int_reg(dst), dst, ); ++ bb_reg_state->contains[dst - BBRG_RAX].offset = offset; ++} ++ ++static bool ++bb_is_osp_defined(enum bb_reg_code reg) ++{ ++ if (bb_is_int_reg(reg)) ++ return bb_reg_code_value(reg) == BBRG_OSP; ++ else ++ return 0; ++} ++ ++static bfd_vma ++bb_actual_value(enum bb_reg_code reg) ++{ ++ BB_CHECK(!bb_is_int_reg(reg), reg, 0); ++ return bb_actual[reg - BBRG_RAX].value; ++} ++ ++static int ++bb_actual_valid(enum bb_reg_code reg) ++{ ++ BB_CHECK(!bb_is_int_reg(reg), reg, 0); ++ return bb_actual[reg - BBRG_RAX].valid; ++} ++ ++static void ++bb_actual_set_value(enum bb_reg_code reg, bfd_vma value) ++{ ++ BB_CHECK(!bb_is_int_reg(reg), reg, ); ++ bb_actual[reg - BBRG_RAX].value = value; ++} ++ ++static void ++bb_actual_set_valid(enum bb_reg_code reg, int valid) ++{ ++ BB_CHECK(!bb_is_int_reg(reg), reg, ); ++ bb_actual[reg - BBRG_RAX].valid = valid; ++} ++ ++/* The scheduler code switches RSP then does PUSH, it is not an error for RSP ++ * to be undefined in this area of the code. ++ */ ++static bool ++bb_is_scheduler_address(void) ++{ ++ return bb_curr_addr >= bb__sched_text_start && ++ bb_curr_addr < bb__sched_text_end; ++} ++ ++static void ++bb_reg_read(enum bb_reg_code reg) ++{ ++ int i, r = 0; ++ if (!bb_is_int_reg(reg) || ++ bb_reg_code_value(reg) != reg) ++ return; ++ for (i = 0; ++ i < min_t(unsigned int, REGPARM, ARRAY_SIZE(bb_param_reg)); ++ ++i) { ++ if (reg == bb_param_reg[i]) { ++ r = i + 1; ++ break; ++ } ++ } ++ bb_reg_params = max(bb_reg_params, r); ++} ++ ++static void ++bb_do_reg_state_print(const struct bb_reg_state *s) ++{ ++ int i, offset_address, offset_value; ++ const struct bb_memory_contains *c; ++ enum bb_reg_code value; ++ kdb_printf(" bb_reg_state %p\n", s); ++ for (i = 0; i < ARRAY_SIZE(s->contains); ++i) { ++ value = s->contains[i].value; ++ offset_value = s->contains[i].offset; ++ kdb_printf(" %s = %s", ++ bbrg_name[i + BBRG_RAX], bbrg_name[value]); ++ if (value == BBRG_OSP) ++ KDB_DEBUG_BB_OFFSET_PRINTF(offset_value, "", ""); ++ kdb_printf("\n"); ++ } ++ for (i = 0, c = s->memory; i < s->mem_count; ++i, ++c) { ++ offset_address = c->offset_address; ++ value = c->value; ++ offset_value = c->offset_value; ++ kdb_printf(" slot %d offset_address %c0x%x %s", ++ i, ++ offset_address >= 0 ? '+' : '-', ++ offset_address >= 0 ? offset_address : -offset_address, ++ bbrg_name[value]); ++ if (value == BBRG_OSP) ++ KDB_DEBUG_BB_OFFSET_PRINTF(offset_value, "", ""); ++ kdb_printf("\n"); ++ } ++} ++ ++static void ++bb_reg_state_print(const struct bb_reg_state *s) ++{ ++ if (KDB_DEBUG(BB)) ++ bb_do_reg_state_print(s); ++} ++ ++/* Set register 'dst' to contain the value from 'src'. This includes reading ++ * from 'src' and writing to 'dst'. The offset value is copied iff 'src' ++ * contains a stack pointer. ++ * ++ * Be very careful about the context here. 'dst' and 'src' reflect integer ++ * registers by name, _not_ by the value of their contents. "mov %rax,%rsi" ++ * will call this function as bb_reg_set_reg(BBRG_RSI, BBRG_RAX), which ++ * reflects what the assembler code is doing. However we need to track the ++ * _values_ in the registers, not their names. IOW, we really care about "what ++ * value does rax contain when it is copied into rsi?", so we can record the ++ * fact that we now have two copies of that value, one in rax and one in rsi. ++ */ ++ ++static void ++bb_reg_set_reg(enum bb_reg_code dst, enum bb_reg_code src) ++{ ++ enum bb_reg_code src_value = BBRG_UNDEFINED; ++ short offset_value = 0; ++ KDB_DEBUG_BB(" %s = %s", bbrg_name[dst], bbrg_name[src]); ++ if (bb_is_int_reg(src)) { ++ bb_reg_read(src); ++ src_value = bb_reg_code_value(src); ++ KDB_DEBUG_BB(" (%s", bbrg_name[src_value]); ++ if (bb_is_osp_defined(src)) { ++ offset_value = bb_reg_code_offset(src); ++ KDB_DEBUG_BB_OFFSET(offset_value, "", ""); ++ } ++ KDB_DEBUG_BB(")"); ++ } ++ if (bb_is_int_reg(dst)) { ++ bb_reg_code_set_value(dst, src_value); ++ bb_reg_code_set_offset(dst, offset_value); ++ } ++ KDB_DEBUG_BB("\n"); ++} ++ ++static void ++bb_reg_set_undef(enum bb_reg_code dst) ++{ ++ bb_reg_set_reg(dst, BBRG_UNDEFINED); ++} ++ ++/* Delete any record of a stored register held in osp + 'offset' */ ++ ++static void ++bb_delete_memory(short offset) ++{ ++ int i; ++ struct bb_memory_contains *c; ++ for (i = 0, c = bb_reg_state->memory; ++ i < bb_reg_state->mem_count; ++ ++i, ++c) { ++ if (c->offset_address == offset && ++ c->value != BBRG_UNDEFINED) { ++ KDB_DEBUG_BB(" delete %s from ", ++ bbrg_name[c->value]); ++ KDB_DEBUG_BB_OFFSET(offset, "osp", ""); ++ KDB_DEBUG_BB(" slot %d\n", ++ (int)(c - bb_reg_state->memory)); ++ memset(c, BBRG_UNDEFINED, sizeof(*c)); ++ if (i == bb_reg_state->mem_count - 1) ++ --bb_reg_state->mem_count; ++ } ++ } ++} ++ ++/* Set memory location *('dst' + 'offset_address') to contain the supplied ++ * value and offset. 'dst' is assumed to be a register that contains a stack ++ * pointer. ++ */ ++ ++static void ++bb_memory_set_reg_value(enum bb_reg_code dst, short offset_address, ++ enum bb_reg_code value, short offset_value) ++{ ++ int i; ++ struct bb_memory_contains *c, *free = NULL; ++ BB_CHECK(!bb_is_osp_defined(dst), dst, ); ++ KDB_DEBUG_BB(" *(%s", bbrg_name[dst]); ++ KDB_DEBUG_BB_OFFSET(offset_address, "", ""); ++ offset_address += bb_reg_code_offset(dst); ++ KDB_DEBUG_BB_OFFSET(offset_address, " osp", ") = "); ++ KDB_DEBUG_BB("%s", bbrg_name[value]); ++ if (value == BBRG_OSP) ++ KDB_DEBUG_BB_OFFSET(offset_value, "", ""); ++ for (i = 0, c = bb_reg_state->memory; ++ i < bb_reg_state_max; ++ ++i, ++c) { ++ if (c->offset_address == offset_address) ++ free = c; ++ else if (c->value == BBRG_UNDEFINED && !free) ++ free = c; ++ } ++ if (!free) { ++ struct bb_reg_state *new, *old = bb_reg_state; ++ size_t old_size, new_size; ++ int slot; ++ old_size = sizeof(*old) + bb_reg_state_max * ++ sizeof(old->memory[0]); ++ slot = bb_reg_state_max; ++ bb_reg_state_max += 5; ++ new_size = sizeof(*new) + bb_reg_state_max * ++ sizeof(new->memory[0]); ++ new = debug_kmalloc(new_size, GFP_ATOMIC); ++ if (!new) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", __FUNCTION__); ++ bb_giveup = 1; ++ } else { ++ memcpy(new, old, old_size); ++ memset((char *)new + old_size, BBRG_UNDEFINED, ++ new_size - old_size); ++ bb_reg_state = new; ++ debug_kfree(old); ++ free = bb_reg_state->memory + slot; ++ } ++ } ++ if (free) { ++ int slot = free - bb_reg_state->memory; ++ free->offset_address = offset_address; ++ free->value = value; ++ free->offset_value = offset_value; ++ KDB_DEBUG_BB(" slot %d", slot); ++ bb_reg_state->mem_count = max(bb_reg_state->mem_count, slot+1); ++ } ++ KDB_DEBUG_BB("\n"); ++} ++ ++/* Set memory location *('dst' + 'offset') to contain the value from register ++ * 'src'. 'dst' is assumed to be a register that contains a stack pointer. ++ * This differs from bb_memory_set_reg_value because it takes a src register ++ * which contains a value and possibly an offset, bb_memory_set_reg_value is ++ * passed the value and offset directly. ++ */ ++ ++static void ++bb_memory_set_reg(enum bb_reg_code dst, enum bb_reg_code src, ++ short offset_address) ++{ ++ int offset_value; ++ enum bb_reg_code value; ++ BB_CHECK(!bb_is_osp_defined(dst), dst, ); ++ if (!bb_is_int_reg(src)) ++ return; ++ value = bb_reg_code_value(src); ++ if (value == BBRG_UNDEFINED) { ++ bb_delete_memory(offset_address + bb_reg_code_offset(dst)); ++ return; ++ } ++ offset_value = bb_reg_code_offset(src); ++ bb_reg_read(src); ++ bb_memory_set_reg_value(dst, offset_address, value, offset_value); ++} ++ ++/* Set register 'dst' to contain the value from memory *('src' + offset_address). ++ * 'src' is assumed to be a register that contains a stack pointer. ++ */ ++ ++static void ++bb_reg_set_memory(enum bb_reg_code dst, enum bb_reg_code src, short offset_address) ++{ ++ int i, defined = 0; ++ struct bb_memory_contains *s; ++ BB_CHECK(!bb_is_osp_defined(src), src, ); ++ KDB_DEBUG_BB(" %s = *(%s", ++ bbrg_name[dst], bbrg_name[src]); ++ KDB_DEBUG_BB_OFFSET(offset_address, "", ")"); ++ offset_address += bb_reg_code_offset(src); ++ KDB_DEBUG_BB_OFFSET(offset_address, " (osp", ")"); ++ for (i = 0, s = bb_reg_state->memory; ++ i < bb_reg_state->mem_count; ++ ++i, ++s) { ++ if (s->offset_address == offset_address && bb_is_int_reg(dst)) { ++ bb_reg_code_set_value(dst, s->value); ++ KDB_DEBUG_BB(" value %s", bbrg_name[s->value]); ++ if (s->value == BBRG_OSP) { ++ bb_reg_code_set_offset(dst, s->offset_value); ++ KDB_DEBUG_BB_OFFSET(s->offset_value, "", ""); ++ } else { ++ bb_reg_code_set_offset(dst, 0); ++ } ++ defined = 1; ++ } ++ } ++ if (!defined) ++ bb_reg_set_reg(dst, BBRG_UNDEFINED); ++ else ++ KDB_DEBUG_BB("\n"); ++} ++ ++/* A generic read from an operand. */ ++ ++static void ++bb_read_operand(const struct bb_operand *operand) ++{ ++ int m = 0; ++ if (operand->base_rc) ++ bb_reg_read(operand->base_rc); ++ if (operand->index_rc) ++ bb_reg_read(operand->index_rc); ++ if (bb_is_simple_memory(operand) && ++ bb_is_osp_defined(operand->base_rc) && ++ bb_decode.match->usage != BBOU_LEA) { ++ m = (bb_reg_code_offset(operand->base_rc) + operand->disp + ++ KDB_WORD_SIZE - 1) / KDB_WORD_SIZE; ++ bb_memory_params = max(bb_memory_params, m); ++ } ++} ++ ++/* A generic write to an operand, resulting in an undefined value in that ++ * location. All well defined operands are handled separately, this function ++ * only handles the opcodes where the result is undefined. ++ */ ++ ++static void ++bb_write_operand(const struct bb_operand *operand) ++{ ++ enum bb_reg_code base_rc = operand->base_rc; ++ if (operand->memory) { ++ if (base_rc) ++ bb_reg_read(base_rc); ++ if (operand->index_rc) ++ bb_reg_read(operand->index_rc); ++ } else if (operand->reg && base_rc) { ++ bb_reg_set_undef(base_rc); ++ } ++ if (bb_is_simple_memory(operand) && bb_is_osp_defined(base_rc)) { ++ int offset; ++ offset = bb_reg_code_offset(base_rc) + operand->disp; ++ offset = ALIGN(offset - KDB_WORD_SIZE + 1, KDB_WORD_SIZE); ++ bb_delete_memory(offset); ++ } ++} ++ ++/* Adjust a register that contains a stack pointer */ ++ ++static void ++bb_adjust_osp(enum bb_reg_code reg, int adjust) ++{ ++ int offset = bb_reg_code_offset(reg), old_offset = offset; ++ KDB_DEBUG_BB(" %s osp offset ", bbrg_name[reg]); ++ KDB_DEBUG_BB_OFFSET(bb_reg_code_offset(reg), "", " -> "); ++ offset += adjust; ++ bb_reg_code_set_offset(reg, offset); ++ KDB_DEBUG_BB_OFFSET(bb_reg_code_offset(reg), "", "\n"); ++ /* When RSP is adjusted upwards, it invalidates any memory ++ * stored between the old and current stack offsets. ++ */ ++ if (reg == BBRG_RSP) { ++ while (old_offset < bb_reg_code_offset(reg)) { ++ bb_delete_memory(old_offset); ++ old_offset += KDB_WORD_SIZE; ++ } ++ } ++} ++ ++/* The current instruction adjusts a register that contains a stack pointer. ++ * Direction is 1 or -1, depending on whether the instruction is add/lea or ++ * sub. ++ */ ++ ++static void ++bb_adjust_osp_instruction(int direction) ++{ ++ enum bb_reg_code dst_reg = bb_decode.dst.base_rc; ++ if (bb_decode.src.immediate || ++ bb_decode.match->usage == BBOU_LEA /* lea has its own checks */) { ++ int adjust = direction * bb_decode.src.disp; ++ bb_adjust_osp(dst_reg, adjust); ++ } else { ++ /* variable stack adjustment, osp offset is not well defined */ ++ KDB_DEBUG_BB(" %s osp offset ", bbrg_name[dst_reg]); ++ KDB_DEBUG_BB_OFFSET(bb_reg_code_offset(dst_reg), "", " -> undefined\n"); ++ bb_reg_code_set_value(dst_reg, BBRG_UNDEFINED); ++ bb_reg_code_set_offset(dst_reg, 0); ++ } ++} ++ ++/* Some instructions using memory have an explicit length suffix (b, w, l, q). ++ * The equivalent instructions using a register imply the length from the ++ * register name. Deduce the operand length. ++ */ ++ ++static int ++bb_operand_length(const struct bb_operand *operand, char opcode_suffix) ++{ ++ int l = 0; ++ switch (opcode_suffix) { ++ case 'b': ++ l = 8; ++ break; ++ case 'w': ++ l = 16; ++ break; ++ case 'l': ++ l = 32; ++ break; ++ case 'q': ++ l = 64; ++ break; ++ } ++ if (l == 0 && operand->reg) { ++ switch (strlen(operand->base)) { ++ case 3: ++ switch (operand->base[2]) { ++ case 'h': ++ case 'l': ++ l = 8; ++ break; ++ default: ++ l = 16; ++ break; ++ } ++ case 4: ++ if (operand->base[1] == 'r') ++ l = 64; ++ else ++ l = 32; ++ break; ++ } ++ } ++ return l; ++} ++ ++static int ++bb_reg_state_size(const struct bb_reg_state *state) ++{ ++ return sizeof(*state) + ++ state->mem_count * sizeof(state->memory[0]); ++} ++ ++/* Canonicalize the current bb_reg_state so it can be compared against ++ * previously created states. Sort the memory entries in descending order of ++ * offset_address (stack grows down). Empty slots are moved to the end of the ++ * list and trimmed. ++ */ ++ ++static void ++bb_reg_state_canonicalize(void) ++{ ++ int i, order, changed; ++ struct bb_memory_contains *p1, *p2, temp; ++ do { ++ changed = 0; ++ for (i = 0, p1 = bb_reg_state->memory; ++ i < bb_reg_state->mem_count-1; ++ ++i, ++p1) { ++ p2 = p1 + 1; ++ if (p2->value == BBRG_UNDEFINED) { ++ order = 0; ++ } else if (p1->value == BBRG_UNDEFINED) { ++ order = 1; ++ } else if (p1->offset_address < p2->offset_address) { ++ order = 1; ++ } else if (p1->offset_address > p2->offset_address) { ++ order = -1; ++ } else { ++ order = 0; ++ } ++ if (order > 0) { ++ temp = *p2; ++ *p2 = *p1; ++ *p1 = temp; ++ changed = 1; ++ } ++ } ++ } while(changed); ++ for (i = 0, p1 = bb_reg_state->memory; ++ i < bb_reg_state_max; ++ ++i, ++p1) { ++ if (p1->value != BBRG_UNDEFINED) ++ bb_reg_state->mem_count = i + 1; ++ } ++ bb_reg_state_print(bb_reg_state); ++} ++ ++static int ++bb_special_case(bfd_vma to) ++{ ++ int i, j, rsp_offset, expect_offset, offset, errors = 0, max_errors = 40; ++ enum bb_reg_code reg, expect_value, value; ++ struct bb_name_state *r; ++ ++ for (i = 0, r = bb_special_cases; ++ i < ARRAY_SIZE(bb_special_cases); ++ ++i, ++r) { ++ if (to == r->address && ++ (r->fname == NULL || strcmp(bb_func_name, r->fname) == 0)) ++ goto match; ++ } ++ /* Some inline assembler code has jumps to .fixup sections which result ++ * in out of line transfers with undefined state, ignore them. ++ */ ++ if (strcmp(bb_func_name, "strnlen_user") == 0 || ++ strcmp(bb_func_name, "copy_from_user") == 0) ++ return 1; ++ return 0; ++ ++match: ++ /* Check the running registers match */ ++ for (reg = BBRG_RAX; reg < r->regs_size; ++reg) { ++ expect_value = r->regs[reg].value; ++ if (test_bit(expect_value, r->skip_regs.bits)) { ++ /* this regs entry is not defined for this label */ ++ continue; ++ } ++ if (expect_value == BBRG_UNDEFINED) ++ continue; ++ expect_offset = r->regs[reg].offset; ++ value = bb_reg_code_value(reg); ++ offset = bb_reg_code_offset(reg); ++ if (expect_value == value && ++ (value != BBRG_OSP || r->osp_offset == offset)) ++ continue; ++ kdb_printf("%s: Expected %s to contain %s", ++ __FUNCTION__, ++ bbrg_name[reg], ++ bbrg_name[expect_value]); ++ if (r->osp_offset) ++ KDB_DEBUG_BB_OFFSET_PRINTF(r->osp_offset, "", ""); ++ kdb_printf(". It actually contains %s", bbrg_name[value]); ++ if (offset) ++ KDB_DEBUG_BB_OFFSET_PRINTF(offset, "", ""); ++ kdb_printf("\n"); ++ ++errors; ++ if (max_errors-- == 0) ++ goto fail; ++ } ++ /* Check that any memory data on stack matches */ ++ i = j = 0; ++ while (i < bb_reg_state->mem_count && ++ j < r->mem_size) { ++ expect_value = r->mem[j].value; ++ if (test_bit(expect_value, r->skip_mem.bits) || ++ expect_value == BBRG_UNDEFINED) { ++ /* this memory slot is not defined for this label */ ++ ++j; ++ continue; ++ } ++ rsp_offset = bb_reg_state->memory[i].offset_address - ++ bb_reg_code_offset(BBRG_RSP); ++ if (rsp_offset > ++ r->mem[j].offset_address) { ++ /* extra slots in memory are OK */ ++ ++i; ++ } else if (rsp_offset < ++ r->mem[j].offset_address) { ++ /* Required memory slot is missing */ ++ kdb_printf("%s: Invalid bb_reg_state.memory, " ++ "missing memory entry[%d] %s\n", ++ __FUNCTION__, j, bbrg_name[expect_value]); ++ ++errors; ++ if (max_errors-- == 0) ++ goto fail; ++ ++j; ++ } else { ++ if (bb_reg_state->memory[i].offset_value || ++ bb_reg_state->memory[i].value != expect_value) { ++ /* memory slot is present but contains wrong ++ * value. ++ */ ++ kdb_printf("%s: Invalid bb_reg_state.memory, " ++ "wrong value in slot %d, " ++ "should be %s, it is %s\n", ++ __FUNCTION__, i, ++ bbrg_name[expect_value], ++ bbrg_name[bb_reg_state->memory[i].value]); ++ ++errors; ++ if (max_errors-- == 0) ++ goto fail; ++ } ++ ++i; ++ ++j; ++ } ++ } ++ while (j < r->mem_size) { ++ expect_value = r->mem[j].value; ++ if (test_bit(expect_value, r->skip_mem.bits) || ++ expect_value == BBRG_UNDEFINED) ++ ++j; ++ else ++ break; ++ } ++ if (j != r->mem_size) { ++ /* Hit end of memory before testing all the pt_reg slots */ ++ kdb_printf("%s: Invalid bb_reg_state.memory, " ++ "missing trailing entries\n", ++ __FUNCTION__); ++ ++errors; ++ if (max_errors-- == 0) ++ goto fail; ++ } ++ if (errors) ++ goto fail; ++ return 1; ++fail: ++ kdb_printf("%s: on transfer to %s\n", __FUNCTION__, r->name); ++ bb_giveup = 1; ++ return 1; ++} ++ ++/* Transfer of control to a label outside the current function. If the ++ * transfer is to a known common code path then do a sanity check on the state ++ * at this point. ++ */ ++ ++static void ++bb_sanity_check(int type) ++{ ++ enum bb_reg_code expect, actual; ++ int i, offset, error = 0; ++ ++ for (i = 0; i < ARRAY_SIZE(bb_preserved_reg); ++i) { ++ expect = bb_preserved_reg[i]; ++ actual = bb_reg_code_value(expect); ++ offset = bb_reg_code_offset(expect); ++ if (expect == actual) ++ continue; ++ /* type == 1 is sysret/sysexit, ignore RSP */ ++ if (type && expect == BBRG_RSP) ++ continue; ++ /* type == 1 is sysret/sysexit, ignore RBP for i386 */ ++ /* We used to have "#ifndef CONFIG_X86_64" for the type=1 RBP ++ * test; however, x86_64 can run ia32 compatible mode and ++ * hit this problem. Perform the following test anyway! ++ */ ++ if (type && expect == BBRG_RBP) ++ continue; ++ /* RSP should contain OSP+0. Except for ptregscall_common and ++ * ia32_ptregs_common, they get a partial pt_regs, fudge the ++ * stack to make it a full pt_regs then reverse the effect on ++ * exit, so the offset is -0x50 on exit. ++ */ ++ if (expect == BBRG_RSP && ++ bb_is_osp_defined(expect) && ++ (offset == 0 || ++ (offset == -0x50 && ++ (strcmp(bb_func_name, "ptregscall_common") == 0 || ++ strcmp(bb_func_name, "ia32_ptregs_common") == 0)))) ++ continue; ++ kdb_printf("%s: Expected %s, got %s", ++ __FUNCTION__, ++ bbrg_name[expect], bbrg_name[actual]); ++ if (offset) ++ KDB_DEBUG_BB_OFFSET_PRINTF(offset, "", ""); ++ kdb_printf("\n"); ++ error = 1; ++ } ++ BB_CHECK(error, error, ); ++} ++ ++/* Transfer of control. Follow the arc and save the current state as input to ++ * another basic block. ++ */ ++ ++static void ++bb_transfer(bfd_vma from, bfd_vma to, unsigned int drop_through) ++{ ++ int i, found; ++ size_t size; ++ struct bb* bb = NULL; /*stupid gcc */ ++ struct bb_jmp *bb_jmp; ++ struct bb_reg_state *state; ++ bb_reg_state_canonicalize(); ++ found = 0; ++ for (i = 0; i < bb_jmp_count; ++i) { ++ bb_jmp = bb_jmp_list + i; ++ if (bb_jmp->from == from && ++ bb_jmp->to == to && ++ bb_jmp->drop_through == drop_through) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ /* Transfer outside the current function. Check the special ++ * cases (mainly in entry.S) first. If it is not a known ++ * special case then check if the target address is the start ++ * of a function or not. If it is the start of a function then ++ * assume tail recursion and require that the state be the same ++ * as on entry. Otherwise assume out of line code (e.g. ++ * spinlock contention path) and ignore it, the state can be ++ * anything. ++ */ ++ kdb_symtab_t symtab; ++ if (bb_special_case(to)) ++ return; ++ kdbnearsym(to, &symtab); ++ if (symtab.sym_start != to) ++ return; ++ bb_sanity_check(0); ++ if (bb_giveup) ++ return; ++#ifdef NO_SIBLINGS ++ /* Only print this message when the kernel is compiled with ++ * -fno-optimize-sibling-calls. Otherwise it would print a ++ * message for every tail recursion call. If you see the ++ * message below then you probably have an assembler label that ++ * is not listed in the special cases. ++ */ ++ kdb_printf(" not matched: from " ++ kdb_bfd_vma_fmt0 ++ " to " kdb_bfd_vma_fmt0 ++ " drop_through %d bb_jmp[%d]\n", ++ from, to, drop_through, i); ++#endif /* NO_SIBLINGS */ ++ return; ++ } ++ KDB_DEBUG_BB(" matched: from " kdb_bfd_vma_fmt0 ++ " to " kdb_bfd_vma_fmt0 ++ " drop_through %d bb_jmp[%d]\n", ++ from, to, drop_through, i); ++ found = 0; ++ for (i = 0; i < bb_count; ++i) { ++ bb = bb_list[i]; ++ if (bb->start == to) { ++ found = 1; ++ break; ++ } ++ } ++ BB_CHECK(!found, to, ); ++ /* If the register state for this arc has already been set (we are ++ * rescanning the block that originates the arc) and the state is the ++ * same as the previous state for this arc then this input to the ++ * target block is the same as last time, so there is no need to rescan ++ * the target block. ++ */ ++ state = bb_jmp->state; ++ size = bb_reg_state_size(bb_reg_state); ++ if (state) { ++ bb_reg_state->ref_count = state->ref_count; ++ if (memcmp(state, bb_reg_state, size) == 0) { ++ KDB_DEBUG_BB(" no state change\n"); ++ return; ++ } ++ if (--state->ref_count == 0) ++ debug_kfree(state); ++ bb_jmp->state = NULL; ++ } ++ /* New input state is required. To save space, check if any other arcs ++ * have the same state and reuse them where possible. The overall set ++ * of inputs to the target block is now different so the target block ++ * must be rescanned. ++ */ ++ bb->changed = 1; ++ for (i = 0; i < bb_jmp_count; ++i) { ++ state = bb_jmp_list[i].state; ++ if (!state) ++ continue; ++ bb_reg_state->ref_count = state->ref_count; ++ if (memcmp(state, bb_reg_state, size) == 0) { ++ KDB_DEBUG_BB(" reuse bb_jmp[%d]\n", i); ++ bb_jmp->state = state; ++ ++state->ref_count; ++ return; ++ } ++ } ++ state = debug_kmalloc(size, GFP_ATOMIC); ++ if (!state) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ memcpy(state, bb_reg_state, size); ++ state->ref_count = 1; ++ bb_jmp->state = state; ++ KDB_DEBUG_BB(" new state %p\n", state); ++} ++ ++/* Isolate the processing for 'mov' so it can be used for 'xadd'/'xchg' as ++ * well. ++ * ++ * xadd/xchg expect this function to return BBOU_NOP for special cases, ++ * otherwise it returns BBOU_RSWD. All special cases must be handled entirely ++ * within this function, including doing bb_read_operand or bb_write_operand ++ * where necessary. ++ */ ++ ++static enum bb_operand_usage ++bb_usage_mov(const struct bb_operand *src, const struct bb_operand *dst, int l) ++{ ++ int full_register_src, full_register_dst; ++ full_register_src = bb_operand_length(src, bb_decode.opcode[l]) ++ == KDB_WORD_SIZE * 8; ++ full_register_dst = bb_operand_length(dst, bb_decode.opcode[l]) ++ == KDB_WORD_SIZE * 8; ++ /* If both src and dst are full integer registers then record the ++ * register change. ++ */ ++ if (src->reg && ++ bb_is_int_reg(src->base_rc) && ++ dst->reg && ++ bb_is_int_reg(dst->base_rc) && ++ full_register_src && ++ full_register_dst) { ++ /* Special case for the code that switches stacks in ++ * jprobe_return. That code must modify RSP but it does it in ++ * a well defined manner. Do not invalidate RSP. ++ */ ++ if (src->base_rc == BBRG_RBX && ++ dst->base_rc == BBRG_RSP && ++ strcmp(bb_func_name, "jprobe_return") == 0) { ++ bb_read_operand(src); ++ return BBOU_NOP; ++ } ++ /* math_abort takes the equivalent of a longjmp structure and ++ * resets the stack. Ignore this, it leaves RSP well defined. ++ */ ++ if (dst->base_rc == BBRG_RSP && ++ strcmp(bb_func_name, "math_abort") == 0) { ++ bb_read_operand(src); ++ return BBOU_NOP; ++ } ++ bb_reg_set_reg(dst->base_rc, src->base_rc); ++ return BBOU_NOP; ++ } ++ /* If the move is from a full integer register to stack then record it. ++ */ ++ if (src->reg && ++ bb_is_simple_memory(dst) && ++ bb_is_osp_defined(dst->base_rc) && ++ full_register_src) { ++ /* Ugly special case. Initializing list heads on stack causes ++ * false references to stack variables when the list head is ++ * used. Static code analysis cannot detect that the list head ++ * has been changed by a previous execution loop and that a ++ * basic block is only executed after the list head has been ++ * changed. ++ * ++ * These false references can result in valid stack variables ++ * being incorrectly cleared on some logic paths. Ignore ++ * stores to stack variables which point to themselves or to ++ * the previous word so the list head initialization is not ++ * recorded. ++ */ ++ if (bb_is_osp_defined(src->base_rc)) { ++ int stack1 = bb_reg_code_offset(src->base_rc); ++ int stack2 = bb_reg_code_offset(dst->base_rc) + ++ dst->disp; ++ if (stack1 == stack2 || ++ stack1 == stack2 - KDB_WORD_SIZE) ++ return BBOU_NOP; ++ } ++ bb_memory_set_reg(dst->base_rc, src->base_rc, dst->disp); ++ return BBOU_NOP; ++ } ++ /* If the move is from stack to a full integer register then record it. ++ */ ++ if (bb_is_simple_memory(src) && ++ bb_is_osp_defined(src->base_rc) && ++ dst->reg && ++ bb_is_int_reg(dst->base_rc) && ++ full_register_dst) { ++#ifdef CONFIG_X86_32 ++ /* mov from TSS_sysenter_sp0+offset to esp to fix up the ++ * sysenter stack, it leaves esp well defined. mov ++ * TSS_ysenter_sp0+offset(%esp),%esp is followed by up to 5 ++ * push instructions to mimic the hardware stack push. If ++ * TSS_sysenter_sp0 is offset then only 3 words will be ++ * pushed. ++ */ ++ if (dst->base_rc == BBRG_RSP && ++ src->disp >= TSS_sysenter_sp0 && ++ bb_is_osp_defined(BBRG_RSP)) { ++ int pushes; ++ pushes = src->disp == TSS_sysenter_sp0 ? 5 : 3; ++ bb_reg_code_set_offset(BBRG_RSP, ++ bb_reg_code_offset(BBRG_RSP) + ++ pushes * KDB_WORD_SIZE); ++ KDB_DEBUG_BB_OFFSET( ++ bb_reg_code_offset(BBRG_RSP), ++ " sysenter fixup, RSP", ++ "\n"); ++ return BBOU_NOP; ++ } ++#endif /* CONFIG_X86_32 */ ++ bb_read_operand(src); ++ bb_reg_set_memory(dst->base_rc, src->base_rc, src->disp); ++ return BBOU_NOP; ++ } ++ /* move %gs:0x,%rsp is used to unconditionally switch to another ++ * stack. Ignore this special case, it is handled by the stack ++ * unwinding code. ++ */ ++ if (src->segment && ++ strcmp(src->segment, "%gs") == 0 && ++ dst->reg && ++ dst->base_rc == BBRG_RSP) ++ return BBOU_NOP; ++ /* move %reg,%reg is a nop */ ++ if (src->reg && ++ dst->reg && ++ !src->segment && ++ !dst->segment && ++ strcmp(src->base, dst->base) == 0) ++ return BBOU_NOP; ++ /* Special case for the code that switches stacks in the scheduler ++ * (switch_to()). That code must modify RSP but it does it in a well ++ * defined manner. Do not invalidate RSP. ++ */ ++ if (dst->reg && ++ dst->base_rc == BBRG_RSP && ++ full_register_dst && ++ bb_is_scheduler_address()) { ++ bb_read_operand(src); ++ return BBOU_NOP; ++ } ++ /* Special case for the code that switches stacks in resume from ++ * hibernation code. That code must modify RSP but it does it in a ++ * well defined manner. Do not invalidate RSP. ++ */ ++ if (src->memory && ++ dst->reg && ++ dst->base_rc == BBRG_RSP && ++ full_register_dst && ++ strcmp(bb_func_name, "restore_image") == 0) { ++ bb_read_operand(src); ++ return BBOU_NOP; ++ } ++ return BBOU_RSWD; ++} ++ ++static enum bb_operand_usage ++bb_usage_xadd(const struct bb_operand *src, const struct bb_operand *dst) ++{ ++ /* Simulate xadd as a series of instructions including mov, that way we ++ * get the benefit of all the special cases already handled by ++ * BBOU_MOV. ++ * ++ * tmp = src + dst, src = dst, dst = tmp. ++ * ++ * For tmp, pick a register that is undefined. If all registers are ++ * defined then pick one that is not being used by xadd. ++ */ ++ enum bb_reg_code reg = BBRG_UNDEFINED; ++ struct bb_operand tmp; ++ struct bb_reg_contains save_tmp; ++ enum bb_operand_usage usage; ++ int undefined = 0; ++ for (reg = BBRG_RAX; reg < BBRG_RAX + KDB_INT_REGISTERS; ++reg) { ++ if (bb_reg_code_value(reg) == BBRG_UNDEFINED) { ++ undefined = 1; ++ break; ++ } ++ } ++ if (!undefined) { ++ for (reg = BBRG_RAX; reg < BBRG_RAX + KDB_INT_REGISTERS; ++reg) { ++ if (reg != src->base_rc && ++ reg != src->index_rc && ++ reg != dst->base_rc && ++ reg != dst->index_rc && ++ reg != BBRG_RSP) ++ break; ++ } ++ } ++ KDB_DEBUG_BB(" %s saving tmp %s\n", __FUNCTION__, bbrg_name[reg]); ++ save_tmp = bb_reg_state->contains[reg - BBRG_RAX]; ++ bb_reg_set_undef(reg); ++ memset(&tmp, 0, sizeof(tmp)); ++ tmp.present = 1; ++ tmp.reg = 1; ++ tmp.base = debug_kmalloc(strlen(bbrg_name[reg]) + 2, GFP_ATOMIC); ++ if (tmp.base) { ++ tmp.base[0] = '%'; ++ strcpy(tmp.base + 1, bbrg_name[reg]); ++ } ++ tmp.base_rc = reg; ++ bb_read_operand(src); ++ bb_read_operand(dst); ++ if (bb_usage_mov(src, dst, sizeof("xadd")-1) == BBOU_NOP) ++ usage = BBOU_RSRD; ++ else ++ usage = BBOU_RSRDWS; ++ bb_usage_mov(&tmp, dst, sizeof("xadd")-1); ++ KDB_DEBUG_BB(" %s restoring tmp %s\n", __FUNCTION__, bbrg_name[reg]); ++ bb_reg_state->contains[reg - BBRG_RAX] = save_tmp; ++ debug_kfree(tmp.base); ++ return usage; ++} ++ ++static enum bb_operand_usage ++bb_usage_xchg(const struct bb_operand *src, const struct bb_operand *dst) ++{ ++ /* Simulate xchg as a series of mov instructions, that way we get the ++ * benefit of all the special cases already handled by BBOU_MOV. ++ * ++ * mov dst,tmp; mov src,dst; mov tmp,src; ++ * ++ * For tmp, pick a register that is undefined. If all registers are ++ * defined then pick one that is not being used by xchg. ++ */ ++ enum bb_reg_code reg = BBRG_UNDEFINED; ++ int rs = BBOU_RS, rd = BBOU_RD, ws = BBOU_WS, wd = BBOU_WD; ++ struct bb_operand tmp; ++ struct bb_reg_contains save_tmp; ++ int undefined = 0; ++ for (reg = BBRG_RAX; reg < BBRG_RAX + KDB_INT_REGISTERS; ++reg) { ++ if (bb_reg_code_value(reg) == BBRG_UNDEFINED) { ++ undefined = 1; ++ break; ++ } ++ } ++ if (!undefined) { ++ for (reg = BBRG_RAX; reg < BBRG_RAX + KDB_INT_REGISTERS; ++reg) { ++ if (reg != src->base_rc && ++ reg != src->index_rc && ++ reg != dst->base_rc && ++ reg != dst->index_rc && ++ reg != BBRG_RSP) ++ break; ++ } ++ } ++ KDB_DEBUG_BB(" %s saving tmp %s\n", __FUNCTION__, bbrg_name[reg]); ++ save_tmp = bb_reg_state->contains[reg - BBRG_RAX]; ++ memset(&tmp, 0, sizeof(tmp)); ++ tmp.present = 1; ++ tmp.reg = 1; ++ tmp.base = debug_kmalloc(strlen(bbrg_name[reg]) + 2, GFP_ATOMIC); ++ if (tmp.base) { ++ tmp.base[0] = '%'; ++ strcpy(tmp.base + 1, bbrg_name[reg]); ++ } ++ tmp.base_rc = reg; ++ if (bb_usage_mov(dst, &tmp, sizeof("xchg")-1) == BBOU_NOP) ++ rd = 0; ++ if (bb_usage_mov(src, dst, sizeof("xchg")-1) == BBOU_NOP) { ++ rs = 0; ++ wd = 0; ++ } ++ if (bb_usage_mov(&tmp, src, sizeof("xchg")-1) == BBOU_NOP) ++ ws = 0; ++ KDB_DEBUG_BB(" %s restoring tmp %s\n", __FUNCTION__, bbrg_name[reg]); ++ bb_reg_state->contains[reg - BBRG_RAX] = save_tmp; ++ debug_kfree(tmp.base); ++ return rs | rd | ws | wd; ++} ++ ++/* Invalidate all the scratch registers */ ++ ++static void ++bb_invalidate_scratch_reg(void) ++{ ++ int i, j; ++ for (i = BBRG_RAX; i < BBRG_RAX + KDB_INT_REGISTERS; ++i) { ++ for (j = 0; j < ARRAY_SIZE(bb_preserved_reg); ++j) { ++ if (i == bb_preserved_reg[j]) ++ goto preserved; ++ } ++ bb_reg_set_undef(i); ++preserved: ++ continue; ++ } ++} ++ ++static void ++bb_pass2_computed_jmp(const struct bb_operand *src) ++{ ++ unsigned long table = src->disp; ++ kdb_machreg_t addr; ++ while (!bb_giveup) { ++ if (kdb_getword(&addr, table, sizeof(addr))) ++ return; ++ if (addr < bb_func_start || addr >= bb_func_end) ++ return; ++ bb_transfer(bb_curr_addr, addr, 0); ++ table += KDB_WORD_SIZE; ++ } ++} ++ ++/* The current instruction has been decoded and all the information is in ++ * bb_decode. Based on the opcode, track any operand usage that we care about. ++ */ ++ ++static void ++bb_usage(void) ++{ ++ enum bb_operand_usage usage = bb_decode.match->usage; ++ struct bb_operand *src = &bb_decode.src; ++ struct bb_operand *dst = &bb_decode.dst; ++ struct bb_operand *dst2 = &bb_decode.dst2; ++ int opcode_suffix, operand_length; ++ ++ /* First handle all the special usage cases, and map them to a generic ++ * case after catering for the side effects. ++ */ ++ ++ if (usage == BBOU_IMUL && ++ src->present && !dst->present && !dst2->present) { ++ /* single operand imul, same effects as mul */ ++ usage = BBOU_MUL; ++ } ++ ++ /* AT&T syntax uses movs for move with sign extension, instead ++ * of the Intel movsx. The AT&T syntax causes problems for the opcode ++ * mapping; movs with sign extension needs to be treated as a generic ++ * read src, write dst, but instead it falls under the movs I/O ++ * instruction. Fix it. ++ */ ++ if (usage == BBOU_MOVS && strlen(bb_decode.opcode) > 5) ++ usage = BBOU_RSWD; ++ ++ /* This switch statement deliberately does not use 'default' at the top ++ * level. That way the compiler will complain if a new BBOU_ enum is ++ * added above and not explicitly handled here. ++ */ ++ switch (usage) { ++ case BBOU_UNKNOWN: /* drop through */ ++ case BBOU_RS: /* drop through */ ++ case BBOU_RD: /* drop through */ ++ case BBOU_RSRD: /* drop through */ ++ case BBOU_WS: /* drop through */ ++ case BBOU_RSWS: /* drop through */ ++ case BBOU_RDWS: /* drop through */ ++ case BBOU_RSRDWS: /* drop through */ ++ case BBOU_WD: /* drop through */ ++ case BBOU_RSWD: /* drop through */ ++ case BBOU_RDWD: /* drop through */ ++ case BBOU_RSRDWD: /* drop through */ ++ case BBOU_WSWD: /* drop through */ ++ case BBOU_RSWSWD: /* drop through */ ++ case BBOU_RDWSWD: /* drop through */ ++ case BBOU_RSRDWSWD: ++ break; /* ignore generic usage for now */ ++ case BBOU_ADD: ++ /* Special case for add instructions that adjust registers ++ * which are mapping the stack. ++ */ ++ if (dst->reg && bb_is_osp_defined(dst->base_rc)) { ++ bb_adjust_osp_instruction(1); ++ usage = BBOU_RS; ++ } else { ++ usage = BBOU_RSRDWD; ++ } ++ break; ++ case BBOU_CALL: ++ /* Invalidate the scratch registers. Functions sync_regs and ++ * save_v86_state are special, their return value is the new ++ * stack pointer. ++ */ ++ bb_reg_state_print(bb_reg_state); ++ bb_invalidate_scratch_reg(); ++ if (bb_is_static_disp(src)) { ++ if (src->disp == bb_sync_regs) { ++ bb_reg_set_reg(BBRG_RAX, BBRG_RSP); ++ } else if (src->disp == bb_save_v86_state) { ++ bb_reg_set_reg(BBRG_RAX, BBRG_RSP); ++ bb_adjust_osp(BBRG_RAX, +KDB_WORD_SIZE); ++ } ++ } ++ usage = BBOU_NOP; ++ break; ++ case BBOU_CBW: ++ /* Convert word in RAX. Read RAX, write RAX */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RAX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_CMOV: ++ /* cmove %gs:0x,%rsp is used to conditionally switch to ++ * another stack. Ignore this special case, it is handled by ++ * the stack unwinding code. ++ */ ++ if (src->segment && ++ strcmp(src->segment, "%gs") == 0 && ++ dst->reg && ++ dst->base_rc == BBRG_RSP) ++ usage = BBOU_NOP; ++ else ++ usage = BBOU_RSWD; ++ break; ++ case BBOU_CMPXCHG: ++ /* Read RAX, write RAX plus src read, dst write */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RAX); ++ usage = BBOU_RSWD; ++ break; ++ case BBOU_CMPXCHGD: ++ /* Read RAX, RBX, RCX, RDX, write RAX, RDX plus src read/write */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_read(BBRG_RBX); ++ bb_reg_read(BBRG_RCX); ++ bb_reg_read(BBRG_RDX); ++ bb_reg_set_undef(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_RSWS; ++ break; ++ case BBOU_CPUID: ++ /* Read RAX, write RAX, RBX, RCX, RDX */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RBX); ++ bb_reg_set_undef(BBRG_RCX); ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_CWD: ++ /* Convert word in RAX, RDX. Read RAX, write RDX */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_DIV: /* drop through */ ++ case BBOU_IDIV: ++ /* The 8 bit variants only affect RAX, the 16, 32 and 64 bit ++ * variants affect RDX as well. ++ */ ++ switch (usage) { ++ case BBOU_DIV: ++ opcode_suffix = bb_decode.opcode[3]; ++ break; ++ case BBOU_IDIV: ++ opcode_suffix = bb_decode.opcode[4]; ++ break; ++ default: ++ opcode_suffix = 'q'; ++ break; ++ } ++ operand_length = bb_operand_length(src, opcode_suffix); ++ bb_reg_read(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RAX); ++ if (operand_length != 8) { ++ bb_reg_read(BBRG_RDX); ++ bb_reg_set_undef(BBRG_RDX); ++ } ++ usage = BBOU_RS; ++ break; ++ case BBOU_IMUL: ++ /* Only the two and three operand forms get here. The one ++ * operand form is treated as mul. ++ */ ++ if (dst2->present) { ++ /* The three operand form is a special case, read the first two ++ * operands, write the third. ++ */ ++ bb_read_operand(src); ++ bb_read_operand(dst); ++ bb_write_operand(dst2); ++ usage = BBOU_NOP; ++ } else { ++ usage = BBOU_RSRDWD; ++ } ++ break; ++ case BBOU_IRET: ++ bb_sanity_check(0); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_JMP: ++ if (bb_is_static_disp(src)) ++ bb_transfer(bb_curr_addr, src->disp, 0); ++ else if (src->indirect && ++ src->disp && ++ src->base == NULL && ++ src->index && ++ src->scale == KDB_WORD_SIZE) ++ bb_pass2_computed_jmp(src); ++ usage = BBOU_RS; ++ break; ++ case BBOU_LAHF: ++ /* Write RAX */ ++ bb_reg_set_undef(BBRG_RAX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_LEA: ++ /* dst = src + disp. Often used to calculate offsets into the ++ * stack, so check if it uses a stack pointer. ++ */ ++ usage = BBOU_RSWD; ++ if (bb_is_simple_memory(src)) { ++ if (bb_is_osp_defined(src->base_rc)) { ++ bb_reg_set_reg(dst->base_rc, src->base_rc); ++ bb_adjust_osp_instruction(1); ++ usage = BBOU_RS; ++ } else if (src->disp == 0 && ++ src->base_rc == dst->base_rc) { ++ /* lea 0(%reg),%reg is generated by i386 ++ * GENERIC_NOP7. ++ */ ++ usage = BBOU_NOP; ++ } else if (src->disp == 4096 && ++ (src->base_rc == BBRG_R8 || ++ src->base_rc == BBRG_RDI) && ++ strcmp(bb_func_name, "relocate_kernel") == 0) { ++ /* relocate_kernel: setup a new stack at the ++ * end of the physical control page, using ++ * (x86_64) lea 4096(%r8),%rsp or (i386) lea ++ * 4096(%edi),%esp ++ */ ++ usage = BBOU_NOP; ++ } ++ } ++ break; ++ case BBOU_LEAVE: ++ /* RSP = RBP; RBP = *(RSP); RSP += KDB_WORD_SIZE; */ ++ bb_reg_set_reg(BBRG_RSP, BBRG_RBP); ++ if (bb_is_osp_defined(BBRG_RSP)) ++ bb_reg_set_memory(BBRG_RBP, BBRG_RSP, 0); ++ else ++ bb_reg_set_undef(BBRG_RBP); ++ if (bb_is_osp_defined(BBRG_RSP)) ++ bb_adjust_osp(BBRG_RSP, KDB_WORD_SIZE); ++ /* common_interrupt uses leave in a non-standard manner */ ++ if (strcmp(bb_func_name, "common_interrupt") != 0) ++ bb_sanity_check(0); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_LODS: ++ /* Read RSI, write RAX, RSI */ ++ bb_reg_read(BBRG_RSI); ++ bb_reg_set_undef(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RSI); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_LOOP: ++ /* Read and write RCX */ ++ bb_reg_read(BBRG_RCX); ++ bb_reg_set_undef(BBRG_RCX); ++ if (bb_is_static_disp(src)) ++ bb_transfer(bb_curr_addr, src->disp, 0); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_LSS: ++ /* lss offset(%esp),%esp leaves esp well defined */ ++ if (dst->reg && ++ dst->base_rc == BBRG_RSP && ++ bb_is_simple_memory(src) && ++ src->base_rc == BBRG_RSP) { ++ bb_adjust_osp(BBRG_RSP, 2*KDB_WORD_SIZE + src->disp); ++ usage = BBOU_NOP; ++ } else { ++ usage = BBOU_RSWD; ++ } ++ break; ++ case BBOU_MONITOR: ++ /* Read RAX, RCX, RDX */ ++ bb_reg_set_undef(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RCX); ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_MOV: ++ usage = bb_usage_mov(src, dst, sizeof("mov")-1); ++ break; ++ case BBOU_MOVS: ++ /* Read RSI, RDI, write RSI, RDI */ ++ bb_reg_read(BBRG_RSI); ++ bb_reg_read(BBRG_RDI); ++ bb_reg_set_undef(BBRG_RSI); ++ bb_reg_set_undef(BBRG_RDI); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_MUL: ++ /* imul (one operand form only) or mul. Read RAX. If the ++ * operand length is not 8 then write RDX. ++ */ ++ if (bb_decode.opcode[0] == 'i') ++ opcode_suffix = bb_decode.opcode[4]; ++ else ++ opcode_suffix = bb_decode.opcode[3]; ++ operand_length = bb_operand_length(src, opcode_suffix); ++ bb_reg_read(BBRG_RAX); ++ if (operand_length != 8) ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_MWAIT: ++ /* Read RAX, RCX */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_read(BBRG_RCX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_NOP: ++ break; ++ case BBOU_OUTS: ++ /* Read RSI, RDX, write RSI */ ++ bb_reg_read(BBRG_RSI); ++ bb_reg_read(BBRG_RDX); ++ bb_reg_set_undef(BBRG_RSI); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_POP: ++ /* Complicated by the fact that you can pop from top of stack ++ * to a stack location, for this case the destination location ++ * is calculated after adjusting RSP. Analysis of the kernel ++ * code shows that gcc only uses this strange format to get the ++ * flags into a local variable, e.g. pushf; popl 0x10(%esp); so ++ * I am going to ignore this special case. ++ */ ++ usage = BBOU_WS; ++ if (!bb_is_osp_defined(BBRG_RSP)) { ++ if (!bb_is_scheduler_address()) { ++ kdb_printf("pop when BBRG_RSP is undefined?\n"); ++ bb_giveup = 1; ++ } ++ } else { ++ if (src->reg) { ++ bb_reg_set_memory(src->base_rc, BBRG_RSP, 0); ++ usage = BBOU_NOP; ++ } ++ /* pop %rsp does not adjust rsp */ ++ if (!src->reg || ++ src->base_rc != BBRG_RSP) ++ bb_adjust_osp(BBRG_RSP, KDB_WORD_SIZE); ++ } ++ break; ++ case BBOU_POPF: ++ /* Do not care about flags, just adjust RSP */ ++ if (!bb_is_osp_defined(BBRG_RSP)) { ++ if (!bb_is_scheduler_address()) { ++ kdb_printf("popf when BBRG_RSP is undefined?\n"); ++ bb_giveup = 1; ++ } ++ } else { ++ bb_adjust_osp(BBRG_RSP, KDB_WORD_SIZE); ++ } ++ usage = BBOU_WS; ++ break; ++ case BBOU_PUSH: ++ /* Complicated by the fact that you can push from a stack ++ * location to top of stack, the source location is calculated ++ * before adjusting RSP. Analysis of the kernel code shows ++ * that gcc only uses this strange format to restore the flags ++ * from a local variable, e.g. pushl 0x10(%esp); popf; so I am ++ * going to ignore this special case. ++ */ ++ usage = BBOU_RS; ++ if (!bb_is_osp_defined(BBRG_RSP)) { ++ if (!bb_is_scheduler_address()) { ++ kdb_printf("push when BBRG_RSP is undefined?\n"); ++ bb_giveup = 1; ++ } ++ } else { ++ bb_adjust_osp(BBRG_RSP, -KDB_WORD_SIZE); ++ if (src->reg && ++ bb_reg_code_offset(BBRG_RSP) <= 0) ++ bb_memory_set_reg(BBRG_RSP, src->base_rc, 0); ++ } ++ break; ++ case BBOU_PUSHF: ++ /* Do not care about flags, just adjust RSP */ ++ if (!bb_is_osp_defined(BBRG_RSP)) { ++ if (!bb_is_scheduler_address()) { ++ kdb_printf("pushf when BBRG_RSP is undefined?\n"); ++ bb_giveup = 1; ++ } ++ } else { ++ bb_adjust_osp(BBRG_RSP, -KDB_WORD_SIZE); ++ } ++ usage = BBOU_WS; ++ break; ++ case BBOU_RDMSR: ++ /* Read RCX, write RAX, RDX */ ++ bb_reg_read(BBRG_RCX); ++ bb_reg_set_undef(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_RDTSC: ++ /* Write RAX, RDX */ ++ bb_reg_set_undef(BBRG_RAX); ++ bb_reg_set_undef(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_RET: ++ usage = BBOU_NOP; ++ /* Functions that restore state which was saved by another ++ * function or build new kernel stacks. We cannot verify what ++ * is being restored so skip the sanity check. ++ */ ++ if (strcmp(bb_func_name, "restore_image") == 0 || ++ strcmp(bb_func_name, "relocate_kernel") == 0 || ++ strcmp(bb_func_name, "identity_mapped") == 0 || ++ strcmp(bb_func_name, "xen_iret_crit_fixup") == 0 || ++ strcmp(bb_func_name, "math_abort") == 0) ++ break; ++ bb_sanity_check(0); ++ break; ++ case BBOU_SAHF: ++ /* Read RAX */ ++ bb_reg_read(BBRG_RAX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_SCAS: ++ /* Read RAX, RDI, write RDI */ ++ bb_reg_read(BBRG_RAX); ++ bb_reg_read(BBRG_RDI); ++ bb_reg_set_undef(BBRG_RDI); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_SUB: ++ /* Special case for sub instructions that adjust registers ++ * which are mapping the stack. ++ */ ++ if (dst->reg && bb_is_osp_defined(dst->base_rc)) { ++ bb_adjust_osp_instruction(-1); ++ usage = BBOU_RS; ++ } else { ++ usage = BBOU_RSRDWD; ++ } ++ break; ++ case BBOU_SYSEXIT: ++ bb_sanity_check(1); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_SYSRET: ++ bb_sanity_check(1); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_WRMSR: ++ /* Read RCX, RAX, RDX */ ++ bb_reg_read(BBRG_RCX); ++ bb_reg_read(BBRG_RAX); ++ bb_reg_read(BBRG_RDX); ++ usage = BBOU_NOP; ++ break; ++ case BBOU_XADD: ++ usage = bb_usage_xadd(src, dst); ++ break; ++ case BBOU_XCHG: ++ /* i386 do_IRQ with 4K stacks does xchg %ebx,%esp; call ++ * irq_handler; mov %ebx,%esp; to switch stacks. Ignore this ++ * stack switch when tracking registers, it is handled by ++ * higher level backtrace code. Convert xchg %ebx,%esp to mov ++ * %esp,%ebx so the later mov %ebx,%esp becomes a NOP and the ++ * stack remains defined so we can backtrace through do_IRQ's ++ * stack switch. ++ * ++ * Ditto for do_softirq. ++ */ ++ if (src->reg && ++ dst->reg && ++ src->base_rc == BBRG_RBX && ++ dst->base_rc == BBRG_RSP && ++ (strcmp(bb_func_name, "do_IRQ") == 0 || ++ strcmp(bb_func_name, "do_softirq") == 0)) { ++ strcpy(bb_decode.opcode, "mov"); ++ usage = bb_usage_mov(dst, src, sizeof("mov")-1); ++ } else { ++ usage = bb_usage_xchg(src, dst); ++ } ++ break; ++ case BBOU_XOR: ++ /* xor %reg,%reg only counts as a register write, the original ++ * contents of reg are irrelevant. ++ */ ++ if (src->reg && dst->reg && src->base_rc == dst->base_rc) ++ usage = BBOU_WS; ++ else ++ usage = BBOU_RSRDWD; ++ break; ++ } ++ ++ /* The switch statement above handled all the special cases. Every ++ * opcode should now have a usage of NOP or one of the generic cases. ++ */ ++ if (usage == BBOU_UNKNOWN || usage == BBOU_NOP) { ++ /* nothing to do */ ++ } else if (usage >= BBOU_RS && usage <= BBOU_RSRDWSWD) { ++ if (usage & BBOU_RS) ++ bb_read_operand(src); ++ if (usage & BBOU_RD) ++ bb_read_operand(dst); ++ if (usage & BBOU_WS) ++ bb_write_operand(src); ++ if (usage & BBOU_WD) ++ bb_write_operand(dst); ++ } else { ++ kdb_printf("%s: opcode not fully handled\n", __FUNCTION__); ++ if (!KDB_DEBUG(BB)) { ++ bb_print_opcode(); ++ if (bb_decode.src.present) ++ bb_print_operand("src", &bb_decode.src); ++ if (bb_decode.dst.present) ++ bb_print_operand("dst", &bb_decode.dst); ++ if (bb_decode.dst2.present) ++ bb_print_operand("dst2", &bb_decode.dst2); ++ } ++ bb_giveup = 1; ++ } ++} ++ ++static void ++bb_parse_buffer(void) ++{ ++ char *p, *src, *dst = NULL, *dst2 = NULL; ++ int paren = 0; ++ p = bb_buffer; ++ memset(&bb_decode, 0, sizeof(bb_decode)); ++ KDB_DEBUG_BB(" '%s'\n", p); ++ p += strcspn(p, ":"); /* skip address and function name+offset: */ ++ if (*p++ != ':') { ++ kdb_printf("%s: cannot find ':' in buffer '%s'\n", ++ __FUNCTION__, bb_buffer); ++ bb_giveup = 1; ++ return; ++ } ++ p += strspn(p, " \t"); /* step to opcode */ ++ if (strncmp(p, "(bad)", 5) == 0) ++ strcpy(p, "nop"); ++ /* separate any opcode prefix */ ++ if (strncmp(p, "lock", 4) == 0 || ++ strncmp(p, "rep", 3) == 0 || ++ strncmp(p, "rex", 3) == 0 || ++ strncmp(p, "addr", 4) == 0) { ++ bb_decode.prefix = p; ++ p += strcspn(p, " \t"); ++ *p++ = '\0'; ++ p += strspn(p, " \t"); ++ } ++ bb_decode.opcode = p; ++ strsep(&p, " \t"); /* step to end of opcode */ ++ if (bb_parse_opcode()) ++ return; ++ if (!p) ++ goto no_operands; ++ p += strspn(p, " \t"); /* step to operand(s) */ ++ if (!*p) ++ goto no_operands; ++ src = p; ++ p = strsep(&p, " \t"); /* strip comments after operands */ ++ /* split 'src','dst' but ignore ',' inside '(' ')' */ ++ while (*p) { ++ if (*p == '(') { ++ ++paren; ++ } else if (*p == ')') { ++ --paren; ++ } else if (*p == ',' && paren == 0) { ++ *p = '\0'; ++ if (dst) ++ dst2 = p+1; ++ else ++ dst = p+1; ++ } ++ ++p; ++ } ++ bb_parse_operand(src, &bb_decode.src); ++ if (KDB_DEBUG(BB)) ++ bb_print_operand("src", &bb_decode.src); ++ if (dst && !bb_giveup) { ++ bb_parse_operand(dst, &bb_decode.dst); ++ if (KDB_DEBUG(BB)) ++ bb_print_operand("dst", &bb_decode.dst); ++ } ++ if (dst2 && !bb_giveup) { ++ bb_parse_operand(dst2, &bb_decode.dst2); ++ if (KDB_DEBUG(BB)) ++ bb_print_operand("dst2", &bb_decode.dst2); ++ } ++no_operands: ++ if (!bb_giveup) ++ bb_usage(); ++} ++ ++static int ++bb_dis_pass2(PTR file, const char *fmt, ...) ++{ ++ char *p; ++ int l = strlen(bb_buffer); ++ va_list ap; ++ va_start(ap, fmt); ++ vsnprintf(bb_buffer + l, sizeof(bb_buffer) - l, fmt, ap); ++ va_end(ap); ++ if ((p = strchr(bb_buffer, '\n'))) { ++ *p = '\0'; ++ p = bb_buffer; ++ p += strcspn(p, ":"); ++ if (*p++ == ':') ++ bb_fixup_switch_to(p); ++ bb_parse_buffer(); ++ bb_buffer[0] = '\0'; ++ } ++ return 0; ++} ++ ++static void ++bb_printaddr_pass2(bfd_vma addr, disassemble_info *dip) ++{ ++ kdb_symtab_t symtab; ++ unsigned int offset; ++ dip->fprintf_func(dip->stream, "0x%lx", addr); ++ kdbnearsym(addr, &symtab); ++ if (symtab.sym_name) { ++ dip->fprintf_func(dip->stream, " <%s", symtab.sym_name); ++ if ((offset = addr - symtab.sym_start)) ++ dip->fprintf_func(dip->stream, "+0x%x", offset); ++ dip->fprintf_func(dip->stream, ">"); ++ } ++} ++ ++/* Set the starting register and memory state for the current bb */ ++ ++static void ++bb_start_block0_special(void) ++{ ++ int i; ++ short offset_address; ++ enum bb_reg_code reg, value; ++ struct bb_name_state *r; ++ for (i = 0, r = bb_special_cases; ++ i < ARRAY_SIZE(bb_special_cases); ++ ++i, ++r) { ++ if (bb_func_start == r->address && r->fname == NULL) ++ goto match; ++ } ++ return; ++match: ++ /* Set the running registers */ ++ for (reg = BBRG_RAX; reg < r->regs_size; ++reg) { ++ value = r->regs[reg].value; ++ if (test_bit(value, r->skip_regs.bits)) { ++ /* this regs entry is not defined for this label */ ++ continue; ++ } ++ bb_reg_code_set_value(reg, value); ++ bb_reg_code_set_offset(reg, r->regs[reg].offset); ++ } ++ /* Set any memory contents, e.g. pt_regs. Adjust RSP as required. */ ++ offset_address = 0; ++ for (i = 0; i < r->mem_size; ++i) { ++ offset_address = max_t(int, ++ r->mem[i].offset_address + KDB_WORD_SIZE, ++ offset_address); ++ } ++ if (bb_reg_code_offset(BBRG_RSP) > -offset_address) ++ bb_adjust_osp(BBRG_RSP, -offset_address - bb_reg_code_offset(BBRG_RSP)); ++ for (i = 0; i < r->mem_size; ++i) { ++ value = r->mem[i].value; ++ if (test_bit(value, r->skip_mem.bits)) { ++ /* this memory entry is not defined for this label */ ++ continue; ++ } ++ bb_memory_set_reg_value(BBRG_RSP, r->mem[i].offset_address, ++ value, 0); ++ bb_reg_set_undef(value); ++ } ++ return; ++} ++ ++static void ++bb_pass2_start_block(int number) ++{ ++ int i, j, k, first, changed; ++ size_t size; ++ struct bb_jmp *bb_jmp; ++ struct bb_reg_state *state; ++ struct bb_memory_contains *c1, *c2; ++ bb_reg_state->mem_count = bb_reg_state_max; ++ size = bb_reg_state_size(bb_reg_state); ++ memset(bb_reg_state, 0, size); ++ ++ if (number == 0) { ++ /* The first block is assumed to have well defined inputs */ ++ bb_start_block0(); ++ /* Some assembler labels have non-standard entry ++ * states. ++ */ ++ bb_start_block0_special(); ++ bb_reg_state_print(bb_reg_state); ++ return; ++ } ++ ++ /* Merge all the input states for the current bb together */ ++ first = 1; ++ changed = 0; ++ for (i = 0; i < bb_jmp_count; ++i) { ++ bb_jmp = bb_jmp_list + i; ++ if (bb_jmp->to != bb_curr->start) ++ continue; ++ state = bb_jmp->state; ++ if (!state) ++ continue; ++ if (first) { ++ size = bb_reg_state_size(state); ++ memcpy(bb_reg_state, state, size); ++ KDB_DEBUG_BB(" first state %p\n", state); ++ bb_reg_state_print(bb_reg_state); ++ first = 0; ++ continue; ++ } ++ ++ KDB_DEBUG_BB(" merging state %p\n", state); ++ /* Merge the register states */ ++ for (j = 0; j < ARRAY_SIZE(state->contains); ++j) { ++ if (memcmp(bb_reg_state->contains + j, ++ state->contains + j, ++ sizeof(bb_reg_state->contains[0]))) { ++ /* Different states for this register from two ++ * or more inputs, make it undefined. ++ */ ++ if (bb_reg_state->contains[j].value == ++ BBRG_UNDEFINED) { ++ KDB_DEBUG_BB(" ignoring %s\n", ++ bbrg_name[j + BBRG_RAX]); ++ } else { ++ bb_reg_set_undef(BBRG_RAX + j); ++ changed = 1; ++ } ++ } ++ } ++ ++ /* Merge the memory states. This relies on both ++ * bb_reg_state->memory and state->memory being sorted in ++ * descending order, with undefined entries at the end. ++ */ ++ c1 = bb_reg_state->memory; ++ c2 = state->memory; ++ j = k = 0; ++ while (j < bb_reg_state->mem_count && ++ k < state->mem_count) { ++ if (c1->offset_address < c2->offset_address) { ++ KDB_DEBUG_BB_OFFSET(c2->offset_address, ++ " ignoring c2->offset_address ", ++ "\n"); ++ ++c2; ++ ++k; ++ continue; ++ } ++ if (c1->offset_address > c2->offset_address) { ++ /* Memory location is not in all input states, ++ * delete the memory location. ++ */ ++ bb_delete_memory(c1->offset_address); ++ changed = 1; ++ ++c1; ++ ++j; ++ continue; ++ } ++ if (memcmp(c1, c2, sizeof(*c1))) { ++ /* Same location, different contents, delete ++ * the memory location. ++ */ ++ bb_delete_memory(c1->offset_address); ++ KDB_DEBUG_BB_OFFSET(c2->offset_address, ++ " ignoring c2->offset_address ", ++ "\n"); ++ changed = 1; ++ } ++ ++c1; ++ ++c2; ++ ++j; ++ ++k; ++ } ++ while (j < bb_reg_state->mem_count) { ++ bb_delete_memory(c1->offset_address); ++ changed = 1; ++ ++c1; ++ ++j; ++ } ++ } ++ if (changed) { ++ KDB_DEBUG_BB(" final state\n"); ++ bb_reg_state_print(bb_reg_state); ++ } ++} ++ ++/* We have reached the exit point from the current function, either a call to ++ * the next function or the instruction that was about to executed when an ++ * interrupt occurred. Save the current register state in bb_exit_state. ++ */ ++ ++static void ++bb_save_exit_state(void) ++{ ++ size_t size; ++ debug_kfree(bb_exit_state); ++ bb_exit_state = NULL; ++ bb_reg_state_canonicalize(); ++ size = bb_reg_state_size(bb_reg_state); ++ bb_exit_state = debug_kmalloc(size, GFP_ATOMIC); ++ if (!bb_exit_state) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ memcpy(bb_exit_state, bb_reg_state, size); ++} ++ ++static int ++bb_pass2_do_changed_blocks(int allow_missing) ++{ ++ int i, j, missing, changed, maxloops; ++ unsigned long addr; ++ struct bb_jmp *bb_jmp; ++ KDB_DEBUG_BB("\n %s: allow_missing %d\n", __FUNCTION__, allow_missing); ++ /* Absolute worst case is we have to iterate over all the basic blocks ++ * in an "out of order" state, each iteration losing one register or ++ * memory state. Any more loops than that is a bug. "out of order" ++ * means that the layout of blocks in memory does not match the logic ++ * flow through those blocks so (for example) block 27 comes before ++ * block 2. To allow for out of order blocks, multiply maxloops by the ++ * number of blocks. ++ */ ++ maxloops = (KDB_INT_REGISTERS + bb_reg_state_max) * bb_count; ++ changed = 1; ++ do { ++ changed = 0; ++ for (i = 0; i < bb_count; ++i) { ++ bb_curr = bb_list[i]; ++ if (!bb_curr->changed) ++ continue; ++ missing = 0; ++ for (j = 0, bb_jmp = bb_jmp_list; ++ j < bb_jmp_count; ++ ++j, ++bb_jmp) { ++ if (bb_jmp->to == bb_curr->start && ++ !bb_jmp->state) ++ ++missing; ++ } ++ if (missing > allow_missing) ++ continue; ++ bb_curr->changed = 0; ++ changed = 1; ++ KDB_DEBUG_BB("\n bb[%d]\n", i); ++ bb_pass2_start_block(i); ++ for (addr = bb_curr->start; ++ addr <= bb_curr->end; ) { ++ bb_curr_addr = addr; ++ if (addr == bb_exit_addr) ++ bb_save_exit_state(); ++ addr += kdba_id_printinsn(addr, &kdb_di); ++ kdb_di.fprintf_func(NULL, "\n"); ++ if (bb_giveup) ++ goto done; ++ } ++ if (!bb_exit_state) { ++ /* ATTRIB_NORET functions are a problem with ++ * the current gcc. Allow the trailing address ++ * a bit of leaway. ++ */ ++ if (addr == bb_exit_addr || ++ addr == bb_exit_addr + 1) ++ bb_save_exit_state(); ++ } ++ if (bb_curr->drop_through) ++ bb_transfer(bb_curr->end, ++ bb_list[i+1]->start, 1); ++ } ++ if (maxloops-- == 0) { ++ kdb_printf("\n\n%s maxloops reached\n", ++ __FUNCTION__); ++ bb_giveup = 1; ++ goto done; ++ } ++ } while(changed); ++done: ++ for (i = 0; i < bb_count; ++i) { ++ bb_curr = bb_list[i]; ++ if (bb_curr->changed) ++ return 1; /* more to do, increase allow_missing */ ++ } ++ return 0; /* all blocks done */ ++} ++ ++/* Assume that the current function is a pass through function that does not ++ * refer to its register parameters. Exclude known asmlinkage functions and ++ * assume the other functions actually use their registers. ++ */ ++ ++static void ++bb_assume_pass_through(void) ++{ ++ static int first_time = 1; ++ if (strncmp(bb_func_name, "sys_", 4) == 0 || ++ strncmp(bb_func_name, "compat_sys_", 11) == 0 || ++ strcmp(bb_func_name, "schedule") == 0 || ++ strcmp(bb_func_name, "do_softirq") == 0 || ++ strcmp(bb_func_name, "printk") == 0 || ++ strcmp(bb_func_name, "vprintk") == 0 || ++ strcmp(bb_func_name, "preempt_schedule") == 0 || ++ strcmp(bb_func_name, "start_kernel") == 0 || ++ strcmp(bb_func_name, "csum_partial") == 0 || ++ strcmp(bb_func_name, "csum_partial_copy_generic") == 0 || ++ strcmp(bb_func_name, "math_state_restore") == 0 || ++ strcmp(bb_func_name, "panic") == 0 || ++ strcmp(bb_func_name, "kdb_printf") == 0 || ++ strcmp(bb_func_name, "kdb_interrupt") == 0) ++ return; ++ if (bb_asmlinkage_arch()) ++ return; ++ bb_reg_params = REGPARM; ++ if (first_time) { ++ kdb_printf(" %s has memory parameters but no register " ++ "parameters.\n Assuming it is a 'pass " ++ "through' function that does not refer to " ++ "its register\n parameters and setting %d " ++ "register parameters\n", ++ bb_func_name, REGPARM); ++ first_time = 0; ++ return; ++ } ++ kdb_printf(" Assuming %s is 'pass through' with %d register " ++ "parameters\n", ++ bb_func_name, REGPARM); ++} ++ ++static void ++bb_pass2(void) ++{ ++ int allow_missing; ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf("%s: start\n", __FUNCTION__); ++ ++ kdb_di.fprintf_func = bb_dis_pass2; ++ kdb_di.print_address_func = bb_printaddr_pass2; ++ ++ bb_reg_state = debug_kmalloc(sizeof(*bb_reg_state), GFP_ATOMIC); ++ if (!bb_reg_state) { ++ kdb_printf("\n\n%s: out of debug_kmalloc\n", __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ bb_list[0]->changed = 1; ++ ++ /* If a block does not have all its input states available then it is ++ * possible for a register to initially appear to hold a known value, ++ * but when other inputs are available then it becomes a variable ++ * value. The initial false state of "known" can generate false values ++ * for other registers and can even make it look like stack locations ++ * are being changed. ++ * ++ * To avoid these false positives, only process blocks which have all ++ * their inputs defined. That gives a clean depth first traversal of ++ * the tree, except for loops. If there are any loops, then start ++ * processing blocks with one missing input, then two missing inputs ++ * etc. ++ * ++ * Absolute worst case is we have to iterate over all the jmp entries, ++ * each iteration allowing one more missing input. Any more loops than ++ * that is a bug. Watch out for the corner case of 0 jmp entries. ++ */ ++ for (allow_missing = 0; allow_missing <= bb_jmp_count; ++allow_missing) { ++ if (!bb_pass2_do_changed_blocks(allow_missing)) ++ break; ++ if (bb_giveup) ++ break; ++ } ++ if (allow_missing > bb_jmp_count) { ++ kdb_printf("\n\n%s maxloops reached\n", ++ __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ ++ if (bb_memory_params && bb_reg_params) ++ bb_reg_params = REGPARM; ++ if (REGPARM && ++ bb_memory_params && ++ !bb_reg_params) ++ bb_assume_pass_through(); ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) { ++ kdb_printf("%s: end bb_reg_params %d bb_memory_params %d\n", ++ __FUNCTION__, bb_reg_params, bb_memory_params); ++ if (bb_exit_state) { ++ kdb_printf("%s: bb_exit_state at " kdb_bfd_vma_fmt0 "\n", ++ __FUNCTION__, bb_exit_addr); ++ bb_do_reg_state_print(bb_exit_state); ++ } ++ } ++} ++ ++static void ++bb_cleanup(void) ++{ ++ int i; ++ struct bb* bb; ++ struct bb_reg_state *state; ++ while (bb_count) { ++ bb = bb_list[0]; ++ bb_delete(0); ++ } ++ debug_kfree(bb_list); ++ bb_list = NULL; ++ bb_count = bb_max = 0; ++ for (i = 0; i < bb_jmp_count; ++i) { ++ state = bb_jmp_list[i].state; ++ if (state && --state->ref_count == 0) ++ debug_kfree(state); ++ } ++ debug_kfree(bb_jmp_list); ++ bb_jmp_list = NULL; ++ bb_jmp_count = bb_jmp_max = 0; ++ debug_kfree(bb_reg_state); ++ bb_reg_state = NULL; ++ bb_reg_state_max = 0; ++ debug_kfree(bb_exit_state); ++ bb_exit_state = NULL; ++ bb_reg_params = bb_memory_params = 0; ++ bb_giveup = 0; ++} ++ ++static int ++bb_spurious_global_label(const char *func_name) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(bb_spurious); ++i) { ++ if (strcmp(bb_spurious[i], func_name) == 0) ++ return 1; ++ } ++ return 0; ++} ++ ++/* Given the current actual register contents plus the exit state deduced from ++ * a basic block analysis of the current function, rollback the actual register ++ * contents to the values they had on entry to this function. ++ */ ++ ++static void ++bb_actual_rollback(const struct kdb_activation_record *ar) ++{ ++ int i, offset_address; ++ struct bb_memory_contains *c; ++ enum bb_reg_code reg; ++ unsigned long address, osp = 0; ++ struct bb_actual new[ARRAY_SIZE(bb_actual)]; ++ ++ ++ if (!bb_exit_state) { ++ kdb_printf("%s: no bb_exit_state, cannot rollback\n", ++ __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ memcpy(bb_reg_state, bb_exit_state, bb_reg_state_size(bb_exit_state)); ++ memset(new, 0, sizeof(new)); ++ ++ /* The most important register for obtaining saved state is rsp so get ++ * its new value first. Prefer rsp if it is valid, then other ++ * registers. Saved values of rsp in memory are unusable without a ++ * register that points to memory. ++ */ ++ if (!bb_actual_valid(BBRG_RSP)) { ++ kdb_printf("%s: no starting value for RSP, cannot rollback\n", ++ __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf("%s: rsp " kdb_bfd_vma_fmt0, ++ __FUNCTION__, bb_actual_value(BBRG_RSP)); ++ i = BBRG_RSP; ++ if (!bb_is_osp_defined(i)) { ++ for (i = BBRG_RAX; i < BBRG_RAX + KDB_INT_REGISTERS; ++i) { ++ if (bb_is_osp_defined(i) && bb_actual_valid(i)) ++ break; ++ } ++ } ++ if (bb_is_osp_defined(i) && bb_actual_valid(i)) { ++ osp = new[BBRG_RSP - BBRG_RAX].value = ++ bb_actual_value(i) - bb_reg_code_offset(i); ++ new[BBRG_RSP - BBRG_RAX].valid = 1; ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf(" -> osp " kdb_bfd_vma_fmt0 "\n", osp); ++ } else { ++ bb_actual_set_valid(BBRG_RSP, 0); ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf(" -> undefined\n"); ++ kdb_printf("%s: no ending value for RSP, cannot rollback\n", ++ __FUNCTION__); ++ bb_giveup = 1; ++ return; ++ } ++ ++ /* Now the other registers. First look at register values that have ++ * been copied to other registers. ++ */ ++ for (i = BBRG_RAX; i < BBRG_RAX + KDB_INT_REGISTERS; ++i) { ++ reg = bb_reg_code_value(i); ++ if (bb_is_int_reg(reg)) { ++ new[reg - BBRG_RAX] = bb_actual[i - BBRG_RAX]; ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) { ++ kdb_printf("%s: %s is in %s ", ++ __FUNCTION__, ++ bbrg_name[reg], ++ bbrg_name[i]); ++ if (bb_actual_valid(i)) ++ kdb_printf(" -> " kdb_bfd_vma_fmt0 "\n", ++ bb_actual_value(i)); ++ else ++ kdb_printf("(invalid)\n"); ++ } ++ } ++ } ++ ++ /* Finally register values that have been saved on stack */ ++ for (i = 0, c = bb_reg_state->memory; ++ i < bb_reg_state->mem_count; ++ ++i, ++c) { ++ offset_address = c->offset_address; ++ reg = c->value; ++ if (!bb_is_int_reg(reg)) ++ continue; ++ address = osp + offset_address; ++ if (address < ar->stack.logical_start || ++ address >= ar->stack.logical_end) { ++ new[reg - BBRG_RAX].value = 0; ++ new[reg - BBRG_RAX].valid = 0; ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf("%s: %s -> undefined\n", ++ __FUNCTION__, ++ bbrg_name[reg]); ++ } else { ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) { ++ kdb_printf("%s: %s -> *(osp", ++ __FUNCTION__, ++ bbrg_name[reg]); ++ KDB_DEBUG_BB_OFFSET_PRINTF(offset_address, "", " "); ++ kdb_printf(kdb_bfd_vma_fmt0, address); ++ } ++ new[reg - BBRG_RAX].value = *(bfd_vma *)address; ++ new[reg - BBRG_RAX].valid = 1; ++ if (KDB_DEBUG(BB) | KDB_DEBUG(BB_SUMM)) ++ kdb_printf(") = " kdb_bfd_vma_fmt0 "\n", ++ new[reg - BBRG_RAX].value); ++ } ++ } ++ ++ memcpy(bb_actual, new, sizeof(bb_actual)); ++} ++ ++/* Return true if the current function is an interrupt handler */ ++ ++static bool ++bb_interrupt_handler(kdb_machreg_t rip) ++{ ++ unsigned long disp8, disp32, target, addr = (unsigned long)rip; ++ unsigned char code[5]; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(bb_hardware_handlers); ++i) ++ if (strcmp(bb_func_name, bb_hardware_handlers[i]) == 0) ++ return 1; ++ ++ /* Given the large number of interrupt handlers, it is easiest to look ++ * at the next instruction and see if it is a jmp to the common exit ++ * routines. ++ */ ++ if (kdb_getarea(code, addr) || ++ kdb_getword(&disp32, addr+1, 4) || ++ kdb_getword(&disp8, addr+1, 1)) ++ return 0; /* not a valid code address */ ++ if (code[0] == 0xe9) { ++ target = addr + (s32) disp32 + 5; /* jmp disp32 */ ++ if (target == bb_ret_from_intr || ++ target == bb_common_interrupt || ++ target == bb_error_entry) ++ return 1; ++ } ++ if (code[0] == 0xeb) { ++ target = addr + (s8) disp8 + 2; /* jmp disp8 */ ++ if (target == bb_ret_from_intr || ++ target == bb_common_interrupt || ++ target == bb_error_entry) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Copy argument information that was deduced by the basic block analysis and ++ * rollback into the kdb stack activation record. ++ */ ++ ++static void ++bb_arguments(struct kdb_activation_record *ar) ++{ ++ int i; ++ enum bb_reg_code reg; ++ kdb_machreg_t rsp; ++ ar->args = bb_reg_params + bb_memory_params; ++ bitmap_zero(ar->valid.bits, KDBA_MAXARGS); ++ for (i = 0; i < bb_reg_params; ++i) { ++ reg = bb_param_reg[i]; ++ if (bb_actual_valid(reg)) { ++ ar->arg[i] = bb_actual_value(reg); ++ set_bit(i, ar->valid.bits); ++ } ++ } ++ if (!bb_actual_valid(BBRG_RSP)) ++ return; ++ rsp = bb_actual_value(BBRG_RSP); ++ for (i = bb_reg_params; i < ar->args; ++i) { ++ rsp += KDB_WORD_SIZE; ++ if (kdb_getarea(ar->arg[i], rsp) == 0) ++ set_bit(i, ar->valid.bits); ++ } ++} ++ ++/* Given an exit address from a function, decompose the entire function into ++ * basic blocks and determine the register state at the exit point. ++ */ ++ ++static void ++kdb_bb(unsigned long exit) ++{ ++ kdb_symtab_t symtab; ++ if (!kdbnearsym(exit, &symtab)) { ++ kdb_printf("%s: address " kdb_bfd_vma_fmt0 " not recognised\n", ++ __FUNCTION__, exit); ++ bb_giveup = 1; ++ return; ++ } ++ bb_exit_addr = exit; ++ bb_mod_name = symtab.mod_name; ++ bb_func_name = symtab.sym_name; ++ bb_func_start = symtab.sym_start; ++ bb_func_end = symtab.sym_end; ++ /* Various global labels exist in the middle of assembler code and have ++ * a non-standard state. Ignore these labels and use the start of the ++ * previous label instead. ++ */ ++ while (bb_spurious_global_label(symtab.sym_name)) { ++ if (!kdbnearsym(symtab.sym_start - 1, &symtab)) ++ break; ++ bb_func_start = symtab.sym_start; ++ } ++ bb_mod_name = symtab.mod_name; ++ bb_func_name = symtab.sym_name; ++ bb_func_start = symtab.sym_start; ++ /* Ignore spurious labels past this point and use the next non-spurious ++ * label as the end point. ++ */ ++ if (kdbnearsym(bb_func_end, &symtab)) { ++ while (bb_spurious_global_label(symtab.sym_name)) { ++ bb_func_end = symtab.sym_end; ++ if (!kdbnearsym(symtab.sym_end + 1, &symtab)) ++ break; ++ } ++ } ++ bb_pass1(); ++ if (!bb_giveup) ++ bb_pass2(); ++ if (bb_giveup) ++ kdb_printf("%s: " kdb_bfd_vma_fmt0 ++ " [%s]%s failed at " kdb_bfd_vma_fmt0 "\n\n", ++ __FUNCTION__, exit, ++ bb_mod_name, bb_func_name, bb_curr_addr); ++} ++ ++static int ++kdb_bb1(int argc, const char **argv) ++{ ++ int diag; ++ unsigned long addr; ++ bb_cleanup(); /* in case previous command was interrupted */ ++ kdba_id_init(&kdb_di); ++ if (argc != 1) ++ return KDB_ARGCOUNT; ++ if ((diag = kdbgetularg((char *)argv[1], &addr))) ++ return diag; ++ kdb_save_flags(); ++ kdb_flags |= KDB_DEBUG_FLAG_BB << KDB_DEBUG_FLAG_SHIFT; ++ kdb_bb(addr); ++ bb_cleanup(); ++ kdb_restore_flags(); ++ kdbnearsym_cleanup(); ++ return 0; ++} ++ ++/* Run a basic block analysis on every function in the base kernel. Used as a ++ * global sanity check to find errors in the basic block code. ++ */ ++ ++static int ++kdb_bb_all(int argc, const char **argv) ++{ ++ loff_t pos = 0; ++ const char *symname; ++ unsigned long addr; ++ int i, max_errors = 20; ++ struct bb_name_state *r; ++ kdb_printf("%s: build variables:" ++ " CCVERSION \"" __stringify(CCVERSION) "\"" ++#ifdef CONFIG_X86_64 ++ " CONFIG_X86_64" ++#endif ++#ifdef CONFIG_4KSTACKS ++ " CONFIG_4KSTACKS" ++#endif ++#ifdef CONFIG_PREEMPT ++ " CONFIG_PREEMPT" ++#endif ++#ifdef CONFIG_VM86 ++ " CONFIG_VM86" ++#endif ++#ifdef CONFIG_FRAME_POINTER ++ " CONFIG_FRAME_POINTER" ++#endif ++#ifdef CONFIG_TRACE_IRQFLAGS ++ " CONFIG_TRACE_IRQFLAGS" ++#endif ++#ifdef CONFIG_HIBERNATION ++ " CONFIG_HIBERNATION" ++#endif ++#ifdef CONFIG_KPROBES ++ " CONFIG_KPROBES" ++#endif ++#ifdef CONFIG_KEXEC ++ " CONFIG_KEXEC" ++#endif ++#ifdef CONFIG_MATH_EMULATION ++ " CONFIG_MATH_EMULATION" ++#endif ++#ifdef CONFIG_XEN ++ " CONFIG_XEN" ++#endif ++#ifdef CONFIG_DEBUG_INFO ++ " CONFIG_DEBUG_INFO" ++#endif ++#ifdef NO_SIBLINGS ++ " NO_SIBLINGS" ++#endif ++ " REGPARM=" __stringify(REGPARM) ++ "\n\n", __FUNCTION__); ++ for (i = 0, r = bb_special_cases; ++ i < ARRAY_SIZE(bb_special_cases); ++ ++i, ++r) { ++ if (!r->address) ++ kdb_printf("%s: cannot find special_case name %s\n", ++ __FUNCTION__, r->name); ++ } ++ for (i = 0; i < ARRAY_SIZE(bb_spurious); ++i) { ++ if (!kallsyms_lookup_name(bb_spurious[i])) ++ kdb_printf("%s: cannot find spurious label %s\n", ++ __FUNCTION__, bb_spurious[i]); ++ } ++ while ((symname = kdb_walk_kallsyms(&pos))) { ++ if (strcmp(symname, "_stext") == 0 || ++ strcmp(symname, "stext") == 0) ++ break; ++ } ++ if (!symname) { ++ kdb_printf("%s: cannot find _stext\n", __FUNCTION__); ++ return 0; ++ } ++ kdba_id_init(&kdb_di); ++ i = 0; ++ while ((symname = kdb_walk_kallsyms(&pos))) { ++ if (strcmp(symname, "_etext") == 0) ++ break; ++ if (i++ % 100 == 0) ++ kdb_printf("."); ++ /* x86_64 has some 16 bit functions that appear between stext ++ * and _etext. Skip them. ++ */ ++ if (strcmp(symname, "verify_cpu") == 0 || ++ strcmp(symname, "verify_cpu_noamd") == 0 || ++ strcmp(symname, "verify_cpu_sse_test") == 0 || ++ strcmp(symname, "verify_cpu_no_longmode") == 0 || ++ strcmp(symname, "verify_cpu_sse_ok") == 0 || ++ strcmp(symname, "mode_seta") == 0 || ++ strcmp(symname, "bad_address") == 0 || ++ strcmp(symname, "wakeup_code") == 0 || ++ strcmp(symname, "wakeup_code_start") == 0 || ++ strcmp(symname, "wakeup_start") == 0 || ++ strcmp(symname, "wakeup_32_vector") == 0 || ++ strcmp(symname, "wakeup_32") == 0 || ++ strcmp(symname, "wakeup_long64_vector") == 0 || ++ strcmp(symname, "wakeup_long64") == 0 || ++ strcmp(symname, "gdta") == 0 || ++ strcmp(symname, "idt_48a") == 0 || ++ strcmp(symname, "gdt_48a") == 0 || ++ strcmp(symname, "bogus_real_magic") == 0 || ++ strcmp(symname, "bogus_64_magic") == 0 || ++ strcmp(symname, "no_longmode") == 0 || ++ strcmp(symname, "mode_set") == 0 || ++ strcmp(symname, "mode_seta") == 0 || ++ strcmp(symname, "setbada") == 0 || ++ strcmp(symname, "check_vesa") == 0 || ++ strcmp(symname, "check_vesaa") == 0 || ++ strcmp(symname, "_setbada") == 0 || ++ strcmp(symname, "wakeup_stack_begin") == 0 || ++ strcmp(symname, "wakeup_stack") == 0 || ++ strcmp(symname, "wakeup_level4_pgt") == 0 || ++ strcmp(symname, "acpi_copy_wakeup_routine") == 0 || ++ strcmp(symname, "wakeup_end") == 0 || ++ strcmp(symname, "do_suspend_lowlevel_s4bios") == 0 || ++ strcmp(symname, "do_suspend_lowlevel") == 0 || ++ strcmp(symname, "wakeup_pmode_return") == 0 || ++ strcmp(symname, "restore_registers") == 0) ++ continue; ++ /* __kprobes_text_end contains branches to the middle of code, ++ * with undefined states. ++ */ ++ if (strcmp(symname, "__kprobes_text_end") == 0) ++ continue; ++ /* Data in the middle of the text segment :( */ ++ if (strcmp(symname, "level2_kernel_pgt") == 0 || ++ strcmp(symname, "level3_kernel_pgt") == 0) ++ continue; ++ if (bb_spurious_global_label(symname)) ++ continue; ++ if ((addr = kallsyms_lookup_name(symname)) == 0) ++ continue; ++ // kdb_printf("BB " kdb_bfd_vma_fmt0 " %s\n", addr, symname); ++ bb_cleanup(); /* in case previous command was interrupted */ ++ kdbnearsym_cleanup(); ++ kdb_bb(addr); ++ touch_nmi_watchdog(); ++ if (bb_giveup) { ++ if (max_errors-- == 0) { ++ kdb_printf("%s: max_errors reached, giving up\n", ++ __FUNCTION__); ++ break; ++ } else { ++ bb_giveup = 0; ++ } ++ } ++ } ++ kdb_printf("\n"); ++ bb_cleanup(); ++ kdbnearsym_cleanup(); ++ return 0; ++} ++ ++/* ++ *============================================================================= ++ * ++ * Everything above this line is doing basic block analysis, function by ++ * function. Everything below this line uses the basic block data to do a ++ * complete backtrace over all functions that are used by a process. ++ * ++ *============================================================================= ++ */ ++ ++ ++/*============================================================================*/ ++/* */ ++/* Most of the backtrace code and data is common to x86_64 and i386. This */ ++/* large ifdef contains all of the differences between the two architectures. */ ++/* */ ++/* Make sure you update the correct section of this ifdef. */ ++/* */ ++/*============================================================================*/ ++#define XCS "cs" ++#define RSP "sp" ++#define RIP "ip" ++#define ARCH_RSP sp ++#define ARCH_RIP ip ++ ++#ifdef CONFIG_X86_64 ++ ++#define ARCH_NORMAL_PADDING (16 * 8) ++ ++/* x86_64 has multiple alternate stacks, with different sizes and different ++ * offsets to get the link from one stack to the next. Some of the stacks are ++ * referenced via cpu_pda, some via per_cpu orig_ist. Debug events can even ++ * have multiple nested stacks within the single physical stack, each nested ++ * stack has its own link and some of those links are wrong. ++ * ++ * Consistent it's not! ++ * ++ * Do not assume that these stacks are aligned on their size. ++ */ ++#define INTERRUPT_STACK (N_EXCEPTION_STACKS + 1) ++void ++kdba_get_stack_info_alternate(kdb_machreg_t addr, int cpu, ++ struct kdb_activation_record *ar) ++{ ++ static struct { ++ const char *id; ++ unsigned int total_size; ++ unsigned int nested_size; ++ unsigned int next; ++ } *sdp, stack_data[] = { ++ [STACKFAULT_STACK - 1] = { "stackfault", EXCEPTION_STKSZ, EXCEPTION_STKSZ, EXCEPTION_STKSZ - 2*sizeof(void *) }, ++ [DOUBLEFAULT_STACK - 1] = { "doublefault", EXCEPTION_STKSZ, EXCEPTION_STKSZ, EXCEPTION_STKSZ - 2*sizeof(void *) }, ++ [NMI_STACK - 1] = { "nmi", EXCEPTION_STKSZ, EXCEPTION_STKSZ, EXCEPTION_STKSZ - 2*sizeof(void *) }, ++ [DEBUG_STACK - 1] = { "debug", DEBUG_STKSZ, EXCEPTION_STKSZ, EXCEPTION_STKSZ - 2*sizeof(void *) }, ++ [MCE_STACK - 1] = { "machine check", EXCEPTION_STKSZ, EXCEPTION_STKSZ, EXCEPTION_STKSZ - 2*sizeof(void *) }, ++ [INTERRUPT_STACK - 1] = { "interrupt", IRQSTACKSIZE, IRQSTACKSIZE, IRQSTACKSIZE - sizeof(void *) }, ++ }; ++ unsigned long total_start = 0, total_size, total_end; ++ int sd, found = 0; ++ extern unsigned long kdba_orig_ist(int, int); ++ ++ for (sd = 0, sdp = stack_data; ++ sd < ARRAY_SIZE(stack_data); ++ ++sd, ++sdp) { ++ total_size = sdp->total_size; ++ if (!total_size) ++ continue; /* in case stack_data[] has any holes */ ++ if (cpu < 0) { ++ /* Arbitrary address which can be on any cpu, see if it ++ * falls within any of the alternate stacks ++ */ ++ int c; ++ for_each_online_cpu(c) { ++ if (sd == INTERRUPT_STACK - 1) ++ total_end = (unsigned long)cpu_pda(c)->irqstackptr; ++ else ++ total_end = per_cpu(orig_ist, c).ist[sd]; ++ total_start = total_end - total_size; ++ if (addr >= total_start && addr < total_end) { ++ found = 1; ++ cpu = c; ++ break; ++ } ++ } ++ if (!found) ++ continue; ++ } ++ /* Only check the supplied or found cpu */ ++ if (sd == INTERRUPT_STACK - 1) ++ total_end = (unsigned long)cpu_pda(cpu)->irqstackptr; ++ else ++ total_end = per_cpu(orig_ist, cpu).ist[sd]; ++ total_start = total_end - total_size; ++ if (addr >= total_start && addr < total_end) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) ++ return; ++ /* find which nested stack the address is in */ ++ while (addr > total_start + sdp->nested_size) ++ total_start += sdp->nested_size; ++ ar->stack.physical_start = total_start; ++ ar->stack.physical_end = total_start + sdp->nested_size; ++ ar->stack.logical_start = total_start; ++ ar->stack.logical_end = total_start + sdp->next; ++ ar->stack.next = *(unsigned long *)ar->stack.logical_end; ++ ar->stack.id = sdp->id; ++ ++ /* Nasty: when switching to the interrupt stack, the stack state of the ++ * caller is split over two stacks, the original stack and the ++ * interrupt stack. One word (the previous frame pointer) is stored on ++ * the interrupt stack, the rest of the interrupt data is in the old ++ * frame. To make the interrupted stack state look as though it is ++ * contiguous, copy the missing word from the interrupt stack to the ++ * original stack and adjust the new stack pointer accordingly. ++ */ ++ ++ if (sd == INTERRUPT_STACK - 1) { ++ *(unsigned long *)(ar->stack.next - KDB_WORD_SIZE) = ++ ar->stack.next; ++ ar->stack.next -= KDB_WORD_SIZE; ++ } ++} ++ ++/* rip is not in the thread struct for x86_64. We know that the stack value ++ * was saved in schedule near the label thread_return. Setting rip to ++ * thread_return lets the stack trace find that we are in schedule and ++ * correctly decode its prologue. ++ */ ++ ++static kdb_machreg_t ++kdba_bt_stack_rip(const struct task_struct *p) ++{ ++ return bb_thread_return; ++} ++ ++#else /* !CONFIG_X86_64 */ ++ ++#define ARCH_NORMAL_PADDING (19 * 4) ++ ++#ifdef CONFIG_4KSTACKS ++static struct thread_info **kdba_hardirq_ctx, **kdba_softirq_ctx; ++#endif /* CONFIG_4KSTACKS */ ++ ++/* On a 4K stack kernel, hardirq_ctx and softirq_ctx are [NR_CPUS] arrays. The ++ * first element of each per-cpu stack is a struct thread_info. ++ */ ++void ++kdba_get_stack_info_alternate(kdb_machreg_t addr, int cpu, ++ struct kdb_activation_record *ar) ++{ ++#ifdef CONFIG_4KSTACKS ++ struct thread_info *tinfo; ++ tinfo = (struct thread_info *)(addr & -THREAD_SIZE); ++ if (cpu < 0) { ++ /* Arbitrary address, see if it falls within any of the irq ++ * stacks ++ */ ++ int found = 0; ++ for_each_online_cpu(cpu) { ++ if (tinfo == kdba_hardirq_ctx[cpu] || ++ tinfo == kdba_softirq_ctx[cpu]) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) ++ return; ++ } ++ if (tinfo == kdba_hardirq_ctx[cpu] || ++ tinfo == kdba_softirq_ctx[cpu]) { ++ ar->stack.physical_start = (kdb_machreg_t)tinfo; ++ ar->stack.physical_end = ar->stack.physical_start + THREAD_SIZE; ++ ar->stack.logical_start = ar->stack.physical_start + ++ sizeof(struct thread_info); ++ ar->stack.logical_end = ar->stack.physical_end; ++ ar->stack.next = tinfo->previous_esp; ++ if (tinfo == kdba_hardirq_ctx[cpu]) ++ ar->stack.id = "hardirq_ctx"; ++ else ++ ar->stack.id = "softirq_ctx"; ++ } ++#endif /* CONFIG_4KSTACKS */ ++} ++ ++/* rip is in the thread struct for i386 */ ++ ++static kdb_machreg_t ++kdba_bt_stack_rip(const struct task_struct *p) ++{ ++ return p->thread.ip; ++} ++ ++#endif /* CONFIG_X86_64 */ ++ ++/* Given an address which claims to be on a stack, an optional cpu number and ++ * an optional task address, get information about the stack. ++ * ++ * t == NULL, cpu < 0 indicates an arbitrary stack address with no associated ++ * struct task, the address can be in an alternate stack or any task's normal ++ * stack. ++ * ++ * t != NULL, cpu >= 0 indicates a running task, the address can be in an ++ * alternate stack or that task's normal stack. ++ * ++ * t != NULL, cpu < 0 indicates a blocked task, the address can only be in that ++ * task's normal stack. ++ * ++ * t == NULL, cpu >= 0 is not a valid combination. ++ */ ++ ++static void ++kdba_get_stack_info(kdb_machreg_t rsp, int cpu, ++ struct kdb_activation_record *ar, ++ const struct task_struct *t) ++{ ++ struct thread_info *tinfo; ++ struct task_struct *g, *p; ++ memset(&ar->stack, 0, sizeof(ar->stack)); ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("%s: " RSP "=0x%lx cpu=%d task=%p\n", ++ __FUNCTION__, rsp, cpu, t); ++ if (t == NULL || cpu >= 0) { ++ kdba_get_stack_info_alternate(rsp, cpu, ar); ++ if (ar->stack.logical_start) ++ goto out; ++ } ++ rsp &= -THREAD_SIZE; ++ tinfo = (struct thread_info *)rsp; ++ if (t == NULL) { ++ /* Arbitrary stack address without an associated task, see if ++ * it falls within any normal process stack, including the idle ++ * tasks. ++ */ ++ kdb_do_each_thread(g, p) { ++ if (tinfo == task_thread_info(p)) { ++ t = p; ++ goto found; ++ } ++ } kdb_while_each_thread(g, p); ++ for_each_online_cpu(cpu) { ++ p = idle_task(cpu); ++ if (tinfo == task_thread_info(p)) { ++ t = p; ++ goto found; ++ } ++ } ++ found: ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("%s: found task %p\n", __FUNCTION__, t); ++ } else if (cpu >= 0) { ++ /* running task */ ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ if (krp->p != t || tinfo != task_thread_info(t)) ++ t = NULL; ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("%s: running task %p\n", __FUNCTION__, t); ++ } else { ++ /* blocked task */ ++ if (tinfo != task_thread_info(t)) ++ t = NULL; ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("%s: blocked task %p\n", __FUNCTION__, t); ++ } ++ if (t) { ++ ar->stack.physical_start = rsp; ++ ar->stack.physical_end = rsp + THREAD_SIZE; ++ ar->stack.logical_start = rsp + sizeof(struct thread_info); ++ ar->stack.logical_end = ar->stack.physical_end - ARCH_NORMAL_PADDING; ++ ar->stack.next = 0; ++ ar->stack.id = "normal"; ++ } ++out: ++ if (ar->stack.physical_start && KDB_DEBUG(ARA)) { ++ kdb_printf("%s: ar->stack\n", __FUNCTION__); ++ kdb_printf(" physical_start=0x%lx\n", ar->stack.physical_start); ++ kdb_printf(" physical_end=0x%lx\n", ar->stack.physical_end); ++ kdb_printf(" logical_start=0x%lx\n", ar->stack.logical_start); ++ kdb_printf(" logical_end=0x%lx\n", ar->stack.logical_end); ++ kdb_printf(" next=0x%lx\n", ar->stack.next); ++ kdb_printf(" id=%s\n", ar->stack.id); ++ kdb_printf(" set MDCOUNT %ld\n", ++ (ar->stack.physical_end - ar->stack.physical_start) / ++ KDB_WORD_SIZE); ++ kdb_printf(" mds " kdb_machreg_fmt0 "\n", ++ ar->stack.physical_start); ++ } ++} ++ ++static void ++bt_print_one(kdb_machreg_t rip, kdb_machreg_t rsp, ++ const struct kdb_activation_record *ar, ++ const kdb_symtab_t *symtab, int argcount) ++{ ++ int btsymarg = 0; ++ int nosect = 0; ++ ++ kdbgetintenv("BTSYMARG", &btsymarg); ++ kdbgetintenv("NOSECT", &nosect); ++ ++ kdb_printf(kdb_machreg_fmt0, rsp); ++ kdb_symbol_print(rip, symtab, ++ KDB_SP_SPACEB|KDB_SP_VALUE); ++ if (argcount && ar->args) { ++ int i, argc = ar->args; ++ kdb_printf(" ("); ++ if (argc > argcount) ++ argc = argcount; ++ for (i = 0; i < argc; i++) { ++ if (i) ++ kdb_printf(", "); ++ if (test_bit(i, ar->valid.bits)) ++ kdb_printf("0x%lx", ar->arg[i]); ++ else ++ kdb_printf("invalid"); ++ } ++ kdb_printf(")"); ++ } ++ kdb_printf("\n"); ++ if (symtab->sym_name) { ++ if (!nosect) { ++ kdb_printf(" %s", ++ symtab->mod_name); ++ if (symtab->sec_name && symtab->sec_start) ++ kdb_printf(" 0x%lx 0x%lx", ++ symtab->sec_start, symtab->sec_end); ++ kdb_printf(" 0x%lx 0x%lx\n", ++ symtab->sym_start, symtab->sym_end); ++ } ++ } ++ if (argcount && ar->args && btsymarg) { ++ int i, argc = ar->args; ++ kdb_symtab_t arg_symtab; ++ for (i = 0; i < argc; i++) { ++ kdb_machreg_t arg = ar->arg[i]; ++ if (test_bit(i, ar->valid.bits) && ++ kdbnearsym(arg, &arg_symtab)) { ++ kdb_printf(" ARG %2d ", i); ++ kdb_symbol_print(arg, &arg_symtab, ++ KDB_SP_DEFAULT|KDB_SP_NEWLINE); ++ } ++ } ++ } ++} ++ ++static void ++kdba_bt_new_stack(struct kdb_activation_record *ar, kdb_machreg_t *rsp, ++ int *count, int *suppress) ++{ ++ /* Nasty: common_interrupt builds a partial pt_regs, with r15 through ++ * rbx not being filled in. It passes struct pt_regs* to do_IRQ (in ++ * rdi) but the stack pointer is not adjusted to account for r15 ++ * through rbx. This has two effects :- ++ * ++ * (1) struct pt_regs on an external interrupt actually overlaps with ++ * the local stack area used by do_IRQ. Not only are r15-rbx ++ * undefined, the area that claims to hold their values can even ++ * change as the irq is processed. ++ * ++ * (2) The back stack pointer saved for the new frame is not pointing ++ * at pt_regs, it is pointing at rbx within the pt_regs passed to ++ * do_IRQ. ++ * ++ * There is nothing that I can do about (1) but I have to fix (2) ++ * because kdb backtrace looks for the "start" address of pt_regs as it ++ * walks back through the stacks. When switching from the interrupt ++ * stack to another stack, we have to assume that pt_regs has been ++ * seen and turn off backtrace supression. ++ */ ++ int probable_pt_regs = strcmp(ar->stack.id, "interrupt") == 0; ++ *rsp = ar->stack.next; ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("new " RSP "=" kdb_machreg_fmt0 "\n", *rsp); ++ bb_actual_set_value(BBRG_RSP, *rsp); ++ kdba_get_stack_info(*rsp, -1, ar, NULL); ++ if (!ar->stack.physical_start) { ++ kdb_printf("+++ Cannot resolve next stack\n"); ++ } else if (!*suppress) { ++ kdb_printf(" ======================= <%s>\n", ++ ar->stack.id); ++ ++*count; ++ } ++ if (probable_pt_regs) ++ *suppress = 0; ++} ++ ++/* ++ * kdba_bt_stack ++ * ++ * Inputs: ++ * addr Address provided to 'bt' command, if any. ++ * argcount ++ * p Pointer to task for 'btp' command. ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * Ultimately all the bt* commands come through this routine. If ++ * old_style is 0 then it uses the basic block analysis to get an accurate ++ * backtrace with arguments, otherwise it falls back to the old method of ++ * printing anything on stack that looks like a kernel address. ++ * ++ * Allowing for the stack data pushed by the hardware is tricky. We ++ * deduce the presence of hardware pushed data by looking for interrupt ++ * handlers, either by name or by the code that they contain. This ++ * information must be applied to the next function up the stack, because ++ * the hardware data is above the saved rip for the interrupted (next) ++ * function. ++ * ++ * To make things worse, the amount of data pushed is arch specific and ++ * may depend on the rsp for the next function, not the current function. ++ * The number of bytes pushed by hardware cannot be calculated until we ++ * are actually processing the stack for the interrupted function and have ++ * its rsp. ++ * ++ * It is also possible for an interrupt to occur in user space and for the ++ * interrupt handler to also be interrupted. Check the code selector ++ * whenever the previous function is an interrupt handler and stop ++ * backtracing if the interrupt was not in kernel space. ++ */ ++ ++static int ++kdba_bt_stack(kdb_machreg_t addr, int argcount, const struct task_struct *p, ++ int old_style) ++{ ++ struct kdb_activation_record ar; ++ kdb_machreg_t rip = 0, rsp = 0, prev_rsp, cs; ++ kdb_symtab_t symtab; ++ int rip_at_rsp = 0, count = 0, btsp = 0, suppress, ++ interrupt_handler = 0, prev_interrupt_handler = 0, hardware_pushed, ++ prev_noret = 0; ++ struct pt_regs *regs = NULL; ++ ++ kdbgetintenv("BTSP", &btsp); ++ suppress = !btsp; ++ memset(&ar, 0, sizeof(ar)); ++ if (old_style) ++ kdb_printf("Using old style backtrace, unreliable with no arguments\n"); ++ ++ /* ++ * The caller may have supplied an address at which the stack traceback ++ * operation should begin. This address is assumed by this code to ++ * point to a return address on the stack to be traced back. ++ * ++ * Warning: type in the wrong address and you will get garbage in the ++ * backtrace. ++ */ ++ if (addr) { ++ rsp = addr; ++ kdb_getword(&rip, rsp, sizeof(rip)); ++ rip_at_rsp = 1; ++ suppress = 0; ++ kdba_get_stack_info(rsp, -1, &ar, NULL); ++ } else { ++ if (task_curr(p)) { ++ struct kdb_running_process *krp = ++ kdb_running_process + task_cpu(p); ++ kdb_machreg_t cs; ++ regs = krp->regs; ++ if (krp->seqno && ++ krp->p == p && ++ krp->seqno >= kdb_seqno - 1 && ++ !KDB_NULL_REGS(regs)) { ++ /* valid saved state, continue processing */ ++ } else { ++ kdb_printf ++ ("Process did not save state, cannot backtrace\n"); ++ kdb_ps1(p); ++ return 0; ++ } ++ kdba_getregcontents(XCS, regs, &cs); ++ if ((cs & 0xffff) != __KERNEL_CS) { ++ kdb_printf("Stack is not in kernel space, backtrace not available\n"); ++ return 0; ++ } ++ rip = krp->arch.ARCH_RIP; ++ rsp = krp->arch.ARCH_RSP; ++ kdba_get_stack_info(rsp, kdb_process_cpu(p), &ar, p); ++ } else { ++ /* Not on cpu, assume blocked. Blocked tasks do not ++ * have pt_regs. p->thread contains some data, alas ++ * what it contains differs between i386 and x86_64. ++ */ ++ rip = kdba_bt_stack_rip(p); ++ rsp = p->thread.sp; ++ suppress = 0; ++ kdba_get_stack_info(rsp, -1, &ar, p); ++ } ++ } ++ if (!ar.stack.physical_start) { ++ kdb_printf(RSP "=0x%lx is not in a valid kernel stack, backtrace not available\n", ++ rsp); ++ return 0; ++ } ++ memset(&bb_actual, 0, sizeof(bb_actual)); ++ bb_actual_set_value(BBRG_RSP, rsp); ++ bb_actual_set_valid(BBRG_RSP, 1); ++ ++ kdb_printf(RSP "%*s" RIP "%*sFunction (args)\n", ++ 2*KDB_WORD_SIZE, " ", ++ 2*KDB_WORD_SIZE, " "); ++ if (ar.stack.next && !suppress) ++ kdb_printf(" ======================= <%s>\n", ++ ar.stack.id); ++ ++ bb_cleanup(); ++ /* Run through all the stacks */ ++ while (ar.stack.physical_start) { ++ if (rip_at_rsp) { ++ rip = *(kdb_machreg_t *)rsp; ++ /* I wish that gcc was fixed to include a nop ++ * instruction after ATTRIB_NORET functions. The lack ++ * of a nop means that the return address points to the ++ * start of next function, so fudge it to point to one ++ * byte previous. ++ * ++ * No, we cannot just decrement all rip values. ++ * Sometimes an rip legally points to the start of a ++ * function, e.g. interrupted code or hand crafted ++ * assembler. ++ */ ++ if (prev_noret) { ++ kdbnearsym(rip, &symtab); ++ if (rip == symtab.sym_start) { ++ --rip; ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("\tprev_noret, " RIP ++ "=0x%lx\n", rip); ++ } ++ } ++ } ++ kdbnearsym(rip, &symtab); ++ if (old_style) { ++ if (__kernel_text_address(rip) && !suppress) { ++ bt_print_one(rip, rsp, &ar, &symtab, 0); ++ ++count; ++ } ++ if (rsp == (unsigned long)regs) { ++ if (ar.stack.next && suppress) ++ kdb_printf(" ======================= <%s>\n", ++ ar.stack.id); ++ ++count; ++ suppress = 0; ++ } ++ rsp += sizeof(rip); ++ rip_at_rsp = 1; ++ if (rsp >= ar.stack.logical_end) { ++ if (!ar.stack.next) ++ break; ++ kdba_bt_new_stack(&ar, &rsp, &count, &suppress); ++ rip_at_rsp = 0; ++ continue; ++ } ++ } else { ++ /* Start each analysis with no dynamic data from the ++ * previous kdb_bb() run. ++ */ ++ bb_cleanup(); ++ kdb_bb(rip); ++ if (bb_giveup) ++ break; ++ prev_interrupt_handler = interrupt_handler; ++ interrupt_handler = bb_interrupt_handler(rip); ++ prev_rsp = rsp; ++ if (rip_at_rsp) { ++ if (prev_interrupt_handler) { ++ cs = *((kdb_machreg_t *)rsp + 1) & 0xffff; ++ hardware_pushed = ++ bb_hardware_pushed_arch(rsp, &ar); ++ } else { ++ cs = __KERNEL_CS; ++ hardware_pushed = 0; ++ } ++ rsp += sizeof(rip) + hardware_pushed; ++ if (KDB_DEBUG(ARA)) ++ kdb_printf("%s: " RSP " " ++ kdb_machreg_fmt0 ++ " -> " kdb_machreg_fmt0 ++ " hardware_pushed %d" ++ " prev_interrupt_handler %d" ++ " cs 0x%lx\n", ++ __FUNCTION__, ++ prev_rsp, ++ rsp, ++ hardware_pushed, ++ prev_interrupt_handler, ++ cs); ++ if (rsp >= ar.stack.logical_end && ++ ar.stack.next) { ++ kdba_bt_new_stack(&ar, &rsp, &count, ++ &suppress); ++ rip_at_rsp = 0; ++ continue; ++ } ++ bb_actual_set_value(BBRG_RSP, rsp); ++ } else { ++ cs = __KERNEL_CS; ++ } ++ rip_at_rsp = 1; ++ bb_actual_rollback(&ar); ++ if (bb_giveup) ++ break; ++ if (bb_actual_value(BBRG_RSP) < rsp) { ++ kdb_printf("%s: " RSP " is going backwards, " ++ kdb_machreg_fmt0 " -> " ++ kdb_machreg_fmt0 "\n", ++ __FUNCTION__, ++ rsp, ++ bb_actual_value(BBRG_RSP)); ++ bb_giveup = 1; ++ break; ++ } ++ bb_arguments(&ar); ++ if (!suppress) { ++ bt_print_one(rip, prev_rsp, &ar, &symtab, argcount); ++ ++count; ++ } ++ /* Functions that terminate the backtrace */ ++ if (strcmp(bb_func_name, "cpu_idle") == 0 || ++ strcmp(bb_func_name, "child_rip") == 0) ++ break; ++ if (rsp >= ar.stack.logical_end && ++ !ar.stack.next) ++ break; ++ if (rsp <= (unsigned long)regs && ++ bb_actual_value(BBRG_RSP) > (unsigned long)regs) { ++ if (ar.stack.next && suppress) ++ kdb_printf(" ======================= <%s>\n", ++ ar.stack.id); ++ ++count; ++ suppress = 0; ++ } ++ if (cs != __KERNEL_CS) { ++ kdb_printf("Reached user space\n"); ++ break; ++ } ++ rsp = bb_actual_value(BBRG_RSP); ++ } ++ prev_noret = bb_noret(bb_func_name); ++ if (count > 200) ++ break; ++ } ++ if (bb_giveup) ++ return 1; ++ bb_cleanup(); ++ kdbnearsym_cleanup(); ++ ++ if (count > 200) { ++ kdb_printf("bt truncated, count limit reached\n"); ++ return 1; ++ } else if (suppress) { ++ kdb_printf ++ ("bt did not find pt_regs - no trace produced. Suggest 'set BTSP 1'\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * kdba_bt_address ++ * ++ * Do a backtrace starting at a specified stack address. Use this if the ++ * heuristics get the stack decode wrong. ++ * ++ * Inputs: ++ * addr Address provided to 'bt' command. ++ * argcount ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * mds %rsp comes in handy when examining the stack to do a manual ++ * traceback. ++ */ ++ ++int kdba_bt_address(kdb_machreg_t addr, int argcount) ++{ ++ int ret; ++ kdba_id_init(&kdb_di); /* kdb_bb needs this done once */ ++ ret = kdba_bt_stack(addr, argcount, NULL, 0); ++ if (ret == 1) ++ ret = kdba_bt_stack(addr, argcount, NULL, 1); ++ return ret; ++} ++ ++/* ++ * kdba_bt_process ++ * ++ * Do a backtrace for a specified process. ++ * ++ * Inputs: ++ * p Struct task pointer extracted by 'bt' command. ++ * argcount ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ */ ++ ++int kdba_bt_process(const struct task_struct *p, int argcount) ++{ ++ int ret; ++ kdba_id_init(&kdb_di); /* kdb_bb needs this done once */ ++ ret = kdba_bt_stack(0, argcount, p, 0); ++ if (ret == 1) ++ ret = kdba_bt_stack(0, argcount, p, 1); ++ return ret; ++} ++ ++static int __init kdba_bt_x86_init(void) ++{ ++ int i, c, cp = -1; ++ struct bb_name_state *r; ++ ++ kdb_register_repeat("bb1", kdb_bb1, "", "Analyse one basic block", 0, KDB_REPEAT_NONE); ++ kdb_register_repeat("bb_all", kdb_bb_all, "", "Backtrace check on all built in functions", 0, KDB_REPEAT_NONE); ++ ++ /* Split the opcode usage table by the first letter of each set of ++ * opcodes, for faster mapping of opcode to its operand usage. ++ */ ++ for (i = 0; i < ARRAY_SIZE(bb_opcode_usage_all); ++i) { ++ c = bb_opcode_usage_all[i].opcode[0] - 'a'; ++ if (c != cp) { ++ cp = c; ++ bb_opcode_usage[c].opcode = bb_opcode_usage_all + i; ++ } ++ ++bb_opcode_usage[c].size; ++ } ++ ++ bb_common_interrupt = kallsyms_lookup_name("common_interrupt"); ++ bb_error_entry = kallsyms_lookup_name("error_entry"); ++ bb_ret_from_intr = kallsyms_lookup_name("ret_from_intr"); ++ bb_thread_return = kallsyms_lookup_name("thread_return"); ++ bb_sync_regs = kallsyms_lookup_name("sync_regs"); ++ bb_save_v86_state = kallsyms_lookup_name("save_v86_state"); ++ bb__sched_text_start = kallsyms_lookup_name("__sched_text_start"); ++ bb__sched_text_end = kallsyms_lookup_name("__sched_text_end"); ++ for (i = 0, r = bb_special_cases; ++ i < ARRAY_SIZE(bb_special_cases); ++ ++i, ++r) { ++ r->address = kallsyms_lookup_name(r->name); ++ } ++ ++#ifdef CONFIG_4KSTACKS ++ kdba_hardirq_ctx = (struct thread_info **)kallsyms_lookup_name("hardirq_ctx"); ++ kdba_softirq_ctx = (struct thread_info **)kallsyms_lookup_name("softirq_ctx"); ++#endif /* CONFIG_4KSTACKS */ ++ ++ return 0; ++} ++ ++static void __exit kdba_bt_x86_exit(void) ++{ ++ kdb_unregister("bb1"); ++ kdb_unregister("bb_all"); ++} ++ ++module_init(kdba_bt_x86_init) ++module_exit(kdba_bt_x86_exit) +--- /dev/null ++++ b/arch/x86/kdb/kdba_id.c +@@ -0,0 +1,261 @@ ++/* ++ * Kernel Debugger Architecture Dependent Instruction Disassembly ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * kdba_dis_getsym ++ * ++ * Get a symbol for the disassembler. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * dip Pointer to disassemble_info ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * Not used for kdb. ++ */ ++ ++/* ARGSUSED */ ++static int ++kdba_dis_getsym(bfd_vma addr, disassemble_info *dip) ++{ ++ ++ return 0; ++} ++ ++/* ++ * kdba_printaddress ++ * ++ * Print (symbolically) an address. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * dip Pointer to disassemble_info ++ * flag True if a ":" sequence should follow the address ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * ++ */ ++ ++/* ARGSUSED */ ++static void ++kdba_printaddress(kdb_machreg_t addr, disassemble_info *dip, int flag) ++{ ++ kdb_symtab_t symtab; ++ int spaces = 5; ++ unsigned int offset; ++ ++ /* ++ * Print a symbol name or address as necessary. ++ */ ++ kdbnearsym(addr, &symtab); ++ if (symtab.sym_name) { ++ /* Do not use kdb_symbol_print here, it always does ++ * kdb_printf but we want dip->fprintf_func. ++ */ ++ dip->fprintf_func(dip->stream, ++ "0x%0*lx %s", ++ (int)(2*sizeof(addr)), addr, symtab.sym_name); ++ if ((offset = addr - symtab.sym_start) == 0) { ++ spaces += 4; ++ } ++ else { ++ unsigned int o = offset; ++ while (o >>= 4) ++ --spaces; ++ dip->fprintf_func(dip->stream, "+0x%x", offset); ++ } ++ ++ } else { ++ dip->fprintf_func(dip->stream, "0x%lx", addr); ++ } ++ ++ if (flag) { ++ if (spaces < 1) { ++ spaces = 1; ++ } ++ dip->fprintf_func(dip->stream, ":%*s", spaces, " "); ++ } ++} ++ ++/* ++ * kdba_dis_printaddr ++ * ++ * Print (symbolically) an address. Called by GNU disassembly ++ * code via disassemble_info structure. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * dip Pointer to disassemble_info ++ * Returns: ++ * 0 ++ * Locking: ++ * Remarks: ++ * This function will never append ":" to the printed ++ * symbolic address. ++ */ ++ ++static void ++kdba_dis_printaddr(bfd_vma addr, disassemble_info *dip) ++{ ++ kdba_printaddress(addr, dip, 0); ++} ++ ++/* ++ * kdba_dis_getmem ++ * ++ * Fetch 'length' bytes from 'addr' into 'buf'. ++ * ++ * Parameters: ++ * addr Address for which to get symbol ++ * buf Address of buffer to fill with bytes from 'addr' ++ * length Number of bytes to fetch ++ * dip Pointer to disassemble_info ++ * Returns: ++ * 0 if data is available, otherwise error. ++ * Locking: ++ * Remarks: ++ * ++ */ ++ ++/* ARGSUSED */ ++static int ++kdba_dis_getmem(bfd_vma addr, bfd_byte *buf, unsigned int length, disassemble_info *dip) ++{ ++ return kdb_getarea_size(buf, addr, length); ++} ++ ++/* ++ * kdba_id_parsemode ++ * ++ * Parse IDMODE environment variable string and ++ * set appropriate value into "disassemble_info" structure. ++ * ++ * Parameters: ++ * mode Mode string ++ * dip Disassemble_info structure pointer ++ * Returns: ++ * Locking: ++ * Remarks: ++ * We handle the values 'x86' and '8086' to enable either ++ * 32-bit instruction set or 16-bit legacy instruction set. ++ */ ++ ++int ++kdba_id_parsemode(const char *mode, disassemble_info *dip) ++{ ++ if (mode) { ++ if (strcmp(mode, "x86_64") == 0) { ++ dip->mach = bfd_mach_x86_64; ++ } else if (strcmp(mode, "x86") == 0) { ++ dip->mach = bfd_mach_i386_i386; ++ } else if (strcmp(mode, "8086") == 0) { ++ dip->mach = bfd_mach_i386_i8086; ++ } else { ++ return KDB_BADMODE; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * kdba_check_pc ++ * ++ * Check that the pc is satisfactory. ++ * ++ * Parameters: ++ * pc Program Counter Value. ++ * Returns: ++ * None ++ * Locking: ++ * None. ++ * Remarks: ++ * Can change pc. ++ */ ++ ++void ++kdba_check_pc(kdb_machreg_t *pc) ++{ ++ /* No action */ ++} ++ ++/* ++ * kdba_id_printinsn ++ * ++ * Format and print a single instruction at 'pc'. Return the ++ * length of the instruction. ++ * ++ * Parameters: ++ * pc Program Counter Value. ++ * dip Disassemble_info structure pointer ++ * Returns: ++ * Length of instruction, -1 for error. ++ * Locking: ++ * None. ++ * Remarks: ++ * Depends on 'IDMODE' environment variable. ++ */ ++ ++int ++kdba_id_printinsn(kdb_machreg_t pc, disassemble_info *dip) ++{ ++ kdba_printaddress(pc, dip, 1); ++ return print_insn_i386_att(pc, dip); ++} ++ ++/* ++ * kdba_id_init ++ * ++ * Initialize the architecture dependent elements of ++ * the disassembly information structure ++ * for the GNU disassembler. ++ * ++ * Parameters: ++ * None. ++ * Outputs: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++void ++kdba_id_init(disassemble_info *dip) ++{ ++ dip->read_memory_func = kdba_dis_getmem; ++ dip->print_address_func = kdba_dis_printaddr; ++ dip->symbol_at_address_func = kdba_dis_getsym; ++ ++ dip->flavour = bfd_target_elf_flavour; ++ dip->arch = bfd_arch_i386; ++#ifdef CONFIG_X86_64 ++ dip->mach = bfd_mach_x86_64; ++#endif ++#ifdef CONFIG_X86_32 ++ dip->mach = bfd_mach_i386_i386; ++#endif ++ dip->endian = BFD_ENDIAN_LITTLE; ++ ++ dip->display_endian = BFD_ENDIAN_LITTLE; ++} +--- /dev/null ++++ b/arch/x86/kdb/kdba_io.c +@@ -0,0 +1,609 @@ ++/* ++ * Kernel Debugger Architecture Dependent Console I/O handler ++ * ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_VT_CONSOLE ++#define KDB_BLINK_LED 1 ++#else ++#undef KDB_BLINK_LED ++#endif ++ ++#ifdef CONFIG_KDB_USB ++ ++/* support up to 8 USB keyboards (probably excessive, but...) */ ++#define KDB_USB_NUM_KEYBOARDS 8 ++struct kdb_usb_kbd_info kdb_usb_kbds[KDB_USB_NUM_KEYBOARDS]; ++ ++extern int kdb_no_usb; ++ ++static unsigned char kdb_usb_keycode[256] = { ++ 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, ++ 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, ++ 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, ++ 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, ++ 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, ++ 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, ++ 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, ++ 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113, ++ 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189, ++ 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, ++ 150,158,159,128,136,177,178,176,142,152,173,140 ++}; ++ ++/* ++ * kdb_usb_keyboard_attach() ++ * Attach a USB keyboard to kdb. ++ */ ++int ++kdb_usb_keyboard_attach(struct urb *urb, unsigned char *buffer, void *poll_func) ++{ ++ int i; ++ int rc = -1; ++ ++ if (kdb_no_usb) ++ return 0; ++ ++ /* ++ * Search through the array of KDB USB keyboards (kdb_usb_kbds) ++ * looking for a free index. If found, assign the keyboard to ++ * the array index. ++ */ ++ ++ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { ++ if (kdb_usb_kbds[i].urb) /* index is already assigned */ ++ continue; ++ ++ /* found a free array index */ ++ kdb_usb_kbds[i].urb = urb; ++ kdb_usb_kbds[i].buffer = buffer; ++ kdb_usb_kbds[i].poll_func = poll_func; ++ ++ rc = 0; /* success */ ++ ++ break; ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL (kdb_usb_keyboard_attach); ++ ++/* ++ * kdb_usb_keyboard_detach() ++ * Detach a USB keyboard from kdb. ++ */ ++int ++kdb_usb_keyboard_detach(struct urb *urb) ++{ ++ int i; ++ int rc = -1; ++ ++ if (kdb_no_usb) ++ return 0; ++ ++ /* ++ * Search through the array of KDB USB keyboards (kdb_usb_kbds) ++ * looking for the index with the matching URB. If found, ++ * clear the array index. ++ */ ++ ++ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { ++ if (kdb_usb_kbds[i].urb != urb) ++ continue; ++ ++ /* found it, clear the index */ ++ kdb_usb_kbds[i].urb = NULL; ++ kdb_usb_kbds[i].buffer = NULL; ++ kdb_usb_kbds[i].poll_func = NULL; ++ kdb_usb_kbds[i].caps_lock = 0; ++ ++ rc = 0; /* success */ ++ ++ break; ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL (kdb_usb_keyboard_detach); ++ ++/* ++ * get_usb_char ++ * This function drives the USB attached keyboards. ++ * Fetch the USB scancode and decode it. ++ */ ++static int ++get_usb_char(void) ++{ ++ int i; ++ int ret; ++ unsigned char keycode, spec; ++ extern u_short plain_map[], shift_map[], ctrl_map[]; ++ ++ if (kdb_no_usb) ++ return -1; ++ ++ /* ++ * Loop through all the USB keyboard(s) and return ++ * the first character obtained from them. ++ */ ++ ++ for (i = 0; i < KDB_USB_NUM_KEYBOARDS; i++) { ++ /* skip uninitialized keyboard array entries */ ++ if (!kdb_usb_kbds[i].urb || !kdb_usb_kbds[i].buffer || ++ !kdb_usb_kbds[i].poll_func) ++ continue; ++ ++ /* Transfer char */ ++ ret = (*kdb_usb_kbds[i].poll_func)(kdb_usb_kbds[i].urb); ++ if (ret == -EBUSY && kdb_usb_kbds[i].poll_ret != -EBUSY) ++ kdb_printf("NOTICE: USB HD driver BUSY. " ++ "USB keyboard has been disabled.\n"); ++ ++ kdb_usb_kbds[i].poll_ret = ret; ++ ++ if (ret < 0) /* error or no characters, try the next kbd */ ++ continue; ++ ++ spec = kdb_usb_kbds[i].buffer[0]; ++ keycode = kdb_usb_kbds[i].buffer[2]; ++ kdb_usb_kbds[i].buffer[0] = (char)0; ++ kdb_usb_kbds[i].buffer[2] = (char)0; ++ ++ if(kdb_usb_kbds[i].buffer[3]) { ++ kdb_usb_kbds[i].buffer[3] = (char)0; ++ continue; ++ } ++ ++ /* A normal key is pressed, decode it */ ++ if(keycode) ++ keycode = kdb_usb_keycode[keycode]; ++ ++ /* 2 Keys pressed at one time ? */ ++ if (spec && keycode) { ++ switch(spec) ++ { ++ case 0x2: ++ case 0x20: /* Shift */ ++ return shift_map[keycode]; ++ case 0x1: ++ case 0x10: /* Ctrl */ ++ return ctrl_map[keycode]; ++ case 0x4: ++ case 0x40: /* Alt */ ++ break; ++ } ++ } else if (keycode) { /* If only one key pressed */ ++ switch(keycode) ++ { ++ case 0x1C: /* Enter */ ++ return 13; ++ ++ case 0x3A: /* Capslock */ ++ kdb_usb_kbds[i].caps_lock = !(kdb_usb_kbds[i].caps_lock); ++ break; ++ case 0x0E: /* Backspace */ ++ return 8; ++ case 0x0F: /* TAB */ ++ return 9; ++ case 0x77: /* Pause */ ++ break ; ++ default: ++ if(!kdb_usb_kbds[i].caps_lock) { ++ return plain_map[keycode]; ++ } ++ else { ++ return shift_map[keycode]; ++ } ++ } ++ } ++ } ++ ++ /* no chars were returned from any of the USB keyboards */ ++ ++ return -1; ++} ++#endif /* CONFIG_KDB_USB */ ++ ++/* ++ * This module contains code to read characters from the keyboard or a serial ++ * port. ++ * ++ * It is used by the kernel debugger, and is polled, not interrupt driven. ++ * ++ */ ++ ++#ifdef KDB_BLINK_LED ++/* ++ * send: Send a byte to the keyboard controller. Used primarily to ++ * alter LED settings. ++ */ ++ ++static void ++kdb_kbdsend(unsigned char byte) ++{ ++ int timeout; ++ for (timeout = 200 * 1000; timeout && (inb(KBD_STATUS_REG) & KBD_STAT_IBF); timeout--); ++ outb(byte, KBD_DATA_REG); ++ udelay(40); ++ for (timeout = 200 * 1000; timeout && (~inb(KBD_STATUS_REG) & KBD_STAT_OBF); timeout--); ++ inb(KBD_DATA_REG); ++ udelay(40); ++} ++ ++static void ++kdb_toggleled(int led) ++{ ++ static int leds; ++ ++ leds ^= led; ++ ++ kdb_kbdsend(KBD_CMD_SET_LEDS); ++ kdb_kbdsend((unsigned char)leds); ++} ++#endif /* KDB_BLINK_LED */ ++ ++#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_CORE_CONSOLE) ++#define CONFIG_SERIAL_CONSOLE ++#endif ++ ++#if defined(CONFIG_SERIAL_CONSOLE) ++ ++struct kdb_serial kdb_serial; ++ ++static unsigned int ++serial_inp(struct kdb_serial *kdb_serial, unsigned long offset) ++{ ++ offset <<= kdb_serial->ioreg_shift; ++ ++ switch (kdb_serial->io_type) { ++ case SERIAL_IO_MEM: ++ return readb((void __iomem *)(kdb_serial->iobase + offset)); ++ break; ++ default: ++ return inb(kdb_serial->iobase + offset); ++ break; ++ } ++} ++ ++/* Check if there is a byte ready at the serial port */ ++static int get_serial_char(void) ++{ ++ unsigned char ch; ++ ++ if (kdb_serial.iobase == 0) ++ return -1; ++ ++ if (serial_inp(&kdb_serial, UART_LSR) & UART_LSR_DR) { ++ ch = serial_inp(&kdb_serial, UART_RX); ++ if (ch == 0x7f) ++ ch = 8; ++ return ch; ++ } ++ return -1; ++} ++#endif /* CONFIG_SERIAL_CONSOLE */ ++ ++#ifdef CONFIG_VT_CONSOLE ++ ++static int kbd_exists; ++ ++/* ++ * Check if the keyboard controller has a keypress for us. ++ * Some parts (Enter Release, LED change) are still blocking polled here, ++ * but hopefully they are all short. ++ */ ++static int get_kbd_char(void) ++{ ++ int scancode, scanstatus; ++ static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ ++ static int shift_key; /* Shift next keypress */ ++ static int ctrl_key; ++ u_short keychar; ++ extern u_short plain_map[], shift_map[], ctrl_map[]; ++ ++ if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) || ++ (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) { ++ kbd_exists = 0; ++ return -1; ++ } ++ kbd_exists = 1; ++ ++ if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ++ return -1; ++ ++ /* ++ * Fetch the scancode ++ */ ++ scancode = inb(KBD_DATA_REG); ++ scanstatus = inb(KBD_STATUS_REG); ++ ++ /* ++ * Ignore mouse events. ++ */ ++ if (scanstatus & KBD_STAT_MOUSE_OBF) ++ return -1; ++ ++ /* ++ * Ignore release, trigger on make ++ * (except for shift keys, where we want to ++ * keep the shift state so long as the key is ++ * held down). ++ */ ++ ++ if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { ++ /* ++ * Next key may use shift table ++ */ ++ if ((scancode & 0x80) == 0) { ++ shift_key=1; ++ } else { ++ shift_key=0; ++ } ++ return -1; ++ } ++ ++ if ((scancode&0x7f) == 0x1d) { ++ /* ++ * Left ctrl key ++ */ ++ if ((scancode & 0x80) == 0) { ++ ctrl_key = 1; ++ } else { ++ ctrl_key = 0; ++ } ++ return -1; ++ } ++ ++ if ((scancode & 0x80) != 0) ++ return -1; ++ ++ scancode &= 0x7f; ++ ++ /* ++ * Translate scancode ++ */ ++ ++ if (scancode == 0x3a) { ++ /* ++ * Toggle caps lock ++ */ ++ shift_lock ^= 1; ++ ++#ifdef KDB_BLINK_LED ++ kdb_toggleled(0x4); ++#endif ++ return -1; ++ } ++ ++ if (scancode == 0x0e) { ++ /* ++ * Backspace ++ */ ++ return 8; ++ } ++ ++ /* Special Key */ ++ switch (scancode) { ++ case 0xF: /* Tab */ ++ return 9; ++ case 0x53: /* Del */ ++ return 4; ++ case 0x47: /* Home */ ++ return 1; ++ case 0x4F: /* End */ ++ return 5; ++ case 0x4B: /* Left */ ++ return 2; ++ case 0x48: /* Up */ ++ return 16; ++ case 0x50: /* Down */ ++ return 14; ++ case 0x4D: /* Right */ ++ return 6; ++ } ++ ++ if (scancode == 0xe0) { ++ return -1; ++ } ++ ++ /* ++ * For Japanese 86/106 keyboards ++ * See comment in drivers/char/pc_keyb.c. ++ * - Masahiro Adegawa ++ */ ++ if (scancode == 0x73) { ++ scancode = 0x59; ++ } else if (scancode == 0x7d) { ++ scancode = 0x7c; ++ } ++ ++ if (!shift_lock && !shift_key && !ctrl_key) { ++ keychar = plain_map[scancode]; ++ } else if (shift_lock || shift_key) { ++ keychar = shift_map[scancode]; ++ } else if (ctrl_key) { ++ keychar = ctrl_map[scancode]; ++ } else { ++ keychar = 0x0020; ++ kdb_printf("Unknown state/scancode (%d)\n", scancode); ++ } ++ keychar &= 0x0fff; ++ if (keychar == '\t') ++ keychar = ' '; ++ switch (KTYP(keychar)) { ++ case KT_LETTER: ++ case KT_LATIN: ++ if (isprint(keychar)) ++ break; /* printable characters */ ++ /* drop through */ ++ case KT_SPEC: ++ if (keychar == K_ENTER) ++ break; ++ /* drop through */ ++ default: ++ return(-1); /* ignore unprintables */ ++ } ++ ++ if ((scancode & 0x7f) == 0x1c) { ++ /* ++ * enter key. All done. Absorb the release scancode. ++ */ ++ while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ++ ; ++ ++ /* ++ * Fetch the scancode ++ */ ++ scancode = inb(KBD_DATA_REG); ++ scanstatus = inb(KBD_STATUS_REG); ++ ++ while (scanstatus & KBD_STAT_MOUSE_OBF) { ++ scancode = inb(KBD_DATA_REG); ++ scanstatus = inb(KBD_STATUS_REG); ++ } ++ ++ if (scancode != 0x9c) { ++ /* ++ * Wasn't an enter-release, why not? ++ */ ++ kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", ++ scancode, scanstatus); ++ } ++ ++ kdb_printf("\n"); ++ return 13; ++ } ++ ++ return keychar & 0xff; ++} ++#endif /* CONFIG_VT_CONSOLE */ ++ ++#ifdef KDB_BLINK_LED ++ ++/* Leave numlock alone, setting it messes up laptop keyboards with the keypad ++ * mapped over normal keys. ++ */ ++static int kdba_blink_mask = 0x1 | 0x4; ++ ++#define BOGOMIPS (boot_cpu_data.loops_per_jiffy/(500000/HZ)) ++static int blink_led(void) ++{ ++ static long delay; ++ ++ if (kbd_exists == 0) ++ return -1; ++ ++ if (--delay < 0) { ++ if (BOGOMIPS == 0) /* early kdb */ ++ delay = 150000000/1000; /* arbitrary bogomips */ ++ else ++ delay = 150000000/BOGOMIPS; /* Roughly 1 second when polling */ ++ kdb_toggleled(kdba_blink_mask); ++ } ++ return -1; ++} ++#endif ++ ++get_char_func poll_funcs[] = { ++#if defined(CONFIG_VT_CONSOLE) ++ get_kbd_char, ++#endif ++#if defined(CONFIG_SERIAL_CONSOLE) ++ get_serial_char, ++#endif ++#ifdef KDB_BLINK_LED ++ blink_led, ++#endif ++#ifdef CONFIG_KDB_USB ++ get_usb_char, ++#endif ++ NULL ++}; ++ ++/* ++ * On some Compaq Deskpro's, there is a keyboard freeze many times after ++ * exiting from the kdb. As kdb's keyboard handler is not interrupt-driven and ++ * uses a polled interface, it makes more sense to disable motherboard keyboard ++ * controller's OBF interrupts during kdb's polling.In case, of interrupts ++ * remaining enabled during kdb's polling, it may cause un-necessary ++ * interrupts being signalled during keypresses, which are also sometimes seen ++ * as spurious interrupts after exiting from kdb. This hack to disable OBF ++ * interrupts before entry to kdb and re-enabling them at kdb exit point also ++ * solves the keyboard freeze issue. These functions are called from ++ * kdb_local(), hence these are arch. specific setup and cleanup functions ++ * executing only on the local processor - ashishk@sco.com ++ */ ++ ++void kdba_local_arch_setup(void) ++{ ++#ifdef CONFIG_VT_CONSOLE ++ int timeout; ++ unsigned char c; ++ ++ while (kbd_read_status() & KBD_STAT_IBF); ++ kbd_write_command(KBD_CCMD_READ_MODE); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF); ++ for (timeout = 200 * 1000; timeout && ++ (!(kbd_read_status() & KBD_STAT_OBF)); timeout--); ++ c = kbd_read_input(); ++ c &= ~KBD_MODE_KBD_INT; ++ while (kbd_read_status() & KBD_STAT_IBF); ++ kbd_write_command(KBD_CCMD_WRITE_MODE); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF); ++ kbd_write_output(c); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF); ++ mdelay(1); ++#endif /* CONFIG_VT_CONSOLE */ ++} ++ ++void kdba_local_arch_cleanup(void) ++{ ++#ifdef CONFIG_VT_CONSOLE ++ int timeout; ++ unsigned char c; ++ ++ while (kbd_read_status() & KBD_STAT_IBF); ++ kbd_write_command(KBD_CCMD_READ_MODE); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF); ++ for (timeout = 200 * 1000; timeout && ++ (!(kbd_read_status() & KBD_STAT_OBF)); timeout--); ++ c = kbd_read_input(); ++ c |= KBD_MODE_KBD_INT; ++ while (kbd_read_status() & KBD_STAT_IBF); ++ kbd_write_command(KBD_CCMD_WRITE_MODE); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF); ++ kbd_write_output(c); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF); ++ mdelay(1); ++#endif /* CONFIG_VT_CONSOLE */ ++} +--- /dev/null ++++ b/arch/x86/kdb/kdbasupport_32.c +@@ -0,0 +1,1072 @@ ++/* ++ * Kernel Debugger Architecture Independent Support Functions ++ * ++ * 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) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static kdb_machreg_t ++kdba_getcr(int regnum) ++{ ++ kdb_machreg_t contents = 0; ++ switch(regnum) { ++ case 0: ++ __asm__ ("movl %%cr0,%0\n\t":"=r"(contents)); ++ break; ++ case 1: ++ break; ++ case 2: ++ __asm__ ("movl %%cr2,%0\n\t":"=r"(contents)); ++ break; ++ case 3: ++ __asm__ ("movl %%cr3,%0\n\t":"=r"(contents)); ++ break; ++ case 4: ++ __asm__ ("movl %%cr4,%0\n\t":"=r"(contents)); ++ break; ++ default: ++ break; ++ } ++ ++ return contents; ++} ++ ++static void ++kdba_putdr(int regnum, kdb_machreg_t contents) ++{ ++ switch(regnum) { ++ case 0: ++ __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); ++ break; ++ case 1: ++ __asm__ ("movl %0,%%db1\n\t"::"r"(contents)); ++ break; ++ case 2: ++ __asm__ ("movl %0,%%db2\n\t"::"r"(contents)); ++ break; ++ case 3: ++ __asm__ ("movl %0,%%db3\n\t"::"r"(contents)); ++ break; ++ case 4: ++ case 5: ++ break; ++ case 6: ++ __asm__ ("movl %0,%%db6\n\t"::"r"(contents)); ++ break; ++ case 7: ++ __asm__ ("movl %0,%%db7\n\t"::"r"(contents)); ++ break; ++ default: ++ break; ++ } ++} ++ ++kdb_machreg_t ++kdba_getdr(int regnum) ++{ ++ kdb_machreg_t contents = 0; ++ switch(regnum) { ++ case 0: ++ __asm__ ("movl %%db0,%0\n\t":"=r"(contents)); ++ break; ++ case 1: ++ __asm__ ("movl %%db1,%0\n\t":"=r"(contents)); ++ break; ++ case 2: ++ __asm__ ("movl %%db2,%0\n\t":"=r"(contents)); ++ break; ++ case 3: ++ __asm__ ("movl %%db3,%0\n\t":"=r"(contents)); ++ break; ++ case 4: ++ case 5: ++ break; ++ case 6: ++ __asm__ ("movl %%db6,%0\n\t":"=r"(contents)); ++ break; ++ case 7: ++ __asm__ ("movl %%db7,%0\n\t":"=r"(contents)); ++ break; ++ default: ++ break; ++ } ++ ++ return contents; ++} ++ ++kdb_machreg_t ++kdba_getdr6(void) ++{ ++ return kdba_getdr(6); ++} ++ ++kdb_machreg_t ++kdba_getdr7(void) ++{ ++ return kdba_getdr(7); ++} ++ ++void ++kdba_putdr6(kdb_machreg_t contents) ++{ ++ kdba_putdr(6, contents); ++} ++ ++static void ++kdba_putdr7(kdb_machreg_t contents) ++{ ++ kdba_putdr(7, contents); ++} ++ ++void ++kdba_installdbreg(kdb_bp_t *bp) ++{ ++ int cpu = smp_processor_id(); ++ ++ kdb_machreg_t dr7; ++ ++ dr7 = kdba_getdr7(); ++ ++ kdba_putdr(bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ ++ dr7 |= DR7_GE; ++ if (cpu_has_de) ++ set_in_cr4(X86_CR4_DE); ++ ++ switch (bp->bp_hard[cpu]->bph_reg){ ++ case 0: ++ DR7_RW0SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN0SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G0SET(dr7); ++ break; ++ case 1: ++ DR7_RW1SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN1SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G1SET(dr7); ++ break; ++ case 2: ++ DR7_RW2SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN2SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G2SET(dr7); ++ break; ++ case 3: ++ DR7_RW3SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN3SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G3SET(dr7); ++ break; ++ default: ++ kdb_printf("kdb: Bad debug register!! %ld\n", ++ bp->bp_hard[cpu]->bph_reg); ++ break; ++ } ++ ++ kdba_putdr7(dr7); ++ return; ++} ++ ++void ++kdba_removedbreg(kdb_bp_t *bp) ++{ ++ int regnum; ++ kdb_machreg_t dr7; ++ int cpu = smp_processor_id(); ++ ++ if (!bp->bp_hard[cpu]) ++ return; ++ ++ regnum = bp->bp_hard[cpu]->bph_reg; ++ ++ dr7 = kdba_getdr7(); ++ ++ kdba_putdr(regnum, 0); ++ ++ switch (regnum) { ++ case 0: ++ DR7_G0CLR(dr7); ++ DR7_L0CLR(dr7); ++ break; ++ case 1: ++ DR7_G1CLR(dr7); ++ DR7_L1CLR(dr7); ++ break; ++ case 2: ++ DR7_G2CLR(dr7); ++ DR7_L2CLR(dr7); ++ break; ++ case 3: ++ DR7_G3CLR(dr7); ++ DR7_L3CLR(dr7); ++ break; ++ default: ++ kdb_printf("kdb: Bad debug register!! %d\n", regnum); ++ break; ++ } ++ ++ kdba_putdr7(dr7); ++} ++ ++ ++/* ++ * kdba_getregcontents ++ * ++ * Return the contents of the register specified by the ++ * input string argument. Return an error if the string ++ * does not match a machine register. ++ * ++ * The following pseudo register names are supported: ++ * ®s - Prints address of exception frame ++ * kesp - Prints kernel stack pointer at time of fault ++ * cesp - Prints current kernel stack pointer, inside kdb ++ * ceflags - Prints current flags, inside kdb ++ * % - Uses the value of the registers at the ++ * last time the user process entered kernel ++ * mode, instead of the registers at the time ++ * kdb was entered. ++ * ++ * Parameters: ++ * regname Pointer to string naming register ++ * regs Pointer to structure containing registers. ++ * Outputs: ++ * *contents Pointer to unsigned long to recieve register contents ++ * Returns: ++ * 0 Success ++ * KDB_BADREG Invalid register name ++ * Locking: ++ * None. ++ * Remarks: ++ * If kdb was entered via an interrupt from the kernel itself then ++ * ss and sp are *not* on the stack. ++ */ ++ ++static struct kdbregs { ++ char *reg_name; ++ size_t reg_offset; ++} kdbreglist[] = { ++ { "ax", offsetof(struct pt_regs, ax) }, ++ { "bx", offsetof(struct pt_regs, bx) }, ++ { "cx", offsetof(struct pt_regs, cx) }, ++ { "dx", offsetof(struct pt_regs, dx) }, ++ ++ { "si", offsetof(struct pt_regs, si) }, ++ { "di", offsetof(struct pt_regs, di) }, ++ { "sp", offsetof(struct pt_regs, sp) }, ++ { "ip", offsetof(struct pt_regs, ip) }, ++ ++ { "bp", offsetof(struct pt_regs, bp) }, ++ { "ss", offsetof(struct pt_regs, ss) }, ++ { "cs", offsetof(struct pt_regs, cs) }, ++ { "flags", offsetof(struct pt_regs, flags) }, ++ ++ { "ds", offsetof(struct pt_regs, ds) }, ++ { "es", offsetof(struct pt_regs, es) }, ++ { "origax", offsetof(struct pt_regs, orig_ax) }, ++ ++}; ++ ++static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); ++ ++static struct kdbregs dbreglist[] = { ++ { "dr0", 0 }, ++ { "dr1", 1 }, ++ { "dr2", 2 }, ++ { "dr3", 3 }, ++ { "dr6", 6 }, ++ { "dr7", 7 }, ++}; ++ ++static const int ndbreglist = sizeof(dbreglist) / sizeof(struct kdbregs); ++ ++int ++kdba_getregcontents(const char *regname, ++ struct pt_regs *regs, ++ kdb_machreg_t *contents) ++{ ++ int i; ++ ++ if (strcmp(regname, "cesp") == 0) { ++ asm volatile("movl %%esp,%0":"=m" (*contents)); ++ return 0; ++ } ++ ++ if (strcmp(regname, "ceflags") == 0) { ++ unsigned long flags; ++ local_save_flags(flags); ++ *contents = flags; ++ return 0; ++ } ++ ++ if (regname[0] == '%') { ++ /* User registers: %%e[a-c]x, etc */ ++ regname++; ++ regs = (struct pt_regs *) ++ (kdb_current_task->thread.sp0 - sizeof(struct pt_regs)); ++ } ++ ++ for (i=0; ics & 0xffff) == __KERNEL_CS) { ++ /* sp and ss are not on stack */ ++ *contents -= 2*4; ++ } ++ return 0; ++ } ++ ++ for (i=0; ics & 0xffff) == __KERNEL_CS) { ++ /* No cpl switch, sp and ss are not on stack */ ++ if (strcmp(kdbreglist[i].reg_name, "sp") == 0) { ++ *contents = (kdb_machreg_t)regs + ++ sizeof(struct pt_regs) - 2*4; ++ return(0); ++ } ++ if (strcmp(kdbreglist[i].reg_name, "xss") == 0) { ++ asm volatile( ++ "pushl %%ss\n" ++ "popl %0\n" ++ :"=m" (*contents)); ++ return(0); ++ } ++ } ++ *contents = *(unsigned long *)((unsigned long)regs + ++ kdbreglist[i].reg_offset); ++ return(0); ++ } ++ ++ return KDB_BADREG; ++} ++ ++/* ++ * kdba_setregcontents ++ * ++ * Set the contents of the register specified by the ++ * input string argument. Return an error if the string ++ * does not match a machine register. ++ * ++ * Supports modification of user-mode registers via ++ * % ++ * ++ * Parameters: ++ * regname Pointer to string naming register ++ * regs Pointer to structure containing registers. ++ * contents Unsigned long containing new register contents ++ * Outputs: ++ * Returns: ++ * 0 Success ++ * KDB_BADREG Invalid register name ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdba_setregcontents(const char *regname, ++ struct pt_regs *regs, ++ unsigned long contents) ++{ ++ int i; ++ ++ if (regname[0] == '%') { ++ regname++; ++ regs = (struct pt_regs *) ++ (kdb_current_task->thread.sp0 - sizeof(struct pt_regs)); ++ } ++ ++ for (i=0; ithread.sp0 - sizeof(struct pt_regs)); ++ } ++ ++ if (type == NULL) { ++ struct kdbregs *rlp; ++ kdb_machreg_t contents; ++ ++ if (!regs) { ++ kdb_printf("%s: pt_regs not available, use bt* or pid to select a different task\n", __FUNCTION__); ++ return KDB_BADREG; ++ } ++ ++ for (i=0, rlp=kdbreglist; iip : 0; ++} ++ ++int ++kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_BADREG; ++ regs->ip = newpc; ++ KDB_STATE_SET(IP_ADJUSTED); ++ return 0; ++} ++ ++/* ++ * kdba_main_loop ++ * ++ * Do any architecture specific set up before entering the main kdb loop. ++ * The primary function of this routine is to make all processes look the ++ * same to kdb, kdb must be able to list a process without worrying if the ++ * process is running or blocked, so make all process look as though they ++ * are blocked. ++ * ++ * Inputs: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * error2 kdb's current reason code. Initially error but can change ++ * acording to kdb state. ++ * db_result Result from break or debug point. ++ * regs The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it should ++ * always be valid. ++ * Returns: ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * Outputs: ++ * Sets ip and sp in current->thread. ++ * Locking: ++ * None. ++ * Remarks: ++ * none. ++ */ ++ ++int ++kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, ++ kdb_dbtrap_t db_result, struct pt_regs *regs) ++{ ++ int ret; ++ ret = kdb_save_running(regs, reason, reason2, error, db_result); ++ kdb_unsave_running(regs); ++ return ret; ++} ++ ++void ++kdba_disableint(kdb_intstate_t *state) ++{ ++ unsigned long *fp = (unsigned long *)state; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ *fp = flags; ++} ++ ++void ++kdba_restoreint(kdb_intstate_t *state) ++{ ++ unsigned long flags = *(int *)state; ++ local_irq_restore(flags); ++} ++ ++void ++kdba_setsinglestep(struct pt_regs *regs) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ if (regs->flags & EF_IE) ++ KDB_STATE_SET(A_IF); ++ else ++ KDB_STATE_CLEAR(A_IF); ++ regs->flags = (regs->flags | EF_TF) & ~EF_IE; ++} ++ ++void ++kdba_clearsinglestep(struct pt_regs *regs) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ if (KDB_STATE(A_IF)) ++ regs->flags |= EF_IE; ++ else ++ regs->flags &= ~EF_IE; ++} ++ ++int asmlinkage ++kdba_setjmp(kdb_jmp_buf *jb) ++{ ++#if defined(CONFIG_FRAME_POINTER) ++ __asm__ ("movl 8(%esp), %eax\n\t" ++ "movl %ebx, 0(%eax)\n\t" ++ "movl %esi, 4(%eax)\n\t" ++ "movl %edi, 8(%eax)\n\t" ++ "movl (%esp), %ecx\n\t" ++ "movl %ecx, 12(%eax)\n\t" ++ "leal 8(%esp), %ecx\n\t" ++ "movl %ecx, 16(%eax)\n\t" ++ "movl 4(%esp), %ecx\n\t" ++ "movl %ecx, 20(%eax)\n\t"); ++#else /* CONFIG_FRAME_POINTER */ ++ __asm__ ("movl 4(%esp), %eax\n\t" ++ "movl %ebx, 0(%eax)\n\t" ++ "movl %esi, 4(%eax)\n\t" ++ "movl %edi, 8(%eax)\n\t" ++ "movl %ebp, 12(%eax)\n\t" ++ "leal 4(%esp), %ecx\n\t" ++ "movl %ecx, 16(%eax)\n\t" ++ "movl 0(%esp), %ecx\n\t" ++ "movl %ecx, 20(%eax)\n\t"); ++#endif /* CONFIG_FRAME_POINTER */ ++ return 0; ++} ++ ++void asmlinkage ++kdba_longjmp(kdb_jmp_buf *jb, int reason) ++{ ++#if defined(CONFIG_FRAME_POINTER) ++ __asm__("movl 8(%esp), %ecx\n\t" ++ "movl 12(%esp), %eax\n\t" ++ "movl 20(%ecx), %edx\n\t" ++ "movl 0(%ecx), %ebx\n\t" ++ "movl 4(%ecx), %esi\n\t" ++ "movl 8(%ecx), %edi\n\t" ++ "movl 12(%ecx), %ebp\n\t" ++ "movl 16(%ecx), %esp\n\t" ++ "jmp *%edx\n"); ++#else /* CONFIG_FRAME_POINTER */ ++ __asm__("movl 4(%esp), %ecx\n\t" ++ "movl 8(%esp), %eax\n\t" ++ "movl 20(%ecx), %edx\n\t" ++ "movl 0(%ecx), %ebx\n\t" ++ "movl 4(%ecx), %esi\n\t" ++ "movl 8(%ecx), %edi\n\t" ++ "movl 12(%ecx), %ebp\n\t" ++ "movl 16(%ecx), %esp\n\t" ++ "jmp *%edx\n"); ++#endif /* CONFIG_FRAME_POINTER */ ++} ++ ++/* ++ * kdba_pt_regs ++ * ++ * Format a struct pt_regs ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no address is supplied, it uses the last irq pt_regs. ++ */ ++ ++static int ++kdba_pt_regs(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ int nextarg; ++ struct pt_regs *p; ++ static const char *fmt = " %-11.11s 0x%lx\n"; ++ ++ if (argc == 0) { ++ addr = (kdb_machreg_t) get_irq_regs(); ++ } else if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ p = (struct pt_regs *) addr; ++ kdb_printf("struct pt_regs 0x%p-0x%p\n", p, (unsigned char *)p + sizeof(*p) - 1); ++ kdb_print_nameval("bx", p->bx); ++ kdb_print_nameval("cx", p->cx); ++ kdb_print_nameval("dx", p->dx); ++ kdb_print_nameval("si", p->si); ++ kdb_print_nameval("di", p->di); ++ kdb_print_nameval("bp", p->bp); ++ kdb_print_nameval("ax", p->ax); ++ kdb_printf(fmt, "ds", p->ds); ++ kdb_printf(fmt, "es", p->es); ++ kdb_print_nameval("orig_ax", p->orig_ax); ++ kdb_print_nameval("ip", p->ip); ++ kdb_printf(fmt, "cs", p->cs); ++ kdb_printf(fmt, "flags", p->flags); ++ kdb_printf(fmt, "sp", p->sp); ++ kdb_printf(fmt, "ss", p->ss); ++ return 0; ++} ++ ++/* ++ * kdba_stackdepth ++ * ++ * Print processes that are using more than a specific percentage of their ++ * stack. ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no percentage is supplied, it uses 60. ++ */ ++ ++static void ++kdba_stackdepth1(struct task_struct *p, unsigned long sp) ++{ ++ struct thread_info *tinfo; ++ int used; ++ const char *type; ++ kdb_ps1(p); ++ do { ++ tinfo = (struct thread_info *)(sp & -THREAD_SIZE); ++ used = sizeof(*tinfo) + THREAD_SIZE - (sp & (THREAD_SIZE-1)); ++ type = NULL; ++ if (kdb_task_has_cpu(p)) { ++ struct kdb_activation_record ar; ++ memset(&ar, 0, sizeof(ar)); ++ kdba_get_stack_info_alternate(sp, -1, &ar); ++ type = ar.stack.id; ++ } ++ if (!type) ++ type = "process"; ++ kdb_printf(" %s stack %p sp %lx used %d\n", type, tinfo, sp, used); ++ sp = tinfo->previous_esp; ++ } while (sp); ++} ++ ++static int ++kdba_stackdepth(int argc, const char **argv) ++{ ++ int diag, cpu, threshold, used, over; ++ unsigned long percentage; ++ unsigned long esp; ++ long offset = 0; ++ int nextarg; ++ struct task_struct *p, *g; ++ struct kdb_running_process *krp; ++ struct thread_info *tinfo; ++ ++ if (argc == 0) { ++ percentage = 60; ++ } else if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &percentage, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ percentage = max_t(int, percentage, 1); ++ percentage = min_t(int, percentage, 100); ++ threshold = ((2 * THREAD_SIZE * percentage) / 100 + 1) >> 1; ++ kdb_printf("stackdepth: processes using more than %ld%% (%d bytes) of stack\n", ++ percentage, threshold); ++ ++ /* Run the active tasks first, they can have multiple stacks */ ++ for (cpu = 0, krp = kdb_running_process; cpu < NR_CPUS; ++cpu, ++krp) { ++ if (!cpu_online(cpu)) ++ continue; ++ p = krp->p; ++ esp = krp->arch.sp; ++ over = 0; ++ do { ++ tinfo = (struct thread_info *)(esp & -THREAD_SIZE); ++ used = sizeof(*tinfo) + THREAD_SIZE - (esp & (THREAD_SIZE-1)); ++ if (used >= threshold) ++ over = 1; ++ esp = tinfo->previous_esp; ++ } while (esp); ++ if (over) ++ kdba_stackdepth1(p, krp->arch.sp); ++ } ++ /* Now the tasks that are not on cpus */ ++ kdb_do_each_thread(g, p) { ++ if (kdb_task_has_cpu(p)) ++ continue; ++ esp = p->thread.sp; ++ used = sizeof(*tinfo) + THREAD_SIZE - (esp & (THREAD_SIZE-1)); ++ over = used >= threshold; ++ if (over) ++ kdba_stackdepth1(p, esp); ++ } kdb_while_each_thread(g, p); ++ ++ return 0; ++} ++ ++asmlinkage int kdb_call(void); ++ ++/* Executed once on each cpu at startup. */ ++void ++kdba_cpu_up(void) ++{ ++} ++ ++static int __init ++kdba_arch_init(void) ++{ ++#ifdef CONFIG_SMP ++ set_intr_gate(KDB_VECTOR, kdb_interrupt); ++#endif ++ set_intr_gate(KDBENTER_VECTOR, kdb_call); ++ return 0; ++} ++ ++arch_initcall(kdba_arch_init); ++ ++/* ++ * kdba_init ++ * ++ * Architecture specific initialization. ++ * ++ * Parameters: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * None. ++ */ ++ ++void __init ++kdba_init(void) ++{ ++ kdba_arch_init(); /* Need to register KDBENTER_VECTOR early */ ++ kdb_register("pt_regs", kdba_pt_regs, "address", "Format struct pt_regs", 0); ++ kdb_register("stackdepth", kdba_stackdepth, "[percentage]", "Print processes using >= stack percentage", 0); ++ ++ return; ++} ++ ++/* ++ * kdba_adjust_ip ++ * ++ * Architecture specific adjustment of instruction pointer before leaving ++ * kdb. ++ * ++ * Parameters: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * regs The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it should ++ * always be valid. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * noop on ix86. ++ */ ++ ++void ++kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *regs) ++{ ++ return; ++} ++ ++void ++kdba_set_current_task(const struct task_struct *p) ++{ ++ kdb_current_task = p; ++ if (kdb_task_has_cpu(p)) { ++ struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p); ++ kdb_current_regs = krp->regs; ++ return; ++ } ++ kdb_current_regs = NULL; ++} ++ ++/* ++ * asm-i386 uaccess.h supplies __copy_to_user which relies on MMU to ++ * trap invalid addresses in the _xxx fields. Verify the other address ++ * of the pair is valid by accessing the first and last byte ourselves, ++ * then any access violations should only be caused by the _xxx ++ * addresses, ++ */ ++ ++int ++kdba_putarea_size(unsigned long to_xxx, void *from, size_t size) ++{ ++ mm_segment_t oldfs = get_fs(); ++ int r; ++ char c; ++ c = *((volatile char *)from); ++ c = *((volatile char *)from + size - 1); ++ ++ if (to_xxx < PAGE_OFFSET) { ++ return kdb_putuserarea_size(to_xxx, from, size); ++ } ++ ++ set_fs(KERNEL_DS); ++ r = __copy_to_user_inatomic((void __user *)to_xxx, from, size); ++ set_fs(oldfs); ++ return r; ++} ++ ++int ++kdba_getarea_size(void *to, unsigned long from_xxx, size_t size) ++{ ++ mm_segment_t oldfs = get_fs(); ++ int r; ++ *((volatile char *)to) = '\0'; ++ *((volatile char *)to + size - 1) = '\0'; ++ ++ if (from_xxx < PAGE_OFFSET) { ++ return kdb_getuserarea_size(to, from_xxx, size); ++ } ++ ++ set_fs(KERNEL_DS); ++ switch (size) { ++ case 1: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 1); ++ break; ++ case 2: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 2); ++ break; ++ case 4: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 4); ++ break; ++ case 8: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, 8); ++ break; ++ default: ++ r = __copy_to_user_inatomic((void __user *)to, (void *)from_xxx, size); ++ break; ++ } ++ set_fs(oldfs); ++ return r; ++} ++ ++int ++kdba_verify_rw(unsigned long addr, size_t size) ++{ ++ unsigned char data[size]; ++ return(kdba_getarea_size(data, addr, size) || kdba_putarea_size(addr, data, size)); ++} ++ ++#ifdef CONFIG_SMP ++ ++#include ++ ++/* When first entering KDB, try a normal IPI. That reduces backtrace problems ++ * on the other cpus. ++ */ ++void ++smp_kdb_stop(void) ++{ ++ if (!KDB_FLAG(NOIPI)) ++ send_IPI_allbutself(KDB_VECTOR); ++} ++ ++/* The normal KDB IPI handler */ ++void ++smp_kdb_interrupt(struct pt_regs *regs) ++{ ++ struct pt_regs *old_regs = set_irq_regs(regs); ++ ack_APIC_irq(); ++ irq_enter(); ++ kdb_ipi(regs, NULL); ++ irq_exit(); ++ set_irq_regs(old_regs); ++} ++ ++/* Invoked once from kdb_wait_for_cpus when waiting for cpus. For those cpus ++ * that have not responded to the normal KDB interrupt yet, hit them with an ++ * NMI event. ++ */ ++void ++kdba_wait_for_cpus(void) ++{ ++ int c; ++ if (KDB_FLAG(CATASTROPHIC)) ++ return; ++ kdb_printf(" Sending NMI to non-responding cpu(s): "); ++ for_each_online_cpu(c) { ++ if (kdb_running_process[c].seqno < kdb_seqno - 1) { ++ kdb_printf(" %d", c); ++ send_IPI_mask(&cpumask_of_cpu(c), NMI_VECTOR); ++ } ++ } ++ kdb_printf(".\n"); ++} ++ ++#endif /* CONFIG_SMP */ +--- /dev/null ++++ b/arch/x86/kdb/kdbasupport_64.c +@@ -0,0 +1,1022 @@ ++/* ++ * Kernel Debugger Architecture Independent Support Functions ++ * ++ * 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++kdb_machreg_t ++kdba_getdr6(void) ++{ ++ return kdba_getdr(6); ++} ++ ++kdb_machreg_t ++kdba_getdr7(void) ++{ ++ return kdba_getdr(7); ++} ++ ++void ++kdba_putdr6(kdb_machreg_t contents) ++{ ++ kdba_putdr(6, contents); ++} ++ ++static void ++kdba_putdr7(kdb_machreg_t contents) ++{ ++ kdba_putdr(7, contents); ++} ++ ++void ++kdba_installdbreg(kdb_bp_t *bp) ++{ ++ int cpu = smp_processor_id(); ++ ++ kdb_machreg_t dr7; ++ ++ dr7 = kdba_getdr7(); ++ ++ kdba_putdr(bp->bp_hard[cpu]->bph_reg, bp->bp_addr); ++ ++ dr7 |= DR7_GE; ++ if (cpu_has_de) ++ set_in_cr4(X86_CR4_DE); ++ ++ switch (bp->bp_hard[cpu]->bph_reg){ ++ case 0: ++ DR7_RW0SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN0SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G0SET(dr7); ++ break; ++ case 1: ++ DR7_RW1SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN1SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G1SET(dr7); ++ break; ++ case 2: ++ DR7_RW2SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN2SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G2SET(dr7); ++ break; ++ case 3: ++ DR7_RW3SET(dr7,bp->bp_hard[cpu]->bph_mode); ++ DR7_LEN3SET(dr7,bp->bp_hard[cpu]->bph_length); ++ DR7_G3SET(dr7); ++ break; ++ default: ++ kdb_printf("kdb: Bad debug register!! %ld\n", ++ bp->bp_hard[cpu]->bph_reg); ++ break; ++ } ++ ++ kdba_putdr7(dr7); ++ return; ++} ++ ++void ++kdba_removedbreg(kdb_bp_t *bp) ++{ ++ int regnum; ++ kdb_machreg_t dr7; ++ int cpu = smp_processor_id(); ++ ++ if (!bp->bp_hard[cpu]) ++ return; ++ ++ regnum = bp->bp_hard[cpu]->bph_reg; ++ ++ dr7 = kdba_getdr7(); ++ ++ kdba_putdr(regnum, 0); ++ ++ switch (regnum) { ++ case 0: ++ DR7_G0CLR(dr7); ++ DR7_L0CLR(dr7); ++ break; ++ case 1: ++ DR7_G1CLR(dr7); ++ DR7_L1CLR(dr7); ++ break; ++ case 2: ++ DR7_G2CLR(dr7); ++ DR7_L2CLR(dr7); ++ break; ++ case 3: ++ DR7_G3CLR(dr7); ++ DR7_L3CLR(dr7); ++ break; ++ default: ++ kdb_printf("kdb: Bad debug register!! %d\n", regnum); ++ break; ++ } ++ ++ kdba_putdr7(dr7); ++} ++ ++kdb_machreg_t ++kdba_getdr(int regnum) ++{ ++ kdb_machreg_t contents = 0; ++ switch(regnum) { ++ case 0: ++ __asm__ ("movq %%db0,%0\n\t":"=r"(contents)); ++ break; ++ case 1: ++ __asm__ ("movq %%db1,%0\n\t":"=r"(contents)); ++ break; ++ case 2: ++ __asm__ ("movq %%db2,%0\n\t":"=r"(contents)); ++ break; ++ case 3: ++ __asm__ ("movq %%db3,%0\n\t":"=r"(contents)); ++ break; ++ case 4: ++ case 5: ++ break; ++ case 6: ++ __asm__ ("movq %%db6,%0\n\t":"=r"(contents)); ++ break; ++ case 7: ++ __asm__ ("movq %%db7,%0\n\t":"=r"(contents)); ++ break; ++ default: ++ break; ++ } ++ ++ return contents; ++} ++ ++ ++kdb_machreg_t ++kdb_getcr(int regnum) ++{ ++ kdb_machreg_t contents = 0; ++ switch(regnum) { ++ case 0: ++ __asm__ ("movq %%cr0,%0\n\t":"=r"(contents)); ++ break; ++ case 1: ++ break; ++ case 2: ++ __asm__ ("movq %%cr2,%0\n\t":"=r"(contents)); ++ break; ++ case 3: ++ __asm__ ("movq %%cr3,%0\n\t":"=r"(contents)); ++ break; ++ case 4: ++ __asm__ ("movq %%cr4,%0\n\t":"=r"(contents)); ++ break; ++ default: ++ break; ++ } ++ ++ return contents; ++} ++ ++void ++kdba_putdr(int regnum, kdb_machreg_t contents) ++{ ++ switch(regnum) { ++ case 0: ++ __asm__ ("movq %0,%%db0\n\t"::"r"(contents)); ++ break; ++ case 1: ++ __asm__ ("movq %0,%%db1\n\t"::"r"(contents)); ++ break; ++ case 2: ++ __asm__ ("movq %0,%%db2\n\t"::"r"(contents)); ++ break; ++ case 3: ++ __asm__ ("movq %0,%%db3\n\t"::"r"(contents)); ++ break; ++ case 4: ++ case 5: ++ break; ++ case 6: ++ __asm__ ("movq %0,%%db6\n\t"::"r"(contents)); ++ break; ++ case 7: ++ __asm__ ("movq %0,%%db7\n\t"::"r"(contents)); ++ break; ++ default: ++ break; ++ } ++} ++ ++/* ++ * kdba_getregcontents ++ * ++ * Return the contents of the register specified by the ++ * input string argument. Return an error if the string ++ * does not match a machine register. ++ * ++ * The following pseudo register names are supported: ++ * ®s - Prints address of exception frame ++ * krsp - Prints kernel stack pointer at time of fault ++ * crsp - Prints current kernel stack pointer, inside kdb ++ * ceflags - Prints current flags, inside kdb ++ * % - Uses the value of the registers at the ++ * last time the user process entered kernel ++ * mode, instead of the registers at the time ++ * kdb was entered. ++ * ++ * Parameters: ++ * regname Pointer to string naming register ++ * regs Pointer to structure containing registers. ++ * Outputs: ++ * *contents Pointer to unsigned long to recieve register contents ++ * Returns: ++ * 0 Success ++ * KDB_BADREG Invalid register name ++ * Locking: ++ * None. ++ * Remarks: ++ * If kdb was entered via an interrupt from the kernel itself then ++ * ss and sp are *not* on the stack. ++ */ ++ ++static struct kdbregs { ++ char *reg_name; ++ size_t reg_offset; ++} kdbreglist[] = { ++ { "r15", offsetof(struct pt_regs, r15) }, ++ { "r14", offsetof(struct pt_regs, r14) }, ++ { "r13", offsetof(struct pt_regs, r13) }, ++ { "r12", offsetof(struct pt_regs, r12) }, ++ { "bp", offsetof(struct pt_regs, bp) }, ++ { "bx", offsetof(struct pt_regs, bx) }, ++ { "r11", offsetof(struct pt_regs, r11) }, ++ { "r10", offsetof(struct pt_regs, r10) }, ++ { "r9", offsetof(struct pt_regs, r9) }, ++ { "r8", offsetof(struct pt_regs, r8) }, ++ { "ax", offsetof(struct pt_regs, ax) }, ++ { "cx", offsetof(struct pt_regs, cx) }, ++ { "dx", offsetof(struct pt_regs, dx) }, ++ { "si", offsetof(struct pt_regs, si) }, ++ { "di", offsetof(struct pt_regs, di) }, ++ { "orig_ax", offsetof(struct pt_regs, orig_ax) }, ++ { "ip", offsetof(struct pt_regs, ip) }, ++ { "cs", offsetof(struct pt_regs, cs) }, ++ { "flags", offsetof(struct pt_regs, flags) }, ++ { "sp", offsetof(struct pt_regs, sp) }, ++ { "ss", offsetof(struct pt_regs, ss) }, ++}; ++ ++static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); ++ ++static struct kdbregs dbreglist[] = { ++ { "dr0", 0 }, ++ { "dr1", 1 }, ++ { "dr2", 2 }, ++ { "dr3", 3 }, ++ { "dr6", 6 }, ++ { "dr7", 7 }, ++}; ++ ++static const int ndbreglist = sizeof(dbreglist) / sizeof(struct kdbregs); ++ ++int ++kdba_getregcontents(const char *regname, ++ struct pt_regs *regs, ++ kdb_machreg_t *contents) ++{ ++ int i; ++ ++ if (strcmp(regname, "®s") == 0) { ++ *contents = (unsigned long)regs; ++ return 0; ++ } ++ ++ if (strcmp(regname, "krsp") == 0) { ++ *contents = (unsigned long)regs + sizeof(struct pt_regs); ++ if ((regs->cs & 0xffff) == __KERNEL_CS) { ++ /* sp and ss are not on stack */ ++ *contents -= 2*4; ++ } ++ return 0; ++ } ++ ++ if (strcmp(regname, "crsp") == 0) { ++ asm volatile("movq %%rsp,%0":"=m" (*contents)); ++ return 0; ++ } ++ ++ if (strcmp(regname, "ceflags") == 0) { ++ unsigned long flags; ++ local_save_flags(flags); ++ *contents = flags; ++ return 0; ++ } ++ ++ if (regname[0] == '%') { ++ /* User registers: %%r[a-c]x, etc */ ++ regname++; ++ regs = (struct pt_regs *) ++ (current->thread.sp0 - sizeof(struct pt_regs)); ++ } ++ ++ for (i=0; ics & 0xffff) == __KERNEL_CS) { ++ /* No cpl switch, sp is not on stack */ ++ if (strcmp(kdbreglist[i].reg_name, "sp") == 0) { ++ *contents = (kdb_machreg_t)regs + ++ sizeof(struct pt_regs) - 2*8; ++ return(0); ++ } ++#if 0 /* FIXME */ ++ if (strcmp(kdbreglist[i].reg_name, "ss") == 0) { ++ kdb_machreg_t r; ++ ++ r = (kdb_machreg_t)regs + ++ sizeof(struct pt_regs) - 2*8; ++ *contents = (kdb_machreg_t)SS(r); /* XXX */ ++ return(0); ++ } ++#endif ++ } ++ *contents = *(unsigned long *)((unsigned long)regs + ++ kdbreglist[i].reg_offset); ++ return(0); ++ } ++ ++ for (i=0; i ++ * ++ * Parameters: ++ * regname Pointer to string naming register ++ * regs Pointer to structure containing registers. ++ * contents Unsigned long containing new register contents ++ * Outputs: ++ * Returns: ++ * 0 Success ++ * KDB_BADREG Invalid register name ++ * Locking: ++ * None. ++ * Remarks: ++ */ ++ ++int ++kdba_setregcontents(const char *regname, ++ struct pt_regs *regs, ++ unsigned long contents) ++{ ++ int i; ++ ++ if (regname[0] == '%') { ++ regname++; ++ regs = (struct pt_regs *) ++ (current->thread.sp0 - sizeof(struct pt_regs)); ++ } ++ ++ for (i=0; ithread.sp0 - sizeof(struct pt_regs)); ++ } ++ ++ if (type == NULL) { ++ struct kdbregs *rlp; ++ kdb_machreg_t contents; ++ ++ for (i=0, rlp=kdbreglist; iip; ++} ++ ++int ++kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return KDB_BADREG; ++ regs->ip = newpc; ++ KDB_STATE_SET(IP_ADJUSTED); ++ return 0; ++} ++ ++/* ++ * kdba_main_loop ++ * ++ * Do any architecture specific set up before entering the main kdb loop. ++ * The primary function of this routine is to make all processes look the ++ * same to kdb, kdb must be able to list a process without worrying if the ++ * process is running or blocked, so make all process look as though they ++ * are blocked. ++ * ++ * Inputs: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * error2 kdb's current reason code. Initially error but can change ++ * acording to kdb state. ++ * db_result Result from break or debug point. ++ * ef The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it should ++ * always be valid. ++ * Returns: ++ * 0 KDB was invoked for an event which it wasn't responsible ++ * 1 KDB handled the event for which it was invoked. ++ * Outputs: ++ * Sets ip and sp in current->thread. ++ * Locking: ++ * None. ++ * Remarks: ++ * none. ++ */ ++ ++int ++kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, ++ kdb_dbtrap_t db_result, struct pt_regs *regs) ++{ ++ int ret; ++ ++ if (regs) ++ kdba_getregcontents("sp", regs, &(current->thread.sp)); ++ ret = kdb_save_running(regs, reason, reason2, error, db_result); ++ kdb_unsave_running(regs); ++ return ret; ++} ++ ++void ++kdba_disableint(kdb_intstate_t *state) ++{ ++ unsigned long *fp = (unsigned long *)state; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ *fp = flags; ++} ++ ++void ++kdba_restoreint(kdb_intstate_t *state) ++{ ++ unsigned long flags = *(unsigned long *)state; ++ local_irq_restore(flags); ++} ++ ++void ++kdba_setsinglestep(struct pt_regs *regs) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ if (regs->flags & X86_EFLAGS_IF) ++ KDB_STATE_SET(A_IF); ++ else ++ KDB_STATE_CLEAR(A_IF); ++ regs->flags = (regs->flags | X86_EFLAGS_TF) & ~X86_EFLAGS_IF; ++} ++ ++void ++kdba_clearsinglestep(struct pt_regs *regs) ++{ ++ if (KDB_NULL_REGS(regs)) ++ return; ++ if (KDB_STATE(A_IF)) ++ regs->flags |= X86_EFLAGS_IF; ++ else ++ regs->flags &= ~X86_EFLAGS_IF; ++} ++ ++int asmlinkage ++kdba_setjmp(kdb_jmp_buf *jb) ++{ ++#ifdef CONFIG_FRAME_POINTER ++ __asm__ __volatile__ ++ ("movq %%rbx, (0*8)(%%rdi);" ++ "movq %%rcx, (1*8)(%%rdi);" ++ "movq %%r12, (2*8)(%%rdi);" ++ "movq %%r13, (3*8)(%%rdi);" ++ "movq %%r14, (4*8)(%%rdi);" ++ "movq %%r15, (5*8)(%%rdi);" ++ "leaq 16(%%rsp), %%rdx;" ++ "movq %%rdx, (6*8)(%%rdi);" ++ "movq %%rax, (7*8)(%%rdi)" ++ : ++ : "a" (__builtin_return_address(0)), ++ "c" (__builtin_frame_address(1)) ++ ); ++#else /* !CONFIG_FRAME_POINTER */ ++ __asm__ __volatile__ ++ ("movq %%rbx, (0*8)(%%rdi);" ++ "movq %%rbp, (1*8)(%%rdi);" ++ "movq %%r12, (2*8)(%%rdi);" ++ "movq %%r13, (3*8)(%%rdi);" ++ "movq %%r14, (4*8)(%%rdi);" ++ "movq %%r15, (5*8)(%%rdi);" ++ "leaq 8(%%rsp), %%rdx;" ++ "movq %%rdx, (6*8)(%%rdi);" ++ "movq %%rax, (7*8)(%%rdi)" ++ : ++ : "a" (__builtin_return_address(0)) ++ ); ++#endif /* CONFIG_FRAME_POINTER */ ++ return 0; ++} ++ ++void asmlinkage ++kdba_longjmp(kdb_jmp_buf *jb, int reason) ++{ ++ __asm__("movq (0*8)(%rdi),%rbx;" ++ "movq (1*8)(%rdi),%rbp;" ++ "movq (2*8)(%rdi),%r12;" ++ "movq (3*8)(%rdi),%r13;" ++ "movq (4*8)(%rdi),%r14;" ++ "movq (5*8)(%rdi),%r15;" ++ "movq (7*8)(%rdi),%rdx;" ++ "movq (6*8)(%rdi),%rsp;" ++ "mov %rsi, %rax;" ++ "jmpq *%rdx"); ++} ++ ++/* ++ * kdba_pt_regs ++ * ++ * Format a struct pt_regs ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no address is supplied, it uses the current irq pt_regs. ++ */ ++ ++static int ++kdba_pt_regs(int argc, const char **argv) ++{ ++ int diag; ++ kdb_machreg_t addr; ++ long offset = 0; ++ int nextarg; ++ struct pt_regs *p; ++ static const char *fmt = " %-11.11s 0x%lx\n"; ++ static int first_time = 1; ++ ++ if (argc == 0) { ++ addr = (kdb_machreg_t) get_irq_regs(); ++ } else if (argc == 1) { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL); ++ if (diag) ++ return diag; ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ p = (struct pt_regs *) addr; ++ if (first_time) { ++ first_time = 0; ++ kdb_printf("\n+++ Warning: x86_64 pt_regs are not always " ++ "completely defined, r15-bx may be invalid\n\n"); ++ } ++ kdb_printf("struct pt_regs 0x%p-0x%p\n", p, (unsigned char *)p + sizeof(*p) - 1); ++ kdb_print_nameval("r15", p->r15); ++ kdb_print_nameval("r14", p->r14); ++ kdb_print_nameval("r13", p->r13); ++ kdb_print_nameval("r12", p->r12); ++ kdb_print_nameval("bp", p->bp); ++ kdb_print_nameval("bx", p->bx); ++ kdb_print_nameval("r11", p->r11); ++ kdb_print_nameval("r10", p->r10); ++ kdb_print_nameval("r9", p->r9); ++ kdb_print_nameval("r8", p->r8); ++ kdb_print_nameval("ax", p->ax); ++ kdb_print_nameval("cx", p->cx); ++ kdb_print_nameval("dx", p->dx); ++ kdb_print_nameval("si", p->si); ++ kdb_print_nameval("di", p->di); ++ kdb_print_nameval("orig_ax", p->orig_ax); ++ kdb_print_nameval("ip", p->ip); ++ kdb_printf(fmt, "cs", p->cs); ++ kdb_printf(fmt, "flags", p->flags); ++ kdb_printf(fmt, "sp", p->sp); ++ kdb_printf(fmt, "ss", p->ss); ++ return 0; ++} ++ ++/* ++ * kdba_cpu_pda ++ * ++ * Format a struct cpu_pda ++ * ++ * Inputs: ++ * argc argument count ++ * argv argument vector ++ * Outputs: ++ * None. ++ * Returns: ++ * zero for success, a kdb diagnostic if error ++ * Locking: ++ * none. ++ * Remarks: ++ * If no cpu is supplied, it prints the current cpu. If the cpu is '*' ++ * then it prints all cpus. ++ */ ++ ++static int ++kdba_cpu_pda(int argc, const char **argv) ++{ ++ int diag, nextarg, all_cpus = 0; ++ long offset = 0; ++ unsigned long cpu; ++ struct x8664_pda *c; ++ static const char *fmtl = " %-17.17s 0x%lx\n"; ++ static const char *fmtd = " %-17.17s %d\n"; ++ static const char *fmtp = " %-17.17s 0x%p\n"; ++ ++ if (argc == 0) { ++ cpu = smp_processor_id(); ++ } else if (argc == 1) { ++ if (strcmp(argv[1], "*") == 0) { ++ all_cpus = 1; ++ cpu = 0; ++ } else { ++ nextarg = 1; ++ diag = kdbgetaddrarg(argc, argv, &nextarg, &cpu, &offset, NULL); ++ if (diag) ++ return diag; ++ } ++ } else { ++ return KDB_ARGCOUNT; ++ } ++ ++ for (; cpu < NR_CPUS; ++cpu) { ++ if (cpu_online(cpu)) { ++ c = cpu_pda(cpu); ++ kdb_printf("struct cpu_pda 0x%p-0x%p\n", c, (unsigned char *)c + sizeof(*c) - 1); ++ kdb_printf(fmtp, "pcurrent", c->pcurrent); ++ kdb_printf(fmtl, "data_offset", c->data_offset); ++ kdb_printf(fmtl, "kernelstack", c->kernelstack); ++ kdb_printf(fmtl, "oldrsp", c->oldrsp); ++ kdb_printf(fmtd, "irqcount", c->irqcount); ++ kdb_printf(fmtd, "cpunumber", c->cpunumber); ++ kdb_printf(fmtp, "irqstackptr", c->irqstackptr); ++ kdb_printf(fmtp, "nodenumber", cpu_to_node(cpu)); ++ kdb_printf(fmtd, "__softirq_pending", c->__softirq_pending); ++ kdb_printf(fmtd, "__nmi_count", c->__nmi_count); ++ kdb_printf(fmtd, "mmu_state", c->mmu_state); ++ kdb_printf(fmtp, "active_mm", c->active_mm); ++ kdb_printf(fmtd, "apic_timer_irqs", c->apic_timer_irqs); ++ } ++ if (!all_cpus) ++ break; ++ } ++ return 0; ++} ++ ++/* ++ * kdba_entry ++ * ++ * This is the interface routine between ++ * the notifier die_chain and kdb ++ */ ++static int kdba_entry( struct notifier_block *b, unsigned long val, void *v) ++{ ++ struct die_args *args = v; ++ int err, trap, ret = 0; ++ struct pt_regs *regs; ++ ++ regs = args->regs; ++ err = args->err; ++ trap = args->trapnr; ++ switch (val){ ++#ifdef CONFIG_SMP ++ case DIE_NMI_IPI: ++ ret = kdb_ipi(regs, NULL); ++ break; ++#endif /* CONFIG_SMP */ ++ case DIE_OOPS: ++ ret = kdb(KDB_REASON_OOPS, err, regs); ++ break; ++ case DIE_CALL: ++ ret = kdb(KDB_REASON_ENTER, err, regs); ++ break; ++ case DIE_DEBUG: ++ ret = kdb(KDB_REASON_DEBUG, err, regs); ++ break; ++ case DIE_NMIWATCHDOG: ++ ret = kdb(KDB_REASON_NMI, err, regs); ++ break; ++ case DIE_INT3: ++ ret = kdb(KDB_REASON_BREAK, err, regs); ++ // falls thru ++ default: ++ break; ++ } ++ return (ret ? NOTIFY_STOP : NOTIFY_DONE); ++} ++ ++/* ++ * notifier block for kdb entry ++ */ ++static struct notifier_block kdba_notifier = { ++ .notifier_call = kdba_entry ++}; ++ ++asmlinkage int kdb_call(void); ++ ++/* Executed once on each cpu at startup. */ ++void ++kdba_cpu_up(void) ++{ ++} ++ ++static int __init ++kdba_arch_init(void) ++{ ++#ifdef CONFIG_SMP ++ set_intr_gate(KDB_VECTOR, kdb_interrupt); ++#endif ++ set_intr_gate(KDBENTER_VECTOR, kdb_call); ++ return 0; ++} ++ ++arch_initcall(kdba_arch_init); ++ ++/* ++ * kdba_init ++ * ++ * Architecture specific initialization. ++ * ++ * Parameters: ++ * None. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * None. ++ */ ++ ++void __init ++kdba_init(void) ++{ ++ kdba_arch_init(); /* Need to register KDBENTER_VECTOR early */ ++ kdb_register("pt_regs", kdba_pt_regs, "address", "Format struct pt_regs", 0); ++ kdb_register("cpu_pda", kdba_cpu_pda, "", "Format struct cpu_pda", 0); ++ register_die_notifier(&kdba_notifier); ++ return; ++} ++ ++/* ++ * kdba_adjust_ip ++ * ++ * Architecture specific adjustment of instruction pointer before leaving ++ * kdb. ++ * ++ * Parameters: ++ * reason The reason KDB was invoked ++ * error The hardware-defined error code ++ * ef The exception frame at time of fault/breakpoint. If reason ++ * is SILENT or CPU_UP then regs is NULL, otherwise it should ++ * always be valid. ++ * Returns: ++ * None. ++ * Locking: ++ * None. ++ * Remarks: ++ * noop on ix86. ++ */ ++ ++void ++kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *ef) ++{ ++ return; ++} ++ ++void ++kdba_set_current_task(const struct task_struct *p) ++{ ++ kdb_current_task = p; ++ if (kdb_task_has_cpu(p)) { ++ struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p); ++ kdb_current_regs = krp->regs; ++ return; ++ } ++ kdb_current_regs = NULL; ++} ++ ++#ifdef CONFIG_SMP ++ ++#include ++ ++/* When first entering KDB, try a normal IPI. That reduces backtrace problems ++ * on the other cpus. ++ */ ++void ++smp_kdb_stop(void) ++{ ++ if (!KDB_FLAG(NOIPI)) ++ send_IPI_allbutself(KDB_VECTOR); ++} ++ ++/* The normal KDB IPI handler */ ++extern asmlinkage void smp_kdb_interrupt(struct pt_regs *regs); /* for sparse */ ++asmlinkage void ++smp_kdb_interrupt(struct pt_regs *regs) ++{ ++ struct pt_regs *old_regs = set_irq_regs(regs); ++ ack_APIC_irq(); ++ irq_enter(); ++ kdb_ipi(regs, NULL); ++ irq_exit(); ++ set_irq_regs(old_regs); ++} ++ ++/* Invoked once from kdb_wait_for_cpus when waiting for cpus. For those cpus ++ * that have not responded to the normal KDB interrupt yet, hit them with an ++ * NMI event. ++ */ ++void ++kdba_wait_for_cpus(void) ++{ ++ int c; ++ if (KDB_FLAG(CATASTROPHIC)) ++ return; ++ kdb_printf(" Sending NMI to non-responding cpus: "); ++ for_each_online_cpu(c) { ++ if (kdb_running_process[c].seqno < kdb_seqno - 1) { ++ kdb_printf(" %d", c); ++ send_IPI_mask(&cpumask_of_cpu(c), NMI_VECTOR); ++ } ++ } ++ kdb_printf(".\n"); ++} ++ ++#endif /* CONFIG_SMP */ +--- /dev/null ++++ b/arch/x86/kdb/kdba_support.c +@@ -0,0 +1,59 @@ ++/* ++ * Kernel Debugger Architecture Independent Support Functions ++ * ++ * 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) 1999-2008 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_KDB_KDUMP ++void kdba_kdump_prepare(struct pt_regs *regs) ++{ ++ int i; ++ struct pt_regs r; ++ if (regs == NULL) ++ regs = &r; ++ ++ machine_crash_shutdown_begin(); ++ ++ for (i = 1; i < NR_CPUS; ++i) { ++ if (!cpu_online(i)) ++ continue; ++ ++ KDB_STATE_SET_CPU(KEXEC, i); ++ } ++ ++ machine_crash_shutdown_end(regs); ++} ++ ++extern void halt_current_cpu(struct pt_regs *); ++ ++void kdba_kdump_shutdown_slave(struct pt_regs *regs) ++{ ++#ifndef CONFIG_XEN ++ halt_current_cpu(regs); ++#endif /* CONFIG_XEN */ ++} ++ ++#endif +--- /dev/null ++++ b/arch/x86/kdb/kdb_cmds_32 +@@ -0,0 +1,17 @@ ++# Standard architecture specific commands for kdb. ++# These commands are appended to those in kdb/kdb_cmds, see that file for ++# restrictions. ++ ++# Standard debugging information for first level support, invoked from archkdb* ++# commands that are defined in kdb/kdb_cmds. ++ ++defcmd archkdbcommon "" "Common arch debugging" ++ set LINES 2000000 ++ set BTAPROMPT 0 ++ -summary ++ -id %eip-24 ++ -cpu ++ -ps ++ -dmesg 600 ++ -bt ++endefcmd +--- /dev/null ++++ b/arch/x86/kdb/kdb_cmds_64 +@@ -0,0 +1,18 @@ ++# Standard architecture specific commands for kdb. ++# These commands are appended to those in kdb/kdb_cmds, see that file for ++# restrictions. ++ ++# Standard debugging information for first level support, invoked from archkdb* ++# commands that are defined in kdb/kdb_cmds. ++ ++defcmd archkdbcommon "" "Common arch debugging" ++ set LINES 2000000 ++ set BTAPROMPT 0 ++ -summary ++ -id %rip-24 ++ -cpu ++ -ps ++ -dmesg 600 ++ -bt ++ -cpu_pda * ++endefcmd +--- /dev/null ++++ b/arch/x86/kdb/Makefile +@@ -0,0 +1,5 @@ ++ifeq ($(CONFIG_X86_32),y) ++include ${srctree}/arch/x86/kdb/Makefile_32 ++else ++include ${srctree}/arch/x86/kdb/Makefile_64 ++endif +--- /dev/null ++++ b/arch/x86/kdb/Makefile_32 +@@ -0,0 +1,25 @@ ++# ++# 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++# ++ ++obj-$(CONFIG_KDB) := kdba_bp_32.o kdbasupport_32.o i386-dis.o ++ ++# The i386 and x86_64 backtrace commands are handled by common code. ++obj-y += kdba_bt.o kdba_io.o kdba_id.o kdba_support.o ++ifneq (,$(findstring -fno-optimize-sibling-calls,$(KBUILD_CFLAGS))) ++ CFLAGS_kdba_bt.o += -DNO_SIBLINGS ++endif ++REGPARM := $(subst -mregparm=,,$(filter -mregparm=%,$(KBUILD_CFLAGS))) ++ifeq (,$(REGPARM)) ++ REGPARM := 3 ++endif ++ ++CFLAGS_kdba_bt.o += -DREGPARM=$(REGPARM) -DCCVERSION="$(CCVERSION)" ++ ++override CFLAGS := $(CFLAGS:%-pg=% ) ++ ++CFLAGS_kdba_io.o += -I $(TOPDIR)/arch/$(SRCARCH)/kdb +--- /dev/null ++++ b/arch/x86/kdb/Makefile_64 +@@ -0,0 +1,25 @@ ++# ++# 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. ++# ++ ++obj-$(CONFIG_KDB) := kdba_bp_64.o kdbasupport_64.o x86_64-dis.o ++ ++# The i386 and x86_64 backtrace commands are handled by common code. ++obj-y += kdba_bt.o kdba_io.o kdba_id.o kdba_support.o ++ifneq (,$(findstring -fno-optimize-sibling-calls,$(KBUILD_CFLAGS))) ++ CFLAGS_kdba_bt.o += -DNO_SIBLINGS ++endif ++REGPARM := $(subst -mregparm=,,$(filter -mregparm=%,$(KBUILD_CFLAGS))) ++ifeq (,$(REGPARM)) ++ REGPARM := 6 ++endif ++ ++CFLAGS_kdba_bt.o += -DREGPARM=$(REGPARM) -DCCVERSION="$(CCVERSION)" ++ ++override CFLAGS := $(CFLAGS:%-pg=% ) ++ ++CFLAGS_kdba_io.o += -I $(TOPDIR)/arch/$(SRCARCH)/kdb +--- /dev/null ++++ b/arch/x86/kdb/pc_keyb.h +@@ -0,0 +1,137 @@ ++/* ++ * include/linux/pc_keyb.h ++ * ++ * PC Keyboard And Keyboard Controller ++ * ++ * (c) 1997 Martin Mares ++ */ ++ ++/* ++ * Configuration Switches ++ */ ++ ++#undef KBD_REPORT_ERR /* Report keyboard errors */ ++#define KBD_REPORT_UNKN /* Report unknown scan codes */ ++#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ ++#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ ++#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ ++ ++ ++ ++#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ ++#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ ++#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ ++ ++/* ++ * Internal variables of the driver ++ */ ++ ++extern unsigned char pckbd_read_mask; ++extern unsigned char aux_device_present; ++ ++/* ++ * Keyboard Controller Registers on normal PCs. ++ */ ++ ++#define KBD_STATUS_REG 0x64 /* Status register (R) */ ++#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ ++#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ ++ ++/* ++ * Keyboard Controller Commands ++ */ ++ ++#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ ++#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ ++#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ ++#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ ++#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ ++#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ ++#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ ++#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ ++#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ ++#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ ++#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if ++ initiated by the auxiliary device */ ++#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ ++ ++/* ++ * Keyboard Commands ++ */ ++ ++#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ ++#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ ++#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ ++#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ ++#define KBD_CMD_RESET 0xFF /* Reset */ ++ ++/* ++ * Keyboard Replies ++ */ ++ ++#define KBD_REPLY_POR 0xAA /* Power on reset */ ++#define KBD_REPLY_ACK 0xFA /* Command ACK */ ++#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ ++ ++/* ++ * Status Register Bits ++ */ ++ ++#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ ++#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ ++#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ ++#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ ++#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ ++#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ ++#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ ++#define KBD_STAT_PERR 0x80 /* Parity error */ ++ ++#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) ++ ++/* ++ * Controller Mode Register Bits ++ */ ++ ++#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ ++#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ ++#define KBD_MODE_SYS 0x04 /* The system flag (?) */ ++#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ ++#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ ++#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ ++#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ ++#define KBD_MODE_RFU 0x80 ++ ++/* ++ * Mouse Commands ++ */ ++ ++#define AUX_SET_RES 0xE8 /* Set resolution */ ++#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ ++#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ ++#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ ++#define AUX_SET_STREAM 0xEA /* Set stream mode */ ++#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ ++#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ ++#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ ++#define AUX_RESET 0xFF /* Reset aux device */ ++#define AUX_ACK 0xFA /* Command byte ACK. */ ++ ++#define AUX_BUF_SIZE 2048 /* This might be better divisible by ++ three to make overruns stay in sync ++ but then the read function would need ++ a lock etc - ick */ ++ ++struct aux_queue { ++ unsigned long head; ++ unsigned long tail; ++ wait_queue_head_t proc_list; ++ struct fasync_struct *fasync; ++ unsigned char buf[AUX_BUF_SIZE]; ++}; ++ ++ ++/* How to access the keyboard macros on this platform. */ ++#define kbd_read_input() inb(KBD_DATA_REG) ++#define kbd_read_status() inb(KBD_STATUS_REG) ++#define kbd_write_output(val) outb(val, KBD_DATA_REG) ++#define kbd_write_command(val) outb(val, KBD_CNTL_REG) +--- /dev/null ++++ b/arch/x86/kdb/x86_64-dis.c +@@ -0,0 +1,4686 @@ ++/* Print i386 instructions for GDB, the GNU debugger. ++ Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, ++ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Run through col -b to remove trailing whitespace and various #ifdef/ifndef ++ * __KERNEL__ added. ++ * Keith Owens 15 May 2006 ++ */ ++ ++/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) ++ July 1988 ++ modified by John Hassey (hassey@dg-rtp.dg.com) ++ x86-64 support added by Jan Hubicka (jh@suse.cz) ++ VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ ++ ++/* The main tables describing the instructions is essentially a copy ++ of the "Opcode Map" chapter (Appendix A) of the Intel 80386 ++ Programmers Manual. Usually, there is a capital letter, followed ++ by a small letter. The capital letter tell the addressing mode, ++ and the small letter tells about the operand size. Refer to ++ the Intel manual for details. */ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++#define abort() BUG() ++#else /* __KERNEL__ */ ++#include "dis-asm.h" ++#include "sysdep.h" ++#include "opintl.h" ++#endif /* __KERNEL__ */ ++ ++#define MAXLEN 20 ++ ++#ifndef __KERNEL__ ++#include ++#endif /* __KERNEL__ */ ++ ++#ifndef UNIXWARE_COMPAT ++/* Set non-zero for broken, compatible instructions. Set to zero for ++ non-broken opcodes. */ ++#define UNIXWARE_COMPAT 1 ++#endif ++ ++static int fetch_data (struct disassemble_info *, bfd_byte *); ++static void ckprefix (void); ++static const char *prefix_name (int, int); ++static int print_insn (bfd_vma, disassemble_info *); ++static void dofloat (int); ++static void OP_ST (int, int); ++static void OP_STi (int, int); ++static int putop (const char *, int); ++static void oappend (const char *); ++static void append_seg (void); ++static void OP_indirE (int, int); ++static void print_operand_value (char *, int, bfd_vma); ++static void OP_E (int, int); ++static void OP_G (int, int); ++static bfd_vma get64 (void); ++static bfd_signed_vma get32 (void); ++static bfd_signed_vma get32s (void); ++static int get16 (void); ++static void set_op (bfd_vma, int); ++static void OP_REG (int, int); ++static void OP_IMREG (int, int); ++static void OP_I (int, int); ++static void OP_I64 (int, int); ++static void OP_sI (int, int); ++static void OP_J (int, int); ++static void OP_SEG (int, int); ++static void OP_DIR (int, int); ++static void OP_OFF (int, int); ++static void OP_OFF64 (int, int); ++static void ptr_reg (int, int); ++static void OP_ESreg (int, int); ++static void OP_DSreg (int, int); ++static void OP_C (int, int); ++static void OP_D (int, int); ++static void OP_T (int, int); ++static void OP_Rd (int, int); ++static void OP_MMX (int, int); ++static void OP_XMM (int, int); ++static void OP_EM (int, int); ++static void OP_EX (int, int); ++static void OP_MS (int, int); ++static void OP_XS (int, int); ++static void OP_M (int, int); ++static void OP_VMX (int, int); ++static void OP_0fae (int, int); ++static void OP_0f07 (int, int); ++static void NOP_Fixup (int, int); ++static void OP_3DNowSuffix (int, int); ++static void OP_SIMD_Suffix (int, int); ++static void SIMD_Fixup (int, int); ++static void PNI_Fixup (int, int); ++static void SVME_Fixup (int, int); ++static void INVLPG_Fixup (int, int); ++static void BadOp (void); ++static void SEG_Fixup (int, int); ++static void VMX_Fixup (int, int); ++ ++struct dis_private { ++ /* Points to first byte not fetched. */ ++ bfd_byte *max_fetched; ++ bfd_byte the_buffer[MAXLEN]; ++ bfd_vma insn_start; ++ int orig_sizeflag; ++#ifndef __KERNEL__ ++ jmp_buf bailout; ++#endif /* __KERNEL__ */ ++}; ++ ++/* The opcode for the fwait instruction, which we treat as a prefix ++ when we can. */ ++#define FWAIT_OPCODE (0x9b) ++ ++/* Set to 1 for 64bit mode disassembly. */ ++static int mode_64bit; ++ ++/* Flags for the prefixes for the current instruction. See below. */ ++static int prefixes; ++ ++/* REX prefix the current instruction. See below. */ ++static int rex; ++/* Bits of REX we've already used. */ ++static int rex_used; ++#define REX_MODE64 8 ++#define REX_EXTX 4 ++#define REX_EXTY 2 ++#define REX_EXTZ 1 ++/* Mark parts used in the REX prefix. When we are testing for ++ empty prefix (for 8bit register REX extension), just mask it ++ out. Otherwise test for REX bit is excuse for existence of REX ++ only in case value is nonzero. */ ++#define USED_REX(value) \ ++ { \ ++ if (value) \ ++ rex_used |= (rex & value) ? (value) | 0x40 : 0; \ ++ else \ ++ rex_used |= 0x40; \ ++ } ++ ++/* Flags for prefixes which we somehow handled when printing the ++ current instruction. */ ++static int used_prefixes; ++ ++/* Flags stored in PREFIXES. */ ++#define PREFIX_REPZ 1 ++#define PREFIX_REPNZ 2 ++#define PREFIX_LOCK 4 ++#define PREFIX_CS 8 ++#define PREFIX_SS 0x10 ++#define PREFIX_DS 0x20 ++#define PREFIX_ES 0x40 ++#define PREFIX_FS 0x80 ++#define PREFIX_GS 0x100 ++#define PREFIX_DATA 0x200 ++#define PREFIX_ADDR 0x400 ++#define PREFIX_FWAIT 0x800 ++ ++/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) ++ to ADDR (exclusive) are valid. Returns 1 for success, longjmps ++ on error. */ ++#define FETCH_DATA(info, addr) \ ++ ((addr) <= ((struct dis_private *) (info->private_data))->max_fetched \ ++ ? 1 : fetch_data ((info), (addr))) ++ ++static int ++fetch_data (struct disassemble_info *info, bfd_byte *addr) ++{ ++ int status; ++ struct dis_private *priv = (struct dis_private *) info->private_data; ++ bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); ++ ++ status = (*info->read_memory_func) (start, ++ priv->max_fetched, ++ addr - priv->max_fetched, ++ info); ++ if (status != 0) ++ { ++ /* If we did manage to read at least one byte, then ++ print_insn_i386 will do something sensible. Otherwise, print ++ an error. We do that here because this is where we know ++ STATUS. */ ++ if (priv->max_fetched == priv->the_buffer) ++ (*info->memory_error_func) (status, start, info); ++#ifndef __KERNEL__ ++ longjmp (priv->bailout, 1); ++#else /* __KERNEL__ */ ++ /* XXX - what to do? */ ++ kdb_printf("Hmm. longjmp.\n"); ++#endif /* __KERNEL__ */ ++ } ++ else ++ priv->max_fetched = addr; ++ return 1; ++} ++ ++#define XX NULL, 0 ++ ++#define Eb OP_E, b_mode ++#define Ev OP_E, v_mode ++#define Ed OP_E, d_mode ++#define Eq OP_E, q_mode ++#define Edq OP_E, dq_mode ++#define Edqw OP_E, dqw_mode ++#define indirEv OP_indirE, branch_v_mode ++#define indirEp OP_indirE, f_mode ++#define Em OP_E, m_mode ++#define Ew OP_E, w_mode ++#define Ma OP_E, v_mode ++#define M OP_M, 0 /* lea, lgdt, etc. */ ++#define Mp OP_M, f_mode /* 32 or 48 bit memory operand for LDS, LES etc */ ++#define Gb OP_G, b_mode ++#define Gv OP_G, v_mode ++#define Gd OP_G, d_mode ++#define Gdq OP_G, dq_mode ++#define Gm OP_G, m_mode ++#define Gw OP_G, w_mode ++#define Rd OP_Rd, d_mode ++#define Rm OP_Rd, m_mode ++#define Ib OP_I, b_mode ++#define sIb OP_sI, b_mode /* sign extened byte */ ++#define Iv OP_I, v_mode ++#define Iq OP_I, q_mode ++#define Iv64 OP_I64, v_mode ++#define Iw OP_I, w_mode ++#define I1 OP_I, const_1_mode ++#define Jb OP_J, b_mode ++#define Jv OP_J, v_mode ++#define Cm OP_C, m_mode ++#define Dm OP_D, m_mode ++#define Td OP_T, d_mode ++#define Sv SEG_Fixup, v_mode ++ ++#define RMeAX OP_REG, eAX_reg ++#define RMeBX OP_REG, eBX_reg ++#define RMeCX OP_REG, eCX_reg ++#define RMeDX OP_REG, eDX_reg ++#define RMeSP OP_REG, eSP_reg ++#define RMeBP OP_REG, eBP_reg ++#define RMeSI OP_REG, eSI_reg ++#define RMeDI OP_REG, eDI_reg ++#define RMrAX OP_REG, rAX_reg ++#define RMrBX OP_REG, rBX_reg ++#define RMrCX OP_REG, rCX_reg ++#define RMrDX OP_REG, rDX_reg ++#define RMrSP OP_REG, rSP_reg ++#define RMrBP OP_REG, rBP_reg ++#define RMrSI OP_REG, rSI_reg ++#define RMrDI OP_REG, rDI_reg ++#define RMAL OP_REG, al_reg ++#define RMAL OP_REG, al_reg ++#define RMCL OP_REG, cl_reg ++#define RMDL OP_REG, dl_reg ++#define RMBL OP_REG, bl_reg ++#define RMAH OP_REG, ah_reg ++#define RMCH OP_REG, ch_reg ++#define RMDH OP_REG, dh_reg ++#define RMBH OP_REG, bh_reg ++#define RMAX OP_REG, ax_reg ++#define RMDX OP_REG, dx_reg ++ ++#define eAX OP_IMREG, eAX_reg ++#define eBX OP_IMREG, eBX_reg ++#define eCX OP_IMREG, eCX_reg ++#define eDX OP_IMREG, eDX_reg ++#define eSP OP_IMREG, eSP_reg ++#define eBP OP_IMREG, eBP_reg ++#define eSI OP_IMREG, eSI_reg ++#define eDI OP_IMREG, eDI_reg ++#define AL OP_IMREG, al_reg ++#define AL OP_IMREG, al_reg ++#define CL OP_IMREG, cl_reg ++#define DL OP_IMREG, dl_reg ++#define BL OP_IMREG, bl_reg ++#define AH OP_IMREG, ah_reg ++#define CH OP_IMREG, ch_reg ++#define DH OP_IMREG, dh_reg ++#define BH OP_IMREG, bh_reg ++#define AX OP_IMREG, ax_reg ++#define DX OP_IMREG, dx_reg ++#define indirDX OP_IMREG, indir_dx_reg ++ ++#define Sw OP_SEG, w_mode ++#define Ap OP_DIR, 0 ++#define Ob OP_OFF, b_mode ++#define Ob64 OP_OFF64, b_mode ++#define Ov OP_OFF, v_mode ++#define Ov64 OP_OFF64, v_mode ++#define Xb OP_DSreg, eSI_reg ++#define Xv OP_DSreg, eSI_reg ++#define Yb OP_ESreg, eDI_reg ++#define Yv OP_ESreg, eDI_reg ++#define DSBX OP_DSreg, eBX_reg ++ ++#define es OP_REG, es_reg ++#define ss OP_REG, ss_reg ++#define cs OP_REG, cs_reg ++#define ds OP_REG, ds_reg ++#define fs OP_REG, fs_reg ++#define gs OP_REG, gs_reg ++ ++#define MX OP_MMX, 0 ++#define XM OP_XMM, 0 ++#define EM OP_EM, v_mode ++#define EX OP_EX, v_mode ++#define MS OP_MS, v_mode ++#define XS OP_XS, v_mode ++#define VM OP_VMX, q_mode ++#define OPSUF OP_3DNowSuffix, 0 ++#define OPSIMD OP_SIMD_Suffix, 0 ++ ++#define cond_jump_flag NULL, cond_jump_mode ++#define loop_jcxz_flag NULL, loop_jcxz_mode ++ ++/* bits in sizeflag */ ++#define SUFFIX_ALWAYS 4 ++#define AFLAG 2 ++#define DFLAG 1 ++ ++#define b_mode 1 /* byte operand */ ++#define v_mode 2 /* operand size depends on prefixes */ ++#define w_mode 3 /* word operand */ ++#define d_mode 4 /* double word operand */ ++#define q_mode 5 /* quad word operand */ ++#define t_mode 6 /* ten-byte operand */ ++#define x_mode 7 /* 16-byte XMM operand */ ++#define m_mode 8 /* d_mode in 32bit, q_mode in 64bit mode. */ ++#define cond_jump_mode 9 ++#define loop_jcxz_mode 10 ++#define dq_mode 11 /* operand size depends on REX prefixes. */ ++#define dqw_mode 12 /* registers like dq_mode, memory like w_mode. */ ++#define f_mode 13 /* 4- or 6-byte pointer operand */ ++#define const_1_mode 14 ++#define branch_v_mode 15 /* v_mode for branch. */ ++ ++#define es_reg 100 ++#define cs_reg 101 ++#define ss_reg 102 ++#define ds_reg 103 ++#define fs_reg 104 ++#define gs_reg 105 ++ ++#define eAX_reg 108 ++#define eCX_reg 109 ++#define eDX_reg 110 ++#define eBX_reg 111 ++#define eSP_reg 112 ++#define eBP_reg 113 ++#define eSI_reg 114 ++#define eDI_reg 115 ++ ++#define al_reg 116 ++#define cl_reg 117 ++#define dl_reg 118 ++#define bl_reg 119 ++#define ah_reg 120 ++#define ch_reg 121 ++#define dh_reg 122 ++#define bh_reg 123 ++ ++#define ax_reg 124 ++#define cx_reg 125 ++#define dx_reg 126 ++#define bx_reg 127 ++#define sp_reg 128 ++#define bp_reg 129 ++#define si_reg 130 ++#define di_reg 131 ++ ++#define rAX_reg 132 ++#define rCX_reg 133 ++#define rDX_reg 134 ++#define rBX_reg 135 ++#define rSP_reg 136 ++#define rBP_reg 137 ++#define rSI_reg 138 ++#define rDI_reg 139 ++ ++#define indir_dx_reg 150 ++ ++#define FLOATCODE 1 ++#define USE_GROUPS 2 ++#define USE_PREFIX_USER_TABLE 3 ++#define X86_64_SPECIAL 4 ++ ++#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 ++ ++#define GRP1b NULL, NULL, USE_GROUPS, NULL, 0, NULL, 0 ++#define GRP1S NULL, NULL, USE_GROUPS, NULL, 1, NULL, 0 ++#define GRP1Ss NULL, NULL, USE_GROUPS, NULL, 2, NULL, 0 ++#define GRP2b NULL, NULL, USE_GROUPS, NULL, 3, NULL, 0 ++#define GRP2S NULL, NULL, USE_GROUPS, NULL, 4, NULL, 0 ++#define GRP2b_one NULL, NULL, USE_GROUPS, NULL, 5, NULL, 0 ++#define GRP2S_one NULL, NULL, USE_GROUPS, NULL, 6, NULL, 0 ++#define GRP2b_cl NULL, NULL, USE_GROUPS, NULL, 7, NULL, 0 ++#define GRP2S_cl NULL, NULL, USE_GROUPS, NULL, 8, NULL, 0 ++#define GRP3b NULL, NULL, USE_GROUPS, NULL, 9, NULL, 0 ++#define GRP3S NULL, NULL, USE_GROUPS, NULL, 10, NULL, 0 ++#define GRP4 NULL, NULL, USE_GROUPS, NULL, 11, NULL, 0 ++#define GRP5 NULL, NULL, USE_GROUPS, NULL, 12, NULL, 0 ++#define GRP6 NULL, NULL, USE_GROUPS, NULL, 13, NULL, 0 ++#define GRP7 NULL, NULL, USE_GROUPS, NULL, 14, NULL, 0 ++#define GRP8 NULL, NULL, USE_GROUPS, NULL, 15, NULL, 0 ++#define GRP9 NULL, NULL, USE_GROUPS, NULL, 16, NULL, 0 ++#define GRP10 NULL, NULL, USE_GROUPS, NULL, 17, NULL, 0 ++#define GRP11 NULL, NULL, USE_GROUPS, NULL, 18, NULL, 0 ++#define GRP12 NULL, NULL, USE_GROUPS, NULL, 19, NULL, 0 ++#define GRP13 NULL, NULL, USE_GROUPS, NULL, 20, NULL, 0 ++#define GRP14 NULL, NULL, USE_GROUPS, NULL, 21, NULL, 0 ++#define GRPAMD NULL, NULL, USE_GROUPS, NULL, 22, NULL, 0 ++#define GRPPADLCK1 NULL, NULL, USE_GROUPS, NULL, 23, NULL, 0 ++#define GRPPADLCK2 NULL, NULL, USE_GROUPS, NULL, 24, NULL, 0 ++ ++#define PREGRP0 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 0, NULL, 0 ++#define PREGRP1 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 1, NULL, 0 ++#define PREGRP2 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 2, NULL, 0 ++#define PREGRP3 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 3, NULL, 0 ++#define PREGRP4 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 4, NULL, 0 ++#define PREGRP5 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 5, NULL, 0 ++#define PREGRP6 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 6, NULL, 0 ++#define PREGRP7 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 7, NULL, 0 ++#define PREGRP8 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 8, NULL, 0 ++#define PREGRP9 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 9, NULL, 0 ++#define PREGRP10 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 10, NULL, 0 ++#define PREGRP11 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 11, NULL, 0 ++#define PREGRP12 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 12, NULL, 0 ++#define PREGRP13 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 13, NULL, 0 ++#define PREGRP14 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 14, NULL, 0 ++#define PREGRP15 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 15, NULL, 0 ++#define PREGRP16 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 16, NULL, 0 ++#define PREGRP17 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 17, NULL, 0 ++#define PREGRP18 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 18, NULL, 0 ++#define PREGRP19 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 19, NULL, 0 ++#define PREGRP20 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 20, NULL, 0 ++#define PREGRP21 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 21, NULL, 0 ++#define PREGRP22 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 22, NULL, 0 ++#define PREGRP23 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 23, NULL, 0 ++#define PREGRP24 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 24, NULL, 0 ++#define PREGRP25 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 25, NULL, 0 ++#define PREGRP26 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 26, NULL, 0 ++#define PREGRP27 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 27, NULL, 0 ++#define PREGRP28 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 28, NULL, 0 ++#define PREGRP29 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 29, NULL, 0 ++#define PREGRP30 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 30, NULL, 0 ++#define PREGRP31 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 31, NULL, 0 ++#define PREGRP32 NULL, NULL, USE_PREFIX_USER_TABLE, NULL, 32, NULL, 0 ++ ++#define X86_64_0 NULL, NULL, X86_64_SPECIAL, NULL, 0, NULL, 0 ++ ++typedef void (*op_rtn) (int bytemode, int sizeflag); ++ ++struct dis386 { ++ const char *name; ++ op_rtn op1; ++ int bytemode1; ++ op_rtn op2; ++ int bytemode2; ++ op_rtn op3; ++ int bytemode3; ++}; ++ ++/* Upper case letters in the instruction names here are macros. ++ 'A' => print 'b' if no register operands or suffix_always is true ++ 'B' => print 'b' if suffix_always is true ++ 'C' => print 's' or 'l' ('w' or 'd' in Intel mode) depending on operand ++ . size prefix ++ 'E' => print 'e' if 32-bit form of jcxz ++ 'F' => print 'w' or 'l' depending on address size prefix (loop insns) ++ 'H' => print ",pt" or ",pn" branch hint ++ 'I' => honor following macro letter even in Intel mode (implemented only ++ . for some of the macro letters) ++ 'J' => print 'l' ++ 'L' => print 'l' if suffix_always is true ++ 'N' => print 'n' if instruction has no wait "prefix" ++ 'O' => print 'd', or 'o' ++ 'P' => print 'w', 'l' or 'q' if instruction has an operand size prefix, ++ . or suffix_always is true. print 'q' if rex prefix is present. ++ 'Q' => print 'w', 'l' or 'q' if no register operands or suffix_always ++ . is true ++ 'R' => print 'w', 'l' or 'q' ("wd" or "dq" in intel mode) ++ 'S' => print 'w', 'l' or 'q' if suffix_always is true ++ 'T' => print 'q' in 64bit mode and behave as 'P' otherwise ++ 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise ++ 'W' => print 'b' or 'w' ("w" or "de" in intel mode) ++ 'X' => print 's', 'd' depending on data16 prefix (for XMM) ++ 'Y' => 'q' if instruction has an REX 64bit overwrite prefix ++ ++ Many of the above letters print nothing in Intel mode. See "putop" ++ for the details. ++ ++ Braces '{' and '}', and vertical bars '|', indicate alternative ++ mnemonic strings for AT&T, Intel, X86_64 AT&T, and X86_64 Intel ++ modes. In cases where there are only two alternatives, the X86_64 ++ instruction is reserved, and "(bad)" is printed. ++*/ ++ ++static const struct dis386 dis386[] = { ++ /* 00 */ ++ { "addB", Eb, Gb, XX }, ++ { "addS", Ev, Gv, XX }, ++ { "addB", Gb, Eb, XX }, ++ { "addS", Gv, Ev, XX }, ++ { "addB", AL, Ib, XX }, ++ { "addS", eAX, Iv, XX }, ++ { "push{T|}", es, XX, XX }, ++ { "pop{T|}", es, XX, XX }, ++ /* 08 */ ++ { "orB", Eb, Gb, XX }, ++ { "orS", Ev, Gv, XX }, ++ { "orB", Gb, Eb, XX }, ++ { "orS", Gv, Ev, XX }, ++ { "orB", AL, Ib, XX }, ++ { "orS", eAX, Iv, XX }, ++ { "push{T|}", cs, XX, XX }, ++ { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ ++ /* 10 */ ++ { "adcB", Eb, Gb, XX }, ++ { "adcS", Ev, Gv, XX }, ++ { "adcB", Gb, Eb, XX }, ++ { "adcS", Gv, Ev, XX }, ++ { "adcB", AL, Ib, XX }, ++ { "adcS", eAX, Iv, XX }, ++ { "push{T|}", ss, XX, XX }, ++ { "popT|}", ss, XX, XX }, ++ /* 18 */ ++ { "sbbB", Eb, Gb, XX }, ++ { "sbbS", Ev, Gv, XX }, ++ { "sbbB", Gb, Eb, XX }, ++ { "sbbS", Gv, Ev, XX }, ++ { "sbbB", AL, Ib, XX }, ++ { "sbbS", eAX, Iv, XX }, ++ { "push{T|}", ds, XX, XX }, ++ { "pop{T|}", ds, XX, XX }, ++ /* 20 */ ++ { "andB", Eb, Gb, XX }, ++ { "andS", Ev, Gv, XX }, ++ { "andB", Gb, Eb, XX }, ++ { "andS", Gv, Ev, XX }, ++ { "andB", AL, Ib, XX }, ++ { "andS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG ES prefix */ ++ { "daa{|}", XX, XX, XX }, ++ /* 28 */ ++ { "subB", Eb, Gb, XX }, ++ { "subS", Ev, Gv, XX }, ++ { "subB", Gb, Eb, XX }, ++ { "subS", Gv, Ev, XX }, ++ { "subB", AL, Ib, XX }, ++ { "subS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG CS prefix */ ++ { "das{|}", XX, XX, XX }, ++ /* 30 */ ++ { "xorB", Eb, Gb, XX }, ++ { "xorS", Ev, Gv, XX }, ++ { "xorB", Gb, Eb, XX }, ++ { "xorS", Gv, Ev, XX }, ++ { "xorB", AL, Ib, XX }, ++ { "xorS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG SS prefix */ ++ { "aaa{|}", XX, XX, XX }, ++ /* 38 */ ++ { "cmpB", Eb, Gb, XX }, ++ { "cmpS", Ev, Gv, XX }, ++ { "cmpB", Gb, Eb, XX }, ++ { "cmpS", Gv, Ev, XX }, ++ { "cmpB", AL, Ib, XX }, ++ { "cmpS", eAX, Iv, XX }, ++ { "(bad)", XX, XX, XX }, /* SEG DS prefix */ ++ { "aas{|}", XX, XX, XX }, ++ /* 40 */ ++ { "inc{S|}", RMeAX, XX, XX }, ++ { "inc{S|}", RMeCX, XX, XX }, ++ { "inc{S|}", RMeDX, XX, XX }, ++ { "inc{S|}", RMeBX, XX, XX }, ++ { "inc{S|}", RMeSP, XX, XX }, ++ { "inc{S|}", RMeBP, XX, XX }, ++ { "inc{S|}", RMeSI, XX, XX }, ++ { "inc{S|}", RMeDI, XX, XX }, ++ /* 48 */ ++ { "dec{S|}", RMeAX, XX, XX }, ++ { "dec{S|}", RMeCX, XX, XX }, ++ { "dec{S|}", RMeDX, XX, XX }, ++ { "dec{S|}", RMeBX, XX, XX }, ++ { "dec{S|}", RMeSP, XX, XX }, ++ { "dec{S|}", RMeBP, XX, XX }, ++ { "dec{S|}", RMeSI, XX, XX }, ++ { "dec{S|}", RMeDI, XX, XX }, ++ /* 50 */ ++ { "pushS", RMrAX, XX, XX }, ++ { "pushS", RMrCX, XX, XX }, ++ { "pushS", RMrDX, XX, XX }, ++ { "pushS", RMrBX, XX, XX }, ++ { "pushS", RMrSP, XX, XX }, ++ { "pushS", RMrBP, XX, XX }, ++ { "pushS", RMrSI, XX, XX }, ++ { "pushS", RMrDI, XX, XX }, ++ /* 58 */ ++ { "popS", RMrAX, XX, XX }, ++ { "popS", RMrCX, XX, XX }, ++ { "popS", RMrDX, XX, XX }, ++ { "popS", RMrBX, XX, XX }, ++ { "popS", RMrSP, XX, XX }, ++ { "popS", RMrBP, XX, XX }, ++ { "popS", RMrSI, XX, XX }, ++ { "popS", RMrDI, XX, XX }, ++ /* 60 */ ++ { "pusha{P|}", XX, XX, XX }, ++ { "popa{P|}", XX, XX, XX }, ++ { "bound{S|}", Gv, Ma, XX }, ++ { X86_64_0 }, ++ { "(bad)", XX, XX, XX }, /* seg fs */ ++ { "(bad)", XX, XX, XX }, /* seg gs */ ++ { "(bad)", XX, XX, XX }, /* op size prefix */ ++ { "(bad)", XX, XX, XX }, /* adr size prefix */ ++ /* 68 */ ++ { "pushT", Iq, XX, XX }, ++ { "imulS", Gv, Ev, Iv }, ++ { "pushT", sIb, XX, XX }, ++ { "imulS", Gv, Ev, sIb }, ++ { "ins{b||b|}", Yb, indirDX, XX }, ++ { "ins{R||R|}", Yv, indirDX, XX }, ++ { "outs{b||b|}", indirDX, Xb, XX }, ++ { "outs{R||R|}", indirDX, Xv, XX }, ++ /* 70 */ ++ { "joH", Jb, XX, cond_jump_flag }, ++ { "jnoH", Jb, XX, cond_jump_flag }, ++ { "jbH", Jb, XX, cond_jump_flag }, ++ { "jaeH", Jb, XX, cond_jump_flag }, ++ { "jeH", Jb, XX, cond_jump_flag }, ++ { "jneH", Jb, XX, cond_jump_flag }, ++ { "jbeH", Jb, XX, cond_jump_flag }, ++ { "jaH", Jb, XX, cond_jump_flag }, ++ /* 78 */ ++ { "jsH", Jb, XX, cond_jump_flag }, ++ { "jnsH", Jb, XX, cond_jump_flag }, ++ { "jpH", Jb, XX, cond_jump_flag }, ++ { "jnpH", Jb, XX, cond_jump_flag }, ++ { "jlH", Jb, XX, cond_jump_flag }, ++ { "jgeH", Jb, XX, cond_jump_flag }, ++ { "jleH", Jb, XX, cond_jump_flag }, ++ { "jgH", Jb, XX, cond_jump_flag }, ++ /* 80 */ ++ { GRP1b }, ++ { GRP1S }, ++ { "(bad)", XX, XX, XX }, ++ { GRP1Ss }, ++ { "testB", Eb, Gb, XX }, ++ { "testS", Ev, Gv, XX }, ++ { "xchgB", Eb, Gb, XX }, ++ { "xchgS", Ev, Gv, XX }, ++ /* 88 */ ++ { "movB", Eb, Gb, XX }, ++ { "movS", Ev, Gv, XX }, ++ { "movB", Gb, Eb, XX }, ++ { "movS", Gv, Ev, XX }, ++ { "movQ", Sv, Sw, XX }, ++ { "leaS", Gv, M, XX }, ++ { "movQ", Sw, Sv, XX }, ++ { "popU", Ev, XX, XX }, ++ /* 90 */ ++ { "nop", NOP_Fixup, 0, XX, XX }, ++ { "xchgS", RMeCX, eAX, XX }, ++ { "xchgS", RMeDX, eAX, XX }, ++ { "xchgS", RMeBX, eAX, XX }, ++ { "xchgS", RMeSP, eAX, XX }, ++ { "xchgS", RMeBP, eAX, XX }, ++ { "xchgS", RMeSI, eAX, XX }, ++ { "xchgS", RMeDI, eAX, XX }, ++ /* 98 */ ++ { "cW{tR||tR|}", XX, XX, XX }, ++ { "cR{tO||tO|}", XX, XX, XX }, ++ { "Jcall{T|}", Ap, XX, XX }, ++ { "(bad)", XX, XX, XX }, /* fwait */ ++ { "pushfT", XX, XX, XX }, ++ { "popfT", XX, XX, XX }, ++ { "sahf{|}", XX, XX, XX }, ++ { "lahf{|}", XX, XX, XX }, ++ /* a0 */ ++ { "movB", AL, Ob64, XX }, ++ { "movS", eAX, Ov64, XX }, ++ { "movB", Ob64, AL, XX }, ++ { "movS", Ov64, eAX, XX }, ++ { "movs{b||b|}", Yb, Xb, XX }, ++ { "movs{R||R|}", Yv, Xv, XX }, ++ { "cmps{b||b|}", Xb, Yb, XX }, ++ { "cmps{R||R|}", Xv, Yv, XX }, ++ /* a8 */ ++ { "testB", AL, Ib, XX }, ++ { "testS", eAX, Iv, XX }, ++ { "stosB", Yb, AL, XX }, ++ { "stosS", Yv, eAX, XX }, ++ { "lodsB", AL, Xb, XX }, ++ { "lodsS", eAX, Xv, XX }, ++ { "scasB", AL, Yb, XX }, ++ { "scasS", eAX, Yv, XX }, ++ /* b0 */ ++ { "movB", RMAL, Ib, XX }, ++ { "movB", RMCL, Ib, XX }, ++ { "movB", RMDL, Ib, XX }, ++ { "movB", RMBL, Ib, XX }, ++ { "movB", RMAH, Ib, XX }, ++ { "movB", RMCH, Ib, XX }, ++ { "movB", RMDH, Ib, XX }, ++ { "movB", RMBH, Ib, XX }, ++ /* b8 */ ++ { "movS", RMeAX, Iv64, XX }, ++ { "movS", RMeCX, Iv64, XX }, ++ { "movS", RMeDX, Iv64, XX }, ++ { "movS", RMeBX, Iv64, XX }, ++ { "movS", RMeSP, Iv64, XX }, ++ { "movS", RMeBP, Iv64, XX }, ++ { "movS", RMeSI, Iv64, XX }, ++ { "movS", RMeDI, Iv64, XX }, ++ /* c0 */ ++ { GRP2b }, ++ { GRP2S }, ++ { "retT", Iw, XX, XX }, ++ { "retT", XX, XX, XX }, ++ { "les{S|}", Gv, Mp, XX }, ++ { "ldsS", Gv, Mp, XX }, ++ { "movA", Eb, Ib, XX }, ++ { "movQ", Ev, Iv, XX }, ++ /* c8 */ ++ { "enterT", Iw, Ib, XX }, ++ { "leaveT", XX, XX, XX }, ++ { "lretP", Iw, XX, XX }, ++ { "lretP", XX, XX, XX }, ++ { "int3", XX, XX, XX }, ++ { "int", Ib, XX, XX }, ++ { "into{|}", XX, XX, XX }, ++ { "iretP", XX, XX, XX }, ++ /* d0 */ ++ { GRP2b_one }, ++ { GRP2S_one }, ++ { GRP2b_cl }, ++ { GRP2S_cl }, ++ { "aam{|}", sIb, XX, XX }, ++ { "aad{|}", sIb, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "xlat", DSBX, XX, XX }, ++ /* d8 */ ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ { FLOAT }, ++ /* e0 */ ++ { "loopneFH", Jb, XX, loop_jcxz_flag }, ++ { "loopeFH", Jb, XX, loop_jcxz_flag }, ++ { "loopFH", Jb, XX, loop_jcxz_flag }, ++ { "jEcxzH", Jb, XX, loop_jcxz_flag }, ++ { "inB", AL, Ib, XX }, ++ { "inS", eAX, Ib, XX }, ++ { "outB", Ib, AL, XX }, ++ { "outS", Ib, eAX, XX }, ++ /* e8 */ ++ { "callT", Jv, XX, XX }, ++ { "jmpT", Jv, XX, XX }, ++ { "Jjmp{T|}", Ap, XX, XX }, ++ { "jmp", Jb, XX, XX }, ++ { "inB", AL, indirDX, XX }, ++ { "inS", eAX, indirDX, XX }, ++ { "outB", indirDX, AL, XX }, ++ { "outS", indirDX, eAX, XX }, ++ /* f0 */ ++ { "(bad)", XX, XX, XX }, /* lock prefix */ ++ { "icebp", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, /* repne */ ++ { "(bad)", XX, XX, XX }, /* repz */ ++ { "hlt", XX, XX, XX }, ++ { "cmc", XX, XX, XX }, ++ { GRP3b }, ++ { GRP3S }, ++ /* f8 */ ++ { "clc", XX, XX, XX }, ++ { "stc", XX, XX, XX }, ++ { "cli", XX, XX, XX }, ++ { "sti", XX, XX, XX }, ++ { "cld", XX, XX, XX }, ++ { "std", XX, XX, XX }, ++ { GRP4 }, ++ { GRP5 }, ++}; ++ ++static const struct dis386 dis386_twobyte[] = { ++ /* 00 */ ++ { GRP6 }, ++ { GRP7 }, ++ { "larS", Gv, Ew, XX }, ++ { "lslS", Gv, Ew, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "syscall", XX, XX, XX }, ++ { "clts", XX, XX, XX }, ++ { "sysretP", XX, XX, XX }, ++ /* 08 */ ++ { "invd", XX, XX, XX }, ++ { "wbinvd", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "ud2a", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { GRPAMD }, ++ { "femms", XX, XX, XX }, ++ { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix. */ ++ /* 10 */ ++ { PREGRP8 }, ++ { PREGRP9 }, ++ { PREGRP30 }, ++ { "movlpX", EX, XM, SIMD_Fixup, 'h' }, ++ { "unpcklpX", XM, EX, XX }, ++ { "unpckhpX", XM, EX, XX }, ++ { PREGRP31 }, ++ { "movhpX", EX, XM, SIMD_Fixup, 'l' }, ++ /* 18 */ ++ { GRP14 }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 20 */ ++ { "movL", Rm, Cm, XX }, ++ { "movL", Rm, Dm, XX }, ++ { "movL", Cm, Rm, XX }, ++ { "movL", Dm, Rm, XX }, ++ { "movL", Rd, Td, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "movL", Td, Rd, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 28 */ ++ { "movapX", XM, EX, XX }, ++ { "movapX", EX, XM, XX }, ++ { PREGRP2 }, ++ { "movntpX", Ev, XM, XX }, ++ { PREGRP4 }, ++ { PREGRP3 }, ++ { "ucomisX", XM,EX, XX }, ++ { "comisX", XM,EX, XX }, ++ /* 30 */ ++ { "wrmsr", XX, XX, XX }, ++ { "rdtsc", XX, XX, XX }, ++ { "rdmsr", XX, XX, XX }, ++ { "rdpmc", XX, XX, XX }, ++ { "sysenter", XX, XX, XX }, ++ { "sysexit", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 38 */ ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ /* 40 */ ++ { "cmovo", Gv, Ev, XX }, ++ { "cmovno", Gv, Ev, XX }, ++ { "cmovb", Gv, Ev, XX }, ++ { "cmovae", Gv, Ev, XX }, ++ { "cmove", Gv, Ev, XX }, ++ { "cmovne", Gv, Ev, XX }, ++ { "cmovbe", Gv, Ev, XX }, ++ { "cmova", Gv, Ev, XX }, ++ /* 48 */ ++ { "cmovs", Gv, Ev, XX }, ++ { "cmovns", Gv, Ev, XX }, ++ { "cmovp", Gv, Ev, XX }, ++ { "cmovnp", Gv, Ev, XX }, ++ { "cmovl", Gv, Ev, XX }, ++ { "cmovge", Gv, Ev, XX }, ++ { "cmovle", Gv, Ev, XX }, ++ { "cmovg", Gv, Ev, XX }, ++ /* 50 */ ++ { "movmskpX", Gdq, XS, XX }, ++ { PREGRP13 }, ++ { PREGRP12 }, ++ { PREGRP11 }, ++ { "andpX", XM, EX, XX }, ++ { "andnpX", XM, EX, XX }, ++ { "orpX", XM, EX, XX }, ++ { "xorpX", XM, EX, XX }, ++ /* 58 */ ++ { PREGRP0 }, ++ { PREGRP10 }, ++ { PREGRP17 }, ++ { PREGRP16 }, ++ { PREGRP14 }, ++ { PREGRP7 }, ++ { PREGRP5 }, ++ { PREGRP6 }, ++ /* 60 */ ++ { "punpcklbw", MX, EM, XX }, ++ { "punpcklwd", MX, EM, XX }, ++ { "punpckldq", MX, EM, XX }, ++ { "packsswb", MX, EM, XX }, ++ { "pcmpgtb", MX, EM, XX }, ++ { "pcmpgtw", MX, EM, XX }, ++ { "pcmpgtd", MX, EM, XX }, ++ { "packuswb", MX, EM, XX }, ++ /* 68 */ ++ { "punpckhbw", MX, EM, XX }, ++ { "punpckhwd", MX, EM, XX }, ++ { "punpckhdq", MX, EM, XX }, ++ { "packssdw", MX, EM, XX }, ++ { PREGRP26 }, ++ { PREGRP24 }, ++ { "movd", MX, Edq, XX }, ++ { PREGRP19 }, ++ /* 70 */ ++ { PREGRP22 }, ++ { GRP10 }, ++ { GRP11 }, ++ { GRP12 }, ++ { "pcmpeqb", MX, EM, XX }, ++ { "pcmpeqw", MX, EM, XX }, ++ { "pcmpeqd", MX, EM, XX }, ++ { "emms", XX, XX, XX }, ++ /* 78 */ ++ { "vmread", Em, Gm, XX }, ++ { "vmwrite", Gm, Em, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { PREGRP28 }, ++ { PREGRP29 }, ++ { PREGRP23 }, ++ { PREGRP20 }, ++ /* 80 */ ++ { "joH", Jv, XX, cond_jump_flag }, ++ { "jnoH", Jv, XX, cond_jump_flag }, ++ { "jbH", Jv, XX, cond_jump_flag }, ++ { "jaeH", Jv, XX, cond_jump_flag }, ++ { "jeH", Jv, XX, cond_jump_flag }, ++ { "jneH", Jv, XX, cond_jump_flag }, ++ { "jbeH", Jv, XX, cond_jump_flag }, ++ { "jaH", Jv, XX, cond_jump_flag }, ++ /* 88 */ ++ { "jsH", Jv, XX, cond_jump_flag }, ++ { "jnsH", Jv, XX, cond_jump_flag }, ++ { "jpH", Jv, XX, cond_jump_flag }, ++ { "jnpH", Jv, XX, cond_jump_flag }, ++ { "jlH", Jv, XX, cond_jump_flag }, ++ { "jgeH", Jv, XX, cond_jump_flag }, ++ { "jleH", Jv, XX, cond_jump_flag }, ++ { "jgH", Jv, XX, cond_jump_flag }, ++ /* 90 */ ++ { "seto", Eb, XX, XX }, ++ { "setno", Eb, XX, XX }, ++ { "setb", Eb, XX, XX }, ++ { "setae", Eb, XX, XX }, ++ { "sete", Eb, XX, XX }, ++ { "setne", Eb, XX, XX }, ++ { "setbe", Eb, XX, XX }, ++ { "seta", Eb, XX, XX }, ++ /* 98 */ ++ { "sets", Eb, XX, XX }, ++ { "setns", Eb, XX, XX }, ++ { "setp", Eb, XX, XX }, ++ { "setnp", Eb, XX, XX }, ++ { "setl", Eb, XX, XX }, ++ { "setge", Eb, XX, XX }, ++ { "setle", Eb, XX, XX }, ++ { "setg", Eb, XX, XX }, ++ /* a0 */ ++ { "pushT", fs, XX, XX }, ++ { "popT", fs, XX, XX }, ++ { "cpuid", XX, XX, XX }, ++ { "btS", Ev, Gv, XX }, ++ { "shldS", Ev, Gv, Ib }, ++ { "shldS", Ev, Gv, CL }, ++ { GRPPADLCK2 }, ++ { GRPPADLCK1 }, ++ /* a8 */ ++ { "pushT", gs, XX, XX }, ++ { "popT", gs, XX, XX }, ++ { "rsm", XX, XX, XX }, ++ { "btsS", Ev, Gv, XX }, ++ { "shrdS", Ev, Gv, Ib }, ++ { "shrdS", Ev, Gv, CL }, ++ { GRP13 }, ++ { "imulS", Gv, Ev, XX }, ++ /* b0 */ ++ { "cmpxchgB", Eb, Gb, XX }, ++ { "cmpxchgS", Ev, Gv, XX }, ++ { "lssS", Gv, Mp, XX }, ++ { "btrS", Ev, Gv, XX }, ++ { "lfsS", Gv, Mp, XX }, ++ { "lgsS", Gv, Mp, XX }, ++ { "movz{bR|x|bR|x}", Gv, Eb, XX }, ++ { "movz{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movzww ! */ ++ /* b8 */ ++ { "(bad)", XX, XX, XX }, ++ { "ud2b", XX, XX, XX }, ++ { GRP8 }, ++ { "btcS", Ev, Gv, XX }, ++ { "bsfS", Gv, Ev, XX }, ++ { "bsrS", Gv, Ev, XX }, ++ { "movs{bR|x|bR|x}", Gv, Eb, XX }, ++ { "movs{wR|x|wR|x}", Gv, Ew, XX }, /* yes, there really is movsww ! */ ++ /* c0 */ ++ { "xaddB", Eb, Gb, XX }, ++ { "xaddS", Ev, Gv, XX }, ++ { PREGRP1 }, ++ { "movntiS", Ev, Gv, XX }, ++ { "pinsrw", MX, Edqw, Ib }, ++ { "pextrw", Gdq, MS, Ib }, ++ { "shufpX", XM, EX, Ib }, ++ { GRP9 }, ++ /* c8 */ ++ { "bswap", RMeAX, XX, XX }, ++ { "bswap", RMeCX, XX, XX }, ++ { "bswap", RMeDX, XX, XX }, ++ { "bswap", RMeBX, XX, XX }, ++ { "bswap", RMeSP, XX, XX }, ++ { "bswap", RMeBP, XX, XX }, ++ { "bswap", RMeSI, XX, XX }, ++ { "bswap", RMeDI, XX, XX }, ++ /* d0 */ ++ { PREGRP27 }, ++ { "psrlw", MX, EM, XX }, ++ { "psrld", MX, EM, XX }, ++ { "psrlq", MX, EM, XX }, ++ { "paddq", MX, EM, XX }, ++ { "pmullw", MX, EM, XX }, ++ { PREGRP21 }, ++ { "pmovmskb", Gdq, MS, XX }, ++ /* d8 */ ++ { "psubusb", MX, EM, XX }, ++ { "psubusw", MX, EM, XX }, ++ { "pminub", MX, EM, XX }, ++ { "pand", MX, EM, XX }, ++ { "paddusb", MX, EM, XX }, ++ { "paddusw", MX, EM, XX }, ++ { "pmaxub", MX, EM, XX }, ++ { "pandn", MX, EM, XX }, ++ /* e0 */ ++ { "pavgb", MX, EM, XX }, ++ { "psraw", MX, EM, XX }, ++ { "psrad", MX, EM, XX }, ++ { "pavgw", MX, EM, XX }, ++ { "pmulhuw", MX, EM, XX }, ++ { "pmulhw", MX, EM, XX }, ++ { PREGRP15 }, ++ { PREGRP25 }, ++ /* e8 */ ++ { "psubsb", MX, EM, XX }, ++ { "psubsw", MX, EM, XX }, ++ { "pminsw", MX, EM, XX }, ++ { "por", MX, EM, XX }, ++ { "paddsb", MX, EM, XX }, ++ { "paddsw", MX, EM, XX }, ++ { "pmaxsw", MX, EM, XX }, ++ { "pxor", MX, EM, XX }, ++ /* f0 */ ++ { PREGRP32 }, ++ { "psllw", MX, EM, XX }, ++ { "pslld", MX, EM, XX }, ++ { "psllq", MX, EM, XX }, ++ { "pmuludq", MX, EM, XX }, ++ { "pmaddwd", MX, EM, XX }, ++ { "psadbw", MX, EM, XX }, ++ { PREGRP18 }, ++ /* f8 */ ++ { "psubb", MX, EM, XX }, ++ { "psubw", MX, EM, XX }, ++ { "psubd", MX, EM, XX }, ++ { "psubq", MX, EM, XX }, ++ { "paddb", MX, EM, XX }, ++ { "paddw", MX, EM, XX }, ++ { "paddd", MX, EM, XX }, ++ { "(bad)", XX, XX, XX } ++}; ++ ++static const unsigned char onebyte_has_modrm[256] = { ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++ /* ------------------------------- */ ++ /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ ++ /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ ++ /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ ++ /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ ++ /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ ++ /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ ++ /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ ++ /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ ++ /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ ++ /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ ++ /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ ++ /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ ++ /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ ++ /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ ++ /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ ++ /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ ++ /* ------------------------------- */ ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++}; ++ ++static const unsigned char twobyte_has_modrm[256] = { ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++ /* ------------------------------- */ ++ /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ ++ /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ ++ /* 20 */ 1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1, /* 2f */ ++ /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ ++ /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ ++ /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ ++ /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ ++ /* 70 */ 1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1, /* 7f */ ++ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ ++ /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ ++ /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ ++ /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ ++ /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ ++ /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ ++ /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ ++ /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ ++ /* ------------------------------- */ ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++}; ++ ++static const unsigned char twobyte_uses_SSE_prefix[256] = { ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++ /* ------------------------------- */ ++ /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ ++ /* 10 */ 1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0, /* 1f */ ++ /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ ++ /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ ++ /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ ++ /* 50 */ 0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* 5f */ ++ /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1, /* 6f */ ++ /* 70 */ 1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1, /* 7f */ ++ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ ++ /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ ++ /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ ++ /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ ++ /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ ++ /* d0 */ 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* df */ ++ /* e0 */ 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, /* ef */ ++ /* f0 */ 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 /* ff */ ++ /* ------------------------------- */ ++ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ ++}; ++ ++static char obuf[100]; ++static char *obufp; ++static char scratchbuf[100]; ++static unsigned char *start_codep; ++static unsigned char *insn_codep; ++static unsigned char *codep; ++static disassemble_info *the_info; ++static int mod; ++static int rm; ++static int reg; ++static unsigned char need_modrm; ++ ++/* If we are accessing mod/rm/reg without need_modrm set, then the ++ values are stale. Hitting this abort likely indicates that you ++ need to update onebyte_has_modrm or twobyte_has_modrm. */ ++#define MODRM_CHECK if (!need_modrm) abort () ++ ++static const char **names64; ++static const char **names32; ++static const char **names16; ++static const char **names8; ++static const char **names8rex; ++static const char **names_seg; ++static const char **index16; ++ ++static const char *intel_names64[] = { ++ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", ++ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" ++}; ++static const char *intel_names32[] = { ++ "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", ++ "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" ++}; ++static const char *intel_names16[] = { ++ "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", ++ "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" ++}; ++static const char *intel_names8[] = { ++ "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", ++}; ++static const char *intel_names8rex[] = { ++ "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", ++ "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" ++}; ++static const char *intel_names_seg[] = { ++ "es", "cs", "ss", "ds", "fs", "gs", "?", "?", ++}; ++static const char *intel_index16[] = { ++ "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" ++}; ++ ++static const char *att_names64[] = { ++ "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi", ++ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" ++}; ++static const char *att_names32[] = { ++ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", ++ "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d" ++}; ++static const char *att_names16[] = { ++ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di", ++ "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w" ++}; ++static const char *att_names8[] = { ++ "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh", ++}; ++static const char *att_names8rex[] = { ++ "%al", "%cl", "%dl", "%bl", "%spl", "%bpl", "%sil", "%dil", ++ "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b" ++}; ++static const char *att_names_seg[] = { ++ "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "%?", "%?", ++}; ++static const char *att_index16[] = { ++ "%bx,%si", "%bx,%di", "%bp,%si", "%bp,%di", "%si", "%di", "%bp", "%bx" ++}; ++ ++static const struct dis386 grps[][8] = { ++ /* GRP1b */ ++ { ++ { "addA", Eb, Ib, XX }, ++ { "orA", Eb, Ib, XX }, ++ { "adcA", Eb, Ib, XX }, ++ { "sbbA", Eb, Ib, XX }, ++ { "andA", Eb, Ib, XX }, ++ { "subA", Eb, Ib, XX }, ++ { "xorA", Eb, Ib, XX }, ++ { "cmpA", Eb, Ib, XX } ++ }, ++ /* GRP1S */ ++ { ++ { "addQ", Ev, Iv, XX }, ++ { "orQ", Ev, Iv, XX }, ++ { "adcQ", Ev, Iv, XX }, ++ { "sbbQ", Ev, Iv, XX }, ++ { "andQ", Ev, Iv, XX }, ++ { "subQ", Ev, Iv, XX }, ++ { "xorQ", Ev, Iv, XX }, ++ { "cmpQ", Ev, Iv, XX } ++ }, ++ /* GRP1Ss */ ++ { ++ { "addQ", Ev, sIb, XX }, ++ { "orQ", Ev, sIb, XX }, ++ { "adcQ", Ev, sIb, XX }, ++ { "sbbQ", Ev, sIb, XX }, ++ { "andQ", Ev, sIb, XX }, ++ { "subQ", Ev, sIb, XX }, ++ { "xorQ", Ev, sIb, XX }, ++ { "cmpQ", Ev, sIb, XX } ++ }, ++ /* GRP2b */ ++ { ++ { "rolA", Eb, Ib, XX }, ++ { "rorA", Eb, Ib, XX }, ++ { "rclA", Eb, Ib, XX }, ++ { "rcrA", Eb, Ib, XX }, ++ { "shlA", Eb, Ib, XX }, ++ { "shrA", Eb, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarA", Eb, Ib, XX }, ++ }, ++ /* GRP2S */ ++ { ++ { "rolQ", Ev, Ib, XX }, ++ { "rorQ", Ev, Ib, XX }, ++ { "rclQ", Ev, Ib, XX }, ++ { "rcrQ", Ev, Ib, XX }, ++ { "shlQ", Ev, Ib, XX }, ++ { "shrQ", Ev, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarQ", Ev, Ib, XX }, ++ }, ++ /* GRP2b_one */ ++ { ++ { "rolA", Eb, I1, XX }, ++ { "rorA", Eb, I1, XX }, ++ { "rclA", Eb, I1, XX }, ++ { "rcrA", Eb, I1, XX }, ++ { "shlA", Eb, I1, XX }, ++ { "shrA", Eb, I1, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarA", Eb, I1, XX }, ++ }, ++ /* GRP2S_one */ ++ { ++ { "rolQ", Ev, I1, XX }, ++ { "rorQ", Ev, I1, XX }, ++ { "rclQ", Ev, I1, XX }, ++ { "rcrQ", Ev, I1, XX }, ++ { "shlQ", Ev, I1, XX }, ++ { "shrQ", Ev, I1, XX }, ++ { "(bad)", XX, XX, XX}, ++ { "sarQ", Ev, I1, XX }, ++ }, ++ /* GRP2b_cl */ ++ { ++ { "rolA", Eb, CL, XX }, ++ { "rorA", Eb, CL, XX }, ++ { "rclA", Eb, CL, XX }, ++ { "rcrA", Eb, CL, XX }, ++ { "shlA", Eb, CL, XX }, ++ { "shrA", Eb, CL, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarA", Eb, CL, XX }, ++ }, ++ /* GRP2S_cl */ ++ { ++ { "rolQ", Ev, CL, XX }, ++ { "rorQ", Ev, CL, XX }, ++ { "rclQ", Ev, CL, XX }, ++ { "rcrQ", Ev, CL, XX }, ++ { "shlQ", Ev, CL, XX }, ++ { "shrQ", Ev, CL, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "sarQ", Ev, CL, XX } ++ }, ++ /* GRP3b */ ++ { ++ { "testA", Eb, Ib, XX }, ++ { "(bad)", Eb, XX, XX }, ++ { "notA", Eb, XX, XX }, ++ { "negA", Eb, XX, XX }, ++ { "mulA", Eb, XX, XX }, /* Don't print the implicit %al register, */ ++ { "imulA", Eb, XX, XX }, /* to distinguish these opcodes from other */ ++ { "divA", Eb, XX, XX }, /* mul/imul opcodes. Do the same for div */ ++ { "idivA", Eb, XX, XX } /* and idiv for consistency. */ ++ }, ++ /* GRP3S */ ++ { ++ { "testQ", Ev, Iv, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "notQ", Ev, XX, XX }, ++ { "negQ", Ev, XX, XX }, ++ { "mulQ", Ev, XX, XX }, /* Don't print the implicit register. */ ++ { "imulQ", Ev, XX, XX }, ++ { "divQ", Ev, XX, XX }, ++ { "idivQ", Ev, XX, XX }, ++ }, ++ /* GRP4 */ ++ { ++ { "incA", Eb, XX, XX }, ++ { "decA", Eb, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP5 */ ++ { ++ { "incQ", Ev, XX, XX }, ++ { "decQ", Ev, XX, XX }, ++ { "callT", indirEv, XX, XX }, ++ { "JcallT", indirEp, XX, XX }, ++ { "jmpT", indirEv, XX, XX }, ++ { "JjmpT", indirEp, XX, XX }, ++ { "pushU", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP6 */ ++ { ++ { "sldtQ", Ev, XX, XX }, ++ { "strQ", Ev, XX, XX }, ++ { "lldt", Ew, XX, XX }, ++ { "ltr", Ew, XX, XX }, ++ { "verr", Ew, XX, XX }, ++ { "verw", Ew, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX } ++ }, ++ /* GRP7 */ ++ { ++ { "sgdtIQ", VMX_Fixup, 0, XX, XX }, ++ { "sidtIQ", PNI_Fixup, 0, XX, XX }, ++ { "lgdt{Q|Q||}", M, XX, XX }, ++ { "lidt{Q|Q||}", SVME_Fixup, 0, XX, XX }, ++ { "smswQ", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "lmsw", Ew, XX, XX }, ++ { "invlpg", INVLPG_Fixup, w_mode, XX, XX }, ++ }, ++ /* GRP8 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "btQ", Ev, Ib, XX }, ++ { "btsQ", Ev, Ib, XX }, ++ { "btrQ", Ev, Ib, XX }, ++ { "btcQ", Ev, Ib, XX }, ++ }, ++ /* GRP9 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "cmpxchg8b", Eq, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "", VM, XX, XX }, /* See OP_VMX. */ ++ { "vmptrst", Eq, XX, XX }, ++ }, ++ /* GRP10 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrlw", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psraw", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psllw", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP11 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrld", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrad", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "pslld", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRP12 */ ++ { ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psrlq", MS, Ib, XX }, ++ { "psrldq", MS, Ib, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "psllq", MS, Ib, XX }, ++ { "pslldq", MS, Ib, XX }, ++ }, ++ /* GRP13 */ ++ { ++ { "fxsave", Ev, XX, XX }, ++ { "fxrstor", Ev, XX, XX }, ++ { "ldmxcsr", Ev, XX, XX }, ++ { "stmxcsr", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "lfence", OP_0fae, 0, XX, XX }, ++ { "mfence", OP_0fae, 0, XX, XX }, ++ { "clflush", OP_0fae, 0, XX, XX }, ++ }, ++ /* GRP14 */ ++ { ++ { "prefetchnta", Ev, XX, XX }, ++ { "prefetcht0", Ev, XX, XX }, ++ { "prefetcht1", Ev, XX, XX }, ++ { "prefetcht2", Ev, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRPAMD */ ++ { ++ { "prefetch", Eb, XX, XX }, ++ { "prefetchw", Eb, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* GRPPADLCK1 */ ++ { ++ { "xstore-rng", OP_0f07, 0, XX, XX }, ++ { "xcrypt-ecb", OP_0f07, 0, XX, XX }, ++ { "xcrypt-cbc", OP_0f07, 0, XX, XX }, ++ { "xcrypt-ctr", OP_0f07, 0, XX, XX }, ++ { "xcrypt-cfb", OP_0f07, 0, XX, XX }, ++ { "xcrypt-ofb", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ }, ++ /* GRPPADLCK2 */ ++ { ++ { "montmul", OP_0f07, 0, XX, XX }, ++ { "xsha1", OP_0f07, 0, XX, XX }, ++ { "xsha256", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ { "(bad)", OP_0f07, 0, XX, XX }, ++ } ++}; ++ ++static const struct dis386 prefix_user_table[][4] = { ++ /* PREGRP0 */ ++ { ++ { "addps", XM, EX, XX }, ++ { "addss", XM, EX, XX }, ++ { "addpd", XM, EX, XX }, ++ { "addsd", XM, EX, XX }, ++ }, ++ /* PREGRP1 */ ++ { ++ { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX. */ ++ { "", XM, EX, OPSIMD }, ++ { "", XM, EX, OPSIMD }, ++ { "", XM, EX, OPSIMD }, ++ }, ++ /* PREGRP2 */ ++ { ++ { "cvtpi2ps", XM, EM, XX }, ++ { "cvtsi2ssY", XM, Ev, XX }, ++ { "cvtpi2pd", XM, EM, XX }, ++ { "cvtsi2sdY", XM, Ev, XX }, ++ }, ++ /* PREGRP3 */ ++ { ++ { "cvtps2pi", MX, EX, XX }, ++ { "cvtss2siY", Gv, EX, XX }, ++ { "cvtpd2pi", MX, EX, XX }, ++ { "cvtsd2siY", Gv, EX, XX }, ++ }, ++ /* PREGRP4 */ ++ { ++ { "cvttps2pi", MX, EX, XX }, ++ { "cvttss2siY", Gv, EX, XX }, ++ { "cvttpd2pi", MX, EX, XX }, ++ { "cvttsd2siY", Gv, EX, XX }, ++ }, ++ /* PREGRP5 */ ++ { ++ { "divps", XM, EX, XX }, ++ { "divss", XM, EX, XX }, ++ { "divpd", XM, EX, XX }, ++ { "divsd", XM, EX, XX }, ++ }, ++ /* PREGRP6 */ ++ { ++ { "maxps", XM, EX, XX }, ++ { "maxss", XM, EX, XX }, ++ { "maxpd", XM, EX, XX }, ++ { "maxsd", XM, EX, XX }, ++ }, ++ /* PREGRP7 */ ++ { ++ { "minps", XM, EX, XX }, ++ { "minss", XM, EX, XX }, ++ { "minpd", XM, EX, XX }, ++ { "minsd", XM, EX, XX }, ++ }, ++ /* PREGRP8 */ ++ { ++ { "movups", XM, EX, XX }, ++ { "movss", XM, EX, XX }, ++ { "movupd", XM, EX, XX }, ++ { "movsd", XM, EX, XX }, ++ }, ++ /* PREGRP9 */ ++ { ++ { "movups", EX, XM, XX }, ++ { "movss", EX, XM, XX }, ++ { "movupd", EX, XM, XX }, ++ { "movsd", EX, XM, XX }, ++ }, ++ /* PREGRP10 */ ++ { ++ { "mulps", XM, EX, XX }, ++ { "mulss", XM, EX, XX }, ++ { "mulpd", XM, EX, XX }, ++ { "mulsd", XM, EX, XX }, ++ }, ++ /* PREGRP11 */ ++ { ++ { "rcpps", XM, EX, XX }, ++ { "rcpss", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP12 */ ++ { ++ { "rsqrtps", XM, EX, XX }, ++ { "rsqrtss", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP13 */ ++ { ++ { "sqrtps", XM, EX, XX }, ++ { "sqrtss", XM, EX, XX }, ++ { "sqrtpd", XM, EX, XX }, ++ { "sqrtsd", XM, EX, XX }, ++ }, ++ /* PREGRP14 */ ++ { ++ { "subps", XM, EX, XX }, ++ { "subss", XM, EX, XX }, ++ { "subpd", XM, EX, XX }, ++ { "subsd", XM, EX, XX }, ++ }, ++ /* PREGRP15 */ ++ { ++ { "(bad)", XM, EX, XX }, ++ { "cvtdq2pd", XM, EX, XX }, ++ { "cvttpd2dq", XM, EX, XX }, ++ { "cvtpd2dq", XM, EX, XX }, ++ }, ++ /* PREGRP16 */ ++ { ++ { "cvtdq2ps", XM, EX, XX }, ++ { "cvttps2dq",XM, EX, XX }, ++ { "cvtps2dq",XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP17 */ ++ { ++ { "cvtps2pd", XM, EX, XX }, ++ { "cvtss2sd", XM, EX, XX }, ++ { "cvtpd2ps", XM, EX, XX }, ++ { "cvtsd2ss", XM, EX, XX }, ++ }, ++ /* PREGRP18 */ ++ { ++ { "maskmovq", MX, MS, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "maskmovdqu", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP19 */ ++ { ++ { "movq", MX, EM, XX }, ++ { "movdqu", XM, EX, XX }, ++ { "movdqa", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP20 */ ++ { ++ { "movq", EM, MX, XX }, ++ { "movdqu", EX, XM, XX }, ++ { "movdqa", EX, XM, XX }, ++ { "(bad)", EX, XM, XX }, ++ }, ++ /* PREGRP21 */ ++ { ++ { "(bad)", EX, XM, XX }, ++ { "movq2dq", XM, MS, XX }, ++ { "movq", EX, XM, XX }, ++ { "movdq2q", MX, XS, XX }, ++ }, ++ /* PREGRP22 */ ++ { ++ { "pshufw", MX, EM, Ib }, ++ { "pshufhw", XM, EX, Ib }, ++ { "pshufd", XM, EX, Ib }, ++ { "pshuflw", XM, EX, Ib }, ++ }, ++ /* PREGRP23 */ ++ { ++ { "movd", Edq, MX, XX }, ++ { "movq", XM, EX, XX }, ++ { "movd", Edq, XM, XX }, ++ { "(bad)", Ed, XM, XX }, ++ }, ++ /* PREGRP24 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "punpckhqdq", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP25 */ ++ { ++ { "movntq", EM, MX, XX }, ++ { "(bad)", EM, XM, XX }, ++ { "movntdq", EM, XM, XX }, ++ { "(bad)", EM, XM, XX }, ++ }, ++ /* PREGRP26 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "punpcklqdq", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP27 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "addsubpd", XM, EX, XX }, ++ { "addsubps", XM, EX, XX }, ++ }, ++ /* PREGRP28 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "haddpd", XM, EX, XX }, ++ { "haddps", XM, EX, XX }, ++ }, ++ /* PREGRP29 */ ++ { ++ { "(bad)", MX, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "hsubpd", XM, EX, XX }, ++ { "hsubps", XM, EX, XX }, ++ }, ++ /* PREGRP30 */ ++ { ++ { "movlpX", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ ++ { "movsldup", XM, EX, XX }, ++ { "movlpd", XM, EX, XX }, ++ { "movddup", XM, EX, XX }, ++ }, ++ /* PREGRP31 */ ++ { ++ { "movhpX", XM, EX, SIMD_Fixup, 'l' }, ++ { "movshdup", XM, EX, XX }, ++ { "movhpd", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ }, ++ /* PREGRP32 */ ++ { ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "(bad)", XM, EX, XX }, ++ { "lddqu", XM, M, XX }, ++ }, ++}; ++ ++static const struct dis386 x86_64_table[][2] = { ++ { ++ { "arpl", Ew, Gw, XX }, ++ { "movs{||lq|xd}", Gv, Ed, XX }, ++ }, ++}; ++ ++#ifdef __KERNEL__ ++#define INTERNAL_DISASSEMBLER_ERROR "" ++#else /* __KERNEL__ */ ++#define INTERNAL_DISASSEMBLER_ERROR _("") ++#endif /* __KERNEL__ */ ++ ++static void ++ckprefix (void) ++{ ++ int newrex; ++ rex = 0; ++ prefixes = 0; ++ used_prefixes = 0; ++ rex_used = 0; ++ while (1) ++ { ++ FETCH_DATA (the_info, codep + 1); ++ newrex = 0; ++ switch (*codep) ++ { ++ /* REX prefixes family. */ ++ case 0x40: ++ case 0x41: ++ case 0x42: ++ case 0x43: ++ case 0x44: ++ case 0x45: ++ case 0x46: ++ case 0x47: ++ case 0x48: ++ case 0x49: ++ case 0x4a: ++ case 0x4b: ++ case 0x4c: ++ case 0x4d: ++ case 0x4e: ++ case 0x4f: ++ if (mode_64bit) ++ newrex = *codep; ++ else ++ return; ++ break; ++ case 0xf3: ++ prefixes |= PREFIX_REPZ; ++ break; ++ case 0xf2: ++ prefixes |= PREFIX_REPNZ; ++ break; ++ case 0xf0: ++ prefixes |= PREFIX_LOCK; ++ break; ++ case 0x2e: ++ prefixes |= PREFIX_CS; ++ break; ++ case 0x36: ++ prefixes |= PREFIX_SS; ++ break; ++ case 0x3e: ++ prefixes |= PREFIX_DS; ++ break; ++ case 0x26: ++ prefixes |= PREFIX_ES; ++ break; ++ case 0x64: ++ prefixes |= PREFIX_FS; ++ break; ++ case 0x65: ++ prefixes |= PREFIX_GS; ++ break; ++ case 0x66: ++ prefixes |= PREFIX_DATA; ++ break; ++ case 0x67: ++ prefixes |= PREFIX_ADDR; ++ break; ++ case FWAIT_OPCODE: ++ /* fwait is really an instruction. If there are prefixes ++ before the fwait, they belong to the fwait, *not* to the ++ following instruction. */ ++ if (prefixes) ++ { ++ prefixes |= PREFIX_FWAIT; ++ codep++; ++ return; ++ } ++ prefixes = PREFIX_FWAIT; ++ break; ++ default: ++ return; ++ } ++ /* Rex is ignored when followed by another prefix. */ ++ if (rex) ++ { ++ oappend (prefix_name (rex, 0)); ++ oappend (" "); ++ } ++ rex = newrex; ++ codep++; ++ } ++} ++ ++/* Return the name of the prefix byte PREF, or NULL if PREF is not a ++ prefix byte. */ ++ ++static const char * ++prefix_name (int pref, int sizeflag) ++{ ++ switch (pref) ++ { ++ /* REX prefixes family. */ ++ case 0x40: ++ return "rex"; ++ case 0x41: ++ return "rexZ"; ++ case 0x42: ++ return "rexY"; ++ case 0x43: ++ return "rexYZ"; ++ case 0x44: ++ return "rexX"; ++ case 0x45: ++ return "rexXZ"; ++ case 0x46: ++ return "rexXY"; ++ case 0x47: ++ return "rexXYZ"; ++ case 0x48: ++ return "rex64"; ++ case 0x49: ++ return "rex64Z"; ++ case 0x4a: ++ return "rex64Y"; ++ case 0x4b: ++ return "rex64YZ"; ++ case 0x4c: ++ return "rex64X"; ++ case 0x4d: ++ return "rex64XZ"; ++ case 0x4e: ++ return "rex64XY"; ++ case 0x4f: ++ return "rex64XYZ"; ++ case 0xf3: ++ return "repz"; ++ case 0xf2: ++ return "repnz"; ++ case 0xf0: ++ return "lock"; ++ case 0x2e: ++ return "cs"; ++ case 0x36: ++ return "ss"; ++ case 0x3e: ++ return "ds"; ++ case 0x26: ++ return "es"; ++ case 0x64: ++ return "fs"; ++ case 0x65: ++ return "gs"; ++ case 0x66: ++ return (sizeflag & DFLAG) ? "data16" : "data32"; ++ case 0x67: ++ if (mode_64bit) ++ return (sizeflag & AFLAG) ? "addr32" : "addr64"; ++ else ++ return (sizeflag & AFLAG) ? "addr16" : "addr32"; ++ case FWAIT_OPCODE: ++ return "fwait"; ++ default: ++ return NULL; ++ } ++} ++ ++static char op1out[100], op2out[100], op3out[100]; ++static int op_ad, op_index[3]; ++static int two_source_ops; ++static bfd_vma op_address[3]; ++static bfd_vma op_riprel[3]; ++static bfd_vma start_pc; ++ ++/* ++ * On the 386's of 1988, the maximum length of an instruction is 15 bytes. ++ * (see topic "Redundant prefixes" in the "Differences from 8086" ++ * section of the "Virtual 8086 Mode" chapter.) ++ * 'pc' should be the address of this instruction, it will ++ * be used to print the target address if this is a relative jump or call ++ * The function returns the length of this instruction in bytes. ++ */ ++ ++static char intel_syntax; ++static char open_char; ++static char close_char; ++static char separator_char; ++static char scale_char; ++ ++/* Here for backwards compatibility. When gdb stops using ++ print_insn_i386_att and print_insn_i386_intel these functions can ++ disappear, and print_insn_i386 be merged into print_insn. */ ++int ++print_insn_i386_att (bfd_vma pc, disassemble_info *info) ++{ ++ intel_syntax = 0; ++ ++ return print_insn (pc, info); ++} ++ ++int ++print_insn_i386_intel (bfd_vma pc, disassemble_info *info) ++{ ++ intel_syntax = 1; ++ ++ return print_insn (pc, info); ++} ++ ++int ++print_insn_i386 (bfd_vma pc, disassemble_info *info) ++{ ++ intel_syntax = -1; ++ ++ return print_insn (pc, info); ++} ++ ++static int ++print_insn (bfd_vma pc, disassemble_info *info) ++{ ++ const struct dis386 *dp; ++ int i; ++ char *first, *second, *third; ++ int needcomma; ++ unsigned char uses_SSE_prefix, uses_LOCK_prefix; ++ int sizeflag; ++ const char *p; ++ struct dis_private priv; ++ ++ mode_64bit = (info->mach == bfd_mach_x86_64_intel_syntax ++ || info->mach == bfd_mach_x86_64); ++ ++ if (intel_syntax == (char) -1) ++ intel_syntax = (info->mach == bfd_mach_i386_i386_intel_syntax ++ || info->mach == bfd_mach_x86_64_intel_syntax); ++ ++ if (info->mach == bfd_mach_i386_i386 ++ || info->mach == bfd_mach_x86_64 ++ || info->mach == bfd_mach_i386_i386_intel_syntax ++ || info->mach == bfd_mach_x86_64_intel_syntax) ++ priv.orig_sizeflag = AFLAG | DFLAG; ++ else if (info->mach == bfd_mach_i386_i8086) ++ priv.orig_sizeflag = 0; ++ else ++ abort (); ++ ++ for (p = info->disassembler_options; p != NULL; ) ++ { ++ if (strncmp (p, "x86-64", 6) == 0) ++ { ++ mode_64bit = 1; ++ priv.orig_sizeflag = AFLAG | DFLAG; ++ } ++ else if (strncmp (p, "i386", 4) == 0) ++ { ++ mode_64bit = 0; ++ priv.orig_sizeflag = AFLAG | DFLAG; ++ } ++ else if (strncmp (p, "i8086", 5) == 0) ++ { ++ mode_64bit = 0; ++ priv.orig_sizeflag = 0; ++ } ++ else if (strncmp (p, "intel", 5) == 0) ++ { ++ intel_syntax = 1; ++ } ++ else if (strncmp (p, "att", 3) == 0) ++ { ++ intel_syntax = 0; ++ } ++ else if (strncmp (p, "addr", 4) == 0) ++ { ++ if (p[4] == '1' && p[5] == '6') ++ priv.orig_sizeflag &= ~AFLAG; ++ else if (p[4] == '3' && p[5] == '2') ++ priv.orig_sizeflag |= AFLAG; ++ } ++ else if (strncmp (p, "data", 4) == 0) ++ { ++ if (p[4] == '1' && p[5] == '6') ++ priv.orig_sizeflag &= ~DFLAG; ++ else if (p[4] == '3' && p[5] == '2') ++ priv.orig_sizeflag |= DFLAG; ++ } ++ else if (strncmp (p, "suffix", 6) == 0) ++ priv.orig_sizeflag |= SUFFIX_ALWAYS; ++ ++ p = strchr (p, ','); ++ if (p != NULL) ++ p++; ++ } ++ ++ if (intel_syntax) ++ { ++ names64 = intel_names64; ++ names32 = intel_names32; ++ names16 = intel_names16; ++ names8 = intel_names8; ++ names8rex = intel_names8rex; ++ names_seg = intel_names_seg; ++ index16 = intel_index16; ++ open_char = '['; ++ close_char = ']'; ++ separator_char = '+'; ++ scale_char = '*'; ++ } ++ else ++ { ++ names64 = att_names64; ++ names32 = att_names32; ++ names16 = att_names16; ++ names8 = att_names8; ++ names8rex = att_names8rex; ++ names_seg = att_names_seg; ++ index16 = att_index16; ++ open_char = '('; ++ close_char = ')'; ++ separator_char = ','; ++ scale_char = ','; ++ } ++ ++ /* The output looks better if we put 7 bytes on a line, since that ++ puts most long word instructions on a single line. */ ++ info->bytes_per_line = 7; ++ ++ info->private_data = &priv; ++ priv.max_fetched = priv.the_buffer; ++ priv.insn_start = pc; ++ ++ obuf[0] = 0; ++ op1out[0] = 0; ++ op2out[0] = 0; ++ op3out[0] = 0; ++ ++ op_index[0] = op_index[1] = op_index[2] = -1; ++ ++ the_info = info; ++ start_pc = pc; ++ start_codep = priv.the_buffer; ++ codep = priv.the_buffer; ++ ++#ifndef __KERNEL__ ++ if (setjmp (priv.bailout) != 0) ++ { ++ const char *name; ++ ++ /* Getting here means we tried for data but didn't get it. That ++ means we have an incomplete instruction of some sort. Just ++ print the first byte as a prefix or a .byte pseudo-op. */ ++ if (codep > priv.the_buffer) ++ { ++ name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); ++ if (name != NULL) ++ (*info->fprintf_func) (info->stream, "%s", name); ++ else ++ { ++ /* Just print the first byte as a .byte instruction. */ ++ (*info->fprintf_func) (info->stream, ".byte 0x%x", ++ (unsigned int) priv.the_buffer[0]); ++ } ++ ++ return 1; ++ } ++ ++ return -1; ++ } ++#endif /* __KERNEL__ */ ++ ++ obufp = obuf; ++ ckprefix (); ++ ++ insn_codep = codep; ++ sizeflag = priv.orig_sizeflag; ++ ++ FETCH_DATA (info, codep + 1); ++ two_source_ops = (*codep == 0x62) || (*codep == 0xc8); ++ ++ if ((prefixes & PREFIX_FWAIT) ++ && ((*codep < 0xd8) || (*codep > 0xdf))) ++ { ++ const char *name; ++ ++ /* fwait not followed by floating point instruction. Print the ++ first prefix, which is probably fwait itself. */ ++ name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); ++ if (name == NULL) ++ name = INTERNAL_DISASSEMBLER_ERROR; ++ (*info->fprintf_func) (info->stream, "%s", name); ++ return 1; ++ } ++ ++ if (*codep == 0x0f) ++ { ++ FETCH_DATA (info, codep + 2); ++ dp = &dis386_twobyte[*++codep]; ++ need_modrm = twobyte_has_modrm[*codep]; ++ uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; ++ uses_LOCK_prefix = (*codep & ~0x02) == 0x20; ++ } ++ else ++ { ++ dp = &dis386[*codep]; ++ need_modrm = onebyte_has_modrm[*codep]; ++ uses_SSE_prefix = 0; ++ uses_LOCK_prefix = 0; ++ } ++ codep++; ++ ++ if (!uses_SSE_prefix && (prefixes & PREFIX_REPZ)) ++ { ++ oappend ("repz "); ++ used_prefixes |= PREFIX_REPZ; ++ } ++ if (!uses_SSE_prefix && (prefixes & PREFIX_REPNZ)) ++ { ++ oappend ("repnz "); ++ used_prefixes |= PREFIX_REPNZ; ++ } ++ if (!uses_LOCK_prefix && (prefixes & PREFIX_LOCK)) ++ { ++ oappend ("lock "); ++ used_prefixes |= PREFIX_LOCK; ++ } ++ ++ if (prefixes & PREFIX_ADDR) ++ { ++ sizeflag ^= AFLAG; ++ if (dp->bytemode3 != loop_jcxz_mode || intel_syntax) ++ { ++ if ((sizeflag & AFLAG) || mode_64bit) ++ oappend ("addr32 "); ++ else ++ oappend ("addr16 "); ++ used_prefixes |= PREFIX_ADDR; ++ } ++ } ++ ++ if (!uses_SSE_prefix && (prefixes & PREFIX_DATA)) ++ { ++ sizeflag ^= DFLAG; ++ if (dp->bytemode3 == cond_jump_mode ++ && dp->bytemode1 == v_mode ++ && !intel_syntax) ++ { ++ if (sizeflag & DFLAG) ++ oappend ("data32 "); ++ else ++ oappend ("data16 "); ++ used_prefixes |= PREFIX_DATA; ++ } ++ } ++ ++ if (need_modrm) ++ { ++ FETCH_DATA (info, codep + 1); ++ mod = (*codep >> 6) & 3; ++ reg = (*codep >> 3) & 7; ++ rm = *codep & 7; ++ } ++ ++ if (dp->name == NULL && dp->bytemode1 == FLOATCODE) ++ { ++ dofloat (sizeflag); ++ } ++ else ++ { ++ int index; ++ if (dp->name == NULL) ++ { ++ switch (dp->bytemode1) ++ { ++ case USE_GROUPS: ++ dp = &grps[dp->bytemode2][reg]; ++ break; ++ ++ case USE_PREFIX_USER_TABLE: ++ index = 0; ++ used_prefixes |= (prefixes & PREFIX_REPZ); ++ if (prefixes & PREFIX_REPZ) ++ index = 1; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ index = 2; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_REPNZ); ++ if (prefixes & PREFIX_REPNZ) ++ index = 3; ++ } ++ } ++ dp = &prefix_user_table[dp->bytemode2][index]; ++ break; ++ ++ case X86_64_SPECIAL: ++ dp = &x86_64_table[dp->bytemode2][mode_64bit]; ++ break; ++ ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ break; ++ } ++ } ++ ++ if (putop (dp->name, sizeflag) == 0) ++ { ++ obufp = op1out; ++ op_ad = 2; ++ if (dp->op1) ++ (*dp->op1) (dp->bytemode1, sizeflag); ++ ++ obufp = op2out; ++ op_ad = 1; ++ if (dp->op2) ++ (*dp->op2) (dp->bytemode2, sizeflag); ++ ++ obufp = op3out; ++ op_ad = 0; ++ if (dp->op3) ++ (*dp->op3) (dp->bytemode3, sizeflag); ++ } ++ } ++ ++ /* See if any prefixes were not used. If so, print the first one ++ separately. If we don't do this, we'll wind up printing an ++ instruction stream which does not precisely correspond to the ++ bytes we are disassembling. */ ++ if ((prefixes & ~used_prefixes) != 0) ++ { ++ const char *name; ++ ++ name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag); ++ if (name == NULL) ++ name = INTERNAL_DISASSEMBLER_ERROR; ++ (*info->fprintf_func) (info->stream, "%s", name); ++ return 1; ++ } ++ if (rex & ~rex_used) ++ { ++ const char *name; ++ name = prefix_name (rex | 0x40, priv.orig_sizeflag); ++ if (name == NULL) ++ name = INTERNAL_DISASSEMBLER_ERROR; ++ (*info->fprintf_func) (info->stream, "%s ", name); ++ } ++ ++ obufp = obuf + strlen (obuf); ++ for (i = strlen (obuf); i < 6; i++) ++ oappend (" "); ++ oappend (" "); ++ (*info->fprintf_func) (info->stream, "%s", obuf); ++ ++ /* The enter and bound instructions are printed with operands in the same ++ order as the intel book; everything else is printed in reverse order. */ ++ if (intel_syntax || two_source_ops) ++ { ++ first = op1out; ++ second = op2out; ++ third = op3out; ++ op_ad = op_index[0]; ++ op_index[0] = op_index[2]; ++ op_index[2] = op_ad; ++ } ++ else ++ { ++ first = op3out; ++ second = op2out; ++ third = op1out; ++ } ++ needcomma = 0; ++ if (*first) ++ { ++ if (op_index[0] != -1 && !op_riprel[0]) ++ (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); ++ else ++ (*info->fprintf_func) (info->stream, "%s", first); ++ needcomma = 1; ++ } ++ if (*second) ++ { ++ if (needcomma) ++ (*info->fprintf_func) (info->stream, ","); ++ if (op_index[1] != -1 && !op_riprel[1]) ++ (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); ++ else ++ (*info->fprintf_func) (info->stream, "%s", second); ++ needcomma = 1; ++ } ++ if (*third) ++ { ++ if (needcomma) ++ (*info->fprintf_func) (info->stream, ","); ++ if (op_index[2] != -1 && !op_riprel[2]) ++ (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); ++ else ++ (*info->fprintf_func) (info->stream, "%s", third); ++ } ++ for (i = 0; i < 3; i++) ++ if (op_index[i] != -1 && op_riprel[i]) ++ { ++ (*info->fprintf_func) (info->stream, " # "); ++ (*info->print_address_func) ((bfd_vma) (start_pc + codep - start_codep ++ + op_address[op_index[i]]), info); ++ } ++ return codep - priv.the_buffer; ++} ++ ++static const char *float_mem[] = { ++ /* d8 */ ++ "fadd{s||s|}", ++ "fmul{s||s|}", ++ "fcom{s||s|}", ++ "fcomp{s||s|}", ++ "fsub{s||s|}", ++ "fsubr{s||s|}", ++ "fdiv{s||s|}", ++ "fdivr{s||s|}", ++ /* d9 */ ++ "fld{s||s|}", ++ "(bad)", ++ "fst{s||s|}", ++ "fstp{s||s|}", ++ "fldenvIC", ++ "fldcw", ++ "fNstenvIC", ++ "fNstcw", ++ /* da */ ++ "fiadd{l||l|}", ++ "fimul{l||l|}", ++ "ficom{l||l|}", ++ "ficomp{l||l|}", ++ "fisub{l||l|}", ++ "fisubr{l||l|}", ++ "fidiv{l||l|}", ++ "fidivr{l||l|}", ++ /* db */ ++ "fild{l||l|}", ++ "fisttp{l||l|}", ++ "fist{l||l|}", ++ "fistp{l||l|}", ++ "(bad)", ++ "fld{t||t|}", ++ "(bad)", ++ "fstp{t||t|}", ++ /* dc */ ++ "fadd{l||l|}", ++ "fmul{l||l|}", ++ "fcom{l||l|}", ++ "fcomp{l||l|}", ++ "fsub{l||l|}", ++ "fsubr{l||l|}", ++ "fdiv{l||l|}", ++ "fdivr{l||l|}", ++ /* dd */ ++ "fld{l||l|}", ++ "fisttp{ll||ll|}", ++ "fst{l||l|}", ++ "fstp{l||l|}", ++ "frstorIC", ++ "(bad)", ++ "fNsaveIC", ++ "fNstsw", ++ /* de */ ++ "fiadd", ++ "fimul", ++ "ficom", ++ "ficomp", ++ "fisub", ++ "fisubr", ++ "fidiv", ++ "fidivr", ++ /* df */ ++ "fild", ++ "fisttp", ++ "fist", ++ "fistp", ++ "fbld", ++ "fild{ll||ll|}", ++ "fbstp", ++ "fistp{ll||ll|}", ++}; ++ ++static const unsigned char float_mem_mode[] = { ++ /* d8 */ ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ /* d9 */ ++ d_mode, ++ 0, ++ d_mode, ++ d_mode, ++ 0, ++ w_mode, ++ 0, ++ w_mode, ++ /* da */ ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ /* db */ ++ d_mode, ++ d_mode, ++ d_mode, ++ d_mode, ++ 0, ++ t_mode, ++ 0, ++ t_mode, ++ /* dc */ ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ /* dd */ ++ q_mode, ++ q_mode, ++ q_mode, ++ q_mode, ++ 0, ++ 0, ++ 0, ++ w_mode, ++ /* de */ ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ /* df */ ++ w_mode, ++ w_mode, ++ w_mode, ++ w_mode, ++ t_mode, ++ q_mode, ++ t_mode, ++ q_mode ++}; ++ ++#define ST OP_ST, 0 ++#define STi OP_STi, 0 ++ ++#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 ++#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 ++#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 ++#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 ++#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 ++#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 ++#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 ++#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 ++#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 ++ ++static const struct dis386 float_reg[][8] = { ++ /* d8 */ ++ { ++ { "fadd", ST, STi, XX }, ++ { "fmul", ST, STi, XX }, ++ { "fcom", STi, XX, XX }, ++ { "fcomp", STi, XX, XX }, ++ { "fsub", ST, STi, XX }, ++ { "fsubr", ST, STi, XX }, ++ { "fdiv", ST, STi, XX }, ++ { "fdivr", ST, STi, XX }, ++ }, ++ /* d9 */ ++ { ++ { "fld", STi, XX, XX }, ++ { "fxch", STi, XX, XX }, ++ { FGRPd9_2 }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPd9_4 }, ++ { FGRPd9_5 }, ++ { FGRPd9_6 }, ++ { FGRPd9_7 }, ++ }, ++ /* da */ ++ { ++ { "fcmovb", ST, STi, XX }, ++ { "fcmove", ST, STi, XX }, ++ { "fcmovbe",ST, STi, XX }, ++ { "fcmovu", ST, STi, XX }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPda_5 }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* db */ ++ { ++ { "fcmovnb",ST, STi, XX }, ++ { "fcmovne",ST, STi, XX }, ++ { "fcmovnbe",ST, STi, XX }, ++ { "fcmovnu",ST, STi, XX }, ++ { FGRPdb_4 }, ++ { "fucomi", ST, STi, XX }, ++ { "fcomi", ST, STi, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* dc */ ++ { ++ { "fadd", STi, ST, XX }, ++ { "fmul", STi, ST, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++#if UNIXWARE_COMPAT ++ { "fsub", STi, ST, XX }, ++ { "fsubr", STi, ST, XX }, ++ { "fdiv", STi, ST, XX }, ++ { "fdivr", STi, ST, XX }, ++#else ++ { "fsubr", STi, ST, XX }, ++ { "fsub", STi, ST, XX }, ++ { "fdivr", STi, ST, XX }, ++ { "fdiv", STi, ST, XX }, ++#endif ++ }, ++ /* dd */ ++ { ++ { "ffree", STi, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "fst", STi, XX, XX }, ++ { "fstp", STi, XX, XX }, ++ { "fucom", STi, XX, XX }, ++ { "fucomp", STi, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++ /* de */ ++ { ++ { "faddp", STi, ST, XX }, ++ { "fmulp", STi, ST, XX }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPde_3 }, ++#if UNIXWARE_COMPAT ++ { "fsubp", STi, ST, XX }, ++ { "fsubrp", STi, ST, XX }, ++ { "fdivp", STi, ST, XX }, ++ { "fdivrp", STi, ST, XX }, ++#else ++ { "fsubrp", STi, ST, XX }, ++ { "fsubp", STi, ST, XX }, ++ { "fdivrp", STi, ST, XX }, ++ { "fdivp", STi, ST, XX }, ++#endif ++ }, ++ /* df */ ++ { ++ { "ffreep", STi, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { "(bad)", XX, XX, XX }, ++ { FGRPdf_4 }, ++ { "fucomip",ST, STi, XX }, ++ { "fcomip", ST, STi, XX }, ++ { "(bad)", XX, XX, XX }, ++ }, ++}; ++ ++static char *fgrps[][8] = { ++ /* d9_2 0 */ ++ { ++ "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* d9_4 1 */ ++ { ++ "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", ++ }, ++ ++ /* d9_5 2 */ ++ { ++ "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", ++ }, ++ ++ /* d9_6 3 */ ++ { ++ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", ++ }, ++ ++ /* d9_7 4 */ ++ { ++ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", ++ }, ++ ++ /* da_5 5 */ ++ { ++ "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* db_4 6 */ ++ { ++ "feni(287 only)","fdisi(287 only)","fNclex","fNinit", ++ "fNsetpm(287 only)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* de_3 7 */ ++ { ++ "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++ ++ /* df_4 8 */ ++ { ++ "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", ++ }, ++}; ++ ++static void ++dofloat (int sizeflag) ++{ ++ const struct dis386 *dp; ++ unsigned char floatop; ++ ++ floatop = codep[-1]; ++ ++ if (mod != 3) ++ { ++ int fp_indx = (floatop - 0xd8) * 8 + reg; ++ ++ putop (float_mem[fp_indx], sizeflag); ++ obufp = op1out; ++ OP_E (float_mem_mode[fp_indx], sizeflag); ++ return; ++ } ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ ++ dp = &float_reg[floatop - 0xd8][reg]; ++ if (dp->name == NULL) ++ { ++ putop (fgrps[dp->bytemode1][rm], sizeflag); ++ ++ /* Instruction fnstsw is only one with strange arg. */ ++ if (floatop == 0xdf && codep[-1] == 0xe0) ++ strcpy (op1out, names16[0]); ++ } ++ else ++ { ++ putop (dp->name, sizeflag); ++ ++ obufp = op1out; ++ if (dp->op1) ++ (*dp->op1) (dp->bytemode1, sizeflag); ++ obufp = op2out; ++ if (dp->op2) ++ (*dp->op2) (dp->bytemode2, sizeflag); ++ } ++} ++ ++static void ++OP_ST (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ oappend ("%st"); ++} ++ ++static void ++OP_STi (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ sprintf (scratchbuf, "%%st(%d)", rm); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++/* Capital letters in template are macros. */ ++static int ++putop (const char *template, int sizeflag) ++{ ++ const char *p; ++ int alt = 0; ++ ++ for (p = template; *p; p++) ++ { ++ switch (*p) ++ { ++ default: ++ *obufp++ = *p; ++ break; ++ case '{': ++ alt = 0; ++ if (intel_syntax) ++ alt += 1; ++ if (mode_64bit) ++ alt += 2; ++ while (alt != 0) ++ { ++ while (*++p != '|') ++ { ++ if (*p == '}') ++ { ++ /* Alternative not valid. */ ++ strcpy (obuf, "(bad)"); ++ obufp = obuf + 5; ++ return 1; ++ } ++ else if (*p == '\0') ++ abort (); ++ } ++ alt--; ++ } ++ /* Fall through. */ ++ case 'I': ++ alt = 1; ++ continue; ++ case '|': ++ while (*++p != '}') ++ { ++ if (*p == '\0') ++ abort (); ++ } ++ break; ++ case '}': ++ break; ++ case 'A': ++ if (intel_syntax) ++ break; ++ if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) ++ *obufp++ = 'b'; ++ break; ++ case 'B': ++ if (intel_syntax) ++ break; ++ if (sizeflag & SUFFIX_ALWAYS) ++ *obufp++ = 'b'; ++ break; ++ case 'C': ++ if (intel_syntax && !alt) ++ break; ++ if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = intel_syntax ? 'd' : 'l'; ++ else ++ *obufp++ = intel_syntax ? 'w' : 's'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ break; ++ case 'E': /* For jcxz/jecxz */ ++ if (mode_64bit) ++ { ++ if (sizeflag & AFLAG) ++ *obufp++ = 'r'; ++ else ++ *obufp++ = 'e'; ++ } ++ else ++ if (sizeflag & AFLAG) ++ *obufp++ = 'e'; ++ used_prefixes |= (prefixes & PREFIX_ADDR); ++ break; ++ case 'F': ++ if (intel_syntax) ++ break; ++ if ((prefixes & PREFIX_ADDR) || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ if (sizeflag & AFLAG) ++ *obufp++ = mode_64bit ? 'q' : 'l'; ++ else ++ *obufp++ = mode_64bit ? 'l' : 'w'; ++ used_prefixes |= (prefixes & PREFIX_ADDR); ++ } ++ break; ++ case 'H': ++ if (intel_syntax) ++ break; ++ if ((prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_CS ++ || (prefixes & (PREFIX_CS | PREFIX_DS)) == PREFIX_DS) ++ { ++ used_prefixes |= prefixes & (PREFIX_CS | PREFIX_DS); ++ *obufp++ = ','; ++ *obufp++ = 'p'; ++ if (prefixes & PREFIX_DS) ++ *obufp++ = 't'; ++ else ++ *obufp++ = 'n'; ++ } ++ break; ++ case 'J': ++ if (intel_syntax) ++ break; ++ *obufp++ = 'l'; ++ break; ++ case 'L': ++ if (intel_syntax) ++ break; ++ if (sizeflag & SUFFIX_ALWAYS) ++ *obufp++ = 'l'; ++ break; ++ case 'N': ++ if ((prefixes & PREFIX_FWAIT) == 0) ++ *obufp++ = 'n'; ++ else ++ used_prefixes |= PREFIX_FWAIT; ++ break; ++ case 'O': ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ *obufp++ = 'o'; ++ else ++ *obufp++ = 'd'; ++ break; ++ case 'T': ++ if (intel_syntax) ++ break; ++ if (mode_64bit) ++ { ++ *obufp++ = 'q'; ++ break; ++ } ++ /* Fall through. */ ++ case 'P': ++ if (intel_syntax) ++ break; ++ if ((prefixes & PREFIX_DATA) ++ || (rex & REX_MODE64) ++ || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = 'l'; ++ else ++ *obufp++ = 'w'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ } ++ break; ++ case 'U': ++ if (intel_syntax) ++ break; ++ if (mode_64bit) ++ { ++ *obufp++ = 'q'; ++ break; ++ } ++ /* Fall through. */ ++ case 'Q': ++ if (intel_syntax && !alt) ++ break; ++ USED_REX (REX_MODE64); ++ if (mod != 3 || (sizeflag & SUFFIX_ALWAYS)) ++ { ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = intel_syntax ? 'd' : 'l'; ++ else ++ *obufp++ = 'w'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ } ++ break; ++ case 'R': ++ USED_REX (REX_MODE64); ++ if (intel_syntax) ++ { ++ if (rex & REX_MODE64) ++ { ++ *obufp++ = 'q'; ++ *obufp++ = 't'; ++ } ++ else if (sizeflag & DFLAG) ++ { ++ *obufp++ = 'd'; ++ *obufp++ = 'q'; ++ } ++ else ++ { ++ *obufp++ = 'w'; ++ *obufp++ = 'd'; ++ } ++ } ++ else ++ { ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else if (sizeflag & DFLAG) ++ *obufp++ = 'l'; ++ else ++ *obufp++ = 'w'; ++ } ++ if (!(rex & REX_MODE64)) ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case 'S': ++ if (intel_syntax) ++ break; ++ if (sizeflag & SUFFIX_ALWAYS) ++ { ++ if (rex & REX_MODE64) ++ *obufp++ = 'q'; ++ else ++ { ++ if (sizeflag & DFLAG) ++ *obufp++ = 'l'; ++ else ++ *obufp++ = 'w'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ } ++ break; ++ case 'X': ++ if (prefixes & PREFIX_DATA) ++ *obufp++ = 'd'; ++ else ++ *obufp++ = 's'; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case 'Y': ++ if (intel_syntax) ++ break; ++ if (rex & REX_MODE64) ++ { ++ USED_REX (REX_MODE64); ++ *obufp++ = 'q'; ++ } ++ break; ++ /* implicit operand size 'l' for i386 or 'q' for x86-64 */ ++ case 'W': ++ /* operand size flag for cwtl, cbtw */ ++ USED_REX (0); ++ if (rex) ++ *obufp++ = 'l'; ++ else if (sizeflag & DFLAG) ++ *obufp++ = 'w'; ++ else ++ *obufp++ = 'b'; ++ if (intel_syntax) ++ { ++ if (rex) ++ { ++ *obufp++ = 'q'; ++ *obufp++ = 'e'; ++ } ++ if (sizeflag & DFLAG) ++ { ++ *obufp++ = 'd'; ++ *obufp++ = 'e'; ++ } ++ else ++ { ++ *obufp++ = 'w'; ++ } ++ } ++ if (!rex) ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ } ++ alt = 0; ++ } ++ *obufp = 0; ++ return 0; ++} ++ ++static void ++oappend (const char *s) ++{ ++ strcpy (obufp, s); ++ obufp += strlen (s); ++} ++ ++static void ++append_seg (void) ++{ ++ if (prefixes & PREFIX_CS) ++ { ++ used_prefixes |= PREFIX_CS; ++ oappend ("%cs:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_DS) ++ { ++ used_prefixes |= PREFIX_DS; ++ oappend ("%ds:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_SS) ++ { ++ used_prefixes |= PREFIX_SS; ++ oappend ("%ss:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_ES) ++ { ++ used_prefixes |= PREFIX_ES; ++ oappend ("%es:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_FS) ++ { ++ used_prefixes |= PREFIX_FS; ++ oappend ("%fs:" + intel_syntax); ++ } ++ if (prefixes & PREFIX_GS) ++ { ++ used_prefixes |= PREFIX_GS; ++ oappend ("%gs:" + intel_syntax); ++ } ++} ++ ++static void ++OP_indirE (int bytemode, int sizeflag) ++{ ++ if (!intel_syntax) ++ oappend ("*"); ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++print_operand_value (char *buf, int hex, bfd_vma disp) ++{ ++ if (mode_64bit) ++ { ++ if (hex) ++ { ++ char tmp[30]; ++ int i; ++ buf[0] = '0'; ++ buf[1] = 'x'; ++ sprintf_vma (tmp, disp); ++ for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); ++ strcpy (buf + 2, tmp + i); ++ } ++ else ++ { ++ bfd_signed_vma v = disp; ++ char tmp[30]; ++ int i; ++ if (v < 0) ++ { ++ *(buf++) = '-'; ++ v = -disp; ++ /* Check for possible overflow on 0x8000000000000000. */ ++ if (v < 0) ++ { ++ strcpy (buf, "9223372036854775808"); ++ return; ++ } ++ } ++ if (!v) ++ { ++ strcpy (buf, "0"); ++ return; ++ } ++ ++ i = 0; ++ tmp[29] = 0; ++ while (v) ++ { ++ tmp[28 - i] = (v % 10) + '0'; ++ v /= 10; ++ i++; ++ } ++ strcpy (buf, tmp + 29 - i); ++ } ++ } ++ else ++ { ++ if (hex) ++ sprintf (buf, "0x%x", (unsigned int) disp); ++ else ++ sprintf (buf, "%d", (int) disp); ++ } ++} ++ ++static void ++OP_E (int bytemode, int sizeflag) ++{ ++ bfd_vma disp; ++ int add = 0; ++ int riprel = 0; ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add += 8; ++ ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ ++ if (mod == 3) ++ { ++ switch (bytemode) ++ { ++ case b_mode: ++ USED_REX (0); ++ if (rex) ++ oappend (names8rex[rm + add]); ++ else ++ oappend (names8[rm + add]); ++ break; ++ case w_mode: ++ oappend (names16[rm + add]); ++ break; ++ case d_mode: ++ oappend (names32[rm + add]); ++ break; ++ case q_mode: ++ oappend (names64[rm + add]); ++ break; ++ case m_mode: ++ if (mode_64bit) ++ oappend (names64[rm + add]); ++ else ++ oappend (names32[rm + add]); ++ break; ++ case branch_v_mode: ++ if (mode_64bit) ++ oappend (names64[rm + add]); ++ else ++ { ++ if ((sizeflag & DFLAG) || bytemode != branch_v_mode) ++ oappend (names32[rm + add]); ++ else ++ oappend (names16[rm + add]); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ break; ++ case v_mode: ++ case dq_mode: ++ case dqw_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ oappend (names64[rm + add]); ++ else if ((sizeflag & DFLAG) || bytemode != v_mode) ++ oappend (names32[rm + add]); ++ else ++ oappend (names16[rm + add]); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case 0: ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ break; ++ } ++ return; ++ } ++ ++ disp = 0; ++ append_seg (); ++ ++ if ((sizeflag & AFLAG) || mode_64bit) /* 32 bit address mode */ ++ { ++ int havesib; ++ int havebase; ++ int base; ++ int index = 0; ++ int scale = 0; ++ ++ havesib = 0; ++ havebase = 1; ++ base = rm; ++ ++ if (base == 4) ++ { ++ havesib = 1; ++ FETCH_DATA (the_info, codep + 1); ++ index = (*codep >> 3) & 7; ++ if (mode_64bit || index != 0x4) ++ /* When INDEX == 0x4 in 32 bit mode, SCALE is ignored. */ ++ scale = (*codep >> 6) & 3; ++ base = *codep & 7; ++ USED_REX (REX_EXTY); ++ if (rex & REX_EXTY) ++ index += 8; ++ codep++; ++ } ++ base += add; ++ ++ switch (mod) ++ { ++ case 0: ++ if ((base & 7) == 5) ++ { ++ havebase = 0; ++ if (mode_64bit && !havesib) ++ riprel = 1; ++ disp = get32s (); ++ } ++ break; ++ case 1: ++ FETCH_DATA (the_info, codep + 1); ++ disp = *codep++; ++ if ((disp & 0x80) != 0) ++ disp -= 0x100; ++ break; ++ case 2: ++ disp = get32s (); ++ break; ++ } ++ ++ if (!intel_syntax) ++ if (mod != 0 || (base & 7) == 5) ++ { ++ print_operand_value (scratchbuf, !riprel, disp); ++ oappend (scratchbuf); ++ if (riprel) ++ { ++ set_op (disp, 1); ++ oappend ("(%rip)"); ++ } ++ } ++ ++ if (havebase || (havesib && (index != 4 || scale != 0))) ++ { ++ if (intel_syntax) ++ { ++ switch (bytemode) ++ { ++ case b_mode: ++ oappend ("BYTE PTR "); ++ break; ++ case w_mode: ++ case dqw_mode: ++ oappend ("WORD PTR "); ++ break; ++ case branch_v_mode: ++ case v_mode: ++ case dq_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ oappend ("QWORD PTR "); ++ else if ((sizeflag & DFLAG) || bytemode == dq_mode) ++ oappend ("DWORD PTR "); ++ else ++ oappend ("WORD PTR "); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case d_mode: ++ oappend ("DWORD PTR "); ++ break; ++ case q_mode: ++ oappend ("QWORD PTR "); ++ break; ++ case m_mode: ++ if (mode_64bit) ++ oappend ("QWORD PTR "); ++ else ++ oappend ("DWORD PTR "); ++ break; ++ case f_mode: ++ if (sizeflag & DFLAG) ++ { ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ oappend ("FWORD PTR "); ++ } ++ else ++ oappend ("DWORD PTR "); ++ break; ++ case t_mode: ++ oappend ("TBYTE PTR "); ++ break; ++ case x_mode: ++ oappend ("XMMWORD PTR "); ++ break; ++ default: ++ break; ++ } ++ } ++ *obufp++ = open_char; ++ if (intel_syntax && riprel) ++ oappend ("rip + "); ++ *obufp = '\0'; ++ if (havebase) ++ oappend (mode_64bit && (sizeflag & AFLAG) ++ ? names64[base] : names32[base]); ++ if (havesib) ++ { ++ if (index != 4) ++ { ++ if (!intel_syntax || havebase) ++ { ++ *obufp++ = separator_char; ++ *obufp = '\0'; ++ } ++ oappend (mode_64bit && (sizeflag & AFLAG) ++ ? names64[index] : names32[index]); ++ } ++ if (scale != 0 || (!intel_syntax && index != 4)) ++ { ++ *obufp++ = scale_char; ++ *obufp = '\0'; ++ sprintf (scratchbuf, "%d", 1 << scale); ++ oappend (scratchbuf); ++ } ++ } ++ if (intel_syntax && disp) ++ { ++ if ((bfd_signed_vma) disp > 0) ++ { ++ *obufp++ = '+'; ++ *obufp = '\0'; ++ } ++ else if (mod != 1) ++ { ++ *obufp++ = '-'; ++ *obufp = '\0'; ++ disp = - (bfd_signed_vma) disp; ++ } ++ ++ print_operand_value (scratchbuf, mod != 1, disp); ++ oappend (scratchbuf); ++ } ++ ++ *obufp++ = close_char; ++ *obufp = '\0'; ++ } ++ else if (intel_syntax) ++ { ++ if (mod != 0 || (base & 7) == 5) ++ { ++ if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS)) ++ ; ++ else ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ print_operand_value (scratchbuf, 1, disp); ++ oappend (scratchbuf); ++ } ++ } ++ } ++ else ++ { /* 16 bit address mode */ ++ switch (mod) ++ { ++ case 0: ++ if (rm == 6) ++ { ++ disp = get16 (); ++ if ((disp & 0x8000) != 0) ++ disp -= 0x10000; ++ } ++ break; ++ case 1: ++ FETCH_DATA (the_info, codep + 1); ++ disp = *codep++; ++ if ((disp & 0x80) != 0) ++ disp -= 0x100; ++ break; ++ case 2: ++ disp = get16 (); ++ if ((disp & 0x8000) != 0) ++ disp -= 0x10000; ++ break; ++ } ++ ++ if (!intel_syntax) ++ if (mod != 0 || rm == 6) ++ { ++ print_operand_value (scratchbuf, 0, disp); ++ oappend (scratchbuf); ++ } ++ ++ if (mod != 0 || rm != 6) ++ { ++ *obufp++ = open_char; ++ *obufp = '\0'; ++ oappend (index16[rm]); ++ if (intel_syntax && disp) ++ { ++ if ((bfd_signed_vma) disp > 0) ++ { ++ *obufp++ = '+'; ++ *obufp = '\0'; ++ } ++ else if (mod != 1) ++ { ++ *obufp++ = '-'; ++ *obufp = '\0'; ++ disp = - (bfd_signed_vma) disp; ++ } ++ ++ print_operand_value (scratchbuf, mod != 1, disp); ++ oappend (scratchbuf); ++ } ++ ++ *obufp++ = close_char; ++ *obufp = '\0'; ++ } ++ else if (intel_syntax) ++ { ++ if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS)) ++ ; ++ else ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ print_operand_value (scratchbuf, 1, disp & 0xffff); ++ oappend (scratchbuf); ++ } ++ } ++} ++ ++static void ++OP_G (int bytemode, int sizeflag) ++{ ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add += 8; ++ switch (bytemode) ++ { ++ case b_mode: ++ USED_REX (0); ++ if (rex) ++ oappend (names8rex[reg + add]); ++ else ++ oappend (names8[reg + add]); ++ break; ++ case w_mode: ++ oappend (names16[reg + add]); ++ break; ++ case d_mode: ++ oappend (names32[reg + add]); ++ break; ++ case q_mode: ++ oappend (names64[reg + add]); ++ break; ++ case v_mode: ++ case dq_mode: ++ case dqw_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ oappend (names64[reg + add]); ++ else if ((sizeflag & DFLAG) || bytemode != v_mode) ++ oappend (names32[reg + add]); ++ else ++ oappend (names16[reg + add]); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case m_mode: ++ if (mode_64bit) ++ oappend (names64[reg + add]); ++ else ++ oappend (names32[reg + add]); ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ break; ++ } ++} ++ ++static bfd_vma ++get64 (void) ++{ ++ bfd_vma x; ++#ifdef BFD64 ++ unsigned int a; ++ unsigned int b; ++ ++ FETCH_DATA (the_info, codep + 8); ++ a = *codep++ & 0xff; ++ a |= (*codep++ & 0xff) << 8; ++ a |= (*codep++ & 0xff) << 16; ++ a |= (*codep++ & 0xff) << 24; ++ b = *codep++ & 0xff; ++ b |= (*codep++ & 0xff) << 8; ++ b |= (*codep++ & 0xff) << 16; ++ b |= (*codep++ & 0xff) << 24; ++ x = a + ((bfd_vma) b << 32); ++#else ++ abort (); ++ x = 0; ++#endif ++ return x; ++} ++ ++static bfd_signed_vma ++get32 (void) ++{ ++ bfd_signed_vma x = 0; ++ ++ FETCH_DATA (the_info, codep + 4); ++ x = *codep++ & (bfd_signed_vma) 0xff; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; ++ return x; ++} ++ ++static bfd_signed_vma ++get32s (void) ++{ ++ bfd_signed_vma x = 0; ++ ++ FETCH_DATA (the_info, codep + 4); ++ x = *codep++ & (bfd_signed_vma) 0xff; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 8; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 16; ++ x |= (*codep++ & (bfd_signed_vma) 0xff) << 24; ++ ++ x = (x ^ ((bfd_signed_vma) 1 << 31)) - ((bfd_signed_vma) 1 << 31); ++ ++ return x; ++} ++ ++static int ++get16 (void) ++{ ++ int x = 0; ++ ++ FETCH_DATA (the_info, codep + 2); ++ x = *codep++ & 0xff; ++ x |= (*codep++ & 0xff) << 8; ++ return x; ++} ++ ++static void ++set_op (bfd_vma op, int riprel) ++{ ++ op_index[op_ad] = op_ad; ++ if (mode_64bit) ++ { ++ op_address[op_ad] = op; ++ op_riprel[op_ad] = riprel; ++ } ++ else ++ { ++ /* Mask to get a 32-bit address. */ ++ op_address[op_ad] = op & 0xffffffff; ++ op_riprel[op_ad] = riprel & 0xffffffff; ++ } ++} ++ ++static void ++OP_REG (int code, int sizeflag) ++{ ++ const char *s; ++ int add = 0; ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add = 8; ++ ++ switch (code) ++ { ++ case indir_dx_reg: ++ if (intel_syntax) ++ s = "[dx]"; ++ else ++ s = "(%dx)"; ++ break; ++ case ax_reg: case cx_reg: case dx_reg: case bx_reg: ++ case sp_reg: case bp_reg: case si_reg: case di_reg: ++ s = names16[code - ax_reg + add]; ++ break; ++ case es_reg: case ss_reg: case cs_reg: ++ case ds_reg: case fs_reg: case gs_reg: ++ s = names_seg[code - es_reg + add]; ++ break; ++ case al_reg: case ah_reg: case cl_reg: case ch_reg: ++ case dl_reg: case dh_reg: case bl_reg: case bh_reg: ++ USED_REX (0); ++ if (rex) ++ s = names8rex[code - al_reg + add]; ++ else ++ s = names8[code - al_reg]; ++ break; ++ case rAX_reg: case rCX_reg: case rDX_reg: case rBX_reg: ++ case rSP_reg: case rBP_reg: case rSI_reg: case rDI_reg: ++ if (mode_64bit) ++ { ++ s = names64[code - rAX_reg + add]; ++ break; ++ } ++ code += eAX_reg - rAX_reg; ++ /* Fall through. */ ++ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: ++ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ s = names64[code - eAX_reg + add]; ++ else if (sizeflag & DFLAG) ++ s = names32[code - eAX_reg + add]; ++ else ++ s = names16[code - eAX_reg + add]; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ default: ++ s = INTERNAL_DISASSEMBLER_ERROR; ++ break; ++ } ++ oappend (s); ++} ++ ++static void ++OP_IMREG (int code, int sizeflag) ++{ ++ const char *s; ++ ++ switch (code) ++ { ++ case indir_dx_reg: ++ if (intel_syntax) ++ s = "[dx]"; ++ else ++ s = "(%dx)"; ++ break; ++ case ax_reg: case cx_reg: case dx_reg: case bx_reg: ++ case sp_reg: case bp_reg: case si_reg: case di_reg: ++ s = names16[code - ax_reg]; ++ break; ++ case es_reg: case ss_reg: case cs_reg: ++ case ds_reg: case fs_reg: case gs_reg: ++ s = names_seg[code - es_reg]; ++ break; ++ case al_reg: case ah_reg: case cl_reg: case ch_reg: ++ case dl_reg: case dh_reg: case bl_reg: case bh_reg: ++ USED_REX (0); ++ if (rex) ++ s = names8rex[code - al_reg]; ++ else ++ s = names8[code - al_reg]; ++ break; ++ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: ++ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ s = names64[code - eAX_reg]; ++ else if (sizeflag & DFLAG) ++ s = names32[code - eAX_reg]; ++ else ++ s = names16[code - eAX_reg]; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ default: ++ s = INTERNAL_DISASSEMBLER_ERROR; ++ break; ++ } ++ oappend (s); ++} ++ ++static void ++OP_I (int bytemode, int sizeflag) ++{ ++ bfd_signed_vma op; ++ bfd_signed_vma mask = -1; ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ op = *codep++; ++ mask = 0xff; ++ break; ++ case q_mode: ++ if (mode_64bit) ++ { ++ op = get32s (); ++ break; ++ } ++ /* Fall through. */ ++ case v_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ op = get32s (); ++ else if (sizeflag & DFLAG) ++ { ++ op = get32 (); ++ mask = 0xffffffff; ++ } ++ else ++ { ++ op = get16 (); ++ mask = 0xfffff; ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case w_mode: ++ mask = 0xfffff; ++ op = get16 (); ++ break; ++ case const_1_mode: ++ if (intel_syntax) ++ oappend ("1"); ++ return; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ ++ op &= mask; ++ scratchbuf[0] = '$'; ++ print_operand_value (scratchbuf + 1, 1, op); ++ oappend (scratchbuf + intel_syntax); ++ scratchbuf[0] = '\0'; ++} ++ ++static void ++OP_I64 (int bytemode, int sizeflag) ++{ ++ bfd_signed_vma op; ++ bfd_signed_vma mask = -1; ++ ++ if (!mode_64bit) ++ { ++ OP_I (bytemode, sizeflag); ++ return; ++ } ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ op = *codep++; ++ mask = 0xff; ++ break; ++ case v_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ op = get64 (); ++ else if (sizeflag & DFLAG) ++ { ++ op = get32 (); ++ mask = 0xffffffff; ++ } ++ else ++ { ++ op = get16 (); ++ mask = 0xfffff; ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case w_mode: ++ mask = 0xfffff; ++ op = get16 (); ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ ++ op &= mask; ++ scratchbuf[0] = '$'; ++ print_operand_value (scratchbuf + 1, 1, op); ++ oappend (scratchbuf + intel_syntax); ++ scratchbuf[0] = '\0'; ++} ++ ++static void ++OP_sI (int bytemode, int sizeflag) ++{ ++ bfd_signed_vma op; ++ bfd_signed_vma mask = -1; ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ op = *codep++; ++ if ((op & 0x80) != 0) ++ op -= 0x100; ++ mask = 0xffffffff; ++ break; ++ case v_mode: ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ op = get32s (); ++ else if (sizeflag & DFLAG) ++ { ++ op = get32s (); ++ mask = 0xffffffff; ++ } ++ else ++ { ++ mask = 0xffffffff; ++ op = get16 (); ++ if ((op & 0x8000) != 0) ++ op -= 0x10000; ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ break; ++ case w_mode: ++ op = get16 (); ++ mask = 0xffffffff; ++ if ((op & 0x8000) != 0) ++ op -= 0x10000; ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ ++ scratchbuf[0] = '$'; ++ print_operand_value (scratchbuf + 1, 1, op); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_J (int bytemode, int sizeflag) ++{ ++ bfd_vma disp; ++ bfd_vma mask = -1; ++ ++ switch (bytemode) ++ { ++ case b_mode: ++ FETCH_DATA (the_info, codep + 1); ++ disp = *codep++; ++ if ((disp & 0x80) != 0) ++ disp -= 0x100; ++ break; ++ case v_mode: ++ if (sizeflag & DFLAG) ++ disp = get32s (); ++ else ++ { ++ disp = get16 (); ++ /* For some reason, a data16 prefix on a jump instruction ++ means that the pc is masked to 16 bits after the ++ displacement is added! */ ++ mask = 0xffff; ++ } ++ break; ++ default: ++ oappend (INTERNAL_DISASSEMBLER_ERROR); ++ return; ++ } ++ disp = (start_pc + codep - start_codep + disp) & mask; ++ set_op (disp, 0); ++ print_operand_value (scratchbuf, 1, disp); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_SEG (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ oappend (names_seg[reg]); ++} ++ ++static void ++OP_DIR (int dummy ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ int seg, offset; ++ ++ if (sizeflag & DFLAG) ++ { ++ offset = get32 (); ++ seg = get16 (); ++ } ++ else ++ { ++ offset = get16 (); ++ seg = get16 (); ++ } ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (intel_syntax) ++ sprintf (scratchbuf, "0x%x,0x%x", seg, offset); ++ else ++ sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_OFF (int bytemode ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ bfd_vma off; ++ ++ append_seg (); ++ ++ if ((sizeflag & AFLAG) || mode_64bit) ++ off = get32 (); ++ else ++ off = get16 (); ++ ++ if (intel_syntax) ++ { ++ if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS))) ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ } ++ print_operand_value (scratchbuf, 1, off); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_OFF64 (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ bfd_vma off; ++ ++ if (!mode_64bit) ++ { ++ OP_OFF (bytemode, sizeflag); ++ return; ++ } ++ ++ append_seg (); ++ ++ off = get64 (); ++ ++ if (intel_syntax) ++ { ++ if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS ++ | PREFIX_ES | PREFIX_FS | PREFIX_GS))) ++ { ++ oappend (names_seg[ds_reg - es_reg]); ++ oappend (":"); ++ } ++ } ++ print_operand_value (scratchbuf, 1, off); ++ oappend (scratchbuf); ++} ++ ++static void ++ptr_reg (int code, int sizeflag) ++{ ++ const char *s; ++ ++ *obufp++ = open_char; ++ used_prefixes |= (prefixes & PREFIX_ADDR); ++ if (mode_64bit) ++ { ++ if (!(sizeflag & AFLAG)) ++ s = names32[code - eAX_reg]; ++ else ++ s = names64[code - eAX_reg]; ++ } ++ else if (sizeflag & AFLAG) ++ s = names32[code - eAX_reg]; ++ else ++ s = names16[code - eAX_reg]; ++ oappend (s); ++ *obufp++ = close_char; ++ *obufp = 0; ++} ++ ++static void ++OP_ESreg (int code, int sizeflag) ++{ ++ if (intel_syntax) ++ { ++ if (codep[-1] & 1) ++ { ++ USED_REX (REX_MODE64); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (rex & REX_MODE64) ++ oappend ("QWORD PTR "); ++ else if ((sizeflag & DFLAG)) ++ oappend ("DWORD PTR "); ++ else ++ oappend ("WORD PTR "); ++ } ++ else ++ oappend ("BYTE PTR "); ++ } ++ ++ oappend ("%es:" + intel_syntax); ++ ptr_reg (code, sizeflag); ++} ++ ++static void ++OP_DSreg (int code, int sizeflag) ++{ ++ if (intel_syntax) ++ { ++ if (codep[-1] != 0xd7 && (codep[-1] & 1)) ++ { ++ USED_REX (REX_MODE64); ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (rex & REX_MODE64) ++ oappend ("QWORD PTR "); ++ else if ((sizeflag & DFLAG)) ++ oappend ("DWORD PTR "); ++ else ++ oappend ("WORD PTR "); ++ } ++ else ++ oappend ("BYTE PTR "); ++ } ++ ++ if ((prefixes ++ & (PREFIX_CS ++ | PREFIX_DS ++ | PREFIX_SS ++ | PREFIX_ES ++ | PREFIX_FS ++ | PREFIX_GS)) == 0) ++ prefixes |= PREFIX_DS; ++ append_seg (); ++ ptr_reg (code, sizeflag); ++} ++ ++static void ++OP_C (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ int add = 0; ++ if (rex & REX_EXTX) ++ { ++ USED_REX (REX_EXTX); ++ add = 8; ++ } ++ else if (!mode_64bit && (prefixes & PREFIX_LOCK)) ++ { ++ used_prefixes |= PREFIX_LOCK; ++ add = 8; ++ } ++ sprintf (scratchbuf, "%%cr%d", reg + add); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_D (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add = 8; ++ if (intel_syntax) ++ sprintf (scratchbuf, "db%d", reg + add); ++ else ++ sprintf (scratchbuf, "%%db%d", reg + add); ++ oappend (scratchbuf); ++} ++ ++static void ++OP_T (int dummy ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ sprintf (scratchbuf, "%%tr%d", reg); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_Rd (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ OP_E (bytemode, sizeflag); ++ else ++ BadOp (); ++} ++ ++static void ++OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ { ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add = 8; ++ sprintf (scratchbuf, "%%xmm%d", reg + add); ++ } ++ else ++ sprintf (scratchbuf, "%%mm%d", reg); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ int add = 0; ++ USED_REX (REX_EXTX); ++ if (rex & REX_EXTX) ++ add = 8; ++ sprintf (scratchbuf, "%%xmm%d", reg + add); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_EM (int bytemode, int sizeflag) ++{ ++ if (mod != 3) ++ { ++ if (intel_syntax && bytemode == v_mode) ++ { ++ bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ } ++ OP_E (bytemode, sizeflag); ++ return; ++ } ++ ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ { ++ int add = 0; ++ ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add = 8; ++ sprintf (scratchbuf, "%%xmm%d", rm + add); ++ } ++ else ++ sprintf (scratchbuf, "%%mm%d", rm); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_EX (int bytemode, int sizeflag) ++{ ++ int add = 0; ++ if (mod != 3) ++ { ++ if (intel_syntax && bytemode == v_mode) ++ { ++ switch (prefixes & (PREFIX_DATA|PREFIX_REPZ|PREFIX_REPNZ)) ++ { ++ case 0: bytemode = x_mode; break; ++ case PREFIX_REPZ: bytemode = d_mode; used_prefixes |= PREFIX_REPZ; break; ++ case PREFIX_DATA: bytemode = x_mode; used_prefixes |= PREFIX_DATA; break; ++ case PREFIX_REPNZ: bytemode = q_mode; used_prefixes |= PREFIX_REPNZ; break; ++ default: bytemode = 0; break; ++ } ++ } ++ OP_E (bytemode, sizeflag); ++ return; ++ } ++ USED_REX (REX_EXTZ); ++ if (rex & REX_EXTZ) ++ add = 8; ++ ++ /* Skip mod/rm byte. */ ++ MODRM_CHECK; ++ codep++; ++ sprintf (scratchbuf, "%%xmm%d", rm + add); ++ oappend (scratchbuf + intel_syntax); ++} ++ ++static void ++OP_MS (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ OP_EM (bytemode, sizeflag); ++ else ++ BadOp (); ++} ++ ++static void ++OP_XS (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ OP_EX (bytemode, sizeflag); ++ else ++ BadOp (); ++} ++ ++static void ++OP_M (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ BadOp (); /* bad lea,lds,les,lfs,lgs,lss modrm */ ++ else ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++OP_0f07 (int bytemode, int sizeflag) ++{ ++ if (mod != 3 || rm != 0) ++ BadOp (); ++ else ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++OP_0fae (int bytemode, int sizeflag) ++{ ++ if (mod == 3) ++ { ++ if (reg == 7) ++ strcpy (obuf + strlen (obuf) - sizeof ("clflush") + 1, "sfence"); ++ ++ if (reg < 5 || rm != 0) ++ { ++ BadOp (); /* bad sfence, mfence, or lfence */ ++ return; ++ } ++ } ++ else if (reg != 7) ++ { ++ BadOp (); /* bad clflush */ ++ return; ++ } ++ ++ OP_E (bytemode, sizeflag); ++} ++ ++static void ++NOP_Fixup (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ /* NOP with REPZ prefix is called PAUSE. */ ++ if (prefixes == PREFIX_REPZ) ++ strcpy (obuf, "pause"); ++} ++ ++static const char *const Suffix3DNow[] = { ++/* 00 */ NULL, NULL, NULL, NULL, ++/* 04 */ NULL, NULL, NULL, NULL, ++/* 08 */ NULL, NULL, NULL, NULL, ++/* 0C */ "pi2fw", "pi2fd", NULL, NULL, ++/* 10 */ NULL, NULL, NULL, NULL, ++/* 14 */ NULL, NULL, NULL, NULL, ++/* 18 */ NULL, NULL, NULL, NULL, ++/* 1C */ "pf2iw", "pf2id", NULL, NULL, ++/* 20 */ NULL, NULL, NULL, NULL, ++/* 24 */ NULL, NULL, NULL, NULL, ++/* 28 */ NULL, NULL, NULL, NULL, ++/* 2C */ NULL, NULL, NULL, NULL, ++/* 30 */ NULL, NULL, NULL, NULL, ++/* 34 */ NULL, NULL, NULL, NULL, ++/* 38 */ NULL, NULL, NULL, NULL, ++/* 3C */ NULL, NULL, NULL, NULL, ++/* 40 */ NULL, NULL, NULL, NULL, ++/* 44 */ NULL, NULL, NULL, NULL, ++/* 48 */ NULL, NULL, NULL, NULL, ++/* 4C */ NULL, NULL, NULL, NULL, ++/* 50 */ NULL, NULL, NULL, NULL, ++/* 54 */ NULL, NULL, NULL, NULL, ++/* 58 */ NULL, NULL, NULL, NULL, ++/* 5C */ NULL, NULL, NULL, NULL, ++/* 60 */ NULL, NULL, NULL, NULL, ++/* 64 */ NULL, NULL, NULL, NULL, ++/* 68 */ NULL, NULL, NULL, NULL, ++/* 6C */ NULL, NULL, NULL, NULL, ++/* 70 */ NULL, NULL, NULL, NULL, ++/* 74 */ NULL, NULL, NULL, NULL, ++/* 78 */ NULL, NULL, NULL, NULL, ++/* 7C */ NULL, NULL, NULL, NULL, ++/* 80 */ NULL, NULL, NULL, NULL, ++/* 84 */ NULL, NULL, NULL, NULL, ++/* 88 */ NULL, NULL, "pfnacc", NULL, ++/* 8C */ NULL, NULL, "pfpnacc", NULL, ++/* 90 */ "pfcmpge", NULL, NULL, NULL, ++/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", ++/* 98 */ NULL, NULL, "pfsub", NULL, ++/* 9C */ NULL, NULL, "pfadd", NULL, ++/* A0 */ "pfcmpgt", NULL, NULL, NULL, ++/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", ++/* A8 */ NULL, NULL, "pfsubr", NULL, ++/* AC */ NULL, NULL, "pfacc", NULL, ++/* B0 */ "pfcmpeq", NULL, NULL, NULL, ++/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", ++/* B8 */ NULL, NULL, NULL, "pswapd", ++/* BC */ NULL, NULL, NULL, "pavgusb", ++/* C0 */ NULL, NULL, NULL, NULL, ++/* C4 */ NULL, NULL, NULL, NULL, ++/* C8 */ NULL, NULL, NULL, NULL, ++/* CC */ NULL, NULL, NULL, NULL, ++/* D0 */ NULL, NULL, NULL, NULL, ++/* D4 */ NULL, NULL, NULL, NULL, ++/* D8 */ NULL, NULL, NULL, NULL, ++/* DC */ NULL, NULL, NULL, NULL, ++/* E0 */ NULL, NULL, NULL, NULL, ++/* E4 */ NULL, NULL, NULL, NULL, ++/* E8 */ NULL, NULL, NULL, NULL, ++/* EC */ NULL, NULL, NULL, NULL, ++/* F0 */ NULL, NULL, NULL, NULL, ++/* F4 */ NULL, NULL, NULL, NULL, ++/* F8 */ NULL, NULL, NULL, NULL, ++/* FC */ NULL, NULL, NULL, NULL, ++}; ++ ++static void ++OP_3DNowSuffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ const char *mnemonic; ++ ++ FETCH_DATA (the_info, codep + 1); ++ /* AMD 3DNow! instructions are specified by an opcode suffix in the ++ place where an 8-bit immediate would normally go. ie. the last ++ byte of the instruction. */ ++ obufp = obuf + strlen (obuf); ++ mnemonic = Suffix3DNow[*codep++ & 0xff]; ++ if (mnemonic) ++ oappend (mnemonic); ++ else ++ { ++ /* Since a variable sized modrm/sib chunk is between the start ++ of the opcode (0x0f0f) and the opcode suffix, we need to do ++ all the modrm processing first, and don't know until now that ++ we have a bad opcode. This necessitates some cleaning up. */ ++ op1out[0] = '\0'; ++ op2out[0] = '\0'; ++ BadOp (); ++ } ++} ++ ++static const char *simd_cmp_op[] = { ++ "eq", ++ "lt", ++ "le", ++ "unord", ++ "neq", ++ "nlt", ++ "nle", ++ "ord" ++}; ++ ++static void ++OP_SIMD_Suffix (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ unsigned int cmp_type; ++ ++ FETCH_DATA (the_info, codep + 1); ++ obufp = obuf + strlen (obuf); ++ cmp_type = *codep++ & 0xff; ++ if (cmp_type < 8) ++ { ++ char suffix1 = 'p', suffix2 = 's'; ++ used_prefixes |= (prefixes & PREFIX_REPZ); ++ if (prefixes & PREFIX_REPZ) ++ suffix1 = 's'; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_DATA); ++ if (prefixes & PREFIX_DATA) ++ suffix2 = 'd'; ++ else ++ { ++ used_prefixes |= (prefixes & PREFIX_REPNZ); ++ if (prefixes & PREFIX_REPNZ) ++ suffix1 = 's', suffix2 = 'd'; ++ } ++ } ++ sprintf (scratchbuf, "cmp%s%c%c", ++ simd_cmp_op[cmp_type], suffix1, suffix2); ++ used_prefixes |= (prefixes & PREFIX_REPZ); ++ oappend (scratchbuf); ++ } ++ else ++ { ++ /* We have a bad extension byte. Clean up. */ ++ op1out[0] = '\0'; ++ op2out[0] = '\0'; ++ BadOp (); ++ } ++} ++ ++static void ++SIMD_Fixup (int extrachar, int sizeflag ATTRIBUTE_UNUSED) ++{ ++ /* Change movlps/movhps to movhlps/movlhps for 2 register operand ++ forms of these instructions. */ ++ if (mod == 3) ++ { ++ char *p = obuf + strlen (obuf); ++ *(p + 1) = '\0'; ++ *p = *(p - 1); ++ *(p - 1) = *(p - 2); ++ *(p - 2) = *(p - 3); ++ *(p - 3) = extrachar; ++ } ++} ++ ++static void ++PNI_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ if (mod == 3 && reg == 1 && rm <= 1) ++ { ++ /* Override "sidt". */ ++ char *p = obuf + strlen (obuf) - 4; ++ ++ /* We might have a suffix when disassembling with -Msuffix. */ ++ if (*p == 'i') ++ --p; ++ ++ if (rm) ++ { ++ /* mwait %eax,%ecx */ ++ strcpy (p, "mwait"); ++ if (!intel_syntax) ++ strcpy (op1out, names32[0]); ++ } ++ else ++ { ++ /* monitor %eax,%ecx,%edx" */ ++ strcpy (p, "monitor"); ++ if (!intel_syntax) ++ { ++ if (!mode_64bit) ++ strcpy (op1out, names32[0]); ++ else if (!(prefixes & PREFIX_ADDR)) ++ strcpy (op1out, names64[0]); ++ else ++ { ++ strcpy (op1out, names32[0]); ++ used_prefixes |= PREFIX_ADDR; ++ } ++ strcpy (op3out, names32[2]); ++ } ++ } ++ if (!intel_syntax) ++ { ++ strcpy (op2out, names32[1]); ++ two_source_ops = 1; ++ } ++ ++ codep++; ++ } ++ else ++ OP_M (0, sizeflag); ++} ++ ++static void ++SVME_Fixup (int bytemode, int sizeflag) ++{ ++ const char *alt; ++ char *p; ++ ++ switch (*codep) ++ { ++ case 0xd8: ++ alt = "vmrun"; ++ break; ++ case 0xd9: ++ alt = "vmmcall"; ++ break; ++ case 0xda: ++ alt = "vmload"; ++ break; ++ case 0xdb: ++ alt = "vmsave"; ++ break; ++ case 0xdc: ++ alt = "stgi"; ++ break; ++ case 0xdd: ++ alt = "clgi"; ++ break; ++ case 0xde: ++ alt = "skinit"; ++ break; ++ case 0xdf: ++ alt = "invlpga"; ++ break; ++ default: ++ OP_M (bytemode, sizeflag); ++ return; ++ } ++ /* Override "lidt". */ ++ p = obuf + strlen (obuf) - 4; ++ /* We might have a suffix. */ ++ if (*p == 'i') ++ --p; ++ strcpy (p, alt); ++ if (!(prefixes & PREFIX_ADDR)) ++ { ++ ++codep; ++ return; ++ } ++ used_prefixes |= PREFIX_ADDR; ++ switch (*codep++) ++ { ++ case 0xdf: ++ strcpy (op2out, names32[1]); ++ two_source_ops = 1; ++ /* Fall through. */ ++ case 0xd8: ++ case 0xda: ++ case 0xdb: ++ *obufp++ = open_char; ++ if (mode_64bit || (sizeflag & AFLAG)) ++ alt = names32[0]; ++ else ++ alt = names16[0]; ++ strcpy (obufp, alt); ++ obufp += strlen (alt); ++ *obufp++ = close_char; ++ *obufp = '\0'; ++ break; ++ } ++} ++ ++static void ++INVLPG_Fixup (int bytemode, int sizeflag) ++{ ++ const char *alt; ++ ++ switch (*codep) ++ { ++ case 0xf8: ++ alt = "swapgs"; ++ break; ++ case 0xf9: ++ alt = "rdtscp"; ++ break; ++ default: ++ OP_M (bytemode, sizeflag); ++ return; ++ } ++ /* Override "invlpg". */ ++ strcpy (obuf + strlen (obuf) - 6, alt); ++ codep++; ++} ++ ++static void ++BadOp (void) ++{ ++ /* Throw away prefixes and 1st. opcode byte. */ ++ codep = insn_codep + 1; ++ oappend ("(bad)"); ++} ++ ++static void ++SEG_Fixup (int extrachar, int sizeflag) ++{ ++ if (mod == 3) ++ { ++ /* We need to add a proper suffix with ++ ++ movw %ds,%ax ++ movl %ds,%eax ++ movq %ds,%rax ++ movw %ax,%ds ++ movl %eax,%ds ++ movq %rax,%ds ++ */ ++ const char *suffix; ++ ++ if (prefixes & PREFIX_DATA) ++ suffix = "w"; ++ else ++ { ++ USED_REX (REX_MODE64); ++ if (rex & REX_MODE64) ++ suffix = "q"; ++ else ++ suffix = "l"; ++ } ++ strcat (obuf, suffix); ++ } ++ else ++ { ++ /* We need to fix the suffix for ++ ++ movw %ds,(%eax) ++ movw %ds,(%rax) ++ movw (%eax),%ds ++ movw (%rax),%ds ++ ++ Override "mov[l|q]". */ ++ char *p = obuf + strlen (obuf) - 1; ++ ++ /* We might not have a suffix. */ ++ if (*p == 'v') ++ ++p; ++ *p = 'w'; ++ } ++ ++ OP_E (extrachar, sizeflag); ++} ++ ++static void ++VMX_Fixup (int extrachar ATTRIBUTE_UNUSED, int sizeflag) ++{ ++ if (mod == 3 && reg == 0 && rm >=1 && rm <= 4) ++ { ++ /* Override "sgdt". */ ++ char *p = obuf + strlen (obuf) - 4; ++ ++ /* We might have a suffix when disassembling with -Msuffix. */ ++ if (*p == 'g') ++ --p; ++ ++ switch (rm) ++ { ++ case 1: ++ strcpy (p, "vmcall"); ++ break; ++ case 2: ++ strcpy (p, "vmlaunch"); ++ break; ++ case 3: ++ strcpy (p, "vmresume"); ++ break; ++ case 4: ++ strcpy (p, "vmxoff"); ++ break; ++ } ++ ++ codep++; ++ } ++ else ++ OP_E (0, sizeflag); ++} ++ ++static void ++OP_VMX (int bytemode, int sizeflag) ++{ ++ used_prefixes |= (prefixes & (PREFIX_DATA | PREFIX_REPZ)); ++ if (prefixes & PREFIX_DATA) ++ strcpy (obuf, "vmclear"); ++ else if (prefixes & PREFIX_REPZ) ++ strcpy (obuf, "vmxon"); ++ else ++ strcpy (obuf, "vmptrld"); ++ OP_E (bytemode, sizeflag); ++} +--- a/arch/x86/kernel/crash.c ++++ b/arch/x86/kernel/crash.c +@@ -35,13 +35,38 @@ static int crashing_cpu; + #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) + static atomic_t waiting_for_crash_ipi; + ++#ifdef CONFIG_KDB_KDUMP ++void halt_current_cpu(struct pt_regs *regs) ++{ ++#ifdef CONFIG_X86_32 ++ struct pt_regs fixed_regs; ++#endif ++ local_irq_disable(); ++#ifdef CONFIG_X86_32 ++ if (!user_mode_vm(regs)) { ++ crash_fixup_ss_esp(&fixed_regs, regs); ++ regs = &fixed_regs; ++ } ++#endif ++ crash_save_cpu(regs, raw_smp_processor_id()); ++ disable_local_APIC(); ++ atomic_dec(&waiting_for_crash_ipi); ++ /* Assume hlt works */ ++ halt(); ++ for(;;) ++ cpu_relax(); ++} ++#endif /* CONFIG_KDB_KDUMP */ ++ + static int crash_nmi_callback(struct notifier_block *self, + unsigned long val, void *data) + { + struct pt_regs *regs; ++#ifndef CONFIG_KDB_KDUMP + #ifdef CONFIG_X86_32 + struct pt_regs fixed_regs; + #endif ++#endif /* !CONFIG_KDB_KDUMP */ + int cpu; + + if (val != DIE_NMI_IPI) +@@ -56,6 +81,9 @@ static int crash_nmi_callback(struct not + */ + if (cpu == crashing_cpu) + return NOTIFY_STOP; ++#ifdef CONFIG_KDB_KDUMP ++ halt_current_cpu(regs); ++#else + local_irq_disable(); + + #ifdef CONFIG_X86_32 +@@ -71,6 +99,7 @@ static int crash_nmi_callback(struct not + halt(); + for (;;) + cpu_relax(); ++#endif /* !CONFIG_KDB_KDUMP */ + + return 1; + } +@@ -84,6 +113,43 @@ static struct notifier_block crash_nmi_n + .notifier_call = crash_nmi_callback, + }; + ++#ifdef CONFIG_KDB_KDUMP ++static void wait_other_cpus(void) ++{ ++ unsigned long msecs; ++ ++ msecs = 1000; /* Wait at most a second for the other cpus to stop */ ++ while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { ++ udelay(1000); ++ msecs--; ++ } ++} ++ ++static void nmi_shootdown_cpus_init(void) ++{ ++ atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); ++} ++ ++static void nmi_shootdown_cpus(void) ++{ ++ nmi_shootdown_cpus_init(); ++ ++ /* Would it be better to replace the trap vector here? */ ++ if (register_die_notifier(&crash_nmi_nb)) ++ return; /* return what? */ ++ /* Ensure the new callback function is set before sending ++ * out the NMI ++ */ ++ wmb(); ++ ++ smp_send_nmi_allbutself(); ++ ++ wait_other_cpus(); ++ /* Leave the nmi callback set */ ++ ++ disable_local_APIC(); ++} ++#else + static void nmi_shootdown_cpus(void) + { + unsigned long msecs; +@@ -108,12 +174,22 @@ static void nmi_shootdown_cpus(void) + /* Leave the nmi callback set */ + disable_local_APIC(); + } +-#else ++#endif /* !CONFIG_KDB_KDUMP */ ++ ++#else /* defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) */ ++ + static void nmi_shootdown_cpus(void) + { + /* There are no cpus to shootdown */ + } +-#endif ++ ++#ifdef CONFIG_KDB_KDUMP ++static void nmi_shootdown_cpus_init(void) {}; ++static void wait_other_cpus() {} ++static void halt_current_cpu(struct pt_regs *regs) {}; ++#endif /* CONFIG_KDB_KDUMP */ ++ ++#endif /* defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) */ + + void native_machine_crash_shutdown(struct pt_regs *regs) + { +@@ -140,3 +216,33 @@ void native_machine_crash_shutdown(struc + #endif + crash_save_cpu(regs, safe_smp_processor_id()); + } ++ ++#ifdef CONFIG_KDB_KDUMP ++void machine_crash_shutdown_begin(void) ++{ ++ local_irq_disable(); ++ ++ /* Make a note of crashing cpu. Will be used in NMI callback.*/ ++ crashing_cpu = safe_smp_processor_id(); ++#ifndef CONFIG_XEN ++ nmi_shootdown_cpus_init(); ++#endif /* CONFIG_XEN */ ++} ++ ++void machine_crash_shutdown_end(struct pt_regs *regs) ++{ ++#ifndef CONFIG_XEN ++ wait_other_cpus(); ++ ++ local_irq_disable(); ++ lapic_shutdown(); ++#if defined(CONFIG_X86_IO_APIC) ++ disable_IO_APIC(); ++#endif ++#ifdef CONFIG_HPET_TIMER ++ hpet_disable(); ++#endif ++#endif /* CONFIG_XEN */ ++ crash_save_cpu(regs,safe_smp_processor_id()); ++} ++#endif /* CONFIG_KDB_KDUMP */ +--- a/arch/x86/kernel/entry_32.S ++++ b/arch/x86/kernel/entry_32.S +@@ -1015,6 +1015,26 @@ ENTRY(alignment_check) + CFI_ENDPROC + END(alignment_check) + ++#ifdef CONFIG_KDB ++ ++ENTRY(kdb_call) ++ RING0_INT_FRAME ++ pushl %eax # save orig EAX ++ CFI_ADJUST_CFA_OFFSET 4 ++ SAVE_ALL ++ movl %esp,%ecx # struct pt_regs ++ movl $0,%edx # error_code ++ movl $1,%eax # KDB_REASON_ENTER ++ call kdb ++ jmp restore_all ++ CFI_ENDPROC ++ ++#ifdef CONFIG_SMP ++BUILD_INTERRUPT(kdb_interrupt,KDB_VECTOR) ++#endif /* CONFIG_SMP */ ++ ++#endif /* CONFIG_KDB */ ++ + ENTRY(divide_error) + RING0_INT_FRAME + pushl $0 # no error code +--- a/arch/x86/kernel/entry_64.S ++++ b/arch/x86/kernel/entry_64.S +@@ -1467,3 +1467,30 @@ ENTRY(xen_failsafe_callback) + END(xen_failsafe_callback) + + #endif /* CONFIG_XEN */ ++ ++#ifdef CONFIG_KDB ++ ++#ifdef CONFIG_SMP ++ENTRY(kdb_interrupt) ++ apicinterrupt KDB_VECTOR,smp_kdb_interrupt ++END(kdb_interrupt) ++#endif /* CONFIG_SMP */ ++ ++ENTRY(kdb_call) ++ INTR_FRAME ++ cld ++ pushq $-1 # orig_eax ++ CFI_ADJUST_CFA_OFFSET 8 ++ SAVE_ALL ++ movq $1,%rdi # KDB_REASON_ENTER ++ movq $0,%rsi # error_code ++ movq %rsp,%rdx # struct pt_regs ++ call kdb ++ RESTORE_ALL ++ addq $8,%rsp # forget orig_eax ++ CFI_ADJUST_CFA_OFFSET -8 ++ iretq ++ CFI_ENDPROC ++END(kdb_call) ++ ++#endif /* CONFIG_KDB */ +--- a/arch/x86/kernel/io_apic_32.c ++++ b/arch/x86/kernel/io_apic_32.c +@@ -33,6 +33,10 @@ + #include + #include + #include ++ ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ + #include + #include + #include +@@ -1189,6 +1193,10 @@ next: + return -ENOSPC; + if (test_and_set_bit(vector, used_vectors)) + goto next; ++#ifdef CONFIG_KDB ++ if (vector == KDBENTER_VECTOR) ++ goto next; ++#endif + + current_vector = vector; + current_offset = offset; +--- a/arch/x86/kernel/io_apic_64.c ++++ b/arch/x86/kernel/io_apic_64.c +@@ -39,6 +39,10 @@ + #include + #include + ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ ++ + #include + #include + #include +@@ -853,6 +857,10 @@ next: + continue; + if (vector == IA32_SYSCALL_VECTOR) + goto next; ++#ifdef CONFIG_KDB ++ if (vector == KDBENTER_VECTOR) ++ goto next; ++#endif /* CONFIG_KDB */ + for_each_cpu_mask_and(new_cpu, tmp_mask, cpu_online_map) + if (per_cpu(vector_irq, new_cpu)[vector] != -1) + goto next; +--- a/arch/x86/kernel/reboot.c ++++ b/arch/x86/kernel/reboot.c +@@ -3,6 +3,9 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ + #include + #include + #include +@@ -455,6 +458,14 @@ void native_machine_shutdown(void) + /* Make certain I only run on the appropriate processor */ + set_cpus_allowed_ptr(current, &cpumask_of_cpu(reboot_cpu_id)); + ++#if defined(CONFIG_X86_32) && defined(CONFIG_KDB) ++ /* ++ * If this restart is occuring while kdb is running (e.g. reboot ++ * command), the other CPU's are already stopped. Don't try to ++ * stop them yet again. ++ */ ++ if (!KDB_IS_RUNNING()) ++#endif /* defined(CONFIG_X86_32) && defined(CONFIG_KDB) */ + /* O.K Now that I'm on the appropriate processor, + * stop all of the others. + */ +--- a/arch/x86/kernel/traps_32.c ++++ b/arch/x86/kernel/traps_32.c +@@ -46,6 +46,10 @@ + #include + #endif + ++#ifdef CONFIG_KDB ++#include ++#endif /* CONFIG_KDB */ ++ + #include + #include + #include +@@ -395,6 +399,9 @@ void __kprobes oops_end(unsigned long fl + add_taint(TAINT_DIE); + __raw_spin_unlock(&die_lock); + raw_local_irq_restore(flags); ++#ifdef CONFIG_KDB ++ kdb(KDB_REASON_OOPS, signr, regs); ++#endif /* CONFIG_KDB */ + + if (!regs) + return; +@@ -465,6 +472,9 @@ void die(const char *str, struct pt_regs + printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); + } + ++#ifdef CONFIG_KDB ++ kdb_diemsg = str; ++#endif /* CONFIG_KDB */ + oops_end(flags, regs, SIGSEGV); + } + +@@ -575,7 +585,7 @@ void do_##name(struct pt_regs *regs, lon + } + + DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) +-#ifndef CONFIG_KPROBES ++#if !defined(CONFIG_KPROBES) && !defined(CONFIG_KDB) + DO_VM86_ERROR(3, SIGTRAP, "int3", int3) + #endif + DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow) +@@ -718,6 +728,10 @@ io_check_error(unsigned char reason, str + static notrace __kprobes void + unknown_nmi_error(unsigned char reason, struct pt_regs *regs) + { ++#ifdef CONFIG_KDB ++ (void)kdb(KDB_REASON_NMI, reason, regs); ++#endif /* CONFIG_KDB */ ++ + if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) + return; + #ifdef CONFIG_MCA +@@ -758,6 +772,9 @@ void notrace __kprobes die_nmi(char *str + printk(" on CPU%d, ip %08lx, registers:\n", + smp_processor_id(), regs->ip); + show_registers(regs); ++#ifdef CONFIG_KDB ++ kdb(KDB_REASON_NMI, 0, regs); ++#endif /* CONFIG_KDB */ + if (do_panic) + panic("Non maskable interrupt"); + console_silent(); +@@ -787,6 +804,16 @@ static notrace __kprobes void default_do + if (!cpu) + reason = get_nmi_reason(); + ++#if defined(CONFIG_SMP) && defined(CONFIG_KDB) ++ /* ++ * Call the kernel debugger to see if this NMI is due ++ * to an KDB requested IPI. If so, kdb will handle it. ++ */ ++ if (kdb_ipi(regs, NULL)) { ++ return; ++ } ++#endif /* defined(CONFIG_SMP) && defined(CONFIG_KDB) */ ++ + if (!(reason & 0xc0)) { + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) +@@ -854,6 +881,10 @@ void __kprobes do_int3(struct pt_regs *r + { + trace_hardirqs_fixup(); + ++#ifdef CONFIG_KDB ++ if (kdb(KDB_REASON_BREAK, error_code, regs)) ++ return; ++#endif + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return; +@@ -904,6 +935,11 @@ void __kprobes do_debug(struct pt_regs * + clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR); + tsk->thread.debugctlmsr = 0; + ++#ifdef CONFIG_KDB ++ if (kdb(KDB_REASON_DEBUG, error_code, regs)) ++ return; ++#endif /* CONFIG_KDB */ ++ + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, + SIGTRAP) == NOTIFY_STOP) + return; +@@ -958,6 +994,16 @@ clear_TF_reenable: + return; + } + ++#if defined(CONFIG_KDB) && !defined(CONFIG_KPROBES) ++void do_int3(struct pt_regs * regs, long error_code) ++{ ++ if (kdb(KDB_REASON_BREAK, error_code, regs)) ++ return; ++ do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); ++} ++#endif /* CONFIG_KDB && !CONFIG_KPROBES */ ++ ++ + /* + * Note that we play around with the 'TS' bit in an attempt to get + * the correct behaviour even in the presence of the asynchronous +--- a/arch/x86/kernel/traps_64.c ++++ b/arch/x86/kernel/traps_64.c +@@ -583,6 +583,8 @@ die_nmi(char *str, struct pt_regs *regs, + printk(" on CPU%d, ip %08lx, registers:\n", + smp_processor_id(), regs->ip); + show_registers(regs); ++ if (strncmp(str, "NMI Watchdog", 12) == 0) ++ notify_die(DIE_NMIWATCHDOG, "nmi_watchdog", regs, 0, 2, SIGINT); + if (kexec_should_crash(current)) + crash_kexec(regs); + if (do_panic || panic_on_oops) +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -171,6 +171,9 @@ ifeq ($(CONFIG_X86_32),y) + drivers-$(CONFIG_FB) += arch/x86/video/ + endif + ++# KDB support ++drivers-$(CONFIG_KDB) += arch/x86/kdb/ ++ + #### + # boot loader support. Several targets are kept for legacy purposes + +--- /dev/null ++++ b/include/asm-x86/ansidecl_32.h +@@ -0,0 +1,383 @@ ++/* ANSI and traditional C compatability macros ++ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 ++ Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++/* ANSI and traditional C compatibility macros ++ ++ ANSI C is assumed if __STDC__ is #defined. ++ ++ Macro ANSI C definition Traditional C definition ++ ----- ---- - ---------- ----------- - ---------- ++ ANSI_PROTOTYPES 1 not defined ++ PTR `void *' `char *' ++ PTRCONST `void *const' `char *' ++ LONG_DOUBLE `long double' `double' ++ const not defined `' ++ volatile not defined `' ++ signed not defined `' ++ VA_START(ap, var) va_start(ap, var) va_start(ap) ++ ++ Note that it is safe to write "void foo();" indicating a function ++ with no return value, in all K+R compilers we have been able to test. ++ ++ For declaring functions with prototypes, we also provide these: ++ ++ PARAMS ((prototype)) ++ -- for functions which take a fixed number of arguments. Use this ++ when declaring the function. When defining the function, write a ++ K+R style argument list. For example: ++ ++ char *strcpy PARAMS ((char *dest, char *source)); ++ ... ++ char * ++ strcpy (dest, source) ++ char *dest; ++ char *source; ++ { ... } ++ ++ ++ VPARAMS ((prototype, ...)) ++ -- for functions which take a variable number of arguments. Use ++ PARAMS to declare the function, VPARAMS to define it. For example: ++ ++ int printf PARAMS ((const char *format, ...)); ++ ... ++ int ++ printf VPARAMS ((const char *format, ...)) ++ { ++ ... ++ } ++ ++ For writing functions which take variable numbers of arguments, we ++ also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These ++ hide the differences between K+R and C89 more ++ thoroughly than the simple VA_START() macro mentioned above. ++ ++ VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. ++ Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls ++ corresponding to the list of fixed arguments. Then use va_arg ++ normally to get the variable arguments, or pass your va_list object ++ around. You do not declare the va_list yourself; VA_OPEN does it ++ for you. ++ ++ Here is a complete example: ++ ++ int ++ printf VPARAMS ((const char *format, ...)) ++ { ++ int result; ++ ++ VA_OPEN (ap, format); ++ VA_FIXEDARG (ap, const char *, format); ++ ++ result = vfprintf (stdout, format, ap); ++ VA_CLOSE (ap); ++ ++ return result; ++ } ++ ++ ++ You can declare variables either before or after the VA_OPEN, ++ VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning ++ and end of a block. They must appear at the same nesting level, ++ and any variables declared after VA_OPEN go out of scope at ++ VA_CLOSE. Unfortunately, with a K+R compiler, that includes the ++ argument list. You can have multiple instances of VA_OPEN/VA_CLOSE ++ pairs in a single function in case you need to traverse the ++ argument list more than once. ++ ++ For ease of writing code which uses GCC extensions but needs to be ++ portable to other compilers, we provide the GCC_VERSION macro that ++ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various ++ wrappers around __attribute__. Also, __extension__ will be #defined ++ to nothing if it doesn't work. See below. ++ ++ This header also defines a lot of obsolete macros: ++ CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID, ++ AND, DOTS, NOARGS. Don't use them. */ ++ ++#ifndef _ANSIDECL_H ++#define _ANSIDECL_H 1 ++ ++/* Every source file includes this file, ++ so they will all get the switch for lint. */ ++/* LINTLIBRARY */ ++ ++/* Using MACRO(x,y) in cpp #if conditionals does not work with some ++ older preprocessors. Thus we can't define something like this: ++ ++#define HAVE_GCC_VERSION(MAJOR, MINOR) \ ++ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) ++ ++and then test "#if HAVE_GCC_VERSION(2,7)". ++ ++So instead we use the macro below and test it against specific values. */ ++ ++/* This macro simplifies testing whether we are using gcc, and if it ++ is of a particular minimum version. (Both major & minor numbers are ++ significant.) This macro will evaluate to 0 if we are not using ++ gcc at all. */ ++#ifndef GCC_VERSION ++#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) ++#endif /* GCC_VERSION */ ++ ++#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus)) ++/* All known AIX compilers implement these things (but don't always ++ define __STDC__). The RISC/OS MIPS compiler defines these things ++ in SVR4 mode, but does not define __STDC__. */ ++/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other ++ C++ compilers, does not define __STDC__, though it acts as if this ++ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ ++ ++#define ANSI_PROTOTYPES 1 ++#define PTR void * ++#define PTRCONST void *const ++#define LONG_DOUBLE long double ++ ++/* PARAMS is often defined elsewhere (e.g. by libintl.h), so wrap it in ++ a #ifndef. */ ++#ifndef PARAMS ++#define PARAMS(ARGS) ARGS ++#endif ++ ++#define VPARAMS(ARGS) ARGS ++#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR) ++ ++/* variadic function helper macros */ ++/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's ++ use without inhibiting further decls and without declaring an ++ actual variable. */ ++#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy ++#define VA_CLOSE(AP) } va_end(AP); } ++#define VA_FIXEDARG(AP, T, N) struct Qdmy ++ ++#undef const ++#undef volatile ++#undef signed ++ ++#ifdef __KERNEL__ ++#ifndef __STDC_VERSION__ ++#define __STDC_VERSION__ 0 ++#endif ++#endif /* __KERNEL__ */ ++ ++/* inline requires special treatment; it's in C99, and GCC >=2.7 supports ++ it too, but it's not in C89. */ ++#undef inline ++#if __STDC_VERSION__ > 199901L ++/* it's a keyword */ ++#else ++# if GCC_VERSION >= 2007 ++# define inline __inline__ /* __inline__ prevents -pedantic warnings */ ++# else ++# define inline /* nothing */ ++# endif ++#endif ++ ++/* These are obsolete. Do not use. */ ++#ifndef IN_GCC ++#define CONST const ++#define VOLATILE volatile ++#define SIGNED signed ++ ++#define PROTO(type, name, arglist) type name arglist ++#define EXFUN(name, proto) name proto ++#define DEFUN(name, arglist, args) name(args) ++#define DEFUN_VOID(name) name(void) ++#define AND , ++#define DOTS , ... ++#define NOARGS void ++#endif /* ! IN_GCC */ ++ ++#else /* Not ANSI C. */ ++ ++#undef ANSI_PROTOTYPES ++#define PTR char * ++#define PTRCONST PTR ++#define LONG_DOUBLE double ++ ++#define PARAMS(args) () ++#define VPARAMS(args) (va_alist) va_dcl ++#define VA_START(va_list, var) va_start(va_list) ++ ++#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy ++#define VA_CLOSE(AP) } va_end(AP); } ++#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE) ++ ++/* some systems define these in header files for non-ansi mode */ ++#undef const ++#undef volatile ++#undef signed ++#undef inline ++#define const ++#define volatile ++#define signed ++#define inline ++ ++#ifndef IN_GCC ++#define CONST ++#define VOLATILE ++#define SIGNED ++ ++#define PROTO(type, name, arglist) type name () ++#define EXFUN(name, proto) name() ++#define DEFUN(name, arglist, args) name arglist args; ++#define DEFUN_VOID(name) name() ++#define AND ; ++#define DOTS ++#define NOARGS ++#endif /* ! IN_GCC */ ++ ++#endif /* ANSI C. */ ++ ++/* Define macros for some gcc attributes. This permits us to use the ++ macros freely, and know that they will come into play for the ++ version of gcc in which they are supported. */ ++ ++#if (GCC_VERSION < 2007) ++# define __attribute__(x) ++#endif ++ ++/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ ++#ifndef ATTRIBUTE_MALLOC ++# if (GCC_VERSION >= 2096) ++# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) ++# else ++# define ATTRIBUTE_MALLOC ++# endif /* GNUC >= 2.96 */ ++#endif /* ATTRIBUTE_MALLOC */ ++ ++/* Attributes on labels were valid as of gcc 2.93. */ ++#ifndef ATTRIBUTE_UNUSED_LABEL ++# if (!defined (__cplusplus) && GCC_VERSION >= 2093) ++# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ++# else ++# define ATTRIBUTE_UNUSED_LABEL ++# endif /* !__cplusplus && GNUC >= 2.93 */ ++#endif /* ATTRIBUTE_UNUSED_LABEL */ ++ ++#ifndef ATTRIBUTE_UNUSED ++#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) ++#endif /* ATTRIBUTE_UNUSED */ ++ ++/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the ++ identifier name. */ ++#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) ++# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED ++#else /* !__cplusplus || GNUC >= 3.4 */ ++# define ARG_UNUSED(NAME) NAME ++#endif /* !__cplusplus || GNUC >= 3.4 */ ++ ++#ifndef ATTRIBUTE_NORETURN ++#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) ++#endif /* ATTRIBUTE_NORETURN */ ++ ++/* Attribute `nonnull' was valid as of gcc 3.3. */ ++#ifndef ATTRIBUTE_NONNULL ++# if (GCC_VERSION >= 3003) ++# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) ++# else ++# define ATTRIBUTE_NONNULL(m) ++# endif /* GNUC >= 3.3 */ ++#endif /* ATTRIBUTE_NONNULL */ ++ ++/* Attribute `pure' was valid as of gcc 3.0. */ ++#ifndef ATTRIBUTE_PURE ++# if (GCC_VERSION >= 3000) ++# define ATTRIBUTE_PURE __attribute__ ((__pure__)) ++# else ++# define ATTRIBUTE_PURE ++# endif /* GNUC >= 3.0 */ ++#endif /* ATTRIBUTE_PURE */ ++ ++/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. ++ This was the case for the `printf' format attribute by itself ++ before GCC 3.3, but as of 3.3 we need to add the `nonnull' ++ attribute to retain this behavior. */ ++#ifndef ATTRIBUTE_PRINTF ++#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) ++#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) ++#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) ++#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) ++#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) ++#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) ++#endif /* ATTRIBUTE_PRINTF */ ++ ++/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on ++ a function pointer. Format attributes were allowed on function ++ pointers as of gcc 3.1. */ ++#ifndef ATTRIBUTE_FPTR_PRINTF ++# if (GCC_VERSION >= 3001) ++# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) ++# else ++# define ATTRIBUTE_FPTR_PRINTF(m, n) ++# endif /* GNUC >= 3.1 */ ++# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) ++# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) ++# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) ++# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) ++# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) ++#endif /* ATTRIBUTE_FPTR_PRINTF */ ++ ++/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A ++ NULL format specifier was allowed as of gcc 3.3. */ ++#ifndef ATTRIBUTE_NULL_PRINTF ++# if (GCC_VERSION >= 3003) ++# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ++# else ++# define ATTRIBUTE_NULL_PRINTF(m, n) ++# endif /* GNUC >= 3.3 */ ++# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) ++# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) ++# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) ++# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) ++# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) ++#endif /* ATTRIBUTE_NULL_PRINTF */ ++ ++/* Attribute `sentinel' was valid as of gcc 3.5. */ ++#ifndef ATTRIBUTE_SENTINEL ++# if (GCC_VERSION >= 3005) ++# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) ++# else ++# define ATTRIBUTE_SENTINEL ++# endif /* GNUC >= 3.5 */ ++#endif /* ATTRIBUTE_SENTINEL */ ++ ++ ++#ifndef ATTRIBUTE_ALIGNED_ALIGNOF ++# if (GCC_VERSION >= 3000) ++# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) ++# else ++# define ATTRIBUTE_ALIGNED_ALIGNOF(m) ++# endif /* GNUC >= 3.0 */ ++#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ ++ ++/* We use __extension__ in some places to suppress -pedantic warnings ++ about GCC extensions. This feature didn't work properly before ++ gcc 2.8. */ ++#if GCC_VERSION < 2008 ++#define __extension__ ++#endif ++ ++#endif /* ansidecl.h */ +--- /dev/null ++++ b/include/asm-x86/ansidecl_64.h +@@ -0,0 +1,383 @@ ++/* ANSI and traditional C compatability macros ++ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 ++ Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++This program is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2 of the License, or ++(at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++/* ANSI and traditional C compatibility macros ++ ++ ANSI C is assumed if __STDC__ is #defined. ++ ++ Macro ANSI C definition Traditional C definition ++ ----- ---- - ---------- ----------- - ---------- ++ ANSI_PROTOTYPES 1 not defined ++ PTR `void *' `char *' ++ PTRCONST `void *const' `char *' ++ LONG_DOUBLE `long double' `double' ++ const not defined `' ++ volatile not defined `' ++ signed not defined `' ++ VA_START(ap, var) va_start(ap, var) va_start(ap) ++ ++ Note that it is safe to write "void foo();" indicating a function ++ with no return value, in all K+R compilers we have been able to test. ++ ++ For declaring functions with prototypes, we also provide these: ++ ++ PARAMS ((prototype)) ++ -- for functions which take a fixed number of arguments. Use this ++ when declaring the function. When defining the function, write a ++ K+R style argument list. For example: ++ ++ char *strcpy PARAMS ((char *dest, char *source)); ++ ... ++ char * ++ strcpy (dest, source) ++ char *dest; ++ char *source; ++ { ... } ++ ++ ++ VPARAMS ((prototype, ...)) ++ -- for functions which take a variable number of arguments. Use ++ PARAMS to declare the function, VPARAMS to define it. For example: ++ ++ int printf PARAMS ((const char *format, ...)); ++ ... ++ int ++ printf VPARAMS ((const char *format, ...)) ++ { ++ ... ++ } ++ ++ For writing functions which take variable numbers of arguments, we ++ also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These ++ hide the differences between K+R and C89 more ++ thoroughly than the simple VA_START() macro mentioned above. ++ ++ VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. ++ Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls ++ corresponding to the list of fixed arguments. Then use va_arg ++ normally to get the variable arguments, or pass your va_list object ++ around. You do not declare the va_list yourself; VA_OPEN does it ++ for you. ++ ++ Here is a complete example: ++ ++ int ++ printf VPARAMS ((const char *format, ...)) ++ { ++ int result; ++ ++ VA_OPEN (ap, format); ++ VA_FIXEDARG (ap, const char *, format); ++ ++ result = vfprintf (stdout, format, ap); ++ VA_CLOSE (ap); ++ ++ return result; ++ } ++ ++ ++ You can declare variables either before or after the VA_OPEN, ++ VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning ++ and end of a block. They must appear at the same nesting level, ++ and any variables declared after VA_OPEN go out of scope at ++ VA_CLOSE. Unfortunately, with a K+R compiler, that includes the ++ argument list. You can have multiple instances of VA_OPEN/VA_CLOSE ++ pairs in a single function in case you need to traverse the ++ argument list more than once. ++ ++ For ease of writing code which uses GCC extensions but needs to be ++ portable to other compilers, we provide the GCC_VERSION macro that ++ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various ++ wrappers around __attribute__. Also, __extension__ will be #defined ++ to nothing if it doesn't work. See below. ++ ++ This header also defines a lot of obsolete macros: ++ CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID, ++ AND, DOTS, NOARGS. Don't use them. */ ++ ++#ifndef _ANSIDECL_H ++#define _ANSIDECL_H 1 ++ ++/* Every source file includes this file, ++ so they will all get the switch for lint. */ ++/* LINTLIBRARY */ ++ ++/* Using MACRO(x,y) in cpp #if conditionals does not work with some ++ older preprocessors. Thus we can't define something like this: ++ ++#define HAVE_GCC_VERSION(MAJOR, MINOR) \ ++ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) ++ ++and then test "#if HAVE_GCC_VERSION(2,7)". ++ ++So instead we use the macro below and test it against specific values. */ ++ ++/* This macro simplifies testing whether we are using gcc, and if it ++ is of a particular minimum version. (Both major & minor numbers are ++ significant.) This macro will evaluate to 0 if we are not using ++ gcc at all. */ ++#ifndef GCC_VERSION ++#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) ++#endif /* GCC_VERSION */ ++ ++#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus)) ++/* All known AIX compilers implement these things (but don't always ++ define __STDC__). The RISC/OS MIPS compiler defines these things ++ in SVR4 mode, but does not define __STDC__. */ ++/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other ++ C++ compilers, does not define __STDC__, though it acts as if this ++ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ ++ ++#define ANSI_PROTOTYPES 1 ++#define PTR void * ++#define PTRCONST void *const ++#define LONG_DOUBLE long double ++ ++/* PARAMS is often defined elsewhere (e.g. by libintl.h), so wrap it in ++ a #ifndef. */ ++#ifndef PARAMS ++#define PARAMS(ARGS) ARGS ++#endif ++ ++#define VPARAMS(ARGS) ARGS ++#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR) ++ ++/* variadic function helper macros */ ++/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's ++ use without inhibiting further decls and without declaring an ++ actual variable. */ ++#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy ++#define VA_CLOSE(AP) } va_end(AP); } ++#define VA_FIXEDARG(AP, T, N) struct Qdmy ++ ++#undef const ++#undef volatile ++#undef signed ++ ++#ifdef __KERNEL__ ++#ifndef __STDC_VERSION__ ++#define __STDC_VERSION__ 0 ++#endif ++#endif /* __KERNEL__ */ ++ ++/* inline requires special treatment; it's in C99, and GCC >=2.7 supports ++ it too, but it's not in C89. */ ++#undef inline ++#if __STDC_VERSION__ > 199901L ++/* it's a keyword */ ++#else ++# if GCC_VERSION >= 2007 ++# define inline __inline__ /* __inline__ prevents -pedantic warnings */ ++# else ++# define inline /* nothing */ ++# endif ++#endif ++ ++/* These are obsolete. Do not use. */ ++#ifndef IN_GCC ++#define CONST const ++#define VOLATILE volatile ++#define SIGNED signed ++ ++#define PROTO(type, name, arglist) type name arglist ++#define EXFUN(name, proto) name proto ++#define DEFUN(name, arglist, args) name(args) ++#define DEFUN_VOID(name) name(void) ++#define AND , ++#define DOTS , ... ++#define NOARGS void ++#endif /* ! IN_GCC */ ++ ++#else /* Not ANSI C. */ ++ ++#undef ANSI_PROTOTYPES ++#define PTR char * ++#define PTRCONST PTR ++#define LONG_DOUBLE double ++ ++#define PARAMS(args) () ++#define VPARAMS(args) (va_alist) va_dcl ++#define VA_START(va_list, var) va_start(va_list) ++ ++#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy ++#define VA_CLOSE(AP) } va_end(AP); } ++#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE) ++ ++/* some systems define these in header files for non-ansi mode */ ++#undef const ++#undef volatile ++#undef signed ++#undef inline ++#define const ++#define volatile ++#define signed ++#define inline ++ ++#ifndef IN_GCC ++#define CONST ++#define VOLATILE ++#define SIGNED ++ ++#define PROTO(type, name, arglist) type name () ++#define EXFUN(name, proto) name() ++#define DEFUN(name, arglist, args) name arglist args; ++#define DEFUN_VOID(name) name() ++#define AND ; ++#define DOTS ++#define NOARGS ++#endif /* ! IN_GCC */ ++ ++#endif /* ANSI C. */ ++ ++/* Define macros for some gcc attributes. This permits us to use the ++ macros freely, and know that they will come into play for the ++ version of gcc in which they are supported. */ ++ ++#if (GCC_VERSION < 2007) ++# define __attribute__(x) ++#endif ++ ++/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ ++#ifndef ATTRIBUTE_MALLOC ++# if (GCC_VERSION >= 2096) ++# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) ++# else ++# define ATTRIBUTE_MALLOC ++# endif /* GNUC >= 2.96 */ ++#endif /* ATTRIBUTE_MALLOC */ ++ ++/* Attributes on labels were valid as of gcc 2.93. */ ++#ifndef ATTRIBUTE_UNUSED_LABEL ++# if (!defined (__cplusplus) && GCC_VERSION >= 2093) ++# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ++# else ++# define ATTRIBUTE_UNUSED_LABEL ++# endif /* !__cplusplus && GNUC >= 2.93 */ ++#endif /* ATTRIBUTE_UNUSED_LABEL */ ++ ++#ifndef ATTRIBUTE_UNUSED ++#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) ++#endif /* ATTRIBUTE_UNUSED */ ++ ++/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the ++ identifier name. */ ++#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) ++# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED ++#else /* !__cplusplus || GNUC >= 3.4 */ ++# define ARG_UNUSED(NAME) NAME ++#endif /* !__cplusplus || GNUC >= 3.4 */ ++ ++#ifndef ATTRIBUTE_NORETURN ++#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) ++#endif /* ATTRIBUTE_NORETURN */ ++ ++/* Attribute `nonnull' was valid as of gcc 3.3. */ ++#ifndef ATTRIBUTE_NONNULL ++# if (GCC_VERSION >= 3003) ++# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) ++# else ++# define ATTRIBUTE_NONNULL(m) ++# endif /* GNUC >= 3.3 */ ++#endif /* ATTRIBUTE_NONNULL */ ++ ++/* Attribute `pure' was valid as of gcc 3.0. */ ++#ifndef ATTRIBUTE_PURE ++# if (GCC_VERSION >= 3000) ++# define ATTRIBUTE_PURE __attribute__ ((__pure__)) ++# else ++# define ATTRIBUTE_PURE ++# endif /* GNUC >= 3.0 */ ++#endif /* ATTRIBUTE_PURE */ ++ ++/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. ++ This was the case for the `printf' format attribute by itself ++ before GCC 3.3, but as of 3.3 we need to add the `nonnull' ++ attribute to retain this behavior. */ ++#ifndef ATTRIBUTE_PRINTF ++#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) ++#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) ++#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) ++#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) ++#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) ++#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) ++#endif /* ATTRIBUTE_PRINTF */ ++ ++/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on ++ a function pointer. Format attributes were allowed on function ++ pointers as of gcc 3.1. */ ++#ifndef ATTRIBUTE_FPTR_PRINTF ++# if (GCC_VERSION >= 3001) ++# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) ++# else ++# define ATTRIBUTE_FPTR_PRINTF(m, n) ++# endif /* GNUC >= 3.1 */ ++# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) ++# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) ++# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) ++# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) ++# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) ++#endif /* ATTRIBUTE_FPTR_PRINTF */ ++ ++/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A ++ NULL format specifier was allowed as of gcc 3.3. */ ++#ifndef ATTRIBUTE_NULL_PRINTF ++# if (GCC_VERSION >= 3003) ++# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ++# else ++# define ATTRIBUTE_NULL_PRINTF(m, n) ++# endif /* GNUC >= 3.3 */ ++# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) ++# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) ++# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) ++# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) ++# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) ++#endif /* ATTRIBUTE_NULL_PRINTF */ ++ ++/* Attribute `sentinel' was valid as of gcc 3.5. */ ++#ifndef ATTRIBUTE_SENTINEL ++# if (GCC_VERSION >= 3005) ++# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) ++# else ++# define ATTRIBUTE_SENTINEL ++# endif /* GNUC >= 3.5 */ ++#endif /* ATTRIBUTE_SENTINEL */ ++ ++ ++#ifndef ATTRIBUTE_ALIGNED_ALIGNOF ++# if (GCC_VERSION >= 3000) ++# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) ++# else ++# define ATTRIBUTE_ALIGNED_ALIGNOF(m) ++# endif /* GNUC >= 3.0 */ ++#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ ++ ++/* We use __extension__ in some places to suppress -pedantic warnings ++ about GCC extensions. This feature didn't work properly before ++ gcc 2.8. */ ++#if GCC_VERSION < 2008 ++#define __extension__ ++#endif ++ ++#endif /* ansidecl.h */ +--- /dev/null ++++ b/include/asm-x86/ansidecl.h +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "ansidecl_32.h" ++#else ++# include "ansidecl_64.h" ++#endif +--- /dev/null ++++ b/include/asm-x86/bfd_32.h +@@ -0,0 +1,4921 @@ ++/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically ++ generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", ++ "bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", ++ "syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c", ++ "linker.c" and "simple.c". ++ Run "make headers" in your build bfd/ to regenerate. */ ++ ++/* Main header file for the bfd library -- portable access to object files. ++ ++ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, ++ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ Contributed by Cygnus Support. ++ ++ This file is part of BFD, the Binary File Descriptor library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef __BFD_H_SEEN__ ++#define __BFD_H_SEEN__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef __KERNEL__ ++#include ++#else /* __KERNEL__ */ ++#include "ansidecl.h" ++#include "symcat.h" ++#endif /* __KERNEL__ */ ++#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) ++#ifndef SABER ++/* This hack is to avoid a problem with some strict ANSI C preprocessors. ++ The problem is, "32_" is not a valid preprocessing token, and we don't ++ want extra underscores (e.g., "nlm_32_"). The XCONCAT2 macro will ++ cause the inner CONCAT2 macros to be evaluated first, producing ++ still-valid pp-tokens. Then the final concatenation can be done. */ ++#undef CONCAT4 ++#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d)) ++#endif ++#endif ++ ++/* The word size used by BFD on the host. This may be 64 with a 32 ++ bit target if the host is 64 bit, or if other 64 bit targets have ++ been selected with --enable-targets, or if --enable-64-bit-bfd. */ ++#ifdef __KERNEL__ ++#define BFD_ARCH_SIZE 32 ++#else /* __KERNEL__ */ ++#define BFD_ARCH_SIZE 64 ++#endif /* __KERNEL__ */ ++ ++/* The word size of the default bfd target. */ ++#define BFD_DEFAULT_TARGET_SIZE 32 ++ ++#define BFD_HOST_64BIT_LONG 0 ++#define BFD_HOST_LONG_LONG 1 ++#if 1 ++#define BFD_HOST_64_BIT long long ++#define BFD_HOST_U_64_BIT unsigned long long ++typedef BFD_HOST_64_BIT bfd_int64_t; ++typedef BFD_HOST_U_64_BIT bfd_uint64_t; ++#endif ++ ++#if BFD_ARCH_SIZE >= 64 ++#define BFD64 ++#endif ++ ++#ifndef INLINE ++#if __GNUC__ >= 2 ++#define INLINE __inline__ ++#else ++#define INLINE ++#endif ++#endif ++ ++/* Forward declaration. */ ++typedef struct bfd bfd; ++ ++/* Boolean type used in bfd. Too many systems define their own ++ versions of "boolean" for us to safely typedef a "boolean" of ++ our own. Using an enum for "bfd_boolean" has its own set of ++ problems, with strange looking casts required to avoid warnings ++ on some older compilers. Thus we just use an int. ++ ++ General rule: Functions which are bfd_boolean return TRUE on ++ success and FALSE on failure (unless they're a predicate). */ ++ ++typedef int bfd_boolean; ++#undef FALSE ++#undef TRUE ++#define FALSE 0 ++#define TRUE 1 ++ ++#ifdef BFD64 ++ ++#ifndef BFD_HOST_64_BIT ++ #error No 64 bit integer type available ++#endif /* ! defined (BFD_HOST_64_BIT) */ ++ ++typedef BFD_HOST_U_64_BIT bfd_vma; ++typedef BFD_HOST_64_BIT bfd_signed_vma; ++typedef BFD_HOST_U_64_BIT bfd_size_type; ++typedef BFD_HOST_U_64_BIT symvalue; ++ ++#ifndef fprintf_vma ++#if BFD_HOST_64BIT_LONG ++#define sprintf_vma(s,x) sprintf (s, "%016lx", x) ++#define fprintf_vma(f,x) fprintf (f, "%016lx", x) ++#else ++#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) ++#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) ++#define fprintf_vma(s,x) \ ++ fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) ++#define sprintf_vma(s,x) \ ++ sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) ++#endif ++#endif ++ ++#else /* not BFD64 */ ++ ++/* Represent a target address. Also used as a generic unsigned type ++ which is guaranteed to be big enough to hold any arithmetic types ++ we need to deal with. */ ++typedef unsigned long bfd_vma; ++ ++/* A generic signed type which is guaranteed to be big enough to hold any ++ arithmetic types we need to deal with. Can be assumed to be compatible ++ with bfd_vma in the same way that signed and unsigned ints are compatible ++ (as parameters, in assignment, etc). */ ++typedef long bfd_signed_vma; ++ ++typedef unsigned long symvalue; ++typedef unsigned long bfd_size_type; ++ ++/* Print a bfd_vma x on stream s. */ ++#define fprintf_vma(s,x) fprintf (s, "%08lx", x) ++#define sprintf_vma(s,x) sprintf (s, "%08lx", x) ++ ++#endif /* not BFD64 */ ++ ++#define HALF_BFD_SIZE_TYPE \ ++ (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) ++ ++#ifndef BFD_HOST_64_BIT ++/* Fall back on a 32 bit type. The idea is to make these types always ++ available for function return types, but in the case that ++ BFD_HOST_64_BIT is undefined such a function should abort or ++ otherwise signal an error. */ ++typedef bfd_signed_vma bfd_int64_t; ++typedef bfd_vma bfd_uint64_t; ++#endif ++ ++/* An offset into a file. BFD always uses the largest possible offset ++ based on the build time availability of fseek, fseeko, or fseeko64. */ ++typedef BFD_HOST_64_BIT file_ptr; ++typedef unsigned BFD_HOST_64_BIT ufile_ptr; ++ ++extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); ++extern void bfd_fprintf_vma (bfd *, void *, bfd_vma); ++ ++#define printf_vma(x) fprintf_vma(stdout,x) ++#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x) ++ ++typedef unsigned int flagword; /* 32 bits of flags */ ++typedef unsigned char bfd_byte; ++ ++/* File formats. */ ++ ++typedef enum bfd_format ++{ ++ bfd_unknown = 0, /* File format is unknown. */ ++ bfd_object, /* Linker/assembler/compiler output. */ ++ bfd_archive, /* Object archive file. */ ++ bfd_core, /* Core dump. */ ++ bfd_type_end /* Marks the end; don't use it! */ ++} ++bfd_format; ++ ++/* Values that may appear in the flags field of a BFD. These also ++ appear in the object_flags field of the bfd_target structure, where ++ they indicate the set of flags used by that backend (not all flags ++ are meaningful for all object file formats) (FIXME: at the moment, ++ the object_flags values have mostly just been copied from backend ++ to another, and are not necessarily correct). */ ++ ++/* No flags. */ ++#define BFD_NO_FLAGS 0x00 ++ ++/* BFD contains relocation entries. */ ++#define HAS_RELOC 0x01 ++ ++/* BFD is directly executable. */ ++#define EXEC_P 0x02 ++ ++/* BFD has line number information (basically used for F_LNNO in a ++ COFF header). */ ++#define HAS_LINENO 0x04 ++ ++/* BFD has debugging information. */ ++#define HAS_DEBUG 0x08 ++ ++/* BFD has symbols. */ ++#define HAS_SYMS 0x10 ++ ++/* BFD has local symbols (basically used for F_LSYMS in a COFF ++ header). */ ++#define HAS_LOCALS 0x20 ++ ++/* BFD is a dynamic object. */ ++#define DYNAMIC 0x40 ++ ++/* Text section is write protected (if D_PAGED is not set, this is ++ like an a.out NMAGIC file) (the linker sets this by default, but ++ clears it for -r or -N). */ ++#define WP_TEXT 0x80 ++ ++/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the ++ linker sets this by default, but clears it for -r or -n or -N). */ ++#define D_PAGED 0x100 ++ ++/* BFD is relaxable (this means that bfd_relax_section may be able to ++ do something) (sometimes bfd_relax_section can do something even if ++ this is not set). */ ++#define BFD_IS_RELAXABLE 0x200 ++ ++/* This may be set before writing out a BFD to request using a ++ traditional format. For example, this is used to request that when ++ writing out an a.out object the symbols not be hashed to eliminate ++ duplicates. */ ++#define BFD_TRADITIONAL_FORMAT 0x400 ++ ++/* This flag indicates that the BFD contents are actually cached in ++ memory. If this is set, iostream points to a bfd_in_memory struct. */ ++#define BFD_IN_MEMORY 0x800 ++ ++/* The sections in this BFD specify a memory page. */ ++#define HAS_LOAD_PAGE 0x1000 ++ ++/* This BFD has been created by the linker and doesn't correspond ++ to any input file. */ ++#define BFD_LINKER_CREATED 0x2000 ++ ++/* Symbols and relocation. */ ++ ++/* A count of carsyms (canonical archive symbols). */ ++typedef unsigned long symindex; ++ ++/* How to perform a relocation. */ ++typedef const struct reloc_howto_struct reloc_howto_type; ++ ++#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) ++ ++/* General purpose part of a symbol X; ++ target specific parts are in libcoff.h, libaout.h, etc. */ ++ ++#define bfd_get_section(x) ((x)->section) ++#define bfd_get_output_section(x) ((x)->section->output_section) ++#define bfd_set_section(x,y) ((x)->section) = (y) ++#define bfd_asymbol_base(x) ((x)->section->vma) ++#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) ++#define bfd_asymbol_name(x) ((x)->name) ++/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ ++#define bfd_asymbol_bfd(x) ((x)->the_bfd) ++#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) ++ ++/* A canonical archive symbol. */ ++/* This is a type pun with struct ranlib on purpose! */ ++typedef struct carsym ++{ ++ char *name; ++ file_ptr file_offset; /* Look here to find the file. */ ++} ++carsym; /* To make these you call a carsymogen. */ ++ ++/* Used in generating armaps (archive tables of contents). ++ Perhaps just a forward definition would do? */ ++struct orl /* Output ranlib. */ ++{ ++ char **name; /* Symbol name. */ ++ union ++ { ++ file_ptr pos; ++ bfd *abfd; ++ } u; /* bfd* or file position. */ ++ int namidx; /* Index into string table. */ ++}; ++ ++/* Linenumber stuff. */ ++typedef struct lineno_cache_entry ++{ ++ unsigned int line_number; /* Linenumber from start of function. */ ++ union ++ { ++ struct bfd_symbol *sym; /* Function name. */ ++ bfd_vma offset; /* Offset into section. */ ++ } u; ++} ++alent; ++ ++/* Object and core file sections. */ ++ ++#define align_power(addr, align) \ ++ (((addr) + ((bfd_vma) 1 << (align)) - 1) & ((bfd_vma) -1 << (align))) ++ ++typedef struct bfd_section *sec_ptr; ++ ++#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) ++#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) ++#define bfd_get_section_lma(bfd, ptr) ((ptr)->lma + 0) ++#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) ++#define bfd_section_name(bfd, ptr) ((ptr)->name) ++#define bfd_section_size(bfd, ptr) ((ptr)->size) ++#define bfd_get_section_size(ptr) ((ptr)->size) ++#define bfd_section_vma(bfd, ptr) ((ptr)->vma) ++#define bfd_section_lma(bfd, ptr) ((ptr)->lma) ++#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) ++#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) ++#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) ++ ++#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) ++ ++#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) ++#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) ++#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) ++/* Find the address one past the end of SEC. */ ++#define bfd_get_section_limit(bfd, sec) \ ++ (((sec)->rawsize ? (sec)->rawsize : (sec)->size) \ ++ / bfd_octets_per_byte (bfd)) ++ ++typedef struct stat stat_type; ++ ++typedef enum bfd_print_symbol ++{ ++ bfd_print_symbol_name, ++ bfd_print_symbol_more, ++ bfd_print_symbol_all ++} bfd_print_symbol_type; ++ ++/* Information about a symbol that nm needs. */ ++ ++typedef struct _symbol_info ++{ ++ symvalue value; ++ char type; ++ const char *name; /* Symbol name. */ ++ unsigned char stab_type; /* Stab type. */ ++ char stab_other; /* Stab other. */ ++ short stab_desc; /* Stab desc. */ ++ const char *stab_name; /* String for stab type. */ ++} symbol_info; ++ ++/* Get the name of a stabs type code. */ ++ ++extern const char *bfd_get_stab_name (int); ++ ++/* Hash table routines. There is no way to free up a hash table. */ ++ ++/* An element in the hash table. Most uses will actually use a larger ++ structure, and an instance of this will be the first field. */ ++ ++struct bfd_hash_entry ++{ ++ /* Next entry for this hash code. */ ++ struct bfd_hash_entry *next; ++ /* String being hashed. */ ++ const char *string; ++ /* Hash code. This is the full hash code, not the index into the ++ table. */ ++ unsigned long hash; ++}; ++ ++/* A hash table. */ ++ ++struct bfd_hash_table ++{ ++ /* The hash array. */ ++ struct bfd_hash_entry **table; ++ /* The number of slots in the hash table. */ ++ unsigned int size; ++ /* A function used to create new elements in the hash table. The ++ first entry is itself a pointer to an element. When this ++ function is first invoked, this pointer will be NULL. However, ++ having the pointer permits a hierarchy of method functions to be ++ built each of which calls the function in the superclass. Thus ++ each function should be written to allocate a new block of memory ++ only if the argument is NULL. */ ++ struct bfd_hash_entry *(*newfunc) ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++ /* An objalloc for this hash table. This is a struct objalloc *, ++ but we use void * to avoid requiring the inclusion of objalloc.h. */ ++ void *memory; ++}; ++ ++/* Initialize a hash table. */ ++extern bfd_boolean bfd_hash_table_init ++ (struct bfd_hash_table *, ++ struct bfd_hash_entry *(*) (struct bfd_hash_entry *, ++ struct bfd_hash_table *, ++ const char *)); ++ ++/* Initialize a hash table specifying a size. */ ++extern bfd_boolean bfd_hash_table_init_n ++ (struct bfd_hash_table *, ++ struct bfd_hash_entry *(*) (struct bfd_hash_entry *, ++ struct bfd_hash_table *, ++ const char *), ++ unsigned int size); ++ ++/* Free up a hash table. */ ++extern void bfd_hash_table_free ++ (struct bfd_hash_table *); ++ ++/* Look up a string in a hash table. If CREATE is TRUE, a new entry ++ will be created for this string if one does not already exist. The ++ COPY argument must be TRUE if this routine should copy the string ++ into newly allocated memory when adding an entry. */ ++extern struct bfd_hash_entry *bfd_hash_lookup ++ (struct bfd_hash_table *, const char *, bfd_boolean create, ++ bfd_boolean copy); ++ ++/* Replace an entry in a hash table. */ ++extern void bfd_hash_replace ++ (struct bfd_hash_table *, struct bfd_hash_entry *old, ++ struct bfd_hash_entry *nw); ++ ++/* Base method for creating a hash table entry. */ ++extern struct bfd_hash_entry *bfd_hash_newfunc ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++ ++/* Grab some space for a hash table entry. */ ++extern void *bfd_hash_allocate ++ (struct bfd_hash_table *, unsigned int); ++ ++/* Traverse a hash table in a random order, calling a function on each ++ element. If the function returns FALSE, the traversal stops. The ++ INFO argument is passed to the function. */ ++extern void bfd_hash_traverse ++ (struct bfd_hash_table *, ++ bfd_boolean (*) (struct bfd_hash_entry *, void *), ++ void *info); ++ ++/* Allows the default size of a hash table to be configured. New hash ++ tables allocated using bfd_hash_table_init will be created with ++ this size. */ ++extern void bfd_hash_set_default_size (bfd_size_type); ++ ++/* This structure is used to keep track of stabs in sections ++ information while linking. */ ++ ++struct stab_info ++{ ++ /* A hash table used to hold stabs strings. */ ++ struct bfd_strtab_hash *strings; ++ /* The header file hash table. */ ++ struct bfd_hash_table includes; ++ /* The first .stabstr section. */ ++ struct bfd_section *stabstr; ++}; ++ ++#define COFF_SWAP_TABLE (void *) &bfd_coff_std_swap_table ++ ++/* User program access to BFD facilities. */ ++ ++/* Direct I/O routines, for programs which know more about the object ++ file than BFD does. Use higher level routines if possible. */ ++ ++extern bfd_size_type bfd_bread (void *, bfd_size_type, bfd *); ++extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); ++extern int bfd_seek (bfd *, file_ptr, int); ++extern file_ptr bfd_tell (bfd *); ++extern int bfd_flush (bfd *); ++extern int bfd_stat (bfd *, struct stat *); ++ ++/* Deprecated old routines. */ ++#if __GNUC__ ++#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ ++ bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ ++ bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#else ++#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ ++ bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ ++ bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#endif ++extern void warn_deprecated (const char *, const char *, int, const char *); ++ ++/* Cast from const char * to char * so that caller can assign to ++ a char * without a warning. */ ++#define bfd_get_filename(abfd) ((char *) (abfd)->filename) ++#define bfd_get_cacheable(abfd) ((abfd)->cacheable) ++#define bfd_get_format(abfd) ((abfd)->format) ++#define bfd_get_target(abfd) ((abfd)->xvec->name) ++#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) ++#define bfd_family_coff(abfd) \ ++ (bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ ++ bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) ++#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) ++#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) ++#define bfd_header_big_endian(abfd) \ ++ ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) ++#define bfd_header_little_endian(abfd) \ ++ ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) ++#define bfd_get_file_flags(abfd) ((abfd)->flags) ++#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) ++#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) ++#define bfd_my_archive(abfd) ((abfd)->my_archive) ++#define bfd_has_map(abfd) ((abfd)->has_armap) ++ ++#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) ++#define bfd_usrdata(abfd) ((abfd)->usrdata) ++ ++#define bfd_get_start_address(abfd) ((abfd)->start_address) ++#define bfd_get_symcount(abfd) ((abfd)->symcount) ++#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) ++#define bfd_count_sections(abfd) ((abfd)->section_count) ++ ++#define bfd_get_dynamic_symcount(abfd) ((abfd)->dynsymcount) ++ ++#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) ++ ++#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) ++ ++extern bfd_boolean bfd_cache_close ++ (bfd *abfd); ++/* NB: This declaration should match the autogenerated one in libbfd.h. */ ++ ++extern bfd_boolean bfd_cache_close_all (void); ++ ++extern bfd_boolean bfd_record_phdr ++ (bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, ++ bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); ++ ++/* Byte swapping routines. */ ++ ++bfd_uint64_t bfd_getb64 (const void *); ++bfd_uint64_t bfd_getl64 (const void *); ++bfd_int64_t bfd_getb_signed_64 (const void *); ++bfd_int64_t bfd_getl_signed_64 (const void *); ++bfd_vma bfd_getb32 (const void *); ++bfd_vma bfd_getl32 (const void *); ++bfd_signed_vma bfd_getb_signed_32 (const void *); ++bfd_signed_vma bfd_getl_signed_32 (const void *); ++bfd_vma bfd_getb16 (const void *); ++bfd_vma bfd_getl16 (const void *); ++bfd_signed_vma bfd_getb_signed_16 (const void *); ++bfd_signed_vma bfd_getl_signed_16 (const void *); ++void bfd_putb64 (bfd_uint64_t, void *); ++void bfd_putl64 (bfd_uint64_t, void *); ++void bfd_putb32 (bfd_vma, void *); ++void bfd_putl32 (bfd_vma, void *); ++void bfd_putb16 (bfd_vma, void *); ++void bfd_putl16 (bfd_vma, void *); ++ ++/* Byte swapping routines which take size and endiannes as arguments. */ ++ ++bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); ++void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); ++ ++extern bfd_boolean bfd_section_already_linked_table_init (void); ++extern void bfd_section_already_linked_table_free (void); ++ ++/* Externally visible ECOFF routines. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++struct ecoff_debug_info; ++struct ecoff_debug_swap; ++struct ecoff_extr; ++struct bfd_symbol; ++struct bfd_link_info; ++struct bfd_link_hash_entry; ++struct bfd_elf_version_tree; ++#endif ++extern bfd_vma bfd_ecoff_get_gp_value ++ (bfd * abfd); ++extern bfd_boolean bfd_ecoff_set_gp_value ++ (bfd *abfd, bfd_vma gp_value); ++extern bfd_boolean bfd_ecoff_set_regmasks ++ (bfd *abfd, unsigned long gprmask, unsigned long fprmask, ++ unsigned long *cprmask); ++extern void *bfd_ecoff_debug_init ++ (bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); ++extern void bfd_ecoff_debug_free ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_accumulate ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, bfd *input_bfd, ++ struct ecoff_debug_info *input_debug, ++ const struct ecoff_debug_swap *input_swap, struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_accumulate_other ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, bfd *input_bfd, ++ struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_externals ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, bfd_boolean relocatable, ++ bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), ++ void (*set_index) (struct bfd_symbol *, bfd_size_type)); ++extern bfd_boolean bfd_ecoff_debug_one_external ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, const char *name, ++ struct ecoff_extr *esym); ++extern bfd_size_type bfd_ecoff_debug_size ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap); ++extern bfd_boolean bfd_ecoff_write_debug ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, file_ptr where); ++extern bfd_boolean bfd_ecoff_write_accumulated_debug ++ (void *handle, bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, ++ struct bfd_link_info *info, file_ptr where); ++ ++/* Externally visible ELF routines. */ ++ ++struct bfd_link_needed_list ++{ ++ struct bfd_link_needed_list *next; ++ bfd *by; ++ const char *name; ++}; ++ ++enum dynamic_lib_link_class { ++ DYN_NORMAL = 0, ++ DYN_AS_NEEDED = 1, ++ DYN_DT_NEEDED = 2, ++ DYN_NO_ADD_NEEDED = 4, ++ DYN_NO_NEEDED = 8 ++}; ++ ++extern bfd_boolean bfd_elf_record_link_assignment ++ (struct bfd_link_info *, const char *, bfd_boolean); ++extern struct bfd_link_needed_list *bfd_elf_get_needed_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_get_bfd_needed_list ++ (bfd *, struct bfd_link_needed_list **); ++extern bfd_boolean bfd_elf_size_dynamic_sections ++ (bfd *, const char *, const char *, const char *, const char * const *, ++ struct bfd_link_info *, struct bfd_section **, ++ struct bfd_elf_version_tree *); ++extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr ++ (bfd *, struct bfd_link_info *); ++extern void bfd_elf_set_dt_needed_name ++ (bfd *, const char *); ++extern const char *bfd_elf_get_dt_soname ++ (bfd *); ++extern void bfd_elf_set_dyn_lib_class ++ (bfd *, int); ++extern int bfd_elf_get_dyn_lib_class ++ (bfd *); ++extern struct bfd_link_needed_list *bfd_elf_get_runpath_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_discard_info ++ (bfd *, struct bfd_link_info *); ++extern unsigned int _bfd_elf_default_action_discarded ++ (struct bfd_section *); ++ ++/* Return an upper bound on the number of bytes required to store a ++ copy of ABFD's program header table entries. Return -1 if an error ++ occurs; bfd_get_error will return an appropriate code. */ ++extern long bfd_get_elf_phdr_upper_bound ++ (bfd *abfd); ++ ++/* Copy ABFD's program header table entries to *PHDRS. The entries ++ will be stored as an array of Elf_Internal_Phdr structures, as ++ defined in include/elf/internal.h. To find out how large the ++ buffer needs to be, call bfd_get_elf_phdr_upper_bound. ++ ++ Return the number of program header table entries read, or -1 if an ++ error occurs; bfd_get_error will return an appropriate code. */ ++extern int bfd_get_elf_phdrs ++ (bfd *abfd, void *phdrs); ++ ++/* Create a new BFD as if by bfd_openr. Rather than opening a file, ++ reconstruct an ELF file by reading the segments out of remote memory ++ based on the ELF file header at EHDR_VMA and the ELF program headers it ++ points to. If not null, *LOADBASEP is filled in with the difference ++ between the VMAs from which the segments were read, and the VMAs the ++ file headers (and hence BFD's idea of each section's VMA) put them at. ++ ++ The function TARGET_READ_MEMORY is called to copy LEN bytes from the ++ remote memory at target address VMA into the local buffer at MYADDR; it ++ should return zero on success or an `errno' code on failure. TEMPL must ++ be a BFD for an ELF target with the word size and byte order found in ++ the remote memory. */ ++extern bfd *bfd_elf_bfd_from_remote_memory ++ (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, ++ int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); ++ ++/* Return the arch_size field of an elf bfd, or -1 if not elf. */ ++extern int bfd_get_arch_size ++ (bfd *); ++ ++/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ ++extern int bfd_get_sign_extend_vma ++ (bfd *); ++ ++extern struct bfd_section *_bfd_elf_tls_setup ++ (bfd *, struct bfd_link_info *); ++ ++extern void _bfd_elf_provide_symbol ++ (struct bfd_link_info *, const char *, bfd_vma, struct bfd_section *); ++ ++extern void _bfd_elf_provide_section_bound_symbols ++ (struct bfd_link_info *, struct bfd_section *, const char *, const char *); ++ ++extern void _bfd_elf_fix_excluded_sec_syms ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, ++ char **); ++ ++/* SunOS shared library support routines for the linker. */ ++ ++extern struct bfd_link_needed_list *bfd_sunos_get_needed_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_sunos_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_sunos_size_dynamic_sections ++ (bfd *, struct bfd_link_info *, struct bfd_section **, ++ struct bfd_section **, struct bfd_section **); ++ ++/* Linux shared library support routines for the linker. */ ++ ++extern bfd_boolean bfd_i386linux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_m68klinux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_sparclinux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++ ++/* mmap hacks */ ++ ++struct _bfd_window_internal; ++typedef struct _bfd_window_internal bfd_window_internal; ++ ++typedef struct _bfd_window ++{ ++ /* What the user asked for. */ ++ void *data; ++ bfd_size_type size; ++ /* The actual window used by BFD. Small user-requested read-only ++ regions sharing a page may share a single window into the object ++ file. Read-write versions shouldn't until I've fixed things to ++ keep track of which portions have been claimed by the ++ application; don't want to give the same region back when the ++ application wants two writable copies! */ ++ struct _bfd_window_internal *i; ++} ++bfd_window; ++ ++extern void bfd_init_window ++ (bfd_window *); ++extern void bfd_free_window ++ (bfd_window *); ++extern bfd_boolean bfd_get_file_window ++ (bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); ++ ++/* XCOFF support routines for the linker. */ ++ ++extern bfd_boolean bfd_xcoff_link_record_set ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); ++extern bfd_boolean bfd_xcoff_import_symbol ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, ++ const char *, const char *, const char *, unsigned int); ++extern bfd_boolean bfd_xcoff_export_symbol ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); ++extern bfd_boolean bfd_xcoff_link_count_reloc ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_xcoff_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_xcoff_size_dynamic_sections ++ (bfd *, struct bfd_link_info *, const char *, const char *, ++ unsigned long, unsigned long, unsigned long, bfd_boolean, ++ int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean); ++extern bfd_boolean bfd_xcoff_link_generate_rtinit ++ (bfd *, const char *, const char *, bfd_boolean); ++ ++/* XCOFF support routines for ar. */ ++extern bfd_boolean bfd_xcoff_ar_archive_set_magic ++ (bfd *, char *); ++ ++/* Externally visible COFF routines. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++struct internal_syment; ++union internal_auxent; ++#endif ++ ++extern bfd_boolean bfd_coff_get_syment ++ (bfd *, struct bfd_symbol *, struct internal_syment *); ++ ++extern bfd_boolean bfd_coff_get_auxent ++ (bfd *, struct bfd_symbol *, int, union internal_auxent *); ++ ++extern bfd_boolean bfd_coff_set_symbol_class ++ (bfd *, struct bfd_symbol *, unsigned int); ++ ++extern bfd_boolean bfd_m68k_coff_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); ++ ++/* ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_arm_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_arm_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++extern bfd_boolean bfd_arm_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++/* PE ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_arm_pe_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_arm_pe_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++/* ELF ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_elf32_arm_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++void bfd_elf32_arm_set_target_relocs ++ (struct bfd_link_info *, int, char *, int, int); ++ ++extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd ++ (bfd *, struct bfd_link_info *); ++ ++/* ELF ARM mapping symbol support */ ++extern bfd_boolean bfd_is_arm_mapping_symbol_name ++ (const char * name); ++ ++/* ARM Note section processing. */ ++extern bfd_boolean bfd_arm_merge_machines ++ (bfd *, bfd *); ++ ++extern bfd_boolean bfd_arm_update_notes ++ (bfd *, const char *); ++ ++extern unsigned int bfd_arm_get_mach_from_notes ++ (bfd *, const char *); ++ ++/* TI COFF load page support. */ ++extern void bfd_ticoff_set_section_load_page ++ (struct bfd_section *, int); ++ ++extern int bfd_ticoff_get_section_load_page ++ (struct bfd_section *); ++ ++/* H8/300 functions. */ ++extern bfd_vma bfd_h8300_pad_address ++ (bfd *, bfd_vma); ++ ++/* IA64 Itanium code generation. Called from linker. */ ++extern void bfd_elf32_ia64_after_parse ++ (int); ++ ++extern void bfd_elf64_ia64_after_parse ++ (int); ++ ++/* This structure is used for a comdat section, as in PE. A comdat ++ section is associated with a particular symbol. When the linker ++ sees a comdat section, it keeps only one of the sections with a ++ given name and associated with a given symbol. */ ++ ++struct coff_comdat_info ++{ ++ /* The name of the symbol associated with a comdat section. */ ++ const char *name; ++ ++ /* The local symbol table index of the symbol associated with a ++ comdat section. This is only meaningful to the object file format ++ specific code; it is not an index into the list returned by ++ bfd_canonicalize_symtab. */ ++ long symbol; ++}; ++ ++extern struct coff_comdat_info *bfd_coff_get_comdat_section ++ (bfd *, struct bfd_section *); ++ ++/* Extracted from init.c. */ ++void bfd_init (void); ++ ++/* Extracted from opncls.c. */ ++bfd *bfd_fopen (const char *filename, const char *target, ++ const char *mode, int fd); ++ ++bfd *bfd_openr (const char *filename, const char *target); ++ ++bfd *bfd_fdopenr (const char *filename, const char *target, int fd); ++ ++bfd *bfd_openstreamr (const char *, const char *, void *); ++ ++bfd *bfd_openr_iovec (const char *filename, const char *target, ++ void *(*open) (struct bfd *nbfd, ++ void *open_closure), ++ void *open_closure, ++ file_ptr (*pread) (struct bfd *nbfd, ++ void *stream, ++ void *buf, ++ file_ptr nbytes, ++ file_ptr offset), ++ int (*close) (struct bfd *nbfd, ++ void *stream)); ++ ++bfd *bfd_openw (const char *filename, const char *target); ++ ++bfd_boolean bfd_close (bfd *abfd); ++ ++bfd_boolean bfd_close_all_done (bfd *); ++ ++bfd *bfd_create (const char *filename, bfd *templ); ++ ++bfd_boolean bfd_make_writable (bfd *abfd); ++ ++bfd_boolean bfd_make_readable (bfd *abfd); ++ ++unsigned long bfd_calc_gnu_debuglink_crc32 ++ (unsigned long crc, const unsigned char *buf, bfd_size_type len); ++ ++char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); ++ ++struct bfd_section *bfd_create_gnu_debuglink_section ++ (bfd *abfd, const char *filename); ++ ++bfd_boolean bfd_fill_in_gnu_debuglink_section ++ (bfd *abfd, struct bfd_section *sect, const char *filename); ++ ++/* Extracted from libbfd.c. */ ++ ++/* Byte swapping macros for user section data. */ ++ ++#define bfd_put_8(abfd, val, ptr) \ ++ ((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) ++#define bfd_put_signed_8 \ ++ bfd_put_8 ++#define bfd_get_8(abfd, ptr) \ ++ (*(unsigned char *) (ptr) & 0xff) ++#define bfd_get_signed_8(abfd, ptr) \ ++ (((*(unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) ++ ++#define bfd_put_16(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx16, ((val),(ptr))) ++#define bfd_put_signed_16 \ ++ bfd_put_16 ++#define bfd_get_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx16, (ptr)) ++#define bfd_get_signed_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) ++ ++#define bfd_put_32(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx32, ((val),(ptr))) ++#define bfd_put_signed_32 \ ++ bfd_put_32 ++#define bfd_get_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx32, (ptr)) ++#define bfd_get_signed_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_32, (ptr)) ++ ++#define bfd_put_64(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx64, ((val), (ptr))) ++#define bfd_put_signed_64 \ ++ bfd_put_64 ++#define bfd_get_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx64, (ptr)) ++#define bfd_get_signed_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_64, (ptr)) ++ ++#define bfd_get(bits, abfd, ptr) \ ++ ((bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ ++ : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ ++ : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ ++ : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ ++ : (abort (), (bfd_vma) - 1)) ++ ++#define bfd_put(bits, abfd, val, ptr) \ ++ ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ ++ : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ ++ : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ ++ : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ ++ : (abort (), (void) 0)) ++ ++ ++/* Byte swapping macros for file header data. */ ++ ++#define bfd_h_put_8(abfd, val, ptr) \ ++ bfd_put_8 (abfd, val, ptr) ++#define bfd_h_put_signed_8(abfd, val, ptr) \ ++ bfd_put_8 (abfd, val, ptr) ++#define bfd_h_get_8(abfd, ptr) \ ++ bfd_get_8 (abfd, ptr) ++#define bfd_h_get_signed_8(abfd, ptr) \ ++ bfd_get_signed_8 (abfd, ptr) ++ ++#define bfd_h_put_16(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) ++#define bfd_h_put_signed_16 \ ++ bfd_h_put_16 ++#define bfd_h_get_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx16, (ptr)) ++#define bfd_h_get_signed_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) ++ ++#define bfd_h_put_32(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) ++#define bfd_h_put_signed_32 \ ++ bfd_h_put_32 ++#define bfd_h_get_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx32, (ptr)) ++#define bfd_h_get_signed_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) ++ ++#define bfd_h_put_64(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) ++#define bfd_h_put_signed_64 \ ++ bfd_h_put_64 ++#define bfd_h_get_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx64, (ptr)) ++#define bfd_h_get_signed_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) ++ ++/* Aliases for the above, which should eventually go away. */ ++ ++#define H_PUT_64 bfd_h_put_64 ++#define H_PUT_32 bfd_h_put_32 ++#define H_PUT_16 bfd_h_put_16 ++#define H_PUT_8 bfd_h_put_8 ++#define H_PUT_S64 bfd_h_put_signed_64 ++#define H_PUT_S32 bfd_h_put_signed_32 ++#define H_PUT_S16 bfd_h_put_signed_16 ++#define H_PUT_S8 bfd_h_put_signed_8 ++#define H_GET_64 bfd_h_get_64 ++#define H_GET_32 bfd_h_get_32 ++#define H_GET_16 bfd_h_get_16 ++#define H_GET_8 bfd_h_get_8 ++#define H_GET_S64 bfd_h_get_signed_64 ++#define H_GET_S32 bfd_h_get_signed_32 ++#define H_GET_S16 bfd_h_get_signed_16 ++#define H_GET_S8 bfd_h_get_signed_8 ++ ++ ++/* Extracted from bfdio.c. */ ++long bfd_get_mtime (bfd *abfd); ++ ++long bfd_get_size (bfd *abfd); ++ ++/* Extracted from bfdwin.c. */ ++/* Extracted from section.c. */ ++typedef struct bfd_section ++{ ++ /* The name of the section; the name isn't a copy, the pointer is ++ the same as that passed to bfd_make_section. */ ++ const char *name; ++ ++ /* A unique sequence number. */ ++ int id; ++ ++ /* Which section in the bfd; 0..n-1 as sections are created in a bfd. */ ++ int index; ++ ++ /* The next section in the list belonging to the BFD, or NULL. */ ++ struct bfd_section *next; ++ ++ /* The previous section in the list belonging to the BFD, or NULL. */ ++ struct bfd_section *prev; ++ ++ /* The field flags contains attributes of the section. Some ++ flags are read in from the object file, and some are ++ synthesized from other information. */ ++ flagword flags; ++ ++#define SEC_NO_FLAGS 0x000 ++ ++ /* Tells the OS to allocate space for this section when loading. ++ This is clear for a section containing debug information only. */ ++#define SEC_ALLOC 0x001 ++ ++ /* Tells the OS to load the section from the file when loading. ++ This is clear for a .bss section. */ ++#define SEC_LOAD 0x002 ++ ++ /* The section contains data still to be relocated, so there is ++ some relocation information too. */ ++#define SEC_RELOC 0x004 ++ ++ /* A signal to the OS that the section contains read only data. */ ++#define SEC_READONLY 0x008 ++ ++ /* The section contains code only. */ ++#define SEC_CODE 0x010 ++ ++ /* The section contains data only. */ ++#define SEC_DATA 0x020 ++ ++ /* The section will reside in ROM. */ ++#define SEC_ROM 0x040 ++ ++ /* The section contains constructor information. This section ++ type is used by the linker to create lists of constructors and ++ destructors used by <>. When a back end sees a symbol ++ which should be used in a constructor list, it creates a new ++ section for the type of name (e.g., <<__CTOR_LIST__>>), attaches ++ the symbol to it, and builds a relocation. To build the lists ++ of constructors, all the linker has to do is catenate all the ++ sections called <<__CTOR_LIST__>> and relocate the data ++ contained within - exactly the operations it would peform on ++ standard data. */ ++#define SEC_CONSTRUCTOR 0x080 ++ ++ /* The section has contents - a data section could be ++ <> | <>; a debug section could be ++ <> */ ++#define SEC_HAS_CONTENTS 0x100 ++ ++ /* An instruction to the linker to not output the section ++ even if it has information which would normally be written. */ ++#define SEC_NEVER_LOAD 0x200 ++ ++ /* The section contains thread local data. */ ++#define SEC_THREAD_LOCAL 0x400 ++ ++ /* The section has GOT references. This flag is only for the ++ linker, and is currently only used by the elf32-hppa back end. ++ It will be set if global offset table references were detected ++ in this section, which indicate to the linker that the section ++ contains PIC code, and must be handled specially when doing a ++ static link. */ ++#define SEC_HAS_GOT_REF 0x800 ++ ++ /* The section contains common symbols (symbols may be defined ++ multiple times, the value of a symbol is the amount of ++ space it requires, and the largest symbol value is the one ++ used). Most targets have exactly one of these (which we ++ translate to bfd_com_section_ptr), but ECOFF has two. */ ++#define SEC_IS_COMMON 0x1000 ++ ++ /* The section contains only debugging information. For ++ example, this is set for ELF .debug and .stab sections. ++ strip tests this flag to see if a section can be ++ discarded. */ ++#define SEC_DEBUGGING 0x2000 ++ ++ /* The contents of this section are held in memory pointed to ++ by the contents field. This is checked by bfd_get_section_contents, ++ and the data is retrieved from memory if appropriate. */ ++#define SEC_IN_MEMORY 0x4000 ++ ++ /* The contents of this section are to be excluded by the ++ linker for executable and shared objects unless those ++ objects are to be further relocated. */ ++#define SEC_EXCLUDE 0x8000 ++ ++ /* The contents of this section are to be sorted based on the sum of ++ the symbol and addend values specified by the associated relocation ++ entries. Entries without associated relocation entries will be ++ appended to the end of the section in an unspecified order. */ ++#define SEC_SORT_ENTRIES 0x10000 ++ ++ /* When linking, duplicate sections of the same name should be ++ discarded, rather than being combined into a single section as ++ is usually done. This is similar to how common symbols are ++ handled. See SEC_LINK_DUPLICATES below. */ ++#define SEC_LINK_ONCE 0x20000 ++ ++ /* If SEC_LINK_ONCE is set, this bitfield describes how the linker ++ should handle duplicate sections. */ ++#define SEC_LINK_DUPLICATES 0x40000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that duplicate ++ sections with the same name should simply be discarded. */ ++#define SEC_LINK_DUPLICATES_DISCARD 0x0 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if there are any duplicate sections, although ++ it should still only link one copy. */ ++#define SEC_LINK_DUPLICATES_ONE_ONLY 0x80000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if any duplicate sections are a different size. */ ++#define SEC_LINK_DUPLICATES_SAME_SIZE 0x100000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if any duplicate sections contain different ++ contents. */ ++#define SEC_LINK_DUPLICATES_SAME_CONTENTS \ ++ (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) ++ ++ /* This section was created by the linker as part of dynamic ++ relocation or other arcane processing. It is skipped when ++ going through the first-pass output, trusting that someone ++ else up the line will take care of it later. */ ++#define SEC_LINKER_CREATED 0x200000 ++ ++ /* This section should not be subject to garbage collection. */ ++#define SEC_KEEP 0x400000 ++ ++ /* This section contains "short" data, and should be placed ++ "near" the GP. */ ++#define SEC_SMALL_DATA 0x800000 ++ ++ /* Attempt to merge identical entities in the section. ++ Entity size is given in the entsize field. */ ++#define SEC_MERGE 0x1000000 ++ ++ /* If given with SEC_MERGE, entities to merge are zero terminated ++ strings where entsize specifies character size instead of fixed ++ size entries. */ ++#define SEC_STRINGS 0x2000000 ++ ++ /* This section contains data about section groups. */ ++#define SEC_GROUP 0x4000000 ++ ++ /* The section is a COFF shared library section. This flag is ++ only for the linker. If this type of section appears in ++ the input file, the linker must copy it to the output file ++ without changing the vma or size. FIXME: Although this ++ was originally intended to be general, it really is COFF ++ specific (and the flag was renamed to indicate this). It ++ might be cleaner to have some more general mechanism to ++ allow the back end to control what the linker does with ++ sections. */ ++#define SEC_COFF_SHARED_LIBRARY 0x10000000 ++ ++ /* This section contains data which may be shared with other ++ executables or shared objects. This is for COFF only. */ ++#define SEC_COFF_SHARED 0x20000000 ++ ++ /* When a section with this flag is being linked, then if the size of ++ the input section is less than a page, it should not cross a page ++ boundary. If the size of the input section is one page or more, ++ it should be aligned on a page boundary. This is for TI ++ TMS320C54X only. */ ++#define SEC_TIC54X_BLOCK 0x40000000 ++ ++ /* Conditionally link this section; do not link if there are no ++ references found to any symbol in the section. This is for TI ++ TMS320C54X only. */ ++#define SEC_TIC54X_CLINK 0x80000000 ++ ++ /* End of section flags. */ ++ ++ /* Some internal packed boolean fields. */ ++ ++ /* See the vma field. */ ++ unsigned int user_set_vma : 1; ++ ++ /* A mark flag used by some of the linker backends. */ ++ unsigned int linker_mark : 1; ++ ++ /* Another mark flag used by some of the linker backends. Set for ++ output sections that have an input section. */ ++ unsigned int linker_has_input : 1; ++ ++ /* Mark flags used by some linker backends for garbage collection. */ ++ unsigned int gc_mark : 1; ++ unsigned int gc_mark_from_eh : 1; ++ ++ /* The following flags are used by the ELF linker. */ ++ ++ /* Mark sections which have been allocated to segments. */ ++ unsigned int segment_mark : 1; ++ ++ /* Type of sec_info information. */ ++ unsigned int sec_info_type:3; ++#define ELF_INFO_TYPE_NONE 0 ++#define ELF_INFO_TYPE_STABS 1 ++#define ELF_INFO_TYPE_MERGE 2 ++#define ELF_INFO_TYPE_EH_FRAME 3 ++#define ELF_INFO_TYPE_JUST_SYMS 4 ++ ++ /* Nonzero if this section uses RELA relocations, rather than REL. */ ++ unsigned int use_rela_p:1; ++ ++ /* Bits used by various backends. The generic code doesn't touch ++ these fields. */ ++ ++ /* Nonzero if this section has TLS related relocations. */ ++ unsigned int has_tls_reloc:1; ++ ++ /* Nonzero if this section has a gp reloc. */ ++ unsigned int has_gp_reloc:1; ++ ++ /* Nonzero if this section needs the relax finalize pass. */ ++ unsigned int need_finalize_relax:1; ++ ++ /* Whether relocations have been processed. */ ++ unsigned int reloc_done : 1; ++ ++ /* End of internal packed boolean fields. */ ++ ++ /* The virtual memory address of the section - where it will be ++ at run time. The symbols are relocated against this. The ++ user_set_vma flag is maintained by bfd; if it's not set, the ++ backend can assign addresses (for example, in <>, where ++ the default address for <<.data>> is dependent on the specific ++ target and various flags). */ ++ bfd_vma vma; ++ ++ /* The load address of the section - where it would be in a ++ rom image; really only used for writing section header ++ information. */ ++ bfd_vma lma; ++ ++ /* The size of the section in octets, as it will be output. ++ Contains a value even if the section has no contents (e.g., the ++ size of <<.bss>>). */ ++ bfd_size_type size; ++ ++ /* For input sections, the original size on disk of the section, in ++ octets. This field is used by the linker relaxation code. It is ++ currently only set for sections where the linker relaxation scheme ++ doesn't cache altered section and reloc contents (stabs, eh_frame, ++ SEC_MERGE, some coff relaxing targets), and thus the original size ++ needs to be kept to read the section multiple times. ++ For output sections, rawsize holds the section size calculated on ++ a previous linker relaxation pass. */ ++ bfd_size_type rawsize; ++ ++ /* If this section is going to be output, then this value is the ++ offset in *bytes* into the output section of the first byte in the ++ input section (byte ==> smallest addressable unit on the ++ target). In most cases, if this was going to start at the ++ 100th octet (8-bit quantity) in the output section, this value ++ would be 100. However, if the target byte size is 16 bits ++ (bfd_octets_per_byte is "2"), this value would be 50. */ ++ bfd_vma output_offset; ++ ++ /* The output section through which to map on output. */ ++ struct bfd_section *output_section; ++ ++ /* The alignment requirement of the section, as an exponent of 2 - ++ e.g., 3 aligns to 2^3 (or 8). */ ++ unsigned int alignment_power; ++ ++ /* If an input section, a pointer to a vector of relocation ++ records for the data in this section. */ ++ struct reloc_cache_entry *relocation; ++ ++ /* If an output section, a pointer to a vector of pointers to ++ relocation records for the data in this section. */ ++ struct reloc_cache_entry **orelocation; ++ ++ /* The number of relocation records in one of the above. */ ++ unsigned reloc_count; ++ ++ /* Information below is back end specific - and not always used ++ or updated. */ ++ ++ /* File position of section data. */ ++ file_ptr filepos; ++ ++ /* File position of relocation info. */ ++ file_ptr rel_filepos; ++ ++ /* File position of line data. */ ++ file_ptr line_filepos; ++ ++ /* Pointer to data for applications. */ ++ void *userdata; ++ ++ /* If the SEC_IN_MEMORY flag is set, this points to the actual ++ contents. */ ++ unsigned char *contents; ++ ++ /* Attached line number information. */ ++ alent *lineno; ++ ++ /* Number of line number records. */ ++ unsigned int lineno_count; ++ ++ /* Entity size for merging purposes. */ ++ unsigned int entsize; ++ ++ /* Points to the kept section if this section is a link-once section, ++ and is discarded. */ ++ struct bfd_section *kept_section; ++ ++ /* When a section is being output, this value changes as more ++ linenumbers are written out. */ ++ file_ptr moving_line_filepos; ++ ++ /* What the section number is in the target world. */ ++ int target_index; ++ ++ void *used_by_bfd; ++ ++ /* If this is a constructor section then here is a list of the ++ relocations created to relocate items within it. */ ++ struct relent_chain *constructor_chain; ++ ++ /* The BFD which owns the section. */ ++ bfd *owner; ++ ++ /* A symbol which points at this section only. */ ++ struct bfd_symbol *symbol; ++ struct bfd_symbol **symbol_ptr_ptr; ++ ++ /* Early in the link process, map_head and map_tail are used to build ++ a list of input sections attached to an output section. Later, ++ output sections use these fields for a list of bfd_link_order ++ structs. */ ++ union { ++ struct bfd_link_order *link_order; ++ struct bfd_section *s; ++ } map_head, map_tail; ++} asection; ++ ++/* These sections are global, and are managed by BFD. The application ++ and target back end are not permitted to change the values in ++ these sections. New code should use the section_ptr macros rather ++ than referring directly to the const sections. The const sections ++ may eventually vanish. */ ++#define BFD_ABS_SECTION_NAME "*ABS*" ++#define BFD_UND_SECTION_NAME "*UND*" ++#define BFD_COM_SECTION_NAME "*COM*" ++#define BFD_IND_SECTION_NAME "*IND*" ++ ++/* The absolute section. */ ++extern asection bfd_abs_section; ++#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) ++#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) ++/* Pointer to the undefined section. */ ++extern asection bfd_und_section; ++#define bfd_und_section_ptr ((asection *) &bfd_und_section) ++#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) ++/* Pointer to the common section. */ ++extern asection bfd_com_section; ++#define bfd_com_section_ptr ((asection *) &bfd_com_section) ++/* Pointer to the indirect section. */ ++extern asection bfd_ind_section; ++#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) ++#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) ++ ++#define bfd_is_const_section(SEC) \ ++ ( ((SEC) == bfd_abs_section_ptr) \ ++ || ((SEC) == bfd_und_section_ptr) \ ++ || ((SEC) == bfd_com_section_ptr) \ ++ || ((SEC) == bfd_ind_section_ptr)) ++ ++extern const struct bfd_symbol * const bfd_abs_symbol; ++extern const struct bfd_symbol * const bfd_com_symbol; ++extern const struct bfd_symbol * const bfd_und_symbol; ++extern const struct bfd_symbol * const bfd_ind_symbol; ++ ++/* Macros to handle insertion and deletion of a bfd's sections. These ++ only handle the list pointers, ie. do not adjust section_count, ++ target_index etc. */ ++#define bfd_section_list_remove(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ asection *_next = _s->next; \ ++ asection *_prev = _s->prev; \ ++ if (_prev) \ ++ _prev->next = _next; \ ++ else \ ++ (ABFD)->sections = _next; \ ++ if (_next) \ ++ _next->prev = _prev; \ ++ else \ ++ (ABFD)->section_last = _prev; \ ++ } \ ++ while (0) ++#define bfd_section_list_append(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ bfd *_abfd = ABFD; \ ++ _s->next = NULL; \ ++ if (_abfd->section_last) \ ++ { \ ++ _s->prev = _abfd->section_last; \ ++ _abfd->section_last->next = _s; \ ++ } \ ++ else \ ++ { \ ++ _s->prev = NULL; \ ++ _abfd->sections = _s; \ ++ } \ ++ _abfd->section_last = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_prepend(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ bfd *_abfd = ABFD; \ ++ _s->prev = NULL; \ ++ if (_abfd->sections) \ ++ { \ ++ _s->next = _abfd->sections; \ ++ _abfd->sections->prev = _s; \ ++ } \ ++ else \ ++ { \ ++ _s->next = NULL; \ ++ _abfd->section_last = _s; \ ++ } \ ++ _abfd->sections = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_insert_after(ABFD, A, S) \ ++ do \ ++ { \ ++ asection *_a = A; \ ++ asection *_s = S; \ ++ asection *_next = _a->next; \ ++ _s->next = _next; \ ++ _s->prev = _a; \ ++ _a->next = _s; \ ++ if (_next) \ ++ _next->prev = _s; \ ++ else \ ++ (ABFD)->section_last = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_insert_before(ABFD, B, S) \ ++ do \ ++ { \ ++ asection *_b = B; \ ++ asection *_s = S; \ ++ asection *_prev = _b->prev; \ ++ _s->prev = _prev; \ ++ _s->next = _b; \ ++ _b->prev = _s; \ ++ if (_prev) \ ++ _prev->next = _s; \ ++ else \ ++ (ABFD)->sections = _s; \ ++ } \ ++ while (0) ++#define bfd_section_removed_from_list(ABFD, S) \ ++ ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) ++ ++void bfd_section_list_clear (bfd *); ++ ++asection *bfd_get_section_by_name (bfd *abfd, const char *name); ++ ++asection *bfd_get_section_by_name_if ++ (bfd *abfd, ++ const char *name, ++ bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++char *bfd_get_unique_section_name ++ (bfd *abfd, const char *templat, int *count); ++ ++asection *bfd_make_section_old_way (bfd *abfd, const char *name); ++ ++asection *bfd_make_section_anyway_with_flags ++ (bfd *abfd, const char *name, flagword flags); ++ ++asection *bfd_make_section_anyway (bfd *abfd, const char *name); ++ ++asection *bfd_make_section_with_flags ++ (bfd *, const char *name, flagword flags); ++ ++asection *bfd_make_section (bfd *, const char *name); ++ ++bfd_boolean bfd_set_section_flags ++ (bfd *abfd, asection *sec, flagword flags); ++ ++void bfd_map_over_sections ++ (bfd *abfd, ++ void (*func) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++asection *bfd_sections_find_if ++ (bfd *abfd, ++ bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++bfd_boolean bfd_set_section_size ++ (bfd *abfd, asection *sec, bfd_size_type val); ++ ++bfd_boolean bfd_set_section_contents ++ (bfd *abfd, asection *section, const void *data, ++ file_ptr offset, bfd_size_type count); ++ ++bfd_boolean bfd_get_section_contents ++ (bfd *abfd, asection *section, void *location, file_ptr offset, ++ bfd_size_type count); ++ ++bfd_boolean bfd_malloc_and_get_section ++ (bfd *abfd, asection *section, bfd_byte **buf); ++ ++bfd_boolean bfd_copy_private_section_data ++ (bfd *ibfd, asection *isec, bfd *obfd, asection *osec); ++ ++#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ ++ BFD_SEND (obfd, _bfd_copy_private_section_data, \ ++ (ibfd, isection, obfd, osection)) ++bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); ++ ++bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); ++ ++/* Extracted from archures.c. */ ++enum bfd_architecture ++{ ++ bfd_arch_unknown, /* File arch not known. */ ++ bfd_arch_obscure, /* Arch known, not one of these. */ ++ bfd_arch_m68k, /* Motorola 68xxx */ ++#define bfd_mach_m68000 1 ++#define bfd_mach_m68008 2 ++#define bfd_mach_m68010 3 ++#define bfd_mach_m68020 4 ++#define bfd_mach_m68030 5 ++#define bfd_mach_m68040 6 ++#define bfd_mach_m68060 7 ++#define bfd_mach_cpu32 8 ++#define bfd_mach_mcf5200 9 ++#define bfd_mach_mcf5206e 10 ++#define bfd_mach_mcf5307 11 ++#define bfd_mach_mcf5407 12 ++#define bfd_mach_mcf528x 13 ++#define bfd_mach_mcfv4e 14 ++#define bfd_mach_mcf521x 15 ++#define bfd_mach_mcf5249 16 ++#define bfd_mach_mcf547x 17 ++#define bfd_mach_mcf548x 18 ++ bfd_arch_vax, /* DEC Vax */ ++ bfd_arch_i960, /* Intel 960 */ ++ /* The order of the following is important. ++ lower number indicates a machine type that ++ only accepts a subset of the instructions ++ available to machines with higher numbers. ++ The exception is the "ca", which is ++ incompatible with all other machines except ++ "core". */ ++ ++#define bfd_mach_i960_core 1 ++#define bfd_mach_i960_ka_sa 2 ++#define bfd_mach_i960_kb_sb 3 ++#define bfd_mach_i960_mc 4 ++#define bfd_mach_i960_xa 5 ++#define bfd_mach_i960_ca 6 ++#define bfd_mach_i960_jx 7 ++#define bfd_mach_i960_hx 8 ++ ++ bfd_arch_or32, /* OpenRISC 32 */ ++ ++ bfd_arch_a29k, /* AMD 29000 */ ++ bfd_arch_sparc, /* SPARC */ ++#define bfd_mach_sparc 1 ++/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ ++#define bfd_mach_sparc_sparclet 2 ++#define bfd_mach_sparc_sparclite 3 ++#define bfd_mach_sparc_v8plus 4 ++#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ ++#define bfd_mach_sparc_sparclite_le 6 ++#define bfd_mach_sparc_v9 7 ++#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ ++#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ ++#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ ++/* Nonzero if MACH has the v9 instruction set. */ ++#define bfd_mach_sparc_v9_p(mach) \ ++ ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ ++ && (mach) != bfd_mach_sparc_sparclite_le) ++/* Nonzero if MACH is a 64 bit sparc architecture. */ ++#define bfd_mach_sparc_64bit_p(mach) \ ++ ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) ++ bfd_arch_mips, /* MIPS Rxxxx */ ++#define bfd_mach_mips3000 3000 ++#define bfd_mach_mips3900 3900 ++#define bfd_mach_mips4000 4000 ++#define bfd_mach_mips4010 4010 ++#define bfd_mach_mips4100 4100 ++#define bfd_mach_mips4111 4111 ++#define bfd_mach_mips4120 4120 ++#define bfd_mach_mips4300 4300 ++#define bfd_mach_mips4400 4400 ++#define bfd_mach_mips4600 4600 ++#define bfd_mach_mips4650 4650 ++#define bfd_mach_mips5000 5000 ++#define bfd_mach_mips5400 5400 ++#define bfd_mach_mips5500 5500 ++#define bfd_mach_mips6000 6000 ++#define bfd_mach_mips7000 7000 ++#define bfd_mach_mips8000 8000 ++#define bfd_mach_mips9000 9000 ++#define bfd_mach_mips10000 10000 ++#define bfd_mach_mips12000 12000 ++#define bfd_mach_mips16 16 ++#define bfd_mach_mips5 5 ++#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ ++#define bfd_mach_mipsisa32 32 ++#define bfd_mach_mipsisa32r2 33 ++#define bfd_mach_mipsisa64 64 ++#define bfd_mach_mipsisa64r2 65 ++ bfd_arch_i386, /* Intel 386 */ ++#define bfd_mach_i386_i386 1 ++#define bfd_mach_i386_i8086 2 ++#define bfd_mach_i386_i386_intel_syntax 3 ++#define bfd_mach_x86_64 64 ++#define bfd_mach_x86_64_intel_syntax 65 ++ bfd_arch_we32k, /* AT&T WE32xxx */ ++ bfd_arch_tahoe, /* CCI/Harris Tahoe */ ++ bfd_arch_i860, /* Intel 860 */ ++ bfd_arch_i370, /* IBM 360/370 Mainframes */ ++ bfd_arch_romp, /* IBM ROMP PC/RT */ ++ bfd_arch_alliant, /* Alliant */ ++ bfd_arch_convex, /* Convex */ ++ bfd_arch_m88k, /* Motorola 88xxx */ ++ bfd_arch_m98k, /* Motorola 98xxx */ ++ bfd_arch_pyramid, /* Pyramid Technology */ ++ bfd_arch_h8300, /* Renesas H8/300 (formerly Hitachi H8/300) */ ++#define bfd_mach_h8300 1 ++#define bfd_mach_h8300h 2 ++#define bfd_mach_h8300s 3 ++#define bfd_mach_h8300hn 4 ++#define bfd_mach_h8300sn 5 ++#define bfd_mach_h8300sx 6 ++#define bfd_mach_h8300sxn 7 ++ bfd_arch_pdp11, /* DEC PDP-11 */ ++ bfd_arch_powerpc, /* PowerPC */ ++#define bfd_mach_ppc 32 ++#define bfd_mach_ppc64 64 ++#define bfd_mach_ppc_403 403 ++#define bfd_mach_ppc_403gc 4030 ++#define bfd_mach_ppc_505 505 ++#define bfd_mach_ppc_601 601 ++#define bfd_mach_ppc_602 602 ++#define bfd_mach_ppc_603 603 ++#define bfd_mach_ppc_ec603e 6031 ++#define bfd_mach_ppc_604 604 ++#define bfd_mach_ppc_620 620 ++#define bfd_mach_ppc_630 630 ++#define bfd_mach_ppc_750 750 ++#define bfd_mach_ppc_860 860 ++#define bfd_mach_ppc_a35 35 ++#define bfd_mach_ppc_rs64ii 642 ++#define bfd_mach_ppc_rs64iii 643 ++#define bfd_mach_ppc_7400 7400 ++#define bfd_mach_ppc_e500 500 ++ bfd_arch_rs6000, /* IBM RS/6000 */ ++#define bfd_mach_rs6k 6000 ++#define bfd_mach_rs6k_rs1 6001 ++#define bfd_mach_rs6k_rsc 6003 ++#define bfd_mach_rs6k_rs2 6002 ++ bfd_arch_hppa, /* HP PA RISC */ ++#define bfd_mach_hppa10 10 ++#define bfd_mach_hppa11 11 ++#define bfd_mach_hppa20 20 ++#define bfd_mach_hppa20w 25 ++ bfd_arch_d10v, /* Mitsubishi D10V */ ++#define bfd_mach_d10v 1 ++#define bfd_mach_d10v_ts2 2 ++#define bfd_mach_d10v_ts3 3 ++ bfd_arch_d30v, /* Mitsubishi D30V */ ++ bfd_arch_dlx, /* DLX */ ++ bfd_arch_m68hc11, /* Motorola 68HC11 */ ++ bfd_arch_m68hc12, /* Motorola 68HC12 */ ++#define bfd_mach_m6812_default 0 ++#define bfd_mach_m6812 1 ++#define bfd_mach_m6812s 2 ++ bfd_arch_z8k, /* Zilog Z8000 */ ++#define bfd_mach_z8001 1 ++#define bfd_mach_z8002 2 ++ bfd_arch_h8500, /* Renesas H8/500 (formerly Hitachi H8/500) */ ++ bfd_arch_sh, /* Renesas / SuperH SH (formerly Hitachi SH) */ ++#define bfd_mach_sh 1 ++#define bfd_mach_sh2 0x20 ++#define bfd_mach_sh_dsp 0x2d ++#define bfd_mach_sh2a 0x2a ++#define bfd_mach_sh2a_nofpu 0x2b ++#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 ++#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 ++#define bfd_mach_sh2a_or_sh4 0x2a3 ++#define bfd_mach_sh2a_or_sh3e 0x2a4 ++#define bfd_mach_sh2e 0x2e ++#define bfd_mach_sh3 0x30 ++#define bfd_mach_sh3_nommu 0x31 ++#define bfd_mach_sh3_dsp 0x3d ++#define bfd_mach_sh3e 0x3e ++#define bfd_mach_sh4 0x40 ++#define bfd_mach_sh4_nofpu 0x41 ++#define bfd_mach_sh4_nommu_nofpu 0x42 ++#define bfd_mach_sh4a 0x4a ++#define bfd_mach_sh4a_nofpu 0x4b ++#define bfd_mach_sh4al_dsp 0x4d ++#define bfd_mach_sh5 0x50 ++ bfd_arch_alpha, /* Dec Alpha */ ++#define bfd_mach_alpha_ev4 0x10 ++#define bfd_mach_alpha_ev5 0x20 ++#define bfd_mach_alpha_ev6 0x30 ++ bfd_arch_arm, /* Advanced Risc Machines ARM. */ ++#define bfd_mach_arm_unknown 0 ++#define bfd_mach_arm_2 1 ++#define bfd_mach_arm_2a 2 ++#define bfd_mach_arm_3 3 ++#define bfd_mach_arm_3M 4 ++#define bfd_mach_arm_4 5 ++#define bfd_mach_arm_4T 6 ++#define bfd_mach_arm_5 7 ++#define bfd_mach_arm_5T 8 ++#define bfd_mach_arm_5TE 9 ++#define bfd_mach_arm_XScale 10 ++#define bfd_mach_arm_ep9312 11 ++#define bfd_mach_arm_iWMMXt 12 ++ bfd_arch_ns32k, /* National Semiconductors ns32000 */ ++ bfd_arch_w65, /* WDC 65816 */ ++ bfd_arch_tic30, /* Texas Instruments TMS320C30 */ ++ bfd_arch_tic4x, /* Texas Instruments TMS320C3X/4X */ ++#define bfd_mach_tic3x 30 ++#define bfd_mach_tic4x 40 ++ bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ ++ bfd_arch_tic80, /* TI TMS320c80 (MVP) */ ++ bfd_arch_v850, /* NEC V850 */ ++#define bfd_mach_v850 1 ++#define bfd_mach_v850e 'E' ++#define bfd_mach_v850e1 '1' ++ bfd_arch_arc, /* ARC Cores */ ++#define bfd_mach_arc_5 5 ++#define bfd_mach_arc_6 6 ++#define bfd_mach_arc_7 7 ++#define bfd_mach_arc_8 8 ++ bfd_arch_m32c, /* Renesas M16C/M32C. */ ++#define bfd_mach_m16c 0x75 ++#define bfd_mach_m32c 0x78 ++ bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ ++#define bfd_mach_m32r 1 /* For backwards compatibility. */ ++#define bfd_mach_m32rx 'x' ++#define bfd_mach_m32r2 '2' ++ bfd_arch_mn10200, /* Matsushita MN10200 */ ++ bfd_arch_mn10300, /* Matsushita MN10300 */ ++#define bfd_mach_mn10300 300 ++#define bfd_mach_am33 330 ++#define bfd_mach_am33_2 332 ++ bfd_arch_fr30, ++#define bfd_mach_fr30 0x46523330 ++ bfd_arch_frv, ++#define bfd_mach_frv 1 ++#define bfd_mach_frvsimple 2 ++#define bfd_mach_fr300 300 ++#define bfd_mach_fr400 400 ++#define bfd_mach_fr450 450 ++#define bfd_mach_frvtomcat 499 /* fr500 prototype */ ++#define bfd_mach_fr500 500 ++#define bfd_mach_fr550 550 ++ bfd_arch_mcore, ++ bfd_arch_ia64, /* HP/Intel ia64 */ ++#define bfd_mach_ia64_elf64 64 ++#define bfd_mach_ia64_elf32 32 ++ bfd_arch_ip2k, /* Ubicom IP2K microcontrollers. */ ++#define bfd_mach_ip2022 1 ++#define bfd_mach_ip2022ext 2 ++ bfd_arch_iq2000, /* Vitesse IQ2000. */ ++#define bfd_mach_iq2000 1 ++#define bfd_mach_iq10 2 ++ bfd_arch_ms1, ++#define bfd_mach_ms1 1 ++#define bfd_mach_mrisc2 2 ++ bfd_arch_pj, ++ bfd_arch_avr, /* Atmel AVR microcontrollers. */ ++#define bfd_mach_avr1 1 ++#define bfd_mach_avr2 2 ++#define bfd_mach_avr3 3 ++#define bfd_mach_avr4 4 ++#define bfd_mach_avr5 5 ++ bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ ++#define bfd_mach_cr16c 1 ++ bfd_arch_crx, /* National Semiconductor CRX. */ ++#define bfd_mach_crx 1 ++ bfd_arch_cris, /* Axis CRIS */ ++#define bfd_mach_cris_v0_v10 255 ++#define bfd_mach_cris_v32 32 ++#define bfd_mach_cris_v10_v32 1032 ++ bfd_arch_s390, /* IBM s390 */ ++#define bfd_mach_s390_31 31 ++#define bfd_mach_s390_64 64 ++ bfd_arch_openrisc, /* OpenRISC */ ++ bfd_arch_mmix, /* Donald Knuth's educational processor. */ ++ bfd_arch_xstormy16, ++#define bfd_mach_xstormy16 1 ++ bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ ++#define bfd_mach_msp11 11 ++#define bfd_mach_msp110 110 ++#define bfd_mach_msp12 12 ++#define bfd_mach_msp13 13 ++#define bfd_mach_msp14 14 ++#define bfd_mach_msp15 15 ++#define bfd_mach_msp16 16 ++#define bfd_mach_msp31 31 ++#define bfd_mach_msp32 32 ++#define bfd_mach_msp33 33 ++#define bfd_mach_msp41 41 ++#define bfd_mach_msp42 42 ++#define bfd_mach_msp43 43 ++#define bfd_mach_msp44 44 ++ bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ ++#define bfd_mach_xtensa 1 ++ bfd_arch_maxq, /* Dallas MAXQ 10/20 */ ++#define bfd_mach_maxq10 10 ++#define bfd_mach_maxq20 20 ++ bfd_arch_last ++ }; ++ ++typedef struct bfd_arch_info ++{ ++ int bits_per_word; ++ int bits_per_address; ++ int bits_per_byte; ++ enum bfd_architecture arch; ++ unsigned long mach; ++ const char *arch_name; ++ const char *printable_name; ++ unsigned int section_align_power; ++ /* TRUE if this is the default machine for the architecture. ++ The default arch should be the first entry for an arch so that ++ all the entries for that arch can be accessed via <>. */ ++ bfd_boolean the_default; ++ const struct bfd_arch_info * (*compatible) ++ (const struct bfd_arch_info *a, const struct bfd_arch_info *b); ++ ++ bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); ++ ++ const struct bfd_arch_info *next; ++} ++bfd_arch_info_type; ++ ++const char *bfd_printable_name (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_scan_arch (const char *string); ++ ++const char **bfd_arch_list (void); ++ ++const bfd_arch_info_type *bfd_arch_get_compatible ++ (const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); ++ ++void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); ++ ++enum bfd_architecture bfd_get_arch (bfd *abfd); ++ ++unsigned long bfd_get_mach (bfd *abfd); ++ ++unsigned int bfd_arch_bits_per_byte (bfd *abfd); ++ ++unsigned int bfd_arch_bits_per_address (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_lookup_arch ++ (enum bfd_architecture arch, unsigned long machine); ++ ++const char *bfd_printable_arch_mach ++ (enum bfd_architecture arch, unsigned long machine); ++ ++unsigned int bfd_octets_per_byte (bfd *abfd); ++ ++unsigned int bfd_arch_mach_octets_per_byte ++ (enum bfd_architecture arch, unsigned long machine); ++ ++/* Extracted from reloc.c. */ ++typedef enum bfd_reloc_status ++{ ++ /* No errors detected. */ ++ bfd_reloc_ok, ++ ++ /* The relocation was performed, but there was an overflow. */ ++ bfd_reloc_overflow, ++ ++ /* The address to relocate was not within the section supplied. */ ++ bfd_reloc_outofrange, ++ ++ /* Used by special functions. */ ++ bfd_reloc_continue, ++ ++ /* Unsupported relocation size requested. */ ++ bfd_reloc_notsupported, ++ ++ /* Unused. */ ++ bfd_reloc_other, ++ ++ /* The symbol to relocate against was undefined. */ ++ bfd_reloc_undefined, ++ ++ /* The relocation was performed, but may not be ok - presently ++ generated only when linking i960 coff files with i960 b.out ++ symbols. If this type is returned, the error_message argument ++ to bfd_perform_relocation will be set. */ ++ bfd_reloc_dangerous ++ } ++ bfd_reloc_status_type; ++ ++ ++typedef struct reloc_cache_entry ++{ ++ /* A pointer into the canonical table of pointers. */ ++ struct bfd_symbol **sym_ptr_ptr; ++ ++ /* offset in section. */ ++ bfd_size_type address; ++ ++ /* addend for relocation value. */ ++ bfd_vma addend; ++ ++ /* Pointer to how to perform the required relocation. */ ++ reloc_howto_type *howto; ++ ++} ++arelent; ++ ++enum complain_overflow ++{ ++ /* Do not complain on overflow. */ ++ complain_overflow_dont, ++ ++ /* Complain if the bitfield overflows, whether it is considered ++ as signed or unsigned. */ ++ complain_overflow_bitfield, ++ ++ /* Complain if the value overflows when considered as signed ++ number. */ ++ complain_overflow_signed, ++ ++ /* Complain if the value overflows when considered as an ++ unsigned number. */ ++ complain_overflow_unsigned ++}; ++ ++struct reloc_howto_struct ++{ ++ /* The type field has mainly a documentary use - the back end can ++ do what it wants with it, though normally the back end's ++ external idea of what a reloc number is stored ++ in this field. For example, a PC relative word relocation ++ in a coff environment has the type 023 - because that's ++ what the outside world calls a R_PCRWORD reloc. */ ++ unsigned int type; ++ ++ /* The value the final relocation is shifted right by. This drops ++ unwanted data from the relocation. */ ++ unsigned int rightshift; ++ ++ /* The size of the item to be relocated. This is *not* a ++ power-of-two measure. To get the number of bytes operated ++ on by a type of relocation, use bfd_get_reloc_size. */ ++ int size; ++ ++ /* The number of bits in the item to be relocated. This is used ++ when doing overflow checking. */ ++ unsigned int bitsize; ++ ++ /* Notes that the relocation is relative to the location in the ++ data section of the addend. The relocation function will ++ subtract from the relocation value the address of the location ++ being relocated. */ ++ bfd_boolean pc_relative; ++ ++ /* The bit position of the reloc value in the destination. ++ The relocated value is left shifted by this amount. */ ++ unsigned int bitpos; ++ ++ /* What type of overflow error should be checked for when ++ relocating. */ ++ enum complain_overflow complain_on_overflow; ++ ++ /* If this field is non null, then the supplied function is ++ called rather than the normal function. This allows really ++ strange relocation methods to be accommodated (e.g., i960 callj ++ instructions). */ ++ bfd_reloc_status_type (*special_function) ++ (bfd *, arelent *, struct bfd_symbol *, void *, asection *, ++ bfd *, char **); ++ ++ /* The textual name of the relocation type. */ ++ char *name; ++ ++ /* Some formats record a relocation addend in the section contents ++ rather than with the relocation. For ELF formats this is the ++ distinction between USE_REL and USE_RELA (though the code checks ++ for USE_REL == 1/0). The value of this field is TRUE if the ++ addend is recorded with the section contents; when performing a ++ partial link (ld -r) the section contents (the data) will be ++ modified. The value of this field is FALSE if addends are ++ recorded with the relocation (in arelent.addend); when performing ++ a partial link the relocation will be modified. ++ All relocations for all ELF USE_RELA targets should set this field ++ to FALSE (values of TRUE should be looked on with suspicion). ++ However, the converse is not true: not all relocations of all ELF ++ USE_REL targets set this field to TRUE. Why this is so is peculiar ++ to each particular target. For relocs that aren't used in partial ++ links (e.g. GOT stuff) it doesn't matter what this is set to. */ ++ bfd_boolean partial_inplace; ++ ++ /* src_mask selects the part of the instruction (or data) to be used ++ in the relocation sum. If the target relocations don't have an ++ addend in the reloc, eg. ELF USE_REL, src_mask will normally equal ++ dst_mask to extract the addend from the section contents. If ++ relocations do have an addend in the reloc, eg. ELF USE_RELA, this ++ field should be zero. Non-zero values for ELF USE_RELA targets are ++ bogus as in those cases the value in the dst_mask part of the ++ section contents should be treated as garbage. */ ++ bfd_vma src_mask; ++ ++ /* dst_mask selects which parts of the instruction (or data) are ++ replaced with a relocated value. */ ++ bfd_vma dst_mask; ++ ++ /* When some formats create PC relative instructions, they leave ++ the value of the pc of the place being relocated in the offset ++ slot of the instruction, so that a PC relative relocation can ++ be made just by adding in an ordinary offset (e.g., sun3 a.out). ++ Some formats leave the displacement part of an instruction ++ empty (e.g., m88k bcs); this flag signals the fact. */ ++ bfd_boolean pcrel_offset; ++}; ++ ++#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ ++ { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } ++#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ ++ HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ ++ NAME, FALSE, 0, 0, IN) ++ ++#define EMPTY_HOWTO(C) \ ++ HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ ++ NULL, FALSE, 0, 0, FALSE) ++ ++#define HOWTO_PREPARE(relocation, symbol) \ ++ { \ ++ if (symbol != NULL) \ ++ { \ ++ if (bfd_is_com_section (symbol->section)) \ ++ { \ ++ relocation = 0; \ ++ } \ ++ else \ ++ { \ ++ relocation = symbol->value; \ ++ } \ ++ } \ ++ } ++ ++unsigned int bfd_get_reloc_size (reloc_howto_type *); ++ ++typedef struct relent_chain ++{ ++ arelent relent; ++ struct relent_chain *next; ++} ++arelent_chain; ++ ++bfd_reloc_status_type bfd_check_overflow ++ (enum complain_overflow how, ++ unsigned int bitsize, ++ unsigned int rightshift, ++ unsigned int addrsize, ++ bfd_vma relocation); ++ ++bfd_reloc_status_type bfd_perform_relocation ++ (bfd *abfd, ++ arelent *reloc_entry, ++ void *data, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message); ++ ++bfd_reloc_status_type bfd_install_relocation ++ (bfd *abfd, ++ arelent *reloc_entry, ++ void *data, bfd_vma data_start, ++ asection *input_section, ++ char **error_message); ++ ++enum bfd_reloc_code_real { ++ _dummy_first_bfd_reloc_code_real, ++ ++ ++/* Basic absolute relocations of N bits. */ ++ BFD_RELOC_64, ++ BFD_RELOC_32, ++ BFD_RELOC_26, ++ BFD_RELOC_24, ++ BFD_RELOC_16, ++ BFD_RELOC_14, ++ BFD_RELOC_8, ++ ++/* PC-relative relocations. Sometimes these are relative to the address ++of the relocation itself; sometimes they are relative to the start of ++the section containing the relocation. It depends on the specific target. ++ ++The 24-bit relocation is used in some Intel 960 configurations. */ ++ BFD_RELOC_64_PCREL, ++ BFD_RELOC_32_PCREL, ++ BFD_RELOC_24_PCREL, ++ BFD_RELOC_16_PCREL, ++ BFD_RELOC_12_PCREL, ++ BFD_RELOC_8_PCREL, ++ ++/* Section relative relocations. Some targets need this for DWARF2. */ ++ BFD_RELOC_32_SECREL, ++ ++/* For ELF. */ ++ BFD_RELOC_32_GOT_PCREL, ++ BFD_RELOC_16_GOT_PCREL, ++ BFD_RELOC_8_GOT_PCREL, ++ BFD_RELOC_32_GOTOFF, ++ BFD_RELOC_16_GOTOFF, ++ BFD_RELOC_LO16_GOTOFF, ++ BFD_RELOC_HI16_GOTOFF, ++ BFD_RELOC_HI16_S_GOTOFF, ++ BFD_RELOC_8_GOTOFF, ++ BFD_RELOC_64_PLT_PCREL, ++ BFD_RELOC_32_PLT_PCREL, ++ BFD_RELOC_24_PLT_PCREL, ++ BFD_RELOC_16_PLT_PCREL, ++ BFD_RELOC_8_PLT_PCREL, ++ BFD_RELOC_64_PLTOFF, ++ BFD_RELOC_32_PLTOFF, ++ BFD_RELOC_16_PLTOFF, ++ BFD_RELOC_LO16_PLTOFF, ++ BFD_RELOC_HI16_PLTOFF, ++ BFD_RELOC_HI16_S_PLTOFF, ++ BFD_RELOC_8_PLTOFF, ++ ++/* Relocations used by 68K ELF. */ ++ BFD_RELOC_68K_GLOB_DAT, ++ BFD_RELOC_68K_JMP_SLOT, ++ BFD_RELOC_68K_RELATIVE, ++ ++/* Linkage-table relative. */ ++ BFD_RELOC_32_BASEREL, ++ BFD_RELOC_16_BASEREL, ++ BFD_RELOC_LO16_BASEREL, ++ BFD_RELOC_HI16_BASEREL, ++ BFD_RELOC_HI16_S_BASEREL, ++ BFD_RELOC_8_BASEREL, ++ BFD_RELOC_RVA, ++ ++/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ ++ BFD_RELOC_8_FFnn, ++ ++/* These PC-relative relocations are stored as word displacements -- ++i.e., byte displacements shifted right two bits. The 30-bit word ++displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the ++SPARC. (SPARC tools generally refer to this as <>.) The ++signed 16-bit displacement is used on the MIPS, and the 23-bit ++displacement is used on the Alpha. */ ++ BFD_RELOC_32_PCREL_S2, ++ BFD_RELOC_16_PCREL_S2, ++ BFD_RELOC_23_PCREL_S2, ++ ++/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of ++the target word. These are used on the SPARC. */ ++ BFD_RELOC_HI22, ++ BFD_RELOC_LO10, ++ ++/* For systems that allocate a Global Pointer register, these are ++displacements off that register. These relocation types are ++handled specially, because the value the register will have is ++decided relatively late. */ ++ BFD_RELOC_GPREL16, ++ BFD_RELOC_GPREL32, ++ ++/* Reloc types used for i960/b.out. */ ++ BFD_RELOC_I960_CALLJ, ++ ++/* SPARC ELF relocations. There is probably some overlap with other ++relocation types already defined. */ ++ BFD_RELOC_NONE, ++ BFD_RELOC_SPARC_WDISP22, ++ BFD_RELOC_SPARC22, ++ BFD_RELOC_SPARC13, ++ BFD_RELOC_SPARC_GOT10, ++ BFD_RELOC_SPARC_GOT13, ++ BFD_RELOC_SPARC_GOT22, ++ BFD_RELOC_SPARC_PC10, ++ BFD_RELOC_SPARC_PC22, ++ BFD_RELOC_SPARC_WPLT30, ++ BFD_RELOC_SPARC_COPY, ++ BFD_RELOC_SPARC_GLOB_DAT, ++ BFD_RELOC_SPARC_JMP_SLOT, ++ BFD_RELOC_SPARC_RELATIVE, ++ BFD_RELOC_SPARC_UA16, ++ BFD_RELOC_SPARC_UA32, ++ BFD_RELOC_SPARC_UA64, ++ ++/* I think these are specific to SPARC a.out (e.g., Sun 4). */ ++ BFD_RELOC_SPARC_BASE13, ++ BFD_RELOC_SPARC_BASE22, ++ ++/* SPARC64 relocations */ ++#define BFD_RELOC_SPARC_64 BFD_RELOC_64 ++ BFD_RELOC_SPARC_10, ++ BFD_RELOC_SPARC_11, ++ BFD_RELOC_SPARC_OLO10, ++ BFD_RELOC_SPARC_HH22, ++ BFD_RELOC_SPARC_HM10, ++ BFD_RELOC_SPARC_LM22, ++ BFD_RELOC_SPARC_PC_HH22, ++ BFD_RELOC_SPARC_PC_HM10, ++ BFD_RELOC_SPARC_PC_LM22, ++ BFD_RELOC_SPARC_WDISP16, ++ BFD_RELOC_SPARC_WDISP19, ++ BFD_RELOC_SPARC_7, ++ BFD_RELOC_SPARC_6, ++ BFD_RELOC_SPARC_5, ++#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL ++ BFD_RELOC_SPARC_PLT32, ++ BFD_RELOC_SPARC_PLT64, ++ BFD_RELOC_SPARC_HIX22, ++ BFD_RELOC_SPARC_LOX10, ++ BFD_RELOC_SPARC_H44, ++ BFD_RELOC_SPARC_M44, ++ BFD_RELOC_SPARC_L44, ++ BFD_RELOC_SPARC_REGISTER, ++ ++/* SPARC little endian relocation */ ++ BFD_RELOC_SPARC_REV32, ++ ++/* SPARC TLS relocations */ ++ BFD_RELOC_SPARC_TLS_GD_HI22, ++ BFD_RELOC_SPARC_TLS_GD_LO10, ++ BFD_RELOC_SPARC_TLS_GD_ADD, ++ BFD_RELOC_SPARC_TLS_GD_CALL, ++ BFD_RELOC_SPARC_TLS_LDM_HI22, ++ BFD_RELOC_SPARC_TLS_LDM_LO10, ++ BFD_RELOC_SPARC_TLS_LDM_ADD, ++ BFD_RELOC_SPARC_TLS_LDM_CALL, ++ BFD_RELOC_SPARC_TLS_LDO_HIX22, ++ BFD_RELOC_SPARC_TLS_LDO_LOX10, ++ BFD_RELOC_SPARC_TLS_LDO_ADD, ++ BFD_RELOC_SPARC_TLS_IE_HI22, ++ BFD_RELOC_SPARC_TLS_IE_LO10, ++ BFD_RELOC_SPARC_TLS_IE_LD, ++ BFD_RELOC_SPARC_TLS_IE_LDX, ++ BFD_RELOC_SPARC_TLS_IE_ADD, ++ BFD_RELOC_SPARC_TLS_LE_HIX22, ++ BFD_RELOC_SPARC_TLS_LE_LOX10, ++ BFD_RELOC_SPARC_TLS_DTPMOD32, ++ BFD_RELOC_SPARC_TLS_DTPMOD64, ++ BFD_RELOC_SPARC_TLS_DTPOFF32, ++ BFD_RELOC_SPARC_TLS_DTPOFF64, ++ BFD_RELOC_SPARC_TLS_TPOFF32, ++ BFD_RELOC_SPARC_TLS_TPOFF64, ++ ++/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or ++"addend" in some special way. ++For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when ++writing; when reading, it will be the absolute section symbol. The ++addend is the displacement in bytes of the "lda" instruction from ++the "ldah" instruction (which is at the address of this reloc). */ ++ BFD_RELOC_ALPHA_GPDISP_HI16, ++ ++/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as ++with GPDISP_HI16 relocs. The addend is ignored when writing the ++relocations out, and is filled in with the file's GP value on ++reading, for convenience. */ ++ BFD_RELOC_ALPHA_GPDISP_LO16, ++ ++/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 ++relocation except that there is no accompanying GPDISP_LO16 ++relocation. */ ++ BFD_RELOC_ALPHA_GPDISP, ++ ++/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; ++the assembler turns it into a LDQ instruction to load the address of ++the symbol, and then fills in a register in the real instruction. ++ ++The LITERAL reloc, at the LDQ instruction, refers to the .lita ++section symbol. The addend is ignored when writing, but is filled ++in with the file's GP value on reading, for convenience, as with the ++GPDISP_LO16 reloc. ++ ++The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. ++It should refer to the symbol to be referenced, as with 16_GOTOFF, ++but it generates output not based on the position within the .got ++section, but relative to the GP value chosen for the file during the ++final link stage. ++ ++The LITUSE reloc, on the instruction using the loaded address, gives ++information to the linker that it might be able to use to optimize ++away some literal section references. The symbol is ignored (read ++as the absolute section symbol), and the "addend" indicates the type ++of instruction using the register: ++1 - "memory" fmt insn ++2 - byte-manipulation (byte offset reg) ++3 - jsr (target of branch) */ ++ BFD_RELOC_ALPHA_LITERAL, ++ BFD_RELOC_ALPHA_ELF_LITERAL, ++ BFD_RELOC_ALPHA_LITUSE, ++ ++/* The HINT relocation indicates a value that should be filled into the ++"hint" field of a jmp/jsr/ret instruction, for possible branch- ++prediction logic which may be provided on some processors. */ ++ BFD_RELOC_ALPHA_HINT, ++ ++/* The LINKAGE relocation outputs a linkage pair in the object file, ++which is filled by the linker. */ ++ BFD_RELOC_ALPHA_LINKAGE, ++ ++/* The CODEADDR relocation outputs a STO_CA in the object file, ++which is filled by the linker. */ ++ BFD_RELOC_ALPHA_CODEADDR, ++ ++/* The GPREL_HI/LO relocations together form a 32-bit offset from the ++GP register. */ ++ BFD_RELOC_ALPHA_GPREL_HI16, ++ BFD_RELOC_ALPHA_GPREL_LO16, ++ ++/* Like BFD_RELOC_23_PCREL_S2, except that the source and target must ++share a common GP, and the target address is adjusted for ++STO_ALPHA_STD_GPLOAD. */ ++ BFD_RELOC_ALPHA_BRSGP, ++ ++/* Alpha thread-local storage relocations. */ ++ BFD_RELOC_ALPHA_TLSGD, ++ BFD_RELOC_ALPHA_TLSLDM, ++ BFD_RELOC_ALPHA_DTPMOD64, ++ BFD_RELOC_ALPHA_GOTDTPREL16, ++ BFD_RELOC_ALPHA_DTPREL64, ++ BFD_RELOC_ALPHA_DTPREL_HI16, ++ BFD_RELOC_ALPHA_DTPREL_LO16, ++ BFD_RELOC_ALPHA_DTPREL16, ++ BFD_RELOC_ALPHA_GOTTPREL16, ++ BFD_RELOC_ALPHA_TPREL64, ++ BFD_RELOC_ALPHA_TPREL_HI16, ++ BFD_RELOC_ALPHA_TPREL_LO16, ++ BFD_RELOC_ALPHA_TPREL16, ++ ++/* Bits 27..2 of the relocation address shifted right 2 bits; ++simple reloc otherwise. */ ++ BFD_RELOC_MIPS_JMP, ++ ++/* The MIPS16 jump instruction. */ ++ BFD_RELOC_MIPS16_JMP, ++ ++/* MIPS16 GP relative reloc. */ ++ BFD_RELOC_MIPS16_GPREL, ++ ++/* High 16 bits of 32-bit value; simple reloc. */ ++ BFD_RELOC_HI16, ++ ++/* High 16 bits of 32-bit value but the low 16 bits will be sign ++extended and added to form the final result. If the low 16 ++bits form a negative number, we need to add one to the high value ++to compensate for the borrow when the low bits are added. */ ++ BFD_RELOC_HI16_S, ++ ++/* Low 16 bits. */ ++ BFD_RELOC_LO16, ++ ++/* High 16 bits of 32-bit pc-relative value */ ++ BFD_RELOC_HI16_PCREL, ++ ++/* High 16 bits of 32-bit pc-relative value, adjusted */ ++ BFD_RELOC_HI16_S_PCREL, ++ ++/* Low 16 bits of pc-relative value */ ++ BFD_RELOC_LO16_PCREL, ++ ++/* MIPS16 high 16 bits of 32-bit value. */ ++ BFD_RELOC_MIPS16_HI16, ++ ++/* MIPS16 high 16 bits of 32-bit value but the low 16 bits will be sign ++extended and added to form the final result. If the low 16 ++bits form a negative number, we need to add one to the high value ++to compensate for the borrow when the low bits are added. */ ++ BFD_RELOC_MIPS16_HI16_S, ++ ++/* MIPS16 low 16 bits. */ ++ BFD_RELOC_MIPS16_LO16, ++ ++/* Relocation against a MIPS literal section. */ ++ BFD_RELOC_MIPS_LITERAL, ++ ++/* MIPS ELF relocations. */ ++ BFD_RELOC_MIPS_GOT16, ++ BFD_RELOC_MIPS_CALL16, ++ BFD_RELOC_MIPS_GOT_HI16, ++ BFD_RELOC_MIPS_GOT_LO16, ++ BFD_RELOC_MIPS_CALL_HI16, ++ BFD_RELOC_MIPS_CALL_LO16, ++ BFD_RELOC_MIPS_SUB, ++ BFD_RELOC_MIPS_GOT_PAGE, ++ BFD_RELOC_MIPS_GOT_OFST, ++ BFD_RELOC_MIPS_GOT_DISP, ++ BFD_RELOC_MIPS_SHIFT5, ++ BFD_RELOC_MIPS_SHIFT6, ++ BFD_RELOC_MIPS_INSERT_A, ++ BFD_RELOC_MIPS_INSERT_B, ++ BFD_RELOC_MIPS_DELETE, ++ BFD_RELOC_MIPS_HIGHEST, ++ BFD_RELOC_MIPS_HIGHER, ++ BFD_RELOC_MIPS_SCN_DISP, ++ BFD_RELOC_MIPS_REL16, ++ BFD_RELOC_MIPS_RELGOT, ++ BFD_RELOC_MIPS_JALR, ++ BFD_RELOC_MIPS_TLS_DTPMOD32, ++ BFD_RELOC_MIPS_TLS_DTPREL32, ++ BFD_RELOC_MIPS_TLS_DTPMOD64, ++ BFD_RELOC_MIPS_TLS_DTPREL64, ++ BFD_RELOC_MIPS_TLS_GD, ++ BFD_RELOC_MIPS_TLS_LDM, ++ BFD_RELOC_MIPS_TLS_DTPREL_HI16, ++ BFD_RELOC_MIPS_TLS_DTPREL_LO16, ++ BFD_RELOC_MIPS_TLS_GOTTPREL, ++ BFD_RELOC_MIPS_TLS_TPREL32, ++ BFD_RELOC_MIPS_TLS_TPREL64, ++ BFD_RELOC_MIPS_TLS_TPREL_HI16, ++ BFD_RELOC_MIPS_TLS_TPREL_LO16, ++ ++ ++/* Fujitsu Frv Relocations. */ ++ BFD_RELOC_FRV_LABEL16, ++ BFD_RELOC_FRV_LABEL24, ++ BFD_RELOC_FRV_LO16, ++ BFD_RELOC_FRV_HI16, ++ BFD_RELOC_FRV_GPREL12, ++ BFD_RELOC_FRV_GPRELU12, ++ BFD_RELOC_FRV_GPREL32, ++ BFD_RELOC_FRV_GPRELHI, ++ BFD_RELOC_FRV_GPRELLO, ++ BFD_RELOC_FRV_GOT12, ++ BFD_RELOC_FRV_GOTHI, ++ BFD_RELOC_FRV_GOTLO, ++ BFD_RELOC_FRV_FUNCDESC, ++ BFD_RELOC_FRV_FUNCDESC_GOT12, ++ BFD_RELOC_FRV_FUNCDESC_GOTHI, ++ BFD_RELOC_FRV_FUNCDESC_GOTLO, ++ BFD_RELOC_FRV_FUNCDESC_VALUE, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFF12, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFFHI, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFFLO, ++ BFD_RELOC_FRV_GOTOFF12, ++ BFD_RELOC_FRV_GOTOFFHI, ++ BFD_RELOC_FRV_GOTOFFLO, ++ BFD_RELOC_FRV_GETTLSOFF, ++ BFD_RELOC_FRV_TLSDESC_VALUE, ++ BFD_RELOC_FRV_GOTTLSDESC12, ++ BFD_RELOC_FRV_GOTTLSDESCHI, ++ BFD_RELOC_FRV_GOTTLSDESCLO, ++ BFD_RELOC_FRV_TLSMOFF12, ++ BFD_RELOC_FRV_TLSMOFFHI, ++ BFD_RELOC_FRV_TLSMOFFLO, ++ BFD_RELOC_FRV_GOTTLSOFF12, ++ BFD_RELOC_FRV_GOTTLSOFFHI, ++ BFD_RELOC_FRV_GOTTLSOFFLO, ++ BFD_RELOC_FRV_TLSOFF, ++ BFD_RELOC_FRV_TLSDESC_RELAX, ++ BFD_RELOC_FRV_GETTLSOFF_RELAX, ++ BFD_RELOC_FRV_TLSOFF_RELAX, ++ BFD_RELOC_FRV_TLSMOFF, ++ ++ ++/* This is a 24bit GOT-relative reloc for the mn10300. */ ++ BFD_RELOC_MN10300_GOTOFF24, ++ ++/* This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT32, ++ ++/* This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT24, ++ ++/* This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT16, ++ ++/* Copy symbol at runtime. */ ++ BFD_RELOC_MN10300_COPY, ++ ++/* Create GOT entry. */ ++ BFD_RELOC_MN10300_GLOB_DAT, ++ ++/* Create PLT entry. */ ++ BFD_RELOC_MN10300_JMP_SLOT, ++ ++/* Adjust by program base. */ ++ BFD_RELOC_MN10300_RELATIVE, ++ ++ ++/* i386/elf relocations */ ++ BFD_RELOC_386_GOT32, ++ BFD_RELOC_386_PLT32, ++ BFD_RELOC_386_COPY, ++ BFD_RELOC_386_GLOB_DAT, ++ BFD_RELOC_386_JUMP_SLOT, ++ BFD_RELOC_386_RELATIVE, ++ BFD_RELOC_386_GOTOFF, ++ BFD_RELOC_386_GOTPC, ++ BFD_RELOC_386_TLS_TPOFF, ++ BFD_RELOC_386_TLS_IE, ++ BFD_RELOC_386_TLS_GOTIE, ++ BFD_RELOC_386_TLS_LE, ++ BFD_RELOC_386_TLS_GD, ++ BFD_RELOC_386_TLS_LDM, ++ BFD_RELOC_386_TLS_LDO_32, ++ BFD_RELOC_386_TLS_IE_32, ++ BFD_RELOC_386_TLS_LE_32, ++ BFD_RELOC_386_TLS_DTPMOD32, ++ BFD_RELOC_386_TLS_DTPOFF32, ++ BFD_RELOC_386_TLS_TPOFF32, ++ ++/* x86-64/elf relocations */ ++ BFD_RELOC_X86_64_GOT32, ++ BFD_RELOC_X86_64_PLT32, ++ BFD_RELOC_X86_64_COPY, ++ BFD_RELOC_X86_64_GLOB_DAT, ++ BFD_RELOC_X86_64_JUMP_SLOT, ++ BFD_RELOC_X86_64_RELATIVE, ++ BFD_RELOC_X86_64_GOTPCREL, ++ BFD_RELOC_X86_64_32S, ++ BFD_RELOC_X86_64_DTPMOD64, ++ BFD_RELOC_X86_64_DTPOFF64, ++ BFD_RELOC_X86_64_TPOFF64, ++ BFD_RELOC_X86_64_TLSGD, ++ BFD_RELOC_X86_64_TLSLD, ++ BFD_RELOC_X86_64_DTPOFF32, ++ BFD_RELOC_X86_64_GOTTPOFF, ++ BFD_RELOC_X86_64_TPOFF32, ++ BFD_RELOC_X86_64_GOTOFF64, ++ BFD_RELOC_X86_64_GOTPC32, ++ ++/* ns32k relocations */ ++ BFD_RELOC_NS32K_IMM_8, ++ BFD_RELOC_NS32K_IMM_16, ++ BFD_RELOC_NS32K_IMM_32, ++ BFD_RELOC_NS32K_IMM_8_PCREL, ++ BFD_RELOC_NS32K_IMM_16_PCREL, ++ BFD_RELOC_NS32K_IMM_32_PCREL, ++ BFD_RELOC_NS32K_DISP_8, ++ BFD_RELOC_NS32K_DISP_16, ++ BFD_RELOC_NS32K_DISP_32, ++ BFD_RELOC_NS32K_DISP_8_PCREL, ++ BFD_RELOC_NS32K_DISP_16_PCREL, ++ BFD_RELOC_NS32K_DISP_32_PCREL, ++ ++/* PDP11 relocations */ ++ BFD_RELOC_PDP11_DISP_8_PCREL, ++ BFD_RELOC_PDP11_DISP_6_PCREL, ++ ++/* Picojava relocs. Not all of these appear in object files. */ ++ BFD_RELOC_PJ_CODE_HI16, ++ BFD_RELOC_PJ_CODE_LO16, ++ BFD_RELOC_PJ_CODE_DIR16, ++ BFD_RELOC_PJ_CODE_DIR32, ++ BFD_RELOC_PJ_CODE_REL16, ++ BFD_RELOC_PJ_CODE_REL32, ++ ++/* Power(rs6000) and PowerPC relocations. */ ++ BFD_RELOC_PPC_B26, ++ BFD_RELOC_PPC_BA26, ++ BFD_RELOC_PPC_TOC16, ++ BFD_RELOC_PPC_B16, ++ BFD_RELOC_PPC_B16_BRTAKEN, ++ BFD_RELOC_PPC_B16_BRNTAKEN, ++ BFD_RELOC_PPC_BA16, ++ BFD_RELOC_PPC_BA16_BRTAKEN, ++ BFD_RELOC_PPC_BA16_BRNTAKEN, ++ BFD_RELOC_PPC_COPY, ++ BFD_RELOC_PPC_GLOB_DAT, ++ BFD_RELOC_PPC_JMP_SLOT, ++ BFD_RELOC_PPC_RELATIVE, ++ BFD_RELOC_PPC_LOCAL24PC, ++ BFD_RELOC_PPC_EMB_NADDR32, ++ BFD_RELOC_PPC_EMB_NADDR16, ++ BFD_RELOC_PPC_EMB_NADDR16_LO, ++ BFD_RELOC_PPC_EMB_NADDR16_HI, ++ BFD_RELOC_PPC_EMB_NADDR16_HA, ++ BFD_RELOC_PPC_EMB_SDAI16, ++ BFD_RELOC_PPC_EMB_SDA2I16, ++ BFD_RELOC_PPC_EMB_SDA2REL, ++ BFD_RELOC_PPC_EMB_SDA21, ++ BFD_RELOC_PPC_EMB_MRKREF, ++ BFD_RELOC_PPC_EMB_RELSEC16, ++ BFD_RELOC_PPC_EMB_RELST_LO, ++ BFD_RELOC_PPC_EMB_RELST_HI, ++ BFD_RELOC_PPC_EMB_RELST_HA, ++ BFD_RELOC_PPC_EMB_BIT_FLD, ++ BFD_RELOC_PPC_EMB_RELSDA, ++ BFD_RELOC_PPC64_HIGHER, ++ BFD_RELOC_PPC64_HIGHER_S, ++ BFD_RELOC_PPC64_HIGHEST, ++ BFD_RELOC_PPC64_HIGHEST_S, ++ BFD_RELOC_PPC64_TOC16_LO, ++ BFD_RELOC_PPC64_TOC16_HI, ++ BFD_RELOC_PPC64_TOC16_HA, ++ BFD_RELOC_PPC64_TOC, ++ BFD_RELOC_PPC64_PLTGOT16, ++ BFD_RELOC_PPC64_PLTGOT16_LO, ++ BFD_RELOC_PPC64_PLTGOT16_HI, ++ BFD_RELOC_PPC64_PLTGOT16_HA, ++ BFD_RELOC_PPC64_ADDR16_DS, ++ BFD_RELOC_PPC64_ADDR16_LO_DS, ++ BFD_RELOC_PPC64_GOT16_DS, ++ BFD_RELOC_PPC64_GOT16_LO_DS, ++ BFD_RELOC_PPC64_PLT16_LO_DS, ++ BFD_RELOC_PPC64_SECTOFF_DS, ++ BFD_RELOC_PPC64_SECTOFF_LO_DS, ++ BFD_RELOC_PPC64_TOC16_DS, ++ BFD_RELOC_PPC64_TOC16_LO_DS, ++ BFD_RELOC_PPC64_PLTGOT16_DS, ++ BFD_RELOC_PPC64_PLTGOT16_LO_DS, ++ ++/* PowerPC and PowerPC64 thread-local storage relocations. */ ++ BFD_RELOC_PPC_TLS, ++ BFD_RELOC_PPC_DTPMOD, ++ BFD_RELOC_PPC_TPREL16, ++ BFD_RELOC_PPC_TPREL16_LO, ++ BFD_RELOC_PPC_TPREL16_HI, ++ BFD_RELOC_PPC_TPREL16_HA, ++ BFD_RELOC_PPC_TPREL, ++ BFD_RELOC_PPC_DTPREL16, ++ BFD_RELOC_PPC_DTPREL16_LO, ++ BFD_RELOC_PPC_DTPREL16_HI, ++ BFD_RELOC_PPC_DTPREL16_HA, ++ BFD_RELOC_PPC_DTPREL, ++ BFD_RELOC_PPC_GOT_TLSGD16, ++ BFD_RELOC_PPC_GOT_TLSGD16_LO, ++ BFD_RELOC_PPC_GOT_TLSGD16_HI, ++ BFD_RELOC_PPC_GOT_TLSGD16_HA, ++ BFD_RELOC_PPC_GOT_TLSLD16, ++ BFD_RELOC_PPC_GOT_TLSLD16_LO, ++ BFD_RELOC_PPC_GOT_TLSLD16_HI, ++ BFD_RELOC_PPC_GOT_TLSLD16_HA, ++ BFD_RELOC_PPC_GOT_TPREL16, ++ BFD_RELOC_PPC_GOT_TPREL16_LO, ++ BFD_RELOC_PPC_GOT_TPREL16_HI, ++ BFD_RELOC_PPC_GOT_TPREL16_HA, ++ BFD_RELOC_PPC_GOT_DTPREL16, ++ BFD_RELOC_PPC_GOT_DTPREL16_LO, ++ BFD_RELOC_PPC_GOT_DTPREL16_HI, ++ BFD_RELOC_PPC_GOT_DTPREL16_HA, ++ BFD_RELOC_PPC64_TPREL16_DS, ++ BFD_RELOC_PPC64_TPREL16_LO_DS, ++ BFD_RELOC_PPC64_TPREL16_HIGHER, ++ BFD_RELOC_PPC64_TPREL16_HIGHERA, ++ BFD_RELOC_PPC64_TPREL16_HIGHEST, ++ BFD_RELOC_PPC64_TPREL16_HIGHESTA, ++ BFD_RELOC_PPC64_DTPREL16_DS, ++ BFD_RELOC_PPC64_DTPREL16_LO_DS, ++ BFD_RELOC_PPC64_DTPREL16_HIGHER, ++ BFD_RELOC_PPC64_DTPREL16_HIGHERA, ++ BFD_RELOC_PPC64_DTPREL16_HIGHEST, ++ BFD_RELOC_PPC64_DTPREL16_HIGHESTA, ++ ++/* IBM 370/390 relocations */ ++ BFD_RELOC_I370_D12, ++ ++/* The type of reloc used to build a constructor table - at the moment ++probably a 32 bit wide absolute relocation, but the target can choose. ++It generally does map to one of the other relocation types. */ ++ BFD_RELOC_CTOR, ++ ++/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are ++not stored in the instruction. */ ++ BFD_RELOC_ARM_PCREL_BRANCH, ++ ++/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is ++not stored in the instruction. The 2nd lowest bit comes from a 1 bit ++field in the instruction. */ ++ BFD_RELOC_ARM_PCREL_BLX, ++ ++/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is ++not stored in the instruction. The 2nd lowest bit comes from a 1 bit ++field in the instruction. */ ++ BFD_RELOC_THUMB_PCREL_BLX, ++ ++/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. ++The lowest bit must be zero and is not stored in the instruction. ++Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an ++"nn" one smaller in all cases. Note further that BRANCH23 ++corresponds to R_ARM_THM_CALL. */ ++ BFD_RELOC_THUMB_PCREL_BRANCH7, ++ BFD_RELOC_THUMB_PCREL_BRANCH9, ++ BFD_RELOC_THUMB_PCREL_BRANCH12, ++ BFD_RELOC_THUMB_PCREL_BRANCH20, ++ BFD_RELOC_THUMB_PCREL_BRANCH23, ++ BFD_RELOC_THUMB_PCREL_BRANCH25, ++ ++/* 12-bit immediate offset, used in ARM-format ldr and str instructions. */ ++ BFD_RELOC_ARM_OFFSET_IMM, ++ ++/* 5-bit immediate offset, used in Thumb-format ldr and str instructions. */ ++ BFD_RELOC_ARM_THUMB_OFFSET, ++ ++/* Pc-relative or absolute relocation depending on target. Used for ++entries in .init_array sections. */ ++ BFD_RELOC_ARM_TARGET1, ++ ++/* Read-only segment base relative address. */ ++ BFD_RELOC_ARM_ROSEGREL32, ++ ++/* Data segment base relative address. */ ++ BFD_RELOC_ARM_SBREL32, ++ ++/* This reloc is used for references to RTTI data from exception handling ++tables. The actual definition depends on the target. It may be a ++pc-relative or some form of GOT-indirect relocation. */ ++ BFD_RELOC_ARM_TARGET2, ++ ++/* 31-bit PC relative address. */ ++ BFD_RELOC_ARM_PREL31, ++ ++/* Relocations for setting up GOTs and PLTs for shared libraries. */ ++ BFD_RELOC_ARM_JUMP_SLOT, ++ BFD_RELOC_ARM_GLOB_DAT, ++ BFD_RELOC_ARM_GOT32, ++ BFD_RELOC_ARM_PLT32, ++ BFD_RELOC_ARM_RELATIVE, ++ BFD_RELOC_ARM_GOTOFF, ++ BFD_RELOC_ARM_GOTPC, ++ ++/* ARM thread-local storage relocations. */ ++ BFD_RELOC_ARM_TLS_GD32, ++ BFD_RELOC_ARM_TLS_LDO32, ++ BFD_RELOC_ARM_TLS_LDM32, ++ BFD_RELOC_ARM_TLS_DTPOFF32, ++ BFD_RELOC_ARM_TLS_DTPMOD32, ++ BFD_RELOC_ARM_TLS_TPOFF32, ++ BFD_RELOC_ARM_TLS_IE32, ++ BFD_RELOC_ARM_TLS_LE32, ++ ++/* These relocs are only used within the ARM assembler. They are not ++(at present) written to any object files. */ ++ BFD_RELOC_ARM_IMMEDIATE, ++ BFD_RELOC_ARM_ADRL_IMMEDIATE, ++ BFD_RELOC_ARM_T32_IMMEDIATE, ++ BFD_RELOC_ARM_SHIFT_IMM, ++ BFD_RELOC_ARM_SMI, ++ BFD_RELOC_ARM_SWI, ++ BFD_RELOC_ARM_MULTI, ++ BFD_RELOC_ARM_CP_OFF_IMM, ++ BFD_RELOC_ARM_CP_OFF_IMM_S2, ++ BFD_RELOC_ARM_ADR_IMM, ++ BFD_RELOC_ARM_LDR_IMM, ++ BFD_RELOC_ARM_LITERAL, ++ BFD_RELOC_ARM_IN_POOL, ++ BFD_RELOC_ARM_OFFSET_IMM8, ++ BFD_RELOC_ARM_T32_OFFSET_U8, ++ BFD_RELOC_ARM_T32_OFFSET_IMM, ++ BFD_RELOC_ARM_HWLITERAL, ++ BFD_RELOC_ARM_THUMB_ADD, ++ BFD_RELOC_ARM_THUMB_IMM, ++ BFD_RELOC_ARM_THUMB_SHIFT, ++ ++/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ ++ BFD_RELOC_SH_PCDISP8BY2, ++ BFD_RELOC_SH_PCDISP12BY2, ++ BFD_RELOC_SH_IMM3, ++ BFD_RELOC_SH_IMM3U, ++ BFD_RELOC_SH_DISP12, ++ BFD_RELOC_SH_DISP12BY2, ++ BFD_RELOC_SH_DISP12BY4, ++ BFD_RELOC_SH_DISP12BY8, ++ BFD_RELOC_SH_DISP20, ++ BFD_RELOC_SH_DISP20BY8, ++ BFD_RELOC_SH_IMM4, ++ BFD_RELOC_SH_IMM4BY2, ++ BFD_RELOC_SH_IMM4BY4, ++ BFD_RELOC_SH_IMM8, ++ BFD_RELOC_SH_IMM8BY2, ++ BFD_RELOC_SH_IMM8BY4, ++ BFD_RELOC_SH_PCRELIMM8BY2, ++ BFD_RELOC_SH_PCRELIMM8BY4, ++ BFD_RELOC_SH_SWITCH16, ++ BFD_RELOC_SH_SWITCH32, ++ BFD_RELOC_SH_USES, ++ BFD_RELOC_SH_COUNT, ++ BFD_RELOC_SH_ALIGN, ++ BFD_RELOC_SH_CODE, ++ BFD_RELOC_SH_DATA, ++ BFD_RELOC_SH_LABEL, ++ BFD_RELOC_SH_LOOP_START, ++ BFD_RELOC_SH_LOOP_END, ++ BFD_RELOC_SH_COPY, ++ BFD_RELOC_SH_GLOB_DAT, ++ BFD_RELOC_SH_JMP_SLOT, ++ BFD_RELOC_SH_RELATIVE, ++ BFD_RELOC_SH_GOTPC, ++ BFD_RELOC_SH_GOT_LOW16, ++ BFD_RELOC_SH_GOT_MEDLOW16, ++ BFD_RELOC_SH_GOT_MEDHI16, ++ BFD_RELOC_SH_GOT_HI16, ++ BFD_RELOC_SH_GOTPLT_LOW16, ++ BFD_RELOC_SH_GOTPLT_MEDLOW16, ++ BFD_RELOC_SH_GOTPLT_MEDHI16, ++ BFD_RELOC_SH_GOTPLT_HI16, ++ BFD_RELOC_SH_PLT_LOW16, ++ BFD_RELOC_SH_PLT_MEDLOW16, ++ BFD_RELOC_SH_PLT_MEDHI16, ++ BFD_RELOC_SH_PLT_HI16, ++ BFD_RELOC_SH_GOTOFF_LOW16, ++ BFD_RELOC_SH_GOTOFF_MEDLOW16, ++ BFD_RELOC_SH_GOTOFF_MEDHI16, ++ BFD_RELOC_SH_GOTOFF_HI16, ++ BFD_RELOC_SH_GOTPC_LOW16, ++ BFD_RELOC_SH_GOTPC_MEDLOW16, ++ BFD_RELOC_SH_GOTPC_MEDHI16, ++ BFD_RELOC_SH_GOTPC_HI16, ++ BFD_RELOC_SH_COPY64, ++ BFD_RELOC_SH_GLOB_DAT64, ++ BFD_RELOC_SH_JMP_SLOT64, ++ BFD_RELOC_SH_RELATIVE64, ++ BFD_RELOC_SH_GOT10BY4, ++ BFD_RELOC_SH_GOT10BY8, ++ BFD_RELOC_SH_GOTPLT10BY4, ++ BFD_RELOC_SH_GOTPLT10BY8, ++ BFD_RELOC_SH_GOTPLT32, ++ BFD_RELOC_SH_SHMEDIA_CODE, ++ BFD_RELOC_SH_IMMU5, ++ BFD_RELOC_SH_IMMS6, ++ BFD_RELOC_SH_IMMS6BY32, ++ BFD_RELOC_SH_IMMU6, ++ BFD_RELOC_SH_IMMS10, ++ BFD_RELOC_SH_IMMS10BY2, ++ BFD_RELOC_SH_IMMS10BY4, ++ BFD_RELOC_SH_IMMS10BY8, ++ BFD_RELOC_SH_IMMS16, ++ BFD_RELOC_SH_IMMU16, ++ BFD_RELOC_SH_IMM_LOW16, ++ BFD_RELOC_SH_IMM_LOW16_PCREL, ++ BFD_RELOC_SH_IMM_MEDLOW16, ++ BFD_RELOC_SH_IMM_MEDLOW16_PCREL, ++ BFD_RELOC_SH_IMM_MEDHI16, ++ BFD_RELOC_SH_IMM_MEDHI16_PCREL, ++ BFD_RELOC_SH_IMM_HI16, ++ BFD_RELOC_SH_IMM_HI16_PCREL, ++ BFD_RELOC_SH_PT_16, ++ BFD_RELOC_SH_TLS_GD_32, ++ BFD_RELOC_SH_TLS_LD_32, ++ BFD_RELOC_SH_TLS_LDO_32, ++ BFD_RELOC_SH_TLS_IE_32, ++ BFD_RELOC_SH_TLS_LE_32, ++ BFD_RELOC_SH_TLS_DTPMOD32, ++ BFD_RELOC_SH_TLS_DTPOFF32, ++ BFD_RELOC_SH_TLS_TPOFF32, ++ ++/* ARC Cores relocs. ++ARC 22 bit pc-relative branch. The lowest two bits must be zero and are ++not stored in the instruction. The high 20 bits are installed in bits 26 ++through 7 of the instruction. */ ++ BFD_RELOC_ARC_B22_PCREL, ++ ++/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not ++stored in the instruction. The high 24 bits are installed in bits 23 ++through 0. */ ++ BFD_RELOC_ARC_B26, ++ ++/* Mitsubishi D10V relocs. ++This is a 10-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_10_PCREL_R, ++ ++/* Mitsubishi D10V relocs. ++This is a 10-bit reloc with the right 2 bits ++assumed to be 0. This is the same as the previous reloc ++except it is in the left container, i.e., ++shifted left 15 bits. */ ++ BFD_RELOC_D10V_10_PCREL_L, ++ ++/* This is an 18-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_18, ++ ++/* This is an 18-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_18_PCREL, ++ ++/* Mitsubishi D30V relocs. ++This is a 6-bit absolute reloc. */ ++ BFD_RELOC_D30V_6, ++ ++/* This is a 6-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_9_PCREL, ++ ++/* This is a 6-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_9_PCREL_R, ++ ++/* This is a 12-bit absolute reloc with the ++right 3 bitsassumed to be 0. */ ++ BFD_RELOC_D30V_15, ++ ++/* This is a 12-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_15_PCREL, ++ ++/* This is a 12-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_15_PCREL_R, ++ ++/* This is an 18-bit absolute reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_21, ++ ++/* This is an 18-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_21_PCREL, ++ ++/* This is an 18-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_21_PCREL_R, ++ ++/* This is a 32-bit absolute reloc. */ ++ BFD_RELOC_D30V_32, ++ ++/* This is a 32-bit pc-relative reloc. */ ++ BFD_RELOC_D30V_32_PCREL, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_HI16_S, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_LO16, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_JMP26, ++ ++/* Renesas M16C/M32C Relocations. */ ++ BFD_RELOC_M16C_8_PCREL8, ++ BFD_RELOC_M16C_16_PCREL8, ++ BFD_RELOC_M16C_8_PCREL16, ++ BFD_RELOC_M16C_8_ELABEL24, ++ BFD_RELOC_M16C_8_ABS16, ++ BFD_RELOC_M16C_16_ABS16, ++ BFD_RELOC_M16C_16_ABS24, ++ BFD_RELOC_M16C_16_ABS32, ++ BFD_RELOC_M16C_24_ABS16, ++ BFD_RELOC_M16C_24_ABS24, ++ BFD_RELOC_M16C_24_ABS32, ++ BFD_RELOC_M16C_32_ABS16, ++ BFD_RELOC_M16C_32_ABS24, ++ BFD_RELOC_M16C_32_ABS32, ++ BFD_RELOC_M16C_40_ABS16, ++ BFD_RELOC_M16C_40_ABS24, ++ BFD_RELOC_M16C_40_ABS32, ++ ++/* Renesas M32R (formerly Mitsubishi M32R) relocs. ++This is a 24 bit absolute address. */ ++ BFD_RELOC_M32R_24, ++ ++/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_10_PCREL, ++ ++/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_18_PCREL, ++ ++/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_26_PCREL, ++ ++/* This is a 16-bit reloc containing the high 16 bits of an address ++used when the lower 16 bits are treated as unsigned. */ ++ BFD_RELOC_M32R_HI16_ULO, ++ ++/* This is a 16-bit reloc containing the high 16 bits of an address ++used when the lower 16 bits are treated as signed. */ ++ BFD_RELOC_M32R_HI16_SLO, ++ ++/* This is a 16-bit reloc containing the lower 16 bits of an address. */ ++ BFD_RELOC_M32R_LO16, ++ ++/* This is a 16-bit reloc containing the small data area offset for use in ++add3, load, and store instructions. */ ++ BFD_RELOC_M32R_SDA16, ++ ++/* For PIC. */ ++ BFD_RELOC_M32R_GOT24, ++ BFD_RELOC_M32R_26_PLTREL, ++ BFD_RELOC_M32R_COPY, ++ BFD_RELOC_M32R_GLOB_DAT, ++ BFD_RELOC_M32R_JMP_SLOT, ++ BFD_RELOC_M32R_RELATIVE, ++ BFD_RELOC_M32R_GOTOFF, ++ BFD_RELOC_M32R_GOTOFF_HI_ULO, ++ BFD_RELOC_M32R_GOTOFF_HI_SLO, ++ BFD_RELOC_M32R_GOTOFF_LO, ++ BFD_RELOC_M32R_GOTPC24, ++ BFD_RELOC_M32R_GOT16_HI_ULO, ++ BFD_RELOC_M32R_GOT16_HI_SLO, ++ BFD_RELOC_M32R_GOT16_LO, ++ BFD_RELOC_M32R_GOTPC_HI_ULO, ++ BFD_RELOC_M32R_GOTPC_HI_SLO, ++ BFD_RELOC_M32R_GOTPC_LO, ++ ++/* This is a 9-bit reloc */ ++ BFD_RELOC_V850_9_PCREL, ++ ++/* This is a 22-bit reloc */ ++ BFD_RELOC_V850_22_PCREL, ++ ++/* This is a 16 bit offset from the short data area pointer. */ ++ BFD_RELOC_V850_SDA_16_16_OFFSET, ++ ++/* This is a 16 bit offset (of which only 15 bits are used) from the ++short data area pointer. */ ++ BFD_RELOC_V850_SDA_15_16_OFFSET, ++ ++/* This is a 16 bit offset from the zero data area pointer. */ ++ BFD_RELOC_V850_ZDA_16_16_OFFSET, ++ ++/* This is a 16 bit offset (of which only 15 bits are used) from the ++zero data area pointer. */ ++ BFD_RELOC_V850_ZDA_15_16_OFFSET, ++ ++/* This is an 8 bit offset (of which only 6 bits are used) from the ++tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_6_8_OFFSET, ++ ++/* This is an 8bit offset (of which only 7 bits are used) from the tiny ++data area pointer. */ ++ BFD_RELOC_V850_TDA_7_8_OFFSET, ++ ++/* This is a 7 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_7_7_OFFSET, ++ ++/* This is a 16 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_16_16_OFFSET, ++ ++/* This is a 5 bit offset (of which only 4 bits are used) from the tiny ++data area pointer. */ ++ BFD_RELOC_V850_TDA_4_5_OFFSET, ++ ++/* This is a 4 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_4_4_OFFSET, ++ ++/* This is a 16 bit offset from the short data area pointer, with the ++bits placed non-contiguously in the instruction. */ ++ BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, ++ ++/* This is a 16 bit offset from the zero data area pointer, with the ++bits placed non-contiguously in the instruction. */ ++ BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, ++ ++/* This is a 6 bit offset from the call table base pointer. */ ++ BFD_RELOC_V850_CALLT_6_7_OFFSET, ++ ++/* This is a 16 bit offset from the call table base pointer. */ ++ BFD_RELOC_V850_CALLT_16_16_OFFSET, ++ ++/* Used for relaxing indirect function calls. */ ++ BFD_RELOC_V850_LONGCALL, ++ ++/* Used for relaxing indirect jumps. */ ++ BFD_RELOC_V850_LONGJUMP, ++ ++/* Used to maintain alignment whilst relaxing. */ ++ BFD_RELOC_V850_ALIGN, ++ ++/* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu ++instructions. */ ++ BFD_RELOC_V850_LO16_SPLIT_OFFSET, ++ ++/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the ++instruction. */ ++ BFD_RELOC_MN10300_32_PCREL, ++ ++/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the ++instruction. */ ++ BFD_RELOC_MN10300_16_PCREL, ++ ++/* This is a 8bit DP reloc for the tms320c30, where the most ++significant 8 bits of a 24 bit word are placed into the least ++significant 8 bits of the opcode. */ ++ BFD_RELOC_TIC30_LDP, ++ ++/* This is a 7bit reloc for the tms320c54x, where the least ++significant 7 bits of a 16 bit word are placed into the least ++significant 7 bits of the opcode. */ ++ BFD_RELOC_TIC54X_PARTLS7, ++ ++/* This is a 9bit DP reloc for the tms320c54x, where the most ++significant 9 bits of a 16 bit word are placed into the least ++significant 9 bits of the opcode. */ ++ BFD_RELOC_TIC54X_PARTMS9, ++ ++/* This is an extended address 23-bit reloc for the tms320c54x. */ ++ BFD_RELOC_TIC54X_23, ++ ++/* This is a 16-bit reloc for the tms320c54x, where the least ++significant 16 bits of a 23-bit extended address are placed into ++the opcode. */ ++ BFD_RELOC_TIC54X_16_OF_23, ++ ++/* This is a reloc for the tms320c54x, where the most ++significant 7 bits of a 23-bit extended address are placed into ++the opcode. */ ++ BFD_RELOC_TIC54X_MS7_OF_23, ++ ++/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ ++ BFD_RELOC_FR30_48, ++ ++/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into ++two sections. */ ++ BFD_RELOC_FR30_20, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in ++4 bits. */ ++ BFD_RELOC_FR30_6_IN_4, ++ ++/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset ++into 8 bits. */ ++ BFD_RELOC_FR30_8_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset ++into 8 bits. */ ++ BFD_RELOC_FR30_9_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset ++into 8 bits. */ ++ BFD_RELOC_FR30_10_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative ++short offset into 8 bits. */ ++ BFD_RELOC_FR30_9_PCREL, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative ++short offset into 11 bits. */ ++ BFD_RELOC_FR30_12_PCREL, ++ ++/* Motorola Mcore relocations. */ ++ BFD_RELOC_MCORE_PCREL_IMM8BY4, ++ BFD_RELOC_MCORE_PCREL_IMM11BY2, ++ BFD_RELOC_MCORE_PCREL_IMM4BY2, ++ BFD_RELOC_MCORE_PCREL_32, ++ BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, ++ BFD_RELOC_MCORE_RVA, ++ ++/* These are relocations for the GETA instruction. */ ++ BFD_RELOC_MMIX_GETA, ++ BFD_RELOC_MMIX_GETA_1, ++ BFD_RELOC_MMIX_GETA_2, ++ BFD_RELOC_MMIX_GETA_3, ++ ++/* These are relocations for a conditional branch instruction. */ ++ BFD_RELOC_MMIX_CBRANCH, ++ BFD_RELOC_MMIX_CBRANCH_J, ++ BFD_RELOC_MMIX_CBRANCH_1, ++ BFD_RELOC_MMIX_CBRANCH_2, ++ BFD_RELOC_MMIX_CBRANCH_3, ++ ++/* These are relocations for the PUSHJ instruction. */ ++ BFD_RELOC_MMIX_PUSHJ, ++ BFD_RELOC_MMIX_PUSHJ_1, ++ BFD_RELOC_MMIX_PUSHJ_2, ++ BFD_RELOC_MMIX_PUSHJ_3, ++ BFD_RELOC_MMIX_PUSHJ_STUBBABLE, ++ ++/* These are relocations for the JMP instruction. */ ++ BFD_RELOC_MMIX_JMP, ++ BFD_RELOC_MMIX_JMP_1, ++ BFD_RELOC_MMIX_JMP_2, ++ BFD_RELOC_MMIX_JMP_3, ++ ++/* This is a relocation for a relative address as in a GETA instruction or ++a branch. */ ++ BFD_RELOC_MMIX_ADDR19, ++ ++/* This is a relocation for a relative address as in a JMP instruction. */ ++ BFD_RELOC_MMIX_ADDR27, ++ ++/* This is a relocation for an instruction field that may be a general ++register or a value 0..255. */ ++ BFD_RELOC_MMIX_REG_OR_BYTE, ++ ++/* This is a relocation for an instruction field that may be a general ++register. */ ++ BFD_RELOC_MMIX_REG, ++ ++/* This is a relocation for two instruction fields holding a register and ++an offset, the equivalent of the relocation. */ ++ BFD_RELOC_MMIX_BASE_PLUS_OFFSET, ++ ++/* This relocation is an assertion that the expression is not allocated as ++a global register. It does not modify contents. */ ++ BFD_RELOC_MMIX_LOCAL, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative ++short offset into 7 bits. */ ++ BFD_RELOC_AVR_7_PCREL, ++ ++/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative ++short offset into 12 bits. */ ++ BFD_RELOC_AVR_13_PCREL, ++ ++/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually ++program memory address) into 16 bits. */ ++ BFD_RELOC_AVR_16_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually ++data memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_LO8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit ++of data memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HI8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit ++of program memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HH8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(usually data memory address) into 8 bit immediate value of SUBI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 8 bit of data memory address) into 8 bit immediate value of ++SUBI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(most high 8 bit of program memory address) into 8 bit immediate value ++of LDI or SUBI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually ++command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit ++of command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit ++of command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(usually command address) into 8 bit immediate value of SUBI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_PM_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 8 bit of 16 bit command address) into 8 bit immediate value ++of SUBI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_PM_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 6 bit of 22 bit command address) into 8 bit immediate ++value of SUBI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_PM_NEG, ++ ++/* This is a 32 bit reloc for the AVR that stores 23 bit value ++into 22 bits. */ ++ BFD_RELOC_AVR_CALL, ++ ++/* This is a 16 bit reloc for the AVR that stores all needed bits ++for absolute addressing with ldi with overflow check to linktime */ ++ BFD_RELOC_AVR_LDI, ++ ++/* This is a 6 bit reloc for the AVR that stores offset for ldd/std ++instructions */ ++ BFD_RELOC_AVR_6, ++ ++/* This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw ++instructions */ ++ BFD_RELOC_AVR_6_ADIW, ++ ++/* Direct 12 bit. */ ++ BFD_RELOC_390_12, ++ ++/* 12 bit GOT offset. */ ++ BFD_RELOC_390_GOT12, ++ ++/* 32 bit PC relative PLT address. */ ++ BFD_RELOC_390_PLT32, ++ ++/* Copy symbol at runtime. */ ++ BFD_RELOC_390_COPY, ++ ++/* Create GOT entry. */ ++ BFD_RELOC_390_GLOB_DAT, ++ ++/* Create PLT entry. */ ++ BFD_RELOC_390_JMP_SLOT, ++ ++/* Adjust by program base. */ ++ BFD_RELOC_390_RELATIVE, ++ ++/* 32 bit PC relative offset to GOT. */ ++ BFD_RELOC_390_GOTPC, ++ ++/* 16 bit GOT offset. */ ++ BFD_RELOC_390_GOT16, ++ ++/* PC relative 16 bit shifted by 1. */ ++ BFD_RELOC_390_PC16DBL, ++ ++/* 16 bit PC rel. PLT shifted by 1. */ ++ BFD_RELOC_390_PLT16DBL, ++ ++/* PC relative 32 bit shifted by 1. */ ++ BFD_RELOC_390_PC32DBL, ++ ++/* 32 bit PC rel. PLT shifted by 1. */ ++ BFD_RELOC_390_PLT32DBL, ++ ++/* 32 bit PC rel. GOT shifted by 1. */ ++ BFD_RELOC_390_GOTPCDBL, ++ ++/* 64 bit GOT offset. */ ++ BFD_RELOC_390_GOT64, ++ ++/* 64 bit PC relative PLT address. */ ++ BFD_RELOC_390_PLT64, ++ ++/* 32 bit rel. offset to GOT entry. */ ++ BFD_RELOC_390_GOTENT, ++ ++/* 64 bit offset to GOT. */ ++ BFD_RELOC_390_GOTOFF64, ++ ++/* 12-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT12, ++ ++/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT16, ++ ++/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT32, ++ ++/* 64-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT64, ++ ++/* 32-bit rel. offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLTENT, ++ ++/* 16-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF16, ++ ++/* 32-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF32, ++ ++/* 64-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF64, ++ ++/* s390 tls relocations. */ ++ BFD_RELOC_390_TLS_LOAD, ++ BFD_RELOC_390_TLS_GDCALL, ++ BFD_RELOC_390_TLS_LDCALL, ++ BFD_RELOC_390_TLS_GD32, ++ BFD_RELOC_390_TLS_GD64, ++ BFD_RELOC_390_TLS_GOTIE12, ++ BFD_RELOC_390_TLS_GOTIE32, ++ BFD_RELOC_390_TLS_GOTIE64, ++ BFD_RELOC_390_TLS_LDM32, ++ BFD_RELOC_390_TLS_LDM64, ++ BFD_RELOC_390_TLS_IE32, ++ BFD_RELOC_390_TLS_IE64, ++ BFD_RELOC_390_TLS_IEENT, ++ BFD_RELOC_390_TLS_LE32, ++ BFD_RELOC_390_TLS_LE64, ++ BFD_RELOC_390_TLS_LDO32, ++ BFD_RELOC_390_TLS_LDO64, ++ BFD_RELOC_390_TLS_DTPMOD, ++ BFD_RELOC_390_TLS_DTPOFF, ++ BFD_RELOC_390_TLS_TPOFF, ++ ++/* Long displacement extension. */ ++ BFD_RELOC_390_20, ++ BFD_RELOC_390_GOT20, ++ BFD_RELOC_390_GOTPLT20, ++ BFD_RELOC_390_TLS_GOTIE20, ++ ++/* Scenix IP2K - 9-bit register number / data address */ ++ BFD_RELOC_IP2K_FR9, ++ ++/* Scenix IP2K - 4-bit register/data bank number */ ++ BFD_RELOC_IP2K_BANK, ++ ++/* Scenix IP2K - low 13 bits of instruction word address */ ++ BFD_RELOC_IP2K_ADDR16CJP, ++ ++/* Scenix IP2K - high 3 bits of instruction word address */ ++ BFD_RELOC_IP2K_PAGE3, ++ ++/* Scenix IP2K - ext/low/high 8 bits of data address */ ++ BFD_RELOC_IP2K_LO8DATA, ++ BFD_RELOC_IP2K_HI8DATA, ++ BFD_RELOC_IP2K_EX8DATA, ++ ++/* Scenix IP2K - low/high 8 bits of instruction word address */ ++ BFD_RELOC_IP2K_LO8INSN, ++ BFD_RELOC_IP2K_HI8INSN, ++ ++/* Scenix IP2K - even/odd PC modifier to modify snb pcl.0 */ ++ BFD_RELOC_IP2K_PC_SKIP, ++ ++/* Scenix IP2K - 16 bit word address in text section. */ ++ BFD_RELOC_IP2K_TEXT, ++ ++/* Scenix IP2K - 7-bit sp or dp offset */ ++ BFD_RELOC_IP2K_FR_OFFSET, ++ ++/* Scenix VPE4K coprocessor - data/insn-space addressing */ ++ BFD_RELOC_VPE4KMATH_DATA, ++ BFD_RELOC_VPE4KMATH_INSN, ++ ++/* These two relocations are used by the linker to determine which of ++the entries in a C++ virtual function table are actually used. When ++the --gc-sections option is given, the linker will zero out the entries ++that are not used, so that the code for those functions need not be ++included in the output. ++ ++VTABLE_INHERIT is a zero-space relocation used to describe to the ++linker the inheritance tree of a C++ virtual function table. The ++relocation's symbol should be the parent class' vtable, and the ++relocation should be located at the child vtable. ++ ++VTABLE_ENTRY is a zero-space relocation that describes the use of a ++virtual function table entry. The reloc's symbol should refer to the ++table of the class mentioned in the code. Off of that base, an offset ++describes the entry that is being used. For Rela hosts, this offset ++is stored in the reloc's addend. For Rel hosts, we are forced to put ++this offset in the reloc's section offset. */ ++ BFD_RELOC_VTABLE_INHERIT, ++ BFD_RELOC_VTABLE_ENTRY, ++ ++/* Intel IA64 Relocations. */ ++ BFD_RELOC_IA64_IMM14, ++ BFD_RELOC_IA64_IMM22, ++ BFD_RELOC_IA64_IMM64, ++ BFD_RELOC_IA64_DIR32MSB, ++ BFD_RELOC_IA64_DIR32LSB, ++ BFD_RELOC_IA64_DIR64MSB, ++ BFD_RELOC_IA64_DIR64LSB, ++ BFD_RELOC_IA64_GPREL22, ++ BFD_RELOC_IA64_GPREL64I, ++ BFD_RELOC_IA64_GPREL32MSB, ++ BFD_RELOC_IA64_GPREL32LSB, ++ BFD_RELOC_IA64_GPREL64MSB, ++ BFD_RELOC_IA64_GPREL64LSB, ++ BFD_RELOC_IA64_LTOFF22, ++ BFD_RELOC_IA64_LTOFF64I, ++ BFD_RELOC_IA64_PLTOFF22, ++ BFD_RELOC_IA64_PLTOFF64I, ++ BFD_RELOC_IA64_PLTOFF64MSB, ++ BFD_RELOC_IA64_PLTOFF64LSB, ++ BFD_RELOC_IA64_FPTR64I, ++ BFD_RELOC_IA64_FPTR32MSB, ++ BFD_RELOC_IA64_FPTR32LSB, ++ BFD_RELOC_IA64_FPTR64MSB, ++ BFD_RELOC_IA64_FPTR64LSB, ++ BFD_RELOC_IA64_PCREL21B, ++ BFD_RELOC_IA64_PCREL21BI, ++ BFD_RELOC_IA64_PCREL21M, ++ BFD_RELOC_IA64_PCREL21F, ++ BFD_RELOC_IA64_PCREL22, ++ BFD_RELOC_IA64_PCREL60B, ++ BFD_RELOC_IA64_PCREL64I, ++ BFD_RELOC_IA64_PCREL32MSB, ++ BFD_RELOC_IA64_PCREL32LSB, ++ BFD_RELOC_IA64_PCREL64MSB, ++ BFD_RELOC_IA64_PCREL64LSB, ++ BFD_RELOC_IA64_LTOFF_FPTR22, ++ BFD_RELOC_IA64_LTOFF_FPTR64I, ++ BFD_RELOC_IA64_LTOFF_FPTR32MSB, ++ BFD_RELOC_IA64_LTOFF_FPTR32LSB, ++ BFD_RELOC_IA64_LTOFF_FPTR64MSB, ++ BFD_RELOC_IA64_LTOFF_FPTR64LSB, ++ BFD_RELOC_IA64_SEGREL32MSB, ++ BFD_RELOC_IA64_SEGREL32LSB, ++ BFD_RELOC_IA64_SEGREL64MSB, ++ BFD_RELOC_IA64_SEGREL64LSB, ++ BFD_RELOC_IA64_SECREL32MSB, ++ BFD_RELOC_IA64_SECREL32LSB, ++ BFD_RELOC_IA64_SECREL64MSB, ++ BFD_RELOC_IA64_SECREL64LSB, ++ BFD_RELOC_IA64_REL32MSB, ++ BFD_RELOC_IA64_REL32LSB, ++ BFD_RELOC_IA64_REL64MSB, ++ BFD_RELOC_IA64_REL64LSB, ++ BFD_RELOC_IA64_LTV32MSB, ++ BFD_RELOC_IA64_LTV32LSB, ++ BFD_RELOC_IA64_LTV64MSB, ++ BFD_RELOC_IA64_LTV64LSB, ++ BFD_RELOC_IA64_IPLTMSB, ++ BFD_RELOC_IA64_IPLTLSB, ++ BFD_RELOC_IA64_COPY, ++ BFD_RELOC_IA64_LTOFF22X, ++ BFD_RELOC_IA64_LDXMOV, ++ BFD_RELOC_IA64_TPREL14, ++ BFD_RELOC_IA64_TPREL22, ++ BFD_RELOC_IA64_TPREL64I, ++ BFD_RELOC_IA64_TPREL64MSB, ++ BFD_RELOC_IA64_TPREL64LSB, ++ BFD_RELOC_IA64_LTOFF_TPREL22, ++ BFD_RELOC_IA64_DTPMOD64MSB, ++ BFD_RELOC_IA64_DTPMOD64LSB, ++ BFD_RELOC_IA64_LTOFF_DTPMOD22, ++ BFD_RELOC_IA64_DTPREL14, ++ BFD_RELOC_IA64_DTPREL22, ++ BFD_RELOC_IA64_DTPREL64I, ++ BFD_RELOC_IA64_DTPREL32MSB, ++ BFD_RELOC_IA64_DTPREL32LSB, ++ BFD_RELOC_IA64_DTPREL64MSB, ++ BFD_RELOC_IA64_DTPREL64LSB, ++ BFD_RELOC_IA64_LTOFF_DTPREL22, ++ ++/* Motorola 68HC11 reloc. ++This is the 8 bit high part of an absolute address. */ ++ BFD_RELOC_M68HC11_HI8, ++ ++/* Motorola 68HC11 reloc. ++This is the 8 bit low part of an absolute address. */ ++ BFD_RELOC_M68HC11_LO8, ++ ++/* Motorola 68HC11 reloc. ++This is the 3 bit of a value. */ ++ BFD_RELOC_M68HC11_3B, ++ ++/* Motorola 68HC11 reloc. ++This reloc marks the beginning of a jump/call instruction. ++It is used for linker relaxation to correctly identify beginning ++of instruction and change some branches to use PC-relative ++addressing mode. */ ++ BFD_RELOC_M68HC11_RL_JUMP, ++ ++/* Motorola 68HC11 reloc. ++This reloc marks a group of several instructions that gcc generates ++and for which the linker relaxation pass can modify and/or remove ++some of them. */ ++ BFD_RELOC_M68HC11_RL_GROUP, ++ ++/* Motorola 68HC11 reloc. ++This is the 16-bit lower part of an address. It is used for 'call' ++instruction to specify the symbol address without any special ++transformation (due to memory bank window). */ ++ BFD_RELOC_M68HC11_LO16, ++ ++/* Motorola 68HC11 reloc. ++This is a 8-bit reloc that specifies the page number of an address. ++It is used by 'call' instruction to specify the page number of ++the symbol. */ ++ BFD_RELOC_M68HC11_PAGE, ++ ++/* Motorola 68HC11 reloc. ++This is a 24-bit reloc that represents the address with a 16-bit ++value and a 8-bit page number. The symbol address is transformed ++to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ ++ BFD_RELOC_M68HC11_24, ++ ++/* Motorola 68HC12 reloc. ++This is the 5 bits of a value. */ ++ BFD_RELOC_M68HC12_5B, ++ ++/* NS CR16C Relocations. */ ++ BFD_RELOC_16C_NUM08, ++ BFD_RELOC_16C_NUM08_C, ++ BFD_RELOC_16C_NUM16, ++ BFD_RELOC_16C_NUM16_C, ++ BFD_RELOC_16C_NUM32, ++ BFD_RELOC_16C_NUM32_C, ++ BFD_RELOC_16C_DISP04, ++ BFD_RELOC_16C_DISP04_C, ++ BFD_RELOC_16C_DISP08, ++ BFD_RELOC_16C_DISP08_C, ++ BFD_RELOC_16C_DISP16, ++ BFD_RELOC_16C_DISP16_C, ++ BFD_RELOC_16C_DISP24, ++ BFD_RELOC_16C_DISP24_C, ++ BFD_RELOC_16C_DISP24a, ++ BFD_RELOC_16C_DISP24a_C, ++ BFD_RELOC_16C_REG04, ++ BFD_RELOC_16C_REG04_C, ++ BFD_RELOC_16C_REG04a, ++ BFD_RELOC_16C_REG04a_C, ++ BFD_RELOC_16C_REG14, ++ BFD_RELOC_16C_REG14_C, ++ BFD_RELOC_16C_REG16, ++ BFD_RELOC_16C_REG16_C, ++ BFD_RELOC_16C_REG20, ++ BFD_RELOC_16C_REG20_C, ++ BFD_RELOC_16C_ABS20, ++ BFD_RELOC_16C_ABS20_C, ++ BFD_RELOC_16C_ABS24, ++ BFD_RELOC_16C_ABS24_C, ++ BFD_RELOC_16C_IMM04, ++ BFD_RELOC_16C_IMM04_C, ++ BFD_RELOC_16C_IMM16, ++ BFD_RELOC_16C_IMM16_C, ++ BFD_RELOC_16C_IMM20, ++ BFD_RELOC_16C_IMM20_C, ++ BFD_RELOC_16C_IMM24, ++ BFD_RELOC_16C_IMM24_C, ++ BFD_RELOC_16C_IMM32, ++ BFD_RELOC_16C_IMM32_C, ++ ++/* NS CRX Relocations. */ ++ BFD_RELOC_CRX_REL4, ++ BFD_RELOC_CRX_REL8, ++ BFD_RELOC_CRX_REL8_CMP, ++ BFD_RELOC_CRX_REL16, ++ BFD_RELOC_CRX_REL24, ++ BFD_RELOC_CRX_REL32, ++ BFD_RELOC_CRX_REGREL12, ++ BFD_RELOC_CRX_REGREL22, ++ BFD_RELOC_CRX_REGREL28, ++ BFD_RELOC_CRX_REGREL32, ++ BFD_RELOC_CRX_ABS16, ++ BFD_RELOC_CRX_ABS32, ++ BFD_RELOC_CRX_NUM8, ++ BFD_RELOC_CRX_NUM16, ++ BFD_RELOC_CRX_NUM32, ++ BFD_RELOC_CRX_IMM16, ++ BFD_RELOC_CRX_IMM32, ++ BFD_RELOC_CRX_SWITCH8, ++ BFD_RELOC_CRX_SWITCH16, ++ BFD_RELOC_CRX_SWITCH32, ++ ++/* These relocs are only used within the CRIS assembler. They are not ++(at present) written to any object files. */ ++ BFD_RELOC_CRIS_BDISP8, ++ BFD_RELOC_CRIS_UNSIGNED_5, ++ BFD_RELOC_CRIS_SIGNED_6, ++ BFD_RELOC_CRIS_UNSIGNED_6, ++ BFD_RELOC_CRIS_SIGNED_8, ++ BFD_RELOC_CRIS_UNSIGNED_8, ++ BFD_RELOC_CRIS_SIGNED_16, ++ BFD_RELOC_CRIS_UNSIGNED_16, ++ BFD_RELOC_CRIS_LAPCQ_OFFSET, ++ BFD_RELOC_CRIS_UNSIGNED_4, ++ ++/* Relocs used in ELF shared libraries for CRIS. */ ++ BFD_RELOC_CRIS_COPY, ++ BFD_RELOC_CRIS_GLOB_DAT, ++ BFD_RELOC_CRIS_JUMP_SLOT, ++ BFD_RELOC_CRIS_RELATIVE, ++ ++/* 32-bit offset to symbol-entry within GOT. */ ++ BFD_RELOC_CRIS_32_GOT, ++ ++/* 16-bit offset to symbol-entry within GOT. */ ++ BFD_RELOC_CRIS_16_GOT, ++ ++/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_CRIS_32_GOTPLT, ++ ++/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_CRIS_16_GOTPLT, ++ ++/* 32-bit offset to symbol, relative to GOT. */ ++ BFD_RELOC_CRIS_32_GOTREL, ++ ++/* 32-bit offset to symbol with PLT entry, relative to GOT. */ ++ BFD_RELOC_CRIS_32_PLT_GOTREL, ++ ++/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ ++ BFD_RELOC_CRIS_32_PLT_PCREL, ++ ++/* Intel i860 Relocations. */ ++ BFD_RELOC_860_COPY, ++ BFD_RELOC_860_GLOB_DAT, ++ BFD_RELOC_860_JUMP_SLOT, ++ BFD_RELOC_860_RELATIVE, ++ BFD_RELOC_860_PC26, ++ BFD_RELOC_860_PLT26, ++ BFD_RELOC_860_PC16, ++ BFD_RELOC_860_LOW0, ++ BFD_RELOC_860_SPLIT0, ++ BFD_RELOC_860_LOW1, ++ BFD_RELOC_860_SPLIT1, ++ BFD_RELOC_860_LOW2, ++ BFD_RELOC_860_SPLIT2, ++ BFD_RELOC_860_LOW3, ++ BFD_RELOC_860_LOGOT0, ++ BFD_RELOC_860_SPGOT0, ++ BFD_RELOC_860_LOGOT1, ++ BFD_RELOC_860_SPGOT1, ++ BFD_RELOC_860_LOGOTOFF0, ++ BFD_RELOC_860_SPGOTOFF0, ++ BFD_RELOC_860_LOGOTOFF1, ++ BFD_RELOC_860_SPGOTOFF1, ++ BFD_RELOC_860_LOGOTOFF2, ++ BFD_RELOC_860_LOGOTOFF3, ++ BFD_RELOC_860_LOPC, ++ BFD_RELOC_860_HIGHADJ, ++ BFD_RELOC_860_HAGOT, ++ BFD_RELOC_860_HAGOTOFF, ++ BFD_RELOC_860_HAPC, ++ BFD_RELOC_860_HIGH, ++ BFD_RELOC_860_HIGOT, ++ BFD_RELOC_860_HIGOTOFF, ++ ++/* OpenRISC Relocations. */ ++ BFD_RELOC_OPENRISC_ABS_26, ++ BFD_RELOC_OPENRISC_REL_26, ++ ++/* H8 elf Relocations. */ ++ BFD_RELOC_H8_DIR16A8, ++ BFD_RELOC_H8_DIR16R8, ++ BFD_RELOC_H8_DIR24A8, ++ BFD_RELOC_H8_DIR24R8, ++ BFD_RELOC_H8_DIR32A16, ++ ++/* Sony Xstormy16 Relocations. */ ++ BFD_RELOC_XSTORMY16_REL_12, ++ BFD_RELOC_XSTORMY16_12, ++ BFD_RELOC_XSTORMY16_24, ++ BFD_RELOC_XSTORMY16_FPTR16, ++ ++/* Relocations used by VAX ELF. */ ++ BFD_RELOC_VAX_GLOB_DAT, ++ BFD_RELOC_VAX_JMP_SLOT, ++ BFD_RELOC_VAX_RELATIVE, ++ ++/* Morpho MS1 - 16 bit immediate relocation. */ ++ BFD_RELOC_MS1_PC16, ++ ++/* Morpho MS1 - Hi 16 bits of an address. */ ++ BFD_RELOC_MS1_HI16, ++ ++/* Morpho MS1 - Low 16 bits of an address. */ ++ BFD_RELOC_MS1_LO16, ++ ++/* Morpho MS1 - Used to tell the linker which vtable entries are used. */ ++ BFD_RELOC_MS1_GNU_VTINHERIT, ++ ++/* Morpho MS1 - Used to tell the linker which vtable entries are used. */ ++ BFD_RELOC_MS1_GNU_VTENTRY, ++ ++/* msp430 specific relocation codes */ ++ BFD_RELOC_MSP430_10_PCREL, ++ BFD_RELOC_MSP430_16_PCREL, ++ BFD_RELOC_MSP430_16, ++ BFD_RELOC_MSP430_16_PCREL_BYTE, ++ BFD_RELOC_MSP430_16_BYTE, ++ BFD_RELOC_MSP430_2X_PCREL, ++ BFD_RELOC_MSP430_RL_PCREL, ++ ++/* IQ2000 Relocations. */ ++ BFD_RELOC_IQ2000_OFFSET_16, ++ BFD_RELOC_IQ2000_OFFSET_21, ++ BFD_RELOC_IQ2000_UHI16, ++ ++/* Special Xtensa relocation used only by PLT entries in ELF shared ++objects to indicate that the runtime linker should set the value ++to one of its own internal functions or data structures. */ ++ BFD_RELOC_XTENSA_RTLD, ++ ++/* Xtensa relocations for ELF shared objects. */ ++ BFD_RELOC_XTENSA_GLOB_DAT, ++ BFD_RELOC_XTENSA_JMP_SLOT, ++ BFD_RELOC_XTENSA_RELATIVE, ++ ++/* Xtensa relocation used in ELF object files for symbols that may require ++PLT entries. Otherwise, this is just a generic 32-bit relocation. */ ++ BFD_RELOC_XTENSA_PLT, ++ ++/* Xtensa relocations to mark the difference of two local symbols. ++These are only needed to support linker relaxation and can be ignored ++when not relaxing. The field is set to the value of the difference ++assuming no relaxation. The relocation encodes the position of the ++first symbol so the linker can determine whether to adjust the field ++value. */ ++ BFD_RELOC_XTENSA_DIFF8, ++ BFD_RELOC_XTENSA_DIFF16, ++ BFD_RELOC_XTENSA_DIFF32, ++ ++/* Generic Xtensa relocations for instruction operands. Only the slot ++number is encoded in the relocation. The relocation applies to the ++last PC-relative immediate operand, or if there are no PC-relative ++immediates, to the last immediate operand. */ ++ BFD_RELOC_XTENSA_SLOT0_OP, ++ BFD_RELOC_XTENSA_SLOT1_OP, ++ BFD_RELOC_XTENSA_SLOT2_OP, ++ BFD_RELOC_XTENSA_SLOT3_OP, ++ BFD_RELOC_XTENSA_SLOT4_OP, ++ BFD_RELOC_XTENSA_SLOT5_OP, ++ BFD_RELOC_XTENSA_SLOT6_OP, ++ BFD_RELOC_XTENSA_SLOT7_OP, ++ BFD_RELOC_XTENSA_SLOT8_OP, ++ BFD_RELOC_XTENSA_SLOT9_OP, ++ BFD_RELOC_XTENSA_SLOT10_OP, ++ BFD_RELOC_XTENSA_SLOT11_OP, ++ BFD_RELOC_XTENSA_SLOT12_OP, ++ BFD_RELOC_XTENSA_SLOT13_OP, ++ BFD_RELOC_XTENSA_SLOT14_OP, ++ ++/* Alternate Xtensa relocations. Only the slot is encoded in the ++relocation. The meaning of these relocations is opcode-specific. */ ++ BFD_RELOC_XTENSA_SLOT0_ALT, ++ BFD_RELOC_XTENSA_SLOT1_ALT, ++ BFD_RELOC_XTENSA_SLOT2_ALT, ++ BFD_RELOC_XTENSA_SLOT3_ALT, ++ BFD_RELOC_XTENSA_SLOT4_ALT, ++ BFD_RELOC_XTENSA_SLOT5_ALT, ++ BFD_RELOC_XTENSA_SLOT6_ALT, ++ BFD_RELOC_XTENSA_SLOT7_ALT, ++ BFD_RELOC_XTENSA_SLOT8_ALT, ++ BFD_RELOC_XTENSA_SLOT9_ALT, ++ BFD_RELOC_XTENSA_SLOT10_ALT, ++ BFD_RELOC_XTENSA_SLOT11_ALT, ++ BFD_RELOC_XTENSA_SLOT12_ALT, ++ BFD_RELOC_XTENSA_SLOT13_ALT, ++ BFD_RELOC_XTENSA_SLOT14_ALT, ++ ++/* Xtensa relocations for backward compatibility. These have all been ++replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ ++ BFD_RELOC_XTENSA_OP0, ++ BFD_RELOC_XTENSA_OP1, ++ BFD_RELOC_XTENSA_OP2, ++ ++/* Xtensa relocation to mark that the assembler expanded the ++instructions from an original target. The expansion size is ++encoded in the reloc size. */ ++ BFD_RELOC_XTENSA_ASM_EXPAND, ++ ++/* Xtensa relocation to mark that the linker should simplify ++assembler-expanded instructions. This is commonly used ++internally by the linker after analysis of a ++BFD_RELOC_XTENSA_ASM_EXPAND. */ ++ BFD_RELOC_XTENSA_ASM_SIMPLIFY, ++ BFD_RELOC_UNUSED }; ++typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; ++reloc_howto_type *bfd_reloc_type_lookup ++ (bfd *abfd, bfd_reloc_code_real_type code); ++ ++const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); ++ ++/* Extracted from syms.c. */ ++ ++typedef struct bfd_symbol ++{ ++ /* A pointer to the BFD which owns the symbol. This information ++ is necessary so that a back end can work out what additional ++ information (invisible to the application writer) is carried ++ with the symbol. ++ ++ This field is *almost* redundant, since you can use section->owner ++ instead, except that some symbols point to the global sections ++ bfd_{abs,com,und}_section. This could be fixed by making ++ these globals be per-bfd (or per-target-flavor). FIXME. */ ++ struct bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ ++ ++ /* The text of the symbol. The name is left alone, and not copied; the ++ application may not alter it. */ ++ const char *name; ++ ++ /* The value of the symbol. This really should be a union of a ++ numeric value with a pointer, since some flags indicate that ++ a pointer to another symbol is stored here. */ ++ symvalue value; ++ ++ /* Attributes of a symbol. */ ++#define BSF_NO_FLAGS 0x00 ++ ++ /* The symbol has local scope; <> in <>. The value ++ is the offset into the section of the data. */ ++#define BSF_LOCAL 0x01 ++ ++ /* The symbol has global scope; initialized data in <>. The ++ value is the offset into the section of the data. */ ++#define BSF_GLOBAL 0x02 ++ ++ /* The symbol has global scope and is exported. The value is ++ the offset into the section of the data. */ ++#define BSF_EXPORT BSF_GLOBAL /* No real difference. */ ++ ++ /* A normal C symbol would be one of: ++ <>, <>, <> or ++ <>. */ ++ ++ /* The symbol is a debugging record. The value has an arbitrary ++ meaning, unless BSF_DEBUGGING_RELOC is also set. */ ++#define BSF_DEBUGGING 0x08 ++ ++ /* The symbol denotes a function entry point. Used in ELF, ++ perhaps others someday. */ ++#define BSF_FUNCTION 0x10 ++ ++ /* Used by the linker. */ ++#define BSF_KEEP 0x20 ++#define BSF_KEEP_G 0x40 ++ ++ /* A weak global symbol, overridable without warnings by ++ a regular global symbol of the same name. */ ++#define BSF_WEAK 0x80 ++ ++ /* This symbol was created to point to a section, e.g. ELF's ++ STT_SECTION symbols. */ ++#define BSF_SECTION_SYM 0x100 ++ ++ /* The symbol used to be a common symbol, but now it is ++ allocated. */ ++#define BSF_OLD_COMMON 0x200 ++ ++ /* The default value for common data. */ ++#define BFD_FORT_COMM_DEFAULT_VALUE 0 ++ ++ /* In some files the type of a symbol sometimes alters its ++ location in an output file - ie in coff a <> symbol ++ which is also <> symbol appears where it was ++ declared and not at the end of a section. This bit is set ++ by the target BFD part to convey this information. */ ++#define BSF_NOT_AT_END 0x400 ++ ++ /* Signal that the symbol is the label of constructor section. */ ++#define BSF_CONSTRUCTOR 0x800 ++ ++ /* Signal that the symbol is a warning symbol. The name is a ++ warning. The name of the next symbol is the one to warn about; ++ if a reference is made to a symbol with the same name as the next ++ symbol, a warning is issued by the linker. */ ++#define BSF_WARNING 0x1000 ++ ++ /* Signal that the symbol is indirect. This symbol is an indirect ++ pointer to the symbol with the same name as the next symbol. */ ++#define BSF_INDIRECT 0x2000 ++ ++ /* BSF_FILE marks symbols that contain a file name. This is used ++ for ELF STT_FILE symbols. */ ++#define BSF_FILE 0x4000 ++ ++ /* Symbol is from dynamic linking information. */ ++#define BSF_DYNAMIC 0x8000 ++ ++ /* The symbol denotes a data object. Used in ELF, and perhaps ++ others someday. */ ++#define BSF_OBJECT 0x10000 ++ ++ /* This symbol is a debugging symbol. The value is the offset ++ into the section of the data. BSF_DEBUGGING should be set ++ as well. */ ++#define BSF_DEBUGGING_RELOC 0x20000 ++ ++ /* This symbol is thread local. Used in ELF. */ ++#define BSF_THREAD_LOCAL 0x40000 ++ ++ flagword flags; ++ ++ /* A pointer to the section to which this symbol is ++ relative. This will always be non NULL, there are special ++ sections for undefined and absolute symbols. */ ++ struct bfd_section *section; ++ ++ /* Back end special data. */ ++ union ++ { ++ void *p; ++ bfd_vma i; ++ } ++ udata; ++} ++asymbol; ++ ++#define bfd_get_symtab_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) ++ ++bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); ++ ++bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); ++ ++#define bfd_is_local_label_name(abfd, name) \ ++ BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) ++ ++bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); ++ ++#define bfd_is_target_special_symbol(abfd, sym) \ ++ BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) ++ ++#define bfd_canonicalize_symtab(abfd, location) \ ++ BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) ++ ++bfd_boolean bfd_set_symtab ++ (bfd *abfd, asymbol **location, unsigned int count); ++ ++void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); ++ ++#define bfd_make_empty_symbol(abfd) \ ++ BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) ++ ++asymbol *_bfd_generic_make_empty_symbol (bfd *); ++ ++#define bfd_make_debug_symbol(abfd,ptr,size) \ ++ BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) ++ ++int bfd_decode_symclass (asymbol *symbol); ++ ++bfd_boolean bfd_is_undefined_symclass (int symclass); ++ ++void bfd_symbol_info (asymbol *symbol, symbol_info *ret); ++ ++bfd_boolean bfd_copy_private_symbol_data ++ (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); ++ ++#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ ++ BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ ++ (ibfd, isymbol, obfd, osymbol)) ++ ++/* Extracted from bfd.c. */ ++struct bfd ++{ ++ /* A unique identifier of the BFD */ ++ unsigned int id; ++ ++ /* The filename the application opened the BFD with. */ ++ const char *filename; ++ ++ /* A pointer to the target jump table. */ ++ const struct bfd_target *xvec; ++ ++ /* The IOSTREAM, and corresponding IO vector that provide access ++ to the file backing the BFD. */ ++ void *iostream; ++ const struct bfd_iovec *iovec; ++ ++ /* Is the file descriptor being cached? That is, can it be closed as ++ needed, and re-opened when accessed later? */ ++ bfd_boolean cacheable; ++ ++ /* Marks whether there was a default target specified when the ++ BFD was opened. This is used to select which matching algorithm ++ to use to choose the back end. */ ++ bfd_boolean target_defaulted; ++ ++ /* The caching routines use these to maintain a ++ least-recently-used list of BFDs. */ ++ struct bfd *lru_prev, *lru_next; ++ ++ /* When a file is closed by the caching routines, BFD retains ++ state information on the file here... */ ++ ufile_ptr where; ++ ++ /* ... and here: (``once'' means at least once). */ ++ bfd_boolean opened_once; ++ ++ /* Set if we have a locally maintained mtime value, rather than ++ getting it from the file each time. */ ++ bfd_boolean mtime_set; ++ ++ /* File modified time, if mtime_set is TRUE. */ ++ long mtime; ++ ++ /* Reserved for an unimplemented file locking extension. */ ++ int ifd; ++ ++ /* The format which belongs to the BFD. (object, core, etc.) */ ++ bfd_format format; ++ ++ /* The direction with which the BFD was opened. */ ++ enum bfd_direction ++ { ++ no_direction = 0, ++ read_direction = 1, ++ write_direction = 2, ++ both_direction = 3 ++ } ++ direction; ++ ++ /* Format_specific flags. */ ++ flagword flags; ++ ++ /* Currently my_archive is tested before adding origin to ++ anything. I believe that this can become always an add of ++ origin, with origin set to 0 for non archive files. */ ++ ufile_ptr origin; ++ ++ /* Remember when output has begun, to stop strange things ++ from happening. */ ++ bfd_boolean output_has_begun; ++ ++ /* A hash table for section names. */ ++ struct bfd_hash_table section_htab; ++ ++ /* Pointer to linked list of sections. */ ++ struct bfd_section *sections; ++ ++ /* The last section on the section list. */ ++ struct bfd_section *section_last; ++ ++ /* The number of sections. */ ++ unsigned int section_count; ++ ++ /* Stuff only useful for object files: ++ The start address. */ ++ bfd_vma start_address; ++ ++ /* Used for input and output. */ ++ unsigned int symcount; ++ ++ /* Symbol table for output BFD (with symcount entries). */ ++ struct bfd_symbol **outsymbols; ++ ++ /* Used for slurped dynamic symbol tables. */ ++ unsigned int dynsymcount; ++ ++ /* Pointer to structure which contains architecture information. */ ++ const struct bfd_arch_info *arch_info; ++ ++ /* Flag set if symbols from this BFD should not be exported. */ ++ bfd_boolean no_export; ++ ++ /* Stuff only useful for archives. */ ++ void *arelt_data; ++ struct bfd *my_archive; /* The containing archive BFD. */ ++ struct bfd *next; /* The next BFD in the archive. */ ++ struct bfd *archive_head; /* The first BFD in the archive. */ ++ bfd_boolean has_armap; ++ ++ /* A chain of BFD structures involved in a link. */ ++ struct bfd *link_next; ++ ++ /* A field used by _bfd_generic_link_add_archive_symbols. This will ++ be used only for archive elements. */ ++ int archive_pass; ++ ++ /* Used by the back end to hold private data. */ ++ union ++ { ++ struct aout_data_struct *aout_data; ++ struct artdata *aout_ar_data; ++ struct _oasys_data *oasys_obj_data; ++ struct _oasys_ar_data *oasys_ar_data; ++ struct coff_tdata *coff_obj_data; ++ struct pe_tdata *pe_obj_data; ++ struct xcoff_tdata *xcoff_obj_data; ++ struct ecoff_tdata *ecoff_obj_data; ++ struct ieee_data_struct *ieee_data; ++ struct ieee_ar_data_struct *ieee_ar_data; ++ struct srec_data_struct *srec_data; ++ struct ihex_data_struct *ihex_data; ++ struct tekhex_data_struct *tekhex_data; ++ struct elf_obj_tdata *elf_obj_data; ++ struct nlm_obj_tdata *nlm_obj_data; ++ struct bout_data_struct *bout_data; ++ struct mmo_data_struct *mmo_data; ++ struct sun_core_struct *sun_core_data; ++ struct sco5_core_struct *sco5_core_data; ++ struct trad_core_struct *trad_core_data; ++ struct som_data_struct *som_data; ++ struct hpux_core_struct *hpux_core_data; ++ struct hppabsd_core_struct *hppabsd_core_data; ++ struct sgi_core_struct *sgi_core_data; ++ struct lynx_core_struct *lynx_core_data; ++ struct osf_core_struct *osf_core_data; ++ struct cisco_core_struct *cisco_core_data; ++ struct versados_data_struct *versados_data; ++ struct netbsd_core_struct *netbsd_core_data; ++ struct mach_o_data_struct *mach_o_data; ++ struct mach_o_fat_data_struct *mach_o_fat_data; ++ struct bfd_pef_data_struct *pef_data; ++ struct bfd_pef_xlib_data_struct *pef_xlib_data; ++ struct bfd_sym_data_struct *sym_data; ++ void *any; ++ } ++ tdata; ++ ++ /* Used by the application to hold private data. */ ++ void *usrdata; ++ ++ /* Where all the allocated stuff under this BFD goes. This is a ++ struct objalloc *, but we use void * to avoid requiring the inclusion ++ of objalloc.h. */ ++ void *memory; ++}; ++ ++typedef enum bfd_error ++{ ++ bfd_error_no_error = 0, ++ bfd_error_system_call, ++ bfd_error_invalid_target, ++ bfd_error_wrong_format, ++ bfd_error_wrong_object_format, ++ bfd_error_invalid_operation, ++ bfd_error_no_memory, ++ bfd_error_no_symbols, ++ bfd_error_no_armap, ++ bfd_error_no_more_archived_files, ++ bfd_error_malformed_archive, ++ bfd_error_file_not_recognized, ++ bfd_error_file_ambiguously_recognized, ++ bfd_error_no_contents, ++ bfd_error_nonrepresentable_section, ++ bfd_error_no_debug_section, ++ bfd_error_bad_value, ++ bfd_error_file_truncated, ++ bfd_error_file_too_big, ++ bfd_error_invalid_error_code ++} ++bfd_error_type; ++ ++bfd_error_type bfd_get_error (void); ++ ++void bfd_set_error (bfd_error_type error_tag); ++ ++const char *bfd_errmsg (bfd_error_type error_tag); ++ ++void bfd_perror (const char *message); ++ ++typedef void (*bfd_error_handler_type) (const char *, ...); ++ ++bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); ++ ++void bfd_set_error_program_name (const char *); ++ ++bfd_error_handler_type bfd_get_error_handler (void); ++ ++long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); ++ ++long bfd_canonicalize_reloc ++ (bfd *abfd, asection *sec, arelent **loc, asymbol **syms); ++ ++void bfd_set_reloc ++ (bfd *abfd, asection *sec, arelent **rel, unsigned int count); ++ ++bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); ++ ++int bfd_get_arch_size (bfd *abfd); ++ ++int bfd_get_sign_extend_vma (bfd *abfd); ++ ++bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); ++ ++unsigned int bfd_get_gp_size (bfd *abfd); ++ ++void bfd_set_gp_size (bfd *abfd, unsigned int i); ++ ++bfd_vma bfd_scan_vma (const char *string, const char **end, int base); ++ ++bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_copy_private_header_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_copy_private_header_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_copy_private_bfd_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_merge_private_bfd_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); ++ ++#define bfd_set_private_flags(abfd, flags) \ ++ BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) ++#define bfd_sizeof_headers(abfd, reloc) \ ++ BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) ++ ++#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ ++ BFD_SEND (abfd, _bfd_find_nearest_line, \ ++ (abfd, sec, syms, off, file, func, line)) ++ ++#define bfd_find_line(abfd, syms, sym, file, line) \ ++ BFD_SEND (abfd, _bfd_find_line, \ ++ (abfd, syms, sym, file, line)) ++ ++#define bfd_find_inliner_info(abfd, file, func, line) \ ++ BFD_SEND (abfd, _bfd_find_inliner_info, \ ++ (abfd, file, func, line)) ++ ++#define bfd_debug_info_start(abfd) \ ++ BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) ++ ++#define bfd_debug_info_end(abfd) \ ++ BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) ++ ++#define bfd_debug_info_accumulate(abfd, section) \ ++ BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) ++ ++#define bfd_stat_arch_elt(abfd, stat) \ ++ BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) ++ ++#define bfd_update_armap_timestamp(abfd) \ ++ BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) ++ ++#define bfd_set_arch_mach(abfd, arch, mach)\ ++ BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) ++ ++#define bfd_relax_section(abfd, section, link_info, again) \ ++ BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) ++ ++#define bfd_gc_sections(abfd, link_info) \ ++ BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) ++ ++#define bfd_merge_sections(abfd, link_info) \ ++ BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) ++ ++#define bfd_is_group_section(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) ++ ++#define bfd_discard_group(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) ++ ++#define bfd_link_hash_table_create(abfd) \ ++ BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) ++ ++#define bfd_link_hash_table_free(abfd, hash) \ ++ BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) ++ ++#define bfd_link_add_symbols(abfd, info) \ ++ BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) ++ ++#define bfd_link_just_syms(abfd, sec, info) \ ++ BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) ++ ++#define bfd_final_link(abfd, info) \ ++ BFD_SEND (abfd, _bfd_final_link, (abfd, info)) ++ ++#define bfd_free_cached_info(abfd) \ ++ BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) ++ ++#define bfd_get_dynamic_symtab_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) ++ ++#define bfd_print_private_bfd_data(abfd, file)\ ++ BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) ++ ++#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ ++ BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) ++ ++#define bfd_get_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ ++ BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ ++ dyncount, dynsyms, ret)) ++ ++#define bfd_get_dynamic_reloc_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) ++ ++#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ ++ BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) ++ ++extern bfd_byte *bfd_get_relocated_section_contents ++ (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, ++ bfd_boolean, asymbol **); ++ ++bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); ++ ++struct bfd_preserve ++{ ++ void *marker; ++ void *tdata; ++ flagword flags; ++ const struct bfd_arch_info *arch_info; ++ struct bfd_section *sections; ++ struct bfd_section *section_last; ++ unsigned int section_count; ++ struct bfd_hash_table section_htab; ++}; ++ ++bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); ++ ++void bfd_preserve_restore (bfd *, struct bfd_preserve *); ++ ++void bfd_preserve_finish (bfd *, struct bfd_preserve *); ++ ++/* Extracted from archive.c. */ ++symindex bfd_get_next_mapent ++ (bfd *abfd, symindex previous, carsym **sym); ++ ++bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); ++ ++bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); ++ ++/* Extracted from corefile.c. */ ++const char *bfd_core_file_failing_command (bfd *abfd); ++ ++int bfd_core_file_failing_signal (bfd *abfd); ++ ++bfd_boolean core_file_matches_executable_p ++ (bfd *core_bfd, bfd *exec_bfd); ++ ++/* Extracted from targets.c. */ ++#define BFD_SEND(bfd, message, arglist) \ ++ ((*((bfd)->xvec->message)) arglist) ++ ++#ifdef DEBUG_BFD_SEND ++#undef BFD_SEND ++#define BFD_SEND(bfd, message, arglist) \ ++ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ ++ ((*((bfd)->xvec->message)) arglist) : \ ++ (bfd_assert (__FILE__,__LINE__), NULL)) ++#endif ++#define BFD_SEND_FMT(bfd, message, arglist) \ ++ (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) ++ ++#ifdef DEBUG_BFD_SEND ++#undef BFD_SEND_FMT ++#define BFD_SEND_FMT(bfd, message, arglist) \ ++ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ ++ (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ ++ (bfd_assert (__FILE__,__LINE__), NULL)) ++#endif ++ ++enum bfd_flavour ++{ ++ bfd_target_unknown_flavour, ++ bfd_target_aout_flavour, ++ bfd_target_coff_flavour, ++ bfd_target_ecoff_flavour, ++ bfd_target_xcoff_flavour, ++ bfd_target_elf_flavour, ++ bfd_target_ieee_flavour, ++ bfd_target_nlm_flavour, ++ bfd_target_oasys_flavour, ++ bfd_target_tekhex_flavour, ++ bfd_target_srec_flavour, ++ bfd_target_ihex_flavour, ++ bfd_target_som_flavour, ++ bfd_target_os9k_flavour, ++ bfd_target_versados_flavour, ++ bfd_target_msdos_flavour, ++ bfd_target_ovax_flavour, ++ bfd_target_evax_flavour, ++ bfd_target_mmo_flavour, ++ bfd_target_mach_o_flavour, ++ bfd_target_pef_flavour, ++ bfd_target_pef_xlib_flavour, ++ bfd_target_sym_flavour ++}; ++ ++enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; ++ ++/* Forward declaration. */ ++typedef struct bfd_link_info _bfd_link_info; ++ ++typedef struct bfd_target ++{ ++ /* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */ ++ char *name; ++ ++ /* The "flavour" of a back end is a general indication about ++ the contents of a file. */ ++ enum bfd_flavour flavour; ++ ++ /* The order of bytes within the data area of a file. */ ++ enum bfd_endian byteorder; ++ ++ /* The order of bytes within the header parts of a file. */ ++ enum bfd_endian header_byteorder; ++ ++ /* A mask of all the flags which an executable may have set - ++ from the set <>, <>, ...<>. */ ++ flagword object_flags; ++ ++ /* A mask of all the flags which a section may have set - from ++ the set <>, <>, ...<>. */ ++ flagword section_flags; ++ ++ /* The character normally found at the front of a symbol. ++ (if any), perhaps `_'. */ ++ char symbol_leading_char; ++ ++ /* The pad character for file names within an archive header. */ ++ char ar_pad_char; ++ ++ /* The maximum number of characters in an archive header. */ ++ unsigned short ar_max_namelen; ++ ++ /* Entries for byte swapping for data. These are different from the ++ other entry points, since they don't take a BFD as the first argument. ++ Certain other handlers could do the same. */ ++ bfd_uint64_t (*bfd_getx64) (const void *); ++ bfd_int64_t (*bfd_getx_signed_64) (const void *); ++ void (*bfd_putx64) (bfd_uint64_t, void *); ++ bfd_vma (*bfd_getx32) (const void *); ++ bfd_signed_vma (*bfd_getx_signed_32) (const void *); ++ void (*bfd_putx32) (bfd_vma, void *); ++ bfd_vma (*bfd_getx16) (const void *); ++ bfd_signed_vma (*bfd_getx_signed_16) (const void *); ++ void (*bfd_putx16) (bfd_vma, void *); ++ ++ /* Byte swapping for the headers. */ ++ bfd_uint64_t (*bfd_h_getx64) (const void *); ++ bfd_int64_t (*bfd_h_getx_signed_64) (const void *); ++ void (*bfd_h_putx64) (bfd_uint64_t, void *); ++ bfd_vma (*bfd_h_getx32) (const void *); ++ bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); ++ void (*bfd_h_putx32) (bfd_vma, void *); ++ bfd_vma (*bfd_h_getx16) (const void *); ++ bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); ++ void (*bfd_h_putx16) (bfd_vma, void *); ++ ++ /* Format dependent routines: these are vectors of entry points ++ within the target vector structure, one for each format to check. */ ++ ++ /* Check the format of a file being read. Return a <> or zero. */ ++ const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); ++ ++ /* Set the format of a file being written. */ ++ bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); ++ ++ /* Write cached information into a file being written, at <>. */ ++ bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); ++ ++ ++ /* Generic entry points. */ ++#define BFD_JUMP_TABLE_GENERIC(NAME) \ ++ NAME##_close_and_cleanup, \ ++ NAME##_bfd_free_cached_info, \ ++ NAME##_new_section_hook, \ ++ NAME##_get_section_contents, \ ++ NAME##_get_section_contents_in_window ++ ++ /* Called when the BFD is being closed to do any necessary cleanup. */ ++ bfd_boolean (*_close_and_cleanup) (bfd *); ++ /* Ask the BFD to free all cached information. */ ++ bfd_boolean (*_bfd_free_cached_info) (bfd *); ++ /* Called when a new section is created. */ ++ bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); ++ /* Read the contents of a section. */ ++ bfd_boolean (*_bfd_get_section_contents) ++ (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); ++ bfd_boolean (*_bfd_get_section_contents_in_window) ++ (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); ++ ++ /* Entry points to copy private data. */ ++#define BFD_JUMP_TABLE_COPY(NAME) \ ++ NAME##_bfd_copy_private_bfd_data, \ ++ NAME##_bfd_merge_private_bfd_data, \ ++ NAME##_bfd_copy_private_section_data, \ ++ NAME##_bfd_copy_private_symbol_data, \ ++ NAME##_bfd_copy_private_header_data, \ ++ NAME##_bfd_set_private_flags, \ ++ NAME##_bfd_print_private_bfd_data ++ ++ /* Called to copy BFD general private data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_bfd_data) (bfd *, bfd *); ++ /* Called to merge BFD general private data from one object file ++ to a common output file when linking. */ ++ bfd_boolean (*_bfd_merge_private_bfd_data) (bfd *, bfd *); ++ /* Called to copy BFD private section data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_section_data) ++ (bfd *, sec_ptr, bfd *, sec_ptr); ++ /* Called to copy BFD private symbol data from one symbol ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_symbol_data) ++ (bfd *, asymbol *, bfd *, asymbol *); ++ /* Called to copy BFD private header data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_header_data) ++ (bfd *, bfd *); ++ /* Called to set private backend flags. */ ++ bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); ++ ++ /* Called to print private BFD data. */ ++ bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); ++ ++ /* Core file entry points. */ ++#define BFD_JUMP_TABLE_CORE(NAME) \ ++ NAME##_core_file_failing_command, \ ++ NAME##_core_file_failing_signal, \ ++ NAME##_core_file_matches_executable_p ++ ++ char * (*_core_file_failing_command) (bfd *); ++ int (*_core_file_failing_signal) (bfd *); ++ bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); ++ ++ /* Archive entry points. */ ++#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ ++ NAME##_slurp_armap, \ ++ NAME##_slurp_extended_name_table, \ ++ NAME##_construct_extended_name_table, \ ++ NAME##_truncate_arname, \ ++ NAME##_write_armap, \ ++ NAME##_read_ar_hdr, \ ++ NAME##_openr_next_archived_file, \ ++ NAME##_get_elt_at_index, \ ++ NAME##_generic_stat_arch_elt, \ ++ NAME##_update_armap_timestamp ++ ++ bfd_boolean (*_bfd_slurp_armap) (bfd *); ++ bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); ++ bfd_boolean (*_bfd_construct_extended_name_table) ++ (bfd *, char **, bfd_size_type *, const char **); ++ void (*_bfd_truncate_arname) (bfd *, const char *, char *); ++ bfd_boolean (*write_armap) ++ (bfd *, unsigned int, struct orl *, unsigned int, int); ++ void * (*_bfd_read_ar_hdr_fn) (bfd *); ++ bfd * (*openr_next_archived_file) (bfd *, bfd *); ++#define bfd_get_elt_at_index(b,i) BFD_SEND (b, _bfd_get_elt_at_index, (b,i)) ++ bfd * (*_bfd_get_elt_at_index) (bfd *, symindex); ++ int (*_bfd_stat_arch_elt) (bfd *, struct stat *); ++ bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); ++ ++ /* Entry points used for symbols. */ ++#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ ++ NAME##_get_symtab_upper_bound, \ ++ NAME##_canonicalize_symtab, \ ++ NAME##_make_empty_symbol, \ ++ NAME##_print_symbol, \ ++ NAME##_get_symbol_info, \ ++ NAME##_bfd_is_local_label_name, \ ++ NAME##_bfd_is_target_special_symbol, \ ++ NAME##_get_lineno, \ ++ NAME##_find_nearest_line, \ ++ _bfd_generic_find_line, \ ++ NAME##_find_inliner_info, \ ++ NAME##_bfd_make_debug_symbol, \ ++ NAME##_read_minisymbols, \ ++ NAME##_minisymbol_to_symbol ++ ++ long (*_bfd_get_symtab_upper_bound) (bfd *); ++ long (*_bfd_canonicalize_symtab) ++ (bfd *, struct bfd_symbol **); ++ struct bfd_symbol * ++ (*_bfd_make_empty_symbol) (bfd *); ++ void (*_bfd_print_symbol) ++ (bfd *, void *, struct bfd_symbol *, bfd_print_symbol_type); ++#define bfd_print_symbol(b,p,s,e) BFD_SEND (b, _bfd_print_symbol, (b,p,s,e)) ++ void (*_bfd_get_symbol_info) ++ (bfd *, struct bfd_symbol *, symbol_info *); ++#define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) ++ bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); ++ bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); ++ alent * (*_get_lineno) (bfd *, struct bfd_symbol *); ++ bfd_boolean (*_bfd_find_nearest_line) ++ (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, ++ const char **, const char **, unsigned int *); ++ bfd_boolean (*_bfd_find_line) ++ (bfd *, struct bfd_symbol **, struct bfd_symbol *, ++ const char **, unsigned int *); ++ bfd_boolean (*_bfd_find_inliner_info) ++ (bfd *, const char **, const char **, unsigned int *); ++ /* Back-door to allow format-aware applications to create debug symbols ++ while using BFD for everything else. Currently used by the assembler ++ when creating COFF files. */ ++ asymbol * (*_bfd_make_debug_symbol) ++ (bfd *, void *, unsigned long size); ++#define bfd_read_minisymbols(b, d, m, s) \ ++ BFD_SEND (b, _read_minisymbols, (b, d, m, s)) ++ long (*_read_minisymbols) ++ (bfd *, bfd_boolean, void **, unsigned int *); ++#define bfd_minisymbol_to_symbol(b, d, m, f) \ ++ BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) ++ asymbol * (*_minisymbol_to_symbol) ++ (bfd *, bfd_boolean, const void *, asymbol *); ++ ++ /* Routines for relocs. */ ++#define BFD_JUMP_TABLE_RELOCS(NAME) \ ++ NAME##_get_reloc_upper_bound, \ ++ NAME##_canonicalize_reloc, \ ++ NAME##_bfd_reloc_type_lookup ++ ++ long (*_get_reloc_upper_bound) (bfd *, sec_ptr); ++ long (*_bfd_canonicalize_reloc) ++ (bfd *, sec_ptr, arelent **, struct bfd_symbol **); ++ /* See documentation on reloc types. */ ++ reloc_howto_type * ++ (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); ++ ++ /* Routines used when writing an object file. */ ++#define BFD_JUMP_TABLE_WRITE(NAME) \ ++ NAME##_set_arch_mach, \ ++ NAME##_set_section_contents ++ ++ bfd_boolean (*_bfd_set_arch_mach) ++ (bfd *, enum bfd_architecture, unsigned long); ++ bfd_boolean (*_bfd_set_section_contents) ++ (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); ++ ++ /* Routines used by the linker. */ ++#define BFD_JUMP_TABLE_LINK(NAME) \ ++ NAME##_sizeof_headers, \ ++ NAME##_bfd_get_relocated_section_contents, \ ++ NAME##_bfd_relax_section, \ ++ NAME##_bfd_link_hash_table_create, \ ++ NAME##_bfd_link_hash_table_free, \ ++ NAME##_bfd_link_add_symbols, \ ++ NAME##_bfd_link_just_syms, \ ++ NAME##_bfd_final_link, \ ++ NAME##_bfd_link_split_section, \ ++ NAME##_bfd_gc_sections, \ ++ NAME##_bfd_merge_sections, \ ++ NAME##_bfd_is_group_section, \ ++ NAME##_bfd_discard_group, \ ++ NAME##_section_already_linked \ ++ ++ int (*_bfd_sizeof_headers) (bfd *, bfd_boolean); ++ bfd_byte * (*_bfd_get_relocated_section_contents) ++ (bfd *, struct bfd_link_info *, struct bfd_link_order *, ++ bfd_byte *, bfd_boolean, struct bfd_symbol **); ++ ++ bfd_boolean (*_bfd_relax_section) ++ (bfd *, struct bfd_section *, struct bfd_link_info *, bfd_boolean *); ++ ++ /* Create a hash table for the linker. Different backends store ++ different information in this table. */ ++ struct bfd_link_hash_table * ++ (*_bfd_link_hash_table_create) (bfd *); ++ ++ /* Release the memory associated with the linker hash table. */ ++ void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); ++ ++ /* Add symbols from this object file into the hash table. */ ++ bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); ++ ++ /* Indicate that we are only retrieving symbol values from this section. */ ++ void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); ++ ++ /* Do a link based on the link_order structures attached to each ++ section of the BFD. */ ++ bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); ++ ++ /* Should this section be split up into smaller pieces during linking. */ ++ bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); ++ ++ /* Remove sections that are not referenced from the output. */ ++ bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); ++ ++ /* Attempt to merge SEC_MERGE sections. */ ++ bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); ++ ++ /* Is this section a member of a group? */ ++ bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); ++ ++ /* Discard members of a group. */ ++ bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); ++ ++ /* Check if SEC has been already linked during a reloceatable or ++ final link. */ ++ void (*_section_already_linked) (bfd *, struct bfd_section *); ++ ++ /* Routines to handle dynamic symbols and relocs. */ ++#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ ++ NAME##_get_dynamic_symtab_upper_bound, \ ++ NAME##_canonicalize_dynamic_symtab, \ ++ NAME##_get_synthetic_symtab, \ ++ NAME##_get_dynamic_reloc_upper_bound, \ ++ NAME##_canonicalize_dynamic_reloc ++ ++ /* Get the amount of memory required to hold the dynamic symbols. */ ++ long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); ++ /* Read in the dynamic symbols. */ ++ long (*_bfd_canonicalize_dynamic_symtab) ++ (bfd *, struct bfd_symbol **); ++ /* Create synthetized symbols. */ ++ long (*_bfd_get_synthetic_symtab) ++ (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, ++ struct bfd_symbol **); ++ /* Get the amount of memory required to hold the dynamic relocs. */ ++ long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); ++ /* Read in the dynamic relocs. */ ++ long (*_bfd_canonicalize_dynamic_reloc) ++ (bfd *, arelent **, struct bfd_symbol **); ++ ++ /* Opposite endian version of this target. */ ++ const struct bfd_target * alternative_target; ++ ++ /* Data for use by back-end routines, which isn't ++ generic enough to belong in this structure. */ ++ const void *backend_data; ++ ++} bfd_target; ++ ++bfd_boolean bfd_set_default_target (const char *name); ++ ++const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); ++ ++const char ** bfd_target_list (void); ++ ++const bfd_target *bfd_search_for_target ++ (int (*search_func) (const bfd_target *, void *), ++ void *); ++ ++/* Extracted from format.c. */ ++bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); ++ ++bfd_boolean bfd_check_format_matches ++ (bfd *abfd, bfd_format format, char ***matching); ++ ++bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); ++ ++const char *bfd_format_string (bfd_format format); ++ ++/* Extracted from linker.c. */ ++bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); ++ ++#define bfd_link_split_section(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) ++ ++void bfd_section_already_linked (bfd *abfd, asection *sec); ++ ++#define bfd_section_already_linked(abfd, sec) \ ++ BFD_SEND (abfd, _section_already_linked, (abfd, sec)) ++ ++/* Extracted from simple.c. */ ++bfd_byte *bfd_simple_get_relocated_section_contents ++ (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif +--- /dev/null ++++ b/include/asm-x86/bfd_64.h +@@ -0,0 +1,4917 @@ ++/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically ++ generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", ++ "bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", ++ "syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c", ++ "linker.c" and "simple.c". ++ Run "make headers" in your build bfd/ to regenerate. */ ++ ++/* Main header file for the bfd library -- portable access to object files. ++ ++ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, ++ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. ++ ++ Contributed by Cygnus Support. ++ ++ This file is part of BFD, the Binary File Descriptor library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ ++ ++/* Extracted from binutils 2.16.91.0.2 (OpenSUSE 10.0) and modified for kdb use. ++ * Any trailing whitespace was removed and #ifdef/ifndef __KERNEL__ added as ++ * required. ++ * Keith Owens 15 May 2006 ++ */ ++ ++#ifndef __BFD_H_SEEN__ ++#define __BFD_H_SEEN__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifdef __KERNEL__ ++#include ++#else /* __KERNEL__ */ ++#include "ansidecl.h" ++#include "symcat.h" ++#endif /* __KERNEL__ */ ++#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) ++#ifndef SABER ++/* This hack is to avoid a problem with some strict ANSI C preprocessors. ++ The problem is, "32_" is not a valid preprocessing token, and we don't ++ want extra underscores (e.g., "nlm_32_"). The XCONCAT2 macro will ++ cause the inner CONCAT2 macros to be evaluated first, producing ++ still-valid pp-tokens. Then the final concatenation can be done. */ ++#undef CONCAT4 ++#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d)) ++#endif ++#endif ++ ++/* The word size used by BFD on the host. This may be 64 with a 32 ++ bit target if the host is 64 bit, or if other 64 bit targets have ++ been selected with --enable-targets, or if --enable-64-bit-bfd. */ ++#define BFD_ARCH_SIZE 64 ++ ++/* The word size of the default bfd target. */ ++#define BFD_DEFAULT_TARGET_SIZE 64 ++ ++#define BFD_HOST_64BIT_LONG 1 ++#define BFD_HOST_LONG_LONG 1 ++#if 1 ++#define BFD_HOST_64_BIT long ++#define BFD_HOST_U_64_BIT unsigned long ++typedef BFD_HOST_64_BIT bfd_int64_t; ++typedef BFD_HOST_U_64_BIT bfd_uint64_t; ++#endif ++ ++#if BFD_ARCH_SIZE >= 64 ++#define BFD64 ++#endif ++ ++#ifndef INLINE ++#if __GNUC__ >= 2 ++#define INLINE __inline__ ++#else ++#define INLINE ++#endif ++#endif ++ ++/* Forward declaration. */ ++typedef struct bfd bfd; ++ ++/* Boolean type used in bfd. Too many systems define their own ++ versions of "boolean" for us to safely typedef a "boolean" of ++ our own. Using an enum for "bfd_boolean" has its own set of ++ problems, with strange looking casts required to avoid warnings ++ on some older compilers. Thus we just use an int. ++ ++ General rule: Functions which are bfd_boolean return TRUE on ++ success and FALSE on failure (unless they're a predicate). */ ++ ++typedef int bfd_boolean; ++#undef FALSE ++#undef TRUE ++#define FALSE 0 ++#define TRUE 1 ++ ++#ifdef BFD64 ++ ++#ifndef BFD_HOST_64_BIT ++ #error No 64 bit integer type available ++#endif /* ! defined (BFD_HOST_64_BIT) */ ++ ++typedef BFD_HOST_U_64_BIT bfd_vma; ++typedef BFD_HOST_64_BIT bfd_signed_vma; ++typedef BFD_HOST_U_64_BIT bfd_size_type; ++typedef BFD_HOST_U_64_BIT symvalue; ++ ++#ifndef fprintf_vma ++#if BFD_HOST_64BIT_LONG ++#define sprintf_vma(s,x) sprintf (s, "%016lx", x) ++#define fprintf_vma(f,x) fprintf (f, "%016lx", x) ++#else ++#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) ++#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) ++#define fprintf_vma(s,x) \ ++ fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) ++#define sprintf_vma(s,x) \ ++ sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) ++#endif ++#endif ++ ++#else /* not BFD64 */ ++ ++/* Represent a target address. Also used as a generic unsigned type ++ which is guaranteed to be big enough to hold any arithmetic types ++ we need to deal with. */ ++typedef unsigned long bfd_vma; ++ ++/* A generic signed type which is guaranteed to be big enough to hold any ++ arithmetic types we need to deal with. Can be assumed to be compatible ++ with bfd_vma in the same way that signed and unsigned ints are compatible ++ (as parameters, in assignment, etc). */ ++typedef long bfd_signed_vma; ++ ++typedef unsigned long symvalue; ++typedef unsigned long bfd_size_type; ++ ++/* Print a bfd_vma x on stream s. */ ++#define fprintf_vma(s,x) fprintf (s, "%08lx", x) ++#define sprintf_vma(s,x) sprintf (s, "%08lx", x) ++ ++#endif /* not BFD64 */ ++ ++#define HALF_BFD_SIZE_TYPE \ ++ (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2)) ++ ++#ifndef BFD_HOST_64_BIT ++/* Fall back on a 32 bit type. The idea is to make these types always ++ available for function return types, but in the case that ++ BFD_HOST_64_BIT is undefined such a function should abort or ++ otherwise signal an error. */ ++typedef bfd_signed_vma bfd_int64_t; ++typedef bfd_vma bfd_uint64_t; ++#endif ++ ++/* An offset into a file. BFD always uses the largest possible offset ++ based on the build time availability of fseek, fseeko, or fseeko64. */ ++typedef BFD_HOST_64_BIT file_ptr; ++typedef unsigned BFD_HOST_64_BIT ufile_ptr; ++ ++extern void bfd_sprintf_vma (bfd *, char *, bfd_vma); ++extern void bfd_fprintf_vma (bfd *, void *, bfd_vma); ++ ++#define printf_vma(x) fprintf_vma(stdout,x) ++#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x) ++ ++typedef unsigned int flagword; /* 32 bits of flags */ ++typedef unsigned char bfd_byte; ++ ++/* File formats. */ ++ ++typedef enum bfd_format ++{ ++ bfd_unknown = 0, /* File format is unknown. */ ++ bfd_object, /* Linker/assembler/compiler output. */ ++ bfd_archive, /* Object archive file. */ ++ bfd_core, /* Core dump. */ ++ bfd_type_end /* Marks the end; don't use it! */ ++} ++bfd_format; ++ ++/* Values that may appear in the flags field of a BFD. These also ++ appear in the object_flags field of the bfd_target structure, where ++ they indicate the set of flags used by that backend (not all flags ++ are meaningful for all object file formats) (FIXME: at the moment, ++ the object_flags values have mostly just been copied from backend ++ to another, and are not necessarily correct). */ ++ ++/* No flags. */ ++#define BFD_NO_FLAGS 0x00 ++ ++/* BFD contains relocation entries. */ ++#define HAS_RELOC 0x01 ++ ++/* BFD is directly executable. */ ++#define EXEC_P 0x02 ++ ++/* BFD has line number information (basically used for F_LNNO in a ++ COFF header). */ ++#define HAS_LINENO 0x04 ++ ++/* BFD has debugging information. */ ++#define HAS_DEBUG 0x08 ++ ++/* BFD has symbols. */ ++#define HAS_SYMS 0x10 ++ ++/* BFD has local symbols (basically used for F_LSYMS in a COFF ++ header). */ ++#define HAS_LOCALS 0x20 ++ ++/* BFD is a dynamic object. */ ++#define DYNAMIC 0x40 ++ ++/* Text section is write protected (if D_PAGED is not set, this is ++ like an a.out NMAGIC file) (the linker sets this by default, but ++ clears it for -r or -N). */ ++#define WP_TEXT 0x80 ++ ++/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the ++ linker sets this by default, but clears it for -r or -n or -N). */ ++#define D_PAGED 0x100 ++ ++/* BFD is relaxable (this means that bfd_relax_section may be able to ++ do something) (sometimes bfd_relax_section can do something even if ++ this is not set). */ ++#define BFD_IS_RELAXABLE 0x200 ++ ++/* This may be set before writing out a BFD to request using a ++ traditional format. For example, this is used to request that when ++ writing out an a.out object the symbols not be hashed to eliminate ++ duplicates. */ ++#define BFD_TRADITIONAL_FORMAT 0x400 ++ ++/* This flag indicates that the BFD contents are actually cached in ++ memory. If this is set, iostream points to a bfd_in_memory struct. */ ++#define BFD_IN_MEMORY 0x800 ++ ++/* The sections in this BFD specify a memory page. */ ++#define HAS_LOAD_PAGE 0x1000 ++ ++/* This BFD has been created by the linker and doesn't correspond ++ to any input file. */ ++#define BFD_LINKER_CREATED 0x2000 ++ ++/* Symbols and relocation. */ ++ ++/* A count of carsyms (canonical archive symbols). */ ++typedef unsigned long symindex; ++ ++/* How to perform a relocation. */ ++typedef const struct reloc_howto_struct reloc_howto_type; ++ ++#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) ++ ++/* General purpose part of a symbol X; ++ target specific parts are in libcoff.h, libaout.h, etc. */ ++ ++#define bfd_get_section(x) ((x)->section) ++#define bfd_get_output_section(x) ((x)->section->output_section) ++#define bfd_set_section(x,y) ((x)->section) = (y) ++#define bfd_asymbol_base(x) ((x)->section->vma) ++#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) ++#define bfd_asymbol_name(x) ((x)->name) ++/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ ++#define bfd_asymbol_bfd(x) ((x)->the_bfd) ++#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) ++ ++/* A canonical archive symbol. */ ++/* This is a type pun with struct ranlib on purpose! */ ++typedef struct carsym ++{ ++ char *name; ++ file_ptr file_offset; /* Look here to find the file. */ ++} ++carsym; /* To make these you call a carsymogen. */ ++ ++/* Used in generating armaps (archive tables of contents). ++ Perhaps just a forward definition would do? */ ++struct orl /* Output ranlib. */ ++{ ++ char **name; /* Symbol name. */ ++ union ++ { ++ file_ptr pos; ++ bfd *abfd; ++ } u; /* bfd* or file position. */ ++ int namidx; /* Index into string table. */ ++}; ++ ++/* Linenumber stuff. */ ++typedef struct lineno_cache_entry ++{ ++ unsigned int line_number; /* Linenumber from start of function. */ ++ union ++ { ++ struct bfd_symbol *sym; /* Function name. */ ++ bfd_vma offset; /* Offset into section. */ ++ } u; ++} ++alent; ++ ++/* Object and core file sections. */ ++ ++#define align_power(addr, align) \ ++ (((addr) + ((bfd_vma) 1 << (align)) - 1) & ((bfd_vma) -1 << (align))) ++ ++typedef struct bfd_section *sec_ptr; ++ ++#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) ++#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) ++#define bfd_get_section_lma(bfd, ptr) ((ptr)->lma + 0) ++#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) ++#define bfd_section_name(bfd, ptr) ((ptr)->name) ++#define bfd_section_size(bfd, ptr) ((ptr)->size) ++#define bfd_get_section_size(ptr) ((ptr)->size) ++#define bfd_section_vma(bfd, ptr) ((ptr)->vma) ++#define bfd_section_lma(bfd, ptr) ((ptr)->lma) ++#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) ++#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) ++#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) ++ ++#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) ++ ++#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) ++#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) ++#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) ++/* Find the address one past the end of SEC. */ ++#define bfd_get_section_limit(bfd, sec) \ ++ (((sec)->rawsize ? (sec)->rawsize : (sec)->size) \ ++ / bfd_octets_per_byte (bfd)) ++ ++typedef struct stat stat_type; ++ ++typedef enum bfd_print_symbol ++{ ++ bfd_print_symbol_name, ++ bfd_print_symbol_more, ++ bfd_print_symbol_all ++} bfd_print_symbol_type; ++ ++/* Information about a symbol that nm needs. */ ++ ++typedef struct _symbol_info ++{ ++ symvalue value; ++ char type; ++ const char *name; /* Symbol name. */ ++ unsigned char stab_type; /* Stab type. */ ++ char stab_other; /* Stab other. */ ++ short stab_desc; /* Stab desc. */ ++ const char *stab_name; /* String for stab type. */ ++} symbol_info; ++ ++/* Get the name of a stabs type code. */ ++ ++extern const char *bfd_get_stab_name (int); ++ ++/* Hash table routines. There is no way to free up a hash table. */ ++ ++/* An element in the hash table. Most uses will actually use a larger ++ structure, and an instance of this will be the first field. */ ++ ++struct bfd_hash_entry ++{ ++ /* Next entry for this hash code. */ ++ struct bfd_hash_entry *next; ++ /* String being hashed. */ ++ const char *string; ++ /* Hash code. This is the full hash code, not the index into the ++ table. */ ++ unsigned long hash; ++}; ++ ++/* A hash table. */ ++ ++struct bfd_hash_table ++{ ++ /* The hash array. */ ++ struct bfd_hash_entry **table; ++ /* The number of slots in the hash table. */ ++ unsigned int size; ++ /* A function used to create new elements in the hash table. The ++ first entry is itself a pointer to an element. When this ++ function is first invoked, this pointer will be NULL. However, ++ having the pointer permits a hierarchy of method functions to be ++ built each of which calls the function in the superclass. Thus ++ each function should be written to allocate a new block of memory ++ only if the argument is NULL. */ ++ struct bfd_hash_entry *(*newfunc) ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++ /* An objalloc for this hash table. This is a struct objalloc *, ++ but we use void * to avoid requiring the inclusion of objalloc.h. */ ++ void *memory; ++}; ++ ++/* Initialize a hash table. */ ++extern bfd_boolean bfd_hash_table_init ++ (struct bfd_hash_table *, ++ struct bfd_hash_entry *(*) (struct bfd_hash_entry *, ++ struct bfd_hash_table *, ++ const char *)); ++ ++/* Initialize a hash table specifying a size. */ ++extern bfd_boolean bfd_hash_table_init_n ++ (struct bfd_hash_table *, ++ struct bfd_hash_entry *(*) (struct bfd_hash_entry *, ++ struct bfd_hash_table *, ++ const char *), ++ unsigned int size); ++ ++/* Free up a hash table. */ ++extern void bfd_hash_table_free ++ (struct bfd_hash_table *); ++ ++/* Look up a string in a hash table. If CREATE is TRUE, a new entry ++ will be created for this string if one does not already exist. The ++ COPY argument must be TRUE if this routine should copy the string ++ into newly allocated memory when adding an entry. */ ++extern struct bfd_hash_entry *bfd_hash_lookup ++ (struct bfd_hash_table *, const char *, bfd_boolean create, ++ bfd_boolean copy); ++ ++/* Replace an entry in a hash table. */ ++extern void bfd_hash_replace ++ (struct bfd_hash_table *, struct bfd_hash_entry *old, ++ struct bfd_hash_entry *nw); ++ ++/* Base method for creating a hash table entry. */ ++extern struct bfd_hash_entry *bfd_hash_newfunc ++ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); ++ ++/* Grab some space for a hash table entry. */ ++extern void *bfd_hash_allocate ++ (struct bfd_hash_table *, unsigned int); ++ ++/* Traverse a hash table in a random order, calling a function on each ++ element. If the function returns FALSE, the traversal stops. The ++ INFO argument is passed to the function. */ ++extern void bfd_hash_traverse ++ (struct bfd_hash_table *, ++ bfd_boolean (*) (struct bfd_hash_entry *, void *), ++ void *info); ++ ++/* Allows the default size of a hash table to be configured. New hash ++ tables allocated using bfd_hash_table_init will be created with ++ this size. */ ++extern void bfd_hash_set_default_size (bfd_size_type); ++ ++/* This structure is used to keep track of stabs in sections ++ information while linking. */ ++ ++struct stab_info ++{ ++ /* A hash table used to hold stabs strings. */ ++ struct bfd_strtab_hash *strings; ++ /* The header file hash table. */ ++ struct bfd_hash_table includes; ++ /* The first .stabstr section. */ ++ struct bfd_section *stabstr; ++}; ++ ++#define COFF_SWAP_TABLE (void *) &bfd_coff_std_swap_table ++ ++/* User program access to BFD facilities. */ ++ ++/* Direct I/O routines, for programs which know more about the object ++ file than BFD does. Use higher level routines if possible. */ ++ ++extern bfd_size_type bfd_bread (void *, bfd_size_type, bfd *); ++extern bfd_size_type bfd_bwrite (const void *, bfd_size_type, bfd *); ++extern int bfd_seek (bfd *, file_ptr, int); ++extern file_ptr bfd_tell (bfd *); ++extern int bfd_flush (bfd *); ++extern int bfd_stat (bfd *, struct stat *); ++ ++/* Deprecated old routines. */ ++#if __GNUC__ ++#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ ++ bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ ++ bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#else ++#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ ++ bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ ++ (warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ ++ bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) ++#endif ++extern void warn_deprecated (const char *, const char *, int, const char *); ++ ++/* Cast from const char * to char * so that caller can assign to ++ a char * without a warning. */ ++#define bfd_get_filename(abfd) ((char *) (abfd)->filename) ++#define bfd_get_cacheable(abfd) ((abfd)->cacheable) ++#define bfd_get_format(abfd) ((abfd)->format) ++#define bfd_get_target(abfd) ((abfd)->xvec->name) ++#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) ++#define bfd_family_coff(abfd) \ ++ (bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ ++ bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) ++#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) ++#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) ++#define bfd_header_big_endian(abfd) \ ++ ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) ++#define bfd_header_little_endian(abfd) \ ++ ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) ++#define bfd_get_file_flags(abfd) ((abfd)->flags) ++#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) ++#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) ++#define bfd_my_archive(abfd) ((abfd)->my_archive) ++#define bfd_has_map(abfd) ((abfd)->has_armap) ++ ++#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) ++#define bfd_usrdata(abfd) ((abfd)->usrdata) ++ ++#define bfd_get_start_address(abfd) ((abfd)->start_address) ++#define bfd_get_symcount(abfd) ((abfd)->symcount) ++#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) ++#define bfd_count_sections(abfd) ((abfd)->section_count) ++ ++#define bfd_get_dynamic_symcount(abfd) ((abfd)->dynsymcount) ++ ++#define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) ++ ++#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) ++ ++extern bfd_boolean bfd_cache_close ++ (bfd *abfd); ++/* NB: This declaration should match the autogenerated one in libbfd.h. */ ++ ++extern bfd_boolean bfd_cache_close_all (void); ++ ++extern bfd_boolean bfd_record_phdr ++ (bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, ++ bfd_boolean, bfd_boolean, unsigned int, struct bfd_section **); ++ ++/* Byte swapping routines. */ ++ ++bfd_uint64_t bfd_getb64 (const void *); ++bfd_uint64_t bfd_getl64 (const void *); ++bfd_int64_t bfd_getb_signed_64 (const void *); ++bfd_int64_t bfd_getl_signed_64 (const void *); ++bfd_vma bfd_getb32 (const void *); ++bfd_vma bfd_getl32 (const void *); ++bfd_signed_vma bfd_getb_signed_32 (const void *); ++bfd_signed_vma bfd_getl_signed_32 (const void *); ++bfd_vma bfd_getb16 (const void *); ++bfd_vma bfd_getl16 (const void *); ++bfd_signed_vma bfd_getb_signed_16 (const void *); ++bfd_signed_vma bfd_getl_signed_16 (const void *); ++void bfd_putb64 (bfd_uint64_t, void *); ++void bfd_putl64 (bfd_uint64_t, void *); ++void bfd_putb32 (bfd_vma, void *); ++void bfd_putl32 (bfd_vma, void *); ++void bfd_putb16 (bfd_vma, void *); ++void bfd_putl16 (bfd_vma, void *); ++ ++/* Byte swapping routines which take size and endiannes as arguments. */ ++ ++bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean); ++void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean); ++ ++extern bfd_boolean bfd_section_already_linked_table_init (void); ++extern void bfd_section_already_linked_table_free (void); ++ ++/* Externally visible ECOFF routines. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++struct ecoff_debug_info; ++struct ecoff_debug_swap; ++struct ecoff_extr; ++struct bfd_symbol; ++struct bfd_link_info; ++struct bfd_link_hash_entry; ++struct bfd_elf_version_tree; ++#endif ++extern bfd_vma bfd_ecoff_get_gp_value ++ (bfd * abfd); ++extern bfd_boolean bfd_ecoff_set_gp_value ++ (bfd *abfd, bfd_vma gp_value); ++extern bfd_boolean bfd_ecoff_set_regmasks ++ (bfd *abfd, unsigned long gprmask, unsigned long fprmask, ++ unsigned long *cprmask); ++extern void *bfd_ecoff_debug_init ++ (bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); ++extern void bfd_ecoff_debug_free ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_accumulate ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, bfd *input_bfd, ++ struct ecoff_debug_info *input_debug, ++ const struct ecoff_debug_swap *input_swap, struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_accumulate_other ++ (void *handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, ++ const struct ecoff_debug_swap *output_swap, bfd *input_bfd, ++ struct bfd_link_info *); ++extern bfd_boolean bfd_ecoff_debug_externals ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, bfd_boolean relocatable, ++ bfd_boolean (*get_extr) (struct bfd_symbol *, struct ecoff_extr *), ++ void (*set_index) (struct bfd_symbol *, bfd_size_type)); ++extern bfd_boolean bfd_ecoff_debug_one_external ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, const char *name, ++ struct ecoff_extr *esym); ++extern bfd_size_type bfd_ecoff_debug_size ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap); ++extern bfd_boolean bfd_ecoff_write_debug ++ (bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, file_ptr where); ++extern bfd_boolean bfd_ecoff_write_accumulated_debug ++ (void *handle, bfd *abfd, struct ecoff_debug_info *debug, ++ const struct ecoff_debug_swap *swap, ++ struct bfd_link_info *info, file_ptr where); ++ ++/* Externally visible ELF routines. */ ++ ++struct bfd_link_needed_list ++{ ++ struct bfd_link_needed_list *next; ++ bfd *by; ++ const char *name; ++}; ++ ++enum dynamic_lib_link_class { ++ DYN_NORMAL = 0, ++ DYN_AS_NEEDED = 1, ++ DYN_DT_NEEDED = 2, ++ DYN_NO_ADD_NEEDED = 4, ++ DYN_NO_NEEDED = 8 ++}; ++ ++extern bfd_boolean bfd_elf_record_link_assignment ++ (struct bfd_link_info *, const char *, bfd_boolean); ++extern struct bfd_link_needed_list *bfd_elf_get_needed_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_get_bfd_needed_list ++ (bfd *, struct bfd_link_needed_list **); ++extern bfd_boolean bfd_elf_size_dynamic_sections ++ (bfd *, const char *, const char *, const char *, const char * const *, ++ struct bfd_link_info *, struct bfd_section **, ++ struct bfd_elf_version_tree *); ++extern bfd_boolean bfd_elf_size_dynsym_hash_dynstr ++ (bfd *, struct bfd_link_info *); ++extern void bfd_elf_set_dt_needed_name ++ (bfd *, const char *); ++extern const char *bfd_elf_get_dt_soname ++ (bfd *); ++extern void bfd_elf_set_dyn_lib_class ++ (bfd *, int); ++extern int bfd_elf_get_dyn_lib_class ++ (bfd *); ++extern struct bfd_link_needed_list *bfd_elf_get_runpath_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_elf_discard_info ++ (bfd *, struct bfd_link_info *); ++extern unsigned int _bfd_elf_default_action_discarded ++ (struct bfd_section *); ++ ++/* Return an upper bound on the number of bytes required to store a ++ copy of ABFD's program header table entries. Return -1 if an error ++ occurs; bfd_get_error will return an appropriate code. */ ++extern long bfd_get_elf_phdr_upper_bound ++ (bfd *abfd); ++ ++/* Copy ABFD's program header table entries to *PHDRS. The entries ++ will be stored as an array of Elf_Internal_Phdr structures, as ++ defined in include/elf/internal.h. To find out how large the ++ buffer needs to be, call bfd_get_elf_phdr_upper_bound. ++ ++ Return the number of program header table entries read, or -1 if an ++ error occurs; bfd_get_error will return an appropriate code. */ ++extern int bfd_get_elf_phdrs ++ (bfd *abfd, void *phdrs); ++ ++/* Create a new BFD as if by bfd_openr. Rather than opening a file, ++ reconstruct an ELF file by reading the segments out of remote memory ++ based on the ELF file header at EHDR_VMA and the ELF program headers it ++ points to. If not null, *LOADBASEP is filled in with the difference ++ between the VMAs from which the segments were read, and the VMAs the ++ file headers (and hence BFD's idea of each section's VMA) put them at. ++ ++ The function TARGET_READ_MEMORY is called to copy LEN bytes from the ++ remote memory at target address VMA into the local buffer at MYADDR; it ++ should return zero on success or an `errno' code on failure. TEMPL must ++ be a BFD for an ELF target with the word size and byte order found in ++ the remote memory. */ ++extern bfd *bfd_elf_bfd_from_remote_memory ++ (bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep, ++ int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, int len)); ++ ++/* Return the arch_size field of an elf bfd, or -1 if not elf. */ ++extern int bfd_get_arch_size ++ (bfd *); ++ ++/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ ++extern int bfd_get_sign_extend_vma ++ (bfd *); ++ ++extern struct bfd_section *_bfd_elf_tls_setup ++ (bfd *, struct bfd_link_info *); ++ ++extern void _bfd_elf_provide_symbol ++ (struct bfd_link_info *, const char *, bfd_vma, struct bfd_section *); ++ ++extern void _bfd_elf_provide_section_bound_symbols ++ (struct bfd_link_info *, struct bfd_section *, const char *, const char *); ++ ++extern void _bfd_elf_fix_excluded_sec_syms ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, ++ char **); ++ ++/* SunOS shared library support routines for the linker. */ ++ ++extern struct bfd_link_needed_list *bfd_sunos_get_needed_list ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_sunos_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_sunos_size_dynamic_sections ++ (bfd *, struct bfd_link_info *, struct bfd_section **, ++ struct bfd_section **, struct bfd_section **); ++ ++/* Linux shared library support routines for the linker. */ ++ ++extern bfd_boolean bfd_i386linux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_m68klinux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++extern bfd_boolean bfd_sparclinux_size_dynamic_sections ++ (bfd *, struct bfd_link_info *); ++ ++/* mmap hacks */ ++ ++struct _bfd_window_internal; ++typedef struct _bfd_window_internal bfd_window_internal; ++ ++typedef struct _bfd_window ++{ ++ /* What the user asked for. */ ++ void *data; ++ bfd_size_type size; ++ /* The actual window used by BFD. Small user-requested read-only ++ regions sharing a page may share a single window into the object ++ file. Read-write versions shouldn't until I've fixed things to ++ keep track of which portions have been claimed by the ++ application; don't want to give the same region back when the ++ application wants two writable copies! */ ++ struct _bfd_window_internal *i; ++} ++bfd_window; ++ ++extern void bfd_init_window ++ (bfd_window *); ++extern void bfd_free_window ++ (bfd_window *); ++extern bfd_boolean bfd_get_file_window ++ (bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean); ++ ++/* XCOFF support routines for the linker. */ ++ ++extern bfd_boolean bfd_xcoff_link_record_set ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type); ++extern bfd_boolean bfd_xcoff_import_symbol ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_vma, ++ const char *, const char *, const char *, unsigned int); ++extern bfd_boolean bfd_xcoff_export_symbol ++ (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); ++extern bfd_boolean bfd_xcoff_link_count_reloc ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_xcoff_record_link_assignment ++ (bfd *, struct bfd_link_info *, const char *); ++extern bfd_boolean bfd_xcoff_size_dynamic_sections ++ (bfd *, struct bfd_link_info *, const char *, const char *, ++ unsigned long, unsigned long, unsigned long, bfd_boolean, ++ int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean); ++extern bfd_boolean bfd_xcoff_link_generate_rtinit ++ (bfd *, const char *, const char *, bfd_boolean); ++ ++/* XCOFF support routines for ar. */ ++extern bfd_boolean bfd_xcoff_ar_archive_set_magic ++ (bfd *, char *); ++ ++/* Externally visible COFF routines. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++struct internal_syment; ++union internal_auxent; ++#endif ++ ++extern bfd_boolean bfd_coff_get_syment ++ (bfd *, struct bfd_symbol *, struct internal_syment *); ++ ++extern bfd_boolean bfd_coff_get_auxent ++ (bfd *, struct bfd_symbol *, int, union internal_auxent *); ++ ++extern bfd_boolean bfd_coff_set_symbol_class ++ (bfd *, struct bfd_symbol *, unsigned int); ++ ++extern bfd_boolean bfd_m68k_coff_create_embedded_relocs ++ (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); ++ ++/* ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_arm_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_arm_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++extern bfd_boolean bfd_arm_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++/* PE ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_arm_pe_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_arm_pe_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++/* ELF ARM Interworking support. Called from linker. */ ++extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections ++ (struct bfd_link_info *); ++ ++extern bfd_boolean bfd_elf32_arm_process_before_allocation ++ (bfd *, struct bfd_link_info *, int); ++ ++void bfd_elf32_arm_set_target_relocs ++ (struct bfd_link_info *, int, char *, int, int); ++ ++extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking ++ (bfd *, struct bfd_link_info *); ++ ++extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd ++ (bfd *, struct bfd_link_info *); ++ ++/* ELF ARM mapping symbol support */ ++extern bfd_boolean bfd_is_arm_mapping_symbol_name ++ (const char * name); ++ ++/* ARM Note section processing. */ ++extern bfd_boolean bfd_arm_merge_machines ++ (bfd *, bfd *); ++ ++extern bfd_boolean bfd_arm_update_notes ++ (bfd *, const char *); ++ ++extern unsigned int bfd_arm_get_mach_from_notes ++ (bfd *, const char *); ++ ++/* TI COFF load page support. */ ++extern void bfd_ticoff_set_section_load_page ++ (struct bfd_section *, int); ++ ++extern int bfd_ticoff_get_section_load_page ++ (struct bfd_section *); ++ ++/* H8/300 functions. */ ++extern bfd_vma bfd_h8300_pad_address ++ (bfd *, bfd_vma); ++ ++/* IA64 Itanium code generation. Called from linker. */ ++extern void bfd_elf32_ia64_after_parse ++ (int); ++ ++extern void bfd_elf64_ia64_after_parse ++ (int); ++ ++/* This structure is used for a comdat section, as in PE. A comdat ++ section is associated with a particular symbol. When the linker ++ sees a comdat section, it keeps only one of the sections with a ++ given name and associated with a given symbol. */ ++ ++struct coff_comdat_info ++{ ++ /* The name of the symbol associated with a comdat section. */ ++ const char *name; ++ ++ /* The local symbol table index of the symbol associated with a ++ comdat section. This is only meaningful to the object file format ++ specific code; it is not an index into the list returned by ++ bfd_canonicalize_symtab. */ ++ long symbol; ++}; ++ ++extern struct coff_comdat_info *bfd_coff_get_comdat_section ++ (bfd *, struct bfd_section *); ++ ++/* Extracted from init.c. */ ++void bfd_init (void); ++ ++/* Extracted from opncls.c. */ ++bfd *bfd_fopen (const char *filename, const char *target, ++ const char *mode, int fd); ++ ++bfd *bfd_openr (const char *filename, const char *target); ++ ++bfd *bfd_fdopenr (const char *filename, const char *target, int fd); ++ ++bfd *bfd_openstreamr (const char *, const char *, void *); ++ ++bfd *bfd_openr_iovec (const char *filename, const char *target, ++ void *(*open) (struct bfd *nbfd, ++ void *open_closure), ++ void *open_closure, ++ file_ptr (*pread) (struct bfd *nbfd, ++ void *stream, ++ void *buf, ++ file_ptr nbytes, ++ file_ptr offset), ++ int (*close) (struct bfd *nbfd, ++ void *stream)); ++ ++bfd *bfd_openw (const char *filename, const char *target); ++ ++bfd_boolean bfd_close (bfd *abfd); ++ ++bfd_boolean bfd_close_all_done (bfd *); ++ ++bfd *bfd_create (const char *filename, bfd *templ); ++ ++bfd_boolean bfd_make_writable (bfd *abfd); ++ ++bfd_boolean bfd_make_readable (bfd *abfd); ++ ++unsigned long bfd_calc_gnu_debuglink_crc32 ++ (unsigned long crc, const unsigned char *buf, bfd_size_type len); ++ ++char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); ++ ++struct bfd_section *bfd_create_gnu_debuglink_section ++ (bfd *abfd, const char *filename); ++ ++bfd_boolean bfd_fill_in_gnu_debuglink_section ++ (bfd *abfd, struct bfd_section *sect, const char *filename); ++ ++/* Extracted from libbfd.c. */ ++ ++/* Byte swapping macros for user section data. */ ++ ++#define bfd_put_8(abfd, val, ptr) \ ++ ((void) (*((unsigned char *) (ptr)) = (val) & 0xff)) ++#define bfd_put_signed_8 \ ++ bfd_put_8 ++#define bfd_get_8(abfd, ptr) \ ++ (*(unsigned char *) (ptr) & 0xff) ++#define bfd_get_signed_8(abfd, ptr) \ ++ (((*(unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) ++ ++#define bfd_put_16(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx16, ((val),(ptr))) ++#define bfd_put_signed_16 \ ++ bfd_put_16 ++#define bfd_get_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx16, (ptr)) ++#define bfd_get_signed_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) ++ ++#define bfd_put_32(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx32, ((val),(ptr))) ++#define bfd_put_signed_32 \ ++ bfd_put_32 ++#define bfd_get_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx32, (ptr)) ++#define bfd_get_signed_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_32, (ptr)) ++ ++#define bfd_put_64(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_putx64, ((val), (ptr))) ++#define bfd_put_signed_64 \ ++ bfd_put_64 ++#define bfd_get_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx64, (ptr)) ++#define bfd_get_signed_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_getx_signed_64, (ptr)) ++ ++#define bfd_get(bits, abfd, ptr) \ ++ ((bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ ++ : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ ++ : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ ++ : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ ++ : (abort (), (bfd_vma) - 1)) ++ ++#define bfd_put(bits, abfd, val, ptr) \ ++ ((bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ ++ : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ ++ : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ ++ : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ ++ : (abort (), (void) 0)) ++ ++ ++/* Byte swapping macros for file header data. */ ++ ++#define bfd_h_put_8(abfd, val, ptr) \ ++ bfd_put_8 (abfd, val, ptr) ++#define bfd_h_put_signed_8(abfd, val, ptr) \ ++ bfd_put_8 (abfd, val, ptr) ++#define bfd_h_get_8(abfd, ptr) \ ++ bfd_get_8 (abfd, ptr) ++#define bfd_h_get_signed_8(abfd, ptr) \ ++ bfd_get_signed_8 (abfd, ptr) ++ ++#define bfd_h_put_16(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) ++#define bfd_h_put_signed_16 \ ++ bfd_h_put_16 ++#define bfd_h_get_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx16, (ptr)) ++#define bfd_h_get_signed_16(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) ++ ++#define bfd_h_put_32(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) ++#define bfd_h_put_signed_32 \ ++ bfd_h_put_32 ++#define bfd_h_get_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx32, (ptr)) ++#define bfd_h_get_signed_32(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) ++ ++#define bfd_h_put_64(abfd, val, ptr) \ ++ BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) ++#define bfd_h_put_signed_64 \ ++ bfd_h_put_64 ++#define bfd_h_get_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx64, (ptr)) ++#define bfd_h_get_signed_64(abfd, ptr) \ ++ BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) ++ ++/* Aliases for the above, which should eventually go away. */ ++ ++#define H_PUT_64 bfd_h_put_64 ++#define H_PUT_32 bfd_h_put_32 ++#define H_PUT_16 bfd_h_put_16 ++#define H_PUT_8 bfd_h_put_8 ++#define H_PUT_S64 bfd_h_put_signed_64 ++#define H_PUT_S32 bfd_h_put_signed_32 ++#define H_PUT_S16 bfd_h_put_signed_16 ++#define H_PUT_S8 bfd_h_put_signed_8 ++#define H_GET_64 bfd_h_get_64 ++#define H_GET_32 bfd_h_get_32 ++#define H_GET_16 bfd_h_get_16 ++#define H_GET_8 bfd_h_get_8 ++#define H_GET_S64 bfd_h_get_signed_64 ++#define H_GET_S32 bfd_h_get_signed_32 ++#define H_GET_S16 bfd_h_get_signed_16 ++#define H_GET_S8 bfd_h_get_signed_8 ++ ++ ++/* Extracted from bfdio.c. */ ++long bfd_get_mtime (bfd *abfd); ++ ++long bfd_get_size (bfd *abfd); ++ ++/* Extracted from bfdwin.c. */ ++/* Extracted from section.c. */ ++typedef struct bfd_section ++{ ++ /* The name of the section; the name isn't a copy, the pointer is ++ the same as that passed to bfd_make_section. */ ++ const char *name; ++ ++ /* A unique sequence number. */ ++ int id; ++ ++ /* Which section in the bfd; 0..n-1 as sections are created in a bfd. */ ++ int index; ++ ++ /* The next section in the list belonging to the BFD, or NULL. */ ++ struct bfd_section *next; ++ ++ /* The previous section in the list belonging to the BFD, or NULL. */ ++ struct bfd_section *prev; ++ ++ /* The field flags contains attributes of the section. Some ++ flags are read in from the object file, and some are ++ synthesized from other information. */ ++ flagword flags; ++ ++#define SEC_NO_FLAGS 0x000 ++ ++ /* Tells the OS to allocate space for this section when loading. ++ This is clear for a section containing debug information only. */ ++#define SEC_ALLOC 0x001 ++ ++ /* Tells the OS to load the section from the file when loading. ++ This is clear for a .bss section. */ ++#define SEC_LOAD 0x002 ++ ++ /* The section contains data still to be relocated, so there is ++ some relocation information too. */ ++#define SEC_RELOC 0x004 ++ ++ /* A signal to the OS that the section contains read only data. */ ++#define SEC_READONLY 0x008 ++ ++ /* The section contains code only. */ ++#define SEC_CODE 0x010 ++ ++ /* The section contains data only. */ ++#define SEC_DATA 0x020 ++ ++ /* The section will reside in ROM. */ ++#define SEC_ROM 0x040 ++ ++ /* The section contains constructor information. This section ++ type is used by the linker to create lists of constructors and ++ destructors used by <>. When a back end sees a symbol ++ which should be used in a constructor list, it creates a new ++ section for the type of name (e.g., <<__CTOR_LIST__>>), attaches ++ the symbol to it, and builds a relocation. To build the lists ++ of constructors, all the linker has to do is catenate all the ++ sections called <<__CTOR_LIST__>> and relocate the data ++ contained within - exactly the operations it would peform on ++ standard data. */ ++#define SEC_CONSTRUCTOR 0x080 ++ ++ /* The section has contents - a data section could be ++ <> | <>; a debug section could be ++ <> */ ++#define SEC_HAS_CONTENTS 0x100 ++ ++ /* An instruction to the linker to not output the section ++ even if it has information which would normally be written. */ ++#define SEC_NEVER_LOAD 0x200 ++ ++ /* The section contains thread local data. */ ++#define SEC_THREAD_LOCAL 0x400 ++ ++ /* The section has GOT references. This flag is only for the ++ linker, and is currently only used by the elf32-hppa back end. ++ It will be set if global offset table references were detected ++ in this section, which indicate to the linker that the section ++ contains PIC code, and must be handled specially when doing a ++ static link. */ ++#define SEC_HAS_GOT_REF 0x800 ++ ++ /* The section contains common symbols (symbols may be defined ++ multiple times, the value of a symbol is the amount of ++ space it requires, and the largest symbol value is the one ++ used). Most targets have exactly one of these (which we ++ translate to bfd_com_section_ptr), but ECOFF has two. */ ++#define SEC_IS_COMMON 0x1000 ++ ++ /* The section contains only debugging information. For ++ example, this is set for ELF .debug and .stab sections. ++ strip tests this flag to see if a section can be ++ discarded. */ ++#define SEC_DEBUGGING 0x2000 ++ ++ /* The contents of this section are held in memory pointed to ++ by the contents field. This is checked by bfd_get_section_contents, ++ and the data is retrieved from memory if appropriate. */ ++#define SEC_IN_MEMORY 0x4000 ++ ++ /* The contents of this section are to be excluded by the ++ linker for executable and shared objects unless those ++ objects are to be further relocated. */ ++#define SEC_EXCLUDE 0x8000 ++ ++ /* The contents of this section are to be sorted based on the sum of ++ the symbol and addend values specified by the associated relocation ++ entries. Entries without associated relocation entries will be ++ appended to the end of the section in an unspecified order. */ ++#define SEC_SORT_ENTRIES 0x10000 ++ ++ /* When linking, duplicate sections of the same name should be ++ discarded, rather than being combined into a single section as ++ is usually done. This is similar to how common symbols are ++ handled. See SEC_LINK_DUPLICATES below. */ ++#define SEC_LINK_ONCE 0x20000 ++ ++ /* If SEC_LINK_ONCE is set, this bitfield describes how the linker ++ should handle duplicate sections. */ ++#define SEC_LINK_DUPLICATES 0x40000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that duplicate ++ sections with the same name should simply be discarded. */ ++#define SEC_LINK_DUPLICATES_DISCARD 0x0 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if there are any duplicate sections, although ++ it should still only link one copy. */ ++#define SEC_LINK_DUPLICATES_ONE_ONLY 0x80000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if any duplicate sections are a different size. */ ++#define SEC_LINK_DUPLICATES_SAME_SIZE 0x100000 ++ ++ /* This value for SEC_LINK_DUPLICATES means that the linker ++ should warn if any duplicate sections contain different ++ contents. */ ++#define SEC_LINK_DUPLICATES_SAME_CONTENTS \ ++ (SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE) ++ ++ /* This section was created by the linker as part of dynamic ++ relocation or other arcane processing. It is skipped when ++ going through the first-pass output, trusting that someone ++ else up the line will take care of it later. */ ++#define SEC_LINKER_CREATED 0x200000 ++ ++ /* This section should not be subject to garbage collection. */ ++#define SEC_KEEP 0x400000 ++ ++ /* This section contains "short" data, and should be placed ++ "near" the GP. */ ++#define SEC_SMALL_DATA 0x800000 ++ ++ /* Attempt to merge identical entities in the section. ++ Entity size is given in the entsize field. */ ++#define SEC_MERGE 0x1000000 ++ ++ /* If given with SEC_MERGE, entities to merge are zero terminated ++ strings where entsize specifies character size instead of fixed ++ size entries. */ ++#define SEC_STRINGS 0x2000000 ++ ++ /* This section contains data about section groups. */ ++#define SEC_GROUP 0x4000000 ++ ++ /* The section is a COFF shared library section. This flag is ++ only for the linker. If this type of section appears in ++ the input file, the linker must copy it to the output file ++ without changing the vma or size. FIXME: Although this ++ was originally intended to be general, it really is COFF ++ specific (and the flag was renamed to indicate this). It ++ might be cleaner to have some more general mechanism to ++ allow the back end to control what the linker does with ++ sections. */ ++#define SEC_COFF_SHARED_LIBRARY 0x10000000 ++ ++ /* This section contains data which may be shared with other ++ executables or shared objects. This is for COFF only. */ ++#define SEC_COFF_SHARED 0x20000000 ++ ++ /* When a section with this flag is being linked, then if the size of ++ the input section is less than a page, it should not cross a page ++ boundary. If the size of the input section is one page or more, ++ it should be aligned on a page boundary. This is for TI ++ TMS320C54X only. */ ++#define SEC_TIC54X_BLOCK 0x40000000 ++ ++ /* Conditionally link this section; do not link if there are no ++ references found to any symbol in the section. This is for TI ++ TMS320C54X only. */ ++#define SEC_TIC54X_CLINK 0x80000000 ++ ++ /* End of section flags. */ ++ ++ /* Some internal packed boolean fields. */ ++ ++ /* See the vma field. */ ++ unsigned int user_set_vma : 1; ++ ++ /* A mark flag used by some of the linker backends. */ ++ unsigned int linker_mark : 1; ++ ++ /* Another mark flag used by some of the linker backends. Set for ++ output sections that have an input section. */ ++ unsigned int linker_has_input : 1; ++ ++ /* Mark flags used by some linker backends for garbage collection. */ ++ unsigned int gc_mark : 1; ++ unsigned int gc_mark_from_eh : 1; ++ ++ /* The following flags are used by the ELF linker. */ ++ ++ /* Mark sections which have been allocated to segments. */ ++ unsigned int segment_mark : 1; ++ ++ /* Type of sec_info information. */ ++ unsigned int sec_info_type:3; ++#define ELF_INFO_TYPE_NONE 0 ++#define ELF_INFO_TYPE_STABS 1 ++#define ELF_INFO_TYPE_MERGE 2 ++#define ELF_INFO_TYPE_EH_FRAME 3 ++#define ELF_INFO_TYPE_JUST_SYMS 4 ++ ++ /* Nonzero if this section uses RELA relocations, rather than REL. */ ++ unsigned int use_rela_p:1; ++ ++ /* Bits used by various backends. The generic code doesn't touch ++ these fields. */ ++ ++ /* Nonzero if this section has TLS related relocations. */ ++ unsigned int has_tls_reloc:1; ++ ++ /* Nonzero if this section has a gp reloc. */ ++ unsigned int has_gp_reloc:1; ++ ++ /* Nonzero if this section needs the relax finalize pass. */ ++ unsigned int need_finalize_relax:1; ++ ++ /* Whether relocations have been processed. */ ++ unsigned int reloc_done : 1; ++ ++ /* End of internal packed boolean fields. */ ++ ++ /* The virtual memory address of the section - where it will be ++ at run time. The symbols are relocated against this. The ++ user_set_vma flag is maintained by bfd; if it's not set, the ++ backend can assign addresses (for example, in <>, where ++ the default address for <<.data>> is dependent on the specific ++ target and various flags). */ ++ bfd_vma vma; ++ ++ /* The load address of the section - where it would be in a ++ rom image; really only used for writing section header ++ information. */ ++ bfd_vma lma; ++ ++ /* The size of the section in octets, as it will be output. ++ Contains a value even if the section has no contents (e.g., the ++ size of <<.bss>>). */ ++ bfd_size_type size; ++ ++ /* For input sections, the original size on disk of the section, in ++ octets. This field is used by the linker relaxation code. It is ++ currently only set for sections where the linker relaxation scheme ++ doesn't cache altered section and reloc contents (stabs, eh_frame, ++ SEC_MERGE, some coff relaxing targets), and thus the original size ++ needs to be kept to read the section multiple times. ++ For output sections, rawsize holds the section size calculated on ++ a previous linker relaxation pass. */ ++ bfd_size_type rawsize; ++ ++ /* If this section is going to be output, then this value is the ++ offset in *bytes* into the output section of the first byte in the ++ input section (byte ==> smallest addressable unit on the ++ target). In most cases, if this was going to start at the ++ 100th octet (8-bit quantity) in the output section, this value ++ would be 100. However, if the target byte size is 16 bits ++ (bfd_octets_per_byte is "2"), this value would be 50. */ ++ bfd_vma output_offset; ++ ++ /* The output section through which to map on output. */ ++ struct bfd_section *output_section; ++ ++ /* The alignment requirement of the section, as an exponent of 2 - ++ e.g., 3 aligns to 2^3 (or 8). */ ++ unsigned int alignment_power; ++ ++ /* If an input section, a pointer to a vector of relocation ++ records for the data in this section. */ ++ struct reloc_cache_entry *relocation; ++ ++ /* If an output section, a pointer to a vector of pointers to ++ relocation records for the data in this section. */ ++ struct reloc_cache_entry **orelocation; ++ ++ /* The number of relocation records in one of the above. */ ++ unsigned reloc_count; ++ ++ /* Information below is back end specific - and not always used ++ or updated. */ ++ ++ /* File position of section data. */ ++ file_ptr filepos; ++ ++ /* File position of relocation info. */ ++ file_ptr rel_filepos; ++ ++ /* File position of line data. */ ++ file_ptr line_filepos; ++ ++ /* Pointer to data for applications. */ ++ void *userdata; ++ ++ /* If the SEC_IN_MEMORY flag is set, this points to the actual ++ contents. */ ++ unsigned char *contents; ++ ++ /* Attached line number information. */ ++ alent *lineno; ++ ++ /* Number of line number records. */ ++ unsigned int lineno_count; ++ ++ /* Entity size for merging purposes. */ ++ unsigned int entsize; ++ ++ /* Points to the kept section if this section is a link-once section, ++ and is discarded. */ ++ struct bfd_section *kept_section; ++ ++ /* When a section is being output, this value changes as more ++ linenumbers are written out. */ ++ file_ptr moving_line_filepos; ++ ++ /* What the section number is in the target world. */ ++ int target_index; ++ ++ void *used_by_bfd; ++ ++ /* If this is a constructor section then here is a list of the ++ relocations created to relocate items within it. */ ++ struct relent_chain *constructor_chain; ++ ++ /* The BFD which owns the section. */ ++ bfd *owner; ++ ++ /* A symbol which points at this section only. */ ++ struct bfd_symbol *symbol; ++ struct bfd_symbol **symbol_ptr_ptr; ++ ++ /* Early in the link process, map_head and map_tail are used to build ++ a list of input sections attached to an output section. Later, ++ output sections use these fields for a list of bfd_link_order ++ structs. */ ++ union { ++ struct bfd_link_order *link_order; ++ struct bfd_section *s; ++ } map_head, map_tail; ++} asection; ++ ++/* These sections are global, and are managed by BFD. The application ++ and target back end are not permitted to change the values in ++ these sections. New code should use the section_ptr macros rather ++ than referring directly to the const sections. The const sections ++ may eventually vanish. */ ++#define BFD_ABS_SECTION_NAME "*ABS*" ++#define BFD_UND_SECTION_NAME "*UND*" ++#define BFD_COM_SECTION_NAME "*COM*" ++#define BFD_IND_SECTION_NAME "*IND*" ++ ++/* The absolute section. */ ++extern asection bfd_abs_section; ++#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) ++#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) ++/* Pointer to the undefined section. */ ++extern asection bfd_und_section; ++#define bfd_und_section_ptr ((asection *) &bfd_und_section) ++#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) ++/* Pointer to the common section. */ ++extern asection bfd_com_section; ++#define bfd_com_section_ptr ((asection *) &bfd_com_section) ++/* Pointer to the indirect section. */ ++extern asection bfd_ind_section; ++#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) ++#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) ++ ++#define bfd_is_const_section(SEC) \ ++ ( ((SEC) == bfd_abs_section_ptr) \ ++ || ((SEC) == bfd_und_section_ptr) \ ++ || ((SEC) == bfd_com_section_ptr) \ ++ || ((SEC) == bfd_ind_section_ptr)) ++ ++extern const struct bfd_symbol * const bfd_abs_symbol; ++extern const struct bfd_symbol * const bfd_com_symbol; ++extern const struct bfd_symbol * const bfd_und_symbol; ++extern const struct bfd_symbol * const bfd_ind_symbol; ++ ++/* Macros to handle insertion and deletion of a bfd's sections. These ++ only handle the list pointers, ie. do not adjust section_count, ++ target_index etc. */ ++#define bfd_section_list_remove(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ asection *_next = _s->next; \ ++ asection *_prev = _s->prev; \ ++ if (_prev) \ ++ _prev->next = _next; \ ++ else \ ++ (ABFD)->sections = _next; \ ++ if (_next) \ ++ _next->prev = _prev; \ ++ else \ ++ (ABFD)->section_last = _prev; \ ++ } \ ++ while (0) ++#define bfd_section_list_append(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ bfd *_abfd = ABFD; \ ++ _s->next = NULL; \ ++ if (_abfd->section_last) \ ++ { \ ++ _s->prev = _abfd->section_last; \ ++ _abfd->section_last->next = _s; \ ++ } \ ++ else \ ++ { \ ++ _s->prev = NULL; \ ++ _abfd->sections = _s; \ ++ } \ ++ _abfd->section_last = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_prepend(ABFD, S) \ ++ do \ ++ { \ ++ asection *_s = S; \ ++ bfd *_abfd = ABFD; \ ++ _s->prev = NULL; \ ++ if (_abfd->sections) \ ++ { \ ++ _s->next = _abfd->sections; \ ++ _abfd->sections->prev = _s; \ ++ } \ ++ else \ ++ { \ ++ _s->next = NULL; \ ++ _abfd->section_last = _s; \ ++ } \ ++ _abfd->sections = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_insert_after(ABFD, A, S) \ ++ do \ ++ { \ ++ asection *_a = A; \ ++ asection *_s = S; \ ++ asection *_next = _a->next; \ ++ _s->next = _next; \ ++ _s->prev = _a; \ ++ _a->next = _s; \ ++ if (_next) \ ++ _next->prev = _s; \ ++ else \ ++ (ABFD)->section_last = _s; \ ++ } \ ++ while (0) ++#define bfd_section_list_insert_before(ABFD, B, S) \ ++ do \ ++ { \ ++ asection *_b = B; \ ++ asection *_s = S; \ ++ asection *_prev = _b->prev; \ ++ _s->prev = _prev; \ ++ _s->next = _b; \ ++ _b->prev = _s; \ ++ if (_prev) \ ++ _prev->next = _s; \ ++ else \ ++ (ABFD)->sections = _s; \ ++ } \ ++ while (0) ++#define bfd_section_removed_from_list(ABFD, S) \ ++ ((S)->next == NULL ? (ABFD)->section_last != (S) : (S)->next->prev != (S)) ++ ++void bfd_section_list_clear (bfd *); ++ ++asection *bfd_get_section_by_name (bfd *abfd, const char *name); ++ ++asection *bfd_get_section_by_name_if ++ (bfd *abfd, ++ const char *name, ++ bfd_boolean (*func) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++char *bfd_get_unique_section_name ++ (bfd *abfd, const char *templat, int *count); ++ ++asection *bfd_make_section_old_way (bfd *abfd, const char *name); ++ ++asection *bfd_make_section_anyway_with_flags ++ (bfd *abfd, const char *name, flagword flags); ++ ++asection *bfd_make_section_anyway (bfd *abfd, const char *name); ++ ++asection *bfd_make_section_with_flags ++ (bfd *, const char *name, flagword flags); ++ ++asection *bfd_make_section (bfd *, const char *name); ++ ++bfd_boolean bfd_set_section_flags ++ (bfd *abfd, asection *sec, flagword flags); ++ ++void bfd_map_over_sections ++ (bfd *abfd, ++ void (*func) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++asection *bfd_sections_find_if ++ (bfd *abfd, ++ bfd_boolean (*operation) (bfd *abfd, asection *sect, void *obj), ++ void *obj); ++ ++bfd_boolean bfd_set_section_size ++ (bfd *abfd, asection *sec, bfd_size_type val); ++ ++bfd_boolean bfd_set_section_contents ++ (bfd *abfd, asection *section, const void *data, ++ file_ptr offset, bfd_size_type count); ++ ++bfd_boolean bfd_get_section_contents ++ (bfd *abfd, asection *section, void *location, file_ptr offset, ++ bfd_size_type count); ++ ++bfd_boolean bfd_malloc_and_get_section ++ (bfd *abfd, asection *section, bfd_byte **buf); ++ ++bfd_boolean bfd_copy_private_section_data ++ (bfd *ibfd, asection *isec, bfd *obfd, asection *osec); ++ ++#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ ++ BFD_SEND (obfd, _bfd_copy_private_section_data, \ ++ (ibfd, isection, obfd, osection)) ++bfd_boolean bfd_generic_is_group_section (bfd *, const asection *sec); ++ ++bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); ++ ++/* Extracted from archures.c. */ ++enum bfd_architecture ++{ ++ bfd_arch_unknown, /* File arch not known. */ ++ bfd_arch_obscure, /* Arch known, not one of these. */ ++ bfd_arch_m68k, /* Motorola 68xxx */ ++#define bfd_mach_m68000 1 ++#define bfd_mach_m68008 2 ++#define bfd_mach_m68010 3 ++#define bfd_mach_m68020 4 ++#define bfd_mach_m68030 5 ++#define bfd_mach_m68040 6 ++#define bfd_mach_m68060 7 ++#define bfd_mach_cpu32 8 ++#define bfd_mach_mcf5200 9 ++#define bfd_mach_mcf5206e 10 ++#define bfd_mach_mcf5307 11 ++#define bfd_mach_mcf5407 12 ++#define bfd_mach_mcf528x 13 ++#define bfd_mach_mcfv4e 14 ++#define bfd_mach_mcf521x 15 ++#define bfd_mach_mcf5249 16 ++#define bfd_mach_mcf547x 17 ++#define bfd_mach_mcf548x 18 ++ bfd_arch_vax, /* DEC Vax */ ++ bfd_arch_i960, /* Intel 960 */ ++ /* The order of the following is important. ++ lower number indicates a machine type that ++ only accepts a subset of the instructions ++ available to machines with higher numbers. ++ The exception is the "ca", which is ++ incompatible with all other machines except ++ "core". */ ++ ++#define bfd_mach_i960_core 1 ++#define bfd_mach_i960_ka_sa 2 ++#define bfd_mach_i960_kb_sb 3 ++#define bfd_mach_i960_mc 4 ++#define bfd_mach_i960_xa 5 ++#define bfd_mach_i960_ca 6 ++#define bfd_mach_i960_jx 7 ++#define bfd_mach_i960_hx 8 ++ ++ bfd_arch_or32, /* OpenRISC 32 */ ++ ++ bfd_arch_a29k, /* AMD 29000 */ ++ bfd_arch_sparc, /* SPARC */ ++#define bfd_mach_sparc 1 ++/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ ++#define bfd_mach_sparc_sparclet 2 ++#define bfd_mach_sparc_sparclite 3 ++#define bfd_mach_sparc_v8plus 4 ++#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ ++#define bfd_mach_sparc_sparclite_le 6 ++#define bfd_mach_sparc_v9 7 ++#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ ++#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ ++#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ ++/* Nonzero if MACH has the v9 instruction set. */ ++#define bfd_mach_sparc_v9_p(mach) \ ++ ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ ++ && (mach) != bfd_mach_sparc_sparclite_le) ++/* Nonzero if MACH is a 64 bit sparc architecture. */ ++#define bfd_mach_sparc_64bit_p(mach) \ ++ ((mach) >= bfd_mach_sparc_v9 && (mach) != bfd_mach_sparc_v8plusb) ++ bfd_arch_mips, /* MIPS Rxxxx */ ++#define bfd_mach_mips3000 3000 ++#define bfd_mach_mips3900 3900 ++#define bfd_mach_mips4000 4000 ++#define bfd_mach_mips4010 4010 ++#define bfd_mach_mips4100 4100 ++#define bfd_mach_mips4111 4111 ++#define bfd_mach_mips4120 4120 ++#define bfd_mach_mips4300 4300 ++#define bfd_mach_mips4400 4400 ++#define bfd_mach_mips4600 4600 ++#define bfd_mach_mips4650 4650 ++#define bfd_mach_mips5000 5000 ++#define bfd_mach_mips5400 5400 ++#define bfd_mach_mips5500 5500 ++#define bfd_mach_mips6000 6000 ++#define bfd_mach_mips7000 7000 ++#define bfd_mach_mips8000 8000 ++#define bfd_mach_mips9000 9000 ++#define bfd_mach_mips10000 10000 ++#define bfd_mach_mips12000 12000 ++#define bfd_mach_mips16 16 ++#define bfd_mach_mips5 5 ++#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ ++#define bfd_mach_mipsisa32 32 ++#define bfd_mach_mipsisa32r2 33 ++#define bfd_mach_mipsisa64 64 ++#define bfd_mach_mipsisa64r2 65 ++ bfd_arch_i386, /* Intel 386 */ ++#define bfd_mach_i386_i386 1 ++#define bfd_mach_i386_i8086 2 ++#define bfd_mach_i386_i386_intel_syntax 3 ++#define bfd_mach_x86_64 64 ++#define bfd_mach_x86_64_intel_syntax 65 ++ bfd_arch_we32k, /* AT&T WE32xxx */ ++ bfd_arch_tahoe, /* CCI/Harris Tahoe */ ++ bfd_arch_i860, /* Intel 860 */ ++ bfd_arch_i370, /* IBM 360/370 Mainframes */ ++ bfd_arch_romp, /* IBM ROMP PC/RT */ ++ bfd_arch_alliant, /* Alliant */ ++ bfd_arch_convex, /* Convex */ ++ bfd_arch_m88k, /* Motorola 88xxx */ ++ bfd_arch_m98k, /* Motorola 98xxx */ ++ bfd_arch_pyramid, /* Pyramid Technology */ ++ bfd_arch_h8300, /* Renesas H8/300 (formerly Hitachi H8/300) */ ++#define bfd_mach_h8300 1 ++#define bfd_mach_h8300h 2 ++#define bfd_mach_h8300s 3 ++#define bfd_mach_h8300hn 4 ++#define bfd_mach_h8300sn 5 ++#define bfd_mach_h8300sx 6 ++#define bfd_mach_h8300sxn 7 ++ bfd_arch_pdp11, /* DEC PDP-11 */ ++ bfd_arch_powerpc, /* PowerPC */ ++#define bfd_mach_ppc 32 ++#define bfd_mach_ppc64 64 ++#define bfd_mach_ppc_403 403 ++#define bfd_mach_ppc_403gc 4030 ++#define bfd_mach_ppc_505 505 ++#define bfd_mach_ppc_601 601 ++#define bfd_mach_ppc_602 602 ++#define bfd_mach_ppc_603 603 ++#define bfd_mach_ppc_ec603e 6031 ++#define bfd_mach_ppc_604 604 ++#define bfd_mach_ppc_620 620 ++#define bfd_mach_ppc_630 630 ++#define bfd_mach_ppc_750 750 ++#define bfd_mach_ppc_860 860 ++#define bfd_mach_ppc_a35 35 ++#define bfd_mach_ppc_rs64ii 642 ++#define bfd_mach_ppc_rs64iii 643 ++#define bfd_mach_ppc_7400 7400 ++#define bfd_mach_ppc_e500 500 ++ bfd_arch_rs6000, /* IBM RS/6000 */ ++#define bfd_mach_rs6k 6000 ++#define bfd_mach_rs6k_rs1 6001 ++#define bfd_mach_rs6k_rsc 6003 ++#define bfd_mach_rs6k_rs2 6002 ++ bfd_arch_hppa, /* HP PA RISC */ ++#define bfd_mach_hppa10 10 ++#define bfd_mach_hppa11 11 ++#define bfd_mach_hppa20 20 ++#define bfd_mach_hppa20w 25 ++ bfd_arch_d10v, /* Mitsubishi D10V */ ++#define bfd_mach_d10v 1 ++#define bfd_mach_d10v_ts2 2 ++#define bfd_mach_d10v_ts3 3 ++ bfd_arch_d30v, /* Mitsubishi D30V */ ++ bfd_arch_dlx, /* DLX */ ++ bfd_arch_m68hc11, /* Motorola 68HC11 */ ++ bfd_arch_m68hc12, /* Motorola 68HC12 */ ++#define bfd_mach_m6812_default 0 ++#define bfd_mach_m6812 1 ++#define bfd_mach_m6812s 2 ++ bfd_arch_z8k, /* Zilog Z8000 */ ++#define bfd_mach_z8001 1 ++#define bfd_mach_z8002 2 ++ bfd_arch_h8500, /* Renesas H8/500 (formerly Hitachi H8/500) */ ++ bfd_arch_sh, /* Renesas / SuperH SH (formerly Hitachi SH) */ ++#define bfd_mach_sh 1 ++#define bfd_mach_sh2 0x20 ++#define bfd_mach_sh_dsp 0x2d ++#define bfd_mach_sh2a 0x2a ++#define bfd_mach_sh2a_nofpu 0x2b ++#define bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu 0x2a1 ++#define bfd_mach_sh2a_nofpu_or_sh3_nommu 0x2a2 ++#define bfd_mach_sh2a_or_sh4 0x2a3 ++#define bfd_mach_sh2a_or_sh3e 0x2a4 ++#define bfd_mach_sh2e 0x2e ++#define bfd_mach_sh3 0x30 ++#define bfd_mach_sh3_nommu 0x31 ++#define bfd_mach_sh3_dsp 0x3d ++#define bfd_mach_sh3e 0x3e ++#define bfd_mach_sh4 0x40 ++#define bfd_mach_sh4_nofpu 0x41 ++#define bfd_mach_sh4_nommu_nofpu 0x42 ++#define bfd_mach_sh4a 0x4a ++#define bfd_mach_sh4a_nofpu 0x4b ++#define bfd_mach_sh4al_dsp 0x4d ++#define bfd_mach_sh5 0x50 ++ bfd_arch_alpha, /* Dec Alpha */ ++#define bfd_mach_alpha_ev4 0x10 ++#define bfd_mach_alpha_ev5 0x20 ++#define bfd_mach_alpha_ev6 0x30 ++ bfd_arch_arm, /* Advanced Risc Machines ARM. */ ++#define bfd_mach_arm_unknown 0 ++#define bfd_mach_arm_2 1 ++#define bfd_mach_arm_2a 2 ++#define bfd_mach_arm_3 3 ++#define bfd_mach_arm_3M 4 ++#define bfd_mach_arm_4 5 ++#define bfd_mach_arm_4T 6 ++#define bfd_mach_arm_5 7 ++#define bfd_mach_arm_5T 8 ++#define bfd_mach_arm_5TE 9 ++#define bfd_mach_arm_XScale 10 ++#define bfd_mach_arm_ep9312 11 ++#define bfd_mach_arm_iWMMXt 12 ++ bfd_arch_ns32k, /* National Semiconductors ns32000 */ ++ bfd_arch_w65, /* WDC 65816 */ ++ bfd_arch_tic30, /* Texas Instruments TMS320C30 */ ++ bfd_arch_tic4x, /* Texas Instruments TMS320C3X/4X */ ++#define bfd_mach_tic3x 30 ++#define bfd_mach_tic4x 40 ++ bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ ++ bfd_arch_tic80, /* TI TMS320c80 (MVP) */ ++ bfd_arch_v850, /* NEC V850 */ ++#define bfd_mach_v850 1 ++#define bfd_mach_v850e 'E' ++#define bfd_mach_v850e1 '1' ++ bfd_arch_arc, /* ARC Cores */ ++#define bfd_mach_arc_5 5 ++#define bfd_mach_arc_6 6 ++#define bfd_mach_arc_7 7 ++#define bfd_mach_arc_8 8 ++ bfd_arch_m32c, /* Renesas M16C/M32C. */ ++#define bfd_mach_m16c 0x75 ++#define bfd_mach_m32c 0x78 ++ bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ ++#define bfd_mach_m32r 1 /* For backwards compatibility. */ ++#define bfd_mach_m32rx 'x' ++#define bfd_mach_m32r2 '2' ++ bfd_arch_mn10200, /* Matsushita MN10200 */ ++ bfd_arch_mn10300, /* Matsushita MN10300 */ ++#define bfd_mach_mn10300 300 ++#define bfd_mach_am33 330 ++#define bfd_mach_am33_2 332 ++ bfd_arch_fr30, ++#define bfd_mach_fr30 0x46523330 ++ bfd_arch_frv, ++#define bfd_mach_frv 1 ++#define bfd_mach_frvsimple 2 ++#define bfd_mach_fr300 300 ++#define bfd_mach_fr400 400 ++#define bfd_mach_fr450 450 ++#define bfd_mach_frvtomcat 499 /* fr500 prototype */ ++#define bfd_mach_fr500 500 ++#define bfd_mach_fr550 550 ++ bfd_arch_mcore, ++ bfd_arch_ia64, /* HP/Intel ia64 */ ++#define bfd_mach_ia64_elf64 64 ++#define bfd_mach_ia64_elf32 32 ++ bfd_arch_ip2k, /* Ubicom IP2K microcontrollers. */ ++#define bfd_mach_ip2022 1 ++#define bfd_mach_ip2022ext 2 ++ bfd_arch_iq2000, /* Vitesse IQ2000. */ ++#define bfd_mach_iq2000 1 ++#define bfd_mach_iq10 2 ++ bfd_arch_ms1, ++#define bfd_mach_ms1 1 ++#define bfd_mach_mrisc2 2 ++ bfd_arch_pj, ++ bfd_arch_avr, /* Atmel AVR microcontrollers. */ ++#define bfd_mach_avr1 1 ++#define bfd_mach_avr2 2 ++#define bfd_mach_avr3 3 ++#define bfd_mach_avr4 4 ++#define bfd_mach_avr5 5 ++ bfd_arch_cr16c, /* National Semiconductor CompactRISC. */ ++#define bfd_mach_cr16c 1 ++ bfd_arch_crx, /* National Semiconductor CRX. */ ++#define bfd_mach_crx 1 ++ bfd_arch_cris, /* Axis CRIS */ ++#define bfd_mach_cris_v0_v10 255 ++#define bfd_mach_cris_v32 32 ++#define bfd_mach_cris_v10_v32 1032 ++ bfd_arch_s390, /* IBM s390 */ ++#define bfd_mach_s390_31 31 ++#define bfd_mach_s390_64 64 ++ bfd_arch_openrisc, /* OpenRISC */ ++ bfd_arch_mmix, /* Donald Knuth's educational processor. */ ++ bfd_arch_xstormy16, ++#define bfd_mach_xstormy16 1 ++ bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ ++#define bfd_mach_msp11 11 ++#define bfd_mach_msp110 110 ++#define bfd_mach_msp12 12 ++#define bfd_mach_msp13 13 ++#define bfd_mach_msp14 14 ++#define bfd_mach_msp15 15 ++#define bfd_mach_msp16 16 ++#define bfd_mach_msp31 31 ++#define bfd_mach_msp32 32 ++#define bfd_mach_msp33 33 ++#define bfd_mach_msp41 41 ++#define bfd_mach_msp42 42 ++#define bfd_mach_msp43 43 ++#define bfd_mach_msp44 44 ++ bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ ++#define bfd_mach_xtensa 1 ++ bfd_arch_maxq, /* Dallas MAXQ 10/20 */ ++#define bfd_mach_maxq10 10 ++#define bfd_mach_maxq20 20 ++ bfd_arch_last ++ }; ++ ++typedef struct bfd_arch_info ++{ ++ int bits_per_word; ++ int bits_per_address; ++ int bits_per_byte; ++ enum bfd_architecture arch; ++ unsigned long mach; ++ const char *arch_name; ++ const char *printable_name; ++ unsigned int section_align_power; ++ /* TRUE if this is the default machine for the architecture. ++ The default arch should be the first entry for an arch so that ++ all the entries for that arch can be accessed via <>. */ ++ bfd_boolean the_default; ++ const struct bfd_arch_info * (*compatible) ++ (const struct bfd_arch_info *a, const struct bfd_arch_info *b); ++ ++ bfd_boolean (*scan) (const struct bfd_arch_info *, const char *); ++ ++ const struct bfd_arch_info *next; ++} ++bfd_arch_info_type; ++ ++const char *bfd_printable_name (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_scan_arch (const char *string); ++ ++const char **bfd_arch_list (void); ++ ++const bfd_arch_info_type *bfd_arch_get_compatible ++ (const bfd *abfd, const bfd *bbfd, bfd_boolean accept_unknowns); ++ ++void bfd_set_arch_info (bfd *abfd, const bfd_arch_info_type *arg); ++ ++enum bfd_architecture bfd_get_arch (bfd *abfd); ++ ++unsigned long bfd_get_mach (bfd *abfd); ++ ++unsigned int bfd_arch_bits_per_byte (bfd *abfd); ++ ++unsigned int bfd_arch_bits_per_address (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_get_arch_info (bfd *abfd); ++ ++const bfd_arch_info_type *bfd_lookup_arch ++ (enum bfd_architecture arch, unsigned long machine); ++ ++const char *bfd_printable_arch_mach ++ (enum bfd_architecture arch, unsigned long machine); ++ ++unsigned int bfd_octets_per_byte (bfd *abfd); ++ ++unsigned int bfd_arch_mach_octets_per_byte ++ (enum bfd_architecture arch, unsigned long machine); ++ ++/* Extracted from reloc.c. */ ++typedef enum bfd_reloc_status ++{ ++ /* No errors detected. */ ++ bfd_reloc_ok, ++ ++ /* The relocation was performed, but there was an overflow. */ ++ bfd_reloc_overflow, ++ ++ /* The address to relocate was not within the section supplied. */ ++ bfd_reloc_outofrange, ++ ++ /* Used by special functions. */ ++ bfd_reloc_continue, ++ ++ /* Unsupported relocation size requested. */ ++ bfd_reloc_notsupported, ++ ++ /* Unused. */ ++ bfd_reloc_other, ++ ++ /* The symbol to relocate against was undefined. */ ++ bfd_reloc_undefined, ++ ++ /* The relocation was performed, but may not be ok - presently ++ generated only when linking i960 coff files with i960 b.out ++ symbols. If this type is returned, the error_message argument ++ to bfd_perform_relocation will be set. */ ++ bfd_reloc_dangerous ++ } ++ bfd_reloc_status_type; ++ ++ ++typedef struct reloc_cache_entry ++{ ++ /* A pointer into the canonical table of pointers. */ ++ struct bfd_symbol **sym_ptr_ptr; ++ ++ /* offset in section. */ ++ bfd_size_type address; ++ ++ /* addend for relocation value. */ ++ bfd_vma addend; ++ ++ /* Pointer to how to perform the required relocation. */ ++ reloc_howto_type *howto; ++ ++} ++arelent; ++ ++enum complain_overflow ++{ ++ /* Do not complain on overflow. */ ++ complain_overflow_dont, ++ ++ /* Complain if the bitfield overflows, whether it is considered ++ as signed or unsigned. */ ++ complain_overflow_bitfield, ++ ++ /* Complain if the value overflows when considered as signed ++ number. */ ++ complain_overflow_signed, ++ ++ /* Complain if the value overflows when considered as an ++ unsigned number. */ ++ complain_overflow_unsigned ++}; ++ ++struct reloc_howto_struct ++{ ++ /* The type field has mainly a documentary use - the back end can ++ do what it wants with it, though normally the back end's ++ external idea of what a reloc number is stored ++ in this field. For example, a PC relative word relocation ++ in a coff environment has the type 023 - because that's ++ what the outside world calls a R_PCRWORD reloc. */ ++ unsigned int type; ++ ++ /* The value the final relocation is shifted right by. This drops ++ unwanted data from the relocation. */ ++ unsigned int rightshift; ++ ++ /* The size of the item to be relocated. This is *not* a ++ power-of-two measure. To get the number of bytes operated ++ on by a type of relocation, use bfd_get_reloc_size. */ ++ int size; ++ ++ /* The number of bits in the item to be relocated. This is used ++ when doing overflow checking. */ ++ unsigned int bitsize; ++ ++ /* Notes that the relocation is relative to the location in the ++ data section of the addend. The relocation function will ++ subtract from the relocation value the address of the location ++ being relocated. */ ++ bfd_boolean pc_relative; ++ ++ /* The bit position of the reloc value in the destination. ++ The relocated value is left shifted by this amount. */ ++ unsigned int bitpos; ++ ++ /* What type of overflow error should be checked for when ++ relocating. */ ++ enum complain_overflow complain_on_overflow; ++ ++ /* If this field is non null, then the supplied function is ++ called rather than the normal function. This allows really ++ strange relocation methods to be accommodated (e.g., i960 callj ++ instructions). */ ++ bfd_reloc_status_type (*special_function) ++ (bfd *, arelent *, struct bfd_symbol *, void *, asection *, ++ bfd *, char **); ++ ++ /* The textual name of the relocation type. */ ++ char *name; ++ ++ /* Some formats record a relocation addend in the section contents ++ rather than with the relocation. For ELF formats this is the ++ distinction between USE_REL and USE_RELA (though the code checks ++ for USE_REL == 1/0). The value of this field is TRUE if the ++ addend is recorded with the section contents; when performing a ++ partial link (ld -r) the section contents (the data) will be ++ modified. The value of this field is FALSE if addends are ++ recorded with the relocation (in arelent.addend); when performing ++ a partial link the relocation will be modified. ++ All relocations for all ELF USE_RELA targets should set this field ++ to FALSE (values of TRUE should be looked on with suspicion). ++ However, the converse is not true: not all relocations of all ELF ++ USE_REL targets set this field to TRUE. Why this is so is peculiar ++ to each particular target. For relocs that aren't used in partial ++ links (e.g. GOT stuff) it doesn't matter what this is set to. */ ++ bfd_boolean partial_inplace; ++ ++ /* src_mask selects the part of the instruction (or data) to be used ++ in the relocation sum. If the target relocations don't have an ++ addend in the reloc, eg. ELF USE_REL, src_mask will normally equal ++ dst_mask to extract the addend from the section contents. If ++ relocations do have an addend in the reloc, eg. ELF USE_RELA, this ++ field should be zero. Non-zero values for ELF USE_RELA targets are ++ bogus as in those cases the value in the dst_mask part of the ++ section contents should be treated as garbage. */ ++ bfd_vma src_mask; ++ ++ /* dst_mask selects which parts of the instruction (or data) are ++ replaced with a relocated value. */ ++ bfd_vma dst_mask; ++ ++ /* When some formats create PC relative instructions, they leave ++ the value of the pc of the place being relocated in the offset ++ slot of the instruction, so that a PC relative relocation can ++ be made just by adding in an ordinary offset (e.g., sun3 a.out). ++ Some formats leave the displacement part of an instruction ++ empty (e.g., m88k bcs); this flag signals the fact. */ ++ bfd_boolean pcrel_offset; ++}; ++ ++#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ ++ { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } ++#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ ++ HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ ++ NAME, FALSE, 0, 0, IN) ++ ++#define EMPTY_HOWTO(C) \ ++ HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ ++ NULL, FALSE, 0, 0, FALSE) ++ ++#define HOWTO_PREPARE(relocation, symbol) \ ++ { \ ++ if (symbol != NULL) \ ++ { \ ++ if (bfd_is_com_section (symbol->section)) \ ++ { \ ++ relocation = 0; \ ++ } \ ++ else \ ++ { \ ++ relocation = symbol->value; \ ++ } \ ++ } \ ++ } ++ ++unsigned int bfd_get_reloc_size (reloc_howto_type *); ++ ++typedef struct relent_chain ++{ ++ arelent relent; ++ struct relent_chain *next; ++} ++arelent_chain; ++ ++bfd_reloc_status_type bfd_check_overflow ++ (enum complain_overflow how, ++ unsigned int bitsize, ++ unsigned int rightshift, ++ unsigned int addrsize, ++ bfd_vma relocation); ++ ++bfd_reloc_status_type bfd_perform_relocation ++ (bfd *abfd, ++ arelent *reloc_entry, ++ void *data, ++ asection *input_section, ++ bfd *output_bfd, ++ char **error_message); ++ ++bfd_reloc_status_type bfd_install_relocation ++ (bfd *abfd, ++ arelent *reloc_entry, ++ void *data, bfd_vma data_start, ++ asection *input_section, ++ char **error_message); ++ ++enum bfd_reloc_code_real { ++ _dummy_first_bfd_reloc_code_real, ++ ++ ++/* Basic absolute relocations of N bits. */ ++ BFD_RELOC_64, ++ BFD_RELOC_32, ++ BFD_RELOC_26, ++ BFD_RELOC_24, ++ BFD_RELOC_16, ++ BFD_RELOC_14, ++ BFD_RELOC_8, ++ ++/* PC-relative relocations. Sometimes these are relative to the address ++of the relocation itself; sometimes they are relative to the start of ++the section containing the relocation. It depends on the specific target. ++ ++The 24-bit relocation is used in some Intel 960 configurations. */ ++ BFD_RELOC_64_PCREL, ++ BFD_RELOC_32_PCREL, ++ BFD_RELOC_24_PCREL, ++ BFD_RELOC_16_PCREL, ++ BFD_RELOC_12_PCREL, ++ BFD_RELOC_8_PCREL, ++ ++/* Section relative relocations. Some targets need this for DWARF2. */ ++ BFD_RELOC_32_SECREL, ++ ++/* For ELF. */ ++ BFD_RELOC_32_GOT_PCREL, ++ BFD_RELOC_16_GOT_PCREL, ++ BFD_RELOC_8_GOT_PCREL, ++ BFD_RELOC_32_GOTOFF, ++ BFD_RELOC_16_GOTOFF, ++ BFD_RELOC_LO16_GOTOFF, ++ BFD_RELOC_HI16_GOTOFF, ++ BFD_RELOC_HI16_S_GOTOFF, ++ BFD_RELOC_8_GOTOFF, ++ BFD_RELOC_64_PLT_PCREL, ++ BFD_RELOC_32_PLT_PCREL, ++ BFD_RELOC_24_PLT_PCREL, ++ BFD_RELOC_16_PLT_PCREL, ++ BFD_RELOC_8_PLT_PCREL, ++ BFD_RELOC_64_PLTOFF, ++ BFD_RELOC_32_PLTOFF, ++ BFD_RELOC_16_PLTOFF, ++ BFD_RELOC_LO16_PLTOFF, ++ BFD_RELOC_HI16_PLTOFF, ++ BFD_RELOC_HI16_S_PLTOFF, ++ BFD_RELOC_8_PLTOFF, ++ ++/* Relocations used by 68K ELF. */ ++ BFD_RELOC_68K_GLOB_DAT, ++ BFD_RELOC_68K_JMP_SLOT, ++ BFD_RELOC_68K_RELATIVE, ++ ++/* Linkage-table relative. */ ++ BFD_RELOC_32_BASEREL, ++ BFD_RELOC_16_BASEREL, ++ BFD_RELOC_LO16_BASEREL, ++ BFD_RELOC_HI16_BASEREL, ++ BFD_RELOC_HI16_S_BASEREL, ++ BFD_RELOC_8_BASEREL, ++ BFD_RELOC_RVA, ++ ++/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ ++ BFD_RELOC_8_FFnn, ++ ++/* These PC-relative relocations are stored as word displacements -- ++i.e., byte displacements shifted right two bits. The 30-bit word ++displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the ++SPARC. (SPARC tools generally refer to this as <>.) The ++signed 16-bit displacement is used on the MIPS, and the 23-bit ++displacement is used on the Alpha. */ ++ BFD_RELOC_32_PCREL_S2, ++ BFD_RELOC_16_PCREL_S2, ++ BFD_RELOC_23_PCREL_S2, ++ ++/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of ++the target word. These are used on the SPARC. */ ++ BFD_RELOC_HI22, ++ BFD_RELOC_LO10, ++ ++/* For systems that allocate a Global Pointer register, these are ++displacements off that register. These relocation types are ++handled specially, because the value the register will have is ++decided relatively late. */ ++ BFD_RELOC_GPREL16, ++ BFD_RELOC_GPREL32, ++ ++/* Reloc types used for i960/b.out. */ ++ BFD_RELOC_I960_CALLJ, ++ ++/* SPARC ELF relocations. There is probably some overlap with other ++relocation types already defined. */ ++ BFD_RELOC_NONE, ++ BFD_RELOC_SPARC_WDISP22, ++ BFD_RELOC_SPARC22, ++ BFD_RELOC_SPARC13, ++ BFD_RELOC_SPARC_GOT10, ++ BFD_RELOC_SPARC_GOT13, ++ BFD_RELOC_SPARC_GOT22, ++ BFD_RELOC_SPARC_PC10, ++ BFD_RELOC_SPARC_PC22, ++ BFD_RELOC_SPARC_WPLT30, ++ BFD_RELOC_SPARC_COPY, ++ BFD_RELOC_SPARC_GLOB_DAT, ++ BFD_RELOC_SPARC_JMP_SLOT, ++ BFD_RELOC_SPARC_RELATIVE, ++ BFD_RELOC_SPARC_UA16, ++ BFD_RELOC_SPARC_UA32, ++ BFD_RELOC_SPARC_UA64, ++ ++/* I think these are specific to SPARC a.out (e.g., Sun 4). */ ++ BFD_RELOC_SPARC_BASE13, ++ BFD_RELOC_SPARC_BASE22, ++ ++/* SPARC64 relocations */ ++#define BFD_RELOC_SPARC_64 BFD_RELOC_64 ++ BFD_RELOC_SPARC_10, ++ BFD_RELOC_SPARC_11, ++ BFD_RELOC_SPARC_OLO10, ++ BFD_RELOC_SPARC_HH22, ++ BFD_RELOC_SPARC_HM10, ++ BFD_RELOC_SPARC_LM22, ++ BFD_RELOC_SPARC_PC_HH22, ++ BFD_RELOC_SPARC_PC_HM10, ++ BFD_RELOC_SPARC_PC_LM22, ++ BFD_RELOC_SPARC_WDISP16, ++ BFD_RELOC_SPARC_WDISP19, ++ BFD_RELOC_SPARC_7, ++ BFD_RELOC_SPARC_6, ++ BFD_RELOC_SPARC_5, ++#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL ++ BFD_RELOC_SPARC_PLT32, ++ BFD_RELOC_SPARC_PLT64, ++ BFD_RELOC_SPARC_HIX22, ++ BFD_RELOC_SPARC_LOX10, ++ BFD_RELOC_SPARC_H44, ++ BFD_RELOC_SPARC_M44, ++ BFD_RELOC_SPARC_L44, ++ BFD_RELOC_SPARC_REGISTER, ++ ++/* SPARC little endian relocation */ ++ BFD_RELOC_SPARC_REV32, ++ ++/* SPARC TLS relocations */ ++ BFD_RELOC_SPARC_TLS_GD_HI22, ++ BFD_RELOC_SPARC_TLS_GD_LO10, ++ BFD_RELOC_SPARC_TLS_GD_ADD, ++ BFD_RELOC_SPARC_TLS_GD_CALL, ++ BFD_RELOC_SPARC_TLS_LDM_HI22, ++ BFD_RELOC_SPARC_TLS_LDM_LO10, ++ BFD_RELOC_SPARC_TLS_LDM_ADD, ++ BFD_RELOC_SPARC_TLS_LDM_CALL, ++ BFD_RELOC_SPARC_TLS_LDO_HIX22, ++ BFD_RELOC_SPARC_TLS_LDO_LOX10, ++ BFD_RELOC_SPARC_TLS_LDO_ADD, ++ BFD_RELOC_SPARC_TLS_IE_HI22, ++ BFD_RELOC_SPARC_TLS_IE_LO10, ++ BFD_RELOC_SPARC_TLS_IE_LD, ++ BFD_RELOC_SPARC_TLS_IE_LDX, ++ BFD_RELOC_SPARC_TLS_IE_ADD, ++ BFD_RELOC_SPARC_TLS_LE_HIX22, ++ BFD_RELOC_SPARC_TLS_LE_LOX10, ++ BFD_RELOC_SPARC_TLS_DTPMOD32, ++ BFD_RELOC_SPARC_TLS_DTPMOD64, ++ BFD_RELOC_SPARC_TLS_DTPOFF32, ++ BFD_RELOC_SPARC_TLS_DTPOFF64, ++ BFD_RELOC_SPARC_TLS_TPOFF32, ++ BFD_RELOC_SPARC_TLS_TPOFF64, ++ ++/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or ++"addend" in some special way. ++For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when ++writing; when reading, it will be the absolute section symbol. The ++addend is the displacement in bytes of the "lda" instruction from ++the "ldah" instruction (which is at the address of this reloc). */ ++ BFD_RELOC_ALPHA_GPDISP_HI16, ++ ++/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as ++with GPDISP_HI16 relocs. The addend is ignored when writing the ++relocations out, and is filled in with the file's GP value on ++reading, for convenience. */ ++ BFD_RELOC_ALPHA_GPDISP_LO16, ++ ++/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 ++relocation except that there is no accompanying GPDISP_LO16 ++relocation. */ ++ BFD_RELOC_ALPHA_GPDISP, ++ ++/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; ++the assembler turns it into a LDQ instruction to load the address of ++the symbol, and then fills in a register in the real instruction. ++ ++The LITERAL reloc, at the LDQ instruction, refers to the .lita ++section symbol. The addend is ignored when writing, but is filled ++in with the file's GP value on reading, for convenience, as with the ++GPDISP_LO16 reloc. ++ ++The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. ++It should refer to the symbol to be referenced, as with 16_GOTOFF, ++but it generates output not based on the position within the .got ++section, but relative to the GP value chosen for the file during the ++final link stage. ++ ++The LITUSE reloc, on the instruction using the loaded address, gives ++information to the linker that it might be able to use to optimize ++away some literal section references. The symbol is ignored (read ++as the absolute section symbol), and the "addend" indicates the type ++of instruction using the register: ++1 - "memory" fmt insn ++2 - byte-manipulation (byte offset reg) ++3 - jsr (target of branch) */ ++ BFD_RELOC_ALPHA_LITERAL, ++ BFD_RELOC_ALPHA_ELF_LITERAL, ++ BFD_RELOC_ALPHA_LITUSE, ++ ++/* The HINT relocation indicates a value that should be filled into the ++"hint" field of a jmp/jsr/ret instruction, for possible branch- ++prediction logic which may be provided on some processors. */ ++ BFD_RELOC_ALPHA_HINT, ++ ++/* The LINKAGE relocation outputs a linkage pair in the object file, ++which is filled by the linker. */ ++ BFD_RELOC_ALPHA_LINKAGE, ++ ++/* The CODEADDR relocation outputs a STO_CA in the object file, ++which is filled by the linker. */ ++ BFD_RELOC_ALPHA_CODEADDR, ++ ++/* The GPREL_HI/LO relocations together form a 32-bit offset from the ++GP register. */ ++ BFD_RELOC_ALPHA_GPREL_HI16, ++ BFD_RELOC_ALPHA_GPREL_LO16, ++ ++/* Like BFD_RELOC_23_PCREL_S2, except that the source and target must ++share a common GP, and the target address is adjusted for ++STO_ALPHA_STD_GPLOAD. */ ++ BFD_RELOC_ALPHA_BRSGP, ++ ++/* Alpha thread-local storage relocations. */ ++ BFD_RELOC_ALPHA_TLSGD, ++ BFD_RELOC_ALPHA_TLSLDM, ++ BFD_RELOC_ALPHA_DTPMOD64, ++ BFD_RELOC_ALPHA_GOTDTPREL16, ++ BFD_RELOC_ALPHA_DTPREL64, ++ BFD_RELOC_ALPHA_DTPREL_HI16, ++ BFD_RELOC_ALPHA_DTPREL_LO16, ++ BFD_RELOC_ALPHA_DTPREL16, ++ BFD_RELOC_ALPHA_GOTTPREL16, ++ BFD_RELOC_ALPHA_TPREL64, ++ BFD_RELOC_ALPHA_TPREL_HI16, ++ BFD_RELOC_ALPHA_TPREL_LO16, ++ BFD_RELOC_ALPHA_TPREL16, ++ ++/* Bits 27..2 of the relocation address shifted right 2 bits; ++simple reloc otherwise. */ ++ BFD_RELOC_MIPS_JMP, ++ ++/* The MIPS16 jump instruction. */ ++ BFD_RELOC_MIPS16_JMP, ++ ++/* MIPS16 GP relative reloc. */ ++ BFD_RELOC_MIPS16_GPREL, ++ ++/* High 16 bits of 32-bit value; simple reloc. */ ++ BFD_RELOC_HI16, ++ ++/* High 16 bits of 32-bit value but the low 16 bits will be sign ++extended and added to form the final result. If the low 16 ++bits form a negative number, we need to add one to the high value ++to compensate for the borrow when the low bits are added. */ ++ BFD_RELOC_HI16_S, ++ ++/* Low 16 bits. */ ++ BFD_RELOC_LO16, ++ ++/* High 16 bits of 32-bit pc-relative value */ ++ BFD_RELOC_HI16_PCREL, ++ ++/* High 16 bits of 32-bit pc-relative value, adjusted */ ++ BFD_RELOC_HI16_S_PCREL, ++ ++/* Low 16 bits of pc-relative value */ ++ BFD_RELOC_LO16_PCREL, ++ ++/* MIPS16 high 16 bits of 32-bit value. */ ++ BFD_RELOC_MIPS16_HI16, ++ ++/* MIPS16 high 16 bits of 32-bit value but the low 16 bits will be sign ++extended and added to form the final result. If the low 16 ++bits form a negative number, we need to add one to the high value ++to compensate for the borrow when the low bits are added. */ ++ BFD_RELOC_MIPS16_HI16_S, ++ ++/* MIPS16 low 16 bits. */ ++ BFD_RELOC_MIPS16_LO16, ++ ++/* Relocation against a MIPS literal section. */ ++ BFD_RELOC_MIPS_LITERAL, ++ ++/* MIPS ELF relocations. */ ++ BFD_RELOC_MIPS_GOT16, ++ BFD_RELOC_MIPS_CALL16, ++ BFD_RELOC_MIPS_GOT_HI16, ++ BFD_RELOC_MIPS_GOT_LO16, ++ BFD_RELOC_MIPS_CALL_HI16, ++ BFD_RELOC_MIPS_CALL_LO16, ++ BFD_RELOC_MIPS_SUB, ++ BFD_RELOC_MIPS_GOT_PAGE, ++ BFD_RELOC_MIPS_GOT_OFST, ++ BFD_RELOC_MIPS_GOT_DISP, ++ BFD_RELOC_MIPS_SHIFT5, ++ BFD_RELOC_MIPS_SHIFT6, ++ BFD_RELOC_MIPS_INSERT_A, ++ BFD_RELOC_MIPS_INSERT_B, ++ BFD_RELOC_MIPS_DELETE, ++ BFD_RELOC_MIPS_HIGHEST, ++ BFD_RELOC_MIPS_HIGHER, ++ BFD_RELOC_MIPS_SCN_DISP, ++ BFD_RELOC_MIPS_REL16, ++ BFD_RELOC_MIPS_RELGOT, ++ BFD_RELOC_MIPS_JALR, ++ BFD_RELOC_MIPS_TLS_DTPMOD32, ++ BFD_RELOC_MIPS_TLS_DTPREL32, ++ BFD_RELOC_MIPS_TLS_DTPMOD64, ++ BFD_RELOC_MIPS_TLS_DTPREL64, ++ BFD_RELOC_MIPS_TLS_GD, ++ BFD_RELOC_MIPS_TLS_LDM, ++ BFD_RELOC_MIPS_TLS_DTPREL_HI16, ++ BFD_RELOC_MIPS_TLS_DTPREL_LO16, ++ BFD_RELOC_MIPS_TLS_GOTTPREL, ++ BFD_RELOC_MIPS_TLS_TPREL32, ++ BFD_RELOC_MIPS_TLS_TPREL64, ++ BFD_RELOC_MIPS_TLS_TPREL_HI16, ++ BFD_RELOC_MIPS_TLS_TPREL_LO16, ++ ++ ++/* Fujitsu Frv Relocations. */ ++ BFD_RELOC_FRV_LABEL16, ++ BFD_RELOC_FRV_LABEL24, ++ BFD_RELOC_FRV_LO16, ++ BFD_RELOC_FRV_HI16, ++ BFD_RELOC_FRV_GPREL12, ++ BFD_RELOC_FRV_GPRELU12, ++ BFD_RELOC_FRV_GPREL32, ++ BFD_RELOC_FRV_GPRELHI, ++ BFD_RELOC_FRV_GPRELLO, ++ BFD_RELOC_FRV_GOT12, ++ BFD_RELOC_FRV_GOTHI, ++ BFD_RELOC_FRV_GOTLO, ++ BFD_RELOC_FRV_FUNCDESC, ++ BFD_RELOC_FRV_FUNCDESC_GOT12, ++ BFD_RELOC_FRV_FUNCDESC_GOTHI, ++ BFD_RELOC_FRV_FUNCDESC_GOTLO, ++ BFD_RELOC_FRV_FUNCDESC_VALUE, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFF12, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFFHI, ++ BFD_RELOC_FRV_FUNCDESC_GOTOFFLO, ++ BFD_RELOC_FRV_GOTOFF12, ++ BFD_RELOC_FRV_GOTOFFHI, ++ BFD_RELOC_FRV_GOTOFFLO, ++ BFD_RELOC_FRV_GETTLSOFF, ++ BFD_RELOC_FRV_TLSDESC_VALUE, ++ BFD_RELOC_FRV_GOTTLSDESC12, ++ BFD_RELOC_FRV_GOTTLSDESCHI, ++ BFD_RELOC_FRV_GOTTLSDESCLO, ++ BFD_RELOC_FRV_TLSMOFF12, ++ BFD_RELOC_FRV_TLSMOFFHI, ++ BFD_RELOC_FRV_TLSMOFFLO, ++ BFD_RELOC_FRV_GOTTLSOFF12, ++ BFD_RELOC_FRV_GOTTLSOFFHI, ++ BFD_RELOC_FRV_GOTTLSOFFLO, ++ BFD_RELOC_FRV_TLSOFF, ++ BFD_RELOC_FRV_TLSDESC_RELAX, ++ BFD_RELOC_FRV_GETTLSOFF_RELAX, ++ BFD_RELOC_FRV_TLSOFF_RELAX, ++ BFD_RELOC_FRV_TLSMOFF, ++ ++ ++/* This is a 24bit GOT-relative reloc for the mn10300. */ ++ BFD_RELOC_MN10300_GOTOFF24, ++ ++/* This is a 32bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT32, ++ ++/* This is a 24bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT24, ++ ++/* This is a 16bit GOT-relative reloc for the mn10300, offset by two bytes ++in the instruction. */ ++ BFD_RELOC_MN10300_GOT16, ++ ++/* Copy symbol at runtime. */ ++ BFD_RELOC_MN10300_COPY, ++ ++/* Create GOT entry. */ ++ BFD_RELOC_MN10300_GLOB_DAT, ++ ++/* Create PLT entry. */ ++ BFD_RELOC_MN10300_JMP_SLOT, ++ ++/* Adjust by program base. */ ++ BFD_RELOC_MN10300_RELATIVE, ++ ++ ++/* i386/elf relocations */ ++ BFD_RELOC_386_GOT32, ++ BFD_RELOC_386_PLT32, ++ BFD_RELOC_386_COPY, ++ BFD_RELOC_386_GLOB_DAT, ++ BFD_RELOC_386_JUMP_SLOT, ++ BFD_RELOC_386_RELATIVE, ++ BFD_RELOC_386_GOTOFF, ++ BFD_RELOC_386_GOTPC, ++ BFD_RELOC_386_TLS_TPOFF, ++ BFD_RELOC_386_TLS_IE, ++ BFD_RELOC_386_TLS_GOTIE, ++ BFD_RELOC_386_TLS_LE, ++ BFD_RELOC_386_TLS_GD, ++ BFD_RELOC_386_TLS_LDM, ++ BFD_RELOC_386_TLS_LDO_32, ++ BFD_RELOC_386_TLS_IE_32, ++ BFD_RELOC_386_TLS_LE_32, ++ BFD_RELOC_386_TLS_DTPMOD32, ++ BFD_RELOC_386_TLS_DTPOFF32, ++ BFD_RELOC_386_TLS_TPOFF32, ++ ++/* x86-64/elf relocations */ ++ BFD_RELOC_X86_64_GOT32, ++ BFD_RELOC_X86_64_PLT32, ++ BFD_RELOC_X86_64_COPY, ++ BFD_RELOC_X86_64_GLOB_DAT, ++ BFD_RELOC_X86_64_JUMP_SLOT, ++ BFD_RELOC_X86_64_RELATIVE, ++ BFD_RELOC_X86_64_GOTPCREL, ++ BFD_RELOC_X86_64_32S, ++ BFD_RELOC_X86_64_DTPMOD64, ++ BFD_RELOC_X86_64_DTPOFF64, ++ BFD_RELOC_X86_64_TPOFF64, ++ BFD_RELOC_X86_64_TLSGD, ++ BFD_RELOC_X86_64_TLSLD, ++ BFD_RELOC_X86_64_DTPOFF32, ++ BFD_RELOC_X86_64_GOTTPOFF, ++ BFD_RELOC_X86_64_TPOFF32, ++ BFD_RELOC_X86_64_GOTOFF64, ++ BFD_RELOC_X86_64_GOTPC32, ++ ++/* ns32k relocations */ ++ BFD_RELOC_NS32K_IMM_8, ++ BFD_RELOC_NS32K_IMM_16, ++ BFD_RELOC_NS32K_IMM_32, ++ BFD_RELOC_NS32K_IMM_8_PCREL, ++ BFD_RELOC_NS32K_IMM_16_PCREL, ++ BFD_RELOC_NS32K_IMM_32_PCREL, ++ BFD_RELOC_NS32K_DISP_8, ++ BFD_RELOC_NS32K_DISP_16, ++ BFD_RELOC_NS32K_DISP_32, ++ BFD_RELOC_NS32K_DISP_8_PCREL, ++ BFD_RELOC_NS32K_DISP_16_PCREL, ++ BFD_RELOC_NS32K_DISP_32_PCREL, ++ ++/* PDP11 relocations */ ++ BFD_RELOC_PDP11_DISP_8_PCREL, ++ BFD_RELOC_PDP11_DISP_6_PCREL, ++ ++/* Picojava relocs. Not all of these appear in object files. */ ++ BFD_RELOC_PJ_CODE_HI16, ++ BFD_RELOC_PJ_CODE_LO16, ++ BFD_RELOC_PJ_CODE_DIR16, ++ BFD_RELOC_PJ_CODE_DIR32, ++ BFD_RELOC_PJ_CODE_REL16, ++ BFD_RELOC_PJ_CODE_REL32, ++ ++/* Power(rs6000) and PowerPC relocations. */ ++ BFD_RELOC_PPC_B26, ++ BFD_RELOC_PPC_BA26, ++ BFD_RELOC_PPC_TOC16, ++ BFD_RELOC_PPC_B16, ++ BFD_RELOC_PPC_B16_BRTAKEN, ++ BFD_RELOC_PPC_B16_BRNTAKEN, ++ BFD_RELOC_PPC_BA16, ++ BFD_RELOC_PPC_BA16_BRTAKEN, ++ BFD_RELOC_PPC_BA16_BRNTAKEN, ++ BFD_RELOC_PPC_COPY, ++ BFD_RELOC_PPC_GLOB_DAT, ++ BFD_RELOC_PPC_JMP_SLOT, ++ BFD_RELOC_PPC_RELATIVE, ++ BFD_RELOC_PPC_LOCAL24PC, ++ BFD_RELOC_PPC_EMB_NADDR32, ++ BFD_RELOC_PPC_EMB_NADDR16, ++ BFD_RELOC_PPC_EMB_NADDR16_LO, ++ BFD_RELOC_PPC_EMB_NADDR16_HI, ++ BFD_RELOC_PPC_EMB_NADDR16_HA, ++ BFD_RELOC_PPC_EMB_SDAI16, ++ BFD_RELOC_PPC_EMB_SDA2I16, ++ BFD_RELOC_PPC_EMB_SDA2REL, ++ BFD_RELOC_PPC_EMB_SDA21, ++ BFD_RELOC_PPC_EMB_MRKREF, ++ BFD_RELOC_PPC_EMB_RELSEC16, ++ BFD_RELOC_PPC_EMB_RELST_LO, ++ BFD_RELOC_PPC_EMB_RELST_HI, ++ BFD_RELOC_PPC_EMB_RELST_HA, ++ BFD_RELOC_PPC_EMB_BIT_FLD, ++ BFD_RELOC_PPC_EMB_RELSDA, ++ BFD_RELOC_PPC64_HIGHER, ++ BFD_RELOC_PPC64_HIGHER_S, ++ BFD_RELOC_PPC64_HIGHEST, ++ BFD_RELOC_PPC64_HIGHEST_S, ++ BFD_RELOC_PPC64_TOC16_LO, ++ BFD_RELOC_PPC64_TOC16_HI, ++ BFD_RELOC_PPC64_TOC16_HA, ++ BFD_RELOC_PPC64_TOC, ++ BFD_RELOC_PPC64_PLTGOT16, ++ BFD_RELOC_PPC64_PLTGOT16_LO, ++ BFD_RELOC_PPC64_PLTGOT16_HI, ++ BFD_RELOC_PPC64_PLTGOT16_HA, ++ BFD_RELOC_PPC64_ADDR16_DS, ++ BFD_RELOC_PPC64_ADDR16_LO_DS, ++ BFD_RELOC_PPC64_GOT16_DS, ++ BFD_RELOC_PPC64_GOT16_LO_DS, ++ BFD_RELOC_PPC64_PLT16_LO_DS, ++ BFD_RELOC_PPC64_SECTOFF_DS, ++ BFD_RELOC_PPC64_SECTOFF_LO_DS, ++ BFD_RELOC_PPC64_TOC16_DS, ++ BFD_RELOC_PPC64_TOC16_LO_DS, ++ BFD_RELOC_PPC64_PLTGOT16_DS, ++ BFD_RELOC_PPC64_PLTGOT16_LO_DS, ++ ++/* PowerPC and PowerPC64 thread-local storage relocations. */ ++ BFD_RELOC_PPC_TLS, ++ BFD_RELOC_PPC_DTPMOD, ++ BFD_RELOC_PPC_TPREL16, ++ BFD_RELOC_PPC_TPREL16_LO, ++ BFD_RELOC_PPC_TPREL16_HI, ++ BFD_RELOC_PPC_TPREL16_HA, ++ BFD_RELOC_PPC_TPREL, ++ BFD_RELOC_PPC_DTPREL16, ++ BFD_RELOC_PPC_DTPREL16_LO, ++ BFD_RELOC_PPC_DTPREL16_HI, ++ BFD_RELOC_PPC_DTPREL16_HA, ++ BFD_RELOC_PPC_DTPREL, ++ BFD_RELOC_PPC_GOT_TLSGD16, ++ BFD_RELOC_PPC_GOT_TLSGD16_LO, ++ BFD_RELOC_PPC_GOT_TLSGD16_HI, ++ BFD_RELOC_PPC_GOT_TLSGD16_HA, ++ BFD_RELOC_PPC_GOT_TLSLD16, ++ BFD_RELOC_PPC_GOT_TLSLD16_LO, ++ BFD_RELOC_PPC_GOT_TLSLD16_HI, ++ BFD_RELOC_PPC_GOT_TLSLD16_HA, ++ BFD_RELOC_PPC_GOT_TPREL16, ++ BFD_RELOC_PPC_GOT_TPREL16_LO, ++ BFD_RELOC_PPC_GOT_TPREL16_HI, ++ BFD_RELOC_PPC_GOT_TPREL16_HA, ++ BFD_RELOC_PPC_GOT_DTPREL16, ++ BFD_RELOC_PPC_GOT_DTPREL16_LO, ++ BFD_RELOC_PPC_GOT_DTPREL16_HI, ++ BFD_RELOC_PPC_GOT_DTPREL16_HA, ++ BFD_RELOC_PPC64_TPREL16_DS, ++ BFD_RELOC_PPC64_TPREL16_LO_DS, ++ BFD_RELOC_PPC64_TPREL16_HIGHER, ++ BFD_RELOC_PPC64_TPREL16_HIGHERA, ++ BFD_RELOC_PPC64_TPREL16_HIGHEST, ++ BFD_RELOC_PPC64_TPREL16_HIGHESTA, ++ BFD_RELOC_PPC64_DTPREL16_DS, ++ BFD_RELOC_PPC64_DTPREL16_LO_DS, ++ BFD_RELOC_PPC64_DTPREL16_HIGHER, ++ BFD_RELOC_PPC64_DTPREL16_HIGHERA, ++ BFD_RELOC_PPC64_DTPREL16_HIGHEST, ++ BFD_RELOC_PPC64_DTPREL16_HIGHESTA, ++ ++/* IBM 370/390 relocations */ ++ BFD_RELOC_I370_D12, ++ ++/* The type of reloc used to build a constructor table - at the moment ++probably a 32 bit wide absolute relocation, but the target can choose. ++It generally does map to one of the other relocation types. */ ++ BFD_RELOC_CTOR, ++ ++/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are ++not stored in the instruction. */ ++ BFD_RELOC_ARM_PCREL_BRANCH, ++ ++/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is ++not stored in the instruction. The 2nd lowest bit comes from a 1 bit ++field in the instruction. */ ++ BFD_RELOC_ARM_PCREL_BLX, ++ ++/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is ++not stored in the instruction. The 2nd lowest bit comes from a 1 bit ++field in the instruction. */ ++ BFD_RELOC_THUMB_PCREL_BLX, ++ ++/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches. ++The lowest bit must be zero and is not stored in the instruction. ++Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an ++"nn" one smaller in all cases. Note further that BRANCH23 ++corresponds to R_ARM_THM_CALL. */ ++ BFD_RELOC_THUMB_PCREL_BRANCH7, ++ BFD_RELOC_THUMB_PCREL_BRANCH9, ++ BFD_RELOC_THUMB_PCREL_BRANCH12, ++ BFD_RELOC_THUMB_PCREL_BRANCH20, ++ BFD_RELOC_THUMB_PCREL_BRANCH23, ++ BFD_RELOC_THUMB_PCREL_BRANCH25, ++ ++/* 12-bit immediate offset, used in ARM-format ldr and str instructions. */ ++ BFD_RELOC_ARM_OFFSET_IMM, ++ ++/* 5-bit immediate offset, used in Thumb-format ldr and str instructions. */ ++ BFD_RELOC_ARM_THUMB_OFFSET, ++ ++/* Pc-relative or absolute relocation depending on target. Used for ++entries in .init_array sections. */ ++ BFD_RELOC_ARM_TARGET1, ++ ++/* Read-only segment base relative address. */ ++ BFD_RELOC_ARM_ROSEGREL32, ++ ++/* Data segment base relative address. */ ++ BFD_RELOC_ARM_SBREL32, ++ ++/* This reloc is used for references to RTTI data from exception handling ++tables. The actual definition depends on the target. It may be a ++pc-relative or some form of GOT-indirect relocation. */ ++ BFD_RELOC_ARM_TARGET2, ++ ++/* 31-bit PC relative address. */ ++ BFD_RELOC_ARM_PREL31, ++ ++/* Relocations for setting up GOTs and PLTs for shared libraries. */ ++ BFD_RELOC_ARM_JUMP_SLOT, ++ BFD_RELOC_ARM_GLOB_DAT, ++ BFD_RELOC_ARM_GOT32, ++ BFD_RELOC_ARM_PLT32, ++ BFD_RELOC_ARM_RELATIVE, ++ BFD_RELOC_ARM_GOTOFF, ++ BFD_RELOC_ARM_GOTPC, ++ ++/* ARM thread-local storage relocations. */ ++ BFD_RELOC_ARM_TLS_GD32, ++ BFD_RELOC_ARM_TLS_LDO32, ++ BFD_RELOC_ARM_TLS_LDM32, ++ BFD_RELOC_ARM_TLS_DTPOFF32, ++ BFD_RELOC_ARM_TLS_DTPMOD32, ++ BFD_RELOC_ARM_TLS_TPOFF32, ++ BFD_RELOC_ARM_TLS_IE32, ++ BFD_RELOC_ARM_TLS_LE32, ++ ++/* These relocs are only used within the ARM assembler. They are not ++(at present) written to any object files. */ ++ BFD_RELOC_ARM_IMMEDIATE, ++ BFD_RELOC_ARM_ADRL_IMMEDIATE, ++ BFD_RELOC_ARM_T32_IMMEDIATE, ++ BFD_RELOC_ARM_SHIFT_IMM, ++ BFD_RELOC_ARM_SMI, ++ BFD_RELOC_ARM_SWI, ++ BFD_RELOC_ARM_MULTI, ++ BFD_RELOC_ARM_CP_OFF_IMM, ++ BFD_RELOC_ARM_CP_OFF_IMM_S2, ++ BFD_RELOC_ARM_ADR_IMM, ++ BFD_RELOC_ARM_LDR_IMM, ++ BFD_RELOC_ARM_LITERAL, ++ BFD_RELOC_ARM_IN_POOL, ++ BFD_RELOC_ARM_OFFSET_IMM8, ++ BFD_RELOC_ARM_T32_OFFSET_U8, ++ BFD_RELOC_ARM_T32_OFFSET_IMM, ++ BFD_RELOC_ARM_HWLITERAL, ++ BFD_RELOC_ARM_THUMB_ADD, ++ BFD_RELOC_ARM_THUMB_IMM, ++ BFD_RELOC_ARM_THUMB_SHIFT, ++ ++/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ ++ BFD_RELOC_SH_PCDISP8BY2, ++ BFD_RELOC_SH_PCDISP12BY2, ++ BFD_RELOC_SH_IMM3, ++ BFD_RELOC_SH_IMM3U, ++ BFD_RELOC_SH_DISP12, ++ BFD_RELOC_SH_DISP12BY2, ++ BFD_RELOC_SH_DISP12BY4, ++ BFD_RELOC_SH_DISP12BY8, ++ BFD_RELOC_SH_DISP20, ++ BFD_RELOC_SH_DISP20BY8, ++ BFD_RELOC_SH_IMM4, ++ BFD_RELOC_SH_IMM4BY2, ++ BFD_RELOC_SH_IMM4BY4, ++ BFD_RELOC_SH_IMM8, ++ BFD_RELOC_SH_IMM8BY2, ++ BFD_RELOC_SH_IMM8BY4, ++ BFD_RELOC_SH_PCRELIMM8BY2, ++ BFD_RELOC_SH_PCRELIMM8BY4, ++ BFD_RELOC_SH_SWITCH16, ++ BFD_RELOC_SH_SWITCH32, ++ BFD_RELOC_SH_USES, ++ BFD_RELOC_SH_COUNT, ++ BFD_RELOC_SH_ALIGN, ++ BFD_RELOC_SH_CODE, ++ BFD_RELOC_SH_DATA, ++ BFD_RELOC_SH_LABEL, ++ BFD_RELOC_SH_LOOP_START, ++ BFD_RELOC_SH_LOOP_END, ++ BFD_RELOC_SH_COPY, ++ BFD_RELOC_SH_GLOB_DAT, ++ BFD_RELOC_SH_JMP_SLOT, ++ BFD_RELOC_SH_RELATIVE, ++ BFD_RELOC_SH_GOTPC, ++ BFD_RELOC_SH_GOT_LOW16, ++ BFD_RELOC_SH_GOT_MEDLOW16, ++ BFD_RELOC_SH_GOT_MEDHI16, ++ BFD_RELOC_SH_GOT_HI16, ++ BFD_RELOC_SH_GOTPLT_LOW16, ++ BFD_RELOC_SH_GOTPLT_MEDLOW16, ++ BFD_RELOC_SH_GOTPLT_MEDHI16, ++ BFD_RELOC_SH_GOTPLT_HI16, ++ BFD_RELOC_SH_PLT_LOW16, ++ BFD_RELOC_SH_PLT_MEDLOW16, ++ BFD_RELOC_SH_PLT_MEDHI16, ++ BFD_RELOC_SH_PLT_HI16, ++ BFD_RELOC_SH_GOTOFF_LOW16, ++ BFD_RELOC_SH_GOTOFF_MEDLOW16, ++ BFD_RELOC_SH_GOTOFF_MEDHI16, ++ BFD_RELOC_SH_GOTOFF_HI16, ++ BFD_RELOC_SH_GOTPC_LOW16, ++ BFD_RELOC_SH_GOTPC_MEDLOW16, ++ BFD_RELOC_SH_GOTPC_MEDHI16, ++ BFD_RELOC_SH_GOTPC_HI16, ++ BFD_RELOC_SH_COPY64, ++ BFD_RELOC_SH_GLOB_DAT64, ++ BFD_RELOC_SH_JMP_SLOT64, ++ BFD_RELOC_SH_RELATIVE64, ++ BFD_RELOC_SH_GOT10BY4, ++ BFD_RELOC_SH_GOT10BY8, ++ BFD_RELOC_SH_GOTPLT10BY4, ++ BFD_RELOC_SH_GOTPLT10BY8, ++ BFD_RELOC_SH_GOTPLT32, ++ BFD_RELOC_SH_SHMEDIA_CODE, ++ BFD_RELOC_SH_IMMU5, ++ BFD_RELOC_SH_IMMS6, ++ BFD_RELOC_SH_IMMS6BY32, ++ BFD_RELOC_SH_IMMU6, ++ BFD_RELOC_SH_IMMS10, ++ BFD_RELOC_SH_IMMS10BY2, ++ BFD_RELOC_SH_IMMS10BY4, ++ BFD_RELOC_SH_IMMS10BY8, ++ BFD_RELOC_SH_IMMS16, ++ BFD_RELOC_SH_IMMU16, ++ BFD_RELOC_SH_IMM_LOW16, ++ BFD_RELOC_SH_IMM_LOW16_PCREL, ++ BFD_RELOC_SH_IMM_MEDLOW16, ++ BFD_RELOC_SH_IMM_MEDLOW16_PCREL, ++ BFD_RELOC_SH_IMM_MEDHI16, ++ BFD_RELOC_SH_IMM_MEDHI16_PCREL, ++ BFD_RELOC_SH_IMM_HI16, ++ BFD_RELOC_SH_IMM_HI16_PCREL, ++ BFD_RELOC_SH_PT_16, ++ BFD_RELOC_SH_TLS_GD_32, ++ BFD_RELOC_SH_TLS_LD_32, ++ BFD_RELOC_SH_TLS_LDO_32, ++ BFD_RELOC_SH_TLS_IE_32, ++ BFD_RELOC_SH_TLS_LE_32, ++ BFD_RELOC_SH_TLS_DTPMOD32, ++ BFD_RELOC_SH_TLS_DTPOFF32, ++ BFD_RELOC_SH_TLS_TPOFF32, ++ ++/* ARC Cores relocs. ++ARC 22 bit pc-relative branch. The lowest two bits must be zero and are ++not stored in the instruction. The high 20 bits are installed in bits 26 ++through 7 of the instruction. */ ++ BFD_RELOC_ARC_B22_PCREL, ++ ++/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not ++stored in the instruction. The high 24 bits are installed in bits 23 ++through 0. */ ++ BFD_RELOC_ARC_B26, ++ ++/* Mitsubishi D10V relocs. ++This is a 10-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_10_PCREL_R, ++ ++/* Mitsubishi D10V relocs. ++This is a 10-bit reloc with the right 2 bits ++assumed to be 0. This is the same as the previous reloc ++except it is in the left container, i.e., ++shifted left 15 bits. */ ++ BFD_RELOC_D10V_10_PCREL_L, ++ ++/* This is an 18-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_18, ++ ++/* This is an 18-bit reloc with the right 2 bits ++assumed to be 0. */ ++ BFD_RELOC_D10V_18_PCREL, ++ ++/* Mitsubishi D30V relocs. ++This is a 6-bit absolute reloc. */ ++ BFD_RELOC_D30V_6, ++ ++/* This is a 6-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_9_PCREL, ++ ++/* This is a 6-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_9_PCREL_R, ++ ++/* This is a 12-bit absolute reloc with the ++right 3 bitsassumed to be 0. */ ++ BFD_RELOC_D30V_15, ++ ++/* This is a 12-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_15_PCREL, ++ ++/* This is a 12-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_15_PCREL_R, ++ ++/* This is an 18-bit absolute reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_21, ++ ++/* This is an 18-bit pc-relative reloc with ++the right 3 bits assumed to be 0. */ ++ BFD_RELOC_D30V_21_PCREL, ++ ++/* This is an 18-bit pc-relative reloc with ++the right 3 bits assumed to be 0. Same ++as the previous reloc but on the right side ++of the container. */ ++ BFD_RELOC_D30V_21_PCREL_R, ++ ++/* This is a 32-bit absolute reloc. */ ++ BFD_RELOC_D30V_32, ++ ++/* This is a 32-bit pc-relative reloc. */ ++ BFD_RELOC_D30V_32_PCREL, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_HI16_S, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_LO16, ++ ++/* DLX relocs */ ++ BFD_RELOC_DLX_JMP26, ++ ++/* Renesas M16C/M32C Relocations. */ ++ BFD_RELOC_M16C_8_PCREL8, ++ BFD_RELOC_M16C_16_PCREL8, ++ BFD_RELOC_M16C_8_PCREL16, ++ BFD_RELOC_M16C_8_ELABEL24, ++ BFD_RELOC_M16C_8_ABS16, ++ BFD_RELOC_M16C_16_ABS16, ++ BFD_RELOC_M16C_16_ABS24, ++ BFD_RELOC_M16C_16_ABS32, ++ BFD_RELOC_M16C_24_ABS16, ++ BFD_RELOC_M16C_24_ABS24, ++ BFD_RELOC_M16C_24_ABS32, ++ BFD_RELOC_M16C_32_ABS16, ++ BFD_RELOC_M16C_32_ABS24, ++ BFD_RELOC_M16C_32_ABS32, ++ BFD_RELOC_M16C_40_ABS16, ++ BFD_RELOC_M16C_40_ABS24, ++ BFD_RELOC_M16C_40_ABS32, ++ ++/* Renesas M32R (formerly Mitsubishi M32R) relocs. ++This is a 24 bit absolute address. */ ++ BFD_RELOC_M32R_24, ++ ++/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_10_PCREL, ++ ++/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_18_PCREL, ++ ++/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ ++ BFD_RELOC_M32R_26_PCREL, ++ ++/* This is a 16-bit reloc containing the high 16 bits of an address ++used when the lower 16 bits are treated as unsigned. */ ++ BFD_RELOC_M32R_HI16_ULO, ++ ++/* This is a 16-bit reloc containing the high 16 bits of an address ++used when the lower 16 bits are treated as signed. */ ++ BFD_RELOC_M32R_HI16_SLO, ++ ++/* This is a 16-bit reloc containing the lower 16 bits of an address. */ ++ BFD_RELOC_M32R_LO16, ++ ++/* This is a 16-bit reloc containing the small data area offset for use in ++add3, load, and store instructions. */ ++ BFD_RELOC_M32R_SDA16, ++ ++/* For PIC. */ ++ BFD_RELOC_M32R_GOT24, ++ BFD_RELOC_M32R_26_PLTREL, ++ BFD_RELOC_M32R_COPY, ++ BFD_RELOC_M32R_GLOB_DAT, ++ BFD_RELOC_M32R_JMP_SLOT, ++ BFD_RELOC_M32R_RELATIVE, ++ BFD_RELOC_M32R_GOTOFF, ++ BFD_RELOC_M32R_GOTOFF_HI_ULO, ++ BFD_RELOC_M32R_GOTOFF_HI_SLO, ++ BFD_RELOC_M32R_GOTOFF_LO, ++ BFD_RELOC_M32R_GOTPC24, ++ BFD_RELOC_M32R_GOT16_HI_ULO, ++ BFD_RELOC_M32R_GOT16_HI_SLO, ++ BFD_RELOC_M32R_GOT16_LO, ++ BFD_RELOC_M32R_GOTPC_HI_ULO, ++ BFD_RELOC_M32R_GOTPC_HI_SLO, ++ BFD_RELOC_M32R_GOTPC_LO, ++ ++/* This is a 9-bit reloc */ ++ BFD_RELOC_V850_9_PCREL, ++ ++/* This is a 22-bit reloc */ ++ BFD_RELOC_V850_22_PCREL, ++ ++/* This is a 16 bit offset from the short data area pointer. */ ++ BFD_RELOC_V850_SDA_16_16_OFFSET, ++ ++/* This is a 16 bit offset (of which only 15 bits are used) from the ++short data area pointer. */ ++ BFD_RELOC_V850_SDA_15_16_OFFSET, ++ ++/* This is a 16 bit offset from the zero data area pointer. */ ++ BFD_RELOC_V850_ZDA_16_16_OFFSET, ++ ++/* This is a 16 bit offset (of which only 15 bits are used) from the ++zero data area pointer. */ ++ BFD_RELOC_V850_ZDA_15_16_OFFSET, ++ ++/* This is an 8 bit offset (of which only 6 bits are used) from the ++tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_6_8_OFFSET, ++ ++/* This is an 8bit offset (of which only 7 bits are used) from the tiny ++data area pointer. */ ++ BFD_RELOC_V850_TDA_7_8_OFFSET, ++ ++/* This is a 7 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_7_7_OFFSET, ++ ++/* This is a 16 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_16_16_OFFSET, ++ ++/* This is a 5 bit offset (of which only 4 bits are used) from the tiny ++data area pointer. */ ++ BFD_RELOC_V850_TDA_4_5_OFFSET, ++ ++/* This is a 4 bit offset from the tiny data area pointer. */ ++ BFD_RELOC_V850_TDA_4_4_OFFSET, ++ ++/* This is a 16 bit offset from the short data area pointer, with the ++bits placed non-contiguously in the instruction. */ ++ BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, ++ ++/* This is a 16 bit offset from the zero data area pointer, with the ++bits placed non-contiguously in the instruction. */ ++ BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, ++ ++/* This is a 6 bit offset from the call table base pointer. */ ++ BFD_RELOC_V850_CALLT_6_7_OFFSET, ++ ++/* This is a 16 bit offset from the call table base pointer. */ ++ BFD_RELOC_V850_CALLT_16_16_OFFSET, ++ ++/* Used for relaxing indirect function calls. */ ++ BFD_RELOC_V850_LONGCALL, ++ ++/* Used for relaxing indirect jumps. */ ++ BFD_RELOC_V850_LONGJUMP, ++ ++/* Used to maintain alignment whilst relaxing. */ ++ BFD_RELOC_V850_ALIGN, ++ ++/* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu ++instructions. */ ++ BFD_RELOC_V850_LO16_SPLIT_OFFSET, ++ ++/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the ++instruction. */ ++ BFD_RELOC_MN10300_32_PCREL, ++ ++/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the ++instruction. */ ++ BFD_RELOC_MN10300_16_PCREL, ++ ++/* This is a 8bit DP reloc for the tms320c30, where the most ++significant 8 bits of a 24 bit word are placed into the least ++significant 8 bits of the opcode. */ ++ BFD_RELOC_TIC30_LDP, ++ ++/* This is a 7bit reloc for the tms320c54x, where the least ++significant 7 bits of a 16 bit word are placed into the least ++significant 7 bits of the opcode. */ ++ BFD_RELOC_TIC54X_PARTLS7, ++ ++/* This is a 9bit DP reloc for the tms320c54x, where the most ++significant 9 bits of a 16 bit word are placed into the least ++significant 9 bits of the opcode. */ ++ BFD_RELOC_TIC54X_PARTMS9, ++ ++/* This is an extended address 23-bit reloc for the tms320c54x. */ ++ BFD_RELOC_TIC54X_23, ++ ++/* This is a 16-bit reloc for the tms320c54x, where the least ++significant 16 bits of a 23-bit extended address are placed into ++the opcode. */ ++ BFD_RELOC_TIC54X_16_OF_23, ++ ++/* This is a reloc for the tms320c54x, where the most ++significant 7 bits of a 23-bit extended address are placed into ++the opcode. */ ++ BFD_RELOC_TIC54X_MS7_OF_23, ++ ++/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ ++ BFD_RELOC_FR30_48, ++ ++/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into ++two sections. */ ++ BFD_RELOC_FR30_20, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in ++4 bits. */ ++ BFD_RELOC_FR30_6_IN_4, ++ ++/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset ++into 8 bits. */ ++ BFD_RELOC_FR30_8_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset ++into 8 bits. */ ++ BFD_RELOC_FR30_9_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset ++into 8 bits. */ ++ BFD_RELOC_FR30_10_IN_8, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative ++short offset into 8 bits. */ ++ BFD_RELOC_FR30_9_PCREL, ++ ++/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative ++short offset into 11 bits. */ ++ BFD_RELOC_FR30_12_PCREL, ++ ++/* Motorola Mcore relocations. */ ++ BFD_RELOC_MCORE_PCREL_IMM8BY4, ++ BFD_RELOC_MCORE_PCREL_IMM11BY2, ++ BFD_RELOC_MCORE_PCREL_IMM4BY2, ++ BFD_RELOC_MCORE_PCREL_32, ++ BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, ++ BFD_RELOC_MCORE_RVA, ++ ++/* These are relocations for the GETA instruction. */ ++ BFD_RELOC_MMIX_GETA, ++ BFD_RELOC_MMIX_GETA_1, ++ BFD_RELOC_MMIX_GETA_2, ++ BFD_RELOC_MMIX_GETA_3, ++ ++/* These are relocations for a conditional branch instruction. */ ++ BFD_RELOC_MMIX_CBRANCH, ++ BFD_RELOC_MMIX_CBRANCH_J, ++ BFD_RELOC_MMIX_CBRANCH_1, ++ BFD_RELOC_MMIX_CBRANCH_2, ++ BFD_RELOC_MMIX_CBRANCH_3, ++ ++/* These are relocations for the PUSHJ instruction. */ ++ BFD_RELOC_MMIX_PUSHJ, ++ BFD_RELOC_MMIX_PUSHJ_1, ++ BFD_RELOC_MMIX_PUSHJ_2, ++ BFD_RELOC_MMIX_PUSHJ_3, ++ BFD_RELOC_MMIX_PUSHJ_STUBBABLE, ++ ++/* These are relocations for the JMP instruction. */ ++ BFD_RELOC_MMIX_JMP, ++ BFD_RELOC_MMIX_JMP_1, ++ BFD_RELOC_MMIX_JMP_2, ++ BFD_RELOC_MMIX_JMP_3, ++ ++/* This is a relocation for a relative address as in a GETA instruction or ++a branch. */ ++ BFD_RELOC_MMIX_ADDR19, ++ ++/* This is a relocation for a relative address as in a JMP instruction. */ ++ BFD_RELOC_MMIX_ADDR27, ++ ++/* This is a relocation for an instruction field that may be a general ++register or a value 0..255. */ ++ BFD_RELOC_MMIX_REG_OR_BYTE, ++ ++/* This is a relocation for an instruction field that may be a general ++register. */ ++ BFD_RELOC_MMIX_REG, ++ ++/* This is a relocation for two instruction fields holding a register and ++an offset, the equivalent of the relocation. */ ++ BFD_RELOC_MMIX_BASE_PLUS_OFFSET, ++ ++/* This relocation is an assertion that the expression is not allocated as ++a global register. It does not modify contents. */ ++ BFD_RELOC_MMIX_LOCAL, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative ++short offset into 7 bits. */ ++ BFD_RELOC_AVR_7_PCREL, ++ ++/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative ++short offset into 12 bits. */ ++ BFD_RELOC_AVR_13_PCREL, ++ ++/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually ++program memory address) into 16 bits. */ ++ BFD_RELOC_AVR_16_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually ++data memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_LO8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit ++of data memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HI8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit ++of program memory address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HH8_LDI, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(usually data memory address) into 8 bit immediate value of SUBI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 8 bit of data memory address) into 8 bit immediate value of ++SUBI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(most high 8 bit of program memory address) into 8 bit immediate value ++of LDI or SUBI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually ++command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit ++of command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit ++of command address) into 8 bit immediate value of LDI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_PM, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(usually command address) into 8 bit immediate value of SUBI insn. */ ++ BFD_RELOC_AVR_LO8_LDI_PM_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 8 bit of 16 bit command address) into 8 bit immediate value ++of SUBI insn. */ ++ BFD_RELOC_AVR_HI8_LDI_PM_NEG, ++ ++/* This is a 16 bit reloc for the AVR that stores negated 8 bit value ++(high 6 bit of 22 bit command address) into 8 bit immediate ++value of SUBI insn. */ ++ BFD_RELOC_AVR_HH8_LDI_PM_NEG, ++ ++/* This is a 32 bit reloc for the AVR that stores 23 bit value ++into 22 bits. */ ++ BFD_RELOC_AVR_CALL, ++ ++/* This is a 16 bit reloc for the AVR that stores all needed bits ++for absolute addressing with ldi with overflow check to linktime */ ++ BFD_RELOC_AVR_LDI, ++ ++/* This is a 6 bit reloc for the AVR that stores offset for ldd/std ++instructions */ ++ BFD_RELOC_AVR_6, ++ ++/* This is a 6 bit reloc for the AVR that stores offset for adiw/sbiw ++instructions */ ++ BFD_RELOC_AVR_6_ADIW, ++ ++/* Direct 12 bit. */ ++ BFD_RELOC_390_12, ++ ++/* 12 bit GOT offset. */ ++ BFD_RELOC_390_GOT12, ++ ++/* 32 bit PC relative PLT address. */ ++ BFD_RELOC_390_PLT32, ++ ++/* Copy symbol at runtime. */ ++ BFD_RELOC_390_COPY, ++ ++/* Create GOT entry. */ ++ BFD_RELOC_390_GLOB_DAT, ++ ++/* Create PLT entry. */ ++ BFD_RELOC_390_JMP_SLOT, ++ ++/* Adjust by program base. */ ++ BFD_RELOC_390_RELATIVE, ++ ++/* 32 bit PC relative offset to GOT. */ ++ BFD_RELOC_390_GOTPC, ++ ++/* 16 bit GOT offset. */ ++ BFD_RELOC_390_GOT16, ++ ++/* PC relative 16 bit shifted by 1. */ ++ BFD_RELOC_390_PC16DBL, ++ ++/* 16 bit PC rel. PLT shifted by 1. */ ++ BFD_RELOC_390_PLT16DBL, ++ ++/* PC relative 32 bit shifted by 1. */ ++ BFD_RELOC_390_PC32DBL, ++ ++/* 32 bit PC rel. PLT shifted by 1. */ ++ BFD_RELOC_390_PLT32DBL, ++ ++/* 32 bit PC rel. GOT shifted by 1. */ ++ BFD_RELOC_390_GOTPCDBL, ++ ++/* 64 bit GOT offset. */ ++ BFD_RELOC_390_GOT64, ++ ++/* 64 bit PC relative PLT address. */ ++ BFD_RELOC_390_PLT64, ++ ++/* 32 bit rel. offset to GOT entry. */ ++ BFD_RELOC_390_GOTENT, ++ ++/* 64 bit offset to GOT. */ ++ BFD_RELOC_390_GOTOFF64, ++ ++/* 12-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT12, ++ ++/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT16, ++ ++/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT32, ++ ++/* 64-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLT64, ++ ++/* 32-bit rel. offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_390_GOTPLTENT, ++ ++/* 16-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF16, ++ ++/* 32-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF32, ++ ++/* 64-bit rel. offset from the GOT to a PLT entry. */ ++ BFD_RELOC_390_PLTOFF64, ++ ++/* s390 tls relocations. */ ++ BFD_RELOC_390_TLS_LOAD, ++ BFD_RELOC_390_TLS_GDCALL, ++ BFD_RELOC_390_TLS_LDCALL, ++ BFD_RELOC_390_TLS_GD32, ++ BFD_RELOC_390_TLS_GD64, ++ BFD_RELOC_390_TLS_GOTIE12, ++ BFD_RELOC_390_TLS_GOTIE32, ++ BFD_RELOC_390_TLS_GOTIE64, ++ BFD_RELOC_390_TLS_LDM32, ++ BFD_RELOC_390_TLS_LDM64, ++ BFD_RELOC_390_TLS_IE32, ++ BFD_RELOC_390_TLS_IE64, ++ BFD_RELOC_390_TLS_IEENT, ++ BFD_RELOC_390_TLS_LE32, ++ BFD_RELOC_390_TLS_LE64, ++ BFD_RELOC_390_TLS_LDO32, ++ BFD_RELOC_390_TLS_LDO64, ++ BFD_RELOC_390_TLS_DTPMOD, ++ BFD_RELOC_390_TLS_DTPOFF, ++ BFD_RELOC_390_TLS_TPOFF, ++ ++/* Long displacement extension. */ ++ BFD_RELOC_390_20, ++ BFD_RELOC_390_GOT20, ++ BFD_RELOC_390_GOTPLT20, ++ BFD_RELOC_390_TLS_GOTIE20, ++ ++/* Scenix IP2K - 9-bit register number / data address */ ++ BFD_RELOC_IP2K_FR9, ++ ++/* Scenix IP2K - 4-bit register/data bank number */ ++ BFD_RELOC_IP2K_BANK, ++ ++/* Scenix IP2K - low 13 bits of instruction word address */ ++ BFD_RELOC_IP2K_ADDR16CJP, ++ ++/* Scenix IP2K - high 3 bits of instruction word address */ ++ BFD_RELOC_IP2K_PAGE3, ++ ++/* Scenix IP2K - ext/low/high 8 bits of data address */ ++ BFD_RELOC_IP2K_LO8DATA, ++ BFD_RELOC_IP2K_HI8DATA, ++ BFD_RELOC_IP2K_EX8DATA, ++ ++/* Scenix IP2K - low/high 8 bits of instruction word address */ ++ BFD_RELOC_IP2K_LO8INSN, ++ BFD_RELOC_IP2K_HI8INSN, ++ ++/* Scenix IP2K - even/odd PC modifier to modify snb pcl.0 */ ++ BFD_RELOC_IP2K_PC_SKIP, ++ ++/* Scenix IP2K - 16 bit word address in text section. */ ++ BFD_RELOC_IP2K_TEXT, ++ ++/* Scenix IP2K - 7-bit sp or dp offset */ ++ BFD_RELOC_IP2K_FR_OFFSET, ++ ++/* Scenix VPE4K coprocessor - data/insn-space addressing */ ++ BFD_RELOC_VPE4KMATH_DATA, ++ BFD_RELOC_VPE4KMATH_INSN, ++ ++/* These two relocations are used by the linker to determine which of ++the entries in a C++ virtual function table are actually used. When ++the --gc-sections option is given, the linker will zero out the entries ++that are not used, so that the code for those functions need not be ++included in the output. ++ ++VTABLE_INHERIT is a zero-space relocation used to describe to the ++linker the inheritance tree of a C++ virtual function table. The ++relocation's symbol should be the parent class' vtable, and the ++relocation should be located at the child vtable. ++ ++VTABLE_ENTRY is a zero-space relocation that describes the use of a ++virtual function table entry. The reloc's symbol should refer to the ++table of the class mentioned in the code. Off of that base, an offset ++describes the entry that is being used. For Rela hosts, this offset ++is stored in the reloc's addend. For Rel hosts, we are forced to put ++this offset in the reloc's section offset. */ ++ BFD_RELOC_VTABLE_INHERIT, ++ BFD_RELOC_VTABLE_ENTRY, ++ ++/* Intel IA64 Relocations. */ ++ BFD_RELOC_IA64_IMM14, ++ BFD_RELOC_IA64_IMM22, ++ BFD_RELOC_IA64_IMM64, ++ BFD_RELOC_IA64_DIR32MSB, ++ BFD_RELOC_IA64_DIR32LSB, ++ BFD_RELOC_IA64_DIR64MSB, ++ BFD_RELOC_IA64_DIR64LSB, ++ BFD_RELOC_IA64_GPREL22, ++ BFD_RELOC_IA64_GPREL64I, ++ BFD_RELOC_IA64_GPREL32MSB, ++ BFD_RELOC_IA64_GPREL32LSB, ++ BFD_RELOC_IA64_GPREL64MSB, ++ BFD_RELOC_IA64_GPREL64LSB, ++ BFD_RELOC_IA64_LTOFF22, ++ BFD_RELOC_IA64_LTOFF64I, ++ BFD_RELOC_IA64_PLTOFF22, ++ BFD_RELOC_IA64_PLTOFF64I, ++ BFD_RELOC_IA64_PLTOFF64MSB, ++ BFD_RELOC_IA64_PLTOFF64LSB, ++ BFD_RELOC_IA64_FPTR64I, ++ BFD_RELOC_IA64_FPTR32MSB, ++ BFD_RELOC_IA64_FPTR32LSB, ++ BFD_RELOC_IA64_FPTR64MSB, ++ BFD_RELOC_IA64_FPTR64LSB, ++ BFD_RELOC_IA64_PCREL21B, ++ BFD_RELOC_IA64_PCREL21BI, ++ BFD_RELOC_IA64_PCREL21M, ++ BFD_RELOC_IA64_PCREL21F, ++ BFD_RELOC_IA64_PCREL22, ++ BFD_RELOC_IA64_PCREL60B, ++ BFD_RELOC_IA64_PCREL64I, ++ BFD_RELOC_IA64_PCREL32MSB, ++ BFD_RELOC_IA64_PCREL32LSB, ++ BFD_RELOC_IA64_PCREL64MSB, ++ BFD_RELOC_IA64_PCREL64LSB, ++ BFD_RELOC_IA64_LTOFF_FPTR22, ++ BFD_RELOC_IA64_LTOFF_FPTR64I, ++ BFD_RELOC_IA64_LTOFF_FPTR32MSB, ++ BFD_RELOC_IA64_LTOFF_FPTR32LSB, ++ BFD_RELOC_IA64_LTOFF_FPTR64MSB, ++ BFD_RELOC_IA64_LTOFF_FPTR64LSB, ++ BFD_RELOC_IA64_SEGREL32MSB, ++ BFD_RELOC_IA64_SEGREL32LSB, ++ BFD_RELOC_IA64_SEGREL64MSB, ++ BFD_RELOC_IA64_SEGREL64LSB, ++ BFD_RELOC_IA64_SECREL32MSB, ++ BFD_RELOC_IA64_SECREL32LSB, ++ BFD_RELOC_IA64_SECREL64MSB, ++ BFD_RELOC_IA64_SECREL64LSB, ++ BFD_RELOC_IA64_REL32MSB, ++ BFD_RELOC_IA64_REL32LSB, ++ BFD_RELOC_IA64_REL64MSB, ++ BFD_RELOC_IA64_REL64LSB, ++ BFD_RELOC_IA64_LTV32MSB, ++ BFD_RELOC_IA64_LTV32LSB, ++ BFD_RELOC_IA64_LTV64MSB, ++ BFD_RELOC_IA64_LTV64LSB, ++ BFD_RELOC_IA64_IPLTMSB, ++ BFD_RELOC_IA64_IPLTLSB, ++ BFD_RELOC_IA64_COPY, ++ BFD_RELOC_IA64_LTOFF22X, ++ BFD_RELOC_IA64_LDXMOV, ++ BFD_RELOC_IA64_TPREL14, ++ BFD_RELOC_IA64_TPREL22, ++ BFD_RELOC_IA64_TPREL64I, ++ BFD_RELOC_IA64_TPREL64MSB, ++ BFD_RELOC_IA64_TPREL64LSB, ++ BFD_RELOC_IA64_LTOFF_TPREL22, ++ BFD_RELOC_IA64_DTPMOD64MSB, ++ BFD_RELOC_IA64_DTPMOD64LSB, ++ BFD_RELOC_IA64_LTOFF_DTPMOD22, ++ BFD_RELOC_IA64_DTPREL14, ++ BFD_RELOC_IA64_DTPREL22, ++ BFD_RELOC_IA64_DTPREL64I, ++ BFD_RELOC_IA64_DTPREL32MSB, ++ BFD_RELOC_IA64_DTPREL32LSB, ++ BFD_RELOC_IA64_DTPREL64MSB, ++ BFD_RELOC_IA64_DTPREL64LSB, ++ BFD_RELOC_IA64_LTOFF_DTPREL22, ++ ++/* Motorola 68HC11 reloc. ++This is the 8 bit high part of an absolute address. */ ++ BFD_RELOC_M68HC11_HI8, ++ ++/* Motorola 68HC11 reloc. ++This is the 8 bit low part of an absolute address. */ ++ BFD_RELOC_M68HC11_LO8, ++ ++/* Motorola 68HC11 reloc. ++This is the 3 bit of a value. */ ++ BFD_RELOC_M68HC11_3B, ++ ++/* Motorola 68HC11 reloc. ++This reloc marks the beginning of a jump/call instruction. ++It is used for linker relaxation to correctly identify beginning ++of instruction and change some branches to use PC-relative ++addressing mode. */ ++ BFD_RELOC_M68HC11_RL_JUMP, ++ ++/* Motorola 68HC11 reloc. ++This reloc marks a group of several instructions that gcc generates ++and for which the linker relaxation pass can modify and/or remove ++some of them. */ ++ BFD_RELOC_M68HC11_RL_GROUP, ++ ++/* Motorola 68HC11 reloc. ++This is the 16-bit lower part of an address. It is used for 'call' ++instruction to specify the symbol address without any special ++transformation (due to memory bank window). */ ++ BFD_RELOC_M68HC11_LO16, ++ ++/* Motorola 68HC11 reloc. ++This is a 8-bit reloc that specifies the page number of an address. ++It is used by 'call' instruction to specify the page number of ++the symbol. */ ++ BFD_RELOC_M68HC11_PAGE, ++ ++/* Motorola 68HC11 reloc. ++This is a 24-bit reloc that represents the address with a 16-bit ++value and a 8-bit page number. The symbol address is transformed ++to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ ++ BFD_RELOC_M68HC11_24, ++ ++/* Motorola 68HC12 reloc. ++This is the 5 bits of a value. */ ++ BFD_RELOC_M68HC12_5B, ++ ++/* NS CR16C Relocations. */ ++ BFD_RELOC_16C_NUM08, ++ BFD_RELOC_16C_NUM08_C, ++ BFD_RELOC_16C_NUM16, ++ BFD_RELOC_16C_NUM16_C, ++ BFD_RELOC_16C_NUM32, ++ BFD_RELOC_16C_NUM32_C, ++ BFD_RELOC_16C_DISP04, ++ BFD_RELOC_16C_DISP04_C, ++ BFD_RELOC_16C_DISP08, ++ BFD_RELOC_16C_DISP08_C, ++ BFD_RELOC_16C_DISP16, ++ BFD_RELOC_16C_DISP16_C, ++ BFD_RELOC_16C_DISP24, ++ BFD_RELOC_16C_DISP24_C, ++ BFD_RELOC_16C_DISP24a, ++ BFD_RELOC_16C_DISP24a_C, ++ BFD_RELOC_16C_REG04, ++ BFD_RELOC_16C_REG04_C, ++ BFD_RELOC_16C_REG04a, ++ BFD_RELOC_16C_REG04a_C, ++ BFD_RELOC_16C_REG14, ++ BFD_RELOC_16C_REG14_C, ++ BFD_RELOC_16C_REG16, ++ BFD_RELOC_16C_REG16_C, ++ BFD_RELOC_16C_REG20, ++ BFD_RELOC_16C_REG20_C, ++ BFD_RELOC_16C_ABS20, ++ BFD_RELOC_16C_ABS20_C, ++ BFD_RELOC_16C_ABS24, ++ BFD_RELOC_16C_ABS24_C, ++ BFD_RELOC_16C_IMM04, ++ BFD_RELOC_16C_IMM04_C, ++ BFD_RELOC_16C_IMM16, ++ BFD_RELOC_16C_IMM16_C, ++ BFD_RELOC_16C_IMM20, ++ BFD_RELOC_16C_IMM20_C, ++ BFD_RELOC_16C_IMM24, ++ BFD_RELOC_16C_IMM24_C, ++ BFD_RELOC_16C_IMM32, ++ BFD_RELOC_16C_IMM32_C, ++ ++/* NS CRX Relocations. */ ++ BFD_RELOC_CRX_REL4, ++ BFD_RELOC_CRX_REL8, ++ BFD_RELOC_CRX_REL8_CMP, ++ BFD_RELOC_CRX_REL16, ++ BFD_RELOC_CRX_REL24, ++ BFD_RELOC_CRX_REL32, ++ BFD_RELOC_CRX_REGREL12, ++ BFD_RELOC_CRX_REGREL22, ++ BFD_RELOC_CRX_REGREL28, ++ BFD_RELOC_CRX_REGREL32, ++ BFD_RELOC_CRX_ABS16, ++ BFD_RELOC_CRX_ABS32, ++ BFD_RELOC_CRX_NUM8, ++ BFD_RELOC_CRX_NUM16, ++ BFD_RELOC_CRX_NUM32, ++ BFD_RELOC_CRX_IMM16, ++ BFD_RELOC_CRX_IMM32, ++ BFD_RELOC_CRX_SWITCH8, ++ BFD_RELOC_CRX_SWITCH16, ++ BFD_RELOC_CRX_SWITCH32, ++ ++/* These relocs are only used within the CRIS assembler. They are not ++(at present) written to any object files. */ ++ BFD_RELOC_CRIS_BDISP8, ++ BFD_RELOC_CRIS_UNSIGNED_5, ++ BFD_RELOC_CRIS_SIGNED_6, ++ BFD_RELOC_CRIS_UNSIGNED_6, ++ BFD_RELOC_CRIS_SIGNED_8, ++ BFD_RELOC_CRIS_UNSIGNED_8, ++ BFD_RELOC_CRIS_SIGNED_16, ++ BFD_RELOC_CRIS_UNSIGNED_16, ++ BFD_RELOC_CRIS_LAPCQ_OFFSET, ++ BFD_RELOC_CRIS_UNSIGNED_4, ++ ++/* Relocs used in ELF shared libraries for CRIS. */ ++ BFD_RELOC_CRIS_COPY, ++ BFD_RELOC_CRIS_GLOB_DAT, ++ BFD_RELOC_CRIS_JUMP_SLOT, ++ BFD_RELOC_CRIS_RELATIVE, ++ ++/* 32-bit offset to symbol-entry within GOT. */ ++ BFD_RELOC_CRIS_32_GOT, ++ ++/* 16-bit offset to symbol-entry within GOT. */ ++ BFD_RELOC_CRIS_16_GOT, ++ ++/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_CRIS_32_GOTPLT, ++ ++/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ ++ BFD_RELOC_CRIS_16_GOTPLT, ++ ++/* 32-bit offset to symbol, relative to GOT. */ ++ BFD_RELOC_CRIS_32_GOTREL, ++ ++/* 32-bit offset to symbol with PLT entry, relative to GOT. */ ++ BFD_RELOC_CRIS_32_PLT_GOTREL, ++ ++/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ ++ BFD_RELOC_CRIS_32_PLT_PCREL, ++ ++/* Intel i860 Relocations. */ ++ BFD_RELOC_860_COPY, ++ BFD_RELOC_860_GLOB_DAT, ++ BFD_RELOC_860_JUMP_SLOT, ++ BFD_RELOC_860_RELATIVE, ++ BFD_RELOC_860_PC26, ++ BFD_RELOC_860_PLT26, ++ BFD_RELOC_860_PC16, ++ BFD_RELOC_860_LOW0, ++ BFD_RELOC_860_SPLIT0, ++ BFD_RELOC_860_LOW1, ++ BFD_RELOC_860_SPLIT1, ++ BFD_RELOC_860_LOW2, ++ BFD_RELOC_860_SPLIT2, ++ BFD_RELOC_860_LOW3, ++ BFD_RELOC_860_LOGOT0, ++ BFD_RELOC_860_SPGOT0, ++ BFD_RELOC_860_LOGOT1, ++ BFD_RELOC_860_SPGOT1, ++ BFD_RELOC_860_LOGOTOFF0, ++ BFD_RELOC_860_SPGOTOFF0, ++ BFD_RELOC_860_LOGOTOFF1, ++ BFD_RELOC_860_SPGOTOFF1, ++ BFD_RELOC_860_LOGOTOFF2, ++ BFD_RELOC_860_LOGOTOFF3, ++ BFD_RELOC_860_LOPC, ++ BFD_RELOC_860_HIGHADJ, ++ BFD_RELOC_860_HAGOT, ++ BFD_RELOC_860_HAGOTOFF, ++ BFD_RELOC_860_HAPC, ++ BFD_RELOC_860_HIGH, ++ BFD_RELOC_860_HIGOT, ++ BFD_RELOC_860_HIGOTOFF, ++ ++/* OpenRISC Relocations. */ ++ BFD_RELOC_OPENRISC_ABS_26, ++ BFD_RELOC_OPENRISC_REL_26, ++ ++/* H8 elf Relocations. */ ++ BFD_RELOC_H8_DIR16A8, ++ BFD_RELOC_H8_DIR16R8, ++ BFD_RELOC_H8_DIR24A8, ++ BFD_RELOC_H8_DIR24R8, ++ BFD_RELOC_H8_DIR32A16, ++ ++/* Sony Xstormy16 Relocations. */ ++ BFD_RELOC_XSTORMY16_REL_12, ++ BFD_RELOC_XSTORMY16_12, ++ BFD_RELOC_XSTORMY16_24, ++ BFD_RELOC_XSTORMY16_FPTR16, ++ ++/* Relocations used by VAX ELF. */ ++ BFD_RELOC_VAX_GLOB_DAT, ++ BFD_RELOC_VAX_JMP_SLOT, ++ BFD_RELOC_VAX_RELATIVE, ++ ++/* Morpho MS1 - 16 bit immediate relocation. */ ++ BFD_RELOC_MS1_PC16, ++ ++/* Morpho MS1 - Hi 16 bits of an address. */ ++ BFD_RELOC_MS1_HI16, ++ ++/* Morpho MS1 - Low 16 bits of an address. */ ++ BFD_RELOC_MS1_LO16, ++ ++/* Morpho MS1 - Used to tell the linker which vtable entries are used. */ ++ BFD_RELOC_MS1_GNU_VTINHERIT, ++ ++/* Morpho MS1 - Used to tell the linker which vtable entries are used. */ ++ BFD_RELOC_MS1_GNU_VTENTRY, ++ ++/* msp430 specific relocation codes */ ++ BFD_RELOC_MSP430_10_PCREL, ++ BFD_RELOC_MSP430_16_PCREL, ++ BFD_RELOC_MSP430_16, ++ BFD_RELOC_MSP430_16_PCREL_BYTE, ++ BFD_RELOC_MSP430_16_BYTE, ++ BFD_RELOC_MSP430_2X_PCREL, ++ BFD_RELOC_MSP430_RL_PCREL, ++ ++/* IQ2000 Relocations. */ ++ BFD_RELOC_IQ2000_OFFSET_16, ++ BFD_RELOC_IQ2000_OFFSET_21, ++ BFD_RELOC_IQ2000_UHI16, ++ ++/* Special Xtensa relocation used only by PLT entries in ELF shared ++objects to indicate that the runtime linker should set the value ++to one of its own internal functions or data structures. */ ++ BFD_RELOC_XTENSA_RTLD, ++ ++/* Xtensa relocations for ELF shared objects. */ ++ BFD_RELOC_XTENSA_GLOB_DAT, ++ BFD_RELOC_XTENSA_JMP_SLOT, ++ BFD_RELOC_XTENSA_RELATIVE, ++ ++/* Xtensa relocation used in ELF object files for symbols that may require ++PLT entries. Otherwise, this is just a generic 32-bit relocation. */ ++ BFD_RELOC_XTENSA_PLT, ++ ++/* Xtensa relocations to mark the difference of two local symbols. ++These are only needed to support linker relaxation and can be ignored ++when not relaxing. The field is set to the value of the difference ++assuming no relaxation. The relocation encodes the position of the ++first symbol so the linker can determine whether to adjust the field ++value. */ ++ BFD_RELOC_XTENSA_DIFF8, ++ BFD_RELOC_XTENSA_DIFF16, ++ BFD_RELOC_XTENSA_DIFF32, ++ ++/* Generic Xtensa relocations for instruction operands. Only the slot ++number is encoded in the relocation. The relocation applies to the ++last PC-relative immediate operand, or if there are no PC-relative ++immediates, to the last immediate operand. */ ++ BFD_RELOC_XTENSA_SLOT0_OP, ++ BFD_RELOC_XTENSA_SLOT1_OP, ++ BFD_RELOC_XTENSA_SLOT2_OP, ++ BFD_RELOC_XTENSA_SLOT3_OP, ++ BFD_RELOC_XTENSA_SLOT4_OP, ++ BFD_RELOC_XTENSA_SLOT5_OP, ++ BFD_RELOC_XTENSA_SLOT6_OP, ++ BFD_RELOC_XTENSA_SLOT7_OP, ++ BFD_RELOC_XTENSA_SLOT8_OP, ++ BFD_RELOC_XTENSA_SLOT9_OP, ++ BFD_RELOC_XTENSA_SLOT10_OP, ++ BFD_RELOC_XTENSA_SLOT11_OP, ++ BFD_RELOC_XTENSA_SLOT12_OP, ++ BFD_RELOC_XTENSA_SLOT13_OP, ++ BFD_RELOC_XTENSA_SLOT14_OP, ++ ++/* Alternate Xtensa relocations. Only the slot is encoded in the ++relocation. The meaning of these relocations is opcode-specific. */ ++ BFD_RELOC_XTENSA_SLOT0_ALT, ++ BFD_RELOC_XTENSA_SLOT1_ALT, ++ BFD_RELOC_XTENSA_SLOT2_ALT, ++ BFD_RELOC_XTENSA_SLOT3_ALT, ++ BFD_RELOC_XTENSA_SLOT4_ALT, ++ BFD_RELOC_XTENSA_SLOT5_ALT, ++ BFD_RELOC_XTENSA_SLOT6_ALT, ++ BFD_RELOC_XTENSA_SLOT7_ALT, ++ BFD_RELOC_XTENSA_SLOT8_ALT, ++ BFD_RELOC_XTENSA_SLOT9_ALT, ++ BFD_RELOC_XTENSA_SLOT10_ALT, ++ BFD_RELOC_XTENSA_SLOT11_ALT, ++ BFD_RELOC_XTENSA_SLOT12_ALT, ++ BFD_RELOC_XTENSA_SLOT13_ALT, ++ BFD_RELOC_XTENSA_SLOT14_ALT, ++ ++/* Xtensa relocations for backward compatibility. These have all been ++replaced by BFD_RELOC_XTENSA_SLOT0_OP. */ ++ BFD_RELOC_XTENSA_OP0, ++ BFD_RELOC_XTENSA_OP1, ++ BFD_RELOC_XTENSA_OP2, ++ ++/* Xtensa relocation to mark that the assembler expanded the ++instructions from an original target. The expansion size is ++encoded in the reloc size. */ ++ BFD_RELOC_XTENSA_ASM_EXPAND, ++ ++/* Xtensa relocation to mark that the linker should simplify ++assembler-expanded instructions. This is commonly used ++internally by the linker after analysis of a ++BFD_RELOC_XTENSA_ASM_EXPAND. */ ++ BFD_RELOC_XTENSA_ASM_SIMPLIFY, ++ BFD_RELOC_UNUSED }; ++typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; ++reloc_howto_type *bfd_reloc_type_lookup ++ (bfd *abfd, bfd_reloc_code_real_type code); ++ ++const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); ++ ++/* Extracted from syms.c. */ ++ ++typedef struct bfd_symbol ++{ ++ /* A pointer to the BFD which owns the symbol. This information ++ is necessary so that a back end can work out what additional ++ information (invisible to the application writer) is carried ++ with the symbol. ++ ++ This field is *almost* redundant, since you can use section->owner ++ instead, except that some symbols point to the global sections ++ bfd_{abs,com,und}_section. This could be fixed by making ++ these globals be per-bfd (or per-target-flavor). FIXME. */ ++ struct bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ ++ ++ /* The text of the symbol. The name is left alone, and not copied; the ++ application may not alter it. */ ++ const char *name; ++ ++ /* The value of the symbol. This really should be a union of a ++ numeric value with a pointer, since some flags indicate that ++ a pointer to another symbol is stored here. */ ++ symvalue value; ++ ++ /* Attributes of a symbol. */ ++#define BSF_NO_FLAGS 0x00 ++ ++ /* The symbol has local scope; <> in <>. The value ++ is the offset into the section of the data. */ ++#define BSF_LOCAL 0x01 ++ ++ /* The symbol has global scope; initialized data in <>. The ++ value is the offset into the section of the data. */ ++#define BSF_GLOBAL 0x02 ++ ++ /* The symbol has global scope and is exported. The value is ++ the offset into the section of the data. */ ++#define BSF_EXPORT BSF_GLOBAL /* No real difference. */ ++ ++ /* A normal C symbol would be one of: ++ <>, <>, <> or ++ <>. */ ++ ++ /* The symbol is a debugging record. The value has an arbitrary ++ meaning, unless BSF_DEBUGGING_RELOC is also set. */ ++#define BSF_DEBUGGING 0x08 ++ ++ /* The symbol denotes a function entry point. Used in ELF, ++ perhaps others someday. */ ++#define BSF_FUNCTION 0x10 ++ ++ /* Used by the linker. */ ++#define BSF_KEEP 0x20 ++#define BSF_KEEP_G 0x40 ++ ++ /* A weak global symbol, overridable without warnings by ++ a regular global symbol of the same name. */ ++#define BSF_WEAK 0x80 ++ ++ /* This symbol was created to point to a section, e.g. ELF's ++ STT_SECTION symbols. */ ++#define BSF_SECTION_SYM 0x100 ++ ++ /* The symbol used to be a common symbol, but now it is ++ allocated. */ ++#define BSF_OLD_COMMON 0x200 ++ ++ /* The default value for common data. */ ++#define BFD_FORT_COMM_DEFAULT_VALUE 0 ++ ++ /* In some files the type of a symbol sometimes alters its ++ location in an output file - ie in coff a <> symbol ++ which is also <> symbol appears where it was ++ declared and not at the end of a section. This bit is set ++ by the target BFD part to convey this information. */ ++#define BSF_NOT_AT_END 0x400 ++ ++ /* Signal that the symbol is the label of constructor section. */ ++#define BSF_CONSTRUCTOR 0x800 ++ ++ /* Signal that the symbol is a warning symbol. The name is a ++ warning. The name of the next symbol is the one to warn about; ++ if a reference is made to a symbol with the same name as the next ++ symbol, a warning is issued by the linker. */ ++#define BSF_WARNING 0x1000 ++ ++ /* Signal that the symbol is indirect. This symbol is an indirect ++ pointer to the symbol with the same name as the next symbol. */ ++#define BSF_INDIRECT 0x2000 ++ ++ /* BSF_FILE marks symbols that contain a file name. This is used ++ for ELF STT_FILE symbols. */ ++#define BSF_FILE 0x4000 ++ ++ /* Symbol is from dynamic linking information. */ ++#define BSF_DYNAMIC 0x8000 ++ ++ /* The symbol denotes a data object. Used in ELF, and perhaps ++ others someday. */ ++#define BSF_OBJECT 0x10000 ++ ++ /* This symbol is a debugging symbol. The value is the offset ++ into the section of the data. BSF_DEBUGGING should be set ++ as well. */ ++#define BSF_DEBUGGING_RELOC 0x20000 ++ ++ /* This symbol is thread local. Used in ELF. */ ++#define BSF_THREAD_LOCAL 0x40000 ++ ++ flagword flags; ++ ++ /* A pointer to the section to which this symbol is ++ relative. This will always be non NULL, there are special ++ sections for undefined and absolute symbols. */ ++ struct bfd_section *section; ++ ++ /* Back end special data. */ ++ union ++ { ++ void *p; ++ bfd_vma i; ++ } ++ udata; ++} ++asymbol; ++ ++#define bfd_get_symtab_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) ++ ++bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); ++ ++bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); ++ ++#define bfd_is_local_label_name(abfd, name) \ ++ BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) ++ ++bfd_boolean bfd_is_target_special_symbol (bfd *abfd, asymbol *sym); ++ ++#define bfd_is_target_special_symbol(abfd, sym) \ ++ BFD_SEND (abfd, _bfd_is_target_special_symbol, (abfd, sym)) ++ ++#define bfd_canonicalize_symtab(abfd, location) \ ++ BFD_SEND (abfd, _bfd_canonicalize_symtab, (abfd, location)) ++ ++bfd_boolean bfd_set_symtab ++ (bfd *abfd, asymbol **location, unsigned int count); ++ ++void bfd_print_symbol_vandf (bfd *abfd, void *file, asymbol *symbol); ++ ++#define bfd_make_empty_symbol(abfd) \ ++ BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) ++ ++asymbol *_bfd_generic_make_empty_symbol (bfd *); ++ ++#define bfd_make_debug_symbol(abfd,ptr,size) \ ++ BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) ++ ++int bfd_decode_symclass (asymbol *symbol); ++ ++bfd_boolean bfd_is_undefined_symclass (int symclass); ++ ++void bfd_symbol_info (asymbol *symbol, symbol_info *ret); ++ ++bfd_boolean bfd_copy_private_symbol_data ++ (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); ++ ++#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ ++ BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ ++ (ibfd, isymbol, obfd, osymbol)) ++ ++/* Extracted from bfd.c. */ ++struct bfd ++{ ++ /* A unique identifier of the BFD */ ++ unsigned int id; ++ ++ /* The filename the application opened the BFD with. */ ++ const char *filename; ++ ++ /* A pointer to the target jump table. */ ++ const struct bfd_target *xvec; ++ ++ /* The IOSTREAM, and corresponding IO vector that provide access ++ to the file backing the BFD. */ ++ void *iostream; ++ const struct bfd_iovec *iovec; ++ ++ /* Is the file descriptor being cached? That is, can it be closed as ++ needed, and re-opened when accessed later? */ ++ bfd_boolean cacheable; ++ ++ /* Marks whether there was a default target specified when the ++ BFD was opened. This is used to select which matching algorithm ++ to use to choose the back end. */ ++ bfd_boolean target_defaulted; ++ ++ /* The caching routines use these to maintain a ++ least-recently-used list of BFDs. */ ++ struct bfd *lru_prev, *lru_next; ++ ++ /* When a file is closed by the caching routines, BFD retains ++ state information on the file here... */ ++ ufile_ptr where; ++ ++ /* ... and here: (``once'' means at least once). */ ++ bfd_boolean opened_once; ++ ++ /* Set if we have a locally maintained mtime value, rather than ++ getting it from the file each time. */ ++ bfd_boolean mtime_set; ++ ++ /* File modified time, if mtime_set is TRUE. */ ++ long mtime; ++ ++ /* Reserved for an unimplemented file locking extension. */ ++ int ifd; ++ ++ /* The format which belongs to the BFD. (object, core, etc.) */ ++ bfd_format format; ++ ++ /* The direction with which the BFD was opened. */ ++ enum bfd_direction ++ { ++ no_direction = 0, ++ read_direction = 1, ++ write_direction = 2, ++ both_direction = 3 ++ } ++ direction; ++ ++ /* Format_specific flags. */ ++ flagword flags; ++ ++ /* Currently my_archive is tested before adding origin to ++ anything. I believe that this can become always an add of ++ origin, with origin set to 0 for non archive files. */ ++ ufile_ptr origin; ++ ++ /* Remember when output has begun, to stop strange things ++ from happening. */ ++ bfd_boolean output_has_begun; ++ ++ /* A hash table for section names. */ ++ struct bfd_hash_table section_htab; ++ ++ /* Pointer to linked list of sections. */ ++ struct bfd_section *sections; ++ ++ /* The last section on the section list. */ ++ struct bfd_section *section_last; ++ ++ /* The number of sections. */ ++ unsigned int section_count; ++ ++ /* Stuff only useful for object files: ++ The start address. */ ++ bfd_vma start_address; ++ ++ /* Used for input and output. */ ++ unsigned int symcount; ++ ++ /* Symbol table for output BFD (with symcount entries). */ ++ struct bfd_symbol **outsymbols; ++ ++ /* Used for slurped dynamic symbol tables. */ ++ unsigned int dynsymcount; ++ ++ /* Pointer to structure which contains architecture information. */ ++ const struct bfd_arch_info *arch_info; ++ ++ /* Flag set if symbols from this BFD should not be exported. */ ++ bfd_boolean no_export; ++ ++ /* Stuff only useful for archives. */ ++ void *arelt_data; ++ struct bfd *my_archive; /* The containing archive BFD. */ ++ struct bfd *next; /* The next BFD in the archive. */ ++ struct bfd *archive_head; /* The first BFD in the archive. */ ++ bfd_boolean has_armap; ++ ++ /* A chain of BFD structures involved in a link. */ ++ struct bfd *link_next; ++ ++ /* A field used by _bfd_generic_link_add_archive_symbols. This will ++ be used only for archive elements. */ ++ int archive_pass; ++ ++ /* Used by the back end to hold private data. */ ++ union ++ { ++ struct aout_data_struct *aout_data; ++ struct artdata *aout_ar_data; ++ struct _oasys_data *oasys_obj_data; ++ struct _oasys_ar_data *oasys_ar_data; ++ struct coff_tdata *coff_obj_data; ++ struct pe_tdata *pe_obj_data; ++ struct xcoff_tdata *xcoff_obj_data; ++ struct ecoff_tdata *ecoff_obj_data; ++ struct ieee_data_struct *ieee_data; ++ struct ieee_ar_data_struct *ieee_ar_data; ++ struct srec_data_struct *srec_data; ++ struct ihex_data_struct *ihex_data; ++ struct tekhex_data_struct *tekhex_data; ++ struct elf_obj_tdata *elf_obj_data; ++ struct nlm_obj_tdata *nlm_obj_data; ++ struct bout_data_struct *bout_data; ++ struct mmo_data_struct *mmo_data; ++ struct sun_core_struct *sun_core_data; ++ struct sco5_core_struct *sco5_core_data; ++ struct trad_core_struct *trad_core_data; ++ struct som_data_struct *som_data; ++ struct hpux_core_struct *hpux_core_data; ++ struct hppabsd_core_struct *hppabsd_core_data; ++ struct sgi_core_struct *sgi_core_data; ++ struct lynx_core_struct *lynx_core_data; ++ struct osf_core_struct *osf_core_data; ++ struct cisco_core_struct *cisco_core_data; ++ struct versados_data_struct *versados_data; ++ struct netbsd_core_struct *netbsd_core_data; ++ struct mach_o_data_struct *mach_o_data; ++ struct mach_o_fat_data_struct *mach_o_fat_data; ++ struct bfd_pef_data_struct *pef_data; ++ struct bfd_pef_xlib_data_struct *pef_xlib_data; ++ struct bfd_sym_data_struct *sym_data; ++ void *any; ++ } ++ tdata; ++ ++ /* Used by the application to hold private data. */ ++ void *usrdata; ++ ++ /* Where all the allocated stuff under this BFD goes. This is a ++ struct objalloc *, but we use void * to avoid requiring the inclusion ++ of objalloc.h. */ ++ void *memory; ++}; ++ ++typedef enum bfd_error ++{ ++ bfd_error_no_error = 0, ++ bfd_error_system_call, ++ bfd_error_invalid_target, ++ bfd_error_wrong_format, ++ bfd_error_wrong_object_format, ++ bfd_error_invalid_operation, ++ bfd_error_no_memory, ++ bfd_error_no_symbols, ++ bfd_error_no_armap, ++ bfd_error_no_more_archived_files, ++ bfd_error_malformed_archive, ++ bfd_error_file_not_recognized, ++ bfd_error_file_ambiguously_recognized, ++ bfd_error_no_contents, ++ bfd_error_nonrepresentable_section, ++ bfd_error_no_debug_section, ++ bfd_error_bad_value, ++ bfd_error_file_truncated, ++ bfd_error_file_too_big, ++ bfd_error_invalid_error_code ++} ++bfd_error_type; ++ ++bfd_error_type bfd_get_error (void); ++ ++void bfd_set_error (bfd_error_type error_tag); ++ ++const char *bfd_errmsg (bfd_error_type error_tag); ++ ++void bfd_perror (const char *message); ++ ++typedef void (*bfd_error_handler_type) (const char *, ...); ++ ++bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); ++ ++void bfd_set_error_program_name (const char *); ++ ++bfd_error_handler_type bfd_get_error_handler (void); ++ ++long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); ++ ++long bfd_canonicalize_reloc ++ (bfd *abfd, asection *sec, arelent **loc, asymbol **syms); ++ ++void bfd_set_reloc ++ (bfd *abfd, asection *sec, arelent **rel, unsigned int count); ++ ++bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); ++ ++int bfd_get_arch_size (bfd *abfd); ++ ++int bfd_get_sign_extend_vma (bfd *abfd); ++ ++bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); ++ ++unsigned int bfd_get_gp_size (bfd *abfd); ++ ++void bfd_set_gp_size (bfd *abfd, unsigned int i); ++ ++bfd_vma bfd_scan_vma (const char *string, const char **end, int base); ++ ++bfd_boolean bfd_copy_private_header_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_copy_private_header_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_copy_private_header_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_copy_private_bfd_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); ++ ++#define bfd_merge_private_bfd_data(ibfd, obfd) \ ++ BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ ++ (ibfd, obfd)) ++bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); ++ ++#define bfd_set_private_flags(abfd, flags) \ ++ BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) ++#define bfd_sizeof_headers(abfd, reloc) \ ++ BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) ++ ++#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \ ++ BFD_SEND (abfd, _bfd_find_nearest_line, \ ++ (abfd, sec, syms, off, file, func, line)) ++ ++#define bfd_find_line(abfd, syms, sym, file, line) \ ++ BFD_SEND (abfd, _bfd_find_line, \ ++ (abfd, syms, sym, file, line)) ++ ++#define bfd_find_inliner_info(abfd, file, func, line) \ ++ BFD_SEND (abfd, _bfd_find_inliner_info, \ ++ (abfd, file, func, line)) ++ ++#define bfd_debug_info_start(abfd) \ ++ BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) ++ ++#define bfd_debug_info_end(abfd) \ ++ BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) ++ ++#define bfd_debug_info_accumulate(abfd, section) \ ++ BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) ++ ++#define bfd_stat_arch_elt(abfd, stat) \ ++ BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) ++ ++#define bfd_update_armap_timestamp(abfd) \ ++ BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) ++ ++#define bfd_set_arch_mach(abfd, arch, mach)\ ++ BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) ++ ++#define bfd_relax_section(abfd, section, link_info, again) \ ++ BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) ++ ++#define bfd_gc_sections(abfd, link_info) \ ++ BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) ++ ++#define bfd_merge_sections(abfd, link_info) \ ++ BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) ++ ++#define bfd_is_group_section(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_is_group_section, (abfd, sec)) ++ ++#define bfd_discard_group(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) ++ ++#define bfd_link_hash_table_create(abfd) \ ++ BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd)) ++ ++#define bfd_link_hash_table_free(abfd, hash) \ ++ BFD_SEND (abfd, _bfd_link_hash_table_free, (hash)) ++ ++#define bfd_link_add_symbols(abfd, info) \ ++ BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info)) ++ ++#define bfd_link_just_syms(abfd, sec, info) \ ++ BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) ++ ++#define bfd_final_link(abfd, info) \ ++ BFD_SEND (abfd, _bfd_final_link, (abfd, info)) ++ ++#define bfd_free_cached_info(abfd) \ ++ BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) ++ ++#define bfd_get_dynamic_symtab_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) ++ ++#define bfd_print_private_bfd_data(abfd, file)\ ++ BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) ++ ++#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ ++ BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) ++ ++#define bfd_get_synthetic_symtab(abfd, count, syms, dyncount, dynsyms, ret) \ ++ BFD_SEND (abfd, _bfd_get_synthetic_symtab, (abfd, count, syms, \ ++ dyncount, dynsyms, ret)) ++ ++#define bfd_get_dynamic_reloc_upper_bound(abfd) \ ++ BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) ++ ++#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ ++ BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) ++ ++extern bfd_byte *bfd_get_relocated_section_contents ++ (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, ++ bfd_boolean, asymbol **); ++ ++bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); ++ ++struct bfd_preserve ++{ ++ void *marker; ++ void *tdata; ++ flagword flags; ++ const struct bfd_arch_info *arch_info; ++ struct bfd_section *sections; ++ struct bfd_section *section_last; ++ unsigned int section_count; ++ struct bfd_hash_table section_htab; ++}; ++ ++bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); ++ ++void bfd_preserve_restore (bfd *, struct bfd_preserve *); ++ ++void bfd_preserve_finish (bfd *, struct bfd_preserve *); ++ ++/* Extracted from archive.c. */ ++symindex bfd_get_next_mapent ++ (bfd *abfd, symindex previous, carsym **sym); ++ ++bfd_boolean bfd_set_archive_head (bfd *output, bfd *new_head); ++ ++bfd *bfd_openr_next_archived_file (bfd *archive, bfd *previous); ++ ++/* Extracted from corefile.c. */ ++const char *bfd_core_file_failing_command (bfd *abfd); ++ ++int bfd_core_file_failing_signal (bfd *abfd); ++ ++bfd_boolean core_file_matches_executable_p ++ (bfd *core_bfd, bfd *exec_bfd); ++ ++/* Extracted from targets.c. */ ++#define BFD_SEND(bfd, message, arglist) \ ++ ((*((bfd)->xvec->message)) arglist) ++ ++#ifdef DEBUG_BFD_SEND ++#undef BFD_SEND ++#define BFD_SEND(bfd, message, arglist) \ ++ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ ++ ((*((bfd)->xvec->message)) arglist) : \ ++ (bfd_assert (__FILE__,__LINE__), NULL)) ++#endif ++#define BFD_SEND_FMT(bfd, message, arglist) \ ++ (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) ++ ++#ifdef DEBUG_BFD_SEND ++#undef BFD_SEND_FMT ++#define BFD_SEND_FMT(bfd, message, arglist) \ ++ (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ ++ (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ ++ (bfd_assert (__FILE__,__LINE__), NULL)) ++#endif ++ ++enum bfd_flavour ++{ ++ bfd_target_unknown_flavour, ++ bfd_target_aout_flavour, ++ bfd_target_coff_flavour, ++ bfd_target_ecoff_flavour, ++ bfd_target_xcoff_flavour, ++ bfd_target_elf_flavour, ++ bfd_target_ieee_flavour, ++ bfd_target_nlm_flavour, ++ bfd_target_oasys_flavour, ++ bfd_target_tekhex_flavour, ++ bfd_target_srec_flavour, ++ bfd_target_ihex_flavour, ++ bfd_target_som_flavour, ++ bfd_target_os9k_flavour, ++ bfd_target_versados_flavour, ++ bfd_target_msdos_flavour, ++ bfd_target_ovax_flavour, ++ bfd_target_evax_flavour, ++ bfd_target_mmo_flavour, ++ bfd_target_mach_o_flavour, ++ bfd_target_pef_flavour, ++ bfd_target_pef_xlib_flavour, ++ bfd_target_sym_flavour ++}; ++ ++enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; ++ ++/* Forward declaration. */ ++typedef struct bfd_link_info _bfd_link_info; ++ ++typedef struct bfd_target ++{ ++ /* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */ ++ char *name; ++ ++ /* The "flavour" of a back end is a general indication about ++ the contents of a file. */ ++ enum bfd_flavour flavour; ++ ++ /* The order of bytes within the data area of a file. */ ++ enum bfd_endian byteorder; ++ ++ /* The order of bytes within the header parts of a file. */ ++ enum bfd_endian header_byteorder; ++ ++ /* A mask of all the flags which an executable may have set - ++ from the set <>, <>, ...<>. */ ++ flagword object_flags; ++ ++ /* A mask of all the flags which a section may have set - from ++ the set <>, <>, ...<>. */ ++ flagword section_flags; ++ ++ /* The character normally found at the front of a symbol. ++ (if any), perhaps `_'. */ ++ char symbol_leading_char; ++ ++ /* The pad character for file names within an archive header. */ ++ char ar_pad_char; ++ ++ /* The maximum number of characters in an archive header. */ ++ unsigned short ar_max_namelen; ++ ++ /* Entries for byte swapping for data. These are different from the ++ other entry points, since they don't take a BFD as the first argument. ++ Certain other handlers could do the same. */ ++ bfd_uint64_t (*bfd_getx64) (const void *); ++ bfd_int64_t (*bfd_getx_signed_64) (const void *); ++ void (*bfd_putx64) (bfd_uint64_t, void *); ++ bfd_vma (*bfd_getx32) (const void *); ++ bfd_signed_vma (*bfd_getx_signed_32) (const void *); ++ void (*bfd_putx32) (bfd_vma, void *); ++ bfd_vma (*bfd_getx16) (const void *); ++ bfd_signed_vma (*bfd_getx_signed_16) (const void *); ++ void (*bfd_putx16) (bfd_vma, void *); ++ ++ /* Byte swapping for the headers. */ ++ bfd_uint64_t (*bfd_h_getx64) (const void *); ++ bfd_int64_t (*bfd_h_getx_signed_64) (const void *); ++ void (*bfd_h_putx64) (bfd_uint64_t, void *); ++ bfd_vma (*bfd_h_getx32) (const void *); ++ bfd_signed_vma (*bfd_h_getx_signed_32) (const void *); ++ void (*bfd_h_putx32) (bfd_vma, void *); ++ bfd_vma (*bfd_h_getx16) (const void *); ++ bfd_signed_vma (*bfd_h_getx_signed_16) (const void *); ++ void (*bfd_h_putx16) (bfd_vma, void *); ++ ++ /* Format dependent routines: these are vectors of entry points ++ within the target vector structure, one for each format to check. */ ++ ++ /* Check the format of a file being read. Return a <> or zero. */ ++ const struct bfd_target *(*_bfd_check_format[bfd_type_end]) (bfd *); ++ ++ /* Set the format of a file being written. */ ++ bfd_boolean (*_bfd_set_format[bfd_type_end]) (bfd *); ++ ++ /* Write cached information into a file being written, at <>. */ ++ bfd_boolean (*_bfd_write_contents[bfd_type_end]) (bfd *); ++ ++ ++ /* Generic entry points. */ ++#define BFD_JUMP_TABLE_GENERIC(NAME) \ ++ NAME##_close_and_cleanup, \ ++ NAME##_bfd_free_cached_info, \ ++ NAME##_new_section_hook, \ ++ NAME##_get_section_contents, \ ++ NAME##_get_section_contents_in_window ++ ++ /* Called when the BFD is being closed to do any necessary cleanup. */ ++ bfd_boolean (*_close_and_cleanup) (bfd *); ++ /* Ask the BFD to free all cached information. */ ++ bfd_boolean (*_bfd_free_cached_info) (bfd *); ++ /* Called when a new section is created. */ ++ bfd_boolean (*_new_section_hook) (bfd *, sec_ptr); ++ /* Read the contents of a section. */ ++ bfd_boolean (*_bfd_get_section_contents) ++ (bfd *, sec_ptr, void *, file_ptr, bfd_size_type); ++ bfd_boolean (*_bfd_get_section_contents_in_window) ++ (bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type); ++ ++ /* Entry points to copy private data. */ ++#define BFD_JUMP_TABLE_COPY(NAME) \ ++ NAME##_bfd_copy_private_bfd_data, \ ++ NAME##_bfd_merge_private_bfd_data, \ ++ NAME##_bfd_copy_private_section_data, \ ++ NAME##_bfd_copy_private_symbol_data, \ ++ NAME##_bfd_copy_private_header_data, \ ++ NAME##_bfd_set_private_flags, \ ++ NAME##_bfd_print_private_bfd_data ++ ++ /* Called to copy BFD general private data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_bfd_data) (bfd *, bfd *); ++ /* Called to merge BFD general private data from one object file ++ to a common output file when linking. */ ++ bfd_boolean (*_bfd_merge_private_bfd_data) (bfd *, bfd *); ++ /* Called to copy BFD private section data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_section_data) ++ (bfd *, sec_ptr, bfd *, sec_ptr); ++ /* Called to copy BFD private symbol data from one symbol ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_symbol_data) ++ (bfd *, asymbol *, bfd *, asymbol *); ++ /* Called to copy BFD private header data from one object file ++ to another. */ ++ bfd_boolean (*_bfd_copy_private_header_data) ++ (bfd *, bfd *); ++ /* Called to set private backend flags. */ ++ bfd_boolean (*_bfd_set_private_flags) (bfd *, flagword); ++ ++ /* Called to print private BFD data. */ ++ bfd_boolean (*_bfd_print_private_bfd_data) (bfd *, void *); ++ ++ /* Core file entry points. */ ++#define BFD_JUMP_TABLE_CORE(NAME) \ ++ NAME##_core_file_failing_command, \ ++ NAME##_core_file_failing_signal, \ ++ NAME##_core_file_matches_executable_p ++ ++ char * (*_core_file_failing_command) (bfd *); ++ int (*_core_file_failing_signal) (bfd *); ++ bfd_boolean (*_core_file_matches_executable_p) (bfd *, bfd *); ++ ++ /* Archive entry points. */ ++#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ ++ NAME##_slurp_armap, \ ++ NAME##_slurp_extended_name_table, \ ++ NAME##_construct_extended_name_table, \ ++ NAME##_truncate_arname, \ ++ NAME##_write_armap, \ ++ NAME##_read_ar_hdr, \ ++ NAME##_openr_next_archived_file, \ ++ NAME##_get_elt_at_index, \ ++ NAME##_generic_stat_arch_elt, \ ++ NAME##_update_armap_timestamp ++ ++ bfd_boolean (*_bfd_slurp_armap) (bfd *); ++ bfd_boolean (*_bfd_slurp_extended_name_table) (bfd *); ++ bfd_boolean (*_bfd_construct_extended_name_table) ++ (bfd *, char **, bfd_size_type *, const char **); ++ void (*_bfd_truncate_arname) (bfd *, const char *, char *); ++ bfd_boolean (*write_armap) ++ (bfd *, unsigned int, struct orl *, unsigned int, int); ++ void * (*_bfd_read_ar_hdr_fn) (bfd *); ++ bfd * (*openr_next_archived_file) (bfd *, bfd *); ++#define bfd_get_elt_at_index(b,i) BFD_SEND (b, _bfd_get_elt_at_index, (b,i)) ++ bfd * (*_bfd_get_elt_at_index) (bfd *, symindex); ++ int (*_bfd_stat_arch_elt) (bfd *, struct stat *); ++ bfd_boolean (*_bfd_update_armap_timestamp) (bfd *); ++ ++ /* Entry points used for symbols. */ ++#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ ++ NAME##_get_symtab_upper_bound, \ ++ NAME##_canonicalize_symtab, \ ++ NAME##_make_empty_symbol, \ ++ NAME##_print_symbol, \ ++ NAME##_get_symbol_info, \ ++ NAME##_bfd_is_local_label_name, \ ++ NAME##_bfd_is_target_special_symbol, \ ++ NAME##_get_lineno, \ ++ NAME##_find_nearest_line, \ ++ _bfd_generic_find_line, \ ++ NAME##_find_inliner_info, \ ++ NAME##_bfd_make_debug_symbol, \ ++ NAME##_read_minisymbols, \ ++ NAME##_minisymbol_to_symbol ++ ++ long (*_bfd_get_symtab_upper_bound) (bfd *); ++ long (*_bfd_canonicalize_symtab) ++ (bfd *, struct bfd_symbol **); ++ struct bfd_symbol * ++ (*_bfd_make_empty_symbol) (bfd *); ++ void (*_bfd_print_symbol) ++ (bfd *, void *, struct bfd_symbol *, bfd_print_symbol_type); ++#define bfd_print_symbol(b,p,s,e) BFD_SEND (b, _bfd_print_symbol, (b,p,s,e)) ++ void (*_bfd_get_symbol_info) ++ (bfd *, struct bfd_symbol *, symbol_info *); ++#define bfd_get_symbol_info(b,p,e) BFD_SEND (b, _bfd_get_symbol_info, (b,p,e)) ++ bfd_boolean (*_bfd_is_local_label_name) (bfd *, const char *); ++ bfd_boolean (*_bfd_is_target_special_symbol) (bfd *, asymbol *); ++ alent * (*_get_lineno) (bfd *, struct bfd_symbol *); ++ bfd_boolean (*_bfd_find_nearest_line) ++ (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma, ++ const char **, const char **, unsigned int *); ++ bfd_boolean (*_bfd_find_line) ++ (bfd *, struct bfd_symbol **, struct bfd_symbol *, ++ const char **, unsigned int *); ++ bfd_boolean (*_bfd_find_inliner_info) ++ (bfd *, const char **, const char **, unsigned int *); ++ /* Back-door to allow format-aware applications to create debug symbols ++ while using BFD for everything else. Currently used by the assembler ++ when creating COFF files. */ ++ asymbol * (*_bfd_make_debug_symbol) ++ (bfd *, void *, unsigned long size); ++#define bfd_read_minisymbols(b, d, m, s) \ ++ BFD_SEND (b, _read_minisymbols, (b, d, m, s)) ++ long (*_read_minisymbols) ++ (bfd *, bfd_boolean, void **, unsigned int *); ++#define bfd_minisymbol_to_symbol(b, d, m, f) \ ++ BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) ++ asymbol * (*_minisymbol_to_symbol) ++ (bfd *, bfd_boolean, const void *, asymbol *); ++ ++ /* Routines for relocs. */ ++#define BFD_JUMP_TABLE_RELOCS(NAME) \ ++ NAME##_get_reloc_upper_bound, \ ++ NAME##_canonicalize_reloc, \ ++ NAME##_bfd_reloc_type_lookup ++ ++ long (*_get_reloc_upper_bound) (bfd *, sec_ptr); ++ long (*_bfd_canonicalize_reloc) ++ (bfd *, sec_ptr, arelent **, struct bfd_symbol **); ++ /* See documentation on reloc types. */ ++ reloc_howto_type * ++ (*reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); ++ ++ /* Routines used when writing an object file. */ ++#define BFD_JUMP_TABLE_WRITE(NAME) \ ++ NAME##_set_arch_mach, \ ++ NAME##_set_section_contents ++ ++ bfd_boolean (*_bfd_set_arch_mach) ++ (bfd *, enum bfd_architecture, unsigned long); ++ bfd_boolean (*_bfd_set_section_contents) ++ (bfd *, sec_ptr, const void *, file_ptr, bfd_size_type); ++ ++ /* Routines used by the linker. */ ++#define BFD_JUMP_TABLE_LINK(NAME) \ ++ NAME##_sizeof_headers, \ ++ NAME##_bfd_get_relocated_section_contents, \ ++ NAME##_bfd_relax_section, \ ++ NAME##_bfd_link_hash_table_create, \ ++ NAME##_bfd_link_hash_table_free, \ ++ NAME##_bfd_link_add_symbols, \ ++ NAME##_bfd_link_just_syms, \ ++ NAME##_bfd_final_link, \ ++ NAME##_bfd_link_split_section, \ ++ NAME##_bfd_gc_sections, \ ++ NAME##_bfd_merge_sections, \ ++ NAME##_bfd_is_group_section, \ ++ NAME##_bfd_discard_group, \ ++ NAME##_section_already_linked \ ++ ++ int (*_bfd_sizeof_headers) (bfd *, bfd_boolean); ++ bfd_byte * (*_bfd_get_relocated_section_contents) ++ (bfd *, struct bfd_link_info *, struct bfd_link_order *, ++ bfd_byte *, bfd_boolean, struct bfd_symbol **); ++ ++ bfd_boolean (*_bfd_relax_section) ++ (bfd *, struct bfd_section *, struct bfd_link_info *, bfd_boolean *); ++ ++ /* Create a hash table for the linker. Different backends store ++ different information in this table. */ ++ struct bfd_link_hash_table * ++ (*_bfd_link_hash_table_create) (bfd *); ++ ++ /* Release the memory associated with the linker hash table. */ ++ void (*_bfd_link_hash_table_free) (struct bfd_link_hash_table *); ++ ++ /* Add symbols from this object file into the hash table. */ ++ bfd_boolean (*_bfd_link_add_symbols) (bfd *, struct bfd_link_info *); ++ ++ /* Indicate that we are only retrieving symbol values from this section. */ ++ void (*_bfd_link_just_syms) (asection *, struct bfd_link_info *); ++ ++ /* Do a link based on the link_order structures attached to each ++ section of the BFD. */ ++ bfd_boolean (*_bfd_final_link) (bfd *, struct bfd_link_info *); ++ ++ /* Should this section be split up into smaller pieces during linking. */ ++ bfd_boolean (*_bfd_link_split_section) (bfd *, struct bfd_section *); ++ ++ /* Remove sections that are not referenced from the output. */ ++ bfd_boolean (*_bfd_gc_sections) (bfd *, struct bfd_link_info *); ++ ++ /* Attempt to merge SEC_MERGE sections. */ ++ bfd_boolean (*_bfd_merge_sections) (bfd *, struct bfd_link_info *); ++ ++ /* Is this section a member of a group? */ ++ bfd_boolean (*_bfd_is_group_section) (bfd *, const struct bfd_section *); ++ ++ /* Discard members of a group. */ ++ bfd_boolean (*_bfd_discard_group) (bfd *, struct bfd_section *); ++ ++ /* Check if SEC has been already linked during a reloceatable or ++ final link. */ ++ void (*_section_already_linked) (bfd *, struct bfd_section *); ++ ++ /* Routines to handle dynamic symbols and relocs. */ ++#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ ++ NAME##_get_dynamic_symtab_upper_bound, \ ++ NAME##_canonicalize_dynamic_symtab, \ ++ NAME##_get_synthetic_symtab, \ ++ NAME##_get_dynamic_reloc_upper_bound, \ ++ NAME##_canonicalize_dynamic_reloc ++ ++ /* Get the amount of memory required to hold the dynamic symbols. */ ++ long (*_bfd_get_dynamic_symtab_upper_bound) (bfd *); ++ /* Read in the dynamic symbols. */ ++ long (*_bfd_canonicalize_dynamic_symtab) ++ (bfd *, struct bfd_symbol **); ++ /* Create synthetized symbols. */ ++ long (*_bfd_get_synthetic_symtab) ++ (bfd *, long, struct bfd_symbol **, long, struct bfd_symbol **, ++ struct bfd_symbol **); ++ /* Get the amount of memory required to hold the dynamic relocs. */ ++ long (*_bfd_get_dynamic_reloc_upper_bound) (bfd *); ++ /* Read in the dynamic relocs. */ ++ long (*_bfd_canonicalize_dynamic_reloc) ++ (bfd *, arelent **, struct bfd_symbol **); ++ ++ /* Opposite endian version of this target. */ ++ const struct bfd_target * alternative_target; ++ ++ /* Data for use by back-end routines, which isn't ++ generic enough to belong in this structure. */ ++ const void *backend_data; ++ ++} bfd_target; ++ ++bfd_boolean bfd_set_default_target (const char *name); ++ ++const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); ++ ++const char ** bfd_target_list (void); ++ ++const bfd_target *bfd_search_for_target ++ (int (*search_func) (const bfd_target *, void *), ++ void *); ++ ++/* Extracted from format.c. */ ++bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); ++ ++bfd_boolean bfd_check_format_matches ++ (bfd *abfd, bfd_format format, char ***matching); ++ ++bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); ++ ++const char *bfd_format_string (bfd_format format); ++ ++/* Extracted from linker.c. */ ++bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec); ++ ++#define bfd_link_split_section(abfd, sec) \ ++ BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) ++ ++void bfd_section_already_linked (bfd *abfd, asection *sec); ++ ++#define bfd_section_already_linked(abfd, sec) \ ++ BFD_SEND (abfd, _section_already_linked, (abfd, sec)) ++ ++/* Extracted from simple.c. */ ++bfd_byte *bfd_simple_get_relocated_section_contents ++ (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif +--- /dev/null ++++ b/include/asm-x86/bfd.h +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "bfd_32.h" ++#else ++# include "bfd_64.h" ++#endif +--- a/include/asm-x86/irq_vectors.h ++++ b/include/asm-x86/irq_vectors.h +@@ -16,6 +16,7 @@ + #else + # define IA32_SYSCALL_VECTOR 0x80 + #endif ++#define KDBENTER_VECTOR 0x81 + + /* + * Reserve the lowest usable priority level 0x20 - 0x2f for triggering +@@ -65,6 +66,7 @@ + # define RESCHEDULE_VECTOR 0xfc + # define CALL_FUNCTION_VECTOR 0xfb + # define CALL_FUNCTION_SINGLE_VECTOR 0xfa ++#define KDB_VECTOR 0xf9 + # define THERMAL_APIC_VECTOR 0xf0 + + #else +@@ -77,6 +79,10 @@ + #define THERMAL_APIC_VECTOR 0xfa + #define THRESHOLD_APIC_VECTOR 0xf9 + #define UV_BAU_MESSAGE 0xf8 ++/* Overload KDB_VECTOR with UV_BAU_MESSAGE. By the time the UV hardware is ++ * ready, we should have moved to a dynamically allocated vector scheme. ++ */ ++#define KDB_VECTOR 0xf8 + #define INVALIDATE_TLB_VECTOR_END 0xf7 + #define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f7 used for TLB flush */ + +--- /dev/null ++++ b/include/asm-x86/kdb.h +@@ -0,0 +1,134 @@ ++#ifndef _ASM_KDB_H ++#define _ASM_KDB_H ++ ++/* ++ * Kernel Debugger Architecture Dependent (x86) Global Headers ++ * ++ * 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) 1999-2008 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * KDB_ENTER() is a macro which causes entry into the kernel ++ * debugger from any point in the kernel code stream. If it ++ * is intended to be used from interrupt level, it must use ++ * a non-maskable entry method. The vector is KDB_VECTOR, ++ * defined in hw_irq.h ++ */ ++#define KDB_ENTER() do {if (kdb_on && !KDB_IS_RUNNING()) { asm("\tint $129\n"); }} while(0) ++ ++/* ++ * Needed for exported symbols. ++ */ ++typedef unsigned long kdb_machreg_t; ++ ++/* ++ * Per cpu arch specific kdb state. Must be in range 0xff000000. ++ */ ++#define KDB_STATE_A_IF 0x01000000 /* Saved IF flag */ ++ ++ ++#ifdef CONFIG_X86_32 ++ ++#define kdb_machreg_fmt "0x%lx" ++#define kdb_machreg_fmt0 "0x%08lx" ++#define kdb_bfd_vma_fmt "0x%lx" ++#define kdb_bfd_vma_fmt0 "0x%08lx" ++#define kdb_elfw_addr_fmt "0x%x" ++#define kdb_elfw_addr_fmt0 "0x%08x" ++ ++#else /* CONFIG_X86_32 */ ++ ++#define kdb_machreg_fmt "0x%lx" ++#define kdb_machreg_fmt0 "0x%016lx" ++#define kdb_bfd_vma_fmt "0x%lx" ++#define kdb_bfd_vma_fmt0 "0x%016lx" ++#define kdb_elfw_addr_fmt "0x%x" ++#define kdb_elfw_addr_fmt0 "0x%016x" ++ ++/* ++ * Functions to safely read and write kernel areas. The {to,from}_xxx ++ * addresses are not necessarily valid, these functions must check for ++ * validity. If the arch already supports get and put routines with ++ * suitable validation and/or recovery on invalid addresses then use ++ * those routines, otherwise check it yourself. ++ */ ++ ++/* ++ * asm-i386 uaccess.h supplies __copy_to_user which relies on MMU to ++ * trap invalid addresses in the _xxx fields. Verify the other address ++ * of the pair is valid by accessing the first and last byte ourselves, ++ * then any access violations should only be caused by the _xxx ++ * addresses, ++ */ ++ ++#include ++ ++static inline int ++__kdba_putarea_size(unsigned long to_xxx, void *from, size_t size) ++{ ++ mm_segment_t oldfs = get_fs(); ++ int r; ++ char c; ++ c = *((volatile char *)from); ++ c = *((volatile char *)from + size - 1); ++ ++ if (to_xxx < PAGE_OFFSET) { ++ return kdb_putuserarea_size(to_xxx, from, size); ++ } ++ ++ set_fs(KERNEL_DS); ++ r = __copy_to_user_inatomic((void *)to_xxx, from, size); ++ set_fs(oldfs); ++ return r; ++} ++ ++static inline int ++__kdba_getarea_size(void *to, unsigned long from_xxx, size_t size) ++{ ++ mm_segment_t oldfs = get_fs(); ++ int r; ++ *((volatile char *)to) = '\0'; ++ *((volatile char *)to + size - 1) = '\0'; ++ ++ if (from_xxx < PAGE_OFFSET) { ++ return kdb_getuserarea_size(to, from_xxx, size); ++ } ++ ++ set_fs(KERNEL_DS); ++ r = __copy_to_user_inatomic(to, (void *)from_xxx, size); ++ set_fs(oldfs); ++ return r; ++} ++ ++/* For numa with replicated code/data, the platform must supply its own ++ * kdba_putarea_size and kdba_getarea_size routines. Without replication kdb ++ * uses the standard architecture routines. ++ */ ++#ifdef CONFIG_NUMA_REPLICATE ++extern int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size); ++extern int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size); ++#else ++#define kdba_putarea_size __kdba_putarea_size ++#define kdba_getarea_size __kdba_getarea_size ++#endif ++ ++static inline int ++kdba_verify_rw(unsigned long addr, size_t size) ++{ ++ unsigned char data[size]; ++ return(kdba_getarea_size(data, addr, size) || kdba_putarea_size(addr, data, size)); ++} ++ ++#endif /* !CONFIG_X86_32 */ ++ ++static inline unsigned long ++kdba_funcptr_value(void *fp) ++{ ++ return (unsigned long)fp; ++} ++ ++#endif /* !_ASM_KDB_H */ +--- /dev/null ++++ b/include/asm-x86/kdbprivate.h +@@ -0,0 +1,241 @@ ++#ifndef _ASM_KDBPRIVATE_H ++#define _ASM_KDBPRIVATE_H ++ ++/* ++ * Kernel Debugger Architecture Dependent (x86) Private Headers ++ * ++ * 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) 1999-2008 Silicon Graphics, Inc. All Rights Reserved. ++ */ ++ ++typedef unsigned char kdb_machinst_t; ++ ++/* ++ * KDB_MAXBPT describes the total number of breakpoints ++ * supported by this architecure. ++ */ ++#define KDB_MAXBPT 16 ++ ++/* ++ * KDB_MAXHARDBPT describes the total number of hardware ++ * breakpoint registers that exist. ++ */ ++#define KDB_MAXHARDBPT 4 ++ ++/* Maximum number of arguments to a function */ ++#define KDBA_MAXARGS 16 ++ ++/* ++ * Support for ia32 debug registers ++ */ ++typedef struct _kdbhard_bp { ++ kdb_machreg_t bph_reg; /* Register this breakpoint uses */ ++ ++ unsigned int bph_free:1; /* Register available for use */ ++ unsigned int bph_data:1; /* Data Access breakpoint */ ++ ++ unsigned int bph_write:1; /* Write Data breakpoint */ ++ unsigned int bph_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ ++ unsigned int bph_length:2; /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */ ++ unsigned int bph_installed; /* flag: hw bp is installed */ ++} kdbhard_bp_t; ++ ++#define IA32_BREAKPOINT_INSTRUCTION 0xcc ++ ++#define DR6_BT 0x00008000 ++#define DR6_BS 0x00004000 ++#define DR6_BD 0x00002000 ++ ++#define DR6_B3 0x00000008 ++#define DR6_B2 0x00000004 ++#define DR6_B1 0x00000002 ++#define DR6_B0 0x00000001 ++#define DR6_DR_MASK 0x0000000F ++ ++#define DR7_RW_VAL(dr, drnum) \ ++ (((dr) >> (16 + (4 * (drnum)))) & 0x3) ++ ++#define DR7_RW_SET(dr, drnum, rw) \ ++ do { \ ++ (dr) &= ~(0x3 << (16 + (4 * (drnum)))); \ ++ (dr) |= (((rw) & 0x3) << (16 + (4 * (drnum)))); \ ++ } while (0) ++ ++#define DR7_RW0(dr) DR7_RW_VAL(dr, 0) ++#define DR7_RW0SET(dr,rw) DR7_RW_SET(dr, 0, rw) ++#define DR7_RW1(dr) DR7_RW_VAL(dr, 1) ++#define DR7_RW1SET(dr,rw) DR7_RW_SET(dr, 1, rw) ++#define DR7_RW2(dr) DR7_RW_VAL(dr, 2) ++#define DR7_RW2SET(dr,rw) DR7_RW_SET(dr, 2, rw) ++#define DR7_RW3(dr) DR7_RW_VAL(dr, 3) ++#define DR7_RW3SET(dr,rw) DR7_RW_SET(dr, 3, rw) ++ ++ ++#define DR7_LEN_VAL(dr, drnum) \ ++ (((dr) >> (18 + (4 * (drnum)))) & 0x3) ++ ++#define DR7_LEN_SET(dr, drnum, rw) \ ++ do { \ ++ (dr) &= ~(0x3 << (18 + (4 * (drnum)))); \ ++ (dr) |= (((rw) & 0x3) << (18 + (4 * (drnum)))); \ ++ } while (0) ++ ++#define DR7_LEN0(dr) DR7_LEN_VAL(dr, 0) ++#define DR7_LEN0SET(dr,len) DR7_LEN_SET(dr, 0, len) ++#define DR7_LEN1(dr) DR7_LEN_VAL(dr, 1) ++#define DR7_LEN1SET(dr,len) DR7_LEN_SET(dr, 1, len) ++#define DR7_LEN2(dr) DR7_LEN_VAL(dr, 2) ++#define DR7_LEN2SET(dr,len) DR7_LEN_SET(dr, 2, len) ++#define DR7_LEN3(dr) DR7_LEN_VAL(dr, 3) ++#define DR7_LEN3SET(dr,len) DR7_LEN_SET(dr, 3, len) ++ ++#define DR7_G0(dr) (((dr)>>1)&0x1) ++#define DR7_G0SET(dr) ((dr) |= 0x2) ++#define DR7_G0CLR(dr) ((dr) &= ~0x2) ++#define DR7_G1(dr) (((dr)>>3)&0x1) ++#define DR7_G1SET(dr) ((dr) |= 0x8) ++#define DR7_G1CLR(dr) ((dr) &= ~0x8) ++#define DR7_G2(dr) (((dr)>>5)&0x1) ++#define DR7_G2SET(dr) ((dr) |= 0x20) ++#define DR7_G2CLR(dr) ((dr) &= ~0x20) ++#define DR7_G3(dr) (((dr)>>7)&0x1) ++#define DR7_G3SET(dr) ((dr) |= 0x80) ++#define DR7_G3CLR(dr) ((dr) &= ~0x80) ++ ++#define DR7_L0(dr) (((dr))&0x1) ++#define DR7_L0SET(dr) ((dr) |= 0x1) ++#define DR7_L0CLR(dr) ((dr) &= ~0x1) ++#define DR7_L1(dr) (((dr)>>2)&0x1) ++#define DR7_L1SET(dr) ((dr) |= 0x4) ++#define DR7_L1CLR(dr) ((dr) &= ~0x4) ++#define DR7_L2(dr) (((dr)>>4)&0x1) ++#define DR7_L2SET(dr) ((dr) |= 0x10) ++#define DR7_L2CLR(dr) ((dr) &= ~0x10) ++#define DR7_L3(dr) (((dr)>>6)&0x1) ++#define DR7_L3SET(dr) ((dr) |= 0x40) ++#define DR7_L3CLR(dr) ((dr) &= ~0x40) ++ ++#define DR7_GD 0x00002000 /* General Detect Enable */ ++#define DR7_GE 0x00000200 /* Global exact */ ++#define DR7_LE 0x00000100 /* Local exact */ ++ ++extern kdb_machreg_t kdba_getdr6(void); ++extern void kdba_putdr6(kdb_machreg_t); ++ ++extern kdb_machreg_t kdba_getdr7(void); ++ ++struct kdba_running_process { ++ long sp; /* KDB may be on a different stack */ ++ long ip; /* eip when esp was set */ ++}; ++ ++static inline ++void kdba_unsave_running(struct kdba_running_process *k, struct pt_regs *regs) ++{ ++} ++ ++struct kdb_activation_record; ++extern void kdba_get_stack_info_alternate(kdb_machreg_t addr, int cpu, ++ struct kdb_activation_record *ar); ++ ++extern void kdba_wait_for_cpus(void); ++ ++ ++#ifdef CONFIG_X86_32 ++ ++#define DR_TYPE_EXECUTE 0x0 ++#define DR_TYPE_WRITE 0x1 ++#define DR_TYPE_IO 0x2 ++#define DR_TYPE_RW 0x3 ++ ++/* ++ * Platform specific environment entries ++ */ ++#define KDB_PLATFORM_ENV "IDMODE=x86", "BYTESPERWORD=4", "IDCOUNT=16" ++ ++/* ++ * Support for setjmp/longjmp ++ */ ++#define JB_BX 0 ++#define JB_SI 1 ++#define JB_DI 2 ++#define JB_BP 3 ++#define JB_SP 4 ++#define JB_PC 5 ++ ++typedef struct __kdb_jmp_buf { ++ unsigned long regs[6]; /* kdba_setjmp assumes fixed offsets here */ ++} kdb_jmp_buf; ++ ++extern int asmlinkage kdba_setjmp(kdb_jmp_buf *); ++extern void asmlinkage kdba_longjmp(kdb_jmp_buf *, int); ++#define kdba_setjmp kdba_setjmp ++ ++extern kdb_jmp_buf *kdbjmpbuf; ++ ++/* Arch specific data saved for running processes */ ++static inline ++void kdba_save_running(struct kdba_running_process *k, struct pt_regs *regs) ++{ ++ k->sp = current_stack_pointer; ++ __asm__ __volatile__ ( " lea 1f,%%eax; movl %%eax,%0 ; 1: " : "=r"(k->ip) : : "eax" ); ++} ++ ++extern void kdb_interrupt(void); ++ ++#define KDB_INT_REGISTERS 8 ++ ++#else /* CONFIG_X86_32 */ ++ ++extern kdb_machreg_t kdba_getdr(int); ++extern void kdba_putdr(int, kdb_machreg_t); ++ ++extern kdb_machreg_t kdb_getcr(int); ++ ++/* ++ * Platform specific environment entries ++ */ ++#define KDB_PLATFORM_ENV "IDMODE=x86_64", "BYTESPERWORD=8", "IDCOUNT=16" ++ ++/* ++ * reg indicies for x86_64 setjmp/longjmp ++ */ ++#define JB_RBX 0 ++#define JB_RBP 1 ++#define JB_R12 2 ++#define JB_R13 3 ++#define JB_R14 4 ++#define JB_R15 5 ++#define JB_RSP 6 ++#define JB_PC 7 ++ ++typedef struct __kdb_jmp_buf { ++ unsigned long regs[8]; /* kdba_setjmp assumes fixed offsets here */ ++} kdb_jmp_buf; ++ ++extern int asmlinkage kdba_setjmp(kdb_jmp_buf *); ++extern void asmlinkage kdba_longjmp(kdb_jmp_buf *, int); ++#define kdba_setjmp kdba_setjmp ++ ++extern kdb_jmp_buf *kdbjmpbuf; ++ ++/* Arch specific data saved for running processes */ ++register unsigned long current_stack_pointer asm("rsp") __used; ++ ++static inline ++void kdba_save_running(struct kdba_running_process *k, struct pt_regs *regs) ++{ ++ k->sp = current_stack_pointer; ++ __asm__ __volatile__ ( " lea 0(%%rip),%%rax; movq %%rax,%0 ; " : "=r"(k->ip) : : "rax" ); ++} ++ ++extern asmlinkage void kdb_interrupt(void); ++ ++#define KDB_INT_REGISTERS 16 ++ ++#endif /* !CONFIG_X86_32 */ ++ ++#endif /* !_ASM_KDBPRIVATE_H */ +--- a/include/asm-x86/kdebug.h ++++ b/include/asm-x86/kdebug.h +@@ -15,6 +15,8 @@ enum die_val { + DIE_DIE, + DIE_NMIWATCHDOG, + DIE_KERNELDEBUG, ++ DIE_KDEBUG_ENTER, ++ DIE_KDEBUG_LEAVE, + DIE_TRAP, + DIE_GPF, + DIE_CALL, +--- a/include/asm-x86/kmap_types.h ++++ b/include/asm-x86/kmap_types.h +@@ -21,7 +21,8 @@ D(9) KM_IRQ0, + D(10) KM_IRQ1, + D(11) KM_SOFTIRQ0, + D(12) KM_SOFTIRQ1, +-D(13) KM_TYPE_NR ++D(13) KM_KDB, ++D(14) KM_TYPE_NR + }; + + #undef D +--- a/include/asm-x86/ptrace.h ++++ b/include/asm-x86/ptrace.h +@@ -16,6 +16,29 @@ + /* this struct defines the way the registers are stored on the + stack during a system call. */ + ++enum EFLAGS { ++ EF_CF = 0x00000001, ++ EF_PF = 0x00000004, ++ EF_AF = 0x00000010, ++ EF_ZF = 0x00000040, ++ EF_SF = 0x00000080, ++ EF_TF = 0x00000100, ++ EF_IE = 0x00000200, ++ EF_DF = 0x00000400, ++ EF_OF = 0x00000800, ++ EF_IOPL = 0x00003000, ++ EF_IOPL_RING0 = 0x00000000, ++ EF_IOPL_RING1 = 0x00001000, ++ EF_IOPL_RING2 = 0x00002000, ++ EF_NT = 0x00004000, /* nested task */ ++ EF_RF = 0x00010000, /* resume */ ++ EF_VM = 0x00020000, /* virtual mode */ ++ EF_AC = 0x00040000, /* alignment */ ++ EF_VIF = 0x00080000, /* virtual interrupt */ ++ EF_VIP = 0x00100000, /* virtual interrupt pending */ ++ EF_ID = 0x00200000, /* id */ ++}; ++ + #ifndef __KERNEL__ + + struct pt_regs { diff --git a/src/patches/suse-2.6.27.31/patches.suse/kdump-dump_after_notifier.patch b/src/patches/suse-2.6.27.31/patches.suse/kdump-dump_after_notifier.patch new file mode 100644 index 000000000..50db84fd1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kdump-dump_after_notifier.patch @@ -0,0 +1,136 @@ +From: Takenori Nagano +Subject: [PATCH] Add dump_after_notifier sysctl +Patch-mainline: never +References: 265764 + +This patch adds dump_after_notifier sysctl to execute kdump after the notifier +call chain. This basically makes it possible to execute KDB before kdump. + +Signed-off-by: Takenori Nagano +Acked-by: Bernhard Walle + +--- + include/linux/kexec.h | 2 ++ + include/linux/sysctl.h | 1 + + kernel/kexec.c | 29 +++++++++++++++++++++++++++++ + kernel/panic.c | 5 ++++- + kernel/sysctl_check.c | 1 + + 5 files changed, 37 insertions(+), 1 deletion(-) + +--- a/include/linux/kexec.h ++++ b/include/linux/kexec.h +@@ -154,6 +154,7 @@ unsigned long paddr_vmcoreinfo_note(void + + extern struct kimage *kexec_image; + extern struct kimage *kexec_crash_image; ++extern int dump_after_notifier; + + #ifndef kexec_flush_icache_page + #define kexec_flush_icache_page(page) +@@ -208,5 +209,6 @@ struct pt_regs; + struct task_struct; + static inline void crash_kexec(struct pt_regs *regs) { } + static inline int kexec_should_crash(struct task_struct *p) { return 0; } ++#define dump_after_notifier 0 + #endif /* CONFIG_KEXEC */ + #endif /* LINUX_KEXEC_H */ +--- a/include/linux/sysctl.h ++++ b/include/linux/sysctl.h +@@ -164,6 +164,7 @@ enum + KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */ + KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */ + KERN_KDB=77, /* int: kdb on/off */ ++ KERN_DUMP_AFTER_NOTIFIER=78, /* int: kdump after panic_notifier (SUSE only) */ + }; + + +--- a/kernel/kexec.c ++++ b/kernel/kexec.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -45,6 +46,7 @@ + + /* Per cpu memory for storing cpu states in case of system crash. */ + note_buf_t* crash_notes; ++int dump_after_notifier; + + /* vmcoreinfo stuff */ + unsigned char vmcoreinfo_data[VMCOREINFO_BYTES]; +@@ -1151,6 +1153,30 @@ void crash_save_cpu(struct pt_regs *regs + final_note(buf); + } + ++#ifdef CONFIG_SYSCTL ++static ctl_table dump_after_notifier_table[] = { ++ { ++ .ctl_name = KERN_DUMP_AFTER_NOTIFIER, ++ .procname = "dump_after_notifier", ++ .data = &dump_after_notifier, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++ { .ctl_name = 0 } ++}; ++ ++static ctl_table kexec_sys_table[] = { ++ { ++ .ctl_name = CTL_KERN, ++ .procname = "kernel", ++ .mode = 0555, ++ .child = dump_after_notifier_table, ++ }, ++ { .ctl_name = 0 } ++}; ++#endif ++ + static int __init crash_notes_memory_init(void) + { + /* Allocate memory for saving cpu registers. */ +@@ -1160,6 +1186,9 @@ static int __init crash_notes_memory_ini + " states failed\n"); + return -ENOMEM; + } ++#ifdef CONFIG_SYSCTL ++ register_sysctl_table(kexec_sys_table); ++#endif + return 0; + } + module_init(crash_notes_memory_init) +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -95,7 +95,8 @@ NORET_TYPE void panic(const char * fmt, + * everything else. + * Do we want to call this before we try to display a message? + */ +- crash_kexec(NULL); ++ if (!dump_after_notifier) ++ crash_kexec(NULL); + + #ifdef CONFIG_SMP + /* +@@ -108,6 +109,8 @@ NORET_TYPE void panic(const char * fmt, + + atomic_notifier_call_chain(&panic_notifier_list, 0, buf); + ++ crash_kexec(NULL); ++ + if (!panic_blink) + panic_blink = no_blink; + +--- a/kernel/sysctl_check.c ++++ b/kernel/sysctl_check.c +@@ -106,6 +106,7 @@ static const struct trans_ctl_table tran + { KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" }, + { KERN_SETUID_DUMPABLE, "suid_dumpable" }, + { KERN_KDB, "kdb" }, ++ { KERN_DUMP_AFTER_NOTIFIER, "dump_after_notifier" }, + {} + }; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/kvm-as-kmp b/src/patches/suse-2.6.27.31/patches.suse/kvm-as-kmp new file mode 100644 index 000000000..81e95647c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/kvm-as-kmp @@ -0,0 +1,64 @@ +From: Alexander Graf +Date: Sat, 18 Oct 2008 01:18:24 +0200 +Subject: Allow KVM to be built as KMP +References: FATE#303679 + +As discussed on the kernel mailinglist, we need a helper config +option to enable KVM dependencies in the kernel, so we can +build it as a KMP later on. This patch provides this option. + +Signed-off-by: Alexander Graf +Signed-off-by: Hannes Reinecke +--- + arch/x86/kvm/Kconfig | 14 ++++++++++++++ + 1 files changed, 14 insertions(+), 0 deletions(-) + +Index: linux-2.6.27/arch/x86/kvm/Kconfig +=================================================================== +--- linux-2.6.27.orig/arch/x86/kvm/Kconfig ++++ linux-2.6.27/arch/x86/kvm/Kconfig +@@ -17,6 +17,20 @@ menuconfig VIRTUALIZATION + + if VIRTUALIZATION + ++config KVM_KMP ++ bool "Build Kernel-based Virtual Machine (KVM) as KMP" ++ depends on HAVE_KVM ++ select PREEMPT_NOTIFIERS ++ select MMU_NOTIFIER ++ select ANON_INODES ++ ---help--- ++ Normally KVM has to be enabled in the kernel config to automatically ++ select depending features. Because we are building KVM as a KMP, we ++ need the chance to only select the dependencies, but not build KVM ++ itself. ++ ++ Say Y here. ++ + config KVM + tristate "Kernel-based Virtual Machine (KVM) support" + depends on HAVE_KVM +Index: linux-2.6.27/arch/ia64/kvm/Kconfig +=================================================================== +--- linux-2.6.27.orig/arch/ia64/kvm/Kconfig ++++ linux-2.6.27/arch/ia64/kvm/Kconfig +@@ -17,6 +17,19 @@ menuconfig VIRTUALIZATION + + if VIRTUALIZATION + ++config KVM_KMP ++ bool "Build Kernel-based Virtual Machine (KVM) as KMP" ++ depends on HAVE_KVM ++ select PREEMPT_NOTIFIERS ++ select ANON_INODES ++ ---help--- ++ Normally KVM has to be enabled in the kernel config to automatically ++ select depending features. Because we are building KVM as a KMP, we ++ need the chance to only select the dependencies, but not build KVM ++ itself. ++ ++ Say Y here. ++ + config KVM + tristate "Kernel-based Virtual Machine (KVM) support" + depends on HAVE_KVM && EXPERIMENTAL diff --git a/src/patches/suse-2.6.27.31/patches.suse/led_classdev.sysfs-name.patch b/src/patches/suse-2.6.27.31/patches.suse/led_classdev.sysfs-name.patch new file mode 100644 index 000000000..de75e13af --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/led_classdev.sysfs-name.patch @@ -0,0 +1,55 @@ +Subject: use correct name for /sys/devices/virtual/leds/ entries +From: olh@suse.de +References: 468350 + +the low hanging fruits + +--- + drivers/leds/leds-cobalt-qube.c | 2 +- + drivers/leds/leds-cobalt-raq.c | 4 ++-- + drivers/leds/ledtrig-default-on.c | 2 +- + drivers/macintosh/via-pmu-led.c | 2 +- + 4 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/leds/leds-cobalt-qube.c ++++ b/drivers/leds/leds-cobalt-qube.c +@@ -28,7 +28,7 @@ static void qube_front_led_set(struct le + } + + static struct led_classdev qube_front_led = { +- .name = "qube-front", ++ .name = "qube::front", + .brightness = LED_FULL, + .brightness_set = qube_front_led_set, + .default_trigger = "ide-disk", +--- a/drivers/leds/leds-cobalt-raq.c ++++ b/drivers/leds/leds-cobalt-raq.c +@@ -49,7 +49,7 @@ static void raq_web_led_set(struct led_c + } + + static struct led_classdev raq_web_led = { +- .name = "raq-web", ++ .name = "raq::web", + .brightness_set = raq_web_led_set, + }; + +@@ -70,7 +70,7 @@ static void raq_power_off_led_set(struct + } + + static struct led_classdev raq_power_off_led = { +- .name = "raq-power-off", ++ .name = "raq::power-off", + .brightness_set = raq_power_off_led_set, + .default_trigger = "power-off", + }; +--- a/drivers/macintosh/via-pmu-led.c ++++ b/drivers/macintosh/via-pmu-led.c +@@ -72,7 +72,7 @@ static void pmu_led_set(struct led_class + } + + static struct led_classdev pmu_led = { +- .name = "pmu-front-led", ++ .name = "pmu-led::front", + #ifdef CONFIG_ADB_PMU_LED_IDE + .default_trigger = "ide-disk", + #endif diff --git a/src/patches/suse-2.6.27.31/patches.suse/md-bitmap-sub-page-chunks b/src/patches/suse-2.6.27.31/patches.suse/md-bitmap-sub-page-chunks new file mode 100644 index 000000000..f561a70ca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/md-bitmap-sub-page-chunks @@ -0,0 +1,110 @@ +From: Neil Brown +Subject: md: Allow write-intent bitmaps to have chunksize < PAGE_SIZE +Patch-mainline: no +References: 459557 + +md currently insists that the chunk size used for write-intent +bitmaps (the amount of data that corresponds to one chunk) +be at least one page. + +The reason for this list restriction is lost in the mists of time, +but a review of the code (and a vague memory) suggests that the only +problem would be related to resync. Resync tries very hard to +work in multiples of a page, but also needs to sync with units +of a bitmap_chunk too. + +This connection comes out in the bitmap_start_sync call. + +So change bitmap_start_sync to always work in multiples of a page. +If the bitmap chunk size is less that one page, we flag multiple +chunks as 'syncing' and generally make them all appear to the +resync routines like one chunk. + +All other code either already works with data ranges that could +span multiple chunks, or explicitly only cares about a single chunk. + +This is needed because some architectures use 64K pages in SLES11 +where they used 4K pages in SLES10. So arrays created on SLES10 +might not work with SLES11 without this change. + +Also, the default chunk size is 4K, and so newly create arrays +that use the default will not work. + +Signed-off-by: Neil Brown + +--- + drivers/md/bitmap.c | 41 ++++++++++++++++++++++++++++++++--------- + 1 file changed, 32 insertions(+), 9 deletions(-) + +--- a/drivers/md/bitmap.c ++++ b/drivers/md/bitmap.c +@@ -110,13 +110,12 @@ static int bitmap_checkpage(struct bitma + { + unsigned char *mappage; + +- if (page >= bitmap->pages) { +- printk(KERN_ALERT +- "%s: invalid bitmap page request: %lu (> %lu)\n", +- bmname(bitmap), page, bitmap->pages-1); ++ if (page >= bitmap->pages) ++ /* This can happen if bitmap_start_sync goes beyond ++ * End-of-device while looking for a whole page. ++ * It is harmless. ++ */ + return -EINVAL; +- } +- + + if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */ + return 0; +@@ -571,7 +570,7 @@ static int bitmap_read_sb(struct bitmap + else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO || + le32_to_cpu(sb->version) > BITMAP_MAJOR_HI) + reason = "unrecognized superblock version"; +- else if (chunksize < PAGE_SIZE) ++ else if (chunksize < 512) + reason = "bitmap chunksize too small"; + else if ((1 << ffz(~chunksize)) != chunksize) + reason = "bitmap chunksize not a power of 2"; +@@ -1347,8 +1346,8 @@ void bitmap_endwrite(struct bitmap *bitm + } + } + +-int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, +- int degraded) ++static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, ++ int degraded) + { + bitmap_counter_t *bmc; + int rv; +@@ -1376,6 +1375,30 @@ int bitmap_start_sync(struct bitmap *bit + return rv; + } + ++int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, ++ int degraded) ++{ ++ /* bitmap_start_sync must always report on multiples of whole ++ * pages, otherwise resync (which is very PAGE_SIZE based) will ++ * get confused. ++ * So call __bitmap_start_sync repeatedly (if needed) until ++ * At least PAGE_SIZE>>9 blocks are covered. ++ * Return the 'or' of the result. ++ */ ++ int rv = 0; ++ int blocks1; ++ ++ *blocks = 0; ++ while (*blocks < (PAGE_SIZE>>9)) { ++ rv |= __bitmap_start_sync(bitmap, offset, ++ &blocks1, degraded); ++ offset += blocks1; ++ *blocks += blocks1; ++ } ++ return rv; ++} ++ ++ + void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) + { + bitmap_counter_t *bmc; diff --git a/src/patches/suse-2.6.27.31/patches.suse/md-notify-when-stopped b/src/patches/suse-2.6.27.31/patches.suse/md-notify-when-stopped new file mode 100644 index 000000000..3bd7719bb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/md-notify-when-stopped @@ -0,0 +1,25 @@ +From: NeilBrown +Subject: md: notify udev when an md array is stopped. +Patch-mainline: 2.6.28-rc3 + +When an md array is stopped we need to udev to remove any +(/dev/disk/by-id/md*) links. Otherwise /dev can become a bit of a +mess. + +Signed-off-by: Neil Brown + +--- + drivers/md/md.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -3996,6 +3996,8 @@ static int do_md_stop(mddev_t * mddev, i + mddev->barriers_work = 0; + mddev->safemode = 0; + ++ kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE); ++ + } else if (mddev->pers) + printk(KERN_INFO "md: %s switched to read-only mode.\n", + mdname(mddev)); diff --git a/src/patches/suse-2.6.27.31/patches.suse/md-raid-metadata-PAGE_SIZE.patch b/src/patches/suse-2.6.27.31/patches.suse/md-raid-metadata-PAGE_SIZE.patch new file mode 100644 index 000000000..d9790f474 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/md-raid-metadata-PAGE_SIZE.patch @@ -0,0 +1,47 @@ +Subject: [Bug 429490] sles10 raid0 can not be started +From: bugzilla_noreply@novell.com + +### Comment #4 from Neil Brown 2008-10-08 17:34:49 MDT --- +The md code was written with the expectation that the chunk size would +always be at least one page. This may not always be a strict requirement, +but I guess that test protects against untested code. + +For raid4/5/6, the stripe-cache is stored as pages so a chunk size +less than one page would certainly cause problems with the current code. + +For raid0, I think a smaller chunk size should work. +The filesystem is always allowed to send down one-page requests, and +if the chunk size is less than that page size, these requests will have +to be split up, possibly multiple times. However I think the code will +get this right - it has only actually be used for page-sized requests +that are not page-aligned. + +You could try changing the test to + + if (chunk_size < PAGE_SIZE && mddev->level != 0) { + +and see how that works. + +Signed-off-by: Olaf Hering + +--- + drivers/md/md.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -3587,9 +3587,14 @@ static int do_md_run(mddev_t * mddev) + return -EINVAL; + } + if (chunk_size < PAGE_SIZE) { ++ if (mddev->level) { + printk(KERN_ERR "too small chunk_size: %d < %ld\n", + chunk_size, PAGE_SIZE); + return -EINVAL; ++ } else { ++ printk(KERN_ERR "too small chunk_size: %d < %ld, but continuing anyway on raid0. Good luck!\n", ++ chunk_size, PAGE_SIZE); ++ } + } + + /* devices must have minimum size of one chunk */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/mem_cgroup_stat-dynamic-alloc b/src/patches/suse-2.6.27.31/patches.suse/mem_cgroup_stat-dynamic-alloc new file mode 100644 index 000000000..afeb58eed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mem_cgroup_stat-dynamic-alloc @@ -0,0 +1,104 @@ +From: Jan Blunck +Subject: Dynamically allocate struct mem_cgroup_stat_cpu memory + +When increasing NR_CPUS to 4096 the size of struct mem_cgroup is growing to +507904 bytes per instance on x86_64. This patch changes the allocation of +these structures to use nr_cpu_ids instead. Although the init_mem_cgroup still +is that huge since it stays statically allocated. + +Signed-off-by: Jan Blunck +--- + mm/memcontrol.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 41 insertions(+), 8 deletions(-) + +Index: b/mm/memcontrol.c +=================================================================== +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -59,7 +59,7 @@ struct mem_cgroup_stat_cpu { + } ____cacheline_aligned_in_smp; + + struct mem_cgroup_stat { +- struct mem_cgroup_stat_cpu cpustat[NR_CPUS]; ++ struct mem_cgroup_stat_cpu *cpustat; + }; + + /* +@@ -143,6 +143,7 @@ struct mem_cgroup { + struct mem_cgroup_stat stat; + }; + static struct mem_cgroup init_mem_cgroup; ++static struct mem_cgroup_stat_cpu init_mem_cgroup_stat_cpu[NR_CPUS]; + + /* + * We use the lower bit of the page->page_cgroup pointer as a bit spin +@@ -1097,23 +1098,54 @@ static void free_mem_cgroup_per_zone_inf + static struct mem_cgroup *mem_cgroup_alloc(void) + { + struct mem_cgroup *mem; ++ struct mem_cgroup_stat_cpu *cpustat; ++ size_t statsize = nr_cpu_ids * sizeof(*cpustat); + +- if (sizeof(*mem) < PAGE_SIZE) +- mem = kmalloc(sizeof(*mem), GFP_KERNEL); +- else ++ if (sizeof(*mem) > PAGE_SIZE) { + mem = vmalloc(sizeof(*mem)); +- +- if (mem) ++ if (!mem) ++ goto out; + memset(mem, 0, sizeof(*mem)); ++ } else ++ mem = kzalloc(sizeof(*mem), GFP_KERNEL); ++ ++ if (!mem) ++ goto out; ++ ++ if (statsize > PAGE_SIZE) { ++ cpustat = vmalloc(statsize); ++ if (!cpustat) ++ goto out_mem; ++ memset(cpustat, 0, statsize); ++ } else ++ cpustat = kzalloc(statsize, GFP_KERNEL); ++ ++ if (!cpustat) ++ goto out_mem; ++ ++ mem->stat.cpustat = cpustat; + return mem; ++ ++out_mem: ++ if (is_vmalloc_addr(mem)) ++ vfree(mem); ++ else ++ kfree(mem); ++out: ++ return NULL; + } + + static void mem_cgroup_free(struct mem_cgroup *mem) + { +- if (sizeof(*mem) < PAGE_SIZE) +- kfree(mem); ++ if (is_vmalloc_addr(mem->stat.cpustat)) ++ vfree(mem->stat.cpustat); + else ++ kfree(mem->stat.cpustat); ++ ++ if (is_vmalloc_addr(mem)) + vfree(mem); ++ else ++ kfree(mem); + } + + +@@ -1125,6 +1157,7 @@ mem_cgroup_create(struct cgroup_subsys * + + if (unlikely((cont->parent) == NULL)) { + mem = &init_mem_cgroup; ++ mem->stat.cpustat = &init_mem_cgroup_stat_cpu[0]; + page_cgroup_cache = KMEM_CACHE(page_cgroup, SLAB_PANIC); + } else { + mem = mem_cgroup_alloc(); diff --git a/src/patches/suse-2.6.27.31/patches.suse/mm-devzero-optimisation.patch b/src/patches/suse-2.6.27.31/patches.suse/mm-devzero-optimisation.patch new file mode 100644 index 000000000..bd499e7d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mm-devzero-optimisation.patch @@ -0,0 +1,270 @@ +From: Nick Piggin +Subject: mm: /dev/zero optimisation +References: bnc#430738 +Patch-mainline: no (could be submit) + +Patch for removal of ZERO_PAGE from main VM paths also removed the +/dev/zero optimisation to map directly from ZERO_PAGE when doing +mmap() and also the interesting read(2) "hack" where the MMU was +used to make zero-filling the target buffer zero-copy. + +Some benchmarks have run into issues with this. Customers sometimes +use these benchmarks to qualify and test systems, so even if the +benchmarks themselves are "stupid", it saves some trouble to retain +this optimisation for them. Also, while I don't think it was established +that there is a "real" workload where this helps, but it can't be proven +that one does not exist. + +Signed-off-by: Nick Piggin +--- + drivers/char/mem.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + include/linux/mm.h | 2 + + mm/memory.c | 90 ++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 195 insertions(+), 2 deletions(-) + +--- a/drivers/char/mem.c ++++ b/drivers/char/mem.c +@@ -702,6 +702,100 @@ static ssize_t splice_write_null(struct + return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); + } + ++#if 1 //ndef CONFIG_XEN ++/* ++ * For fun, we are using the MMU for this. ++ */ ++static inline size_t read_zero_pagealigned(char __user * buf, size_t size) ++{ ++ struct mm_struct *mm; ++ struct vm_area_struct * vma; ++ unsigned long addr=(unsigned long)buf; ++ ++ mm = current->mm; ++ /* Oops, this was forgotten before. -ben */ ++ down_read(&mm->mmap_sem); ++ ++ /* For private mappings, just map in zero pages. */ ++ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { ++ unsigned long count; ++ ++ if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0) ++ goto out_up; ++ if (vma->vm_flags & (VM_SHARED | VM_HUGETLB)) ++ break; ++ count = vma->vm_end - addr; ++ if (count > size) ++ count = size; ++ ++ zap_page_range(vma, addr, count, NULL); ++ if (zeromap_page_range(vma, addr, count, PAGE_COPY)) ++ break; ++ ++ size -= count; ++ buf += count; ++ addr += count; ++ if (size == 0) ++ goto out_up; ++ } ++ ++ up_read(&mm->mmap_sem); ++ ++ /* The shared case is hard. Let's do the conventional zeroing. */ ++ do { ++ unsigned long unwritten = clear_user(buf, PAGE_SIZE); ++ if (unwritten) ++ return size + unwritten - PAGE_SIZE; ++ cond_resched(); ++ buf += PAGE_SIZE; ++ size -= PAGE_SIZE; ++ } while (size); ++ ++ return size; ++out_up: ++ up_read(&mm->mmap_sem); ++ return size; ++} ++ ++static ssize_t read_zero(struct file * file, char __user * buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long left, unwritten, written = 0; ++ ++ if (!count) ++ return 0; ++ ++ if (!access_ok(VERIFY_WRITE, buf, count)) ++ return -EFAULT; ++ ++ left = count; ++ ++ /* do we want to be clever? Arbitrary cut-off */ ++ if (count >= PAGE_SIZE*4) { ++ unsigned long partial; ++ ++ /* How much left of the page? */ ++ partial = (PAGE_SIZE-1) & -(unsigned long) buf; ++ unwritten = clear_user(buf, partial); ++ written = partial - unwritten; ++ if (unwritten) ++ goto out; ++ left -= partial; ++ buf += partial; ++ unwritten = read_zero_pagealigned(buf, left & PAGE_MASK); ++ written += (left & PAGE_MASK) - unwritten; ++ if (unwritten) ++ goto out; ++ buf += left & PAGE_MASK; ++ left &= ~PAGE_MASK; ++ } ++ unwritten = clear_user(buf, left); ++ written += left - unwritten; ++out: ++ return written ? written : -EFAULT; ++} ++ ++#else /* CONFIG_XEN */ + static ssize_t read_zero(struct file * file, char __user * buf, + size_t count, loff_t *ppos) + { +@@ -730,15 +824,24 @@ static ssize_t read_zero(struct file * f + } + return written ? written : -EFAULT; + } ++#endif /* CONFIG_XEN */ + + static int mmap_zero(struct file * file, struct vm_area_struct * vma) + { ++ int err = 0; ++ + #ifndef CONFIG_MMU + return -ENOSYS; + #endif ++ + if (vma->vm_flags & VM_SHARED) + return shmem_zero_setup(vma); +- return 0; ++#if 1 //ndef CONFIG_XEN ++ err = zeromap_page_range(vma, vma->vm_start, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot); ++ BUG_ON(err == -EEXIST); ++#endif ++ return err; + } + + static ssize_t write_full(struct file * file, const char __user * buf, +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -791,6 +791,8 @@ void free_pgd_range(struct mmu_gather *t + unsigned long end, unsigned long floor, unsigned long ceiling); + int copy_page_range(struct mm_struct *dst, struct mm_struct *src, + struct vm_area_struct *vma); ++int zeromap_page_range(struct vm_area_struct *vma, unsigned long from, ++ unsigned long size, pgprot_t prot); + void unmap_mapping_range(struct address_space *mapping, + loff_t const holebegin, loff_t const holelen, int even_cows); + int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1268,6 +1268,95 @@ int get_user_pages(struct task_struct *t + } + EXPORT_SYMBOL(get_user_pages); + ++static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd, ++ unsigned long addr, unsigned long end, pgprot_t prot) ++{ ++ pte_t *pte; ++ spinlock_t *ptl; ++ int err = 0; ++ ++ pte = pte_alloc_map_lock(mm, pmd, addr, &ptl); ++ if (!pte) ++ return -EAGAIN; ++ arch_enter_lazy_mmu_mode(); ++ do { ++ struct page *page = ZERO_PAGE(addr); ++ pte_t zero_pte = pte_wrprotect(mk_pte(page, prot)); ++ ++ if (unlikely(!pte_none(*pte))) { ++ err = -EEXIST; ++ pte++; ++ break; ++ } ++ page_cache_get(page); ++ page_add_file_rmap(page); ++ inc_mm_counter(mm, file_rss); ++ set_pte_at(mm, addr, pte, zero_pte); ++ } while (pte++, addr += PAGE_SIZE, addr != end); ++ arch_leave_lazy_mmu_mode(); ++ pte_unmap_unlock(pte - 1, ptl); ++ return err; ++} ++ ++static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud, ++ unsigned long addr, unsigned long end, pgprot_t prot) ++{ ++ pmd_t *pmd; ++ unsigned long next; ++ int err; ++ ++ pmd = pmd_alloc(mm, pud, addr); ++ if (!pmd) ++ return -EAGAIN; ++ do { ++ next = pmd_addr_end(addr, end); ++ err = zeromap_pte_range(mm, pmd, addr, next, prot); ++ if (err) ++ break; ++ } while (pmd++, addr = next, addr != end); ++ return err; ++} ++ ++static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd, ++ unsigned long addr, unsigned long end, pgprot_t prot) ++{ ++ pud_t *pud; ++ unsigned long next; ++ int err; ++ ++ pud = pud_alloc(mm, pgd, addr); ++ if (!pud) ++ return -EAGAIN; ++ do { ++ next = pud_addr_end(addr, end); ++ err = zeromap_pmd_range(mm, pud, addr, next, prot); ++ if (err) ++ break; ++ } while (pud++, addr = next, addr != end); ++ return err; ++} ++ ++int zeromap_page_range(struct vm_area_struct *vma, ++ unsigned long addr, unsigned long size, pgprot_t prot) ++{ ++ pgd_t *pgd; ++ unsigned long next; ++ unsigned long end = addr + size; ++ struct mm_struct *mm = vma->vm_mm; ++ int err; ++ ++ BUG_ON(addr >= end); ++ pgd = pgd_offset(mm, addr); ++ flush_cache_range(vma, addr, end); ++ do { ++ next = pgd_addr_end(addr, end); ++ err = zeromap_pud_range(mm, pgd, addr, next, prot); ++ if (err) ++ break; ++ } while (pgd++, addr = next, addr != end); ++ return err; ++} ++ + pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, + spinlock_t **ptl) + { +@@ -1899,7 +1988,6 @@ gotten: + + if (unlikely(anon_vma_prepare(vma))) + goto oom; +- VM_BUG_ON(old_page == ZERO_PAGE(0)); + new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address); + if (!new_page) + goto oom; diff --git a/src/patches/suse-2.6.27.31/patches.suse/mm-do-not-disable-memory-hotplug-when-hibernation-is-enabled.patch b/src/patches/suse-2.6.27.31/patches.suse/mm-do-not-disable-memory-hotplug-when-hibernation-is-enabled.patch new file mode 100644 index 000000000..d337c6dce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mm-do-not-disable-memory-hotplug-when-hibernation-is-enabled.patch @@ -0,0 +1,23 @@ +From: Pavel Machek +Subject: mm: Do not disable memory hotplug when hibernation is enabled +References: bnc#438914 + +Signed-off-by: Rafael J. Wysocki + +diff -ur linux/mm/Kconfig linux.tmp/mm/Kconfig +--- linux/mm/Kconfig 2008-10-27 10:10:59.000000000 +0100 ++++ linux.tmp/mm/Kconfig 2008-10-29 10:02:41.000000000 +0100 +@@ -128,12 +128,9 @@ + config MEMORY_HOTPLUG + bool "Allow for memory hot-add" + depends on SPARSEMEM || X86_64_ACPI_NUMA +- depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG ++ depends on HOTPLUG && ARCH_ENABLE_MEMORY_HOTPLUG + depends on (IA64 || X86 || PPC64 || SUPERH || S390) + +-comment "Memory hotplug is currently incompatible with Software Suspend" +- depends on SPARSEMEM && HOTPLUG && HIBERNATION +- + config MEMORY_HOTPLUG_SPARSE + def_bool y + depends on SPARSEMEM && MEMORY_HOTPLUG diff --git a/src/patches/suse-2.6.27.31/patches.suse/mm-increase-dirty-limits.patch b/src/patches/suse-2.6.27.31/patches.suse/mm-increase-dirty-limits.patch new file mode 100644 index 000000000..7c4a3c178 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mm-increase-dirty-limits.patch @@ -0,0 +1,32 @@ +From: Jan Kara +Subject: Increase limits for starting writeback of dirty data +References: bnc#449662 +Patch-mainline: ? + +Return limits for dirty pages writeback to the numbers from SLES10. This dramatically +improves performance of workloads dirtying a lot of memory (e.g. simple databases not +using direct IO) and we're not aware it would harm anything. + +Signed-off-by: Jan Kara + +diff -rupX /home/jack/.kerndiffexclude linux-2.6.27/mm/page-writeback.c linux-2.6.27-dirty_limits//mm/page-writeback.c +--- linux-2.6.27/mm/page-writeback.c 2008-10-10 00:13:53.000000000 +0200 ++++ linux-2.6.27-dirty_limits/mm/page-writeback.c 2009-01-07 16:09:24.000000000 +0100 +@@ -66,7 +66,7 @@ static inline long sync_writeback_pages( + /* + * Start background writeback (via pdflush) at this percentage + */ +-int dirty_background_ratio = 5; ++int dirty_background_ratio = 10; + + /* + * free highmem will not be subtracted from the total free memory +@@ -77,7 +77,7 @@ int vm_highmem_is_dirtyable; + /* + * The generator of dirty data starts writeback at this percentage + */ +-int vm_dirty_ratio = 10; ++int vm_dirty_ratio = 40; + + /* + * The interval between `kupdate'-style writebacks, in jiffies diff --git a/src/patches/suse-2.6.27.31/patches.suse/mm-vmalloc-fail-dump-stack.patch b/src/patches/suse-2.6.27.31/patches.suse/mm-vmalloc-fail-dump-stack.patch new file mode 100644 index 000000000..af30108ce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mm-vmalloc-fail-dump-stack.patch @@ -0,0 +1,68 @@ +From: Nick Piggin +Subject: mm: improve vmalloc reporting +Patch-upstream: no (could be merged) +References: bnc#511079 + +Add a dump_stack and some information about allocation size when vmalloc +fails, and also pass down caller information for some of the vmalloc +variants (rather than report those variants themselves as the caller +in /proc/vmallocinfo). + +Signed-off-by: Nick Piggin +--- + mm/vmalloc.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +Index: linux-2.6.27/mm/vmalloc.c +=================================================================== +--- linux-2.6.27.orig/mm/vmalloc.c ++++ linux-2.6.27/mm/vmalloc.c +@@ -279,8 +279,11 @@ found: + out: + write_unlock(&vmlist_lock); + kfree(area); +- if (printk_ratelimit()) ++ if (printk_ratelimit()) { + printk(KERN_WARNING "allocation failed: out of vmalloc space - use vmalloc= to increase size.\n"); ++ printk(KERN_WARNING "vmalloc size=%lx flags=%lx start=%lx end=%lx node=%d gfp=%lx\n", size, flags, start, end, node, (unsigned long)gfp_mask); ++ dump_stack(); ++ } + return NULL; + } + +@@ -604,7 +607,7 @@ void *vmalloc_user(unsigned long size) + struct vm_struct *area; + void *ret; + +- ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); ++ ret = __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL, -1, __builtin_return_address(0)); + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); +@@ -651,7 +654,7 @@ EXPORT_SYMBOL(vmalloc_node); + + void *vmalloc_exec(unsigned long size) + { +- return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC); ++ return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC, -1, __builtin_return_address(0)); + } + + #if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32) +@@ -671,7 +674,7 @@ void *vmalloc_exec(unsigned long size) + */ + void *vmalloc_32(unsigned long size) + { +- return __vmalloc(size, GFP_VMALLOC32, PAGE_KERNEL); ++ return __vmalloc_node(size, GFP_VMALLOC32, PAGE_KERNEL, -1, __builtin_return_address(0)); + } + EXPORT_SYMBOL(vmalloc_32); + +@@ -687,7 +690,7 @@ void *vmalloc_32_user(unsigned long size + struct vm_struct *area; + void *ret; + +- ret = __vmalloc(size, GFP_VMALLOC32 | __GFP_ZERO, PAGE_KERNEL); ++ ret = __vmalloc_node(size, GFP_VMALLOC32 | __GFP_ZERO, PAGE_KERNEL, -1, __builtin_return_address(0)); + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); diff --git a/src/patches/suse-2.6.27.31/patches.suse/mnt-want-write-speedup.patch b/src/patches/suse-2.6.27.31/patches.suse/mnt-want-write-speedup.patch new file mode 100644 index 000000000..22a3d3988 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mnt-want-write-speedup.patch @@ -0,0 +1,417 @@ +From: Nick Piggin +Subject: fs: mnt_want_write speedup +References: bnc#436953 +Patch-upstream: no (could be submitted) + +This patch speeds up lmbench lat_mmap test by about 8%. lat_mmap is set up +basically to mmap a 64MB file on tmpfs, fault in its pages, then unmap it. +A microbenchmark yes, but it exercises some important paths in the mm. + +Before: + avg = 501.9 + std = 14.7773 + +After: + avg = 462.286 + std = 5.46106 + +(50 runs of each, stddev gives a reasonable confidence, but there is quite +a bit of variation there still) + +It does this by removing the complex per-cpu locking and counter-cache and +replaces it with a percpu counter in struct vfsmount. This makes the code +much simpler, and avoids spinlocks (although the msync is still pretty +costly, unfortunately). It results in about 900 bytes smaller code too. It +does increase the size of a vfsmount, however. + +It should also give a speedup on large systems if CPUs are frequently operating +on different mounts (because the existing scheme has to operate on an atomic in +the struct vfsmount when switching between mounts). But I'm most interested in +the single threaded path performance for the moment. + +--- + fs/namespace.c | 251 +++++++++++++++----------------------------------- + include/linux/mount.h | 18 +++ + 2 files changed, 96 insertions(+), 173 deletions(-) + +--- linux-2.6.27.orig/fs/namespace.c ++++ linux-2.6.27/fs/namespace.c +@@ -130,10 +130,20 @@ struct vfsmount *alloc_vfsmnt(const char + INIT_LIST_HEAD(&mnt->mnt_share); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + INIT_LIST_HEAD(&mnt->mnt_slave); +- atomic_set(&mnt->__mnt_writers, 0); ++#ifdef CONFIG_SMP ++ mnt->mnt_writers = alloc_percpu(int); ++ if (!mnt->mnt_writers) ++ goto out_free_devname; ++#else ++ mnt->mnt_writers = 0; ++#endif + } + return mnt; + ++#ifdef CONFIG_SMP ++out_free_devname: ++ kfree(mnt->mnt_devname); ++#endif + out_free_id: + mnt_free_id(mnt); + out_free_cache: +@@ -170,65 +180,38 @@ int __mnt_is_readonly(struct vfsmount *m + } + EXPORT_SYMBOL_GPL(__mnt_is_readonly); + +-struct mnt_writer { +- /* +- * If holding multiple instances of this lock, they +- * must be ordered by cpu number. +- */ +- spinlock_t lock; +- struct lock_class_key lock_class; /* compiles out with !lockdep */ +- unsigned long count; +- struct vfsmount *mnt; +-} ____cacheline_aligned_in_smp; +-static DEFINE_PER_CPU(struct mnt_writer, mnt_writers); ++static inline void inc_mnt_writers(struct vfsmount *mnt) ++{ ++#ifdef CONFIG_SMP ++ (*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))++; ++#else ++ mnt->mnt_writers++; ++#endif ++} + +-static int __init init_mnt_writers(void) ++static inline void dec_mnt_writers(struct vfsmount *mnt) + { +- int cpu; +- for_each_possible_cpu(cpu) { +- struct mnt_writer *writer = &per_cpu(mnt_writers, cpu); +- spin_lock_init(&writer->lock); +- lockdep_set_class(&writer->lock, &writer->lock_class); +- writer->count = 0; +- } +- return 0; ++#ifdef CONFIG_SMP ++ (*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))--; ++#else ++ mnt->mnt_writers--; ++#endif + } +-fs_initcall(init_mnt_writers); + +-static void unlock_mnt_writers(void) ++static unsigned int count_mnt_writers(struct vfsmount *mnt) + { ++#ifdef CONFIG_SMP ++ unsigned int count = 0; + int cpu; +- struct mnt_writer *cpu_writer; + + for_each_possible_cpu(cpu) { +- cpu_writer = &per_cpu(mnt_writers, cpu); +- spin_unlock(&cpu_writer->lock); ++ count += *per_cpu_ptr(mnt->mnt_writers, cpu); + } +-} + +-static inline void __clear_mnt_count(struct mnt_writer *cpu_writer) +-{ +- if (!cpu_writer->mnt) +- return; +- /* +- * This is in case anyone ever leaves an invalid, +- * old ->mnt and a count of 0. +- */ +- if (!cpu_writer->count) +- return; +- atomic_add(cpu_writer->count, &cpu_writer->mnt->__mnt_writers); +- cpu_writer->count = 0; +-} +- /* +- * must hold cpu_writer->lock +- */ +-static inline void use_cpu_writer_for_mount(struct mnt_writer *cpu_writer, +- struct vfsmount *mnt) +-{ +- if (cpu_writer->mnt == mnt) +- return; +- __clear_mnt_count(cpu_writer); +- cpu_writer->mnt = mnt; ++ return count; ++#else ++ return mnt->mnt_writers; ++#endif + } + + /* +@@ -252,75 +235,34 @@ static inline void use_cpu_writer_for_mo + int mnt_want_write(struct vfsmount *mnt) + { + int ret = 0; +- struct mnt_writer *cpu_writer; + +- cpu_writer = &get_cpu_var(mnt_writers); +- spin_lock(&cpu_writer->lock); ++ preempt_disable(); ++ inc_mnt_writers(mnt); ++ /* ++ * The store to inc_mnt_writers must be visible before we pass ++ * MNT_WRITE_HOLD loop below, so that the slowpath can see our ++ * incremented count after it has set MNT_WRITE_HOLD. ++ */ ++ smp_mb(); ++ while (mnt->mnt_flags & MNT_WRITE_HOLD) ++ cpu_relax(); ++ /* ++ * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will ++ * be set to match its requirements. So we must not load that until ++ * MNT_WRITE_HOLD is cleared. ++ */ ++ smp_rmb(); + if (__mnt_is_readonly(mnt)) { ++ dec_mnt_writers(mnt); + ret = -EROFS; + goto out; + } +- use_cpu_writer_for_mount(cpu_writer, mnt); +- cpu_writer->count++; + out: +- spin_unlock(&cpu_writer->lock); +- put_cpu_var(mnt_writers); ++ preempt_enable(); + return ret; + } + EXPORT_SYMBOL_GPL(mnt_want_write); + +-static void lock_mnt_writers(void) +-{ +- int cpu; +- struct mnt_writer *cpu_writer; +- +- for_each_possible_cpu(cpu) { +- cpu_writer = &per_cpu(mnt_writers, cpu); +- spin_lock(&cpu_writer->lock); +- __clear_mnt_count(cpu_writer); +- cpu_writer->mnt = NULL; +- } +-} +- +-/* +- * These per-cpu write counts are not guaranteed to have +- * matched increments and decrements on any given cpu. +- * A file open()ed for write on one cpu and close()d on +- * another cpu will imbalance this count. Make sure it +- * does not get too far out of whack. +- */ +-static void handle_write_count_underflow(struct vfsmount *mnt) +-{ +- if (atomic_read(&mnt->__mnt_writers) >= +- MNT_WRITER_UNDERFLOW_LIMIT) +- return; +- /* +- * It isn't necessary to hold all of the locks +- * at the same time, but doing it this way makes +- * us share a lot more code. +- */ +- lock_mnt_writers(); +- /* +- * vfsmount_lock is for mnt_flags. +- */ +- spin_lock(&vfsmount_lock); +- /* +- * If coalescing the per-cpu writer counts did not +- * get us back to a positive writer count, we have +- * a bug. +- */ +- if ((atomic_read(&mnt->__mnt_writers) < 0) && +- !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { +- WARN(1, KERN_DEBUG "leak detected on mount(%p) writers " +- "count: %d\n", +- mnt, atomic_read(&mnt->__mnt_writers)); +- /* use the flag to keep the dmesg spam down */ +- mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; +- } +- spin_unlock(&vfsmount_lock); +- unlock_mnt_writers(); +-} +- + /** + * mnt_drop_write - give up write access to a mount + * @mnt: the mount on which to give up write access +@@ -331,37 +273,9 @@ static void handle_write_count_underflow + */ + void mnt_drop_write(struct vfsmount *mnt) + { +- int must_check_underflow = 0; +- struct mnt_writer *cpu_writer; +- +- cpu_writer = &get_cpu_var(mnt_writers); +- spin_lock(&cpu_writer->lock); +- +- use_cpu_writer_for_mount(cpu_writer, mnt); +- if (cpu_writer->count > 0) { +- cpu_writer->count--; +- } else { +- must_check_underflow = 1; +- atomic_dec(&mnt->__mnt_writers); +- } +- +- spin_unlock(&cpu_writer->lock); +- /* +- * Logically, we could call this each time, +- * but the __mnt_writers cacheline tends to +- * be cold, and makes this expensive. +- */ +- if (must_check_underflow) +- handle_write_count_underflow(mnt); +- /* +- * This could be done right after the spinlock +- * is taken because the spinlock keeps us on +- * the cpu, and disables preemption. However, +- * putting it here bounds the amount that +- * __mnt_writers can underflow. Without it, +- * we could theoretically wrap __mnt_writers. +- */ +- put_cpu_var(mnt_writers); ++ preempt_disable(); ++ dec_mnt_writers(mnt); ++ preempt_enable(); + } + EXPORT_SYMBOL_GPL(mnt_drop_write); + +@@ -369,24 +283,34 @@ static int mnt_make_readonly(struct vfsm + { + int ret = 0; + +- lock_mnt_writers(); ++ spin_lock(&vfsmount_lock); ++ mnt->mnt_flags |= MNT_WRITE_HOLD; + /* +- * With all the locks held, this value is stable ++ * After storing MNT_WRITE_HOLD, we'll read the counters. This store ++ * should be visible before we do. + */ +- if (atomic_read(&mnt->__mnt_writers) > 0) { ++ smp_mb(); ++ ++ /* ++ * With writers on hold, if this value is zero, then there are definitely ++ * no active writers (although held writers may subsequently increment ++ * the count, they'll have to wait, and decrement it after seeing ++ * MNT_READONLY). ++ */ ++ if (count_mnt_writers(mnt) > 0) { + ret = -EBUSY; + goto out; + } +- /* +- * nobody can do a successful mnt_want_write() with all +- * of the counts in MNT_DENIED_WRITE and the locks held. +- */ +- spin_lock(&vfsmount_lock); + if (!ret) + mnt->mnt_flags |= MNT_READONLY; +- spin_unlock(&vfsmount_lock); + out: +- unlock_mnt_writers(); ++ /* ++ * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers ++ * that become unheld will see MNT_READONLY. ++ */ ++ smp_wmb(); ++ mnt->mnt_flags &= ~MNT_WRITE_HOLD; ++ spin_unlock(&vfsmount_lock); + return ret; + } + +@@ -410,6 +334,9 @@ void free_vfsmnt(struct vfsmount *mnt) + { + kfree(mnt->mnt_devname); + mnt_free_id(mnt); ++#ifdef CONFIG_SMP ++ free_percpu(mnt->mnt_writers); ++#endif + kmem_cache_free(mnt_cache, mnt); + } + +@@ -604,36 +531,14 @@ static struct vfsmount *clone_mnt(struct + + static inline void __mntput(struct vfsmount *mnt) + { +- int cpu; + struct super_block *sb = mnt->mnt_sb; + /* +- * We don't have to hold all of the locks at the +- * same time here because we know that we're the +- * last reference to mnt and that no new writers +- * can come in. +- */ +- for_each_possible_cpu(cpu) { +- struct mnt_writer *cpu_writer = &per_cpu(mnt_writers, cpu); +- if (cpu_writer->mnt != mnt) +- continue; +- spin_lock(&cpu_writer->lock); +- atomic_add(cpu_writer->count, &mnt->__mnt_writers); +- cpu_writer->count = 0; +- /* +- * Might as well do this so that no one +- * ever sees the pointer and expects +- * it to be valid. +- */ +- cpu_writer->mnt = NULL; +- spin_unlock(&cpu_writer->lock); +- } +- /* + * This probably indicates that somebody messed + * up a mnt_want/drop_write() pair. If this + * happens, the filesystem was probably unable + * to make r/w->r/o transitions. + */ +- WARN_ON(atomic_read(&mnt->__mnt_writers)); ++ WARN_ON(count_mnt_writers(mnt)); + dput(mnt->mnt_root); + free_vfsmnt(mnt); + deactivate_super(sb); +--- linux-2.6.27.orig/include/linux/mount.h ++++ linux-2.6.27/include/linux/mount.h +@@ -32,6 +32,7 @@ struct mnt_namespace; + + #define MNT_SHRINKABLE 0x100 + #define MNT_IMBALANCED_WRITE_COUNT 0x200 /* just for debugging */ ++#define MNT_WRITE_HOLD 0x400 + + #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ + #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ +@@ -66,13 +67,30 @@ struct vfsmount { + int mnt_expiry_mark; /* true if marked for expiry */ + int mnt_pinned; + int mnt_ghosts; ++#ifdef __GENKSYMS__ + /* + * This value is not stable unless all of the mnt_writers[] spinlocks + * are held, and all mnt_writer[]s on this mount have 0 as their ->count + */ + atomic_t __mnt_writers; ++#else ++#ifdef CONFIG_SMP ++ int *mnt_writers; ++#else ++ int mnt_writers; ++#endif ++#endif + }; + ++static inline int *get_mnt_writers_ptr(struct vfsmount *mnt) ++{ ++#ifdef CONFIG_SMP ++ return mnt->mnt_writers; ++#else ++ return &mnt->mnt_writers; ++#endif ++} ++ + static inline struct vfsmount *mntget(struct vfsmount *mnt) + { + if (mnt) diff --git a/src/patches/suse-2.6.27.31/patches.suse/mnt_clone_write.patch b/src/patches/suse-2.6.27.31/patches.suse/mnt_clone_write.patch new file mode 100644 index 000000000..e51b8875e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/mnt_clone_write.patch @@ -0,0 +1,196 @@ +From: Nick Piggin +Subject: fs: introduce mnt_clone_write +References: bnc#436953 +Patch-upstream: no (could be submitted) + +This patch speeds up lmbench lat_mmap test by about another 2% after the +first patch. + +Before: + avg = 462.286 + std = 5.46106 + +After: + avg = 453.12 + std = 9.58257 + +(50 runs of each, stddev gives a reasonable confidence) + +It does this by introducing mnt_clone_write, which avoids some heavyweight +operations of mnt_want_write if called on a vfsmount which we know already +has a write count; and mnt_want_write_file, which can call mnt_clone_write +if the file is open for write. + +After these two patches, mnt_want_write and mnt_drop_write go from 7% on +the profile down to 1.3% (including mnt_clone_write). + +--- + fs/file_table.c | 2 - + fs/inode.c | 2 - + fs/namespace.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/open.c | 4 +-- + fs/xattr.c | 4 +-- + include/linux/mount.h | 5 +++ + 6 files changed, 74 insertions(+), 6 deletions(-) + +Index: linux-2.6.27/fs/file_table.c +=================================================================== +--- linux-2.6.27.orig/fs/file_table.c ++++ linux-2.6.27/fs/file_table.c +@@ -210,7 +210,7 @@ int init_file(struct file *file, struct + */ + if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) { + file_take_write(file); +- error = mnt_want_write(mnt); ++ error = mnt_clone_write_2(mnt); + WARN_ON(error); + } + return error; +Index: linux-2.6.27/fs/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/inode.c ++++ linux-2.6.27/fs/inode.c +@@ -1256,7 +1256,7 @@ void file_update_time(struct file *file) + if (IS_NOCMTIME(inode)) + return; + +- err = mnt_want_write(file->f_path.mnt); ++ err = mnt_want_write_file(file->f_path.mnt, file); + if (err) + return; + +Index: linux-2.6.27/fs/namespace.c +=================================================================== +--- linux-2.6.27.orig/fs/namespace.c ++++ linux-2.6.27/fs/namespace.c +@@ -264,6 +264,69 @@ out: + EXPORT_SYMBOL_GPL(mnt_want_write); + + /** ++ * mnt_clone_write - get write access to a mount ++ * @mnt: the mount on which to take a write ++ * ++ * This is effectively like mnt_want_write, except ++ * it must only be used to take an extra write reference ++ * on a mountpoint that we already know has a write reference ++ * on it. This allows some optimisation. ++ * ++ * The caller should really check __mnt_is_readonly before callint ++ * mnt_clone_write. See mnt_clone_write_2. ++ * ++ * After finished, mnt_drop_write must be called as usual to ++ * drop the reference. ++ */ ++void mnt_clone_write(struct vfsmount *mnt) ++{ ++ preempt_disable(); ++ inc_mnt_writers(mnt); ++ preempt_enable(); ++} ++EXPORT_SYMBOL_GPL(mnt_clone_write); ++ ++/** ++ * mnt_clone_write_2 - get write access to a mount ++ * @mnt: the mount on which to take a write ++ * ++ * Same as mnt_clone_write, but it performs the __mnt_is_readonly ++ * check itself, and returns -error on failure. This is the preferred ++ * function. This is here to preserve kABI compatibility. ++ * ++ * After finished, mnt_drop_write must be called as usual to ++ * drop the reference. ++ */ ++int mnt_clone_write_2(struct vfsmount *mnt) ++{ ++ /* superblock may be r/o */ ++ if (__mnt_is_readonly(mnt)) ++ return -EROFS; ++ preempt_disable(); ++ inc_mnt_writers(mnt); ++ preempt_enable(); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mnt_clone_write_2); ++ ++/** ++ * mnt_want_write_file - get write access to a file's mount ++ * @file: the file who's mount on which to take a write ++ * ++ * This is like mnt_want_write, but it takes a file and can ++ * do some optimisations if the file is open for write already ++ */ ++int mnt_want_write_file(struct vfsmount *mnt, struct file *file) ++{ ++ struct inode *inode = file->f_dentry->d_inode; ++ if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) ++ return mnt_want_write(mnt); ++ else ++ return mnt_clone_write_2(mnt); ++} ++EXPORT_SYMBOL_GPL(mnt_want_write_file); ++ ++/** + * mnt_drop_write - give up write access to a mount + * @mnt: the mount on which to give up write access + * +Index: linux-2.6.27/fs/open.c +=================================================================== +--- linux-2.6.27.orig/fs/open.c ++++ linux-2.6.27/fs/open.c +@@ -616,7 +616,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd + + audit_inode(NULL, dentry); + +- err = mnt_want_write(file->f_path.mnt); ++ err = mnt_want_write_file(file->f_path.mnt, file); + if (err) + goto out_putf; + mutex_lock(&inode->i_mutex); +@@ -765,7 +765,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd + if (!file) + goto out; + +- error = mnt_want_write(file->f_path.mnt); ++ error = mnt_want_write_file(file->f_path.mnt, file); + if (error) + goto out_fput; + dentry = file->f_path.dentry; +Index: linux-2.6.27/fs/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/xattr.c ++++ linux-2.6.27/fs/xattr.c +@@ -301,7 +301,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons + return error; + dentry = f->f_path.dentry; + audit_inode(NULL, dentry); +- error = mnt_want_write(f->f_path.mnt); ++ error = mnt_want_write_file(f->f_path.mnt, f); + if (!error) { + error = setxattr(dentry, name, value, size, flags); + mnt_drop_write(f->f_path.mnt); +@@ -528,7 +528,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c + return error; + dentry = f->f_path.dentry; + audit_inode(NULL, dentry); +- error = mnt_want_write(f->f_path.mnt); ++ error = mnt_want_write_file(f->f_path.mnt, f); + if (!error) { + error = removexattr(dentry, name); + mnt_drop_write(f->f_path.mnt); +Index: linux-2.6.27/include/linux/mount.h +=================================================================== +--- linux-2.6.27.orig/include/linux/mount.h ++++ linux-2.6.27/include/linux/mount.h +@@ -98,7 +98,12 @@ static inline struct vfsmount *mntget(st + return mnt; + } + ++struct file; ++ + extern int mnt_want_write(struct vfsmount *mnt); ++extern int mnt_want_write_file(struct vfsmount *mnt, struct file *file); ++extern void mnt_clone_write(struct vfsmount *mnt); ++extern int mnt_clone_write_2(struct vfsmount *mnt); + extern void mnt_drop_write(struct vfsmount *mnt); + extern void mntput_no_expire(struct vfsmount *mnt); + extern void mnt_pin(struct vfsmount *mnt); diff --git a/src/patches/suse-2.6.27.31/patches.suse/modpost-filter-out-built-in-depends b/src/patches/suse-2.6.27.31/patches.suse/modpost-filter-out-built-in-depends new file mode 100644 index 000000000..fd282e91e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/modpost-filter-out-built-in-depends @@ -0,0 +1,27 @@ +From: Michal Marek +Subject: modpost: filter out "built-in" depends +References: bnc#450085 + +In the binary spec files, we "annotate" the Module.symvers file with +information where particular vmlinux exports come from. This annotation +confuses modpost when building external modules. This patch makes modpost +treat "built-in" exports as vmlinux exports, so that these don't show up +in modules' depends: fields. + +Signed-off-by: Michal Marek +--- + scripts/mod/modpost.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -86,7 +86,8 @@ static int is_vmlinux(const char *modnam + myname = modname; + + return (strcmp(myname, "vmlinux") == 0) || +- (strcmp(myname, "vmlinux.o") == 0); ++ (strcmp(myname, "vmlinux.o") == 0) || ++ (strcmp(myname, "built-in") == 0); + } + + void *do_nofail(void *ptr, const char *expr) diff --git a/src/patches/suse-2.6.27.31/patches.suse/module-ref-dynamic-alloc b/src/patches/suse-2.6.27.31/patches.suse/module-ref-dynamic-alloc new file mode 100644 index 000000000..388fe65d0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/module-ref-dynamic-alloc @@ -0,0 +1,110 @@ +From: Takashi Iwai +Subject: [PATCH] Allocate module.ref array dynamically +Patch-mainline: +References: bnc#425240 + +This patch makes the module handling code to allocate the ref +array of each module struct dynamically. It saves both module +disk space and memory footprints when number of CPUs is high +like 4096. + +Reference: Novell bnc#425240 + https://bugzilla.novell.com/show_bug.cgi?id=425240 + +Signed-off-by: Takashi Iwai + +--- + include/linux/module.h | 2 +- + kernel/module.c | 21 ++++++++++++++++----- + 2 files changed, 17 insertions(+), 6 deletions(-) + +Index: linux-2.6.27/kernel/module.c +=================================================================== +--- linux-2.6.27.orig/kernel/module.c ++++ linux-2.6.27/kernel/module.c +@@ -557,17 +557,28 @@ static char last_unloaded_module[MODULE_ + + #ifdef CONFIG_MODULE_UNLOAD + /* Init the unload section of the module. */ +-static void module_unload_init(struct module *mod) ++static int module_unload_init(struct module *mod) + { + unsigned int i; ++ size_t refsize = nr_cpu_ids * sizeof(*mod->ref); + + INIT_LIST_HEAD(&mod->modules_which_use_me); +- for (i = 0; i < NR_CPUS; i++) ++ ++ mod->ref = kzalloc(refsize, GFP_KERNEL); ++ if (!mod->ref) { ++ mod->ref = vmalloc(refsize); ++ if (!mod->ref) ++ return -ENOMEM; ++ memset(mod->ref, 0, refsize); ++ } ++ for (i = 0; i < nr_cpu_ids; i++) + local_set(&mod->ref[i].count, 0); + /* Hold reference count during initialization. */ + local_set(&mod->ref[raw_smp_processor_id()].count, 1); + /* Backwards compatibility macros put refcount during init. */ + mod->waiter = current; ++ ++ return 0; + } + + /* modules using other modules */ +@@ -647,6 +658,10 @@ static void module_unload_free(struct mo + } + } + } ++ if (is_vmalloc_addr(mod->ref)) ++ vfree(mod->ref); ++ else ++ kfree(mod->ref); + } + + #ifdef CONFIG_MODULE_FORCE_UNLOAD +@@ -705,7 +720,7 @@ unsigned int module_refcount(struct modu + { + unsigned int i, total = 0; + +- for (i = 0; i < NR_CPUS; i++) ++ for (i = 0; i < nr_cpu_ids; i++) + total += local_read(&mod->ref[i].count); + return total; + } +@@ -894,8 +909,9 @@ static inline int use_module(struct modu + return strong_try_module_get(b) == 0; + } + +-static inline void module_unload_init(struct module *mod) ++static inline int module_unload_init(struct module *mod) + { ++ return 0; + } + #endif /* CONFIG_MODULE_UNLOAD */ + +@@ -2108,7 +2124,9 @@ static noinline struct module *load_modu + mod = (void *)sechdrs[modindex].sh_addr; + + /* Now we've moved module, initialize linked lists, etc. */ +- module_unload_init(mod); ++ err = module_unload_init(mod); ++ if (err) ++ goto free_unload; + + /* add kobject, so we can reference it. */ + err = mod_sysfs_init(mod); +Index: linux-2.6.27/include/linux/module.h +=================================================================== +--- linux-2.6.27.orig/include/linux/module.h ++++ linux-2.6.27/include/linux/module.h +@@ -343,7 +343,7 @@ struct module + void (*exit)(void); + + /* Reference counts */ +- struct module_ref ref[NR_CPUS]; ++ struct module_ref *ref; + #endif + }; + #ifndef MODULE_ARCH_INIT diff --git a/src/patches/suse-2.6.27.31/patches.suse/nameif-track-rename.patch b/src/patches/suse-2.6.27.31/patches.suse/nameif-track-rename.patch new file mode 100644 index 000000000..1df72268a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/nameif-track-rename.patch @@ -0,0 +1,50 @@ +Subject: [PATCH] keep track of network interface renaming +From: Olaf Hering + +Keep track about which network interface names were renamed after the +network device driver printed its banner. Example insanity: + +honeydew:~ # dmesg| grep -Ew '(eth[0-9]|rename|renamed)' +e1000: eth0: e1000_probe: Intel(R) PRO/1000 Network Connection +e1000: eth1: e1000_probe: Intel(R) PRO/1000 Network Connection +e1000: eth2: e1000_probe: Intel(R) PRO/1000 Network Connection +e1000: eth3: e1000_probe: Intel(R) PRO/1000 Network Connection +dev_change_name: about to rename 'eth3' to 'eth0' +dev_change_name: about to rename 'eth3' to 'ethxx3' +eth3 renamed to ethxx3 +dev_change_name: about to rename 'ethxx3' to 'eth0' +dev_change_name: about to rename 'eth0' to 'eth3' +eth0 renamed to eth3 +dev_change_name: about to rename 'eth1' to 'eth2' +dev_change_name: about to rename 'eth1' to 'ethxx1' +eth1 renamed to ethxx1 +dev_change_name: about to rename 'ethxx1' to 'eth2' +dev_change_name: about to rename 'eth2' to 'eth1' +eth2 renamed to eth1 +dev_change_name: about to rename 'ethxx3' to 'eth0' +ethxx3 renamed to eth0 +dev_change_name: about to rename 'ethxx1' to 'eth2' +ethxx1 renamed to eth2 +e1000: eth0: e1000_watchdog_task: NIC Link is Up 100 Mbps Full Duplex + + + +Signed-off-by: Olaf Hering + + net/core/dev.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -922,7 +922,11 @@ int dev_change_name(struct net_device *d + else if (__dev_get_by_name(net, newname)) + return -EEXIST; + else ++ { ++ if (strncmp(newname, dev->name, IFNAMSIZ)) ++ printk(KERN_INFO "%s renamed to %s by %s [%u]\n", dev->name, newname, current->comm, current->pid); + strlcpy(dev->name, newname, IFNAMSIZ); ++ } + + rollback: + err = device_rename(&dev->dev, dev->name); diff --git a/src/patches/suse-2.6.27.31/patches.suse/netfilter-ip_conntrack_slp.patch b/src/patches/suse-2.6.27.31/patches.suse/netfilter-ip_conntrack_slp.patch new file mode 100644 index 000000000..7cda76dc2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/netfilter-ip_conntrack_slp.patch @@ -0,0 +1,180 @@ +From: Jiri Bohac +Subject: connection tracking helper for SLP +References: fate#301134 + +A simple connection tracking helper for SLP. Marks replies to a +SLP broadcast query as ESTABLISHED to allow them to pass through the +firewall. + +Signed-off-by: Jiri Bohac + +--- + net/netfilter/Kconfig | 15 ++++ + net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_slp.c | 127 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 143 insertions(+) + +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -278,6 +278,21 @@ config NF_CONNTRACK_TFTP + + To compile it as a module, choose M here. If unsure, say N. + ++config NF_CONNTRACK_SLP ++ tristate "SLP protocol support" ++ depends on NF_CONNTRACK ++ depends on NETFILTER_ADVANCED ++ help ++ SLP queries are sometimes sent as broadcast messages from an ++ unprivileged port and responded to with unicast messages to the ++ same port. This make them hard to firewall properly because connection ++ tracking doesn't deal with broadcasts. This helper tracks locally ++ originating broadcast SLP queries and the corresponding ++ responses. It relies on correct IP address configuration, specifically ++ netmask and broadcast address. ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ + config NF_CT_NETLINK + tristate 'Connection tracking netlink interface' + depends on NF_CONNTRACK +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_co + obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o + obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o + obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o ++obj-$(CONFIG_NF_CONNTRACK_SLP) += nf_conntrack_slp.o + + # generic X tables + obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o +--- /dev/null ++++ b/net/netfilter/nf_conntrack_slp.c +@@ -0,0 +1,127 @@ ++/* ++ * NetBIOS name service broadcast connection tracking helper ++ * ++ * (c) 2007 Jiri Bohac ++ * (c) 2005 Patrick McHardy ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++/* ++ * This helper tracks locally originating NetBIOS name service ++ * requests by issuing permanent expectations (valid until ++ * timing out) matching all reply connections from the ++ * destination network. The only NetBIOS specific thing is ++ * actually the port number. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define SLP_PORT 427 ++ ++MODULE_AUTHOR("Jiri Bohac "); ++MODULE_DESCRIPTION("SLP broadcast connection tracking helper"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ip_conntrack_slp"); ++ ++static unsigned int timeout __read_mostly = 3; ++module_param(timeout, uint, 0400); ++MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); ++ ++static int help(struct sk_buff *skb, unsigned int protoff, ++ struct nf_conn *ct, enum ip_conntrack_info ctinfo) ++{ ++ struct nf_conntrack_expect *exp; ++ struct iphdr *iph = ip_hdr(skb); ++ struct rtable *rt = skb->rtable; ++ struct in_device *in_dev; ++ __be32 mask = 0; ++ ++ /* we're only interested in locally generated packets */ ++ if (skb->sk == NULL) ++ goto out; ++ if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST)) ++ goto out; ++ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) ++ goto out; ++ ++ rcu_read_lock(); ++ in_dev = __in_dev_get_rcu(rt->u.dst.dev); ++ if (in_dev != NULL) { ++ for_primary_ifa(in_dev) { ++ if (ifa->ifa_broadcast == iph->daddr) { ++ mask = ifa->ifa_mask; ++ break; ++ } ++ } endfor_ifa(in_dev); ++ } ++ rcu_read_unlock(); ++ ++ if (mask == 0) ++ goto out; ++ ++ exp = nf_ct_expect_alloc(ct); ++ if (exp == NULL) ++ goto out; ++ ++ exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ exp->tuple.src.u.udp.port = htons(SLP_PORT); ++ ++ exp->mask.src.u3.ip = mask; ++ exp->mask.src.u.udp.port = htons(0xFFFF); ++ ++ exp->expectfn = NULL; ++ exp->flags = NF_CT_EXPECT_PERMANENT; ++ exp->class = NF_CT_EXPECT_CLASS_DEFAULT; ++ exp->helper = NULL; ++ ++ nf_ct_expect_related(exp); ++ nf_ct_expect_put(exp); ++ ++ nf_ct_refresh(ct, skb, timeout * HZ); ++out: ++ return NF_ACCEPT; ++} ++ ++static struct nf_conntrack_expect_policy exp_policy = { ++ .max_expected = 1, ++}; ++ ++static struct nf_conntrack_helper helper __read_mostly = { ++ .name = "slp", ++ .tuple.src.l3num = AF_INET, ++ .tuple.src.u.udp.port = __constant_htons(SLP_PORT), ++ .tuple.dst.protonum = IPPROTO_UDP, ++ .me = THIS_MODULE, ++ .help = help, ++ .expect_policy = &exp_policy, ++}; ++ ++static int __init nf_conntrack_slp_init(void) ++{ ++ exp_policy.timeout = timeout; ++ return nf_conntrack_helper_register(&helper); ++} ++ ++static void __exit nf_conntrack_slp_fini(void) ++{ ++ nf_conntrack_helper_unregister(&helper); ++} ++ ++module_init(nf_conntrack_slp_init); ++module_exit(nf_conntrack_slp_fini); diff --git a/src/patches/suse-2.6.27.31/patches.suse/netfilter-ipt_LOG-mac b/src/patches/suse-2.6.27.31/patches.suse/netfilter-ipt_LOG-mac new file mode 100644 index 000000000..dfc104a81 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/netfilter-ipt_LOG-mac @@ -0,0 +1,32 @@ +From: Jaroslav Kysela +Subject: LTC23987-iptables LOG output shows too long MAC info +References: 176921 + +LTC23987-iptables LOG output shows too long MAC info for qeth VLAN interface + +Signed-off-by: Jaroslav Kysela + +--- + net/ipv4/netfilter/ipt_LOG.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/net/ipv4/netfilter/ipt_LOG.c ++++ b/net/ipv4/netfilter/ipt_LOG.c +@@ -410,12 +410,12 @@ ipt_log_packet(unsigned int pf, + printk("MAC="); + if (skb->dev && skb->dev->hard_header_len + && skb->mac_header != skb->network_header) { +- int i; ++ int i, len; + const unsigned char *p = skb_mac_header(skb); +- for (i = 0; i < skb->dev->hard_header_len; i++,p++) +- printk("%02x%c", *p, +- i==skb->dev->hard_header_len - 1 +- ? ' ':':'); ++ len = (int)(skb_network_header(skb) - p); ++ len = min((int)skb->dev->hard_header_len, len); ++ for (i = 0; i < len; i++,p++) ++ printk("%02x%c", *p, i==len - 1 ? ' ':':'); + } else + printk(" "); + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/netfilter-ipv4options b/src/patches/suse-2.6.27.31/patches.suse/netfilter-ipv4options new file mode 100644 index 000000000..415b2a200 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/netfilter-ipv4options @@ -0,0 +1,254 @@ +From: Fabrice MARIE +From: Harald Welte +Subject: netfilter ipv4options match from patch-o-matic-ng +References: bnc#131728 - FATE#182 + +This is a module which is used to match ipv4 options. + +Updated-by: Jeff Mahoney + +Acked-by: Olaf Kirch +Acked-by: Jaroslav Kysela +--- + + include/linux/netfilter_ipv4/ipt_ipv4options.h | 21 +++ + net/ipv4/netfilter/Kconfig | 14 ++ + net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_ipv4options.c | 175 +++++++++++++++++++++++++ + 4 files changed, 211 insertions(+) + +--- /dev/null ++++ b/include/linux/netfilter_ipv4/ipt_ipv4options.h +@@ -0,0 +1,21 @@ ++#ifndef __ipt_ipv4options_h_included__ ++#define __ipt_ipv4options_h_included__ ++ ++#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */ ++#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */ ++#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */ ++#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */ ++#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10 ++#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */ ++#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40 ++#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */ ++#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100 ++#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */ ++#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */ ++ ++struct ipt_ipv4options_info { ++ u_int16_t options; ++}; ++ ++ ++#endif /* __ipt_ipv4options_h_included__ */ +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -111,6 +111,20 @@ config IP_NF_MATCH_ADDRTYPE + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++config IP_NF_MATCH_IPV4OPTIONS ++ tristate 'IPV4OPTIONS match support' ++ depends on IP_NF_IPTABLES ++ help ++ This option adds a IPV4OPTIONS match. ++ It allows you to filter options like source routing, ++ record route, timestamp and router-altert. ++ ++ If you say Y here, try iptables -m ipv4options --help for more information. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say 'N'. ++ ++ + # `filter', generic and specific targets + config IP_NF_FILTER + tristate "Packet filtering" +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o + obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o + obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o + obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o ++obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o + + # targets + obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o +--- /dev/null ++++ b/net/ipv4/netfilter/ipt_ipv4options.c +@@ -0,0 +1,175 @@ ++/* ++ This is a module which is used to match ipv4 options. ++ This file is distributed under the terms of the GNU General Public ++ License (GPL). Copies of the GPL can be obtained from: ++ ftp://prep.ai.mit.edu/pub/gnu/GPL ++ ++ 11-mars-2001 Fabrice MARIE : initial development. ++ 12-july-2001 Fabrice MARIE : added router-alert otions matching. Fixed a bug with no-srr ++ 12-august-2001 Imran Patel : optimization of the match. ++ 18-november-2001 Fabrice MARIE : added [!] 'any' option match. ++ 19-february-2004 Harald Welte : merge with 2.6.x ++*/ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Fabrice Marie "); ++ ++static bool ++match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const struct xt_match *match, ++ const void *matchinfo, ++ int offset, ++ unsigned int protoff, ++ bool *hotdrop) ++{ ++ const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ ++ const struct iphdr *iph = ip_hdr(skb); ++ const struct ip_options *opt; ++ ++ if (iph->ihl * 4 == sizeof(struct iphdr)) { ++ /* No options, so we match only the "DONTs" and the "IGNOREs" */ ++ ++ if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) || ++ ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) || ++ ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT)) ++ return 0; ++ return 1; ++ } ++ else { ++ if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ++ /* there are options, and we don't need to care which one */ ++ return 1; ++ else { ++ if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) ++ /* there are options but we don't want any ! */ ++ return 0; ++ } ++ } ++ ++ opt = &(IPCB(skb)->opt); ++ ++ /* source routing */ ++ if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) { ++ if (!((opt->srr) && (opt->is_strictroute))) ++ return 0; ++ } ++ else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) { ++ if (!((opt->srr) && (!opt->is_strictroute))) ++ return 0; ++ } ++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) { ++ if (opt->srr) ++ return 0; ++ } ++ /* record route */ ++ if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) { ++ if (!opt->rr) ++ return 0; ++ } ++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) { ++ if (opt->rr) ++ return 0; ++ } ++ /* timestamp */ ++ if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) { ++ if (!opt->ts) ++ return 0; ++ } ++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) { ++ if (opt->ts) ++ return 0; ++ } ++ /* router-alert option */ ++ if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) { ++ if (!opt->router_alert) ++ return 0; ++ } ++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) { ++ if (opt->router_alert) ++ return 0; ++ } ++ ++ /* we match ! */ ++ return 1; ++} ++ ++static bool ++checkentry(const char *tablename, ++ const void *ip, ++ const struct xt_match *match, ++ void *matchinfo, ++ unsigned int hook_mask) ++{ ++ const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ ++ /* Check the size */ ++ if (match->matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info))) ++ return 0; ++ /* Now check the coherence of the data ... */ ++ if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) && ++ (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) || ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) || ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) || ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) || ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT))) ++ return 0; /* opposites */ ++ if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) && ++ (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) || ++ ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) || ++ ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT))) ++ return 0; /* opposites */ ++ if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) && ++ ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) ++ return 0; /* cannot match in the same time loose and strict source routing */ ++ if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || ++ ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) && ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR)) ++ return 0; /* opposites */ ++ if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) && ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR)) ++ return 0; /* opposites */ ++ if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) && ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)) ++ return 0; /* opposites */ ++ if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) && ++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)) ++ return 0; /* opposites */ ++ ++ /* everything looks ok. */ ++ return 1; ++} ++ ++static struct xt_match ipv4options_match = { ++ .name = "ipv4options", ++ .match = match, ++ .matchsize = sizeof(struct ipt_ipv4options_info), ++ .checkentry = checkentry, ++ .me = THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return xt_register_match(&ipv4options_match); ++} ++ ++static void __exit fini(void) ++{ ++ xt_unregister_match(&ipv4options_match); ++} ++ ++module_init(init); ++module_exit(fini); diff --git a/src/patches/suse-2.6.27.31/patches.suse/no-frame-pointer-select b/src/patches/suse-2.6.27.31/patches.suse/no-frame-pointer-select new file mode 100644 index 000000000..50ad86048 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/no-frame-pointer-select @@ -0,0 +1,37 @@ +From: Andi Kleen +Subject: Fix stack unwinder Kconfig +Patch-mainline: no +References: bnc#402518 + +Incremental patch for dwarf2 unwinder + +Fix the Kconfigs that do SELECT FRAME_POINTER to do select UNWIND_INFO +instead. + +Signed-off-by: Andi Kleen +Acked-by: Jan Beulich + +--- + lib/Kconfig.debug | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -694,13 +694,15 @@ config FAULT_INJECTION_STACKTRACE_FILTER + depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT + depends on !X86_64 + select STACKTRACE +- select FRAME_POINTER if !PPC ++ select FRAME_POINTER if !PPC && !X86 ++ select UNWIND_INFO if X86 && !FRAME_POINTER + help + Provide stacktrace filter for fault-injection capabilities + + config LATENCYTOP + bool "Latency measuring infrastructure" +- select FRAME_POINTER if !MIPS && !PPC ++ select FRAME_POINTER if !MIPS && !PPC && !X86 ++ select UNWIND_INFO if X86 && !FRAME_POINTER + select KALLSYMS + select KALLSYMS_ALL + select STACKTRACE diff --git a/src/patches/suse-2.6.27.31/patches.suse/no-partition-scan b/src/patches/suse-2.6.27.31/patches.suse/no-partition-scan new file mode 100644 index 000000000..d880f02bd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/no-partition-scan @@ -0,0 +1,106 @@ +From: Hannes Reinecke +Subject: Implement 'no_partition_scan' commandline option +Refences: FATE#303697 + +Under certain setups the partition table on the disk is not +useable directly (eg for dmraid or multipathing). So we should +be able to switch it off completely so as not to be flooded with +pointless messages. + +Signed-off-by: Hannes Reinecke + +--- + block/genhd.c | 38 ++++++++++++++++++++++++++++++++++++-- + fs/partitions/check.c | 2 ++ + include/linux/genhd.h | 1 + + 3 files changed, 39 insertions(+), 2 deletions(-) + +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -173,6 +173,18 @@ static int exact_lock(dev_t devt, void * + return 0; + } + ++static int __read_mostly no_partition_scan; ++ ++static int __init no_partition_scan_setup(char *str) ++{ ++ no_partition_scan = 1; ++ printk(KERN_INFO "genhd: omit partition scan.\n"); ++ ++ return 1; ++} ++ ++__setup("no_partition_scan", no_partition_scan_setup); ++ + /** + * add_disk - add partitioning information to kernel list + * @disk: per-device partitioning information +@@ -186,6 +198,8 @@ void add_disk(struct gendisk *disk) + int retval; + + disk->flags |= GENHD_FL_UP; ++ if (no_partition_scan) ++ disk->flags |= GENHD_FL_NO_PARTITION_SCAN; + blk_register_region(MKDEV(disk->major, disk->first_minor), + disk->minors, NULL, exact_match, exact_lock, disk); + register_disk(disk); +@@ -429,7 +443,27 @@ static ssize_t disk_range_show(struct de + { + struct gendisk *disk = dev_to_disk(dev); + +- return sprintf(buf, "%d\n", disk->minors); ++ return sprintf(buf, "%d\n", ++ (disk->flags & GENHD_FL_NO_PARTITION_SCAN ? 0 : disk->minors)); ++} ++ ++static ssize_t disk_range_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct gendisk *disk = dev_to_disk(dev); ++ int i; ++ ++ if (count > 0 && sscanf(buf, "%d", &i) > 0) { ++ if (i == 0) ++ disk->flags |= GENHD_FL_NO_PARTITION_SCAN; ++ else if (i <= disk->minors) ++ disk->flags &= ~GENHD_FL_NO_PARTITION_SCAN; ++ else ++ count = -EINVAL; ++ } ++ ++ return count; + } + + static ssize_t disk_removable_show(struct device *dev, +@@ -519,7 +553,7 @@ static ssize_t disk_fail_store(struct de + + #endif + +-static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); ++static DEVICE_ATTR(range, S_IRUGO|S_IWUSR, disk_range_show, disk_range_store); + static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); + static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); + static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); +--- a/fs/partitions/check.c ++++ b/fs/partitions/check.c +@@ -486,6 +486,8 @@ int rescan_partitions(struct gendisk *di + disk->fops->revalidate_disk(disk); + check_disk_size_change(disk, bdev); + bdev->bd_invalidated = 0; ++ if (disk->flags & GENHD_FL_NO_PARTITION_SCAN) ++ return 0; + if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) + return 0; + if (IS_ERR(state)) /* I/O error reading the partition table */ +--- a/include/linux/genhd.h ++++ b/include/linux/genhd.h +@@ -109,6 +109,7 @@ struct hd_struct { + #define GENHD_FL_UP 16 + #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 + #define GENHD_FL_FAIL 64 ++#define GENHD_FL_NO_PARTITION_SCAN 128 + + struct gendisk { + int major; /* major number of driver */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/novfs-add-the-novell-filesystem-client-kernel-module.patch b/src/patches/suse-2.6.27.31/patches.suse/novfs-add-the-novell-filesystem-client-kernel-module.patch new file mode 100644 index 000000000..54bd1a449 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/novfs-add-the-novell-filesystem-client-kernel-module.patch @@ -0,0 +1,18498 @@ +From 9297af3ffd8a1c98f35fb7a273386576e061ff16 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Thu, 27 Mar 2008 10:40:48 -0700 +Subject: novfs: Add the Novell filesystem client kernel module +Patch-mainline: not yet, being worked on. + +This adds the Novell filesystem client kernel module. + +Things to do before it can be submitted: + - coding style cleanups + - remove typedefs + - function name lowercase + - 80 chars wide + - sparse cleanups + - __user markings + - endian markings + - remove functions that are never called and structures never used + - yeah, there are a lot of them... + - remove wrapper functions + - private kmalloc/free? + - resolve FIXME markings that have been added to the code + - wrong types passed to functions!!! + - userspace interface revisit + - uses /proc/novfs, not nice. + - might need userspace tools rework + +Cc: Lonnie Iverson +Signed-off-by: Greg Kroah-Hartman + +--- + fs/Kconfig | 9 + fs/Makefile | 1 + fs/novfs/Makefile | 19 + fs/novfs/commands.h | 1087 ++++++++++ + fs/novfs/daemon.c | 2400 ++++++++++++++++++++++ + fs/novfs/file.c | 1964 ++++++++++++++++++ + fs/novfs/inode.c | 5563 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/novfs/nwcapi.c | 2537 +++++++++++++++++++++++ + fs/novfs/nwcapi.h | 2213 ++++++++++++++++++++ + fs/novfs/nwerror.h | 658 ++++++ + fs/novfs/proc.c | 152 + + fs/novfs/profile.c | 687 ++++++ + fs/novfs/scope.c | 675 ++++++ + fs/novfs/vfs.h | 436 ++++ + 14 files changed, 18401 insertions(+) + +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -2123,6 +2123,15 @@ config 9P_FS + + If unsure, say N. + ++config NOVFS ++ tristate "Novell Netware Filesystem support (novfs) (EXPERIMENTAL)" ++ depends on INET && EXPERIMENTAL ++ help ++ If you say Y here, you will get an experimental Novell Netware ++ filesystem driver. ++ ++ If unsure, say N. ++ + endif # NETWORK_FILESYSTEMS + + if BLOCK +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -125,3 +125,4 @@ obj-$(CONFIG_HPPFS) += hppfs/ + obj-$(CONFIG_DEBUG_FS) += debugfs/ + obj-$(CONFIG_OCFS2_FS) += ocfs2/ + obj-$(CONFIG_GFS2_FS) += gfs2/ ++obj-$(CONFIG_NOVFS) += novfs/ +--- /dev/null ++++ b/fs/novfs/Makefile +@@ -0,0 +1,19 @@ ++# ++# Makefile for the Novell NetWare Client for Linux filesystem. ++# ++ ++NOVFS_VFS_MAJOR = 2 ++NOVFS_VFS_MINOR = 0 ++NOVFS_VFS_SUB = 0 ++NOVFS_VFS_RELEASE = 440 ++ ++EXTRA_CFLAGS += -DNOVFS_VFS_MAJOR=$(NOVFS_VFS_MAJOR) ++EXTRA_CFLAGS += -DNOVFS_VFS_MINOR=$(NOVFS_VFS_MINOR) ++EXTRA_CFLAGS += -DNOVFS_VFS_SUB=$(NOVFS_VFS_SUB) ++EXTRA_CFLAGS += -DNOVFS_VFS_PATCH=$(NOVFS_VFS_PATCH) ++EXTRA_CFLAGS += -DNOVFS_VFS_RELEASE=$(NOVFS_VFS_RELEASE) ++ ++obj-$(CONFIG_NOVFS) += novfs.o ++ ++novfs-objs := inode.o proc.o profile.o daemon.o file.o scope.o nwcapi.o ++ +--- /dev/null ++++ b/fs/novfs/commands.h +@@ -0,0 +1,1087 @@ ++/* ++ * NetWare Redirector for Linux ++ * Author: James Turner/Richard Williams ++ * ++ * This file contains all defined commands. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#ifndef __NOVFS_COMMANDS_H ++#define __NOVFS_COMMANDS_H ++ ++#define VFS_COMMAND_GET_CONNECTED_SERVER_LIST 0 ++#define VFS_COMMAND_GET_SERVER_VOLUME_LIST 1 ++#define VFS_COMMAND_VERIFY_FILE 2 ++#define VFS_COMMAND_OPEN_CONNECTION_BY_ADDR 3 ++#define VFS_COMMAND_LOGIN_IDENTITY 4 ++#define VFS_COMMAND_ENUMERATE_DIRECTORY 5 ++#define VFS_COMMAND_OPEN_FILE 6 ++#define VFS_COMMAND_CREATE_FILE 7 ++#define VFS_COMMAND_CLOSE_FILE 8 ++#define VFS_COMMAND_READ_FILE 9 ++#define VFS_COMMAND_WRITE_FILE 10 ++#define VFS_COMMAND_DELETE_FILE 11 ++#define VFS_COMMAND_CREATE_DIRECOTRY 12 ++#define VFS_COMMAND_START_ENUMERATE 13 ++#define VFS_COMMAND_END_ENUMERATE 14 ++#define VFS_COMMAND_LOGIN_USER 15 ++#define VFS_COMMAND_LOGOUT_USER 16 ++#define VFS_COMMAND_CREATE_CONTEXT 17 ++#define VFS_COMMAND_DESTROY_CONTEXT 18 ++#define VFS_COMMAND_SET_FILE_INFO 19 ++#define VFS_COMMAND_TRUNCATE_FILE 20 ++#define VFS_COMMAND_OPEN_CONNECTION_BY_NAME 21 ++#define VFS_COMMAND_XPLAT_CALL 22 ++#define VFS_COMMAND_RENAME_FILE 23 ++#define VFS_COMMAND_ENUMERATE_DIRECTORY_EX 24 ++#define VFS_COMMAND_GETPWUD 25 ++#define VFS_COMMAND_ENUM_XCONN 26 ++#define VFS_COMMAND_READ_STREAM 27 ++#define VFS_COMMAND_WRITE_STREAM 28 ++#define VFS_COMMAND_CLOSE_STREAM 29 ++#define VFS_COMMAND_GET_VERSION 30 ++#define VFS_COMMAND_SET_MOUNT_PATH 31 ++#define VFS_COMMAND_GET_USER_SPACE 32 ++#define VFS_COMMAND_DBG 33 ++#define VFS_COMMAND_GET_CACHE_FLAG 34 ++#define VFS_COMMAND_GET_EXTENDED_ATTRIBUTE 35 ++#define VFS_COMMAND_LIST_EXTENDED_ATTRIBUTES 36 ++#define VFS_COMMAND_SET_EXTENDED_ATTRIBUTE 37 ++#define VFS_COMMAND_SET_FILE_LOCK 38 ++ ++#define NWD_ACCESS_QUERY 0x00000001 ++#define NWD_ACCESS_READ 0x00000002 ++#define NWD_ACCESS_WRITE 0x00000004 ++#define NWD_ACCESS_EXECUTE 0x00000008 ++#define NWD_ACCESS_VALID 0x0000000F ++ ++/* ++ Share Mode ++ ++ A value of zero in a shared mode field specifies the caller ++ desires exclusive access to the object. ++*/ ++ ++#define NWD_SHARE_READ 0x00000001 ++#define NWD_SHARE_WRITE 0x00000002 ++#define NWD_SHARE_DELETE 0x00000004 ++#define NWD_SHARE_VALID 0x00000007 ++ ++/* ++ Creates a new file. The create API will fail if the specified ++ file already exists. ++*/ ++#define NWD_DISP_CREATE_NEW 0x00000001 ++ ++/* ++ Creates a new file. If the specified file already exists, ++ the create API will overwrite the old file and clear the ++ existing attributes. ++*/ ++#define NWD_DISP_CREATE_ALWAYS 0x00000002 ++ ++/* ++ Opens the file. The API will fail if the file does not exist. ++*/ ++#define NWD_DISP_OPEN_EXISTING 0x00000003 ++ ++/* ++ Opens the file. If the file does not exist, the API will ++ create the file. ++*/ ++#define NWD_DISP_OPEN_ALWAYS 0x00000004 ++ ++/* ++ Opens the file. When the file is opened the API will truncate ++ the stream to zero bytes. The API will fail if the file ++ does not exist. ++*/ ++#define NWD_DISP_TRUNCATE_EXISTING 0x00000005 ++#define NWD_DISP_MAXIMUM 0x00000005 ++ ++/* ++ Open/Create returned information values ++ ++ The bottom two bytes of NWD_ACTION are returned ++ as a value. All values are mutually exclusive. ++*/ ++ ++#define NWD_ACTION_OPENED 0x00000001 ++#define NWD_ACTION_CREATED 0x00000002 ++ ++#define MAX_IO_SIZE (1024 * 32) ++ ++#define MAX_XATTR_NAME_LEN 255 ++#define MAX_PATH_LENGTH 255 ++#define ENOATTR ENODATA ++/*===[ Type definitions ]=================================================*/ ++ ++/*===[ Function prototypes ]==============================================*/ ++ ++#pragma pack(push, 1) ++ ++#ifndef NWHANDLE ++typedef void *NWHANDLE; ++#endif ++ ++/*typedef struct _ncl_string ++{ ++ unsigned int type; ++ unsigned char *buffer; ++ unsigned int len; ++ ++} NclString, *PNclString; ++*/ ++typedef struct _ncl_string { ++ unsigned int type; ++ unsigned char *buffer; ++ u32 len; ++ ++} NclString, *PNclString; ++ ++typedef struct _nwd_string { ++ unsigned int type; ++ unsigned int len; ++ unsigned int boffset; ++ ++} NwdString, *PNwdString; ++ ++typedef struct _COMMAND_REQUEST_HEADER { ++ unsigned int CommandType; ++ unsigned long SequenceNumber; ++ struct schandle SessionId; ++} COMMAND_REQUEST_HEADER, *PCOMMAND_REQUEST_HEADER; ++ ++typedef struct _COMMAND_REPLY_HEADER { ++ unsigned long Sequence_Number; ++ unsigned int ErrorCode; ++ ++} COMMAND_REPLY_HEADER, *PCOMMAND_REPLY_HEADER; ++ ++typedef struct _CLOSE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ NWHANDLE FileHandle; ++} CLOSE_REQUEST, *PCLOSE_REQUEST; ++ ++typedef struct _CLOSE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++} CLOSE_REPLY, *PCLOSE_REPLY; ++ ++typedef struct _DELETE_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int isDirectory; ++ unsigned int pathlength; ++ unsigned char path[1]; ++} DELETE_FILE_REQUEST, *PDELETE_FILE_REQUEST; ++ ++typedef struct _DELETE_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++} DELETE_FILE_REPLY, *PDELETE_FILE_REPLY; ++ ++typedef struct _FLUSH_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ NWHANDLE FileHandle; ++} FLUSH_REQUEST, *PFLUSH_REQUEST; ++ ++typedef struct _FLUSH_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++} FLUSH_REPLY, *PFLUSH_REPLY; ++ ++typedef struct _GET_FILEINFO_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ NWHANDLE FileHandle; ++} GET_FILEINFO_REQUEST, *PGET_FILEINFO_REQUEST; ++ ++typedef struct _GET_FILEINFO_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++} GET_FILEINFO_REPLY, *PGET_FILEINFO_REPLY; ++ ++typedef struct _GET_CONNECTED_SERVER_LIST_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++} GET_CONNECTED_SERVER_LIST_REQUEST, *PGET_CONNECTED_SERVER_LIST_REQUEST; ++ ++typedef struct _GET_CONNECTED_SERVER_LIST_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char List[1]; ++} GET_CONNECTED_SERVER_LIST_REPLY, *PGET_CONNECTED_SERVER_LIST_REPLY; ++ ++typedef struct _GET_CONNECTED_SERVER_LIST_REQUEST_EX { ++ COMMAND_REQUEST_HEADER Command; ++} GET_CONNECTED_SERVER_LIST_REQUEST_EX, *PGET_CONNECTED_SERVER_LIST_REQUEST_EX; ++ ++typedef struct _GET_CONNECTED_SERVER_LIST_REPLY_EX { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned int bufferLen; ++ unsigned char List[1]; ++ ++} GET_CONNECTED_SERVER_LIST_REPLY_EX, *PGET_CONNECTED_SERVER_LIST_REPLY_EX; ++ ++typedef struct _GET_SERVER_VOLUME_LIST_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int Length; ++ unsigned char Name[1]; ++} GET_SERVER_VOLUME_LIST_REQUEST, *PGET_SERVER_VOLUME_LIST_REQUEST; ++ ++typedef struct _GET_SERVER_VOLUME_LIST_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char List[1]; ++} GET_SERVER_VOLUME_LIST_REPLY, *PGET_SERVER_VOLUME_LIST_REPLY; ++ ++typedef struct _OPEN_CONNECTION_BY_ADDR_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int address; ++ ++} OPEN_CONNECTION_BY_ADDR_REQUEST, *POPEN_CONNECTION_BY_ADDR_REQUEST; ++ ++typedef struct _OPEN_CONNECTION_BY_ADDR_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char serverName[64]; ++ unsigned char treeName[64]; ++ NWHANDLE connHandle; ++ ++} OPEN_CONNECTION_BY_ADDR_REPLY, *POPEN_CONNECTION_BY_ADDR_REPLY; ++ ++typedef struct _OPEN_CONNECTION_BY_NAME_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int NameLen; ++ unsigned char Name[1]; ++ ++} OPEN_CONNECTION_BY_NAME_REQUEST, *POPEN_CONNECTION_BY_NAME_REQUEST; ++ ++typedef struct _OPEN_CONNECTION_BY_NAME_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char treeName[64]; ++ NWHANDLE connHandle; ++ ++} OPEN_CONNECTION_BY_NAME_REPLY, *POPEN_CONNECTION_BY_NAME_REPLY; ++ ++/* ++typedef struct _LOGIN_IDENTITY_REQUEST ++{ ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int treeFlags; ++ unsigned char treeName[64]; ++ unsigned int serverFlags; ++ unsigned char serverName[64]; ++ unsigned int userFlags; ++ unsigned char userName[512]; ++ unsigned int passwordFlags; ++ unsigned char password[128]; ++ ++} LOGIN_IDENTITY_REQUEST, *PLOGIN_IDENTITY_REQUEST; ++ ++typedef struct _LOGIN_IDENTITY_REPLY ++{ ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char serverName[64]; ++ unsigned char treeName[64]; ++ NWHANDLE connHandle; ++ ++} LOGIN_IDENTITY_REPLY, *PLOGIN_IDENTITY_REPLY; ++*/ ++ ++typedef struct _VERIFY_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int pathLen; ++ unsigned char path[1]; ++ ++} VERIFY_FILE_REQUEST, *PVERIFY_FILE_REQUEST; ++ ++typedef struct _VERIFY_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned int lastAccessTime; ++ unsigned int modifyTime; ++ unsigned int createTime; ++ unsigned long long fileSize; ++ unsigned int fileMode; ++ ++} VERIFY_FILE_REPLY, *PVERIFY_FILE_REPLY; ++ ++typedef struct _BEGIN_ENUMERATE_DIRECTORY_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int pathLen; ++ unsigned char path[1]; ++ ++} BEGIN_ENUMERATE_DIRECTORY_REQUEST, *PBEGIN_ENUMERATE_DIRECTORY_REQUEST; ++ ++typedef struct _BEGIN_ENUMERATE_DIRECTORY_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ HANDLE enumerateHandle; ++ ++} BEGIN_ENUMERATE_DIRECTORY_REPLY, *PBEGIN_ENUMERATE_DIRECTORY_REPLY; ++ ++typedef struct _END_ENUMERATE_DIRECTORY_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE enumerateHandle; ++ ++} END_ENUMERATE_DIRECTORY_REQUEST, *PEND_ENUMERATE_DIRECTORY_REQUEST; ++ ++typedef struct _END_ENUMERATE_DIRECTORY_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} END_ENUMERATE_DIRECTORY_REPLY, *PEND_ENUMERATE_DIRECTORY_REPLY; ++ ++typedef struct _ENUMERATE_DIRECTORY_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE enumerateHandle; ++ unsigned int pathLen; ++ unsigned char path[1]; ++ ++} ENUMERATE_DIRECTORY_REQUEST, *PENUMERATE_DIRECTORY_REQUEST; ++ ++typedef struct _ENUMERATE_DIRECTORY_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ HANDLE enumerateHandle; ++ unsigned int lastAccessTime; ++ unsigned int modifyTime; ++ unsigned int createTime; ++ unsigned long long size; ++ unsigned int mode; ++ unsigned int nameLen; ++ unsigned char name[1]; ++ ++} ENUMERATE_DIRECTORY_REPLY, *PENUMERATE_DIRECTORY_REPLY; ++ ++typedef struct _ENUMERATE_DIRECTORY_EX_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE enumerateHandle; ++ unsigned int pathLen; ++ unsigned char path[1]; ++ ++} ENUMERATE_DIRECTORY_EX_REQUEST, *PENUMERATE_DIRECTORY_EX_REQUEST; ++ ++typedef struct _ENUMERATE_DIRECTORY_EX_DATA { ++ unsigned int length; ++ unsigned int lastAccessTime; ++ unsigned int modifyTime; ++ unsigned int createTime; ++ unsigned long long size; ++ unsigned int mode; ++ unsigned int nameLen; ++ unsigned char name[1]; ++ ++} ENUMERATE_DIRECTORY_EX_DATA, *PENUMERATE_DIRECTORY_EX_DATA; ++ ++typedef struct _ENUMERATE_DIRECTORY_EX_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ HANDLE enumerateHandle; ++ unsigned int enumCount; ++ ++} ENUMERATE_DIRECTORY_EX_REPLY, *PENUMERATE_DIRECTORY_EX_REPLY; ++ ++typedef struct _OPEN_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int access; /* File Access */ ++ unsigned int mode; /* Sharing Mode */ ++ unsigned int disp; /* Create Disposition */ ++ unsigned int pathLen; ++ unsigned char path[1]; ++ ++} OPEN_FILE_REQUEST, *POPEN_FILE_REQUEST; ++ ++typedef struct _OPEN_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ HANDLE handle; ++ unsigned int lastAccessTime; ++ unsigned int modifyTime; ++ unsigned int createTime; ++ unsigned int attributes; ++ loff_t size; ++ ++} OPEN_FILE_REPLY, *POPEN_FILE_REPLY; ++ ++typedef struct _CREATE_FILE_REQUEST { ++ ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int pathlength; ++ unsigned char path[1]; ++ ++} CREATE_FILE_REQUEST, *PCREATE_FILE_REQUEST; ++ ++typedef struct _CREATE_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} CREATE_FILE_REPLY, *PCREATE_FILE_REPLY; ++ ++typedef struct _CLOSE_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE handle; ++ ++} CLOSE_FILE_REQUEST, *PCLOSE_FILE_REQUEST; ++ ++typedef struct _CLOSE_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} CLOSE_FILE_REPLY, *PCLOSE_FILE_REPLY; ++ ++typedef struct _READ_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE handle; ++ loff_t offset; ++ size_t len; ++ ++} READ_FILE_REQUEST, *PREAD_FILE_REQUEST; ++ ++typedef struct _READ_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned long long bytesRead; ++ unsigned char data[1]; ++ ++} READ_FILE_REPLY, *PREAD_FILE_REPLY; ++ ++typedef struct _WRITE_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE handle; ++ loff_t offset; ++ size_t len; ++ unsigned char data[1]; ++ ++} WRITE_FILE_REQUEST, *PWRITE_FILE_REQUEST; ++ ++typedef struct _WRITE_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned long long bytesWritten; ++} WRITE_FILE_REPLY, *PWRITE_FILE_REPLY; ++ ++typedef struct _READ_STREAM_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE connection; ++ unsigned char handle[6]; ++ loff_t offset; ++ size_t len; ++} READ_STREAM_REQUEST, *PREAD_STREAM_REQUEST; ++ ++typedef struct _READ_STREAM_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ size_t bytesRead; ++ unsigned char data[1]; ++} READ_STREAM_REPLY, *PREAD_STREAM_REPLY; ++ ++typedef struct _WRITE_STREAM_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE connection; ++ unsigned char handle[6]; ++ loff_t offset; ++ size_t len; ++ unsigned char data[1]; ++} WRITE_STREAM_REQUEST, *PWRITE_STREAM_REQUEST; ++ ++typedef struct _WRITE_STREAM_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ size_t bytesWritten; ++} WRITE_STREAM_REPLY, *PWRITE_STREAM_REPLY; ++ ++typedef struct _CLOSE_STREAM_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE connection; ++ unsigned char handle[6]; ++} CLOSE_STREAM_REQUEST, *PCLOSE_STREAM_REQUEST; ++ ++typedef struct _CLOSE_STREAM_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} CLOSE_STREAM_REPLY, *PCLOSE_STREAM_REPLY; ++ ++typedef struct _CREATE_DIRECTORY_REQUEST { ++ ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int pathlength; ++ unsigned char path[1]; ++ ++} CREATE_DIRECTORY_REQUEST, *PCREATE_DIRECTORY_REQUEST; ++ ++typedef struct _CREATE_DIRECTORY_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} CREATE_DIRECTORY_REPLY, *PCREATE_DIRECTORY_REPLY; ++ ++typedef struct _LOGIN_USER_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int srvNameType; ++ unsigned int serverLength; ++ unsigned int serverOffset; ++ unsigned int usrNameType; ++ unsigned int userNameLength; ++ unsigned int userNameOffset; ++ unsigned int pwdNameType; ++ unsigned int passwordLength; ++ unsigned int passwordOffset; ++ ++} LOGIN_USER_REQUEST, *PLOGIN_USER_REQUEST; ++ ++typedef struct _LOGIN_USER_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned int connectionHandle; ++ HANDLE loginIdentity; ++ ++} LOGIN_USER_REPLY, *PLOGIN_USER_REPLY; ++ ++typedef struct _LOGOUT_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int length; ++ unsigned char Name[1]; ++ ++} LOGOUT_REQUEST, *PLOGOUT_REQUEST; ++ ++typedef struct _LOGOUT_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} LOGOUT_REPLY, *PLOGOUT_REPLY; ++ ++typedef struct _CREATE_CONTEXT_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ ++} CREATE_CONTEXT_REQUEST, *PCREATE_CONTEXT_REQUEST; ++ ++typedef struct _CREATE_CONTEXT_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ struct schandle SessionId; ++} CREATE_CONTEXT_REPLY, *PCREATE_CONTEXT_REPLY; ++ ++typedef struct _DESTROY_CONTEXT_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ ++} DESTROY_CONTEXT_REQUEST, *PDESTROY_CONTEXT_REQUEST; ++ ++typedef struct _DESTROY_CONTEXT_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} DESTROY_CONTEXT_REPLY, *PDESTROY_CONTEXT_REPLY; ++ ++/* ++ * Attribute flags. These should be or-ed together to figure out what ++ * has been changed! ++ */ ++#ifndef ATTR_MODE ++#define ATTR_MODE 1 ++#define ATTR_UID 2 ++#define ATTR_GID 4 ++#define ATTR_SIZE 8 ++#define ATTR_ATIME 16 ++#define ATTR_MTIME 32 ++#define ATTR_CTIME 64 ++#define ATTR_ATIME_SET 128 ++#define ATTR_MTIME_SET 256 ++#define ATTR_FORCE 512 /* Not a change, but a change it */ ++#define ATTR_ATTR_FLAG 1024 ++#endif ++ ++typedef struct _LNX_FILE_INFO { ++ unsigned int ia_valid; ++ unsigned int ia_mode; ++ uid_t ia_uid; ++ gid_t ia_gid; ++ loff_t ia_size; ++ time_t ia_atime; ++ time_t ia_mtime; ++ time_t ia_ctime; ++ unsigned int ia_attr_flags; ++ ++} LX_FILE_INFO, *PLX_FILE_INFO; ++ ++typedef struct _SET_FILE_INFO_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ LX_FILE_INFO fileInfo; ++ unsigned int pathlength; ++ char path[1]; ++ ++} SET_FILE_INFO_REQUEST, *PSET_FILE_INFO_REQUEST; ++ ++typedef struct _SET_FILE_INFO_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} SET_FILE_INFO_REPLY, *PSET_FILE_INFO_REPLY; ++ ++typedef struct _TRUNCATE_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int pathLen; ++ char path[1]; ++ ++} TRUNCATE_FILE_REQUEST, *PTRUNCATE_FILE_REQUEST; ++ ++typedef struct _TRUNCATE_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} TRUNCATE_FILE_REPLY, *PTRUNCATE_FILE_REPLY; ++ ++typedef struct _GETPWUID_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int uid; ++} GETPWUID_REQUEST, *PGETPWUID_REQUEST; ++ ++typedef struct _GETPWUID_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char UserName[1]; ++} GETPWUID_REPLY, *PGETPWUID_REPLY; ++ ++typedef struct _GET_VERSION_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++} GET_VERSION_REQUEST, *PGET_VERSION_REQUEST; ++ ++typedef struct _GET_VERSION_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char Version[1]; ++} GET_VERSION_REPLY, *PGET_VERSION_REPLY; ++ ++typedef struct _SET_MOUNT_PATH { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int PathLength; ++ unsigned char Path[1]; ++} SET_MOUNT_PATH_REQUEST, *PSET_MOUNT_PATH_REQUEST; ++ ++typedef struct _SET_MOUNT_PATH_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++} SET_MOUNT_PATH, *PSET_MOUNT_PATH_REPLY; ++ ++typedef struct _GET_USER_SPACE { ++ COMMAND_REQUEST_HEADER Command; ++} GET_USER_SPACE_REQUEST, *PGET_USER_SPACE_REQUEST; ++ ++typedef struct _GET_USER_SPACE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ uint64_t TotalSpace; ++ uint64_t FreeSpace; ++ uint64_t TotalEnties; ++ uint64_t FreeEnties; ++} GET_USER_SPACE_REPLY, *PGET_USER_SPACE_REPLY; ++ ++typedef struct _XPLAT_CALL_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int NwcCommand; ++ unsigned long dataLen; ++ unsigned char data[1]; ++ ++} XPLAT_CALL_REQUEST, *PXPLAT_CALL_REQUEST; ++ ++typedef struct _XPLAT_CALL_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned long dataLen; ++ unsigned char data[1]; ++ ++} XPLAT_CALL_REPLY, *PXPLAT_CALL_REPLY; ++ ++/* XPlat NWC structures used by the daemon */ ++ ++typedef struct _NWD_OPEN_CONN_BY_NAME { ++ HANDLE ConnHandle; ++ unsigned int nameLen; ++ unsigned int oName; /* Ofset to the Name */ ++ unsigned int serviceLen; ++ unsigned int oServiceType; /* Offset to service Type; */ ++ unsigned int uConnFlags; ++ unsigned int uTranType; ++ HANDLE newConnHandle; ++ ++} NwdCOpenConnByName, *PNwdCOpenConnByName; ++ ++typedef struct _NWD_TRAN_ADDR { ++ unsigned int uTransportType; ++ unsigned int uAddressLength; ++ unsigned int oAddress; ++ ++} NwdCTranAddr, *PNwdCTranAddr; ++ ++typedef struct _NWD_OPEN_CONN_BY_ADDR { ++ HANDLE ConnHandle; ++ unsigned int oServiceType; ++ unsigned int uConnFlags; ++ NwdCTranAddr TranAddr; ++ ++} NwdCOpenConnByAddr, *PNwdCOpenConnByAddr; ++ ++typedef struct _NWD_CLOSE_CONN { ++ HANDLE ConnHandle; ++ ++} NwdCCloseConn, *PNwdCCloseConn; ++ ++typedef struct _NWD_NCP_REQ { ++ HANDLE ConnHandle; ++ unsigned int replyLen; ++ unsigned int requestLen; ++ unsigned int function; ++/* unsigned int subFunction; */ ++/* unsigned int verb; */ ++ unsigned int flags; ++ unsigned char data[1]; ++ ++} NwdCNCPReq, *PNwdCNCPReq; ++ ++typedef struct _NWD_NCP_REP { ++ unsigned int replyLen; ++ unsigned char data[1]; ++ ++} NwdCNCPRep, *PNwdCNCPRep; ++ ++typedef struct _NWC_AUTH_WID { ++ HANDLE ConnHandle; ++ u32 AuthenticationId; ++ ++} NwdCAuthenticateWithId, *PNwdCAuthenticateWithId; ++ ++typedef struct _NWC_AUTHENTICATE { ++ HANDLE ConnHandle; ++ unsigned int uAuthenticationType; ++ unsigned int userNameOffset; ++ unsigned int passwordOffset; ++ unsigned int MaxInfoLength; ++ unsigned int InfoLength; ++ unsigned int authenInfoOffset; ++ ++} NwdCAuthenticate, *PNwdCAuthenticate; ++ ++typedef struct _NWC_UNAUTHENTICATE { ++ HANDLE ConnHandle; ++ unsigned int AuthenticationId; ++ ++} NwdCUnauthenticate, *PNwdCUnauthenticate; ++ ++typedef struct _NWC_LISC_ID { ++ HANDLE ConnHandle; ++ ++} NwdCLicenseConn, *PNwdCLicenseConn; ++ ++typedef struct _NWC_UNLIC_CONN { ++ HANDLE ConnHandle; ++ ++} NwdCUnlicenseConn, *PNwdCUnlicenseConn; ++ ++typedef struct _NWC_GET_IDENT_INFO { ++ u32 AuthenticationId; ++ unsigned int AuthType; ++ unsigned int NameType; ++ unsigned short int ObjectType; ++ unsigned int IdentityFlags; ++ unsigned int domainLen; ++ unsigned int pDomainNameOffset; ++ unsigned int objectLen; ++ unsigned int pObjectNameOffset; ++ ++} NwdCGetIdentityInfo, *PNwdCGetIdentityInfo; ++ ++typedef struct _NWC_LO_ID { ++ u32 AuthenticationId; ++ ++} NwdCLogoutIdentity, *PNwdCLogoutIdentity; ++ ++typedef struct _RENAME_FILE_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ int directoryFlag; ++ unsigned int newnameLen; ++ unsigned char newname[256]; ++ unsigned int oldnameLen; ++ unsigned char oldname[256]; ++} RENAME_FILE_REQUEST, *PRENAME_FILE_REQUEST; ++ ++typedef struct _RENAME_FILE_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} RENAME_FILE_REPLY, *PRENAME_FILE_REPLY; ++ ++typedef struct __NwdServerVersion { ++ unsigned int uMajorVersion; ++ unsigned short int uMinorVersion; ++ unsigned short int uRevision; ++ ++} NwdServerVersion, *PNwdServerVersion; ++ ++#define MAX_ADDRESS_LENGTH 32 ++ ++typedef struct tagNwdTranAddrEx { ++ unsigned int uTransportType; ++ unsigned int uAddressLength; ++ unsigned char Buffer[MAX_ADDRESS_LENGTH]; ++ ++} NwdTranAddr, *PNwdTranAddr; ++ ++typedef struct __NWD_CONN_INFO { ++ unsigned int uInfoVersion; ++ unsigned int uAuthenticationState; ++ unsigned int uBroadcastState; ++ u32 uConnectionReference; ++ unsigned int pTreeNameOffset; ++/* unsigned int pWorkGroupIdOffset; Not used */ ++ unsigned int uSecurityState; ++ unsigned int uConnectionNumber; ++ unsigned int uUserId; ++ unsigned int pServerNameOffset; ++ unsigned int uNdsState; ++ unsigned int uMaxPacketSize; ++ unsigned int uLicenseState; ++ unsigned int uPublicState; ++ unsigned int bcastState; ++ unsigned int pServiceTypeOffset; ++ unsigned int uDistance; ++ u32 uAuthId; ++ unsigned int uDisconnected; ++ NwdServerVersion ServerVersion; ++ NwdTranAddr TranAddress; ++ ++} NwdConnInfo, *PNwdConnInfo; ++ ++typedef struct _nwd_conn_info { ++ HANDLE ConnHandle; ++ unsigned int uInfoLevel; ++ unsigned int uInfoLength; ++ ++} NwdCGetConnInfo, *PNwdCGetConnInfo; ++ ++typedef struct nwd_open_conn_by_Ref { ++ HANDLE uConnReference; ++ unsigned int uConnFlags; ++ HANDLE ConnHandle; ++ ++} NwdCOpenConnByRef, *PNwdCOpenConnByRef; ++ ++typedef struct nwd_get_reqversion { ++ unsigned int uMajorVersion; ++ unsigned int uMinorVersion; ++ unsigned int uRevision; ++ ++} NwdCGetRequesterVersion, *PNwdCGetRequesterVersion; ++ ++typedef struct _nwc_scan_conn_info { ++ unsigned int uScanIndex; ++ unsigned int uScanInfoLevel; ++ unsigned int uScanInfoLen; ++ unsigned int uScanConnInfoOffset; ++ unsigned int uScanFlags; ++ unsigned int uReturnInfoLevel; ++ unsigned int uReturnInfoLength; ++ unsigned int uConnectionReference; ++ unsigned int uReturnConnInfoOffset; ++ ++} NwdCScanConnInfo, *PNwdCScanConnInfo; ++ ++typedef struct nwc_get_pref_ds_tree { ++ unsigned int uTreeLength; ++ unsigned int DsTreeNameOffset; ++ ++} NwdCGetPreferredDsTree, *PNwdCGetPreferredDsTree; ++ ++typedef struct nwc_set_pref_ds_tree { ++ unsigned int uTreeLength; ++ unsigned int DsTreeNameOffset; ++ ++} NwdCSetPreferredDsTree, *PNwdCSetPreferredDsTree; ++ ++typedef struct nwc_set_def_name_ctx { ++ unsigned int uTreeLength; ++ unsigned int TreeOffset; ++ unsigned int uNameLength; ++ unsigned int NameContextOffset; ++ ++} NwdCSetDefaultNameContext, *PNwdCSetDefaultNameContext; ++ ++typedef struct nwc_get_def_name_ctx { ++ unsigned int uTreeLength; ++ unsigned int TreeOffset; ++ unsigned int uNameLength; ++ unsigned int NameContextOffset; ++ ++} NwdCGetDefaultNameContext, *PNwdCGetDefaultNameContext; ++ ++typedef struct _nwc_get_treemonitored_connref { ++ NwdString TreeName; ++ HANDLE uConnReference; ++ ++} NwdCGetTreeMonitoredConnRef, *PNwdCGetTreeMonitoredConnRef; ++ ++typedef struct _nwc_enumerate_identities { ++ unsigned int Iterator; ++ unsigned int domainNameLen; ++ unsigned int domainNameOffset; ++ unsigned int AuthType; ++ unsigned int objectNameLen; ++ unsigned int objectNameOffset; ++ unsigned int NameType; ++ unsigned short int ObjectType; ++ unsigned int IdentityFlags; ++ u32 AuthenticationId; ++ ++} NwdCDEnumerateIdentities, *PNwdCEnumerateIdentities; ++ ++typedef struct nwd_change_key { ++ unsigned int domainNameOffset; ++ unsigned int domainNameLen; ++ unsigned int AuthType; ++ unsigned int objectNameOffset; ++ unsigned int objectNameLen; ++ unsigned int NameType; ++ unsigned short int ObjectType; ++ unsigned int verifyPasswordOffset; ++ unsigned int verifyPasswordLen; ++ unsigned int newPasswordOffset; ++ unsigned int newPasswordLen; ++ ++} NwdCChangeKey, *PNwdCChangeKey; ++ ++typedef struct _nwd_get_primary_conn { ++ HANDLE uConnReference; ++ ++} NwdCGetPrimaryConnection, *PNwdCGetPrimaryConnection; ++ ++typedef struct _nwd_set_primary_conn { ++ HANDLE ConnHandle; ++ ++} NwdCSetPrimaryConnection, *PNwdCSetPrimaryConnection; ++ ++typedef struct _nwd_map_drive_ex { ++ u32 ConnHandle; ++ u32 localUid; ++ u32 linkOffsetLength; ++ u32 linkOffset; ++ u32 dirPathOffsetLength; ++ u32 dirPathOffset; ++ ++} NwdCMapDriveEx, *PNwdCMapDriveEx; ++ ++typedef struct _nwd_unmap_drive_ex { ++ unsigned int linkLen; ++ char linkPath[1]; ++ ++} NwdCUnmapDriveEx, *PNwdCUnmapDriveEx; ++ ++typedef struct _nwd_enum_links { ++ unsigned int totalLen; ++ unsigned int linkCount; ++ ++} NwdCEnumLinks, *PNwdCEnumLinks; ++ ++typedef struct nwd_getbroadcastnotification { ++ unsigned int uMessageFlags; ++ HANDLE uConnReference; ++ unsigned int messageLen; ++ char message[1]; ++ ++} NwdCGetBroadcastNotification, *PNwdCGetBroadcastNotification; ++ ++typedef struct _enum_entry { ++ unsigned int entryLen; ++ u32 connHdl; ++ char data[0]; ++} NwdCEnumEntry, *PNwdCEnumEntry; ++ ++typedef struct _nwd_set_conn_info { ++ HANDLE ConnHandle; ++ unsigned int uInfoLevel; ++ unsigned int uInfoLength; ++ unsigned int offsetConnInfo; ++ ++} NwdCSetConnInfo, *PNwdCSetConnInfo; ++ ++typedef struct _len_string { ++ u32 stLen; ++ char string[1]; ++ ++} LString, *PLString; ++ ++typedef struct _DEBUG_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ int cmdlen; ++ char dbgcmd[1]; ++ ++} DEBUG_REQUEST, *PDEBUG_REQUEST; ++ ++typedef struct _DEBUG_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} DEBUG_REPLY, *PDEBUG_REPLY; ++ ++typedef struct _Nwd_Set_Key { ++ HANDLE ConnHandle; ++ unsigned int AuthenticationId; ++ unsigned int objectNameLen; ++ unsigned int objectNameOffset; ++ unsigned short int ObjectType; ++ unsigned int newPasswordLen; ++ unsigned int newPasswordOffset; ++ ++} NwdCSetKey, *PNwdCSetKey; ++ ++typedef struct _Nwd_Verify_Key { ++ unsigned int AuthType; ++ unsigned int NameType; ++ unsigned short int ObjectType; ++ unsigned int domainNameLen; ++ unsigned int domainNameOffset; ++ unsigned int objectNameLen; ++ unsigned int objectNameOffset; ++ unsigned int verifyPasswordLen; ++ unsigned int verifyPasswordOffset; ++ ++} NwdCVerifyKey, *PNwdCVerifyKey; ++ ++typedef struct _GET_CACHE_FLAG { ++ COMMAND_REQUEST_HEADER Command; ++ int pathLen; ++ unsigned char path[0]; ++ ++} GET_CACHE_FLAG_REQUEST, *PGET_CACHE_FLAG_REQUEST; ++ ++typedef struct _GET_CACHE_FLAG_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ int CacheFlag; ++ ++} GET_CACHE_FLAG_REPLY, *PGET_CACHE_FLAG_REPLY; ++ ++typedef struct _XA_LIST_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char *pData; ++ ++} XA_LIST_REPLY, *PXA_LIST_REPLY; ++ ++typedef struct _XA_GET_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int pathLen; ++ unsigned int nameLen; ++ unsigned char data[1]; //hold path, attribute name ++ ++} XA_GET_REQUEST, *PXA_GET_REQUEST; ++ ++typedef struct _XA_GET_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char *pData; ++ ++} XA_GET_REPLY, *PXA_GET_REPLY; ++ ++typedef struct _XA_SET_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ unsigned int TtlWriteDataSize; ++ unsigned int WritePosition; ++ int flags; ++ unsigned int pathLen; ++ unsigned int nameLen; ++ unsigned int valueLen; ++ unsigned char data[1]; //hold path, attribute name, value data ++ ++} XA_SET_REQUEST, *PXA_SET_REQUEST; ++ ++typedef struct _XA_SET_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ unsigned char *pData; ++ ++} XA_SET_REPLY, *PXA_SET_REPLY; ++ ++typedef struct _SET_FILE_LOCK_REQUEST { ++ COMMAND_REQUEST_HEADER Command; ++ HANDLE handle; ++ unsigned char fl_type; ++ loff_t fl_start; ++ loff_t fl_len; ++ ++} SET_FILE_LOCK_REQUEST, *PSET_FILE_LOCK_REQUEST; ++ ++typedef struct _SET_FILE_LOCK_REPLY { ++ COMMAND_REPLY_HEADER Reply; ++ ++} SET_FILE_LOCK_REPLY, *PSET_FILE_LOCK_REPLY; ++ ++#pragma pack(pop) ++ ++#endif /* __NOVFS_COMMANDS_H */ +--- /dev/null ++++ b/fs/novfs/daemon.c +@@ -0,0 +1,2400 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * This file contains all the functions necessary for sending commands to our ++ * daemon module. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vfs.h" ++#include "nwcapi.h" ++#include "commands.h" ++#include "nwerror.h" ++ ++#define QUEUE_SENDING 0 ++#define QUEUE_WAITING 1 ++#define QUEUE_TIMEOUT 2 ++#define QUEUE_ACKED 3 ++#define QUEUE_DONE 4 ++ ++#define TIMEOUT_VALUE 10 ++ ++#define DH_TYPE_UNDEFINED 0 ++#define DH_TYPE_STREAM 1 ++#define DH_TYPE_CONNECTION 2 ++ ++/*===[ Type definitions ]=================================================*/ ++typedef struct _DAEMON_QUEUE { ++ struct list_head list; /* Must be first entry */ ++ spinlock_t lock; /* Used to control access to list */ ++ struct semaphore semaphore; /* Used to signal when data is available */ ++} daemon_queue_t; ++ ++typedef struct _DAEMON_COMMAND { ++ struct list_head list; /* Must be first entry */ ++ atomic_t reference; ++ unsigned int status; ++ unsigned int flags; ++ struct semaphore semaphore; ++ unsigned long sequence; ++ struct timer_list timer; ++ void *request; ++ unsigned long reqlen; ++ void *data; ++ int datalen; ++ void *reply; ++ unsigned long replen; ++} daemon_command_t; ++ ++typedef struct _DAEMON_HANDLE_ { ++ struct list_head list; ++ rwlock_t lock; ++ session_t session; ++} daemon_handle_t; ++ ++typedef struct _DAEMON_RESOURCE_ { ++ struct list_head list; ++ int type; ++ HANDLE connection; ++ unsigned char handle[6]; ++ mode_t mode; ++ loff_t size; ++} daemon_resource_t; ++ ++typedef struct _DRIVE_MAP_ { ++ struct list_head list; /* Must be first item */ ++ session_t session; ++ unsigned long hash; ++ int namelen; ++ char name[1]; ++} drive_map_t; ++ ++/*===[ Function prototypes ]==============================================*/ ++int Daemon_Close_Control(struct inode *Inode, struct file *File); ++int Daemon_Library_close(struct inode *inode, struct file *file); ++int Daemon_Library_open(struct inode *inode, struct file *file); ++loff_t Daemon_Library_llseek(struct file *file, loff_t offset, int origin); ++int Daemon_Open_Control(struct inode *Inode, struct file *File); ++uint Daemon_Poll(struct file *file, struct poll_table_struct *poll_table); ++int Daemon_Remove_Resource(daemon_handle_t * DHandle, int Type, HANDLE CHandle, ++ unsigned long FHandle); ++ ++int Daemon_SetMountPoint(char *Path); ++void Daemon_Timer(unsigned long data); ++int Daemon_getpwuid(uid_t uid, int unamelen, char *uname); ++int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, int dlen, ++ void **reply, unsigned long * replen, int interruptible); ++void Queue_get(daemon_command_t * que); ++void Queue_put(daemon_command_t * que); ++void Uninit_Daemon_Queue(void); ++daemon_command_t *find_queue(unsigned long sequence); ++daemon_command_t *get_next_queue(int Set_Queue_Waiting); ++int NwdConvertNetwareHandle(PXPLAT pdata, daemon_handle_t * DHandle); ++int NwdConvertLocalHandle(PXPLAT pdata, daemon_handle_t * DHandle); ++int NwdGetMountPath(PXPLAT pdata); ++static int NwdSetMapDrive(PXPLAT pdata, session_t Session); ++static int NwdUnMapDrive(PXPLAT pdata, session_t Session); ++void RemoveDriveMaps(void); ++int local_unlink(const char *pathname); ++ ++/*===[ Global variables ]=================================================*/ ++static daemon_queue_t Daemon_Queue; ++ ++static DECLARE_WAIT_QUEUE_HEAD(Read_waitqueue); ++ ++static atomic_t Sequence = ATOMIC_INIT(-1); ++static atomic_t Daemon_Open_Count = ATOMIC_INIT(0); ++ ++static unsigned long Daemon_Command_Timeout = TIMEOUT_VALUE; ++ ++static DECLARE_MUTEX(DriveMapLock); ++static LIST_HEAD(DriveMapList); ++ ++int MaxIoSize = PAGE_SIZE; ++ ++void Init_Daemon_Queue(void) ++{ ++ INIT_LIST_HEAD(&Daemon_Queue.list); ++ spin_lock_init(&Daemon_Queue.lock); ++ init_MUTEX_LOCKED(&Daemon_Queue.semaphore); ++} ++ ++/*++======================================================================*/ ++void Uninit_Daemon_Queue(void) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ /* Does nothing for now but we maybe should clear the queue. */ ++} ++ ++/*++======================================================================*/ ++void Daemon_Timer(unsigned long data) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_command_t *que = (daemon_command_t *) data; ++ ++ if (QUEUE_ACKED != que->status) { ++ que->status = QUEUE_TIMEOUT; ++ } ++ up(&que->semaphore); ++} ++ ++int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, int dlen, ++ void **reply, unsigned long * replen, int interruptible) ++/* ++ * Arguments: void *request - pointer to the request that is to be sent. Needs to be kernel memory. ++ * int reqlen - length of the request. ++ *========================================================================*/ ++{ ++ daemon_command_t *que; ++ int retCode = 0; ++ uint64_t ts1, ts2; ++ ++ ts1 = get_nanosecond_time(); ++ ++ DbgPrint("Queue_Daemon_Command: 0x%p %d\n", request, reqlen); ++ ++ if (atomic_read(&Daemon_Open_Count)) { ++ ++ que = kmalloc(sizeof(*que), GFP_KERNEL); ++ DbgPrint("Queue_Daemon_Command: que=0x%p\n", que); ++ if (que) { ++ atomic_set(&que->reference, 0); ++ que->status = QUEUE_SENDING; ++ que->flags = 0; ++ ++ init_MUTEX_LOCKED(&que->semaphore); ++ ++ que->sequence = atomic_inc_return(&Sequence); ++ ++ ((PCOMMAND_REQUEST_HEADER) request)->SequenceNumber = ++ que->sequence; ++ ++ /* ++ * Setup and start que timer ++ */ ++ init_timer(&que->timer); ++ que->timer.expires = jiffies + (HZ * Daemon_Command_Timeout); ++ que->timer.data = (unsigned long) que; ++ que->timer.function = Daemon_Timer; ++ add_timer(&que->timer); ++ ++ /* ++ * Setup request ++ */ ++ que->request = request; ++ que->reqlen = reqlen; ++ que->data = data; ++ que->datalen = dlen; ++ que->reply = NULL; ++ que->replen = 0; ++ ++ /* ++ * Added entry to queue. ++ */ ++ /* ++ * Check to see if interruptible and set flags. ++ */ ++ if (interruptible) { ++ que->flags |= INTERRUPTIBLE; ++ } ++ ++ Queue_get(que); ++ ++ spin_lock(&Daemon_Queue.lock); ++ list_add_tail(&que->list, &Daemon_Queue.list); ++ spin_unlock(&Daemon_Queue.lock); ++ ++ /* ++ * Signal that there is data to be read ++ */ ++ up(&Daemon_Queue.semaphore); ++ ++ /* ++ * Give a change to the other processes. ++ */ ++ yield(); ++ ++ /* ++ * Block waiting for reply or timeout ++ */ ++ down(&que->semaphore); ++ ++ if (QUEUE_ACKED == que->status) { ++ que->status = QUEUE_WAITING; ++ mod_timer(&que->timer, ++ jiffies + ++ (HZ * 2 * Daemon_Command_Timeout)); ++ if (interruptible) { ++ retCode = ++ down_interruptible(&que->semaphore); ++ } else { ++ down(&que->semaphore); ++ } ++ } ++ ++ /* ++ * Delete timer ++ */ ++ del_timer(&que->timer); ++ ++ /* ++ * Check for timeout ++ */ ++ if ((QUEUE_TIMEOUT == que->status) ++ && (NULL == que->reply)) { ++ DbgPrint("Queue_Daemon_Command: Timeout\n"); ++ retCode = -ETIME; ++ } ++ *reply = que->reply; ++ *replen = que->replen; ++ ++ /* ++ * Remove item from queue ++ */ ++ Queue_put(que); ++ ++ } else { /* Error case with no memory */ ++ ++ retCode = -ENOMEM; ++ *reply = NULL; ++ *replen = 0; ++ } ++ } else { ++ retCode = -EIO; ++ *reply = NULL; ++ *replen = 0; ++ ++ } ++ ts2 = get_nanosecond_time(); ++ ts2 = ts2 - ts1; ++ ++ DbgPrint("Queue_Daemon_Command: %llu retCode=%d \n", ts2, retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++void Queue_get(daemon_command_t * Que) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint("Queue_get: que=0x%p %d\n", Que, atomic_read(&Que->reference)); ++ atomic_inc(&Que->reference); ++} ++ ++/*++======================================================================*/ ++void Queue_put(daemon_command_t * Que) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ ++ DbgPrint("Queue_put: que=0x%p %d\n", Que, atomic_read(&Que->reference)); ++ spin_lock(&Daemon_Queue.lock); ++ ++ if (atomic_dec_and_test(&Que->reference)) { ++ /* ++ * Remove item from queue ++ */ ++ list_del(&Que->list); ++ spin_unlock(&Daemon_Queue.lock); ++ ++ /* ++ * Free item memory ++ */ ++ kfree(Que); ++ } else { ++ spin_unlock(&Daemon_Queue.lock); ++ } ++} ++ ++/*++======================================================================*/ ++daemon_command_t *get_next_queue(int Set_Queue_Waiting) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_command_t *que; ++ ++ DbgPrint("get_next_queue: que=0x%p\n", Daemon_Queue.list.next); ++ ++ spin_lock(&Daemon_Queue.lock); ++ que = (daemon_command_t *) Daemon_Queue.list.next; ++ ++ while (que && (que != (daemon_command_t *) & Daemon_Queue.list.next) ++ && (que->status != QUEUE_SENDING)) { ++ que = (daemon_command_t *) que->list.next; ++ } ++ ++ if ((NULL == que) || (que == (daemon_command_t *) & Daemon_Queue.list) ++ || (que->status != QUEUE_SENDING)) { ++ que = NULL; ++ } else if (Set_Queue_Waiting) { ++ que->status = QUEUE_WAITING; ++ } ++ ++ if (que) { ++ atomic_inc(&que->reference); ++ } ++ ++ spin_unlock(&Daemon_Queue.lock); ++ ++ DbgPrint("get_next_queue: return=0x%p\n", que); ++ return (que); ++} ++ ++/*++======================================================================*/ ++daemon_command_t *find_queue(unsigned long sequence) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_command_t *que; ++ ++ DbgPrint("find_queue: 0x%x\n", sequence); ++ ++ spin_lock(&Daemon_Queue.lock); ++ que = (daemon_command_t *) Daemon_Queue.list.next; ++ ++ while (que && (que != (daemon_command_t *) & Daemon_Queue.list.next) ++ && (que->sequence != sequence)) { ++ que = (daemon_command_t *) que->list.next; ++ } ++ ++ if ((NULL == que) ++ || (que == (daemon_command_t *) & Daemon_Queue.list.next) ++ || (que->sequence != sequence)) { ++ que = NULL; ++ } ++ ++ if (que) { ++ atomic_inc(&que->reference); ++ } ++ ++ spin_unlock(&Daemon_Queue.lock); ++ ++ DbgPrint("find_queue: return 0x%p\n", que); ++ return (que); ++} ++ ++/*++======================================================================*/ ++int Daemon_Open_Control(struct inode *Inode, struct file *File) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint("Daemon_Open_Control: pid=%d Count=%d\n", current->pid, ++ atomic_read(&Daemon_Open_Count)); ++ atomic_inc(&Daemon_Open_Count); ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++int Daemon_Close_Control(struct inode *Inode, struct file *File) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_command_t *que; ++ ++ DbgPrint("Daemon_Close_Control: pid=%d Count=%d\n", current->pid, ++ atomic_read(&Daemon_Open_Count)); ++ ++ if (atomic_dec_and_test(&Daemon_Open_Count)) { ++ /* ++ * Signal any pending que itmes. ++ */ ++ ++ spin_lock(&Daemon_Queue.lock); ++ que = (daemon_command_t *) Daemon_Queue.list.next; ++ ++ while (que ++ && (que != (daemon_command_t *) & Daemon_Queue.list.next) ++ && (que->status != QUEUE_DONE)) { ++ que->status = QUEUE_TIMEOUT; ++ up(&que->semaphore); ++ ++ que = (daemon_command_t *) que->list.next; ++ } ++ spin_unlock(&Daemon_Queue.lock); ++ ++ RemoveDriveMaps(); ++ ++ Scope_Cleanup(); ++ } ++ ++ return (0); ++} ++ ++ssize_t Daemon_Send_Command(struct file *file, char __user *buf, size_t len, loff_t * off) ++{ ++ daemon_command_t *que; ++ size_t retValue = 0; ++ int Finished = 0; ++ struct data_list *dlist; ++ int i, dcnt, bcnt, ccnt, error; ++ char *vadr; ++ unsigned long cpylen; ++ ++ DbgPrint("Daemon_Send_Command: %u %lld\n", len, *off); ++ if (len > MaxIoSize) { ++ MaxIoSize = len; ++ } ++ ++ while (!Finished) { ++ que = get_next_queue(1); ++ DbgPrint("Daemon_Send_Command: 0x%p\n", que); ++ if (que) { ++ retValue = que->reqlen; ++ if (retValue > len) { ++ retValue = len; ++ } ++ if (retValue > 0x80) ++ mydump(0x80, que->request); ++ else ++ mydump(retValue, que->request); ++ ++ cpylen = copy_to_user(buf, que->request, retValue); ++ if (que->datalen && (retValue < len)) { ++ buf += retValue; ++ dlist = que->data; ++ dcnt = que->datalen; ++ for (i = 0; i < dcnt; i++, dlist++) { ++ if (DLREAD == dlist->rwflag) { ++ bcnt = dlist->len; ++ DbgPrint ++ ("Daemon_Send_Command%d: page=0x%p offset=0x%p len=%d\n", ++ i, dlist->page, ++ dlist->offset, dlist->len); ++ if ((bcnt + retValue) <= len) { ++ void *km_adr = NULL; ++ ++ if (dlist->page) { ++ km_adr = ++ kmap(dlist-> ++ page); ++ vadr = km_adr; ++ vadr += ++ (unsigned long) ++ dlist-> ++ offset; ++ } else { ++ vadr = ++ dlist-> ++ offset; ++ } ++ ++ ccnt = ++ copy_to_user(buf, ++ vadr, ++ bcnt); ++ ++ DbgPrint ++ ("Daemon_Send_Command: Copy %d from 0x%p to 0x%p.\n", ++ bcnt, vadr, buf); ++ if (bcnt > 0x80) ++ mydump(0x80, ++ vadr); ++ else ++ mydump(bcnt, ++ vadr); ++ ++ if (km_adr) { ++ kunmap(dlist-> ++ page); ++ } ++ ++ retValue += bcnt; ++ buf += bcnt; ++ } else { ++ break; ++ } ++ } ++ } ++ } ++ Queue_put(que); ++ break; ++ } ++ ++ if (O_NONBLOCK & file->f_flags) { ++ retValue = -EAGAIN; ++ break; ++ } else { ++ if ((error = ++ down_interruptible(&Daemon_Queue.semaphore))) { ++ DbgPrint ++ ("Daemon_Send_Command: after down_interruptible error...%d\n", ++ error); ++ retValue = -EINTR; ++ break; ++ } ++ DbgPrint ++ ("Daemon_Send_Command: after down_interruptible\n"); ++ } ++ } ++ ++ *off = *off; ++ ++ DbgPrint("Daemon_Send_Command: return 0x%x\n", retValue); ++ ++ return (retValue); ++} ++ ++ssize_t Daemon_Receive_Reply(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) ++{ ++ daemon_command_t *que; ++ size_t retValue = 0; ++ void *reply; ++ unsigned long sequence, cpylen; ++ ++ struct data_list *dlist; ++ char *vadr; ++ int i; ++ ++ DbgPrint("Daemon_Receive_Reply: buf=0x%p nbytes=%d ppos=%llx\n", buf, ++ nbytes, *ppos); ++ ++ /* ++ * Get sequence number from reply buffer ++ */ ++ ++ cpylen = copy_from_user(&sequence, buf, sizeof(sequence)); ++ ++ /* ++ * Find item based on sequence number ++ */ ++ que = find_queue(sequence); ++ ++ DbgPrint("Daemon_Receive_Reply: 0x%x 0x%p %d\n", sequence, que, nbytes); ++ if (que) { ++ do { ++ retValue = nbytes; ++ /* ++ * Ack packet from novfsd. Remove timer and ++ * return ++ */ ++ if (nbytes == sizeof(sequence)) { ++ que->status = QUEUE_ACKED; ++ break; ++ } ++ ++ if (NULL != (dlist = que->data)) { ++ int thiscopy, left = nbytes; ++ retValue = 0; ++ ++ DbgPrint ++ ("Daemon_Receive_Reply: dlist=0x%p count=%d\n", ++ dlist, que->datalen); ++ for (i = 0; ++ (i < que->datalen) && (retValue < nbytes); ++ i++, dlist++) { ++ DbgPrint("Daemon_Receive_Reply:\n" ++ " dlist[%d].page: 0x%p\n" ++ " dlist[%d].offset: 0x%p\n" ++ " dlist[%d].len: 0x%x\n" ++ " dlist[%d].rwflag: 0x%x\n", ++ i, dlist->page, i, ++ dlist->offset, i, dlist->len, ++ i, dlist->rwflag); ++ ++ if (DLWRITE == dlist->rwflag) { ++ void *km_adr = NULL; ++ ++ if (dlist->page) { ++ km_adr = ++ kmap(dlist->page); ++ vadr = km_adr; ++ vadr += ++ (unsigned long) dlist-> ++ offset; ++ } else { ++ vadr = dlist->offset; ++ } ++ ++ thiscopy = dlist->len; ++ if (thiscopy > left) { ++ thiscopy = left; ++ dlist->len = left; ++ } ++ cpylen = ++ copy_from_user(vadr, buf, ++ thiscopy); ++ ++ if (thiscopy > 0x80) ++ mydump(0x80, vadr); ++ else ++ mydump(thiscopy, vadr); ++ ++ if (km_adr) { ++ kunmap(dlist->page); ++ } ++ ++ left -= thiscopy; ++ retValue += thiscopy; ++ buf += thiscopy; ++ } ++ } ++ que->replen = retValue; ++ } else { ++ reply = kmalloc(nbytes, GFP_KERNEL); ++ DbgPrint("Daemon_Receive_Reply: reply=0x%p\n", reply); ++ if (reply) { ++ retValue = nbytes; ++ que->reply = reply; ++ que->replen = nbytes; ++ ++ retValue -= copy_from_user(reply, buf, retValue); ++ if (retValue > 0x80) ++ mydump(0x80, reply); ++ else ++ mydump(retValue, reply); ++ ++ } else { ++ retValue = -ENOMEM; ++ } ++ } ++ ++ /* ++ * Set status that packet is done. ++ */ ++ que->status = QUEUE_DONE; ++ ++ } while (0); ++ up(&que->semaphore); ++ Queue_put(que); ++ } ++ ++ DbgPrint("Daemon_Receive_Reply: return 0x%x\n", retValue); ++ ++ return (retValue); ++} ++ ++int do_login(NclString *Server, NclString *Username, NclString *Password, HANDLE *lgnId, struct schandle *Session) ++{ ++ PLOGIN_USER_REQUEST cmd; ++ PLOGIN_USER_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen, datalen; ++ unsigned char *data; ++ ++ datalen = Server->len + Username->len + Password->len; ++ cmdlen = sizeof(*cmd) + datalen; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ data = (unsigned char *) cmd + sizeof(*cmd); ++ cmd->Command.CommandType = VFS_COMMAND_LOGIN_USER; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, Session, sizeof(*Session)); ++ ++ cmd->srvNameType = Server->type; ++ cmd->serverLength = Server->len; ++ cmd->serverOffset = (unsigned long) (data - (unsigned char *) cmd); ++ memcpy(data, Server->buffer, Server->len); ++ data += Server->len; ++ ++ cmd->usrNameType = Username->type; ++ cmd->userNameLength = Username->len; ++ cmd->userNameOffset = (unsigned long) (data - (unsigned char *) cmd); ++ memcpy(data, Username->buffer, Username->len); ++ data += Username->len; ++ ++ cmd->pwdNameType = Password->type; ++ cmd->passwordLength = Password->len; ++ cmd->passwordOffset = (unsigned long) (data - (unsigned char *) cmd); ++ memcpy(data, Password->buffer, Password->len); ++ data += Password->len; ++ ++ retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ retCode = reply->Reply.ErrorCode; ++ } else { ++ retCode = 0; ++ if (lgnId) { ++ *lgnId = reply->loginIdentity; ++ } ++ } ++ kfree(reply); ++ } ++ memset(cmd, 0, cmdlen); ++ kfree(cmd); ++ return retCode; ++ ++} ++ ++int do_logout(struct qstr *Server, struct schandle *Session) ++{ ++ PLOGOUT_REQUEST cmd; ++ PLOGOUT_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen; ++ ++ cmdlen = offsetof(LOGOUT_REQUEST, Name) + Server->len; ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_LOGOUT_USER; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, Session, sizeof(*Session)); ++ cmd->length = Server->len; ++ memcpy(cmd->Name, Server->name, Server->len); ++ ++ retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int Daemon_getpwuid(uid_t uid, int unamelen, char *uname) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ GETPWUID_REQUEST cmd; ++ PGETPWUID_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ cmd.Command.CommandType = VFS_COMMAND_GETPWUD; ++ cmd.Command.SequenceNumber = 0; ++ SC_INITIALIZE(cmd.Command.SessionId); ++ cmd.uid = uid; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } else { ++ retCode = 0; ++ memset(uname, 0, unamelen); ++ replylen = replylen - offsetof(GETPWUID_REPLY, UserName); ++ if (replylen) { ++ if (replylen > unamelen) { ++ retCode = -EINVAL; ++ replylen = unamelen - 1; ++ } ++ memcpy(uname, reply->UserName, replylen); ++ } ++ } ++ kfree(reply); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int Daemon_getversion(char *Buf, int length) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ GET_VERSION_REQUEST cmd; ++ PGET_VERSION_REPLY reply; ++ unsigned long replylen = 0; ++ int retVal = 0; ++ ++ cmd.Command.CommandType = VFS_COMMAND_GET_VERSION; ++ cmd.Command.SequenceNumber = 0; ++ SC_INITIALIZE(cmd.Command.SessionId); ++ ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ retVal = -EIO; ++ } else { ++ retVal = replylen - offsetof(GET_VERSION_REPLY, Version); ++ if (retVal < length) { ++ memcpy(Buf, reply->Version, retVal); ++ Buf[retVal] = '\0'; ++ } ++ } ++ kfree(reply); ++ } ++ return (retVal); ++ ++} ++ ++static int daemon_login(struct login *Login, struct schandle *Session) ++{ ++ int retCode = -ENOMEM; ++ struct login lLogin; ++ NclString server; ++ NclString username; ++ NclString password; ++ ++ if (!copy_from_user(&lLogin, Login, sizeof(lLogin))) { ++ server.buffer = kmalloc(lLogin.Server.length, GFP_KERNEL); ++ if (server.buffer) { ++ server.len = lLogin.Server.length; ++ server.type = NWC_STRING_TYPE_ASCII; ++ if (!copy_from_user((void *)server.buffer, lLogin.Server.data, server.len)) { ++ username.buffer = kmalloc(lLogin.UserName.length, GFP_KERNEL); ++ if (username.buffer) { ++ username.len = lLogin.UserName.length; ++ username.type = NWC_STRING_TYPE_ASCII; ++ if (!copy_from_user((void *)username.buffer, lLogin.UserName.data, username.len)) { ++ password.buffer = kmalloc(lLogin.Password.length, GFP_KERNEL); ++ if (password.buffer) { ++ password.len = lLogin.Password.length; ++ password.type = NWC_STRING_TYPE_ASCII; ++ if (!copy_from_user((void *)password.buffer, lLogin.Password.data, password.len)) { ++ retCode = do_login (&server, &username, &password, NULL, Session); ++ if (!retCode) { ++ char *name; ++ name = Scope_Get_UserName(); ++ if (name) ++ Novfs_Add_to_Root(name); ++ } ++ } ++ memset(password.buffer, 0, password.len); ++ kfree(password.buffer); ++ } ++ } ++ memset(username.buffer, 0, username.len); ++ kfree(username.buffer); ++ } ++ } ++ kfree(server.buffer); ++ } ++ } ++ ++ return (retCode); ++} ++ ++static int daemon_logout(struct logout *Logout, struct schandle *Session) ++{ ++ struct logout lLogout; ++ struct qstr server; ++ int retCode = -ENOMEM; ++ ++ if (copy_from_user(&lLogout, Logout, sizeof(lLogout))) ++ return -EFAULT; ++ ++ server.name = kmalloc(lLogout.Server.length, GFP_KERNEL); ++ if (!server.name) ++ return -ENOMEM; ++ server.len = lLogout.Server.length; ++ if (copy_from_user((void *)server.name, lLogout.Server.data, server.len)) ++ goto exit; ++ ++ retCode = do_logout(&server, Session); ++exit: ++ kfree(server.name); ++ return retCode; ++} ++ ++int Daemon_CreateSessionId(struct schandle *SessionId) ++{ ++ CREATE_CONTEXT_REQUEST cmd; ++ PCREATE_CONTEXT_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ ++ DbgPrint("Daemon_CreateSessionId: %d\n", current->pid); ++ ++ cmd.Command.CommandType = VFS_COMMAND_CREATE_CONTEXT; ++ cmd.Command.SequenceNumber = 0; ++ SC_INITIALIZE(cmd.Command.SessionId); ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (!reply->Reply.ErrorCode ++ && replylen > sizeof(COMMAND_REPLY_HEADER)) { ++ *SessionId = reply->SessionId; ++ retCode = 0; ++ } else { ++ SessionId->hTypeId = 0; ++ SessionId->hId = 0; ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ DbgPrint("Daemon_CreateSessionId: SessionId=0x%llx\n", *SessionId); ++ return (retCode); ++} ++ ++int Daemon_DestroySessionId(struct schandle *SessionId) ++{ ++ DESTROY_CONTEXT_REQUEST cmd; ++ PDESTROY_CONTEXT_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ ++ DbgPrint("Daemon_DestroySessionId: 0x%p:%p\n", ++ SessionId->hTypeId, SessionId->hId); ++ ++ cmd.Command.CommandType = VFS_COMMAND_DESTROY_CONTEXT; ++ cmd.Command.SequenceNumber = 0; ++ memcpy(&cmd.Command.SessionId, SessionId, sizeof (*SessionId)); ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (!reply->Reply.ErrorCode) { ++ drive_map_t *dm; ++ struct list_head *list; ++ ++ retCode = 0; ++ ++ /* ++ * When destroying the session check to see if there are any ++ * mapped drives. If there are then remove them. ++ */ ++ down(&DriveMapLock); ++ list_for_each(list, &DriveMapList) { ++ struct schandle *temp; ++ ++ dm = list_entry(list, drive_map_t, list); ++ temp = &dm->session; ++ if (SC_EQUAL(SessionId, temp)) { ++ local_unlink(dm->name); ++ list = list->prev; ++ list_del(&dm->list); ++ kfree(dm); ++ } ++ ++ } ++ up(&DriveMapLock); ++ ++ } else { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ return (retCode); ++} ++ ++int Daemon_Get_UserSpace(struct schandle *SessionId, uint64_t * TotalSize, ++ uint64_t * Free, uint64_t * TotalEnties, ++ uint64_t * FreeEnties) ++{ ++ GET_USER_SPACE_REQUEST cmd; ++ PGET_USER_SPACE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ ++ DbgPrint("Daemon_Get_UserSpace: 0x%p:%p\n", ++ SessionId->hTypeId, SessionId->hId); ++ ++ cmd.Command.CommandType = VFS_COMMAND_GET_USER_SPACE; ++ cmd.Command.SequenceNumber = 0; ++ memcpy(&cmd.Command.SessionId, SessionId, sizeof (*SessionId)); ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (!reply->Reply.ErrorCode) { ++ ++ DbgPrint("TotalSpace: %llu\n", reply->TotalSpace); ++ DbgPrint("FreeSpace: %llu\n", reply->FreeSpace); ++ DbgPrint("TotalEnties: %llu\n", reply->TotalEnties); ++ DbgPrint("FreeEnties: %llu\n", reply->FreeEnties); ++ ++ if (TotalSize) ++ *TotalSize = reply->TotalSpace; ++ if (Free) ++ *Free = reply->FreeSpace; ++ if (TotalEnties) ++ *TotalEnties = reply->TotalEnties; ++ if (FreeEnties) ++ *FreeEnties = reply->FreeEnties; ++ retCode = 0; ++ } else { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Daemon_SetMountPoint(char *Path) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PSET_MOUNT_PATH_REQUEST cmd; ++ PSET_MOUNT_PATH_REPLY reply; ++ unsigned long replylen, cmdlen; ++ int retCode = -ENOMEM; ++ ++ DbgPrint("Daemon_SetMountPoint: %s\n", Path); ++ ++ replylen = strlen(Path); ++ cmdlen = sizeof(SET_MOUNT_PATH_REQUEST) + replylen; ++ ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_SET_MOUNT_PATH; ++ cmd->Command.SequenceNumber = 0; ++ SC_INITIALIZE(cmd->Command.SessionId); ++ cmd->PathLength = replylen; ++ ++ strcpy(cmd->Path, Path); ++ ++ replylen = 0; ++ ++ retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (!reply->Reply.ErrorCode) { ++ retCode = 0; ++ } else { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ return retCode; ++} ++ ++/*++======================================================================*/ ++int Daemon_SendDebugCmd(char *Command) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DEBUG_REQUEST cmd; ++ PDEBUG_REPLY reply; ++ DEBUG_REPLY lreply; ++ unsigned long replylen, cmdlen; ++ struct data_list dlist[2]; ++ ++ int retCode = -ENOMEM; ++ ++ DbgPrint("Daemon_SendDebugCmd: %s\n", Command); ++ ++ dlist[0].page = NULL; ++ dlist[0].offset = (char *)Command; ++ dlist[0].len = strlen(Command); ++ dlist[0].rwflag = DLREAD; ++ ++ dlist[1].page = NULL; ++ dlist[1].offset = (char *)&lreply; ++ dlist[1].len = sizeof(lreply); ++ dlist[1].rwflag = DLWRITE; ++ ++ cmdlen = offsetof(DEBUG_REQUEST, dbgcmd); ++ ++ cmd.Command.CommandType = VFS_COMMAND_DBG; ++ cmd.Command.SequenceNumber = 0; ++ SC_INITIALIZE(cmd.Command.SessionId); ++ cmd.cmdlen = strlen(Command); ++ ++ replylen = 0; ++ ++ retCode = Queue_Daemon_Command(&cmd, cmdlen, dlist, 2, (void *)&reply, &replylen, INTERRUPTIBLE); ++ if (reply) { ++ kfree(reply); ++ } ++ if (0 == retCode) { ++ retCode = lreply.Reply.ErrorCode; ++ } ++ ++ return (retCode); ++} ++ ++int Daemon_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int retCode = -ENOSYS; ++ unsigned long cpylen; ++ struct schandle session_id; ++ ++ session_id = Scope_Get_SessionId(NULL); ++ ++ switch (cmd) { ++ case IOC_LOGIN: ++ retCode = daemon_login((struct login *)arg, &session_id); ++ break; ++ ++ case IOC_LOGOUT: ++ retCode = daemon_logout((struct logout *) arg, &session_id); ++ break; ++ case IOC_DEBUGPRINT: ++ { ++ struct Ioctl_Debug { ++ int length; ++ char *data; ++ } io; ++ char *buf; ++ io.length = 0; ++ cpylen = copy_from_user(&io, (char *)arg, sizeof(io)); ++ if (io.length) { ++ buf = kmalloc(io.length + 1, GFP_KERNEL); ++ if (buf) { ++ buf[0] = 0; ++ cpylen = ++ copy_from_user(buf, io.data, ++ io.length); ++ buf[io.length] = '\0'; ++ DbgPrint("%s", buf); ++ kfree(buf); ++ retCode = 0; ++ } ++ } ++ break; ++ } ++ ++ case IOC_XPLAT: ++ { ++ XPLAT data; ++ ++ cpylen = ++ copy_from_user(&data, (void *)arg, sizeof(data)); ++ retCode = ((data.xfunction & 0x0000FFFF) | 0xCC000000); ++ ++ switch (data.xfunction) { ++ case NWC_GET_MOUNT_PATH: ++ DbgPrint ++ ("[Daemon_ioctl] Call NwdGetMountPath\n"); ++ retCode = NwdGetMountPath(&data); ++ break; ++ } ++ ++ DbgPrint("[NOVFS XPLAT] status Code = %X\n", retCode); ++ break; ++ } ++ ++ } ++ return (retCode); ++} ++ ++int Daemon_Added_Resource(daemon_handle_t *DHandle, int Type, HANDLE CHandle, unsigned char *FHandle, unsigned long Mode, unsigned long Size) ++{ ++ daemon_resource_t *resource; ++ ++ if (FHandle) ++ DbgPrint("Daemon_Added_Resource: DHandle=0x%p Type=%d CHandle=0x%p FHandle=0x%x Mode=0x%x Size=%d\n", DHandle, Type, CHandle, *(u32 *) & FHandle[2], Mode, Size); ++ else ++ DbgPrint("Daemon_Added_Resource: DHandle=0x%p Type=%d CHandle=0x%p\n", DHandle, Type, CHandle); ++ ++ resource = kmalloc(sizeof(daemon_resource_t), GFP_KERNEL); ++ if (!resource) ++ return -ENOMEM; ++ ++ resource->type = Type; ++ resource->connection = CHandle; ++ if (FHandle) ++ memcpy(resource->handle, FHandle, sizeof(resource->handle)); ++ else ++ memset(resource->handle, 0, sizeof(resource->handle)); ++ resource->mode = Mode; ++ resource->size = Size; ++ write_lock(&DHandle->lock); ++ list_add(&resource->list, &DHandle->list); ++ write_unlock(&DHandle->lock); ++ DbgPrint("Daemon_Added_Resource: Adding resource=0x%p\n", resource); ++ ++ return 0; ++} ++ ++/*++======================================================================*/ ++int Daemon_Remove_Resource(daemon_handle_t * DHandle, int Type, HANDLE CHandle, ++ unsigned long FHandle) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_resource_t *resource; ++ struct list_head *l; ++ int retVal = -ENOMEM; ++ ++ DbgPrint ++ ("Daemon_Remove_Resource: DHandle=0x%p Type=%d CHandle=0x%p FHandle=0x%x\n", ++ DHandle, Type, CHandle, FHandle); ++ ++ write_lock(&DHandle->lock); ++ ++ list_for_each(l, &DHandle->list) { ++ resource = list_entry(l, daemon_resource_t, list); ++ ++ if ((Type == resource->type) && ++ (resource->connection == CHandle)) { ++ DbgPrint ++ ("Daemon_Remove_Resource: Found resource=0x%p\n", ++ resource); ++ l = l->prev; ++ list_del(&resource->list); ++ kfree(resource); ++ break; ++ } ++ } ++ ++ write_unlock(&DHandle->lock); ++ ++ return (retVal); ++} ++ ++int Daemon_Library_open(struct inode *inode, struct file *file) ++{ ++ daemon_handle_t *dh; ++ ++ DbgPrint("Daemon_Library_open: inode=0x%p file=0x%p\n", inode, file); ++ ++ dh = kmalloc(sizeof(daemon_handle_t), GFP_KERNEL); ++ if (!dh) ++ return -ENOMEM; ++ ++ file->private_data = dh; ++ INIT_LIST_HEAD(&dh->list); ++ rwlock_init(&dh->lock); ++ dh->session = Scope_Get_SessionId(NULL); ++ ++ return 0; ++} ++ ++/*++======================================================================*/ ++int Daemon_Library_close(struct inode *inode, struct file *file) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_handle_t *dh; ++ daemon_resource_t *resource; ++ struct list_head *l; ++ ++ char commanddata[sizeof(XPLAT_CALL_REQUEST) + sizeof(NwdCCloseConn)]; ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCCloseConn nwdClose; ++ unsigned long cmdlen, replylen; ++ ++ DbgPrint("Daemon_Library_close: inode=0x%p file=0x%p\n", inode, file); ++ if (file->private_data) { ++ dh = (daemon_handle_t *) file->private_data; ++ ++ list_for_each(l, &dh->list) { ++ resource = list_entry(l, daemon_resource_t, list); ++ ++ if (DH_TYPE_STREAM == resource->type) { ++ Novfs_Close_Stream(resource->connection, ++ resource->handle, ++ dh->session); ++ } else if (DH_TYPE_CONNECTION == resource->type) { ++ cmd = (PXPLAT_CALL_REQUEST) commanddata; ++ cmdlen = ++ offsetof(XPLAT_CALL_REQUEST, ++ data) + sizeof(NwdCCloseConn); ++ cmd->Command.CommandType = ++ VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = dh->session; ++ cmd->NwcCommand = NWC_CLOSE_CONN; ++ ++ cmd->dataLen = sizeof(NwdCCloseConn); ++ nwdClose = (PNwdCCloseConn) cmd->data; ++ nwdClose->ConnHandle = ++ (HANDLE) resource->connection; ++ ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, ++ 0, (void **)&reply, ++ &replylen, 0); ++ if (reply) ++ kfree(reply); ++ } ++ l = l->prev; ++ list_del(&resource->list); ++ kfree(resource); ++ } ++ kfree(dh); ++ file->private_data = NULL; ++ } ++ ++ return (0); ++} ++ ++ssize_t Daemon_Library_read(struct file *file, char __user *buf, size_t len, loff_t *off) ++{ ++ daemon_handle_t *dh; ++ daemon_resource_t *resource; ++ ++ size_t thisread, totalread = 0; ++ loff_t offset = *off; ++ ++ DbgPrint("Daemon_Library_read: file=0x%p len=%d off=%lld\n", file, len, ++ *off); ++ ++ if (file->private_data) { ++ dh = file->private_data; ++ read_lock(&dh->lock); ++ if (&dh->list != dh->list.next) { ++ resource = ++ list_entry(dh->list.next, daemon_resource_t, list); ++ ++ if (DH_TYPE_STREAM == resource->type) { ++ while (len > 0 && (offset < resource->size)) { ++ thisread = len; ++ if (Novfs_Read_Stream ++ (resource->connection, ++ resource->handle, buf, &thisread, ++ &offset, 1, dh->session) ++ || !thisread) { ++ break; ++ } ++ len -= thisread; ++ buf += thisread; ++ offset += thisread; ++ totalread += thisread; ++ } ++ } ++ } ++ read_unlock(&dh->lock); ++ } ++ *off = offset; ++ DbgPrint("Daemon_Library_read return = 0x%x\n", totalread); ++ return (totalread); ++} ++ ++ssize_t Daemon_Library_write(struct file *file, const char __user *buf, size_t len, loff_t *off) ++{ ++ daemon_handle_t *dh; ++ daemon_resource_t *resource; ++ ++ size_t thiswrite, totalwrite = -EINVAL; ++ loff_t offset = *off; ++ int status; ++ ++ DbgPrint("Daemon_Library_write: file=0x%p len=%d off=%lld\n", file, len, ++ *off); ++ ++ if (file->private_data) { ++ dh = file->private_data; ++ write_lock(&dh->lock); ++ if (&dh->list != dh->list.next) { ++ resource = ++ list_entry(dh->list.next, daemon_resource_t, list); ++ ++ if ((DH_TYPE_STREAM == resource->type) && (len >= 0)) { ++ totalwrite = 0; ++ do { ++ thiswrite = len; ++ status = ++ Novfs_Write_Stream(resource-> ++ connection, ++ resource->handle, ++ (void *)buf, ++ &thiswrite, ++ &offset, ++ dh->session); ++ if (status || !thiswrite) { ++ /* ++ * If len is zero then the file will have just been ++ * truncated to offset. Update size. ++ */ ++ if (!status && !len) { ++ resource->size = offset; ++ } ++ totalwrite = status; ++ break; ++ } ++ len -= thiswrite; ++ buf += thiswrite; ++ offset += thiswrite; ++ totalwrite += thiswrite; ++ if (offset > resource->size) { ++ resource->size = offset; ++ } ++ } while (len > 0); ++ } ++ } ++ write_unlock(&dh->lock); ++ } ++ *off = offset; ++ DbgPrint("Daemon_Library_write return = 0x%x\n", totalwrite); ++ ++ return (totalwrite); ++} ++ ++/*++======================================================================*/ ++loff_t Daemon_Library_llseek(struct file * file, loff_t offset, int origin) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ daemon_handle_t *dh; ++ daemon_resource_t *resource; ++ ++ loff_t retVal = -EINVAL; ++ ++ DbgPrint("Daemon_Library_llseek: file=0x%p offset=%lld origin=%d\n", ++ file, offset, origin); ++ ++ if (file->private_data) { ++ dh = file->private_data; ++ read_lock(&dh->lock); ++ if (&dh->list != dh->list.next) { ++ resource = ++ list_entry(dh->list.next, daemon_resource_t, list); ++ ++ if (DH_TYPE_STREAM == resource->type) { ++ switch (origin) { ++ case 2: ++ offset += resource->size; ++ break; ++ case 1: ++ offset += file->f_pos; ++ } ++ if (offset >= 0) { ++ if (offset != file->f_pos) { ++ file->f_pos = offset; ++ file->f_version = 0; ++ } ++ retVal = offset; ++ } ++ } ++ } ++ read_unlock(&dh->lock); ++ } ++ ++ DbgPrint("Daemon_Library_llseek: ret %lld\n", retVal); ++ ++ return retVal; ++} ++ ++int Daemon_Library_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int retCode = -ENOSYS; ++ daemon_handle_t *dh; ++ HANDLE handle = NULL; ++ unsigned long cpylen; ++ ++ dh = file->private_data; ++ ++ DbgPrint("Daemon_Library_ioctl: file=0x%p 0x%x 0x%p dh=0x%p\n", file, ++ cmd, arg, dh); ++ ++ if (dh) { ++ ++ switch (cmd) { ++ case IOC_LOGIN: ++ retCode = daemon_login((struct login *)arg, &dh->session); ++ break; ++ ++ case IOC_LOGOUT: ++ retCode = daemon_logout((struct logout *)arg, &dh->session); ++ break; ++ ++ case IOC_DEBUGPRINT: ++ { ++ struct Ioctl_Debug { ++ int length; ++ char *data; ++ } io; ++ char *buf; ++ io.length = 0; ++ cpylen = ++ copy_from_user(&io, (void *)arg, ++ sizeof(io)); ++ if (io.length) { ++ buf = kmalloc(io.length + 1, GFP_KERNEL); ++ if (buf) { ++ buf[0] = 0; ++ cpylen = copy_from_user(buf, io.data, io.length); ++ buf[io.length] = '\0'; ++ DbgPrint("%s", buf); ++ kfree(buf); ++ retCode = 0; ++ } ++ } ++ break; ++ } ++ ++ case IOC_XPLAT: ++ { ++ XPLAT data; ++ ++ cpylen = ++ copy_from_user(&data, (void *)arg, ++ sizeof(data)); ++ retCode = ++ ((data. ++ xfunction & 0x0000FFFF) | 0xCC000000); ++ ++ switch (data.xfunction) { ++ case NWC_OPEN_CONN_BY_NAME: ++ DbgPrint("[VFS XPLAT] Call NwOpenConnByName\n"); ++ retCode = NwOpenConnByName(&data, &handle, dh->session); ++ if (!retCode) ++ Daemon_Added_Resource(dh, DH_TYPE_CONNECTION, handle, NULL, 0, 0); ++ break; ++ ++ case NWC_OPEN_CONN_BY_ADDRESS: ++ DbgPrint("[VFS XPLAT] Call NwOpenConnByAddress\n"); ++ retCode = NwOpenConnByAddr(&data, &handle, dh->session); ++ if (!retCode) ++ Daemon_Added_Resource(dh, DH_TYPE_CONNECTION, handle, NULL, 0, 0); ++ break; ++ ++ case NWC_OPEN_CONN_BY_REFERENCE: ++ DbgPrint("[VFS XPLAT] Call NwOpenConnByReference\n"); ++ retCode = NwOpenConnByRef(&data, &handle, dh->session); ++ if (!retCode) ++ Daemon_Added_Resource(dh, ++ DH_TYPE_CONNECTION, ++ handle, NULL, ++ 0, 0); ++ break; ++ ++ case NWC_SYS_CLOSE_CONN: ++ DbgPrint("[VFS XPLAT] Call NwSysCloseConn\n"); ++ retCode = NwSysConnClose(&data, (unsigned long *)&handle, dh->session); ++ Daemon_Remove_Resource(dh, DH_TYPE_CONNECTION, handle, 0); ++ break; ++ ++ case NWC_CLOSE_CONN: ++ DbgPrint ++ ("[VFS XPLAT] Call NwCloseConn\n"); ++ retCode = ++ NwConnClose(&data, &handle, ++ dh->session); ++ Daemon_Remove_Resource(dh, ++ DH_TYPE_CONNECTION, ++ handle, 0); ++ break; ++ ++ case NWC_LOGIN_IDENTITY: ++ DbgPrint("[VFS XPLAT] Call NwLoginIdentity\n"); ++ retCode = NwLoginIdentity(&data, &dh->session); ++ break; ++ ++ case NWC_RAW_NCP_REQUEST: ++ DbgPrint("[VFS XPLAT] Send Raw NCP Request\n"); ++ retCode = NwRawSend(&data, dh->session); ++ break; ++ ++ case NWC_AUTHENTICATE_CONN_WITH_ID: ++ DbgPrint ++ ("[VFS XPLAT] Authenticate Conn With ID\n"); ++ retCode = ++ NwAuthConnWithId(&data, ++ dh->session); ++ break; ++ ++ case NWC_UNAUTHENTICATE_CONN: ++ DbgPrint ++ ("[VFS XPLAT] UnAuthenticate Conn With ID\n"); ++ retCode = ++ NwUnAuthenticate(&data, ++ dh->session); ++ break; ++ ++ case NWC_LICENSE_CONN: ++ DbgPrint("Call NwLicenseConn\n"); ++ retCode = ++ NwLicenseConn(&data, dh->session); ++ break; ++ ++ case NWC_LOGOUT_IDENTITY: ++ DbgPrint ++ ("[VFS XPLAT] Call NwLogoutIdentity\n"); ++ retCode = ++ NwLogoutIdentity(&data, ++ dh->session); ++ break; ++ ++ case NWC_UNLICENSE_CONN: ++ DbgPrint ++ ("[VFS XPLAT] Call NwUnlicense\n"); ++ retCode = ++ NwUnlicenseConn(&data, dh->session); ++ break; ++ ++ case NWC_GET_CONN_INFO: ++ DbgPrint ++ ("[VFS XPLAT] Call NwGetConnInfo\n"); ++ retCode = ++ NwGetConnInfo(&data, dh->session); ++ break; ++ ++ case NWC_SET_CONN_INFO: ++ DbgPrint ++ ("[VFS XPLAT] Call NwGetConnInfo\n"); ++ retCode = ++ NwSetConnInfo(&data, dh->session); ++ break; ++ ++ case NWC_SCAN_CONN_INFO: ++ DbgPrint ++ ("[VFS XPLAT] Call NwScanConnInfo\n"); ++ retCode = ++ NwScanConnInfo(&data, dh->session); ++ break; ++ ++ case NWC_GET_IDENTITY_INFO: ++ DbgPrint ++ ("[VFS XPLAT] Call NwGetIdentityInfo\n"); ++ retCode = ++ NwGetIdentityInfo(&data, ++ dh->session); ++ break; ++ ++ case NWC_GET_REQUESTER_VERSION: ++ DbgPrint ++ ("[VFS XPLAT] Call NwGetDaemonVersion\n"); ++ retCode = ++ NwGetDaemonVersion(&data, ++ dh->session); ++ break; ++ ++ case NWC_GET_PREFERRED_DS_TREE: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcGetPreferredDsTree\n"); ++ retCode = ++ NwcGetPreferredDSTree(&data, ++ dh->session); ++ break; ++ ++ case NWC_SET_PREFERRED_DS_TREE: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcSetPreferredDsTree\n"); ++ retCode = ++ NwcSetPreferredDSTree(&data, ++ dh->session); ++ break; ++ ++ case NWC_GET_DEFAULT_NAME_CONTEXT: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcGetDefaultNameContext\n"); ++ retCode = ++ NwcGetDefaultNameCtx(&data, ++ dh->session); ++ break; ++ ++ case NWC_SET_DEFAULT_NAME_CONTEXT: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcSetDefaultNameContext\n"); ++ retCode = ++ NwcSetDefaultNameCtx(&data, ++ dh->session); ++ break; ++ ++ case NWC_QUERY_FEATURE: ++ DbgPrint ++ ("[VFS XPLAT] Call NwQueryFeature\n"); ++ retCode = ++ NwQueryFeature(&data, dh->session); ++ break; ++ ++ case NWC_GET_TREE_MONITORED_CONN_REF: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcGetTreeMonitoredConn\n"); ++ retCode = ++ NwcGetTreeMonitoredConn(&data, ++ dh-> ++ session); ++ break; ++ ++ case NWC_ENUMERATE_IDENTITIES: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcEnumerateIdentities\n"); ++ retCode = ++ NwcEnumIdentities(&data, ++ dh->session); ++ break; ++ ++ case NWC_CHANGE_KEY: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcChangeAuthKey\n"); ++ retCode = ++ NwcChangeAuthKey(&data, ++ dh->session); ++ break; ++ ++ case NWC_CONVERT_LOCAL_HANDLE: ++ DbgPrint ++ ("[VFS XPLAT] Call NwdConvertLocalHandle\n"); ++ retCode = ++ NwdConvertLocalHandle(&data, dh); ++ break; ++ ++ case NWC_CONVERT_NETWARE_HANDLE: ++ DbgPrint ++ ("[VFS XPLAT] Call NwdConvertNetwareHandle\n"); ++ retCode = ++ NwdConvertNetwareHandle(&data, dh); ++ break; ++ ++ case NWC_SET_PRIMARY_CONN: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcSetPrimaryConn\n"); ++ retCode = ++ NwcSetPrimaryConn(&data, ++ dh->session); ++ break; ++ ++ case NWC_GET_PRIMARY_CONN: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcGetPrimaryConn\n"); ++ retCode = ++ NwcGetPrimaryConn(&data, ++ dh->session); ++ break; ++ ++ case NWC_MAP_DRIVE: ++ DbgPrint("[VFS XPLAT] Call NwcMapDrive\n"); ++ retCode = NwdSetMapDrive(&data, dh->session); ++ break; ++ ++ case NWC_UNMAP_DRIVE: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcUnMapDrive\n"); ++ retCode = NwdUnMapDrive(&data, dh->session); ++ break; ++ ++ case NWC_ENUMERATE_DRIVES: ++ DbgPrint ++ ("[VFS XPLAT] Call NwcEnumerateDrives\n"); ++ retCode = ++ NwcEnumerateDrives(&data, ++ dh->session); ++ break; ++ ++ case NWC_GET_MOUNT_PATH: ++ DbgPrint ++ ("[VFS XPLAT] Call NwdGetMountPath\n"); ++ retCode = NwdGetMountPath(&data); ++ break; ++ ++ case NWC_GET_BROADCAST_MESSAGE: ++ DbgPrint ++ ("[VSF XPLAT Call NwdGetBroadcastMessage\n"); ++ retCode = ++ NwcGetBroadcastMessage(&data, ++ dh->session); ++ break; ++ ++ case NWC_SET_KEY: ++ DbgPrint("[VSF XPLAT Call NwdSetKey\n"); ++ retCode = ++ NwdSetKeyValue(&data, dh->session); ++ break; ++ ++ case NWC_VERIFY_KEY: ++ DbgPrint ++ ("[VSF XPLAT Call NwdVerifyKey\n"); ++ retCode = ++ NwdVerifyKeyValue(&data, ++ dh->session); ++ break; ++ ++ case NWC_RAW_NCP_REQUEST_ALL: ++ case NWC_NDS_RESOLVE_NAME_TO_ID: ++ case NWC_FRAGMENT_REQUEST: ++ case NWC_GET_CONFIGURED_NSPS: ++ default: ++ break; ++ ++ } ++ ++ DbgPrint("[NOVFS XPLAT] status Code = %X\n", ++ retCode); ++ break; ++ } ++ } ++ } ++ ++ return (retCode); ++} ++ ++unsigned int Daemon_Poll(struct file *file, struct poll_table_struct *poll_table) ++{ ++ daemon_command_t *que; ++ unsigned int mask = POLLOUT | POLLWRNORM; ++ ++ que = get_next_queue(0); ++ if (que) ++ mask |= (POLLIN | POLLRDNORM); ++ return mask; ++} ++ ++int NwdConvertNetwareHandle(PXPLAT pdata, daemon_handle_t *DHandle) ++{ ++ int retVal; ++ NwcConvertNetWareHandle nh; ++ unsigned long cpylen; ++ ++ DbgPrint("NwdConvertNetwareHandle: DHandle=0x%p\n", DHandle); ++ ++ cpylen = copy_from_user(&nh, pdata->reqData, sizeof(NwcConvertNetWareHandle)); ++ ++ retVal = Daemon_Added_Resource(DHandle, DH_TYPE_STREAM, ++ Uint32toHandle(nh.ConnHandle), ++ nh.NetWareHandle, nh.uAccessMode, ++ nh.uFileSize); ++ ++ return retVal; ++} ++ ++/*++======================================================================*/ ++int NwdConvertLocalHandle(PXPLAT pdata, daemon_handle_t * DHandle) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retVal = NWE_REQUESTER_FAILURE; ++ daemon_resource_t *resource; ++ NwcConvertLocalHandle lh; ++ struct list_head *l; ++ unsigned long cpylen; ++ ++ DbgPrint("NwdConvertLocalHandle: DHandle=0x%p\n", DHandle); ++ ++ read_lock(&DHandle->lock); ++ ++ list_for_each(l, &DHandle->list) { ++ resource = list_entry(l, daemon_resource_t, list); ++ ++ if (DH_TYPE_STREAM == resource->type) { ++ lh.uConnReference = ++ HandletoUint32(resource->connection); ++ ++//sgled memcpy(lh.NwWareHandle, resource->handle, sizeof(resource->handle)); ++ memcpy(lh.NetWareHandle, resource->handle, sizeof(resource->handle)); //sgled ++ if (pdata->repLen >= sizeof(NwcConvertLocalHandle)) { ++ cpylen = ++ copy_to_user(pdata->repData, &lh, ++ sizeof(NwcConvertLocalHandle)); ++ retVal = 0; ++ } else { ++ retVal = NWE_BUFFER_OVERFLOW; ++ } ++ break; ++ } ++ } ++ ++ read_unlock(&DHandle->lock); ++ ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int NwdGetMountPath(PXPLAT pdata) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retVal = NWE_REQUESTER_FAILURE; ++ int len; ++ unsigned long cpylen; ++ NwcGetMountPath mp; ++ ++ cpylen = copy_from_user(&mp, pdata->reqData, pdata->reqLen); ++ ++ if (Novfs_CurrentMount) { ++ ++ len = strlen(Novfs_CurrentMount) + 1; ++ if ((len > mp.MountPathLen) && mp.pMountPath) { ++ retVal = NWE_BUFFER_OVERFLOW; ++ } else { ++ if (mp.pMountPath) { ++ cpylen = ++ copy_to_user(mp.pMountPath, ++ Novfs_CurrentMount, len); ++ } ++ retVal = 0; ++ } ++ ++ mp.MountPathLen = len; ++ ++ if (pdata->repData && (pdata->repLen >= sizeof(mp))) { ++ cpylen = copy_to_user(pdata->repData, &mp, sizeof(mp)); ++ } ++ } ++ ++ return (retVal); ++} ++ ++static int NwdSetMapDrive(PXPLAT pdata, session_t Session) ++{ ++ int retVal; ++ NwcMapDriveEx symInfo; ++ char *path; ++ drive_map_t *drivemap, *dm; ++ struct list_head *list; ++ ++ retVal = NwcSetMapDrive(pdata, Session); ++ if (retVal) ++ return retVal; ++ ++ if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) ++ return -EFAULT; ++ ++ drivemap = kmalloc(sizeof(drive_map_t) + symInfo.linkOffsetLength, GFP_KERNEL); ++ if (!drivemap) ++ return -ENOMEM; ++ ++ path = (char *)pdata->reqData; ++ path += symInfo.linkOffset; ++ if (copy_from_user(drivemap->name, path, symInfo.linkOffsetLength)) { ++ kfree(drivemap); ++ return -EFAULT; ++ } ++ ++ drivemap->session = Session; ++ drivemap->hash = full_name_hash(drivemap->name, symInfo.linkOffsetLength - 1); ++ drivemap->namelen = symInfo.linkOffsetLength - 1; ++ DbgPrint("NwdSetMapDrive: hash=0x%x path=%s\n", drivemap->hash, drivemap->name); ++ ++ dm = (drive_map_t *) & DriveMapList.next; ++ ++ down(&DriveMapLock); ++ ++ list_for_each(list, &DriveMapList) { ++ dm = list_entry(list, drive_map_t, list); ++ DbgPrint("NwdSetMapDrive: dm=0x%p\n" ++ " hash: 0x%x\n" ++ " namelen: %d\n" ++ " name: %s\n", ++ dm, dm->hash, dm->namelen, dm->name); ++ ++ if (drivemap->hash == dm->hash) { ++ if (0 == ++ strcmp(dm->name, drivemap->name)) { ++ dm = NULL; ++ break; ++ } ++ } else if (drivemap->hash < dm->hash) { ++ break; ++ } ++ } ++ ++ if (dm) { ++ if ((dm == (drive_map_t *) & DriveMapList) || ++ (dm->hash < drivemap->hash)) { ++ list_add(&drivemap->list, &dm->list); ++ } else { ++ list_add_tail(&drivemap->list, ++ &dm->list); ++ } ++ } else { ++ kfree(drivemap); ++ } ++ up(&DriveMapLock); ++ ++ return (retVal); ++} ++ ++static int NwdUnMapDrive(PXPLAT pdata, session_t Session) ++{ ++ int retVal = NWE_REQUESTER_FAILURE; ++ NwcUnmapDriveEx symInfo; ++ char *path; ++ drive_map_t *dm; ++ struct list_head *list; ++ unsigned long hash; ++ ++ retVal = NwcUnMapDrive(pdata, Session); ++ if (retVal) ++ return retVal; ++ ++ if (copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo))) ++ return -EFAULT; ++ ++ path = kmalloc(symInfo.linkLen, GFP_KERNEL); ++ if (!path) ++ return -ENOMEM; ++ ++ if (copy_from_user(path, ((NwcUnmapDriveEx *)pdata->reqData)->linkData, symInfo.linkLen)) { ++ kfree(path); ++ return -EFAULT; ++ } ++ ++ hash = full_name_hash(path, symInfo.linkLen - 1); ++ DbgPrint("NwdUnMapDrive: hash=0x%x path=%s\n", hash, path); ++ ++ dm = NULL; ++ ++ down(&DriveMapLock); ++ ++ list_for_each(list, &DriveMapList) { ++ dm = list_entry(list, drive_map_t, list); ++ DbgPrint("NwdUnMapDrive: dm=0x%p %s\n" ++ " hash: 0x%x\n" ++ " namelen: %d\n", ++ dm, dm->name, dm->hash, dm->namelen); ++ ++ if (hash == dm->hash) { ++ if (0 == strcmp(dm->name, path)) { ++ break; ++ } ++ } else if (hash < dm->hash) { ++ dm = NULL; ++ break; ++ } ++ } ++ ++ if (dm) { ++ DbgPrint("NwdUnMapDrive: Remove dm=0x%p %s\n" ++ " hash: 0x%x\n" ++ " namelen: %d\n", ++ dm, dm->name, dm->hash, dm->namelen); ++ list_del(&dm->list); ++ kfree(dm); ++ } ++ ++ up(&DriveMapLock); ++ ++ return retVal; ++} ++ ++/*++======================================================================*/ ++void RemoveDriveMaps(void) ++/* ++ * ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ drive_map_t *dm; ++ struct list_head *list; ++ ++ down(&DriveMapLock); ++ list_for_each(list, &DriveMapList) { ++ dm = list_entry(list, drive_map_t, list); ++ ++ DbgPrint("RemoveDriveMap: dm=0x%p\n" ++ " hash: 0x%x\n" ++ " namelen: %d\n" ++ " name: %s\n", ++ dm, dm->hash, dm->namelen, dm->name); ++ local_unlink(dm->name); ++ list = list->prev; ++ list_del(&dm->list); ++ kfree(dm); ++ } ++ up(&DriveMapLock); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) ++/*++======================================================================*/ ++int local_unlink(const char *pathname) ++{ ++ int error; ++ struct dentry *dentry; ++ struct nameidata nd; ++ struct inode *inode = NULL; ++ ++ DbgPrint("local_unlink: %s\n", pathname); ++ error = path_lookup(pathname, LOOKUP_PARENT, &nd); ++ DbgPrint("local_unlink: path_lookup %d\n", error); ++ if (!error) { ++ error = -EISDIR; ++ if (nd.last_type == LAST_NORM) { ++ dentry = lookup_create(&nd, 1); ++ DbgPrint("local_unlink: lookup_hash 0x%p\n", dentry); ++ ++ error = PTR_ERR(dentry); ++ if (!IS_ERR(dentry)) { ++ if (nd.last.name[nd.last.len]) { ++ error = ++ !dentry-> ++ d_inode ? -ENOENT : S_ISDIR(dentry-> ++ d_inode-> ++ i_mode) ++ ? -EISDIR : -ENOTDIR; ++ } else { ++ inode = dentry->d_inode; ++ if (inode) { ++ atomic_inc(&inode->i_count); ++ } ++ error = vfs_unlink(nd.path.dentry->d_inode, dentry, nd.path.mnt); ++ DbgPrint ++ ("local_unlink: vfs_unlink %d\n", ++ error); ++ } ++ dput(dentry); ++ } ++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex); ++ ++ } ++ path_put(&nd.path); ++ } ++ ++ if (inode) { ++ iput(inode); /* truncate the inode here */ ++ } ++ ++ DbgPrint("local_unlink: error=%d\n", error); ++ return error; ++} ++ ++#else ++/*++======================================================================*/ ++int local_unlink(const char *pathname) ++{ ++ int error; ++ struct dentry *dentry; ++ struct nameidata nd; ++ struct inode *inode = NULL; ++ ++ DbgPrint("local_unlink: %s\n", pathname); ++ error = path_lookup(pathname, LOOKUP_PARENT, &nd); ++ DbgPrint("local_unlink: path_lookup %d\n", error); ++ if (!error) { ++ error = -EISDIR; ++ if (nd.last_type == LAST_NORM) { ++ down(&nd.dentry->d_inode->i_sem); ++ dentry = ++ lookup_one_len(&nd.last, nd.dentry, ++ sizeof(nd.last)); ++ DbgPrint("local_unlink: lookup_hash 0x%p\n", dentry); ++ ++ error = PTR_ERR(dentry); ++ if (!IS_ERR(dentry)) { ++ if (nd.last.name[nd.last.len]) { ++ error = ++ !dentry-> ++ d_inode ? -ENOENT : S_ISDIR(dentry-> ++ d_inode-> ++ i_mode) ++ ? -EISDIR : -ENOTDIR; ++ } else { ++ inode = dentry->d_inode; ++ if (inode) { ++ atomic_inc(&inode->i_count); ++ } ++ error = ++ vfs_unlink(nd.dentry->d_inode, ++ dentry); ++ DbgPrint ++ ("local_unlink: vfs_unlink %d\n", ++ error); ++ } ++ dput(dentry); ++ } ++ up(&nd.dentry->d_inode->i_sem); ++ } ++ path_release(&nd); ++ } ++ ++ if (inode) { ++ iput(inode); /* truncate the inode here */ ++ } ++ ++ DbgPrint("local_unlink: error=%d\n", error); ++ return error; ++} ++#endif +--- /dev/null ++++ b/fs/novfs/file.c +@@ -0,0 +1,1964 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * This file contains functions for accessing files through the daemon. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vfs.h" ++#include "commands.h" ++#include "nwerror.h" ++ ++/*===[ Function prototypes ]==============================================*/ ++int Novfs_get_alltrees(struct dentry *parent); ++ssize_t Novfs_tree_read(struct file *file, char *buf, size_t len, loff_t * off); ++ ++int Novfs_Find_Name_In_List(struct qstr *Name, unsigned char * List); ++ ++int Novfs_Create(unsigned char * Path, int DirectoryFlag, session_t SessionId); ++int Novfs_Close_File(HANDLE Handle, session_t SessionId); ++int Novfs_Read_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, ++ loff_t * Offset, session_t SessionId); ++int Novfs_Write_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, ++ loff_t * Offset, session_t SessionId); ++int Novfs_Write_Page(HANDLE Handle, struct page *Page, session_t SessionId); ++int Novfs_Read_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, ++ size_t * Bytes, loff_t * Offset, int User, ++ session_t SessionId); ++int Novfs_Write_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, ++ size_t * Bytes, loff_t * Offset, session_t SessionId); ++int Novfs_Close_Stream(HANDLE ConnHandle, unsigned char * Handle, session_t SessionId); ++int Novfs_Delete(unsigned char * Path, int DirectoryFlag, session_t SessionId); ++int Novfs_Truncate_File(unsigned char * Path, int PathLen, session_t SessionId); ++int Novfs_Truncate_File_Ex(HANDLE Handle, loff_t Offset, session_t SessionId); ++int Novfs_Rename_File(int DirectoryFlag, unsigned char * OldName, int OldLen, ++ unsigned char * NewName, int NewLen, session_t SessionId); ++int Novfs_Set_Attr(unsigned char * Path, struct iattr *Attr, session_t SessionId); ++int Novfs_Get_File_Cache_Flag(unsigned char * Path, session_t SessionId); ++ ++static struct file_operations Novfs_tree_operations = { ++ read:Novfs_tree_read, ++}; ++ ++/* ++ * StripTrailingDots was added because some apps will ++ * try and create a file name with a trailing dot. NetWare ++ * doesn't like this and will return an error. ++ */ ++static int StripTrailingDots = 1; ++ ++int Novfs_get_alltrees(struct dentry *parent) ++{ ++ unsigned char *p; ++ PCOMMAND_REPLY_HEADER reply = NULL; ++ unsigned long replylen = 0; ++ COMMAND_REQUEST_HEADER cmd; ++ int retCode; ++ struct dentry *entry; ++ struct qstr name; ++ struct inode *inode; ++ ++ cmd.CommandType = 0; ++ cmd.SequenceNumber = 0; ++//sg ??? cmd.SessionId = 0x1234; ++ SC_INITIALIZE(cmd.SessionId); ++ ++ DbgPrint("Novfs_get_alltrees:\n"); ++ ++ retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ DbgPrint("Novfs_get_alltrees: relpy=0x%p replylen=%d\n", reply, ++ replylen); ++ if (reply) { ++ mydump(replylen, reply); ++ if (!reply->ErrorCode ++ && (replylen > sizeof(COMMAND_REPLY_HEADER))) { ++ p = (char *)reply + 8; ++ while (*p) { ++ DbgPrint("Novfs_get_alltrees: %s\n", p); ++ name.len = strlen(p); ++ name.name = p; ++ name.hash = full_name_hash(name.name, name.len); ++ entry = d_lookup(parent, &name); ++ if (NULL == entry) { ++ DbgPrint("Novfs_get_alltrees: adding %s\n", p); ++ entry = d_alloc(parent, &name); ++ if (entry) { ++ entry->d_op = &Novfs_dentry_operations; ++ inode = Novfs_get_inode(parent->d_sb, S_IFREG | 0400, 0, 0, 0, &name); ++ if (inode) { ++ inode->i_fop = &Novfs_tree_operations; ++ d_add(entry, inode); ++ } ++ } ++ } ++ p += (name.len + 1); ++ } ++ } ++ kfree(reply); ++ } ++ return (retCode); ++} ++ ++ssize_t Novfs_tree_read(struct file * file, char *buf, size_t len, loff_t * off) ++{ ++ if (file->f_pos != 0) { ++ return (0); ++ } ++ if (copy_to_user(buf, "Tree\n", 5)) { ++ return (0); ++ } ++ return (5); ++} ++ ++int Novfs_Get_Connected_Server_List(unsigned char ** ServerList, struct schandle *SessionId) ++{ ++ GET_CONNECTED_SERVER_LIST_REQUEST req; ++ PGET_CONNECTED_SERVER_LIST_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ ++ *ServerList = NULL; ++ ++ req.Command.CommandType = VFS_COMMAND_GET_CONNECTED_SERVER_LIST; ++ memcpy(&req.Command.SessionId, SessionId, sizeof(*SessionId)); ++ ++ retCode = ++ Queue_Daemon_Command(&req, sizeof(req), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ DbgPrint("Novfs_Get_Connected_Server_List: reply\n"); ++ replylen -= sizeof(COMMAND_REPLY_HEADER); ++ if (!reply->Reply.ErrorCode && replylen) { ++ memcpy(reply, reply->List, replylen); ++ *ServerList = (unsigned char *) reply; ++ retCode = 0; ++ } else { ++ kfree(reply); ++ retCode = -ENOENT; ++ } ++ } ++ return (retCode); ++} ++ ++int Novfs_Get_Server_Volume_List(struct qstr *Server, unsigned char ** VolumeList, ++ struct schandle *SessionId) ++{ ++ PGET_SERVER_VOLUME_LIST_REQUEST req; ++ PGET_SERVER_VOLUME_LIST_REPLY reply = NULL; ++ unsigned long replylen = 0, reqlen; ++ int retCode; ++ ++ *VolumeList = NULL; ++ reqlen = sizeof(GET_SERVER_VOLUME_LIST_REQUEST) + Server->len; ++ req = kmalloc(reqlen, GFP_KERNEL); ++ if (!req) ++ return -ENOMEM; ++ req->Command.CommandType = VFS_COMMAND_GET_SERVER_VOLUME_LIST; ++ req->Length = Server->len; ++ memcpy(req->Name, Server->name, Server->len); ++ memcpy(&req->Command.SessionId, SessionId, sizeof(*SessionId)); ++ ++ retCode = Queue_Daemon_Command(req, reqlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ DbgPrint("Novfs_Get_Server_Volume_List: reply\n"); ++ mydump(replylen, reply); ++ replylen -= sizeof(COMMAND_REPLY_HEADER); ++ ++ if (!reply->Reply.ErrorCode && replylen) { ++ memcpy(reply, reply->List, replylen); ++ *VolumeList = (unsigned char *) reply; ++ retCode = 0; ++ } else { ++ kfree(reply); ++ retCode = -ENOENT; ++ } ++ } ++ kfree(req); ++ return retCode; ++} ++ ++int Novfs_Find_Name_In_List(struct qstr *Name, unsigned char * List) ++{ ++ int len; ++ int retCode = 0; ++ ++ while (*List) { ++ len = strlen(List); ++ if ((len == Name->len) && !strncmp(Name->name, List, len)) { ++ retCode = 1; ++ break; ++ } ++ List += (len + 1); ++ } ++ return (retCode); ++} ++ ++int Novfs_Get_File_Info(unsigned char * Path, struct entry_info *Info, struct schandle *SessionId) ++{ ++ PVERIFY_FILE_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ PVERIFY_FILE_REQUEST cmd; ++ int cmdlen; ++ int retCode = -ENOENT; ++ int pathlen; ++ ++ DbgPrint("%s: Path = %s\n", __func__, Path); ++ ++ Info->mode = S_IFDIR | 0700; ++ Info->uid = current->uid; ++ Info->gid = current->gid; ++ Info->size = 0; ++ Info->atime = Info->mtime = Info->ctime = CURRENT_TIME; ++ ++ if (Path && *Path) { ++ pathlen = strlen(Path); ++ if (StripTrailingDots) { ++ if ('.' == Path[pathlen - 1]) ++ pathlen--; ++ } ++ cmdlen = offsetof(VERIFY_FILE_REQUEST, path) + pathlen; ++ cmd = (PVERIFY_FILE_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_VERIFY_FILE; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->pathLen = pathlen; ++ memcpy(cmd->path, Path, cmd->pathLen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, ++ (void *)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ ++ if (reply->Reply.ErrorCode) { ++ retCode = -ENOENT; ++ } else { ++ Info->type = 3; ++ Info->mode = S_IRWXU; ++ ++ if (reply-> ++ fileMode & NW_ATTRIBUTE_DIRECTORY) { ++ Info->mode |= S_IFDIR; ++ } else { ++ Info->mode |= S_IFREG; ++ } ++ ++ if (reply-> ++ fileMode & NW_ATTRIBUTE_READ_ONLY) { ++ Info->mode &= ~(S_IWUSR); ++ } ++ ++ Info->uid = current->euid; ++ Info->gid = current->egid; ++ Info->size = reply->fileSize; ++ Info->atime.tv_sec = ++ reply->lastAccessTime; ++ Info->atime.tv_nsec = 0; ++ Info->mtime.tv_sec = reply->modifyTime; ++ Info->mtime.tv_nsec = 0; ++ Info->ctime.tv_sec = reply->createTime; ++ Info->ctime.tv_nsec = 0; ++ DbgPrint("%s: replylen=%d sizeof(VERIFY_FILE_REPLY)=%d\n", __func__, replylen, sizeof(VERIFY_FILE_REPLY)); ++ if (replylen > sizeof(VERIFY_FILE_REPLY)) { ++ unsigned int *lp = &reply->fileMode; ++ lp++; ++ DbgPrint("%s: extra data 0x%x\n", __func__, *lp); ++ Info->mtime.tv_nsec = *lp; ++ } ++ retCode = 0; ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ } ++ ++ DbgPrint("%s: return 0x%x\n", __func__, retCode); ++ return (retCode); ++} ++ ++int Novfs_GetX_File_Info(char *Path, const char *Name, char *buffer, ++ ssize_t buffer_size, ssize_t * dataLen, ++ session_t *SessionId) ++{ ++ PXA_GET_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ PXA_GET_REQUEST cmd; ++ int cmdlen; ++ int retCode = -ENOENT; ++ ++ int namelen = strlen(Name); ++ int pathlen = strlen(Path); ++ ++ DbgPrint("%s: xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i\n", __func__, Path, pathlen, Name, namelen); ++ ++ if (namelen > MAX_XATTR_NAME_LEN) { ++ return ENOATTR; ++ } ++ ++ cmdlen = offsetof(XA_GET_REQUEST, data) + pathlen + 1 + namelen + 1; // two '\0' ++ cmd = (PXA_GET_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_GET_EXTENDED_ATTRIBUTE; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ ++ cmd->pathLen = pathlen; ++ memcpy(cmd->data, Path, cmd->pathLen + 1); //+ '\0' ++ ++ cmd->nameLen = namelen; ++ memcpy(cmd->data + cmd->pathLen + 1, Name, cmd->nameLen + 1); ++ ++ DbgPrint("%s xattr: PXA_GET_REQUEST BEGIN\n", __func__); ++ DbgPrint("%s xattr: Queue_Daemon_Command %d\n", __func__, cmd->Command.CommandType); ++ DbgPrint("%s xattr: Command.SessionId = %d\n", __func__, cmd->Command.SessionId); ++ DbgPrint("%s xattr: pathLen = %d\n", __func__, cmd->pathLen); ++ DbgPrint("%s xattr: Path = %s\n", __func__, cmd->data); ++ DbgPrint("%s xattr: nameLen = %d\n", __func__, cmd->nameLen); ++ DbgPrint("%s xattr: name = %s\n", __func__, (cmd->data + cmd->pathLen + 1)); ++ DbgPrint("%s xattr: PXA_GET_REQUEST END\n", __func__); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ ++ if (reply->Reply.ErrorCode) { ++ DbgPrint("%s xattr: reply->Reply.ErrorCode=%d, %X\n", __func__, reply->Reply.ErrorCode, reply->Reply.ErrorCode); ++ DbgPrint("%s xattr: replylen=%d\n", __func__, replylen); ++ ++ //0xC9 = EA not found (C9), 0xD1 = EA access denied ++ if ((reply->Reply.ErrorCode == 0xC9) ++ || (reply->Reply.ErrorCode == 0xD1)) { ++ retCode = -ENOATTR; ++ } else { ++ retCode = -ENOENT; ++ } ++ } else { ++ ++ *dataLen = ++ replylen - sizeof(COMMAND_REPLY_HEADER); ++ DbgPrint("%s xattr: replylen=%u, dataLen=%u\n", __func__, replylen, *dataLen); ++ ++ if (buffer_size >= *dataLen) { ++ DbgPrint("%s xattr: copying to buffer from &reply->pData\n", __func__); ++ memcpy(buffer, &reply->pData, *dataLen); ++ ++ retCode = 0; ++ } else { ++ DbgPrint("%s xattr: (!!!) buffer is smaller then reply\n", __func__); ++ retCode = -ERANGE; ++ } ++ DbgPrint("%s xattr: /dumping buffer\n", __func__); ++ mydump(*dataLen, buffer); ++ DbgPrint("%s xattr: \\after dumping buffer\n", __func__); ++ } ++ ++ kfree(reply); ++ } else { ++ DbgPrint("%s xattr: reply = NULL\n", __func__); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return retCode; ++} ++ ++int Novfs_SetX_File_Info(char *Path, const char *Name, const void *Value, ++ unsigned long valueLen, unsigned long *bytesWritten, ++ int flags, struct schandle *SessionId) ++{ ++ PXA_SET_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ PXA_SET_REQUEST cmd; ++ int cmdlen; ++ int retCode = -ENOENT; ++ ++ int namelen = strlen(Name); ++ int pathlen = strlen(Path); ++ ++ DbgPrint("%s xattr: Path = %s, pathlen = %i, Name = %s, namelen = %i, value len = %u\n", __func__, ++ Path, pathlen, Name, namelen, valueLen); ++ ++ if (namelen > MAX_XATTR_NAME_LEN) { ++ return ENOATTR; ++ } ++ ++ cmdlen = offsetof(XA_SET_REQUEST, data) + pathlen + 1 + namelen + 1 + valueLen; ++ cmd = (PXA_SET_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_SET_EXTENDED_ATTRIBUTE; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ ++ cmd->flags = flags; ++ cmd->pathLen = pathlen; ++ memcpy(cmd->data, Path, cmd->pathLen + 1); //+ '\0' ++ ++ cmd->nameLen = namelen; ++ memcpy(cmd->data + cmd->pathLen + 1, Name, cmd->nameLen + 1); ++ ++ cmd->valueLen = valueLen; ++ memcpy(cmd->data + cmd->pathLen + 1 + cmd->nameLen + 1, Value, ++ valueLen); ++ ++ DbgPrint("%s xattr: PXA_SET_REQUEST BEGIN\n", __func__); ++ DbgPrint("%s xattr: Queue_Daemon_Command %d\n", __func__, cmd->Command.CommandType); ++ DbgPrint("%s xattr: Command.SessionId = %d\n", __func__, cmd->Command.SessionId); ++ DbgPrint("%s xattr: pathLen = %d\n", __func__, cmd->pathLen); ++ DbgPrint("%s xattr: Path = %s\n", __func__, cmd->data); ++ DbgPrint("%s xattr: nameLen = %d\n", __func__, cmd->nameLen); ++ DbgPrint("%s xattr: name = %s\n", __func__, (cmd->data + cmd->pathLen + 1)); ++ mydump(valueLen < 16 ? valueLen : 16, (char *)Value); ++ ++ DbgPrint("%s xattr: PXA_SET_REQUEST END\n", __func__); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ ++ if (reply->Reply.ErrorCode) { ++ DbgPrint("%s xattr: reply->Reply.ErrorCode=%d, %X\n", __func__, reply->Reply.ErrorCode, reply->Reply.ErrorCode); ++ DbgPrint("%s xattr: replylen=%d\n", __func__, replylen); ++ ++ retCode = -reply->Reply.ErrorCode; //-ENOENT; ++ } else { ++ ++ DbgPrint("%s xattr: replylen=%u, real len = %u\n", __func__, replylen, replylen - sizeof(COMMAND_REPLY_HEADER)); ++ memcpy(bytesWritten, &reply->pData, ++ replylen - sizeof(COMMAND_REPLY_HEADER)); ++ ++ retCode = 0; ++ } ++ ++ kfree(reply); ++ } else { ++ DbgPrint("%s xattr: reply = NULL\n", __func__); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return retCode; ++} ++ ++int Novfs_ListX_File_Info(char *Path, char *buffer, ssize_t buffer_size, ssize_t * dataLen, struct schandle *SessionId) ++{ ++ PXA_LIST_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ PVERIFY_FILE_REQUEST cmd; ++ int cmdlen; ++ int retCode = -ENOENT; ++ ++ int pathlen = strlen(Path); ++ DbgPrint("%s xattr: Path = %s, pathlen = %i\n", __func__, Path, pathlen); ++ ++ *dataLen = 0; ++ cmdlen = offsetof(VERIFY_FILE_REQUEST, path) + pathlen; ++ cmd = (PVERIFY_FILE_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_LIST_EXTENDED_ATTRIBUTES; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ cmd->pathLen = pathlen; ++ memcpy(cmd->path, Path, cmd->pathLen + 1); //+ '\0' ++ DbgPrint("%s xattr: PVERIFY_FILE_REQUEST BEGIN\n", __func__); ++ DbgPrint("%s xattr: Queue_Daemon_Command %d\n", __func__, cmd->Command.CommandType); ++ DbgPrint("%s xattr: Command.SessionId = %d\n", __func__, cmd->Command.SessionId); ++ DbgPrint("%s xattr: pathLen = %d\n", __func__, cmd->pathLen); ++ DbgPrint("%s xattr: Path = %s\n", __func__, cmd->path); ++ DbgPrint("%s xattr: PVERIFY_FILE_REQUEST END\n", __func__); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ ++ if (reply->Reply.ErrorCode) { ++ DbgPrint("%s xattr: reply->Reply.ErrorCode=%d, %X\n", __func__, reply->Reply.ErrorCode, reply->Reply.ErrorCode); ++ DbgPrint("%s xattr: replylen=%d\n", __func__, replylen); ++ ++ retCode = -ENOENT; ++ } else { ++ *dataLen = replylen - sizeof(COMMAND_REPLY_HEADER); ++ DbgPrint("%s xattr: replylen=%u, dataLen=%u\n", __func__, replylen, *dataLen); ++ ++ if (buffer_size >= *dataLen) { ++ DbgPrint("%s xattr: copying to buffer from &reply->pData\n", __func__); ++ memcpy(buffer, &reply->pData, *dataLen); ++ } else { ++ DbgPrint("%s xattr: (!!!) buffer is smaller then reply\n", __func__); ++ retCode = -ERANGE; ++ } ++ DbgPrint("%s xattr: /dumping buffer\n", __func__); ++ mydump(*dataLen, buffer); ++ DbgPrint("%s xattr: \\after dumping buffer\n", __func__); ++ ++ retCode = 0; ++ } ++ ++ kfree(reply); ++ } else { ++ DbgPrint("%s xattr: reply = NULL\n", __func__); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return retCode; ++} ++ ++static int begin_directory_enumerate(unsigned char *Path, int PathLen, HANDLE *EnumHandle, struct schandle *SessionId) ++{ ++ PBEGIN_ENUMERATE_DIRECTORY_REQUEST cmd; ++ PBEGIN_ENUMERATE_DIRECTORY_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode, cmdlen; ++ ++ *EnumHandle = 0; ++ ++ cmdlen = offsetof(BEGIN_ENUMERATE_DIRECTORY_REQUEST, path) + PathLen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_START_ENUMERATE; ++ cmd->Command.SequenceNumber = 0; ++ memcpy(&cmd->Command.SessionId, SessionId, sizeof(*SessionId)); ++ ++ cmd->pathLen = PathLen; ++ memcpy(cmd->path, Path, PathLen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++/* ++ * retCode = Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, &replylen, 0); ++ */ ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } else { ++ *EnumHandle = reply->enumerateHandle; ++ retCode = 0; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } else { ++ retCode = -ENOMEM; ++ } ++ return (retCode); ++} ++ ++static int end_directory_enumerate(HANDLE EnumHandle, struct schandle *SessionId) ++{ ++ END_ENUMERATE_DIRECTORY_REQUEST cmd; ++ PEND_ENUMERATE_DIRECTORY_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ cmd.Command.CommandType = VFS_COMMAND_END_ENUMERATE; ++ cmd.Command.SequenceNumber = 0; ++ copy_session_id(&cmd.Command.SessionId, SessionId); ++ ++ cmd.enumerateHandle = EnumHandle; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, 0); ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ ++ return (retCode); ++} ++ ++int directory_enumerate(HANDLE * EnumHandle, struct entry_info *Info, ++ session_t SessionId) ++{ ++ ENUMERATE_DIRECTORY_REQUEST cmd; ++ PENUMERATE_DIRECTORY_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ cmd.Command.CommandType = VFS_COMMAND_ENUMERATE_DIRECTORY; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.enumerateHandle = *EnumHandle; ++ cmd.pathLen = 0; ++ cmd.path[0] = '\0'; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ /* ++ * The VFS_COMMAND_ENUMERATE_DIRECTORY call can return an ++ * error but there could still be valid data. ++ */ ++ if (!reply->Reply.ErrorCode || ++ ((replylen > sizeof(COMMAND_REPLY_HEADER)) && ++ (reply->nameLen > 0))) { ++ Info->type = 3; ++ Info->mode = S_IRWXU; ++ ++ if (reply->mode & NW_ATTRIBUTE_DIRECTORY) { ++ Info->mode |= S_IFDIR; ++ Info->mode |= S_IXUSR; ++ } else { ++ Info->mode |= S_IFREG; ++ } ++ ++ if (reply->mode & NW_ATTRIBUTE_READ_ONLY) { ++ Info->mode &= ~(S_IWUSR); ++ } ++ ++ if (reply->mode & NW_ATTRIBUTE_EXECUTE) { ++ Info->mode |= S_IXUSR; ++ } ++ ++ Info->uid = current->uid; ++ Info->gid = current->gid; ++ Info->size = reply->size; ++ Info->atime.tv_sec = reply->lastAccessTime; ++ Info->atime.tv_nsec = 0; ++ Info->mtime.tv_sec = reply->modifyTime; ++ Info->mtime.tv_nsec = 0; ++ Info->ctime.tv_sec = reply->createTime; ++ Info->ctime.tv_nsec = 0; ++ Info->namelength = reply->nameLen; ++ memcpy(Info->name, reply->name, reply->nameLen); ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -1; /* Eof of data */ ++ } ++ *EnumHandle = reply->enumerateHandle; ++ } else { ++ retCode = -ENODATA; ++ } ++ kfree(reply); ++ } ++ ++ return (retCode); ++} ++ ++static int directory_enumerate_ex(HANDLE *EnumHandle, struct schandle *SessionId, int *Count, struct entry_info **PInfo, int Interrupt) ++{ ++ ENUMERATE_DIRECTORY_EX_REQUEST cmd; ++ PENUMERATE_DIRECTORY_EX_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ struct entry_info *info; ++ PENUMERATE_DIRECTORY_EX_DATA data; ++ int isize; ++ ++ if (PInfo) { ++ *PInfo = NULL; ++ } ++ *Count = 0; ++ ++ cmd.Command.CommandType = VFS_COMMAND_ENUMERATE_DIRECTORY_EX; ++ cmd.Command.SequenceNumber = 0; ++ copy_session_id(&cmd.Command.SessionId, SessionId); ++ ++ cmd.enumerateHandle = *EnumHandle; ++ cmd.pathLen = 0; ++ cmd.path[0] = '\0'; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, Interrupt); ++ ++ if (reply) { ++ retCode = 0; ++ /* ++ * The VFS_COMMAND_ENUMERATE_DIRECTORY call can return an ++ * error but there could still be valid data. ++ */ ++ ++ if (!reply->Reply.ErrorCode || ++ ((replylen > sizeof(COMMAND_REPLY_HEADER)) && ++ (reply->enumCount > 0))) { ++ DbgPrint("directory_enumerate_ex: isize=%d\n", ++ replylen); ++ data = (PENUMERATE_DIRECTORY_EX_DATA) ((char *)reply + sizeof(ENUMERATE_DIRECTORY_EX_REPLY)); ++ isize = replylen - sizeof(PENUMERATE_DIRECTORY_EX_REPLY) - reply->enumCount * offsetof(ENUMERATE_DIRECTORY_EX_DATA, name); ++ isize += (reply->enumCount * offsetof(struct entry_info, name)); ++ ++ if (PInfo) { ++ *PInfo = info = Novfs_Malloc(isize, GFP_KERNEL); ++ if (*PInfo) { ++ DbgPrint("directory_enumerate_ex1: data=0x%p info=0x%p\n", data, info); ++ *Count = reply->enumCount; ++ do { ++ DbgPrint("directory_enumerate_ex2: data=0x%p length=%d\n", data); ++ ++ info->type = 3; ++ info->mode = S_IRWXU; ++ ++ if (data->mode & NW_ATTRIBUTE_DIRECTORY) { ++ info->mode |= S_IFDIR; ++ info->mode |= S_IXUSR; ++ } else { ++ info->mode |= S_IFREG; ++ } ++ ++ if (data->mode & NW_ATTRIBUTE_READ_ONLY) { ++ info->mode &= ~(S_IWUSR); ++ } ++ ++ if (data->mode & NW_ATTRIBUTE_EXECUTE) { ++ info->mode |= S_IXUSR; ++ } ++ ++ info->uid = current->euid; ++ info->gid = current->egid; ++ info->size = data->size; ++ info->atime.tv_sec = data->lastAccessTime; ++ info->atime.tv_nsec = 0; ++ info->mtime.tv_sec = data->modifyTime; ++ info->mtime.tv_nsec = 0; ++ info->ctime.tv_sec = data->createTime; ++ info->ctime.tv_nsec = 0; ++ info->namelength = data->nameLen; ++ memcpy(info->name, data->name, data->nameLen); ++ data = (PENUMERATE_DIRECTORY_EX_DATA)&data->name[data->nameLen]; ++ replylen = (int)((char *)&info->name[info->namelength] - (char *)info); ++ DbgPrint("directory_enumerate_ex3: info=0x%p\n", info); ++ mydump(replylen, info); ++ ++ info = (struct entry_info *)&info->name[info->namelength]; ++ ++ } while (--reply->enumCount); ++ } ++ } ++ ++ if (reply->Reply.ErrorCode) { ++ retCode = -1; /* Eof of data */ ++ } ++ *EnumHandle = reply->enumerateHandle; ++ } else { ++ retCode = -ENODATA; ++ } ++ kfree(reply); ++ } ++ ++ return (retCode); ++} ++ ++int Novfs_Get_Directory_ListEx(unsigned char * Path, HANDLE * EnumHandle, int *Count, ++ struct entry_info **Info, struct schandle *SessionId) ++{ ++ int retCode = -ENOENT; ++ ++ if (Count) ++ *Count = 0; ++ if (Info) ++ *Info = NULL; ++ ++ if ((HANDLE) - 1 == *EnumHandle) { ++ return (-ENODATA); ++ } ++ ++ if (0 == *EnumHandle) ++ retCode = begin_directory_enumerate(Path, strlen(Path), EnumHandle, SessionId); ++ ++ if (*EnumHandle) { ++ retCode = directory_enumerate_ex(EnumHandle, SessionId, Count, Info, INTERRUPTIBLE); ++ if (retCode) { ++ end_directory_enumerate(*EnumHandle, SessionId); ++ if (-1 == retCode) { ++ retCode = 0; ++ *EnumHandle = Uint32toHandle(-1); ++ } ++ } ++ } ++ return (retCode); ++} ++ ++int Novfs_Open_File(unsigned char * Path, int Flags, struct entry_info *Info, HANDLE * Handle, ++ session_t SessionId) ++{ ++ POPEN_FILE_REQUEST cmd; ++ POPEN_FILE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen, pathlen; ++ ++ pathlen = strlen(Path); ++ ++ if (StripTrailingDots) { ++ if ('.' == Path[pathlen - 1]) ++ pathlen--; ++ } ++ ++ *Handle = 0; ++ ++ cmdlen = offsetof(OPEN_FILE_REQUEST, path) + pathlen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_OPEN_FILE; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ ++ cmd->access = 0; ++ ++ if (!(Flags & O_WRONLY) || (Flags & O_RDWR)) { ++ cmd->access |= NWD_ACCESS_READ; ++ } ++ ++ if ((Flags & O_WRONLY) || (Flags & O_RDWR)) { ++ cmd->access |= NWD_ACCESS_WRITE; ++ } ++ ++ switch (Flags & (O_CREAT | O_EXCL | O_TRUNC)) { ++ case O_CREAT: ++ cmd->disp = NWD_DISP_OPEN_ALWAYS; ++ break; ++ ++ case O_CREAT | O_EXCL: ++ cmd->disp = NWD_DISP_CREATE_NEW; ++ break; ++ ++ case O_TRUNC: ++ cmd->disp = NWD_DISP_CREATE_ALWAYS; ++ break; ++ ++ case O_CREAT | O_TRUNC: ++ cmd->disp = NWD_DISP_CREATE_ALWAYS; ++ break; ++ ++ case O_CREAT | O_EXCL | O_TRUNC: ++ cmd->disp = NWD_DISP_CREATE_NEW; ++ break; ++ ++ default: ++ cmd->disp = NWD_DISP_OPEN_EXISTING; ++ break; ++ } ++ ++ cmd->mode = NWD_SHARE_READ | NWD_SHARE_WRITE | NWD_SHARE_DELETE; ++ ++ cmd->pathLen = pathlen; ++ memcpy(cmd->path, Path, pathlen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ if (NWE_OBJECT_EXISTS == reply->Reply.ErrorCode) { ++ retCode = -EEXIST; ++ } else if (NWE_ACCESS_DENIED == ++ reply->Reply.ErrorCode) { ++ retCode = -EACCES; ++ } else if (NWE_FILE_IN_USE == ++ reply->Reply.ErrorCode) { ++ retCode = -EBUSY; ++ } else { ++ retCode = -ENOENT; ++ } ++ } else { ++ *Handle = reply->handle; ++ retCode = 0; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } else { ++ retCode = -ENOMEM; ++ } ++ return (retCode); ++} ++ ++int Novfs_Create(unsigned char * Path, int DirectoryFlag, session_t SessionId) ++{ ++ PCREATE_FILE_REQUEST cmd; ++ PCREATE_FILE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen, pathlen; ++ ++ pathlen = strlen(Path); ++ ++ if (StripTrailingDots) { ++ if ('.' == Path[pathlen - 1]) ++ pathlen--; ++ } ++ ++ cmdlen = offsetof(CREATE_FILE_REQUEST, path) + pathlen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_CREATE_FILE; ++ if (DirectoryFlag) { ++ cmd->Command.CommandType = VFS_COMMAND_CREATE_DIRECOTRY; ++ } ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ ++ cmd->pathlength = pathlen; ++ memcpy(cmd->path, Path, pathlen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } else { ++ retCode = -ENOMEM; ++ } ++ return (retCode); ++} ++ ++int Novfs_Close_File(HANDLE Handle, session_t SessionId) ++{ ++ CLOSE_FILE_REQUEST cmd; ++ PCLOSE_FILE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ cmd.Command.CommandType = VFS_COMMAND_CLOSE_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.handle = Handle; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, 0); ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ return (retCode); ++} ++ ++int Novfs_Read_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, ++ loff_t * Offset, session_t SessionId) ++{ ++ READ_FILE_REQUEST cmd; ++ PREAD_FILE_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ size_t len; ++ ++ len = *Bytes; ++ *Bytes = 0; ++ ++ if ((offsetof(READ_FILE_REPLY, data) + len) > MaxIoSize) { ++ len = MaxIoSize - offsetof(READ_FILE_REPLY, data); ++ len = (len / PAGE_SIZE) * PAGE_SIZE; ++ } ++ ++ cmd.Command.CommandType = VFS_COMMAND_READ_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.handle = Handle; ++ cmd.len = len; ++ cmd.offset = *Offset; ++ ++ retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ ++ DbgPrint("Novfs_Read_File: Queue_Daemon_Command 0x%x replylen=%d\n", retCode, replylen); ++ ++ if (!retCode) { ++ if (reply->Reply.ErrorCode) { ++ if (NWE_FILE_IO_LOCKED == reply->Reply.ErrorCode) { ++ retCode = -EBUSY; ++ } else { ++ retCode = -EIO; ++ } ++ } else { ++ replylen -= offsetof(READ_FILE_REPLY, data); ++ if (replylen > 0) { ++ replylen -= copy_to_user(Buffer, reply->data, replylen); ++ *Bytes = replylen; ++ } ++ } ++ } ++ ++ if (reply) { ++ kfree(reply); ++ } ++ ++ DbgPrint("Novfs_Read_File *Bytes=0x%x retCode=0x%x\n", *Bytes, retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Read_Pages(HANDLE Handle, struct data_list *DList, int DList_Cnt, ++ size_t * Bytes, loff_t * Offset, session_t SessionId) ++{ ++ READ_FILE_REQUEST cmd; ++ PREAD_FILE_REPLY reply = NULL; ++ READ_FILE_REPLY lreply; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ size_t len; ++ ++ len = *Bytes; ++ *Bytes = 0; ++ ++ DbgPrint ++ ("Novfs_Read_Pages: Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld SessionId=0x%p:%p\n", ++ Handle, DList, DList_Cnt, len, *Offset, SessionId.hTypeId, ++ SessionId.hId); ++ ++ cmd.Command.CommandType = VFS_COMMAND_READ_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.handle = Handle; ++ cmd.len = len; ++ cmd.offset = *Offset; ++ ++ /* ++ * Dlst first entry is reserved for reply header. ++ */ ++ DList[0].page = NULL; ++ DList[0].offset = &lreply; ++ DList[0].len = offsetof(READ_FILE_REPLY, data); ++ DList[0].rwflag = DLWRITE; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), DList, DList_Cnt, ++ (void *)&reply, &replylen, INTERRUPTIBLE); ++ ++ DbgPrint("Novfs_Read_Pages: Queue_Daemon_Command 0x%x\n", retCode); ++ ++ if (!retCode) { ++ if (reply) { ++ memcpy(&lreply, reply, sizeof(lreply)); ++ } ++ ++ if (lreply.Reply.ErrorCode) { ++ if (NWE_FILE_IO_LOCKED == lreply.Reply.ErrorCode) { ++ retCode = -EBUSY; ++ } else { ++ retCode = -EIO; ++ } ++ } ++ *Bytes = replylen - offsetof(READ_FILE_REPLY, data); ++ } ++ ++ if (reply) { ++ kfree(reply); ++ } ++ ++ DbgPrint("Novfs_Read_Pages: retCode=0x%x\n", retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Write_File(HANDLE Handle, unsigned char * Buffer, size_t * Bytes, ++ loff_t * Offset, session_t SessionId) ++{ ++ WRITE_FILE_REQUEST cmd; ++ PWRITE_FILE_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0, cmdlen; ++ size_t len; ++ ++ unsigned long boff; ++ struct page **pages; ++ struct data_list *dlist; ++ int res = 0, npage, i; ++ WRITE_FILE_REPLY lreply; ++ ++ len = *Bytes; ++ cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ ++ *Bytes = 0; ++ ++ memset(&lreply, 0, sizeof(lreply)); ++ ++ DbgPrint("Novfs_Write_File cmdlen=%ld len=%ld\n", cmdlen, len); ++ ++ if ((cmdlen + len) > MaxIoSize) { ++ len = MaxIoSize - cmdlen; ++ len = (len / PAGE_SIZE) * PAGE_SIZE; ++ } ++ cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ cmd.handle = Handle; ++ cmd.len = len; ++ cmd.offset = *Offset; ++ ++ DbgPrint("Novfs_Write_File cmdlen=%ld len=%ld\n", cmdlen, len); ++ ++ npage = ++ (((unsigned long)Buffer & ~PAGE_MASK) + len + ++ (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ ++ dlist = Novfs_Malloc(sizeof(struct data_list) * (npage + 1), GFP_KERNEL); ++ if (NULL == dlist) { ++ return (-ENOMEM); ++ } ++ ++ pages = Novfs_Malloc(sizeof(struct page *) * npage, GFP_KERNEL); ++ ++ if (NULL == pages) { ++ kfree(dlist); ++ return (-ENOMEM); ++ } ++ ++ down_read(¤t->mm->mmap_sem); ++ ++ res = get_user_pages(current, current->mm, (unsigned long)Buffer, npage, 0, /* read type */ ++ 0, /* don't force */ ++ pages, NULL); ++ ++ up_read(¤t->mm->mmap_sem); ++ ++ DbgPrint("Novfs_Write_File res=%d\n", res); ++ ++ if (res > 0) { ++ boff = (unsigned long)Buffer & ~PAGE_MASK; ++ ++ flush_dcache_page(pages[0]); ++ dlist[0].page = pages[0]; ++ dlist[0].offset = (char *)boff; ++ dlist[0].len = PAGE_SIZE - boff; ++ dlist[0].rwflag = DLREAD; ++ ++ if (dlist[0].len > len) { ++ dlist[0].len = len; ++ } ++ ++ DbgPrint("Novfs_Write_File0: page=0x%p offset=0x%p len=%d\n", ++ dlist[0].page, dlist[0].offset, dlist[0].len); ++ ++ boff = dlist[0].len; ++ ++ DbgPrint("Novfs_Write_File len=%d boff=%d\n", len, boff); ++ ++ for (i = 1; (i < res) && (boff < len); i++) { ++ flush_dcache_page(pages[i]); ++ ++ dlist[i].page = pages[i]; ++ dlist[i].offset = NULL; ++ dlist[i].len = len - boff; ++ if (dlist[i].len > PAGE_SIZE) { ++ dlist[i].len = PAGE_SIZE; ++ } ++ dlist[i].rwflag = DLREAD; ++ ++ boff += dlist[i].len; ++ DbgPrint ++ ("Novfs_Write_File%d: page=0x%p offset=0x%p len=%d\n", ++ i, dlist[i].page, dlist[i].offset, dlist[i].len); ++ } ++ ++ dlist[i].page = NULL; ++ dlist[i].offset = &lreply; ++ dlist[i].len = sizeof(lreply); ++ dlist[i].rwflag = DLWRITE; ++ res++; ++ ++ DbgPrint("Novfs_Write_File Buffer=0x%p boff=0x%x len=%d\n", ++ Buffer, boff, len); ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, cmdlen, dlist, res, ++ (void *)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ } else { ++ char *kdata; ++ ++ res = 0; ++ ++ kdata = Novfs_Malloc(len, GFP_KERNEL); ++ if (kdata) { ++ len -= copy_from_user(kdata, Buffer, len); ++ dlist[0].page = NULL; ++ dlist[0].offset = kdata; ++ dlist[0].len = len; ++ dlist[0].rwflag = DLREAD; ++ ++ dlist[1].page = NULL; ++ dlist[1].offset = &lreply; ++ dlist[1].len = sizeof(lreply); ++ dlist[1].rwflag = DLWRITE; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, cmdlen, dlist, 2, ++ (void *)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ kfree(kdata); ++ } ++ } ++ ++ DbgPrint("Novfs_Write_File retCode=0x%x reply=0x%p\n", retCode, reply); ++ ++ if (!retCode) { ++ switch (lreply.Reply.ErrorCode) { ++ case 0: ++ *Bytes = (size_t) lreply.bytesWritten; ++ retCode = 0; ++ break; ++ ++ case NWE_INSUFFICIENT_SPACE: ++ retCode = -ENOSPC; ++ break; ++ ++ case NWE_ACCESS_DENIED: ++ retCode = -EACCES; ++ break; ++ ++ default: ++ retCode = -EIO; ++ break; ++ } ++ } ++ ++ if (res) { ++ for (i = 0; i < res; i++) { ++ if (dlist[i].page) { ++ page_cache_release(dlist[i].page); ++ } ++ } ++ } ++ ++ kfree(pages); ++ kfree(dlist); ++ ++ DbgPrint("Novfs_Write_File *Bytes=0x%x retCode=0x%x\n", *Bytes, ++ retCode); ++ ++ return (retCode); ++} ++ ++/* ++ * Arguments: HANDLE Handle - novfsd file handle ++ * struct page *Page - Page to be written out ++ * session_t SessionId - novfsd session handle ++ * ++ * Returns: 0 - Success ++ * -ENOSPC - Out of space on server ++ * -EACCES - Access denied ++ * -EIO - Any other error ++ * ++ * Abstract: Write page to file. ++ */ ++int Novfs_Write_Page(HANDLE Handle, struct page *Page, session_t SessionId) ++{ ++ WRITE_FILE_REQUEST cmd; ++ WRITE_FILE_REPLY lreply; ++ PWRITE_FILE_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0, cmdlen; ++ struct data_list dlst[2]; ++ ++ DbgPrint ++ ("Novfs_Write_Page: Handle=0x%p Page=0x%p Index=%lu SessionId=0x%llx\n", ++ Handle, Page, Page->index, SessionId); ++ ++ dlst[0].page = NULL; ++ dlst[0].offset = &lreply; ++ dlst[0].len = sizeof(lreply); ++ dlst[0].rwflag = DLWRITE; ++ ++ dlst[1].page = Page; ++ dlst[1].offset = 0; ++ dlst[1].len = PAGE_CACHE_SIZE; ++ dlst[1].rwflag = DLREAD; ++ ++ cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ ++ cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.handle = Handle; ++ cmd.len = PAGE_CACHE_SIZE; ++ cmd.offset = (loff_t) Page->index << PAGE_CACHE_SHIFT;; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, cmdlen, &dlst, 2, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (!retCode) { ++ if (reply) { ++ memcpy(&lreply, reply, sizeof(lreply)); ++ } ++ switch (lreply.Reply.ErrorCode) { ++ case 0: ++ retCode = 0; ++ break; ++ ++ case NWE_INSUFFICIENT_SPACE: ++ retCode = -ENOSPC; ++ break; ++ ++ case NWE_ACCESS_DENIED: ++ retCode = -EACCES; ++ break; ++ ++ default: ++ retCode = -EIO; ++ break; ++ } ++ } ++ ++ if (reply) { ++ kfree(reply); ++ } ++ ++ DbgPrint("Novfs_Write_Page retCode=0x%x\n", retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Write_Pages(HANDLE Handle, struct data_list *DList, int DList_Cnt, ++ size_t Bytes, loff_t Offset, session_t SessionId) ++{ ++ WRITE_FILE_REQUEST cmd; ++ WRITE_FILE_REPLY lreply; ++ PWRITE_FILE_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0, cmdlen; ++ size_t len; ++ ++ DbgPrint ++ ("Novfs_Write_Pages: Handle=0x%p Dlst=0x%p Dlcnt=%d Bytes=%d Offset=%lld SessionId=0x%llx\n", ++ Handle, DList, DList_Cnt, Bytes, Offset, SessionId); ++ ++ DList[0].page = NULL; ++ DList[0].offset = &lreply; ++ DList[0].len = sizeof(lreply); ++ DList[0].rwflag = DLWRITE; ++ ++ len = Bytes; ++ cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ ++ if (len) { ++ cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.handle = Handle; ++ cmd.len = len; ++ cmd.offset = Offset; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, cmdlen, DList, DList_Cnt, ++ (void *)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (!retCode) { ++ if (reply) { ++ memcpy(&lreply, reply, sizeof(lreply)); ++ } ++ switch (lreply.Reply.ErrorCode) { ++ case 0: ++ retCode = 0; ++ break; ++ ++ case NWE_INSUFFICIENT_SPACE: ++ retCode = -ENOSPC; ++ break; ++ ++ case NWE_ACCESS_DENIED: ++ retCode = -EACCES; ++ break; ++ ++ default: ++ retCode = -EIO; ++ break; ++ } ++ } ++ if (reply) { ++ kfree(reply); ++ } ++ } ++ DbgPrint("Novfs_Write_Pages retCode=0x%x\n", retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Read_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, ++ size_t * Bytes, loff_t * Offset, int User, ++ session_t SessionId) ++{ ++ READ_STREAM_REQUEST cmd; ++ PREAD_STREAM_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0; ++ size_t len; ++ ++ len = *Bytes; ++ *Bytes = 0; ++ ++ if ((offsetof(READ_FILE_REPLY, data) + len) > MaxIoSize) { ++ len = MaxIoSize - offsetof(READ_FILE_REPLY, data); ++ len = (len / PAGE_SIZE) * PAGE_SIZE; ++ } ++ ++ cmd.Command.CommandType = VFS_COMMAND_READ_STREAM; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.connection = ConnHandle; ++ memcpy(cmd.handle, Handle, sizeof(cmd.handle)); ++ cmd.len = len; ++ cmd.offset = *Offset; ++ ++ retCode = Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, &replylen, INTERRUPTIBLE); ++ ++ DbgPrint("Novfs_Read_Stream: Queue_Daemon_Command 0x%x replylen=%d\n", retCode, replylen); ++ ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } else { ++ replylen -= offsetof(READ_STREAM_REPLY, data); ++ if (replylen > 0) { ++ if (User) ++ replylen -= copy_to_user(Buffer, reply->data, replylen); ++ else ++ memcpy(Buffer, reply->data, replylen); ++ *Bytes = replylen; ++ } ++ } ++ kfree(reply); ++ } ++ ++ DbgPrint("Novfs_Read_Stream *Bytes=0x%x retCode=0x%x\n", *Bytes, retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Write_Stream(HANDLE ConnHandle, unsigned char * Handle, unsigned char * Buffer, ++ size_t * Bytes, loff_t * Offset, session_t SessionId) ++{ ++ PWRITE_STREAM_REQUEST cmd; ++ PWRITE_STREAM_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0, cmdlen; ++ size_t len; ++ ++ len = *Bytes; ++ cmdlen = len + offsetof(WRITE_STREAM_REQUEST, data); ++ *Bytes = 0; ++ ++ if (cmdlen > MaxIoSize) { ++ cmdlen = MaxIoSize; ++ len = cmdlen - offsetof(WRITE_STREAM_REQUEST, data); ++ } ++ ++ DbgPrint("Novfs_Write_Stream cmdlen=%d len=%d\n", cmdlen, len); ++ ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ if (Buffer && len) { ++ len -= copy_from_user(cmd->data, Buffer, len); ++ } ++ ++ DbgPrint("Novfs_Write_Stream len=%d\n", len); ++ ++ cmd->Command.CommandType = VFS_COMMAND_WRITE_STREAM; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ ++ cmd->connection = ConnHandle; ++ memcpy(cmd->handle, Handle, sizeof(cmd->handle)); ++ cmd->len = len; ++ cmd->offset = *Offset; ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ switch (reply->Reply.ErrorCode) { ++ case 0: ++ retCode = 0; ++ break; ++ ++ case NWE_INSUFFICIENT_SPACE: ++ retCode = -ENOSPC; ++ break; ++ ++ case NWE_ACCESS_DENIED: ++ retCode = -EACCES; ++ break; ++ ++ default: ++ retCode = -EIO; ++ break; ++ } ++ DbgPrint ++ ("Novfs_Write_Stream reply->bytesWritten=0x%lx\n", ++ reply->bytesWritten); ++ *Bytes = reply->bytesWritten; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ DbgPrint("Novfs_Write_Stream *Bytes=0x%x retCode=0x%x\n", *Bytes, ++ retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Close_Stream(HANDLE ConnHandle, unsigned char * Handle, session_t SessionId) ++{ ++ CLOSE_STREAM_REQUEST cmd; ++ PCLOSE_STREAM_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ cmd.Command.CommandType = VFS_COMMAND_CLOSE_STREAM; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.connection = ConnHandle; ++ memcpy(cmd.handle, Handle, sizeof(cmd.handle)); ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, 0); ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ return (retCode); ++} ++ ++int Novfs_Delete(unsigned char * Path, int DirectoryFlag, session_t SessionId) ++{ ++ PDELETE_FILE_REQUEST cmd; ++ PDELETE_FILE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen, pathlen; ++ ++ pathlen = strlen(Path); ++ ++ if (StripTrailingDots) { ++ if ('.' == Path[pathlen - 1]) ++ pathlen--; ++ } ++ ++ cmdlen = offsetof(DELETE_FILE_REQUEST, path) + pathlen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_DELETE_FILE; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ ++ cmd->isDirectory = DirectoryFlag; ++ cmd->pathlength = pathlen; ++ memcpy(cmd->path, Path, pathlen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ if ((reply->Reply.ErrorCode & 0xFFFF) == 0x0006) { /* Access Denied Error */ ++ retCode = -EACCES; ++ } else { ++ retCode = -EIO; ++ } ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } else { ++ retCode = -ENOMEM; ++ } ++ return (retCode); ++} ++ ++int Novfs_Truncate_File(unsigned char * Path, int PathLen, session_t SessionId) ++{ ++ PTRUNCATE_FILE_REQUEST cmd; ++ PTRUNCATE_FILE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen; ++ ++ if (StripTrailingDots) { ++ if ('.' == Path[PathLen - 1]) ++ PathLen--; ++ } ++ cmdlen = offsetof(TRUNCATE_FILE_REQUEST, path) + PathLen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_TRUNCATE_FILE; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ ++ cmd->pathLen = PathLen; ++ memcpy(cmd->path, Path, PathLen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ if (reply->Reply.ErrorCode) { ++ retCode = -EIO; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } else { ++ retCode = -ENOMEM; ++ } ++ return (retCode); ++} ++ ++int Novfs_Truncate_File_Ex(HANDLE Handle, loff_t Offset, session_t SessionId) ++{ ++ WRITE_FILE_REQUEST cmd; ++ PWRITE_FILE_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode = 0, cmdlen; ++ ++ DbgPrint("Novfs_Truncate_File_Ex Handle=0x%p Offset=%lld\n", Handle, ++ Offset); ++ ++ cmdlen = offsetof(WRITE_FILE_REQUEST, data); ++ ++ cmd.Command.CommandType = VFS_COMMAND_WRITE_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ cmd.handle = Handle; ++ cmd.len = 0; ++ cmd.offset = Offset; ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ DbgPrint("Novfs_Truncate_File_Ex retCode=0x%x reply=0x%p\n", retCode, ++ reply); ++ ++ if (!retCode) { ++ switch (reply->Reply.ErrorCode) { ++ case 0: ++ retCode = 0; ++ break; ++ ++ case NWE_INSUFFICIENT_SPACE: ++ retCode = -ENOSPC; ++ break; ++ ++ case NWE_ACCESS_DENIED: ++ retCode = -EACCES; ++ break; ++ ++ case NWE_FILE_IO_LOCKED: ++ retCode = -EBUSY; ++ break; ++ ++ default: ++ retCode = -EIO; ++ break; ++ } ++ } ++ ++ if (reply) { ++ kfree(reply); ++ } ++ ++ DbgPrint("Novfs_Truncate_File_Ex retCode=%d\n", retCode); ++ ++ return (retCode); ++} ++ ++int Novfs_Rename_File(int DirectoryFlag, unsigned char * OldName, int OldLen, ++ unsigned char * NewName, int NewLen, session_t SessionId) ++{ ++ RENAME_FILE_REQUEST cmd; ++ PRENAME_FILE_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ DbgPrint("Novfs_Rename_File:\n" ++ " DirectoryFlag: %d\n" ++ " OldName: %.*s\n" ++ " NewName: %.*s\n" ++ " SessionId: 0x%llx\n", ++ DirectoryFlag, OldLen, OldName, NewLen, NewName, SessionId); ++ ++ cmd.Command.CommandType = VFS_COMMAND_RENAME_FILE; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = SessionId; ++ ++ cmd.directoryFlag = DirectoryFlag; ++ ++ if (StripTrailingDots) { ++ if ('.' == OldName[OldLen - 1]) ++ OldLen--; ++ if ('.' == NewName[NewLen - 1]) ++ NewLen--; ++ } ++ ++ cmd.newnameLen = NewLen; ++ memcpy(cmd.newname, NewName, NewLen); ++ ++ cmd.oldnameLen = OldLen; ++ memcpy(cmd.oldname, OldName, OldLen); ++ ++ retCode = ++ Queue_Daemon_Command(&cmd, sizeof(cmd), NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ retCode = 0; ++ if (reply->Reply.ErrorCode) { ++ retCode = -ENOENT; ++ } ++ kfree(reply); ++ } ++ return (retCode); ++} ++ ++int Novfs_Set_Attr(unsigned char * Path, struct iattr *Attr, session_t SessionId) ++{ ++ PSET_FILE_INFO_REQUEST cmd; ++ PSET_FILE_INFO_REPLY reply; ++ unsigned long replylen = 0; ++ int retCode, cmdlen, pathlen; ++ ++ pathlen = strlen(Path); ++ ++ if (StripTrailingDots) { ++ if ('.' == Path[pathlen - 1]) ++ pathlen--; ++ } ++ ++ cmdlen = offsetof(SET_FILE_INFO_REQUEST, path) + pathlen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_SET_FILE_INFO; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ cmd->fileInfo.ia_valid = Attr->ia_valid; ++ cmd->fileInfo.ia_mode = Attr->ia_mode; ++ cmd->fileInfo.ia_uid = Attr->ia_uid; ++ cmd->fileInfo.ia_gid = Attr->ia_uid; ++ cmd->fileInfo.ia_size = Attr->ia_size; ++ cmd->fileInfo.ia_atime = Attr->ia_atime.tv_sec; ++ cmd->fileInfo.ia_mtime = Attr->ia_mtime.tv_sec;; ++ cmd->fileInfo.ia_ctime = Attr->ia_ctime.tv_sec;; ++/* ++ cmd->fileInfo.ia_attr_flags = Attr->ia_attr_flags; ++*/ ++ cmd->fileInfo.ia_attr_flags = 0; ++ ++ cmd->pathlength = pathlen; ++ memcpy(cmd->path, Path, pathlen); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, (void *)&reply, ++ &replylen, INTERRUPTIBLE); ++ if (reply) { ++ switch (reply->Reply.ErrorCode) { ++ case 0: ++ retCode = 0; ++ break; ++ ++ case NWE_PARAM_INVALID: ++ retCode = -EINVAL; ++ break; ++ ++ case NWE_FILE_IO_LOCKED: ++ retCode = -EBUSY; ++ break; ++ ++ default: ++ retCode = -EIO; ++ break; ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } else { ++ retCode = -ENOMEM; ++ } ++ return (retCode); ++} ++ ++int Novfs_Get_File_Cache_Flag(unsigned char * Path, session_t SessionId) ++{ ++ PGET_CACHE_FLAG_REQUEST cmd; ++ PGET_CACHE_FLAG_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int cmdlen; ++ int retCode = 0; ++ int pathlen; ++ ++ DbgPrint("Novfs_Get_File_Cache_Flag: Path = %s\n", Path); ++ ++ if (Path && *Path) { ++ pathlen = strlen(Path); ++ if (StripTrailingDots) { ++ if ('.' == Path[pathlen - 1]) ++ pathlen--; ++ } ++ cmdlen = offsetof(GET_CACHE_FLAG_REQUEST, path) + pathlen; ++ cmd = (PGET_CACHE_FLAG_REQUEST) Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_GET_CACHE_FLAG; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ cmd->pathLen = pathlen; ++ memcpy(cmd->path, Path, cmd->pathLen); ++ ++ Queue_Daemon_Command(cmd, cmdlen, NULL, 0, ++ (void *)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ ++ if (!reply->Reply.ErrorCode) { ++ retCode = reply->CacheFlag; ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ } ++ ++ DbgPrint("Novfs_Get_File_Cache_Flag: return %d\n", retCode); ++ return (retCode); ++} ++ ++/* ++ * Arguments: ++ * SessionId, file handle, type of lock (read/write or unlock), ++ * start of lock area, length of lock area ++ * ++ * Returns: ++ * 0 on success ++ * negative value on error ++ * ++ * Abstract: ++ * ++ * Notes: lock type - fcntl ++ */ ++int Novfs_Set_File_Lock(session_t SessionId, HANDLE Handle, ++ unsigned char fl_type, loff_t fl_start, loff_t fl_len) ++{ ++ PSET_FILE_LOCK_REQUEST cmd; ++ PSET_FILE_LOCK_REPLY reply = NULL; ++ unsigned long replylen = 0; ++ int retCode; ++ ++ retCode = -1; ++ ++ DbgPrint("Novfs_Set_File_Lock:\n" ++ " SessionId: 0x%llx\n", SessionId); ++ ++ cmd = ++ (PSET_FILE_LOCK_REQUEST) Novfs_Malloc(sizeof(SET_FILE_LOCK_REQUEST), ++ GFP_KERNEL); ++ ++ if (cmd) { ++ DbgPrint("Novfs_Set_File_Lock 2\n"); ++ ++ cmd->Command.CommandType = VFS_COMMAND_SET_FILE_LOCK; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = SessionId; ++ ++ cmd->handle = Handle; ++ if (F_RDLCK == fl_type) { ++ fl_type = 1; // LockRegionExclusive ++ } else if (F_WRLCK == fl_type) { ++ fl_type = 0; // LockRegionShared ++ } ++ ++ cmd->fl_type = fl_type; ++ cmd->fl_start = fl_start; ++ cmd->fl_len = fl_len; ++ ++ DbgPrint("Novfs_Set_File_Lock 3\n"); ++ ++ DbgPrint("Novfs_Set_File_Lock: BEGIN dump arguments\n"); ++ DbgPrint("Novfs_Set_File_Lock: Queue_Daemon_Command %d\n", ++ cmd->Command.CommandType); ++ DbgPrint("Novfs_Set_File_Lock: cmd->handle = 0x%p\n", ++ cmd->handle); ++ DbgPrint("Novfs_Set_File_Lock: cmd->fl_type = %u\n", ++ cmd->fl_type); ++ DbgPrint("Novfs_Set_File_Lock: cmd->fl_start = 0x%X\n", ++ cmd->fl_start); ++ DbgPrint("Novfs_Set_File_Lock: cmd->fl_len = 0x%X\n", ++ cmd->fl_len); ++ DbgPrint ++ ("Novfs_Set_File_Lock: sizeof(SET_FILE_LOCK_REQUEST) = %u\n", ++ sizeof(SET_FILE_LOCK_REQUEST)); ++ DbgPrint("Novfs_Set_File_Lock: END dump arguments\n"); ++ ++ retCode = ++ Queue_Daemon_Command(cmd, sizeof(SET_FILE_LOCK_REQUEST), ++ NULL, 0, (void *)&reply, &replylen, ++ INTERRUPTIBLE); ++ DbgPrint("Novfs_Set_File_Lock 4\n"); ++ ++ if (reply) { ++ DbgPrint("Novfs_Set_File_Lock 5, ErrorCode = %X\n", ++ reply->Reply.ErrorCode); ++ ++ if (reply->Reply.ErrorCode) { ++ retCode = reply->Reply.ErrorCode; ++ } ++ kfree(reply); ++ } ++ ++ kfree(cmd); ++ } ++ ++ DbgPrint("Novfs_Set_File_Lock 6\n"); ++ ++ return (retCode); ++} +--- /dev/null ++++ b/fs/novfs/inode.c +@@ -0,0 +1,5563 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * This file contains functions used to control access to the Linux file ++ * system. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/*===[ Include files specific to this module ]============================*/ ++#include "vfs.h" ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++#define FSPRIVATE u.generic_ip ++#else ++#define FSPRIVATE i_private ++#endif ++ ++ ++#define FILE_UPDATE_TIMEOUT 2 ++ ++struct inode_data { ++ void *Scope; ++ unsigned long Flags; ++ struct list_head IList; ++ struct inode *Inode; ++ unsigned long cntDC; ++ struct list_head DirCache; ++ struct semaphore DirCacheLock; ++ HANDLE FileHandle; ++ int CacheFlag; ++ char Name[1]; /* Needs to be last entry */ ++}; ++ ++// FIXME these are wrong, but fake the compiler out for now until the proper people can be flogged... ++extern void *Scope_Get_ScopefromName(struct qstr *Name); ++extern void *Scope_Get_ScopefromPath(struct dentry *Dentry); ++ ++/*===[ Function prototypes ]==============================================*/ ++int Novfs_Remove_from_Root(char *RemoveName); ++int Novfs_Add_to_Root(char *); ++char *Novfs_dget_path(struct dentry *d, char *path, unsigned int pathlen); ++int verify_dentry(struct dentry *dentry, int Flags); ++int invalidate_dentry(struct dentry *parent); ++struct dentry *Novfs_d_lookup(struct dentry *Parent, struct qstr *Name); ++int Novfs_d_add(struct dentry *p, struct dentry *d, struct inode *i, int add); ++int Novfs_d_strcmp(struct qstr *s1, struct qstr *s2); ++unsigned long Novfs_internal_hash(struct qstr *name); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++int Novfs_get_sb(struct file_system_type *Fstype, int Flags, ++ const char *Dev_name, void *Data, struct vfsmount *Mnt); ++#else ++struct super_block *Novfs_get_sb(struct file_system_type *Fstype, int Flags, ++ const char *Dev_name, void *Data); ++#endif ++ ++int Novfs_fill_super(struct super_block *SB, void *Data, int Silent); ++ ++/* ++ * Declared dentry_operations ++ */ ++int Novfs_d_revalidate(struct dentry *, struct nameidata *); ++int Novfs_d_hash(struct dentry *, struct qstr *); ++int Novfs_d_compare(struct dentry *, struct qstr *, struct qstr *); ++int Novfs_d_delete(struct dentry *dentry); ++void Novfs_d_release(struct dentry *dentry); ++void Novfs_d_iput(struct dentry *dentry, struct inode *inode); ++ ++/* ++ * Declared directory operations ++ */ ++int Novfs_dir_open(struct inode *inode, struct file *file); ++int Novfs_dir_release(struct inode *inode, struct file *file); ++loff_t Novfs_dir_lseek(struct file *file, loff_t offset, int origin); ++ssize_t Novfs_dir_read(struct file *file, char *buf, size_t len, loff_t * off); ++void addtodentry(struct dentry *Parent, unsigned char *List, int Level); ++int Novfs_filldir(void *data, const char *name, int namelen, loff_t off, ++ ino_t ino, unsigned ftype); ++int Novfs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir); ++int Novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync); ++ ++/* ++ * Declared address space operations ++ */ ++int Novfs_a_writepage(struct page *page, struct writeback_control *wbc); ++int Novfs_a_writepages(struct address_space *mapping, ++ struct writeback_control *wbc); ++int Novfs_a_prepare_write(struct file *file, struct page *page, unsigned from, ++ unsigned to); ++int Novfs_a_commit_write(struct file *file, struct page *page, unsigned offset, ++ unsigned to); ++int Novfs_a_readpage(struct file *file, struct page *page); ++int Novfs_a_readpages(struct file *file, struct address_space *mapping, ++ struct list_head *page_lst, unsigned nr_pages); ++ssize_t Novfs_a_direct_IO(int rw, struct kiocb *kiocb, const struct iovec *iov, ++ loff_t offset, unsigned long nr_segs); ++ ++/* ++ * Declared file_operations ++ */ ++ssize_t Novfs_f_read(struct file *, char *, size_t, loff_t *); ++ssize_t Novfs_f_write(struct file *, const char *, size_t, loff_t *); ++int Novfs_f_readdir(struct file *, void *, filldir_t); ++int Novfs_f_ioctl(struct inode *, struct file *, unsigned int, unsigned long); ++int Novfs_f_mmap(struct file *file, struct vm_area_struct *vma); ++int Novfs_f_open(struct inode *, struct file *); ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) ++int Novfs_f_flush(struct file *); ++#else ++int Novfs_f_flush(struct file *, fl_owner_t); ++#endif ++int Novfs_f_release(struct inode *, struct file *); ++int Novfs_f_fsync(struct file *, struct dentry *, int datasync); ++int Novfs_f_lock(struct file *, int, struct file_lock *); ++ ++/* ++ * Declared inode_operations ++ */ ++int Novfs_i_create(struct inode *, struct dentry *, int, struct nameidata *); ++struct dentry *Novfs_i_lookup(struct inode *, struct dentry *, ++ struct nameidata *); ++int Novfs_i_mkdir(struct inode *, struct dentry *, int); ++int Novfs_i_unlink(struct inode *dir, struct dentry *dentry); ++int Novfs_i_rmdir(struct inode *, struct dentry *); ++int Novfs_i_mknod(struct inode *, struct dentry *, int, dev_t); ++int Novfs_i_rename(struct inode *, struct dentry *, struct inode *, ++ struct dentry *); ++int Novfs_i_permission(struct inode *inode, int mask); ++int Novfs_i_setattr(struct dentry *, struct iattr *); ++int Novfs_i_getattr(struct vfsmount *mnt, struct dentry *, struct kstat *); ++int Novfs_i_revalidate(struct dentry *dentry); ++ ++/* ++ * Extended attributes operations ++ */ ++ ++int Novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, ++ size_t size); ++int Novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, ++ size_t value_size, int flags); ++int Novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); ++ ++void update_inode(struct inode *Inode, struct entry_info *Info); ++ ++/* ++ * Declared super_operations ++ */ ++void Novfs_read_inode(struct inode *inode); ++void Novfs_write_inode(struct inode *inode); ++int Novfs_notify_change(struct dentry *dentry, struct iattr *attr); ++void Novfs_clear_inode(struct inode *inode); ++int Novfs_show_options(struct seq_file *s, struct vfsmount *m); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++int Novfs_statfs(struct dentry *de, struct kstatfs *buf); ++#else ++int Novfs_statfs(struct super_block *sb, struct kstatfs *buf); ++#endif ++ ++/* ++ * Declared control interface functions ++ */ ++ssize_t ++Novfs_Control_read(struct file *file, char *buf, size_t nbytes, loff_t * ppos); ++ ++ssize_t ++Novfs_Control_write(struct file *file, const char *buf, size_t nbytes, ++ loff_t * ppos); ++ ++int Novfs_Control_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++int __init init_novfs(void); ++void __exit exit_novfs(void); ++ ++int Novfs_lock_inode_cache(struct inode *i); ++void Novfs_unlock_inode_cache(struct inode *i); ++int Novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, ++ ino_t * ino, struct entry_info *info); ++int Novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, ++ struct entry_info *info); ++int Novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, ++ struct entry_info *info); ++int Novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, ++ struct entry_info *info, u64 * EntryTime); ++int Novfs_get_remove_entry(struct inode *i, ino_t * ino, struct entry_info *info); ++void Novfs_invalidate_inode_cache(struct inode *i); ++static struct dir_cache *Novfs_lookup_inode_cache(struct inode *i, struct qstr *name, ino_t ino); ++int Novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino); ++int Novfs_add_inode_entry(struct inode *i, struct qstr *name, ino_t ino, ++ struct entry_info *info); ++int Novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, ++ struct entry_info *info); ++void Novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino); ++void Novfs_free_invalid_entries(struct inode *i); ++void Novfs_free_inode_cache(struct inode *i); ++ ++/*===[ Global variables ]=================================================*/ ++struct dentry_operations Novfs_dentry_operations = { ++ .d_revalidate = Novfs_d_revalidate, ++ .d_hash = Novfs_d_hash, ++ .d_compare = Novfs_d_compare, ++ //.d_delete = Novfs_d_delete, ++ .d_release = Novfs_d_release, ++ .d_iput = Novfs_d_iput, ++}; ++ ++struct file_operations Novfs_dir_operations = { ++ .owner = THIS_MODULE, ++ .open = Novfs_dir_open, ++ .release = Novfs_dir_release, ++ .llseek = Novfs_dir_lseek, ++ .read = Novfs_dir_read, ++ .readdir = Novfs_dir_readdir, ++ .fsync = Novfs_dir_fsync, ++}; ++ ++static struct file_operations Novfs_file_operations = { ++ .owner = THIS_MODULE, ++ .read = Novfs_f_read, ++ .write = Novfs_f_write, ++ .readdir = Novfs_f_readdir, ++ .ioctl = Novfs_f_ioctl, ++ .mmap = Novfs_f_mmap, ++ .open = Novfs_f_open, ++ .flush = Novfs_f_flush, ++ .release = Novfs_f_release, ++ .fsync = Novfs_f_fsync, ++ .llseek = generic_file_llseek, ++ .lock = Novfs_f_lock, ++}; ++ ++static struct address_space_operations Novfs_nocache_aops = { ++ .readpage = Novfs_a_readpage, ++}; ++ ++struct backing_dev_info Novfs_backing_dev_info = { ++ .ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE, ++ .state = 0, ++ .capabilities = BDI_CAP_NO_WRITEBACK | BDI_CAP_MAP_COPY, ++ .unplug_io_fn = default_unplug_io_fn, ++}; ++ ++static struct address_space_operations Novfs_aops = { ++ .readpage = Novfs_a_readpage, ++ .readpages = Novfs_a_readpages, ++ .writepage = Novfs_a_writepage, ++ .writepages = Novfs_a_writepages, ++ .prepare_write = Novfs_a_prepare_write, ++ .commit_write = Novfs_a_commit_write, ++ .set_page_dirty = __set_page_dirty_nobuffers, ++ .direct_IO = Novfs_a_direct_IO, ++}; ++ ++static struct inode_operations Novfs_inode_operations = { ++ .create = Novfs_i_create, ++ .lookup = Novfs_i_lookup, ++ .unlink = Novfs_i_unlink, ++ .mkdir = Novfs_i_mkdir, ++ .rmdir = Novfs_i_rmdir, ++ .mknod = Novfs_i_mknod, ++ .rename = Novfs_i_rename, ++ .setattr = Novfs_i_setattr, ++ .getattr = Novfs_i_getattr, ++/* ++ .getxattr = Novfs_i_getxattr, ++ .setxattr = Novfs_i_setxattr, ++ .listxattr = Novfs_i_listxattr, ++*/ ++}; ++ ++static struct inode_operations Novfs_file_inode_operations = { ++ .setattr = Novfs_i_setattr, ++ .getattr = Novfs_i_getattr, ++/* ++ .getxattr = Novfs_i_getxattr, ++ .setxattr = Novfs_i_setxattr, ++ .listxattr = Novfs_i_listxattr, ++*/ ++}; ++ ++static struct super_operations Novfs_ops = { ++ .statfs = Novfs_statfs, ++ .clear_inode = Novfs_clear_inode, ++ .drop_inode = generic_delete_inode, ++ .show_options = Novfs_show_options, ++ ++}; ++ ++/* Not currently used ++static struct file_operations Novfs_Control_operations = { ++ .read = Novfs_Control_read, ++ .write = Novfs_Control_write, ++ .ioctl = Novfs_Control_ioctl, ++}; ++*/ ++ ++static atomic_t Novfs_Inode_Number = ATOMIC_INIT(0); ++ ++struct dentry *Novfs_root = NULL; ++ ++int Novfs_Version_Major = NOVFS_VFS_MAJOR; ++int Novfs_Version_Minor = NOVFS_VFS_MINOR; ++int Novfs_Version_Sub = NOVFS_VFS_SUB; ++int Novfs_Version_Release = NOVFS_VFS_RELEASE; ++ ++char *Novfs_CurrentMount = NULL; ++ ++DECLARE_MUTEX(InodeList_lock); ++ ++LIST_HEAD(InodeList); ++ ++DECLARE_MUTEX(TimeDir_Lock); ++uint64_t lastTime; ++char lastDir[PATH_MAX]; ++ ++uint64_t inHAXTime; ++int inHAX; ++ ++unsigned long InodeCount = 0, DCCount = 0; ++unsigned long File_update_timeout = FILE_UPDATE_TIMEOUT; ++int PageCache = 0; ++ ++typedef struct _Novfs_List2 { ++ struct list_head list; ++ void *data; ++} Novfs_List2; ++ ++typedef struct _File_Private2 { ++ int listedall; ++ HANDLE enumHandle; ++} FilePrivate2; ++ ++static void PRINT_DENTRY(const char *s, struct dentry *d) ++{ ++ DbgPrint("%s: 0x%p\n", s, d); ++ DbgPrint(" d_count: 0x%x\n", d->d_count); ++ DbgPrint(" d_lock: 0x%x\n", d->d_lock); ++ DbgPrint(" d_inode: 0x%x\n", d->d_inode); ++ DbgPrint(" d_lru: 0x%p\n" ++ " next: 0x%p\n" ++ " prev: 0x%p\n", &d->d_lru, d->d_lru.next, ++ d->d_lru.prev); ++ DbgPrint(" d_child: 0x%p\n" " next: 0x%p\n" ++ " prev: 0x%p\n", &d->D_CHILD, d->D_CHILD.next, ++ d->D_CHILD.prev); ++ DbgPrint(" d_subdirs: 0x%p\n" " next: 0x%p\n" ++ " prev: 0x%p\n", &d->d_subdirs, d->d_subdirs.next, ++ d->d_subdirs.prev); ++ DbgPrint(" d_alias: 0x%p\n" " next: 0x%p\n" ++ " prev: 0x%p\n", &d->d_alias, d->d_alias.next, ++ d->d_alias.prev); ++ DbgPrint(" d_time: 0x%x\n", d->d_time); ++ DbgPrint(" d_op: 0x%p\n", d->d_op); ++ DbgPrint(" d_sb: 0x%p\n", d->d_sb); ++ DbgPrint(" d_flags: 0x%x\n", d->d_flags); ++ DbgPrint(" d_mounted: 0x%x\n", d->d_mounted); ++ DbgPrint(" d_fsdata: 0x%p\n", d->d_fsdata); ++/* DbgPrint(" d_cookie: 0x%x\n", d->d_cookie); */ ++ DbgPrint(" d_parent: 0x%p\n", d->d_parent); ++ DbgPrint(" d_name: 0x%p %.*s\n", &d->d_name, d->d_name.len, ++ d->d_name.name); ++ DbgPrint(" name: 0x%p\n" " len: %d\n" ++ " hash: 0x%x\n", d->d_name.name, d->d_name.len, ++ d->d_name.hash); ++ DbgPrint(" d_hash: 0x%x\n" " next: 0x%x\n" ++ " pprev: 0x%x\n", d->d_hash, d->d_hash.next, ++ d->d_hash.pprev); ++} ++ ++/*++======================================================================*/ ++int Novfs_Remove_from_Root(char *RemoveName) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct qstr name; ++ struct dentry *dentry; ++ struct inode *dir; ++ ++ DbgPrint("Novfs_Remove_from_Root: %s\n", RemoveName); ++ name.len = strlen(RemoveName); ++ name.name = RemoveName; ++ Novfs_d_hash(Novfs_root, &name); ++ ++ dentry = d_lookup(Novfs_root, &name); ++ if (dentry) { ++ if (dentry->d_inode && dentry->d_inode->FSPRIVATE) { ++ ((struct inode_data *)(dentry->d_inode->FSPRIVATE))->Scope = ++ NULL; ++ } ++ dput(dentry); ++ } ++ ++ dir = Novfs_root->d_inode; ++ ++ Novfs_lock_inode_cache(dir); ++ Novfs_remove_inode_entry(dir, &name, 0); ++ Novfs_unlock_inode_cache(dir); ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++int Novfs_Add_to_Root(char *AddName) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct qstr name; ++ struct inode *dir; ++ struct entry_info info; ++ ino_t ino; ++ ++ DbgPrint("Novfs_Add_to_Root: %s\n", AddName); ++ name.len = strlen(AddName); ++ name.name = AddName; ++ Novfs_d_hash(Novfs_root, &name); ++ ++ dir = Novfs_root->d_inode; ++ ++ Novfs_lock_inode_cache(dir); ++ ++ ino = 0; ++ ++ if (!Novfs_lookup_inode_cache(dir, &name, 0)) { ++ info.mode = S_IFDIR | 0700; ++ info.size = 0; ++ info.atime = info.ctime = info.mtime = CURRENT_TIME; ++ ++ ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ Novfs_add_inode_entry(dir, &name, ino, &info); ++ } ++ ++ Novfs_unlock_inode_cache(dir); ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++int Novfs_Add_to_Root2(char *AddName) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct dentry *entry; ++ struct qstr name; ++ struct inode *inode; ++ void *scope; ++ ++ DbgPrint("Novfs_Add_to_Root: %s\n", AddName); ++ name.len = strlen(AddName); ++ name.name = AddName; ++ ++ Novfs_d_hash(Novfs_root, &name); ++ ++ entry = Novfs_d_lookup(Novfs_root, &name); ++ DbgPrint("Novfs_Add_to_Root: Novfs_d_lookup 0x%p\n", entry); ++ if (NULL == entry) { ++ scope = Scope_Lookup(); ++ ++ entry = d_alloc(Novfs_root, &name); ++ DbgPrint("Novfs_Add_to_Root: d_alloc 0x%p\n", entry); ++ if (entry) { ++ entry->d_op = &Novfs_dentry_operations; ++ entry->d_time = jiffies + (File_update_timeout * HZ); ++ /* ++ * done in Novfs_d_add now... entry->d_fsdata = (void *)Novfs_internal_hash( &name ); ++ */ ++ inode = ++ Novfs_get_inode(Novfs_root->d_sb, S_IFDIR | 0700, 0, Scope_Get_Uid(scope), 0, &name); ++ DbgPrint("Novfs_Add_to_Root: Inode=0x%p\n", inode); ++ if (inode) { ++ inode->i_atime = ++ inode->i_ctime = ++ inode->i_mtime = CURRENT_TIME; ++ if (!Novfs_d_add(Novfs_root, entry, inode, 1)) { ++ if (inode->FSPRIVATE) { ++ ((struct inode_data *) inode-> ++ FSPRIVATE)->Flags = USER_INODE; ++ } ++ PRINT_DENTRY("After Novfs_d_add", ++ entry); ++ } else { ++ dput(entry); ++ iput(inode); ++ } ++ } ++ } ++ } else { ++ dput(entry); ++ PRINT_DENTRY("Novfs_Add_to_Root: After dput Dentry", entry); ++ } ++ return (0); ++} ++ ++/*++======================================================================*/ ++char *Novfs_dget_path(struct dentry *Dentry, char *Buf, unsigned int Buflen) ++/* ++ * Arguments: struct dentry *Dentry - starting entry ++ * char *Buf - pointer to memory buffer ++ * unsigned int Buflen - size of memory buffer ++ * ++ * Returns: pointer to path. ++ * ++ * Abstract: Walks the dentry chain building a path. ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ char *retval = &Buf[Buflen]; ++ struct dentry *p = Dentry; ++ ++ *(--retval) = '\0'; ++ Buflen--; ++ ++ if (!IS_ROOT(p) && !IS_ROOT(p->d_parent)) { ++ while (Buflen && !IS_ROOT(p) && !IS_ROOT(p->d_parent)) { ++ if (Buflen > p->d_name.len) { ++ retval -= p->d_name.len; ++ Buflen -= p->d_name.len; ++ memcpy(retval, p->d_name.name, p->d_name.len); ++ *(--retval) = '\\'; ++ Buflen--; ++ p = p->d_parent; ++ } else { ++ retval = NULL; ++ break; ++ } ++ } ++ } else { ++ *(--retval) = '\\'; ++ } ++ ++ if (retval) ++ DbgPrint("Novfs_dget_path: %s\n", retval); ++ return (retval); ++} ++ ++/*++======================================================================*/ ++int verify_dentry(struct dentry *dentry, int Flags) ++/* ++ * Arguments: struct dentry *dentry - entry to verify ++ * ++ * Returns: zero - Inode cache has been updated. If not in the cache ++ * then file doesn't exist. ++ * !zero - Error ++ * ++ * Abstract: This routine will verify if the file that dentry is pointing ++ * at exist and if it does it will put it in the inode cache of ++ * the parent. ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retVal = -ENOENT; ++ struct inode *dir; ++ struct entry_info *info = NULL; ++ struct inode_data *id; ++ session_t session; ++ char *path, *list = NULL, *cp; ++ ino_t ino = 0; ++ struct qstr name; ++ int iLock = 0; ++ struct dentry *parent = NULL; ++ u64 ctime; ++ struct inode *inode; ++ ++ if (IS_ROOT(dentry)) { ++ DbgPrint("verify_dentry: Root entry\n"); ++ return (0); ++ } ++ ++ if (dentry && dentry->d_parent && ++ (dir = dentry->d_parent->d_inode) && (id = dir->FSPRIVATE)) { ++ parent = dget_parent(dentry); ++ ++ info = Novfs_Malloc(sizeof(struct entry_info) + PATH_LENGTH_BUFFER, GFP_KERNEL); ++ ++ if (info) { ++ if (Novfs_lock_inode_cache(dir)) { ++ name.len = dentry->d_name.len; ++ name.name = dentry->d_name.name; ++ name.hash = Novfs_internal_hash(&name); ++ if (!Novfs_get_entry_time(dir, &name, &ino, info, &ctime)) { ++ inode = dentry->d_inode; ++ if (inode && inode->FSPRIVATE && ++ ((inode->i_size != info->size) || ++ (inode->i_mtime.tv_sec != ++ info->mtime.tv_sec) ++ || (inode->i_mtime.tv_nsec != ++ info->mtime.tv_nsec))) { ++ /* ++ * Values don't match so update. ++ */ ++ ((struct inode_data *) inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ } ++ ++ ctime = get_jiffies_64() - ctime; ++ if (Flags || ctime < (u64) (File_update_timeout * HZ)) { ++ retVal = 0; ++ Novfs_unlock_inode_cache(dir); ++ dput(parent); ++ kfree(info); ++ return (0); ++ } ++ } ++ Novfs_unlock_inode_cache(dir); ++ } ++ ++ if (IS_ROOT(dentry->d_parent)) { ++ session = Scope_Get_SessionId(Scope_Get_ScopefromName(&dentry->d_name)); ++ } else { ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ if (!SC_PRESENT(session)) { ++ id->Scope = Scope_Get_ScopefromPath(dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ ino = 0; ++ retVal = 0; ++ ++ if (IS_ROOT(dentry->d_parent)) { ++ DbgPrint("verify_dentry: parent is Root directory\n"); ++ list = Scope_Get_ScopeUsers(); ++ ++ iLock = Novfs_lock_inode_cache(dir); ++ Novfs_invalidate_inode_cache(dir); ++ ++ if (list) { ++ cp = list; ++ while (*cp) { ++ name.name = cp; ++ name.len = strlen(cp); ++ name.hash = Novfs_internal_hash(&name); ++ cp += (name.len + 1); ++ ino = 0; ++ if (Novfs_get_entry(dir, &name, &ino, info)) { ++ info->mode = S_IFDIR | 0700; ++ info->size = 0; ++ info->atime = info->ctime = info->mtime = CURRENT_TIME; ++ ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ Novfs_add_inode_entry(dir, &name, ino, info); ++ } ++ } ++ } ++ Novfs_free_invalid_entries(dir); ++ } else { ++ ++ path = ++ Novfs_dget_path(dentry, info->name, ++ PATH_LENGTH_BUFFER); ++ if (path) { ++ if (dentry->d_name.len <= ++ NW_MAX_PATH_LENGTH) { ++ name.hash = ++ Novfs_internal_hash ++ (&dentry->d_name); ++ name.len = dentry->d_name.len; ++ name.name = dentry->d_name.name; ++ ++ retVal = Novfs_Get_File_Info(path, info, &session); ++ if (0 == retVal) { ++ dentry->d_time = ++ jiffies + ++ (File_update_timeout ++ * HZ); ++ iLock = ++ Novfs_lock_inode_cache ++ (dir); ++ if (Novfs_update_entry ++ (dir, &name, 0, ++ info)) { ++ if (dentry-> ++ d_inode) { ++ ino = dentry->d_inode->i_ino; ++ } else { ++ ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ } ++ Novfs_add_inode_entry ++ (dir, &name, ++ ino, info); ++ } ++ if (dentry->d_inode) { ++ update_inode ++ (dentry-> ++ d_inode, ++ info); ++ id->Flags &= ++ ~UPDATE_INODE; ++ ++ dentry-> ++ d_inode-> ++ i_flags &= ++ ~S_DEAD; ++ if (dentry-> ++ d_inode-> ++ FSPRIVATE) { ++ ((struct inode_data *) dentry->d_inode->FSPRIVATE)->Scope = id->Scope; ++ } ++ } ++ } else if (-EINTR != retVal) { ++ retVal = 0; ++ iLock = Novfs_lock_inode_cache(dir); ++ Novfs_remove_inode_entry(dir, &name, 0); ++ if (dentry->d_inode ++ && !(dentry->d_inode->i_flags & S_DEAD)) { ++ dentry->d_inode->i_flags |= S_DEAD; ++ dentry->d_inode-> i_size = 0; ++ dentry->d_inode->i_atime.tv_sec = ++ dentry->d_inode->i_atime.tv_nsec = ++ dentry->d_inode->i_ctime.tv_sec = ++ dentry->d_inode->i_ctime.tv_nsec = ++ dentry->d_inode->i_mtime.tv_sec = ++ dentry->d_inode->i_mtime.tv_nsec = 0; ++ dentry->d_inode->i_blocks = 0; ++ d_delete(dentry); /* Remove from cache */ ++ } ++ } ++ } else { ++ retVal = -ENAMETOOLONG; ++ } ++ } ++ } ++ } else { ++ retVal = -ENOMEM; ++ } ++ if (iLock) { ++ Novfs_unlock_inode_cache(dir); ++ } ++ dput(parent); ++ } ++ ++ if (list) ++ kfree(list); ++ if (info) ++ kfree(info); ++ ++ DbgPrint("verify_dentry: return=0x%x\n", retVal); ++ ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++struct dentry *Novfs_d_lookup(struct dentry *Parent, struct qstr *Name) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ return (d_lookup(Parent, Name)); ++} ++ ++/*++======================================================================*/ ++int Novfs_d_add(struct dentry *Parent, struct dentry *d, struct inode *i, int a) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ void *scope; ++ struct inode_data *id = NULL; ++ ++ char *path, *buf; ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(d, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ DbgPrint("Novfs_d_add: inode=0x%p ino=%d path %s\n", i, ++ i->i_ino, path); ++ } ++ kfree(buf); ++ } ++ ++ if (Parent && Parent->d_inode && Parent->d_inode->FSPRIVATE) { ++ id = (struct inode_data *) Parent->d_inode->FSPRIVATE; ++ } ++ ++ if (id && id->Scope) { ++ scope = id->Scope; ++ } else { ++ scope = Scope_Get_ScopefromPath(d); ++ } ++ ++ ((struct inode_data *) i->FSPRIVATE)->Scope = scope; ++ ++ d->d_time = jiffies + (File_update_timeout * HZ); ++ if (a) { ++ d_add(d, i); ++ } else { ++ d_instantiate(d, i); ++ } ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++int Novfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) ++/* ++ * Arguments: struct dentry *dentry - pointer to dentry to revalidate. ++ * struct nameidata *nd - pointer to nameidata. ++ * ++ * Returns: zero - dentry is not valid. ++ * !zero - valid entry ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ struct inode *dir; ++ struct inode_data *id; ++ struct qstr name; ++ ++ DbgPrint("Novfs_d_revalidate: 0x%p %.*s\n" ++ " d_count: %d\n" ++ " d_inode: 0x%p\n", ++ dentry, dentry->d_name.len, dentry->d_name.name, ++ dentry->d_count, dentry->d_inode); ++ ++ if (IS_ROOT(dentry)) { ++ retCode = 1; ++ } else { ++ if (dentry->d_inode && ++ dentry->d_parent && ++ (dir = dentry->d_parent->d_inode) && ++ (id = dir->FSPRIVATE)) { ++ /* ++ * Check timer to see if in valid time limit ++ */ ++ if (jiffies > dentry->d_time) { ++ /* ++ * Revalidate entry ++ */ ++ name.len = dentry->d_name.len; ++ name.name = dentry->d_name.name; ++ name.hash = ++ Novfs_internal_hash(&dentry->d_name); ++ dentry->d_time = 0; ++ ++ if (0 == verify_dentry(dentry, 0)) { ++ if (Novfs_lock_inode_cache(dir)) { ++ if (Novfs_lookup_inode_cache ++ (dir, &name, 0)) { ++ dentry->d_time = ++ jiffies + ++ (File_update_timeout ++ * HZ); ++ retCode = 1; ++ } ++ Novfs_unlock_inode_cache(dir); ++ } ++ } ++ } else { ++ retCode = 1; ++ } ++ } ++ } ++ ++ if ((0 == retCode) && dentry->d_inode) { ++ /* ++ * Entry has become invalid ++ */ ++/* dput(dentry); ++*/ ++ } ++ ++ DbgPrint("Novfs_d_revalidate: return 0x%x %.*s\n", retCode, ++ dentry->d_name.len, dentry->d_name.name); ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++unsigned long Novfs_internal_hash(struct qstr *name) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ unsigned long hash = 0; ++ unsigned int len = name->len; ++ unsigned char *c = (unsigned char *)name->name; ++ ++ while (len--) { ++ /* ++ * Lower case values for the hash. ++ */ ++ hash = partial_name_hash(tolower(*c++), hash); ++ } ++ ++ return (hash); ++} ++ ++/*++======================================================================*/ ++int Novfs_d_hash(struct dentry *dentry, struct qstr *name) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint("Novfs_d_hash: %.*s\n", name->len, name->name); ++ ++ name->hash = Novfs_internal_hash(name); ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++int Novfs_d_strcmp(struct qstr *s1, struct qstr *s2) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 1; ++ unsigned char *str1, *str2; ++ unsigned int len; ++ ++ DbgPrint("Novfs_d_strcmp: s1=%.*s s2=%.*s\n", s1->len, s1->name, ++ s2->len, s2->name); ++ ++ if (s1->len && (s1->len == s2->len) && (s1->hash == s2->hash)) { ++ len = s1->len; ++ str1 = (unsigned char *)s1->name; ++ str2 = (unsigned char *)s2->name; ++ for (retCode = 0; len--; str1++, str2++) { ++ if (*str1 != *str2) { ++ if (tolower(*str1) != tolower(*str2)) { ++ retCode = 1; ++ break; ++ } ++ } ++ } ++ } ++ ++ DbgPrint("Novfs_d_strcmp: retCode=0x%x\n", retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_d_compare(struct dentry *parent, struct qstr *s1, struct qstr *s2) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode; ++ ++ retCode = Novfs_d_strcmp(s1, s2); ++ ++ DbgPrint("Novfs_d_compare: retCode=0x%x\n", retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_d_delete(struct dentry *dentry) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retVal = 0; ++ ++ DbgPrint("Novfs_d_delete: 0x%p %.*s\n" ++ " d_count: %d\n" ++ " d_inode: 0x%p\n", ++ dentry, dentry->d_name.len, dentry->d_name.name, ++ dentry->d_count, dentry->d_inode); ++ ++ if (dentry->d_inode && (dentry->d_inode->i_flags & S_DEAD)) { ++ retVal = 1; ++ } ++ ++ dentry->d_time = 0; ++ ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++void Novfs_d_release(struct dentry *dentry) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint("Novfs_d_release: 0x%p %.*s\n", dentry, dentry->d_name.len, ++ dentry->d_name.name); ++} ++ ++/*++======================================================================*/ ++void Novfs_d_iput(struct dentry *dentry, struct inode *inode) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint ++ ("Novfs_d_iput: Inode=0x%p Ino=%d Dentry=0x%p i_state=%d Name=%.*s\n", ++ inode, inode->i_ino, dentry, inode->i_state, dentry->d_name.len, ++ dentry->d_name.name); ++ ++ iput(inode); ++ ++} ++ ++/*++======================================================================*/ ++int Novfs_dir_open(struct inode *dir, struct file *file) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ char *path, *buf; ++ FilePrivate2 *file_private = NULL; ++ ++ DbgPrint("Novfs_dir_open: Inode 0x%p %d Name %.*s\n", dir, dir->i_ino, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name); ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ DbgPrint("Novfs_dir_open: path %s\n", path); ++ } ++ kfree(buf); ++ } ++ ++ file_private = Novfs_Malloc(sizeof(FilePrivate2), GFP_KERNEL); ++ file_private->listedall = 0; ++ file_private->enumHandle = NULL; ++ ++ file->private_data = file_private; ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++int Novfs_dir_release(struct inode *dir, struct file *file) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ FilePrivate2 *file_private; ++ file_private = (FilePrivate2 *) file->private_data; ++ ++ DbgPrint("Novfs_dir_release: Inode 0x%p %d Name %.*s\n", dir, ++ dir->i_ino, file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ ++ if (file_private) { ++ kfree(file_private); ++ file->private_data = NULL; ++ } ++ ++ return (0); ++} ++ ++/*++======================================================================*/ ++loff_t Novfs_dir_lseek(struct file * file, loff_t offset, int origin) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ FilePrivate2 *file_private = NULL; ++ ++ DbgPrint("Novfs_dir_lseek: offset %lld %d Name %.*s\n", offset, origin, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name); ++ //printk("<1> seekdir file = %.*s offset = %i\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name, (int)offset); ++ ++ if (0 != offset) { ++ return -ESPIPE; ++ } ++ ++ file->f_pos = 0; ++ ++ file_private = (FilePrivate2 *) file->private_data; ++ file_private->listedall = 0; ++ file_private->enumHandle = NULL; ++ ++ return 0; ++ //return(default_llseek(file, offset, origin)); ++} ++ ++/*++======================================================================*/ ++ssize_t Novfs_dir_read(struct file * file, char *buf, size_t len, loff_t * off) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++/* ++ int rlen = 0; ++ ++ DbgPrint("Novfs_dir_readdir: dentry path %.*s buf=0x%p len=%d off=%lld\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name, buf, len, *off); ++ ++ if (0 == *off) ++ { ++ rlen = 8; ++ rlen -= copy_to_user(buf, "Testing\n", 8); ++ *off += rlen; ++ } ++ return(rlen); ++*/ ++ DbgPrint("Novfs_dir_read: %lld %d Name %.*s\n", *off, len, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name); ++ return (generic_read_dir(file, buf, len, off)); ++} ++ ++static void Novfs_Dump_Info(struct entry_info *info) ++{ ++ char atime_buf[32], mtime_buf[32], ctime_buf[32]; ++ char namebuf[512]; ++ int len = 0; ++ ++ if (info == NULL) { ++ DbgPrint("Novfs_dir_readdir : Dump_Info info == NULL\n"); ++ return; ++ } ++ ++ if (info->namelength >= 512) { ++ len = 511; ++ } else { ++ len = info->namelength; ++ } ++ ++ memcpy(namebuf, info->name, len); ++ namebuf[len] = '\0'; ++ ++ ctime_r(&info->atime.tv_sec, atime_buf); ++ ctime_r(&info->mtime.tv_sec, mtime_buf); ++ ctime_r(&info->ctime.tv_sec, ctime_buf); ++ DbgPrint("Novfs_dir_readdir : type = %i\n", info->type); ++ DbgPrint("Novfs_dir_readdir : mode = %x\n", info->mode); ++ DbgPrint("Novfs_dir_readdir : uid = %d\n", info->uid); ++ DbgPrint("Novfs_dir_readdir : gid = %d\n", info->gid); ++ DbgPrint("Novfs_dir_readdir : size = %i\n", info->size); ++ DbgPrint("Novfs_dir_readdir : atime = %s\n", atime_buf); ++ DbgPrint("Novfs_dir_readdir : mtime = %s\n", mtime_buf); ++ DbgPrint("Novfs_dir_readdir : ctime = %s\n", ctime_buf); ++ DbgPrint("Novfs_dir_readdir : namelength = %i\n", info->namelength); ++ DbgPrint("Novfs_dir_readdir : name = %s\n", namebuf); ++} ++ ++/*++======================================================================*/ ++void processList(struct file *file, void *dirent, filldir_t filldir, char *list, ++ int type, session_t SessionId) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ unsigned char *path, *buf = NULL, *cp; ++ struct qstr name; ++ struct entry_info *pinfo = NULL; ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ path = buf; ++ if (buf) { ++ path = Novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ strcpy(buf, path); ++ } ++ path = buf + strlen(buf); ++ *path++ = '\\'; ++ } ++ ++ if (list) { ++ cp = list; ++ while (*cp) { ++ name.name = cp; ++ DbgPrint("Novfs_dir_readdir : name.name = %s\n", ++ name.name); ++ name.len = strlen(cp); ++ name.hash = Novfs_internal_hash(&name); ++ cp += (name.len + 1); ++ ++ pinfo = ++ Novfs_Malloc(sizeof(struct entry_info) + ++ PATH_LENGTH_BUFFER, GFP_KERNEL); ++ pinfo->mode = S_IFDIR | 0700; ++ pinfo->size = 0; ++ pinfo->atime = pinfo->ctime = pinfo->mtime = ++ CURRENT_TIME; ++ strcpy(pinfo->name, name.name); ++ pinfo->namelength = name.len; ++ ++ Novfs_Dump_Info(pinfo); ++ ++ filldir(dirent, pinfo->name, pinfo->namelength, ++ file->f_pos, file->f_pos, pinfo->mode >> 12); ++ file->f_pos += 1; ++ ++ kfree(pinfo); ++ } ++ } ++ ++ if (buf) { ++ kfree(buf); ++ } ++} ++ ++int processEntries(struct file *file, void *dirent, filldir_t filldir, ++ HANDLE * enumHandle, session_t sessionId) ++{ ++ unsigned char *path = NULL, *buf = NULL; ++ int count = 0, status = 0; ++ struct entry_info *pinfo = NULL; ++ struct entry_info *pInfoMem = NULL; ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (!buf) { ++ return -ENOMEM; ++ } ++ ++ path = Novfs_dget_path(file->f_dentry, buf, PATH_LENGTH_BUFFER); ++ if (!path) { ++ kfree(buf); ++ return -ENOMEM; ++ } ++ //NWSearchfiles ++ count = 0; ++ status = Novfs_Get_Directory_ListEx(path, enumHandle, &count, &pinfo, &sessionId); ++ pInfoMem = pinfo; ++ ++ if ((count == -1) || (count == 0) || (status != 0)) { ++ kfree(pInfoMem); ++ kfree(buf); ++ return -1; ++ } ++ // parse resultset ++ while (pinfo && count--) { ++ filldir(dirent, pinfo->name, pinfo->namelength, file->f_pos, ++ file->f_pos, pinfo->mode >> 12); ++ file->f_pos += 1; ++ ++ pinfo = (struct entry_info *)(pinfo->name + pinfo->namelength); ++ } ++ ++ kfree(pInfoMem); ++ kfree(buf); ++ return 0; ++} ++ ++/*++======================================================================*/ ++int Novfs_dir_readdir(struct file *file, void *dirent, filldir_t filldir) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ unsigned char *list = NULL; ++ int status = 0; //-ENOMEM; ++ struct inode *inode = file->f_dentry->d_inode; ++ session_t sessionId; ++ uid_t uid; ++ int type = 0; ++ FilePrivate2 *file_private = NULL; ++ int lComm; ++ ++ file_private = (FilePrivate2 *) file->private_data; ++ DbgPrint("Novfs_dir_readdir: Name %.*s\n", file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ ++ //printk("<1> file = %.*s\n", file->f_dentry->d_name.len, file->f_dentry->d_name.name); ++ ++// Use this hack by default ++#ifndef SKIP_CROSSOVER_HACK ++ // Hack for crossover - begin ++ down(&TimeDir_Lock); ++ if ((file->f_dentry->d_name.len == 7) && ++ ((0 == strncmp(file->f_dentry->d_name.name, " !xover", 7)) || ++ (0 == strncmp(file->f_dentry->d_name.name, "z!xover", 7)))) { ++ //printk("<1> xoverhack: we are in xoverHack\n"); ++ ++ inHAX = 1; ++ inHAXTime = get_nanosecond_time(); ++ //up( &TimeDir_Lock ); ++ //return 0; ++ file_private->listedall = 1; ++ } else { ++ if (inHAX) { ++ if (get_nanosecond_time() - inHAXTime > ++ 100 * 1000 * 1000) { ++ //printk("<1> xoverhack: it was long, long, long ago...\n"); ++ inHAX = 0; ++ } else { ++ //printk("<1> xoverhack: word gotcha in xoverHack...\n"); ++ inHAXTime = get_nanosecond_time(); ++ //up( &TimeDir_Lock ); ++ //return 0; ++ file_private->listedall = 1; ++ } ++ } ++ } ++ ++ up(&TimeDir_Lock); ++ // Hack for crossover - end ++#endif ++ ++ if (file->f_pos == 0) { ++ if (filldir(dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR) < ++ 0) ++ return 1; ++ file->f_pos++; ++ return 1; ++ } ++ ++ if (file->f_pos == 1) { ++ if (filldir ++ (dirent, "..", 2, file->f_pos, ++ file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) ++ return 1; ++ file->f_pos++; ++ return 1; ++ } ++ ++ if (file_private->listedall != 0) { ++ return 0; ++ } ++ ++ inode = file->f_dentry->d_inode; ++ if (inode && inode->FSPRIVATE) { ++ sessionId = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)-> Scope); ++ if (0 == SC_PRESENT(sessionId)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ sessionId = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ } ++ uid = Scope_Get_Uid(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ } else { ++ SC_INITIALIZE(sessionId); ++ uid = current->euid; ++ } ++ ++ if (IS_ROOT(file->f_dentry) || // Root ++ IS_ROOT(file->f_dentry->d_parent) || // User ++ IS_ROOT(file->f_dentry->d_parent->d_parent)) // Server ++ { ++ if (IS_ROOT(file->f_dentry)) { ++ DbgPrint("Novfs_dir_readdir: Root directory\n"); ++ list = Scope_Get_ScopeUsers(); ++ type = USER_LIST; ++ } else if (IS_ROOT(file->f_dentry->d_parent)) { ++ DbgPrint ++ ("Novfs_dir_readdir: Parent is Root directory\n"); ++ Novfs_Get_Connected_Server_List(&list, &sessionId); ++ type = SERVER_LIST; ++ } else { ++ DbgPrint ++ ("Novfs_dir_readdir: Parent-Parent is Root directory\n"); ++ Novfs_Get_Server_Volume_List(&file->f_dentry->d_name, ++ &list, &sessionId); ++ type = VOLUME_LIST; ++ } ++ ++ processList(file, dirent, filldir, list, type, sessionId); ++ file_private->listedall = 1; ++ } else { ++ status = ++ processEntries(file, dirent, filldir, ++ &file_private->enumHandle, sessionId); ++ ++ if (status != 0) { ++ file_private->listedall = 1; ++#ifndef SKIP_CROSSOVER_HACK ++ // Hack for crossover part 2 - begin ++ lComm = strlen(current->comm); ++ if ((lComm > 4) ++ && (0 == ++ strcmp(current->comm + lComm - 4, ".EXE"))) { ++ if (filldir ++ (dirent, " !xover", 7, file->f_pos, ++ inode->i_ino, DT_DIR) < 0) ++ return 1; ++ if (filldir ++ (dirent, "z!xover", 7, file->f_pos, ++ inode->i_ino, DT_DIR) < 0) ++ return 1; ++ file->f_pos += 2; ++ } ++ // Hack for crossover part2 - end ++#endif ++ } ++ } ++ ++ file->private_data = file_private; ++ return 1; ++} ++ ++/*++======================================================================*/ ++int Novfs_dir_fsync(struct file *file, struct dentry *dentry, int datasync) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint("Novfs_dir_fsync: Name %.*s\n", file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ return (simple_sync_file(file, dentry, datasync)); ++} ++ ++/*++======================================================================*/ ++ssize_t Novfs_f_read(struct file * file, char *buf, size_t len, loff_t * off) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ size_t thisread, totalread = 0; ++ loff_t offset = *off; ++ struct inode *inode; ++ session_t session; ++ struct inode_data *id; ++ ++ if (file->f_dentry && ++ (inode = file->f_dentry->d_inode) && ++ (id = (struct inode_data *)inode->FSPRIVATE)) { ++ ++ DbgPrint("Novfs_f_read(0x%p 0x%p %d %lld %.*s)\n", ++ file->private_data, ++ buf, len, offset, ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ ++ if (PageCache && !(file->f_flags & O_DIRECT) && id->CacheFlag) { ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++ totalread = generic_file_read(file, buf, len, off); ++#else ++ totalread = do_sync_read(file, buf, len, off); ++#endif ++ } else { ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ while (len > 0 && (offset < i_size_read(inode))) { ++ int retval; ++ thisread = len; ++ retval = ++ Novfs_Read_File(file->private_data, buf, ++ &thisread, &offset, ++ session); ++ if (retval || !thisread) { ++ if (retval) { ++ totalread = retval; ++ } ++ break; ++ } ++ DbgPrint("Novfs_f_read thisread = 0x%x\n", ++ thisread); ++ len -= thisread; ++ buf += thisread; ++ offset += thisread; ++ totalread += thisread; ++ } ++ *off = offset; ++ } ++ } ++ DbgPrint("Novfs_f_read return = %d\n", totalread); ++ ++ return (totalread); ++} ++ ++/*++======================================================================*/ ++ssize_t Novfs_f_write(struct file * file, const char *buf, size_t len, ++ loff_t * off) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ ssize_t thiswrite, totalwrite = 0; ++ loff_t offset = *off; ++ session_t session; ++ struct inode *inode; ++ int status; ++ struct inode_data *id; ++ ++ if (file->f_dentry && ++ (inode = file->f_dentry->d_inode) && ++ (id = file->f_dentry->d_inode->FSPRIVATE)) { ++ DbgPrint("Novfs_f_write(0x%p 0x%p 0x%p %d %lld %.*s)\n", ++ file->private_data, inode, id->FileHandle, len, offset, ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ ++ if (PageCache && ++ !(file->f_flags & O_DIRECT) && ++ id->CacheFlag && !(file->f_flags & O_WRONLY)) { ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++ totalwrite = generic_file_write(file, buf, len, off); ++#else ++ totalwrite = do_sync_write(file, buf, len, off); ++#endif ++ } else { ++ if (file->f_flags & O_APPEND) { ++ offset = i_size_read(inode); ++ DbgPrint ++ ("Novfs_f_write appending to end %lld %.*s\n", ++ offset, file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ } ++ ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ while (len > 0) { ++ thiswrite = len; ++ if ((status = ++ Novfs_Write_File(file->private_data, ++ (unsigned char *)buf, ++ &thiswrite, &offset, ++ session)) || !thiswrite) { ++ totalwrite = status; ++ break; ++ } ++ DbgPrint("Novfs_f_write thiswrite = 0x%x\n", ++ thiswrite); ++ len -= thiswrite; ++ buf += thiswrite; ++ offset += thiswrite; ++ totalwrite += thiswrite; ++ if (offset > i_size_read(inode)) { ++ i_size_write(inode, offset); ++ inode->i_blocks = ++ (offset + inode->i_sb->s_blocksize - ++ 1) >> inode->i_blkbits; ++ } ++ inode->i_mtime = inode->i_atime = CURRENT_TIME; ++ id->Flags |= UPDATE_INODE; ++ ++ } ++ *off = offset; ++ } ++ } ++ DbgPrint("Novfs_f_write return = 0x%x\n", totalwrite); ++ ++ return (totalwrite); ++} ++ ++int Novfs_f_readdir(struct file *file, void *data, filldir_t fill) ++{ ++ return -EISDIR; ++} ++ ++int Novfs_f_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ DbgPrint("Novfs_f_ioctl: file=0x%p cmd=0x%x arg=0x%p\n", file, cmd, ++ arg); ++ ++ return -ENOSYS; ++} ++ ++/*++======================================================================*/ ++int Novfs_f_mmap(struct file *file, struct vm_area_struct *vma) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = -EINVAL; ++ ++ DbgPrint("Novfs_f_mmap: file=0x%p %.*s\n", file, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name); ++ ++ retCode = generic_file_mmap(file, vma); ++ ++ DbgPrint("Novfs_f_mmap: retCode=0x%x\n", retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_f_open(struct inode *inode, struct file *file) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct entry_info *info = NULL; ++ int retCode = -ENOENT; ++ session_t session; ++ char *path; ++ struct dentry *parent; ++ ino_t ino; ++ struct inode_data *id; ++ int errInfo; ++ ++ DbgPrint ++ ("Novfs_f_open: inode=0x%p file=0x%p dentry=0x%p dentry->d_inode=0x%p %.*s\n", ++ inode, file, file->f_dentry, file->f_dentry->d_inode, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name); ++ if (file->f_dentry) { ++ DbgPrint ++ ("Novfs_f_open: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name, ++ file->f_flags, file->f_mode, inode->i_mode); ++ } ++ ++ if (inode && inode->FSPRIVATE) { ++ id = (struct inode_data *) file->f_dentry->d_inode->FSPRIVATE; ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ info = Novfs_Malloc(sizeof(struct entry_info) + PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (info) { ++ path = ++ Novfs_dget_path(file->f_dentry, info->name, ++ PATH_LENGTH_BUFFER); ++ if (path) { ++ if (file->f_flags & O_TRUNC) { ++ errInfo = Novfs_Get_File_Info(path, info, &session); ++ ++ if (errInfo || info->size == 0) { ++ // clear O_TRUNC flag, bug #275366 ++ file->f_flags = ++ file->f_flags & (~O_TRUNC); ++ } ++ } ++ ++ DbgPrint("Novfs_f_open: %s\n", path); ++ retCode = Novfs_Open_File(path, ++ file-> ++ f_flags & ~O_EXCL, ++ info, ++ &file->private_data, ++ session); ++ ++ DbgPrint("Novfs_f_open: 0x%x 0x%p\n", retCode, ++ file->private_data); ++ if (!retCode) { ++ /* ++ *update_inode(inode, &info); ++ */ ++ //id->FileHandle = file->private_data; ++ id->CacheFlag = ++ Novfs_Get_File_Cache_Flag(path, ++ session); ++ ++ if (!Novfs_Get_File_Info(path, info, &session)) ++ update_inode(inode, info); ++ ++ parent = dget_parent(file->f_dentry); ++ ++ if (parent && parent->d_inode) { ++ struct inode *dir = ++ parent->d_inode; ++ Novfs_lock_inode_cache(dir); ++ ino = 0; ++ if (Novfs_get_entry ++ (dir, ++ &file->f_dentry->d_name, ++ &ino, info)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Flags |= ++ UPDATE_INODE; ++ } ++ ++ Novfs_unlock_inode_cache(dir); ++ } ++ dput(parent); ++ } ++ } ++ kfree(info); ++ } ++ } ++ DbgPrint("Novfs_f_open: retCode=0x%x\n", retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_flush_mapping(HANDLE Handle, struct address_space *mapping, ++ session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct pagevec pagevec; ++ unsigned nrpages; ++ pgoff_t index = 0; ++ int done, rc = 0; ++ ++ pagevec_init(&pagevec, 0); ++ ++ do { ++ done = 1; ++ nrpages = pagevec_lookup_tag(&pagevec, ++ mapping, ++ &index, ++ PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE); ++ ++ if (nrpages) { ++ struct page *page; ++ int i; ++ ++ DbgPrint("Novfs_flush_mapping: %u\n", nrpages); ++ ++ done = 0; ++ for (i = 0; !rc && (i < nrpages); i++) { ++ page = pagevec.pages[i]; ++ ++ DbgPrint("Novfs_flush_mapping: page 0x%p %lu\n", ++ page, page->index); ++ ++ lock_page(page); ++ page_cache_get(page); ++ if (page->mapping == mapping) { ++ if (clear_page_dirty_for_io(page)) { ++ rc = Novfs_Write_Page(Handle, ++ page, ++ Session); ++ if (!rc) { ++ //ClearPageDirty(page); ++ radix_tree_tag_clear ++ (&mapping-> ++ page_tree, ++ page_index(page), ++ PAGECACHE_TAG_DIRTY); ++ } ++ } ++ } ++ ++ page_cache_release(page); ++ unlock_page(page); ++ } ++ pagevec_release(&pagevec); ++ } ++ } while (!rc && !done); ++ ++ DbgPrint("Novfs_flush_mapping: return %d\n", rc); ++ ++ return (rc); ++} ++ ++/*++======================================================================*/ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) ++int Novfs_f_flush(struct file *file) ++#else ++int Novfs_f_flush(struct file *file, fl_owner_t ownid) ++#endif ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ ++ int rc = 0; ++#ifdef FLUSH ++ struct inode *inode; ++ session_t session; ++ struct inode_data *id; ++ ++ DbgPrint("Novfs_f_flush: Called from 0x%p\n", ++ __builtin_return_address(0)); ++ if (file->f_dentry && (inode = file->f_dentry->d_inode) ++ && (id = file->f_dentry->d_inode->FSPRIVATE)) { ++ ++ if ((file->f_flags & O_ACCMODE) != O_RDONLY) { ++ inode = file->f_dentry->d_inode; ++ DbgPrint ++ ("Novfs_f_flush: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name, file->f_flags, ++ file->f_mode, inode->i_mode); ++ ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ if (inode && ++ inode->i_mapping && inode->i_mapping->nrpages) { ++ ++ DbgPrint("Novfs_f_flush: %.*s pages=%lu\n", ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name, ++ inode->i_mapping->nrpages); ++ ++ if (file->f_dentry && ++ file->f_dentry->d_inode && ++ file->f_dentry->d_inode->i_mapping && ++ file->f_dentry->d_inode->i_mapping->a_ops && ++ file->f_dentry->d_inode->i_mapping->a_ops-> ++ writepage) { ++ rc = filemap_fdatawrite(file->f_dentry-> ++ d_inode-> ++ i_mapping); ++ } else { ++ rc = Novfs_flush_mapping(file-> ++ private_data, ++ file-> ++ f_dentry-> ++ d_inode-> ++ i_mapping, ++ session); ++ } ++ } ++ } ++ } ++#endif ++ return (rc); ++} ++ ++/*++======================================================================*/ ++int Novfs_f_release(struct inode *inode, struct file *file) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = -EACCES; ++ session_t session; ++ struct inode_data *id; ++ ++ DbgPrint("Novfs_f_release: path=%.*s handle=%p\n", ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name, file->private_data); ++ ++ if (inode && (id = inode->FSPRIVATE)) { ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ if ((file->f_flags & O_ACCMODE) != O_RDONLY) { ++ DbgPrint ++ ("Novfs_f_release: %.*s f_flags=0%o f_mode=0%o i_mode=0%o\n", ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name, file->f_flags, ++ file->f_mode, inode->i_mode); ++ ++ if (inode->i_mapping && inode->i_mapping->nrpages) { ++ ++ DbgPrint("Novfs_f_release: %.*s pages=%lu\n", ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name, ++ inode->i_mapping->nrpages); ++ ++ if (inode->i_mapping->a_ops && ++ inode->i_mapping->a_ops->writepage) { ++ filemap_fdatawrite(file->f_dentry-> ++ d_inode->i_mapping); ++ } else { ++ Novfs_flush_mapping(file->private_data, ++ file->f_dentry-> ++ d_inode->i_mapping, ++ session); ++ } ++ } ++ } ++ ++ if (file->f_dentry && file->f_dentry->d_inode) { ++ invalidate_remote_inode(file->f_dentry->d_inode); ++ } ++ ++ retCode = Novfs_Close_File(file->private_data, session); ++ //id->FileHandle = 0; ++ } ++ return (retCode); ++} ++ ++int Novfs_f_fsync(struct file *file, struct dentry *dentry, int datasync) ++{ ++ return 0; ++} ++ ++/*++======================================================================*/ ++int Novfs_f_llseek(struct file *file, loff_t offset, int origin) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ DbgPrint("Novfs_f_llseek: File=0x%p Name=%.*s offset=%lld origin=%d\n", ++ file, file->f_dentry->d_name.len, file->f_dentry->d_name.name, ++ offset, origin); ++ return (generic_file_llseek(file, offset, origin)); ++} ++ ++/*++======================================================================*/ ++int Novfs_f_lock(struct file *file, int cmd, struct file_lock *lock) ++/* ++ * Arguments: ++ * "file" - pointer to file structure - contains file handle in "file->private_data" ++ * ++ * "cmd" could be F_SETLK, F_SETLKW, F_GETLK ++ * F_SETLK/F_SETLKW are for setting/unsetting file lock ++ * F_GETLK is for getting infomation about region - is it locked, or not ++ * ++ * "lock" structure - contains "start" and "end" of locking region ++ * ++ * Returns: ++ * 0 on success ++ * -ENOSYS on F_GETLK cmd. It's not implemented. ++ * -EINVAL if (lock->fl_start > lock->fl_end) ++ * -EAGAIN on all other errors ++ * Abstract: ++ * ++ * Notes: ++ * "lock->fl_start" and "lock->fl_end" are of type "long long", ++ * but xtier functions in novfsd "NCFsdLockFile" and "NCFsdUnlockFile" ++ * receive arguments in u64 type. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int err_code; ++ ++ struct inode *inode; ++ session_t session; ++ struct inode_data *id; ++ loff_t len; ++ ++ DbgPrint("Novfs_f_lock(0x%p): begin in Novfs_f_lock 0x%p\n", ++ __builtin_return_address(0), file->private_data); ++ DbgPrint ++ ("Novfs_f_lock: cmd = %d, F_GETLK = %d, F_SETLK = %d, F_SETLKW = %d\n", ++ cmd, F_GETLK, F_SETLK, F_SETLKW); ++ DbgPrint ++ ("Novfs_f_lock: lock->fl_start = 0x%llX, lock->fl_end = 0x%llX\n", ++ lock->fl_start, lock->fl_end); ++ ++ err_code = -1; ++ if (lock->fl_start <= lock->fl_end) { ++ /* Get len from "start" and "end" */ ++ len = lock->fl_end - lock->fl_start + 1; ++ if ((0 == lock->fl_start) && (OFFSET_MAX == lock->fl_end)) { ++ len = 0; ++ } ++ ++ if (file->f_dentry && ++ (inode = file->f_dentry->d_inode) && ++ (id = (struct inode_data *)inode->FSPRIVATE)) { ++ DbgPrint("Novfs_f_lock: (0x%p 0x%p %.*s)\n", ++ file->private_data, inode, ++ file->f_dentry->d_name.len, ++ file->f_dentry->d_name.name); ++ ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ /* fl_type = F_RDLCK, F_WRLCK, F_UNLCK */ ++ switch (cmd) { ++ case F_SETLK: ++#ifdef F_GETLK64 ++ case F_SETLK64: ++#endif ++ ++ err_code = ++ Novfs_Set_File_Lock(session, ++ file->private_data, ++ lock->fl_type, ++ lock->fl_start, len); ++ break; ++ ++ case F_SETLKW: ++#ifdef F_GETLK64 ++ case F_SETLKW64: ++#endif ++ err_code = ++ Novfs_Set_File_Lock(session, ++ file->private_data, ++ lock->fl_type, ++ lock->fl_start, len); ++ break; ++ ++ case F_GETLK: ++#ifdef F_GETLK64 ++ case F_GETLK64: ++#endif ++ err_code = -ENOSYS; ++ /* ++ * Not implemented. We doesn't have appropriate xtier function. ++ * */ ++ break; ++ ++ default: ++ printk ++ ("<1> novfs in Novfs_f_lock, not implemented cmd = %d\n", ++ cmd); ++ DbgPrint ++ ("Novfs_f_lock: novfs in Novfs_f_lock, not implemented cmd = %d\n", ++ cmd); ++ break; ++ } ++ } ++ ++ DbgPrint("Novfs_f_lock: lock->fl_type = %u, err_code 0x%X\n", ++ lock->fl_type, err_code); ++ ++ if ((err_code != 0) && (err_code != -1) ++ && (err_code != -ENOSYS)) { ++ err_code = -EAGAIN; ++ } ++ } else { ++ err_code = -EINVAL; ++ } ++ ++ return (err_code); ++} ++ ++/*++======================================================================*/ ++static void Novfs_copy_cache_pages(struct address_space *mapping, ++ struct list_head *pages, int bytes_read, ++ char *data, struct pagevec *plru_pvec) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct page *page; ++ char *target; ++ ++ while (bytes_read > 0) { ++ if (list_empty(pages)) ++ break; ++ ++ page = list_entry(pages->prev, struct page, lru); ++ list_del(&page->lru); ++ ++ if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { ++ page_cache_release(page); ++ data += PAGE_CACHE_SIZE; ++ bytes_read -= PAGE_CACHE_SIZE; ++ continue; ++ } ++ ++ target = kmap_atomic(page, KM_USER0); ++ ++ if (PAGE_CACHE_SIZE > bytes_read) { ++ memcpy(target, data, bytes_read); ++ /* zero the tail end of this partial page */ ++ memset(target + bytes_read, 0, ++ PAGE_CACHE_SIZE - bytes_read); ++ bytes_read = 0; ++ } else { ++ memcpy(target, data, PAGE_CACHE_SIZE); ++ bytes_read -= PAGE_CACHE_SIZE; ++ } ++ kunmap_atomic(target, KM_USER0); ++ ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ if (!pagevec_add(plru_pvec, page)) ++ __pagevec_lru_add(plru_pvec); ++ data += PAGE_CACHE_SIZE; ++ } ++ return; ++} ++ ++/*++======================================================================*/ ++int Novfs_a_writepage(struct page *page, struct writeback_control *wbc) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = -EFAULT; ++ struct inode *inode = page->mapping->host; ++ struct inode_data *id = inode->FSPRIVATE; ++ loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); ++ session_t session; ++ struct data_list dlst[2]; ++ size_t len = PAGE_CACHE_SIZE; ++ ++ session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ ++ page_cache_get(page); ++ ++ pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); ++ ++ /* ++ * Leave first dlst entry for reply header. ++ */ ++ dlst[1].page = page; ++ dlst[1].offset = NULL; ++ dlst[1].len = len; ++ dlst[1].rwflag = DLREAD; ++ ++ /* ++ * Check size so we don't write pass end of file. ++ */ ++ if ((pos + (loff_t) len) > i_size_read(inode)) { ++ len = (size_t) (i_size_read(inode) - pos); ++ } ++ ++ retCode = Novfs_Write_Pages(id->FileHandle, dlst, 2, len, pos, session); ++ if (!retCode) { ++ SetPageUptodate(page); ++ } ++ ++ unlock_page(page); ++ page_cache_release(page); ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_a_writepages(struct address_space *mapping, ++ struct writeback_control *wbc) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ struct inode *inode = mapping->host; ++ session_t session; ++ HANDLE fh = 0; ++ struct inode_data *id = NULL; ++ ++ int max_page_lookup = MaxIoSize / PAGE_CACHE_SIZE; ++ ++ struct data_list *dlist; ++ struct data_list *dlptr; ++ struct page **pages; ++ ++ int dlist_idx, i = 0; ++ pgoff_t index, next_index = 0; ++ loff_t pos = 0; ++ size_t tsize; ++ ++ SC_INITIALIZE(session); ++ DbgPrint ++ ("Novfs_a_writepages: inode=0x%p mapping=0x%p wbc=0x%p nr_to_write=%d\n", ++ inode, mapping, wbc, wbc->nr_to_write); ++ ++ if (inode) { ++ DbgPrint(" Inode=0x%p Ino=%d Id=0x%p\n", inode, inode->i_ino, ++ inode->FSPRIVATE); ++ ++ if (NULL != (id = inode->FSPRIVATE)) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ fh = ((struct inode_data *)inode->FSPRIVATE)->FileHandle; ++ } ++ } ++ ++ dlist = Novfs_Malloc(sizeof(struct data_list) * max_page_lookup, GFP_KERNEL); ++ pages = ++ Novfs_Malloc(sizeof(struct page *) * max_page_lookup, GFP_KERNEL); ++ ++ if (id) ++ DbgPrint ++ ("Novfs_a_writepages: inode=0x%p fh=0x%p dlist=0x%p pages=0x%p %s\n", ++ inode, fh, dlist, pages, id->Name); ++ else ++ DbgPrint ++ ("Novfs_a_writepages: inode=0x%p fh=0x%p dlist=0x%p pages=0x%p\n", ++ inode, fh, dlist, pages); ++ ++ if (dlist && pages) { ++ struct backing_dev_info *bdi = mapping->backing_dev_info; ++ int done = 0; ++ int nr_pages = 0; ++ int scanned = 0; ++ ++ if (wbc->nonblocking && bdi_write_congested(bdi)) { ++ wbc->encountered_congestion = 1; ++ return 0; ++ } ++ ++ if (wbc->sync_mode == WB_SYNC_NONE) { ++ index = mapping->writeback_index; /* Start from prev offset */ ++ } else { ++ index = 0; /* whole-file sweep */ ++ scanned = 1; ++ } ++ ++ next_index = index; ++ ++ while (!done && (wbc->nr_to_write > 0)) { ++ dlist_idx = 0; ++ dlptr = &dlist[1]; ++ ++ DbgPrint("Novfs_a_writepages1: nr_pages=%d\n", ++ nr_pages); ++ if (!nr_pages) { ++ memset(pages, 0, ++ sizeof(struct page *) * max_page_lookup); ++ ++ AS_TREE_LOCK(&mapping->tree_lock); ++ ++ /* ++ * Need to ask for one less then max_page_lookup or we ++ * will overflow the request buffer. This also frees ++ * the first entry for the reply buffer. ++ */ ++ nr_pages = ++ radix_tree_gang_lookup_tag(&mapping-> ++ page_tree, ++ (void **)pages, ++ index, ++ max_page_lookup - ++ 1, ++ PAGECACHE_TAG_DIRTY); ++ ++ DbgPrint("Novfs_a_writepages2: nr_pages=%d\n", ++ nr_pages); ++ /* ++ * Check to see if there are dirty pages and there is a valid ++ * file handle. ++ */ ++ if (nr_pages && !fh) { ++ set_bit(AS_EIO, &mapping->flags); ++ done = 1; ++ DbgPrint ++ ("Novfs_a_writepage: set_bit AS_EIO\n"); ++ break; ++ } ++ ++ for (i = 0; i < nr_pages; i++) { ++ page_cache_get(pages[i]); ++ } ++ ++ AS_TREE_UNLOCK(&mapping->tree_lock); ++ ++ if (nr_pages) { ++ index = pages[nr_pages - 1]->index + 1; ++ pos = ++ (loff_t) pages[0]-> ++ index << PAGE_CACHE_SHIFT; ++ } ++ ++ if (!nr_pages) { ++ if (scanned) { ++ index = 0; ++ scanned = 0; ++ continue; ++ } ++ done = 1; ++ } else { ++ next_index = pages[0]->index; ++ i = 0; ++ } ++ } else { ++ if (pages[i]) { ++ pos = ++ (loff_t) pages[i]-> ++ index << PAGE_CACHE_SHIFT; ++ } ++ } ++ ++ for (; i < nr_pages; i++) { ++ struct page *page = pages[i]; ++ ++ /* ++ * At this point we hold neither mapping->tree_lock nor ++ * lock on the page itself: the page may be truncated or ++ * invalidated (changing page->mapping to NULL), or even ++ * swizzled back from swapper_space to tmpfs file ++ * mapping ++ */ ++ ++ DbgPrint ++ ("Novfs_a_writepages: pos=0x%llx index=%d page->index=%d next_index=%d\n", ++ pos, index, page->index, next_index); ++ ++ if (page->index != next_index) { ++ next_index = page->index; ++ break; ++ } ++ next_index = page->index + 1; ++ ++ lock_page(page); ++ ++ if (wbc->sync_mode != WB_SYNC_NONE) ++ wait_on_page_writeback(page); ++ ++ if (page->mapping != mapping ++ || PageWriteback(page) ++ || !clear_page_dirty_for_io(page)) { ++ unlock_page(page); ++ continue; ++ } ++ ++ dlptr[dlist_idx].page = page; ++ dlptr[dlist_idx].offset = NULL; ++ dlptr[dlist_idx].len = PAGE_CACHE_SIZE; ++ dlptr[dlist_idx].rwflag = DLREAD; ++ dlist_idx++; ++ DbgPrint ++ ("Novfs_a_writepages: Add page=0x%p index=0x%lx\n", ++ page, page->index); ++ } ++ ++ DbgPrint("Novfs_a_writepages: dlist_idx=%d\n", ++ dlist_idx); ++ if (dlist_idx) { ++ tsize = dlist_idx * PAGE_CACHE_SIZE; ++ /* ++ * Check size so we don't write pass end of file. ++ */ ++ if ((pos + tsize) > i_size_read(inode)) { ++ tsize = ++ (size_t) (i_size_read(inode) - pos); ++ } ++ ++ retCode = ++ Novfs_Write_Pages(fh, dlist, dlist_idx + 1, ++ tsize, pos, session); ++ switch (retCode) { ++ case 0: ++ wbc->nr_to_write -= dlist_idx; ++ break; ++ ++ case -ENOSPC: ++ set_bit(AS_ENOSPC, &mapping->flags); ++ done = 1; ++ break; ++ ++ default: ++ set_bit(AS_EIO, &mapping->flags); ++ done = 1; ++ break; ++ } ++ ++ do { ++ unlock_page((struct page *) ++ dlptr[dlist_idx - 1].page); ++ page_cache_release((struct page *) ++ dlptr[dlist_idx - ++ 1].page); ++ DbgPrint ++ ("Novfs_a_writepages: release page=0x%p index=0x%lx\n", ++ dlptr[dlist_idx - 1].page, ++ ((struct page *) ++ dlptr[dlist_idx - ++ 1].page)->index); ++ if (!retCode) { ++ wbc->nr_to_write--; ++ } ++ } while (--dlist_idx); ++ } ++ ++ if (i >= nr_pages) { ++ nr_pages = 0; ++ } ++ } ++ ++ mapping->writeback_index = index; ++ ++ } else { ++ DbgPrint("Novfs_a_writepage: set_bit AS_EIO\n"); ++ set_bit(AS_EIO, &mapping->flags); ++ } ++ if (dlist) ++ kfree(dlist); ++ if (pages) ++ kfree(pages); ++ ++ DbgPrint("Novfs_a_writepage: retCode=%d\n", retCode); ++ return (0); ++ ++} ++ ++/*++======================================================================*/ ++int Novfs_a_readpage(struct file *file, struct page *page) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ void *pbuf; ++ struct inode *inode = NULL; ++ struct dentry *dentry = NULL; ++ loff_t offset; ++ size_t len; ++ session_t session; ++ ++ SC_INITIALIZE(session); ++ DbgPrint("Novfs_a_readpage: File=0x%p Name=%.*s Page=0x%p", file, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name, page); ++ ++ dentry = file->f_dentry; ++ ++ if (dentry) { ++ DbgPrint(" Dentry=0x%p Name=%.*s", dentry, dentry->d_name.len, ++ dentry->d_name.name); ++ if (dentry->d_inode) { ++ inode = dentry->d_inode; ++ } ++ } ++ ++ if (inode) { ++ DbgPrint(" Inode=0x%p Ino=%d", inode, inode->i_ino); ++ ++ if (inode->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)inode-> ++ FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ } ++ } ++ } ++ ++ DbgPrint("\n"); ++ ++ if (!PageUptodate(page)) { ++ struct data_list dlst[2]; ++ ++ offset = page->index << PAGE_CACHE_SHIFT; ++ len = PAGE_CACHE_SIZE; ++ ++ /* ++ * Save the first entry for the reply header. ++ */ ++ dlst[1].page = page; ++ dlst[1].offset = NULL; ++ dlst[1].len = PAGE_CACHE_SIZE; ++ dlst[1].rwflag = DLWRITE; ++ ++ DbgPrint("Novfs_a_readpage: calling= Novfs_Read_Pages %lld\n", ++ offset); ++ retCode = ++ Novfs_Read_Pages(file->private_data, dlst, 2, &len, &offset, ++ session); ++ if (len && (len < PAGE_CACHE_SIZE)) { ++ pbuf = kmap_atomic(page, KM_USER0); ++ memset(&((char *)pbuf)[len], 0, PAGE_CACHE_SIZE - len); ++ kunmap_atomic(pbuf, KM_USER0); ++ } ++ ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ } ++ unlock_page(page); ++ ++ DbgPrint("Novfs_a_readpage: retCode=%d\n", retCode); ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int Novfs_a_readpages(struct file *file, struct address_space *mapping, ++ struct list_head *page_lst, unsigned nr_pages) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ struct inode *inode = NULL; ++ struct dentry *dentry = NULL; ++ session_t session; ++ loff_t offset; ++ size_t len; ++ ++ unsigned page_idx; ++ struct pagevec lru_pvec; ++ pgoff_t next_index; ++ ++ char *rbuf, done = 0; ++ SC_INITIALIZE(session); ++ ++ DbgPrint("Novfs_a_readpages: File=0x%p Name=%.*s Pages=%d\n", file, ++ file->f_dentry->d_name.len, file->f_dentry->d_name.name, ++ nr_pages); ++ ++ dentry = file->f_dentry; ++ ++ if (dentry) { ++ DbgPrint(" Dentry=0x%p Name=%.*s\n", dentry, dentry->d_name.len, ++ dentry->d_name.name); ++ if (dentry->d_inode) { ++ inode = dentry->d_inode; ++ } ++ } ++ ++ if (inode) { ++ DbgPrint(" Inode=0x%p Ino=%d\n", inode, inode->i_ino); ++ ++ if (inode->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)inode-> ++ FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *) inode->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(file->f_dentry); ++ session = ++ Scope_Get_SessionId(((struct inode_data *) inode-> ++ FSPRIVATE)->Scope); ++ } ++ } ++ } ++ ++ rbuf = (char *)Novfs_Malloc(MaxIoSize, GFP_KERNEL); ++ if (rbuf) { ++ pagevec_init(&lru_pvec, 0); ++ for (page_idx = 0; page_idx < nr_pages && !done;) { ++ struct page *page, *tpage; ++ ++ if (list_empty(page_lst)) ++ break; ++ ++ page = list_entry(page_lst->prev, struct page, lru); ++ ++ next_index = page->index; ++ offset = (loff_t) page->index << PAGE_CACHE_SHIFT; ++ len = 0; ++ ++ /* ++ * Count number of contiguous pages. ++ */ ++ list_for_each_entry_reverse(tpage, page_lst, lru) { ++ if ((next_index != tpage->index) || ++ (len >= MaxIoSize - PAGE_SIZE)) { ++ break; ++ } ++ len += PAGE_SIZE; ++ next_index++; ++ } ++ ++ if (len && !done) { ++ struct data_list dllst[2]; ++ ++ dllst[1].page = NULL; ++ dllst[1].offset = rbuf; ++ dllst[1].len = len; ++ dllst[1].rwflag = DLWRITE; ++ ++ DbgPrint ++ ("Novfs_a_readpages: calling Novfs_Read_Pages %lld\n", ++ offset); ++ if (!Novfs_Read_Pages ++ (file->private_data, dllst, 2, &len, ++ &offset, session)) { ++ Novfs_copy_cache_pages(mapping, ++ page_lst, len, ++ rbuf, &lru_pvec); ++ page_idx += len >> PAGE_CACHE_SHIFT; ++ if ((int)(len & PAGE_CACHE_MASK) != len) { ++ page_idx++; ++ } ++ if (len == 0) { ++ done = 1; ++ } ++ } else { ++ done = 1; ++ } ++ } ++ } ++ ++ /* ++ * Free any remaining pages. ++ */ ++ while (!list_empty(page_lst)) { ++ struct page *page = ++ list_entry(page_lst->prev, struct page, lru); ++ ++ list_del(&page->lru); ++ page_cache_release(page); ++ } ++ ++ pagevec_lru_add(&lru_pvec); ++ kfree(rbuf); ++ } else { ++ retCode = -ENOMEM; ++ } ++ ++ DbgPrint("Novfs_a_readpages: retCode=%d\n", retCode); ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int Novfs_a_prepare_write(struct file *file, struct page *page, unsigned from, ++ unsigned to) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retVal = 0; ++ loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; ++ size_t len = PAGE_CACHE_SIZE; ++ session_t session; ++ struct data_list dllst[2]; ++ struct inode *inode = file->f_dentry->d_inode; ++ SC_INITIALIZE(session); ++ ++ DbgPrint ++ ("Novfs_a_prepare_write: File=0x%p Page=0x%p offset=0x%llx From=%u To=%u filesize=%lld\n", ++ file, page, offset, from, to, ++ i_size_read(file->f_dentry->d_inode)); ++ if (!PageUptodate(page)) { ++ /* ++ * Check to see if whole page ++ */ ++ if ((to == PAGE_CACHE_SIZE) && (from == 0)) { ++ SetPageUptodate(page); ++ } ++ ++ /* ++ * Check to see if we can read page. ++ */ ++ else if ((file->f_flags & O_ACCMODE) != O_WRONLY) { ++ /* ++ * Get session. ++ */ ++ if (file->f_dentry && file->f_dentry->d_inode) { ++ if (file->f_dentry->d_inode->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ } ++ } ++ } ++ ++ page_cache_get(page); ++ ++ len = i_size_read(inode) - offset; ++ if (len > PAGE_CACHE_SIZE) { ++ len = PAGE_CACHE_SIZE; ++ } ++ ++ if (len) { ++ /* ++ * Read page from server. ++ */ ++ ++ dllst[1].page = page; ++ dllst[1].offset = 0; ++ dllst[1].len = len; ++ dllst[1].rwflag = DLWRITE; ++ ++ DbgPrint ++ ("Novfs_a_prepare_write: calling Novfs_Read_Pages %lld\n", ++ offset); ++ Novfs_Read_Pages(file->private_data, dllst, 2, ++ &len, &offset, session); ++ ++ /* ++ * Zero unnsed page. ++ */ ++ } ++ ++ if (len < PAGE_CACHE_SIZE) { ++ char *adr = kmap_atomic(page, KM_USER0); ++ memset(adr + len, 0, PAGE_CACHE_SIZE - len); ++ kunmap_atomic(adr, KM_USER0); ++ } ++ } else { ++ /* ++ * Zero section of memory that not going to be used. ++ */ ++ char *adr = kmap_atomic(page, KM_USER0); ++ memset(adr, 0, from); ++ memset(adr + to, 0, PAGE_CACHE_SIZE - to); ++ kunmap_atomic(adr, KM_USER0); ++ ++ DbgPrint("Novfs_a_prepare_write: memset 0x%p\n", adr); ++ } ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ } ++// DbgPrint("Novfs_a_prepare_write: return %d\n", retVal); ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_a_commit_write(struct file *file, struct page *page, unsigned offset, ++ unsigned to) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ struct inode *inode = page->mapping->host; ++ loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; ++ session_t session; ++ struct inode_data *id; ++ struct data_list dlst[1]; ++ size_t len = to - offset; ++ ++ SC_INITIALIZE(session); ++ ++ DbgPrint ++ ("Novfs_a_commit_write: File=0x%p Page=0x%p offset=0x%x To=%u filesize=%lld\n", ++ file, page, offset, to, i_size_read(file->f_dentry->d_inode)); ++ if (file->f_dentry->d_inode ++ && (id = file->f_dentry->d_inode->FSPRIVATE)) { ++ session = Scope_Get_SessionId(id->Scope); ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = Scope_Get_ScopefromPath(file->f_dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ /* ++ * Setup file handle ++ */ ++ id->FileHandle = file->private_data; ++ ++ if (pos > inode->i_size) { ++ i_size_write(inode, pos); ++ } ++ ++ if (!PageUptodate(page)) { ++ pos = ++ ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; ++ ++ if (to < offset) { ++ return (retCode); ++ } ++ dlst[0].page = page; ++ dlst[0].offset = (void *)(unsigned long) offset; ++ dlst[0].len = len; ++ dlst[0].rwflag = DLREAD; ++ ++ retCode = ++ Novfs_Write_Pages(id->FileHandle, dlst, 1, len, pos, ++ session); ++ ++ } else { ++ set_page_dirty(page); ++ } ++ } ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++ssize_t Novfs_a_direct_IO(int rw, struct kiocb * kiocb, ++ const struct iovec * iov, ++ loff_t offset, unsigned long nr_segs) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: This is a dummy function so that we can allow a file ++ * to get the direct IO flag set. Novfs_f_read and ++ * Novfs_f_write will do the work. Maybe not the best ++ * way to do but it was the easiest to implement. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ return (-EIO); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ char *path, *buf; ++ struct entry_info info; ++ HANDLE handle; ++ session_t session; ++ int retCode = -EACCES; ++ ++ DbgPrint("Novfs_i_create: mode=0%o flags=0%o %.*s\n", mode, ++ nd->NDOPENFLAGS, dentry->d_name.len, dentry->d_name.name); ++ ++ if (IS_ROOT(dentry) || /* Root */ ++ IS_ROOT(dentry->d_parent) || /* User */ ++ IS_ROOT(dentry->d_parent->d_parent) || /* Server */ ++ IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ ++ return (-EACCES); ++ } ++ ++ if (mode | S_IFREG) { ++ if (dir->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)-> ++ Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *) dir->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(dentry); ++ session = Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ } ++ ++ buf = ++ (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, ++ GFP_KERNEL); ++ if (buf) { ++ path = ++ Novfs_dget_path(dentry, buf, ++ PATH_LENGTH_BUFFER); ++ if (path) { ++ retCode = ++ Novfs_Open_File(path, ++ nd-> ++ NDOPENFLAGS | ++ O_RDWR, &info, ++ &handle, session); ++ if (!retCode && handle) { ++ Novfs_Close_File(handle, ++ session); ++ if (!Novfs_i_mknod ++ (dir, dentry, ++ mode | S_IFREG, 0)) { ++ if (dentry->d_inode) { ++ ((struct inode_data *)dentry->d_inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ } ++ } ++ } ++ } ++ kfree(buf); ++ } ++ } ++ } ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++void update_inode(struct inode *Inode, struct entry_info *Info) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ static char dbuf[128]; ++ ++ DbgPrint("update_inode: Inode=0x%p I_ino=%d\n", Inode, Inode->i_ino); ++ ++ DbgPrint("update_inode: atime=%s\n", ++ ctime_r(&Info->atime.tv_sec, dbuf)); ++ DbgPrint("update_inode: ctime=%s\n", ++ ctime_r(&Info->ctime.tv_sec, dbuf)); ++ DbgPrint("update_inode: mtime=%s %d\n", ++ ctime_r(&Info->mtime.tv_sec, dbuf), Info->mtime.tv_nsec); ++ DbgPrint("update_inode: size=%lld\n", Info->size); ++ DbgPrint("update_inode: mode=0%o\n", Info->mode); ++ ++ if (Inode && ++ ((Inode->i_size != Info->size) || ++ (Inode->i_mtime.tv_sec != Info->mtime.tv_sec) || ++ (Inode->i_mtime.tv_nsec != Info->mtime.tv_nsec))) { ++ DbgPrint ++ ("update_inode: calling invalidate_remote_inode sz %d %d\n", ++ Inode->i_size, Info->size); ++ DbgPrint ++ ("update_inode: calling invalidate_remote_inode sec %d %d\n", ++ Inode->i_mtime.tv_sec, Info->mtime.tv_sec); ++ DbgPrint ++ ("update_inode: calling invalidate_remote_inode ns %d %d\n", ++ Inode->i_mtime.tv_nsec, Info->mtime.tv_nsec); ++ ++ if (Inode && Inode->i_mapping) { ++ invalidate_remote_inode(Inode); ++ } ++ } ++ ++ Inode->i_mode = Info->mode; ++ Inode->i_size = Info->size; ++ Inode->i_atime = Info->atime; ++ Inode->i_ctime = Info->ctime; ++ Inode->i_mtime = Info->mtime; ++ ++ if (Inode->i_size && Inode->i_sb->s_blocksize) { ++ Inode->i_blocks = (unsigned long) (Info->size >> (loff_t) Inode->i_blkbits); ++ Inode->i_bytes = Info->size & (Inode->i_sb->s_blocksize - 1); ++ ++ DbgPrint("update_inode: i_sb->s_blocksize=%d\n", Inode->i_sb->s_blocksize); ++ DbgPrint("update_inode: i_blkbits=%d\n", Inode->i_blkbits); ++ DbgPrint("update_inode: i_blocks=%d\n", Inode->i_blocks); ++ DbgPrint("update_inode: i_bytes=%d\n", Inode->i_bytes); ++ } ++} ++ ++/*++======================================================================*/ ++struct dentry *Novfs_i_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct dentry *retVal = ERR_PTR(-ENOENT); ++ struct dentry *parent; ++ struct entry_info *info = NULL; ++ struct inode_data *id; ++ struct inode *inode = NULL; ++ uid_t uid = current->euid; ++ ino_t ino = 0; ++ struct qstr name; ++ char *buf; ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ char *path; ++ path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ DbgPrint ++ ("Novfs_i_lookup: dir 0x%p %d hash %d inode 0x%0p %s\n", ++ dir, dir->i_ino, dentry->d_name.hash, ++ dentry->d_inode, path); ++ } ++ kfree(buf); ++ } else { ++ DbgPrint ++ ("Novfs_i_lookup: dir 0x%p %d name %.*s hash %d inode 0x%0p\n", ++ dir, dir->i_ino, dentry->d_name.len, dentry->d_name.name, ++ dentry->d_name.hash, dentry->d_inode); ++ } ++ ++ if ((dentry->d_name.len == 7) ++ && (0 == strncmp(dentry->d_name.name, " !xover", 7))) { ++ dentry->d_op = &Novfs_dentry_operations; ++ igrab(dir); ++ d_add(dentry, dir); ++ return NULL; ++ } ++ if ((dentry->d_name.len == 7) ++ && (0 == strncmp(dentry->d_name.name, "z!xover", 7))) { ++ dentry->d_op = &Novfs_dentry_operations; ++ igrab(dir); ++ d_add(dentry, dir); ++ return NULL; ++ } ++ ++ if (dir && (id = dir->FSPRIVATE)) { ++ retVal = 0; ++ if (IS_ROOT(dentry)) { ++ DbgPrint("Novfs_i_lookup: Root entry=0x%p\n", ++ Novfs_root); ++ inode = Novfs_root->d_inode; ++ return (0); ++ } else { ++ info = ++ Novfs_Malloc(sizeof(struct entry_info) + ++ PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (info) { ++ if (NULL == ++ (retVal = ++ ERR_PTR(verify_dentry(dentry, 1)))) { ++ name.name = dentry->d_name.name; ++ name.len = dentry->d_name.len; ++ name.hash = Novfs_internal_hash(&name); ++ ++ if (Novfs_lock_inode_cache(dir)) { ++ if (!Novfs_get_entry ++ (dir, &name, &ino, info)) { ++ inode = ++ ilookup(dentry-> ++ d_sb, ino); ++ if (inode) { ++ update_inode ++ (inode, ++ info); ++ } ++ } ++ Novfs_unlock_inode_cache(dir); ++ } ++ ++ if (!inode && ino) { ++ uid = Scope_Get_Uid(id->Scope); ++ if (Novfs_lock_inode_cache(dir)) { ++ inode = Novfs_get_inode (dentry->d_sb, info->mode, 0, uid, ino, &name); ++ if (inode) { ++ if (!Novfs_get_entry(dir, &dentry->d_name, &ino, info)) { ++ update_inode ++ (inode, ++ info); ++ } ++ } ++ Novfs_unlock_inode_cache ++ (dir); ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ if (!retVal) { ++ dentry->d_op = &Novfs_dentry_operations; ++ if (inode) { ++ parent = dget_parent(dentry); ++ Novfs_d_add(dentry->d_parent, dentry, inode, 1); ++ dput(parent); ++ } else { ++ d_add(dentry, inode); ++ } ++ } ++ ++ if (info) ++ kfree(info); ++ ++ DbgPrint ++ ("Novfs_i_lookup: inode=0x%p dentry->d_inode=0x%p return=0x%p\n", ++ dir, dentry->d_inode, retVal); ++ ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_unlink(struct inode *dir, struct dentry *dentry) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = -ENOENT; ++ struct inode *inode; ++ session_t session; ++ char *path, *buf; ++ uint64_t t64; ++ ++ DbgPrint("Novfs_i_unlink: dir=0x%p dir->i_ino=%d %.*s\n", dir, ++ dir->i_ino, dentry->d_name.len, dentry->d_name.name); ++ DbgPrint("Novfs_i_unlink: IS_ROOT(dentry)=%d\n", IS_ROOT(dentry)); ++ DbgPrint("Novfs_i_unlink: IS_ROOT(dentry->d_parent)=%d\n", ++ IS_ROOT(dentry->d_parent)); ++ DbgPrint("Novfs_i_unlink: IS_ROOT(dentry->d_parent->d_parent)=%d\n", ++ IS_ROOT(dentry->d_parent->d_parent)); ++ DbgPrint ++ ("Novfs_i_unlink: IS_ROOT(dentry->d_parent->d_parent->d_parent)=%d\n", ++ IS_ROOT(dentry->d_parent->d_parent->d_parent)); ++ ++ if (IS_ROOT(dentry) || /* Root */ ++ IS_ROOT(dentry->d_parent) || /* User */ ++ (!IS_ROOT(dentry->d_parent->d_parent) && /* Server */ ++ IS_ROOT(dentry->d_parent->d_parent->d_parent))) { /* Volume */ ++ return (-EACCES); ++ } ++ ++ inode = dentry->d_inode; ++ if (inode) { ++ DbgPrint ++ ("Novfs_i_unlink: dir=0x%p dir->i_ino=%d inode=0x%p ino=%d\n", ++ dir, dir->i_ino, inode, inode->i_ino); ++ if (inode->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(dentry); ++ session = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ } ++ ++ buf = ++ (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, ++ GFP_KERNEL); ++ if (buf) { ++ path = ++ Novfs_dget_path(dentry, buf, ++ PATH_LENGTH_BUFFER); ++ if (path) { ++ DbgPrint ++ ("Novfs_i_unlink: path %s mode 0%o\n", ++ path, inode->i_mode); ++ if (IS_ROOT(dentry->d_parent->d_parent)) { ++ retCode = do_logout(&dentry->d_name, &session); ++ } else { ++ retCode = ++ Novfs_Delete(path, ++ S_ISDIR(inode-> ++ i_mode), ++ session); ++ } ++ if (!retCode || IS_DEADDIR(inode)) { ++ Novfs_remove_inode_entry(dir, ++ &dentry-> ++ d_name, ++ 0); ++ dentry->d_time = 0; ++ t64 = 0; ++ Scope_Set_UserSpace(&t64, &t64, ++ &t64, &t64); ++ retCode = 0; ++ } ++ } ++ kfree(buf); ++ } ++ } ++ } ++ ++ DbgPrint("Novfs_i_unlink: retCode 0x%x\n", retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ char *path, *buf; ++ session_t session; ++ int retCode = 0; ++ struct inode *inode; ++ struct entry_info info; ++ uid_t uid; ++ ++ DbgPrint("Novfs_i_mkdir: dir=0x%p ino=%d dentry=0x%p %.*s mode=0%lo\n", ++ dir, dir->i_ino, dentry, dentry->d_name.len, ++ dentry->d_name.name, mode); ++ ++ if (IS_ROOT(dentry) || /* Root */ ++ IS_ROOT(dentry->d_parent) || /* User */ ++ IS_ROOT(dentry->d_parent->d_parent) || /* Server */ ++ IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ ++ return (-EACCES); ++ } ++ ++ mode |= S_IFDIR; ++ mode &= (S_IFMT | S_IRWXU); ++ if (dir->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)dir->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(dentry); ++ session = ++ Scope_Get_SessionId(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ } ++ ++ uid = Scope_Get_Uid(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ DbgPrint("Novfs_i_mkdir: path %s\n", path); ++ retCode = ++ Novfs_Create(path, S_ISDIR(mode), session); ++ if (!retCode) { ++ retCode = Novfs_Get_File_Info(path, &info, &session); ++ if (!retCode) { ++ retCode = Novfs_i_mknod(dir, dentry, mode, 0); ++ inode = dentry->d_inode; ++ if (inode) { ++ update_inode(inode, ++ &info); ++ ((struct inode_data *)inode->FSPRIVATE)->Flags &= ~UPDATE_INODE; ++ ++ dentry->d_time = ++ jiffies + ++ (File_update_timeout ++ * HZ); ++ ++ Novfs_lock_inode_cache ++ (dir); ++ if (Novfs_update_entry ++ (dir, ++ &dentry->d_name, 0, ++ &info)) { ++ Novfs_add_inode_entry ++ (dir, ++ &dentry-> ++ d_name, ++ inode-> ++ i_ino, ++ &info); ++ } ++ Novfs_unlock_inode_cache ++ (dir); ++ } ++ ++ } ++ } ++ } ++ kfree(buf); ++ } ++ } ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_rmdir(struct inode *inode, struct dentry *dentry) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ return (Novfs_i_unlink(inode, dentry)); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode *inode = NULL; ++ int retCode = -EACCES; ++ uid_t uid; ++ struct dentry *parent; ++ ++ if (IS_ROOT(dentry) || /* Root */ ++ IS_ROOT(dentry->d_parent) || /* User */ ++ IS_ROOT(dentry->d_parent->d_parent) || /* Server */ ++ IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ ++ return (-EACCES); ++ } ++ ++ if (((struct inode_data *)dir->FSPRIVATE)) { ++ uid = Scope_Get_Uid(((struct inode_data *)dir->FSPRIVATE)->Scope); ++ if (mode & (S_IFREG | S_IFDIR)) { ++ inode = ++ Novfs_get_inode(dir->i_sb, mode, dev, uid, 0, &dentry->d_name); ++ } ++ } ++ if (inode) { ++ struct entry_info info; ++ ++ dentry->d_op = &Novfs_dentry_operations; ++ parent = dget_parent(dentry); ++ Novfs_d_add(parent, dentry, inode, 0); ++ memset(&info, 0, sizeof(info)); ++ info.mode = inode->i_mode; ++ Novfs_lock_inode_cache(dir); ++ Novfs_add_inode_entry(dir, &dentry->d_name, inode->i_ino, ++ &info); ++ Novfs_unlock_inode_cache(dir); ++ ++ dput(parent); ++ ++ retCode = 0; ++ } ++ DbgPrint("Novfs_i_mknod: return 0x%x\n", retCode); ++ return retCode; ++} ++ ++int Novfs_i_rename(struct inode *odir, struct dentry *od, struct inode *ndir, ++ struct dentry *nd) ++{ ++ int retCode = -ENOTEMPTY; ++ char *newpath, *newbuf, *newcon; ++ char *oldpath, *oldbuf, *oldcon; ++ struct qstr newname, oldname; ++ struct entry_info *info = NULL; ++ int oldlen, newlen; ++ session_t session; ++ ino_t ino; ++ ++ if (IS_ROOT(od) || /* Root */ ++ IS_ROOT(od->d_parent) || /* User */ ++ IS_ROOT(od->d_parent->d_parent) || /* Server */ ++ IS_ROOT(od->d_parent->d_parent->d_parent)) { /* Volume */ ++ return (-EACCES); ++ } ++ ++ DbgPrint("Novfs_i_rename: odir=0x%p ino=%d ndir=0x%p ino=%d\n", odir, ++ odir->i_ino, ndir, ndir->i_ino); ++ ++ oldbuf = Novfs_Malloc(PATH_LENGTH_BUFFER * 2, GFP_KERNEL); ++ newbuf = oldbuf + PATH_LENGTH_BUFFER; ++ if (oldbuf && newbuf) { ++ oldpath = Novfs_dget_path(od, oldbuf, PATH_LENGTH_BUFFER); ++ newpath = Novfs_dget_path(nd, newbuf, PATH_LENGTH_BUFFER); ++ if (oldpath && newpath) { ++ oldlen = PATH_LENGTH_BUFFER - (int)(oldpath - oldbuf); ++ newlen = PATH_LENGTH_BUFFER - (int)(newpath - newbuf); ++ ++ DbgPrint ++ ("Novfs_i_rename: od=0x%p od->inode=0x%p od->inode->i_ino=%d %s\n", ++ od, od->d_inode, od->d_inode->i_ino, oldpath); ++ if (nd->d_inode) { ++ DbgPrint ++ ("Novfs_i_rename: nd=0x%p nd->inode=0x%p nd->inode->i_ino=%d %s\n", ++ nd, nd->d_inode, nd->d_inode->i_ino, ++ newpath); ++ } else { ++ DbgPrint ++ ("Novfs_i_rename: nd=0x%p nd->inode=0x%p %s\n", ++ nd, nd->d_inode, newpath); ++ } ++ ++ /* ++ * Check to see if two different servers or different volumes ++ */ ++ newcon = strchr(newpath + 1, '\\'); ++ oldcon = strchr(oldpath + 1, '\\'); ++ DbgPrint("Novfs_i_rename: newcon=0x%p newpath=0x%p\n", ++ newcon, newpath); ++ DbgPrint("Novfs_i_rename: oldcon=0x%p oldpath=0x%p\n", ++ oldcon, oldpath); ++ retCode = -EXDEV; ++ if (newcon && oldcon ++ && ((int)(newcon - newpath) == ++ (int)(oldcon - oldpath))) { ++ newcon = strchr(newcon + 1, '\\'); ++ oldcon = strchr(oldcon + 1, '\\'); ++ DbgPrint("Novfs_i_rename2: newcon=0x%p newpath=0x%p\n", newcon, newpath); ++ DbgPrint("Novfs_i_rename2: oldcon=0x%p oldpath=0x%p\n", oldcon, oldpath); ++ if (newcon && oldcon && ++ ((int)(newcon - newpath) == (int)(oldcon - oldpath))) { ++ newname.name = newpath; ++ newname.len = (int)(newcon - newpath); ++ newname.hash = 0; ++ ++ oldname.name = oldpath; ++ oldname.len = (int)(oldcon - oldpath); ++ oldname.hash = 0; ++ if (!Novfs_d_strcmp(&newname, &oldname)) { ++ ++ if (od->d_inode ++ && od->d_inode->FSPRIVATE) { ++ ++ if ((nd->d_inode) && ++ (nd->d_inode->FSPRIVATE)) { ++ session = Scope_Get_SessionId(((struct inode_data *)ndir->FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)ndir->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(nd); ++ session = Scope_Get_SessionId(((struct inode_data *)ndir->FSPRIVATE)->Scope); ++ } ++ ++ retCode = Novfs_Delete(newpath, S_ISDIR(nd->d_inode->i_mode), session); ++ } ++ ++ session = Scope_Get_SessionId(((struct inode_data *) ndir->FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)ndir->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(nd); ++ session = Scope_Get_SessionId(((struct inode_data *) ndir->FSPRIVATE)->Scope); ++ } ++ retCode = Novfs_Rename_File(S_ISDIR(od->d_inode->i_mode), oldpath, oldlen - 1, newpath, newlen - 1, session); ++ ++ if (!retCode) { ++ info = (struct entry_info *) oldbuf; ++ od->d_time = 0; ++ Novfs_remove_inode_entry(odir, &od->d_name, 0); ++ Novfs_remove_inode_entry(ndir, &nd->d_name, 0); ++ Novfs_Get_File_Info(newpath, info, &session); ++ nd->d_time = jiffies + (File_update_timeout * HZ); ++ ++ if (od->d_inode && od->d_inode->i_ino) { ++ ino = od->d_inode-> i_ino; ++ } else { ++ ino = (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ } ++ Novfs_add_inode_entry(ndir, &nd->d_name, ino, info); ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ if (oldbuf) ++ kfree(oldbuf); ++ ++ DbgPrint("Novfs_i_rename: return %d\n", retCode); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_permission(struct inode *inode, int mask) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_setattr(struct dentry *dentry, struct iattr *attr) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ char *path, *buf; ++ struct inode *inode = dentry->d_inode; ++ char atime_buf[32]; ++ char mtime_buf[32]; ++ char ctime_buf[32]; ++ unsigned int ia_valid = attr->ia_valid; ++ session_t session; ++ int retVal = 0; ++ struct iattr mattr; ++ ++ if (IS_ROOT(dentry) || /* Root */ ++ IS_ROOT(dentry->d_parent) || /* User */ ++ IS_ROOT(dentry->d_parent->d_parent) || /* Server */ ++ IS_ROOT(dentry->d_parent->d_parent->d_parent)) { /* Volume */ ++ return (-EACCES); ++ } ++ ++ if (inode && inode->FSPRIVATE) { ++ session = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ if (0 == SC_PRESENT(session)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(dentry); ++ session = ++ Scope_Get_SessionId(((struct inode_data *) inode-> ++ FSPRIVATE)->Scope); ++ } ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ strcpy(atime_buf, "Unspecified"); ++ strcpy(mtime_buf, "Unspecified"); ++ strcpy(ctime_buf, "Unspecified"); ++ if (attr->ia_valid & ATTR_ATIME) { ++ ctime_r(&attr->ia_atime.tv_sec, ++ atime_buf); ++ } ++ if (attr->ia_valid & ATTR_MTIME) { ++ ctime_r(&attr->ia_mtime.tv_sec, ++ mtime_buf); ++ } ++ if (attr->ia_valid & ATTR_CTIME) { ++ ctime_r(&attr->ia_ctime.tv_sec, ++ ctime_buf); ++ } ++ /* Removed for Bug 132374. jlt */ ++ DbgPrint("Novfs_i_setattr: %s\n" ++ " ia_valid: 0x%x\n" ++ " ia_mode: 0%o\n" ++ " ia_uid: %d\n" ++ " ia_gid: %d\n" ++ " ia_size: %lld\n" ++ " ia_atime: %s\n" ++ " ia_mtime: %s\n" ++ " ia_ctime: %s\n", ++ path, ++ attr->ia_valid, ++ attr->ia_mode, ++ attr->ia_uid, ++ attr->ia_gid, ++ attr->ia_size, ++ atime_buf, mtime_buf, ctime_buf); ++ ++ if ((attr->ia_valid & ATTR_FILE) ++ && (attr->ia_valid & ATTR_SIZE)) { ++ memcpy(&mattr, attr, sizeof(mattr)); ++ mattr.ia_valid &= ++ ~(ATTR_FILE | ATTR_SIZE); ++ attr = &mattr; ++ ia_valid = attr->ia_valid; ++#if 0 // thanks to vfs changes in our tree... ++ retVal = Novfs_Truncate_File_Ex(attr->ia_file->private_data, attr->ia_size, session); ++ if (!retVal) { ++ inode->i_size = attr->ia_size; ++ ((struct inode_data *)inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ } ++#endif ++ } ++ ++ if (ia_valid ++ && !(retVal = ++ Novfs_Set_Attr(path, attr, session))) { ++ ((struct inode_data *)inode->FSPRIVATE)->Flags |= UPDATE_INODE; ++ ++ if (ia_valid & ATTR_ATIME) ++ inode->i_atime = attr->ia_atime; ++ if (ia_valid & ATTR_MTIME) ++ inode->i_mtime = attr->ia_mtime; ++ if (ia_valid & ATTR_CTIME) ++ inode->i_ctime = attr->ia_ctime; ++ if (ia_valid & ATTR_MODE) { ++ inode->i_mode = ++ attr-> ++ ia_mode & (S_IFMT | ++ S_IRWXU); ++ } ++ } ++ } ++ } ++ kfree(buf); ++ } ++ DbgPrint("Novfs_i_setattr: return 0x%x\n", retVal); ++ ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_getattr(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *kstat) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retCode = 0; ++ char atime_buf[32]; ++ char mtime_buf[32]; ++ char ctime_buf[32]; ++ struct inode *inode = dentry->d_inode; ++ ++ struct entry_info info; ++ char *path, *buf; ++ session_t session; ++ struct inode_data *id; ++ ++ if (!IS_ROOT(dentry) && !IS_ROOT(dentry->d_parent)) { ++ SC_INITIALIZE(session); ++ id = dentry->d_inode->FSPRIVATE; ++ ++ if (id && (id->Flags & UPDATE_INODE)) { ++ session = Scope_Get_SessionId(id->Scope); ++ ++ if (0 == SC_PRESENT(session)) { ++ id->Scope = Scope_Get_ScopefromPath(dentry); ++ session = Scope_Get_SessionId(id->Scope); ++ } ++ ++ buf = ++ (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, ++ GFP_KERNEL); ++ if (buf) { ++ path = ++ Novfs_dget_path(dentry, buf, ++ PATH_LENGTH_BUFFER); ++ if (path) { ++ retCode = Novfs_Get_File_Info(path, &info, &session); ++ if (!retCode) { ++ update_inode(inode, &info); ++ id->Flags &= ~UPDATE_INODE; ++ } ++ } ++ kfree(buf); ++ } ++ } ++ } ++ ++ kstat->ino = inode->i_ino; ++ kstat->dev = inode->i_sb->s_dev; ++ kstat->mode = inode->i_mode; ++ kstat->nlink = inode->i_nlink; ++ kstat->uid = inode->i_uid; ++ kstat->gid = inode->i_gid; ++ kstat->rdev = inode->i_rdev; ++ kstat->size = i_size_read(inode); ++ kstat->atime = inode->i_atime; ++ kstat->mtime = inode->i_mtime; ++ kstat->ctime = inode->i_ctime; ++ kstat->blksize = inode->i_sb->s_blocksize; ++ kstat->blocks = inode->i_blocks; ++ if (inode->i_bytes) { ++ kstat->blocks++; ++ } ++ ctime_r(&kstat->atime.tv_sec, atime_buf); ++ ctime_r(&kstat->mtime.tv_sec, mtime_buf); ++ ctime_r(&kstat->ctime.tv_sec, ctime_buf); ++ ++ DbgPrint("Novfs_i_getattr: 0x%x 0x%p <%.*s>\n" ++ " ino: %d\n" ++ " dev: 0x%x\n" ++ " mode: 0%o\n" ++ " nlink: 0x%x\n" ++ " uid: 0x%x\n" ++ " gid: 0x%x\n" ++ " rdev: 0x%x\n" ++ " size: 0x%llx\n" ++ " atime: %s\n" ++ " mtime: %s\n" ++ " ctime: %s\n" ++ " blksize: 0x%x\n" ++ " blocks: 0x%x\n", ++ retCode, dentry, dentry->d_name.len, dentry->d_name.name, ++ kstat->ino, ++ kstat->dev, ++ kstat->mode, ++ kstat->nlink, ++ kstat->uid, ++ kstat->gid, ++ kstat->rdev, ++ kstat->size, ++ atime_buf, ++ mtime_buf, ctime_buf, kstat->blksize, kstat->blocks); ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_getxattr(struct dentry *dentry, const char *name, void *buffer, ++ size_t buffer_size) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode *inode = dentry->d_inode; ++ session_t sessionId; ++ char *path, *buf, *bufRead; ++ ssize_t dataLen; ++ ++ int retxcode = 0; ++ ++ SC_INITIALIZE(sessionId); ++ ++ DbgPrint("Novfs_i_getxattr: Ian\n"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ ++ DbgPrint ++ ("Novfs_i_getxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", ++ dentry->d_name.len, dentry->d_name.name); ++ DbgPrint("Novfs_i_getxattr: name %s\n", name); ++ DbgPrint("Novfs_i_getxattr: size %u\n", buffer_size); ++ ++ if (inode && inode->FSPRIVATE) { ++ sessionId = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ DbgPrint("Novfs_i_getxattr: SessionId = %u\n", sessionId); ++ //if (0 == sessionId) ++ if (0 == SC_PRESENT(sessionId)) { ++ ((struct inode_data *) inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(dentry); ++ sessionId = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ DbgPrint("Novfs_i_getxattr: SessionId = %u\n", ++ sessionId); ++ } ++ } ++ ++ dataLen = 0; ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ bufRead = (char *)Novfs_Malloc(XA_BUFFER, GFP_KERNEL); ++ if (bufRead) { ++ retxcode = Novfs_GetX_File_Info(path, name, bufRead, XA_BUFFER, &dataLen, &sessionId); ++ DbgPrint("Novfs_i_getxattr: after Novfs_GetX_File_Info retxcode = %d\n", retxcode); ++ if (!retxcode) { ++ mydump(64, bufRead); ++ if (buffer_size != 0) { ++ if (buffer_size >= dataLen) { ++ memcpy(buffer, bufRead, ++ dataLen); ++ } else { ++ DbgPrint ++ ("Novfs_i_getxattr: (!!!) not enough buffer_size. buffer_size = %d, dataLen = %d\n", ++ buffer_size, ++ dataLen); ++ retxcode = -ERANGE; ++ } ++ } ++ ++ if (bufRead) { ++ kfree(bufRead); ++ } ++ } ++ } ++ } ++ kfree(buf); ++ } ++ ++ if (retxcode) { ++ dataLen = retxcode; ++ } else { ++ if ((buffer_size > 0) && (buffer_size < dataLen)) { ++ dataLen = -ERANGE; ++ } ++ } ++ ++ return (dataLen); ++} ++ ++/*++======================================================================*/ ++int Novfs_i_setxattr(struct dentry *dentry, const char *name, const void *value, ++ size_t value_size, int flags) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ ++ struct inode *inode = dentry->d_inode; ++ session_t sessionId; ++ char *path, *buf; ++ unsigned long bytesWritten = 0; ++ int retError = 0; ++ int retxcode = 0; ++ ++ SC_INITIALIZE(sessionId); ++ ++ DbgPrint("Novfs_i_setxattr: Ian\n"); /*%.*s\n", dentry->d_name.len, dentry->d_name.name); */ ++ DbgPrint ++ ("Novfs_i_setxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", ++ dentry->d_name.len, dentry->d_name.name); ++ DbgPrint("Novfs_i_setxattr: name %s\n", name); ++ DbgPrint("Novfs_i_setxattr: value_size %u\n", value_size); ++ DbgPrint("Novfs_i_setxattr: flags %d\n", flags); ++ ++ if (inode && inode->FSPRIVATE) { ++ sessionId = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)-> ++ Scope); ++ DbgPrint("Novfs_i_setxattr: SessionId = %u\n", sessionId); ++ //if (0 == sessionId) ++ if (0 == SC_PRESENT(sessionId)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = ++ Scope_Get_ScopefromPath(dentry); ++ sessionId = ++ Scope_Get_SessionId(((struct inode_data *)inode-> ++ FSPRIVATE)->Scope); ++ DbgPrint("Novfs_i_setxattr: SessionId = %u\n", ++ sessionId); ++ } ++ } ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ retxcode = ++ Novfs_SetX_File_Info(path, name, value, value_size, ++ &bytesWritten, flags, ++ &sessionId); ++ if (!retxcode) { ++ DbgPrint ++ ("Novfs_i_setxattr: bytesWritten = %u\n", ++ bytesWritten); ++ } ++ } ++ kfree(buf); ++ } ++ ++ if (retxcode) { ++ retError = retxcode; ++ } ++ ++ if (bytesWritten < value_size) { ++ retError = retxcode; ++ } ++ return (retError); ++} ++ ++int Novfs_i_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) ++{ ++ struct inode *inode = dentry->d_inode; ++ session_t sessionId; ++ char *path, *buf, *bufList; ++ ssize_t dataLen; ++ ++ int retxcode = 0; ++ ++ SC_INITIALIZE(sessionId); ++ ++ DbgPrint("Novfs_i_listxattr: Ian\n"); //%.*s\n", dentry->d_name.len, dentry->d_name.name); ++ DbgPrint ++ ("Novfs_i_listxattr: dentry->d_name.len %u, dentry->d_name.name %s\n", ++ dentry->d_name.len, dentry->d_name.name); ++ DbgPrint("Novfs_i_listxattr: size %u\n", buffer_size); ++ ++ if (inode && inode->FSPRIVATE) { ++ sessionId = ++ Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)-> Scope); ++ DbgPrint("Novfs_i_listxattr: SessionId = %u\n", sessionId); ++ //if (0 == sessionId) ++ if (0 == SC_PRESENT(sessionId)) { ++ ((struct inode_data *)inode->FSPRIVATE)->Scope = Scope_Get_ScopefromPath(dentry); ++ sessionId = Scope_Get_SessionId(((struct inode_data *)inode->FSPRIVATE)->Scope); ++ DbgPrint("Novfs_i_listxattr: SessionId = %u\n", ++ sessionId); ++ } ++ } ++ ++ dataLen = 0; ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Novfs_dget_path(dentry, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ bufList = (char *)Novfs_Malloc(XA_BUFFER, GFP_KERNEL); ++ if (bufList) { ++ retxcode = Novfs_ListX_File_Info(path, bufList, XA_BUFFER, &dataLen, &sessionId); ++ ++ mydump(64, bufList); ++ if (buffer_size != 0) { ++ if (buffer_size >= dataLen) { ++ memcpy(buffer, bufList, ++ dataLen); ++ } else { ++ DbgPrint ++ ("Novfs_i_listxattr: (!!!) not enough buffer_size. buffer_size = %d, dataLen = %d\n", ++ buffer_size, dataLen); ++ retxcode = -1; ++ } ++ } ++ ++ if (bufList) { ++ kfree(bufList); ++ } ++ } ++ ++ } ++ kfree(buf); ++ } ++ ++ if (retxcode) { ++ dataLen = -1; ++ } else { ++ ++ if ((buffer_size > 0) && (buffer_size < dataLen)) { ++ dataLen = -ERANGE; ++ } ++ } ++ return (dataLen); ++} ++ ++int Novfs_i_revalidate(struct dentry *dentry) ++{ ++ ++ DbgPrint("Novfs_i_revalidate: name %.*s\n", dentry->d_name.len, ++ dentry->d_name.name); ++ ++ return (0); ++} ++ ++void Novfs_read_inode(struct inode *inode) ++{ ++ DbgPrint("Novfs_read_inode: 0x%p %d\n", inode, inode->i_ino); ++} ++ ++void Novfs_write_inode(struct inode *inode) ++{ ++ DbgPrint("Novfs_write_inode: Inode=0x%p Ino=%d\n", inode, inode->i_ino); ++} ++ ++int Novfs_notify_change(struct dentry *dentry, struct iattr *attr) ++{ ++ struct inode *inode = dentry->d_inode; ++ ++ DbgPrint ++ ("Novfs_notify_change: Dentry=0x%p Name=%.*s Inode=0x%p Ino=%d ia_valid=0x%x\n", ++ dentry, dentry->d_name.len, dentry->d_name.name, inode, ++ inode->i_ino, attr->ia_valid); ++ return (0); ++} ++ ++/*++======================================================================*/ ++void Novfs_clear_inode(struct inode *inode) ++/* ++ * Arguments: sb - pointer to the super_block ++ * buf - pointer to the statfs buffer ++ * ++ * Returns: 0 ++ * ++ * Abstract: Called when statfs(2) system called. ++ * ++ * Notes: ++ * ++ * Environment: Superblock operation ++ * ++ *========================================================================*/ ++{ ++ InodeCount--; ++ ++ if (inode->FSPRIVATE) { ++ struct inode_data *id = inode->FSPRIVATE; ++ ++ DbgPrint ++ ("Novfs_clear_inode: inode=0x%p ino=%d Scope=0x%p Name=%s\n", ++ inode, inode->i_ino, id->Scope, id->Name); ++ ++ Novfs_free_inode_cache(inode); ++ ++ down(&InodeList_lock); ++ list_del(&id->IList); ++ up(&InodeList_lock); ++ ++ kfree(inode->FSPRIVATE); ++ inode->FSPRIVATE = NULL; ++ ++ remove_inode_hash(inode); ++ ++ } else { ++ DbgPrint("Novfs_clear_inode: inode=0x%p ino=%d\n", inode, ++ inode->i_ino); ++ } ++} ++ ++/*++======================================================================*/ ++int Novfs_show_options(struct seq_file *s, struct vfsmount *m) ++/* ++ * Arguments: ++ * ++ * Returns: 0 ++ * ++ * Abstract: Called when /proc/mounts is read ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ char *buf, *path, *tmp; ++ ++ buf = (char *)Novfs_Malloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ struct path my_path; ++ my_path.mnt = m; ++ my_path.dentry = m->mnt_root; ++ path = d_path(&my_path, buf, PATH_LENGTH_BUFFER); ++ if (path) { ++ if (!Novfs_CurrentMount ++ || (Novfs_CurrentMount ++ && strcmp(Novfs_CurrentMount, path))) { ++ DbgPrint("Novfs_show_options: %.*s %.*s %s\n", ++ m->mnt_root->d_name.len, ++ m->mnt_root->d_name.name, ++ m->mnt_mountpoint->d_name.len, ++ m->mnt_mountpoint->d_name.name, path); ++ tmp = ++ (char *)Novfs_Malloc(PATH_LENGTH_BUFFER - ++ (int)(path - buf), ++ GFP_KERNEL); ++ if (tmp) { ++ strcpy(tmp, path); ++ path = Novfs_CurrentMount; ++ Novfs_CurrentMount = tmp; ++ Daemon_SetMountPoint ++ (Novfs_CurrentMount); ++ ++ if (path) { ++ kfree(path); ++ } ++ } ++ } ++ } ++ kfree(buf); ++ } ++ return (0); ++} ++ ++/*++======================================================================*/ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++int Novfs_statfs(struct dentry *de, struct kstatfs *buf) ++#else ++int Novfs_statfs(struct super_block *sb, struct kstatfs *buf) ++#endif ++/* ++ * Arguments: sb - pointer to the super_block ++ * buf - pointer to the statfs buffer ++ * ++ * Returns: 0 ++ * ++ * Abstract: Called when statfs(2) system called. ++ * ++ * Notes: ++ * ++ * Environment: Superblock operation ++ * ++ *========================================================================*/ ++{ ++ uint64_t td, fd, te, fe; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++ struct super_block *sb = de->d_sb; ++#endif ++ ++ DbgPrint("Novfs_statfs:\n"); ++ ++ td = fd = te = fe = 0; ++ ++ Scope_Get_UserSpace(&td, &fd, &te, &fe); ++ ++ DbgPrint("td=%llu\n", td); ++ DbgPrint("fd=%llu\n", fd); ++ DbgPrint("te=%llu\n", te); ++ DbgPrint("fe=%llu\n", fd); ++ ++ buf->f_type = sb->s_magic; ++ buf->f_bsize = sb->s_blocksize; ++ buf->f_namelen = NW_MAX_PATH_LENGTH; ++ buf->f_blocks = ++ (sector_t) (td + ++ (uint64_t) (sb->s_blocksize - ++ 1)) >> (uint64_t) sb->s_blocksize_bits; ++ buf->f_bfree = (sector_t) fd >> (uint64_t) sb->s_blocksize_bits; ++ buf->f_bavail = (sector_t) buf->f_bfree; ++ buf->f_files = (sector_t) te; ++ buf->f_ffree = (sector_t) fe; ++ buf->f_frsize = sb->s_blocksize; ++ if (te > 0xffffffff) ++ buf->f_files = 0xffffffff; ++ ++ if (fe > 0xffffffff) ++ buf->f_ffree = 0xffffffff; ++ ++ DbgPrint("f_type: 0x%x\n", buf->f_type); ++ DbgPrint("f_bsize: %u\n", buf->f_bsize); ++ DbgPrint("f_namelen: %d\n", buf->f_namelen); ++ DbgPrint("f_blocks: %llu\n", buf->f_blocks); ++ DbgPrint("f_bfree: %llu\n", buf->f_bfree); ++ DbgPrint("f_bavail: %llu\n", buf->f_bavail); ++ DbgPrint("f_files: %llu\n", buf->f_files); ++ DbgPrint("f_ffree: %llu\n", buf->f_ffree); ++ DbgPrint("f_frsize: %u\n", buf->f_frsize); ++ ++ return 0; ++} ++ ++struct inode *Novfs_get_inode(struct super_block *sb, int mode, int dev, ++ uid_t Uid, ino_t ino, struct qstr *name) ++{ ++ struct inode *inode = new_inode(sb); ++ ++ if (inode) { ++ InodeCount++; ++ inode->i_mode = mode; ++ inode->i_uid = Uid; ++ inode->i_gid = 0; ++ /* bug # 340510 tells us to comment this out... */ ++//#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++// inode->i_blksize = sb->s_blocksize; ++//#else ++// inode->i_sb->s_blocksize = sb->s_blocksize; ++//#endif ++ inode->i_blkbits = sb->s_blocksize_bits; ++ inode->i_blocks = 0; ++ inode->i_rdev = 0; ++ inode->i_ino = (ino) ? ino : (ino_t)atomic_inc_return(&Novfs_Inode_Number); ++ if (PageCache) { ++ inode->i_mapping->a_ops = &Novfs_aops; ++ } else { ++ inode->i_mapping->a_ops = &Novfs_nocache_aops; ++ } ++ inode->i_mapping->backing_dev_info = &Novfs_backing_dev_info; ++ inode->i_atime.tv_sec = 0; ++ inode->i_atime.tv_nsec = 0; ++ inode->i_mtime = inode->i_ctime = inode->i_atime; ++ ++ DbgPrint("Novfs_get_inode: Inode=0x%p I_ino=%d len=%d\n", inode, ++ inode->i_ino, name->len); ++ ++ if (NULL != ++ (inode->FSPRIVATE = ++ Novfs_Malloc(sizeof(struct inode_data) + name->len, ++ GFP_KERNEL))) { ++ struct inode_data *id; ++ id = inode->FSPRIVATE; ++ ++ DbgPrint("Novfs_get_inode: FSPRIVATE 0x%p\n", id); ++ ++ id->Scope = NULL; ++ id->Flags = 0; ++ id->Inode = inode; ++ ++ id->cntDC = 1; ++ ++ INIT_LIST_HEAD(&id->DirCache); ++ init_MUTEX(&id->DirCacheLock); ++ ++ id->FileHandle = 0; ++ id->CacheFlag = 0; ++ ++ down(&InodeList_lock); ++ ++ list_add_tail(&id->IList, &InodeList); ++ up(&InodeList_lock); ++ ++ id->Name[0] = '\0'; ++ ++ memcpy(id->Name, name->name, name->len); ++ id->Name[name->len] = '\0'; ++ ++ DbgPrint("Novfs_get_inode: name %s\n", id->Name); ++ } ++ ++ insert_inode_hash(inode); ++ ++ switch (mode & S_IFMT) { ++ ++ case S_IFREG: ++ inode->i_op = &Novfs_file_inode_operations; ++ inode->i_fop = &Novfs_file_operations; ++ break; ++ ++ case S_IFDIR: ++ inode->i_op = &Novfs_inode_operations; ++ inode->i_fop = &Novfs_dir_operations; ++// Again bug #340510 ++//#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++// inode->i_blksize = 0; ++//#else ++// inode->i_sb->s_blocksize = 0; ++//#endif ++ inode->i_blkbits = 0; ++ break; ++ ++ default: ++ init_special_inode(inode, mode, dev); ++ break; ++ } ++ ++ DbgPrint("Novfs_get_inode: size=%lld\n", inode->i_size); ++ DbgPrint("Novfs_get_inode: mode=0%o\n", inode->i_mode); ++ DbgPrint("Novfs_get_inode: i_sb->s_blocksize=%d\n", ++ inode->i_sb->s_blocksize); ++ DbgPrint("Novfs_get_inode: i_blkbits=%d\n", inode->i_blkbits); ++ DbgPrint("Novfs_get_inode: i_blocks=%d\n", inode->i_blocks); ++ DbgPrint("Novfs_get_inode: i_bytes=%d\n", inode->i_bytes); ++ } ++ ++ DbgPrint("Novfs_get_inode: 0x%p %d\n", inode, inode->i_ino); ++ return (inode); ++} ++ ++int Novfs_fill_super(struct super_block *SB, void *Data, int Silent) ++{ ++ struct inode *inode; ++ struct dentry *server, *tree; ++ struct qstr name; ++ struct entry_info info; ++ ++ SB->s_blocksize = PAGE_CACHE_SIZE; ++ SB->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ SB->s_maxbytes = 0xFFFFFFFFFFFFFFFFULL; /* Max file size */ ++ SB->s_op = &Novfs_ops; ++ SB->s_flags |= (MS_NODIRATIME | MS_NODEV | MS_POSIXACL); ++ SB->s_magic = NOVFS_MAGIC; ++ ++ name.len = 1; ++ name.name = "/"; ++ ++ inode = Novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); ++ if (!inode) { ++ return (-ENOMEM); ++ } ++ ++ Novfs_root = d_alloc_root(inode); ++ ++ if (!Novfs_root) { ++ iput(inode); ++ return (-ENOMEM); ++ } ++ Novfs_root->d_time = jiffies + (File_update_timeout * HZ); ++ ++ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; ++ ++ SB->s_root = Novfs_root; ++ ++ DbgPrint("Novfs_fill_super: root 0x%p\n", Novfs_root); ++ ++ if (Novfs_root) { ++ Novfs_root->d_op = &Novfs_dentry_operations; ++ ++ name.name = SERVER_DIRECTORY_NAME; ++ name.len = strlen(SERVER_DIRECTORY_NAME); ++ name.hash = Novfs_internal_hash(&name); ++ ++ inode = Novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); ++ if (inode) { ++ info.mode = inode->i_mode; ++ info.namelength = 0; ++ inode->i_size = info.size = 0; ++ inode->i_uid = info.uid = 0; ++ inode->i_gid = info.gid = 0; ++ inode->i_atime = info.atime = ++ inode->i_ctime = info.ctime = ++ inode->i_mtime = info.mtime = CURRENT_TIME; ++ ++ server = d_alloc(Novfs_root, &name); ++ if (server) { ++ server->d_op = &Novfs_dentry_operations; ++ server->d_time = 0xffffffff; ++ d_add(server, inode); ++ DbgPrint("Novfs_fill_super: d_add %s 0x%p\n", ++ SERVER_DIRECTORY_NAME, server); ++ Novfs_add_inode_entry(Novfs_root->d_inode, ++ &name, inode->i_ino, ++ &info); ++ } ++ } ++ ++ name.name = TREE_DIRECTORY_NAME; ++ name.len = strlen(TREE_DIRECTORY_NAME); ++ name.hash = Novfs_internal_hash(&name); ++ ++ inode = Novfs_get_inode(SB, S_IFDIR | 0777, 0, 0, 0, &name); ++ if (inode) { ++ info.mode = inode->i_mode; ++ info.namelength = 0; ++ inode->i_size = info.size = 0; ++ inode->i_uid = info.uid = 0; ++ inode->i_gid = info.gid = 0; ++ inode->i_atime = info.atime = ++ inode->i_ctime = info.ctime = ++ inode->i_mtime = info.mtime = CURRENT_TIME; ++ tree = d_alloc(Novfs_root, &name); ++ if (tree) { ++ tree->d_op = &Novfs_dentry_operations; ++ tree->d_time = 0xffffffff; ++ ++ d_add(tree, inode); ++ DbgPrint("Novfs_fill_super: d_add %s 0x%p\n", ++ TREE_DIRECTORY_NAME, tree); ++ Novfs_add_inode_entry(Novfs_root->d_inode, ++ &name, inode->i_ino, ++ &info); ++ } ++ } ++ } ++ ++ return (0); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++int Novfs_get_sb(struct file_system_type *Fstype, int Flags, ++ const char *Dev_name, void *Data, struct vfsmount *Mnt) ++#else ++struct super_block *Novfs_get_sb(struct file_system_type *Fstype, int Flags, ++ const char *Dev_name, void *Data) ++#endif ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++ int sb; ++#else ++ struct super_block *sb; ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++ sb = get_sb_nodev(Fstype, Flags, Data, Novfs_fill_super, Mnt); ++#else ++ sb = get_sb_nodev(Fstype, Flags, Data, Novfs_fill_super); ++#endif ++ ++ DbgPrint("Novfs_get_sb: sb=0x%p Fstype=0x%x Dev_name=%s\n", sb, Fstype, ++ Dev_name); ++ ++ return (sb); ++} ++ ++static void novfs_kill_sb(struct super_block *super) ++{ ++ /* calling shrink_dcache_sb() fixes novell bugzilla #345179, but I'm ++ * not so sure about it... */ ++ shrink_dcache_sb(super); ++ kill_litter_super(super); ++} ++ ++ssize_t Novfs_Control_read(struct file *file, char *buf, size_t nbytes, ++ loff_t * ppos) ++{ ++ ssize_t retval = 0; ++ ++ DbgPrint("Novfs_Control_read: kernel_locked 0x%x\n", kernel_locked()); ++ ++ return retval; ++} ++ ++ssize_t Novfs_Control_write(struct file * file, const char *buf, size_t nbytes, ++ loff_t * ppos) ++{ ++ ssize_t retval = 0; ++ ++ DbgPrint("Novfs_Control_write: kernel_locked 0x%x\n", kernel_locked()); ++ if (buf && nbytes) { ++ } ++ ++ return (retval); ++} ++ ++int Novfs_Control_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int retval = 0; ++ ++ DbgPrint("Novfs_Control_ioctl: kernel_locked 0x%x\n", kernel_locked()); ++ ++ return (retval); ++} ++ ++static struct file_system_type Novfs_fs_type = { ++ .name = "novfs", ++ .get_sb = Novfs_get_sb, ++ .kill_sb = novfs_kill_sb, ++ .owner = THIS_MODULE, ++}; ++ ++int __init init_novfs(void) ++{ ++ int retCode; ++ ++ lastDir[0] = 0; ++ lastTime = get_nanosecond_time(); ++ ++ inHAX = 0; ++ inHAXTime = get_nanosecond_time(); ++ ++ retCode = Init_Procfs_Interface(); ++ ++ init_profile(); ++ ++ if (!retCode) { ++ DbgPrint("init_novfs: %s %s %s\n", __DATE__, __TIME__, ++ NOVFS_VERSION_STRING); ++ Init_Daemon_Queue(); ++ Scope_Init(); ++ retCode = register_filesystem(&Novfs_fs_type); ++ if (retCode) { ++ Uninit_Procfs_Interface(); ++ Uninit_Daemon_Queue(); ++ Scope_Uninit(); ++ } ++ } ++ return (retCode); ++} ++ ++void __exit exit_novfs(void) ++{ ++ printk(KERN_INFO "exit_novfs\n"); ++ ++ Scope_Uninit(); ++ printk(KERN_INFO "exit_novfs after Scope_Uninit\n"); ++ ++ Uninit_Daemon_Queue(); ++ printk(KERN_INFO "exit_novfs after Uninit_Daemon_Queue\n"); ++ ++ uninit_profile(); ++ printk(KERN_INFO "exit_novfs after uninit_profile\n"); ++ ++ Uninit_Procfs_Interface(); ++ printk(KERN_INFO "exit_novfs Uninit_Procfs_Interface\n"); ++ ++ unregister_filesystem(&Novfs_fs_type); ++ printk(KERN_INFO "exit_novfs: Exit\n"); ++ ++ if (Novfs_CurrentMount) { ++ kfree(Novfs_CurrentMount); ++ Novfs_CurrentMount = NULL; ++ } ++} ++ ++int Novfs_lock_inode_cache(struct inode *i) ++/* ++ * ++ * Arguments: struct inode *i - pointer to directory inode ++ * ++ * Returns: 0 - locked ++ * -1 - not locked ++ * ++ * Abstract: Locks the inode cache. ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ int retVal = 0; ++ ++ DbgPrint("Novfs_lock_inode_cache: 0x%p\n", i); ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ down(&id->DirCacheLock); ++ retVal = 1; ++ } ++ DbgPrint("Novfs_lock_inode_cache: return %d\n", retVal); ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++void Novfs_unlock_inode_cache(struct inode *i) ++/* ++ * Arguments: struct inode *i - pointer to directory inode ++ * ++ * Returns: nothing ++ * ++ * Abstract: Unlocks inode cache. ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ up(&id->DirCacheLock); ++ } ++} ++ ++/*++======================================================================*/ ++int Novfs_enumerate_inode_cache(struct inode *i, struct list_head **iteration, ++ ino_t * ino, struct entry_info *info) ++/* ++ * Arguments: struct inode *i - pointer to directory inode ++ * ++ * Returns: 0 - item found ++ * -1 - done ++ * ++ * Abstract: Unlocks inode cache. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct list_head *l = NULL; ++ int retVal = -1; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if ((NULL == iteration) || (NULL == *iteration)) { ++ l = id->DirCache.next; ++ } else { ++ l = *iteration; ++ } ++ ++ if (l == &id->DirCache) { ++ l = NULL; ++ } else { ++ dc = list_entry(l, struct dir_cache, list); ++ ++ *ino = dc->ino; ++ info->type = 0; ++ info->mode = dc->mode; ++ info->size = dc->size; ++ info->atime = dc->atime; ++ info->mtime = dc->mtime; ++ info->ctime = dc->ctime; ++ info->namelength = dc->nameLen; ++ memcpy(info->name, dc->name, dc->nameLen); ++ info->name[dc->nameLen] = '\0'; ++ retVal = 0; ++ ++ l = l->next; ++ } ++ } ++ *iteration = l; ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_get_entry(struct inode *i, struct qstr *name, ino_t * ino, ++ struct entry_info *info) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ int retVal = -1; ++ char *n = ""; ++ int nl = 6; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (name && name->len) { ++ n = (char *)name->name; ++ nl = name->len; ++ } ++ ++ dc = Novfs_lookup_inode_cache(i, name, *ino); ++ if (dc) { ++ dc->flags |= ENTRY_VALID; ++ retVal = 0; ++ *ino = dc->ino; ++ info->type = 0; ++ info->mode = dc->mode; ++ info->size = dc->size; ++ info->atime = dc->atime; ++ info->mtime = dc->mtime; ++ info->ctime = dc->ctime; ++ info->namelength = dc->nameLen; ++ memcpy(info->name, dc->name, dc->nameLen); ++ info->name[dc->nameLen] = '\0'; ++ retVal = 0; ++ } ++ ++ DbgPrint("Novfs_get_entry:\n" ++ " inode: 0x%p\n" ++ " name: %.*s\n" " ino: %d\n", i, nl, n, *ino); ++ } ++ DbgPrint("Novfs_get_entry: return %d\n", retVal); ++ return (retVal); ++} ++ ++int Novfs_get_entry_by_pos(struct inode *i, loff_t pos, ino_t * ino, ++ struct entry_info *info) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ int retVal = -1; ++ loff_t count = 0; ++ loff_t i_pos = pos - 2; ++ struct list_head *inter = NULL; ++ while (!Novfs_enumerate_inode_cache(i, &inter, ino, info)) { ++ DbgPrint ++ ("Novfs_dir_readdir : Novfs_get_entry_by_pos : info->name = %s\n", ++ info->name); ++ if (count == i_pos) { ++ retVal = 0; ++ break; ++ } else ++ count++; ++ } ++ ++ return retVal; ++} ++ ++/*++======================================================================*/ ++int Novfs_get_entry_time(struct inode *i, struct qstr *name, ino_t * ino, ++ struct entry_info *info, u64 * EntryTime) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ int retVal = -1; ++ char *n = ""; ++ int nl = 6; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (name && name->len) { ++ n = (char *)name->name; ++ nl = name->len; ++ } ++ DbgPrint("Novfs_get_entry_time:\n" ++ " inode: 0x%p\n" ++ " name: %.*s\n" " ino: %d\n", i, nl, n, *ino); ++ ++ dc = Novfs_lookup_inode_cache(i, name, *ino); ++ if (dc) { ++ retVal = 0; ++ *ino = dc->ino; ++ info->type = 0; ++ info->mode = dc->mode; ++ info->size = dc->size; ++ info->atime = dc->atime; ++ info->mtime = dc->mtime; ++ info->ctime = dc->ctime; ++ info->namelength = dc->nameLen; ++ memcpy(info->name, dc->name, dc->nameLen); ++ info->name[dc->nameLen] = '\0'; ++ if (EntryTime) { ++ *EntryTime = dc->jiffies; ++ } ++ retVal = 0; ++ } ++ } ++ DbgPrint("Novfs_get_entry_time: return %d\n", retVal); ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_get_remove_entry(struct inode *i, ino_t * ino, struct entry_info *info) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: This routine will return the first entry on the list ++ * and then remove it. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct list_head *l = NULL; ++ int retVal = -1; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ l = id->DirCache.next; ++ ++ if (l != &id->DirCache) { ++ dc = list_entry(l, struct dir_cache, list); ++ ++ *ino = dc->ino; ++ info->type = 0; ++ info->mode = dc->mode; ++ info->size = dc->size; ++ info->atime = dc->atime; ++ info->mtime = dc->mtime; ++ info->ctime = dc->ctime; ++ info->namelength = dc->nameLen; ++ memcpy(info->name, dc->name, dc->nameLen); ++ info->name[dc->nameLen] = '\0'; ++ retVal = 0; ++ ++ list_del(&dc->list); ++ kfree(dc); ++ DCCount--; ++ ++ id->cntDC--; ++ } ++ } ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++void Novfs_invalidate_inode_cache(struct inode *i) ++/* ++ * Arguments: struct inode *i - pointer to directory inode ++ * ++ * Returns: nothing ++ * ++ * Abstract: Marks all entries in the directory cache as invalid. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct list_head *l; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ list_for_each(l, &id->DirCache) { ++ dc = list_entry(l, struct dir_cache, list); ++ dc->flags &= ~ENTRY_VALID; ++ } ++ } ++} ++ ++/*++======================================================================*/ ++static struct dir_cache *Novfs_lookup_inode_cache(struct inode *i, struct qstr *name, ino_t ino) ++/* ++ * Arguments: struct inode *i - pointer to directory inode ++ * struct qstr *name - pointer to name ++ * ino_t - inode number ++ * ++ * Returns: struct dir_cache entry if match ++ * NULL - if there is no match. ++ * ++ * Abstract: Checks a inode directory to see if there are any enties ++ * matching name or ino. If name is specified then ino is ++ * not used. ino is use if name is not specified. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct dir_cache *retVal = NULL; ++ struct list_head *l; ++ char *n = ""; ++ int nl = 6; ++ int hash = 0; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (name && name->name) { ++ nl = name->len; ++ n = (char *)name->name; ++ hash = name->hash; ++ } ++ DbgPrint("Novfs_lookup_inode_cache:\n" ++ " inode: 0x%p\n" ++ " name: %.*s\n" ++ " hash: 0x%x\n" ++ " len: %d\n" ++ " ino: %d\n", i, nl, n, hash, nl, ino); ++ ++ list_for_each(l, &id->DirCache) { ++ dc = list_entry(l, struct dir_cache, list); ++ if (name) { ++ ++/* DbgPrint("Novfs_lookup_inode_cache: 0x%p\n" \ ++ " ino: %d\n" \ ++ " hash: 0x%x\n" \ ++ " len: %d\n" \ ++ " name: %.*s\n", ++ dc, dc->ino, dc->hash, dc->nameLen, dc->nameLen, dc->name); ++*/ ++ if ((name->hash == dc->hash) && ++ (name->len == dc->nameLen) && ++ (0 == ++ memcmp(name->name, dc->name, name->len))) { ++ retVal = dc; ++ break; ++ } ++ } else { ++ if (ino == dc->ino) { ++ retVal = dc; ++ break; ++ } ++ } ++ } ++ } ++ ++ DbgPrint("Novfs_lookup_inode_cache: return 0x%p\n", retVal); ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_lookup_validate(struct inode *i, struct qstr *name, ino_t ino) ++/* ++ * Arguments: struct inode *i - pointer to directory inode ++ * struct qstr *name - pointer to name ++ * ino_t - inode number ++ * ++ * Returns: 0 if found ++ * !0 if not found ++ * ++ * Abstract: Checks a inode directory to see if there are any enties ++ * matching name or ino. If entry is found the valid bit ++ * is set. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ int retVal = -1; ++ char *n = ""; ++ int nl = 6; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ if (name && name->len) { ++ n = (char *)name->name; ++ nl = name->len; ++ } ++ DbgPrint("Novfs_update_entry:\n" ++ " inode: 0x%p\n" ++ " name: %.*s\n" " ino: %d\n", i, nl, n, ino); ++ ++ dc = Novfs_lookup_inode_cache(i, name, ino); ++ if (dc) { ++ dc->flags |= ENTRY_VALID; ++ retVal = 0; ++ } ++ } ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_add_inode_entry(struct inode *i, ++ struct qstr *name, ino_t ino, struct entry_info *info) ++/* ++ * Arguments: ++ * ++ * Returns: -ENOMEM - alloc error. ++ * 0 - success. ++ * ++ * Abstract: Added entry to directory cache. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *new; ++ int retVal = -ENOMEM; ++ struct dir_cache *todel; ++ struct list_head *todeltmp; ++ ++ //SClark ++ DbgPrint("Novfs_add_inode_entry:\n" " i: %u\n", i); ++ if ((id = i->FSPRIVATE)) { ++ DbgPrint(" i->FSPRIVATE: %p\n", id); ++ if (id->DirCache.next) ++ DbgPrint(" id->DirCache.next: %p\n", ++ id->DirCache.next); ++ } ++ //SClark ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ new = Novfs_Malloc(sizeof(struct dir_cache) + name->len, GFP_KERNEL); ++ if (new) { ++ id->cntDC++; ++ ++ DCCount++; ++ DbgPrint("Novfs_add_inode_entry:\n" ++ " inode: 0x%p\n" ++ " id: 0x%p\n" ++ " DC: 0x%p\n" ++ " new: 0x%p\n" ++ " name: %.*s\n" ++ " ino: %d\n" ++ " size: %lld\n" ++ " mode: 0x%x\n", ++ i, id, &id->DirCache, new, name->len, ++ name->name, ino, info->size, info->mode); ++ ++ retVal = 0; ++ new->flags = ENTRY_VALID; ++ new->jiffies = get_jiffies_64(); ++ new->size = info->size; ++ new->mode = info->mode; ++ new->atime = info->atime; ++ new->mtime = info->mtime; ++ new->ctime = info->ctime; ++ new->ino = ino; ++ new->hash = name->hash; ++ new->nameLen = name->len; ++ memcpy(new->name, name->name, name->len); ++ new->name[new->nameLen] = '\0'; ++ list_add(&new->list, &id->DirCache); ++ ++ if (id->cntDC > 20) { ++ todeltmp = id->DirCache.prev; ++ todel = list_entry(todeltmp, struct dir_cache, list); ++ ++ list_del(&todel->list); ++ ++ kfree(todel); ++ ++ DCCount--; ++ id->cntDC--; ++ } ++ } ++ } ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++int Novfs_update_entry(struct inode *i, struct qstr *name, ino_t ino, ++ struct entry_info *info) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ int retVal = -1; ++ char *n = ""; ++ int nl = 6; ++ char atime_buf[32]; ++ char mtime_buf[32]; ++ char ctime_buf[32]; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ ++ if (name && name->len) { ++ n = (char *)name->name; ++ nl = name->len; ++ } ++ ctime_r(&info->atime.tv_sec, atime_buf); ++ ctime_r(&info->mtime.tv_sec, mtime_buf); ++ ctime_r(&info->ctime.tv_sec, ctime_buf); ++ DbgPrint("Novfs_update_entry:\n" ++ " inode: 0x%p\n" ++ " name: %.*s\n" ++ " ino: %d\n" ++ " size: %lld\n" ++ " atime: %s\n" ++ " mtime: %s\n" ++ " ctime: %s\n", ++ i, nl, n, ino, info->size, atime_buf, mtime_buf, ++ ctime_buf); ++ ++ dc = Novfs_lookup_inode_cache(i, name, ino); ++ if (dc) { ++ retVal = 0; ++ dc->flags = ENTRY_VALID; ++ dc->jiffies = get_jiffies_64(); ++ dc->size = info->size; ++ dc->mode = info->mode; ++ dc->atime = info->atime; ++ dc->mtime = info->mtime; ++ dc->ctime = info->ctime; ++ ++ ctime_r(&dc->atime.tv_sec, atime_buf); ++ ctime_r(&dc->mtime.tv_sec, mtime_buf); ++ ctime_r(&dc->ctime.tv_sec, ctime_buf); ++ DbgPrint("Novfs_update_entry entry: 0x%p\n" ++ " flags: 0x%x\n" ++ " jiffies: %lld\n" ++ " ino: %d\n" ++ " size: %lld\n" ++ " mode: 0%o\n" ++ " atime: %s\n" ++ " mtime: %s %d\n" ++ " ctime: %s\n" ++ " hash: 0x%x\n" ++ " nameLen: %d\n" ++ " name: %s\n", ++ dc, dc->flags, dc->jiffies, dc->ino, dc->size, ++ dc->mode, atime_buf, mtime_buf, ++ dc->mtime.tv_nsec, ctime_buf, dc->hash, ++ dc->nameLen, dc->name); ++ } ++ } ++ DbgPrint("Novfs_update_entry: return %d\n", retVal); ++ return (retVal); ++} ++ ++/*++======================================================================*/ ++void Novfs_remove_inode_entry(struct inode *i, struct qstr *name, ino_t ino) ++/* ++ * Arguments: ++ * ++ * Returns: nothing ++ * ++ * Abstract: Removes entry from directory cache. You can specify a name ++ * or an inode number. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ char *n = ""; ++ int nl = 6; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ dc = Novfs_lookup_inode_cache(i, name, ino); ++ if (dc) { ++ if (name && name->name) { ++ nl = name->len; ++ n = (char *)name->name; ++ } ++ DbgPrint("Novfs_remove_inode_entry:\n" ++ " inode: 0x%p\n" ++ " id: 0x%p\n" ++ " DC: 0x%p\n" ++ " name: %.*s\n" ++ " ino: %d\n" ++ " entry: 0x%p\n" ++ " name: %.*s\n" ++ " ino: %d\n" ++ " next: 0x%p\n" ++ " prev: 0x%p\n", ++ i, id, &id->DirCache, nl, n, ino, dc, ++ dc->nameLen, dc->name, dc->ino, dc->list.next, ++ dc->list.prev); ++ list_del(&dc->list); ++ kfree(dc); ++ DCCount--; ++ ++ id->cntDC--; ++ } ++ } ++} ++ ++/*++======================================================================*/ ++void Novfs_free_invalid_entries(struct inode *i) ++/* ++ * Arguments: struct inode *i - pointer to directory inode. ++ * ++ * Returns: nothing ++ * ++ * Abstract: Frees all invalid entries in the directory cache. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct list_head *l; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ list_for_each(l, &id->DirCache) { ++ dc = list_entry(l, struct dir_cache, list); ++ if (0 == (dc->flags & ENTRY_VALID)) { ++ DbgPrint("Novfs_free_invalid_entries:\n" ++ " inode: 0x%p\n" ++ " id: 0x%p\n" ++ " entry: 0x%p\n" ++ " name: %.*s\n" ++ " ino: %d\n", ++ i, id, dc, dc->nameLen, dc->name, ++ dc->ino); ++ l = l->prev; ++ list_del(&dc->list); ++ kfree(dc); ++ DCCount--; ++ ++ id->cntDC--; ++ } ++ } ++ } ++} ++ ++/*++======================================================================*/ ++void Novfs_free_inode_cache(struct inode *i) ++/* ++ * Arguments: struct inode *i - pointer to directory inode. ++ * ++ * Returns: nothing ++ * ++ * Abstract: Frees all entries in the inode cache. ++ * ++ * Notes: DirCacheLock should be held before calling this routine. ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct list_head *l; ++ ++ if (i && (id = i->FSPRIVATE) && id->DirCache.next) { ++ list_for_each(l, &id->DirCache) { ++ dc = list_entry(l, struct dir_cache, list); ++ l = l->prev; ++ list_del(&dc->list); ++ kfree(dc); ++ DCCount--; ++ ++ id->cntDC--; ++ } ++ } ++} ++ ++void Novfs_dump_inode(void *pf) ++{ ++ struct inode *inode; ++ void (*pfunc) (char *Fmt, ...) = pf; ++ struct inode_data *id; ++ struct dir_cache *dc; ++ struct list_head *il, *l; ++ char atime_buf[32]; ++ char mtime_buf[32]; ++ char ctime_buf[32]; ++ unsigned long icnt = 0, dccnt = 0; ++ ++ down(&InodeList_lock); ++ list_for_each(il, &InodeList) { ++ id = list_entry(il, struct inode_data, IList); ++ inode = id->Inode; ++ if (inode) { ++ icnt++; ++ ++ pfunc("Inode=0x%p I_ino=%d\n", inode, inode->i_ino); ++ ++ pfunc(" atime=%s\n", ++ ctime_r(&inode->i_atime.tv_sec, atime_buf)); ++ pfunc(" ctime=%s\n", ++ ctime_r(&inode->i_mtime.tv_sec, atime_buf)); ++ pfunc(" mtime=%s\n", ++ ctime_r(&inode->i_ctime.tv_sec, atime_buf)); ++ pfunc(" size=%lld\n", inode->i_size); ++ pfunc(" mode=0%o\n", inode->i_mode); ++ pfunc(" count=0%o\n", atomic_read(&inode->i_count)); ++ } ++ ++ pfunc(" inode_data: 0x%p Name=%s Scope=0x%p\n", id, id->Name, ++ id->Scope); ++ ++ if (id->DirCache.next) { ++ list_for_each(l, &id->DirCache) { ++ dccnt++; ++ dc = list_entry(l, struct dir_cache, list); ++ ctime_r(&dc->atime.tv_sec, atime_buf); ++ ctime_r(&dc->mtime.tv_sec, mtime_buf); ++ ctime_r(&dc->ctime.tv_sec, ctime_buf); ++ ++ pfunc(" Cache Entry: 0x%p\n" ++ " flags: 0x%x\n" ++ " jiffies: %llu\n" ++ " ino: %u\n" ++ " size: %llu\n" ++ " mode: 0%o\n" ++ " atime: %s\n" ++ " mtime: %s\n" ++ " ctime: %s\n" ++ " hash: 0x%x\n" ++ " len: %d\n" ++ " name: %s\n", ++ dc, dc->flags, dc->jiffies, ++ dc->ino, dc->size, dc->mode, ++ atime_buf, mtime_buf, ctime_buf, ++ dc->hash, dc->nameLen, dc->name); ++ } ++ } ++ } ++ up(&InodeList_lock); ++ ++ pfunc("Inodes: %d(%d) DirCache: %d(%d)\n", InodeCount, icnt, DCCount, ++ dccnt); ++ ++} ++ ++module_init(init_novfs); ++module_exit(exit_novfs); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Novell Inc."); ++MODULE_DESCRIPTION("Novell NetWare Client for Linux"); ++MODULE_VERSION(NOVFS_VERSION_STRING); +--- /dev/null ++++ b/fs/novfs/nwcapi.c +@@ -0,0 +1,2537 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner/Richard Williams ++ * ++ * This file contains functions used to interface to the library interface of ++ * the daemon. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "nwcapi.h" ++#include "nwerror.h" ++#include "vfs.h" ++#include "commands.h" ++ ++static void GetUserData(NwcScanConnInfo *connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply); ++static void GetConnData(NwcGetConnInfo *connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply); ++ ++ ++int NwOpenConnByName(PXPLAT pdata, HANDLE * Handle, session_t Session) ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCOpenConnByName openConn, connReply; ++ NwcOpenConnByName ocbn; ++ int retCode = 0; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ char *data; ++ ++ cpylen = copy_from_user(&ocbn, pdata->reqData, sizeof(ocbn)); ++ datalen = sizeof(*openConn) + strlen_user(ocbn.pName->pString) + strlen_user(ocbn.pServiceType); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_OPEN_CONN_BY_NAME; ++ ++ cmd->dataLen = datalen; ++ openConn = (PNwdCOpenConnByName) cmd->data; ++ ++ openConn->nameLen = strlen_user(ocbn.pName->pString); ++ openConn->serviceLen = strlen_user(ocbn.pServiceType); ++ openConn->uConnFlags = ocbn.uConnFlags; ++ openConn->ConnHandle = Uint32toHandle(ocbn.ConnHandle); ++ data = (char *)openConn; ++ data += sizeof(*openConn); ++ openConn->oName = sizeof(*openConn); ++ ++ openConn->oServiceType = openConn->oName + openConn->nameLen; ++ cpylen = copy_from_user(data, ocbn.pName->pString, openConn->nameLen); ++ data += openConn->nameLen; ++ cpylen = copy_from_user(data, ocbn.pServiceType, openConn->serviceLen); ++ ++ retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ /* ++ * we got reply data from the daemon ++ */ ++ connReply = (PNwdCOpenConnByName) reply->data; ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ /* ++ * we got valid data. ++ */ ++ connReply = (PNwdCOpenConnByName) reply->data; ++ ocbn.RetConnHandle = HandletoUint32(connReply->newConnHandle); ++ *Handle = connReply->newConnHandle; ++ ++ cpylen = copy_to_user(pdata->reqData, &ocbn, sizeof(ocbn)); ++ DbgPrint("New Conn Handle = %X\n", connReply->newConnHandle); ++ } ++ kfree(reply); ++ } ++ ++ kfree(cmd); ++ ++ return retCode; ++ ++} ++ ++int NwOpenConnByAddr(PXPLAT pdata, HANDLE * Handle, session_t Session) ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCOpenConnByAddr openConn, connReply; ++ NwcOpenConnByAddr ocba; ++ NwcTranAddr tranAddr; ++ int retCode = 0; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ char addr[MAX_ADDRESS_LENGTH]; ++ ++ cpylen = copy_from_user(&ocba, pdata->reqData, sizeof(ocba)); ++ datalen = sizeof(*openConn); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_OPEN_CONN_BY_ADDRESS; ++ cmd->dataLen = datalen; ++ openConn = (PNwdCOpenConnByAddr) cmd->data; ++ ++ cpylen = copy_from_user(&tranAddr, ocba.pTranAddr, sizeof(tranAddr)); ++ ++ DbgPrint("NwOpenConnByAddr: tranAddr\n"); ++ mydump(sizeof(tranAddr), &tranAddr); ++ ++ openConn->TranAddr.uTransportType = tranAddr.uTransportType; ++ openConn->TranAddr.uAddressLength = tranAddr.uAddressLength; ++ memset(addr, 0xcc, sizeof(addr) - 1); ++ ++ cpylen = copy_from_user(addr, tranAddr.puAddress, tranAddr.uAddressLength); ++ ++ DbgPrint("NwOpenConnByAddr: addr\n"); ++ mydump(sizeof(addr), addr); ++ ++ openConn->TranAddr.oAddress = *(unsigned int*) (&addr[2]); ++ ++ retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ /* ++ * we got reply data from the daemon ++ */ ++ connReply = (PNwdCOpenConnByAddr) reply->data; ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ /* ++ * we got valid data. ++ */ ++ connReply = (PNwdCOpenConnByAddr) reply->data; ++ ocba.ConnHandle = HandletoUint32(connReply->ConnHandle); ++ *Handle = connReply->ConnHandle; ++ cpylen = copy_to_user(pdata->reqData, &ocba, sizeof(ocba)); ++ DbgPrint("New Conn Handle = %X\n", connReply->ConnHandle); ++ } ++ kfree(reply); ++ } ++ ++ kfree(cmd); ++ return retCode; ++} ++ ++/*++======================================================================*/ ++int NwOpenConnByRef(PXPLAT pdata, HANDLE * Handle, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCOpenConnByRef openConn; ++ NwcOpenConnByReference ocbr; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = copy_from_user(&ocbr, pdata->reqData, sizeof(ocbr)); ++ datalen = sizeof(*openConn); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_OPEN_CONN_BY_REFERENCE; ++ cmd->dataLen = datalen; ++ openConn = (PNwdCOpenConnByRef) cmd->data; ++ ++ openConn->uConnReference = (HANDLE) (unsigned long) ocbr.uConnReference; ++ openConn->uConnFlags = ocbr.uConnFlags; ++ ++ retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ /* ++ * we got reply data from the daemon ++ */ ++ openConn = (PNwdCOpenConnByRef) reply->data; ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ /* ++ * we got valid data. ++ */ ++ ocbr.ConnHandle = HandletoUint32(openConn->ConnHandle); ++ *Handle = openConn->ConnHandle; ++ ++ cpylen = copy_to_user(pdata->reqData, &ocbr, sizeof(ocbr)); ++ DbgPrint("New Conn Handle = %X\n", openConn->ConnHandle); ++ } ++ kfree(reply); ++ } ++ ++ kfree(cmd); ++ return (retCode); ++ ++} ++ ++int NwRawSend(PXPLAT pdata, session_t Session) ++{ ++ NwcRequest xRequest; ++ PNwcFrag frag = NULL; ++ PNwcFrag cFrag = NULL; ++ PNwcFrag reqFrag = NULL; ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen, totalLen; ++ unsigned int x; ++ PNwdCNCPReq ncpData; ++ PNwdCNCPRep ncpReply; ++ unsigned char *reqData; ++ unsigned long actualReplyLength = 0; ++ ++ DbgPrint("[XPLAT] Process Raw NCP Send\n"); ++ cpylen = copy_from_user(&xRequest, pdata->reqData, sizeof(xRequest)); ++ ++ /* ++ * Figure out the length of the request ++ */ ++ frag = kmalloc(xRequest.uNumReplyFrags * sizeof(NwcFrag), GFP_KERNEL); ++ DbgPrint("[XPLAT RawNCP] - Reply Frag Count 0x%X\n", xRequest.uNumReplyFrags); ++ ++ if (!frag) ++ goto exit; ++ ++ cpylen = copy_from_user(frag, xRequest.pReplyFrags, xRequest.uNumReplyFrags * sizeof(NwcFrag)); ++ totalLen = 0; ++ ++ cFrag = frag; ++ for (x = 0; x < xRequest.uNumReplyFrags; x++) { ++ DbgPrint("[XPLAT - RawNCP] - Frag Len = %d\n", cFrag->uLength); ++ totalLen += cFrag->uLength; ++ cFrag++; ++ } ++ ++ DbgPrint("[XPLAT - RawNCP] - totalLen = %d\n", totalLen); ++ datalen = 0; ++ reqFrag = kmalloc(xRequest.uNumRequestFrags * sizeof(NwcFrag), GFP_KERNEL); ++ if (!reqFrag) ++ goto exit; ++ ++ cpylen = copy_from_user(reqFrag, xRequest.pRequestFrags, xRequest.uNumRequestFrags * sizeof(NwcFrag)); ++ cFrag = reqFrag; ++ for (x = 0; x < xRequest.uNumRequestFrags; x++) { ++ datalen += cFrag->uLength; ++ cFrag++; ++ } ++ ++ /* ++ * Allocate the cmd Request ++ */ ++ cmdlen = datalen + sizeof(*cmd) + sizeof(*ncpData); ++ DbgPrint("[XPLAT RawNCP] - Frag Count 0x%X\n", xRequest.uNumRequestFrags); ++ DbgPrint("[XPLAT RawNCP] - Total Command Data Len = %x\n", cmdlen); ++ ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ goto exit; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_RAW_NCP_REQUEST; ++ ++ /* ++ * build the NCP Request ++ */ ++ cmd->dataLen = cmdlen - sizeof(*cmd); ++ ncpData = (PNwdCNCPReq) cmd->data; ++ ncpData->replyLen = totalLen; ++ ncpData->requestLen = datalen; ++ ncpData->ConnHandle = (HANDLE) (unsigned long) xRequest.ConnHandle; ++ ncpData->function = xRequest.uFunction; ++ ++ reqData = ncpData->data; ++ cFrag = reqFrag; ++ ++ for (x = 0; x < xRequest.uNumRequestFrags; x++) { ++ cpylen = ++ copy_from_user(reqData, cFrag->pData, ++ cFrag->uLength); ++ reqData += cFrag->uLength; ++ cFrag++; ++ } ++ ++ retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ DbgPrint("RawNCP - reply = %x\n", reply); ++ DbgPrint("RawNCP - retCode = %x\n", retCode); ++ ++ if (reply) { ++ /* ++ * we got reply data from the daemon ++ */ ++ ncpReply = (PNwdCNCPRep) reply->data; ++ retCode = reply->Reply.ErrorCode; ++ ++ DbgPrint("RawNCP - Reply Frag Count 0x%X\n", ++ xRequest.uNumReplyFrags); ++ ++ /* ++ * We need to copy the reply frags to the packet. ++ */ ++ reqData = ncpReply->data; ++ cFrag = frag; ++ ++ totalLen = ncpReply->replyLen; ++ for (x = 0; x < xRequest.uNumReplyFrags; x++) { ++ ++ DbgPrint("RawNCP - Copy Frag %d: 0x%X\n", x, ++ cFrag->uLength); ++ ++ datalen = min((unsigned long)cFrag->uLength, totalLen); ++ ++ cpylen = copy_to_user(cFrag->pData, reqData, datalen); ++ totalLen -= datalen; ++ reqData += datalen; ++ actualReplyLength += datalen; ++ ++ cFrag++; ++ } ++ ++ kfree(reply); ++ } else { ++ retCode = -EIO; ++ } ++ ++ kfree(cmd); ++ ++ xRequest.uActualReplyLength = actualReplyLength; ++ cpylen = copy_to_user(pdata->reqData, &xRequest, sizeof(xRequest)); ++ ++exit: ++ kfree(reqFrag); ++ kfree(frag); ++ return retCode; ++} ++ ++int NwConnClose(PXPLAT pdata, HANDLE * Handle, session_t Session) ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcCloseConn cc; ++ PNwdCCloseConn nwdClose; ++ int retCode = 0; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = copy_from_user(&cc, pdata->reqData, sizeof(cc)); ++ ++ datalen = sizeof(*nwdClose); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = kmalloc(cmdlen, GFP_KERNEL); ++ if (!cmd) ++ return -ENOMEM; ++ ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_CLOSE_CONN; ++ ++ nwdClose = (PNwdCCloseConn) cmd->data; ++ cmd->dataLen = sizeof(*nwdClose); ++ *Handle = nwdClose->ConnHandle = Uint32toHandle(cc.ConnHandle); ++ ++ /* ++ * send the request ++ */ ++ retCode = Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, 0); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ return retCode; ++} ++ ++int NwSysConnClose(PXPLAT pdata, unsigned long *Handle, session_t Session) ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcCloseConn cc; ++ PNwdCCloseConn nwdClose; ++ unsigned int retCode = 0; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = copy_from_user(&cc, pdata->reqData, sizeof(cc)); ++ ++ datalen = sizeof(*nwdClose); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SYS_CLOSE_CONN; ++ ++ nwdClose = (PNwdCCloseConn) cmd->data; ++ cmd->dataLen = sizeof(*nwdClose); ++ nwdClose->ConnHandle = (HANDLE) (unsigned long) cc.ConnHandle; ++ *Handle = (unsigned long) cc.ConnHandle; ++ ++ /* ++ * send the request ++ */ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, 0); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwLoginIdentity(PXPLAT pdata, struct schandle *Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ NwcLoginIdentity lgn, *plgn; ++ int retCode = -ENOMEM; ++ NclString server; ++ NclString username; ++ NclString password; ++ unsigned long cpylen; ++ NwcString nwcStr; ++ ++ cpylen = copy_from_user(&lgn, pdata->reqData, sizeof(lgn)); ++ ++ DbgPrint("NwLoginIdentity:\n"); ++ mydump(sizeof(lgn), &lgn); ++ ++ cpylen = copy_from_user(&nwcStr, lgn.pDomainName, sizeof(nwcStr)); ++ DbgPrint("NwLoginIdentity: DomainName\n"); ++ mydump(sizeof(nwcStr), &nwcStr); ++ ++ if ((server.buffer = Novfs_Malloc(nwcStr.DataLen, GFP_KERNEL))) { ++ server.type = nwcStr.DataType; ++ server.len = nwcStr.DataLen; ++ if (!copy_from_user ++ ((void *)server.buffer, nwcStr.pBuffer, server.len)) { ++ DbgPrint("NwLoginIdentity: Server\n"); ++ mydump(server.len, server.buffer); ++ ++ cpylen = ++ copy_from_user(&nwcStr, lgn.pObjectName, ++ sizeof(nwcStr)); ++ DbgPrint("NwLoginIdentity: ObjectName\n"); ++ mydump(sizeof(nwcStr), &nwcStr); ++ ++ if ((username.buffer = ++ Novfs_Malloc(nwcStr.DataLen, GFP_KERNEL))) { ++ username.type = nwcStr.DataType; ++ username.len = nwcStr.DataLen; ++ if (!copy_from_user ++ ((void *)username.buffer, nwcStr.pBuffer, ++ username.len)) { ++ DbgPrint("NwLoginIdentity: User\n"); ++ mydump(username.len, username.buffer); ++ ++ cpylen = ++ copy_from_user(&nwcStr, ++ lgn.pPassword, ++ sizeof(nwcStr)); ++ DbgPrint("NwLoginIdentity: Password\n"); ++ mydump(sizeof(nwcStr), &nwcStr); ++ ++ if ((password.buffer = ++ Novfs_Malloc(nwcStr.DataLen, ++ GFP_KERNEL))) { ++ password.type = nwcStr.DataType; ++ password.len = nwcStr.DataLen; ++ if (!copy_from_user ++ ((void *)password.buffer, ++ nwcStr.pBuffer, ++ password.len)) { ++ retCode = ++ do_login(&server, ++ &username, ++ &password, ++ (HANDLE *)&lgn.AuthenticationId, ++ Session); ++ if (retCode) { ++ lgn.AuthenticationId = 0; ++ } ++ ++ plgn = ++ (NwcLoginIdentity *) ++ pdata->reqData; ++ cpylen = ++ copy_to_user(&plgn-> ++ AuthenticationId, ++ &lgn. ++ AuthenticationId, ++ sizeof ++ (plgn-> ++ AuthenticationId)); ++ ++ } ++ memset(password.buffer, 0, ++ password.len); ++ kfree(password.buffer); ++ } ++ } ++ memset(username.buffer, 0, username.len); ++ kfree(username.buffer); ++ } ++ } ++ kfree(server.buffer); ++ } ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int NwAuthConnWithId(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ NwcAuthenticateWithId pauth; ++ PNwdCAuthenticateWithId pDauth; ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ datalen = sizeof(*pDauth); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_AUTHENTICATE_CONN_WITH_ID; ++ ++ cpylen = copy_from_user(&pauth, pdata->reqData, sizeof(pauth)); ++ ++ pDauth = (PNwdCAuthenticateWithId) cmd->data; ++ cmd->dataLen = datalen; ++ pDauth->AuthenticationId = pauth.AuthenticationId; ++ pDauth->ConnHandle = (HANDLE) (unsigned long) pauth.ConnHandle; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int NwLicenseConn(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcLicenseConn lisc; ++ PNwdCLicenseConn pDLisc; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ datalen = sizeof(*pDLisc); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_LICENSE_CONN; ++ ++ cpylen = copy_from_user(&lisc, pdata->reqData, sizeof(lisc)); ++ ++ pDLisc = (PNwdCLicenseConn) cmd->data; ++ cmd->dataLen = datalen; ++ pDLisc->ConnHandle = (HANDLE) (unsigned long) lisc.ConnHandle; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int NwLogoutIdentity(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcLogoutIdentity logout; ++ PNwdCLogoutIdentity pDLogout; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ datalen = sizeof(*pDLogout); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_LOGOUT_IDENTITY; ++ ++ cpylen = ++ copy_from_user(&logout, pdata->reqData, sizeof(logout)); ++ ++ pDLogout = (PNwdCLogoutIdentity) cmd->data; ++ cmd->dataLen = datalen; ++ pDLogout->AuthenticationId = logout.AuthenticationId; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int NwUnlicenseConn(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCUnlicenseConn pUconn; ++ NwcUnlicenseConn ulc; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = copy_from_user(&ulc, pdata->reqData, sizeof(ulc)); ++ datalen = sizeof(*pUconn); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_UNLICENSE_CONN; ++ cmd->dataLen = datalen; ++ pUconn = (PNwdCUnlicenseConn) cmd->data; ++ ++ pUconn->ConnHandle = (HANDLE) (unsigned long) ulc.ConnHandle; ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ /* ++ * we got reply data from the daemon ++ */ ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwUnAuthenticate(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcUnauthenticate auth; ++ PNwdCUnauthenticate pDAuth; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ datalen = sizeof(*pDAuth); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_UNAUTHENTICATE_CONN; ++ ++ cpylen = copy_from_user(&auth, pdata->reqData, sizeof(auth)); ++ ++ pDAuth = (PNwdCUnauthenticate) cmd->data; ++ cmd->dataLen = datalen; ++ pDAuth->AuthenticationId = auth.AuthenticationId; ++ pDAuth->ConnHandle = (HANDLE) (unsigned long) auth.ConnHandle; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwGetConnInfo(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcGetConnInfo connInfo; ++ PNwdCGetConnInfo pDConnInfo; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, replylen, cpylen; ++ ++ cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cpylen = ++ copy_from_user(&connInfo, pdata->reqData, sizeof(NwcGetConnInfo)); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_CONN_INFO; ++ ++ pDConnInfo = (PNwdCGetConnInfo) cmd->data; ++ ++ pDConnInfo->ConnHandle = (HANDLE) (unsigned long) connInfo.ConnHandle; ++ pDConnInfo->uInfoLevel = connInfo.uInfoLevel; ++ pDConnInfo->uInfoLength = connInfo.uInfoLength; ++ cmd->dataLen = sizeof(*pDConnInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ GetConnData(&connInfo, cmd, reply); ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwSetConnInfo(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcSetConnInfo connInfo; ++ PNwdCSetConnInfo pDConnInfo; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, replylen, cpylen; ++ ++ cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cpylen = ++ copy_from_user(&connInfo, pdata->reqData, sizeof(NwcSetConnInfo)); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_CONN_INFO; ++ ++ pDConnInfo = (PNwdCSetConnInfo) cmd->data; ++ ++ pDConnInfo->ConnHandle = (HANDLE) (unsigned long) connInfo.ConnHandle; ++ pDConnInfo->uInfoLevel = connInfo.uInfoLevel; ++ pDConnInfo->uInfoLength = connInfo.uInfoLength; ++ cmd->dataLen = sizeof(*pDConnInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwGetIdentityInfo(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcGetIdentityInfo qidInfo, *gId; ++ PNwdCGetIdentityInfo idInfo; ++ NwcString xferStr; ++ char *str; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, replylen, cpylen; ++ ++ cmdlen = sizeof(*cmd) + sizeof(*idInfo); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ cpylen = copy_from_user(&qidInfo, pdata->reqData, sizeof(qidInfo)); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_IDENTITY_INFO; ++ ++ idInfo = (PNwdCGetIdentityInfo) cmd->data; ++ ++ idInfo->AuthenticationId = qidInfo.AuthenticationId; ++ cmd->dataLen = sizeof(*idInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ ++ if (!reply->Reply.ErrorCode) { ++ /* ++ * Save the return info to the user structure. ++ */ ++ gId = pdata->reqData; ++ idInfo = (PNwdCGetIdentityInfo) reply->data; ++ cpylen = ++ copy_to_user(&gId->AuthenticationId, ++ &idInfo->AuthenticationId, ++ sizeof(idInfo-> ++ AuthenticationId)); ++ cpylen = ++ copy_to_user(&gId->AuthType, ++ &idInfo->AuthType, ++ sizeof(idInfo->AuthType)); ++ cpylen = ++ copy_to_user(&gId->IdentityFlags, ++ &idInfo->IdentityFlags, ++ sizeof(idInfo->IdentityFlags)); ++ cpylen = ++ copy_to_user(&gId->NameType, ++ &idInfo->NameType, ++ sizeof(idInfo->NameType)); ++ cpylen = ++ copy_to_user(&gId->ObjectType, ++ &idInfo->ObjectType, ++ sizeof(idInfo->ObjectType)); ++ ++ cpylen = ++ copy_from_user(&xferStr, gId->pDomainName, ++ sizeof(NwcString)); ++ str = ++ (char *)((char *)reply->data + ++ idInfo->pDomainNameOffset); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ idInfo->domainLen); ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ xferStr.DataLen = idInfo->domainLen; ++ cpylen = ++ copy_to_user(gId->pDomainName, &xferStr, ++ sizeof(NwcString)); ++ ++ cpylen = ++ copy_from_user(&xferStr, gId->pObjectName, ++ sizeof(NwcString)); ++ str = ++ (char *)((char *)reply->data + ++ idInfo->pObjectNameOffset); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ idInfo->objectLen); ++ xferStr.DataLen = idInfo->objectLen - 1; ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ cpylen = ++ copy_to_user(gId->pObjectName, &xferStr, ++ sizeof(NwcString)); ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++int NwScanConnInfo(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcScanConnInfo connInfo, *rInfo; ++ PNwdCScanConnInfo pDConnInfo; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, replylen, cpylen; ++ unsigned char *localData; ++ ++ cpylen = ++ copy_from_user(&connInfo, pdata->reqData, sizeof(NwcScanConnInfo)); ++ ++ cmdlen = sizeof(*cmd) + sizeof(*pDConnInfo) + connInfo.uScanInfoLen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SCAN_CONN_INFO; ++ ++ pDConnInfo = (PNwdCScanConnInfo) cmd->data; ++ ++ DbgPrint("NwScanConnInfo: Input Data\n"); ++ DbgPrint("connInfo.uScanIndex = 0x%X\n", connInfo.uScanIndex); ++ DbgPrint("connInfo.uConnectionReference = 0x%X\n", ++ connInfo.uConnectionReference); ++ DbgPrint("connInfo.uScanInfoLevel = 0x%X\n", ++ connInfo.uScanInfoLevel); ++ DbgPrint("connInfo.uScanInfoLen = 0x%X\n", ++ connInfo.uScanInfoLen); ++ DbgPrint("connInfo.uReturnInfoLength = 0x%X\n", ++ connInfo.uReturnInfoLength); ++ DbgPrint("connInfo.uReturnInfoLevel = 0x%X\n", ++ connInfo.uReturnInfoLevel); ++ DbgPrint("connInfo.uScanFlags = 0x%X\n", connInfo.uScanFlags); ++ ++ pDConnInfo->uScanIndex = connInfo.uScanIndex; ++ pDConnInfo->uConnectionReference = ++ connInfo.uConnectionReference; ++ pDConnInfo->uScanInfoLevel = connInfo.uScanInfoLevel; ++ pDConnInfo->uScanInfoLen = connInfo.uScanInfoLen; ++ pDConnInfo->uReturnInfoLength = connInfo.uReturnInfoLength; ++ pDConnInfo->uReturnInfoLevel = connInfo.uReturnInfoLevel; ++ pDConnInfo->uScanFlags = connInfo.uScanFlags; ++ ++ if (pDConnInfo->uScanInfoLen) { ++ localData = (unsigned char *) pDConnInfo; ++ pDConnInfo->uScanConnInfoOffset = sizeof(*pDConnInfo); ++ localData += pDConnInfo->uScanConnInfoOffset; ++ cpylen = ++ copy_from_user(localData, connInfo.pScanConnInfo, ++ connInfo.uScanInfoLen); ++ } else { ++ pDConnInfo->uScanConnInfoOffset = 0; ++ } ++ ++ cmd->dataLen = sizeof(*pDConnInfo); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ DbgPrint("NwScanConnInfo: Reply recieved\n"); ++ DbgPrint(" NextIndex = %x\n", connInfo.uScanIndex); ++ DbgPrint(" ErrorCode = %x\n", reply->Reply.ErrorCode); ++ DbgPrint(" data = %x\n", reply->data); ++ ++ pDConnInfo = (PNwdCScanConnInfo) reply->data; ++ retCode = (unsigned long) reply->Reply.ErrorCode; ++ if (!retCode) { ++ GetUserData(&connInfo, cmd, reply); ++ rInfo = (NwcScanConnInfo *) pdata->repData; ++ cpylen = ++ copy_to_user(pdata->repData, ++ &pDConnInfo->uScanIndex, ++ sizeof(pDConnInfo-> ++ uScanIndex)); ++ cpylen = ++ copy_to_user(&rInfo->uConnectionReference, ++ &pDConnInfo-> ++ uConnectionReference, ++ sizeof(pDConnInfo-> ++ uConnectionReference)); ++ } else { ++ unsigned long x; ++ ++ x = 0; ++ rInfo = (NwcScanConnInfo *) pdata->reqData; ++ cpylen = ++ copy_to_user(&rInfo->uConnectionReference, ++ &x, ++ sizeof(rInfo-> ++ uConnectionReference)); ++ } ++ ++ kfree(reply); ++ } else { ++ retCode = -EIO; ++ } ++ kfree(cmd); ++ ++ } ++ ++ return (retCode); ++} ++ ++/*++======================================================================*/ ++static void GetUserData(NwcScanConnInfo * connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply) ++/* ++ * Abstract: Copies the user data out of the scan conn info call. ++ * ++ *========================================================================*/ ++{ ++ unsigned long uLevel; ++ PNwdCScanConnInfo pDConnInfo; ++ ++ unsigned char *srcData = NULL; ++ unsigned long dataLen = 0, cpylen; ++ ++ pDConnInfo = (PNwdCScanConnInfo) reply->data; ++ uLevel = pDConnInfo->uReturnInfoLevel; ++ DbgPrint ++ ("[GetUserData] uLevel = %d, reply = 0x%p, reply->data = 0x%X\n", ++ uLevel, reply, reply->data); ++ ++ switch (uLevel) { ++ case NWC_CONN_INFO_RETURN_ALL: ++ case NWC_CONN_INFO_NDS_STATE: ++ case NWC_CONN_INFO_MAX_PACKET_SIZE: ++ case NWC_CONN_INFO_LICENSE_STATE: ++ case NWC_CONN_INFO_PUBLIC_STATE: ++ case NWC_CONN_INFO_SERVICE_TYPE: ++ case NWC_CONN_INFO_DISTANCE: ++ case NWC_CONN_INFO_SERVER_VERSION: ++ case NWC_CONN_INFO_AUTH_ID: ++ case NWC_CONN_INFO_SUSPENDED: ++ case NWC_CONN_INFO_WORKGROUP_ID: ++ case NWC_CONN_INFO_SECURITY_STATE: ++ case NWC_CONN_INFO_CONN_NUMBER: ++ case NWC_CONN_INFO_USER_ID: ++ case NWC_CONN_INFO_BCAST_STATE: ++ case NWC_CONN_INFO_CONN_REF: ++ case NWC_CONN_INFO_AUTH_STATE: ++ case NWC_CONN_INFO_TREE_NAME: ++ case NWC_CONN_INFO_SERVER_NAME: ++ case NWC_CONN_INFO_VERSION: ++ srcData = (unsigned char *) pDConnInfo; ++ srcData += pDConnInfo->uReturnConnInfoOffset; ++ dataLen = pDConnInfo->uReturnInfoLength; ++ break; ++ ++ case NWC_CONN_INFO_TRAN_ADDR: ++ { ++ unsigned char *dstData = connInfo->pReturnConnInfo; ++ NwcTranAddr tranAddr; ++ ++ srcData = (unsigned char *) reply->data; ++ dataLen = reply->dataLen; ++ ++ DbgPrint ++ ("GetUserData NWC_CONN_INFO_TRAN_ADDR 0x%p -> 0x%p :: 0x%X\n", ++ srcData, connInfo->pReturnConnInfo, dataLen); ++ ++ cpylen = ++ copy_from_user(&tranAddr, dstData, ++ sizeof(tranAddr)); ++ ++ srcData += ++ ((PNwdCScanConnInfo) srcData)-> ++ uReturnConnInfoOffset; ++ ++ tranAddr.uTransportType = ++ ((PNwdTranAddr) srcData)->uTransportType; ++ tranAddr.uAddressLength = ++ ((PNwdTranAddr) srcData)->uAddressLength; ++ ++ cpylen = ++ copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); ++ cpylen = ++ copy_to_user(tranAddr.puAddress, ++ ((PNwdTranAddr) srcData)->Buffer, ++ ((PNwdTranAddr) srcData)-> ++ uAddressLength); ++ dataLen = 0; ++ break; ++ } ++ case NWC_CONN_INFO_RETURN_NONE: ++ case NWC_CONN_INFO_TREE_NAME_UNICODE: ++ case NWC_CONN_INFO_SERVER_NAME_UNICODE: ++ case NWC_CONN_INFO_LOCAL_TRAN_ADDR: ++ case NWC_CONN_INFO_ALTERNATE_ADDR: ++ case NWC_CONN_INFO_SERVER_GUID: ++ default: ++ break; ++ } ++ ++ if (srcData && dataLen) { ++ DbgPrint("Copy Data in GetUserData 0x%p -> 0x%p :: 0x%X\n", ++ srcData, connInfo->pReturnConnInfo, dataLen); ++ cpylen = ++ copy_to_user(connInfo->pReturnConnInfo, srcData, dataLen); ++ } ++ ++ return; ++} ++ ++/*++======================================================================*/ ++static void GetConnData(NwcGetConnInfo * connInfo, PXPLAT_CALL_REQUEST cmd, PXPLAT_CALL_REPLY reply) ++/* ++ * Abstract: Copies the user data out of the scan conn info call. ++ * ++ *========================================================================*/ ++{ ++ unsigned long uLevel; ++ PNwdCGetConnInfo pDConnInfo; ++ ++ unsigned char *srcData = NULL; ++ unsigned long dataLen = 0, cpylen; ++ ++ pDConnInfo = (PNwdCGetConnInfo) cmd->data; ++ uLevel = pDConnInfo->uInfoLevel; ++ ++ switch (uLevel) { ++ case NWC_CONN_INFO_RETURN_ALL: ++ srcData = (unsigned char *) reply->data; ++ dataLen = reply->dataLen; ++ break; ++ ++ case NWC_CONN_INFO_RETURN_NONE: ++ dataLen = 0; ++ break; ++ ++ case NWC_CONN_INFO_TRAN_ADDR: ++ { ++ unsigned char *dstData = connInfo->pConnInfo; ++ NwcTranAddr tranAddr; ++ ++ srcData = (unsigned char *) reply->data; ++ ++ cpylen = ++ copy_from_user(&tranAddr, dstData, ++ sizeof(tranAddr)); ++ tranAddr.uTransportType = ++ ((PNwdTranAddr) srcData)->uTransportType; ++ tranAddr.uAddressLength = ++ ((PNwdTranAddr) srcData)->uAddressLength; ++ ++ cpylen = ++ copy_to_user(dstData, &tranAddr, sizeof(tranAddr)); ++ cpylen = ++ copy_to_user(tranAddr.puAddress, ++ ((PNwdTranAddr) srcData)->Buffer, ++ ((PNwdTranAddr) srcData)-> ++ uAddressLength); ++ dataLen = 0; ++ break; ++ } ++ case NWC_CONN_INFO_NDS_STATE: ++ case NWC_CONN_INFO_MAX_PACKET_SIZE: ++ case NWC_CONN_INFO_LICENSE_STATE: ++ case NWC_CONN_INFO_PUBLIC_STATE: ++ case NWC_CONN_INFO_SERVICE_TYPE: ++ case NWC_CONN_INFO_DISTANCE: ++ case NWC_CONN_INFO_SERVER_VERSION: ++ case NWC_CONN_INFO_AUTH_ID: ++ case NWC_CONN_INFO_SUSPENDED: ++ case NWC_CONN_INFO_WORKGROUP_ID: ++ case NWC_CONN_INFO_SECURITY_STATE: ++ case NWC_CONN_INFO_CONN_NUMBER: ++ case NWC_CONN_INFO_USER_ID: ++ case NWC_CONN_INFO_BCAST_STATE: ++ case NWC_CONN_INFO_CONN_REF: ++ case NWC_CONN_INFO_AUTH_STATE: ++ case NWC_CONN_INFO_VERSION: ++ case NWC_CONN_INFO_SERVER_NAME: ++ case NWC_CONN_INFO_TREE_NAME: ++ srcData = (unsigned char *) reply->data; ++ dataLen = reply->dataLen; ++ break; ++ ++ case NWC_CONN_INFO_TREE_NAME_UNICODE: ++ case NWC_CONN_INFO_SERVER_NAME_UNICODE: ++ break; ++ ++ case NWC_CONN_INFO_LOCAL_TRAN_ADDR: ++ break; ++ ++ case NWC_CONN_INFO_ALTERNATE_ADDR: ++ break; ++ ++ case NWC_CONN_INFO_SERVER_GUID: ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (srcData && dataLen) { ++ cpylen = ++ copy_to_user(connInfo->pConnInfo, srcData, ++ connInfo->uInfoLength); ++ } ++ ++ return; ++} ++ ++/*++======================================================================*/ ++int NwGetDaemonVersion(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCGetRequesterVersion pDVersion; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ ++ datalen = sizeof(*pDVersion); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_REQUESTER_VERSION; ++ cmdlen = sizeof(*cmd); ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ pDVersion = (PNwdCGetRequesterVersion) reply->data; ++ cpylen = ++ copy_to_user(pDVersion, pdata->reqData, ++ sizeof(*pDVersion)); ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwcGetPreferredDSTree(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCGetPreferredDsTree pDGetTree; ++ NwcGetPreferredDsTree xplatCall, *p; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ unsigned char *dPtr; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcGetPreferredDsTree)); ++ datalen = sizeof(*pDGetTree) + xplatCall.uTreeLength; ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_PREFERRED_DS_TREE; ++ cmdlen = sizeof(*cmd); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ pDGetTree = ++ (PNwdCGetPreferredDsTree) reply->data; ++ dPtr = ++ reply->data + pDGetTree->DsTreeNameOffset; ++ p = (NwcGetPreferredDsTree *) pdata->reqData; ++ ++ DbgPrint ++ ("NwcGetPreferredDSTree: Reply recieved\n"); ++ DbgPrint(" TreeLen = %x\n", ++ pDGetTree->uTreeLength); ++ DbgPrint(" TreeName = %s\n", dPtr); ++ ++ cpylen = ++ copy_to_user(p, &pDGetTree->uTreeLength, 4); ++ cpylen = ++ copy_to_user(xplatCall.pDsTreeName, dPtr, ++ pDGetTree->uTreeLength); ++ } ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwcSetPreferredDSTree(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ PNwdCSetPreferredDsTree pDSetTree; ++ NwcSetPreferredDsTree xplatCall; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ unsigned char *dPtr; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcSetPreferredDsTree)); ++ datalen = sizeof(*pDSetTree) + xplatCall.uTreeLength; ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_PREFERRED_DS_TREE; ++ ++ pDSetTree = (PNwdCSetPreferredDsTree) cmd->data; ++ pDSetTree->DsTreeNameOffset = sizeof(*pDSetTree); ++ pDSetTree->uTreeLength = xplatCall.uTreeLength; ++ ++ dPtr = cmd->data + sizeof(*pDSetTree); ++ cpylen = ++ copy_from_user(dPtr, xplatCall.pDsTreeName, ++ xplatCall.uTreeLength); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwcSetDefaultNameCtx(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcSetDefaultNameContext xplatCall; ++ PNwdCSetDefaultNameContext pDSet; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, datalen, replylen, cpylen; ++ unsigned char *dPtr; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcSetDefaultNameContext)); ++ datalen = ++ sizeof(*pDSet) + xplatCall.uTreeLength + xplatCall.uNameLength; ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_DEFAULT_NAME_CONTEXT; ++ cmd->dataLen = ++ sizeof(NwdCSetDefaultNameContext) + xplatCall.uTreeLength + ++ xplatCall.uNameLength; ++ ++ pDSet = (PNwdCSetDefaultNameContext) cmd->data; ++ dPtr = cmd->data; ++ ++ pDSet->TreeOffset = sizeof(NwdCSetDefaultNameContext); ++ pDSet->uTreeLength = xplatCall.uTreeLength; ++ pDSet->NameContextOffset = ++ pDSet->TreeOffset + xplatCall.uTreeLength; ++ pDSet->uNameLength = xplatCall.uNameLength; ++ ++//sgled cpylen = copy_from_user(dPtr+pDSet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); ++ cpylen = copy_from_user(dPtr + pDSet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled ++ cpylen = ++ copy_from_user(dPtr + pDSet->NameContextOffset, ++ xplatCall.pNameContext, ++ xplatCall.uNameLength); ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++/*++======================================================================*/ ++int NwcGetDefaultNameCtx(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcGetDefaultNameContext xplatCall; ++ PNwdCGetDefaultNameContext pGet; ++ char *dPtr; ++ int retCode = -ENOMEM; ++ unsigned long cmdlen, replylen, cpylen; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcGetDefaultNameContext)); ++ cmdlen = ++ sizeof(*cmd) + sizeof(NwdCGetDefaultNameContext) + ++ xplatCall.uTreeLength; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_DEFAULT_NAME_CONTEXT; ++ cmd->dataLen = ++ sizeof(NwdCGetDefaultNameContext) + xplatCall.uTreeLength; ++ ++ pGet = (PNwdCGetDefaultNameContext) cmd->data; ++ dPtr = cmd->data; ++ ++ pGet->TreeOffset = sizeof(NwdCGetDefaultNameContext); ++ pGet->uTreeLength = xplatCall.uTreeLength; ++ ++//sgled cpylen = copy_from_user( dPtr + pGet->TreeOffset, xplatCall.pTreeName, xplatCall.uTreeLength); ++ cpylen = copy_from_user(dPtr + pGet->TreeOffset, xplatCall.pDsTreeName, xplatCall.uTreeLength); //sgled ++ dPtr[pGet->TreeOffset + pGet->uTreeLength] = 0; ++ ++ retCode = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ retCode = reply->Reply.ErrorCode; ++ if (!retCode) { ++ pGet = (PNwdCGetDefaultNameContext) reply->data; ++ ++ DbgPrint ++ ("NwcGetDefaultNameCtx: retCode=0x%x uNameLength1=%d uNameLength2=%d\n", ++ retCode, pGet->uNameLength, ++ xplatCall.uNameLength); ++ if (xplatCall.uNameLength < pGet->uNameLength) { ++ pGet->uNameLength = ++ xplatCall.uNameLength; ++ retCode = NWE_BUFFER_OVERFLOW; ++ } ++ dPtr = (char *)pGet + pGet->NameContextOffset; ++ cpylen = ++ copy_to_user(xplatCall.pNameContext, dPtr, ++ pGet->uNameLength); ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (retCode); ++ ++} ++ ++int NwQueryFeature(PXPLAT pdata, session_t Session) ++{ ++ NwcQueryFeature xpCall; ++ int status = 0; ++ unsigned long cpylen; ++ ++ cpylen = ++ copy_from_user(&xpCall, pdata->reqData, sizeof(NwcQueryFeature)); ++ switch (xpCall.Feature) { ++ case NWC_FEAT_NDS: ++ case NWC_FEAT_NDS_MTREE: ++ case NWC_FEAT_PRN_CAPTURE: ++ case NWC_FEAT_NDS_RESOLVE: ++ ++ status = NWE_REQUESTER_FAILURE; ++ ++ } ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcGetTreeMonitoredConn(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcGetTreeMonitoredConnRef xplatCall, *p; ++ PNwdCGetTreeMonitoredConnRef pDConnRef; ++ char *dPtr; ++ unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcGetTreeMonitoredConnRef)); ++ datalen = sizeof(*pDConnRef) + xplatCall.pTreeName->DataLen; ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_GET_TREE_MONITORED_CONN_REF; ++ ++ pDConnRef = (PNwdCGetTreeMonitoredConnRef) cmd->data; ++ pDConnRef->TreeName.boffset = sizeof(*pDConnRef); ++ pDConnRef->TreeName.len = xplatCall.pTreeName->DataLen; ++ pDConnRef->TreeName.type = xplatCall.pTreeName->DataType; ++ ++ dPtr = cmd->data + sizeof(*pDConnRef); ++ cpylen = ++ copy_from_user(dPtr, xplatCall.pTreeName->pBuffer, ++ pDConnRef->TreeName.len); ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ pDConnRef = (PNwdCGetTreeMonitoredConnRef) reply->data; ++ dPtr = reply->data + pDConnRef->TreeName.boffset; ++ p = (NwcGetTreeMonitoredConnRef *) pdata->reqData; ++ cpylen = ++ copy_to_user(&p->uConnReference, ++ &pDConnRef->uConnReference, 4); ++ ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcEnumIdentities(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcEnumerateIdentities xplatCall, *eId; ++ PNwdCEnumerateIdentities pEnum; ++ NwcString xferStr; ++ char *str; ++ unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcEnumerateIdentities)); ++ datalen = sizeof(*pEnum); ++ cmdlen = datalen + sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_ENUMERATE_IDENTITIES; ++ ++ DbgPrint("NwcEnumIdentities: Send Request\n"); ++ DbgPrint(" iterator = %x\n", xplatCall.Iterator); ++ DbgPrint(" cmdlen = %d\n", cmdlen); ++ ++ pEnum = (PNwdCEnumerateIdentities) cmd->data; ++ pEnum->Iterator = xplatCall.Iterator; ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ ++ eId = pdata->repData; ++ pEnum = (PNwdCEnumerateIdentities) reply->data; ++ cpylen = ++ copy_to_user(&eId->Iterator, &pEnum->Iterator, ++ sizeof(pEnum->Iterator)); ++ DbgPrint("[XPLAT NWCAPI] Found AuthId 0x%X\n", ++ pEnum->AuthenticationId); ++ cpylen = ++ copy_to_user(&eId->AuthenticationId, ++ &pEnum->AuthenticationId, ++ sizeof(pEnum->AuthenticationId)); ++ cpylen = ++ copy_to_user(&eId->AuthType, &pEnum->AuthType, ++ sizeof(pEnum->AuthType)); ++ cpylen = ++ copy_to_user(&eId->IdentityFlags, ++ &pEnum->IdentityFlags, ++ sizeof(pEnum->IdentityFlags)); ++ cpylen = ++ copy_to_user(&eId->NameType, &pEnum->NameType, ++ sizeof(pEnum->NameType)); ++ cpylen = ++ copy_to_user(&eId->ObjectType, &pEnum->ObjectType, ++ sizeof(pEnum->ObjectType)); ++ ++ if (!status) { ++ cpylen = ++ copy_from_user(&xferStr, eId->pDomainName, ++ sizeof(NwcString)); ++ str = ++ (char *)((char *)reply->data + ++ pEnum->domainNameOffset); ++ DbgPrint("[XPLAT NWCAPI] Found Domain %s\n", ++ str); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ pEnum->domainNameLen); ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ xferStr.DataLen = pEnum->domainNameLen - 1; ++ cpylen = ++ copy_to_user(eId->pDomainName, &xferStr, ++ sizeof(NwcString)); ++ ++ cpylen = ++ copy_from_user(&xferStr, eId->pObjectName, ++ sizeof(NwcString)); ++ str = ++ (char *)((char *)reply->data + ++ pEnum->objectNameOffset); ++ DbgPrint("[XPLAT NWCAPI] Found User %s\n", str); ++ cpylen = ++ copy_to_user(xferStr.pBuffer, str, ++ pEnum->objectNameLen); ++ xferStr.DataType = NWC_STRING_TYPE_ASCII; ++ xferStr.DataLen = pEnum->objectNameLen - 1; ++ cpylen = ++ copy_to_user(eId->pObjectName, &xferStr, ++ sizeof(NwcString)); ++ } ++ ++ kfree(reply); ++ ++ } ++ kfree(cmd); ++ ++ } ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcChangeAuthKey(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Change the password on the server ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcChangeKey xplatCall; ++ PNwdCChangeKey pNewKey; ++ NwcString xferStr; ++ char *str; ++ unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, sizeof(NwcChangeKey)); ++ ++ datalen = ++ sizeof(NwdCChangeKey) + xplatCall.pDomainName->DataLen + ++ xplatCall.pObjectName->DataLen + xplatCall.pNewPassword->DataLen + ++ xplatCall.pVerifyPassword->DataLen; ++ ++ cmdlen = sizeof(*cmd) + datalen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ pNewKey = (PNwdCChangeKey) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_CHANGE_KEY; ++ ++ pNewKey->NameType = xplatCall.NameType; ++ pNewKey->ObjectType = xplatCall.ObjectType; ++ pNewKey->AuthType = xplatCall.AuthType; ++ str = (char *)pNewKey; ++ ++ /* ++ * Get the tree name ++ */ ++ str += sizeof(*pNewKey); ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pDomainName, ++ sizeof(NwcString)); ++ pNewKey->domainNameOffset = sizeof(*pNewKey); ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->domainNameLen = xferStr.DataLen; ++ ++ /* ++ * Get the User Name ++ */ ++ str += pNewKey->domainNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pObjectName, ++ sizeof(NwcString)); ++ pNewKey->objectNameOffset = ++ pNewKey->domainNameOffset + pNewKey->domainNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->objectNameLen = xferStr.DataLen; ++ ++ /* ++ * Get the New Password ++ */ ++ str += pNewKey->objectNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pNewPassword, ++ sizeof(NwcString)); ++ pNewKey->newPasswordOffset = ++ pNewKey->objectNameOffset + pNewKey->objectNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->newPasswordLen = xferStr.DataLen; ++ ++ /* ++ * Get the Verify Password ++ */ ++ str += pNewKey->newPasswordLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pVerifyPassword, ++ sizeof(NwcString)); ++ pNewKey->verifyPasswordOffset = ++ pNewKey->newPasswordOffset + pNewKey->newPasswordLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->verifyPasswordLen = xferStr.DataLen; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ memset(cmd, 0, cmdlen); ++ ++ kfree(cmd); ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcSetPrimaryConn(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Set the primary connection Id ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcSetPrimaryConnection xplatCall; ++ PNwdCSetPrimaryConnection pConn; ++ unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, ++ sizeof(NwcSetPrimaryConnection)); ++ ++ datalen = sizeof(NwdCSetPrimaryConnection); ++ cmdlen = sizeof(*cmd) + datalen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ pConn = (PNwdCSetPrimaryConnection) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_PRIMARY_CONN; ++ pConn->ConnHandle = (HANDLE) (unsigned long) xplatCall.ConnHandle; ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ ++ kfree(cmd); ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcGetPrimaryConn(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Get the Primary connection ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ XPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ unsigned long status = -ENOMEM, cmdlen, replylen, cpylen; ++ ++ cmdlen = (unsigned long) (&((PXPLAT_CALL_REQUEST) 0)->data); ++ ++ cmd.dataLen = 0; ++ cmd.Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd.Command.SequenceNumber = 0; ++ cmd.Command.SessionId = Session; ++ cmd.NwcCommand = NWC_GET_PRIMARY_CONN; ++ ++ status = ++ Queue_Daemon_Command((void *)&cmd, cmdlen, NULL, 0, (void **)&reply, ++ &replylen, INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ if (!status) { ++ cpylen = ++ copy_to_user(pdata->repData, reply->data, ++ sizeof(unsigned long)); ++ } ++ ++ kfree(reply); ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcSetMapDrive(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Get the Primary connection ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ unsigned long status = 0, datalen, cmdlen, replylen, cpylen; ++ NwcMapDriveEx symInfo; ++ ++ DbgPrint("Call to NwcSetMapDrive\n"); ++ cpylen = copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo)); ++ cmdlen = sizeof(*cmd); ++ datalen = ++ sizeof(symInfo) + symInfo.dirPathOffsetLength + ++ symInfo.linkOffsetLength; ++ ++ DbgPrint(" cmdlen = %d\n", cmdlen); ++ DbgPrint(" dataLen = %d\n", datalen); ++ DbgPrint(" symInfo.dirPathOffsetLength = %d\n", ++ symInfo.dirPathOffsetLength); ++ DbgPrint(" symInfo.linkOffsetLength = %d\n", symInfo.linkOffsetLength); ++ DbgPrint(" pdata->datalen = %d\n", pdata->reqLen); ++ ++ mydump(sizeof(symInfo), &symInfo); ++ ++ cmdlen += datalen; ++ ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_MAP_DRIVE; ++ ++ cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (status); ++ ++} ++ ++/*++======================================================================*/ ++int NwcUnMapDrive(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Get the Primary connection ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ unsigned long status = 0, datalen, cmdlen, replylen, cpylen; ++ NwcUnmapDriveEx symInfo; ++ ++ DbgPrint("Call to NwcUnMapDrive\n"); ++ ++ cpylen = copy_from_user(&symInfo, pdata->reqData, sizeof(symInfo)); ++ cmdlen = sizeof(*cmd); ++ datalen = sizeof(symInfo) + symInfo.linkLen; ++ ++ cmdlen += datalen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_UNMAP_DRIVE; ++ ++ cpylen = copy_from_user(cmd->data, pdata->reqData, datalen); ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcEnumerateDrives(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Get the Primary connection ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ unsigned long status = 0, cmdlen, replylen, cpylen; ++ unsigned long offset; ++ char *cp; ++ ++ DbgPrint("Call to NwcEnumerateDrives\n"); ++ ++ cmdlen = sizeof(*cmd); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ cmd->dataLen = 0; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_ENUMERATE_DRIVES; ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ DbgPrint("Status Code = 0x%X\n", status); ++ if (!status) { ++ offset = ++ sizeof(((PNwcGetMappedDrives) pdata-> ++ repData)->MapBuffLen); ++ cp = reply->data; ++ replylen = ++ ((PNwcGetMappedDrives) pdata->repData)-> ++ MapBuffLen; ++ cpylen = ++ copy_to_user(pdata->repData, cp, offset); ++ cp += offset; ++ cpylen = ++ copy_to_user(((PNwcGetMappedDrives) pdata-> ++ repData)->MapBuffer, cp, ++ min(replylen - offset, ++ reply->dataLen - offset)); ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwcGetBroadcastMessage(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Get the Primary connection ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ unsigned long cmdlen, replylen; ++ int status = 0x8866, cpylen; ++ NwcGetBroadcastNotification msg; ++ PNwdCGetBroadcastNotification dmsg; ++ ++ cmdlen = sizeof(*cmd) + sizeof(*dmsg); ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ if (cmd) { ++ ++ cpylen = copy_from_user(&msg, pdata->reqData, sizeof(msg)); ++ cmd->dataLen = sizeof(*dmsg); ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ ++ cmd->NwcCommand = NWC_GET_BROADCAST_MESSAGE; ++ dmsg = (PNwdCGetBroadcastNotification) cmd->data; ++ dmsg->uConnReference = (HANDLE) (unsigned long) msg.uConnReference; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ ++ if (!status) { ++ char *cp = pdata->repData; ++ ++ dmsg = ++ (PNwdCGetBroadcastNotification) reply->data; ++ if (pdata->repLen < dmsg->messageLen) { ++ dmsg->messageLen = pdata->repLen; ++ } ++ msg.messageLen = dmsg->messageLen; ++ cpylen = offsetof(NwcGetBroadcastNotification, message); ++ cp += cpylen; ++ cpylen = copy_to_user(pdata->repData, &msg, cpylen); ++ cpylen = copy_to_user(cp, dmsg->message, msg.messageLen); ++ } else { ++ msg.messageLen = 0; ++ msg.message[0] = 0; ++ cpylen = offsetof(NwcGetBroadcastNotification, message); ++ cpylen = copy_to_user(pdata->repData, &msg, sizeof(msg)); ++ } ++ ++ kfree(reply); ++ } ++ kfree(cmd); ++ } ++ return (status); ++} ++ ++int NwdSetKeyValue(PXPLAT pdata, session_t Session) ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcSetKey xplatCall; ++ PNwdCSetKey pNewKey; ++ NwcString cstrObjectName, cstrPassword; ++ char *str; ++ unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = copy_from_user(&xplatCall, pdata->reqData, sizeof(NwcSetKey)); ++ cpylen = ++ copy_from_user(&cstrObjectName, xplatCall.pObjectName, ++ sizeof(NwcString)); ++ cpylen = ++ copy_from_user(&cstrPassword, xplatCall.pNewPassword, ++ sizeof(NwcString)); ++ ++ datalen = ++ sizeof(NwdCSetKey) + cstrObjectName.DataLen + cstrPassword.DataLen; ++ ++ cmdlen = sizeof(*cmd) + datalen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ pNewKey = (PNwdCSetKey) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_SET_KEY; ++ ++ pNewKey->ObjectType = xplatCall.ObjectType; ++ pNewKey->AuthenticationId = xplatCall.AuthenticationId; ++ pNewKey->ConnHandle = (HANDLE) (unsigned long) xplatCall.ConnHandle; ++ str = (char *)pNewKey; ++ ++ /* ++ * Get the User Name ++ */ ++ str += sizeof(NwdCSetKey); ++ cpylen = ++ copy_from_user(str, cstrObjectName.pBuffer, ++ cstrObjectName.DataLen); ++ ++ str += pNewKey->objectNameLen = cstrObjectName.DataLen; ++ pNewKey->objectNameOffset = sizeof(NwdCSetKey); ++ ++ /* ++ * Get the Verify Password ++ */ ++ cpylen = ++ copy_from_user(str, cstrPassword.pBuffer, ++ cstrPassword.DataLen); ++ ++ pNewKey->newPasswordLen = cstrPassword.DataLen; ++ pNewKey->newPasswordOffset = ++ pNewKey->objectNameOffset + pNewKey->objectNameLen; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ memset(cmd, 0, cmdlen); ++ kfree(cmd); ++ } ++ ++ return (status); ++} ++ ++/*++======================================================================*/ ++int NwdVerifyKeyValue(PXPLAT pdata, session_t Session) ++/* ++ * Arguments: ++ * ++ * Returns: ++ * ++ * Abstract: Change the password on the server ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ PXPLAT_CALL_REQUEST cmd; ++ PXPLAT_CALL_REPLY reply; ++ NwcVerifyKey xplatCall; ++ PNwdCVerifyKey pNewKey; ++ NwcString xferStr; ++ char *str; ++ unsigned long status = -ENOMEM, cmdlen, datalen, replylen, cpylen; ++ ++ cpylen = ++ copy_from_user(&xplatCall, pdata->reqData, sizeof(NwcVerifyKey)); ++ ++ datalen = ++ sizeof(NwdCVerifyKey) + xplatCall.pDomainName->DataLen + ++ xplatCall.pObjectName->DataLen + xplatCall.pVerifyPassword->DataLen; ++ ++ cmdlen = sizeof(*cmd) + datalen; ++ cmd = Novfs_Malloc(cmdlen, GFP_KERNEL); ++ ++ if (cmd) { ++ pNewKey = (PNwdCVerifyKey) cmd->data; ++ cmd->dataLen = datalen; ++ cmd->Command.CommandType = VFS_COMMAND_XPLAT_CALL; ++ cmd->Command.SequenceNumber = 0; ++ cmd->Command.SessionId = Session; ++ cmd->NwcCommand = NWC_VERIFY_KEY; ++ ++ pNewKey->NameType = xplatCall.NameType; ++ pNewKey->ObjectType = xplatCall.ObjectType; ++ pNewKey->AuthType = xplatCall.AuthType; ++ str = (char *)pNewKey; ++ ++ /* ++ * Get the tree name ++ */ ++ str += sizeof(*pNewKey); ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pDomainName, ++ sizeof(NwcString)); ++ pNewKey->domainNameOffset = sizeof(*pNewKey); ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->domainNameLen = xferStr.DataLen; ++ ++ /* ++ * Get the User Name ++ */ ++ str += pNewKey->domainNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pObjectName, ++ sizeof(NwcString)); ++ pNewKey->objectNameOffset = ++ pNewKey->domainNameOffset + pNewKey->domainNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->objectNameLen = xferStr.DataLen; ++ ++ /* ++ * Get the Verify Password ++ */ ++ str += pNewKey->objectNameLen; ++ cpylen = ++ copy_from_user(&xferStr, xplatCall.pVerifyPassword, ++ sizeof(NwcString)); ++ pNewKey->verifyPasswordOffset = ++ pNewKey->objectNameOffset + pNewKey->objectNameLen; ++ cpylen = copy_from_user(str, xferStr.pBuffer, xferStr.DataLen); ++ pNewKey->verifyPasswordLen = xferStr.DataLen; ++ ++ status = ++ Queue_Daemon_Command((void *)cmd, cmdlen, NULL, 0, ++ (void **)&reply, &replylen, ++ INTERRUPTIBLE); ++ if (reply) { ++ status = reply->Reply.ErrorCode; ++ kfree(reply); ++ } ++ memset(cmd, 0, cmdlen); ++ kfree(cmd); ++ } ++ ++ return (status); ++} +--- /dev/null ++++ b/fs/novfs/nwcapi.h +@@ -0,0 +1,2213 @@ ++/* ++ * NetWare Redirector for Linux ++ * Author: Sheffer Clark ++ * ++ * This file contains all typedefs and constants for the NetWare Client APIs. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++#ifndef __NWCLNX_H__ ++#define __NWCLNX_H__ ++ ++#if 0 //sgled hack ++#else //sgled hack (up to endif) ++ ++#define NW_MAX_TREE_NAME_LEN 33 ++#define NW_MAX_SERVICE_TYPE_LEN 49 ++/* Transport Type - (nuint32 value) */ ++#define NWC_TRAN_TYPE_IPX 0x0001 ++#define NWC_TRAN_TYPE_DDP 0x0003 ++#define NWC_TRAN_TYPE_ASP 0x0004 ++#define NWC_TRAN_TYPE_UDP 0x0008 ++#define NWC_TRAN_TYPE_TCP 0x0009 ++#define NWC_TRAN_TYPE_UDP6 0x000A ++#define NWC_TRAN_TYPE_TCP6 0x000B ++#define NWC_TRAN_TYPE_WILD 0x8000 ++ ++// ++// DeviceIoControl requests for the NetWare Redirector ++// ++// Macro definition for defining DeviceIoControl function control codes. ++// The function codes 0 - 2047 are reserved for Microsoft. ++// Function codes 2048 - 4096 are reserved for customers. ++// The NetWare Redirector will use codes beginning at 3600. ++// ++// METHOD_NEITHER User buffers will be passed directly from the application ++// to the file system. The redirector is responsible for either probing ++// and locking the buffers or using a try - except around access of the ++// buffers. ++ ++#define BASE_REQ_NUM 0x4a541000 ++ ++// Connection functions ++#define NWC_OPEN_CONN_BY_NAME (BASE_REQ_NUM + 0) ++#define NWC_OPEN_CONN_BY_ADDRESS (BASE_REQ_NUM + 1) ++#define NWC_OPEN_CONN_BY_REFERENCE (BASE_REQ_NUM + 2) ++#define NWC_CLOSE_CONN (BASE_REQ_NUM + 3) ++#define NWC_SYS_CLOSE_CONN (BASE_REQ_NUM + 4) ++#define NWC_GET_CONN_INFO (BASE_REQ_NUM + 5) ++#define NWC_SET_CONN_INFO (BASE_REQ_NUM + 6) ++#define NWC_SCAN_CONN_INFO (BASE_REQ_NUM + 7) ++#define NWC_MAKE_CONN_PERMANENT (BASE_REQ_NUM + 8) ++#define NWC_LICENSE_CONN (BASE_REQ_NUM + 9) ++#define NWC_UNLICENSE_CONN (BASE_REQ_NUM + 10) ++#define NWC_GET_NUM_CONNS (BASE_REQ_NUM + 11) ++#define NWC_GET_PREFERRED_SERVER (BASE_REQ_NUM + 12) ++#define NWC_SET_PREFERRED_SERVER (BASE_REQ_NUM + 13) ++#define NWC_GET_PRIMARY_CONN (BASE_REQ_NUM + 14) ++#define NWC_SET_PRIMARY_CONN (BASE_REQ_NUM + 15) ++ ++// Authentication functions ++#define NWC_CHANGE_KEY (BASE_REQ_NUM + 20) ++#define NWC_ENUMERATE_IDENTITIES (BASE_REQ_NUM + 21) ++#define NWC_GET_IDENTITY_INFO (BASE_REQ_NUM + 22) ++#define NWC_LOGIN_IDENTITY (BASE_REQ_NUM + 23) ++#define NWC_LOGOUT_IDENTITY (BASE_REQ_NUM + 24) ++#define NWC_SET_KEY (BASE_REQ_NUM + 25) ++#define NWC_VERIFY_KEY (BASE_REQ_NUM + 26) ++#define NWC_AUTHENTICATE_CONN_WITH_ID (BASE_REQ_NUM + 27) ++#define NWC_UNAUTHENTICATE_CONN (BASE_REQ_NUM + 28) ++ ++// Directory Services functions ++#define NWC_GET_DEFAULT_NAME_CONTEXT (BASE_REQ_NUM + 30) ++#define NWC_SET_DEFAULT_NAME_CONTEXT (BASE_REQ_NUM + 31) ++#define NWC_GET_PREFERRED_DS_TREE (BASE_REQ_NUM + 32) ++#define NWC_SET_PREFERRED_DS_TREE (BASE_REQ_NUM + 33) ++#define NWC_GET_TREE_MONITORED_CONN_REF (BASE_REQ_NUM + 34) ++#define NWC_NDS_RESOLVE_NAME_TO_ID (BASE_REQ_NUM + 35) ++ ++// NCP Request functions ++#define NWC_FRAGMENT_REQUEST (BASE_REQ_NUM + 40) ++#define NWC_NCP_ORDERED_REQUEST_ALL (BASE_REQ_NUM + 41) ++#define NWC_RAW_NCP_REQUEST (BASE_REQ_NUM + 42) ++#define NWC_RAW_NCP_REQUEST_ALL (BASE_REQ_NUM + 43) ++ ++// File Handle Conversion functions ++#define NWC_CONVERT_LOCAL_HANDLE (BASE_REQ_NUM + 50) ++#define NWC_CONVERT_NETWARE_HANDLE (BASE_REQ_NUM + 51) ++ ++// Misc. functions ++#define NWC_MAP_DRIVE (BASE_REQ_NUM + 60) ++#define NWC_UNMAP_DRIVE (BASE_REQ_NUM + 61) ++#define NWC_ENUMERATE_DRIVES (BASE_REQ_NUM + 62) ++ ++#define NWC_GET_REQUESTER_VERSION (BASE_REQ_NUM + 63) ++#define NWC_QUERY_FEATURE (BASE_REQ_NUM + 64) ++ ++#define NWC_GET_CONFIGURED_NSPS (BASE_REQ_NUM + 65) ++ ++#define NWC_GET_MOUNT_PATH (BASE_REQ_NUM + 66) ++ ++#define NWC_GET_BROADCAST_MESSAGE (BASE_REQ_NUM + 67) ++ ++#endif //sgled hack ------------------------------- ++ ++#define IOC_XPLAT 0x4a540002 ++ ++typedef struct _XPLAT_ { ++ int xfunction; ++ unsigned long reqLen; ++ void *reqData; ++ unsigned long repLen; ++ void *repData; ++ ++} XPLAT, *PXPLAT; ++ ++#if 0 ++N_EXTERN_LIBRARY(NWRCODE) ++ NWCLnxReq ++ (nuint32 request, nptr pInBuf, nuint32 inLen, nptr pOutBuf, nuint32 outLen); ++#endif ++// ++// Network Name Format Type ++// ++ ++#define NWC_NAME_FORMAT_NDS 0x0001 ++#define NWC_NAME_FORMAT_BIND 0x0002 ++#define NWC_NAME_FORMAT_BDP 0x0004 ++#define NWC_NAME_FORMAT_NDS_TREE 0x0008 ++#define NWC_NAME_FORMAT_WILD 0x8000 ++ ++// ++// API String Types ++// ++ ++#define NWC_STRING_TYPE_ASCII 0x0001 // multi-byte, not really ascii ++#define NWC_STRING_TYPE_UNICODE 0x0002 ++#define NWC_STRING_TYPE_UTF8 0x0003 ++ ++// ++// Open Connection Flags ++// ++ ++#define NWC_OPEN_LICENSED 0x0001 ++#define NWC_OPEN_UNLICENSED 0x0002 ++#define NWC_OPEN_PRIVATE 0x0004 ++#define NWC_OPEN_PUBLIC 0x0008 ++#define NWC_OPEN_EXISTING_HANDLE 0x0010 ++#define NWC_OPEN_NO_HANDLE 0x0020 ++#define NWC_OPEN_PERMANENT 0x0040 ++#define NWC_OPEN_DISCONNECTED 0x0080 ++#define NWC_OPEN_NEAREST 0x0100 ++#define NWC_OPEN_IGNORE_CACHE 0x0200 ++ ++// ++// Close Connection Flags ++// ++ ++#define NWC_CLOSE_TEMPORARY 0x0000 ++#define NWC_CLOSE_PERMANENT 0x0001 ++ ++// ++// Connection Information Levels ++// ++ ++#define NWC_CONN_INFO_RETURN_ALL 0xFFFF ++#define NWC_CONN_INFO_RETURN_NONE 0x0000 ++#define NWC_CONN_INFO_VERSION 0x0001 ++#define NWC_CONN_INFO_AUTH_STATE 0x0002 ++#define NWC_CONN_INFO_BCAST_STATE 0x0003 ++#define NWC_CONN_INFO_CONN_REF 0x0004 ++#define NWC_CONN_INFO_TREE_NAME 0x0005 ++#define NWC_CONN_INFO_WORKGROUP_ID 0x0006 ++#define NWC_CONN_INFO_SECURITY_STATE 0x0007 ++#define NWC_CONN_INFO_CONN_NUMBER 0x0008 ++#define NWC_CONN_INFO_USER_ID 0x0009 ++#define NWC_CONN_INFO_SERVER_NAME 0x000A ++#define NWC_CONN_INFO_TRAN_ADDR 0x000B ++#define NWC_CONN_INFO_NDS_STATE 0x000C ++#define NWC_CONN_INFO_MAX_PACKET_SIZE 0x000D ++#define NWC_CONN_INFO_LICENSE_STATE 0x000E ++#define NWC_CONN_INFO_PUBLIC_STATE 0x000F ++#define NWC_CONN_INFO_SERVICE_TYPE 0x0010 ++#define NWC_CONN_INFO_DISTANCE 0x0011 ++#define NWC_CONN_INFO_SERVER_VERSION 0x0012 ++#define NWC_CONN_INFO_AUTH_ID 0x0013 ++#define NWC_CONN_INFO_SUSPENDED 0x0014 ++#define NWC_CONN_INFO_TREE_NAME_UNICODE 0x0015 ++#define NWC_CONN_INFO_SERVER_NAME_UNICODE 0x0016 ++#define NWC_CONN_INFO_LOCAL_TRAN_ADDR 0x0017 ++#define NWC_CONN_INFO_ALTERNATE_ADDR 0x0018 ++#define NWC_CONN_INFO_SERVER_GUID 0x0019 ++ ++#define NWC_CONN_INFO_MAX_LEVEL 0x0014 ++ ++// ++// Information Versions ++// ++ ++#define NWC_INFO_VERSION_1 0x0001 ++#define NWC_INFO_VERSION_2 0x0002 ++ ++// ++// Authentication State ++// ++ ++#define NWC_AUTH_TYPE_NONE 0x0000 ++#define NWC_AUTH_TYPE_BINDERY 0x0001 ++#define NWC_AUTH_TYPE_NDS 0x0002 ++#define NWC_AUTH_TYPE_PNW 0x0003 ++ ++#define NWC_AUTH_STATE_NONE 0x0000 ++#define NWC_AUTH_STATE_BINDERY 0x0001 ++#define NWC_AUTH_STATE_NDS 0x0002 ++#define NWC_AUTH_STATE_PNW 0x0003 ++ ++// ++// Authentication Flags ++// ++ ++#define NWC_AUTH_PRIVATE 0x00000004 ++#define NWC_AUTH_PUBLIC 0x00000008 ++ ++// ++// Broadcast State ++// ++ ++#define NWC_BCAST_PERMIT_ALL 0x0000 ++#define NWC_BCAST_PERMIT_SYSTEM 0x0001 ++#define NWC_BCAST_PERMIT_NONE 0x0002 ++#define NWC_BCAST_PERMIT_SYSTEM_POLLED 0x0003 ++#define NWC_BCAST_PERMIT_ALL_POLLED 0x0004 ++ ++// ++// Broadcast State ++// ++ ++#define NWC_NDS_NOT_CAPABLE 0x0000 ++#define NWC_NDS_CAPABLE 0x0001 ++ ++// ++// License State ++// ++ ++#define NWC_NOT_LICENSED 0x0000 ++#define NWC_CONNECTION_LICENSED 0x0001 ++#define NWC_HANDLE_LICENSED 0x0002 ++ ++// ++// Public State ++// ++ ++#define NWC_CONN_PUBLIC 0x0000 ++#define NWC_CONN_PRIVATE 0x0001 ++ ++// ++// Scan Connection Information Flags used ++// for finding connections by specific criteria ++// ++ ++#define NWC_MATCH_NOT_EQUALS 0x0000 ++#define NWC_MATCH_EQUALS 0x0001 ++#define NWC_RETURN_PUBLIC 0x0002 ++#define NWC_RETURN_PRIVATE 0x0004 ++#define NWC_RETURN_LICENSED 0x0008 ++#define NWC_RETURN_UNLICENSED 0x0010 ++ ++// ++// Authentication Types ++// ++ ++#define NWC_AUTHENT_BIND 0x0001 ++#define NWC_AUTHENT_NDS 0x0002 ++#define NWC_AUTHENT_PNW 0x0003 ++ ++// ++// Disconnected info ++// ++ ++#define NWC_SUSPENDED 0x0001 ++ ++// ++// Maximum object lengths ++// ++ ++#define MAX_DEVICE_LENGTH 16 ++#define MAX_NETWORK_NAME_LENGTH 1024 ++#define MAX_OBJECT_NAME_LENGTH 48 ++#define MAX_PASSWORD_LENGTH 128 ++#define MAX_SERVER_NAME_LENGTH 48 ++#define MAX_SERVICE_TYPE_LENGTH 48 ++#define MAX_TREE_NAME_LENGTH 32 ++#define MAX_ADDRESS_LENGTH 32 ++#define MAX_NAME_SERVICE_PROVIDERS 10 ++ ++// ++// Flags for the GetBroadcastMessage API ++// ++ ++#define MESSAGE_GET_NEXT_MESSAGE 1 ++#define MESSAGE_RECEIVED_FOR_CONNECTION 2 ++ ++// ++// This constant must always be equal to the last device ++// ++ ++#define DEVICE_LAST_DEVICE 0x00000003 ++ ++// ++// Defined feature set provided by requester ++// ++ ++#ifndef NWC_FEAT_PRIV_CONN ++#define NWC_FEAT_PRIV_CONN 1 ++#define NWC_FEAT_REQ_AUTH 2 ++#define NWC_FEAT_SECURITY 3 ++#define NWC_FEAT_NDS 4 ++#define NWC_FEAT_NDS_MTREE 5 ++#define NWC_FEAT_PRN_CAPTURE 6 ++#define NWC_FEAT_NDS_RESOLVE 7 ++#endif ++ ++//===[ Type definitions ]================================================== ++ ++// ++// Connection Handle returned from all OpenConnByXXXX calls ++// ++ ++typedef u32 NW_CONN_HANDLE, *PNW_CONN_HANDLE; ++ ++// ++// Authentication Id returned from the NwcCreateAuthenticationId call ++// ++ ++typedef u32 AUTHEN_ID, *PAUTHEN_ID; ++ ++// ++// Structure for defining what a transport ++// address looks like ++// ++ ++typedef struct tagNwcTranAddr { ++ u32 uTransportType; ++ u32 uAddressLength; ++ unsigned char *puAddress; ++ ++} NwcTranAddr, *PNwcTranAddr; ++ ++// ++// Structure for defining what a new transport ++// address looks like ++// ++ ++typedef struct tagNwcTranAddrEx { ++ u32 uTransportType; ++ u32 uAddressLength; ++ unsigned char buBuffer[MAX_ADDRESS_LENGTH]; ++ ++} NwcTranAddrEx, *PNwcTranAddrEx; ++ ++typedef struct tagNwcReferral { ++ u32 uAddrCnt; ++ PNwcTranAddrEx pAddrs; ++ ++} NwcReferral, *PNwcReferral; ++ ++typedef struct tagNwcServerVersion { ++ u32 uMajorVersion; ++ u16 uMinorVersion; ++ u16 uRevision; ++ ++} NwcServerVersion, *PNwcServerVersion; ++ ++typedef struct tagNwcConnString { ++ char *pString; ++ u32 uStringType; ++ u32 uNameFormatType; ++ ++} NwcConnString, *PNwcConnString; ++ ++//#if defined(NTYPES_H) ++//typedef NWCString NwcString, *PNwcString; ++//#else ++typedef struct tagNwcString { ++ u32 DataType; ++ u32 BuffSize; ++ u32 DataLen; ++ void *pBuffer; ++ u32 CodePage; ++ u32 CountryCode; ++ ++} NwcString, *PNwcString; ++//#endif ++ ++// ++// Structure used in NDS Resolve name ++// ++ ++#define RESOLVE_INFO_SVC_V1_00 0x00FE0001 ++ ++typedef struct tagNwcResolveInfo { ++ u32 uResolveInfoVersion; ++ u32 luFlags; ++ u32 luReqFlags; ++ u32 luReqScope; ++ u32 luResolveType; ++ u32 luRepFlags; ++ u32 luResolvedOffset; ++ u32 luDerefNameLen; ++ u16 *pDerefName; ++} NwcResolveInfo, *PNwcResolveInfo; ++ ++// ++// Definition of a fragment for the Raw NCP requests ++// ++ ++typedef struct tagNwcFrag { ++ void *pData; ++ u32 uLength; ++ ++} NwcFrag, *PNwcFrag; ++ ++// ++// Current connection information available for ++// enumeration using GetConnInfo and ScanConnInfo ++// ++ ++#define NW_INFO_BUFFER_SIZE NW_MAX_TREE_NAME_LEN + \ ++ NW_MAX_TREE_NAME_LEN + \ ++ NW_MAX_SERVICE_TYPE_LEN ++ ++typedef struct tagNwcConnInfo { ++ u32 uInfoVersion; ++ u32 uAuthenticationState; ++ u32 uBroadcastState; ++ u32 uConnectionReference; ++ u32 TreeNameOffset; ++ u32 uSecurityState; ++ u32 uConnectionNumber; ++ u32 uUserId; ++ u32 ServerNameOffset; ++ u32 uNdsState; ++ u32 uMaxPacketSize; ++ u32 uLicenseState; ++ u32 uPublicState; ++ u32 bcastState; ++ u32 ServiceTypeOffset; ++ u32 uDistance; ++ u32 uAuthId; ++ u32 uDisconnected; ++ NwcServerVersion serverVersion; ++ NwcTranAddrEx tranAddress; ++ unsigned char buBuffer[NW_INFO_BUFFER_SIZE]; ++ ++} NwcConnInfo, *PNwcConnInfo; ++ ++// ++// Get Browse Connection References ++// ++ ++typedef struct _GetBrowseConnectionsRec { ++ ++ u32 recordSize; ++ u32 numConnectionsReturned; ++ u32 numConnectionsAvailable; ++ u32 connReferences[1]; ++ ++} GetBrowseConnectionRec, *PGetBrowseConnectionRec; ++ ++//++======================================================================= ++// API Name: NwcClearBroadcastMessage ++// ++// Arguments In: NONE ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// ++// Abstract: This API is clears the broadcast message buffer. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++//++======================================================================= ++// API Name: NwcCloseConn ++// ++// Arguments In: ConnHandle - The handle to a connection that is ++// no longer needed. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_INVALID_OWNER ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API is used by an application that opened the ++// connection using one of the open connection calls ++// is finished using the connection. After it is closed, ++// the handle may no longer be used to access the ++// connection. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcCloseConn { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcCloseConn, *PNwcCloseConn; ++ ++//++======================================================================= ++// API Name: NwcConvertLocalFileHandle ++// ++// Arguments In: NONE ++// ++// Arguments Out: uConnReference - The connection reference associated ++// with the returned NetWare file handle. ++// ++// pNetWareFileHandle - The six byte NetWare file handle ++// associated with the given local file handle. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_RESOURCE_NOT_OWNED ++// ++// Abstract: This API is used to return the NetWare handle that ++// has been associated to a local file handle. ++// In addition to returning the NetWare file handle, ++// this API also returns the connection reference to ++// the connection that owns the file. ++// ++// Notes: This API does not create a new NetWare handle, it ++// only returns the existing handle associated to the ++// local handle. ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcConvertLocalHandle { ++ u32 uConnReference; ++ unsigned char NetWareHandle[6]; ++ ++} NwcConvertLocalHandle, *PNwcConvertLocalHandle; ++ ++//++======================================================================= ++// API Name: NwcConvertNetWareHandle ++// ++// Arguments In: ConnHandle - The connection associated with the ++// NetWare file handle to convert. ++// ++// uAccessMode - The access rights to be used when ++// allocating the local file handle. ++// ++// pNetWareHandle - The NetWare handle that will be ++// bound to the new local handle being created. ++// ++// uFileSize - The current file size of the NetWare ++// file associated with the given NetWare file handle. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_RESOURCE_NOT_OWNED ++// ++// Abstract: This API is used to convert a NetWare file handle ++// to a local file handle. ++// ++// The local handle must have been created previously ++// by doing a local open to \Special\$Special.net. ++// ++// Then an Ioctl to this function must be issued using the ++// handle returned from the special net open. ++// ++// Notes: After making this call, the NetWare file handle ++// should not be closed using the NetWare library ++// call, instead it should be closed using the local ++// operating system's close call. ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++typedef struct tagNwcConvertNetWareHandle { ++ NW_CONN_HANDLE ConnHandle; ++ u32 uAccessMode; ++ unsigned char NetWareHandle[6]; ++ u32 uFileSize; ++} NwcConvertNetWareHandle, *PNwcConvertNetWareHandle; ++ ++//++======================================================================= ++// API Name: NwcFragmentRequest ++// ++// Arguments In: ConnHandle ++// The connection handle the request is being ++// directed to. ++// ++// uFunction ++// The NCP function to be called, should be 104 ++// for NDS fragger/defragger requests. ++// ++// uSubFunction ++// The NCP subfunction to be called, should be ++// 2 for NDS fragger/defragger requests. ++// ++// uVerb ++// The actual operation to be completed on the ++// server backend. ++// ++// flags ++// Currently not implemented. Reserved for ++// future use. ++// ++// uNumRequestFrags ++// The number of fragments that the request packet ++// has been broken into. ++// ++// pRequestFrags ++// List of fragments that make up the request packet. ++// Each fragment includes the length of the fragment ++// data and a pointer to the data. ++// ++// uNumReplyFrags ++// The number of fragments the reply packet has been ++// broken into. ++// ++// Arguments Out: pReplyFrags ++// List of fragments that make up the reply packet. ++// Each fragment includes the length of the fragment ++// data and a pointer to the data. ++// ++// uActualReplyLength ++// Total size of the reply packet after any header ++// and tail information is removed. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// ++// Abstract: API for sending large NCP/NDS packets that are ++// larger than the max MTU size for the underlying ++// network. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++typedef struct tagNwcFragmentRequest { ++ NW_CONN_HANDLE ConnHandle; ++ u32 uFunction; ++ u32 uSubFunction; ++ u32 uVerb; ++ u32 flags; ++ u32 uNumRequestFrags; ++ PNwcFrag pRequestFrags; ++ u32 uNumReplyFrags; ++ PNwcFrag pReplyFrags; ++ u32 uActualReplyLength; ++} NwcFragmentRequest, *PNwcFragmentRequest; ++ ++//++======================================================================= ++// API Name: NwcGetBroadcastMessage ++// ++// Arguments In: uMessageFlags - Not currently used. ++// ++// uConnReference - connection reference for ++// pending message. ++// ++// messageLen - length of message buffer. ++// ++// message - message buffer ++// ++// Arguments Out: messageLen - length of the message ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_NO_MORE_ENTRIES ++// ++// Abstract: This API is used for notifying a caller of pending ++// broadcast messages on the server. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++/* jlt ++typedef struct tagNwcGetBroadcastMessage ++{ ++ u32 uMessageFlags; ++ u32 uConnReference; ++ u32 messageLen; ++ unsigned char message[255]; ++ ++} NwcGetBroadcastMessage, *PNwcGetBroadcastMessage; ++*/ ++ ++//++======================================================================= ++// API Name: NwcGetConnInfo ++// ++// Arguments In: ConnHandle - Connection handle for the connection to ++// get information on. ++// uInfoLevel - Specifies what information should be ++// returned. ++// uInfoLen - Length of the ConnInfo buffer. ++// ++// Arguments Out: pConnInfo - A pointer to a buffer to return connection ++// information in. If the caller is requesting all ++// information the pointer will be to a structure of ++// type NwcConnInfo. If the caller is requesting just ++// a single piece of information, the pointer is the ++// type of information being requested. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_INVALID_OWNER ++// NWE_RESOURCE_LOCK ++// NWE_STRING_TRANSLATION ++// ++// Abstract: This API returns connection information for the specified ++// connection. The requester can receive one piece of ++// information or the whole information structure. ++// Some of the entries in the NwcConnInfo structure are ++// pointers. The requester is responsible for supplying ++// valid pointers for any info specified to be returned. ++// If the requester does not want a piece of information ++// returned, a NULL pointer should be placed in the field. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetConnInfo { ++ NW_CONN_HANDLE ConnHandle; ++ u32 uInfoLevel; ++ u32 uInfoLength; ++ void *pConnInfo; ++ ++} NwcGetConnInfo, *PNwcGetConnInfo; ++ ++//++======================================================================= ++// API Name: NwcGetDefaultNameContext ++// ++// Arguments In:: uTreeLength - Length of tree string. ++// ++// pDsTreeName - Pointer to tree string (multi-byte) ++// ++// pNameLength - On input, this is the length of the ++// name context buffer. On output, this is the actual ++// length of the name context string. ++// ++// Arguments Out: pNameContext - The buffer to copy the default name ++// context into (multi-byte). ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_BUFFER_OVERFLOW ++// NWE_OBJECT_NOT_FOUND ++// NWE_PARAM_INVALID ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API returns the default name context that ++// was previously set either by configuration or ++// by calling NwcSetDefaultNameContext. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetDefaultNameContext { ++ u32 uTreeLength; ++ unsigned char *pDsTreeName; ++ u32 uNameLength; ++// unsigned short *pNameContext; ++ unsigned char *pNameContext; ++ ++} NwcGetDefaultNameContext, *PNwcGetDefaultNameContext; ++ ++//++======================================================================= ++// API Name: NwcGetTreeMonitoredConnReference ++// ++// Arguments In: NONE ++// ++// Arguments Out: uConnReference - The connection reference associated ++// with the monitored connection. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_OBJECT_NOT_FOUND ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This call returns a connection reference to a ++// connection that is monitored. This connection ++// reference may be used to open the connection. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetTreeMonitoredConnRef { ++ PNwcString pTreeName; ++ u32 uConnReference; ++ ++} NwcGetTreeMonitoredConnRef, *PNwcGetTreeMonitoredConnRef; ++ ++//++======================================================================= ++// API Name: NwcGetNumberConns ++// ++// Arguments In: NONE ++// ++// Arguments Out: uMaxConns - The maximum number of connections ++// supported by the redirector. -1 for dynamic. ++// ++// uPublicConns - The current number of public ++// connections. ++// ++// uTasksPrivateConns - The current number of private ++// connections that are owned by the calling process. ++// ++// uOtherPrivateConns - The current number of private ++// connections that are not owned by the calling ++// process. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API returns the current number of connections ++// as well as the maximum number of supported ++// connections. If the requester/redirector supports ++// a dynamic connection table, -1 will be returned ++// in the uMaxConns field. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetNumberConns { ++ u32 uMaxConns; ++ u32 uPublicConns; ++ u32 uTasksPrivateConns; ++ u32 uOtherPrivateConns; ++ ++} NwcGetNumberConns, *PNwcGetNumberConns; ++ ++//++======================================================================= ++// API Name: NwcGetPreferredServer ++// ++// Arguments In: uServerNameLength - On input, this is the length ++// in bytes of the server buffer. On output, this is ++// the actual length of the server name string in bytes. ++// ++// Arguments Out: pServerName - The buffer to copy the preferred server ++// name into. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_BUFFER_OVERFLOW ++// NWE_OBJECT_NOT_FOUND ++// NWE_PARAM_INVALID ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API returns the configured preferred bindery ++// server previously set either by configuration or ++// by calling NwcSetPreferredServer. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetPreferredServer { ++ u32 uServerNameLength; ++ char *pServerName; ++ ++} NwcGetPreferredServer, *PNwcGetPreferredServer; ++ ++//++======================================================================= ++// API Name: NwcGetPreferredDsTree ++// ++// Arguments In: uTreeLength - On input, this is the length in bytes ++// of the DS tree name buffer. On output, this is the ++// actual length of the DS tree name string in bytes. ++// ++// Arguments Out: pDsTreeName - The buffer to copy the DS tree name into. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_BUFFER_OVERFLOW ++// NWE_PARAM_INVALID ++// NWE_DS_PREFERRED_NOT_FOUND ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API returns the preferred DS tree name that was ++// previously set either by configuration or ++// by calling NwcSetPreferredDsTree. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++typedef struct tagNwcGetPreferredDsTree { ++ u32 uTreeLength; ++ unsigned char *pDsTreeName; ++} NwcGetPreferredDsTree, *PNwcGetPreferredDsTree; ++ ++//++======================================================================= ++// API Name: NwcGetPrimaryConnection ++// ++// Arguments In: NONE ++// ++// Arguments Out: uConnReference - Reference to the primary connection. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_PRIMARY_NOT_SET ++// ++// Abstract: This API returns the reference to the current primary ++// connection in the redirector. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetPrimaryConnection { ++ u32 uConnReference; ++ ++} NwcGetPrimaryConnection, *PNwcGetPrimaryConnection; ++ ++//++======================================================================= ++// API Name: NwcGetRequesterVersion ++// ++// Arguments In: NONE ++// ++// Arguments Out: uMajorVersion ++// uMinorVersion ++// uRevision ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: This API returns the major version, minor version and ++// revision of the requester/redirector. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetRequesterVersion { ++ u32 uMajorVersion; ++ u32 uMinorVersion; ++ u32 uRevision; ++ ++} NwcGetRequesterVersion, *PNwcGetRequesterVersion; ++ ++//++======================================================================= ++// API Name: NwcLicenseConn ++// ++// Arguments In: ConnHandle - An open connection handle that is in ++// an unlicensed state. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_HANDLE_ALREADY_LICENSED ++// ++// ++// Abstract: This API changes a connections state to licensed. ++// The licensed count will be incremented, and if ++// necessary, the license NCP will be sent. ++// If this handle is already in a licensed state, ++// an error will be returned. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcLicenseConn { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcLicenseConn, *PNwcLicenseConn; ++ ++//++======================================================================= ++// API Name: NwcMakeConnPermanent ++// ++// Arguments In: ConnHandle - An open connection handle associated ++// with the connection to be made permanent. ++// ++// Arguments Out: NONE ++// ++// Returns: NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_INVALID_OWNER ++// ++// Abstract: This API is used to keep the connection from being ++// destroyed until a NwcSysCloseConn request is made ++// on the connection. This allows the connection to ++// remain after all processes that have the ++// connection open terminate. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcMakeConnPermanent { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcMakeConnPermanent, *PNwcMakeConnPermanent; ++ ++//++======================================================================= ++// API Name: NwcMapDrive ++// ++// Arguments In: ConnHandle - The connection handle of the server ++// to where the drive is to be mapped. ++// ++// LocalUID - Local user ID ++// ++// LocalPathLen - Length of local/link directory path string, ++// including nul terminator. ++// ++// LocalPathOffset - Offset of local directory path that will ++// be mapped to NetWare directory path. ++// ++// NetWarePathLen - Offset of NetWare directory path, ++// including nul terminator. ++// ++// NetWarePathOffset - Offset of NetWare directory path in ++// structure. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_INSUFFICIENT_RESOURCES ++// NWE_STRING_TRANSLATION ++// ++// Abstract: This API maps the target drive to the specified ++// directory. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcMapDrive { ++ NW_CONN_HANDLE ConnHandle; ++ u32 LocalUID; ++ u32 LinkPathLen; ++ u32 LinkPathOffset; ++ u32 DestPathLen; ++ u32 DestPathOffset; ++ ++} NwcMapDrive, *PNwcMapDrive; ++ ++//++======================================================================= ++// API Name: NwcUnmapDrive ++// ++// Arguments In: LinkPathLen - Length of local/link path string, ++// including nul terminator. ++// ++// LinkPath - Local/link path in structure ++// to be unmapped ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_PARAM_INVALID ++// ++// Abstract: This API deletes a network drive mapping. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcUnmapDrive { ++ u32 LinkPathLen; ++ unsigned char LinkPath[1]; ++ ++} NwcUnmapDrive, *PNwcUnmapDrive; ++ ++//++======================================================================= ++// API Name: NWCGetMappedDrives ++// ++// Arguments In: ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_BUFFER_OVERFLOW ++// ++// Abstract: This API returns the NetWare mapped drive info ++// per user. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcMapDriveElem { ++ u32 ElemLen; // Lenght of drive element ++ u32 ConnRefernce; // Connection reference ++ u32 LinkPathLen; // Local/link dir path, length includes nul ++ unsigned char LinkPath[1]; // LinkPath[LinkPathLen] ++// u32 DirPathLen; // NetWare dir path, length includes nul (vol:path) ++// unsigned char DirPath[DirPathLen]; // NetWarePath[DirPathLen] ++} NwcMapDriveElem, *PNwcMapDriveElem; ++ ++typedef struct tagNwcMapDriveBuff { ++ u32 MapCount; // Number of mapped drives ++ NwcMapDriveElem MapDriveElem[1]; // MapDriveElem[MapCount] ++ ++} NwcMapDriveBuff, *PNwcMapDriveBuff; ++ ++typedef struct tagNwcGetMappedDrives { ++ u32 MapBuffLen; // Buffer length (actual buffer size returned) ++ PNwcMapDriveBuff MapBuffer; // Pointer to map buffer ++ ++} NwcGetMappedDrives, *PNwcGetMappedDrives; ++ ++//++======================================================================= ++// API Name: NwcGetMountPath ++// ++// Arguments In: MountPathLen - Length of mount path buffer ++// including nul terminator. ++// ++// Arguments Out: MountPath - Pointer to mount path buffer ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_BUFFER_OVERFLOW ++// ++// Abstract: This API returns the mount point of the NOVFS file ++// system. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetMountPath { ++ u32 MountPathLen; ++ unsigned char *pMountPath; ++ ++} NwcGetMountPath, *PNwcGetMountPath; ++ ++//++======================================================================= ++// API Name: NwcMonitorConn ++// ++// Arguments In: ConnHandle - The handle associated with the connection ++// that is to be marked as the monitored connection. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_RESOURCE_LOCK ++// NWE_CONN_INVALID ++// ++// ++// Abstract: This call marks the connection associated with the ++// connection handle as monitored. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcMonitorConn { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcMonitorConn, *PNwcMonitorConn; ++ ++//++======================================================================= ++// API Name: NwcOpenConnByAddr ++// ++// Arguments In: pServiceType - The type of service required. ++// ++// uConnFlags - Specifies whether this connection ++// should be public or private. ++// ++// pTranAddress - Specifies the transport address of ++// the service to open a connection on. ++// a connection to. ++// ++// Arguments Out: ConnHandle - The new connection handle returned. ++// This handle may in turn be used for all requests ++// directed to this connection. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_INSUFFICIENT_RESOURCES ++// NWE_TRAN_INVALID_TYPE ++// NWE_RESOURCE_LOCK ++// NWE_UNSUPPORTED_TRAN_TYPE ++// ++// Abstract: This API will create a service connection to ++// the service specified by the transport address. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcOpenConnByAddr { ++ char *pServiceType; ++ u32 uConnFlags; ++ PNwcTranAddr pTranAddr; ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcOpenConnByAddr, *PNwcOpenConnByAddr; ++ ++//++======================================================================= ++// API Name: NwcOpenConnByName ++// ++// Arguments In: ConnHandle - The connection to use when resolving ++// a name. For instance, if the name is a bindery name ++// the requester will scan the bindery of the given ++// connection to retrieve the service's address. This ++// value can also be NULL if the caller doesn't care ++// which connection is used to resolve the address. ++// ++// pName - A pointer to the name of the service trying ++// to be connected to. This string is NULL terminated, ++// contains no wild cards, and is a maximum of 512 ++// characters long. ++// ++// pServiceType - The type of service required. ++// ++// uConnFlags - Specifies whether this connection ++// should be public or private. ++// ++// uTranType - Specifies the preferred or required ++// transport type to be used. ++// NWC_TRAN_TYPE_WILD may be ORed with the other values ++// or used alone. When ORed with another value, the ++// wild value indicates an unmarked alternative is ++// acceptable. When used alone, the current preferred ++// transport is used. ++// ++// Arguments Out: ConnHandle - The new connection handle returned. ++// This handle may in turn be used for all requests ++// directed to this connection. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_BUFFER_OVERFLOW ++// NWE_INSUFFICIENT_RESOURCES ++// NWE_INVALID_STRING_TYPE ++// NWE_RESOURCE_LOCK ++// NWE_STRING_TRANSLATION ++// NWE_TRAN_INVALID_TYPE ++// NWE_UNSUPPORTED_TRAN_TYPE ++// ++// Abstract: This API will resolve the given name to a network ++// address then create a service connection to the ++// specified service. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcOpenConnByName { ++ NW_CONN_HANDLE ConnHandle; ++ PNwcConnString pName; ++ char *pServiceType; ++ u32 uConnFlags; ++ u32 uTranType; ++ NW_CONN_HANDLE RetConnHandle; ++ ++} NwcOpenConnByName, *PNwcOpenConnByName; ++ ++//++======================================================================= ++// API Name: NwcOpenConnByReference ++// ++// Arguments In: uConnReference - A reference handle which identifies ++// a valid connection that the caller wants to obtain ++// a connection handle to. A reference handle can be ++// used to get information about the connection without ++// actually getting a handle to it. A connection handle ++// must be used to make actual requests to that ++// connection. ++// ++// uConnFlags - Currently unused. ++// ++// Arguments Out: ConnHandle - The new connection handle returned. ++// This handle may in turn be used for all requests ++// directed to this connection. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// ++// Abstract: This API will open the connection associated with ++// the given connection reference. The connection ++// reference can be obtained by calling the ++// NwcScanConnInfo API. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcOpenConnByReference { ++ u32 uConnReference; ++ u32 uConnFlags; ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcOpenConnByReference, *PNwcOpenConnByReference; ++ ++//++======================================================================= ++// API Name: NwcRawRequest ++// ++// Arguments In: ConnHandle - The connection handle of the connection ++// that the request is being directed to. ++// ++// uFunction - The NCP function that is being called. ++// ++// uNumRequestFrags - The number of fragments that the ++// request packet has been broken into. ++// ++// pRequestFrags - List of fragments that make up the ++// request packet. Each fragment includes the length ++// of the fragment data and a pointer to the data. ++// ++// uNumReplyFrags - The number of fragments the reply ++// packet has been broken into. ++// ++// Arguments Out: pReplyFrags - List of fragments that make up the ++// request packet. Each fragment includes the length ++// of the fragment data and a pointer to the data. ++// ++// uActualReplyLength - Total size of the reply packet ++// after any header and tail information is removed. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// ++// Abstract: API for sending raw NCP packets directly to a server. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcRequest { ++ NW_CONN_HANDLE ConnHandle; ++ u32 uFunction; ++ u32 uNumRequestFrags; ++ PNwcFrag pRequestFrags; ++ u32 uNumReplyFrags; ++ PNwcFrag pReplyFrags; ++ u32 uActualReplyLength; ++ ++} NwcRequest, *PNwcRequest; ++ ++//++======================================================================= ++// API Name: NwcRawRequestAll ++// ++// Arguments In: uFunction - The NCP function that is being called. ++// ++// uNumRequestFrags - The number of fragments that the ++// request packet has been broken into. ++// ++// pRequestFrags - List of fragments that make up the ++// request packet. Each fragment includes the length ++// of the fragment data and a pointer to the data. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// ++// Abstract: API for sending the given NCP request to all valid ++// connections. If there is a private connection that ++// is not owned by the caller of this function, that ++// connection will not be included. Also, if the ++// caller has both a private and a public connection ++// to the same server, only the private connection ++// will receive the request. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcRequestAll { ++ u32 uFunction; ++ u32 uNumRequestFrags; ++ PNwcFrag pRequestFrags; ++ ++} NwcRequestAll, *PNwcRequestAll; ++ ++//++======================================================================= ++// API Name: NwcScanConnInfo ++// ++// Arguments In: uScanIndex - The index to be used on the next ++// iteration of the scan. This value should be initially ++// set to zero. The output of this parameter will be ++// used in subsequent calls to this function. ++// ++// uScanInfoLevel - Describes the composition of the ++// pScanConnInfo pointer. If this parameter contains ++// NWC_CONN_INFO_RETURN_ALL, information for all ++// connections will be returned. ++// ++// uScanInfoLen - Lenght of pScanConnInfo buffer ++// ++// pScanConnInfo - This parameter is a pointer to ++// data that describes one piece of connection ++// information. The type of this data depends on ++// which level of information is being scanned for. ++// For instance, if the scan is being used to find all ++// connections with a particular authentication state, ++// pScanConnInfo would be a "pnuint" since ++// authentication state is described as nuint in the ++// NwcConnInfo structure. ++// ++// uScanFlag - This parameter tells whether to return ++// connection information for connections that match ++// the scan criteria or that do not match the scan ++// criteria. If the caller wants to find all the ++// connections that are not in the "NOVELL_INC" DS ++// tree, he would use the call as described below in ++// the description except the uScanFlag parameter would ++// have the value of NWC_MATCH_NOT_EQUALS. This flag ++// is also used to tell the requester whether to ++// return private or public, licensed or unlicensed ++// connections. ++// ++// uReturnInfoLevel - Specifies what information ++// should be returned. ++// ++// uReturnInfoLength - The size in bytes of pConnInfo. ++// ++// Arguments Out: uConnectionReference - Connection reference ++// associated with the information that is being ++// returned. ++// ++// pReturnConnInfo - A pointer to the NwcConnInfo ++// structure defined above. In some of the ++// structures within the union, there are pointers to ++// data to be returned. It is the responsibility of ++// the caller to provide pointers to valid memory ++// to copy this data into. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_RESOURCE_LOCK ++// NWE_CONN_INVALID ++// NWE_INVALID_LEVEL ++// NWE_STRING_TRANSLATION ++// NWE_INVALID_MATCH_DATA ++// NWE_MATCH_FAILED ++// NWE_BUFFER_OVERFLOW ++// NWE_NO_MORE_ENTRIES ++// ++// Abstract: This API is used to return connection information ++// for multiple connections. It will return one ++// piece or the full structure of connection information ++// for one connection at a time. This call is designed ++// to scan for connections based on any piece of ++// connection information as described in the ++// NwcConnInfo structure. For instance, if the caller ++// wants to scan for all connections in the DS tree ++// "NOVELL_INC", the call would be made with the ++// following paramters: ++// ++// uScanLevelInfo = NWC_CONN_INFO_TREE_NAME ++// pScanConnInfo = "NOVELL_INC" ++// uScanFlag = NWC_MATCH_EQUALS | ++// NWC_RETURN_PUBLIC | ++// NWC_RETURN_LICENSED ++// ++// The scan flag is used to tell if the scan is ++// supposed to return connections that match or don't ++// match. This design doesn't allow any other ++// conditions for this flag (such as greater than or ++// less than). ++// ++// If the caller specifies the uReturnInfoLevel = ++// NWC_CONN_INFO_RETURN_ALL, the full NwcConnInfo ++// structure is returned. The caller must supply ++// data for any pointers in the NwcConnInfo structure ++// (these include tree name, workgroup id, server name ++// and transport address). However if the caller ++// doesn't want to get a particular piece of info ++// that is expecting a pointer to some data, a NULL ++// pointer may be used to indicate to the requester ++// that it should not return that piece of information. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcScanConnInfo { ++ u32 uScanIndex; ++ u32 uScanInfoLevel; ++ u32 uScanInfoLen; ++ void *pScanConnInfo; ++ u32 uScanFlags; ++ u32 uReturnInfoLevel; ++ u32 uReturnInfoLength; ++ u32 uConnectionReference; ++ void *pReturnConnInfo; ++ ++} NwcScanConnInfo, *PNwcScanConnInfo; ++ ++//++======================================================================= ++// API Name: NwcSetConnInfo ++// ++// Arguments In: ConnHandle - Connection handle for the connection to ++// set information on. ++// ++// uInfoLevel - Specifies what information should be set. ++// ++// uInfoLen - Length in bytes of the information being set. ++// ++// pConnInfo - Connection information to set. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_RESOURCE_LOCK ++// NWE_CONN_INVALID ++// NWE_INVALID_LEVEL ++// ++// ++// Abstract: This API sets information in the connection associated ++// with the connection handle. ++// ++// Notes: At this time the only setable information levels are: ++// NWC_CONN_INFO_AUTH_STATE ++// NWC_CONN_INFO_BCAST_STATE ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSetConnInfo { ++ NW_CONN_HANDLE ConnHandle; ++ u32 uInfoLevel; ++ u32 uInfoLength; ++ void *pConnInfo; ++ ++} NwcSetConnInfo, *PNwcSetConnInfo; ++ ++//++======================================================================= ++// API Name: NwcSetDefaultNameContext ++// ++// Arguments In:: uTreeLength - Length of tree string. ++// ++// pDsTreeName - The tree string (multi-byte). ++// ++// uNameLength - The length in bytes of the name ++// context string. ++// ++// pNameContext - The string to be used as the default ++// name context (multi-byte). ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_PARAM_INVALID ++// NWE_RESOURCE_LOCK ++// NWE_STRING_TRANSLATION ++// ++// Abstract: This API sets the default name context. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSetDefaultNameContext { ++ u32 uTreeLength; ++ unsigned char *pDsTreeName; ++ u32 uNameLength; ++// unsined short *pNameContext; ++ unsigned char *pNameContext; ++ ++} NwcSetDefaultNameContext, *PNwcSetDefaultNameContext; ++ ++//++======================================================================= ++// API Name: NwcSetPreferredDsTree ++// ++// Arguments In: uTreeLength - The length in bytes of the DS tree name. ++// ++// pDsTreeName - The string to be used as the preferred ++// DS tree name. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_INSUFFICIENT_RESOURCES ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API sets the preferred DS tree name. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSetPreferredDsTree { ++ u32 uTreeLength; ++ unsigned char *pDsTreeName; ++ ++} NwcSetPreferredDsTree, *PNwcSetPreferredDsTree; ++ ++//++======================================================================= ++// API Name: NwcSetPreferredServer ++// ++// Arguments In: uServerNameLength - The length in bytes of the ++// preferred server string. ++// ++// pServerName - a pointer to an ASCIIZ string of the ++// preferred bindery server. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_INSUFFICIENT_RESOURCES ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API sets the preferred server name. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSetPreferredServer { ++ u32 uServerNameLength; ++ char *pServerName; ++ ++} NwcSetPreferredServer, *PNwcSetPreferredServer; ++ ++//++======================================================================= ++// API Name: NwcSetPrimaryConnection ++// ++// Arguments In: ConnHandle - Connection handle associated to the ++// connection reference which the caller wishes to set ++// as primary. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_PRIMARY_NOT_SET ++// ++// Abstract: This API sets the primary connection according to ++// the connection handle passed in by the caller. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSetPrimaryConnection { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcSetPrimaryConnection, *PNwcSetPrimaryConnection; ++ ++//++======================================================================= ++// API Name: NwcSysCloseConn ++// ++// Arguments In: ConnHandle - The handle to a connection that is ++// to be destroyed. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// ++// Abstract: This API is similiar to the NwcCloseConn API, except ++// that it forces all handles to the connection closed ++// and destroys the service connection. This is a system ++// level request that will cause all processes that are ++// accessing this connection to lose access to the ++// resources associated to the connection. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSysCloseConn { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcSysCloseConn, *PNwcSysCloseConn; ++ ++//++======================================================================= ++// API Name: NwcUnlicenseConn ++// ++// Arguments In: ConnHandle - Open connection handle that will be ++// accessing the connection in an unlicensed manner. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_HANDLE_ALREADY_UNLICENSED ++// ++// Abstract: This API is used to change the state of a connection ++// handle from licensed to unlicensed. If all handles ++// to the connection have been changed to the unlicensed ++// state, the unlicensed NCP is sent to the server. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcUnlicenseConn { ++ NW_CONN_HANDLE ConnHandle; ++ ++} NwcUnlicenseConn, *PNwcUnlicenseConn; ++ ++//++======================================================================= ++// API Name: NwcQueryFeature ++// ++// Arguments In: Feature - The number associated with a particular ++// feature that the caller wants to know if the requester ++// is supporting ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_REQUESTER_FAILURE ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcQueryFeature { ++ u32 Feature; ++ ++} NwcQueryFeature, *PNwcQueryFeature; ++ ++//++======================================================================= ++// API Name: NWCChangePassword ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcChangeKey { ++ PNwcString pDomainName; ++ u32 AuthType; ++ PNwcString pObjectName; ++ u32 NameType; ++ u16 ObjectType; ++ PNwcString pVerifyPassword; ++ PNwcString pNewPassword; ++ ++} NwcChangeKey, *PNwcChangeKey; ++ ++//++======================================================================= ++// API Name: NWCEnumerateIdentities ` ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcEnumerateIdentities { ++ u32 Iterator; ++ PNwcString pDomainName; ++ u32 AuthType; ++ PNwcString pObjectName; ++ u32 NameType; ++ u16 ObjectType; ++ u32 IdentityFlags; ++ AUTHEN_ID AuthenticationId; ++ ++} NwcEnumerateIdentities, *PNwcEnumerateIdentities; ++ ++//++======================================================================= ++// API Name: NWCGetIdentityInfo ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcGetIdentityInfo { ++ AUTHEN_ID AuthenticationId; ++ PNwcString pDomainName; ++ u32 AuthType; ++ PNwcString pObjectName; ++ u32 NameType; ++ u16 ObjectType; ++ u32 IdentityFlags; ++ ++} NwcGetIdentityInfo, *PNwcGetIdentityInfo; ++ ++//++======================================================================= ++// API Name: NWCLoginIdentity ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcLoginIdentity { ++ PNwcString pDomainName; ++ u32 AuthType; ++ PNwcString pObjectName; ++ u32 NameType; ++ u16 ObjectType; ++ u32 IdentityFlags; ++ PNwcString pPassword; ++ AUTHEN_ID AuthenticationId; ++ ++} NwcLoginIdentity, *PNwcLoginIdentity; ++ ++//++======================================================================= ++// API Name: NWCLogoutIdentity ++//// ++ ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcLogoutIdentity { ++ AUTHEN_ID AuthenticationId; ++ ++} NwcLogoutIdentity, *PNwcLogoutIdentity; ++ ++//++======================================================================= ++// API Name: NWCSetPassword ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcSetKey { ++ NW_CONN_HANDLE ConnHandle; ++ AUTHEN_ID AuthenticationId; ++ PNwcString pObjectName; ++ u16 ObjectType; ++ PNwcString pNewPassword; ++ ++} NwcSetKey, *PNwcSetKey; ++ ++//++======================================================================= ++// API Name: NWCVerifyPassword ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//++======================================================================= ++ ++typedef struct tagNwcVerifyKey { ++ PNwcString pDomainName; ++ u32 AuthType; ++ PNwcString pObjectName; ++ u32 NameType; ++ u16 ObjectType; ++ PNwcString pVerifyPassword; ++ ++} NwcVerifyKey, *PNwcVerifyKey; ++ ++//++======================================================================= ++// API Name: NwcAuthenticateWithId ++// ++// Arguments In: ConnHandle - The connection to be authenticated ++// ++// AuthenticationId - the authentication Id associated ++// to the information necessary to authenticate this ++// connection. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: This API is used to authenticate a connection using ++// an authentication ID that has already been created. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcAuthenticateWithId { ++ NW_CONN_HANDLE ConnHandle; ++ AUTHEN_ID AuthenticationId; ++ ++} NwcAuthenticateWithId, *PNwcAuthenticateWithId; ++ ++//++======================================================================= ++// API Name: NwcUnauthenticate ++// ++// Arguments In: ConnHandle - The connection to unauthenticate. ++// ++// Arguments Out: NONE ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// NWE_INVALID_OWNER ++// NWE_RESOURCE_LOCK ++// ++// Abstract: This API removes the authentication for the specified ++// connection. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcUnauthenticate { ++ NW_CONN_HANDLE ConnHandle; ++ AUTHEN_ID AuthenticationId; ++ ++} NwcUnauthenticate, *PNwcUnauthenticate; ++ ++//++======================================================================= ++// API Name: NwcGetCfgNameServiceProviders ++// ++// Arguments In: ++// ++// Arguments Out: ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// ++// Abstract: ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct { ++ u32 providerCount; ++ u32 providers[MAX_NAME_SERVICE_PROVIDERS]; ++ ++} NwcGetCfgNameServiceProviders, *PNwcGetCfgNameServiceProviders; ++ ++//++======================================================================= ++// API Name: NwcNdsResolveNameToId ++// ++// Arguments In: connHandle ++// Specifies connection to use to resolve name with. ++// ++// pName ++// Points to the name of the NDS entry to resolve. ++// ++// uReqTranType ++// Specifies the preferred or required transport to ++// be used. ++// ++// pResolveInfo ++// Points to the NwcNdsResolveInfo structure ++// containing information on how the entry is to be ++// resolved. ++// ++// Arguments Out: pResolveInfo ++// Points to the NwcNdsResolveInfo structure ++// containing return information on the resolved ++// entry. ++// ++// pluEntryId ++// Points to the resolved name's entry ID. ++// ++// pReferral ++// Points to the NwcReferral structure which describes ++// network addresses that can be used to locate other ++// NDS partitions that contain the entry name. ++// ++// Returns: STATUS_SUCCESS ++// NWE_CONN_INVALID, ++// NWE_BUFFER_OVERFLOW, ++// NWE_TRAN_INVALID_TYPE, ++// NWE_ACCESS_VIOLATION, ++// NWE_UNSUPPORTED_TRAN_TYPE, ++// Nds error code ++// ++// Abstract: This API resolves a NDS entry name. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcNdsResolveNameToId { ++ NW_CONN_HANDLE connHandle; ++ PNwcString pName; ++ u32 uReqTranType; ++ PNwcResolveInfo pResolveInfo; ++ u32 entryId; ++ PNwcReferral pReferral; ++ ++} NwcNdsResolveNameToId, *PNwcNdsResolveNameToId; ++ ++//++======================================================================= ++// API Name: NwcOrderedRequest ++// ++// Arguments In: uFunction - The NCP function that is being called. ++// ++// uNumRequestFrags - The number of fragments that the ++// request packet has been broken into. ++// ++// pRequestFrags - List of fragments that make up the ++// request packet. Each fragment includes the length ++// of the fragment data and a pointer to the data. ++// ++// uInverseReqCode - The NCP function that will be called ++// if the request fails. ++// ++// uNumInverseFrags - The number of fragments the inverse ++// request packet has been broken into. ++// ++// pReplyFrags - List of fragments that make up the ++// inverse request packet. Each fragment includes the length ++// of the fragment data and a pointer to the data. ++// ++// Returns: STATUS_SUCCESS ++// NWE_ACCESS_VIOLATION ++// NWE_CONN_INVALID ++// ++// Abstract: API for sending raw NCP packets directly to a server. ++// ++// Notes: ++// ++// Environment: PASSIVE_LEVEL, LINUX ++// ++//=======================================================================-- ++ ++typedef struct tagNwcOrderedRequest { ++ u32 uReqCode; ++ u32 uNumRequestFrags; ++ PNwcFrag pRequestFrags; ++ u32 uInverseReqCode; ++ u32 uNumInverseFrags; ++ PNwcFrag pInverseFrags; ++ ++} NwcOrderedRequest, *PNwcOrderedRequest; ++ ++#if 1 //sgled ++typedef struct tagNwcUnmapDriveEx { ++// unsigned long connHdl; ++ unsigned int linkLen; ++ char linkData[1]; ++ ++} NwcUnmapDriveEx, *PNwcUnmapDriveEx; ++ ++typedef struct tagNwcMapDriveEx { ++ NW_CONN_HANDLE ConnHandle; ++ unsigned int localUid; ++ unsigned int linkOffsetLength; ++ unsigned int linkOffset; ++ unsigned int dirPathOffsetLength; ++ unsigned int dirPathOffset; ++} NwcMapDriveEx, *PNwcMapDriveEx; ++ ++typedef struct tagNwcGetBroadcastNotification { ++ u32 uMessageFlags; ++ u32 uConnReference; ++ u32 messageLen; ++ char message[1]; ++} NwcGetBroadcastNotification, *PNwcGetBroadcastNotification; ++ ++#endif ++#endif /* __NWCLNX_H__ */ +--- /dev/null ++++ b/fs/novfs/nwerror.h +@@ -0,0 +1,658 @@ ++/* ++ * NetWare Redirector for Linux ++ * Author: Tom Buckley ++ * ++ * This file contains all return error codes. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++#ifndef __NOVFS_ERROR_H ++#define __NOVFS_ERROR_H ++ ++ ++/* ++ * Network errors ++ * Decimal values at end of line are 32768 lower than actual ++ */ ++ ++#define SHELL_ERROR 0x8800 ++#define VLM_ERROR 0x8800 ++#define ALREADY_ATTACHED 0x8800 // 0 - Attach attempted to server with valid, existing connection ++#define INVALID_CONNECTION 0x8801 // 1 - Request attempted with invalid or non-attached connection handle ++#define DRIVE_IN_USE 0x8802 // 2 - OS/2 only (NOT USED) ++#define CANT_ADD_CDS 0x8803 // 3 - Map drive attempted but unable to add new current directory structure ++#define DRIVE_CANNOT_MAP 0x8803 ++#define BAD_DRIVE_BASE 0x8804 // 4 - Map drive attempted with invalid path specification ++#define NET_READ_ERROR 0x8805 // 5 - Attempt to receive from the selected transport failed ++#define NET_RECV_ERROR 0x8805 // 5 ++#define UNKNOWN_NET_ERROR 0x8806 // 6 - Network send attempted with an un-specific network error ++#define SERVER_INVALID_SLOT 0x8807 // 7 - Server request attempted with invalid server connection slot ++#define BAD_SERVER_SLOT 0x8807 // 7 ++#define NO_SERVER_SLOTS 0x8808 // 8 - Attach attempted to server with no connection slots available ++#define NET_WRITE_ERROR 0x8809 // 9 - Attempt to send on the selected transport failed ++#define CONNECTION_IN_ERROR_STATE 0x8809 // Client-32 ++#define NET_SEND_ERROR 0x8809 // 9 ++#define SERVER_NO_ROUTE 0x880A // 10 - Attempted to find route to server where no route exists ++#define BAD_LOCAL_TARGET 0x880B // 11 - OS/2 only ++#define TOO_MANY_REQ_FRAGS 0x880C // 12 - Attempted request with too many request fragments specified ++#define CONNECT_LIST_OVERFLOW 0x880D // 13 ++#define BUFFER_OVERFLOW 0x880E // 14 - Attempt to receive more data than the reply buffer had room for ++#define MORE_DATA_ERROR 0x880E // Client-32 ++#define NO_CONN_TO_SERVER 0x880F // 15 ++#define NO_CONNECTION_TO_SERVER 0x880F // 15 - Attempt to get connection for a server not connected ++#define NO_ROUTER_FOUND 0x8810 // 16 - OS/2 only ++#define BAD_FUNC_ERROR 0x8811 // 17 ++#define INVALID_SHELL_CALL 0x8811 // 17 - Attempted function call to non- existent or illegal function ++#define SCAN_COMPLETE 0x8812 ++#define LIP_RESIZE_ERROR 0x8812 // Client-32 ++#define UNSUPPORTED_NAME_FORMAT_TYPE 0x8813 ++#define INVALID_DIR_HANDLE 0x8813 // Client-32 ++#define HANDLE_ALREADY_LICENSED 0x8814 ++#define OUT_OF_CLIENT_MEMORY 0x8814 // Client-32 ++#define HANDLE_ALREADY_UNLICENSED 0x8815 ++#define PATH_NOT_OURS 0x8815 // Client-32 ++#define INVALID_NCP_PACKET_LENGTH 0x8816 ++#define PATH_IS_PRINT_DEVICE 0x8816 // Client-32 ++#define SETTING_UP_TIMEOUT 0x8817 ++#define PATH_IS_EXCLUDED_DEVICE 0x8817 // Client-32 ++#define SETTING_SIGNALS 0x8818 ++#define PATH_IS_INVALID 0x8818 // Client-32 ++#define SERVER_CONNECTION_LOST 0x8819 ++#define NOT_SAME_DEVICE 0x8819 // Client-32 ++#define OUT_OF_HEAP_SPACE 0x881A ++#define INVALID_SERVICE_REQUEST 0x881B ++#define INVALID_SEARCH_HANDLE 0x881B // Client-32 ++#define INVALID_TASK_NUMBER 0x881C ++#define INVALID_DEVICE_HANDLE 0x881C // Client-32 ++#define INVALID_MESSAGE_LENGTH 0x881D ++#define INVALID_SEM_HANDLE 0x881D // Client-32 ++#define EA_SCAN_DONE 0x881E ++#define INVALID_CFG_HANDLE 0x881E // Client-32 ++#define BAD_CONNECTION_NUMBER 0x881F ++#define INVALID_MOD_HANDLE 0x881F // Client-32 ++#define ASYN_FIRST_PASS 0x8820 ++#define INVALID_DEVICE_INDEX 0x8821 ++#define INVALID_CONN_HANDLE 0x8822 ++#define INVALID_QUEUE_ID 0x8823 ++#define INVALID_PDEVICE_HANDLE 0x8824 ++#define INVALID_JOB_HANDLE 0x8825 ++#define INVALID_ELEMENT_ID 0x8826 ++#define ALIAS_NOT_FOUND 0x8827 ++#define RESOURCE_SUSPENDED 0x8828 ++#define INVALID_QUEUE_SPECIFIED 0x8829 ++#define DEVICE_ALREADY_OPEN 0x882A ++#define JOB_ALREADY_OPEN 0x882B ++#define QUEUE_NAME_ID_MISMATCH 0x882C ++#define JOB_ALREADY_STARTED 0x882D ++#define SPECT_DAA_TYPE_NOT_SUPPORTED 0x882E ++#define INVALID_ENVIR_HANDLE 0x882F ++#define NOT_SAME_CONNECTION 0x8830 // 48 - Internal server request attempted accross different server connections ++#define PRIMARY_CONNECTION_NOT_SET 0x8831 // 49 - Attempt to retrieve default connection with no primary connection set ++#define NO_PRIMARY_SET 0x8831 // 49 ++#define KEYWORD_NOT_FOUND 0x8832 // Client-32 ++#define PRINT_CAPTURE_NOT_IN_PROGRESS 0x8832 // Client-32 ++#define NO_CAPTURE_SET 0x8832 // 50 ++#define NO_CAPTURE_IN_PROGRESS 0x8832 // 50 - Capture information requested on port with no capture in progress ++#define BAD_BUFFER_LENGTH 0x8833 // 51 ++#define INVALID_BUFFER_LENGTH 0x8833 // 51 - Used to indicate length which caller requested on a GetDNC or SetDNC was too large ++#define NO_USER_NAME 0x8834 // 52 ++#define NO_NETWARE_PRINT_SPOOLER 0x8835 // 53 - Capture requested without having the local print spooler installed ++#define INVALID_PARAMETER 0x8836 // 54 - Attempted function with an invalid function parameter specified ++#define CONFIG_FILE_OPEN_FAILED 0x8837 // 55 - OS/2 only ++#define NO_CONFIG_FILE 0x8838 // 56 - OS/2 only ++#define CONFIG_FILE_READ_FAILED 0x8839 // 57 - OS/2 only ++#define CONFIG_LINE_TOO_LONG 0x883A // 58 - OS/2 only ++#define CONFIG_LINES_IGNORED 0x883B // 59 - OS/2 only ++#define NOT_MY_RESOURCE 0x883C // 60 - Attempted request made with a parameter using foriegn resource ++#define DAEMON_INSTALLED 0x883D // 61 - OS/2 only ++#define SPOOLER_INSTALLED 0x883E // 62 - Attempted load of print spooler with print spooler already installed ++#define CONN_TABLE_FULL 0x883F // 63 ++#define CONNECTION_TABLE_FULL 0x883F // 63 - Attempted to allocate a connection handle with no more local connection table entries ++#define CONFIG_SECTION_NOT_FOUND 0x8840 // 64 - OS/2 only ++#define BAD_TRAN_TYPE 0x8841 // 65 ++#define INVALID_TRANSPORT_TYPE 0x8841 // 65 - Attempted function on a connection with an invalid transport selected ++#define TDS_TAG_IN_USE 0x8842 // 66 - OS/2 only ++#define TDS_OUT_OF_MEMORY 0x8843 // 67 - OS/2 only ++#define TDS_INVALID_TAG 0x8844 // 68 - Attempted TDS function with invalid tag ++#define TDS_WRITE_TRUNCATED 0x8845 // 69 - Attempted TDS write with buffer that exceeded buffer ++#define NO_CONNECTION_TO_DS 0x8846 // Client-32 ++#define NO_DIRECTORY_SERVICE_CONNECTION 0x8846 // 70 ++#define SERVICE_BUSY 0x8846 // 70 - Attempted request made to partially asynchronous function in busy state ++#define NO_SERVER_ERROR 0x8847 // 71 - Attempted connect failed to find any servers responding ++#define BAD_VLM_ERROR 0x8848 // 72 - Attempted function call to non-existant or not-loaded overlay ++#define NETWORK_DRIVE_IN_USE 0x8849 // 73 - Attempted map to network drive that was already mapped ++#define LOCAL_DRIVE_IN_USE 0x884A // 74 - Attempted map to local drive that was in use ++#define NO_DRIVES_AVAILABLE 0x884B // 75 - Attempted map to next available drive when none were available ++#define DEVICE_NOT_REDIRECTED 0x884C // 76 - The device is not redirected ++#define NO_MORE_SFT_ENTRIES 0x884D // 77 - Maximum number of files was reached ++#define UNLOAD_ERROR 0x884E // 78 - Attempted unload failed ++#define IN_USE_ERROR 0x884F // 79 - Attempted re-use of already in use connection entry ++#define TOO_MANY_REP_FRAGS 0x8850 // 80 - Attempted request with too many reply fragments specified ++#define TABLE_FULL 0x8851 // 81 - Attempted to add a name into the name table after it was full ++#ifndef SOCKET_NOT_OPEN ++#define SOCKET_NOT_OPEN 0x8852 // 82 - Listen was posted on unopened socket ++#endif ++#define MEM_MGR_ERROR 0x8853 // 83 - Attempted enhanced memory operation failed ++#define SFT3_ERROR 0x8854 // 84 - An SFT3 switch occured mid-transfer ++#define PREFERRED_NOT_FOUND 0x8855 // 85 - the preferred directory server was not established but another directory server was returned ++#define DEVICE_NOT_RECOGNIZED 0x8856 // 86 - used to determine if the device is not used by VISE so pass it on to the next redirector, if any. ++#define BAD_NET_TYPE 0x8857 // 87 - the network type (Bind/NDS) does not match the server version ++#define ERROR_OPENING_FILE 0x8858 // 88 - generic open failure error, invalid path, access denied, etc.. ++#define NO_PREFERRED_SPECIFIED 0x8859 // 89 - no preferred name specified ++#define ERROR_OPENING_SOCKET 0x885A // 90 - error opening a socket ++#define REQUESTER_FAILURE 0x885A // Client-32 ++#define RESOURCE_ACCESS_DENIED 0x885B // Client-32 ++#define SIGNATURE_LEVEL_CONFLICT 0x8861 ++#define NO_LOCK_FOUND 0x8862 // OS/2 - process lock on conn handle failed, process ID not recognized ++#define LOCK_TABLE_FULL 0x8863 // OS/2 - process lock on conn handle failed, process lock table full ++#define INVALID_MATCH_DATA 0x8864 ++#define MATCH_FAILED 0x8865 ++#define NO_MORE_ENTRIES 0x8866 ++#define INSUFFICIENT_RESOURCES 0x8867 ++#define STRING_TRANSLATION 0x8868 ++#define STRING_TRANSLATION_NEEDED 0x8868 // Client-32 ++#define ACCESS_VIOLATION 0x8869 ++#define NOT_AUTHENTICATED 0x886A ++#define INVALID_LEVEL 0x886B ++#define RESOURCE_LOCK_ERROR 0x886C ++#define INVALID_NAME_FORMAT 0x886D ++#define OBJECT_EXISTS 0x886E ++#define OBJECT_NOT_FOUND 0x886F ++#define UNSUPPORTED_TRAN_TYPE 0x8870 ++#define INVALID_STRING_TYPE 0x8871 ++#define INVALID_OWNER 0x8872 ++#define UNSUPPORTED_AUTHENTICATOR 0x8873 ++#define IO_PENDING 0x8874 ++#define INVALID_DRIVE_NUM 0x8875 ++#define SHELL_FAILURE 0x88FF ++#define VLM_FAILURE 0x88FF ++ ++#define SVC_ALREADY_REGISTERED 0x8880 // Client-32 ++#define SVC_REGISTRY_FULL 0x8881 // Client-32 ++#define SVC_NOT_REGISTERED 0x8882 // Client-32 ++#define OUT_OF_RESOURCES 0x8883 // Client-32 ++#define RESOLVE_SVC_FAILED 0x8884 // Client-32 ++#define CONNECT_FAILED 0x8885 // Client-32 ++#define PROTOCOL_NOT_BOUND 0x8886 // Client-32 ++#define AUTHENTICATION_FAILED 0x8887 // Client-32 ++#define INVALID_AUTHEN_HANDLE 0x8888 // Client-32 ++#define AUTHEN_HANDLE_ALREADY_EXISTS 0x8889 // Client-32 ++ ++#define DIFF_OBJECT_ALREADY_AUTHEN 0x8890 // Client-32 ++#define REQUEST_NOT_SERVICEABLE 0x8891 // Client-32 ++#define AUTO_RECONNECT_SO_REBUILD 0x8892 // Client-32 ++#define AUTO_RECONNECT_RETRY_REQUEST 0x8893 // Client-32 ++#define ASYNC_REQUEST_IN_USE 0x8894 // Client-32 ++#define ASYNC_REQUEST_CANCELED 0x8895 // Client-32 ++#define SESS_SVC_ALREADY_REGISTERED 0x8896 // Client-32 ++#define SESS_SVC_NOT_REGISTERED 0x8897 // Client-32 ++#define PREVIOUSLY_AUTHENTICATED 0x8899 // Client-32 ++#define RESOLVE_SVC_PARTIAL 0x889A // Client-32 ++#define NO_DEFAULT_SPECIFIED 0x889B // Client-32 ++#define HOOK_REQUEST_NOT_HANDLED 0x889C // Client-32 ++#define HOOK_REQUEST_BUSY 0x889D // Client-32 ++#define HOOK_REQUEST_QUEUED 0x889D // Client-32 ++#define AUTO_RECONNECT_SO_IGNORE 0x889E // Client-32 ++#define ASYNC_REQUEST_NOT_IN_USE 0x889F // Client-32 ++#define AUTO_RECONNECT_FAILURE 0x88A0 // Client-32 ++#define NET_ERROR_ABORT_APPLICATION 0x88A1 // Client-32 ++#define NET_ERROR_SUSPEND_APPLICATION 0x88A2 // Client-32 ++#define NET_ERROR_ABORTED_PROCESS_GROUP 0x88A3 // Client-32 ++#define NET_ERROR_PASSWORD_HAS_EXPIRED 0x88A5 // Client-32 ++#define NET_ERROR_NETWORK_INACTIVE 0x88A6 // Client-32 ++#define REPLY_TRUNCATED 0x88E6 // 230 NLM ++#define UTF8_CONVERSION_FAILED 0x88F0 // NWCALLS ++ ++/* ++ * Server Errors ++ */ ++ ++#define ERR_INSUFFICIENT_SPACE 0x8901 // 001 ++#define NLM_INVALID_CONNECTION 0x890A // 010 ++#define ERR_TIMEOUT 0x8910 // 016 - nlm connection timeout ++#define ERR_NO_MORE_ENTRY 0x8914 // 020 ++#define ERR_BUFFER_TOO_SMALL 0x8977 // 119 ++#define ERR_VOLUME_FLAG_NOT_SET 0x8978 // 120 the service requested, not avail. on the selected vol. ++#define ERR_NO_ITEMS_FOUND 0x8979 // 121 ++#define ERR_CONN_ALREADY_TEMP 0x897A // 122 ++#define ERR_CONN_ALREADY_LOGGED_IN 0x897B // 123 ++#define ERR_CONN_NOT_AUTHENTICATED 0x897C // 124 ++#define ERR_CONN_NOT_LOGGED_IN 0x897D // 125 ++#define NCP_BOUNDARY_CHECK_FAILED 0x897E // 126 ++#define ERR_LOCK_WAITING 0x897F // 127 ++#define ERR_LOCK_FAIL 0x8980 // 128 ++#define FILE_IN_USE_ERROR 0x8980 // 128 ++#define NO_MORE_FILE_HANDLES 0x8981 // 129 ++#define NO_OPEN_PRIVILEGES 0x8982 // 130 ++#define IO_ERROR_NETWORK_DISK 0x8983 // 131 ++#define ERR_AUDITING_HARD_IO_ERROR 0x8983 // 131 ++#define NO_CREATE_PRIVILEGES 0x8984 // 132 ++#define ERR_AUDITING_NOT_SUPV 0x8984 // 132 ++#define NO_CREATE_DELETE_PRIVILEGES 0x8985 // 133 ++#define CREATE_FILE_EXISTS_READ_ONLY 0x8986 // 134 ++#define WILD_CARDS_IN_CREATE_FILE_NAME 0x8987 // 135 ++#define CREATE_FILENAME_ERROR 0x8987 // 135 ++#define INVALID_FILE_HANDLE 0x8988 // 136 ++#define NO_SEARCH_PRIVILEGES 0x8989 // 137 ++#define NO_DELETE_PRIVILEGES 0x898A // 138 ++#define NO_RENAME_PRIVILEGES 0x898B // 139 ++#define NO_MODIFY_PRIVILEGES 0x898C // 140 ++#define SOME_FILES_AFFECTED_IN_USE 0x898D // 141 ++#define NO_FILES_AFFECTED_IN_USE 0x898E // 142 ++#define SOME_FILES_AFFECTED_READ_ONLY 0x898F // 143 ++#define NO_FILES_AFFECTED_READ_ONLY 0x8990 // 144 ++#define SOME_FILES_RENAMED_NAME_EXISTS 0x8991 // 145 ++#define NO_FILES_RENAMED_NAME_EXISTS 0x8992 // 146 ++#define NO_READ_PRIVILEGES 0x8993 // 147 ++#define NO_WRITE_PRIVILEGES_OR_READONLY 0x8994 // 148 ++#define FILE_DETACHED 0x8995 // 149 ++#define SERVER_OUT_OF_MEMORY 0x8996 // 150 ++#define ERR_TARGET_NOT_A_SUBDIRECTORY 0x8996 // 150 can be changed later (note written by server people). ++#define NO_DISK_SPACE_FOR_SPOOL_FILE 0x8997 // 151 ++#define ERR_AUDITING_NOT_ENABLED 0x8997 // 151 ++#define VOLUME_DOES_NOT_EXIST 0x8998 // 152 ++#define DIRECTORY_FULL 0x8999 // 153 ++#define RENAMING_ACROSS_VOLUMES 0x899A // 154 ++#define BAD_DIRECTORY_HANDLE 0x899B // 155 ++#define INVALID_PATH 0x899C // 156 ++#define NO_MORE_TRUSTEES 0x899C // 156 ++#define NO_MORE_DIRECTORY_HANDLES 0x899D // 157 ++#define INVALID_FILENAME 0x899E // 158 ++#define DIRECTORY_ACTIVE 0x899F // 159 ++#define DIRECTORY_NOT_EMPTY 0x89A0 // 160 ++#define DIRECTORY_IO_ERROR 0x89A1 // 161 ++#define READ_FILE_WITH_RECORD_LOCKED 0x89A2 // 162 ++#define ERR_TRANSACTION_RESTARTED 0x89A3 // 163 ++#define ERR_RENAME_DIR_INVALID 0x89A4 // 164 ++#define ERR_INVALID_OPENCREATE_MODE 0x89A5 // 165 ++#define ERR_ALREADY_IN_USE 0x89A6 // 166 ++#define ERR_AUDITING_ACTIVE 0x89A6 // 166 ++#define ERR_INVALID_RESOURCE_TAG 0x89A7 // 167 ++#define ERR_ACCESS_DENIED 0x89A8 // 168 ++#define ERR_AUDITING_NO_RIGHTS 0x89A8 // 168 ++#define ERR_LINK_IN_PATH 0x89A9 // 169 ++#define INVALID_DATA_TYPE 0x89AA // 170 ++#define INVALID_DATA_STREAM 0x89BE // 190 ++#define INVALID_NAME_SPACE 0x89BF // 191 ++#define NO_ACCOUNTING_PRIVILEGES 0x89C0 // 192 ++#define LOGIN_DENIED_NO_ACCOUNT_BALANCE 0x89C1 // 193 ++#define LOGIN_DENIED_NO_CREDIT 0x89C2 // 194 ++#define ERR_AUDITING_RECORD_SIZE 0x89C2 // 194 ++#define ERR_TOO_MANY_HOLDS 0x89C3 // 195 ++#define ACCOUNTING_DISABLED 0x89C4 // 196 ++#define INTRUDER_DETECTION_LOCK 0x89C5 // 197 ++#define NO_CONSOLE_OPERATOR 0x89C6 // 198 ++#define NO_CONSOLE_PRIVILEGES 0x89C6 // 198 ++#define ERR_Q_IO_FAILURE 0x89D0 // 208 ++#define ERR_NO_QUEUE 0x89D1 // 209 ++#define ERR_NO_Q_SERVER 0x89D2 // 210 ++#define ERR_NO_Q_RIGHTS 0x89D3 // 211 ++#define ERR_Q_FULL 0x89D4 // 212 ++#define ERR_NO_Q_JOB 0x89D5 // 213 ++#define ERR_NO_Q_JOB_RIGHTS 0x89D6 // 214 ++#define ERR_Q_IN_SERVICE 0x89D7 // 215 ++#define PASSWORD_NOT_UNIQUE 0x89D7 // 215 ++#define ERR_Q_NOT_ACTIVE 0x89D8 // 216 ++#define PASSWORD_TOO_SHORT 0x89D8 // 216 ++#define ERR_Q_STN_NOT_SERVER 0x89D9 // 217 ++#define LOGIN_DENIED_NO_CONNECTION 0x89D9 // 217 ++#define ERR_MAXIMUM_LOGINS_EXCEEDED 0x89D9 // 217 ++#define ERR_Q_HALTED 0x89DA // 218 ++#define UNAUTHORIZED_LOGIN_TIME 0x89DA // 218 ++#define UNAUTHORIZED_LOGIN_STATION 0x89DB // 219 ++#define ERR_Q_MAX_SERVERS 0x89DB // 219 ++#define ACCOUNT_DISABLED 0x89DC // 220 ++#define PASSWORD_HAS_EXPIRED_NO_GRACE 0x89DE // 222 ++#define PASSWORD_HAS_EXPIRED 0x89DF // 223 ++#define E_NO_MORE_USERS 0x89E7 // 231 ++#define NOT_ITEM_PROPERTY 0x89E8 // 232 ++#define WRITE_PROPERTY_TO_GROUP 0x89E8 // 232 ++#define MEMBER_ALREADY_EXISTS 0x89E9 // 233 ++#define NO_SUCH_MEMBER 0x89EA // 234 ++#define NOT_GROUP_PROPERTY 0x89EB // 235 ++#define NO_SUCH_SEGMENT 0x89EC // 236 ++#define PROPERTY_ALREADY_EXISTS 0x89ED // 237 ++#define OBJECT_ALREADY_EXISTS 0x89EE // 238 ++#define INVALID_NAME 0x89EF // 239 ++#define WILD_CARD_NOT_ALLOWED 0x89F0 // 240 ++#define INVALID_BINDERY_SECURITY 0x89F1 // 241 ++#define NO_OBJECT_READ_PRIVILEGE 0x89F2 // 242 ++#define NO_OBJECT_RENAME_PRIVILEGE 0x89F3 // 243 ++#define NO_OBJECT_DELETE_PRIVILEGE 0x89F4 // 244 ++#define NO_OBJECT_CREATE_PRIVILEGE 0x89F5 // 245 ++#define NO_PROPERTY_DELETE_PRIVILEGE 0x89F6 // 246 ++#define NO_PROPERTY_CREATE_PRIVILEGE 0x89F7 // 247 ++#define NO_PROPERTY_WRITE_PRIVILEGE 0x89F8 // 248 ++#define NO_FREE_CONNECTION_SLOTS 0x89F9 // 249 ++#define NO_PROPERTY_READ_PRIVILEGE 0x89F9 // 249 ++#define NO_MORE_SERVER_SLOTS 0x89FA // 250 ++#define TEMP_REMAP_ERROR 0x89FA // 250 ++#define INVALID_PARAMETERS 0x89FB // 251 ++#define NO_SUCH_PROPERTY 0x89FB // 251 ++#define ERR_NCP_NOT_SUPPORTED 0x89FB // 251 ++#define INTERNET_PACKET_REQT_CANCELED 0x89FC // 252 ++#define UNKNOWN_FILE_SERVER 0x89FC // 252 ++#define MESSAGE_QUEUE_FULL 0x89FC // 252 ++#define NO_SUCH_OBJECT 0x89FC // 252 ++#define LOCK_COLLISION 0x89FD // 253 ++#define BAD_STATION_NUMBER 0x89FD // 253 ++#define INVALID_PACKET_LENGTH 0x89FD // 253 ++#define UNKNOWN_REQUEST 0x89FD // 253 ++#define BINDERY_LOCKED 0x89FE // 254 ++#define TRUSTEE_NOT_FOUND 0x89FE // 254 ++#define DIRECTORY_LOCKED 0x89FE // 254 ++#define INVALID_SEMAPHORE_NAME_LENGTH 0x89FE // 254 ++#define PACKET_NOT_DELIVERABLE 0x89FE // 254 ++#define SERVER_BINDERY_LOCKED 0x89FE // 254 ++#define SOCKET_TABLE_FULL 0x89FE // 254 ++#define SPOOL_DIRECTORY_ERROR 0x89FE // 254 ++#define SUPERVISOR_HAS_DISABLED_LOGIN 0x89FE // 254 ++#define TIMEOUT_FAILURE 0x89FE // 254 ++#define BAD_PRINTER_ERROR 0x89FF // 255 ++#define BAD_RECORD_OFFSET 0x89FF // 255 ++#define CLOSE_FCB_ERROR 0x89FF // 255 ++#define FILE_EXTENSION_ERROR 0x89FF // 255 ++#define FILE_NAME_ERROR 0x89FF // 255 ++#define HARDWARE_FAILURE 0x89FF // 255 ++#define INVALID_DRIVE_NUMBER 0x89FF // 255 ++#define DOS_INVALID_DRIVE 0x000F // 255 ++#define INVALID_INITIAL_SEMAPHORE_VALUE 0x89FF // 255 ++#define INVALID_SEMAPHORE_HANDLE 0x89FF // 255 ++#define IO_BOUND_ERROR 0x89FF // 255 ++#define NO_FILES_FOUND_ERROR 0x89FF // 255 ++#define NO_RESPONSE_FROM_SERVER 0x89FF // 255 ++#define NO_SUCH_OBJECT_OR_BAD_PASSWORD 0x89FF // 255 ++#define PATH_NOT_LOCATABLE 0x89FF // 255 ++#define QUEUE_FULL_ERROR 0x89FF // 255 ++#define REQUEST_NOT_OUTSTANDING 0x89FF // 255 ++#ifndef SOCKET_ALREADY_OPEN ++#define SOCKET_ALREADY_OPEN 0x89FF // 255 ++#endif ++#define LOCK_ERROR 0x89FF // 255 ++#ifndef FAILURE ++#define FAILURE 0x89FF // 255 Generic Failure ++#endif ++ ++#if 0 ++#define NOT_SAME_LOCAL_DRIVE 0x89F6 ++#define TARGET_DRIVE_NOT_LOCAL 0x89F7 ++#define ALREADY_ATTACHED_TO_SERVER 0x89F8 // 248 ++#define NOT_ATTACHED_TO_SERVER 0x89F8 ++#endif ++ ++/* ++ * Network errors ++ * Decimal values at end of line are 32768 lower than actual ++ */ ++#define NWE_ALREADY_ATTACHED 0x8800 // 0 - Attach attempted to server with valid, existing connection ++#define NWE_CONN_INVALID 0x8801 // 1 - Request attempted with invalid or non-attached connection handle ++#define NWE_DRIVE_IN_USE 0x8802 // 2 - OS/2 only (NOT USED) ++#define NWE_DRIVE_CANNOT_MAP 0x8803 // 3 - Map drive attempted but unable to add new current directory structure ++#define NWE_DRIVE_BAD_PATH 0x8804 // 4 - Map drive attempted with invalid path specification ++#define NWE_NET_RECEIVE 0x8805 // 5 - Attempt to receive from the selected transport failed ++#define NWE_NET_UNKNOWN 0x8806 // 6 - Network send attempted with an un-specific network error ++#define NWE_SERVER_BAD_SLOT 0x8807 // 7 - Server request attempted with invalid server connection slot ++#define NWE_SERVER_NO_SLOTS 0x8808 // 8 - Attach attempted to server with no connection slots available ++#define NWE_NET_SEND 0x8809 // 9 - Attempt to send on the selected transport failed ++#define NWE_SERVER_NO_ROUTE 0x880A // 10 - Attempted to find route to server where no route exists ++#define NWE_BAD_LOCAL_TARGET 0x880B // 11 - OS/2 only ++#define NWE_REQ_TOO_MANY_REQ_FRAGS 0x880C // 12 - Attempted request with too many request fragments specified ++#define NWE_CONN_LIST_OVERFLOW 0x880D // 13 ++#define NWE_BUFFER_OVERFLOW 0x880E // 14 - Attempt to receive more data than the reply buffer had room for ++#define NWE_SERVER_NO_CONN 0x880F // 15 - Attempt to get connection for a server not connected ++#define NWE_NO_ROUTER_FOUND 0x8810 // 16 - OS/2 only ++#define NWE_FUNCTION_INVALID 0x8811 // 17 - Attempted function call to non- existent or illegal function ++#define NWE_SCAN_COMPLETE 0x8812 ++#define NWE_UNSUPPORTED_NAME_FORMAT_TYP 0x8813 ++#define NWE_HANDLE_ALREADY_LICENSED 0x8814 ++#define NWE_HANDLE_ALREADY_UNLICENSED 0x8815 ++#define NWE_INVALID_NCP_PACKET_LENGTH 0x8816 ++#define NWE_SETTING_UP_TIMEOUT 0x8817 ++#define NWE_SETTING_SIGNALS 0x8818 ++#define NWE_SERVER_CONNECTION_LOST 0x8819 ++#define NWE_OUT_OF_HEAP_SPACE 0x881A ++#define NWE_INVALID_SERVICE_REQUEST 0x881B ++#define NWE_INVALID_TASK_NUMBER 0x881C ++#define NWE_INVALID_MESSAGE_LENGTH 0x881D ++#define NWE_EA_SCAN_DONE 0x881E ++#define NWE_BAD_CONNECTION_NUMBER 0x881F ++#define NWE_MULT_TREES_NOT_SUPPORTED 0x8820 // 32 - Attempt to open a connection to a DS tree other than the default tree ++#define NWE_CONN_NOT_SAME 0x8830 // 48 - Internal server request attempted across different server connections ++#define NWE_CONN_PRIMARY_NOT_SET 0x8831 // 49 - Attempt to retrieve default connection with no primary connection set ++#define NWE_PRN_CAPTURE_NOT_IN_PROGRESS 0x8832 // 50 - Capture information requested on port with no capture in progress ++#define NWE_BUFFER_INVALID_LEN 0x8833 // 51 - Used to indicate length which caller requested on a GetDNC or SetDNC was too large ++#define NWE_USER_NO_NAME 0x8834 // 52 ++#define NWE_PRN_NO_LOCAL_SPOOLER 0x8835 // 53 - Capture requested without having the local print spooler installed ++#define NWE_PARAM_INVALID 0x8836 // 54 - Attempted function with an invalid function parameter specified ++#define NWE_CFG_OPEN_FAILED 0x8837 // 55 - OS/2 only ++#define NWE_CFG_NO_FILE 0x8838 // 56 - OS/2 only ++#define NWE_CFG_READ_FAILED 0x8839 // 57 - OS/2 only ++#define NWE_CFG_LINE_TOO_LONG 0x883A // 58 - OS/2 only ++#define NWE_CFG_LINES_IGNORED 0x883B // 59 - OS/2 only ++#define NWE_RESOURCE_NOT_OWNED 0x883C // 60 - Attempted request made with a parameter using foriegn resource ++#define NWE_DAEMON_INSTALLED 0x883D // 61 - OS/2 only ++#define NWE_PRN_SPOOLER_INSTALLED 0x883E // 62 - Attempted load of print spooler with print spooler already installed ++#define NWE_CONN_TABLE_FULL 0x883F // 63 - Attempted to allocate a connection handle with no more local connection table entries ++#define NWE_CFG_SECTION_NOT_FOUND 0x8840 // 64 - OS/2 only ++#define NWE_TRAN_INVALID_TYPE 0x8841 // 65 - Attempted function on a connection with an invalid transport selected ++#define NWE_TDS_TAG_IN_USE 0x8842 // 66 - OS/2 only ++#define NWE_TDS_OUT_OF_MEMORY 0x8843 // 67 - OS/2 only ++#define NWE_TDS_INVALID_TAG 0x8844 // 68 - Attempted TDS function with invalid tag ++#define NWE_TDS_WRITE_TRUNCATED 0x8845 // 69 - Attempted TDS write with buffer that exceeded buffer ++#define NWE_DS_NO_CONN 0x8846 // 70 ++#define NWE_SERVICE_BUSY 0x8846 // 70 - Attempted request made to partially asynchronous function in busy state ++#define NWE_SERVER_NOT_FOUND 0x8847 // 71 - Attempted connect failed to find any servers responding ++#define NWE_VLM_INVALID 0x8848 // 72 - Attempted function call to non-existant or not-loaded overlay ++#define NWE_DRIVE_ALREADY_MAPPED 0x8849 // 73 - Attempted map to network drive that was already mapped ++#define NWE_DRIVE_LOCAL_IN_USE 0x884A // 74 - Attempted map to local drive that was in use ++#define NWE_DRIVE_NONE_AVAILABLE 0x884B // 75 - Attempted map to next available drive when none were available ++#define NWE_DEVICE_NOT_REDIRECTED 0x884C // 76 - The device is not redirected ++#define NWE_FILE_MAX_REACHED 0x884D // 77 - Maximum number of files was reached ++#define NWE_UNLOAD_FAILED 0x884E // 78 - Attempted unload failed ++#define NWE_CONN_IN_USE 0x884F // 79 - Attempted re-use of already in use connection entry ++#define NWE_REQ_TOO_MANY_REP_FRAGS 0x8850 // 80 - Attempted request with too many reply fragments specified ++#define NWE_NAME_TABLE_FULL 0x8851 // 81 - Attempted to add a name into the name table after it was full ++#define NWE_SOCKET_NOT_OPEN 0x8852 // 82 - Listen was posted on unopened socket ++#define NWE_MEMORY_MGR_ERROR 0x8853 // 83 - Attempted enhanced memory operation failed ++#define NWE_SFT3_ERROR 0x8854 // 84 - An SFT3 switch occured mid-transfer ++#define NWE_DS_PREFERRED_NOT_FOUND 0x8855 // 85 - the preferred directory server was not established but another directory server was returned ++#define NWE_DEVICE_NOT_RECOGNIZED 0x8856 // 86 - used to determine if the device is not used by VISE so pass it on to the next redirector, if any. ++#define NWE_NET_INVALID_TYPE 0x8857 // 87 - the network type (Bind/NDS) does not match the server version ++#define NWE_FILE_OPEN_FAILED 0x8858 // 88 - generic open failure error, invalid path, access denied, etc.. ++#define NWE_DS_PREFERRED_NOT_SPECIFIED 0x8859 // 89 - no preferred name specified ++#define NWE_SOCKET_OPEN_FAILED 0x885A // 90 - error opening a socket ++#define NWE_SIGNATURE_LEVEL_CONFLICT 0x8861 ++#define NWE_NO_LOCK_FOUND 0x8862 // OS/2 - process lock on conn handle failed, process ID not recognized ++#define NWE_LOCK_TABLE_FULL 0x8863 // OS/2 - process lock on conn handle failed, process lock table full ++#define NWE_INVALID_MATCH_DATA 0x8864 ++#define NWE_MATCH_FAILED 0x8865 ++#define NWE_NO_MORE_ENTRIES 0x8866 ++#define NWE_INSUFFICIENT_RESOURCES 0x8867 ++#define NWE_STRING_TRANSLATION 0x8868 ++#define NWE_ACCESS_VIOLATION 0x8869 ++#define NWE_NOT_AUTHENTICATED 0x886A ++#define NWE_INVALID_LEVEL 0x886B ++#define NWE_RESOURCE_LOCK 0x886C ++#define NWE_INVALID_NAME_FORMAT 0x886D ++#define NWE_OBJECT_EXISTS 0x886E ++#define NWE_OBJECT_NOT_FOUND 0x886F ++#define NWE_UNSUPPORTED_TRAN_TYPE 0x8870 ++#define NWE_INVALID_STRING_TYPE 0x8871 ++#define NWE_INVALID_OWNER 0x8872 ++#define NWE_UNSUPPORTED_AUTHENTICATOR 0x8873 ++#define NWE_IO_PENDING 0x8874 ++#define NWE_INVALID_DRIVE_NUMBER 0x8875 ++#define NWE_REPLY_TRUNCATED 0x88e6 // 230 NLM ++#define NWE_REQUESTER_FAILURE 0x88FF ++ ++/* ++ * Server Errors ++ */ ++#define NWE_INSUFFICIENT_SPACE 0x8901 // 001 ++#define NWE_INVALID_CONNECTION 0x890a // 010 - nlm invalid connection ++#define NWE_TIMEOUT 0x8910 // 016 - nlm connection timeout ++#define NWE_NO_MORE_ENTRY 0x8914 // 020 ++#define NWE_BUFFER_TOO_SMALL 0x8977 // 119 ++#define NWE_VOL_FLAG_NOT_SET 0x8978 // 120 the service requested, not avail. on the selected vol. ++#define NWE_NO_ITEMS_FOUND 0x8979 // 121 ++#define NWE_CONN_ALREADY_TEMP 0x897a // 122 ++#define NWE_CONN_ALREADY_LOGGED_IN 0x897b // 123 ++#define NWE_CONN_NOT_AUTHENTICATED 0x897c // 124 ++#define NWE_CONN_NOT_LOGGED_IN 0x897d // 125 ++#define NWE_NCP_BOUNDARY_CHECK_FAILED 0x897e // 126 ++#define NWE_LOCK_WAITING 0x897f // 127 ++#define NWE_LOCK_FAIL 0x8980 // 128 ++#define NWE_FILE_IN_USE 0x8980 // 128 ++#define NWE_FILE_NO_HANDLES 0x8981 // 129 ++#define NWE_FILE_NO_OPEN_PRIV 0x8982 // 130 ++#define NWE_DISK_IO_ERROR 0x8983 // 131 ++#define NWE_AUDITING_HARD_IO_ERROR 0x8983 // 131 ++#define NWE_FILE_NO_CREATE_PRIV 0x8984 // 132 ++#define NWE_AUDITING_NOT_SUPV 0x8984 // 132 ++#define NWE_FILE_NO_CREATE_DEL_PRIV 0x8985 // 133 ++#define NWE_FILE_EXISTS_READ_ONLY 0x8986 // 134 ++#define NWE_FILE_WILD_CARDS_IN_NAME 0x8987 // 135 ++#define NWE_FILE_INVALID_HANDLE 0x8988 // 136 ++#define NWE_FILE_NO_SRCH_PRIV 0x8989 // 137 ++#define NWE_FILE_NO_DEL_PRIV 0x898A // 138 ++#define NWE_FILE_NO_RENAME_PRIV 0x898B // 139 ++#define NWE_FILE_NO_MOD_PRIV 0x898C // 140 ++#define NWE_FILE_SOME_IN_USE 0x898D // 141 ++#define NWE_FILE_NONE_IN_USE 0x898E // 142 ++#define NWE_FILE_SOME_READ_ONLY 0x898F // 143 ++#define NWE_FILE_NONE_READ_ONLY 0x8990 // 144 ++#define NWE_FILE_SOME_RENAMED_EXIST 0x8991 // 145 ++#define NWE_FILE_NONE_RENAMED_EXIST 0x8992 // 146 ++#define NWE_FILE_NO_READ_PRIV 0x8993 // 147 ++#define NWE_FILE_NO_WRITE_PRIV 0x8994 // 148 ++#define NWE_FILE_READ_ONLY 0x8994 // 148 ++#define NWE_FILE_DETACHED 0x8995 // 149 ++#define NWE_SERVER_OUT_OF_MEMORY 0x8996 // 150 ++#define NWE_DIR_TARGET_INVALID 0x8996 // 150 ++#define NWE_DISK_NO_SPOOL_SPACE 0x8997 // 151 ++#define NWE_AUDITING_NOT_ENABLED 0x8997 // 151 ++#define NWE_VOL_INVALID 0x8998 // 152 ++#define NWE_DIR_FULL 0x8999 // 153 ++#define NWE_VOL_RENAMING_ACROSS 0x899A // 154 ++#define NWE_DIRHANDLE_INVALID 0x899B // 155 ++#define NWE_PATH_INVALID 0x899C // 156 ++#define NWE_TRUSTEES_NO_MORE 0x899C // 156 ++#define NWE_DIRHANDLE_NO_MORE 0x899D // 157 ++#define NWE_FILE_NAME_INVALID 0x899E // 158 ++#define NWE_DIR_ACTIVE 0x899F // 159 ++#define NWE_DIR_NOT_EMPTY 0x89A0 // 160 ++#define NWE_DIR_IO_ERROR 0x89A1 // 161 ++#define NWE_FILE_IO_LOCKED 0x89A2 // 162 ++#define NWE_TTS_RANSACTION_RESTARTED 0x89A3 // 163 ++#define NWE_TTS_TRANSACTION_RESTARTED 0x89A3 // 163 ++#define NWE_DIR_RENAME_INVALID 0x89A4 // 164 ++#define NWE_FILE_OPENCREAT_MODE_INVALID 0x89A5 // 165 ++#define NWE_ALREADY_IN_USE 0x89A6 // 166 ++#define NWE_AUDITING_ACTIVE 0x89A6 // 166 ++#define NWE_RESOURCE_TAG_INVALID 0x89A7 // 167 ++#define NWE_ACCESS_DENIED 0x89A8 // 168 ++#define NWE_AUDITING_NO_RIGHTS 0x89A8 // 168 ++#define NWE_LINK_IN_PATH 0x89A9 // 169 ++#define NWE_INVALID_DATA_TYPE_FLAG 0x89AA // 170 (legacy vol with UTF8) ++#define NWE_DATA_STREAM_INVALID 0x89BE // 190 ++#define NWE_NAME_SPACE_INVALID 0x89BF // 191 ++#define NWE_ACCTING_NO_PRIV 0x89C0 // 192 ++#define NWE_ACCTING_NO_BALANCE 0x89C1 // 193 ++#define NWE_ACCTING_NO_CREDIT 0x89C2 // 194 ++#define NWE_AUDITING_RECORD_SIZE 0x89C2 // 194 ++#define NWE_ACCTING_TOO_MANY_HOLDS 0x89C3 // 195 ++#define NWE_ACCTING_DISABLED 0x89C4 // 196 ++#define NWE_LOGIN_LOCKOUT 0x89C5 // 197 ++#define NWE_CONSOLE_NO_PRIV 0x89C6 // 198 ++#define NWE_Q_IO_FAILURE 0x89D0 // 208 ++#define NWE_Q_NONE 0x89D1 // 209 ++#define NWE_Q_NO_SERVER 0x89D2 // 210 ++#define NWE_Q_NO_RIGHTS 0x89D3 // 211 ++#define NWE_Q_FULL 0x89D4 // 212 ++#define NWE_Q_NO_JOB 0x89D5 // 213 ++#define NWE_Q_NO_JOB_RIGHTS 0x89D6 // 214 ++#define NWE_PASSWORD_UNENCRYPTED 0x89D6 // 214 ++#define NWE_Q_IN_SERVICE 0x89D7 // 215 ++#define NWE_PASSWORD_NOT_UNIQUE 0x89D7 // 215 ++#define NWE_Q_NOT_ACTIVE 0x89D8 // 216 ++#define NWE_PASSWORD_TOO_SHORT 0x89D8 // 216 ++#define NWE_Q_STN_NOT_SERVER 0x89D9 // 217 ++#define NWE_LOGIN_NO_CONN 0x89D9 // 217 ++#define NWE_LOGIN_MAX_EXCEEDED 0x89D9 // 217 ++#define NWE_Q_HALTED 0x89DA // 218 ++#define NWE_LOGIN_UNAUTHORIZED_TIME 0x89DA // 218 ++#define NWE_LOGIN_UNAUTHORIZED_STATION 0x89DB // 219 ++#define NWE_Q_MAX_SERVERS 0x89DB // 219 ++#define NWE_ACCT_DISABLED 0x89DC // 220 ++#define NWE_PASSWORD_INVALID 0x89DE // 222 ++#define NWE_PASSWORD_EXPIRED 0x89DF // 223 ++#define NWE_LOGIN_NO_CONN_AVAIL 0x89E0 // 224 ++#define NWE_E_NO_MORE_USERS 0x89E7 // 231 ++#define NWE_BIND_NOT_ITEM_PROP 0x89E8 // 232 ++#define NWE_BIND_WRITE_TO_GROUP_PROP 0x89E8 // 232 ++#define NWE_BIND_MEMBER_ALREADY_EXISTS 0x89E9 // 233 ++#define NWE_BIND_NO_SUCH_MEMBER 0x89EA // 234 ++#define NWE_BIND_NOT_GROUP_PROP 0x89EB // 235 ++#define NWE_BIND_NO_SUCH_SEGMENT 0x89EC // 236 ++#define NWE_BIND_PROP_ALREADY_EXISTS 0x89ED // 237 ++#define NWE_BIND_OBJ_ALREADY_EXISTS 0x89EE // 238 ++#define NWE_BIND_NAME_INVALID 0x89EF // 239 ++#define NWE_BIND_WILDCARD_INVALID 0x89F0 // 240 ++#define NWE_BIND_SECURITY_INVALID 0x89F1 // 241 ++#define NWE_BIND_OBJ_NO_READ_PRIV 0x89F2 // 242 ++#define NWE_BIND_OBJ_NO_RENAME_PRIV 0x89F3 // 243 ++#define NWE_BIND_OBJ_NO_DELETE_PRIV 0x89F4 // 244 ++#define NWE_BIND_OBJ_NO_CREATE_PRIV 0x89F5 // 245 ++#define NWE_BIND_PROP_NO_DELETE_PRIV 0x89F6 // 246 ++#define NWE_BIND_PROP_NO_CREATE_PRIV 0x89F7 // 247 ++#define NWE_BIND_PROP_NO_WRITE_PRIV 0x89F8 // 248 ++#define NWE_BIND_PROP_NO_READ_PRIV 0x89F9 // 249 ++#define NWE_NO_FREE_CONN_SLOTS 0x89F9 // 249 ++#define NWE_NO_MORE_SERVER_SLOTS 0x89FA // 250 ++#define NWE_TEMP_REMAP_ERROR 0x89FA // 250 ++#define NWE_PARAMETERS_INVALID 0x89FB // 251 ++#define NWE_BIND_NO_SUCH_PROP 0x89FB // 251 ++#define NWE_NCP_NOT_SUPPORTED 0x89FB // 251 ++#define NWE_INET_PACKET_REQ_CANCELED 0x89FC // 252 ++#define NWE_SERVER_UNKNOWN 0x89FC // 252 ++#define NWE_MSG_Q_FULL 0x89FC // 252 ++#define NWE_BIND_NO_SUCH_OBJ 0x89FC // 252 ++#define NWE_LOCK_COLLISION 0x89FD // 253 ++#define NWE_CONN_NUM_INVALID 0x89FD // 253 ++#define NWE_PACKET_LEN_INVALID 0x89FD // 253 ++#define NWE_UNKNOWN_REQ 0x89FD // 253 ++#define NWE_BIND_LOCKED 0x89FE // 254 ++#define NWE_TRUSTEE_NOT_FOUND 0x89FE // 254 ++#define NWE_DIR_LOCKED 0x89FE // 254 ++#define NWE_SEM_INVALID_NAME_LEN 0x89FE // 254 ++#define NWE_PACKET_NOT_DELIVERABLE 0x89FE // 254 ++#define NWE_SOCKET_TABLE_FULL 0x89FE // 254 ++#define NWE_SPOOL_DIR_ERROR 0x89FE // 254 ++#define NWE_LOGIN_DISABLED_BY_SUPER 0x89FE // 254 ++#define NWE_TIMEOUT_FAILURE 0x89FE // 254 ++#define NWE_FILE_EXT 0x89FF // 255 ++#define NWE_FILE_NAME 0x89FF // 255 ++#define NWE_HARD_FAILURE 0x89FF // 255 ++#define NWE_FCB_CLOSE 0x89FF // 255 ++#define NWE_IO_BOUND 0x89FF // 255 ++#define NWE_BAD_SPOOL_PRINTER 0x89FF // 255 ++#define NWE_BAD_RECORD_OFFSET 0x89FF // 255 ++#define NWE_DRIVE_INVALID_NUM 0x89FF // 255 ++#define NWE_SEM_INVALID_INIT_VAL 0x89FF // 255 ++#define NWE_SEM_INVALID_HANDLE 0x89FF // 255 ++#define NWE_NO_FILES_FOUND_ERROR 0x89FF // 255 ++#define NWE_NO_RESPONSE_FROM_SERVER 0x89FF // 255 ++#define NWE_NO_OBJ_OR_BAD_PASSWORD 0x89FF // 255 ++#define NWE_PATH_NOT_LOCATABLE 0x89FF // 255 ++#define NWE_Q_FULL_ERROR 0x89FF // 255 ++#define NWE_REQ_NOT_OUTSTANDING 0x89FF // 255 ++#define NWE_SOCKET_ALREADY_OPEN 0x89FF // 255 ++#define NWE_LOCK_ERROR 0x89FF // 255 ++#define NWE_FAILURE 0x89FF // 255 Generic Failure ++ ++#endif /* __NOVFS_ERROR_H */ +--- /dev/null ++++ b/fs/novfs/proc.c +@@ -0,0 +1,152 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * This module contains functions that create the interface to the proc ++ * filesystem. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "vfs.h" ++ ++struct proc_dir_entry *Novfs_Procfs_dir; ++static struct proc_dir_entry *Novfs_Control; ++static struct proc_dir_entry *Novfs_Library; ++static struct proc_dir_entry *Novfs_Version; ++ ++static struct file_operations Daemon_proc_fops; ++static struct file_operations Library_proc_fops; ++ ++/*===[ Code ]=============================================================*/ ++ ++static int Novfs_Get_Version(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ char *buf, tbuf[48]; ++ int len = 0, i; ++ ++ if (!off) { ++ buf = page + off; ++ *start = buf; ++ len = sprintf(buf, "Novfs Version=%s\n", NOVFS_VERSION_STRING); ++ i = Daemon_getversion(tbuf, sizeof(tbuf)); ++ if ((i > 0) && i < (count - len)) { ++ len += sprintf(buf + len, "Novfsd Version=%s\n", tbuf); ++ } ++ ++ if (Novfs_CurrentMount) { ++ i = strlen(Novfs_CurrentMount); ++ if ((i > 0) && i < (count - len)) { ++ len += ++ sprintf(buf + len, "Novfs mount=%s\n", ++ Novfs_CurrentMount); ++ } ++ } ++ DbgPrint("Novfs_Get_Version:\n%s\n", buf); ++ } ++ *eof = 1; ++ return (len); ++} ++ ++int Init_Procfs_Interface(void) ++{ ++ int retCode = 0; ++ ++ Novfs_Procfs_dir = proc_mkdir(MODULE_NAME, NULL); ++ if (Novfs_Procfs_dir) { ++ Novfs_Procfs_dir->owner = THIS_MODULE; ++ ++ Novfs_Control = create_proc_entry("Control", 0600, Novfs_Procfs_dir); ++ ++ if (Novfs_Control) { ++ Novfs_Control->owner = THIS_MODULE; ++ Novfs_Control->size = 0; ++ memcpy(&Daemon_proc_fops, Novfs_Control->proc_fops, ++ sizeof(struct file_operations)); ++ ++ /* ++ * Setup our functions ++ */ ++ Daemon_proc_fops.owner = THIS_MODULE; ++ Daemon_proc_fops.open = Daemon_Open_Control; ++ Daemon_proc_fops.release = Daemon_Close_Control; ++ Daemon_proc_fops.read = Daemon_Send_Command; ++ Daemon_proc_fops.write = Daemon_Receive_Reply; ++ Daemon_proc_fops.ioctl = Daemon_ioctl; ++ ++ Novfs_Control->proc_fops = &Daemon_proc_fops; ++ } else { ++ remove_proc_entry(MODULE_NAME, NULL); ++ return (-ENOENT); ++ } ++ ++ Novfs_Library = create_proc_entry("Library", 0666, Novfs_Procfs_dir); ++ if (Novfs_Library) { ++ Novfs_Library->owner = THIS_MODULE; ++ Novfs_Library->size = 0; ++ ++ /* ++ * Setup our file functions ++ */ ++ memcpy(&Library_proc_fops, Novfs_Library->proc_fops, ++ sizeof(struct file_operations)); ++ Library_proc_fops.owner = THIS_MODULE; ++ Library_proc_fops.open = Daemon_Library_open; ++ Library_proc_fops.release = Daemon_Library_close; ++ Library_proc_fops.read = Daemon_Library_read; ++ Library_proc_fops.write = Daemon_Library_write; ++ Library_proc_fops.llseek = Daemon_Library_llseek; ++ Library_proc_fops.ioctl = Daemon_Library_ioctl; ++ Novfs_Library->proc_fops = &Library_proc_fops; ++ } else { ++ remove_proc_entry("Control", Novfs_Procfs_dir); ++ remove_proc_entry(MODULE_NAME, NULL); ++ return (-ENOENT); ++ } ++ ++ Novfs_Version = ++ create_proc_read_entry("Version", 0444, Novfs_Procfs_dir, ++ Novfs_Get_Version, NULL); ++ if (Novfs_Version) { ++ Novfs_Version->owner = THIS_MODULE; ++ Novfs_Version->size = 0; ++ } else { ++ remove_proc_entry("Library", Novfs_Procfs_dir); ++ remove_proc_entry("Control", Novfs_Procfs_dir); ++ remove_proc_entry(MODULE_NAME, NULL); ++ retCode = -ENOENT; ++ } ++ } else { ++ retCode = -ENOENT; ++ } ++ return (retCode); ++} ++ ++void Uninit_Procfs_Interface(void) ++{ ++ ++ DbgPrint("Uninit_Procfs_Interface remove_proc_entry(Version, NULL)\n"); ++ remove_proc_entry("Version", Novfs_Procfs_dir); ++ ++ DbgPrint("Uninit_Procfs_Interface remove_proc_entry(Control, NULL)\n"); ++ remove_proc_entry("Control", Novfs_Procfs_dir); ++ ++ DbgPrint("Uninit_Procfs_Interface remove_proc_entry(Library, NULL)\n"); ++ remove_proc_entry("Library", Novfs_Procfs_dir); ++ ++ DbgPrint("Uninit_Procfs_Interface remove_proc_entry(%s, NULL)\n", ++ MODULE_NAME); ++ remove_proc_entry(MODULE_NAME, NULL); ++ ++ DbgPrint("Uninit_Procfs_Interface done\n"); ++} +--- /dev/null ++++ b/fs/novfs/profile.c +@@ -0,0 +1,687 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * This file contains a debugging code for the novfs VFS. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vfs.h" ++ ++/*===[ Manifest constants ]===============================================*/ ++#define DBGBUFFERSIZE (1024*1024*32) ++ ++/*===[ Type definitions ]=================================================*/ ++struct local_rtc_time { ++ int tm_sec; ++ int tm_min; ++ int tm_hour; ++ int tm_mday; ++ int tm_mon; ++ int tm_year; ++ int tm_wday; ++ int tm_yday; ++ int tm_isdst; ++}; ++ ++static char *DbgPrintBuffer = NULL; ++static char DbgPrintOn = 0; ++static char DbgSyslogOn = 0; ++static char DbgProfileOn = 0; ++ ++static unsigned long DbgPrintBufferOffset = 0; ++static unsigned long DbgPrintBufferReadOffset = 0; ++static unsigned long DbgPrintBufferSize = DBGBUFFERSIZE; ++ ++static struct file_operations Dbg_proc_file_operations; ++static struct file_operations dentry_proc_file_ops; ++static struct file_operations inode_proc_file_ops; ++ ++static struct proc_dir_entry *dbg_dir = NULL; ++static struct proc_dir_entry *dbg_file = NULL; ++static struct proc_dir_entry *dentry_file = NULL; ++static struct proc_dir_entry *inode_file = NULL; ++ ++static DECLARE_MUTEX(LocalPrint_lock); ++ ++static ssize_t User_proc_write_DbgBuffer(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos) ++{ ++ ssize_t retval = nbytes; ++ unsigned char *lbuf; ++ unsigned char *p; ++ int i; ++ ++ lbuf = kmalloc(nbytes + 1, GFP_KERNEL); ++ if (lbuf) { ++ if (copy_from_user(lbuf, buf, nbytes)) ++ return -EFAULT; ++ ++ lbuf[nbytes] = 0; ++ DbgPrint("User_proc_write_DbgBuffer: %s\n", lbuf); ++ ++ for (i = 0; lbuf[i] && lbuf[i] != '\n'; i++) ++ ; ++ ++ if ('\n' == lbuf[i]) ++ lbuf[i] = '\0'; ++ ++ if (!strcmp("on", lbuf)) { ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ DbgPrintOn = 1; ++ } else if (!strcmp("off", lbuf)) { ++ DbgPrintOn = 0; ++ } else if (!strcmp("reset", lbuf)) { ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ } else if (NULL != (p = strchr(lbuf, ' '))) { ++ *p++ = '\0'; ++ if (!strcmp("syslog", lbuf)) { ++ ++ if (!strcmp("on", p)) { ++ DbgSyslogOn = 1; ++ } else if (!strcmp("off", p)) { ++ DbgSyslogOn = 0; ++ } ++ } else if (!strcmp("novfsd", lbuf)) { ++ Daemon_SendDebugCmd(p); ++ } else if (!strcmp("file_update_timeout", lbuf)) { ++ File_update_timeout = ++ simple_strtoul(p, NULL, 0); ++ } else if (!strcmp("cache", lbuf)) { ++ if (!strcmp("on", p)) { ++ PageCache = 1; ++ } else if (!strcmp("off", p)) { ++ PageCache = 0; ++ } ++ } else if (!strcmp("profile", lbuf)) { ++ if (!strcmp("on", p)) { ++ DbgProfileOn = 1; ++ } else if (!strcmp("off", p)) { ++ DbgProfileOn = 0; ++ } ++ } ++ } ++ kfree(lbuf); ++ } ++ ++ return (retval); ++} ++ ++static ssize_t User_proc_read_DbgBuffer(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) ++{ ++ ssize_t retval = 0; ++ size_t count; ++ ++ if (0 != (count = DbgPrintBufferOffset - DbgPrintBufferReadOffset)) { ++ ++ if (count > nbytes) { ++ count = nbytes; ++ } ++ ++ count -= ++ copy_to_user(buf, &DbgPrintBuffer[DbgPrintBufferReadOffset], ++ count); ++ ++ if (count == 0) { ++ if (retval == 0) ++ retval = -EFAULT; ++ } else { ++ DbgPrintBufferReadOffset += count; ++ if (DbgPrintBufferReadOffset >= DbgPrintBufferOffset) { ++ DbgPrintBufferOffset = ++ DbgPrintBufferReadOffset = 0; ++ } ++ retval = count; ++ } ++ } ++ ++ return retval; ++} ++ ++static int proc_read_DbgBuffer(char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ int len; ++ ++ printk(KERN_ALERT "proc_read_DbgBuffer: off=%ld count=%d DbgPrintBufferOffset=%lu DbgPrintBufferReadOffset=%lu\n", off, count, DbgPrintBufferOffset, DbgPrintBufferReadOffset); ++ ++ len = DbgPrintBufferOffset - DbgPrintBufferReadOffset; ++ ++ if ((int)(DbgPrintBufferOffset - DbgPrintBufferReadOffset) > count) ++ len = count; ++ ++ if (len) { ++ memcpy(page, &DbgPrintBuffer[DbgPrintBufferReadOffset], len); ++ DbgPrintBufferReadOffset += len; ++ } ++ ++ if (DbgPrintBufferReadOffset >= DbgPrintBufferOffset) ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ ++ printk(KERN_ALERT "proc_read_DbgBuffer: return %d\n", len); ++ ++ return len; ++} ++ ++#define DBG_BUFFER_SIZE (2*1024) ++ ++static int LocalPrint(char *Fmt, ...) ++{ ++ int len = 0; ++ va_list args; ++ ++ if (DbgPrintBuffer) { ++ va_start(args, Fmt); ++ len += vsnprintf(DbgPrintBuffer + DbgPrintBufferOffset, ++ DbgPrintBufferSize - DbgPrintBufferOffset, ++ Fmt, args); ++ DbgPrintBufferOffset += len; ++ } ++ ++ return (len); ++} ++ ++int DbgPrint(char *Fmt, ...) ++{ ++ char *buf; ++ int len = 0; ++ unsigned long offset; ++ va_list args; ++ ++ if ((DbgPrintBuffer && DbgPrintOn) || DbgSyslogOn) { ++ buf = kmalloc(DBG_BUFFER_SIZE, GFP_KERNEL); ++ ++ if (buf) { ++ va_start(args, Fmt); ++ len = sprintf(buf, "[%d] ", current->pid); ++ ++ len += ++ vsnprintf(buf + len, DBG_BUFFER_SIZE - len, Fmt, ++ args); ++ if (-1 == len) { ++ len = DBG_BUFFER_SIZE - 1; ++ buf[len] = '\0'; ++ } ++ /* ++ len = sprintf(&DbgPrintBuffer[offset], "[%llu] ", ts); ++ len += vsprintf(&DbgPrintBuffer[offset+len], Fmt, args); ++ */ ++ ++ if (len) { ++ if (DbgSyslogOn) { ++ printk("<6>%s", buf); ++ } ++ ++ if (DbgPrintBuffer && DbgPrintOn) { ++ if ((DbgPrintBufferOffset + len) > ++ DbgPrintBufferSize) { ++ offset = DbgPrintBufferOffset; ++ DbgPrintBufferOffset = 0; ++ memset(&DbgPrintBuffer[offset], ++ 0, ++ DbgPrintBufferSize - ++ offset); ++ } ++ ++ mb(); ++ ++ if ((DbgPrintBufferOffset + len) < ++ DbgPrintBufferSize) { ++ DbgPrintBufferOffset += len; ++ offset = ++ DbgPrintBufferOffset - len; ++ memcpy(&DbgPrintBuffer[offset], ++ buf, len + 1); ++ } ++ } ++ } ++ kfree(buf); ++ } ++ } ++ ++ return (len); ++} ++ ++static void doline(unsigned char *b, unsigned char *e, unsigned char *l) ++{ ++ unsigned char c; ++ ++ *b++ = ' '; ++ ++ while (l < e) { ++ c = *l++; ++ if ((c < ' ') || (c > '~')) { ++ c = '.'; ++ } ++ *b++ = c; ++ *b = '\0'; ++ } ++} ++ ++void mydump(int size, void *dumpptr) ++{ ++ unsigned char *ptr = (unsigned char *)dumpptr; ++ unsigned char *line = NULL, buf[100], *bptr = buf; ++ int i; ++ ++ if (DbgPrintBuffer || DbgSyslogOn) { ++ if (size) { ++ for (i = 0; i < size; i++) { ++ if (0 == (i % 16)) { ++ if (line) { ++ doline(bptr, ptr, line); ++ DbgPrint("%s\n", buf); ++ bptr = buf; ++ } ++ bptr += sprintf(bptr, "0x%p: ", ptr); ++ line = ptr; ++ } ++ bptr += sprintf(bptr, "%02x ", *ptr++); ++ } ++ doline(bptr, ptr, line); ++ DbgPrint("%s\n", buf); ++ } ++ } ++} ++ ++#define FEBRUARY 2 ++#define STARTOFTIME 1970 ++#define SECDAY 86400L ++#define SECYR (SECDAY * 365) ++#define leapyear(year) ((year) % 4 == 0) ++#define days_in_year(a) (leapyear(a) ? 366 : 365) ++#define days_in_month(a) (month_days[(a) - 1]) ++ ++static int month_days[12] = { ++ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ++}; ++ ++/* ++ * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) ++ */ ++static void Novfs_GregorianDay(struct local_rtc_time *tm) ++{ ++ int leapsToDate; ++ int lastYear; ++ int day; ++ int MonthOffset[] = ++ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; ++ ++ lastYear = tm->tm_year - 1; ++ ++ /* ++ * Number of leap corrections to apply up to end of last year ++ */ ++ leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; ++ ++ /* ++ * This year is a leap year if it is divisible by 4 except when it is ++ * divisible by 100 unless it is divisible by 400 ++ * ++ * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be ++ */ ++ if ((tm->tm_year % 4 == 0) && ++ ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) && ++ (tm->tm_mon > 2)) { ++ /* ++ * We are past Feb. 29 in a leap year ++ */ ++ day = 1; ++ } else { ++ day = 0; ++ } ++ ++ day += lastYear * 365 + leapsToDate + MonthOffset[tm->tm_mon - 1] + ++ tm->tm_mday; ++ ++ tm->tm_wday = day % 7; ++} ++ ++static void private_to_tm(int tim, struct local_rtc_time *tm) ++{ ++ register int i; ++ register long hms, day; ++ ++ day = tim / SECDAY; ++ hms = tim % SECDAY; ++ ++ /* Hours, minutes, seconds are easy */ ++ tm->tm_hour = hms / 3600; ++ tm->tm_min = (hms % 3600) / 60; ++ tm->tm_sec = (hms % 3600) % 60; ++ ++ /* Number of years in days */ ++ for (i = STARTOFTIME; day >= days_in_year(i); i++) ++ day -= days_in_year(i); ++ tm->tm_year = i; ++ ++ /* Number of months in days left */ ++ if (leapyear(tm->tm_year)) ++ days_in_month(FEBRUARY) = 29; ++ for (i = 1; day >= days_in_month(i); i++) ++ day -= days_in_month(i); ++ days_in_month(FEBRUARY) = 28; ++ tm->tm_mon = i; ++ ++ /* Days are what is left over (+1) from all that. */ ++ tm->tm_mday = day + 1; ++ ++ /* ++ * Determine the day of week ++ */ ++ Novfs_GregorianDay(tm); ++} ++ ++char *ctime_r(time_t * clock, char *buf) ++{ ++ struct local_rtc_time tm; ++ static char *DAYOFWEEK[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; ++ static char *MONTHOFYEAR[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; ++ ++ private_to_tm(*clock, &tm); ++ ++ sprintf(buf, "%s %s %d %d:%02d:%02d %d", DAYOFWEEK[tm.tm_wday], ++ MONTHOFYEAR[tm.tm_mon - 1], tm.tm_mday, tm.tm_hour, tm.tm_min, ++ tm.tm_sec, tm.tm_year); ++ return (buf); ++} ++ ++static void profile_dump_dt(struct dentry *parent, void *pf) ++{ ++ void (*pfunc) (char *Fmt, ...) = pf; ++ struct l { ++ struct l *next; ++ struct dentry *dentry; ++ } *l, *n, *start; ++ struct list_head *p; ++ struct dentry *d; ++ char *buf, *path, *sd; ++ char inode_number[16]; ++ ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (!buf) ++ return; ++ ++ if (parent) { ++ pfunc("starting 0x%p %.*s\n", parent, parent->d_name.len, ++ parent->d_name.name); ++ if (parent->d_subdirs.next == &parent->d_subdirs) { ++ pfunc("No children...\n"); ++ } else { ++ start = kmalloc(sizeof(*start), GFP_KERNEL); ++ if (start) { ++ start->next = NULL; ++ start->dentry = parent; ++ l = start; ++ while (l) { ++ p = l->dentry->d_subdirs.next; ++ while (p != &l->dentry->d_subdirs) { ++ d = list_entry(p, struct dentry, ++ D_CHILD); ++ p = p->next; ++ ++ if (d->d_subdirs.next != &d->d_subdirs) { ++ n = kmalloc(sizeof(*n), GFP_KERNEL); ++ if (n) { ++ n->next = l->next; ++ l->next = n; ++ n->dentry = d; ++ } ++ } else { ++ path = Scope_dget_path(d, buf, PATH_LENGTH_BUFFER, 1); ++ if (path) { ++ pfunc("1-0x%p %s\n" ++ " d_name: %.*s\n" ++ " d_parent: 0x%p\n" ++ " d_count: %d\n" ++ " d_flags: 0x%x\n" ++ " d_subdirs: 0x%p\n" ++ " d_inode: 0x%p\n", ++ d, path, ++ d->d_name.len, ++ d->d_name.name, ++ d->d_parent, ++ atomic_read(&d->d_count), ++ d->d_flags, ++ d->d_subdirs. ++ next, ++ d->d_inode); ++ } ++ } ++ } ++ l = l->next; ++ } ++ l = start; ++ while (l) { ++ d = l->dentry; ++ path = Scope_dget_path(d, buf, PATH_LENGTH_BUFFER, 1); ++ if (path) { ++ sd = " (None)"; ++ if (&d->d_subdirs != d->d_subdirs.next) ++ sd = ""; ++ inode_number[0] = '\0'; ++ if (d->d_inode) { ++ sprintf(inode_number, ++ " (%lu)", ++ d->d_inode-> ++ i_ino); ++ } ++ pfunc("0x%p %s\n" ++ " d_parent: 0x%p\n" ++ " d_count: %d\n" ++ " d_flags: 0x%x\n" ++ " d_subdirs: 0x%p%s\n" ++ " d_inode: 0x%p%s\n", ++ d, path, d->d_parent, ++ atomic_read(&d->d_count), ++ d->d_flags, ++ d->d_subdirs.next, sd, ++ d->d_inode, inode_number); ++ } ++ ++ n = l; ++ l = l->next; ++ kfree(n); ++ } ++ } ++ } ++ } ++ ++ kfree(buf); ++ ++} ++ ++static ssize_t profile_common_read(char __user *buf, size_t len, loff_t *off) ++{ ++ ssize_t retval = 0; ++ size_t count; ++ unsigned long offset = *off; ++ ++ if (0 != (count = DbgPrintBufferOffset - offset)) { ++ if (count > len) { ++ count = len; ++ } ++ ++ count -= copy_to_user(buf, &DbgPrintBuffer[offset], count); ++ ++ if (count == 0) { ++ retval = -EFAULT; ++ } else { ++ *off += (loff_t) count; ++ retval = count; ++ } ++ } ++ return retval; ++ ++} ++ ++static ssize_t profile_inode_read(struct file * file, char __user *buf, size_t len, loff_t *off) ++{ ++ ssize_t retval = 0; ++ unsigned long offset = *off; ++ static char save_DbgPrintOn; ++ ++ if (offset == 0) { ++ down(&LocalPrint_lock); ++ save_DbgPrintOn = DbgPrintOn; ++ DbgPrintOn = 0; ++ ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ Novfs_dump_inode(LocalPrint); ++ } ++ ++ retval = profile_common_read(buf, len, off); ++ ++ if (0 == retval) { ++ DbgPrintOn = save_DbgPrintOn; ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ ++ up(&LocalPrint_lock); ++ } ++ ++ return retval; ++ ++} ++ ++static ssize_t profile_dentry_read(struct file *file, char __user *buf, size_t len, loff_t * off) ++{ ++ ssize_t retval = 0; ++ unsigned long offset = *off; ++ static char save_DbgPrintOn; ++ ++ if (offset == 0) { ++ down(&LocalPrint_lock); ++ save_DbgPrintOn = DbgPrintOn; ++ DbgPrintOn = 0; ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ profile_dump_dt(Novfs_root, LocalPrint); ++ } ++ ++ retval = profile_common_read(buf, len, off); ++ ++ if (0 == retval) { ++ DbgPrintBufferOffset = DbgPrintBufferReadOffset = 0; ++ DbgPrintOn = save_DbgPrintOn; ++ ++ up(&LocalPrint_lock); ++ } ++ ++ return retval; ++ ++} ++ ++uint64_t get_nanosecond_time(void) ++{ ++ struct timespec ts; ++ uint64_t retVal; ++ ++ ts = current_kernel_time(); ++ ++ retVal = (uint64_t) NSEC_PER_SEC; ++ retVal *= (uint64_t) ts.tv_sec; ++ retVal += (uint64_t) ts.tv_nsec; ++ ++ return (retVal); ++} ++ ++int init_profile(void) ++{ ++ int retCode = 0; ++ ++ if (Novfs_Procfs_dir) { ++ dbg_dir = Novfs_Procfs_dir; ++ } else { ++ dbg_dir = proc_mkdir(MODULE_NAME, NULL); ++ } ++ ++ if (dbg_dir) { ++ dbg_dir->owner = THIS_MODULE; ++ dbg_file = create_proc_read_entry("Debug", ++ 0600, ++ dbg_dir, ++ proc_read_DbgBuffer, NULL); ++ if (dbg_file) { ++ dbg_file->owner = THIS_MODULE; ++ dbg_file->size = DBGBUFFERSIZE; ++ memcpy(&Dbg_proc_file_operations, dbg_file->proc_fops, ++ sizeof(struct file_operations)); ++ Dbg_proc_file_operations.read = User_proc_read_DbgBuffer; ++ Dbg_proc_file_operations.write = User_proc_write_DbgBuffer; ++ dbg_file->proc_fops = &Dbg_proc_file_operations; ++ } else { ++ remove_proc_entry(MODULE_NAME, NULL); ++ vfree(DbgPrintBuffer); ++ DbgPrintBuffer = NULL; ++ } ++ } ++ ++ if (DbgPrintBuffer) { ++ if (dbg_dir) { ++ inode_file = create_proc_entry("inode", 0600, dbg_dir); ++ if (inode_file) { ++ inode_file->owner = THIS_MODULE; ++ inode_file->size = 0; ++ memcpy(&inode_proc_file_ops, ++ inode_file->proc_fops, ++ sizeof(struct file_operations)); ++ inode_proc_file_ops.owner = THIS_MODULE; ++ inode_proc_file_ops.read = profile_inode_read; ++ inode_file->proc_fops = &inode_proc_file_ops; ++ } ++ ++ dentry_file = create_proc_entry("dentry", ++ 0600, dbg_dir); ++ if (dentry_file) { ++ dentry_file->owner = THIS_MODULE; ++ dentry_file->size = 0; ++ memcpy(&dentry_proc_file_ops, ++ dentry_file->proc_fops, ++ sizeof(struct file_operations)); ++ dentry_proc_file_ops.owner = THIS_MODULE; ++ dentry_proc_file_ops.read = profile_dentry_read; ++ dentry_file->proc_fops = &dentry_proc_file_ops; ++ } ++ } else { ++ vfree(DbgPrintBuffer); ++ DbgPrintBuffer = NULL; ++ } ++ } ++ return (retCode); ++} ++ ++void uninit_profile(void) ++{ ++ if (dbg_file) { ++ DbgPrint("Calling remove_proc_entry(Debug, NULL)\n"); ++ remove_proc_entry("Debug", dbg_dir); ++ } ++ if (inode_file) { ++ DbgPrint("Calling remove_proc_entry(inode, NULL)\n"); ++ remove_proc_entry("inode", dbg_dir); ++ } ++ if (dentry_file) { ++ DbgPrint("Calling remove_proc_entry(dentry, NULL)\n"); ++ remove_proc_entry("dentry", dbg_dir); ++ } ++ if (dbg_dir && (dbg_dir != Novfs_Procfs_dir)) { ++ DbgPrint("Calling remove_proc_entry(%s, NULL)\n", MODULE_NAME); ++ remove_proc_entry(MODULE_NAME, NULL); ++ } ++} ++ ++ +--- /dev/null ++++ b/fs/novfs/scope.c +@@ -0,0 +1,675 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * This file contains functions used to scope users. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vfs.h" ++ ++#define SHUTDOWN_INTERVAL 5 ++#define CLEANUP_INTERVAL 10 ++#define MAX_USERNAME_LENGTH 32 ++ ++struct scope_list { ++ struct list_head entry; ++ struct schandle ScopeId; ++ struct schandle SessionId; ++ pid_t ScopePid; ++ struct task_struct *ScopeTask; ++ unsigned int ScopeHash; ++ uid_t ScopeUid; ++ u64 ScopeUSize; ++ u64 ScopeUFree; ++ u64 ScopeUTEnties; ++ u64 ScopeUAEnties; ++ int ScopeUserNameLength; ++ unsigned char ScopeUserName[MAX_USERNAME_LENGTH]; ++}; ++ ++static struct list_head Scope_List; ++static struct semaphore Scope_Lock; ++static struct semaphore Scope_Thread_Delay; ++static int Scope_Thread_Terminate; ++static struct timer_list Scope_Timer; ++static unsigned int Scope_Hash_Val = 1; ++ ++static struct scope_list *Scope_Search4Scope(struct schandle *Id, bool Session, ++ bool Locked) ++{ ++ struct scope_list *scope; ++ struct scope_list *rscope = NULL; ++ struct schandle *cur_scope; ++ struct list_head *sl; ++ int offset; ++ ++ DbgPrint("Scope_Search4Scope: 0x%p:%p 0x%x 0x%x\n", ++ Id->hTypeId, Id->hId, Session, Locked); ++ ++ if (Session) ++ offset = offsetof(struct scope_list, SessionId); ++ else ++ offset = offsetof(struct scope_list, ScopeId); ++ ++ if (!Locked) ++ down(&Scope_Lock); ++ ++ sl = Scope_List.next; ++ DbgPrint("Scope_Search4Scope: 0x%p\n", sl); ++ while (sl != &Scope_List) { ++ scope = list_entry(sl, struct scope_list, entry); ++ ++ cur_scope = (session_t *) ((char *)scope + offset); ++ if (SC_EQUAL(Id, cur_scope)) { ++ rscope = scope; ++ break; ++ } ++ ++ sl = sl->next; ++ } ++ ++ if (!Locked) ++ up(&Scope_Lock); ++ ++ DbgPrint("Scope_Search4Scope: return 0x%p\n", rscope); ++ return rscope; ++} ++ ++static struct scope_list *Scope_Find_Scope(bool Create) ++{ ++ struct scope_list *scope = NULL; ++ struct scope_list *pscope = NULL; ++ struct task_struct *task; ++ struct schandle scopeId; ++ int addscope = 0; ++ ++ task = current; ++ ++ DbgPrint("Scope_Find_Scope: %d %d %d %d\n", task->uid, task->euid, ++ task->suid, task->fsuid); ++ ++ /* scopeId = task->euid; */ ++ UID_TO_SCHANDLE(scopeId, task->euid); ++ ++ scope = Scope_Search4Scope(&scopeId, 0, 0); ++ if (scope || (!Create)) ++ return scope; ++ ++ scope = kmalloc(sizeof(*pscope), GFP_KERNEL); ++ if (!scope) ++ return NULL; ++ scope->ScopeId = scopeId; ++ SC_INITIALIZE(scope->SessionId); ++ scope->ScopePid = task->pid; ++ scope->ScopeTask = task; ++ scope->ScopeHash = 0; ++ scope->ScopeUid = task->euid; ++ scope->ScopeUserName[0] = '\0'; ++ ++ if (!Daemon_CreateSessionId(&scope->SessionId)) { ++ DbgPrint("Scope_Find_Scope2: %d %d %d %d\n", task->uid, ++ task->euid, task->suid, task->fsuid); ++ memset(scope->ScopeUserName, 0, sizeof(scope->ScopeUserName)); ++ scope->ScopeUserNameLength = 0; ++ Daemon_getpwuid(task->euid, sizeof(scope->ScopeUserName), ++ scope->ScopeUserName); ++ scope->ScopeUserNameLength = strlen(scope->ScopeUserName); ++ addscope = 1; ++ } ++ ++ scope->ScopeHash = Scope_Hash_Val++; ++ DbgPrint("Scope_Find_Scope: Adding 0x%p\n" ++ " ScopeId: 0x%p:%p\n" ++ " SessionId: 0x%p:%p\n" ++ " ScopePid: %d\n" ++ " ScopeTask: 0x%p\n" ++ " ScopeHash: %u\n" ++ " ScopeUid: %u\n" ++ " ScopeUserNameLength: %u\n" ++ " ScopeUserName: %s\n", ++ scope, ++ scope->ScopeId.hTypeId, scope->ScopeId.hId, ++ scope->SessionId.hTypeId, scope->SessionId.hId, ++ scope->ScopePid, ++ scope->ScopeTask, ++ scope->ScopeHash, ++ scope->ScopeUid, ++ scope->ScopeUserNameLength, ++ scope->ScopeUserName); ++ ++ if (SC_PRESENT(scope->SessionId)) { ++ down(&Scope_Lock); ++ pscope = Scope_Search4Scope(&scopeId, 0, 1); ++ if (!pscope) ++ list_add(&scope->entry, &Scope_List); ++ up(&Scope_Lock); ++ ++ if (pscope) { ++ printk(KERN_ERR "Scope_Find_Scope scope not added " ++ "because it was already there...\n"); ++ Daemon_DestroySessionId(&scope->SessionId); ++ kfree(scope); ++ scope = pscope; ++ addscope = 0; ++ } ++ } else { ++ kfree(scope); ++ scope = NULL; ++ } ++ ++ if (addscope) ++ Novfs_Add_to_Root(scope->ScopeUserName); ++ ++ return scope; ++} ++ ++static int Scope_Validate_Scope(struct scope_list *Scope) ++{ ++ struct scope_list *s; ++ struct list_head *sl; ++ int retVal = 0; ++ ++ DbgPrint("Scope_Validate_Scope: 0x%p\n", Scope); ++ ++ down(&Scope_Lock); ++ ++ sl = Scope_List.next; ++ while (sl != &Scope_List) { ++ s = list_entry(sl, struct scope_list, entry); ++ ++ if (s == Scope) { ++ retVal = 1; ++ break; ++ } ++ ++ sl = sl->next; ++ } ++ ++ up(&Scope_Lock); ++ ++ return retVal; ++} ++ ++/* FIXME void stuff */ ++uid_t Scope_Get_Uid(void *foo) ++{ ++ struct scope_list *scope = foo; ++ uid_t uid = 0; ++ ++ if (!scope) ++ scope = Scope_Find_Scope(1); ++ ++ if (scope && Scope_Validate_Scope(scope)) ++ uid = scope->ScopeUid; ++ ++ return uid; ++} ++ ++char *Scope_Get_UserName(void) ++{ ++ char *name = NULL; ++ struct scope_list *Scope; ++ ++ Scope = Scope_Find_Scope(1); ++ ++ if (Scope && Scope_Validate_Scope(Scope)) ++ name = Scope->ScopeUserName; ++ ++ return name; ++} ++ ++/* FIXME the void * needs to get fixed... */ ++session_t Scope_Get_SessionId(void *foo) ++{ ++ session_t sessionId; ++ struct scope_list *Scope = foo; ++ ++ DbgPrint("Scope_Get_SessionId: 0x%p\n", Scope); ++ SC_INITIALIZE(sessionId); ++ if (!Scope) ++ Scope = Scope_Find_Scope(1); ++ ++ if (Scope && Scope_Validate_Scope(Scope)) ++ sessionId = Scope->SessionId; ++ ++ DbgPrint("Scope_Get_SessionId: return 0x%p:%p\n", sessionId.hTypeId, ++ sessionId.hId); ++ return sessionId; ++} ++ ++struct scope_list *Scope_Get_ScopefromName(struct qstr *name) ++{ ++ struct scope_list *scope; ++ struct scope_list *rscope = NULL; ++ struct list_head *sl; ++ ++ DbgPrint("Scope_Get_ScopefromName: %.*s\n", name->len, name->name); ++ ++ down(&Scope_Lock); ++ ++ sl = Scope_List.next; ++ while (sl != &Scope_List) { ++ scope = list_entry(sl, struct scope_list, entry); ++ ++ if ((name->len == scope->ScopeUserNameLength) && ++ (strncmp(scope->ScopeUserName, name->name, name->len) == 0)) { ++ rscope = scope; ++ break; ++ } ++ sl = sl->next; ++ } ++ ++ up(&Scope_Lock); ++ ++ return rscope; ++} ++ ++int Scope_Set_UserSpace(u64 *TotalSize, u64 *Free, ++ u64 *TotalEnties, u64 *FreeEnties) ++{ ++ struct scope_list *scope; ++ int retVal = 0; ++ ++ scope = Scope_Find_Scope(1); ++ ++ if (scope) { ++ if (TotalSize) ++ scope->ScopeUSize = *TotalSize; ++ if (Free) ++ scope->ScopeUFree = *Free; ++ if (TotalEnties) ++ scope->ScopeUTEnties = *TotalEnties; ++ if (FreeEnties) ++ scope->ScopeUAEnties = *FreeEnties; ++ } ++ ++ return retVal; ++} ++ ++int Scope_Get_UserSpace(u64 *TotalSize, u64 *Free, ++ u64 *TotalEnties, u64 *FreeEnties) ++{ ++ struct scope_list *scope; ++ int retVal = 0; ++ ++ u64 td, fd, te, fe; ++ ++ scope = Scope_Find_Scope(1); ++ ++ td = fd = te = fe = 0; ++ if (scope) { ++ ++ retVal = Daemon_Get_UserSpace(&scope->SessionId, ++ &td, &fd, &te, &fe); ++ ++ scope->ScopeUSize = td; ++ scope->ScopeUFree = fd; ++ scope->ScopeUTEnties = te; ++ scope->ScopeUAEnties = fe; ++ } ++ ++ if (TotalSize) ++ *TotalSize = td; ++ if (Free) ++ *Free = fd; ++ if (TotalEnties) ++ *TotalEnties = te; ++ if (FreeEnties) ++ *FreeEnties = fe; ++ ++ return retVal; ++} ++ ++struct scope_list *Scope_Get_ScopefromPath(struct dentry *dentry) ++{ ++ struct scope_list *scope = NULL; ++ char *buf, *path, *cp; ++ struct qstr name; ++ ++ buf = kmalloc(PATH_LENGTH_BUFFER, GFP_KERNEL); ++ if (buf) { ++ path = Scope_dget_path(dentry, buf, PATH_LENGTH_BUFFER, 0); ++ if (path) { ++ DbgPrint("Scope_Get_ScopefromPath: %s\n", path); ++ ++ if (*path == '/') ++ path++; ++ ++ cp = path; ++ if (*cp) { ++ while (*cp && (*cp != '/')) ++ cp++; ++ ++ *cp = '\0'; ++ name.hash = 0; ++ name.len = (int)(cp - path); ++ name.name = path; ++ scope = Scope_Get_ScopefromName(&name); ++ } ++ } ++ kfree(buf); ++ } ++ ++ return scope; ++} ++ ++static char *add_to_list(char *name, char *list, char *endoflist) ++{ ++ while (*name && (list < endoflist)) ++ *list++ = *name++; ++ ++ if (list < endoflist) ++ *list++ = '\0'; ++ ++ return list; ++} ++ ++char *Scope_Get_ScopeUsers(void) ++{ ++ struct scope_list *scope; ++ struct list_head *sl; ++ int asize = 8 * MAX_USERNAME_LENGTH; ++ char *list, *cp, *ep; ++ ++ DbgPrint("Scope_Get_ScopeUsers\n"); ++ ++ do { /* Copy list until done or out of memory */ ++ list = kmalloc(asize, GFP_KERNEL); ++ ++ DbgPrint("Scope_Get_ScopeUsers list=0x%p\n", list); ++ if (list) { ++ cp = list; ++ ep = cp + asize; ++ ++ /* ++ * Add the tree and server entries ++ */ ++ cp = add_to_list(TREE_DIRECTORY_NAME, cp, ep); ++ cp = add_to_list(SERVER_DIRECTORY_NAME, cp, ep); ++ ++ down(&Scope_Lock); ++ ++ sl = Scope_List.next; ++ while ((sl != &Scope_List) && (cp < ep)) { ++ scope = list_entry(sl, struct scope_list, entry); ++ ++ DbgPrint("Scope_Get_ScopeUsers found 0x%p %s\n", ++ scope, scope->ScopeUserName); ++ ++ cp = add_to_list(scope->ScopeUserName, cp, ep); ++ ++ sl = sl->next; ++ } ++ ++ up(&Scope_Lock); ++ ++ if (cp < ep) { ++ *cp++ = '\0'; ++ asize = 0; ++ } else { /* Allocation was to small, up size */ ++ asize *= 4; ++ kfree(list); ++ list = NULL; ++ } ++ } else { /* if allocation fails return an empty list */ ++ ++ break; ++ } ++ } while (!list); /* list was to small try again */ ++ ++ return list; ++} ++ ++void *Scope_Lookup(void) ++{ ++ return Scope_Find_Scope(1); ++} ++ ++static void Scope_Timer_Function(unsigned long context) ++{ ++ up(&Scope_Thread_Delay); ++} ++ ++static int Scope_Cleanup_Thread(void *Args) ++{ ++ struct scope_list *scope; ++ struct scope_list *rscope; ++ struct list_head *sl, cleanup; ++ struct task_struct *task; ++ ++ DbgPrint("Scope_Cleanup_Thread: %d\n", current->pid); ++ ++ /* ++ * Setup and start que timer ++ */ ++ init_timer(&Scope_Timer); ++ ++ while (0 == Scope_Thread_Terminate) { ++ DbgPrint("Scope_Cleanup_Thread: looping\n"); ++ if (Scope_Thread_Terminate) ++ break; ++ ++ /* ++ * Check scope list for any terminated processes ++ */ ++ down(&Scope_Lock); ++ ++ sl = Scope_List.next; ++ INIT_LIST_HEAD(&cleanup); ++ ++ while (sl != &Scope_List) { ++ scope = list_entry(sl, struct scope_list, entry); ++ sl = sl->next; ++ ++ rscope = NULL; ++ rcu_read_lock(); ++ for_each_process(task) { ++ if ((task->uid == scope->ScopeUid) ++ || (task->euid == scope->ScopeUid)) { ++ rscope = scope; ++ break; ++ } ++ } ++ rcu_read_unlock(); ++ ++ if (!rscope) { ++ list_move(&scope->entry, &cleanup); ++ DbgPrint("Scope_Cleanup_Thread: Scope=0x%p\n", ++ rscope); ++ } ++ } ++ ++ up(&Scope_Lock); ++ ++ sl = cleanup.next; ++ while (sl != &cleanup) { ++ scope = list_entry(sl, struct scope_list, entry); ++ sl = sl->next; ++ ++ DbgPrint("Scope_Cleanup_Thread: Removing 0x%p\n" ++ " ScopeId: 0x%p:%p\n" ++ " SessionId: 0x%p:%p\n" ++ " ScopePid: %d\n" ++ " ScopeTask: 0x%p\n" ++ " ScopeHash: %u\n" ++ " ScopeUid: %u\n" ++ " ScopeUserName: %s\n", ++ scope, ++ scope->ScopeId, ++ scope->SessionId, ++ scope->ScopePid, ++ scope->ScopeTask, ++ scope->ScopeHash, ++ scope->ScopeUid, scope->ScopeUserName); ++ if (!Scope_Search4Scope(&scope->SessionId, 1, 0)) { ++ Novfs_Remove_from_Root(scope->ScopeUserName); ++ Daemon_DestroySessionId(&scope->SessionId); ++ } ++ kfree(scope); ++ } ++ ++ Scope_Timer.expires = jiffies + HZ * CLEANUP_INTERVAL; ++ Scope_Timer.data = (unsigned long)0; ++ Scope_Timer.function = Scope_Timer_Function; ++ add_timer(&Scope_Timer); ++ DbgPrint("Scope_Cleanup_Thread: sleeping\n"); ++ ++ if (down_interruptible(&Scope_Thread_Delay)) ++ break; ++ ++ del_timer(&Scope_Timer); ++ } ++ Scope_Thread_Terminate = 0; ++ ++ printk(KERN_INFO "Scope_Cleanup_Thread: Exit\n"); ++ DbgPrint("Scope_Cleanup_Thread: Exit\n"); ++ return 0; ++} ++ ++void Scope_Cleanup(void) ++{ ++ struct scope_list *scope; ++ struct list_head *sl; ++ ++ DbgPrint("Scope_Cleanup:\n"); ++ ++ /* ++ * Check scope list for any terminated processes ++ */ ++ down(&Scope_Lock); ++ ++ sl = Scope_List.next; ++ ++ while (sl != &Scope_List) { ++ scope = list_entry(sl, struct scope_list, entry); ++ sl = sl->next; ++ ++ list_del(&scope->entry); ++ ++ DbgPrint("Scope_Cleanup: Removing 0x%p\n" ++ " ScopeId: 0x%p:%p\n" ++ " SessionId: 0x%p:%p\n" ++ " ScopePid: %d\n" ++ " ScopeTask: 0x%p\n" ++ " ScopeHash: %u\n" ++ " ScopeUid: %u\n" ++ " ScopeUserName: %s\n", ++ scope, ++ scope->ScopeId, ++ scope->SessionId, ++ scope->ScopePid, ++ scope->ScopeTask, ++ scope->ScopeHash, ++ scope->ScopeUid, scope->ScopeUserName); ++ if (!Scope_Search4Scope(&scope->SessionId, 1, 1)) { ++ Novfs_Remove_from_Root(scope->ScopeUserName); ++ Daemon_DestroySessionId(&scope->SessionId); ++ } ++ kfree(scope); ++ } ++ ++ up(&Scope_Lock); ++ ++} ++ ++/* ++ * Arguments: struct dentry *dentry - starting entry ++ * char *Buf - pointer to memory buffer ++ * unsigned int Buflen - size of memory buffer ++ * ++ * Returns: pointer to path. ++ * ++ * Abstract: Walks the dentry chain building a path. ++ */ ++char *Scope_dget_path(struct dentry *dentry, char *Buf, unsigned int Buflen, ++ int Flags) ++{ ++ char *retval = &Buf[Buflen]; ++ struct dentry *p = dentry; ++ int len; ++ ++ *(--retval) = '\0'; ++ Buflen--; ++ ++ do { ++ if (Buflen > p->d_name.len) { ++ retval -= p->d_name.len; ++ Buflen -= p->d_name.len; ++ memcpy(retval, p->d_name.name, p->d_name.len); ++ *(--retval) = '/'; ++ Buflen--; ++ p = p->d_parent; ++ } else { ++ retval = NULL; ++ break; ++ } ++ } while (!IS_ROOT(p)); ++ ++ if (IS_ROOT(dentry)) ++ retval++; ++ ++ if (Flags) { ++ len = strlen(p->d_sb->s_type->name); ++ if (Buflen - len > 0) { ++ retval -= len; ++ Buflen -= len; ++ memcpy(retval, p->d_sb->s_type->name, len); ++ *(--retval) = '/'; ++ Buflen--; ++ } ++ } ++ ++ return retval; ++} ++ ++void Scope_Init(void) ++{ ++ INIT_LIST_HEAD(&Scope_List); ++ init_MUTEX(&Scope_Lock); ++ init_MUTEX_LOCKED(&Scope_Thread_Delay); ++ ++ kthread_run(Scope_Cleanup_Thread, NULL, "novfs_ST"); ++} ++ ++void Scope_Uninit(void) ++{ ++ unsigned long expires = jiffies + HZ * SHUTDOWN_INTERVAL; ++ ++ printk(KERN_INFO "Scope_Uninit: Start\n"); ++ ++ Scope_Thread_Terminate = 1; ++ ++ up(&Scope_Thread_Delay); ++ ++ mb(); ++ while (Scope_Thread_Terminate && (jiffies < expires)) ++ yield(); ++ ++ /* down(&Scope_Thread_Delay); */ ++ printk(KERN_INFO "Scope_Uninit: Exit\n"); ++ ++} ++ ++ +--- /dev/null ++++ b/fs/novfs/vfs.h +@@ -0,0 +1,436 @@ ++/* ++ * Novell NCP Redirector for Linux ++ * Author: James Turner ++ * ++ * Include file for novfs. ++ * ++ * Copyright (C) 2005 Novell, Inc. ++ * ++ * 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. ++ */ ++#ifndef __NOVFS_H ++#define __NOVFS_H ++ ++#ifndef __STDC_VERSION__ ++#define __STDC_VERSION__ 0L ++#endif ++ ++#include ++#include ++#include ++ ++#include "nwcapi.h" ++ ++typedef void *HANDLE; ++ ++struct schandle { ++ void *hTypeId; ++ void *hId; ++}; ++ ++static inline void copy_schandle(struct schandle *dest, struct schandle *source) ++{ ++ memcpy(dest, source, sizeof(struct schandle)); ++} ++#define copy_session_id copy_schandle ++ ++typedef struct schandle session_t; ++ ++#include "commands.h" ++ ++#define SC_PRESENT(X) ((X.hTypeId != NULL) || (X.hId != NULL)) ? 1 : 0 ++#define SC_EQUAL(X, Y) ((X->hTypeId == Y->hTypeId) && (X->hId == Y->hId)) ? 1 : 0 ++#define SC_INITIALIZE(X) {X.hTypeId = X.hId = NULL;} ++ ++#define UID_TO_SCHANDLE(hSC, uid) \ ++ { \ ++ hSC.hTypeId = NULL; \ ++ hSC.hId = (HANDLE)(unsigned long)(uid); \ ++ } ++ ++ ++ ++/*===[ Manifest constants ]===============================================*/ ++#define NOVFS_MAGIC 0x4e574653 ++#define MODULE_NAME "novfs" ++ ++#define TREE_DIRECTORY_NAME ".Trees" ++#define SERVER_DIRECTORY_NAME ".Servers" ++ ++#define PATH_LENGTH_BUFFER PATH_MAX ++#define NW_MAX_PATH_LENGTH 255 ++ ++#define XA_BUFFER (8 * 1024) ++ ++#define IOC_LOGIN 0x4a540000 ++#define IOC_LOGOUT 0x4a540001 ++#define IOC_XPLAT 0x4a540002 ++#define IOC_SESSION 0x4a540003 ++#define IOC_DEBUGPRINT 0x4a540004 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) ++#define D_CHILD d_u.d_child ++#define AS_TREE_LOCK(l) read_lock_irq(l) ++#define AS_TREE_UNLOCK(l) read_unlock_irq(l) ++#else ++#define D_CHILD d_child ++#define AS_TREE_LOCK(l) spin_lock_irq(l) ++#define AS_TREE_UNLOCK(l) spin_unlock_irq(l) ++#endif ++ ++/* ++ * NetWare file attributes ++ */ ++ ++#define NW_ATTRIBUTE_NORMAL 0x00 ++#define NW_ATTRIBUTE_READ_ONLY 0x01 ++#define NW_ATTRIBUTE_HIDDEN 0x02 ++#define NW_ATTRIBUTE_SYSTEM 0x04 ++#define NW_ATTRIBUTE_EXECUTE_ONLY 0x08 ++#define NW_ATTRIBUTE_DIRECTORY 0x10 ++#define NW_ATTRIBUTE_ARCHIVE 0x20 ++#define NW_ATTRIBUTE_EXECUTE 0x40 ++#define NW_ATTRIBUTE_SHAREABLE 0x80 ++ ++/* ++ * Define READ/WRITE flag for struct data_list ++ */ ++#define DLREAD 0 ++#define DLWRITE 1 ++ ++/* ++ * Define list type ++ */ ++#define USER_LIST 1 ++#define SERVER_LIST 2 ++#define VOLUME_LIST 3 ++ ++/* ++ * Define flags used in for inodes ++ */ ++#define USER_INODE 1 ++#define UPDATE_INODE 2 ++ ++/* ++ * Define flags for directory cache flags ++ */ ++#define ENTRY_VALID 0x00000001 ++ ++#ifdef INTENT_MAGIC ++#define NDOPENFLAGS intent.it_flags ++#else ++#define NDOPENFLAGS intent.open.flags ++#endif ++ ++/* ++ * daemon_command_t flags values ++ */ ++#define INTERRUPTIBLE 1 ++ ++#ifndef NOVFS_VFS_MAJOR ++#define NOVFS_VFS_MAJOR 0 ++#endif ++ ++#ifndef NOVFS_VFS_MINOR ++#define NOVFS_VFS_MINOR 0 ++#endif ++ ++#ifndef NOVFS_VFS_SUB ++#define NOVFS_VFS_SUB 0 ++#endif ++ ++#ifndef NOVFS_VFS_RELEASE ++#define NOVFS_VFS_RELEASE 0 ++#endif ++ ++#define VALUE_TO_STR( value ) #value ++#define DEFINE_TO_STR(value) VALUE_TO_STR(value) ++ ++#define NOVFS_VERSION_STRING \ ++ DEFINE_TO_STR(NOVFS_VFS_MAJOR)"." \ ++ DEFINE_TO_STR(NOVFS_VFS_MINOR)"." \ ++ DEFINE_TO_STR(NOVFS_VFS_SUB)"-" \ ++ DEFINE_TO_STR(NOVFS_VFS_RELEASE) \ ++ "\0" ++ ++struct entry_info { ++ int type; ++ umode_t mode; ++ uid_t uid; ++ gid_t gid; ++ loff_t size; ++ struct timespec atime; ++ struct timespec mtime; ++ struct timespec ctime; ++ int namelength; ++ unsigned char name[1]; ++}; ++ ++struct novfs_string { ++ int length; ++ unsigned char *data; ++}; ++ ++struct login { ++ struct novfs_string Server; ++ struct novfs_string UserName; ++ struct novfs_string Password; ++}; ++ ++struct logout { ++ struct novfs_string Server; ++}; ++ ++struct dir_cache { ++ struct list_head list; ++ int flags; ++ u64 jiffies; ++ ino_t ino; ++ loff_t size; ++ umode_t mode; ++ struct timespec atime; ++ struct timespec mtime; ++ struct timespec ctime; ++ unsigned long hash; ++ int nameLen; ++ char name[1]; ++}; ++ ++struct data_list { ++ void *page; ++ void *offset; ++ int len; ++ int rwflag; ++}; ++ ++ ++extern char *ctime_r(time_t * clock, char *buf); ++ ++static inline u32 HandletoUint32(HANDLE h) ++/* ++ * ++ * Arguments: HANDLE h - handle value ++ * ++ * Returns: u32 - u32 value ++ * ++ * Abstract: Converts a HANDLE to a u32 type. ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ return (u32) ((unsigned long) h); ++} ++ ++/*++======================================================================*/ ++static inline HANDLE Uint32toHandle(u32 ui32) ++/* ++ * ++ * Arguments: u32 ui32 ++ * ++ * Returns: HANDLE - Handle type. ++ * ++ * Abstract: Converts a u32 to a HANDLE type. ++ * ++ * Notes: ++ * ++ * Environment: ++ * ++ *========================================================================*/ ++{ ++ return ((HANDLE) (unsigned long) ui32); ++} ++ ++/* Global variables */ ++ ++extern int Novfs_Version_Major; ++extern int Novfs_Version_Minor; ++extern int Novfs_Version_Sub; ++extern int Novfs_Version_Release; ++extern struct dentry *Novfs_root; ++extern struct proc_dir_entry *Novfs_Procfs_dir; ++extern unsigned long File_update_timeout; ++extern int PageCache; ++extern char *Novfs_CurrentMount; ++extern struct dentry_operations Novfs_dentry_operations; ++extern int MaxIoSize; ++ ++ ++/* Global functions */ ++extern int Novfs_Remove_from_Root(char *); ++extern void Novfs_dump_inode(void *pf); ++ ++extern void mydump(int size, void *dumpptr); ++ ++extern int Queue_Daemon_Command(void *request, unsigned long reqlen, void *data, ++ int dlen, void **reply, unsigned long * replen, ++ int interruptible); ++ ++extern int Init_Procfs_Interface(void); ++extern void Uninit_Procfs_Interface(void); ++ ++/* ++ * daemon.c functions ++ */ ++extern void Init_Daemon_Queue(void); ++extern void Uninit_Daemon_Queue(void); ++extern int do_login(NclString * Server, NclString * Username, NclString * Password, HANDLE * lgnId, struct schandle *Session); ++extern int do_logout(struct qstr *Server, struct schandle *Session); ++extern int Daemon_SetMountPoint(char *Path); ++extern int Daemon_CreateSessionId(struct schandle *SessionId); ++extern int Daemon_DestroySessionId(struct schandle *SessionId); ++extern int Daemon_getpwuid(uid_t uid, int unamelen, char *uname); ++extern int Daemon_Get_UserSpace(struct schandle *session_id, u64 *TotalSize, ++ u64 *TotalFree, u64 *TotalDirectoryEnties, ++ u64 *FreeDirectoryEnties); ++extern int Daemon_SendDebugCmd(char *Command); ++extern ssize_t Daemon_Receive_Reply(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos); ++extern ssize_t Daemon_Send_Command(struct file *file, char __user *buf, size_t len, loff_t *off); ++extern int Daemon_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++extern int Daemon_Library_close(struct inode *inode, struct file *file); ++extern int Daemon_Library_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ++extern int Daemon_Library_open(struct inode *inode, struct file *file); ++extern ssize_t Daemon_Library_write(struct file *file, const char __user *buf, size_t len, loff_t * off); ++extern ssize_t Daemon_Library_read(struct file *file, char __user *buf, size_t len, loff_t * off); ++extern loff_t Daemon_Library_llseek(struct file *file, loff_t offset, int origin); ++extern int Daemon_Open_Control(struct inode *Inode, struct file *File); ++extern int Daemon_Close_Control(struct inode *Inode, struct file *File); ++extern int Daemon_getversion(char *Buf, int Length); ++ ++ ++/* ++ * file.c functions ++ */ ++extern int Novfs_get_alltrees(struct dentry *parent); ++extern int Novfs_Get_Connected_Server_List(unsigned char **ServerList, struct schandle *SessionId); ++extern int Novfs_Get_Server_Volume_List(struct qstr *Server, unsigned char **VolumeList, struct schandle *SessionId); ++extern int Novfs_Get_File_Info(unsigned char *Path, struct entry_info *Info, struct schandle *SessionId); ++extern int Novfs_GetX_File_Info(char *Path, const char *Name, char *buffer, ssize_t buffer_size, ssize_t *dataLen, struct schandle *SessionId); ++extern int Novfs_ListX_File_Info(char *Path, char *buffer, ssize_t buffer_size, ssize_t * dataLen, struct schandle *SessionId); ++extern int Novfs_SetX_File_Info(char *Path, const char *Name, const void *Value, ++ unsigned long valueLen, ++ unsigned long *bytesWritten, int flags, ++ struct schandle *SessionId); ++ ++extern int Novfs_Get_Directory_ListEx(unsigned char *Path, HANDLE *EnumHandle, ++ int *Count, struct entry_info **Info, ++ struct schandle *SessionId); ++extern int Novfs_Open_File(unsigned char *Path, int Flags, struct entry_info *info, ++ HANDLE * Handle, session_t SessionId); ++extern int Novfs_Create(unsigned char *Path, int DirectoryFlag, ++ session_t SessionId); ++extern int Novfs_Close_File(HANDLE Handle, session_t SessionId); ++extern int Novfs_Read_File(HANDLE Handle, unsigned char *Buffer, size_t * Bytes, ++ loff_t * Offset, session_t SessionId); ++extern int Novfs_Read_Pages(HANDLE Handle, struct data_list *dlist, int DList_Cnt, ++ size_t * Bytes, loff_t * Offset, ++ session_t SessionId); ++extern int Novfs_Write_File(HANDLE Handle, unsigned char *Buffer, ++ size_t * Bytes, loff_t * Offset, ++ session_t SessionId); ++extern int Novfs_Write_Page(HANDLE Handle, struct page *Page, ++ session_t SessionId); ++extern int Novfs_Write_Pages(HANDLE Handle, struct data_list *dlist, int DList_Cnt, ++ size_t Bytes, loff_t Offset, session_t SessionId); ++extern int Novfs_Delete(unsigned char *Path, int DirectoryFlag, ++ session_t SessionId); ++extern int Novfs_Truncate_File(unsigned char *Path, int PathLen, ++ session_t SessionId); ++extern int Novfs_Truncate_File_Ex(HANDLE Handle, loff_t Offset, ++ session_t SessionId); ++extern int Novfs_Rename_File(int DirectoryFlag, unsigned char *OldName, ++ int OldLen, unsigned char *NewName, int NewLen, ++ session_t SessionId); ++extern int Novfs_Set_Attr(unsigned char *Path, struct iattr *Attr, ++ session_t SessionId); ++extern int Novfs_Get_File_Cache_Flag(unsigned char * Path, session_t SessionId); ++extern int Novfs_Set_File_Lock(session_t SessionId, HANDLE fhandle, ++ unsigned char fl_type, loff_t fl_start, ++ loff_t len); ++ ++extern struct inode *Novfs_get_inode(struct super_block *sb, int mode, int dev, uid_t uid, ino_t ino, struct qstr *name); ++extern int Novfs_Read_Stream(HANDLE ConnHandle, unsigned char * Handle, ++ unsigned char * Buffer, size_t * Bytes, loff_t * Offset, ++ int User, session_t SessionId); ++extern int Novfs_Write_Stream(HANDLE ConnHandle, unsigned char * Handle, ++ unsigned char * Buffer, size_t * Bytes, loff_t * Offset, ++ session_t SessionId); ++extern int Novfs_Close_Stream(HANDLE ConnHandle, unsigned char * Handle, ++ session_t SessionId); ++ ++extern int Novfs_Add_to_Root(char *); ++ ++ ++/* ++ * scope.c functions ++ */ ++extern void Scope_Init(void); ++extern void Scope_Uninit(void); ++extern void *Scope_Lookup(void); ++extern uid_t Scope_Get_Uid(void *); ++extern session_t Scope_Get_SessionId(void *Scope); ++//extern session_t Scope_Get_SessionId(PSCOPE_LIST Scope); ++extern char *Scope_Get_ScopeUsers(void); ++extern int Scope_Set_UserSpace(u64 *TotalSize, u64 *Free, ++ u64 *TotalEnties, u64 *FreeEnties); ++extern int Scope_Get_UserSpace(u64 *TotalSize, u64 *Free, ++ u64 *TotalEnties, u64 *FreeEnties); ++extern char *Scope_dget_path(struct dentry *Dentry, char *Buf, ++ unsigned int Buflen, int Flags); ++extern char *Scope_Get_UserName(void); ++extern void Scope_Cleanup(void); ++ ++/* ++ * profile.c functions ++ */ ++extern u64 get_nanosecond_time(void); ++static inline void *Novfs_Malloc(size_t size, int flags) { return kmalloc(size, flags); } ++extern int DbgPrint(char *Fmt, ...); ++extern int init_profile(void); ++extern void uninit_profile(void); ++ ++/* ++ * nwcapi.c functions ++ */ ++extern int NwAuthConnWithId(PXPLAT pdata, session_t Session); ++extern int NwConnClose(PXPLAT pdata, HANDLE * Handle, session_t Session); ++extern int NwGetConnInfo(PXPLAT pdata, session_t Session); ++extern int NwSetConnInfo(PXPLAT pdata, session_t Session); ++extern int NwGetDaemonVersion(PXPLAT pdata, session_t Session); ++extern int NwGetIdentityInfo(PXPLAT pdata, session_t Session); ++extern int NwLicenseConn(PXPLAT pdata, session_t Session); ++extern int NwLoginIdentity(PXPLAT pdata, struct schandle *Session); ++extern int NwLogoutIdentity(PXPLAT pdata, session_t Session); ++extern int NwOpenConnByAddr(PXPLAT pdata, HANDLE * Handle, session_t Session); ++extern int NwOpenConnByName(PXPLAT pdata, HANDLE * Handle, session_t Session); ++extern int NwOpenConnByRef(PXPLAT pdata, HANDLE * Handle, session_t Session); ++extern int NwQueryFeature(PXPLAT pdata, session_t Session); ++extern int NwRawSend(PXPLAT pdata, session_t Session); ++extern int NwScanConnInfo(PXPLAT pdata, session_t Session); ++extern int NwSysConnClose(PXPLAT pdata, unsigned long * Handle, session_t Session); ++extern int NwUnAuthenticate(PXPLAT pdata, session_t Session); ++extern int NwUnlicenseConn(PXPLAT pdata, session_t Session); ++extern int NwcChangeAuthKey(PXPLAT pdata, session_t Session); ++extern int NwcEnumIdentities(PXPLAT pdata, session_t Session); ++extern int NwcGetDefaultNameCtx(PXPLAT pdata, session_t Session); ++extern int NwcGetPreferredDSTree(PXPLAT pdata, session_t Session); ++extern int NwcGetTreeMonitoredConn(PXPLAT pdata, session_t Session); ++extern int NwcSetDefaultNameCtx(PXPLAT pdata, session_t Session); ++extern int NwcSetPreferredDSTree(PXPLAT pdata, session_t Session); ++extern int NwcSetPrimaryConn(PXPLAT pdata, session_t Session); ++extern int NwcGetPrimaryConn(PXPLAT pdata, session_t Session); ++extern int NwcSetMapDrive(PXPLAT pdata, session_t Session); ++extern int NwcUnMapDrive(PXPLAT pdata, session_t Session); ++extern int NwcEnumerateDrives(PXPLAT pdata, session_t Session); ++extern int NwcGetBroadcastMessage(PXPLAT pdata, session_t Session); ++extern int NwdSetKeyValue(PXPLAT pdata, session_t Session); ++extern int NwdVerifyKeyValue(PXPLAT pdata, session_t Session); ++ ++ ++#endif /* __NOVFS_H */ ++ diff --git a/src/patches/suse-2.6.27.31/patches.suse/novfs-clear-mappeddrives.patch b/src/patches/suse-2.6.27.31/patches.suse/novfs-clear-mappeddrives.patch new file mode 100644 index 000000000..0b0d3b537 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/novfs-clear-mappeddrives.patch @@ -0,0 +1,164 @@ +From: Goldwyn Rodrigues +Subject: Unlink mapped drives on exit +References: bnc#449451 + +Mapped drives were not being unlinked properly because +of ABI change in the kernel. Fixed local_unlink function +to correctly unlink files. + +--- + fs/novfs/daemon.c | 97 +++++++++++++++++++++++++++++++----------------------- + fs/novfs/nwcapi.c | 2 - + 2 files changed, 57 insertions(+), 42 deletions(-) + +Index: linux-2.6.27/fs/novfs/daemon.c +=================================================================== +--- linux-2.6.27.orig/fs/novfs/daemon.c 2008-11-27 16:02:22.000000000 +0530 ++++ linux-2.6.27/fs/novfs/daemon.c 2008-11-28 11:20:08.000000000 +0530 +@@ -15,6 +15,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -96,7 +97,7 @@ static int NwdConvertNetwareHandle(struc + static int set_map_drive(struct novfs_xplat *pdata, struct novfs_schandle Session); + static int unmap_drive(struct novfs_xplat *pdata, struct novfs_schandle Session); + static int NwdGetMountPath(struct novfs_xplat *pdata); +-static int local_unlink(const char *pathname); ++static long local_unlink(const char *pathname); + + + /*===[ Global variables ]=================================================*/ +@@ -1610,7 +1611,7 @@ int novfs_daemon_lib_ioctl(struct inode + + case NWC_SET_CONN_INFO: + DbgPrint +- ("[VFS XPLAT] Call NwGetConnInfo\n"); ++ ("[VFS XPLAT] Call NwSetConnInfo\n"); + retCode = + novfs_set_conn_info(&data, dh->session); + break; +@@ -2061,54 +2062,68 @@ static void RemoveDriveMaps(void) + up(&DriveMapLock); + } + +-static int local_unlink(const char *pathname) ++/* As picked from do_unlinkat() */ ++ ++static long local_unlink(const char *pathname) + { + int error; + struct dentry *dentry; ++ char *name, *c; + struct nameidata nd; + struct inode *inode = NULL; + +- DbgPrint("local_unlink: %s\n", pathname); + error = path_lookup(pathname, LOOKUP_PARENT, &nd); +- DbgPrint("local_unlink: path_lookup %d\n", error); +- if (!error) { +- error = -EISDIR; +- if (nd.last_type == LAST_NORM) { +- dentry = lookup_create(&nd, 1); +- DbgPrint("local_unlink: lookup_hash 0x%p\n", dentry); +- +- error = PTR_ERR(dentry); +- if (!IS_ERR(dentry)) { +- if (nd.last.name[nd.last.len]) { +- error = +- !dentry-> +- d_inode ? -ENOENT : S_ISDIR(dentry-> +- d_inode-> +- i_mode) +- ? -EISDIR : -ENOTDIR; +- } else { +- inode = dentry->d_inode; +- if (inode) { +- atomic_inc(&inode->i_count); +- } +- error = vfs_unlink(nd.path.dentry->d_inode, dentry, nd.path.mnt); +- DbgPrint +- ("local_unlink: vfs_unlink %d\n", +- error); +- } +- dput(dentry); +- } +- mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +- +- } +- path_put(&nd.path); ++ DbgPrint("local_unlink: path_lookup %s error: %d\n", pathname, error); ++ if (error) ++ return error; ++ ++ error = -EISDIR; ++ if (nd.last_type != LAST_NORM) ++ goto exit1; ++ mutex_lock(&nd.path.dentry->d_inode->i_mutex); ++ /* Get the filename of pathname */ ++ name=c=(char *)pathname; ++ while (*c!='\0') { ++ if (*c=='/') ++ name=++c; ++ c++; ++ } ++ dentry = lookup_one_len(name, nd.path.dentry, strlen(name)); ++ error = PTR_ERR(dentry); ++ DbgPrint("local_unlink: dentry %p\n", dentry); ++ if (!(dentry->d_inode->i_mode & S_IFLNK)) { ++ DbgPrint("local_unlink: %s not a link", name); ++ error=-ENOENT; ++ goto exit1; ++ } ++ ++ if (!IS_ERR(dentry)) { ++ /* Why not before? Because we want correct error value */ ++ if (nd.last.name[nd.last.len]) ++ goto slashes; ++ inode = dentry->d_inode; ++ if (inode) ++ atomic_inc(&inode->i_count); ++ error = mnt_want_write(nd.path.mnt); ++ DbgPrint("local_unlink: inode %p mnt_want_write error %d\n", inode, error); ++ if (error) ++ goto exit2; ++ error = vfs_unlink(nd.path.dentry->d_inode, dentry, nd.path.mnt); ++ mnt_drop_write(nd.path.mnt); ++ exit2: ++ dput(dentry); + } +- +- if (inode) { ++ mutex_unlock(&nd.path.dentry->d_inode->i_mutex); ++ if (inode) + iput(inode); /* truncate the inode here */ +- } +- +- DbgPrint("local_unlink: error=%d\n", error); ++exit1: ++ path_put(&nd.path); ++ DbgPrint("local_unlink: returning error %d\n", error); + return error; ++ ++slashes: ++ error = !dentry->d_inode ? -ENOENT : ++ S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR; ++ goto exit2; + } + +Index: linux-2.6.27/fs/novfs/nwcapi.c +=================================================================== +--- linux-2.6.27.orig/fs/novfs/nwcapi.c 2008-11-27 16:02:22.000000000 +0530 ++++ linux-2.6.27/fs/novfs/nwcapi.c 2008-11-28 11:02:15.000000000 +0530 +@@ -993,7 +993,7 @@ int novfs_scan_conn_info(struct novfs_xp + DbgPrint("NwScanConnInfo: Reply recieved\n"); + DbgPrint(" NextIndex = %x\n", connInfo.uScanIndex); + DbgPrint(" ErrorCode = %x\n", reply->Reply.ErrorCode); +- DbgPrint(" data = %x\n", reply->data); ++ DbgPrint(" data = %p\n", reply->data); + + pDConnInfo = (struct nwd_scan_conn_info *) reply->data; + retCode = (unsigned long) reply->Reply.ErrorCode; diff --git a/src/patches/suse-2.6.27.31/patches.suse/novfs-gregorian-day-fix b/src/patches/suse-2.6.27.31/patches.suse/novfs-gregorian-day-fix new file mode 100644 index 000000000..915a79c69 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/novfs-gregorian-day-fix @@ -0,0 +1,31 @@ +From: Jeff Mahoney +Subject: [PATCH] novfs: Fix GregorianDay conflict + + powerpc and sparc have their own non-static versions of GregorianDay + that conflict with this one. + +Signed-off-by: Jeff Mahoney +--- + fs/novfs/profile.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/novfs/profile.c ++++ b/fs/novfs/profile.c +@@ -314,7 +314,7 @@ static int month_days[12] = { + /* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +-static void GregorianDay(struct local_rtc_time *tm) ++static void NovfsGregorianDay(struct local_rtc_time *tm) + { + int leapsToDate; + int lastYear; +@@ -384,7 +384,7 @@ static void private_to_tm(int tim, struc + /* + * Determine the day of week + */ +- GregorianDay(tm); ++ NovfsGregorianDay(tm); + } + + char *ctime_r(time_t * clock, char *buf) diff --git a/src/patches/suse-2.6.27.31/patches.suse/novfs-patch-2.6.27 b/src/patches/suse-2.6.27.31/patches.suse/novfs-patch-2.6.27 new file mode 100644 index 000000000..d7b929954 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/novfs-patch-2.6.27 @@ -0,0 +1,30 @@ +From: Jeff Mahoney +Subject: [PATCH] novfs: mapping->tree_lock is a spin_lock + + mapping->tree_lock changed from a read_lock to a spin_lock in 2.6.27. + +Signed-off-by: Jeff Mahoney +--- + fs/novfs/inode.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/novfs/inode.c ++++ b/fs/novfs/inode.c +@@ -2029,7 +2029,7 @@ int novfs_a_writepages(struct address_sp + memset(pages, 0, + sizeof(struct page *) * max_page_lookup); + +- read_lock_irq(&mapping->tree_lock); ++ spin_lock_irq(&mapping->tree_lock); + + /* + * Need to ask for one less then max_page_lookup or we +@@ -2063,7 +2063,7 @@ int novfs_a_writepages(struct address_sp + page_cache_get(pages[i]); + } + +- read_unlock_irq(&mapping->tree_lock); ++ spin_unlock_irq(&mapping->tree_lock); + + if (nr_pages) { + index = pages[nr_pages - 1]->index + 1; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Abstract-ocfs2_extent_tree-in-b.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Abstract-ocfs2_extent_tree-in-b.patch new file mode 100644 index 000000000..e3b004312 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Abstract-ocfs2_extent_tree-in-b.patch @@ -0,0 +1,1685 @@ +From: Tao Ma +Subject: [PATCH 03/16] ocfs2: Abstract ocfs2_extent_tree in b-tree operations. +Patch-mainline: 2.6.28? +References: FATE302067 + +In the old extent tree operation, we take the hypothesis that we +are using the ocfs2_extent_list in ocfs2_dinode as the tree root. +As xattr will also use ocfs2_extent_list to store large value +for a xattr entry, we refactor the tree operation so that xattr +can use it directly. + +The refactoring includes 4 steps: +1. Abstract set/get of last_eb_blk and update_clusters since they may + be stored in different location for dinode and xattr. +2. Add a new structure named ocfs2_extent_tree to indicate the + extent tree the operation will work on. +3. Remove all the use of fe_bh and di, use root_bh and root_el in + extent tree instead. So now all the fe_bh is replaced with + et->root_bh, el with root_el accordingly. +4. Make ocfs2_lock_allocators generic. Now it is limited to be only used + in file extend allocation. But the whole function is useful when we want + to store large EAs. + +Note: This patch doesn't touch ocfs2_commit_truncate() since it is not used +for anything other than truncate inode data btrees. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 508 +++++++++++++++++++++++++++++++++------------------ + fs/ocfs2/alloc.h | 23 ++- + fs/ocfs2/aops.c | 11 +- + fs/ocfs2/dir.c | 7 +- + fs/ocfs2/file.c | 104 ++--------- + fs/ocfs2/file.h | 4 - + fs/ocfs2/suballoc.c | 82 ++++++++ + fs/ocfs2/suballoc.h | 5 + + 8 files changed, 456 insertions(+), 288 deletions(-) + +Index: linux-2.6.26/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/alloc.c ++++ linux-2.6.26/fs/ocfs2/alloc.c +@@ -49,6 +49,143 @@ + + #include "buffer_head_io.h" + ++/* ++ * ocfs2_extent_tree and ocfs2_extent_tree_operations are used to abstract ++ * the b-tree operations in ocfs2. Now all the b-tree operations are not ++ * limited to ocfs2_dinode only. Any data which need to allocate clusters ++ * to store can use b-tree. And it only needs to implement its ocfs2_extent_tree ++ * and operation. ++ * ++ * ocfs2_extent_tree contains info for the root of the b-tree, it must have a ++ * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree ++ * functions. ++ * ocfs2_extent_tree_operations abstract the normal operations we do for ++ * the root of extent b-tree. ++ */ ++struct ocfs2_extent_tree; ++ ++struct ocfs2_extent_tree_operations { ++ void (*set_last_eb_blk) (struct ocfs2_extent_tree *et, u64 blkno); ++ u64 (*get_last_eb_blk) (struct ocfs2_extent_tree *et); ++ void (*update_clusters) (struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 new_clusters); ++ int (*sanity_check) (struct inode *inode, struct ocfs2_extent_tree *et); ++}; ++ ++struct ocfs2_extent_tree { ++ enum ocfs2_extent_tree_type type; ++ struct ocfs2_extent_tree_operations *eops; ++ struct buffer_head *root_bh; ++ struct ocfs2_extent_list *root_el; ++}; ++ ++static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, ++ u64 blkno) ++{ ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)et->root_bh->b_data; ++ ++ BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ di->i_last_eb_blk = cpu_to_le64(blkno); ++} ++ ++static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)et->root_bh->b_data; ++ ++ BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ return le64_to_cpu(di->i_last_eb_blk); ++} ++ ++static void ocfs2_dinode_update_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 clusters) ++{ ++ struct ocfs2_dinode *di = ++ (struct ocfs2_dinode *)et->root_bh->b_data; ++ ++ le32_add_cpu(&di->i_clusters, clusters); ++ spin_lock(&OCFS2_I(inode)->ip_lock); ++ OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters); ++ spin_unlock(&OCFS2_I(inode)->ip_lock); ++} ++ ++static int ocfs2_dinode_sanity_check(struct inode *inode, ++ struct ocfs2_extent_tree *et) ++{ ++ int ret = 0; ++ struct ocfs2_dinode *di; ++ ++ BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ ++ di = (struct ocfs2_dinode *)et->root_bh->b_data; ++ if (!OCFS2_IS_VALID_DINODE(di)) { ++ ret = -EIO; ++ ocfs2_error(inode->i_sb, ++ "Inode %llu has invalid path root", ++ (unsigned long long)OCFS2_I(inode)->ip_blkno); ++ } ++ ++ return ret; ++} ++ ++static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { ++ .set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, ++ .get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, ++ .update_clusters = ocfs2_dinode_update_clusters, ++ .sanity_check = ocfs2_dinode_sanity_check, ++}; ++ ++static struct ocfs2_extent_tree* ++ ocfs2_new_extent_tree(struct buffer_head *bh, ++ enum ocfs2_extent_tree_type et_type) ++{ ++ struct ocfs2_extent_tree *et; ++ ++ et = kzalloc(sizeof(*et), GFP_NOFS); ++ if (!et) ++ return NULL; ++ ++ et->type = et_type; ++ get_bh(bh); ++ et->root_bh = bh; ++ ++ /* current we only support dinode extent. */ ++ BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ if (et_type == OCFS2_DINODE_EXTENT) { ++ et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; ++ et->eops = &ocfs2_dinode_et_ops; ++ } ++ ++ return et; ++} ++ ++static void ocfs2_free_extent_tree(struct ocfs2_extent_tree *et) ++{ ++ if (et) { ++ brelse(et->root_bh); ++ kfree(et); ++ } ++} ++ ++static inline void ocfs2_set_last_eb_blk(struct ocfs2_extent_tree *et, ++ u64 new_last_eb_blk) ++{ ++ et->eops->set_last_eb_blk(et, new_last_eb_blk); ++} ++ ++static inline u64 ocfs2_get_last_eb_blk(struct ocfs2_extent_tree *et) ++{ ++ return et->eops->get_last_eb_blk(et); ++} ++ ++static inline void ocfs2_update_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 clusters) ++{ ++ et->eops->update_clusters(inode, et, clusters); ++} ++ + static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc); + static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt, + struct ocfs2_extent_block *eb); +@@ -205,17 +342,6 @@ static struct ocfs2_path *ocfs2_new_path + } + + /* +- * Allocate and initialize a new path based on a disk inode tree. +- */ +-static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh) +-{ +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +- struct ocfs2_extent_list *el = &di->id2.i_list; +- +- return ocfs2_new_path(di_bh, el); +-} +- +-/* + * Convenience function to journal all components in a path. + */ + static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle, +@@ -368,24 +494,33 @@ struct ocfs2_merge_ctxt { + */ + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, +- struct buffer_head *bh) ++ struct buffer_head *root_bh, ++ enum ocfs2_extent_tree_type type) + { + int retval; +- struct ocfs2_extent_list *el; ++ struct ocfs2_extent_list *el = NULL; + struct ocfs2_extent_block *eb; + struct buffer_head *eb_bh = NULL; +- struct ocfs2_dinode *fe = (struct ocfs2_dinode *)bh->b_data; ++ u64 last_eb_blk = 0; + + mlog_entry_void(); + +- if (!OCFS2_IS_VALID_DINODE(fe)) { +- OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe); +- retval = -EIO; +- goto bail; ++ if (type == OCFS2_DINODE_EXTENT) { ++ struct ocfs2_dinode *fe = ++ (struct ocfs2_dinode *)root_bh->b_data; ++ if (!OCFS2_IS_VALID_DINODE(fe)) { ++ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe); ++ retval = -EIO; ++ goto bail; ++ } ++ ++ if (fe->i_last_eb_blk) ++ last_eb_blk = le64_to_cpu(fe->i_last_eb_blk); ++ el = &fe->id2.i_list; + } + +- if (fe->i_last_eb_blk) { +- retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk), ++ if (last_eb_blk) { ++ retval = ocfs2_read_block(osb, last_eb_blk, + &eb_bh, OCFS2_BH_CACHED, inode); + if (retval < 0) { + mlog_errno(retval); +@@ -393,8 +528,7 @@ int ocfs2_num_free_extents(struct ocfs2_ + } + eb = (struct ocfs2_extent_block *) eb_bh->b_data; + el = &eb->h_list; +- } else +- el = &fe->id2.i_list; ++ } + + BUG_ON(el->l_tree_depth != 0); + +@@ -532,7 +666,7 @@ static inline u32 ocfs2_sum_rightmost_re + static int ocfs2_add_branch(struct ocfs2_super *osb, + handle_t *handle, + struct inode *inode, +- struct buffer_head *fe_bh, ++ struct ocfs2_extent_tree *et, + struct buffer_head *eb_bh, + struct buffer_head **last_eb_bh, + struct ocfs2_alloc_context *meta_ac) +@@ -541,7 +675,6 @@ static int ocfs2_add_branch(struct ocfs2 + u64 next_blkno, new_last_eb_blk; + struct buffer_head *bh; + struct buffer_head **new_eb_bhs = NULL; +- struct ocfs2_dinode *fe; + struct ocfs2_extent_block *eb; + struct ocfs2_extent_list *eb_el; + struct ocfs2_extent_list *el; +@@ -551,13 +684,11 @@ static int ocfs2_add_branch(struct ocfs2 + + BUG_ON(!last_eb_bh || !*last_eb_bh); + +- fe = (struct ocfs2_dinode *) fe_bh->b_data; +- + if (eb_bh) { + eb = (struct ocfs2_extent_block *) eb_bh->b_data; + el = &eb->h_list; + } else +- el = &fe->id2.i_list; ++ el = et->root_el; + + /* we never add a branch to a leaf. */ + BUG_ON(!el->l_tree_depth); +@@ -647,7 +778,7 @@ static int ocfs2_add_branch(struct ocfs2 + mlog_errno(status); + goto bail; + } +- status = ocfs2_journal_access(handle, inode, fe_bh, ++ status = ocfs2_journal_access(handle, inode, et->root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); +@@ -663,7 +794,7 @@ static int ocfs2_add_branch(struct ocfs2 + } + + /* Link the new branch into the rest of the tree (el will +- * either be on the fe, or the extent block passed in. */ ++ * either be on the root_bh, or the extent block passed in. */ + i = le16_to_cpu(el->l_next_free_rec); + el->l_recs[i].e_blkno = cpu_to_le64(next_blkno); + el->l_recs[i].e_cpos = cpu_to_le32(new_cpos); +@@ -672,7 +803,7 @@ static int ocfs2_add_branch(struct ocfs2 + + /* fe needs a new last extent block pointer, as does the + * next_leaf on the previously last-extent-block. */ +- fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk); ++ ocfs2_set_last_eb_blk(et, new_last_eb_blk); + + eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data; + eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk); +@@ -680,7 +811,7 @@ static int ocfs2_add_branch(struct ocfs2 + status = ocfs2_journal_dirty(handle, *last_eb_bh); + if (status < 0) + mlog_errno(status); +- status = ocfs2_journal_dirty(handle, fe_bh); ++ status = ocfs2_journal_dirty(handle, et->root_bh); + if (status < 0) + mlog_errno(status); + if (eb_bh) { +@@ -718,16 +849,15 @@ bail: + static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, + handle_t *handle, + struct inode *inode, +- struct buffer_head *fe_bh, ++ struct ocfs2_extent_tree *et, + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **ret_new_eb_bh) + { + int status, i; + u32 new_clusters; + struct buffer_head *new_eb_bh = NULL; +- struct ocfs2_dinode *fe; + struct ocfs2_extent_block *eb; +- struct ocfs2_extent_list *fe_el; ++ struct ocfs2_extent_list *root_el; + struct ocfs2_extent_list *eb_el; + + mlog_entry_void(); +@@ -747,8 +877,7 @@ static int ocfs2_shift_tree_depth(struct + } + + eb_el = &eb->h_list; +- fe = (struct ocfs2_dinode *) fe_bh->b_data; +- fe_el = &fe->id2.i_list; ++ root_el = et->root_el; + + status = ocfs2_journal_access(handle, inode, new_eb_bh, + OCFS2_JOURNAL_ACCESS_CREATE); +@@ -757,11 +886,11 @@ static int ocfs2_shift_tree_depth(struct + goto bail; + } + +- /* copy the fe data into the new extent block */ +- eb_el->l_tree_depth = fe_el->l_tree_depth; +- eb_el->l_next_free_rec = fe_el->l_next_free_rec; +- for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++) +- eb_el->l_recs[i] = fe_el->l_recs[i]; ++ /* copy the root extent list data into the new extent block */ ++ eb_el->l_tree_depth = root_el->l_tree_depth; ++ eb_el->l_next_free_rec = root_el->l_next_free_rec; ++ for (i = 0; i < le16_to_cpu(root_el->l_next_free_rec); i++) ++ eb_el->l_recs[i] = root_el->l_recs[i]; + + status = ocfs2_journal_dirty(handle, new_eb_bh); + if (status < 0) { +@@ -769,7 +898,7 @@ static int ocfs2_shift_tree_depth(struct + goto bail; + } + +- status = ocfs2_journal_access(handle, inode, fe_bh, ++ status = ocfs2_journal_access(handle, inode, et->root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); +@@ -778,21 +907,21 @@ static int ocfs2_shift_tree_depth(struct + + new_clusters = ocfs2_sum_rightmost_rec(eb_el); + +- /* update fe now */ +- le16_add_cpu(&fe_el->l_tree_depth, 1); +- fe_el->l_recs[0].e_cpos = 0; +- fe_el->l_recs[0].e_blkno = eb->h_blkno; +- fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters); +- for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++) +- memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec)); +- fe_el->l_next_free_rec = cpu_to_le16(1); ++ /* update root_bh now */ ++ le16_add_cpu(&root_el->l_tree_depth, 1); ++ root_el->l_recs[0].e_cpos = 0; ++ root_el->l_recs[0].e_blkno = eb->h_blkno; ++ root_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters); ++ for (i = 1; i < le16_to_cpu(root_el->l_next_free_rec); i++) ++ memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec)); ++ root_el->l_next_free_rec = cpu_to_le16(1); + + /* If this is our 1st tree depth shift, then last_eb_blk + * becomes the allocated extent block */ +- if (fe_el->l_tree_depth == cpu_to_le16(1)) +- fe->i_last_eb_blk = eb->h_blkno; ++ if (root_el->l_tree_depth == cpu_to_le16(1)) ++ ocfs2_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + +- status = ocfs2_journal_dirty(handle, fe_bh); ++ status = ocfs2_journal_dirty(handle, et->root_bh); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -818,22 +947,21 @@ bail: + * 1) a lowest extent block is found, then we pass it back in + * *lowest_eb_bh and return '0' + * +- * 2) the search fails to find anything, but the dinode has room. We ++ * 2) the search fails to find anything, but the root_el has room. We + * pass NULL back in *lowest_eb_bh, but still return '0' + * +- * 3) the search fails to find anything AND the dinode is full, in ++ * 3) the search fails to find anything AND the root_el is full, in + * which case we return > 0 + * + * return status < 0 indicates an error. + */ + static int ocfs2_find_branch_target(struct ocfs2_super *osb, + struct inode *inode, +- struct buffer_head *fe_bh, ++ struct ocfs2_extent_tree *et, + struct buffer_head **target_bh) + { + int status = 0, i; + u64 blkno; +- struct ocfs2_dinode *fe; + struct ocfs2_extent_block *eb; + struct ocfs2_extent_list *el; + struct buffer_head *bh = NULL; +@@ -843,8 +971,7 @@ static int ocfs2_find_branch_target(stru + + *target_bh = NULL; + +- fe = (struct ocfs2_dinode *) fe_bh->b_data; +- el = &fe->id2.i_list; ++ el = et->root_el; + + while(le16_to_cpu(el->l_tree_depth) > 1) { + if (le16_to_cpu(el->l_next_free_rec) == 0) { +@@ -896,8 +1023,8 @@ static int ocfs2_find_branch_target(stru + + /* If we didn't find one and the fe doesn't have any room, + * then return '1' */ +- if (!lowest_bh +- && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count)) ++ el = et->root_el; ++ if (!lowest_bh && (el->l_next_free_rec == el->l_count)) + status = 1; + + *target_bh = lowest_bh; +@@ -920,19 +1047,19 @@ bail: + * *last_eb_bh will be updated by ocfs2_add_branch(). + */ + static int ocfs2_grow_tree(struct inode *inode, handle_t *handle, +- struct buffer_head *di_bh, int *final_depth, ++ struct ocfs2_extent_tree *et, int *final_depth, + struct buffer_head **last_eb_bh, + struct ocfs2_alloc_context *meta_ac) + { + int ret, shift; +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +- int depth = le16_to_cpu(di->id2.i_list.l_tree_depth); ++ struct ocfs2_extent_list *el = et->root_el; ++ int depth = le16_to_cpu(el->l_tree_depth); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct buffer_head *bh = NULL; + + BUG_ON(meta_ac == NULL); + +- shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh); ++ shift = ocfs2_find_branch_target(osb, inode, et, &bh); + if (shift < 0) { + ret = shift; + mlog_errno(ret); +@@ -949,7 +1076,7 @@ static int ocfs2_grow_tree(struct inode + /* ocfs2_shift_tree_depth will return us a buffer with + * the new extent block (so we can pass that to + * ocfs2_add_branch). */ +- ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh, ++ ret = ocfs2_shift_tree_depth(osb, handle, inode, et, + meta_ac, &bh); + if (ret < 0) { + mlog_errno(ret); +@@ -976,7 +1103,7 @@ static int ocfs2_grow_tree(struct inode + /* call ocfs2_add_branch to add the final part of the tree with + * the new data. */ + mlog(0, "add branch. bh = %p\n", bh); +- ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh, ++ ret = ocfs2_add_branch(osb, handle, inode, et, bh, last_eb_bh, + meta_ac); + if (ret < 0) { + mlog_errno(ret); +@@ -2068,11 +2195,11 @@ static int ocfs2_rotate_subtree_left(str + struct ocfs2_path *right_path, + int subtree_index, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- int *deleted) ++ int *deleted, ++ struct ocfs2_extent_tree *et) + { + int ret, i, del_right_subtree = 0, right_has_empty = 0; +- struct buffer_head *root_bh, *di_bh = path_root_bh(right_path); +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ++ struct buffer_head *root_bh, *et_root_bh = path_root_bh(right_path); + struct ocfs2_extent_list *right_leaf_el, *left_leaf_el; + struct ocfs2_extent_block *eb; + +@@ -2124,7 +2251,7 @@ static int ocfs2_rotate_subtree_left(str + * We have to update i_last_eb_blk during the meta + * data delete. + */ +- ret = ocfs2_journal_access(handle, inode, di_bh, ++ ret = ocfs2_journal_access(handle, inode, et_root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -2199,7 +2326,7 @@ static int ocfs2_rotate_subtree_left(str + ocfs2_update_edge_lengths(inode, handle, left_path); + + eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; +- di->i_last_eb_blk = eb->h_blkno; ++ ocfs2_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + + /* + * Removal of the extent in the left leaf was skipped +@@ -2209,7 +2336,7 @@ static int ocfs2_rotate_subtree_left(str + if (right_has_empty) + ocfs2_remove_empty_extent(left_leaf_el); + +- ret = ocfs2_journal_dirty(handle, di_bh); ++ ret = ocfs2_journal_dirty(handle, et_root_bh); + if (ret) + mlog_errno(ret); + +@@ -2332,7 +2459,8 @@ static int __ocfs2_rotate_tree_left(stru + handle_t *handle, int orig_credits, + struct ocfs2_path *path, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- struct ocfs2_path **empty_extent_path) ++ struct ocfs2_path **empty_extent_path, ++ struct ocfs2_extent_tree *et) + { + int ret, subtree_root, deleted; + u32 right_cpos; +@@ -2405,7 +2533,7 @@ static int __ocfs2_rotate_tree_left(stru + + ret = ocfs2_rotate_subtree_left(inode, handle, left_path, + right_path, subtree_root, +- dealloc, &deleted); ++ dealloc, &deleted, et); + if (ret == -EAGAIN) { + /* + * The rotation has to temporarily stop due to +@@ -2448,29 +2576,20 @@ out: + } + + static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, +- struct ocfs2_path *path, +- struct ocfs2_cached_dealloc_ctxt *dealloc) ++ struct ocfs2_path *path, ++ struct ocfs2_cached_dealloc_ctxt *dealloc, ++ struct ocfs2_extent_tree *et) + { + int ret, subtree_index; + u32 cpos; + struct ocfs2_path *left_path = NULL; +- struct ocfs2_dinode *di; + struct ocfs2_extent_block *eb; + struct ocfs2_extent_list *el; + +- /* +- * XXX: This code assumes that the root is an inode, which is +- * true for now but may change as tree code gets generic. +- */ +- di = (struct ocfs2_dinode *)path_root_bh(path)->b_data; +- if (!OCFS2_IS_VALID_DINODE(di)) { +- ret = -EIO; +- ocfs2_error(inode->i_sb, +- "Inode %llu has invalid path root", +- (unsigned long long)OCFS2_I(inode)->ip_blkno); +- goto out; +- } + ++ ret = et->eops->sanity_check(inode, et); ++ if (ret) ++ goto out; + /* + * There's two ways we handle this depending on + * whether path is the only existing one. +@@ -2527,7 +2646,7 @@ static int ocfs2_remove_rightmost_path(s + ocfs2_update_edge_lengths(inode, handle, left_path); + + eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; +- di->i_last_eb_blk = eb->h_blkno; ++ ocfs2_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + } else { + /* + * 'path' is also the leftmost path which +@@ -2538,12 +2657,12 @@ static int ocfs2_remove_rightmost_path(s + */ + ocfs2_unlink_path(inode, handle, dealloc, path, 1); + +- el = &di->id2.i_list; ++ el = et->root_el; + el->l_tree_depth = 0; + el->l_next_free_rec = 0; + memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); + +- di->i_last_eb_blk = 0; ++ ocfs2_set_last_eb_blk(et, 0); + } + + ocfs2_journal_dirty(handle, path_root_bh(path)); +@@ -2571,7 +2690,8 @@ out: + */ + static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle, + struct ocfs2_path *path, +- struct ocfs2_cached_dealloc_ctxt *dealloc) ++ struct ocfs2_cached_dealloc_ctxt *dealloc, ++ struct ocfs2_extent_tree *et) + { + int ret, orig_credits = handle->h_buffer_credits; + struct ocfs2_path *tmp_path = NULL, *restart_path = NULL; +@@ -2585,7 +2705,7 @@ static int ocfs2_rotate_tree_left(struct + if (path->p_tree_depth == 0) { + rightmost_no_delete: + /* +- * In-inode extents. This is trivially handled, so do ++ * Inline extents. This is trivially handled, so do + * it up front. + */ + ret = ocfs2_rotate_rightmost_leaf_left(inode, handle, +@@ -2639,7 +2759,7 @@ rightmost_no_delete: + */ + + ret = ocfs2_remove_rightmost_path(inode, handle, path, +- dealloc); ++ dealloc, et); + if (ret) + mlog_errno(ret); + goto out; +@@ -2651,7 +2771,7 @@ rightmost_no_delete: + */ + try_rotate: + ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits, path, +- dealloc, &restart_path); ++ dealloc, &restart_path, et); + if (ret && ret != -EAGAIN) { + mlog_errno(ret); + goto out; +@@ -2663,7 +2783,7 @@ try_rotate: + + ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits, + tmp_path, dealloc, +- &restart_path); ++ &restart_path, et); + if (ret && ret != -EAGAIN) { + mlog_errno(ret); + goto out; +@@ -2949,6 +3069,7 @@ static int ocfs2_merge_rec_left(struct i + handle_t *handle, + struct ocfs2_extent_rec *split_rec, + struct ocfs2_cached_dealloc_ctxt *dealloc, ++ struct ocfs2_extent_tree *et, + int index) + { + int ret, i, subtree_index = 0, has_empty_extent = 0; +@@ -3069,7 +3190,8 @@ static int ocfs2_merge_rec_left(struct i + le16_to_cpu(el->l_next_free_rec) == 1) { + + ret = ocfs2_remove_rightmost_path(inode, handle, +- right_path, dealloc); ++ right_path, ++ dealloc, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -3096,7 +3218,8 @@ static int ocfs2_try_to_merge_extent(str + int split_index, + struct ocfs2_extent_rec *split_rec, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- struct ocfs2_merge_ctxt *ctxt) ++ struct ocfs2_merge_ctxt *ctxt, ++ struct ocfs2_extent_tree *et) + + { + int ret = 0; +@@ -3114,7 +3237,7 @@ static int ocfs2_try_to_merge_extent(str + * illegal. + */ + ret = ocfs2_rotate_tree_left(inode, handle, path, +- dealloc); ++ dealloc, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -3157,7 +3280,8 @@ static int ocfs2_try_to_merge_extent(str + BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0])); + + /* The merge left us with an empty extent, remove it. */ +- ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc); ++ ret = ocfs2_rotate_tree_left(inode, handle, path, ++ dealloc, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -3171,7 +3295,7 @@ static int ocfs2_try_to_merge_extent(str + */ + ret = ocfs2_merge_rec_left(inode, path, + handle, rec, +- dealloc, ++ dealloc, et, + split_index); + + if (ret) { +@@ -3180,7 +3304,7 @@ static int ocfs2_try_to_merge_extent(str + } + + ret = ocfs2_rotate_tree_left(inode, handle, path, +- dealloc); ++ dealloc, et); + /* + * Error from this last rotate is not critical, so + * print but don't bubble it up. +@@ -3200,7 +3324,7 @@ static int ocfs2_try_to_merge_extent(str + ret = ocfs2_merge_rec_left(inode, + path, + handle, split_rec, +- dealloc, ++ dealloc, et, + split_index); + if (ret) { + mlog_errno(ret); +@@ -3223,7 +3347,7 @@ static int ocfs2_try_to_merge_extent(str + * our leaf. Try to rotate it away. + */ + ret = ocfs2_rotate_tree_left(inode, handle, path, +- dealloc); ++ dealloc, et); + if (ret) + mlog_errno(ret); + ret = 0; +@@ -3357,16 +3481,6 @@ rotate: + ocfs2_rotate_leaf(el, insert_rec); + } + +-static inline void ocfs2_update_dinode_clusters(struct inode *inode, +- struct ocfs2_dinode *di, +- u32 clusters) +-{ +- le32_add_cpu(&di->i_clusters, clusters); +- spin_lock(&OCFS2_I(inode)->ip_lock); +- OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters); +- spin_unlock(&OCFS2_I(inode)->ip_lock); +-} +- + static void ocfs2_adjust_rightmost_records(struct inode *inode, + handle_t *handle, + struct ocfs2_path *path, +@@ -3568,8 +3682,8 @@ static void ocfs2_split_record(struct in + } + + /* +- * This function only does inserts on an allocation b-tree. For dinode +- * lists, ocfs2_insert_at_leaf() is called directly. ++ * This function only does inserts on an allocation b-tree. For tree ++ * depth = 0, ocfs2_insert_at_leaf() is called directly. + * + * right_path is the path we want to do the actual insert + * in. left_path should only be passed in if we need to update that +@@ -3666,7 +3780,7 @@ out: + + static int ocfs2_do_insert_extent(struct inode *inode, + handle_t *handle, +- struct buffer_head *di_bh, ++ struct ocfs2_extent_tree *et, + struct ocfs2_extent_rec *insert_rec, + struct ocfs2_insert_type *type) + { +@@ -3674,13 +3788,11 @@ static int ocfs2_do_insert_extent(struct + u32 cpos; + struct ocfs2_path *right_path = NULL; + struct ocfs2_path *left_path = NULL; +- struct ocfs2_dinode *di; + struct ocfs2_extent_list *el; + +- di = (struct ocfs2_dinode *) di_bh->b_data; +- el = &di->id2.i_list; ++ el = et->root_el; + +- ret = ocfs2_journal_access(handle, inode, di_bh, ++ ret = ocfs2_journal_access(handle, inode, et->root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -3692,7 +3804,7 @@ static int ocfs2_do_insert_extent(struct + goto out_update_clusters; + } + +- right_path = ocfs2_new_inode_path(di_bh); ++ right_path = ocfs2_new_path(et->root_bh, et->root_el); + if (!right_path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -3742,7 +3854,7 @@ static int ocfs2_do_insert_extent(struct + * ocfs2_rotate_tree_right() might have extended the + * transaction without re-journaling our tree root. + */ +- ret = ocfs2_journal_access(handle, inode, di_bh, ++ ret = ocfs2_journal_access(handle, inode, et->root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -3767,10 +3879,10 @@ static int ocfs2_do_insert_extent(struct + + out_update_clusters: + if (type->ins_split == SPLIT_NONE) +- ocfs2_update_dinode_clusters(inode, di, +- le16_to_cpu(insert_rec->e_leaf_clusters)); ++ ocfs2_update_clusters(inode, et, ++ le16_to_cpu(insert_rec->e_leaf_clusters)); + +- ret = ocfs2_journal_dirty(handle, di_bh); ++ ret = ocfs2_journal_dirty(handle, et->root_bh); + if (ret) + mlog_errno(ret); + +@@ -3924,8 +4036,8 @@ static void ocfs2_figure_contig_type(str + * ocfs2_figure_appending_type() will figure out whether we'll have to + * insert at the tail of the rightmost leaf. + * +- * This should also work against the dinode list for tree's with 0 +- * depth. If we consider the dinode list to be the rightmost leaf node ++ * This should also work against the root extent list for tree's with 0 ++ * depth. If we consider the root extent list to be the rightmost leaf node + * then the logic here makes sense. + */ + static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert, +@@ -3976,14 +4088,13 @@ set_tail_append: + * structure. + */ + static int ocfs2_figure_insert_type(struct inode *inode, +- struct buffer_head *di_bh, ++ struct ocfs2_extent_tree *et, + struct buffer_head **last_eb_bh, + struct ocfs2_extent_rec *insert_rec, + int *free_records, + struct ocfs2_insert_type *insert) + { + int ret; +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_extent_block *eb; + struct ocfs2_extent_list *el; + struct ocfs2_path *path = NULL; +@@ -3991,7 +4102,7 @@ static int ocfs2_figure_insert_type(stru + + insert->ins_split = SPLIT_NONE; + +- el = &di->id2.i_list; ++ el = et->root_el; + insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth); + + if (el->l_tree_depth) { +@@ -4002,7 +4113,7 @@ static int ocfs2_figure_insert_type(stru + * may want it later. + */ + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- le64_to_cpu(di->i_last_eb_blk), &bh, ++ ocfs2_get_last_eb_blk(et), &bh, + OCFS2_BH_CACHED, inode); + if (ret) { + mlog_exit(ret); +@@ -4029,7 +4140,7 @@ static int ocfs2_figure_insert_type(stru + return 0; + } + +- path = ocfs2_new_inode_path(di_bh); ++ path = ocfs2_new_path(et->root_bh, et->root_el); + if (!path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4079,7 +4190,8 @@ static int ocfs2_figure_insert_type(stru + * the case that we're doing a tail append, so maybe we can + * take advantage of that information somehow. + */ +- if (le64_to_cpu(di->i_last_eb_blk) == path_leaf_bh(path)->b_blocknr) { ++ if (ocfs2_get_last_eb_blk(et) == ++ path_leaf_bh(path)->b_blocknr) { + /* + * Ok, ocfs2_find_path() returned us the rightmost + * tree path. This might be an appending insert. There are +@@ -4109,21 +4221,30 @@ out: + int ocfs2_insert_extent(struct ocfs2_super *osb, + handle_t *handle, + struct inode *inode, +- struct buffer_head *fe_bh, ++ struct buffer_head *root_bh, + u32 cpos, + u64 start_blk, + u32 new_clusters, + u8 flags, +- struct ocfs2_alloc_context *meta_ac) ++ struct ocfs2_alloc_context *meta_ac, ++ enum ocfs2_extent_tree_type et_type) + { + int status; + int uninitialized_var(free_records); + struct buffer_head *last_eb_bh = NULL; + struct ocfs2_insert_type insert = {0, }; + struct ocfs2_extent_rec rec; ++ struct ocfs2_extent_tree *et = NULL; + + BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + ++ et = ocfs2_new_extent_tree(root_bh, et_type); ++ if (!et) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto bail; ++ } ++ + mlog(0, "add %u clusters at position %u to inode %llu\n", + new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); + +@@ -4141,7 +4262,7 @@ int ocfs2_insert_extent(struct ocfs2_sup + rec.e_leaf_clusters = cpu_to_le16(new_clusters); + rec.e_flags = flags; + +- status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec, ++ status = ocfs2_figure_insert_type(inode, et, &last_eb_bh, &rec, + &free_records, &insert); + if (status < 0) { + mlog_errno(status); +@@ -4155,7 +4276,7 @@ int ocfs2_insert_extent(struct ocfs2_sup + free_records, insert.ins_tree_depth); + + if (insert.ins_contig == CONTIG_NONE && free_records == 0) { +- status = ocfs2_grow_tree(inode, handle, fe_bh, ++ status = ocfs2_grow_tree(inode, handle, et, + &insert.ins_tree_depth, &last_eb_bh, + meta_ac); + if (status) { +@@ -4165,16 +4286,18 @@ int ocfs2_insert_extent(struct ocfs2_sup + } + + /* Finally, we can add clusters. This might rotate the tree for us. */ +- status = ocfs2_do_insert_extent(inode, handle, fe_bh, &rec, &insert); ++ status = ocfs2_do_insert_extent(inode, handle, et, &rec, &insert); + if (status < 0) + mlog_errno(status); +- else ++ else if (et->type == OCFS2_DINODE_EXTENT) + ocfs2_extent_map_insert_rec(inode, &rec); + + bail: + if (last_eb_bh) + brelse(last_eb_bh); + ++ if (et) ++ ocfs2_free_extent_tree(et); + mlog_exit(status); + return status; + } +@@ -4202,7 +4325,7 @@ static void ocfs2_make_right_split_rec(s + static int ocfs2_split_and_insert(struct inode *inode, + handle_t *handle, + struct ocfs2_path *path, +- struct buffer_head *di_bh, ++ struct ocfs2_extent_tree *et, + struct buffer_head **last_eb_bh, + int split_index, + struct ocfs2_extent_rec *orig_split_rec, +@@ -4216,7 +4339,6 @@ static int ocfs2_split_and_insert(struct + struct ocfs2_extent_rec split_rec = *orig_split_rec; + struct ocfs2_insert_type insert; + struct ocfs2_extent_block *eb; +- struct ocfs2_dinode *di; + + leftright: + /* +@@ -4225,8 +4347,7 @@ leftright: + */ + rec = path_leaf_el(path)->l_recs[split_index]; + +- di = (struct ocfs2_dinode *)di_bh->b_data; +- rightmost_el = &di->id2.i_list; ++ rightmost_el = et->root_el; + + depth = le16_to_cpu(rightmost_el->l_tree_depth); + if (depth) { +@@ -4237,8 +4358,8 @@ leftright: + + if (le16_to_cpu(rightmost_el->l_next_free_rec) == + le16_to_cpu(rightmost_el->l_count)) { +- ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh, +- meta_ac); ++ ret = ocfs2_grow_tree(inode, handle, et, ++ &depth, last_eb_bh, meta_ac); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4275,8 +4396,7 @@ leftright: + do_leftright = 1; + } + +- ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, +- &insert); ++ ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4318,8 +4438,9 @@ out: + * of the tree is required. All other cases will degrade into a less + * optimal tree layout. + * +- * last_eb_bh should be the rightmost leaf block for any inode with a +- * btree. Since a split may grow the tree or a merge might shrink it, the caller cannot trust the contents of that buffer after this call. ++ * last_eb_bh should be the rightmost leaf block for any extent ++ * btree. Since a split may grow the tree or a merge might shrink it, ++ * the caller cannot trust the contents of that buffer after this call. + * + * This code is optimized for readability - several passes might be + * made over certain portions of the tree. All of those blocks will +@@ -4327,7 +4448,7 @@ out: + * extra overhead is not expressed in terms of disk reads. + */ + static int __ocfs2_mark_extent_written(struct inode *inode, +- struct buffer_head *di_bh, ++ struct ocfs2_extent_tree *et, + handle_t *handle, + struct ocfs2_path *path, + int split_index, +@@ -4367,10 +4488,9 @@ static int __ocfs2_mark_extent_written(s + */ + if (path->p_tree_depth) { + struct ocfs2_extent_block *eb; +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- le64_to_cpu(di->i_last_eb_blk), ++ ocfs2_get_last_eb_blk(et), + &last_eb_bh, OCFS2_BH_CACHED, inode); + if (ret) { + mlog_exit(ret); +@@ -4404,7 +4524,7 @@ static int __ocfs2_mark_extent_written(s + if (ctxt.c_split_covers_rec) + el->l_recs[split_index] = *split_rec; + else +- ret = ocfs2_split_and_insert(inode, handle, path, di_bh, ++ ret = ocfs2_split_and_insert(inode, handle, path, et, + &last_eb_bh, split_index, + split_rec, meta_ac); + if (ret) +@@ -4412,7 +4532,7 @@ static int __ocfs2_mark_extent_written(s + } else { + ret = ocfs2_try_to_merge_extent(inode, handle, path, + split_index, split_rec, +- dealloc, &ctxt); ++ dealloc, &ctxt, et); + if (ret) + mlog_errno(ret); + } +@@ -4430,16 +4550,18 @@ out: + * + * The caller is responsible for passing down meta_ac if we'll need it. + */ +-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh, ++int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + handle_t *handle, u32 cpos, u32 len, u32 phys, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc) ++ struct ocfs2_cached_dealloc_ctxt *dealloc, ++ enum ocfs2_extent_tree_type et_type) + { + int ret, index; + u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); + struct ocfs2_extent_rec split_rec; + struct ocfs2_path *left_path = NULL; + struct ocfs2_extent_list *el; ++ struct ocfs2_extent_tree *et = NULL; + + mlog(0, "Inode %lu cpos %u, len %u, phys %u (%llu)\n", + inode->i_ino, cpos, len, phys, (unsigned long long)start_blkno); +@@ -4453,13 +4575,21 @@ int ocfs2_mark_extent_written(struct ino + goto out; + } + ++ et = ocfs2_new_extent_tree(root_bh, et_type); ++ if (!et) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ + /* + * XXX: This should be fixed up so that we just re-insert the + * next extent records. + */ +- ocfs2_extent_map_trunc(inode, 0); ++ if (et_type == OCFS2_DINODE_EXTENT) ++ ocfs2_extent_map_trunc(inode, 0); + +- left_path = ocfs2_new_inode_path(di_bh); ++ left_path = ocfs2_new_path(et->root_bh, et->root_el); + if (!left_path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4490,23 +4620,25 @@ int ocfs2_mark_extent_written(struct ino + split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags; + split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN; + +- ret = __ocfs2_mark_extent_written(inode, di_bh, handle, left_path, +- index, &split_rec, meta_ac, dealloc); ++ ret = __ocfs2_mark_extent_written(inode, et, handle, left_path, ++ index, &split_rec, meta_ac, ++ dealloc); + if (ret) + mlog_errno(ret); + + out: + ocfs2_free_path(left_path); ++ if (et) ++ ocfs2_free_extent_tree(et); + return ret; + } + +-static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, ++static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et, + handle_t *handle, struct ocfs2_path *path, + int index, u32 new_range, + struct ocfs2_alloc_context *meta_ac) + { + int ret, depth, credits = handle->h_buffer_credits; +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct buffer_head *last_eb_bh = NULL; + struct ocfs2_extent_block *eb; + struct ocfs2_extent_list *rightmost_el, *el; +@@ -4524,7 +4656,7 @@ static int ocfs2_split_tree(struct inode + depth = path->p_tree_depth; + if (depth > 0) { + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- le64_to_cpu(di->i_last_eb_blk), ++ ocfs2_get_last_eb_blk(et), + &last_eb_bh, OCFS2_BH_CACHED, inode); + if (ret < 0) { + mlog_errno(ret); +@@ -4537,7 +4669,7 @@ static int ocfs2_split_tree(struct inode + rightmost_el = path_leaf_el(path); + + credits += path->p_tree_depth + +- ocfs2_extend_meta_needed(&di->id2.i_list); ++ ocfs2_extend_meta_needed(et->root_el); + ret = ocfs2_extend_trans(handle, credits); + if (ret) { + mlog_errno(ret); +@@ -4546,7 +4678,7 @@ static int ocfs2_split_tree(struct inode + + if (le16_to_cpu(rightmost_el->l_next_free_rec) == + le16_to_cpu(rightmost_el->l_count)) { +- ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh, ++ ret = ocfs2_grow_tree(inode, handle, et, &depth, &last_eb_bh, + meta_ac); + if (ret) { + mlog_errno(ret); +@@ -4560,7 +4692,7 @@ static int ocfs2_split_tree(struct inode + insert.ins_split = SPLIT_RIGHT; + insert.ins_tree_depth = depth; + +- ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert); ++ ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert); + if (ret) + mlog_errno(ret); + +@@ -4572,7 +4704,8 @@ out: + static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle, + struct ocfs2_path *path, int index, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- u32 cpos, u32 len) ++ u32 cpos, u32 len, ++ struct ocfs2_extent_tree *et) + { + int ret; + u32 left_cpos, rec_range, trunc_range; +@@ -4584,7 +4717,7 @@ static int ocfs2_truncate_rec(struct ino + struct ocfs2_extent_block *eb; + + if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) { +- ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc); ++ ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4715,7 +4848,7 @@ static int ocfs2_truncate_rec(struct ino + + ocfs2_journal_dirty(handle, path_leaf_bh(path)); + +- ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc); ++ ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4726,20 +4859,29 @@ out: + return ret; + } + +-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh, ++int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc) ++ struct ocfs2_cached_dealloc_ctxt *dealloc, ++ enum ocfs2_extent_tree_type et_type) + { + int ret, index; + u32 rec_range, trunc_range; + struct ocfs2_extent_rec *rec; + struct ocfs2_extent_list *el; +- struct ocfs2_path *path; ++ struct ocfs2_path *path = NULL; ++ struct ocfs2_extent_tree *et = NULL; ++ ++ et = ocfs2_new_extent_tree(root_bh, et_type); ++ if (!et) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } + + ocfs2_extent_map_trunc(inode, 0); + +- path = ocfs2_new_inode_path(di_bh); ++ path = ocfs2_new_path(et->root_bh, et->root_el); + if (!path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4792,13 +4934,13 @@ int ocfs2_remove_extent(struct inode *in + + if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) { + ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, +- cpos, len); ++ cpos, len, et); + if (ret) { + mlog_errno(ret); + goto out; + } + } else { +- ret = ocfs2_split_tree(inode, di_bh, handle, path, index, ++ ret = ocfs2_split_tree(inode, et, handle, path, index, + trunc_range, meta_ac); + if (ret) { + mlog_errno(ret); +@@ -4847,7 +4989,7 @@ int ocfs2_remove_extent(struct inode *in + } + + ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, +- cpos, len); ++ cpos, len, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4856,6 +4998,8 @@ int ocfs2_remove_extent(struct inode *in + + out: + ocfs2_free_path(path); ++ if (et) ++ ocfs2_free_extent_tree(et); + return ret; + } + +@@ -6364,7 +6508,8 @@ int ocfs2_convert_inline_data_to_extents + * the in-inode data from our pages. + */ + ret = ocfs2_insert_extent(osb, handle, inode, di_bh, +- 0, block, 1, 0, NULL); ++ 0, block, 1, 0, ++ NULL, OCFS2_DINODE_EXTENT); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -6406,13 +6551,14 @@ int ocfs2_commit_truncate(struct ocfs2_s + handle_t *handle = NULL; + struct inode *tl_inode = osb->osb_tl_inode; + struct ocfs2_path *path = NULL; ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data; + + mlog_entry_void(); + + new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb, + i_size_read(inode)); + +- path = ocfs2_new_inode_path(fe_bh); ++ path = ocfs2_new_path(fe_bh, &di->id2.i_list); + if (!path) { + status = -ENOMEM; + mlog_errno(status); +Index: linux-2.6.26/fs/ocfs2/alloc.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/alloc.h ++++ linux-2.6.26/fs/ocfs2/alloc.h +@@ -26,28 +26,37 @@ + #ifndef OCFS2_ALLOC_H + #define OCFS2_ALLOC_H + ++enum ocfs2_extent_tree_type { ++ OCFS2_DINODE_EXTENT = 0, ++}; ++ + struct ocfs2_alloc_context; + int ocfs2_insert_extent(struct ocfs2_super *osb, + handle_t *handle, + struct inode *inode, +- struct buffer_head *fe_bh, ++ struct buffer_head *root_bh, + u32 cpos, + u64 start_blk, + u32 new_clusters, + u8 flags, +- struct ocfs2_alloc_context *meta_ac); ++ struct ocfs2_alloc_context *meta_ac, ++ enum ocfs2_extent_tree_type et_type); + struct ocfs2_cached_dealloc_ctxt; +-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh, ++int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + handle_t *handle, u32 cpos, u32 len, u32 phys, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc); +-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh, ++ struct ocfs2_cached_dealloc_ctxt *dealloc, ++ enum ocfs2_extent_tree_type et_type); ++int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc); ++ struct ocfs2_cached_dealloc_ctxt *dealloc, ++ enum ocfs2_extent_tree_type et_type); + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, +- struct buffer_head *bh); ++ struct buffer_head *root_bh, ++ enum ocfs2_extent_tree_type et_type); ++ + /* + * how many new metadata chunks would an allocation need at maximum? + * +Index: linux-2.6.26/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/aops.c ++++ linux-2.6.26/fs/ocfs2/aops.c +@@ -1278,7 +1278,8 @@ static int ocfs2_write_cluster(struct ad + } else if (unwritten) { + ret = ocfs2_mark_extent_written(inode, wc->w_di_bh, + wc->w_handle, cpos, 1, phys, +- meta_ac, &wc->w_dealloc); ++ meta_ac, &wc->w_dealloc, ++ OCFS2_DINODE_EXTENT); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1712,7 +1713,13 @@ int ocfs2_write_begin_nolock(struct addr + * ocfs2_lock_allocators(). It greatly over-estimates + * the work to be done. + */ +- ret = ocfs2_lock_allocators(inode, wc->w_di_bh, ++ mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u," ++ " clusters_to_add = %u, extents_to_split = %u\n", ++ (unsigned long long)OCFS2_I(inode)->ip_blkno, ++ (long long)i_size_read(inode), le32_to_cpu(di->i_clusters), ++ clusters_to_alloc, extents_to_split); ++ ++ ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list, + clusters_to_alloc, extents_to_split, + &data_ac, &meta_ac); + if (ret) { +Index: linux-2.6.26/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/dir.c ++++ linux-2.6.26/fs/ocfs2/dir.c +@@ -1306,7 +1306,7 @@ static int ocfs2_expand_inline_dir(struc + * related blocks have been journaled already. + */ + ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0, +- NULL); ++ NULL, OCFS2_DINODE_EXTENT); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1338,7 +1338,7 @@ static int ocfs2_expand_inline_dir(struc + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + + ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno, +- len, 0, NULL); ++ len, 0, NULL, OCFS2_DINODE_EXTENT); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1481,7 +1481,8 @@ static int ocfs2_extend_dir(struct ocfs2 + if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) { + spin_unlock(&OCFS2_I(dir)->ip_lock); + num_free_extents = ocfs2_num_free_extents(osb, dir, +- parent_fe_bh); ++ parent_fe_bh, ++ OCFS2_DINODE_EXTENT); + if (num_free_extents < 0) { + status = num_free_extents; + mlog_errno(status); +Index: linux-2.6.26/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/file.c ++++ linux-2.6.26/fs/ocfs2/file.c +@@ -521,7 +521,8 @@ int ocfs2_do_extend_allocation(struct oc + if (mark_unwritten) + flags = OCFS2_EXT_UNWRITTEN; + +- free_extents = ocfs2_num_free_extents(osb, inode, fe_bh); ++ free_extents = ocfs2_num_free_extents(osb, inode, fe_bh, ++ OCFS2_DINODE_EXTENT); + if (free_extents < 0) { + status = free_extents; + mlog_errno(status); +@@ -570,7 +571,7 @@ int ocfs2_do_extend_allocation(struct oc + num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); + status = ocfs2_insert_extent(osb, handle, inode, fe_bh, + *logical_offset, block, num_bits, +- flags, meta_ac); ++ flags, meta_ac, OCFS2_DINODE_EXTENT); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -599,92 +600,6 @@ leave: + return status; + } + +-/* +- * For a given allocation, determine which allocators will need to be +- * accessed, and lock them, reserving the appropriate number of bits. +- * +- * Sparse file systems call this from ocfs2_write_begin_nolock() +- * and ocfs2_allocate_unwritten_extents(). +- * +- * File systems which don't support holes call this from +- * ocfs2_extend_allocation(). +- */ +-int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *di_bh, +- u32 clusters_to_add, u32 extents_to_split, +- struct ocfs2_alloc_context **data_ac, +- struct ocfs2_alloc_context **meta_ac) +-{ +- int ret = 0, num_free_extents; +- unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +- +- *meta_ac = NULL; +- if (data_ac) +- *data_ac = NULL; +- +- BUG_ON(clusters_to_add != 0 && data_ac == NULL); +- +- mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, " +- "clusters_to_add = %u, extents_to_split = %u\n", +- (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode), +- le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split); +- +- num_free_extents = ocfs2_num_free_extents(osb, inode, di_bh); +- if (num_free_extents < 0) { +- ret = num_free_extents; +- mlog_errno(ret); +- goto out; +- } +- +- /* +- * Sparse allocation file systems need to be more conservative +- * with reserving room for expansion - the actual allocation +- * happens while we've got a journal handle open so re-taking +- * a cluster lock (because we ran out of room for another +- * extent) will violate ordering rules. +- * +- * Most of the time we'll only be seeing this 1 cluster at a time +- * anyway. +- * +- * Always lock for any unwritten extents - we might want to +- * add blocks during a split. +- */ +- if (!num_free_extents || +- (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) { +- ret = ocfs2_reserve_new_metadata(osb, &di->id2.i_list, meta_ac); +- if (ret < 0) { +- if (ret != -ENOSPC) +- mlog_errno(ret); +- goto out; +- } +- } +- +- if (clusters_to_add == 0) +- goto out; +- +- ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac); +- if (ret < 0) { +- if (ret != -ENOSPC) +- mlog_errno(ret); +- goto out; +- } +- +-out: +- if (ret) { +- if (*meta_ac) { +- ocfs2_free_alloc_context(*meta_ac); +- *meta_ac = NULL; +- } +- +- /* +- * We cannot have an error and a non null *data_ac. +- */ +- } +- +- return ret; +-} +- + static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, + u32 clusters_to_add, int mark_unwritten) + { +@@ -725,7 +640,13 @@ static int __ocfs2_extend_allocation(str + restart_all: + BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters); + +- status = ocfs2_lock_allocators(inode, bh, clusters_to_add, 0, &data_ac, ++ mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, " ++ "clusters_to_add = %u\n", ++ (unsigned long long)OCFS2_I(inode)->ip_blkno, ++ (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters), ++ clusters_to_add); ++ status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list, ++ clusters_to_add, 0, &data_ac, + &meta_ac); + if (status) { + mlog_errno(status); +@@ -1397,7 +1318,8 @@ static int __ocfs2_remove_inode_range(st + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + +- ret = ocfs2_lock_allocators(inode, di_bh, 0, 1, NULL, &meta_ac); ++ ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list, ++ 0, 1, NULL, &meta_ac); + if (ret) { + mlog_errno(ret); + return ret; +@@ -1428,7 +1350,7 @@ static int __ocfs2_remove_inode_range(st + } + + ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac, +- dealloc); ++ dealloc, OCFS2_DINODE_EXTENT); + if (ret) { + mlog_errno(ret); + goto out_commit; +Index: linux-2.6.26/fs/ocfs2/file.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/file.h ++++ linux-2.6.26/fs/ocfs2/file.h +@@ -55,10 +55,6 @@ int ocfs2_do_extend_allocation(struct oc + enum ocfs2_alloc_restarted *reason_ret); + int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, + u64 zero_to); +-int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *fe, +- u32 clusters_to_add, u32 extents_to_split, +- struct ocfs2_alloc_context **data_ac, +- struct ocfs2_alloc_context **meta_ac); + int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); + int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat); +Index: linux-2.6.26/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.26/fs/ocfs2/suballoc.c +@@ -1891,3 +1891,85 @@ static inline void ocfs2_debug_suballoc_ + (unsigned long long)fe->id2.i_chain.cl_recs[i].c_blkno); + } + } ++ ++/* ++ * For a given allocation, determine which allocators will need to be ++ * accessed, and lock them, reserving the appropriate number of bits. ++ * ++ * Sparse file systems call this from ocfs2_write_begin_nolock() ++ * and ocfs2_allocate_unwritten_extents(). ++ * ++ * File systems which don't support holes call this from ++ * ocfs2_extend_allocation(). ++ */ ++int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, ++ struct ocfs2_extent_list *root_el, ++ u32 clusters_to_add, u32 extents_to_split, ++ struct ocfs2_alloc_context **data_ac, ++ struct ocfs2_alloc_context **meta_ac) ++{ ++ int ret = 0, num_free_extents; ++ unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ *meta_ac = NULL; ++ if (data_ac) ++ *data_ac = NULL; ++ ++ BUG_ON(clusters_to_add != 0 && data_ac == NULL); ++ ++ num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh, ++ OCFS2_DINODE_EXTENT); ++ if (num_free_extents < 0) { ++ ret = num_free_extents; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ /* ++ * Sparse allocation file systems need to be more conservative ++ * with reserving room for expansion - the actual allocation ++ * happens while we've got a journal handle open so re-taking ++ * a cluster lock (because we ran out of room for another ++ * extent) will violate ordering rules. ++ * ++ * Most of the time we'll only be seeing this 1 cluster at a time ++ * anyway. ++ * ++ * Always lock for any unwritten extents - we might want to ++ * add blocks during a split. ++ */ ++ if (!num_free_extents || ++ (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) { ++ ret = ocfs2_reserve_new_metadata(osb, root_el, meta_ac); ++ if (ret < 0) { ++ if (ret != -ENOSPC) ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ if (clusters_to_add == 0) ++ goto out; ++ ++ ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac); ++ if (ret < 0) { ++ if (ret != -ENOSPC) ++ mlog_errno(ret); ++ goto out; ++ } ++ ++out: ++ if (ret) { ++ if (*meta_ac) { ++ ocfs2_free_alloc_context(*meta_ac); ++ *meta_ac = NULL; ++ } ++ ++ /* ++ * We cannot have an error and a non null *data_ac. ++ */ ++ } ++ ++ return ret; ++} +Index: linux-2.6.26/fs/ocfs2/suballoc.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.h ++++ linux-2.6.26/fs/ocfs2/suballoc.h +@@ -161,4 +161,9 @@ u64 ocfs2_which_cluster_group(struct ino + int ocfs2_check_group_descriptor(struct super_block *sb, + struct ocfs2_dinode *di, + struct ocfs2_group_desc *gd); ++int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, ++ struct ocfs2_extent_list *root_el, ++ u32 clusters_to_add, u32 extents_to_split, ++ struct ocfs2_alloc_context **data_ac, ++ struct ocfs2_alloc_context **meta_ac); + #endif /* _CHAINALLOC_H_ */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-an-insertion-check-to-ocfs2_extent_tree_o.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-an-insertion-check-to-ocfs2_extent_tree_o.patch new file mode 100644 index 000000000..d6588102d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-an-insertion-check-to-ocfs2_extent_tree_o.patch @@ -0,0 +1,163 @@ +From: Joel Becker +Subject: ocfs2: Add an insertion check to ocfs2_extent_tree_operations. +Patch-mainline: 2.6.28? +References: FATE302067 + +A couple places check an extent_tree for a valid inode. We move that +out to add an eo_insert_check() operation. It can be called from +ocfs2_insert_extent() and elsewhere. + +We also have the wrapper calls ocfs2_et_insert_check() and +ocfs2_et_sanity_check() ignore NULL ops. That way we don't have to +provide useless operations for xattr types. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 69 ++++++++++++++++++++++++++++++++++------------------- + 1 files changed, 44 insertions(+), 25 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 243bacf..2083c2c 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -71,6 +71,9 @@ struct ocfs2_extent_tree_operations { + void (*eo_update_clusters)(struct inode *inode, + struct ocfs2_extent_tree *et, + u32 new_clusters); ++ int (*eo_insert_check)(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ struct ocfs2_extent_rec *rec); + int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et); + + /* These are internal to ocfs2_extent_tree and don't have +@@ -125,6 +128,25 @@ static void ocfs2_dinode_update_clusters(struct inode *inode, + spin_unlock(&OCFS2_I(inode)->ip_lock); + } + ++static int ocfs2_dinode_insert_check(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ struct ocfs2_extent_rec *rec) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); ++ mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) && ++ (OCFS2_I(inode)->ip_clusters != rec->e_cpos), ++ "Device %s, asking for sparse allocation: inode %llu, " ++ "cpos %u, clusters %u\n", ++ osb->dev_str, ++ (unsigned long long)OCFS2_I(inode)->ip_blkno, ++ rec->e_cpos, ++ OCFS2_I(inode)->ip_clusters); ++ ++ return 0; ++} ++ + static int ocfs2_dinode_sanity_check(struct inode *inode, + struct ocfs2_extent_tree *et) + { +@@ -148,6 +170,7 @@ static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { + .eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, + .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, + .eo_update_clusters = ocfs2_dinode_update_clusters, ++ .eo_insert_check = ocfs2_dinode_insert_check, + .eo_sanity_check = ocfs2_dinode_sanity_check, + .eo_fill_root_el = ocfs2_dinode_fill_root_el, + }; +@@ -186,17 +209,10 @@ static void ocfs2_xattr_value_update_clusters(struct inode *inode, + le32_add_cpu(&xv->xr_clusters, clusters); + } + +-static int ocfs2_xattr_value_sanity_check(struct inode *inode, +- struct ocfs2_extent_tree *et) +-{ +- return 0; +-} +- + static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = { + .eo_set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, + .eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, + .eo_update_clusters = ocfs2_xattr_value_update_clusters, +- .eo_sanity_check = ocfs2_xattr_value_sanity_check, + .eo_fill_root_el = ocfs2_xattr_value_fill_root_el, + }; + +@@ -241,17 +257,10 @@ static void ocfs2_xattr_tree_update_clusters(struct inode *inode, + le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters); + } + +-static int ocfs2_xattr_tree_sanity_check(struct inode *inode, +- struct ocfs2_extent_tree *et) +-{ +- return 0; +-} +- + static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .eo_set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk, + .eo_get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, + .eo_update_clusters = ocfs2_xattr_tree_update_clusters, +- .eo_sanity_check = ocfs2_xattr_tree_sanity_check, + .eo_fill_root_el = ocfs2_xattr_tree_fill_root_el, + .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters, + }; +@@ -344,10 +353,25 @@ static inline void ocfs2_et_update_clusters(struct inode *inode, + et->et_ops->eo_update_clusters(inode, et, clusters); + } + ++static inline int ocfs2_et_insert_check(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ struct ocfs2_extent_rec *rec) ++{ ++ int ret = 0; ++ ++ if (et->et_ops->eo_insert_check) ++ ret = et->et_ops->eo_insert_check(inode, et, rec); ++ return ret; ++} ++ + static inline int ocfs2_et_sanity_check(struct inode *inode, + struct ocfs2_extent_tree *et) + { +- return et->et_ops->eo_sanity_check(inode, et); ++ int ret = 0; ++ ++ if (et->et_ops->eo_sanity_check) ++ ret = et->et_ops->eo_sanity_check(inode, et); ++ return ret; + } + + static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc); +@@ -4408,24 +4432,19 @@ static int ocfs2_insert_extent(struct ocfs2_super *osb, + struct ocfs2_insert_type insert = {0, }; + struct ocfs2_extent_rec rec; + +- BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); +- + mlog(0, "add %u clusters at position %u to inode %llu\n", + new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); + +- mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) && +- (OCFS2_I(inode)->ip_clusters != cpos), +- "Device %s, asking for sparse allocation: inode %llu, " +- "cpos %u, clusters %u\n", +- osb->dev_str, +- (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos, +- OCFS2_I(inode)->ip_clusters); +- + memset(&rec, 0, sizeof(rec)); + rec.e_cpos = cpu_to_le32(cpos); + rec.e_blkno = cpu_to_le64(start_blk); + rec.e_leaf_clusters = cpu_to_le16(new_clusters); + rec.e_flags = flags; ++ status = ocfs2_et_insert_check(inode, et, &rec); ++ if (status) { ++ mlog_errno(status); ++ goto bail; ++ } + + status = ocfs2_figure_insert_type(inode, et, &last_eb_bh, &rec, + &free_records, &insert); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-clusters-free-in-dealloc_ctxt.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-clusters-free-in-dealloc_ctxt.patch new file mode 100644 index 000000000..2419413ac --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-clusters-free-in-dealloc_ctxt.patch @@ -0,0 +1,196 @@ +From: Tao Ma +Date: Wed, 12 Nov 2008 08:26:58 +0800 +Subject: ocfs2: Add clusters free in dealloc_ctxt. +Patch-mainline: 2.6.29 + +Now in ocfs2 xattr set, the whole process are divided into many small +parts and they are wrapped into diffrent transactions and it make the +set doesn't look like a real transaction. So we want to integrate it +into a real one. + +In some cases we will allocate some clusters and free some in just one +transaction. e.g, one xattr is larger than inline size, so it and its +value root is stored within the inode while the value is outside in a +cluster. Then we try to update it with a smaller value(larger than the +size of root but smaller than inline size), we may need to free the +outside cluster while allocate a new bucket(one cluster) since now the +inode may be full. The old solution will lock the global_bitmap(if the +local alloc failed in stress test) and then the truncate log. This will +cause a ABBA lock with truncate log flush. + +This patch add the clusters free in dealloc_ctxt, so that we can record +the free clusters during the transaction and then free it after we +release the global_bitmap in xattr set. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++---- + fs/ocfs2/alloc.h | 4 ++ + 2 files changed, 103 insertions(+), 7 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.c +@@ -5809,7 +5809,10 @@ int ocfs2_truncate_log_init(struct ocfs2 + */ + + /* +- * Describes a single block free from a suballocator ++ * Describe a single bit freed from a suballocator. For the block ++ * suballocators, it represents one block. For the global cluster ++ * allocator, it represents some clusters and free_bit indicates ++ * clusters number. + */ + struct ocfs2_cached_block_free { + struct ocfs2_cached_block_free *free_next; +@@ -5824,10 +5827,10 @@ struct ocfs2_per_slot_free_list { + struct ocfs2_cached_block_free *f_first; + }; + +-static int ocfs2_free_cached_items(struct ocfs2_super *osb, +- int sysfile_type, +- int slot, +- struct ocfs2_cached_block_free *head) ++static int ocfs2_free_cached_blocks(struct ocfs2_super *osb, ++ int sysfile_type, ++ int slot, ++ struct ocfs2_cached_block_free *head) + { + int ret; + u64 bg_blkno; +@@ -5902,6 +5905,82 @@ out: + return ret; + } + ++int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, ++ u64 blkno, unsigned int bit) ++{ ++ int ret = 0; ++ struct ocfs2_cached_block_free *item; ++ ++ item = kmalloc(sizeof(*item), GFP_NOFS); ++ if (item == NULL) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ mlog(0, "Insert clusters: (bit %u, blk %llu)\n", ++ bit, (unsigned long long)blkno); ++ ++ item->free_blk = blkno; ++ item->free_bit = bit; ++ item->free_next = ctxt->c_global_allocator; ++ ++ ctxt->c_global_allocator = item; ++ return ret; ++} ++ ++static int ocfs2_free_cached_clusters(struct ocfs2_super *osb, ++ struct ocfs2_cached_block_free *head) ++{ ++ struct ocfs2_cached_block_free *tmp; ++ struct inode *tl_inode = osb->osb_tl_inode; ++ handle_t *handle; ++ int ret = 0; ++ ++ mutex_lock(&tl_inode->i_mutex); ++ ++ while (head) { ++ if (ocfs2_truncate_log_needs_flush(osb)) { ++ ret = __ocfs2_flush_truncate_log(osb); ++ if (ret < 0) { ++ mlog_errno(ret); ++ break; ++ } ++ } ++ ++ handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ break; ++ } ++ ++ ret = ocfs2_truncate_log_append(osb, handle, head->free_blk, ++ head->free_bit); ++ ++ ocfs2_commit_trans(osb, handle); ++ tmp = head; ++ head = head->free_next; ++ kfree(tmp); ++ ++ if (ret < 0) { ++ mlog_errno(ret); ++ break; ++ } ++ } ++ ++ mutex_unlock(&tl_inode->i_mutex); ++ ++ while (head) { ++ /* Premature exit may have left some dangling items. */ ++ tmp = head; ++ head = head->free_next; ++ kfree(tmp); ++ } ++ ++ return ret; ++} ++ + int ocfs2_run_deallocs(struct ocfs2_super *osb, + struct ocfs2_cached_dealloc_ctxt *ctxt) + { +@@ -5917,8 +5996,10 @@ int ocfs2_run_deallocs(struct ocfs2_supe + if (fl->f_first) { + mlog(0, "Free items: (type %u, slot %d)\n", + fl->f_inode_type, fl->f_slot); +- ret2 = ocfs2_free_cached_items(osb, fl->f_inode_type, +- fl->f_slot, fl->f_first); ++ ret2 = ocfs2_free_cached_blocks(osb, ++ fl->f_inode_type, ++ fl->f_slot, ++ fl->f_first); + if (ret2) + mlog_errno(ret2); + if (!ret) +@@ -5929,6 +6010,17 @@ int ocfs2_run_deallocs(struct ocfs2_supe + kfree(fl); + } + ++ if (ctxt->c_global_allocator) { ++ ret2 = ocfs2_free_cached_clusters(osb, ++ ctxt->c_global_allocator); ++ if (ret2) ++ mlog_errno(ret2); ++ if (!ret) ++ ret = ret2; ++ ++ ctxt->c_global_allocator = NULL; ++ } ++ + return ret; + } + +Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.h +@@ -167,11 +167,15 @@ int __ocfs2_flush_truncate_log(struct oc + */ + struct ocfs2_cached_dealloc_ctxt { + struct ocfs2_per_slot_free_list *c_first_suballocator; ++ struct ocfs2_cached_block_free *c_global_allocator; + }; + static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c) + { + c->c_first_suballocator = NULL; ++ c->c_global_allocator = NULL; + } ++int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, ++ u64 blkno, unsigned int bit); + int ocfs2_run_deallocs(struct ocfs2_super *osb, + struct ocfs2_cached_dealloc_ctxt *ctxt); + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-empty-bucket-support-in-xattr.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-empty-bucket-support-in-xattr.patch new file mode 100644 index 000000000..f81258af8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-empty-bucket-support-in-xattr.patch @@ -0,0 +1,319 @@ +From: Tao Ma +Subject: ocfs2: Add empty bucket support in xattr. +Patch-mainline: 2.6.28 + +As Mark mentioned, it may be time-consuming when we remove the +empty xattr bucket, so this patch try to let empty bucket exist +in xattr operation. The modification includes: +1. Remove the functin of bucket and extent record deletion during + xattr delete. +2. In xattr set: + 1) Don't clean the last entry so that if the bucket is empty, + the hash value of the bucket is the hash value of the entry + which is deleted last. + 2) During insert, if we meet with an empty bucket, just use the + 1st entry. +3. In binary search of xattr bucket, use the bucket hash value(which + stored in the 1st xattr entry) to find the right place. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 197 ++++++++++++------------------------------------------ + 1 files changed, 43 insertions(+), 154 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -2317,9 +2317,12 @@ static int ocfs2_xattr_bucket_find(struc + + /* + * Check whether the hash of the last entry in our +- * bucket is larger than the search one. ++ * bucket is larger than the search one. for an empty ++ * bucket, the last one is also the first one. + */ +- xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1]; ++ if (xh->xh_count) ++ xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1]; ++ + last_hash = le32_to_cpu(xe->xe_name_hash); + + /* record lower_bh which may be the insert place. */ +@@ -2466,7 +2469,8 @@ static int ocfs2_iterate_xattr_buckets(s + if (i == 0) + num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); + +- mlog(0, "iterating xattr bucket %llu\n", blkno); ++ mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno, ++ le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash)); + if (func) { + ret = func(inode, &bucket, para); + if (ret) { +@@ -3931,8 +3935,6 @@ static inline char *ocfs2_xattr_bucket_g + + /* + * Handle the normal xattr set, including replace, delete and new. +- * When the bucket is empty, "is_empty" is set and the caller can +- * free this bucket. + * + * Note: "local" indicates the real data's locality. So we can't + * just its bucket locality by its length. +@@ -3941,8 +3943,7 @@ static void ocfs2_xattr_set_entry_normal + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, + u32 name_hash, +- int local, +- int *is_empty) ++ int local) + { + struct ocfs2_xattr_entry *last, *xe; + int name_len = strlen(xi->name); +@@ -3995,14 +3996,23 @@ static void ocfs2_xattr_set_entry_normal + ocfs2_xattr_set_local(xe, local); + return; + } else { +- /* Remove the old entry. */ ++ /* ++ * Remove the old entry if there is more than one. ++ * We don't remove the last entry so that we can ++ * use it to indicate the hash value of the empty ++ * bucket. ++ */ + last -= 1; +- memmove(xe, xe + 1, +- (void *)last - (void *)xe); +- memset(last, 0, sizeof(struct ocfs2_xattr_entry)); + le16_add_cpu(&xh->xh_count, -1); +- if (xh->xh_count == 0 && is_empty) +- *is_empty = 1; ++ if (xh->xh_count) { ++ memmove(xe, xe + 1, ++ (void *)last - (void *)xe); ++ memset(last, 0, ++ sizeof(struct ocfs2_xattr_entry)); ++ } else ++ xh->xh_free_start = ++ cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE); ++ + return; + } + } else { +@@ -4010,7 +4020,7 @@ static void ocfs2_xattr_set_entry_normal + int low = 0, high = count - 1, tmp; + struct ocfs2_xattr_entry *tmp_xe; + +- while (low <= high) { ++ while (low <= high && count) { + tmp = (low + high) / 2; + tmp_xe = &xh->xh_entries[tmp]; + +@@ -4106,8 +4116,7 @@ static int ocfs2_xattr_set_entry_in_buck + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, + u32 name_hash, +- int local, +- int *bucket_empty) ++ int local) + { + int i, ret; + handle_t *handle = NULL; +@@ -4146,8 +4155,7 @@ static int ocfs2_xattr_set_entry_in_buck + } + } + +- ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, +- local, bucket_empty); ++ ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local); + + /*Only dirty the blocks we have touched in set xattr. */ + ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs, +@@ -4296,69 +4304,6 @@ static int ocfs2_xattr_bucket_set_value_ + return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len); + } + +-/* +- * Remove the xattr bucket pointed by bucket_bh. +- * All the buckets after it in the same xattr extent rec will be +- * move forward one by one. +- */ +-static int ocfs2_rm_xattr_bucket(struct inode *inode, +- struct buffer_head *first_bh, +- struct ocfs2_xattr_bucket *bucket) +-{ +- int ret = 0, credits; +- struct ocfs2_xattr_header *xh = +- (struct ocfs2_xattr_header *)first_bh->b_data; +- u16 bucket_num = le16_to_cpu(xh->xh_num_buckets); +- u64 end, start = bucket->bhs[0]->b_blocknr; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- handle_t *handle; +- u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- +- end = first_bh->b_blocknr + (bucket_num - 1) * blk_per_bucket; +- +- mlog(0, "rm xattr bucket %llu\n", start); +- /* +- * We need to update the first xattr_header and all the buckets starting +- * from start in this xattr rec. +- * +- * XXX: Should we empty the old last bucket here? +- */ +- credits = 1 + end - start; +- handle = ocfs2_start_trans(osb, credits); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- return ret; +- } +- +- ret = ocfs2_journal_access(handle, inode, first_bh, +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } +- +- +- while (start < end) { +- ret = ocfs2_cp_xattr_bucket(inode, handle, +- start + blk_per_bucket, +- start, 0); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } +- start += blk_per_bucket; +- } +- +- /* update the first_bh. */ +- xh->xh_num_buckets = cpu_to_le16(bucket_num - 1); +- ocfs2_journal_dirty(handle, first_bh); +- +-out_commit: +- ocfs2_commit_trans(osb, handle); +- return ret; +-} +- + static int ocfs2_rm_xattr_cluster(struct inode *inode, + struct buffer_head *root_bh, + u64 blkno, +@@ -4448,57 +4393,6 @@ out: + return ret; + } + +-/* +- * Free the xattr bucket indicated by xs->bucket and if all the buckets +- * in the clusters is free, free the clusters also. +- */ +-static int ocfs2_xattr_bucket_shrink(struct inode *inode, +- struct ocfs2_xattr_info *xi, +- struct ocfs2_xattr_search *xs, +- u32 name_hash) +-{ +- int ret; +- u32 e_cpos, num_clusters; +- u64 p_blkno; +- struct buffer_head *first_bh = NULL; +- struct ocfs2_xattr_header *first_xh; +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; +- +- BUG_ON(xs->header->xh_count != 0); +- +- ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, +- &e_cpos, &num_clusters, +- &xb->xb_attrs.xb_root.xt_list); +- if (ret) { +- mlog_errno(ret); +- return ret; +- } +- +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, +- &first_bh, OCFS2_BH_CACHED, inode); +- if (ret) { +- mlog_errno(ret); +- return ret; +- } +- +- ret = ocfs2_rm_xattr_bucket(inode, first_bh, &xs->bucket); +- if (ret) { +- mlog_errno(ret); +- goto out; +- } +- +- first_xh = (struct ocfs2_xattr_header *)first_bh->b_data; +- if (first_xh->xh_num_buckets == 0) +- ret = ocfs2_rm_xattr_cluster(inode, xs->xattr_bh, +- p_blkno, e_cpos, +- num_clusters); +- +-out: +- brelse(first_bh); +- return ret; +-} +- + static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + struct ocfs2_xattr_search *xs) + { +@@ -4550,7 +4444,7 @@ static int ocfs2_xattr_set_in_bucket(str + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs) + { +- int ret, local = 1, bucket_empty = 0; ++ int ret, local = 1; + size_t value_len; + char *val = (char *)xi->value; + struct ocfs2_xattr_entry *xe = xs->here; +@@ -4596,34 +4490,29 @@ static int ocfs2_xattr_set_in_bucket(str + xi->value_len = OCFS2_XATTR_ROOT_SIZE; + } + +- ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, +- local, &bucket_empty); ++ ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local); + if (ret) { + mlog_errno(ret); + goto out; + } + +- if (value_len > OCFS2_XATTR_INLINE_SIZE) { +- /* allocate the space now for the outside block storage. */ +- ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, +- value_len); +- if (ret) { +- mlog_errno(ret); ++ if (value_len <= OCFS2_XATTR_INLINE_SIZE) ++ goto out; + +- if (xs->not_found) { +- /* +- * We can't allocate enough clusters for outside +- * storage and we have allocated xattr already, +- * so need to remove it. +- */ +- ocfs2_xattr_bucket_remove_xs(inode, xs); +- } +- goto out; ++ /* allocate the space now for the outside block storage. */ ++ ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, ++ value_len); ++ if (ret) { ++ mlog_errno(ret); ++ ++ if (xs->not_found) { ++ /* ++ * We can't allocate enough clusters for outside ++ * storage and we have allocated xattr already, ++ * so need to remove it. ++ */ ++ ocfs2_xattr_bucket_remove_xs(inode, xs); + } +- } else { +- if (bucket_empty) +- ret = ocfs2_xattr_bucket_shrink(inode, xi, +- xs, name_hash); + goto out; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extended-attribute-support.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extended-attribute-support.patch new file mode 100644 index 000000000..133ea4d4e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extended-attribute-support.patch @@ -0,0 +1,2247 @@ +From: Tiger Yang +Subject: [PATCH 09/16] ocfs2: Add extended attribute support +Patch-mainline: 2.6.28? +References: FATE302067 + +This patch implements storing extended attributes both in inode or a single +external block. We only store EA's in-inode when blocksize > 512 or that +inode block has free space for it. When an EA's value is larger than 80 +bytes, we will store the value via b-tree outside inode or block. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/Makefile | 2 + fs/ocfs2/file.c | 5 + fs/ocfs2/inode.c | 8 + fs/ocfs2/inode.h | 3 + fs/ocfs2/journal.h | 10 + fs/ocfs2/namei.c | 5 + fs/ocfs2/ocfs2.h | 2 + fs/ocfs2/ocfs2_fs.h | 8 + fs/ocfs2/suballoc.c | 17 + fs/ocfs2/suballoc.h | 3 + fs/ocfs2/super.c | 14 + fs/ocfs2/symlink.c | 9 + fs/ocfs2/xattr.c | 1636 +++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/xattr.h | 58 + + fs/ocfs2/xattr_trusted.c | 82 ++ + fs/ocfs2/xattr_user.c | 94 ++ + 16 files changed, 1950 insertions(+), 6 deletions(-) + create mode 100644 fs/ocfs2/xattr.h + create mode 100644 fs/ocfs2/xattr_trusted.c + create mode 100644 fs/ocfs2/xattr_user.c + +--- a/fs/ocfs2/Makefile ++++ b/fs/ocfs2/Makefile +@@ -36,6 +36,8 @@ ocfs2-objs := \ + uptodate.o \ + ver.o \ + xattr.o \ ++ xattr_user.o \ ++ xattr_trusted.o + + ocfs2_stackglue-objs := stackglue.o + ocfs2_stack_o2cb-objs := stack_o2cb.o +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -55,6 +55,7 @@ + #include "mmap.h" + #include "suballoc.h" + #include "super.h" ++#include "xattr.h" + + #include "buffer_head_io.h" + +@@ -2130,6 +2131,10 @@ const struct inode_operations ocfs2_file + .setattr = ocfs2_setattr, + .getattr = ocfs2_getattr, + .permission = ocfs2_permission, ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = ocfs2_listxattr, ++ .removexattr = generic_removexattr, + .fallocate = ocfs2_fallocate, + }; + +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -49,6 +49,7 @@ + #include "symlink.h" + #include "sysfile.h" + #include "uptodate.h" ++#include "xattr.h" + + #include "buffer_head_io.h" + +@@ -728,6 +729,13 @@ static int ocfs2_wipe_inode(struct inode + if (status < 0) { + mlog_errno(status); + goto bail_unlock_dir; ++ } ++ ++ /*Free extended attribute resources associated with this inode.*/ ++ status = ocfs2_xattr_remove(inode, di_bh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto bail_unlock_dir; + } + + status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode, +--- a/fs/ocfs2/inode.h ++++ b/fs/ocfs2/inode.h +@@ -40,6 +40,9 @@ struct ocfs2_inode_info + /* protects allocation changes on this inode. */ + struct rw_semaphore ip_alloc_sem; + ++ /* protects extended attribute changes on this inode */ ++ struct rw_semaphore ip_xattr_sem; ++ + /* These fields are protected by ip_lock */ + spinlock_t ip_lock; + u32 ip_open_count; +--- a/fs/ocfs2/journal.h ++++ b/fs/ocfs2/journal.h +@@ -283,6 +283,9 @@ int ocfs2_journal_dirty + /* simple file updates like chmod, etc. */ + #define OCFS2_INODE_UPDATE_CREDITS 1 + ++/* extended attribute block update */ ++#define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1 ++ + /* group extend. inode update and last group update. */ + #define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) + +@@ -340,6 +343,13 @@ int ocfs2_journal_dirty + #define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \ + + OCFS2_UNLINK_CREDITS) + ++/* global bitmap dinode, group desc., relinked group, ++ * suballocator dinode, group desc., relinked group, ++ * dinode, xattr block */ ++#define OCFS2_XATTR_BLOCK_CREATE_CREDITS (OCFS2_SUBALLOC_ALLOC * 2 + \ ++ + OCFS2_INODE_UPDATE_CREDITS \ ++ + OCFS2_XATTR_BLOCK_UPDATE_CREDITS) ++ + /* + * Please note that the caller must make sure that root_el is the root + * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -60,6 +60,7 @@ + #include "symlink.h" + #include "sysfile.h" + #include "uptodate.h" ++#include "xattr.h" + + #include "buffer_head_io.h" + +@@ -1918,4 +1919,8 @@ const struct inode_operations ocfs2_dir_ + .setattr = ocfs2_setattr, + .getattr = ocfs2_getattr, + .permission = ocfs2_permission, ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = ocfs2_listxattr, ++ .removexattr = generic_removexattr, + }; +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -184,6 +184,7 @@ enum ocfs2_mount_options + OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */ + OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */ + OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */ ++ OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */ + }; + + #define OCFS2_OSB_SOFT_RO 0x0001 +@@ -214,6 +215,7 @@ struct ocfs2_super + u32 bitmap_cpg; + u8 *uuid; + char *uuid_str; ++ u32 uuid_hash; + u8 *vol_label; + u64 first_cluster_group_blkno; + u32 fs_generation; +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -570,7 +570,7 @@ struct ocfs2_super_block { + /*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts + before tunefs required */ + __le16 s_tunefs_flag; +- __le32 s_reserved1; ++ __le32 s_uuid_hash; /* hash value of uuid */ + __le64 s_first_cluster_group; /* Block offset of 1st cluster + * group header */ + /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */ +@@ -787,7 +787,11 @@ struct ocfs2_xattr_tree_root { + /*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */ + }; + +-#define OCFS2_XATTR_INDEXED 0x1 ++#define OCFS2_XATTR_INDEXED 0x1 ++#define OCFS2_HASH_SHIFT 5 ++#define OCFS2_XATTR_ROUND 3 ++#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \ ++ ~(OCFS2_XATTR_ROUND)) + + /* + * On disk structure for xattr block. +--- a/fs/ocfs2/suballoc.c ++++ b/fs/ocfs2/suballoc.c +@@ -493,9 +493,9 @@ bail: + return status; + } + +-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, +- struct ocfs2_extent_list *root_el, +- struct ocfs2_alloc_context **ac) ++int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb, ++ int blocks, ++ struct ocfs2_alloc_context **ac) + { + int status; + u32 slot; +@@ -507,7 +507,7 @@ int ocfs2_reserve_new_metadata(struct oc + goto bail; + } + +- (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(root_el); ++ (*ac)->ac_bits_wanted = blocks; + (*ac)->ac_which = OCFS2_AC_USE_META; + slot = osb->slot_num; + (*ac)->ac_group_search = ocfs2_block_group_search; +@@ -532,6 +532,15 @@ bail: + return status; + } + ++int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, ++ struct ocfs2_extent_list *root_el, ++ struct ocfs2_alloc_context **ac) ++{ ++ return ocfs2_reserve_new_metadata_blocks(osb, ++ ocfs2_extend_meta_needed(root_el), ++ ac); ++} ++ + static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb, + struct ocfs2_alloc_context *ac) + { +--- a/fs/ocfs2/suballoc.h ++++ b/fs/ocfs2/suballoc.h +@@ -67,6 +67,9 @@ static inline int ocfs2_alloc_context_bi + int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, + struct ocfs2_extent_list *root_el, + struct ocfs2_alloc_context **ac); ++int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb, ++ int blocks, ++ struct ocfs2_alloc_context **ac); + int ocfs2_reserve_new_inode(struct ocfs2_super *osb, + struct ocfs2_alloc_context **ac); + int ocfs2_reserve_clusters(struct ocfs2_super *osb, +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -64,6 +64,7 @@ + #include "sysfile.h" + #include "uptodate.h" + #include "ver.h" ++#include "xattr.h" + + #include "buffer_head_io.h" + +@@ -154,6 +155,8 @@ enum { + Opt_localalloc, + Opt_localflocks, + Opt_stack, ++ Opt_user_xattr, ++ Opt_nouser_xattr, + Opt_err, + }; + +@@ -173,6 +176,8 @@ static match_table_t tokens = { + {Opt_localalloc, "localalloc=%d"}, + {Opt_localflocks, "localflocks"}, + {Opt_stack, "cluster_stack=%s"}, ++ {Opt_user_xattr, "user_xattr"}, ++ {Opt_nouser_xattr, "nouser_xattr"}, + {Opt_err, NULL} + }; + +@@ -847,6 +852,12 @@ static int ocfs2_parse_options(struct su + case Opt_data_writeback: + mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK; + break; ++ case Opt_user_xattr: ++ mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR; ++ break; ++ case Opt_nouser_xattr: ++ mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR; ++ break; + case Opt_atime_quantum: + if (match_int(&args[0], &option)) { + status = 0; +@@ -1132,6 +1143,7 @@ static void ocfs2_inode_init_once(void * + oi->ip_dir_start_lookup = 0; + + init_rwsem(&oi->ip_alloc_sem); ++ init_rwsem(&oi->ip_xattr_sem); + mutex_init(&oi->ip_io_mutex); + + oi->ip_blkno = 0ULL; +@@ -1375,6 +1387,7 @@ static int ocfs2_initialize_super(struct + sb->s_fs_info = osb; + sb->s_op = &ocfs2_sops; + sb->s_export_op = &ocfs2_export_ops; ++ sb->s_xattr = ocfs2_xattr_handlers; + sb->s_time_gran = 1; + sb->s_flags |= MS_NOATIME; + /* this is needed to support O_LARGEFILE */ +@@ -1570,6 +1583,7 @@ static int ocfs2_initialize_super(struct + osb->first_cluster_group_blkno = + le64_to_cpu(di->id2.i_super.s_first_cluster_group); + osb->fs_generation = le32_to_cpu(di->i_fs_generation); ++ osb->uuid_hash = le32_to_cpu(di->id2.i_super.s_uuid_hash); + mlog(0, "vol_label: %s\n", osb->vol_label); + mlog(0, "uuid: %s\n", osb->uuid_str); + mlog(0, "root_blkno=%llu, system_dir_blkno=%llu\n", +--- a/fs/ocfs2/symlink.c ++++ b/fs/ocfs2/symlink.c +@@ -50,6 +50,7 @@ + #include "inode.h" + #include "journal.h" + #include "symlink.h" ++#include "xattr.h" + + #include "buffer_head_io.h" + +@@ -168,10 +169,18 @@ const struct inode_operations ocfs2_syml + .follow_link = ocfs2_follow_link, + .getattr = ocfs2_getattr, + .setattr = ocfs2_setattr, ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = ocfs2_listxattr, ++ .removexattr = generic_removexattr, + }; + const struct inode_operations ocfs2_fast_symlink_inode_operations = { + .readlink = ocfs2_readlink, + .follow_link = ocfs2_follow_link, + .getattr = ocfs2_getattr, + .setattr = ocfs2_setattr, ++ .setxattr = generic_setxattr, ++ .getxattr = generic_getxattr, ++ .listxattr = ocfs2_listxattr, ++ .removexattr = generic_removexattr, + }; +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -5,6 +5,9 @@ + * + * Copyright (C) 2008 Oracle. All rights reserved. + * ++ * CREDITS: ++ * Lots of code in this file is taken from ext3. ++ * + * 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 +@@ -21,6 +24,19 @@ + * Boston, MA 021110-1307, USA. + */ + ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ + #define MLOG_MASK_PREFIX ML_XATTR + #include + +@@ -28,12 +44,135 @@ + #include "alloc.h" + #include "dlmglue.h" + #include "file.h" ++#include "symlink.h" ++#include "sysfile.h" + #include "inode.h" + #include "journal.h" + #include "ocfs2_fs.h" + #include "suballoc.h" + #include "uptodate.h" + #include "buffer_head_io.h" ++#include "xattr.h" ++ ++ ++struct ocfs2_xattr_def_value_root { ++ struct ocfs2_xattr_value_root xv; ++ struct ocfs2_extent_rec er; ++}; ++ ++#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) ++#define OCFS2_XATTR_INLINE_SIZE 80 ++ ++static struct ocfs2_xattr_def_value_root def_xv = { ++ .xv.xr_list.l_count = cpu_to_le16(1), ++}; ++ ++struct xattr_handler *ocfs2_xattr_handlers[] = { ++ &ocfs2_xattr_user_handler, ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ &ocfs2_xattr_acl_access_handler, ++ &ocfs2_xattr_acl_default_handler, ++#endif ++ &ocfs2_xattr_trusted_handler, ++#ifdef CONFIG_OCFS2_FS_SECURITY ++ &ocfs2_xattr_security_handler, ++#endif ++ NULL ++}; ++ ++static struct xattr_handler *ocfs2_xattr_handler_map[] = { ++ [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS] ++ = &ocfs2_xattr_acl_access_handler, ++ [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT] ++ = &ocfs2_xattr_acl_default_handler, ++#endif ++ [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, ++#ifdef CONFIG_OCFS2_FS_SECURITY ++ [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler, ++#endif ++}; ++ ++struct ocfs2_xattr_info { ++ int name_index; ++ const char *name; ++ const void *value; ++ size_t value_len; ++}; ++ ++struct ocfs2_xattr_search { ++ struct buffer_head *inode_bh; ++ /* ++ * xattr_bh point to the block buffer head which has extended attribute ++ * when extended attribute in inode, xattr_bh is equal to inode_bh. ++ */ ++ struct buffer_head *xattr_bh; ++ struct ocfs2_xattr_header *header; ++ void *base; ++ void *end; ++ struct ocfs2_xattr_entry *here; ++ int not_found; ++}; ++ ++static inline struct xattr_handler *ocfs2_xattr_handler(int name_index) ++{ ++ struct xattr_handler *handler = NULL; ++ ++ if (name_index > 0 && name_index < OCFS2_XATTR_MAX) ++ handler = ocfs2_xattr_handler_map[name_index]; ++ ++ return handler; ++} ++ ++static inline u32 ocfs2_xattr_name_hash(struct inode *inode, ++ char *prefix, ++ int prefix_len, ++ char *name, ++ int name_len) ++{ ++ /* Get hash value of uuid from super block */ ++ u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash; ++ int i; ++ ++ /* hash extended attribute prefix */ ++ for (i = 0; i < prefix_len; i++) { ++ hash = (hash << OCFS2_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ ++ *prefix++; ++ } ++ /* hash extended attribute name */ ++ for (i = 0; i < name_len; i++) { ++ hash = (hash << OCFS2_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ ++ *name++; ++ } ++ ++ return hash; ++} ++ ++/* ++ * ocfs2_xattr_hash_entry() ++ * ++ * Compute the hash of an extended attribute. ++ */ ++static void ocfs2_xattr_hash_entry(struct inode *inode, ++ struct ocfs2_xattr_header *header, ++ struct ocfs2_xattr_entry *entry) ++{ ++ u32 hash = 0; ++ struct xattr_handler *handler = ++ ocfs2_xattr_handler(ocfs2_xattr_get_type(entry)); ++ char *prefix = handler->prefix; ++ char *name = (char *)header + le16_to_cpu(entry->xe_name_offset); ++ int prefix_len = strlen(handler->prefix); ++ ++ hash = ocfs2_xattr_name_hash(inode, prefix, prefix_len, name, ++ entry->xe_name_len); ++ entry->xe_name_hash = cpu_to_le32(hash); ++ ++ return; ++} + + static int ocfs2_xattr_extend_allocation(struct inode *inode, + u32 clusters_to_add, +@@ -303,3 +442,1500 @@ static int ocfs2_xattr_value_truncate(st + + return ret; + } ++ ++static int ocfs2_xattr_list_entries(struct inode *inode, ++ struct ocfs2_xattr_header *header, ++ char *buffer, size_t buffer_size) ++{ ++ size_t rest = buffer_size; ++ int i; ++ ++ for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) { ++ struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; ++ struct xattr_handler *handler = ++ ocfs2_xattr_handler(ocfs2_xattr_get_type(entry)); ++ ++ if (handler) { ++ size_t size = handler->list(inode, buffer, rest, ++ ((char *)header + ++ le16_to_cpu(entry->xe_name_offset)), ++ entry->xe_name_len); ++ if (buffer) { ++ if (size > rest) ++ return -ERANGE; ++ buffer += size; ++ } ++ rest -= size; ++ } ++ } ++ ++ return buffer_size - rest; ++} ++ ++static int ocfs2_xattr_ibody_list(struct inode *inode, ++ struct ocfs2_dinode *di, ++ char *buffer, ++ size_t buffer_size) ++{ ++ struct ocfs2_xattr_header *header = NULL; ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ int ret = 0; ++ ++ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) ++ return ret; ++ ++ header = (struct ocfs2_xattr_header *) ++ ((void *)di + inode->i_sb->s_blocksize - ++ le16_to_cpu(di->i_xattr_inline_size)); ++ ++ ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_block_list(struct inode *inode, ++ struct ocfs2_dinode *di, ++ char *buffer, ++ size_t buffer_size) ++{ ++ struct buffer_head *blk_bh = NULL; ++ struct ocfs2_xattr_header *header = NULL; ++ int ret = 0; ++ ++ if (!di->i_xattr_loc) ++ return ret; ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ le64_to_cpu(di->i_xattr_loc), ++ &blk_bh, OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ /*Verify the signature of xattr block*/ ++ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, ++ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { ++ ret = -EFAULT; ++ goto cleanup; ++ } ++ ++ header = &((struct ocfs2_xattr_block *)blk_bh->b_data)-> ++ xb_attrs.xb_header; ++ ++ ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size); ++cleanup: ++ brelse(blk_bh); ++ ++ return ret; ++} ++ ++ssize_t ocfs2_listxattr(struct dentry *dentry, ++ char *buffer, ++ size_t size) ++{ ++ int ret = 0, i_ret = 0, b_ret = 0; ++ struct buffer_head *di_bh = NULL; ++ struct ocfs2_dinode *di = NULL; ++ struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode); ++ ++ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) ++ return ret; ++ ++ ret = ocfs2_inode_lock(dentry->d_inode, &di_bh, 0); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ di = (struct ocfs2_dinode *)di_bh->b_data; ++ ++ down_read(&oi->ip_xattr_sem); ++ i_ret = ocfs2_xattr_ibody_list(dentry->d_inode, di, buffer, size); ++ if (i_ret < 0) ++ b_ret = 0; ++ else { ++ if (buffer) { ++ buffer += i_ret; ++ size -= i_ret; ++ } ++ b_ret = ocfs2_xattr_block_list(dentry->d_inode, di, ++ buffer, size); ++ if (b_ret < 0) ++ i_ret = 0; ++ } ++ up_read(&oi->ip_xattr_sem); ++ ocfs2_inode_unlock(dentry->d_inode, 0); ++ ++ brelse(di_bh); ++ ++ return i_ret + b_ret; ++} ++ ++static int ocfs2_xattr_find_entry(int name_index, ++ const char *name, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_xattr_entry *entry; ++ size_t name_len; ++ int i, cmp = 1; ++ ++ if (name == NULL) ++ return -EINVAL; ++ ++ name_len = strlen(name); ++ entry = xs->here; ++ for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) { ++ cmp = name_index - ocfs2_xattr_get_type(entry); ++ if (!cmp) ++ cmp = name_len - entry->xe_name_len; ++ if (!cmp) ++ cmp = memcmp(name, (xs->base + ++ le16_to_cpu(entry->xe_name_offset)), ++ name_len); ++ if (cmp == 0) ++ break; ++ entry += 1; ++ } ++ xs->here = entry; ++ ++ return cmp ? -ENODATA : 0; ++} ++ ++static int ocfs2_xattr_get_value_outside(struct inode *inode, ++ struct ocfs2_xattr_search *xs, ++ void *buffer, ++ size_t len) ++{ ++ u32 cpos, p_cluster, num_clusters, bpc, clusters; ++ u64 blkno; ++ int i, ret = 0; ++ size_t cplen, blocksize; ++ struct buffer_head *bh = NULL; ++ struct ocfs2_xattr_value_root *xv; ++ struct ocfs2_extent_list *el; ++ ++ xv = (struct ocfs2_xattr_value_root *) ++ (xs->base + le16_to_cpu(xs->here->xe_name_offset) + ++ OCFS2_XATTR_SIZE(xs->here->xe_name_len)); ++ el = &xv->xr_list; ++ clusters = le32_to_cpu(xv->xr_clusters); ++ bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); ++ blocksize = inode->i_sb->s_blocksize; ++ ++ cpos = 0; ++ while (cpos < clusters) { ++ ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster, ++ &num_clusters, el); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); ++ /* Copy ocfs2_xattr_value */ ++ for (i = 0; i < num_clusters * bpc; i++, blkno++) { ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, ++ &bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ cplen = len >= blocksize ? blocksize : len; ++ memcpy(buffer, bh->b_data, cplen); ++ len -= cplen; ++ buffer += cplen; ++ ++ brelse(bh); ++ bh = NULL; ++ if (len == 0) ++ break; ++ } ++ cpos += num_clusters; ++ } ++out: ++ return ret; ++} ++ ++static int ocfs2_xattr_ibody_get(struct inode *inode, ++ int name_index, ++ const char *name, ++ void *buffer, ++ size_t buffer_size, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ size_t size; ++ int ret = 0; ++ ++ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) ++ return -ENODATA; ++ ++ xs->end = (void *)di + inode->i_sb->s_blocksize; ++ xs->header = (struct ocfs2_xattr_header *) ++ (xs->end - le16_to_cpu(di->i_xattr_inline_size)); ++ xs->base = (void *)xs->header; ++ xs->here = xs->header->xh_entries; ++ ++ ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ if (ret) ++ return ret; ++ size = le64_to_cpu(xs->here->xe_value_size); ++ if (buffer) { ++ if (size > buffer_size) ++ return -ERANGE; ++ if (ocfs2_xattr_is_local(xs->here)) { ++ memcpy(buffer, (void *)xs->base + ++ le16_to_cpu(xs->here->xe_name_offset) + ++ OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); ++ } else { ++ ret = ocfs2_xattr_get_value_outside(inode, xs, ++ buffer, size); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ } ++ } ++ ++ return size; ++} ++ ++static int ocfs2_xattr_block_get(struct inode *inode, ++ int name_index, ++ const char *name, ++ void *buffer, ++ size_t buffer_size, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ struct buffer_head *blk_bh = NULL; ++ struct ocfs2_xattr_block *xb; ++ size_t size; ++ int ret = -ENODATA; ++ ++ if (!di->i_xattr_loc) ++ return ret; ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ le64_to_cpu(di->i_xattr_loc), ++ &blk_bh, OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ /*Verify the signature of xattr block*/ ++ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, ++ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { ++ ret = -EFAULT; ++ goto cleanup; ++ } ++ ++ xs->xattr_bh = blk_bh; ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ xs->header = &xb->xb_attrs.xb_header; ++ xs->base = (void *)xs->header; ++ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; ++ xs->here = xs->header->xh_entries; ++ ++ ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ if (ret) ++ goto cleanup; ++ size = le64_to_cpu(xs->here->xe_value_size); ++ if (buffer) { ++ ret = -ERANGE; ++ if (size > buffer_size) ++ goto cleanup; ++ if (ocfs2_xattr_is_local(xs->here)) { ++ memcpy(buffer, (void *)xs->base + ++ le16_to_cpu(xs->here->xe_name_offset) + ++ OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); ++ } else { ++ ret = ocfs2_xattr_get_value_outside(inode, xs, ++ buffer, size); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto cleanup; ++ } ++ } ++ } ++ ret = size; ++cleanup: ++ brelse(blk_bh); ++ ++ return ret; ++} ++ ++/* ocfs2_xattr_get() ++ * ++ * Copy an extended attribute into the buffer provided. ++ * Buffer is NULL to compute the size of buffer required. ++ */ ++int ocfs2_xattr_get(struct inode *inode, ++ int name_index, ++ const char *name, ++ void *buffer, ++ size_t buffer_size) ++{ ++ int ret; ++ struct ocfs2_dinode *di = NULL; ++ struct buffer_head *di_bh = NULL; ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_xattr_search xis = { ++ .not_found = -ENODATA, ++ }; ++ struct ocfs2_xattr_search xbs = { ++ .not_found = -ENODATA, ++ }; ++ ++ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) ++ ret = -ENODATA; ++ ++ ret = ocfs2_inode_lock(inode, &di_bh, 0); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ xis.inode_bh = xbs.inode_bh = di_bh; ++ di = (struct ocfs2_dinode *)di_bh->b_data; ++ ++ down_read(&oi->ip_xattr_sem); ++ ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, ++ buffer_size, &xis); ++ if (ret == -ENODATA) ++ ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, ++ buffer_size, &xbs); ++ up_read(&oi->ip_xattr_sem); ++ ocfs2_inode_unlock(inode, 0); ++ ++ brelse(di_bh); ++ ++ return ret; ++} ++ ++static int __ocfs2_xattr_set_value_outside(struct inode *inode, ++ struct ocfs2_xattr_value_root *xv, ++ const void *value, ++ int value_len) ++{ ++ int ret = 0, i, cp_len, credits; ++ u16 blocksize = inode->i_sb->s_blocksize; ++ u32 p_cluster, num_clusters; ++ u32 cpos = 0, bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); ++ u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len); ++ u64 blkno; ++ struct buffer_head *bh = NULL; ++ handle_t *handle; ++ ++ BUG_ON(clusters > le32_to_cpu(xv->xr_clusters)); ++ ++ credits = clusters * bpc; ++ handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), credits); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ while (cpos < clusters) { ++ ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster, ++ &num_clusters, &xv->xr_list); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); ++ ++ for (i = 0; i < num_clusters * bpc; i++, blkno++) { ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, ++ &bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_journal_access(handle, ++ inode, ++ bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ cp_len = value_len > blocksize ? blocksize : value_len; ++ memcpy(bh->b_data, value, cp_len); ++ value_len -= cp_len; ++ value += cp_len; ++ if (cp_len < blocksize) ++ memset(bh->b_data + cp_len, 0, ++ blocksize - cp_len); ++ ++ ret = ocfs2_journal_dirty(handle, bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ brelse(bh); ++ bh = NULL; ++ ++ /* ++ * XXX: do we need to empty all the following ++ * blocks in this cluster? ++ */ ++ if (!value_len) ++ break; ++ } ++ cpos += num_clusters; ++ } ++out_commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++out: ++ brelse(bh); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_cleanup(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ size_t offs) ++{ ++ handle_t *handle = NULL; ++ int ret = 0; ++ size_t name_len = strlen(xi->name); ++ void *val = xs->base + offs; ++ size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; ++ ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), ++ OCFS2_XATTR_BLOCK_UPDATE_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ /* Decrease xattr count */ ++ le16_add_cpu(&xs->header->xh_count, -1); ++ /* Remove the xattr entry and tree root which has already be set*/ ++ memset((void *)xs->here, 0, sizeof(struct ocfs2_xattr_entry)); ++ memset(val, 0, size); ++ ++ ret = ocfs2_journal_dirty(handle, xs->xattr_bh); ++ if (ret < 0) ++ mlog_errno(ret); ++out_commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++out: ++ return ret; ++} ++ ++static int ocfs2_xattr_update_entry(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ size_t offs) ++{ ++ handle_t *handle = NULL; ++ int ret = 0; ++ ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), ++ OCFS2_XATTR_BLOCK_UPDATE_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ xs->here->xe_name_offset = cpu_to_le16(offs); ++ xs->here->xe_value_size = cpu_to_le64(xi->value_len); ++ if (xi->value_len <= OCFS2_XATTR_INLINE_SIZE) ++ ocfs2_xattr_set_local(xs->here, 1); ++ else ++ ocfs2_xattr_set_local(xs->here, 0); ++ ocfs2_xattr_hash_entry(inode, xs->header, xs->here); ++ ++ ret = ocfs2_journal_dirty(handle, xs->xattr_bh); ++ if (ret < 0) ++ mlog_errno(ret); ++out_commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++out: ++ return ret; ++} ++ ++/* ++ * ocfs2_xattr_set_value_outside() ++ * ++ * Set large size value in B tree. ++ */ ++static int ocfs2_xattr_set_value_outside(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ size_t offs) ++{ ++ size_t name_len = strlen(xi->name); ++ void *val = xs->base + offs; ++ struct ocfs2_xattr_value_root *xv = NULL; ++ size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; ++ int ret = 0; ++ ++ memset(val, 0, size); ++ memcpy(val, xi->name, name_len); ++ xv = (struct ocfs2_xattr_value_root *) ++ (val + OCFS2_XATTR_SIZE(name_len)); ++ xv->xr_clusters = 0; ++ xv->xr_last_eb_blk = 0; ++ xv->xr_list.l_tree_depth = 0; ++ xv->xr_list.l_count = cpu_to_le16(1); ++ xv->xr_list.l_next_free_rec = 0; ++ ++ ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv, ++ xi->value_len); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ret = __ocfs2_xattr_set_value_outside(inode, xv, xi->value, ++ xi->value_len); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ret = ocfs2_xattr_update_entry(inode, xi, xs, offs); ++ if (ret < 0) ++ mlog_errno(ret); ++ ++ return ret; ++} ++ ++/* ++ * ocfs2_xattr_set_entry_local() ++ * ++ * Set, replace or remove extended attribute in local. ++ */ ++static void ocfs2_xattr_set_entry_local(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_entry *last, ++ size_t min_offs) ++{ ++ size_t name_len = strlen(xi->name); ++ int i; ++ ++ if (xi->value && xs->not_found) { ++ /* Insert the new xattr entry. */ ++ le16_add_cpu(&xs->header->xh_count, 1); ++ ocfs2_xattr_set_type(last, xi->name_index); ++ ocfs2_xattr_set_local(last, 1); ++ last->xe_name_len = name_len; ++ } else { ++ void *first_val; ++ void *val; ++ size_t offs, size; ++ ++ first_val = xs->base + min_offs; ++ offs = le16_to_cpu(xs->here->xe_name_offset); ++ val = xs->base + offs; ++ ++ if (le64_to_cpu(xs->here->xe_value_size) > ++ OCFS2_XATTR_INLINE_SIZE) ++ size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_ROOT_SIZE; ++ else ++ size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size)); ++ ++ if (xi->value && size == OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(xi->value_len)) { ++ /* The old and the new value have the ++ same size. Just replace the value. */ ++ ocfs2_xattr_set_local(xs->here, 1); ++ xs->here->xe_value_size = cpu_to_le64(xi->value_len); ++ /* Clear value bytes. */ ++ memset(val + OCFS2_XATTR_SIZE(name_len), ++ 0, ++ OCFS2_XATTR_SIZE(xi->value_len)); ++ memcpy(val + OCFS2_XATTR_SIZE(name_len), ++ xi->value, ++ xi->value_len); ++ return; ++ } ++ /* Remove the old name+value. */ ++ memmove(first_val + size, first_val, val - first_val); ++ memset(first_val, 0, size); ++ xs->here->xe_name_hash = 0; ++ xs->here->xe_name_offset = 0; ++ ocfs2_xattr_set_local(xs->here, 1); ++ xs->here->xe_value_size = 0; ++ ++ min_offs += size; ++ ++ /* Adjust all value offsets. */ ++ last = xs->header->xh_entries; ++ for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) { ++ size_t o = le16_to_cpu(last->xe_name_offset); ++ ++ if (o < offs) ++ last->xe_name_offset = cpu_to_le16(o + size); ++ last += 1; ++ } ++ ++ if (!xi->value) { ++ /* Remove the old entry. */ ++ last -= 1; ++ memmove(xs->here, xs->here + 1, ++ (void *)last - (void *)xs->here); ++ memset(last, 0, sizeof(struct ocfs2_xattr_entry)); ++ le16_add_cpu(&xs->header->xh_count, -1); ++ } ++ } ++ if (xi->value) { ++ /* Insert the new name+value. */ ++ size_t size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(xi->value_len); ++ void *val = xs->base + min_offs - size; ++ ++ xs->here->xe_name_offset = cpu_to_le16(min_offs - size); ++ memset(val, 0, size); ++ memcpy(val, xi->name, name_len); ++ memcpy(val + OCFS2_XATTR_SIZE(name_len), ++ xi->value, ++ xi->value_len); ++ xs->here->xe_value_size = cpu_to_le64(xi->value_len); ++ ocfs2_xattr_set_local(xs->here, 1); ++ ocfs2_xattr_hash_entry(inode, xs->header, xs->here); ++ } ++ ++ return; ++} ++ ++/* ++ * ocfs2_xattr_set_entry() ++ * ++ * Set extended attribute entry into inode or block. ++ * ++ * If extended attribute value size > OCFS2_XATTR_INLINE_SIZE, ++ * We first insert tree root(ocfs2_xattr_value_root) with set_entry_local(), ++ * then set value in B tree with set_value_outside(). ++ */ ++static int ocfs2_xattr_set_entry(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ int flag) ++{ ++ struct ocfs2_xattr_entry *last; ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ size_t min_offs = xs->end - xs->base, name_len = strlen(xi->name); ++ size_t size_l = 0; ++ handle_t *handle = NULL; ++ int free, i, ret; ++ struct ocfs2_xattr_info xi_l = { ++ .name_index = xi->name_index, ++ .name = xi->name, ++ .value = xi->value, ++ .value_len = xi->value_len, ++ }; ++ ++ /* Compute min_offs, last and free space. */ ++ last = xs->header->xh_entries; ++ ++ for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) { ++ size_t offs = le16_to_cpu(last->xe_name_offset); ++ if (offs < min_offs) ++ min_offs = offs; ++ last += 1; ++ } ++ ++ free = min_offs - ((void *)last - xs->base) - sizeof(__u32); ++ if (free < 0) ++ return -EFAULT; ++ ++ if (!xs->not_found) { ++ size_t size = 0; ++ if (ocfs2_xattr_is_local(xs->here)) ++ size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size)); ++ else ++ size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_ROOT_SIZE; ++ free += (size + sizeof(struct ocfs2_xattr_entry)); ++ } ++ /* Check free space in inode or block */ ++ if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) { ++ if (free < sizeof(struct ocfs2_xattr_entry) + ++ OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_ROOT_SIZE) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ size_l = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; ++ xi_l.value = (void *)&def_xv; ++ xi_l.value_len = OCFS2_XATTR_ROOT_SIZE; ++ } else if (xi->value) { ++ if (free < sizeof(struct ocfs2_xattr_entry) + ++ OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(xi->value_len)) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ } ++ ++ if (!xs->not_found) { ++ /* For existing extended attribute */ ++ size_t size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size)); ++ size_t offs = le16_to_cpu(xs->here->xe_name_offset); ++ void *val = xs->base + offs; ++ ++ if (ocfs2_xattr_is_local(xs->here) && size == size_l) { ++ /* Replace existing local xattr with tree root */ ++ ret = ocfs2_xattr_set_value_outside(inode, xi, xs, ++ offs); ++ if (ret < 0) ++ mlog_errno(ret); ++ goto out; ++ } else if (!ocfs2_xattr_is_local(xs->here)) { ++ /* For existing xattr which has value outside */ ++ struct ocfs2_xattr_value_root *xv = NULL; ++ xv = (struct ocfs2_xattr_value_root *)(val + ++ OCFS2_XATTR_SIZE(name_len)); ++ ++ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) { ++ /* ++ * If new value need set outside also, ++ * first truncate old value to new value, ++ * then set new value with set_value_outside(). ++ */ ++ ret = ocfs2_xattr_value_truncate(inode, ++ xs->xattr_bh, ++ xv, ++ xi->value_len); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = __ocfs2_xattr_set_value_outside(inode, ++ xv, ++ xi->value, ++ xi->value_len); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_xattr_update_entry(inode, ++ xi, ++ xs, ++ offs); ++ if (ret < 0) ++ mlog_errno(ret); ++ goto out; ++ } else { ++ /* ++ * If new value need set in local, ++ * just trucate old value to zero. ++ */ ++ ret = ocfs2_xattr_value_truncate(inode, ++ xs->xattr_bh, ++ xv, ++ 0); ++ if (ret < 0) ++ mlog_errno(ret); ++ } ++ } ++ } ++ ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), ++ OCFS2_INODE_UPDATE_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, xs->inode_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ if (!(flag & OCFS2_INLINE_XATTR_FL)) { ++ /*set extended attribue in external blcok*/ ++ ret = ocfs2_extend_trans(handle, ++ OCFS2_XATTR_BLOCK_UPDATE_CREDITS); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ } ++ ++ /* ++ * Set value in local, include set tree root in local. ++ * This is the first step for value size >INLINE_SIZE. ++ */ ++ ocfs2_xattr_set_entry_local(inode, &xi_l, xs, last, min_offs); ++ ++ if (!(flag & OCFS2_INLINE_XATTR_FL)) { ++ ret = ocfs2_journal_dirty(handle, xs->xattr_bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ } ++ ++ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) && ++ (flag & OCFS2_INLINE_XATTR_FL)) { ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ unsigned int xattrsize = osb->s_xattr_inline_size; ++ ++ /* ++ * Adjust extent record count or inline data size ++ * to reserve space for extended attribute. ++ */ ++ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { ++ struct ocfs2_inline_data *idata = &di->id2.i_data; ++ le16_add_cpu(&idata->id_count, -xattrsize); ++ } else if (!(ocfs2_inode_is_fast_symlink(inode))) { ++ struct ocfs2_extent_list *el = &di->id2.i_list; ++ le16_add_cpu(&el->l_count, -(xattrsize / ++ sizeof(struct ocfs2_extent_rec))); ++ } ++ di->i_xattr_inline_size = cpu_to_le16(xattrsize); ++ } ++ /* Update xattr flag */ ++ spin_lock(&oi->ip_lock); ++ oi->ip_dyn_features |= flag; ++ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); ++ spin_unlock(&oi->ip_lock); ++ /* Update inode ctime */ ++ inode->i_ctime = CURRENT_TIME; ++ di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); ++ di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); ++ ++ ret = ocfs2_journal_dirty(handle, xs->inode_bh); ++ if (ret < 0) ++ mlog_errno(ret); ++ ++out_commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++ ++ if (!ret && xi->value_len > OCFS2_XATTR_INLINE_SIZE) { ++ /* ++ * Set value outside in B tree. ++ * This is the second step for value size > INLINE_SIZE. ++ */ ++ size_t offs = le16_to_cpu(xs->here->xe_name_offset); ++ ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs); ++ if (ret < 0) { ++ int ret2; ++ ++ mlog_errno(ret); ++ /* ++ * If set value outside failed, we have to clean ++ * the junk tree root we have already set in local. ++ */ ++ ret2 = ocfs2_xattr_cleanup(inode, xi, xs, offs); ++ if (ret2 < 0) ++ mlog_errno(ret2); ++ } ++ } ++out: ++ return ret; ++ ++} ++ ++static int ocfs2_xattr_free_block(handle_t *handle, ++ struct ocfs2_super *osb, ++ struct ocfs2_xattr_block *xb) ++{ ++ struct inode *xb_alloc_inode; ++ struct buffer_head *xb_alloc_bh = NULL; ++ u64 blk = le64_to_cpu(xb->xb_blkno); ++ u16 bit = le16_to_cpu(xb->xb_suballoc_bit); ++ u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit); ++ int ret = 0; ++ ++ xb_alloc_inode = ocfs2_get_system_file_inode(osb, ++ EXTENT_ALLOC_SYSTEM_INODE, ++ le16_to_cpu(xb->xb_suballoc_slot)); ++ if (!xb_alloc_inode) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ mutex_lock(&xb_alloc_inode->i_mutex); ++ ++ ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_mutex; ++ } ++ ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_unlock; ++ } ++ ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, ++ bit, bg_blkno, 1); ++ if (ret < 0) ++ mlog_errno(ret); ++out_unlock: ++ ocfs2_inode_unlock(xb_alloc_inode, 1); ++ brelse(xb_alloc_bh); ++out_mutex: ++ mutex_unlock(&xb_alloc_inode->i_mutex); ++ iput(xb_alloc_inode); ++out: ++ return ret; ++} ++ ++static int ocfs2_remove_value_outside(struct inode*inode, ++ struct buffer_head *bh, ++ struct ocfs2_xattr_header *header) ++{ ++ int ret = 0, i; ++ ++ for (i = 0; i < le16_to_cpu(header->xh_count); i++) { ++ struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; ++ ++ if (!ocfs2_xattr_is_local(entry)) { ++ struct ocfs2_xattr_value_root *xv; ++ void *val; ++ ++ val = (void *)header + ++ le16_to_cpu(entry->xe_name_offset); ++ xv = (struct ocfs2_xattr_value_root *) ++ (val + OCFS2_XATTR_SIZE(entry->xe_name_len)); ++ ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_ibody_remove(struct inode *inode, ++ struct buffer_head *di_bh) ++{ ++ ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ++ struct ocfs2_xattr_header *header; ++ int ret; ++ ++ header = (struct ocfs2_xattr_header *) ++ ((void *)di + inode->i_sb->s_blocksize - ++ le16_to_cpu(di->i_xattr_inline_size)); ++ ++ ret = ocfs2_remove_value_outside(inode, di_bh, header); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_block_remove(struct inode *inode, ++ struct buffer_head *blk_bh) ++{ ++ struct ocfs2_xattr_block *xb; ++ struct ocfs2_xattr_header *header; ++ int ret = 0; ++ ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ header = &(xb->xb_attrs.xb_header); ++ ++ ret = ocfs2_remove_value_outside(inode, blk_bh, header); ++ ++ return ret; ++} ++ ++/* ++ * ocfs2_xattr_remove() ++ * ++ * Free extended attribute resources associated with this inode. ++ */ ++int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) ++{ ++ struct ocfs2_xattr_block *xb; ++ struct buffer_head *blk_bh = NULL; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ++ handle_t *handle; ++ int ret; ++ ++ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) ++ return 0; ++ ++ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { ++ ret = ocfs2_xattr_ibody_remove(inode, di_bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ if (di->i_xattr_loc) { ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ le64_to_cpu(di->i_xattr_loc), ++ &blk_bh, OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ /*Verify the signature of xattr block*/ ++ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, ++ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = ocfs2_xattr_block_remove(inode, blk_bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), ++ OCFS2_INODE_UPDATE_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ret = ocfs2_journal_access(handle, inode, di_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ if (di->i_xattr_loc) { ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ ocfs2_xattr_free_block(handle, osb, xb); ++ di->i_xattr_loc = cpu_to_le64(0); ++ } ++ ++ spin_lock(&oi->ip_lock); ++ oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL); ++ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features); ++ spin_unlock(&oi->ip_lock); ++ ++ ret = ocfs2_journal_dirty(handle, di_bh); ++ if (ret < 0) ++ mlog_errno(ret); ++out_commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++out: ++ brelse(blk_bh); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_has_space_inline(struct inode *inode, ++ struct ocfs2_dinode *di) ++{ ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ unsigned int xattrsize = OCFS2_SB(inode->i_sb)->s_xattr_inline_size; ++ int free; ++ ++ if (xattrsize < OCFS2_MIN_XATTR_INLINE_SIZE) ++ return 0; ++ ++ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { ++ struct ocfs2_inline_data *idata = &di->id2.i_data; ++ free = le16_to_cpu(idata->id_count) - le64_to_cpu(di->i_size); ++ } else if (ocfs2_inode_is_fast_symlink(inode)) { ++ free = ocfs2_fast_symlink_chars(inode->i_sb) - ++ le64_to_cpu(di->i_size); ++ } else { ++ struct ocfs2_extent_list *el = &di->id2.i_list; ++ free = (le16_to_cpu(el->l_count) - ++ le16_to_cpu(el->l_next_free_rec)) * ++ sizeof(struct ocfs2_extent_rec); ++ } ++ if (free >= xattrsize) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * ocfs2_xattr_ibody_find() ++ * ++ * Find extended attribute in inode block and ++ * fill search info into struct ocfs2_xattr_search. ++ */ ++static int ocfs2_xattr_ibody_find(struct inode *inode, ++ int name_index, ++ const char *name, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ int ret; ++ int has_space = 0; ++ ++ if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE) ++ return 0; ++ ++ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) { ++ down_read(&oi->ip_alloc_sem); ++ has_space = ocfs2_xattr_has_space_inline(inode, di); ++ up_read(&oi->ip_alloc_sem); ++ if (!has_space) ++ return 0; ++ } ++ ++ xs->xattr_bh = xs->inode_bh; ++ xs->end = (void *)di + inode->i_sb->s_blocksize; ++ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) ++ xs->header = (struct ocfs2_xattr_header *) ++ (xs->end - le16_to_cpu(di->i_xattr_inline_size)); ++ else ++ xs->header = (struct ocfs2_xattr_header *) ++ (xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size); ++ xs->base = (void *)xs->header; ++ xs->here = xs->header->xh_entries; ++ ++ /* Find the named attribute. */ ++ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) { ++ ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ if (ret && ret != -ENODATA) ++ return ret; ++ xs->not_found = ret; ++ } ++ ++ return 0; ++} ++ ++/* ++ * ocfs2_xattr_ibody_set() ++ * ++ * Set, replace or remove an extended attribute into inode block. ++ * ++ */ ++static int ocfs2_xattr_ibody_set(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ int ret; ++ ++ if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE) ++ return -ENOSPC; ++ ++ down_write(&oi->ip_alloc_sem); ++ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) { ++ if (!ocfs2_xattr_has_space_inline(inode, di)) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ } ++ ++ ret = ocfs2_xattr_set_entry(inode, xi, xs, ++ (OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL)); ++out: ++ up_write(&oi->ip_alloc_sem); ++ ++ return ret; ++} ++ ++/* ++ * ocfs2_xattr_block_find() ++ * ++ * Find extended attribute in external block and ++ * fill search info into struct ocfs2_xattr_search. ++ */ ++static int ocfs2_xattr_block_find(struct inode *inode, ++ int name_index, ++ const char *name, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ struct buffer_head *blk_bh = NULL; ++ int ret = 0; ++ ++ if (!di->i_xattr_loc) ++ return ret; ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ le64_to_cpu(di->i_xattr_loc), ++ &blk_bh, OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ /*Verify the signature of xattr block*/ ++ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, ++ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { ++ ret = -EFAULT; ++ goto cleanup; ++ } ++ ++ xs->xattr_bh = blk_bh; ++ xs->header = &((struct ocfs2_xattr_block *)blk_bh->b_data)-> ++ xb_attrs.xb_header; ++ xs->base = (void *)xs->header; ++ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; ++ xs->here = xs->header->xh_entries; ++ ++ ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ if (ret && ret != -ENODATA) { ++ xs->xattr_bh = NULL; ++ goto cleanup; ++ } ++ xs->not_found = ret; ++ return 0; ++ ++cleanup: ++ brelse(blk_bh); ++ ++ return ret; ++} ++ ++/* ++ * ocfs2_xattr_block_set() ++ * ++ * Set, replace or remove an extended attribute into external block. ++ * ++ */ ++static int ocfs2_xattr_block_set(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct buffer_head *new_bh = NULL; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ struct ocfs2_alloc_context *meta_ac = NULL; ++ handle_t *handle = NULL; ++ struct ocfs2_xattr_block *xblk = NULL; ++ u16 suballoc_bit_start; ++ u32 num_got; ++ u64 first_blkno; ++ int ret; ++ ++ if (!xs->xattr_bh) { ++ /* ++ * Alloc one external block for extended attribute ++ * outside of inode. ++ */ ++ ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ handle = ocfs2_start_trans(osb, ++ OCFS2_XATTR_BLOCK_CREATE_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ret = ocfs2_journal_access(handle, inode, xs->inode_bh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1, ++ &suballoc_bit_start, &num_got, ++ &first_blkno); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ new_bh = sb_getblk(inode->i_sb, first_blkno); ++ ocfs2_set_new_buffer_uptodate(inode, new_bh); ++ ++ ret = ocfs2_journal_access(handle, inode, new_bh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ /* Initialize ocfs2_xattr_block */ ++ xs->xattr_bh = new_bh; ++ xblk = (struct ocfs2_xattr_block *)new_bh->b_data; ++ memset(xblk, 0, inode->i_sb->s_blocksize); ++ strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE); ++ xblk->xb_suballoc_slot = cpu_to_le16(osb->slot_num); ++ xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start); ++ xblk->xb_fs_generation = cpu_to_le32(osb->fs_generation); ++ xblk->xb_blkno = cpu_to_le64(first_blkno); ++ ++ xs->header = &xblk->xb_attrs.xb_header; ++ xs->base = (void *)xs->header; ++ xs->end = (void *)xblk + inode->i_sb->s_blocksize; ++ xs->here = xs->header->xh_entries; ++ ++ ++ ret = ocfs2_journal_dirty(handle, new_bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ di->i_xattr_loc = cpu_to_le64(first_blkno); ++ ret = ocfs2_journal_dirty(handle, xs->inode_bh); ++ if (ret < 0) ++ mlog_errno(ret); ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ if (meta_ac) ++ ocfs2_free_alloc_context(meta_ac); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Set extended attribute into external block */ ++ ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL); ++ ++ return ret; ++} ++ ++/* ++ * ocfs2_xattr_set() ++ * ++ * Set, replace or remove an extended attribute for this inode. ++ * value is NULL to remove an existing extended attribute, else either ++ * create or replace an extended attribute. ++ */ ++int ocfs2_xattr_set(struct inode *inode, ++ int name_index, ++ const char *name, ++ const void *value, ++ size_t value_len, ++ int flags) ++{ ++ struct buffer_head *di_bh = NULL; ++ struct ocfs2_dinode *di; ++ int ret; ++ ++ struct ocfs2_xattr_info xi = { ++ .name_index = name_index, ++ .name = name, ++ .value = value, ++ .value_len = value_len, ++ }; ++ ++ struct ocfs2_xattr_search xis = { ++ .not_found = -ENODATA, ++ }; ++ ++ struct ocfs2_xattr_search xbs = { ++ .not_found = -ENODATA, ++ }; ++ ++ ret = ocfs2_inode_lock(inode, &di_bh, 1); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ xis.inode_bh = xbs.inode_bh = di_bh; ++ di = (struct ocfs2_dinode *)di_bh->b_data; ++ ++ down_write(&OCFS2_I(inode)->ip_xattr_sem); ++ /* ++ * Scan inode and external block to find the same name ++ * extended attribute and collect search infomation. ++ */ ++ ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis); ++ if (ret) ++ goto cleanup; ++ if (xis.not_found) { ++ ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs); ++ if (ret) ++ goto cleanup; ++ } ++ ++ if (xis.not_found && xbs.not_found) { ++ ret = -ENODATA; ++ if (flags & XATTR_REPLACE) ++ goto cleanup; ++ ret = 0; ++ if (!value) ++ goto cleanup; ++ } else { ++ ret = -EEXIST; ++ if (flags & XATTR_CREATE) ++ goto cleanup; ++ } ++ ++ if (!value) { ++ /* Remove existing extended attribute */ ++ if (!xis.not_found) ++ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); ++ else if (!xbs.not_found) ++ ret = ocfs2_xattr_block_set(inode, &xi, &xbs); ++ } else { ++ /* We always try to set extended attribute into inode first*/ ++ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); ++ if (!ret && !xbs.not_found) { ++ /* ++ * If succeed and that extended attribute existing in ++ * external block, then we will remove it. ++ */ ++ xi.value = NULL; ++ xi.value_len = 0; ++ ret = ocfs2_xattr_block_set(inode, &xi, &xbs); ++ } else if (ret == -ENOSPC) { ++ if (di->i_xattr_loc && !xbs.xattr_bh) { ++ ret = ocfs2_xattr_block_find(inode, name_index, ++ name, &xbs); ++ if (ret) ++ goto cleanup; ++ } ++ /* ++ * If no space in inode, we will set extended attribute ++ * into external block. ++ */ ++ ret = ocfs2_xattr_block_set(inode, &xi, &xbs); ++ if (ret) ++ goto cleanup; ++ if (!xis.not_found) { ++ /* ++ * If succeed and that extended attribute ++ * existing in inode, we will remove it. ++ */ ++ xi.value = NULL; ++ xi.value_len = 0; ++ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); ++ } ++ } ++ } ++cleanup: ++ up_write(&OCFS2_I(inode)->ip_xattr_sem); ++ ocfs2_inode_unlock(inode, 1); ++ brelse(di_bh); ++ brelse(xbs.xattr_bh); ++ ++ return ret; ++} ++ +--- /dev/null ++++ b/fs/ocfs2/xattr.h +@@ -0,0 +1,58 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * xattr.h ++ * ++ * Function prototypes ++ * ++ * Copyright (C) 2008 Oracle. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ */ ++ ++#ifndef OCFS2_XATTR_H ++#define OCFS2_XATTR_H ++ ++#include ++#include ++ ++enum ocfs2_xattr_type { ++ OCFS2_XATTR_INDEX_USER = 1, ++ OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS, ++ OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT, ++ OCFS2_XATTR_INDEX_TRUSTED, ++ OCFS2_XATTR_INDEX_SECURITY, ++ OCFS2_XATTR_MAX ++}; ++ ++extern struct xattr_handler ocfs2_xattr_user_handler; ++extern struct xattr_handler ocfs2_xattr_trusted_handler; ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++extern struct xattr_handler ocfs2_xattr_acl_access_handler; ++extern struct xattr_handler ocfs2_xattr_acl_default_handler; ++#endif ++#ifdef CONFIG_OCFS2_FS_SECURITY ++extern struct xattr_handler ocfs2_xattr_security_handler; ++#endif ++ ++extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); ++extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t); ++extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *, ++ size_t, int); ++extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh); ++extern struct xattr_handler *ocfs2_xattr_handlers[]; ++ ++#endif /* OCFS2_XATTR_H */ +--- /dev/null ++++ b/fs/ocfs2/xattr_trusted.c +@@ -0,0 +1,82 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * xattr_trusted.c ++ * ++ * Copyright (C) 2008 Oracle. All rights reserved. ++ * ++ * CREDITS: ++ * Lots of code in this file is taken from ext3. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#define MLOG_MASK_PREFIX ML_INODE ++#include ++ ++#include "ocfs2.h" ++#include "alloc.h" ++#include "dlmglue.h" ++#include "file.h" ++#include "ocfs2_fs.h" ++#include "xattr.h" ++ ++#define XATTR_TRUSTED_PREFIX "trusted." ++ ++static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, ++ size_t list_size, const char *name, ++ size_t name_len) ++{ ++ const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1; ++ const size_t total_len = prefix_len + name_len + 1; ++ ++ if (list && total_len <= list_size) { ++ memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); ++ memcpy(list + prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return total_len; ++} ++ ++static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name, ++ buffer, size); ++} ++ ++static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ ++ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value, ++ size, flags); ++} ++ ++struct xattr_handler ocfs2_xattr_trusted_handler = { ++ .prefix = XATTR_TRUSTED_PREFIX, ++ .list = ocfs2_xattr_trusted_list, ++ .get = ocfs2_xattr_trusted_get, ++ .set = ocfs2_xattr_trusted_set, ++}; +--- /dev/null ++++ b/fs/ocfs2/xattr_user.c +@@ -0,0 +1,94 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * xattr_user.c ++ * ++ * Copyright (C) 2008 Oracle. All rights reserved. ++ * ++ * CREDITS: ++ * Lots of code in this file is taken from ext3. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#define MLOG_MASK_PREFIX ML_INODE ++#include ++ ++#include "ocfs2.h" ++#include "alloc.h" ++#include "dlmglue.h" ++#include "file.h" ++#include "ocfs2_fs.h" ++#include "xattr.h" ++ ++#define XATTR_USER_PREFIX "user." ++ ++static size_t ocfs2_xattr_user_list(struct inode *inode, char *list, ++ size_t list_size, const char *name, ++ size_t name_len) ++{ ++ const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1; ++ const size_t total_len = prefix_len + name_len + 1; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) ++ return 0; ++ ++ if (list && total_len <= list_size) { ++ memcpy(list, XATTR_USER_PREFIX, prefix_len); ++ memcpy(list + prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return total_len; ++} ++ ++static int ocfs2_xattr_user_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) ++ return -EOPNOTSUPP; ++ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name, ++ buffer, size); ++} ++ ++static int ocfs2_xattr_user_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) ++ return -EOPNOTSUPP; ++ ++ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value, ++ size, flags); ++} ++ ++struct xattr_handler ocfs2_xattr_user_handler = { ++ .prefix = XATTR_USER_PREFIX, ++ .list = ocfs2_xattr_user_list, ++ .get = ocfs2_xattr_user_get, ++ .set = ocfs2_xattr_user_set, ++}; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extent-tree-operation-for-x.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extent-tree-operation-for-x.patch new file mode 100644 index 000000000..8515ee3ee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extent-tree-operation-for-x.patch @@ -0,0 +1,992 @@ +From: Tao Ma +Subject: [PATCH 07/16] ocfs2: Add extent tree operation for xattr value btrees +Patch-mainline: 2.6.28? +References: FATE302067 + +Add some thin wrappers around ocfs2_insert_extent() for each of the 3 +different btree types, ocfs2_inode_insert_extent(), +ocfs2_xattr_value_insert_extent() and ocfs2_xattr_tree_insert_extent(). The +last is for the xattr index btree, which will be used in a followup patch. + +All the old callers in file.c etc will call ocfs2_dinode_insert_extent(), +while the other two handle the xattr issue. And the init of extent tree are +handled by these functions. + +When storing xattr value which is too large, we will allocate some clusters +for it and here ocfs2_extent_list and ocfs2_extent_rec will also be used. In +order to re-use the b-tree operation code, a new parameter named "private" +is added into ocfs2_extent_tree and it is used to indicate the root of +ocfs2_exent_list. The reason is that we can't deduce the root from the +buffer_head now. It may be in an inode, an ocfs2_xattr_block or even worse, +in any place in an ocfs2_xattr_bucket. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/Makefile | 3 +- + fs/ocfs2/alloc.c | 184 +++++++++++++++++++++----- + fs/ocfs2/alloc.h | 42 ++++-- + fs/ocfs2/aops.c | 5 +- + fs/ocfs2/cluster/masklog.c | 1 + + fs/ocfs2/cluster/masklog.h | 1 + + fs/ocfs2/dir.c | 11 +- + fs/ocfs2/extent_map.c | 60 +++++++++ + fs/ocfs2/extent_map.h | 3 + + fs/ocfs2/file.c | 9 +- + fs/ocfs2/suballoc.c | 5 +- + fs/ocfs2/suballoc.h | 3 +- + fs/ocfs2/xattr.c | 305 ++++++++++++++++++++++++++++++++++++++++++++ + 13 files changed, 568 insertions(+), 64 deletions(-) + create mode 100644 fs/ocfs2/xattr.c + +Index: linux-2.6.26/fs/ocfs2/Makefile +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/Makefile ++++ linux-2.6.26/fs/ocfs2/Makefile +@@ -34,7 +34,8 @@ ocfs2-objs := \ + symlink.o \ + sysfile.o \ + uptodate.o \ +- ver.o ++ ver.o \ ++ xattr.o \ + + ocfs2_stackglue-objs := stackglue.o + ocfs2_stack_o2cb-objs := stack_o2cb.o +Index: linux-2.6.26/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/alloc.c ++++ linux-2.6.26/fs/ocfs2/alloc.c +@@ -78,6 +78,7 @@ struct ocfs2_extent_tree { + struct ocfs2_extent_tree_operations *eops; + struct buffer_head *root_bh; + struct ocfs2_extent_list *root_el; ++ void *private; + }; + + static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, +@@ -136,9 +137,50 @@ static struct ocfs2_extent_tree_operatio + .sanity_check = ocfs2_dinode_sanity_check, + }; + ++static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, ++ u64 blkno) ++{ ++ struct ocfs2_xattr_value_root *xv = ++ (struct ocfs2_xattr_value_root *)et->private; ++ ++ xv->xr_last_eb_blk = cpu_to_le64(blkno); ++} ++ ++static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_xattr_value_root *xv = ++ (struct ocfs2_xattr_value_root *) et->private; ++ ++ return le64_to_cpu(xv->xr_last_eb_blk); ++} ++ ++static void ocfs2_xattr_value_update_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 clusters) ++{ ++ struct ocfs2_xattr_value_root *xv = ++ (struct ocfs2_xattr_value_root *)et->private; ++ ++ le32_add_cpu(&xv->xr_clusters, clusters); ++} ++ ++static int ocfs2_xattr_value_sanity_check(struct inode *inode, ++ struct ocfs2_extent_tree *et) ++{ ++ return 0; ++} ++ ++static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { ++ .set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, ++ .get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, ++ .update_clusters = ocfs2_xattr_value_update_clusters, ++ .sanity_check = ocfs2_xattr_value_sanity_check, ++}; ++ + static struct ocfs2_extent_tree* + ocfs2_new_extent_tree(struct buffer_head *bh, +- enum ocfs2_extent_tree_type et_type) ++ enum ocfs2_extent_tree_type et_type, ++ void *private) + { + struct ocfs2_extent_tree *et; + +@@ -149,12 +191,16 @@ static struct ocfs2_extent_tree* + et->type = et_type; + get_bh(bh); + et->root_bh = bh; ++ et->private = private; + +- /* current we only support dinode extent. */ +- BUG_ON(et->type != OCFS2_DINODE_EXTENT); + if (et_type == OCFS2_DINODE_EXTENT) { + et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; + et->eops = &ocfs2_dinode_et_ops; ++ } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) { ++ struct ocfs2_xattr_value_root *xv = ++ (struct ocfs2_xattr_value_root *) private; ++ et->root_el = &xv->xr_list; ++ et->eops = &ocfs2_xattr_et_ops; + } + + return et; +@@ -495,7 +541,8 @@ struct ocfs2_merge_ctxt { + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, + struct buffer_head *root_bh, +- enum ocfs2_extent_tree_type type) ++ enum ocfs2_extent_tree_type type, ++ void *private) + { + int retval; + struct ocfs2_extent_list *el = NULL; +@@ -517,6 +564,12 @@ int ocfs2_num_free_extents(struct ocfs2_ + if (fe->i_last_eb_blk) + last_eb_blk = le64_to_cpu(fe->i_last_eb_blk); + el = &fe->id2.i_list; ++ } else if (type == OCFS2_XATTR_VALUE_EXTENT) { ++ struct ocfs2_xattr_value_root *xv = ++ (struct ocfs2_xattr_value_root *) private; ++ ++ last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk); ++ el = &xv->xr_list; + } + + if (last_eb_blk) { +@@ -4218,33 +4271,25 @@ out: + * + * The caller needs to update fe->i_clusters + */ +-int ocfs2_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac, +- enum ocfs2_extent_tree_type et_type) ++static int ocfs2_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac, ++ struct ocfs2_extent_tree *et) + { + int status; + int uninitialized_var(free_records); + struct buffer_head *last_eb_bh = NULL; + struct ocfs2_insert_type insert = {0, }; + struct ocfs2_extent_rec rec; +- struct ocfs2_extent_tree *et = NULL; + + BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); + +- et = ocfs2_new_extent_tree(root_bh, et_type); +- if (!et) { +- status = -ENOMEM; +- mlog_errno(status); +- goto bail; +- } +- + mlog(0, "add %u clusters at position %u to inode %llu\n", + new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); + +@@ -4296,9 +4341,68 @@ bail: + if (last_eb_bh) + brelse(last_eb_bh); + ++ mlog_exit(status); ++ return status; ++} ++ ++int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac) ++{ ++ int status; ++ struct ocfs2_extent_tree *et = NULL; ++ ++ et = ocfs2_new_extent_tree(root_bh, OCFS2_DINODE_EXTENT, NULL); ++ if (!et) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto bail; ++ } ++ ++ status = ocfs2_insert_extent(osb, handle, inode, root_bh, ++ cpos, start_blk, new_clusters, ++ flags, meta_ac, et); ++ + if (et) + ocfs2_free_extent_tree(et); +- mlog_exit(status); ++bail: ++ return status; ++} ++ ++int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac, ++ void *private) ++{ ++ int status; ++ struct ocfs2_extent_tree *et = NULL; ++ ++ et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_VALUE_EXTENT, private); ++ if (!et) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto bail; ++ } ++ ++ status = ocfs2_insert_extent(osb, handle, inode, root_bh, ++ cpos, start_blk, new_clusters, ++ flags, meta_ac, et); ++ ++ if (et) ++ ocfs2_free_extent_tree(et); ++bail: + return status; + } + +@@ -4320,7 +4424,8 @@ int ocfs2_add_clusters_in_btree(struct o + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + enum ocfs2_alloc_restarted *reason_ret, +- enum ocfs2_extent_tree_type type) ++ enum ocfs2_extent_tree_type type, ++ void *private) + { + int status = 0; + int free_extents; +@@ -4334,7 +4439,8 @@ int ocfs2_add_clusters_in_btree(struct o + if (mark_unwritten) + flags = OCFS2_EXT_UNWRITTEN; + +- free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type); ++ free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type, ++ private); + if (free_extents < 0) { + status = free_extents; + mlog_errno(status); +@@ -4381,9 +4487,16 @@ int ocfs2_add_clusters_in_btree(struct o + block = ocfs2_clusters_to_blocks(osb->sb, bit_off); + mlog(0, "Allocating %u clusters at block %u for inode %llu\n", + num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); +- status = ocfs2_insert_extent(osb, handle, inode, root_bh, +- *logical_offset, block, num_bits, +- flags, meta_ac, type); ++ if (type == OCFS2_DINODE_EXTENT) ++ status = ocfs2_dinode_insert_extent(osb, handle, inode, root_bh, ++ *logical_offset, block, ++ num_bits, flags, meta_ac); ++ else ++ status = ocfs2_xattr_value_insert_extent(osb, handle, ++ inode, root_bh, ++ *logical_offset, ++ block, num_bits, flags, ++ meta_ac, private); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -4664,7 +4777,8 @@ int ocfs2_mark_extent_written(struct ino + handle_t *handle, u32 cpos, u32 len, u32 phys, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type) ++ enum ocfs2_extent_tree_type et_type, ++ void *private) + { + int ret, index; + u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); +@@ -4685,7 +4799,7 @@ int ocfs2_mark_extent_written(struct ino + goto out; + } + +- et = ocfs2_new_extent_tree(root_bh, et_type); ++ et = ocfs2_new_extent_tree(root_bh, et_type, private); + if (!et) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4973,7 +5087,8 @@ int ocfs2_remove_extent(struct inode *in + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type) ++ enum ocfs2_extent_tree_type et_type, ++ void *private) + { + int ret, index; + u32 rec_range, trunc_range; +@@ -4982,7 +5097,7 @@ int ocfs2_remove_extent(struct inode *in + struct ocfs2_path *path = NULL; + struct ocfs2_extent_tree *et = NULL; + +- et = ocfs2_new_extent_tree(root_bh, et_type); ++ et = ocfs2_new_extent_tree(root_bh, et_type, private); + if (!et) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -6617,9 +6732,8 @@ int ocfs2_convert_inline_data_to_extents + * this proves to be false, we could always re-build + * the in-inode data from our pages. + */ +- ret = ocfs2_insert_extent(osb, handle, inode, di_bh, +- 0, block, 1, 0, +- NULL, OCFS2_DINODE_EXTENT); ++ ret = ocfs2_dinode_insert_extent(osb, handle, inode, di_bh, ++ 0, block, 1, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; +Index: linux-2.6.26/fs/ocfs2/alloc.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/alloc.h ++++ linux-2.6.26/fs/ocfs2/alloc.h +@@ -28,19 +28,29 @@ + + enum ocfs2_extent_tree_type { + OCFS2_DINODE_EXTENT = 0, ++ OCFS2_XATTR_VALUE_EXTENT, + }; + + struct ocfs2_alloc_context; +-int ocfs2_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac, +- enum ocfs2_extent_tree_type et_type); ++int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac); ++int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac, ++ void *private); + enum ocfs2_alloc_restarted { + RESTART_NONE = 0, + RESTART_TRANS, +@@ -57,22 +67,26 @@ int ocfs2_add_clusters_in_btree(struct o + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + enum ocfs2_alloc_restarted *reason_ret, +- enum ocfs2_extent_tree_type type); ++ enum ocfs2_extent_tree_type type, ++ void *private); + struct ocfs2_cached_dealloc_ctxt; + int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + handle_t *handle, u32 cpos, u32 len, u32 phys, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type); ++ enum ocfs2_extent_tree_type et_type, ++ void *private); + int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type); ++ enum ocfs2_extent_tree_type et_type, ++ void *private); + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, + struct buffer_head *root_bh, +- enum ocfs2_extent_tree_type et_type); ++ enum ocfs2_extent_tree_type et_type, ++ void *private); + + /* + * how many new metadata chunks would an allocation need at maximum? +Index: linux-2.6.26/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/aops.c ++++ linux-2.6.26/fs/ocfs2/aops.c +@@ -1279,7 +1279,7 @@ static int ocfs2_write_cluster(struct ad + ret = ocfs2_mark_extent_written(inode, wc->w_di_bh, + wc->w_handle, cpos, 1, phys, + meta_ac, &wc->w_dealloc, +- OCFS2_DINODE_EXTENT); ++ OCFS2_DINODE_EXTENT, NULL); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1721,7 +1721,8 @@ int ocfs2_write_begin_nolock(struct addr + + ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list, + clusters_to_alloc, extents_to_split, +- &data_ac, &meta_ac); ++ &data_ac, &meta_ac, ++ OCFS2_DINODE_EXTENT, NULL); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.26/fs/ocfs2/cluster/masklog.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/cluster/masklog.c ++++ linux-2.6.26/fs/ocfs2/cluster/masklog.c +@@ -109,6 +109,7 @@ static struct mlog_attribute mlog_attrs[ + define_mask(CONN), + define_mask(QUORUM), + define_mask(EXPORT), ++ define_mask(XATTR), + define_mask(ERROR), + define_mask(NOTICE), + define_mask(KTHREAD), +Index: linux-2.6.26/fs/ocfs2/cluster/masklog.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/cluster/masklog.h ++++ linux-2.6.26/fs/ocfs2/cluster/masklog.h +@@ -112,6 +112,7 @@ + #define ML_CONN 0x0000000004000000ULL /* net connection management */ + #define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */ + #define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */ ++#define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */ + /* bits that are infrequently given and frequently matched in the high word */ + #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ + #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ +Index: linux-2.6.26/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/dir.c ++++ linux-2.6.26/fs/ocfs2/dir.c +@@ -1305,8 +1305,8 @@ static int ocfs2_expand_inline_dir(struc + * This should never fail as our extent list is empty and all + * related blocks have been journaled already. + */ +- ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0, +- NULL, OCFS2_DINODE_EXTENT); ++ ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 0, blkno, ++ len, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1337,8 +1337,8 @@ static int ocfs2_expand_inline_dir(struc + } + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + +- ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno, +- len, 0, NULL, OCFS2_DINODE_EXTENT); ++ ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 1, ++ blkno, len, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1482,7 +1482,8 @@ static int ocfs2_extend_dir(struct ocfs2 + spin_unlock(&OCFS2_I(dir)->ip_lock); + num_free_extents = ocfs2_num_free_extents(osb, dir, + parent_fe_bh, +- OCFS2_DINODE_EXTENT); ++ OCFS2_DINODE_EXTENT, ++ NULL); + if (num_free_extents < 0) { + status = num_free_extents; + mlog_errno(status); +Index: linux-2.6.26/fs/ocfs2/extent_map.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/extent_map.c ++++ linux-2.6.26/fs/ocfs2/extent_map.c +@@ -373,6 +373,66 @@ out: + return ret; + } + ++int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, ++ u32 *p_cluster, u32 *num_clusters, ++ struct ocfs2_extent_list *el) ++{ ++ int ret = 0, i; ++ struct buffer_head *eb_bh = NULL; ++ struct ocfs2_extent_block *eb; ++ struct ocfs2_extent_rec *rec; ++ u32 coff; ++ ++ if (el->l_tree_depth) { ++ ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ eb = (struct ocfs2_extent_block *) eb_bh->b_data; ++ el = &eb->h_list; ++ ++ if (el->l_tree_depth) { ++ ocfs2_error(inode->i_sb, ++ "Inode %lu has non zero tree depth in " ++ "xattr leaf block %llu\n", inode->i_ino, ++ (unsigned long long)eb_bh->b_blocknr); ++ ret = -EROFS; ++ goto out; ++ } ++ } ++ ++ i = ocfs2_search_extent_list(el, v_cluster); ++ if (i == -1) { ++ ret = -EROFS; ++ mlog_errno(ret); ++ goto out; ++ } else { ++ rec = &el->l_recs[i]; ++ BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); ++ ++ if (!rec->e_blkno) { ++ ocfs2_error(inode->i_sb, "Inode %lu has bad extent " ++ "record (%u, %u, 0) in xattr", inode->i_ino, ++ le32_to_cpu(rec->e_cpos), ++ ocfs2_rec_clusters(el, rec)); ++ ret = -EROFS; ++ goto out; ++ } ++ coff = v_cluster - le32_to_cpu(rec->e_cpos); ++ *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, ++ le64_to_cpu(rec->e_blkno)); ++ *p_cluster = *p_cluster + coff; ++ if (num_clusters) ++ *num_clusters = ocfs2_rec_clusters(el, rec) - coff; ++ } ++out: ++ if (eb_bh) ++ brelse(eb_bh); ++ return ret; ++} ++ + int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, + u32 *p_cluster, u32 *num_clusters, + unsigned int *extent_flags) +Index: linux-2.6.26/fs/ocfs2/extent_map.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/extent_map.h ++++ linux-2.6.26/fs/ocfs2/extent_map.h +@@ -50,4 +50,7 @@ int ocfs2_get_clusters(struct inode *ino + int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, + u64 *ret_count, unsigned int *extent_flags); + ++int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, ++ u32 *p_cluster, u32 *num_clusters, ++ struct ocfs2_extent_list *el); + #endif /* _EXTENT_MAP_H */ +Index: linux-2.6.26/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/file.c ++++ linux-2.6.26/fs/ocfs2/file.c +@@ -515,7 +515,7 @@ int ocfs2_add_inode_data(struct ocfs2_su + clusters_to_add, mark_unwritten, + fe_bh, el, handle, + data_ac, meta_ac, reason_ret, +- OCFS2_DINODE_EXTENT); ++ OCFS2_DINODE_EXTENT, NULL); + } + + static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, +@@ -565,7 +565,7 @@ restart_all: + clusters_to_add); + status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list, + clusters_to_add, 0, &data_ac, +- &meta_ac); ++ &meta_ac, OCFS2_DINODE_EXTENT, NULL); + if (status) { + mlog_errno(status); + goto leave; +@@ -1237,7 +1237,8 @@ static int __ocfs2_remove_inode_range(st + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list, +- 0, 1, NULL, &meta_ac); ++ 0, 1, NULL, &meta_ac, ++ OCFS2_DINODE_EXTENT, NULL); + if (ret) { + mlog_errno(ret); + return ret; +@@ -1268,7 +1269,7 @@ static int __ocfs2_remove_inode_range(st + } + + ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac, +- dealloc, OCFS2_DINODE_EXTENT); ++ dealloc, OCFS2_DINODE_EXTENT, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; +Index: linux-2.6.26/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.26/fs/ocfs2/suballoc.c +@@ -1906,7 +1906,8 @@ int ocfs2_lock_allocators(struct inode * + struct ocfs2_extent_list *root_el, + u32 clusters_to_add, u32 extents_to_split, + struct ocfs2_alloc_context **data_ac, +- struct ocfs2_alloc_context **meta_ac) ++ struct ocfs2_alloc_context **meta_ac, ++ enum ocfs2_extent_tree_type type, void *private) + { + int ret = 0, num_free_extents; + unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; +@@ -1919,7 +1920,7 @@ int ocfs2_lock_allocators(struct inode * + BUG_ON(clusters_to_add != 0 && data_ac == NULL); + + num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh, +- OCFS2_DINODE_EXTENT); ++ type, private); + if (num_free_extents < 0) { + ret = num_free_extents; + mlog_errno(ret); +Index: linux-2.6.26/fs/ocfs2/suballoc.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.h ++++ linux-2.6.26/fs/ocfs2/suballoc.h +@@ -165,5 +165,6 @@ int ocfs2_lock_allocators(struct inode * + struct ocfs2_extent_list *root_el, + u32 clusters_to_add, u32 extents_to_split, + struct ocfs2_alloc_context **data_ac, +- struct ocfs2_alloc_context **meta_ac); ++ struct ocfs2_alloc_context **meta_ac, ++ enum ocfs2_extent_tree_type type, void *private); + #endif /* _CHAINALLOC_H_ */ +Index: linux-2.6.26/fs/ocfs2/xattr.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/ocfs2/xattr.c +@@ -0,0 +1,305 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * xattr.c ++ * ++ * Copyright (C) 2008 Oracle. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ */ ++ ++#define MLOG_MASK_PREFIX ML_XATTR ++#include ++ ++#include "ocfs2.h" ++#include "alloc.h" ++#include "dlmglue.h" ++#include "file.h" ++#include "inode.h" ++#include "journal.h" ++#include "ocfs2_fs.h" ++#include "suballoc.h" ++#include "uptodate.h" ++#include "buffer_head_io.h" ++ ++static int ocfs2_xattr_extend_allocation(struct inode *inode, ++ u32 clusters_to_add, ++ struct buffer_head *xattr_bh, ++ struct ocfs2_xattr_value_root *xv) ++{ ++ int status = 0; ++ int restart_func = 0; ++ int credits = 0; ++ handle_t *handle = NULL; ++ struct ocfs2_alloc_context *data_ac = NULL; ++ struct ocfs2_alloc_context *meta_ac = NULL; ++ enum ocfs2_alloc_restarted why; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_extent_list *root_el = &xv->xr_list; ++ u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters); ++ ++ mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add); ++ ++restart_all: ++ ++ status = ocfs2_lock_allocators(inode, xattr_bh, root_el, ++ clusters_to_add, 0, &data_ac, ++ &meta_ac, OCFS2_XATTR_VALUE_EXTENT, xv); ++ if (status) { ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add); ++ handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ handle = NULL; ++ mlog_errno(status); ++ goto leave; ++ } ++ ++restarted_transaction: ++ status = ocfs2_journal_access(handle, inode, xattr_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ prev_clusters = le32_to_cpu(xv->xr_clusters); ++ status = ocfs2_add_clusters_in_btree(osb, ++ inode, ++ &logical_start, ++ clusters_to_add, ++ 0, ++ xattr_bh, ++ root_el, ++ handle, ++ data_ac, ++ meta_ac, ++ &why, ++ OCFS2_XATTR_VALUE_EXTENT, ++ xv); ++ if ((status < 0) && (status != -EAGAIN)) { ++ if (status != -ENOSPC) ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ status = ocfs2_journal_dirty(handle, xattr_bh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters; ++ ++ if (why != RESTART_NONE && clusters_to_add) { ++ if (why == RESTART_META) { ++ mlog(0, "restarting function.\n"); ++ restart_func = 1; ++ } else { ++ BUG_ON(why != RESTART_TRANS); ++ ++ mlog(0, "restarting transaction.\n"); ++ /* TODO: This can be more intelligent. */ ++ credits = ocfs2_calc_extend_credits(osb->sb, ++ root_el, ++ clusters_to_add); ++ status = ocfs2_extend_trans(handle, credits); ++ if (status < 0) { ++ /* handle still has to be committed at ++ * this point. */ ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto leave; ++ } ++ goto restarted_transaction; ++ } ++ } ++ ++leave: ++ if (handle) { ++ ocfs2_commit_trans(osb, handle); ++ handle = NULL; ++ } ++ if (data_ac) { ++ ocfs2_free_alloc_context(data_ac); ++ data_ac = NULL; ++ } ++ if (meta_ac) { ++ ocfs2_free_alloc_context(meta_ac); ++ meta_ac = NULL; ++ } ++ if ((!status) && restart_func) { ++ restart_func = 0; ++ goto restart_all; ++ } ++ ++ return status; ++} ++ ++static int __ocfs2_remove_xattr_range(struct inode *inode, ++ struct buffer_head *root_bh, ++ struct ocfs2_xattr_value_root *xv, ++ u32 cpos, u32 phys_cpos, u32 len, ++ struct ocfs2_cached_dealloc_ctxt *dealloc) ++{ ++ int ret; ++ u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct inode *tl_inode = osb->osb_tl_inode; ++ handle_t *handle; ++ struct ocfs2_alloc_context *meta_ac = NULL; ++ ++ ret = ocfs2_lock_allocators(inode, root_bh, &xv->xr_list, ++ 0, 1, NULL, &meta_ac, ++ OCFS2_XATTR_VALUE_EXTENT, xv); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ mutex_lock(&tl_inode->i_mutex); ++ ++ if (ocfs2_truncate_log_needs_flush(osb)) { ++ ret = __ocfs2_flush_truncate_log(osb); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, root_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac, ++ dealloc, OCFS2_XATTR_VALUE_EXTENT, xv); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ le32_add_cpu(&xv->xr_clusters, -len); ++ ++ ret = ocfs2_journal_dirty(handle, root_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len); ++ if (ret) ++ mlog_errno(ret); ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ mutex_unlock(&tl_inode->i_mutex); ++ ++ if (meta_ac) ++ ocfs2_free_alloc_context(meta_ac); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_shrink_size(struct inode *inode, ++ u32 old_clusters, ++ u32 new_clusters, ++ struct buffer_head *root_bh, ++ struct ocfs2_xattr_value_root *xv) ++{ ++ int ret = 0; ++ u32 trunc_len, cpos, phys_cpos, alloc_size; ++ u64 block; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_cached_dealloc_ctxt dealloc; ++ ++ ocfs2_init_dealloc_ctxt(&dealloc); ++ ++ if (old_clusters <= new_clusters) ++ return 0; ++ ++ cpos = new_clusters; ++ trunc_len = old_clusters - new_clusters; ++ while (trunc_len) { ++ ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos, ++ &alloc_size, &xv->xr_list); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ if (alloc_size > trunc_len) ++ alloc_size = trunc_len; ++ ++ ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos, ++ phys_cpos, alloc_size, ++ &dealloc); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); ++ ocfs2_remove_xattr_clusters_from_cache(inode, block, ++ alloc_size); ++ cpos += alloc_size; ++ trunc_len -= alloc_size; ++ } ++ ++out: ++ ocfs2_schedule_truncate_log_flush(osb, 1); ++ ocfs2_run_deallocs(osb, &dealloc); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_value_truncate(struct inode *inode, ++ struct buffer_head *root_bh, ++ struct ocfs2_xattr_value_root *xv, ++ int len) ++{ ++ int ret; ++ u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len); ++ u32 old_clusters = le32_to_cpu(xv->xr_clusters); ++ ++ if (new_clusters == old_clusters) ++ return 0; ++ ++ if (new_clusters > old_clusters) ++ ret = ocfs2_xattr_extend_allocation(inode, ++ new_clusters - old_clusters, ++ root_bh, xv); ++ else ++ ret = ocfs2_xattr_shrink_size(inode, ++ old_clusters, new_clusters, ++ root_bh, xv); ++ ++ return ret; ++} diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-helper-function-in-uptodate.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-helper-function-in-uptodate.patch new file mode 100644 index 000000000..9688b4ecc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-helper-function-in-uptodate.patch @@ -0,0 +1,85 @@ +From: Tao Ma +Subject: [PATCH 06/16] ocfs2: Add helper function in uptodate.c for removing xattr clusters +Patch-mainline: 2.6.28? +References: FATE302067 + +The old uptodate only handles the issue of removing one buffer_head from +ocfs2 inode's buffer cache. With xattr clusters, we may need to remove +multiple buffer_head's at a time. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/uptodate.c | 32 ++++++++++++++++++++++++++------ + fs/ocfs2/uptodate.h | 3 +++ + 2 files changed, 29 insertions(+), 6 deletions(-) + +diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c +index 4da8851..e26459e 100644 +--- a/fs/ocfs2/uptodate.c ++++ b/fs/ocfs2/uptodate.c +@@ -511,14 +511,10 @@ static void ocfs2_remove_metadata_tree(struct ocfs2_caching_info *ci, + ci->ci_num_cached--; + } + +-/* Called when we remove a chunk of metadata from an inode. We don't +- * bother reverting things to an inlined array in the case of a remove +- * which moves us back under the limit. */ +-void ocfs2_remove_from_cache(struct inode *inode, +- struct buffer_head *bh) ++static void ocfs2_remove_block_from_cache(struct inode *inode, ++ sector_t block) + { + int index; +- sector_t block = bh->b_blocknr; + struct ocfs2_meta_cache_item *item = NULL; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_caching_info *ci = &oi->ip_metadata_cache; +@@ -544,6 +540,30 @@ void ocfs2_remove_from_cache(struct inode *inode, + kmem_cache_free(ocfs2_uptodate_cachep, item); + } + ++/* ++ * Called when we remove a chunk of metadata from an inode. We don't ++ * bother reverting things to an inlined array in the case of a remove ++ * which moves us back under the limit. ++ */ ++void ocfs2_remove_from_cache(struct inode *inode, ++ struct buffer_head *bh) ++{ ++ sector_t block = bh->b_blocknr; ++ ++ ocfs2_remove_block_from_cache(inode, block); ++} ++ ++/* Called when we remove xattr clusters from an inode. */ ++void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode, ++ sector_t block, ++ u32 c_len) ++{ ++ u64 i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len; ++ ++ for (i = 0; i < b_len; i++, block++) ++ ocfs2_remove_block_from_cache(inode, block); ++} ++ + int __init init_ocfs2_uptodate_cache(void) + { + ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate", +diff --git a/fs/ocfs2/uptodate.h b/fs/ocfs2/uptodate.h +index 2e73206..531b4b3 100644 +--- a/fs/ocfs2/uptodate.h ++++ b/fs/ocfs2/uptodate.h +@@ -40,6 +40,9 @@ void ocfs2_set_new_buffer_uptodate(struct inode *inode, + struct buffer_head *bh); + void ocfs2_remove_from_cache(struct inode *inode, + struct buffer_head *bh); ++void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode, ++ sector_t block, ++ u32 c_len); + int ocfs2_buffer_read_ahead(struct inode *inode, + struct buffer_head *bh); + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-incompatible-flag-for-exten.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-incompatible-flag-for-exten.patch new file mode 100644 index 000000000..909927831 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-incompatible-flag-for-exten.patch @@ -0,0 +1,148 @@ +From: Tiger Yang +Subject: [PATCH 16/16] ocfs2: Add incompatible flag for extended attribute +Patch-mainline: 2.6.28? +References: FATE302067 + +This patch adds the s_incompat flag for extended attribute support. This +helps us ensure that older versions of Ocfs2 or ocfs2-tools will not be able +to mount a volume with xattr support. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/ocfs2.h | 7 +++++++ + fs/ocfs2/ocfs2_fs.h | 19 +++++++++++++------ + fs/ocfs2/super.c | 3 ++- + fs/ocfs2/xattr.c | 12 ++++++++++++ + 4 files changed, 34 insertions(+), 7 deletions(-) + +diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h +index 35ed7eb..487487a 100644 +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -343,6 +343,13 @@ static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb) + return 0; + } + ++static inline int ocfs2_supports_xattr(struct ocfs2_super *osb) ++{ ++ if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR) ++ return 1; ++ return 0; ++} ++ + /* set / clear functions because cluster events can make these happen + * in parallel so we want the transitions to be atomic. this also + * means that any future flags osb_flags must be protected by spinlock +diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h +index 8d5e72f..f24ce3d 100644 +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -91,7 +91,8 @@ + | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \ + | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \ + | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \ +- | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK) ++ | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ ++ | OCFS2_FEATURE_INCOMPAT_XATTR) + #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN + + /* +@@ -128,10 +129,6 @@ + /* Support for data packed into inode blocks */ + #define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040 + +-/* Support for the extended slot map */ +-#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100 +- +- + /* + * Support for alternate, userspace cluster stacks. If set, the superblock + * field s_cluster_info contains a tag for the alternate stack in use as +@@ -143,6 +140,12 @@ + */ + #define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK 0x0080 + ++/* Support for the extended slot map */ ++#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100 ++ ++/* Support for extended attributes */ ++#define OCFS2_FEATURE_INCOMPAT_XATTR 0x0200 ++ + /* + * backup superblock flag is used to indicate that this volume + * has backup superblocks. +@@ -578,7 +581,11 @@ struct ocfs2_super_block { + /*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Selected userspace + stack. Only valid + with INCOMPAT flag. */ +-/*B8*/ __le64 s_reserved2[17]; /* Fill out superblock */ ++/*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size ++ for this fs*/ ++ __le16 s_reserved0; ++ __le32 s_reserved1; ++/*C0*/ __le64 s_reserved2[16]; /* Fill out superblock */ + /*140*/ + + /* +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 03a25c4..2173169 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -1434,7 +1434,8 @@ static int ocfs2_initialize_super(struct super_block *sb, + + osb->slot_num = OCFS2_INVALID_SLOT; + +- osb->s_xattr_inline_size = OCFS2_MIN_XATTR_INLINE_SIZE; ++ osb->s_xattr_inline_size = le16_to_cpu( ++ di->id2.i_super.s_xattr_inline_size); + + osb->local_alloc_state = OCFS2_LA_UNUSED; + osb->local_alloc_bh = NULL; +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index e78ed7a..505fb40 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -580,6 +580,9 @@ ssize_t ocfs2_listxattr(struct dentry *dentry, + struct ocfs2_dinode *di = NULL; + struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode); + ++ if (!ocfs2_supports_xattr(OCFS2_SB(dentry->d_sb))) ++ return -EOPNOTSUPP; ++ + if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) + return ret; + +@@ -859,6 +862,9 @@ int ocfs2_xattr_get(struct inode *inode, + .not_found = -ENODATA, + }; + ++ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb))) ++ return -EOPNOTSUPP; ++ + if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) + ret = -ENODATA; + +@@ -1557,6 +1563,9 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) + handle_t *handle; + int ret; + ++ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb))) ++ return 0; ++ + if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) + return 0; + +@@ -1993,6 +2002,9 @@ int ocfs2_xattr_set(struct inode *inode, + .not_found = -ENODATA, + }; + ++ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb))) ++ return -EOPNOTSUPP; ++ + ret = ocfs2_inode_lock(inode, &di_bh, 1); + if (ret < 0) { + mlog_errno(ret); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-quota-calls-for-allocation-and-freeing-of.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-quota-calls-for-allocation-and-freeing-of.patch new file mode 100644 index 000000000..f95388a78 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-quota-calls-for-allocation-and-freeing-of.patch @@ -0,0 +1,785 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 25/28] ocfs2: Add quota calls for allocation and freeing of inodes and space +Patch-mainline: 2.6.29? + +Add quota calls for allocation and freeing of inodes and space, also update +estimates on number of needed credits for a transaction. Move out inode +allocation from ocfs2_mknod_locked() because vfs_dq_init() must be called +outside of a transaction. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/alloc.c | 18 ++++++- + fs/ocfs2/aops.c | 16 +++++- + fs/ocfs2/dir.c | 24 ++++++++- + fs/ocfs2/file.c | 70 ++++++++++++++++++++++-- + fs/ocfs2/inode.c | 10 +++- + fs/ocfs2/journal.h | 99 ++++++++++++++++++++++++---------- + fs/ocfs2/namei.c | 151 +++++++++++++++++++++++++++++++++++---------------- + 7 files changed, 296 insertions(+), 92 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_DISK_ALLOC + #include +@@ -5292,7 +5293,7 @@ int ocfs2_remove_btree_range(struct inod + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); +@@ -6523,6 +6524,8 @@ static int ocfs2_do_truncate(struct ocfs + goto bail; + } + ++ vfs_dq_free_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, clusters_to_del)); + spin_lock(&OCFS2_I(inode)->ip_lock); + OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) - + clusters_to_del; +@@ -6836,6 +6839,7 @@ int ocfs2_convert_inline_data_to_extents + struct page **pages = NULL; + loff_t end = osb->s_clustersize; + struct ocfs2_extent_tree et; ++ int did_quota = 0; + + has_data = i_size_read(inode) ? 1 : 0; + +@@ -6855,7 +6859,8 @@ int ocfs2_convert_inline_data_to_extents + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS); ++ handle = ocfs2_start_trans(osb, ++ ocfs2_inline_to_extents_credits(osb->sb)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); +@@ -6874,6 +6879,13 @@ int ocfs2_convert_inline_data_to_extents + unsigned int page_end; + u64 phys; + ++ if (vfs_dq_alloc_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, 1))) { ++ ret = -EDQUOT; ++ goto out_commit; ++ } ++ did_quota = 1; ++ + ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, + &num); + if (ret) { +@@ -6947,6 +6959,10 @@ int ocfs2_convert_inline_data_to_extents + } + + out_commit: ++ if (ret < 0 && did_quota) ++ vfs_dq_free_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, 1)); ++ + ocfs2_commit_trans(osb, handle); + + out_unlock: +Index: linux-2.6.27-ocfs2/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/aops.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/aops.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_FILE_IO + #include +@@ -1750,6 +1751,11 @@ int ocfs2_write_begin_nolock(struct addr + + wc->w_handle = handle; + ++ if (clusters_to_alloc && vfs_dq_alloc_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc))) { ++ ret = -EDQUOT; ++ goto out_commit; ++ } + /* + * We don't want this to fail in ocfs2_write_end(), so do it + * here. +@@ -1758,7 +1764,7 @@ int ocfs2_write_begin_nolock(struct addr + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out_quota; + } + + /* +@@ -1771,14 +1777,14 @@ int ocfs2_write_begin_nolock(struct addr + mmap_page); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out_quota; + } + + ret = ocfs2_write_cluster_by_desc(mapping, data_ac, meta_ac, wc, pos, + len); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out_quota; + } + + if (data_ac) +@@ -1790,6 +1796,10 @@ success: + *pagep = wc->w_target_page; + *fsdata = wc; + return 0; ++out_quota: ++ if (clusters_to_alloc) ++ vfs_dq_free_space(inode, ++ ocfs2_clusters_to_bytes(osb->sb, clusters_to_alloc)); + out_commit: + ocfs2_commit_trans(osb, handle); + +Index: linux-2.6.27-ocfs2/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dir.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/dir.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_NAMEI + #include +@@ -1216,9 +1217,9 @@ static int ocfs2_expand_inline_dir(struc + unsigned int blocks_wanted, + struct buffer_head **first_block_bh) + { +- int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS; + u32 alloc, bit_off, len; + struct super_block *sb = dir->i_sb; ++ int ret, credits = ocfs2_inline_to_extents_credits(sb); + u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits; + struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(dir); +@@ -1227,6 +1228,7 @@ static int ocfs2_expand_inline_dir(struc + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + handle_t *handle; + struct ocfs2_extent_tree et; ++ int did_quota = 0; + + ocfs2_init_dinode_extent_tree(&et, dir, di_bh); + +@@ -1264,6 +1266,12 @@ static int ocfs2_expand_inline_dir(struc + goto out_sem; + } + ++ if (vfs_dq_alloc_space_nodirty(dir, ++ ocfs2_clusters_to_bytes(osb->sb, alloc))) { ++ ret = -EDQUOT; ++ goto out_commit; ++ } ++ did_quota = 1; + /* + * Try to claim as many clusters as the bitmap can give though + * if we only get one now, that's enough to continue. The rest +@@ -1386,6 +1394,9 @@ static int ocfs2_expand_inline_dir(struc + dirdata_bh = NULL; + + out_commit: ++ if (ret < 0 && did_quota) ++ vfs_dq_free_space_nodirty(dir, ++ ocfs2_clusters_to_bytes(osb->sb, 2)); + ocfs2_commit_trans(osb, handle); + + out_sem: +@@ -1410,7 +1421,7 @@ static int ocfs2_do_extend_dir(struct su + struct buffer_head **new_bh) + { + int status; +- int extend; ++ int extend, did_quota = 0; + u64 p_blkno, v_blkno; + + spin_lock(&OCFS2_I(dir)->ip_lock); +@@ -1420,6 +1431,13 @@ static int ocfs2_do_extend_dir(struct su + if (extend) { + u32 offset = OCFS2_I(dir)->ip_clusters; + ++ if (vfs_dq_alloc_space_nodirty(dir, ++ ocfs2_clusters_to_bytes(sb, 1))) { ++ status = -EDQUOT; ++ goto bail; ++ } ++ did_quota = 1; ++ + status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset, + 1, 0, parent_fe_bh, handle, + data_ac, meta_ac, NULL); +@@ -1445,6 +1463,8 @@ static int ocfs2_do_extend_dir(struct su + } + status = 0; + bail: ++ if (did_quota && status < 0) ++ vfs_dq_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1)); + mlog_exit(status); + return status; + } +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_INODE + #include +@@ -57,6 +58,7 @@ + #include "super.h" + #include "xattr.h" + #include "acl.h" ++#include "quota.h" + + #include "buffer_head_io.h" + +@@ -537,6 +539,8 @@ static int __ocfs2_extend_allocation(str + enum ocfs2_alloc_restarted why; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_extent_tree et; ++ u32 total_clusters = clusters_to_add; ++ int did_quota = 0; + + mlog_entry("(clusters_to_add = %u)\n", clusters_to_add); + +@@ -585,6 +589,12 @@ restart_all: + goto leave; + } + ++ if (!did_quota && vfs_dq_alloc_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, total_clusters))) { ++ status = -EDQUOT; ++ goto leave; ++ } ++ did_quota = 1; + restarted_transaction: + /* reserve a write to the file entry early on - that we if we + * run out of credits in the allocation path, we can still +@@ -655,6 +665,9 @@ restarted_transaction: + OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode)); + + leave: ++ if (status < 0 && did_quota) ++ vfs_dq_free_space(inode, ++ ocfs2_clusters_to_bytes(osb->sb, total_clusters)); + if (handle) { + ocfs2_commit_trans(osb, handle); + handle = NULL; +@@ -886,6 +899,9 @@ int ocfs2_setattr(struct dentry *dentry, + struct ocfs2_super *osb = OCFS2_SB(sb); + struct buffer_head *bh = NULL; + handle_t *handle = NULL; ++ int locked[MAXQUOTAS] = {0, 0}; ++ int credits, qtype; ++ struct ocfs2_mem_dqinfo *oinfo; + + mlog_entry("(0x%p, '%.*s')\n", dentry, + dentry->d_name.len, dentry->d_name.name); +@@ -956,11 +972,47 @@ int ocfs2_setattr(struct dentry *dentry, + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); +- if (IS_ERR(handle)) { +- status = PTR_ERR(handle); +- mlog_errno(status); +- goto bail_unlock; ++ if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || ++ (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { ++ credits = OCFS2_INODE_UPDATE_CREDITS; ++ if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid ++ && OCFS2_HAS_RO_COMPAT_FEATURE(sb, ++ OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { ++ oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv; ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto bail_unlock; ++ credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) + ++ ocfs2_calc_qdel_credits(sb, USRQUOTA); ++ locked[USRQUOTA] = 1; ++ } ++ if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid ++ && OCFS2_HAS_RO_COMPAT_FEATURE(sb, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { ++ oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv; ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto bail_unlock; ++ credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) + ++ ocfs2_calc_qdel_credits(sb, GRPQUOTA); ++ locked[GRPQUOTA] = 1; ++ } ++ handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto bail_unlock; ++ } ++ status = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0; ++ if (status < 0) ++ goto bail_commit; ++ } else { ++ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto bail_unlock; ++ } + } + + /* +@@ -983,6 +1035,12 @@ int ocfs2_setattr(struct dentry *dentry, + bail_commit: + ocfs2_commit_trans(osb, handle); + bail_unlock: ++ for (qtype = 0; qtype < MAXQUOTAS; qtype++) { ++ if (!locked[qtype]) ++ continue; ++ oinfo = sb_dqinfo(sb, qtype)->dqi_priv; ++ ocfs2_unlock_global_qf(oinfo, 1); ++ } + ocfs2_inode_unlock(inode, 1); + bail_unlock_rw: + if (size_change) +Index: linux-2.6.27-ocfs2/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/inode.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/inode.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + +@@ -619,7 +620,8 @@ static int ocfs2_remove_inode(struct ino + goto bail; + } + +- handle = ocfs2_start_trans(osb, OCFS2_DELETE_INODE_CREDITS); ++ handle = ocfs2_start_trans(osb, OCFS2_DELETE_INODE_CREDITS + ++ ocfs2_quota_trans_credits(inode->i_sb)); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); +@@ -651,6 +653,7 @@ static int ocfs2_remove_inode(struct ino + } + + ocfs2_remove_from_cache(inode, di_bh); ++ vfs_dq_free_inode(inode); + + status = ocfs2_free_dinode(handle, inode_alloc_inode, + inode_alloc_bh, di); +@@ -933,7 +936,10 @@ void ocfs2_delete_inode(struct inode *in + + mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); + +- if (is_bad_inode(inode)) { ++ /* When we fail in read_inode() we mark inode as bad. The second test ++ * catches the case when inode allocation fails before allocating ++ * a block for inode. */ ++ if (is_bad_inode(inode) || !OCFS2_I(inode)->ip_blkno) { + mlog(0, "Skipping delete of bad inode\n"); + goto bail; + } +Index: linux-2.6.27-ocfs2/fs/ocfs2/journal.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/journal.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/journal.h +@@ -293,6 +293,37 @@ int ocfs2_journal_dirty + /* extended attribute block update */ + #define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1 + ++/* global quotafile inode update, data block */ ++#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) ++ ++/* ++ * The two writes below can accidentally see global info dirty due ++ * to set_info() quotactl so make them prepared for the writes. ++ */ ++/* quota data block, global info */ ++/* Write to local quota file */ ++#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) ++ ++/* global quota data block, local quota data block, global quota inode, ++ * global quota info */ ++#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) ++ ++static inline int ocfs2_quota_trans_credits(struct super_block *sb) ++{ ++ int credits = 0; ++ ++ if (OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) ++ credits += OCFS2_QWRITE_CREDITS; ++ if (OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) ++ credits += OCFS2_QWRITE_CREDITS; ++ return credits; ++} ++ ++/* Number of credits needed for removing quota structure from file */ ++int ocfs2_calc_qdel_credits(struct super_block *sb, int type); ++/* Number of credits needed for initialization of new quota structure */ ++int ocfs2_calc_qinit_credits(struct super_block *sb, int type); ++ + /* group extend. inode update and last group update. */ + #define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) + +@@ -303,8 +334,11 @@ int ocfs2_journal_dirty + * prev. group desc. if we relink. */ + #define OCFS2_SUBALLOC_ALLOC (3) + +-#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC \ +- + OCFS2_INODE_UPDATE_CREDITS) ++static inline int ocfs2_inline_to_extents_credits(struct super_block *sb) ++{ ++ return OCFS2_SUBALLOC_ALLOC + OCFS2_INODE_UPDATE_CREDITS + ++ ocfs2_quota_trans_credits(sb); ++} + + /* dinode + group descriptor update. We don't relink on free yet. */ + #define OCFS2_SUBALLOC_FREE (2) +@@ -313,16 +347,23 @@ int ocfs2_journal_dirty + #define OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC (OCFS2_SUBALLOC_FREE \ + + OCFS2_TRUNCATE_LOG_UPDATE) + +-#define OCFS2_REMOVE_EXTENT_CREDITS (OCFS2_TRUNCATE_LOG_UPDATE + OCFS2_INODE_UPDATE_CREDITS) ++static inline int ocfs2_remove_extent_credits(struct super_block *sb) ++{ ++ return OCFS2_TRUNCATE_LOG_UPDATE + OCFS2_INODE_UPDATE_CREDITS + ++ ocfs2_quota_trans_credits(sb); ++} + + /* data block for new dir/symlink, 2 for bitmap updates (bitmap fe + + * bitmap block for the new bit) */ + #define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2) + + /* parent fe, parent block, new file entry, inode alloc fe, inode alloc +- * group descriptor + mkdir/symlink blocks */ +-#define OCFS2_MKNOD_CREDITS (3 + OCFS2_SUBALLOC_ALLOC \ +- + OCFS2_DIR_LINK_ADDITIONAL_CREDITS) ++ * group descriptor + mkdir/symlink blocks + quota update */ ++static inline int ocfs2_mknod_credits(struct super_block *sb) ++{ ++ return 3 + OCFS2_SUBALLOC_ALLOC + OCFS2_DIR_LINK_ADDITIONAL_CREDITS + ++ ocfs2_quota_trans_credits(sb); ++} + + /* local alloc metadata change + main bitmap updates */ + #define OCFS2_WINDOW_MOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS \ +@@ -332,13 +373,21 @@ int ocfs2_journal_dirty + * for the dinode, one for the new block. */ + #define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2) + +-/* file update (nlink, etc) + directory mtime/ctime + dir entry block */ +-#define OCFS2_LINK_CREDITS (2*OCFS2_INODE_UPDATE_CREDITS + 1) ++/* file update (nlink, etc) + directory mtime/ctime + dir entry block + quota ++ * update on dir */ ++static inline int ocfs2_link_credits(struct super_block *sb) ++{ ++ return 2*OCFS2_INODE_UPDATE_CREDITS + 1 + ++ ocfs2_quota_trans_credits(sb); ++} + + /* inode + dir inode (if we unlink a dir), + dir entry block + orphan + * dir inode link */ +-#define OCFS2_UNLINK_CREDITS (2 * OCFS2_INODE_UPDATE_CREDITS + 1 \ +- + OCFS2_LINK_CREDITS) ++static inline int ocfs2_unlink_credits(struct super_block *sb) ++{ ++ /* The quota update from ocfs2_link_credits is unused here... */ ++ return 2 * OCFS2_INODE_UPDATE_CREDITS + 1 + ocfs2_link_credits(sb); ++} + + /* dinode + orphan dir dinode + inode alloc dinode + orphan dir entry + + * inode alloc group descriptor */ +@@ -347,8 +396,10 @@ int ocfs2_journal_dirty + /* dinode update, old dir dinode update, new dir dinode update, old + * dir dir entry, new dir dir entry, dir entry update for renaming + * directory + target unlink */ +-#define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \ +- + OCFS2_UNLINK_CREDITS) ++static inline int ocfs2_rename_credits(struct super_block *sb) ++{ ++ return 3 * OCFS2_INODE_UPDATE_CREDITS + 3 + ocfs2_unlink_credits(sb); ++} + + /* global bitmap dinode, group desc., relinked group, + * suballocator dinode, group desc., relinked group, +@@ -357,21 +408,6 @@ int ocfs2_journal_dirty + + OCFS2_INODE_UPDATE_CREDITS \ + + OCFS2_XATTR_BLOCK_UPDATE_CREDITS) + +-/* global quotafile inode update, data block */ +-#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) +- +-/* +- * The two writes below can accidentally see global info dirty due +- * to set_info() quotactl so make them prepared for the writes. +- */ +-/* quota data block, global info */ +-/* Write to local quota file */ +-#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) +- +-/* global quota data block, local quota data block, global quota inode, +- * global quota info */ +-#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) +- + /* + * Please note that the caller must make sure that root_el is the root + * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise +@@ -401,18 +437,19 @@ static inline int ocfs2_calc_extend_cred + * credit for the dinode there. */ + extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth); + +- return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks; ++ return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks + ++ ocfs2_quota_trans_credits(sb); + } + + static inline int ocfs2_calc_symlink_credits(struct super_block *sb) + { +- int blocks = OCFS2_MKNOD_CREDITS; ++ int blocks = ocfs2_mknod_credits(sb); + + /* links can be longer than one block so we may update many + * within our single allocated extent. */ + blocks += ocfs2_clusters_to_blocks(sb, 1); + +- return blocks; ++ return blocks + ocfs2_quota_trans_credits(sb); + } + + static inline int ocfs2_calc_group_alloc_credits(struct super_block *sb, +@@ -449,6 +486,8 @@ static inline int ocfs2_calc_tree_trunc_ + /* update to the truncate log. */ + credits += OCFS2_TRUNCATE_LOG_UPDATE; + ++ credits += ocfs2_quota_trans_credits(sb); ++ + return credits; + } + +Index: linux-2.6.27-ocfs2/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/namei.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/namei.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_NAMEI + #include +@@ -212,6 +213,7 @@ static struct inode *ocfs2_get_init_inod + } else + inode->i_gid = current->fsgid; + inode->i_mode = mode; ++ vfs_dq_init(inode); + return inode; + } + +@@ -233,6 +235,7 @@ static int ocfs2_mknod(struct inode *dir + struct ocfs2_alloc_context *xattr_ac = NULL; + int want_clusters = 0; + int xattr_credits = 0; ++ int did_quota_inode = 0; + struct ocfs2_security_xattr_info si = { + .enable = 1, + }; +@@ -323,7 +326,8 @@ static int ocfs2_mknod(struct inode *dir + goto leave; + } + +- handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS + xattr_credits); ++ handle = ocfs2_start_trans(osb, ++ ocfs2_mknod_credits(dir->i_sb) + xattr_credits); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + handle = NULL; +@@ -331,6 +335,15 @@ static int ocfs2_mknod(struct inode *dir + goto leave; + } + ++ /* We don't use standard VFS wrapper because we don't want vfs_dq_init ++ * to be called. */ ++ if (sb_any_quota_active(osb->sb) && ++ osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { ++ status = -EDQUOT; ++ goto leave; ++ } ++ did_quota_inode = 1; ++ + /* do the real work now. */ + status = ocfs2_mknod_locked(osb, dir, inode, dentry, dev, + &new_fe_bh, parent_fe_bh, handle, +@@ -399,6 +412,8 @@ static int ocfs2_mknod(struct inode *dir + d_instantiate(dentry, inode); + status = 0; + leave: ++ if (status < 0 && did_quota_inode) ++ vfs_dq_free_inode(inode); + if (handle) + ocfs2_commit_trans(osb, handle); + +@@ -649,7 +664,7 @@ static int ocfs2_link(struct dentry *old + goto out_unlock_inode; + } + +- handle = ocfs2_start_trans(osb, OCFS2_LINK_CREDITS); ++ handle = ocfs2_start_trans(osb, ocfs2_link_credits(osb->sb)); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + handle = NULL; +@@ -836,7 +851,7 @@ static int ocfs2_unlink(struct inode *di + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_UNLINK_CREDITS); ++ handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb)); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + handle = NULL; +@@ -1242,7 +1257,7 @@ static int ocfs2_rename(struct inode *ol + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_RENAME_CREDITS); ++ handle = ocfs2_start_trans(osb, ocfs2_rename_credits(osb->sb)); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + handle = NULL; +@@ -1560,6 +1575,7 @@ static int ocfs2_symlink(struct inode *d + struct ocfs2_alloc_context *xattr_ac = NULL; + int want_clusters = 0; + int xattr_credits = 0; ++ int did_quota = 0, did_quota_inode = 0; + struct ocfs2_security_xattr_info si = { + .enable = 1, + }; +@@ -1656,6 +1672,15 @@ static int ocfs2_symlink(struct inode *d + goto bail; + } + ++ /* We don't use standard VFS wrapper because we don't want vfs_dq_init ++ * to be called. */ ++ if (sb_any_quota_active(osb->sb) && ++ osb->sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { ++ status = -EDQUOT; ++ goto bail; ++ } ++ did_quota_inode = 1; ++ + status = ocfs2_mknod_locked(osb, dir, inode, dentry, + 0, &new_fe_bh, parent_fe_bh, handle, + inode_ac); +@@ -1671,6 +1696,12 @@ static int ocfs2_symlink(struct inode *d + u32 offset = 0; + + inode->i_op = &ocfs2_symlink_inode_operations; ++ if (vfs_dq_alloc_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, 1))) { ++ status = -EDQUOT; ++ goto bail; ++ } ++ did_quota = 1; + status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0, + new_fe_bh, + handle, data_ac, NULL, +@@ -1736,6 +1767,11 @@ static int ocfs2_symlink(struct inode *d + dentry->d_op = &ocfs2_dentry_ops; + d_instantiate(dentry, inode); + bail: ++ if (status < 0 && did_quota) ++ vfs_dq_free_space_nodirty(inode, ++ ocfs2_clusters_to_bytes(osb->sb, 1)); ++ if (status < 0 && did_quota_inode) ++ vfs_dq_free_inode(inode); + if (handle) + ocfs2_commit_trans(osb, handle); + +Index: linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/xattr.c +@@ -1613,7 +1613,7 @@ static int ocfs2_remove_value_outside(st + + ocfs2_init_dealloc_ctxt(&ctxt.dealloc); + +- ctxt.handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ ctxt.handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); + if (IS_ERR(ctxt.handle)) { + ret = PTR_ERR(ctxt.handle); + mlog_errno(ret); +@@ -2190,7 +2190,7 @@ static int ocfs2_calc_xattr_set_need(str + */ + if (!xi->value) { + if (!ocfs2_xattr_is_local(xe)) +- credits += OCFS2_REMOVE_EXTENT_CREDITS; ++ credits += ocfs2_remove_extent_credits(inode->i_sb); + + goto out; + } +@@ -2207,7 +2207,7 @@ static int ocfs2_calc_xattr_set_need(str + */ + if (ocfs2_xattr_can_be_in_inode(inode, xi, xis)) { + clusters_add += new_clusters; +- credits += OCFS2_REMOVE_EXTENT_CREDITS + ++ credits += ocfs2_remove_extent_credits(inode->i_sb) + + OCFS2_INODE_UPDATE_CREDITS; + if (!ocfs2_xattr_is_local(xe)) + credits += ocfs2_calc_extend_credits( +@@ -2231,7 +2231,7 @@ static int ocfs2_calc_xattr_set_need(str + xv = &def_xv.xv; + + if (old_clusters >= new_clusters) { +- credits += OCFS2_REMOVE_EXTENT_CREDITS; ++ credits += ocfs2_remove_extent_credits(inode->i_sb); + goto out; + } else { + meta_add += ocfs2_extend_meta_needed(&xv->xr_list); +@@ -4700,7 +4700,7 @@ static int ocfs2_rm_xattr_cluster(struct + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); + if (IS_ERR(handle)) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -5059,7 +5059,7 @@ static int ocfs2_delete_xattr_in_bucket( + + ocfs2_init_dealloc_ctxt(&ctxt.dealloc); + +- ctxt.handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ ctxt.handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(inode->i_sb)); + if (IS_ERR(ctxt.handle)) { + ret = PTR_ERR(ctxt.handle); + mlog_errno(ret); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-the-basic-xattr-disk-layout-in-ocf.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-the-basic-xattr-disk-layout-in-ocf.patch new file mode 100644 index 000000000..a3996241e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-the-basic-xattr-disk-layout-in-ocf.patch @@ -0,0 +1,162 @@ +From: Tao Ma +Subject: [PATCH 05/16] Add the basic xattr disk layout in ocfs2_fs.h +Patch-mainline: 2.6.28? +References: FATE302067 + +Ocfs2 uses a very flexible structure for storing extended attributes on +disk. Small amount of attributes are stored directly in the inode block - up +to 256 bytes worth. If that fills up, attributes are also stored in an +external block, linked to from the inode block. That block can in turn +expand to a btree, capable of storing large numbers of attributes. + +Individual attribute values are stored inline if they're small enough +(currently about 80 bytes, this can be changed though), and otherwise are +expanded to a btree. The theoretical limit to the size of an individual +attribute is about the same as an inode, though the kernel's upper bound on +the size of an attributes data is far smaller. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/ocfs2_fs.h | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 118 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h +index 4f61985..1b46505 100644 +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -64,6 +64,7 @@ + #define OCFS2_INODE_SIGNATURE "INODE01" + #define OCFS2_EXTENT_BLOCK_SIGNATURE "EXBLK01" + #define OCFS2_GROUP_DESC_SIGNATURE "GROUP01" ++#define OCFS2_XATTR_BLOCK_SIGNATURE "XATTR01" + + /* Compatibility flags */ + #define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \ +@@ -715,6 +716,123 @@ struct ocfs2_group_desc + /*40*/ __u8 bg_bitmap[0]; + }; + ++/* ++ * On disk extended attribute structure for OCFS2. ++ */ ++ ++/* ++ * ocfs2_xattr_entry indicates one extend attribute. ++ * ++ * Note that it can be stored in inode, one block or one xattr bucket. ++ */ ++struct ocfs2_xattr_entry { ++ __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */ ++ __le16 xe_name_offset; /* byte offset from the 1st etnry in the local ++ local xattr storage(inode, xattr block or ++ xattr bucket). */ ++ __u8 xe_name_len; /* xattr name len, does't include prefix. */ ++ __u8 xe_type; /* the low 7 bits indicates the name prefix's ++ * type and the highest 1 bits indicate whether ++ * the EA is stored in the local storage. */ ++ __le64 xe_value_size; /* real xattr value length. */ ++}; ++ ++/* ++ * On disk structure for xattr header. ++ * ++ * One ocfs2_xattr_header describes how many ocfs2_xattr_entry records in ++ * the local xattr storage. ++ */ ++struct ocfs2_xattr_header { ++ __le16 xh_count; /* contains the count of how ++ many records are in the ++ local xattr storage. */ ++ __le16 xh_reserved1; ++ __le32 xh_reserved2; ++ __le64 xh_csum; ++ struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */ ++}; ++ ++/* ++ * On disk structure for xattr value root. ++ * ++ * It is used when one extended attribute's size is larger, and we will save it ++ * in an outside cluster. It will stored in a b-tree like file content. ++ */ ++struct ocfs2_xattr_value_root { ++/*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */ ++ __le32 xr_reserved0; ++ __le64 xr_last_eb_blk; /* Pointer to last extent block */ ++/*10*/ struct ocfs2_extent_list xr_list; /* Extent record list */ ++}; ++ ++/* ++ * On disk structure for xattr tree root. ++ * ++ * It is used when there are too many extended attributes for one file. These ++ * attributes will be organized and stored in an indexed-btree. ++ */ ++struct ocfs2_xattr_tree_root { ++/*00*/ __le32 xt_clusters; /* clusters covered by xattr. */ ++ __le32 xt_reserved0; ++ __le64 xt_last_eb_blk; /* Pointer to last extent block */ ++/*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */ ++}; ++ ++#define OCFS2_XATTR_INDEXED 0x1 ++ ++/* ++ * On disk structure for xattr block. ++ */ ++struct ocfs2_xattr_block { ++/*00*/ __u8 xb_signature[8]; /* Signature for verification */ ++ __le16 xb_suballoc_slot; /* Slot suballocator this ++ block belongs to. */ ++ __le16 xb_suballoc_bit; /* Bit offset in suballocator ++ block group */ ++ __le32 xb_fs_generation; /* Must match super block */ ++/*10*/ __le64 xb_blkno; /* Offset on disk, in blocks */ ++ __le64 xb_csum; ++/*20*/ __le16 xb_flags; /* Indicates whether this block contains ++ real xattr or a xattr tree. */ ++ __le16 xb_reserved0; ++ __le32 xb_reserved1; ++ __le64 xb_reserved2; ++/*30*/ union { ++ struct ocfs2_xattr_header xb_header; /* xattr header if this ++ block contains xattr */ ++ struct ocfs2_xattr_tree_root xb_root;/* xattr tree root if this ++ block cotains xattr ++ tree. */ ++ } xb_attrs; ++}; ++ ++#define OCFS2_XATTR_ENTRY_LOCAL 0x80 ++#define OCFS2_XATTR_TYPE_MASK 0x7F ++static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe, ++ int local) ++{ ++ if (local) ++ xe->xe_type |= OCFS2_XATTR_ENTRY_LOCAL; ++ else ++ xe->xe_type &= ~OCFS2_XATTR_ENTRY_LOCAL; ++} ++ ++static inline int ocfs2_xattr_is_local(struct ocfs2_xattr_entry *xe) ++{ ++ return xe->xe_type & OCFS2_XATTR_ENTRY_LOCAL; ++} ++ ++static inline void ocfs2_xattr_set_type(struct ocfs2_xattr_entry *xe, int type) ++{ ++ xe->xe_type |= type & OCFS2_XATTR_TYPE_MASK; ++} ++ ++static inline int ocfs2_xattr_get_type(struct ocfs2_xattr_entry *xe) ++{ ++ return xe->xe_type & OCFS2_XATTR_TYPE_MASK; ++} ++ + #ifdef __KERNEL__ + static inline int ocfs2_fast_symlink_chars(struct super_block *sb) + { +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-the-inode64-mount-option.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-the-inode64-mount-option.patch new file mode 100644 index 000000000..0ec77b12c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-the-inode64-mount-option.patch @@ -0,0 +1,117 @@ +From: Joel Becker +Subject: ocfs2: Add the 'inode64' mount option. +Patch-mainline: 2.6.28? +References: FATE302877 + +Now that ocfs2 limits inode numbers to 32bits, add a mount option to +disable the limit. This parallels XFS. 64bit systems can handle the +larger inode numbers. + +[ Added description of inode64 mount option in ocfs2.txt. --Mark ] + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + Documentation/filesystems/ocfs2.txt | 4 ++++ + fs/ocfs2/ocfs2.h | 1 + + fs/ocfs2/suballoc.c | 5 +++-- + fs/ocfs2/super.c | 17 +++++++++++++++++ + 4 files changed, 25 insertions(+), 2 deletions(-) + +Index: linux-2.6.26/Documentation/filesystems/ocfs2.txt +=================================================================== +--- linux-2.6.26.orig/Documentation/filesystems/ocfs2.txt ++++ linux-2.6.26/Documentation/filesystems/ocfs2.txt +@@ -76,3 +76,7 @@ localalloc=8(*) Allows custom localallo + large, the fs will silently revert it to the default. + Localalloc is not enabled for local mounts. + localflocks This disables cluster aware flock. ++inode64 Indicates that Ocfs2 is allowed to create inodes at ++ any location in the filesystem, including those which ++ will result in inode numbers occupying more than 32 ++ bits of significance. +Index: linux-2.6.26/fs/ocfs2/ocfs2.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/ocfs2.h ++++ linux-2.6.26/fs/ocfs2/ocfs2.h +@@ -185,6 +185,7 @@ enum ocfs2_mount_options + OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */ + OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */ + OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */ ++ OCFS2_MOUNT_INODE64 = 1 << 7, /* Allow inode numbers > 2^32 */ + }; + + #define OCFS2_OSB_SOFT_RO 0x0001 +Index: linux-2.6.26/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.26/fs/ocfs2/suballoc.c +@@ -601,9 +601,10 @@ int ocfs2_reserve_new_inode(struct ocfs2 + /* + * stat(2) can't handle i_ino > 32bits, so we tell the + * lower levels not to allocate us a block group past that +- * limit. ++ * limit. The 'inode64' mount option avoids this behavior. + */ +- (*ac)->ac_max_block = (u32)~0U; ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64)) ++ (*ac)->ac_max_block = (u32)~0U; + + /* + * slot is set when we successfully steal inode from other nodes. +Index: linux-2.6.26/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/super.c ++++ linux-2.6.26/fs/ocfs2/super.c +@@ -157,6 +157,7 @@ enum { + Opt_stack, + Opt_user_xattr, + Opt_nouser_xattr, ++ Opt_inode64, + Opt_err, + }; + +@@ -178,6 +179,7 @@ static match_table_t tokens = { + {Opt_stack, "cluster_stack=%s"}, + {Opt_user_xattr, "user_xattr"}, + {Opt_nouser_xattr, "nouser_xattr"}, ++ {Opt_inode64, "inode64"}, + {Opt_err, NULL} + }; + +@@ -411,6 +413,15 @@ static int ocfs2_remount(struct super_bl + goto out; + } + ++ /* Probably don't want this on remount; it might ++ * mess with other nodes */ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) && ++ (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) { ++ ret = -EINVAL; ++ mlog(ML_ERROR, "Cannot enable inode64 on remount\n"); ++ goto out; ++ } ++ + /* We're going to/from readonly mode. */ + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { + /* Lock here so the check of HARD_RO and the potential +@@ -929,6 +940,9 @@ static int ocfs2_parse_options(struct su + OCFS2_STACK_LABEL_LEN); + mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0'; + break; ++ case Opt_inode64: ++ mopt->mount_opt |= OCFS2_MOUNT_INODE64; ++ break; + default: + mlog(ML_ERROR, + "Unrecognized mount option \"%s\" " +@@ -996,6 +1010,9 @@ static int ocfs2_show_options(struct seq + else + seq_printf(s, ",user_xattr"); + ++ if (opts & OCFS2_MOUNT_INODE64) ++ seq_printf(s, ",inode64"); ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-bucket-iteration-for.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-bucket-iteration-for.patch new file mode 100644 index 000000000..22050d793 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-bucket-iteration-for.patch @@ -0,0 +1,412 @@ +From: Tao Ma +Subject: [PATCH 11/16] ocfs2: Add xattr bucket iteration for large numbers of EAs +Patch-mainline: 2.6.28? +References: FATE302067 + +Ocfs2 breaks up xattr index tree leaves into 4k regions, called buckets. +Attributes are stored within a given bucket, depending on hash value. + +After a discussion with Mark, we decided that the per-bucket index +(xe_entry[]) would only exist in the 1st block of a bucket. Likewise, +name/value pairs will not straddle more than one block. This allows the +majority of operations to work directly on the buffer heads in a leaf block. + +This patch adds code to iterate the buckets in an EA. A new abstration of +ocfs2_xattr_bucket is added. It records the bhs in this bucket and +ocfs2_xattr_header. This keeps the code neat, improving readibility. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/ocfs2_fs.h | 35 +++++++- + fs/ocfs2/xattr.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++- + fs/ocfs2/xattr.h | 9 ++ + 3 files changed, 293 insertions(+), 6 deletions(-) + +diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h +index 98e1f8b..8d5e72f 100644 +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -755,8 +755,13 @@ struct ocfs2_xattr_header { + __le16 xh_count; /* contains the count of how + many records are in the + local xattr storage. */ +- __le16 xh_reserved1; +- __le32 xh_reserved2; ++ __le16 xh_free_start; /* current offset for storing ++ xattr. */ ++ __le16 xh_name_value_len; /* total length of name/value ++ length in this bucket. */ ++ __le16 xh_num_buckets; /* bucket nums in one extent ++ record, only valid in the ++ first bucket. */ + __le64 xh_csum; + struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */ + }; +@@ -793,6 +798,10 @@ struct ocfs2_xattr_tree_root { + #define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \ + ~(OCFS2_XATTR_ROUND)) + ++#define OCFS2_XATTR_BUCKET_SIZE 4096 ++#define OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET (OCFS2_XATTR_BUCKET_SIZE \ ++ / OCFS2_MIN_BLOCKSIZE) ++ + /* + * On disk structure for xattr block. + */ +@@ -963,6 +972,17 @@ static inline u64 ocfs2_backup_super_blkno(struct super_block *sb, int index) + return 0; + + } ++ ++static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb) ++{ ++ int size; ++ ++ size = sb->s_blocksize - ++ offsetof(struct ocfs2_xattr_block, ++ xb_attrs.xb_root.xt_list.l_recs); ++ ++ return size / sizeof(struct ocfs2_extent_rec); ++} + #else + static inline int ocfs2_fast_symlink_chars(int blocksize) + { +@@ -1046,6 +1066,17 @@ static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index) + + return 0; + } ++ ++static inline int ocfs2_xattr_recs_per_xb(int blocksize) ++{ ++ int size; ++ ++ size = blocksize - ++ offsetof(struct ocfs2_xattr_block, ++ xb_attrs.xb_root.xt_list.l_recs); ++ ++ return size / sizeof(struct ocfs2_extent_rec); ++} + #endif /* __KERNEL__ */ + + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 3685cc6..ed41c15 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -52,6 +52,7 @@ + #include "suballoc.h" + #include "uptodate.h" + #include "buffer_head_io.h" ++#include "super.h" + #include "xattr.h" + + +@@ -60,6 +61,11 @@ struct ocfs2_xattr_def_value_root { + struct ocfs2_extent_rec er; + }; + ++struct ocfs2_xattr_bucket { ++ struct buffer_head *bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET]; ++ struct ocfs2_xattr_header *xh; ++}; ++ + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) + #define OCFS2_XATTR_INLINE_SIZE 80 + +@@ -115,6 +121,11 @@ struct ocfs2_xattr_search { + int not_found; + }; + ++static int ocfs2_xattr_tree_list_index_block(struct inode *inode, ++ struct ocfs2_xattr_tree_root *xt, ++ char *buffer, ++ size_t buffer_size); ++ + static inline struct xattr_handler *ocfs2_xattr_handler(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -499,7 +510,7 @@ static int ocfs2_xattr_block_list(struct inode *inode, + size_t buffer_size) + { + struct buffer_head *blk_bh = NULL; +- struct ocfs2_xattr_header *header = NULL; ++ struct ocfs2_xattr_block *xb; + int ret = 0; + + if (!di->i_xattr_loc) +@@ -519,10 +530,17 @@ static int ocfs2_xattr_block_list(struct inode *inode, + goto cleanup; + } + +- header = &((struct ocfs2_xattr_block *)blk_bh->b_data)-> +- xb_attrs.xb_header; ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; + +- ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size); ++ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { ++ struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header; ++ ret = ocfs2_xattr_list_entries(inode, header, ++ buffer, buffer_size); ++ } else { ++ struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; ++ ret = ocfs2_xattr_tree_list_index_block(inode, xt, ++ buffer, buffer_size); ++ } + cleanup: + brelse(blk_bh); + +@@ -1939,3 +1957,232 @@ cleanup: + return ret; + } + ++/* ++ * Find the xattr extent rec which may contains name_hash. ++ * e_cpos will be the first name hash of the xattr rec. ++ * el must be the ocfs2_xattr_header.xb_attrs.xb_root.xt_list. ++ */ ++static int ocfs2_xattr_get_rec(struct inode *inode, ++ u32 name_hash, ++ u64 *p_blkno, ++ u32 *e_cpos, ++ u32 *num_clusters, ++ struct ocfs2_extent_list *el) ++{ ++ int ret = 0, i; ++ struct buffer_head *eb_bh = NULL; ++ struct ocfs2_extent_block *eb; ++ struct ocfs2_extent_rec *rec = NULL; ++ u64 e_blkno = 0; ++ ++ if (el->l_tree_depth) { ++ ret = ocfs2_find_leaf(inode, el, name_hash, &eb_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ eb = (struct ocfs2_extent_block *) eb_bh->b_data; ++ el = &eb->h_list; ++ ++ if (el->l_tree_depth) { ++ ocfs2_error(inode->i_sb, ++ "Inode %lu has non zero tree depth in " ++ "xattr tree block %llu\n", inode->i_ino, ++ (unsigned long long)eb_bh->b_blocknr); ++ ret = -EROFS; ++ goto out; ++ } ++ } ++ ++ for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) { ++ rec = &el->l_recs[i]; ++ ++ if (le32_to_cpu(rec->e_cpos) <= name_hash) { ++ e_blkno = le64_to_cpu(rec->e_blkno); ++ break; ++ } ++ } ++ ++ if (!e_blkno) { ++ ocfs2_error(inode->i_sb, "Inode %lu has bad extent " ++ "record (%u, %u, 0) in xattr", inode->i_ino, ++ le32_to_cpu(rec->e_cpos), ++ ocfs2_rec_clusters(el, rec)); ++ ret = -EROFS; ++ goto out; ++ } ++ ++ *p_blkno = le64_to_cpu(rec->e_blkno); ++ *num_clusters = le16_to_cpu(rec->e_leaf_clusters); ++ if (e_cpos) ++ *e_cpos = le32_to_cpu(rec->e_cpos); ++out: ++ brelse(eb_bh); ++ return ret; ++} ++ ++typedef int (xattr_bucket_func)(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ void *para); ++ ++static int ocfs2_iterate_xattr_buckets(struct inode *inode, ++ u64 blkno, ++ u32 clusters, ++ xattr_bucket_func *func, ++ void *para) ++{ ++ int i, j, ret = 0; ++ int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)); ++ u32 num_buckets = clusters * bpc; ++ struct ocfs2_xattr_bucket bucket; ++ ++ memset(&bucket, 0, sizeof(bucket)); ++ ++ mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n", ++ clusters, blkno); ++ ++ for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { ++ ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), ++ blkno, blk_per_bucket, ++ bucket.bhs, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ bucket.xh = (struct ocfs2_xattr_header *)bucket.bhs[0]->b_data; ++ /* ++ * The real bucket num in this series of blocks is stored ++ * in the 1st bucket. ++ */ ++ if (i == 0) ++ num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); ++ ++ mlog(0, "iterating xattr bucket %llu\n", blkno); ++ if (func) { ++ ret = func(inode, &bucket, para); ++ if (ret) { ++ mlog_errno(ret); ++ break; ++ } ++ } ++ ++ for (j = 0; j < blk_per_bucket; j++) ++ brelse(bucket.bhs[j]); ++ memset(&bucket, 0, sizeof(bucket)); ++ } ++ ++out: ++ for (j = 0; j < blk_per_bucket; j++) ++ brelse(bucket.bhs[j]); ++ ++ return ret; ++} ++ ++struct ocfs2_xattr_tree_list { ++ char *buffer; ++ size_t buffer_size; ++}; ++ ++static int ocfs2_xattr_bucket_get_name_value(struct inode *inode, ++ struct ocfs2_xattr_header *xh, ++ int index, ++ int *block_off, ++ int *new_offset) ++{ ++ u16 name_offset; ++ ++ if (index < 0 || index >= le16_to_cpu(xh->xh_count)) ++ return -EINVAL; ++ ++ name_offset = le16_to_cpu(xh->xh_entries[index].xe_name_offset); ++ ++ *block_off = name_offset >> inode->i_sb->s_blocksize_bits; ++ *new_offset = name_offset % inode->i_sb->s_blocksize; ++ ++ return 0; ++} ++ ++static int ocfs2_list_xattr_bucket(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ void *para) ++{ ++ int ret = 0; ++ struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para; ++ size_t size; ++ int i, block_off, new_offset; ++ ++ for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) { ++ struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i]; ++ struct xattr_handler *handler = ++ ocfs2_xattr_handler(ocfs2_xattr_get_type(entry)); ++ ++ if (handler) { ++ ret = ocfs2_xattr_bucket_get_name_value(inode, ++ bucket->xh, ++ i, ++ &block_off, ++ &new_offset); ++ if (ret) ++ break; ++ size = handler->list(inode, xl->buffer, xl->buffer_size, ++ bucket->bhs[block_off]->b_data + ++ new_offset, ++ entry->xe_name_len); ++ if (xl->buffer) { ++ if (size > xl->buffer_size) ++ return -ERANGE; ++ xl->buffer += size; ++ } ++ xl->buffer_size -= size; ++ } ++ } ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_tree_list_index_block(struct inode *inode, ++ struct ocfs2_xattr_tree_root *xt, ++ char *buffer, ++ size_t buffer_size) ++{ ++ struct ocfs2_extent_list *el = &xt->xt_list; ++ int ret = 0; ++ u32 name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0; ++ u64 p_blkno = 0; ++ struct ocfs2_xattr_tree_list xl = { ++ .buffer = buffer, ++ .buffer_size = buffer_size, ++ }; ++ ++ if (le16_to_cpu(el->l_next_free_rec) == 0) ++ return 0; ++ ++ while (name_hash > 0) { ++ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, ++ &e_cpos, &num_clusters, el); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters, ++ ocfs2_list_xattr_bucket, ++ &xl); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ if (e_cpos == 0) ++ break; ++ ++ name_hash = e_cpos - 1; ++ } ++ ++ ret = buffer_size - xl.buffer_size; ++out: ++ return ret; ++} +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index f565c64..a69c8aa 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -55,4 +55,13 @@ extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *, + extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh); + extern struct xattr_handler *ocfs2_xattr_handlers[]; + ++static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) ++{ ++ return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE; ++} ++ ++static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) ++{ ++ return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); ++} + #endif /* OCFS2_XATTR_H */ +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-index-tree-operations.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-index-tree-operations.patch new file mode 100644 index 000000000..287414a6e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-index-tree-operations.patch @@ -0,0 +1,176 @@ +From: Tao Ma +Subject: [PATCH 10/16] ocfs2: Add xattr index tree operations +Patch-mainline: 2.6.28? +References: FATE302067 + +When necessary, an ocfs2_xattr_block will embed an ocfs2_extent_list to +store large numbers of EAs. This patch adds a new type in +ocfs2_extent_tree_type and adds the implementation so that we can re-use the +b-tree code to handle the storage of many EAs. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/alloc.h | 10 ++++++ + 2 files changed, 99 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index d175db1..47cdea6 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -177,6 +177,48 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { + .sanity_check = ocfs2_xattr_value_sanity_check, + }; + ++static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, ++ u64 blkno) ++{ ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *) et->root_bh->b_data; ++ struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; ++ ++ xt->xt_last_eb_blk = cpu_to_le64(blkno); ++} ++ ++static u64 ocfs2_xattr_tree_get_last_eb_blk(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *) et->root_bh->b_data; ++ struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; ++ ++ return le64_to_cpu(xt->xt_last_eb_blk); ++} ++ ++static void ocfs2_xattr_tree_update_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 clusters) ++{ ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)et->root_bh->b_data; ++ ++ le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters); ++} ++ ++static int ocfs2_xattr_tree_sanity_check(struct inode *inode, ++ struct ocfs2_extent_tree *et) ++{ ++ return 0; ++} ++ ++static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { ++ .set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk, ++ .get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, ++ .update_clusters = ocfs2_xattr_tree_update_clusters, ++ .sanity_check = ocfs2_xattr_tree_sanity_check, ++}; ++ + static struct ocfs2_extent_tree* + ocfs2_new_extent_tree(struct buffer_head *bh, + enum ocfs2_extent_tree_type et_type, +@@ -201,6 +243,11 @@ static struct ocfs2_extent_tree* + (struct ocfs2_xattr_value_root *) private; + et->root_el = &xv->xr_list; + et->eops = &ocfs2_xattr_et_ops; ++ } else if (et_type == OCFS2_XATTR_TREE_EXTENT) { ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)bh->b_data; ++ et->root_el = &xb->xb_attrs.xb_root.xt_list; ++ et->eops = &ocfs2_xattr_tree_et_ops; + } + + return et; +@@ -570,6 +617,12 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, + + last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk); + el = &xv->xr_list; ++ } else if (type == OCFS2_XATTR_TREE_EXTENT) { ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)root_bh->b_data; ++ ++ last_eb_blk = le64_to_cpu(xb->xb_attrs.xb_root.xt_last_eb_blk); ++ el = &xb->xb_attrs.xb_root.xt_list; + } + + if (last_eb_blk) { +@@ -4406,6 +4459,36 @@ bail: + return status; + } + ++int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac) ++{ ++ int status; ++ struct ocfs2_extent_tree *et = NULL; ++ ++ et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_TREE_EXTENT, NULL); ++ if (!et) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto bail; ++ } ++ ++ status = ocfs2_insert_extent(osb, handle, inode, root_bh, ++ cpos, start_blk, new_clusters, ++ flags, meta_ac, et); ++ ++ if (et) ++ ocfs2_free_extent_tree(et); ++bail: ++ return status; ++} ++ + /* + * Allcate and add clusters into the extent b-tree. + * The new clusters(clusters_to_add) will be inserted at logical_offset. +@@ -4491,6 +4574,12 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, + status = ocfs2_dinode_insert_extent(osb, handle, inode, root_bh, + *logical_offset, block, + num_bits, flags, meta_ac); ++ else if (type == OCFS2_XATTR_TREE_EXTENT) ++ status = ocfs2_xattr_tree_insert_extent(osb, handle, ++ inode, root_bh, ++ *logical_offset, ++ block, num_bits, flags, ++ meta_ac); + else + status = ocfs2_xattr_value_insert_extent(osb, handle, + inode, root_bh, +diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h +index 168e86e..b8cfc53 100644 +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -29,6 +29,7 @@ + enum ocfs2_extent_tree_type { + OCFS2_DINODE_EXTENT = 0, + OCFS2_XATTR_VALUE_EXTENT, ++ OCFS2_XATTR_TREE_EXTENT, + }; + + struct ocfs2_alloc_context; +@@ -51,6 +52,15 @@ int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, + u8 flags, + struct ocfs2_alloc_context *meta_ac, + void *private); ++int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *root_bh, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac); + enum ocfs2_alloc_restarted { + RESTART_NONE = 0, + RESTART_TRANS, +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-lookup-code-xattr-btr.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-lookup-code-xattr-btr.patch new file mode 100644 index 000000000..71b862568 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-lookup-code-xattr-btr.patch @@ -0,0 +1,496 @@ +From: Tao Ma +Subject: [PATCH 12/16] ocfs2: Add xattr lookup code xattr btrees +Patch-mainline: 2.6.28? +References: FATE302067 + +Add code to lookup a given extended attribute in the xattr btree. Lookup +follows this general scheme: + +1. Use ocfs2_xattr_get_rec to find the xattr extent record + +2. Find the xattr bucket within the extent which may contain this xattr + +3. Iterate the bucket to find the xattr. In ocfs2_xattr_block_get(), we need + to recalcuate the block offset and name offset for the right position of + name/value. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 files changed, 328 insertions(+), 23 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index ed41c15..a5ca066 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -115,12 +115,25 @@ struct ocfs2_xattr_search { + */ + struct buffer_head *xattr_bh; + struct ocfs2_xattr_header *header; ++ struct ocfs2_xattr_bucket bucket; + void *base; + void *end; + struct ocfs2_xattr_entry *here; + int not_found; + }; + ++static int ocfs2_xattr_bucket_get_name_value(struct inode *inode, ++ struct ocfs2_xattr_header *xh, ++ int index, ++ int *block_off, ++ int *new_offset); ++ ++static int ocfs2_xattr_index_block_find(struct inode *inode, ++ struct buffer_head *root_bh, ++ int name_index, ++ const char *name, ++ struct ocfs2_xattr_search *xs); ++ + static int ocfs2_xattr_tree_list_index_block(struct inode *inode, + struct ocfs2_xattr_tree_root *xt, + char *buffer, +@@ -620,7 +633,7 @@ static int ocfs2_xattr_find_entry(int name_index, + } + + static int ocfs2_xattr_get_value_outside(struct inode *inode, +- struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_value_root *xv, + void *buffer, + size_t len) + { +@@ -629,12 +642,8 @@ static int ocfs2_xattr_get_value_outside(struct inode *inode, + int i, ret = 0; + size_t cplen, blocksize; + struct buffer_head *bh = NULL; +- struct ocfs2_xattr_value_root *xv; + struct ocfs2_extent_list *el; + +- xv = (struct ocfs2_xattr_value_root *) +- (xs->base + le16_to_cpu(xs->here->xe_name_offset) + +- OCFS2_XATTR_SIZE(xs->here->xe_name_len)); + el = &xv->xr_list; + clusters = le32_to_cpu(xv->xr_clusters); + bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); +@@ -684,6 +693,7 @@ static int ocfs2_xattr_ibody_get(struct inode *inode, + { + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; ++ struct ocfs2_xattr_value_root *xv; + size_t size; + int ret = 0; + +@@ -708,7 +718,11 @@ static int ocfs2_xattr_ibody_get(struct inode *inode, + le16_to_cpu(xs->here->xe_name_offset) + + OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); + } else { +- ret = ocfs2_xattr_get_value_outside(inode, xs, ++ xv = (struct ocfs2_xattr_value_root *) ++ (xs->base + le16_to_cpu( ++ xs->here->xe_name_offset) + ++ OCFS2_XATTR_SIZE(xs->here->xe_name_len)); ++ ret = ocfs2_xattr_get_value_outside(inode, xv, + buffer, size); + if (ret < 0) { + mlog_errno(ret); +@@ -730,12 +744,15 @@ static int ocfs2_xattr_block_get(struct inode *inode, + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; + struct buffer_head *blk_bh = NULL; + struct ocfs2_xattr_block *xb; ++ struct ocfs2_xattr_value_root *xv; + size_t size; +- int ret = -ENODATA; ++ int ret = -ENODATA, name_offset, name_len, block_off, i; + + if (!di->i_xattr_loc) + return ret; + ++ memset(&xs->bucket, 0, sizeof(xs->bucket)); ++ + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), + le64_to_cpu(di->i_xattr_loc), + &blk_bh, OCFS2_BH_CACHED, inode); +@@ -752,12 +769,19 @@ static int ocfs2_xattr_block_get(struct inode *inode, + + xs->xattr_bh = blk_bh; + xb = (struct ocfs2_xattr_block *)blk_bh->b_data; +- xs->header = &xb->xb_attrs.xb_header; +- xs->base = (void *)xs->header; +- xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; +- xs->here = xs->header->xh_entries; + +- ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { ++ xs->header = &xb->xb_attrs.xb_header; ++ xs->base = (void *)xs->header; ++ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; ++ xs->here = xs->header->xh_entries; ++ ++ ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ } else ++ ret = ocfs2_xattr_index_block_find(inode, blk_bh, ++ name_index, ++ name, xs); ++ + if (ret) + goto cleanup; + size = le64_to_cpu(xs->here->xe_value_size); +@@ -765,12 +789,26 @@ static int ocfs2_xattr_block_get(struct inode *inode, + ret = -ERANGE; + if (size > buffer_size) + goto cleanup; ++ ++ name_offset = le16_to_cpu(xs->here->xe_name_offset); ++ name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len); ++ i = xs->here - xs->header->xh_entries; ++ ++ if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { ++ ret = ocfs2_xattr_bucket_get_name_value(inode, ++ xs->bucket.xh, ++ i, ++ &block_off, ++ &name_offset); ++ xs->base = xs->bucket.bhs[block_off]->b_data; ++ } + if (ocfs2_xattr_is_local(xs->here)) { + memcpy(buffer, (void *)xs->base + +- le16_to_cpu(xs->here->xe_name_offset) + +- OCFS2_XATTR_SIZE(xs->here->xe_name_len), size); ++ name_offset + name_len, size); + } else { +- ret = ocfs2_xattr_get_value_outside(inode, xs, ++ xv = (struct ocfs2_xattr_value_root *) ++ (xs->base + name_offset + name_len); ++ ret = ocfs2_xattr_get_value_outside(inode, xv, + buffer, size); + if (ret < 0) { + mlog_errno(ret); +@@ -780,8 +818,11 @@ static int ocfs2_xattr_block_get(struct inode *inode, + } + ret = size; + cleanup: +- brelse(blk_bh); ++ for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++) ++ brelse(xs->bucket.bhs[i]); ++ memset(&xs->bucket, 0, sizeof(xs->bucket)); + ++ brelse(blk_bh); + return ret; + } + +@@ -1695,6 +1736,7 @@ static int ocfs2_xattr_block_find(struct inode *inode, + { + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; + struct buffer_head *blk_bh = NULL; ++ struct ocfs2_xattr_block *xb; + int ret = 0; + + if (!di->i_xattr_loc) +@@ -1715,20 +1757,26 @@ static int ocfs2_xattr_block_find(struct inode *inode, + } + + xs->xattr_bh = blk_bh; +- xs->header = &((struct ocfs2_xattr_block *)blk_bh->b_data)-> +- xb_attrs.xb_header; +- xs->base = (void *)xs->header; +- xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; +- xs->here = xs->header->xh_entries; ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ ++ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { ++ xs->header = &xb->xb_attrs.xb_header; ++ xs->base = (void *)xs->header; ++ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size; ++ xs->here = xs->header->xh_entries; ++ ++ ret = ocfs2_xattr_find_entry(name_index, name, xs); ++ } else ++ ret = ocfs2_xattr_index_block_find(inode, blk_bh, ++ name_index, ++ name, xs); + +- ret = ocfs2_xattr_find_entry(name_index, name, xs); + if (ret && ret != -ENODATA) { + xs->xattr_bh = NULL; + goto cleanup; + } + xs->not_found = ret; + return 0; +- + cleanup: + brelse(blk_bh); + +@@ -1957,6 +2005,18 @@ cleanup: + return ret; + } + ++static inline u32 ocfs2_xattr_hash_by_name(struct inode *inode, ++ int name_index, ++ const char *suffix_name) ++{ ++ struct xattr_handler *handler = ocfs2_xattr_handler(name_index); ++ char *prefix = handler->prefix; ++ int prefix_len = strlen(handler->prefix); ++ ++ return ocfs2_xattr_name_hash(inode, prefix, prefix_len, ++ (char *)suffix_name, strlen(suffix_name)); ++} ++ + /* + * Find the xattr extent rec which may contains name_hash. + * e_cpos will be the first name hash of the xattr rec. +@@ -2026,6 +2086,251 @@ typedef int (xattr_bucket_func)(struct inode *inode, + struct ocfs2_xattr_bucket *bucket, + void *para); + ++static int ocfs2_find_xe_in_bucket(struct inode *inode, ++ struct buffer_head *header_bh, ++ int name_index, ++ const char *name, ++ u32 name_hash, ++ u16 *xe_index, ++ int *found) ++{ ++ int i, ret = 0, cmp = 1, block_off, new_offset; ++ struct ocfs2_xattr_header *xh = ++ (struct ocfs2_xattr_header *)header_bh->b_data; ++ size_t name_len = strlen(name); ++ struct ocfs2_xattr_entry *xe = NULL; ++ struct buffer_head *name_bh = NULL; ++ char *xe_name; ++ ++ /* ++ * We don't use binary search in the bucket because there ++ * may be multiple entries with the same name hash. ++ */ ++ for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { ++ xe = &xh->xh_entries[i]; ++ ++ if (name_hash > le32_to_cpu(xe->xe_name_hash)) ++ continue; ++ else if (name_hash < le32_to_cpu(xe->xe_name_hash)) ++ break; ++ ++ cmp = name_index - ocfs2_xattr_get_type(xe); ++ if (!cmp) ++ cmp = name_len - xe->xe_name_len; ++ if (cmp) ++ continue; ++ ++ ret = ocfs2_xattr_bucket_get_name_value(inode, ++ xh, ++ i, ++ &block_off, ++ &new_offset); ++ if (ret) { ++ mlog_errno(ret); ++ break; ++ } ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ header_bh->b_blocknr + block_off, ++ &name_bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ break; ++ } ++ xe_name = name_bh->b_data + new_offset; ++ ++ cmp = memcmp(name, xe_name, name_len); ++ brelse(name_bh); ++ name_bh = NULL; ++ ++ if (cmp == 0) { ++ *xe_index = i; ++ *found = 1; ++ ret = 0; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * Find the specified xattr entry in a series of buckets. ++ * This series start from p_blkno and last for num_clusters. ++ * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains ++ * the num of the valid buckets. ++ * ++ * Return the buffer_head this xattr should reside in. And if the xattr's ++ * hash is in the gap of 2 buckets, return the lower bucket. ++ */ ++static int ocfs2_xattr_bucket_find(struct inode *inode, ++ int name_index, ++ const char *name, ++ u32 name_hash, ++ u64 p_blkno, ++ u32 first_hash, ++ u32 num_clusters, ++ struct ocfs2_xattr_search *xs) ++{ ++ int ret, found = 0; ++ struct buffer_head *bh = NULL; ++ struct buffer_head *lower_bh = NULL; ++ struct ocfs2_xattr_header *xh = NULL; ++ struct ocfs2_xattr_entry *xe = NULL; ++ u16 index = 0; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int low_bucket = 0, bucket, high_bucket; ++ u32 last_hash; ++ u64 blkno; ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, ++ &bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xh = (struct ocfs2_xattr_header *)bh->b_data; ++ high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1; ++ ++ while (low_bucket <= high_bucket) { ++ brelse(bh); ++ bh = NULL; ++ bucket = (low_bucket + high_bucket) / 2; ++ ++ blkno = p_blkno + bucket * blk_per_bucket; ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, ++ &bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xh = (struct ocfs2_xattr_header *)bh->b_data; ++ xe = &xh->xh_entries[0]; ++ if (name_hash < le32_to_cpu(xe->xe_name_hash)) { ++ high_bucket = bucket - 1; ++ continue; ++ } ++ ++ /* ++ * Check whether the hash of the last entry in our ++ * bucket is larger than the search one. ++ */ ++ xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1]; ++ last_hash = le32_to_cpu(xe->xe_name_hash); ++ ++ /* record lower_bh which may be the insert place. */ ++ brelse(lower_bh); ++ lower_bh = bh; ++ bh = NULL; ++ ++ if (name_hash > le32_to_cpu(xe->xe_name_hash)) { ++ low_bucket = bucket + 1; ++ continue; ++ } ++ ++ /* the searched xattr should reside in this bucket if exists. */ ++ ret = ocfs2_find_xe_in_bucket(inode, lower_bh, ++ name_index, name, name_hash, ++ &index, &found); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ break; ++ } ++ ++ /* ++ * Record the bucket we have found. ++ * When the xattr's hash value is in the gap of 2 buckets, we will ++ * always set it to the previous bucket. ++ */ ++ if (!lower_bh) { ++ /* ++ * We can't find any bucket whose first name_hash is less ++ * than the find name_hash. ++ */ ++ BUG_ON(bh->b_blocknr != p_blkno); ++ lower_bh = bh; ++ bh = NULL; ++ } ++ xs->bucket.bhs[0] = lower_bh; ++ xs->bucket.xh = (struct ocfs2_xattr_header *) ++ xs->bucket.bhs[0]->b_data; ++ lower_bh = NULL; ++ ++ xs->header = xs->bucket.xh; ++ xs->base = xs->bucket.bhs[0]->b_data; ++ xs->end = xs->base + inode->i_sb->s_blocksize; ++ ++ if (found) { ++ /* ++ * If we have found the xattr enty, read all the blocks in ++ * this bucket. ++ */ ++ ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), ++ xs->bucket.bhs[0]->b_blocknr + 1, ++ blk_per_bucket - 1, &xs->bucket.bhs[1], ++ OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xs->here = &xs->header->xh_entries[index]; ++ mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name, ++ (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index); ++ } else ++ ret = -ENODATA; ++ ++out: ++ brelse(bh); ++ brelse(lower_bh); ++ return ret; ++} ++ ++static int ocfs2_xattr_index_block_find(struct inode *inode, ++ struct buffer_head *root_bh, ++ int name_index, ++ const char *name, ++ struct ocfs2_xattr_search *xs) ++{ ++ int ret; ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)root_bh->b_data; ++ struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root; ++ struct ocfs2_extent_list *el = &xb_root->xt_list; ++ u64 p_blkno = 0; ++ u32 first_hash, num_clusters = 0; ++ u32 name_hash = ocfs2_xattr_hash_by_name(inode, name_index, name); ++ ++ if (le16_to_cpu(el->l_next_free_rec) == 0) ++ return -ENODATA; ++ ++ mlog(0, "find xattr %s, hash = %u, index = %d in xattr tree\n", ++ name, name_hash, name_index); ++ ++ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash, ++ &num_clusters, el); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash); ++ ++ mlog(0, "find xattr extent rec %u clusters from %llu, the first hash " ++ "in the rec is %u\n", num_clusters, p_blkno, first_hash); ++ ++ ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash, ++ p_blkno, first_hash, num_clusters, xs); ++ ++out: ++ return ret; ++} ++ + static int ocfs2_iterate_xattr_buckets(struct inode *inode, + u64 blkno, + u32 clusters, +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-mount-option-in-ocfs2_show_options.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-mount-option-in-ocfs2_show_options.patch new file mode 100644 index 000000000..7b33d9fc7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-xattr-mount-option-in-ocfs2_show_options.patch @@ -0,0 +1,33 @@ +From: Sunil Mushran +Subject: ocfs2: Add xattr mount option in ocfs2_show_options() +Patch-mainline: 2.6.28? +References: FATE302067 + +Patch adds check for [no]user_xattr in ocfs2_show_options() that completes +the list of all mount options. + +Signed-off-by: Sunil Mushran +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/super.c | 5 +++++ + 1 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 2173169..d789c53 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -991,6 +991,11 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) + seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, + osb->osb_cluster_stack); + ++ if (opts & OCFS2_MOUNT_NOUSERXATTR) ++ seq_printf(s, ",nouser_xattr"); ++ else ++ seq_printf(s, ",user_xattr"); ++ + return 0; + } + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Assign-feature-bits-and-system-inodes-to-quot.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Assign-feature-bits-and-system-inodes-to-quot.patch new file mode 100644 index 000000000..77c25c1e2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Assign-feature-bits-and-system-inodes-to-quot.patch @@ -0,0 +1,136 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 22/28] ocfs2: Assign feature bits and system inodes to quota feature and quota files +Patch-mainline: 2.6.29? + +Signed-off-by: Jan Kara +--- + fs/ocfs2/inode.c | 2 ++ + fs/ocfs2/ocfs2_fs.h | 23 ++++++++++++++++++++--- + fs/ocfs2/super.c | 17 +++++++++++++++++ + 3 files changed, 39 insertions(+), 3 deletions(-) + +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -292,6 +292,8 @@ int ocfs2_populate_inode(struct inode *i + mlog(0, "local alloc inode: i_ino=%lu\n", inode->i_ino); + } else if (fe->i_flags & cpu_to_le32(OCFS2_BITMAP_FL)) { + OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP; ++ } else if (fe->i_flags & cpu_to_le32(OCFS2_QUOTA_FL)) { ++ inode->i_flags |= S_NOQUOTA; + } else if (fe->i_flags & cpu_to_le32(OCFS2_SUPER_BLOCK_FL)) { + mlog(0, "superblock inode: i_ino=%lu\n", inode->i_ino); + /* we can't actually hit this as read_inode can't +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -94,7 +94,9 @@ + | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \ + | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \ + | OCFS2_FEATURE_INCOMPAT_XATTR) +-#define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN ++#define OCFS2_FEATURE_RO_COMPAT_SUPP (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \ ++ | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \ ++ | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) + + /* + * Heartbeat-only devices are missing journals and other files. The +@@ -163,6 +165,12 @@ + */ + #define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001 + ++/* ++ * Maintain quota information for this filesystem ++ */ ++#define OCFS2_FEATURE_RO_COMPAT_USRQUOTA 0x0002 ++#define OCFS2_FEATURE_RO_COMPAT_GRPQUOTA 0x0004 ++ + /* The byte offset of the first backup block will be 1G. + * The following will be 4G, 16G, 64G, 256G and 1T. + */ +@@ -192,6 +200,7 @@ + #define OCFS2_HEARTBEAT_FL (0x00000200) /* Heartbeat area */ + #define OCFS2_CHAIN_FL (0x00000400) /* Chain allocator */ + #define OCFS2_DEALLOC_FL (0x00000800) /* Truncate log */ ++#define OCFS2_QUOTA_FL (0x00001000) /* Quota file */ + + /* + * Flags on ocfs2_dinode.i_dyn_features +@@ -329,13 +338,17 @@ enum { + #define OCFS2_FIRST_ONLINE_SYSTEM_INODE SLOT_MAP_SYSTEM_INODE + HEARTBEAT_SYSTEM_INODE, + GLOBAL_BITMAP_SYSTEM_INODE, +-#define OCFS2_LAST_GLOBAL_SYSTEM_INODE GLOBAL_BITMAP_SYSTEM_INODE ++ USER_QUOTA_SYSTEM_INODE, ++ GROUP_QUOTA_SYSTEM_INODE, ++#define OCFS2_LAST_GLOBAL_SYSTEM_INODE GROUP_QUOTA_SYSTEM_INODE + ORPHAN_DIR_SYSTEM_INODE, + EXTENT_ALLOC_SYSTEM_INODE, + INODE_ALLOC_SYSTEM_INODE, + JOURNAL_SYSTEM_INODE, + LOCAL_ALLOC_SYSTEM_INODE, + TRUNCATE_LOG_SYSTEM_INODE, ++ LOCAL_USER_QUOTA_SYSTEM_INODE, ++ LOCAL_GROUP_QUOTA_SYSTEM_INODE, + NUM_SYSTEM_INODES + }; + +@@ -349,6 +362,8 @@ static struct ocfs2_system_inode_info oc + [SLOT_MAP_SYSTEM_INODE] = { "slot_map", 0, S_IFREG | 0644 }, + [HEARTBEAT_SYSTEM_INODE] = { "heartbeat", OCFS2_HEARTBEAT_FL, S_IFREG | 0644 }, + [GLOBAL_BITMAP_SYSTEM_INODE] = { "global_bitmap", 0, S_IFREG | 0644 }, ++ [USER_QUOTA_SYSTEM_INODE] = { "aquota.user", OCFS2_QUOTA_FL, S_IFREG | 0644 }, ++ [GROUP_QUOTA_SYSTEM_INODE] = { "aquota.group", OCFS2_QUOTA_FL, S_IFREG | 0644 }, + + /* Slot-specific system inodes (one copy per slot) */ + [ORPHAN_DIR_SYSTEM_INODE] = { "orphan_dir:%04d", 0, S_IFDIR | 0755 }, +@@ -356,7 +371,9 @@ static struct ocfs2_system_inode_info oc + [INODE_ALLOC_SYSTEM_INODE] = { "inode_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_CHAIN_FL, S_IFREG | 0644 }, + [JOURNAL_SYSTEM_INODE] = { "journal:%04d", OCFS2_JOURNAL_FL, S_IFREG | 0644 }, + [LOCAL_ALLOC_SYSTEM_INODE] = { "local_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_LOCAL_ALLOC_FL, S_IFREG | 0644 }, +- [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 } ++ [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 }, ++ [LOCAL_USER_QUOTA_SYSTEM_INODE] = { "aquota%04d.user", OCFS2_QUOTA_FL, S_IFREG | 0644 }, ++ [LOCAL_GROUP_QUOTA_SYSTEM_INODE] = { "aquota%04d.group", OCFS2_QUOTA_FL, S_IFREG | 0644 }, + }; + + /* Parameter passed from mount.ocfs2 to module */ +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -225,6 +225,19 @@ static int ocfs2_sync_fs(struct super_bl + return 0; + } + ++static int ocfs2_need_system_inode(struct ocfs2_super *osb, int ino) ++{ ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA) ++ && (ino == USER_QUOTA_SYSTEM_INODE ++ || ino == LOCAL_USER_QUOTA_SYSTEM_INODE)) ++ return 0; ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) ++ && (ino == GROUP_QUOTA_SYSTEM_INODE ++ || ino == LOCAL_GROUP_QUOTA_SYSTEM_INODE)) ++ return 0; ++ return 1; ++} ++ + static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) + { + struct inode *new = NULL; +@@ -251,6 +264,8 @@ static int ocfs2_init_global_system_inod + + for (i = OCFS2_FIRST_ONLINE_SYSTEM_INODE; + i <= OCFS2_LAST_GLOBAL_SYSTEM_INODE; i++) { ++ if (!ocfs2_need_system_inode(osb, i)) ++ continue; + new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); + if (!new) { + ocfs2_release_system_inodes(osb); +@@ -281,6 +296,8 @@ static int ocfs2_init_local_system_inode + for (i = OCFS2_LAST_GLOBAL_SYSTEM_INODE + 1; + i < NUM_SYSTEM_INODES; + i++) { ++ if (!ocfs2_need_system_inode(osb, i)) ++ continue; + new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); + if (!new) { + ocfs2_release_system_inodes(osb); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Calculate-EA-hash-only-by-its-suffix.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Calculate-EA-hash-only-by-its-suffix.patch new file mode 100644 index 000000000..b15613422 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Calculate-EA-hash-only-by-its-suffix.patch @@ -0,0 +1,95 @@ +From: Tao Ma +Subject: ocfs2: Calculate EA hash only by its suffix. +Patch-mainline: 2.6.28 + +According to Christoph Hellwig's advice, the hash value of EA +is only calculated by its suffix. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 35 +++++------------------------------ + 1 files changed, 5 insertions(+), 30 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -164,21 +164,13 @@ static inline struct xattr_handler *ocfs + } + + static u32 ocfs2_xattr_name_hash(struct inode *inode, +- char *prefix, +- int prefix_len, +- char *name, ++ const char *name, + int name_len) + { + /* Get hash value of uuid from super block */ + u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash; + int i; + +- /* hash extended attribute prefix */ +- for (i = 0; i < prefix_len; i++) { +- hash = (hash << OCFS2_HASH_SHIFT) ^ +- (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^ +- *prefix++; +- } + /* hash extended attribute name */ + for (i = 0; i < name_len; i++) { + hash = (hash << OCFS2_HASH_SHIFT) ^ +@@ -199,14 +191,9 @@ static void ocfs2_xattr_hash_entry(struc + struct ocfs2_xattr_entry *entry) + { + u32 hash = 0; +- struct xattr_handler *handler = +- ocfs2_xattr_handler(ocfs2_xattr_get_type(entry)); +- char *prefix = handler->prefix; + char *name = (char *)header + le16_to_cpu(entry->xe_name_offset); +- int prefix_len = strlen(handler->prefix); + +- hash = ocfs2_xattr_name_hash(inode, prefix, prefix_len, name, +- entry->xe_name_len); ++ hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len); + entry->xe_name_hash = cpu_to_le32(hash); + + return; +@@ -2109,18 +2096,6 @@ cleanup: + return ret; + } + +-static inline u32 ocfs2_xattr_hash_by_name(struct inode *inode, +- int name_index, +- const char *suffix_name) +-{ +- struct xattr_handler *handler = ocfs2_xattr_handler(name_index); +- char *prefix = handler->prefix; +- int prefix_len = strlen(handler->prefix); +- +- return ocfs2_xattr_name_hash(inode, prefix, prefix_len, +- (char *)suffix_name, strlen(suffix_name)); +-} +- + /* + * Find the xattr extent rec which may contains name_hash. + * e_cpos will be the first name hash of the xattr rec. +@@ -2411,7 +2386,7 @@ static int ocfs2_xattr_index_block_find( + struct ocfs2_extent_list *el = &xb_root->xt_list; + u64 p_blkno = 0; + u32 first_hash, num_clusters = 0; +- u32 name_hash = ocfs2_xattr_hash_by_name(inode, name_index, name); ++ u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); + + if (le16_to_cpu(el->l_next_free_rec) == 0) + return -ENODATA; +@@ -4451,8 +4426,8 @@ static int ocfs2_xattr_set_in_bucket(str + size_t value_len; + char *val = (char *)xi->value; + struct ocfs2_xattr_entry *xe = xs->here; +- u32 name_hash = ocfs2_xattr_hash_by_name(inode, +- xi->name_index, xi->name); ++ u32 name_hash = ocfs2_xattr_name_hash(inode, xi->name, ++ strlen(xi->name)); + + if (!xs->not_found && !ocfs2_xattr_is_local(xe)) { + /* diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Change-ocfs2_get_-_extent_tree-to-ocfs2_ini.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Change-ocfs2_get_-_extent_tree-to-ocfs2_ini.patch new file mode 100644 index 000000000..a78f397fb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Change-ocfs2_get_-_extent_tree-to-ocfs2_ini.patch @@ -0,0 +1,348 @@ +From: Joel Becker +Subject: ocfs2: Change ocfs2_get_*_extent_tree() to ocfs2_init_*_extent_tree() +Patch-mainline: 2.6.28? +References: FATE302067 + +The original get/put_extent_tree() functions held a reference on +et_root_bh. However, every single caller already has a safe reference, +making the get/put cycle irrelevant. + +We change ocfs2_get_*_extent_tree() to ocfs2_init_*_extent_tree(). It +no longer gets a reference on et_root_bh. ocfs2_put_extent_tree() is +removed. Callers now have a simpler init+use pattern. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 49 +++++++++++++++++++++---------------------------- + fs/ocfs2/alloc.h | 26 ++++++++++++-------------- + fs/ocfs2/aops.c | 6 ++---- + fs/ocfs2/dir.c | 6 ++---- + fs/ocfs2/file.c | 10 +++------- + fs/ocfs2/xattr.c | 14 ++++---------- + 6 files changed, 44 insertions(+), 67 deletions(-) + +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -55,7 +55,7 @@ + * + * To implement an on-disk btree (extent tree) type in ocfs2, add + * an ocfs2_extent_tree_operations structure and the matching +- * ocfs2_get__extent_tree() function. That's pretty much it ++ * ocfs2_init__extent_tree() function. That's pretty much it + * for the allocation portion of the extent tree. + */ + struct ocfs2_extent_tree_operations { +@@ -301,14 +301,13 @@ static struct ocfs2_extent_tree_operatio + .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters, + }; + +-static void __ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh, +- void *obj, +- struct ocfs2_extent_tree_operations *ops) ++static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ void *obj, ++ struct ocfs2_extent_tree_operations *ops) + { + et->et_ops = ops; +- get_bh(bh); + et->et_root_bh = bh; + if (!obj) + obj = (void *)bh->b_data; +@@ -321,33 +320,28 @@ static void __ocfs2_get_extent_tree(stru + et->et_ops->eo_fill_max_leaf_clusters(inode, et); + } + +-void ocfs2_get_dinode_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh) +-{ +- __ocfs2_get_extent_tree(et, inode, bh, NULL, &ocfs2_dinode_et_ops); +-} +- +-void ocfs2_get_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh) ++void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh) + { +- __ocfs2_get_extent_tree(et, inode, bh, NULL, +- &ocfs2_xattr_tree_et_ops); ++ __ocfs2_init_extent_tree(et, inode, bh, NULL, &ocfs2_dinode_et_ops); + } + +-void ocfs2_get_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, + struct inode *inode, +- struct buffer_head *bh, +- struct ocfs2_xattr_value_root *xv) ++ struct buffer_head *bh) + { +- __ocfs2_get_extent_tree(et, inode, bh, xv, +- &ocfs2_xattr_value_et_ops); ++ __ocfs2_init_extent_tree(et, inode, bh, NULL, ++ &ocfs2_xattr_tree_et_ops); + } + +-void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) ++void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ struct ocfs2_xattr_value_root *xv) + { +- brelse(et->et_root_bh); ++ __ocfs2_init_extent_tree(et, inode, bh, xv, ++ &ocfs2_xattr_value_et_ops); + } + + static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et, +@@ -6800,10 +6794,9 @@ int ocfs2_convert_inline_data_to_extents + * this proves to be false, we could always re-build + * the in-inode data from our pages. + */ +- ocfs2_get_dinode_extent_tree(&et, inode, di_bh); ++ ocfs2_init_dinode_extent_tree(&et, inode, di_bh); + ret = ocfs2_insert_extent(osb, handle, inode, &et, + 0, block, 1, 0, NULL); +- ocfs2_put_extent_tree(&et); + if (ret) { + mlog_errno(ret); + goto out_commit; +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -41,7 +41,7 @@ + * + * ocfs2_extent_tree becomes the first-class object for extent tree + * manipulation. Callers of the alloc.c code need to fill it via one of +- * the ocfs2_get_*_extent_tree() operations below. ++ * the ocfs2_init_*_extent_tree() operations below. + * + * ocfs2_extent_tree contains info for the root of the b-tree, it must have a + * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree +@@ -59,21 +59,19 @@ struct ocfs2_extent_tree { + }; + + /* +- * ocfs2_*_get_extent_tree() will fill an ocfs2_extent_tree from the +- * specified object buffer. The bh is referenced until +- * ocfs2_put_extent_tree(). ++ * ocfs2_init_*_extent_tree() will fill an ocfs2_extent_tree from the ++ * specified object buffer. + */ +-void ocfs2_get_dinode_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh); +-void ocfs2_get_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh); +-void ocfs2_get_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh); ++void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, + struct inode *inode, +- struct buffer_head *bh, +- struct ocfs2_xattr_value_root *xv); +-void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et); ++ struct buffer_head *bh); ++void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ struct ocfs2_xattr_value_root *xv); + + struct ocfs2_alloc_context; + int ocfs2_insert_extent(struct ocfs2_super *osb, +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -1277,11 +1277,10 @@ static int ocfs2_write_cluster(struct ad + goto out; + } + } else if (unwritten) { +- ocfs2_get_dinode_extent_tree(&et, inode, wc->w_di_bh); ++ ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh); + ret = ocfs2_mark_extent_written(inode, &et, + wc->w_handle, cpos, 1, phys, + meta_ac, &wc->w_dealloc); +- ocfs2_put_extent_tree(&et); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1722,11 +1721,10 @@ int ocfs2_write_begin_nolock(struct addr + (long long)i_size_read(inode), le32_to_cpu(di->i_clusters), + clusters_to_alloc, extents_to_split); + +- ocfs2_get_dinode_extent_tree(&et, inode, wc->w_di_bh); ++ ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh); + ret = ocfs2_lock_allocators(inode, &et, + clusters_to_alloc, extents_to_split, + &data_ac, &meta_ac); +- ocfs2_put_extent_tree(&et); + if (ret) { + mlog_errno(ret); + goto out; +--- a/fs/ocfs2/dir.c ++++ b/fs/ocfs2/dir.c +@@ -1194,7 +1194,7 @@ static int ocfs2_expand_inline_dir(struc + handle_t *handle; + struct ocfs2_extent_tree et; + +- ocfs2_get_dinode_extent_tree(&et, dir, di_bh); ++ ocfs2_init_dinode_extent_tree(&et, dir, di_bh); + + alloc = ocfs2_clusters_for_bytes(sb, bytes); + +@@ -1363,7 +1363,6 @@ out: + + brelse(dirdata_bh); + +- ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -1485,9 +1484,8 @@ static int ocfs2_extend_dir(struct ocfs2 + spin_lock(&OCFS2_I(dir)->ip_lock); + if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) { + spin_unlock(&OCFS2_I(dir)->ip_lock); +- ocfs2_get_dinode_extent_tree(&et, dir, parent_fe_bh); ++ ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh); + num_free_extents = ocfs2_num_free_extents(osb, dir, &et); +- ocfs2_put_extent_tree(&et); + if (num_free_extents < 0) { + status = num_free_extents; + mlog_errno(status); +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -512,12 +512,11 @@ int ocfs2_add_inode_data(struct ocfs2_su + int ret; + struct ocfs2_extent_tree et; + +- ocfs2_get_dinode_extent_tree(&et, inode, fe_bh); ++ ocfs2_init_dinode_extent_tree(&et, inode, fe_bh); + ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset, + clusters_to_add, mark_unwritten, + &et, handle, + data_ac, meta_ac, reason_ret); +- ocfs2_put_extent_tree(&et); + + return ret; + } +@@ -568,10 +567,9 @@ restart_all: + (unsigned long long)OCFS2_I(inode)->ip_blkno, + (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters), + clusters_to_add); +- ocfs2_get_dinode_extent_tree(&et, inode, bh); ++ ocfs2_init_dinode_extent_tree(&et, inode, bh); + status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, + &data_ac, &meta_ac); +- ocfs2_put_extent_tree(&et); + if (status) { + mlog_errno(status); + goto leave; +@@ -1243,11 +1241,10 @@ static int __ocfs2_remove_inode_range(st + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + struct ocfs2_extent_tree et; + +- ocfs2_get_dinode_extent_tree(&et, inode, di_bh); ++ ocfs2_init_dinode_extent_tree(&et, inode, di_bh); + + ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); + if (ret) { +- ocfs2_put_extent_tree(&et); + mlog_errno(ret); + return ret; + } +@@ -1304,7 +1301,6 @@ out: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + +- ocfs2_put_extent_tree(&et); + return ret; + } + +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -227,7 +227,7 @@ static int ocfs2_xattr_extend_allocation + + mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add); + +- ocfs2_get_xattr_value_extent_tree(&et, inode, xattr_bh, xv); ++ ocfs2_init_xattr_value_extent_tree(&et, inode, xattr_bh, xv); + + restart_all: + +@@ -323,7 +323,6 @@ leave: + goto restart_all; + } + +- ocfs2_put_extent_tree(&et); + return status; + } + +@@ -341,11 +340,10 @@ static int __ocfs2_remove_xattr_range(st + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_extent_tree et; + +- ocfs2_get_xattr_value_extent_tree(&et, inode, root_bh, xv); ++ ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv); + + ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); + if (ret) { +- ocfs2_put_extent_tree(&et); + mlog_errno(ret); + return ret; + } +@@ -401,7 +399,6 @@ out: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + +- ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -3648,7 +3645,7 @@ static int ocfs2_add_new_xattr_cluster(s + (unsigned long long)OCFS2_I(inode)->ip_blkno, + prev_cpos, prev_blkno); + +- ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh); ++ ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); + + ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, + &data_ac, &meta_ac); +@@ -3743,7 +3740,6 @@ leave: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + +- ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -4352,7 +4348,7 @@ static int ocfs2_rm_xattr_cluster(struct + struct ocfs2_cached_dealloc_ctxt dealloc; + struct ocfs2_extent_tree et; + +- ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh); ++ ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); + + ocfs2_init_dealloc_ctxt(&dealloc); + +@@ -4363,7 +4359,6 @@ static int ocfs2_rm_xattr_cluster(struct + + ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); + if (ret) { +- ocfs2_put_extent_tree(&et); + mlog_errno(ret); + return ret; + } +@@ -4423,7 +4418,6 @@ out: + + ocfs2_run_deallocs(osb, &dealloc); + +- ocfs2_put_extent_tree(&et); + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Change-quotafile-names.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Change-quotafile-names.patch new file mode 100644 index 000000000..8652628d0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Change-quotafile-names.patch @@ -0,0 +1,27 @@ +From: Jan Kara +References: fate#302681 +Subject: ocfs2: Change file names of local quota files to be consistent +Patch-mainline: 2.6.29? + +Change names of local quota files to be consistent with how other node-local +system files are named. + +Signed-off-by: Jan Kara + +--- + fs/ocfs2/ocfs2_fs.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -372,8 +372,8 @@ static struct ocfs2_system_inode_info oc + [JOURNAL_SYSTEM_INODE] = { "journal:%04d", OCFS2_JOURNAL_FL, S_IFREG | 0644 }, + [LOCAL_ALLOC_SYSTEM_INODE] = { "local_alloc:%04d", OCFS2_BITMAP_FL | OCFS2_LOCAL_ALLOC_FL, S_IFREG | 0644 }, + [TRUNCATE_LOG_SYSTEM_INODE] = { "truncate_log:%04d", OCFS2_DEALLOC_FL, S_IFREG | 0644 }, +- [LOCAL_USER_QUOTA_SYSTEM_INODE] = { "aquota%04d.user", OCFS2_QUOTA_FL, S_IFREG | 0644 }, +- [LOCAL_GROUP_QUOTA_SYSTEM_INODE] = { "aquota%04d.group", OCFS2_QUOTA_FL, S_IFREG | 0644 }, ++ [LOCAL_USER_QUOTA_SYSTEM_INODE] = { "aquota.user:%04d", OCFS2_QUOTA_FL, S_IFREG | 0644 }, ++ [LOCAL_GROUP_QUOTA_SYSTEM_INODE] = { "aquota.group:%04d", OCFS2_QUOTA_FL, S_IFREG | 0644 }, + }; + + /* Parameter passed from mount.ocfs2 to module */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Comment-struct-ocfs2_extent_tree_operations.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Comment-struct-ocfs2_extent_tree_operations.patch new file mode 100644 index 000000000..8dc6cbd97 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Comment-struct-ocfs2_extent_tree_operations.patch @@ -0,0 +1,87 @@ +From: Joel Becker +Subject: ocfs2: Comment struct ocfs2_extent_tree_operations. +Patch-mainline: 2.6.28? +References: FATE302067 + +struct ocfs2_extent_tree_operations provides methods for the different +on-disk btrees in ocfs2. Describing what those methods do is probably a +good idea. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- + 1 files changed, 43 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index d196d40..51c3183 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -50,21 +50,62 @@ + #include "buffer_head_io.h" + + ++/* ++ * Operations for a specific extent tree type. ++ * ++ * To implement an on-disk btree (extent tree) type in ocfs2, add ++ * an ocfs2_extent_tree_operations structure and the matching ++ * ocfs2_get__extent_tree() function. That's pretty much it ++ * for the allocation portion of the extent tree. ++ */ + struct ocfs2_extent_tree_operations { ++ /* ++ * last_eb_blk is the block number of the right most leaf extent ++ * block. Most on-disk structures containing an extent tree store ++ * this value for fast access. The ->eo_set_last_eb_blk() and ++ * ->eo_get_last_eb_blk() operations access this value. They are ++ * both required. ++ */ + void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et, + u64 blkno); + u64 (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et); ++ ++ /* ++ * The on-disk structure usually keeps track of how many total ++ * clusters are stored in this extent tree. This function updates ++ * that value. new_clusters is the delta, and must be ++ * added to the total. Required. ++ */ + void (*eo_update_clusters)(struct inode *inode, + struct ocfs2_extent_tree *et, + u32 new_clusters); ++ ++ /* ++ * If ->eo_insert_check() exists, it is called before rec is ++ * inserted into the extent tree. It is optional. ++ */ + int (*eo_insert_check)(struct inode *inode, + struct ocfs2_extent_tree *et, + struct ocfs2_extent_rec *rec); + int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et); + +- /* These are internal to ocfs2_extent_tree and don't have +- * accessor functions */ ++ /* ++ * -------------------------------------------------------------- ++ * The remaining are internal to ocfs2_extent_tree and don't have ++ * accessor functions ++ */ ++ ++ /* ++ * ->eo_fill_root_el() takes et->et_object and sets et->et_root_el. ++ * It is required. ++ */ + void (*eo_fill_root_el)(struct ocfs2_extent_tree *et); ++ ++ /* ++ * ->eo_fill_max_leaf_clusters sets et->et_max_leaf_clusters if ++ * it exists. If it does not, et->et_max_leaf_clusters is set ++ * to 0 (unlimited). Optional. ++ */ + void (*eo_fill_max_leaf_clusters)(struct inode *inode, + struct ocfs2_extent_tree *et); + }; +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-an-xattr-bucket-s-block.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-an-xattr-bucket-s-block.patch new file mode 100644 index 000000000..65abb1812 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-an-xattr-bucket-s-block.patch @@ -0,0 +1,110 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 16:21:03 -0700 +Subject: ocfs2: Convenient access to an xattr bucket's block number. +Patch-mainline: 2.6.29 + +The xattr code often wants to know the block number of an xattr bucket. +This is usually found by dereferencing the first bh hanging off of the +ocfs2_xattr_bucket structure. Rather than do this all the time, let's +provide a nice little macro. The idea is ripped from the ocfs2_path +code. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 20 +++++++++++--------- + 1 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 9c0ee42..3cf8e80 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -154,6 +154,8 @@ static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) + return len / sizeof(struct ocfs2_xattr_entry); + } + ++#define bucket_blkno(_b) ((_b)->bu_bhs[0]->b_blocknr) ++ + static inline const char *ocfs2_xattr_prefix(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -2290,7 +2292,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + * If we have found the xattr enty, read all the blocks in + * this bucket. + */ +- ret = ocfs2_read_blocks(inode, xs->bucket.bu_bhs[0]->b_blocknr + 1, ++ ret = ocfs2_read_blocks(inode, bucket_blkno(&xs->bucket) + 1, + blk_per_bucket - 1, &xs->bucket.bu_bhs[1], + 0); + if (ret) { +@@ -2300,7 +2302,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + + xs->here = &xs->header->xh_entries[index]; + mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name, +- (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr, index); ++ (unsigned long long)bucket_blkno(&xs->bucket), index); + } else + ret = -ENODATA; + +@@ -2637,7 +2639,7 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + if (!xs->not_found) { + if (OCFS2_XATTR_BUCKET_SIZE != blocksize) { + ret = ocfs2_read_blocks(inode, +- xs->bucket.bu_bhs[0]->b_blocknr + 1, ++ bucket_blkno(&xs->bucket) + 1, + blk_per_bucket - 1, &xs->bucket.bu_bhs[1], + 0); + if (ret) { +@@ -2835,7 +2837,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + size_t end, offset, len, value_len; + struct ocfs2_xattr_header *xh; + char *entries, *buf, *bucket_buf = NULL; +- u64 blkno = bucket->bu_bhs[0]->b_blocknr; ++ u64 blkno = bucket_blkno(bucket); + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u16 xh_free_start; + size_t blocksize = inode->i_sb->s_blocksize; +@@ -4124,11 +4126,11 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + + mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", + (unsigned long)xi->value_len, xi->name_index, +- (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr); ++ (unsigned long long)bucket_blkno(&xs->bucket)); + + if (!xs->bucket.bu_bhs[1]) { + ret = ocfs2_read_blocks(inode, +- xs->bucket.bu_bhs[0]->b_blocknr + 1, ++ bucket_blkno(&xs->bucket) + 1, + blk_per_bucket - 1, &xs->bucket.bu_bhs[1], + 0); + if (ret) { +@@ -4540,7 +4542,7 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, + xh->xh_entries[0].xe_name_hash) { + mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, " + "hash = %u\n", +- (unsigned long long)bucket->bu_bhs[0]->b_blocknr, ++ (unsigned long long)bucket_blkno(bucket), + le32_to_cpu(xh->xh_entries[0].xe_name_hash)); + return -ENOSPC; + } +@@ -4574,7 +4576,7 @@ try_again: + + mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " + "of %u which exceed block size\n", +- (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr, ++ (unsigned long long)bucket_blkno(&xs->bucket), + header_size); + + if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) +@@ -4614,7 +4616,7 @@ try_again: + mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, " + "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len =" + " %u\n", xs->not_found, +- (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr, ++ (unsigned long long)bucket_blkno(&xs->bucket), + free, need, max_free, le16_to_cpu(xh->xh_free_start), + le16_to_cpu(xh->xh_name_value_len)); + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-an-xattr-bucket-s-header.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-an-xattr-bucket-s-header.patch new file mode 100644 index 000000000..380175d96 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-an-xattr-bucket-s-header.patch @@ -0,0 +1,137 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 17:04:49 -0700 +Subject: ocfs2: Convenient access to an xattr bucket's header. +Patch-mainline: 2.6.29 + +The xattr code often wants to access the ocfs2_xattr_header at the start +of an bucket. Rather than walk the pointer chains, let's just create +another nice macro. As a side benefit, we can get rid of the mostly +spurious ->bu_xh element on the bucket structure. The idea is ripped +from the ocfs2_path code. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 28 ++++++++++++---------------- + 1 files changed, 12 insertions(+), 16 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 8594df3..1b77302 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -62,7 +62,6 @@ struct ocfs2_xattr_def_value_root { + + struct ocfs2_xattr_bucket { + struct buffer_head *bu_bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET]; +- struct ocfs2_xattr_header *bu_xh; + }; + + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) +@@ -156,6 +155,7 @@ static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) + + #define bucket_blkno(_b) ((_b)->bu_bhs[0]->b_blocknr) + #define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data) ++#define bucket_xh(_b) ((struct ocfs2_xattr_header *)bucket_block((_b), 0)) + + static inline const char *ocfs2_xattr_prefix(int name_index) + { +@@ -798,7 +798,7 @@ static int ocfs2_xattr_block_get(struct inode *inode, + + if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { + ret = ocfs2_xattr_bucket_get_name_value(inode, +- xs->bucket.bu_xh, ++ bucket_xh(&xs->bucket), + i, + &block_off, + &name_offset); +@@ -2280,11 +2280,9 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + bh = NULL; + } + xs->bucket.bu_bhs[0] = lower_bh; +- xs->bucket.bu_xh = (struct ocfs2_xattr_header *) +- bucket_block(&xs->bucket, 0); + lower_bh = NULL; + +- xs->header = xs->bucket.bu_xh; ++ xs->header = bucket_xh(&xs->bucket); + xs->base = bucket_block(&xs->bucket, 0); + xs->end = xs->base + inode->i_sb->s_blocksize; + +@@ -2379,17 +2377,16 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + goto out; + } + +- bucket.bu_xh = (struct ocfs2_xattr_header *)bucket_block(&bucket, 0); + /* + * The real bucket num in this series of blocks is stored + * in the 1st bucket. + */ + if (i == 0) +- num_buckets = le16_to_cpu(bucket.bu_xh->xh_num_buckets); ++ num_buckets = le16_to_cpu(bucket_xh(&bucket)->xh_num_buckets); + + mlog(0, "iterating xattr bucket %llu, first hash %u\n", + (unsigned long long)blkno, +- le32_to_cpu(bucket.bu_xh->xh_entries[0].xe_name_hash)); ++ le32_to_cpu(bucket_xh(&bucket)->xh_entries[0].xe_name_hash)); + if (func) { + ret = func(inode, &bucket, para); + if (ret) { +@@ -2444,14 +2441,14 @@ static int ocfs2_list_xattr_bucket(struct inode *inode, + int i, block_off, new_offset; + const char *prefix, *name; + +- for (i = 0 ; i < le16_to_cpu(bucket->bu_xh->xh_count); i++) { +- struct ocfs2_xattr_entry *entry = &bucket->bu_xh->xh_entries[i]; ++ for (i = 0 ; i < le16_to_cpu(bucket_xh(bucket)->xh_count); i++) { ++ struct ocfs2_xattr_entry *entry = &bucket_xh(bucket)->xh_entries[i]; + type = ocfs2_xattr_get_type(entry); + prefix = ocfs2_xattr_prefix(type); + + if (prefix) { + ret = ocfs2_xattr_bucket_get_name_value(inode, +- bucket->bu_xh, ++ bucket_xh(bucket), + i, + &block_off, + &new_offset); +@@ -2631,8 +2628,7 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + + xs->bucket.bu_bhs[0] = new_bh; + get_bh(new_bh); +- xs->bucket.bu_xh = (struct ocfs2_xattr_header *)bucket_block(&xs->bucket, 0); +- xs->header = xs->bucket.bu_xh; ++ xs->header = bucket_xh(&xs->bucket); + + xs->base = new_bh->b_data; + xs->end = xs->base + inode->i_sb->s_blocksize; +@@ -4398,7 +4394,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + struct ocfs2_xattr_search *xs) + { + handle_t *handle = NULL; +- struct ocfs2_xattr_header *xh = xs->bucket.bu_xh; ++ struct ocfs2_xattr_header *xh = bucket_xh(&xs->bucket); + struct ocfs2_xattr_entry *last = &xh->xh_entries[ + le16_to_cpu(xh->xh_count) - 1]; + int ret = 0; +@@ -4533,7 +4529,7 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, + struct ocfs2_xattr_bucket *bucket, + const char *name) + { +- struct ocfs2_xattr_header *xh = bucket->bu_xh; ++ struct ocfs2_xattr_header *xh = bucket_xh(bucket); + u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); + + if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash)) +@@ -4703,7 +4699,7 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + void *para) + { + int ret = 0; +- struct ocfs2_xattr_header *xh = bucket->bu_xh; ++ struct ocfs2_xattr_header *xh = bucket_xh(bucket); + u16 i; + struct ocfs2_xattr_entry *xe; + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-xattr-bucket-data-blocks.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-xattr-bucket-data-blocks.patch new file mode 100644 index 000000000..a5c391682 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Convenient-access-to-xattr-bucket-data-blocks.patch @@ -0,0 +1,91 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 16:57:21 -0700 +Subject: ocfs2: Convenient access to xattr bucket data blocks. +Patch-mainline: 2.6.29 + +The xattr code often wants to access the data pointer for blocks in an +xattr bucket. This is usually found by dereferencing the bh array +hanging off of the ocfs2_xattr_bucket structure. Rather than do this +all the time, let's provide a nice little macro. The idea is ripped +from the ocfs2_path code. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 15 ++++++++------- + 1 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 3cf8e80..8594df3 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -155,6 +155,7 @@ static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) + } + + #define bucket_blkno(_b) ((_b)->bu_bhs[0]->b_blocknr) ++#define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data) + + static inline const char *ocfs2_xattr_prefix(int name_index) + { +@@ -801,7 +802,7 @@ static int ocfs2_xattr_block_get(struct inode *inode, + i, + &block_off, + &name_offset); +- xs->base = xs->bucket.bu_bhs[block_off]->b_data; ++ xs->base = bucket_block(&xs->bucket, block_off); + } + if (ocfs2_xattr_is_local(xs->here)) { + memcpy(buffer, (void *)xs->base + +@@ -2280,11 +2281,11 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + } + xs->bucket.bu_bhs[0] = lower_bh; + xs->bucket.bu_xh = (struct ocfs2_xattr_header *) +- xs->bucket.bu_bhs[0]->b_data; ++ bucket_block(&xs->bucket, 0); + lower_bh = NULL; + + xs->header = xs->bucket.bu_xh; +- xs->base = xs->bucket.bu_bhs[0]->b_data; ++ xs->base = bucket_block(&xs->bucket, 0); + xs->end = xs->base + inode->i_sb->s_blocksize; + + if (found) { +@@ -2378,7 +2379,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + goto out; + } + +- bucket.bu_xh = (struct ocfs2_xattr_header *)bucket.bu_bhs[0]->b_data; ++ bucket.bu_xh = (struct ocfs2_xattr_header *)bucket_block(&bucket, 0); + /* + * The real bucket num in this series of blocks is stored + * in the 1st bucket. +@@ -2457,7 +2458,7 @@ static int ocfs2_list_xattr_bucket(struct inode *inode, + if (ret) + break; + +- name = (const char *)bucket->bu_bhs[block_off]->b_data + ++ name = (const char *)bucket_block(bucket, block_off) + + new_offset; + ret = ocfs2_xattr_list_entry(xl->buffer, + xl->buffer_size, +@@ -2630,7 +2631,7 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + + xs->bucket.bu_bhs[0] = new_bh; + get_bh(new_bh); +- xs->bucket.bu_xh = (struct ocfs2_xattr_header *)xs->bucket.bu_bhs[0]->b_data; ++ xs->bucket.bu_xh = (struct ocfs2_xattr_header *)bucket_block(&xs->bucket, 0); + xs->header = xs->bucket.bu_xh; + + xs->base = new_bh->b_data; +@@ -3931,7 +3932,7 @@ static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode, + int block_off = offs >> inode->i_sb->s_blocksize_bits; + + offs = offs % inode->i_sb->s_blocksize; +- return bucket->bu_bhs[block_off]->b_data + offs; ++ return bucket_block(bucket, block_off) + offs; + } + + /* +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Copy-xattr-buckets-with-a-dedicated-function.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Copy-xattr-buckets-with-a-dedicated-function.patch new file mode 100644 index 000000000..941c43a06 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Copy-xattr-buckets-with-a-dedicated-function.patch @@ -0,0 +1,75 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 18:54:43 -0700 +Subject: ocfs2: Copy xattr buckets with a dedicated function. +Patch-mainline: 2.6.29 + +Now that the places that copy whole buckets are using struct +ocfs2_xattr_bucket, we can do the copy in a dedicated function. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 26 ++++++++++++++++---------- + 1 files changed, 16 insertions(+), 10 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 99aefe4..71d9e7b 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -240,6 +240,19 @@ static void ocfs2_xattr_bucket_journal_dirty(handle_t *handle, + ocfs2_journal_dirty(handle, bucket->bu_bhs[i]); + } + ++static void ocfs2_xattr_bucket_copy_data(struct inode *inode, ++ struct ocfs2_xattr_bucket *dest, ++ struct ocfs2_xattr_bucket *src) ++{ ++ int i; ++ int blocksize = inode->i_sb->s_blocksize; ++ int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ for (i = 0; i < blks; i++) { ++ memcpy(bucket_block(dest, i), bucket_block(src, i), ++ blocksize); ++ } ++} + + static inline const char *ocfs2_xattr_prefix(int name_index) + { +@@ -3299,9 +3312,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + } + + /* copy the whole bucket to the new first. */ +- for (i = 0; i < blk_per_bucket; i++) +- memcpy(bucket_block(&t_bucket, i), bucket_block(&s_bucket, i), +- blocksize); ++ ocfs2_xattr_bucket_copy_data(inode, &t_bucket, &s_bucket); + + /* update the new bucket. */ + xh = bucket_xh(&t_bucket); +@@ -3410,9 +3421,7 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + u64 t_blkno, + int t_is_new) + { +- int ret, i; +- int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- int blocksize = inode->i_sb->s_blocksize; ++ int ret; + struct ocfs2_xattr_bucket s_bucket, t_bucket; + + BUG_ON(s_blkno == t_blkno); +@@ -3443,10 +3452,7 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + if (ret) + goto out; + +- for (i = 0; i < blk_per_bucket; i++) { +- memcpy(bucket_block(&t_bucket, i), bucket_block(&s_bucket, i), +- blocksize); +- } ++ ocfs2_xattr_bucket_copy_data(inode, &t_bucket, &s_bucket); + ocfs2_xattr_bucket_journal_dirty(handle, inode, &t_bucket); + + out: +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Create-specific-get_extent_tree-functions.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Create-specific-get_extent_tree-functions.patch new file mode 100644 index 000000000..026a9ccbb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Create-specific-get_extent_tree-functions.patch @@ -0,0 +1,183 @@ +From: Joel Becker +Subject: ocfs2: Create specific get_extent_tree functions. +Patch-mainline: 2.6.28? +References: FATE302067 + +A caller knows what kind of extent tree they have. There's no reason +they have to call ocfs2_get_extent_tree() with a NULL when they could +just as easily call a specific function to their type of extent tree. + +Introduce ocfs2_dinode_get_extent_tree(), +ocfs2_xattr_tree_get_extent_tree(), and +ocfs2_xattr_value_get_extent_tree(). They only take the necessary +arguments, calling into the underlying __ocfs2_get_extent_tree() to do +the real work. + +__ocfs2_get_extent_tree() is the old ocfs2_get_extent_tree(), but +without needing any switch-by-type logic. + +ocfs2_get_extent_tree() is now a wrapper around the specific calls. It +exists because a couple alloc.c functions can take et_type. This will +go later. + +Another benefit is that ocfs2_xattr_value_get_extent_tree() can take a +struct ocfs2_xattr_value_root* instead of void*. This gives us +typechecking where we didn't have it before. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 76 +++++++++++++++++++++++++++++++++++++++--------------- + fs/ocfs2/alloc.h | 2 +- + 2 files changed, 56 insertions(+), 22 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 7c0721d..243bacf 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -192,7 +192,7 @@ static int ocfs2_xattr_value_sanity_check(struct inode *inode, + return 0; + } + +-static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { ++static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = { + .eo_set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, + .eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, + .eo_update_clusters = ocfs2_xattr_value_update_clusters, +@@ -256,27 +256,21 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters, + }; + +-static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh, +- enum ocfs2_extent_tree_type et_type, +- void *obj) ++static void __ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ void *obj, ++ enum ocfs2_extent_tree_type et_type, ++ struct ocfs2_extent_tree_operations *ops) + { + et->et_type = et_type; ++ et->et_ops = ops; + get_bh(bh); + et->et_root_bh = bh; + if (!obj) + obj = (void *)bh->b_data; + et->et_object = obj; + +- if (et_type == OCFS2_DINODE_EXTENT) { +- et->et_ops = &ocfs2_dinode_et_ops; +- } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) { +- et->et_ops = &ocfs2_xattr_et_ops; +- } else if (et_type == OCFS2_XATTR_TREE_EXTENT) { +- et->et_ops = &ocfs2_xattr_tree_et_ops; +- } +- + et->et_ops->eo_fill_root_el(et); + if (!et->et_ops->eo_fill_max_leaf_clusters) + et->et_max_leaf_clusters = 0; +@@ -284,6 +278,49 @@ static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, + et->et_ops->eo_fill_max_leaf_clusters(inode, et); + } + ++static void ocfs2_get_dinode_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh) ++{ ++ __ocfs2_get_extent_tree(et, inode, bh, NULL, OCFS2_DINODE_EXTENT, ++ &ocfs2_dinode_et_ops); ++} ++ ++static void ocfs2_get_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh) ++{ ++ __ocfs2_get_extent_tree(et, inode, bh, NULL, ++ OCFS2_XATTR_TREE_EXTENT, ++ &ocfs2_xattr_tree_et_ops); ++} ++ ++static void ocfs2_get_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ struct ocfs2_xattr_value_root *xv) ++{ ++ __ocfs2_get_extent_tree(et, inode, bh, xv, ++ OCFS2_XATTR_VALUE_EXTENT, ++ &ocfs2_xattr_value_et_ops); ++} ++ ++static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ enum ocfs2_extent_tree_type et_type, ++ void *obj) ++{ ++ if (et_type == OCFS2_DINODE_EXTENT) ++ ocfs2_get_dinode_extent_tree(et, inode, bh); ++ else if (et_type == OCFS2_XATTR_VALUE_EXTENT) ++ ocfs2_get_xattr_tree_extent_tree(et, inode, bh); ++ else if (et_type == OCFS2_XATTR_TREE_EXTENT) ++ ocfs2_get_xattr_value_extent_tree(et, inode, bh, obj); ++ else ++ BUG(); ++} ++ + static void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) + { + brelse(et->et_root_bh); +@@ -4441,8 +4478,7 @@ int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, + int status; + struct ocfs2_extent_tree et; + +- ocfs2_get_extent_tree(&et, inode, root_bh, OCFS2_DINODE_EXTENT, +- NULL); ++ ocfs2_get_dinode_extent_tree(&et, inode, root_bh); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, + flags, meta_ac, &et); +@@ -4460,13 +4496,12 @@ int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, + u32 new_clusters, + u8 flags, + struct ocfs2_alloc_context *meta_ac, +- void *obj) ++ struct ocfs2_xattr_value_root *xv) + { + int status; + struct ocfs2_extent_tree et; + +- ocfs2_get_extent_tree(&et, inode, root_bh, +- OCFS2_XATTR_VALUE_EXTENT, obj); ++ ocfs2_get_xattr_value_extent_tree(&et, inode, root_bh, xv); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, + flags, meta_ac, &et); +@@ -4488,8 +4523,7 @@ int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, + int status; + struct ocfs2_extent_tree et; + +- ocfs2_get_extent_tree(&et, inode, root_bh, OCFS2_XATTR_TREE_EXTENT, +- NULL); ++ ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, + flags, meta_ac, &et); +diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h +index ff40c8f..04a551f 100644 +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -56,7 +56,7 @@ int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, + u32 new_clusters, + u8 flags, + struct ocfs2_alloc_context *meta_ac, +- void *private); ++ struct ocfs2_xattr_value_root *xv); + int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, + handle_t *handle, + struct inode *inode, +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Delete-all-xattr-buckets-during.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Delete-all-xattr-buckets-during.patch new file mode 100644 index 000000000..842c3c430 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Delete-all-xattr-buckets-during.patch @@ -0,0 +1,126 @@ +From: Tao Ma +Subject: [PATCH 15/16] ocfs2: Delete all xattr buckets during inode removal +Patch-mainline: 2.6.28? +References: FATE302067 + +In inode removal, we need to iterate all the buckets, remove any +externally-stored EA values and delete the xattr buckets. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 files changed, 80 insertions(+), 4 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 408553c..e78ed7a 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -147,6 +147,9 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs); + ++static int ocfs2_delete_xattr_index_block(struct inode *inode, ++ struct buffer_head *xb_bh); ++ + static inline struct xattr_handler *ocfs2_xattr_handler(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -1527,13 +1530,14 @@ static int ocfs2_xattr_block_remove(struct inode *inode, + struct buffer_head *blk_bh) + { + struct ocfs2_xattr_block *xb; +- struct ocfs2_xattr_header *header; + int ret = 0; + + xb = (struct ocfs2_xattr_block *)blk_bh->b_data; +- header = &(xb->xb_attrs.xb_header); +- +- ret = ocfs2_remove_value_outside(inode, blk_bh, header); ++ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) { ++ struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header); ++ ret = ocfs2_remove_value_outside(inode, blk_bh, header); ++ } else ++ ret = ocfs2_delete_xattr_index_block(inode, blk_bh); + + return ret; + } +@@ -4754,3 +4758,75 @@ out: + mlog_exit(ret); + return ret; + } ++ ++static int ocfs2_delete_xattr_in_bucket(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ void *para) ++{ ++ int ret = 0; ++ struct ocfs2_xattr_header *xh = bucket->xh; ++ u16 i; ++ struct ocfs2_xattr_entry *xe; ++ ++ for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { ++ xe = &xh->xh_entries[i]; ++ if (ocfs2_xattr_is_local(xe)) ++ continue; ++ ++ ret = ocfs2_xattr_bucket_value_truncate(inode, ++ bucket->bhs[0], ++ i, 0); ++ if (ret) { ++ mlog_errno(ret); ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static int ocfs2_delete_xattr_index_block(struct inode *inode, ++ struct buffer_head *xb_bh) ++{ ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)xb_bh->b_data; ++ struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; ++ int ret = 0; ++ u32 name_hash = UINT_MAX, e_cpos, num_clusters; ++ u64 p_blkno; ++ ++ if (le16_to_cpu(el->l_next_free_rec) == 0) ++ return 0; ++ ++ while (name_hash > 0) { ++ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, ++ &e_cpos, &num_clusters, el); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters, ++ ocfs2_delete_xattr_in_bucket, ++ NULL); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_rm_xattr_cluster(inode, xb_bh, ++ p_blkno, e_cpos, num_clusters); ++ if (ret) { ++ mlog_errno(ret); ++ break; ++ } ++ ++ if (e_cpos == 0) ++ break; ++ ++ name_hash = e_cpos - 1; ++ } ++ ++out: ++ return ret; ++} +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Determine-an-extent-tree-s-max_leaf_clusters.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Determine-an-extent-tree-s-max_leaf_clusters.patch new file mode 100644 index 000000000..8e5aa7c8c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Determine-an-extent-tree-s-max_leaf_clusters.patch @@ -0,0 +1,78 @@ +From: Joel Becker +Subject: ocfs2: Determine an extent tree's max_leaf_clusters in an et_op. +Patch-mainline: 2.6.28? +References: FATE302067 + +Provide an optional extent_tree_operation to specify the +max_leaf_clusters of an ocfs2_extent_tree. If not provided, the value +is 0 (unlimited). + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 18 +++++++++++++++--- + 1 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 0b900f6..7c0721d 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -76,6 +76,8 @@ struct ocfs2_extent_tree_operations { + /* These are internal to ocfs2_extent_tree and don't have + * accessor functions */ + void (*eo_fill_root_el)(struct ocfs2_extent_tree *et); ++ void (*eo_fill_max_leaf_clusters)(struct inode *inode, ++ struct ocfs2_extent_tree *et); + }; + + struct ocfs2_extent_tree { +@@ -205,6 +207,14 @@ static void ocfs2_xattr_tree_fill_root_el(struct ocfs2_extent_tree *et) + et->et_root_el = &xb->xb_attrs.xb_root.xt_list; + } + ++static void ocfs2_xattr_tree_fill_max_leaf_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et) ++{ ++ et->et_max_leaf_clusters = ++ ocfs2_clusters_for_bytes(inode->i_sb, ++ OCFS2_MAX_XATTR_TREE_LEAF_SIZE); ++} ++ + static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +@@ -243,6 +253,7 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .eo_update_clusters = ocfs2_xattr_tree_update_clusters, + .eo_sanity_check = ocfs2_xattr_tree_sanity_check, + .eo_fill_root_el = ocfs2_xattr_tree_fill_root_el, ++ .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters, + }; + + static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, +@@ -254,7 +265,6 @@ static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, + et->et_type = et_type; + get_bh(bh); + et->et_root_bh = bh; +- et->et_max_leaf_clusters = 0; + if (!obj) + obj = (void *)bh->b_data; + et->et_object = obj; +@@ -265,11 +275,13 @@ static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, + et->et_ops = &ocfs2_xattr_et_ops; + } else if (et_type == OCFS2_XATTR_TREE_EXTENT) { + et->et_ops = &ocfs2_xattr_tree_et_ops; +- et->et_max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, +- OCFS2_MAX_XATTR_TREE_LEAF_SIZE); + } + + et->et_ops->eo_fill_root_el(et); ++ if (!et->et_ops->eo_fill_max_leaf_clusters) ++ et->et_max_leaf_clusters = 0; ++ else ++ et->et_ops->eo_fill_max_leaf_clusters(inode, et); + } + + static void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Documentation-update-for-user_xattr-nouser_.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Documentation-update-for-user_xattr-nouser_.patch new file mode 100644 index 000000000..a121b77fc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Documentation-update-for-user_xattr-nouser_.patch @@ -0,0 +1,19 @@ +From: Mark Fasheh +Subject: ocfs2: Documentation update for user_xattr / nouser_xattr mount options +Patch-mainline: 2.6.28 + +Signed-off-by: Mark Fasheh +--- + Documentation/filesystems/ocfs2.txt | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +Index: linux-2.6.27/Documentation/filesystems/ocfs2.txt +=================================================================== +--- linux-2.6.27.orig/Documentation/filesystems/ocfs2.txt ++++ linux-2.6.27/Documentation/filesystems/ocfs2.txt +@@ -80,3 +80,5 @@ inode64 Indicates that Ocfs2 is allowe + any location in the filesystem, including those which + will result in inode numbers occupying more than 32 + bits of significance. ++user_xattr (*) Enables Extended User Attributes. ++nouser_xattr Disables Extended User Attributes. diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Don-t-check-for-NULL-before-brelse.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Don-t-check-for-NULL-before-brelse.patch new file mode 100644 index 000000000..071ec6ede --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Don-t-check-for-NULL-before-brelse.patch @@ -0,0 +1,618 @@ +From: Mark Fasheh +Subject: ocfs2: Don't check for NULL before brelse() +Patch-mainline: 2.6.28 + +This is pointless as brelse() already does the check. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 33 ++++++------------- + fs/ocfs2/aops.c | 3 +- + fs/ocfs2/dir.c | 24 +++++--------- + fs/ocfs2/file.c | 9 ++--- + fs/ocfs2/inode.c | 7 ++-- + fs/ocfs2/ioctl.c | 3 +- + fs/ocfs2/journal.c | 9 ++--- + fs/ocfs2/localalloc.c | 15 +++------ + fs/ocfs2/namei.c | 83 +++++++++++++++--------------------------------- + fs/ocfs2/suballoc.c | 29 ++++++---------- + fs/ocfs2/super.c | 3 +- + fs/ocfs2/symlink.c | 3 +- + 12 files changed, 74 insertions(+), 147 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27/fs/ocfs2/alloc.c +@@ -719,8 +719,7 @@ int ocfs2_num_free_extents(struct ocfs2_ + + retval = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec); + bail: +- if (eb_bh) +- brelse(eb_bh); ++ brelse(eb_bh); + + mlog_exit(retval); + return retval; +@@ -806,8 +805,7 @@ static int ocfs2_create_new_meta_bhs(str + bail: + if (status < 0) { + for(i = 0; i < wanted; i++) { +- if (bhs[i]) +- brelse(bhs[i]); ++ brelse(bhs[i]); + bhs[i] = NULL; + } + } +@@ -1017,8 +1015,7 @@ static int ocfs2_add_branch(struct ocfs2 + bail: + if (new_eb_bhs) { + for (i = 0; i < new_blocks; i++) +- if (new_eb_bhs[i]) +- brelse(new_eb_bhs[i]); ++ brelse(new_eb_bhs[i]); + kfree(new_eb_bhs); + } + +@@ -1116,8 +1113,7 @@ static int ocfs2_shift_tree_depth(struct + new_eb_bh = NULL; + status = 0; + bail: +- if (new_eb_bh) +- brelse(new_eb_bh); ++ brelse(new_eb_bh); + + mlog_exit(status); + return status; +@@ -1177,10 +1173,8 @@ static int ocfs2_find_branch_target(stru + goto bail; + } + +- if (bh) { +- brelse(bh); +- bh = NULL; +- } ++ brelse(bh); ++ bh = NULL; + + status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED, + inode); +@@ -1199,8 +1193,7 @@ static int ocfs2_find_branch_target(stru + + if (le16_to_cpu(el->l_next_free_rec) < + le16_to_cpu(el->l_count)) { +- if (lowest_bh) +- brelse(lowest_bh); ++ brelse(lowest_bh); + lowest_bh = bh; + get_bh(lowest_bh); + } +@@ -1214,8 +1207,7 @@ static int ocfs2_find_branch_target(stru + + *target_bh = lowest_bh; + bail: +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(status); + return status; +@@ -4480,8 +4472,7 @@ int ocfs2_insert_extent(struct ocfs2_sup + ocfs2_extent_map_insert_rec(inode, &rec); + + bail: +- if (last_eb_bh) +- brelse(last_eb_bh); ++ brelse(last_eb_bh); + + mlog_exit(status); + return status; +@@ -5686,8 +5677,7 @@ int ocfs2_begin_truncate_log_recovery(st + bail: + if (tl_inode) + iput(tl_inode); +- if (tl_bh) +- brelse(tl_bh); ++ brelse(tl_bh); + + if (status < 0 && (*tl_copy)) { + kfree(*tl_copy); +@@ -7124,8 +7114,7 @@ static void ocfs2_free_truncate_context( + mlog(ML_NOTICE, + "Truncate completion has non-empty dealloc context\n"); + +- if (tc->tc_last_eb_bh) +- brelse(tc->tc_last_eb_bh); ++ brelse(tc->tc_last_eb_bh); + + kfree(tc); + } +Index: linux-2.6.27/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/aops.c ++++ linux-2.6.27/fs/ocfs2/aops.c +@@ -128,8 +128,7 @@ static int ocfs2_symlink_get_block(struc + err = 0; + + bail: +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(err); + return err; +Index: linux-2.6.27/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dir.c ++++ linux-2.6.27/fs/ocfs2/dir.c +@@ -716,8 +716,7 @@ static int ocfs2_dir_foreach_blk_el(stru + for (i = ra_sectors >> (sb->s_blocksize_bits - 9); + i > 0; i--) { + tmp = ocfs2_bread(inode, ++blk, &err, 1); +- if (tmp) +- brelse(tmp); ++ brelse(tmp); + } + last_ra_blk = blk; + ra_sectors = 8; +@@ -899,10 +898,8 @@ int ocfs2_find_files_on_disk(const char + leave: + if (status < 0) { + *dirent = NULL; +- if (*dirent_bh) { +- brelse(*dirent_bh); +- *dirent_bh = NULL; +- } ++ brelse(*dirent_bh); ++ *dirent_bh = NULL; + } + + mlog_exit(status); +@@ -951,8 +948,7 @@ int ocfs2_check_dir_for_entry(struct ino + + ret = 0; + bail: +- if (dirent_bh) +- brelse(dirent_bh); ++ brelse(dirent_bh); + + mlog_exit(ret); + return ret; +@@ -1127,8 +1123,7 @@ static int ocfs2_fill_new_dir_el(struct + + status = 0; + bail: +- if (new_bh) +- brelse(new_bh); ++ brelse(new_bh); + + mlog_exit(status); + return status; +@@ -1574,8 +1569,7 @@ bail: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + +- if (new_bh) +- brelse(new_bh); ++ brelse(new_bh); + + mlog_exit(status); + return status; +@@ -1702,8 +1696,7 @@ static int ocfs2_find_dir_space_el(struc + + status = 0; + bail: +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(status); + return status; +@@ -1762,7 +1755,6 @@ int ocfs2_prepare_dir_for_insert(struct + *ret_de_bh = bh; + bh = NULL; + out: +- if (bh) +- brelse(bh); ++ brelse(bh); + return ret; + } +Index: linux-2.6.27/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/file.c ++++ linux-2.6.27/fs/ocfs2/file.c +@@ -671,10 +671,8 @@ leave: + restart_func = 0; + goto restart_all; + } +- if (bh) { +- brelse(bh); +- bh = NULL; +- } ++ brelse(bh); ++ bh = NULL; + + mlog_exit(status); + return status; +@@ -991,8 +989,7 @@ bail_unlock_rw: + if (size_change) + ocfs2_rw_unlock(inode, 1); + bail: +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(status); + return status; +Index: linux-2.6.27/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.c ++++ linux-2.6.27/fs/ocfs2/inode.c +@@ -1174,10 +1174,9 @@ struct buffer_head *ocfs2_bread(struct i + return bh; + + fail: +- if (bh) { +- brelse(bh); +- bh = NULL; +- } ++ brelse(bh); ++ bh = NULL; ++ + *err = -EIO; + return NULL; + } +Index: linux-2.6.27/fs/ocfs2/ioctl.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/ioctl.c ++++ linux-2.6.27/fs/ocfs2/ioctl.c +@@ -102,8 +102,7 @@ bail_unlock: + bail: + mutex_unlock(&inode->i_mutex); + +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(status); + return status; +Index: linux-2.6.27/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/journal.c ++++ linux-2.6.27/fs/ocfs2/journal.c +@@ -554,8 +554,7 @@ done: + if (status < 0) { + if (inode_lock) + ocfs2_inode_unlock(inode, 1); +- if (bh != NULL) +- brelse(bh); ++ brelse(bh); + if (inode) { + OCFS2_I(inode)->ip_open_count--; + iput(inode); +@@ -869,8 +868,7 @@ static int ocfs2_force_read_journal(stru + + bail: + for(i = 0; i < CONCURRENT_JOURNAL_FILL; i++) +- if (bhs[i]) +- brelse(bhs[i]); ++ brelse(bhs[i]); + mlog_exit(status); + return status; + } +@@ -1286,8 +1284,7 @@ done: + if (inode) + iput(inode); + +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(status); + return status; +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -294,8 +294,7 @@ int ocfs2_load_local_alloc(struct ocfs2_ + + bail: + if (status < 0) +- if (alloc_bh) +- brelse(alloc_bh); ++ brelse(alloc_bh); + if (inode) + iput(inode); + +@@ -411,8 +410,7 @@ out_commit: + ocfs2_commit_trans(osb, handle); + + out_unlock: +- if (main_bm_bh) +- brelse(main_bm_bh); ++ brelse(main_bm_bh); + + ocfs2_inode_unlock(main_bm_inode, 1); + +@@ -488,8 +486,7 @@ bail: + *alloc_copy = NULL; + } + +- if (alloc_bh) +- brelse(alloc_bh); ++ brelse(alloc_bh); + + if (inode) { + mutex_unlock(&inode->i_mutex); +@@ -557,8 +554,7 @@ out_unlock: + out_mutex: + mutex_unlock(&main_bm_inode->i_mutex); + +- if (main_bm_bh) +- brelse(main_bm_bh); ++ brelse(main_bm_bh); + + iput(main_bm_inode); + +@@ -1281,8 +1277,7 @@ bail: + if (handle) + ocfs2_commit_trans(osb, handle); + +- if (main_bm_bh) +- brelse(main_bm_bh); ++ brelse(main_bm_bh); + + if (main_bm_inode) + iput(main_bm_inode); +Index: linux-2.6.27/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/namei.c ++++ linux-2.6.27/fs/ocfs2/namei.c +@@ -328,14 +328,9 @@ leave: + if (status == -ENOSPC) + mlog(0, "Disk is full\n"); + +- if (new_fe_bh) +- brelse(new_fe_bh); +- +- if (de_bh) +- brelse(de_bh); +- +- if (parent_fe_bh) +- brelse(parent_fe_bh); ++ brelse(new_fe_bh); ++ brelse(de_bh); ++ brelse(parent_fe_bh); + + if ((status < 0) && inode) + iput(inode); +@@ -648,12 +643,9 @@ out_unlock_inode: + out: + ocfs2_inode_unlock(dir, 1); + +- if (de_bh) +- brelse(de_bh); +- if (fe_bh) +- brelse(fe_bh); +- if (parent_fe_bh) +- brelse(parent_fe_bh); ++ brelse(de_bh); ++ brelse(fe_bh); ++ brelse(parent_fe_bh); + + mlog_exit(err); + +@@ -852,17 +844,10 @@ leave: + iput(orphan_dir); + } + +- if (fe_bh) +- brelse(fe_bh); +- +- if (dirent_bh) +- brelse(dirent_bh); +- +- if (parent_node_bh) +- brelse(parent_node_bh); +- +- if (orphan_entry_bh) +- brelse(orphan_entry_bh); ++ brelse(fe_bh); ++ brelse(dirent_bh); ++ brelse(parent_node_bh); ++ brelse(orphan_entry_bh); + + mlog_exit(status); + +@@ -1373,24 +1358,15 @@ bail: + + if (new_inode) + iput(new_inode); +- if (newfe_bh) +- brelse(newfe_bh); +- if (old_inode_bh) +- brelse(old_inode_bh); +- if (old_dir_bh) +- brelse(old_dir_bh); +- if (new_dir_bh) +- brelse(new_dir_bh); +- if (new_de_bh) +- brelse(new_de_bh); +- if (old_de_bh) +- brelse(old_de_bh); +- if (old_inode_de_bh) +- brelse(old_inode_de_bh); +- if (orphan_entry_bh) +- brelse(orphan_entry_bh); +- if (insert_entry_bh) +- brelse(insert_entry_bh); ++ brelse(newfe_bh); ++ brelse(old_inode_bh); ++ brelse(old_dir_bh); ++ brelse(new_dir_bh); ++ brelse(new_de_bh); ++ brelse(old_de_bh); ++ brelse(old_inode_de_bh); ++ brelse(orphan_entry_bh); ++ brelse(insert_entry_bh); + + mlog_exit(status); + +@@ -1493,8 +1469,7 @@ bail: + + if (bhs) { + for(i = 0; i < blocks; i++) +- if (bhs[i]) +- brelse(bhs[i]); ++ brelse(bhs[i]); + kfree(bhs); + } + +@@ -1660,12 +1635,9 @@ bail: + + ocfs2_inode_unlock(dir, 1); + +- if (new_fe_bh) +- brelse(new_fe_bh); +- if (parent_fe_bh) +- brelse(parent_fe_bh); +- if (de_bh) +- brelse(de_bh); ++ brelse(new_fe_bh); ++ brelse(parent_fe_bh); ++ brelse(de_bh); + if (inode_ac) + ocfs2_free_alloc_context(inode_ac); + if (data_ac) +@@ -1760,8 +1732,7 @@ leave: + iput(orphan_dir_inode); + } + +- if (orphan_dir_bh) +- brelse(orphan_dir_bh); ++ brelse(orphan_dir_bh); + + mlog_exit(status); + return status; +@@ -1830,8 +1801,7 @@ static int ocfs2_orphan_add(struct ocfs2 + (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num); + + leave: +- if (orphan_dir_bh) +- brelse(orphan_dir_bh); ++ brelse(orphan_dir_bh); + + mlog_exit(status); + return status; +@@ -1899,8 +1869,7 @@ int ocfs2_orphan_del(struct ocfs2_super + } + + leave: +- if (target_de_bh) +- brelse(target_de_bh); ++ brelse(target_de_bh); + + mlog_exit(status); + return status; +Index: linux-2.6.27/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.27/fs/ocfs2/suballoc.c +@@ -130,10 +130,8 @@ void ocfs2_free_ac_resource(struct ocfs2 + iput(inode); + ac->ac_inode = NULL; + } +- if (ac->ac_bh) { +- brelse(ac->ac_bh); +- ac->ac_bh = NULL; +- } ++ brelse(ac->ac_bh); ++ ac->ac_bh = NULL; + } + + void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) +@@ -401,8 +399,7 @@ bail: + if (ac) + ocfs2_free_alloc_context(ac); + +- if (bg_bh) +- brelse(bg_bh); ++ brelse(bg_bh); + + mlog_exit(status); + return status; +@@ -494,8 +491,7 @@ static int ocfs2_reserve_suballoc_bits(s + get_bh(bh); + ac->ac_bh = bh; + bail: +- if (bh) +- brelse(bh); ++ brelse(bh); + + mlog_exit(status); + return status; +@@ -1270,10 +1266,9 @@ static int ocfs2_search_chain(struct ocf + if (!bg->bg_next_group) + break; + +- if (prev_group_bh) { +- brelse(prev_group_bh); +- prev_group_bh = NULL; +- } ++ brelse(prev_group_bh); ++ prev_group_bh = NULL; ++ + next_group = le64_to_cpu(bg->bg_next_group); + prev_group_bh = group_bh; + group_bh = NULL; +@@ -1368,10 +1363,8 @@ static int ocfs2_search_chain(struct ocf + *bg_blkno = le64_to_cpu(bg->bg_blkno); + *bits_left = le16_to_cpu(bg->bg_free_bits_count); + bail: +- if (group_bh) +- brelse(group_bh); +- if (prev_group_bh) +- brelse(prev_group_bh); ++ brelse(group_bh); ++ brelse(prev_group_bh); + + mlog_exit(status); + return status; +@@ -1845,8 +1838,7 @@ int ocfs2_free_suballoc_bits(handle_t *h + } + + bail: +- if (group_bh) +- brelse(group_bh); ++ brelse(group_bh); + + mlog_exit(status); + return status; +Index: linux-2.6.27/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/super.c ++++ linux-2.6.27/fs/ocfs2/super.c +@@ -762,8 +762,7 @@ static int ocfs2_fill_super(struct super + return status; + + read_super_error: +- if (bh != NULL) +- brelse(bh); ++ brelse(bh); + + if (inode) + iput(inode); +Index: linux-2.6.27/fs/ocfs2/symlink.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/symlink.c ++++ linux-2.6.27/fs/ocfs2/symlink.c +@@ -158,8 +158,7 @@ bail: + kunmap(page); + page_cache_release(page); + } +- if (bh) +- brelse(bh); ++ brelse(bh); + + return ERR_PTR(status); + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Enable-quota-accounting-on-mount-disable-on.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Enable-quota-accounting-on-mount-disable-on.patch new file mode 100644 index 000000000..6577927a1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Enable-quota-accounting-on-mount-disable-on.patch @@ -0,0 +1,403 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 26/28] ocfs2: Enable quota accounting on mount, disable on umount +Patch-mainline: 2.6.29? + +Enable quota usage tracking on mount and disable it on umount. Also +add support for quota on and quota off quotactls and usrquota and +grpquota mount options. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/journal.c | 20 ++++ + fs/ocfs2/ocfs2.h | 3 + fs/ocfs2/super.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 234 insertions(+), 3 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/journal.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/journal.c +@@ -55,7 +55,7 @@ static int ocfs2_recover_node(struct ocf + int node_num); + static int __ocfs2_recovery_thread(void *arg); + static int ocfs2_commit_cache(struct ocfs2_super *osb); +-static int ocfs2_wait_on_mount(struct ocfs2_super *osb); ++static int __ocfs2_wait_on_mount(struct ocfs2_super *osb, int quota); + static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, + int dirty, int replayed); + static int ocfs2_trylock_journal(struct ocfs2_super *osb, +@@ -64,6 +64,17 @@ static int ocfs2_recover_orphans(struct + int slot); + static int ocfs2_commit_thread(void *arg); + ++static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb) ++{ ++ return __ocfs2_wait_on_mount(osb, 0); ++} ++ ++static inline int ocfs2_wait_on_quotas(struct ocfs2_super *osb) ++{ ++ return __ocfs2_wait_on_mount(osb, 1); ++} ++ ++ + + /* + * The recovery_list is a simple linked list of node numbers to recover. +@@ -913,6 +924,8 @@ void ocfs2_complete_recovery(struct work + + mlog(0, "Complete recovery for slot %d\n", item->lri_slot); + ++ ocfs2_wait_on_quotas(osb); ++ + la_dinode = item->lri_la_dinode; + if (la_dinode) { + mlog(0, "Clean up local alloc %llu\n", +@@ -1659,13 +1672,14 @@ static int ocfs2_recover_orphans(struct + return ret; + } + +-static int ocfs2_wait_on_mount(struct ocfs2_super *osb) ++static int __ocfs2_wait_on_mount(struct ocfs2_super *osb, int quota) + { + /* This check is good because ocfs2 will wait on our recovery + * thread before changing it to something other than MOUNTED + * or DISABLED. */ + wait_event(osb->osb_mount_event, +- atomic_read(&osb->vol_state) == VOLUME_MOUNTED || ++ (!quota && atomic_read(&osb->vol_state) == VOLUME_MOUNTED) || ++ atomic_read(&osb->vol_state) == VOLUME_MOUNTED_QUOTAS || + atomic_read(&osb->vol_state) == VOLUME_DISABLED); + + /* If there's an error on mount, then we may never get to the +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h +@@ -161,6 +161,7 @@ enum ocfs2_vol_state + { + VOLUME_INIT = 0, + VOLUME_MOUNTED, ++ VOLUME_MOUNTED_QUOTAS, + VOLUME_DISMOUNTED, + VOLUME_DISABLED + }; +@@ -196,6 +197,8 @@ enum ocfs2_mount_options + OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */ + OCFS2_MOUNT_INODE64 = 1 << 7, /* Allow inode numbers > 2^32 */ + OCFS2_MOUNT_POSIX_ACL = 1 << 8, /* POSIX access control lists */ ++ OCFS2_MOUNT_USRQUOTA = 1 << 9, /* We support user quotas */ ++ OCFS2_MOUNT_GRPQUOTA = 1 << 10, /* We support group quotas */ + }; + + #define OCFS2_OSB_SOFT_RO 0x0001 +Index: linux-2.6.27-ocfs2/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/super.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/super.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_SUPER + #include +@@ -127,6 +128,9 @@ static int ocfs2_get_sector(struct super + static void ocfs2_write_super(struct super_block *sb); + static struct inode *ocfs2_alloc_inode(struct super_block *sb); + static void ocfs2_destroy_inode(struct inode *inode); ++static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend); ++static int ocfs2_enable_quotas(struct ocfs2_super *osb); ++static void ocfs2_disable_quotas(struct ocfs2_super *osb); + + static const struct super_operations ocfs2_sops = { + .statfs = ocfs2_statfs, +@@ -165,6 +169,8 @@ enum { + Opt_inode64, + Opt_acl, + Opt_noacl, ++ Opt_usrquota, ++ Opt_grpquota, + Opt_err, + }; + +@@ -189,6 +195,8 @@ static match_table_t tokens = { + {Opt_inode64, "inode64"}, + {Opt_acl, "acl"}, + {Opt_noacl, "noacl"}, ++ {Opt_usrquota, "usrquota"}, ++ {Opt_grpquota, "grpquota"}, + {Opt_err, NULL} + }; + +@@ -452,6 +460,12 @@ static int ocfs2_remount(struct super_bl + + /* We're going to/from readonly mode. */ + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { ++ /* Disable quota accounting before remounting RO */ ++ if (*flags & MS_RDONLY) { ++ ret = ocfs2_susp_quotas(osb, 0); ++ if (ret < 0) ++ goto out; ++ } + /* Lock here so the check of HARD_RO and the potential + * setting of SOFT_RO is atomic. */ + spin_lock(&osb->osb_lock); +@@ -487,6 +501,21 @@ static int ocfs2_remount(struct super_bl + } + unlock_osb: + spin_unlock(&osb->osb_lock); ++ /* Enable quota accounting after remounting RW */ ++ if (!ret && !(*flags & MS_RDONLY)) { ++ if (sb_any_quota_suspended(sb)) ++ ret = ocfs2_susp_quotas(osb, 1); ++ else ++ ret = ocfs2_enable_quotas(osb); ++ if (ret < 0) { ++ /* Return back changes... */ ++ spin_lock(&osb->osb_lock); ++ sb->s_flags |= MS_RDONLY; ++ osb->osb_flags |= OCFS2_OSB_SOFT_RO; ++ spin_unlock(&osb->osb_lock); ++ goto out; ++ } ++ } + } + + if (!ret) { +@@ -647,6 +676,131 @@ static int ocfs2_verify_userspace_stack( + return 0; + } + ++static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend) ++{ ++ int type; ++ struct super_block *sb = osb->sb; ++ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; ++ int status = 0; ++ ++ for (type = 0; type < MAXQUOTAS; type++) { ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) ++ continue; ++ if (unsuspend) ++ status = vfs_quota_enable( ++ sb_dqopt(sb)->files[type], ++ type, QFMT_OCFS2, ++ DQUOT_SUSPENDED); ++ else ++ status = vfs_quota_disable(sb, type, ++ DQUOT_SUSPENDED); ++ if (status < 0) ++ break; ++ } ++ if (status < 0) ++ mlog(ML_ERROR, "Failed to suspend/unsuspend quotas on " ++ "remount (error = %d).\n", status); ++ return status; ++} ++ ++static int ocfs2_enable_quotas(struct ocfs2_super *osb) ++{ ++ struct inode *inode[MAXQUOTAS] = { NULL, NULL }; ++ struct super_block *sb = osb->sb; ++ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; ++ unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, ++ LOCAL_GROUP_QUOTA_SYSTEM_INODE }; ++ int status; ++ int type; ++ ++ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NEGATIVE_USAGE; ++ for (type = 0; type < MAXQUOTAS; type++) { ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) ++ continue; ++ inode[type] = ocfs2_get_system_file_inode(osb, ino[type], ++ osb->slot_num); ++ if (!inode[type]) { ++ status = -ENOENT; ++ goto out_quota_off; ++ } ++ status = vfs_quota_enable(inode[type], type, QFMT_OCFS2, ++ DQUOT_USAGE_ENABLED); ++ if (status < 0) ++ goto out_quota_off; ++ } ++ ++ for (type = 0; type < MAXQUOTAS; type++) ++ iput(inode[type]); ++ return 0; ++out_quota_off: ++ ocfs2_disable_quotas(osb); ++ for (type = 0; type < MAXQUOTAS; type++) ++ iput(inode[type]); ++ mlog_errno(status); ++ return status; ++} ++ ++static void ocfs2_disable_quotas(struct ocfs2_super *osb) ++{ ++ int type; ++ struct inode *inode; ++ struct super_block *sb = osb->sb; ++ ++ /* We mostly ignore errors in this function because there's not much ++ * we can do when we see them */ ++ for (type = 0; type < MAXQUOTAS; type++) { ++ if (!sb_has_quota_loaded(sb, type)) ++ continue; ++ inode = igrab(sb->s_dquot.files[type]); ++ /* Turn off quotas. This will remove all dquot structures from ++ * memory and so they will be automatically synced to global ++ * quota files */ ++ vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED | ++ DQUOT_LIMITS_ENABLED); ++ if (!inode) ++ continue; ++ iput(inode); ++ } ++} ++ ++/* Handle quota on quotactl */ ++static int ocfs2_quota_on(struct super_block *sb, int type, int format_id, ++ char *path, int remount) ++{ ++ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; ++ ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) ++ return -EINVAL; ++ ++ if (remount) ++ return 0; /* Just ignore it has been handled in ++ * ocfs2_remount() */ ++ return vfs_quota_enable(sb_dqopt(sb)->files[type], type, ++ format_id, DQUOT_LIMITS_ENABLED); ++} ++ ++/* Handle quota off quotactl */ ++static int ocfs2_quota_off(struct super_block *sb, int type, int remount) ++{ ++ if (remount) ++ return 0; /* Ignore now and handle later in ++ * ocfs2_remount() */ ++ return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED); ++} ++ ++static struct quotactl_ops ocfs2_quotactl_ops = { ++ .quota_on = ocfs2_quota_on, ++ .quota_off = ocfs2_quota_off, ++ .quota_sync = vfs_quota_sync, ++ .get_info = vfs_get_dqinfo, ++ .set_info = vfs_set_dqinfo, ++ .get_dqblk = vfs_get_dqblk, ++ .set_dqblk = vfs_set_dqblk, ++}; ++ + static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) + { + struct dentry *root; +@@ -689,6 +843,22 @@ static int ocfs2_fill_super(struct super + osb->osb_commit_interval = parsed_options.commit_interval; + osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); + osb->local_alloc_bits = osb->local_alloc_default_bits; ++ if (osb->s_mount_opt & OCFS2_MOUNT_USRQUOTA && ++ !OCFS2_HAS_RO_COMPAT_FEATURE(sb, ++ OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { ++ status = -EINVAL; ++ mlog(ML_ERROR, "User quotas were requested, but this " ++ "filesystem does not have the feature enabled.\n"); ++ goto read_super_error; ++ } ++ if (osb->s_mount_opt & OCFS2_MOUNT_GRPQUOTA && ++ !OCFS2_HAS_RO_COMPAT_FEATURE(sb, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { ++ status = -EINVAL; ++ mlog(ML_ERROR, "Group quotas were requested, but this " ++ "filesystem does not have the feature enabled.\n"); ++ goto read_super_error; ++ } + + status = ocfs2_verify_userspace_stack(osb, &parsed_options); + if (status) +@@ -793,6 +963,20 @@ static int ocfs2_fill_super(struct super + atomic_set(&osb->vol_state, VOLUME_MOUNTED); + wake_up(&osb->osb_mount_event); + ++ /* Now we can initialize quotas because we can afford to wait ++ * for cluster locks recovery now. That also means that truncation ++ * log recovery can happen but that waits for proper quota setup */ ++ if (!(sb->s_flags & MS_RDONLY)) { ++ status = ocfs2_enable_quotas(osb); ++ if (status < 0) { ++ mlog_errno(status); ++ goto read_super_error; ++ } ++ } ++ /* Now we wake up again for processes waiting for quotas */ ++ atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); ++ wake_up(&osb->osb_mount_event); ++ + mlog_exit(status); + return status; + +@@ -993,6 +1177,28 @@ static int ocfs2_parse_options(struct su + printk(KERN_INFO "ocfs2 (no)acl options not supported\n"); + break; + #endif ++ case Opt_usrquota: ++ /* We check only on remount, otherwise features ++ * aren't yet initialized. */ ++ if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb, ++ OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { ++ mlog(ML_ERROR, "User quota requested but " ++ "filesystem feature is not set\n"); ++ status = 0; ++ goto bail; ++ } ++ mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA; ++ break; ++ case Opt_grpquota: ++ if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { ++ mlog(ML_ERROR, "Group quota requested but " ++ "filesystem feature is not set\n"); ++ status = 0; ++ goto bail; ++ } ++ mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA; ++ break; + default: + mlog(ML_ERROR, + "Unrecognized mount option \"%s\" " +@@ -1071,6 +1277,10 @@ static int ocfs2_show_options(struct seq + else + seq_printf(s, ",noacl"); + #endif ++ if (opts & OCFS2_MOUNT_USRQUOTA) ++ seq_printf(s, ",usrquota"); ++ if (opts & OCFS2_MOUNT_GRPQUOTA) ++ seq_printf(s, ",grpquota"); + + return 0; + } +@@ -1396,6 +1606,8 @@ static void ocfs2_dismount_volume(struct + osb = OCFS2_SB(sb); + BUG_ON(!osb); + ++ ocfs2_disable_quotas(osb); ++ + ocfs2_shutdown_local_alloc(osb); + + ocfs2_truncate_log_shutdown(osb); +@@ -1506,6 +1718,8 @@ static int ocfs2_initialize_super(struct + sb->s_fs_info = osb; + sb->s_op = &ocfs2_sops; + sb->s_export_op = &ocfs2_export_ops; ++ sb->s_qcop = &ocfs2_quotactl_ops; ++ sb->dq_op = &ocfs2_quota_operations; + sb->s_xattr = ocfs2_xattr_handlers; + sb->s_time_gran = 1; + sb->s_flags |= MS_NOATIME; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Enable-xattr-set-in-index-btree.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Enable-xattr-set-in-index-btree.patch new file mode 100644 index 000000000..ed4e2b5fb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Enable-xattr-set-in-index-btree.patch @@ -0,0 +1,2387 @@ +From: Tao Ma +Subject: [PATCH 14/16] ocfs2: Enable xattr set in index btree +Patch-mainline: 2.6.28? +References: FATE302067 + +Where the previous patches added the ability of list/get xattr in buckets +for ocfs2, this patch enables ocfs2 to store large numbers of EAs. + +The original design doc is written by Mark Fasheh, and it can be found in +http://oss.oracle.com/osswiki/OCFS2/DesignDocs/IndexedEATrees. I only had to +make small modifications to it. + +First, because the bucket size is 4K, a new field named xh_free_start is added +in ocfs2_xattr_header to indicate the next valid name/value offset in a bucket. +It is used when we store new EA name/value. With this field, we can find the +place more quickly and what's more, we don't need to sort the name/value every +time to let the last entry indicate the next unused space. This makes the +insert operation more efficient for blocksizes smaller than 4k. + +Because of the new xh_free_start, another field named as xh_name_value_len is +also added in ocfs2_xattr_header. It records the total length of all the +name/values in the bucket. We need this so that we can check it and defragment +the bucket if there is not enough contiguous free space. + +An xattr insertion looks like this: +1. xattr_index_block_find: find the right bucket by the name_hash, say bucketA. +2. check whether there is enough space in bucketA. If yes, insert it directly + and modify xh_free_start and xh_name_value_len accordingly. If not, check + xh_name_value_len to see whether we can store this by defragment the bucket. + If yes, defragment it and go on insertion. +3. If defragement doesn't work, check whether there is new empty bucket in + the clusters within this extent record. If yes, init the new bucket and move + all the buckets after bucketA one by one to the next bucket. Move half of the + entries in bucketA to the next bucket and go on insertion. +4. If there is no new bucket, grow the extent tree. + +As for xattr deletion, we will delete an xattr bucket when all it's xattrs +are removed and move all the buckets after it to the previous one. When all +the xattr buckets in an extend record are freed, free this extend records +from ocfs2_xattr_tree. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 2267 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + fs/ocfs2/xattr.h | 8 + + 2 files changed, 2273 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index a5ca066..408553c 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_XATTR + #include +@@ -139,6 +140,13 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode, + char *buffer, + size_t buffer_size); + ++static int ocfs2_xattr_create_index_block(struct inode *inode, ++ struct ocfs2_xattr_search *xs); ++ ++static int ocfs2_xattr_set_entry_index_block(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs); ++ + static inline struct xattr_handler *ocfs2_xattr_handler(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -1784,6 +1792,52 @@ cleanup: + } + + /* ++ * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree ++ * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header ++ * re-initialized. ++ */ ++static int ocfs2_restore_xattr_block(struct inode *inode, ++ struct ocfs2_xattr_search *xs) ++{ ++ int ret; ++ handle_t *handle; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; ++ struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list; ++ u16 xb_flags = le16_to_cpu(xb->xb_flags); ++ ++ BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) || ++ le16_to_cpu(el->l_next_free_rec) != 0); ++ ++ handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ handle = NULL; ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - ++ offsetof(struct ocfs2_xattr_block, xb_attrs)); ++ ++ xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED); ++ ++ ocfs2_journal_dirty(handle, xs->xattr_bh); ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ return ret; ++} ++ ++/* + * ocfs2_xattr_block_set() + * + * Set, replace or remove an extended attribute into external block. +@@ -1878,10 +1932,25 @@ out: + ocfs2_free_alloc_context(meta_ac); + if (ret < 0) + return ret; ++ } else ++ xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; ++ ++ if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) { ++ /* Set extended attribute into external block */ ++ ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL); ++ if (!ret || ret != -ENOSPC) ++ goto end; ++ ++ ret = ocfs2_xattr_create_index_block(inode, xs); ++ if (ret) ++ goto end; + } + +- /* Set extended attribute into external block */ +- ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL); ++ ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs); ++ if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0) ++ ret = ocfs2_restore_xattr_block(inode, xs); ++ ++end: + + return ret; + } +@@ -1903,6 +1972,7 @@ int ocfs2_xattr_set(struct inode *inode, + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + int ret; ++ u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + + struct ocfs2_xattr_info xi = { + .name_index = name_index, +@@ -2001,6 +2071,8 @@ cleanup: + ocfs2_inode_unlock(inode, 1); + brelse(di_bh); + brelse(xbs.xattr_bh); ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(xbs.bucket.bhs[i]); + + return ret; + } +@@ -2491,3 +2563,2194 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode, + out: + return ret; + } ++ ++static int cmp_xe(const void *a, const void *b) ++{ ++ const struct ocfs2_xattr_entry *l = a, *r = b; ++ u32 l_hash = le32_to_cpu(l->xe_name_hash); ++ u32 r_hash = le32_to_cpu(r->xe_name_hash); ++ ++ if (l_hash > r_hash) ++ return 1; ++ if (l_hash < r_hash) ++ return -1; ++ return 0; ++} ++ ++static void swap_xe(void *a, void *b, int size) ++{ ++ struct ocfs2_xattr_entry *l = a, *r = b, tmp; ++ ++ tmp = *l; ++ memcpy(l, r, sizeof(struct ocfs2_xattr_entry)); ++ memcpy(r, &tmp, sizeof(struct ocfs2_xattr_entry)); ++} ++ ++/* ++ * When the ocfs2_xattr_block is filled up, new bucket will be created ++ * and all the xattr entries will be moved to the new bucket. ++ * Note: we need to sort the entries since they are not saved in order ++ * in the ocfs2_xattr_block. ++ */ ++static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode, ++ struct buffer_head *xb_bh, ++ struct buffer_head *xh_bh, ++ struct buffer_head *data_bh) ++{ ++ int i, blocksize = inode->i_sb->s_blocksize; ++ u16 offset, size, off_change; ++ struct ocfs2_xattr_entry *xe; ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)xb_bh->b_data; ++ struct ocfs2_xattr_header *xb_xh = &xb->xb_attrs.xb_header; ++ struct ocfs2_xattr_header *xh = ++ (struct ocfs2_xattr_header *)xh_bh->b_data; ++ u16 count = le16_to_cpu(xb_xh->xh_count); ++ char *target = xh_bh->b_data, *src = xb_bh->b_data; ++ ++ mlog(0, "cp xattr from block %llu to bucket %llu\n", ++ (unsigned long long)xb_bh->b_blocknr, ++ (unsigned long long)xh_bh->b_blocknr); ++ ++ memset(xh_bh->b_data, 0, blocksize); ++ if (data_bh) ++ memset(data_bh->b_data, 0, blocksize); ++ /* ++ * Since the xe_name_offset is based on ocfs2_xattr_header, ++ * there is a offset change corresponding to the change of ++ * ocfs2_xattr_header's position. ++ */ ++ off_change = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header); ++ xe = &xb_xh->xh_entries[count - 1]; ++ offset = le16_to_cpu(xe->xe_name_offset) + off_change; ++ size = blocksize - offset; ++ ++ /* copy all the names and values. */ ++ if (data_bh) ++ target = data_bh->b_data; ++ memcpy(target + offset, src + offset, size); ++ ++ /* Init new header now. */ ++ xh->xh_count = xb_xh->xh_count; ++ xh->xh_num_buckets = cpu_to_le16(1); ++ xh->xh_name_value_len = cpu_to_le16(size); ++ xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE - size); ++ ++ /* copy all the entries. */ ++ target = xh_bh->b_data; ++ offset = offsetof(struct ocfs2_xattr_header, xh_entries); ++ size = count * sizeof(struct ocfs2_xattr_entry); ++ memcpy(target + offset, (char *)xb_xh + offset, size); ++ ++ /* Change the xe offset for all the xe because of the move. */ ++ off_change = OCFS2_XATTR_BUCKET_SIZE - blocksize + ++ offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header); ++ for (i = 0; i < count; i++) ++ le16_add_cpu(&xh->xh_entries[i].xe_name_offset, off_change); ++ ++ mlog(0, "copy entry: start = %u, size = %u, offset_change = %u\n", ++ offset, size, off_change); ++ ++ sort(target + offset, count, sizeof(struct ocfs2_xattr_entry), ++ cmp_xe, swap_xe); ++} ++ ++/* ++ * After we move xattr from block to index btree, we have to ++ * update ocfs2_xattr_search to the new xe and base. ++ * ++ * When the entry is in xattr block, xattr_bh indicates the storage place. ++ * While if the entry is in index b-tree, "bucket" indicates the ++ * real place of the xattr. ++ */ ++static int ocfs2_xattr_update_xattr_search(struct inode *inode, ++ struct ocfs2_xattr_search *xs, ++ struct buffer_head *old_bh, ++ struct buffer_head *new_bh) ++{ ++ int ret = 0; ++ char *buf = old_bh->b_data; ++ struct ocfs2_xattr_block *old_xb = (struct ocfs2_xattr_block *)buf; ++ struct ocfs2_xattr_header *old_xh = &old_xb->xb_attrs.xb_header; ++ int i, blocksize = inode->i_sb->s_blocksize; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ xs->bucket.bhs[0] = new_bh; ++ get_bh(new_bh); ++ xs->bucket.xh = (struct ocfs2_xattr_header *)xs->bucket.bhs[0]->b_data; ++ xs->header = xs->bucket.xh; ++ ++ xs->base = new_bh->b_data; ++ xs->end = xs->base + inode->i_sb->s_blocksize; ++ ++ if (!xs->not_found) { ++ if (OCFS2_XATTR_BUCKET_SIZE != blocksize) { ++ ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), ++ xs->bucket.bhs[0]->b_blocknr + 1, ++ blk_per_bucket - 1, &xs->bucket.bhs[1], ++ OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ i = xs->here - old_xh->xh_entries; ++ xs->here = &xs->header->xh_entries[i]; ++ } ++ } ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_create_index_block(struct inode *inode, ++ struct ocfs2_xattr_search *xs) ++{ ++ int ret, credits = OCFS2_SUBALLOC_ALLOC; ++ u32 bit_off, len; ++ u64 blkno; ++ handle_t *handle; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_inode_info *oi = OCFS2_I(inode); ++ struct ocfs2_alloc_context *data_ac; ++ struct buffer_head *xh_bh = NULL, *data_bh = NULL; ++ struct buffer_head *xb_bh = xs->xattr_bh; ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)xb_bh->b_data; ++ struct ocfs2_xattr_tree_root *xr; ++ u16 xb_flags = le16_to_cpu(xb->xb_flags); ++ u16 bpb = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ mlog(0, "create xattr index block for %llu\n", ++ (unsigned long long)xb_bh->b_blocknr); ++ ++ BUG_ON(xb_flags & OCFS2_XATTR_INDEXED); ++ ++ ret = ocfs2_reserve_clusters(osb, 1, &data_ac); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ /* ++ * XXX: ++ * We can use this lock for now, and maybe move to a dedicated mutex ++ * if performance becomes a problem later. ++ */ ++ down_write(&oi->ip_alloc_sem); ++ ++ /* ++ * 3 more credits, one for xattr block update, one for the 1st block ++ * of the new xattr bucket and one for the value/data. ++ */ ++ credits += 3; ++ handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out_sem; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, xb_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ /* ++ * The bucket may spread in many blocks, and ++ * we will only touch the 1st block and the last block ++ * in the whole bucket(one for entry and one for data). ++ */ ++ blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off); ++ ++ mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno); ++ ++ xh_bh = sb_getblk(inode->i_sb, blkno); ++ if (!xh_bh) { ++ ret = -EIO; ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ocfs2_set_new_buffer_uptodate(inode, xh_bh); ++ ++ ret = ocfs2_journal_access(handle, inode, xh_bh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ if (bpb > 1) { ++ data_bh = sb_getblk(inode->i_sb, blkno + bpb - 1); ++ if (!data_bh) { ++ ret = -EIO; ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ocfs2_set_new_buffer_uptodate(inode, data_bh); ++ ++ ret = ocfs2_journal_access(handle, inode, data_bh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ } ++ ++ ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xh_bh, data_bh); ++ ++ ocfs2_journal_dirty(handle, xh_bh); ++ if (data_bh) ++ ocfs2_journal_dirty(handle, data_bh); ++ ++ ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh); ++ ++ /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */ ++ memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - ++ offsetof(struct ocfs2_xattr_block, xb_attrs)); ++ ++ xr = &xb->xb_attrs.xb_root; ++ xr->xt_clusters = cpu_to_le32(1); ++ xr->xt_last_eb_blk = 0; ++ xr->xt_list.l_tree_depth = 0; ++ xr->xt_list.l_count = cpu_to_le16(ocfs2_xattr_recs_per_xb(inode->i_sb)); ++ xr->xt_list.l_next_free_rec = cpu_to_le16(1); ++ ++ xr->xt_list.l_recs[0].e_cpos = 0; ++ xr->xt_list.l_recs[0].e_blkno = cpu_to_le64(blkno); ++ xr->xt_list.l_recs[0].e_leaf_clusters = cpu_to_le16(1); ++ ++ xb->xb_flags = cpu_to_le16(xb_flags | OCFS2_XATTR_INDEXED); ++ ++ ret = ocfs2_journal_dirty(handle, xb_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++ ++out_sem: ++ up_write(&oi->ip_alloc_sem); ++ ++out: ++ if (data_ac) ++ ocfs2_free_alloc_context(data_ac); ++ ++ brelse(xh_bh); ++ brelse(data_bh); ++ ++ return ret; ++} ++ ++static int cmp_xe_offset(const void *a, const void *b) ++{ ++ const struct ocfs2_xattr_entry *l = a, *r = b; ++ u32 l_name_offset = le16_to_cpu(l->xe_name_offset); ++ u32 r_name_offset = le16_to_cpu(r->xe_name_offset); ++ ++ if (l_name_offset < r_name_offset) ++ return 1; ++ if (l_name_offset > r_name_offset) ++ return -1; ++ return 0; ++} ++ ++/* ++ * defrag a xattr bucket if we find that the bucket has some ++ * holes beteen name/value pairs. ++ * We will move all the name/value pairs to the end of the bucket ++ * so that we can spare some space for insertion. ++ */ ++static int ocfs2_defrag_xattr_bucket(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket) ++{ ++ int ret, i; ++ size_t end, offset, len, value_len; ++ struct ocfs2_xattr_header *xh; ++ char *entries, *buf, *bucket_buf = NULL; ++ u64 blkno = bucket->bhs[0]->b_blocknr; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ u16 xh_free_start; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ size_t blocksize = inode->i_sb->s_blocksize; ++ handle_t *handle; ++ struct buffer_head **bhs; ++ struct ocfs2_xattr_entry *xe; ++ ++ bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, ++ GFP_NOFS); ++ if (!bhs) ++ return -ENOMEM; ++ ++ ret = ocfs2_read_blocks(osb, blkno, blk_per_bucket, bhs, ++ OCFS2_BH_CACHED, inode); ++ if (ret) ++ goto out; ++ ++ /* ++ * In order to make the operation more efficient and generic, ++ * we copy all the blocks into a contiguous memory and do the ++ * defragment there, so if anything is error, we will not touch ++ * the real block. ++ */ ++ bucket_buf = kmalloc(OCFS2_XATTR_BUCKET_SIZE, GFP_NOFS); ++ if (!bucket_buf) { ++ ret = -EIO; ++ goto out; ++ } ++ ++ buf = bucket_buf; ++ for (i = 0; i < blk_per_bucket; i++, buf += blocksize) ++ memcpy(buf, bhs[i]->b_data, blocksize); ++ ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), blk_per_bucket); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ handle = NULL; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ ret = ocfs2_journal_access(handle, inode, bhs[i], ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto commit; ++ } ++ } ++ ++ xh = (struct ocfs2_xattr_header *)bucket_buf; ++ entries = (char *)xh->xh_entries; ++ xh_free_start = le16_to_cpu(xh->xh_free_start); ++ ++ mlog(0, "adjust xattr bucket in %llu, count = %u, " ++ "xh_free_start = %u, xh_name_value_len = %u.\n", ++ blkno, le16_to_cpu(xh->xh_count), xh_free_start, ++ le16_to_cpu(xh->xh_name_value_len)); ++ ++ /* ++ * sort all the entries by their offset. ++ * the largest will be the first, so that we can ++ * move them to the end one by one. ++ */ ++ sort(entries, le16_to_cpu(xh->xh_count), ++ sizeof(struct ocfs2_xattr_entry), ++ cmp_xe_offset, swap_xe); ++ ++ /* Move all name/values to the end of the bucket. */ ++ xe = xh->xh_entries; ++ end = OCFS2_XATTR_BUCKET_SIZE; ++ for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) { ++ offset = le16_to_cpu(xe->xe_name_offset); ++ if (ocfs2_xattr_is_local(xe)) ++ value_len = OCFS2_XATTR_SIZE( ++ le64_to_cpu(xe->xe_value_size)); ++ else ++ value_len = OCFS2_XATTR_ROOT_SIZE; ++ len = OCFS2_XATTR_SIZE(xe->xe_name_len) + value_len; ++ ++ /* ++ * We must make sure that the name/value pair ++ * exist in the same block. So adjust end to ++ * the previous block end if needed. ++ */ ++ if (((end - len) / blocksize != ++ (end - 1) / blocksize)) ++ end = end - end % blocksize; ++ ++ if (end > offset + len) { ++ memmove(bucket_buf + end - len, ++ bucket_buf + offset, len); ++ xe->xe_name_offset = cpu_to_le16(end - len); ++ } ++ ++ mlog_bug_on_msg(end < offset + len, "Defrag check failed for " ++ "bucket %llu\n", (unsigned long long)blkno); ++ ++ end -= len; ++ } ++ ++ mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for " ++ "bucket %llu\n", (unsigned long long)blkno); ++ ++ if (xh_free_start == end) ++ goto commit; ++ ++ memset(bucket_buf + xh_free_start, 0, end - xh_free_start); ++ xh->xh_free_start = cpu_to_le16(end); ++ ++ /* sort the entries by their name_hash. */ ++ sort(entries, le16_to_cpu(xh->xh_count), ++ sizeof(struct ocfs2_xattr_entry), ++ cmp_xe, swap_xe); ++ ++ buf = bucket_buf; ++ for (i = 0; i < blk_per_bucket; i++, buf += blocksize) { ++ memcpy(bhs[i]->b_data, buf, blocksize); ++ ocfs2_journal_dirty(handle, bhs[i]); ++ } ++ ++commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++out: ++ ++ if (bhs) { ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(bhs[i]); ++ } ++ kfree(bhs); ++ ++ kfree(bucket_buf); ++ return ret; ++} ++ ++/* ++ * Move half nums of the xattr bucket in the previous cluster to this new ++ * cluster. We only touch the last cluster of the previous extend record. ++ * ++ * first_bh is the first buffer_head of a series of bucket in the same ++ * extent rec and header_bh is the header of one bucket in this cluster. ++ * They will be updated if we move the data header_bh contains to the new ++ * cluster. first_hash will be set as the 1st xe's name_hash of the new cluster. ++ */ ++static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode, ++ handle_t *handle, ++ struct buffer_head **first_bh, ++ struct buffer_head **header_bh, ++ u64 new_blkno, ++ u64 prev_blkno, ++ u32 num_clusters, ++ u32 *first_hash) ++{ ++ int i, ret, credits; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); ++ int num_buckets = ocfs2_xattr_buckets_per_cluster(osb); ++ int blocksize = inode->i_sb->s_blocksize; ++ struct buffer_head *old_bh, *new_bh, *prev_bh, *new_first_bh = NULL; ++ struct ocfs2_xattr_header *new_xh; ++ struct ocfs2_xattr_header *xh = ++ (struct ocfs2_xattr_header *)((*first_bh)->b_data); ++ ++ BUG_ON(le16_to_cpu(xh->xh_num_buckets) < num_buckets); ++ BUG_ON(OCFS2_XATTR_BUCKET_SIZE == osb->s_clustersize); ++ ++ prev_bh = *first_bh; ++ get_bh(prev_bh); ++ xh = (struct ocfs2_xattr_header *)prev_bh->b_data; ++ ++ prev_blkno += (num_clusters - 1) * bpc + bpc / 2; ++ ++ mlog(0, "move half of xattrs in cluster %llu to %llu\n", ++ prev_blkno, new_blkno); ++ ++ /* ++ * We need to update the 1st half of the new cluster and ++ * 1 more for the update of the 1st bucket of the previous ++ * extent record. ++ */ ++ credits = bpc / 2 + 1; ++ ret = ocfs2_extend_trans(handle, credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, prev_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ for (i = 0; i < bpc / 2; i++, prev_blkno++, new_blkno++) { ++ old_bh = new_bh = NULL; ++ new_bh = sb_getblk(inode->i_sb, new_blkno); ++ if (!new_bh) { ++ ret = -EIO; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ocfs2_set_new_buffer_uptodate(inode, new_bh); ++ ++ ret = ocfs2_journal_access(handle, inode, new_bh, ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ brelse(new_bh); ++ goto out; ++ } ++ ++ ret = ocfs2_read_block(osb, prev_blkno, ++ &old_bh, OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ brelse(new_bh); ++ goto out; ++ } ++ ++ memcpy(new_bh->b_data, old_bh->b_data, blocksize); ++ ++ if (i == 0) { ++ new_xh = (struct ocfs2_xattr_header *)new_bh->b_data; ++ new_xh->xh_num_buckets = cpu_to_le16(num_buckets / 2); ++ ++ if (first_hash) ++ *first_hash = le32_to_cpu( ++ new_xh->xh_entries[0].xe_name_hash); ++ new_first_bh = new_bh; ++ get_bh(new_first_bh); ++ } ++ ++ ocfs2_journal_dirty(handle, new_bh); ++ ++ if (*header_bh == old_bh) { ++ brelse(*header_bh); ++ *header_bh = new_bh; ++ get_bh(*header_bh); ++ ++ brelse(*first_bh); ++ *first_bh = new_first_bh; ++ get_bh(*first_bh); ++ } ++ brelse(new_bh); ++ brelse(old_bh); ++ } ++ ++ le16_add_cpu(&xh->xh_num_buckets, -(num_buckets / 2)); ++ ++ ocfs2_journal_dirty(handle, prev_bh); ++out: ++ brelse(prev_bh); ++ brelse(new_first_bh); ++ return ret; ++} ++ ++static int ocfs2_read_xattr_bucket(struct inode *inode, ++ u64 blkno, ++ struct buffer_head **bhs, ++ int new) ++{ ++ int ret = 0; ++ u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ if (!new) ++ return ocfs2_read_blocks(OCFS2_SB(inode->i_sb), blkno, ++ blk_per_bucket, bhs, ++ OCFS2_BH_CACHED, inode); ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ bhs[i] = sb_getblk(inode->i_sb, blkno + i); ++ if (bhs[i] == NULL) { ++ ret = -EIO; ++ mlog_errno(ret); ++ break; ++ } ++ ocfs2_set_new_buffer_uptodate(inode, bhs[i]); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk). ++ * first_hash will record the 1st hash of the new bucket. ++ */ ++static int ocfs2_half_xattr_bucket(struct inode *inode, ++ handle_t *handle, ++ u64 blk, ++ u64 new_blk, ++ u32 *first_hash, ++ int new_bucket_head) ++{ ++ int ret, i; ++ u16 count, start, len, name_value_len, xe_len, name_offset; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ struct buffer_head **s_bhs, **t_bhs = NULL; ++ struct ocfs2_xattr_header *xh; ++ struct ocfs2_xattr_entry *xe; ++ int blocksize = inode->i_sb->s_blocksize; ++ ++ mlog(0, "move half of xattrs from bucket %llu to %llu\n", ++ blk, new_blk); ++ ++ s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); ++ if (!s_bhs) ++ return -ENOMEM; ++ ++ ret = ocfs2_read_xattr_bucket(inode, blk, s_bhs, 0); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, s_bhs[0], ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ t_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); ++ if (!t_bhs) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = ocfs2_read_xattr_bucket(inode, new_blk, t_bhs, new_bucket_head); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ ret = ocfs2_journal_access(handle, inode, t_bhs[i], ++ OCFS2_JOURNAL_ACCESS_CREATE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ /* copy the whole bucket to the new first. */ ++ for (i = 0; i < blk_per_bucket; i++) ++ memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); ++ ++ /* update the new bucket. */ ++ xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; ++ count = le16_to_cpu(xh->xh_count); ++ start = count / 2; ++ ++ /* ++ * Calculate the total name/value len and xh_free_start for ++ * the old bucket first. ++ */ ++ name_offset = OCFS2_XATTR_BUCKET_SIZE; ++ name_value_len = 0; ++ for (i = 0; i < start; i++) { ++ xe = &xh->xh_entries[i]; ++ xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len); ++ if (ocfs2_xattr_is_local(xe)) ++ xe_len += ++ OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size)); ++ else ++ xe_len += OCFS2_XATTR_ROOT_SIZE; ++ name_value_len += xe_len; ++ if (le16_to_cpu(xe->xe_name_offset) < name_offset) ++ name_offset = le16_to_cpu(xe->xe_name_offset); ++ } ++ ++ /* ++ * Now begin the modification to the new bucket. ++ * ++ * In the new bucket, We just move the xattr entry to the beginning ++ * and don't touch the name/value. So there will be some holes in the ++ * bucket, and they will be removed when ocfs2_defrag_xattr_bucket is ++ * called. ++ */ ++ xe = &xh->xh_entries[start]; ++ len = sizeof(struct ocfs2_xattr_entry) * (count - start); ++ mlog(0, "mv xattr entry len %d from %d to %d\n", len, ++ (char *)xe - (char *)xh, (char *)xh->xh_entries - (char *)xh); ++ memmove((char *)xh->xh_entries, (char *)xe, len); ++ xe = &xh->xh_entries[count - start]; ++ len = sizeof(struct ocfs2_xattr_entry) * start; ++ memset((char *)xe, 0, len); ++ ++ le16_add_cpu(&xh->xh_count, -start); ++ le16_add_cpu(&xh->xh_name_value_len, -name_value_len); ++ ++ /* Calculate xh_free_start for the new bucket. */ ++ xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE); ++ for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { ++ xe = &xh->xh_entries[i]; ++ xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len); ++ if (ocfs2_xattr_is_local(xe)) ++ xe_len += ++ OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size)); ++ else ++ xe_len += OCFS2_XATTR_ROOT_SIZE; ++ if (le16_to_cpu(xe->xe_name_offset) < ++ le16_to_cpu(xh->xh_free_start)) ++ xh->xh_free_start = xe->xe_name_offset; ++ } ++ ++ /* set xh->xh_num_buckets for the new xh. */ ++ if (new_bucket_head) ++ xh->xh_num_buckets = cpu_to_le16(1); ++ else ++ xh->xh_num_buckets = 0; ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ ocfs2_journal_dirty(handle, t_bhs[i]); ++ if (ret) ++ mlog_errno(ret); ++ } ++ ++ /* store the first_hash of the new bucket. */ ++ if (first_hash) ++ *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash); ++ ++ /* ++ * Now only update the 1st block of the old bucket. ++ * Please note that the entry has been sorted already above. ++ */ ++ xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; ++ memset(&xh->xh_entries[start], 0, ++ sizeof(struct ocfs2_xattr_entry) * (count - start)); ++ xh->xh_count = cpu_to_le16(start); ++ xh->xh_free_start = cpu_to_le16(name_offset); ++ xh->xh_name_value_len = cpu_to_le16(name_value_len); ++ ++ ocfs2_journal_dirty(handle, s_bhs[0]); ++ if (ret) ++ mlog_errno(ret); ++ ++out: ++ if (s_bhs) { ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(s_bhs[i]); ++ } ++ kfree(s_bhs); ++ ++ if (t_bhs) { ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(t_bhs[i]); ++ } ++ kfree(t_bhs); ++ ++ return ret; ++} ++ ++/* ++ * Copy xattr from one bucket to another bucket. ++ * ++ * The caller must make sure that the journal transaction ++ * has enough space for journaling. ++ */ ++static int ocfs2_cp_xattr_bucket(struct inode *inode, ++ handle_t *handle, ++ u64 s_blkno, ++ u64 t_blkno, ++ int t_is_new) ++{ ++ int ret, i; ++ int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int blocksize = inode->i_sb->s_blocksize; ++ struct buffer_head **s_bhs, **t_bhs = NULL; ++ ++ BUG_ON(s_blkno == t_blkno); ++ ++ mlog(0, "cp bucket %llu to %llu, target is %d\n", ++ s_blkno, t_blkno, t_is_new); ++ ++ s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, ++ GFP_NOFS); ++ if (!s_bhs) ++ return -ENOMEM; ++ ++ ret = ocfs2_read_xattr_bucket(inode, s_blkno, s_bhs, 0); ++ if (ret) ++ goto out; ++ ++ t_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, ++ GFP_NOFS); ++ if (!t_bhs) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = ocfs2_read_xattr_bucket(inode, t_blkno, t_bhs, t_is_new); ++ if (ret) ++ goto out; ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ ret = ocfs2_journal_access(handle, inode, t_bhs[i], ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) ++ goto out; ++ } ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); ++ ocfs2_journal_dirty(handle, t_bhs[i]); ++ } ++ ++out: ++ if (s_bhs) { ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(s_bhs[i]); ++ } ++ kfree(s_bhs); ++ ++ if (t_bhs) { ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(t_bhs[i]); ++ } ++ kfree(t_bhs); ++ ++ return ret; ++} ++ ++/* ++ * Copy one xattr cluster from src_blk to to_blk. ++ * The to_blk will become the first bucket header of the cluster, so its ++ * xh_num_buckets will be initialized as the bucket num in the cluster. ++ */ ++static int ocfs2_cp_xattr_cluster(struct inode *inode, ++ handle_t *handle, ++ struct buffer_head *first_bh, ++ u64 src_blk, ++ u64 to_blk, ++ u32 *first_hash) ++{ ++ int i, ret, credits; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); ++ int num_buckets = ocfs2_xattr_buckets_per_cluster(osb); ++ struct buffer_head *bh = NULL; ++ struct ocfs2_xattr_header *xh; ++ u64 to_blk_start = to_blk; ++ ++ mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk); ++ ++ /* ++ * We need to update the new cluster and 1 more for the update of ++ * the 1st bucket of the previous extent rec. ++ */ ++ credits = bpc + 1; ++ ret = ocfs2_extend_trans(handle, credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, first_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ for (i = 0; i < num_buckets; i++) { ++ ret = ocfs2_cp_xattr_bucket(inode, handle, ++ src_blk, to_blk, 1); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ src_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ to_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ } ++ ++ /* update the old bucket header. */ ++ xh = (struct ocfs2_xattr_header *)first_bh->b_data; ++ le16_add_cpu(&xh->xh_num_buckets, -num_buckets); ++ ++ ocfs2_journal_dirty(handle, first_bh); ++ ++ /* update the new bucket header. */ ++ ret = ocfs2_read_block(osb, to_blk_start, &bh, OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xh = (struct ocfs2_xattr_header *)bh->b_data; ++ xh->xh_num_buckets = cpu_to_le16(num_buckets); ++ ++ ocfs2_journal_dirty(handle, bh); ++ ++ if (first_hash) ++ *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash); ++out: ++ brelse(bh); ++ return ret; ++} ++ ++/* ++ * Move half of the xattrs in this cluster to the new cluster. ++ * This function should only be called when bucket size == cluster size. ++ * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead. ++ */ ++static int ocfs2_half_xattr_cluster(struct inode *inode, ++ handle_t *handle, ++ u64 prev_blk, ++ u64 new_blk, ++ u32 *first_hash) ++{ ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int ret, credits = 2 * blk_per_bucket; ++ ++ BUG_ON(OCFS2_XATTR_BUCKET_SIZE < OCFS2_SB(inode->i_sb)->s_clustersize); ++ ++ ret = ocfs2_extend_trans(handle, credits); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ /* Move half of the xattr in start_blk to the next bucket. */ ++ return ocfs2_half_xattr_bucket(inode, handle, prev_blk, ++ new_blk, first_hash, 1); ++} ++ ++/* ++ * Move some xattrs from the old cluster to the new one since they are not ++ * contiguous in ocfs2 xattr tree. ++ * ++ * new_blk starts a new separate cluster, and we will move some xattrs from ++ * prev_blk to it. v_start will be set as the first name hash value in this ++ * new cluster so that it can be used as e_cpos during tree insertion and ++ * don't collide with our original b-tree operations. first_bh and header_bh ++ * will also be updated since they will be used in ocfs2_extend_xattr_bucket ++ * to extend the insert bucket. ++ * ++ * The problem is how much xattr should we move to the new one and when should ++ * we update first_bh and header_bh? ++ * 1. If cluster size > bucket size, that means the previous cluster has more ++ * than 1 bucket, so just move half nums of bucket into the new cluster and ++ * update the first_bh and header_bh if the insert bucket has been moved ++ * to the new cluster. ++ * 2. If cluster_size == bucket_size: ++ * a) If the previous extent rec has more than one cluster and the insert ++ * place isn't in the last cluster, copy the entire last cluster to the ++ * new one. This time, we don't need to upate the first_bh and header_bh ++ * since they will not be moved into the new cluster. ++ * b) Otherwise, move the bottom half of the xattrs in the last cluster into ++ * the new one. And we set the extend flag to zero if the insert place is ++ * moved into the new allocated cluster since no extend is needed. ++ */ ++static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode, ++ handle_t *handle, ++ struct buffer_head **first_bh, ++ struct buffer_head **header_bh, ++ u64 new_blk, ++ u64 prev_blk, ++ u32 prev_clusters, ++ u32 *v_start, ++ int *extend) ++{ ++ int ret = 0; ++ int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); ++ ++ mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n", ++ prev_blk, prev_clusters, new_blk); ++ ++ if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1) ++ ret = ocfs2_mv_xattr_bucket_cross_cluster(inode, ++ handle, ++ first_bh, ++ header_bh, ++ new_blk, ++ prev_blk, ++ prev_clusters, ++ v_start); ++ else { ++ u64 last_blk = prev_blk + bpc * (prev_clusters - 1); ++ ++ if (prev_clusters > 1 && (*header_bh)->b_blocknr != last_blk) ++ ret = ocfs2_cp_xattr_cluster(inode, handle, *first_bh, ++ last_blk, new_blk, ++ v_start); ++ else { ++ ret = ocfs2_half_xattr_cluster(inode, handle, ++ last_blk, new_blk, ++ v_start); ++ ++ if ((*header_bh)->b_blocknr == last_blk && extend) ++ *extend = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * Add a new cluster for xattr storage. ++ * ++ * If the new cluster is contiguous with the previous one, it will be ++ * appended to the same extent record, and num_clusters will be updated. ++ * If not, we will insert a new extent for it and move some xattrs in ++ * the last cluster into the new allocated one. ++ * We also need to limit the maximum size of a btree leaf, otherwise we'll ++ * lose the benefits of hashing because we'll have to search large leaves. ++ * So now the maximum size is OCFS2_MAX_XATTR_TREE_LEAF_SIZE(or clustersize, ++ * if it's bigger). ++ * ++ * first_bh is the first block of the previous extent rec and header_bh ++ * indicates the bucket we will insert the new xattrs. They will be updated ++ * when the header_bh is moved into the new cluster. ++ */ ++static int ocfs2_add_new_xattr_cluster(struct inode *inode, ++ struct buffer_head *root_bh, ++ struct buffer_head **first_bh, ++ struct buffer_head **header_bh, ++ u32 *num_clusters, ++ u32 prev_cpos, ++ u64 prev_blkno, ++ int *extend) ++{ ++ int ret, credits; ++ u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); ++ u32 prev_clusters = *num_clusters; ++ u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0; ++ u64 block; ++ handle_t *handle = NULL; ++ struct ocfs2_alloc_context *data_ac = NULL; ++ struct ocfs2_alloc_context *meta_ac = NULL; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)root_bh->b_data; ++ struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root; ++ struct ocfs2_extent_list *root_el = &xb_root->xt_list; ++ enum ocfs2_extent_tree_type type = OCFS2_XATTR_TREE_EXTENT; ++ ++ mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, " ++ "previous xattr blkno = %llu\n", ++ (unsigned long long)OCFS2_I(inode)->ip_blkno, ++ prev_cpos, prev_blkno); ++ ++ ret = ocfs2_lock_allocators(inode, root_bh, root_el, ++ clusters_to_add, 0, &data_ac, ++ &meta_ac, type, NULL); ++ if (ret) { ++ mlog_errno(ret); ++ goto leave; ++ } ++ ++ credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add); ++ handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ handle = NULL; ++ mlog_errno(ret); ++ goto leave; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, root_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto leave; ++ } ++ ++ ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1, ++ clusters_to_add, &bit_off, &num_bits); ++ if (ret < 0) { ++ if (ret != -ENOSPC) ++ mlog_errno(ret); ++ goto leave; ++ } ++ ++ BUG_ON(num_bits > clusters_to_add); ++ ++ block = ocfs2_clusters_to_blocks(osb->sb, bit_off); ++ mlog(0, "Allocating %u clusters at block %u for xattr in inode %llu\n", ++ num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); ++ ++ if (prev_blkno + prev_clusters * bpc == block && ++ (prev_clusters + num_bits) << osb->s_clustersize_bits <= ++ OCFS2_MAX_XATTR_TREE_LEAF_SIZE) { ++ /* ++ * If this cluster is contiguous with the old one and ++ * adding this new cluster, we don't surpass the limit of ++ * OCFS2_MAX_XATTR_TREE_LEAF_SIZE, cool. We will let it be ++ * initialized and used like other buckets in the previous ++ * cluster. ++ * So add it as a contiguous one. The caller will handle ++ * its init process. ++ */ ++ v_start = prev_cpos + prev_clusters; ++ *num_clusters = prev_clusters + num_bits; ++ mlog(0, "Add contiguous %u clusters to previous extent rec.\n", ++ num_bits); ++ } else { ++ ret = ocfs2_adjust_xattr_cross_cluster(inode, ++ handle, ++ first_bh, ++ header_bh, ++ block, ++ prev_blkno, ++ prev_clusters, ++ &v_start, ++ extend); ++ if (ret) { ++ mlog_errno(ret); ++ goto leave; ++ } ++ } ++ ++ mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", ++ num_bits, block, v_start); ++ ret = ocfs2_xattr_tree_insert_extent(osb, handle, inode, root_bh, ++ v_start, block, num_bits, ++ 0, meta_ac); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto leave; ++ } ++ ++ ret = ocfs2_journal_dirty(handle, root_bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto leave; ++ } ++ ++leave: ++ if (handle) ++ ocfs2_commit_trans(osb, handle); ++ if (data_ac) ++ ocfs2_free_alloc_context(data_ac); ++ if (meta_ac) ++ ocfs2_free_alloc_context(meta_ac); ++ ++ return ret; ++} ++ ++/* ++ * Extend a new xattr bucket and move xattrs to the end one by one until ++ * We meet with start_bh. Only move half of the xattrs to the bucket after it. ++ */ ++static int ocfs2_extend_xattr_bucket(struct inode *inode, ++ struct buffer_head *first_bh, ++ struct buffer_head *start_bh, ++ u32 num_clusters) ++{ ++ int ret, credits; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ u64 start_blk = start_bh->b_blocknr, end_blk; ++ u32 num_buckets = num_clusters * ocfs2_xattr_buckets_per_cluster(osb); ++ handle_t *handle; ++ struct ocfs2_xattr_header *first_xh = ++ (struct ocfs2_xattr_header *)first_bh->b_data; ++ u16 bucket = le16_to_cpu(first_xh->xh_num_buckets); ++ ++ mlog(0, "extend xattr bucket in %llu, xattr extend rec starting " ++ "from %llu, len = %u\n", start_blk, ++ (unsigned long long)first_bh->b_blocknr, num_clusters); ++ ++ BUG_ON(bucket >= num_buckets); ++ ++ end_blk = first_bh->b_blocknr + (bucket - 1) * blk_per_bucket; ++ ++ /* ++ * We will touch all the buckets after the start_bh(include it). ++ * Add one more bucket and modify the first_bh. ++ */ ++ credits = end_blk - start_blk + 2 * blk_per_bucket + 1; ++ handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ handle = NULL; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, first_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto commit; ++ } ++ ++ while (end_blk != start_blk) { ++ ret = ocfs2_cp_xattr_bucket(inode, handle, end_blk, ++ end_blk + blk_per_bucket, 0); ++ if (ret) ++ goto commit; ++ end_blk -= blk_per_bucket; ++ } ++ ++ /* Move half of the xattr in start_blk to the next bucket. */ ++ ret = ocfs2_half_xattr_bucket(inode, handle, start_blk, ++ start_blk + blk_per_bucket, NULL, 0); ++ ++ le16_add_cpu(&first_xh->xh_num_buckets, 1); ++ ocfs2_journal_dirty(handle, first_bh); ++ ++commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ return ret; ++} ++ ++/* ++ * Add new xattr bucket in an extent record and adjust the buckets accordingly. ++ * xb_bh is the ocfs2_xattr_block. ++ * We will move all the buckets starting from header_bh to the next place. As ++ * for this one, half num of its xattrs will be moved to the next one. ++ * ++ * We will allocate a new cluster if current cluster is full and adjust ++ * header_bh and first_bh if the insert place is moved to the new cluster. ++ */ ++static int ocfs2_add_new_xattr_bucket(struct inode *inode, ++ struct buffer_head *xb_bh, ++ struct buffer_head *header_bh) ++{ ++ struct ocfs2_xattr_header *first_xh = NULL; ++ struct buffer_head *first_bh = NULL; ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)xb_bh->b_data; ++ struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root; ++ struct ocfs2_extent_list *el = &xb_root->xt_list; ++ struct ocfs2_xattr_header *xh = ++ (struct ocfs2_xattr_header *)header_bh->b_data; ++ u32 name_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash); ++ struct super_block *sb = inode->i_sb; ++ struct ocfs2_super *osb = OCFS2_SB(sb); ++ int ret, num_buckets, extend = 1; ++ u64 p_blkno; ++ u32 e_cpos, num_clusters; ++ ++ mlog(0, "Add new xattr bucket starting form %llu\n", ++ (unsigned long long)header_bh->b_blocknr); ++ ++ /* ++ * Add refrence for header_bh here because it may be ++ * changed in ocfs2_add_new_xattr_cluster and we need ++ * to free it in the end. ++ */ ++ get_bh(header_bh); ++ ++ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &e_cpos, ++ &num_clusters, el); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_read_block(osb, p_blkno, ++ &first_bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ num_buckets = ocfs2_xattr_buckets_per_cluster(osb) * num_clusters; ++ first_xh = (struct ocfs2_xattr_header *)first_bh->b_data; ++ ++ if (num_buckets == le16_to_cpu(first_xh->xh_num_buckets)) { ++ ret = ocfs2_add_new_xattr_cluster(inode, ++ xb_bh, ++ &first_bh, ++ &header_bh, ++ &num_clusters, ++ e_cpos, ++ p_blkno, ++ &extend); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ if (extend) ++ ret = ocfs2_extend_xattr_bucket(inode, ++ first_bh, ++ header_bh, ++ num_clusters); ++ if (ret) ++ mlog_errno(ret); ++out: ++ brelse(first_bh); ++ brelse(header_bh); ++ return ret; ++} ++ ++static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ int offs) ++{ ++ int block_off = offs >> inode->i_sb->s_blocksize_bits; ++ ++ offs = offs % inode->i_sb->s_blocksize; ++ return bucket->bhs[block_off]->b_data + offs; ++} ++ ++/* ++ * Handle the normal xattr set, including replace, delete and new. ++ * When the bucket is empty, "is_empty" is set and the caller can ++ * free this bucket. ++ * ++ * Note: "local" indicates the real data's locality. So we can't ++ * just its bucket locality by its length. ++ */ ++static void ocfs2_xattr_set_entry_normal(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ u32 name_hash, ++ int local, ++ int *is_empty) ++{ ++ struct ocfs2_xattr_entry *last, *xe; ++ int name_len = strlen(xi->name); ++ struct ocfs2_xattr_header *xh = xs->header; ++ u16 count = le16_to_cpu(xh->xh_count), start; ++ size_t blocksize = inode->i_sb->s_blocksize; ++ char *val; ++ size_t offs, size, new_size; ++ ++ last = &xh->xh_entries[count]; ++ if (!xs->not_found) { ++ xe = xs->here; ++ offs = le16_to_cpu(xe->xe_name_offset); ++ if (ocfs2_xattr_is_local(xe)) ++ size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size)); ++ else ++ size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE); ++ ++ /* ++ * If the new value will be stored outside, xi->value has been ++ * initalized as an empty ocfs2_xattr_value_root, and the same ++ * goes with xi->value_len, so we can set new_size safely here. ++ * See ocfs2_xattr_set_in_bucket. ++ */ ++ new_size = OCFS2_XATTR_SIZE(name_len) + ++ OCFS2_XATTR_SIZE(xi->value_len); ++ ++ le16_add_cpu(&xh->xh_name_value_len, -size); ++ if (xi->value) { ++ if (new_size > size) ++ goto set_new_name_value; ++ ++ /* Now replace the old value with new one. */ ++ if (local) ++ xe->xe_value_size = cpu_to_le64(xi->value_len); ++ else ++ xe->xe_value_size = 0; ++ ++ val = ocfs2_xattr_bucket_get_val(inode, ++ &xs->bucket, offs); ++ memset(val + OCFS2_XATTR_SIZE(name_len), 0, ++ size - OCFS2_XATTR_SIZE(name_len)); ++ if (OCFS2_XATTR_SIZE(xi->value_len) > 0) ++ memcpy(val + OCFS2_XATTR_SIZE(name_len), ++ xi->value, xi->value_len); ++ ++ le16_add_cpu(&xh->xh_name_value_len, new_size); ++ ocfs2_xattr_set_local(xe, local); ++ return; ++ } else { ++ /* Remove the old entry. */ ++ last -= 1; ++ memmove(xe, xe + 1, ++ (void *)last - (void *)xe); ++ memset(last, 0, sizeof(struct ocfs2_xattr_entry)); ++ le16_add_cpu(&xh->xh_count, -1); ++ if (xh->xh_count == 0 && is_empty) ++ *is_empty = 1; ++ return; ++ } ++ } else { ++ /* find a new entry for insert. */ ++ int low = 0, high = count - 1, tmp; ++ struct ocfs2_xattr_entry *tmp_xe; ++ ++ while (low <= high) { ++ tmp = (low + high) / 2; ++ tmp_xe = &xh->xh_entries[tmp]; ++ ++ if (name_hash > le32_to_cpu(tmp_xe->xe_name_hash)) ++ low = tmp + 1; ++ else if (name_hash < ++ le32_to_cpu(tmp_xe->xe_name_hash)) ++ high = tmp - 1; ++ else ++ break; ++ } ++ ++ xe = &xh->xh_entries[low]; ++ if (low != count) ++ memmove(xe + 1, xe, (void *)last - (void *)xe); ++ ++ le16_add_cpu(&xh->xh_count, 1); ++ memset(xe, 0, sizeof(struct ocfs2_xattr_entry)); ++ xe->xe_name_hash = cpu_to_le32(name_hash); ++ xe->xe_name_len = name_len; ++ ocfs2_xattr_set_type(xe, xi->name_index); ++ } ++ ++set_new_name_value: ++ /* Insert the new name+value. */ ++ size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(xi->value_len); ++ ++ /* ++ * We must make sure that the name/value pair ++ * exists in the same block. ++ */ ++ offs = le16_to_cpu(xh->xh_free_start); ++ start = offs - size; ++ ++ if (start >> inode->i_sb->s_blocksize_bits != ++ (offs - 1) >> inode->i_sb->s_blocksize_bits) { ++ offs = offs - offs % blocksize; ++ xh->xh_free_start = cpu_to_le16(offs); ++ } ++ ++ val = ocfs2_xattr_bucket_get_val(inode, ++ &xs->bucket, offs - size); ++ xe->xe_name_offset = cpu_to_le16(offs - size); ++ ++ memset(val, 0, size); ++ memcpy(val, xi->name, name_len); ++ memcpy(val + OCFS2_XATTR_SIZE(name_len), xi->value, xi->value_len); ++ ++ xe->xe_value_size = cpu_to_le64(xi->value_len); ++ ocfs2_xattr_set_local(xe, local); ++ xs->here = xe; ++ le16_add_cpu(&xh->xh_free_start, -size); ++ le16_add_cpu(&xh->xh_name_value_len, size); ++ ++ return; ++} ++ ++static int ocfs2_xattr_bucket_handle_journal(struct inode *inode, ++ handle_t *handle, ++ struct ocfs2_xattr_search *xs, ++ struct buffer_head **bhs, ++ u16 bh_num) ++{ ++ int ret = 0, off, block_off; ++ struct ocfs2_xattr_entry *xe = xs->here; ++ ++ /* ++ * First calculate all the blocks we should journal_access ++ * and journal_dirty. The first block should always be touched. ++ */ ++ ret = ocfs2_journal_dirty(handle, bhs[0]); ++ if (ret) ++ mlog_errno(ret); ++ ++ /* calc the data. */ ++ off = le16_to_cpu(xe->xe_name_offset); ++ block_off = off >> inode->i_sb->s_blocksize_bits; ++ ret = ocfs2_journal_dirty(handle, bhs[block_off]); ++ if (ret) ++ mlog_errno(ret); ++ ++ return ret; ++} ++ ++/* ++ * Set the xattr entry in the specified bucket. ++ * The bucket is indicated by xs->bucket and it should have the enough ++ * space for the xattr insertion. ++ */ ++static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ u32 name_hash, ++ int local, ++ int *bucket_empty) ++{ ++ int i, ret; ++ handle_t *handle = NULL; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ mlog(0, "Set xattr entry len = %d index = %d in bucket %llu\n", ++ xi->value_len, xi->name_index, ++ (unsigned long long)xs->bucket.bhs[0]->b_blocknr); ++ ++ if (!xs->bucket.bhs[1]) { ++ ret = ocfs2_read_blocks(osb, ++ xs->bucket.bhs[0]->b_blocknr + 1, ++ blk_per_bucket - 1, &xs->bucket.bhs[1], ++ OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ handle = ocfs2_start_trans(osb, blk_per_bucket); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ handle = NULL; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ for (i = 0; i < blk_per_bucket; i++) { ++ ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[i], ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, ++ local, bucket_empty); ++ ++ /*Only dirty the blocks we have touched in set xattr. */ ++ ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs, ++ xs->bucket.bhs, blk_per_bucket); ++ if (ret) ++ mlog_errno(ret); ++out: ++ ocfs2_commit_trans(osb, handle); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_value_update_size(struct inode *inode, ++ struct buffer_head *xe_bh, ++ struct ocfs2_xattr_entry *xe, ++ u64 new_size) ++{ ++ int ret; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ handle_t *handle = NULL; ++ ++ handle = ocfs2_start_trans(osb, 1); ++ if (handle == NULL) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, xe_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ xe->xe_value_size = cpu_to_le64(new_size); ++ ++ ret = ocfs2_journal_dirty(handle, xe_bh); ++ if (ret < 0) ++ mlog_errno(ret); ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ return ret; ++} ++ ++/* ++ * Truncate the specified xe_off entry in xattr bucket. ++ * bucket is indicated by header_bh and len is the new length. ++ * Both the ocfs2_xattr_value_root and the entry will be updated here. ++ * ++ * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed. ++ */ ++static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, ++ struct buffer_head *header_bh, ++ int xe_off, ++ int len) ++{ ++ int ret, offset; ++ u64 value_blk; ++ struct buffer_head *value_bh = NULL; ++ struct ocfs2_xattr_value_root *xv; ++ struct ocfs2_xattr_entry *xe; ++ struct ocfs2_xattr_header *xh = ++ (struct ocfs2_xattr_header *)header_bh->b_data; ++ size_t blocksize = inode->i_sb->s_blocksize; ++ ++ xe = &xh->xh_entries[xe_off]; ++ ++ BUG_ON(!xe || ocfs2_xattr_is_local(xe)); ++ ++ offset = le16_to_cpu(xe->xe_name_offset) + ++ OCFS2_XATTR_SIZE(xe->xe_name_len); ++ ++ value_blk = offset / blocksize; ++ ++ /* We don't allow ocfs2_xattr_value to be stored in different block. */ ++ BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize); ++ value_blk += header_bh->b_blocknr; ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), value_blk, ++ &value_bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xv = (struct ocfs2_xattr_value_root *) ++ (value_bh->b_data + offset % blocksize); ++ ++ mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n", ++ xe_off, (unsigned long long)header_bh->b_blocknr, len); ++ ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_xattr_value_update_size(inode, header_bh, xe, len); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++out: ++ brelse(value_bh); ++ return ret; ++} ++ ++static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, ++ struct ocfs2_xattr_search *xs, ++ int len) ++{ ++ int ret, offset; ++ struct ocfs2_xattr_entry *xe = xs->here; ++ struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base; ++ ++ BUG_ON(!xs->bucket.bhs[0] || !xe || ocfs2_xattr_is_local(xe)); ++ ++ offset = xe - xh->xh_entries; ++ ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bhs[0], ++ offset, len); ++ if (ret) ++ mlog_errno(ret); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, ++ struct ocfs2_xattr_search *xs, ++ char *val, ++ int value_len) ++{ ++ int offset; ++ struct ocfs2_xattr_value_root *xv; ++ struct ocfs2_xattr_entry *xe = xs->here; ++ ++ BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe)); ++ ++ offset = le16_to_cpu(xe->xe_name_offset) + ++ OCFS2_XATTR_SIZE(xe->xe_name_len); ++ ++ xv = (struct ocfs2_xattr_value_root *)(xs->base + offset); ++ ++ return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len); ++} ++ ++/* ++ * Remove the xattr bucket pointed by bucket_bh. ++ * All the buckets after it in the same xattr extent rec will be ++ * move forward one by one. ++ */ ++static int ocfs2_rm_xattr_bucket(struct inode *inode, ++ struct buffer_head *first_bh, ++ struct ocfs2_xattr_bucket *bucket) ++{ ++ int ret = 0, credits; ++ struct ocfs2_xattr_header *xh = ++ (struct ocfs2_xattr_header *)first_bh->b_data; ++ u16 bucket_num = le16_to_cpu(xh->xh_num_buckets); ++ u64 end, start = bucket->bhs[0]->b_blocknr; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ handle_t *handle; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ end = first_bh->b_blocknr + (bucket_num - 1) * blk_per_bucket; ++ ++ mlog(0, "rm xattr bucket %llu\n", start); ++ /* ++ * We need to update the first xattr_header and all the buckets starting ++ * from start in this xattr rec. ++ * ++ * XXX: Should we empty the old last bucket here? ++ */ ++ credits = 1 + end - start; ++ handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, first_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ++ while (start < end) { ++ ret = ocfs2_cp_xattr_bucket(inode, handle, ++ start + blk_per_bucket, ++ start, 0); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ start += blk_per_bucket; ++ } ++ ++ /* update the first_bh. */ ++ xh->xh_num_buckets = cpu_to_le16(bucket_num - 1); ++ ocfs2_journal_dirty(handle, first_bh); ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++ return ret; ++} ++ ++static int ocfs2_rm_xattr_cluster(struct inode *inode, ++ struct buffer_head *root_bh, ++ u64 blkno, ++ u32 cpos, ++ u32 len) ++{ ++ int ret; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct inode *tl_inode = osb->osb_tl_inode; ++ handle_t *handle; ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)root_bh->b_data; ++ struct ocfs2_extent_list *root_el = &xb->xb_attrs.xb_root.xt_list; ++ struct ocfs2_alloc_context *meta_ac = NULL; ++ struct ocfs2_cached_dealloc_ctxt dealloc; ++ ++ ocfs2_init_dealloc_ctxt(&dealloc); ++ ++ mlog(0, "rm xattr extent rec at %u len = %u, start from %llu\n", ++ cpos, len, (unsigned long long)blkno); ++ ++ ocfs2_remove_xattr_clusters_from_cache(inode, blkno, len); ++ ++ ret = ocfs2_lock_allocators(inode, root_bh, root_el, ++ 0, 1, NULL, &meta_ac, ++ OCFS2_XATTR_TREE_EXTENT, NULL); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ mutex_lock(&tl_inode->i_mutex); ++ ++ if (ocfs2_truncate_log_needs_flush(osb)) { ++ ret = __ocfs2_flush_truncate_log(osb); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ if (handle == NULL) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, root_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac, ++ &dealloc, OCFS2_XATTR_TREE_EXTENT, NULL); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, -len); ++ ++ ret = ocfs2_journal_dirty(handle, root_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_truncate_log_append(osb, handle, blkno, len); ++ if (ret) ++ mlog_errno(ret); ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ ocfs2_schedule_truncate_log_flush(osb, 1); ++ ++ mutex_unlock(&tl_inode->i_mutex); ++ ++ if (meta_ac) ++ ocfs2_free_alloc_context(meta_ac); ++ ++ ocfs2_run_deallocs(osb, &dealloc); ++ ++ return ret; ++} ++ ++/* ++ * Free the xattr bucket indicated by xs->bucket and if all the buckets ++ * in the clusters is free, free the clusters also. ++ */ ++static int ocfs2_xattr_bucket_shrink(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs, ++ u32 name_hash) ++{ ++ int ret; ++ u32 e_cpos, num_clusters; ++ u64 p_blkno; ++ struct buffer_head *first_bh = NULL; ++ struct ocfs2_xattr_header *first_xh; ++ struct ocfs2_xattr_block *xb = ++ (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; ++ ++ BUG_ON(xs->header->xh_count != 0); ++ ++ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, ++ &e_cpos, &num_clusters, ++ &xb->xb_attrs.xb_root.xt_list); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, ++ &first_bh, OCFS2_BH_CACHED, inode); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ ret = ocfs2_rm_xattr_bucket(inode, first_bh, &xs->bucket); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ first_xh = (struct ocfs2_xattr_header *)first_bh->b_data; ++ if (first_xh->xh_num_buckets == 0) ++ ret = ocfs2_rm_xattr_cluster(inode, xs->xattr_bh, ++ p_blkno, e_cpos, ++ num_clusters); ++ ++out: ++ brelse(first_bh); ++ return ret; ++} ++ ++static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, ++ struct ocfs2_xattr_search *xs) ++{ ++ handle_t *handle = NULL; ++ struct ocfs2_xattr_header *xh = xs->bucket.xh; ++ struct ocfs2_xattr_entry *last = &xh->xh_entries[ ++ le16_to_cpu(xh->xh_count) - 1]; ++ int ret = 0; ++ ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), 1); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ return; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[0], ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ /* Remove the old entry. */ ++ memmove(xs->here, xs->here + 1, ++ (void *)last - (void *)xs->here); ++ memset(last, 0, sizeof(struct ocfs2_xattr_entry)); ++ le16_add_cpu(&xh->xh_count, -1); ++ ++ ret = ocfs2_journal_dirty(handle, xs->bucket.bhs[0]); ++ if (ret < 0) ++ mlog_errno(ret); ++out_commit: ++ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); ++} ++ ++/* ++ * Set the xattr name/value in the bucket specified in xs. ++ * ++ * As the new value in xi may be stored in the bucket or in an outside cluster, ++ * we divide the whole process into 3 steps: ++ * 1. insert name/value in the bucket(ocfs2_xattr_set_entry_in_bucket) ++ * 2. truncate of the outside cluster(ocfs2_xattr_bucket_value_truncate_xs) ++ * 3. Set the value to the outside cluster(ocfs2_xattr_bucket_set_value_outside) ++ * 4. If the clusters for the new outside value can't be allocated, we need ++ * to free the xattr we allocated in set. ++ */ ++static int ocfs2_xattr_set_in_bucket(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs) ++{ ++ int ret, local = 1, bucket_empty = 0; ++ size_t value_len; ++ char *val = (char *)xi->value; ++ struct ocfs2_xattr_entry *xe = xs->here; ++ u32 name_hash = ocfs2_xattr_hash_by_name(inode, ++ xi->name_index, xi->name); ++ ++ if (!xs->not_found && !ocfs2_xattr_is_local(xe)) { ++ /* ++ * We need to truncate the xattr storage first. ++ * ++ * If both the old and new value are stored to ++ * outside block, we only need to truncate ++ * the storage and then set the value outside. ++ * ++ * If the new value should be stored within block, ++ * we should free all the outside block first and ++ * the modification to the xattr block will be done ++ * by following steps. ++ */ ++ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) ++ value_len = xi->value_len; ++ else ++ value_len = 0; ++ ++ ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, ++ value_len); ++ if (ret) ++ goto out; ++ ++ if (value_len) ++ goto set_value_outside; ++ } ++ ++ value_len = xi->value_len; ++ /* So we have to handle the inside block change now. */ ++ if (value_len > OCFS2_XATTR_INLINE_SIZE) { ++ /* ++ * If the new value will be stored outside of block, ++ * initalize a new empty value root and insert it first. ++ */ ++ local = 0; ++ xi->value = &def_xv; ++ xi->value_len = OCFS2_XATTR_ROOT_SIZE; ++ } ++ ++ ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, ++ local, &bucket_empty); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ if (value_len > OCFS2_XATTR_INLINE_SIZE) { ++ /* allocate the space now for the outside block storage. */ ++ ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, ++ value_len); ++ if (ret) { ++ mlog_errno(ret); ++ ++ if (xs->not_found) { ++ /* ++ * We can't allocate enough clusters for outside ++ * storage and we have allocated xattr already, ++ * so need to remove it. ++ */ ++ ocfs2_xattr_bucket_remove_xs(inode, xs); ++ } ++ goto out; ++ } ++ } else { ++ if (bucket_empty) ++ ret = ocfs2_xattr_bucket_shrink(inode, xi, ++ xs, name_hash); ++ goto out; ++ } ++ ++set_value_outside: ++ ret = ocfs2_xattr_bucket_set_value_outside(inode, xs, val, value_len); ++out: ++ return ret; ++} ++ ++/* check whether the xattr bucket is filled up with the same hash value. */ ++static int ocfs2_check_xattr_bucket_collision(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket) ++{ ++ struct ocfs2_xattr_header *xh = bucket->xh; ++ ++ if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash == ++ xh->xh_entries[0].xe_name_hash) { ++ mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, " ++ "hash = %u\n", ++ (unsigned long long)bucket->bhs[0]->b_blocknr, ++ le32_to_cpu(xh->xh_entries[0].xe_name_hash)); ++ return -ENOSPC; ++ } ++ ++ return 0; ++} ++ ++static int ocfs2_xattr_set_entry_index_block(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs) ++{ ++ struct ocfs2_xattr_header *xh; ++ struct ocfs2_xattr_entry *xe; ++ u16 count, header_size, xh_free_start; ++ int i, free, max_free, need, old; ++ size_t value_size = 0, name_len = strlen(xi->name); ++ size_t blocksize = inode->i_sb->s_blocksize; ++ int ret, allocation = 0; ++ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ mlog_entry("Set xattr %s in xattr index block\n", xi->name); ++ ++try_again: ++ xh = xs->header; ++ count = le16_to_cpu(xh->xh_count); ++ xh_free_start = le16_to_cpu(xh->xh_free_start); ++ header_size = sizeof(struct ocfs2_xattr_header) + ++ count * sizeof(struct ocfs2_xattr_entry); ++ max_free = OCFS2_XATTR_BUCKET_SIZE - ++ le16_to_cpu(xh->xh_name_value_len) - header_size; ++ ++ mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " ++ "of %u which exceed block size\n", ++ (unsigned long long)xs->bucket.bhs[0]->b_blocknr, ++ header_size); ++ ++ if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) ++ value_size = OCFS2_XATTR_ROOT_SIZE; ++ else if (xi->value) ++ value_size = OCFS2_XATTR_SIZE(xi->value_len); ++ ++ if (xs->not_found) ++ need = sizeof(struct ocfs2_xattr_entry) + ++ OCFS2_XATTR_SIZE(name_len) + value_size; ++ else { ++ need = value_size + OCFS2_XATTR_SIZE(name_len); ++ ++ /* ++ * We only replace the old value if the new length is smaller ++ * than the old one. Otherwise we will allocate new space in the ++ * bucket to store it. ++ */ ++ xe = xs->here; ++ if (ocfs2_xattr_is_local(xe)) ++ old = OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size)); ++ else ++ old = OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE); ++ ++ if (old >= value_size) ++ need = 0; ++ } ++ ++ free = xh_free_start - header_size; ++ /* ++ * We need to make sure the new name/value pair ++ * can exist in the same block. ++ */ ++ if (xh_free_start % blocksize < need) ++ free -= xh_free_start % blocksize; ++ ++ mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, " ++ "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len =" ++ " %u\n", xs->not_found, ++ (unsigned long long)xs->bucket.bhs[0]->b_blocknr, ++ free, need, max_free, le16_to_cpu(xh->xh_free_start), ++ le16_to_cpu(xh->xh_name_value_len)); ++ ++ if (free < need || count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) { ++ if (need <= max_free && ++ count < ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) { ++ /* ++ * We can create the space by defragment. Since only the ++ * name/value will be moved, the xe shouldn't be changed ++ * in xs. ++ */ ++ ret = ocfs2_defrag_xattr_bucket(inode, &xs->bucket); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xh_free_start = le16_to_cpu(xh->xh_free_start); ++ free = xh_free_start - header_size; ++ if (xh_free_start % blocksize < need) ++ free -= xh_free_start % blocksize; ++ ++ if (free >= need) ++ goto xattr_set; ++ ++ mlog(0, "Can't get enough space for xattr insert by " ++ "defragment. Need %u bytes, but we have %d, so " ++ "allocate new bucket for it.\n", need, free); ++ } ++ ++ /* ++ * We have to add new buckets or clusters and one ++ * allocation should leave us enough space for insert. ++ */ ++ BUG_ON(allocation); ++ ++ /* ++ * We do not allow for overlapping ranges between buckets. And ++ * the maximum number of collisions we will allow for then is ++ * one bucket's worth, so check it here whether we need to ++ * add a new bucket for the insert. ++ */ ++ ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_add_new_xattr_bucket(inode, ++ xs->xattr_bh, ++ xs->bucket.bhs[0]); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ for (i = 0; i < blk_per_bucket; i++) ++ brelse(xs->bucket.bhs[i]); ++ ++ memset(&xs->bucket, 0, sizeof(xs->bucket)); ++ ++ ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh, ++ xi->name_index, ++ xi->name, xs); ++ if (ret && ret != -ENODATA) ++ goto out; ++ xs->not_found = ret; ++ allocation = 1; ++ goto try_again; ++ } ++ ++xattr_set: ++ ret = ocfs2_xattr_set_in_bucket(inode, xi, xs); ++out: ++ mlog_exit(ret); ++ return ret; ++} +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index a69c8aa..d33dbe5 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -64,4 +64,12 @@ static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) + { + return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); + } ++ ++static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) ++{ ++ u16 len = sb->s_blocksize - ++ offsetof(struct ocfs2_xattr_header, xh_entries); ++ ++ return len / sizeof(struct ocfs2_xattr_entry); ++} + #endif /* OCFS2_XATTR_H */ +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Field-prefixes-for-the-xattr_bucket-structure.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Field-prefixes-for-the-xattr_bucket-structure.patch new file mode 100644 index 000000000..b00923c86 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Field-prefixes-for-the-xattr_bucket-structure.patch @@ -0,0 +1,362 @@ +From: Joel Becker +Date: Sat, 18 Oct 2008 19:11:42 -0700 +Subject: ocfs2: Field prefixes for the xattr_bucket structure +Patch-mainline: 2.6.29 + +The ocfs2_xattr_bucket structure keeps track of the buffers for one +xattr bucket. Let's prefix the fields for easier code navigation. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 100 +++++++++++++++++++++++++++--------------------------- + 1 files changed, 50 insertions(+), 50 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 74d7367..9c0ee42 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -61,8 +61,8 @@ struct ocfs2_xattr_def_value_root { + }; + + struct ocfs2_xattr_bucket { +- struct buffer_head *bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET]; +- struct ocfs2_xattr_header *xh; ++ struct buffer_head *bu_bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET]; ++ struct ocfs2_xattr_header *bu_xh; + }; + + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) +@@ -795,11 +795,11 @@ static int ocfs2_xattr_block_get(struct inode *inode, + + if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { + ret = ocfs2_xattr_bucket_get_name_value(inode, +- xs->bucket.xh, ++ xs->bucket.bu_xh, + i, + &block_off, + &name_offset); +- xs->base = xs->bucket.bhs[block_off]->b_data; ++ xs->base = xs->bucket.bu_bhs[block_off]->b_data; + } + if (ocfs2_xattr_is_local(xs->here)) { + memcpy(buffer, (void *)xs->base + +@@ -818,7 +818,7 @@ static int ocfs2_xattr_block_get(struct inode *inode, + ret = size; + cleanup: + for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++) +- brelse(xs->bucket.bhs[i]); ++ brelse(xs->bucket.bu_bhs[i]); + memset(&xs->bucket, 0, sizeof(xs->bucket)); + + brelse(xs->xattr_bh); +@@ -2032,7 +2032,7 @@ cleanup: + brelse(di_bh); + brelse(xbs.xattr_bh); + for (i = 0; i < blk_per_bucket; i++) +- brelse(xbs.bucket.bhs[i]); ++ brelse(xbs.bucket.bu_bhs[i]); + + return ret; + } +@@ -2276,13 +2276,13 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + lower_bh = bh; + bh = NULL; + } +- xs->bucket.bhs[0] = lower_bh; +- xs->bucket.xh = (struct ocfs2_xattr_header *) +- xs->bucket.bhs[0]->b_data; ++ xs->bucket.bu_bhs[0] = lower_bh; ++ xs->bucket.bu_xh = (struct ocfs2_xattr_header *) ++ xs->bucket.bu_bhs[0]->b_data; + lower_bh = NULL; + +- xs->header = xs->bucket.xh; +- xs->base = xs->bucket.bhs[0]->b_data; ++ xs->header = xs->bucket.bu_xh; ++ xs->base = xs->bucket.bu_bhs[0]->b_data; + xs->end = xs->base + inode->i_sb->s_blocksize; + + if (found) { +@@ -2290,8 +2290,8 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + * If we have found the xattr enty, read all the blocks in + * this bucket. + */ +- ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1, +- blk_per_bucket - 1, &xs->bucket.bhs[1], ++ ret = ocfs2_read_blocks(inode, xs->bucket.bu_bhs[0]->b_blocknr + 1, ++ blk_per_bucket - 1, &xs->bucket.bu_bhs[1], + 0); + if (ret) { + mlog_errno(ret); +@@ -2300,7 +2300,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + + xs->here = &xs->header->xh_entries[index]; + mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name, +- (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index); ++ (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr, index); + } else + ret = -ENODATA; + +@@ -2370,23 +2370,23 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + + for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { + ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, +- bucket.bhs, 0); ++ bucket.bu_bhs, 0); + if (ret) { + mlog_errno(ret); + goto out; + } + +- bucket.xh = (struct ocfs2_xattr_header *)bucket.bhs[0]->b_data; ++ bucket.bu_xh = (struct ocfs2_xattr_header *)bucket.bu_bhs[0]->b_data; + /* + * The real bucket num in this series of blocks is stored + * in the 1st bucket. + */ + if (i == 0) +- num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets); ++ num_buckets = le16_to_cpu(bucket.bu_xh->xh_num_buckets); + + mlog(0, "iterating xattr bucket %llu, first hash %u\n", + (unsigned long long)blkno, +- le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash)); ++ le32_to_cpu(bucket.bu_xh->xh_entries[0].xe_name_hash)); + if (func) { + ret = func(inode, &bucket, para); + if (ret) { +@@ -2396,13 +2396,13 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + } + + for (j = 0; j < blk_per_bucket; j++) +- brelse(bucket.bhs[j]); ++ brelse(bucket.bu_bhs[j]); + memset(&bucket, 0, sizeof(bucket)); + } + + out: + for (j = 0; j < blk_per_bucket; j++) +- brelse(bucket.bhs[j]); ++ brelse(bucket.bu_bhs[j]); + + return ret; + } +@@ -2441,21 +2441,21 @@ static int ocfs2_list_xattr_bucket(struct inode *inode, + int i, block_off, new_offset; + const char *prefix, *name; + +- for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) { +- struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i]; ++ for (i = 0 ; i < le16_to_cpu(bucket->bu_xh->xh_count); i++) { ++ struct ocfs2_xattr_entry *entry = &bucket->bu_xh->xh_entries[i]; + type = ocfs2_xattr_get_type(entry); + prefix = ocfs2_xattr_prefix(type); + + if (prefix) { + ret = ocfs2_xattr_bucket_get_name_value(inode, +- bucket->xh, ++ bucket->bu_xh, + i, + &block_off, + &new_offset); + if (ret) + break; + +- name = (const char *)bucket->bhs[block_off]->b_data + ++ name = (const char *)bucket->bu_bhs[block_off]->b_data + + new_offset; + ret = ocfs2_xattr_list_entry(xl->buffer, + xl->buffer_size, +@@ -2626,10 +2626,10 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + int i, blocksize = inode->i_sb->s_blocksize; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + +- xs->bucket.bhs[0] = new_bh; ++ xs->bucket.bu_bhs[0] = new_bh; + get_bh(new_bh); +- xs->bucket.xh = (struct ocfs2_xattr_header *)xs->bucket.bhs[0]->b_data; +- xs->header = xs->bucket.xh; ++ xs->bucket.bu_xh = (struct ocfs2_xattr_header *)xs->bucket.bu_bhs[0]->b_data; ++ xs->header = xs->bucket.bu_xh; + + xs->base = new_bh->b_data; + xs->end = xs->base + inode->i_sb->s_blocksize; +@@ -2637,8 +2637,8 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + if (!xs->not_found) { + if (OCFS2_XATTR_BUCKET_SIZE != blocksize) { + ret = ocfs2_read_blocks(inode, +- xs->bucket.bhs[0]->b_blocknr + 1, +- blk_per_bucket - 1, &xs->bucket.bhs[1], ++ xs->bucket.bu_bhs[0]->b_blocknr + 1, ++ blk_per_bucket - 1, &xs->bucket.bu_bhs[1], + 0); + if (ret) { + mlog_errno(ret); +@@ -2835,7 +2835,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + size_t end, offset, len, value_len; + struct ocfs2_xattr_header *xh; + char *entries, *buf, *bucket_buf = NULL; +- u64 blkno = bucket->bhs[0]->b_blocknr; ++ u64 blkno = bucket->bu_bhs[0]->b_blocknr; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u16 xh_free_start; + size_t blocksize = inode->i_sb->s_blocksize; +@@ -3929,7 +3929,7 @@ static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode, + int block_off = offs >> inode->i_sb->s_blocksize_bits; + + offs = offs % inode->i_sb->s_blocksize; +- return bucket->bhs[block_off]->b_data + offs; ++ return bucket->bu_bhs[block_off]->b_data + offs; + } + + /* +@@ -4124,12 +4124,12 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + + mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", + (unsigned long)xi->value_len, xi->name_index, +- (unsigned long long)xs->bucket.bhs[0]->b_blocknr); ++ (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr); + +- if (!xs->bucket.bhs[1]) { ++ if (!xs->bucket.bu_bhs[1]) { + ret = ocfs2_read_blocks(inode, +- xs->bucket.bhs[0]->b_blocknr + 1, +- blk_per_bucket - 1, &xs->bucket.bhs[1], ++ xs->bucket.bu_bhs[0]->b_blocknr + 1, ++ blk_per_bucket - 1, &xs->bucket.bu_bhs[1], + 0); + if (ret) { + mlog_errno(ret); +@@ -4146,7 +4146,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + } + + for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[i], ++ ret = ocfs2_journal_access(handle, inode, xs->bucket.bu_bhs[i], + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { + mlog_errno(ret); +@@ -4158,7 +4158,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + + /*Only dirty the blocks we have touched in set xattr. */ + ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs, +- xs->bucket.bhs, blk_per_bucket); ++ xs->bucket.bu_bhs, blk_per_bucket); + if (ret) + mlog_errno(ret); + out: +@@ -4272,10 +4272,10 @@ static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, + struct ocfs2_xattr_entry *xe = xs->here; + struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base; + +- BUG_ON(!xs->bucket.bhs[0] || !xe || ocfs2_xattr_is_local(xe)); ++ BUG_ON(!xs->bucket.bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe)); + + offset = xe - xh->xh_entries; +- ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bhs[0], ++ ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bu_bhs[0], + offset, len); + if (ret) + mlog_errno(ret); +@@ -4395,7 +4395,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + struct ocfs2_xattr_search *xs) + { + handle_t *handle = NULL; +- struct ocfs2_xattr_header *xh = xs->bucket.xh; ++ struct ocfs2_xattr_header *xh = xs->bucket.bu_xh; + struct ocfs2_xattr_entry *last = &xh->xh_entries[ + le16_to_cpu(xh->xh_count) - 1]; + int ret = 0; +@@ -4407,7 +4407,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + return; + } + +- ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[0], ++ ret = ocfs2_journal_access(handle, inode, xs->bucket.bu_bhs[0], + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -4420,7 +4420,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + memset(last, 0, sizeof(struct ocfs2_xattr_entry)); + le16_add_cpu(&xh->xh_count, -1); + +- ret = ocfs2_journal_dirty(handle, xs->bucket.bhs[0]); ++ ret = ocfs2_journal_dirty(handle, xs->bucket.bu_bhs[0]); + if (ret < 0) + mlog_errno(ret); + out_commit: +@@ -4530,7 +4530,7 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, + struct ocfs2_xattr_bucket *bucket, + const char *name) + { +- struct ocfs2_xattr_header *xh = bucket->xh; ++ struct ocfs2_xattr_header *xh = bucket->bu_xh; + u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name)); + + if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash)) +@@ -4540,7 +4540,7 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, + xh->xh_entries[0].xe_name_hash) { + mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, " + "hash = %u\n", +- (unsigned long long)bucket->bhs[0]->b_blocknr, ++ (unsigned long long)bucket->bu_bhs[0]->b_blocknr, + le32_to_cpu(xh->xh_entries[0].xe_name_hash)); + return -ENOSPC; + } +@@ -4574,7 +4574,7 @@ try_again: + + mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " + "of %u which exceed block size\n", +- (unsigned long long)xs->bucket.bhs[0]->b_blocknr, ++ (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr, + header_size); + + if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) +@@ -4614,7 +4614,7 @@ try_again: + mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, " + "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len =" + " %u\n", xs->not_found, +- (unsigned long long)xs->bucket.bhs[0]->b_blocknr, ++ (unsigned long long)xs->bucket.bu_bhs[0]->b_blocknr, + free, need, max_free, le16_to_cpu(xh->xh_free_start), + le16_to_cpu(xh->xh_name_value_len)); + +@@ -4667,14 +4667,14 @@ try_again: + + ret = ocfs2_add_new_xattr_bucket(inode, + xs->xattr_bh, +- xs->bucket.bhs[0]); ++ xs->bucket.bu_bhs[0]); + if (ret) { + mlog_errno(ret); + goto out; + } + + for (i = 0; i < blk_per_bucket; i++) +- brelse(xs->bucket.bhs[i]); ++ brelse(xs->bucket.bu_bhs[i]); + + memset(&xs->bucket, 0, sizeof(xs->bucket)); + +@@ -4700,7 +4700,7 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + void *para) + { + int ret = 0; +- struct ocfs2_xattr_header *xh = bucket->xh; ++ struct ocfs2_xattr_header *xh = bucket->bu_xh; + u16 i; + struct ocfs2_xattr_entry *xe; + +@@ -4710,7 +4710,7 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + continue; + + ret = ocfs2_xattr_bucket_value_truncate(inode, +- bucket->bhs[0], ++ bucket->bu_bhs[0], + i, 0); + if (ret) { + mlog_errno(ret); +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-grace-time-syncing.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-grace-time-syncing.patch new file mode 100644 index 000000000..0b277d453 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-grace-time-syncing.patch @@ -0,0 +1,64 @@ +From: Jan Kara +References: fate#302681 +Subject: ocfs2: Fix grace time syncing +Patch-mainline: 2.6.29? + +Fix syncing of grace times with other nodes. Previously, grace time could never +be reset to 0 even after user got below his softlimit. + +Signed-off-by: Jan Kara + +Index: linux-2.6.27/fs/ocfs2/quota_global.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/quota_global.c 2008-10-31 07:59:08.000000000 +0100 ++++ linux-2.6.27/fs/ocfs2/quota_global.c 2008-10-31 08:03:32.000000000 +0100 +@@ -418,22 +418,35 @@ + dquot->dq_dqb.dqb_curspace += spacechange; + if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags)) + dquot->dq_dqb.dqb_curinodes += inodechange; +- /* Now merge grace time changes... */ +- if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) && +- oldbtime > 0) { +- if (dquot->dq_dqb.dqb_btime > 0) +- dquot->dq_dqb.dqb_btime = ++ /* Set properly space grace time... */ ++ if (dquot->dq_dqb.dqb_bsoftlimit && ++ dquot->dq_dqb.dqb_curspace > dquot->dq_dqb.dqb_bsoftlimit) { ++ if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) && ++ oldbtime > 0) { ++ if (dquot->dq_dqb.dqb_btime > 0) ++ dquot->dq_dqb.dqb_btime = + min(dquot->dq_dqb.dqb_btime, oldbtime); +- else +- dquot->dq_dqb.dqb_btime = oldbtime; +- } +- if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) && +- olditime > 0) { +- if (dquot->dq_dqb.dqb_itime > 0) +- dquot->dq_dqb.dqb_itime = ++ else ++ dquot->dq_dqb.dqb_btime = oldbtime; ++ } ++ } else { ++ dquot->dq_dqb.dqb_btime = 0; ++ clear_bit(DQ_BLKS_B, &dquot->dq_flags); ++ } ++ /* Set properly inode grace time... */ ++ if (dquot->dq_dqb.dqb_isoftlimit && ++ dquot->dq_dqb.dqb_curinodes > dquot->dq_dqb.dqb_isoftlimit) { ++ if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) && ++ olditime > 0) { ++ if (dquot->dq_dqb.dqb_itime > 0) ++ dquot->dq_dqb.dqb_itime = + min(dquot->dq_dqb.dqb_itime, olditime); +- else +- dquot->dq_dqb.dqb_itime = olditime; ++ else ++ dquot->dq_dqb.dqb_itime = olditime; ++ } ++ } else { ++ dquot->dq_dqb.dqb_itime = 0; ++ clear_bit(DQ_INODES_B, &dquot->dq_flags); + } + /* All information is properly updated, clear the flags */ + __clear_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-hang-in-quota-recovery-code.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-hang-in-quota-recovery-code.patch new file mode 100644 index 000000000..a24bfec2f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-hang-in-quota-recovery-code.patch @@ -0,0 +1,59 @@ +From: Jan Kara +References: fate#302681 +Subject: ocfs2: Fix hang in quota recovery code +Patch-mainline: 2.6.29? + +It could happen that some node started using a recovered slot before we got to +quota recovery on it and it crashed. Recovery thread would then hang waiting +for quota file lock which could never be obtained because it first has to be +recovered by the recovery thread. We move ocfs2_begin_quota_recovery() +under super block cluster lock so no node can start using recovered slot before +we start quota recovery on it. + +Signed-off-by: Jan Kara + +--- + fs/ocfs2/journal.c | 4 ++-- + fs/ocfs2/quota_local.c | 11 ++--------- + 2 files changed, 4 insertions(+), 11 deletions(-) + +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -1127,8 +1127,6 @@ skip_recovery: + if (status < 0) + mlog_errno(status); + +- ocfs2_super_unlock(osb, 1); +- + /* Now it is right time to recover quotas... */ + for (i = 0; i < rm_quota_used; i++) { + qrec = ocfs2_begin_quota_recovery(osb, rm_quota[i]); +@@ -1141,6 +1139,8 @@ skip_recovery: + NULL, NULL, qrec); + } + ++ ocfs2_super_unlock(osb, 1); ++ + /* We always run recovery on our own orphan dir - the dead + * node(s) may have disallowd a previos inode delete. Re-processing + * is therefore required. */ +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -383,15 +383,8 @@ struct ocfs2_quota_recovery *ocfs2_begin + goto out; + } + status = ocfs2_inode_lock_full(lqinode, NULL, 1, +- OCFS2_META_LOCK_NOQUEUE); +- /* Someone else is holding the lock? Then he must be +- * doing the recovery. Just skip the file... */ +- if (status == -EAGAIN) { +- mlog(ML_NOTICE, "skipping quota recovery for slot %d " +- "because quota file is locked.\n", slot_num); +- status = 0; +- goto out_put; +- } else if (status < 0) { ++ OCFS2_META_LOCK_RECOVERY); ++ if (status < 0) { + mlog_errno(status); + goto out_put; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-mount-cleanup-after-quota-failure.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-mount-cleanup-after-quota-failure.patch new file mode 100644 index 000000000..a6b86f53f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-mount-cleanup-after-quota-failure.patch @@ -0,0 +1,31 @@ +From: Jan Kara +References: fate#302681 +Subject: ocfs2: Fix mount cleanup after quota failure +Patch-mainline: 2.6.29? + +When we fail to initialize quotas during mount, the kernel oopses because +we tried to clean-up superblock twice. + +Signed-off-by: Jan Kara + +--- + fs/ocfs2/super.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -969,8 +969,13 @@ static int ocfs2_fill_super(struct super + if (!(sb->s_flags & MS_RDONLY)) { + status = ocfs2_enable_quotas(osb); + if (status < 0) { ++ /* We have to err-out specially here because ++ * s_root is already set */ + mlog_errno(status); +- goto read_super_error; ++ atomic_set(&osb->vol_state, VOLUME_DISABLED); ++ wake_up(&osb->osb_mount_event); ++ mlog_exit(status); ++ return status; + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-oop-in-recovery-without-quotas b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-oop-in-recovery-without-quotas new file mode 100644 index 000000000..71697281c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-oop-in-recovery-without-quotas @@ -0,0 +1,38 @@ +From: Jan Kara +References: fate#302681 +Subject: ocfs2: Fix recovery of nodes when quota feature is disabled +Patch-mainline: 2.6.29? + +When quota feature is disabled, uninitialized content of variable status got +passed up from ocfs2_begin_quota_recovery() which could then cause problems, +even more so because we queued quota recovery structure even when pointer +was invalid. + +Signed-off-by: Jan Kara + +--- + fs/ocfs2/journal.c | 1 + + fs/ocfs2/quota_local.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -1135,6 +1135,7 @@ skip_recovery: + if (IS_ERR(qrec)) { + status = PTR_ERR(qrec); + mlog_errno(status); ++ continue; + } + ocfs2_queue_recovery_completion(osb->journal, rm_quota[i], + NULL, NULL, qrec); +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -365,7 +365,7 @@ struct ocfs2_quota_recovery *ocfs2_begin + struct inode *lqinode; + struct buffer_head *bh; + int type; +- int status; ++ int status = 0; + struct ocfs2_quota_recovery *rec; + + mlog(ML_NOTICE, "Beginning quota recovery in slot %u\n", slot_num); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-oops-when-one-quotatype-enabled b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-oops-when-one-quotatype-enabled new file mode 100644 index 000000000..5f8cd7477 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Fix-oops-when-one-quotatype-enabled @@ -0,0 +1,41 @@ +From: Jan Kara +References: fate#302681 +Subject: ocfs2: Fix oops when only usrquota or grpquota feature is enabled +Patch-mainline: 2.6.29? + +This patch fixes oops when only usrquota or grpquota feature is enabled on the +filesystem. We should not look at quota info header when it does not exist... + +Signed-off-by: Jan Kara + +Index: linux-2.6.27/fs/ocfs2/quota_global.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/quota_global.c 2008-11-20 21:11:35.000000000 +0100 ++++ linux-2.6.27/fs/ocfs2/quota_global.c 2008-11-20 21:45:26.000000000 +0100 +@@ -768,6 +768,8 @@ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (type != -1 && cnt != type) + continue; ++ if (!sb_has_quota_active(sb, cnt)) ++ continue; + oinfo = sb_dqinfo(sb, cnt)->dqi_priv; + status = ocfs2_lock_global_qf(oinfo, 0); + if (status < 0) +@@ -836,6 +838,8 @@ + struct ocfs2_mem_dqinfo *oinfo; + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (!sb_has_quota_active(sb, cnt)) ++ continue; + oinfo = sb_dqinfo(sb, cnt)->dqi_priv; + status = ocfs2_lock_global_qf(oinfo, 1); + if (status < 0) +@@ -873,6 +877,8 @@ + + mlog_entry_void(); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (!sb_has_quota_active(sb, cnt)) ++ continue; + oinfo = sb_dqinfo(sb, cnt)->dqi_priv; + status = ocfs2_lock_global_qf(oinfo, 0); + if (status < 0) diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implement-quota-recovery.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implement-quota-recovery.patch new file mode 100644 index 000000000..8370cb2cb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implement-quota-recovery.patch @@ -0,0 +1,819 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 28/28] ocfs2: Implement quota recovery +Patch-mainline: 2.6.29? + +Implement functions for recovery after a crash. Functions just +read local quota file and sync info to global quota file. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/journal.c | 103 +++++++++-- + fs/ocfs2/journal.h | 1 + fs/ocfs2/ocfs2.h | 4 + fs/ocfs2/quota.h | 21 ++ + fs/ocfs2/quota_local.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++++- + fs/ocfs2/super.c | 3 + 6 files changed, 530 insertions(+), 30 deletions(-) + +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -45,6 +45,7 @@ + #include "slot_map.h" + #include "super.h" + #include "sysfile.h" ++#include "quota.h" + + #include "buffer_head_io.h" + +@@ -52,7 +53,7 @@ DEFINE_SPINLOCK(trans_inc_lock); + + static int ocfs2_force_read_journal(struct inode *inode); + static int ocfs2_recover_node(struct ocfs2_super *osb, +- int node_num); ++ int node_num, int slot_num); + static int __ocfs2_recovery_thread(void *arg); + static int ocfs2_commit_cache(struct ocfs2_super *osb); + static int __ocfs2_wait_on_mount(struct ocfs2_super *osb, int quota); +@@ -889,6 +890,7 @@ struct ocfs2_la_recovery_item { + int lri_slot; + struct ocfs2_dinode *lri_la_dinode; + struct ocfs2_dinode *lri_tl_dinode; ++ struct ocfs2_quota_recovery *lri_qrec; + }; + + /* Does the second half of the recovery process. By this point, the +@@ -909,6 +911,7 @@ void ocfs2_complete_recovery(struct work + struct ocfs2_super *osb = journal->j_osb; + struct ocfs2_dinode *la_dinode, *tl_dinode; + struct ocfs2_la_recovery_item *item, *n; ++ struct ocfs2_quota_recovery *qrec; + LIST_HEAD(tmp_la_list); + + mlog_entry_void(); +@@ -956,6 +959,16 @@ void ocfs2_complete_recovery(struct work + if (ret < 0) + mlog_errno(ret); + ++ qrec = item->lri_qrec; ++ if (qrec) { ++ mlog(0, "Recovering quota files"); ++ ret = ocfs2_finish_quota_recovery(osb, qrec, ++ item->lri_slot); ++ if (ret < 0) ++ mlog_errno(ret); ++ /* Recovery info is already freed now */ ++ } ++ + kfree(item); + } + +@@ -969,7 +982,8 @@ void ocfs2_complete_recovery(struct work + static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal, + int slot_num, + struct ocfs2_dinode *la_dinode, +- struct ocfs2_dinode *tl_dinode) ++ struct ocfs2_dinode *tl_dinode, ++ struct ocfs2_quota_recovery *qrec) + { + struct ocfs2_la_recovery_item *item; + +@@ -984,6 +998,9 @@ static void ocfs2_queue_recovery_complet + if (tl_dinode) + kfree(tl_dinode); + ++ if (qrec) ++ ocfs2_free_quota_recovery(qrec); ++ + mlog_errno(-ENOMEM); + return; + } +@@ -992,6 +1009,7 @@ static void ocfs2_queue_recovery_complet + item->lri_la_dinode = la_dinode; + item->lri_slot = slot_num; + item->lri_tl_dinode = tl_dinode; ++ item->lri_qrec = qrec; + + spin_lock(&journal->j_lock); + list_add_tail(&item->lri_list, &journal->j_la_cleanups); +@@ -1011,6 +1029,7 @@ void ocfs2_complete_mount_recovery(struc + ocfs2_queue_recovery_completion(journal, + osb->slot_num, + osb->local_alloc_copy, ++ NULL, + NULL); + ocfs2_schedule_truncate_log_flush(osb, 0); + +@@ -1019,11 +1038,26 @@ void ocfs2_complete_mount_recovery(struc + } + } + ++void ocfs2_complete_quota_recovery(struct ocfs2_super *osb) ++{ ++ if (osb->quota_rec) { ++ ocfs2_queue_recovery_completion(osb->journal, ++ osb->slot_num, ++ NULL, ++ NULL, ++ osb->quota_rec); ++ osb->quota_rec = NULL; ++ } ++} ++ + static int __ocfs2_recovery_thread(void *arg) + { +- int status, node_num; ++ int status, node_num, slot_num; + struct ocfs2_super *osb = arg; + struct ocfs2_recovery_map *rm = osb->recovery_map; ++ int *rm_quota = NULL; ++ int rm_quota_used = 0, i; ++ struct ocfs2_quota_recovery *qrec; + + mlog_entry_void(); + +@@ -1032,6 +1066,11 @@ static int __ocfs2_recovery_thread(void + goto bail; + } + ++ rm_quota = kzalloc(osb->max_slots * sizeof(int), GFP_NOFS); ++ if (!rm_quota) { ++ status = -ENOMEM; ++ goto bail; ++ } + restart: + status = ocfs2_super_lock(osb, 1); + if (status < 0) { +@@ -1045,8 +1084,28 @@ restart: + * clear it until ocfs2_recover_node() has succeeded. */ + node_num = rm->rm_entries[0]; + spin_unlock(&osb->osb_lock); ++ mlog(0, "checking node %d\n", node_num); ++ slot_num = ocfs2_node_num_to_slot(osb, node_num); ++ if (slot_num == -ENOENT) { ++ status = 0; ++ mlog(0, "no slot for this node, so no recovery" ++ "required.\n"); ++ goto skip_recovery; ++ } ++ mlog(0, "node %d was using slot %d\n", node_num, slot_num); + +- status = ocfs2_recover_node(osb, node_num); ++ /* It is a bit subtle with quota recovery. We cannot do it ++ * immediately because we have to obtain cluster locks from ++ * quota files and we also don't want to just skip it because ++ * then quota usage would be out of sync until some node takes ++ * the slot. So we remember which nodes need quota recovery ++ * and when everything else is done, we recover quotas. */ ++ for (i = 0; i < rm_quota_used && rm_quota[i] != slot_num; i++); ++ if (i == rm_quota_used) ++ rm_quota[rm_quota_used++] = slot_num; ++ ++ status = ocfs2_recover_node(osb, node_num, slot_num); ++skip_recovery: + if (!status) { + ocfs2_recovery_map_clear(osb, node_num); + } else { +@@ -1070,11 +1129,22 @@ restart: + + ocfs2_super_unlock(osb, 1); + ++ /* Now it is right time to recover quotas... */ ++ for (i = 0; i < rm_quota_used; i++) { ++ qrec = ocfs2_begin_quota_recovery(osb, rm_quota[i]); ++ if (IS_ERR(qrec)) { ++ status = PTR_ERR(qrec); ++ mlog_errno(status); ++ } ++ ocfs2_queue_recovery_completion(osb->journal, rm_quota[i], ++ NULL, NULL, qrec); ++ } ++ + /* We always run recovery on our own orphan dir - the dead + * node(s) may have disallowd a previos inode delete. Re-processing + * is therefore required. */ + ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL, +- NULL); ++ NULL, NULL); + + bail: + mutex_lock(&osb->recovery_lock); +@@ -1089,6 +1159,9 @@ bail: + + mutex_unlock(&osb->recovery_lock); + ++ if (rm_quota) ++ kfree(rm_quota); ++ + mlog_exit(status); + /* no one is callint kthread_stop() for us so the kthread() api + * requires that we call do_exit(). And it isn't exported, but +@@ -1317,31 +1390,19 @@ done: + * far less concerning. + */ + static int ocfs2_recover_node(struct ocfs2_super *osb, +- int node_num) ++ int node_num, int slot_num) + { + int status = 0; +- int slot_num; + struct ocfs2_dinode *la_copy = NULL; + struct ocfs2_dinode *tl_copy = NULL; + +- mlog_entry("(node_num=%d, osb->node_num = %d)\n", +- node_num, osb->node_num); +- +- mlog(0, "checking node %d\n", node_num); ++ mlog_entry("(node_num=%d, slot_num=%d, osb->node_num = %d)\n", ++ node_num, slot_num, osb->node_num); + + /* Should not ever be called to recover ourselves -- in that + * case we should've called ocfs2_journal_load instead. */ + BUG_ON(osb->node_num == node_num); + +- slot_num = ocfs2_node_num_to_slot(osb, node_num); +- if (slot_num == -ENOENT) { +- status = 0; +- mlog(0, "no slot for this node, so no recovery required.\n"); +- goto done; +- } +- +- mlog(0, "node %d was using slot %d\n", node_num, slot_num); +- + status = ocfs2_replay_journal(osb, node_num, slot_num); + if (status < 0) { + if (status == -EBUSY) { +@@ -1377,7 +1438,7 @@ static int ocfs2_recover_node(struct ocf + + /* This will kfree the memory pointed to by la_copy and tl_copy */ + ocfs2_queue_recovery_completion(osb->journal, slot_num, la_copy, +- tl_copy); ++ tl_copy, NULL); + + status = 0; + done: +--- a/fs/ocfs2/journal.h ++++ b/fs/ocfs2/journal.h +@@ -173,6 +173,7 @@ void ocfs2_recovery_thread(struct ocfs + int node_num); + int ocfs2_mark_dead_nodes(struct ocfs2_super *osb); + void ocfs2_complete_mount_recovery(struct ocfs2_super *osb); ++void ocfs2_complete_quota_recovery(struct ocfs2_super *osb); + + static inline void ocfs2_start_checkpoint(struct ocfs2_super *osb) + { +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -209,6 +209,7 @@ enum ocfs2_mount_options + struct ocfs2_journal; + struct ocfs2_slot_info; + struct ocfs2_recovery_map; ++struct ocfs2_quota_recovery; + struct ocfs2_super + { + struct task_struct *commit_task; +@@ -290,10 +291,11 @@ struct ocfs2_super + char *local_alloc_debug_buf; + #endif + +- /* Next two fields are for local node slot recovery during ++ /* Next three fields are for local node slot recovery during + * mount. */ + int dirty; + struct ocfs2_dinode *local_alloc_copy; ++ struct ocfs2_quota_recovery *quota_rec; + + struct ocfs2_alloc_stats alloc_stats; + char dev_str[20]; /* "major,minor" of the device */ +--- a/fs/ocfs2/quota.h ++++ b/fs/ocfs2/quota.h +@@ -38,6 +38,17 @@ struct ocfs2_dquot { + s64 dq_originodes; /* Last globally synced inode usage */ + }; + ++/* Description of one chunk to recover in memory */ ++struct ocfs2_recovery_chunk { ++ struct list_head rc_list; /* List of chunks */ ++ int rc_chunk; /* Chunk number */ ++ unsigned long *rc_bitmap; /* Bitmap of entries to recover */ ++}; ++ ++struct ocfs2_quota_recovery { ++ struct list_head r_list[MAXQUOTAS]; /* List of chunks to recover */ ++}; ++ + /* In-memory structure with quota header information */ + struct ocfs2_mem_dqinfo { + unsigned int dqi_type; /* Quota type this structure describes */ +@@ -54,6 +65,10 @@ struct ocfs2_mem_dqinfo { + struct buffer_head *dqi_ibh; /* Buffer with information header */ + struct qtree_mem_dqinfo dqi_gi; /* Info about global file */ + struct timer_list dqi_sync_timer; /* Timer for syncing dquots */ ++ struct ocfs2_quota_recovery *dqi_rec; /* Pointer to recovery ++ * information, in case we ++ * enable quotas on file ++ * needing it */ + }; + + static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot) +@@ -72,6 +87,12 @@ extern struct kmem_cache *ocfs2_qf_chunk + + extern struct qtree_fmt_operations ocfs2_global_ops; + ++struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( ++ struct ocfs2_super *osb, int slot_num); ++int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, ++ struct ocfs2_quota_recovery *rec, ++ int slot_num); ++void ocfs2_free_quota_recovery(struct ocfs2_quota_recovery *rec); + ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data, + size_t len, loff_t off); + ssize_t ocfs2_quota_write(struct super_block *sb, int type, +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -49,14 +49,25 @@ static unsigned int ol_quota_chunk_block + return 1 + (ol_chunk_blocks(sb) + 1) * c; + } + +-/* Offset of the dquot structure in the quota file */ +-static loff_t ol_dqblk_off(struct super_block *sb, int c, int off) ++static unsigned int ol_dqblk_block(struct super_block *sb, int c, int off) ++{ ++ int epb = ol_quota_entries_per_block(sb); ++ ++ return ol_quota_chunk_block(sb, c) + 1 + off / epb; ++} ++ ++static unsigned int ol_dqblk_block_off(struct super_block *sb, int c, int off) + { + int epb = ol_quota_entries_per_block(sb); + +- return ((ol_quota_chunk_block(sb, c) + 1 + off / epb) +- << sb->s_blocksize_bits) + +- (off % epb) * sizeof(struct ocfs2_local_disk_dqblk); ++ return (off % epb) * sizeof(struct ocfs2_local_disk_dqblk); ++} ++ ++/* Offset of the dquot structure in the quota file */ ++static loff_t ol_dqblk_off(struct super_block *sb, int c, int off) ++{ ++ return (ol_dqblk_block(sb, c, off) << sb->s_blocksize_bits) + ++ ol_dqblk_block_off(sb, c, off); + } + + /* Compute block number from given offset */ +@@ -253,6 +264,382 @@ static void olq_update_info(struct buffe + spin_unlock(&dq_data_lock); + } + ++static int ocfs2_add_recovery_chunk(struct super_block *sb, ++ struct ocfs2_local_disk_chunk *dchunk, ++ int chunk, ++ struct list_head *head) ++{ ++ struct ocfs2_recovery_chunk *rc; ++ ++ rc = kmalloc(sizeof(struct ocfs2_recovery_chunk), GFP_NOFS); ++ if (!rc) ++ return -ENOMEM; ++ rc->rc_chunk = chunk; ++ rc->rc_bitmap = kmalloc(sb->s_blocksize, GFP_NOFS); ++ if (!rc->rc_bitmap) { ++ kfree(rc); ++ return -ENOMEM; ++ } ++ memcpy(rc->rc_bitmap, dchunk->dqc_bitmap, ++ (ol_chunk_entries(sb) + 7) >> 3); ++ list_add_tail(&rc->rc_list, head); ++ return 0; ++} ++ ++static void free_recovery_list(struct list_head *head) ++{ ++ struct ocfs2_recovery_chunk *next; ++ struct ocfs2_recovery_chunk *rchunk; ++ ++ list_for_each_entry_safe(rchunk, next, head, rc_list) { ++ list_del(&rchunk->rc_list); ++ kfree(rchunk->rc_bitmap); ++ kfree(rchunk); ++ } ++} ++ ++void ocfs2_free_quota_recovery(struct ocfs2_quota_recovery *rec) ++{ ++ int type; ++ ++ for (type = 0; type < MAXQUOTAS; type++) ++ free_recovery_list(&(rec->r_list[type])); ++ kfree(rec); ++} ++ ++/* Load entries in our quota file we have to recover*/ ++static int ocfs2_recovery_load_quota(struct inode *lqinode, ++ struct ocfs2_local_disk_dqinfo *ldinfo, ++ int type, ++ struct list_head *head) ++{ ++ struct super_block *sb = lqinode->i_sb; ++ struct buffer_head *hbh; ++ struct ocfs2_local_disk_chunk *dchunk; ++ int i, chunks = le32_to_cpu(ldinfo->dqi_chunks); ++ int status = 0; ++ ++ for (i = 0; i < chunks; i++) { ++ hbh = ocfs2_bread(lqinode, ol_quota_chunk_block(sb, i), ++ &status, 0); ++ if (!hbh) { ++ mlog_errno(status); ++ break; ++ } ++ dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data; ++ if (le32_to_cpu(dchunk->dqc_free) < ol_chunk_entries(sb)) ++ status = ocfs2_add_recovery_chunk(sb, dchunk, i, head); ++ brelse(hbh); ++ if (status < 0) ++ break; ++ } ++ if (status < 0) ++ free_recovery_list(head); ++ return status; ++} ++ ++static struct ocfs2_quota_recovery *ocfs2_alloc_quota_recovery(void) ++{ ++ int type; ++ struct ocfs2_quota_recovery *rec; ++ ++ rec = kmalloc(sizeof(struct ocfs2_quota_recovery), GFP_NOFS); ++ if (!rec) ++ return NULL; ++ for (type = 0; type < MAXQUOTAS; type++) ++ INIT_LIST_HEAD(&(rec->r_list[type])); ++ return rec; ++} ++ ++/* Load information we need for quota recovery into memory */ ++struct ocfs2_quota_recovery *ocfs2_begin_quota_recovery( ++ struct ocfs2_super *osb, ++ int slot_num) ++{ ++ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; ++ unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, ++ LOCAL_GROUP_QUOTA_SYSTEM_INODE }; ++ struct super_block *sb = osb->sb; ++ struct ocfs2_local_disk_dqinfo *ldinfo; ++ struct inode *lqinode; ++ struct buffer_head *bh; ++ int type; ++ int status; ++ struct ocfs2_quota_recovery *rec; ++ ++ mlog(ML_NOTICE, "Beginning quota recovery in slot %u\n", slot_num); ++ rec = ocfs2_alloc_quota_recovery(); ++ if (!rec) ++ return ERR_PTR(-ENOMEM); ++ /* First init... */ ++ ++ for (type = 0; type < MAXQUOTAS; type++) { ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) ++ continue; ++ lqinode = ocfs2_get_system_file_inode(osb, ino[type], slot_num); ++ if (!lqinode) { ++ status = -ENOENT; ++ goto out; ++ } ++ status = ocfs2_inode_lock_full(lqinode, NULL, 1, ++ OCFS2_META_LOCK_NOQUEUE); ++ /* Someone else is holding the lock? Then he must be ++ * doing the recovery. Just skip the file... */ ++ if (status == -EAGAIN) { ++ mlog(ML_NOTICE, "skipping quota recovery for slot %d " ++ "because quota file is locked.\n", slot_num); ++ status = 0; ++ goto out_put; ++ } else if (status < 0) { ++ mlog_errno(status); ++ goto out_put; ++ } ++ /* Now read local header */ ++ bh = ocfs2_bread(lqinode, 0, &status, 0); ++ if (!bh) { ++ mlog_errno(status); ++ mlog(ML_ERROR, "failed to read quota file info header " ++ "(slot=%d type=%d)\n", slot_num, type); ++ goto out_lock; ++ } ++ ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data + ++ OCFS2_LOCAL_INFO_OFF); ++ status = ocfs2_recovery_load_quota(lqinode, ldinfo, type, ++ &rec->r_list[type]); ++ brelse(bh); ++out_lock: ++ ocfs2_inode_unlock(lqinode, 1); ++out_put: ++ iput(lqinode); ++ if (status < 0) ++ break; ++ } ++out: ++ if (status < 0) { ++ ocfs2_free_quota_recovery(rec); ++ rec = ERR_PTR(status); ++ } ++ return rec; ++} ++ ++/* Sync changes in local quota file into global quota file and ++ * reinitialize local quota file. ++ * The function expects local quota file to be already locked and ++ * dqonoff_mutex locked. */ ++static int ocfs2_recover_local_quota_file(struct inode *lqinode, ++ int type, ++ struct ocfs2_quota_recovery *rec) ++{ ++ struct super_block *sb = lqinode->i_sb; ++ struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ struct ocfs2_local_disk_chunk *dchunk; ++ struct ocfs2_local_disk_dqblk *dqblk; ++ struct dquot *dquot; ++ handle_t *handle; ++ struct buffer_head *hbh = NULL, *qbh = NULL; ++ int status = 0; ++ int bit, chunk; ++ struct ocfs2_recovery_chunk *rchunk, *next; ++ qsize_t spacechange, inodechange; ++ ++ mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type); ++ ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ ++ list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) { ++ chunk = rchunk->rc_chunk; ++ hbh = ocfs2_bread(lqinode, ol_quota_chunk_block(sb, chunk), ++ &status, 0); ++ if (!hbh) { ++ mlog_errno(status); ++ break; ++ } ++ dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data; ++ for_each_bit(bit, rchunk->rc_bitmap, ol_chunk_entries(sb)) { ++ qbh = ocfs2_bread(lqinode, ++ ol_dqblk_block(sb, chunk, bit), ++ &status, 0); ++ if (!qbh) { ++ mlog_errno(status); ++ break; ++ } ++ dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data + ++ ol_dqblk_block_off(sb, chunk, bit)); ++ dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type); ++ if (!dquot) { ++ status = -EIO; ++ mlog(ML_ERROR, "Failed to get quota structure " ++ "for id %u, type %d. Cannot finish quota " ++ "file recovery.\n", ++ (unsigned)le64_to_cpu(dqblk->dqb_id), ++ type); ++ goto out_put_bh; ++ } ++ handle = ocfs2_start_trans(OCFS2_SB(sb), ++ OCFS2_QSYNC_CREDITS); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_put_dquot; ++ } ++ mutex_lock(&sb_dqopt(sb)->dqio_mutex); ++ spin_lock(&dq_data_lock); ++ /* Add usage from quota entry into quota changes ++ * of our node. Auxiliary variables are important ++ * due to signedness */ ++ spacechange = le64_to_cpu(dqblk->dqb_spacemod); ++ inodechange = le64_to_cpu(dqblk->dqb_inodemod); ++ dquot->dq_dqb.dqb_curspace += spacechange; ++ dquot->dq_dqb.dqb_curinodes += inodechange; ++ spin_unlock(&dq_data_lock); ++ /* We want to drop reference held by the crashed ++ * node. Since we have our own reference we know ++ * global structure actually won't be freed. */ ++ status = ocfs2_global_release_dquot(dquot); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_commit; ++ } ++ /* Release local quota file entry */ ++ status = ocfs2_journal_access(handle, lqinode, ++ qbh, OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_commit; ++ } ++ lock_buffer(qbh); ++ WARN_ON(!ocfs2_test_bit(bit, dchunk->dqc_bitmap)); ++ ocfs2_clear_bit(bit, dchunk->dqc_bitmap); ++ le32_add_cpu(&dchunk->dqc_free, 1); ++ unlock_buffer(qbh); ++ status = ocfs2_journal_dirty(handle, qbh); ++ if (status < 0) ++ mlog_errno(status); ++out_commit: ++ mutex_unlock(&sb_dqopt(sb)->dqio_mutex); ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++out_put_dquot: ++ dqput(dquot); ++out_put_bh: ++ brelse(qbh); ++ if (status < 0) ++ break; ++ } ++ brelse(hbh); ++ list_del(&rchunk->rc_list); ++ kfree(rchunk->rc_bitmap); ++ kfree(rchunk); ++ if (status < 0) ++ break; ++ } ++ ocfs2_unlock_global_qf(oinfo, 1); ++out: ++ if (status < 0) ++ free_recovery_list(&(rec->r_list[type])); ++ mlog_exit(status); ++ return status; ++} ++ ++/* Recover local quota files for given node different from us */ ++int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, ++ struct ocfs2_quota_recovery *rec, ++ int slot_num) ++{ ++ unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, ++ LOCAL_GROUP_QUOTA_SYSTEM_INODE }; ++ struct super_block *sb = osb->sb; ++ struct ocfs2_local_disk_dqinfo *ldinfo; ++ struct buffer_head *bh; ++ handle_t *handle; ++ int type; ++ int status = 0; ++ struct inode *lqinode; ++ unsigned int flags; ++ ++ mlog(ML_NOTICE, "Finishing quota recovery in slot %u\n", slot_num); ++ mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); ++ for (type = 0; type < MAXQUOTAS; type++) { ++ if (list_empty(&(rec->r_list[type]))) ++ continue; ++ mlog(0, "Recovering quota in slot %d\n", slot_num); ++ lqinode = ocfs2_get_system_file_inode(osb, ino[type], slot_num); ++ if (!lqinode) { ++ status = -ENOENT; ++ goto out; ++ } ++ status = ocfs2_inode_lock_full(lqinode, NULL, 1, ++ OCFS2_META_LOCK_NOQUEUE); ++ /* Someone else is holding the lock? Then he must be ++ * doing the recovery. Just skip the file... */ ++ if (status == -EAGAIN) { ++ mlog(ML_NOTICE, "skipping quota recovery for slot %d " ++ "because quota file is locked.\n", slot_num); ++ status = 0; ++ goto out_put; ++ } else if (status < 0) { ++ mlog_errno(status); ++ goto out_put; ++ } ++ /* Now read local header */ ++ bh = ocfs2_bread(lqinode, 0, &status, 0); ++ if (!bh) { ++ mlog_errno(status); ++ mlog(ML_ERROR, "failed to read quota file info header " ++ "(slot=%d type=%d)\n", slot_num, type); ++ goto out_lock; ++ } ++ ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data + ++ OCFS2_LOCAL_INFO_OFF); ++ /* Is recovery still needed? */ ++ flags = le32_to_cpu(ldinfo->dqi_flags); ++ if (!(flags & OLQF_CLEAN)) ++ status = ocfs2_recover_local_quota_file(lqinode, ++ type, ++ rec); ++ /* We don't want to mark file as clean when it is actually ++ * active */ ++ if (slot_num == osb->slot_num) ++ goto out_bh; ++ /* Mark quota file as clean if we are recovering quota file of ++ * some other node. */ ++ handle = ocfs2_start_trans(osb, 1); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_bh; ++ } ++ status = ocfs2_journal_access(handle, lqinode, bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ lock_buffer(bh); ++ ldinfo->dqi_flags = cpu_to_le32(flags | OLQF_CLEAN); ++ unlock_buffer(bh); ++ status = ocfs2_journal_dirty(handle, bh); ++ if (status < 0) ++ mlog_errno(status); ++out_trans: ++ ocfs2_commit_trans(osb, handle); ++out_bh: ++ brelse(bh); ++out_lock: ++ ocfs2_inode_unlock(lqinode, 1); ++out_put: ++ iput(lqinode); ++ if (status < 0) ++ break; ++ } ++out: ++ mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); ++ kfree(rec); ++ return status; ++} ++ + /* Read information header from quota file */ + static int ocfs2_local_read_info(struct super_block *sb, int type) + { +@@ -262,6 +649,7 @@ static int ocfs2_local_read_info(struct + struct inode *lqinode = sb_dqopt(sb)->files[type]; + int status; + struct buffer_head *bh = NULL; ++ struct ocfs2_quota_recovery *rec; + int locked = 0; + + info->dqi_maxblimit = 0x7fffffffffffffffLL; +@@ -275,6 +663,7 @@ static int ocfs2_local_read_info(struct + info->dqi_priv = oinfo; + oinfo->dqi_type = type; + INIT_LIST_HEAD(&oinfo->dqi_chunk); ++ oinfo->dqi_rec = NULL; + oinfo->dqi_lqi_bh = NULL; + oinfo->dqi_ibh = NULL; + +@@ -305,10 +694,27 @@ static int ocfs2_local_read_info(struct + oinfo->dqi_ibh = bh; + + /* We crashed when using local quota file? */ +- if (!(info->dqi_flags & OLQF_CLEAN)) +- goto out_err; /* So far we just bail out. Later we should resync here */ ++ if (!(info->dqi_flags & OLQF_CLEAN)) { ++ rec = OCFS2_SB(sb)->quota_rec; ++ if (!rec) { ++ rec = ocfs2_alloc_quota_recovery(); ++ if (!rec) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto out_err; ++ } ++ OCFS2_SB(sb)->quota_rec = rec; ++ } + +- status = ocfs2_load_local_quota_bitmaps(sb_dqopt(sb)->files[type], ++ status = ocfs2_recovery_load_quota(lqinode, ldinfo, type, ++ &rec->r_list[type]); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ } ++ ++ status = ocfs2_load_local_quota_bitmaps(lqinode, + ldinfo, + &oinfo->dqi_chunk); + if (status < 0) { +@@ -394,6 +800,12 @@ static int ocfs2_local_free_info(struct + } + ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); + ++ /* dqonoff_mutex protects us against racing with recovery thread... */ ++ if (oinfo->dqi_rec) { ++ ocfs2_free_quota_recovery(oinfo->dqi_rec); ++ mark_clean = 0; ++ } ++ + if (!mark_clean) + goto out; + +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -973,6 +973,9 @@ static int ocfs2_fill_super(struct super + goto read_super_error; + } + } ++ ++ ocfs2_complete_quota_recovery(osb); ++ + /* Now we wake up again for processes waiting for quotas */ + atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); + wake_up(&osb->osb_mount_event); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implement-quota-syncing-thread.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implement-quota-syncing-thread.patch new file mode 100644 index 000000000..eda2413e0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implement-quota-syncing-thread.patch @@ -0,0 +1,177 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 27/28] ocfs2: Implement quota syncing thread +Patch-mainline: 2.6.29? + +This patch implements functions and timer setup which handles periodic +syncing of locally cached quota information to global quota file. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/quota.h | 3 ++ + fs/ocfs2/quota_global.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/quota_local.c | 4 ++ + mm/pdflush.c | 1 + 4 files changed, 79 insertions(+) + +--- a/fs/ocfs2/quota.h ++++ b/fs/ocfs2/quota.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include "ocfs2.h" + +@@ -43,6 +44,7 @@ struct ocfs2_mem_dqinfo { + unsigned int dqi_chunks; /* Number of chunks in local quota file */ + unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */ + unsigned int dqi_syncms; /* How often should we sync with other nodes */ ++ unsigned int dqi_syncjiff; /* Precomputed dqi_syncms in jiffies */ + struct list_head dqi_chunk; /* List of chunks */ + struct inode *dqi_gqinode; /* Global quota file inode */ + struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */ +@@ -51,6 +53,7 @@ struct ocfs2_mem_dqinfo { + struct buffer_head *dqi_lqi_bh; /* Buffer head with local quota file inode */ + struct buffer_head *dqi_ibh; /* Buffer with information header */ + struct qtree_mem_dqinfo dqi_gi; /* Info about global file */ ++ struct timer_list dqi_sync_timer; /* Timer for syncing dquots */ + }; + + static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot) +--- a/fs/ocfs2/quota_global.c ++++ b/fs/ocfs2/quota_global.c +@@ -1,10 +1,14 @@ + /* + * Implementation of operations over global quota file + */ ++#include + #include + #include + #include + #include ++#include ++#include ++#include + + #define MLOG_MASK_PREFIX ML_QUOTA + #include +@@ -19,6 +23,8 @@ + #include "dlmglue.h" + #include "quota.h" + ++static void qsync_timer_fn(unsigned long oinfo_ptr); ++ + static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp) + { + struct ocfs2_global_disk_dqblk *d = dp; +@@ -269,6 +275,7 @@ int ocfs2_global_read_info(struct super_ + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); ++ oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms); + oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); + oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); + oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); +@@ -276,6 +283,10 @@ int ocfs2_global_read_info(struct super_ + oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize - + OCFS2_QBLK_RESERVED_SPACE; + oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi); ++ setup_timer(&oinfo->dqi_sync_timer, qsync_timer_fn, ++ (unsigned long)oinfo); ++ mod_timer(&oinfo->dqi_sync_timer, ++ round_jiffies(jiffies + oinfo->dqi_syncjiff)); + out_err: + mlog_exit(status); + return status; +@@ -463,6 +474,66 @@ out: + } + + /* ++ * Functions for periodic syncing of dquots with global file ++ */ ++static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type) ++{ ++ handle_t *handle; ++ struct super_block *sb = dquot->dq_sb; ++ struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ struct ocfs2_super *osb = OCFS2_SB(sb); ++ int status = 0; ++ ++ mlog_entry("id=%u qtype=%u type=%lu device=%s\n", dquot->dq_id, ++ dquot->dq_type, type, sb->s_id); ++ if (type != dquot->dq_type) ++ goto out; ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ ++ handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ mutex_lock(&sb_dqopt(sb)->dqio_mutex); ++ status = ocfs2_sync_dquot(dquot); ++ mutex_unlock(&sb_dqopt(sb)->dqio_mutex); ++ if (status < 0) ++ mlog_errno(status); ++ /* We have to write local structure as well... */ ++ dquot_mark_dquot_dirty(dquot); ++ status = dquot_commit(dquot); ++ if (status < 0) ++ mlog_errno(status); ++ ocfs2_commit_trans(osb, handle); ++out_ilock: ++ ocfs2_unlock_global_qf(oinfo, 1); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++static void ocfs2_do_qsync(unsigned long oinfo_ptr) ++{ ++ struct ocfs2_mem_dqinfo *oinfo = (struct ocfs2_mem_dqinfo *)oinfo_ptr; ++ struct super_block *sb = oinfo->dqi_gqinode->i_sb; ++ ++ dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type); ++} ++ ++static void qsync_timer_fn(unsigned long oinfo_ptr) ++{ ++ struct ocfs2_mem_dqinfo *oinfo = (struct ocfs2_mem_dqinfo *)oinfo_ptr; ++ ++ pdflush_operation(ocfs2_do_qsync, oinfo_ptr); ++ mod_timer(&oinfo->dqi_sync_timer, ++ round_jiffies(jiffies + oinfo->dqi_syncjiff)); ++} ++ ++/* + * Wrappers for generic quota functions + */ + +--- a/fs/ocfs2/quota_local.c ++++ b/fs/ocfs2/quota_local.c +@@ -368,6 +368,10 @@ static int ocfs2_local_free_info(struct + int mark_clean = 1, len; + int status; + ++ /* At this point we know there are no more dquots and thus ++ * even if there's some sync in the pdflush queue, it won't ++ * find any dquots and return without doing anything */ ++ del_timer_sync(&oinfo->dqi_sync_timer); + iput(oinfo->dqi_gqinode); + ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock); + ocfs2_lock_res_free(&oinfo->dqi_gqlock); +--- a/mm/pdflush.c ++++ b/mm/pdflush.c +@@ -225,6 +225,7 @@ int pdflush_operation(void (*fn)(unsigne + + return ret; + } ++EXPORT_SYMBOL(pdflush_operation); + + static void start_one_pdflush_thread(void) + { diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implementation-of-local-and-global-quota-file.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implementation-of-local-and-global-quota-file.patch new file mode 100644 index 000000000..bfb1679dd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Implementation-of-local-and-global-quota-file.patch @@ -0,0 +1,2453 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 24/28] ocfs2: Implementation of local and global quota file handling +Patch-mainline: 2.6.29? + +For each quota type each node has local quota file. In this file it stores +changes users have made to disk usage via this node. Once in a while this +information is synced to global file (and thus with other nodes) so that +limits enforcement at least aproximately works. + +Global quota files contain all the information about usage and limits. It's +mostly handled by the generic VFS code (which implements a trie of structures +inside a quota file). We only have to provide functions to convert structures +from on-disk format to in-memory one. We also have to provide wrappers for +various quota functions starting transactions and acquiring necessary cluster +locks before the actual IO is really started. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/Makefile | 2 + + fs/ocfs2/cluster/masklog.h | 1 + + fs/ocfs2/dlmglue.c | 137 +++++++ + fs/ocfs2/dlmglue.h | 17 + + fs/ocfs2/file.c | 6 +- + fs/ocfs2/file.h | 4 + + fs/ocfs2/journal.h | 15 + + fs/ocfs2/ocfs2_fs.h | 95 +++++ + fs/ocfs2/ocfs2_lockid.h | 5 + + fs/ocfs2/quota.h | 94 +++++ + fs/ocfs2/quota_global.c | 855 ++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/quota_local.c | 846 +++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/super.c | 35 ++- + 13 files changed, 2107 insertions(+), 5 deletions(-) + create mode 100644 fs/ocfs2/quota.h + create mode 100644 fs/ocfs2/quota_global.c + create mode 100644 fs/ocfs2/quota_local.c + +Index: linux-2.6.27-ocfs2/fs/ocfs2/Makefile +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/Makefile ++++ linux-2.6.27-ocfs2/fs/ocfs2/Makefile +@@ -35,6 +35,8 @@ ocfs2-objs := \ + sysfile.o \ + uptodate.o \ + ver.o \ ++ quota_local.o \ ++ quota_global.o \ + xattr.o + + ifeq ($(CONFIG_OCFS2_FS_POSIX_ACL),y) +Index: linux-2.6.27-ocfs2/fs/ocfs2/cluster/masklog.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/cluster/masklog.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/cluster/masklog.h +@@ -113,6 +113,7 @@ + #define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */ + #define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */ + #define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */ ++#define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */ + /* bits that are infrequently given and frequently matched in the high word */ + #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ + #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ +Index: linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlmglue.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_DLM_GLUE + #include +@@ -51,6 +52,7 @@ + #include "slot_map.h" + #include "super.h" + #include "uptodate.h" ++#include "quota.h" + + #include "buffer_head_io.h" + +@@ -68,6 +70,7 @@ struct ocfs2_mask_waiter { + static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres); + static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres); + static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres); ++static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres); + + /* + * Return value from ->downconvert_worker functions. +@@ -102,6 +105,7 @@ static int ocfs2_dentry_convert_worker(s + static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb, + struct ocfs2_lock_res *lockres); + ++static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres); + + #define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres) + +@@ -258,6 +262,12 @@ static struct ocfs2_lock_res_ops ocfs2_f + .flags = 0, + }; + ++static struct ocfs2_lock_res_ops ocfs2_qinfo_lops = { ++ .set_lvb = ocfs2_set_qinfo_lvb, ++ .get_osb = ocfs2_get_qinfo_osb, ++ .flags = LOCK_TYPE_REQUIRES_REFRESH | LOCK_TYPE_USES_LVB, ++}; ++ + static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) + { + return lockres->l_type == OCFS2_LOCK_TYPE_META || +@@ -279,6 +289,13 @@ static inline struct ocfs2_dentry_lock * + return (struct ocfs2_dentry_lock *)lockres->l_priv; + } + ++static inline struct ocfs2_mem_dqinfo *ocfs2_lock_res_qinfo(struct ocfs2_lock_res *lockres) ++{ ++ BUG_ON(lockres->l_type != OCFS2_LOCK_TYPE_QINFO); ++ ++ return (struct ocfs2_mem_dqinfo *)lockres->l_priv; ++} ++ + static inline struct ocfs2_super *ocfs2_get_lockres_osb(struct ocfs2_lock_res *lockres) + { + if (lockres->l_ops->get_osb) +@@ -507,6 +524,13 @@ static struct ocfs2_super *ocfs2_get_ino + return OCFS2_SB(inode->i_sb); + } + ++static struct ocfs2_super *ocfs2_get_qinfo_osb(struct ocfs2_lock_res *lockres) ++{ ++ struct ocfs2_mem_dqinfo *info = lockres->l_priv; ++ ++ return OCFS2_SB(info->dqi_gi.dqi_sb); ++} ++ + static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres) + { + struct ocfs2_file_private *fp = lockres->l_priv; +@@ -609,6 +633,17 @@ void ocfs2_file_lock_res_init(struct ocf + lockres->l_flags |= OCFS2_LOCK_NOCACHE; + } + ++void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, ++ struct ocfs2_mem_dqinfo *info) ++{ ++ ocfs2_lock_res_init_once(lockres); ++ ocfs2_build_lock_name(OCFS2_LOCK_TYPE_QINFO, info->dqi_gi.dqi_type, ++ 0, lockres->l_name); ++ ocfs2_lock_res_init_common(OCFS2_SB(info->dqi_gi.dqi_sb), lockres, ++ OCFS2_LOCK_TYPE_QINFO, &ocfs2_qinfo_lops, ++ info); ++} ++ + void ocfs2_lock_res_free(struct ocfs2_lock_res *res) + { + mlog_entry_void(); +@@ -3449,6 +3484,108 @@ static int ocfs2_dentry_convert_worker(s + return UNBLOCK_CONTINUE_POST; + } + ++static void ocfs2_set_qinfo_lvb(struct ocfs2_lock_res *lockres) ++{ ++ struct ocfs2_qinfo_lvb *lvb; ++ struct ocfs2_mem_dqinfo *oinfo = ocfs2_lock_res_qinfo(lockres); ++ struct mem_dqinfo *info = sb_dqinfo(oinfo->dqi_gi.dqi_sb, ++ oinfo->dqi_gi.dqi_type); ++ ++ mlog_entry_void(); ++ ++ lvb = (struct ocfs2_qinfo_lvb *)ocfs2_dlm_lvb(&lockres->l_lksb); ++ lvb->lvb_version = OCFS2_LVB_VERSION; ++ lvb->lvb_bgrace = cpu_to_be32(info->dqi_bgrace); ++ lvb->lvb_igrace = cpu_to_be32(info->dqi_igrace); ++ lvb->lvb_syncms = cpu_to_be32(oinfo->dqi_syncms); ++ lvb->lvb_blocks = cpu_to_be32(oinfo->dqi_gi.dqi_blocks); ++ lvb->lvb_free_blk = cpu_to_be32(oinfo->dqi_gi.dqi_free_blk); ++ lvb->lvb_free_entry = cpu_to_be32(oinfo->dqi_gi.dqi_free_entry); ++ ++ mlog_exit_void(); ++} ++ ++void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex) ++{ ++ struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock; ++ struct ocfs2_super *osb = OCFS2_SB(oinfo->dqi_gi.dqi_sb); ++ int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; ++ ++ mlog_entry_void(); ++ if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb)) ++ ocfs2_cluster_unlock(osb, lockres, level); ++ mlog_exit_void(); ++} ++ ++/* Lock quota info, this function expects at least shared lock on the quota file ++ * so that we can safely refresh quota info from disk. */ ++int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(oinfo->dqi_gi.dqi_sb, ++ oinfo->dqi_gi.dqi_type); ++ struct ocfs2_lock_res *lockres = &oinfo->dqi_gqlock; ++ struct ocfs2_super *osb = OCFS2_SB(oinfo->dqi_gi.dqi_sb); ++ struct ocfs2_qinfo_lvb *lvb; ++ int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR; ++ int status = 0; ++ struct buffer_head *bh; ++ struct ocfs2_global_disk_dqinfo *gdinfo; ++ ++ mlog_entry_void(); ++ ++ /* We'll allow faking a readonly metadata lock for ++ * rodevices. */ ++ if (ocfs2_is_hard_readonly(osb)) { ++ if (ex) ++ status = -EROFS; ++ goto bail; ++ } ++ if (ocfs2_mount_local(osb)) ++ goto bail; ++ ++ status = ocfs2_cluster_lock(osb, lockres, level, 0, 0); ++ if (status < 0) { ++ mlog_errno(status); ++ goto bail; ++ } ++ if (!ocfs2_should_refresh_lock_res(lockres)) ++ goto bail; ++ /* OK, we have the lock but we need to refresh the quota info */ ++ lvb = ocfs2_dlm_lvb(&lockres->l_lksb); ++ if (lvb->lvb_version == OCFS2_LVB_VERSION) { ++ info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); ++ info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); ++ oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); ++ oinfo->dqi_gi.dqi_blocks = be32_to_cpu(lvb->lvb_blocks); ++ oinfo->dqi_gi.dqi_free_blk = be32_to_cpu(lvb->lvb_free_blk); ++ oinfo->dqi_gi.dqi_free_entry = ++ be32_to_cpu(lvb->lvb_free_entry); ++ } else { ++ bh = ocfs2_bread(oinfo->dqi_gqinode, 0, &status, 0); ++ if (!bh) { ++ ocfs2_qinfo_unlock(oinfo, ex); ++ mlog_errno(status); ++ goto bail_refresh; ++ } ++ gdinfo = (struct ocfs2_global_disk_dqinfo *) ++ (bh->b_data + OCFS2_GLOBAL_INFO_OFF); ++ info->dqi_bgrace = le32_to_cpu(gdinfo->dqi_bgrace); ++ info->dqi_igrace = le32_to_cpu(gdinfo->dqi_igrace); ++ oinfo->dqi_syncms = le32_to_cpu(gdinfo->dqi_syncms); ++ oinfo->dqi_gi.dqi_blocks = le32_to_cpu(gdinfo->dqi_blocks); ++ oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(gdinfo->dqi_free_blk); ++ oinfo->dqi_gi.dqi_free_entry = ++ le32_to_cpu(gdinfo->dqi_free_entry); ++ brelse(bh); ++ ocfs2_track_lock_refresh(lockres); ++ } ++bail_refresh: ++ ocfs2_complete_lock_res_refresh(lockres, status); ++bail: ++ mlog_exit(status); ++ return status; ++} ++ + /* + * This is the filesystem locking protocol. It provides the lock handling + * hooks for the underlying DLM. It has a maximum version number. +Index: linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dlmglue.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/dlmglue.h +@@ -49,6 +49,17 @@ struct ocfs2_meta_lvb { + __be32 lvb_reserved2; + }; + ++struct ocfs2_qinfo_lvb { ++ __u8 lvb_version; ++ __u8 lvb_reserved[3]; ++ __be32 lvb_bgrace; ++ __be32 lvb_igrace; ++ __be32 lvb_syncms; ++ __be32 lvb_blocks; ++ __be32 lvb_free_blk; ++ __be32 lvb_free_entry; ++}; ++ + /* ocfs2_inode_lock_full() 'arg_flags' flags */ + /* don't wait on recovery. */ + #define OCFS2_META_LOCK_RECOVERY (0x01) +@@ -69,6 +80,9 @@ void ocfs2_dentry_lock_res_init(struct o + struct ocfs2_file_private; + void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, + struct ocfs2_file_private *fp); ++struct ocfs2_mem_dqinfo; ++void ocfs2_qinfo_lock_res_init(struct ocfs2_lock_res *lockres, ++ struct ocfs2_mem_dqinfo *info); + void ocfs2_lock_res_free(struct ocfs2_lock_res *res); + int ocfs2_create_new_inode_locks(struct inode *inode); + int ocfs2_drop_inode_locks(struct inode *inode); +@@ -103,6 +117,9 @@ int ocfs2_dentry_lock(struct dentry *den + void ocfs2_dentry_unlock(struct dentry *dentry, int ex); + int ocfs2_file_lock(struct file *file, int ex, int trylock); + void ocfs2_file_unlock(struct file *file); ++int ocfs2_qinfo_lock(struct ocfs2_mem_dqinfo *oinfo, int ex); ++void ocfs2_qinfo_unlock(struct ocfs2_mem_dqinfo *oinfo, int ex); ++ + + void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres); + void ocfs2_simple_drop_lockres(struct ocfs2_super *osb, +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.c +@@ -304,9 +304,9 @@ bail: + return status; + } + +-static int ocfs2_simple_size_update(struct inode *inode, +- struct buffer_head *di_bh, +- u64 new_i_size) ++int ocfs2_simple_size_update(struct inode *inode, ++ struct buffer_head *di_bh, ++ u64 new_i_size) + { + int ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.h +@@ -51,6 +51,9 @@ int ocfs2_add_inode_data(struct ocfs2_su + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, + enum ocfs2_alloc_restarted *reason_ret); ++int ocfs2_simple_size_update(struct inode *inode, ++ struct buffer_head *di_bh, ++ u64 new_i_size); + int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, + u64 zero_to); + int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); +Index: linux-2.6.27-ocfs2/fs/ocfs2/journal.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/journal.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/journal.h +@@ -357,6 +357,21 @@ int ocfs2_journal_dirty + + OCFS2_INODE_UPDATE_CREDITS \ + + OCFS2_XATTR_BLOCK_UPDATE_CREDITS) + ++/* global quotafile inode update, data block */ ++#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) ++ ++/* ++ * The two writes below can accidentally see global info dirty due ++ * to set_info() quotactl so make them prepared for the writes. ++ */ ++/* quota data block, global info */ ++/* Write to local quota file */ ++#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) ++ ++/* global quota data block, local quota data block, global quota inode, ++ * global quota info */ ++#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) ++ + /* + * Please note that the caller must make sure that root_el is the root + * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2_fs.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_fs.h +@@ -859,6 +859,101 @@ struct ocfs2_xattr_block { + } xb_attrs; + }; + ++/* ++ * On disk structures for global quota file ++ */ ++ ++/* Magic numbers and known versions for global quota files */ ++#define OCFS2_GLOBAL_QMAGICS {\ ++ 0x0cf52470, /* USRQUOTA */ \ ++ 0x0cf52471 /* GRPQUOTA */ \ ++} ++ ++#define OCFS2_GLOBAL_QVERSIONS {\ ++ 0, \ ++ 0, \ ++} ++ ++/* Generic header of all quota files */ ++struct ocfs2_disk_dqheader { ++ __le32 dqh_magic; /* Magic number identifying file */ ++ __le32 dqh_version; /* Quota format version */ ++}; ++ ++#define OCFS2_GLOBAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader)) ++ ++/* Information header of global quota file (immediately follows the generic ++ * header) */ ++struct ocfs2_global_disk_dqinfo { ++/*00*/ __le32 dqi_bgrace; ++ __le32 dqi_igrace; ++ __le32 dqi_syncms; ++ __le32 dqi_blocks; ++/*10*/ __le32 dqi_free_blk; ++ __le32 dqi_free_entry; ++}; ++ ++/* Structure with global user / group information. We reserve some space ++ * for future use. */ ++struct ocfs2_global_disk_dqblk { ++/*00*/ __le32 dqb_id; /* ID the structure belongs to */ ++ __le32 dqb_use_count; /* Number of nodes having reference to this structure */ ++ __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ ++/*10*/ __le64 dqb_isoftlimit; /* preferred inode limit */ ++ __le64 dqb_curinodes; /* current # allocated inodes */ ++/*20*/ __le64 dqb_bhardlimit; /* absolute limit on disk space */ ++ __le64 dqb_bsoftlimit; /* preferred limit on disk space */ ++/*30*/ __le64 dqb_curspace; /* current space occupied */ ++ __le64 dqb_btime; /* time limit for excessive disk use */ ++/*40*/ __le64 dqb_itime; /* time limit for excessive inode use */ ++ __le64 dqb_pad1; ++/*50*/ __le64 dqb_pad2; ++}; ++ ++/* ++ * On-disk structures for local quota file ++ */ ++ ++/* Magic numbers and known versions for local quota files */ ++#define OCFS2_LOCAL_QMAGICS {\ ++ 0x0cf524c0, /* USRQUOTA */ \ ++ 0x0cf524c1 /* GRPQUOTA */ \ ++} ++ ++#define OCFS2_LOCAL_QVERSIONS {\ ++ 0, \ ++ 0, \ ++} ++ ++/* Quota flags in dqinfo header */ ++#define OLQF_CLEAN 0x0001 /* Quota file is empty (this should be after\ ++ * quota has been cleanly turned off) */ ++ ++#define OCFS2_LOCAL_INFO_OFF (sizeof(struct ocfs2_disk_dqheader)) ++ ++/* Information header of local quota file (immediately follows the generic ++ * header) */ ++struct ocfs2_local_disk_dqinfo { ++ __le32 dqi_flags; /* Flags for quota file */ ++ __le32 dqi_chunks; /* Number of chunks of quota structures ++ * with a bitmap */ ++ __le32 dqi_blocks; /* Number of blocks allocated for quota file */ ++}; ++ ++/* Header of one chunk of a quota file */ ++struct ocfs2_local_disk_chunk { ++ __le32 dqc_free; /* Number of free entries in the bitmap */ ++ u8 dqc_bitmap[0]; /* Bitmap of entries in the corresponding ++ * chunk of quota file */ ++}; ++ ++/* One entry in local quota file */ ++struct ocfs2_local_disk_dqblk { ++/*00*/ __le64 dqb_id; /* id this quota applies to */ ++ __le64 dqb_spacemod; /* Change in the amount of used space */ ++/*10*/ __le64 dqb_inodemod; /* Change in the amount of used inodes */ ++}; ++ + #define OCFS2_XATTR_ENTRY_LOCAL 0x80 + #define OCFS2_XATTR_TYPE_MASK 0x7F + static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe, +Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_lockid.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2_lockid.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2_lockid.h +@@ -46,6 +46,7 @@ enum ocfs2_lock_type { + OCFS2_LOCK_TYPE_DENTRY, + OCFS2_LOCK_TYPE_OPEN, + OCFS2_LOCK_TYPE_FLOCK, ++ OCFS2_LOCK_TYPE_QINFO, + OCFS2_NUM_LOCK_TYPES + }; + +@@ -77,6 +78,9 @@ static inline char ocfs2_lock_type_char( + case OCFS2_LOCK_TYPE_FLOCK: + c = 'F'; + break; ++ case OCFS2_LOCK_TYPE_QINFO: ++ c = 'Q'; ++ break; + default: + c = '\0'; + } +@@ -95,6 +99,7 @@ static char *ocfs2_lock_type_strings[] = + [OCFS2_LOCK_TYPE_DENTRY] = "Dentry", + [OCFS2_LOCK_TYPE_OPEN] = "Open", + [OCFS2_LOCK_TYPE_FLOCK] = "Flock", ++ [OCFS2_LOCK_TYPE_QINFO] = "Quota", + }; + + static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) +Index: linux-2.6.27-ocfs2/fs/ocfs2/quota.h +=================================================================== +--- /dev/null ++++ linux-2.6.27-ocfs2/fs/ocfs2/quota.h +@@ -0,0 +1,97 @@ ++/* ++ * quota.h for OCFS2 ++ * ++ * On disk quota structures for local and global quota file, in-memory ++ * structures. ++ * ++ */ ++ ++#ifndef _OCFS2_QUOTA_H ++#define _OCFS2_QUOTA_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "ocfs2.h" ++ ++/* Common stuff */ ++/* id number of quota format */ ++#define QFMT_OCFS2 3 ++ ++/* How many bytes to we reserve in each quota file block for our internal ++ * purposes? E.g. checksums... */ ++#define OCFS2_QBLK_RESERVED_SPACE 8 ++ ++/* ++ * In-memory structures ++ */ ++struct ocfs2_dquot { ++ struct dquot dq_dquot; /* Generic VFS dquot */ ++ loff_t dq_local_off; /* Offset in the local quota file */ ++ struct ocfs2_quota_chunk *dq_chunk; /* Chunk dquot is in */ ++ unsigned int dq_use_count; /* Number of nodes having reference to this entry in global quota file */ ++ s64 dq_origspace; /* Last globally synced space usage */ ++ s64 dq_originodes; /* Last globally synced inode usage */ ++}; ++ ++/* In-memory structure with quota header information */ ++struct ocfs2_mem_dqinfo { ++ unsigned int dqi_type; /* Quota type this structure describes */ ++ unsigned int dqi_chunks; /* Number of chunks in local quota file */ ++ unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */ ++ unsigned int dqi_syncms; /* How often should we sync with other nodes */ ++ struct list_head dqi_chunk; /* List of chunks */ ++ struct inode *dqi_gqinode; /* Global quota file inode */ ++ struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */ ++ struct buffer_head *dqi_gqi_bh; /* Buffer head with global quota file inode - set only if inode lock is obtained */ ++ int dqi_gqi_count; /* Number of holders of dqi_gqi_bh */ ++ struct buffer_head *dqi_lqi_bh; /* Buffer head with local quota file inode */ ++ struct buffer_head *dqi_ibh; /* Buffer with information header */ ++ struct qtree_mem_dqinfo dqi_gi; /* Info about global file */ ++}; ++ ++static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot) ++{ ++ return container_of(dquot, struct ocfs2_dquot, dq_dquot); ++} ++ ++struct ocfs2_quota_chunk { ++ struct list_head qc_chunk; /* List of quotafile chunks */ ++ int qc_num; /* Number of quota chunk */ ++ struct buffer_head *qc_headerbh; /* Buffer head with chunk header */ ++}; ++ ++extern struct kmem_cache *ocfs2_dquot_cachep; ++extern struct kmem_cache *ocfs2_qf_chunk_cachep; ++ ++extern struct qtree_fmt_operations ocfs2_global_ops; ++ ++ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data, ++ size_t len, loff_t off); ++ssize_t ocfs2_quota_write(struct super_block *sb, int type, ++ const char *data, size_t len, loff_t off); ++int ocfs2_global_read_info(struct super_block *sb, int type); ++int ocfs2_global_write_info(struct super_block *sb, int type); ++int ocfs2_global_read_dquot(struct dquot *dquot); ++int __ocfs2_sync_dquot(struct dquot *dquot, int freeing); ++static inline int ocfs2_sync_dquot(struct dquot *dquot) ++{ ++ return __ocfs2_sync_dquot(dquot, 0); ++} ++static inline int ocfs2_global_release_dquot(struct dquot *dquot) ++{ ++ return __ocfs2_sync_dquot(dquot, 1); ++} ++ ++int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex); ++void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex); ++ ++int init_ocfs2_quota_format(void); ++void exit_ocfs2_quota_format(void); ++ ++extern struct dquot_operations ocfs2_quota_operations; ++ ++#endif /* _OCFS2_QUOTA_H */ +Index: linux-2.6.27-ocfs2/fs/ocfs2/quota_global.c +=================================================================== +--- /dev/null ++++ linux-2.6.27-ocfs2/fs/ocfs2/quota_global.c +@@ -0,0 +1,856 @@ ++/* ++ * Implementation of operations over global quota file ++ */ ++#include ++#include ++#include ++#include ++ ++#define MLOG_MASK_PREFIX ML_QUOTA ++#include ++ ++#include "ocfs2_fs.h" ++#include "ocfs2.h" ++#include "alloc.h" ++#include "inode.h" ++#include "journal.h" ++#include "file.h" ++#include "sysfile.h" ++#include "dlmglue.h" ++#include "quota.h" ++ ++static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp) ++{ ++ struct ocfs2_global_disk_dqblk *d = dp; ++ struct mem_dqblk *m = &dquot->dq_dqb; ++ ++ /* Update from disk only entries not set by the admin */ ++ if (!test_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags)) { ++ m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit); ++ m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit); ++ } ++ if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags)) ++ m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes); ++ if (!test_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags)) { ++ m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit); ++ m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit); ++ } ++ if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags)) ++ m->dqb_curspace = le64_to_cpu(d->dqb_curspace); ++ if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags)) ++ m->dqb_btime = le64_to_cpu(d->dqb_btime); ++ if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags)) ++ m->dqb_itime = le64_to_cpu(d->dqb_itime); ++ OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count); ++} ++ ++static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot) ++{ ++ struct ocfs2_global_disk_dqblk *d = dp; ++ struct mem_dqblk *m = &dquot->dq_dqb; ++ ++ d->dqb_id = cpu_to_le32(dquot->dq_id); ++ d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count); ++ d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit); ++ d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit); ++ d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes); ++ d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit); ++ d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit); ++ d->dqb_curspace = cpu_to_le64(m->dqb_curspace); ++ d->dqb_btime = cpu_to_le64(m->dqb_btime); ++ d->dqb_itime = cpu_to_le64(m->dqb_itime); ++ d->dqb_pad1 = d->dqb_pad2 = 0; ++} ++ ++static int ocfs2_global_is_id(void *dp, struct dquot *dquot) ++{ ++ struct ocfs2_global_disk_dqblk *d = dp; ++ struct ocfs2_mem_dqinfo *oinfo = ++ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; ++ ++ if (qtree_entry_unused(&oinfo->dqi_gi, dp)) ++ return 0; ++ return le32_to_cpu(d->dqb_id) == dquot->dq_id; ++} ++ ++struct qtree_fmt_operations ocfs2_global_ops = { ++ .mem2disk_dqblk = ocfs2_global_mem2diskdqb, ++ .disk2mem_dqblk = ocfs2_global_disk2memdqb, ++ .is_id = ocfs2_global_is_id, ++}; ++ ++/* Read data from global quotafile - avoid pagecache and such because we cannot ++ * afford acquiring the locks... We use quota cluster lock to serialize ++ * operations. Caller is responsible for acquiring it. */ ++ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data, ++ size_t len, loff_t off) ++{ ++ struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ struct inode *gqinode = oinfo->dqi_gqinode; ++ loff_t i_size = i_size_read(gqinode); ++ int offset = off & (sb->s_blocksize - 1); ++ sector_t blk = off >> sb->s_blocksize_bits; ++ int err = 0; ++ struct buffer_head *bh; ++ size_t toread, tocopy; ++ ++ if (off > i_size) ++ return 0; ++ if (off + len > i_size) ++ len = i_size - off; ++ toread = len; ++ while (toread > 0) { ++ tocopy = min(sb->s_blocksize - offset, toread); ++ bh = ocfs2_bread(gqinode, blk, &err, 0); ++ if (!bh) { ++ mlog_errno(err); ++ return err; ++ } ++ memcpy(data, bh->b_data + offset, tocopy); ++ brelse(bh); ++ offset = 0; ++ toread -= tocopy; ++ data += tocopy; ++ blk++; ++ } ++ return len; ++} ++ ++/* Write to quotafile (we know the transaction is already started and has ++ * enough credits) */ ++ssize_t ocfs2_quota_write(struct super_block *sb, int type, ++ const char *data, size_t len, loff_t off) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct inode *gqinode = oinfo->dqi_gqinode; ++ int offset = off & (sb->s_blocksize - 1); ++ sector_t blk = off >> sb->s_blocksize_bits; ++ int err = 0; ++ struct buffer_head *bh; ++ handle_t *handle = journal_current_handle(); ++ size_t tocopy, towrite = len; ++ ++ if (!handle) { ++ mlog(ML_ERROR, "Quota write (off=%llu, len=%llu) cancelled " ++ "because transaction was not started.\n", ++ (unsigned long long)off, (unsigned long long)len); ++ return -EIO; ++ } ++ mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA); ++ if (gqinode->i_size < off + len) { ++ down_write(&OCFS2_I(gqinode)->ip_alloc_sem); ++ err = ocfs2_extend_no_holes(gqinode, off + len, off); ++ up_write(&OCFS2_I(gqinode)->ip_alloc_sem); ++ if (err < 0) ++ goto out; ++ err = ocfs2_simple_size_update(gqinode, ++ oinfo->dqi_gqi_bh, ++ off + len); ++ if (err < 0) ++ goto out; ++ } ++ WARN_ON(off >> sb->s_blocksize_bits != \ ++ (off + len) >> sb->s_blocksize_bits); ++ WARN_ON(((off + len) & ((1 << sb->s_blocksize_bits) - 1)) > ++ sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE); ++ for (towrite = len; towrite > 0; towrite -= tocopy) { ++ tocopy = min(towrite, sb->s_blocksize - offset); ++ bh = ocfs2_bread(gqinode, blk, &err, 0); ++ if (!bh) { ++ mlog_errno(err); ++ return err; ++ } ++ err = ocfs2_journal_access(handle, gqinode, bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (err < 0) { ++ brelse(bh); ++ goto out; ++ } ++ lock_buffer(bh); ++ memcpy(bh->b_data + offset, data, tocopy); ++ flush_dcache_page(bh->b_page); ++ unlock_buffer(bh); ++ err = ocfs2_journal_dirty(handle, bh); ++ brelse(bh); ++ if (err < 0) ++ goto out; ++ offset = 0; ++ data += tocopy; ++ blk++; ++ } ++out: ++ /* Nothing written? */ ++ if (len == towrite) { ++ mutex_unlock(&gqinode->i_mutex); ++ mlog_errno(err); ++ return err; ++ } ++ gqinode->i_version++; ++ ocfs2_mark_inode_dirty(handle, gqinode, oinfo->dqi_gqi_bh); ++ mutex_unlock(&gqinode->i_mutex); ++ return len - towrite; ++} ++ ++int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex) ++{ ++ int status; ++ struct buffer_head *bh = NULL; ++ ++ status = ocfs2_inode_lock(oinfo->dqi_gqinode, &bh, ex); ++ if (status < 0) ++ return status; ++ spin_lock(&dq_data_lock); ++ if (!oinfo->dqi_gqi_count++) ++ oinfo->dqi_gqi_bh = bh; ++ else ++ WARN_ON(bh != oinfo->dqi_gqi_bh); ++ spin_unlock(&dq_data_lock); ++ return 0; ++} ++ ++void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex) ++{ ++ ocfs2_inode_unlock(oinfo->dqi_gqinode, ex); ++ brelse(oinfo->dqi_gqi_bh); ++ spin_lock(&dq_data_lock); ++ if (!--oinfo->dqi_gqi_count) ++ oinfo->dqi_gqi_bh = NULL; ++ spin_unlock(&dq_data_lock); ++} ++ ++/* Read information header from global quota file */ ++int ocfs2_global_read_info(struct super_block *sb, int type) ++{ ++ struct inode *gqinode = NULL; ++ unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE, ++ GROUP_QUOTA_SYSTEM_INODE }; ++ struct ocfs2_global_disk_dqinfo dinfo; ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ int status; ++ ++ mlog_entry_void(); ++ ++ /* Read global header */ ++ gqinode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type], ++ OCFS2_INVALID_SLOT); ++ if (!gqinode) { ++ mlog(ML_ERROR, "failed to get global quota inode (type=%d)\n", ++ type); ++ status = -EINVAL; ++ goto out_err; ++ } ++ oinfo->dqi_gi.dqi_sb = sb; ++ oinfo->dqi_gi.dqi_type = type; ++ ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo); ++ oinfo->dqi_gi.dqi_entry_size = sizeof(struct ocfs2_global_disk_dqblk); ++ oinfo->dqi_gi.dqi_ops = &ocfs2_global_ops; ++ oinfo->dqi_gqi_bh = NULL; ++ oinfo->dqi_gqi_count = 0; ++ oinfo->dqi_gqinode = gqinode; ++ status = ocfs2_lock_global_qf(oinfo, 0); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ status = sb->s_op->quota_read(sb, type, (char *)&dinfo, ++ sizeof(struct ocfs2_global_disk_dqinfo), ++ OCFS2_GLOBAL_INFO_OFF); ++ ocfs2_unlock_global_qf(oinfo, 0); ++ if (status != sizeof(struct ocfs2_global_disk_dqinfo)) { ++ mlog(ML_ERROR, "Cannot read global quota info (%d).\n", ++ status); ++ if (status >= 0) ++ status = -EIO; ++ mlog_errno(status); ++ goto out_err; ++ } ++ info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); ++ info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); ++ oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); ++ oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); ++ oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); ++ oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); ++ oinfo->dqi_gi.dqi_blocksize_bits = sb->s_blocksize_bits; ++ oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize - ++ OCFS2_QBLK_RESERVED_SPACE; ++ oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi); ++out_err: ++ mlog_exit(status); ++ return status; ++} ++ ++/* Write information to global quota file. Expects exlusive lock on quota ++ * file inode and quota info */ ++static int __ocfs2_global_write_info(struct super_block *sb, int type) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct ocfs2_global_disk_dqinfo dinfo; ++ ssize_t size; ++ ++ spin_lock(&dq_data_lock); ++ info->dqi_flags &= ~DQF_INFO_DIRTY; ++ dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); ++ dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); ++ spin_unlock(&dq_data_lock); ++ dinfo.dqi_syncms = cpu_to_le32(oinfo->dqi_syncms); ++ dinfo.dqi_blocks = cpu_to_le32(oinfo->dqi_gi.dqi_blocks); ++ dinfo.dqi_free_blk = cpu_to_le32(oinfo->dqi_gi.dqi_free_blk); ++ dinfo.dqi_free_entry = cpu_to_le32(oinfo->dqi_gi.dqi_free_entry); ++ size = sb->s_op->quota_write(sb, type, (char *)&dinfo, ++ sizeof(struct ocfs2_global_disk_dqinfo), ++ OCFS2_GLOBAL_INFO_OFF); ++ if (size != sizeof(struct ocfs2_global_disk_dqinfo)) { ++ mlog(ML_ERROR, "Cannot write global quota info structure\n"); ++ if (size >= 0) ++ size = -EIO; ++ return size; ++ } ++ return 0; ++} ++ ++int ocfs2_global_write_info(struct super_block *sb, int type) ++{ ++ int err; ++ struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv; ++ ++ err = ocfs2_qinfo_lock(info, 1); ++ if (err < 0) ++ return err; ++ err = __ocfs2_global_write_info(sb, type); ++ ocfs2_qinfo_unlock(info, 1); ++ return err; ++} ++ ++/* Read in information from global quota file and acquire a reference to it. ++ * dquot_acquire() has already started the transaction and locked quota file */ ++int ocfs2_global_read_dquot(struct dquot *dquot) ++{ ++ int err, err2, ex = 0; ++ struct ocfs2_mem_dqinfo *info = ++ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; ++ ++ err = ocfs2_qinfo_lock(info, 0); ++ if (err < 0) ++ goto out; ++ err = qtree_read_dquot(&info->dqi_gi, dquot); ++ if (err < 0) ++ goto out_qlock; ++ OCFS2_DQUOT(dquot)->dq_use_count++; ++ OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace; ++ OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; ++ if (!dquot->dq_off) { /* No real quota entry? */ ++ /* Upgrade to exclusive lock for allocation */ ++ err = ocfs2_qinfo_lock(info, 1); ++ if (err < 0) ++ goto out_qlock; ++ ex = 1; ++ } ++ err = qtree_write_dquot(&info->dqi_gi, dquot); ++ if (ex && info_dirty(sb_dqinfo(dquot->dq_sb, dquot->dq_type))) { ++ err2 = __ocfs2_global_write_info(dquot->dq_sb, dquot->dq_type); ++ if (!err) ++ err = err2; ++ } ++out_qlock: ++ if (ex) ++ ocfs2_qinfo_unlock(info, 1); ++ ocfs2_qinfo_unlock(info, 0); ++out: ++ if (err < 0) ++ mlog_errno(err); ++ return err; ++} ++ ++/* Sync local information about quota modifications with global quota file. ++ * Caller must have started the transaction and obtained exclusive lock for ++ * global quota file inode */ ++int __ocfs2_sync_dquot(struct dquot *dquot, int freeing) ++{ ++ int err, err2; ++ struct super_block *sb = dquot->dq_sb; ++ int type = dquot->dq_type; ++ struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv; ++ struct ocfs2_global_disk_dqblk dqblk; ++ s64 spacechange, inodechange; ++ time_t olditime, oldbtime; ++ ++ err = sb->s_op->quota_read(sb, type, (char *)&dqblk, ++ sizeof(struct ocfs2_global_disk_dqblk), ++ dquot->dq_off); ++ if (err != sizeof(struct ocfs2_global_disk_dqblk)) { ++ if (err >= 0) { ++ mlog(ML_ERROR, "Short read from global quota file " ++ "(%u read)\n", err); ++ err = -EIO; ++ } ++ goto out; ++ } ++ ++ /* Update space and inode usage. Get also other information from ++ * global quota file so that we don't overwrite any changes there. ++ * We are */ ++ spin_lock(&dq_data_lock); ++ spacechange = dquot->dq_dqb.dqb_curspace - ++ OCFS2_DQUOT(dquot)->dq_origspace; ++ inodechange = dquot->dq_dqb.dqb_curinodes - ++ OCFS2_DQUOT(dquot)->dq_originodes; ++ olditime = dquot->dq_dqb.dqb_itime; ++ oldbtime = dquot->dq_dqb.dqb_btime; ++ ocfs2_global_disk2memdqb(dquot, &dqblk); ++ mlog(0, "Syncing global dquot %d space %lld+%lld, inodes %lld+%lld\n", ++ dquot->dq_id, dquot->dq_dqb.dqb_curspace, spacechange, ++ dquot->dq_dqb.dqb_curinodes, inodechange); ++ if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags)) ++ dquot->dq_dqb.dqb_curspace += spacechange; ++ if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags)) ++ dquot->dq_dqb.dqb_curinodes += inodechange; ++ /* Now merge grace time changes... */ ++ if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) && ++ oldbtime > 0) { ++ if (dquot->dq_dqb.dqb_btime > 0) ++ dquot->dq_dqb.dqb_btime = ++ min(dquot->dq_dqb.dqb_btime, oldbtime); ++ else ++ dquot->dq_dqb.dqb_btime = oldbtime; ++ } ++ if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) && ++ olditime > 0) { ++ if (dquot->dq_dqb.dqb_itime > 0) ++ dquot->dq_dqb.dqb_itime = ++ min(dquot->dq_dqb.dqb_itime, olditime); ++ else ++ dquot->dq_dqb.dqb_itime = olditime; ++ } ++ /* All information is properly updated, clear the flags */ ++ __clear_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); ++ __clear_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); ++ __clear_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); ++ __clear_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); ++ __clear_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); ++ __clear_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); ++ OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace; ++ OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; ++ spin_unlock(&dq_data_lock); ++ err = ocfs2_qinfo_lock(info, freeing); ++ if (err < 0) { ++ mlog(ML_ERROR, "Failed to lock quota info, loosing quota write" ++ " (type=%d, id=%u)\n", dquot->dq_type, ++ (unsigned)dquot->dq_id); ++ goto out; ++ } ++ if (freeing) ++ OCFS2_DQUOT(dquot)->dq_use_count--; ++ err = qtree_write_dquot(&info->dqi_gi, dquot); ++ if (err < 0) ++ goto out_qlock; ++ if (freeing && !OCFS2_DQUOT(dquot)->dq_use_count) { ++ err = qtree_release_dquot(&info->dqi_gi, dquot); ++ if (info_dirty(sb_dqinfo(sb, type))) { ++ err2 = __ocfs2_global_write_info(sb, type); ++ if (!err) ++ err = err2; ++ } ++ } ++out_qlock: ++ ocfs2_qinfo_unlock(info, freeing); ++out: ++ if (err < 0) ++ mlog_errno(err); ++ return err; ++} ++ ++/* ++ * Wrappers for generic quota functions ++ */ ++ ++static int ocfs2_write_dquot(struct dquot *dquot) ++{ ++ handle_t *handle; ++ struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb); ++ int status = 0; ++ ++ mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type); ++ ++ handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out; ++ } ++ status = dquot_commit(dquot); ++ ocfs2_commit_trans(osb, handle); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++int ocfs2_calc_qdel_credits(struct super_block *sb, int type) ++{ ++ struct ocfs2_mem_dqinfo *oinfo; ++ int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA }; ++ ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type])) ++ return 0; ++ ++ oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ /* We modify tree, leaf block, global info, local chunk header, ++ * global and local inode */ ++ return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 + ++ 2 * OCFS2_INODE_UPDATE_CREDITS; ++} ++ ++static int ocfs2_release_dquot(struct dquot *dquot) ++{ ++ handle_t *handle; ++ struct ocfs2_mem_dqinfo *oinfo = ++ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; ++ struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb); ++ int status = 0; ++ ++ mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type); ++ ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ handle = ocfs2_start_trans(osb, ++ ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type)); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ status = dquot_release(dquot); ++ ocfs2_commit_trans(osb, handle); ++out_ilock: ++ ocfs2_unlock_global_qf(oinfo, 1); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++int ocfs2_calc_qinit_credits(struct super_block *sb, int type) ++{ ++ struct ocfs2_mem_dqinfo *oinfo; ++ struct ocfs2_dinode *lfe, *gfe; ++ int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, ++ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA }; ++ ++ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type])) ++ return 0; ++ ++ oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ gfe = (struct ocfs2_dinode *)oinfo->dqi_gqi_bh->b_data; ++ lfe = (struct ocfs2_dinode *)oinfo->dqi_lqi_bh->b_data; ++ /* We can extend local file + global file. In local file we ++ * can modify info, chunk header block and dquot block. In ++ * global file we can modify info, tree and leaf block */ ++ return ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) + ++ ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) + ++ 3 + oinfo->dqi_gi.dqi_qtree_depth + 2; ++} ++ ++static int ocfs2_acquire_dquot(struct dquot *dquot) ++{ ++ handle_t *handle; ++ struct ocfs2_mem_dqinfo *oinfo = ++ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; ++ struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb); ++ int status = 0; ++ ++ mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type); ++ /* We need an exclusive lock, because we're going to update use count ++ * and instantiate possibly new dquot structure */ ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ handle = ocfs2_start_trans(osb, ++ ocfs2_calc_qinit_credits(dquot->dq_sb, dquot->dq_type)); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ status = dquot_acquire(dquot); ++ ocfs2_commit_trans(osb, handle); ++out_ilock: ++ ocfs2_unlock_global_qf(oinfo, 1); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++static int ocfs2_mark_dquot_dirty(struct dquot *dquot) ++{ ++ unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) | ++ (1 << (DQ_LASTSET_B + QIF_BLIMITS_B)) | ++ (1 << (DQ_LASTSET_B + QIF_INODES_B)) | ++ (1 << (DQ_LASTSET_B + QIF_SPACE_B)) | ++ (1 << (DQ_LASTSET_B + QIF_BTIME_B)) | ++ (1 << (DQ_LASTSET_B + QIF_ITIME_B)); ++ int sync = 0; ++ int status; ++ struct super_block *sb = dquot->dq_sb; ++ int type = dquot->dq_type; ++ struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ handle_t *handle; ++ struct ocfs2_super *osb = OCFS2_SB(sb); ++ ++ mlog_entry("id=%u, type=%d", dquot->dq_id, type); ++ dquot_mark_dquot_dirty(dquot); ++ ++ /* In case user set some limits, sync dquot immediately to global ++ * quota file so that information propagates quicker */ ++ spin_lock(&dq_data_lock); ++ if (dquot->dq_flags & mask) ++ sync = 1; ++ spin_unlock(&dq_data_lock); ++ if (!sync) { ++ status = ocfs2_write_dquot(dquot); ++ goto out; ++ } ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ status = ocfs2_sync_dquot(dquot); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ /* Now write updated local dquot structure */ ++ status = dquot_commit(dquot); ++out_trans: ++ ocfs2_commit_trans(osb, handle); ++out_ilock: ++ ocfs2_unlock_global_qf(oinfo, 1); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++/* This should happen only after set_dqinfo(). */ ++static int ocfs2_write_info(struct super_block *sb, int type) ++{ ++ handle_t *handle; ++ int status = 0; ++ struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; ++ ++ mlog_entry_void(); ++ ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QINFO_WRITE_CREDITS); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ status = dquot_commit_info(sb, type); ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++out_ilock: ++ ocfs2_unlock_global_qf(oinfo, 1); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++/* This is difficult. We have to lock quota inode and start transaction ++ * in this function but we don't want to take the penalty of exlusive ++ * quota file lock when we are just going to use cached structures. So ++ * we just take read lock check whether we have dquot cached and if so, ++ * we don't have to take the write lock... */ ++static int ocfs2_dquot_initialize(struct inode *inode, int type) ++{ ++ handle_t *handle = NULL; ++ int status = 0; ++ struct super_block *sb = inode->i_sb; ++ struct ocfs2_mem_dqinfo *oinfo; ++ int exclusive = 0; ++ int cnt; ++ qid_t id; ++ ++ mlog_entry_void(); ++ ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (type != -1 && cnt != type) ++ continue; ++ oinfo = sb_dqinfo(sb, cnt)->dqi_priv; ++ status = ocfs2_lock_global_qf(oinfo, 0); ++ if (status < 0) ++ goto out; ++ /* This is just a performance optimization not a reliable test. ++ * Since we hold an inode lock, noone can actually release ++ * the structure until we are finished with initialization. */ ++ if (inode->i_dquot[cnt] != NODQUOT) { ++ ocfs2_unlock_global_qf(oinfo, 0); ++ continue; ++ } ++ /* When we have inode lock, we know that no dquot_release() can ++ * run and thus we can safely check whether we need to ++ * read+modify global file to get quota information or whether ++ * our node already has it. */ ++ if (cnt == USRQUOTA) ++ id = inode->i_uid; ++ else if (cnt == GRPQUOTA) ++ id = inode->i_gid; ++ else ++ BUG(); ++ /* Obtain exclusion from quota off... */ ++ down_write(&sb_dqopt(sb)->dqptr_sem); ++ exclusive = !dquot_is_cached(sb, id, cnt); ++ up_write(&sb_dqopt(sb)->dqptr_sem); ++ if (exclusive) { ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) { ++ exclusive = 0; ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ handle = ocfs2_start_trans(OCFS2_SB(sb), ++ ocfs2_calc_qinit_credits(sb, cnt)); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out_ilock; ++ } ++ } ++ dquot_initialize(inode, cnt); ++ if (exclusive) { ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++ ocfs2_unlock_global_qf(oinfo, 1); ++ } ++ ocfs2_unlock_global_qf(oinfo, 0); ++ } ++ mlog_exit(0); ++ return 0; ++out_ilock: ++ if (exclusive) ++ ocfs2_unlock_global_qf(oinfo, 1); ++ ocfs2_unlock_global_qf(oinfo, 0); ++out: ++ mlog_exit(status); ++ return status; ++} ++ ++static int ocfs2_dquot_drop_slow(struct inode *inode) ++{ ++ int status; ++ int cnt; ++ int got_lock[MAXQUOTAS] = {0, 0}; ++ handle_t *handle; ++ struct super_block *sb = inode->i_sb; ++ struct ocfs2_mem_dqinfo *oinfo; ++ ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ oinfo = sb_dqinfo(sb, cnt)->dqi_priv; ++ status = ocfs2_lock_global_qf(oinfo, 1); ++ if (status < 0) ++ goto out; ++ got_lock[cnt] = 1; ++ } ++ handle = ocfs2_start_trans(OCFS2_SB(sb), ++ ocfs2_calc_qinit_credits(sb, USRQUOTA) + ++ ocfs2_calc_qinit_credits(sb, GRPQUOTA)); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out; ++ } ++ dquot_drop(inode); ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++out: ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) ++ if (got_lock[cnt]) { ++ oinfo = sb_dqinfo(sb, cnt)->dqi_priv; ++ ocfs2_unlock_global_qf(oinfo, 1); ++ } ++ return status; ++} ++ ++/* See the comment before ocfs2_dquot_initialize. */ ++static int ocfs2_dquot_drop(struct inode *inode) ++{ ++ int status = 0; ++ struct super_block *sb = inode->i_sb; ++ struct ocfs2_mem_dqinfo *oinfo; ++ int exclusive = 0; ++ int cnt; ++ int got_lock[MAXQUOTAS] = {0, 0}; ++ ++ mlog_entry_void(); ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ oinfo = sb_dqinfo(sb, cnt)->dqi_priv; ++ status = ocfs2_lock_global_qf(oinfo, 0); ++ if (status < 0) ++ goto out; ++ got_lock[cnt] = 1; ++ } ++ /* Lock against anyone releasing references so that when when we check ++ * we know we are not going to be last ones to release dquot */ ++ down_write(&sb_dqopt(sb)->dqptr_sem); ++ /* Urgh, this is a terrible hack :( */ ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { ++ if (inode->i_dquot[cnt] != NODQUOT && ++ atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) { ++ exclusive = 1; ++ break; ++ } ++ } ++ if (!exclusive) ++ dquot_drop_locked(inode); ++ up_write(&sb_dqopt(sb)->dqptr_sem); ++out: ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) ++ if (got_lock[cnt]) { ++ oinfo = sb_dqinfo(sb, cnt)->dqi_priv; ++ ocfs2_unlock_global_qf(oinfo, 0); ++ } ++ /* In case we bailed out because we had to do expensive locking ++ * do it now... */ ++ if (exclusive) ++ status = ocfs2_dquot_drop_slow(inode); ++ mlog_exit(status); ++ return status; ++} ++ ++static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type) ++{ ++ struct ocfs2_dquot *dquot = ++ kmem_cache_zalloc(ocfs2_dquot_cachep, GFP_NOFS); ++ ++ if (!dquot) ++ return NULL; ++ return &dquot->dq_dquot; ++} ++ ++static void ocfs2_destroy_dquot(struct dquot *dquot) ++{ ++ kmem_cache_free(ocfs2_dquot_cachep, dquot); ++} ++ ++struct dquot_operations ocfs2_quota_operations = { ++ .initialize = ocfs2_dquot_initialize, ++ .drop = ocfs2_dquot_drop, ++ .alloc_space = dquot_alloc_space, ++ .alloc_inode = dquot_alloc_inode, ++ .free_space = dquot_free_space, ++ .free_inode = dquot_free_inode, ++ .transfer = dquot_transfer, ++ .write_dquot = ocfs2_write_dquot, ++ .acquire_dquot = ocfs2_acquire_dquot, ++ .release_dquot = ocfs2_release_dquot, ++ .mark_dirty = ocfs2_mark_dquot_dirty, ++ .write_info = ocfs2_write_info, ++ .alloc_dquot = ocfs2_alloc_dquot, ++ .destroy_dquot = ocfs2_destroy_dquot, ++}; +Index: linux-2.6.27-ocfs2/fs/ocfs2/quota_local.c +=================================================================== +--- /dev/null ++++ linux-2.6.27-ocfs2/fs/ocfs2/quota_local.c +@@ -0,0 +1,843 @@ ++/* ++ * Implementation of operations over local quota file ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define MLOG_MASK_PREFIX ML_QUOTA ++#include ++ ++#include "ocfs2_fs.h" ++#include "ocfs2.h" ++#include "inode.h" ++#include "alloc.h" ++#include "file.h" ++#include "buffer_head_io.h" ++#include "journal.h" ++#include "sysfile.h" ++#include "dlmglue.h" ++#include "quota.h" ++ ++/* Number of local quota structures per block */ ++static inline unsigned int ol_quota_entries_per_block(struct super_block *sb) ++{ ++ return ((sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) / ++ sizeof(struct ocfs2_local_disk_dqblk)); ++} ++ ++/* Number of blocks with entries in one chunk */ ++static inline unsigned int ol_chunk_blocks(struct super_block *sb) ++{ ++ return ((sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) - ++ OCFS2_QBLK_RESERVED_SPACE) << 3) / ++ ol_quota_entries_per_block(sb); ++} ++ ++/* Number of entries in a chunk bitmap */ ++static unsigned int ol_chunk_entries(struct super_block *sb) ++{ ++ return ol_chunk_blocks(sb) * ol_quota_entries_per_block(sb); ++} ++ ++/* Offset of the chunk in quota file */ ++static unsigned int ol_quota_chunk_block(struct super_block *sb, int c) ++{ ++ /* 1 block for local quota file info, 1 block per chunk for chunk info */ ++ return 1 + (ol_chunk_blocks(sb) + 1) * c; ++} ++ ++/* Offset of the dquot structure in the quota file */ ++static loff_t ol_dqblk_off(struct super_block *sb, int c, int off) ++{ ++ int epb = ol_quota_entries_per_block(sb); ++ ++ return ((ol_quota_chunk_block(sb, c) + 1 + off / epb) ++ << sb->s_blocksize_bits) + ++ (off % epb) * sizeof(struct ocfs2_local_disk_dqblk); ++} ++ ++/* Compute block number from given offset */ ++static inline unsigned int ol_dqblk_file_block(struct super_block *sb, loff_t off) ++{ ++ return off >> sb->s_blocksize_bits; ++} ++ ++static inline unsigned int ol_dqblk_block_offset(struct super_block *sb, loff_t off) ++{ ++ return off & ((1 << sb->s_blocksize_bits) - 1); ++} ++ ++/* Compute offset in the chunk of a structure with the given offset */ ++static int ol_dqblk_chunk_off(struct super_block *sb, int c, loff_t off) ++{ ++ int epb = ol_quota_entries_per_block(sb); ++ ++ return ((off >> sb->s_blocksize_bits) - ++ ol_quota_chunk_block(sb, c) - 1) * epb ++ + ((unsigned int)(off & ((1 << sb->s_blocksize_bits) - 1))) / ++ sizeof(struct ocfs2_local_disk_dqblk); ++} ++ ++/* Write bufferhead into the fs */ ++static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh, ++ void (*modify)(struct buffer_head *, void *), void *private) ++{ ++ struct super_block *sb = inode->i_sb; ++ handle_t *handle; ++ int status; ++ ++ handle = ocfs2_start_trans(OCFS2_SB(sb), 1); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ return status; ++ } ++ status = ocfs2_journal_access(handle, inode, bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++ return status; ++ } ++ lock_buffer(bh); ++ modify(bh, private); ++ unlock_buffer(bh); ++ status = ocfs2_journal_dirty(handle, bh); ++ if (status < 0) { ++ mlog_errno(status); ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++ return status; ++ } ++ status = ocfs2_commit_trans(OCFS2_SB(sb), handle); ++ if (status < 0) { ++ mlog_errno(status); ++ return status; ++ } ++ return 0; ++} ++ ++/* Check whether we understand format of quota files */ ++static int ocfs2_local_check_quota_file(struct super_block *sb, int type) ++{ ++ unsigned int lmagics[MAXQUOTAS] = OCFS2_LOCAL_QMAGICS; ++ unsigned int lversions[MAXQUOTAS] = OCFS2_LOCAL_QVERSIONS; ++ unsigned int gmagics[MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS; ++ unsigned int gversions[MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS; ++ unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE, ++ GROUP_QUOTA_SYSTEM_INODE }; ++ struct buffer_head *bh; ++ struct inode *linode = sb_dqopt(sb)->files[type]; ++ struct inode *ginode = NULL; ++ struct ocfs2_disk_dqheader *dqhead; ++ int status, ret = 0; ++ ++ /* First check whether we understand local quota file */ ++ bh = ocfs2_bread(linode, 0, &status, 0); ++ if (!bh) { ++ mlog_errno(status); ++ mlog(ML_ERROR, "failed to read quota file header (type=%d)\n", ++ type); ++ goto out_err; ++ } ++ dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data); ++ if (le32_to_cpu(dqhead->dqh_magic) != lmagics[type]) { ++ mlog(ML_ERROR, "quota file magic does not match (%u != %u)," ++ " type=%d\n", le32_to_cpu(dqhead->dqh_magic), ++ lmagics[type], type); ++ goto out_err; ++ } ++ if (le32_to_cpu(dqhead->dqh_version) != lversions[type]) { ++ mlog(ML_ERROR, "quota file version does not match (%u != %u)," ++ " type=%d\n", le32_to_cpu(dqhead->dqh_version), ++ lversions[type], type); ++ goto out_err; ++ } ++ brelse(bh); ++ bh = NULL; ++ ++ /* Next check whether we understand global quota file */ ++ ginode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type], ++ OCFS2_INVALID_SLOT); ++ if (!ginode) { ++ mlog(ML_ERROR, "cannot get global quota file inode " ++ "(type=%d)\n", type); ++ goto out_err; ++ } ++ /* Since the header is read only, we don't care about locking */ ++ bh = ocfs2_bread(ginode, 0, &status, 0); ++ if (!bh) { ++ mlog_errno(status); ++ mlog(ML_ERROR, "failed to read global quota file header " ++ "(type=%d)\n", type); ++ goto out_err; ++ } ++ dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data); ++ if (le32_to_cpu(dqhead->dqh_magic) != gmagics[type]) { ++ mlog(ML_ERROR, "global quota file magic does not match " ++ "(%u != %u), type=%d\n", ++ le32_to_cpu(dqhead->dqh_magic), gmagics[type], type); ++ goto out_err; ++ } ++ if (le32_to_cpu(dqhead->dqh_version) != gversions[type]) { ++ mlog(ML_ERROR, "global quota file version does not match " ++ "(%u != %u), type=%d\n", ++ le32_to_cpu(dqhead->dqh_version), gversions[type], ++ type); ++ goto out_err; ++ } ++ ++ ret = 1; ++out_err: ++ brelse(bh); ++ iput(ginode); ++ return ret; ++} ++ ++/* Release given list of quota file chunks */ ++static void ocfs2_release_local_quota_bitmaps(struct list_head *head) ++{ ++ struct ocfs2_quota_chunk *pos, *next; ++ ++ list_for_each_entry_safe(pos, next, head, qc_chunk) { ++ list_del(&pos->qc_chunk); ++ brelse(pos->qc_headerbh); ++ kmem_cache_free(ocfs2_qf_chunk_cachep, pos); ++ } ++} ++ ++/* Load quota bitmaps into memory */ ++static int ocfs2_load_local_quota_bitmaps(struct inode *inode, ++ struct ocfs2_local_disk_dqinfo *ldinfo, ++ struct list_head *head) ++{ ++ struct ocfs2_quota_chunk *newchunk; ++ int i, status; ++ ++ INIT_LIST_HEAD(head); ++ for (i = 0; i < le32_to_cpu(ldinfo->dqi_chunks); i++) { ++ newchunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS); ++ if (!newchunk) { ++ ocfs2_release_local_quota_bitmaps(head); ++ return -ENOMEM; ++ } ++ newchunk->qc_num = i; ++ newchunk->qc_headerbh = ocfs2_bread(inode, ++ ol_quota_chunk_block(inode->i_sb, i), ++ &status, 0); ++ if (!newchunk->qc_headerbh) { ++ mlog_errno(status); ++ kmem_cache_free(ocfs2_qf_chunk_cachep, newchunk); ++ ocfs2_release_local_quota_bitmaps(head); ++ return status; ++ } ++ list_add_tail(&newchunk->qc_chunk, head); ++ } ++ return 0; ++} ++ ++static void olq_update_info(struct buffer_head *bh, void *private) ++{ ++ struct mem_dqinfo *info = private; ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct ocfs2_local_disk_dqinfo *ldinfo; ++ ++ ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data + ++ OCFS2_LOCAL_INFO_OFF); ++ spin_lock(&dq_data_lock); ++ ldinfo->dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); ++ ldinfo->dqi_chunks = cpu_to_le32(oinfo->dqi_chunks); ++ ldinfo->dqi_blocks = cpu_to_le32(oinfo->dqi_blocks); ++ spin_unlock(&dq_data_lock); ++} ++ ++/* Read information header from quota file */ ++static int ocfs2_local_read_info(struct super_block *sb, int type) ++{ ++ struct ocfs2_local_disk_dqinfo *ldinfo; ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo; ++ struct inode *lqinode = sb_dqopt(sb)->files[type]; ++ int status; ++ struct buffer_head *bh = NULL; ++ int locked = 0; ++ ++ info->dqi_maxblimit = 0x7fffffffffffffffLL; ++ info->dqi_maxilimit = 0x7fffffffffffffffLL; ++ oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); ++ if (!oinfo) { ++ mlog(ML_ERROR, "failed to allocate memory for ocfs2 quota" ++ " info."); ++ goto out_err; ++ } ++ info->dqi_priv = oinfo; ++ oinfo->dqi_type = type; ++ INIT_LIST_HEAD(&oinfo->dqi_chunk); ++ oinfo->dqi_lqi_bh = NULL; ++ oinfo->dqi_ibh = NULL; ++ ++ status = ocfs2_global_read_info(sb, type); ++ if (status < 0) ++ goto out_err; ++ ++ status = ocfs2_inode_lock(lqinode, &oinfo->dqi_lqi_bh, 1); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ locked = 1; ++ ++ /* Now read local header */ ++ bh = ocfs2_bread(lqinode, 0, &status, 0); ++ if (!bh) { ++ mlog_errno(status); ++ mlog(ML_ERROR, "failed to read quota file info header " ++ "(type=%d)\n", type); ++ goto out_err; ++ } ++ ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data + ++ OCFS2_LOCAL_INFO_OFF); ++ info->dqi_flags = le32_to_cpu(ldinfo->dqi_flags); ++ oinfo->dqi_chunks = le32_to_cpu(ldinfo->dqi_chunks); ++ oinfo->dqi_blocks = le32_to_cpu(ldinfo->dqi_blocks); ++ oinfo->dqi_ibh = bh; ++ ++ /* We crashed when using local quota file? */ ++ if (!(info->dqi_flags & OLQF_CLEAN)) ++ goto out_err; /* So far we just bail out. Later we should resync here */ ++ ++ status = ocfs2_load_local_quota_bitmaps(sb_dqopt(sb)->files[type], ++ ldinfo, ++ &oinfo->dqi_chunk); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ ++ /* Now mark quota file as used */ ++ info->dqi_flags &= ~OLQF_CLEAN; ++ status = ocfs2_modify_bh(lqinode, bh, olq_update_info, info); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ ++ return 0; ++out_err: ++ if (oinfo) { ++ iput(oinfo->dqi_gqinode); ++ ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock); ++ ocfs2_lock_res_free(&oinfo->dqi_gqlock); ++ brelse(oinfo->dqi_lqi_bh); ++ if (locked) ++ ocfs2_inode_unlock(lqinode, 1); ++ ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); ++ kfree(oinfo); ++ } ++ brelse(bh); ++ return -1; ++} ++ ++/* Write local info to quota file */ ++static int ocfs2_local_write_info(struct super_block *sb, int type) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct buffer_head *bh = ((struct ocfs2_mem_dqinfo *)info->dqi_priv) ++ ->dqi_ibh; ++ int status; ++ ++ status = ocfs2_modify_bh(sb_dqopt(sb)->files[type], bh, olq_update_info, ++ info); ++ if (status < 0) { ++ mlog_errno(status); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* Release info from memory */ ++static int ocfs2_local_free_info(struct super_block *sb, int type) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct ocfs2_quota_chunk *chunk; ++ struct ocfs2_local_disk_chunk *dchunk; ++ int mark_clean = 1, len; ++ int status; ++ ++ iput(oinfo->dqi_gqinode); ++ ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock); ++ ocfs2_lock_res_free(&oinfo->dqi_gqlock); ++ list_for_each_entry(chunk, &oinfo->dqi_chunk, qc_chunk) { ++ dchunk = (struct ocfs2_local_disk_chunk *) ++ (chunk->qc_headerbh->b_data); ++ if (chunk->qc_num < oinfo->dqi_chunks - 1) { ++ len = ol_chunk_entries(sb); ++ } else { ++ len = (oinfo->dqi_blocks - ++ ol_quota_chunk_block(sb, chunk->qc_num) - 1) ++ * ol_quota_entries_per_block(sb); ++ } ++ /* Not all entries free? Bug! */ ++ if (le32_to_cpu(dchunk->dqc_free) != len) { ++ mlog(ML_ERROR, "releasing quota file with used " ++ "entries (type=%d)\n", type); ++ mark_clean = 0; ++ } ++ } ++ ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk); ++ ++ if (!mark_clean) ++ goto out; ++ ++ /* Mark local file as clean */ ++ info->dqi_flags |= OLQF_CLEAN; ++ status = ocfs2_modify_bh(sb_dqopt(sb)->files[type], ++ oinfo->dqi_ibh, ++ olq_update_info, ++ info); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ ++out: ++ ocfs2_inode_unlock(sb_dqopt(sb)->files[type], 1); ++ brelse(oinfo->dqi_ibh); ++ brelse(oinfo->dqi_lqi_bh); ++ kfree(oinfo); ++ return 0; ++} ++ ++static void olq_set_dquot(struct buffer_head *bh, void *private) ++{ ++ struct ocfs2_dquot *od = private; ++ struct ocfs2_local_disk_dqblk *dqblk; ++ struct super_block *sb = od->dq_dquot.dq_sb; ++ ++ dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data ++ + ol_dqblk_block_offset(sb, od->dq_local_off)); ++ ++ dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id); ++ spin_lock(&dq_data_lock); ++ dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace - ++ od->dq_origspace); ++ dqblk->dqb_inodemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curinodes - ++ od->dq_originodes); ++ spin_unlock(&dq_data_lock); ++ mlog(0, "Writing local dquot %u space %lld inodes %lld\n", ++ od->dq_dquot.dq_id, dqblk->dqb_spacemod, dqblk->dqb_inodemod); ++} ++ ++/* Write dquot to local quota file */ ++static int ocfs2_local_write_dquot(struct dquot *dquot) ++{ ++ struct super_block *sb = dquot->dq_sb; ++ struct ocfs2_dquot *od = OCFS2_DQUOT(dquot); ++ struct buffer_head *bh; ++ int status; ++ ++ bh = ocfs2_bread(sb_dqopt(sb)->files[dquot->dq_type], ++ ol_dqblk_file_block(sb, od->dq_local_off), ++ &status, 0); ++ if (!bh) { ++ mlog_errno(status); ++ goto out; ++ } ++ status = ocfs2_modify_bh(sb_dqopt(sb)->files[dquot->dq_type], bh, ++ olq_set_dquot, od); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++out: ++ brelse(bh); ++ return status; ++} ++ ++/* Find free entry in local quota file */ ++static struct ocfs2_quota_chunk *ocfs2_find_free_entry(struct super_block *sb, ++ int type, ++ int *offset) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct ocfs2_quota_chunk *chunk; ++ struct ocfs2_local_disk_chunk *dchunk; ++ int found = 0, len; ++ ++ list_for_each_entry(chunk, &oinfo->dqi_chunk, qc_chunk) { ++ dchunk = (struct ocfs2_local_disk_chunk *) ++ chunk->qc_headerbh->b_data; ++ if (le32_to_cpu(dchunk->dqc_free) > 0) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) ++ return NULL; ++ ++ if (chunk->qc_num < oinfo->dqi_chunks - 1) { ++ len = ol_chunk_entries(sb); ++ } else { ++ len = (oinfo->dqi_blocks - ++ ol_quota_chunk_block(sb, chunk->qc_num) - 1) ++ * ol_quota_entries_per_block(sb); ++ } ++ ++ found = ocfs2_find_next_zero_bit(dchunk->dqc_bitmap, len, 0); ++ /* We failed? */ ++ if (found == len) { ++ mlog(ML_ERROR, "Did not find empty entry in chunk %d with %u" ++ " entries free (type=%d)\n", chunk->qc_num, ++ le32_to_cpu(dchunk->dqc_free), type); ++ return ERR_PTR(-EIO); ++ } ++ *offset = found; ++ return chunk; ++} ++ ++/* Add new chunk to the local quota file */ ++static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( ++ struct super_block *sb, ++ int type, ++ int *offset) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct inode *lqinode = sb_dqopt(sb)->files[type]; ++ struct ocfs2_quota_chunk *chunk = NULL; ++ struct ocfs2_local_disk_chunk *dchunk; ++ int status; ++ handle_t *handle; ++ struct buffer_head *bh = NULL; ++ u64 p_blkno; ++ ++ /* We are protected by dqio_sem so no locking needed */ ++ status = ocfs2_extend_no_holes(lqinode, ++ lqinode->i_size + 2 * sb->s_blocksize, ++ lqinode->i_size); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh, ++ lqinode->i_size + 2 * sb->s_blocksize); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ ++ chunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS); ++ if (!chunk) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto out; ++ } ++ ++ down_read(&OCFS2_I(lqinode)->ip_alloc_sem); ++ status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks, ++ &p_blkno, NULL, NULL); ++ up_read(&OCFS2_I(lqinode)->ip_alloc_sem); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ bh = sb_getblk(sb, p_blkno); ++ if (!bh) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto out; ++ } ++ dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data; ++ ++ handle = ocfs2_start_trans(OCFS2_SB(sb), 2); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out; ++ } ++ ++ status = ocfs2_journal_access(handle, lqinode, bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ lock_buffer(bh); ++ dchunk->dqc_free = ol_quota_entries_per_block(sb); ++ memset(dchunk->dqc_bitmap, 0, ++ sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) - ++ OCFS2_QBLK_RESERVED_SPACE); ++ set_buffer_uptodate(bh); ++ unlock_buffer(bh); ++ status = ocfs2_journal_dirty(handle, bh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ ++ oinfo->dqi_blocks += 2; ++ oinfo->dqi_chunks++; ++ status = ocfs2_local_write_info(sb, type); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ status = ocfs2_commit_trans(OCFS2_SB(sb), handle); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ ++ list_add_tail(&chunk->qc_chunk, &oinfo->dqi_chunk); ++ chunk->qc_num = list_entry(chunk->qc_chunk.prev, ++ struct ocfs2_quota_chunk, ++ qc_chunk)->qc_num + 1; ++ chunk->qc_headerbh = bh; ++ *offset = 0; ++ return chunk; ++out_trans: ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++out: ++ brelse(bh); ++ kmem_cache_free(ocfs2_qf_chunk_cachep, chunk); ++ return ERR_PTR(status); ++} ++ ++/* Find free entry in local quota file */ ++static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( ++ struct super_block *sb, ++ int type, ++ int *offset) ++{ ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv; ++ struct ocfs2_quota_chunk *chunk; ++ struct inode *lqinode = sb_dqopt(sb)->files[type]; ++ struct ocfs2_local_disk_chunk *dchunk; ++ int epb = ol_quota_entries_per_block(sb); ++ unsigned int chunk_blocks; ++ int status; ++ handle_t *handle; ++ ++ if (list_empty(&oinfo->dqi_chunk)) ++ return ocfs2_local_quota_add_chunk(sb, type, offset); ++ /* Is the last chunk full? */ ++ chunk = list_entry(oinfo->dqi_chunk.prev, ++ struct ocfs2_quota_chunk, qc_chunk); ++ chunk_blocks = oinfo->dqi_blocks - ++ ol_quota_chunk_block(sb, chunk->qc_num) - 1; ++ if (ol_chunk_blocks(sb) == chunk_blocks) ++ return ocfs2_local_quota_add_chunk(sb, type, offset); ++ ++ /* We are protected by dqio_sem so no locking needed */ ++ status = ocfs2_extend_no_holes(lqinode, ++ lqinode->i_size + sb->s_blocksize, ++ lqinode->i_size); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh, ++ lqinode->i_size + sb->s_blocksize); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ handle = ocfs2_start_trans(OCFS2_SB(sb), 2); ++ if (IS_ERR(handle)) { ++ status = PTR_ERR(handle); ++ mlog_errno(status); ++ goto out; ++ } ++ status = ocfs2_journal_access(handle, lqinode, chunk->qc_headerbh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ ++ dchunk = (struct ocfs2_local_disk_chunk *)chunk->qc_headerbh->b_data; ++ lock_buffer(chunk->qc_headerbh); ++ le32_add_cpu(&dchunk->dqc_free, ol_quota_entries_per_block(sb)); ++ unlock_buffer(chunk->qc_headerbh); ++ status = ocfs2_journal_dirty(handle, chunk->qc_headerbh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ oinfo->dqi_blocks++; ++ status = ocfs2_local_write_info(sb, type); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_trans; ++ } ++ ++ status = ocfs2_commit_trans(OCFS2_SB(sb), handle); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ *offset = chunk_blocks * epb; ++ return chunk; ++out_trans: ++ ocfs2_commit_trans(OCFS2_SB(sb), handle); ++out: ++ return ERR_PTR(status); ++} ++ ++void olq_alloc_dquot(struct buffer_head *bh, void *private) ++{ ++ int *offset = private; ++ struct ocfs2_local_disk_chunk *dchunk; ++ ++ dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data; ++ ocfs2_set_bit(*offset, dchunk->dqc_bitmap); ++ le32_add_cpu(&dchunk->dqc_free, -1); ++} ++ ++/* Create dquot in the local file for given id */ ++static int ocfs2_create_local_dquot(struct dquot *dquot) ++{ ++ struct super_block *sb = dquot->dq_sb; ++ int type = dquot->dq_type; ++ struct inode *lqinode = sb_dqopt(sb)->files[type]; ++ struct ocfs2_quota_chunk *chunk; ++ struct ocfs2_dquot *od = OCFS2_DQUOT(dquot); ++ int offset; ++ int status; ++ ++ chunk = ocfs2_find_free_entry(sb, type, &offset); ++ if (!chunk) { ++ chunk = ocfs2_extend_local_quota_file(sb, type, &offset); ++ if (IS_ERR(chunk)) ++ return PTR_ERR(chunk); ++ } else if (IS_ERR(chunk)) { ++ return PTR_ERR(chunk); ++ } ++ od->dq_local_off = ol_dqblk_off(sb, chunk->qc_num, offset); ++ od->dq_chunk = chunk; ++ ++ /* Initialize dquot structure on disk */ ++ status = ocfs2_local_write_dquot(dquot); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ ++ /* Mark structure as allocated */ ++ status = ocfs2_modify_bh(lqinode, chunk->qc_headerbh, olq_alloc_dquot, ++ &offset); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++out: ++ return status; ++} ++ ++/* Create entry in local file for dquot, load data from the global file */ ++static int ocfs2_local_read_dquot(struct dquot *dquot) ++{ ++ int status; ++ ++ mlog_entry("id=%u, type=%d\n", dquot->dq_id, dquot->dq_type); ++ ++ status = ocfs2_global_read_dquot(dquot); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ ++ /* Now create entry in the local quota file */ ++ status = ocfs2_create_local_dquot(dquot); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out_err; ++ } ++ mlog_exit(0); ++ return 0; ++out_err: ++ mlog_exit(status); ++ return status; ++} ++ ++/* Release dquot structure from local quota file. ocfs2_release_dquot() has ++ * already started a transaction and obtained exclusive lock for global ++ * quota file. */ ++static int ocfs2_local_release_dquot(struct dquot *dquot) ++{ ++ int status; ++ int type = dquot->dq_type; ++ struct ocfs2_dquot *od = OCFS2_DQUOT(dquot); ++ struct super_block *sb = dquot->dq_sb; ++ struct ocfs2_local_disk_chunk *dchunk; ++ int offset; ++ handle_t *handle = journal_current_handle(); ++ ++ BUG_ON(!handle); ++ /* First write all local changes to global file */ ++ status = ocfs2_global_release_dquot(dquot); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ ++ status = ocfs2_journal_access(handle, sb_dqopt(sb)->files[type], ++ od->dq_chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ offset = ol_dqblk_chunk_off(sb, od->dq_chunk->qc_num, ++ od->dq_local_off); ++ dchunk = (struct ocfs2_local_disk_chunk *) ++ (od->dq_chunk->qc_headerbh->b_data); ++ /* Mark structure as freed */ ++ lock_buffer(od->dq_chunk->qc_headerbh); ++ ocfs2_clear_bit(offset, dchunk->dqc_bitmap); ++ le32_add_cpu(&dchunk->dqc_free, 1); ++ unlock_buffer(od->dq_chunk->qc_headerbh); ++ status = ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto out; ++ } ++ status = 0; ++out: ++ /* Clear the read bit so that next time someone uses this ++ * dquot he reads fresh info from disk and allocates local ++ * dquot structure */ ++ clear_bit(DQ_READ_B, &dquot->dq_flags); ++ return status; ++} ++ ++static struct quota_format_ops ocfs2_format_ops = { ++ .check_quota_file = ocfs2_local_check_quota_file, ++ .read_file_info = ocfs2_local_read_info, ++ .write_file_info = ocfs2_global_write_info, ++ .free_file_info = ocfs2_local_free_info, ++ .read_dqblk = ocfs2_local_read_dquot, ++ .commit_dqblk = ocfs2_local_write_dquot, ++ .release_dqblk = ocfs2_local_release_dquot, ++}; ++ ++static struct quota_format_type ocfs2_quota_format = { ++ .qf_fmt_id = QFMT_OCFS2, ++ .qf_ops = &ocfs2_format_ops, ++ .qf_owner = THIS_MODULE ++}; ++ ++int init_ocfs2_quota_format(void) ++{ ++ return register_quota_format(&ocfs2_quota_format); ++} ++ ++void exit_ocfs2_quota_format(void) ++{ ++ unregister_quota_format(&ocfs2_quota_format); ++} +Index: linux-2.6.27-ocfs2/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/super.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/super.c +@@ -65,10 +65,13 @@ + #include "uptodate.h" + #include "ver.h" + #include "xattr.h" ++#include "quota.h" + + #include "buffer_head_io.h" + + static struct kmem_cache *ocfs2_inode_cachep = NULL; ++struct kmem_cache *ocfs2_dquot_cachep; ++struct kmem_cache *ocfs2_qf_chunk_cachep; + + /* OCFS2 needs to schedule several differnt types of work which + * require cluster locking, disk I/O, recovery waits, etc. Since these +@@ -137,6 +140,8 @@ static const struct super_operations ocf + .put_super = ocfs2_put_super, + .remount_fs = ocfs2_remount, + .show_options = ocfs2_show_options, ++ .quota_read = ocfs2_quota_read, ++ .quota_write = ocfs2_quota_write, + }; + + enum { +@@ -1073,6 +1078,7 @@ static int ocfs2_show_options(struct seq + static int __init ocfs2_init(void) + { + int status; ++ int added_format = 0; + + mlog_entry_void(); + +@@ -1090,6 +1096,13 @@ static int __init ocfs2_init(void) + goto leave; + } + ++ status = init_ocfs2_quota_format(); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ added_format = 1; ++ + ocfs2_wq = create_singlethread_workqueue("ocfs2_wq"); + if (!ocfs2_wq) { + status = -ENOMEM; +@@ -1108,6 +1121,8 @@ leave: + if (status < 0) { + ocfs2_free_mem_caches(); + exit_ocfs2_uptodate_cache(); ++ if (added_format) ++ exit_ocfs2_quota_format(); + } + + mlog_exit(status); +@@ -1127,6 +1142,8 @@ static void __exit ocfs2_exit(void) + destroy_workqueue(ocfs2_wq); + } + ++ exit_ocfs2_quota_format(); ++ + debugfs_remove(ocfs2_debugfs_root); + + ocfs2_free_mem_caches(); +@@ -1242,8 +1259,27 @@ static int ocfs2_initialize_mem_caches(v + (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + ocfs2_inode_init_once); +- if (!ocfs2_inode_cachep) ++ ocfs2_dquot_cachep = kmem_cache_create("ocfs2_dquot_cache", ++ sizeof(struct ocfs2_dquot), ++ 0, ++ (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| ++ SLAB_MEM_SPREAD), ++ NULL); ++ ocfs2_qf_chunk_cachep = kmem_cache_create("ocfs2_qf_chunk_cache", ++ sizeof(struct ocfs2_quota_chunk), ++ 0, ++ (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), ++ NULL); ++ if (!ocfs2_inode_cachep || !ocfs2_dquot_cachep || ++ !ocfs2_qf_chunk_cachep) { ++ if (ocfs2_inode_cachep) ++ kmem_cache_destroy(ocfs2_inode_cachep); ++ if (ocfs2_dquot_cachep) ++ kmem_cache_destroy(ocfs2_dquot_cachep); ++ if (ocfs2_qf_chunk_cachep) ++ kmem_cache_destroy(ocfs2_qf_chunk_cachep); + return -ENOMEM; ++ } + + return 0; + } +@@ -1252,8 +1288,15 @@ static void ocfs2_free_mem_caches(void) + { + if (ocfs2_inode_cachep) + kmem_cache_destroy(ocfs2_inode_cachep); +- + ocfs2_inode_cachep = NULL; ++ ++ if (ocfs2_dquot_cachep) ++ kmem_cache_destroy(ocfs2_dquot_cachep); ++ ocfs2_dquot_cachep = NULL; ++ ++ if (ocfs2_qf_chunk_cachep) ++ kmem_cache_destroy(ocfs2_qf_chunk_cachep); ++ ocfs2_qf_chunk_cachep = NULL; + } + + static int ocfs2_get_sector(struct super_block *sb, +Index: linux-2.6.27-ocfs2/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/dir.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/dir.c +@@ -82,8 +82,8 @@ static int ocfs2_do_extend_dir(struct su + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **new_bh); + +-static struct buffer_head *ocfs2_bread(struct inode *inode, +- int block, int *err, int reada) ++struct buffer_head *ocfs2_bread(struct inode *inode, ++ int block, int *err, int reada) + { + struct buffer_head *bh = NULL; + int tmperr; +Index: linux-2.6.27-ocfs2/fs/ocfs2/inode.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/inode.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/inode.h +@@ -142,6 +142,8 @@ int ocfs2_mark_inode_dirty(handle_t *han + struct buffer_head *bh); + int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb); + int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb); ++struct buffer_head *ocfs2_bread(struct inode *inode, ++ int block, int *err, int reada); + + void ocfs2_set_inode_flags(struct inode *inode); + void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Improve-ocfs2_read_xattr_bucket.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Improve-ocfs2_read_xattr_bucket.patch new file mode 100644 index 000000000..57fa3455c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Improve-ocfs2_read_xattr_bucket.patch @@ -0,0 +1,322 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 17:33:40 -0700 +Subject: ocfs2: Improve ocfs2_read_xattr_bucket(). +Patch-mainline: 2.6.29 + +The ocfs2_read_xattr_bucket() function would read an xattr bucket into a +list of buffer heads. However, we have a nice ocfs2_xattr_bucket +structure. Let's have it fill that out instead. + +In addition, ocfs2_read_xattr_bucket() would initialize buffer heads for +a bucket that's never been on disk before. That's confusing. Let's +call that functionality ocfs2_init_xattr_bucket(). + +The functions ocfs2_cp_xattr_bucket() and ocfs2_half_xattr_bucket() are +updated to use the ocfs2_xattr_bucket structure rather than raw bh +lists. That way they can use the new read/init calls. In addition, +they drop the wasted read of an existing target bucket. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 165 ++++++++++++++++++++++++++---------------------------- + 1 files changed, 79 insertions(+), 86 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 3478ad1..fa13fa4 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -168,6 +168,48 @@ static void ocfs2_xattr_bucket_relse(struct inode *inode, + } + } + ++/* ++ * A bucket that has never been written to disk doesn't need to be ++ * read. We just need the buffer_heads. Don't call this for ++ * buckets that are already on disk. ocfs2_read_xattr_bucket() initializes ++ * them fully. ++ */ ++static int ocfs2_init_xattr_bucket(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ u64 xb_blkno) ++{ ++ int i, rc = 0; ++ int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ for (i = 0; i < blks; i++) { ++ bucket->bu_bhs[i] = sb_getblk(inode->i_sb, xb_blkno + i); ++ if (!bucket->bu_bhs[i]) { ++ rc = -EIO; ++ mlog_errno(rc); ++ break; ++ } ++ ++ ocfs2_set_new_buffer_uptodate(inode, bucket->bu_bhs[i]); ++ } ++ ++ if (rc) ++ ocfs2_xattr_bucket_relse(inode, bucket); ++ return rc; ++} ++ ++/* Read the xattr bucket at xb_blkno */ ++static int ocfs2_read_xattr_bucket(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ u64 xb_blkno) ++{ ++ int rc, blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ rc = ocfs2_read_blocks(inode, xb_blkno, blks, bucket->bu_bhs, 0); ++ if (rc) ++ ocfs2_xattr_bucket_relse(inode, bucket); ++ return rc; ++} ++ + static inline const char *ocfs2_xattr_prefix(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -3097,31 +3139,6 @@ out: + return ret; + } + +-static int ocfs2_read_xattr_bucket(struct inode *inode, +- u64 blkno, +- struct buffer_head **bhs, +- int new) +-{ +- int ret = 0; +- u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- +- if (!new) +- return ocfs2_read_blocks(inode, blkno, +- blk_per_bucket, bhs, 0); +- +- for (i = 0; i < blk_per_bucket; i++) { +- bhs[i] = sb_getblk(inode->i_sb, blkno + i); +- if (bhs[i] == NULL) { +- ret = -EIO; +- mlog_errno(ret); +- break; +- } +- ocfs2_set_new_buffer_uptodate(inode, bhs[i]); +- } +- +- return ret; +-} +- + /* + * Find the suitable pos when we divide a bucket into 2. + * We have to make sure the xattrs with the same hash value exist +@@ -3184,7 +3201,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + int ret, i; + int count, start, len, name_value_len = 0, xe_len, name_offset = 0; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- struct buffer_head **s_bhs, **t_bhs = NULL; ++ struct ocfs2_xattr_bucket s_bucket, t_bucket; + struct ocfs2_xattr_header *xh; + struct ocfs2_xattr_entry *xe; + int blocksize = inode->i_sb->s_blocksize; +@@ -3192,37 +3209,34 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + mlog(0, "move some of xattrs from bucket %llu to %llu\n", + (unsigned long long)blk, (unsigned long long)new_blk); + +- s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); +- if (!s_bhs) +- return -ENOMEM; ++ memset(&s_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); ++ memset(&t_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); + +- ret = ocfs2_read_xattr_bucket(inode, blk, s_bhs, 0); ++ ret = ocfs2_read_xattr_bucket(inode, &s_bucket, blk); + if (ret) { + mlog_errno(ret); + goto out; + } + +- ret = ocfs2_journal_access(handle, inode, s_bhs[0], ++ ret = ocfs2_journal_access(handle, inode, s_bucket.bu_bhs[0], + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; + } + +- t_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS); +- if (!t_bhs) { +- ret = -ENOMEM; +- goto out; +- } +- +- ret = ocfs2_read_xattr_bucket(inode, new_blk, t_bhs, new_bucket_head); ++ /* ++ * Even if !new_bucket_head, we're overwriting t_bucket. Thus, ++ * there's no need to read it. ++ */ ++ ret = ocfs2_init_xattr_bucket(inode, &t_bucket, new_blk); + if (ret) { + mlog_errno(ret); + goto out; + } + + for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, t_bhs[i], ++ ret = ocfs2_journal_access(handle, inode, t_bucket.bu_bhs[i], + new_bucket_head ? + OCFS2_JOURNAL_ACCESS_CREATE : + OCFS2_JOURNAL_ACCESS_WRITE); +@@ -3232,7 +3246,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + } + } + +- xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; ++ xh = bucket_xh(&s_bucket); + count = le16_to_cpu(xh->xh_count); + start = ocfs2_xattr_find_divide_pos(xh); + +@@ -3245,9 +3259,9 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + * that of the last entry in the previous bucket. + */ + for (i = 0; i < blk_per_bucket; i++) +- memset(t_bhs[i]->b_data, 0, blocksize); ++ memset(bucket_block(&t_bucket, i), 0, blocksize); + +- xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; ++ xh = bucket_xh(&t_bucket); + xh->xh_free_start = cpu_to_le16(blocksize); + xh->xh_entries[0].xe_name_hash = xe->xe_name_hash; + le32_add_cpu(&xh->xh_entries[0].xe_name_hash, 1); +@@ -3257,10 +3271,11 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + + /* copy the whole bucket to the new first. */ + for (i = 0; i < blk_per_bucket; i++) +- memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); ++ memcpy(bucket_block(&t_bucket, i), bucket_block(&s_bucket, i), ++ blocksize); + + /* update the new bucket. */ +- xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data; ++ xh = bucket_xh(&t_bucket); + + /* + * Calculate the total name/value len and xh_free_start for +@@ -3325,7 +3340,7 @@ set_num_buckets: + xh->xh_num_buckets = 0; + + for (i = 0; i < blk_per_bucket; i++) { +- ocfs2_journal_dirty(handle, t_bhs[i]); ++ ocfs2_journal_dirty(handle, t_bucket.bu_bhs[i]); + if (ret) + mlog_errno(ret); + } +@@ -3342,29 +3357,20 @@ set_num_buckets: + if (start == count) + goto out; + +- xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data; ++ xh = bucket_xh(&s_bucket); + memset(&xh->xh_entries[start], 0, + sizeof(struct ocfs2_xattr_entry) * (count - start)); + xh->xh_count = cpu_to_le16(start); + xh->xh_free_start = cpu_to_le16(name_offset); + xh->xh_name_value_len = cpu_to_le16(name_value_len); + +- ocfs2_journal_dirty(handle, s_bhs[0]); ++ ocfs2_journal_dirty(handle, s_bucket.bu_bhs[0]); + if (ret) + mlog_errno(ret); + + out: +- if (s_bhs) { +- for (i = 0; i < blk_per_bucket; i++) +- brelse(s_bhs[i]); +- } +- kfree(s_bhs); +- +- if (t_bhs) { +- for (i = 0; i < blk_per_bucket; i++) +- brelse(t_bhs[i]); +- } +- kfree(t_bhs); ++ ocfs2_xattr_bucket_relse(inode, &s_bucket); ++ ocfs2_xattr_bucket_relse(inode, &t_bucket); + + return ret; + } +@@ -3384,7 +3390,7 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + int ret, i; + int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + int blocksize = inode->i_sb->s_blocksize; +- struct buffer_head **s_bhs, **t_bhs = NULL; ++ struct ocfs2_xattr_bucket s_bucket, t_bucket; + + BUG_ON(s_blkno == t_blkno); + +@@ -3392,28 +3398,23 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + (unsigned long long)s_blkno, (unsigned long long)t_blkno, + t_is_new); + +- s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, +- GFP_NOFS); +- if (!s_bhs) +- return -ENOMEM; ++ memset(&s_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); ++ memset(&t_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); + +- ret = ocfs2_read_xattr_bucket(inode, s_blkno, s_bhs, 0); ++ ret = ocfs2_read_xattr_bucket(inode, &s_bucket, s_blkno); + if (ret) + goto out; + +- t_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, +- GFP_NOFS); +- if (!t_bhs) { +- ret = -ENOMEM; +- goto out; +- } +- +- ret = ocfs2_read_xattr_bucket(inode, t_blkno, t_bhs, t_is_new); ++ /* ++ * Even if !t_is_new, we're overwriting t_bucket. Thus, ++ * there's no need to read it. ++ */ ++ ret = ocfs2_init_xattr_bucket(inode, &t_bucket, t_blkno); + if (ret) + goto out; + + for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, t_bhs[i], ++ ret = ocfs2_journal_access(handle, inode, t_bucket.bu_bhs[i], + t_is_new ? + OCFS2_JOURNAL_ACCESS_CREATE : + OCFS2_JOURNAL_ACCESS_WRITE); +@@ -3422,22 +3423,14 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + } + + for (i = 0; i < blk_per_bucket; i++) { +- memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize); +- ocfs2_journal_dirty(handle, t_bhs[i]); ++ memcpy(bucket_block(&t_bucket, i), bucket_block(&s_bucket, i), ++ blocksize); ++ ocfs2_journal_dirty(handle, t_bucket.bu_bhs[i]); + } + + out: +- if (s_bhs) { +- for (i = 0; i < blk_per_bucket; i++) +- brelse(s_bhs[i]); +- } +- kfree(s_bhs); +- +- if (t_bhs) { +- for (i = 0; i < blk_per_bucket; i++) +- brelse(t_bhs[i]); +- } +- kfree(t_bhs); ++ ocfs2_xattr_bucket_relse(inode, &s_bucket); ++ ocfs2_xattr_bucket_relse(inode, &t_bucket); + + return ret; + } +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Kill-the-last-naked-wait_on_buffer-for-cach.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Kill-the-last-naked-wait_on_buffer-for-cach.patch new file mode 100644 index 000000000..0597e0d79 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Kill-the-last-naked-wait_on_buffer-for-cach.patch @@ -0,0 +1,36 @@ +From: Joel Becker +Subject: ocfs2: Kill the last naked wait_on_buffer() for cached reads. +Patch-mainline: 2.6.28 + +ocfs2's cached buffer I/O goes through ocfs2_read_block(s)(). dir.c had +a naked wait_on_buffer() to wait for some readahead, but it should +use ocfs2_read_block() instead. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dir.c | 7 +++---- + 1 files changed, 3 insertions(+), 4 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dir.c ++++ linux-2.6.27/fs/ocfs2/dir.c +@@ -302,14 +302,13 @@ restart: + } + if ((bh = bh_use[ra_ptr++]) == NULL) + goto next; +- wait_on_buffer(bh); +- if (!buffer_uptodate(bh)) { +- /* read error, skip block & hope for the best */ ++ if (ocfs2_read_block(dir, block, &bh)) { ++ /* read error, skip block & hope for the best. ++ * ocfs2_read_block() has released the bh. */ + ocfs2_error(dir->i_sb, "reading directory %llu, " + "offset %lu\n", + (unsigned long long)OCFS2_I(dir)->ip_blkno, + block); +- brelse(bh); + goto next; + } + i = ocfs2_search_dirblock(bh, dir, name, namelen, diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Limit-inode-allocation-to-32bits.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Limit-inode-allocation-to-32bits.patch new file mode 100644 index 000000000..775f3b3e0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Limit-inode-allocation-to-32bits.patch @@ -0,0 +1,357 @@ +From: Joel Becker +Subject: ocfs2: Limit inode allocation to 32bits. +Patch-mainline: 2.6.28? +References: FATE302877 + +ocfs2 inode numbers are block numbers. For any filesystem with less +than 2^32 blocks, this is not a problem. However, when ocfs2 starts +using JDB2, it will be able to support filesystems with more than 2^32 +blocks. This would result in inode numbers higher than 2^32. + +The problem is that stat(2) can't handle those numbers on 32bit +machines. The simple solution is to have ocfs2 allocate all inodes +below that boundary. + +The suballoc code is changed to honor an optional block limit. Only the +inode suballocator sets that limit - all other allocations stay unlimited. + +The biggest trick is to grow the inode suballocator beneath that limit. +There's no point in allocating block groups that are above the limit, +then rejecting their elements later on. We want to prevent the inode +allocator from ever having block groups above the limit. This involves +a little gyration with the local alloc code. If the local alloc window +is above the limit, it signals the caller to try the global bitmap but +does not disable the local alloc file (which can be used for other +allocations). + +[ Minor cleanup - removed an ML_NOTICE comment. --Mark ] + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/localalloc.c | 55 +++++++++++++++++++++++++++++++ + fs/ocfs2/suballoc.c | 86 ++++++++++++++++++++++++++++++++++++++++---------- + fs/ocfs2/suballoc.h | 11 ++++-- + 3 files changed, 132 insertions(+), 20 deletions(-) + +--- a/fs/ocfs2/localalloc.c ++++ b/fs/ocfs2/localalloc.c +@@ -453,6 +453,46 @@ out: + return status; + } + ++/* Check to see if the local alloc window is within ac->ac_max_block */ ++static int ocfs2_local_alloc_in_range(struct inode *inode, ++ struct ocfs2_alloc_context *ac, ++ u32 bits_wanted) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_dinode *alloc; ++ struct ocfs2_local_alloc *la; ++ int start; ++ u64 block_off; ++ ++ if (!ac->ac_max_block) ++ return 1; ++ ++ alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data; ++ la = OCFS2_LOCAL_ALLOC(alloc); ++ ++ start = ocfs2_local_alloc_find_clear_bits(osb, alloc, bits_wanted); ++ if (start == -1) { ++ mlog_errno(-ENOSPC); ++ return 0; ++ } ++ ++ /* ++ * Converting (bm_off + start + bits_wanted) to blocks gives us ++ * the blkno just past our actual allocation. This is perfect ++ * to compare with ac_max_block. ++ */ ++ block_off = ocfs2_clusters_to_blocks(inode->i_sb, ++ le32_to_cpu(la->la_bm_off) + ++ start + bits_wanted); ++ mlog(0, "Checking %llu against %llu\n", ++ (unsigned long long)block_off, ++ (unsigned long long)ac->ac_max_block); ++ if (block_off > ac->ac_max_block) ++ return 0; ++ ++ return 1; ++} ++ + /* + * make sure we've got at least bitswanted contiguous bits in the + * local alloc. You lose them when you drop i_mutex. +@@ -524,6 +564,21 @@ int ocfs2_reserve_local_alloc_bits(struc + } + } + ++ if (ac->ac_max_block) ++ mlog(0, "Calling in_range for max block %llu\n", ++ (unsigned long long)ac->ac_max_block); ++ ++ if (!ocfs2_local_alloc_in_range(local_alloc_inode, ac, ++ bits_wanted)) { ++ /* ++ * The window is outside ac->ac_max_block. ++ * This errno tells the caller to keep localalloc enabled ++ * but to get the allocation from the main bitmap. ++ */ ++ status = -EFBIG; ++ goto bail; ++ } ++ + ac->ac_inode = local_alloc_inode; + /* We should never use localalloc from another slot */ + ac->ac_alloc_slot = osb->slot_num; +--- a/fs/ocfs2/suballoc.c ++++ b/fs/ocfs2/suballoc.c +@@ -62,15 +62,18 @@ static int ocfs2_block_group_fill(handle + struct ocfs2_chain_list *cl); + static int ocfs2_block_group_alloc(struct ocfs2_super *osb, + struct inode *alloc_inode, +- struct buffer_head *bh); ++ struct buffer_head *bh, ++ u64 max_block); + + static int ocfs2_cluster_group_search(struct inode *inode, + struct buffer_head *group_bh, + u32 bits_wanted, u32 min_bits, ++ u64 max_block, + u16 *bit_off, u16 *bits_found); + static int ocfs2_block_group_search(struct inode *inode, + struct buffer_head *group_bh, + u32 bits_wanted, u32 min_bits, ++ u64 max_block, + u16 *bit_off, u16 *bits_found); + static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, + struct ocfs2_alloc_context *ac, +@@ -110,6 +113,9 @@ static inline void ocfs2_block_to_cluste + u64 data_blkno, + u64 *bg_blkno, + u16 *bg_bit_off); ++static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb, ++ u32 bits_wanted, u64 max_block, ++ struct ocfs2_alloc_context **ac); + + static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) + { +@@ -276,7 +282,8 @@ static inline u16 ocfs2_find_smallest_ch + */ + static int ocfs2_block_group_alloc(struct ocfs2_super *osb, + struct inode *alloc_inode, +- struct buffer_head *bh) ++ struct buffer_head *bh, ++ u64 max_block) + { + int status, credits; + struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data; +@@ -294,9 +301,9 @@ static int ocfs2_block_group_alloc(struc + mlog_entry_void(); + + cl = &fe->id2.i_chain; +- status = ocfs2_reserve_clusters(osb, +- le16_to_cpu(cl->cl_cpg), +- &ac); ++ status = ocfs2_reserve_clusters_with_limit(osb, ++ le16_to_cpu(cl->cl_cpg), ++ max_block, &ac); + if (status < 0) { + if (status != -ENOSPC) + mlog_errno(status); +@@ -469,7 +476,8 @@ static int ocfs2_reserve_suballoc_bits(s + goto bail; + } + +- status = ocfs2_block_group_alloc(osb, alloc_inode, bh); ++ status = ocfs2_block_group_alloc(osb, alloc_inode, bh, ++ ac->ac_max_block); + if (status < 0) { + if (status != -ENOSPC) + mlog_errno(status); +@@ -591,6 +599,13 @@ int ocfs2_reserve_new_inode(struct ocfs2 + (*ac)->ac_group_search = ocfs2_block_group_search; + + /* ++ * stat(2) can't handle i_ino > 32bits, so we tell the ++ * lower levels not to allocate us a block group past that ++ * limit. ++ */ ++ (*ac)->ac_max_block = (u32)~0U; ++ ++ /* + * slot is set when we successfully steal inode from other nodes. + * It is reset in 3 places: + * 1. when we flush the truncate log +@@ -670,9 +685,9 @@ bail: + /* Callers don't need to care which bitmap (local alloc or main) to + * use so we figure it out for them, but unfortunately this clutters + * things a bit. */ +-int ocfs2_reserve_clusters(struct ocfs2_super *osb, +- u32 bits_wanted, +- struct ocfs2_alloc_context **ac) ++static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb, ++ u32 bits_wanted, u64 max_block, ++ struct ocfs2_alloc_context **ac) + { + int status; + +@@ -686,16 +701,14 @@ int ocfs2_reserve_clusters(struct ocfs2_ + } + + (*ac)->ac_bits_wanted = bits_wanted; ++ (*ac)->ac_max_block = max_block; + + status = -ENOSPC; + if (ocfs2_alloc_should_use_local(osb, bits_wanted)) { + status = ocfs2_reserve_local_alloc_bits(osb, + bits_wanted, + *ac); +- if ((status < 0) && (status != -ENOSPC)) { +- mlog_errno(status); +- goto bail; +- } else if (status == -ENOSPC) { ++ if (status == -ENOSPC) { + /* reserve_local_bits will return enospc with + * the local alloc inode still locked, so we + * can change this safely here. */ +@@ -704,6 +717,14 @@ int ocfs2_reserve_clusters(struct ocfs2_ + * can clean up what's left of the local + * allocation */ + osb->local_alloc_state = OCFS2_LA_DISABLED; ++ } else if (status == -EFBIG) { ++ /* The local alloc window is outside ac_max_block. ++ * use the main bitmap, but don't disable ++ * local alloc. */ ++ status = -ENOSPC; ++ } else if (status < 0) { ++ mlog_errno(status); ++ goto bail; + } + } + +@@ -727,6 +748,13 @@ bail: + return status; + } + ++int ocfs2_reserve_clusters(struct ocfs2_super *osb, ++ u32 bits_wanted, ++ struct ocfs2_alloc_context **ac) ++{ ++ return ocfs2_reserve_clusters_with_limit(osb, bits_wanted, 0, ac); ++} ++ + /* + * More or less lifted from ext3. I'll leave their description below: + * +@@ -1009,10 +1037,12 @@ static inline int ocfs2_block_group_reas + static int ocfs2_cluster_group_search(struct inode *inode, + struct buffer_head *group_bh, + u32 bits_wanted, u32 min_bits, ++ u64 max_block, + u16 *bit_off, u16 *bits_found) + { + int search = -ENOSPC; + int ret; ++ u64 blkoff; + struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data; + u16 tmp_off, tmp_found; + unsigned int max_bits, gd_cluster_off; +@@ -1046,6 +1076,17 @@ static int ocfs2_cluster_group_search(st + if (ret) + return ret; + ++ if (max_block) { ++ blkoff = ocfs2_clusters_to_blocks(inode->i_sb, ++ gd_cluster_off + ++ tmp_off + tmp_found); ++ mlog(0, "Checking %llu against %llu\n", ++ (unsigned long long)blkoff, ++ (unsigned long long)max_block); ++ if (blkoff > max_block) ++ return -ENOSPC; ++ } ++ + /* ocfs2_block_group_find_clear_bits() might + * return success, but we still want to return + * -ENOSPC unless it found the minimum number +@@ -1063,19 +1104,31 @@ static int ocfs2_cluster_group_search(st + static int ocfs2_block_group_search(struct inode *inode, + struct buffer_head *group_bh, + u32 bits_wanted, u32 min_bits, ++ u64 max_block, + u16 *bit_off, u16 *bits_found) + { + int ret = -ENOSPC; ++ u64 blkoff; + struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data; + + BUG_ON(min_bits != 1); + BUG_ON(ocfs2_is_cluster_bitmap(inode)); + +- if (bg->bg_free_bits_count) ++ if (bg->bg_free_bits_count) { + ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb), + group_bh, bits_wanted, + le16_to_cpu(bg->bg_bits), + bit_off, bits_found); ++ if (!ret && max_block) { ++ blkoff = le64_to_cpu(bg->bg_blkno) + *bit_off + ++ *bits_found; ++ mlog(0, "Checking %llu against %llu\n", ++ (unsigned long long)blkoff, ++ (unsigned long long)max_block); ++ if (blkoff > max_block) ++ ret = -ENOSPC; ++ } ++ } + + return ret; + } +@@ -1140,7 +1193,7 @@ static int ocfs2_search_one_group(struct + } + + ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits, +- bit_off, &found); ++ ac->ac_max_block, bit_off, &found); + if (ret < 0) { + if (ret != -ENOSPC) + mlog_errno(ret); +@@ -1213,7 +1266,8 @@ static int ocfs2_search_chain(struct ocf + /* for now, the chain search is a bit simplistic. We just use + * the 1st group with any empty bits. */ + while ((status = ac->ac_group_search(alloc_inode, group_bh, +- bits_wanted, min_bits, bit_off, ++ bits_wanted, min_bits, ++ ac->ac_max_block, bit_off, + &tmp_bits)) == -ENOSPC) { + if (!bg->bg_next_group) + break; +--- a/fs/ocfs2/suballoc.h ++++ b/fs/ocfs2/suballoc.h +@@ -28,10 +28,11 @@ + + typedef int (group_search_t)(struct inode *, + struct buffer_head *, +- u32, +- u32, +- u16 *, +- u16 *); ++ u32, /* bits_wanted */ ++ u32, /* min_bits */ ++ u64, /* max_block */ ++ u16 *, /* *bit_off */ ++ u16 *); /* *bits_found */ + + struct ocfs2_alloc_context { + struct inode *ac_inode; /* which bitmap are we allocating from? */ +@@ -51,6 +52,8 @@ struct ocfs2_alloc_context { + group_search_t *ac_group_search; + + u64 ac_last_group; ++ u64 ac_max_block; /* Highest block number to allocate. 0 is ++ is the same as ~0 - unlimited */ + }; + + void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-cached-block-reads-the-common-case.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-cached-block-reads-the-common-case.patch new file mode 100644 index 000000000..23eb293ab --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-cached-block-reads-the-common-case.patch @@ -0,0 +1,205 @@ +From: Joel Becker +Subject: ocfs2: Make cached block reads the common case. +Patch-mainline: 2.6.28 + +ocfs2_read_blocks() currently requires the CACHED flag for cached I/O. +However, that's the common case. Let's flip it around and provide an +IGNORE_CACHE flag for the special users. This has the added benefit of +cleaning up the code some (ignore_cache takes on its special meaning +earlier in the loop). + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/buffer_head_io.c | 19 +++++++++++-------- + fs/ocfs2/buffer_head_io.h | 4 ++-- + fs/ocfs2/dir.c | 2 +- + fs/ocfs2/inode.c | 3 ++- + fs/ocfs2/journal.c | 3 ++- + fs/ocfs2/localalloc.c | 4 ++-- + fs/ocfs2/slot_map.c | 6 ++++-- + 7 files changed, 24 insertions(+), 17 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.c ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.c +@@ -181,7 +181,8 @@ int ocfs2_read_blocks(struct inode *inod + inode, (unsigned long long)block, nr, flags); + + BUG_ON(!inode); +- BUG_ON((flags & OCFS2_BH_READAHEAD) && !(flags & OCFS2_BH_CACHED)); ++ BUG_ON((flags & OCFS2_BH_READAHEAD) && ++ (flags & OCFS2_BH_IGNORE_CACHE)); + + if (bhs == NULL) { + status = -EINVAL; +@@ -214,7 +215,7 @@ int ocfs2_read_blocks(struct inode *inod + } + } + bh = bhs[i]; +- ignore_cache = 0; ++ ignore_cache = (flags & OCFS2_BH_IGNORE_CACHE); + + /* There are three read-ahead cases here which we need to + * be concerned with. All three assume a buffer has +@@ -240,26 +241,27 @@ int ocfs2_read_blocks(struct inode *inod + * before our is-it-in-flight check. + */ + +- if (flags & OCFS2_BH_CACHED && +- !ocfs2_buffer_uptodate(inode, bh)) { ++ if (!ignore_cache && !ocfs2_buffer_uptodate(inode, bh)) { + mlog(ML_UPTODATE, + "bh (%llu), inode %llu not uptodate\n", + (unsigned long long)bh->b_blocknr, + (unsigned long long)OCFS2_I(inode)->ip_blkno); ++ /* We're using ignore_cache here to say ++ * "go to disk" */ + ignore_cache = 1; + } + + /* XXX: Can we ever get this and *not* have the cached + * flag set? */ + if (buffer_jbd(bh)) { +- if (!(flags & OCFS2_BH_CACHED) || ignore_cache) ++ if (ignore_cache) + mlog(ML_BH_IO, "trying to sync read a jbd " + "managed bh (blocknr = %llu)\n", + (unsigned long long)bh->b_blocknr); + continue; + } + +- if (!(flags & OCFS2_BH_CACHED) || ignore_cache) { ++ if (ignore_cache) { + if (buffer_dirty(bh)) { + /* This should probably be a BUG, or + * at least return an error. */ +@@ -294,7 +296,7 @@ int ocfs2_read_blocks(struct inode *inod + * previously read-ahead buffer may have + * completed I/O while we were waiting for the + * buffer lock. */ +- if ((flags & OCFS2_BH_CACHED) ++ if (!(flags & OCFS2_BH_IGNORE_CACHE) + && !(flags & OCFS2_BH_READAHEAD) + && ocfs2_buffer_uptodate(inode, bh)) { + unlock_buffer(bh); +@@ -344,7 +346,8 @@ int ocfs2_read_blocks(struct inode *inod + + mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n", + (unsigned long long)block, nr, +- (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes", flags); ++ ((flags & OCFS2_BH_IGNORE_CACHE) || ignore_cache) ? "no" : "yes", ++ flags); + + bail: + +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.h ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.h +@@ -49,7 +49,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_ + int ocfs2_write_super_or_backup(struct ocfs2_super *osb, + struct buffer_head *bh); + +-#define OCFS2_BH_CACHED 1 ++#define OCFS2_BH_IGNORE_CACHE 1 + #define OCFS2_BH_READAHEAD 8 + + static inline int ocfs2_read_block(struct inode *inode, u64 off, +@@ -63,7 +63,7 @@ static inline int ocfs2_read_block(struc + goto bail; + } + +- status = ocfs2_read_blocks(inode, off, 1, bh, OCFS2_BH_CACHED); ++ status = ocfs2_read_blocks(inode, off, 1, bh, 0); + + bail: + return status; +Index: linux-2.6.27/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dir.c ++++ linux-2.6.27/fs/ocfs2/dir.c +@@ -88,7 +88,7 @@ static struct buffer_head *ocfs2_bread(s + struct buffer_head *bh = NULL; + int tmperr; + u64 p_blkno; +- int readflags = OCFS2_BH_CACHED; ++ int readflags = 0; + + if (reada) + readflags |= OCFS2_BH_READAHEAD; +Index: linux-2.6.27/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.c ++++ linux-2.6.27/fs/ocfs2/inode.c +@@ -461,7 +461,8 @@ static int ocfs2_read_locked_inode(struc + } + + if (can_lock) +- status = ocfs2_read_blocks(inode, args->fi_blkno, 1, &bh, 0); ++ status = ocfs2_read_blocks(inode, args->fi_blkno, 1, &bh, ++ OCFS2_BH_IGNORE_CACHE); + else + status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); + if (status < 0) { +Index: linux-2.6.27/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/journal.c ++++ linux-2.6.27/fs/ocfs2/journal.c +@@ -1134,7 +1134,8 @@ static int ocfs2_read_journal_inode(stru + } + SET_INODE_JOURNAL(inode); + +- status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, bh, 0); ++ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, bh, ++ OCFS2_BH_IGNORE_CACHE); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -249,7 +249,7 @@ int ocfs2_load_local_alloc(struct ocfs2_ + } + + status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, +- &alloc_bh, 0); ++ &alloc_bh, OCFS2_BH_IGNORE_CACHE); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -460,7 +460,7 @@ int ocfs2_begin_local_alloc_recovery(str + mutex_lock(&inode->i_mutex); + + status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, +- &alloc_bh, 0); ++ &alloc_bh, OCFS2_BH_IGNORE_CACHE); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/slot_map.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/slot_map.c ++++ linux-2.6.27/fs/ocfs2/slot_map.c +@@ -150,7 +150,8 @@ int ocfs2_refresh_slot_info(struct ocfs2 + * be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If + * this is not true, the read of -1 (UINT64_MAX) will fail. + */ +- ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh, 0); ++ ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh, ++ OCFS2_BH_IGNORE_CACHE); + if (ret == 0) { + spin_lock(&osb->osb_lock); + ocfs2_update_slot_info(si); +@@ -403,7 +404,8 @@ static int ocfs2_map_slot_buffers(struct + (unsigned long long)blkno); + + bh = NULL; /* Acquire a fresh bh */ +- status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh, 0); ++ status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh, ++ OCFS2_BH_IGNORE_CACHE); + if (status < 0) { + mlog_errno(status); + goto bail; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-high-level-btree-extend-co.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-high-level-btree-extend-co.patch new file mode 100644 index 000000000..96b9e233e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-high-level-btree-extend-co.patch @@ -0,0 +1,420 @@ +From: Tao Ma +Subject: [PATCH 04/16] ocfs2: Make high level btree extend code generic +Patch-mainline: 2.6.28? +References: FATE302067 + +Factor out the non-inode specifics of ocfs2_do_extend_allocation() into a more generic +function, ocfs2_do_cluster_allocation(). ocfs2_do_extend_allocation calls +ocfs2_do_cluster_allocation() now, but the latter can be used for other +btree types as well. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 110 ++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/alloc.h | 17 ++++++ + fs/ocfs2/aops.c | 8 +-- + fs/ocfs2/dir.c | 6 +- + fs/ocfs2/file.c | 136 ++++++++++--------------------------------------------- + fs/ocfs2/file.h | 26 ++++------ + fs/ocfs2/namei.c | 8 +-- + 7 files changed, 176 insertions(+), 135 deletions(-) + +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -4302,6 +4302,116 @@ bail: + return status; + } + ++/* ++ * Allcate and add clusters into the extent b-tree. ++ * The new clusters(clusters_to_add) will be inserted at logical_offset. ++ * The extent b-tree's root is root_el and it should be in root_bh, and ++ * it is not limited to the file storage. Any extent tree can use this ++ * function if it implements the proper ocfs2_extent_tree. ++ */ ++int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, ++ struct inode *inode, ++ u32 *logical_offset, ++ u32 clusters_to_add, ++ int mark_unwritten, ++ struct buffer_head *root_bh, ++ struct ocfs2_extent_list *root_el, ++ handle_t *handle, ++ struct ocfs2_alloc_context *data_ac, ++ struct ocfs2_alloc_context *meta_ac, ++ enum ocfs2_alloc_restarted *reason_ret, ++ enum ocfs2_extent_tree_type type) ++{ ++ int status = 0; ++ int free_extents; ++ enum ocfs2_alloc_restarted reason = RESTART_NONE; ++ u32 bit_off, num_bits; ++ u64 block; ++ u8 flags = 0; ++ ++ BUG_ON(!clusters_to_add); ++ ++ if (mark_unwritten) ++ flags = OCFS2_EXT_UNWRITTEN; ++ ++ free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type); ++ if (free_extents < 0) { ++ status = free_extents; ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ /* there are two cases which could cause us to EAGAIN in the ++ * we-need-more-metadata case: ++ * 1) we haven't reserved *any* ++ * 2) we are so fragmented, we've needed to add metadata too ++ * many times. */ ++ if (!free_extents && !meta_ac) { ++ mlog(0, "we haven't reserved any metadata!\n"); ++ status = -EAGAIN; ++ reason = RESTART_META; ++ goto leave; ++ } else if ((!free_extents) ++ && (ocfs2_alloc_context_bits_left(meta_ac) ++ < ocfs2_extend_meta_needed(root_el))) { ++ mlog(0, "filesystem is really fragmented...\n"); ++ status = -EAGAIN; ++ reason = RESTART_META; ++ goto leave; ++ } ++ ++ status = __ocfs2_claim_clusters(osb, handle, data_ac, 1, ++ clusters_to_add, &bit_off, &num_bits); ++ if (status < 0) { ++ if (status != -ENOSPC) ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ BUG_ON(num_bits > clusters_to_add); ++ ++ /* reserve our write early -- insert_extent may update the inode */ ++ status = ocfs2_journal_access(handle, inode, root_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ block = ocfs2_clusters_to_blocks(osb->sb, bit_off); ++ mlog(0, "Allocating %u clusters at block %u for inode %llu\n", ++ num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); ++ status = ocfs2_insert_extent(osb, handle, inode, root_bh, ++ *logical_offset, block, num_bits, ++ flags, meta_ac, type); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ status = ocfs2_journal_dirty(handle, root_bh); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ clusters_to_add -= num_bits; ++ *logical_offset += num_bits; ++ ++ if (clusters_to_add) { ++ mlog(0, "need to alloc once more, wanted = %u\n", ++ clusters_to_add); ++ status = -EAGAIN; ++ reason = RESTART_TRANS; ++ } ++ ++leave: ++ mlog_exit(status); ++ if (reason_ret) ++ *reason_ret = reason; ++ return status; ++} ++ + static void ocfs2_make_right_split_rec(struct super_block *sb, + struct ocfs2_extent_rec *split_rec, + u32 cpos, +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -41,6 +41,23 @@ int ocfs2_insert_extent(struct ocfs2_sup + u8 flags, + struct ocfs2_alloc_context *meta_ac, + enum ocfs2_extent_tree_type et_type); ++enum ocfs2_alloc_restarted { ++ RESTART_NONE = 0, ++ RESTART_TRANS, ++ RESTART_META ++}; ++int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, ++ struct inode *inode, ++ u32 *logical_offset, ++ u32 clusters_to_add, ++ int mark_unwritten, ++ struct buffer_head *root_bh, ++ struct ocfs2_extent_list *root_el, ++ handle_t *handle, ++ struct ocfs2_alloc_context *data_ac, ++ struct ocfs2_alloc_context *meta_ac, ++ enum ocfs2_alloc_restarted *reason_ret, ++ enum ocfs2_extent_tree_type type); + struct ocfs2_cached_dealloc_ctxt; + int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + handle_t *handle, u32 cpos, u32 len, u32 phys, +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -1255,10 +1255,10 @@ static int ocfs2_write_cluster(struct ad + * any additional semaphores or cluster locks. + */ + tmp_pos = cpos; +- ret = ocfs2_do_extend_allocation(OCFS2_SB(inode->i_sb), inode, +- &tmp_pos, 1, 0, wc->w_di_bh, +- wc->w_handle, data_ac, +- meta_ac, NULL); ++ ret = ocfs2_add_inode_data(OCFS2_SB(inode->i_sb), inode, ++ &tmp_pos, 1, 0, wc->w_di_bh, ++ wc->w_handle, data_ac, ++ meta_ac, NULL); + /* + * This shouldn't happen because we must have already + * calculated the correct meta data allocation required. The +--- a/fs/ocfs2/dir.c ++++ b/fs/ocfs2/dir.c +@@ -1383,9 +1383,9 @@ static int ocfs2_do_extend_dir(struct su + if (extend) { + u32 offset = OCFS2_I(dir)->ip_clusters; + +- status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, &offset, +- 1, 0, parent_fe_bh, handle, +- data_ac, meta_ac, NULL); ++ status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset, ++ 1, 0, parent_fe_bh, handle, ++ data_ac, meta_ac, NULL); + BUG_ON(status == -EAGAIN); + if (status < 0) { + mlog_errno(status); +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -488,7 +488,7 @@ bail: + } + + /* +- * extend allocation only here. ++ * extend file allocation only here. + * we'll update all the disk stuff, and oip->alloc_size + * + * expect stuff to be locked, a transaction started and enough data / +@@ -497,107 +497,25 @@ bail: + * Will return -EAGAIN, and a reason if a restart is needed. + * If passed in, *reason will always be set, even in error. + */ +-int ocfs2_do_extend_allocation(struct ocfs2_super *osb, +- struct inode *inode, +- u32 *logical_offset, +- u32 clusters_to_add, +- int mark_unwritten, +- struct buffer_head *fe_bh, +- handle_t *handle, +- struct ocfs2_alloc_context *data_ac, +- struct ocfs2_alloc_context *meta_ac, +- enum ocfs2_alloc_restarted *reason_ret) ++int ocfs2_add_inode_data(struct ocfs2_super *osb, ++ struct inode *inode, ++ u32 *logical_offset, ++ u32 clusters_to_add, ++ int mark_unwritten, ++ struct buffer_head *fe_bh, ++ handle_t *handle, ++ struct ocfs2_alloc_context *data_ac, ++ struct ocfs2_alloc_context *meta_ac, ++ enum ocfs2_alloc_restarted *reason_ret) + { +- int status = 0; +- int free_extents; + struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; +- enum ocfs2_alloc_restarted reason = RESTART_NONE; +- u32 bit_off, num_bits; +- u64 block; +- u8 flags = 0; +- +- BUG_ON(!clusters_to_add); +- +- if (mark_unwritten) +- flags = OCFS2_EXT_UNWRITTEN; +- +- free_extents = ocfs2_num_free_extents(osb, inode, fe_bh, +- OCFS2_DINODE_EXTENT); +- if (free_extents < 0) { +- status = free_extents; +- mlog_errno(status); +- goto leave; +- } +- +- /* there are two cases which could cause us to EAGAIN in the +- * we-need-more-metadata case: +- * 1) we haven't reserved *any* +- * 2) we are so fragmented, we've needed to add metadata too +- * many times. */ +- if (!free_extents && !meta_ac) { +- mlog(0, "we haven't reserved any metadata!\n"); +- status = -EAGAIN; +- reason = RESTART_META; +- goto leave; +- } else if ((!free_extents) +- && (ocfs2_alloc_context_bits_left(meta_ac) +- < ocfs2_extend_meta_needed(&fe->id2.i_list))) { +- mlog(0, "filesystem is really fragmented...\n"); +- status = -EAGAIN; +- reason = RESTART_META; +- goto leave; +- } +- +- status = __ocfs2_claim_clusters(osb, handle, data_ac, 1, +- clusters_to_add, &bit_off, &num_bits); +- if (status < 0) { +- if (status != -ENOSPC) +- mlog_errno(status); +- goto leave; +- } +- +- BUG_ON(num_bits > clusters_to_add); +- +- /* reserve our write early -- insert_extent may update the inode */ +- status = ocfs2_journal_access(handle, inode, fe_bh, +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (status < 0) { +- mlog_errno(status); +- goto leave; +- } +- +- block = ocfs2_clusters_to_blocks(osb->sb, bit_off); +- mlog(0, "Allocating %u clusters at block %u for inode %llu\n", +- num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); +- status = ocfs2_insert_extent(osb, handle, inode, fe_bh, +- *logical_offset, block, num_bits, +- flags, meta_ac, OCFS2_DINODE_EXTENT); +- if (status < 0) { +- mlog_errno(status); +- goto leave; +- } ++ struct ocfs2_extent_list *el = &fe->id2.i_list; + +- status = ocfs2_journal_dirty(handle, fe_bh); +- if (status < 0) { +- mlog_errno(status); +- goto leave; +- } +- +- clusters_to_add -= num_bits; +- *logical_offset += num_bits; +- +- if (clusters_to_add) { +- mlog(0, "need to alloc once more, clusters = %u, wanted = " +- "%u\n", fe->i_clusters, clusters_to_add); +- status = -EAGAIN; +- reason = RESTART_TRANS; +- } +- +-leave: +- mlog_exit(status); +- if (reason_ret) +- *reason_ret = reason; +- return status; ++ return ocfs2_add_clusters_in_btree(osb, inode, logical_offset, ++ clusters_to_add, mark_unwritten, ++ fe_bh, el, handle, ++ data_ac, meta_ac, reason_ret, ++ OCFS2_DINODE_EXTENT); + } + + static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, +@@ -676,16 +594,16 @@ restarted_transaction: + + prev_clusters = OCFS2_I(inode)->ip_clusters; + +- status = ocfs2_do_extend_allocation(osb, +- inode, +- &logical_start, +- clusters_to_add, +- mark_unwritten, +- bh, +- handle, +- data_ac, +- meta_ac, +- &why); ++ status = ocfs2_add_inode_data(osb, ++ inode, ++ &logical_start, ++ clusters_to_add, ++ mark_unwritten, ++ bh, ++ handle, ++ data_ac, ++ meta_ac, ++ &why); + if ((status < 0) && (status != -EAGAIN)) { + if (status != -ENOSPC) + mlog_errno(status); +--- a/fs/ocfs2/file.h ++++ b/fs/ocfs2/file.h +@@ -31,6 +31,7 @@ extern const struct file_operations ocfs + extern const struct inode_operations ocfs2_file_iops; + extern const struct inode_operations ocfs2_special_file_iops; + struct ocfs2_alloc_context; ++enum ocfs2_alloc_restarted; + + struct ocfs2_file_private { + struct file *fp_file; +@@ -38,21 +39,16 @@ struct ocfs2_file_private { + struct ocfs2_lock_res fp_flock; + }; + +-enum ocfs2_alloc_restarted { +- RESTART_NONE = 0, +- RESTART_TRANS, +- RESTART_META +-}; +-int ocfs2_do_extend_allocation(struct ocfs2_super *osb, +- struct inode *inode, +- u32 *logical_offset, +- u32 clusters_to_add, +- int mark_unwritten, +- struct buffer_head *fe_bh, +- handle_t *handle, +- struct ocfs2_alloc_context *data_ac, +- struct ocfs2_alloc_context *meta_ac, +- enum ocfs2_alloc_restarted *reason_ret); ++int ocfs2_add_inode_data(struct ocfs2_super *osb, ++ struct inode *inode, ++ u32 *logical_offset, ++ u32 clusters_to_add, ++ int mark_unwritten, ++ struct buffer_head *fe_bh, ++ handle_t *handle, ++ struct ocfs2_alloc_context *data_ac, ++ struct ocfs2_alloc_context *meta_ac, ++ enum ocfs2_alloc_restarted *reason_ret); + int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, + u64 zero_to); + int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -1598,10 +1598,10 @@ static int ocfs2_symlink(struct inode *d + u32 offset = 0; + + inode->i_op = &ocfs2_symlink_inode_operations; +- status = ocfs2_do_extend_allocation(osb, inode, &offset, 1, 0, +- new_fe_bh, +- handle, data_ac, NULL, +- NULL); ++ status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0, ++ new_fe_bh, ++ handle, data_ac, NULL, ++ NULL); + if (status < 0) { + if (status != -ENOSPC && status != -EINTR) { + mlog(ML_ERROR, diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-ocfs2_extent_tree-get-put-instead-of-all.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-ocfs2_extent_tree-get-put-instead-of-all.patch new file mode 100644 index 000000000..38acf14db --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-ocfs2_extent_tree-get-put-instead-of-all.patch @@ -0,0 +1,271 @@ +From: Joel Becker +Subject: ocfs2: Make ocfs2_extent_tree get/put instead of alloc. +Patch-mainline: 2.6.28? +References: FATE302067 + +Rather than allocating a struct ocfs2_extent_tree, just put it on the +stack. Fill it with ocfs2_get_extent_tree() and drop it with +ocfs2_put_extent_tree(). Now the callers don't have to ENOMEM, yet +still safely ref the root_bh. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 117 ++++++++++++++++------------------------------------- + 1 files changed, 36 insertions(+), 81 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index ab16b89..0abf11e 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -223,22 +223,17 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .eo_sanity_check = ocfs2_xattr_tree_sanity_check, + }; + +-static struct ocfs2_extent_tree* +- ocfs2_new_extent_tree(struct inode *inode, +- struct buffer_head *bh, +- enum ocfs2_extent_tree_type et_type, +- void *private) ++static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ enum ocfs2_extent_tree_type et_type, ++ void *private) + { +- struct ocfs2_extent_tree *et; +- +- et = kzalloc(sizeof(*et), GFP_NOFS); +- if (!et) +- return NULL; +- + et->et_type = et_type; + get_bh(bh); + et->et_root_bh = bh; + et->et_private = private; ++ et->et_max_leaf_clusters = 0; + + if (et_type == OCFS2_DINODE_EXTENT) { + et->et_root_el = +@@ -257,16 +252,11 @@ static struct ocfs2_extent_tree* + et->et_max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, + OCFS2_MAX_XATTR_TREE_LEAF_SIZE); + } +- +- return et; + } + +-static void ocfs2_free_extent_tree(struct ocfs2_extent_tree *et) ++static void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) + { +- if (et) { +- brelse(et->et_root_bh); +- kfree(et); +- } ++ brelse(et->et_root_bh); + } + + static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et, +@@ -4439,22 +4429,15 @@ int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, + struct ocfs2_alloc_context *meta_ac) + { + int status; +- struct ocfs2_extent_tree *et = NULL; +- +- et = ocfs2_new_extent_tree(inode, root_bh, OCFS2_DINODE_EXTENT, NULL); +- if (!et) { +- status = -ENOMEM; +- mlog_errno(status); +- goto bail; +- } ++ struct ocfs2_extent_tree et; + ++ ocfs2_get_extent_tree(&et, inode, root_bh, OCFS2_DINODE_EXTENT, ++ NULL); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, +- flags, meta_ac, et); ++ flags, meta_ac, &et); ++ ocfs2_put_extent_tree(&et); + +- if (et) +- ocfs2_free_extent_tree(et); +-bail: + return status; + } + +@@ -4470,23 +4453,15 @@ int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, + void *private) + { + int status; +- struct ocfs2_extent_tree *et = NULL; +- +- et = ocfs2_new_extent_tree(inode, root_bh, +- OCFS2_XATTR_VALUE_EXTENT, private); +- if (!et) { +- status = -ENOMEM; +- mlog_errno(status); +- goto bail; +- } ++ struct ocfs2_extent_tree et; + ++ ocfs2_get_extent_tree(&et, inode, root_bh, ++ OCFS2_XATTR_VALUE_EXTENT, private); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, +- flags, meta_ac, et); ++ flags, meta_ac, &et); ++ ocfs2_put_extent_tree(&et); + +- if (et) +- ocfs2_free_extent_tree(et); +-bail: + return status; + } + +@@ -4501,23 +4476,15 @@ int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, + struct ocfs2_alloc_context *meta_ac) + { + int status; +- struct ocfs2_extent_tree *et = NULL; +- +- et = ocfs2_new_extent_tree(inode, root_bh, OCFS2_XATTR_TREE_EXTENT, +- NULL); +- if (!et) { +- status = -ENOMEM; +- mlog_errno(status); +- goto bail; +- } ++ struct ocfs2_extent_tree et; + ++ ocfs2_get_extent_tree(&et, inode, root_bh, OCFS2_XATTR_TREE_EXTENT, ++ NULL); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, +- flags, meta_ac, et); ++ flags, meta_ac, &et); ++ ocfs2_put_extent_tree(&et); + +- if (et) +- ocfs2_free_extent_tree(et); +-bail: + return status; + } + +@@ -4906,11 +4873,13 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + struct ocfs2_extent_rec split_rec; + struct ocfs2_path *left_path = NULL; + struct ocfs2_extent_list *el; +- struct ocfs2_extent_tree *et = NULL; ++ struct ocfs2_extent_tree et; + + mlog(0, "Inode %lu cpos %u, len %u, phys %u (%llu)\n", + inode->i_ino, cpos, len, phys, (unsigned long long)start_blkno); + ++ ocfs2_get_extent_tree(&et, inode, root_bh, et_type, private); ++ + if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) { + ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents " + "that are being written to, but the feature bit " +@@ -4920,13 +4889,6 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + goto out; + } + +- et = ocfs2_new_extent_tree(inode, root_bh, et_type, private); +- if (!et) { +- ret = -ENOMEM; +- mlog_errno(ret); +- goto out; +- } +- + /* + * XXX: This should be fixed up so that we just re-insert the + * next extent records. +@@ -4934,7 +4896,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + if (et_type == OCFS2_DINODE_EXTENT) + ocfs2_extent_map_trunc(inode, 0); + +- left_path = ocfs2_new_path(et->et_root_bh, et->et_root_el); ++ left_path = ocfs2_new_path(et.et_root_bh, et.et_root_el); + if (!left_path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4965,7 +4927,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags; + split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN; + +- ret = __ocfs2_mark_extent_written(inode, et, handle, left_path, ++ ret = __ocfs2_mark_extent_written(inode, &et, handle, left_path, + index, &split_rec, meta_ac, + dealloc); + if (ret) +@@ -4973,8 +4935,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + + out: + ocfs2_free_path(left_path); +- if (et) +- ocfs2_free_extent_tree(et); ++ ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -5216,18 +5177,13 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + struct ocfs2_extent_rec *rec; + struct ocfs2_extent_list *el; + struct ocfs2_path *path = NULL; +- struct ocfs2_extent_tree *et = NULL; ++ struct ocfs2_extent_tree et; + +- et = ocfs2_new_extent_tree(inode, root_bh, et_type, private); +- if (!et) { +- ret = -ENOMEM; +- mlog_errno(ret); +- goto out; +- } ++ ocfs2_get_extent_tree(&et, inode, root_bh, et_type, private); + + ocfs2_extent_map_trunc(inode, 0); + +- path = ocfs2_new_path(et->et_root_bh, et->et_root_el); ++ path = ocfs2_new_path(et.et_root_bh, et.et_root_el); + if (!path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -5280,13 +5236,13 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + + if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) { + ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, +- cpos, len, et); ++ cpos, len, &et); + if (ret) { + mlog_errno(ret); + goto out; + } + } else { +- ret = ocfs2_split_tree(inode, et, handle, path, index, ++ ret = ocfs2_split_tree(inode, &et, handle, path, index, + trunc_range, meta_ac); + if (ret) { + mlog_errno(ret); +@@ -5335,7 +5291,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + } + + ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, +- cpos, len, et); ++ cpos, len, &et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -5344,8 +5300,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + + out: + ocfs2_free_path(path); +- if (et) +- ocfs2_free_extent_tree(et); ++ ocfs2_put_extent_tree(&et); + return ret; + } + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-ocfs2_extent_tree-the-first-class-repres.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-ocfs2_extent_tree-the-first-class-repres.patch new file mode 100644 index 000000000..ded6ee26b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-ocfs2_extent_tree-the-first-class-repres.patch @@ -0,0 +1,1208 @@ +From: Joel Becker +Subject: ocfs2: Make ocfs2_extent_tree the first-class representation of a tree. +Patch-mainline: 2.6.28? +References: FATE302067 + +We now have three different kinds of extent trees in ocfs2: inode data +(dinode), extended attributes (xattr_tree), and extended attribute +values (xattr_value). There is a nice abstraction for them, +ocfs2_extent_tree, but it is hidden in alloc.c. All the calling +functions have to pick amongst a varied API and pass in type bits and +often extraneous pointers. + +A better way is to make ocfs2_extent_tree a first-class object. +Everyone converts their object to an ocfs2_extent_tree() via the +ocfs2_get_*_extent_tree() calls, then uses the ocfs2_extent_tree for all +tree calls to alloc.c. + +This simplifies a lot of callers, making for readability. It also +provides an easy way to add additional extent tree types, as they only +need to be defined in alloc.c with a ocfs2_get__extent_tree() +function. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 300 +++++++++++++++----------------------------------- + fs/ocfs2/alloc.h | 111 +++++++++++--------- + fs/ocfs2/aops.c | 16 ++- + fs/ocfs2/dir.c | 20 ++-- + fs/ocfs2/file.c | 36 ++++--- + fs/ocfs2/suballoc.c | 12 +-- + fs/ocfs2/suballoc.h | 6 +- + fs/ocfs2/xattr.c | 71 +++++++------ + 8 files changed, 240 insertions(+), 332 deletions(-) + +Index: linux-2.6.26/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/alloc.c ++++ linux-2.6.26/fs/ocfs2/alloc.c +@@ -49,20 +49,6 @@ + + #include "buffer_head_io.h" + +-/* +- * ocfs2_extent_tree and ocfs2_extent_tree_operations are used to abstract +- * the b-tree operations in ocfs2. Now all the b-tree operations are not +- * limited to ocfs2_dinode only. Any data which need to allocate clusters +- * to store can use b-tree. And it only needs to implement its ocfs2_extent_tree +- * and operation. +- * +- * ocfs2_extent_tree contains info for the root of the b-tree, it must have a +- * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree +- * functions. +- * ocfs2_extent_tree_operations abstract the normal operations we do for +- * the root of extent b-tree. +- */ +-struct ocfs2_extent_tree; + + struct ocfs2_extent_tree_operations { + void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et, +@@ -83,28 +69,38 @@ struct ocfs2_extent_tree_operations { + struct ocfs2_extent_tree *et); + }; + +-struct ocfs2_extent_tree { +- enum ocfs2_extent_tree_type et_type; +- struct ocfs2_extent_tree_operations *et_ops; +- struct buffer_head *et_root_bh; +- struct ocfs2_extent_list *et_root_el; +- void *et_object; +- unsigned int et_max_leaf_clusters; +-}; + +-static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et) +-{ +- struct ocfs2_dinode *di = et->et_object; +- +- et->et_root_el = &di->id2.i_list; +-} ++/* ++ * Pre-declare ocfs2_dinode_et_ops so we can use it as a sanity check ++ * in the methods. ++ */ ++static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et); ++static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, ++ u64 blkno); ++static void ocfs2_dinode_update_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 clusters); ++static int ocfs2_dinode_insert_check(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ struct ocfs2_extent_rec *rec); ++static int ocfs2_dinode_sanity_check(struct inode *inode, ++ struct ocfs2_extent_tree *et); ++static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et); ++static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { ++ .eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, ++ .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, ++ .eo_update_clusters = ocfs2_dinode_update_clusters, ++ .eo_insert_check = ocfs2_dinode_insert_check, ++ .eo_sanity_check = ocfs2_dinode_sanity_check, ++ .eo_fill_root_el = ocfs2_dinode_fill_root_el, ++}; + + static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { + struct ocfs2_dinode *di = et->et_object; + +- BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); ++ BUG_ON(et->et_ops != &ocfs2_dinode_et_ops); + di->i_last_eb_blk = cpu_to_le64(blkno); + } + +@@ -112,7 +108,7 @@ static u64 ocfs2_dinode_get_last_eb_blk( + { + struct ocfs2_dinode *di = et->et_object; + +- BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); ++ BUG_ON(et->et_ops != &ocfs2_dinode_et_ops); + return le64_to_cpu(di->i_last_eb_blk); + } + +@@ -153,7 +149,7 @@ static int ocfs2_dinode_sanity_check(str + int ret = 0; + struct ocfs2_dinode *di; + +- BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); ++ BUG_ON(et->et_ops != &ocfs2_dinode_et_ops); + + di = et->et_object; + if (!OCFS2_IS_VALID_DINODE(di)) { +@@ -166,14 +162,13 @@ static int ocfs2_dinode_sanity_check(str + return ret; + } + +-static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { +- .eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, +- .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, +- .eo_update_clusters = ocfs2_dinode_update_clusters, +- .eo_insert_check = ocfs2_dinode_insert_check, +- .eo_sanity_check = ocfs2_dinode_sanity_check, +- .eo_fill_root_el = ocfs2_dinode_fill_root_el, +-}; ++static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_dinode *di = et->et_object; ++ ++ et->et_root_el = &di->id2.i_list; ++} ++ + + static void ocfs2_xattr_value_fill_root_el(struct ocfs2_extent_tree *et) + { +@@ -269,10 +264,8 @@ static void __ocfs2_get_extent_tree(stru + struct inode *inode, + struct buffer_head *bh, + void *obj, +- enum ocfs2_extent_tree_type et_type, + struct ocfs2_extent_tree_operations *ops) + { +- et->et_type = et_type; + et->et_ops = ops; + get_bh(bh); + et->et_root_bh = bh; +@@ -287,50 +280,31 @@ static void __ocfs2_get_extent_tree(stru + et->et_ops->eo_fill_max_leaf_clusters(inode, et); + } + +-static void ocfs2_get_dinode_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh) ++void ocfs2_get_dinode_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh) + { +- __ocfs2_get_extent_tree(et, inode, bh, NULL, OCFS2_DINODE_EXTENT, +- &ocfs2_dinode_et_ops); ++ __ocfs2_get_extent_tree(et, inode, bh, NULL, &ocfs2_dinode_et_ops); + } + +-static void ocfs2_get_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh) ++void ocfs2_get_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh) + { + __ocfs2_get_extent_tree(et, inode, bh, NULL, +- OCFS2_XATTR_TREE_EXTENT, + &ocfs2_xattr_tree_et_ops); + } + +-static void ocfs2_get_xattr_value_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh, +- struct ocfs2_xattr_value_root *xv) ++void ocfs2_get_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ struct ocfs2_xattr_value_root *xv) + { + __ocfs2_get_extent_tree(et, inode, bh, xv, +- OCFS2_XATTR_VALUE_EXTENT, + &ocfs2_xattr_value_et_ops); + } + +-static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, +- struct inode *inode, +- struct buffer_head *bh, +- enum ocfs2_extent_tree_type et_type, +- void *obj) +-{ +- if (et_type == OCFS2_DINODE_EXTENT) +- ocfs2_get_dinode_extent_tree(et, inode, bh); +- else if (et_type == OCFS2_XATTR_VALUE_EXTENT) +- ocfs2_get_xattr_tree_extent_tree(et, inode, bh); +- else if (et_type == OCFS2_XATTR_TREE_EXTENT) +- ocfs2_get_xattr_value_extent_tree(et, inode, bh, obj); +- else +- BUG(); +-} +- +-static void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) ++void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) + { + brelse(et->et_root_bh); + } +@@ -682,22 +656,18 @@ struct ocfs2_merge_ctxt { + */ + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, +- struct buffer_head *root_bh, +- enum ocfs2_extent_tree_type type, +- void *obj) ++ struct ocfs2_extent_tree *et) + { + int retval; + struct ocfs2_extent_list *el = NULL; + struct ocfs2_extent_block *eb; + struct buffer_head *eb_bh = NULL; + u64 last_eb_blk = 0; +- struct ocfs2_extent_tree et; + + mlog_entry_void(); + +- ocfs2_get_extent_tree(&et, inode, root_bh, type, obj); +- el = et.et_root_el; +- last_eb_blk = ocfs2_et_get_last_eb_blk(&et); ++ el = et->et_root_el; ++ last_eb_blk = ocfs2_et_get_last_eb_blk(et); + + if (last_eb_blk) { + retval = ocfs2_read_block(osb, last_eb_blk, +@@ -717,7 +687,6 @@ bail: + if (eb_bh) + brelse(eb_bh); + +- ocfs2_put_extent_tree(&et); + mlog_exit(retval); + return retval; + } +@@ -4415,16 +4384,15 @@ out: + * + * The caller needs to update fe->i_clusters + */ +-static int ocfs2_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_extent_tree *et) ++int ocfs2_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac) + { + int status; + int uninitialized_var(free_records); +@@ -4473,7 +4441,7 @@ static int ocfs2_insert_extent(struct oc + status = ocfs2_do_insert_extent(inode, handle, et, &rec, &insert); + if (status < 0) + mlog_errno(status); +- else if (et->et_type == OCFS2_DINODE_EXTENT) ++ else if (et->et_ops == &ocfs2_dinode_et_ops) + ocfs2_extent_map_insert_rec(inode, &rec); + + bail: +@@ -4484,77 +4452,10 @@ bail: + return status; + } + +-int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac) +-{ +- int status; +- struct ocfs2_extent_tree et; +- +- ocfs2_get_dinode_extent_tree(&et, inode, root_bh); +- status = ocfs2_insert_extent(osb, handle, inode, root_bh, +- cpos, start_blk, new_clusters, +- flags, meta_ac, &et); +- ocfs2_put_extent_tree(&et); +- +- return status; +-} +- +-int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_xattr_value_root *xv) +-{ +- int status; +- struct ocfs2_extent_tree et; +- +- ocfs2_get_xattr_value_extent_tree(&et, inode, root_bh, xv); +- status = ocfs2_insert_extent(osb, handle, inode, root_bh, +- cpos, start_blk, new_clusters, +- flags, meta_ac, &et); +- ocfs2_put_extent_tree(&et); +- +- return status; +-} +- +-int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac) +-{ +- int status; +- struct ocfs2_extent_tree et; +- +- ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh); +- status = ocfs2_insert_extent(osb, handle, inode, root_bh, +- cpos, start_blk, new_clusters, +- flags, meta_ac, &et); +- ocfs2_put_extent_tree(&et); +- +- return status; +-} +- + /* + * Allcate and add clusters into the extent b-tree. + * The new clusters(clusters_to_add) will be inserted at logical_offset. +- * The extent b-tree's root is root_el and it should be in root_bh, and ++ * The extent b-tree's root is specified by et, and + * it is not limited to the file storage. Any extent tree can use this + * function if it implements the proper ocfs2_extent_tree. + */ +@@ -4563,14 +4464,11 @@ int ocfs2_add_clusters_in_btree(struct o + u32 *logical_offset, + u32 clusters_to_add, + int mark_unwritten, +- struct buffer_head *root_bh, +- struct ocfs2_extent_list *root_el, ++ struct ocfs2_extent_tree *et, + handle_t *handle, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, +- enum ocfs2_alloc_restarted *reason_ret, +- enum ocfs2_extent_tree_type type, +- void *obj) ++ enum ocfs2_alloc_restarted *reason_ret) + { + int status = 0; + int free_extents; +@@ -4584,8 +4482,7 @@ int ocfs2_add_clusters_in_btree(struct o + if (mark_unwritten) + flags = OCFS2_EXT_UNWRITTEN; + +- free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type, +- obj); ++ free_extents = ocfs2_num_free_extents(osb, inode, et); + if (free_extents < 0) { + status = free_extents; + mlog_errno(status); +@@ -4604,7 +4501,7 @@ int ocfs2_add_clusters_in_btree(struct o + goto leave; + } else if ((!free_extents) + && (ocfs2_alloc_context_bits_left(meta_ac) +- < ocfs2_extend_meta_needed(root_el))) { ++ < ocfs2_extend_meta_needed(et->et_root_el))) { + mlog(0, "filesystem is really fragmented...\n"); + status = -EAGAIN; + reason = RESTART_META; +@@ -4622,7 +4519,7 @@ int ocfs2_add_clusters_in_btree(struct o + BUG_ON(num_bits > clusters_to_add); + + /* reserve our write early -- insert_extent may update the inode */ +- status = ocfs2_journal_access(handle, inode, root_bh, ++ status = ocfs2_journal_access(handle, inode, et->et_root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); +@@ -4632,28 +4529,15 @@ int ocfs2_add_clusters_in_btree(struct o + block = ocfs2_clusters_to_blocks(osb->sb, bit_off); + mlog(0, "Allocating %u clusters at block %u for inode %llu\n", + num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); +- if (type == OCFS2_DINODE_EXTENT) +- status = ocfs2_dinode_insert_extent(osb, handle, inode, root_bh, +- *logical_offset, block, +- num_bits, flags, meta_ac); +- else if (type == OCFS2_XATTR_TREE_EXTENT) +- status = ocfs2_xattr_tree_insert_extent(osb, handle, +- inode, root_bh, +- *logical_offset, +- block, num_bits, flags, +- meta_ac); +- else +- status = ocfs2_xattr_value_insert_extent(osb, handle, +- inode, root_bh, +- *logical_offset, +- block, num_bits, flags, +- meta_ac, obj); ++ status = ocfs2_insert_extent(osb, handle, inode, et, ++ *logical_offset, block, ++ num_bits, flags, meta_ac); + if (status < 0) { + mlog_errno(status); + goto leave; + } + +- status = ocfs2_journal_dirty(handle, root_bh); ++ status = ocfs2_journal_dirty(handle, et->et_root_bh); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -4924,25 +4808,21 @@ out: + * + * The caller is responsible for passing down meta_ac if we'll need it. + */ +-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, ++int ocfs2_mark_extent_written(struct inode *inode, ++ struct ocfs2_extent_tree *et, + handle_t *handle, u32 cpos, u32 len, u32 phys, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type, +- void *obj) ++ struct ocfs2_cached_dealloc_ctxt *dealloc) + { + int ret, index; + u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); + struct ocfs2_extent_rec split_rec; + struct ocfs2_path *left_path = NULL; + struct ocfs2_extent_list *el; +- struct ocfs2_extent_tree et; + + mlog(0, "Inode %lu cpos %u, len %u, phys %u (%llu)\n", + inode->i_ino, cpos, len, phys, (unsigned long long)start_blkno); + +- ocfs2_get_extent_tree(&et, inode, root_bh, et_type, obj); +- + if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) { + ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents " + "that are being written to, but the feature bit " +@@ -4955,11 +4835,14 @@ int ocfs2_mark_extent_written(struct ino + /* + * XXX: This should be fixed up so that we just re-insert the + * next extent records. ++ * ++ * XXX: This is a hack on the extent tree, maybe it should be ++ * an op? + */ +- if (et_type == OCFS2_DINODE_EXTENT) ++ if (et->et_ops == &ocfs2_dinode_et_ops) + ocfs2_extent_map_trunc(inode, 0); + +- left_path = ocfs2_new_path(et.et_root_bh, et.et_root_el); ++ left_path = ocfs2_new_path(et->et_root_bh, et->et_root_el); + if (!left_path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4990,7 +4873,7 @@ int ocfs2_mark_extent_written(struct ino + split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags; + split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN; + +- ret = __ocfs2_mark_extent_written(inode, &et, handle, left_path, ++ ret = __ocfs2_mark_extent_written(inode, et, handle, left_path, + index, &split_rec, meta_ac, + dealloc); + if (ret) +@@ -4998,7 +4881,6 @@ int ocfs2_mark_extent_written(struct ino + + out: + ocfs2_free_path(left_path); +- ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -5228,25 +5110,21 @@ out: + return ret; + } + +-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, ++int ocfs2_remove_extent(struct inode *inode, ++ struct ocfs2_extent_tree *et, + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type, +- void *obj) ++ struct ocfs2_cached_dealloc_ctxt *dealloc) + { + int ret, index; + u32 rec_range, trunc_range; + struct ocfs2_extent_rec *rec; + struct ocfs2_extent_list *el; + struct ocfs2_path *path = NULL; +- struct ocfs2_extent_tree et; +- +- ocfs2_get_extent_tree(&et, inode, root_bh, et_type, obj); + + ocfs2_extent_map_trunc(inode, 0); + +- path = ocfs2_new_path(et.et_root_bh, et.et_root_el); ++ path = ocfs2_new_path(et->et_root_bh, et->et_root_el); + if (!path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -5299,13 +5177,13 @@ int ocfs2_remove_extent(struct inode *in + + if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) { + ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, +- cpos, len, &et); ++ cpos, len, et); + if (ret) { + mlog_errno(ret); + goto out; + } + } else { +- ret = ocfs2_split_tree(inode, &et, handle, path, index, ++ ret = ocfs2_split_tree(inode, et, handle, path, index, + trunc_range, meta_ac); + if (ret) { + mlog_errno(ret); +@@ -5354,7 +5232,7 @@ int ocfs2_remove_extent(struct inode *in + } + + ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, +- cpos, len, &et); ++ cpos, len, et); + if (ret) { + mlog_errno(ret); + goto out; +@@ -5363,7 +5241,6 @@ int ocfs2_remove_extent(struct inode *in + + out: + ocfs2_free_path(path); +- ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -6782,6 +6659,7 @@ int ocfs2_convert_inline_data_to_extents + struct ocfs2_alloc_context *data_ac = NULL; + struct page **pages = NULL; + loff_t end = osb->s_clustersize; ++ struct ocfs2_extent_tree et; + + has_data = i_size_read(inode) ? 1 : 0; + +@@ -6881,8 +6759,10 @@ int ocfs2_convert_inline_data_to_extents + * this proves to be false, we could always re-build + * the in-inode data from our pages. + */ +- ret = ocfs2_dinode_insert_extent(osb, handle, inode, di_bh, +- 0, block, 1, 0, NULL); ++ ocfs2_get_dinode_extent_tree(&et, inode, di_bh); ++ ret = ocfs2_insert_extent(osb, handle, inode, &et, ++ 0, block, 1, 0, NULL); ++ ocfs2_put_extent_tree(&et); + if (ret) { + mlog_errno(ret); + goto out_commit; +Index: linux-2.6.26/fs/ocfs2/alloc.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/alloc.h ++++ linux-2.6.26/fs/ocfs2/alloc.h +@@ -26,46 +26,66 @@ + #ifndef OCFS2_ALLOC_H + #define OCFS2_ALLOC_H + +-enum ocfs2_extent_tree_type { +- OCFS2_DINODE_EXTENT = 0, +- OCFS2_XATTR_VALUE_EXTENT, +- OCFS2_XATTR_TREE_EXTENT, +-}; + + /* + * For xattr tree leaf, we limit the leaf byte size to be 64K. + */ + #define OCFS2_MAX_XATTR_TREE_LEAF_SIZE 65536 + ++/* ++ * ocfs2_extent_tree and ocfs2_extent_tree_operations are used to abstract ++ * the b-tree operations in ocfs2. Now all the b-tree operations are not ++ * limited to ocfs2_dinode only. Any data which need to allocate clusters ++ * to store can use b-tree. And it only needs to implement its ocfs2_extent_tree ++ * and operation. ++ * ++ * ocfs2_extent_tree becomes the first-class object for extent tree ++ * manipulation. Callers of the alloc.c code need to fill it via one of ++ * the ocfs2_get_*_extent_tree() operations below. ++ * ++ * ocfs2_extent_tree contains info for the root of the b-tree, it must have a ++ * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree ++ * functions. ++ * ocfs2_extent_tree_operations abstract the normal operations we do for ++ * the root of extent b-tree. ++ */ ++struct ocfs2_extent_tree_operations; ++struct ocfs2_extent_tree { ++ struct ocfs2_extent_tree_operations *et_ops; ++ struct buffer_head *et_root_bh; ++ struct ocfs2_extent_list *et_root_el; ++ void *et_object; ++ unsigned int et_max_leaf_clusters; ++}; ++ ++/* ++ * ocfs2_*_get_extent_tree() will fill an ocfs2_extent_tree from the ++ * specified object buffer. The bh is referenced until ++ * ocfs2_put_extent_tree(). ++ */ ++void ocfs2_get_dinode_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh); ++void ocfs2_get_xattr_tree_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh); ++void ocfs2_get_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ++ struct inode *inode, ++ struct buffer_head *bh, ++ struct ocfs2_xattr_value_root *xv); ++void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et); ++ + struct ocfs2_alloc_context; +-int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac); +-int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_xattr_value_root *xv); +-int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, +- handle_t *handle, +- struct inode *inode, +- struct buffer_head *root_bh, +- u32 cpos, +- u64 start_blk, +- u32 new_clusters, +- u8 flags, +- struct ocfs2_alloc_context *meta_ac); ++int ocfs2_insert_extent(struct ocfs2_super *osb, ++ handle_t *handle, ++ struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 cpos, ++ u64 start_blk, ++ u32 new_clusters, ++ u8 flags, ++ struct ocfs2_alloc_context *meta_ac); ++ + enum ocfs2_alloc_restarted { + RESTART_NONE = 0, + RESTART_TRANS, +@@ -76,32 +96,25 @@ int ocfs2_add_clusters_in_btree(struct o + u32 *logical_offset, + u32 clusters_to_add, + int mark_unwritten, +- struct buffer_head *root_bh, +- struct ocfs2_extent_list *root_el, ++ struct ocfs2_extent_tree *et, + handle_t *handle, + struct ocfs2_alloc_context *data_ac, + struct ocfs2_alloc_context *meta_ac, +- enum ocfs2_alloc_restarted *reason_ret, +- enum ocfs2_extent_tree_type type, +- void *private); ++ enum ocfs2_alloc_restarted *reason_ret); + struct ocfs2_cached_dealloc_ctxt; +-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, ++int ocfs2_mark_extent_written(struct inode *inode, ++ struct ocfs2_extent_tree *et, + handle_t *handle, u32 cpos, u32 len, u32 phys, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type, +- void *private); +-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, ++ struct ocfs2_cached_dealloc_ctxt *dealloc); ++int ocfs2_remove_extent(struct inode *inode, ++ struct ocfs2_extent_tree *et, + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, +- struct ocfs2_cached_dealloc_ctxt *dealloc, +- enum ocfs2_extent_tree_type et_type, +- void *private); ++ struct ocfs2_cached_dealloc_ctxt *dealloc); + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, +- struct buffer_head *root_bh, +- enum ocfs2_extent_tree_type et_type, +- void *private); ++ struct ocfs2_extent_tree *et); + + /* + * how many new metadata chunks would an allocation need at maximum? +Index: linux-2.6.26/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/aops.c ++++ linux-2.6.26/fs/ocfs2/aops.c +@@ -1242,6 +1242,7 @@ static int ocfs2_write_cluster(struct ad + int ret, i, new, should_zero = 0; + u64 v_blkno, p_blkno; + struct inode *inode = mapping->host; ++ struct ocfs2_extent_tree et; + + new = phys == 0 ? 1 : 0; + if (new || unwritten) +@@ -1276,10 +1277,11 @@ static int ocfs2_write_cluster(struct ad + goto out; + } + } else if (unwritten) { +- ret = ocfs2_mark_extent_written(inode, wc->w_di_bh, ++ ocfs2_get_dinode_extent_tree(&et, inode, wc->w_di_bh); ++ ret = ocfs2_mark_extent_written(inode, &et, + wc->w_handle, cpos, 1, phys, +- meta_ac, &wc->w_dealloc, +- OCFS2_DINODE_EXTENT, NULL); ++ meta_ac, &wc->w_dealloc); ++ ocfs2_put_extent_tree(&et); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1666,6 +1668,7 @@ int ocfs2_write_begin_nolock(struct addr + struct ocfs2_alloc_context *data_ac = NULL; + struct ocfs2_alloc_context *meta_ac = NULL; + handle_t *handle; ++ struct ocfs2_extent_tree et; + + ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh); + if (ret) { +@@ -1719,10 +1722,11 @@ int ocfs2_write_begin_nolock(struct addr + (long long)i_size_read(inode), le32_to_cpu(di->i_clusters), + clusters_to_alloc, extents_to_split); + +- ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list, ++ ocfs2_get_dinode_extent_tree(&et, inode, wc->w_di_bh); ++ ret = ocfs2_lock_allocators(inode, &et, + clusters_to_alloc, extents_to_split, +- &data_ac, &meta_ac, +- OCFS2_DINODE_EXTENT, NULL); ++ &data_ac, &meta_ac); ++ ocfs2_put_extent_tree(&et); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.26/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/dir.c ++++ linux-2.6.26/fs/ocfs2/dir.c +@@ -1192,6 +1192,9 @@ static int ocfs2_expand_inline_dir(struc + struct buffer_head *dirdata_bh = NULL; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + handle_t *handle; ++ struct ocfs2_extent_tree et; ++ ++ ocfs2_get_dinode_extent_tree(&et, dir, di_bh); + + alloc = ocfs2_clusters_for_bytes(sb, bytes); + +@@ -1305,8 +1308,8 @@ static int ocfs2_expand_inline_dir(struc + * This should never fail as our extent list is empty and all + * related blocks have been journaled already. + */ +- ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 0, blkno, +- len, 0, NULL); ++ ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len, ++ 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1337,8 +1340,8 @@ static int ocfs2_expand_inline_dir(struc + } + blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); + +- ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 1, +- blkno, len, 0, NULL); ++ ret = ocfs2_insert_extent(osb, handle, dir, &et, 1, ++ blkno, len, 0, NULL); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1360,6 +1363,7 @@ out: + + brelse(dirdata_bh); + ++ ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -1437,6 +1441,7 @@ static int ocfs2_extend_dir(struct ocfs2 + struct buffer_head *new_bh = NULL; + struct ocfs2_dir_entry * de; + struct super_block *sb = osb->sb; ++ struct ocfs2_extent_tree et; + + mlog_entry_void(); + +@@ -1480,10 +1485,9 @@ static int ocfs2_extend_dir(struct ocfs2 + spin_lock(&OCFS2_I(dir)->ip_lock); + if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) { + spin_unlock(&OCFS2_I(dir)->ip_lock); +- num_free_extents = ocfs2_num_free_extents(osb, dir, +- parent_fe_bh, +- OCFS2_DINODE_EXTENT, +- NULL); ++ ocfs2_get_dinode_extent_tree(&et, dir, parent_fe_bh); ++ num_free_extents = ocfs2_num_free_extents(osb, dir, &et); ++ ocfs2_put_extent_tree(&et); + if (num_free_extents < 0) { + status = num_free_extents; + mlog_errno(status); +Index: linux-2.6.26/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/file.c ++++ linux-2.6.26/fs/ocfs2/file.c +@@ -509,14 +509,17 @@ int ocfs2_add_inode_data(struct ocfs2_su + struct ocfs2_alloc_context *meta_ac, + enum ocfs2_alloc_restarted *reason_ret) + { +- struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; +- struct ocfs2_extent_list *el = &fe->id2.i_list; ++ int ret; ++ struct ocfs2_extent_tree et; + +- return ocfs2_add_clusters_in_btree(osb, inode, logical_offset, ++ ocfs2_get_dinode_extent_tree(&et, inode, fe_bh); ++ ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset, + clusters_to_add, mark_unwritten, +- fe_bh, el, handle, +- data_ac, meta_ac, reason_ret, +- OCFS2_DINODE_EXTENT, NULL); ++ &et, handle, ++ data_ac, meta_ac, reason_ret); ++ ocfs2_put_extent_tree(&et); ++ ++ return ret; + } + + static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, +@@ -533,6 +536,7 @@ static int __ocfs2_extend_allocation(str + struct ocfs2_alloc_context *meta_ac = NULL; + enum ocfs2_alloc_restarted why; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_extent_tree et; + + mlog_entry("(clusters_to_add = %u)\n", clusters_to_add); + +@@ -564,9 +568,10 @@ restart_all: + (unsigned long long)OCFS2_I(inode)->ip_blkno, + (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters), + clusters_to_add); +- status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list, +- clusters_to_add, 0, &data_ac, +- &meta_ac, OCFS2_DINODE_EXTENT, NULL); ++ ocfs2_get_dinode_extent_tree(&et, inode, bh); ++ status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, ++ &data_ac, &meta_ac); ++ ocfs2_put_extent_tree(&et); + if (status) { + mlog_errno(status); + goto leave; +@@ -1236,11 +1241,13 @@ static int __ocfs2_remove_inode_range(st + handle_t *handle; + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ++ struct ocfs2_extent_tree et; ++ ++ ocfs2_get_dinode_extent_tree(&et, inode, di_bh); + +- ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list, +- 0, 1, NULL, &meta_ac, +- OCFS2_DINODE_EXTENT, NULL); ++ ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); + if (ret) { ++ ocfs2_put_extent_tree(&et); + mlog_errno(ret); + return ret; + } +@@ -1269,8 +1276,8 @@ static int __ocfs2_remove_inode_range(st + goto out; + } + +- ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac, +- dealloc, OCFS2_DINODE_EXTENT, NULL); ++ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac, ++ dealloc); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1297,6 +1304,7 @@ out: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + ++ ocfs2_put_extent_tree(&et); + return ret; + } + +Index: linux-2.6.26/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.26/fs/ocfs2/suballoc.c +@@ -1911,12 +1911,11 @@ static inline void ocfs2_debug_suballoc_ + * File systems which don't support holes call this from + * ocfs2_extend_allocation(). + */ +-int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, +- struct ocfs2_extent_list *root_el, ++int ocfs2_lock_allocators(struct inode *inode, ++ struct ocfs2_extent_tree *et, + u32 clusters_to_add, u32 extents_to_split, + struct ocfs2_alloc_context **data_ac, +- struct ocfs2_alloc_context **meta_ac, +- enum ocfs2_extent_tree_type type, void *private) ++ struct ocfs2_alloc_context **meta_ac) + { + int ret = 0, num_free_extents; + unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; +@@ -1928,8 +1927,7 @@ int ocfs2_lock_allocators(struct inode * + + BUG_ON(clusters_to_add != 0 && data_ac == NULL); + +- num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh, +- type, private); ++ num_free_extents = ocfs2_num_free_extents(osb, inode, et); + if (num_free_extents < 0) { + ret = num_free_extents; + mlog_errno(ret); +@@ -1951,7 +1949,7 @@ int ocfs2_lock_allocators(struct inode * + */ + if (!num_free_extents || + (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) { +- ret = ocfs2_reserve_new_metadata(osb, root_el, meta_ac); ++ ret = ocfs2_reserve_new_metadata(osb, et->et_root_el, meta_ac); + if (ret < 0) { + if (ret != -ENOSPC) + mlog_errno(ret); +Index: linux-2.6.26/fs/ocfs2/suballoc.h +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/suballoc.h ++++ linux-2.6.26/fs/ocfs2/suballoc.h +@@ -164,10 +164,8 @@ u64 ocfs2_which_cluster_group(struct ino + int ocfs2_check_group_descriptor(struct super_block *sb, + struct ocfs2_dinode *di, + struct ocfs2_group_desc *gd); +-int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, +- struct ocfs2_extent_list *root_el, ++int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et, + u32 clusters_to_add, u32 extents_to_split, + struct ocfs2_alloc_context **data_ac, +- struct ocfs2_alloc_context **meta_ac, +- enum ocfs2_extent_tree_type type, void *private); ++ struct ocfs2_alloc_context **meta_ac); + #endif /* _CHAINALLOC_H_ */ +Index: linux-2.6.26/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.26.orig/fs/ocfs2/xattr.c ++++ linux-2.6.26/fs/ocfs2/xattr.c +@@ -222,22 +222,24 @@ static int ocfs2_xattr_extend_allocation + struct ocfs2_alloc_context *meta_ac = NULL; + enum ocfs2_alloc_restarted why; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct ocfs2_extent_list *root_el = &xv->xr_list; + u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters); ++ struct ocfs2_extent_tree et; + + mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add); + ++ ocfs2_get_xattr_value_extent_tree(&et, inode, xattr_bh, xv); ++ + restart_all: + +- status = ocfs2_lock_allocators(inode, xattr_bh, root_el, +- clusters_to_add, 0, &data_ac, +- &meta_ac, OCFS2_XATTR_VALUE_EXTENT, xv); ++ status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, ++ &data_ac, &meta_ac); + if (status) { + mlog_errno(status); + goto leave; + } + +- credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add); ++ credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, ++ clusters_to_add); + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); +@@ -260,14 +262,11 @@ restarted_transaction: + &logical_start, + clusters_to_add, + 0, +- xattr_bh, +- root_el, ++ &et, + handle, + data_ac, + meta_ac, +- &why, +- OCFS2_XATTR_VALUE_EXTENT, +- xv); ++ &why); + if ((status < 0) && (status != -EAGAIN)) { + if (status != -ENOSPC) + mlog_errno(status); +@@ -292,7 +291,7 @@ restarted_transaction: + mlog(0, "restarting transaction.\n"); + /* TODO: This can be more intelligent. */ + credits = ocfs2_calc_extend_credits(osb->sb, +- root_el, ++ et.et_root_el, + clusters_to_add); + status = ocfs2_extend_trans(handle, credits); + if (status < 0) { +@@ -324,6 +323,7 @@ leave: + goto restart_all; + } + ++ ocfs2_put_extent_tree(&et); + return status; + } + +@@ -339,11 +339,13 @@ static int __ocfs2_remove_xattr_range(st + struct inode *tl_inode = osb->osb_tl_inode; + handle_t *handle; + struct ocfs2_alloc_context *meta_ac = NULL; ++ struct ocfs2_extent_tree et; ++ ++ ocfs2_get_xattr_value_extent_tree(&et, inode, root_bh, xv); + +- ret = ocfs2_lock_allocators(inode, root_bh, &xv->xr_list, +- 0, 1, NULL, &meta_ac, +- OCFS2_XATTR_VALUE_EXTENT, xv); ++ ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); + if (ret) { ++ ocfs2_put_extent_tree(&et); + mlog_errno(ret); + return ret; + } +@@ -372,8 +374,8 @@ static int __ocfs2_remove_xattr_range(st + goto out_commit; + } + +- ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac, +- dealloc, OCFS2_XATTR_VALUE_EXTENT, xv); ++ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac, ++ dealloc); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -399,6 +401,7 @@ out: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + ++ ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -3638,26 +3641,24 @@ static int ocfs2_add_new_xattr_cluster(s + struct ocfs2_alloc_context *data_ac = NULL; + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)root_bh->b_data; +- struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root; +- struct ocfs2_extent_list *root_el = &xb_root->xt_list; +- enum ocfs2_extent_tree_type type = OCFS2_XATTR_TREE_EXTENT; ++ struct ocfs2_extent_tree et; + + mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, " + "previous xattr blkno = %llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno, + prev_cpos, prev_blkno); + +- ret = ocfs2_lock_allocators(inode, root_bh, root_el, +- clusters_to_add, 0, &data_ac, +- &meta_ac, type, NULL); ++ ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh); ++ ++ ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, ++ &data_ac, &meta_ac); + if (ret) { + mlog_errno(ret); + goto leave; + } + +- credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add); ++ credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, ++ clusters_to_add); + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); +@@ -3721,9 +3722,8 @@ static int ocfs2_add_new_xattr_cluster(s + + mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", + num_bits, block, v_start); +- ret = ocfs2_xattr_tree_insert_extent(osb, handle, inode, root_bh, +- v_start, block, num_bits, +- 0, meta_ac); ++ ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, ++ num_bits, 0, meta_ac); + if (ret < 0) { + mlog_errno(ret); + goto leave; +@@ -3743,6 +3743,7 @@ leave: + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); + ++ ocfs2_put_extent_tree(&et); + return ret; + } + +@@ -4347,9 +4348,11 @@ static int ocfs2_rm_xattr_cluster(struct + handle_t *handle; + struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)root_bh->b_data; +- struct ocfs2_extent_list *root_el = &xb->xb_attrs.xb_root.xt_list; + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_cached_dealloc_ctxt dealloc; ++ struct ocfs2_extent_tree et; ++ ++ ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh); + + ocfs2_init_dealloc_ctxt(&dealloc); + +@@ -4358,10 +4361,9 @@ static int ocfs2_rm_xattr_cluster(struct + + ocfs2_remove_xattr_clusters_from_cache(inode, blkno, len); + +- ret = ocfs2_lock_allocators(inode, root_bh, root_el, +- 0, 1, NULL, &meta_ac, +- OCFS2_XATTR_TREE_EXTENT, NULL); ++ ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); + if (ret) { ++ ocfs2_put_extent_tree(&et); + mlog_errno(ret); + return ret; + } +@@ -4390,8 +4392,8 @@ static int ocfs2_rm_xattr_cluster(struct + goto out_commit; + } + +- ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac, +- &dealloc, OCFS2_XATTR_TREE_EXTENT, NULL); ++ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac, ++ &dealloc); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -4421,6 +4423,7 @@ out: + + ocfs2_run_deallocs(osb, &dealloc); + ++ ocfs2_put_extent_tree(&et); + return ret; + } + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-private-into-object-on-ocfs2_extent_.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-private-into-object-on-ocfs2_extent_.patch new file mode 100644 index 000000000..10eb480a5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Make-private-into-object-on-ocfs2_extent_.patch @@ -0,0 +1,260 @@ +From: Joel Becker +Subject: ocfs2: Make 'private' into 'object' on ocfs2_extent_tree. +Patch-mainline: 2.6.28? +References: FATE302067 + +The 'private' pointer was a way to store off xattr values, which don't +live at a set place in the bh. But the concept of "the object +containing the extent tree" is much more generic. For an inode it's the +struct ocfs2_dinode, for an xattr value its the value. Let's save off +the 'object' at all times. If NULL is passed to +ocfs2_get_extent_tree(), 'object' is set to bh->b_data; + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 62 +++++++++++++++++++++++++---------------------------- + 1 files changed, 29 insertions(+), 33 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 0abf11e..93f44f4 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -79,15 +79,14 @@ struct ocfs2_extent_tree { + struct ocfs2_extent_tree_operations *et_ops; + struct buffer_head *et_root_bh; + struct ocfs2_extent_list *et_root_el; +- void *et_private; ++ void *et_object; + unsigned int et_max_leaf_clusters; + }; + + static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +- struct ocfs2_dinode *di = +- (struct ocfs2_dinode *)et->et_root_bh->b_data; ++ struct ocfs2_dinode *di = et->et_object; + + BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); + di->i_last_eb_blk = cpu_to_le64(blkno); +@@ -95,8 +94,7 @@ static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, + + static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et) + { +- struct ocfs2_dinode *di = +- (struct ocfs2_dinode *)et->et_root_bh->b_data; ++ struct ocfs2_dinode *di = et->et_object; + + BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); + return le64_to_cpu(di->i_last_eb_blk); +@@ -106,8 +104,7 @@ static void ocfs2_dinode_update_clusters(struct inode *inode, + struct ocfs2_extent_tree *et, + u32 clusters) + { +- struct ocfs2_dinode *di = +- (struct ocfs2_dinode *)et->et_root_bh->b_data; ++ struct ocfs2_dinode *di = et->et_object; + + le32_add_cpu(&di->i_clusters, clusters); + spin_lock(&OCFS2_I(inode)->ip_lock); +@@ -123,7 +120,7 @@ static int ocfs2_dinode_sanity_check(struct inode *inode, + + BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); + +- di = (struct ocfs2_dinode *)et->et_root_bh->b_data; ++ di = et->et_object; + if (!OCFS2_IS_VALID_DINODE(di)) { + ret = -EIO; + ocfs2_error(inode->i_sb, +@@ -145,7 +142,7 @@ static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *)et->et_private; ++ (struct ocfs2_xattr_value_root *)et->et_object; + + xv->xr_last_eb_blk = cpu_to_le64(blkno); + } +@@ -153,7 +150,7 @@ static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, + static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et) + { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *) et->et_private; ++ (struct ocfs2_xattr_value_root *) et->et_object; + + return le64_to_cpu(xv->xr_last_eb_blk); + } +@@ -163,7 +160,7 @@ static void ocfs2_xattr_value_update_clusters(struct inode *inode, + u32 clusters) + { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *)et->et_private; ++ (struct ocfs2_xattr_value_root *)et->et_object; + + le32_add_cpu(&xv->xr_clusters, clusters); + } +@@ -184,8 +181,7 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { + static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *) et->et_root_bh->b_data; ++ struct ocfs2_xattr_block *xb = et->et_object; + struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + xt->xt_last_eb_blk = cpu_to_le64(blkno); +@@ -193,8 +189,7 @@ static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, + + static u64 ocfs2_xattr_tree_get_last_eb_blk(struct ocfs2_extent_tree *et) + { +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *) et->et_root_bh->b_data; ++ struct ocfs2_xattr_block *xb = et->et_object; + struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + return le64_to_cpu(xt->xt_last_eb_blk); +@@ -204,8 +199,7 @@ static void ocfs2_xattr_tree_update_clusters(struct inode *inode, + struct ocfs2_extent_tree *et, + u32 clusters) + { +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)et->et_root_bh->b_data; ++ struct ocfs2_xattr_block *xb = et->et_object; + + le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters); + } +@@ -227,26 +221,28 @@ static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, + struct inode *inode, + struct buffer_head *bh, + enum ocfs2_extent_tree_type et_type, +- void *private) ++ void *obj) + { + et->et_type = et_type; + get_bh(bh); + et->et_root_bh = bh; +- et->et_private = private; + et->et_max_leaf_clusters = 0; ++ if (!obj) ++ obj = (void *)bh->b_data; ++ et->et_object = obj; + + if (et_type == OCFS2_DINODE_EXTENT) { + et->et_root_el = +- &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; ++ &((struct ocfs2_dinode *)obj)->id2.i_list; + et->et_ops = &ocfs2_dinode_et_ops; + } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *) private; ++ (struct ocfs2_xattr_value_root *)obj; + et->et_root_el = &xv->xr_list; + et->et_ops = &ocfs2_xattr_et_ops; + } else if (et_type == OCFS2_XATTR_TREE_EXTENT) { + struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)bh->b_data; ++ (struct ocfs2_xattr_block *)obj; + et->et_root_el = &xb->xb_attrs.xb_root.xt_list; + et->et_ops = &ocfs2_xattr_tree_et_ops; + et->et_max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, +@@ -593,7 +589,7 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, + struct buffer_head *root_bh, + enum ocfs2_extent_tree_type type, +- void *private) ++ void *obj) + { + int retval; + struct ocfs2_extent_list *el = NULL; +@@ -617,7 +613,7 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, + el = &fe->id2.i_list; + } else if (type == OCFS2_XATTR_VALUE_EXTENT) { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *) private; ++ (struct ocfs2_xattr_value_root *) obj; + + last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk); + el = &xv->xr_list; +@@ -4450,13 +4446,13 @@ int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, + u32 new_clusters, + u8 flags, + struct ocfs2_alloc_context *meta_ac, +- void *private) ++ void *obj) + { + int status; + struct ocfs2_extent_tree et; + + ocfs2_get_extent_tree(&et, inode, root_bh, +- OCFS2_XATTR_VALUE_EXTENT, private); ++ OCFS2_XATTR_VALUE_EXTENT, obj); + status = ocfs2_insert_extent(osb, handle, inode, root_bh, + cpos, start_blk, new_clusters, + flags, meta_ac, &et); +@@ -4507,7 +4503,7 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, + struct ocfs2_alloc_context *meta_ac, + enum ocfs2_alloc_restarted *reason_ret, + enum ocfs2_extent_tree_type type, +- void *private) ++ void *obj) + { + int status = 0; + int free_extents; +@@ -4522,7 +4518,7 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, + flags = OCFS2_EXT_UNWRITTEN; + + free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type, +- private); ++ obj); + if (free_extents < 0) { + status = free_extents; + mlog_errno(status); +@@ -4584,7 +4580,7 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, + inode, root_bh, + *logical_offset, + block, num_bits, flags, +- meta_ac, private); ++ meta_ac, obj); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -4866,7 +4862,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc, + enum ocfs2_extent_tree_type et_type, +- void *private) ++ void *obj) + { + int ret, index; + u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); +@@ -4878,7 +4874,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + mlog(0, "Inode %lu cpos %u, len %u, phys %u (%llu)\n", + inode->i_ino, cpos, len, phys, (unsigned long long)start_blkno); + +- ocfs2_get_extent_tree(&et, inode, root_bh, et_type, private); ++ ocfs2_get_extent_tree(&et, inode, root_bh, et_type, obj); + + if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) { + ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents " +@@ -5170,7 +5166,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc, + enum ocfs2_extent_tree_type et_type, +- void *private) ++ void *obj) + { + int ret, index; + u32 rec_range, trunc_range; +@@ -5179,7 +5175,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + struct ocfs2_path *path = NULL; + struct ocfs2_extent_tree et; + +- ocfs2_get_extent_tree(&et, inode, root_bh, et_type, private); ++ ocfs2_get_extent_tree(&et, inode, root_bh, et_type, obj); + + ocfs2_extent_map_trunc(inode, 0); + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Mark-system-files-as-not-subject-to-quota-acc.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Mark-system-files-as-not-subject-to-quota-acc.patch new file mode 100644 index 000000000..5d175f5b5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Mark-system-files-as-not-subject-to-quota-acc.patch @@ -0,0 +1,27 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 23/28] ocfs2: Mark system files as not subject to quota accounting +Patch-mainline: 2.6.29? + +Mark system files as not subject to quota accounting. This prevents +possible recursions into quota code and thus deadlocks. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/inode.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -284,8 +284,10 @@ int ocfs2_populate_inode(struct inode *i + + inode->i_nlink = le16_to_cpu(fe->i_links_count); + +- if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) ++ if (fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL)) { + OCFS2_I(inode)->ip_flags |= OCFS2_INODE_SYSTEM_FILE; ++ inode->i_flags |= S_NOQUOTA; ++ } + + if (fe->i_flags & cpu_to_le32(OCFS2_LOCAL_ALLOC_FL)) { + OCFS2_I(inode)->ip_flags |= OCFS2_INODE_BITMAP; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Modify-ocfs2_num_free_extents-f.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Modify-ocfs2_num_free_extents-f.patch new file mode 100644 index 000000000..4912ceb4f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Modify-ocfs2_num_free_extents-f.patch @@ -0,0 +1,142 @@ +From: Tao Ma +Subject: [PATCH 01/16] ocfs2: Modify ocfs2_num_free_extents for future xattr usage. +Patch-mainline: 2.6.28? +References: FATE302067 + +ocfs2_num_free_extents() is used to find the number of free extent records +in an inode btree. Hence, it takes an "ocfs2_dinode" parameter. We want to +use this for extended attribute trees in the future, so genericize the +interface the take a buffer head. A future patch will allow that buffer_head +to contain any structure rooting an ocfs2 btree. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 3 ++- + fs/ocfs2/alloc.h | 2 +- + fs/ocfs2/aops.c | 5 +++-- + fs/ocfs2/dir.c | 3 ++- + fs/ocfs2/file.c | 11 ++++++----- + fs/ocfs2/file.h | 2 +- + 6 files changed, 15 insertions(+), 11 deletions(-) + +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -368,12 +368,13 @@ struct ocfs2_merge_ctxt { + */ + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, +- struct ocfs2_dinode *fe) ++ struct buffer_head *bh) + { + int retval; + struct ocfs2_extent_list *el; + struct ocfs2_extent_block *eb; + struct buffer_head *eb_bh = NULL; ++ struct ocfs2_dinode *fe = (struct ocfs2_dinode *)bh->b_data; + + mlog_entry_void(); + +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -47,7 +47,7 @@ int ocfs2_remove_extent(struct inode *in + struct ocfs2_cached_dealloc_ctxt *dealloc); + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, +- struct ocfs2_dinode *fe); ++ struct buffer_head *bh); + /* how many new metadata chunks would an allocation need at maximum? */ + static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe) + { +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -1712,8 +1712,9 @@ int ocfs2_write_begin_nolock(struct addr + * ocfs2_lock_allocators(). It greatly over-estimates + * the work to be done. + */ +- ret = ocfs2_lock_allocators(inode, di, clusters_to_alloc, +- extents_to_split, &data_ac, &meta_ac); ++ ret = ocfs2_lock_allocators(inode, wc->w_di_bh, ++ clusters_to_alloc, extents_to_split, ++ &data_ac, &meta_ac); + if (ret) { + mlog_errno(ret); + goto out; +--- a/fs/ocfs2/dir.c ++++ b/fs/ocfs2/dir.c +@@ -1479,7 +1479,8 @@ static int ocfs2_extend_dir(struct ocfs2 + spin_lock(&OCFS2_I(dir)->ip_lock); + if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) { + spin_unlock(&OCFS2_I(dir)->ip_lock); +- num_free_extents = ocfs2_num_free_extents(osb, dir, fe); ++ num_free_extents = ocfs2_num_free_extents(osb, dir, ++ parent_fe_bh); + if (num_free_extents < 0) { + status = num_free_extents; + mlog_errno(status); +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -521,7 +521,7 @@ int ocfs2_do_extend_allocation(struct oc + if (mark_unwritten) + flags = OCFS2_EXT_UNWRITTEN; + +- free_extents = ocfs2_num_free_extents(osb, inode, fe); ++ free_extents = ocfs2_num_free_extents(osb, inode, fe_bh); + if (free_extents < 0) { + status = free_extents; + mlog_errno(status); +@@ -609,7 +609,7 @@ leave: + * File systems which don't support holes call this from + * ocfs2_extend_allocation(). + */ +-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, ++int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *di_bh, + u32 clusters_to_add, u32 extents_to_split, + struct ocfs2_alloc_context **data_ac, + struct ocfs2_alloc_context **meta_ac) +@@ -617,6 +617,7 @@ int ocfs2_lock_allocators(struct inode * + int ret = 0, num_free_extents; + unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + + *meta_ac = NULL; + if (data_ac) +@@ -629,7 +630,7 @@ int ocfs2_lock_allocators(struct inode * + (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode), + le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split); + +- num_free_extents = ocfs2_num_free_extents(osb, inode, di); ++ num_free_extents = ocfs2_num_free_extents(osb, inode, di_bh); + if (num_free_extents < 0) { + ret = num_free_extents; + mlog_errno(ret); +@@ -724,7 +725,7 @@ static int __ocfs2_extend_allocation(str + restart_all: + BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters); + +- status = ocfs2_lock_allocators(inode, fe, clusters_to_add, 0, &data_ac, ++ status = ocfs2_lock_allocators(inode, bh, clusters_to_add, 0, &data_ac, + &meta_ac); + if (status) { + mlog_errno(status); +@@ -1395,7 +1396,7 @@ static int __ocfs2_remove_inode_range(st + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + +- ret = ocfs2_lock_allocators(inode, di, 0, 1, NULL, &meta_ac); ++ ret = ocfs2_lock_allocators(inode, di_bh, 0, 1, NULL, &meta_ac); + if (ret) { + mlog_errno(ret); + return ret; +--- a/fs/ocfs2/file.h ++++ b/fs/ocfs2/file.h +@@ -55,7 +55,7 @@ int ocfs2_do_extend_allocation(struct oc + enum ocfs2_alloc_restarted *reason_ret); + int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, + u64 zero_to); +-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, ++int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *fe, + u32 clusters_to_add, u32 extents_to_split, + struct ocfs2_alloc_context **data_ac, + struct ocfs2_alloc_context **meta_ac); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Move-ocfs2_bread-into-dir.c.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Move-ocfs2_bread-into-dir.c.patch new file mode 100644 index 000000000..485d694f5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Move-ocfs2_bread-into-dir.c.patch @@ -0,0 +1,143 @@ +From: Joel Becker +Subject: ocfs2: Move ocfs2_bread() into dir.c +Patch-mainline: 2.6.28 + +dir.c is the only place using ocfs2_bread(), so let's make it static to +that file. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/dir.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/inode.c | 50 -------------------------------------------------- + fs/ocfs2/inode.h | 2 -- + 3 files changed, 43 insertions(+), 52 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dir.c ++++ linux-2.6.27/fs/ocfs2/dir.c +@@ -82,6 +82,49 @@ static int ocfs2_do_extend_dir(struct su + struct ocfs2_alloc_context *meta_ac, + struct buffer_head **new_bh); + ++static struct buffer_head *ocfs2_bread(struct inode *inode, ++ int block, int *err, int reada) ++{ ++ struct buffer_head *bh = NULL; ++ int tmperr; ++ u64 p_blkno; ++ int readflags = OCFS2_BH_CACHED; ++ ++ if (reada) ++ readflags |= OCFS2_BH_READAHEAD; ++ ++ if (((u64)block << inode->i_sb->s_blocksize_bits) >= ++ i_size_read(inode)) { ++ BUG_ON(!reada); ++ return NULL; ++ } ++ ++ down_read(&OCFS2_I(inode)->ip_alloc_sem); ++ tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, ++ NULL); ++ up_read(&OCFS2_I(inode)->ip_alloc_sem); ++ if (tmperr < 0) { ++ mlog_errno(tmperr); ++ goto fail; ++ } ++ ++ tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags); ++ if (tmperr < 0) ++ goto fail; ++ ++ tmperr = 0; ++ ++ *err = 0; ++ return bh; ++ ++fail: ++ brelse(bh); ++ bh = NULL; ++ ++ *err = -EIO; ++ return NULL; ++} ++ + /* + * bh passed here can be an inode block or a dir data block, depending + * on the inode inline data flag. +Index: linux-2.6.27/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.c ++++ linux-2.6.27/fs/ocfs2/inode.c +@@ -1133,56 +1133,6 @@ void ocfs2_drop_inode(struct inode *inod + } + + /* +- * TODO: this should probably be merged into ocfs2_get_block +- * +- * However, you now need to pay attention to the cont_prepare_write() +- * stuff in ocfs2_get_block (that is, ocfs2_get_block pretty much +- * expects never to extend). +- */ +-struct buffer_head *ocfs2_bread(struct inode *inode, +- int block, int *err, int reada) +-{ +- struct buffer_head *bh = NULL; +- int tmperr; +- u64 p_blkno; +- int readflags = OCFS2_BH_CACHED; +- +- if (reada) +- readflags |= OCFS2_BH_READAHEAD; +- +- if (((u64)block << inode->i_sb->s_blocksize_bits) >= +- i_size_read(inode)) { +- BUG_ON(!reada); +- return NULL; +- } +- +- down_read(&OCFS2_I(inode)->ip_alloc_sem); +- tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, +- NULL); +- up_read(&OCFS2_I(inode)->ip_alloc_sem); +- if (tmperr < 0) { +- mlog_errno(tmperr); +- goto fail; +- } +- +- tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags); +- if (tmperr < 0) +- goto fail; +- +- tmperr = 0; +- +- *err = 0; +- return bh; +- +-fail: +- brelse(bh); +- bh = NULL; +- +- *err = -EIO; +- return NULL; +-} +- +-/* + * This is called from our getattr. + */ + int ocfs2_inode_revalidate(struct dentry *dentry) +Index: linux-2.6.27/fs/ocfs2/inode.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.h ++++ linux-2.6.27/fs/ocfs2/inode.h +@@ -117,8 +117,6 @@ extern struct kmem_cache *ocfs2_inode_ca + + extern const struct address_space_operations ocfs2_aops; + +-struct buffer_head *ocfs2_bread(struct inode *inode, int block, +- int *err, int reada); + void ocfs2_clear_inode(struct inode *inode); + void ocfs2_delete_inode(struct inode *inode); + void ocfs2_drop_inode(struct inode *inode); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Move-trusted-and-user-attribute-support-into.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Move-trusted-and-user-attribute-support-into.patch new file mode 100644 index 000000000..f3da96dcd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Move-trusted-and-user-attribute-support-into.patch @@ -0,0 +1,343 @@ +From: Mark Fasheh +Subject: ocfs2: Move trusted and user attribute support into xattr.c +Patch-mainline: 2.6.28 + +Per Christoph Hellwig's suggestion - don't split these up. It's not like we +gained much by having the two tiny files around. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/Makefile | 4 +- + fs/ocfs2/xattr.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/xattr_trusted.c | 82 ---------------------------------- + fs/ocfs2/xattr_user.c | 94 --------------------------------------- + 4 files changed, 111 insertions(+), 179 deletions(-) + delete mode 100644 fs/ocfs2/xattr_trusted.c + delete mode 100644 fs/ocfs2/xattr_user.c + +Index: linux-2.6.27/fs/ocfs2/Makefile +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/Makefile ++++ linux-2.6.27/fs/ocfs2/Makefile +@@ -35,9 +35,7 @@ ocfs2-objs := \ + sysfile.o \ + uptodate.o \ + ver.o \ +- xattr.o \ +- xattr_user.o \ +- xattr_trusted.o ++ xattr.o + + ocfs2_stackglue-objs := stackglue.o + ocfs2_stack_o2cb-objs := stack_o2cb.o +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -37,6 +37,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #define MLOG_MASK_PREFIX ML_XATTR + #include +@@ -4756,3 +4759,110 @@ static int ocfs2_delete_xattr_index_bloc + out: + return ret; + } ++ ++/* ++ * 'trusted' attributes support ++ */ ++ ++#define XATTR_TRUSTED_PREFIX "trusted." ++ ++static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, ++ size_t list_size, const char *name, ++ size_t name_len) ++{ ++ const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1; ++ const size_t total_len = prefix_len + name_len + 1; ++ ++ if (list && total_len <= list_size) { ++ memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); ++ memcpy(list + prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return total_len; ++} ++ ++static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name, ++ buffer, size); ++} ++ ++static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ ++ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value, ++ size, flags); ++} ++ ++struct xattr_handler ocfs2_xattr_trusted_handler = { ++ .prefix = XATTR_TRUSTED_PREFIX, ++ .list = ocfs2_xattr_trusted_list, ++ .get = ocfs2_xattr_trusted_get, ++ .set = ocfs2_xattr_trusted_set, ++}; ++ ++ ++/* ++ * 'user' attributes support ++ */ ++ ++#define XATTR_USER_PREFIX "user." ++ ++static size_t ocfs2_xattr_user_list(struct inode *inode, char *list, ++ size_t list_size, const char *name, ++ size_t name_len) ++{ ++ const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1; ++ const size_t total_len = prefix_len + name_len + 1; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) ++ return 0; ++ ++ if (list && total_len <= list_size) { ++ memcpy(list, XATTR_USER_PREFIX, prefix_len); ++ memcpy(list + prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return total_len; ++} ++ ++static int ocfs2_xattr_user_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) ++ return -EOPNOTSUPP; ++ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name, ++ buffer, size); ++} ++ ++static int ocfs2_xattr_user_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) ++ return -EOPNOTSUPP; ++ ++ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value, ++ size, flags); ++} ++ ++struct xattr_handler ocfs2_xattr_user_handler = { ++ .prefix = XATTR_USER_PREFIX, ++ .list = ocfs2_xattr_user_list, ++ .get = ocfs2_xattr_user_get, ++ .set = ocfs2_xattr_user_set, ++}; +Index: linux-2.6.27/fs/ocfs2/xattr_trusted.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr_trusted.c ++++ /dev/null +@@ -1,82 +0,0 @@ +-/* -*- mode: c; c-basic-offset: 8; -*- +- * vim: noexpandtab sw=8 ts=8 sts=0: +- * +- * xattr_trusted.c +- * +- * Copyright (C) 2008 Oracle. All rights reserved. +- * +- * CREDITS: +- * Lots of code in this file is taken from ext3. +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public +- * License along with this program; if not, write to the +- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, +- * Boston, MA 021110-1307, USA. +- */ +- +-#include +-#include +-#include +- +-#define MLOG_MASK_PREFIX ML_INODE +-#include +- +-#include "ocfs2.h" +-#include "alloc.h" +-#include "dlmglue.h" +-#include "file.h" +-#include "ocfs2_fs.h" +-#include "xattr.h" +- +-#define XATTR_TRUSTED_PREFIX "trusted." +- +-static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, +- size_t list_size, const char *name, +- size_t name_len) +-{ +- const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1; +- const size_t total_len = prefix_len + name_len + 1; +- +- if (list && total_len <= list_size) { +- memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); +- memcpy(list + prefix_len, name, name_len); +- list[prefix_len + name_len] = '\0'; +- } +- return total_len; +-} +- +-static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name, +- void *buffer, size_t size) +-{ +- if (strcmp(name, "") == 0) +- return -EINVAL; +- return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name, +- buffer, size); +-} +- +-static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name, +- const void *value, size_t size, int flags) +-{ +- if (strcmp(name, "") == 0) +- return -EINVAL; +- +- return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value, +- size, flags); +-} +- +-struct xattr_handler ocfs2_xattr_trusted_handler = { +- .prefix = XATTR_TRUSTED_PREFIX, +- .list = ocfs2_xattr_trusted_list, +- .get = ocfs2_xattr_trusted_get, +- .set = ocfs2_xattr_trusted_set, +-}; +Index: linux-2.6.27/fs/ocfs2/xattr_user.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr_user.c ++++ /dev/null +@@ -1,94 +0,0 @@ +-/* -*- mode: c; c-basic-offset: 8; -*- +- * vim: noexpandtab sw=8 ts=8 sts=0: +- * +- * xattr_user.c +- * +- * Copyright (C) 2008 Oracle. All rights reserved. +- * +- * CREDITS: +- * Lots of code in this file is taken from ext3. +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * General Public License for more details. +- * +- * You should have received a copy of the GNU General Public +- * License along with this program; if not, write to the +- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, +- * Boston, MA 021110-1307, USA. +- */ +- +-#include +-#include +-#include +- +-#define MLOG_MASK_PREFIX ML_INODE +-#include +- +-#include "ocfs2.h" +-#include "alloc.h" +-#include "dlmglue.h" +-#include "file.h" +-#include "ocfs2_fs.h" +-#include "xattr.h" +- +-#define XATTR_USER_PREFIX "user." +- +-static size_t ocfs2_xattr_user_list(struct inode *inode, char *list, +- size_t list_size, const char *name, +- size_t name_len) +-{ +- const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1; +- const size_t total_len = prefix_len + name_len + 1; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- +- if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) +- return 0; +- +- if (list && total_len <= list_size) { +- memcpy(list, XATTR_USER_PREFIX, prefix_len); +- memcpy(list + prefix_len, name, name_len); +- list[prefix_len + name_len] = '\0'; +- } +- return total_len; +-} +- +-static int ocfs2_xattr_user_get(struct inode *inode, const char *name, +- void *buffer, size_t size) +-{ +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- +- if (strcmp(name, "") == 0) +- return -EINVAL; +- if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) +- return -EOPNOTSUPP; +- return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name, +- buffer, size); +-} +- +-static int ocfs2_xattr_user_set(struct inode *inode, const char *name, +- const void *value, size_t size, int flags) +-{ +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- +- if (strcmp(name, "") == 0) +- return -EINVAL; +- if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR) +- return -EOPNOTSUPP; +- +- return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value, +- size, flags); +-} +- +-struct xattr_handler ocfs2_xattr_user_handler = { +- .prefix = XATTR_USER_PREFIX, +- .list = ocfs2_xattr_user_list, +- .get = ocfs2_xattr_user_get, +- .set = ocfs2_xattr_user_set, +-}; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Optionally-limit-extent-size-in.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Optionally-limit-extent-size-in.patch new file mode 100644 index 000000000..74c19f794 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Optionally-limit-extent-size-in.patch @@ -0,0 +1,168 @@ +From: Tao Ma +Subject: [PATCH 13/16] ocfs2: Optionally limit extent size in ocfs2_insert_extent() +Patch-mainline: 2.6.28? +References: FATE302067 + +In xattr bucket, we want to limit the maximum size of a btree leaf, +otherwise we'll lose the benefits of hashing because we'll have to search +large leaves. + +So add a new field in ocfs2_extent_tree which indicates the maximum leaf cluster +size we want so that we can prevent ocfs2_insert_extent() from merging the leaf +record even if it is contiguous with an adjacent record. + +Other btree types are not affected by this change. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 39 ++++++++++++++++++++++++++++++--------- + fs/ocfs2/alloc.h | 5 +++++ + 2 files changed, 35 insertions(+), 9 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 47cdea6..16879bd 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -79,6 +79,7 @@ struct ocfs2_extent_tree { + struct buffer_head *root_bh; + struct ocfs2_extent_list *root_el; + void *private; ++ unsigned int max_leaf_clusters; + }; + + static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, +@@ -220,7 +221,8 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + }; + + static struct ocfs2_extent_tree* +- ocfs2_new_extent_tree(struct buffer_head *bh, ++ ocfs2_new_extent_tree(struct inode *inode, ++ struct buffer_head *bh, + enum ocfs2_extent_tree_type et_type, + void *private) + { +@@ -248,6 +250,8 @@ static struct ocfs2_extent_tree* + (struct ocfs2_xattr_block *)bh->b_data; + et->root_el = &xb->xb_attrs.xb_root.xt_list; + et->eops = &ocfs2_xattr_tree_et_ops; ++ et->max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, ++ OCFS2_MAX_XATTR_TREE_LEAF_SIZE); + } + + return et; +@@ -4118,7 +4122,8 @@ out: + static void ocfs2_figure_contig_type(struct inode *inode, + struct ocfs2_insert_type *insert, + struct ocfs2_extent_list *el, +- struct ocfs2_extent_rec *insert_rec) ++ struct ocfs2_extent_rec *insert_rec, ++ struct ocfs2_extent_tree *et) + { + int i; + enum ocfs2_contig_type contig_type = CONTIG_NONE; +@@ -4134,6 +4139,20 @@ static void ocfs2_figure_contig_type(struct inode *inode, + } + } + insert->ins_contig = contig_type; ++ ++ if (insert->ins_contig != CONTIG_NONE) { ++ struct ocfs2_extent_rec *rec = ++ &el->l_recs[insert->ins_contig_index]; ++ unsigned int len = le16_to_cpu(rec->e_leaf_clusters) + ++ le16_to_cpu(insert_rec->e_leaf_clusters); ++ ++ /* ++ * Caller might want us to limit the size of extents, don't ++ * calculate contiguousness if we might exceed that limit. ++ */ ++ if (et->max_leaf_clusters && len > et->max_leaf_clusters) ++ insert->ins_contig = CONTIG_NONE; ++ } + } + + /* +@@ -4241,7 +4260,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, + le16_to_cpu(el->l_next_free_rec); + + if (!insert->ins_tree_depth) { +- ocfs2_figure_contig_type(inode, insert, el, insert_rec); ++ ocfs2_figure_contig_type(inode, insert, el, insert_rec, et); + ocfs2_figure_appending_type(insert, el, insert_rec); + return 0; + } +@@ -4275,7 +4294,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, + * into two types of appends: simple record append, or a + * rotate inside the tail leaf. + */ +- ocfs2_figure_contig_type(inode, insert, el, insert_rec); ++ ocfs2_figure_contig_type(inode, insert, el, insert_rec, et); + + /* + * The insert code isn't quite ready to deal with all cases of +@@ -4411,7 +4430,7 @@ int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, + int status; + struct ocfs2_extent_tree *et = NULL; + +- et = ocfs2_new_extent_tree(root_bh, OCFS2_DINODE_EXTENT, NULL); ++ et = ocfs2_new_extent_tree(inode, root_bh, OCFS2_DINODE_EXTENT, NULL); + if (!et) { + status = -ENOMEM; + mlog_errno(status); +@@ -4442,7 +4461,8 @@ int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, + int status; + struct ocfs2_extent_tree *et = NULL; + +- et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_VALUE_EXTENT, private); ++ et = ocfs2_new_extent_tree(inode, root_bh, ++ OCFS2_XATTR_VALUE_EXTENT, private); + if (!et) { + status = -ENOMEM; + mlog_errno(status); +@@ -4472,7 +4492,8 @@ int ocfs2_xattr_tree_insert_extent(struct ocfs2_super *osb, + int status; + struct ocfs2_extent_tree *et = NULL; + +- et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_TREE_EXTENT, NULL); ++ et = ocfs2_new_extent_tree(inode, root_bh, OCFS2_XATTR_TREE_EXTENT, ++ NULL); + if (!et) { + status = -ENOMEM; + mlog_errno(status); +@@ -4888,7 +4909,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + goto out; + } + +- et = ocfs2_new_extent_tree(root_bh, et_type, private); ++ et = ocfs2_new_extent_tree(inode, root_bh, et_type, private); + if (!et) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -5186,7 +5207,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + struct ocfs2_path *path = NULL; + struct ocfs2_extent_tree *et = NULL; + +- et = ocfs2_new_extent_tree(root_bh, et_type, private); ++ et = ocfs2_new_extent_tree(inode, root_bh, et_type, private); + if (!et) { + ret = -ENOMEM; + mlog_errno(ret); +diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h +index b8cfc53..ff40c8f 100644 +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -32,6 +32,11 @@ enum ocfs2_extent_tree_type { + OCFS2_XATTR_TREE_EXTENT, + }; + ++/* ++ * For xattr tree leaf, we limit the leaf byte size to be 64K. ++ */ ++#define OCFS2_MAX_XATTR_TREE_LEAF_SIZE 65536 ++ + struct ocfs2_alloc_context; + int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, + handle_t *handle, +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-POSIX-file-locks-support.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-POSIX-file-locks-support.patch new file mode 100644 index 000000000..dc52231ad --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-POSIX-file-locks-support.patch @@ -0,0 +1,326 @@ +From: Mark Fasheh +Subject: ocfs2: POSIX file locks support +Patch-mainline: 2.6.28? +References: FATE110294 + +This is actually pretty easy since fs/dlm already handles the bulk of the +work. The Ocfs2 userspace cluster stack module already uses fs/dlm as the +underlying lock manager, so I only had to add the right calls. + +Cluster-aware POSIX locks ("plocks") can be turned off by the same means at +UNIX locks - mount with 'noflocks', or create a local-only Ocfs2 volume. +Internally, the file system uses two sets of file_operations, depending on +whether cluster aware plocks is required. This turns out to be easier than +implementing local-only versions of ->lock. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/file.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/file.h | 2 + + fs/ocfs2/inode.c | 15 ++++++++++++-- + fs/ocfs2/locks.c | 15 ++++++++++++++ + fs/ocfs2/locks.h | 1 + fs/ocfs2/stack_user.c | 33 ++++++++++++++++++++++++++++++++ + fs/ocfs2/stackglue.c | 20 +++++++++++++++++++ + fs/ocfs2/stackglue.h | 19 ++++++++++++++++++ + 8 files changed, 154 insertions(+), 2 deletions(-) + +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -2154,6 +2154,10 @@ const struct inode_operations ocfs2_spec + .permission = ocfs2_permission, + }; + ++/* ++ * Other than ->lock, keep ocfs2_fops and ocfs2_dops in sync with ++ * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks! ++ */ + const struct file_operations ocfs2_fops = { + .llseek = generic_file_llseek, + .read = do_sync_read, +@@ -2168,6 +2172,7 @@ const struct file_operations ocfs2_fops + #ifdef CONFIG_COMPAT + .compat_ioctl = ocfs2_compat_ioctl, + #endif ++ .lock = ocfs2_lock, + .flock = ocfs2_flock, + .splice_read = ocfs2_file_splice_read, + .splice_write = ocfs2_file_splice_write, +@@ -2177,6 +2182,52 @@ const struct file_operations ocfs2_dops + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = ocfs2_readdir, ++ .fsync = ocfs2_sync_file, ++ .release = ocfs2_dir_release, ++ .open = ocfs2_dir_open, ++ .unlocked_ioctl = ocfs2_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = ocfs2_compat_ioctl, ++#endif ++ .lock = ocfs2_lock, ++ .flock = ocfs2_flock, ++}; ++ ++/* ++ * POSIX-lockless variants of our file_operations. ++ * ++ * These will be used if the underlying cluster stack does not support ++ * posix file locking, if the user passes the "localflocks" mount ++ * option, or if we have a local-only fs. ++ * ++ * ocfs2_flock is in here because all stacks handle UNIX file locks, ++ * so we still want it in the case of no stack support for ++ * plocks. Internally, it will do the right thing when asked to ignore ++ * the cluster. ++ */ ++const struct file_operations ocfs2_fops_no_plocks = { ++ .llseek = generic_file_llseek, ++ .read = do_sync_read, ++ .write = do_sync_write, ++ .mmap = ocfs2_mmap, ++ .fsync = ocfs2_sync_file, ++ .release = ocfs2_file_release, ++ .open = ocfs2_file_open, ++ .aio_read = ocfs2_file_aio_read, ++ .aio_write = ocfs2_file_aio_write, ++ .unlocked_ioctl = ocfs2_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = ocfs2_compat_ioctl, ++#endif ++ .flock = ocfs2_flock, ++ .splice_read = ocfs2_file_splice_read, ++ .splice_write = ocfs2_file_splice_write, ++}; ++ ++const struct file_operations ocfs2_dops_no_plocks = { ++ .llseek = generic_file_llseek, ++ .read = generic_read_dir, ++ .readdir = ocfs2_readdir, + .fsync = ocfs2_sync_file, + .release = ocfs2_dir_release, + .open = ocfs2_dir_open, +--- a/fs/ocfs2/file.h ++++ b/fs/ocfs2/file.h +@@ -28,6 +28,8 @@ + + extern const struct file_operations ocfs2_fops; + extern const struct file_operations ocfs2_dops; ++extern const struct file_operations ocfs2_fops_no_plocks; ++extern const struct file_operations ocfs2_dops_no_plocks; + extern const struct inode_operations ocfs2_file_iops; + extern const struct inode_operations ocfs2_special_file_iops; + struct ocfs2_alloc_context; +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -220,6 +220,7 @@ int ocfs2_populate_inode(struct inode *i + struct super_block *sb; + struct ocfs2_super *osb; + int status = -EINVAL; ++ int use_plocks = 1; + + mlog_entry("(0x%p, size:%llu)\n", inode, + (unsigned long long)le64_to_cpu(fe->i_size)); +@@ -227,6 +228,10 @@ int ocfs2_populate_inode(struct inode *i + sb = inode->i_sb; + osb = OCFS2_SB(sb); + ++ if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) || ++ ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks()) ++ use_plocks = 0; ++ + /* this means that read_inode cannot create a superblock inode + * today. change if needed. */ + if (!OCFS2_IS_VALID_DINODE(fe) || +@@ -296,13 +301,19 @@ int ocfs2_populate_inode(struct inode *i + + switch (inode->i_mode & S_IFMT) { + case S_IFREG: +- inode->i_fop = &ocfs2_fops; ++ if (use_plocks) ++ inode->i_fop = &ocfs2_fops; ++ else ++ inode->i_fop = &ocfs2_fops_no_plocks; + inode->i_op = &ocfs2_file_iops; + i_size_write(inode, le64_to_cpu(fe->i_size)); + break; + case S_IFDIR: + inode->i_op = &ocfs2_dir_iops; +- inode->i_fop = &ocfs2_dops; ++ if (use_plocks) ++ inode->i_fop = &ocfs2_dops; ++ else ++ inode->i_fop = &ocfs2_dops_no_plocks; + i_size_write(inode, le64_to_cpu(fe->i_size)); + break; + case S_IFLNK: +--- a/fs/ocfs2/locks.c ++++ b/fs/ocfs2/locks.c +@@ -24,6 +24,7 @@ + */ + + #include ++#include + + #define MLOG_MASK_PREFIX ML_INODE + #include +@@ -32,6 +33,7 @@ + + #include "dlmglue.h" + #include "file.h" ++#include "inode.h" + #include "locks.h" + + static int ocfs2_do_flock(struct file *file, struct inode *inode, +@@ -123,3 +125,16 @@ int ocfs2_flock(struct file *file, int c + else + return ocfs2_do_flock(file, inode, cmd, fl); + } ++ ++int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl) ++{ ++ struct inode *inode = file->f_mapping->host; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ if (!(fl->fl_flags & FL_POSIX)) ++ return -ENOLCK; ++ if (__mandatory_lock(inode)) ++ return -ENOLCK; ++ ++ return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl); ++} +--- a/fs/ocfs2/locks.h ++++ b/fs/ocfs2/locks.h +@@ -27,5 +27,6 @@ + #define OCFS2_LOCKS_H + + int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl); ++int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl); + + #endif /* OCFS2_LOCKS_H */ +--- a/fs/ocfs2/stack_user.c ++++ b/fs/ocfs2/stack_user.c +@@ -28,6 +28,7 @@ + #include "ocfs2.h" /* For struct ocfs2_lock_res */ + #include "stackglue.h" + ++#include + + /* + * The control protocol starts with a handshake. Until the handshake +@@ -746,6 +747,37 @@ static void user_dlm_dump_lksb(union ocf + { + } + ++static int user_plock(struct ocfs2_cluster_connection *conn, ++ u64 ino, ++ struct file *file, ++ int cmd, ++ struct file_lock *fl) ++{ ++ /* ++ * This more or less just demuxes the plock request into any ++ * one of three dlm calls. ++ * ++ * Internally, fs/dlm will pass these to a misc device, which ++ * a userspace daemon will read and write to. ++ * ++ * For now, cancel requests (which happen internally only), ++ * are turned into unlocks. Most of this function taken from ++ * gfs2_lock. ++ */ ++ ++ if (cmd == F_CANCELLK) { ++ cmd = F_SETLK; ++ fl->fl_type = F_UNLCK; ++ } ++ ++ if (IS_GETLK(cmd)) ++ return dlm_posix_get(conn->cc_lockspace, ino, file, fl); ++ else if (fl->fl_type == F_UNLCK) ++ return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl); ++ else ++ return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl); ++} ++ + /* + * Compare a requested locking protocol version against the current one. + * +@@ -839,6 +871,7 @@ static struct ocfs2_stack_operations ocf + .dlm_unlock = user_dlm_unlock, + .lock_status = user_dlm_lock_status, + .lock_lvb = user_dlm_lvb, ++ .plock = user_plock, + .dump_lksb = user_dlm_dump_lksb, + }; + +--- a/fs/ocfs2/stackglue.c ++++ b/fs/ocfs2/stackglue.c +@@ -288,6 +288,26 @@ void ocfs2_dlm_dump_lksb(union ocfs2_dlm + } + EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); + ++int ocfs2_stack_supports_plocks(void) ++{ ++ return !!(active_stack && active_stack->sp_ops->plock); ++} ++EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks); ++ ++/* ++ * ocfs2_plock() can only be safely called if ++ * ocfs2_stack_supports_plocks() returned true ++ */ ++int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, ++ struct file *file, int cmd, struct file_lock *fl) ++{ ++ WARN_ON_ONCE(active_stack->sp_ops->plock == NULL); ++ if (active_stack->sp_ops->plock) ++ return active_stack->sp_ops->plock(conn, ino, file, cmd, fl); ++ return -EOPNOTSUPP; ++} ++EXPORT_SYMBOL_GPL(ocfs2_plock); ++ + int ocfs2_cluster_connect(const char *stack_name, + const char *group, + int grouplen, +--- a/fs/ocfs2/stackglue.h ++++ b/fs/ocfs2/stackglue.h +@@ -28,6 +28,10 @@ + #include "dlm/dlmapi.h" + #include + ++/* Needed for plock-related prototypes */ ++struct file; ++struct file_lock; ++ + /* + * dlmconstants.h does not have a LOCAL flag. We hope to remove it + * some day, but right now we need it. Let's fake it. This value is larger +@@ -187,6 +191,17 @@ struct ocfs2_stack_operations { + void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); + + /* ++ * Cluster-aware posix locks ++ * ++ * This is NULL for stacks which do not support posix locks. ++ */ ++ int (*plock)(struct ocfs2_cluster_connection *conn, ++ u64 ino, ++ struct file *file, ++ int cmd, ++ struct file_lock *fl); ++ ++ /* + * This is an optoinal debugging hook. If provided, the + * stack can dump debugging information about this lock. + */ +@@ -240,6 +255,10 @@ int ocfs2_dlm_lock_status(union ocfs2_dl + void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); + void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); + ++int ocfs2_stack_supports_plocks(void); ++int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, ++ struct file *file, int cmd, struct file_lock *fl); ++ + void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto); + + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Prefix-the-extent-tree-operations-structure.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Prefix-the-extent-tree-operations-structure.patch new file mode 100644 index 000000000..b248384f4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Prefix-the-extent-tree-operations-structure.patch @@ -0,0 +1,227 @@ +From: Joel Becker +Subject: ocfs2: Prefix the extent tree operations structure. +Patch-mainline: 2.6.28? +References: FATE302067 + +The ocfs2_extent_tree_operations structure gains a field prefix on its +members. The ->eo_sanity_check() operation gains a wrapper function for +completeness. All of the extent tree operation wrappers gain a +consistent name (ocfs2_et_*()). + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 85 +++++++++++++++++++++++++++++------------------------ + 1 files changed, 46 insertions(+), 39 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 16879bd..9fe49f2 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -65,12 +65,13 @@ + struct ocfs2_extent_tree; + + struct ocfs2_extent_tree_operations { +- void (*set_last_eb_blk) (struct ocfs2_extent_tree *et, u64 blkno); +- u64 (*get_last_eb_blk) (struct ocfs2_extent_tree *et); +- void (*update_clusters) (struct inode *inode, +- struct ocfs2_extent_tree *et, +- u32 new_clusters); +- int (*sanity_check) (struct inode *inode, struct ocfs2_extent_tree *et); ++ void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et, ++ u64 blkno); ++ u64 (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et); ++ void (*eo_update_clusters)(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 new_clusters); ++ int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et); + }; + + struct ocfs2_extent_tree { +@@ -132,10 +133,10 @@ static int ocfs2_dinode_sanity_check(struct inode *inode, + } + + static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { +- .set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, +- .get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, +- .update_clusters = ocfs2_dinode_update_clusters, +- .sanity_check = ocfs2_dinode_sanity_check, ++ .eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, ++ .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, ++ .eo_update_clusters = ocfs2_dinode_update_clusters, ++ .eo_sanity_check = ocfs2_dinode_sanity_check, + }; + + static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, +@@ -172,10 +173,10 @@ static int ocfs2_xattr_value_sanity_check(struct inode *inode, + } + + static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { +- .set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, +- .get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, +- .update_clusters = ocfs2_xattr_value_update_clusters, +- .sanity_check = ocfs2_xattr_value_sanity_check, ++ .eo_set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, ++ .eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, ++ .eo_update_clusters = ocfs2_xattr_value_update_clusters, ++ .eo_sanity_check = ocfs2_xattr_value_sanity_check, + }; + + static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, +@@ -214,10 +215,10 @@ static int ocfs2_xattr_tree_sanity_check(struct inode *inode, + } + + static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { +- .set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk, +- .get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, +- .update_clusters = ocfs2_xattr_tree_update_clusters, +- .sanity_check = ocfs2_xattr_tree_sanity_check, ++ .eo_set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk, ++ .eo_get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, ++ .eo_update_clusters = ocfs2_xattr_tree_update_clusters, ++ .eo_sanity_check = ocfs2_xattr_tree_sanity_check, + }; + + static struct ocfs2_extent_tree* +@@ -265,22 +266,28 @@ static void ocfs2_free_extent_tree(struct ocfs2_extent_tree *et) + } + } + +-static inline void ocfs2_set_last_eb_blk(struct ocfs2_extent_tree *et, +- u64 new_last_eb_blk) ++static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et, ++ u64 new_last_eb_blk) + { +- et->eops->set_last_eb_blk(et, new_last_eb_blk); ++ et->eops->eo_set_last_eb_blk(et, new_last_eb_blk); + } + +-static inline u64 ocfs2_get_last_eb_blk(struct ocfs2_extent_tree *et) ++static inline u64 ocfs2_et_get_last_eb_blk(struct ocfs2_extent_tree *et) + { +- return et->eops->get_last_eb_blk(et); ++ return et->eops->eo_get_last_eb_blk(et); + } + +-static inline void ocfs2_update_clusters(struct inode *inode, +- struct ocfs2_extent_tree *et, +- u32 clusters) ++static inline void ocfs2_et_update_clusters(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 clusters) ++{ ++ et->eops->eo_update_clusters(inode, et, clusters); ++} ++ ++static inline int ocfs2_et_sanity_check(struct inode *inode, ++ struct ocfs2_extent_tree *et) + { +- et->eops->update_clusters(inode, et, clusters); ++ return et->eops->eo_sanity_check(inode, et); + } + + static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc); +@@ -913,7 +920,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, + + /* fe needs a new last extent block pointer, as does the + * next_leaf on the previously last-extent-block. */ +- ocfs2_set_last_eb_blk(et, new_last_eb_blk); ++ ocfs2_et_set_last_eb_blk(et, new_last_eb_blk); + + eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data; + eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk); +@@ -1029,7 +1036,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, + /* If this is our 1st tree depth shift, then last_eb_blk + * becomes the allocated extent block */ + if (root_el->l_tree_depth == cpu_to_le16(1)) +- ocfs2_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); ++ ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + + status = ocfs2_journal_dirty(handle, et->root_bh); + if (status < 0) { +@@ -2436,7 +2443,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle, + ocfs2_update_edge_lengths(inode, handle, left_path); + + eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; +- ocfs2_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); ++ ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + + /* + * Removal of the extent in the left leaf was skipped +@@ -2697,7 +2704,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, + struct ocfs2_extent_list *el; + + +- ret = et->eops->sanity_check(inode, et); ++ ret = ocfs2_et_sanity_check(inode, et); + if (ret) + goto out; + /* +@@ -2756,7 +2763,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, + ocfs2_update_edge_lengths(inode, handle, left_path); + + eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; +- ocfs2_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); ++ ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + } else { + /* + * 'path' is also the leftmost path which +@@ -2772,7 +2779,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, + el->l_next_free_rec = 0; + memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); + +- ocfs2_set_last_eb_blk(et, 0); ++ ocfs2_et_set_last_eb_blk(et, 0); + } + + ocfs2_journal_dirty(handle, path_root_bh(path)); +@@ -3989,8 +3996,8 @@ static int ocfs2_do_insert_extent(struct inode *inode, + + out_update_clusters: + if (type->ins_split == SPLIT_NONE) +- ocfs2_update_clusters(inode, et, +- le16_to_cpu(insert_rec->e_leaf_clusters)); ++ ocfs2_et_update_clusters(inode, et, ++ le16_to_cpu(insert_rec->e_leaf_clusters)); + + ret = ocfs2_journal_dirty(handle, et->root_bh); + if (ret) +@@ -4238,7 +4245,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, + * may want it later. + */ + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- ocfs2_get_last_eb_blk(et), &bh, ++ ocfs2_et_get_last_eb_blk(et), &bh, + OCFS2_BH_CACHED, inode); + if (ret) { + mlog_exit(ret); +@@ -4315,7 +4322,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, + * the case that we're doing a tail append, so maybe we can + * take advantage of that information somehow. + */ +- if (ocfs2_get_last_eb_blk(et) == ++ if (ocfs2_et_get_last_eb_blk(et) == + path_leaf_bh(path)->b_blocknr) { + /* + * Ok, ocfs2_find_path() returned us the rightmost +@@ -4823,7 +4830,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode, + struct ocfs2_extent_block *eb; + + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- ocfs2_get_last_eb_blk(et), ++ ocfs2_et_get_last_eb_blk(et), + &last_eb_bh, OCFS2_BH_CACHED, inode); + if (ret) { + mlog_exit(ret); +@@ -4990,7 +4997,7 @@ static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et, + depth = path->p_tree_depth; + if (depth > 0) { + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- ocfs2_get_last_eb_blk(et), ++ ocfs2_et_get_last_eb_blk(et), + &last_eb_bh, OCFS2_BH_CACHED, inode); + if (ret < 0) { + mlog_errno(ret); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Prefix-the-ocfs2_extent_tree-structure.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Prefix-the-ocfs2_extent_tree-structure.patch new file mode 100644 index 000000000..263a2854d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Prefix-the-ocfs2_extent_tree-structure.patch @@ -0,0 +1,415 @@ +From: Joel Becker +Subject: ocfs2: Prefix the ocfs2_extent_tree structure. +Patch-mainline: 2.6.28? +References: FATE302067 + +The members of the ocfs2_extent_tree structure gain a prefix of 'et_'. +All users are updated. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 118 ++++++++++++++++++++++++++++-------------------------- + 1 files changed, 61 insertions(+), 57 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 9fe49f2..ab16b89 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -75,28 +75,30 @@ struct ocfs2_extent_tree_operations { + }; + + struct ocfs2_extent_tree { +- enum ocfs2_extent_tree_type type; +- struct ocfs2_extent_tree_operations *eops; +- struct buffer_head *root_bh; +- struct ocfs2_extent_list *root_el; +- void *private; +- unsigned int max_leaf_clusters; ++ enum ocfs2_extent_tree_type et_type; ++ struct ocfs2_extent_tree_operations *et_ops; ++ struct buffer_head *et_root_bh; ++ struct ocfs2_extent_list *et_root_el; ++ void *et_private; ++ unsigned int et_max_leaf_clusters; + }; + + static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)et->root_bh->b_data; ++ struct ocfs2_dinode *di = ++ (struct ocfs2_dinode *)et->et_root_bh->b_data; + +- BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); + di->i_last_eb_blk = cpu_to_le64(blkno); + } + + static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et) + { +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)et->root_bh->b_data; ++ struct ocfs2_dinode *di = ++ (struct ocfs2_dinode *)et->et_root_bh->b_data; + +- BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); + return le64_to_cpu(di->i_last_eb_blk); + } + +@@ -105,7 +107,7 @@ static void ocfs2_dinode_update_clusters(struct inode *inode, + u32 clusters) + { + struct ocfs2_dinode *di = +- (struct ocfs2_dinode *)et->root_bh->b_data; ++ (struct ocfs2_dinode *)et->et_root_bh->b_data; + + le32_add_cpu(&di->i_clusters, clusters); + spin_lock(&OCFS2_I(inode)->ip_lock); +@@ -119,9 +121,9 @@ static int ocfs2_dinode_sanity_check(struct inode *inode, + int ret = 0; + struct ocfs2_dinode *di; + +- BUG_ON(et->type != OCFS2_DINODE_EXTENT); ++ BUG_ON(et->et_type != OCFS2_DINODE_EXTENT); + +- di = (struct ocfs2_dinode *)et->root_bh->b_data; ++ di = (struct ocfs2_dinode *)et->et_root_bh->b_data; + if (!OCFS2_IS_VALID_DINODE(di)) { + ret = -EIO; + ocfs2_error(inode->i_sb, +@@ -143,7 +145,7 @@ static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *)et->private; ++ (struct ocfs2_xattr_value_root *)et->et_private; + + xv->xr_last_eb_blk = cpu_to_le64(blkno); + } +@@ -151,7 +153,7 @@ static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, + static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et) + { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *) et->private; ++ (struct ocfs2_xattr_value_root *) et->et_private; + + return le64_to_cpu(xv->xr_last_eb_blk); + } +@@ -161,7 +163,7 @@ static void ocfs2_xattr_value_update_clusters(struct inode *inode, + u32 clusters) + { + struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *)et->private; ++ (struct ocfs2_xattr_value_root *)et->et_private; + + le32_add_cpu(&xv->xr_clusters, clusters); + } +@@ -183,7 +185,7 @@ static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { + struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *) et->root_bh->b_data; ++ (struct ocfs2_xattr_block *) et->et_root_bh->b_data; + struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + xt->xt_last_eb_blk = cpu_to_le64(blkno); +@@ -192,7 +194,7 @@ static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, + static u64 ocfs2_xattr_tree_get_last_eb_blk(struct ocfs2_extent_tree *et) + { + struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *) et->root_bh->b_data; ++ (struct ocfs2_xattr_block *) et->et_root_bh->b_data; + struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + return le64_to_cpu(xt->xt_last_eb_blk); +@@ -203,7 +205,7 @@ static void ocfs2_xattr_tree_update_clusters(struct inode *inode, + u32 clusters) + { + struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)et->root_bh->b_data; ++ (struct ocfs2_xattr_block *)et->et_root_bh->b_data; + + le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters); + } +@@ -233,25 +235,26 @@ static struct ocfs2_extent_tree* + if (!et) + return NULL; + +- et->type = et_type; ++ et->et_type = et_type; + get_bh(bh); +- et->root_bh = bh; +- et->private = private; ++ et->et_root_bh = bh; ++ et->et_private = private; + + if (et_type == OCFS2_DINODE_EXTENT) { +- et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; +- et->eops = &ocfs2_dinode_et_ops; ++ et->et_root_el = ++ &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; ++ et->et_ops = &ocfs2_dinode_et_ops; + } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) { + struct ocfs2_xattr_value_root *xv = + (struct ocfs2_xattr_value_root *) private; +- et->root_el = &xv->xr_list; +- et->eops = &ocfs2_xattr_et_ops; ++ et->et_root_el = &xv->xr_list; ++ et->et_ops = &ocfs2_xattr_et_ops; + } else if (et_type == OCFS2_XATTR_TREE_EXTENT) { + struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)bh->b_data; +- et->root_el = &xb->xb_attrs.xb_root.xt_list; +- et->eops = &ocfs2_xattr_tree_et_ops; +- et->max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, ++ et->et_root_el = &xb->xb_attrs.xb_root.xt_list; ++ et->et_ops = &ocfs2_xattr_tree_et_ops; ++ et->et_max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, + OCFS2_MAX_XATTR_TREE_LEAF_SIZE); + } + +@@ -261,7 +264,7 @@ static struct ocfs2_extent_tree* + static void ocfs2_free_extent_tree(struct ocfs2_extent_tree *et) + { + if (et) { +- brelse(et->root_bh); ++ brelse(et->et_root_bh); + kfree(et); + } + } +@@ -269,25 +272,25 @@ static void ocfs2_free_extent_tree(struct ocfs2_extent_tree *et) + static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 new_last_eb_blk) + { +- et->eops->eo_set_last_eb_blk(et, new_last_eb_blk); ++ et->et_ops->eo_set_last_eb_blk(et, new_last_eb_blk); + } + + static inline u64 ocfs2_et_get_last_eb_blk(struct ocfs2_extent_tree *et) + { +- return et->eops->eo_get_last_eb_blk(et); ++ return et->et_ops->eo_get_last_eb_blk(et); + } + + static inline void ocfs2_et_update_clusters(struct inode *inode, + struct ocfs2_extent_tree *et, + u32 clusters) + { +- et->eops->eo_update_clusters(inode, et, clusters); ++ et->et_ops->eo_update_clusters(inode, et, clusters); + } + + static inline int ocfs2_et_sanity_check(struct inode *inode, + struct ocfs2_extent_tree *et) + { +- return et->eops->eo_sanity_check(inode, et); ++ return et->et_ops->eo_sanity_check(inode, et); + } + + static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc); +@@ -805,7 +808,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, + eb = (struct ocfs2_extent_block *) eb_bh->b_data; + el = &eb->h_list; + } else +- el = et->root_el; ++ el = et->et_root_el; + + /* we never add a branch to a leaf. */ + BUG_ON(!el->l_tree_depth); +@@ -895,7 +898,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, + mlog_errno(status); + goto bail; + } +- status = ocfs2_journal_access(handle, inode, et->root_bh, ++ status = ocfs2_journal_access(handle, inode, et->et_root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); +@@ -928,7 +931,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, + status = ocfs2_journal_dirty(handle, *last_eb_bh); + if (status < 0) + mlog_errno(status); +- status = ocfs2_journal_dirty(handle, et->root_bh); ++ status = ocfs2_journal_dirty(handle, et->et_root_bh); + if (status < 0) + mlog_errno(status); + if (eb_bh) { +@@ -994,7 +997,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, + } + + eb_el = &eb->h_list; +- root_el = et->root_el; ++ root_el = et->et_root_el; + + status = ocfs2_journal_access(handle, inode, new_eb_bh, + OCFS2_JOURNAL_ACCESS_CREATE); +@@ -1015,7 +1018,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, + goto bail; + } + +- status = ocfs2_journal_access(handle, inode, et->root_bh, ++ status = ocfs2_journal_access(handle, inode, et->et_root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { + mlog_errno(status); +@@ -1038,7 +1041,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, + if (root_el->l_tree_depth == cpu_to_le16(1)) + ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); + +- status = ocfs2_journal_dirty(handle, et->root_bh); ++ status = ocfs2_journal_dirty(handle, et->et_root_bh); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1088,7 +1091,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb, + + *target_bh = NULL; + +- el = et->root_el; ++ el = et->et_root_el; + + while(le16_to_cpu(el->l_tree_depth) > 1) { + if (le16_to_cpu(el->l_next_free_rec) == 0) { +@@ -1140,7 +1143,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb, + + /* If we didn't find one and the fe doesn't have any room, + * then return '1' */ +- el = et->root_el; ++ el = et->et_root_el; + if (!lowest_bh && (el->l_next_free_rec == el->l_count)) + status = 1; + +@@ -1169,7 +1172,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle, + struct ocfs2_alloc_context *meta_ac) + { + int ret, shift; +- struct ocfs2_extent_list *el = et->root_el; ++ struct ocfs2_extent_list *el = et->et_root_el; + int depth = le16_to_cpu(el->l_tree_depth); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct buffer_head *bh = NULL; +@@ -2774,7 +2777,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, + */ + ocfs2_unlink_path(inode, handle, dealloc, path, 1); + +- el = et->root_el; ++ el = et->et_root_el; + el->l_tree_depth = 0; + el->l_next_free_rec = 0; + memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec)); +@@ -3907,9 +3910,9 @@ static int ocfs2_do_insert_extent(struct inode *inode, + struct ocfs2_path *left_path = NULL; + struct ocfs2_extent_list *el; + +- el = et->root_el; ++ el = et->et_root_el; + +- ret = ocfs2_journal_access(handle, inode, et->root_bh, ++ ret = ocfs2_journal_access(handle, inode, et->et_root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -3921,7 +3924,7 @@ static int ocfs2_do_insert_extent(struct inode *inode, + goto out_update_clusters; + } + +- right_path = ocfs2_new_path(et->root_bh, et->root_el); ++ right_path = ocfs2_new_path(et->et_root_bh, et->et_root_el); + if (!right_path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -3971,7 +3974,7 @@ static int ocfs2_do_insert_extent(struct inode *inode, + * ocfs2_rotate_tree_right() might have extended the + * transaction without re-journaling our tree root. + */ +- ret = ocfs2_journal_access(handle, inode, et->root_bh, ++ ret = ocfs2_journal_access(handle, inode, et->et_root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -3999,7 +4002,7 @@ out_update_clusters: + ocfs2_et_update_clusters(inode, et, + le16_to_cpu(insert_rec->e_leaf_clusters)); + +- ret = ocfs2_journal_dirty(handle, et->root_bh); ++ ret = ocfs2_journal_dirty(handle, et->et_root_bh); + if (ret) + mlog_errno(ret); + +@@ -4157,7 +4160,8 @@ static void ocfs2_figure_contig_type(struct inode *inode, + * Caller might want us to limit the size of extents, don't + * calculate contiguousness if we might exceed that limit. + */ +- if (et->max_leaf_clusters && len > et->max_leaf_clusters) ++ if (et->et_max_leaf_clusters && ++ (len > et->et_max_leaf_clusters)) + insert->ins_contig = CONTIG_NONE; + } + } +@@ -4234,7 +4238,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, + + insert->ins_split = SPLIT_NONE; + +- el = et->root_el; ++ el = et->et_root_el; + insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth); + + if (el->l_tree_depth) { +@@ -4272,7 +4276,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, + return 0; + } + +- path = ocfs2_new_path(et->root_bh, et->root_el); ++ path = ocfs2_new_path(et->et_root_bh, et->et_root_el); + if (!path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -4413,7 +4417,7 @@ static int ocfs2_insert_extent(struct ocfs2_super *osb, + status = ocfs2_do_insert_extent(inode, handle, et, &rec, &insert); + if (status < 0) + mlog_errno(status); +- else if (et->type == OCFS2_DINODE_EXTENT) ++ else if (et->et_type == OCFS2_DINODE_EXTENT) + ocfs2_extent_map_insert_rec(inode, &rec); + + bail: +@@ -4687,7 +4691,7 @@ leftright: + */ + rec = path_leaf_el(path)->l_recs[split_index]; + +- rightmost_el = et->root_el; ++ rightmost_el = et->et_root_el; + + depth = le16_to_cpu(rightmost_el->l_tree_depth); + if (depth) { +@@ -4930,7 +4934,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, + if (et_type == OCFS2_DINODE_EXTENT) + ocfs2_extent_map_trunc(inode, 0); + +- left_path = ocfs2_new_path(et->root_bh, et->root_el); ++ left_path = ocfs2_new_path(et->et_root_bh, et->et_root_el); + if (!left_path) { + ret = -ENOMEM; + mlog_errno(ret); +@@ -5010,7 +5014,7 @@ static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et, + rightmost_el = path_leaf_el(path); + + credits += path->p_tree_depth + +- ocfs2_extend_meta_needed(et->root_el); ++ ocfs2_extend_meta_needed(et->et_root_el); + ret = ocfs2_extend_trans(handle, credits); + if (ret) { + mlog_errno(ret); +@@ -5223,7 +5227,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, + + ocfs2_extent_map_trunc(inode, 0); + +- path = ocfs2_new_path(et->root_bh, et->root_el); ++ path = ocfs2_new_path(et->et_root_bh, et->et_root_el); + if (!path) { + ret = -ENOMEM; + mlog_errno(ret); +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Provide-a-wrapper-to-brelse-xattr-bucket-bu.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Provide-a-wrapper-to-brelse-xattr-bucket-bu.patch new file mode 100644 index 000000000..77688ee7f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Provide-a-wrapper-to-brelse-xattr-bucket-bu.patch @@ -0,0 +1,117 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 17:16:48 -0700 +Subject: ocfs2: Provide a wrapper to brelse() xattr bucket buffers. +Patch-mainline: 2.6.29 + +A common theme is walking all the buffer heads on an ocfs2_xattr_bucket +and releasing them. Let's wrap that. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 33 ++++++++++++++++++--------------- + 1 files changed, 18 insertions(+), 15 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 1b77302..3478ad1 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -157,6 +157,17 @@ static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) + #define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data) + #define bucket_xh(_b) ((struct ocfs2_xattr_header *)bucket_block((_b), 0)) + ++static void ocfs2_xattr_bucket_relse(struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket) ++{ ++ int i, blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ for (i = 0; i < blks; i++) { ++ brelse(bucket->bu_bhs[i]); ++ bucket->bu_bhs[i] = NULL; ++ } ++} ++ + static inline const char *ocfs2_xattr_prefix(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -820,8 +831,7 @@ static int ocfs2_xattr_block_get(struct inode *inode, + } + ret = size; + cleanup: +- for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++) +- brelse(xs->bucket.bu_bhs[i]); ++ ocfs2_xattr_bucket_relse(inode, &xs->bucket); + memset(&xs->bucket, 0, sizeof(xs->bucket)); + + brelse(xs->xattr_bh); +@@ -1932,7 +1942,6 @@ int ocfs2_xattr_set(struct inode *inode, + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + int ret; +- u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + + struct ocfs2_xattr_info xi = { + .name_index = name_index, +@@ -2034,8 +2043,7 @@ cleanup: + ocfs2_inode_unlock(inode, 1); + brelse(di_bh); + brelse(xbs.xattr_bh); +- for (i = 0; i < blk_per_bucket; i++) +- brelse(xbs.bucket.bu_bhs[i]); ++ ocfs2_xattr_bucket_relse(inode, &xbs.bucket); + + return ret; + } +@@ -2358,7 +2366,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + xattr_bucket_func *func, + void *para) + { +- int i, j, ret = 0; ++ int i, ret = 0; + int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)); + u32 num_buckets = clusters * bpc; +@@ -2395,14 +2403,12 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + } + } + +- for (j = 0; j < blk_per_bucket; j++) +- brelse(bucket.bu_bhs[j]); ++ ocfs2_xattr_bucket_relse(inode, &bucket); + memset(&bucket, 0, sizeof(bucket)); + } + + out: +- for (j = 0; j < blk_per_bucket; j++) +- brelse(bucket.bu_bhs[j]); ++ ocfs2_xattr_bucket_relse(inode, &bucket); + + return ret; + } +@@ -4554,11 +4560,10 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, + struct ocfs2_xattr_header *xh; + struct ocfs2_xattr_entry *xe; + u16 count, header_size, xh_free_start; +- int i, free, max_free, need, old; ++ int free, max_free, need, old; + size_t value_size = 0, name_len = strlen(xi->name); + size_t blocksize = inode->i_sb->s_blocksize; + int ret, allocation = 0; +- u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + + mlog_entry("Set xattr %s in xattr index block\n", xi->name); + +@@ -4672,9 +4677,7 @@ try_again: + goto out; + } + +- for (i = 0; i < blk_per_bucket; i++) +- brelse(xs->bucket.bu_bhs[i]); +- ++ ocfs2_xattr_bucket_relse(inode, &xs->bucket); + memset(&xs->bucket, 0, sizeof(xs->bucket)); + + ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh, +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Provide-the-get_root_el-method-to-ocfs2_ext.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Provide-the-get_root_el-method-to-ocfs2_ext.patch new file mode 100644 index 000000000..bd84ba458 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Provide-the-get_root_el-method-to-ocfs2_ext.patch @@ -0,0 +1,113 @@ +From: Joel Becker +Subject: ocfs2: Provide the get_root_el() method to ocfs2_extent_tree_operations. +Patch-mainline: 2.6.28? +References: FATE302067 + +The root_el of an ocfs2_extent_tree needs to be calculated from +et->et_object. Make it an operation on et->et_ops. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 38 ++++++++++++++++++++++++++++++-------- + 1 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 93f44f4..fb6ae67 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -72,6 +72,10 @@ struct ocfs2_extent_tree_operations { + struct ocfs2_extent_tree *et, + u32 new_clusters); + int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et); ++ ++ /* These are internal to ocfs2_extent_tree and don't have ++ * accessor functions */ ++ void (*eo_fill_root_el)(struct ocfs2_extent_tree *et); + }; + + struct ocfs2_extent_tree { +@@ -83,6 +87,13 @@ struct ocfs2_extent_tree { + unsigned int et_max_leaf_clusters; + }; + ++static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_dinode *di = et->et_object; ++ ++ et->et_root_el = &di->id2.i_list; ++} ++ + static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +@@ -136,8 +147,16 @@ static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { + .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, + .eo_update_clusters = ocfs2_dinode_update_clusters, + .eo_sanity_check = ocfs2_dinode_sanity_check, ++ .eo_fill_root_el = ocfs2_dinode_fill_root_el, + }; + ++static void ocfs2_xattr_value_fill_root_el(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_xattr_value_root *xv = et->et_object; ++ ++ et->et_root_el = &xv->xr_list; ++} ++ + static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +@@ -176,8 +195,16 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { + .eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, + .eo_update_clusters = ocfs2_xattr_value_update_clusters, + .eo_sanity_check = ocfs2_xattr_value_sanity_check, ++ .eo_fill_root_el = ocfs2_xattr_value_fill_root_el, + }; + ++static void ocfs2_xattr_tree_fill_root_el(struct ocfs2_extent_tree *et) ++{ ++ struct ocfs2_xattr_block *xb = et->et_object; ++ ++ et->et_root_el = &xb->xb_attrs.xb_root.xt_list; ++} ++ + static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et, + u64 blkno) + { +@@ -215,6 +242,7 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .eo_get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, + .eo_update_clusters = ocfs2_xattr_tree_update_clusters, + .eo_sanity_check = ocfs2_xattr_tree_sanity_check, ++ .eo_fill_root_el = ocfs2_xattr_tree_fill_root_el, + }; + + static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, +@@ -232,22 +260,16 @@ static void ocfs2_get_extent_tree(struct ocfs2_extent_tree *et, + et->et_object = obj; + + if (et_type == OCFS2_DINODE_EXTENT) { +- et->et_root_el = +- &((struct ocfs2_dinode *)obj)->id2.i_list; + et->et_ops = &ocfs2_dinode_et_ops; + } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) { +- struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *)obj; +- et->et_root_el = &xv->xr_list; + et->et_ops = &ocfs2_xattr_et_ops; + } else if (et_type == OCFS2_XATTR_TREE_EXTENT) { +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)obj; +- et->et_root_el = &xb->xb_attrs.xb_root.xt_list; + et->et_ops = &ocfs2_xattr_tree_et_ops; + et->et_max_leaf_clusters = ocfs2_clusters_for_bytes(inode->i_sb, + OCFS2_MAX_XATTR_TREE_LEAF_SIZE); + } ++ ++ et->et_ops->eo_fill_root_el(et); + } + + static void ocfs2_put_extent_tree(struct ocfs2_extent_tree *et) +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Refactor-xattr-list-and-remove-ocfs2_xattr_ha.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Refactor-xattr-list-and-remove-ocfs2_xattr_ha.patch new file mode 100644 index 000000000..11f3e15f8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Refactor-xattr-list-and-remove-ocfs2_xattr_ha.patch @@ -0,0 +1,185 @@ +From: Tao Ma +Subject: ocfs2: Refactor xattr list and remove ocfs2_xattr_handler(). +Patch-mainline: 2.6.28 + +According to Christoph Hellwig's advice, we really don't need +a ->list to handle one xattr's list. Just a map from index to +xattr prefix is enough. And I also refactor the old list method +with the reference from fs/xfs/linux-2.6/xfs_xattr.c and the +xattr list method in btrfs. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 95 ++++++++++++++++++++++++++++++++++-------------------- + 1 files changed, 60 insertions(+), 35 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -153,14 +153,14 @@ static int ocfs2_xattr_set_entry_index_b + static int ocfs2_delete_xattr_index_block(struct inode *inode, + struct buffer_head *xb_bh); + +-static inline struct xattr_handler *ocfs2_xattr_handler(int name_index) ++static inline const char *ocfs2_xattr_prefix(int name_index) + { + struct xattr_handler *handler = NULL; + + if (name_index > 0 && name_index < OCFS2_XATTR_MAX) + handler = ocfs2_xattr_handler_map[name_index]; + +- return handler; ++ return handler ? handler->prefix : NULL; + } + + static u32 ocfs2_xattr_name_hash(struct inode *inode, +@@ -468,33 +468,56 @@ static int ocfs2_xattr_value_truncate(st + return ret; + } + ++static int ocfs2_xattr_list_entry(char *buffer, size_t size, ++ size_t *result, const char *prefix, ++ const char *name, int name_len) ++{ ++ char *p = buffer + *result; ++ int prefix_len = strlen(prefix); ++ int total_len = prefix_len + name_len + 1; ++ ++ *result += total_len; ++ ++ /* we are just looking for how big our buffer needs to be */ ++ if (!size) ++ return 0; ++ ++ if (*result > size) ++ return -ERANGE; ++ ++ memcpy(p, prefix, prefix_len); ++ memcpy(p + prefix_len, name, name_len); ++ p[prefix_len + name_len] = '\0'; ++ ++ return 0; ++} ++ + static int ocfs2_xattr_list_entries(struct inode *inode, + struct ocfs2_xattr_header *header, + char *buffer, size_t buffer_size) + { +- size_t rest = buffer_size; +- int i; ++ size_t result = 0; ++ int i, type, ret; ++ const char *prefix, *name; + + for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) { + struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; +- struct xattr_handler *handler = +- ocfs2_xattr_handler(ocfs2_xattr_get_type(entry)); ++ type = ocfs2_xattr_get_type(entry); ++ prefix = ocfs2_xattr_prefix(type); + +- if (handler) { +- size_t size = handler->list(inode, buffer, rest, +- ((char *)header + +- le16_to_cpu(entry->xe_name_offset)), +- entry->xe_name_len); +- if (buffer) { +- if (size > rest) +- return -ERANGE; +- buffer += size; +- } +- rest -= size; ++ if (prefix) { ++ name = (const char *)header + ++ le16_to_cpu(entry->xe_name_offset); ++ ++ ret = ocfs2_xattr_list_entry(buffer, buffer_size, ++ &result, prefix, name, ++ entry->xe_name_len); ++ if (ret) ++ return ret; + } + } + +- return buffer_size - rest; ++ return result; + } + + static int ocfs2_xattr_ibody_list(struct inode *inode, +@@ -2472,6 +2495,7 @@ out: + struct ocfs2_xattr_tree_list { + char *buffer; + size_t buffer_size; ++ size_t result; + }; + + static int ocfs2_xattr_bucket_get_name_value(struct inode *inode, +@@ -2497,17 +2521,17 @@ static int ocfs2_list_xattr_bucket(struc + struct ocfs2_xattr_bucket *bucket, + void *para) + { +- int ret = 0; ++ int ret = 0, type; + struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para; +- size_t size; + int i, block_off, new_offset; ++ const char *prefix, *name; + + for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) { + struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i]; +- struct xattr_handler *handler = +- ocfs2_xattr_handler(ocfs2_xattr_get_type(entry)); ++ type = ocfs2_xattr_get_type(entry); ++ prefix = ocfs2_xattr_prefix(type); + +- if (handler) { ++ if (prefix) { + ret = ocfs2_xattr_bucket_get_name_value(inode, + bucket->xh, + i, +@@ -2515,16 +2539,16 @@ static int ocfs2_list_xattr_bucket(struc + &new_offset); + if (ret) + break; +- size = handler->list(inode, xl->buffer, xl->buffer_size, +- bucket->bhs[block_off]->b_data + +- new_offset, +- entry->xe_name_len); +- if (xl->buffer) { +- if (size > xl->buffer_size) +- return -ERANGE; +- xl->buffer += size; +- } +- xl->buffer_size -= size; ++ ++ name = (const char *)bucket->bhs[block_off]->b_data + ++ new_offset; ++ ret = ocfs2_xattr_list_entry(xl->buffer, ++ xl->buffer_size, ++ &xl->result, ++ prefix, name, ++ entry->xe_name_len); ++ if (ret) ++ break; + } + } + +@@ -2543,6 +2567,7 @@ static int ocfs2_xattr_tree_list_index_b + struct ocfs2_xattr_tree_list xl = { + .buffer = buffer, + .buffer_size = buffer_size, ++ .result = 0, + }; + + if (le16_to_cpu(el->l_next_free_rec) == 0) +@@ -2570,7 +2595,7 @@ static int ocfs2_xattr_tree_list_index_b + name_hash = e_cpos - 1; + } + +- ret = buffer_size - xl.buffer_size; ++ ret = xl.result; + out: + return ret; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Remove-pointless.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Remove-pointless.patch new file mode 100644 index 000000000..4f32c3529 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Remove-pointless.patch @@ -0,0 +1,25 @@ +From: Mark Fasheh +Subject: ocfs2: Remove pointless !! +Patch-mainline: 2.6.28 + +ocfs2_stack_supports_plocks() doesn't need this to properly return a zero or +one value. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/stackglue.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/stackglue.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/stackglue.c ++++ linux-2.6.27/fs/ocfs2/stackglue.c +@@ -290,7 +290,7 @@ EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); + + int ocfs2_stack_supports_plocks(void) + { +- return !!(active_stack && active_stack->sp_ops->plock); ++ return active_stack && active_stack->sp_ops->plock; + } + EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks); + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Require-an-inode-for-ocfs2_read_block-s.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Require-an-inode-for-ocfs2_read_block-s.patch new file mode 100644 index 000000000..080dd3a0a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Require-an-inode-for-ocfs2_read_block-s.patch @@ -0,0 +1,824 @@ +From: Joel Becker +Subject: ocfs2: Require an inode for ocfs2_read_block(s)(). +Patch-mainline: 2.6.28 + +Now that synchronous readers are using ocfs2_read_blocks_sync(), all +callers of ocfs2_read_blocks() are passing an inode. Use it +unconditionally. Since it's there, we don't need to pass the +ocfs2_super either. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 30 ++++++++---------- + fs/ocfs2/aops.c | 10 ++---- + fs/ocfs2/buffer_head_io.c | 35 +++++++-------------- + fs/ocfs2/buffer_head_io.h | 18 ++++------- + fs/ocfs2/dir.c | 12 ++++---- + fs/ocfs2/dlmglue.c | 9 ++--- + fs/ocfs2/extent_map.c | 12 ++++---- + fs/ocfs2/file.c | 12 +++---- + fs/ocfs2/inode.c | 6 +-- + fs/ocfs2/journal.c | 2 +- + fs/ocfs2/localalloc.c | 8 ++-- + fs/ocfs2/namei.c | 5 +-- + fs/ocfs2/resize.c | 4 +- + fs/ocfs2/slot_map.c | 5 +-- + fs/ocfs2/suballoc.c | 17 +++++----- + fs/ocfs2/symlink.c | 5 +-- + fs/ocfs2/xattr.c | 74 +++++++++++++++++++++----------------------- + 17 files changed, 116 insertions(+), 148 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27/fs/ocfs2/alloc.c +@@ -705,8 +705,8 @@ int ocfs2_num_free_extents(struct ocfs2_ + last_eb_blk = ocfs2_et_get_last_eb_blk(et); + + if (last_eb_blk) { +- retval = ocfs2_read_block(osb, last_eb_blk, +- &eb_bh, OCFS2_BH_CACHED, inode); ++ retval = ocfs2_read_block(inode, last_eb_blk, ++ &eb_bh, OCFS2_BH_CACHED); + if (retval < 0) { + mlog_errno(retval); + goto bail; +@@ -1176,8 +1176,7 @@ static int ocfs2_find_branch_target(stru + brelse(bh); + bh = NULL; + +- status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED, +- inode); ++ status = ocfs2_read_block(inode, blkno, &bh, OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1550,8 +1549,7 @@ static int __ocfs2_find_path(struct inod + + brelse(bh); + bh = NULL; +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, +- &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, blkno, &bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4305,9 +4303,9 @@ static int ocfs2_figure_insert_type(stru + * ocfs2_figure_insert_type() and ocfs2_add_branch() + * may want it later. + */ +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + ocfs2_et_get_last_eb_blk(et), &bh, +- OCFS2_BH_CACHED, inode); ++ OCFS2_BH_CACHED); + if (ret) { + mlog_exit(ret); + goto out; +@@ -4773,9 +4771,9 @@ static int __ocfs2_mark_extent_written(s + if (path->p_tree_depth) { + struct ocfs2_extent_block *eb; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + ocfs2_et_get_last_eb_blk(et), +- &last_eb_bh, OCFS2_BH_CACHED, inode); ++ &last_eb_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_exit(ret); + goto out; +@@ -4932,9 +4930,9 @@ static int ocfs2_split_tree(struct inode + + depth = path->p_tree_depth; + if (depth > 0) { +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + ocfs2_et_get_last_eb_blk(et), +- &last_eb_bh, OCFS2_BH_CACHED, inode); ++ &last_eb_bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -5601,8 +5599,8 @@ static int ocfs2_get_truncate_log_info(s + goto bail; + } + +- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh, +- OCFS2_BH_CACHED, inode); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh, ++ OCFS2_BH_CACHED); + if (status < 0) { + iput(inode); + mlog_errno(status); +@@ -7000,8 +6998,8 @@ int ocfs2_prepare_truncate(struct ocfs2_ + ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc); + + if (fe->id2.i_list.l_tree_depth) { +- status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk), +- &last_eb_bh, OCFS2_BH_CACHED, inode); ++ status = ocfs2_read_block(inode, le64_to_cpu(fe->i_last_eb_blk), ++ &last_eb_bh, OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/aops.c ++++ linux-2.6.27/fs/ocfs2/aops.c +@@ -68,9 +68,8 @@ static int ocfs2_symlink_get_block(struc + goto bail; + } + +- status = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- OCFS2_I(inode)->ip_blkno, +- &bh, OCFS2_BH_CACHED, inode); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ++ &bh, OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -260,13 +259,12 @@ static int ocfs2_readpage_inline(struct + { + int ret; + struct buffer_head *di_bh = NULL; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + + BUG_ON(!PageLocked(page)); + BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)); + +- ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh, +- OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh, ++ OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.c ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.c +@@ -170,22 +170,20 @@ bail: + return status; + } + +-int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr, +- struct buffer_head *bhs[], int flags, +- struct inode *inode) ++int ocfs2_read_blocks(struct inode *inode, u64 block, int nr, ++ struct buffer_head *bhs[], int flags) + { + int status = 0; +- struct super_block *sb; + int i, ignore_cache = 0; + struct buffer_head *bh; + +- mlog_entry("(block=(%llu), nr=(%d), flags=%d, inode=%p)\n", +- (unsigned long long)block, nr, flags, inode); ++ mlog_entry("(inode=%p, block=(%llu), nr=(%d), flags=%d)\n", ++ inode, (unsigned long long)block, nr, flags); + +- BUG_ON((flags & OCFS2_BH_READAHEAD) && +- (!inode || !(flags & OCFS2_BH_CACHED))); ++ BUG_ON(!inode); ++ BUG_ON((flags & OCFS2_BH_READAHEAD) && !(flags & OCFS2_BH_CACHED)); + +- if (osb == NULL || osb->sb == NULL || bhs == NULL) { ++ if (bhs == NULL) { + status = -EINVAL; + mlog_errno(status); + goto bail; +@@ -204,19 +202,12 @@ int ocfs2_read_blocks(struct ocfs2_super + goto bail; + } + +- sb = osb->sb; +- +- if (flags & OCFS2_BH_CACHED && !inode) +- flags &= ~OCFS2_BH_CACHED; +- +- if (inode) +- mutex_lock(&OCFS2_I(inode)->ip_io_mutex); ++ mutex_lock(&OCFS2_I(inode)->ip_io_mutex); + for (i = 0 ; i < nr ; i++) { + if (bhs[i] == NULL) { +- bhs[i] = sb_getblk(sb, block++); ++ bhs[i] = sb_getblk(inode->i_sb, block++); + if (bhs[i] == NULL) { +- if (inode) +- mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); ++ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); + status = -EIO; + mlog_errno(status); + goto bail; +@@ -347,11 +338,9 @@ int ocfs2_read_blocks(struct ocfs2_super + /* Always set the buffer in the cache, even if it was + * a forced read, or read-ahead which hasn't yet + * completed. */ +- if (inode) +- ocfs2_set_buffer_uptodate(inode, bh); ++ ocfs2_set_buffer_uptodate(inode, bh); + } +- if (inode) +- mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); ++ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); + + mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n", + (unsigned long long)block, nr, +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.h ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.h +@@ -31,21 +31,19 @@ + void ocfs2_end_buffer_io_sync(struct buffer_head *bh, + int uptodate); + +-static inline int ocfs2_read_block(struct ocfs2_super *osb, ++static inline int ocfs2_read_block(struct inode *inode, + u64 off, + struct buffer_head **bh, +- int flags, +- struct inode *inode); ++ int flags); + + int ocfs2_write_block(struct ocfs2_super *osb, + struct buffer_head *bh, + struct inode *inode); +-int ocfs2_read_blocks(struct ocfs2_super *osb, ++int ocfs2_read_blocks(struct inode *inode, + u64 block, + int nr, + struct buffer_head *bhs[], +- int flags, +- struct inode *inode); ++ int flags); + int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, + unsigned int nr, struct buffer_head *bhs[]); + +@@ -55,9 +53,8 @@ int ocfs2_write_super_or_backup(struct o + #define OCFS2_BH_CACHED 1 + #define OCFS2_BH_READAHEAD 8 + +-static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off, +- struct buffer_head **bh, int flags, +- struct inode *inode) ++static inline int ocfs2_read_block(struct inode *inode, u64 off, ++ struct buffer_head **bh, int flags) + { + int status = 0; + +@@ -67,8 +64,7 @@ static inline int ocfs2_read_block(struc + goto bail; + } + +- status = ocfs2_read_blocks(osb, off, 1, bh, +- flags, inode); ++ status = ocfs2_read_blocks(inode, off, 1, bh, flags); + + bail: + return status; +Index: linux-2.6.27/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dir.c ++++ linux-2.6.27/fs/ocfs2/dir.c +@@ -188,8 +188,8 @@ static struct buffer_head *ocfs2_find_en + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + +- ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED, dir); ++ ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh, ++ OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -417,8 +417,8 @@ static inline int ocfs2_delete_entry_id( + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + +- ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED, dir); ++ ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, ++ &di_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -596,8 +596,8 @@ static int ocfs2_dir_foreach_blk_id(stru + struct ocfs2_inline_data *data; + struct ocfs2_dir_entry *de; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ++ &di_bh, OCFS2_BH_CACHED); + if (ret) { + mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno); +Index: linux-2.6.27/fs/ocfs2/dlmglue.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dlmglue.c ++++ linux-2.6.27/fs/ocfs2/dlmglue.c +@@ -2024,8 +2024,8 @@ static int ocfs2_inode_lock_update(struc + } else { + /* Boo, we have to go to disk. */ + /* read bh, cast, ocfs2_refresh_inode */ +- status = ocfs2_read_block(OCFS2_SB(inode->i_sb), oi->ip_blkno, +- bh, OCFS2_BH_CACHED, inode); ++ status = ocfs2_read_block(inode, oi->ip_blkno, ++ bh, OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail_refresh; +@@ -2086,11 +2086,10 @@ static int ocfs2_assign_bh(struct inode + return 0; + } + +- status = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ status = ocfs2_read_block(inode, + OCFS2_I(inode)->ip_blkno, + ret_bh, +- OCFS2_BH_CACHED, +- inode); ++ OCFS2_BH_CACHED); + if (status < 0) + mlog_errno(status); + +Index: linux-2.6.27/fs/ocfs2/extent_map.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/extent_map.c ++++ linux-2.6.27/fs/ocfs2/extent_map.c +@@ -335,9 +335,9 @@ static int ocfs2_figure_hole_clusters(st + if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) + goto no_more_extents; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + le64_to_cpu(eb->h_next_leaf_blk), +- &next_eb_bh, OCFS2_BH_CACHED, inode); ++ &next_eb_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -458,8 +458,8 @@ int ocfs2_get_clusters(struct inode *ino + if (ret == 0) + goto out; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ++ &di_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.27/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/file.c ++++ linux-2.6.27/fs/ocfs2/file.c +@@ -545,8 +545,8 @@ static int __ocfs2_extend_allocation(str + */ + BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb)); + +- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh, +- OCFS2_BH_CACHED, inode); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh, ++ OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -1132,8 +1132,7 @@ static int ocfs2_write_remove_suid(struc + struct buffer_head *bh = NULL; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, oi->ip_blkno, &bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1159,9 +1158,8 @@ static int ocfs2_allocate_unwritten_exte + struct buffer_head *di_bh = NULL; + + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- OCFS2_I(inode)->ip_blkno, &di_bh, +- OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ++ &di_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.27/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.c ++++ linux-2.6.27/fs/ocfs2/inode.c +@@ -461,8 +461,7 @@ static int ocfs2_read_locked_inode(struc + } + + if (can_lock) +- status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0, +- inode); ++ status = ocfs2_read_block(inode, args->fi_blkno, &bh, 0); + else + status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); + if (status < 0) { +@@ -1166,8 +1165,7 @@ struct buffer_head *ocfs2_bread(struct i + goto fail; + } + +- tmperr = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, &bh, +- readflags, inode); ++ tmperr = ocfs2_read_block(inode, p_blkno, &bh, readflags); + if (tmperr < 0) + goto fail; + +Index: linux-2.6.27/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/journal.c ++++ linux-2.6.27/fs/ocfs2/journal.c +@@ -1134,7 +1134,7 @@ static int ocfs2_read_journal_inode(stru + } + SET_INODE_JOURNAL(inode); + +- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, bh, 0, inode); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -248,8 +248,8 @@ int ocfs2_load_local_alloc(struct ocfs2_ + goto bail; + } + +- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, +- &alloc_bh, 0, inode); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ++ &alloc_bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -459,8 +459,8 @@ int ocfs2_begin_local_alloc_recovery(str + + mutex_lock(&inode->i_mutex); + +- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, +- &alloc_bh, 0, inode); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ++ &alloc_bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/namei.c ++++ linux-2.6.27/fs/ocfs2/namei.c +@@ -1752,10 +1752,9 @@ static int ocfs2_orphan_add(struct ocfs2 + + mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); + +- status = ocfs2_read_block(osb, ++ status = ocfs2_read_block(orphan_dir_inode, + OCFS2_I(orphan_dir_inode)->ip_blkno, +- &orphan_dir_bh, OCFS2_BH_CACHED, +- orphan_dir_inode); ++ &orphan_dir_bh, OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto leave; +Index: linux-2.6.27/fs/ocfs2/resize.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/resize.c ++++ linux-2.6.27/fs/ocfs2/resize.c +@@ -332,8 +332,8 @@ int ocfs2_group_extend(struct inode * in + lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, + first_new_cluster - 1); + +- ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED, +- main_bm_inode); ++ ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh, ++ OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + goto out_unlock; +Index: linux-2.6.27/fs/ocfs2/slot_map.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/slot_map.c ++++ linux-2.6.27/fs/ocfs2/slot_map.c +@@ -150,8 +150,7 @@ int ocfs2_refresh_slot_info(struct ocfs2 + * be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If + * this is not true, the read of -1 (UINT64_MAX) will fail. + */ +- ret = ocfs2_read_blocks(osb, -1, si->si_blocks, si->si_bh, 0, +- si->si_inode); ++ ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh, 0); + if (ret == 0) { + spin_lock(&osb->osb_lock); + ocfs2_update_slot_info(si); +@@ -404,7 +403,7 @@ static int ocfs2_map_slot_buffers(struct + (unsigned long long)blkno); + + bh = NULL; /* Acquire a fresh bh */ +- status = ocfs2_read_block(osb, blkno, &bh, 0, si->si_inode); ++ status = ocfs2_read_block(si->si_inode, blkno, &bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.27/fs/ocfs2/suballoc.c +@@ -1172,8 +1172,8 @@ static int ocfs2_search_one_group(struct + struct ocfs2_group_desc *gd; + struct inode *alloc_inode = ac->ac_inode; + +- ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno, +- &group_bh, OCFS2_BH_CACHED, alloc_inode); ++ ret = ocfs2_read_block(alloc_inode, gd_blkno, ++ &group_bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -1242,9 +1242,9 @@ static int ocfs2_search_chain(struct ocf + bits_wanted, chain, + (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno); + +- status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), ++ status = ocfs2_read_block(alloc_inode, + le64_to_cpu(cl->cl_recs[chain].c_blkno), +- &group_bh, OCFS2_BH_CACHED, alloc_inode); ++ &group_bh, OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1272,9 +1272,9 @@ static int ocfs2_search_chain(struct ocf + next_group = le64_to_cpu(bg->bg_next_group); + prev_group_bh = group_bh; + group_bh = NULL; +- status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), ++ status = ocfs2_read_block(alloc_inode, + next_group, &group_bh, +- OCFS2_BH_CACHED, alloc_inode); ++ OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1777,7 +1777,6 @@ int ocfs2_free_suballoc_bits(handle_t *h + { + int status = 0; + u32 tmp_used; +- struct ocfs2_super *osb = OCFS2_SB(alloc_inode->i_sb); + struct ocfs2_dinode *fe = (struct ocfs2_dinode *) alloc_bh->b_data; + struct ocfs2_chain_list *cl = &fe->id2.i_chain; + struct buffer_head *group_bh = NULL; +@@ -1796,8 +1795,8 @@ int ocfs2_free_suballoc_bits(handle_t *h + (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno, count, + (unsigned long long)bg_blkno, start_bit); + +- status = ocfs2_read_block(osb, bg_blkno, &group_bh, OCFS2_BH_CACHED, +- alloc_inode); ++ status = ocfs2_read_block(alloc_inode, bg_blkno, &group_bh, ++ OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/symlink.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/symlink.c ++++ linux-2.6.27/fs/ocfs2/symlink.c +@@ -84,11 +84,10 @@ static char *ocfs2_fast_symlink_getlink( + + mlog_entry_void(); + +- status = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ status = ocfs2_read_block(inode, + OCFS2_I(inode)->ip_blkno, + bh, +- OCFS2_BH_CACHED, +- inode); ++ OCFS2_BH_CACHED); + if (status < 0) { + mlog_errno(status); + link = ERR_PTR(status); +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -553,9 +553,9 @@ static int ocfs2_xattr_block_list(struct + if (!di->i_xattr_loc) + return ret; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED, inode); ++ &blk_bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -688,8 +688,8 @@ static int ocfs2_xattr_get_value_outside + blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); + /* Copy ocfs2_xattr_value */ + for (i = 0; i < num_clusters * bpc; i++, blkno++) { +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, +- &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, blkno, ++ &bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -780,9 +780,9 @@ static int ocfs2_xattr_block_get(struct + + memset(&xs->bucket, 0, sizeof(xs->bucket)); + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED, inode); ++ &blk_bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -938,8 +938,8 @@ static int __ocfs2_xattr_set_value_outsi + blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); + + for (i = 0; i < num_clusters * bpc; i++, blkno++) { +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, +- &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, blkno, ++ &bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1530,8 +1530,8 @@ static int ocfs2_xattr_free_block(struct + u64 blk, bg_blkno; + u16 bit; + +- ret = ocfs2_read_block(osb, block, &blk_bh, +- OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, block, &blk_bh, ++ OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1789,9 +1789,9 @@ static int ocfs2_xattr_block_find(struct + if (!di->i_xattr_loc) + return ret; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED, inode); ++ &blk_bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -2232,9 +2232,9 @@ static int ocfs2_find_xe_in_bucket(struc + break; + } + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_block(inode, + header_bh->b_blocknr + block_off, +- &name_bh, OCFS2_BH_CACHED, inode); ++ &name_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + break; +@@ -2285,8 +2285,7 @@ static int ocfs2_xattr_bucket_find(struc + u32 last_hash; + u64 blkno; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, +- &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, p_blkno, &bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2302,8 +2301,7 @@ static int ocfs2_xattr_bucket_find(struc + + blkno = p_blkno + bucket * blk_per_bucket; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, +- &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, blkno, &bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2375,10 +2373,9 @@ static int ocfs2_xattr_bucket_find(struc + * If we have found the xattr enty, read all the blocks in + * this bucket. + */ +- ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), +- xs->bucket.bhs[0]->b_blocknr + 1, ++ ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1, + blk_per_bucket - 1, &xs->bucket.bhs[1], +- OCFS2_BH_CACHED, inode); ++ OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2454,9 +2451,8 @@ static int ocfs2_iterate_xattr_buckets(s + clusters, blkno); + + for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { +- ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), +- blkno, blk_per_bucket, +- bucket.bhs, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, ++ bucket.bhs, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2721,10 +2717,10 @@ static int ocfs2_xattr_update_xattr_sear + + if (!xs->not_found) { + if (OCFS2_XATTR_BUCKET_SIZE != blocksize) { +- ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), ++ ret = ocfs2_read_blocks(inode, + xs->bucket.bhs[0]->b_blocknr + 1, + blk_per_bucket - 1, &xs->bucket.bhs[1], +- OCFS2_BH_CACHED, inode); ++ OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + return ret; +@@ -2929,8 +2925,8 @@ static int ocfs2_defrag_xattr_bucket(str + if (!bhs) + return -ENOMEM; + +- ret = ocfs2_read_blocks(osb, blkno, blk_per_bucket, bhs, +- OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, ++ OCFS2_BH_CACHED); + if (ret) + goto out; + +@@ -3130,8 +3126,8 @@ static int ocfs2_mv_xattr_bucket_cross_c + goto out; + } + +- ret = ocfs2_read_block(osb, prev_blkno, +- &old_bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, prev_blkno, ++ &old_bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + brelse(new_bh); +@@ -3184,9 +3180,9 @@ static int ocfs2_read_xattr_bucket(struc + u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + + if (!new) +- return ocfs2_read_blocks(OCFS2_SB(inode->i_sb), blkno, ++ return ocfs2_read_blocks(inode, blkno, + blk_per_bucket, bhs, +- OCFS2_BH_CACHED, inode); ++ OCFS2_BH_CACHED); + + for (i = 0; i < blk_per_bucket; i++) { + bhs[i] = sb_getblk(inode->i_sb, blkno + i); +@@ -3501,7 +3497,7 @@ static int ocfs2_cp_xattr_cluster(struct + ocfs2_journal_dirty(handle, first_bh); + + /* update the new bucket header. */ +- ret = ocfs2_read_block(osb, to_blk_start, &bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, to_blk_start, &bh, OCFS2_BH_CACHED); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -3888,8 +3884,8 @@ static int ocfs2_add_new_xattr_bucket(st + goto out; + } + +- ret = ocfs2_read_block(osb, p_blkno, +- &first_bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, p_blkno, ++ &first_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4131,10 +4127,10 @@ static int ocfs2_xattr_set_entry_in_buck + (unsigned long long)xs->bucket.bhs[0]->b_blocknr); + + if (!xs->bucket.bhs[1]) { +- ret = ocfs2_read_blocks(osb, ++ ret = ocfs2_read_blocks(inode, + xs->bucket.bhs[0]->b_blocknr + 1, + blk_per_bucket - 1, &xs->bucket.bhs[1], +- OCFS2_BH_CACHED, inode); ++ OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4240,8 +4236,8 @@ static int ocfs2_xattr_bucket_value_trun + BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize); + value_blk += header_bh->b_blocknr; + +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), value_blk, +- &value_bh, OCFS2_BH_CACHED, inode); ++ ret = ocfs2_read_block(inode, value_blk, ++ &value_bh, OCFS2_BH_CACHED); + if (ret) { + mlog_errno(ret); + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Resolve-deadlock-in-ocfs2_xattr_free_.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Resolve-deadlock-in-ocfs2_xattr_free_.patch new file mode 100644 index 000000000..65fdd0d35 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Resolve-deadlock-in-ocfs2_xattr_free_.patch @@ -0,0 +1,221 @@ +From: Tao Ma +Subject: [PATCH] ocfs2: Resolve deadlock in ocfs2_xattr_free_block. +Patch-mainline: 2.6.28? +References: FATE302067 + +In ocfs2_xattr_free_block, we take a cluster lock on xb_alloc_inode while we +have a transaction open. This will deadlock the downconvert thread, so fix +it. + +We can clean up how xattr blocks are removed while here - this patch also +moves the mechanism of releasing xattr block (including both value, xattr +tree and xattr block) into this function. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 152 +++++++++++++++++++++++++++++------------------------- + 1 files changed, 82 insertions(+), 70 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index ed50f9a..bbe87d0 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -1443,51 +1443,6 @@ out: + + } + +-static int ocfs2_xattr_free_block(handle_t *handle, +- struct ocfs2_super *osb, +- struct ocfs2_xattr_block *xb) +-{ +- struct inode *xb_alloc_inode; +- struct buffer_head *xb_alloc_bh = NULL; +- u64 blk = le64_to_cpu(xb->xb_blkno); +- u16 bit = le16_to_cpu(xb->xb_suballoc_bit); +- u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit); +- int ret = 0; +- +- xb_alloc_inode = ocfs2_get_system_file_inode(osb, +- EXTENT_ALLOC_SYSTEM_INODE, +- le16_to_cpu(xb->xb_suballoc_slot)); +- if (!xb_alloc_inode) { +- ret = -ENOMEM; +- mlog_errno(ret); +- goto out; +- } +- mutex_lock(&xb_alloc_inode->i_mutex); +- +- ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); +- if (ret < 0) { +- mlog_errno(ret); +- goto out_mutex; +- } +- ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE); +- if (ret < 0) { +- mlog_errno(ret); +- goto out_unlock; +- } +- ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, +- bit, bg_blkno, 1); +- if (ret < 0) +- mlog_errno(ret); +-out_unlock: +- ocfs2_inode_unlock(xb_alloc_inode, 1); +- brelse(xb_alloc_bh); +-out_mutex: +- mutex_unlock(&xb_alloc_inode->i_mutex); +- iput(xb_alloc_inode); +-out: +- return ret; +-} +- + static int ocfs2_remove_value_outside(struct inode*inode, + struct buffer_head *bh, + struct ocfs2_xattr_header *header) +@@ -1549,6 +1504,84 @@ static int ocfs2_xattr_block_remove(struct inode *inode, + return ret; + } + ++static int ocfs2_xattr_free_block(struct inode *inode, ++ u64 block) ++{ ++ struct inode *xb_alloc_inode; ++ struct buffer_head *xb_alloc_bh = NULL; ++ struct buffer_head *blk_bh = NULL; ++ struct ocfs2_xattr_block *xb; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ handle_t *handle; ++ int ret = 0; ++ u64 blk, bg_blkno; ++ u16 bit; ++ ++ ret = ocfs2_read_block(osb, block, &blk_bh, ++ OCFS2_BH_CACHED, inode); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ /*Verify the signature of xattr block*/ ++ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, ++ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = ocfs2_xattr_block_remove(inode, blk_bh); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xb = (struct ocfs2_xattr_block *)blk_bh->b_data; ++ blk = le64_to_cpu(xb->xb_blkno); ++ bit = le16_to_cpu(xb->xb_suballoc_bit); ++ bg_blkno = ocfs2_which_suballoc_group(blk, bit); ++ ++ xb_alloc_inode = ocfs2_get_system_file_inode(osb, ++ EXTENT_ALLOC_SYSTEM_INODE, ++ le16_to_cpu(xb->xb_suballoc_slot)); ++ if (!xb_alloc_inode) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ mutex_lock(&xb_alloc_inode->i_mutex); ++ ++ ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out_mutex; ++ } ++ ++ handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out_unlock; ++ } ++ ++ ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, ++ bit, bg_blkno, 1); ++ if (ret < 0) ++ mlog_errno(ret); ++ ++ ocfs2_commit_trans(osb, handle); ++out_unlock: ++ ocfs2_inode_unlock(xb_alloc_inode, 1); ++ brelse(xb_alloc_bh); ++out_mutex: ++ mutex_unlock(&xb_alloc_inode->i_mutex); ++ iput(xb_alloc_inode); ++out: ++ brelse(blk_bh); ++ return ret; ++} ++ + /* + * ocfs2_xattr_remove() + * +@@ -1556,9 +1589,6 @@ static int ocfs2_xattr_block_remove(struct inode *inode, + */ + int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) + { +- struct ocfs2_xattr_block *xb; +- struct buffer_head *blk_bh = NULL; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; + handle_t *handle; +@@ -1577,22 +1607,10 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) + goto out; + } + } +- if (di->i_xattr_loc) { +- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), +- le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED, inode); +- if (ret < 0) { +- mlog_errno(ret); +- return ret; +- } +- /*Verify the signature of xattr block*/ +- if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, +- strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { +- ret = -EFAULT; +- goto out; +- } + +- ret = ocfs2_xattr_block_remove(inode, blk_bh); ++ if (di->i_xattr_loc) { ++ ret = ocfs2_xattr_free_block(inode, ++ le64_to_cpu(di->i_xattr_loc)); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1613,11 +1631,7 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) + goto out_commit; + } + +- if (di->i_xattr_loc) { +- xb = (struct ocfs2_xattr_block *)blk_bh->b_data; +- ocfs2_xattr_free_block(handle, osb, xb); +- di->i_xattr_loc = cpu_to_le64(0); +- } ++ di->i_xattr_loc = 0; + + spin_lock(&oi->ip_lock); + oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL); +@@ -1630,8 +1644,6 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) + out_commit: + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: +- brelse(blk_bh); +- + return ret; + } + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Separate-out-sync-reads-from-ocfs2_read_block.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Separate-out-sync-reads-from-ocfs2_read_block.patch new file mode 100644 index 000000000..f1efb9555 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Separate-out-sync-reads-from-ocfs2_read_block.patch @@ -0,0 +1,202 @@ +From: Joel Becker +Subject: ocfs2: Separate out sync reads from ocfs2_read_blocks() +Patch-mainline: 2.6.28 + +The ocfs2_read_blocks() function currently handles sync reads, cached, +reads, and sometimes cached reads. We're going to add some +functionality to it, so first we should simplify it. The uncached, +synchronous reads are much easer to handle as a separate function, so we +instroduce ocfs2_read_blocks_sync(). + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/buffer_head_io.c | 84 ++++++++++++++++++++++++++++++++++++++++++++- + fs/ocfs2/buffer_head_io.h | 2 + + fs/ocfs2/inode.c | 7 +++- + fs/ocfs2/journal.c | 5 +-- + fs/ocfs2/resize.c | 8 ++-- + 5 files changed, 96 insertions(+), 10 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.c ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.c +@@ -66,7 +66,7 @@ int ocfs2_write_block(struct ocfs2_super + /* remove from dirty list before I/O. */ + clear_buffer_dirty(bh); + +- get_bh(bh); /* for end_buffer_write_sync() */ ++ get_bh(bh); /* for end_buffer_write_sync() */ + bh->b_end_io = end_buffer_write_sync; + submit_bh(WRITE, bh); + +@@ -88,6 +88,88 @@ out: + return ret; + } + ++int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, ++ unsigned int nr, struct buffer_head *bhs[]) ++{ ++ int status = 0; ++ unsigned int i; ++ struct buffer_head *bh; ++ ++ if (!nr) { ++ mlog(ML_BH_IO, "No buffers will be read!\n"); ++ goto bail; ++ } ++ ++ for (i = 0 ; i < nr ; i++) { ++ if (bhs[i] == NULL) { ++ bhs[i] = sb_getblk(osb->sb, block++); ++ if (bhs[i] == NULL) { ++ status = -EIO; ++ mlog_errno(status); ++ goto bail; ++ } ++ } ++ bh = bhs[i]; ++ ++ if (buffer_jbd(bh)) { ++ mlog(ML_ERROR, ++ "trying to sync read a jbd " ++ "managed bh (blocknr = %llu), skipping\n", ++ (unsigned long long)bh->b_blocknr); ++ continue; ++ } ++ ++ if (buffer_dirty(bh)) { ++ /* This should probably be a BUG, or ++ * at least return an error. */ ++ mlog(ML_ERROR, ++ "trying to sync read a dirty " ++ "buffer! (blocknr = %llu), skipping\n", ++ (unsigned long long)bh->b_blocknr); ++ continue; ++ } ++ ++ lock_buffer(bh); ++ if (buffer_jbd(bh)) { ++ mlog(ML_ERROR, ++ "block %llu had the JBD bit set " ++ "while I was in lock_buffer!", ++ (unsigned long long)bh->b_blocknr); ++ BUG(); ++ } ++ ++ clear_buffer_uptodate(bh); ++ get_bh(bh); /* for end_buffer_read_sync() */ ++ bh->b_end_io = end_buffer_read_sync; ++ submit_bh(READ, bh); ++ } ++ ++ for (i = nr; i > 0; i--) { ++ bh = bhs[i - 1]; ++ ++ if (buffer_jbd(bh)) { ++ mlog(ML_ERROR, ++ "the journal got the buffer while it was " ++ "locked for io! (blocknr = %llu)\n", ++ (unsigned long long)bh->b_blocknr); ++ BUG(); ++ } ++ ++ wait_on_buffer(bh); ++ if (!buffer_uptodate(bh)) { ++ /* Status won't be cleared from here on out, ++ * so we can safely record this and loop back ++ * to cleanup the other buffers. */ ++ status = -EIO; ++ put_bh(bh); ++ bhs[i - 1] = NULL; ++ } ++ } ++ ++bail: ++ return status; ++} ++ + int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr, + struct buffer_head *bhs[], int flags, + struct inode *inode) +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.h ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.h +@@ -46,6 +46,8 @@ int ocfs2_read_blocks(struct ocfs2_super + struct buffer_head *bhs[], + int flags, + struct inode *inode); ++int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, ++ unsigned int nr, struct buffer_head *bhs[]); + + int ocfs2_write_super_or_backup(struct ocfs2_super *osb, + struct buffer_head *bh); +Index: linux-2.6.27/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.c ++++ linux-2.6.27/fs/ocfs2/inode.c +@@ -460,8 +460,11 @@ static int ocfs2_read_locked_inode(struc + } + } + +- status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0, +- can_lock ? inode : NULL); ++ if (can_lock) ++ status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0, ++ inode); ++ else ++ status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/journal.c ++++ linux-2.6.27/fs/ocfs2/journal.c +@@ -850,9 +850,8 @@ static int ocfs2_force_read_journal(stru + + /* We are reading journal data which should not + * be put in the uptodate cache */ +- status = ocfs2_read_blocks(OCFS2_SB(inode->i_sb), +- p_blkno, p_blocks, bhs, 0, +- NULL); ++ status = ocfs2_read_blocks_sync(OCFS2_SB(inode->i_sb), ++ p_blkno, p_blocks, bhs); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/resize.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/resize.c ++++ linux-2.6.27/fs/ocfs2/resize.c +@@ -200,7 +200,7 @@ static int update_backups(struct inode * + if (cluster > clusters) + break; + +- ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL); ++ ret = ocfs2_read_blocks_sync(osb, blkno, 1, &backup); + if (ret < 0) { + mlog_errno(ret); + break; +@@ -236,8 +236,8 @@ static void ocfs2_update_super_and_backu + * update the superblock last. + * It doesn't matter if the write failed. + */ +- ret = ocfs2_read_block(osb, OCFS2_SUPER_BLOCK_BLKNO, +- &super_bh, 0, NULL); ++ ret = ocfs2_read_blocks_sync(osb, OCFS2_SUPER_BLOCK_BLKNO, 1, ++ &super_bh); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -540,7 +540,7 @@ int ocfs2_group_add(struct inode *inode, + goto out_unlock; + } + +- ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL); ++ ret = ocfs2_read_blocks_sync(osb, input->group, 1, &group_bh); + if (ret < 0) { + mlog(ML_ERROR, "Can't read the group descriptor # %llu " + "from the device.", (unsigned long long)input->group); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Simplify-ocfs2_read_block.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Simplify-ocfs2_read_block.patch new file mode 100644 index 000000000..146da98a0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Simplify-ocfs2_read_block.patch @@ -0,0 +1,590 @@ +From: Joel Becker +Subject: ocfs2: Simplify ocfs2_read_block() +Patch-mainline: 2.6.28 + +More than 30 callers of ocfs2_read_block() pass exactly OCFS2_BH_CACHED. +Only six pass a different flag set. Rather than have every caller care, +let's make ocfs2_read_block() take no flags and always do a cached read. +The remaining six places can call ocfs2_read_blocks() directly. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 25 ++++++++++--------------- + fs/ocfs2/aops.c | 6 ++---- + fs/ocfs2/buffer_head_io.h | 7 +++---- + fs/ocfs2/dir.c | 9 +++------ + fs/ocfs2/dlmglue.c | 8 ++------ + fs/ocfs2/extent_map.c | 8 +++----- + fs/ocfs2/file.c | 7 +++---- + fs/ocfs2/inode.c | 4 ++-- + fs/ocfs2/journal.c | 2 +- + fs/ocfs2/localalloc.c | 8 ++++---- + fs/ocfs2/namei.c | 2 +- + fs/ocfs2/resize.c | 3 +-- + fs/ocfs2/slot_map.c | 2 +- + fs/ocfs2/suballoc.c | 11 ++++------- + fs/ocfs2/symlink.c | 5 +---- + fs/ocfs2/xattr.c | 42 ++++++++++++++---------------------------- + 16 files changed, 55 insertions(+), 94 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27/fs/ocfs2/alloc.c +@@ -706,7 +706,7 @@ int ocfs2_num_free_extents(struct ocfs2_ + + if (last_eb_blk) { + retval = ocfs2_read_block(inode, last_eb_blk, +- &eb_bh, OCFS2_BH_CACHED); ++ &eb_bh); + if (retval < 0) { + mlog_errno(retval); + goto bail; +@@ -1176,7 +1176,7 @@ static int ocfs2_find_branch_target(stru + brelse(bh); + bh = NULL; + +- status = ocfs2_read_block(inode, blkno, &bh, OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, blkno, &bh); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1549,7 +1549,7 @@ static int __ocfs2_find_path(struct inod + + brelse(bh); + bh = NULL; +- ret = ocfs2_read_block(inode, blkno, &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, blkno, &bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4303,9 +4303,7 @@ static int ocfs2_figure_insert_type(stru + * ocfs2_figure_insert_type() and ocfs2_add_branch() + * may want it later. + */ +- ret = ocfs2_read_block(inode, +- ocfs2_et_get_last_eb_blk(et), &bh, +- OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), &bh); + if (ret) { + mlog_exit(ret); + goto out; +@@ -4771,9 +4769,8 @@ static int __ocfs2_mark_extent_written(s + if (path->p_tree_depth) { + struct ocfs2_extent_block *eb; + +- ret = ocfs2_read_block(inode, +- ocfs2_et_get_last_eb_blk(et), +- &last_eb_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), ++ &last_eb_bh); + if (ret) { + mlog_exit(ret); + goto out; +@@ -4930,9 +4927,8 @@ static int ocfs2_split_tree(struct inode + + depth = path->p_tree_depth; + if (depth > 0) { +- ret = ocfs2_read_block(inode, +- ocfs2_et_get_last_eb_blk(et), +- &last_eb_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), ++ &last_eb_bh); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -5599,8 +5595,7 @@ static int ocfs2_get_truncate_log_info(s + goto bail; + } + +- status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh, +- OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh); + if (status < 0) { + iput(inode); + mlog_errno(status); +@@ -6999,7 +6994,7 @@ int ocfs2_prepare_truncate(struct ocfs2_ + + if (fe->id2.i_list.l_tree_depth) { + status = ocfs2_read_block(inode, le64_to_cpu(fe->i_last_eb_blk), +- &last_eb_bh, OCFS2_BH_CACHED); ++ &last_eb_bh); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/aops.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/aops.c ++++ linux-2.6.27/fs/ocfs2/aops.c +@@ -68,8 +68,7 @@ static int ocfs2_symlink_get_block(struc + goto bail; + } + +- status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, +- &bh, OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -263,8 +262,7 @@ static int ocfs2_readpage_inline(struct + BUG_ON(!PageLocked(page)); + BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)); + +- ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh, +- OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.27/fs/ocfs2/buffer_head_io.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/buffer_head_io.h ++++ linux-2.6.27/fs/ocfs2/buffer_head_io.h +@@ -33,8 +33,7 @@ void ocfs2_end_buffer_io_sync(struct buf + + static inline int ocfs2_read_block(struct inode *inode, + u64 off, +- struct buffer_head **bh, +- int flags); ++ struct buffer_head **bh); + + int ocfs2_write_block(struct ocfs2_super *osb, + struct buffer_head *bh, +@@ -54,7 +53,7 @@ int ocfs2_write_super_or_backup(struct o + #define OCFS2_BH_READAHEAD 8 + + static inline int ocfs2_read_block(struct inode *inode, u64 off, +- struct buffer_head **bh, int flags) ++ struct buffer_head **bh) + { + int status = 0; + +@@ -64,7 +63,7 @@ static inline int ocfs2_read_block(struc + goto bail; + } + +- status = ocfs2_read_blocks(inode, off, 1, bh, flags); ++ status = ocfs2_read_blocks(inode, off, 1, bh, OCFS2_BH_CACHED); + + bail: + return status; +Index: linux-2.6.27/fs/ocfs2/dir.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dir.c ++++ linux-2.6.27/fs/ocfs2/dir.c +@@ -188,8 +188,7 @@ static struct buffer_head *ocfs2_find_en + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + +- ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh, +- OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -417,8 +416,7 @@ static inline int ocfs2_delete_entry_id( + struct ocfs2_dinode *di; + struct ocfs2_inline_data *data; + +- ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -596,8 +594,7 @@ static int ocfs2_dir_foreach_blk_id(stru + struct ocfs2_inline_data *data; + struct ocfs2_dir_entry *de; + +- ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh); + if (ret) { + mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno); +Index: linux-2.6.27/fs/ocfs2/dlmglue.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/dlmglue.c ++++ linux-2.6.27/fs/ocfs2/dlmglue.c +@@ -2024,8 +2024,7 @@ static int ocfs2_inode_lock_update(struc + } else { + /* Boo, we have to go to disk. */ + /* read bh, cast, ocfs2_refresh_inode */ +- status = ocfs2_read_block(inode, oi->ip_blkno, +- bh, OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, oi->ip_blkno, bh); + if (status < 0) { + mlog_errno(status); + goto bail_refresh; +@@ -2086,10 +2085,7 @@ static int ocfs2_assign_bh(struct inode + return 0; + } + +- status = ocfs2_read_block(inode, +- OCFS2_I(inode)->ip_blkno, +- ret_bh, +- OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ret_bh); + if (status < 0) + mlog_errno(status); + +Index: linux-2.6.27/fs/ocfs2/extent_map.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/extent_map.c ++++ linux-2.6.27/fs/ocfs2/extent_map.c +@@ -337,7 +337,7 @@ static int ocfs2_figure_hole_clusters(st + + ret = ocfs2_read_block(inode, + le64_to_cpu(eb->h_next_leaf_blk), +- &next_eb_bh, OCFS2_BH_CACHED); ++ &next_eb_bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -458,8 +458,7 @@ int ocfs2_get_clusters(struct inode *ino + if (ret == 0) + goto out; + +- ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.27/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/file.c ++++ linux-2.6.27/fs/ocfs2/file.c +@@ -545,8 +545,7 @@ static int __ocfs2_extend_allocation(str + */ + BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb)); + +- status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh, +- OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -1132,7 +1131,7 @@ static int ocfs2_write_remove_suid(struc + struct buffer_head *bh = NULL; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + +- ret = ocfs2_read_block(inode, oi->ip_blkno, &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, oi->ip_blkno, &bh); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1159,7 +1158,7 @@ static int ocfs2_allocate_unwritten_exte + + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { + ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, +- &di_bh, OCFS2_BH_CACHED); ++ &di_bh); + if (ret) { + mlog_errno(ret); + goto out; +Index: linux-2.6.27/fs/ocfs2/inode.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/inode.c ++++ linux-2.6.27/fs/ocfs2/inode.c +@@ -461,7 +461,7 @@ static int ocfs2_read_locked_inode(struc + } + + if (can_lock) +- status = ocfs2_read_block(inode, args->fi_blkno, &bh, 0); ++ status = ocfs2_read_blocks(inode, args->fi_blkno, 1, &bh, 0); + else + status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); + if (status < 0) { +@@ -1165,7 +1165,7 @@ struct buffer_head *ocfs2_bread(struct i + goto fail; + } + +- tmperr = ocfs2_read_block(inode, p_blkno, &bh, readflags); ++ tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags); + if (tmperr < 0) + goto fail; + +Index: linux-2.6.27/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/journal.c ++++ linux-2.6.27/fs/ocfs2/journal.c +@@ -1134,7 +1134,7 @@ static int ocfs2_read_journal_inode(stru + } + SET_INODE_JOURNAL(inode); + +- status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, bh, 0); ++ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -248,8 +248,8 @@ int ocfs2_load_local_alloc(struct ocfs2_ + goto bail; + } + +- status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, +- &alloc_bh, 0); ++ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, ++ &alloc_bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -459,8 +459,8 @@ int ocfs2_begin_local_alloc_recovery(str + + mutex_lock(&inode->i_mutex); + +- status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, +- &alloc_bh, 0); ++ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, ++ &alloc_bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/namei.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/namei.c ++++ linux-2.6.27/fs/ocfs2/namei.c +@@ -1754,7 +1754,7 @@ static int ocfs2_orphan_add(struct ocfs2 + + status = ocfs2_read_block(orphan_dir_inode, + OCFS2_I(orphan_dir_inode)->ip_blkno, +- &orphan_dir_bh, OCFS2_BH_CACHED); ++ &orphan_dir_bh); + if (status < 0) { + mlog_errno(status); + goto leave; +Index: linux-2.6.27/fs/ocfs2/resize.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/resize.c ++++ linux-2.6.27/fs/ocfs2/resize.c +@@ -332,8 +332,7 @@ int ocfs2_group_extend(struct inode * in + lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, + first_new_cluster - 1); + +- ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh, +- OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh); + if (ret < 0) { + mlog_errno(ret); + goto out_unlock; +Index: linux-2.6.27/fs/ocfs2/slot_map.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/slot_map.c ++++ linux-2.6.27/fs/ocfs2/slot_map.c +@@ -403,7 +403,7 @@ static int ocfs2_map_slot_buffers(struct + (unsigned long long)blkno); + + bh = NULL; /* Acquire a fresh bh */ +- status = ocfs2_read_block(si->si_inode, blkno, &bh, 0); ++ status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh, 0); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.27/fs/ocfs2/suballoc.c +@@ -1172,8 +1172,7 @@ static int ocfs2_search_one_group(struct + struct ocfs2_group_desc *gd; + struct inode *alloc_inode = ac->ac_inode; + +- ret = ocfs2_read_block(alloc_inode, gd_blkno, +- &group_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(alloc_inode, gd_blkno, &group_bh); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -1244,7 +1243,7 @@ static int ocfs2_search_chain(struct ocf + + status = ocfs2_read_block(alloc_inode, + le64_to_cpu(cl->cl_recs[chain].c_blkno), +- &group_bh, OCFS2_BH_CACHED); ++ &group_bh); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1273,8 +1272,7 @@ static int ocfs2_search_chain(struct ocf + prev_group_bh = group_bh; + group_bh = NULL; + status = ocfs2_read_block(alloc_inode, +- next_group, &group_bh, +- OCFS2_BH_CACHED); ++ next_group, &group_bh); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1795,8 +1793,7 @@ int ocfs2_free_suballoc_bits(handle_t *h + (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno, count, + (unsigned long long)bg_blkno, start_bit); + +- status = ocfs2_read_block(alloc_inode, bg_blkno, &group_bh, +- OCFS2_BH_CACHED); ++ status = ocfs2_read_block(alloc_inode, bg_blkno, &group_bh); + if (status < 0) { + mlog_errno(status); + goto bail; +Index: linux-2.6.27/fs/ocfs2/symlink.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/symlink.c ++++ linux-2.6.27/fs/ocfs2/symlink.c +@@ -84,10 +84,7 @@ static char *ocfs2_fast_symlink_getlink( + + mlog_entry_void(); + +- status = ocfs2_read_block(inode, +- OCFS2_I(inode)->ip_blkno, +- bh, +- OCFS2_BH_CACHED); ++ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, bh); + if (status < 0) { + mlog_errno(status); + link = ERR_PTR(status); +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -553,9 +553,7 @@ static int ocfs2_xattr_block_list(struct + if (!di->i_xattr_loc) + return ret; + +- ret = ocfs2_read_block(inode, +- le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -688,8 +686,7 @@ static int ocfs2_xattr_get_value_outside + blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); + /* Copy ocfs2_xattr_value */ + for (i = 0; i < num_clusters * bpc; i++, blkno++) { +- ret = ocfs2_read_block(inode, blkno, +- &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, blkno, &bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -780,9 +777,7 @@ static int ocfs2_xattr_block_get(struct + + memset(&xs->bucket, 0, sizeof(xs->bucket)); + +- ret = ocfs2_read_block(inode, +- le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -938,8 +933,7 @@ static int __ocfs2_xattr_set_value_outsi + blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); + + for (i = 0; i < num_clusters * bpc; i++, blkno++) { +- ret = ocfs2_read_block(inode, blkno, +- &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, blkno, &bh); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -1530,8 +1524,7 @@ static int ocfs2_xattr_free_block(struct + u64 blk, bg_blkno; + u16 bit; + +- ret = ocfs2_read_block(inode, block, &blk_bh, +- OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, block, &blk_bh); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1789,9 +1782,7 @@ static int ocfs2_xattr_block_find(struct + if (!di->i_xattr_loc) + return ret; + +- ret = ocfs2_read_block(inode, +- le64_to_cpu(di->i_xattr_loc), +- &blk_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -2232,9 +2223,8 @@ static int ocfs2_find_xe_in_bucket(struc + break; + } + +- ret = ocfs2_read_block(inode, +- header_bh->b_blocknr + block_off, +- &name_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off, ++ &name_bh); + if (ret) { + mlog_errno(ret); + break; +@@ -2285,7 +2275,7 @@ static int ocfs2_xattr_bucket_find(struc + u32 last_hash; + u64 blkno; + +- ret = ocfs2_read_block(inode, p_blkno, &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, p_blkno, &bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2301,7 +2291,7 @@ static int ocfs2_xattr_bucket_find(struc + + blkno = p_blkno + bucket * blk_per_bucket; + +- ret = ocfs2_read_block(inode, blkno, &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, blkno, &bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2914,7 +2904,6 @@ static int ocfs2_defrag_xattr_bucket(str + u64 blkno = bucket->bhs[0]->b_blocknr; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u16 xh_free_start; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + size_t blocksize = inode->i_sb->s_blocksize; + handle_t *handle; + struct buffer_head **bhs; +@@ -3126,8 +3115,7 @@ static int ocfs2_mv_xattr_bucket_cross_c + goto out; + } + +- ret = ocfs2_read_block(inode, prev_blkno, +- &old_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, prev_blkno, &old_bh); + if (ret < 0) { + mlog_errno(ret); + brelse(new_bh); +@@ -3497,7 +3485,7 @@ static int ocfs2_cp_xattr_cluster(struct + ocfs2_journal_dirty(handle, first_bh); + + /* update the new bucket header. */ +- ret = ocfs2_read_block(inode, to_blk_start, &bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, to_blk_start, &bh); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -3884,8 +3872,7 @@ static int ocfs2_add_new_xattr_bucket(st + goto out; + } + +- ret = ocfs2_read_block(inode, p_blkno, +- &first_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, p_blkno, &first_bh); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4236,8 +4223,7 @@ static int ocfs2_xattr_bucket_value_trun + BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize); + value_blk += header_bh->b_blocknr; + +- ret = ocfs2_read_block(inode, value_blk, +- &value_bh, OCFS2_BH_CACHED); ++ ret = ocfs2_read_block(inode, value_blk, &value_bh); + if (ret) { + mlog_errno(ret); + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Support-nested-transactions.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Support-nested-transactions.patch new file mode 100644 index 000000000..2c031504a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Support-nested-transactions.patch @@ -0,0 +1,53 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 19/28] ocfs2: Support nested transactions +Patch-mainline: 2.6.29? + +OCFS2 can easily support nested transactions. We just have to +take care and not spoil statistics acquire semaphore unnecessarily. + +Signed-off-by: Jan Kara +--- + fs/ocfs2/journal.c | 14 +++++++------- + 1 files changed, 7 insertions(+), 7 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/journal.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/journal.c 2008-10-24 11:40:35.000000000 +0200 ++++ linux-2.6.27/fs/ocfs2/journal.c 2008-10-24 14:19:31.000000000 +0200 +@@ -256,11 +256,9 @@ + BUG_ON(osb->journal->j_state == OCFS2_JOURNAL_FREE); + BUG_ON(max_buffs <= 0); + +- /* JBD might support this, but our journalling code doesn't yet. */ +- if (journal_current_handle()) { +- mlog(ML_ERROR, "Recursive transaction attempted!\n"); +- BUG(); +- } ++ /* Nested transaction? Just return the handle... */ ++ if (journal_current_handle()) ++ return jbd2_journal_start(journal, max_buffs); + + down_read(&osb->journal->j_trans_barrier); + +@@ -285,16 +283,18 @@ + int ocfs2_commit_trans(struct ocfs2_super *osb, + handle_t *handle) + { +- int ret; ++ int ret, nested; + struct ocfs2_journal *journal = osb->journal; + + BUG_ON(!handle); + ++ nested = handle->h_ref > 1; + ret = jbd2_journal_stop(handle); + if (ret < 0) + mlog_errno(ret); + +- up_read(&journal->j_trans_barrier); ++ if (!nested) ++ up_read(&journal->j_trans_barrier); + + return ret; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Switch-over-to-JBD2.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Switch-over-to-JBD2.patch new file mode 100644 index 000000000..6be2985c4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Switch-over-to-JBD2.patch @@ -0,0 +1,761 @@ +From: Joel Becker +Subject: ocfs2: Switch over to JBD2. +Patch-mainline: 2.6.28? +References: FATE302877 + +ocfs2 wants JBD2 for many reasons, not the least of which is that JBD is +limiting our maximum filesystem size. + +It's a pretty trivial change. Most functions are just renamed. The +only functional change is moving to Jan's inode-based ordered data mode. +It's better, too. + +Because JBD2 reads and writes JBD journals, this is compatible with any +existing filesystem. It can even interact with JBD-based ocfs2 as long +as the journal is formated for JBD. + +We provide a compatibility option so that paranoid people can still use +JBD for the time being. This will go away shortly. + +[ Moved call of ocfs2_begin_ordered_truncate() from ocfs2_delete_inode() to + ocfs2_truncate_for_delete(). --Mark ] + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/Kconfig | 40 +++++++++++++-------- + fs/ocfs2/alloc.c | 28 +++++---------- + fs/ocfs2/aops.c | 21 ++++++++--- + fs/ocfs2/file.c | 14 +++++-- + fs/ocfs2/inode.c | 5 ++ + fs/ocfs2/inode.h | 1 + fs/ocfs2/journal.c | 72 ++++++++++++++++++++------------------ + fs/ocfs2/journal.h | 25 +++++++++++-- + fs/ocfs2/ocfs2.h | 7 +++ + fs/ocfs2/ocfs2_jbd_compat.h | 82 ++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/super.c | 10 +++-- + fs/ocfs2/uptodate.c | 6 ++- + 12 files changed, 227 insertions(+), 84 deletions(-) + create mode 100644 fs/ocfs2/ocfs2_jbd_compat.h + +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -206,17 +206,16 @@ config JBD + tristate + help + This is a generic journalling layer for block devices. It is +- currently used by the ext3 and OCFS2 file systems, but it could +- also be used to add journal support to other file systems or block ++ currently used by the ext3 file system, but it could also be ++ used to add journal support to other file systems or block + devices such as RAID or LVM. + +- If you are using the ext3 or OCFS2 file systems, you need to +- say Y here. If you are not using ext3 OCFS2 then you will probably +- want to say N. ++ If you are using the ext3 file system, you need to say Y here. ++ If you are not using ext3 then you will probably want to say N. + + To compile this device as a module, choose M here: the module will be +- called jbd. If you are compiling ext3 or OCFS2 into the kernel, +- you cannot compile this code as a module. ++ called jbd. If you are compiling ext3 into the kernel, you ++ cannot compile this code as a module. + + config JBD_DEBUG + bool "JBD (ext3) debugging support" +@@ -240,16 +239,17 @@ config JBD2 + help + This is a generic journaling layer for block devices that support + both 32-bit and 64-bit block numbers. It is currently used by +- the ext4dev/ext4 filesystem, but it could also be used to add +- journal support to other file systems or block devices such +- as RAID or LVM. ++ the ext4dev/ext4 and OCFS2 filesystems, but it could also be ++ used to add journal support to other file systems or block ++ devices such as RAID or LVM. + +- If you are using ext4dev/ext4, you need to say Y here. If you are not +- using ext4dev/ext4 then you will probably want to say N. ++ If you are using ext4dev/ext4 or OCFS2, you need to say Y here. ++ If you are not using ext4dev/ext4 or OCFS2 then you will ++ probably want to say N. + + To compile this device as a module, choose M here. The module will be +- called jbd2. If you are compiling ext4dev/ext4 into the kernel, +- you cannot compile this code as a module. ++ called jbd2. If you are compiling ext4dev/ext4 or OCFS2 into the ++ kernel, you cannot compile this code as a module. + + config JBD2_DEBUG + bool "JBD2 (ext4dev/ext4) debugging support" +@@ -426,7 +426,7 @@ config OCFS2_FS + tristate "OCFS2 file system support" + depends on NET && SYSFS + select CONFIGFS_FS +- select JBD ++ select JBD2 + select CRC32 + help + OCFS2 is a general purpose extent based shared disk cluster file +@@ -497,6 +497,16 @@ config OCFS2_DEBUG_FS + this option for debugging only as it is likely to decrease + performance of the filesystem. + ++config OCFS2_COMPAT_JBD ++ bool "Use JBD for compatibility" ++ depends on OCFS2_FS ++ default n ++ select JBD ++ help ++ The ocfs2 filesystem now uses JBD2 for its journalling. JBD2 ++ is backwards compatible with JBD. It is safe to say N here. ++ However, if you really want to use the original JBD, say Y here. ++ + endif # BLOCK + + config DNOTIFY +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -6430,20 +6430,13 @@ bail: + return status; + } + +-static int ocfs2_writeback_zero_func(handle_t *handle, struct buffer_head *bh) ++static int ocfs2_zero_func(handle_t *handle, struct buffer_head *bh) + { + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + return 0; + } + +-static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh) +-{ +- set_buffer_uptodate(bh); +- mark_buffer_dirty(bh); +- return ocfs2_journal_dirty_data(handle, bh); +-} +- + static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle, + unsigned int from, unsigned int to, + struct page *page, int zero, u64 *phys) +@@ -6462,17 +6455,18 @@ static void ocfs2_map_and_dirty_page(str + * here if they aren't - ocfs2_map_page_blocks() + * might've skipped some + */ +- if (ocfs2_should_order_data(inode)) { +- ret = walk_page_buffers(handle, +- page_buffers(page), +- from, to, &partial, +- ocfs2_ordered_zero_func); +- if (ret < 0) +- mlog_errno(ret); +- } else { ++ ret = walk_page_buffers(handle, page_buffers(page), ++ from, to, &partial, ++ ocfs2_zero_func); ++ if (ret < 0) ++ mlog_errno(ret); ++ else if (ocfs2_should_order_data(inode)) { ++ ret = ocfs2_jbd2_file_inode(handle, inode); ++#ifdef CONFIG_OCFS2_COMPAT_JBD + ret = walk_page_buffers(handle, page_buffers(page), + from, to, &partial, +- ocfs2_writeback_zero_func); ++ ocfs2_journal_dirty_data); ++#endif + if (ret < 0) + mlog_errno(ret); + } +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -485,11 +485,14 @@ handle_t *ocfs2_start_walk_page_trans(st + } + + if (ocfs2_should_order_data(inode)) { ++ ret = ocfs2_jbd2_file_inode(handle, inode); ++#ifdef CONFIG_OCFS2_COMPAT_JBD + ret = walk_page_buffers(handle, + page_buffers(page), + from, to, NULL, + ocfs2_journal_dirty_data); +- if (ret < 0) ++#endif ++ if (ret < 0) + mlog_errno(ret); + } + out: +@@ -669,7 +672,7 @@ static void ocfs2_invalidatepage(struct + { + journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal; + +- journal_invalidatepage(journal, page, offset); ++ jbd2_journal_invalidatepage(journal, page, offset); + } + + static int ocfs2_releasepage(struct page *page, gfp_t wait) +@@ -678,7 +681,7 @@ static int ocfs2_releasepage(struct page + + if (!page_has_buffers(page)) + return 0; +- return journal_try_to_free_buffers(journal, page, wait); ++ return jbd2_journal_try_to_free_buffers(journal, page, wait); + } + + static ssize_t ocfs2_direct_IO(int rw, +@@ -1074,11 +1077,15 @@ static void ocfs2_write_failure(struct i + tmppage = wc->w_pages[i]; + + if (page_has_buffers(tmppage)) { +- if (ocfs2_should_order_data(inode)) ++ if (ocfs2_should_order_data(inode)) { ++ ocfs2_jbd2_file_inode(wc->w_handle, inode); ++#ifdef CONFIG_OCFS2_COMPAT_JBD + walk_page_buffers(wc->w_handle, + page_buffers(tmppage), + from, to, NULL, + ocfs2_journal_dirty_data); ++#endif ++ } + + block_commit_write(tmppage, from, to); + } +@@ -1917,11 +1924,15 @@ int ocfs2_write_end_nolock(struct addres + } + + if (page_has_buffers(tmppage)) { +- if (ocfs2_should_order_data(inode)) ++ if (ocfs2_should_order_data(inode)) { ++ ocfs2_jbd2_file_inode(wc->w_handle, inode); ++#ifdef CONFIG_OCFS2_COMPAT_JBD + walk_page_buffers(wc->w_handle, + page_buffers(tmppage), + from, to, NULL, + ocfs2_journal_dirty_data); ++#endif ++ } + block_commit_write(tmppage, from, to); + } + } +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -185,7 +185,7 @@ static int ocfs2_sync_file(struct file * + goto bail; + + journal = osb->journal->j_journal; +- err = journal_force_commit(journal); ++ err = jbd2_journal_force_commit(journal); + + bail: + mlog_exit(err); +@@ -941,9 +941,15 @@ int ocfs2_setattr(struct dentry *dentry, + goto bail_unlock; + } + +- if (i_size_read(inode) > attr->ia_size) ++ if (i_size_read(inode) > attr->ia_size) { ++ if (ocfs2_should_order_data(inode)) { ++ status = ocfs2_begin_ordered_truncate(inode, ++ attr->ia_size); ++ if (status) ++ goto bail_unlock; ++ } + status = ocfs2_truncate_file(inode, bh, attr->ia_size); +- else ++ } else + status = ocfs2_extend_file(inode, bh, attr->ia_size); + if (status < 0) { + if (status != -ENOSPC) +@@ -1888,7 +1894,7 @@ out_dio: + */ + if (old_size != i_size_read(inode) || + old_clusters != OCFS2_I(inode)->ip_clusters) { +- ret = journal_force_commit(osb->journal->j_journal); ++ ret = jbd2_journal_force_commit(osb->journal->j_journal); + if (ret < 0) + written = ret; + } +--- a/fs/ocfs2/inode.c ++++ b/fs/ocfs2/inode.c +@@ -523,6 +523,9 @@ static int ocfs2_truncate_for_delete(str + * data and fast symlinks. + */ + if (fe->i_clusters) { ++ if (ocfs2_should_order_data(inode)) ++ ocfs2_begin_ordered_truncate(inode, 0); ++ + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); +@@ -1089,6 +1092,8 @@ void ocfs2_clear_inode(struct inode *ino + oi->ip_last_trans = 0; + oi->ip_dir_start_lookup = 0; + oi->ip_blkno = 0ULL; ++ jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal, ++ &oi->ip_jinode); + + bail: + mlog_exit_void(); +--- a/fs/ocfs2/inode.h ++++ b/fs/ocfs2/inode.h +@@ -71,6 +71,7 @@ struct ocfs2_inode_info + struct ocfs2_extent_map ip_extent_map; + + struct inode vfs_inode; ++ struct jbd2_inode ip_jinode; + }; + + /* +--- a/fs/ocfs2/journal.c ++++ b/fs/ocfs2/journal.c +@@ -215,9 +215,9 @@ static int ocfs2_commit_cache(struct ocf + goto finally; + } + +- journal_lock_updates(journal->j_journal); +- status = journal_flush(journal->j_journal); +- journal_unlock_updates(journal->j_journal); ++ jbd2_journal_lock_updates(journal->j_journal); ++ status = jbd2_journal_flush(journal->j_journal); ++ jbd2_journal_unlock_updates(journal->j_journal); + if (status < 0) { + up_write(&journal->j_trans_barrier); + mlog_errno(status); +@@ -264,7 +264,7 @@ handle_t *ocfs2_start_trans(struct ocfs2 + + down_read(&osb->journal->j_trans_barrier); + +- handle = journal_start(journal, max_buffs); ++ handle = jbd2_journal_start(journal, max_buffs); + if (IS_ERR(handle)) { + up_read(&osb->journal->j_trans_barrier); + +@@ -290,7 +290,7 @@ int ocfs2_commit_trans(struct ocfs2_supe + + BUG_ON(!handle); + +- ret = journal_stop(handle); ++ ret = jbd2_journal_stop(handle); + if (ret < 0) + mlog_errno(ret); + +@@ -304,7 +304,7 @@ int ocfs2_commit_trans(struct ocfs2_supe + * transaction. extend_trans will either extend the current handle by + * nblocks, or commit it and start a new one with nblocks credits. + * +- * This might call journal_restart() which will commit dirty buffers ++ * This might call jbd2_journal_restart() which will commit dirty buffers + * and then restart the transaction. Before calling + * ocfs2_extend_trans(), any changed blocks should have been + * dirtied. After calling it, all blocks which need to be changed must +@@ -332,7 +332,7 @@ int ocfs2_extend_trans(handle_t *handle, + #ifdef CONFIG_OCFS2_DEBUG_FS + status = 1; + #else +- status = journal_extend(handle, nblocks); ++ status = jbd2_journal_extend(handle, nblocks); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -340,8 +340,10 @@ int ocfs2_extend_trans(handle_t *handle, + #endif + + if (status > 0) { +- mlog(0, "journal_extend failed, trying journal_restart\n"); +- status = journal_restart(handle, nblocks); ++ mlog(0, ++ "jbd2_journal_extend failed, trying " ++ "jbd2_journal_restart\n"); ++ status = jbd2_journal_restart(handle, nblocks); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -393,11 +395,11 @@ int ocfs2_journal_access(handle_t *handl + switch (type) { + case OCFS2_JOURNAL_ACCESS_CREATE: + case OCFS2_JOURNAL_ACCESS_WRITE: +- status = journal_get_write_access(handle, bh); ++ status = jbd2_journal_get_write_access(handle, bh); + break; + + case OCFS2_JOURNAL_ACCESS_UNDO: +- status = journal_get_undo_access(handle, bh); ++ status = jbd2_journal_get_undo_access(handle, bh); + break; + + default: +@@ -422,7 +424,7 @@ int ocfs2_journal_dirty(handle_t *handle + mlog_entry("(bh->b_blocknr=%llu)\n", + (unsigned long long)bh->b_blocknr); + +- status = journal_dirty_metadata(handle, bh); ++ status = jbd2_journal_dirty_metadata(handle, bh); + if (status < 0) + mlog(ML_ERROR, "Could not dirty metadata buffer. " + "(bh->b_blocknr=%llu)\n", +@@ -432,6 +434,7 @@ int ocfs2_journal_dirty(handle_t *handle + return status; + } + ++#ifdef CONFIG_OCFS2_COMPAT_JBD + int ocfs2_journal_dirty_data(handle_t *handle, + struct buffer_head *bh) + { +@@ -443,8 +446,9 @@ int ocfs2_journal_dirty_data(handle_t *h + + return err; + } ++#endif + +-#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * JBD_DEFAULT_MAX_COMMIT_AGE) ++#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE) + + void ocfs2_set_journal_params(struct ocfs2_super *osb) + { +@@ -457,9 +461,9 @@ void ocfs2_set_journal_params(struct ocf + spin_lock(&journal->j_state_lock); + journal->j_commit_interval = commit_interval; + if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER) +- journal->j_flags |= JFS_BARRIER; ++ journal->j_flags |= JBD2_BARRIER; + else +- journal->j_flags &= ~JFS_BARRIER; ++ journal->j_flags &= ~JBD2_BARRIER; + spin_unlock(&journal->j_state_lock); + } + +@@ -524,14 +528,14 @@ int ocfs2_journal_init(struct ocfs2_jour + mlog(0, "inode->ip_clusters = %u\n", OCFS2_I(inode)->ip_clusters); + + /* call the kernels journal init function now */ +- j_journal = journal_init_inode(inode); ++ j_journal = jbd2_journal_init_inode(inode); + if (j_journal == NULL) { + mlog(ML_ERROR, "Linux journal layer error\n"); + status = -EINVAL; + goto done; + } + +- mlog(0, "Returned from journal_init_inode\n"); ++ mlog(0, "Returned from jbd2_journal_init_inode\n"); + mlog(0, "j_journal->j_maxlen = %u\n", j_journal->j_maxlen); + + *dirty = (le32_to_cpu(di->id1.journal1.ij_flags) & +@@ -639,7 +643,7 @@ void ocfs2_journal_shutdown(struct ocfs2 + if (journal->j_state != OCFS2_JOURNAL_LOADED) + goto done; + +- /* need to inc inode use count as journal_destroy will iput. */ ++ /* need to inc inode use count - jbd2_journal_destroy will iput. */ + if (!igrab(inode)) + BUG(); + +@@ -668,9 +672,9 @@ void ocfs2_journal_shutdown(struct ocfs2 + BUG_ON(atomic_read(&(osb->journal->j_num_trans)) != 0); + + if (ocfs2_mount_local(osb)) { +- journal_lock_updates(journal->j_journal); +- status = journal_flush(journal->j_journal); +- journal_unlock_updates(journal->j_journal); ++ jbd2_journal_lock_updates(journal->j_journal); ++ status = jbd2_journal_flush(journal->j_journal); ++ jbd2_journal_unlock_updates(journal->j_journal); + if (status < 0) + mlog_errno(status); + } +@@ -686,7 +690,7 @@ void ocfs2_journal_shutdown(struct ocfs2 + } + + /* Shutdown the kernel journal system */ +- journal_destroy(journal->j_journal); ++ jbd2_journal_destroy(journal->j_journal); + + OCFS2_I(inode)->ip_open_count--; + +@@ -711,15 +715,15 @@ static void ocfs2_clear_journal_error(st + { + int olderr; + +- olderr = journal_errno(journal); ++ olderr = jbd2_journal_errno(journal); + if (olderr) { + mlog(ML_ERROR, "File system error %d recorded in " + "journal %u.\n", olderr, slot); + mlog(ML_ERROR, "File system on device %s needs checking.\n", + sb->s_id); + +- journal_ack_err(journal); +- journal_clear_err(journal); ++ jbd2_journal_ack_err(journal); ++ jbd2_journal_clear_err(journal); + } + } + +@@ -734,7 +738,7 @@ int ocfs2_journal_load(struct ocfs2_jour + + osb = journal->j_osb; + +- status = journal_load(journal->j_journal); ++ status = jbd2_journal_load(journal->j_journal); + if (status < 0) { + mlog(ML_ERROR, "Failed to load journal!\n"); + goto done; +@@ -778,7 +782,7 @@ int ocfs2_journal_wipe(struct ocfs2_jour + + BUG_ON(!journal); + +- status = journal_wipe(journal->j_journal, full); ++ status = jbd2_journal_wipe(journal->j_journal, full); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1229,19 +1233,19 @@ static int ocfs2_replay_journal(struct o + } + + mlog(0, "calling journal_init_inode\n"); +- journal = journal_init_inode(inode); ++ journal = jbd2_journal_init_inode(inode); + if (journal == NULL) { + mlog(ML_ERROR, "Linux journal layer error\n"); + status = -EIO; + goto done; + } + +- status = journal_load(journal); ++ status = jbd2_journal_load(journal); + if (status < 0) { + mlog_errno(status); + if (!igrab(inode)) + BUG(); +- journal_destroy(journal); ++ jbd2_journal_destroy(journal); + goto done; + } + +@@ -1249,9 +1253,9 @@ static int ocfs2_replay_journal(struct o + + /* wipe the journal */ + mlog(0, "flushing the journal.\n"); +- journal_lock_updates(journal); +- status = journal_flush(journal); +- journal_unlock_updates(journal); ++ jbd2_journal_lock_updates(journal); ++ status = jbd2_journal_flush(journal); ++ jbd2_journal_unlock_updates(journal); + if (status < 0) + mlog_errno(status); + +@@ -1272,7 +1276,7 @@ static int ocfs2_replay_journal(struct o + if (!igrab(inode)) + BUG(); + +- journal_destroy(journal); ++ jbd2_journal_destroy(journal); + + done: + /* drop the lock on this nodes journal */ +--- a/fs/ocfs2/journal.h ++++ b/fs/ocfs2/journal.h +@@ -27,7 +27,12 @@ + #define OCFS2_JOURNAL_H + + #include +-#include ++#ifndef CONFIG_OCFS2_COMPAT_JBD ++# include ++#else ++# include ++# include "ocfs2_jbd_compat.h" ++#endif + + enum ocfs2_journal_state { + OCFS2_JOURNAL_FREE = 0, +@@ -215,8 +220,8 @@ static inline void ocfs2_checkpoint_inod + * buffer. Will have to call ocfs2_journal_dirty once + * we've actually dirtied it. Type is one of . or . + * ocfs2_journal_dirty - Mark a journalled buffer as having dirty data. +- * ocfs2_journal_dirty_data - Indicate that a data buffer should go out before +- * the current handle commits. ++ * ocfs2_jbd2_file_inode - Mark an inode so that its data goes out before ++ * the current handle commits. + */ + + /* You must always start_trans with a number of buffs > 0, but it's +@@ -268,8 +273,10 @@ int ocfs2_journal_acces + */ + int ocfs2_journal_dirty(handle_t *handle, + struct buffer_head *bh); ++#ifdef CONFIG_OCFS2_COMPAT_JBD + int ocfs2_journal_dirty_data(handle_t *handle, + struct buffer_head *bh); ++#endif + + /* + * Credit Macros: +@@ -430,4 +437,16 @@ static inline int ocfs2_calc_tree_trunc_ + return credits; + } + ++static inline int ocfs2_jbd2_file_inode(handle_t *handle, struct inode *inode) ++{ ++ return jbd2_journal_file_inode(handle, &OCFS2_I(inode)->ip_jinode); ++} ++ ++static inline int ocfs2_begin_ordered_truncate(struct inode *inode, ++ loff_t new_size) ++{ ++ return jbd2_journal_begin_ordered_truncate(&OCFS2_I(inode)->ip_jinode, ++ new_size); ++} ++ + #endif /* OCFS2_JOURNAL_H */ +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -34,7 +34,12 @@ + #include + #include + #include +-#include ++#ifndef CONFIG_OCFS2_COMPAT_JBD ++# include ++#else ++# include ++# include "ocfs2_jbd_compat.h" ++#endif + + /* For union ocfs2_dlm_lksb */ + #include "stackglue.h" +--- /dev/null ++++ b/fs/ocfs2/ocfs2_jbd_compat.h +@@ -0,0 +1,82 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * ocfs2_jbd_compat.h ++ * ++ * Compatibility defines for JBD. ++ * ++ * Copyright (C) 2008 Oracle. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public ++ * License version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#ifndef OCFS2_JBD_COMPAT_H ++#define OCFS2_JBD_COMPAT_H ++ ++#ifndef CONFIG_OCFS2_COMPAT_JBD ++# error Should not have been included ++#endif ++ ++struct jbd2_inode { ++ unsigned int dummy; ++}; ++ ++#define JBD2_BARRIER JFS_BARRIER ++#define JBD2_DEFAULT_MAX_COMMIT_AGE JBD_DEFAULT_MAX_COMMIT_AGE ++ ++#define jbd2_journal_ack_err journal_ack_err ++#define jbd2_journal_clear_err journal_clear_err ++#define jbd2_journal_destroy journal_destroy ++#define jbd2_journal_dirty_metadata journal_dirty_metadata ++#define jbd2_journal_errno journal_errno ++#define jbd2_journal_extend journal_extend ++#define jbd2_journal_flush journal_flush ++#define jbd2_journal_force_commit journal_force_commit ++#define jbd2_journal_get_write_access journal_get_write_access ++#define jbd2_journal_get_undo_access journal_get_undo_access ++#define jbd2_journal_init_inode journal_init_inode ++#define jbd2_journal_invalidatepage journal_invalidatepage ++#define jbd2_journal_load journal_load ++#define jbd2_journal_lock_updates journal_lock_updates ++#define jbd2_journal_restart journal_restart ++#define jbd2_journal_start journal_start ++#define jbd2_journal_start_commit journal_start_commit ++#define jbd2_journal_stop journal_stop ++#define jbd2_journal_try_to_free_buffers journal_try_to_free_buffers ++#define jbd2_journal_unlock_updates journal_unlock_updates ++#define jbd2_journal_wipe journal_wipe ++#define jbd2_log_wait_commit log_wait_commit ++ ++static inline int jbd2_journal_file_inode(handle_t *handle, ++ struct jbd2_inode *inode) ++{ ++ return 0; ++} ++ ++static inline int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode, ++ loff_t new_size) ++{ ++ return 0; ++} ++ ++static inline void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, ++ struct inode *inode) ++{ ++ return; ++} ++ ++static inline void jbd2_journal_release_jbd_inode(journal_t *journal, ++ struct jbd2_inode *jinode) ++{ ++ return; ++} ++ ++ ++#endif /* OCFS2_JBD_COMPAT_H */ +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -212,10 +212,11 @@ static int ocfs2_sync_fs(struct super_bl + ocfs2_schedule_truncate_log_flush(osb, 0); + } + +- if (journal_start_commit(OCFS2_SB(sb)->journal->j_journal, &target)) { ++ if (jbd2_journal_start_commit(OCFS2_SB(sb)->journal->j_journal, ++ &target)) { + if (wait) +- log_wait_commit(OCFS2_SB(sb)->journal->j_journal, +- target); ++ jbd2_log_wait_commit(OCFS2_SB(sb)->journal->j_journal, ++ target); + } + return 0; + } +@@ -332,6 +333,7 @@ static struct inode *ocfs2_alloc_inode(s + if (!oi) + return NULL; + ++ jbd2_journal_init_jbd_inode(&oi->ip_jinode, &oi->vfs_inode); + return &oi->vfs_inode; + } + +@@ -895,7 +897,7 @@ static int ocfs2_parse_options(struct su + if (option < 0) + return 0; + if (option == 0) +- option = JBD_DEFAULT_MAX_COMMIT_AGE; ++ option = JBD2_DEFAULT_MAX_COMMIT_AGE; + mopt->commit_interval = HZ * option; + break; + case Opt_localalloc: +--- a/fs/ocfs2/uptodate.c ++++ b/fs/ocfs2/uptodate.c +@@ -53,7 +53,11 @@ + #include + #include + #include +-#include ++#ifndef CONFIG_OCFS2_COMPAT_JBD ++# include ++#else ++# include ++#endif + + #define MLOG_MASK_PREFIX ML_UPTODATE + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Take-ocfs2_xattr_bucket-structures-off-of-the.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Take-ocfs2_xattr_bucket-structures-off-of-the.patch new file mode 100644 index 000000000..c00c7d47c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Take-ocfs2_xattr_bucket-structures-off-of-the.patch @@ -0,0 +1,722 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 19:13:20 -0700 +Subject: ocfs2: Take ocfs2_xattr_bucket structures off of the stack. +Patch-mainline: 2.6.29 + +The ocfs2_xattr_bucket structure is a nice abstraction, but it is a bit +large to have on the stack. Just like ocfs2_path, let's allocate it +with a ocfs2_xattr_bucket_new() function. + +We can now store the inode on the bucket, cleaning up all the other +bucket functions. While we're here, we catch another place or two that +wasn't using ocfs2_read_xattr_bucket(). + +Updates: +- No longer allocating xis.bucket, as it will never be used. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 281 ++++++++++++++++++++++++++++++++---------------------- + 1 files changed, 166 insertions(+), 115 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 71d9e7b..766494e 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -61,7 +61,14 @@ struct ocfs2_xattr_def_value_root { + }; + + struct ocfs2_xattr_bucket { ++ /* The inode these xattrs are associated with */ ++ struct inode *bu_inode; ++ ++ /* The actual buffers that make up the bucket */ + struct buffer_head *bu_bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET]; ++ ++ /* How many blocks make up one bucket for this filesystem */ ++ int bu_blocks; + }; + + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) +@@ -97,7 +104,7 @@ struct ocfs2_xattr_search { + */ + struct buffer_head *xattr_bh; + struct ocfs2_xattr_header *header; +- struct ocfs2_xattr_bucket bucket; ++ struct ocfs2_xattr_bucket *bucket; + void *base; + void *end; + struct ocfs2_xattr_entry *here; +@@ -157,69 +164,91 @@ static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) + #define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data) + #define bucket_xh(_b) ((struct ocfs2_xattr_header *)bucket_block((_b), 0)) + +-static void ocfs2_xattr_bucket_relse(struct inode *inode, +- struct ocfs2_xattr_bucket *bucket) ++static struct ocfs2_xattr_bucket *ocfs2_xattr_bucket_new(struct inode *inode) + { +- int i, blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ struct ocfs2_xattr_bucket *bucket; ++ int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + +- for (i = 0; i < blks; i++) { ++ BUG_ON(blks > OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET); ++ ++ bucket = kzalloc(sizeof(struct ocfs2_xattr_bucket), GFP_NOFS); ++ if (bucket) { ++ bucket->bu_inode = inode; ++ bucket->bu_blocks = blks; ++ } ++ ++ return bucket; ++} ++ ++static void ocfs2_xattr_bucket_relse(struct ocfs2_xattr_bucket *bucket) ++{ ++ int i; ++ ++ for (i = 0; i < bucket->bu_blocks; i++) { + brelse(bucket->bu_bhs[i]); + bucket->bu_bhs[i] = NULL; + } + } + ++static void ocfs2_xattr_bucket_free(struct ocfs2_xattr_bucket *bucket) ++{ ++ if (bucket) { ++ ocfs2_xattr_bucket_relse(bucket); ++ bucket->bu_inode = NULL; ++ kfree(bucket); ++ } ++} ++ + /* + * A bucket that has never been written to disk doesn't need to be + * read. We just need the buffer_heads. Don't call this for + * buckets that are already on disk. ocfs2_read_xattr_bucket() initializes + * them fully. + */ +-static int ocfs2_init_xattr_bucket(struct inode *inode, +- struct ocfs2_xattr_bucket *bucket, ++static int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket, + u64 xb_blkno) + { + int i, rc = 0; +- int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + +- for (i = 0; i < blks; i++) { +- bucket->bu_bhs[i] = sb_getblk(inode->i_sb, xb_blkno + i); ++ for (i = 0; i < bucket->bu_blocks; i++) { ++ bucket->bu_bhs[i] = sb_getblk(bucket->bu_inode->i_sb, ++ xb_blkno + i); + if (!bucket->bu_bhs[i]) { + rc = -EIO; + mlog_errno(rc); + break; + } + +- ocfs2_set_new_buffer_uptodate(inode, bucket->bu_bhs[i]); ++ ocfs2_set_new_buffer_uptodate(bucket->bu_inode, ++ bucket->bu_bhs[i]); + } + + if (rc) +- ocfs2_xattr_bucket_relse(inode, bucket); ++ ocfs2_xattr_bucket_relse(bucket); + return rc; + } + + /* Read the xattr bucket at xb_blkno */ +-static int ocfs2_read_xattr_bucket(struct inode *inode, +- struct ocfs2_xattr_bucket *bucket, ++static int ocfs2_read_xattr_bucket(struct ocfs2_xattr_bucket *bucket, + u64 xb_blkno) + { +- int rc, blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int rc; + +- rc = ocfs2_read_blocks(inode, xb_blkno, blks, bucket->bu_bhs, 0); ++ rc = ocfs2_read_blocks(bucket->bu_inode, xb_blkno, ++ bucket->bu_blocks, bucket->bu_bhs, 0); + if (rc) +- ocfs2_xattr_bucket_relse(inode, bucket); ++ ocfs2_xattr_bucket_relse(bucket); + return rc; + } + + static int ocfs2_xattr_bucket_journal_access(handle_t *handle, +- struct inode *inode, + struct ocfs2_xattr_bucket *bucket, + int type) + { + int i, rc = 0; +- int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + +- for (i = 0; i < blks; i++) { +- rc = ocfs2_journal_access(handle, inode, ++ for (i = 0; i < bucket->bu_blocks; i++) { ++ rc = ocfs2_journal_access(handle, bucket->bu_inode, + bucket->bu_bhs[i], type); + if (rc) { + mlog_errno(rc); +@@ -231,24 +260,24 @@ static int ocfs2_xattr_bucket_journal_access(handle_t *handle, + } + + static void ocfs2_xattr_bucket_journal_dirty(handle_t *handle, +- struct inode *inode, + struct ocfs2_xattr_bucket *bucket) + { +- int i, blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int i; + +- for (i = 0; i < blks; i++) ++ for (i = 0; i < bucket->bu_blocks; i++) + ocfs2_journal_dirty(handle, bucket->bu_bhs[i]); + } + +-static void ocfs2_xattr_bucket_copy_data(struct inode *inode, +- struct ocfs2_xattr_bucket *dest, ++static void ocfs2_xattr_bucket_copy_data(struct ocfs2_xattr_bucket *dest, + struct ocfs2_xattr_bucket *src) + { + int i; +- int blocksize = inode->i_sb->s_blocksize; +- int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int blocksize = src->bu_inode->i_sb->s_blocksize; ++ ++ BUG_ON(dest->bu_blocks != src->bu_blocks); ++ BUG_ON(dest->bu_inode != src->bu_inode); + +- for (i = 0; i < blks; i++) { ++ for (i = 0; i < src->bu_blocks; i++) { + memcpy(bucket_block(dest, i), bucket_block(src, i), + blocksize); + } +@@ -869,7 +898,12 @@ static int ocfs2_xattr_block_get(struct inode *inode, + size_t size; + int ret = -ENODATA, name_offset, name_len, block_off, i; + +- memset(&xs->bucket, 0, sizeof(xs->bucket)); ++ xs->bucket = ocfs2_xattr_bucket_new(inode); ++ if (!xs->bucket) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto cleanup; ++ } + + ret = ocfs2_xattr_block_find(inode, name_index, name, xs); + if (ret) { +@@ -895,11 +929,11 @@ static int ocfs2_xattr_block_get(struct inode *inode, + + if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { + ret = ocfs2_xattr_bucket_get_name_value(inode, +- bucket_xh(&xs->bucket), ++ bucket_xh(xs->bucket), + i, + &block_off, + &name_offset); +- xs->base = bucket_block(&xs->bucket, block_off); ++ xs->base = bucket_block(xs->bucket, block_off); + } + if (ocfs2_xattr_is_local(xs->here)) { + memcpy(buffer, (void *)xs->base + +@@ -917,8 +951,7 @@ static int ocfs2_xattr_block_get(struct inode *inode, + } + ret = size; + cleanup: +- ocfs2_xattr_bucket_relse(inode, &xs->bucket); +- memset(&xs->bucket, 0, sizeof(xs->bucket)); ++ ocfs2_xattr_bucket_free(xs->bucket); + + brelse(xs->xattr_bh); + xs->xattr_bh = NULL; +@@ -2047,10 +2080,20 @@ int ocfs2_xattr_set(struct inode *inode, + if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb))) + return -EOPNOTSUPP; + ++ /* ++ * Only xbs will be used on indexed trees. xis doesn't need a ++ * bucket. ++ */ ++ xbs.bucket = ocfs2_xattr_bucket_new(inode); ++ if (!xbs.bucket) { ++ mlog_errno(-ENOMEM); ++ return -ENOMEM; ++ } ++ + ret = ocfs2_inode_lock(inode, &di_bh, 1); + if (ret < 0) { + mlog_errno(ret); +- return ret; ++ goto cleanup_nolock; + } + xis.inode_bh = xbs.inode_bh = di_bh; + di = (struct ocfs2_dinode *)di_bh->b_data; +@@ -2127,9 +2170,10 @@ int ocfs2_xattr_set(struct inode *inode, + cleanup: + up_write(&OCFS2_I(inode)->ip_xattr_sem); + ocfs2_inode_unlock(inode, 1); ++cleanup_nolock: + brelse(di_bh); + brelse(xbs.xattr_bh); +- ocfs2_xattr_bucket_relse(inode, &xbs.bucket); ++ ocfs2_xattr_bucket_free(xbs.bucket); + + return ret; + } +@@ -2373,11 +2417,11 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + lower_bh = bh; + bh = NULL; + } +- xs->bucket.bu_bhs[0] = lower_bh; ++ xs->bucket->bu_bhs[0] = lower_bh; + lower_bh = NULL; + +- xs->header = bucket_xh(&xs->bucket); +- xs->base = bucket_block(&xs->bucket, 0); ++ xs->header = bucket_xh(xs->bucket); ++ xs->base = bucket_block(xs->bucket, 0); + xs->end = xs->base + inode->i_sb->s_blocksize; + + if (found) { +@@ -2385,8 +2429,8 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + * If we have found the xattr enty, read all the blocks in + * this bucket. + */ +- ret = ocfs2_read_blocks(inode, bucket_blkno(&xs->bucket) + 1, +- blk_per_bucket - 1, &xs->bucket.bu_bhs[1], ++ ret = ocfs2_read_blocks(inode, bucket_blkno(xs->bucket) + 1, ++ blk_per_bucket - 1, &xs->bucket->bu_bhs[1], + 0); + if (ret) { + mlog_errno(ret); +@@ -2395,7 +2439,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + + xs->here = &xs->header->xh_entries[index]; + mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name, +- (unsigned long long)bucket_blkno(&xs->bucket), index); ++ (unsigned long long)bucket_blkno(xs->bucket), index); + } else + ret = -ENODATA; + +@@ -2453,22 +2497,24 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + void *para) + { + int i, ret = 0; +- int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)); + u32 num_buckets = clusters * bpc; +- struct ocfs2_xattr_bucket bucket; ++ struct ocfs2_xattr_bucket *bucket; + +- memset(&bucket, 0, sizeof(bucket)); ++ bucket = ocfs2_xattr_bucket_new(inode); ++ if (!bucket) { ++ mlog_errno(-ENOMEM); ++ return -ENOMEM; ++ } + + mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n", + clusters, (unsigned long long)blkno); + +- for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { +- ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, +- bucket.bu_bhs, 0); ++ for (i = 0; i < num_buckets; i++, blkno += bucket->bu_blocks) { ++ ret = ocfs2_read_xattr_bucket(bucket, blkno); + if (ret) { + mlog_errno(ret); +- goto out; ++ break; + } + + /* +@@ -2476,26 +2522,24 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, + * in the 1st bucket. + */ + if (i == 0) +- num_buckets = le16_to_cpu(bucket_xh(&bucket)->xh_num_buckets); ++ num_buckets = le16_to_cpu(bucket_xh(bucket)->xh_num_buckets); + + mlog(0, "iterating xattr bucket %llu, first hash %u\n", + (unsigned long long)blkno, +- le32_to_cpu(bucket_xh(&bucket)->xh_entries[0].xe_name_hash)); ++ le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash)); + if (func) { +- ret = func(inode, &bucket, para); +- if (ret) { ++ ret = func(inode, bucket, para); ++ if (ret) + mlog_errno(ret); +- break; +- } ++ /* Fall through to bucket_relse() */ + } + +- ocfs2_xattr_bucket_relse(inode, &bucket); +- memset(&bucket, 0, sizeof(bucket)); ++ ocfs2_xattr_bucket_relse(bucket); ++ if (ret) ++ break; + } + +-out: +- ocfs2_xattr_bucket_relse(inode, &bucket); +- ++ ocfs2_xattr_bucket_free(bucket); + return ret; + } + +@@ -2718,9 +2762,9 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + int i, blocksize = inode->i_sb->s_blocksize; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + +- xs->bucket.bu_bhs[0] = new_bh; ++ xs->bucket->bu_bhs[0] = new_bh; + get_bh(new_bh); +- xs->header = bucket_xh(&xs->bucket); ++ xs->header = bucket_xh(xs->bucket); + + xs->base = new_bh->b_data; + xs->end = xs->base + inode->i_sb->s_blocksize; +@@ -2728,8 +2772,8 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode, + if (!xs->not_found) { + if (OCFS2_XATTR_BUCKET_SIZE != blocksize) { + ret = ocfs2_read_blocks(inode, +- bucket_blkno(&xs->bucket) + 1, +- blk_per_bucket - 1, &xs->bucket.bu_bhs[1], ++ bucket_blkno(xs->bucket) + 1, ++ blk_per_bucket - 1, &xs->bucket->bu_bhs[1], + 0); + if (ret) { + mlog_errno(ret); +@@ -3244,8 +3288,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + { + int ret, i; + int count, start, len, name_value_len = 0, xe_len, name_offset = 0; +- u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- struct ocfs2_xattr_bucket s_bucket, t_bucket; ++ struct ocfs2_xattr_bucket *s_bucket = NULL, *t_bucket = NULL; + struct ocfs2_xattr_header *xh; + struct ocfs2_xattr_entry *xe; + int blocksize = inode->i_sb->s_blocksize; +@@ -3253,16 +3296,21 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + mlog(0, "move some of xattrs from bucket %llu to %llu\n", + (unsigned long long)blk, (unsigned long long)new_blk); + +- memset(&s_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); +- memset(&t_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); ++ s_bucket = ocfs2_xattr_bucket_new(inode); ++ t_bucket = ocfs2_xattr_bucket_new(inode); ++ if (!s_bucket || !t_bucket) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } + +- ret = ocfs2_read_xattr_bucket(inode, &s_bucket, blk); ++ ret = ocfs2_read_xattr_bucket(s_bucket, blk); + if (ret) { + mlog_errno(ret); + goto out; + } + +- ret = ocfs2_xattr_bucket_journal_access(handle, inode, &s_bucket, ++ ret = ocfs2_xattr_bucket_journal_access(handle, s_bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -3273,13 +3321,13 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + * Even if !new_bucket_head, we're overwriting t_bucket. Thus, + * there's no need to read it. + */ +- ret = ocfs2_init_xattr_bucket(inode, &t_bucket, new_blk); ++ ret = ocfs2_init_xattr_bucket(t_bucket, new_blk); + if (ret) { + mlog_errno(ret); + goto out; + } + +- ret = ocfs2_xattr_bucket_journal_access(handle, inode, &t_bucket, ++ ret = ocfs2_xattr_bucket_journal_access(handle, t_bucket, + new_bucket_head ? + OCFS2_JOURNAL_ACCESS_CREATE : + OCFS2_JOURNAL_ACCESS_WRITE); +@@ -3288,7 +3336,7 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + goto out; + } + +- xh = bucket_xh(&s_bucket); ++ xh = bucket_xh(s_bucket); + count = le16_to_cpu(xh->xh_count); + start = ocfs2_xattr_find_divide_pos(xh); + +@@ -3300,10 +3348,10 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + * The hash value is set as one larger than + * that of the last entry in the previous bucket. + */ +- for (i = 0; i < blk_per_bucket; i++) +- memset(bucket_block(&t_bucket, i), 0, blocksize); ++ for (i = 0; i < t_bucket->bu_blocks; i++) ++ memset(bucket_block(t_bucket, i), 0, blocksize); + +- xh = bucket_xh(&t_bucket); ++ xh = bucket_xh(t_bucket); + xh->xh_free_start = cpu_to_le16(blocksize); + xh->xh_entries[0].xe_name_hash = xe->xe_name_hash; + le32_add_cpu(&xh->xh_entries[0].xe_name_hash, 1); +@@ -3312,10 +3360,10 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + } + + /* copy the whole bucket to the new first. */ +- ocfs2_xattr_bucket_copy_data(inode, &t_bucket, &s_bucket); ++ ocfs2_xattr_bucket_copy_data(t_bucket, s_bucket); + + /* update the new bucket. */ +- xh = bucket_xh(&t_bucket); ++ xh = bucket_xh(t_bucket); + + /* + * Calculate the total name/value len and xh_free_start for +@@ -3379,7 +3427,7 @@ set_num_buckets: + else + xh->xh_num_buckets = 0; + +- ocfs2_xattr_bucket_journal_dirty(handle, inode, &t_bucket); ++ ocfs2_xattr_bucket_journal_dirty(handle, t_bucket); + + /* store the first_hash of the new bucket. */ + if (first_hash) +@@ -3393,18 +3441,18 @@ set_num_buckets: + if (start == count) + goto out; + +- xh = bucket_xh(&s_bucket); ++ xh = bucket_xh(s_bucket); + memset(&xh->xh_entries[start], 0, + sizeof(struct ocfs2_xattr_entry) * (count - start)); + xh->xh_count = cpu_to_le16(start); + xh->xh_free_start = cpu_to_le16(name_offset); + xh->xh_name_value_len = cpu_to_le16(name_value_len); + +- ocfs2_xattr_bucket_journal_dirty(handle, inode, &s_bucket); ++ ocfs2_xattr_bucket_journal_dirty(handle, s_bucket); + + out: +- ocfs2_xattr_bucket_relse(inode, &s_bucket); +- ocfs2_xattr_bucket_relse(inode, &t_bucket); ++ ocfs2_xattr_bucket_free(s_bucket); ++ ocfs2_xattr_bucket_free(t_bucket); + + return ret; + } +@@ -3422,7 +3470,7 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + int t_is_new) + { + int ret; +- struct ocfs2_xattr_bucket s_bucket, t_bucket; ++ struct ocfs2_xattr_bucket *s_bucket = NULL, *t_bucket = NULL; + + BUG_ON(s_blkno == t_blkno); + +@@ -3430,10 +3478,15 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + (unsigned long long)s_blkno, (unsigned long long)t_blkno, + t_is_new); + +- memset(&s_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); +- memset(&t_bucket, 0, sizeof(struct ocfs2_xattr_bucket)); +- +- ret = ocfs2_read_xattr_bucket(inode, &s_bucket, s_blkno); ++ s_bucket = ocfs2_xattr_bucket_new(inode); ++ t_bucket = ocfs2_xattr_bucket_new(inode); ++ if (!s_bucket || !t_bucket) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_read_xattr_bucket(s_bucket, s_blkno); + if (ret) + goto out; + +@@ -3441,23 +3494,23 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + * Even if !t_is_new, we're overwriting t_bucket. Thus, + * there's no need to read it. + */ +- ret = ocfs2_init_xattr_bucket(inode, &t_bucket, t_blkno); ++ ret = ocfs2_init_xattr_bucket(t_bucket, t_blkno); + if (ret) + goto out; + +- ret = ocfs2_xattr_bucket_journal_access(handle, inode, &t_bucket, ++ ret = ocfs2_xattr_bucket_journal_access(handle, t_bucket, + t_is_new ? + OCFS2_JOURNAL_ACCESS_CREATE : + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) + goto out; + +- ocfs2_xattr_bucket_copy_data(inode, &t_bucket, &s_bucket); +- ocfs2_xattr_bucket_journal_dirty(handle, inode, &t_bucket); ++ ocfs2_xattr_bucket_copy_data(t_bucket, s_bucket); ++ ocfs2_xattr_bucket_journal_dirty(handle, t_bucket); + + out: +- ocfs2_xattr_bucket_relse(inode, &s_bucket); +- ocfs2_xattr_bucket_relse(inode, &t_bucket); ++ ocfs2_xattr_bucket_free(t_bucket); ++ ocfs2_xattr_bucket_free(s_bucket); + + return ret; + } +@@ -4009,7 +4062,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode, + xe->xe_value_size = 0; + + val = ocfs2_xattr_bucket_get_val(inode, +- &xs->bucket, offs); ++ xs->bucket, offs); + memset(val + OCFS2_XATTR_SIZE(name_len), 0, + size - OCFS2_XATTR_SIZE(name_len)); + if (OCFS2_XATTR_SIZE(xi->value_len) > 0) +@@ -4087,8 +4140,7 @@ set_new_name_value: + xh->xh_free_start = cpu_to_le16(offs); + } + +- val = ocfs2_xattr_bucket_get_val(inode, +- &xs->bucket, offs - size); ++ val = ocfs2_xattr_bucket_get_val(inode, xs->bucket, offs - size); + xe->xe_name_offset = cpu_to_le16(offs - size); + + memset(val, 0, size); +@@ -4122,12 +4174,12 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + + mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", + (unsigned long)xi->value_len, xi->name_index, +- (unsigned long long)bucket_blkno(&xs->bucket)); ++ (unsigned long long)bucket_blkno(xs->bucket)); + +- if (!xs->bucket.bu_bhs[1]) { ++ if (!xs->bucket->bu_bhs[1]) { + ret = ocfs2_read_blocks(inode, +- bucket_blkno(&xs->bucket) + 1, +- blk_per_bucket - 1, &xs->bucket.bu_bhs[1], ++ bucket_blkno(xs->bucket) + 1, ++ blk_per_bucket - 1, &xs->bucket->bu_bhs[1], + 0); + if (ret) { + mlog_errno(ret); +@@ -4143,7 +4195,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + goto out; + } + +- ret = ocfs2_xattr_bucket_journal_access(handle, inode, &xs->bucket, ++ ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { + mlog_errno(ret); +@@ -4151,7 +4203,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + } + + ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local); +- ocfs2_xattr_bucket_journal_dirty(handle, inode, &xs->bucket); ++ ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket); + + out: + ocfs2_commit_trans(osb, handle); +@@ -4264,10 +4316,10 @@ static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, + struct ocfs2_xattr_entry *xe = xs->here; + struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base; + +- BUG_ON(!xs->bucket.bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe)); ++ BUG_ON(!xs->bucket->bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe)); + + offset = xe - xh->xh_entries; +- ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bu_bhs[0], ++ ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket->bu_bhs[0], + offset, len); + if (ret) + mlog_errno(ret); +@@ -4387,7 +4439,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + struct ocfs2_xattr_search *xs) + { + handle_t *handle = NULL; +- struct ocfs2_xattr_header *xh = bucket_xh(&xs->bucket); ++ struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); + struct ocfs2_xattr_entry *last = &xh->xh_entries[ + le16_to_cpu(xh->xh_count) - 1]; + int ret = 0; +@@ -4400,7 +4452,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + return; + } + +- ret = ocfs2_xattr_bucket_journal_access(handle, inode, &xs->bucket, ++ ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +@@ -4413,7 +4465,7 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + memset(last, 0, sizeof(struct ocfs2_xattr_entry)); + le16_add_cpu(&xh->xh_count, -1); + +- ocfs2_xattr_bucket_journal_dirty(handle, inode, &xs->bucket); ++ ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket); + + out_commit: + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); +@@ -4565,7 +4617,7 @@ try_again: + + mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " + "of %u which exceed block size\n", +- (unsigned long long)bucket_blkno(&xs->bucket), ++ (unsigned long long)bucket_blkno(xs->bucket), + header_size); + + if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) +@@ -4605,7 +4657,7 @@ try_again: + mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, " + "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len =" + " %u\n", xs->not_found, +- (unsigned long long)bucket_blkno(&xs->bucket), ++ (unsigned long long)bucket_blkno(xs->bucket), + free, need, max_free, le16_to_cpu(xh->xh_free_start), + le16_to_cpu(xh->xh_name_value_len)); + +@@ -4617,7 +4669,7 @@ try_again: + * name/value will be moved, the xe shouldn't be changed + * in xs. + */ +- ret = ocfs2_defrag_xattr_bucket(inode, &xs->bucket); ++ ret = ocfs2_defrag_xattr_bucket(inode, xs->bucket); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4649,7 +4701,7 @@ try_again: + * add a new bucket for the insert. + */ + ret = ocfs2_check_xattr_bucket_collision(inode, +- &xs->bucket, ++ xs->bucket, + xi->name); + if (ret) { + mlog_errno(ret); +@@ -4658,14 +4710,13 @@ try_again: + + ret = ocfs2_add_new_xattr_bucket(inode, + xs->xattr_bh, +- xs->bucket.bu_bhs[0]); ++ xs->bucket->bu_bhs[0]); + if (ret) { + mlog_errno(ret); + goto out; + } + +- ocfs2_xattr_bucket_relse(inode, &xs->bucket); +- memset(&xs->bucket, 0, sizeof(xs->bucket)); ++ ocfs2_xattr_bucket_relse(xs->bucket); + + ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh, + xi->name_index, +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Track-local-alloc-bits-internally.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Track-local-alloc-bits-internally.patch new file mode 100644 index 000000000..714efaeba --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Track-local-alloc-bits-internally.patch @@ -0,0 +1,181 @@ +From: Mark Fasheh +Subject: ocfs2: Track local alloc bits internally +Patch-mainline: 2.6.28 + +Do this instead of tracking absolute local alloc size. This avoids +needless re-calculatiion of bits from bytes in localalloc.c. Additionally, +the value is now in a more natural unit for internal file system bitmap +work. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/localalloc.c | 34 ++++++++++++---------------------- + fs/ocfs2/ocfs2.h | 10 +++++++++- + fs/ocfs2/super.c | 8 +++++--- + 3 files changed, 26 insertions(+), 26 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -47,8 +47,6 @@ + + #define OCFS2_LOCAL_ALLOC(dinode) (&((dinode)->id2.i_lab)) + +-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb); +- + static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc); + + static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb, +@@ -75,21 +73,13 @@ static int ocfs2_local_alloc_new_window( + static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, + struct inode *local_alloc_inode); + +-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb) +-{ +- BUG_ON(osb->s_clustersize_bits > 20); +- +- /* Size local alloc windows by the megabyte */ +- return osb->local_alloc_size << (20 - osb->s_clustersize_bits); +-} +- + /* + * Tell us whether a given allocation should use the local alloc + * file. Otherwise, it has to go to the main bitmap. + */ + int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits) + { +- int la_bits = ocfs2_local_alloc_window_bits(osb); ++ int la_bits = osb->local_alloc_bits; + int ret = 0; + + if (osb->local_alloc_state != OCFS2_LA_ENABLED) +@@ -120,14 +110,16 @@ int ocfs2_load_local_alloc(struct ocfs2_ + + mlog_entry_void(); + +- if (osb->local_alloc_size == 0) ++ if (osb->local_alloc_bits == 0) + goto bail; + +- if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) { ++ if (osb->local_alloc_bits >= osb->bitmap_cpg) { + mlog(ML_NOTICE, "Requested local alloc window %d is larger " + "than max possible %u. Using defaults.\n", +- ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1)); +- osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; ++ osb->local_alloc_bits, (osb->bitmap_cpg - 1)); ++ osb->local_alloc_bits = ++ ocfs2_megabytes_to_clusters(osb->sb, ++ OCFS2_DEFAULT_LOCAL_ALLOC_SIZE); + } + + /* read the alloc off disk */ +@@ -190,8 +182,7 @@ bail: + if (inode) + iput(inode); + +- mlog(0, "Local alloc window bits = %d\n", +- ocfs2_local_alloc_window_bits(osb)); ++ mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits); + + mlog_exit(status); + return status; +@@ -530,7 +521,7 @@ int ocfs2_reserve_local_alloc_bits(struc + goto bail; + } + +- if (bits_wanted > ocfs2_local_alloc_window_bits(osb)) { ++ if (bits_wanted > osb->local_alloc_bits) { + mlog(0, "Asking for more than my max window size!\n"); + status = -ENOSPC; + goto bail; +@@ -858,7 +849,7 @@ static int ocfs2_local_alloc_reserve_for + goto bail; + } + +- (*ac)->ac_bits_wanted = ocfs2_local_alloc_window_bits(osb); ++ (*ac)->ac_bits_wanted = osb->local_alloc_bits; + + status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac); + if (status < 0) { +@@ -904,7 +895,7 @@ static int ocfs2_local_alloc_new_window( + "one\n"); + + mlog(0, "Allocating %u clusters for a new window.\n", +- ocfs2_local_alloc_window_bits(osb)); ++ osb->local_alloc_bits); + + /* Instruct the allocation code to try the most recently used + * cluster group. We'll re-record the group used this pass +@@ -914,8 +905,7 @@ static int ocfs2_local_alloc_new_window( + /* we used the generic suballoc reserve function, but we set + * everything up nicely, so there's no reason why we can't use + * the more specific cluster api to claim bits. */ +- status = ocfs2_claim_clusters(osb, handle, ac, +- ocfs2_local_alloc_window_bits(osb), ++ status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits, + &cluster_off, &cluster_count); + if (status < 0) { + if (status != -ENOSPC) +Index: linux-2.6.27/fs/ocfs2/ocfs2.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/ocfs2.h ++++ linux-2.6.27/fs/ocfs2/ocfs2.h +@@ -261,7 +261,7 @@ struct ocfs2_super + struct ocfs2_journal *journal; + unsigned long osb_commit_interval; + +- int local_alloc_size; ++ unsigned int local_alloc_bits; + enum ocfs2_local_alloc_state local_alloc_state; + struct buffer_head *local_alloc_bh; + u64 la_last_gd; +@@ -570,6 +570,14 @@ static inline unsigned int ocfs2_pages_p + return pages_per_cluster; + } + ++static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb, ++ unsigned int megs) ++{ ++ BUILD_BUG_ON(OCFS2_MAX_CLUSTERSIZE > 1048576); ++ ++ return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits); ++} ++ + static inline void ocfs2_init_inode_steal_slot(struct ocfs2_super *osb) + { + spin_lock(&osb->osb_lock); +Index: linux-2.6.27/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/super.c ++++ linux-2.6.27/fs/ocfs2/super.c +@@ -655,7 +655,7 @@ static int ocfs2_fill_super(struct super + osb->s_atime_quantum = parsed_options.atime_quantum; + osb->preferred_slot = parsed_options.slot; + osb->osb_commit_interval = parsed_options.commit_interval; +- osb->local_alloc_size = parsed_options.localalloc_opt; ++ osb->local_alloc_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); + + status = ocfs2_verify_userspace_stack(osb, &parsed_options); + if (status) +@@ -965,6 +965,7 @@ static int ocfs2_show_options(struct seq + { + struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb); + unsigned long opts = osb->s_mount_opt; ++ unsigned int local_alloc_megs; + + if (opts & OCFS2_MOUNT_HB_LOCAL) + seq_printf(s, ",_netdev,heartbeat=local"); +@@ -997,8 +998,9 @@ static int ocfs2_show_options(struct seq + seq_printf(s, ",commit=%u", + (unsigned) (osb->osb_commit_interval / HZ)); + +- if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE) +- seq_printf(s, ",localalloc=%d", osb->local_alloc_size); ++ local_alloc_megs = osb->local_alloc_bits >> (20 - osb->s_clustersize_bits); ++ if (local_alloc_megs != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE) ++ seq_printf(s, ",localalloc=%d", local_alloc_megs); + + if (opts & OCFS2_MOUNT_LOCALFLOCKS) + seq_printf(s, ",localflocks,"); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Uninline-ocfs2_xattr_name_hash.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Uninline-ocfs2_xattr_name_hash.patch new file mode 100644 index 000000000..6297efd34 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Uninline-ocfs2_xattr_name_hash.patch @@ -0,0 +1,32 @@ +From: Mark Fasheh +Subject: ocfs2: Uninline ocfs2_xattr_name_hash() +Patch-mainline: 2.6.28 + +This is too big to be inlined. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 10 +++++----- + 1 files changed, 5 insertions(+), 5 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -160,11 +160,11 @@ static inline struct xattr_handler *ocfs + return handler; + } + +-static inline u32 ocfs2_xattr_name_hash(struct inode *inode, +- char *prefix, +- int prefix_len, +- char *name, +- int name_len) ++static u32 ocfs2_xattr_name_hash(struct inode *inode, ++ char *prefix, ++ int prefix_len, ++ char *name, ++ int name_len) + { + /* Get hash value of uuid from super block */ + u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_defrag_xattr_bucket.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_defrag_xattr_bucket.patch new file mode 100644 index 000000000..11a11cb11 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_defrag_xattr_bucket.patch @@ -0,0 +1,114 @@ +From: Joel Becker +Date: Mon, 27 Oct 2008 15:25:18 -0700 +Subject: ocfs2: Use buckets in ocfs2_defrag_xattr_bucket(). +Patch-mainline: 2.6.29 + +Use the ocfs2_xattr_bucket abstraction for reading and writing the +bucket in ocfs2_defrag_xattr_bucket(). + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 55 ++++++++++++++++++++++------------------------------- + 1 files changed, 23 insertions(+), 32 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 76969b9..127a628 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -2894,21 +2894,11 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + struct ocfs2_xattr_header *xh; + char *entries, *buf, *bucket_buf = NULL; + u64 blkno = bucket_blkno(bucket); +- u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u16 xh_free_start; + size_t blocksize = inode->i_sb->s_blocksize; + handle_t *handle; +- struct buffer_head **bhs; + struct ocfs2_xattr_entry *xe; +- +- bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket, +- GFP_NOFS); +- if (!bhs) +- return -ENOMEM; +- +- ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, 0); +- if (ret) +- goto out; ++ struct ocfs2_xattr_bucket *wb = NULL; + + /* + * In order to make the operation more efficient and generic, +@@ -2922,11 +2912,21 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + goto out; + } + ++ wb = ocfs2_xattr_bucket_new(inode); ++ if (!wb) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = ocfs2_read_xattr_bucket(wb, blkno); ++ if (ret) ++ goto out; ++ + buf = bucket_buf; +- for (i = 0; i < blk_per_bucket; i++, buf += blocksize) +- memcpy(buf, bhs[i]->b_data, blocksize); ++ for (i = 0; i < wb->bu_blocks; i++, buf += blocksize) ++ memcpy(buf, bucket_block(wb, i), blocksize); + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), blk_per_bucket); ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), wb->bu_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + handle = NULL; +@@ -2934,13 +2934,11 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + goto out; + } + +- for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, bhs[i], +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret < 0) { +- mlog_errno(ret); +- goto commit; +- } ++ ret = ocfs2_xattr_bucket_journal_access(handle, wb, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto commit; + } + + xh = (struct ocfs2_xattr_header *)bucket_buf; +@@ -3009,21 +3007,14 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + cmp_xe, swap_xe); + + buf = bucket_buf; +- for (i = 0; i < blk_per_bucket; i++, buf += blocksize) { +- memcpy(bhs[i]->b_data, buf, blocksize); +- ocfs2_journal_dirty(handle, bhs[i]); +- } ++ for (i = 0; i < wb->bu_blocks; i++, buf += blocksize) ++ memcpy(bucket_block(wb, i), buf, blocksize); ++ ocfs2_xattr_bucket_journal_dirty(handle, wb); + + commit: + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: +- +- if (bhs) { +- for (i = 0; i < blk_per_bucket; i++) +- brelse(bhs[i]); +- } +- kfree(bhs); +- ++ ocfs2_xattr_bucket_free(wb); + kfree(bucket_buf); + return ret; + } +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_bucket_find.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_bucket_find.patch new file mode 100644 index 000000000..d513cf66a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_bucket_find.patch @@ -0,0 +1,198 @@ +From: Joel Becker +Date: Mon, 27 Oct 2008 15:01:54 -0700 +Subject: ocfs2: Use buckets in ocfs2_xattr_bucket_find(). +Patch-mainline: 2.6.29 + +Change the ocfs2_xattr_bucket_find() function to use ocfs2_xattr_bucket +as its abstraction. This makes for more efficient reads, as buckets are +linear blocks, and also has improved caching characteristics. It also +reads better. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 89 +++++++++++++++++++----------------------------------- + 1 files changed, 31 insertions(+), 58 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 766494e..46986c6 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -2248,7 +2248,7 @@ typedef int (xattr_bucket_func)(struct inode *inode, + void *para); + + static int ocfs2_find_xe_in_bucket(struct inode *inode, +- struct buffer_head *header_bh, ++ struct ocfs2_xattr_bucket *bucket, + int name_index, + const char *name, + u32 name_hash, +@@ -2256,11 +2256,9 @@ static int ocfs2_find_xe_in_bucket(struct inode *inode, + int *found) + { + int i, ret = 0, cmp = 1, block_off, new_offset; +- struct ocfs2_xattr_header *xh = +- (struct ocfs2_xattr_header *)header_bh->b_data; ++ struct ocfs2_xattr_header *xh = bucket_xh(bucket); + size_t name_len = strlen(name); + struct ocfs2_xattr_entry *xe = NULL; +- struct buffer_head *name_bh = NULL; + char *xe_name; + + /* +@@ -2291,19 +2289,8 @@ static int ocfs2_find_xe_in_bucket(struct inode *inode, + break; + } + +- ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off, +- &name_bh); +- if (ret) { +- mlog_errno(ret); +- break; +- } +- xe_name = name_bh->b_data + new_offset; +- +- cmp = memcmp(name, xe_name, name_len); +- brelse(name_bh); +- name_bh = NULL; +- +- if (cmp == 0) { ++ xe_name = bucket_block(bucket, block_off) + new_offset; ++ if (!memcmp(name, xe_name, name_len)) { + *xe_index = i; + *found = 1; + ret = 0; +@@ -2333,39 +2320,42 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + struct ocfs2_xattr_search *xs) + { + int ret, found = 0; +- struct buffer_head *bh = NULL; +- struct buffer_head *lower_bh = NULL; + struct ocfs2_xattr_header *xh = NULL; + struct ocfs2_xattr_entry *xe = NULL; + u16 index = 0; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + int low_bucket = 0, bucket, high_bucket; ++ struct ocfs2_xattr_bucket *search; + u32 last_hash; +- u64 blkno; ++ u64 blkno, lower_blkno = 0; + +- ret = ocfs2_read_block(inode, p_blkno, &bh); ++ search = ocfs2_xattr_bucket_new(inode); ++ if (!search) { ++ ret = -ENOMEM; ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_read_xattr_bucket(search, p_blkno); + if (ret) { + mlog_errno(ret); + goto out; + } + +- xh = (struct ocfs2_xattr_header *)bh->b_data; ++ xh = bucket_xh(search); + high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1; +- + while (low_bucket <= high_bucket) { +- brelse(bh); +- bh = NULL; +- bucket = (low_bucket + high_bucket) / 2; ++ ocfs2_xattr_bucket_relse(search); + ++ bucket = (low_bucket + high_bucket) / 2; + blkno = p_blkno + bucket * blk_per_bucket; +- +- ret = ocfs2_read_block(inode, blkno, &bh); ++ ret = ocfs2_read_xattr_bucket(search, blkno); + if (ret) { + mlog_errno(ret); + goto out; + } + +- xh = (struct ocfs2_xattr_header *)bh->b_data; ++ xh = bucket_xh(search); + xe = &xh->xh_entries[0]; + if (name_hash < le32_to_cpu(xe->xe_name_hash)) { + high_bucket = bucket - 1; +@@ -2382,10 +2372,8 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + + last_hash = le32_to_cpu(xe->xe_name_hash); + +- /* record lower_bh which may be the insert place. */ +- brelse(lower_bh); +- lower_bh = bh; +- bh = NULL; ++ /* record lower_blkno which may be the insert place. */ ++ lower_blkno = blkno; + + if (name_hash > le32_to_cpu(xe->xe_name_hash)) { + low_bucket = bucket + 1; +@@ -2393,7 +2381,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + } + + /* the searched xattr should reside in this bucket if exists. */ +- ret = ocfs2_find_xe_in_bucket(inode, lower_bh, ++ ret = ocfs2_find_xe_in_bucket(inode, search, + name_index, name, name_hash, + &index, &found); + if (ret) { +@@ -2408,35 +2396,21 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + * When the xattr's hash value is in the gap of 2 buckets, we will + * always set it to the previous bucket. + */ +- if (!lower_bh) { +- /* +- * We can't find any bucket whose first name_hash is less +- * than the find name_hash. +- */ +- BUG_ON(bh->b_blocknr != p_blkno); +- lower_bh = bh; +- bh = NULL; ++ if (!lower_blkno) ++ lower_blkno = p_blkno; ++ ++ /* This should be in cache - we just read it during the search */ ++ ret = ocfs2_read_xattr_bucket(xs->bucket, lower_blkno); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; + } +- xs->bucket->bu_bhs[0] = lower_bh; +- lower_bh = NULL; + + xs->header = bucket_xh(xs->bucket); + xs->base = bucket_block(xs->bucket, 0); + xs->end = xs->base + inode->i_sb->s_blocksize; + + if (found) { +- /* +- * If we have found the xattr enty, read all the blocks in +- * this bucket. +- */ +- ret = ocfs2_read_blocks(inode, bucket_blkno(xs->bucket) + 1, +- blk_per_bucket - 1, &xs->bucket->bu_bhs[1], +- 0); +- if (ret) { +- mlog_errno(ret); +- goto out; +- } +- + xs->here = &xs->header->xh_entries[index]; + mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name, + (unsigned long long)bucket_blkno(xs->bucket), index); +@@ -2444,8 +2418,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode, + ret = -ENODATA; + + out: +- brelse(bh); +- brelse(lower_bh); ++ ocfs2_xattr_bucket_free(search); + return ret; + } + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_create_index_block.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_create_index_block.patch new file mode 100644 index 000000000..68e7d70fc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_create_index_block.patch @@ -0,0 +1,240 @@ +From: Joel Becker +Date: Mon, 27 Oct 2008 15:18:29 -0700 +Subject: ocfs2: Use buckets in ocfs2_xattr_create_index_block(). +Patch-mainline: 2.6.29 + +Use the ocfs2_xattr_bucket abstraction in +ocfs2_xattr_create_index_block() and its helpers. We get more efficient +reads, a lot less buffer_head munging, and nicer code to boot. While +we're at it, ocfs2_xattr_update_xattr_search() becomes void. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 114 +++++++++++++++-------------------------------------- + 1 files changed, 32 insertions(+), 82 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 46986c6..76969b9 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -2649,32 +2649,34 @@ static void swap_xe(void *a, void *b, int size) + /* + * When the ocfs2_xattr_block is filled up, new bucket will be created + * and all the xattr entries will be moved to the new bucket. ++ * The header goes at the start of the bucket, and the names+values are ++ * filled from the end. This is why *target starts as the last buffer. + * Note: we need to sort the entries since they are not saved in order + * in the ocfs2_xattr_block. + */ + static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode, + struct buffer_head *xb_bh, +- struct buffer_head *xh_bh, +- struct buffer_head *data_bh) ++ struct ocfs2_xattr_bucket *bucket) + { + int i, blocksize = inode->i_sb->s_blocksize; ++ int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u16 offset, size, off_change; + struct ocfs2_xattr_entry *xe; + struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)xb_bh->b_data; + struct ocfs2_xattr_header *xb_xh = &xb->xb_attrs.xb_header; +- struct ocfs2_xattr_header *xh = +- (struct ocfs2_xattr_header *)xh_bh->b_data; ++ struct ocfs2_xattr_header *xh = bucket_xh(bucket); + u16 count = le16_to_cpu(xb_xh->xh_count); +- char *target = xh_bh->b_data, *src = xb_bh->b_data; ++ char *src = xb_bh->b_data; ++ char *target = bucket_block(bucket, blks - 1); + + mlog(0, "cp xattr from block %llu to bucket %llu\n", + (unsigned long long)xb_bh->b_blocknr, +- (unsigned long long)xh_bh->b_blocknr); ++ (unsigned long long)bucket_blkno(bucket)); ++ ++ for (i = 0; i < blks; i++) ++ memset(bucket_block(bucket, i), 0, blocksize); + +- memset(xh_bh->b_data, 0, blocksize); +- if (data_bh) +- memset(data_bh->b_data, 0, blocksize); + /* + * Since the xe_name_offset is based on ocfs2_xattr_header, + * there is a offset change corresponding to the change of +@@ -2686,8 +2688,6 @@ static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode, + size = blocksize - offset; + + /* copy all the names and values. */ +- if (data_bh) +- target = data_bh->b_data; + memcpy(target + offset, src + offset, size); + + /* Init new header now. */ +@@ -2697,7 +2697,7 @@ static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode, + xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE - size); + + /* copy all the entries. */ +- target = xh_bh->b_data; ++ target = bucket_block(bucket, 0); + offset = offsetof(struct ocfs2_xattr_header, xh_entries); + size = count * sizeof(struct ocfs2_xattr_entry); + memcpy(target + offset, (char *)xb_xh + offset, size); +@@ -2723,42 +2723,24 @@ static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode, + * While if the entry is in index b-tree, "bucket" indicates the + * real place of the xattr. + */ +-static int ocfs2_xattr_update_xattr_search(struct inode *inode, +- struct ocfs2_xattr_search *xs, +- struct buffer_head *old_bh, +- struct buffer_head *new_bh) ++static void ocfs2_xattr_update_xattr_search(struct inode *inode, ++ struct ocfs2_xattr_search *xs, ++ struct buffer_head *old_bh) + { +- int ret = 0; + char *buf = old_bh->b_data; + struct ocfs2_xattr_block *old_xb = (struct ocfs2_xattr_block *)buf; + struct ocfs2_xattr_header *old_xh = &old_xb->xb_attrs.xb_header; +- int i, blocksize = inode->i_sb->s_blocksize; +- u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ int i; + +- xs->bucket->bu_bhs[0] = new_bh; +- get_bh(new_bh); + xs->header = bucket_xh(xs->bucket); +- +- xs->base = new_bh->b_data; ++ xs->base = bucket_block(xs->bucket, 0); + xs->end = xs->base + inode->i_sb->s_blocksize; + +- if (!xs->not_found) { +- if (OCFS2_XATTR_BUCKET_SIZE != blocksize) { +- ret = ocfs2_read_blocks(inode, +- bucket_blkno(xs->bucket) + 1, +- blk_per_bucket - 1, &xs->bucket->bu_bhs[1], +- 0); +- if (ret) { +- mlog_errno(ret); +- return ret; +- } +- +- } +- i = xs->here - old_xh->xh_entries; +- xs->here = &xs->header->xh_entries[i]; +- } ++ if (xs->not_found) ++ return; + +- return ret; ++ i = xs->here - old_xh->xh_entries; ++ xs->here = &xs->header->xh_entries[i]; + } + + static int ocfs2_xattr_create_index_block(struct inode *inode, +@@ -2771,18 +2753,17 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_alloc_context *data_ac; +- struct buffer_head *xh_bh = NULL, *data_bh = NULL; + struct buffer_head *xb_bh = xs->xattr_bh; + struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)xb_bh->b_data; + struct ocfs2_xattr_tree_root *xr; + u16 xb_flags = le16_to_cpu(xb->xb_flags); +- u16 bpb = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + + mlog(0, "create xattr index block for %llu\n", + (unsigned long long)xb_bh->b_blocknr); + + BUG_ON(xb_flags & OCFS2_XATTR_INDEXED); ++ BUG_ON(!xs->bucket); + + ret = ocfs2_reserve_clusters(osb, 1, &data_ac); + if (ret) { +@@ -2798,10 +2779,10 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + down_write(&oi->ip_alloc_sem); + + /* +- * 3 more credits, one for xattr block update, one for the 1st block +- * of the new xattr bucket and one for the value/data. ++ * We need more credits. One for the xattr block update and one ++ * for each block of the new xattr bucket. + */ +- credits += 3; ++ credits += 1 + ocfs2_blocks_per_xattr_bucket(inode->i_sb); + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); +@@ -2832,51 +2813,23 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + mlog(0, "allocate 1 cluster from %llu to xattr block\n", + (unsigned long long)blkno); + +- xh_bh = sb_getblk(inode->i_sb, blkno); +- if (!xh_bh) { +- ret = -EIO; ++ ret = ocfs2_init_xattr_bucket(xs->bucket, blkno); ++ if (ret) { + mlog_errno(ret); + goto out_commit; + } + +- ocfs2_set_new_buffer_uptodate(inode, xh_bh); +- +- ret = ocfs2_journal_access(handle, inode, xh_bh, +- OCFS2_JOURNAL_ACCESS_CREATE); ++ ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, ++ OCFS2_JOURNAL_ACCESS_CREATE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + +- if (bpb > 1) { +- data_bh = sb_getblk(inode->i_sb, blkno + bpb - 1); +- if (!data_bh) { +- ret = -EIO; +- mlog_errno(ret); +- goto out_commit; +- } +- +- ocfs2_set_new_buffer_uptodate(inode, data_bh); +- +- ret = ocfs2_journal_access(handle, inode, data_bh, +- OCFS2_JOURNAL_ACCESS_CREATE); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } +- } +- +- ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xh_bh, data_bh); +- +- ocfs2_journal_dirty(handle, xh_bh); +- if (data_bh) +- ocfs2_journal_dirty(handle, data_bh); ++ ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xs->bucket); ++ ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket); + +- ret = ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } ++ ocfs2_xattr_update_xattr_search(inode, xs, xb_bh); + + /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */ + memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize - +@@ -2911,9 +2864,6 @@ out: + if (data_ac) + ocfs2_free_alloc_context(data_ac); + +- brelse(xh_bh); +- brelse(data_bh); +- + return ret; + } + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_set_entry_in_bucke.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_set_entry_in_bucke.patch new file mode 100644 index 000000000..18d4bd697 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-buckets-in-ocfs2_xattr_set_entry_in_bucke.patch @@ -0,0 +1,52 @@ +From: Joel Becker +Date: Mon, 27 Oct 2008 18:07:45 -0700 +Subject: ocfs2: Use buckets in ocfs2_xattr_set_entry_in_bucket(). +Patch-mainline: 2.6.29 + +The ocfs2_xattr_set_entry_in_bucket() function is already working on an +ocfs2_xattr_bucket structure, so let's use the bucket API. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 11 +++++------ + 1 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 127a628..029a9f4 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -4083,25 +4083,24 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + { + int ret; + handle_t *handle = NULL; +- u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ u64 blkno; + + mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", + (unsigned long)xi->value_len, xi->name_index, + (unsigned long long)bucket_blkno(xs->bucket)); + + if (!xs->bucket->bu_bhs[1]) { +- ret = ocfs2_read_blocks(inode, +- bucket_blkno(xs->bucket) + 1, +- blk_per_bucket - 1, &xs->bucket->bu_bhs[1], +- 0); ++ blkno = bucket_blkno(xs->bucket); ++ ocfs2_xattr_bucket_relse(xs->bucket); ++ ret = ocfs2_read_xattr_bucket(xs->bucket, blkno); + if (ret) { + mlog_errno(ret); + goto out; + } + } + +- handle = ocfs2_start_trans(osb, blk_per_bucket); ++ handle = ocfs2_start_trans(osb, xs->bucket->bu_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + handle = NULL; +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-ocfs2_extent_list-instead-o.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-ocfs2_extent_list-instead-o.patch new file mode 100644 index 000000000..3f2d0e8c5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-ocfs2_extent_list-instead-o.patch @@ -0,0 +1,223 @@ +From: Tao Ma +Subject: [PATCH 02/16] ocfs2: Use ocfs2_extent_list instead of ocfs2_dinode. +Patch-mainline: 2.6.28? +References: FATE302067 + +ocfs2_extend_meta_needed(), ocfs2_calc_extend_credits() and +ocfs2_reserve_new_metadata() are all useful for extent tree operations. But +they are all limited to an inode btree because they use a struct +ocfs2_dinode parameter. Change their parameter to struct ocfs2_extent_list +(the part of an ocfs2_dinode they actually use) so that the xattr btree code +can use these functions. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 3 ++- + fs/ocfs2/alloc.h | 12 +++++++++--- + fs/ocfs2/aops.c | 3 ++- + fs/ocfs2/dir.c | 5 +++-- + fs/ocfs2/file.c | 9 +++++---- + fs/ocfs2/journal.h | 17 +++++++++++------ + fs/ocfs2/suballoc.c | 4 ++-- + fs/ocfs2/suballoc.h | 7 ++++++- + 8 files changed, 40 insertions(+), 20 deletions(-) + +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -4536,7 +4536,8 @@ static int ocfs2_split_tree(struct inode + } else + rightmost_el = path_leaf_el(path); + +- credits += path->p_tree_depth + ocfs2_extend_meta_needed(di); ++ credits += path->p_tree_depth + ++ ocfs2_extend_meta_needed(&di->id2.i_list); + ret = ocfs2_extend_trans(handle, credits); + if (ret) { + mlog_errno(ret); +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -48,8 +48,14 @@ int ocfs2_remove_extent(struct inode *in + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, + struct buffer_head *bh); +-/* how many new metadata chunks would an allocation need at maximum? */ +-static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe) ++/* ++ * how many new metadata chunks would an allocation need at maximum? ++ * ++ * Please note that the caller must make sure that root_el is the root ++ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise ++ * the result may be wrong. ++ */ ++static inline int ocfs2_extend_meta_needed(struct ocfs2_extent_list *root_el) + { + /* + * Rather than do all the work of determining how much we need +@@ -59,7 +65,7 @@ static inline int ocfs2_extend_meta_need + * new tree_depth==0 extent_block, and one block at the new + * top-of-the tree. + */ +- return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2; ++ return le16_to_cpu(root_el->l_tree_depth) + 2; + } + + void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di); +--- a/fs/ocfs2/aops.c ++++ b/fs/ocfs2/aops.c +@@ -1720,7 +1720,8 @@ int ocfs2_write_begin_nolock(struct addr + goto out; + } + +- credits = ocfs2_calc_extend_credits(inode->i_sb, di, ++ credits = ocfs2_calc_extend_credits(inode->i_sb, ++ &di->id2.i_list, + clusters_to_alloc); + + } +--- a/fs/ocfs2/dir.c ++++ b/fs/ocfs2/dir.c +@@ -1430,6 +1430,7 @@ static int ocfs2_extend_dir(struct ocfs2 + int credits, num_free_extents, drop_alloc_sem = 0; + loff_t dir_i_size; + struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data; ++ struct ocfs2_extent_list *el = &fe->id2.i_list; + struct ocfs2_alloc_context *data_ac = NULL; + struct ocfs2_alloc_context *meta_ac = NULL; + handle_t *handle = NULL; +@@ -1488,7 +1489,7 @@ static int ocfs2_extend_dir(struct ocfs2 + } + + if (!num_free_extents) { +- status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac); ++ status = ocfs2_reserve_new_metadata(osb, el, &meta_ac); + if (status < 0) { + if (status != -ENOSPC) + mlog_errno(status); +@@ -1503,7 +1504,7 @@ static int ocfs2_extend_dir(struct ocfs2 + goto bail; + } + +- credits = ocfs2_calc_extend_credits(sb, fe, 1); ++ credits = ocfs2_calc_extend_credits(sb, el, 1); + } else { + spin_unlock(&OCFS2_I(dir)->ip_lock); + credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -540,7 +540,7 @@ int ocfs2_do_extend_allocation(struct oc + goto leave; + } else if ((!free_extents) + && (ocfs2_alloc_context_bits_left(meta_ac) +- < ocfs2_extend_meta_needed(fe))) { ++ < ocfs2_extend_meta_needed(&fe->id2.i_list))) { + mlog(0, "filesystem is really fragmented...\n"); + status = -EAGAIN; + reason = RESTART_META; +@@ -652,7 +652,7 @@ int ocfs2_lock_allocators(struct inode * + */ + if (!num_free_extents || + (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) { +- ret = ocfs2_reserve_new_metadata(osb, di, meta_ac); ++ ret = ocfs2_reserve_new_metadata(osb, &di->id2.i_list, meta_ac); + if (ret < 0) { + if (ret != -ENOSPC) + mlog_errno(ret); +@@ -732,7 +732,8 @@ restart_all: + goto leave; + } + +- credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add); ++ credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list, ++ clusters_to_add); + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); +@@ -790,7 +791,7 @@ restarted_transaction: + mlog(0, "restarting transaction.\n"); + /* TODO: This can be more intelligent. */ + credits = ocfs2_calc_extend_credits(osb->sb, +- fe, ++ &fe->id2.i_list, + clusters_to_add); + status = ocfs2_extend_trans(handle, credits); + if (status < 0) { +--- a/fs/ocfs2/journal.h ++++ b/fs/ocfs2/journal.h +@@ -340,11 +340,16 @@ int ocfs2_journal_dirty + #define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \ + + OCFS2_UNLINK_CREDITS) + ++/* ++ * Please note that the caller must make sure that root_el is the root ++ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise ++ * the result may be wrong. ++ */ + static inline int ocfs2_calc_extend_credits(struct super_block *sb, +- struct ocfs2_dinode *fe, ++ struct ocfs2_extent_list *root_el, + u32 bits_wanted) + { +- int bitmap_blocks, sysfile_bitmap_blocks, dinode_blocks; ++ int bitmap_blocks, sysfile_bitmap_blocks, extent_blocks; + + /* bitmap dinode, group desc. + relinked group. */ + bitmap_blocks = OCFS2_SUBALLOC_ALLOC; +@@ -355,16 +360,16 @@ static inline int ocfs2_calc_extend_cred + * however many metadata chunks needed * a remaining suballoc + * alloc. */ + sysfile_bitmap_blocks = 1 + +- (OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(fe); ++ (OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(root_el); + + /* this does not include *new* metadata blocks, which are +- * accounted for in sysfile_bitmap_blocks. fe + ++ * accounted for in sysfile_bitmap_blocks. root_el + + * prev. last_eb_blk + blocks along edge of tree. + * calc_symlink_credits passes because we just need 1 + * credit for the dinode there. */ +- dinode_blocks = 1 + 1 + le16_to_cpu(fe->id2.i_list.l_tree_depth); ++ extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth); + +- return bitmap_blocks + sysfile_bitmap_blocks + dinode_blocks; ++ return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks; + } + + static inline int ocfs2_calc_symlink_credits(struct super_block *sb) +--- a/fs/ocfs2/suballoc.c ++++ b/fs/ocfs2/suballoc.c +@@ -494,7 +494,7 @@ bail: + } + + int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, +- struct ocfs2_dinode *fe, ++ struct ocfs2_extent_list *root_el, + struct ocfs2_alloc_context **ac) + { + int status; +@@ -507,7 +507,7 @@ int ocfs2_reserve_new_metadata(struct oc + goto bail; + } + +- (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(fe); ++ (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(root_el); + (*ac)->ac_which = OCFS2_AC_USE_META; + slot = osb->slot_num; + (*ac)->ac_group_search = ocfs2_block_group_search; +--- a/fs/ocfs2/suballoc.h ++++ b/fs/ocfs2/suballoc.h +@@ -59,8 +59,13 @@ static inline int ocfs2_alloc_context_bi + return ac->ac_bits_wanted - ac->ac_bits_given; + } + ++/* ++ * Please note that the caller must make sure that root_el is the root ++ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise ++ * the result may be wrong. ++ */ + int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, +- struct ocfs2_dinode *fe, ++ struct ocfs2_extent_list *root_el, + struct ocfs2_alloc_context **ac); + int ocfs2_reserve_new_inode(struct ocfs2_super *osb, + struct ocfs2_alloc_context **ac); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-struct-ocfs2_extent_tree-in-ocfs2_num_fre.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-struct-ocfs2_extent_tree-in-ocfs2_num_fre.patch new file mode 100644 index 000000000..c4e614923 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Use-struct-ocfs2_extent_tree-in-ocfs2_num_fre.patch @@ -0,0 +1,72 @@ +From: Joel Becker +Subject: ocfs2: Use struct ocfs2_extent_tree in ocfs2_num_free_extents(). +Patch-mainline: 2.6.28? +References: FATE302067 + +ocfs2_num_free_extents() re-implements the logic of +ocfs2_get_extent_tree(). Now that ocfs2_get_extent_tree() does not +allocate, let's use it in ocfs2_num_free_extents() to simplify the code. + +The inode validation code in ocfs2_num_free_extents() is not needed. +All callers are passing in pre-validated inodes. + +Signed-off-by: Joel Becker +Acked-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 30 +++++------------------------- + 1 files changed, 5 insertions(+), 25 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index fb6ae67..0b900f6 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -618,34 +618,13 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct ocfs2_extent_block *eb; + struct buffer_head *eb_bh = NULL; + u64 last_eb_blk = 0; ++ struct ocfs2_extent_tree et; + + mlog_entry_void(); + +- if (type == OCFS2_DINODE_EXTENT) { +- struct ocfs2_dinode *fe = +- (struct ocfs2_dinode *)root_bh->b_data; +- if (!OCFS2_IS_VALID_DINODE(fe)) { +- OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe); +- retval = -EIO; +- goto bail; +- } +- +- if (fe->i_last_eb_blk) +- last_eb_blk = le64_to_cpu(fe->i_last_eb_blk); +- el = &fe->id2.i_list; +- } else if (type == OCFS2_XATTR_VALUE_EXTENT) { +- struct ocfs2_xattr_value_root *xv = +- (struct ocfs2_xattr_value_root *) obj; +- +- last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk); +- el = &xv->xr_list; +- } else if (type == OCFS2_XATTR_TREE_EXTENT) { +- struct ocfs2_xattr_block *xb = +- (struct ocfs2_xattr_block *)root_bh->b_data; +- +- last_eb_blk = le64_to_cpu(xb->xb_attrs.xb_root.xt_last_eb_blk); +- el = &xb->xb_attrs.xb_root.xt_list; +- } ++ ocfs2_get_extent_tree(&et, inode, root_bh, type, obj); ++ el = et.et_root_el; ++ last_eb_blk = ocfs2_et_get_last_eb_blk(&et); + + if (last_eb_blk) { + retval = ocfs2_read_block(osb, last_eb_blk, +@@ -665,6 +644,7 @@ bail: + if (eb_bh) + brelse(eb_bh); + ++ ocfs2_put_extent_tree(&et); + mlog_exit(retval); + return retval; + } +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Wrap-journal_access-journal_dirty-for-xattr-b.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Wrap-journal_access-journal_dirty-for-xattr-b.patch new file mode 100644 index 000000000..b727246df --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Wrap-journal_access-journal_dirty-for-xattr-b.patch @@ -0,0 +1,266 @@ +From: Joel Becker +Date: Fri, 24 Oct 2008 18:47:33 -0700 +Subject: ocfs2: Wrap journal_access/journal_dirty for xattr buckets. +Patch-mainline: 2.6.29 + +A common action is to call ocfs2_journal_access() and +ocfs2_journal_dirty() on the buffer heads of an xattr bucket. Let's +create nice wrappers. + +While we're there, let's drop the places that try to be smart by writing +only the first and last blocks of a bucket. A bucket is contiguous, so +writing the whole thing is actually more efficient. + +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 140 +++++++++++++++++++++++++----------------------------- + 1 files changed, 64 insertions(+), 76 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index fa13fa4..99aefe4 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -210,6 +210,37 @@ static int ocfs2_read_xattr_bucket(struct inode *inode, + return rc; + } + ++static int ocfs2_xattr_bucket_journal_access(handle_t *handle, ++ struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket, ++ int type) ++{ ++ int i, rc = 0; ++ int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ for (i = 0; i < blks; i++) { ++ rc = ocfs2_journal_access(handle, inode, ++ bucket->bu_bhs[i], type); ++ if (rc) { ++ mlog_errno(rc); ++ break; ++ } ++ } ++ ++ return rc; ++} ++ ++static void ocfs2_xattr_bucket_journal_dirty(handle_t *handle, ++ struct inode *inode, ++ struct ocfs2_xattr_bucket *bucket) ++{ ++ int i, blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ for (i = 0; i < blks; i++) ++ ocfs2_journal_dirty(handle, bucket->bu_bhs[i]); ++} ++ ++ + static inline const char *ocfs2_xattr_prefix(int name_index) + { + struct xattr_handler *handler = NULL; +@@ -3218,8 +3249,8 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + goto out; + } + +- ret = ocfs2_journal_access(handle, inode, s_bucket.bu_bhs[0], +- OCFS2_JOURNAL_ACCESS_WRITE); ++ ret = ocfs2_xattr_bucket_journal_access(handle, inode, &s_bucket, ++ OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out; +@@ -3235,15 +3266,13 @@ static int ocfs2_divide_xattr_bucket(struct inode *inode, + goto out; + } + +- for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, t_bucket.bu_bhs[i], +- new_bucket_head ? +- OCFS2_JOURNAL_ACCESS_CREATE : +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret) { +- mlog_errno(ret); +- goto out; +- } ++ ret = ocfs2_xattr_bucket_journal_access(handle, inode, &t_bucket, ++ new_bucket_head ? ++ OCFS2_JOURNAL_ACCESS_CREATE : ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; + } + + xh = bucket_xh(&s_bucket); +@@ -3339,11 +3368,7 @@ set_num_buckets: + else + xh->xh_num_buckets = 0; + +- for (i = 0; i < blk_per_bucket; i++) { +- ocfs2_journal_dirty(handle, t_bucket.bu_bhs[i]); +- if (ret) +- mlog_errno(ret); +- } ++ ocfs2_xattr_bucket_journal_dirty(handle, inode, &t_bucket); + + /* store the first_hash of the new bucket. */ + if (first_hash) +@@ -3364,9 +3389,7 @@ set_num_buckets: + xh->xh_free_start = cpu_to_le16(name_offset); + xh->xh_name_value_len = cpu_to_le16(name_value_len); + +- ocfs2_journal_dirty(handle, s_bucket.bu_bhs[0]); +- if (ret) +- mlog_errno(ret); ++ ocfs2_xattr_bucket_journal_dirty(handle, inode, &s_bucket); + + out: + ocfs2_xattr_bucket_relse(inode, &s_bucket); +@@ -3413,20 +3436,18 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode, + if (ret) + goto out; + +- for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, t_bucket.bu_bhs[i], +- t_is_new ? +- OCFS2_JOURNAL_ACCESS_CREATE : +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret) +- goto out; +- } ++ ret = ocfs2_xattr_bucket_journal_access(handle, inode, &t_bucket, ++ t_is_new ? ++ OCFS2_JOURNAL_ACCESS_CREATE : ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) ++ goto out; + + for (i = 0; i < blk_per_bucket; i++) { + memcpy(bucket_block(&t_bucket, i), bucket_block(&s_bucket, i), + blocksize); +- ocfs2_journal_dirty(handle, t_bucket.bu_bhs[i]); + } ++ ocfs2_xattr_bucket_journal_dirty(handle, inode, &t_bucket); + + out: + ocfs2_xattr_bucket_relse(inode, &s_bucket); +@@ -3799,9 +3820,9 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, + + /* + * We will touch all the buckets after the start_bh(include it). +- * Add one more bucket and modify the first_bh. ++ * Then we add one more bucket. + */ +- credits = end_blk - start_blk + 2 * blk_per_bucket + 1; ++ credits = end_blk - start_blk + 3 * blk_per_bucket + 1; + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); +@@ -4077,33 +4098,6 @@ set_new_name_value: + return; + } + +-static int ocfs2_xattr_bucket_handle_journal(struct inode *inode, +- handle_t *handle, +- struct ocfs2_xattr_search *xs, +- struct buffer_head **bhs, +- u16 bh_num) +-{ +- int ret = 0, off, block_off; +- struct ocfs2_xattr_entry *xe = xs->here; +- +- /* +- * First calculate all the blocks we should journal_access +- * and journal_dirty. The first block should always be touched. +- */ +- ret = ocfs2_journal_dirty(handle, bhs[0]); +- if (ret) +- mlog_errno(ret); +- +- /* calc the data. */ +- off = le16_to_cpu(xe->xe_name_offset); +- block_off = off >> inode->i_sb->s_blocksize_bits; +- ret = ocfs2_journal_dirty(handle, bhs[block_off]); +- if (ret) +- mlog_errno(ret); +- +- return ret; +-} +- + /* + * Set the xattr entry in the specified bucket. + * The bucket is indicated by xs->bucket and it should have the enough +@@ -4115,7 +4109,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + u32 name_hash, + int local) + { +- int i, ret; ++ int ret; + handle_t *handle = NULL; + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +@@ -4143,22 +4137,16 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + goto out; + } + +- for (i = 0; i < blk_per_bucket; i++) { +- ret = ocfs2_journal_access(handle, inode, xs->bucket.bu_bhs[i], +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret < 0) { +- mlog_errno(ret); +- goto out; +- } ++ ret = ocfs2_xattr_bucket_journal_access(handle, inode, &xs->bucket, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; + } + + ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local); ++ ocfs2_xattr_bucket_journal_dirty(handle, inode, &xs->bucket); + +- /*Only dirty the blocks we have touched in set xattr. */ +- ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs, +- xs->bucket.bu_bhs, blk_per_bucket); +- if (ret) +- mlog_errno(ret); + out: + ocfs2_commit_trans(osb, handle); + +@@ -4398,15 +4386,16 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + le16_to_cpu(xh->xh_count) - 1]; + int ret = 0; + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), 1); ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), ++ ocfs2_blocks_per_xattr_bucket(inode->i_sb)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + return; + } + +- ret = ocfs2_journal_access(handle, inode, xs->bucket.bu_bhs[0], +- OCFS2_JOURNAL_ACCESS_WRITE); ++ ret = ocfs2_xattr_bucket_journal_access(handle, inode, &xs->bucket, ++ OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -4418,9 +4407,8 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + memset(last, 0, sizeof(struct ocfs2_xattr_entry)); + le16_add_cpu(&xh->xh_count, -1); + +- ret = ocfs2_journal_dirty(handle, xs->bucket.bu_bhs[0]); +- if (ret < 0) +- mlog_errno(ret); ++ ocfs2_xattr_bucket_journal_dirty(handle, inode, &xs->bucket); ++ + out_commit: + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + } +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-POSIX-ACL-API.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-POSIX-ACL-API.patch new file mode 100644 index 000000000..f025363ef --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-POSIX-ACL-API.patch @@ -0,0 +1,514 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:17:04 +0800 +Subject: ocfs2: add POSIX ACL API +Patch-mainline: 2.6.29 + +This patch adds POSIX ACL(access control lists) APIs in ocfs2. We convert +struct posix_acl to many ocfs2_acl_entry and regard them as an extended +attribute entry. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/Makefile | 4 + + fs/ocfs2/acl.c | 378 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/acl.h | 29 ++++ + fs/ocfs2/ocfs2.h | 1 + + fs/ocfs2/xattr.c | 10 ++ + fs/ocfs2/xattr.h | 4 + + 6 files changed, 426 insertions(+), 0 deletions(-) + create mode 100644 fs/ocfs2/acl.c + create mode 100644 fs/ocfs2/acl.h + +diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile +index 589dcdf..e9ef5d1 100644 +--- a/fs/ocfs2/Makefile ++++ b/fs/ocfs2/Makefile +@@ -37,6 +37,10 @@ ocfs2-objs := \ + ver.o \ + xattr.o + ++ifeq ($(CONFIG_OCFS2_FS_POSIX_ACL),y) ++ocfs2-objs += acl.o ++endif ++ + ocfs2_stackglue-objs := stackglue.o + ocfs2_stack_o2cb-objs := stack_o2cb.o + ocfs2_stack_user-objs := stack_user.o +diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c +new file mode 100644 +index 0000000..62d0faa +--- /dev/null ++++ b/fs/ocfs2/acl.c +@@ -0,0 +1,378 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * acl.c ++ * ++ * Copyright (C) 2004, 2008 Oracle. All rights reserved. ++ * ++ * CREDITS: ++ * Lots of code in this file is copy from linux/fs/ext3/acl.c. ++ * Copyright (C) 2001-2003 Andreas Gruenbacher, ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++ ++#define MLOG_MASK_PREFIX ML_INODE ++#include ++ ++#include "ocfs2.h" ++#include "alloc.h" ++#include "dlmglue.h" ++#include "file.h" ++#include "ocfs2_fs.h" ++ ++#include "xattr.h" ++#include "acl.h" ++ ++/* ++ * Convert from xattr value to acl struct. ++ */ ++static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size) ++{ ++ int n, count; ++ struct posix_acl *acl; ++ ++ if (!value) ++ return NULL; ++ if (size < sizeof(struct posix_acl_entry)) ++ return ERR_PTR(-EINVAL); ++ ++ count = size / sizeof(struct posix_acl_entry); ++ if (count < 0) ++ return ERR_PTR(-EINVAL); ++ if (count == 0) ++ return NULL; ++ ++ acl = posix_acl_alloc(count, GFP_NOFS); ++ if (!acl) ++ return ERR_PTR(-ENOMEM); ++ for (n = 0; n < count; n++) { ++ struct ocfs2_acl_entry *entry = ++ (struct ocfs2_acl_entry *)value; ++ ++ acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); ++ acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); ++ acl->a_entries[n].e_id = le32_to_cpu(entry->e_id); ++ value += sizeof(struct posix_acl_entry); ++ ++ } ++ return acl; ++} ++ ++/* ++ * Convert acl struct to xattr value. ++ */ ++static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size) ++{ ++ struct ocfs2_acl_entry *entry = NULL; ++ char *ocfs2_acl; ++ size_t n; ++ ++ *size = acl->a_count * sizeof(struct posix_acl_entry); ++ ++ ocfs2_acl = kmalloc(*size, GFP_NOFS); ++ if (!ocfs2_acl) ++ return ERR_PTR(-ENOMEM); ++ ++ entry = (struct ocfs2_acl_entry *)ocfs2_acl; ++ for (n = 0; n < acl->a_count; n++, entry++) { ++ entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); ++ entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); ++ entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); ++ } ++ return ocfs2_acl; ++} ++ ++static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode, ++ int type, ++ struct buffer_head *di_bh) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ int name_index; ++ char *value = NULL; ++ struct posix_acl *acl; ++ int retval; ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return NULL; ++ ++ switch (type) { ++ case ACL_TYPE_ACCESS: ++ name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; ++ break; ++ case ACL_TYPE_DEFAULT: ++ name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; ++ break; ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++ ++ retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0); ++ if (retval > 0) { ++ value = kmalloc(retval, GFP_NOFS); ++ if (!value) ++ return ERR_PTR(-ENOMEM); ++ retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, ++ "", value, retval); ++ } ++ ++ if (retval > 0) ++ acl = ocfs2_acl_from_xattr(value, retval); ++ else if (retval == -ENODATA || retval == 0) ++ acl = NULL; ++ else ++ acl = ERR_PTR(retval); ++ ++ kfree(value); ++ ++ return acl; ++} ++ ++ ++/* ++ * Get posix acl. ++ */ ++static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct buffer_head *di_bh = NULL; ++ struct posix_acl *acl; ++ int ret; ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return NULL; ++ ++ ret = ocfs2_inode_lock(inode, &di_bh, 0); ++ if (ret < 0) { ++ mlog_errno(ret); ++ acl = ERR_PTR(ret); ++ return acl; ++ } ++ ++ acl = ocfs2_get_acl_nolock(inode, type, di_bh); ++ ++ ocfs2_inode_unlock(inode, 0); ++ ++ brelse(di_bh); ++ ++ return acl; ++} ++ ++/* ++ * Set the access or default ACL of an inode. ++ */ ++static int ocfs2_set_acl(handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *di_bh, ++ int type, ++ struct posix_acl *acl, ++ struct ocfs2_alloc_context *meta_ac, ++ struct ocfs2_alloc_context *data_ac) ++{ ++ int name_index; ++ void *value = NULL; ++ size_t size = 0; ++ int ret; ++ ++ if (S_ISLNK(inode->i_mode)) ++ return -EOPNOTSUPP; ++ ++ switch (type) { ++ case ACL_TYPE_ACCESS: ++ name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS; ++ if (acl) { ++ mode_t mode = inode->i_mode; ++ ret = posix_acl_equiv_mode(acl, &mode); ++ if (ret < 0) ++ return ret; ++ else { ++ inode->i_mode = mode; ++ if (ret == 0) ++ acl = NULL; ++ } ++ } ++ break; ++ case ACL_TYPE_DEFAULT: ++ name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT; ++ if (!S_ISDIR(inode->i_mode)) ++ return acl ? -EACCES : 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (acl) { ++ value = ocfs2_acl_to_xattr(acl, &size); ++ if (IS_ERR(value)) ++ return (int)PTR_ERR(value); ++ } ++ ++ if (handle) ++ ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index, ++ "", value, size, 0, ++ meta_ac, data_ac); ++ else ++ ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0); ++ ++ kfree(value); ++ ++ return ret; ++} ++ ++static size_t ocfs2_xattr_list_acl_access(struct inode *inode, ++ char *list, ++ size_t list_len, ++ const char *name, ++ size_t name_len) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return 0; ++ ++ if (list && size <= list_len) ++ memcpy(list, POSIX_ACL_XATTR_ACCESS, size); ++ return size; ++} ++ ++static size_t ocfs2_xattr_list_acl_default(struct inode *inode, ++ char *list, ++ size_t list_len, ++ const char *name, ++ size_t name_len) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return 0; ++ ++ if (list && size <= list_len) ++ memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); ++ return size; ++} ++ ++static int ocfs2_xattr_get_acl(struct inode *inode, ++ int type, ++ void *buffer, ++ size_t size) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct posix_acl *acl; ++ int ret; ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return -EOPNOTSUPP; ++ ++ acl = ocfs2_get_acl(inode, type); ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ if (acl == NULL) ++ return -ENODATA; ++ ret = posix_acl_to_xattr(acl, buffer, size); ++ posix_acl_release(acl); ++ ++ return ret; ++} ++ ++static int ocfs2_xattr_get_acl_access(struct inode *inode, ++ const char *name, ++ void *buffer, ++ size_t size) ++{ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ return ocfs2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); ++} ++ ++static int ocfs2_xattr_get_acl_default(struct inode *inode, ++ const char *name, ++ void *buffer, ++ size_t size) ++{ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ return ocfs2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); ++} ++ ++static int ocfs2_xattr_set_acl(struct inode *inode, ++ int type, ++ const void *value, ++ size_t size) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct posix_acl *acl; ++ int ret = 0; ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return -EOPNOTSUPP; ++ ++ if (!is_owner_or_cap(inode)) ++ return -EPERM; ++ ++ if (value) { ++ acl = posix_acl_from_xattr(value, size); ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ else if (acl) { ++ ret = posix_acl_valid(acl); ++ if (ret) ++ goto cleanup; ++ } ++ } else ++ acl = NULL; ++ ++ ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); ++ ++cleanup: ++ posix_acl_release(acl); ++ return ret; ++} ++ ++static int ocfs2_xattr_set_acl_access(struct inode *inode, ++ const char *name, ++ const void *value, ++ size_t size, ++ int flags) ++{ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ return ocfs2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); ++} ++ ++static int ocfs2_xattr_set_acl_default(struct inode *inode, ++ const char *name, ++ const void *value, ++ size_t size, ++ int flags) ++{ ++ if (strcmp(name, "") != 0) ++ return -EINVAL; ++ return ocfs2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); ++} ++ ++struct xattr_handler ocfs2_xattr_acl_access_handler = { ++ .prefix = POSIX_ACL_XATTR_ACCESS, ++ .list = ocfs2_xattr_list_acl_access, ++ .get = ocfs2_xattr_get_acl_access, ++ .set = ocfs2_xattr_set_acl_access, ++}; ++ ++struct xattr_handler ocfs2_xattr_acl_default_handler = { ++ .prefix = POSIX_ACL_XATTR_DEFAULT, ++ .list = ocfs2_xattr_list_acl_default, ++ .get = ocfs2_xattr_get_acl_default, ++ .set = ocfs2_xattr_set_acl_default, ++}; +diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h +new file mode 100644 +index 0000000..1b39f3e +--- /dev/null ++++ b/fs/ocfs2/acl.h +@@ -0,0 +1,29 @@ ++/* -*- mode: c; c-basic-offset: 8; -*- ++ * vim: noexpandtab sw=8 ts=8 sts=0: ++ * ++ * acl.h ++ * ++ * Copyright (C) 2004, 2008 Oracle. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public ++ * License version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#ifndef OCFS2_ACL_H ++#define OCFS2_ACL_H ++ ++#include ++ ++struct ocfs2_acl_entry { ++ __le16 e_tag; ++ __le16 e_perm; ++ __le32 e_id; ++}; ++ ++#endif /* OCFS2_ACL_H */ +diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h +index 3fed9e3..25d07ff 100644 +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -195,6 +195,7 @@ enum ocfs2_mount_options + OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */ + OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */ + OCFS2_MOUNT_INODE64 = 1 << 7, /* Allow inode numbers > 2^32 */ ++ OCFS2_MOUNT_POSIX_ACL = 1 << 8, /* POSIX access control lists */ + }; + + #define OCFS2_OSB_SOFT_RO 0x0001 +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index ba9b870..2e273c2 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -91,6 +91,10 @@ static struct ocfs2_xattr_def_value_root def_xv = { + + struct xattr_handler *ocfs2_xattr_handlers[] = { + &ocfs2_xattr_user_handler, ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ &ocfs2_xattr_acl_access_handler, ++ &ocfs2_xattr_acl_default_handler, ++#endif + &ocfs2_xattr_trusted_handler, + &ocfs2_xattr_security_handler, + NULL +@@ -98,6 +102,12 @@ struct xattr_handler *ocfs2_xattr_handlers[] = { + + static struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = { + [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS] ++ = &ocfs2_xattr_acl_access_handler, ++ [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT] ++ = &ocfs2_xattr_acl_default_handler, ++#endif + [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, + [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler, + }; +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index 86aa10f..6163df3 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -40,6 +40,10 @@ struct ocfs2_security_xattr_info { + extern struct xattr_handler ocfs2_xattr_user_handler; + extern struct xattr_handler ocfs2_xattr_trusted_handler; + extern struct xattr_handler ocfs2_xattr_security_handler; ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++extern struct xattr_handler ocfs2_xattr_acl_access_handler; ++extern struct xattr_handler ocfs2_xattr_acl_default_handler; ++#endif + extern struct xattr_handler *ocfs2_xattr_handlers[]; + + ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-mount-option-and-Kconfig-option-for-acl.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-mount-option-and-Kconfig-option-for-acl.patch new file mode 100644 index 000000000..1f0dad1af --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-mount-option-and-Kconfig-option-for-acl.patch @@ -0,0 +1,103 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:17:52 +0800 +Subject: ocfs2: add mount option and Kconfig option for acl +Patch-mainline: 2.6.29 + +This patch adds the Kconfig option "CONFIG_OCFS2_FS_POSIX_ACL" +and mount options "acl" to enable acls in Ocfs2. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/super.c | 33 +++++++++++++++++++++++++++++++++ + 1 files changed, 33 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 304b63a..9e7accc 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -158,6 +158,8 @@ enum { + Opt_user_xattr, + Opt_nouser_xattr, + Opt_inode64, ++ Opt_acl, ++ Opt_noacl, + Opt_err, + }; + +@@ -180,6 +182,8 @@ static const match_table_t tokens = { + {Opt_user_xattr, "user_xattr"}, + {Opt_nouser_xattr, "nouser_xattr"}, + {Opt_inode64, "inode64"}, ++ {Opt_acl, "acl"}, ++ {Opt_noacl, "noacl"}, + {Opt_err, NULL} + }; + +@@ -466,6 +470,8 @@ unlock_osb: + if (!ret) { + /* Only save off the new mount options in case of a successful + * remount. */ ++ if (!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)) ++ parsed_options.mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; + osb->s_mount_opt = parsed_options.mount_opt; + osb->s_atime_quantum = parsed_options.atime_quantum; + osb->preferred_slot = parsed_options.slot; +@@ -651,6 +657,10 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) + } + brelse(bh); + bh = NULL; ++ ++ if (!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)) ++ parsed_options.mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; ++ + osb->s_mount_opt = parsed_options.mount_opt; + osb->s_atime_quantum = parsed_options.atime_quantum; + osb->preferred_slot = parsed_options.slot; +@@ -664,6 +674,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) + + sb->s_magic = OCFS2_SUPER_MAGIC; + ++ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ++ ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); ++ + /* Hard readonly mode only if: bdev_read_only, MS_RDONLY, + * heartbeat=none */ + if (bdev_read_only(sb->s_bdev)) { +@@ -945,6 +958,19 @@ static int ocfs2_parse_options(struct super_block *sb, + case Opt_inode64: + mopt->mount_opt |= OCFS2_MOUNT_INODE64; + break; ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ case Opt_acl: ++ mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL; ++ break; ++ case Opt_noacl: ++ mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; ++ break; ++#else ++ case Opt_acl: ++ case Opt_noacl: ++ printk(KERN_INFO "ocfs2 (no)acl options not supported\n"); ++ break; ++#endif + default: + mlog(ML_ERROR, + "Unrecognized mount option \"%s\" " +@@ -1017,6 +1043,13 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) + if (opts & OCFS2_MOUNT_INODE64) + seq_printf(s, ",inode64"); + ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ if (opts & OCFS2_MOUNT_POSIX_ACL) ++ seq_printf(s, ",acl"); ++ else ++ seq_printf(s, ",noacl"); ++#endif ++ + return 0; + } + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_acl_chmod.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_acl_chmod.patch new file mode 100644 index 000000000..de90d36f6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_acl_chmod.patch @@ -0,0 +1,93 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:17:29 +0800 +Subject: ocfs2: add ocfs2_acl_chmod +Patch-mainline: 2.6.29 + +This function is used to update acl xattrs during file mode changes. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/acl.c | 27 +++++++++++++++++++++++++++ + fs/ocfs2/acl.h | 5 +++++ + fs/ocfs2/file.c | 6 ++++++ + 3 files changed, 38 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c +index a6a2bf6..df72256 100644 +--- a/fs/ocfs2/acl.c ++++ b/fs/ocfs2/acl.c +@@ -245,6 +245,33 @@ int ocfs2_check_acl(struct inode *inode, int mask) + return -EAGAIN; + } + ++int ocfs2_acl_chmod(struct inode *inode) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct posix_acl *acl, *clone; ++ int ret; ++ ++ if (S_ISLNK(inode->i_mode)) ++ return -EOPNOTSUPP; ++ ++ if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) ++ return 0; ++ ++ acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); ++ if (IS_ERR(acl) || !acl) ++ return PTR_ERR(acl); ++ clone = posix_acl_clone(acl, GFP_KERNEL); ++ posix_acl_release(acl); ++ if (!clone) ++ return -ENOMEM; ++ ret = posix_acl_chmod_masq(clone, inode->i_mode); ++ if (!ret) ++ ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS, ++ clone, NULL, NULL); ++ posix_acl_release(clone); ++ return ret; ++} ++ + static size_t ocfs2_xattr_list_acl_access(struct inode *inode, + char *list, + size_t list_len, +diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h +index fef10f1..68ffd64 100644 +--- a/fs/ocfs2/acl.h ++++ b/fs/ocfs2/acl.h +@@ -29,10 +29,15 @@ struct ocfs2_acl_entry { + #ifdef CONFIG_OCFS2_FS_POSIX_ACL + + extern int ocfs2_check_acl(struct inode *, int); ++extern int ocfs2_acl_chmod(struct inode *); + + #else /* CONFIG_OCFS2_FS_POSIX_ACL*/ + + #define ocfs2_check_acl NULL ++static inline int ocfs2_acl_chmod(struct inode *inode) ++{ ++ return 0; ++} + + #endif /* CONFIG_OCFS2_FS_POSIX_ACL*/ + +diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c +index 7bad7d9..4636aa6 100644 +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -990,6 +990,12 @@ bail_unlock_rw: + bail: + brelse(bh); + ++ if (!status && attr->ia_valid & ATTR_MODE) { ++ status = ocfs2_acl_chmod(inode); ++ if (status < 0) ++ mlog_errno(status); ++ } ++ + mlog_exit(status); + return status; + } +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_check_acl.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_check_acl.patch new file mode 100644 index 000000000..658bc20a2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_check_acl.patch @@ -0,0 +1,84 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:17:18 +0800 +Subject: ocfs2: add ocfs2_check_acl +Patch-mainline: 2.6.29 + +This function is used to enhance permission checking with POSIX ACLs. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/acl.c | 15 +++++++++++++++ + fs/ocfs2/acl.h | 10 ++++++++++ + fs/ocfs2/file.c | 3 ++- + 3 files changed, 27 insertions(+), 1 deletions(-) + +diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c +index 62d0faa..a6a2bf6 100644 +--- a/fs/ocfs2/acl.c ++++ b/fs/ocfs2/acl.c +@@ -230,6 +230,21 @@ static int ocfs2_set_acl(handle_t *handle, + return ret; + } + ++int ocfs2_check_acl(struct inode *inode, int mask) ++{ ++ struct posix_acl *acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); ++ ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ if (acl) { ++ int ret = posix_acl_permission(inode, acl, mask); ++ posix_acl_release(acl); ++ return ret; ++ } ++ ++ return -EAGAIN; ++} ++ + static size_t ocfs2_xattr_list_acl_access(struct inode *inode, + char *list, + size_t list_len, +diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h +index 1b39f3e..fef10f1 100644 +--- a/fs/ocfs2/acl.h ++++ b/fs/ocfs2/acl.h +@@ -26,4 +26,14 @@ struct ocfs2_acl_entry { + __le32 e_id; + }; + ++#ifdef CONFIG_OCFS2_FS_POSIX_ACL ++ ++extern int ocfs2_check_acl(struct inode *, int); ++ ++#else /* CONFIG_OCFS2_FS_POSIX_ACL*/ ++ ++#define ocfs2_check_acl NULL ++ ++#endif /* CONFIG_OCFS2_FS_POSIX_ACL*/ ++ + #endif /* OCFS2_ACL_H */ +diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c +index 3605491..7bad7d9 100644 +--- a/fs/ocfs2/file.c ++++ b/fs/ocfs2/file.c +@@ -56,6 +56,7 @@ + #include "suballoc.h" + #include "super.h" + #include "xattr.h" ++#include "acl.h" + + #include "buffer_head_io.h" + +@@ -1035,7 +1036,7 @@ int ocfs2_permission(struct inode *inode, int mask) + goto out; + } + +- ret = generic_permission(inode, mask, NULL); ++ ret = generic_permission(inode, mask, ocfs2_check_acl); + + ocfs2_inode_unlock(inode, 0); + out: +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_init_acl-in-mknod.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_init_acl-in-mknod.patch new file mode 100644 index 000000000..430506595 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_init_acl-in-mknod.patch @@ -0,0 +1,281 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:17:41 +0800 +Subject: ocfs2: add ocfs2_init_acl in mknod +Patch-mainline: 2.6.29 + +We need to get the parent directories acls and let the new child inherit it. +To this, we add additional calculations for data/metadata allocation. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/acl.c | 59 ++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/acl.h | 14 +++++++++ + fs/ocfs2/namei.c | 23 ++++++++++----- + fs/ocfs2/xattr.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/xattr.h | 3 ++ + 5 files changed, 170 insertions(+), 8 deletions(-) + +diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c +index df72256..12dfb44 100644 +--- a/fs/ocfs2/acl.c ++++ b/fs/ocfs2/acl.c +@@ -272,6 +272,65 @@ int ocfs2_acl_chmod(struct inode *inode) + return ret; + } + ++/* ++ * Initialize the ACLs of a new inode. If parent directory has default ACL, ++ * then clone to new inode. Called from ocfs2_mknod. ++ */ ++int ocfs2_init_acl(handle_t *handle, ++ struct inode *inode, ++ struct inode *dir, ++ struct buffer_head *di_bh, ++ struct buffer_head *dir_bh, ++ struct ocfs2_alloc_context *meta_ac, ++ struct ocfs2_alloc_context *data_ac) ++{ ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct posix_acl *acl = NULL; ++ int ret = 0; ++ ++ if (!S_ISLNK(inode->i_mode)) { ++ if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { ++ acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, ++ dir_bh); ++ if (IS_ERR(acl)) ++ return PTR_ERR(acl); ++ } ++ if (!acl) ++ inode->i_mode &= ~current->fs->umask; ++ } ++ if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) { ++ struct posix_acl *clone; ++ mode_t mode; ++ ++ if (S_ISDIR(inode->i_mode)) { ++ ret = ocfs2_set_acl(handle, inode, di_bh, ++ ACL_TYPE_DEFAULT, acl, ++ meta_ac, data_ac); ++ if (ret) ++ goto cleanup; ++ } ++ clone = posix_acl_clone(acl, GFP_NOFS); ++ ret = -ENOMEM; ++ if (!clone) ++ goto cleanup; ++ ++ mode = inode->i_mode; ++ ret = posix_acl_create_masq(clone, &mode); ++ if (ret >= 0) { ++ inode->i_mode = mode; ++ if (ret > 0) { ++ ret = ocfs2_set_acl(handle, inode, ++ di_bh, ACL_TYPE_ACCESS, ++ clone, meta_ac, data_ac); ++ } ++ } ++ posix_acl_release(clone); ++ } ++cleanup: ++ posix_acl_release(acl); ++ return ret; ++} ++ + static size_t ocfs2_xattr_list_acl_access(struct inode *inode, + char *list, + size_t list_len, +diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h +index 68ffd64..8f6389e 100644 +--- a/fs/ocfs2/acl.h ++++ b/fs/ocfs2/acl.h +@@ -30,6 +30,10 @@ struct ocfs2_acl_entry { + + extern int ocfs2_check_acl(struct inode *, int); + extern int ocfs2_acl_chmod(struct inode *); ++extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, ++ struct buffer_head *, struct buffer_head *, ++ struct ocfs2_alloc_context *, ++ struct ocfs2_alloc_context *); + + #else /* CONFIG_OCFS2_FS_POSIX_ACL*/ + +@@ -38,6 +42,16 @@ static inline int ocfs2_acl_chmod(struct inode *inode) + { + return 0; + } ++static inline int ocfs2_init_acl(handle_t *handle, ++ struct inode *inode, ++ struct inode *dir, ++ struct buffer_head *di_bh, ++ struct buffer_head *dir_bh, ++ struct ocfs2_alloc_context *meta_ac, ++ struct ocfs2_alloc_context *data_ac) ++{ ++ return 0; ++} + + #endif /* CONFIG_OCFS2_FS_POSIX_ACL*/ + +diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c +index 40da46b..7655145 100644 +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -61,6 +61,7 @@ + #include "sysfile.h" + #include "uptodate.h" + #include "xattr.h" ++#include "acl.h" + + #include "buffer_head_io.h" + +@@ -302,14 +303,13 @@ static int ocfs2_mknod(struct inode *dir, + } + } + +- /* calculate meta data/clusters for setting security xattr */ +- if (si.enable) { +- status = ocfs2_calc_security_init(dir, &si, &want_clusters, +- &xattr_credits, &xattr_ac); +- if (status < 0) { +- mlog_errno(status); +- goto leave; +- } ++ /* calculate meta data/clusters for setting security and acl xattr */ ++ status = ocfs2_calc_xattr_init(dir, parent_fe_bh, mode, ++ &si, &want_clusters, ++ &xattr_credits, &xattr_ac); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; + } + + /* Reserve a cluster if creating an extent based directory. */ +@@ -363,6 +363,13 @@ static int ocfs2_mknod(struct inode *dir, + inc_nlink(dir); + } + ++ status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh, ++ xattr_ac, data_ac); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ + if (si.enable) { + status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, + xattr_ac, data_ac); +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 2e273c2..3cc8385 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -84,6 +84,10 @@ struct ocfs2_xattr_set_ctxt { + #define OCFS2_XATTR_FREE_IN_IBODY (OCFS2_MIN_XATTR_INLINE_SIZE \ + - sizeof(struct ocfs2_xattr_header) \ + - sizeof(__u32)) ++#define OCFS2_XATTR_FREE_IN_BLOCK(ptr) ((ptr)->i_sb->s_blocksize \ ++ - sizeof(struct ocfs2_xattr_block) \ ++ - sizeof(struct ocfs2_xattr_header) \ ++ - sizeof(__u32)) + + static struct ocfs2_xattr_def_value_root def_xv = { + .xv.xr_list.l_count = cpu_to_le16(1), +@@ -402,6 +406,81 @@ int ocfs2_calc_security_init(struct inode *dir, + return ret; + } + ++int ocfs2_calc_xattr_init(struct inode *dir, ++ struct buffer_head *dir_bh, ++ int mode, ++ struct ocfs2_security_xattr_info *si, ++ int *want_clusters, ++ int *xattr_credits, ++ struct ocfs2_alloc_context **xattr_ac) ++{ ++ int ret = 0; ++ struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); ++ int s_size = 0; ++ int a_size = 0; ++ int acl_len = 0; ++ ++ if (si->enable) ++ s_size = ocfs2_xattr_entry_real_size(strlen(si->name), ++ si->value_len); ++ ++ if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { ++ acl_len = ocfs2_xattr_get_nolock(dir, dir_bh, ++ OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT, ++ "", NULL, 0); ++ if (acl_len > 0) { ++ a_size = ocfs2_xattr_entry_real_size(0, acl_len); ++ if (S_ISDIR(mode)) ++ a_size <<= 1; ++ } else if (acl_len != 0 && acl_len != -ENODATA) { ++ mlog_errno(ret); ++ return ret; ++ } ++ } ++ ++ if (!(s_size + a_size)) ++ return ret; ++ ++ /* ++ * The max space of security xattr taken inline is ++ * 256(name) + 80(value) + 16(entry) = 352 bytes, ++ * The max space of acl xattr taken inline is ++ * 80(value) + 16(entry) * 2(if directory) = 192 bytes, ++ * when blocksize = 512, may reserve one more cluser for ++ * xattr bucket, otherwise reserve one metadata block ++ * for them is ok. ++ */ ++ if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE || ++ (s_size + a_size) > OCFS2_XATTR_FREE_IN_IBODY) { ++ ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ *xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS; ++ } ++ ++ if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE && ++ (s_size + a_size) > OCFS2_XATTR_FREE_IN_BLOCK(dir)) { ++ *want_clusters += 1; ++ *xattr_credits += ocfs2_blocks_per_xattr_bucket(dir->i_sb); ++ } ++ ++ /* reserve clusters for xattr value which will be set in B tree*/ ++ if (si->enable && si->value_len > OCFS2_XATTR_INLINE_SIZE) ++ *want_clusters += ocfs2_clusters_for_bytes(dir->i_sb, ++ si->value_len); ++ if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL && ++ acl_len > OCFS2_XATTR_INLINE_SIZE) { ++ *want_clusters += ocfs2_clusters_for_bytes(dir->i_sb, acl_len); ++ if (S_ISDIR(mode)) ++ *want_clusters += ocfs2_clusters_for_bytes(dir->i_sb, ++ acl_len); ++ } ++ ++ return ret; ++} ++ + static int ocfs2_xattr_extend_allocation(struct inode *inode, + u32 clusters_to_add, + struct buffer_head *xattr_bh, +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index 6163df3..9a67e7d 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -66,5 +66,8 @@ int ocfs2_init_security_set(handle_t *, struct inode *, + int ocfs2_calc_security_init(struct inode *, + struct ocfs2_security_xattr_info *, + int *, int *, struct ocfs2_alloc_context **); ++int ocfs2_calc_xattr_init(struct inode *, struct buffer_head *, ++ int, struct ocfs2_security_xattr_info *, ++ int *, int *, struct ocfs2_alloc_context **); + + #endif /* OCFS2_XATTR_H */ +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_init_security-in-during-file-create.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_init_security-in-during-file-create.patch new file mode 100644 index 000000000..75265fdf6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_init_security-in-during-file-create.patch @@ -0,0 +1,344 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:16:41 +0800 +Subject: ocfs2: add ocfs2_init_security in during file create +Patch-mainline: 2.6.29 + +Security attributes must be set when creating a new inode. + +We do this in three steps. + +- First, get security xattr's name and value by security_operation + +- Calculate and reserve the meta data and clusters needed by this security + xattr before starting transaction + +- Finally, we set it before add_entry + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/namei.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++------ + fs/ocfs2/xattr.c | 70 +++++++++++++++++++++++++++++++++++ + fs/ocfs2/xattr.h | 17 +++++++++ + 3 files changed, 182 insertions(+), 12 deletions(-) + +diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c +index e8ff0ba..40da46b 100644 +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -229,6 +229,12 @@ static int ocfs2_mknod(struct inode *dir, + struct inode *inode = NULL; + struct ocfs2_alloc_context *inode_ac = NULL; + struct ocfs2_alloc_context *data_ac = NULL; ++ struct ocfs2_alloc_context *xattr_ac = NULL; ++ int want_clusters = 0; ++ int xattr_credits = 0; ++ struct ocfs2_security_xattr_info si = { ++ .enable = 1, ++ }; + + mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, + (unsigned long)dev, dentry->d_name.len, +@@ -285,17 +291,39 @@ static int ocfs2_mknod(struct inode *dir, + goto leave; + } + +- /* Reserve a cluster if creating an extent based directory. */ +- if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { +- status = ocfs2_reserve_clusters(osb, 1, &data_ac); ++ /* get security xattr */ ++ status = ocfs2_init_security_get(inode, dir, &si); ++ if (status) { ++ if (status == -EOPNOTSUPP) ++ si.enable = 0; ++ else { ++ mlog_errno(status); ++ goto leave; ++ } ++ } ++ ++ /* calculate meta data/clusters for setting security xattr */ ++ if (si.enable) { ++ status = ocfs2_calc_security_init(dir, &si, &want_clusters, ++ &xattr_credits, &xattr_ac); + if (status < 0) { +- if (status != -ENOSPC) +- mlog_errno(status); ++ mlog_errno(status); + goto leave; + } + } + +- handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS); ++ /* Reserve a cluster if creating an extent based directory. */ ++ if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) ++ want_clusters += 1; ++ ++ status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); ++ if (status < 0) { ++ if (status != -ENOSPC) ++ mlog_errno(status); ++ goto leave; ++ } ++ ++ handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS + xattr_credits); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + handle = NULL; +@@ -335,6 +363,15 @@ static int ocfs2_mknod(struct inode *dir, + inc_nlink(dir); + } + ++ if (si.enable) { ++ status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, ++ xattr_ac, data_ac); ++ if (status < 0) { ++ mlog_errno(status); ++ goto leave; ++ } ++ } ++ + status = ocfs2_add_entry(handle, dentry, inode, + OCFS2_I(inode)->ip_blkno, parent_fe_bh, + de_bh); +@@ -366,6 +403,8 @@ leave: + brelse(new_fe_bh); + brelse(de_bh); + brelse(parent_fe_bh); ++ kfree(si.name); ++ kfree(si.value); + + if ((status < 0) && inode) { + clear_nlink(inode); +@@ -378,6 +417,9 @@ leave: + if (data_ac) + ocfs2_free_alloc_context(data_ac); + ++ if (xattr_ac) ++ ocfs2_free_alloc_context(xattr_ac); ++ + mlog_exit(status); + + return status; +@@ -1508,6 +1550,12 @@ static int ocfs2_symlink(struct inode *dir, + handle_t *handle = NULL; + struct ocfs2_alloc_context *inode_ac = NULL; + struct ocfs2_alloc_context *data_ac = NULL; ++ struct ocfs2_alloc_context *xattr_ac = NULL; ++ int want_clusters = 0; ++ int xattr_credits = 0; ++ struct ocfs2_security_xattr_info si = { ++ .enable = 1, ++ }; + + mlog_entry("(0x%p, 0x%p, symname='%s' actual='%.*s')\n", dir, + dentry, symname, dentry->d_name.len, dentry->d_name.name); +@@ -1561,17 +1609,39 @@ static int ocfs2_symlink(struct inode *dir, + goto bail; + } + +- /* don't reserve bitmap space for fast symlinks. */ +- if (l > ocfs2_fast_symlink_chars(sb)) { +- status = ocfs2_reserve_clusters(osb, 1, &data_ac); ++ /* get security xattr */ ++ status = ocfs2_init_security_get(inode, dir, &si); ++ if (status) { ++ if (status == -EOPNOTSUPP) ++ si.enable = 0; ++ else { ++ mlog_errno(status); ++ goto bail; ++ } ++ } ++ ++ /* calculate meta data/clusters for setting security xattr */ ++ if (si.enable) { ++ status = ocfs2_calc_security_init(dir, &si, &want_clusters, ++ &xattr_credits, &xattr_ac); + if (status < 0) { +- if (status != -ENOSPC) +- mlog_errno(status); ++ mlog_errno(status); + goto bail; + } + } + +- handle = ocfs2_start_trans(osb, credits); ++ /* don't reserve bitmap space for fast symlinks. */ ++ if (l > ocfs2_fast_symlink_chars(sb)) ++ want_clusters += 1; ++ ++ status = ocfs2_reserve_clusters(osb, want_clusters, &data_ac); ++ if (status < 0) { ++ if (status != -ENOSPC) ++ mlog_errno(status); ++ goto bail; ++ } ++ ++ handle = ocfs2_start_trans(osb, credits + xattr_credits); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + handle = NULL; +@@ -1632,6 +1702,15 @@ static int ocfs2_symlink(struct inode *dir, + } + } + ++ if (si.enable) { ++ status = ocfs2_init_security_set(handle, inode, new_fe_bh, &si, ++ xattr_ac, data_ac); ++ if (status < 0) { ++ mlog_errno(status); ++ goto bail; ++ } ++ } ++ + status = ocfs2_add_entry(handle, dentry, inode, + le64_to_cpu(fe->i_blkno), parent_fe_bh, + de_bh); +@@ -1658,10 +1737,14 @@ bail: + brelse(new_fe_bh); + brelse(parent_fe_bh); + brelse(de_bh); ++ kfree(si.name); ++ kfree(si.value); + if (inode_ac) + ocfs2_free_alloc_context(inode_ac); + if (data_ac) + ocfs2_free_alloc_context(data_ac); ++ if (xattr_ac) ++ ocfs2_free_alloc_context(xattr_ac); + if ((status < 0) && inode) { + clear_nlink(inode); + iput(inode); +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index db03162..2cab0d6 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -81,6 +81,9 @@ struct ocfs2_xattr_set_ctxt { + + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) + #define OCFS2_XATTR_INLINE_SIZE 80 ++#define OCFS2_XATTR_FREE_IN_IBODY (OCFS2_MIN_XATTR_INLINE_SIZE \ ++ - sizeof(struct ocfs2_xattr_header) \ ++ - sizeof(__u32)) + + static struct ocfs2_xattr_def_value_root def_xv = { + .xv.xr_list.l_count = cpu_to_le16(1), +@@ -343,6 +346,52 @@ static void ocfs2_xattr_hash_entry(struct inode *inode, + return; + } + ++static int ocfs2_xattr_entry_real_size(int name_len, size_t value_len) ++{ ++ int size = 0; ++ ++ if (value_len <= OCFS2_XATTR_INLINE_SIZE) ++ size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len); ++ else ++ size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; ++ size += sizeof(struct ocfs2_xattr_entry); ++ ++ return size; ++} ++ ++int ocfs2_calc_security_init(struct inode *dir, ++ struct ocfs2_security_xattr_info *si, ++ int *want_clusters, ++ int *xattr_credits, ++ struct ocfs2_alloc_context **xattr_ac) ++{ ++ int ret = 0; ++ struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); ++ int s_size = ocfs2_xattr_entry_real_size(strlen(si->name), ++ si->value_len); ++ ++ /* ++ * The max space of security xattr taken inline is ++ * 256(name) + 80(value) + 16(entry) = 352 bytes, ++ * So reserve one metadata block for it is ok. ++ */ ++ if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE || ++ s_size > OCFS2_XATTR_FREE_IN_IBODY) { ++ ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ *xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS; ++ } ++ ++ /* reserve clusters for xattr value which will be set in B tree*/ ++ if (si->value_len > OCFS2_XATTR_INLINE_SIZE) ++ *want_clusters += ocfs2_clusters_for_bytes(dir->i_sb, ++ si->value_len); ++ return ret; ++} ++ + static int ocfs2_xattr_extend_allocation(struct inode *inode, + u32 clusters_to_add, + struct buffer_head *xattr_bh, +@@ -5016,6 +5065,27 @@ static int ocfs2_xattr_security_set(struct inode *inode, const char *name, + size, flags); + } + ++int ocfs2_init_security_get(struct inode *inode, ++ struct inode *dir, ++ struct ocfs2_security_xattr_info *si) ++{ ++ return security_inode_init_security(inode, dir, &si->name, &si->value, ++ &si->value_len); ++} ++ ++int ocfs2_init_security_set(handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *di_bh, ++ struct ocfs2_security_xattr_info *si, ++ struct ocfs2_alloc_context *xattr_ac, ++ struct ocfs2_alloc_context *data_ac) ++{ ++ return ocfs2_xattr_set_handle(handle, inode, di_bh, ++ OCFS2_XATTR_INDEX_SECURITY, ++ si->name, si->value, si->value_len, 0, ++ xattr_ac, data_ac); ++} ++ + struct xattr_handler ocfs2_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = ocfs2_xattr_security_list, +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index 55c5256..188ef6b 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -30,6 +30,13 @@ enum ocfs2_xattr_type { + OCFS2_XATTR_MAX + }; + ++struct ocfs2_security_xattr_info { ++ int enable; ++ char *name; ++ void *value; ++ size_t value_len; ++}; ++ + extern struct xattr_handler ocfs2_xattr_user_handler; + extern struct xattr_handler ocfs2_xattr_trusted_handler; + extern struct xattr_handler ocfs2_xattr_security_handler; +@@ -43,5 +50,15 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, + struct ocfs2_alloc_context *, + struct ocfs2_alloc_context *); + int ocfs2_xattr_remove(struct inode *, struct buffer_head *); ++int ocfs2_init_security_get(struct inode *, struct inode *, ++ struct ocfs2_security_xattr_info *); ++int ocfs2_init_security_set(handle_t *, struct inode *, ++ struct buffer_head *, ++ struct ocfs2_security_xattr_info *, ++ struct ocfs2_alloc_context *, ++ struct ocfs2_alloc_context *); ++int ocfs2_calc_security_init(struct inode *, ++ struct ocfs2_security_xattr_info *, ++ int *, int *, struct ocfs2_alloc_context **); + + #endif /* OCFS2_XATTR_H */ +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_xattr_get_nolock.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_xattr_get_nolock.patch new file mode 100644 index 000000000..e8e647c8c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_xattr_get_nolock.patch @@ -0,0 +1,102 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:16:53 +0800 +Subject: ocfs2: add ocfs2_xattr_get_nolock +Patch-mainline: 2.6.29 + +This function does the work of ocfs2_xattr_get under an open lock. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 40 ++++++++++++++++++++++++++++------------ + fs/ocfs2/xattr.h | 2 ++ + 2 files changed, 30 insertions(+), 12 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 2cab0d6..ba9b870 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -925,12 +925,8 @@ cleanup: + return ret; + } + +-/* ocfs2_xattr_get() +- * +- * Copy an extended attribute into the buffer provided. +- * Buffer is NULL to compute the size of buffer required. +- */ +-static int ocfs2_xattr_get(struct inode *inode, ++int ocfs2_xattr_get_nolock(struct inode *inode, ++ struct buffer_head *di_bh, + int name_index, + const char *name, + void *buffer, +@@ -938,7 +934,6 @@ static int ocfs2_xattr_get(struct inode *inode, + { + int ret; + struct ocfs2_dinode *di = NULL; +- struct buffer_head *di_bh = NULL; + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_xattr_search xis = { + .not_found = -ENODATA, +@@ -953,11 +948,6 @@ static int ocfs2_xattr_get(struct inode *inode, + if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) + ret = -ENODATA; + +- ret = ocfs2_inode_lock(inode, &di_bh, 0); +- if (ret < 0) { +- mlog_errno(ret); +- return ret; +- } + xis.inode_bh = xbs.inode_bh = di_bh; + di = (struct ocfs2_dinode *)di_bh->b_data; + +@@ -968,6 +958,32 @@ static int ocfs2_xattr_get(struct inode *inode, + ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, + buffer_size, &xbs); + up_read(&oi->ip_xattr_sem); ++ ++ return ret; ++} ++ ++/* ocfs2_xattr_get() ++ * ++ * Copy an extended attribute into the buffer provided. ++ * Buffer is NULL to compute the size of buffer required. ++ */ ++static int ocfs2_xattr_get(struct inode *inode, ++ int name_index, ++ const char *name, ++ void *buffer, ++ size_t buffer_size) ++{ ++ int ret; ++ struct buffer_head *di_bh = NULL; ++ ++ ret = ocfs2_inode_lock(inode, &di_bh, 0); ++ if (ret < 0) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index, ++ name, buffer, buffer_size); ++ + ocfs2_inode_unlock(inode, 0); + + brelse(di_bh); +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index 188ef6b..86aa10f 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -43,6 +43,8 @@ extern struct xattr_handler ocfs2_xattr_security_handler; + extern struct xattr_handler *ocfs2_xattr_handlers[]; + + ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); ++int ocfs2_xattr_get_nolock(struct inode *, struct buffer_head *, int, ++ const char *, void *, size_t); + int ocfs2_xattr_set(struct inode *, int, const char *, const void *, + size_t, int); + int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_xattr_set_handle.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_xattr_set_handle.patch new file mode 100644 index 000000000..7baefc9b7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-ocfs2_xattr_set_handle.patch @@ -0,0 +1,114 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:16:03 +0800 +Subject: ocfs2: add ocfs2_xattr_set_handle +Patch-mainline: 2.6.29 + +This function is used to set xattr's in a started transaction. It is only +called during inode creation inode for initial security/acl xattrs of the +new inode. These xattrs could be put into ibody or extent block, so xattr +bucket would not be use in this case. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/xattr.h | 4 +++ + 2 files changed, 72 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 7a90892..6480254 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -2326,6 +2326,74 @@ out: + } + + /* ++ * This function only called duing creating inode ++ * for init security/acl xattrs of the new inode. ++ * The xattrs could be put into ibody or extent block, ++ * xattr bucket would not be use in this case. ++ * transanction credits also be reserved in here. ++ */ ++int ocfs2_xattr_set_handle(handle_t *handle, ++ struct inode *inode, ++ struct buffer_head *di_bh, ++ int name_index, ++ const char *name, ++ const void *value, ++ size_t value_len, ++ int flags, ++ struct ocfs2_alloc_context *meta_ac, ++ struct ocfs2_alloc_context *data_ac) ++{ ++ struct ocfs2_dinode *di; ++ int ret; ++ ++ struct ocfs2_xattr_info xi = { ++ .name_index = name_index, ++ .name = name, ++ .value = value, ++ .value_len = value_len, ++ }; ++ ++ struct ocfs2_xattr_search xis = { ++ .not_found = -ENODATA, ++ }; ++ ++ struct ocfs2_xattr_search xbs = { ++ .not_found = -ENODATA, ++ }; ++ ++ struct ocfs2_xattr_set_ctxt ctxt = { ++ .handle = handle, ++ .meta_ac = meta_ac, ++ .data_ac = data_ac, ++ }; ++ ++ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb))) ++ return -EOPNOTSUPP; ++ ++ xis.inode_bh = xbs.inode_bh = di_bh; ++ di = (struct ocfs2_dinode *)di_bh->b_data; ++ ++ down_write(&OCFS2_I(inode)->ip_xattr_sem); ++ ++ ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis); ++ if (ret) ++ goto cleanup; ++ if (xis.not_found) { ++ ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs); ++ if (ret) ++ goto cleanup; ++ } ++ ++ ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt); ++ ++cleanup: ++ up_write(&OCFS2_I(inode)->ip_xattr_sem); ++ brelse(xbs.xattr_bh); ++ ++ return ret; ++} ++ ++/* + * ocfs2_xattr_set() + * + * Set, replace or remove an extended attribute for this inode. +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index 1d8314c..8fbdc16 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -37,6 +37,10 @@ extern struct xattr_handler *ocfs2_xattr_handlers[]; + ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); + int ocfs2_xattr_set(struct inode *, int, const char *, const void *, + size_t, int); ++int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, ++ int, const char *, const void *, size_t, int, ++ struct ocfs2_alloc_context *, ++ struct ocfs2_alloc_context *); + int ocfs2_xattr_remove(struct inode *, struct buffer_head *); + + #endif /* OCFS2_XATTR_H */ +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-security-xattr-API.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-security-xattr-API.patch new file mode 100644 index 000000000..a056804c3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-add-security-xattr-API.patch @@ -0,0 +1,108 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:16:27 +0800 +Subject: ocfs2: add security xattr API +Patch-mainline: 2.6.29 + +This patch add security xattr set/get/list APIs to +support security attributes in Ocfs2. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/xattr.h | 1 + + 2 files changed, 48 insertions(+), 0 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 6480254..db03162 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_XATTR + #include +@@ -88,12 +89,14 @@ static struct ocfs2_xattr_def_value_root def_xv = { + struct xattr_handler *ocfs2_xattr_handlers[] = { + &ocfs2_xattr_user_handler, + &ocfs2_xattr_trusted_handler, ++ &ocfs2_xattr_security_handler, + NULL + }; + + static struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = { + [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler, + [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler, ++ [OCFS2_XATTR_INDEX_SECURITY] = &ocfs2_xattr_security_handler, + }; + + struct ocfs2_xattr_info { +@@ -4977,6 +4980,50 @@ out: + } + + /* ++ * 'security' attributes support ++ */ ++static size_t ocfs2_xattr_security_list(struct inode *inode, char *list, ++ size_t list_size, const char *name, ++ size_t name_len) ++{ ++ const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN; ++ const size_t total_len = prefix_len + name_len + 1; ++ ++ if (list && total_len <= list_size) { ++ memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); ++ memcpy(list + prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return total_len; ++} ++ ++static int ocfs2_xattr_security_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_SECURITY, name, ++ buffer, size); ++} ++ ++static int ocfs2_xattr_security_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ ++ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY, name, value, ++ size, flags); ++} ++ ++struct xattr_handler ocfs2_xattr_security_handler = { ++ .prefix = XATTR_SECURITY_PREFIX, ++ .list = ocfs2_xattr_security_list, ++ .get = ocfs2_xattr_security_get, ++ .set = ocfs2_xattr_security_set, ++}; ++ ++/* + * 'trusted' attributes support + */ + static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list, +diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h +index 8fbdc16..55c5256 100644 +--- a/fs/ocfs2/xattr.h ++++ b/fs/ocfs2/xattr.h +@@ -32,6 +32,7 @@ enum ocfs2_xattr_type { + + extern struct xattr_handler ocfs2_xattr_user_handler; + extern struct xattr_handler ocfs2_xattr_trusted_handler; ++extern struct xattr_handler ocfs2_xattr_security_handler; + extern struct xattr_handler *ocfs2_xattr_handlers[]; + + ssize_t ocfs2_listxattr(struct dentry *, char *, size_t); +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-bug-fix-for-journal-extend-in-xattr.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-bug-fix-for-journal-extend-in-xattr.patch new file mode 100644 index 000000000..cba0a8be8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-bug-fix-for-journal-extend-in-xattr.patch @@ -0,0 +1,55 @@ +From: Tao Ma +Subject: [PATCH] ocfs2: bug-fix for journal extend in xattr. +Patch-mainline: 2.6.28? +References: FATE302067 + +In ocfs2_extend_trans, when we can't extend the current +transaction, it will commit current transaction and restart +a new one. So if the previous credits we have allocated aren't +used(the block isn't dirtied before our extend), we will not +have enough credits for any future operation(it will cause jbd +complain and bug out). So check this and re-extend it. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 15 ++++++++++++++- + 1 files changed, 14 insertions(+), 1 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 2ccffb1..ed50f9a 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -1352,8 +1352,9 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + } + + if (!(flag & OCFS2_INLINE_XATTR_FL)) { +- /*set extended attribue in external blcok*/ ++ /* set extended attribute in external block. */ + ret = ocfs2_extend_trans(handle, ++ OCFS2_INODE_UPDATE_CREDITS + + OCFS2_XATTR_BLOCK_UPDATE_CREDITS); + if (ret) { + mlog_errno(ret); +@@ -3717,6 +3718,18 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + } + } + ++ if (handle->h_buffer_credits < credits) { ++ /* ++ * The journal has been restarted before, and don't ++ * have enough space for the insertion, so extend it ++ * here. ++ */ ++ ret = ocfs2_extend_trans(handle, credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto leave; ++ } ++ } + mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", + num_bits, block, v_start); + ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-fix-build-error.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-fix-build-error.patch new file mode 100644 index 000000000..eba239941 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-fix-build-error.patch @@ -0,0 +1,72 @@ +From: Mark Fasheh +Subject: ocfs2: fix build error +Patch-mainline: 2.6.28 + +I merged the latest ocfs2_read_blocks() changes in xattr.c wrong. This makes +Ocfs2 compile again. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 14 ++++++-------- + 1 files changed, 6 insertions(+), 8 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -2365,7 +2365,7 @@ static int ocfs2_xattr_bucket_find(struc + */ + ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1, + blk_per_bucket - 1, &xs->bucket.bhs[1], +- OCFS2_BH_CACHED); ++ 0); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2442,7 +2442,7 @@ static int ocfs2_iterate_xattr_buckets(s + + for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) { + ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, +- bucket.bhs, OCFS2_BH_CACHED); ++ bucket.bhs, 0); + if (ret) { + mlog_errno(ret); + goto out; +@@ -2710,7 +2710,7 @@ static int ocfs2_xattr_update_xattr_sear + ret = ocfs2_read_blocks(inode, + xs->bucket.bhs[0]->b_blocknr + 1, + blk_per_bucket - 1, &xs->bucket.bhs[1], +- OCFS2_BH_CACHED); ++ 0); + if (ret) { + mlog_errno(ret); + return ret; +@@ -2914,8 +2914,7 @@ static int ocfs2_defrag_xattr_bucket(str + if (!bhs) + return -ENOMEM; + +- ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, +- OCFS2_BH_CACHED); ++ ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, 0); + if (ret) + goto out; + +@@ -3169,8 +3168,7 @@ static int ocfs2_read_xattr_bucket(struc + + if (!new) + return ocfs2_read_blocks(inode, blkno, +- blk_per_bucket, bhs, +- OCFS2_BH_CACHED); ++ blk_per_bucket, bhs, 0); + + for (i = 0; i < blk_per_bucket; i++) { + bhs[i] = sb_getblk(inode->i_sb, blkno + i); +@@ -4117,7 +4115,7 @@ static int ocfs2_xattr_set_entry_in_buck + ret = ocfs2_read_blocks(inode, + xs->bucket.bhs[0]->b_blocknr + 1, + blk_per_bucket - 1, &xs->bucket.bhs[1], +- OCFS2_BH_CACHED); ++ 0); + if (ret) { + mlog_errno(ret); + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-fix-printk-format-warnings.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-fix-printk-format-warnings.patch new file mode 100644 index 000000000..1b2546a84 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-fix-printk-format-warnings.patch @@ -0,0 +1,52 @@ +From: Mark Fasheh +Subject: ocfs2: fix printk format warnings +Patch-mainline: 2.6.28? +References: FATE302067 + +This patch fixes the following build warnings: + +fs/ocfs2/xattr.c: In function 'ocfs2_half_xattr_bucket': +fs/ocfs2/xattr.c:3282: warning: format '%d' expects type 'int', but argument 7 has type 'long int' +fs/ocfs2/xattr.c:3282: warning: format '%d' expects type 'int', but argument 8 has type 'long int' +fs/ocfs2/xattr.c:3282: warning: format '%d' expects type 'int', but argument 7 has type 'long int' +fs/ocfs2/xattr.c:3282: warning: format '%d' expects type 'int', but argument 8 has type 'long int' +fs/ocfs2/xattr.c:3282: warning: format '%d' expects type 'int', but argument 7 has type 'long int' +fs/ocfs2/xattr.c:3282: warning: format '%d' expects type 'int', but argument 8 has type 'long int' +fs/ocfs2/xattr.c: In function 'ocfs2_xattr_set_entry_in_bucket': +fs/ocfs2/xattr.c:4092: warning: format '%d' expects type 'int', but argument 6 has type 'size_t' +fs/ocfs2/xattr.c:4092: warning: format '%d' expects type 'int', but argument 6 has type 'size_t' +fs/ocfs2/xattr.c:4092: warning: format '%d' expects type 'int', but argument 6 has type 'size_t' + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 7 ++++--- + 1 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 505fb40..6b7685e 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -3280,7 +3280,8 @@ static int ocfs2_half_xattr_bucket(struct inode *inode, + xe = &xh->xh_entries[start]; + len = sizeof(struct ocfs2_xattr_entry) * (count - start); + mlog(0, "mv xattr entry len %d from %d to %d\n", len, +- (char *)xe - (char *)xh, (char *)xh->xh_entries - (char *)xh); ++ (int)((char *)xe - (char *)xh), ++ (int)((char *)xh->xh_entries - (char *)xh)); + memmove((char *)xh->xh_entries, (char *)xe, len); + xe = &xh->xh_entries[count - start]; + len = sizeof(struct ocfs2_xattr_entry) * start; +@@ -4089,8 +4090,8 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + +- mlog(0, "Set xattr entry len = %d index = %d in bucket %llu\n", +- xi->value_len, xi->name_index, ++ mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", ++ (unsigned long)xi->value_len, xi->name_index, + (unsigned long long)xs->bucket.bhs[0]->b_blocknr); + + if (!xs->bucket.bhs[1]) { +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-make-la_debug_mutex-static.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-make-la_debug_mutex-static.patch new file mode 100644 index 000000000..1b1589227 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-make-la_debug_mutex-static.patch @@ -0,0 +1,32 @@ +From: Mark Fasheh +Subject: ocfs2: make la_debug_mutex static +Patch-mainline: 2.6.28 + +It can also be moved into ocfs2_la_debug_read(). + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/localalloc.c | 3 +-- + 1 files changed, 1 insertions(+), 2 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -76,8 +76,6 @@ static int ocfs2_local_alloc_slide_windo + + #ifdef CONFIG_OCFS2_FS_STATS + +-DEFINE_MUTEX(la_debug_mutex); +- + static int ocfs2_la_debug_open(struct inode *inode, struct file *file) + { + file->private_data = inode->i_private; +@@ -89,6 +87,7 @@ static int ocfs2_la_debug_open(struct in + static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) + { ++ static DEFINE_MUTEX(la_debug_mutex); + struct ocfs2_super *osb = file->private_data; + int written, ret; + char *buf = osb->local_alloc_debug_buf; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-move-new-inode-allocation-out-of-the-transact.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-move-new-inode-allocation-out-of-the-transact.patch new file mode 100644 index 000000000..d4a232cca --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-move-new-inode-allocation-out-of-the-transact.patch @@ -0,0 +1,255 @@ +From: Tiger Yang +Date: Fri, 14 Nov 2008 11:15:44 +0800 +Subject: ocfs2: move new inode allocation out of the transaction +Patch-mainline: 2.6.29 + +Move out inode allocation from ocfs2_mknod_locked() because +vfs_dq_init() must be called outside of a transaction. + +Signed-off-by: Jan Kara +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/namei.c | 108 ++++++++++++++++++++++++++++++++---------------------- + 1 files changed, 64 insertions(+), 44 deletions(-) + +diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c +index 2545e74..e8ff0ba 100644 +--- a/fs/ocfs2/namei.c ++++ b/fs/ocfs2/namei.c +@@ -66,12 +66,12 @@ + + static int ocfs2_mknod_locked(struct ocfs2_super *osb, + struct inode *dir, +- struct dentry *dentry, int mode, ++ struct inode *inode, ++ struct dentry *dentry, + dev_t dev, + struct buffer_head **new_fe_bh, + struct buffer_head *parent_fe_bh, + handle_t *handle, +- struct inode **ret_inode, + struct ocfs2_alloc_context *inode_ac); + + static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, +@@ -186,6 +186,34 @@ bail: + return ret; + } + ++static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode) ++{ ++ struct inode *inode; ++ ++ inode = new_inode(dir->i_sb); ++ if (!inode) { ++ mlog(ML_ERROR, "new_inode failed!\n"); ++ return NULL; ++ } ++ ++ /* populate as many fields early on as possible - many of ++ * these are used by the support functions here and in ++ * callers. */ ++ if (S_ISDIR(mode)) ++ inode->i_nlink = 2; ++ else ++ inode->i_nlink = 1; ++ inode->i_uid = current->fsuid; ++ if (dir->i_mode & S_ISGID) { ++ inode->i_gid = dir->i_gid; ++ if (S_ISDIR(mode)) ++ mode |= S_ISGID; ++ } else ++ inode->i_gid = current->fsgid; ++ inode->i_mode = mode; ++ return inode; ++} ++ + static int ocfs2_mknod(struct inode *dir, + struct dentry *dentry, + int mode, +@@ -250,6 +278,13 @@ static int ocfs2_mknod(struct inode *dir, + goto leave; + } + ++ inode = ocfs2_get_init_inode(dir, mode); ++ if (!inode) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto leave; ++ } ++ + /* Reserve a cluster if creating an extent based directory. */ + if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) { + status = ocfs2_reserve_clusters(osb, 1, &data_ac); +@@ -269,9 +304,9 @@ static int ocfs2_mknod(struct inode *dir, + } + + /* do the real work now. */ +- status = ocfs2_mknod_locked(osb, dir, dentry, mode, dev, ++ status = ocfs2_mknod_locked(osb, dir, inode, dentry, dev, + &new_fe_bh, parent_fe_bh, handle, +- &inode, inode_ac); ++ inode_ac); + if (status < 0) { + mlog_errno(status); + goto leave; +@@ -332,8 +367,10 @@ leave: + brelse(de_bh); + brelse(parent_fe_bh); + +- if ((status < 0) && inode) ++ if ((status < 0) && inode) { ++ clear_nlink(inode); + iput(inode); ++ } + + if (inode_ac) + ocfs2_free_alloc_context(inode_ac); +@@ -348,12 +385,12 @@ leave: + + static int ocfs2_mknod_locked(struct ocfs2_super *osb, + struct inode *dir, +- struct dentry *dentry, int mode, ++ struct inode *inode, ++ struct dentry *dentry, + dev_t dev, + struct buffer_head **new_fe_bh, + struct buffer_head *parent_fe_bh, + handle_t *handle, +- struct inode **ret_inode, + struct ocfs2_alloc_context *inode_ac) + { + int status = 0; +@@ -361,14 +398,12 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, + struct ocfs2_extent_list *fel; + u64 fe_blkno = 0; + u16 suballoc_bit; +- struct inode *inode = NULL; + +- mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, +- (unsigned long)dev, dentry->d_name.len, ++ mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, ++ inode->i_mode, (unsigned long)dev, dentry->d_name.len, + dentry->d_name.name); + + *new_fe_bh = NULL; +- *ret_inode = NULL; + + status = ocfs2_claim_new_inode(osb, handle, inode_ac, &suballoc_bit, + &fe_blkno); +@@ -377,23 +412,11 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, + goto leave; + } + +- inode = new_inode(dir->i_sb); +- if (!inode) { +- status = -ENOMEM; +- mlog(ML_ERROR, "new_inode failed!\n"); +- goto leave; +- } +- + /* populate as many fields early on as possible - many of + * these are used by the support functions here and in + * callers. */ + inode->i_ino = ino_from_blkno(osb->sb, fe_blkno); + OCFS2_I(inode)->ip_blkno = fe_blkno; +- if (S_ISDIR(mode)) +- inode->i_nlink = 2; +- else +- inode->i_nlink = 1; +- inode->i_mode = mode; + spin_lock(&osb->osb_lock); + inode->i_generation = osb->s_next_generation++; + spin_unlock(&osb->osb_lock); +@@ -421,17 +444,11 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, + fe->i_blkno = cpu_to_le64(fe_blkno); + fe->i_suballoc_bit = cpu_to_le16(suballoc_bit); + fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot); +- fe->i_uid = cpu_to_le32(current->fsuid); +- if (dir->i_mode & S_ISGID) { +- fe->i_gid = cpu_to_le32(dir->i_gid); +- if (S_ISDIR(mode)) +- mode |= S_ISGID; +- } else +- fe->i_gid = cpu_to_le32(current->fsgid); +- fe->i_mode = cpu_to_le16(mode); +- if (S_ISCHR(mode) || S_ISBLK(mode)) ++ fe->i_uid = cpu_to_le32(inode->i_uid); ++ fe->i_gid = cpu_to_le32(inode->i_gid); ++ fe->i_mode = cpu_to_le16(inode->i_mode); ++ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev)); +- + fe->i_links_count = cpu_to_le16(inode->i_nlink); + + fe->i_last_eb_blk = 0; +@@ -446,7 +463,7 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, + /* + * If supported, directories start with inline data. + */ +- if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) { ++ if (S_ISDIR(inode->i_mode) && ocfs2_supports_inline_data(osb)) { + u16 feat = le16_to_cpu(fe->i_dyn_features); + + fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL); +@@ -484,17 +501,12 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb, + status = 0; /* error in ocfs2_create_new_inode_locks is not + * critical */ + +- *ret_inode = inode; + leave: + if (status < 0) { + if (*new_fe_bh) { + brelse(*new_fe_bh); + *new_fe_bh = NULL; + } +- if (inode) { +- clear_nlink(inode); +- iput(inode); +- } + } + + mlog_exit(status); +@@ -1542,6 +1554,13 @@ static int ocfs2_symlink(struct inode *dir, + goto bail; + } + ++ inode = ocfs2_get_init_inode(dir, S_IFLNK | S_IRWXUGO); ++ if (!inode) { ++ status = -ENOMEM; ++ mlog_errno(status); ++ goto bail; ++ } ++ + /* don't reserve bitmap space for fast symlinks. */ + if (l > ocfs2_fast_symlink_chars(sb)) { + status = ocfs2_reserve_clusters(osb, 1, &data_ac); +@@ -1560,10 +1579,9 @@ static int ocfs2_symlink(struct inode *dir, + goto bail; + } + +- status = ocfs2_mknod_locked(osb, dir, dentry, +- S_IFLNK | S_IRWXUGO, 0, +- &new_fe_bh, parent_fe_bh, handle, +- &inode, inode_ac); ++ status = ocfs2_mknod_locked(osb, dir, inode, dentry, ++ 0, &new_fe_bh, parent_fe_bh, handle, ++ inode_ac); + if (status < 0) { + mlog_errno(status); + goto bail; +@@ -1644,8 +1662,10 @@ bail: + ocfs2_free_alloc_context(inode_ac); + if (data_ac) + ocfs2_free_alloc_context(data_ac); +- if ((status < 0) && inode) ++ if ((status < 0) && inode) { ++ clear_nlink(inode); + iput(inode); ++ } + + mlog_exit(status); + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-reserve-inline-space-for-extend.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-reserve-inline-space-for-extend.patch new file mode 100644 index 000000000..0f1d2bcb1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-reserve-inline-space-for-extend.patch @@ -0,0 +1,186 @@ +From: Tiger Yang +Subject: [PATCH 08/16] ocfs2: reserve inline space for extended attribute +Patch-mainline: 2.6.28? +References: FATE302067 + +Add the structures and helper functions we want for handling inline extended +attributes. We also update the inline-data handlers so that they properly +function in the event that we have both inline data and inline attributes +sharing an inode block. + +Signed-off-by: Tiger Yang +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.c | 22 ++++++++++++++++------ + fs/ocfs2/ocfs2.h | 1 + + fs/ocfs2/ocfs2_fs.h | 46 +++++++++++++++++++++++++++++++++++++++++++--- + fs/ocfs2/super.c | 2 ++ + 4 files changed, 62 insertions(+), 9 deletions(-) + +diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c +index 130988f..d175db1 100644 +--- a/fs/ocfs2/alloc.c ++++ b/fs/ocfs2/alloc.c +@@ -6586,20 +6586,29 @@ out: + return ret; + } + +-static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di) ++static void ocfs2_zero_dinode_id2_with_xattr(struct inode *inode, ++ struct ocfs2_dinode *di) + { + unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits; ++ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size); + +- memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2)); ++ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL) ++ memset(&di->id2, 0, blocksize - ++ offsetof(struct ocfs2_dinode, id2) - ++ xattrsize); ++ else ++ memset(&di->id2, 0, blocksize - ++ offsetof(struct ocfs2_dinode, id2)); + } + + void ocfs2_dinode_new_extent_list(struct inode *inode, + struct ocfs2_dinode *di) + { +- ocfs2_zero_dinode_id2(inode, di); ++ ocfs2_zero_dinode_id2_with_xattr(inode, di); + di->id2.i_list.l_tree_depth = 0; + di->id2.i_list.l_next_free_rec = 0; +- di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb)); ++ di->id2.i_list.l_count = cpu_to_le16( ++ ocfs2_extent_recs_per_inode_with_xattr(inode->i_sb, di)); + } + + void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di) +@@ -6616,9 +6625,10 @@ void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di) + * We clear the entire i_data structure here so that all + * fields can be properly initialized. + */ +- ocfs2_zero_dinode_id2(inode, di); ++ ocfs2_zero_dinode_id2_with_xattr(inode, di); + +- idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb)); ++ idata->id_count = cpu_to_le16( ++ ocfs2_max_inline_data_with_xattr(inode->i_sb, di)); + } + + int ocfs2_convert_inline_data_to_extents(struct inode *inode, +diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h +index 7f625f2..9275923 100644 +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -241,6 +241,7 @@ struct ocfs2_super + int s_sectsize_bits; + int s_clustersize; + int s_clustersize_bits; ++ unsigned int s_xattr_inline_size; + + atomic_t vol_state; + struct mutex recovery_lock; +diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h +index 1b46505..1055ba0 100644 +--- a/fs/ocfs2/ocfs2_fs.h ++++ b/fs/ocfs2/ocfs2_fs.h +@@ -300,6 +300,12 @@ struct ocfs2_new_group_input { + */ + #define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8 + ++/* ++ * Inline extended attribute size (in bytes) ++ * The value chosen should be aligned to 16 byte boundaries. ++ */ ++#define OCFS2_MIN_XATTR_INLINE_SIZE 256 ++ + struct ocfs2_system_inode_info { + char *si_name; + int si_iflags; +@@ -622,7 +628,8 @@ struct ocfs2_dinode { + belongs to */ + __le16 i_suballoc_bit; /* Bit offset in suballocator + block group */ +-/*10*/ __le32 i_reserved0; ++/*10*/ __le16 i_reserved0; ++ __le16 i_xattr_inline_size; + __le32 i_clusters; /* Cluster count */ + __le32 i_uid; /* Owner UID */ + __le32 i_gid; /* Owning GID */ +@@ -641,11 +648,12 @@ struct ocfs2_dinode { + __le32 i_atime_nsec; + __le32 i_ctime_nsec; + __le32 i_mtime_nsec; +- __le32 i_attr; ++/*70*/ __le32 i_attr; + __le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL + was set in i_flags */ + __le16 i_dyn_features; +-/*70*/ __le64 i_reserved2[8]; ++ __le64 i_xattr_loc; ++/*80*/ __le64 i_reserved2[7]; + /*B8*/ union { + __le64 i_pad1; /* Generic way to refer to this + 64bit union */ +@@ -846,6 +854,20 @@ static inline int ocfs2_max_inline_data(struct super_block *sb) + offsetof(struct ocfs2_dinode, id2.i_data.id_data); + } + ++static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb, ++ struct ocfs2_dinode *di) ++{ ++ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size); ++ ++ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL) ++ return sb->s_blocksize - ++ offsetof(struct ocfs2_dinode, id2.i_data.id_data) - ++ xattrsize; ++ else ++ return sb->s_blocksize - ++ offsetof(struct ocfs2_dinode, id2.i_data.id_data); ++} ++ + static inline int ocfs2_extent_recs_per_inode(struct super_block *sb) + { + int size; +@@ -856,6 +878,24 @@ static inline int ocfs2_extent_recs_per_inode(struct super_block *sb) + return size / sizeof(struct ocfs2_extent_rec); + } + ++static inline int ocfs2_extent_recs_per_inode_with_xattr( ++ struct super_block *sb, ++ struct ocfs2_dinode *di) ++{ ++ int size; ++ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size); ++ ++ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL) ++ size = sb->s_blocksize - ++ offsetof(struct ocfs2_dinode, id2.i_list.l_recs) - ++ xattrsize; ++ else ++ size = sb->s_blocksize - ++ offsetof(struct ocfs2_dinode, id2.i_list.l_recs); ++ ++ return size / sizeof(struct ocfs2_extent_rec); ++} ++ + static inline int ocfs2_chain_recs_per_inode(struct super_block *sb) + { + int size; +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 88255d3..4029fce 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -1421,6 +1421,8 @@ static int ocfs2_initialize_super(struct super_block *sb, + + osb->slot_num = OCFS2_INVALID_SLOT; + ++ osb->s_xattr_inline_size = OCFS2_MIN_XATTR_INLINE_SIZE; ++ + osb->local_alloc_state = OCFS2_LA_UNUSED; + osb->local_alloc_bh = NULL; + +-- +1.5.4.5 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-throttle-back-local-alloc-when-low-on-disk-sp.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-throttle-back-local-alloc-when-low-on-disk-sp.patch new file mode 100644 index 000000000..144f9a959 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-throttle-back-local-alloc-when-low-on-disk-sp.patch @@ -0,0 +1,486 @@ +From: Mark Fasheh +Subject: ocfs2: throttle back local alloc when low on disk space +Patch-mainline: 2.6.28 + +Ocfs2's local allocator disables itself for the duration of a mount point +when it has trouble allocating a large enough area from the primary bitmap. +That can cause performance problems, especially for disks which were only +temporarily full or fragmented. This patch allows for the allocator to +shrink it's window first, before being disabled. Later, it can also be +re-enabled so that any performance drop is minimized. + +To do this, we allow the value of osb->local_alloc_bits to be shrunk when +needed. The default value is recorded in a mostly read-only variable so that +we can re-initialize when required. + +Locking had to be updated so that we could protect changes to +local_alloc_bits. Mostly this involves protecting various local alloc values +with the osb spinlock. A new state is also added, OCFS2_LA_THROTTLED, which +is used when the local allocator is has shrunk, but is not disabled. If the +available space dips below 1 megabyte, the local alloc file is disabled. In +either case, local alloc is re-enabled 30 seconds after the event, or when +an appropriate amount of bits is seen in the primary bitmap. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/localalloc.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++--- + fs/ocfs2/localalloc.h | 4 + + fs/ocfs2/ocfs2.h | 23 +++++- + fs/ocfs2/suballoc.c | 31 ++++---- + fs/ocfs2/suballoc.h | 1 + + fs/ocfs2/super.c | 4 +- + 6 files changed, 230 insertions(+), 31 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/localalloc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.c ++++ linux-2.6.27/fs/ocfs2/localalloc.c +@@ -73,16 +73,51 @@ static int ocfs2_local_alloc_new_window( + static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, + struct inode *local_alloc_inode); + ++static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) ++{ ++ return (osb->local_alloc_state == OCFS2_LA_THROTTLED || ++ osb->local_alloc_state == OCFS2_LA_ENABLED); ++} ++ ++void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb, ++ unsigned int num_clusters) ++{ ++ spin_lock(&osb->osb_lock); ++ if (osb->local_alloc_state == OCFS2_LA_DISABLED || ++ osb->local_alloc_state == OCFS2_LA_THROTTLED) ++ if (num_clusters >= osb->local_alloc_default_bits) { ++ cancel_delayed_work(&osb->la_enable_wq); ++ osb->local_alloc_state = OCFS2_LA_ENABLED; ++ } ++ spin_unlock(&osb->osb_lock); ++} ++ ++void ocfs2_la_enable_worker(struct work_struct *work) ++{ ++ struct ocfs2_super *osb = ++ container_of(work, struct ocfs2_super, ++ la_enable_wq.work); ++ spin_lock(&osb->osb_lock); ++ osb->local_alloc_state = OCFS2_LA_ENABLED; ++ spin_unlock(&osb->osb_lock); ++} ++ + /* + * Tell us whether a given allocation should use the local alloc + * file. Otherwise, it has to go to the main bitmap. ++ * ++ * This function does semi-dirty reads of local alloc size and state! ++ * This is ok however, as the values are re-checked once under mutex. + */ + int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits) + { +- int la_bits = osb->local_alloc_bits; + int ret = 0; ++ int la_bits; ++ ++ spin_lock(&osb->osb_lock); ++ la_bits = osb->local_alloc_bits; + +- if (osb->local_alloc_state != OCFS2_LA_ENABLED) ++ if (!ocfs2_la_state_enabled(osb)) + goto bail; + + /* la_bits should be at least twice the size (in clusters) of +@@ -96,6 +131,7 @@ int ocfs2_alloc_should_use_local(struct + bail: + mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n", + osb->local_alloc_state, (unsigned long long)bits, la_bits, ret); ++ spin_unlock(&osb->osb_lock); + return ret; + } + +@@ -208,6 +244,9 @@ void ocfs2_shutdown_local_alloc(struct o + + mlog_entry_void(); + ++ cancel_delayed_work(&osb->la_enable_wq); ++ flush_workqueue(ocfs2_wq); ++ + if (osb->local_alloc_state == OCFS2_LA_UNUSED) + goto out; + +@@ -485,7 +524,7 @@ static int ocfs2_local_alloc_in_range(st + } + + /* +- * make sure we've got at least bitswanted contiguous bits in the ++ * make sure we've got at least bits_wanted contiguous bits in the + * local alloc. You lose them when you drop i_mutex. + * + * We will add ourselves to the transaction passed in, but may start +@@ -516,16 +555,18 @@ int ocfs2_reserve_local_alloc_bits(struc + + mutex_lock(&local_alloc_inode->i_mutex); + +- if (osb->local_alloc_state != OCFS2_LA_ENABLED) { +- status = -ENOSPC; +- goto bail; +- } +- +- if (bits_wanted > osb->local_alloc_bits) { +- mlog(0, "Asking for more than my max window size!\n"); ++ /* ++ * We must double check state and allocator bits because ++ * another process may have changed them while holding i_mutex. ++ */ ++ spin_lock(&osb->osb_lock); ++ if (!ocfs2_la_state_enabled(osb) || ++ (bits_wanted > osb->local_alloc_bits)) { ++ spin_unlock(&osb->osb_lock); + status = -ENOSPC; + goto bail; + } ++ spin_unlock(&osb->osb_lock); + + alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data; + +@@ -553,6 +594,21 @@ int ocfs2_reserve_local_alloc_bits(struc + mlog_errno(status); + goto bail; + } ++ ++ /* ++ * Under certain conditions, the window slide code ++ * might have reduced the number of bits available or ++ * disabled the the local alloc entirely. Re-check ++ * here and return -ENOSPC if necessary. ++ */ ++ status = -ENOSPC; ++ if (!ocfs2_la_state_enabled(osb)) ++ goto bail; ++ ++ free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) - ++ le32_to_cpu(alloc->id1.bitmap1.i_used); ++ if (bits_wanted > free_bits) ++ goto bail; + } + + if (ac->ac_max_block) +@@ -835,6 +891,85 @@ bail: + return status; + } + ++enum ocfs2_la_event { ++ OCFS2_LA_EVENT_SLIDE, /* Normal window slide. */ ++ OCFS2_LA_EVENT_FRAGMENTED, /* The global bitmap has ++ * enough bits theoretically ++ * free, but a contiguous ++ * allocation could not be ++ * found. */ ++ OCFS2_LA_EVENT_ENOSPC, /* Global bitmap doesn't have ++ * enough bits free to satisfy ++ * our request. */ ++}; ++#define OCFS2_LA_ENABLE_INTERVAL (30 * HZ) ++/* ++ * Given an event, calculate the size of our next local alloc window. ++ * ++ * This should always be called under i_mutex of the local alloc inode ++ * so that local alloc disabling doesn't race with processes trying to ++ * use the allocator. ++ * ++ * Returns the state which the local alloc was left in. This value can ++ * be ignored by some paths. ++ */ ++static int ocfs2_recalc_la_window(struct ocfs2_super *osb, ++ enum ocfs2_la_event event) ++{ ++ unsigned int bits; ++ int state; ++ ++ spin_lock(&osb->osb_lock); ++ if (osb->local_alloc_state == OCFS2_LA_DISABLED) { ++ WARN_ON_ONCE(osb->local_alloc_state == OCFS2_LA_DISABLED); ++ goto out_unlock; ++ } ++ ++ /* ++ * ENOSPC and fragmentation are treated similarly for now. ++ */ ++ if (event == OCFS2_LA_EVENT_ENOSPC || ++ event == OCFS2_LA_EVENT_FRAGMENTED) { ++ /* ++ * We ran out of contiguous space in the primary ++ * bitmap. Drastically reduce the number of bits used ++ * by local alloc until we have to disable it. ++ */ ++ bits = osb->local_alloc_bits >> 1; ++ if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) { ++ /* ++ * By setting state to THROTTLED, we'll keep ++ * the number of local alloc bits used down ++ * until an event occurs which would give us ++ * reason to assume the bitmap situation might ++ * have changed. ++ */ ++ osb->local_alloc_state = OCFS2_LA_THROTTLED; ++ osb->local_alloc_bits = bits; ++ } else { ++ osb->local_alloc_state = OCFS2_LA_DISABLED; ++ } ++ queue_delayed_work(ocfs2_wq, &osb->la_enable_wq, ++ OCFS2_LA_ENABLE_INTERVAL); ++ goto out_unlock; ++ } ++ ++ /* ++ * Don't increase the size of the local alloc window until we ++ * know we might be able to fulfill the request. Otherwise, we ++ * risk bouncing around the global bitmap during periods of ++ * low space. ++ */ ++ if (osb->local_alloc_state != OCFS2_LA_THROTTLED) ++ osb->local_alloc_bits = osb->local_alloc_default_bits; ++ ++out_unlock: ++ state = osb->local_alloc_state; ++ spin_unlock(&osb->osb_lock); ++ ++ return state; ++} ++ + static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb, + struct ocfs2_alloc_context **ac, + struct inode **bitmap_inode, +@@ -849,12 +984,21 @@ static int ocfs2_local_alloc_reserve_for + goto bail; + } + ++retry_enospc: + (*ac)->ac_bits_wanted = osb->local_alloc_bits; + + status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac); ++ if (status == -ENOSPC) { ++ if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) == ++ OCFS2_LA_DISABLED) ++ goto bail; ++ ++ ocfs2_free_ac_resource(*ac); ++ memset(*ac, 0, sizeof(struct ocfs2_alloc_context)); ++ goto retry_enospc; ++ } + if (status < 0) { +- if (status != -ENOSPC) +- mlog_errno(status); ++ mlog_errno(status); + goto bail; + } + +@@ -907,6 +1051,34 @@ static int ocfs2_local_alloc_new_window( + * the more specific cluster api to claim bits. */ + status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits, + &cluster_off, &cluster_count); ++ if (status == -ENOSPC) { ++retry_enospc: ++ /* ++ * Note: We could also try syncing the journal here to ++ * allow use of any free bits which the current ++ * transaction can't give us access to. --Mark ++ */ ++ if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_FRAGMENTED) == ++ OCFS2_LA_DISABLED) ++ goto bail; ++ ++ status = ocfs2_claim_clusters(osb, handle, ac, ++ osb->local_alloc_bits, ++ &cluster_off, ++ &cluster_count); ++ if (status == -ENOSPC) ++ goto retry_enospc; ++ /* ++ * We only shrunk the *minimum* number of in our ++ * request - it's entirely possible that the allocator ++ * might give us more than we asked for. ++ */ ++ if (status == 0) { ++ spin_lock(&osb->osb_lock); ++ osb->local_alloc_bits = cluster_count; ++ spin_unlock(&osb->osb_lock); ++ } ++ } + if (status < 0) { + if (status != -ENOSPC) + mlog_errno(status); +@@ -950,6 +1122,8 @@ static int ocfs2_local_alloc_slide_windo + + mlog_entry_void(); + ++ ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_SLIDE); ++ + /* This will lock the main bitmap for us. */ + status = ocfs2_local_alloc_reserve_for_window(osb, + &ac, +Index: linux-2.6.27/fs/ocfs2/localalloc.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/localalloc.h ++++ linux-2.6.27/fs/ocfs2/localalloc.h +@@ -52,4 +52,8 @@ int ocfs2_claim_local_alloc_bits(struct + u32 *bit_off, + u32 *num_bits); + ++void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb, ++ unsigned int num_clusters); ++void ocfs2_la_enable_worker(struct work_struct *work); ++ + #endif /* OCFS2_LOCALALLOC_H */ +Index: linux-2.6.27/fs/ocfs2/ocfs2.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/ocfs2.h ++++ linux-2.6.27/fs/ocfs2/ocfs2.h +@@ -176,9 +176,13 @@ struct ocfs2_alloc_stats + + enum ocfs2_local_alloc_state + { +- OCFS2_LA_UNUSED = 0, +- OCFS2_LA_ENABLED, +- OCFS2_LA_DISABLED ++ OCFS2_LA_UNUSED = 0, /* Local alloc will never be used for ++ * this mountpoint. */ ++ OCFS2_LA_ENABLED, /* Local alloc is in use. */ ++ OCFS2_LA_THROTTLED, /* Local alloc is in use, but number ++ * of bits has been reduced. */ ++ OCFS2_LA_DISABLED /* Local alloc has temporarily been ++ * disabled. */ + }; + + enum ocfs2_mount_options +@@ -261,9 +265,20 @@ struct ocfs2_super + struct ocfs2_journal *journal; + unsigned long osb_commit_interval; + ++ struct delayed_work la_enable_wq; ++ ++ /* ++ * Must hold local alloc i_mutex and osb->osb_lock to change ++ * local_alloc_bits. Reads can be done under either lock. ++ */ + unsigned int local_alloc_bits; +- enum ocfs2_local_alloc_state local_alloc_state; ++ unsigned int local_alloc_default_bits; ++ ++ enum ocfs2_local_alloc_state local_alloc_state; /* protected ++ * by osb_lock */ ++ + struct buffer_head *local_alloc_bh; ++ + u64 la_last_gd; + + /* Next two fields are for local node slot recovery during +Index: linux-2.6.27/fs/ocfs2/suballoc.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/suballoc.c ++++ linux-2.6.27/fs/ocfs2/suballoc.c +@@ -117,7 +117,7 @@ static int ocfs2_reserve_clusters_with_l + u32 bits_wanted, u64 max_block, + struct ocfs2_alloc_context **ac); + +-static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) ++void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) + { + struct inode *inode = ac->ac_inode; + +@@ -709,21 +709,11 @@ static int ocfs2_reserve_clusters_with_l + status = ocfs2_reserve_local_alloc_bits(osb, + bits_wanted, + *ac); +- if (status == -ENOSPC) { +- /* reserve_local_bits will return enospc with +- * the local alloc inode still locked, so we +- * can change this safely here. */ +- mlog(0, "Disabling local alloc\n"); +- /* We set to OCFS2_LA_DISABLED so that umount +- * can clean up what's left of the local +- * allocation */ +- osb->local_alloc_state = OCFS2_LA_DISABLED; +- } else if (status == -EFBIG) { ++ if (status == -EFBIG) { + /* The local alloc window is outside ac_max_block. +- * use the main bitmap, but don't disable +- * local alloc. */ ++ * use the main bitmap. */ + status = -ENOSPC; +- } else if (status < 0) { ++ } else if ((status < 0) && (status != -ENOSPC)) { + mlog_errno(status); + goto bail; + } +@@ -1045,6 +1035,7 @@ static int ocfs2_cluster_group_search(st + int ret; + u64 blkoff; + struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + u16 tmp_off, tmp_found; + unsigned int max_bits, gd_cluster_off; + +@@ -1096,6 +1087,12 @@ static int ocfs2_cluster_group_search(st + *bit_off = tmp_off; + *bits_found = tmp_found; + search = 0; /* success */ ++ } else if (tmp_found) { ++ /* ++ * Don't show bits which we'll be returning ++ * for allocation to the local alloc bitmap. ++ */ ++ ocfs2_local_alloc_seen_free_bits(osb, tmp_found); + } + } + +@@ -1902,9 +1899,15 @@ int ocfs2_free_clusters(handle_t *handle + status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh, + bg_start_bit, bg_blkno, + num_clusters); +- if (status < 0) ++ if (status < 0) { + mlog_errno(status); ++ goto out; ++ } ++ ++ ocfs2_local_alloc_seen_free_bits(OCFS2_SB(bitmap_inode->i_sb), ++ num_clusters); + ++out: + mlog_exit(status); + return status; + } +Index: linux-2.6.27/fs/ocfs2/suballoc.h +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/suballoc.h ++++ linux-2.6.27/fs/ocfs2/suballoc.h +@@ -158,6 +158,7 @@ static inline int ocfs2_is_cluster_bitma + * apis above. */ + int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb, + struct ocfs2_alloc_context *ac); ++void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac); + + /* given a cluster offset, calculate which block group it belongs to + * and return that block offset. */ +Index: linux-2.6.27/fs/ocfs2/super.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/super.c ++++ linux-2.6.27/fs/ocfs2/super.c +@@ -655,7 +655,8 @@ static int ocfs2_fill_super(struct super + osb->s_atime_quantum = parsed_options.atime_quantum; + osb->preferred_slot = parsed_options.slot; + osb->osb_commit_interval = parsed_options.commit_interval; +- osb->local_alloc_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); ++ osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); ++ osb->local_alloc_bits = osb->local_alloc_default_bits; + + status = ocfs2_verify_userspace_stack(osb, &parsed_options); + if (status) +@@ -1465,6 +1466,7 @@ static int ocfs2_initialize_super(struct + + osb->local_alloc_state = OCFS2_LA_UNUSED; + osb->local_alloc_bh = NULL; ++ INIT_DELAYED_WORK(&osb->la_enable_wq, ocfs2_la_enable_worker); + + init_waitqueue_head(&osb->osb_mount_event); + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-track-local-alloc-state-via-debugfs.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-track-local-alloc-state-via-debugfs.patch new file mode 100644 index 000000000..0b720c1d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-track-local-alloc-state-via-debugfs.patch @@ -0,0 +1,154 @@ +From: Mark Fasheh +Subject: ocfs2: track local alloc state via debugfs +Patch-mainline: 2.6.28 + +A per-mount debugfs file, "local_alloc" is created which when read will +expose live state of the nodes local alloc file. Performance impact is +minimal, only a bit of memory overhead per mount point. Still, the code is +hidden behind CONFIG_OCFS2_FS_STATS. This feature will help us debug +local alloc performance problems on a live system. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/localalloc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/ocfs2.h | 5 ++ + 2 files changed, 92 insertions(+) + +--- a/fs/ocfs2/localalloc.c ++++ b/fs/ocfs2/localalloc.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #define MLOG_MASK_PREFIX ML_DISK_ALLOC + #include +@@ -73,6 +74,85 @@ static int ocfs2_local_alloc_new_window( + static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, + struct inode *local_alloc_inode); + ++#ifdef CONFIG_OCFS2_FS_STATS ++ ++DEFINE_MUTEX(la_debug_mutex); ++ ++static int ocfs2_la_debug_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++#define LA_DEBUG_BUF_SZ PAGE_CACHE_SIZE ++#define LA_DEBUG_VER 1 ++static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ocfs2_super *osb = file->private_data; ++ int written, ret; ++ char *buf = osb->local_alloc_debug_buf; ++ ++ mutex_lock(&la_debug_mutex); ++ memset(buf, 0, LA_DEBUG_BUF_SZ); ++ ++ written = snprintf(buf, LA_DEBUG_BUF_SZ, ++ "0x%x\t0x%llx\t%u\t%u\t0x%x\n", ++ LA_DEBUG_VER, ++ (unsigned long long)osb->la_last_gd, ++ osb->local_alloc_default_bits, ++ osb->local_alloc_bits, osb->local_alloc_state); ++ ++ ret = simple_read_from_buffer(userbuf, count, ppos, buf, written); ++ ++ mutex_unlock(&la_debug_mutex); ++ return ret; ++} ++ ++static const struct file_operations ocfs2_la_debug_fops = { ++ .open = ocfs2_la_debug_open, ++ .read = ocfs2_la_debug_read, ++}; ++ ++static void ocfs2_init_la_debug(struct ocfs2_super *osb) ++{ ++ osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS); ++ if (!osb->local_alloc_debug_buf) ++ return; ++ ++ osb->local_alloc_debug = debugfs_create_file("local_alloc_stats", ++ S_IFREG|S_IRUSR, ++ osb->osb_debug_root, ++ osb, ++ &ocfs2_la_debug_fops); ++ if (!osb->local_alloc_debug) { ++ kfree(osb->local_alloc_debug_buf); ++ osb->local_alloc_debug_buf = NULL; ++ } ++} ++ ++static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb) ++{ ++ if (osb->local_alloc_debug) ++ debugfs_remove(osb->local_alloc_debug); ++ ++ if (osb->local_alloc_debug_buf) ++ kfree(osb->local_alloc_debug_buf); ++ ++ osb->local_alloc_debug_buf = NULL; ++ osb->local_alloc_debug = NULL; ++} ++#else /* CONFIG_OCFS2_FS_STATS */ ++static void ocfs2_init_la_debug(struct ocfs2_super *osb) ++{ ++ return; ++} ++static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb) ++{ ++ return; ++} ++#endif ++ + static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb) + { + return (osb->local_alloc_state == OCFS2_LA_THROTTLED || +@@ -146,6 +226,8 @@ int ocfs2_load_local_alloc(struct ocfs2_ + + mlog_entry_void(); + ++ ocfs2_init_la_debug(osb); ++ + if (osb->local_alloc_bits == 0) + goto bail; + +@@ -218,6 +300,9 @@ bail: + if (inode) + iput(inode); + ++ if (status < 0) ++ ocfs2_shutdown_la_debug(osb); ++ + mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits); + + mlog_exit(status); +@@ -247,6 +332,8 @@ void ocfs2_shutdown_local_alloc(struct o + cancel_delayed_work(&osb->la_enable_wq); + flush_workqueue(ocfs2_wq); + ++ ocfs2_shutdown_la_debug(osb); ++ + if (osb->local_alloc_state == OCFS2_LA_UNUSED) + goto out; + +--- a/fs/ocfs2/ocfs2.h ++++ b/fs/ocfs2/ocfs2.h +@@ -281,6 +281,11 @@ struct ocfs2_super + + u64 la_last_gd; + ++#ifdef CONFIG_OCFS2_FS_STATS ++ struct dentry *local_alloc_debug; ++ char *local_alloc_debug_buf; ++#endif ++ + /* Next two fields are for local node slot recovery during + * mount. */ + int dirty; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-turn-__ocfs2_remove_inode_range-into-ocfs2_.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-turn-__ocfs2_remove_inode_range-into-ocfs2_.patch new file mode 100644 index 000000000..6eb49c426 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-turn-__ocfs2_remove_inode_range-into-ocfs2_.patch @@ -0,0 +1,230 @@ +From: Mark Fasheh +Date: Wed, 12 Nov 2008 15:16:38 -0800 +Subject: ocfs2: turn __ocfs2_remove_inode_range() into ocfs2_remove_btree_range() +Patch-mainline: 2.6.29 + +This patch genericizes the high level handling of extent removal. +ocfs2_remove_btree_range() is nearly identical to +__ocfs2_remove_inode_range(), except that extent tree operations have been +used where necessary. We update ocfs2_remove_inode_range() to use the +generic helper. Now extent tree based structures have an easy way to +truncate ranges. + +Signed-off-by: Mark Fasheh +Acked-by: Joel Becker +--- + fs/ocfs2/alloc.c | 72 +++++++++++++++++++++++++++++++++++++++++++++ + fs/ocfs2/alloc.h | 5 +++ + fs/ocfs2/file.c | 85 +++-------------------------------------------------- + 3 files changed, 82 insertions(+), 80 deletions(-) + +Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.c +@@ -5264,6 +5264,78 @@ out: + return ret; + } + ++int ocfs2_remove_btree_range(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 cpos, u32 phys_cpos, u32 len, ++ struct ocfs2_cached_dealloc_ctxt *dealloc) ++{ ++ int ret; ++ u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct inode *tl_inode = osb->osb_tl_inode; ++ handle_t *handle; ++ struct ocfs2_alloc_context *meta_ac = NULL; ++ ++ ret = ocfs2_lock_allocators(inode, et, 0, 1, NULL, &meta_ac); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ mutex_lock(&tl_inode->i_mutex); ++ ++ if (ocfs2_truncate_log_needs_flush(osb)) { ++ ret = __ocfs2_flush_truncate_log(osb); ++ if (ret < 0) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ if (IS_ERR(handle)) { ++ ret = PTR_ERR(handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_journal_access(handle, inode, et->et_root_bh, ++ OCFS2_JOURNAL_ACCESS_WRITE); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_remove_extent(inode, et, cpos, len, handle, meta_ac, ++ dealloc); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ocfs2_et_update_clusters(inode, et, -len); ++ ++ ret = ocfs2_journal_dirty(handle, et->et_root_bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out_commit; ++ } ++ ++ ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len); ++ if (ret) ++ mlog_errno(ret); ++ ++out_commit: ++ ocfs2_commit_trans(osb, handle); ++out: ++ mutex_unlock(&tl_inode->i_mutex); ++ ++ if (meta_ac) ++ ocfs2_free_alloc_context(meta_ac); ++ ++ return ret; ++} ++ + int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb) + { + struct buffer_head *tl_bh = osb->osb_tl_bh; +Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.h +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.h ++++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.h +@@ -110,6 +110,11 @@ int ocfs2_remove_extent(struct inode *in + u32 cpos, u32 len, handle_t *handle, + struct ocfs2_alloc_context *meta_ac, + struct ocfs2_cached_dealloc_ctxt *dealloc); ++int ocfs2_remove_btree_range(struct inode *inode, ++ struct ocfs2_extent_tree *et, ++ u32 cpos, u32 phys_cpos, u32 len, ++ struct ocfs2_cached_dealloc_ctxt *dealloc); ++ + int ocfs2_num_free_extents(struct ocfs2_super *osb, + struct inode *inode, + struct ocfs2_extent_tree *et); +Index: linux-2.6.27-ocfs2/fs/ocfs2/file.c +=================================================================== +--- linux-2.6.27-ocfs2.orig/fs/ocfs2/file.c ++++ linux-2.6.27-ocfs2/fs/ocfs2/file.c +@@ -1226,83 +1226,6 @@ out: + return ret; + } + +-static int __ocfs2_remove_inode_range(struct inode *inode, +- struct buffer_head *di_bh, +- u32 cpos, u32 phys_cpos, u32 len, +- struct ocfs2_cached_dealloc_ctxt *dealloc) +-{ +- int ret; +- u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct inode *tl_inode = osb->osb_tl_inode; +- handle_t *handle; +- struct ocfs2_alloc_context *meta_ac = NULL; +- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +- struct ocfs2_extent_tree et; +- +- ocfs2_init_dinode_extent_tree(&et, inode, di_bh); +- +- ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); +- if (ret) { +- mlog_errno(ret); +- return ret; +- } +- +- mutex_lock(&tl_inode->i_mutex); +- +- if (ocfs2_truncate_log_needs_flush(osb)) { +- ret = __ocfs2_flush_truncate_log(osb); +- if (ret < 0) { +- mlog_errno(ret); +- goto out; +- } +- } +- +- handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out; +- } +- +- ret = ocfs2_journal_access(handle, inode, di_bh, +- OCFS2_JOURNAL_ACCESS_WRITE); +- if (ret) { +- mlog_errno(ret); +- goto out; +- } +- +- ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac, +- dealloc); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } +- +- OCFS2_I(inode)->ip_clusters -= len; +- di->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters); +- +- ret = ocfs2_journal_dirty(handle, di_bh); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } +- +- ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len); +- if (ret) +- mlog_errno(ret); +- +-out_commit: +- ocfs2_commit_trans(osb, handle); +-out: +- mutex_unlock(&tl_inode->i_mutex); +- +- if (meta_ac) +- ocfs2_free_alloc_context(meta_ac); +- +- return ret; +-} +- + /* + * Truncate a byte range, avoiding pages within partial clusters. This + * preserves those pages for the zeroing code to write to. +@@ -1402,7 +1325,9 @@ static int ocfs2_remove_inode_range(stru + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_cached_dealloc_ctxt dealloc; + struct address_space *mapping = inode->i_mapping; ++ struct ocfs2_extent_tree et; + ++ ocfs2_init_dinode_extent_tree(&et, inode, di_bh); + ocfs2_init_dealloc_ctxt(&dealloc); + + if (byte_len == 0) +@@ -1458,9 +1383,9 @@ static int ocfs2_remove_inode_range(stru + + /* Only do work for non-holes */ + if (phys_cpos != 0) { +- ret = __ocfs2_remove_inode_range(inode, di_bh, cpos, +- phys_cpos, alloc_size, +- &dealloc); ++ ret = ocfs2_remove_btree_range(inode, &et, cpos, ++ phys_cpos, alloc_size, ++ &dealloc); + if (ret) { + mlog_errno(ret); + goto out; diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-use-smaller-counters-in-ocfs2_remove_xattr_cl.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-use-smaller-counters-in-ocfs2_remove_xattr_cl.patch new file mode 100644 index 000000000..301fd033f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-use-smaller-counters-in-ocfs2_remove_xattr_cl.patch @@ -0,0 +1,25 @@ +From: Mark Fasheh +Subject: ocfs2: use smaller counters in ocfs2_remove_xattr_clusters_from_cache +Patch-mainline: 2.6.28 + +i and b_len don't really need to be u64's. Xattr extent lengths should be +limited by the VFS, and then the size of our on-disk length field. + +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/uptodate.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/uptodate.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/uptodate.c ++++ linux-2.6.27/fs/ocfs2/uptodate.c +@@ -562,7 +562,7 @@ void ocfs2_remove_xattr_clusters_from_ca + sector_t block, + u32 c_len) + { +- u64 i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len; ++ unsigned int i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len; + + for (i = 0; i < b_len; i++, block++) + ocfs2_remove_block_from_cache(inode, block); diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Merge-xattr-set-transaction.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Merge-xattr-set-transaction.patch new file mode 100644 index 000000000..b3e8ec225 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Merge-xattr-set-transaction.patch @@ -0,0 +1,1467 @@ +From: Tao Ma +Date: Wed, 12 Nov 2008 08:27:01 +0800 +Subject: ocfs2/xattr: Merge xattr set transaction. +Patch-mainline: 2.6.29 + +In current ocfs2/xattr, the whole xattr set is divided into +many steps are many transaction are used, this make the +xattr set process isn't like a real transaction, so this +patch try to merge all the transaction into one. Another +benefit is that acl can use it easily now. + +I don't merge the transaction of deleting xattr when we +remove an inode. The reason is that if we have a large number +of xattrs and every xattrs has large values(large enough +for outside storage), the whole transaction will be very +huge and it looks like jbd can't handle it(I meet with a +jbd complain once). And the old inode removal is also divided +into many steps, so I'd like to leave as it is. + +Note: +In xattr set, I try to avoid ocfs2_extend_trans since if +the credits aren't enough for the extension, it will commit +all the dirty blocks and create a new transaction which may +lead to inconsistency in metadata. All ocfs2_extend_trans +remained are safe now. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 673 ++++++++++++++++++++++++++---------------------------- + 1 files changed, 325 insertions(+), 348 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 4fd201a..7a90892 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -72,6 +72,7 @@ struct ocfs2_xattr_bucket { + }; + + struct ocfs2_xattr_set_ctxt { ++ handle_t *handle; + struct ocfs2_alloc_context *meta_ac; + struct ocfs2_alloc_context *data_ac; + struct ocfs2_cached_dealloc_ctxt dealloc; +@@ -346,9 +347,7 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode, + struct ocfs2_xattr_set_ctxt *ctxt) + { + int status = 0; +- int restart_func = 0; +- int credits = 0; +- handle_t *handle = NULL; ++ handle_t *handle = ctxt->handle; + enum ocfs2_alloc_restarted why; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters); +@@ -358,19 +357,6 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode, + + ocfs2_init_xattr_value_extent_tree(&et, inode, xattr_bh, xv); + +-restart_all: +- +- credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, +- clusters_to_add); +- handle = ocfs2_start_trans(osb, credits); +- if (IS_ERR(handle)) { +- status = PTR_ERR(handle); +- handle = NULL; +- mlog_errno(status); +- goto leave; +- } +- +-restarted_transaction: + status = ocfs2_journal_access(handle, inode, xattr_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (status < 0) { +@@ -389,9 +375,8 @@ restarted_transaction: + ctxt->data_ac, + ctxt->meta_ac, + &why); +- if ((status < 0) && (status != -EAGAIN)) { +- if (status != -ENOSPC) +- mlog_errno(status); ++ if (status < 0) { ++ mlog_errno(status); + goto leave; + } + +@@ -403,39 +388,13 @@ restarted_transaction: + + clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters; + +- if (why != RESTART_NONE && clusters_to_add) { +- if (why == RESTART_META) { +- mlog(0, "restarting function.\n"); +- restart_func = 1; +- } else { +- BUG_ON(why != RESTART_TRANS); +- +- mlog(0, "restarting transaction.\n"); +- /* TODO: This can be more intelligent. */ +- credits = ocfs2_calc_extend_credits(osb->sb, +- et.et_root_el, +- clusters_to_add); +- status = ocfs2_extend_trans(handle, credits); +- if (status < 0) { +- /* handle still has to be committed at +- * this point. */ +- status = -ENOMEM; +- mlog_errno(status); +- goto leave; +- } +- goto restarted_transaction; +- } +- } ++ /* ++ * We should have already allocated enough space before the transaction, ++ * so no need to restart. ++ */ ++ BUG_ON(why != RESTART_NONE || clusters_to_add); + + leave: +- if (handle) { +- ocfs2_commit_trans(osb, handle); +- handle = NULL; +- } +- if ((!status) && restart_func) { +- restart_func = 0; +- goto restart_all; +- } + + return status; + } +@@ -448,31 +407,23 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + { + int ret; + u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- handle_t *handle; ++ handle_t *handle = ctxt->handle; + struct ocfs2_extent_tree et; + + ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv); + +- handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out; +- } +- + ret = ocfs2_journal_access(handle, inode, root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, ctxt->meta_ac, + &ctxt->dealloc); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + le32_add_cpu(&xv->xr_clusters, -len); +@@ -480,15 +431,13 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + ret = ocfs2_journal_dirty(handle, root_bh); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + ret = ocfs2_cache_cluster_dealloc(&ctxt->dealloc, phys_blkno, len); + if (ret) + mlog_errno(ret); + +-out_commit: +- ocfs2_commit_trans(osb, handle); + out: + return ret; + } +@@ -975,6 +924,7 @@ static int ocfs2_xattr_get(struct inode *inode, + } + + static int __ocfs2_xattr_set_value_outside(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_value_root *xv, + const void *value, + int value_len) +@@ -986,14 +936,17 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, + u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len); + u64 blkno; + struct buffer_head *bh = NULL; +- handle_t *handle; + + BUG_ON(clusters > le32_to_cpu(xv->xr_clusters)); + ++ /* ++ * In __ocfs2_xattr_set_value_outside has already been dirtied, ++ * so we don't need to worry about whether ocfs2_extend_trans ++ * will create a new transactio for us or not. ++ */ + credits = clusters * bpc; +- handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), credits); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); ++ ret = ocfs2_extend_trans(handle, credits); ++ if (ret) { + mlog_errno(ret); + goto out; + } +@@ -1003,7 +956,7 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, + &num_clusters, &xv->xr_list); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); +@@ -1012,7 +965,7 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, + ret = ocfs2_read_block(inode, blkno, &bh); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + ret = ocfs2_journal_access(handle, +@@ -1021,7 +974,7 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + cp_len = value_len > blocksize ? blocksize : value_len; +@@ -1035,7 +988,7 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, + ret = ocfs2_journal_dirty(handle, bh); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + brelse(bh); + bh = NULL; +@@ -1049,8 +1002,6 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode, + } + cpos += num_clusters; + } +-out_commit: +- ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: + brelse(bh); + +@@ -1058,28 +1009,21 @@ out: + } + + static int ocfs2_xattr_cleanup(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, + size_t offs) + { +- handle_t *handle = NULL; + int ret = 0; + size_t name_len = strlen(xi->name); + void *val = xs->base + offs; + size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE; + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), +- OCFS2_XATTR_BLOCK_UPDATE_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out; +- } + ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + /* Decrease xattr count */ + le16_add_cpu(&xs->header->xh_count, -1); +@@ -1090,32 +1034,23 @@ static int ocfs2_xattr_cleanup(struct inode *inode, + ret = ocfs2_journal_dirty(handle, xs->xattr_bh); + if (ret < 0) + mlog_errno(ret); +-out_commit: +- ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: + return ret; + } + + static int ocfs2_xattr_update_entry(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, + size_t offs) + { +- handle_t *handle = NULL; +- int ret = 0; ++ int ret; + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), +- OCFS2_XATTR_BLOCK_UPDATE_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out; +- } + ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + xs->here->xe_name_offset = cpu_to_le16(offs); +@@ -1129,8 +1064,6 @@ static int ocfs2_xattr_update_entry(struct inode *inode, + ret = ocfs2_journal_dirty(handle, xs->xattr_bh); + if (ret < 0) + mlog_errno(ret); +-out_commit: +- ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: + return ret; + } +@@ -1168,13 +1101,13 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode, + mlog_errno(ret); + return ret; + } +- ret = __ocfs2_xattr_set_value_outside(inode, xv, xi->value, +- xi->value_len); ++ ret = ocfs2_xattr_update_entry(inode, ctxt->handle, xi, xs, offs); + if (ret < 0) { + mlog_errno(ret); + return ret; + } +- ret = ocfs2_xattr_update_entry(inode, xi, xs, offs); ++ ret = __ocfs2_xattr_set_value_outside(inode, ctxt->handle, xv, ++ xi->value, xi->value_len); + if (ret < 0) + mlog_errno(ret); + +@@ -1302,7 +1235,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; + size_t min_offs = xs->end - xs->base, name_len = strlen(xi->name); + size_t size_l = 0; +- handle_t *handle = NULL; ++ handle_t *handle = ctxt->handle; + int free, i, ret; + struct ocfs2_xattr_info xi_l = { + .name_index = xi->name_index, +@@ -1391,19 +1324,21 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + goto out; + } + +- ret = __ocfs2_xattr_set_value_outside(inode, +- xv, +- xi->value, +- xi->value_len); ++ ret = ocfs2_xattr_update_entry(inode, ++ handle, ++ xi, ++ xs, ++ offs); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + +- ret = ocfs2_xattr_update_entry(inode, +- xi, +- xs, +- offs); ++ ret = __ocfs2_xattr_set_value_outside(inode, ++ handle, ++ xv, ++ xi->value, ++ xi->value_len); + if (ret < 0) + mlog_errno(ret); + goto out; +@@ -1413,45 +1348,29 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + * just trucate old value to zero. + */ + ret = ocfs2_xattr_value_truncate(inode, +- xs->xattr_bh, +- xv, +- 0, +- ctxt); ++ xs->xattr_bh, ++ xv, ++ 0, ++ ctxt); + if (ret < 0) + mlog_errno(ret); + } + } + } + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), +- OCFS2_INODE_UPDATE_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out; +- } +- + ret = ocfs2_journal_access(handle, inode, xs->inode_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + if (!(flag & OCFS2_INLINE_XATTR_FL)) { +- /* set extended attribute in external block. */ +- ret = ocfs2_extend_trans(handle, +- OCFS2_INODE_UPDATE_CREDITS + +- OCFS2_XATTR_BLOCK_UPDATE_CREDITS); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } + ret = ocfs2_journal_access(handle, inode, xs->xattr_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + } + +@@ -1465,7 +1384,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + ret = ocfs2_journal_dirty(handle, xs->xattr_bh); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + } + +@@ -1502,9 +1421,6 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + if (ret < 0) + mlog_errno(ret); + +-out_commit: +- ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); +- + if (!ret && xi->value_len > OCFS2_XATTR_INLINE_SIZE) { + /* + * Set value outside in B tree. +@@ -1520,14 +1436,14 @@ out_commit: + * If set value outside failed, we have to clean + * the junk tree root we have already set in local. + */ +- ret2 = ocfs2_xattr_cleanup(inode, xi, xs, offs); ++ ret2 = ocfs2_xattr_cleanup(inode, ctxt->handle, ++ xi, xs, offs); + if (ret2 < 0) + mlog_errno(ret2); + } + } + out: + return ret; +- + } + + static int ocfs2_remove_value_outside(struct inode*inode, +@@ -1540,6 +1456,13 @@ static int ocfs2_remove_value_outside(struct inode*inode, + + ocfs2_init_dealloc_ctxt(&ctxt.dealloc); + ++ ctxt.handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ if (IS_ERR(ctxt.handle)) { ++ ret = PTR_ERR(ctxt.handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ + for (i = 0; i < le16_to_cpu(header->xh_count); i++) { + struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; + +@@ -1560,8 +1483,10 @@ static int ocfs2_remove_value_outside(struct inode*inode, + } + } + ++ ocfs2_commit_trans(osb, ctxt.handle); + ocfs2_schedule_truncate_log_flush(osb, 1); + ocfs2_run_deallocs(osb, &ctxt.dealloc); ++out: + return ret; + } + +@@ -1920,7 +1845,7 @@ static int ocfs2_xattr_block_set(struct inode *inode, + struct buffer_head *new_bh = NULL; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; +- handle_t *handle = NULL; ++ handle_t *handle = ctxt->handle; + struct ocfs2_xattr_block *xblk = NULL; + u16 suballoc_bit_start; + u32 num_got; +@@ -1928,18 +1853,11 @@ static int ocfs2_xattr_block_set(struct inode *inode, + int ret; + + if (!xs->xattr_bh) { +- handle = ocfs2_start_trans(osb, +- OCFS2_XATTR_BLOCK_CREATE_CREDITS); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out; +- } + ret = ocfs2_journal_access(handle, inode, xs->inode_bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto end; + } + + ret = ocfs2_claim_metadata(osb, handle, ctxt->meta_ac, 1, +@@ -1947,7 +1865,7 @@ static int ocfs2_xattr_block_set(struct inode *inode, + &first_blkno); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto end; + } + + new_bh = sb_getblk(inode->i_sb, first_blkno); +@@ -1957,7 +1875,7 @@ static int ocfs2_xattr_block_set(struct inode *inode, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto end; + } + + /* Initialize ocfs2_xattr_block */ +@@ -1978,17 +1896,10 @@ static int ocfs2_xattr_block_set(struct inode *inode, + ret = ocfs2_journal_dirty(handle, new_bh); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto end; + } + di->i_xattr_loc = cpu_to_le64(first_blkno); +- ret = ocfs2_journal_dirty(handle, xs->inode_bh); +- if (ret < 0) +- mlog_errno(ret); +-out_commit: +- ocfs2_commit_trans(osb, handle); +-out: +- if (ret < 0) +- return ret; ++ ocfs2_journal_dirty(handle, xs->inode_bh); + } else + xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data; + +@@ -2057,10 +1968,11 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, + struct ocfs2_xattr_search *xis, + struct ocfs2_xattr_search *xbs, + int *clusters_need, +- int *meta_need) ++ int *meta_need, ++ int *credits_need) + { + int ret = 0, old_in_xb = 0; +- int clusters_add = 0, meta_add = 0; ++ int clusters_add = 0, meta_add = 0, credits = 0; + struct buffer_head *bh = NULL; + struct ocfs2_xattr_block *xb = NULL; + struct ocfs2_xattr_entry *xe = NULL; +@@ -2071,16 +1983,15 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, + xi->value_len); + u64 value_size; + +- /* +- * delete a xattr doesn't need metadata and cluster allocation. +- * so return. +- */ +- if (!xi->value) +- goto out; +- + if (xis->not_found && xbs->not_found) { +- if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) ++ credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ ++ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) { + clusters_add += new_clusters; ++ credits += ocfs2_calc_extend_credits(inode->i_sb, ++ &def_xv.xv.xr_list, ++ new_clusters); ++ } + + goto meta_guess; + } +@@ -2090,6 +2001,7 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, + name_offset = le16_to_cpu(xe->xe_name_offset); + name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); + base = xis->base; ++ credits += OCFS2_INODE_UPDATE_CREDITS; + } else { + int i, block_off; + xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data; +@@ -2105,8 +2017,25 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, + i, &block_off, + &name_offset); + base = bucket_block(xbs->bucket, block_off); +- } else ++ credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb); ++ } else { + base = xbs->base; ++ credits += OCFS2_XATTR_BLOCK_UPDATE_CREDITS; ++ } ++ } ++ ++ /* ++ * delete a xattr doesn't need metadata and cluster allocation. ++ * so just calculate the credits and return. ++ * ++ * The credits for removing the value tree will be extended ++ * by ocfs2_remove_extent itself. ++ */ ++ if (!xi->value) { ++ if (!ocfs2_xattr_is_local(xe)) ++ credits += OCFS2_REMOVE_EXTENT_CREDITS; ++ ++ goto out; + } + + /* do cluster allocation guess first. */ +@@ -2121,6 +2050,13 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, + */ + if (ocfs2_xattr_can_be_in_inode(inode, xi, xis)) { + clusters_add += new_clusters; ++ credits += OCFS2_REMOVE_EXTENT_CREDITS + ++ OCFS2_INODE_UPDATE_CREDITS; ++ if (!ocfs2_xattr_is_local(xe)) ++ credits += ocfs2_calc_extend_credits( ++ inode->i_sb, ++ &def_xv.xv.xr_list, ++ new_clusters); + goto out; + } + } +@@ -2137,11 +2073,16 @@ static int ocfs2_calc_xattr_set_need(struct inode *inode, + } else + xv = &def_xv.xv; + +- if (old_clusters >= new_clusters) ++ if (old_clusters >= new_clusters) { ++ credits += OCFS2_REMOVE_EXTENT_CREDITS; + goto out; +- else { ++ } else { + meta_add += ocfs2_extend_meta_needed(&xv->xr_list); + clusters_add += new_clusters - old_clusters; ++ credits += ocfs2_calc_extend_credits(inode->i_sb, ++ &xv->xr_list, ++ new_clusters - ++ old_clusters); + goto out; + } + } else { +@@ -2177,6 +2118,8 @@ meta_guess: + struct ocfs2_extent_list *el = + &xb->xb_attrs.xb_root.xt_list; + meta_add += ocfs2_extend_meta_needed(el); ++ credits += ocfs2_calc_extend_credits(inode->i_sb, ++ el, 1); + } + + /* +@@ -2187,16 +2130,23 @@ meta_guess: + * also. + */ + clusters_add += 1; ++ credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb); + if (OCFS2_XATTR_BUCKET_SIZE == +- OCFS2_SB(inode->i_sb)->s_clustersize) ++ OCFS2_SB(inode->i_sb)->s_clustersize) { ++ credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb); + clusters_add += 1; +- } else ++ } ++ } else { + meta_add += 1; ++ credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS; ++ } + out: + if (clusters_need) + *clusters_need = clusters_add; + if (meta_need) + *meta_need = meta_add; ++ if (credits_need) ++ *credits_need = credits; + brelse(bh); + return ret; + } +@@ -2206,7 +2156,8 @@ static int ocfs2_init_xattr_set_ctxt(struct inode *inode, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xis, + struct ocfs2_xattr_search *xbs, +- struct ocfs2_xattr_set_ctxt *ctxt) ++ struct ocfs2_xattr_set_ctxt *ctxt, ++ int *credits) + { + int clusters_add, meta_add, ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +@@ -2216,14 +2167,14 @@ static int ocfs2_init_xattr_set_ctxt(struct inode *inode, + ocfs2_init_dealloc_ctxt(&ctxt->dealloc); + + ret = ocfs2_calc_xattr_set_need(inode, di, xi, xis, xbs, +- &clusters_add, &meta_add); ++ &clusters_add, &meta_add, credits); + if (ret) { + mlog_errno(ret); + return ret; + } + +- mlog(0, "Set xattr %s, reserve meta blocks = %d, clusters = %d\n", +- xi->name, meta_add, clusters_add); ++ mlog(0, "Set xattr %s, reserve meta blocks = %d, clusters = %d, " ++ "credits = %d\n", xi->name, meta_add, clusters_add, *credits); + + if (meta_add) { + ret = ocfs2_reserve_new_metadata_blocks(osb, meta_add, +@@ -2254,6 +2205,126 @@ out: + return ret; + } + ++static int __ocfs2_xattr_set_handle(struct inode *inode, ++ struct ocfs2_dinode *di, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xis, ++ struct ocfs2_xattr_search *xbs, ++ struct ocfs2_xattr_set_ctxt *ctxt) ++{ ++ int ret = 0, credits; ++ ++ if (!xi->value) { ++ /* Remove existing extended attribute */ ++ if (!xis->not_found) ++ ret = ocfs2_xattr_ibody_set(inode, xi, xis, ctxt); ++ else if (!xbs->not_found) ++ ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt); ++ } else { ++ /* We always try to set extended attribute into inode first*/ ++ ret = ocfs2_xattr_ibody_set(inode, xi, xis, ctxt); ++ if (!ret && !xbs->not_found) { ++ /* ++ * If succeed and that extended attribute existing in ++ * external block, then we will remove it. ++ */ ++ xi->value = NULL; ++ xi->value_len = 0; ++ ++ xis->not_found = -ENODATA; ++ ret = ocfs2_calc_xattr_set_need(inode, ++ di, ++ xi, ++ xis, ++ xbs, ++ NULL, ++ NULL, ++ &credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_extend_trans(ctxt->handle, credits + ++ ctxt->handle->h_buffer_credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt); ++ } else if (ret == -ENOSPC) { ++ if (di->i_xattr_loc && !xbs->xattr_bh) { ++ ret = ocfs2_xattr_block_find(inode, ++ xi->name_index, ++ xi->name, xbs); ++ if (ret) ++ goto out; ++ ++ xis->not_found = -ENODATA; ++ ret = ocfs2_calc_xattr_set_need(inode, ++ di, ++ xi, ++ xis, ++ xbs, ++ NULL, ++ NULL, ++ &credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_extend_trans(ctxt->handle, credits + ++ ctxt->handle->h_buffer_credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ /* ++ * If no space in inode, we will set extended attribute ++ * into external block. ++ */ ++ ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt); ++ if (ret) ++ goto out; ++ if (!xis->not_found) { ++ /* ++ * If succeed and that extended attribute ++ * existing in inode, we will remove it. ++ */ ++ xi->value = NULL; ++ xi->value_len = 0; ++ xbs->not_found = -ENODATA; ++ ret = ocfs2_calc_xattr_set_need(inode, ++ di, ++ xi, ++ xis, ++ xbs, ++ NULL, ++ NULL, ++ &credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ ret = ocfs2_extend_trans(ctxt->handle, credits + ++ ctxt->handle->h_buffer_credits); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ret = ocfs2_xattr_ibody_set(inode, xi, ++ xis, ctxt); ++ } ++ } ++ } ++ ++out: ++ return ret; ++} ++ + /* + * ocfs2_xattr_set() + * +@@ -2270,8 +2341,9 @@ int ocfs2_xattr_set(struct inode *inode, + { + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; +- int ret; ++ int ret, credits; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct inode *tl_inode = osb->osb_tl_inode; + struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; + + struct ocfs2_xattr_info xi = { +@@ -2337,56 +2409,37 @@ int ocfs2_xattr_set(struct inode *inode, + goto cleanup; + } + +- ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis, &xbs, &ctxt); ++ ++ mutex_lock(&tl_inode->i_mutex); ++ ++ if (ocfs2_truncate_log_needs_flush(osb)) { ++ ret = __ocfs2_flush_truncate_log(osb); ++ if (ret < 0) { ++ mutex_unlock(&tl_inode->i_mutex); ++ mlog_errno(ret); ++ goto cleanup; ++ } ++ } ++ mutex_unlock(&tl_inode->i_mutex); ++ ++ ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis, ++ &xbs, &ctxt, &credits); + if (ret) { + mlog_errno(ret); + goto cleanup; + } + +- if (!value) { +- /* Remove existing extended attribute */ +- if (!xis.not_found) +- ret = ocfs2_xattr_ibody_set(inode, &xi, &xis, &ctxt); +- else if (!xbs.not_found) +- ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); +- } else { +- /* We always try to set extended attribute into inode first*/ +- ret = ocfs2_xattr_ibody_set(inode, &xi, &xis, &ctxt); +- if (!ret && !xbs.not_found) { +- /* +- * If succeed and that extended attribute existing in +- * external block, then we will remove it. +- */ +- xi.value = NULL; +- xi.value_len = 0; +- ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); +- } else if (ret == -ENOSPC) { +- if (di->i_xattr_loc && !xbs.xattr_bh) { +- ret = ocfs2_xattr_block_find(inode, name_index, +- name, &xbs); +- if (ret) +- goto cleanup; +- } +- /* +- * If no space in inode, we will set extended attribute +- * into external block. +- */ +- ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); +- if (ret) +- goto free; +- if (!xis.not_found) { +- /* +- * If succeed and that extended attribute +- * existing in inode, we will remove it. +- */ +- xi.value = NULL; +- xi.value_len = 0; +- ret = ocfs2_xattr_ibody_set(inode, &xi, +- &xis, &ctxt); +- } +- } ++ ctxt.handle = ocfs2_start_trans(osb, credits); ++ if (IS_ERR(ctxt.handle)) { ++ ret = PTR_ERR(ctxt.handle); ++ mlog_errno(ret); ++ goto cleanup; + } +-free: ++ ++ ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt); ++ ++ ocfs2_commit_trans(osb, ctxt.handle); ++ + if (ctxt.data_ac) + ocfs2_free_alloc_context(ctxt.data_ac); + if (ctxt.meta_ac) +@@ -2974,10 +3027,10 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + struct ocfs2_xattr_search *xs, + struct ocfs2_xattr_set_ctxt *ctxt) + { +- int ret, credits = OCFS2_SUBALLOC_ALLOC; ++ int ret; + u32 bit_off, len; + u64 blkno; +- handle_t *handle; ++ handle_t *handle = ctxt->handle; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct buffer_head *xb_bh = xs->xattr_bh; +@@ -2999,30 +3052,18 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + */ + down_write(&oi->ip_alloc_sem); + +- /* +- * We need more credits. One for the xattr block update and one +- * for each block of the new xattr bucket. +- */ +- credits += 1 + ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- handle = ocfs2_start_trans(osb, credits); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- goto out_sem; +- } +- + ret = ocfs2_journal_access(handle, inode, xb_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + ret = __ocfs2_claim_clusters(osb, handle, ctxt->data_ac, + 1, 1, &bit_off, &len); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + /* +@@ -3038,14 +3079,14 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + ret = ocfs2_init_xattr_bucket(xs->bucket, blkno); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, + OCFS2_JOURNAL_ACCESS_CREATE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xs->bucket); +@@ -3070,16 +3111,9 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + + xb->xb_flags = cpu_to_le16(xb_flags | OCFS2_XATTR_INDEXED); + +- ret = ocfs2_journal_dirty(handle, xb_bh); +- if (ret) { +- mlog_errno(ret); +- goto out_commit; +- } ++ ocfs2_journal_dirty(handle, xb_bh); + +-out_commit: +- ocfs2_commit_trans(osb, handle); +- +-out_sem: ++out: + up_write(&oi->ip_alloc_sem); + + return ret; +@@ -3105,6 +3139,7 @@ static int cmp_xe_offset(const void *a, const void *b) + * so that we can spare some space for insertion. + */ + static int ocfs2_defrag_xattr_bucket(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_bucket *bucket) + { + int ret, i; +@@ -3114,7 +3149,6 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + u64 blkno = bucket_blkno(bucket); + u16 xh_free_start; + size_t blocksize = inode->i_sb->s_blocksize; +- handle_t *handle; + struct ocfs2_xattr_entry *xe; + + /* +@@ -3133,19 +3167,11 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + for (i = 0; i < bucket->bu_blocks; i++, buf += blocksize) + memcpy(buf, bucket_block(bucket, i), blocksize); + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), bucket->bu_blocks); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- handle = NULL; +- mlog_errno(ret); +- goto out; +- } +- + ret = ocfs2_xattr_bucket_journal_access(handle, bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { + mlog_errno(ret); +- goto commit; ++ goto out; + } + + xh = (struct ocfs2_xattr_header *)bucket_buf; +@@ -3203,7 +3229,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + "bucket %llu\n", (unsigned long long)blkno); + + if (xh_free_start == end) +- goto commit; ++ goto out; + + memset(bucket_buf + xh_free_start, 0, end - xh_free_start); + xh->xh_free_start = cpu_to_le16(end); +@@ -3218,8 +3244,6 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + memcpy(bucket_block(bucket, i), buf, blocksize); + ocfs2_xattr_bucket_journal_dirty(handle, bucket); + +-commit: +- ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: + kfree(bucket_buf); + return ret; +@@ -3270,7 +3294,7 @@ static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode, + * 1 more for the update of the 1st bucket of the previous + * extent record. + */ +- credits = bpc / 2 + 1; ++ credits = bpc / 2 + 1 + handle->h_buffer_credits; + ret = ocfs2_extend_trans(handle, credits); + if (ret) { + mlog_errno(ret); +@@ -3662,7 +3686,7 @@ static int ocfs2_cp_xattr_cluster(struct inode *inode, + * We need to update the new cluster and 1 more for the update of + * the 1st bucket of the previous extent rec. + */ +- credits = bpc + 1; ++ credits = bpc + 1 + handle->h_buffer_credits; + ret = ocfs2_extend_trans(handle, credits); + if (ret) { + mlog_errno(ret); +@@ -3732,7 +3756,7 @@ static int ocfs2_divide_xattr_cluster(struct inode *inode, + u32 *first_hash) + { + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); +- int ret, credits = 2 * blk_per_bucket; ++ int ret, credits = 2 * blk_per_bucket + handle->h_buffer_credits; + + BUG_ON(OCFS2_XATTR_BUCKET_SIZE < OCFS2_SB(inode->i_sb)->s_clustersize); + +@@ -3845,12 +3869,12 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + int *extend, + struct ocfs2_xattr_set_ctxt *ctxt) + { +- int ret, credits; ++ int ret; + u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); + u32 prev_clusters = *num_clusters; + u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0; + u64 block; +- handle_t *handle = NULL; ++ handle_t *handle = ctxt->handle; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_extent_tree et; + +@@ -3861,16 +3885,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + + ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); + +- credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, +- clusters_to_add); +- handle = ocfs2_start_trans(osb, credits); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- handle = NULL; +- mlog_errno(ret); +- goto leave; +- } +- + ret = ocfs2_journal_access(handle, inode, root_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { +@@ -3924,18 +3938,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + } + } + +- if (handle->h_buffer_credits < credits) { +- /* +- * The journal has been restarted before, and don't +- * have enough space for the insertion, so extend it +- * here. +- */ +- ret = ocfs2_extend_trans(handle, credits); +- if (ret) { +- mlog_errno(ret); +- goto leave; +- } +- } + mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", + num_bits, (unsigned long long)block, v_start); + ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, +@@ -3946,15 +3948,10 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + } + + ret = ocfs2_journal_dirty(handle, root_bh); +- if (ret < 0) { ++ if (ret < 0) + mlog_errno(ret); +- goto leave; +- } + + leave: +- if (handle) +- ocfs2_commit_trans(osb, handle); +- + return ret; + } + +@@ -3963,6 +3960,7 @@ leave: + * We meet with start_bh. Only move half of the xattrs to the bucket after it. + */ + static int ocfs2_extend_xattr_bucket(struct inode *inode, ++ handle_t *handle, + struct buffer_head *first_bh, + struct buffer_head *start_bh, + u32 num_clusters) +@@ -3972,7 +3970,6 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, + u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); + u64 start_blk = start_bh->b_blocknr, end_blk; + u32 num_buckets = num_clusters * ocfs2_xattr_buckets_per_cluster(osb); +- handle_t *handle; + struct ocfs2_xattr_header *first_xh = + (struct ocfs2_xattr_header *)first_bh->b_data; + u16 bucket = le16_to_cpu(first_xh->xh_num_buckets); +@@ -3989,11 +3986,10 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, + * We will touch all the buckets after the start_bh(include it). + * Then we add one more bucket. + */ +- credits = end_blk - start_blk + 3 * blk_per_bucket + 1; +- handle = ocfs2_start_trans(osb, credits); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- handle = NULL; ++ credits = end_blk - start_blk + 3 * blk_per_bucket + 1 + ++ handle->h_buffer_credits; ++ ret = ocfs2_extend_trans(handle, credits); ++ if (ret) { + mlog_errno(ret); + goto out; + } +@@ -4002,14 +3998,14 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto commit; ++ goto out; + } + + while (end_blk != start_blk) { + ret = ocfs2_cp_xattr_bucket(inode, handle, end_blk, + end_blk + blk_per_bucket, 0); + if (ret) +- goto commit; ++ goto out; + end_blk -= blk_per_bucket; + } + +@@ -4020,8 +4016,6 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode, + le16_add_cpu(&first_xh->xh_num_buckets, 1); + ocfs2_journal_dirty(handle, first_bh); + +-commit: +- ocfs2_commit_trans(osb, handle); + out: + return ret; + } +@@ -4099,6 +4093,7 @@ static int ocfs2_add_new_xattr_bucket(struct inode *inode, + + if (extend) + ret = ocfs2_extend_xattr_bucket(inode, ++ ctxt->handle, + first_bh, + header_bh, + num_clusters); +@@ -4272,14 +4267,13 @@ set_new_name_value: + * space for the xattr insertion. + */ + static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, + u32 name_hash, + int local) + { + int ret; +- handle_t *handle = NULL; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + u64 blkno; + + mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n", +@@ -4296,14 +4290,6 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + } + } + +- handle = ocfs2_start_trans(osb, xs->bucket->bu_blocks); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- handle = NULL; +- mlog_errno(ret); +- goto out; +- } +- + ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { +@@ -4315,32 +4301,22 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode, + ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket); + + out: +- ocfs2_commit_trans(osb, handle); +- + return ret; + } + + static int ocfs2_xattr_value_update_size(struct inode *inode, ++ handle_t *handle, + struct buffer_head *xe_bh, + struct ocfs2_xattr_entry *xe, + u64 new_size) + { + int ret; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- handle_t *handle = NULL; +- +- handle = ocfs2_start_trans(osb, 1); +- if (IS_ERR(handle)) { +- ret = -ENOMEM; +- mlog_errno(ret); +- goto out; +- } + + ret = ocfs2_journal_access(handle, inode, xe_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { + mlog_errno(ret); +- goto out_commit; ++ goto out; + } + + xe->xe_value_size = cpu_to_le64(new_size); +@@ -4349,8 +4325,6 @@ static int ocfs2_xattr_value_update_size(struct inode *inode, + if (ret < 0) + mlog_errno(ret); + +-out_commit: +- ocfs2_commit_trans(osb, handle); + out: + return ret; + } +@@ -4407,7 +4381,8 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, + goto out; + } + +- ret = ocfs2_xattr_value_update_size(inode, header_bh, xe, len); ++ ret = ocfs2_xattr_value_update_size(inode, ctxt->handle, ++ header_bh, xe, len); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4439,6 +4414,7 @@ static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, + } + + static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_search *xs, + char *val, + int value_len) +@@ -4454,7 +4430,8 @@ static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode, + + xv = (struct ocfs2_xattr_value_root *)(xs->base + offset); + +- return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len); ++ return __ocfs2_xattr_set_value_outside(inode, handle, ++ xv, val, value_len); + } + + static int ocfs2_rm_xattr_cluster(struct inode *inode, +@@ -4547,27 +4524,19 @@ out: + } + + static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, ++ handle_t *handle, + struct ocfs2_xattr_search *xs) + { +- handle_t *handle = NULL; + struct ocfs2_xattr_header *xh = bucket_xh(xs->bucket); + struct ocfs2_xattr_entry *last = &xh->xh_entries[ + le16_to_cpu(xh->xh_count) - 1]; + int ret = 0; + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), +- ocfs2_blocks_per_xattr_bucket(inode->i_sb)); +- if (IS_ERR(handle)) { +- ret = PTR_ERR(handle); +- mlog_errno(ret); +- return; +- } +- + ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); +- goto out_commit; ++ return; + } + + /* Remove the old entry. */ +@@ -4577,9 +4546,6 @@ static void ocfs2_xattr_bucket_remove_xs(struct inode *inode, + le16_add_cpu(&xh->xh_count, -1); + + ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket); +- +-out_commit: +- ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + } + + /* +@@ -4645,7 +4611,8 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, + xi->value_len = OCFS2_XATTR_ROOT_SIZE; + } + +- ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local); ++ ret = ocfs2_xattr_set_entry_in_bucket(inode, ctxt->handle, xi, xs, ++ name_hash, local); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4666,13 +4633,14 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, + * storage and we have allocated xattr already, + * so need to remove it. + */ +- ocfs2_xattr_bucket_remove_xs(inode, xs); ++ ocfs2_xattr_bucket_remove_xs(inode, ctxt->handle, xs); + } + goto out; + } + + set_value_outside: +- ret = ocfs2_xattr_bucket_set_value_outside(inode, xs, val, value_len); ++ ret = ocfs2_xattr_bucket_set_value_outside(inode, ctxt->handle, ++ xs, val, value_len); + out: + return ret; + } +@@ -4785,7 +4753,8 @@ try_again: + * name/value will be moved, the xe shouldn't be changed + * in xs. + */ +- ret = ocfs2_defrag_xattr_bucket(inode, xs->bucket); ++ ret = ocfs2_defrag_xattr_bucket(inode, ctxt->handle, ++ xs->bucket); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4865,6 +4834,13 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + + ocfs2_init_dealloc_ctxt(&ctxt.dealloc); + ++ ctxt.handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); ++ if (IS_ERR(ctxt.handle)) { ++ ret = PTR_ERR(ctxt.handle); ++ mlog_errno(ret); ++ goto out; ++ } ++ + for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { + xe = &xh->xh_entries[i]; + if (ocfs2_xattr_is_local(xe)) +@@ -4879,9 +4855,10 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + } + } + ++ ret = ocfs2_commit_trans(osb, ctxt.handle); + ocfs2_schedule_truncate_log_flush(osb, 1); + ocfs2_run_deallocs(osb, &ctxt.dealloc); +- ++out: + return ret; + } + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Move-clusters-free-into-dealloc.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Move-clusters-free-into-dealloc.patch new file mode 100644 index 000000000..bc04bb4ae --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Move-clusters-free-into-dealloc.patch @@ -0,0 +1,62 @@ +From: Tao Ma +Date: Wed, 12 Nov 2008 08:26:59 +0800 +Subject: ocfs2/xattr: Move clusters free into dealloc. +Patch-mainline: 2.6.29 + +Move clusters free process into dealloc context so that +they can be freed after the transaction. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 14 +------------- + 1 files changed, 1 insertions(+), 13 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 4501c63..f1da381 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -457,7 +457,6 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + int ret; + u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct inode *tl_inode = osb->osb_tl_inode; + handle_t *handle; + struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_extent_tree et; +@@ -470,16 +469,6 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + return ret; + } + +- mutex_lock(&tl_inode->i_mutex); +- +- if (ocfs2_truncate_log_needs_flush(osb)) { +- ret = __ocfs2_flush_truncate_log(osb); +- if (ret < 0) { +- mlog_errno(ret); +- goto out; +- } +- } +- + handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); +@@ -509,14 +498,13 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + goto out_commit; + } + +- ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len); ++ ret = ocfs2_cache_cluster_dealloc(dealloc, phys_blkno, len); + if (ret) + mlog_errno(ret); + + out_commit: + ocfs2_commit_trans(osb, handle); + out: +- mutex_unlock(&tl_inode->i_mutex); + + if (meta_ac) + ocfs2_free_alloc_context(meta_ac); +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Only-extend-xattr-bucket-in-need.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Only-extend-xattr-bucket-in-need.patch new file mode 100644 index 000000000..55294e525 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Only-extend-xattr-bucket-in-need.patch @@ -0,0 +1,36 @@ +From: Tao Ma +Date: Wed, 12 Nov 2008 08:26:57 +0800 +Subject: ocfs2/xattr: Only extend xattr bucket in need. +Patch-mainline: 2.6.29 + +When the first block of a bucket is filled up with xattr +entries, we normally extend the bucket. But if we are +just replace one xattr with small length, we don't need +to extend it. This is important since we will calculate +what we need before the transaction and in this situation +no resources will be allocated. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index d8fc714..4501c63 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -4564,7 +4564,9 @@ try_again: + free, need, max_free, le16_to_cpu(xh->xh_free_start), + le16_to_cpu(xh->xh_name_value_len)); + +- if (free < need || count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) { ++ if (free < need || ++ (xs->not_found && ++ count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb))) { + if (need <= max_free && + count < ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) { + /* +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Only-set-buffer-update-if-it-doesn-t-ex.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Only-set-buffer-update-if-it-doesn-t-ex.patch new file mode 100644 index 000000000..6eb0a0b9e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Only-set-buffer-update-if-it-doesn-t-ex.patch @@ -0,0 +1,38 @@ +From: Tao Ma +Date: Thu, 6 Nov 2008 08:10:48 +0800 +Subject: ocfs2/xattr: Only set buffer update if it doesn't exist in cache. +Patch-mainline: 2.6.29 + +When we call ocfs2_init_xattr_bucket, we deem that the new buffer head +will be written to disk immediately, so we just use sb_getblk. But in +some cases the buffer may have already been in ocfs2 uptodate cache, +so we only call ocfs2_set_buffer_uptodate if the buffer head isn't +in the cache. + +Signed-off-by: Tao Ma +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 6 ++++-- + 1 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 87cf39d..d8fc714 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -219,8 +219,10 @@ static int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket, + break; + } + +- ocfs2_set_new_buffer_uptodate(bucket->bu_inode, +- bucket->bu_bhs[i]); ++ if (!ocfs2_buffer_uptodate(bucket->bu_inode, ++ bucket->bu_bhs[i])) ++ ocfs2_set_new_buffer_uptodate(bucket->bu_inode, ++ bucket->bu_bhs[i]); + } + + if (rc) +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Remove-additional-bucket-allocation-in.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Remove-additional-bucket-allocation-in.patch new file mode 100644 index 000000000..469079040 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Remove-additional-bucket-allocation-in.patch @@ -0,0 +1,83 @@ +From: Tao Ma +Date: Thu, 6 Nov 2008 08:10:47 +0800 +Subject: ocfs2/xattr: Remove additional bucket allocation in bucket defragment. +Patch-mainline: 2.6.29 + +Joel has refactored xattr bucket and make xattr bucket a general +wrapper. So in ocfs2_defrag_xattr_bucket, we have already passed the +bucket in, so there is no need to allocate a new one and read it. + +Signed-off-by: Tao Ma +Signed-off-by: Joel Becker +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 26 +++++++------------------- + 1 files changed, 7 insertions(+), 19 deletions(-) + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index 029a9f4..87cf39d 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -2898,7 +2898,6 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + size_t blocksize = inode->i_sb->s_blocksize; + handle_t *handle; + struct ocfs2_xattr_entry *xe; +- struct ocfs2_xattr_bucket *wb = NULL; + + /* + * In order to make the operation more efficient and generic, +@@ -2912,21 +2911,11 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + goto out; + } + +- wb = ocfs2_xattr_bucket_new(inode); +- if (!wb) { +- ret = -ENOMEM; +- goto out; +- } +- +- ret = ocfs2_read_xattr_bucket(wb, blkno); +- if (ret) +- goto out; +- + buf = bucket_buf; +- for (i = 0; i < wb->bu_blocks; i++, buf += blocksize) +- memcpy(buf, bucket_block(wb, i), blocksize); ++ for (i = 0; i < bucket->bu_blocks; i++, buf += blocksize) ++ memcpy(buf, bucket_block(bucket, i), blocksize); + +- handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), wb->bu_blocks); ++ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), bucket->bu_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + handle = NULL; +@@ -2934,7 +2923,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + goto out; + } + +- ret = ocfs2_xattr_bucket_journal_access(handle, wb, ++ ret = ocfs2_xattr_bucket_journal_access(handle, bucket, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret < 0) { + mlog_errno(ret); +@@ -3007,14 +2996,13 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode, + cmp_xe, swap_xe); + + buf = bucket_buf; +- for (i = 0; i < wb->bu_blocks; i++, buf += blocksize) +- memcpy(bucket_block(wb, i), buf, blocksize); +- ocfs2_xattr_bucket_journal_dirty(handle, wb); ++ for (i = 0; i < bucket->bu_blocks; i++, buf += blocksize) ++ memcpy(bucket_block(bucket, i), buf, blocksize); ++ ocfs2_xattr_bucket_journal_dirty(handle, bucket); + + commit: + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); + out: +- ocfs2_xattr_bucket_free(wb); + kfree(bucket_buf); + return ret; + } +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Reserve-meta-data-at-the-beginning-of-o.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Reserve-meta-data-at-the-beginning-of-o.patch new file mode 100644 index 000000000..74cf9143c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr-Reserve-meta-data-at-the-beginning-of-o.patch @@ -0,0 +1,1017 @@ +From: Tao Ma +Date: Wed, 12 Nov 2008 08:27:00 +0800 +Subject: ocfs2/xattr: Reserve meta/data at the beginning of ocfs2_xattr_set. +Patch-mainline: 2.6.29 + +In ocfs2 xattr set, we reserve metadata and clusters in any place +they are needed. It is time-consuming and ineffective, so this +patch try to reserve metadata and clusters at the beginning of +ocfs2_xattr_set. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/alloc.h | 4 + + fs/ocfs2/xattr.c | 483 ++++++++++++++++++++++++++++++++++++++++-------------- + 2 files changed, 361 insertions(+), 126 deletions(-) + +diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h +index c301cf2..3eb735e 100644 +--- a/fs/ocfs2/alloc.h ++++ b/fs/ocfs2/alloc.h +@@ -176,6 +176,10 @@ static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c) + } + int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, + u64 blkno, unsigned int bit); ++static inline int ocfs2_dealloc_has_cluster(struct ocfs2_cached_dealloc_ctxt *c) ++{ ++ return c->c_global_allocator != NULL; ++} + int ocfs2_run_deallocs(struct ocfs2_super *osb, + struct ocfs2_cached_dealloc_ctxt *ctxt); + +diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c +index f1da381..4fd201a 100644 +--- a/fs/ocfs2/xattr.c ++++ b/fs/ocfs2/xattr.c +@@ -71,6 +71,12 @@ struct ocfs2_xattr_bucket { + int bu_blocks; + }; + ++struct ocfs2_xattr_set_ctxt { ++ struct ocfs2_alloc_context *meta_ac; ++ struct ocfs2_alloc_context *data_ac; ++ struct ocfs2_cached_dealloc_ctxt dealloc; ++}; ++ + #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) + #define OCFS2_XATTR_INLINE_SIZE 80 + +@@ -133,11 +139,13 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode, + size_t buffer_size); + + static int ocfs2_xattr_create_index_block(struct inode *inode, +- struct ocfs2_xattr_search *xs); ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt); + + static int ocfs2_xattr_set_entry_index_block(struct inode *inode, + struct ocfs2_xattr_info *xi, +- struct ocfs2_xattr_search *xs); ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt); + + static int ocfs2_delete_xattr_index_block(struct inode *inode, + struct buffer_head *xb_bh); +@@ -334,14 +342,13 @@ static void ocfs2_xattr_hash_entry(struct inode *inode, + static int ocfs2_xattr_extend_allocation(struct inode *inode, + u32 clusters_to_add, + struct buffer_head *xattr_bh, +- struct ocfs2_xattr_value_root *xv) ++ struct ocfs2_xattr_value_root *xv, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int status = 0; + int restart_func = 0; + int credits = 0; + handle_t *handle = NULL; +- struct ocfs2_alloc_context *data_ac = NULL; +- struct ocfs2_alloc_context *meta_ac = NULL; + enum ocfs2_alloc_restarted why; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters); +@@ -353,13 +360,6 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode, + + restart_all: + +- status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, +- &data_ac, &meta_ac); +- if (status) { +- mlog_errno(status); +- goto leave; +- } +- + credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, + clusters_to_add); + handle = ocfs2_start_trans(osb, credits); +@@ -386,8 +386,8 @@ restarted_transaction: + 0, + &et, + handle, +- data_ac, +- meta_ac, ++ ctxt->data_ac, ++ ctxt->meta_ac, + &why); + if ((status < 0) && (status != -EAGAIN)) { + if (status != -ENOSPC) +@@ -432,14 +432,6 @@ leave: + ocfs2_commit_trans(osb, handle); + handle = NULL; + } +- if (data_ac) { +- ocfs2_free_alloc_context(data_ac); +- data_ac = NULL; +- } +- if (meta_ac) { +- ocfs2_free_alloc_context(meta_ac); +- meta_ac = NULL; +- } + if ((!status) && restart_func) { + restart_func = 0; + goto restart_all; +@@ -452,23 +444,16 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + struct buffer_head *root_bh, + struct ocfs2_xattr_value_root *xv, + u32 cpos, u32 phys_cpos, u32 len, +- struct ocfs2_cached_dealloc_ctxt *dealloc) ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret; + u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + handle_t *handle; +- struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_extent_tree et; + + ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv); + +- ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); +- if (ret) { +- mlog_errno(ret); +- return ret; +- } +- + handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); +@@ -483,8 +468,8 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + goto out_commit; + } + +- ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac, +- dealloc); ++ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, ctxt->meta_ac, ++ &ctxt->dealloc); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -498,17 +483,13 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, + goto out_commit; + } + +- ret = ocfs2_cache_cluster_dealloc(dealloc, phys_blkno, len); ++ ret = ocfs2_cache_cluster_dealloc(&ctxt->dealloc, phys_blkno, len); + if (ret) + mlog_errno(ret); + + out_commit: + ocfs2_commit_trans(osb, handle); + out: +- +- if (meta_ac) +- ocfs2_free_alloc_context(meta_ac); +- + return ret; + } + +@@ -516,15 +497,12 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, + u32 old_clusters, + u32 new_clusters, + struct buffer_head *root_bh, +- struct ocfs2_xattr_value_root *xv) ++ struct ocfs2_xattr_value_root *xv, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret = 0; + u32 trunc_len, cpos, phys_cpos, alloc_size; + u64 block; +- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); +- struct ocfs2_cached_dealloc_ctxt dealloc; +- +- ocfs2_init_dealloc_ctxt(&dealloc); + + if (old_clusters <= new_clusters) + return 0; +@@ -544,7 +522,7 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, + + ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos, + phys_cpos, alloc_size, +- &dealloc); ++ ctxt); + if (ret) { + mlog_errno(ret); + goto out; +@@ -558,16 +536,14 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, + } + + out: +- ocfs2_schedule_truncate_log_flush(osb, 1); +- ocfs2_run_deallocs(osb, &dealloc); +- + return ret; + } + + static int ocfs2_xattr_value_truncate(struct inode *inode, + struct buffer_head *root_bh, + struct ocfs2_xattr_value_root *xv, +- int len) ++ int len, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret; + u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len); +@@ -579,11 +555,11 @@ static int ocfs2_xattr_value_truncate(struct inode *inode, + if (new_clusters > old_clusters) + ret = ocfs2_xattr_extend_allocation(inode, + new_clusters - old_clusters, +- root_bh, xv); ++ root_bh, xv, ctxt); + else + ret = ocfs2_xattr_shrink_size(inode, + old_clusters, new_clusters, +- root_bh, xv); ++ root_bh, xv, ctxt); + + return ret; + } +@@ -1167,6 +1143,7 @@ out: + static int ocfs2_xattr_set_value_outside(struct inode *inode, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt, + size_t offs) + { + size_t name_len = strlen(xi->name); +@@ -1186,7 +1163,7 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode, + xv->xr_list.l_next_free_rec = 0; + + ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv, +- xi->value_len); ++ xi->value_len, ctxt); + if (ret < 0) { + mlog_errno(ret); + return ret; +@@ -1317,6 +1294,7 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode, + static int ocfs2_xattr_set_entry(struct inode *inode, + struct ocfs2_xattr_info *xi, + struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt, + int flag) + { + struct ocfs2_xattr_entry *last; +@@ -1387,7 +1365,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + if (ocfs2_xattr_is_local(xs->here) && size == size_l) { + /* Replace existing local xattr with tree root */ + ret = ocfs2_xattr_set_value_outside(inode, xi, xs, +- offs); ++ ctxt, offs); + if (ret < 0) + mlog_errno(ret); + goto out; +@@ -1406,7 +1384,8 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + ret = ocfs2_xattr_value_truncate(inode, + xs->xattr_bh, + xv, +- xi->value_len); ++ xi->value_len, ++ ctxt); + if (ret < 0) { + mlog_errno(ret); + goto out; +@@ -1436,7 +1415,8 @@ static int ocfs2_xattr_set_entry(struct inode *inode, + ret = ocfs2_xattr_value_truncate(inode, + xs->xattr_bh, + xv, +- 0); ++ 0, ++ ctxt); + if (ret < 0) + mlog_errno(ret); + } +@@ -1531,7 +1511,7 @@ out_commit: + * This is the second step for value size > INLINE_SIZE. + */ + size_t offs = le16_to_cpu(xs->here->xe_name_offset); +- ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs); ++ ret = ocfs2_xattr_set_value_outside(inode, xi, xs, ctxt, offs); + if (ret < 0) { + int ret2; + +@@ -1555,6 +1535,10 @@ static int ocfs2_remove_value_outside(struct inode*inode, + struct ocfs2_xattr_header *header) + { + int ret = 0, i; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; ++ ++ ocfs2_init_dealloc_ctxt(&ctxt.dealloc); + + for (i = 0; i < le16_to_cpu(header->xh_count); i++) { + struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; +@@ -1567,14 +1551,17 @@ static int ocfs2_remove_value_outside(struct inode*inode, + le16_to_cpu(entry->xe_name_offset); + xv = (struct ocfs2_xattr_value_root *) + (val + OCFS2_XATTR_SIZE(entry->xe_name_len)); +- ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0); ++ ret = ocfs2_xattr_value_truncate(inode, bh, xv, ++ 0, &ctxt); + if (ret < 0) { + mlog_errno(ret); +- return ret; ++ break; + } + } + } + ++ ocfs2_schedule_truncate_log_flush(osb, 1); ++ ocfs2_run_deallocs(osb, &ctxt.dealloc); + return ret; + } + +@@ -1836,7 +1823,8 @@ static int ocfs2_xattr_ibody_find(struct inode *inode, + */ + static int ocfs2_xattr_ibody_set(struct inode *inode, + struct ocfs2_xattr_info *xi, +- struct ocfs2_xattr_search *xs) ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + struct ocfs2_inode_info *oi = OCFS2_I(inode); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; +@@ -1853,7 +1841,7 @@ static int ocfs2_xattr_ibody_set(struct inode *inode, + } + } + +- ret = ocfs2_xattr_set_entry(inode, xi, xs, ++ ret = ocfs2_xattr_set_entry(inode, xi, xs, ctxt, + (OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL)); + out: + up_write(&oi->ip_alloc_sem); +@@ -1926,12 +1914,12 @@ cleanup: + */ + static int ocfs2_xattr_block_set(struct inode *inode, + struct ocfs2_xattr_info *xi, +- struct ocfs2_xattr_search *xs) ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + struct buffer_head *new_bh = NULL; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; +- struct ocfs2_alloc_context *meta_ac = NULL; + handle_t *handle = NULL; + struct ocfs2_xattr_block *xblk = NULL; + u16 suballoc_bit_start; +@@ -1940,15 +1928,6 @@ static int ocfs2_xattr_block_set(struct inode *inode, + int ret; + + if (!xs->xattr_bh) { +- /* +- * Alloc one external block for extended attribute +- * outside of inode. +- */ +- ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); +- if (ret < 0) { +- mlog_errno(ret); +- goto out; +- } + handle = ocfs2_start_trans(osb, + OCFS2_XATTR_BLOCK_CREATE_CREDITS); + if (IS_ERR(handle)) { +@@ -1963,7 +1942,7 @@ static int ocfs2_xattr_block_set(struct inode *inode, + goto out_commit; + } + +- ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1, ++ ret = ocfs2_claim_metadata(osb, handle, ctxt->meta_ac, 1, + &suballoc_bit_start, &num_got, + &first_blkno); + if (ret < 0) { +@@ -1996,7 +1975,6 @@ static int ocfs2_xattr_block_set(struct inode *inode, + xs->end = (void *)xblk + inode->i_sb->s_blocksize; + xs->here = xs->header->xh_entries; + +- + ret = ocfs2_journal_dirty(handle, new_bh); + if (ret < 0) { + mlog_errno(ret); +@@ -2009,8 +1987,6 @@ static int ocfs2_xattr_block_set(struct inode *inode, + out_commit: + ocfs2_commit_trans(osb, handle); + out: +- if (meta_ac) +- ocfs2_free_alloc_context(meta_ac); + if (ret < 0) + return ret; + } else +@@ -2018,22 +1994,266 @@ out: + + if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) { + /* Set extended attribute into external block */ +- ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL); ++ ret = ocfs2_xattr_set_entry(inode, xi, xs, ctxt, ++ OCFS2_HAS_XATTR_FL); + if (!ret || ret != -ENOSPC) + goto end; + +- ret = ocfs2_xattr_create_index_block(inode, xs); ++ ret = ocfs2_xattr_create_index_block(inode, xs, ctxt); + if (ret) + goto end; + } + +- ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs); ++ ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs, ctxt); + + end: + + return ret; + } + ++/* Check whether the new xattr can be inserted into the inode. */ ++static int ocfs2_xattr_can_be_in_inode(struct inode *inode, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xs) ++{ ++ u64 value_size; ++ struct ocfs2_xattr_entry *last; ++ int free, i; ++ size_t min_offs = xs->end - xs->base; ++ ++ if (!xs->header) ++ return 0; ++ ++ last = xs->header->xh_entries; ++ ++ for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) { ++ size_t offs = le16_to_cpu(last->xe_name_offset); ++ if (offs < min_offs) ++ min_offs = offs; ++ last += 1; ++ } ++ ++ free = min_offs - ((void *)last - xs->base) - sizeof(__u32); ++ if (free < 0) ++ return 0; ++ ++ BUG_ON(!xs->not_found); ++ ++ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) ++ value_size = OCFS2_XATTR_ROOT_SIZE; ++ else ++ value_size = OCFS2_XATTR_SIZE(xi->value_len); ++ ++ if (free >= sizeof(struct ocfs2_xattr_entry) + ++ OCFS2_XATTR_SIZE(strlen(xi->name)) + value_size) ++ return 1; ++ ++ return 0; ++} ++ ++static int ocfs2_calc_xattr_set_need(struct inode *inode, ++ struct ocfs2_dinode *di, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xis, ++ struct ocfs2_xattr_search *xbs, ++ int *clusters_need, ++ int *meta_need) ++{ ++ int ret = 0, old_in_xb = 0; ++ int clusters_add = 0, meta_add = 0; ++ struct buffer_head *bh = NULL; ++ struct ocfs2_xattr_block *xb = NULL; ++ struct ocfs2_xattr_entry *xe = NULL; ++ struct ocfs2_xattr_value_root *xv = NULL; ++ char *base = NULL; ++ int name_offset, name_len = 0; ++ u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, ++ xi->value_len); ++ u64 value_size; ++ ++ /* ++ * delete a xattr doesn't need metadata and cluster allocation. ++ * so return. ++ */ ++ if (!xi->value) ++ goto out; ++ ++ if (xis->not_found && xbs->not_found) { ++ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) ++ clusters_add += new_clusters; ++ ++ goto meta_guess; ++ } ++ ++ if (!xis->not_found) { ++ xe = xis->here; ++ name_offset = le16_to_cpu(xe->xe_name_offset); ++ name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); ++ base = xis->base; ++ } else { ++ int i, block_off; ++ xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data; ++ xe = xbs->here; ++ name_offset = le16_to_cpu(xe->xe_name_offset); ++ name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); ++ i = xbs->here - xbs->header->xh_entries; ++ old_in_xb = 1; ++ ++ if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { ++ ret = ocfs2_xattr_bucket_get_name_value(inode, ++ bucket_xh(xbs->bucket), ++ i, &block_off, ++ &name_offset); ++ base = bucket_block(xbs->bucket, block_off); ++ } else ++ base = xbs->base; ++ } ++ ++ /* do cluster allocation guess first. */ ++ value_size = le64_to_cpu(xe->xe_value_size); ++ ++ if (old_in_xb) { ++ /* ++ * In xattr set, we always try to set the xe in inode first, ++ * so if it can be inserted into inode successfully, the old ++ * one will be removed from the xattr block, and this xattr ++ * will be inserted into inode as a new xattr in inode. ++ */ ++ if (ocfs2_xattr_can_be_in_inode(inode, xi, xis)) { ++ clusters_add += new_clusters; ++ goto out; ++ } ++ } ++ ++ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) { ++ /* the new values will be stored outside. */ ++ u32 old_clusters = 0; ++ ++ if (!ocfs2_xattr_is_local(xe)) { ++ old_clusters = ocfs2_clusters_for_bytes(inode->i_sb, ++ value_size); ++ xv = (struct ocfs2_xattr_value_root *) ++ (base + name_offset + name_len); ++ } else ++ xv = &def_xv.xv; ++ ++ if (old_clusters >= new_clusters) ++ goto out; ++ else { ++ meta_add += ocfs2_extend_meta_needed(&xv->xr_list); ++ clusters_add += new_clusters - old_clusters; ++ goto out; ++ } ++ } else { ++ /* ++ * Now the new value will be stored inside. So if the new ++ * value is smaller than the size of value root or the old ++ * value, we don't need any allocation, otherwise we have ++ * to guess metadata allocation. ++ */ ++ if ((ocfs2_xattr_is_local(xe) && value_size >= xi->value_len) || ++ (!ocfs2_xattr_is_local(xe) && ++ OCFS2_XATTR_ROOT_SIZE >= xi->value_len)) ++ goto out; ++ } ++ ++meta_guess: ++ /* calculate metadata allocation. */ ++ if (di->i_xattr_loc) { ++ if (!xbs->xattr_bh) { ++ ret = ocfs2_read_block(inode, ++ le64_to_cpu(di->i_xattr_loc), ++ &bh); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ ++ xb = (struct ocfs2_xattr_block *)bh->b_data; ++ } else ++ xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data; ++ ++ if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { ++ struct ocfs2_extent_list *el = ++ &xb->xb_attrs.xb_root.xt_list; ++ meta_add += ocfs2_extend_meta_needed(el); ++ } ++ ++ /* ++ * This cluster will be used either for new bucket or for ++ * new xattr block. ++ * If the cluster size is the same as the bucket size, one ++ * more is needed since we may need to extend the bucket ++ * also. ++ */ ++ clusters_add += 1; ++ if (OCFS2_XATTR_BUCKET_SIZE == ++ OCFS2_SB(inode->i_sb)->s_clustersize) ++ clusters_add += 1; ++ } else ++ meta_add += 1; ++out: ++ if (clusters_need) ++ *clusters_need = clusters_add; ++ if (meta_need) ++ *meta_need = meta_add; ++ brelse(bh); ++ return ret; ++} ++ ++static int ocfs2_init_xattr_set_ctxt(struct inode *inode, ++ struct ocfs2_dinode *di, ++ struct ocfs2_xattr_info *xi, ++ struct ocfs2_xattr_search *xis, ++ struct ocfs2_xattr_search *xbs, ++ struct ocfs2_xattr_set_ctxt *ctxt) ++{ ++ int clusters_add, meta_add, ret; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ ++ memset(ctxt, 0, sizeof(struct ocfs2_xattr_set_ctxt)); ++ ++ ocfs2_init_dealloc_ctxt(&ctxt->dealloc); ++ ++ ret = ocfs2_calc_xattr_set_need(inode, di, xi, xis, xbs, ++ &clusters_add, &meta_add); ++ if (ret) { ++ mlog_errno(ret); ++ return ret; ++ } ++ ++ mlog(0, "Set xattr %s, reserve meta blocks = %d, clusters = %d\n", ++ xi->name, meta_add, clusters_add); ++ ++ if (meta_add) { ++ ret = ocfs2_reserve_new_metadata_blocks(osb, meta_add, ++ &ctxt->meta_ac); ++ if (ret) { ++ mlog_errno(ret); ++ goto out; ++ } ++ } ++ ++ if (clusters_add) { ++ ret = ocfs2_reserve_clusters(osb, clusters_add, &ctxt->data_ac); ++ if (ret) ++ mlog_errno(ret); ++ } ++out: ++ if (ret) { ++ if (ctxt->meta_ac) { ++ ocfs2_free_alloc_context(ctxt->meta_ac); ++ ctxt->meta_ac = NULL; ++ } ++ ++ /* ++ * We cannot have an error and a non null ctxt->data_ac. ++ */ ++ } ++ ++ return ret; ++} ++ + /* + * ocfs2_xattr_set() + * +@@ -2051,6 +2271,8 @@ int ocfs2_xattr_set(struct inode *inode, + struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di; + int ret; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; + + struct ocfs2_xattr_info xi = { + .name_index = name_index, +@@ -2115,15 +2337,21 @@ int ocfs2_xattr_set(struct inode *inode, + goto cleanup; + } + ++ ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis, &xbs, &ctxt); ++ if (ret) { ++ mlog_errno(ret); ++ goto cleanup; ++ } ++ + if (!value) { + /* Remove existing extended attribute */ + if (!xis.not_found) +- ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); ++ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis, &ctxt); + else if (!xbs.not_found) +- ret = ocfs2_xattr_block_set(inode, &xi, &xbs); ++ ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); + } else { + /* We always try to set extended attribute into inode first*/ +- ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); ++ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis, &ctxt); + if (!ret && !xbs.not_found) { + /* + * If succeed and that extended attribute existing in +@@ -2131,7 +2359,7 @@ int ocfs2_xattr_set(struct inode *inode, + */ + xi.value = NULL; + xi.value_len = 0; +- ret = ocfs2_xattr_block_set(inode, &xi, &xbs); ++ ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); + } else if (ret == -ENOSPC) { + if (di->i_xattr_loc && !xbs.xattr_bh) { + ret = ocfs2_xattr_block_find(inode, name_index, +@@ -2143,9 +2371,9 @@ int ocfs2_xattr_set(struct inode *inode, + * If no space in inode, we will set extended attribute + * into external block. + */ +- ret = ocfs2_xattr_block_set(inode, &xi, &xbs); ++ ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); + if (ret) +- goto cleanup; ++ goto free; + if (!xis.not_found) { + /* + * If succeed and that extended attribute +@@ -2153,10 +2381,19 @@ int ocfs2_xattr_set(struct inode *inode, + */ + xi.value = NULL; + xi.value_len = 0; +- ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); ++ ret = ocfs2_xattr_ibody_set(inode, &xi, ++ &xis, &ctxt); + } + } + } ++free: ++ if (ctxt.data_ac) ++ ocfs2_free_alloc_context(ctxt.data_ac); ++ if (ctxt.meta_ac) ++ ocfs2_free_alloc_context(ctxt.meta_ac); ++ if (ocfs2_dealloc_has_cluster(&ctxt.dealloc)) ++ ocfs2_schedule_truncate_log_flush(osb, 1); ++ ocfs2_run_deallocs(osb, &ctxt.dealloc); + cleanup: + up_write(&OCFS2_I(inode)->ip_xattr_sem); + ocfs2_inode_unlock(inode, 1); +@@ -2734,7 +2971,8 @@ static void ocfs2_xattr_update_xattr_search(struct inode *inode, + } + + static int ocfs2_xattr_create_index_block(struct inode *inode, +- struct ocfs2_xattr_search *xs) ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret, credits = OCFS2_SUBALLOC_ALLOC; + u32 bit_off, len; +@@ -2742,7 +2980,6 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + handle_t *handle; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_inode_info *oi = OCFS2_I(inode); +- struct ocfs2_alloc_context *data_ac; + struct buffer_head *xb_bh = xs->xattr_bh; + struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)xb_bh->b_data; +@@ -2755,12 +2992,6 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + BUG_ON(xb_flags & OCFS2_XATTR_INDEXED); + BUG_ON(!xs->bucket); + +- ret = ocfs2_reserve_clusters(osb, 1, &data_ac); +- if (ret) { +- mlog_errno(ret); +- goto out; +- } +- + /* + * XXX: + * We can use this lock for now, and maybe move to a dedicated mutex +@@ -2787,7 +3018,8 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, + goto out_commit; + } + +- ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len); ++ ret = __ocfs2_claim_clusters(osb, handle, ctxt->data_ac, ++ 1, 1, &bit_off, &len); + if (ret) { + mlog_errno(ret); + goto out_commit; +@@ -2850,10 +3082,6 @@ out_commit: + out_sem: + up_write(&oi->ip_alloc_sem); + +-out: +- if (data_ac) +- ocfs2_free_alloc_context(data_ac); +- + return ret; + } + +@@ -3614,7 +3842,8 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + u32 *num_clusters, + u32 prev_cpos, + u64 prev_blkno, +- int *extend) ++ int *extend, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret, credits; + u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); +@@ -3622,8 +3851,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0; + u64 block; + handle_t *handle = NULL; +- struct ocfs2_alloc_context *data_ac = NULL; +- struct ocfs2_alloc_context *meta_ac = NULL; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + struct ocfs2_extent_tree et; + +@@ -3634,13 +3861,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + + ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); + +- ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, +- &data_ac, &meta_ac); +- if (ret) { +- mlog_errno(ret); +- goto leave; +- } +- + credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, + clusters_to_add); + handle = ocfs2_start_trans(osb, credits); +@@ -3658,7 +3878,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + goto leave; + } + +- ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1, ++ ret = __ocfs2_claim_clusters(osb, handle, ctxt->data_ac, 1, + clusters_to_add, &bit_off, &num_bits); + if (ret < 0) { + if (ret != -ENOSPC) +@@ -3719,7 +3939,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", + num_bits, (unsigned long long)block, v_start); + ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, +- num_bits, 0, meta_ac); ++ num_bits, 0, ctxt->meta_ac); + if (ret < 0) { + mlog_errno(ret); + goto leave; +@@ -3734,10 +3954,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, + leave: + if (handle) + ocfs2_commit_trans(osb, handle); +- if (data_ac) +- ocfs2_free_alloc_context(data_ac); +- if (meta_ac) +- ocfs2_free_alloc_context(meta_ac); + + return ret; + } +@@ -3821,7 +4037,8 @@ out: + */ + static int ocfs2_add_new_xattr_bucket(struct inode *inode, + struct buffer_head *xb_bh, +- struct buffer_head *header_bh) ++ struct buffer_head *header_bh, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + struct ocfs2_xattr_header *first_xh = NULL; + struct buffer_head *first_bh = NULL; +@@ -3872,7 +4089,8 @@ static int ocfs2_add_new_xattr_bucket(struct inode *inode, + &num_clusters, + e_cpos, + p_blkno, +- &extend); ++ &extend, ++ ctxt); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4147,7 +4365,8 @@ out: + static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, + struct buffer_head *header_bh, + int xe_off, +- int len) ++ int len, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret, offset; + u64 value_blk; +@@ -4182,7 +4401,7 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, + + mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n", + xe_off, (unsigned long long)header_bh->b_blocknr, len); +- ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len); ++ ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len, ctxt); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4200,8 +4419,9 @@ out: + } + + static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, +- struct ocfs2_xattr_search *xs, +- int len) ++ struct ocfs2_xattr_search *xs, ++ int len, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret, offset; + struct ocfs2_xattr_entry *xe = xs->here; +@@ -4211,7 +4431,7 @@ static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, + + offset = xe - xh->xh_entries; + ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket->bu_bhs[0], +- offset, len); ++ offset, len, ctxt); + if (ret) + mlog_errno(ret); + +@@ -4375,7 +4595,8 @@ out_commit: + */ + static int ocfs2_xattr_set_in_bucket(struct inode *inode, + struct ocfs2_xattr_info *xi, +- struct ocfs2_xattr_search *xs) ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + int ret, local = 1; + size_t value_len; +@@ -4403,7 +4624,8 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, + value_len = 0; + + ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, +- value_len); ++ value_len, ++ ctxt); + if (ret) + goto out; + +@@ -4434,7 +4656,7 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, + + /* allocate the space now for the outside block storage. */ + ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, +- value_len); ++ value_len, ctxt); + if (ret) { + mlog_errno(ret); + +@@ -4485,7 +4707,8 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, + + static int ocfs2_xattr_set_entry_index_block(struct inode *inode, + struct ocfs2_xattr_info *xi, +- struct ocfs2_xattr_search *xs) ++ struct ocfs2_xattr_search *xs, ++ struct ocfs2_xattr_set_ctxt *ctxt) + { + struct ocfs2_xattr_header *xh; + struct ocfs2_xattr_entry *xe; +@@ -4603,7 +4826,8 @@ try_again: + + ret = ocfs2_add_new_xattr_bucket(inode, + xs->xattr_bh, +- xs->bucket->bu_bhs[0]); ++ xs->bucket->bu_bhs[0], ++ ctxt); + if (ret) { + mlog_errno(ret); + goto out; +@@ -4622,7 +4846,7 @@ try_again: + } + + xattr_set: +- ret = ocfs2_xattr_set_in_bucket(inode, xi, xs); ++ ret = ocfs2_xattr_set_in_bucket(inode, xi, xs, ctxt); + out: + mlog_exit(ret); + return ret; +@@ -4636,6 +4860,10 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + struct ocfs2_xattr_header *xh = bucket_xh(bucket); + u16 i; + struct ocfs2_xattr_entry *xe; ++ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); ++ struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,}; ++ ++ ocfs2_init_dealloc_ctxt(&ctxt.dealloc); + + for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { + xe = &xh->xh_entries[i]; +@@ -4644,13 +4872,16 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, + + ret = ocfs2_xattr_bucket_value_truncate(inode, + bucket->bu_bhs[0], +- i, 0); ++ i, 0, &ctxt); + if (ret) { + mlog_errno(ret); + break; + } + } + ++ ocfs2_schedule_truncate_log_flush(osb, 1); ++ ocfs2_run_deallocs(osb, &ctxt.dealloc); ++ + return ret; + } + +-- +1.5.6 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr.c-Fix-a-bug-when-inserting-xattr.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr.c-Fix-a-bug-when-inserting-xattr.patch new file mode 100644 index 000000000..20e024706 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-xattr.c-Fix-a-bug-when-inserting-xattr.patch @@ -0,0 +1,31 @@ +From: Tao Ma +Subject: ocfs2/xattr.c: Fix a bug when inserting xattr. +Patch-mainline: 2.6.28 + +During the process of xatt insertion, we use binary search +to find the right place and "low" is set to it. But when +there is one xattr which has the same name hash as the inserted +one, low is the wrong value. So set it to the right position. + +Signed-off-by: Tao Ma +Signed-off-by: Mark Fasheh +--- + fs/ocfs2/xattr.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +Index: linux-2.6.27/fs/ocfs2/xattr.c +=================================================================== +--- linux-2.6.27.orig/fs/ocfs2/xattr.c ++++ linux-2.6.27/fs/ocfs2/xattr.c +@@ -4019,8 +4019,10 @@ static void ocfs2_xattr_set_entry_normal + else if (name_hash < + le32_to_cpu(tmp_xe->xe_name_hash)) + high = tmp - 1; +- else ++ else { ++ low = tmp; + break; ++ } + } + + xe = &xh->xh_entries[low]; diff --git a/src/patches/suse-2.6.27.31/patches.suse/of_platform_driver.module-owner.patch b/src/patches/suse-2.6.27.31/patches.suse/of_platform_driver.module-owner.patch new file mode 100644 index 000000000..d24680ade --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/of_platform_driver.module-owner.patch @@ -0,0 +1,884 @@ +Subject: add missing module symlink to /sys/bus/*/driver/* in struct of_platform_driver +From: olh@suse.de +--- + Documentation/sparc/sbus_drivers.txt | 1 + + arch/powerpc/kernel/of_platform.c | 1 + + arch/powerpc/platforms/52xx/mpc52xx_gpio.c | 3 +++ + arch/powerpc/platforms/82xx/ep8248e.c | 1 + + arch/powerpc/platforms/83xx/suspend.c | 1 + + arch/powerpc/platforms/cell/axon_msi.c | 1 + + arch/powerpc/platforms/pasemi/gpio_mdio.c | 1 + + arch/powerpc/sysdev/fsl_msi.c | 1 + + arch/powerpc/sysdev/fsl_rio.c | 1 + + arch/powerpc/sysdev/pmi.c | 1 + + arch/sparc/include/asm/parport.h | 1 + + arch/sparc/kernel/time.c | 1 + + arch/sparc64/kernel/auxio.c | 1 + + arch/sparc64/kernel/power.c | 1 + + arch/sparc64/kernel/time.c | 1 + + drivers/ata/pata_of_platform.c | 1 + + drivers/ata/sata_fsl.c | 1 + + drivers/char/hw_random/n2-drv.c | 1 + + drivers/char/hw_random/pasemi-rng.c | 1 + + drivers/char/ipmi/ipmi_si_intf.c | 1 + + drivers/crypto/talitos.c | 1 + + drivers/dma/fsldma.c | 2 ++ + drivers/i2c/busses/i2c-ibm_iic.c | 1 + + drivers/infiniband/hw/ehca/ehca_main.c | 1 + + drivers/input/misc/sparcspkr.c | 2 ++ + drivers/input/serio/i8042-sparcio.h | 1 + + drivers/input/serio/xilinx_ps2.c | 1 + + drivers/macintosh/smu.c | 1 + + drivers/macintosh/therm_pm72.c | 1 + + drivers/macintosh/therm_windtunnel.c | 1 + + drivers/mtd/maps/physmap_of.c | 1 + + drivers/mtd/maps/sun_uflash.c | 1 + + drivers/mtd/nand/fsl_elbc_nand.c | 1 + + drivers/mtd/nand/fsl_upm.c | 1 + + drivers/mtd/nand/pasemi_nand.c | 1 + + drivers/net/ehea/ehea_main.c | 1 + + drivers/net/fec_mpc52xx_phy.c | 1 + + drivers/net/fs_enet/fs_enet-main.c | 1 + + drivers/net/fs_enet/mii-bitbang.c | 1 + + drivers/net/fs_enet/mii-fec.c | 1 + + drivers/net/ibm_newemac/core.c | 1 + + drivers/net/ibm_newemac/mal.c | 1 + + drivers/net/ibm_newemac/rgmii.c | 1 + + drivers/net/ibm_newemac/tah.c | 1 + + drivers/net/ibm_newemac/zmii.c | 1 + + drivers/net/myri_sbus.c | 1 + + drivers/net/niu.c | 1 + + drivers/net/phy/mdio-ofgpio.c | 1 + + drivers/net/sunbmac.c | 1 + + drivers/net/sunhme.c | 1 + + drivers/net/sunlance.c | 1 + + drivers/net/sunqe.c | 1 + + drivers/net/ucc_geth.c | 1 + + drivers/net/ucc_geth_mii.c | 1 + + drivers/parport/parport_sunbpp.c | 1 + + drivers/pcmcia/electra_cf.c | 1 + + drivers/pcmcia/m8xx_pcmcia.c | 1 + + drivers/scsi/qlogicpti.c | 1 + + drivers/scsi/sun_esp.c | 1 + + drivers/serial/cpm_uart/cpm_uart_core.c | 1 + + drivers/serial/mpc52xx_uart.c | 1 + + drivers/serial/sunhv.c | 1 + + drivers/serial/sunsab.c | 1 + + drivers/serial/sunsu.c | 1 + + drivers/serial/sunzilog.c | 1 + + drivers/usb/host/isp1760-if.c | 1 + + drivers/video/bw2.c | 1 + + drivers/video/cg14.c | 1 + + drivers/video/cg3.c | 1 + + drivers/video/cg6.c | 1 + + drivers/video/ffb.c | 1 + + drivers/video/leo.c | 1 + + drivers/video/p9100.c | 1 + + drivers/video/platinumfb.c | 1 + + drivers/video/tcx.c | 1 + + sound/sparc/amd7930.c | 1 + + sound/sparc/dbri.c | 1 + + 77 files changed, 81 insertions(+) + +--- a/arch/powerpc/kernel/of_platform.c ++++ b/arch/powerpc/kernel/of_platform.c +@@ -307,6 +307,7 @@ static struct of_device_id of_pci_phb_id + }; + + static struct of_platform_driver of_pci_phb_driver = { ++ .owner = THIS_MODULE, + .match_table = of_pci_phb_ids, + .probe = of_pci_phb_probe, + .driver = { +--- a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c ++++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c +@@ -192,6 +192,7 @@ static const struct of_device_id mpc52xx + }; + + static struct of_platform_driver mpc52xx_wkup_gpiochip_driver = { ++ .owner = THIS_MODULE, + .name = "gpio_wkup", + .match_table = mpc52xx_wkup_gpiochip_match, + .probe = mpc52xx_wkup_gpiochip_probe, +@@ -348,6 +349,7 @@ static const struct of_device_id mpc52xx + }; + + static struct of_platform_driver mpc52xx_simple_gpiochip_driver = { ++ .owner = THIS_MODULE, + .name = "gpio", + .match_table = mpc52xx_simple_gpiochip_match, + .probe = mpc52xx_simple_gpiochip_probe, +@@ -433,6 +435,7 @@ static const struct of_device_id mpc52xx + }; + + static struct of_platform_driver mpc52xx_gpt_gpiochip_driver = { ++ .owner = THIS_MODULE, + .name = "gpio_gpt", + .match_table = mpc52xx_gpt_gpiochip_match, + .probe = mpc52xx_gpt_gpiochip_probe, +--- a/arch/powerpc/platforms/82xx/ep8248e.c ++++ b/arch/powerpc/platforms/82xx/ep8248e.c +@@ -163,6 +163,7 @@ static struct of_platform_driver ep8248e + .match_table = ep8248e_mdio_match, + .probe = ep8248e_mdio_probe, + .remove = ep8248e_mdio_remove, ++ .owner = THIS_MODULE, + }; + + struct cpm_pin { +--- a/arch/powerpc/platforms/83xx/suspend.c ++++ b/arch/powerpc/platforms/83xx/suspend.c +@@ -374,6 +374,7 @@ static struct of_device_id pmc_match[] = + }; + + static struct of_platform_driver pmc_driver = { ++ .owner = THIS_MODULE, + .name = "mpc83xx-pmc", + .match_table = pmc_match, + .probe = pmc_probe, +--- a/arch/powerpc/platforms/cell/axon_msi.c ++++ b/arch/powerpc/platforms/cell/axon_msi.c +@@ -417,6 +417,7 @@ static const struct of_device_id axon_ms + }; + + static struct of_platform_driver axon_msi_driver = { ++ .owner = THIS_MODULE, + .match_table = axon_msi_device_id, + .probe = axon_msi_probe, + .shutdown = axon_msi_shutdown, +--- a/arch/powerpc/platforms/pasemi/gpio_mdio.c ++++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c +@@ -322,6 +322,7 @@ MODULE_DEVICE_TABLE(of, gpio_mdio_match) + + static struct of_platform_driver gpio_mdio_driver = + { ++ .owner = THIS_MODULE, + .match_table = gpio_mdio_match, + .probe = gpio_mdio_probe, + .remove = gpio_mdio_remove, +--- a/arch/powerpc/sysdev/fsl_msi.c ++++ b/arch/powerpc/sysdev/fsl_msi.c +@@ -416,6 +416,7 @@ static const struct of_device_id fsl_of_ + }; + + static struct of_platform_driver fsl_of_msi_driver = { ++ .owner = THIS_MODULE, + .name = "fsl-msi", + .match_table = fsl_of_msi_ids, + .probe = fsl_of_msi_probe, +--- a/arch/powerpc/sysdev/fsl_rio.c ++++ b/arch/powerpc/sysdev/fsl_rio.c +@@ -1197,6 +1197,7 @@ static const struct of_device_id fsl_of_ + }; + + static struct of_platform_driver fsl_of_rio_rpn_driver = { ++ .owner = THIS_MODULE, + .name = "fsl-of-rio", + .match_table = fsl_of_rio_rpn_ids, + .probe = fsl_of_rio_rpn_probe, +--- a/arch/powerpc/sysdev/pmi.c ++++ b/arch/powerpc/sysdev/pmi.c +@@ -205,6 +205,7 @@ static int pmi_of_remove(struct of_devic + } + + static struct of_platform_driver pmi_of_platform_driver = { ++ .owner = THIS_MODULE, + .match_table = pmi_match, + .probe = pmi_of_probe, + .remove = pmi_of_remove, +--- a/arch/sparc64/kernel/auxio.c ++++ b/arch/sparc64/kernel/auxio.c +@@ -148,6 +148,7 @@ static int __devinit auxio_probe(struct + } + + static struct of_platform_driver auxio_driver = { ++ .owner = THIS_MODULE, + .match_table = auxio_match, + .probe = auxio_probe, + .driver = { +--- a/arch/sparc64/kernel/power.c ++++ b/arch/sparc64/kernel/power.c +@@ -104,6 +104,7 @@ static struct of_device_id power_match[] + }; + + static struct of_platform_driver power_driver = { ++ .owner = THIS_MODULE, + .match_table = power_match, + .probe = power_probe, + .driver = { +--- a/arch/sparc64/kernel/time.c ++++ b/arch/sparc64/kernel/time.c +@@ -777,6 +777,7 @@ static struct of_device_id clock_match[] + }; + + static struct of_platform_driver clock_driver = { ++ .owner = THIS_MODULE, + .match_table = clock_match, + .probe = clock_probe, + .driver = { +--- a/arch/sparc/include/asm/parport.h ++++ b/arch/sparc/include/asm/parport.h +@@ -231,6 +231,7 @@ static struct of_device_id ecpp_match[] + }; + + static struct of_platform_driver ecpp_driver = { ++ .owner = THIS_MODULE, + .name = "ecpp", + .match_table = ecpp_match, + .probe = ecpp_probe, +--- a/arch/sparc/kernel/time.c ++++ b/arch/sparc/kernel/time.c +@@ -345,6 +345,7 @@ static struct of_device_id clock_match[] + }; + + static struct of_platform_driver clock_driver = { ++ .owner = THIS_MODULE, + .match_table = clock_match, + .probe = clock_probe, + .driver = { +--- a/Documentation/sparc/sbus_drivers.txt ++++ b/Documentation/sparc/sbus_drivers.txt +@@ -68,6 +68,7 @@ probe in an SBUS driver under Linux: + + static struct of_platform_driver mydevice_driver = { + .match_table = mydevice_match, ++ .owner = THIS_MODULE, + .probe = mydevice_probe, + .remove = __devexit_p(mydevice_remove), + .driver = { +--- a/drivers/ata/pata_of_platform.c ++++ b/drivers/ata/pata_of_platform.c +@@ -91,6 +91,7 @@ static struct of_device_id pata_of_platf + MODULE_DEVICE_TABLE(of, pata_of_platform_match); + + static struct of_platform_driver pata_of_platform_driver = { ++ .owner = THIS_MODULE, + .name = "pata_of_platform", + .match_table = pata_of_platform_match, + .probe = pata_of_platform_probe, +--- a/drivers/ata/sata_fsl.c ++++ b/drivers/ata/sata_fsl.c +@@ -1385,6 +1385,7 @@ static struct of_device_id fsl_sata_matc + MODULE_DEVICE_TABLE(of, fsl_sata_match); + + static struct of_platform_driver fsl_sata_driver = { ++ .owner = THIS_MODULE, + .name = "fsl-sata", + .match_table = fsl_sata_match, + .probe = sata_fsl_probe, +--- a/drivers/char/hw_random/n2-drv.c ++++ b/drivers/char/hw_random/n2-drv.c +@@ -751,6 +751,7 @@ static struct of_device_id n2rng_match[] + MODULE_DEVICE_TABLE(of, n2rng_match); + + static struct of_platform_driver n2rng_driver = { ++ .owner = THIS_MODULE, + .name = "n2rng", + .match_table = n2rng_match, + .probe = n2rng_probe, +--- a/drivers/char/hw_random/pasemi-rng.c ++++ b/drivers/char/hw_random/pasemi-rng.c +@@ -140,6 +140,7 @@ static struct of_device_id rng_match[] = + }; + + static struct of_platform_driver rng_driver = { ++ .owner = THIS_MODULE, + .name = "pasemi-rng", + .match_table = rng_match, + .probe = rng_probe, +--- a/drivers/char/ipmi/ipmi_si_intf.c ++++ b/drivers/char/ipmi/ipmi_si_intf.c +@@ -2400,6 +2400,7 @@ static struct of_device_id ipmi_match[] + }; + + static struct of_platform_driver ipmi_of_platform_driver = { ++ .owner = THIS_MODULE, + .name = "ipmi", + .match_table = ipmi_match, + .probe = ipmi_of_probe, +--- a/drivers/crypto/talitos.c ++++ b/drivers/crypto/talitos.c +@@ -1619,6 +1619,7 @@ static struct of_device_id talitos_match + MODULE_DEVICE_TABLE(of, talitos_match); + + static struct of_platform_driver talitos_driver = { ++ .owner = THIS_MODULE, + .name = "talitos", + .match_table = talitos_match, + .probe = talitos_probe, +--- a/drivers/dma/fsldma.c ++++ b/drivers/dma/fsldma.c +@@ -1036,6 +1036,7 @@ static struct of_device_id of_fsl_dma_ch + }; + + static struct of_platform_driver of_fsl_dma_chan_driver = { ++ .owner = THIS_MODULE, + .name = "of-fsl-dma-channel", + .match_table = of_fsl_dma_chan_ids, + .probe = of_fsl_dma_chan_probe, +@@ -1116,6 +1117,7 @@ static struct of_device_id of_fsl_dma_id + }; + + static struct of_platform_driver of_fsl_dma_driver = { ++ .owner = THIS_MODULE, + .name = "of-fsl-dma", + .match_table = of_fsl_dma_ids, + .probe = of_fsl_dma_probe, +--- a/drivers/i2c/busses/i2c-ibm_iic.c ++++ b/drivers/i2c/busses/i2c-ibm_iic.c +@@ -807,6 +807,7 @@ static const struct of_device_id ibm_iic + }; + + static struct of_platform_driver ibm_iic_driver = { ++ .owner = THIS_MODULE, + .name = "ibm-iic", + .match_table = ibm_iic_match, + .probe = iic_probe, +--- a/drivers/infiniband/hw/ehca/ehca_main.c ++++ b/drivers/infiniband/hw/ehca/ehca_main.c +@@ -927,6 +927,7 @@ MODULE_DEVICE_TABLE(of, ehca_device_tabl + + static struct of_platform_driver ehca_driver = { + .name = "ehca", ++ .owner = THIS_MODULE, + .match_table = ehca_device_table, + .probe = ehca_probe, + .remove = ehca_remove, +--- a/drivers/input/misc/sparcspkr.c ++++ b/drivers/input/misc/sparcspkr.c +@@ -258,6 +258,7 @@ static struct of_device_id bbc_beep_matc + }; + + static struct of_platform_driver bbc_beep_driver = { ++ .owner = THIS_MODULE, + .name = "bbcbeep", + .match_table = bbc_beep_match, + .probe = bbc_beep_probe, +@@ -337,6 +338,7 @@ static struct of_device_id grover_beep_m + }; + + static struct of_platform_driver grover_beep_driver = { ++ .owner = THIS_MODULE, + .name = "groverbeep", + .match_table = grover_beep_match, + .probe = grover_beep_probe, +--- a/drivers/input/serio/i8042-sparcio.h ++++ b/drivers/input/serio/i8042-sparcio.h +@@ -96,6 +96,7 @@ static struct of_device_id sparc_i8042_m + MODULE_DEVICE_TABLE(of, sparc_i8042_match); + + static struct of_platform_driver sparc_i8042_driver = { ++ .owner = THIS_MODULE, + .name = "i8042", + .match_table = sparc_i8042_match, + .probe = sparc_i8042_probe, +--- a/drivers/input/serio/xilinx_ps2.c ++++ b/drivers/input/serio/xilinx_ps2.c +@@ -355,6 +355,7 @@ static struct of_device_id xps2_of_match + MODULE_DEVICE_TABLE(of, xps2_of_match); + + static struct of_platform_driver xps2_of_driver = { ++ .owner = THIS_MODULE, + .name = DRIVER_NAME, + .match_table = xps2_of_match, + .probe = xps2_of_probe, +--- a/drivers/macintosh/smu.c ++++ b/drivers/macintosh/smu.c +@@ -670,6 +670,7 @@ static struct of_device_id smu_platform_ + + static struct of_platform_driver smu_of_platform_driver = + { ++ .owner = THIS_MODULE, + .name = "smu", + .match_table = smu_platform_match, + .probe = smu_platform_probe, +--- a/drivers/macintosh/therm_pm72.c ++++ b/drivers/macintosh/therm_pm72.c +@@ -2220,6 +2220,7 @@ static struct of_device_id fcu_match[] = + + static struct of_platform_driver fcu_of_platform_driver = + { ++ .owner = THIS_MODULE, + .name = "temperature", + .match_table = fcu_match, + .probe = fcu_of_probe, +--- a/drivers/macintosh/therm_windtunnel.c ++++ b/drivers/macintosh/therm_windtunnel.c +@@ -470,6 +470,7 @@ static struct of_device_id therm_of_matc + }; + + static struct of_platform_driver therm_of_driver = { ++ .owner = THIS_MODULE, + .name = "temperature", + .match_table = therm_of_match, + .probe = therm_of_probe, +--- a/drivers/mtd/maps/physmap_of.c ++++ b/drivers/mtd/maps/physmap_of.c +@@ -281,6 +281,7 @@ static struct of_device_id of_flash_matc + MODULE_DEVICE_TABLE(of, of_flash_match); + + static struct of_platform_driver of_flash_driver = { ++ .owner = THIS_MODULE, + .name = "of-flash", + .match_table = of_flash_match, + .probe = of_flash_probe, +--- a/drivers/mtd/maps/sun_uflash.c ++++ b/drivers/mtd/maps/sun_uflash.c +@@ -151,6 +151,7 @@ static struct of_device_id uflash_match[ + MODULE_DEVICE_TABLE(of, uflash_match); + + static struct of_platform_driver uflash_driver = { ++ .owner = THIS_MODULE, + .name = UFLASH_DEVNAME, + .match_table = uflash_match, + .probe = uflash_probe, +--- a/drivers/mtd/nand/fsl_elbc_nand.c ++++ b/drivers/mtd/nand/fsl_elbc_nand.c +@@ -1079,6 +1079,7 @@ static const struct of_device_id fsl_elb + static struct of_platform_driver fsl_elbc_ctrl_driver = { + .driver = { + .name = "fsl-elbc", ++ .owner = THIS_MODULE, + }, + .match_table = fsl_elbc_match, + .probe = fsl_elbc_ctrl_probe, +--- a/drivers/mtd/nand/fsl_upm.c ++++ b/drivers/mtd/nand/fsl_upm.c +@@ -267,6 +267,7 @@ static struct of_device_id of_fun_match[ + MODULE_DEVICE_TABLE(of, of_fun_match); + + static struct of_platform_driver of_fun_driver = { ++ .owner = THIS_MODULE, + .name = "fsl,upm-nand", + .match_table = of_fun_match, + .probe = fun_probe, +--- a/drivers/mtd/nand/pasemi_nand.c ++++ b/drivers/mtd/nand/pasemi_nand.c +@@ -220,6 +220,7 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_matc + + static struct of_platform_driver pasemi_nand_driver = + { ++ .owner = THIS_MODULE, + .name = (char*)driver_name, + .match_table = pasemi_nand_match, + .probe = pasemi_nand_probe, +--- a/drivers/net/ehea/ehea_main.c ++++ b/drivers/net/ehea/ehea_main.c +@@ -122,6 +122,7 @@ MODULE_DEVICE_TABLE(of, ehea_device_tabl + + static struct of_platform_driver ehea_driver = { + .name = "ehea", ++ .owner = THIS_MODULE, + .match_table = ehea_device_table, + .probe = ehea_probe_adapter, + .remove = ehea_remove, +--- a/drivers/net/fec_mpc52xx_phy.c ++++ b/drivers/net/fec_mpc52xx_phy.c +@@ -185,6 +185,7 @@ static struct of_device_id mpc52xx_fec_m + }; + + struct of_platform_driver mpc52xx_fec_mdio_driver = { ++ .owner = THIS_MODULE, + .name = "mpc5200b-fec-phy", + .probe = mpc52xx_fec_mdio_probe, + .remove = mpc52xx_fec_mdio_remove, +--- a/drivers/net/fs_enet/fs_enet-main.c ++++ b/drivers/net/fs_enet/fs_enet-main.c +@@ -1192,6 +1192,7 @@ static struct of_device_id fs_enet_match + }; + + static struct of_platform_driver fs_enet_driver = { ++ .owner = THIS_MODULE, + .name = "fs_enet", + .match_table = fs_enet_match, + .probe = fs_enet_probe, +--- a/drivers/net/fs_enet/mii-bitbang.c ++++ b/drivers/net/fs_enet/mii-bitbang.c +@@ -249,6 +249,7 @@ static struct of_device_id fs_enet_mdio_ + }; + + static struct of_platform_driver fs_enet_bb_mdio_driver = { ++ .owner = THIS_MODULE, + .name = "fsl-bb-mdio", + .match_table = fs_enet_mdio_bb_match, + .probe = fs_enet_mdio_probe, +--- a/drivers/net/fs_enet/mii-fec.c ++++ b/drivers/net/fs_enet/mii-fec.c +@@ -218,6 +218,7 @@ static struct of_device_id fs_enet_mdio_ + }; + + static struct of_platform_driver fs_enet_fec_mdio_driver = { ++ .owner = THIS_MODULE, + .name = "fsl-fec-mdio", + .match_table = fs_enet_mdio_fec_match, + .probe = fs_enet_mdio_probe, +--- a/drivers/net/ibm_newemac/core.c ++++ b/drivers/net/ibm_newemac/core.c +@@ -2923,6 +2923,7 @@ static struct of_device_id emac_match[] + }; + + static struct of_platform_driver emac_driver = { ++ .owner = THIS_MODULE, + .name = "emac", + .match_table = emac_match, + +--- a/drivers/net/ibm_newemac/mal.c ++++ b/drivers/net/ibm_newemac/mal.c +@@ -724,6 +724,7 @@ static struct of_device_id mal_platform_ + }; + + static struct of_platform_driver mal_of_driver = { ++ .owner = THIS_MODULE, + .name = "mcmal", + .match_table = mal_platform_match, + +--- a/drivers/net/ibm_newemac/rgmii.c ++++ b/drivers/net/ibm_newemac/rgmii.c +@@ -317,6 +317,7 @@ static struct of_device_id rgmii_match[] + }; + + static struct of_platform_driver rgmii_driver = { ++ .owner = THIS_MODULE, + .name = "emac-rgmii", + .match_table = rgmii_match, + +--- a/drivers/net/ibm_newemac/tah.c ++++ b/drivers/net/ibm_newemac/tah.c +@@ -165,6 +165,7 @@ static struct of_device_id tah_match[] = + }; + + static struct of_platform_driver tah_driver = { ++ .owner = THIS_MODULE, + .name = "emac-tah", + .match_table = tah_match, + +--- a/drivers/net/ibm_newemac/zmii.c ++++ b/drivers/net/ibm_newemac/zmii.c +@@ -311,6 +311,7 @@ static struct of_device_id zmii_match[] + }; + + static struct of_platform_driver zmii_driver = { ++ .owner = THIS_MODULE, + .name = "emac-zmii", + .match_table = zmii_match, + +--- a/drivers/net/myri_sbus.c ++++ b/drivers/net/myri_sbus.c +@@ -1150,6 +1150,7 @@ static struct of_device_id myri_sbus_mat + MODULE_DEVICE_TABLE(of, myri_sbus_match); + + static struct of_platform_driver myri_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "myri", + .match_table = myri_sbus_match, + .probe = myri_sbus_probe, +--- a/drivers/net/niu.c ++++ b/drivers/net/niu.c +@@ -9139,6 +9139,7 @@ static struct of_device_id niu_match[] = + MODULE_DEVICE_TABLE(of, niu_match); + + static struct of_platform_driver niu_of_driver = { ++ .owner = THIS_MODULE, + .name = "niu", + .match_table = niu_match, + .probe = niu_of_probe, +--- a/drivers/net/phy/mdio-ofgpio.c ++++ b/drivers/net/phy/mdio-ofgpio.c +@@ -185,6 +185,7 @@ static struct of_device_id mdio_ofgpio_m + }; + + static struct of_platform_driver mdio_ofgpio_driver = { ++ .owner = THIS_MODULE, + .name = "mdio-gpio", + .match_table = mdio_ofgpio_match, + .probe = mdio_ofgpio_probe, +--- a/drivers/net/sunbmac.c ++++ b/drivers/net/sunbmac.c +@@ -1305,6 +1305,7 @@ static struct of_device_id bigmac_sbus_m + MODULE_DEVICE_TABLE(of, bigmac_sbus_match); + + static struct of_platform_driver bigmac_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "sunbmac", + .match_table = bigmac_sbus_match, + .probe = bigmac_sbus_probe, +--- a/drivers/net/sunhme.c ++++ b/drivers/net/sunhme.c +@@ -3336,6 +3336,7 @@ static struct of_device_id hme_sbus_matc + MODULE_DEVICE_TABLE(of, hme_sbus_match); + + static struct of_platform_driver hme_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "hme", + .match_table = hme_sbus_match, + .probe = hme_sbus_probe, +--- a/drivers/net/sunlance.c ++++ b/drivers/net/sunlance.c +@@ -1583,6 +1583,7 @@ static struct of_device_id sunlance_sbus + MODULE_DEVICE_TABLE(of, sunlance_sbus_match); + + static struct of_platform_driver sunlance_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "sunlance", + .match_table = sunlance_sbus_match, + .probe = sunlance_sbus_probe, +--- a/drivers/net/sunqe.c ++++ b/drivers/net/sunqe.c +@@ -983,6 +983,7 @@ static struct of_device_id qec_sbus_matc + MODULE_DEVICE_TABLE(of, qec_sbus_match); + + static struct of_platform_driver qec_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "qec", + .match_table = qec_sbus_match, + .probe = qec_sbus_probe, +--- a/drivers/net/ucc_geth.c ++++ b/drivers/net/ucc_geth.c +@@ -4083,6 +4083,7 @@ static struct of_device_id ucc_geth_matc + MODULE_DEVICE_TABLE(of, ucc_geth_match); + + static struct of_platform_driver ucc_geth_driver = { ++ .owner = THIS_MODULE, + .name = DRV_NAME, + .match_table = ucc_geth_match, + .probe = ucc_geth_probe, +--- a/drivers/net/ucc_geth_mii.c ++++ b/drivers/net/ucc_geth_mii.c +@@ -268,6 +268,7 @@ static struct of_device_id uec_mdio_matc + }; + + static struct of_platform_driver uec_mdio_driver = { ++ .owner = THIS_MODULE, + .name = MII_DRV_NAME, + .probe = uec_mdio_probe, + .remove = uec_mdio_remove, +--- a/drivers/parport/parport_sunbpp.c ++++ b/drivers/parport/parport_sunbpp.c +@@ -389,6 +389,7 @@ static struct of_device_id bpp_match[] = + MODULE_DEVICE_TABLE(of, bpp_match); + + static struct of_platform_driver bpp_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "bpp", + .match_table = bpp_match, + .probe = bpp_probe, +--- a/drivers/pcmcia/electra_cf.c ++++ b/drivers/pcmcia/electra_cf.c +@@ -356,6 +356,7 @@ static struct of_device_id electra_cf_ma + MODULE_DEVICE_TABLE(of, electra_cf_match); + + static struct of_platform_driver electra_cf_driver = { ++ .owner = THIS_MODULE, + .name = (char *)driver_name, + .match_table = electra_cf_match, + .probe = electra_cf_probe, +--- a/drivers/pcmcia/m8xx_pcmcia.c ++++ b/drivers/pcmcia/m8xx_pcmcia.c +@@ -1319,6 +1319,7 @@ static struct of_device_id m8xx_pcmcia_m + MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match); + + static struct of_platform_driver m8xx_pcmcia_driver = { ++ .owner = THIS_MODULE, + .name = driver_name, + .match_table = m8xx_pcmcia_match, + .probe = m8xx_probe, +--- a/drivers/scsi/qlogicpti.c ++++ b/drivers/scsi/qlogicpti.c +@@ -1434,6 +1434,7 @@ static struct of_device_id qpti_match[] + MODULE_DEVICE_TABLE(of, qpti_match); + + static struct of_platform_driver qpti_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "qpti", + .match_table = qpti_match, + .probe = qpti_sbus_probe, +--- a/drivers/scsi/sun_esp.c ++++ b/drivers/scsi/sun_esp.c +@@ -611,6 +611,7 @@ static struct of_device_id esp_match[] = + MODULE_DEVICE_TABLE(of, esp_match); + + static struct of_platform_driver esp_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "esp", + .match_table = esp_match, + .probe = esp_sbus_probe, +--- a/drivers/serial/cpm_uart/cpm_uart_core.c ++++ b/drivers/serial/cpm_uart/cpm_uart_core.c +@@ -1359,6 +1359,7 @@ static struct of_device_id cpm_uart_matc + }; + + static struct of_platform_driver cpm_uart_driver = { ++ .owner = THIS_MODULE, + .name = "cpm_uart", + .match_table = cpm_uart_match, + .probe = cpm_uart_probe, +--- a/drivers/serial/mpc52xx_uart.c ++++ b/drivers/serial/mpc52xx_uart.c +@@ -1391,6 +1391,7 @@ mpc52xx_uart_of_enumerate(void) + MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); + + static struct of_platform_driver mpc52xx_uart_of_driver = { ++ .owner = THIS_MODULE, + .match_table = mpc52xx_uart_of_match, + .probe = mpc52xx_uart_of_probe, + .remove = mpc52xx_uart_of_remove, +--- a/drivers/serial/sunhv.c ++++ b/drivers/serial/sunhv.c +@@ -630,6 +630,7 @@ static struct of_device_id hv_match[] = + MODULE_DEVICE_TABLE(of, hv_match); + + static struct of_platform_driver hv_driver = { ++ .owner = THIS_MODULE, + .name = "hv", + .match_table = hv_match, + .probe = hv_probe, +--- a/drivers/serial/sunsab.c ++++ b/drivers/serial/sunsab.c +@@ -1091,6 +1091,7 @@ static struct of_device_id sab_match[] = + MODULE_DEVICE_TABLE(of, sab_match); + + static struct of_platform_driver sab_driver = { ++ .owner = THIS_MODULE, + .name = "sab", + .match_table = sab_match, + .probe = sab_probe, +--- a/drivers/serial/sunsu.c ++++ b/drivers/serial/sunsu.c +@@ -1522,6 +1522,7 @@ static struct of_device_id su_match[] = + MODULE_DEVICE_TABLE(of, su_match); + + static struct of_platform_driver su_driver = { ++ .owner = THIS_MODULE, + .name = "su", + .match_table = su_match, + .probe = su_probe, +--- a/drivers/serial/sunzilog.c ++++ b/drivers/serial/sunzilog.c +@@ -1489,6 +1489,7 @@ static struct of_device_id zs_match[] = + MODULE_DEVICE_TABLE(of, zs_match); + + static struct of_platform_driver zs_driver = { ++ .owner = THIS_MODULE, + .name = "zs", + .match_table = zs_match, + .probe = zs_probe, +--- a/drivers/usb/host/isp1760-if.c ++++ b/drivers/usb/host/isp1760-if.c +@@ -121,6 +121,7 @@ static struct of_device_id of_isp1760_ma + MODULE_DEVICE_TABLE(of, of_isp1760_match); + + static struct of_platform_driver isp1760_of_driver = { ++ .owner = THIS_MODULE, + .name = "nxp-isp1760", + .match_table = of_isp1760_match, + .probe = of_isp1760_probe, +--- a/drivers/video/bw2.c ++++ b/drivers/video/bw2.c +@@ -381,6 +381,7 @@ static struct of_device_id bw2_match[] = + MODULE_DEVICE_TABLE(of, bw2_match); + + static struct of_platform_driver bw2_driver = { ++ .owner = THIS_MODULE, + .name = "bw2", + .match_table = bw2_match, + .probe = bw2_probe, +--- a/drivers/video/cg14.c ++++ b/drivers/video/cg14.c +@@ -598,6 +598,7 @@ static struct of_device_id cg14_match[] + MODULE_DEVICE_TABLE(of, cg14_match); + + static struct of_platform_driver cg14_driver = { ++ .owner = THIS_MODULE, + .name = "cg14", + .match_table = cg14_match, + .probe = cg14_probe, +--- a/drivers/video/cg3.c ++++ b/drivers/video/cg3.c +@@ -468,6 +468,7 @@ static struct of_device_id cg3_match[] = + MODULE_DEVICE_TABLE(of, cg3_match); + + static struct of_platform_driver cg3_driver = { ++ .owner = THIS_MODULE, + .name = "cg3", + .match_table = cg3_match, + .probe = cg3_probe, +--- a/drivers/video/cg6.c ++++ b/drivers/video/cg6.c +@@ -826,6 +826,7 @@ static struct of_device_id cg6_match[] = + MODULE_DEVICE_TABLE(of, cg6_match); + + static struct of_platform_driver cg6_driver = { ++ .owner = THIS_MODULE, + .name = "cg6", + .match_table = cg6_match, + .probe = cg6_probe, +--- a/drivers/video/ffb.c ++++ b/drivers/video/ffb.c +@@ -1054,6 +1054,7 @@ static struct of_device_id ffb_match[] = + MODULE_DEVICE_TABLE(of, ffb_match); + + static struct of_platform_driver ffb_driver = { ++ .owner = THIS_MODULE, + .name = "ffb", + .match_table = ffb_match, + .probe = ffb_probe, +--- a/drivers/video/leo.c ++++ b/drivers/video/leo.c +@@ -650,6 +650,7 @@ static struct of_device_id leo_match[] = + MODULE_DEVICE_TABLE(of, leo_match); + + static struct of_platform_driver leo_driver = { ++ .owner = THIS_MODULE, + .name = "leo", + .match_table = leo_match, + .probe = leo_probe, +--- a/drivers/video/p9100.c ++++ b/drivers/video/p9100.c +@@ -358,6 +358,7 @@ static struct of_device_id p9100_match[] + MODULE_DEVICE_TABLE(of, p9100_match); + + static struct of_platform_driver p9100_driver = { ++ .owner = THIS_MODULE, + .name = "p9100", + .match_table = p9100_match, + .probe = p9100_probe, +--- a/drivers/video/platinumfb.c ++++ b/drivers/video/platinumfb.c +@@ -674,6 +674,7 @@ static struct of_device_id platinumfb_ma + + static struct of_platform_driver platinum_driver = + { ++ .owner = THIS_MODULE, + .name = "platinumfb", + .match_table = platinumfb_match, + .probe = platinumfb_probe, +--- a/drivers/video/tcx.c ++++ b/drivers/video/tcx.c +@@ -514,6 +514,7 @@ static struct of_device_id tcx_match[] = + MODULE_DEVICE_TABLE(of, tcx_match); + + static struct of_platform_driver tcx_driver = { ++ .owner = THIS_MODULE, + .name = "tcx", + .match_table = tcx_match, + .probe = tcx_probe, +--- a/sound/sparc/amd7930.c ++++ b/sound/sparc/amd7930.c +@@ -1108,6 +1108,7 @@ static struct of_device_id amd7930_match + }; + + static struct of_platform_driver amd7930_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "audio", + .match_table = amd7930_match, + .probe = amd7930_sbus_probe, +--- a/sound/sparc/dbri.c ++++ b/sound/sparc/dbri.c +@@ -2679,6 +2679,7 @@ static struct of_device_id dbri_match[] + MODULE_DEVICE_TABLE(of, dbri_match); + + static struct of_platform_driver dbri_sbus_driver = { ++ .owner = THIS_MODULE, + .name = "dbri", + .match_table = dbri_match, + .probe = dbri_probe, diff --git a/src/patches/suse-2.6.27.31/patches.suse/osync-error b/src/patches/suse-2.6.27.31/patches.suse/osync-error new file mode 100644 index 000000000..35036490c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/osync-error @@ -0,0 +1,49 @@ +From: mason@suse.de +Subject: make sure O_SYNC writes properly return -EIO +References: bnc#58622 + +Make sure to honor the error status of synchronous writeback during +O_SYNC writes + +Acked-by: Jeff Mahoney + +--- + mm/filemap.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2498,7 +2498,7 @@ generic_file_buffered_write(struct kiocb + + if (likely(status >= 0)) { + written += status; +- *ppos = pos + status; ++ pos += status; + + /* + * For now, when the user asks for O_SYNC, we'll actually give +@@ -2516,10 +2516,23 @@ generic_file_buffered_write(struct kiocb + * to buffered writes (block instantiation inside i_size). So we sync + * the file data here, to try to honour O_DIRECT expectations. + */ +- if (unlikely(file->f_flags & O_DIRECT) && written) ++ if (unlikely(file->f_flags & O_DIRECT) && status >= 0 && written) + status = filemap_write_and_wait_range(mapping, + pos, pos + written - 1); + ++ /* ++ * We must let know userspace if something hasn't been written ++ * correctly. If we got an I/O error it means we got an hardware ++ * failure, anything can be happening to the on-disk data, ++ * letting know userspace that a bit of data might have been ++ * written correctly on disk is a very low priority, compared ++ * to letting know userspace that some data has _not_ been ++ * written at all. ++ */ ++ if (unlikely(status == -EIO)) ++ return status; ++ *ppos = pos; ++ + return written ? written : status; + } + EXPORT_SYMBOL(generic_file_buffered_write); diff --git a/src/patches/suse-2.6.27.31/patches.suse/perfmon2-add_ioctl_interface.patch b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-add_ioctl_interface.patch new file mode 100644 index 000000000..c9129e240 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-add_ioctl_interface.patch @@ -0,0 +1,425 @@ +From: Tony Jones +Subject: switch to ioctl interface for perfmon2 +Patch-mainline: never + +Patch accepted from SGI (bnc#430298, FATE #303968) added 12 new syscalls. +Since these have not been accepted upstream, we don't want to have to +support them. Decision was made to switch to a ioctl based interface. + +Signed-off-by: Tony Jones + +--- + include/linux/syscalls.h | 23 --- + perfmon/Makefile | 3 + perfmon/perfmon_control.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++ + perfmon/perfmon_init.c | 3 + perfmon/perfmon_priv.h | 25 +++ + 5 files changed, 340 insertions(+), 24 deletions(-) + +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -697,27 +697,4 @@ asmlinkage long sys_pipe(int __user *); + + int kernel_execve(const char *filename, char *const argv[], char *const envp[]); + +-asmlinkage long sys_pfm_create_context(struct pfarg_ctx __user *ureq, +- void __user *uarg, size_t smpl_size); +-asmlinkage long sys_pfm_write_pmcs(int fd, struct pfarg_pmc __user *ureq, +- int count); +-asmlinkage long sys_pfm_write_pmds(int fd, struct pfarg_pmd __user *ureq, +- int count); +-asmlinkage long sys_pfm_read_pmds(int fd, struct pfarg_pmd __user *ureq, +- int count); +-asmlinkage long sys_pfm_restart(int fd); +-asmlinkage long sys_pfm_stop(int fd); +-asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *ureq); +-asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ureq); +-asmlinkage long sys_pfm_unload_context(int fd); +-asmlinkage long sys_pfm_delete_evtsets(int fd, +- struct pfarg_setinfo __user *ureq, +- int count); +-asmlinkage long sys_pfm_create_evtsets(int fd, +- struct pfarg_setdesc __user *ureq, +- int count); +-asmlinkage long sys_pfm_getinfo_evtsets(int fd, +- struct pfarg_setinfo __user *ureq, +- int count); +- + #endif +--- a/perfmon/Makefile ++++ b/perfmon/Makefile +@@ -7,6 +7,7 @@ obj-y = perfmon_init.o perfmon_rw.o perf + perfmon_file.o perfmon_ctxsw.o perfmon_intr.o \ + perfmon_dfl_smpl.o perfmon_sets.o perfmon_hotplug.o \ + perfmon_msg.o perfmon_smpl.o perfmon_attach.o \ +- perfmon_activate.o perfmon_ctx.o perfmon_fmt.o ++ perfmon_activate.o perfmon_ctx.o perfmon_fmt.o \ ++ perfmon_control.o + + obj-$(CONFIG_PERFMON_DEBUG_FS) += perfmon_debugfs.o +--- /dev/null ++++ b/perfmon/perfmon_control.c +@@ -0,0 +1,310 @@ ++/* ++ * perfmon_control.c: perfmon2 ioctl interface ++ * ++ * This file implements an ioctl interface alternative replacing the ++ * following syscalls: ++ * ++ * sys_pfm_create_context ++ * sys_pfm_write_pmcs ++ * sys_pfm_write_pmds ++ * sys_pfm_read_pmds ++ * sys_pfm_load_context ++ * sys_pfm_start ++ * sys_pfm_stop ++ * sys_pfm_restart ++ * sys_pfm_create_evtsets ++ * sys_pfm_getinfo_evtsets ++ * sys_pfm_delete_evtsets ++ * sys_pfm_unload_context ++ * ++ * For SLES11 ++ * ++ * Tony Jones ++ * ++ * Copyright (c) 2008 Novell Inc ++ * Contributed by Tony Jones ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "perfmon_priv.h" ++#include ++#include ++ ++/* elements arranged to ensure current padding for 32/64bit */ ++struct pfm_control_init { ++ __u64 req; /* struct pfarg_ctx* */ ++ __u64 fmt_name; /* char* */ ++ __u64 fmt_arg; /* void* */ ++ __u64 fmt_size; /* size_t */ ++}; ++ ++struct pfm_control_arglist { ++ __s32 fd; /* int */ ++ __s32 count; /* int */ ++ __u64 req; /* void* */ ++}; ++ ++struct pfm_control_argptr { ++ __u64 req; /* void* */ ++ __s32 fd; /* int */ ++ __s32 _pad; ++}; ++ ++struct pfm_control_fd { ++ __s32 fd; /* int */ ++ __s32 _pad; ++}; ++ ++union pfm_control { ++ struct pfm_control_init init; ++ struct pfm_control_arglist arglist; ++ struct pfm_control_argptr argptr; ++ struct pfm_control_fd fd; ++}; ++ ++#ifdef CONFIG_COMPAT ++#define _PTR(p) (compat ? compat_ptr(p) : (void*)p) ++#else ++#define _PTR(p) (unsigned long)(p) ++#endif ++ ++static long pfm_control_create_context(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_init *d = &cdata->init; ++ ++ return sys_pfm_create_context((struct pfarg_ctx *)_PTR(d->req), ++ (char *)_PTR(d->fmt_name), ++ (void *)_PTR(d->fmt_arg), ++ (size_t)d->fmt_size); ++} ++ ++static long pfm_control_write_pmcs(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_arglist *d = &cdata->arglist; ++ ++ return sys_pfm_write_pmcs(d->fd, ++ (struct pfarg_pmc __user *)_PTR(d->req), ++ d->count); ++} ++ ++static long pfm_control_write_pmds(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_arglist *d = &cdata->arglist; ++ ++ return sys_pfm_write_pmds(d->fd, ++ (struct pfarg_pmd __user *)_PTR(d->req), ++ d->count); ++} ++ ++static long pfm_control_read_pmds(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_arglist *d = &cdata->arglist; ++ ++ return sys_pfm_read_pmds(d->fd, ++ (struct pfarg_pmd __user *)_PTR(d->req), ++ d->count); ++} ++ ++static long pfm_control_load_context(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_argptr *d = &cdata->argptr; ++ ++ return sys_pfm_load_context(d->fd, ++ (struct pfarg_load __user *)_PTR(d->req)); ++} ++ ++static long pfm_control_start(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_argptr *d = &cdata->argptr; ++ ++ return sys_pfm_start(d->fd, (struct pfarg_start __user *)_PTR(d->req)); ++} ++ ++static long pfm_control_stop(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_fd *d = &cdata->fd; ++ ++ return sys_pfm_stop(d->fd); ++} ++ ++static long pfm_control_restart(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_fd *d = &cdata->fd; ++ ++ return sys_pfm_restart(d->fd); ++} ++ ++static long pfm_control_create_evtsets(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_arglist *d = &cdata->arglist; ++ ++ return sys_pfm_create_evtsets(d->fd, ++ (struct pfarg_setdesc __user *)_PTR(d->req), ++ d->count); ++} ++ ++static long pfm_control_getinfo_evtsets(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_arglist *d = &cdata->arglist; ++ ++ return sys_pfm_getinfo_evtsets(d->fd, ++ (struct pfarg_setinfo __user *)_PTR(d->req), ++ d->count); ++} ++ ++static long pfm_control_delete_evtsets(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_arglist *d = &cdata->arglist; ++ ++ return sys_pfm_delete_evtsets(d->fd, ++ (struct pfarg_setinfo __user *)_PTR(d->req), ++ d->count); ++} ++ ++static long pfm_control_unload_context(union pfm_control *cdata, int compat) ++{ ++ struct pfm_control_fd *d = &cdata->fd; ++ ++ return sys_pfm_unload_context(d->fd); ++} ++ ++#define PFM_CONTROL_COUNT ARRAY_SIZE(pfm_control_tab) ++#define PFM_CMD(func, elem) {func, sizeof(struct elem)} ++ ++struct pfm_control_elem { ++ long (*func)(union pfm_control *, int compat); ++ size_t size; ++}; ++ ++static struct pfm_control_elem pfm_control_tab[] = { ++ PFM_CMD(pfm_control_create_context, pfm_control_init), ++ PFM_CMD(pfm_control_write_pmcs, pfm_control_arglist), ++ PFM_CMD(pfm_control_write_pmds, pfm_control_arglist), ++ PFM_CMD(pfm_control_read_pmds, pfm_control_arglist), ++ PFM_CMD(pfm_control_load_context, pfm_control_argptr), ++ PFM_CMD(pfm_control_start, pfm_control_argptr), ++ PFM_CMD(pfm_control_stop, pfm_control_fd), ++ PFM_CMD(pfm_control_restart, pfm_control_fd), ++ PFM_CMD(pfm_control_create_evtsets, pfm_control_arglist), ++ PFM_CMD(pfm_control_getinfo_evtsets, pfm_control_arglist), ++ PFM_CMD(pfm_control_delete_evtsets, pfm_control_arglist), ++ PFM_CMD(pfm_control_unload_context, pfm_control_fd), ++}; ++ ++static int __pfm_control_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg, ++ int compat) ++{ ++ union pfm_control cdata; ++ int rc, op; ++ ++ if (perfmon_disabled) ++ return -ENOSYS; ++ ++ op = _IOC_NR(cmd); ++ ++ if (unlikely(op < 0 || op >= PFM_CONTROL_COUNT || ++ pfm_control_tab[op].func == NULL)) { ++ PFM_ERR("Invalid control request %d", op); ++ return -EINVAL; ++ } ++ ++ if (_IOC_SIZE(cmd) != pfm_control_tab[op].size) { ++ PFM_ERR("Invalid control request %d, size %d, expected %lu\n", ++ op, _IOC_SIZE(cmd), ++ (unsigned long)pfm_control_tab[op].size); ++ return -EINVAL; ++ } ++ ++ if (_IOC_TYPE(cmd) != 0 || _IOC_DIR(cmd) != _IOC_WRITE) ++ return -EINVAL; ++ ++ if (copy_from_user(&cdata, (void*)arg, pfm_control_tab[op].size) != 0) ++ return -EFAULT; ++ ++ rc = pfm_control_tab[op].func(&cdata, compat); ++ return rc; ++} ++ ++static int pfm_control_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return __pfm_control_ioctl(inode, file, cmd, arg, 0); ++} ++ ++#ifdef CONFIG_COMPAT ++static long compat_pfm_control_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return __pfm_control_ioctl(file->f_dentry->d_inode, file, cmd, arg, 1); ++} ++#endif ++ ++static const struct file_operations pfm_control_operations = { ++ .owner = THIS_MODULE, ++ .ioctl = pfm_control_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = compat_pfm_control_ioctl, ++#endif ++}; ++ ++#ifdef USE_MISC_REGISTER ++static struct miscdevice pfm_misc_device = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "perfmonctl", ++ .fops = &pfm_control_operations ++}; ++#endif ++ ++int __init pfm_init_control(void) ++{ ++ int ret=0; ++#ifndef USE_MISC_REGISTER ++ static struct class *pfm_class; ++ struct device *dev; ++ int major; ++#endif ++ ++#ifdef USE_MISC_REGISTER ++ ret = misc_register(&pfm_misc_device); ++ if (ret) { ++ PFM_ERR("Failed to create perfmon control file. Error %d\n", ret); ++ } ++#else ++ major = register_chrdev(0, "perfmon", &pfm_control_operations); ++ if (major < 0) { ++ PFM_ERR("Failed to register_chardev %d\n", major); ++ return major; ++ } ++ pfm_class = class_create(THIS_MODULE, "perfmon"); ++ if (IS_ERR(pfm_class)) { ++ PFM_ERR("Failed to class_create %ld\n", PTR_ERR(pfm_class)); ++ return -ENOENT; ++ } ++ dev = device_create(pfm_class, NULL, MKDEV(major,0), NULL, "perfmonctl"); ++ if (IS_ERR(dev)) { ++ PFM_ERR("Failed to device_create %ld\n", PTR_ERR(dev)); ++ return -ENOENT; ++ } ++#endif ++ return ret; ++} +--- a/perfmon/perfmon_init.c ++++ b/perfmon/perfmon_init.c +@@ -104,6 +104,9 @@ int __init pfm_init(void) + if (pfm_init_sysfs()) + goto error_disable; + ++ if (pfm_init_control()) ++ goto error_disable; ++ + /* not critical, so no error checking */ + pfm_init_debugfs(); + +--- a/perfmon/perfmon_priv.h ++++ b/perfmon/perfmon_priv.h +@@ -158,6 +158,7 @@ static inline void pfm_check_save_prev_c + + + int pfm_init_fs(void); ++int pfm_init_control(void); + + int pfm_init_hotplug(void); + +@@ -177,6 +178,30 @@ static inline void pfm_post_work(struct + #define PFM_PMC_STK_ARG PFM_ARCH_PMC_STK_ARG + #define PFM_PMD_STK_ARG PFM_ARCH_PMD_STK_ARG + ++/* these used to be in linux/syscalls.h, now accessed via ioctl interface */ ++asmlinkage long sys_pfm_create_context(struct pfarg_ctx __user *ureq, ++ char __user *fmt_name, ++ void __user *fmt_uarg, size_t fmt_size); ++asmlinkage long sys_pfm_write_pmcs(int fd, struct pfarg_pmc __user *ureq, ++ int count); ++asmlinkage long sys_pfm_write_pmds(int fd, struct pfarg_pmd __user *ureq, ++ int count); ++asmlinkage long sys_pfm_read_pmds(int fd, struct pfarg_pmd __user *ureq, ++ int count); ++asmlinkage long sys_pfm_restart(int fd); ++asmlinkage long sys_pfm_stop(int fd); ++asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *ureq); ++asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ureq); ++asmlinkage long sys_pfm_unload_context(int fd); ++asmlinkage long sys_pfm_delete_evtsets(int fd, ++ struct pfarg_setinfo __user *ureq, ++ int count); ++asmlinkage long sys_pfm_create_evtsets(int fd, ++ struct pfarg_setdesc __user *ureq, ++ int count); ++asmlinkage long sys_pfm_getinfo_evtsets(int fd, ++ struct pfarg_setinfo __user *ureq, ++ int count); + #endif /* CONFIG_PERFMON */ + + #endif /* __PERFMON_PRIV_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/perfmon2-fix_disabled.patch b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-fix_disabled.patch new file mode 100644 index 000000000..b3710b50e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-fix_disabled.patch @@ -0,0 +1,19 @@ +From: Tony Jones +Subject: fix initializion of perfmon disabled +Patch-mainline: never + +Initialize perfmon_disabled flag. + +Signed-off-by: Tony Jones + +--- linux-2.6.27.orig/perfmon/perfmon_init.c ++++ linux-2.6.27/perfmon/perfmon_init.c +@@ -50,7 +50,7 @@ DEFINE_PER_CPU(struct pfm_stats, pfm_sta + DEFINE_PER_CPU(struct hrtimer, pfm_hrtimer); + + +-int perfmon_disabled; /* >0 if perfmon is disabled */ ++int perfmon_disabled = 0; /* >0 if perfmon is disabled */ + + /* + * called from cpu_init() and pfm_pmu_register() diff --git a/src/patches/suse-2.6.27.31/patches.suse/perfmon2-remove_get_base_syscall_attr.patch b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-remove_get_base_syscall_attr.patch new file mode 100644 index 000000000..191e058c5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-remove_get_base_syscall_attr.patch @@ -0,0 +1,111 @@ +From: Tony Jones +Subject: remove perfmon syscall_base attribyute +Patch-mainline: never + +Syscalls were removed, delete the old sysfs attribute that reported the +syscall base. + +Signed-off-by: Tony Jones + +--- +--- linux-2.6.27.orig/arch/ia64/include/asm/perfmon_kern.h ++++ linux-2.6.27/arch/ia64/include/asm/perfmon_kern.h +@@ -333,11 +333,6 @@ static inline void pfm_release_dbregs(st + + #define pfm_use_dbregs(_t) __pfm_use_dbregs(_t) + +-static inline int pfm_arch_get_base_syscall(void) +-{ +- return __NR_pfm_create_context; +-} +- + struct pfm_arch_pmu_info { + unsigned long mask_pmcs[PFM_PMC_BV]; /* modify on when masking */ + }; +--- linux-2.6.27.orig/arch/powerpc/include/asm/perfmon_kern.h ++++ linux-2.6.27/arch/powerpc/include/asm/perfmon_kern.h +@@ -359,11 +359,6 @@ static inline void pfm_arch_arm_handle_w + static inline void pfm_arch_disarm_handle_work(struct task_struct *task) + {} + +-static inline int pfm_arch_get_base_syscall(void) +-{ +- return __NR_pfm_create_context; +-} +- + struct pfm_arch_context { + /* Cell: Most recent value of the pm_status + * register read by the interrupt handler. +--- linux-2.6.27.orig/arch/sparc/include/asm/perfmon_kern.h ++++ linux-2.6.27/arch/sparc/include/asm/perfmon_kern.h +@@ -260,11 +260,6 @@ static inline int pfm_arch_pmu_config_in + return 0; + } + +-static inline int pfm_arch_get_base_syscall(void) +-{ +- return __NR_pfm_create_context; +-} +- + struct pfm_arch_context { + /* empty */ + }; +--- linux-2.6.27.orig/include/asm-x86/perfmon_kern.h ++++ linux-2.6.27/include/asm-x86/perfmon_kern.h +@@ -525,16 +525,6 @@ static inline void pfm_arch_arm_handle_w + static inline void pfm_arch_disarm_handle_work(struct task_struct *task) + {} + +-static inline int pfm_arch_get_base_syscall(void) +-{ +-#ifdef __x86_64__ +- /* 32-bit syscall definition coming from ia32_unistd.h */ +- if (test_thread_flag(TIF_IA32)) +- return __NR_ia32_pfm_create_context; +-#endif +- return __NR_pfm_create_context; +-} +- + #define PFM_ARCH_CTX_SIZE (sizeof(struct pfm_arch_context)) + /* + * x86 does not need extra alignment requirements for the sampling buffer +--- linux-2.6.27.orig/perfmon/perfmon_sysfs.c ++++ linux-2.6.27/perfmon/perfmon_sysfs.c +@@ -96,8 +96,6 @@ static struct kobj_type pfm_fmt_ktype = + + static ssize_t pfm_controls_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { +- int base; +- + if (is_attr_name(attr, "version")) + return snprintf(buf, PAGE_SIZE, "%u.%u\n", PFM_VERSION_MAJ, PFM_VERSION_MIN); + +@@ -115,12 +113,6 @@ static ssize_t pfm_controls_show(struct + + if (is_attr_name(attr, "arg_mem_max")) + return snprintf(buf, PAGE_SIZE, "%zu\n", pfm_controls.arg_mem_max); +- +- if (is_attr_name(attr, "syscall")) { +- base = pfm_arch_get_base_syscall(); +- return snprintf(buf, PAGE_SIZE, "%d\n", base); +- } +- + if (is_attr_name(attr, "sys_sessions_count")) + return pfm_sysfs_res_show(buf, PAGE_SIZE, 1); + +@@ -192,7 +184,6 @@ skip: + */ + static PFM_RO_ATTR(version, pfm_controls_show); + static PFM_RO_ATTR(task_sessions_count, pfm_controls_show); +-static PFM_RO_ATTR(syscall, pfm_controls_show); + static PFM_RO_ATTR(sys_sessions_count, pfm_controls_show); + static PFM_RO_ATTR(smpl_buffer_mem_cur, pfm_controls_show); + +@@ -206,7 +199,6 @@ static PFM_RW_ATTR(reset_stats, pfm_cont + + static struct attribute *pfm_kernel_attrs[] = { + &attr_version.attr, +- &attr_syscall.attr, + &attr_task_sessions_count.attr, + &attr_sys_sessions_count.attr, + &attr_smpl_buffer_mem_cur.attr, diff --git a/src/patches/suse-2.6.27.31/patches.suse/perfmon2-remove_syscalls.patch b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-remove_syscalls.patch new file mode 100644 index 000000000..77eef2a8a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/perfmon2-remove_syscalls.patch @@ -0,0 +1,526 @@ +From: Tony Jones +Subject: drop additional perfmon2 syscalls +Patch-mainline: never + +Patch accepted from SGI (bnc#430298, FATE #303968) added 12 new syscalls +which have been replaced (for SLES11) with an ioctl based interface. + +Remove the relevant syscalls. + +Signed-off-by: Tony Jones + +--- + arch/ia64/include/asm/unistd.h | 14 ----------- + arch/ia64/kernel/entry.S | 12 --------- + arch/mips/kernel/scall32-o32.S | 12 --------- + arch/mips/kernel/scall64-64.S | 12 --------- + arch/mips/kernel/scall64-n32.S | 16 +----------- + arch/mips/kernel/scall64-o32.S | 12 --------- + arch/powerpc/include/asm/systbl.h | 12 --------- + arch/powerpc/include/asm/unistd.h | 14 ----------- + arch/sparc/include/asm/unistd_32.h | 14 ----------- + arch/sparc/include/asm/unistd_64.h | 14 ----------- + arch/sparc/kernel/systbls.S | 4 --- + arch/sparc64/kernel/systbls.S | 8 +----- + arch/x86/ia32/ia32entry.S | 12 --------- + arch/x86/kernel/syscall_table_32.S | 12 --------- + include/asm-mips/unistd.h | 46 ++++--------------------------------- + include/asm-x86/ia32_unistd.h | 13 ++++------ + include/asm-x86/unistd_32.h | 14 ----------- + include/asm-x86/unistd_64.h | 25 -------------------- + kernel/sys_ni.c | 13 ---------- + 19 files changed, 21 insertions(+), 258 deletions(-) + +--- a/arch/ia64/include/asm/unistd.h ++++ b/arch/ia64/include/asm/unistd.h +@@ -308,23 +308,11 @@ + #define __NR_dup3 1316 + #define __NR_pipe2 1317 + #define __NR_inotify_init1 1318 +-#define __NR_pfm_create_context 1319 +-#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) +-#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) +-#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) +-#define __NR_pfm_load_context (__NR_pfm_create_context+4) +-#define __NR_pfm_start (__NR_pfm_create_context+5) +-#define __NR_pfm_stop (__NR_pfm_create_context+6) +-#define __NR_pfm_restart (__NR_pfm_create_context+7) +-#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) +-#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) +-#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) +-#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + #ifdef __KERNEL__ + + +-#define NR_syscalls 307 /* length of syscall table */ ++#define NR_syscalls 295 /* length of syscall table */ + + /* + * The following defines stop scripts/checksyscalls.sh from complaining about +--- a/arch/ia64/kernel/entry.S ++++ b/arch/ia64/kernel/entry.S +@@ -1697,18 +1697,6 @@ sys_call_table: + data8 sys_dup3 + data8 sys_pipe2 + data8 sys_inotify_init1 +- data8 sys_pfm_create_context +- data8 sys_pfm_write_pmcs // 1320 +- data8 sys_pfm_write_pmds +- data8 sys_pfm_read_pmds +- data8 sys_pfm_load_context +- data8 sys_pfm_start +- data8 sys_pfm_stop // 1325 +- data8 sys_pfm_restart +- data8 sys_pfm_create_evtsets +- data8 sys_pfm_getinfo_evtsets +- data8 sys_pfm_delete_evtsets +- data8 sys_pfm_unload_context // 1330 + + .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls + #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ +--- a/arch/mips/kernel/scall32-o32.S ++++ b/arch/mips/kernel/scall32-o32.S +@@ -653,18 +653,6 @@ einval: li v0, -EINVAL + sys sys_dup3 3 + sys sys_pipe2 2 + sys sys_inotify_init1 1 +- sys sys_pfm_create_context 4 /* 4330 */ +- sys sys_pfm_write_pmcs 3 +- sys sys_pfm_write_pmds 4 +- sys sys_pfm_read_pmds 3 +- sys sys_pfm_load_context 2 +- sys sys_pfm_start 2 /* 4335 */ +- sys sys_pfm_stop 1 +- sys sys_pfm_restart 1 +- sys sys_pfm_create_evtsets 3 +- sys sys_pfm_getinfo_evtsets 3 +- sys sys_pfm_delete_evtsets 3 /* 4340 */ +- sys sys_pfm_unload_context 1 + .endm + + /* We pre-compute the number of _instruction_ bytes needed to +--- a/arch/mips/kernel/scall64-64.S ++++ b/arch/mips/kernel/scall64-64.S +@@ -487,16 +487,4 @@ sys_call_table: + PTR sys_dup3 + PTR sys_pipe2 + PTR sys_inotify_init1 +- PTR sys_pfm_create_context +- PTR sys_pfm_write_pmcs /* 5290 */ +- PTR sys_pfm_write_pmds +- PTR sys_pfm_read_pmds +- PTR sys_pfm_load_context +- PTR sys_pfm_start +- PTR sys_pfm_stop /* 5295 */ +- PTR sys_pfm_restart +- PTR sys_pfm_create_evtsets +- PTR sys_pfm_getinfo_evtsets +- PTR sys_pfm_delete_evtsets +- PTR sys_pfm_unload_context /* 5300 */ + .size sys_call_table,.-sys_call_table +--- a/arch/mips/kernel/scall64-n32.S ++++ b/arch/mips/kernel/scall64-n32.S +@@ -400,12 +400,12 @@ EXPORT(sysn32_call_table) + PTR sys_ioprio_set + PTR sys_ioprio_get + PTR compat_sys_utimensat +- PTR compat_sys_signalfd /* 6280 */ ++ PTR compat_sys_signalfd /* 5280 */ + PTR sys_ni_syscall + PTR sys_eventfd + PTR sys_fallocate + PTR sys_timerfd_create +- PTR sys_timerfd_gettime /* 6285 */ ++ PTR sys_timerfd_gettime /* 5285 */ + PTR sys_timerfd_settime + PTR sys_signalfd4 + PTR sys_eventfd2 +@@ -413,16 +413,4 @@ EXPORT(sysn32_call_table) + PTR sys_dup3 /* 5290 */ + PTR sys_pipe2 + PTR sys_inotify_init1 +- PTR sys_pfm_create_context +- PTR sys_pfm_write_pmcs +- PTR sys_pfm_write_pmds /* 6295 */ +- PTR sys_pfm_read_pmds +- PTR sys_pfm_load_context +- PTR sys_pfm_start +- PTR sys_pfm_stop +- PTR sys_pfm_restart /* 6300 */ +- PTR sys_pfm_create_evtsets +- PTR sys_pfm_getinfo_evtsets +- PTR sys_pfm_delete_evtsets +- PTR sys_pfm_unload_context + .size sysn32_call_table,.-sysn32_call_table +--- a/arch/mips/kernel/scall64-o32.S ++++ b/arch/mips/kernel/scall64-o32.S +@@ -535,16 +535,4 @@ sys_call_table: + PTR sys_dup3 + PTR sys_pipe2 + PTR sys_inotify_init1 +- PTR sys_pfm_create_context /* 4330 */ +- PTR sys_pfm_write_pmcs +- PTR sys_pfm_write_pmds +- PTR sys_pfm_read_pmds +- PTR sys_pfm_load_context +- PTR sys_pfm_start /* 4335 */ +- PTR sys_pfm_stop +- PTR sys_pfm_restart +- PTR sys_pfm_create_evtsets +- PTR sys_pfm_getinfo_evtsets +- PTR sys_pfm_delete_evtsets /* 4340 */ +- PTR sys_pfm_unload_context + .size sys_call_table,.-sys_call_table +--- a/arch/powerpc/include/asm/systbl.h ++++ b/arch/powerpc/include/asm/systbl.h +@@ -322,15 +322,3 @@ SYSCALL_SPU(epoll_create1) + SYSCALL_SPU(dup3) + SYSCALL_SPU(pipe2) + SYSCALL(inotify_init1) +-SYSCALL(pfm_create_context) +-SYSCALL(pfm_write_pmcs) +-SYSCALL(pfm_write_pmds) +-SYSCALL(pfm_read_pmds) +-SYSCALL(pfm_load_context) +-SYSCALL(pfm_start) +-SYSCALL(pfm_stop) +-SYSCALL(pfm_restart) +-SYSCALL(pfm_create_evtsets) +-SYSCALL(pfm_getinfo_evtsets) +-SYSCALL(pfm_delete_evtsets) +-SYSCALL(pfm_unload_context) +--- a/arch/powerpc/include/asm/unistd.h ++++ b/arch/powerpc/include/asm/unistd.h +@@ -341,22 +341,10 @@ + #define __NR_dup3 316 + #define __NR_pipe2 317 + #define __NR_inotify_init1 318 +-#define __NR_pfm_create_context 319 +-#define __NR_pfm_write_pmcs 320 +-#define __NR_pfm_write_pmds 321 +-#define __NR_pfm_read_pmds 322 +-#define __NR_pfm_load_context 323 +-#define __NR_pfm_start 324 +-#define __NR_pfm_stop 325 +-#define __NR_pfm_restart 326 +-#define __NR_pfm_create_evtsets 327 +-#define __NR_pfm_getinfo_evtsets 328 +-#define __NR_pfm_delete_evtsets 329 +-#define __NR_pfm_unload_context 330 + + #ifdef __KERNEL__ + +-#define __NR_syscalls 331 ++#define __NR_syscalls 319 + + #define __NR__exit __NR_exit + #define NR_syscalls __NR_syscalls +--- a/arch/sparc64/kernel/systbls.S ++++ b/arch/sparc64/kernel/systbls.S +@@ -82,9 +82,7 @@ sys_call_table32: + .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait + /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate + .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 +-/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_pfm_create_context, sys_pfm_write_pmcs +- .word sys_pfm_write_pmds, sys_pfm_read_pmds, sys_pfm_load_context, sys_pfm_start, sys_pfm_stop +-/*330*/ .word sys_pfm_restart, sys_pfm_create_evtsets, sys_pfm_getinfo_evtsets, sys_pfm_delete_evtsets, sys_pfm_unload_context ++/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1 + + #endif /* CONFIG_COMPAT */ + +@@ -158,6 +156,4 @@ sys_call_table: + .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait + /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate + .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 +-/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_pfm_create_context, sys_pfm_write_pmcs +- .word sys_pfm_write_pmds, sys_pfm_read_pmds, sys_pfm_load_context, sys_pfm_start, sys_pfm_stop +-/*330*/ .word sys_pfm_restart, sys_pfm_create_evtsets, sys_pfm_getinfo_evtsets, sys_pfm_delete_evtsets, sys_pfm_unload_context ++/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1 +--- a/arch/sparc/include/asm/unistd_32.h ++++ b/arch/sparc/include/asm/unistd_32.h +@@ -338,20 +338,8 @@ + #define __NR_dup3 320 + #define __NR_pipe2 321 + #define __NR_inotify_init1 322 +-#define __NR_pfm_create_context 323 +-#define __NR_pfm_write_pmcs 324 +-#define __NR_pfm_write_pmds 325 +-#define __NR_pfm_read_pmds 326 +-#define __NR_pfm_load_context 327 +-#define __NR_pfm_start 328 +-#define __NR_pfm_stop 329 +-#define __NR_pfm_restart 330 +-#define __NR_pfm_create_evtsets 331 +-#define __NR_pfm_getinfo_evtsets 332 +-#define __NR_pfm_delete_evtsets 333 +-#define __NR_pfm_unload_context 334 + +-#define NR_SYSCALLS 325 ++#define NR_SYSCALLS 323 + + /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, + * it never had the plain ones and there is no value to adding those +--- a/arch/sparc/include/asm/unistd_64.h ++++ b/arch/sparc/include/asm/unistd_64.h +@@ -340,20 +340,8 @@ + #define __NR_dup3 320 + #define __NR_pipe2 321 + #define __NR_inotify_init1 322 +-#define __NR_pfm_create_context 323 +-#define __NR_pfm_write_pmcs 324 +-#define __NR_pfm_write_pmds 325 +-#define __NR_pfm_read_pmds 326 +-#define __NR_pfm_load_context 327 +-#define __NR_pfm_start 328 +-#define __NR_pfm_stop 329 +-#define __NR_pfm_restart 330 +-#define __NR_pfm_create_evtsets 331 +-#define __NR_pfm_getinfo_evtsets 332 +-#define __NR_pfm_delete_evtsets 333 +-#define __NR_pfm_unload_context 334 + +-#define NR_SYSCALLS 335 ++#define NR_SYSCALLS 323 + + #ifdef __KERNEL__ + #define __ARCH_WANT_IPC_PARSE_VERSION +--- a/arch/sparc/kernel/systbls.S ++++ b/arch/sparc/kernel/systbls.S +@@ -81,6 +81,4 @@ sys_call_table: + /*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait + /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate + /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 +-/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_pfm_create_context, sys_pfm_write_pmcs, sys_pfm_write_pmds +-/*325*/ .long sys_pfm_write_pmds, sys_pfm_read_pmds, sys_pfm_load_context, sys_pfm_start, sys_pfm_stop +-/*330*/ .long sys_pfm_restart, sys_pfm_create_evtsets, sys_pfm_getinfo_evtsets, sys_pfm_delete_evtsets, sys_pfm_unload_context ++/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1 +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -834,16 +834,4 @@ ia32_sys_call_table: + .quad sys_dup3 /* 330 */ + .quad sys_pipe2 + .quad sys_inotify_init1 +- .quad sys_pfm_create_context +- .quad sys_pfm_write_pmcs +- .quad sys_pfm_write_pmds /* 335 */ +- .quad sys_pfm_read_pmds +- .quad sys_pfm_load_context +- .quad sys_pfm_start +- .quad sys_pfm_stop +- .quad sys_pfm_restart /* 340 */ +- .quad sys_pfm_create_evtsets +- .quad sys_pfm_getinfo_evtsets +- .quad sys_pfm_delete_evtsets +- .quad sys_pfm_unload_context + ia32_syscall_end: +--- a/arch/x86/kernel/syscall_table_32.S ++++ b/arch/x86/kernel/syscall_table_32.S +@@ -332,15 +332,3 @@ ENTRY(sys_call_table) + .long sys_dup3 /* 330 */ + .long sys_pipe2 + .long sys_inotify_init1 +- .long sys_pfm_create_context +- .long sys_pfm_write_pmcs +- .long sys_pfm_write_pmds /* 335 */ +- .long sys_pfm_read_pmds +- .long sys_pfm_load_context +- .long sys_pfm_start +- .long sys_pfm_stop +- .long sys_pfm_restart /* 340 */ +- .long sys_pfm_create_evtsets +- .long sys_pfm_getinfo_evtsets +- .long sys_pfm_delete_evtsets +- .long sys_pfm_unload_context +--- a/include/asm-mips/unistd.h ++++ b/include/asm-mips/unistd.h +@@ -350,23 +350,11 @@ + #define __NR_dup3 (__NR_Linux + 327) + #define __NR_pipe2 (__NR_Linux + 328) + #define __NR_inotify_init1 (__NR_Linux + 329) +-#define __NR_pfm_create_context (__NR_Linux + 330) +-#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) +-#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) +-#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) +-#define __NR_pfm_load_context (__NR_pfm_create_context+4) +-#define __NR_pfm_start (__NR_pfm_create_context+5) +-#define __NR_pfm_stop (__NR_pfm_create_context+6) +-#define __NR_pfm_restart (__NR_pfm_create_context+7) +-#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) +-#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) +-#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) +-#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + /* + * Offset of the last Linux o32 flavoured syscall + */ +-#define __NR_Linux_syscalls 341 ++#define __NR_Linux_syscalls 329 + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ + +@@ -668,28 +656,16 @@ + #define __NR_dup3 (__NR_Linux + 286) + #define __NR_pipe2 (__NR_Linux + 287) + #define __NR_inotify_init1 (__NR_Linux + 288) +-#define __NR_pfm_create_context (__NR_Linux + 289) +-#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) +-#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) +-#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) +-#define __NR_pfm_load_context (__NR_pfm_create_context+4) +-#define __NR_pfm_start (__NR_pfm_create_context+5) +-#define __NR_pfm_stop (__NR_pfm_create_context+6) +-#define __NR_pfm_restart (__NR_pfm_create_context+7) +-#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) +-#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) +-#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) +-#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + /* + * Offset of the last Linux 64-bit flavoured syscall + */ +-#define __NR_Linux_syscalls 300 ++#define __NR_Linux_syscalls 288 + + #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ + + #define __NR_64_Linux 5000 +-#define __NR_64_Linux_syscalls 300 ++#define __NR_64_Linux_syscalls 288 + + #if _MIPS_SIM == _MIPS_SIM_NABI32 + +@@ -990,28 +966,16 @@ + #define __NR_dup3 (__NR_Linux + 290) + #define __NR_pipe2 (__NR_Linux + 291) + #define __NR_inotify_init1 (__NR_Linux + 292) +-#define __NR_pfm_create_context (__NR_Linux + 293) +-#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) +-#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) +-#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) +-#define __NR_pfm_load_context (__NR_pfm_create_context+4) +-#define __NR_pfm_start (__NR_pfm_create_context+5) +-#define __NR_pfm_stop (__NR_pfm_create_context+6) +-#define __NR_pfm_restart (__NR_pfm_create_context+7) +-#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) +-#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) +-#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) +-#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + /* + * Offset of the last N32 flavoured syscall + */ +-#define __NR_Linux_syscalls 304 ++#define __NR_Linux_syscalls 292 + + #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ + + #define __NR_N32_Linux 6000 +-#define __NR_N32_Linux_syscalls 304 ++#define __NR_N32_Linux_syscalls 292 + + #ifdef __KERNEL__ + +--- a/include/asm-x86/ia32_unistd.h ++++ b/include/asm-x86/ia32_unistd.h +@@ -8,12 +8,11 @@ + * the number. This should be otherwise in sync with asm-x86/unistd_32.h. -AK + */ + +-#define __NR_ia32_restart_syscall 0 +-#define __NR_ia32_exit 1 +-#define __NR_ia32_read 3 +-#define __NR_ia32_write 4 +-#define __NR_ia32_sigreturn 119 +-#define __NR_ia32_rt_sigreturn 173 +-#define __NR_ia32_pfm_create_context 333 ++#define __NR_ia32_restart_syscall 0 ++#define __NR_ia32_exit 1 ++#define __NR_ia32_read 3 ++#define __NR_ia32_write 4 ++#define __NR_ia32_sigreturn 119 ++#define __NR_ia32_rt_sigreturn 173 + + #endif /* _ASM_X86_64_IA32_UNISTD_H_ */ +--- a/include/asm-x86/unistd_32.h ++++ b/include/asm-x86/unistd_32.h +@@ -338,23 +338,9 @@ + #define __NR_dup3 330 + #define __NR_pipe2 331 + #define __NR_inotify_init1 332 +-#define __NR_pfm_create_context 333 +-#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) +-#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) +-#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) +-#define __NR_pfm_load_context (__NR_pfm_create_context+4) +-#define __NR_pfm_start (__NR_pfm_create_context+5) +-#define __NR_pfm_stop (__NR_pfm_create_context+6) +-#define __NR_pfm_restart (__NR_pfm_create_context+7) +-#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) +-#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) +-#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) +-#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + #ifdef __KERNEL__ + +-#define NR_syscalls 345 +- + #define __ARCH_WANT_IPC_PARSE_VERSION + #define __ARCH_WANT_OLD_READDIR + #define __ARCH_WANT_OLD_STAT +--- a/include/asm-x86/unistd_64.h ++++ b/include/asm-x86/unistd_64.h +@@ -653,30 +653,7 @@ __SYSCALL(__NR_dup3, sys_dup3) + __SYSCALL(__NR_pipe2, sys_pipe2) + #define __NR_inotify_init1 294 + __SYSCALL(__NR_inotify_init1, sys_inotify_init1) +-#define __NR_pfm_create_context 295 +-__SYSCALL(__NR_pfm_create_context, sys_pfm_create_context) +-#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) +-__SYSCALL(__NR_pfm_write_pmcs, sys_pfm_write_pmcs) +-#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) +-__SYSCALL(__NR_pfm_write_pmds, sys_pfm_write_pmds) +-#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) +- __SYSCALL(__NR_pfm_read_pmds, sys_pfm_read_pmds) +-#define __NR_pfm_load_context (__NR_pfm_create_context+4) +-__SYSCALL(__NR_pfm_load_context, sys_pfm_load_context) +-#define __NR_pfm_start (__NR_pfm_create_context+5) +-__SYSCALL(__NR_pfm_start, sys_pfm_start) +-#define __NR_pfm_stop (__NR_pfm_create_context+6) +-__SYSCALL(__NR_pfm_stop, sys_pfm_stop) +-#define __NR_pfm_restart (__NR_pfm_create_context+7) +-__SYSCALL(__NR_pfm_restart, sys_pfm_restart) +-#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) +-__SYSCALL(__NR_pfm_create_evtsets, sys_pfm_create_evtsets) +-#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) +-__SYSCALL(__NR_pfm_getinfo_evtsets, sys_pfm_getinfo_evtsets) +-#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) +-__SYSCALL(__NR_pfm_delete_evtsets, sys_pfm_delete_evtsets) +-#define __NR_pfm_unload_context (__NR_pfm_create_context+11) +-__SYSCALL(__NR_pfm_unload_context, sys_pfm_unload_context) ++ + + #ifndef __NO_STUBS + #define __ARCH_WANT_OLD_READDIR +--- a/kernel/sys_ni.c ++++ b/kernel/sys_ni.c +@@ -127,19 +127,6 @@ cond_syscall(compat_sys_ipc); + cond_syscall(compat_sys_sysctl); + cond_syscall(sys_syslog); + +-cond_syscall(sys_pfm_create_context); +-cond_syscall(sys_pfm_write_pmcs); +-cond_syscall(sys_pfm_write_pmds); +-cond_syscall(sys_pfm_read_pmds); +-cond_syscall(sys_pfm_restart); +-cond_syscall(sys_pfm_start); +-cond_syscall(sys_pfm_stop); +-cond_syscall(sys_pfm_load_context); +-cond_syscall(sys_pfm_unload_context); +-cond_syscall(sys_pfm_create_evtsets); +-cond_syscall(sys_pfm_delete_evtsets); +-cond_syscall(sys_pfm_getinfo_evtsets); +- + /* arch-specific weak syscall entries */ + cond_syscall(sys_pciconfig_read); + cond_syscall(sys_pciconfig_write); diff --git a/src/patches/suse-2.6.27.31/patches.suse/perfmon2.patch b/src/patches/suse-2.6.27.31/patches.suse/perfmon2.patch new file mode 100644 index 000000000..c96e24ee1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/perfmon2.patch @@ -0,0 +1,31401 @@ +From: Cliff Wickman +Subject: perfmon2 +References: bnc#430298 +Patch-mainline: never + +This is Stephane Eranian's patch +from http://perfmon2.sourceforge.net/ +but backfitted to the SuSE KOTD for 10/20/2008 + +[greg's note: I really don't like this, as perfmon2 has been rejected +from upstream, and perfmon3 is being worked on. This should be going +away for SP1, and no one should count on the userspace interface +remaining the same...] + +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/ABI/testing/sysfs-perfmon | 87 + + Documentation/ABI/testing/sysfs-perfmon-fmt | 18 + Documentation/ABI/testing/sysfs-perfmon-pmu | 46 + Documentation/kernel-parameters.txt | 3 + Documentation/perfmon2-debugfs.txt | 126 ++ + Documentation/perfmon2.txt | 213 +++ + MAINTAINERS | 8 + Makefile | 1 + arch/ia64/Kconfig | 10 + arch/ia64/Makefile | 1 + arch/ia64/configs/generic_defconfig | 11 + arch/ia64/include/asm/Kbuild | 4 + arch/ia64/include/asm/hw_irq.h | 2 + arch/ia64/include/asm/perfmon.h | 302 ----- + arch/ia64/include/asm/perfmon_compat.h | 167 +++ + arch/ia64/include/asm/perfmon_default_smpl.h | 121 +- + arch/ia64/include/asm/perfmon_kern.h | 356 ++++++ + arch/ia64/include/asm/processor.h | 10 + arch/ia64/include/asm/system.h | 18 + arch/ia64/include/asm/thread_info.h | 4 + arch/ia64/include/asm/unistd.h | 14 + arch/ia64/kernel/Makefile | 3 + arch/ia64/kernel/entry.S | 12 + arch/ia64/kernel/irq_ia64.c | 7 + arch/ia64/kernel/perfmon_default_smpl.c | 296 ----- + arch/ia64/kernel/perfmon_generic.h | 45 + arch/ia64/kernel/perfmon_itanium.h | 115 -- + arch/ia64/kernel/perfmon_mckinley.h | 187 --- + arch/ia64/kernel/perfmon_montecito.h | 269 ----- + arch/ia64/kernel/process.c | 98 - + arch/ia64/kernel/ptrace.c | 8 + arch/ia64/kernel/setup.c | 3 + arch/ia64/kernel/smpboot.c | 10 + arch/ia64/kernel/sys_ia64.c | 8 + arch/ia64/lib/Makefile | 1 + arch/ia64/oprofile/init.c | 8 + arch/ia64/oprofile/perfmon.c | 39 + arch/ia64/perfmon/Kconfig | 67 + + arch/ia64/perfmon/Makefile | 11 + arch/ia64/perfmon/perfmon.c | 946 +++++++++++++++++ + arch/ia64/perfmon/perfmon_compat.c | 1210 ++++++++++++++++++++++ + arch/ia64/perfmon/perfmon_default_smpl.c | 273 +++++ + arch/ia64/perfmon/perfmon_generic.c | 148 ++ + arch/ia64/perfmon/perfmon_itanium.c | 232 ++++ + arch/ia64/perfmon/perfmon_mckinley.c | 290 +++++ + arch/ia64/perfmon/perfmon_montecito.c | 412 +++++++ + arch/mips/Kconfig | 2 + arch/mips/Makefile | 6 + arch/mips/kernel/process.c | 4 + arch/mips/kernel/scall32-o32.S | 12 + arch/mips/kernel/scall64-64.S | 12 + arch/mips/kernel/scall64-n32.S | 16 + arch/mips/kernel/scall64-o32.S | 12 + arch/mips/kernel/signal.c | 6 + arch/mips/kernel/time.c | 3 + arch/mips/kernel/traps.c | 16 + arch/mips/mti-malta/malta-time.c | 1 + arch/mips/perfmon/Kconfig | 61 + + arch/mips/perfmon/Makefile | 2 + arch/mips/perfmon/perfmon.c | 313 +++++ + arch/mips/perfmon/perfmon_mips64.c | 218 ++++ + arch/powerpc/Kconfig | 2 + arch/powerpc/Makefile | 1 + arch/powerpc/include/asm/Kbuild | 1 + arch/powerpc/include/asm/cell-pmu.h | 5 + arch/powerpc/include/asm/cell-regs.h | 30 + arch/powerpc/include/asm/paca.h | 4 + arch/powerpc/include/asm/perfmon.h | 33 + arch/powerpc/include/asm/perfmon_kern.h | 390 +++++++ + arch/powerpc/include/asm/reg.h | 1 + arch/powerpc/include/asm/systbl.h | 12 + arch/powerpc/include/asm/thread_info.h | 4 + arch/powerpc/include/asm/unistd.h | 14 + arch/powerpc/kernel/entry_32.S | 2 + arch/powerpc/kernel/entry_64.S | 4 + arch/powerpc/kernel/irq.c | 31 + arch/powerpc/kernel/process.c | 10 + arch/powerpc/perfmon/Kconfig | 67 + + arch/powerpc/perfmon/Makefile | 6 + arch/powerpc/perfmon/perfmon.c | 334 ++++++ + arch/powerpc/perfmon/perfmon_cell.c | 1449 +++++++++++++++++++++++++++ + arch/powerpc/perfmon/perfmon_power4.c | 309 +++++ + arch/powerpc/perfmon/perfmon_power5.c | 326 ++++++ + arch/powerpc/perfmon/perfmon_power6.c | 520 +++++++++ + arch/powerpc/perfmon/perfmon_ppc32.c | 340 ++++++ + arch/powerpc/platforms/cell/cbe_regs.c | 27 + arch/sparc/include/asm/hypervisor.h | 24 + arch/sparc/include/asm/irq_64.h | 3 + arch/sparc/include/asm/perfmon.h | 11 + arch/sparc/include/asm/perfmon_kern.h | 286 +++++ + arch/sparc/include/asm/system_64.h | 34 + arch/sparc/include/asm/thread_info_64.h | 28 + arch/sparc/include/asm/unistd_32.h | 14 + arch/sparc/include/asm/unistd_64.h | 14 + arch/sparc/kernel/systbls.S | 4 + arch/sparc64/Kconfig | 2 + arch/sparc64/Makefile | 2 + arch/sparc64/kernel/cpu.c | 47 + arch/sparc64/kernel/hvcalls.S | 41 + arch/sparc64/kernel/irq.c | 63 + + arch/sparc64/kernel/process.c | 26 + arch/sparc64/kernel/rtrap.S | 51 + arch/sparc64/kernel/setup.c | 2 + arch/sparc64/kernel/signal.c | 4 + arch/sparc64/kernel/sys_sparc.c | 101 - + arch/sparc64/kernel/syscalls.S | 23 + arch/sparc64/kernel/systbls.S | 8 + arch/sparc64/kernel/traps.c | 158 +- + arch/sparc64/kernel/ttable.S | 2 + arch/sparc64/perfmon/Kconfig | 26 + arch/sparc64/perfmon/Makefile | 1 + arch/sparc64/perfmon/perfmon.c | 422 +++++++ + arch/x86/Kconfig | 2 + arch/x86/Makefile | 2 + arch/x86/ia32/ia32entry.S | 12 + arch/x86/kernel/apic_32.c | 5 + arch/x86/kernel/apic_64.c | 1 + arch/x86/kernel/cpu/common.c | 3 + arch/x86/kernel/entry_32.S | 2 + arch/x86/kernel/entry_64.S | 8 + arch/x86/kernel/irqinit_64.c | 5 + arch/x86/kernel/process_32.c | 10 + arch/x86/kernel/process_64.c | 10 + arch/x86/kernel/signal_32.c | 5 + arch/x86/kernel/signal_64.c | 6 + arch/x86/kernel/smpboot.c | 2 + arch/x86/kernel/syscall_table_32.S | 12 + arch/x86/oprofile/nmi_int.c | 10 + arch/x86/perfmon/Kconfig | 89 + + arch/x86/perfmon/Makefile | 13 + arch/x86/perfmon/perfmon.c | 761 ++++++++++++++ + arch/x86/perfmon/perfmon_amd64.c | 754 ++++++++++++++ + arch/x86/perfmon/perfmon_intel_arch.c | 610 +++++++++++ + arch/x86/perfmon/perfmon_intel_atom.c | 541 ++++++++++ + arch/x86/perfmon/perfmon_intel_core.c | 449 ++++++++ + arch/x86/perfmon/perfmon_p4.c | 913 +++++++++++++++++ + arch/x86/perfmon/perfmon_p6.c | 310 +++++ + arch/x86/perfmon/perfmon_pebs_core_smpl.c | 256 ++++ + arch/x86/perfmon/perfmon_pebs_p4_smpl.c | 253 ++++ + include/asm-mips/Kbuild | 1 + include/asm-mips/perfmon.h | 34 + include/asm-mips/perfmon_kern.h | 412 +++++++ + include/asm-mips/system.h | 4 + include/asm-mips/thread_info.h | 4 + include/asm-mips/unistd.h | 46 + include/asm-x86/Kbuild | 1 + include/asm-x86/ia32_unistd.h | 13 + include/asm-x86/irq_vectors.h | 5 + include/asm-x86/mach-default/entry_arch.h | 4 + include/asm-x86/perfmon.h | 34 + include/asm-x86/perfmon_kern.h | 548 ++++++++++ + include/asm-x86/perfmon_pebs_core_smpl.h | 164 +++ + include/asm-x86/perfmon_pebs_p4_smpl.h | 193 +++ + include/asm-x86/thread_info.h | 8 + include/asm-x86/unistd_32.h | 14 + include/asm-x86/unistd_64.h | 25 + include/linux/Kbuild | 2 + include/linux/perfmon.h | 213 +++ + include/linux/perfmon_dfl_smpl.h | 78 + + include/linux/perfmon_fmt.h | 74 + + include/linux/perfmon_kern.h | 551 ++++++++++ + include/linux/perfmon_pmu.h | 192 +++ + include/linux/sched.h | 4 + include/linux/syscalls.h | 30 + kernel/sched.c | 1 + kernel/sys_ni.c | 13 + perfmon/Makefile | 12 + perfmon/perfmon_activate.c | 265 ++++ + perfmon/perfmon_attach.c | 474 ++++++++ + perfmon/perfmon_ctx.c | 314 +++++ + perfmon/perfmon_ctxsw.c | 342 ++++++ + perfmon/perfmon_debugfs.c | 168 +++ + perfmon/perfmon_dfl_smpl.c | 298 +++++ + perfmon/perfmon_file.c | 751 +++++++++++++ + perfmon/perfmon_fmt.c | 219 ++++ + perfmon/perfmon_hotplug.c | 151 ++ + perfmon/perfmon_init.c | 131 ++ + perfmon/perfmon_intr.c | 648 ++++++++++++ + perfmon/perfmon_msg.c | 229 ++++ + perfmon/perfmon_pmu.c | 590 ++++++++++ + perfmon/perfmon_priv.h | 182 +++ + perfmon/perfmon_res.c | 450 ++++++++ + perfmon/perfmon_rw.c | 733 +++++++++++++ + perfmon/perfmon_sets.c | 873 ++++++++++++++++ + perfmon/perfmon_smpl.c | 865 ++++++++++++++++ + perfmon/perfmon_syscalls.c | 1060 +++++++++++++++++++ + perfmon/perfmon_sysfs.c | 525 +++++++++ + 187 files changed, 27484 insertions(+), 1731 deletions(-) + +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-perfmon +@@ -0,0 +1,87 @@ ++What: /sys/kernel/perfmon ++Date: Nov 2007 ++KernelVersion: 2.6.24 ++Contact: eranian@gmail.com ++ ++Description: provide the configuration interface for the perfmon2 subsystems. ++ The tree contains information about the detected hardware, current ++ state of the subsystem as well as some configuration parameters. ++ ++ The tree consists of the following entries: ++ ++ /sys/kernel/perfmon/debug (read-write): ++ ++ Enable perfmon2 debugging output via klogd. Debug messages produced during ++ PMU interrupt handling are not controlled by this entry. The traces a rate-limited ++ to avoid flooding of the console. It is possible to change the throttling ++ via /proc/sys/kernel/printk_ratelimit. The value is interpreted as a bitmask. ++ Each bit enables a particular type of debug messages. Refer to the file ++ include/linux/perfmon_kern.h for more information ++ ++ /sys/kernel/perfmon/pmc_max_fast_arg (read-only): ++ ++ Number of perfmon2 syscall arguments copied directly onto the ++ stack (copy_from_user) for pfm_write_pmcs(). Copying to the stack avoids ++ having to allocate a buffer. The unit is the number of pfarg_pmc_t ++ structures. ++ ++ /sys/kernel/perfmon/pmd_max_fast_arg (read-only): ++ ++ Number of perfmon2 syscall arguments copied directly onto the ++ stack (copy_from_user) for pfm_write_pmds()/pfm_read_pmds(). Copying ++ to the stack avoids having to allocate a buffer. The unit is the number ++ of pfarg_pmd_t structures. ++ ++ ++ /sys/kernel/perfmon/reset_stats (write-only): ++ ++ Reset the statistics collected by perfmon2. Stats are available ++ per-cpu via debugfs. ++ ++ /sys/kernel/perfmon/smpl_buffer_mem_cur (read-only): ++ ++ Reports the amount of memory currently dedicated to sampling ++ buffers by the kernel. The unit is byte. ++ ++ /sys/kernel/perfmon/smpl_buffer_mem_max (read-write): ++ ++ Maximum amount of kernel memory usable for sampling buffers. -1 means ++ everything that is available. Unit is byte. ++ ++ /sys/kernel/perfmon/smpl_buffer_mem_cur (read-only): ++ ++ Current utilization of kernel memory in bytes. ++ ++ /sys/kernel/perfmon/sys_group (read-write): ++ ++ Users group allowed to create a system-wide perfmon2 context (session). ++ -1 means any group. This control will be kept until we find a package ++ able to control capabilities via PAM. ++ ++ /sys/kernel/perfmon/task_group (read-write): ++ ++ Users group allowed to create a per-thread context (session). ++ -1 means any group. This control will be kept until we find a ++ package able to control capabilities via PAM. ++ ++ /sys/kernel/perfmon/sys_sessions_count (read-only): ++ ++ Number of system-wide contexts currently attached to CPUs. ++ ++ /sys/kernel/perfmon/task_sessions_count (read-only): ++ ++ Number of per-thread contexts currently attached to threads. ++ ++ /sys/kernel/perfmon/version (read-only): ++ ++ Perfmon2 interface revision number. ++ ++ /sys/kernel/perfmon/arg_mem_max(read-write): ++ ++ Maximum size of vector arguments expressed in bytes. Can be modified ++ ++ /sys/kernel/perfmon/mode(read-write): ++ ++ Bitmask to enable/disable certain perfmon2 features. ++ Currently defined: ++ - bit 0: if set, then reserved bitfield are ignored on PMC writes +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-perfmon-fmt +@@ -0,0 +1,18 @@ ++What: /sys/kernel/perfmon/formats ++Date: 2007 ++KernelVersion: 2.6.24 ++Contact: eranian@gmail.com ++ ++Description: provide description of available perfmon2 custom sampling buffer formats ++ which are implemented as independent kernel modules. Each formats gets ++ a subdir which a few entries. ++ ++ The name of the subdir is the name of the sampling format. The same name ++ must be passed to pfm_create_context() to use the format. ++ ++ Each subdir XX contains the following entries: ++ ++ /sys/kernel/perfmon/formats/XX/version (read-only): ++ ++ Version number of the format in clear text and null terminated. ++ +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-perfmon-pmu +@@ -0,0 +1,46 @@ ++What: /sys/kernel/perfmon/pmu ++Date: Nov 2007 ++KernelVersion: 2.6.24 ++Contact: eranian@gmail.com ++ ++Description: provide information about the currently loaded PMU description module. ++ The module contains the mapping of the actual performance counter registers ++ onto the logical PMU exposed by perfmon. There is at most one PMU description ++ module loaded at any time. ++ ++ The sysfs PMU tree provides a description of the mapping for each register. ++ There is one subdir per config and data registers along an entry for the ++ name of the PMU model. ++ ++ The model entry is as follows: ++ ++ /sys/kernel/perfmon/pmu_desc/model (read-only): ++ ++ Name of the PMU model is clear text and zero terminated. ++ ++ Then for each logical PMU register, XX, gets a subtree with the following entries: ++ ++ /sys/kernel/perfmon/pmu_desc/pm*XX/addr (read-only): ++ ++ The physical address or index of the actual underlying hardware register. ++ On Itanium, it corresponds to the index. But on X86 processor, this is ++ the actual MSR address. ++ ++ /sys/kernel/perfmon/pmu_desc/pm*XX/dfl_val (read-only): ++ ++ The default value of the register in hexadecimal. ++ ++ /sys/kernel/perfmon/pmu_desc/pm*XX/name (read-only): ++ ++ The name of the hardware register. ++ ++ /sys/kernel/perfmon/pmu_desc/pm*XX/rsvd_msk (read-only): ++ ++ The bitmask of reserved bits, i.e., bits which cannot be changed by ++ applications. When a bit is set, it means the corresponding bit in the ++ actual register is reserved. ++ ++ /sys/kernel/perfmon/pmu_desc/pm*XX/width (read-only): ++ ++ the width in bits of the registers. This field is only relevant for counter ++ registers. +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -1705,6 +1705,9 @@ and is between 256 and 4096 characters. + Format: { 0 | 1 } + See arch/parisc/kernel/pdc_chassis.c + ++ perfmon_debug [PERFMON] Enables Perfmon debug messages. Needed ++ to see traces of the early startup startup phase. ++ + pf. [PARIDE] + See Documentation/paride.txt. + +--- /dev/null ++++ b/Documentation/perfmon2-debugfs.txt +@@ -0,0 +1,126 @@ ++ The perfmon2 debug and statistics interface ++ ------------------------------------------ ++ Stephane Eranian ++ ++ ++The perfmon2 interfaces exports a set of statistics which are used to tune and ++debug the implementation. The data is composed of a set of very simple metrics ++mostly aggregated counts and durations. They instruments key points in the ++perfmon2 code, such as context switch and interrupt handling. ++ ++The data is accessible via the debug filesystem (debugfs). Thus you need to ++have the filesystem support enabled in your kernel. Furthermore since, 2.6.25, ++the perfmon2 statistics interface is an optional component. It needs to be ++explicitely enabled in the kernel config file (CONFIG_PERFMON_DEBUG_FS). ++ ++To access the data, the debugs filesystem must be mounted. Supposing the mount ++point is /debugfs, you would need to do: ++ $ mount -t debugs none /debugfs ++ ++The data is located under the perfmon subdirectory and is organized per CPU. ++For each CPU, the same set of metrics is available, one metric per file in ++clear ASCII text. ++ ++The metrics are as follows: ++ ++ ctxswin_count (read-only): ++ ++ Number of PMU context switch in. ++ ++ ctxswin_ns (read-only): ++ ++ Number of nanoseconds spent in the PMU context switch in ++ routine. Dividing this number by the value of ctxswin_count, ++ yields average cost of the PMU context switch in. ++ ++ ctxswout_count (read-only): ++ ++ Number of PMU context switch out. ++ ++ ctxswout_ns (read-only): ++ ++ Number of nanoseconds spent in the PMU context switch in ++ routine. Dividing this number by the value of ctxswout_count, ++ yields average cost of the PMU context switch out. ++ ++ fmt_handler_calls (read-only): ++ ++ Number of calls to the sampling format routine that handles ++ PMU interrupts, i.e., typically the routine that records a ++ sample. ++ ++ fmt_handler_ns (read-only): ++ ++ Number of nanoseconds spent in the routine that handle PMU ++ interrupt in the sampling format. Dividing this number by ++ the number of calls provided by fmt_handler_calls, yields ++ average time spent in this routine. ++ ++ ovfl_intr_all_count (read-only): ++ ++ Number of PMU interrupts received by the kernel. ++ ++ ++ ovfl_intr_nmi_count (read-only): ++ ++ Number of Non Maskeable Interrupts (NMI) received by the kernel ++ for perfmon. This is relevant only on X86 hardware. ++ ++ ovfl_intr_ns (read-only): ++ ++ Number of nanoseconds spent in the perfmon2 PMU interrupt ++ handler routine. Dividing this number of ovfl_intr_all_count ++ yields the average time to handle one PMU interrupt. ++ ++ ovfl_intr_regular_count (read-only): ++ ++ Number of PMU interrupts which are actually processed by ++ the perfmon interrupt handler. There may be spurious or replay ++ interrupts. ++ ++ ovfl_intr_replay_count (read-only): ++ ++ Number of PMU interrupts which were replayed on context switch ++ in or on event set switching. Interrupts get replayed when they ++ were in flight at the time monitoring had to be stopped. ++ ++ perfmon/ovfl_intr_spurious_count (read-only): ++ ++ Number of PMU interrupts which were dropped because there was ++ no active context (session). ++ ++ ovfl_notify_count (read-only): ++ ++ Number of user level notifications sent. Notifications are ++ appended as messages to the context queue. Notifications may ++ be sent on PMU interrupts. ++ ++ pfm_restart_count (read-only): ++ ++ Number of times pfm_restart() is called. ++ ++ reset_pmds_count (read-only): ++ ++ Number of times pfm_reset_pmds() is called. ++ ++ set_switch_count (read-only): ++ ++ Number of event set switches. ++ ++ set_switch_ns (read-only): ++ ++ Number of nanoseconds spent in the set switching routine. ++ Dividing this number by set_switch_count yields the average ++ cost of switching sets. ++ ++ handle_timeout_count (read-only): ++ ++ Number of times the pfm_handle_timeout() routine is called. ++ It is used for timeout-based set switching. ++ ++ handle_work_count (read-only): ++ ++ Number of times pfm_handle_work() is called. The routine ++ handles asynchronous perfmon2 work for per-thread contexts ++ (sessions). ++ +--- /dev/null ++++ b/Documentation/perfmon2.txt +@@ -0,0 +1,213 @@ ++ The perfmon2 hardware monitoring interface ++ ------------------------------------------ ++ Stephane Eranian ++ ++ ++I/ Introduction ++ ++ The perfmon2 interface provides access to the hardware performance counters of ++ major processors. Nowadays, all processors implement some flavors of performance ++ counters which capture micro-architectural level information such as the number ++ of elapsed cycles, number of cache misses, and so on. ++ ++ The interface is implemented as a set of new system calls and a set of config files ++ in /sys. ++ ++ It is possible to monitoring a single thread or a CPU. In either mode, applications ++ can count or collect samples. System-wide monitoring is supported by running a ++ monitoring session on each CPU. The interface support event-based sampling where the ++ sampling period is expressed as the number of occurrences of event, instead of just a ++ timeout. This approach provides a much better granularity and flexibility. ++ ++ For performance reason, it is possible to use a kernel-level sampling buffer to minimize ++ the overhead incurred by sampling. The format of the buffer, i.e., what is recorded, how ++ it is recorded, and how it is exported to user-land is controlled by a kernel module called ++ a custom sampling format. The current implementation comes with a default format but ++ it is possible to create additional formats. There is an in-kernel registration ++ interface for formats. Each format is identified by a simple string which a tool ++ can pass when a monitoring session is created. ++ ++ The interface also provides support for event set and multiplexing to work around ++ hardware limitations in the number of available counters or in how events can be ++ combined. Each set defines as many counters as the hardware can support. The kernel ++ then multiplexes the sets. The interface supports time-base switching but also ++ overflow based switching, i.e., after n overflows of designated counters. ++ ++ Applications never manipulates the actual performance counter registers. Instead they see ++ a logical Performance Monitoring Unit (PMU) composed of a set of config register (PMC) ++ and a set of data registers (PMD). Note that PMD are not necessarily counters, they ++ can be buffers. The logical PMU is then mapped onto the actual PMU using a mapping ++ table which is implemented as a kernel module. The mapping is chosen once for each ++ new processor. It is visible in /sys/kernel/perfmon/pmu_desc. The kernel module ++ is automatically loaded on first use. ++ ++ A monitoring session, or context, is uniquely identified by a file descriptor ++ obtained when the context is created. File sharing semantics apply to access ++ the context inside a process. A context is never inherited across fork. The file ++ descriptor can be used to received counter overflow notifications or when the ++ sampling buffer is full. It is possible to use poll/select on the descriptor ++ to wait for notifications from multiplex contexts. Similarly, the descriptor ++ supports asynchronous notification via SIGIO. ++ ++ Counters are always exported as being 64-bit wide regardless of what the underlying ++ hardware implements. ++ ++II/ Kernel compilation ++ ++ To enable perfmon2, you need to enable CONFIG_PERFMON ++ ++III/ OProfile interactions ++ ++ The set of features offered by perfmon2 is rich enough to support migrating ++ Oprofile on top of it. That means that PMU programming and low-level interrupt ++ handling could be done by perfmon2. The Oprofile sampling buffer management code ++ in the kernel as well as how samples are exported to users could remain through ++ the use of a custom sampling buffer format. This is how Oprofile work on Itanium. ++ ++ The current interactions with Oprofile are: ++ - on X86: Both subsystems can be compiled into the same kernel. There is enforced ++ mutual exclusion between the two subsystems. When there is an Oprofile ++ session, no perfmon2 session can exist and vice-versa. Perfmon2 session ++ encapsulates both per-thread and system-wide sessions here. ++ ++ - On IA-64: Oprofile works on top of perfmon2. Oprofile being a system-wide monitoring ++ tool, the regular per-thread vs. system-wide session restrictions apply. ++ ++ - on PPC: no integration yet. You need to enable/disble one of the two subsystems ++ - on MIPS: no integration yet. You need to enable/disble one of the two subsystems ++ ++IV/ User tools ++ ++ We have released a simple monitoring tool to demonstrate the feature of the ++ interface. The tool is called pfmon and it comes with a simple helper library ++ called libpfm. The library comes with a set of examples to show how to use the ++ kernel perfmon2 interface. Visit http://perfmon2.sf.net for details. ++ ++ There maybe other tools available for perfmon2. ++ ++V/ How to program? ++ ++ The best way to learn how to program perfmon2, is to take a look at the source ++ code for the examples in libpfm. The source code is available from: ++ http://perfmon2.sf.net ++ ++VI/ System calls overview ++ ++ The interface is implemented by the following system calls: ++ ++ * int pfm_create_context(pfarg_ctx_t *ctx, char *fmt, void *arg, size_t arg_size) ++ ++ This function create a perfmon2 context. The type of context is per-thread by ++ default unless PFM_FL_SYSTEM_WIDE is passed in ctx. The sampling format name ++ is passed in fmt. Arguments to the format are passed in arg which is of size ++ arg_size. Upon successful return, the file descriptor identifying the context ++ is returned. ++ ++ * int pfm_write_pmds(int fd, pfarg_pmd_t *pmds, int n) ++ ++ This function is used to program the PMD registers. It is possible to pass ++ vectors of PMDs. ++ ++ * int pfm_write_pmcs(int fd, pfarg_pmc_t *pmds, int n) ++ ++ This function is used to program the PMC registers. It is possible to pass ++ vectors of PMDs. ++ ++ * int pfm_read_pmds(int fd, pfarg_pmd_t *pmds, int n) ++ ++ This function is used to read the PMD registers. It is possible to pass ++ vectors of PMDs. ++ ++ * int pfm_load_context(int fd, pfarg_load_t *load) ++ ++ This function is used to attach the context to a thread or CPU. ++ Thread means kernel-visible thread (NPTL). The thread identification ++ as obtained by gettid must be passed to load->load_target. ++ ++ To operate on another thread (not self), it is mandatory that the thread ++ be stopped via ptrace(). ++ ++ To attach to a CPU, the CPU number must be specified in load->load_target ++ AND the call must be issued on that CPU. To monitor a CPU, a thread MUST ++ be pinned on that CPU. ++ ++ Until the context is attached, the actual counters are not accessed. ++ ++ * int pfm_unload_context(int fd) ++ ++ The context is detached for the thread or CPU is was attached to. ++ As a consequence monitoring is stopped. ++ ++ When monitoring another thread, the thread MUST be stopped via ptrace() ++ for this function to succeed. ++ ++ * int pfm_start(int fd, pfarg_start_t *st) ++ ++ Start monitoring. The context must be attached for this function to succeed. ++ Optionally, it is possible to specify the event set on which to start using the ++ st argument, otherwise just pass NULL. ++ ++ When monitoring another thread, the thread MUST be stopped via ptrace() ++ for this function to succeed. ++ ++ * int pfm_stop(int fd) ++ ++ Stop monitoring. The context must be attached for this function to succeed. ++ ++ When monitoring another thread, the thread MUST be stopped via ptrace() ++ for this function to succeed. ++ ++ ++ * int pfm_create_evtsets(int fd, pfarg_setdesc_t *sets, int n) ++ ++ This function is used to create or change event sets. By default set 0 exists. ++ It is possible to create/change multiple sets in one call. ++ ++ The context must be detached for this call to succeed. ++ ++ Sets are identified by a 16-bit integer. They are sorted based on this ++ set and switching occurs in a round-robin fashion. ++ ++ * int pfm_delete_evtsets(int fd, pfarg_setdesc_t *sets, int n) ++ ++ Delete event sets. The context must be detached for this call to succeed. ++ ++ ++ * int pfm_getinfo_evtsets(int fd, pfarg_setinfo_t *sets, int n) ++ ++ Retrieve information about event sets. In particular it is possible ++ to get the number of activation of a set. It is possible to retrieve ++ information about multiple sets in one call. ++ ++ ++ * int pfm_restart(int fd) ++ ++ Indicate to the kernel that the application is done processing an overflow ++ notification. A consequence of this call could be that monitoring resumes. ++ ++ * int read(fd, pfm_msg_t *msg, sizeof(pfm_msg_t)) ++ ++ the regular read() system call can be used with the context file descriptor to ++ receive overflow notification messages. Non-blocking read() is supported. ++ ++ Each message carry information about the overflow such as which counter overflowed ++ and where the program was (interrupted instruction pointer). ++ ++ * int close(int fd) ++ ++ To destroy a context, the regular close() system call is used. ++ ++ ++VII/ /sys interface overview ++ ++ Refer to Documentation/ABI/testing/sysfs-perfmon-* for a detailed description ++ of the sysfs interface of perfmon2. ++ ++VIII/ debugfs interface overview ++ ++ Refer to Documentation/perfmon2-debugfs.txt for a detailed description of the ++ debug and statistics interface of perfmon2. ++ ++IX/ Documentation ++ ++ Visit http://perfmon2.sf.net +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3244,6 +3244,14 @@ M: balbir@linux.vnet.ibm.com + L: linux-kernel@vger.kernel.org + S: Maintained + ++PERFMON SUBSYSTEM ++P: Stephane Eranian ++M: eranian@gmail.com ++L: perfmon2-devel@lists.sf.net ++W: http://perfmon2.sf.net ++T: git kernel.org:/pub/scm/linux/kernel/git/eranian/linux-2.6 ++S: Maintained ++ + PERSONALITY HANDLING + P: Christoph Hellwig + M: hch@infradead.org +--- a/Makefile ++++ b/Makefile +@@ -651,6 +651,7 @@ export mod_strip_cmd + ifeq ($(KBUILD_EXTMOD),) + core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ + core-$(CONFIG_KDB) += kdb/ ++core-$(CONFIG_PERFMON) += perfmon/ + + vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ + $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ +--- a/arch/ia64/Kconfig ++++ b/arch/ia64/Kconfig +@@ -479,14 +479,6 @@ config IA64_CPE_MIGRATE + build this functionality as a kernel loadable module. Installing + the module will turn on the functionality. + +-config PERFMON +- bool "Performance monitor support" +- help +- Selects whether support for the IA-64 performance monitor hardware +- is included in the kernel. This makes some kernel data-structures a +- little bigger and slows down execution a bit, but it is generally +- a good idea to turn this on. If you're unsure, say Y. +- + config IA64_PALINFO + tristate "/proc/pal support" + help +@@ -558,6 +550,8 @@ source "drivers/firmware/Kconfig" + + source "fs/Kconfig.binfmt" + ++source "arch/ia64/perfmon/Kconfig" ++ + endmenu + + menu "Power management and ACPI" +--- a/arch/ia64/Makefile ++++ b/arch/ia64/Makefile +@@ -57,6 +57,7 @@ core-$(CONFIG_IA64_GENERIC) += arch/ia6 + core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ + core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/ + core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ ++core-$(CONFIG_PERFMON) += arch/ia64/perfmon/ + core-$(CONFIG_IA64_SGI_UV) += arch/ia64/uv/ + core-$(CONFIG_KVM) += arch/ia64/kvm/ + +--- a/arch/ia64/configs/generic_defconfig ++++ b/arch/ia64/configs/generic_defconfig +@@ -209,7 +209,6 @@ CONFIG_IA32_SUPPORT=y + CONFIG_COMPAT=y + CONFIG_COMPAT_FOR_U64_ALIGNMENT=y + CONFIG_IA64_MCA_RECOVERY=y +-CONFIG_PERFMON=y + CONFIG_IA64_PALINFO=y + # CONFIG_IA64_MC_ERR_INJECT is not set + CONFIG_SGI_SN=y +@@ -234,6 +233,16 @@ CONFIG_BINFMT_ELF=y + CONFIG_BINFMT_MISC=m + + # ++# Hardware Performance Monitoring support ++# ++CONFIG_PERFMON=y ++CONFIG_IA64_PERFMON_COMPAT=y ++CONFIG_IA64_PERFMON_GENERIC=m ++CONFIG_IA64_PERFMON_ITANIUM=y ++CONFIG_IA64_PERFMON_MCKINLEY=y ++CONFIG_IA64_PERFMON_MONTECITO=y ++ ++# + # Power management and ACPI + # + CONFIG_PM=y +--- a/arch/ia64/include/asm/Kbuild ++++ b/arch/ia64/include/asm/Kbuild +@@ -5,10 +5,12 @@ header-y += fpu.h + header-y += fpswa.h + header-y += ia64regs.h + header-y += intel_intrin.h +-header-y += perfmon_default_smpl.h + header-y += ptrace_offsets.h + header-y += rse.h + header-y += ucontext.h ++header-y += perfmon.h ++header-y += perfmon_compat.h ++header-y += perfmon_default_smpl.h + + unifdef-y += gcc_intrin.h + unifdef-y += intrinsics.h +--- a/arch/ia64/include/asm/hw_irq.h ++++ b/arch/ia64/include/asm/hw_irq.h +@@ -67,9 +67,9 @@ extern int ia64_last_device_vector; + #define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1) + + #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ +-#define IA64_PERFMON_VECTOR 0xee /* performance monitor interrupt vector */ + #define IA64_TIMER_VECTOR 0xef /* use highest-prio group 15 interrupt for timer */ + #define IA64_MCA_WAKEUP_VECTOR 0xf0 /* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */ ++#define IA64_PERFMON_VECTOR 0xf1 /* performance monitor interrupt vector */ + #define IA64_IPI_LOCAL_TLB_FLUSH 0xfc /* SMP flush local TLB */ + #define IA64_IPI_RESCHEDULE 0xfd /* SMP reschedule */ + #define IA64_IPI_VECTOR 0xfe /* inter-processor interrupt vector */ +--- a/arch/ia64/include/asm/perfmon.h ++++ b/arch/ia64/include/asm/perfmon.h +@@ -1,279 +1,59 @@ + /* +- * Copyright (C) 2001-2003 Hewlett-Packard Co +- * Stephane Eranian +- */ +- +-#ifndef _ASM_IA64_PERFMON_H +-#define _ASM_IA64_PERFMON_H +- +-/* +- * perfmon comamnds supported on all CPU models +- */ +-#define PFM_WRITE_PMCS 0x01 +-#define PFM_WRITE_PMDS 0x02 +-#define PFM_READ_PMDS 0x03 +-#define PFM_STOP 0x04 +-#define PFM_START 0x05 +-#define PFM_ENABLE 0x06 /* obsolete */ +-#define PFM_DISABLE 0x07 /* obsolete */ +-#define PFM_CREATE_CONTEXT 0x08 +-#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */ +-#define PFM_RESTART 0x0a +-#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ +-#define PFM_GET_FEATURES 0x0c +-#define PFM_DEBUG 0x0d +-#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ +-#define PFM_GET_PMC_RESET_VAL 0x0f +-#define PFM_LOAD_CONTEXT 0x10 +-#define PFM_UNLOAD_CONTEXT 0x11 +- +-/* +- * PMU model specific commands (may not be supported on all PMU models) +- */ +-#define PFM_WRITE_IBRS 0x20 +-#define PFM_WRITE_DBRS 0x21 +- +-/* +- * context flags +- */ +-#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */ +-#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ +-#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */ +- +-/* +- * event set flags +- */ +-#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */ +- +-/* +- * PMC flags +- */ +-#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ +-#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */ +- +-/* +- * PMD/PMC/IBR/DBR return flags (ignored on input) ++ * Copyright (c) 2001-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian + * +- * Those flags are used on output and must be checked in case EAGAIN is returned +- * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. +- */ +-#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */ +-#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */ +-#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) +- +-#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) +- +-typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */ +- +-/* +- * Request structure used to define a context +- */ +-typedef struct { +- pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ +- unsigned long ctx_flags; /* noblock/block */ +- unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */ +- unsigned short ctx_reserved1; /* for future use */ +- int ctx_fd; /* return arg: unique identification for context */ +- void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ +- unsigned long ctx_reserved2[11];/* for future use */ +-} pfarg_context_t; +- +-/* +- * Request structure used to write/read a PMC or PMD +- */ +-typedef struct { +- unsigned int reg_num; /* which register */ +- unsigned short reg_set; /* event set for this register */ +- unsigned short reg_reserved1; /* for future use */ +- +- unsigned long reg_value; /* initial pmc/pmd value */ +- unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ +- +- unsigned long reg_long_reset; /* reset after buffer overflow notification */ +- unsigned long reg_short_reset; /* reset after counter overflow */ +- +- unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ +- unsigned long reg_random_seed; /* seed value when randomization is used */ +- unsigned long reg_random_mask; /* bitmask used to limit random value */ +- unsigned long reg_last_reset_val;/* return: PMD last reset value */ +- +- unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ +- unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ +- +- unsigned long reg_reserved2[3]; /* for future use */ +-} pfarg_reg_t; +- +-typedef struct { +- unsigned int dbreg_num; /* which debug register */ +- unsigned short dbreg_set; /* event set for this register */ +- unsigned short dbreg_reserved1; /* for future use */ +- unsigned long dbreg_value; /* value for debug register */ +- unsigned long dbreg_flags; /* return: dbreg error */ +- unsigned long dbreg_reserved2[1]; /* for future use */ +-} pfarg_dbreg_t; +- +-typedef struct { +- unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ +- unsigned int ft_reserved; /* reserved for future use */ +- unsigned long reserved[4]; /* for future use */ +-} pfarg_features_t; +- +-typedef struct { +- pid_t load_pid; /* process to load the context into */ +- unsigned short load_set; /* first event set to load */ +- unsigned short load_reserved1; /* for future use */ +- unsigned long load_reserved2[3]; /* for future use */ +-} pfarg_load_t; +- +-typedef struct { +- int msg_type; /* generic message header */ +- int msg_ctx_fd; /* generic message header */ +- unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ +- unsigned short msg_active_set; /* active set at the time of overflow */ +- unsigned short msg_reserved1; /* for future use */ +- unsigned int msg_reserved2; /* for future use */ +- unsigned long msg_tstamp; /* for perf tuning/debug */ +-} pfm_ovfl_msg_t; +- +-typedef struct { +- int msg_type; /* generic message header */ +- int msg_ctx_fd; /* generic message header */ +- unsigned long msg_tstamp; /* for perf tuning */ +-} pfm_end_msg_t; +- +-typedef struct { +- int msg_type; /* type of the message */ +- int msg_ctx_fd; /* unique identifier for the context */ +- unsigned long msg_tstamp; /* for perf tuning */ +-} pfm_gen_msg_t; +- +-#define PFM_MSG_OVFL 1 /* an overflow happened */ +-#define PFM_MSG_END 2 /* task to which context was attached ended */ +- +-typedef union { +- pfm_ovfl_msg_t pfm_ovfl_msg; +- pfm_end_msg_t pfm_end_msg; +- pfm_gen_msg_t pfm_gen_msg; +-} pfm_msg_t; +- +-/* +- * Define the version numbers for both perfmon as a whole and the sampling buffer format. ++ * This file contains Itanium Processor Family specific definitions ++ * for the perfmon interface. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA + */ +-#define PFM_VERSION_MAJ 2U +-#define PFM_VERSION_MIN 0U +-#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) +-#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) +-#define PFM_VERSION_MINOR(x) ((x) & 0xffff) +- ++#ifndef _ASM_IA64_PERFMON_H_ ++#define _ASM_IA64_PERFMON_H_ + + /* +- * miscellaneous architected definitions ++ * arch-specific user visible interface definitions + */ +-#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */ +-#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */ +-#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */ +- +-#ifdef __KERNEL__ +- +-extern long perfmonctl(int fd, int cmd, void *arg, int narg); +- +-typedef struct { +- void (*handler)(int irq, void *arg, struct pt_regs *regs); +-} pfm_intr_handler_desc_t; +- +-extern void pfm_save_regs (struct task_struct *); +-extern void pfm_load_regs (struct task_struct *); + +-extern void pfm_exit_thread(struct task_struct *); +-extern int pfm_use_debug_registers(struct task_struct *); +-extern int pfm_release_debug_registers(struct task_struct *); +-extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin); +-extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs); +-extern void pfm_init_percpu(void); +-extern void pfm_handle_work(void); +-extern int pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *h); +-extern int pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *h); ++#define PFM_ARCH_MAX_PMCS (256+64) ++#define PFM_ARCH_MAX_PMDS (256+64) + +- +- +-/* +- * Reset PMD register flags +- */ +-#define PFM_PMD_SHORT_RESET 0 +-#define PFM_PMD_LONG_RESET 1 +- +-typedef union { +- unsigned int val; +- struct { +- unsigned int notify_user:1; /* notify user program of overflow */ +- unsigned int reset_ovfl_pmds:1; /* reset overflowed PMDs */ +- unsigned int block_task:1; /* block monitored task on kernel exit */ +- unsigned int mask_monitoring:1; /* mask monitors via PMCx.plm */ +- unsigned int reserved:28; /* for future use */ +- } bits; +-} pfm_ovfl_ctrl_t; +- +-typedef struct { +- unsigned char ovfl_pmd; /* index of overflowed PMD */ +- unsigned char ovfl_notify; /* =1 if monitor requested overflow notification */ +- unsigned short active_set; /* event set active at the time of the overflow */ +- pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */ +- +- unsigned long pmd_last_reset; /* last reset value of of the PMD */ +- unsigned long smpl_pmds[4]; /* bitmask of other PMD of interest on overflow */ +- unsigned long smpl_pmds_values[PMU_MAX_PMDS]; /* values for the other PMDs of interest */ +- unsigned long pmd_value; /* current 64-bit value of the PMD */ +- unsigned long pmd_eventid; /* eventid associated with PMD */ +-} pfm_ovfl_arg_t; +- +- +-typedef struct { +- char *fmt_name; +- pfm_uuid_t fmt_uuid; +- size_t fmt_arg_size; +- unsigned long fmt_flags; +- +- int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg); +- int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size); +- int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg); +- int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp); +- int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); +- int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); +- int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs); +- +- struct list_head fmt_list; +-} pfm_buffer_fmt_t; +- +-extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt); +-extern int pfm_unregister_buffer_fmt(pfm_uuid_t uuid); ++#define PFM_ARCH_PMD_STK_ARG 8 ++#define PFM_ARCH_PMC_STK_ARG 8 + + /* +- * perfmon interface exported to modules ++ * Itanium specific context flags ++ * ++ * bits[00-15]: generic flags (see asm/perfmon.h) ++ * bits[16-31]: arch-specific flags + */ +-extern int pfm_mod_read_pmds(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs); +-extern int pfm_mod_write_pmcs(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs); +-extern int pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs); +-extern int pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs); ++#define PFM_ITA_FL_INSECURE 0x10000 /* clear psr.sp on non system, non self */ + + /* +- * describe the content of the local_cpu_date->pfm_syst_info field ++ * Itanium specific public event set flags (set_flags) ++ * ++ * event set flags layout: ++ * bits[00-15] : generic flags ++ * bits[16-31] : arch-specific flags + */ +-#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exists */ +-#define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */ +-#define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */ ++#define PFM_ITA_SETFL_EXCL_INTR 0x10000 /* exclude interrupt execution */ ++#define PFM_ITA_SETFL_INTR_ONLY 0x20000 /* include only interrupt execution */ ++#define PFM_ITA_SETFL_IDLE_EXCL 0x40000 /* stop monitoring in idle loop */ + + /* +- * sysctl control structure. visible to sampling formats ++ * compatibility for version v2.0 of the interface + */ +-typedef struct { +- int debug; /* turn on/off debugging via syslog */ +- int debug_ovfl; /* turn on/off debug printk in overflow handler */ +- int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ +- int expert_mode; /* turn on/off value checking */ +-} pfm_sysctl_t; +-extern pfm_sysctl_t pfm_sysctl; +- +- +-#endif /* __KERNEL__ */ ++#include + +-#endif /* _ASM_IA64_PERFMON_H */ ++#endif /* _ASM_IA64_PERFMON_H_ */ +--- /dev/null ++++ b/arch/ia64/include/asm/perfmon_compat.h +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This header file contains perfmon interface definition ++ * that are now obsolete and should be dropped in favor ++ * of their equivalent functions as explained below. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++ ++#ifndef _ASM_IA64_PERFMON_COMPAT_H_ ++#define _ASM_IA64_PERFMON_COMPAT_H_ ++ ++/* ++ * custom sampling buffer identifier type ++ */ ++typedef __u8 pfm_uuid_t[16]; ++ ++/* ++ * obsolete perfmon commands. Supported only on IA-64 for ++ * backward compatiblity reasons with perfmon v2.0. ++ */ ++#define PFM_WRITE_PMCS 0x01 /* use pfm_write_pmcs */ ++#define PFM_WRITE_PMDS 0x02 /* use pfm_write_pmds */ ++#define PFM_READ_PMDS 0x03 /* use pfm_read_pmds */ ++#define PFM_STOP 0x04 /* use pfm_stop */ ++#define PFM_START 0x05 /* use pfm_start */ ++#define PFM_ENABLE 0x06 /* obsolete */ ++#define PFM_DISABLE 0x07 /* obsolete */ ++#define PFM_CREATE_CONTEXT 0x08 /* use pfm_create_context */ ++#define PFM_DESTROY_CONTEXT 0x09 /* use close() */ ++#define PFM_RESTART 0x0a /* use pfm_restart */ ++#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ ++#define PFM_GET_FEATURES 0x0c /* use /proc/sys/perfmon */ ++#define PFM_DEBUG 0x0d /* /proc/sys/kernel/perfmon/debug */ ++#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ ++#define PFM_GET_PMC_RESET_VAL 0x0f /* use /proc/perfmon_map */ ++#define PFM_LOAD_CONTEXT 0x10 /* use pfm_load_context */ ++#define PFM_UNLOAD_CONTEXT 0x11 /* use pfm_unload_context */ ++ ++/* ++ * PMU model specific commands (may not be supported on all PMU models) ++ */ ++#define PFM_WRITE_IBRS 0x20 /* obsolete: use PFM_WRITE_PMCS[256-263]*/ ++#define PFM_WRITE_DBRS 0x21 /* obsolete: use PFM_WRITE_PMCS[264-271]*/ ++ ++/* ++ * argument to PFM_CREATE_CONTEXT ++ */ ++struct pfarg_context { ++ pfm_uuid_t ctx_smpl_buf_id; /* buffer format to use */ ++ unsigned long ctx_flags; /* noblock/block */ ++ unsigned int ctx_reserved1; /* for future use */ ++ int ctx_fd; /* return: fildesc */ ++ void *ctx_smpl_vaddr; /* return: vaddr of buffer */ ++ unsigned long ctx_reserved3[11];/* for future use */ ++}; ++ ++/* ++ * argument structure for PFM_WRITE_PMCS/PFM_WRITE_PMDS/PFM_WRITE_PMDS ++ */ ++struct pfarg_reg { ++ unsigned int reg_num; /* which register */ ++ unsigned short reg_set; /* event set for this register */ ++ unsigned short reg_reserved1; /* for future use */ ++ ++ unsigned long reg_value; /* initial pmc/pmd value */ ++ unsigned long reg_flags; /* input: flags, ret: error */ ++ ++ unsigned long reg_long_reset; /* reset value after notification */ ++ unsigned long reg_short_reset; /* reset after counter overflow */ ++ ++ unsigned long reg_reset_pmds[4]; /* registers to reset on overflow */ ++ unsigned long reg_random_seed; /* seed for randomization */ ++ unsigned long reg_random_mask; /* random range limit */ ++ unsigned long reg_last_reset_val;/* return: PMD last reset value */ ++ ++ unsigned long reg_smpl_pmds[4]; /* pmds to be saved on overflow */ ++ unsigned long reg_smpl_eventid; /* opaque sampling event id */ ++ unsigned long reg_ovfl_switch_cnt;/* #overflows to switch */ ++ ++ unsigned long reg_reserved2[2]; /* for future use */ ++}; ++ ++/* ++ * argument to PFM_WRITE_IBRS/PFM_WRITE_DBRS ++ */ ++struct pfarg_dbreg { ++ unsigned int dbreg_num; /* which debug register */ ++ unsigned short dbreg_set; /* event set */ ++ unsigned short dbreg_reserved1; /* for future use */ ++ unsigned long dbreg_value; /* value for debug register */ ++ unsigned long dbreg_flags; /* return: dbreg error */ ++ unsigned long dbreg_reserved2[1]; /* for future use */ ++}; ++ ++/* ++ * argument to PFM_GET_FEATURES ++ */ ++struct pfarg_features { ++ unsigned int ft_version; /* major [16-31], minor [0-15] */ ++ unsigned int ft_reserved; /* reserved for future use */ ++ unsigned long reserved[4]; /* for future use */ ++}; ++ ++typedef struct { ++ int msg_type; /* generic message header */ ++ int msg_ctx_fd; /* generic message header */ ++ unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ ++ unsigned short msg_active_set; /* active set on overflow */ ++ unsigned short msg_reserved1; /* for future use */ ++ unsigned int msg_reserved2; /* for future use */ ++ unsigned long msg_tstamp; /* for perf tuning/debug */ ++} pfm_ovfl_msg_t; ++ ++typedef struct { ++ int msg_type; /* generic message header */ ++ int msg_ctx_fd; /* generic message header */ ++ unsigned long msg_tstamp; /* for perf tuning */ ++} pfm_end_msg_t; ++ ++typedef struct { ++ int msg_type; /* type of the message */ ++ int msg_ctx_fd; /* context file descriptor */ ++ unsigned long msg_tstamp; /* for perf tuning */ ++} pfm_gen_msg_t; ++ ++typedef union { ++ int type; ++ pfm_ovfl_msg_t pfm_ovfl_msg; ++ pfm_end_msg_t pfm_end_msg; ++ pfm_gen_msg_t pfm_gen_msg; ++} pfm_msg_t; ++ ++/* ++ * PMD/PMC return flags in case of error (ignored on input) ++ * ++ * reg_flags layout: ++ * bit 00-15 : generic flags ++ * bits[16-23] : arch-specific flags (see asm/perfmon.h) ++ * bit 24-31 : error codes ++ * ++ * Those flags are used on output and must be checked in case EINVAL is ++ * returned by a command accepting a vector of values and each has a flag ++ * field, such as pfarg_reg or pfarg_reg ++ */ ++#define PFM_REG_RETFL_NOTAVAIL (1<<31) /* not implemented or unaccessible */ ++#define PFM_REG_RETFL_EINVAL (1<<30) /* entry is invalid */ ++#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|\ ++ PFM_REG_RETFL_EINVAL) ++ ++#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) ++ ++#endif /* _ASM_IA64_PERFMON_COMPAT_H_ */ +--- a/arch/ia64/include/asm/perfmon_default_smpl.h ++++ b/arch/ia64/include/asm/perfmon_default_smpl.h +@@ -1,83 +1,106 @@ + /* +- * Copyright (C) 2002-2003 Hewlett-Packard Co +- * Stephane Eranian ++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian + * +- * This file implements the default sampling buffer format +- * for Linux/ia64 perfmon subsystem. ++ * This file implements the old default sampling buffer format ++ * for the perfmon2 subsystem. For IA-64 only. ++ * ++ * It requires the use of the perfmon_compat.h header. It is recommended ++ * that applications be ported to the new format instead. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA + */ +-#ifndef __PERFMON_DEFAULT_SMPL_H__ +-#define __PERFMON_DEFAULT_SMPL_H__ 1 ++#ifndef __ASM_IA64_PERFMON_DEFAULT_SMPL_H__ ++#define __ASM_IA64_PERFMON_DEFAULT_SMPL_H__ 1 ++ ++#ifndef __ia64__ ++#error "this file must be used for compatibility reasons only on IA-64" ++#endif + + #define PFM_DEFAULT_SMPL_UUID { \ +- 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82, 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97} ++ 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82,\ ++ 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97} + + /* + * format specific parameters (passed at context creation) + */ +-typedef struct { ++struct pfm_default_smpl_arg { + unsigned long buf_size; /* size of the buffer in bytes */ + unsigned int flags; /* buffer specific flags */ + unsigned int res1; /* for future use */ + unsigned long reserved[2]; /* for future use */ +-} pfm_default_smpl_arg_t; ++}; + + /* + * combined context+format specific structure. Can be passed +- * to PFM_CONTEXT_CREATE ++ * to PFM_CONTEXT_CREATE (not PFM_CONTEXT_CREATE2) + */ +-typedef struct { +- pfarg_context_t ctx_arg; +- pfm_default_smpl_arg_t buf_arg; +-} pfm_default_smpl_ctx_arg_t; ++struct pfm_default_smpl_ctx_arg { ++ struct pfarg_context ctx_arg; ++ struct pfm_default_smpl_arg buf_arg; ++}; + + /* + * This header is at the beginning of the sampling buffer returned to the user. + * It is directly followed by the first record. + */ +-typedef struct { +- unsigned long hdr_count; /* how many valid entries */ +- unsigned long hdr_cur_offs; /* current offset from top of buffer */ +- unsigned long hdr_reserved2; /* reserved for future use */ +- +- unsigned long hdr_overflows; /* how many times the buffer overflowed */ +- unsigned long hdr_buf_size; /* how many bytes in the buffer */ +- +- unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */ +- unsigned int hdr_reserved1; /* for future use */ +- unsigned long hdr_reserved[10]; /* for future use */ +-} pfm_default_smpl_hdr_t; ++struct pfm_default_smpl_hdr { ++ u64 hdr_count; /* how many valid entries */ ++ u64 hdr_cur_offs; /* current offset from top of buffer */ ++ u64 dr_reserved2; /* reserved for future use */ ++ ++ u64 hdr_overflows; /* how many times the buffer overflowed */ ++ u64 hdr_buf_size; /* how many bytes in the buffer */ ++ ++ u32 hdr_version; /* smpl format version*/ ++ u32 hdr_reserved1; /* for future use */ ++ u64 hdr_reserved[10]; /* for future use */ ++}; + + /* + * Entry header in the sampling buffer. The header is directly followed +- * with the values of the PMD registers of interest saved in increasing +- * index order: PMD4, PMD5, and so on. How many PMDs are present depends ++ * with the values of the PMD registers of interest saved in increasing ++ * index order: PMD4, PMD5, and so on. How many PMDs are present depends + * on how the session was programmed. + * + * In the case where multiple counters overflow at the same time, multiple + * entries are written consecutively. + * +- * last_reset_value member indicates the initial value of the overflowed PMD. ++ * last_reset_value member indicates the initial value of the overflowed PMD. + */ +-typedef struct { +- int pid; /* thread id (for NPTL, this is gettid()) */ +- unsigned char reserved1[3]; /* reserved for future use */ +- unsigned char ovfl_pmd; /* index of overflowed PMD */ +- +- unsigned long last_reset_val; /* initial value of overflowed PMD */ +- unsigned long ip; /* where did the overflow interrupt happened */ +- unsigned long tstamp; /* ar.itc when entering perfmon intr. handler */ +- +- unsigned short cpu; /* cpu on which the overfow occured */ +- unsigned short set; /* event set active when overflow ocurred */ +- int tgid; /* thread group id (for NPTL, this is getpid()) */ +-} pfm_default_smpl_entry_t; +- +-#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */ +-#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(pfm_default_smpl_entry_t)+(sizeof(unsigned long)*PFM_DEFAULT_MAX_PMDS)) +-#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(pfm_default_smpl_hdr_t)+PFM_DEFAULT_MAX_ENTRY_SIZE) ++struct pfm_default_smpl_entry { ++ pid_t pid; /* thread id (for NPTL, this is gettid()) */ ++ uint8_t reserved1[3]; /* for future use */ ++ uint8_t ovfl_pmd; /* overflow pmd for this sample */ ++ u64 last_reset_val; /* initial value of overflowed PMD */ ++ unsigned long ip; /* where did the overflow interrupt happened */ ++ u64 tstamp; /* overflow timetamp */ ++ u16 cpu; /* cpu on which the overfow occured */ ++ u16 set; /* event set active when overflow ocurred */ ++ pid_t tgid; /* thread group id (for NPTL, this is getpid()) */ ++}; ++ ++#define PFM_DEFAULT_MAX_PMDS 64 /* #pmds supported */ ++#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(struct pfm_default_smpl_entry)+\ ++ (sizeof(u64)*PFM_DEFAULT_MAX_PMDS)) ++#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(struct pfm_default_smpl_hdr)+\ ++ PFM_DEFAULT_MAX_ENTRY_SIZE) + + #define PFM_DEFAULT_SMPL_VERSION_MAJ 2U +-#define PFM_DEFAULT_SMPL_VERSION_MIN 0U +-#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff)) ++#define PFM_DEFAULT_SMPL_VERSION_MIN 1U ++#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|\ ++ (PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff)) + +-#endif /* __PERFMON_DEFAULT_SMPL_H__ */ ++#endif /* __ASM_IA64_PERFMON_DEFAULT_SMPL_H__ */ +--- /dev/null ++++ b/arch/ia64/include/asm/perfmon_kern.h +@@ -0,0 +1,356 @@ ++/* ++ * Copyright (c) 2001-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file contains Itanium Processor Family specific definitions ++ * for the perfmon interface. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_IA64_PERFMON_KERN_H_ ++#define _ASM_IA64_PERFMON_KERN_H_ ++ ++#ifdef __KERNEL__ ++ ++#ifdef CONFIG_PERFMON ++#include ++#include ++ ++/* ++ * describe the content of the pfm_syst_info field ++ * layout: ++ * bits[00-15] : generic flags ++ * bits[16-31] : arch-specific flags ++ */ ++#define PFM_ITA_CPUINFO_IDLE_EXCL 0x10000 /* stop monitoring in idle loop */ ++ ++/* ++ * For some CPUs, the upper bits of a counter must be set in order for the ++ * overflow interrupt to happen. On overflow, the counter has wrapped around, ++ * and the upper bits are cleared. This function may be used to set them back. ++ */ ++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, ++ unsigned int cnum) ++{} ++ ++/* ++ * called from __pfm_interrupt_handler(). ctx is not NULL. ++ * ctx is locked. PMU interrupt is masked. ++ * ++ * must stop all monitoring to ensure handler has consistent view. ++ * must collect overflowed PMDs bitmask into povfls_pmds and ++ * npend_ovfls. If no interrupt detected then npend_ovfls ++ * must be set to zero. ++ */ ++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ u64 tmp; ++ ++ /* ++ * do not overwrite existing value, must ++ * process those first (coming from context switch replay) ++ */ ++ if (set->npend_ovfls) ++ return; ++ ++ ia64_srlz_d(); ++ ++ tmp = ia64_get_pmc(0) & ~0xf; ++ ++ set->povfl_pmds[0] = tmp; ++ ++ set->npend_ovfls = ia64_popcnt(tmp); ++} ++ ++static inline int pfm_arch_init_pmu_config(void) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_resend_irq(struct pfm_context *ctx) ++{ ++ ia64_resend_irq(IA64_PERFMON_VECTOR); ++} ++ ++static inline void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++static inline void pfm_arch_serialize(void) ++{ ++ ia64_srlz_d(); ++} ++ ++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx) ++{ ++ PFM_DBG_ovfl("state=%d", ctx->state); ++ ia64_set_pmc(0, 0); ++ /* no serialization */ ++} ++ ++static inline void pfm_arch_write_pmc(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ if (cnum < 256) { ++ ia64_set_pmc(pfm_pmu_conf->pmc_desc[cnum].hw_addr, value); ++ } else if (cnum < 264) { ++ ia64_set_ibr(cnum-256, value); ++ ia64_dv_serialize_instruction(); ++ } else { ++ ia64_set_dbr(cnum-264, value); ++ ia64_dv_serialize_instruction(); ++ } ++} ++ ++/* ++ * On IA-64, for per-thread context which have the ITA_FL_INSECURE ++ * flag, it is possible to start/stop monitoring directly from user evel ++ * without calling pfm_start()/pfm_stop. This allows very lightweight ++ * control yet the kernel sometimes needs to know if monitoring is actually ++ * on or off. ++ * ++ * Tracking of this information is normally done by pfm_start/pfm_stop ++ * in flags.started. Here we need to compensate by checking actual ++ * psr bit. ++ */ ++static inline int pfm_arch_is_active(struct pfm_context *ctx) ++{ ++ return ctx->flags.started ++ || ia64_getreg(_IA64_REG_PSR) & (IA64_PSR_UP|IA64_PSR_PP); ++} ++ ++static inline void pfm_arch_write_pmd(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ /* ++ * for a counting PMD, overflow bit must be cleared ++ */ ++ if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64) ++ value &= pfm_pmu_conf->ovfl_mask; ++ ++ /* ++ * for counters, write to upper bits are ignored, no need to mask ++ */ ++ ia64_set_pmd(pfm_pmu_conf->pmd_desc[cnum].hw_addr, value); ++} ++ ++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ return ia64_get_pmd(pfm_pmu_conf->pmd_desc[cnum].hw_addr); ++} ++ ++static inline u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum) ++{ ++ return ia64_get_pmc(pfm_pmu_conf->pmc_desc[cnum].hw_addr); ++} ++ ++static inline void pfm_arch_ctxswout_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{ ++ struct pt_regs *regs; ++ ++ regs = task_pt_regs(task); ++ ia64_psr(regs)->pp = 0; ++} ++ ++static inline void pfm_arch_ctxswin_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{ ++ struct pt_regs *regs; ++ ++ if (!(ctx->active_set->flags & PFM_ITA_SETFL_INTR_ONLY)) { ++ regs = task_pt_regs(task); ++ ia64_psr(regs)->pp = 1; ++ } ++} ++ ++/* ++ * On IA-64, the PMDs are NOT saved by pfm_arch_freeze_pmu() ++ * when entering the PMU interrupt handler, thus, we need ++ * to save them in pfm_switch_sets_from_intr() ++ */ ++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_save_pmds(ctx, set); ++} ++ ++int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags); ++ ++static inline void pfm_arch_context_free(struct pfm_context *ctx) ++{} ++ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_ctxswin_thread(struct task_struct *task, ++ struct pfm_context *ctx); ++ ++void pfm_arch_unload_context(struct pfm_context *ctx); ++int pfm_arch_load_context(struct pfm_context *ctx); ++int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags); ++ ++void pfm_arch_mask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++void pfm_arch_unmask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); ++ ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx); ++ ++int pfm_arch_init(void); ++void pfm_arch_init_percpu(void); ++char *pfm_arch_get_pmu_module_name(void); ++ ++int __pfm_use_dbregs(struct task_struct *task); ++int __pfm_release_dbregs(struct task_struct *task); ++int pfm_ia64_mark_dbregs_used(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++void pfm_arch_show_session(struct seq_file *m); ++ ++static inline int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_pmu_release(void) ++{} ++ ++/* not necessary on IA-64 */ ++static inline void pfm_cacheflush(void *addr, unsigned int len) ++{} ++ ++/* ++ * miscellaneous architected definitions ++ */ ++#define PFM_ITA_FCNTR 4 /* first counting monitor (PMC/PMD) */ ++ ++/* ++ * private event set flags (set_priv_flags) ++ */ ++#define PFM_ITA_SETFL_USE_DBR 0x1000000 /* set uses debug registers */ ++ ++ ++/* ++ * Itanium-specific data structures ++ */ ++struct pfm_ia64_context_flags { ++ unsigned int use_dbr:1; /* use range restrictions (debug registers) */ ++ unsigned int insecure:1; /* insecure monitoring for non-self session */ ++ unsigned int reserved:30;/* for future use */ ++}; ++ ++struct pfm_arch_context { ++ struct pfm_ia64_context_flags flags; /* arch specific ctx flags */ ++ u64 ctx_saved_psr_up;/* storage for psr_up */ ++#ifdef CONFIG_IA64_PERFMON_COMPAT ++ void *ctx_smpl_vaddr; /* vaddr of user mapping */ ++#endif ++}; ++ ++#ifdef CONFIG_IA64_PERFMON_COMPAT ++ssize_t pfm_arch_compat_read(struct pfm_context *ctx, ++ char __user *buf, ++ int non_block, ++ size_t size); ++int pfm_ia64_compat_init(void); ++int pfm_smpl_buf_alloc_compat(struct pfm_context *ctx, ++ size_t rsize, struct file *filp); ++#else ++static inline ssize_t pfm_arch_compat_read(struct pfm_context *ctx, ++ char __user *buf, ++ int non_block, ++ size_t size) ++{ ++ return -EINVAL; ++} ++ ++static inline int pfm_smpl_buf_alloc_compat(struct pfm_context *ctx, ++ size_t rsize, struct file *filp) ++{ ++ return -EINVAL; ++} ++#endif ++ ++static inline void pfm_arch_arm_handle_work(struct task_struct *task) ++{ ++ /* ++ * On IA-64, we ran out of bits in the bottom 7 bits of the ++ * threadinfo bitmask.Thus we used a 2-stage approach by piggybacking ++ * on NOTIFY_RESUME and then in do_notify_resume() we demultiplex and ++ * call pfm_handle_work() if needed ++ */ ++ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); ++} ++ ++static inline void pfm_arch_disarm_handle_work(struct task_struct *task) ++{ ++ /* ++ * we cannot just clear TIF_NOTIFY_RESUME because other TIF flags are ++ * piggybackedonto it: TIF_PERFMON_WORK, TIF_RESTORE_RSE ++ * ++ * The tsk_clear_notify_resume() checks if any of those are set before ++ * clearing the * bit ++ */ ++ tsk_clear_notify_resume(task); ++} ++ ++static inline int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg) ++{ ++ return 0; ++} ++ ++extern struct pfm_ia64_pmu_info *pfm_ia64_pmu_info; ++ ++#define PFM_ARCH_CTX_SIZE (sizeof(struct pfm_arch_context)) ++ ++/* ++ * IA-64 does not need extra alignment requirements for the sampling buffer ++ */ ++#define PFM_ARCH_SMPL_ALIGN_SIZE 0 ++ ++ ++static inline void pfm_release_dbregs(struct task_struct *task) ++{ ++ if (task->thread.flags & IA64_THREAD_DBG_VALID) ++ __pfm_release_dbregs(task); ++} ++ ++#define pfm_use_dbregs(_t) __pfm_use_dbregs(_t) ++ ++static inline int pfm_arch_get_base_syscall(void) ++{ ++ return __NR_pfm_create_context; ++} ++ ++struct pfm_arch_pmu_info { ++ unsigned long mask_pmcs[PFM_PMC_BV]; /* modify on when masking */ ++}; ++ ++DECLARE_PER_CPU(u32, pfm_syst_info); ++#else /* !CONFIG_PERFMON */ ++/* ++ * perfmon ia64-specific hooks ++ */ ++#define pfm_release_dbregs(_t) do { } while (0) ++#define pfm_use_dbregs(_t) (0) ++ ++#endif /* CONFIG_PERFMON */ ++ ++#endif /* __KERNEL__ */ ++#endif /* _ASM_IA64_PERFMON_KERN_H_ */ +--- a/arch/ia64/include/asm/processor.h ++++ b/arch/ia64/include/asm/processor.h +@@ -42,7 +42,6 @@ + + #define IA64_THREAD_FPH_VALID (__IA64_UL(1) << 0) /* floating-point high state valid? */ + #define IA64_THREAD_DBG_VALID (__IA64_UL(1) << 1) /* debug registers valid? */ +-#define IA64_THREAD_PM_VALID (__IA64_UL(1) << 2) /* performance registers valid? */ + #define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 3) /* don't log unaligned accesses */ + #define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 4) /* generate SIGBUS on unaligned acc. */ + #define IA64_THREAD_MIGRATION (__IA64_UL(1) << 5) /* require migration +@@ -321,14 +320,6 @@ struct thread_struct { + #else + # define INIT_THREAD_IA32 + #endif /* CONFIG_IA32_SUPPORT */ +-#ifdef CONFIG_PERFMON +- void *pfm_context; /* pointer to detailed PMU context */ +- unsigned long pfm_needs_checking; /* when >0, pending perfmon work on kernel exit */ +-# define INIT_THREAD_PM .pfm_context = NULL, \ +- .pfm_needs_checking = 0UL, +-#else +-# define INIT_THREAD_PM +-#endif + __u64 dbr[IA64_NUM_DBG_REGS]; + __u64 ibr[IA64_NUM_DBG_REGS]; + struct ia64_fpreg fph[96]; /* saved/loaded on demand */ +@@ -343,7 +334,6 @@ struct thread_struct { + .task_size = DEFAULT_TASK_SIZE, \ + .last_fph_cpu = -1, \ + INIT_THREAD_IA32 \ +- INIT_THREAD_PM \ + .dbr = {0, }, \ + .ibr = {0, }, \ + .fph = {{{{0}}}, } \ +--- a/arch/ia64/include/asm/system.h ++++ b/arch/ia64/include/asm/system.h +@@ -217,6 +217,7 @@ struct task_struct; + extern void ia64_save_extra (struct task_struct *task); + extern void ia64_load_extra (struct task_struct *task); + ++ + #ifdef CONFIG_VIRT_CPU_ACCOUNTING + extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct *next); + # define IA64_ACCOUNT_ON_SWITCH(p,n) ia64_account_on_switch(p,n) +@@ -224,16 +225,9 @@ extern void ia64_account_on_switch (stru + # define IA64_ACCOUNT_ON_SWITCH(p,n) + #endif + +-#ifdef CONFIG_PERFMON +- DECLARE_PER_CPU(unsigned long, pfm_syst_info); +-# define PERFMON_IS_SYSWIDE() (__get_cpu_var(pfm_syst_info) & 0x1) +-#else +-# define PERFMON_IS_SYSWIDE() (0) +-#endif +- +-#define IA64_HAS_EXTRA_STATE(t) \ +- ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID) \ +- || IS_IA32_PROCESS(task_pt_regs(t)) || PERFMON_IS_SYSWIDE()) ++#define IA64_HAS_EXTRA_STATE(t) \ ++ (((t)->thread.flags & IA64_THREAD_DBG_VALID) \ ++ || IS_IA32_PROCESS(task_pt_regs(t))) + + #define __switch_to(prev,next,last) do { \ + IA64_ACCOUNT_ON_SWITCH(prev, next); \ +@@ -241,6 +235,10 @@ extern void ia64_account_on_switch (stru + ia64_save_extra(prev); \ + if (IA64_HAS_EXTRA_STATE(next)) \ + ia64_load_extra(next); \ ++ if (test_tsk_thread_flag(prev, TIF_PERFMON_CTXSW)) \ ++ pfm_ctxsw_out(prev, next); \ ++ if (test_tsk_thread_flag(next, TIF_PERFMON_CTXSW)) \ ++ pfm_ctxsw_in(prev, next); \ + ia64_psr(task_pt_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \ + (last) = ia64_switch_to((next)); \ + } while (0) +--- a/arch/ia64/include/asm/thread_info.h ++++ b/arch/ia64/include/asm/thread_info.h +@@ -110,6 +110,8 @@ extern void tsk_clear_notify_resume(stru + #define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */ + #define TIF_FREEZE 20 /* is freezing for suspend */ + #define TIF_RESTORE_RSE 21 /* user RBS is newer than kernel RBS */ ++#define TIF_PERFMON_CTXSW 22 /* perfmon needs ctxsw calls */ ++#define TIF_PERFMON_WORK 23 /* work for pfm_handle_work() */ + + #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) + #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) +@@ -123,6 +125,8 @@ extern void tsk_clear_notify_resume(stru + #define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED) + #define _TIF_FREEZE (1 << TIF_FREEZE) + #define _TIF_RESTORE_RSE (1 << TIF_RESTORE_RSE) ++#define _TIF_PERFMON_CTXSW (1 << TIF_PERFMON_CTXSW) ++#define _TIF_PERFMON_WORK (1 << TIF_PERFMON_WORK) + + /* "work to do on user-return" bits */ + #define TIF_ALLWORK_MASK (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SYSCALL_AUDIT|\ +--- a/arch/ia64/include/asm/unistd.h ++++ b/arch/ia64/include/asm/unistd.h +@@ -308,11 +308,23 @@ + #define __NR_dup3 1316 + #define __NR_pipe2 1317 + #define __NR_inotify_init1 1318 ++#define __NR_pfm_create_context 1319 ++#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) ++#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) ++#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) ++#define __NR_pfm_load_context (__NR_pfm_create_context+4) ++#define __NR_pfm_start (__NR_pfm_create_context+5) ++#define __NR_pfm_stop (__NR_pfm_create_context+6) ++#define __NR_pfm_restart (__NR_pfm_create_context+7) ++#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) ++#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) ++#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) ++#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + #ifdef __KERNEL__ + + +-#define NR_syscalls 295 /* length of syscall table */ ++#define NR_syscalls 307 /* length of syscall table */ + + /* + * The following defines stop scripts/checksyscalls.sh from complaining about +--- a/arch/ia64/kernel/Makefile ++++ b/arch/ia64/kernel/Makefile +@@ -5,7 +5,7 @@ + extra-y := head.o init_task.o vmlinux.lds + + obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ +- irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ ++ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o ptrace.o sal.o \ + salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ + unwind.o mca.o mca_asm.o topology.o + +@@ -23,7 +23,6 @@ obj-$(CONFIG_IOSAPIC) += iosapic.o + obj-$(CONFIG_MODULES) += module.o + obj-$(CONFIG_SMP) += smp.o smpboot.o + obj-$(CONFIG_NUMA) += numa.o +-obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o + obj-$(CONFIG_IA64_CYCLONE) += cyclone.o + obj-$(CONFIG_CPU_FREQ) += cpufreq/ + obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o +--- a/arch/ia64/kernel/entry.S ++++ b/arch/ia64/kernel/entry.S +@@ -1697,6 +1697,18 @@ sys_call_table: + data8 sys_dup3 + data8 sys_pipe2 + data8 sys_inotify_init1 ++ data8 sys_pfm_create_context ++ data8 sys_pfm_write_pmcs // 1320 ++ data8 sys_pfm_write_pmds ++ data8 sys_pfm_read_pmds ++ data8 sys_pfm_load_context ++ data8 sys_pfm_start ++ data8 sys_pfm_stop // 1325 ++ data8 sys_pfm_restart ++ data8 sys_pfm_create_evtsets ++ data8 sys_pfm_getinfo_evtsets ++ data8 sys_pfm_delete_evtsets ++ data8 sys_pfm_unload_context // 1330 + + .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls + #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ +--- a/arch/ia64/kernel/irq_ia64.c ++++ b/arch/ia64/kernel/irq_ia64.c +@@ -40,10 +40,6 @@ + #include + #include + +-#ifdef CONFIG_PERFMON +-# include +-#endif +- + #define IRQ_DEBUG 0 + + #define IRQ_VECTOR_UNASSIGNED (0) +@@ -660,9 +656,6 @@ init_IRQ (void) + } + #endif + #endif +-#ifdef CONFIG_PERFMON +- pfm_init_percpu(); +-#endif + platform_irq_init(); + } + +--- a/arch/ia64/kernel/perfmon_default_smpl.c ++++ /dev/null +@@ -1,296 +0,0 @@ +-/* +- * Copyright (C) 2002-2003 Hewlett-Packard Co +- * Stephane Eranian +- * +- * This file implements the default sampling buffer format +- * for the Linux/ia64 perfmon-2 subsystem. +- */ +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-MODULE_AUTHOR("Stephane Eranian "); +-MODULE_DESCRIPTION("perfmon default sampling format"); +-MODULE_LICENSE("GPL"); +- +-#define DEFAULT_DEBUG 1 +- +-#ifdef DEFAULT_DEBUG +-#define DPRINT(a) \ +- do { \ +- if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \ +- } while (0) +- +-#define DPRINT_ovfl(a) \ +- do { \ +- if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \ +- } while (0) +- +-#else +-#define DPRINT(a) +-#define DPRINT_ovfl(a) +-#endif +- +-static int +-default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) +-{ +- pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data; +- int ret = 0; +- +- if (data == NULL) { +- DPRINT(("[%d] no argument passed\n", task_pid_nr(task))); +- return -EINVAL; +- } +- +- DPRINT(("[%d] validate flags=0x%x CPU%d\n", task_pid_nr(task), flags, cpu)); +- +- /* +- * must hold at least the buffer header + one minimally sized entry +- */ +- if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL; +- +- DPRINT(("buf_size=%lu\n", arg->buf_size)); +- +- return ret; +-} +- +-static int +-default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size) +-{ +- pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; +- +- /* +- * size has been validated in default_validate +- */ +- *size = arg->buf_size; +- +- return 0; +-} +- +-static int +-default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data) +-{ +- pfm_default_smpl_hdr_t *hdr; +- pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; +- +- hdr = (pfm_default_smpl_hdr_t *)buf; +- +- hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION; +- hdr->hdr_buf_size = arg->buf_size; +- hdr->hdr_cur_offs = sizeof(*hdr); +- hdr->hdr_overflows = 0UL; +- hdr->hdr_count = 0UL; +- +- DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u cur_offs=%lu\n", +- task_pid_nr(task), +- buf, +- hdr->hdr_buf_size, +- sizeof(*hdr), +- hdr->hdr_version, +- hdr->hdr_cur_offs)); +- +- return 0; +-} +- +-static int +-default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp) +-{ +- pfm_default_smpl_hdr_t *hdr; +- pfm_default_smpl_entry_t *ent; +- void *cur, *last; +- unsigned long *e, entry_size; +- unsigned int npmds, i; +- unsigned char ovfl_pmd; +- unsigned char ovfl_notify; +- +- if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) { +- DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg)); +- return -EINVAL; +- } +- +- hdr = (pfm_default_smpl_hdr_t *)buf; +- cur = buf+hdr->hdr_cur_offs; +- last = buf+hdr->hdr_buf_size; +- ovfl_pmd = arg->ovfl_pmd; +- ovfl_notify = arg->ovfl_notify; +- +- /* +- * precheck for sanity +- */ +- if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; +- +- npmds = hweight64(arg->smpl_pmds[0]); +- +- ent = (pfm_default_smpl_entry_t *)cur; +- +- prefetch(arg->smpl_pmds_values); +- +- entry_size = sizeof(*ent) + (npmds << 3); +- +- /* position for first pmd */ +- e = (unsigned long *)(ent+1); +- +- hdr->hdr_count++; +- +- DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n", +- task->pid, +- hdr->hdr_count, +- cur, last, +- last-cur, +- ovfl_pmd, +- ovfl_notify, npmds)); +- +- /* +- * current = task running at the time of the overflow. +- * +- * per-task mode: +- * - this is ususally the task being monitored. +- * Under certain conditions, it might be a different task +- * +- * system-wide: +- * - this is not necessarily the task controlling the session +- */ +- ent->pid = current->pid; +- ent->ovfl_pmd = ovfl_pmd; +- ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val; +- +- /* +- * where did the fault happen (includes slot number) +- */ +- ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3); +- +- ent->tstamp = stamp; +- ent->cpu = smp_processor_id(); +- ent->set = arg->active_set; +- ent->tgid = current->tgid; +- +- /* +- * selectively store PMDs in increasing index number +- */ +- if (npmds) { +- unsigned long *val = arg->smpl_pmds_values; +- for(i=0; i < npmds; i++) { +- *e++ = *val++; +- } +- } +- +- /* +- * update position for next entry +- */ +- hdr->hdr_cur_offs += entry_size; +- cur += entry_size; +- +- /* +- * post check to avoid losing the last sample +- */ +- if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; +- +- /* +- * keep same ovfl_pmds, ovfl_notify +- */ +- arg->ovfl_ctrl.bits.notify_user = 0; +- arg->ovfl_ctrl.bits.block_task = 0; +- arg->ovfl_ctrl.bits.mask_monitoring = 0; +- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */ +- +- return 0; +-full: +- DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify)); +- +- /* +- * increment number of buffer overflow. +- * important to detect duplicate set of samples. +- */ +- hdr->hdr_overflows++; +- +- /* +- * if no notification requested, then we saturate the buffer +- */ +- if (ovfl_notify == 0) { +- arg->ovfl_ctrl.bits.notify_user = 0; +- arg->ovfl_ctrl.bits.block_task = 0; +- arg->ovfl_ctrl.bits.mask_monitoring = 1; +- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; +- } else { +- arg->ovfl_ctrl.bits.notify_user = 1; +- arg->ovfl_ctrl.bits.block_task = 1; /* ignored for non-blocking context */ +- arg->ovfl_ctrl.bits.mask_monitoring = 1; +- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */ +- } +- return -1; /* we are full, sorry */ +-} +- +-static int +-default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +-{ +- pfm_default_smpl_hdr_t *hdr; +- +- hdr = (pfm_default_smpl_hdr_t *)buf; +- +- hdr->hdr_count = 0UL; +- hdr->hdr_cur_offs = sizeof(*hdr); +- +- ctrl->bits.mask_monitoring = 0; +- ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */ +- +- return 0; +-} +- +-static int +-default_exit(struct task_struct *task, void *buf, struct pt_regs *regs) +-{ +- DPRINT(("[%d] exit(%p)\n", task_pid_nr(task), buf)); +- return 0; +-} +- +-static pfm_buffer_fmt_t default_fmt={ +- .fmt_name = "default_format", +- .fmt_uuid = PFM_DEFAULT_SMPL_UUID, +- .fmt_arg_size = sizeof(pfm_default_smpl_arg_t), +- .fmt_validate = default_validate, +- .fmt_getsize = default_get_size, +- .fmt_init = default_init, +- .fmt_handler = default_handler, +- .fmt_restart = default_restart, +- .fmt_restart_active = default_restart, +- .fmt_exit = default_exit, +-}; +- +-static int __init +-pfm_default_smpl_init_module(void) +-{ +- int ret; +- +- ret = pfm_register_buffer_fmt(&default_fmt); +- if (ret == 0) { +- printk("perfmon_default_smpl: %s v%u.%u registered\n", +- default_fmt.fmt_name, +- PFM_DEFAULT_SMPL_VERSION_MAJ, +- PFM_DEFAULT_SMPL_VERSION_MIN); +- } else { +- printk("perfmon_default_smpl: %s cannot register ret=%d\n", +- default_fmt.fmt_name, +- ret); +- } +- +- return ret; +-} +- +-static void __exit +-pfm_default_smpl_cleanup_module(void) +-{ +- int ret; +- ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid); +- +- printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret); +-} +- +-module_init(pfm_default_smpl_init_module); +-module_exit(pfm_default_smpl_cleanup_module); +- +--- a/arch/ia64/kernel/perfmon_generic.h ++++ /dev/null +@@ -1,45 +0,0 @@ +-/* +- * This file contains the generic PMU register description tables +- * and pmc checker used by perfmon.c. +- * +- * Copyright (C) 2002-2003 Hewlett Packard Co +- * Stephane Eranian +- */ +- +-static pfm_reg_desc_t pfm_gen_pmc_desc[PMU_MAX_PMCS]={ +-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-static pfm_reg_desc_t pfm_gen_pmd_desc[PMU_MAX_PMDS]={ +-/* pmd0 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +-/* pmd1 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +-/* pmd2 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +-/* pmd3 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +-/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +-/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +-/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +-/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-/* +- * impl_pmcs, impl_pmds are computed at runtime to minimize errors! +- */ +-static pmu_config_t pmu_conf_gen={ +- .pmu_name = "Generic", +- .pmu_family = 0xff, /* any */ +- .ovfl_val = (1UL << 32) - 1, +- .num_ibrs = 0, /* does not use */ +- .num_dbrs = 0, /* does not use */ +- .pmd_desc = pfm_gen_pmd_desc, +- .pmc_desc = pfm_gen_pmc_desc +-}; +- +--- a/arch/ia64/kernel/perfmon_itanium.h ++++ /dev/null +@@ -1,115 +0,0 @@ +-/* +- * This file contains the Itanium PMU register description tables +- * and pmc checker used by perfmon.c. +- * +- * Copyright (C) 2002-2003 Hewlett Packard Co +- * Stephane Eranian +- */ +-static int pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +- +-static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={ +-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc8 */ { PFM_REG_CONFIG , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc9 */ { PFM_REG_CONFIG , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc13 */ { PFM_REG_CONFIG , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={ +-/* pmd0 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +-/* pmd1 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +-/* pmd2 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +-/* pmd3 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +-/* pmd4 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +-/* pmd5 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +-/* pmd6 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +-/* pmd7 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +-/* pmd8 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd9 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd10 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd11 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd12 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd13 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd14 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd15 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd16 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd17 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +- { PFM_REG_END , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-static int +-pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +-{ +- int ret; +- int is_loaded; +- +- /* sanitfy check */ +- if (ctx == NULL) return -EINVAL; +- +- is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED; +- +- /* +- * we must clear the (instruction) debug registers if pmc13.ta bit is cleared +- * before they are written (fl_using_dbreg==0) to avoid picking up stale information. +- */ +- if (cnum == 13 && is_loaded && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) { +- +- DPRINT(("pmc[%d]=0x%lx has active pmc13.ta cleared, clearing ibr\n", cnum, *val)); +- +- /* don't mix debug with perfmon */ +- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; +- +- /* +- * a count of 0 will mark the debug registers as in use and also +- * ensure that they are properly cleared. +- */ +- ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs); +- if (ret) return ret; +- } +- +- /* +- * we must clear the (data) debug registers if pmc11.pt bit is cleared +- * before they are written (fl_using_dbreg==0) to avoid picking up stale information. +- */ +- if (cnum == 11 && is_loaded && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) { +- +- DPRINT(("pmc[%d]=0x%lx has active pmc11.pt cleared, clearing dbr\n", cnum, *val)); +- +- /* don't mix debug with perfmon */ +- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; +- +- /* +- * a count of 0 will mark the debug registers as in use and also +- * ensure that they are properly cleared. +- */ +- ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs); +- if (ret) return ret; +- } +- return 0; +-} +- +-/* +- * impl_pmcs, impl_pmds are computed at runtime to minimize errors! +- */ +-static pmu_config_t pmu_conf_ita={ +- .pmu_name = "Itanium", +- .pmu_family = 0x7, +- .ovfl_val = (1UL << 32) - 1, +- .pmd_desc = pfm_ita_pmd_desc, +- .pmc_desc = pfm_ita_pmc_desc, +- .num_ibrs = 8, +- .num_dbrs = 8, +- .use_rr_dbregs = 1, /* debug register are use for range retrictions */ +-}; +- +- +--- a/arch/ia64/kernel/perfmon_mckinley.h ++++ /dev/null +@@ -1,187 +0,0 @@ +-/* +- * This file contains the McKinley PMU register description tables +- * and pmc checker used by perfmon.c. +- * +- * Copyright (C) 2002-2003 Hewlett Packard Co +- * Stephane Eranian +- */ +-static int pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +- +-static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={ +-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc13 */ { PFM_REG_CONFIG , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc14 */ { PFM_REG_CONFIG , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +-/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={ +-/* pmd0 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +-/* pmd1 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +-/* pmd2 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +-/* pmd3 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +-/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +-/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +-/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +-/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +-/* pmd8 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd9 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd10 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd11 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd12 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd13 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd14 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd15 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd16 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +-/* pmd17 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-/* +- * PMC reserved fields must have their power-up values preserved +- */ +-static int +-pfm_mck_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs) +-{ +- unsigned long tmp1, tmp2, ival = *val; +- +- /* remove reserved areas from user value */ +- tmp1 = ival & PMC_RSVD_MASK(cnum); +- +- /* get reserved fields values */ +- tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum); +- +- *val = tmp1 | tmp2; +- +- DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", +- cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); +- return 0; +-} +- +-/* +- * task can be NULL if the context is unloaded +- */ +-static int +-pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +-{ +- int ret = 0, check_case1 = 0; +- unsigned long val8 = 0, val14 = 0, val13 = 0; +- int is_loaded; +- +- /* first preserve the reserved fields */ +- pfm_mck_reserved(cnum, val, regs); +- +- /* sanitfy check */ +- if (ctx == NULL) return -EINVAL; +- +- is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED; +- +- /* +- * we must clear the debug registers if pmc13 has a value which enable +- * memory pipeline event constraints. In this case we need to clear the +- * the debug registers if they have not yet been accessed. This is required +- * to avoid picking stale state. +- * PMC13 is "active" if: +- * one of the pmc13.cfg_dbrpXX field is different from 0x3 +- * AND +- * at the corresponding pmc13.ena_dbrpXX is set. +- */ +- DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, *val, ctx->ctx_fl_using_dbreg, is_loaded)); +- +- if (cnum == 13 && is_loaded +- && (*val & 0x1e00000000000UL) && (*val & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) { +- +- DPRINT(("pmc[%d]=0x%lx has active pmc13 settings, clearing dbr\n", cnum, *val)); +- +- /* don't mix debug with perfmon */ +- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; +- +- /* +- * a count of 0 will mark the debug registers as in use and also +- * ensure that they are properly cleared. +- */ +- ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs); +- if (ret) return ret; +- } +- /* +- * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled +- * before they are (fl_using_dbreg==0) to avoid picking up stale information. +- */ +- if (cnum == 14 && is_loaded && ((*val & 0x2222UL) != 0x2222UL) && ctx->ctx_fl_using_dbreg == 0) { +- +- DPRINT(("pmc[%d]=0x%lx has active pmc14 settings, clearing ibr\n", cnum, *val)); +- +- /* don't mix debug with perfmon */ +- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; +- +- /* +- * a count of 0 will mark the debug registers as in use and also +- * ensure that they are properly cleared. +- */ +- ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs); +- if (ret) return ret; +- +- } +- +- switch(cnum) { +- case 4: *val |= 1UL << 23; /* force power enable bit */ +- break; +- case 8: val8 = *val; +- val13 = ctx->ctx_pmcs[13]; +- val14 = ctx->ctx_pmcs[14]; +- check_case1 = 1; +- break; +- case 13: val8 = ctx->ctx_pmcs[8]; +- val13 = *val; +- val14 = ctx->ctx_pmcs[14]; +- check_case1 = 1; +- break; +- case 14: val8 = ctx->ctx_pmcs[8]; +- val13 = ctx->ctx_pmcs[13]; +- val14 = *val; +- check_case1 = 1; +- break; +- } +- /* check illegal configuration which can produce inconsistencies in tagging +- * i-side events in L1D and L2 caches +- */ +- if (check_case1) { +- ret = ((val13 >> 45) & 0xf) == 0 +- && ((val8 & 0x1) == 0) +- && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0) +- ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0)); +- +- if (ret) DPRINT((KERN_DEBUG "perfmon: failure check_case1\n")); +- } +- +- return ret ? -EINVAL : 0; +-} +- +-/* +- * impl_pmcs, impl_pmds are computed at runtime to minimize errors! +- */ +-static pmu_config_t pmu_conf_mck={ +- .pmu_name = "Itanium 2", +- .pmu_family = 0x1f, +- .flags = PFM_PMU_IRQ_RESEND, +- .ovfl_val = (1UL << 47) - 1, +- .pmd_desc = pfm_mck_pmd_desc, +- .pmc_desc = pfm_mck_pmc_desc, +- .num_ibrs = 8, +- .num_dbrs = 8, +- .use_rr_dbregs = 1 /* debug register are use for range restrictions */ +-}; +- +- +--- a/arch/ia64/kernel/perfmon_montecito.h ++++ /dev/null +@@ -1,269 +0,0 @@ +-/* +- * This file contains the Montecito PMU register description tables +- * and pmc checker used by perfmon.c. +- * +- * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. +- * Contributed by Stephane Eranian +- */ +-static int pfm_mont_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +- +-#define RDEP_MONT_ETB (RDEP(38)|RDEP(39)|RDEP(48)|RDEP(49)|RDEP(50)|RDEP(51)|RDEP(52)|RDEP(53)|RDEP(54)|\ +- RDEP(55)|RDEP(56)|RDEP(57)|RDEP(58)|RDEP(59)|RDEP(60)|RDEP(61)|RDEP(62)|RDEP(63)) +-#define RDEP_MONT_DEAR (RDEP(32)|RDEP(33)|RDEP(36)) +-#define RDEP_MONT_IEAR (RDEP(34)|RDEP(35)) +- +-static pfm_reg_desc_t pfm_mont_pmc_desc[PMU_MAX_PMCS]={ +-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc4 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(4),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc5 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(5),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc6 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(6),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc7 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(7),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc8 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(8),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc9 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(9),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc10 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(10),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc11 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(11),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc12 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(12),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc13 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(13),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc14 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(14),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc15 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(15),0, 0, 0}, {0,0, 0, 0}}, +-/* pmc16 */ { PFM_REG_NOTIMPL, }, +-/* pmc17 */ { PFM_REG_NOTIMPL, }, +-/* pmc18 */ { PFM_REG_NOTIMPL, }, +-/* pmc19 */ { PFM_REG_NOTIMPL, }, +-/* pmc20 */ { PFM_REG_NOTIMPL, }, +-/* pmc21 */ { PFM_REG_NOTIMPL, }, +-/* pmc22 */ { PFM_REG_NOTIMPL, }, +-/* pmc23 */ { PFM_REG_NOTIMPL, }, +-/* pmc24 */ { PFM_REG_NOTIMPL, }, +-/* pmc25 */ { PFM_REG_NOTIMPL, }, +-/* pmc26 */ { PFM_REG_NOTIMPL, }, +-/* pmc27 */ { PFM_REG_NOTIMPL, }, +-/* pmc28 */ { PFM_REG_NOTIMPL, }, +-/* pmc29 */ { PFM_REG_NOTIMPL, }, +-/* pmc30 */ { PFM_REG_NOTIMPL, }, +-/* pmc31 */ { PFM_REG_NOTIMPL, }, +-/* pmc32 */ { PFM_REG_CONFIG, 0, 0x30f01ffffffffffUL, 0x30f01ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc33 */ { PFM_REG_CONFIG, 0, 0x0, 0x1ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc34 */ { PFM_REG_CONFIG, 0, 0xf01ffffffffffUL, 0xf01ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc35 */ { PFM_REG_CONFIG, 0, 0x0, 0x1ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc36 */ { PFM_REG_CONFIG, 0, 0xfffffff0, 0xf, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc37 */ { PFM_REG_MONITOR, 4, 0x0, 0x3fff, NULL, pfm_mont_pmc_check, {RDEP_MONT_IEAR, 0, 0, 0}, {0, 0, 0, 0}}, +-/* pmc38 */ { PFM_REG_CONFIG, 0, 0xdb6, 0x2492, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc39 */ { PFM_REG_MONITOR, 6, 0x0, 0xffcf, NULL, pfm_mont_pmc_check, {RDEP_MONT_ETB,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc40 */ { PFM_REG_MONITOR, 6, 0x2000000, 0xf01cf, NULL, pfm_mont_pmc_check, {RDEP_MONT_DEAR,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc41 */ { PFM_REG_CONFIG, 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +-/* pmc42 */ { PFM_REG_MONITOR, 6, 0x0, 0x7ff4f, NULL, pfm_mont_pmc_check, {RDEP_MONT_ETB,0, 0, 0}, {0,0, 0, 0}}, +- { PFM_REG_END , 0, 0x0, -1, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-static pfm_reg_desc_t pfm_mont_pmd_desc[PMU_MAX_PMDS]={ +-/* pmd0 */ { PFM_REG_NOTIMPL, }, +-/* pmd1 */ { PFM_REG_NOTIMPL, }, +-/* pmd2 */ { PFM_REG_NOTIMPL, }, +-/* pmd3 */ { PFM_REG_NOTIMPL, }, +-/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(4),0, 0, 0}}, +-/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(5),0, 0, 0}}, +-/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(6),0, 0, 0}}, +-/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(7),0, 0, 0}}, +-/* pmd8 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(8),0, 0, 0}}, +-/* pmd9 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(9),0, 0, 0}}, +-/* pmd10 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(10),0, 0, 0}}, +-/* pmd11 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(11),0, 0, 0}}, +-/* pmd12 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(12),0, 0, 0}}, +-/* pmd13 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(13),0, 0, 0}}, +-/* pmd14 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(14),0, 0, 0}}, +-/* pmd15 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(15),0, 0, 0}}, +-/* pmd16 */ { PFM_REG_NOTIMPL, }, +-/* pmd17 */ { PFM_REG_NOTIMPL, }, +-/* pmd18 */ { PFM_REG_NOTIMPL, }, +-/* pmd19 */ { PFM_REG_NOTIMPL, }, +-/* pmd20 */ { PFM_REG_NOTIMPL, }, +-/* pmd21 */ { PFM_REG_NOTIMPL, }, +-/* pmd22 */ { PFM_REG_NOTIMPL, }, +-/* pmd23 */ { PFM_REG_NOTIMPL, }, +-/* pmd24 */ { PFM_REG_NOTIMPL, }, +-/* pmd25 */ { PFM_REG_NOTIMPL, }, +-/* pmd26 */ { PFM_REG_NOTIMPL, }, +-/* pmd27 */ { PFM_REG_NOTIMPL, }, +-/* pmd28 */ { PFM_REG_NOTIMPL, }, +-/* pmd29 */ { PFM_REG_NOTIMPL, }, +-/* pmd30 */ { PFM_REG_NOTIMPL, }, +-/* pmd31 */ { PFM_REG_NOTIMPL, }, +-/* pmd32 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(33)|RDEP(36),0, 0, 0}, {RDEP(40),0, 0, 0}}, +-/* pmd33 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(32)|RDEP(36),0, 0, 0}, {RDEP(40),0, 0, 0}}, +-/* pmd34 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(35),0, 0, 0}, {RDEP(37),0, 0, 0}}, +-/* pmd35 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(34),0, 0, 0}, {RDEP(37),0, 0, 0}}, +-/* pmd36 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(32)|RDEP(33),0, 0, 0}, {RDEP(40),0, 0, 0}}, +-/* pmd37 */ { PFM_REG_NOTIMPL, }, +-/* pmd38 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd39 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd40 */ { PFM_REG_NOTIMPL, }, +-/* pmd41 */ { PFM_REG_NOTIMPL, }, +-/* pmd42 */ { PFM_REG_NOTIMPL, }, +-/* pmd43 */ { PFM_REG_NOTIMPL, }, +-/* pmd44 */ { PFM_REG_NOTIMPL, }, +-/* pmd45 */ { PFM_REG_NOTIMPL, }, +-/* pmd46 */ { PFM_REG_NOTIMPL, }, +-/* pmd47 */ { PFM_REG_NOTIMPL, }, +-/* pmd48 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd49 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd50 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd51 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd52 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd53 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd54 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd55 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd56 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd57 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd58 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd59 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd60 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd61 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd62 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +-/* pmd63 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +- { PFM_REG_END , 0, 0x0, -1, NULL, NULL, {0,}, {0,}}, /* end marker */ +-}; +- +-/* +- * PMC reserved fields must have their power-up values preserved +- */ +-static int +-pfm_mont_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs) +-{ +- unsigned long tmp1, tmp2, ival = *val; +- +- /* remove reserved areas from user value */ +- tmp1 = ival & PMC_RSVD_MASK(cnum); +- +- /* get reserved fields values */ +- tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum); +- +- *val = tmp1 | tmp2; +- +- DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", +- cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); +- return 0; +-} +- +-/* +- * task can be NULL if the context is unloaded +- */ +-static int +-pfm_mont_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +-{ +- int ret = 0; +- unsigned long val32 = 0, val38 = 0, val41 = 0; +- unsigned long tmpval; +- int check_case1 = 0; +- int is_loaded; +- +- /* first preserve the reserved fields */ +- pfm_mont_reserved(cnum, val, regs); +- +- tmpval = *val; +- +- /* sanity check */ +- if (ctx == NULL) return -EINVAL; +- +- is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED; +- +- /* +- * we must clear the debug registers if pmc41 has a value which enable +- * memory pipeline event constraints. In this case we need to clear the +- * the debug registers if they have not yet been accessed. This is required +- * to avoid picking stale state. +- * PMC41 is "active" if: +- * one of the pmc41.cfg_dtagXX field is different from 0x3 +- * AND +- * at the corresponding pmc41.en_dbrpXX is set. +- * AND +- * ctx_fl_using_dbreg == 0 (i.e., dbr not yet used) +- */ +- DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, tmpval, ctx->ctx_fl_using_dbreg, is_loaded)); +- +- if (cnum == 41 && is_loaded +- && (tmpval & 0x1e00000000000UL) && (tmpval & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) { +- +- DPRINT(("pmc[%d]=0x%lx has active pmc41 settings, clearing dbr\n", cnum, tmpval)); +- +- /* don't mix debug with perfmon */ +- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; +- +- /* +- * a count of 0 will mark the debug registers if: +- * AND +- */ +- ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs); +- if (ret) return ret; +- } +- /* +- * we must clear the (instruction) debug registers if: +- * pmc38.ig_ibrpX is 0 (enabled) +- * AND +- * ctx_fl_using_dbreg == 0 (i.e., dbr not yet used) +- */ +- if (cnum == 38 && is_loaded && ((tmpval & 0x492UL) != 0x492UL) && ctx->ctx_fl_using_dbreg == 0) { +- +- DPRINT(("pmc38=0x%lx has active pmc38 settings, clearing ibr\n", tmpval)); +- +- /* don't mix debug with perfmon */ +- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; +- +- /* +- * a count of 0 will mark the debug registers as in use and also +- * ensure that they are properly cleared. +- */ +- ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs); +- if (ret) return ret; +- +- } +- switch(cnum) { +- case 32: val32 = *val; +- val38 = ctx->ctx_pmcs[38]; +- val41 = ctx->ctx_pmcs[41]; +- check_case1 = 1; +- break; +- case 38: val38 = *val; +- val32 = ctx->ctx_pmcs[32]; +- val41 = ctx->ctx_pmcs[41]; +- check_case1 = 1; +- break; +- case 41: val41 = *val; +- val32 = ctx->ctx_pmcs[32]; +- val38 = ctx->ctx_pmcs[38]; +- check_case1 = 1; +- break; +- } +- /* check illegal configuration which can produce inconsistencies in tagging +- * i-side events in L1D and L2 caches +- */ +- if (check_case1) { +- ret = (((val41 >> 45) & 0xf) == 0 && ((val32>>57) & 0x1) == 0) +- && ((((val38>>1) & 0x3) == 0x2 || ((val38>>1) & 0x3) == 0) +- || (((val38>>4) & 0x3) == 0x2 || ((val38>>4) & 0x3) == 0)); +- if (ret) { +- DPRINT(("invalid config pmc38=0x%lx pmc41=0x%lx pmc32=0x%lx\n", val38, val41, val32)); +- return -EINVAL; +- } +- } +- *val = tmpval; +- return 0; +-} +- +-/* +- * impl_pmcs, impl_pmds are computed at runtime to minimize errors! +- */ +-static pmu_config_t pmu_conf_mont={ +- .pmu_name = "Montecito", +- .pmu_family = 0x20, +- .flags = PFM_PMU_IRQ_RESEND, +- .ovfl_val = (1UL << 47) - 1, +- .pmd_desc = pfm_mont_pmd_desc, +- .pmc_desc = pfm_mont_pmc_desc, +- .num_ibrs = 8, +- .num_dbrs = 8, +- .use_rr_dbregs = 1 /* debug register are use for range retrictions */ +-}; +--- a/arch/ia64/kernel/process.c ++++ b/arch/ia64/kernel/process.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -45,10 +46,6 @@ + + #include "entry.h" + +-#ifdef CONFIG_PERFMON +-# include +-#endif +- + #include "sigframe.h" + + void (*ia64_mark_idle)(int); +@@ -162,10 +159,8 @@ show_regs (struct pt_regs *regs) + + void tsk_clear_notify_resume(struct task_struct *tsk) + { +-#ifdef CONFIG_PERFMON +- if (tsk->thread.pfm_needs_checking) ++ if (test_ti_thread_flag(task_thread_info(tsk), TIF_PERFMON_WORK)) + return; +-#endif + if (test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_RSE)) + return; + clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME); +@@ -188,14 +183,9 @@ do_notify_resume_user(sigset_t *unused, + return; + } + +-#ifdef CONFIG_PERFMON +- if (current->thread.pfm_needs_checking) +- /* +- * Note: pfm_handle_work() allow us to call it with interrupts +- * disabled, and may enable interrupts within the function. +- */ +- pfm_handle_work(); +-#endif ++ /* process perfmon asynchronous work (e.g. block thread or reset) */ ++ if (test_thread_flag(TIF_PERFMON_WORK)) ++ pfm_handle_work(task_pt_regs(current)); + + /* deal with pending signal delivery */ + if (test_thread_flag(TIF_SIGPENDING)) { +@@ -212,22 +202,15 @@ do_notify_resume_user(sigset_t *unused, + local_irq_disable(); /* force interrupt disable */ + } + +-static int pal_halt = 1; + static int can_do_pal_halt = 1; + + static int __init nohalt_setup(char * str) + { +- pal_halt = can_do_pal_halt = 0; ++ can_do_pal_halt = 0; + return 1; + } + __setup("nohalt", nohalt_setup); + +-void +-update_pal_halt_status(int status) +-{ +- can_do_pal_halt = pal_halt && status; +-} +- + /* + * We use this if we don't have any better idle routine.. + */ +@@ -236,6 +219,22 @@ default_idle (void) + { + local_irq_enable(); + while (!need_resched()) { ++#ifdef CONFIG_PERFMON ++ u64 psr = 0; ++ /* ++ * If requested, we stop the PMU to avoid ++ * measuring across the core idle loop. ++ * ++ * dcr.pp is not modified on purpose ++ * it is used when coming out of ++ * safe_halt() via interrupt ++ */ ++ if ((__get_cpu_var(pfm_syst_info) & PFM_ITA_CPUINFO_IDLE_EXCL)) { ++ psr = ia64_getreg(_IA64_REG_PSR); ++ if (psr & IA64_PSR_PP) ++ ia64_rsm(IA64_PSR_PP); ++ } ++#endif + if (can_do_pal_halt) { + local_irq_disable(); + if (!need_resched()) { +@@ -244,6 +243,12 @@ default_idle (void) + local_irq_enable(); + } else + cpu_relax(); ++#ifdef CONFIG_PERFMON ++ if ((__get_cpu_var(pfm_syst_info) & PFM_ITA_CPUINFO_IDLE_EXCL)) { ++ if (psr & IA64_PSR_PP) ++ ia64_ssm(IA64_PSR_PP); ++ } ++#endif + } + } + +@@ -344,22 +349,9 @@ cpu_idle (void) + void + ia64_save_extra (struct task_struct *task) + { +-#ifdef CONFIG_PERFMON +- unsigned long info; +-#endif +- + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) + ia64_save_debug_regs(&task->thread.dbr[0]); + +-#ifdef CONFIG_PERFMON +- if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) +- pfm_save_regs(task); +- +- info = __get_cpu_var(pfm_syst_info); +- if (info & PFM_CPUINFO_SYST_WIDE) +- pfm_syst_wide_update_task(task, info, 0); +-#endif +- + #ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(task_pt_regs(task))) + ia32_save_state(task); +@@ -369,22 +361,9 @@ ia64_save_extra (struct task_struct *tas + void + ia64_load_extra (struct task_struct *task) + { +-#ifdef CONFIG_PERFMON +- unsigned long info; +-#endif +- + if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) + ia64_load_debug_regs(&task->thread.dbr[0]); + +-#ifdef CONFIG_PERFMON +- if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) +- pfm_load_regs(task); +- +- info = __get_cpu_var(pfm_syst_info); +- if (info & PFM_CPUINFO_SYST_WIDE) +- pfm_syst_wide_update_task(task, info, 1); +-#endif +- + #ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(task_pt_regs(task))) + ia32_load_state(task); +@@ -510,8 +489,7 @@ copy_thread (int nr, unsigned long clone + * call behavior where scratch registers are preserved across + * system calls (unless used by the system call itself). + */ +-# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \ +- | IA64_THREAD_PM_VALID) ++# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID) + # define THREAD_FLAGS_TO_SET 0 + p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) + | THREAD_FLAGS_TO_SET); +@@ -533,10 +511,8 @@ copy_thread (int nr, unsigned long clone + } + #endif + +-#ifdef CONFIG_PERFMON +- if (current->thread.pfm_context) +- pfm_inherit(p, child_ptregs); +-#endif ++ pfm_copy_thread(p); ++ + return retval; + } + +@@ -745,15 +721,13 @@ exit_thread (void) + { + + ia64_drop_fpu(current); +-#ifdef CONFIG_PERFMON +- /* if needed, stop monitoring and flush state to perfmon context */ +- if (current->thread.pfm_context) +- pfm_exit_thread(current); ++ ++ /* if needed, stop monitoring and flush state to perfmon context */ ++ pfm_exit_thread(); + + /* free debug register resources */ +- if (current->thread.flags & IA64_THREAD_DBG_VALID) +- pfm_release_debug_registers(current); +-#endif ++ pfm_release_dbregs(current); ++ + if (IS_IA32_PROCESS(task_pt_regs(current))) + ia32_drop_ia64_partial_page_list(current); + } +--- a/arch/ia64/kernel/ptrace.c ++++ b/arch/ia64/kernel/ptrace.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -30,9 +31,6 @@ + #include + #include + #include +-#ifdef CONFIG_PERFMON +-#include +-#endif + + #include "entry.h" + +@@ -2124,7 +2122,6 @@ access_uarea(struct task_struct *child, + "address 0x%lx\n", addr); + return -1; + } +-#ifdef CONFIG_PERFMON + /* + * Check if debug registers are used by perfmon. This + * test must be done once we know that we can do the +@@ -2142,9 +2139,8 @@ access_uarea(struct task_struct *child, + * IA64_THREAD_DBG_VALID. The registers are restored + * by the PMU context switch code. + */ +- if (pfm_use_debug_registers(child)) ++ if (pfm_use_dbregs(child)) + return -1; +-#endif + + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; +--- a/arch/ia64/kernel/setup.c ++++ b/arch/ia64/kernel/setup.c +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1052,6 +1053,8 @@ cpu_init (void) + } + platform_cpu_init(); + pm_idle = default_idle; ++ ++ pfm_init_percpu(); + } + + void __init +--- a/arch/ia64/kernel/smpboot.c ++++ b/arch/ia64/kernel/smpboot.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -381,10 +382,6 @@ smp_callin (void) + extern void ia64_init_itm(void); + extern volatile int time_keeper_id; + +-#ifdef CONFIG_PERFMON +- extern void pfm_init_percpu(void); +-#endif +- + cpuid = smp_processor_id(); + phys_id = hard_smp_processor_id(); + itc_master = time_keeper_id; +@@ -410,10 +407,6 @@ smp_callin (void) + + ia64_mca_cmc_vector_setup(); /* Setup vector on AP */ + +-#ifdef CONFIG_PERFMON +- pfm_init_percpu(); +-#endif +- + local_irq_enable(); + + if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { +@@ -749,6 +742,7 @@ int __cpu_disable(void) + fixup_irqs(); + local_flush_tlb_all(); + cpu_clear(cpu, cpu_callin_map); ++ pfm_cpu_disable(); + return 0; + } + +--- a/arch/ia64/kernel/sys_ia64.c ++++ b/arch/ia64/kernel/sys_ia64.c +@@ -293,3 +293,11 @@ sys_pciconfig_write (unsigned long bus, + } + + #endif /* CONFIG_PCI */ ++ ++#ifndef CONFIG_IA64_PERFMON_COMPAT ++asmlinkage long ++sys_perfmonctl (int fd, int cmd, void __user *arg, int count) ++{ ++ return -ENOSYS; ++} ++#endif +--- a/arch/ia64/lib/Makefile ++++ b/arch/ia64/lib/Makefile +@@ -13,7 +13,6 @@ lib-y := __divsi3.o __udivsi3.o __modsi3 + + obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o + obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o +-lib-$(CONFIG_PERFMON) += carta_random.o + + AFLAGS___divdi3.o = + AFLAGS___udivdi3.o = -DUNSIGNED +--- a/arch/ia64/oprofile/init.c ++++ b/arch/ia64/oprofile/init.c +@@ -12,8 +12,8 @@ + #include + #include + +-extern int perfmon_init(struct oprofile_operations * ops); +-extern void perfmon_exit(void); ++extern int op_perfmon_init(struct oprofile_operations * ops); ++extern void op_perfmon_exit(void); + extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth); + + int __init oprofile_arch_init(struct oprofile_operations * ops) +@@ -22,7 +22,7 @@ int __init oprofile_arch_init(struct opr + + #ifdef CONFIG_PERFMON + /* perfmon_init() can fail, but we have no way to report it */ +- ret = perfmon_init(ops); ++ ret = op_perfmon_init(ops); + #endif + ops->backtrace = ia64_backtrace; + +@@ -33,6 +33,6 @@ int __init oprofile_arch_init(struct opr + void oprofile_arch_exit(void) + { + #ifdef CONFIG_PERFMON +- perfmon_exit(); ++ op_perfmon_exit(); + #endif + } +--- a/arch/ia64/oprofile/perfmon.c ++++ b/arch/ia64/oprofile/perfmon.c +@@ -10,25 +10,30 @@ + #include + #include + #include +-#include ++#include ++#include + #include + #include + + static int allow_ints; + + static int +-perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, +- struct pt_regs *regs, unsigned long stamp) ++perfmon_handler(struct pfm_context *ctx, ++ unsigned long ip, u64 stamp, void *data) + { +- int event = arg->pmd_eventid; ++ struct pt_regs *regs; ++ struct pfm_ovfl_arg *arg; ++ ++ regs = data; ++ arg = &ctx->ovfl_arg; + +- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET; + + /* the owner of the oprofile event buffer may have exited + * without perfmon being shutdown (e.g. SIGSEGV) + */ + if (allow_ints) +- oprofile_add_sample(regs, event); ++ oprofile_add_sample(regs, arg->pmd_eventid); + return 0; + } + +@@ -45,17 +50,13 @@ static void perfmon_stop(void) + allow_ints = 0; + } + +- +-#define OPROFILE_FMT_UUID { \ +- 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } +- +-static pfm_buffer_fmt_t oprofile_fmt = { +- .fmt_name = "oprofile_format", +- .fmt_uuid = OPROFILE_FMT_UUID, +- .fmt_handler = perfmon_handler, ++static struct pfm_smpl_fmt oprofile_fmt = { ++ .fmt_name = "OProfile", ++ .fmt_handler = perfmon_handler, ++ .fmt_flags = PFM_FMT_BUILTIN_FLAG, ++ .owner = THIS_MODULE + }; + +- + static char * get_cpu_type(void) + { + __u8 family = local_cpu_data->family; +@@ -75,9 +76,9 @@ static char * get_cpu_type(void) + + static int using_perfmon; + +-int perfmon_init(struct oprofile_operations * ops) ++int __init op_perfmon_init(struct oprofile_operations * ops) + { +- int ret = pfm_register_buffer_fmt(&oprofile_fmt); ++ int ret = pfm_fmt_register(&oprofile_fmt); + if (ret) + return -ENODEV; + +@@ -90,10 +91,10 @@ int perfmon_init(struct oprofile_operati + } + + +-void perfmon_exit(void) ++void op_perfmon_exit(void) + { + if (!using_perfmon) + return; + +- pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); ++ pfm_fmt_unregister(&oprofile_fmt); + } +--- /dev/null ++++ b/arch/ia64/perfmon/Kconfig +@@ -0,0 +1,67 @@ ++menu "Hardware Performance Monitoring support" ++config PERFMON ++ bool "Perfmon2 performance monitoring interface" ++ default n ++ help ++ Enables the perfmon2 interface to access the hardware ++ performance counters. See for ++ more details. ++ ++config PERFMON_DEBUG ++ bool "Perfmon debugging" ++ default n ++ depends on PERFMON ++ help ++ Enables perfmon debugging support ++ ++config PERFMON_DEBUG_FS ++ bool "Enable perfmon statistics reporting via debugfs" ++ default y ++ depends on PERFMON && DEBUG_FS ++ help ++ Enable collection and reporting of perfmon timing statistics under ++ debugfs. This is used for debugging and performance analysis of the ++ subsystem. The debugfs filesystem must be mounted. ++ ++config IA64_PERFMON_COMPAT ++ bool "Enable old perfmon-2 compatbility mode" ++ default n ++ depends on PERFMON ++ help ++ Enable this option to allow performance tools which used the old ++ perfmon-2 interface to continue to work. Old tools are those using ++ the obsolete commands and arguments. Check your programs and look ++ in include/asm-ia64/perfmon_compat.h for more information. ++ ++config IA64_PERFMON_GENERIC ++ tristate "Generic IA-64 PMU support" ++ depends on PERFMON ++ default n ++ help ++ Enables generic IA-64 PMU support. ++ The generic PMU is defined by the IA-64 architecture document. ++ This option should only be necessary when running with a PMU that ++ is not yet explicitely supported. Even then, there is no guarantee ++ that this support will work. ++ ++config IA64_PERFMON_ITANIUM ++ tristate "Itanium (Merced) Performance Monitoring support" ++ depends on PERFMON ++ default n ++ help ++ Enables Itanium (Merced) PMU support. ++ ++config IA64_PERFMON_MCKINLEY ++ tristate "Itanium 2 (McKinley) Performance Monitoring support" ++ depends on PERFMON ++ default n ++ help ++ Enables Itanium 2 (McKinley, Madison, Deerfield) PMU support. ++ ++config IA64_PERFMON_MONTECITO ++ tristate "Itanium 2 9000 (Montecito) Performance Monitoring support" ++ depends on PERFMON ++ default n ++ help ++ Enables support for Itanium 2 9000 (Montecito) PMU. ++endmenu +--- /dev/null ++++ b/arch/ia64/perfmon/Makefile +@@ -0,0 +1,11 @@ ++# ++# Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++# Contributed by Stephane Eranian ++# ++obj-$(CONFIG_PERFMON) += perfmon.o ++obj-$(CONFIG_IA64_PERFMON_COMPAT) += perfmon_default_smpl.o \ ++ perfmon_compat.o ++obj-$(CONFIG_IA64_PERFMON_GENERIC) += perfmon_generic.o ++obj-$(CONFIG_IA64_PERFMON_ITANIUM) += perfmon_itanium.o ++obj-$(CONFIG_IA64_PERFMON_MCKINLEY) += perfmon_mckinley.o ++obj-$(CONFIG_IA64_PERFMON_MONTECITO) += perfmon_montecito.o +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon.c +@@ -0,0 +1,946 @@ ++/* ++ * This file implements the IA-64 specific ++ * support for the perfmon2 interface ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++struct pfm_arch_session { ++ u32 pfs_sys_use_dbr; /* syswide session uses dbr */ ++ u32 pfs_ptrace_use_dbr; /* a thread uses dbr via ptrace()*/ ++}; ++ ++DEFINE_PER_CPU(u32, pfm_syst_info); ++ ++static struct pfm_arch_session pfm_arch_sessions; ++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pfm_arch_sessions_lock); ++ ++static inline void pfm_clear_psr_pp(void) ++{ ++ ia64_rsm(IA64_PSR_PP); ++} ++ ++static inline void pfm_set_psr_pp(void) ++{ ++ ia64_ssm(IA64_PSR_PP); ++} ++ ++static inline void pfm_clear_psr_up(void) ++{ ++ ia64_rsm(IA64_PSR_UP); ++} ++ ++static inline void pfm_set_psr_up(void) ++{ ++ ia64_ssm(IA64_PSR_UP); ++} ++ ++static inline void pfm_set_psr_l(u64 val) ++{ ++ ia64_setreg(_IA64_REG_PSR_L, val); ++} ++ ++static inline void pfm_restore_ibrs(u64 *ibrs, unsigned int nibrs) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nibrs; i++) { ++ ia64_set_ibr(i, ibrs[i]); ++ ia64_dv_serialize_instruction(); ++ } ++ ia64_srlz_i(); ++} ++ ++static inline void pfm_restore_dbrs(u64 *dbrs, unsigned int ndbrs) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ndbrs; i++) { ++ ia64_set_dbr(i, dbrs[i]); ++ ia64_dv_serialize_data(); ++ } ++ ia64_srlz_d(); ++} ++ ++irqreturn_t pmu_interrupt_handler(int irq, void *arg) ++{ ++ struct pt_regs *regs; ++ regs = get_irq_regs(); ++ irq_enter(); ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++ irq_exit(); ++ return IRQ_HANDLED; ++} ++static struct irqaction perfmon_irqaction = { ++ .handler = pmu_interrupt_handler, ++ .flags = IRQF_DISABLED, /* means keep interrupts masked */ ++ .name = "perfmon" ++}; ++ ++void pfm_arch_quiesce_pmu_percpu(void) ++{ ++ u64 dcr; ++ /* ++ * make sure no measurement is active ++ * (may inherit programmed PMCs from EFI). ++ */ ++ pfm_clear_psr_pp(); ++ pfm_clear_psr_up(); ++ ++ /* ++ * ensure dcr.pp is cleared ++ */ ++ dcr = ia64_getreg(_IA64_REG_CR_DCR); ++ ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP); ++ ++ /* ++ * we run with the PMU not frozen at all times ++ */ ++ ia64_set_pmc(0, 0); ++ ia64_srlz_d(); ++} ++ ++void pfm_arch_init_percpu(void) ++{ ++ pfm_arch_quiesce_pmu_percpu(); ++ /* ++ * program PMU interrupt vector ++ */ ++ ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); ++ ia64_srlz_d(); ++} ++ ++int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ ctx_arch->flags.use_dbr = 0; ++ ctx_arch->flags.insecure = (ctx_flags & PFM_ITA_FL_INSECURE) ? 1: 0; ++ ++ PFM_DBG("insecure=%d", ctx_arch->flags.insecure); ++ ++ return 0; ++} ++ ++/* ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * Context is locked. Interrupts are masked. Monitoring may be active. ++ * PMU access is guaranteed. PMC and PMD registers are live in PMU. ++ * ++ * Return: ++ * non-zero : did not save PMDs (as part of stopping the PMU) ++ * 0 : saved PMDs (no need to save them in caller) ++ */ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_event_set *set; ++ u64 psr, tmp; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ set = ctx->active_set; ++ ++ /* ++ * save current PSR: needed because we modify it ++ */ ++ ia64_srlz_d(); ++ psr = ia64_getreg(_IA64_REG_PSR); ++ ++ /* ++ * stop monitoring: ++ * This is the last instruction which may generate an overflow ++ * ++ * we do not clear ipsr.up ++ */ ++ pfm_clear_psr_up(); ++ ia64_srlz_d(); ++ ++ /* ++ * extract overflow status bits ++ */ ++ tmp = ia64_get_pmc(0) & ~0xf; ++ ++ /* ++ * keep a copy of psr.up (for reload) ++ */ ++ ctx_arch->ctx_saved_psr_up = psr & IA64_PSR_UP; ++ ++ /* ++ * save overflow status bits ++ */ ++ set->povfl_pmds[0] = tmp; ++ ++ /* ++ * record how many pending overflows ++ * XXX: assume identity mapping for counters ++ */ ++ set->npend_ovfls = ia64_popcnt(tmp); ++ ++ /* ++ * make sure the PMU is unfrozen for the next task ++ */ ++ if (set->npend_ovfls) { ++ ia64_set_pmc(0, 0); ++ ia64_srlz_d(); ++ } ++ return 1; ++} ++ ++/* ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * set cannot be NULL. Context is locked. Interrupts are masked. ++ * Caller has already restored all PMD and PMC registers. ++ * ++ * must reactivate monitoring ++ */ ++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * when monitoring is not explicitly started ++ * then psr_up = 0, in which case we do not ++ * need to restore ++ */ ++ if (likely(ctx_arch->ctx_saved_psr_up)) { ++ pfm_set_psr_up(); ++ ia64_srlz_d(); ++ } ++} ++ ++int pfm_arch_reserve_session(struct pfm_context *ctx, u32 cpu) ++{ ++ struct pfm_arch_context *ctx_arch; ++ int is_system; ++ int ret = 0; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ is_system = ctx->flags.system; ++ ++ spin_lock(&pfm_arch_sessions_lock); ++ ++ if (is_system && ctx_arch->flags.use_dbr) { ++ PFM_DBG("syswide context uses dbregs"); ++ ++ if (pfm_arch_sessions.pfs_ptrace_use_dbr) { ++ PFM_DBG("cannot reserve syswide context: " ++ "dbregs in use by ptrace"); ++ ret = -EBUSY; ++ } else { ++ pfm_arch_sessions.pfs_sys_use_dbr++; ++ } ++ } ++ spin_unlock(&pfm_arch_sessions_lock); ++ ++ return ret; ++} ++ ++void pfm_arch_release_session(struct pfm_context *ctx, u32 cpu) ++{ ++ struct pfm_arch_context *ctx_arch; ++ int is_system; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ is_system = ctx->flags.system; ++ ++ spin_lock(&pfm_arch_sessions_lock); ++ ++ if (is_system && ctx_arch->flags.use_dbr) ++ pfm_arch_sessions.pfs_sys_use_dbr--; ++ spin_unlock(&pfm_arch_sessions_lock); ++} ++ ++/* ++ * function called from pfm_load_context_*(). Task is not guaranteed to be ++ * current task. If not then other task is guaranteed stopped and off any CPU. ++ * context is locked and interrupts are masked. ++ * ++ * On PFM_LOAD_CONTEXT, the interface guarantees monitoring is stopped. ++ * ++ * For system-wide task is NULL ++ */ ++int pfm_arch_load_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pt_regs *regs; ++ int ret = 0; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * cannot load a context which is using range restrictions, ++ * into a thread that is being debugged. ++ * ++ * if one set out of several is using the debug registers, then ++ * we assume the context as whole is using them. ++ */ ++ if (ctx_arch->flags.use_dbr) { ++ if (ctx->flags.system) { ++ spin_lock(&pfm_arch_sessions_lock); ++ ++ if (pfm_arch_sessions.pfs_ptrace_use_dbr) { ++ PFM_DBG("cannot reserve syswide context: " ++ "dbregs in use by ptrace"); ++ ret = -EBUSY; ++ } else { ++ pfm_arch_sessions.pfs_sys_use_dbr++; ++ PFM_DBG("pfs_sys_use_dbr=%u", ++ pfm_arch_sessions.pfs_sys_use_dbr); ++ } ++ spin_unlock(&pfm_arch_sessions_lock); ++ ++ } else if (ctx->task->thread.flags & IA64_THREAD_DBG_VALID) { ++ PFM_DBG("load_pid [%d] thread is debugged, cannot " ++ "use range restrictions", ctx->task->pid); ++ ret = -EBUSY; ++ } ++ if (ret) ++ return ret; ++ } ++ ++ /* ++ * We need to intervene on context switch to toggle the ++ * psr.pp bit in system-wide. As such, we set the TIF ++ * flag so that pfm_arch_ctxswout_sys() and the ++ * pfm_arch_ctxswin_sys() functions get called ++ * from pfm_ctxsw_sys(); ++ */ ++ if (ctx->flags.system) { ++ set_thread_flag(TIF_PERFMON_CTXSW); ++ PFM_DBG("[%d] set TIF", current->pid); ++ return 0; ++ } ++ ++ regs = task_pt_regs(ctx->task); ++ ++ /* ++ * self-monitoring systematically allows user level control ++ */ ++ if (ctx->task != current) { ++ /* ++ * when not current, task is stopped, so this is safe ++ */ ++ ctx_arch->ctx_saved_psr_up = 0; ++ ia64_psr(regs)->up = ia64_psr(regs)->pp = 0; ++ } else ++ ctx_arch->flags.insecure = 1; ++ ++ /* ++ * allow user level control (start/stop/read pmd) if: ++ * - self-monitoring ++ * - requested at context creation (PFM_IA64_FL_INSECURE) ++ * ++ * There is not security hole with PFM_IA64_FL_INSECURE because ++ * when not self-monitored, the caller must have permissions to ++ * attached to the task. ++ */ ++ if (ctx_arch->flags.insecure) { ++ ia64_psr(regs)->sp = 0; ++ PFM_DBG("clearing psr.sp for [%d]", ctx->task->pid); ++ } ++ return 0; ++} ++ ++int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags) ++{ ++#define PFM_SETFL_BOTH_SWITCH (PFM_SETFL_OVFL_SWITCH|PFM_SETFL_TIME_SWITCH) ++#define PFM_ITA_SETFL_BOTH_INTR (PFM_ITA_SETFL_INTR_ONLY|\ ++ PFM_ITA_SETFL_EXCL_INTR) ++ ++/* exclude return value field */ ++#define PFM_SETFL_ALL_MASK (PFM_ITA_SETFL_BOTH_INTR \ ++ | PFM_SETFL_BOTH_SWITCH \ ++ | PFM_ITA_SETFL_IDLE_EXCL) ++ ++ if ((flags & ~PFM_SETFL_ALL_MASK)) { ++ PFM_DBG("invalid flags=0x%x", flags); ++ return -EINVAL; ++ } ++ ++ if ((flags & PFM_ITA_SETFL_BOTH_INTR) == PFM_ITA_SETFL_BOTH_INTR) { ++ PFM_DBG("both excl intr and ontr only are set"); ++ return -EINVAL; ++ } ++ ++ if ((flags & PFM_ITA_SETFL_IDLE_EXCL) && !ctx->flags.system) { ++ PFM_DBG("idle exclude flag only for system-wide context"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * function called from pfm_unload_context_*(). Context is locked. ++ * interrupts are masked. task is not guaranteed to be current task. ++ * Access to PMU is not guaranteed. ++ * ++ * function must do whatever arch-specific action is required on unload ++ * of a context. ++ * ++ * called for both system-wide and per-thread. task is NULL for ssytem-wide ++ */ ++void pfm_arch_unload_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pt_regs *regs; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ if (ctx->flags.system) { ++ /* ++ * disable context switch hook ++ */ ++ clear_thread_flag(TIF_PERFMON_CTXSW); ++ ++ if (ctx_arch->flags.use_dbr) { ++ spin_lock(&pfm_arch_sessions_lock); ++ pfm_arch_sessions.pfs_sys_use_dbr--; ++ PFM_DBG("sys_use_dbr=%u", pfm_arch_sessions.pfs_sys_use_dbr); ++ spin_unlock(&pfm_arch_sessions_lock); ++ } ++ } else { ++ regs = task_pt_regs(ctx->task); ++ ++ /* ++ * cancel user level control for per-task context ++ */ ++ ia64_psr(regs)->sp = 1; ++ PFM_DBG("setting psr.sp for [%d]", ctx->task->pid); ++ } ++} ++ ++/* ++ * mask monitoring by setting the privilege level to 0 ++ * we cannot use psr.pp/psr.up for this, it is controlled by ++ * the user ++ */ ++void pfm_arch_mask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ unsigned long mask; ++ unsigned int i; ++ ++ arch_info = pfm_pmu_info(); ++ /* ++ * as an optimization we look at the first 64 PMC ++ * registers only starting at PMC4. ++ */ ++ mask = arch_info->mask_pmcs[0] >> PFM_ITA_FCNTR; ++ for (i = PFM_ITA_FCNTR; mask; i++, mask >>= 1) { ++ if (likely(mask & 0x1)) ++ ia64_set_pmc(i, set->pmcs[i] & ~0xfUL); ++ } ++ /* ++ * make changes visisble ++ */ ++ ia64_srlz_d(); ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets() ++ * context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMD registers from set. ++ */ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch; ++ unsigned long *mask; ++ u16 i, num; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ if (ctx_arch->flags.insecure) { ++ num = ctx->regs.num_rw_pmd; ++ mask = ctx->regs.rw_pmds; ++ } else { ++ num = set->nused_pmds; ++ mask = set->used_pmds; ++ } ++ /* ++ * must restore all implemented read-write PMDS to avoid leaking ++ * information especially when PFM_IA64_FL_INSECURE is set. ++ * ++ * XXX: should check PFM_IA64_FL_INSECURE==0 and use used_pmd instead ++ */ ++ for (i = 0; num; i++) { ++ if (likely(test_bit(i, mask))) { ++ pfm_arch_write_pmd(ctx, i, set->pmds[i].value); ++ num--; ++ } ++ } ++ ia64_srlz_d(); ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets() ++ * context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMC registers from set if needed ++ */ ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ u64 mask2 = 0, val, plm; ++ unsigned long impl_mask, mask_pmcs; ++ unsigned int i; ++ ++ arch_info = pfm_pmu_info(); ++ /* ++ * as an optimization we only look at the first 64 ++ * PMC registers. In fact, we should never scan the ++ * entire impl_pmcs because ibr/dbr are implemented ++ * separately. ++ * ++ * always skip PMC0-PMC3. PMC0 taken care of when saving ++ * state. PMC1-PMC3 not used until we get counters in ++ * the 60 and above index range. ++ */ ++ impl_mask = ctx->regs.pmcs[0] >> PFM_ITA_FCNTR; ++ mask_pmcs = arch_info->mask_pmcs[0] >> PFM_ITA_FCNTR; ++ plm = ctx->state == PFM_CTX_MASKED ? ~0xf : ~0x0; ++ ++ for (i = PFM_ITA_FCNTR; ++ impl_mask; ++ i++, impl_mask >>= 1, mask_pmcs >>= 1) { ++ if (likely(impl_mask & 0x1)) { ++ mask2 = mask_pmcs & 0x1 ? plm : ~0; ++ val = set->pmcs[i] & mask2; ++ ia64_set_pmc(i, val); ++ PFM_DBG_ovfl("pmc%u=0x%lx", i, val); ++ } ++ } ++ /* ++ * restore DBR/IBR ++ */ ++ if (set->priv_flags & PFM_ITA_SETFL_USE_DBR) { ++ pfm_restore_ibrs(set->pmcs+256, 8); ++ pfm_restore_dbrs(set->pmcs+264, 8); ++ } ++ ia64_srlz_d(); ++} ++ ++void pfm_arch_unmask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 psr; ++ int is_system; ++ ++ is_system = ctx->flags.system; ++ ++ psr = ia64_getreg(_IA64_REG_PSR); ++ ++ /* ++ * monitoring is masked via the PMC.plm ++ * ++ * As we restore their value, we do not want each counter to ++ * restart right away. We stop monitoring using the PSR, ++ * restore the PMC (and PMD) and then re-establish the psr ++ * as it was. Note that there can be no pending overflow at ++ * this point, because monitoring is still MASKED. ++ * ++ * Because interrupts are masked we can avoid changing ++ * DCR.pp. ++ */ ++ if (is_system) ++ pfm_clear_psr_pp(); ++ else ++ pfm_clear_psr_up(); ++ ++ ia64_srlz_d(); ++ ++ pfm_arch_restore_pmcs(ctx, set); ++ ++ /* ++ * restore psr ++ * ++ * monitoring may start right now but interrupts ++ * are still masked ++ */ ++ pfm_set_psr_l(psr); ++ ia64_srlz_d(); ++} ++ ++/* ++ * Called from pfm_stop() ++ * ++ * For per-thread: ++ * task is not necessarily current. If not current task, then ++ * task is guaranteed stopped and off any cpu. Access to PMU ++ * is not guaranteed. Interrupts are masked. Context is locked. ++ * Set is the active set. ++ * ++ * must disable active monitoring. ctx cannot be NULL ++ */ ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pt_regs *regs; ++ u64 dcr, psr; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ regs = task_pt_regs(task); ++ ++ if (!ctx->flags.system) { ++ /* ++ * in ZOMBIE state we always have task == current due to ++ * pfm_exit_thread() ++ */ ++ ia64_psr(regs)->up = 0; ++ ctx_arch->ctx_saved_psr_up = 0; ++ ++ /* ++ * in case of ZOMBIE state, there is no unload to clear ++ * insecure monitoring, so we do it in stop instead. ++ */ ++ if (ctx->state == PFM_CTX_ZOMBIE) ++ ia64_psr(regs)->sp = 1; ++ ++ if (task == current) { ++ pfm_clear_psr_up(); ++ ia64_srlz_d(); ++ } ++ } else if (ctx->flags.started) { /* do not stop twice */ ++ dcr = ia64_getreg(_IA64_REG_CR_DCR); ++ psr = ia64_getreg(_IA64_REG_PSR); ++ ++ ia64_psr(regs)->pp = 0; ++ ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP); ++ pfm_clear_psr_pp(); ++ ia64_srlz_d(); ++ ++ if (ctx->active_set->flags & PFM_ITA_SETFL_IDLE_EXCL) { ++ PFM_DBG("disabling idle exclude"); ++ __get_cpu_var(pfm_syst_info) &= ~PFM_ITA_CPUINFO_IDLE_EXCL; ++ } ++ } ++} ++ ++/* ++ * called from pfm_start() ++ * ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-thread: ++ * Task is not necessarily current. If not current task, then task ++ * is guaranteed stopped and off any cpu. No access to PMU is task ++ * is not current. ++ * ++ * For system-wide: ++ * task is always current ++ * ++ * must enable active monitoring. ++ */ ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pt_regs *regs; ++ u64 dcr, dcr_pp, psr_pp; ++ u32 flags; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ regs = task_pt_regs(task); ++ flags = ctx->active_set->flags; ++ ++ /* ++ * per-thread mode ++ */ ++ if (!ctx->flags.system) { ++ ++ ia64_psr(regs)->up = 1; ++ ++ if (task == current) { ++ pfm_set_psr_up(); ++ ia64_srlz_d(); ++ } else { ++ /* ++ * activate monitoring at next ctxswin ++ */ ++ ctx_arch->ctx_saved_psr_up = IA64_PSR_UP; ++ } ++ return; ++ } ++ ++ /* ++ * system-wide mode ++ */ ++ dcr = ia64_getreg(_IA64_REG_CR_DCR); ++ if (flags & PFM_ITA_SETFL_INTR_ONLY) { ++ dcr_pp = 1; ++ psr_pp = 0; ++ } else if (flags & PFM_ITA_SETFL_EXCL_INTR) { ++ dcr_pp = 0; ++ psr_pp = 1; ++ } else { ++ dcr_pp = psr_pp = 1; ++ } ++ PFM_DBG("dcr_pp=%lu psr_pp=%lu", dcr_pp, psr_pp); ++ ++ /* ++ * update dcr_pp and psr_pp ++ */ ++ if (dcr_pp) ++ ia64_setreg(_IA64_REG_CR_DCR, dcr | IA64_DCR_PP); ++ else ++ ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP); ++ ++ if (psr_pp) { ++ pfm_set_psr_pp(); ++ ia64_psr(regs)->pp = 1; ++ } else { ++ pfm_clear_psr_pp(); ++ ia64_psr(regs)->pp = 0; ++ } ++ ia64_srlz_d(); ++ ++ if (ctx->active_set->flags & PFM_ITA_SETFL_IDLE_EXCL) { ++ PFM_DBG("enable idle exclude"); ++ __get_cpu_var(pfm_syst_info) |= PFM_ITA_CPUINFO_IDLE_EXCL; ++ } ++} ++ ++/* ++ * Only call this function when a process is trying to ++ * write the debug registers (reading is always allowed) ++ * called from arch/ia64/kernel/ptrace.c:access_uarea() ++ */ ++int __pfm_use_dbregs(struct task_struct *task) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_context *ctx; ++ unsigned long flags; ++ int ret = 0; ++ ++ PFM_DBG("called for [%d]", task->pid); ++ ++ ctx = task->pfm_context; ++ ++ /* ++ * do it only once ++ */ ++ if (task->thread.flags & IA64_THREAD_DBG_VALID) { ++ PFM_DBG("IA64_THREAD_DBG_VALID already set"); ++ return 0; ++ } ++ if (ctx) { ++ spin_lock_irqsave(&ctx->lock, flags); ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ if (ctx_arch->flags.use_dbr == 1) { ++ PFM_DBG("PMU using dbregs already, no ptrace access"); ++ ret = -1; ++ } ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ if (ret) ++ return ret; ++ } ++ ++ spin_lock(&pfm_arch_sessions_lock); ++ ++ /* ++ * We cannot allow setting breakpoints when system wide monitoring ++ * sessions are using the debug registers. ++ */ ++ if (!pfm_arch_sessions.pfs_sys_use_dbr) ++ pfm_arch_sessions.pfs_ptrace_use_dbr++; ++ else ++ ret = -1; ++ ++ PFM_DBG("ptrace_use_dbr=%u sys_use_dbr=%u by [%d] ret = %d", ++ pfm_arch_sessions.pfs_ptrace_use_dbr, ++ pfm_arch_sessions.pfs_sys_use_dbr, ++ task->pid, ret); ++ ++ spin_unlock(&pfm_arch_sessions_lock); ++ if (ret) ++ return ret; ++#ifndef CONFIG_SMP ++ /* ++ * in UP, we need to check whether the current ++ * owner of the PMU is not using the debug registers ++ * for monitoring. Because we are using a lazy ++ * save on ctxswout, we must force a save in this ++ * case because the debug registers are being ++ * modified by another task. We save the current ++ * PMD registers, and clear ownership. In ctxswin, ++ * full state will be reloaded. ++ * ++ * Note: we overwrite task. ++ */ ++ task = __get_cpu_var(pmu_owner); ++ ctx = __get_cpu_var(pmu_ctx); ++ ++ if (task == NULL) ++ return 0; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ if (ctx_arch->flags.use_dbr) ++ pfm_save_pmds_release(ctx); ++#endif ++ return 0; ++} ++ ++/* ++ * This function is called for every task that exits with the ++ * IA64_THREAD_DBG_VALID set. This indicates a task which was ++ * able to use the debug registers for debugging purposes via ++ * ptrace(). Therefore we know it was not using them for ++ * perfmormance monitoring, so we only decrement the number ++ * of "ptraced" debug register users to keep the count up to date ++ */ ++int __pfm_release_dbregs(struct task_struct *task) ++{ ++ int ret; ++ ++ spin_lock(&pfm_arch_sessions_lock); ++ ++ if (pfm_arch_sessions.pfs_ptrace_use_dbr == 0) { ++ PFM_ERR("invalid release for [%d] ptrace_use_dbr=0", task->pid); ++ ret = -1; ++ } else { ++ pfm_arch_sessions.pfs_ptrace_use_dbr--; ++ ret = 0; ++ } ++ spin_unlock(&pfm_arch_sessions_lock); ++ ++ return ret; ++} ++ ++int pfm_ia64_mark_dbregs_used(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct task_struct *task; ++ struct thread_struct *thread; ++ int ret = 0, state; ++ int i, can_access_pmu = 0; ++ int is_loaded, is_system; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ state = ctx->state; ++ task = ctx->task; ++ is_loaded = state == PFM_CTX_LOADED || state == PFM_CTX_MASKED; ++ is_system = ctx->flags.system; ++ can_access_pmu = __get_cpu_var(pmu_owner) == task || is_system; ++ ++ if (is_loaded == 0) ++ goto done; ++ ++ if (is_system == 0) { ++ thread = &(task->thread); ++ ++ /* ++ * cannot use debug registers for montioring if they are ++ * already used for debugging ++ */ ++ if (thread->flags & IA64_THREAD_DBG_VALID) { ++ PFM_DBG("debug registers already in use for [%d]", ++ task->pid); ++ return -EBUSY; ++ } ++ } ++ ++ /* ++ * check for debug registers in system wide mode ++ */ ++ spin_lock(&pfm_arch_sessions_lock); ++ ++ if (is_system) { ++ if (pfm_arch_sessions.pfs_ptrace_use_dbr) ++ ret = -EBUSY; ++ else ++ pfm_arch_sessions.pfs_sys_use_dbr++; ++ } ++ ++ spin_unlock(&pfm_arch_sessions_lock); ++ ++ if (ret != 0) ++ return ret; ++ ++ /* ++ * clear hardware registers to make sure we don't ++ * pick up stale state. ++ */ ++ if (can_access_pmu) { ++ PFM_DBG("clearing ibrs, dbrs"); ++ for (i = 0; i < 8; i++) { ++ ia64_set_ibr(i, 0); ++ ia64_dv_serialize_instruction(); ++ } ++ ia64_srlz_i(); ++ for (i = 0; i < 8; i++) { ++ ia64_set_dbr(i, 0); ++ ia64_dv_serialize_data(); ++ } ++ ia64_srlz_d(); ++ } ++done: ++ /* ++ * debug registers are now in use ++ */ ++ ctx_arch->flags.use_dbr = 1; ++ set->priv_flags |= PFM_ITA_SETFL_USE_DBR; ++ PFM_DBG("set%u use_dbr=1", set->id); ++ return 0; ++} ++EXPORT_SYMBOL(pfm_ia64_mark_dbregs_used); ++ ++char *pfm_arch_get_pmu_module_name(void) ++{ ++ switch (local_cpu_data->family) { ++ case 0x07: ++ return "perfmon_itanium"; ++ case 0x1f: ++ return "perfmon_mckinley"; ++ case 0x20: ++ return "perfmon_montecito"; ++ default: ++ return "perfmon_generic"; ++ } ++ return NULL; ++} ++ ++/* ++ * global arch-specific intialization, called only once ++ */ ++int __init pfm_arch_init(void) ++{ ++ int ret; ++ ++ spin_lock_init(&pfm_arch_sessions_lock); ++ ++#ifdef CONFIG_IA64_PERFMON_COMPAT ++ ret = pfm_ia64_compat_init(); ++ if (ret) ++ return ret; ++#endif ++ register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); ++ ++ ++ return 0; ++} +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon_compat.c +@@ -0,0 +1,1210 @@ ++/* ++ * This file implements the IA-64 specific ++ * support for the perfmon2 interface ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++asmlinkage long sys_pfm_stop(int fd); ++asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *st); ++asmlinkage long sys_pfm_unload_context(int fd); ++asmlinkage long sys_pfm_restart(int fd); ++asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ld); ++ ++ssize_t pfm_sysfs_res_show(char *buf, size_t sz, int what); ++ ++extern ssize_t __pfm_read(struct pfm_context *ctx, ++ union pfarg_msg *msg_buf, ++ int non_block); ++/* ++ * function providing some help for backward compatiblity with old IA-64 ++ * applications. In the old model, certain attributes of a counter were ++ * passed via the PMC, now they are passed via the PMD. ++ */ ++static int pfm_compat_update_pmd(struct pfm_context *ctx, u16 set_id, u16 cnum, ++ u32 rflags, ++ unsigned long *smpl_pmds, ++ unsigned long *reset_pmds, ++ u64 eventid) ++{ ++ struct pfm_event_set *set; ++ int is_counting; ++ unsigned long *impl_pmds; ++ u32 flags = 0; ++ u16 max_pmd; ++ ++ impl_pmds = ctx->regs.pmds; ++ max_pmd = ctx->regs.max_pmd; ++ ++ /* ++ * given that we do not maintain PMC ->PMD dependencies ++ * we cannot figure out what to do in case PMCxx != PMDxx ++ */ ++ if (cnum > max_pmd) ++ return 0; ++ ++ /* ++ * assumes PMCxx controls PMDxx which is always true for counters ++ * on Itanium PMUs. ++ */ ++ is_counting = pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64; ++ set = pfm_find_set(ctx, set_id, 0); ++ ++ /* ++ * for v2.0, we only allowed counting PMD to generate ++ * user-level notifications. Same thing with randomization. ++ */ ++ if (is_counting) { ++ if (rflags & PFM_REGFL_OVFL_NOTIFY) ++ flags |= PFM_REGFL_OVFL_NOTIFY; ++ if (rflags & PFM_REGFL_RANDOM) ++ flags |= PFM_REGFL_RANDOM; ++ /* ++ * verify validity of smpl_pmds ++ */ ++ if (unlikely(bitmap_subset(smpl_pmds, ++ impl_pmds, max_pmd) == 0)) { ++ PFM_DBG("invalid smpl_pmds=0x%llx for pmd%u", ++ (unsigned long long)smpl_pmds[0], cnum); ++ return -EINVAL; ++ } ++ /* ++ * verify validity of reset_pmds ++ */ ++ if (unlikely(bitmap_subset(reset_pmds, ++ impl_pmds, max_pmd) == 0)) { ++ PFM_DBG("invalid reset_pmds=0x%lx for pmd%u", ++ reset_pmds[0], cnum); ++ return -EINVAL; ++ } ++ /* ++ * ensures that a PFM_READ_PMDS succeeds with a ++ * corresponding PFM_WRITE_PMDS ++ */ ++ __set_bit(cnum, set->used_pmds); ++ ++ } else if (rflags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { ++ PFM_DBG("cannot set ovfl_notify or random on pmd%u", cnum); ++ return -EINVAL; ++ } ++ ++ set->pmds[cnum].flags = flags; ++ ++ if (is_counting) { ++ bitmap_copy(set->pmds[cnum].reset_pmds, ++ reset_pmds, ++ max_pmd); ++ ++ bitmap_copy(set->pmds[cnum].smpl_pmds, ++ smpl_pmds, ++ max_pmd); ++ ++ set->pmds[cnum].eventid = eventid; ++ ++ /* ++ * update ovfl_notify ++ */ ++ if (rflags & PFM_REGFL_OVFL_NOTIFY) ++ __set_bit(cnum, set->ovfl_notify); ++ else ++ __clear_bit(cnum, set->ovfl_notify); ++ ++ } ++ PFM_DBG("pmd%u flags=0x%x eventid=0x%lx r_pmds=0x%lx s_pmds=0x%lx", ++ cnum, flags, ++ eventid, ++ reset_pmds[0], ++ smpl_pmds[0]); ++ ++ return 0; ++} ++ ++ ++int __pfm_write_ibrs_old(struct pfm_context *ctx, void *arg, int count) ++{ ++ struct pfarg_dbreg *req = arg; ++ struct pfarg_pmc pmc; ++ int i, ret = 0; ++ ++ memset(&pmc, 0, sizeof(pmc)); ++ ++ for (i = 0; i < count; i++, req++) { ++ pmc.reg_num = 256+req->dbreg_num; ++ pmc.reg_value = req->dbreg_value; ++ pmc.reg_flags = 0; ++ pmc.reg_set = req->dbreg_set; ++ ++ ret = __pfm_write_pmcs(ctx, &pmc, 1); ++ ++ req->dbreg_flags &= ~PFM_REG_RETFL_MASK; ++ req->dbreg_flags |= pmc.reg_flags; ++ ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static long pfm_write_ibrs_old(int fd, void __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct file *filp; ++ struct pfarg_dbreg *req = NULL; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret, fput_needed; ++ ++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*req); ++ ++ filp = fget_light(fd, &fput_needed); ++ if (unlikely(filp == NULL)) { ++ PFM_DBG("invalid fd %d", fd); ++ return -EBADF; ++ } ++ ++ ctx = filp->private_data; ++ ret = -EBADF; ++ ++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) { ++ PFM_DBG("fd %d not related to perfmon", fd); ++ goto error; ++ } ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (ret == 0) ++ ret = __pfm_write_ibrs_old(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ kfree(fptr); ++error: ++ fput_light(filp, fput_needed); ++ return ret; ++} ++ ++int __pfm_write_dbrs_old(struct pfm_context *ctx, void *arg, int count) ++{ ++ struct pfarg_dbreg *req = arg; ++ struct pfarg_pmc pmc; ++ int i, ret = 0; ++ ++ memset(&pmc, 0, sizeof(pmc)); ++ ++ for (i = 0; i < count; i++, req++) { ++ pmc.reg_num = 264+req->dbreg_num; ++ pmc.reg_value = req->dbreg_value; ++ pmc.reg_flags = 0; ++ pmc.reg_set = req->dbreg_set; ++ ++ ret = __pfm_write_pmcs(ctx, &pmc, 1); ++ ++ req->dbreg_flags &= ~PFM_REG_RETFL_MASK; ++ req->dbreg_flags |= pmc.reg_flags; ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static long pfm_write_dbrs_old(int fd, void __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct file *filp; ++ struct pfarg_dbreg *req = NULL; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret, fput_needed; ++ ++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*req); ++ ++ filp = fget_light(fd, &fput_needed); ++ if (unlikely(filp == NULL)) { ++ PFM_DBG("invalid fd %d", fd); ++ return -EBADF; ++ } ++ ++ ctx = filp->private_data; ++ ret = -EBADF; ++ ++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) { ++ PFM_DBG("fd %d not related to perfmon", fd); ++ goto error; ++ } ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (ret == 0) ++ ret = __pfm_write_dbrs_old(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ kfree(fptr); ++error: ++ fput_light(filp, fput_needed); ++ return ret; ++} ++ ++int __pfm_write_pmcs_old(struct pfm_context *ctx, struct pfarg_reg *req_old, ++ int count) ++{ ++ struct pfarg_pmc req; ++ unsigned int i; ++ int ret, error_code; ++ ++ memset(&req, 0, sizeof(req)); ++ ++ for (i = 0; i < count; i++, req_old++) { ++ req.reg_num = req_old->reg_num; ++ req.reg_set = req_old->reg_set; ++ req.reg_flags = 0; ++ req.reg_value = req_old->reg_value; ++ ++ ret = __pfm_write_pmcs(ctx, (void *)&req, 1); ++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK; ++ req_old->reg_flags |= req.reg_flags; ++ ++ if (ret) ++ return ret; ++ ++ ret = pfm_compat_update_pmd(ctx, req_old->reg_set, ++ req_old->reg_num, ++ (u32)req_old->reg_flags, ++ req_old->reg_smpl_pmds, ++ req_old->reg_reset_pmds, ++ req_old->reg_smpl_eventid); ++ ++ error_code = ret ? PFM_REG_RETFL_EINVAL : 0; ++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK; ++ req_old->reg_flags |= error_code; ++ ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static long pfm_write_pmcs_old(int fd, void __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct file *filp; ++ struct pfarg_reg *req = NULL; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret, fput_needed; ++ ++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*req); ++ ++ filp = fget_light(fd, &fput_needed); ++ if (unlikely(filp == NULL)) { ++ PFM_DBG("invalid fd %d", fd); ++ return -EBADF; ++ } ++ ++ ctx = filp->private_data; ++ ret = -EBADF; ++ ++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) { ++ PFM_DBG("fd %d not related to perfmon", fd); ++ goto error; ++ } ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (ret == 0) ++ ret = __pfm_write_pmcs_old(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ kfree(fptr); ++ ++error: ++ fput_light(filp, fput_needed); ++ return ret; ++} ++ ++int __pfm_write_pmds_old(struct pfm_context *ctx, struct pfarg_reg *req_old, ++ int count) ++{ ++ struct pfarg_pmd req; ++ int i, ret; ++ ++ memset(&req, 0, sizeof(req)); ++ ++ for (i = 0; i < count; i++, req_old++) { ++ req.reg_num = req_old->reg_num; ++ req.reg_set = req_old->reg_set; ++ req.reg_value = req_old->reg_value; ++ /* flags passed with pmcs in v2.0 */ ++ ++ req.reg_long_reset = req_old->reg_long_reset; ++ req.reg_short_reset = req_old->reg_short_reset; ++ req.reg_random_mask = req_old->reg_random_mask; ++ /* ++ * reg_random_seed is ignored since v2.3 ++ */ ++ ++ /* ++ * skip last_reset_val not used for writing ++ * skip smpl_pmds, reset_pmds, eventid, ovfl_swtch_cnt ++ * as set in pfm_write_pmcs_old. ++ * ++ * ovfl_switch_cnt ignored, not implemented in v2.0 ++ */ ++ ret = __pfm_write_pmds(ctx, (void *)&req, 1, 1); ++ ++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK; ++ req_old->reg_flags |= req.reg_flags; ++ ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static long pfm_write_pmds_old(int fd, void __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct file *filp; ++ struct pfarg_reg *req = NULL; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret, fput_needed; ++ ++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*req); ++ ++ filp = fget_light(fd, &fput_needed); ++ if (unlikely(filp == NULL)) { ++ PFM_DBG("invalid fd %d", fd); ++ return -EBADF; ++ } ++ ++ ctx = filp->private_data; ++ ret = -EBADF; ++ ++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) { ++ PFM_DBG("fd %d not related to perfmon", fd); ++ goto error; ++ } ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (ret == 0) ++ ret = __pfm_write_pmds_old(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ kfree(fptr); ++error: ++ fput_light(filp, fput_needed); ++ return ret; ++} ++ ++int __pfm_read_pmds_old(struct pfm_context *ctx, struct pfarg_reg *req_old, ++ int count) ++{ ++ struct pfarg_pmd req; ++ int i, ret; ++ ++ memset(&req, 0, sizeof(req)); ++ ++ for (i = 0; i < count; i++, req_old++) { ++ req.reg_num = req_old->reg_num; ++ req.reg_set = req_old->reg_set; ++ ++ /* skip value not used for reading */ ++ req.reg_flags = req_old->reg_flags; ++ ++ /* skip short/long_reset not used for reading */ ++ /* skip last_reset_val not used for reading */ ++ /* skip ovfl_switch_cnt not used for reading */ ++ ++ ret = __pfm_read_pmds(ctx, (void *)&req, 1); ++ ++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK; ++ req_old->reg_flags |= req.reg_flags; ++ if (ret) ++ return ret; ++ ++ /* update fields */ ++ req_old->reg_value = req.reg_value; ++ ++ req_old->reg_last_reset_val = req.reg_last_reset_val; ++ req_old->reg_ovfl_switch_cnt = req.reg_ovfl_switch_cnt; ++ } ++ return 0; ++} ++ ++static long pfm_read_pmds_old(int fd, void __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct file *filp; ++ struct pfarg_reg *req = NULL; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret, fput_needed; ++ ++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*req); ++ ++ filp = fget_light(fd, &fput_needed); ++ if (unlikely(filp == NULL)) { ++ PFM_DBG("invalid fd %d", fd); ++ return -EBADF; ++ } ++ ++ ctx = filp->private_data; ++ ret = -EBADF; ++ ++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) { ++ PFM_DBG("fd %d not related to perfmon", fd); ++ goto error; ++ } ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (ret == 0) ++ ret = __pfm_read_pmds_old(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ kfree(fptr); ++error: ++ fput_light(filp, fput_needed); ++ return ret; ++} ++ ++/* ++ * OBSOLETE: use /proc/perfmon_map instead ++ */ ++static long pfm_get_default_pmcs_old(int fd, void __user *ureq, int count) ++{ ++ struct pfarg_reg *req = NULL; ++ void *fptr; ++ size_t sz; ++ int ret, i; ++ unsigned int cnum; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ /* ++ * ensure the pfm_pmu_conf does not disappear while ++ * we use it ++ */ ++ ret = pfm_pmu_conf_get(1); ++ if (ret) ++ return ret; ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ ++ for (i = 0; i < count; i++, req++) { ++ cnum = req->reg_num; ++ ++ if (i >= PFM_MAX_PMCS || ++ (pfm_pmu_conf->pmc_desc[cnum].type & PFM_REG_I) == 0) { ++ req->reg_flags = PFM_REG_RETFL_EINVAL; ++ break; ++ } ++ req->reg_value = pfm_pmu_conf->pmc_desc[cnum].dfl_val; ++ req->reg_flags = 0; ++ ++ PFM_DBG("pmc[%u]=0x%lx", cnum, req->reg_value); ++ } ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ kfree(fptr); ++error: ++ pfm_pmu_conf_put(); ++ ++ return ret; ++} ++ ++/* ++ * allocate a sampling buffer and remaps it into the user address space of ++ * the task. This is only in compatibility mode ++ * ++ * function called ONLY on current task ++ */ ++int pfm_smpl_buf_alloc_compat(struct pfm_context *ctx, size_t rsize, ++ struct file *filp) ++{ ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma = NULL; ++ struct pfm_arch_context *ctx_arch; ++ size_t size; ++ int ret; ++ extern struct vm_operations_struct pfm_buf_map_vm_ops; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * allocate buffer + map desc ++ */ ++ ret = pfm_smpl_buf_alloc(ctx, rsize); ++ if (ret) ++ return ret; ++ ++ size = ctx->smpl_size; ++ ++ ++ /* allocate vma */ ++ vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); ++ if (!vma) { ++ PFM_DBG("Cannot allocate vma"); ++ goto error_kmem; ++ } ++ memset(vma, 0, sizeof(*vma)); ++ ++ /* ++ * partially initialize the vma for the sampling buffer ++ */ ++ vma->vm_mm = mm; ++ vma->vm_flags = VM_READ | VM_MAYREAD | VM_RESERVED; ++ vma->vm_page_prot = PAGE_READONLY; ++ vma->vm_ops = &pfm_buf_map_vm_ops; ++ vma->vm_file = filp; ++ vma->vm_private_data = ctx; ++ vma->vm_pgoff = 0; ++ ++ /* ++ * simulate effect of mmap() ++ */ ++ get_file(filp); ++ ++ /* ++ * Let's do the difficult operations next. ++ * ++ * now we atomically find some area in the address space and ++ * remap the buffer into it. ++ */ ++ down_write(¤t->mm->mmap_sem); ++ ++ /* find some free area in address space, must have mmap sem held */ ++ vma->vm_start = get_unmapped_area(NULL, 0, size, 0, ++ MAP_PRIVATE|MAP_ANONYMOUS); ++ if (vma->vm_start == 0) { ++ PFM_DBG("cannot find unmapped area of size %zu", size); ++ up_write(¤t->mm->mmap_sem); ++ goto error; ++ } ++ vma->vm_end = vma->vm_start + size; ++ ++ PFM_DBG("aligned_size=%zu mapped @0x%lx", size, vma->vm_start); ++ /* ++ * now insert the vma in the vm list for the process, must be ++ * done with mmap lock held ++ */ ++ insert_vm_struct(mm, vma); ++ ++ mm->total_vm += size >> PAGE_SHIFT; ++ ++ up_write(¤t->mm->mmap_sem); ++ ++ /* ++ * IMPORTANT: we do not issue the fput() ++ * because we want to increase the ref count ++ * on the descriptor to simulate what mmap() ++ * would do ++ */ ++ ++ /* ++ * used to propagate vaddr to syscall stub ++ */ ++ ctx_arch->ctx_smpl_vaddr = (void *)vma->vm_start; ++ ++ return 0; ++error: ++ kmem_cache_free(vm_area_cachep, vma); ++error_kmem: ++ pfm_smpl_buf_space_release(ctx, ctx->smpl_size); ++ vfree(ctx->smpl_addr); ++ return -ENOMEM; ++} ++ ++#define PFM_DEFAULT_SMPL_UUID { \ ++ 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82,\ ++ 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97} ++ ++static pfm_uuid_t old_default_uuid = PFM_DEFAULT_SMPL_UUID; ++static pfm_uuid_t null_uuid; ++ ++/* ++ * function invoked in case, pfm_context_create fails ++ * at the last operation, copy_to_user. It needs to ++ * undo memory allocations and free the file descriptor ++ */ ++static void pfm_undo_create_context_fd(int fd, struct pfm_context *ctx) ++{ ++ struct files_struct *files = current->files; ++ struct file *file; ++ int fput_needed; ++ ++ file = fget_light(fd, &fput_needed); ++ /* ++ * there is no fd_uninstall(), so we do it ++ * here. put_unused_fd() does not remove the ++ * effect of fd_install(). ++ */ ++ ++ spin_lock(&files->file_lock); ++ files->fd_array[fd] = NULL; ++ spin_unlock(&files->file_lock); ++ ++ fput_light(file, fput_needed); ++ ++ /* ++ * decrement ref count and kill file ++ */ ++ put_filp(file); ++ ++ put_unused_fd(fd); ++ ++ pfm_free_context(ctx); ++} ++ ++static int pfm_get_smpl_arg_old(pfm_uuid_t uuid, void __user *fmt_uarg, ++ size_t usize, void **arg, ++ struct pfm_smpl_fmt **fmt) ++{ ++ struct pfm_smpl_fmt *f; ++ void *addr = NULL; ++ size_t sz; ++ int ret; ++ ++ if (!memcmp(uuid, null_uuid, sizeof(pfm_uuid_t))) ++ return 0; ++ ++ if (memcmp(uuid, old_default_uuid, sizeof(pfm_uuid_t))) { ++ PFM_DBG("compatibility mode supports only default sampling format"); ++ return -EINVAL; ++ } ++ /* ++ * find fmt and increase refcount ++ */ ++ f = pfm_smpl_fmt_get("default-old"); ++ if (f == NULL) { ++ PFM_DBG("default-old buffer format not found"); ++ return -EINVAL; ++ } ++ ++ /* ++ * expected format argument size ++ */ ++ sz = f->fmt_arg_size; ++ ++ /* ++ * check user size matches expected size ++ * usize = -1 is for IA-64 backward compatibility ++ */ ++ ret = -EINVAL; ++ if (sz != usize && usize != -1) { ++ PFM_DBG("invalid arg size %zu, format expects %zu", ++ usize, sz); ++ goto error; ++ } ++ ++ ret = -ENOMEM; ++ addr = kmalloc(sz, GFP_KERNEL); ++ if (addr == NULL) ++ goto error; ++ ++ ret = -EFAULT; ++ if (copy_from_user(addr, fmt_uarg, sz)) ++ goto error; ++ ++ *arg = addr; ++ *fmt = f; ++ return 0; ++ ++error: ++ kfree(addr); ++ pfm_smpl_fmt_put(f); ++ return ret; ++} ++ ++static long pfm_create_context_old(int fd, void __user *ureq, int count) ++{ ++ struct pfm_context *new_ctx; ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_smpl_fmt *fmt = NULL; ++ struct pfarg_context req_old; ++ void __user *usmpl_arg; ++ void *smpl_arg = NULL; ++ struct pfarg_ctx req; ++ int ret; ++ ++ if (count != 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&req_old, ureq, sizeof(req_old))) ++ return -EFAULT; ++ ++ memset(&req, 0, sizeof(req)); ++ ++ /* ++ * sampling format args are following pfarg_context ++ */ ++ usmpl_arg = ureq+sizeof(req_old); ++ ++ ret = pfm_get_smpl_arg_old(req_old.ctx_smpl_buf_id, usmpl_arg, -1, ++ &smpl_arg, &fmt); ++ if (ret) ++ return ret; ++ ++ req.ctx_flags = req_old.ctx_flags; ++ ++ /* ++ * returns file descriptor if >=0, or error code */ ++ ret = __pfm_create_context(&req, fmt, smpl_arg, PFM_COMPAT, &new_ctx); ++ if (ret >= 0) { ++ ctx_arch = pfm_ctx_arch(new_ctx); ++ req_old.ctx_fd = ret; ++ req_old.ctx_smpl_vaddr = ctx_arch->ctx_smpl_vaddr; ++ } ++ ++ if (copy_to_user(ureq, &req_old, sizeof(req_old))) { ++ pfm_undo_create_context_fd(req_old.ctx_fd, new_ctx); ++ ret = -EFAULT; ++ } ++ ++ kfree(smpl_arg); ++ ++ return ret; ++} ++ ++/* ++ * obsolete call: use /proc/perfmon ++ */ ++static long pfm_get_features_old(int fd, void __user *arg, int count) ++{ ++ struct pfarg_features req; ++ int ret = 0; ++ ++ if (count != 1) ++ return -EINVAL; ++ ++ memset(&req, 0, sizeof(req)); ++ ++ req.ft_version = PFM_VERSION; ++ ++ if (copy_to_user(arg, &req, sizeof(req))) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ ++static long pfm_debug_old(int fd, void __user *arg, int count) ++{ ++ int m; ++ ++ if (count != 1) ++ return -EINVAL; ++ ++ if (get_user(m, (int __user *)arg)) ++ return -EFAULT; ++ ++ ++ pfm_controls.debug = m == 0 ? 0 : 1; ++ ++ PFM_INFO("debugging %s (timing reset)", ++ pfm_controls.debug ? "on" : "off"); ++ ++ if (m == 0) ++ for_each_online_cpu(m) { ++ memset(&per_cpu(pfm_stats, m), 0, ++ sizeof(struct pfm_stats)); ++ } ++ return 0; ++} ++ ++static long pfm_unload_context_old(int fd, void __user *arg, int count) ++{ ++ if (count) ++ return -EINVAL; ++ ++ return sys_pfm_unload_context(fd); ++} ++ ++static long pfm_restart_old(int fd, void __user *arg, int count) ++{ ++ if (count) ++ return -EINVAL; ++ ++ return sys_pfm_restart(fd); ++} ++ ++static long pfm_stop_old(int fd, void __user *arg, int count) ++{ ++ if (count) ++ return -EINVAL; ++ ++ return sys_pfm_stop(fd); ++} ++ ++static long pfm_start_old(int fd, void __user *arg, int count) ++{ ++ if (count > 1) ++ return -EINVAL; ++ ++ return sys_pfm_start(fd, arg); ++} ++ ++static long pfm_load_context_old(int fd, void __user *ureq, int count) ++{ ++ if (count != 1) ++ return -EINVAL; ++ ++ return sys_pfm_load_context(fd, ureq); ++} ++ ++/* ++ * perfmon command descriptions ++ */ ++struct pfm_cmd_desc { ++ long (*cmd_func)(int fd, void __user *arg, int count); ++}; ++ ++/* ++ * functions MUST be listed in the increasing order of ++ * their index (see permfon.h) ++ */ ++#define PFM_CMD(name) \ ++ { .cmd_func = name, \ ++ } ++#define PFM_CMD_NONE \ ++ { .cmd_func = NULL \ ++ } ++ ++static struct pfm_cmd_desc pfm_cmd_tab[] = { ++/* 0 */PFM_CMD_NONE, ++/* 1 */PFM_CMD(pfm_write_pmcs_old), ++/* 2 */PFM_CMD(pfm_write_pmds_old), ++/* 3 */PFM_CMD(pfm_read_pmds_old), ++/* 4 */PFM_CMD(pfm_stop_old), ++/* 5 */PFM_CMD(pfm_start_old), ++/* 6 */PFM_CMD_NONE, ++/* 7 */PFM_CMD_NONE, ++/* 8 */PFM_CMD(pfm_create_context_old), ++/* 9 */PFM_CMD_NONE, ++/* 10 */PFM_CMD(pfm_restart_old), ++/* 11 */PFM_CMD_NONE, ++/* 12 */PFM_CMD(pfm_get_features_old), ++/* 13 */PFM_CMD(pfm_debug_old), ++/* 14 */PFM_CMD_NONE, ++/* 15 */PFM_CMD(pfm_get_default_pmcs_old), ++/* 16 */PFM_CMD(pfm_load_context_old), ++/* 17 */PFM_CMD(pfm_unload_context_old), ++/* 18 */PFM_CMD_NONE, ++/* 19 */PFM_CMD_NONE, ++/* 20 */PFM_CMD_NONE, ++/* 21 */PFM_CMD_NONE, ++/* 22 */PFM_CMD_NONE, ++/* 23 */PFM_CMD_NONE, ++/* 24 */PFM_CMD_NONE, ++/* 25 */PFM_CMD_NONE, ++/* 26 */PFM_CMD_NONE, ++/* 27 */PFM_CMD_NONE, ++/* 28 */PFM_CMD_NONE, ++/* 29 */PFM_CMD_NONE, ++/* 30 */PFM_CMD_NONE, ++/* 31 */PFM_CMD_NONE, ++/* 32 */PFM_CMD(pfm_write_ibrs_old), ++/* 33 */PFM_CMD(pfm_write_dbrs_old), ++}; ++#define PFM_CMD_COUNT ARRAY_SIZE(pfm_cmd_tab) ++ ++/* ++ * system-call entry point (must return long) ++ */ ++asmlinkage long sys_perfmonctl(int fd, int cmd, void __user *arg, int count) ++{ ++ if (perfmon_disabled) ++ return -ENOSYS; ++ ++ if (unlikely(cmd < 0 || cmd >= PFM_CMD_COUNT ++ || pfm_cmd_tab[cmd].cmd_func == NULL)) { ++ PFM_DBG("invalid cmd=%d", cmd); ++ return -EINVAL; ++ } ++ return (long)pfm_cmd_tab[cmd].cmd_func(fd, arg, count); ++} ++ ++/* ++ * Called from pfm_read() for a perfmon v2.0 context. ++ * ++ * compatibility mode pfm_read() routine. We need a separate ++ * routine because the definition of the message has changed. ++ * The pfm_msg and pfarg_msg structures are different. ++ * ++ * return: sizeof(pfm_msg_t) on success, -errno otherwise ++ */ ++ssize_t pfm_arch_compat_read(struct pfm_context *ctx, ++ char __user *buf, ++ int non_block, ++ size_t size) ++{ ++ union pfarg_msg msg_buf; ++ pfm_msg_t old_msg_buf; ++ pfm_ovfl_msg_t *o_msg; ++ struct pfarg_ovfl_msg *n_msg; ++ int ret; ++ ++ PFM_DBG("msg=%p size=%zu", buf, size); ++ ++ /* ++ * cannot extract partial messages. ++ * check even when there is no message ++ * ++ * cannot extract more than one message per call. Bytes ++ * above sizeof(msg) are ignored. ++ */ ++ if (size < sizeof(old_msg_buf)) { ++ PFM_DBG("message is too small size=%zu must be >=%zu)", ++ size, ++ sizeof(old_msg_buf)); ++ return -EINVAL; ++ } ++ ++ ret = __pfm_read(ctx, &msg_buf, non_block); ++ if (ret < 1) ++ return ret; ++ ++ /* ++ * force return value to old message size ++ */ ++ ret = sizeof(old_msg_buf); ++ ++ o_msg = &old_msg_buf.pfm_ovfl_msg; ++ n_msg = &msg_buf.pfm_ovfl_msg; ++ ++ switch (msg_buf.type) { ++ case PFM_MSG_OVFL: ++ o_msg->msg_type = PFM_MSG_OVFL; ++ o_msg->msg_ctx_fd = 0; ++ o_msg->msg_active_set = n_msg->msg_active_set; ++ o_msg->msg_tstamp = 0; ++ ++ o_msg->msg_ovfl_pmds[0] = n_msg->msg_ovfl_pmds[0]; ++ o_msg->msg_ovfl_pmds[1] = n_msg->msg_ovfl_pmds[1]; ++ o_msg->msg_ovfl_pmds[2] = n_msg->msg_ovfl_pmds[2]; ++ o_msg->msg_ovfl_pmds[3] = n_msg->msg_ovfl_pmds[3]; ++ break; ++ case PFM_MSG_END: ++ o_msg->msg_type = PFM_MSG_END; ++ o_msg->msg_ctx_fd = 0; ++ o_msg->msg_tstamp = 0; ++ break; ++ default: ++ PFM_DBG("unknown msg type=%d", msg_buf.type); ++ } ++ if (copy_to_user(buf, &old_msg_buf, sizeof(old_msg_buf))) ++ ret = -EFAULT; ++ PFM_DBG_ovfl("ret=%d", ret); ++ return ret; ++} ++ ++/* ++ * legacy /proc/perfmon simplified interface (we only maintain the ++ * global information (no more per-cpu stats, use ++ * /sys/devices/system/cpu/cpuXX/perfmon ++ */ ++static struct proc_dir_entry *perfmon_proc; ++ ++static void *pfm_proc_start(struct seq_file *m, loff_t *pos) ++{ ++ if (*pos == 0) ++ return (void *)1; ++ ++ return NULL; ++} ++ ++static void *pfm_proc_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return pfm_proc_start(m, pos); ++} ++ ++static void pfm_proc_stop(struct seq_file *m, void *v) ++{ ++} ++ ++/* ++ * this is a simplified version of the legacy /proc/perfmon. ++ * We have retained ONLY the key information that tools are actually ++ * using ++ */ ++static void pfm_proc_show_header(struct seq_file *m) ++{ ++ char buf[128]; ++ ++ pfm_sysfs_res_show(buf, sizeof(buf), 3); ++ ++ seq_printf(m, "perfmon version : %u.%u\n", ++ PFM_VERSION_MAJ, PFM_VERSION_MIN); ++ ++ seq_printf(m, "model : %s", buf); ++} ++ ++static int pfm_proc_show(struct seq_file *m, void *v) ++{ ++ pfm_proc_show_header(m); ++ return 0; ++} ++ ++struct seq_operations pfm_proc_seq_ops = { ++ .start = pfm_proc_start, ++ .next = pfm_proc_next, ++ .stop = pfm_proc_stop, ++ .show = pfm_proc_show ++}; ++ ++static int pfm_proc_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &pfm_proc_seq_ops); ++} ++ ++ ++static struct file_operations pfm_proc_fops = { ++ .open = pfm_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++/* ++ * called from pfm_arch_init(), global initialization, called once ++ */ ++int __init pfm_ia64_compat_init(void) ++{ ++ /* ++ * create /proc/perfmon ++ */ ++ perfmon_proc = create_proc_entry("perfmon", S_IRUGO, NULL); ++ if (perfmon_proc == NULL) { ++ PFM_ERR("cannot create /proc entry, perfmon disabled"); ++ return -1; ++ } ++ perfmon_proc->proc_fops = &pfm_proc_fops; ++ return 0; ++} +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon_default_smpl.c +@@ -0,0 +1,273 @@ ++/* ++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file implements the old default sampling buffer format ++ * for the Linux/ia64 perfmon-2 subsystem. This is for backward ++ * compatibility only. use the new default format in perfmon/ ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef MODULE ++#define FMT_FLAGS 0 ++#else ++#define FMT_FLAGS PFM_FMTFL_IS_BUILTIN ++#endif ++ ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("perfmon old default sampling format"); ++MODULE_LICENSE("GPL"); ++ ++static int pfm_default_fmt_validate(u32 flags, u16 npmds, void *data) ++{ ++ struct pfm_default_smpl_arg *arg = data; ++ size_t min_buf_size; ++ ++ if (data == NULL) { ++ PFM_DBG("no argument passed"); ++ return -EINVAL; ++ } ++ ++ /* ++ * compute min buf size. All PMD are manipulated as 64bit entities ++ */ ++ min_buf_size = sizeof(struct pfm_default_smpl_hdr) ++ + (sizeof(struct pfm_default_smpl_entry) + (npmds*sizeof(u64))); ++ ++ PFM_DBG("validate flags=0x%x npmds=%u min_buf_size=%lu " ++ "buf_size=%lu CPU%d", flags, npmds, min_buf_size, ++ arg->buf_size, smp_processor_id()); ++ ++ /* ++ * must hold at least the buffer header + one minimally sized entry ++ */ ++ if (arg->buf_size < min_buf_size) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int pfm_default_fmt_get_size(unsigned int flags, void *data, ++ size_t *size) ++{ ++ struct pfm_default_smpl_arg *arg = data; ++ ++ /* ++ * size has been validated in default_validate ++ */ ++ *size = arg->buf_size; ++ ++ return 0; ++} ++ ++static int pfm_default_fmt_init(struct pfm_context *ctx, void *buf, ++ u32 flags, u16 npmds, void *data) ++{ ++ struct pfm_default_smpl_hdr *hdr; ++ struct pfm_default_smpl_arg *arg = data; ++ ++ hdr = buf; ++ ++ hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION; ++ hdr->hdr_buf_size = arg->buf_size; ++ hdr->hdr_cur_offs = sizeof(*hdr); ++ hdr->hdr_overflows = 0; ++ hdr->hdr_count = 0; ++ ++ PFM_DBG("buffer=%p buf_size=%lu hdr_size=%lu " ++ "hdr_version=%u cur_offs=%lu", ++ buf, ++ hdr->hdr_buf_size, ++ sizeof(*hdr), ++ hdr->hdr_version, ++ hdr->hdr_cur_offs); ++ ++ return 0; ++} ++ ++static int pfm_default_fmt_handler(struct pfm_context *ctx, ++ unsigned long ip, u64 tstamp, void *data) ++{ ++ struct pfm_default_smpl_hdr *hdr; ++ struct pfm_default_smpl_entry *ent; ++ void *cur, *last, *buf; ++ u64 *e; ++ size_t entry_size; ++ u16 npmds, i, ovfl_pmd; ++ struct pfm_ovfl_arg *arg; ++ ++ hdr = ctx->smpl_addr; ++ arg = &ctx->ovfl_arg; ++ ++ buf = hdr; ++ cur = buf+hdr->hdr_cur_offs; ++ last = buf+hdr->hdr_buf_size; ++ ovfl_pmd = arg->ovfl_pmd; ++ ++ /* ++ * precheck for sanity ++ */ ++ if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) ++ goto full; ++ ++ npmds = arg->num_smpl_pmds; ++ ++ ent = cur; ++ ++ prefetch(arg->smpl_pmds_values); ++ ++ entry_size = sizeof(*ent) + (npmds << 3); ++ ++ /* position for first pmd */ ++ e = (unsigned long *)(ent+1); ++ ++ hdr->hdr_count++; ++ ++ PFM_DBG_ovfl("count=%lu cur=%p last=%p free_bytes=%lu " ++ "ovfl_pmd=%d npmds=%u", ++ hdr->hdr_count, ++ cur, last, ++ last-cur, ++ ovfl_pmd, ++ npmds); ++ ++ /* ++ * current = task running at the time of the overflow. ++ * ++ * per-task mode: ++ * - this is ususally the task being monitored. ++ * Under certain conditions, it might be a different task ++ * ++ * system-wide: ++ * - this is not necessarily the task controlling the session ++ */ ++ ent->pid = current->pid; ++ ent->ovfl_pmd = ovfl_pmd; ++ ent->last_reset_val = arg->pmd_last_reset; ++ ++ /* ++ * where did the fault happen (includes slot number) ++ */ ++ ent->ip = ip; ++ ++ ent->tstamp = tstamp; ++ ent->cpu = smp_processor_id(); ++ ent->set = arg->active_set; ++ ent->tgid = current->tgid; ++ ++ /* ++ * selectively store PMDs in increasing index number ++ */ ++ if (npmds) { ++ u64 *val = arg->smpl_pmds_values; ++ for (i = 0; i < npmds; i++) ++ *e++ = *val++; ++ } ++ ++ /* ++ * update position for next entry ++ */ ++ hdr->hdr_cur_offs += entry_size; ++ cur += entry_size; ++ ++ /* ++ * post check to avoid losing the last sample ++ */ ++ if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) ++ goto full; ++ ++ /* ++ * reset before returning from interrupt handler ++ */ ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET; ++ return 0; ++full: ++ PFM_DBG_ovfl("smpl buffer full free=%lu, count=%lu", ++ last-cur, hdr->hdr_count); ++ ++ /* ++ * increment number of buffer overflow. ++ * important to detect duplicate set of samples. ++ */ ++ hdr->hdr_overflows++; ++ ++ /* ++ * request notification and masking of monitoring. ++ * Notification is still subject to the overflowed ++ */ ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_NOTIFY | PFM_OVFL_CTRL_MASK; ++ ++ return -ENOBUFS; /* we are full, sorry */ ++} ++ ++static int pfm_default_fmt_restart(int is_active, u32 *ovfl_ctrl, void *buf) ++{ ++ struct pfm_default_smpl_hdr *hdr; ++ ++ hdr = buf; ++ ++ hdr->hdr_count = 0; ++ hdr->hdr_cur_offs = sizeof(*hdr); ++ ++ *ovfl_ctrl = PFM_OVFL_CTRL_RESET; ++ ++ return 0; ++} ++ ++static int pfm_default_fmt_exit(void *buf) ++{ ++ return 0; ++} ++ ++static struct pfm_smpl_fmt default_fmt = { ++ .fmt_name = "default-old", ++ .fmt_version = 0x10000, ++ .fmt_arg_size = sizeof(struct pfm_default_smpl_arg), ++ .fmt_validate = pfm_default_fmt_validate, ++ .fmt_getsize = pfm_default_fmt_get_size, ++ .fmt_init = pfm_default_fmt_init, ++ .fmt_handler = pfm_default_fmt_handler, ++ .fmt_restart = pfm_default_fmt_restart, ++ .fmt_exit = pfm_default_fmt_exit, ++ .fmt_flags = FMT_FLAGS, ++ .owner = THIS_MODULE ++}; ++ ++static int pfm_default_fmt_init_module(void) ++{ ++ int ret; ++ ++ return pfm_fmt_register(&default_fmt); ++ return ret; ++} ++ ++static void pfm_default_fmt_cleanup_module(void) ++{ ++ pfm_fmt_unregister(&default_fmt); ++} ++ ++module_init(pfm_default_fmt_init_module); ++module_exit(pfm_default_fmt_cleanup_module); +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon_generic.c +@@ -0,0 +1,148 @@ ++/* ++ * This file contains the generic PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. ++ * contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Generic IA-64 PMU description tables"); ++MODULE_LICENSE("GPL"); ++ ++#define RDEP(x) (1UL << (x)) ++ ++#define PFM_IA64GEN_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)) ++#define PFM_IA64GEN_RSVD (0xffffffffffff0080UL) ++#define PFM_IA64GEN_NO64 (1UL<<5) ++ ++/* forward declaration */ ++static struct pfm_pmu_config pfm_ia64gen_pmu_conf; ++ ++static struct pfm_arch_pmu_info pfm_ia64gen_pmu_info = { ++ .mask_pmcs = {PFM_IA64GEN_MASK_PMCS,}, ++}; ++ ++static struct pfm_regmap_desc pfm_ia64gen_pmc_desc[] = { ++/* pmc0 */ PMX_NA, ++/* pmc1 */ PMX_NA, ++/* pmc2 */ PMX_NA, ++/* pmc3 */ PMX_NA, ++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 4), ++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 5), ++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 6), ++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 7) ++}; ++#define PFM_IA64GEN_NUM_PMCS ARRAY_SIZE(pfm_ia64gen_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_ia64gen_pmd_desc[] = { ++/* pmd0 */ PMX_NA, ++/* pmd1 */ PMX_NA, ++/* pmd2 */ PMX_NA, ++/* pmd3 */ PMX_NA, ++/* pmd4 */ PMD_DP(PFM_REG_C, "PMD4", 4, 1ull << 4), ++/* pmd5 */ PMD_DP(PFM_REG_C, "PMD5", 5, 1ull << 5), ++/* pmd6 */ PMD_DP(PFM_REG_C, "PMD6", 6, 1ull << 6), ++/* pmd7 */ PMD_DP(PFM_REG_C, "PMD7", 7, 1ull << 7) ++}; ++#define PFM_IA64GEN_NUM_PMDS ARRAY_SIZE(pfm_ia64gen_pmd_desc) ++ ++static int pfm_ia64gen_pmc_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++#define PFM_IA64GEN_PMC_PM_POS6 (1UL<<6) ++ u64 tmpval; ++ int is_system; ++ ++ is_system = ctx->flags.system; ++ tmpval = req->reg_value; ++ ++ switch (req->reg_num) { ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ /* set pmc.oi for 64-bit emulation */ ++ tmpval |= 1UL << 5; ++ ++ if (is_system) ++ tmpval |= PFM_IA64GEN_PMC_PM_POS6; ++ else ++ tmpval &= ~PFM_IA64GEN_PMC_PM_POS6; ++ break; ++ ++ } ++ req->reg_value = tmpval; ++ ++ return 0; ++} ++ ++/* ++ * matches anything ++ */ ++static int pfm_ia64gen_probe_pmu(void) ++{ ++ u64 pm_buffer[16]; ++ pal_perf_mon_info_u_t pm_info; ++ ++ /* ++ * call PAL_PERFMON_INFO to retrieve counter width which ++ * is implementation specific ++ */ ++ if (ia64_pal_perf_mon_info(pm_buffer, &pm_info)) ++ return -1; ++ ++ pfm_ia64gen_pmu_conf.counter_width = pm_info.pal_perf_mon_info_s.width; ++ ++ return 0; ++} ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_ia64gen_pmu_conf = { ++ .pmu_name = "Generic IA-64", ++ .counter_width = 0, /* computed from PAL_PERFMON_INFO */ ++ .pmd_desc = pfm_ia64gen_pmd_desc, ++ .pmc_desc = pfm_ia64gen_pmc_desc, ++ .probe_pmu = pfm_ia64gen_probe_pmu, ++ .num_pmc_entries = PFM_IA64GEN_NUM_PMCS, ++ .num_pmd_entries = PFM_IA64GEN_NUM_PMDS, ++ .pmc_write_check = pfm_ia64gen_pmc_check, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_ia64gen_pmu_info ++ /* no read/write checkers */ ++}; ++ ++static int __init pfm_gen_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_ia64gen_pmu_conf); ++} ++ ++static void __exit pfm_gen_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_ia64gen_pmu_conf); ++} ++ ++module_init(pfm_gen_pmu_init_module); ++module_exit(pfm_gen_pmu_cleanup_module); +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon_itanium.c +@@ -0,0 +1,232 @@ ++/* ++ * This file contains the Itanium PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Itanium (Merced) PMU description tables"); ++MODULE_LICENSE("GPL"); ++ ++#define RDEP(x) (1ULL << (x)) ++ ++#define PFM_ITA_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)|RDEP(10)|RDEP(11)|\ ++ RDEP(12)) ++ ++#define PFM_ITA_NO64 (1ULL<<5) ++ ++static struct pfm_arch_pmu_info pfm_ita_pmu_info = { ++ .mask_pmcs = {PFM_ITA_MASK_PMCS,}, ++}; ++/* reserved bits are 1 in the mask */ ++#define PFM_ITA_RSVD 0xfffffffffc8000a0UL ++/* ++ * For debug registers, writing xBR(y) means we use also xBR(y+1). Hence using ++ * PMC256+y means we use PMC256+y+1. Yet, we do not have dependency information ++ * but this is fine because they are handled separately in the IA-64 specific ++ * code. ++ */ ++static struct pfm_regmap_desc pfm_ita_pmc_desc[] = { ++/* pmc0 */ PMX_NA, ++/* pmc1 */ PMX_NA, ++/* pmc2 */ PMX_NA, ++/* pmc3 */ PMX_NA, ++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 4), ++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 5), ++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 6), ++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 7), ++/* pmc8 */ PMC_D(PFM_REG_W , "PMC8" , 0xfffffffe3ffffff8UL, 0xfff00000001c0000UL, 0, 8), ++/* pmc9 */ PMC_D(PFM_REG_W , "PMC9" , 0xfffffffe3ffffff8UL, 0xfff00000001c0000UL, 0, 9), ++/* pmc10 */ PMC_D(PFM_REG_W , "PMC10", 0x0, 0xfffffffff3f0ff30UL, 0, 10), ++/* pmc11 */ PMC_D(PFM_REG_W , "PMC11", 0x10000000UL, 0xffffffffecf0ff30UL, 0, 11), ++/* pmc12 */ PMC_D(PFM_REG_W , "PMC12", 0x0, 0xffffffffffff0030UL, 0, 12), ++/* pmc13 */ PMC_D(PFM_REG_W , "PMC13", 0x3ffff00000001UL, 0xfffffffffffffffeUL, 0, 13), ++/* pmc14 */ PMX_NA, ++/* pmc15 */ PMX_NA, ++/* pmc16 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc24 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc32 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc40 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc48 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc56 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc64 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc72 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc80 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc88 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc96 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc104 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc112 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc120 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc128 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc136 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc144 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc152 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc160 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc168 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc176 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc184 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc192 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc200 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc208 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc216 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc224 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc232 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc240 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc248 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc256 */ PMC_D(PFM_REG_W , "IBR0", 0x0, 0, 0, 0), ++/* pmc257 */ PMC_D(PFM_REG_W , "IBR1", 0x0, 0x8000000000000000UL, 0, 1), ++/* pmc258 */ PMC_D(PFM_REG_W , "IBR2", 0x0, 0, 0, 2), ++/* pmc259 */ PMC_D(PFM_REG_W , "IBR3", 0x0, 0x8000000000000000UL, 0, 3), ++/* pmc260 */ PMC_D(PFM_REG_W , "IBR4", 0x0, 0, 0, 4), ++/* pmc261 */ PMC_D(PFM_REG_W , "IBR5", 0x0, 0x8000000000000000UL, 0, 5), ++/* pmc262 */ PMC_D(PFM_REG_W , "IBR6", 0x0, 0, 0, 6), ++/* pmc263 */ PMC_D(PFM_REG_W , "IBR7", 0x0, 0x8000000000000000UL, 0, 7), ++/* pmc264 */ PMC_D(PFM_REG_W , "DBR0", 0x0, 0, 0, 0), ++/* pmc265 */ PMC_D(PFM_REG_W , "DBR1", 0x0, 0xc000000000000000UL, 0, 1), ++/* pmc266 */ PMC_D(PFM_REG_W , "DBR2", 0x0, 0, 0, 2), ++/* pmc267 */ PMC_D(PFM_REG_W , "DBR3", 0x0, 0xc000000000000000UL, 0, 3), ++/* pmc268 */ PMC_D(PFM_REG_W , "DBR4", 0x0, 0, 0, 4), ++/* pmc269 */ PMC_D(PFM_REG_W , "DBR5", 0x0, 0xc000000000000000UL, 0, 5), ++/* pmc270 */ PMC_D(PFM_REG_W , "DBR6", 0x0, 0, 0, 6), ++/* pmc271 */ PMC_D(PFM_REG_W , "DBR7", 0x0, 0xc000000000000000UL, 0, 7) ++}; ++#define PFM_ITA_NUM_PMCS ARRAY_SIZE(pfm_ita_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_ita_pmd_desc[] = { ++/* pmd0 */ PMD_DP(PFM_REG_I , "PMD0", 0, 1ull << 10), ++/* pmd1 */ PMD_DP(PFM_REG_I , "PMD1", 1, 1ull << 10), ++/* pmd2 */ PMD_DP(PFM_REG_I , "PMD2", 2, 1ull << 11), ++/* pmd3 */ PMD_DP(PFM_REG_I , "PMD3", 3, 1ull << 11), ++/* pmd4 */ PMD_DP(PFM_REG_C , "PMD4", 4, 1ull << 4), ++/* pmd5 */ PMD_DP(PFM_REG_C , "PMD5", 5, 1ull << 5), ++/* pmd6 */ PMD_DP(PFM_REG_C , "PMD6", 6, 1ull << 6), ++/* pmd7 */ PMD_DP(PFM_REG_C , "PMD7", 7, 1ull << 7), ++/* pmd8 */ PMD_DP(PFM_REG_I , "PMD8", 8, 1ull << 12), ++/* pmd9 */ PMD_DP(PFM_REG_I , "PMD9", 9, 1ull << 12), ++/* pmd10 */ PMD_DP(PFM_REG_I , "PMD10", 10, 1ull << 12), ++/* pmd11 */ PMD_DP(PFM_REG_I , "PMD11", 11, 1ull << 12), ++/* pmd12 */ PMD_DP(PFM_REG_I , "PMD12", 12, 1ull << 12), ++/* pmd13 */ PMD_DP(PFM_REG_I , "PMD13", 13, 1ull << 12), ++/* pmd14 */ PMD_DP(PFM_REG_I , "PMD14", 14, 1ull << 12), ++/* pmd15 */ PMD_DP(PFM_REG_I , "PMD15", 15, 1ull << 12), ++/* pmd16 */ PMD_DP(PFM_REG_I , "PMD16", 16, 1ull << 12), ++/* pmd17 */ PMD_DP(PFM_REG_I , "PMD17", 17, 1ull << 11) ++}; ++#define PFM_ITA_NUM_PMDS ARRAY_SIZE(pfm_ita_pmd_desc) ++ ++static int pfm_ita_pmc_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++#define PFM_ITA_PMC_PM_POS6 (1UL<<6) ++ struct pfm_arch_context *ctx_arch; ++ u64 tmpval; ++ u16 cnum; ++ int ret = 0, is_system; ++ ++ tmpval = req->reg_value; ++ cnum = req->reg_num; ++ ctx_arch = pfm_ctx_arch(ctx); ++ is_system = ctx->flags.system; ++ ++ switch (cnum) { ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 10: ++ case 11: ++ case 12: ++ if (is_system) ++ tmpval |= PFM_ITA_PMC_PM_POS6; ++ else ++ tmpval &= ~PFM_ITA_PMC_PM_POS6; ++ break; ++ } ++ ++ /* ++ * we must clear the (instruction) debug registers if pmc13.ta bit is ++ * cleared before they are written (fl_using_dbreg==0) to avoid ++ * picking up stale information. ++ */ ++ if (cnum == 13 && ((tmpval & 0x1) == 0) ++ && ctx_arch->flags.use_dbr == 0) { ++ PFM_DBG("pmc13 has pmc13.ta cleared, clearing ibr"); ++ ret = pfm_ia64_mark_dbregs_used(ctx, set); ++ if (ret) ++ return ret; ++ } ++ ++ /* ++ * we must clear the (data) debug registers if pmc11.pt bit is cleared ++ * before they are written (fl_using_dbreg==0) to avoid picking up ++ * stale information. ++ */ ++ if (cnum == 11 && ((tmpval >> 28) & 0x1) == 0 ++ && ctx_arch->flags.use_dbr == 0) { ++ PFM_DBG("pmc11 has pmc11.pt cleared, clearing dbr"); ++ ret = pfm_ia64_mark_dbregs_used(ctx, set); ++ if (ret) ++ return ret; ++ } ++ ++ req->reg_value = tmpval; ++ ++ return 0; ++} ++ ++static int pfm_ita_probe_pmu(void) ++{ ++ return local_cpu_data->family == 0x7 && !ia64_platform_is("hpsim") ++ ? 0 : -1; ++} ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_ita_pmu_conf = { ++ .pmu_name = "Itanium", ++ .counter_width = 32, ++ .pmd_desc = pfm_ita_pmd_desc, ++ .pmc_desc = pfm_ita_pmc_desc, ++ .pmc_write_check = pfm_ita_pmc_check, ++ .num_pmc_entries = PFM_ITA_NUM_PMCS, ++ .num_pmd_entries = PFM_ITA_NUM_PMDS, ++ .probe_pmu = pfm_ita_probe_pmu, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_ita_pmu_info ++}; ++ ++static int __init pfm_ita_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_ita_pmu_conf); ++} ++ ++static void __exit pfm_ita_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_ita_pmu_conf); ++} ++ ++module_init(pfm_ita_pmu_init_module); ++module_exit(pfm_ita_pmu_cleanup_module); ++ +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon_mckinley.c +@@ -0,0 +1,290 @@ ++/* ++ * This file contains the McKinley PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Itanium 2 (McKinley) PMU description tables"); ++MODULE_LICENSE("GPL"); ++ ++#define RDEP(x) (1UL << (x)) ++ ++#define PFM_MCK_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)|RDEP(10)|RDEP(11)|\ ++ RDEP(12)) ++ ++#define PFM_MCK_NO64 (1UL<<5) ++ ++static struct pfm_arch_pmu_info pfm_mck_pmu_info = { ++ .mask_pmcs = {PFM_MCK_MASK_PMCS,}, ++}; ++ ++/* reserved bits are 1 in the mask */ ++#define PFM_ITA2_RSVD 0xfffffffffc8000a0UL ++ ++/* ++ * For debug registers, writing xBR(y) means we use also xBR(y+1). Hence using ++ * PMC256+y means we use PMC256+y+1. Yet, we do not have dependency information ++ * but this is fine because they are handled separately in the IA-64 specific ++ * code. ++ */ ++static struct pfm_regmap_desc pfm_mck_pmc_desc[] = { ++/* pmc0 */ PMX_NA, ++/* pmc1 */ PMX_NA, ++/* pmc2 */ PMX_NA, ++/* pmc3 */ PMX_NA, ++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4" , 0x800020UL, 0xfffffffffc8000a0, PFM_MCK_NO64, 4), ++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5" , 0x20UL, PFM_ITA2_RSVD, PFM_MCK_NO64, 5), ++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6" , 0x20UL, PFM_ITA2_RSVD, PFM_MCK_NO64, 6), ++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7" , 0x20UL, PFM_ITA2_RSVD, PFM_MCK_NO64, 7), ++/* pmc8 */ PMC_D(PFM_REG_W , "PMC8" , 0xffffffff3fffffffUL, 0xc0000004UL, 0, 8), ++/* pmc9 */ PMC_D(PFM_REG_W , "PMC9" , 0xffffffff3ffffffcUL, 0xc0000004UL, 0, 9), ++/* pmc10 */ PMC_D(PFM_REG_W , "PMC10", 0x0, 0xffffffffffff0000UL, 0, 10), ++/* pmc11 */ PMC_D(PFM_REG_W , "PMC11", 0x0, 0xfffffffffcf0fe30UL, 0, 11), ++/* pmc12 */ PMC_D(PFM_REG_W , "PMC12", 0x0, 0xffffffffffff0000UL, 0, 12), ++/* pmc13 */ PMC_D(PFM_REG_W , "PMC13", 0x2078fefefefeUL, 0xfffe1fffe7e7e7e7UL, 0, 13), ++/* pmc14 */ PMC_D(PFM_REG_W , "PMC14", 0x0db60db60db60db6UL, 0xffffffffffffdb6dUL, 0, 14), ++/* pmc15 */ PMC_D(PFM_REG_W , "PMC15", 0xfffffff0UL, 0xfffffffffffffff0UL, 0, 15), ++/* pmc16 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc24 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc32 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc40 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc48 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc56 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc64 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc72 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc80 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc88 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc96 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc104 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc112 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc120 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc128 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc136 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc144 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc152 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc160 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc168 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc176 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc184 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc192 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc200 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc208 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc216 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc224 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc232 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc240 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc248 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc256 */ PMC_D(PFM_REG_W , "IBR0", 0x0, 0, 0, 0), ++/* pmc257 */ PMC_D(PFM_REG_W , "IBR1", 0x0, 0x8000000000000000UL, 0, 1), ++/* pmc258 */ PMC_D(PFM_REG_W , "IBR2", 0x0, 0, 0, 2), ++/* pmc259 */ PMC_D(PFM_REG_W , "IBR3", 0x0, 0x8000000000000000UL, 0, 3), ++/* pmc260 */ PMC_D(PFM_REG_W , "IBR4", 0x0, 0, 0, 4), ++/* pmc261 */ PMC_D(PFM_REG_W , "IBR5", 0x0, 0x8000000000000000UL, 0, 5), ++/* pmc262 */ PMC_D(PFM_REG_W , "IBR6", 0x0, 0, 0, 6), ++/* pmc263 */ PMC_D(PFM_REG_W , "IBR7", 0x0, 0x8000000000000000UL, 0, 7), ++/* pmc264 */ PMC_D(PFM_REG_W , "DBR0", 0x0, 0, 0, 0), ++/* pmc265 */ PMC_D(PFM_REG_W , "DBR1", 0x0, 0xc000000000000000UL, 0, 1), ++/* pmc266 */ PMC_D(PFM_REG_W , "DBR2", 0x0, 0, 0, 2), ++/* pmc267 */ PMC_D(PFM_REG_W , "DBR3", 0x0, 0xc000000000000000UL, 0, 3), ++/* pmc268 */ PMC_D(PFM_REG_W , "DBR4", 0x0, 0, 0, 4), ++/* pmc269 */ PMC_D(PFM_REG_W , "DBR5", 0x0, 0xc000000000000000UL, 0, 5), ++/* pmc270 */ PMC_D(PFM_REG_W , "DBR6", 0x0, 0, 0, 6), ++/* pmc271 */ PMC_D(PFM_REG_W , "DBR7", 0x0, 0xc000000000000000UL, 0, 7) ++}; ++#define PFM_MCK_NUM_PMCS ARRAY_SIZE(pfm_mck_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_mck_pmd_desc[] = { ++/* pmd0 */ PMD_DP(PFM_REG_I, "PMD0", 0, 1ull << 10), ++/* pmd1 */ PMD_DP(PFM_REG_I, "PMD1", 1, 1ull << 10), ++/* pmd2 */ PMD_DP(PFM_REG_I, "PMD2", 2, 1ull << 11), ++/* pmd3 */ PMD_DP(PFM_REG_I, "PMD3", 3, 1ull << 11), ++/* pmd4 */ PMD_DP(PFM_REG_C, "PMD4", 4, 1ull << 4), ++/* pmd5 */ PMD_DP(PFM_REG_C, "PMD5", 5, 1ull << 5), ++/* pmd6 */ PMD_DP(PFM_REG_C, "PMD6", 6, 1ull << 6), ++/* pmd7 */ PMD_DP(PFM_REG_C, "PMD7", 7, 1ull << 7), ++/* pmd8 */ PMD_DP(PFM_REG_I, "PMD8", 8, 1ull << 12), ++/* pmd9 */ PMD_DP(PFM_REG_I, "PMD9", 9, 1ull << 12), ++/* pmd10 */ PMD_DP(PFM_REG_I, "PMD10", 10, 1ull << 12), ++/* pmd11 */ PMD_DP(PFM_REG_I, "PMD11", 11, 1ull << 12), ++/* pmd12 */ PMD_DP(PFM_REG_I, "PMD12", 12, 1ull << 12), ++/* pmd13 */ PMD_DP(PFM_REG_I, "PMD13", 13, 1ull << 12), ++/* pmd14 */ PMD_DP(PFM_REG_I, "PMD14", 14, 1ull << 12), ++/* pmd15 */ PMD_DP(PFM_REG_I, "PMD15", 15, 1ull << 12), ++/* pmd16 */ PMD_DP(PFM_REG_I, "PMD16", 16, 1ull << 12), ++/* pmd17 */ PMD_DP(PFM_REG_I, "PMD17", 17, 1ull << 11) ++}; ++#define PFM_MCK_NUM_PMDS ARRAY_SIZE(pfm_mck_pmd_desc) ++ ++static int pfm_mck_pmc_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++ struct pfm_arch_context *ctx_arch; ++ u64 val8 = 0, val14 = 0, val13 = 0; ++ u64 tmpval; ++ u16 cnum; ++ int ret = 0, check_case1 = 0; ++ int is_system; ++ ++ tmpval = req->reg_value; ++ cnum = req->reg_num; ++ ctx_arch = pfm_ctx_arch(ctx); ++ is_system = ctx->flags.system; ++ ++#define PFM_MCK_PMC_PM_POS6 (1UL<<6) ++#define PFM_MCK_PMC_PM_POS4 (1UL<<4) ++ ++ switch (cnum) { ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 11: ++ case 12: ++ if (is_system) ++ tmpval |= PFM_MCK_PMC_PM_POS6; ++ else ++ tmpval &= ~PFM_MCK_PMC_PM_POS6; ++ break; ++ ++ case 8: ++ val8 = tmpval; ++ val13 = set->pmcs[13]; ++ val14 = set->pmcs[14]; ++ check_case1 = 1; ++ break; ++ ++ case 10: ++ if (is_system) ++ tmpval |= PFM_MCK_PMC_PM_POS4; ++ else ++ tmpval &= ~PFM_MCK_PMC_PM_POS4; ++ break; ++ ++ case 13: ++ val8 = set->pmcs[8]; ++ val13 = tmpval; ++ val14 = set->pmcs[14]; ++ check_case1 = 1; ++ break; ++ ++ case 14: ++ val8 = set->pmcs[8]; ++ val13 = set->pmcs[13]; ++ val14 = tmpval; ++ check_case1 = 1; ++ break; ++ } ++ ++ /* ++ * check illegal configuration which can produce inconsistencies ++ * in tagging i-side events in L1D and L2 caches ++ */ ++ if (check_case1) { ++ ret = (((val13 >> 45) & 0xf) == 0 && ((val8 & 0x1) == 0)) ++ && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0) ++ || (((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0)); ++ ++ if (ret) { ++ PFM_DBG("perfmon: invalid config pmc8=0x%lx " ++ "pmc13=0x%lx pmc14=0x%lx", ++ val8, val13, val14); ++ return -EINVAL; ++ } ++ } ++ ++ /* ++ * check if configuration implicitely activates the use of ++ * the debug registers. If true, then we ensure that this is ++ * possible and that we do not pick up stale value in the HW ++ * registers. ++ * ++ * We postpone the checks of pmc13 and pmc14 to avoid side effects ++ * in case of errors ++ */ ++ ++ /* ++ * pmc13 is "active" if: ++ * one of the pmc13.cfg_dbrpXX field is different from 0x3 ++ * AND ++ * at the corresponding pmc13.ena_dbrpXX is set. ++ */ ++ if (cnum == 13 && (tmpval & 0x1e00000000000UL) ++ && (tmpval & 0x18181818UL) != 0x18181818UL ++ && ctx_arch->flags.use_dbr == 0) { ++ PFM_DBG("pmc13=0x%lx active", tmpval); ++ ret = pfm_ia64_mark_dbregs_used(ctx, set); ++ if (ret) ++ return ret; ++ } ++ ++ /* ++ * if any pmc14.ibrpX bit is enabled we must clear the ibrs ++ */ ++ if (cnum == 14 && ((tmpval & 0x2222UL) != 0x2222UL) ++ && ctx_arch->flags.use_dbr == 0) { ++ PFM_DBG("pmc14=0x%lx active", tmpval); ++ ret = pfm_ia64_mark_dbregs_used(ctx, set); ++ if (ret) ++ return ret; ++ } ++ ++ req->reg_value = tmpval; ++ ++ return 0; ++} ++ ++static int pfm_mck_probe_pmu(void) ++{ ++ return local_cpu_data->family == 0x1f ? 0 : -1; ++} ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_mck_pmu_conf = { ++ .pmu_name = "Itanium 2", ++ .counter_width = 47, ++ .pmd_desc = pfm_mck_pmd_desc, ++ .pmc_desc = pfm_mck_pmc_desc, ++ .pmc_write_check = pfm_mck_pmc_check, ++ .num_pmc_entries = PFM_MCK_NUM_PMCS, ++ .num_pmd_entries = PFM_MCK_NUM_PMDS, ++ .probe_pmu = pfm_mck_probe_pmu, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_mck_pmu_info, ++}; ++ ++static int __init pfm_mck_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_mck_pmu_conf); ++} ++ ++static void __exit pfm_mck_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_mck_pmu_conf); ++} ++ ++module_init(pfm_mck_pmu_init_module); ++module_exit(pfm_mck_pmu_cleanup_module); +--- /dev/null ++++ b/arch/ia64/perfmon/perfmon_montecito.c +@@ -0,0 +1,412 @@ ++/* ++ * This file contains the McKinley PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Dual-Core Itanium 2 (Montecito) PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++#define RDEP(x) (1UL << (x)) ++ ++#define PFM_MONT_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)|\ ++ RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|\ ++ RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|\ ++ RDEP(37)|RDEP(39)|RDEP(40)|RDEP(42)) ++ ++#define PFM_MONT_NO64 (1UL<<5) ++ ++static struct pfm_arch_pmu_info pfm_mont_pmu_info = { ++ .mask_pmcs = {PFM_MONT_MASK_PMCS,}, ++}; ++ ++#define PFM_MONT_RSVD 0xffffffff838000a0UL ++/* ++ * ++ * For debug registers, writing xBR(y) means we use also xBR(y+1). Hence using ++ * PMC256+y means we use PMC256+y+1. Yet, we do not have dependency information ++ * but this is fine because they are handled separately in the IA-64 specific ++ * code. ++ * ++ * For PMC4-PMC15, PMC40: we force pmc.ism=2 (IA-64 mode only) ++ */ ++static struct pfm_regmap_desc pfm_mont_pmc_desc[] = { ++/* pmc0 */ PMX_NA, ++/* pmc1 */ PMX_NA, ++/* pmc2 */ PMX_NA, ++/* pmc3 */ PMX_NA, ++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 4), ++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 5), ++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 6), ++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 7), ++/* pmc8 */ PMC_D(PFM_REG_W64, "PMC8" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 8), ++/* pmc9 */ PMC_D(PFM_REG_W64, "PMC9" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 9), ++/* pmc10 */ PMC_D(PFM_REG_W64, "PMC10", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 10), ++/* pmc11 */ PMC_D(PFM_REG_W64, "PMC11", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 11), ++/* pmc12 */ PMC_D(PFM_REG_W64, "PMC12", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 12), ++/* pmc13 */ PMC_D(PFM_REG_W64, "PMC13", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 13), ++/* pmc14 */ PMC_D(PFM_REG_W64, "PMC14", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 14), ++/* pmc15 */ PMC_D(PFM_REG_W64, "PMC15", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 15), ++/* pmc16 */ PMX_NA, ++/* pmc17 */ PMX_NA, ++/* pmc18 */ PMX_NA, ++/* pmc19 */ PMX_NA, ++/* pmc20 */ PMX_NA, ++/* pmc21 */ PMX_NA, ++/* pmc22 */ PMX_NA, ++/* pmc23 */ PMX_NA, ++/* pmc24 */ PMX_NA, ++/* pmc25 */ PMX_NA, ++/* pmc26 */ PMX_NA, ++/* pmc27 */ PMX_NA, ++/* pmc28 */ PMX_NA, ++/* pmc29 */ PMX_NA, ++/* pmc30 */ PMX_NA, ++/* pmc31 */ PMX_NA, ++/* pmc32 */ PMC_D(PFM_REG_W , "PMC32", 0x30f01ffffffffffUL, 0xfcf0fe0000000000UL, 0, 32), ++/* pmc33 */ PMC_D(PFM_REG_W , "PMC33", 0x0, 0xfffffe0000000000UL, 0, 33), ++/* pmc34 */ PMC_D(PFM_REG_W , "PMC34", 0xf01ffffffffffUL, 0xfff0fe0000000000UL, 0, 34), ++/* pmc35 */ PMC_D(PFM_REG_W , "PMC35", 0x0, 0x1ffffffffffUL, 0, 35), ++/* pmc36 */ PMC_D(PFM_REG_W , "PMC36", 0xfffffff0UL, 0xfffffffffffffff0UL, 0, 36), ++/* pmc37 */ PMC_D(PFM_REG_W , "PMC37", 0x0, 0xffffffffffffc000UL, 0, 37), ++/* pmc38 */ PMC_D(PFM_REG_W , "PMC38", 0xdb6UL, 0xffffffffffffdb6dUL, 0, 38), ++/* pmc39 */ PMC_D(PFM_REG_W , "PMC39", 0x0, 0xffffffffffff0030UL, 0, 39), ++/* pmc40 */ PMC_D(PFM_REG_W , "PMC40", 0x2000000UL, 0xfffffffffff0fe30UL, 0, 40), ++/* pmc41 */ PMC_D(PFM_REG_W , "PMC41", 0x00002078fefefefeUL, 0xfffe1fffe7e7e7e7UL, 0, 41), ++/* pmc42 */ PMC_D(PFM_REG_W , "PMC42", 0x0, 0xfff800b0UL, 0, 42), ++/* pmc43 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc48 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc56 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc64 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc72 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc80 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc88 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc96 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc104 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc112 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc120 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc128 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc136 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc144 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc152 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc160 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc168 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc176 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc184 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc192 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc200 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc208 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc216 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc224 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc232 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc240 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc248 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc256 */ PMC_D(PFM_REG_W, "IBR0", 0x0, 0, 0, 0), ++/* pmc257 */ PMC_D(PFM_REG_W, "IBR1", 0x0, 0x8000000000000000UL, 0, 1), ++/* pmc258 */ PMC_D(PFM_REG_W, "IBR2", 0x0, 0, 0, 2), ++/* pmc259 */ PMC_D(PFM_REG_W, "IBR3", 0x0, 0x8000000000000000UL, 0, 3), ++/* pmc260 */ PMC_D(PFM_REG_W, "IBR4", 0x0, 0, 0, 4), ++/* pmc261 */ PMC_D(PFM_REG_W, "IBR5", 0x0, 0x8000000000000000UL, 0, 5), ++/* pmc262 */ PMC_D(PFM_REG_W, "IBR6", 0x0, 0, 0, 6), ++/* pmc263 */ PMC_D(PFM_REG_W, "IBR7", 0x0, 0x8000000000000000UL, 0, 7), ++/* pmc264 */ PMC_D(PFM_REG_W, "DBR0", 0x0, 0, 0, 0), ++/* pmc265 */ PMC_D(PFM_REG_W, "DBR1", 0x0, 0xc000000000000000UL, 0, 1), ++/* pmc266 */ PMC_D(PFM_REG_W, "DBR2", 0x0, 0, 0, 2), ++/* pmc267 */ PMC_D(PFM_REG_W, "DBR3", 0x0, 0xc000000000000000UL, 0, 3), ++/* pmc268 */ PMC_D(PFM_REG_W, "DBR4", 0x0, 0, 0, 4), ++/* pmc269 */ PMC_D(PFM_REG_W, "DBR5", 0x0, 0xc000000000000000UL, 0, 5), ++/* pmc270 */ PMC_D(PFM_REG_W, "DBR6", 0x0, 0, 0, 6), ++/* pmc271 */ PMC_D(PFM_REG_W, "DBR7", 0x0, 0xc000000000000000UL, 0, 7) ++}; ++#define PFM_MONT_NUM_PMCS ARRAY_SIZE(pfm_mont_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_mont_pmd_desc[] = { ++/* pmd0 */ PMX_NA, ++/* pmd1 */ PMX_NA, ++/* pmd2 */ PMX_NA, ++/* pmd3 */ PMX_NA, ++/* pmd4 */ PMD_DP(PFM_REG_C, "PMD4", 4, 1ull << 4), ++/* pmd5 */ PMD_DP(PFM_REG_C, "PMD5", 5, 1ull << 5), ++/* pmd6 */ PMD_DP(PFM_REG_C, "PMD6", 6, 1ull << 6), ++/* pmd7 */ PMD_DP(PFM_REG_C, "PMD7", 7, 1ull << 7), ++/* pmd8 */ PMD_DP(PFM_REG_C, "PMD8", 8, 1ull << 8), ++/* pmd9 */ PMD_DP(PFM_REG_C, "PMD9", 9, 1ull << 9), ++/* pmd10 */ PMD_DP(PFM_REG_C, "PMD10", 10, 1ull << 10), ++/* pmd11 */ PMD_DP(PFM_REG_C, "PMD11", 11, 1ull << 11), ++/* pmd12 */ PMD_DP(PFM_REG_C, "PMD12", 12, 1ull << 12), ++/* pmd13 */ PMD_DP(PFM_REG_C, "PMD13", 13, 1ull << 13), ++/* pmd14 */ PMD_DP(PFM_REG_C, "PMD14", 14, 1ull << 14), ++/* pmd15 */ PMD_DP(PFM_REG_C, "PMD15", 15, 1ull << 15), ++/* pmd16 */ PMX_NA, ++/* pmd17 */ PMX_NA, ++/* pmd18 */ PMX_NA, ++/* pmd19 */ PMX_NA, ++/* pmd20 */ PMX_NA, ++/* pmd21 */ PMX_NA, ++/* pmd22 */ PMX_NA, ++/* pmd23 */ PMX_NA, ++/* pmd24 */ PMX_NA, ++/* pmd25 */ PMX_NA, ++/* pmd26 */ PMX_NA, ++/* pmd27 */ PMX_NA, ++/* pmd28 */ PMX_NA, ++/* pmd29 */ PMX_NA, ++/* pmd30 */ PMX_NA, ++/* pmd31 */ PMX_NA, ++/* pmd32 */ PMD_DP(PFM_REG_I, "PMD32", 32, 1ull << 40), ++/* pmd33 */ PMD_DP(PFM_REG_I, "PMD33", 33, 1ull << 40), ++/* pmd34 */ PMD_DP(PFM_REG_I, "PMD34", 34, 1ull << 37), ++/* pmd35 */ PMD_DP(PFM_REG_I, "PMD35", 35, 1ull << 37), ++/* pmd36 */ PMD_DP(PFM_REG_I, "PMD36", 36, 1ull << 40), ++/* pmd37 */ PMX_NA, ++/* pmd38 */ PMD_DP(PFM_REG_I, "PMD38", 38, (1ull<<39)|(1ull<<42)), ++/* pmd39 */ PMD_DP(PFM_REG_I, "PMD39", 39, (1ull<<39)|(1ull<<42)), ++/* pmd40 */ PMX_NA, ++/* pmd41 */ PMX_NA, ++/* pmd42 */ PMX_NA, ++/* pmd43 */ PMX_NA, ++/* pmd44 */ PMX_NA, ++/* pmd45 */ PMX_NA, ++/* pmd46 */ PMX_NA, ++/* pmd47 */ PMX_NA, ++/* pmd48 */ PMD_DP(PFM_REG_I, "PMD48", 48, (1ull<<39)|(1ull<<42)), ++/* pmd49 */ PMD_DP(PFM_REG_I, "PMD49", 49, (1ull<<39)|(1ull<<42)), ++/* pmd50 */ PMD_DP(PFM_REG_I, "PMD50", 50, (1ull<<39)|(1ull<<42)), ++/* pmd51 */ PMD_DP(PFM_REG_I, "PMD51", 51, (1ull<<39)|(1ull<<42)), ++/* pmd52 */ PMD_DP(PFM_REG_I, "PMD52", 52, (1ull<<39)|(1ull<<42)), ++/* pmd53 */ PMD_DP(PFM_REG_I, "PMD53", 53, (1ull<<39)|(1ull<<42)), ++/* pmd54 */ PMD_DP(PFM_REG_I, "PMD54", 54, (1ull<<39)|(1ull<<42)), ++/* pmd55 */ PMD_DP(PFM_REG_I, "PMD55", 55, (1ull<<39)|(1ull<<42)), ++/* pmd56 */ PMD_DP(PFM_REG_I, "PMD56", 56, (1ull<<39)|(1ull<<42)), ++/* pmd57 */ PMD_DP(PFM_REG_I, "PMD57", 57, (1ull<<39)|(1ull<<42)), ++/* pmd58 */ PMD_DP(PFM_REG_I, "PMD58", 58, (1ull<<39)|(1ull<<42)), ++/* pmd59 */ PMD_DP(PFM_REG_I, "PMD59", 59, (1ull<<39)|(1ull<<42)), ++/* pmd60 */ PMD_DP(PFM_REG_I, "PMD60", 60, (1ull<<39)|(1ull<<42)), ++/* pmd61 */ PMD_DP(PFM_REG_I, "PMD61", 61, (1ull<<39)|(1ull<<42)), ++/* pmd62 */ PMD_DP(PFM_REG_I, "PMD62", 62, (1ull<<39)|(1ull<<42)), ++/* pmd63 */ PMD_DP(PFM_REG_I, "PMD63", 63, (1ull<<39)|(1ull<<42)) ++}; ++#define PFM_MONT_NUM_PMDS ARRAY_SIZE(pfm_mont_pmd_desc) ++ ++static int pfm_mont_has_ht; ++ ++static int pfm_mont_pmc_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++ struct pfm_arch_context *ctx_arch; ++ u64 val32 = 0, val38 = 0, val41 = 0; ++ u64 tmpval; ++ u16 cnum; ++ int ret = 0, check_case1 = 0; ++ int is_system; ++ ++ tmpval = req->reg_value; ++ cnum = req->reg_num; ++ ctx_arch = pfm_ctx_arch(ctx); ++ is_system = ctx->flags.system; ++ ++#define PFM_MONT_PMC_PM_POS6 (1UL<<6) ++#define PFM_MONT_PMC_PM_POS4 (1UL<<4) ++ ++ switch (cnum) { ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ case 9: ++ if (is_system) ++ tmpval |= PFM_MONT_PMC_PM_POS6; ++ else ++ tmpval &= ~PFM_MONT_PMC_PM_POS6; ++ break; ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ if ((req->reg_flags & PFM_REGFL_NO_EMUL64) == 0) { ++ if (pfm_mont_has_ht) { ++ PFM_INFO("perfmon: Errata 121 PMD10/PMD15 cannot be used to overflow" ++ "when threads on on"); ++ return -EINVAL; ++ } ++ } ++ if (is_system) ++ tmpval |= PFM_MONT_PMC_PM_POS6; ++ else ++ tmpval &= ~PFM_MONT_PMC_PM_POS6; ++ break; ++ case 39: ++ case 40: ++ case 42: ++ if (pfm_mont_has_ht && ((req->reg_value >> 8) & 0x7) == 4) { ++ PFM_INFO("perfmon: Errata 120: IP-EAR not available when threads are on"); ++ return -EINVAL; ++ } ++ if (is_system) ++ tmpval |= PFM_MONT_PMC_PM_POS6; ++ else ++ tmpval &= ~PFM_MONT_PMC_PM_POS6; ++ break; ++ ++ case 32: ++ val32 = tmpval; ++ val38 = set->pmcs[38]; ++ val41 = set->pmcs[41]; ++ check_case1 = 1; ++ break; ++ ++ case 37: ++ if (is_system) ++ tmpval |= PFM_MONT_PMC_PM_POS4; ++ else ++ tmpval &= ~PFM_MONT_PMC_PM_POS4; ++ break; ++ ++ case 38: ++ val38 = tmpval; ++ val32 = set->pmcs[32]; ++ val41 = set->pmcs[41]; ++ check_case1 = 1; ++ break; ++ case 41: ++ val41 = tmpval; ++ val32 = set->pmcs[32]; ++ val38 = set->pmcs[38]; ++ check_case1 = 1; ++ break; ++ } ++ ++ if (check_case1) { ++ ret = (((val41 >> 45) & 0xf) == 0 && ((val32>>57) & 0x1) == 0) ++ && ((((val38>>1) & 0x3) == 0x2 || ((val38>>1) & 0x3) == 0) ++ || (((val38>>4) & 0x3) == 0x2 || ((val38>>4) & 0x3) == 0)); ++ if (ret) { ++ PFM_DBG("perfmon: invalid config pmc38=0x%lx " ++ "pmc41=0x%lx pmc32=0x%lx", ++ val38, val41, val32); ++ return -EINVAL; ++ } ++ } ++ ++ /* ++ * check if configuration implicitely activates the use of the ++ * debug registers. If true, then we ensure that this is possible ++ * and that we do not pick up stale value in the HW registers. ++ */ ++ ++ /* ++ * ++ * pmc41 is "active" if: ++ * one of the pmc41.cfgdtagXX field is different from 0x3 ++ * AND ++ * the corsesponding pmc41.en_dbrpXX is set. ++ * AND ++ * ctx_fl_use_dbr (dbr not yet used) ++ */ ++ if (cnum == 41 ++ && (tmpval & 0x1e00000000000) ++ && (tmpval & 0x18181818) != 0x18181818 ++ && ctx_arch->flags.use_dbr == 0) { ++ PFM_DBG("pmc41=0x%lx active, clearing dbr", tmpval); ++ ret = pfm_ia64_mark_dbregs_used(ctx, set); ++ if (ret) ++ return ret; ++ } ++ /* ++ * we must clear the (instruction) debug registers if: ++ * pmc38.ig_ibrpX is 0 (enabled) ++ * and ++ * fl_use_dbr == 0 (dbr not yet used) ++ */ ++ if (cnum == 38 && ((tmpval & 0x492) != 0x492) ++ && ctx_arch->flags.use_dbr == 0) { ++ PFM_DBG("pmc38=0x%lx active pmc38, clearing ibr", tmpval); ++ ret = pfm_ia64_mark_dbregs_used(ctx, set); ++ if (ret) ++ return ret; ++ ++ } ++ req->reg_value = tmpval; ++ return 0; ++} ++ ++static void pfm_handle_errata(void) ++{ ++ pfm_mont_has_ht = 1; ++ ++ PFM_INFO("activating workaround for errata 120 " ++ "(Disable IP-EAR when threads are on)"); ++ ++ PFM_INFO("activating workaround for Errata 121 " ++ "(PMC10-PMC15 cannot be used to overflow" ++ " when threads are on"); ++} ++static int pfm_mont_probe_pmu(void) ++{ ++ if (local_cpu_data->family != 0x20) ++ return -1; ++ ++ /* ++ * the 2 errata must be activated when ++ * threads are/can be enabled ++ */ ++ if (is_multithreading_enabled()) ++ pfm_handle_errata(); ++ ++ return 0; ++} ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_mont_pmu_conf = { ++ .pmu_name = "Montecito", ++ .counter_width = 47, ++ .pmd_desc = pfm_mont_pmd_desc, ++ .pmc_desc = pfm_mont_pmc_desc, ++ .num_pmc_entries = PFM_MONT_NUM_PMCS, ++ .num_pmd_entries = PFM_MONT_NUM_PMDS, ++ .pmc_write_check = pfm_mont_pmc_check, ++ .probe_pmu = pfm_mont_probe_pmu, ++ .version = "1.0", ++ .pmu_info = &pfm_mont_pmu_info, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE ++}; ++ ++static int __init pfm_mont_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_mont_pmu_conf); ++} ++ ++static void __exit pfm_mont_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_mont_pmu_conf); ++} ++ ++module_init(pfm_mont_pmu_init_module); ++module_exit(pfm_mont_pmu_cleanup_module); +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1858,6 +1858,8 @@ config SECCOMP + + If unsure, say Y. Only embedded should say N here. + ++source "arch/mips/perfmon/Kconfig" ++ + endmenu + + config RWSEM_GENERIC_SPINLOCK +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -154,6 +154,12 @@ endif + endif + + # ++# Perfmon support ++# ++ ++core-$(CONFIG_PERFMON) += arch/mips/perfmon/ ++ ++# + # Firmware support + # + libs-$(CONFIG_ARC) += arch/mips/fw/arc/ +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -94,6 +95,7 @@ void start_thread(struct pt_regs * regs, + + void exit_thread(void) + { ++ pfm_exit_thread(); + } + + void flush_thread(void) +@@ -162,6 +164,8 @@ int copy_thread(int nr, unsigned long cl + if (clone_flags & CLONE_SETTLS) + ti->tp_value = regs->regs[7]; + ++ pfm_copy_thread(p); ++ + return 0; + } + +--- a/arch/mips/kernel/scall32-o32.S ++++ b/arch/mips/kernel/scall32-o32.S +@@ -653,6 +653,18 @@ einval: li v0, -EINVAL + sys sys_dup3 3 + sys sys_pipe2 2 + sys sys_inotify_init1 1 ++ sys sys_pfm_create_context 4 /* 4330 */ ++ sys sys_pfm_write_pmcs 3 ++ sys sys_pfm_write_pmds 4 ++ sys sys_pfm_read_pmds 3 ++ sys sys_pfm_load_context 2 ++ sys sys_pfm_start 2 /* 4335 */ ++ sys sys_pfm_stop 1 ++ sys sys_pfm_restart 1 ++ sys sys_pfm_create_evtsets 3 ++ sys sys_pfm_getinfo_evtsets 3 ++ sys sys_pfm_delete_evtsets 3 /* 4340 */ ++ sys sys_pfm_unload_context 1 + .endm + + /* We pre-compute the number of _instruction_ bytes needed to +--- a/arch/mips/kernel/scall64-64.S ++++ b/arch/mips/kernel/scall64-64.S +@@ -487,4 +487,16 @@ sys_call_table: + PTR sys_dup3 + PTR sys_pipe2 + PTR sys_inotify_init1 ++ PTR sys_pfm_create_context ++ PTR sys_pfm_write_pmcs /* 5290 */ ++ PTR sys_pfm_write_pmds ++ PTR sys_pfm_read_pmds ++ PTR sys_pfm_load_context ++ PTR sys_pfm_start ++ PTR sys_pfm_stop /* 5295 */ ++ PTR sys_pfm_restart ++ PTR sys_pfm_create_evtsets ++ PTR sys_pfm_getinfo_evtsets ++ PTR sys_pfm_delete_evtsets ++ PTR sys_pfm_unload_context /* 5300 */ + .size sys_call_table,.-sys_call_table +--- a/arch/mips/kernel/scall64-n32.S ++++ b/arch/mips/kernel/scall64-n32.S +@@ -400,12 +400,12 @@ EXPORT(sysn32_call_table) + PTR sys_ioprio_set + PTR sys_ioprio_get + PTR compat_sys_utimensat +- PTR compat_sys_signalfd /* 5280 */ ++ PTR compat_sys_signalfd /* 6280 */ + PTR sys_ni_syscall + PTR sys_eventfd + PTR sys_fallocate + PTR sys_timerfd_create +- PTR sys_timerfd_gettime /* 5285 */ ++ PTR sys_timerfd_gettime /* 6285 */ + PTR sys_timerfd_settime + PTR sys_signalfd4 + PTR sys_eventfd2 +@@ -413,4 +413,16 @@ EXPORT(sysn32_call_table) + PTR sys_dup3 /* 5290 */ + PTR sys_pipe2 + PTR sys_inotify_init1 ++ PTR sys_pfm_create_context ++ PTR sys_pfm_write_pmcs ++ PTR sys_pfm_write_pmds /* 6295 */ ++ PTR sys_pfm_read_pmds ++ PTR sys_pfm_load_context ++ PTR sys_pfm_start ++ PTR sys_pfm_stop ++ PTR sys_pfm_restart /* 6300 */ ++ PTR sys_pfm_create_evtsets ++ PTR sys_pfm_getinfo_evtsets ++ PTR sys_pfm_delete_evtsets ++ PTR sys_pfm_unload_context + .size sysn32_call_table,.-sysn32_call_table +--- a/arch/mips/kernel/scall64-o32.S ++++ b/arch/mips/kernel/scall64-o32.S +@@ -535,4 +535,16 @@ sys_call_table: + PTR sys_dup3 + PTR sys_pipe2 + PTR sys_inotify_init1 ++ PTR sys_pfm_create_context /* 4330 */ ++ PTR sys_pfm_write_pmcs ++ PTR sys_pfm_write_pmds ++ PTR sys_pfm_read_pmds ++ PTR sys_pfm_load_context ++ PTR sys_pfm_start /* 4335 */ ++ PTR sys_pfm_stop ++ PTR sys_pfm_restart ++ PTR sys_pfm_create_evtsets ++ PTR sys_pfm_getinfo_evtsets ++ PTR sys_pfm_delete_evtsets /* 4340 */ ++ PTR sys_pfm_unload_context + .size sys_call_table,.-sys_call_table +--- a/arch/mips/kernel/signal.c ++++ b/arch/mips/kernel/signal.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -695,8 +696,11 @@ static void do_signal(struct pt_regs *re + * - triggered by the TIF_WORK_MASK flags + */ + asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, +- __u32 thread_info_flags) ++ __u32 thread_info_flags) + { ++ if (thread_info_flags & _TIF_PERFMON_WORK) ++ pfm_handle_work(regs); ++ + /* deal with pending signal delivery */ + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + do_signal(regs); +--- a/arch/mips/kernel/time.c ++++ b/arch/mips/kernel/time.c +@@ -49,10 +49,11 @@ int update_persistent_clock(struct times + return rtc_mips_set_mmss(now.tv_sec); + } + +-static int null_perf_irq(void) ++int null_perf_irq(void) + { + return 0; + } ++EXPORT_SYMBOL(null_perf_irq); + + int (*perf_irq)(void) = null_perf_irq; + +--- a/arch/mips/kernel/traps.c ++++ b/arch/mips/kernel/traps.c +@@ -92,17 +92,15 @@ static void show_raw_backtrace(unsigned + #ifdef CONFIG_KALLSYMS + printk("\n"); + #endif +- while (!kstack_end(sp)) { +- unsigned long __user *p = +- (unsigned long __user *)(unsigned long)sp++; +- if (__get_user(addr, p)) { +- printk(" (Bad stack address)"); +- break; ++#define IS_KVA01(a) ((((unsigned long)a) & 0xc0000000) == 0x80000000) ++ if (IS_KVA01(sp)) { ++ while (!kstack_end(sp)) { ++ addr = *sp++; ++ if (__kernel_text_address(addr)) ++ print_ip_sym(addr); + } +- if (__kernel_text_address(addr)) +- print_ip_sym(addr); ++ printk("\n"); + } +- printk("\n"); + } + + #ifdef CONFIG_KALLSYMS +--- a/arch/mips/mti-malta/malta-time.c ++++ b/arch/mips/mti-malta/malta-time.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + #include +--- /dev/null ++++ b/arch/mips/perfmon/Kconfig +@@ -0,0 +1,61 @@ ++menu "Hardware Performance Monitoring support" ++config PERFMON ++ bool "Perfmon2 performance monitoring interface" ++ default n ++ help ++ Enables the perfmon2 interface to access the hardware ++ performance counters. See for ++ more details. ++ ++config PERFMON_DEBUG ++ bool "Perfmon debugging" ++ default n ++ depends on PERFMON ++ help ++ Enables perfmon debugging support ++ ++config PERFMON_DEBUG_FS ++ bool "Enable perfmon statistics reporting via debugfs" ++ default y ++ depends on PERFMON && DEBUG_FS ++ help ++ Enable collection and reporting of perfmon timing statistics under ++ debugfs. This is used for debugging and performance analysis of the ++ subsystem. The debugfs filesystem must be mounted. ++ ++config PERFMON_FLUSH ++ bool "Flush sampling buffer when modified" ++ depends on PERFMON ++ default n ++ help ++ On some MIPS models, cache aliasing may cause invalid ++ data to be read from the perfmon sampling buffer. Use this option ++ to flush the buffer when it is modified to ensure valid data is ++ visible at the user level. ++ ++config PERFMON_ALIGN ++ bool "Align sampling buffer to avoid cache aliasing" ++ depends on PERFMON ++ default n ++ help ++ On some MIPS models, cache aliasing may cause invalid ++ data to be read from the perfmon sampling buffer. By forcing a bigger ++ page alignment (4-page), one can guarantee the buffer virtual address ++ will conflict in the cache with the user level mapping of the buffer ++ thereby ensuring a consistent view by user programs. ++ ++config PERFMON_DEBUG ++ bool "Perfmon debugging" ++ depends on PERFMON ++ default n ++ depends on PERFMON ++ help ++ Enables perfmon debugging support ++ ++config PERFMON_MIPS64 ++ tristate "Support for MIPS64 hardware performance counters" ++ depends on PERFMON ++ default n ++ help ++ Enables support for the MIPS64 hardware performance counters" ++endmenu +--- /dev/null ++++ b/arch/mips/perfmon/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_PERFMON) += perfmon.o ++obj-$(CONFIG_PERFMON_MIPS64) += perfmon_mips64.o +--- /dev/null ++++ b/arch/mips/perfmon/perfmon.c +@@ -0,0 +1,313 @@ ++/* ++ * This file implements the MIPS64 specific ++ * support for the perfmon2 interface ++ * ++ * Copyright (c) 2005 Philip J. Mucci ++ * ++ * based on versions for other architectures: ++ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++ ++/* ++ * collect pending overflowed PMDs. Called from pfm_ctxsw() ++ * and from PMU interrupt handler. Must fill in set->povfl_pmds[] ++ * and set->npend_ovfls. Interrupts are masked ++ */ ++static void __pfm_get_ovfl_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 new_val, wmask; ++ u64 *used_mask, *intr_pmds; ++ u64 mask[PFM_PMD_BV]; ++ unsigned int i, max; ++ ++ max = ctx->regs.max_intr_pmd; ++ intr_pmds = ctx->regs.intr_pmds; ++ used_mask = set->used_pmds; ++ ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ bitmap_and(cast_ulp(mask), ++ cast_ulp(intr_pmds), ++ cast_ulp(used_mask), ++ max); ++ ++ /* ++ * check all PMD that can generate interrupts ++ * (that includes counters) ++ */ ++ for (i = 0; i < max; i++) { ++ if (test_bit(i, mask)) { ++ new_val = pfm_arch_read_pmd(ctx, i); ++ ++ PFM_DBG_ovfl("pmd%u new_val=0x%llx bit=%d\n", ++ i, (unsigned long long)new_val, ++ (new_val&wmask) ? 1 : 0); ++ ++ if (new_val & wmask) { ++ __set_bit(i, set->povfl_pmds); ++ set->npend_ovfls++; ++ } ++ } ++ } ++} ++ ++static void pfm_stop_active(struct task_struct *task, struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i, max; ++ ++ max = ctx->regs.max_pmc; ++ ++ /* ++ * clear enable bits, assume all pmcs are enable pmcs ++ */ ++ for (i = 0; i < max; i++) { ++ if (test_bit(i, set->used_pmcs)) ++ pfm_arch_write_pmc(ctx, i, 0); ++ } ++ ++ if (set->npend_ovfls) ++ return; ++ ++ __pfm_get_ovfl_pmds(ctx, set); ++} ++ ++/* ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * Context is locked. Interrupts are masked. Monitoring is active. ++ * PMU access is guaranteed. PMC and PMD registers are live in PMU. ++ * ++ * for per-thread: ++ * must stop monitoring for the task ++ * ++ * Return: ++ * non-zero : did not save PMDs (as part of stopping the PMU) ++ * 0 : saved PMDs (no need to save them in caller) ++ */ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ /* ++ * disable lazy restore of PMC registers. ++ */ ++ ctx->active_set->priv_flags |= PFM_SETFL_PRIV_MOD_PMCS; ++ ++ /* ++ * if masked, monitoring is stopped, thus there is no ++ * need to stop the PMU again and there is no need to ++ * check for pending overflows. This is not just an ++ * optimization, this is also for correctness as you ++ * may end up detecting overflows twice. ++ */ ++ if (ctx->state == PFM_CTX_MASKED) ++ return 1; ++ ++ pfm_stop_active(task, ctx, ctx->active_set); ++ ++ return 1; ++} ++ ++/* ++ * Called from pfm_stop() and pfm_ctxsw() ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-thread: ++ * task is not necessarily current. If not current task, then ++ * task is guaranteed stopped and off any cpu. Access to PMU ++ * is not guaranteed. Interrupts are masked. Context is locked. ++ * Set is the active set. ++ * ++ * For system-wide: ++ * task is current ++ * ++ * must disable active monitoring. ctx cannot be NULL ++ */ ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx) ++{ ++ /* ++ * no need to go through stop_save() ++ * if we are already stopped ++ */ ++ if (!ctx->flags.started || ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ /* ++ * stop live registers and collect pending overflow ++ */ ++ if (task == current) ++ pfm_stop_active(task, ctx, ctx->active_set); ++} ++ ++/* ++ * called from pfm_start() or pfm_ctxsw() when idle task and ++ * EXCL_IDLE is on. ++ * ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-trhead: ++ * Task is not necessarily current. If not current task, then task ++ * is guaranteed stopped and off any cpu. Access to PMU is not guaranteed. ++ * ++ * For system-wide: ++ * task is always current ++ * ++ * must enable active monitoring. ++ */ ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ unsigned int i, max_pmc; ++ ++ if (task != current) ++ return; ++ ++ set = ctx->active_set; ++ max_pmc = ctx->regs.max_pmc; ++ ++ for (i = 0; i < max_pmc; i++) { ++ if (test_bit(i, set->used_pmcs)) ++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]); ++ } ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets() ++ * context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMD registers from set. ++ */ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 ovfl_mask, val; ++ u64 *impl_pmds; ++ unsigned int i; ++ unsigned int max_pmd; ++ ++ max_pmd = ctx->regs.max_pmd; ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ impl_pmds = ctx->regs.pmds; ++ ++ /* ++ * must restore all pmds to avoid leaking ++ * information to user. ++ */ ++ for (i = 0; i < max_pmd; i++) { ++ ++ if (test_bit(i, impl_pmds) == 0) ++ continue; ++ ++ val = set->pmds[i].value; ++ ++ /* ++ * set upper bits for counter to ensure ++ * overflow will trigger ++ */ ++ val &= ovfl_mask; ++ ++ pfm_arch_write_pmd(ctx, i, val); ++ } ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(). ++ * Context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMC registers from set, if needed. ++ */ ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 *impl_pmcs; ++ unsigned int i, max_pmc; ++ ++ max_pmc = ctx->regs.max_pmc; ++ impl_pmcs = ctx->regs.pmcs; ++ ++ /* ++ * - by default no PMCS measures anything ++ * - on ctxswout, all used PMCs are disabled (cccr enable bit cleared) ++ * hence when masked we do not need to restore anything ++ */ ++ if (ctx->state == PFM_CTX_MASKED || ctx->flags.started == 0) ++ return; ++ ++ /* ++ * restore all pmcs ++ */ ++ for (i = 0; i < max_pmc; i++) ++ if (test_bit(i, impl_pmcs)) ++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]); ++} ++ ++char *pfm_arch_get_pmu_module_name(void) ++{ ++ switch (cpu_data->cputype) { ++#ifndef CONFIG_SMP ++ case CPU_34K: ++#if defined(CPU_74K) ++ case CPU_74K: ++#endif ++#endif ++ case CPU_SB1: ++ case CPU_SB1A: ++ case CPU_R12000: ++ case CPU_25KF: ++ case CPU_24K: ++ case CPU_20KC: ++ case CPU_5KC: ++ return "perfmon_mips64"; ++ default: ++ return NULL; ++ } ++ return NULL; ++} ++ ++int perfmon_perf_irq(void) ++{ ++ /* BLATANTLY STOLEN FROM OPROFILE, then modified */ ++ struct pt_regs *regs; ++ unsigned int counters = pfm_pmu_conf->regs_all.max_pmc; ++ unsigned int control; ++ unsigned int counter; ++ ++ regs = get_irq_regs(); ++ switch (counters) { ++#define HANDLE_COUNTER(n) \ ++ case n + 1: \ ++ control = read_c0_perfctrl ## n(); \ ++ counter = read_c0_perfcntr ## n(); \ ++ if ((control & MIPS64_PMC_INT_ENABLE_MASK) && \ ++ (counter & MIPS64_PMD_INTERRUPT)) { \ ++ pfm_interrupt_handler(instruction_pointer(regs),\ ++ regs); \ ++ return(1); \ ++ } ++ HANDLE_COUNTER(3) ++ HANDLE_COUNTER(2) ++ HANDLE_COUNTER(1) ++ HANDLE_COUNTER(0) ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(perfmon_perf_irq); +--- /dev/null ++++ b/arch/mips/perfmon/perfmon_mips64.c +@@ -0,0 +1,218 @@ ++/* ++ * This file contains the MIPS64 and decendent PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2005 Philip Mucci ++ * ++ * Based on perfmon_p6.c: ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++MODULE_AUTHOR("Philip Mucci "); ++MODULE_DESCRIPTION("MIPS64 PMU description tables"); ++MODULE_LICENSE("GPL"); ++ ++/* ++ * reserved: ++ * - bit 63-9 ++ * RSVD: reserved bits must be 1 ++ */ ++#define PFM_MIPS64_PMC_RSVD 0xfffffffffffff810ULL ++#define PFM_MIPS64_PMC_VAL (1ULL<<4) ++ ++extern int null_perf_irq(struct pt_regs *regs); ++extern int (*perf_irq)(struct pt_regs *regs); ++extern int perfmon_perf_irq(struct pt_regs *regs); ++ ++static struct pfm_arch_pmu_info pfm_mips64_pmu_info; ++ ++static struct pfm_regmap_desc pfm_mips64_pmc_desc[] = { ++/* pmc0 */ PMC_D(PFM_REG_I64, "CP0_25_0", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 0), ++/* pmc1 */ PMC_D(PFM_REG_I64, "CP0_25_1", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 1), ++/* pmc2 */ PMC_D(PFM_REG_I64, "CP0_25_2", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 2), ++/* pmc3 */ PMC_D(PFM_REG_I64, "CP0_25_3", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 3) ++}; ++#define PFM_MIPS64_NUM_PMCS ARRAY_SIZE(pfm_mips64_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_mips64_pmd_desc[] = { ++/* pmd0 */ PMD_D(PFM_REG_C, "CP0_25_0", 0), ++/* pmd1 */ PMD_D(PFM_REG_C, "CP0_25_1", 1), ++/* pmd2 */ PMD_D(PFM_REG_C, "CP0_25_2", 2), ++/* pmd3 */ PMD_D(PFM_REG_C, "CP0_25_3", 3) ++}; ++#define PFM_MIPS64_NUM_PMDS ARRAY_SIZE(pfm_mips64_pmd_desc) ++ ++static int pfm_mips64_probe_pmu(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ ++ switch (c->cputype) { ++#ifndef CONFIG_SMP ++ case CPU_34K: ++#if defined(CPU_74K) ++ case CPU_74K: ++#endif ++#endif ++ case CPU_SB1: ++ case CPU_SB1A: ++ case CPU_R12000: ++ case CPU_25KF: ++ case CPU_24K: ++ case CPU_20KC: ++ case CPU_5KC: ++ return 0; ++ break; ++ default: ++ PFM_INFO("Unknown cputype 0x%x", c->cputype); ++ } ++ return -1; ++} ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_mips64_pmu_conf = { ++ .pmu_name = "MIPS", /* placeholder */ ++ .counter_width = 31, ++ .pmd_desc = pfm_mips64_pmd_desc, ++ .pmc_desc = pfm_mips64_pmc_desc, ++ .num_pmc_entries = PFM_MIPS64_NUM_PMCS, ++ .num_pmd_entries = PFM_MIPS64_NUM_PMDS, ++ .probe_pmu = pfm_mips64_probe_pmu, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_mips64_pmu_info ++}; ++ ++static inline int n_counters(void) ++{ ++ if (!(read_c0_config1() & MIPS64_CONFIG_PMC_MASK)) ++ return 0; ++ if (!(read_c0_perfctrl0() & MIPS64_PMC_CTR_MASK)) ++ return 1; ++ if (!(read_c0_perfctrl1() & MIPS64_PMC_CTR_MASK)) ++ return 2; ++ if (!(read_c0_perfctrl2() & MIPS64_PMC_CTR_MASK)) ++ return 3; ++ return 4; ++} ++ ++static int __init pfm_mips64_pmu_init_module(void) ++{ ++ struct cpuinfo_mips *c = ¤t_cpu_data; ++ int i, ret, num; ++ u64 temp_mask; ++ ++ switch (c->cputype) { ++ case CPU_5KC: ++ pfm_mips64_pmu_conf.pmu_name = "MIPS5KC"; ++ break; ++ case CPU_R12000: ++ pfm_mips64_pmu_conf.pmu_name = "MIPSR12000"; ++ break; ++ case CPU_20KC: ++ pfm_mips64_pmu_conf.pmu_name = "MIPS20KC"; ++ break; ++ case CPU_24K: ++ pfm_mips64_pmu_conf.pmu_name = "MIPS24K"; ++ break; ++ case CPU_25KF: ++ pfm_mips64_pmu_conf.pmu_name = "MIPS25KF"; ++ break; ++ case CPU_SB1: ++ pfm_mips64_pmu_conf.pmu_name = "SB1"; ++ break; ++ case CPU_SB1A: ++ pfm_mips64_pmu_conf.pmu_name = "SB1A"; ++ break; ++#ifndef CONFIG_SMP ++ case CPU_34K: ++ pfm_mips64_pmu_conf.pmu_name = "MIPS34K"; ++ break; ++#if defined(CPU_74K) ++ case CPU_74K: ++ pfm_mips64_pmu_conf.pmu_name = "MIPS74K"; ++ break; ++#endif ++#endif ++ default: ++ PFM_INFO("Unknown cputype 0x%x", c->cputype); ++ return -1; ++ } ++ ++ /* The R14k and older performance counters have to */ ++ /* be hard-coded, as there is no support for auto-detection */ ++ if ((c->cputype == CPU_R12000) || (c->cputype == CPU_R14000)) ++ num = 4; ++ else if (c->cputype == CPU_R10000) ++ num = 2; ++ else ++ num = n_counters(); ++ ++ if (num == 0) { ++ PFM_INFO("cputype 0x%x has no counters", c->cputype); ++ return -1; ++ } ++ /* mark remaining counters unavailable */ ++ for (i = num; i < PFM_MIPS64_NUM_PMCS; i++) ++ pfm_mips64_pmc_desc[i].type = PFM_REG_NA; ++ ++ for (i = num; i < PFM_MIPS64_NUM_PMDS; i++) ++ pfm_mips64_pmd_desc[i].type = PFM_REG_NA; ++ ++ /* set the PMC_RSVD mask */ ++ switch (c->cputype) { ++ case CPU_5KC: ++ case CPU_R10000: ++ case CPU_20KC: ++ /* 4-bits for event */ ++ temp_mask = 0xfffffffffffffe10ULL; ++ break; ++ case CPU_R12000: ++ case CPU_R14000: ++ /* 5-bits for event */ ++ temp_mask = 0xfffffffffffffc10ULL; ++ break; ++ default: ++ /* 6-bits for event */ ++ temp_mask = 0xfffffffffffff810ULL; ++ } ++ for (i = 0; i < PFM_MIPS64_NUM_PMCS; i++) ++ pfm_mips64_pmc_desc[i].rsvd_msk = temp_mask; ++ ++ pfm_mips64_pmu_conf.num_pmc_entries = num; ++ pfm_mips64_pmu_conf.num_pmd_entries = num; ++ ++ pfm_mips64_pmu_info.pmu_style = c->cputype; ++ ++ ret = pfm_pmu_register(&pfm_mips64_pmu_conf); ++ if (ret == 0) ++ perf_irq = perfmon_perf_irq; ++ return ret; ++} ++ ++static void __exit pfm_mips64_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_mips64_pmu_conf); ++ perf_irq = null_perf_irq; ++} ++ ++module_init(pfm_mips64_pmu_init_module); ++module_exit(pfm_mips64_pmu_cleanup_module); +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -231,6 +231,8 @@ source "init/Kconfig" + source "arch/powerpc/sysdev/Kconfig" + source "arch/powerpc/platforms/Kconfig" + ++source "arch/powerpc/perfmon/Kconfig" ++ + menu "Kernel options" + + config HIGHMEM +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -148,6 +148,7 @@ core-y += arch/powerpc/kernel/ \ + arch/powerpc/platforms/ + core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/ + core-$(CONFIG_XMON) += arch/powerpc/xmon/ ++core-$(CONFIG_PERFMON) += arch/powerpc/perfmon/ + core-$(CONFIG_KVM) += arch/powerpc/kvm/ + + drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ +--- a/arch/powerpc/include/asm/Kbuild ++++ b/arch/powerpc/include/asm/Kbuild +@@ -21,6 +21,7 @@ header-y += resource.h + header-y += sigcontext.h + header-y += statfs.h + header-y += ps3fb.h ++header-y += perfmon.h + + unifdef-y += bootx.h + unifdef-y += byteorder.h +--- a/arch/powerpc/include/asm/cell-pmu.h ++++ b/arch/powerpc/include/asm/cell-pmu.h +@@ -61,6 +61,11 @@ + + /* Macros for the pm_status register. */ + #define CBE_PM_CTR_OVERFLOW_INTR(ctr) (1 << (31 - ((ctr) & 7))) ++#define CBE_PM_OVERFLOW_CTRS(pm_status) (((pm_status) >> 24) & 0xff) ++#define CBE_PM_ALL_OVERFLOW_INTR 0xff000000 ++#define CBE_PM_INTERVAL_INTR 0x00800000 ++#define CBE_PM_TRACE_BUFFER_FULL_INTR 0x00400000 ++#define CBE_PM_TRACE_BUFFER_UNDERFLOW_INTR 0x00200000 + + enum pm_reg_name { + group_control, +--- a/arch/powerpc/include/asm/cell-regs.h ++++ b/arch/powerpc/include/asm/cell-regs.h +@@ -117,8 +117,9 @@ struct cbe_pmd_regs { + u8 pad_0x0c1c_0x0c20 [4]; /* 0x0c1c */ + #define CBE_PMD_FIR_MODE_M8 0x00800 + u64 fir_enable_mask; /* 0x0c20 */ +- +- u8 pad_0x0c28_0x0ca8 [0x0ca8 - 0x0c28]; /* 0x0c28 */ ++ u8 pad_0x0c28_0x0c98 [0x0c98 - 0x0c28]; /* 0x0c28 */ ++ u64 on_ramp_trace; /* 0x0c98 */ ++ u64 pad_0x0ca0; /* 0x0ca0 */ + u64 ras_esc_0; /* 0x0ca8 */ + u8 pad_0x0cb0_0x1000 [0x1000 - 0x0cb0]; /* 0x0cb0 */ + }; +@@ -218,7 +219,11 @@ extern struct cbe_iic_regs __iomem *cbe_ + + + struct cbe_mic_tm_regs { +- u8 pad_0x0000_0x0040[0x0040 - 0x0000]; /* 0x0000 */ ++ u8 pad_0x0000_0x0010[0x0010 - 0x0000]; /* 0x0000 */ ++ ++ u64 MBL_debug; /* 0x0010 */ ++ ++ u8 pad_0x0018_0x0040[0x0040 - 0x0018]; /* 0x0018 */ + + u64 mic_ctl_cnfg2; /* 0x0040 */ + #define CBE_MIC_ENABLE_AUX_TRC 0x8000000000000000LL +@@ -303,6 +308,25 @@ struct cbe_mic_tm_regs { + extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np); + extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu); + ++/* ++ * ++ * PPE Privileged MMIO Registers definition. (offset 0x500000 - 0x500fff) ++ * ++ */ ++struct cbe_ppe_priv_regs { ++ u8 pad_0x0000_0x0858[0x0858 - 0x0000]; /* 0x0000 */ ++ ++ u64 L2_debug1; /* 0x0858 */ ++ ++ u8 pad_0x0860_0x0958[0x0958 - 0x0860]; /* 0x0860 */ ++ ++ u64 ciu_dr1; /* 0x0958 */ ++ ++ u8 pad_0x0960_0x1000[0x1000 - 0x0960]; /* 0x0960 */ ++}; ++ ++extern struct cbe_ppe_priv_regs __iomem *cbe_get_cpu_ppe_priv_regs(int cpu); ++ + /* some utility functions to deal with SMT */ + extern u32 cbe_get_hw_thread_id(int cpu); + extern u32 cbe_cpu_to_node(int cpu); +--- a/arch/powerpc/include/asm/paca.h ++++ b/arch/powerpc/include/asm/paca.h +@@ -97,6 +97,10 @@ struct paca_struct { + u8 soft_enabled; /* irq soft-enable flag */ + u8 hard_enabled; /* set if irqs are enabled in MSR */ + u8 io_sync; /* writel() needs spin_unlock sync */ ++#ifdef CONFIG_PERFMON ++ u8 pmu_except_pending; /* PMU exception occurred while soft ++ * disabled */ ++#endif + + /* Stuff for accurate time accounting */ + u64 user_time; /* accumulated usermode TB ticks */ +--- /dev/null ++++ b/arch/powerpc/include/asm/perfmon.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (c) 2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file contains powerpc specific definitions for the perfmon ++ * interface. ++ * ++ * This file MUST never be included directly. Use linux/perfmon.h. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_POWERPC_PERFMON_H_ ++#define _ASM_POWERPC_PERFMON_H_ ++ ++/* ++ * arch-specific user visible interface definitions ++ */ ++#define PFM_ARCH_MAX_PMCS (256+64) /* 256 HW 64 SW */ ++#define PFM_ARCH_MAX_PMDS (256+64) /* 256 HW 64 SW */ ++ ++#endif /* _ASM_POWERPC_PERFMON_H_ */ +--- /dev/null ++++ b/arch/powerpc/include/asm/perfmon_kern.h +@@ -0,0 +1,390 @@ ++/* ++ * Copyright (c) 2005 David Gibson, IBM Corporation. ++ * ++ * Based on other versions: ++ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file contains powerpc specific definitions for the perfmon ++ * interface. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_POWERPC_PERFMON_KERN_H_ ++#define _ASM_POWERPC_PERFMON_KERN_H_ ++ ++#ifdef __KERNEL__ ++ ++#ifdef CONFIG_PERFMON ++ ++#include ++#include ++ ++#define HID0_PMC5_6_GR_MODE (1UL << (63 - 40)) ++ ++enum powerpc_pmu_type { ++ PFM_POWERPC_PMU_NONE, ++ PFM_POWERPC_PMU_604, ++ PFM_POWERPC_PMU_604e, ++ PFM_POWERPC_PMU_750, /* XXX: Minor event set diffs between IBM and Moto. */ ++ PFM_POWERPC_PMU_7400, ++ PFM_POWERPC_PMU_7450, ++ PFM_POWERPC_PMU_POWER4, ++ PFM_POWERPC_PMU_POWER5, ++ PFM_POWERPC_PMU_POWER5p, ++ PFM_POWERPC_PMU_POWER6, ++ PFM_POWERPC_PMU_CELL, ++}; ++ ++struct pfm_arch_pmu_info { ++ enum powerpc_pmu_type pmu_style; ++ ++ void (*write_pmc)(unsigned int cnum, u64 value); ++ void (*write_pmd)(unsigned int cnum, u64 value); ++ ++ u64 (*read_pmd)(unsigned int cnum); ++ ++ void (*enable_counters)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ void (*disable_counters)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++ void (*irq_handler)(struct pt_regs *regs, struct pfm_context *ctx); ++ void (*get_ovfl_pmds)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++ /* The following routines are optional. */ ++ void (*restore_pmcs)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ void (*restore_pmds)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++ int (*ctxswout_thread)(struct task_struct *task, ++ struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ void (*ctxswin_thread)(struct task_struct *task, ++ struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ int (*load_context)(struct pfm_context *ctx); ++ void (*unload_context)(struct pfm_context *ctx); ++ int (*acquire_pmu)(u64 *unavail_pmcs, u64 *unavail_pmds); ++ void (*release_pmu)(void); ++ void *platform_info; ++ void (*resend_irq)(struct pfm_context *ctx); ++}; ++ ++#ifdef CONFIG_PPC32 ++#define PFM_ARCH_PMD_STK_ARG 6 /* conservative value */ ++#define PFM_ARCH_PMC_STK_ARG 6 /* conservative value */ ++#else ++#define PFM_ARCH_PMD_STK_ARG 8 /* conservative value */ ++#define PFM_ARCH_PMC_STK_ARG 8 /* conservative value */ ++#endif ++ ++static inline void pfm_arch_resend_irq(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ arch_info->resend_irq(ctx); ++} ++ ++static inline void pfm_arch_serialize(void) ++{} ++ ++static inline void pfm_arch_write_pmc(struct pfm_context *ctx, ++ unsigned int cnum, ++ u64 value) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ ++ /* ++ * we only write to the actual register when monitoring is ++ * active (pfm_start was issued) ++ */ ++ if (ctx && ctx->flags.started == 0) ++ return; ++ ++ BUG_ON(!arch_info->write_pmc); ++ ++ arch_info->write_pmc(cnum, value); ++} ++ ++static inline void pfm_arch_write_pmd(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ ++ value &= pfm_pmu_conf->ovfl_mask; ++ ++ BUG_ON(!arch_info->write_pmd); ++ ++ arch_info->write_pmd(cnum, value); ++} ++ ++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ ++ BUG_ON(!arch_info->read_pmd); ++ ++ return arch_info->read_pmd(cnum); ++} ++ ++/* ++ * For some CPUs, the upper bits of a counter must be set in order for the ++ * overflow interrupt to happen. On overflow, the counter has wrapped around, ++ * and the upper bits are cleared. This function may be used to set them back. ++ */ ++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, ++ unsigned int cnum) ++{ ++ u64 val = pfm_arch_read_pmd(ctx, cnum); ++ ++ /* This masks out overflow bit 31 */ ++ pfm_arch_write_pmd(ctx, cnum, val); ++} ++ ++/* ++ * At certain points, perfmon needs to know if monitoring has been ++ * explicitely started/stopped by user via pfm_start/pfm_stop. The ++ * information is tracked in flags.started. However on certain ++ * architectures, it may be possible to start/stop directly from ++ * user level with a single assembly instruction bypassing ++ * the kernel. This function must be used to determine by ++ * an arch-specific mean if monitoring is actually started/stopped. ++ */ ++static inline int pfm_arch_is_active(struct pfm_context *ctx) ++{ ++ return ctx->flags.started; ++} ++ ++static inline void pfm_arch_ctxswout_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++ ++static inline void pfm_arch_ctxswin_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++ ++void pfm_arch_init_percpu(void); ++int pfm_arch_is_monitoring_active(struct pfm_context *ctx); ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, struct pfm_event_set *set); ++int pfm_arch_get_ovfl_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++char *pfm_arch_get_pmu_module_name(void); ++/* ++ * called from __pfm_interrupt_handler(). ctx is not NULL. ++ * ctx is locked. PMU interrupt is masked. ++ * ++ * must stop all monitoring to ensure handler has consistent view. ++ * must collect overflowed PMDs bitmask into povfls_pmds and ++ * npend_ovfls. If no interrupt detected then npend_ovfls ++ * must be set to zero. ++ */ ++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ pfm_arch_stop(current, ctx); ++} ++ ++void powerpc_irq_handler(struct pt_regs *regs); ++ ++/* ++ * unfreeze PMU from pfm_do_interrupt_handler() ++ * ctx may be NULL for spurious ++ */ ++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ if (!ctx) ++ return; ++ ++ PFM_DBG_ovfl("state=%d", ctx->state); ++ ++ ctx->flags.started = 1; ++ ++ if (ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ arch_info = pfm_pmu_info(); ++ BUG_ON(!arch_info->enable_counters); ++ arch_info->enable_counters(ctx, ctx->active_set); ++} ++ ++/* ++ * PowerPC does not save the PMDs during pfm_arch_intr_freeze_pmu(), thus ++ * this routine needs to do it when switching sets on overflow ++ */ ++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_save_pmds(ctx, set); ++} ++ ++/* ++ * this function is called from the PMU interrupt handler ONLY. ++ * On PPC, the PMU is frozen via arch_stop, masking would be implemented ++ * via arch-stop as well. Given that the PMU is already stopped when ++ * entering the interrupt handler, we do not need to stop it again, so ++ * this function is a nop. ++ */ ++static inline void pfm_arch_mask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++/* ++ * Simply need to start the context in order to unmask. ++ */ ++static inline void pfm_arch_unmask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_arch_start(current, ctx); ++} ++ ++ ++static inline int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_context_create(struct pfm_context *ctx, ++ u32 ctx_flags) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_context_free(struct pfm_context *ctx) ++{} ++ ++/* not necessary on PowerPC */ ++static inline void pfm_cacheflush(void *addr, unsigned int len) ++{} ++ ++/* ++ * function called from pfm_setfl_sane(). Context is locked ++ * and interrupts are masked. ++ * The value of flags is the value of ctx_flags as passed by ++ * user. ++ * ++ * function must check arch-specific set flags. ++ * Return: ++ * 1 when flags are valid ++ * 0 on error ++ */ ++static inline int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_init(void) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_load_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ int rc = 0; ++ ++ arch_info = pfm_pmu_info(); ++ if (arch_info->load_context) ++ rc = arch_info->load_context(ctx); ++ ++ return rc; ++} ++ ++static inline void pfm_arch_unload_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ if (arch_info->unload_context) ++ arch_info->unload_context(ctx); ++} ++ ++static inline int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ int rc = 0; ++ ++ arch_info = pfm_pmu_info(); ++ if (arch_info->acquire_pmu) { ++ rc = arch_info->acquire_pmu(unavail_pmcs, unavail_pmds); ++ if (rc) ++ return rc; ++ } ++ ++ return reserve_pmc_hardware(powerpc_irq_handler); ++} ++ ++static inline void pfm_arch_pmu_release(void) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ if (arch_info->release_pmu) ++ arch_info->release_pmu(); ++ ++ release_pmc_hardware(); ++} ++ ++static inline void pfm_arch_arm_handle_work(struct task_struct *task) ++{} ++ ++static inline void pfm_arch_disarm_handle_work(struct task_struct *task) ++{} ++ ++static inline int pfm_arch_get_base_syscall(void) ++{ ++ return __NR_pfm_create_context; ++} ++ ++struct pfm_arch_context { ++ /* Cell: Most recent value of the pm_status ++ * register read by the interrupt handler. ++ * ++ * Interrupt handler sets last_read_updated if it ++ * just read and updated last_read_pm_status ++ */ ++ u32 last_read_pm_status; ++ u32 last_read_updated; ++ u64 powergs_pmc5, powergs_pmc6; ++ u64 delta_tb, delta_tb_start; ++ u64 delta_purr, delta_purr_start; ++}; ++ ++#define PFM_ARCH_CTX_SIZE sizeof(struct pfm_arch_context) ++/* ++ * PowerPC does not need extra alignment requirements for the sampling buffer ++ */ ++#define PFM_ARCH_SMPL_ALIGN_SIZE 0 ++ ++#endif /* CONFIG_PERFMON */ ++ ++#endif /* __KERNEL__ */ ++#endif /* _ASM_POWERPC_PERFMON_KERN_H_ */ +--- a/arch/powerpc/include/asm/reg.h ++++ b/arch/powerpc/include/asm/reg.h +@@ -698,6 +698,7 @@ + #define PV_POWER5 0x003A + #define PV_POWER5p 0x003B + #define PV_970FX 0x003C ++#define PV_POWER6 0x003E + #define PV_630 0x0040 + #define PV_630p 0x0041 + #define PV_970MP 0x0044 +--- a/arch/powerpc/include/asm/systbl.h ++++ b/arch/powerpc/include/asm/systbl.h +@@ -322,3 +322,15 @@ SYSCALL_SPU(epoll_create1) + SYSCALL_SPU(dup3) + SYSCALL_SPU(pipe2) + SYSCALL(inotify_init1) ++SYSCALL(pfm_create_context) ++SYSCALL(pfm_write_pmcs) ++SYSCALL(pfm_write_pmds) ++SYSCALL(pfm_read_pmds) ++SYSCALL(pfm_load_context) ++SYSCALL(pfm_start) ++SYSCALL(pfm_stop) ++SYSCALL(pfm_restart) ++SYSCALL(pfm_create_evtsets) ++SYSCALL(pfm_getinfo_evtsets) ++SYSCALL(pfm_delete_evtsets) ++SYSCALL(pfm_unload_context) +--- a/arch/powerpc/include/asm/thread_info.h ++++ b/arch/powerpc/include/asm/thread_info.h +@@ -130,10 +130,12 @@ static inline struct thread_info *curren + #define _TIF_FREEZE (1< 0x10000 on 4xx/Book-E since it include MSR_CE. + */ + #if MSR_KERNEL >= 0x10000 +-#define LOAD_MSR_KERNEL(r, x) lis r,(x)@h; ori r,r,(x)@l ++#define LOAD_MSR_KERNEL(r, x) lis r,(x)@ha; ori r,r,(x)@l + #else + #define LOAD_MSR_KERNEL(r, x) li r,(x) + #endif +--- a/arch/powerpc/kernel/entry_64.S ++++ b/arch/powerpc/kernel/entry_64.S +@@ -643,6 +643,10 @@ user_work: + b .ret_from_except_lite + + 1: bl .save_nvgprs ++#ifdef CONFIG_PERFMON ++ addi r3,r1,STACK_FRAME_OVERHEAD ++ bl .pfm_handle_work ++#endif /* CONFIG_PERFMON */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_signal + b .ret_from_except +--- a/arch/powerpc/kernel/irq.c ++++ b/arch/powerpc/kernel/irq.c +@@ -104,6 +104,24 @@ static inline notrace void set_soft_enab + : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); + } + ++#ifdef CONFIG_PERFMON ++static inline unsigned long get_pmu_except_pending(void) ++{ ++ unsigned long pending; ++ ++ __asm__ __volatile__("lbz %0,%1(13)" ++ : "=r" (pending) : "i" (offsetof(struct paca_struct, pmu_except_pending))); ++ ++ return pending; ++} ++ ++static inline void set_pmu_except_pending(unsigned long pending) ++{ ++ __asm__ __volatile__("stb %0,%1(13)" ++ : : "r" (pending), "i" (offsetof(struct paca_struct, pmu_except_pending))); ++} ++#endif /* CONFIG_PERFMON */ ++ + notrace void raw_local_irq_restore(unsigned long en) + { + /* +@@ -162,6 +180,19 @@ notrace void raw_local_irq_restore(unsig + lv1_get_version_info(&tmp); + } + ++#ifdef CONFIG_PERFMON ++ /* ++ * If a PMU exception occurred while interrupts were soft disabled, ++ * force a PMU exception. ++ */ ++ if (get_pmu_except_pending()) { ++ set_pmu_except_pending(0); ++ /* Make sure we trigger the edge detection circuitry */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_PMAO); ++ } ++#endif /* CONFIG_PERFMON */ ++ + __hard_irq_enable(); + } + EXPORT_SYMBOL(raw_local_irq_restore); +--- a/arch/powerpc/kernel/process.c ++++ b/arch/powerpc/kernel/process.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -393,9 +394,14 @@ struct task_struct *__switch_to(struct t + new_thread->start_tb = current_tb; + } + #endif +- + local_irq_save(flags); + ++ if (test_tsk_thread_flag(prev, TIF_PERFMON_CTXSW)) ++ pfm_ctxsw_out(prev, new); ++ ++ if (test_tsk_thread_flag(new, TIF_PERFMON_CTXSW)) ++ pfm_ctxsw_in(prev, new); ++ + account_system_vtime(current); + account_process_vtime(current); + calculate_steal_time(); +@@ -544,6 +550,7 @@ void show_regs(struct pt_regs * regs) + void exit_thread(void) + { + discard_lazy_cpu_state(); ++ pfm_exit_thread(); + } + + void flush_thread(void) +@@ -669,6 +676,7 @@ int copy_thread(int nr, unsigned long cl + #else + kregs->nip = (unsigned long)ret_from_fork; + #endif ++ pfm_copy_thread(p); + + return 0; + } +--- /dev/null ++++ b/arch/powerpc/perfmon/Kconfig +@@ -0,0 +1,67 @@ ++menu "Hardware Performance Monitoring support" ++config PERFMON ++ bool "Perfmon2 performance monitoring interface" ++ default n ++ help ++ Enables the perfmon2 interface to access the hardware ++ performance counters. See for ++ more details. ++ ++config PERFMON_DEBUG ++ bool "Perfmon debugging" ++ default n ++ depends on PERFMON ++ help ++ Enables perfmon debugging support ++ ++config PERFMON_DEBUG_FS ++ bool "Enable perfmon statistics reporting via debugfs" ++ default y ++ depends on PERFMON && DEBUG_FS ++ help ++ Enable collection and reporting of perfmon timing statistics under ++ debugfs. This is used for debugging and performance analysis of the ++ subsystem. The debugfs filesystem must be mounted. ++ ++config PERFMON_POWER4 ++ tristate "Support for Power4 hardware performance counters" ++ depends on PERFMON && PPC64 ++ default n ++ help ++ Enables support for the Power 4 hardware performance counters ++ If unsure, say M. ++ ++config PERFMON_POWER5 ++ tristate "Support for Power5 hardware performance counters" ++ depends on PERFMON && PPC64 ++ default n ++ help ++ Enables support for the Power 5 hardware performance counters ++ If unsure, say M. ++ ++config PERFMON_POWER6 ++ tristate "Support for Power6 hardware performance counters" ++ depends on PERFMON && PPC64 ++ default n ++ help ++ Enables support for the Power 6 hardware performance counters ++ If unsure, say M. ++ ++config PERFMON_PPC32 ++ tristate "Support for PPC32 hardware performance counters" ++ depends on PERFMON && PPC32 ++ default n ++ help ++ Enables support for the PPC32 hardware performance counters ++ If unsure, say M. ++ ++config PERFMON_CELL ++ tristate "Support for Cell hardware performance counters" ++ depends on PERFMON && PPC_CELL ++ select PS3_LPM if PPC_PS3 ++ default n ++ help ++ Enables support for the Cell hardware performance counters. ++ If unsure, say M. ++ ++endmenu +--- /dev/null ++++ b/arch/powerpc/perfmon/Makefile +@@ -0,0 +1,6 @@ ++obj-$(CONFIG_PERFMON) += perfmon.o ++obj-$(CONFIG_PERFMON_POWER4) += perfmon_power4.o ++obj-$(CONFIG_PERFMON_POWER5) += perfmon_power5.o ++obj-$(CONFIG_PERFMON_POWER6) += perfmon_power6.o ++obj-$(CONFIG_PERFMON_PPC32) += perfmon_ppc32.o ++obj-$(CONFIG_PERFMON_CELL) += perfmon_cell.o +--- /dev/null ++++ b/arch/powerpc/perfmon/perfmon.c +@@ -0,0 +1,334 @@ ++/* ++ * This file implements the powerpc specific ++ * support for the perfmon2 interface ++ * ++ * Copyright (c) 2005 David Gibson, IBM Corporation. ++ * ++ * based on versions for other architectures: ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++static void pfm_stop_active(struct task_struct *task, ++ struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ BUG_ON(!arch_info->disable_counters || !arch_info->get_ovfl_pmds); ++ ++ arch_info->disable_counters(ctx, set); ++ ++ if (set->npend_ovfls) ++ return; ++ ++ arch_info->get_ovfl_pmds(ctx, set); ++} ++ ++/* ++ * Called from pfm_save_pmds(). Interrupts are masked. Registers are ++ * already saved away. ++ */ ++void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ int i, num; ++ u64 *used_pmds, *intr_pmds; ++ ++ num = set->nused_pmds; ++ used_pmds = set->used_pmds; ++ intr_pmds = ctx->regs.intr_pmds; ++ ++ for (i = 0; num; i++) ++ if (likely(test_bit(i, used_pmds))) { ++ if (likely(test_bit(i, intr_pmds))) ++ pfm_write_pmd(ctx, i, 0); ++ num--; ++ } ++} ++ ++/* ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * Context is locked. Interrupts are masked. Monitoring is active. ++ * PMU access is guaranteed. PMC and PMD registers are live in PMU. ++ * ++ * for per-thread: ++ * must stop monitoring for the task ++ * Return: ++ * non-zero : did not save PMDs (as part of stopping the PMU) ++ * 0 : saved PMDs (no need to save them in caller) ++ */ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ /* ++ * disable lazy restore of the PMC/PMD registers. ++ */ ++ ctx->active_set->priv_flags |= PFM_SETFL_PRIV_MOD_BOTH; ++ ++ if (ctx->state == PFM_CTX_MASKED) ++ return 1; ++ ++ pfm_stop_active(task, ctx, ctx->active_set); ++ ++ if (arch_info->ctxswout_thread) ++ arch_info->ctxswout_thread(task, ctx, ctx->active_set); ++ ++ return pfm_arch_is_active(ctx); ++} ++ ++/* ++ * Called from pfm_ctxsw ++ */ ++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ if (ctx->state != PFM_CTX_MASKED && ctx->flags.started == 1) { ++ BUG_ON(!arch_info->enable_counters); ++ arch_info->enable_counters(ctx, ctx->active_set); ++ } ++ ++ if (arch_info->ctxswin_thread) ++ arch_info->ctxswin_thread(task, ctx, ctx->active_set); ++} ++ ++/* ++ * Called from pfm_stop() and idle notifier ++ * ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-thread: ++ * task is not necessarily current. If not current task, then ++ * task is guaranteed stopped and off any cpu. Access to PMU ++ * is not guaranteed. Interrupts are masked. Context is locked. ++ * Set is the active set. ++ * ++ * For system-wide: ++ * task is current ++ * ++ * must disable active monitoring. ctx cannot be NULL ++ */ ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx) ++{ ++ /* ++ * no need to go through stop_save() ++ * if we are already stopped ++ */ ++ if (!ctx->flags.started || ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ /* ++ * stop live registers and collect pending overflow ++ */ ++ if (task == current) ++ pfm_stop_active(task, ctx, ctx->active_set); ++} ++ ++/* ++ * Enable active monitoring. Called from pfm_start() and ++ * pfm_arch_unmask_monitoring(). ++ * ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-thread: ++ * Task is not necessarily current. If not current task, then task ++ * is guaranteed stopped and off any cpu. No access to PMU if task ++ * is not current. ++ * ++ * For system-wide: ++ * Task is always current ++ */ ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ ++ arch_info = pfm_pmu_info(); ++ if (task != current) ++ return; ++ ++ BUG_ON(!arch_info->enable_counters); ++ ++ arch_info->enable_counters(ctx, ctx->active_set); ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets() ++ * context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMD registers from set. ++ */ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ u64 *used_pmds; ++ u16 i, num; ++ ++ arch_info = pfm_pmu_info(); ++ ++ /* The model-specific module can override the default ++ * restore-PMD method. ++ */ ++ if (arch_info->restore_pmds) ++ return arch_info->restore_pmds(ctx, set); ++ ++ num = set->nused_pmds; ++ used_pmds = set->used_pmds; ++ ++ for (i = 0; num; i++) { ++ if (likely(test_bit(i, used_pmds))) { ++ pfm_write_pmd(ctx, i, set->pmds[i].value); ++ num--; ++ } ++ } ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets() ++ * context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMC registers from set, if needed. ++ */ ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ u64 *impl_pmcs; ++ unsigned int i, max_pmc, reg; ++ ++ arch_info = pfm_pmu_info(); ++ /* The model-specific module can override the default ++ * restore-PMC method. ++ */ ++ if (arch_info->restore_pmcs) ++ return arch_info->restore_pmcs(ctx, set); ++ ++ /* The "common" powerpc model's enable the counters simply by writing ++ * all the control registers. Therefore, if we're masked or stopped we ++ * don't need to bother restoring the PMCs now. ++ */ ++ if (ctx->state == PFM_CTX_MASKED || ctx->flags.started == 0) ++ return; ++ ++ max_pmc = ctx->regs.max_pmc; ++ impl_pmcs = ctx->regs.pmcs; ++ ++ /* ++ * Restore all pmcs in reverse order to ensure the counters aren't ++ * enabled before their event selectors are set correctly. ++ */ ++ reg = max_pmc - 1; ++ for (i = 0; i < max_pmc; i++) { ++ if (test_bit(reg, impl_pmcs)) ++ pfm_arch_write_pmc(ctx, reg, set->pmcs[reg]); ++ reg--; ++ } ++} ++ ++char *pfm_arch_get_pmu_module_name(void) ++{ ++ unsigned int pvr = mfspr(SPRN_PVR); ++ ++ switch (PVR_VER(pvr)) { ++ case 0x0004: /* 604 */ ++ case 0x0009: /* 604e; */ ++ case 0x000A: /* 604ev */ ++ case 0x0008: /* 750/740 */ ++ case 0x7000: /* 750FX */ ++ case 0x7001: ++ case 0x7002: /* 750GX */ ++ case 0x000C: /* 7400 */ ++ case 0x800C: /* 7410 */ ++ case 0x8000: /* 7451/7441 */ ++ case 0x8001: /* 7455/7445 */ ++ case 0x8002: /* 7457/7447 */ ++ case 0x8003: /* 7447A */ ++ case 0x8004: /* 7448 */ ++ return("perfmon_ppc32"); ++ case PV_POWER4: ++ case PV_POWER4p: ++ return "perfmon_power4"; ++ case PV_POWER5: ++ return "perfmon_power5"; ++ case PV_POWER5p: ++ if (PVR_REV(pvr) < 0x300) ++ /* PMU behaves like POWER5 */ ++ return "perfmon_power5"; ++ else ++ /* PMU behaves like POWER6 */ ++ return "perfmon_power6"; ++ case PV_POWER6: ++ return "perfmon_power6"; ++ case PV_970: ++ case PV_970FX: ++ case PV_970MP: ++ return "perfmon_ppc970"; ++ case PV_BE: ++ return "perfmon_cell"; ++ } ++ return NULL; ++} ++ ++void pfm_arch_init_percpu(void) ++{ ++#ifdef CONFIG_PPC64 ++ extern void ppc64_enable_pmcs(void); ++ ppc64_enable_pmcs(); ++#endif ++} ++ ++/** ++ * powerpc_irq_handler ++ * ++ * Get the perfmon context that belongs to the current CPU, and call the ++ * model-specific interrupt handler. ++ **/ ++void powerpc_irq_handler(struct pt_regs *regs) ++{ ++ struct pfm_arch_pmu_info *arch_info; ++ struct pfm_context *ctx; ++ ++ if (! regs->softe) { ++ /* ++ * We got a PMU interrupt while interrupts were soft ++ * disabled. Disable hardware interrupts by clearing ++ * MSR_EE and also clear PMAO because we will need to set ++ * that again later when interrupts are re-enabled and ++ * raw_local_irq_restore() sees that the pmu_except_pending ++ * flag is set. ++ */ ++ regs->msr &= ~MSR_EE; ++ get_paca()->pmu_except_pending = 1; ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); ++ return; ++ } ++ ++ arch_info = pfm_pmu_info(); ++ if (arch_info->irq_handler) { ++ ctx = __get_cpu_var(pmu_ctx); ++ if (likely(ctx)) ++ arch_info->irq_handler(regs, ctx); ++ } ++} +--- /dev/null ++++ b/arch/powerpc/perfmon/perfmon_cell.c +@@ -0,0 +1,1449 @@ ++/* ++ * This file contains the Cell PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright IBM Corporation 2007 ++ * (C) Copyright 2007 TOSHIBA CORPORATION ++ * ++ * Based on other Perfmon2 PMU modules. ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Kevin Corry , " ++ "Carl Love "); ++MODULE_DESCRIPTION("Cell PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++struct pfm_cell_platform_pmu_info { ++ u32 (*read_ctr)(u32 cpu, u32 ctr); ++ void (*write_ctr)(u32 cpu, u32 ctr, u32 val); ++ void (*write_pm07_control)(u32 cpu, u32 ctr, u32 val); ++ void (*write_pm)(u32 cpu, enum pm_reg_name reg, u32 val); ++ void (*enable_pm)(u32 cpu); ++ void (*disable_pm)(u32 cpu); ++ void (*enable_pm_interrupts)(u32 cpu, u32 thread, u32 mask); ++ u32 (*get_and_clear_pm_interrupts)(u32 cpu); ++ u32 (*get_hw_thread_id)(int cpu); ++ struct cbe_ppe_priv_regs __iomem *(*get_cpu_ppe_priv_regs)(int cpu); ++ struct cbe_pmd_regs __iomem *(*get_cpu_pmd_regs)(int cpu); ++ struct cbe_mic_tm_regs __iomem *(*get_cpu_mic_tm_regs)(int cpu); ++ int (*rtas_token)(const char *service); ++ int (*rtas_call)(int token, int param1, int param2, int *param3, ...); ++}; ++ ++/* ++ * Mapping from Perfmon logical control registers to Cell hardware registers. ++ */ ++static struct pfm_regmap_desc pfm_cell_pmc_desc[] = { ++ /* Per-counter control registers. */ ++ PMC_D(PFM_REG_I, "pm0_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm1_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm2_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm3_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm4_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm5_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm6_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm7_control", 0, 0, 0, 0), ++ ++ /* Per-counter RTAS arguments. Each of these registers has three fields. ++ * bits 63-48: debug-bus word ++ * bits 47-32: sub-unit ++ * bits 31-0 : full signal number ++ * (MSB = 63, LSB = 0) ++ */ ++ PMC_D(PFM_REG_I, "pm0_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm1_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm2_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm3_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm4_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm5_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm6_event", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm7_event", 0, 0, 0, 0), ++ ++ /* Global control registers. Same order as enum pm_reg_name. */ ++ PMC_D(PFM_REG_I, "group_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "debug_bus_control", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "trace_address", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "ext_trace_timer", 0, 0, 0, 0), ++ PMC_D(PFM_REG_I, "pm_status", 0, 0, 0, 0), ++ /* set the interrupt overflow bit for the four 32 bit counters ++ * that is currently supported. Will need to fix when 32 and 16 ++ * bit counters are supported. ++ */ ++ PMC_D(PFM_REG_I, "pm_control", 0xF0000000, 0xF0000000, 0, 0), ++ PMC_D(PFM_REG_I, "pm_interval", 0, 0, 0, 0), /* FIX: Does user-space also need read access to this one? */ ++ PMC_D(PFM_REG_I, "pm_start_stop", 0, 0, 0, 0), ++}; ++#define PFM_PM_NUM_PMCS ARRAY_SIZE(pfm_cell_pmc_desc) ++ ++#define CELL_PMC_GROUP_CONTROL 16 ++#define CELL_PMC_PM_STATUS 20 ++#define CELL_PMC_PM_CONTROL 21 ++#define CELL_PMC_PM_CONTROL_CNTR_MASK 0x01E00000UL ++#define CELL_PMC_PM_CONTROL_CNTR_16 0x01E00000UL ++ ++/* ++ * Mapping from Perfmon logical data counters to Cell hardware counters. ++ */ ++static struct pfm_regmap_desc pfm_cell_pmd_desc[] = { ++ PMD_D(PFM_REG_C, "pm0", 0), ++ PMD_D(PFM_REG_C, "pm1", 0), ++ PMD_D(PFM_REG_C, "pm2", 0), ++ PMD_D(PFM_REG_C, "pm3", 0), ++ PMD_D(PFM_REG_C, "pm4", 0), ++ PMD_D(PFM_REG_C, "pm5", 0), ++ PMD_D(PFM_REG_C, "pm6", 0), ++ PMD_D(PFM_REG_C, "pm7", 0), ++}; ++#define PFM_PM_NUM_PMDS ARRAY_SIZE(pfm_cell_pmd_desc) ++ ++#define PFM_EVENT_PMC_BUS_WORD(x) (((x) >> 48) & 0x00ff) ++#define PFM_EVENT_PMC_FULL_SIGNAL_NUMBER(x) ((x) & 0xffffffff) ++#define PFM_EVENT_PMC_SIGNAL_GROUP(x) (((x) & 0xffffffff) / 100) ++#define PFM_PM_CTR_INPUT_MUX_BIT(pm07_control) (((pm07_control) >> 26) & 0x1f) ++#define PFM_PM_CTR_INPUT_MUX_GROUP_INDEX(pm07_control) ((pm07_control) >> 31) ++#define PFM_GROUP_CONTROL_GROUP0_WORD(grp_ctrl) ((grp_ctrl) >> 30) ++#define PFM_GROUP_CONTROL_GROUP1_WORD(grp_ctrl) (((grp_ctrl) >> 28) & 0x3) ++#define PFM_NUM_OF_GROUPS 2 ++#define PFM_PPU_IU1_THREAD1_BASE_BIT 19 ++#define PFM_PPU_XU_THREAD1_BASE_BIT 16 ++#define PFM_COUNTER_CTRL_PMC_PPU_TH0 0x100000000ULL ++#define PFM_COUNTER_CTRL_PMC_PPU_TH1 0x200000000ULL ++ ++/* ++ * Debug-bus signal handling. ++ * ++ * Some Cell systems have firmware that can handle the debug-bus signal ++ * routing. For systems without this firmware, we have a minimal in-kernel ++ * implementation as well. ++ */ ++ ++/* The firmware only sees physical CPUs, so divide by 2 if SMT is on. */ ++#ifdef CONFIG_SCHED_SMT ++#define RTAS_CPU(cpu) ((cpu) / 2) ++#else ++#define RTAS_CPU(cpu) (cpu) ++#endif ++#define RTAS_BUS_WORD(x) (u16)(((x) >> 48) & 0x0000ffff) ++#define RTAS_SUB_UNIT(x) (u16)(((x) >> 32) & 0x0000ffff) ++#define RTAS_SIGNAL_NUMBER(x) (s32)( (x) & 0xffffffff) ++#define RTAS_SIGNAL_GROUP(x) (RTAS_SIGNAL_NUMBER(x) / 100) ++ ++#define subfunc_RESET 1 ++#define subfunc_ACTIVATE 2 ++ ++#define passthru_ENABLE 1 ++#define passthru_DISABLE 2 ++ ++/** ++ * struct cell_rtas_arg ++ * ++ * @cpu: Processor to modify. Linux numbers CPUs based on SMT IDs, but the ++ * firmware only sees the physical CPUs. So this value should be the ++ * SMT ID (from smp_processor_id() or get_cpu()) divided by 2. ++ * @sub_unit: Hardware subunit this applies to (if applicable). ++ * @signal_group: Signal group to enable/disable on the trace bus. ++ * @bus_word: For signal groups that propagate via the trace bus, this trace ++ * bus word will be used. This is a mask of (1 << TraceBusWord). ++ * For other signal groups, this specifies the trigger or event bus. ++ * @bit: Trigger/Event bit, if applicable for the signal group. ++ * ++ * An array of these structures are passed to rtas_call() to set up the ++ * signals on the debug bus. ++ **/ ++struct cell_rtas_arg { ++ u16 cpu; ++ u16 sub_unit; ++ s16 signal_group; ++ u8 bus_word; ++ u8 bit; ++}; ++ ++/** ++ * rtas_reset_signals ++ * ++ * Use the firmware RTAS call to disable signal pass-thru and to reset the ++ * debug-bus signals. ++ **/ ++static int rtas_reset_signals(u32 cpu) ++{ ++ struct cell_rtas_arg signal; ++ u64 real_addr = virt_to_phys(&signal); ++ int rc; ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ memset(&signal, 0, sizeof(signal)); ++ signal.cpu = RTAS_CPU(cpu); ++ rc = info->rtas_call(info->rtas_token("ibm,cbe-perftools"), ++ 5, 1, NULL, ++ subfunc_RESET, ++ passthru_DISABLE, ++ real_addr >> 32, ++ real_addr & 0xffffffff, ++ sizeof(signal)); ++ ++ return rc; ++} ++ ++/** ++ * rtas_activate_signals ++ * ++ * Use the firmware RTAS call to enable signal pass-thru and to activate the ++ * desired signal groups on the debug-bus. ++ **/ ++static int rtas_activate_signals(struct cell_rtas_arg *signals, ++ int num_signals) ++{ ++ u64 real_addr = virt_to_phys(signals); ++ int rc; ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ rc = info->rtas_call(info->rtas_token("ibm,cbe-perftools"), ++ 5, 1, NULL, ++ subfunc_ACTIVATE, ++ passthru_ENABLE, ++ real_addr >> 32, ++ real_addr & 0xffffffff, ++ num_signals * sizeof(*signals)); ++ ++ return rc; ++} ++ ++#define HID1_RESET_MASK (~0x00000001ffffffffUL) ++#define PPU_IU1_WORD0_HID1_EN_MASK (~0x00000001f0c0802cUL) ++#define PPU_IU1_WORD0_HID1_EN_WORD ( 0x00000001f0400000UL) ++#define PPU_IU1_WORD1_HID1_EN_MASK (~0x000000010fc08023UL) ++#define PPU_IU1_WORD1_HID1_EN_WORD ( 0x000000010f400001UL) ++#define PPU_XU_WORD0_HID1_EN_MASK (~0x00000001f038402cUL) ++#define PPU_XU_WORD0_HID1_EN_WORD ( 0x00000001f0080008UL) ++#define PPU_XU_WORD1_HID1_EN_MASK (~0x000000010f074023UL) ++#define PPU_XU_WORD1_HID1_EN_WORD ( 0x000000010f030002UL) ++ ++/* The bus_word field in the cell_rtas_arg structure is a bit-mask ++ * indicating which debug-bus word(s) to use. ++ */ ++enum { ++ BUS_WORD_0 = 1, ++ BUS_WORD_1 = 2, ++ BUS_WORD_2 = 4, ++ BUS_WORD_3 = 8, ++}; ++ ++/* Definitions of the signal-groups that the built-in signal-activation ++ * code can handle. ++ */ ++enum { ++ SIG_GROUP_NONE = 0, ++ ++ /* 2.x PowerPC Processor Unit (PPU) Signal Groups */ ++ SIG_GROUP_PPU_BASE = 20, ++ SIG_GROUP_PPU_IU1 = 21, ++ SIG_GROUP_PPU_XU = 22, ++ ++ /* 3.x PowerPC Storage Subsystem (PPSS) Signal Groups */ ++ SIG_GROUP_PPSS_BASE = 30, ++ ++ /* 4.x Synergistic Processor Unit (SPU) Signal Groups */ ++ SIG_GROUP_SPU_BASE = 40, ++ ++ /* 5.x Memory Flow Controller (MFC) Signal Groups */ ++ SIG_GROUP_MFC_BASE = 50, ++ ++ /* 6.x Element )nterconnect Bus (EIB) Signal Groups */ ++ SIG_GROUP_EIB_BASE = 60, ++ ++ /* 7.x Memory Interface Controller (MIC) Signal Groups */ ++ SIG_GROUP_MIC_BASE = 70, ++ ++ /* 8.x Cell Broadband Engine Interface (BEI) Signal Groups */ ++ SIG_GROUP_BEI_BASE = 80, ++}; ++ ++/** ++ * rmw_spr ++ * ++ * Read-modify-write for a special-purpose-register. ++ **/ ++#define rmw_spr(spr_id, a_mask, o_mask) \ ++ do { \ ++ u64 value = mfspr(spr_id); \ ++ value &= (u64)(a_mask); \ ++ value |= (u64)(o_mask); \ ++ mtspr((spr_id), value); \ ++ } while (0) ++ ++/** ++ * rmw_mmio_reg64 ++ * ++ * Read-modify-write for a 64-bit MMIO register. ++ **/ ++#define rmw_mmio_reg64(mem, a_mask, o_mask) \ ++ do { \ ++ u64 value = in_be64(&(mem)); \ ++ value &= (u64)(a_mask); \ ++ value |= (u64)(o_mask); \ ++ out_be64(&(mem), value); \ ++ } while (0) ++ ++/** ++ * rmwb_mmio_reg64 ++ * ++ * Set or unset a specified bit within a 64-bit MMIO register. ++ **/ ++#define rmwb_mmio_reg64(mem, bit_num, set_bit) \ ++ rmw_mmio_reg64((mem), ~(1UL << (63 - (bit_num))), \ ++ ((set_bit) << (63 - (bit_num)))) ++ ++/** ++ * passthru ++ * ++ * Enable or disable passthru mode in all the Cell signal islands. ++ **/ ++static int passthru(u32 cpu, u64 enable) ++{ ++ struct cbe_ppe_priv_regs __iomem *ppe_priv_regs; ++ struct cbe_pmd_regs __iomem *pmd_regs; ++ struct cbe_mic_tm_regs __iomem *mic_tm_regs; ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ ppe_priv_regs = info->get_cpu_ppe_priv_regs(cpu); ++ pmd_regs = info->get_cpu_pmd_regs(cpu); ++ mic_tm_regs = info->get_cpu_mic_tm_regs(cpu); ++ ++ if (!ppe_priv_regs || !pmd_regs || !mic_tm_regs) { ++ PFM_ERR("Error getting Cell PPE, PMD, and MIC " ++ "register maps: 0x%p, 0x%p, 0x%p", ++ ppe_priv_regs, pmd_regs, mic_tm_regs); ++ return -EINVAL; ++ } ++ ++ rmwb_mmio_reg64(ppe_priv_regs->L2_debug1, 61, enable); ++ rmwb_mmio_reg64(ppe_priv_regs->ciu_dr1, 5, enable); ++ rmwb_mmio_reg64(pmd_regs->on_ramp_trace, 39, enable); ++ rmwb_mmio_reg64(mic_tm_regs->MBL_debug, 20, enable); ++ ++ return 0; ++} ++ ++#define passthru_enable(cpu) passthru(cpu, 1) ++#define passthru_disable(cpu) passthru(cpu, 0) ++ ++static inline void reset_signal_registers(u32 cpu) ++{ ++ rmw_spr(SPRN_HID1, HID1_RESET_MASK, 0); ++} ++ ++/** ++ * celleb_reset_signals ++ * ++ * Non-rtas version of resetting the debug-bus signals. ++ **/ ++static int celleb_reset_signals(u32 cpu) ++{ ++ int rc; ++ rc = passthru_disable(cpu); ++ if (!rc) ++ reset_signal_registers(cpu); ++ return rc; ++} ++ ++/** ++ * ppu_selection ++ * ++ * Write the HID1 register to connect the specified PPU signal-group to the ++ * debug-bus. ++ **/ ++static int ppu_selection(struct cell_rtas_arg *signal) ++{ ++ u64 hid1_enable_word = 0; ++ u64 hid1_enable_mask = 0; ++ ++ switch (signal->signal_group) { ++ ++ case SIG_GROUP_PPU_IU1: /* 2.1 PPU Instruction Unit - Group 1 */ ++ switch (signal->bus_word) { ++ case BUS_WORD_0: ++ hid1_enable_mask = PPU_IU1_WORD0_HID1_EN_MASK; ++ hid1_enable_word = PPU_IU1_WORD0_HID1_EN_WORD; ++ break; ++ case BUS_WORD_1: ++ hid1_enable_mask = PPU_IU1_WORD1_HID1_EN_MASK; ++ hid1_enable_word = PPU_IU1_WORD1_HID1_EN_WORD; ++ break; ++ default: ++ PFM_ERR("Invalid bus-word (0x%x) for signal-group %d.", ++ signal->bus_word, signal->signal_group); ++ return -EINVAL; ++ } ++ break; ++ ++ case SIG_GROUP_PPU_XU: /* 2.2 PPU Execution Unit */ ++ switch (signal->bus_word) { ++ case BUS_WORD_0: ++ hid1_enable_mask = PPU_XU_WORD0_HID1_EN_MASK; ++ hid1_enable_word = PPU_XU_WORD0_HID1_EN_WORD; ++ break; ++ case BUS_WORD_1: ++ hid1_enable_mask = PPU_XU_WORD1_HID1_EN_MASK; ++ hid1_enable_word = PPU_XU_WORD1_HID1_EN_WORD; ++ break; ++ default: ++ PFM_ERR("Invalid bus-word (0x%x) for signal-group %d.", ++ signal->bus_word, signal->signal_group); ++ return -EINVAL; ++ } ++ break; ++ ++ default: ++ PFM_ERR("Signal-group %d not implemented.", ++ signal->signal_group); ++ return -EINVAL; ++ } ++ ++ rmw_spr(SPRN_HID1, hid1_enable_mask, hid1_enable_word); ++ ++ return 0; ++} ++ ++/** ++ * celleb_activate_signals ++ * ++ * Non-rtas version of activating the debug-bus signals. ++ **/ ++static int celleb_activate_signals(struct cell_rtas_arg *signals, ++ int num_signals) ++{ ++ int i, rc = -EINVAL; ++ ++ for (i = 0; i < num_signals; i++) { ++ switch (signals[i].signal_group) { ++ ++ /* 2.x PowerPC Processor Unit (PPU) Signal Selection */ ++ case SIG_GROUP_PPU_IU1: ++ case SIG_GROUP_PPU_XU: ++ rc = ppu_selection(signals + i); ++ if (rc) ++ return rc; ++ break; ++ ++ default: ++ PFM_ERR("Signal-group %d not implemented.", ++ signals[i].signal_group); ++ return -EINVAL; ++ } ++ } ++ ++ if (0 < i) ++ rc = passthru_enable(signals[0].cpu); ++ ++ return rc; ++} ++ ++/** ++ * ps3_reset_signals ++ * ++ * ps3 version of resetting the debug-bus signals. ++ **/ ++static int ps3_reset_signals(u32 cpu) ++{ ++#ifdef CONFIG_PPC_PS3 ++ return ps3_set_signal(0, 0, 0, 0); ++#else ++ return 0; ++#endif ++} ++ ++/** ++ * ps3_activate_signals ++ * ++ * ps3 version of activating the debug-bus signals. ++ **/ ++static int ps3_activate_signals(struct cell_rtas_arg *signals, ++ int num_signals) ++{ ++#ifdef CONFIG_PPC_PS3 ++ int i; ++ ++ for (i = 0; i < num_signals; i++) ++ ps3_set_signal(signals[i].signal_group, signals[i].bit, ++ signals[i].sub_unit, signals[i].bus_word); ++#endif ++ return 0; ++} ++ ++ ++/** ++ * reset_signals ++ * ++ * Call to the firmware (if available) to reset the debug-bus signals. ++ * Otherwise call the built-in version. ++ **/ ++int reset_signals(u32 cpu) ++{ ++ int rc; ++ ++ if (machine_is(celleb)) ++ rc = celleb_reset_signals(cpu); ++ else if (machine_is(ps3)) ++ rc = ps3_reset_signals(cpu); ++ else ++ rc = rtas_reset_signals(cpu); ++ ++ return rc; ++} ++ ++/** ++ * activate_signals ++ * ++ * Call to the firmware (if available) to activate the debug-bus signals. ++ * Otherwise call the built-in version. ++ **/ ++int activate_signals(struct cell_rtas_arg *signals, int num_signals) ++{ ++ int rc; ++ ++ if (machine_is(celleb)) ++ rc = celleb_activate_signals(signals, num_signals); ++ else if (machine_is(ps3)) ++ rc = ps3_activate_signals(signals, num_signals); ++ else ++ rc = rtas_activate_signals(signals, num_signals); ++ ++ return rc; ++} ++ ++/** ++ * pfm_cell_pmc_check ++ * ++ * Verify that we are going to write a valid value to the specified PMC. ++ **/ ++int pfm_cell_pmc_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++ u16 cnum, reg_num = req->reg_num; ++ s16 signal_group = RTAS_SIGNAL_GROUP(req->reg_value); ++ u8 bus_word = RTAS_BUS_WORD(req->reg_value); ++ ++ if (reg_num < NR_CTRS || reg_num >= (NR_CTRS * 2)) ++ return -EINVAL; ++ ++ switch (signal_group) { ++ case SIG_GROUP_PPU_IU1: ++ case SIG_GROUP_PPU_XU: ++ if ((bus_word != 0) && (bus_word != 1)) { ++ PFM_ERR("Invalid bus word (%d) for signal-group %d", ++ bus_word, signal_group); ++ return -EINVAL; ++ } ++ break; ++ default: ++ PFM_ERR("Signal-group %d not implemented.", signal_group); ++ return -EINVAL; ++ } ++ ++ for (cnum = NR_CTRS; cnum < (NR_CTRS * 2); cnum++) { ++ if (test_bit(cnum, cast_ulp(set->used_pmcs)) && ++ bus_word == RTAS_BUS_WORD(set->pmcs[cnum]) && ++ signal_group != RTAS_SIGNAL_GROUP(set->pmcs[cnum])) { ++ PFM_ERR("Impossible signal-group combination: " ++ "(%u,%u,%d) (%u,%u,%d)", ++ reg_num, bus_word, signal_group, cnum, ++ RTAS_BUS_WORD(set->pmcs[cnum]), ++ RTAS_SIGNAL_GROUP(set->pmcs[cnum])); ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * write_pm07_event ++ * ++ * Pull out the RTAS arguments from the 64-bit register value and make the ++ * RTAS activate-signals call. ++ **/ ++static void write_pm07_event(int cpu, unsigned int ctr, u64 value) ++{ ++ struct cell_rtas_arg signal; ++ s32 signal_number; ++ int rc; ++ ++ signal_number = RTAS_SIGNAL_NUMBER(value); ++ if (!signal_number) { ++ /* Don't include counters that are counting cycles. */ ++ return; ++ } ++ ++ signal.cpu = RTAS_CPU(cpu); ++ signal.bus_word = 1 << RTAS_BUS_WORD(value); ++ signal.sub_unit = RTAS_SUB_UNIT(value); ++ signal.signal_group = signal_number / 100; ++ signal.bit = abs(signal_number) % 100; ++ ++ rc = activate_signals(&signal, 1); ++ if (rc) { ++ PFM_WARN("%s(%d, %u, %lu): Error calling " ++ "activate_signals(): %d\n", __func__, ++ cpu, ctr, (unsigned long)value, rc); ++ /* FIX: Could we change this routine to return an error? */ ++ } ++} ++ ++/** ++ * pfm_cell_probe_pmu ++ * ++ * Simply check the processor version register to see if we're currently ++ * on a Cell system. ++ **/ ++static int pfm_cell_probe_pmu(void) ++{ ++ unsigned long pvr = mfspr(SPRN_PVR); ++ ++ if (PVR_VER(pvr) != PV_BE) ++ return -1; ++ ++ return 0; ++} ++ ++/** ++ * pfm_cell_write_pmc ++ **/ ++static void pfm_cell_write_pmc(unsigned int cnum, u64 value) ++{ ++ int cpu = smp_processor_id(); ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ if (cnum < NR_CTRS) { ++ info->write_pm07_control(cpu, cnum, value); ++ ++ } else if (cnum < NR_CTRS * 2) { ++ write_pm07_event(cpu, cnum - NR_CTRS, value); ++ ++ } else if (cnum == CELL_PMC_PM_STATUS) { ++ /* The pm_status register must be treated separately from ++ * the other "global" PMCs. This call will ensure that ++ * the interrupts are routed to the correct CPU, as well ++ * as writing the desired value to the pm_status register. ++ */ ++ info->enable_pm_interrupts(cpu, info->get_hw_thread_id(cpu), ++ value); ++ ++ } else if (cnum < PFM_PM_NUM_PMCS) { ++ info->write_pm(cpu, cnum - (NR_CTRS * 2), value); ++ } ++} ++ ++/** ++ * pfm_cell_write_pmd ++ **/ ++static void pfm_cell_write_pmd(unsigned int cnum, u64 value) ++{ ++ int cpu = smp_processor_id(); ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ if (cnum < NR_CTRS) ++ info->write_ctr(cpu, cnum, value); ++} ++ ++/** ++ * pfm_cell_read_pmd ++ **/ ++static u64 pfm_cell_read_pmd(unsigned int cnum) ++{ ++ int cpu = smp_processor_id(); ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ if (cnum < NR_CTRS) ++ return info->read_ctr(cpu, cnum); ++ ++ return -EINVAL; ++} ++ ++/** ++ * pfm_cell_enable_counters ++ * ++ * Just need to turn on the global disable bit in pm_control. ++ **/ ++static void pfm_cell_enable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ info->enable_pm(smp_processor_id()); ++} ++ ++/** ++ * pfm_cell_disable_counters ++ * ++ * Just need to turn off the global disable bit in pm_control. ++ **/ ++static void pfm_cell_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ info->disable_pm(smp_processor_id()); ++ if (machine_is(ps3)) ++ reset_signals(smp_processor_id()); ++} ++ ++/* ++ * Return the thread id of the specified ppu signal. ++ */ ++static inline u32 get_target_ppu_thread_id(u32 group, u32 bit) ++{ ++ if ((group == SIG_GROUP_PPU_IU1 && ++ bit < PFM_PPU_IU1_THREAD1_BASE_BIT) || ++ (group == SIG_GROUP_PPU_XU && ++ bit < PFM_PPU_XU_THREAD1_BASE_BIT)) ++ return 0; ++ else ++ return 1; ++} ++ ++/* ++ * Return whether the specified counter is for PPU signal group. ++ */ ++static inline int is_counter_for_ppu_sig_grp(u32 counter_control, u32 sig_grp) ++{ ++ if (!(counter_control & CBE_PM_CTR_INPUT_CONTROL) && ++ (counter_control & CBE_PM_CTR_ENABLE) && ++ ((sig_grp == SIG_GROUP_PPU_IU1) || (sig_grp == SIG_GROUP_PPU_XU))) ++ return 1; ++ else ++ return 0; ++} ++ ++/* ++ * Search ppu signal groups. ++ */ ++static int get_ppu_signal_groups(struct pfm_event_set *set, ++ u32 *ppu_sig_grp0, u32 *ppu_sig_grp1) ++{ ++ u64 pm_event, *used_pmcs = set->used_pmcs; ++ int i, j; ++ u32 grp0_wd, grp1_wd, wd, sig_grp; ++ ++ *ppu_sig_grp0 = 0; ++ *ppu_sig_grp1 = 0; ++ grp0_wd = PFM_GROUP_CONTROL_GROUP0_WORD( ++ set->pmcs[CELL_PMC_GROUP_CONTROL]); ++ grp1_wd = PFM_GROUP_CONTROL_GROUP1_WORD( ++ set->pmcs[CELL_PMC_GROUP_CONTROL]); ++ ++ for (i = 0, j = 0; (i < NR_CTRS) && (j < PFM_NUM_OF_GROUPS); i++) { ++ if (test_bit(i + NR_CTRS, used_pmcs)) { ++ pm_event = set->pmcs[i + NR_CTRS]; ++ wd = PFM_EVENT_PMC_BUS_WORD(pm_event); ++ sig_grp = PFM_EVENT_PMC_SIGNAL_GROUP(pm_event); ++ if ((sig_grp == SIG_GROUP_PPU_IU1) || ++ (sig_grp == SIG_GROUP_PPU_XU)) { ++ ++ if (wd == grp0_wd && *ppu_sig_grp0 == 0) { ++ *ppu_sig_grp0 = sig_grp; ++ j++; ++ } else if (wd == grp1_wd && ++ *ppu_sig_grp1 == 0) { ++ *ppu_sig_grp1 = sig_grp; ++ j++; ++ } ++ } ++ } ++ } ++ return j; ++} ++ ++/** ++ * pfm_cell_restore_pmcs ++ * ++ * Write all control register values that are saved in the specified event ++ * set. We could use the pfm_arch_write_pmc() function to restore each PMC ++ * individually (as is done in other architectures), but that results in ++ * multiple RTAS calls. As an optimization, we will setup the RTAS argument ++ * array so we can do all event-control registers in one RTAS call. ++ * ++ * In per-thread mode, ++ * The counter enable bit of the pmX_control PMC is enabled while the target ++ * task runs on the target HW thread. ++ **/ ++void pfm_cell_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 ctr_ctrl; ++ u64 *used_pmcs = set->used_pmcs; ++ int i; ++ int cpu = smp_processor_id(); ++ u32 current_th_id; ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ for (i = 0; i < NR_CTRS; i++) { ++ ctr_ctrl = set->pmcs[i]; ++ ++ if (ctr_ctrl & PFM_COUNTER_CTRL_PMC_PPU_TH0) { ++ current_th_id = info->get_hw_thread_id(cpu); ++ ++ /* ++ * Set the counter enable bit down if the current ++ * HW thread is NOT 0 ++ **/ ++ if (current_th_id) ++ ctr_ctrl = ctr_ctrl & ~CBE_PM_CTR_ENABLE; ++ ++ } else if (ctr_ctrl & PFM_COUNTER_CTRL_PMC_PPU_TH1) { ++ current_th_id = info->get_hw_thread_id(cpu); ++ ++ /* ++ * Set the counter enable bit down if the current ++ * HW thread is 0 ++ **/ ++ if (!current_th_id) ++ ctr_ctrl = ctr_ctrl & ~CBE_PM_CTR_ENABLE; ++ } ++ ++ /* Write the per-counter control register. If the PMC is not ++ * in use, then it will simply clear the register, which will ++ * disable the associated counter. ++ */ ++ info->write_pm07_control(cpu, i, ctr_ctrl); ++ ++ if (test_bit(i + NR_CTRS, used_pmcs)) ++ write_pm07_event(cpu, 0, set->pmcs[i + NR_CTRS]); ++ } ++ ++ /* Write all the global PMCs. Need to call pfm_cell_write_pmc() ++ * instead of cbe_write_pm() due to special handling for the ++ * pm_status register. ++ */ ++ for (i *= 2; i < PFM_PM_NUM_PMCS; i++) ++ pfm_cell_write_pmc(i, set->pmcs[i]); ++} ++ ++/** ++ * pfm_cell_restore_pmds ++ * ++ * Write to pm_control register before writing to counter registers ++ * so that we can decide the counter width berfore writing to the couters. ++ **/ ++void pfm_cell_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 *used_pmds; ++ unsigned int i, max_pmd; ++ int cpu = smp_processor_id(); ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ /* ++ * Write pm_control register value ++ */ ++ info->write_pm(cpu, pm_control, ++ set->pmcs[CELL_PMC_PM_CONTROL] & ++ ~CBE_PM_ENABLE_PERF_MON); ++ PFM_DBG("restore pm_control(0x%lx) before restoring pmds", ++ set->pmcs[CELL_PMC_PM_CONTROL]); ++ ++ max_pmd = ctx->regs.max_pmd; ++ used_pmds = set->used_pmds; ++ ++ for (i = 0; i < max_pmd; i++) ++ if (test_bit(i, used_pmds) && ++ !(pfm_pmu_conf->pmd_desc[i].type & PFM_REG_RO)) ++ pfm_cell_write_pmd(i, set->pmds[i].value); ++} ++ ++/** ++ * pfm_cell_get_cntr_width ++ * ++ * This function check the 16bit counter field in pm_control pmc. ++ * ++ * Return value ++ * 16 : all counters are 16bit width. ++ * 32 : all counters are 32bit width. ++ * 0 : several counter width exists. ++ **/ ++static int pfm_cell_get_cntr_width(struct pfm_context *ctx, ++ struct pfm_event_set *s) ++{ ++ int width = 0; ++ int tmp = 0; ++ u64 cntr_field; ++ ++ if (ctx->flags.switch_ovfl || ctx->flags.switch_time) { ++ list_for_each_entry(s, &ctx->set_list, list) { ++ cntr_field = s->pmcs[CELL_PMC_PM_CONTROL] & ++ CELL_PMC_PM_CONTROL_CNTR_MASK; ++ ++ if (cntr_field == CELL_PMC_PM_CONTROL_CNTR_16) ++ tmp = 16; ++ else if (cntr_field == 0x0) ++ tmp = 32; ++ else ++ return 0; ++ ++ if (tmp != width && width != 0) ++ return 0; ++ ++ width = tmp; ++ } ++ } else { ++ cntr_field = s->pmcs[CELL_PMC_PM_CONTROL] & ++ CELL_PMC_PM_CONTROL_CNTR_MASK; ++ ++ if (cntr_field == CELL_PMC_PM_CONTROL_CNTR_16) ++ width = 16; ++ else if (cntr_field == 0x0) ++ width = 32; ++ else ++ width = 0; ++ } ++ return width; ++} ++ ++/** ++ * pfm_cell_check_cntr_ovfl_mask ++ * ++ * Return value ++ * 1 : cntr_ovfl interrupt is used. ++ * 0 : cntr_ovfl interrupt is not used. ++ **/ ++static int pfm_cell_check_cntr_ovfl(struct pfm_context *ctx, ++ struct pfm_event_set *s) ++{ ++ if (ctx->flags.switch_ovfl || ctx->flags.switch_time) { ++ list_for_each_entry(s, &ctx->set_list, list) { ++ if (CBE_PM_OVERFLOW_CTRS(s->pmcs[CELL_PMC_PM_STATUS])) ++ return 1; ++ } ++ } else { ++ if (CBE_PM_OVERFLOW_CTRS(s->pmcs[CELL_PMC_PM_STATUS])) ++ return 1; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PPC_PS3 ++/** ++ * update_sub_unit_field ++ * ++ **/ ++static inline u64 update_sub_unit_field(u64 pm_event, u64 spe_id) ++{ ++ return ((pm_event & 0xFFFF0000FFFFFFFF) | (spe_id << 32)); ++} ++ ++/** ++ * pfm_get_spe_id ++ * ++ **/ ++static u64 pfm_get_spe_id(void *arg) ++{ ++ struct spu *spu = arg; ++ u64 spe_id; ++ ++ if (machine_is(ps3)) ++ spe_id = ps3_get_spe_id(arg); ++ else ++ spe_id = spu->spe_id; ++ ++ return spe_id; ++} ++ ++/** ++ * pfm_spu_number_to_id ++ * ++ **/ ++static int pfm_spu_number_to_id(int number, u64 *spe_id) ++{ ++ struct spu *spu; ++ int i; ++ ++ for (i = 0; i < MAX_NUMNODES; i++) { ++ if (cbe_spu_info[i].n_spus == 0) ++ continue; ++ ++ list_for_each_entry(spu, &cbe_spu_info[i].spus, cbe_list) ++ if (spu->number == number) { ++ *spe_id = pfm_get_spe_id(spu); ++ return 0; ++ } ++ } ++ return -ENODEV; ++} ++ ++/** ++ * pfm_update_pmX_event_subunit_field ++ * ++ * In system wide mode, ++ * This function updates the subunit field of SPE pmX_event. ++ **/ ++static int pfm_update_pmX_event_subunit_field(struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ int i, last_pmc, ret; ++ u64 signal_group, spe_id; ++ int sub_unit; ++ u64 *used_pmcs; ++ ++ last_pmc = NR_CTRS + 8; ++ ret = 0; ++ list_for_each_entry(set, &ctx->set_list, list) { ++ ++ used_pmcs = set->used_pmcs; ++ for (i = NR_CTRS; i < last_pmc; i++) { ++ if (!test_bit(i, used_pmcs)) ++ continue; ++ ++ signal_group = PFM_EVENT_PMC_SIGNAL_GROUP(set->pmcs[i]); ++ ++ /* ++ * If the target event is a SPE signal group event, ++ * The sub_unit field in pmX_event pmc is changed to the ++ * specified spe_id. ++ */ ++ if (SIG_GROUP_SPU_BASE < signal_group && ++ signal_group < SIG_GROUP_EIB_BASE) { ++ sub_unit = RTAS_SUB_UNIT(set->pmcs[i]); ++ ++ ret = pfm_spu_number_to_id(sub_unit, &spe_id); ++ if (ret) ++ return ret; ++ ++ set->pmcs[i] = update_sub_unit_field( ++ set->pmcs[i], spe_id); ++ } ++ } ++ } ++ return 0; ++} ++#endif ++ ++/** ++ * pfm_cell_load_context ++ * ++ * In per-thread mode, ++ * The pmX_control PMCs which are used for PPU IU/XU event are marked with ++ * the thread id(PFM_COUNTER_CTRL_PMC_PPU_TH0/TH1). ++ **/ ++static int pfm_cell_load_context(struct pfm_context *ctx) ++{ ++ int i; ++ u32 ppu_sig_grp[PFM_NUM_OF_GROUPS] = {SIG_GROUP_NONE, SIG_GROUP_NONE}; ++ u32 bit; ++ int index; ++ u32 target_th_id; ++ int ppu_sig_num = 0; ++ struct pfm_event_set *s; ++ int cntr_width = 32; ++ int ret = 0; ++ ++ if (pfm_cell_check_cntr_ovfl(ctx, ctx->active_set)) { ++ cntr_width = pfm_cell_get_cntr_width(ctx, ctx->active_set); ++ ++ /* ++ * Counter overflow interrupt works with only 32bit counter, ++ * because perfmon core uses pfm_cell_pmu_conf.counter_width ++ * to deal with the counter overflow. we can't change the ++ * counter width here. ++ */ ++ if (cntr_width != 32) ++ return -EINVAL; ++ } ++ ++ if (ctx->flags.system) { ++#ifdef CONFIG_PPC_PS3 ++ if (machine_is(ps3)) ++ ret = pfm_update_pmX_event_subunit_field(ctx); ++#endif ++ return ret; ++ } ++ ++ list_for_each_entry(s, &ctx->set_list, list) { ++ ppu_sig_num = get_ppu_signal_groups(s, &ppu_sig_grp[0], ++ &ppu_sig_grp[1]); ++ ++ for (i = 0; i < NR_CTRS; i++) { ++ index = PFM_PM_CTR_INPUT_MUX_GROUP_INDEX(s->pmcs[i]); ++ if (ppu_sig_num && ++ (ppu_sig_grp[index] != SIG_GROUP_NONE) && ++ is_counter_for_ppu_sig_grp(s->pmcs[i], ++ ppu_sig_grp[index])) { ++ ++ bit = PFM_PM_CTR_INPUT_MUX_BIT(s->pmcs[i]); ++ target_th_id = get_target_ppu_thread_id( ++ ppu_sig_grp[index], bit); ++ if (!target_th_id) ++ s->pmcs[i] |= ++ PFM_COUNTER_CTRL_PMC_PPU_TH0; ++ else ++ s->pmcs[i] |= ++ PFM_COUNTER_CTRL_PMC_PPU_TH1; ++ PFM_DBG("set:%d mark ctr:%d target_thread:%d", ++ s->id, i, target_th_id); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++/** ++ * pfm_cell_unload_context ++ * ++ * For system-wide contexts and self-monitored contexts, make the RTAS call ++ * to reset the debug-bus signals. ++ * ++ * For non-self-monitored contexts, the monitored thread will already have ++ * been taken off the CPU and we don't need to do anything additional. ++ **/ ++static void pfm_cell_unload_context(struct pfm_context *ctx) ++{ ++ if (ctx->task == current || ctx->flags.system) ++ reset_signals(smp_processor_id()); ++} ++ ++/** ++ * pfm_cell_ctxswout_thread ++ * ++ * When a monitored thread is switched out (self-monitored or externally ++ * monitored) we need to reset the debug-bus signals so the next context that ++ * gets switched in can start from a clean set of signals. ++ **/ ++int pfm_cell_ctxswout_thread(struct task_struct *task, ++ struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ reset_signals(smp_processor_id()); ++ return 0; ++} ++ ++/** ++ * pfm_cell_get_ovfl_pmds ++ * ++ * Determine which counters in this set have overflowed and fill in the ++ * set->povfl_pmds mask and set->npend_ovfls count. On Cell, the pm_status ++ * register contains a bit for each counter to indicate overflow. However, ++ * those 8 bits are in the reverse order than what Perfmon2 is expecting, ++ * so we need to reverse the order of the overflow bits. ++ **/ ++static void pfm_cell_get_ovfl_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx); ++ u32 pm_status, ovfl_ctrs; ++ u64 povfl_pmds = 0; ++ int i; ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ if (!ctx_arch->last_read_updated) ++ /* This routine was not called via the interrupt handler. ++ * Need to start by getting interrupts and updating ++ * last_read_pm_status. ++ */ ++ ctx_arch->last_read_pm_status = ++ info->get_and_clear_pm_interrupts(smp_processor_id()); ++ ++ /* Reset the flag that the interrupt handler last read pm_status. */ ++ ctx_arch->last_read_updated = 0; ++ ++ pm_status = ctx_arch->last_read_pm_status & ++ set->pmcs[CELL_PMC_PM_STATUS]; ++ ovfl_ctrs = CBE_PM_OVERFLOW_CTRS(pm_status); ++ ++ /* Reverse the order of the bits in ovfl_ctrs ++ * and store the result in povfl_pmds. ++ */ ++ for (i = 0; i < PFM_PM_NUM_PMDS; i++) { ++ povfl_pmds = (povfl_pmds << 1) | (ovfl_ctrs & 1); ++ ovfl_ctrs >>= 1; ++ } ++ ++ /* Mask povfl_pmds with set->used_pmds to get set->povfl_pmds. ++ * Count the bits set in set->povfl_pmds to get set->npend_ovfls. ++ */ ++ bitmap_and(set->povfl_pmds, &povfl_pmds, ++ set->used_pmds, PFM_PM_NUM_PMDS); ++ set->npend_ovfls = bitmap_weight(set->povfl_pmds, PFM_PM_NUM_PMDS); ++} ++ ++/** ++ * pfm_cell_acquire_pmu ++ * ++ * acquire PMU resource. ++ * This acquisition is done when the first context is created. ++ **/ ++int pfm_cell_acquire_pmu(u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++#ifdef CONFIG_PPC_PS3 ++ int ret; ++ ++ if (machine_is(ps3)) { ++ PFM_DBG(""); ++ ret = ps3_lpm_open(PS3_LPM_TB_TYPE_INTERNAL, NULL, 0); ++ if (ret) { ++ PFM_ERR("Can't create PS3 lpm. error:%d", ret); ++ return -EFAULT; ++ } ++ } ++#endif ++ return 0; ++} ++ ++/** ++ * pfm_cell_release_pmu ++ * ++ * release PMU resource. ++ * actual release happens when last context is destroyed ++ **/ ++void pfm_cell_release_pmu(void) ++{ ++#ifdef CONFIG_PPC_PS3 ++ if (machine_is(ps3)) { ++ if (ps3_lpm_close()) ++ PFM_ERR("Can't delete PS3 lpm."); ++ } ++#endif ++} ++ ++/** ++ * handle_trace_buffer_interrupts ++ * ++ * This routine is for processing just the interval timer and trace buffer ++ * overflow interrupts. Performance counter interrupts are handled by the ++ * perf_irq_handler() routine, which reads and saves the pm_status register. ++ * This routine should not read the actual pm_status register, but rather ++ * the value passed in. ++ **/ ++static void handle_trace_buffer_interrupts(unsigned long iip, ++ struct pt_regs *regs, ++ struct pfm_context *ctx, ++ u32 pm_status) ++{ ++ /* FIX: Currently ignoring trace-buffer interrupts. */ ++ return; ++} ++ ++/** ++ * pfm_cell_irq_handler ++ * ++ * Handler for all Cell performance-monitor interrupts. ++ **/ ++static void pfm_cell_irq_handler(struct pt_regs *regs, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx); ++ u32 last_read_pm_status; ++ int cpu = smp_processor_id(); ++ struct pfm_cell_platform_pmu_info *info = ++ ((struct pfm_arch_pmu_info *) ++ (pfm_pmu_conf->pmu_info))->platform_info; ++ ++ /* Need to disable and reenable the performance counters to get the ++ * desired behavior from the hardware. This is specific to the Cell ++ * PMU hardware. ++ */ ++ info->disable_pm(cpu); ++ ++ /* Read the pm_status register to get the interrupt bits. If a ++ * perfmormance counter overflow interrupt occurred, call the core ++ * perfmon interrupt handler to service the counter overflow. If the ++ * interrupt was for the interval timer or the trace_buffer, ++ * call the interval timer and trace buffer interrupt handler. ++ * ++ * The value read from the pm_status register is stored in the ++ * pmf_arch_context structure for use by other routines. Note that ++ * reading the pm_status register resets the interrupt flags to zero. ++ * Hence, it is important that the register is only read in one place. ++ * ++ * The pm_status reg interrupt reg format is: ++ * [pmd0:pmd1:pmd2:pmd3:pmd4:pmd5:pmd6:pmd7:intt:tbf:tbu:] ++ * - pmd0 to pm7 are the perf counter overflow interrupts. ++ * - intt is the interval timer overflowed interrupt. ++ * - tbf is the trace buffer full interrupt. ++ * - tbu is the trace buffer underflow interrupt. ++ * - The pmd0 bit is the MSB of the 32 bit register. ++ */ ++ ctx_arch->last_read_pm_status = last_read_pm_status = ++ info->get_and_clear_pm_interrupts(cpu); ++ ++ /* Set flag for pfm_cell_get_ovfl_pmds() routine so it knows ++ * last_read_pm_status was updated by the interrupt handler. ++ */ ++ ctx_arch->last_read_updated = 1; ++ ++ if (last_read_pm_status & CBE_PM_ALL_OVERFLOW_INTR) ++ /* At least one counter overflowed. */ ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++ ++ if (last_read_pm_status & (CBE_PM_INTERVAL_INTR | ++ CBE_PM_TRACE_BUFFER_FULL_INTR | ++ CBE_PM_TRACE_BUFFER_UNDERFLOW_INTR)) ++ /* Trace buffer or interval timer overflow. */ ++ handle_trace_buffer_interrupts(instruction_pointer(regs), ++ regs, ctx, last_read_pm_status); ++ ++ /* The interrupt settings is the value written to the pm_status ++ * register. It is saved in the context when the register is ++ * written. ++ */ ++ info->enable_pm_interrupts(cpu, info->get_hw_thread_id(cpu), ++ ctx->active_set->pmcs[CELL_PMC_PM_STATUS]); ++ ++ /* The writes to the various performance counters only writes to a ++ * latch. The new values (interrupt setting bits, reset counter value ++ * etc.) are not copied to the actual registers until the performance ++ * monitor is enabled. In order to get this to work as desired, the ++ * permormance monitor needs to be disabled while writting to the ++ * latches. This is a HW design issue. ++ */ ++ info->enable_pm(cpu); ++} ++ ++ ++static struct pfm_cell_platform_pmu_info ps3_platform_pmu_info = { ++#ifdef CONFIG_PPC_PS3 ++ .read_ctr = ps3_read_ctr, ++ .write_ctr = ps3_write_ctr, ++ .write_pm07_control = ps3_write_pm07_control, ++ .write_pm = ps3_write_pm, ++ .enable_pm = ps3_enable_pm, ++ .disable_pm = ps3_disable_pm, ++ .enable_pm_interrupts = ps3_enable_pm_interrupts, ++ .get_and_clear_pm_interrupts = ps3_get_and_clear_pm_interrupts, ++ .get_hw_thread_id = ps3_get_hw_thread_id, ++ .get_cpu_ppe_priv_regs = NULL, ++ .get_cpu_pmd_regs = NULL, ++ .get_cpu_mic_tm_regs = NULL, ++ .rtas_token = NULL, ++ .rtas_call = NULL, ++#endif ++}; ++ ++static struct pfm_cell_platform_pmu_info native_platform_pmu_info = { ++#ifdef CONFIG_PPC_CELL_NATIVE ++ .read_ctr = cbe_read_ctr, ++ .write_ctr = cbe_write_ctr, ++ .write_pm07_control = cbe_write_pm07_control, ++ .write_pm = cbe_write_pm, ++ .enable_pm = cbe_enable_pm, ++ .disable_pm = cbe_disable_pm, ++ .enable_pm_interrupts = cbe_enable_pm_interrupts, ++ .get_and_clear_pm_interrupts = cbe_get_and_clear_pm_interrupts, ++ .get_hw_thread_id = cbe_get_hw_thread_id, ++ .get_cpu_ppe_priv_regs = cbe_get_cpu_ppe_priv_regs, ++ .get_cpu_pmd_regs = cbe_get_cpu_pmd_regs, ++ .get_cpu_mic_tm_regs = cbe_get_cpu_mic_tm_regs, ++ .rtas_token = rtas_token, ++ .rtas_call = rtas_call, ++#endif ++}; ++ ++static struct pfm_arch_pmu_info pfm_cell_pmu_info = { ++ .pmu_style = PFM_POWERPC_PMU_CELL, ++ .acquire_pmu = pfm_cell_acquire_pmu, ++ .release_pmu = pfm_cell_release_pmu, ++ .write_pmc = pfm_cell_write_pmc, ++ .write_pmd = pfm_cell_write_pmd, ++ .read_pmd = pfm_cell_read_pmd, ++ .enable_counters = pfm_cell_enable_counters, ++ .disable_counters = pfm_cell_disable_counters, ++ .irq_handler = pfm_cell_irq_handler, ++ .get_ovfl_pmds = pfm_cell_get_ovfl_pmds, ++ .restore_pmcs = pfm_cell_restore_pmcs, ++ .restore_pmds = pfm_cell_restore_pmds, ++ .ctxswout_thread = pfm_cell_ctxswout_thread, ++ .load_context = pfm_cell_load_context, ++ .unload_context = pfm_cell_unload_context, ++}; ++ ++static struct pfm_pmu_config pfm_cell_pmu_conf = { ++ .pmu_name = "Cell", ++ .version = "0.1", ++ .counter_width = 32, ++ .pmd_desc = pfm_cell_pmd_desc, ++ .pmc_desc = pfm_cell_pmc_desc, ++ .num_pmc_entries = PFM_PM_NUM_PMCS, ++ .num_pmd_entries = PFM_PM_NUM_PMDS, ++ .probe_pmu = pfm_cell_probe_pmu, ++ .pmu_info = &pfm_cell_pmu_info, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++}; ++ ++/** ++ * pfm_cell_platform_probe ++ * ++ * If we're on a system without the firmware rtas call available, set up the ++ * PMC write-checker for all the pmX_event control registers. ++ **/ ++static void pfm_cell_platform_probe(void) ++{ ++ if (machine_is(celleb)) { ++ int cnum; ++ pfm_cell_pmu_conf.pmc_write_check = pfm_cell_pmc_check; ++ for (cnum = NR_CTRS; cnum < (NR_CTRS * 2); cnum++) ++ pfm_cell_pmc_desc[cnum].type |= PFM_REG_WC; ++ } ++ ++ if (machine_is(ps3)) ++ pfm_cell_pmu_info.platform_info = &ps3_platform_pmu_info; ++ else ++ pfm_cell_pmu_info.platform_info = &native_platform_pmu_info; ++} ++ ++static int __init pfm_cell_pmu_init_module(void) ++{ ++ pfm_cell_platform_probe(); ++ return pfm_pmu_register(&pfm_cell_pmu_conf); ++} ++ ++static void __exit pfm_cell_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_cell_pmu_conf); ++} ++ ++module_init(pfm_cell_pmu_init_module); ++module_exit(pfm_cell_pmu_cleanup_module); +--- /dev/null ++++ b/arch/powerpc/perfmon/perfmon_power4.c +@@ -0,0 +1,309 @@ ++/* ++ * This file contains the POWER4 PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2007, IBM Corporation. ++ * ++ * Based on a simple modification of perfmon_power5.c for POWER4 by ++ * Corey Ashford . ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++MODULE_AUTHOR("Corey Ashford "); ++MODULE_DESCRIPTION("POWER4 PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++static struct pfm_regmap_desc pfm_power4_pmc_desc[] = { ++/* mmcr0 */ PMC_D(PFM_REG_I, "MMCR0", MMCR0_FC, 0, 0, SPRN_MMCR0), ++/* mmcr1 */ PMC_D(PFM_REG_I, "MMCR1", 0, 0, 0, SPRN_MMCR1), ++/* mmcra */ PMC_D(PFM_REG_I, "MMCRA", 0, 0, 0, SPRN_MMCRA) ++}; ++#define PFM_PM_NUM_PMCS ARRAY_SIZE(pfm_power4_pmc_desc) ++ ++/* The TB and PURR registers are read-only. Also, note that the TB register ++ * actually consists of both the 32-bit SPRN_TBRU and SPRN_TBRL registers. ++ * For Perfmon2's purposes, we'll treat it as a single 64-bit register. ++ */ ++static struct pfm_regmap_desc pfm_power4_pmd_desc[] = { ++/* tb */ PMD_D((PFM_REG_I|PFM_REG_RO), "TB", SPRN_TBRL), ++/* pmd1 */ PMD_D(PFM_REG_C, "PMC1", SPRN_PMC1), ++/* pmd2 */ PMD_D(PFM_REG_C, "PMC2", SPRN_PMC2), ++/* pmd3 */ PMD_D(PFM_REG_C, "PMC3", SPRN_PMC3), ++/* pmd4 */ PMD_D(PFM_REG_C, "PMC4", SPRN_PMC4), ++/* pmd5 */ PMD_D(PFM_REG_C, "PMC5", SPRN_PMC5), ++/* pmd6 */ PMD_D(PFM_REG_C, "PMC6", SPRN_PMC6), ++/* pmd7 */ PMD_D(PFM_REG_C, "PMC7", SPRN_PMC7), ++/* pmd8 */ PMD_D(PFM_REG_C, "PMC8", SPRN_PMC8) ++}; ++#define PFM_PM_NUM_PMDS ARRAY_SIZE(pfm_power4_pmd_desc) ++ ++static int pfm_power4_probe_pmu(void) ++{ ++ unsigned long pvr = mfspr(SPRN_PVR); ++ int ver = PVR_VER(pvr); ++ ++ if ((ver == PV_POWER4) || (ver == PV_POWER4p)) ++ return 0; ++ ++ return -1; ++} ++ ++static void pfm_power4_write_pmc(unsigned int cnum, u64 value) ++{ ++ switch (pfm_pmu_conf->pmc_desc[cnum].hw_addr) { ++ case SPRN_MMCR0: ++ mtspr(SPRN_MMCR0, value); ++ break; ++ case SPRN_MMCR1: ++ mtspr(SPRN_MMCR1, value); ++ break; ++ case SPRN_MMCRA: ++ mtspr(SPRN_MMCRA, value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void pfm_power4_write_pmd(unsigned int cnum, u64 value) ++{ ++ u64 ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ mtspr(SPRN_PMC1, value & ovfl_mask); ++ break; ++ case SPRN_PMC2: ++ mtspr(SPRN_PMC2, value & ovfl_mask); ++ break; ++ case SPRN_PMC3: ++ mtspr(SPRN_PMC3, value & ovfl_mask); ++ break; ++ case SPRN_PMC4: ++ mtspr(SPRN_PMC4, value & ovfl_mask); ++ break; ++ case SPRN_PMC5: ++ mtspr(SPRN_PMC5, value & ovfl_mask); ++ break; ++ case SPRN_PMC6: ++ mtspr(SPRN_PMC6, value & ovfl_mask); ++ break; ++ case SPRN_PMC7: ++ mtspr(SPRN_PMC7, value & ovfl_mask); ++ break; ++ case SPRN_PMC8: ++ mtspr(SPRN_PMC8, value & ovfl_mask); ++ break; ++ case SPRN_TBRL: ++ case SPRN_PURR: ++ /* Ignore writes to read-only registers. */ ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static u64 pfm_power4_read_pmd(unsigned int cnum) ++{ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ return mfspr(SPRN_PMC1); ++ case SPRN_PMC2: ++ return mfspr(SPRN_PMC2); ++ case SPRN_PMC3: ++ return mfspr(SPRN_PMC3); ++ case SPRN_PMC4: ++ return mfspr(SPRN_PMC4); ++ case SPRN_PMC5: ++ return mfspr(SPRN_PMC5); ++ case SPRN_PMC6: ++ return mfspr(SPRN_PMC6); ++ case SPRN_PMC7: ++ return mfspr(SPRN_PMC7); ++ case SPRN_PMC8: ++ return mfspr(SPRN_PMC8); ++ case SPRN_TBRL: ++ return ((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL); ++ case SPRN_PURR: ++ if (cpu_has_feature(CPU_FTR_PURR)) ++ return mfspr(SPRN_PURR); ++ else ++ return 0; ++ default: ++ BUG(); ++ } ++} ++ ++/* forward decl */ ++static void pfm_power4_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++/** ++ * pfm_power4_enable_counters ++ * ++ **/ ++static void pfm_power4_enable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i, max_pmc; ++ ++ /* Make sure the counters are disabled before touching the other ++ control registers */ ++ pfm_power4_disable_counters(ctx, set); ++ ++ max_pmc = ctx->regs.max_pmc; ++ ++ /* Write MMCR0 last, and a fairly easy way to do this is to write ++ the registers in the reverse order */ ++ for (i = max_pmc; i != 0; i--) ++ if (test_bit(i - 1, set->used_pmcs)) ++ pfm_power4_write_pmc(i - 1, set->pmcs[i - 1]); ++} ++ ++/** ++ * pfm_power4_disable_counters ++ * ++ **/ ++static void pfm_power4_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ /* Set the Freeze Counters bit */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); ++ asm volatile ("sync"); ++} ++ ++/** ++ * pfm_power4_get_ovfl_pmds ++ * ++ * Determine which counters in this set have overflowed and fill in the ++ * set->povfl_pmds mask and set->npend_ovfls count. ++ **/ ++static void pfm_power4_get_ovfl_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i; ++ unsigned int max_pmd = ctx->regs.max_intr_pmd; ++ u64 *used_pmds = set->used_pmds; ++ u64 *cntr_pmds = ctx->regs.cnt_pmds; ++ u64 width_mask = 1 << pfm_pmu_conf->counter_width; ++ u64 new_val, mask[PFM_PMD_BV]; ++ ++ bitmap_and(cast_ulp(mask), cast_ulp(cntr_pmds), ++ cast_ulp(used_pmds), max_pmd); ++ ++ for (i = 0; i < max_pmd; i++) { ++ if (test_bit(i, mask)) { ++ new_val = pfm_power4_read_pmd(i); ++ if (new_val & width_mask) { ++ set_bit(i, set->povfl_pmds); ++ set->npend_ovfls++; ++ } ++ } ++ } ++} ++ ++static void pfm_power4_irq_handler(struct pt_regs *regs, ++ struct pfm_context *ctx) ++{ ++ u32 mmcr0; ++ ++ /* Disable the counters (set the freeze bit) to not polute ++ * the counts. ++ */ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ mtspr(SPRN_MMCR0, (mmcr0 | MMCR0_FC)); ++ ++ /* Set the PMM bit (see comment below). */ ++ mtmsrd(mfmsr() | MSR_PMM); ++ ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ ++ /* ++ * Reset the perfmon trigger if ++ * not in masking mode. ++ */ ++ if (ctx->state != PFM_CTX_MASKED) ++ mmcr0 |= MMCR0_PMXE; ++ ++ /* ++ * We must clear the PMAO bit on some (GQ) chips. Just do it ++ * all the time. ++ */ ++ mmcr0 &= ~MMCR0_PMAO; ++ ++ /* ++ * Now clear the freeze bit, counting will not start until we ++ * rfid from this exception, because only at that point will ++ * the PMM bit be cleared. ++ */ ++ mmcr0 &= ~MMCR0_FC; ++ mtspr(SPRN_MMCR0, mmcr0); ++} ++ ++static void pfm_power4_resend_irq(struct pfm_context *ctx) ++{ ++ /* ++ * Assert the PMAO bit to cause a PMU interrupt. Make sure we ++ * trigger the edge detection circuitry for PMAO ++ */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_PMAO); ++} ++ ++struct pfm_arch_pmu_info pfm_power4_pmu_info = { ++ .pmu_style = PFM_POWERPC_PMU_POWER4, ++ .write_pmc = pfm_power4_write_pmc, ++ .write_pmd = pfm_power4_write_pmd, ++ .read_pmd = pfm_power4_read_pmd, ++ .irq_handler = pfm_power4_irq_handler, ++ .get_ovfl_pmds = pfm_power4_get_ovfl_pmds, ++ .enable_counters = pfm_power4_enable_counters, ++ .disable_counters = pfm_power4_disable_counters, ++ .resend_irq = pfm_power4_resend_irq ++}; ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_power4_pmu_conf = { ++ .pmu_name = "POWER4", ++ .counter_width = 31, ++ .pmd_desc = pfm_power4_pmd_desc, ++ .pmc_desc = pfm_power4_pmc_desc, ++ .num_pmc_entries = PFM_PM_NUM_PMCS, ++ .num_pmd_entries = PFM_PM_NUM_PMDS, ++ .probe_pmu = pfm_power4_probe_pmu, ++ .pmu_info = &pfm_power4_pmu_info, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE ++}; ++ ++static int __init pfm_power4_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_power4_pmu_conf); ++} ++ ++static void __exit pfm_power4_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_power4_pmu_conf); ++} ++ ++module_init(pfm_power4_pmu_init_module); ++module_exit(pfm_power4_pmu_cleanup_module); +--- /dev/null ++++ b/arch/powerpc/perfmon/perfmon_power5.c +@@ -0,0 +1,326 @@ ++/* ++ * This file contains the POWER5 PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2005 David Gibson, IBM Corporation. ++ * ++ * Based on perfmon_p6.c: ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++MODULE_AUTHOR("David Gibson "); ++MODULE_DESCRIPTION("POWER5 PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++static struct pfm_regmap_desc pfm_power5_pmc_desc[] = { ++/* mmcr0 */ PMC_D(PFM_REG_I, "MMCR0", MMCR0_FC, 0, 0, SPRN_MMCR0), ++/* mmcr1 */ PMC_D(PFM_REG_I, "MMCR1", 0, 0, 0, SPRN_MMCR1), ++/* mmcra */ PMC_D(PFM_REG_I, "MMCRA", 0, 0, 0, SPRN_MMCRA) ++}; ++#define PFM_PM_NUM_PMCS ARRAY_SIZE(pfm_power5_pmc_desc) ++ ++/* The TB and PURR registers are read-only. Also, note that the TB register ++ * actually consists of both the 32-bit SPRN_TBRU and SPRN_TBRL registers. ++ * For Perfmon2's purposes, we'll treat it as a single 64-bit register. ++ */ ++static struct pfm_regmap_desc pfm_power5_pmd_desc[] = { ++/* tb */ PMD_D((PFM_REG_I|PFM_REG_RO), "TB", SPRN_TBRL), ++/* pmd1 */ PMD_D(PFM_REG_C, "PMC1", SPRN_PMC1), ++/* pmd2 */ PMD_D(PFM_REG_C, "PMC2", SPRN_PMC2), ++/* pmd3 */ PMD_D(PFM_REG_C, "PMC3", SPRN_PMC3), ++/* pmd4 */ PMD_D(PFM_REG_C, "PMC4", SPRN_PMC4), ++/* pmd5 */ PMD_D(PFM_REG_C, "PMC5", SPRN_PMC5), ++/* pmd6 */ PMD_D(PFM_REG_C, "PMC6", SPRN_PMC6), ++/* purr */ PMD_D((PFM_REG_I|PFM_REG_RO), "PURR", SPRN_PURR), ++}; ++#define PFM_PM_NUM_PMDS ARRAY_SIZE(pfm_power5_pmd_desc) ++ ++/* forward decl */ ++static void pfm_power5_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++static int pfm_power5_probe_pmu(void) ++{ ++ unsigned long pvr = mfspr(SPRN_PVR); ++ ++ switch (PVR_VER(pvr)) { ++ case PV_POWER5: ++ return 0; ++ case PV_POWER5p: ++ return (PVR_REV(pvr) < 0x300) ? 0 : -1; ++ default: ++ return -1; ++ } ++} ++ ++static void pfm_power5_write_pmc(unsigned int cnum, u64 value) ++{ ++ switch (pfm_pmu_conf->pmc_desc[cnum].hw_addr) { ++ case SPRN_MMCR0: ++ mtspr(SPRN_MMCR0, value); ++ break; ++ case SPRN_MMCR1: ++ mtspr(SPRN_MMCR1, value); ++ break; ++ case SPRN_MMCRA: ++ mtspr(SPRN_MMCRA, value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void pfm_power5_write_pmd(unsigned int cnum, u64 value) ++{ ++ u64 ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ mtspr(SPRN_PMC1, value & ovfl_mask); ++ break; ++ case SPRN_PMC2: ++ mtspr(SPRN_PMC2, value & ovfl_mask); ++ break; ++ case SPRN_PMC3: ++ mtspr(SPRN_PMC3, value & ovfl_mask); ++ break; ++ case SPRN_PMC4: ++ mtspr(SPRN_PMC4, value & ovfl_mask); ++ break; ++ case SPRN_PMC5: ++ mtspr(SPRN_PMC5, value & ovfl_mask); ++ break; ++ case SPRN_PMC6: ++ mtspr(SPRN_PMC6, value & ovfl_mask); ++ break; ++ case SPRN_TBRL: ++ case SPRN_PURR: ++ /* Ignore writes to read-only registers. */ ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static u64 pfm_power5_read_pmd(unsigned int cnum) ++{ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ return mfspr(SPRN_PMC1); ++ case SPRN_PMC2: ++ return mfspr(SPRN_PMC2); ++ case SPRN_PMC3: ++ return mfspr(SPRN_PMC3); ++ case SPRN_PMC4: ++ return mfspr(SPRN_PMC4); ++ case SPRN_PMC5: ++ return mfspr(SPRN_PMC5); ++ case SPRN_PMC6: ++ return mfspr(SPRN_PMC6); ++ case SPRN_TBRL: ++ return ((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL); ++ case SPRN_PURR: ++ if (cpu_has_feature(CPU_FTR_PURR)) ++ return mfspr(SPRN_PURR); ++ else ++ return 0; ++ default: ++ BUG(); ++ } ++} ++ ++/** ++ * pfm_power5_enable_counters ++ * ++ **/ ++static void pfm_power5_enable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i, max_pmc; ++ ++ /* ++ * Make sure the counters are disabled before touching the ++ * other control registers ++ */ ++ pfm_power5_disable_counters(ctx, set); ++ ++ max_pmc = ctx->regs.max_pmc; ++ ++ /* ++ * Write MMCR0 last, and a fairly easy way to do ++ * this is to write the registers in the reverse ++ * order ++ */ ++ for (i = max_pmc; i != 0; i--) ++ if (test_bit(i - 1, set->used_pmcs)) ++ pfm_power5_write_pmc(i - 1, set->pmcs[i - 1]); ++} ++ ++/** ++ * pfm_power5_disable_counters ++ * ++ * Just need to zero all the control registers. ++ **/ ++static void pfm_power5_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ /* Set the Freeze Counters bit */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); ++ asm volatile ("sync"); ++} ++ ++/** ++ * pfm_power5_get_ovfl_pmds ++ * ++ * Determine which counters in this set have overflowed and fill in the ++ * set->povfl_pmds mask and set->npend_ovfls count. ++ **/ ++static void pfm_power5_get_ovfl_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i; ++ unsigned int max = ctx->regs.max_intr_pmd; ++ u64 *used_pmds = set->used_pmds; ++ u64 *intr_pmds = ctx->regs.intr_pmds; ++ u64 width_mask = 1 << pfm_pmu_conf->counter_width; ++ u64 new_val, mask[PFM_PMD_BV]; ++ ++ bitmap_and(cast_ulp(mask), cast_ulp(intr_pmds), ++ cast_ulp(used_pmds), max); ++ /* ++ * If either PMC5 or PMC6 are not being used, just zero out the unused ++ * ones so that they won't interrupt again for another 2^31 counts. ++ * Note that if no other counters overflowed, set->npend_ovfls will ++ * be zero upon returning from this call (i.e. a spurious ++ * interrupt), but that should be ok. ++ * ++ * If neither PMC5 nor PMC6 are used, the counters should be frozen ++ * via MMCR0_FC5_6 and zeroed out. ++ * ++ * If both PMC5 and PMC6 are used, they can be handled correctly by ++ * the loop that follows. ++ */ ++ ++ if (!test_bit(5, cast_ulp(used_pmds))) ++ mtspr(SPRN_PMC5, 0); ++ if (!test_bit(6, cast_ulp(used_pmds))) ++ mtspr(SPRN_PMC6, 0); ++ ++ for (i = 0; i < max; i++) { ++ if (test_bit(i, mask)) { ++ new_val = pfm_power5_read_pmd(i); ++ if (new_val & width_mask) { ++ set_bit(i, set->povfl_pmds); ++ set->npend_ovfls++; ++ } ++ } ++ } ++} ++ ++static void pfm_power5_irq_handler(struct pt_regs *regs, ++ struct pfm_context *ctx) ++{ ++ u32 mmcr0; ++ ++ /* Disable the counters (set the freeze bit) to not polute ++ * the counts. ++ */ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ mtspr(SPRN_MMCR0, (mmcr0 | MMCR0_FC)); ++ ++ /* Set the PMM bit (see comment below). */ ++ mtmsrd(mfmsr() | MSR_PMM); ++ ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ ++ /* ++ * Reset the perfmon trigger if ++ * not in masking mode. ++ */ ++ if (ctx->state != PFM_CTX_MASKED) ++ mmcr0 |= MMCR0_PMXE; ++ ++ /* ++ * We must clear the PMAO bit on some (GQ) chips. Just do it ++ * all the time. ++ */ ++ mmcr0 &= ~MMCR0_PMAO; ++ ++ /* ++ * Now clear the freeze bit, counting will not start until we ++ * rfid from this exception, because only at that point will ++ * the PMM bit be cleared. ++ */ ++ mmcr0 &= ~MMCR0_FC; ++ mtspr(SPRN_MMCR0, mmcr0); ++} ++ ++static void pfm_power5_resend_irq(struct pfm_context *ctx) ++{ ++ /* ++ * Assert the PMAO bit to cause a PMU interrupt. Make sure we ++ * trigger the edge detection circuitry for PMAO ++ */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_PMAO); ++} ++ ++struct pfm_arch_pmu_info pfm_power5_pmu_info = { ++ .pmu_style = PFM_POWERPC_PMU_POWER5, ++ .write_pmc = pfm_power5_write_pmc, ++ .write_pmd = pfm_power5_write_pmd, ++ .read_pmd = pfm_power5_read_pmd, ++ .irq_handler = pfm_power5_irq_handler, ++ .get_ovfl_pmds = pfm_power5_get_ovfl_pmds, ++ .enable_counters = pfm_power5_enable_counters, ++ .disable_counters = pfm_power5_disable_counters, ++ .resend_irq = pfm_power5_resend_irq ++}; ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_power5_pmu_conf = { ++ .pmu_name = "POWER5", ++ .counter_width = 31, ++ .pmd_desc = pfm_power5_pmd_desc, ++ .pmc_desc = pfm_power5_pmc_desc, ++ .num_pmc_entries = PFM_PM_NUM_PMCS, ++ .num_pmd_entries = PFM_PM_NUM_PMDS, ++ .probe_pmu = pfm_power5_probe_pmu, ++ .pmu_info = &pfm_power5_pmu_info, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE ++}; ++ ++static int __init pfm_power5_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_power5_pmu_conf); ++} ++ ++static void __exit pfm_power5_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_power5_pmu_conf); ++} ++ ++module_init(pfm_power5_pmu_init_module); ++module_exit(pfm_power5_pmu_cleanup_module); +--- /dev/null ++++ b/arch/powerpc/perfmon/perfmon_power6.c +@@ -0,0 +1,520 @@ ++/* ++ * This file contains the POWER6 PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Copyright (c) 2007, IBM Corporation ++ * ++ * Based on perfmon_power5.c, and written by Carl Love ++ * and Kevin Corry . Some fixes and refinement by ++ * Corey Ashford ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++ ++MODULE_AUTHOR("Corey Ashford "); ++MODULE_DESCRIPTION("POWER6 PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++static struct pfm_regmap_desc pfm_power6_pmc_desc[] = { ++/* mmcr0 */ PMC_D(PFM_REG_I, "MMCR0", MMCR0_FC, 0, 0, SPRN_MMCR0), ++/* mmcr1 */ PMC_D(PFM_REG_I, "MMCR1", 0, 0, 0, SPRN_MMCR1), ++/* mmcra */ PMC_D(PFM_REG_I, "MMCRA", 0, 0, 0, SPRN_MMCRA) ++}; ++#define PFM_PM_NUM_PMCS ARRAY_SIZE(pfm_power6_pmc_desc) ++#define PFM_DELTA_TB 10000 /* Not a real registers */ ++#define PFM_DELTA_PURR 10001 ++ ++/* ++ * counters wrap to zero at transition from 2^32-1 to 2^32. Note: ++ * interrupt generated at transition from 2^31-1 to 2^31 ++ */ ++#define OVERFLOW_VALUE 0x100000000UL ++ ++/* The TB and PURR registers are read-only. Also, note that the TB register ++ * actually consists of both the 32-bit SPRN_TBRU and SPRN_TBRL registers. ++ * For Perfmon2's purposes, we'll treat it as a single 64-bit register. ++ */ ++static struct pfm_regmap_desc pfm_power6_pmd_desc[] = { ++ /* On POWER 6 PMC5 and PMC6 are not writable, they do not ++ * generate interrupts, and do not qualify their counts ++ * based on problem mode, supervisor mode or hypervisor mode. ++ * These two counters are implemented as virtual counters ++ * to make the appear to work like the other counters. A ++ * kernel timer is used sample the real PMC5 and PMC6 and ++ * update the virtual counters. ++ */ ++/* tb */ PMD_D((PFM_REG_I|PFM_REG_RO), "TB", SPRN_TBRL), ++/* pmd1 */ PMD_D(PFM_REG_C, "PMC1", SPRN_PMC1), ++/* pmd2 */ PMD_D(PFM_REG_C, "PMC2", SPRN_PMC2), ++/* pmd3 */ PMD_D(PFM_REG_C, "PMC3", SPRN_PMC3), ++/* pmd4 */ PMD_D(PFM_REG_C, "PMC4", SPRN_PMC4), ++/* pmd5 */ PMD_D((PFM_REG_I|PFM_REG_V), "PMC5", SPRN_PMC5), ++/* pmd6 */ PMD_D((PFM_REG_I|PFM_REG_V), "PMC6", SPRN_PMC6), ++/* purr */ PMD_D((PFM_REG_I|PFM_REG_RO), "PURR", SPRN_PURR), ++/* delta purr */ PMD_D((PFM_REG_I|PFM_REG_V), "DELTA_TB", PFM_DELTA_TB), ++/* delta tb */ PMD_D((PFM_REG_I|PFM_REG_V), "DELTA_PURR", PFM_DELTA_PURR), ++}; ++ ++#define PFM_PM_NUM_PMDS ARRAY_SIZE(pfm_power6_pmd_desc) ++ ++u32 pmc5_start_save[NR_CPUS]; ++u32 pmc6_start_save[NR_CPUS]; ++ ++static struct timer_list pmc5_6_update[NR_CPUS]; ++u64 enable_cntrs_cnt; ++u64 disable_cntrs_cnt; ++u64 call_delta; ++u64 pm5_6_interrupt; ++u64 pm1_4_interrupt; ++/* need ctx_arch for kernel timer. Can't get it in context of the kernel ++ * timer. ++ */ ++struct pfm_arch_context *pmc5_6_ctx_arch[NR_CPUS]; ++long int update_time; ++ ++static void delta(int cpu_num, struct pfm_arch_context *ctx_arch) ++{ ++ u32 tmp5, tmp6; ++ ++ call_delta++; ++ ++ tmp5 = (u32) mfspr(SPRN_PMC5); ++ tmp6 = (u32) mfspr(SPRN_PMC6); ++ ++ /* ++ * The following difference calculation relies on 32-bit modular ++ * arithmetic for the deltas to come out correct (especially in the ++ * presence of a 32-bit counter wrap). ++ */ ++ ctx_arch->powergs_pmc5 += (u64)(tmp5 - pmc5_start_save[cpu_num]); ++ ctx_arch->powergs_pmc6 += (u64)(tmp6 - pmc6_start_save[cpu_num]); ++ ++ pmc5_start_save[cpu_num] = tmp5; ++ pmc6_start_save[cpu_num] = tmp6; ++ ++ return; ++} ++ ++ ++static void pmc5_6_updater(unsigned long cpu_num) ++{ ++ /* update the virtual pmd 5 and pmd 6 counters */ ++ ++ delta(cpu_num, pmc5_6_ctx_arch[cpu_num]); ++ mod_timer(&pmc5_6_update[cpu_num], jiffies + update_time); ++} ++ ++ ++static int pfm_power6_probe_pmu(void) ++{ ++ unsigned long pvr = mfspr(SPRN_PVR); ++ ++ switch (PVR_VER(pvr)) { ++ case PV_POWER6: ++ return 0; ++ case PV_POWER5p: ++ /* If this is a POWER5+ and the revision is less than 0x300, ++ don't treat it as a POWER6. */ ++ return (PVR_REV(pvr) < 0x300) ? -1 : 0; ++ default: ++ return -1; ++ } ++} ++ ++static void pfm_power6_write_pmc(unsigned int cnum, u64 value) ++{ ++ switch (pfm_pmu_conf->pmc_desc[cnum].hw_addr) { ++ case SPRN_MMCR0: ++ mtspr(SPRN_MMCR0, value); ++ break; ++ case SPRN_MMCR1: ++ mtspr(SPRN_MMCR1, value); ++ break; ++ case SPRN_MMCRA: ++ mtspr(SPRN_MMCRA, value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void pfm_power6_write_pmd(unsigned int cnum, u64 value) ++{ ++ /* On POWER 6 PMC5 and PMC6 are implemented as ++ * virtual counters. See comment in pfm_power6_pmd_desc ++ * definition. ++ */ ++ u64 ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ mtspr(SPRN_PMC1, value & ovfl_mask); ++ break; ++ case SPRN_PMC2: ++ mtspr(SPRN_PMC2, value & ovfl_mask); ++ break; ++ case SPRN_PMC3: ++ mtspr(SPRN_PMC3, value & ovfl_mask); ++ break; ++ case SPRN_PMC4: ++ mtspr(SPRN_PMC4, value & ovfl_mask); ++ break; ++ case SPRN_TBRL: ++ case SPRN_PURR: ++ /* Ignore writes to read-only registers. */ ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static u64 pfm_power6_sread(struct pfm_context *ctx, unsigned int cnum) ++{ ++ struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx); ++ int cpu_num = smp_processor_id(); ++ ++ /* On POWER 6 PMC5 and PMC6 are implemented as ++ * virtual counters. See comment in pfm_power6_pmd_desc ++ * definition. ++ */ ++ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC5: ++ return ctx_arch->powergs_pmc5 + (u64)((u32)mfspr(SPRN_PMC5) - pmc5_start_save[cpu_num]); ++ break; ++ ++ case SPRN_PMC6: ++ return ctx_arch->powergs_pmc6 + (u64)((u32)mfspr(SPRN_PMC6) - pmc6_start_save[cpu_num]); ++ break; ++ ++ case PFM_DELTA_TB: ++ return ctx_arch->delta_tb ++ + (((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL)) ++ - ctx_arch->delta_tb_start; ++ break; ++ ++ case PFM_DELTA_PURR: ++ return ctx_arch->delta_purr ++ + mfspr(SPRN_PURR) ++ - ctx_arch->delta_purr_start; ++ break; ++ ++ default: ++ BUG(); ++ } ++} ++ ++void pfm_power6_swrite(struct pfm_context *ctx, unsigned int cnum, ++ u64 val) ++{ ++ struct pfm_arch_context *ctx_arch = pfm_ctx_arch(ctx); ++ int cpu_num = smp_processor_id(); ++ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC5: ++ pmc5_start_save[cpu_num] = mfspr(SPRN_PMC5); ++ ctx_arch->powergs_pmc5 = val; ++ break; ++ ++ case SPRN_PMC6: ++ pmc6_start_save[cpu_num] = mfspr(SPRN_PMC6); ++ ctx_arch->powergs_pmc6 = val; ++ break; ++ ++ case PFM_DELTA_TB: ++ ctx_arch->delta_tb_start = ++ (((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL)); ++ ctx_arch->delta_tb = val; ++ break; ++ ++ case PFM_DELTA_PURR: ++ ctx_arch->delta_purr_start = mfspr(SPRN_PURR); ++ ctx_arch->delta_purr = val; ++ break; ++ ++ default: ++ BUG(); ++ } ++} ++ ++static u64 pfm_power6_read_pmd(unsigned int cnum) ++{ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ return mfspr(SPRN_PMC1); ++ case SPRN_PMC2: ++ return mfspr(SPRN_PMC2); ++ case SPRN_PMC3: ++ return mfspr(SPRN_PMC3); ++ case SPRN_PMC4: ++ return mfspr(SPRN_PMC4); ++ case SPRN_TBRL: ++ return ((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL); ++ case SPRN_PURR: ++ if (cpu_has_feature(CPU_FTR_PURR)) ++ return mfspr(SPRN_PURR); ++ else ++ return 0; ++ default: ++ BUG(); ++ } ++} ++ ++ ++/** ++ * pfm_power6_enable_counters ++ * ++ **/ ++static void pfm_power6_enable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ ++ unsigned int i, max_pmc; ++ int cpu_num = smp_processor_id(); ++ struct pfm_arch_context *ctx_arch; ++ ++ enable_cntrs_cnt++; ++ ++ /* need the ctx passed down to the routine */ ++ ctx_arch = pfm_ctx_arch(ctx); ++ max_pmc = ctx->regs.max_pmc; ++ ++ /* Write MMCR0 last, and a fairly easy way to do this is to write ++ the registers in the reverse order */ ++ for (i = max_pmc; i != 0; i--) ++ if (test_bit(i - 1, set->used_pmcs)) ++ pfm_power6_write_pmc(i - 1, set->pmcs[i - 1]); ++ ++ /* save current free running HW event count */ ++ pmc5_start_save[cpu_num] = mfspr(SPRN_PMC5); ++ pmc6_start_save[cpu_num] = mfspr(SPRN_PMC6); ++ ++ ctx_arch->delta_purr_start = mfspr(SPRN_PURR); ++ ++ if (cpu_has_feature(CPU_FTR_PURR)) ++ ctx_arch->delta_tb_start = ++ ((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL); ++ else ++ ctx_arch->delta_tb_start = 0; ++ ++ /* Start kernel timer for this cpu to periodically update ++ * the virtual counters. ++ */ ++ init_timer(&pmc5_6_update[cpu_num]); ++ pmc5_6_update[cpu_num].function = pmc5_6_updater; ++ pmc5_6_update[cpu_num].data = (unsigned long) cpu_num; ++ pmc5_6_update[cpu_num].expires = jiffies + update_time; ++ /* context for this timer, timer will be removed if context ++ * is switched because the counters will be stopped first. ++ * NEEDS WORK, I think this is all ok, a little concerned about a ++ * race between the kernel timer going off right as the counters ++ * are being stopped and the context switching. Need to think ++ * about this. ++ */ ++ pmc5_6_ctx_arch[cpu_num] = ctx_arch; ++ add_timer(&pmc5_6_update[cpu_num]); ++} ++ ++/** ++ * pfm_power6_disable_counters ++ * ++ **/ ++static void pfm_power6_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch; ++ int cpu_num = smp_processor_id(); ++ ++ disable_cntrs_cnt++; ++ ++ /* Set the Freeze Counters bit */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); ++ asm volatile ("sync"); ++ ++ /* delete kernel update timer */ ++ del_timer_sync(&pmc5_6_update[cpu_num]); ++ ++ /* Update the virtual pmd 5 and 6 counters from the free running ++ * HW counters ++ */ ++ ctx_arch = pfm_ctx_arch(ctx); ++ delta(cpu_num, ctx_arch); ++ ++ ctx_arch->delta_tb += ++ (((u64)mfspr(SPRN_TBRU) << 32) | mfspr(SPRN_TBRL)) ++ - ctx_arch->delta_tb_start; ++ ++ ctx_arch->delta_purr += mfspr(SPRN_PURR) ++ - ctx_arch->delta_purr_start; ++} ++ ++/** ++ * pfm_power6_get_ovfl_pmds ++ * ++ * Determine which counters in this set have overflowed and fill in the ++ * set->povfl_pmds mask and set->npend_ovfls count. ++ **/ ++static void pfm_power6_get_ovfl_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i; ++ unsigned int first_intr_pmd = ctx->regs.first_intr_pmd; ++ unsigned int max_intr_pmd = ctx->regs.max_intr_pmd; ++ u64 *used_pmds = set->used_pmds; ++ u64 *cntr_pmds = ctx->regs.cnt_pmds; ++ u64 width_mask = 1 << pfm_pmu_conf->counter_width; ++ u64 new_val, mask[PFM_PMD_BV]; ++ ++ bitmap_and(cast_ulp(mask), cast_ulp(cntr_pmds), cast_ulp(used_pmds), max_intr_pmd); ++ ++ /* max_intr_pmd is actually the last interrupting pmd register + 1 */ ++ for (i = first_intr_pmd; i < max_intr_pmd; i++) { ++ if (test_bit(i, mask)) { ++ new_val = pfm_power6_read_pmd(i); ++ if (new_val & width_mask) { ++ set_bit(i, set->povfl_pmds); ++ set->npend_ovfls++; ++ } ++ } ++ } ++} ++ ++static void pfm_power6_irq_handler(struct pt_regs *regs, ++ struct pfm_context *ctx) ++{ ++ u32 mmcr0; ++ u64 mmcra; ++ ++ /* Disable the counters (set the freeze bit) to not polute ++ * the counts. ++ */ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ mtspr(SPRN_MMCR0, (mmcr0 | MMCR0_FC)); ++ mmcra = mfspr(SPRN_MMCRA); ++ ++ /* Set the PMM bit (see comment below). */ ++ mtmsrd(mfmsr() | MSR_PMM); ++ ++ pm1_4_interrupt++; ++ ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ ++ /* ++ * Reset the perfmon trigger if ++ * not in masking mode. ++ */ ++ if (ctx->state != PFM_CTX_MASKED) ++ mmcr0 |= MMCR0_PMXE; ++ ++ /* ++ * Clear the PMU Alert Occurred bit ++ */ ++ mmcr0 &= ~MMCR0_PMAO; ++ ++ /* Clear the appropriate bits in the MMCRA. */ ++ mmcra &= ~(POWER6_MMCRA_THRM | POWER6_MMCRA_OTHER); ++ mtspr(SPRN_MMCRA, mmcra); ++ ++ /* ++ * Now clear the freeze bit, counting will not start until we ++ * rfid from this exception, because only at that point will ++ * the PMM bit be cleared. ++ */ ++ mmcr0 &= ~MMCR0_FC; ++ mtspr(SPRN_MMCR0, mmcr0); ++} ++ ++static void pfm_power6_resend_irq(struct pfm_context *ctx) ++{ ++ /* ++ * Assert the PMAO bit to cause a PMU interrupt. Make sure we ++ * trigger the edge detection circuitry for PMAO ++ */ ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); ++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_PMAO); ++} ++ ++struct pfm_arch_pmu_info pfm_power6_pmu_info = { ++ .pmu_style = PFM_POWERPC_PMU_POWER6, ++ .write_pmc = pfm_power6_write_pmc, ++ .write_pmd = pfm_power6_write_pmd, ++ .read_pmd = pfm_power6_read_pmd, ++ .irq_handler = pfm_power6_irq_handler, ++ .get_ovfl_pmds = pfm_power6_get_ovfl_pmds, ++ .enable_counters = pfm_power6_enable_counters, ++ .disable_counters = pfm_power6_disable_counters, ++ .resend_irq = pfm_power6_resend_irq ++}; ++ ++/* ++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! ++ */ ++static struct pfm_pmu_config pfm_power6_pmu_conf = { ++ .pmu_name = "POWER6", ++ .counter_width = 31, ++ .pmd_desc = pfm_power6_pmd_desc, ++ .pmc_desc = pfm_power6_pmc_desc, ++ .num_pmc_entries = PFM_PM_NUM_PMCS, ++ .num_pmd_entries = PFM_PM_NUM_PMDS, ++ .probe_pmu = pfm_power6_probe_pmu, ++ .pmu_info = &pfm_power6_pmu_info, ++ .pmd_sread = pfm_power6_sread, ++ .pmd_swrite = pfm_power6_swrite, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE ++}; ++ ++static int __init pfm_power6_pmu_init_module(void) ++{ ++ int ret; ++ disable_cntrs_cnt = 0; ++ enable_cntrs_cnt = 0; ++ call_delta = 0; ++ pm5_6_interrupt = 0; ++ pm1_4_interrupt = 0; ++ ++ /* calculate the time for updating counters 5 and 6 */ ++ ++ /* ++ * MAX_EVENT_RATE assumes a max instruction issue rate of 2 ++ * instructions per clock cycle. Experience shows that this factor ++ * of 2 is more than adequate. ++ */ ++ ++# define MAX_EVENT_RATE (ppc_proc_freq * 2) ++ ++ /* ++ * Calculate the time, in jiffies, it takes for event counter 5 or ++ * 6 to completely wrap when counting at the max event rate, and ++ * then figure on sampling at twice that rate. ++ */ ++ update_time = (((unsigned long)HZ * OVERFLOW_VALUE) ++ / ((unsigned long)MAX_EVENT_RATE)) / 2; ++ ++ ret = pfm_pmu_register(&pfm_power6_pmu_conf); ++ return ret; ++} ++ ++static void __exit pfm_power6_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_power6_pmu_conf); ++} ++ ++module_init(pfm_power6_pmu_init_module); ++module_exit(pfm_power6_pmu_cleanup_module); +--- /dev/null ++++ b/arch/powerpc/perfmon/perfmon_ppc32.c +@@ -0,0 +1,340 @@ ++/* ++ * This file contains the PPC32 PMU register description tables ++ * and pmc checker used by perfmon.c. ++ * ++ * Philip Mucci, mucci@cs.utk.edu ++ * ++ * Based on code from: ++ * Copyright (c) 2005 David Gibson, IBM Corporation. ++ * ++ * Based on perfmon_p6.c: ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Philip Mucci "); ++MODULE_DESCRIPTION("PPC32 PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++static struct pfm_pmu_config pfm_ppc32_pmu_conf; ++ ++static struct pfm_regmap_desc pfm_ppc32_pmc_desc[] = { ++/* mmcr0 */ PMC_D(PFM_REG_I, "MMCR0", 0x0, 0, 0, SPRN_MMCR0), ++/* mmcr1 */ PMC_D(PFM_REG_I, "MMCR1", 0x0, 0, 0, SPRN_MMCR1), ++/* mmcr2 */ PMC_D(PFM_REG_I, "MMCR2", 0x0, 0, 0, SPRN_MMCR2), ++}; ++#define PFM_PM_NUM_PMCS ARRAY_SIZE(pfm_ppc32_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_ppc32_pmd_desc[] = { ++/* pmd0 */ PMD_D(PFM_REG_C, "PMC1", SPRN_PMC1), ++/* pmd1 */ PMD_D(PFM_REG_C, "PMC2", SPRN_PMC2), ++/* pmd2 */ PMD_D(PFM_REG_C, "PMC3", SPRN_PMC3), ++/* pmd3 */ PMD_D(PFM_REG_C, "PMC4", SPRN_PMC4), ++/* pmd4 */ PMD_D(PFM_REG_C, "PMC5", SPRN_PMC5), ++/* pmd5 */ PMD_D(PFM_REG_C, "PMC6", SPRN_PMC6), ++}; ++#define PFM_PM_NUM_PMDS ARRAY_SIZE(pfm_ppc32_pmd_desc) ++ ++static void perfmon_perf_irq(struct pt_regs *regs) ++{ ++ u32 mmcr0; ++ ++ /* BLATANTLY STOLEN FROM OPROFILE, then modified */ ++ ++ /* set the PMM bit (see comment below) */ ++ mtmsr(mfmsr() | MSR_PMM); ++ ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++ ++ /* The freeze bit was set by the interrupt. ++ * Clear the freeze bit, and reenable the interrupt. ++ * The counters won't actually start until the rfi clears ++ * the PMM bit. ++ */ ++ ++ /* Unfreezes the counters on this CPU, enables the interrupt, ++ * enables the counters to trigger the interrupt, and sets the ++ * counters to only count when the mark bit is not set. ++ */ ++ mmcr0 = mfspr(SPRN_MMCR0); ++ ++ mmcr0 &= ~(MMCR0_FC | MMCR0_FCM0); ++ mmcr0 |= (MMCR0_FCECE | MMCR0_PMC1CE | MMCR0_PMCnCE | MMCR0_PMXE); ++ ++ mtspr(SPRN_MMCR0, mmcr0); ++} ++ ++static int pfm_ppc32_probe_pmu(void) ++{ ++ enum ppc32_pmu_type pm_type; ++ int nmmcr = 0, npmds = 0, intsok = 0, i; ++ unsigned int pvr; ++ char *str; ++ ++ pvr = mfspr(SPRN_PVR); ++ ++ switch (PVR_VER(pvr)) { ++ case 0x0004: /* 604 */ ++ str = "PPC604"; ++ pm_type = PFM_POWERPC_PMU_604; ++ nmmcr = 1; ++ npmds = 2; ++ break; ++ case 0x0009: /* 604e; */ ++ case 0x000A: /* 604ev */ ++ str = "PPC604e"; ++ pm_type = PFM_POWERPC_PMU_604e; ++ nmmcr = 2; ++ npmds = 4; ++ break; ++ case 0x0008: /* 750/740 */ ++ str = "PPC750"; ++ pm_type = PFM_POWERPC_PMU_750; ++ nmmcr = 2; ++ npmds = 4; ++ break; ++ case 0x7000: /* 750FX */ ++ case 0x7001: ++ str = "PPC750"; ++ pm_type = PFM_POWERPC_PMU_750; ++ nmmcr = 2; ++ npmds = 4; ++ if ((pvr & 0xFF0F) >= 0x0203) ++ intsok = 1; ++ break; ++ case 0x7002: /* 750GX */ ++ str = "PPC750"; ++ pm_type = PFM_POWERPC_PMU_750; ++ nmmcr = 2; ++ npmds = 4; ++ intsok = 1; ++ case 0x000C: /* 7400 */ ++ str = "PPC7400"; ++ pm_type = PFM_POWERPC_PMU_7400; ++ nmmcr = 3; ++ npmds = 4; ++ break; ++ case 0x800C: /* 7410 */ ++ str = "PPC7410"; ++ pm_type = PFM_POWERPC_PMU_7400; ++ nmmcr = 3; ++ npmds = 4; ++ if ((pvr & 0xFFFF) >= 0x01103) ++ intsok = 1; ++ break; ++ case 0x8000: /* 7451/7441 */ ++ case 0x8001: /* 7455/7445 */ ++ case 0x8002: /* 7457/7447 */ ++ case 0x8003: /* 7447A */ ++ case 0x8004: /* 7448 */ ++ str = "PPC7450"; ++ pm_type = PFM_POWERPC_PMU_7450; ++ nmmcr = 3; npmds = 6; ++ intsok = 1; ++ break; ++ default: ++ PFM_INFO("Unknown PVR_VER(0x%x)\n", PVR_VER(pvr)); ++ return -1; ++ } ++ ++ /* ++ * deconfigure unimplemented registers ++ */ ++ for (i = npmds; i < PFM_PM_NUM_PMDS; i++) ++ pfm_ppc32_pmd_desc[i].type = PFM_REG_NA; ++ ++ for (i = nmmcr; i < PFM_PM_NUM_PMCS; i++) ++ pfm_ppc32_pmc_desc[i].type = PFM_REG_NA; ++ ++ /* ++ * update PMU description structure ++ */ ++ pfm_ppc32_pmu_conf.pmu_name = str; ++ pfm_ppc32_pmu_info.pmu_style = pm_type; ++ pfm_ppc32_pmu_conf.num_pmc_entries = nmmcr; ++ pfm_ppc32_pmu_conf.num_pmd_entries = npmds; ++ ++ if (intsok == 0) ++ PFM_INFO("Interrupts unlikely to work\n"); ++ ++ return reserve_pmc_hardware(perfmon_perf_irq); ++} ++ ++static void pfm_ppc32_write_pmc(unsigned int cnum, u64 value) ++{ ++ switch (pfm_pmu_conf->pmc_desc[cnum].hw_addr) { ++ case SPRN_MMCR0: ++ mtspr(SPRN_MMCR0, value); ++ break; ++ case SPRN_MMCR1: ++ mtspr(SPRN_MMCR1, value); ++ break; ++ case SPRN_MMCR2: ++ mtspr(SPRN_MMCR2, value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void pfm_ppc32_write_pmd(unsigned int cnum, u64 value) ++{ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ mtspr(SPRN_PMC1, value); ++ break; ++ case SPRN_PMC2: ++ mtspr(SPRN_PMC2, value); ++ break; ++ case SPRN_PMC3: ++ mtspr(SPRN_PMC3, value); ++ break; ++ case SPRN_PMC4: ++ mtspr(SPRN_PMC4, value); ++ break; ++ case SPRN_PMC5: ++ mtspr(SPRN_PMC5, value); ++ break; ++ case SPRN_PMC6: ++ mtspr(SPRN_PMC6, value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static u64 pfm_ppc32_read_pmd(unsigned int cnum) ++{ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case SPRN_PMC1: ++ return mfspr(SPRN_PMC1); ++ case SPRN_PMC2: ++ return mfspr(SPRN_PMC2); ++ case SPRN_PMC3: ++ return mfspr(SPRN_PMC3); ++ case SPRN_PMC4: ++ return mfspr(SPRN_PMC4); ++ case SPRN_PMC5: ++ return mfspr(SPRN_PMC5); ++ case SPRN_PMC6: ++ return mfspr(SPRN_PMC6); ++ default: ++ BUG(); ++ } ++} ++ ++/** ++ * pfm_ppc32_enable_counters ++ * ++ * Just need to load the current values into the control registers. ++ **/ ++static void pfm_ppc32_enable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i, max_pmc; ++ ++ max_pmc = pfm_pmu_conf->regs.max_pmc; ++ ++ for (i = 0; i < max_pmc; i++) ++ if (test_bit(i, set->used_pmcs)) ++ pfm_ppc32_write_pmc(i, set->pmcs[i]); ++} ++ ++/** ++ * pfm_ppc32_disable_counters ++ * ++ * Just need to zero all the control registers. ++ **/ ++static void pfm_ppc32_disable_counters(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i, max; ++ ++ max = pfm_pmu_conf->regs.max_pmc; ++ ++ for (i = 0; i < max; i++) ++ if (test_bit(i, set->used_pmcs)) ++ pfm_ppc32_write_pmc(ctx, 0); ++} ++ ++/** ++ * pfm_ppc32_get_ovfl_pmds ++ * ++ * Determine which counters in this set have overflowed and fill in the ++ * set->povfl_pmds mask and set->npend_ovfls count. ++ **/ ++static void pfm_ppc32_get_ovfl_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i; ++ unsigned int max_pmd = pfm_pmu_conf->regs.max_cnt_pmd; ++ u64 *used_pmds = set->used_pmds; ++ u64 *cntr_pmds = pfm_pmu_conf->regs.cnt_pmds; ++ u64 width_mask = 1 << pfm_pmu_conf->counter_width; ++ u64 new_val, mask[PFM_PMD_BV]; ++ ++ bitmap_and(cast_ulp(mask), cast_ulp(cntr_pmds), ++ cast_ulp(used_pmds), max_pmd); ++ ++ for (i = 0; i < max_pmd; i++) { ++ if (test_bit(i, mask)) { ++ new_val = pfm_ppc32_read_pmd(i); ++ if (new_val & width_mask) { ++ set_bit(i, set->povfl_pmds); ++ set->npend_ovfls++; ++ } ++ } ++ } ++} ++ ++struct pfm_arch_pmu_info pfm_ppc32_pmu_info = { ++ .pmu_style = PFM_POWERPC_PMU_NONE, ++ .write_pmc = pfm_ppc32_write_pmc, ++ .write_pmd = pfm_ppc32_write_pmd, ++ .read_pmd = pfm_ppc32_read_pmd, ++ .get_ovfl_pmds = pfm_ppc32_get_ovfl_pmds, ++ .enable_counters = pfm_ppc32_enable_counters, ++ .disable_counters = pfm_ppc32_disable_counters, ++}; ++ ++static struct pfm_pmu_config pfm_ppc32_pmu_conf = { ++ .counter_width = 31, ++ .pmd_desc = pfm_ppc32_pmd_desc, ++ .pmc_desc = pfm_ppc32_pmc_desc, ++ .probe_pmu = pfm_ppc32_probe_pmu, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .version = "0.1", ++ .arch_info = &pfm_ppc32_pmu_info, ++}; ++ ++static int __init pfm_ppc32_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_ppc32_pmu_conf); ++} ++ ++static void __exit pfm_ppc32_pmu_cleanup_module(void) ++{ ++ release_pmc_hardware(); ++ pfm_pmu_unregister(&pfm_ppc32_pmu_conf); ++} ++ ++module_init(pfm_ppc32_pmu_init_module); ++module_exit(pfm_ppc32_pmu_cleanup_module); +--- a/arch/powerpc/platforms/cell/cbe_regs.c ++++ b/arch/powerpc/platforms/cell/cbe_regs.c +@@ -33,6 +33,7 @@ static struct cbe_regs_map + struct cbe_iic_regs __iomem *iic_regs; + struct cbe_mic_tm_regs __iomem *mic_tm_regs; + struct cbe_pmd_shadow_regs pmd_shadow_regs; ++ struct cbe_ppe_priv_regs __iomem *ppe_priv_regs; + } cbe_regs_maps[MAX_CBE]; + static int cbe_regs_map_count; + +@@ -145,6 +146,23 @@ struct cbe_mic_tm_regs __iomem *cbe_get_ + } + EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs); + ++struct cbe_ppe_priv_regs __iomem *cbe_get_ppe_priv_regs(struct device_node *np) ++{ ++ struct cbe_regs_map *map = cbe_find_map(np); ++ if (map == NULL) ++ return NULL; ++ return map->ppe_priv_regs; ++} ++ ++struct cbe_ppe_priv_regs __iomem *cbe_get_cpu_ppe_priv_regs(int cpu) ++{ ++ struct cbe_regs_map *map = cbe_thread_map[cpu].regs; ++ if (map == NULL) ++ return NULL; ++ return map->ppe_priv_regs; ++} ++EXPORT_SYMBOL_GPL(cbe_get_cpu_ppe_priv_regs); ++ + u32 cbe_get_hw_thread_id(int cpu) + { + return cbe_thread_map[cpu].thread_id; +@@ -206,6 +224,11 @@ void __init cbe_fill_regs_map(struct cbe + for_each_node_by_type(np, "mic-tm") + if (of_get_parent(np) == be) + map->mic_tm_regs = of_iomap(np, 0); ++ ++ for_each_node_by_type(np, "ppe-mmio") ++ if (of_get_parent(np) == be) ++ map->ppe_priv_regs = of_iomap(np, 0); ++ + } else { + struct device_node *cpu; + /* That hack must die die die ! */ +@@ -227,6 +250,10 @@ void __init cbe_fill_regs_map(struct cbe + prop = of_get_property(cpu, "mic-tm", NULL); + if (prop != NULL) + map->mic_tm_regs = ioremap(prop->address, prop->len); ++ ++ prop = of_get_property(cpu, "ppe-mmio", NULL); ++ if (prop != NULL) ++ map->ppe_priv_regs = ioremap(prop->address, prop->len); + } + } + +--- a/arch/sparc/include/asm/hypervisor.h ++++ b/arch/sparc/include/asm/hypervisor.h +@@ -2713,6 +2713,30 @@ extern unsigned long sun4v_ldc_revoke(un + */ + #define HV_FAST_SET_PERFREG 0x101 + ++#define HV_N2_PERF_SPARC_CTL 0x0 ++#define HV_N2_PERF_DRAM_CTL0 0x1 ++#define HV_N2_PERF_DRAM_CNT0 0x2 ++#define HV_N2_PERF_DRAM_CTL1 0x3 ++#define HV_N2_PERF_DRAM_CNT1 0x4 ++#define HV_N2_PERF_DRAM_CTL2 0x5 ++#define HV_N2_PERF_DRAM_CNT2 0x6 ++#define HV_N2_PERF_DRAM_CTL3 0x7 ++#define HV_N2_PERF_DRAM_CNT3 0x8 ++ ++#define HV_FAST_N2_GET_PERFREG 0x104 ++#define HV_FAST_N2_SET_PERFREG 0x105 ++ ++#ifndef __ASSEMBLY__ ++extern unsigned long sun4v_niagara_getperf(unsigned long reg, ++ unsigned long *val); ++extern unsigned long sun4v_niagara_setperf(unsigned long reg, ++ unsigned long val); ++extern unsigned long sun4v_niagara2_getperf(unsigned long reg, ++ unsigned long *val); ++extern unsigned long sun4v_niagara2_setperf(unsigned long reg, ++ unsigned long val); ++#endif ++ + /* MMU statistics services. + * + * The hypervisor maintains MMU statistics and privileged code provides +--- a/arch/sparc/include/asm/irq_64.h ++++ b/arch/sparc/include/asm/irq_64.h +@@ -67,6 +67,9 @@ extern void virt_irq_free(unsigned int v + extern void __init init_IRQ(void); + extern void fixup_irqs(void); + ++extern int register_perfctr_intr(void (*handler)(struct pt_regs *)); ++extern void release_perfctr_intr(void (*handler)(struct pt_regs *)); ++ + static inline void set_softint(unsigned long bits) + { + __asm__ __volatile__("wr %0, 0x0, %%set_softint" +--- /dev/null ++++ b/arch/sparc/include/asm/perfmon.h +@@ -0,0 +1,11 @@ ++#ifndef _SPARC64_PERFMON_H_ ++#define _SPARC64_PERFMON_H_ ++ ++/* ++ * arch-specific user visible interface definitions ++ */ ++ ++#define PFM_ARCH_MAX_PMCS 2 ++#define PFM_ARCH_MAX_PMDS 3 ++ ++#endif /* _SPARC64_PERFMON_H_ */ +--- /dev/null ++++ b/arch/sparc/include/asm/perfmon_kern.h +@@ -0,0 +1,286 @@ ++#ifndef _SPARC64_PERFMON_KERN_H_ ++#define _SPARC64_PERFMON_KERN_H_ ++ ++#ifdef __KERNEL__ ++ ++#ifdef CONFIG_PERFMON ++ ++#include ++#include ++ ++#define PFM_ARCH_PMD_STK_ARG 2 ++#define PFM_ARCH_PMC_STK_ARG 1 ++ ++struct pfm_arch_pmu_info { ++ u32 pmu_style; ++}; ++ ++static inline void pfm_arch_resend_irq(struct pfm_context *ctx) ++{ ++} ++ ++static inline void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++static inline void pfm_arch_serialize(void) ++{ ++} ++ ++/* ++ * SPARC does not save the PMDs during pfm_arch_intr_freeze_pmu(), thus ++ * this routine needs to do it when switching sets on overflow ++ */ ++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_save_pmds(ctx, set); ++} ++ ++extern void pfm_arch_write_pmc(struct pfm_context *ctx, ++ unsigned int cnum, u64 value); ++extern u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum); ++ ++static inline void pfm_arch_write_pmd(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ u64 pic; ++ ++ value &= pfm_pmu_conf->ovfl_mask; ++ ++ read_pic(pic); ++ ++ switch (cnum) { ++ case 0: ++ pic = (pic & 0xffffffff00000000UL) | ++ (value & 0xffffffffUL); ++ break; ++ case 1: ++ pic = (pic & 0xffffffffUL) | ++ (value << 32UL); ++ break; ++ default: ++ BUG(); ++ } ++ ++ write_pic(pic); ++} ++ ++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, ++ unsigned int cnum) ++{ ++ u64 pic; ++ ++ read_pic(pic); ++ ++ switch (cnum) { ++ case 0: ++ return pic & 0xffffffffUL; ++ case 1: ++ return pic >> 32UL; ++ default: ++ BUG(); ++ return 0; ++ } ++} ++ ++/* ++ * For some CPUs, the upper bits of a counter must be set in order for the ++ * overflow interrupt to happen. On overflow, the counter has wrapped around, ++ * and the upper bits are cleared. This function may be used to set them back. ++ */ ++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, ++ unsigned int cnum) ++{ ++ u64 val = pfm_arch_read_pmd(ctx, cnum); ++ ++ /* This masks out overflow bit 31 */ ++ pfm_arch_write_pmd(ctx, cnum, val); ++} ++ ++/* ++ * At certain points, perfmon needs to know if monitoring has been ++ * explicitely started/stopped by user via pfm_start/pfm_stop. The ++ * information is tracked in ctx.flags.started. However on certain ++ * architectures, it may be possible to start/stop directly from ++ * user level with a single assembly instruction bypassing ++ * the kernel. This function must be used to determine by ++ * an arch-specific mean if monitoring is actually started/stopped. ++ */ ++static inline int pfm_arch_is_active(struct pfm_context *ctx) ++{ ++ return ctx->flags.started; ++} ++ ++static inline void pfm_arch_ctxswout_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{ ++} ++ ++static inline void pfm_arch_ctxswin_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{ ++} ++ ++static inline void pfm_arch_ctxswin_thread(struct task_struct *task, ++ struct pfm_context *ctx) ++{ ++} ++ ++int pfm_arch_is_monitoring_active(struct pfm_context *ctx); ++int pfm_arch_ctxswout_thread(struct task_struct *task, ++ struct pfm_context *ctx); ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); ++char *pfm_arch_get_pmu_module_name(void); ++ ++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_arch_stop(current, ctx); ++ /* ++ * we mark monitoring as stopped to avoid ++ * certain side effects especially in ++ * pfm_switch_sets_from_intr() on ++ * pfm_arch_restore_pmcs() ++ */ ++ ctx->flags.started = 0; ++} ++ ++/* ++ * unfreeze PMU from pfm_do_interrupt_handler() ++ * ctx may be NULL for spurious ++ */ ++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx) ++{ ++ if (!ctx) ++ return; ++ ++ PFM_DBG_ovfl("state=%d", ctx->state); ++ ++ ctx->flags.started = 1; ++ ++ if (ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ pfm_arch_restore_pmcs(ctx, ctx->active_set); ++} ++ ++/* ++ * this function is called from the PMU interrupt handler ONLY. ++ * On SPARC, the PMU is frozen via arch_stop, masking would be implemented ++ * via arch-stop as well. Given that the PMU is already stopped when ++ * entering the interrupt handler, we do not need to stop it again, so ++ * this function is a nop. ++ */ ++static inline void pfm_arch_mask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++} ++ ++/* ++ * on MIPS masking/unmasking uses the start/stop mechanism, so we simply ++ * need to start here. ++ */ ++static inline void pfm_arch_unmask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_arch_start(current, ctx); ++} ++ ++static inline void pfm_arch_pmu_config_remove(void) ++{ ++} ++ ++static inline int pfm_arch_context_create(struct pfm_context *ctx, ++ u32 ctx_flags) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_context_free(struct pfm_context *ctx) ++{ ++} ++ ++/* ++ * function called from pfm_setfl_sane(). Context is locked ++ * and interrupts are masked. ++ * The value of flags is the value of ctx_flags as passed by ++ * user. ++ * ++ * function must check arch-specific set flags. ++ * Return: ++ * 1 when flags are valid ++ * 0 on error ++ */ ++static inline int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_init(void) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_init_percpu(void) ++{ ++} ++ ++static inline int pfm_arch_load_context(struct pfm_context *ctx) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_unload_context(struct pfm_context *ctx) ++{} ++ ++extern void perfmon_interrupt(struct pt_regs *); ++ ++static inline int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++ return register_perfctr_intr(perfmon_interrupt); ++} ++ ++static inline void pfm_arch_pmu_release(void) ++{ ++ release_perfctr_intr(perfmon_interrupt); ++} ++ ++static inline void pfm_arch_arm_handle_work(struct task_struct *task) ++{} ++ ++static inline void pfm_arch_disarm_handle_work(struct task_struct *task) ++{} ++ ++static inline int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_get_base_syscall(void) ++{ ++ return __NR_pfm_create_context; ++} ++ ++struct pfm_arch_context { ++ /* empty */ ++}; ++ ++#define PFM_ARCH_CTX_SIZE sizeof(struct pfm_arch_context) ++/* ++ * SPARC needs extra alignment for the sampling buffer ++ */ ++#define PFM_ARCH_SMPL_ALIGN_SIZE (16 * 1024) ++ ++static inline void pfm_cacheflush(void *addr, unsigned int len) ++{ ++} ++ ++#endif /* CONFIG_PERFMON */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _SPARC64_PERFMON_KERN_H_ */ +--- a/arch/sparc/include/asm/system_64.h ++++ b/arch/sparc/include/asm/system_64.h +@@ -30,6 +30,9 @@ enum sparc_cpu { + #define ARCH_SUN4C_SUN4 0 + #define ARCH_SUN4 0 + ++extern char *sparc_cpu_type; ++extern char *sparc_fpu_type; ++extern char *sparc_pmu_type; + extern char reboot_command[]; + + /* These are here in an effort to more fully work around Spitfire Errata +@@ -104,15 +107,13 @@ do { __asm__ __volatile__("ba,pt %%xcc, + #define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p)) + #define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p)) + +-/* Blackbird errata workaround. See commentary in +- * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() +- * for more information. +- */ +-#define reset_pic() \ +- __asm__ __volatile__("ba,pt %xcc, 99f\n\t" \ ++/* Blackbird errata workaround. */ ++#define write_pic(val) \ ++ __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ + ".align 64\n" \ +- "99:wr %g0, 0x0, %pic\n\t" \ +- "rd %pic, %g0") ++ "99:wr %0, 0x0, %%pic\n\t" \ ++ "rd %%pic, %%g0" : : "r" (val)) ++#define reset_pic() write_pic(0) + + #ifndef __ASSEMBLY__ + +@@ -145,14 +146,10 @@ do { \ + * and 2 stores in this critical code path. -DaveM + */ + #define switch_to(prev, next, last) \ +-do { if (test_thread_flag(TIF_PERFCTR)) { \ +- unsigned long __tmp; \ +- read_pcr(__tmp); \ +- current_thread_info()->pcr_reg = __tmp; \ +- read_pic(__tmp); \ +- current_thread_info()->kernel_cntd0 += (unsigned int)(__tmp);\ +- current_thread_info()->kernel_cntd1 += ((__tmp) >> 32); \ +- } \ ++do { if (test_tsk_thread_flag(prev, TIF_PERFMON_CTXSW)) \ ++ pfm_ctxsw_out(prev, next); \ ++ if (test_tsk_thread_flag(next, TIF_PERFMON_CTXSW)) \ ++ pfm_ctxsw_in(prev, next); \ + flush_tlb_pending(); \ + save_and_clear_fpu(); \ + /* If you are tempted to conditionalize the following */ \ +@@ -197,11 +194,6 @@ do { if (test_thread_flag(TIF_PERFCTR)) + "l1", "l2", "l3", "l4", "l5", "l6", "l7", \ + "i0", "i1", "i2", "i3", "i4", "i5", \ + "o0", "o1", "o2", "o3", "o4", "o5", "o7"); \ +- /* If you fuck with this, update ret_from_syscall code too. */ \ +- if (test_thread_flag(TIF_PERFCTR)) { \ +- write_pcr(current_thread_info()->pcr_reg); \ +- reset_pic(); \ +- } \ + } while(0) + + static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val) +--- a/arch/sparc/include/asm/thread_info_64.h ++++ b/arch/sparc/include/asm/thread_info_64.h +@@ -58,11 +58,6 @@ struct thread_info { + unsigned long gsr[7]; + unsigned long xfsr[7]; + +- __u64 __user *user_cntd0; +- __u64 __user *user_cntd1; +- __u64 kernel_cntd0, kernel_cntd1; +- __u64 pcr_reg; +- + struct restart_block restart_block; + + struct pt_regs *kern_una_regs; +@@ -96,15 +91,10 @@ struct thread_info { + #define TI_RWIN_SPTRS 0x000003c8 + #define TI_GSR 0x00000400 + #define TI_XFSR 0x00000438 +-#define TI_USER_CNTD0 0x00000470 +-#define TI_USER_CNTD1 0x00000478 +-#define TI_KERN_CNTD0 0x00000480 +-#define TI_KERN_CNTD1 0x00000488 +-#define TI_PCR 0x00000490 +-#define TI_RESTART_BLOCK 0x00000498 +-#define TI_KUNA_REGS 0x000004c0 +-#define TI_KUNA_INSN 0x000004c8 +-#define TI_FPREGS 0x00000500 ++#define TI_RESTART_BLOCK 0x00000470 ++#define TI_KUNA_REGS 0x00000498 ++#define TI_KUNA_INSN 0x000004a0 ++#define TI_FPREGS 0x000004c0 + + /* We embed this in the uppermost byte of thread_info->flags */ + #define FAULT_CODE_WRITE 0x01 /* Write access, implies D-TLB */ +@@ -222,11 +212,11 @@ register struct thread_info *current_thr + #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ + #define TIF_SIGPENDING 2 /* signal pending */ + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +-#define TIF_PERFCTR 4 /* performance counters active */ ++/* Bit 4 is available */ + #define TIF_UNALIGNED 5 /* allowed to do unaligned accesses */ + /* flag bit 6 is available */ + #define TIF_32BIT 7 /* 32-bit binary */ +-/* flag bit 8 is available */ ++#define TIF_PERFMON_WORK 8 /* work for pfm_handle_work() */ + #define TIF_SECCOMP 9 /* secure computing */ + #define TIF_SYSCALL_AUDIT 10 /* syscall auditing active */ + /* flag bit 11 is available */ +@@ -237,22 +227,24 @@ register struct thread_info *current_thr + #define TIF_ABI_PENDING 12 + #define TIF_MEMDIE 13 + #define TIF_POLLING_NRFLAG 14 ++#define TIF_PERFMON_CTXSW 15 /* perfmon needs ctxsw calls */ + + #define _TIF_SYSCALL_TRACE (1< + #include + #include ++#include + + #include + #include +@@ -385,11 +386,7 @@ void exit_thread(void) + t->utraps[0]--; + } + +- if (test_and_clear_thread_flag(TIF_PERFCTR)) { +- t->user_cntd0 = t->user_cntd1 = NULL; +- t->pcr_reg = 0; +- write_pcr(0); +- } ++ pfm_exit_thread(); + } + + void flush_thread(void) +@@ -411,13 +408,6 @@ void flush_thread(void) + + set_thread_wsaved(0); + +- /* Turn off performance counters if on. */ +- if (test_and_clear_thread_flag(TIF_PERFCTR)) { +- t->user_cntd0 = t->user_cntd1 = NULL; +- t->pcr_reg = 0; +- write_pcr(0); +- } +- + /* Clear FPU register state. */ + t->fpsaved[0] = 0; + +@@ -631,16 +621,6 @@ int copy_thread(int nr, unsigned long cl + t->kregs->u_regs[UREG_FP] = + ((unsigned long) child_sf) - STACK_BIAS; + +- /* Special case, if we are spawning a kernel thread from +- * a userspace task (usermode helper, NFS or similar), we +- * must disable performance counters in the child because +- * the address space and protection realm are changing. +- */ +- if (t->flags & _TIF_PERFCTR) { +- t->user_cntd0 = t->user_cntd1 = NULL; +- t->pcr_reg = 0; +- t->flags &= ~_TIF_PERFCTR; +- } + t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); + t->kregs->u_regs[UREG_G6] = (unsigned long) t; + t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; +@@ -673,6 +653,8 @@ int copy_thread(int nr, unsigned long cl + if (clone_flags & CLONE_SETTLS) + t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; + ++ pfm_copy_thread(p); ++ + return 0; + } + +--- a/arch/sparc64/kernel/rtrap.S ++++ b/arch/sparc64/kernel/rtrap.S +@@ -65,55 +65,14 @@ __handle_user_windows: + ba,pt %xcc, __handle_user_windows_continue + + andn %l1, %l4, %l1 +-__handle_perfctrs: +- call update_perfctrs +- wrpr %g0, RTRAP_PSTATE, %pstate +- wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +- ldub [%g6 + TI_WSAVED], %o2 +- brz,pt %o2, 1f +- nop +- /* Redo userwin+sched+sig checks */ +- call fault_in_user_windows +- +- wrpr %g0, RTRAP_PSTATE, %pstate +- wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +- ldx [%g6 + TI_FLAGS], %l0 +- andcc %l0, _TIF_NEED_RESCHED, %g0 +- be,pt %xcc, 1f +- +- nop +- call schedule +- wrpr %g0, RTRAP_PSTATE, %pstate +- wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +- ldx [%g6 + TI_FLAGS], %l0 +-1: andcc %l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0 +- +- be,pt %xcc, __handle_perfctrs_continue +- sethi %hi(TSTATE_PEF), %o0 +- mov %l5, %o1 +- add %sp, PTREGS_OFF, %o0 +- mov %l0, %o2 +- call do_notify_resume +- +- wrpr %g0, RTRAP_PSTATE, %pstate +- wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate +- /* Signal delivery can modify pt_regs tstate, so we must +- * reload it. +- */ +- ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 +- sethi %hi(0xf << 20), %l4 +- and %l1, %l4, %l4 +- andn %l1, %l4, %l1 +- ba,pt %xcc, __handle_perfctrs_continue +- +- sethi %hi(TSTATE_PEF), %o0 + __handle_userfpu: + rd %fprs, %l5 + andcc %l5, FPRS_FEF, %g0 + sethi %hi(TSTATE_PEF), %o0 + be,a,pn %icc, __handle_userfpu_continue + andn %l1, %o0, %l1 +- ba,a,pt %xcc, __handle_userfpu_continue ++ ba,pt %xcc, __handle_userfpu_continue ++ nop + + __handle_signal: + mov %l5, %o1 +@@ -202,12 +161,8 @@ __handle_signal_continue: + brnz,pn %o2, __handle_user_windows + nop + __handle_user_windows_continue: +- ldx [%g6 + TI_FLAGS], %l5 +- andcc %l5, _TIF_PERFCTR, %g0 + sethi %hi(TSTATE_PEF), %o0 +- bne,pn %xcc, __handle_perfctrs +-__handle_perfctrs_continue: +- andcc %l1, %o0, %g0 ++ andcc %l1, %o0, %g0 + + /* This fpdepth clear is necessary for non-syscall rtraps only */ + user_nowork: +--- a/arch/sparc64/kernel/setup.c ++++ b/arch/sparc64/kernel/setup.c +@@ -352,6 +352,7 @@ static int show_cpuinfo(struct seq_file + seq_printf(m, + "cpu\t\t: %s\n" + "fpu\t\t: %s\n" ++ "pmu\t\t: %s\n" + "prom\t\t: %s\n" + "type\t\t: %s\n" + "ncpus probed\t: %d\n" +@@ -364,6 +365,7 @@ static int show_cpuinfo(struct seq_file + , + sparc_cpu_type, + sparc_fpu_type, ++ sparc_pmu_type, + prom_version, + ((tlb_type == hypervisor) ? + "sun4v" : +--- a/arch/sparc64/kernel/signal.c ++++ b/arch/sparc64/kernel/signal.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -608,6 +609,9 @@ static void do_signal(struct pt_regs *re + + void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) + { ++ if (thread_info_flags & _TIF_PERFMON_WORK) ++ pfm_handle_work(regs); ++ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs, orig_i0); + if (thread_info_flags & _TIF_NOTIFY_RESUME) { +--- a/arch/sparc64/kernel/sys_sparc.c ++++ b/arch/sparc64/kernel/sys_sparc.c +@@ -26,7 +26,6 @@ + + #include + #include +-#include + #include + + #include "entry.h" +@@ -788,107 +787,11 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, + return ret; + } + +-/* Invoked by rtrap code to update performance counters in +- * user space. +- */ +-asmlinkage void update_perfctrs(void) +-{ +- unsigned long pic, tmp; +- +- read_pic(pic); +- tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic); +- __put_user(tmp, current_thread_info()->user_cntd0); +- tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32)); +- __put_user(tmp, current_thread_info()->user_cntd1); +- reset_pic(); +-} +- + SYSCALL_DEFINE4(perfctr, int, opcode, unsigned long, arg0, + unsigned long, arg1, unsigned long, arg2) + { +- int err = 0; +- +- switch(opcode) { +- case PERFCTR_ON: +- current_thread_info()->pcr_reg = arg2; +- current_thread_info()->user_cntd0 = (u64 __user *) arg0; +- current_thread_info()->user_cntd1 = (u64 __user *) arg1; +- current_thread_info()->kernel_cntd0 = +- current_thread_info()->kernel_cntd1 = 0; +- write_pcr(arg2); +- reset_pic(); +- set_thread_flag(TIF_PERFCTR); +- break; +- +- case PERFCTR_OFF: +- err = -EINVAL; +- if (test_thread_flag(TIF_PERFCTR)) { +- current_thread_info()->user_cntd0 = +- current_thread_info()->user_cntd1 = NULL; +- current_thread_info()->pcr_reg = 0; +- write_pcr(0); +- clear_thread_flag(TIF_PERFCTR); +- err = 0; +- } +- break; +- +- case PERFCTR_READ: { +- unsigned long pic, tmp; +- +- if (!test_thread_flag(TIF_PERFCTR)) { +- err = -EINVAL; +- break; +- } +- read_pic(pic); +- tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic); +- err |= __put_user(tmp, current_thread_info()->user_cntd0); +- tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32)); +- err |= __put_user(tmp, current_thread_info()->user_cntd1); +- reset_pic(); +- break; +- } +- +- case PERFCTR_CLRPIC: +- if (!test_thread_flag(TIF_PERFCTR)) { +- err = -EINVAL; +- break; +- } +- current_thread_info()->kernel_cntd0 = +- current_thread_info()->kernel_cntd1 = 0; +- reset_pic(); +- break; +- +- case PERFCTR_SETPCR: { +- u64 __user *user_pcr = (u64 __user *)arg0; +- +- if (!test_thread_flag(TIF_PERFCTR)) { +- err = -EINVAL; +- break; +- } +- err |= __get_user(current_thread_info()->pcr_reg, user_pcr); +- write_pcr(current_thread_info()->pcr_reg); +- current_thread_info()->kernel_cntd0 = +- current_thread_info()->kernel_cntd1 = 0; +- reset_pic(); +- break; +- } +- +- case PERFCTR_GETPCR: { +- u64 __user *user_pcr = (u64 __user *)arg0; +- +- if (!test_thread_flag(TIF_PERFCTR)) { +- err = -EINVAL; +- break; +- } +- err |= __put_user(current_thread_info()->pcr_reg, user_pcr); +- break; +- } +- +- default: +- err = -EINVAL; +- break; +- }; +- return err; ++ /* Superceded by perfmon2 */ ++ return -ENOSYS; + } + + /* +--- a/arch/sparc64/kernel/syscalls.S ++++ b/arch/sparc64/kernel/syscalls.S +@@ -117,26 +117,9 @@ ret_from_syscall: + stb %g0, [%g6 + TI_NEW_CHILD] + ldx [%g6 + TI_FLAGS], %l0 + call schedule_tail +- mov %g7, %o0 +- andcc %l0, _TIF_PERFCTR, %g0 +- be,pt %icc, 1f +- nop +- ldx [%g6 + TI_PCR], %o7 +- wr %g0, %o7, %pcr +- +- /* Blackbird errata workaround. See commentary in +- * smp.c:smp_percpu_timer_interrupt() for more +- * information. +- */ +- ba,pt %xcc, 99f +- nop +- +- .align 64 +-99: wr %g0, %g0, %pic +- rd %pic, %g0 +- +-1: ba,pt %xcc, ret_sys_call +- ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 ++ mov %g7, %o0 ++ ba,pt %xcc, ret_sys_call ++ ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 + + .globl sparc_exit + .type sparc_exit,#function +--- a/arch/sparc64/kernel/systbls.S ++++ b/arch/sparc64/kernel/systbls.S +@@ -82,7 +82,9 @@ sys_call_table32: + .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait + /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate + .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 +-/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1 ++/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_pfm_create_context, sys_pfm_write_pmcs ++ .word sys_pfm_write_pmds, sys_pfm_read_pmds, sys_pfm_load_context, sys_pfm_start, sys_pfm_stop ++/*330*/ .word sys_pfm_restart, sys_pfm_create_evtsets, sys_pfm_getinfo_evtsets, sys_pfm_delete_evtsets, sys_pfm_unload_context + + #endif /* CONFIG_COMPAT */ + +@@ -156,4 +158,6 @@ sys_call_table: + .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait + /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate + .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 +-/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1 ++/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_pfm_create_context, sys_pfm_write_pmcs ++ .word sys_pfm_write_pmds, sys_pfm_read_pmds, sys_pfm_load_context, sys_pfm_start, sys_pfm_stop ++/*330*/ .word sys_pfm_restart, sys_pfm_create_evtsets, sys_pfm_getinfo_evtsets, sys_pfm_delete_evtsets, sys_pfm_unload_context +--- a/arch/sparc64/kernel/traps.c ++++ b/arch/sparc64/kernel/traps.c +@@ -2485,85 +2485,89 @@ extern void tsb_config_offsets_are_bolix + /* Only invoked on boot processor. */ + void __init trap_init(void) + { +- /* Compile time sanity check. */ +- if (TI_TASK != offsetof(struct thread_info, task) || +- TI_FLAGS != offsetof(struct thread_info, flags) || +- TI_CPU != offsetof(struct thread_info, cpu) || +- TI_FPSAVED != offsetof(struct thread_info, fpsaved) || +- TI_KSP != offsetof(struct thread_info, ksp) || +- TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) || +- TI_KREGS != offsetof(struct thread_info, kregs) || +- TI_UTRAPS != offsetof(struct thread_info, utraps) || +- TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) || +- TI_REG_WINDOW != offsetof(struct thread_info, reg_window) || +- TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) || +- TI_GSR != offsetof(struct thread_info, gsr) || +- TI_XFSR != offsetof(struct thread_info, xfsr) || +- TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) || +- TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) || +- TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) || +- TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) || +- TI_PCR != offsetof(struct thread_info, pcr_reg) || +- TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || +- TI_NEW_CHILD != offsetof(struct thread_info, new_child) || +- TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || +- TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) || +- TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) || +- TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) || +- TI_FPREGS != offsetof(struct thread_info, fpregs) || +- (TI_FPREGS & (64 - 1))) +- thread_info_offsets_are_bolixed_dave(); ++ BUILD_BUG_ON(TI_TASK != offsetof(struct thread_info, task)); ++ BUILD_BUG_ON(TI_FLAGS != offsetof(struct thread_info, flags)); ++ BUILD_BUG_ON(TI_CPU != offsetof(struct thread_info, cpu)); ++ BUILD_BUG_ON(TI_FPSAVED != offsetof(struct thread_info, fpsaved)); ++ BUILD_BUG_ON(TI_KSP != offsetof(struct thread_info, ksp)); ++ BUILD_BUG_ON(TI_FAULT_ADDR != ++ offsetof(struct thread_info, fault_address)); ++ BUILD_BUG_ON(TI_KREGS != offsetof(struct thread_info, kregs)); ++ BUILD_BUG_ON(TI_UTRAPS != offsetof(struct thread_info, utraps)); ++ BUILD_BUG_ON(TI_EXEC_DOMAIN != ++ offsetof(struct thread_info, exec_domain)); ++ BUILD_BUG_ON(TI_REG_WINDOW != ++ offsetof(struct thread_info, reg_window)); ++ BUILD_BUG_ON(TI_RWIN_SPTRS != ++ offsetof(struct thread_info, rwbuf_stkptrs)); ++ BUILD_BUG_ON(TI_GSR != offsetof(struct thread_info, gsr)); ++ BUILD_BUG_ON(TI_XFSR != offsetof(struct thread_info, xfsr)); ++ BUILD_BUG_ON(TI_PRE_COUNT != ++ offsetof(struct thread_info, preempt_count)); ++ BUILD_BUG_ON(TI_NEW_CHILD != ++ offsetof(struct thread_info, new_child)); ++ BUILD_BUG_ON(TI_SYS_NOERROR != ++ offsetof(struct thread_info, syscall_noerror)); ++ BUILD_BUG_ON(TI_RESTART_BLOCK != ++ offsetof(struct thread_info, restart_block)); ++ BUILD_BUG_ON(TI_KUNA_REGS != ++ offsetof(struct thread_info, kern_una_regs)); ++ BUILD_BUG_ON(TI_KUNA_INSN != ++ offsetof(struct thread_info, kern_una_insn)); ++ BUILD_BUG_ON(TI_FPREGS != offsetof(struct thread_info, fpregs)); ++ BUILD_BUG_ON((TI_FPREGS & (64 - 1))); + +- if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) || +- (TRAP_PER_CPU_PGD_PADDR != +- offsetof(struct trap_per_cpu, pgd_paddr)) || +- (TRAP_PER_CPU_CPU_MONDO_PA != +- offsetof(struct trap_per_cpu, cpu_mondo_pa)) || +- (TRAP_PER_CPU_DEV_MONDO_PA != +- offsetof(struct trap_per_cpu, dev_mondo_pa)) || +- (TRAP_PER_CPU_RESUM_MONDO_PA != +- offsetof(struct trap_per_cpu, resum_mondo_pa)) || +- (TRAP_PER_CPU_RESUM_KBUF_PA != +- offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) || +- (TRAP_PER_CPU_NONRESUM_MONDO_PA != +- offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || +- (TRAP_PER_CPU_NONRESUM_KBUF_PA != +- offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) || +- (TRAP_PER_CPU_FAULT_INFO != +- offsetof(struct trap_per_cpu, fault_info)) || +- (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != +- offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) || +- (TRAP_PER_CPU_CPU_LIST_PA != +- offsetof(struct trap_per_cpu, cpu_list_pa)) || +- (TRAP_PER_CPU_TSB_HUGE != +- offsetof(struct trap_per_cpu, tsb_huge)) || +- (TRAP_PER_CPU_TSB_HUGE_TEMP != +- offsetof(struct trap_per_cpu, tsb_huge_temp)) || +- (TRAP_PER_CPU_IRQ_WORKLIST_PA != +- offsetof(struct trap_per_cpu, irq_worklist_pa)) || +- (TRAP_PER_CPU_CPU_MONDO_QMASK != +- offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || +- (TRAP_PER_CPU_DEV_MONDO_QMASK != +- offsetof(struct trap_per_cpu, dev_mondo_qmask)) || +- (TRAP_PER_CPU_RESUM_QMASK != +- offsetof(struct trap_per_cpu, resum_qmask)) || +- (TRAP_PER_CPU_NONRESUM_QMASK != +- offsetof(struct trap_per_cpu, nonresum_qmask))) +- trap_per_cpu_offsets_are_bolixed_dave(); ++ BUILD_BUG_ON(TRAP_PER_CPU_THREAD != ++ offsetof(struct trap_per_cpu, thread)); ++ BUILD_BUG_ON(TRAP_PER_CPU_PGD_PADDR != ++ offsetof(struct trap_per_cpu, pgd_paddr)); ++ BUILD_BUG_ON(TRAP_PER_CPU_CPU_MONDO_PA != ++ offsetof(struct trap_per_cpu, cpu_mondo_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_DEV_MONDO_PA != ++ offsetof(struct trap_per_cpu, dev_mondo_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_RESUM_MONDO_PA != ++ offsetof(struct trap_per_cpu, resum_mondo_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_RESUM_KBUF_PA != ++ offsetof(struct trap_per_cpu, resum_kernel_buf_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_NONRESUM_MONDO_PA != ++ offsetof(struct trap_per_cpu, nonresum_mondo_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_NONRESUM_KBUF_PA != ++ offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_FAULT_INFO != ++ offsetof(struct trap_per_cpu, fault_info)); ++ BUILD_BUG_ON(TRAP_PER_CPU_CPU_MONDO_BLOCK_PA != ++ offsetof(struct trap_per_cpu, cpu_mondo_block_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_CPU_LIST_PA != ++ offsetof(struct trap_per_cpu, cpu_list_pa)); ++ BUILD_BUG_ON(TRAP_PER_CPU_TSB_HUGE != ++ offsetof(struct trap_per_cpu, tsb_huge)); ++ BUILD_BUG_ON(TRAP_PER_CPU_TSB_HUGE_TEMP != ++ offsetof(struct trap_per_cpu, tsb_huge_temp)); ++#if 0 ++ BUILD_BUG_ON(TRAP_PER_CPU_IRQ_WORKLIST != ++ offsetof(struct trap_per_cpu, irq_worklist)); ++#endif ++ BUILD_BUG_ON(TRAP_PER_CPU_CPU_MONDO_QMASK != ++ offsetof(struct trap_per_cpu, cpu_mondo_qmask)); ++ BUILD_BUG_ON(TRAP_PER_CPU_DEV_MONDO_QMASK != ++ offsetof(struct trap_per_cpu, dev_mondo_qmask)); ++ BUILD_BUG_ON(TRAP_PER_CPU_RESUM_QMASK != ++ offsetof(struct trap_per_cpu, resum_qmask)); ++ BUILD_BUG_ON(TRAP_PER_CPU_NONRESUM_QMASK != ++ offsetof(struct trap_per_cpu, nonresum_qmask)); + +- if ((TSB_CONFIG_TSB != +- offsetof(struct tsb_config, tsb)) || +- (TSB_CONFIG_RSS_LIMIT != +- offsetof(struct tsb_config, tsb_rss_limit)) || +- (TSB_CONFIG_NENTRIES != +- offsetof(struct tsb_config, tsb_nentries)) || +- (TSB_CONFIG_REG_VAL != +- offsetof(struct tsb_config, tsb_reg_val)) || +- (TSB_CONFIG_MAP_VADDR != +- offsetof(struct tsb_config, tsb_map_vaddr)) || +- (TSB_CONFIG_MAP_PTE != +- offsetof(struct tsb_config, tsb_map_pte))) +- tsb_config_offsets_are_bolixed_dave(); ++ BUILD_BUG_ON(TSB_CONFIG_TSB != ++ offsetof(struct tsb_config, tsb)); ++ BUILD_BUG_ON(TSB_CONFIG_RSS_LIMIT != ++ offsetof(struct tsb_config, tsb_rss_limit)); ++ BUILD_BUG_ON(TSB_CONFIG_NENTRIES != ++ offsetof(struct tsb_config, tsb_nentries)); ++ BUILD_BUG_ON(TSB_CONFIG_REG_VAL != ++ offsetof(struct tsb_config, tsb_reg_val)); ++ BUILD_BUG_ON(TSB_CONFIG_MAP_VADDR != ++ offsetof(struct tsb_config, tsb_map_vaddr)); ++ BUILD_BUG_ON(TSB_CONFIG_MAP_PTE != ++ offsetof(struct tsb_config, tsb_map_pte)); + + /* Attach to the address space of init_task. On SMP we + * do this in smp.c:smp_callin for other cpus. +--- a/arch/sparc64/kernel/ttable.S ++++ b/arch/sparc64/kernel/ttable.S +@@ -72,7 +72,7 @@ tl0_irq8: BTRAP(0x48) + tl0_irq9: BTRAP(0x49) + tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) + tl0_irq14: TRAP_IRQ(timer_interrupt, 14) +-tl0_irq15: TRAP_IRQ(handler_irq, 15) ++tl0_irq15: TRAP_IRQ(perfctr_irq, 15) + tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) + tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) + tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f) +--- /dev/null ++++ b/arch/sparc64/perfmon/Kconfig +@@ -0,0 +1,26 @@ ++menu "Hardware Performance Monitoring support" ++config PERFMON ++ bool "Perfmon2 performance monitoring interface" ++ default n ++ help ++ Enables the perfmon2 interface to access the hardware ++ performance counters. See for ++ more details. ++ ++config PERFMON_DEBUG ++ bool "Perfmon debugging" ++ depends on PERFMON ++ default n ++ help ++ Enables perfmon debugging support ++ ++config PERFMON_DEBUG_FS ++ bool "Enable perfmon statistics reporting via debugfs" ++ default y ++ depends on PERFMON && DEBUG_FS ++ help ++ Enable collection and reporting of perfmon timing statistics under ++ debugfs. This is used for debugging and performance analysis of the ++ subsystem. The debugfs filesystem must be mounted. ++ ++endmenu +--- /dev/null ++++ b/arch/sparc64/perfmon/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_PERFMON) += perfmon.o +--- /dev/null ++++ b/arch/sparc64/perfmon/perfmon.c +@@ -0,0 +1,422 @@ ++/* perfmon.c: sparc64 perfmon support ++ * ++ * Copyright (C) 2007 David S. Miller (davem@davemloft.net) ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++struct pcr_ops { ++ void (*write)(u64); ++ u64 (*read)(void); ++}; ++ ++static void direct_write_pcr(u64 val) ++{ ++ write_pcr(val); ++} ++ ++static u64 direct_read_pcr(void) ++{ ++ u64 pcr; ++ ++ read_pcr(pcr); ++ ++ return pcr; ++} ++ ++static struct pcr_ops direct_pcr_ops = { ++ .write = direct_write_pcr, ++ .read = direct_read_pcr, ++}; ++ ++/* Using the hypervisor call is needed so that we can set the ++ * hypervisor trace bit correctly, which is hyperprivileged. ++ */ ++static void n2_write_pcr(u64 val) ++{ ++ unsigned long ret; ++ ++ ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val); ++ if (val != HV_EOK) ++ write_pcr(val); ++} ++ ++static u64 n2_read_pcr(void) ++{ ++ u64 pcr; ++ ++ read_pcr(pcr); ++ ++ return pcr; ++} ++ ++static struct pcr_ops n2_pcr_ops = { ++ .write = n2_write_pcr, ++ .read = n2_read_pcr, ++}; ++ ++static struct pcr_ops *pcr_ops; ++ ++void pfm_arch_write_pmc(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ /* ++ * we only write to the actual register when monitoring is ++ * active (pfm_start was issued) ++ */ ++ if (ctx && ctx->flags.started == 0) ++ return; ++ ++ pcr_ops->write(value); ++} ++ ++u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum) ++{ ++ return pcr_ops->read(); ++} ++ ++/* ++ * collect pending overflowed PMDs. Called from pfm_ctxsw() ++ * and from PMU interrupt handler. Must fill in set->povfl_pmds[] ++ * and set->npend_ovfls. Interrupts are masked ++ */ ++static void __pfm_get_ovfl_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ unsigned int max = ctx->regs.max_intr_pmd; ++ u64 wmask = 1ULL << pfm_pmu_conf->counter_width; ++ u64 *intr_pmds = ctx->regs.intr_pmds; ++ u64 *used_mask = set->used_pmds; ++ u64 mask[PFM_PMD_BV]; ++ unsigned int i; ++ ++ bitmap_and(cast_ulp(mask), ++ cast_ulp(intr_pmds), ++ cast_ulp(used_mask), ++ max); ++ ++ /* ++ * check all PMD that can generate interrupts ++ * (that includes counters) ++ */ ++ for (i = 0; i < max; i++) { ++ if (test_bit(i, mask)) { ++ u64 new_val = pfm_arch_read_pmd(ctx, i); ++ ++ PFM_DBG_ovfl("pmd%u new_val=0x%llx bit=%d\n", ++ i, (unsigned long long)new_val, ++ (new_val&wmask) ? 1 : 0); ++ ++ if (new_val & wmask) { ++ __set_bit(i, set->povfl_pmds); ++ set->npend_ovfls++; ++ } ++ } ++ } ++} ++ ++static void pfm_stop_active(struct task_struct *task, struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ unsigned int i, max = ctx->regs.max_pmc; ++ ++ /* ++ * clear enable bits, assume all pmcs are enable pmcs ++ */ ++ for (i = 0; i < max; i++) { ++ if (test_bit(i, set->used_pmcs)) ++ pfm_arch_write_pmc(ctx, i, 0); ++ } ++ ++ if (set->npend_ovfls) ++ return; ++ ++ __pfm_get_ovfl_pmds(ctx, set); ++} ++ ++/* ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * Context is locked. Interrupts are masked. Monitoring is active. ++ * PMU access is guaranteed. PMC and PMD registers are live in PMU. ++ * ++ * for per-thread: ++ * must stop monitoring for the task ++ * ++ * Return: ++ * non-zero : did not save PMDs (as part of stopping the PMU) ++ * 0 : saved PMDs (no need to save them in caller) ++ */ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ /* ++ * disable lazy restore of PMC registers. ++ */ ++ ctx->active_set->priv_flags |= PFM_SETFL_PRIV_MOD_PMCS; ++ ++ pfm_stop_active(task, ctx, ctx->active_set); ++ ++ return 1; ++} ++ ++/* ++ * Called from pfm_stop() and idle notifier ++ * ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-thread: ++ * task is not necessarily current. If not current task, then ++ * task is guaranteed stopped and off any cpu. Access to PMU ++ * is not guaranteed. Interrupts are masked. Context is locked. ++ * Set is the active set. ++ * ++ * For system-wide: ++ * task is current ++ * ++ * must disable active monitoring. ctx cannot be NULL ++ */ ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx) ++{ ++ /* ++ * no need to go through stop_save() ++ * if we are already stopped ++ */ ++ if (!ctx->flags.started || ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ /* ++ * stop live registers and collect pending overflow ++ */ ++ if (task == current) ++ pfm_stop_active(task, ctx, ctx->active_set); ++} ++ ++/* ++ * Enable active monitoring. Called from pfm_start() and ++ * pfm_arch_unmask_monitoring(). ++ * ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-trhead: ++ * Task is not necessarily current. If not current task, then task ++ * is guaranteed stopped and off any cpu. Access to PMU is not guaranteed. ++ * ++ * For system-wide: ++ * task is always current ++ * ++ * must enable active monitoring. ++ */ ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ unsigned int max_pmc = ctx->regs.max_pmc; ++ unsigned int i; ++ ++ if (task != current) ++ return; ++ ++ set = ctx->active_set; ++ for (i = 0; i < max_pmc; i++) { ++ if (test_bit(i, set->used_pmcs)) ++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]); ++ } ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets() ++ * context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMD registers from set. ++ */ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ unsigned int max_pmd = ctx->regs.max_pmd; ++ u64 ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ u64 *impl_pmds = ctx->regs.pmds; ++ unsigned int i; ++ ++ /* ++ * must restore all pmds to avoid leaking ++ * information to user. ++ */ ++ for (i = 0; i < max_pmd; i++) { ++ u64 val; ++ ++ if (test_bit(i, impl_pmds) == 0) ++ continue; ++ ++ val = set->pmds[i].value; ++ ++ /* ++ * set upper bits for counter to ensure ++ * overflow will trigger ++ */ ++ val &= ovfl_mask; ++ ++ pfm_arch_write_pmd(ctx, i, val); ++ } ++} ++ ++/* ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(). ++ * Context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMC registers from set, if needed. ++ */ ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ unsigned int max_pmc = ctx->regs.max_pmc; ++ u64 *impl_pmcs = ctx->regs.pmcs; ++ unsigned int i; ++ ++ /* If we're masked or stopped we don't need to bother restoring ++ * the PMCs now. ++ */ ++ if (ctx->state == PFM_CTX_MASKED || ctx->flags.started == 0) ++ return; ++ ++ /* ++ * restore all pmcs ++ */ ++ for (i = 0; i < max_pmc; i++) ++ if (test_bit(i, impl_pmcs)) ++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]); ++} ++ ++char *pfm_arch_get_pmu_module_name(void) ++{ ++ return NULL; ++} ++ ++void perfmon_interrupt(struct pt_regs *regs) ++{ ++ pfm_interrupt_handler(instruction_pointer(regs), regs); ++} ++ ++static struct pfm_regmap_desc pfm_sparc64_pmc_desc[] = { ++ PMC_D(PFM_REG_I, "PCR", 0, 0, 0, 0), ++}; ++ ++static struct pfm_regmap_desc pfm_sparc64_pmd_desc[] = { ++ PMD_D(PFM_REG_C, "PIC0", 0), ++ PMD_D(PFM_REG_C, "PIC1", 0), ++}; ++ ++static int pfm_sparc64_probe(void) ++{ ++ return 0; ++} ++ ++static struct pfm_pmu_config pmu_sparc64_pmu_conf = { ++ .counter_width = 31, ++ .pmd_desc = pfm_sparc64_pmd_desc, ++ .num_pmd_entries = 2, ++ .pmc_desc = pfm_sparc64_pmc_desc, ++ .num_pmc_entries = 1, ++ .probe_pmu = pfm_sparc64_probe, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++}; ++ ++static unsigned long perf_hsvc_group; ++static unsigned long perf_hsvc_major; ++static unsigned long perf_hsvc_minor; ++ ++static int __init register_perf_hsvc(void) ++{ ++ if (tlb_type == hypervisor) { ++ switch (sun4v_chip_type) { ++ case SUN4V_CHIP_NIAGARA1: ++ perf_hsvc_group = HV_GRP_N2_CPU; ++ break; ++ ++ case SUN4V_CHIP_NIAGARA2: ++ perf_hsvc_group = HV_GRP_N2_CPU; ++ break; ++ ++ default: ++ return -ENODEV; ++ } ++ ++ ++ perf_hsvc_major = 1; ++ perf_hsvc_minor = 0; ++ if (sun4v_hvapi_register(perf_hsvc_group, ++ perf_hsvc_major, ++ &perf_hsvc_minor)) { ++ printk("perfmon: Could not register N2 hvapi.\n"); ++ return -ENODEV; ++ } ++ } ++ return 0; ++} ++ ++static void unregister_perf_hsvc(void) ++{ ++ if (tlb_type != hypervisor) ++ return; ++ sun4v_hvapi_unregister(perf_hsvc_group); ++} ++ ++static int __init pfm_sparc64_pmu_init(void) ++{ ++ u64 mask; ++ int err; ++ ++ err = register_perf_hsvc(); ++ if (err) ++ return err; ++ ++ if (tlb_type == hypervisor && ++ sun4v_chip_type == SUN4V_CHIP_NIAGARA2) ++ pcr_ops = &n2_pcr_ops; ++ else ++ pcr_ops = &direct_pcr_ops; ++ ++ if (!strcmp(sparc_pmu_type, "ultra12")) ++ mask = (0xf << 11) | (0xf << 4) | 0x7; ++ else if (!strcmp(sparc_pmu_type, "ultra3") || ++ !strcmp(sparc_pmu_type, "ultra3i") || ++ !strcmp(sparc_pmu_type, "ultra3+") || ++ !strcmp(sparc_pmu_type, "ultra4+")) ++ mask = (0x3f << 11) | (0x3f << 4) | 0x7; ++ else if (!strcmp(sparc_pmu_type, "niagara2")) ++ mask = ((1UL << 63) | (1UL << 62) | ++ (1UL << 31) | (0xfUL << 27) | (0xffUL << 19) | ++ (1UL << 18) | (0xfUL << 14) | (0xff << 6) | ++ (0x3UL << 4) | 0x7UL); ++ else if (!strcmp(sparc_pmu_type, "niagara")) ++ mask = ((1UL << 9) | (1UL << 8) | ++ (0x7UL << 4) | 0x7UL); ++ else { ++ err = -ENODEV; ++ goto out_err; ++ } ++ ++ pmu_sparc64_pmu_conf.pmu_name = sparc_pmu_type; ++ pfm_sparc64_pmc_desc[0].rsvd_msk = ~mask; ++ ++ return pfm_pmu_register(&pmu_sparc64_pmu_conf); ++ ++out_err: ++ unregister_perf_hsvc(); ++ return err; ++} ++ ++static void __exit pfm_sparc64_pmu_exit(void) ++{ ++ unregister_perf_hsvc(); ++ return pfm_pmu_unregister(&pmu_sparc64_pmu_conf); ++} ++ ++module_init(pfm_sparc64_pmu_init); ++module_exit(pfm_sparc64_pmu_exit); +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -1448,6 +1448,8 @@ config COMPAT_VDSO + + If unsure, say Y. + ++source "arch/x86/perfmon/Kconfig" ++ + endmenu + + config ARCH_ENABLE_MEMORY_HOTPLUG +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -152,6 +152,8 @@ core-$(CONFIG_LGUEST_GUEST) += arch/x86/ + core-y += arch/x86/kernel/ + core-y += arch/x86/mm/ + ++core-$(CONFIG_PERFMON) += arch/x86/perfmon/ ++ + # Remaining sub architecture files + core-y += $(mcore-y) + +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -834,4 +834,16 @@ ia32_sys_call_table: + .quad sys_dup3 /* 330 */ + .quad sys_pipe2 + .quad sys_inotify_init1 ++ .quad sys_pfm_create_context ++ .quad sys_pfm_write_pmcs ++ .quad sys_pfm_write_pmds /* 335 */ ++ .quad sys_pfm_read_pmds ++ .quad sys_pfm_load_context ++ .quad sys_pfm_start ++ .quad sys_pfm_stop ++ .quad sys_pfm_restart /* 340 */ ++ .quad sys_pfm_create_evtsets ++ .quad sys_pfm_getinfo_evtsets ++ .quad sys_pfm_delete_evtsets ++ .quad sys_pfm_unload_context + ia32_syscall_end: +--- a/arch/x86/kernel/apic_32.c ++++ b/arch/x86/kernel/apic_32.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -697,6 +698,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 ms + setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); + return APIC_EILVT_LVTOFF_IBS; + } ++EXPORT_SYMBOL(setup_APIC_eilvt_ibs); + + /* + * Local APIC start and shutdown +@@ -1397,6 +1399,9 @@ void __init apic_intr_init(void) + #ifdef CONFIG_X86_MCE_P4THERMAL + alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); + #endif ++#ifdef CONFIG_PERFMON ++ set_intr_gate(LOCAL_PERFMON_VECTOR, pmu_interrupt); ++#endif + } + + /** +--- a/arch/x86/kernel/apic_64.c ++++ b/arch/x86/kernel/apic_64.c +@@ -299,6 +299,7 @@ u8 setup_APIC_eilvt_ibs(u8 vector, u8 ms + setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask); + return APIC_EILVT_LVTOFF_IBS; + } ++EXPORT_SYMBOL(setup_APIC_eilvt_ibs); + + /* + * Program the next event, relative to now +--- a/arch/x86/kernel/cpu/common.c ++++ b/arch/x86/kernel/cpu/common.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -728,6 +729,8 @@ void __cpuinit cpu_init(void) + current_thread_info()->status = 0; + clear_used_math(); + mxcsr_feature_mask_init(); ++ ++ pfm_init_percpu(); + } + + #ifdef CONFIG_HOTPLUG_CPU +--- a/arch/x86/kernel/entry_32.S ++++ b/arch/x86/kernel/entry_32.S +@@ -513,7 +513,7 @@ ENDPROC(system_call) + ALIGN + RING0_PTREGS_FRAME # can't unwind into user space anyway + work_pending: +- testb $_TIF_NEED_RESCHED, %cl ++ testw $(_TIF_NEED_RESCHED|_TIF_PERFMON_WORK), %cx + jz work_notifysig + work_resched: + call schedule +--- a/arch/x86/kernel/entry_64.S ++++ b/arch/x86/kernel/entry_64.S +@@ -890,7 +890,13 @@ END(error_interrupt) + ENTRY(spurious_interrupt) + apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt + END(spurious_interrupt) +- ++ ++#ifdef CONFIG_PERFMON ++ENTRY(pmu_interrupt) ++ apicinterrupt LOCAL_PERFMON_VECTOR,smp_pmu_interrupt ++END(pmu_interrupt) ++#endif ++ + /* + * Exception entry points. + */ +--- a/arch/x86/kernel/irqinit_64.c ++++ b/arch/x86/kernel/irqinit_64.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -217,6 +218,10 @@ void __init native_init_IRQ(void) + alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); + alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt); + ++#ifdef CONFIG_PERFMON ++ alloc_intr_gate(LOCAL_PERFMON_VECTOR, pmu_interrupt); ++#endif ++ + if (!acpi_ioapic) + setup_irq(2, &irq2); + } +--- a/arch/x86/kernel/process_32.c ++++ b/arch/x86/kernel/process_32.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -277,6 +278,7 @@ void exit_thread(void) + tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; + put_cpu(); + } ++ pfm_exit_thread(); + } + + void flush_thread(void) +@@ -334,6 +336,8 @@ int copy_thread(int nr, unsigned long cl + + savesegment(gs, p->thread.gs); + ++ pfm_copy_thread(p); ++ + tsk = current; + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { + p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, +@@ -450,6 +454,9 @@ __switch_to_xtra(struct task_struct *pre + prev = &prev_p->thread; + next = &next_p->thread; + ++ if (test_tsk_thread_flag(prev_p, TIF_PERFMON_CTXSW)) ++ pfm_ctxsw_out(prev_p, next_p); ++ + debugctl = prev->debugctlmsr; + if (next->ds_area_msr != prev->ds_area_msr) { + /* we clear debugctl to make sure DS +@@ -462,6 +469,9 @@ __switch_to_xtra(struct task_struct *pre + if (next->debugctlmsr != debugctl) + update_debugctlmsr(next->debugctlmsr); + ++ if (test_tsk_thread_flag(next_p, TIF_PERFMON_CTXSW)) ++ pfm_ctxsw_in(prev_p, next_p); ++ + if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { + set_debugreg(next->debugreg0, 0); + set_debugreg(next->debugreg1, 1); +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -240,6 +241,7 @@ void exit_thread(void) + t->io_bitmap_max = 0; + put_cpu(); + } ++ pfm_exit_thread(); + } + + void flush_thread(void) +@@ -344,6 +346,8 @@ int copy_thread(int nr, unsigned long cl + savesegment(es, p->thread.es); + savesegment(ds, p->thread.ds); + ++ pfm_copy_thread(p); ++ + if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) { + p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); + if (!p->thread.io_bitmap_ptr) { +@@ -474,6 +478,9 @@ static inline void __switch_to_xtra(stru + prev = &prev_p->thread, + next = &next_p->thread; + ++ if (test_tsk_thread_flag(prev_p, TIF_PERFMON_CTXSW)) ++ pfm_ctxsw_out(prev_p, next_p); ++ + debugctl = prev->debugctlmsr; + if (next->ds_area_msr != prev->ds_area_msr) { + /* we clear debugctl to make sure DS +@@ -486,6 +493,9 @@ static inline void __switch_to_xtra(stru + if (next->debugctlmsr != debugctl) + update_debugctlmsr(next->debugctlmsr); + ++ if (test_tsk_thread_flag(next_p, TIF_PERFMON_CTXSW)) ++ pfm_ctxsw_in(prev_p, next_p); ++ + if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { + loaddebug(next, 0); + loaddebug(next, 1); +--- a/arch/x86/kernel/signal_32.c ++++ b/arch/x86/kernel/signal_32.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -664,6 +665,10 @@ static void do_signal(struct pt_regs *re + void + do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) + { ++ /* process perfmon asynchronous work (e.g. block thread or reset) */ ++ if (thread_info_flags & _TIF_PERFMON_WORK) ++ pfm_handle_work(regs); ++ + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs); +--- a/arch/x86/kernel/signal_64.c ++++ b/arch/x86/kernel/signal_64.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -528,12 +529,17 @@ static void do_signal(struct pt_regs *re + void do_notify_resume(struct pt_regs *regs, void *unused, + __u32 thread_info_flags) + { ++ + #ifdef CONFIG_X86_MCE + /* notify userspace of pending MCEs */ + if (thread_info_flags & _TIF_MCE_NOTIFY) + mce_notify_user(); + #endif /* CONFIG_X86_MCE */ + ++ /* process perfmon asynchronous work (e.g. block thread or reset) */ ++ if (thread_info_flags & _TIF_PERFMON_WORK) ++ pfm_handle_work(regs); ++ + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs); +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1377,6 +1378,7 @@ int __cpu_disable(void) + remove_cpu_from_maps(cpu); + unlock_vector_lock(); + fixup_irqs(cpu_online_map); ++ pfm_cpu_disable(); + return 0; + } + +--- a/arch/x86/kernel/syscall_table_32.S ++++ b/arch/x86/kernel/syscall_table_32.S +@@ -332,3 +332,15 @@ ENTRY(sys_call_table) + .long sys_dup3 /* 330 */ + .long sys_pipe2 + .long sys_inotify_init1 ++ .long sys_pfm_create_context ++ .long sys_pfm_write_pmcs ++ .long sys_pfm_write_pmds /* 335 */ ++ .long sys_pfm_read_pmds ++ .long sys_pfm_load_context ++ .long sys_pfm_start ++ .long sys_pfm_stop ++ .long sys_pfm_restart /* 340 */ ++ .long sys_pfm_create_evtsets ++ .long sys_pfm_getinfo_evtsets ++ .long sys_pfm_delete_evtsets ++ .long sys_pfm_unload_context +--- a/arch/x86/oprofile/nmi_int.c ++++ b/arch/x86/oprofile/nmi_int.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -217,12 +218,18 @@ static int nmi_setup(void) + int err = 0; + int cpu; + +- if (!allocate_msrs()) ++ if (pfm_session_allcpus_acquire()) ++ return -EBUSY; ++ ++ if (!allocate_msrs()) { ++ pfm_session_allcpus_release(); + return -ENOMEM; ++ } + + err = register_die_notifier(&profile_exceptions_nb); + if (err) { + free_msrs(); ++ pfm_session_allcpus_release(); + return err; + } + +@@ -304,6 +311,7 @@ static void nmi_shutdown(void) + model->shutdown(msrs); + free_msrs(); + put_cpu_var(cpu_msrs); ++ pfm_session_allcpus_release(); + } + + static void nmi_cpu_start(void *dummy) +--- /dev/null ++++ b/arch/x86/perfmon/Kconfig +@@ -0,0 +1,89 @@ ++menu "Hardware Performance Monitoring support" ++config PERFMON ++ bool "Perfmon2 performance monitoring interface" ++ select X86_LOCAL_APIC ++ default n ++ help ++ Enables the perfmon2 interface to access the hardware ++ performance counters. See for ++ more details. ++ ++config PERFMON_DEBUG ++ bool "Perfmon debugging" ++ default n ++ depends on PERFMON ++ help ++ Enables perfmon debugging support ++ ++config PERFMON_DEBUG_FS ++ bool "Enable perfmon statistics reporting via debugfs" ++ default y ++ depends on PERFMON && DEBUG_FS ++ help ++ Enable collection and reporting of perfmon timing statistics under ++ debugfs. This is used for debugging and performance analysis of the ++ subsystem.The debugfs filesystem must be mounted. ++ ++config X86_PERFMON_P6 ++ tristate "Support for Intel P6/Pentium M processor hardware performance counters" ++ depends on PERFMON && X86_32 ++ default n ++ help ++ Enables support for Intel P6-style hardware performance counters. ++ To be used for with Intel Pentium III, PentiumPro, Pentium M processors. ++ ++config X86_PERFMON_P4 ++ tristate "Support for Intel Pentium 4/Xeon hardware performance counters" ++ depends on PERFMON ++ default n ++ help ++ Enables support for Intel Pentium 4/Xeon (Netburst) hardware performance ++ counters. ++ ++config X86_PERFMON_PEBS_P4 ++ tristate "Support for Intel Netburst Precise Event-Based Sampling (PEBS)" ++ depends on PERFMON && X86_PERFMON_P4 ++ default n ++ help ++ Enables support for Precise Event-Based Sampling (PEBS) on the Intel ++ Netburst processors such as Pentium 4, Xeon which support it. ++ ++config X86_PERFMON_CORE ++ tristate "Support for Intel Core-based performance counters" ++ depends on PERFMON ++ default n ++ help ++ Enables support for Intel Core-based performance counters. Enable ++ this option to support Intel Core 2 processors. ++ ++config X86_PERFMON_PEBS_CORE ++ tristate "Support for Intel Core Precise Event-Based Sampling (PEBS)" ++ depends on PERFMON && X86_PERFMON_CORE ++ default n ++ help ++ Enables support for Precise Event-Based Sampling (PEBS) on the Intel ++ Core processors. ++ ++config X86_PERFMON_INTEL_ATOM ++ tristate "Support for Intel Atom processor" ++ depends on PERFMON ++ default n ++ help ++ Enables support for Intel Atom processors. ++ ++config X86_PERFMON_INTEL_ARCH ++ tristate "Support for Intel architectural perfmon v1/v2" ++ depends on PERFMON ++ default n ++ help ++ Enables support for Intel architectural performance counters. ++ This feature was introduced with Intel Core Solo/Core Duo processors. ++ ++config X86_PERFMON_AMD64 ++ tristate "Support AMD Athlon64/Opteron64 hardware performance counters" ++ depends on PERFMON ++ default n ++ help ++ Enables support for Athlon64/Opterton64 hardware performance counters. ++ Support for family 6, 15 and 16(10H) processors. ++endmenu +--- /dev/null ++++ b/arch/x86/perfmon/Makefile +@@ -0,0 +1,13 @@ ++# ++# Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++# Contributed by Stephane Eranian ++# ++obj-$(CONFIG_PERFMON) += perfmon.o ++obj-$(CONFIG_X86_PERFMON_P6) += perfmon_p6.o ++obj-$(CONFIG_X86_PERFMON_P4) += perfmon_p4.o ++obj-$(CONFIG_X86_PERFMON_CORE) += perfmon_intel_core.o ++obj-$(CONFIG_X86_PERFMON_INTEL_ARCH) += perfmon_intel_arch.o ++obj-$(CONFIG_X86_PERFMON_PEBS_P4) += perfmon_pebs_p4_smpl.o ++obj-$(CONFIG_X86_PERFMON_PEBS_CORE) += perfmon_pebs_core_smpl.o ++obj-$(CONFIG_X86_PERFMON_AMD64) += perfmon_amd64.o ++obj-$(CONFIG_X86_PERFMON_INTEL_ATOM) += perfmon_intel_atom.o +--- /dev/null ++++ b/arch/x86/perfmon/perfmon.c +@@ -0,0 +1,761 @@ ++/* ++ * This file implements the X86 specific support for the perfmon2 interface ++ * ++ * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * Copyright (c) 2007 Advanced Micro Devices, Inc. ++ * Contributed by Robert Richter ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++DEFINE_PER_CPU(unsigned long, real_iip); ++DEFINE_PER_CPU(int, pfm_using_nmi); ++DEFINE_PER_CPU(unsigned long, saved_lvtpc); ++ ++/** ++ * pfm_arch_ctxswin_thread - thread context switch in ++ * @task: task switched in ++ * @ctx: context for the task ++ * ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * set cannot be NULL. Context is locked. Interrupts are masked. ++ * ++ * Caller has already restored all PMD and PMC registers, if ++ * necessary (i.e., lazy restore scheme). ++ * ++ * On x86, the only common code just needs to unsecure RDPMC if necessary ++ * ++ * On model-specific features, e.g., PEBS, IBS, are taken care of in the ++ * corresponding PMU description module ++ */ ++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * restore saved real iip ++ */ ++ if (ctx->active_set->npend_ovfls) ++ __get_cpu_var(real_iip) = ctx_arch->saved_real_iip; ++ ++ /* ++ * enable RDPMC on this CPU ++ */ ++ if (ctx_arch->flags.insecure) ++ set_in_cr4(X86_CR4_PCE); ++} ++ ++/** ++ * pfm_arch_ctxswout_thread - context switch out thread ++ * @task: task switched out ++ * @ctx : context switched out ++ * ++ * Called from pfm_ctxsw(). Task is guaranteed to be current. ++ * Context is locked. Interrupts are masked. Monitoring may be active. ++ * PMU access is guaranteed. PMC and PMD registers are live in PMU. ++ * ++ * Return: ++ * non-zero : did not save PMDs (as part of stopping the PMU) ++ * 0 : saved PMDs (no need to save them in caller) ++ */ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * disable lazy restore of PMCS on ctxswin because ++ * we modify some of them. ++ */ ++ ctx->active_set->priv_flags |= PFM_SETFL_PRIV_MOD_PMCS; ++ ++ if (ctx->active_set->npend_ovfls) ++ ctx_arch->saved_real_iip = __get_cpu_var(real_iip); ++ ++ /* ++ * disable RDPMC on this CPU ++ */ ++ if (ctx_arch->flags.insecure) ++ clear_in_cr4(X86_CR4_PCE); ++ ++ if (ctx->state == PFM_CTX_MASKED) ++ return 1; ++ ++ return pmu_info->stop_save(ctx, ctx->active_set); ++} ++ ++/** ++ * pfm_arch_stop - deactivate monitoring ++ * @task: task to stop ++ * @ctx: context to stop ++ * ++ * Called from pfm_stop() ++ * Interrupts are masked. Context is locked. Set is the active set. ++ * ++ * For per-thread: ++ * task is not necessarily current. If not current task, then ++ * task is guaranteed stopped and off any cpu. Access to PMU ++ * is not guaranteed. ++ * ++ * For system-wide: ++ * task is current ++ * ++ * must disable active monitoring. ctx cannot be NULL ++ */ ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * no need to go through stop_save() ++ * if we are already stopped ++ */ ++ if (!ctx->flags.started || ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ if (task != current) ++ return; ++ ++ pmu_info->stop_save(ctx, ctx->active_set); ++} ++ ++ ++/** ++ * pfm_arch_start - activate monitoring ++ * @task: task to start ++ * @ctx: context to stop ++ * ++ * Interrupts are masked. Context is locked. ++ * ++ * For per-thread: ++ * Task is not necessarily current. If not current task, then task ++ * is guaranteed stopped and off any cpu. No access to PMU is task ++ * is not current. ++ * ++ * For system-wide: ++ * task is always current ++ */ ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ ++ set = ctx->active_set; ++ ++ if (task != current) ++ return; ++ ++ /* ++ * cannot restore PMC if no access to PMU. Will be done ++ * when the thread is switched back in ++ */ ++ ++ pfm_arch_restore_pmcs(ctx, set); ++} ++ ++/** ++ * pfm_arch_restore_pmds - reload PMD registers ++ * @ctx: context to restore from ++ * @set: current event set ++ * ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw() ++ * ++ * Context is locked. Interrupts are masked. Set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ */ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u16 i, num; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ num = set->nused_pmds; ++ ++ /* ++ * model-specific override ++ */ ++ if (pmu_info->restore_pmds) { ++ pmu_info->restore_pmds(ctx, set); ++ return; ++ } ++ ++ /* ++ * we can restore only the PMD we use because: ++ * ++ * - can only read with pfm_read_pmds() the registers ++ * declared used via pfm_write_pmds(), smpl_pmds, reset_pmds ++ * ++ * - if cr4.pce=1, only counters are exposed to user. RDPMC ++ * does not work with other types of PMU registers.Thus, no ++ * address is ever exposed by counters ++ * ++ * - there is never a dependency between one pmd register and ++ * another ++ */ ++ for (i = 0; num; i++) { ++ if (likely(test_bit(i, cast_ulp(set->used_pmds)))) { ++ pfm_write_pmd(ctx, i, set->pmds[i].value); ++ num--; ++ } ++ } ++} ++ ++/** ++ * pfm_arch_restore_pmcs - reload PMC registers ++ * @ctx: context to restore from ++ * @set: current event set ++ * ++ * function called from pfm_switch_sets(), pfm_context_load_thread(), ++ * pfm_context_load_sys(), pfm_ctxsw(). ++ * ++ * Context is locked. Interrupts are masked. set cannot be NULL. ++ * Access to the PMU is guaranteed. ++ * ++ * function must restore all PMC registers from set ++ */ ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u64 *mask; ++ u16 i, num; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * we need to restore PMCs only when: ++ * - context is not masked ++ * - monitoring activated ++ * ++ * Masking monitoring after an overflow does not change the ++ * value of flags.started ++ */ ++ if (ctx->state == PFM_CTX_MASKED || !ctx->flags.started) ++ return; ++ ++ /* ++ * model-specific override ++ */ ++ if (pmu_info->restore_pmcs) { ++ pmu_info->restore_pmcs(ctx, set); ++ return; ++ } ++ /* ++ * restore all pmcs ++ * ++ * It is not possible to restore only the pmcs we used because ++ * certain PMU models (e.g. Pentium 4) have dependencies. Thus ++ * we do not want one application using stale PMC coming from ++ * another one. ++ * ++ * On PMU models where there is no dependencies between pmc, then ++ * it is possible to optimize by only restoring the registers that ++ * are used, and this can be done with the models-specific override ++ * for this function. ++ * ++ * The default code takes the safest approach, i.e., assume the worse ++ */ ++ mask = ctx->regs.pmcs; ++ num = ctx->regs.num_pmcs; ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(mask))) { ++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]); ++ num--; ++ } ++ } ++} ++ ++/** ++ * smp_pmu_interrupt - lowest level PMU interrupt handler for X86 ++ * @regs: machine state ++ * ++ * The PMU interrupt is handled through an interrupt gate, therefore ++ * the CPU automatically clears the EFLAGS.IF, i.e., masking interrupts. ++ * ++ * The perfmon interrupt handler MUST run with interrupts disabled due ++ * to possible race with other, higher priority interrupts, such as timer ++ * or IPI function calls. ++ * ++ * See description in IA-32 architecture manual, Vol 3 section 5.8.1 ++ */ ++void smp_pmu_interrupt(struct pt_regs *regs) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_context *ctx; ++ unsigned long iip; ++ int using_nmi; ++ ++ using_nmi = __get_cpu_var(pfm_using_nmi); ++ ++ ack_APIC_irq(); ++ ++ irq_enter(); ++ ++ /* ++ * when using NMI, pfm_handle_nmi() gets called ++ * first. It stops monitoring and record the ++ * iip into real_iip, then it repost the interrupt ++ * using the lower priority vector LOCAL_PERFMON_VECTOR ++ * ++ * On some processors, e.g., P4, it may be that some ++ * state is already recorded from pfm_handle_nmi() ++ * and it only needs to be copied back into the normal ++ * fields so it can be used transparently by higher level ++ * code. ++ */ ++ if (using_nmi) { ++ ctx = __get_cpu_var(pmu_ctx); ++ pmu_info = pfm_pmu_info(); ++ iip = __get_cpu_var(real_iip); ++ if (ctx && pmu_info->nmi_copy_state) ++ pmu_info->nmi_copy_state(ctx); ++ } else ++ iip = instruction_pointer(regs); ++ ++ pfm_interrupt_handler(iip, regs); ++ ++ /* ++ * On Intel P6, Pentium M, P4, Intel Core: ++ * - it is necessary to clear the MASK field for the LVTPC ++ * vector. Otherwise interrupts remain masked. See ++ * section 8.5.1 ++ * AMD X86-64: ++ * - the documentation does not stipulate the behavior. ++ * To be safe, we also rewrite the vector to clear the ++ * mask field ++ */ ++ if (!using_nmi && current_cpu_data.x86_vendor == X86_VENDOR_INTEL) ++ apic_write(APIC_LVTPC, LOCAL_PERFMON_VECTOR); ++ ++ irq_exit(); ++} ++ ++/** ++ * pfm_handle_nmi - PMU NMI handler notifier callback ++ * @nb ; notifier block ++ * @val: type of die notifier ++ * @data: die notifier-specific data ++ * ++ * called from notify_die() notifier from an trap handler path. We only ++ * care about NMI related callbacks, and ignore everything else. ++ * ++ * Cannot grab any locks, include the perfmon context lock ++ * ++ * Must detect if NMI interrupt comes from perfmon, and if so it must ++ * stop the PMU and repost a lower-priority interrupt. The perfmon interrupt ++ * handler needs to grab the context lock, thus is cannot be run directly ++ * from the NMI interrupt call path. ++ */ ++static int __kprobes pfm_handle_nmi(struct notifier_block *nb, ++ unsigned long val, ++ void *data) ++{ ++ struct die_args *args = data; ++ struct pfm_context *ctx; ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ /* ++ * only NMI related calls ++ */ ++ if (val != DIE_NMI_IPI) ++ return NOTIFY_DONE; ++ ++ /* ++ * perfmon not using NMI ++ */ ++ if (!__get_cpu_var(pfm_using_nmi)) ++ return NOTIFY_DONE; ++ ++ /* ++ * No context ++ */ ++ ctx = __get_cpu_var(pmu_ctx); ++ if (!ctx) { ++ PFM_DBG_ovfl("no ctx"); ++ return NOTIFY_DONE; ++ } ++ ++ /* ++ * Detect if we have overflows, i.e., NMI interrupt ++ * caused by PMU ++ */ ++ pmu_info = pfm_pmu_conf->pmu_info; ++ if (!pmu_info->has_ovfls(ctx)) { ++ PFM_DBG_ovfl("no ovfl"); ++ return NOTIFY_DONE; ++ } ++ ++ /* ++ * we stop the PMU to avoid further overflow before this ++ * one is treated by lower priority interrupt handler ++ */ ++ pmu_info->quiesce(); ++ ++ /* ++ * record actual instruction pointer ++ */ ++ __get_cpu_var(real_iip) = instruction_pointer(args->regs); ++ ++ /* ++ * post lower priority interrupt (LOCAL_PERFMON_VECTOR) ++ */ ++ pfm_arch_resend_irq(ctx); ++ ++ pfm_stats_inc(ovfl_intr_nmi_count); ++ ++ /* ++ * we need to rewrite the APIC vector on Intel ++ */ ++ if (current_cpu_data.x86_vendor == X86_VENDOR_INTEL) ++ apic_write(APIC_LVTPC, APIC_DM_NMI); ++ ++ /* ++ * the notification was for us ++ */ ++ return NOTIFY_STOP; ++} ++ ++static struct notifier_block pfm_nmi_nb = { ++ .notifier_call = pfm_handle_nmi ++}; ++ ++/** ++ * pfm_arch_get_pmu_module_name - get PMU description module name for autoload ++ * ++ * called from pfm_pmu_request_module ++ */ ++char *pfm_arch_get_pmu_module_name(void) ++{ ++ switch (current_cpu_data.x86) { ++ case 6: ++ switch (current_cpu_data.x86_model) { ++ case 3: /* Pentium II */ ++ case 7 ... 11: ++ case 13: ++ return "perfmon_p6"; ++ case 15: /* Merom */ ++ case 23: /* Penryn */ ++ return "perfmon_intel_core"; ++ case 28: /* Atom/Silverthorne */ ++ return "perfmon_intel_atom"; ++ case 29: /* Dunnington */ ++ return "perfmon_intel_core"; ++ default: ++ goto try_arch; ++ } ++ case 15: ++ case 16: ++ /* All Opteron processors */ ++ if (current_cpu_data.x86_vendor == X86_VENDOR_AMD) ++ return "perfmon_amd64"; ++ ++ switch (current_cpu_data.x86_model) { ++ case 0 ... 6: ++ return "perfmon_p4"; ++ } ++ /* FALL THROUGH */ ++ default: ++try_arch: ++ if (boot_cpu_has(X86_FEATURE_ARCH_PERFMON)) ++ return "perfmon_intel_arch"; ++ return NULL; ++ } ++ return NULL; ++} ++ ++/** ++ * pfm_arch_resend_irq - post perfmon interrupt on regular vector ++ * ++ * called from pfm_ctxswin_thread() and pfm_handle_nmi() ++ */ ++void pfm_arch_resend_irq(struct pfm_context *ctx) ++{ ++ unsigned long val, dest; ++ /* ++ * we cannot use hw_resend_irq() because it goes to ++ * the I/O APIC. We need to go to the Local APIC. ++ * ++ * The "int vec" is not the right solution either ++ * because it triggers a software intr. We need ++ * to regenerate the interrupt and have it pended ++ * until we unmask interrupts. ++ * ++ * Instead we send ourself an IPI on the perfmon ++ * vector. ++ */ ++ val = APIC_DEST_SELF|APIC_INT_ASSERT| ++ APIC_DM_FIXED|LOCAL_PERFMON_VECTOR; ++ ++ dest = apic_read(APIC_ID); ++ apic_write(APIC_ICR2, dest); ++ apic_write(APIC_ICR, val); ++} ++ ++/** ++ * pfm_arch_pmu_acquire_percpu - setup APIC per CPU ++ * @data: contains pmu flags ++ */ ++static void pfm_arch_pmu_acquire_percpu(void *data) ++{ ++ ++ struct pfm_arch_pmu_info *pmu_info; ++ unsigned int tmp, vec; ++ unsigned long flags = (unsigned long)data; ++ unsigned long lvtpc; ++ ++ pmu_info = pfm_pmu_conf->pmu_info; ++ ++ /* ++ * we only reprogram the LVTPC vector if we have detected ++ * no sharing, otherwise it means the APIC is already programmed ++ * and we use whatever vector (likely NMI) is there ++ */ ++ if (!(flags & PFM_X86_FL_SHARING)) { ++ if (flags & PFM_X86_FL_USE_NMI) ++ vec = APIC_DM_NMI; ++ else ++ vec = LOCAL_PERFMON_VECTOR; ++ ++ tmp = apic_read(APIC_LVTERR); ++ apic_write(APIC_LVTERR, tmp | APIC_LVT_MASKED); ++ apic_write(APIC_LVTPC, vec); ++ apic_write(APIC_LVTERR, tmp); ++ } ++ lvtpc = (unsigned long)apic_read(APIC_LVTPC); ++ ++ __get_cpu_var(pfm_using_nmi) = lvtpc == APIC_DM_NMI; ++ ++ PFM_DBG("LTVPC=0x%lx using_nmi=%d", lvtpc, __get_cpu_var(pfm_using_nmi)); ++ ++ /* ++ * invoke model specific acquire routine. May be used for ++ * model-specific initializations ++ */ ++ if (pmu_info->acquire_pmu_percpu) ++ pmu_info->acquire_pmu_percpu(); ++} ++ ++/** ++ * pfm_arch_pmu_acquire - acquire PMU resource from system ++ * @unavail_pmcs : bitmask to use to set unavailable pmcs ++ * @unavail_pmds : bitmask to use to set unavailable pmds ++ * ++ * interrupts are not masked ++ * ++ * Grab PMU registers from lower level MSR allocator ++ * ++ * Program the APIC according the possible interrupt vector ++ * either LOCAL_PERFMON_VECTOR or NMI ++ */ ++int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_regmap_desc *d; ++ u16 i, nlost; ++ ++ pmu_info = pfm_pmu_conf->pmu_info; ++ pmu_info->flags &= ~PFM_X86_FL_SHARING; ++ ++ nlost = 0; ++ ++ d = pfm_pmu_conf->pmc_desc; ++ for (i = 0; i < pfm_pmu_conf->num_pmc_entries; i++, d++) { ++ if (!(d->type & PFM_REG_I)) ++ continue; ++ ++ if (d->type & PFM_REG_V) ++ continue; ++ /* ++ * reserve register with lower-level allocator ++ */ ++ if (!reserve_evntsel_nmi(d->hw_addr)) { ++ PFM_DBG("pmc%d(%s) already used", i, d->desc); ++ __set_bit(i, cast_ulp(unavail_pmcs)); ++ nlost++; ++ continue; ++ } ++ } ++ PFM_DBG("nlost=%d info_flags=0x%x\n", nlost, pmu_info->flags); ++ /* ++ * some PMU models (e.g., P6) do not support sharing ++ * so check if we found less than the expected number of PMC registers ++ */ ++ if (nlost) { ++ if (pmu_info->flags & PFM_X86_FL_NO_SHARING) { ++ PFM_INFO("PMU already used by another subsystem, " ++ "PMU does not support sharing, " ++ "try disabling Oprofile or " ++ "reboot with nmi_watchdog=0"); ++ goto undo; ++ } ++ pmu_info->flags |= PFM_X86_FL_SHARING; ++ } ++ ++ d = pfm_pmu_conf->pmd_desc; ++ for (i = 0; i < pfm_pmu_conf->num_pmd_entries; i++, d++) { ++ if (!(d->type & PFM_REG_I)) ++ continue; ++ ++ if (d->type & PFM_REG_V) ++ continue; ++ ++ if (!reserve_perfctr_nmi(d->hw_addr)) { ++ PFM_DBG("pmd%d(%s) already used", i, d->desc); ++ __set_bit(i, cast_ulp(unavail_pmds)); ++ } ++ } ++ /* ++ * program APIC on each CPU ++ */ ++ on_each_cpu(pfm_arch_pmu_acquire_percpu, ++ (void *)(unsigned long)pmu_info->flags , 1); ++ ++ return 0; ++undo: ++ /* ++ * must undo reservation of pmcs in case of error ++ */ ++ d = pfm_pmu_conf->pmc_desc; ++ for (i = 0; i < pfm_pmu_conf->num_pmc_entries; i++, d++) { ++ if (!(d->type & (PFM_REG_I|PFM_REG_V))) ++ continue; ++ if (!test_bit(i, cast_ulp(unavail_pmcs))) ++ release_evntsel_nmi(d->hw_addr); ++ } ++ return -EBUSY; ++} ++/** ++ * pfm-arch_pmu_release_percpu - clear NMI state for one CPU ++ * ++ */ ++static void pfm_arch_pmu_release_percpu(void *data) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_conf->pmu_info; ++ ++ __get_cpu_var(pfm_using_nmi) = 0; ++ ++ /* ++ * invoke model specific release routine. ++ * May be used to undo certain initializations ++ * or free some model-specific ressources. ++ */ ++ if (pmu_info->release_pmu_percpu) ++ pmu_info->release_pmu_percpu(); ++} ++ ++/** ++ * pfm_arch_pmu_release - release PMU resource to system ++ * ++ * called from pfm_pmu_release() ++ * interrupts are not masked ++ * ++ * On x86, we return the PMU registers to the MSR allocator ++ */ ++void pfm_arch_pmu_release(void) ++{ ++ struct pfm_regmap_desc *d; ++ u16 i, n; ++ ++ d = pfm_pmu_conf->pmc_desc; ++ n = pfm_pmu_conf->regs_all.num_pmcs; ++ for (i = 0; n; i++, d++) { ++ if (!test_bit(i, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ continue; ++ release_evntsel_nmi(d->hw_addr); ++ n--; ++ PFM_DBG("pmc%u released", i); ++ } ++ d = pfm_pmu_conf->pmd_desc; ++ n = pfm_pmu_conf->regs_all.num_pmds; ++ for (i = 0; n; i++, d++) { ++ if (!test_bit(i, cast_ulp(pfm_pmu_conf->regs_all.pmds))) ++ continue; ++ release_perfctr_nmi(d->hw_addr); ++ n--; ++ PFM_DBG("pmd%u released", i); ++ } ++ ++ /* clear NMI variable if used */ ++ if (__get_cpu_var(pfm_using_nmi)) ++ on_each_cpu(pfm_arch_pmu_release_percpu, NULL , 1); ++} ++ ++/** ++ * pfm_arch_pmu_config_init - validate PMU description structure ++ * @cfg: PMU description structure ++ * ++ * return: ++ * 0 if valid ++ * errno otherwise ++ * ++ * called from pfm_pmu_register() ++ */ ++int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_info(); ++ if (!pmu_info) { ++ PFM_DBG("%s missing pmu_info", cfg->pmu_name); ++ return -EINVAL; ++ } ++ if (!pmu_info->has_ovfls) { ++ PFM_DBG("%s missing has_ovfls callback", cfg->pmu_name); ++ return -EINVAL; ++ } ++ if (!pmu_info->quiesce) { ++ PFM_DBG("%s missing quiesce callback", cfg->pmu_name); ++ return -EINVAL; ++ } ++ if (!pmu_info->stop_save) { ++ PFM_DBG("%s missing stop_save callback", cfg->pmu_name); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/** ++ * pfm_arch_init - one time global arch-specific initialization ++ * ++ * called from pfm_init() ++ */ ++int __init pfm_arch_init(void) ++{ ++ /* ++ * we need to register our NMI handler when the kernels boots ++ * to avoid a deadlock condition with the NMI watchdog or Oprofile ++ * if we were to try and register/unregister on-demand. ++ */ ++ register_die_notifier(&pfm_nmi_nb); ++ return 0; ++} +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_amd64.c +@@ -0,0 +1,754 @@ ++/* ++ * This file contains the PMU description for the Athlon64 and Opteron64 ++ * processors. It supports 32 and 64-bit modes. ++ * ++ * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * Copyright (c) 2007 Advanced Micro Devices, Inc. ++ * Contributed by Robert Richter ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_AUTHOR("Robert Richter "); ++MODULE_DESCRIPTION("AMD64 PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203 ++ ++static int force_nmi; ++MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt"); ++module_param(force_nmi, bool, 0600); ++ ++#define HAS_IBS 0x01 /* has IBS support */ ++ ++static u8 ibs_eilvt_off, ibs_status; /* AMD: extended interrupt LVT offset */ ++ ++static void pfm_amd64_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static void __kprobes pfm_amd64_quiesce(void); ++static int pfm_amd64_has_ovfls(struct pfm_context *ctx); ++static int pfm_amd64_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++#define IBSFETCHCTL_PMC 4 /* pmc4 */ ++#define IBSFETCHCTL_PMD 4 /* pmd4 */ ++#define IBSOPSCTL_PMC 5 /* pmc5 */ ++#define IBSOPSCTL_PMD 7 /* pmd7 */ ++ ++static u64 enable_mask[PFM_MAX_PMCS]; ++static u16 max_enable; ++ ++static struct pfm_arch_pmu_info pfm_amd64_pmu_info = { ++ .stop_save = pfm_amd64_stop_save, ++ .has_ovfls = pfm_amd64_has_ovfls, ++ .quiesce = pfm_amd64_quiesce, ++ .restore_pmcs = pfm_amd64_restore_pmcs ++}; ++ ++#define PFM_AMD64_IBSFETCHVAL (1ULL<<49) /* valid fetch sample */ ++#define PFM_AMD64_IBSFETCHEN (1ULL<<48) /* fetch sampling enabled */ ++#define PFM_AMD64_IBSOPVAL (1ULL<<18) /* valid execution sample */ ++#define PFM_AMD64_IBSOPEN (1ULL<<17) /* execution sampling enabled */ ++ ++/* ++ * force Local APIC interrupt on overflow ++ */ ++#define PFM_K8_VAL (1ULL<<20) ++#define PFM_K8_NO64 (1ULL<<20) ++ ++/* ++ * reserved bits must be 1 ++ * ++ * for family 15: ++ * - upper 32 bits are reserved ++ * - bit 20, bit 21 ++ * ++ * for family 16: ++ * - bits 36-39 are reserved ++ * - bits 42-63 are reserved ++ * - bit 20, bit 21 ++ * ++ * for IBS registers: ++ * IBSFETCHCTL: all bits are reserved except bits 57, 48, 15:0 ++ * IBSOPSCTL : all bits are reserved except bits 17, 15:0 ++ */ ++#define PFM_K8_RSVD ((~((1ULL<<32)-1)) | (1ULL<<20) | (1ULL<<21)) ++#define PFM_16_RSVD ((0x3fffffULL<<42) | (0xfULL<<36) | (1ULL<<20) | (1ULL<<21)) ++#define PFM_AMD64_IBSFETCHCTL_RSVD (~((1ULL<<48)|(1ULL<<57)|0xffffULL)) ++#define PFM_AMD64_IBSOPCTL_RSVD (~((1ULL<<17)|0xffffULL)) ++ ++static struct pfm_regmap_desc pfm_amd64_pmc_desc[] = { ++/* pmc0 */ PMC_D(PFM_REG_I64, "PERFSEL0", PFM_K8_VAL, PFM_K8_RSVD, PFM_K8_NO64, MSR_K7_EVNTSEL0), ++/* pmc1 */ PMC_D(PFM_REG_I64, "PERFSEL1", PFM_K8_VAL, PFM_K8_RSVD, PFM_K8_NO64, MSR_K7_EVNTSEL1), ++/* pmc2 */ PMC_D(PFM_REG_I64, "PERFSEL2", PFM_K8_VAL, PFM_K8_RSVD, PFM_K8_NO64, MSR_K7_EVNTSEL2), ++/* pmc3 */ PMC_D(PFM_REG_I64, "PERFSEL3", PFM_K8_VAL, PFM_K8_RSVD, PFM_K8_NO64, MSR_K7_EVNTSEL3), ++/* pmc4 */ PMC_D(PFM_REG_I, "IBSFETCHCTL", 0, PFM_AMD64_IBSFETCHCTL_RSVD, 0, MSR_AMD64_IBSFETCHCTL), ++/* pmc5 */ PMC_D(PFM_REG_I, "IBSOPCTL", 0, PFM_AMD64_IBSOPCTL_RSVD, 0, MSR_AMD64_IBSOPCTL), ++}; ++#define PFM_AMD_NUM_PMCS ARRAY_SIZE(pfm_amd64_pmc_desc) ++ ++#define PFM_REG_IBS (PFM_REG_I|PFM_REG_INTR) ++ ++/* ++ * AMD64 counters are 48 bits, upper bits are reserved ++ */ ++#define PFM_AMD64_CTR_RSVD (~((1ULL<<48)-1)) ++ ++#define PFM_AMD_D(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "PERFCTR"#n, \ ++ .hw_addr = MSR_K7_PERFCTR0+n, \ ++ .rsvd_msk = PFM_AMD64_CTR_RSVD, \ ++ .dep_pmcs[0] = 1ULL << n \ ++ } ++ ++#define PFM_AMD_IBSO(t, s, a) \ ++ { .type = t, \ ++ .desc = s, \ ++ .hw_addr = a, \ ++ .rsvd_msk = 0, \ ++ .dep_pmcs[0] = 1ULL << 5 \ ++ } ++ ++#define PFM_AMD_IBSF(t, s, a) \ ++ { .type = t, \ ++ .desc = s, \ ++ .hw_addr = a, \ ++ .rsvd_msk = 0, \ ++ .dep_pmcs[0] = 1ULL << 6 \ ++ } ++ ++static struct pfm_regmap_desc pfm_amd64_pmd_desc[] = { ++/* pmd0 */ PFM_AMD_D(0), ++/* pmd1 */ PFM_AMD_D(1), ++/* pmd2 */ PFM_AMD_D(2), ++/* pmd3 */ PFM_AMD_D(3), ++/* pmd4 */ PFM_AMD_IBSF(PFM_REG_IBS, "IBSFETCHCTL", MSR_AMD64_IBSFETCHCTL), ++/* pmd5 */ PFM_AMD_IBSF(PFM_REG_IRO, "IBSFETCHLINAD", MSR_AMD64_IBSFETCHLINAD), ++/* pmd6 */ PFM_AMD_IBSF(PFM_REG_IRO, "IBSFETCHPHYSAD", MSR_AMD64_IBSFETCHPHYSAD), ++/* pmd7 */ PFM_AMD_IBSO(PFM_REG_IBS, "IBSOPCTL", MSR_AMD64_IBSOPCTL), ++/* pmd8 */ PFM_AMD_IBSO(PFM_REG_IRO, "IBSOPRIP", MSR_AMD64_IBSOPRIP), ++/* pmd9 */ PFM_AMD_IBSO(PFM_REG_IRO, "IBSOPDATA", MSR_AMD64_IBSOPDATA), ++/* pmd10 */ PFM_AMD_IBSO(PFM_REG_IRO, "IBSOPDATA2", MSR_AMD64_IBSOPDATA2), ++/* pmd11 */ PFM_AMD_IBSO(PFM_REG_IRO, "IBSOPDATA3", MSR_AMD64_IBSOPDATA3), ++/* pmd12 */ PFM_AMD_IBSO(PFM_REG_IRO, "IBSDCLINAD", MSR_AMD64_IBSDCLINAD), ++/* pmd13 */ PFM_AMD_IBSO(PFM_REG_IRO, "IBSDCPHYSAD", MSR_AMD64_IBSDCPHYSAD), ++}; ++#define PFM_AMD_NUM_PMDS ARRAY_SIZE(pfm_amd64_pmd_desc) ++ ++static struct pfm_context **pfm_nb_sys_owners; ++static struct pfm_context *pfm_nb_task_owner; ++ ++static struct pfm_pmu_config pfm_amd64_pmu_conf; ++ ++#define is_ibs_pmc(x) (x == 4 || x == 5) ++ ++static void pfm_amd64_setup_eilvt_per_cpu(void *info) ++{ ++ u8 lvt_off; ++ ++ /* program the IBS vector to the perfmon vector */ ++ lvt_off = setup_APIC_eilvt_ibs(LOCAL_PERFMON_VECTOR, ++ APIC_EILVT_MSG_FIX, 0); ++ PFM_DBG("APIC_EILVT%d set to 0x%x", lvt_off, LOCAL_PERFMON_VECTOR); ++ ibs_eilvt_off = lvt_off; ++} ++ ++static int pfm_amd64_setup_eilvt(void) ++{ ++#define IBSCTL_LVTOFFSETVAL (1 << 8) ++#define IBSCTL 0x1cc ++ struct pci_dev *cpu_cfg; ++ int nodes; ++ u32 value = 0; ++ ++ /* per CPU setup */ ++ on_each_cpu(pfm_amd64_setup_eilvt_per_cpu, NULL, 1); ++ ++ nodes = 0; ++ cpu_cfg = NULL; ++ do { ++ cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD, ++ PCI_DEVICE_ID_AMD_10H_NB_MISC, ++ cpu_cfg); ++ if (!cpu_cfg) ++ break; ++ ++nodes; ++ pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off ++ | IBSCTL_LVTOFFSETVAL); ++ pci_read_config_dword(cpu_cfg, IBSCTL, &value); ++ if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) { ++ PFM_DBG("Failed to setup IBS LVT offset, " ++ "IBSCTL = 0x%08x", value); ++ return 1; ++ } ++ } while (1); ++ ++ if (!nodes) { ++ PFM_DBG("No CPU node configured for IBS"); ++ return 1; ++ } ++ ++#ifdef CONFIG_NUMA ++ /* Sanity check */ ++ /* Works only for 64bit with proper numa implementation. */ ++ if (nodes != num_possible_nodes()) { ++ PFM_DBG("Failed to setup CPU node(s) for IBS, " ++ "found: %d, expected %d", ++ nodes, num_possible_nodes()); ++ return 1; ++ } ++#endif ++ return 0; ++} ++ ++/* ++ * There can only be one user per socket for the Northbridge (NB) events, ++ * so we enforce mutual exclusion as follows: ++ * - per-thread : only one context machine-wide can use NB events ++ * - system-wide: only one context per processor socket ++ * ++ * Exclusion is enforced at: ++ * - pfm_load_context() ++ * - pfm_write_pmcs() for attached contexts ++ * ++ * Exclusion is released at: ++ * - pfm_unload_context() or any calls that implicitely uses it ++ * ++ * return: ++ * 0 : successfully acquire NB access ++ * < 0: errno, failed to acquire NB access ++ */ ++static int pfm_amd64_acquire_nb(struct pfm_context *ctx) ++{ ++ struct pfm_context **entry, *old; ++ int proc_id; ++ ++#ifdef CONFIG_SMP ++ proc_id = cpu_data(smp_processor_id()).phys_proc_id; ++#else ++ proc_id = 0; ++#endif ++ ++ if (ctx->flags.system) ++ entry = &pfm_nb_sys_owners[proc_id]; ++ else ++ entry = &pfm_nb_task_owner; ++ ++ old = cmpxchg(entry, NULL, ctx); ++ if (!old) { ++ if (ctx->flags.system) ++ PFM_DBG("acquired Northbridge event access on socket %u", proc_id); ++ else ++ PFM_DBG("acquired Northbridge event access globally"); ++ } else if (old != ctx) { ++ if (ctx->flags.system) ++ PFM_DBG("NorthBridge event conflict on socket %u", proc_id); ++ else ++ PFM_DBG("global NorthBridge event conflict"); ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++/* ++ * invoked from pfm_write_pmcs() when pfm_nb_sys_owners is not NULL,i.e., ++ * when we have detected a multi-core processor. ++ * ++ * context is locked, interrupts are masked ++ */ ++static int pfm_amd64_pmc_write_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++ unsigned int event; ++ ++ /* ++ * delay checking NB event until we load the context ++ */ ++ if (ctx->state == PFM_CTX_UNLOADED) ++ return 0; ++ ++ /* ++ * check event is NB event ++ */ ++ event = (unsigned int)(req->reg_value & 0xff); ++ if (event < 0xee) ++ return 0; ++ ++ return pfm_amd64_acquire_nb(ctx); ++} ++ ++/* ++ * invoked on pfm_load_context(). ++ * context is locked, interrupts are masked ++ */ ++static int pfm_amd64_load_context(struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ unsigned int i, n; ++ ++ /* ++ * scan all sets for NB events ++ */ ++ list_for_each_entry(set, &ctx->set_list, list) { ++ n = set->nused_pmcs; ++ for (i = 0; n; i++) { ++ if (!test_bit(i, cast_ulp(set->used_pmcs))) ++ continue; ++ ++ if (!is_ibs_pmc(i) && (set->pmcs[i] & 0xff) >= 0xee) ++ goto found; ++ n--; ++ } ++ } ++ return 0; ++found: ++ return pfm_amd64_acquire_nb(ctx); ++} ++ ++/* ++ * invoked on pfm_unload_context() ++ */ ++static void pfm_amd64_unload_context(struct pfm_context *ctx) ++{ ++ struct pfm_context **entry, *old; ++ int proc_id; ++ ++#ifdef CONFIG_SMP ++ proc_id = cpu_data(smp_processor_id()).phys_proc_id; ++#else ++ proc_id = 0; ++#endif ++ ++ /* ++ * unload always happens on the monitored CPU in system-wide ++ */ ++ if (ctx->flags.system) ++ entry = &pfm_nb_sys_owners[proc_id]; ++ else ++ entry = &pfm_nb_task_owner; ++ ++ old = cmpxchg(entry, ctx, NULL); ++ if (old == ctx) { ++ if (ctx->flags.system) ++ PFM_DBG("released NorthBridge on socket %u", proc_id); ++ else ++ PFM_DBG("released NorthBridge events globally"); ++ } ++} ++ ++/* ++ * detect if we need to activate NorthBridge event access control ++ */ ++static int pfm_amd64_setup_nb_event_control(void) ++{ ++ unsigned int c, n = 0; ++ unsigned int max_phys = 0; ++ ++#ifdef CONFIG_SMP ++ for_each_possible_cpu(c) { ++ if (cpu_data(c).phys_proc_id > max_phys) ++ max_phys = cpu_data(c).phys_proc_id; ++ } ++#else ++ max_phys = 0; ++#endif ++ if (max_phys > 255) { ++ PFM_INFO("socket id %d is too big to handle", max_phys); ++ return -ENOMEM; ++ } ++ ++ n = max_phys + 1; ++ if (n < 2) ++ return 0; ++ ++ pfm_nb_sys_owners = vmalloc(n * sizeof(*pfm_nb_sys_owners)); ++ if (!pfm_nb_sys_owners) ++ return -ENOMEM; ++ ++ memset(pfm_nb_sys_owners, 0, n * sizeof(*pfm_nb_sys_owners)); ++ pfm_nb_task_owner = NULL; ++ ++ /* ++ * activate write-checker for PMC registers ++ */ ++ for (c = 0; c < PFM_AMD_NUM_PMCS; c++) { ++ if (!is_ibs_pmc(c)) ++ pfm_amd64_pmc_desc[c].type |= PFM_REG_WC; ++ } ++ ++ pfm_amd64_pmu_info.load_context = pfm_amd64_load_context; ++ pfm_amd64_pmu_info.unload_context = pfm_amd64_unload_context; ++ ++ pfm_amd64_pmu_conf.pmc_write_check = pfm_amd64_pmc_write_check; ++ ++ PFM_INFO("NorthBridge event access control enabled"); ++ ++ return 0; ++} ++ ++/* ++ * disable registers which are not available on ++ * the host (applies to IBS registers) ++ */ ++static void pfm_amd64_check_registers(void) ++{ ++ u16 i; ++ ++ PFM_DBG("has_ibs=%d", !!(ibs_status & HAS_IBS)); ++ ++ __set_bit(0, cast_ulp(enable_mask)); ++ __set_bit(1, cast_ulp(enable_mask)); ++ __set_bit(2, cast_ulp(enable_mask)); ++ __set_bit(3, cast_ulp(enable_mask)); ++ max_enable = 3+1; ++ ++ ++ /* ++ * remove IBS registers if feature not present ++ */ ++ if (!(ibs_status & HAS_IBS)) { ++ pfm_amd64_pmc_desc[4].type = PFM_REG_NA; ++ pfm_amd64_pmc_desc[5].type = PFM_REG_NA; ++ for (i = 4; i < 14; i++) ++ pfm_amd64_pmd_desc[i].type = PFM_REG_NA; ++ } else { ++ __set_bit(16, cast_ulp(enable_mask)); ++ __set_bit(17, cast_ulp(enable_mask)); ++ max_enable = 17 + 1; ++ } ++ ++ /* ++ * adjust reserved bit fields for family 16 ++ */ ++ if (current_cpu_data.x86 == 16) { ++ for (i = 0; i < PFM_AMD_NUM_PMCS; i++) ++ if (pfm_amd64_pmc_desc[i].rsvd_msk == PFM_K8_RSVD) ++ pfm_amd64_pmc_desc[i].rsvd_msk = PFM_16_RSVD; ++ } ++} ++ ++static int pfm_amd64_probe_pmu(void) ++{ ++ u64 val = 0; ++ if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) { ++ PFM_INFO("not an AMD processor"); ++ return -1; ++ } ++ ++ switch (current_cpu_data.x86) { ++ case 16: ++ case 15: ++ case 6: ++ break; ++ default: ++ PFM_INFO("unsupported family=%d", current_cpu_data.x86); ++ return -1; ++ } ++ ++ /* check for IBS */ ++ if (cpu_has(¤t_cpu_data, X86_FEATURE_IBS)) { ++ ibs_status |= HAS_IBS; ++ rdmsrl(MSR_AMD64_IBSCTL, val); ++ } ++ ++ PFM_INFO("found family=%d IBSCTL=0x%llx", current_cpu_data.x86, (unsigned long long)val); ++ ++ /* ++ * check for local APIC (required) ++ */ ++ if (!cpu_has_apic) { ++ PFM_INFO("no local APIC, unsupported"); ++ return -1; ++ } ++ ++ if (current_cpu_data.x86_max_cores > 1 ++ && pfm_amd64_setup_nb_event_control()) ++ return -1; ++ ++ if (force_nmi) ++ pfm_amd64_pmu_info.flags |= PFM_X86_FL_USE_NMI; ++ ++ if (ibs_status & HAS_IBS) { ++ /* Setup extended interrupt */ ++ if (pfm_amd64_setup_eilvt()) { ++ PFM_INFO("Failed to initialize extended interrupts " ++ "for IBS"); ++ ibs_status &= ~HAS_IBS; ++ PFM_INFO("Unable to use IBS"); ++ } else { ++ PFM_INFO("IBS supported"); ++ } ++ } ++ ++ pfm_amd64_check_registers(); ++ ++ return 0; ++} ++ ++/* ++ * detect is counters have overflowed. ++ * return: ++ * 0 : no overflow ++ * 1 : at least one overflow ++ */ ++static int __kprobes pfm_amd64_has_ovfls(struct pfm_context *ctx) ++{ ++ struct pfm_regmap_desc *xrd; ++ u64 *cnt_mask; ++ u64 wmask, val; ++ u16 i, num; ++ ++ /* ++ * Check for IBS events ++ */ ++ if (ibs_status & HAS_IBS) { ++ rdmsrl(MSR_AMD64_IBSFETCHCTL, val); ++ if (val & PFM_AMD64_IBSFETCHVAL) ++ return 1; ++ rdmsrl(MSR_AMD64_IBSOPCTL, val); ++ if (val & PFM_AMD64_IBSOPVAL) ++ return 1; ++ } ++ /* ++ * Check regular counters ++ */ ++ cnt_mask = ctx->regs.cnt_pmds; ++ num = ctx->regs.num_counters; ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ xrd = pfm_amd64_pmd_desc; ++ ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(cnt_mask))) { ++ rdmsrl(xrd[i].hw_addr, val); ++ if (!(val & wmask)) ++ return 1; ++ num--; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Must check for IBS event BEFORE stop_save_p6 because ++ * stopping monitoring does destroy IBS state information ++ * in IBSFETCHCTL/IBSOPCTL because they are tagged as enable ++ * registers. ++ */ ++static int pfm_amd64_stop_save(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u64 used_mask[PFM_PMC_BV]; ++ u64 *cnt_pmds; ++ u64 val, wmask, ovfl_mask; ++ u32 i, count, use_ibs; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * IBS used if: ++ * - on family 10h processor with IBS ++ * - at least one of the IBS PMD registers is used ++ */ ++ use_ibs = (ibs_status & HAS_IBS) ++ && (test_bit(IBSFETCHCTL_PMD, cast_ulp(set->used_pmds)) ++ || test_bit(IBSOPSCTL_PMD, cast_ulp(set->used_pmds))); ++ ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ bitmap_and(cast_ulp(used_mask), ++ cast_ulp(set->used_pmcs), ++ cast_ulp(enable_mask), ++ max_enable); ++ ++ count = bitmap_weight(cast_ulp(used_mask), max_enable); ++ ++ /* ++ * stop monitoring ++ * Unfortunately, this is very expensive! ++ * wrmsrl() is serializing. ++ * ++ * With IBS, we need to do read-modify-write to preserve the content ++ * for OpsCTL and FetchCTL because they are also used as PMDs and saved ++ * below ++ */ ++ if (use_ibs) { ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(used_mask))) { ++ if (i == IBSFETCHCTL_PMC) { ++ rdmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, val); ++ val &= ~PFM_AMD64_IBSFETCHEN; ++ } else if (i == IBSOPSCTL_PMC) { ++ rdmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, val); ++ val &= ~PFM_AMD64_IBSOPEN; ++ } else ++ val = 0; ++ wrmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, val); ++ count--; ++ } ++ } ++ } else { ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(used_mask))) { ++ wrmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, 0); ++ count--; ++ } ++ } ++ } ++ ++ /* ++ * if we already having a pending overflow condition, we simply ++ * return to take care of this first. ++ */ ++ if (set->npend_ovfls) ++ return 1; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ cnt_pmds = ctx->regs.cnt_pmds; ++ ++ /* ++ * check for pending overflows and save PMDs (combo) ++ * we employ used_pmds because we also need to save ++ * and not just check for pending interrupts. ++ * ++ * Must check for counting PMDs because of virtual PMDs and IBS ++ */ ++ count = set->nused_pmds; ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(set->used_pmds))) { ++ val = pfm_arch_read_pmd(ctx, i); ++ if (likely(test_bit(i, cast_ulp(cnt_pmds)))) { ++ if (!(val & wmask)) { ++ __set_bit(i, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ val = (set->pmds[i].value & ~ovfl_mask) | (val & ovfl_mask); ++ } ++ set->pmds[i].value = val; ++ count--; ++ } ++ } ++ ++ /* ++ * check if IBS contains valid data, and mark the corresponding ++ * PMD has overflowed ++ */ ++ if (use_ibs) { ++ if (set->pmds[IBSFETCHCTL_PMD].value & PFM_AMD64_IBSFETCHVAL) { ++ __set_bit(IBSFETCHCTL_PMD, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ if (set->pmds[IBSOPSCTL_PMD].value & PFM_AMD64_IBSOPVAL) { ++ __set_bit(IBSOPSCTL_PMD, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ } ++ /* 0 means: no need to save PMDs at upper level */ ++ return 0; ++} ++ ++/** ++ * pfm_amd64_quiesce_pmu -- stop monitoring without grabbing any lock ++ * ++ * called from NMI interrupt handler to immediately stop monitoring ++ * cannot grab any lock, including perfmon related locks ++ */ ++static void __kprobes pfm_amd64_quiesce(void) ++{ ++ /* ++ * quiesce PMU by clearing available registers that have ++ * the start/stop capability ++ */ ++ if (test_bit(0, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_K7_EVNTSEL0, 0); ++ if (test_bit(1, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_K7_EVNTSEL0+1, 0); ++ if (test_bit(2, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_K7_EVNTSEL0+2, 0); ++ if (test_bit(3, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_K7_EVNTSEL0+3, 0); ++ ++ if (test_bit(4, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_AMD64_IBSFETCHCTL, 0); ++ if (test_bit(5, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_AMD64_IBSOPCTL, 0); ++} ++ ++/** ++ * pfm_amd64_restore_pmcs - reload PMC registers ++ * @ctx: context to restore from ++ * @set: current event set ++ * ++ * optimized version of pfm_arch_restore_pmcs(). On AMD64, we can ++ * afford to only restore the pmcs registers we use, because they are ++ * all independent from each other. ++ */ ++static void pfm_amd64_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ u64 *mask; ++ u16 i, num; ++ ++ mask = set->used_pmcs; ++ num = set->nused_pmcs; ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(mask))) { ++ wrmsrl(pfm_amd64_pmc_desc[i].hw_addr, set->pmcs[i]); ++ num--; ++ } ++ } ++} ++ ++static struct pfm_pmu_config pfm_amd64_pmu_conf = { ++ .pmu_name = "AMD64", ++ .counter_width = 47, ++ .pmd_desc = pfm_amd64_pmd_desc, ++ .pmc_desc = pfm_amd64_pmc_desc, ++ .num_pmc_entries = PFM_AMD_NUM_PMCS, ++ .num_pmd_entries = PFM_AMD_NUM_PMDS, ++ .probe_pmu = pfm_amd64_probe_pmu, ++ .version = "1.2", ++ .pmu_info = &pfm_amd64_pmu_info, ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init pfm_amd64_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_amd64_pmu_conf); ++} ++ ++static void __exit pfm_amd64_pmu_cleanup_module(void) ++{ ++ if (pfm_nb_sys_owners) ++ vfree(pfm_nb_sys_owners); ++ ++ pfm_pmu_unregister(&pfm_amd64_pmu_conf); ++} ++ ++module_init(pfm_amd64_pmu_init_module); ++module_exit(pfm_amd64_pmu_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_intel_arch.c +@@ -0,0 +1,610 @@ ++/* ++ * This file contains the Intel architectural perfmon v1, v2, v3 ++ * description tables. ++ * ++ * Architectural perfmon was introduced with Intel Core Solo/Duo ++ * processors. ++ * ++ * Copyright (c) 2006-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Intel architectural perfmon v1"); ++MODULE_LICENSE("GPL"); ++ ++static int force, force_nmi; ++MODULE_PARM_DESC(force, "bool: force module to load succesfully"); ++MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt"); ++module_param(force, bool, 0600); ++module_param(force_nmi, bool, 0600); ++ ++static u64 enable_mask[PFM_MAX_PMCS]; ++static u16 max_enable; ++ ++/* ++ * - upper 32 bits are reserved ++ * - INT: APIC enable bit is reserved (forced to 1) ++ * - bit 21 is reserved ++ * ++ * RSVD: reserved bits are 1 ++ */ ++#define PFM_IA_PMC_RSVD ((~((1ULL<<32)-1)) \ ++ | (1ULL<<20) \ ++ | (1ULL<<21)) ++ ++/* ++ * force Local APIC interrupt on overflow ++ * disable with NO_EMUL64 ++ */ ++#define PFM_IA_PMC_VAL (1ULL<<20) ++#define PFM_IA_NO64 (1ULL<<20) ++ ++/* ++ * architectuture specifies that: ++ * IA32_PMCx MSR : starts at 0x0c1 & occupy a contiguous block of MSR ++ * IA32_PERFEVTSELx MSR : starts at 0x186 & occupy a contiguous block of MSR ++ * MSR_GEN_FIXED_CTR0 : starts at 0x309 & occupy a contiguous block of MSR ++ */ ++#define MSR_GEN_SEL_BASE MSR_P6_EVNTSEL0 ++#define MSR_GEN_PMC_BASE MSR_P6_PERFCTR0 ++#define MSR_GEN_FIXED_PMC_BASE MSR_CORE_PERF_FIXED_CTR0 ++ ++/* ++ * layout of EAX for CPUID.0xa leaf function ++ */ ++struct pmu_eax { ++ unsigned int version:8; /* architectural perfmon version */ ++ unsigned int num_cnt:8; /* number of generic counters */ ++ unsigned int cnt_width:8; /* width of generic counters */ ++ unsigned int ebx_length:8; /* number of architected events */ ++}; ++ ++/* ++ * layout of EDX for CPUID.0xa leaf function when perfmon v2 is detected ++ */ ++struct pmu_edx { ++ unsigned int num_cnt:5; /* number of fixed counters */ ++ unsigned int cnt_width:8; /* width of fixed counters */ ++ unsigned int reserved:19; ++}; ++ ++static void pfm_intel_arch_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static int pfm_intel_arch_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static int pfm_intel_arch_has_ovfls(struct pfm_context *ctx); ++static void __kprobes pfm_intel_arch_quiesce(void); ++ ++/* ++ * physical addresses of MSR controlling the perfevtsel and counter registers ++ */ ++struct pfm_arch_pmu_info pfm_intel_arch_pmu_info = { ++ .stop_save = pfm_intel_arch_stop_save, ++ .has_ovfls = pfm_intel_arch_has_ovfls, ++ .quiesce = pfm_intel_arch_quiesce, ++ .restore_pmcs = pfm_intel_arch_restore_pmcs ++}; ++ ++#define PFM_IA_C(n) { \ ++ .type = PFM_REG_I64, \ ++ .desc = "PERFEVTSEL"#n, \ ++ .dfl_val = PFM_IA_PMC_VAL, \ ++ .rsvd_msk = PFM_IA_PMC_RSVD, \ ++ .no_emul64_msk = PFM_IA_NO64, \ ++ .hw_addr = MSR_GEN_SEL_BASE+(n) \ ++ } ++ ++#define PFM_IA_D(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "PMC"#n, \ ++ .hw_addr = MSR_P6_PERFCTR0+n, \ ++ .dep_pmcs[0] = 1ULL << n \ ++ } ++ ++#define PFM_IA_FD(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "FIXED_CTR"#n, \ ++ .hw_addr = MSR_CORE_PERF_FIXED_CTR0+n,\ ++ .dep_pmcs[0] = 1ULL << 16 \ ++ } ++ ++static struct pfm_regmap_desc pfm_intel_arch_pmc_desc[] = { ++/* pmc0 */ PFM_IA_C(0), PFM_IA_C(1), PFM_IA_C(2), PFM_IA_C(3), ++/* pmc4 */ PFM_IA_C(4), PFM_IA_C(5), PFM_IA_C(6), PFM_IA_C(7), ++/* pmc8 */ PFM_IA_C(8), PFM_IA_C(9), PFM_IA_C(10), PFM_IA_C(11), ++/* pmc12 */ PFM_IA_C(12), PFM_IA_C(13), PFM_IA_C(14), PFM_IA_C(15), ++ ++/* pmc16 */ { .type = PFM_REG_I, ++ .desc = "FIXED_CTRL", ++ .dfl_val = 0x8888888888888888ULL, /* force PMI */ ++ .rsvd_msk = 0, /* set dynamically */ ++ .no_emul64_msk = 0, ++ .hw_addr = MSR_CORE_PERF_FIXED_CTR_CTRL ++ }, ++}; ++#define PFM_IA_MAX_PMCS ARRAY_SIZE(pfm_intel_arch_pmc_desc) ++ ++static struct pfm_regmap_desc pfm_intel_arch_pmd_desc[] = { ++/* pmd0 */ PFM_IA_D(0), PFM_IA_D(1), PFM_IA_D(2), PFM_IA_D(3), ++/* pmd4 */ PFM_IA_D(4), PFM_IA_D(5), PFM_IA_D(6), PFM_IA_D(7), ++/* pmd8 */ PFM_IA_D(8), PFM_IA_D(9), PFM_IA_D(10), PFM_IA_D(11), ++/* pmd12 */ PFM_IA_D(12), PFM_IA_D(13), PFM_IA_D(14), PFM_IA_D(15), ++ ++/* pmd16 */ PFM_IA_FD(0), PFM_IA_FD(1), PFM_IA_FD(2), PFM_IA_FD(3), ++/* pmd20 */ PFM_IA_FD(4), PFM_IA_FD(5), PFM_IA_FD(6), PFM_IA_FD(7), ++/* pmd24 */ PFM_IA_FD(8), PFM_IA_FD(9), PFM_IA_FD(10), PFM_IA_FD(11), ++/* pmd28 */ PFM_IA_FD(16), PFM_IA_FD(17), PFM_IA_FD(18), PFM_IA_FD(19) ++}; ++#define PFM_IA_MAX_PMDS ARRAY_SIZE(pfm_intel_arch_pmd_desc) ++ ++#define PFM_IA_MAX_CNT 16 /* # generic counters in mapping table */ ++#define PFM_IA_MAX_FCNT 16 /* # of fixed counters in mapping table */ ++#define PFM_IA_FCNT_BASE 16 /* base index of fixed counters PMD */ ++ ++static struct pfm_pmu_config pfm_intel_arch_pmu_conf; ++ ++static void pfm_intel_arch_check_errata(void) ++{ ++ /* ++ * Core Duo errata AE49 (no fix). Both counters share a single ++ * enable bit in PERFEVTSEL0 ++ */ ++ if (current_cpu_data.x86 == 6 && current_cpu_data.x86_model == 14) ++ pfm_intel_arch_pmu_info.flags |= PFM_X86_FL_NO_SHARING; ++} ++ ++static inline void set_enable_mask(unsigned int i) ++{ ++ __set_bit(i, cast_ulp(enable_mask)); ++ ++ /* max_enable = highest + 1 */ ++ if ((i+1) > max_enable) ++ max_enable = i+ 1; ++} ++ ++static void pfm_intel_arch_setup_generic(unsigned int version, ++ unsigned int width, ++ unsigned int count) ++{ ++ u64 rsvd; ++ unsigned int i; ++ ++ /* ++ * first we handle the generic counters: ++ * ++ * - ensure HW does not have more registers than hardcoded in the tables ++ * - adjust rsvd_msk to actual counter width ++ * - initialize enable_mask (list of PMC with start/stop capability) ++ * - mark unused hardcoded generic counters as unimplemented ++ */ ++ ++ /* ++ * min of number of Hw counters and hardcoded in the tables ++ */ ++ if (count >= PFM_IA_MAX_CNT) { ++ printk(KERN_INFO "perfmon: Limiting number of generic counters" ++ " to %u, HW supports %u", ++ PFM_IA_MAX_CNT, count); ++ count = PFM_IA_MAX_CNT; ++ } ++ ++ /* ++ * adjust rsvd_msk for generic counters based on actual width ++ * initialize enable_mask (1 per pmd) ++ */ ++ rsvd = ~((1ULL << width)-1); ++ for (i = 0; i < count; i++) { ++ pfm_intel_arch_pmd_desc[i].rsvd_msk = rsvd; ++ set_enable_mask(i); ++ } ++ ++ /* ++ * handle version 3 new anythread bit (21) ++ */ ++ if (version == 3) { ++ for (i = 0; i < count; i++) ++ pfm_intel_arch_pmc_desc[i].rsvd_msk &= ~(1ULL << 21); ++ } ++ ++ ++ /* ++ * mark unused generic counters as not available ++ */ ++ for (i = count ; i < PFM_IA_MAX_CNT; i++) { ++ pfm_intel_arch_pmd_desc[i].type = PFM_REG_NA; ++ pfm_intel_arch_pmc_desc[i].type = PFM_REG_NA; ++ } ++} ++ ++static void pfm_intel_arch_setup_fixed(unsigned int version, ++ unsigned int width, ++ unsigned int count) ++{ ++ u64 rsvd, dfl; ++ unsigned int i; ++ ++ /* ++ * handle the fixed counters (if any): ++ * ++ * - ensure HW does not have more registers than hardcoded in the tables ++ * - adjust rsvd_msk to actual counter width ++ * - initialize enable_mask (list of PMC with start/stop capability) ++ * - mark unused hardcoded generic counters as unimplemented ++ */ ++ if (count >= PFM_IA_MAX_FCNT) { ++ printk(KERN_INFO "perfmon: Limiting number of fixed counters" ++ " to %u, HW supports %u", ++ PFM_IA_MAX_FCNT, count); ++ count = PFM_IA_MAX_FCNT; ++ } ++ /* ++ * adjust rsvd_msk for fixed counters based on actual width ++ */ ++ rsvd = ~((1ULL << width)-1); ++ for (i = 0; i < count; i++) ++ pfm_intel_arch_pmd_desc[PFM_IA_FCNT_BASE+i].rsvd_msk = rsvd; ++ ++ /* ++ * handle version new anythread bit (bit 2) ++ */ ++ if (version == 3) ++ rsvd = 1ULL << 3; ++ else ++ rsvd = 3ULL << 2; ++ ++ pfm_intel_arch_pmc_desc[16].rsvd_msk = 0; ++ for (i = 0; i < count; i++) ++ pfm_intel_arch_pmc_desc[16].rsvd_msk |= rsvd << (i<<2); ++ ++ /* ++ * mark unused fixed counters as unimplemented ++ * ++ * update the rsvd_msk, dfl_val in FIXED_CTRL: ++ * - rsvd_msk: set all 4 bits ++ * - dfl_val : clear all 4 bits ++ */ ++ dfl = pfm_intel_arch_pmc_desc[16].dfl_val; ++ rsvd = pfm_intel_arch_pmc_desc[16].rsvd_msk; ++ ++ for (i = count ; i < PFM_IA_MAX_FCNT; i++) { ++ pfm_intel_arch_pmd_desc[PFM_IA_FCNT_BASE+i].type = PFM_REG_NA; ++ rsvd |= 0xfULL << (i<<2); ++ dfl &= ~(0xfULL << (i<<2)); ++ } ++ ++ /* ++ * FIXED_CTR_CTRL unavailable when no fixed counters are defined ++ */ ++ if (!count) { ++ pfm_intel_arch_pmc_desc[16].type = PFM_REG_NA; ++ } else { ++ /* update rsvd_mask and dfl_val */ ++ pfm_intel_arch_pmc_desc[16].rsvd_msk = rsvd; ++ pfm_intel_arch_pmc_desc[16].dfl_val = dfl; ++ set_enable_mask(16); ++ } ++} ++ ++static int pfm_intel_arch_probe_pmu(void) ++{ ++ union { ++ unsigned int val; ++ struct pmu_eax eax; ++ struct pmu_edx edx; ++ } eax, edx; ++ unsigned int ebx, ecx; ++ unsigned int width = 0; ++ ++ edx.val = 0; ++ ++ if (!(cpu_has_arch_perfmon || force)) { ++ PFM_INFO("no support for Intel architectural PMU"); ++ return -1; ++ } ++ ++ if (!cpu_has_apic) { ++ PFM_INFO("no Local APIC, try rebooting with lapic option"); ++ return -1; ++ } ++ ++ /* cpuid() call protected by cpu_has_arch_perfmon */ ++ cpuid(0xa, &eax.val, &ebx, &ecx, &edx.val); ++ ++ /* ++ * reject processors supported by perfmon_intel_core ++ * ++ * We need to do this explicitely to avoid depending ++ * on the link order in case, the modules are compiled as ++ * builtin. ++ * ++ * non Intel processors are rejected by cpu_has_arch_perfmon ++ */ ++ if (current_cpu_data.x86 == 6 && !force) { ++ switch (current_cpu_data.x86_model) { ++ case 15: /* Merom: use perfmon_intel_core */ ++ case 23: /* Penryn: use perfmon_intel_core */ ++ return -1; ++ default: ++ break; ++ } ++ } ++ ++ /* ++ * some 6/15 models have buggy BIOS ++ */ ++ if (eax.eax.version == 0 ++ && current_cpu_data.x86 == 6 && current_cpu_data.x86_model == 15) { ++ PFM_INFO("buggy v2 BIOS, adjusting for 2 generic counters"); ++ eax.eax.version = 2; ++ eax.eax.num_cnt = 2; ++ eax.eax.cnt_width = 40; ++ } ++ ++ /* ++ * Intel Atom processors have a buggy firmware which does not report ++ * the correct number of fixed counters ++ */ ++ if (eax.eax.version == 3 && edx.edx.num_cnt < 3 ++ && current_cpu_data.x86 == 6 && current_cpu_data.x86_model == 28) { ++ PFM_INFO("buggy v3 BIOS, adjusting for 3 fixed counters"); ++ edx.edx.num_cnt = 3; ++ } ++ ++ /* ++ * some v2 BIOSes are incomplete ++ */ ++ if (eax.eax.version == 2 && !edx.edx.num_cnt) { ++ PFM_INFO("buggy v2 BIOS, adjusting for 3 fixed counters"); ++ edx.edx.num_cnt = 3; ++ edx.edx.cnt_width = 40; ++ } ++ ++ /* ++ * no fixed counters on earlier versions ++ */ ++ if (eax.eax.version < 2) { ++ edx.val = 0; ++ } else { ++ /* ++ * use the min value of both widths until we support ++ * variable width counters ++ */ ++ width = eax.eax.cnt_width < edx.edx.cnt_width ? ++ eax.eax.cnt_width : edx.edx.cnt_width; ++ } ++ ++ PFM_INFO("detected architecural perfmon v%d", eax.eax.version); ++ PFM_INFO("num_gen=%d width=%d num_fixed=%d width=%d", ++ eax.eax.num_cnt, ++ eax.eax.cnt_width, ++ edx.edx.num_cnt, ++ edx.edx.cnt_width); ++ ++ ++ pfm_intel_arch_setup_generic(eax.eax.version, ++ width, ++ eax.eax.num_cnt); ++ ++ pfm_intel_arch_setup_fixed(eax.eax.version, ++ width, ++ edx.edx.num_cnt); ++ ++ if (force_nmi) ++ pfm_intel_arch_pmu_info.flags |= PFM_X86_FL_USE_NMI; ++ ++ pfm_intel_arch_check_errata(); ++ ++ return 0; ++} ++ ++/** ++ * pfm_intel_arch_has_ovfls - check for pending overflow condition ++ * @ctx: context to work on ++ * ++ * detect if counters have overflowed. ++ * return: ++ * 0 : no overflow ++ * 1 : at least one overflow ++ */ ++static int __kprobes pfm_intel_arch_has_ovfls(struct pfm_context *ctx) ++{ ++ u64 *cnt_mask; ++ u64 wmask, val; ++ u16 i, num; ++ ++ cnt_mask = ctx->regs.cnt_pmds; ++ num = ctx->regs.num_counters; ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ /* ++ * we can leverage the fact that we know the mapping ++ * to hardcode the MSR address and avoid accessing ++ * more cachelines ++ * ++ * We need to check cnt_mask because not all registers ++ * may be available. ++ */ ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(cnt_mask))) { ++ rdmsrl(pfm_intel_arch_pmd_desc[i].hw_addr, val); ++ if (!(val & wmask)) ++ return 1; ++ num--; ++ } ++ } ++ return 0; ++} ++ ++static int pfm_intel_arch_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ u64 used_mask[PFM_PMC_BV]; ++ u64 *cnt_pmds; ++ u64 val, wmask, ovfl_mask; ++ u32 i, count; ++ ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ bitmap_and(cast_ulp(used_mask), ++ cast_ulp(set->used_pmcs), ++ cast_ulp(enable_mask), ++ max_enable); ++ ++ count = bitmap_weight(cast_ulp(used_mask), max_enable); ++ ++ /* ++ * stop monitoring ++ * Unfortunately, this is very expensive! ++ * wrmsrl() is serializing. ++ */ ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(used_mask))) { ++ wrmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, 0); ++ count--; ++ } ++ } ++ ++ /* ++ * if we already having a pending overflow condition, we simply ++ * return to take care of this first. ++ */ ++ if (set->npend_ovfls) ++ return 1; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ cnt_pmds = ctx->regs.cnt_pmds; ++ ++ /* ++ * check for pending overflows and save PMDs (combo) ++ * we employ used_pmds because we also need to save ++ * and not just check for pending interrupts. ++ * ++ * Must check for counting PMDs because of virtual PMDs ++ */ ++ count = set->nused_pmds; ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(set->used_pmds))) { ++ val = pfm_arch_read_pmd(ctx, i); ++ if (likely(test_bit(i, cast_ulp(cnt_pmds)))) { ++ if (!(val & wmask)) { ++ __set_bit(i, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ val = (set->pmds[i].value & ~ovfl_mask) ++ | (val & ovfl_mask); ++ } ++ set->pmds[i].value = val; ++ count--; ++ } ++ } ++ /* 0 means: no need to save PMDs at upper level */ ++ return 0; ++} ++ ++/** ++ * pfm_intel_arch_quiesce - stop monitoring without grabbing any lock ++ * ++ * called from NMI interrupt handler to immediately stop monitoring ++ * cannot grab any lock, including perfmon related locks ++ */ ++static void __kprobes pfm_intel_arch_quiesce(void) ++{ ++ u16 i; ++ ++ /* ++ * PMC16 is the fixed control control register so it has a ++ * distinct MSR address ++ * ++ * We do not use the hw_addr field in the table to avoid touching ++ * too many cachelines ++ */ ++ for (i = 0; i < pfm_pmu_conf->regs_all.max_pmc; i++) { ++ if (test_bit(i, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) { ++ if (i == 16) ++ wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, 0); ++ else ++ wrmsrl(MSR_P6_EVNTSEL0+i, 0); ++ } ++ } ++} ++ ++/** ++ * pfm_intel_arch_restore_pmcs - reload PMC registers ++ * @ctx: context to restore from ++ * @set: current event set ++ * ++ * optimized version of pfm_arch_restore_pmcs(). On architectural perfmon, ++ * we can afford to only restore the pmcs registers we use, because they ++ * are all independent from each other. ++ */ ++static void pfm_intel_arch_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ u64 *mask; ++ u16 i, num; ++ ++ mask = set->used_pmcs; ++ num = set->nused_pmcs; ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(mask))) { ++ wrmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, set->pmcs[i]); ++ num--; ++ } ++ } ++} ++/* ++ * Counters may have model-specific width. Yet the documentation says ++ * that only the lower 32 bits can be written to due to the specification ++ * of wrmsr. bits [32-(w-1)] are sign extensions of bit 31. Bits [w-63] must ++ * not be set (see rsvd_msk for PMDs). As such the effective width of a ++ * counter is 31 bits only regardless of what CPUID.0xa returns. ++ * ++ * See IA-32 Intel Architecture Software developer manual Vol 3B chapter 18 ++ */ ++static struct pfm_pmu_config pfm_intel_arch_pmu_conf = { ++ .pmu_name = "Intel architectural", ++ .pmd_desc = pfm_intel_arch_pmd_desc, ++ .counter_width = 31, ++ .num_pmc_entries = PFM_IA_MAX_PMCS, ++ .num_pmd_entries = PFM_IA_MAX_PMDS, ++ .pmc_desc = pfm_intel_arch_pmc_desc, ++ .probe_pmu = pfm_intel_arch_probe_pmu, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_intel_arch_pmu_info ++}; ++ ++static int __init pfm_intel_arch_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_intel_arch_pmu_conf); ++} ++ ++static void __exit pfm_intel_arch_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_intel_arch_pmu_conf); ++} ++ ++module_init(pfm_intel_arch_pmu_init_module); ++module_exit(pfm_intel_arch_pmu_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_intel_atom.c +@@ -0,0 +1,541 @@ ++/* ++ * perfmon support for Intel Atom (architectural perfmon v3 + PEBS) ++ * ++ * Copyright (c) 2008 Google,Inc ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Intel Atom"); ++MODULE_LICENSE("GPL"); ++ ++static int force, force_nmi; ++MODULE_PARM_DESC(force, "bool: force module to load succesfully"); ++MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt"); ++module_param(force, bool, 0600); ++module_param(force_nmi, bool, 0600); ++ ++/* ++ * - upper 32 bits are reserved ++ * - INT: APIC enable bit is reserved (forced to 1) ++ * ++ * RSVD: reserved bits are 1 ++ */ ++#define PFM_ATOM_PMC_RSVD ((~((1ULL<<32)-1)) | (1ULL<<20)) ++ ++/* ++ * force Local APIC interrupt on overflow ++ * disable with NO_EMUL64 ++ */ ++#define PFM_ATOM_PMC_VAL (1ULL<<20) ++#define PFM_ATOM_NO64 (1ULL<<20) ++ ++/* ++ * Atom counters are 40-bits. 40-bits can be read but ony 31 can be written ++ * to due to a limitation of wrmsr. Bits [[63-32] are sign extensions of bit 31. ++ * Bits [63-40] must not be set ++ * ++ * See IA-32 Intel Architecture Software developer manual Vol 3B chapter 18 ++ */ ++#define PFM_ATOM_PMD_WIDTH 31 ++#define PFM_ATOM_PMD_RSVD ~((1ULL << 40)-1) ++ ++static void pfm_intel_atom_acquire_pmu_percpu(void); ++static void pfm_intel_atom_release_pmu_percpu(void); ++static void pfm_intel_atom_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static int pfm_intel_atom_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static int pfm_intel_atom_has_ovfls(struct pfm_context *ctx); ++static void __kprobes pfm_intel_atom_quiesce(void); ++ ++struct pfm_arch_pmu_info pfm_intel_atom_pmu_info = { ++ .stop_save = pfm_intel_atom_stop_save, ++ .has_ovfls = pfm_intel_atom_has_ovfls, ++ .quiesce = pfm_intel_atom_quiesce, ++ .restore_pmcs = pfm_intel_atom_restore_pmcs, ++ .acquire_pmu_percpu = pfm_intel_atom_acquire_pmu_percpu, ++ .release_pmu_percpu = pfm_intel_atom_release_pmu_percpu ++ ++}; ++ ++#define PFM_ATOM_C(n) { \ ++ .type = PFM_REG_I64, \ ++ .desc = "PERFEVTSEL"#n, \ ++ .dfl_val = PFM_ATOM_PMC_VAL, \ ++ .rsvd_msk = PFM_ATOM_PMC_RSVD, \ ++ .no_emul64_msk = PFM_ATOM_NO64, \ ++ .hw_addr = MSR_P6_EVNTSEL0 + (n) \ ++ } ++ ++ ++static struct pfm_regmap_desc pfm_intel_atom_pmc_desc[] = { ++/* pmc0 */ PFM_ATOM_C(0), ++/* pmc1 */ PFM_ATOM_C(1), ++/* pmc2 */ PMX_NA, PMX_NA, ++/* pmc4 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc8 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc12 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc16 */ { .type = PFM_REG_I, ++ .desc = "FIXED_CTRL", ++ .dfl_val = 0x0000000000000888ULL, /* force PMI */ ++ .rsvd_msk = 0xfffffffffffffcccULL, /* 3 fixed counters defined */ ++ .no_emul64_msk = 0, ++ .hw_addr = MSR_CORE_PERF_FIXED_CTR_CTRL ++ }, ++/* pmc17 */{ .type = PFM_REG_W, ++ .desc = "PEBS_ENABLE", ++ .dfl_val = 0, ++ .rsvd_msk = 0xfffffffffffffffeULL, ++ .no_emul64_msk = 0, ++ .hw_addr = MSR_IA32_PEBS_ENABLE ++ } ++}; ++#define PFM_ATOM_MAX_PMCS ARRAY_SIZE(pfm_intel_atom_pmc_desc) ++ ++#define PFM_ATOM_D(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "PMC"#n, \ ++ .rsvd_msk = PFM_ATOM_PMD_RSVD, \ ++ .hw_addr = MSR_P6_PERFCTR0+n, \ ++ .dep_pmcs[0] = 1ULL << n \ ++ } ++ ++#define PFM_ATOM_FD(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "FIXED_CTR"#n, \ ++ .rsvd_msk = PFM_ATOM_PMD_RSVD, \ ++ .hw_addr = MSR_CORE_PERF_FIXED_CTR0+n,\ ++ .dep_pmcs[0] = 1ULL << 16 \ ++ } ++ ++static struct pfm_regmap_desc pfm_intel_atom_pmd_desc[] = { ++/* pmd0 */ PFM_ATOM_D(0), ++/* pmd1 */ PFM_ATOM_D(1), ++/* pmd2 */ PMX_NA, ++/* pmd3 */ PMX_NA, ++/* pmd4 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmd8 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmd12 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmd16 */ PFM_ATOM_FD(0), ++/* pmd17 */ PFM_ATOM_FD(1), ++/* pmd18 */ PFM_ATOM_FD(2) ++}; ++#define PFM_ATOM_MAX_PMDS ARRAY_SIZE(pfm_intel_atom_pmd_desc) ++ ++static struct pfm_pmu_config pfm_intel_atom_pmu_conf; ++ ++static int pfm_intel_atom_probe_pmu(void) ++{ ++ if (force) ++ goto doit; ++ ++ if (current_cpu_data.x86_vendor != X86_VENDOR_INTEL) ++ return -1; ++ ++ if (current_cpu_data.x86 != 6) ++ return -1; ++ ++ if (current_cpu_data.x86_model != 28) ++ return -1; ++doit: ++ /* ++ * having APIC is mandatory, so disregard force option ++ */ ++ if (!cpu_has_apic) { ++ PFM_INFO("no Local APIC, try rebooting with lapic option"); ++ return -1; ++ } ++ ++ PFM_INFO("detected Intel Atom PMU"); ++ ++ if (force_nmi) ++ pfm_intel_atom_pmu_info.flags |= PFM_X86_FL_USE_NMI; ++ ++ return 0; ++} ++ ++/** ++ * pfm_intel_atom_has_ovfls - check for pending overflow condition ++ * @ctx: context to work on ++ * ++ * detect if counters have overflowed. ++ * return: ++ * 0 : no overflow ++ * 1 : at least one overflow ++ */ ++static int __kprobes pfm_intel_atom_has_ovfls(struct pfm_context *ctx) ++{ ++ struct pfm_regmap_desc *d; ++ u64 ovf; ++ ++ d = pfm_pmu_conf->pmd_desc; ++ /* ++ * read global overflow status register ++ * if sharing PMU, then not all bit are ours so must ++ * check only the ones we actually use ++ */ ++ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, ovf); ++ ++ /* ++ * for pmd0, we also check PEBS overflow on bit 62 ++ */ ++ if ((d[0].type & PFM_REG_I) && (ovf & ((1ull << 62) | 1ull))) ++ return 1; ++ ++ if ((d[1].type & PFM_REG_I) && (ovf & 2ull)) ++ return 1; ++ ++ if ((d[16].type & PFM_REG_I) && (ovf & (1ull << 32))) ++ return 1; ++ ++ if ((d[17].type & PFM_REG_I) && (ovf & (2ull << 32))) ++ return 1; ++ ++ if ((d[18].type & PFM_REG_I) && (ovf & (4ull << 32))) ++ return 1; ++ ++ return 0; ++} ++ ++/** ++ * pfm_intel_atom_stop_save - stop monitoring, collect pending overflow, save pmds ++ * @ctx: context to work on ++ * @set: active set ++ * ++ * return: ++ * 1: caller needs to save pmds ++ * 0: caller does not need to save pmds, they have been saved by this call ++ */ ++static int pfm_intel_atom_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++#define PFM_ATOM_WMASK (1ULL << 31) ++#define PFM_ATOM_OMASK ((1ULL << 31)-1) ++ u64 clear_ovf = 0; ++ u64 ovf, ovf2, val; ++ ++ /* ++ * read global overflow status register ++ * if sharing PMU, then not all bit are ours so must ++ * check only the ones we actually use. ++ * ++ * XXX: Atom seems to have a bug with the stickyness of ++ * GLOBAL_STATUS. If we read GLOBAL_STATUS after we ++ * clear the generic counters, then their bits in ++ * GLOBAL_STATUS are cleared. This should not be the ++ * case accoding to architected PMU. To workaround ++ * the problem, we read GLOBAL_STATUS BEFORE we stop ++ * all monitoring. ++ */ ++ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, ovf); ++ ++ /* ++ * stop monitoring ++ */ ++ if (test_bit(0, cast_ulp(set->used_pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL0, 0); ++ ++ if (test_bit(1, cast_ulp(set->used_pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL1, 0); ++ ++ if (test_bit(16, cast_ulp(set->used_pmcs))) ++ wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, 0); ++ ++ if (test_bit(17, cast_ulp(set->used_pmcs))) ++ wrmsrl(MSR_IA32_PEBS_ENABLE, 0); ++ ++ /* ++ * XXX: related to bug mentioned above ++ * ++ * read GLOBAL_STATUS again to avoid race condition ++ * with overflows happening after first read and ++ * before stop. That avoids missing overflows on ++ * the fixed counters and PEBS ++ */ ++ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, ovf2); ++ ovf |= ovf2; ++ ++ /* ++ * if we already have a pending overflow condition, we simply ++ * return to take care of it first. ++ */ ++ if (set->npend_ovfls) ++ return 1; ++ ++ /* ++ * check PMD 0,1,16,17,18 for overflow and save their value ++ */ ++ if (test_bit(0, cast_ulp(set->used_pmds))) { ++ rdmsrl(MSR_P6_PERFCTR0, val); ++ if (ovf & ((1ull<<62)|1ull)) { ++ __set_bit(0, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ clear_ovf = (1ull << 62) | 1ull; ++ } ++ val = (set->pmds[0].value & ~PFM_ATOM_OMASK) ++ | (val & PFM_ATOM_OMASK); ++ set->pmds[0].value = val; ++ } ++ ++ if (test_bit(1, cast_ulp(set->used_pmds))) { ++ rdmsrl(MSR_P6_PERFCTR1, val); ++ if (ovf & 2ull) { ++ __set_bit(1, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ clear_ovf |= 2ull; ++ } ++ val = (set->pmds[1].value & ~PFM_ATOM_OMASK) ++ | (val & PFM_ATOM_OMASK); ++ set->pmds[1].value = val; ++ } ++ ++ if (test_bit(16, cast_ulp(set->used_pmds))) { ++ rdmsrl(MSR_CORE_PERF_FIXED_CTR0, val); ++ if (ovf & (1ull << 32)) { ++ __set_bit(16, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ clear_ovf |= 1ull << 32; ++ } ++ val = (set->pmds[16].value & ~PFM_ATOM_OMASK) ++ | (val & PFM_ATOM_OMASK); ++ set->pmds[16].value = val; ++ } ++ ++ if (test_bit(17, cast_ulp(set->used_pmds))) { ++ rdmsrl(MSR_CORE_PERF_FIXED_CTR0+1, val); ++ if (ovf & (2ull << 32)) { ++ __set_bit(17, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ clear_ovf |= 2ull << 32; ++ } ++ val = (set->pmds[17].value & ~PFM_ATOM_OMASK) ++ | (val & PFM_ATOM_OMASK); ++ set->pmds[17].value = val; ++ } ++ ++ if (test_bit(18, cast_ulp(set->used_pmds))) { ++ rdmsrl(MSR_CORE_PERF_FIXED_CTR0+2, val); ++ if (ovf & (4ull << 32)) { ++ __set_bit(18, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ clear_ovf |= 4ull << 32; ++ } ++ val = (set->pmds[18].value & ~PFM_ATOM_OMASK) ++ | (val & PFM_ATOM_OMASK); ++ set->pmds[18].value = val; ++ } ++ ++ if (clear_ovf) ++ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, clear_ovf); ++ ++ /* 0 means: no need to save PMDs at upper level */ ++ return 0; ++} ++ ++/** ++ * pfm_intel_atom_quiesce - stop monitoring without grabbing any lock ++ * ++ * called from NMI interrupt handler to immediately stop monitoring ++ * cannot grab any lock, including perfmon related locks ++ */ ++static void __kprobes pfm_intel_atom_quiesce(void) ++{ ++ /* ++ * quiesce PMU by clearing available registers that have ++ * the start/stop capability ++ */ ++ if (test_bit(0, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL0, 0); ++ ++ if (test_bit(1, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL1, 0); ++ ++ if (test_bit(16, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, 0); ++ ++ if (test_bit(17, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_IA32_PEBS_ENABLE, 0); ++} ++ ++/** ++ * pfm_intel_atom_restore_pmcs - reload PMC registers ++ * @ctx: context to restore from ++ * @set: current event set ++ * ++ * restores pmcs and also PEBS Data Save area pointer ++ */ ++static void pfm_intel_atom_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch; ++ u64 clear_ovf = 0; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ /* ++ * must restore DS pointer before restoring PMCs ++ * as this can potentially reactivate monitoring ++ */ ++ if (ctx_arch->flags.use_ds) ++ wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ctx_arch->ds_area); ++ ++ if (test_bit(0, cast_ulp(set->used_pmcs))) { ++ wrmsrl(MSR_P6_EVNTSEL0, set->pmcs[0]); ++ clear_ovf = 1ull; ++ } ++ ++ if (test_bit(1, cast_ulp(set->used_pmcs))) { ++ wrmsrl(MSR_P6_EVNTSEL1, set->pmcs[1]); ++ clear_ovf |= 2ull; ++ } ++ ++ if (test_bit(16, cast_ulp(set->used_pmcs))) { ++ wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, set->pmcs[16]); ++ clear_ovf |= 7ull << 32; ++ } ++ ++ if (test_bit(17, cast_ulp(set->used_pmcs))) { ++ wrmsrl(MSR_IA32_PEBS_ENABLE, set->pmcs[17]); ++ clear_ovf |= 1ull << 62; ++ } ++ ++ if (clear_ovf) ++ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, clear_ovf); ++} ++ ++static int pfm_intel_atom_pmc17_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * if user activates PEBS_ENABLE, then we need to have a valid ++ * DS Area setup. This only happens when the PEBS sampling format is ++ * used in which case PFM_X86_USE_PEBS is set. We must reject all other ++ * requests. ++ * ++ * Otherwise we may pickup stale MSR_IA32_DS_AREA values. It appears ++ * that a value of 0 for this MSR does crash the system with ++ * PEBS_ENABLE=1. ++ */ ++ if (!ctx_arch->flags.use_pebs && req->reg_value) { ++ PFM_DBG("pmc17 useable only with a PEBS sampling format"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++DEFINE_PER_CPU(u64, saved_global_ctrl); ++ ++/** ++ * pfm_intel_atom_acquire_pmu_percpu - acquire PMU resource per CPU ++ * ++ * For Atom, it is necessary to enable all available ++ * registers. The firmware rightfully has the fixed counters ++ * disabled for backward compatibility with architectural perfmon ++ * v1 ++ * ++ * This function is invoked on each online CPU ++ */ ++static void pfm_intel_atom_acquire_pmu_percpu(void) ++{ ++ struct pfm_regmap_desc *d; ++ u64 mask = 0; ++ unsigned int i; ++ ++ /* ++ * build bitmask of registers that are available to ++ * us. In some cases, there may be fewer registers than ++ * what Atom supports due to sharing with other kernel ++ * subsystems, such as NMI ++ */ ++ d = pfm_pmu_conf->pmd_desc; ++ for (i=0; i < 16; i++) { ++ if ((d[i].type & PFM_REG_I) == 0) ++ continue; ++ mask |= 1ull << i; ++ } ++ for (i=16; i < PFM_ATOM_MAX_PMDS; i++) { ++ if ((d[i].type & PFM_REG_I) == 0) ++ continue; ++ mask |= 1ull << (32+i-16); ++ } ++ ++ /* ++ * keep a local copy of the current MSR_CORE_PERF_GLOBAL_CTRL ++ */ ++ rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, __get_cpu_var(saved_global_ctrl)); ++ ++ PFM_DBG("global=0x%llx set to 0x%llx", ++ __get_cpu_var(saved_global_ctrl), ++ mask); ++ ++ /* ++ * enable all registers ++ * ++ * No need to quiesce PMU. If there is a overflow, it will be ++ * treated as spurious by the handler ++ */ ++ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, mask); ++} ++ ++/** ++ * pfm_intel_atom_release_pmu_percpu - release PMU resource per CPU ++ * ++ * For Atom, we restore MSR_CORE_PERF_GLOBAL_CTRL to its orginal value ++ */ ++static void pfm_intel_atom_release_pmu_percpu(void) ++{ ++ PFM_DBG("global_ctrl restored to 0x%llx\n", ++ __get_cpu_var(saved_global_ctrl)); ++ ++ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, __get_cpu_var(saved_global_ctrl)); ++} ++ ++static struct pfm_pmu_config pfm_intel_atom_pmu_conf = { ++ .pmu_name = "Intel Atom", ++ .pmd_desc = pfm_intel_atom_pmd_desc, ++ .counter_width = PFM_ATOM_PMD_WIDTH, ++ .num_pmc_entries = PFM_ATOM_MAX_PMCS, ++ .num_pmd_entries = PFM_ATOM_MAX_PMDS, ++ .pmc_desc = pfm_intel_atom_pmc_desc, ++ .probe_pmu = pfm_intel_atom_probe_pmu, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmc_write_check = pfm_intel_atom_pmc17_check, ++ .pmu_info = &pfm_intel_atom_pmu_info ++}; ++ ++static int __init pfm_intel_atom_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_intel_atom_pmu_conf); ++} ++ ++static void __exit pfm_intel_atom_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_intel_atom_pmu_conf); ++} ++ ++module_init(pfm_intel_atom_pmu_init_module); ++module_exit(pfm_intel_atom_pmu_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_intel_core.c +@@ -0,0 +1,449 @@ ++/* ++ * This file contains the Intel Core PMU registers description tables. ++ * Intel Core-based processors support architectural perfmon v2 + PEBS ++ * ++ * Copyright (c) 2006-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ */ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Intel Core"); ++MODULE_LICENSE("GPL"); ++ ++static int force_nmi; ++MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt"); ++module_param(force_nmi, bool, 0600); ++ ++/* ++ * - upper 32 bits are reserved ++ * - INT: APIC enable bit is reserved (forced to 1) ++ * - bit 21 is reserved ++ * ++ * RSVD: reserved bits must be 1 ++ */ ++#define PFM_CORE_PMC_RSVD ((~((1ULL<<32)-1)) \ ++ | (1ULL<<20) \ ++ | (1ULL<<21)) ++ ++/* ++ * Core counters are 40-bits ++ */ ++#define PFM_CORE_CTR_RSVD (~((1ULL<<40)-1)) ++ ++/* ++ * force Local APIC interrupt on overflow ++ * disable with NO_EMUL64 ++ */ ++#define PFM_CORE_PMC_VAL (1ULL<<20) ++#define PFM_CORE_NO64 (1ULL<<20) ++ ++#define PFM_CORE_NA { .reg_type = PFM_REGT_NA} ++ ++#define PFM_CORE_CA(m, c, t) \ ++ { \ ++ .addrs[0] = m, \ ++ .ctr = c, \ ++ .reg_type = t \ ++ } ++ ++struct pfm_ds_area_intel_core { ++ u64 bts_buf_base; ++ u64 bts_index; ++ u64 bts_abs_max; ++ u64 bts_intr_thres; ++ u64 pebs_buf_base; ++ u64 pebs_index; ++ u64 pebs_abs_max; ++ u64 pebs_intr_thres; ++ u64 pebs_cnt_reset; ++}; ++ ++static void pfm_core_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static int pfm_core_has_ovfls(struct pfm_context *ctx); ++static int pfm_core_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++static void __kprobes pfm_core_quiesce(void); ++ ++static u64 enable_mask[PFM_MAX_PMCS]; ++static u16 max_enable; ++ ++struct pfm_arch_pmu_info pfm_core_pmu_info = { ++ .stop_save = pfm_core_stop_save, ++ .has_ovfls = pfm_core_has_ovfls, ++ .quiesce = pfm_core_quiesce, ++ .restore_pmcs = pfm_core_restore_pmcs ++}; ++ ++static struct pfm_regmap_desc pfm_core_pmc_desc[] = { ++/* pmc0 */ { ++ .type = PFM_REG_I64, ++ .desc = "PERFEVTSEL0", ++ .dfl_val = PFM_CORE_PMC_VAL, ++ .rsvd_msk = PFM_CORE_PMC_RSVD, ++ .no_emul64_msk = PFM_CORE_NO64, ++ .hw_addr = MSR_P6_EVNTSEL0 ++ }, ++/* pmc1 */ { ++ .type = PFM_REG_I64, ++ .desc = "PERFEVTSEL1", ++ .dfl_val = PFM_CORE_PMC_VAL, ++ .rsvd_msk = PFM_CORE_PMC_RSVD, ++ .no_emul64_msk = PFM_CORE_NO64, ++ .hw_addr = MSR_P6_EVNTSEL1 ++ }, ++/* pmc2 */ PMX_NA, PMX_NA, ++/* pmc4 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc8 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc12 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmc16 */ { .type = PFM_REG_I, ++ .desc = "FIXED_CTRL", ++ .dfl_val = 0x888ULL, ++ .rsvd_msk = 0xfffffffffffffcccULL, ++ .no_emul64_msk = 0, ++ .hw_addr = MSR_CORE_PERF_FIXED_CTR_CTRL ++ }, ++/* pmc17 */ { .type = PFM_REG_W, ++ .desc = "PEBS_ENABLE", ++ .dfl_val = 0, ++ .rsvd_msk = 0xfffffffffffffffeULL, ++ .no_emul64_msk = 0, ++ .hw_addr = MSR_IA32_PEBS_ENABLE ++ } ++}; ++ ++#define PFM_CORE_D(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "PMC"#n, \ ++ .rsvd_msk = PFM_CORE_CTR_RSVD, \ ++ .hw_addr = MSR_P6_PERFCTR0+n, \ ++ .dep_pmcs[0] = 1ULL << n \ ++ } ++ ++#define PFM_CORE_FD(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "FIXED_CTR"#n, \ ++ .rsvd_msk = PFM_CORE_CTR_RSVD, \ ++ .hw_addr = MSR_CORE_PERF_FIXED_CTR0+n,\ ++ .dep_pmcs[0] = 1ULL << 16 \ ++ } ++ ++static struct pfm_regmap_desc pfm_core_pmd_desc[] = { ++/* pmd0 */ PFM_CORE_D(0), ++/* pmd1 */ PFM_CORE_D(1), ++/* pmd2 */ PMX_NA, PMX_NA, ++/* pmd4 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmd8 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmd12 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, ++/* pmd16 */ PFM_CORE_FD(0), ++/* pmd17 */ PFM_CORE_FD(1), ++/* pmd18 */ PFM_CORE_FD(2) ++}; ++#define PFM_CORE_NUM_PMCS ARRAY_SIZE(pfm_core_pmc_desc) ++#define PFM_CORE_NUM_PMDS ARRAY_SIZE(pfm_core_pmd_desc) ++ ++static struct pfm_pmu_config pfm_core_pmu_conf; ++ ++static int pfm_core_probe_pmu(void) ++{ ++ /* ++ * Check for Intel Core processor explicitely ++ * Checking for cpu_has_perfmon is not enough as this ++ * matches intel Core Duo/Core Solo but none supports ++ * PEBS. ++ * ++ * Intel Core = arch perfmon v2 + PEBS ++ */ ++ if (current_cpu_data.x86_vendor != X86_VENDOR_INTEL) { ++ PFM_INFO("not an AMD processor"); ++ return -1; ++ } ++ ++ if (current_cpu_data.x86 != 6) ++ return -1; ++ ++ switch (current_cpu_data.x86_model) { ++ case 15: /* Merom */ ++ break; ++ case 23: /* Penryn */ ++ break; ++ case 29: /* Dunnington */ ++ break; ++ default: ++ return -1; ++ } ++ ++ if (!cpu_has_apic) { ++ PFM_INFO("no Local APIC, unsupported"); ++ return -1; ++ } ++ ++ PFM_INFO("nmi_watchdog=%d nmi_active=%d force_nmi=%d", ++ nmi_watchdog, atomic_read(&nmi_active), force_nmi); ++ ++ /* ++ * Intel Core processors implement DS and PEBS, no need to check ++ */ ++ if (cpu_has_pebs) ++ PFM_INFO("PEBS supported, enabled"); ++ ++ /* ++ * initialize bitmask of register with enable capability, i.e., ++ * startstop. This is used to restrict the number of registers to ++ * touch on start/stop ++ * max_enable: number of bits to scan in enable_mask = highest + 1 ++ * ++ * may be adjusted in pfm_arch_pmu_acquire() ++ */ ++ __set_bit(0, cast_ulp(enable_mask)); ++ __set_bit(1, cast_ulp(enable_mask)); ++ __set_bit(16, cast_ulp(enable_mask)); ++ __set_bit(17, cast_ulp(enable_mask)); ++ max_enable = 17+1; ++ ++ if (force_nmi) ++ pfm_core_pmu_info.flags |= PFM_X86_FL_USE_NMI; ++ ++ return 0; ++} ++ ++static int pfm_core_pmc17_check(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * if user activates PEBS_ENABLE, then we need to have a valid ++ * DS Area setup. This only happens when the PEBS sampling format is ++ * used in which case PFM_X86_USE_PEBS is set. We must reject all other ++ * requests. ++ * ++ * Otherwise we may pickup stale MSR_IA32_DS_AREA values. It appears ++ * that a value of 0 for this MSR does crash the system with ++ * PEBS_ENABLE=1. ++ */ ++ if (!ctx_arch->flags.use_pebs && req->reg_value) { ++ PFM_DBG("pmc17 useable only with a PEBS sampling format"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * detect is counters have overflowed. ++ * return: ++ * 0 : no overflow ++ * 1 : at least one overflow ++ * ++ * used by Intel Core-based processors ++ */ ++static int __kprobes pfm_core_has_ovfls(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u64 *cnt_mask; ++ u64 wmask, val; ++ u16 i, num; ++ ++ pmu_info = &pfm_core_pmu_info; ++ cnt_mask = ctx->regs.cnt_pmds; ++ num = ctx->regs.num_counters; ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(cnt_mask))) { ++ rdmsrl(pfm_core_pmd_desc[i].hw_addr, val); ++ if (!(val & wmask)) ++ return 1; ++ num--; ++ } ++ } ++ return 0; ++} ++ ++static int pfm_core_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_ds_area_intel_core *ds = NULL; ++ u64 used_mask[PFM_PMC_BV]; ++ u64 *cnt_mask; ++ u64 val, wmask, ovfl_mask; ++ u16 count, has_ovfl; ++ u16 i, pebs_idx = ~0; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ /* ++ * used enable pmc bitmask ++ */ ++ bitmap_and(cast_ulp(used_mask), ++ cast_ulp(set->used_pmcs), ++ cast_ulp(enable_mask), ++ max_enable); ++ ++ count = bitmap_weight(cast_ulp(used_mask), max_enable); ++ /* ++ * stop monitoring ++ * Unfortunately, this is very expensive! ++ * wrmsrl() is serializing. ++ */ ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(used_mask))) { ++ wrmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, 0); ++ count--; ++ } ++ } ++ /* ++ * if we already having a pending overflow condition, we simply ++ * return to take care of this first. ++ */ ++ if (set->npend_ovfls) ++ return 1; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ cnt_mask = ctx->regs.cnt_pmds; ++ ++ if (ctx_arch->flags.use_pebs) { ++ ds = ctx_arch->ds_area; ++ pebs_idx = 0; /* PMC0/PMD0 */ ++ PFM_DBG("ds=%p pebs_idx=0x%llx thres=0x%llx", ++ ds, ++ (unsigned long long)ds->pebs_index, ++ (unsigned long long)ds->pebs_intr_thres); ++ } ++ ++ /* ++ * Check for pending overflows and save PMDs (combo) ++ * We employ used_pmds and not intr_pmds because we must ++ * also saved on PMD registers. ++ * Must check for counting PMDs because of virtual PMDs ++ * ++ * XXX: should use the ovf_status register instead, yet ++ * we would have to check if NMI is used and fallback ++ * to individual pmd inspection. ++ */ ++ count = set->nused_pmds; ++ ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(set->used_pmds))) { ++ val = pfm_arch_read_pmd(ctx, i); ++ if (likely(test_bit(i, cast_ulp(cnt_mask)))) { ++ if (i == pebs_idx) ++ has_ovfl = (ds->pebs_index >= ++ ds->pebs_intr_thres); ++ else ++ has_ovfl = !(val & wmask); ++ if (has_ovfl) { ++ __set_bit(i, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ val = (set->pmds[i].value & ~ovfl_mask) ++ | (val & ovfl_mask); ++ } ++ set->pmds[i].value = val; ++ count--; ++ } ++ } ++ /* 0 means: no need to save PMDs at upper level */ ++ return 0; ++} ++ ++/** ++ * pfm_core_quiesce - stop monitoring without grabbing any lock ++ * ++ * called from NMI interrupt handler to immediately stop monitoring ++ * cannot grab any lock, including perfmon related locks ++ */ ++static void __kprobes pfm_core_quiesce(void) ++{ ++ /* ++ * quiesce PMU by clearing available registers that have ++ * the start/stop capability ++ */ ++ if (test_bit(0, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL0, 0); ++ if (test_bit(1, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL1, 0); ++ if (test_bit(16, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, 0); ++ if (test_bit(17, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_IA32_PEBS_ENABLE, 0); ++} ++/** ++ * pfm_core_restore_pmcs - reload PMC registers ++ * @ctx: context to restore from ++ * @set: current event set ++ * ++ * optimized version of pfm_arch_restore_pmcs(). On Core, we can ++ * afford to only restore the pmcs registers we use, because they are ++ * all independent from each other. ++ */ ++static void pfm_core_restore_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ struct pfm_arch_context *ctx_arch; ++ u64 *mask; ++ u16 i, num; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ /* ++ * must restore DS pointer before restoring PMCs ++ * as this can potentially reactivate monitoring ++ */ ++ if (ctx_arch->flags.use_ds) ++ wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ctx_arch->ds_area); ++ ++ mask = set->used_pmcs; ++ num = set->nused_pmcs; ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(mask))) { ++ wrmsrl(pfm_pmu_conf->pmc_desc[i].hw_addr, set->pmcs[i]); ++ num--; ++ } ++ } ++} ++ ++/* ++ * Counters may have model-specific width which can be probed using ++ * the CPUID.0xa leaf. Yet, the documentation says: " ++ * In the initial implementation, only the read bit width is reported ++ * by CPUID, write operations are limited to the low 32 bits. ++ * Bits [w-32] are sign extensions of bit 31. As such the effective width ++ * of a counter is 31 bits only. ++ */ ++static struct pfm_pmu_config pfm_core_pmu_conf = { ++ .pmu_name = "Intel Core", ++ .pmd_desc = pfm_core_pmd_desc, ++ .counter_width = 31, ++ .num_pmc_entries = PFM_CORE_NUM_PMCS, ++ .num_pmd_entries = PFM_CORE_NUM_PMDS, ++ .pmc_desc = pfm_core_pmc_desc, ++ .probe_pmu = pfm_core_probe_pmu, ++ .version = "1.2", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_core_pmu_info, ++ .pmc_write_check = pfm_core_pmc17_check ++}; ++ ++static int __init pfm_core_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_core_pmu_conf); ++} ++ ++static void __exit pfm_core_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_core_pmu_conf); ++} ++ ++module_init(pfm_core_pmu_init_module); ++module_exit(pfm_core_pmu_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_p4.c +@@ -0,0 +1,913 @@ ++/* ++ * This file contains the P4/Xeon PMU register description tables ++ * for both 32 and 64 bit modes. ++ * ++ * Copyright (c) 2005 Intel Corporation ++ * Contributed by Bryan Wilkerson ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Bryan Wilkerson "); ++MODULE_DESCRIPTION("P4/Xeon/EM64T PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++static int force; ++MODULE_PARM_DESC(force, "bool: force module to load succesfully"); ++module_param(force, bool, 0600); ++ ++static int force_nmi; ++MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt"); ++module_param(force_nmi, bool, 0600); ++ ++/* ++ * For extended register information in addition to address that is used ++ * at runtime to figure out the mapping of reg addresses to logical procs ++ * and association of registers to hardware specific features ++ */ ++struct pfm_p4_regmap { ++ /* ++ * one each for the logical CPUs. Index 0 corresponds to T0 and ++ * index 1 corresponds to T1. Index 1 can be zero if no T1 ++ * complement reg exists. ++ */ ++ unsigned long addrs[2]; /* 2 = number of threads */ ++ unsigned int ctr; /* for CCCR/PERFEVTSEL, associated counter */ ++ unsigned int reg_type; ++}; ++ ++/* ++ * bitmask for pfm_p4_regmap.reg_type ++ */ ++#define PFM_REGT_NA 0x0000 /* not available */ ++#define PFM_REGT_EN 0x0001 /* has enable bit (cleared on ctxsw) */ ++#define PFM_REGT_ESCR 0x0002 /* P4: ESCR */ ++#define PFM_REGT_CCCR 0x0004 /* P4: CCCR */ ++#define PFM_REGT_PEBS 0x0010 /* PEBS related */ ++#define PFM_REGT_NOHT 0x0020 /* unavailable with HT */ ++#define PFM_REGT_CTR 0x0040 /* counter */ ++ ++/* ++ * architecture specific context extension. ++ * located at: (struct pfm_arch_context *)(ctx+1) ++ */ ++struct pfm_arch_p4_context { ++ u32 npend_ovfls; /* P4 NMI #pending ovfls */ ++ u32 reserved; ++ u64 povfl_pmds[PFM_PMD_BV]; /* P4 NMI overflowed counters */ ++ u64 saved_cccrs[PFM_MAX_PMCS]; ++}; ++ ++/* ++ * ESCR reserved bitmask: ++ * - bits 31 - 63 reserved ++ * - T1_OS and T1_USR bits are reserved - set depending on logical proc ++ * user mode application should use T0_OS and T0_USR to indicate ++ * RSVD: reserved bits must be 1 ++ */ ++#define PFM_ESCR_RSVD ~0x000000007ffffffcULL ++ ++/* ++ * CCCR default value: ++ * - OVF_PMI_T0=1 (bit 26) ++ * - OVF_PMI_T1=0 (bit 27) (set if necessary in pfm_write_reg()) ++ * - all other bits are zero ++ * ++ * OVF_PMI is forced to zero if PFM_REGFL_NO_EMUL64 is set on CCCR ++ */ ++#define PFM_CCCR_DFL (1ULL<<26) | (3ULL<<16) ++ ++/* ++ * CCCR reserved fields: ++ * - bits 0-11, 25-29, 31-63 ++ * - OVF_PMI (26-27), override with REGFL_NO_EMUL64 ++ * ++ * RSVD: reserved bits must be 1 ++ */ ++#define PFM_CCCR_RSVD ~((0xfull<<12) \ ++ | (0x7full<<18) \ ++ | (0x1ull<<30)) ++ ++#define PFM_P4_NO64 (3ULL<<26) /* use 3 even in non HT mode */ ++ ++#define PEBS_PMD 8 /* thread0: IQ_CTR4, thread1: IQ_CTR5 */ ++ ++/* ++ * With HyperThreading enabled: ++ * ++ * The ESCRs and CCCRs are divided in half with the top half ++ * belonging to logical processor 0 and the bottom half going to ++ * logical processor 1. Thus only half of the PMU resources are ++ * accessible to applications. ++ * ++ * PEBS is not available due to the fact that: ++ * - MSR_PEBS_MATRIX_VERT is shared between the threads ++ * - IA32_PEBS_ENABLE is shared between the threads ++ * ++ * With HyperThreading disabled: ++ * ++ * The full set of PMU resources is exposed to applications. ++ * ++ * The mapping is chosen such that PMCxx -> MSR is the same ++ * in HT and non HT mode, if register is present in HT mode. ++ * ++ */ ++#define PFM_REGT_NHTESCR (PFM_REGT_ESCR|PFM_REGT_NOHT) ++#define PFM_REGT_NHTCCCR (PFM_REGT_CCCR|PFM_REGT_NOHT|PFM_REGT_EN) ++#define PFM_REGT_NHTPEBS (PFM_REGT_PEBS|PFM_REGT_NOHT|PFM_REGT_EN) ++#define PFM_REGT_NHTCTR (PFM_REGT_CTR|PFM_REGT_NOHT) ++#define PFM_REGT_ENAC (PFM_REGT_CCCR|PFM_REGT_EN) ++ ++static void pfm_p4_write_pmc(struct pfm_context *ctx, unsigned int cnum, u64 value); ++static void pfm_p4_write_pmd(struct pfm_context *ctx, unsigned int cnum, u64 value); ++static u64 pfm_p4_read_pmd(struct pfm_context *ctx, unsigned int cnum); ++static u64 pfm_p4_read_pmc(struct pfm_context *ctx, unsigned int cnum); ++static int pfm_p4_create_context(struct pfm_context *ctx, u32 ctx_flags); ++static void pfm_p4_free_context(struct pfm_context *ctx); ++static int pfm_p4_has_ovfls(struct pfm_context *ctx); ++static int pfm_p4_stop_save(struct pfm_context *ctx, struct pfm_event_set *set); ++static void pfm_p4_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); ++static void pfm_p4_nmi_copy_state(struct pfm_context *ctx); ++static void __kprobes pfm_p4_quiesce(void); ++ ++static u64 enable_mask[PFM_MAX_PMCS]; ++static u16 max_enable; ++ ++static struct pfm_p4_regmap pmc_addrs[PFM_MAX_PMCS] = { ++ /*pmc 0 */ {{MSR_P4_BPU_ESCR0, MSR_P4_BPU_ESCR1}, 0, PFM_REGT_ESCR}, /* BPU_ESCR0,1 */ ++ /*pmc 1 */ {{MSR_P4_IS_ESCR0, MSR_P4_IS_ESCR1}, 0, PFM_REGT_ESCR}, /* IS_ESCR0,1 */ ++ /*pmc 2 */ {{MSR_P4_MOB_ESCR0, MSR_P4_MOB_ESCR1}, 0, PFM_REGT_ESCR}, /* MOB_ESCR0,1 */ ++ /*pmc 3 */ {{MSR_P4_ITLB_ESCR0, MSR_P4_ITLB_ESCR1}, 0, PFM_REGT_ESCR}, /* ITLB_ESCR0,1 */ ++ /*pmc 4 */ {{MSR_P4_PMH_ESCR0, MSR_P4_PMH_ESCR1}, 0, PFM_REGT_ESCR}, /* PMH_ESCR0,1 */ ++ /*pmc 5 */ {{MSR_P4_IX_ESCR0, MSR_P4_IX_ESCR1}, 0, PFM_REGT_ESCR}, /* IX_ESCR0,1 */ ++ /*pmc 6 */ {{MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1}, 0, PFM_REGT_ESCR}, /* FSB_ESCR0,1 */ ++ /*pmc 7 */ {{MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR1}, 0, PFM_REGT_ESCR}, /* BSU_ESCR0,1 */ ++ /*pmc 8 */ {{MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1}, 0, PFM_REGT_ESCR}, /* MS_ESCR0,1 */ ++ /*pmc 9 */ {{MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1}, 0, PFM_REGT_ESCR}, /* TC_ESCR0,1 */ ++ /*pmc 10*/ {{MSR_P4_TBPU_ESCR0, MSR_P4_TBPU_ESCR1}, 0, PFM_REGT_ESCR}, /* TBPU_ESCR0,1 */ ++ /*pmc 11*/ {{MSR_P4_FLAME_ESCR0, MSR_P4_FLAME_ESCR1}, 0, PFM_REGT_ESCR}, /* FLAME_ESCR0,1 */ ++ /*pmc 12*/ {{MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1}, 0, PFM_REGT_ESCR}, /* FIRM_ESCR0,1 */ ++ /*pmc 13*/ {{MSR_P4_SAAT_ESCR0, MSR_P4_SAAT_ESCR1}, 0, PFM_REGT_ESCR}, /* SAAT_ESCR0,1 */ ++ /*pmc 14*/ {{MSR_P4_U2L_ESCR0, MSR_P4_U2L_ESCR1}, 0, PFM_REGT_ESCR}, /* U2L_ESCR0,1 */ ++ /*pmc 15*/ {{MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1}, 0, PFM_REGT_ESCR}, /* DAC_ESCR0,1 */ ++ /*pmc 16*/ {{MSR_P4_IQ_ESCR0, MSR_P4_IQ_ESCR1}, 0, PFM_REGT_ESCR}, /* IQ_ESCR0,1 (only model 1 and 2) */ ++ /*pmc 17*/ {{MSR_P4_ALF_ESCR0, MSR_P4_ALF_ESCR1}, 0, PFM_REGT_ESCR}, /* ALF_ESCR0,1 */ ++ /*pmc 18*/ {{MSR_P4_RAT_ESCR0, MSR_P4_RAT_ESCR1}, 0, PFM_REGT_ESCR}, /* RAT_ESCR0,1 */ ++ /*pmc 19*/ {{MSR_P4_SSU_ESCR0, 0}, 0, PFM_REGT_ESCR}, /* SSU_ESCR0 */ ++ /*pmc 20*/ {{MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1}, 0, PFM_REGT_ESCR}, /* CRU_ESCR0,1 */ ++ /*pmc 21*/ {{MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3}, 0, PFM_REGT_ESCR}, /* CRU_ESCR2,3 */ ++ /*pmc 22*/ {{MSR_P4_CRU_ESCR4, MSR_P4_CRU_ESCR5}, 0, PFM_REGT_ESCR}, /* CRU_ESCR4,5 */ ++ ++ /*pmc 23*/ {{MSR_P4_BPU_CCCR0, MSR_P4_BPU_CCCR2}, 0, PFM_REGT_ENAC}, /* BPU_CCCR0,2 */ ++ /*pmc 24*/ {{MSR_P4_BPU_CCCR1, MSR_P4_BPU_CCCR3}, 1, PFM_REGT_ENAC}, /* BPU_CCCR1,3 */ ++ /*pmc 25*/ {{MSR_P4_MS_CCCR0, MSR_P4_MS_CCCR2}, 2, PFM_REGT_ENAC}, /* MS_CCCR0,2 */ ++ /*pmc 26*/ {{MSR_P4_MS_CCCR1, MSR_P4_MS_CCCR3}, 3, PFM_REGT_ENAC}, /* MS_CCCR1,3 */ ++ /*pmc 27*/ {{MSR_P4_FLAME_CCCR0, MSR_P4_FLAME_CCCR2}, 4, PFM_REGT_ENAC}, /* FLAME_CCCR0,2 */ ++ /*pmc 28*/ {{MSR_P4_FLAME_CCCR1, MSR_P4_FLAME_CCCR3}, 5, PFM_REGT_ENAC}, /* FLAME_CCCR1,3 */ ++ /*pmc 29*/ {{MSR_P4_IQ_CCCR0, MSR_P4_IQ_CCCR2}, 6, PFM_REGT_ENAC}, /* IQ_CCCR0,2 */ ++ /*pmc 30*/ {{MSR_P4_IQ_CCCR1, MSR_P4_IQ_CCCR3}, 7, PFM_REGT_ENAC}, /* IQ_CCCR1,3 */ ++ /*pmc 31*/ {{MSR_P4_IQ_CCCR4, MSR_P4_IQ_CCCR5}, 8, PFM_REGT_ENAC}, /* IQ_CCCR4,5 */ ++ /* non HT extensions */ ++ /*pmc 32*/ {{MSR_P4_BPU_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* BPU_ESCR1 */ ++ /*pmc 33*/ {{MSR_P4_IS_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* IS_ESCR1 */ ++ /*pmc 34*/ {{MSR_P4_MOB_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* MOB_ESCR1 */ ++ /*pmc 35*/ {{MSR_P4_ITLB_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* ITLB_ESCR1 */ ++ /*pmc 36*/ {{MSR_P4_PMH_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* PMH_ESCR1 */ ++ /*pmc 37*/ {{MSR_P4_IX_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* IX_ESCR1 */ ++ /*pmc 38*/ {{MSR_P4_FSB_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* FSB_ESCR1 */ ++ /*pmc 39*/ {{MSR_P4_BSU_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* BSU_ESCR1 */ ++ /*pmc 40*/ {{MSR_P4_MS_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* MS_ESCR1 */ ++ /*pmc 41*/ {{MSR_P4_TC_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* TC_ESCR1 */ ++ /*pmc 42*/ {{MSR_P4_TBPU_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* TBPU_ESCR1 */ ++ /*pmc 43*/ {{MSR_P4_FLAME_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* FLAME_ESCR1 */ ++ /*pmc 44*/ {{MSR_P4_FIRM_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* FIRM_ESCR1 */ ++ /*pmc 45*/ {{MSR_P4_SAAT_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* SAAT_ESCR1 */ ++ /*pmc 46*/ {{MSR_P4_U2L_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* U2L_ESCR1 */ ++ /*pmc 47*/ {{MSR_P4_DAC_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* DAC_ESCR1 */ ++ /*pmc 48*/ {{MSR_P4_IQ_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* IQ_ESCR1 (only model 1 and 2) */ ++ /*pmc 49*/ {{MSR_P4_ALF_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* ALF_ESCR1 */ ++ /*pmc 50*/ {{MSR_P4_RAT_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* RAT_ESCR1 */ ++ /*pmc 51*/ {{MSR_P4_CRU_ESCR1, 0}, 0, PFM_REGT_NHTESCR}, /* CRU_ESCR1 */ ++ /*pmc 52*/ {{MSR_P4_CRU_ESCR3, 0}, 0, PFM_REGT_NHTESCR}, /* CRU_ESCR3 */ ++ /*pmc 53*/ {{MSR_P4_CRU_ESCR5, 0}, 0, PFM_REGT_NHTESCR}, /* CRU_ESCR5 */ ++ /*pmc 54*/ {{MSR_P4_BPU_CCCR1, 0}, 9, PFM_REGT_NHTCCCR}, /* BPU_CCCR1 */ ++ /*pmc 55*/ {{MSR_P4_BPU_CCCR3, 0}, 10, PFM_REGT_NHTCCCR}, /* BPU_CCCR3 */ ++ /*pmc 56*/ {{MSR_P4_MS_CCCR1, 0}, 11, PFM_REGT_NHTCCCR}, /* MS_CCCR1 */ ++ /*pmc 57*/ {{MSR_P4_MS_CCCR3, 0}, 12, PFM_REGT_NHTCCCR}, /* MS_CCCR3 */ ++ /*pmc 58*/ {{MSR_P4_FLAME_CCCR1, 0}, 13, PFM_REGT_NHTCCCR}, /* FLAME_CCCR1 */ ++ /*pmc 59*/ {{MSR_P4_FLAME_CCCR3, 0}, 14, PFM_REGT_NHTCCCR}, /* FLAME_CCCR3 */ ++ /*pmc 60*/ {{MSR_P4_IQ_CCCR2, 0}, 15, PFM_REGT_NHTCCCR}, /* IQ_CCCR2 */ ++ /*pmc 61*/ {{MSR_P4_IQ_CCCR3, 0}, 16, PFM_REGT_NHTCCCR}, /* IQ_CCCR3 */ ++ /*pmc 62*/ {{MSR_P4_IQ_CCCR5, 0}, 17, PFM_REGT_NHTCCCR}, /* IQ_CCCR5 */ ++ /*pmc 63*/ {{0x3f2, 0}, 0, PFM_REGT_NHTPEBS},/* PEBS_MATRIX_VERT */ ++ /*pmc 64*/ {{0x3f1, 0}, 0, PFM_REGT_NHTPEBS} /* PEBS_ENABLE */ ++}; ++ ++static struct pfm_p4_regmap pmd_addrs[PFM_MAX_PMDS] = { ++ /*pmd 0 */ {{MSR_P4_BPU_PERFCTR0, MSR_P4_BPU_PERFCTR2}, 0, PFM_REGT_CTR}, /* BPU_CTR0,2 */ ++ /*pmd 1 */ {{MSR_P4_BPU_PERFCTR1, MSR_P4_BPU_PERFCTR3}, 0, PFM_REGT_CTR}, /* BPU_CTR1,3 */ ++ /*pmd 2 */ {{MSR_P4_MS_PERFCTR0, MSR_P4_MS_PERFCTR2}, 0, PFM_REGT_CTR}, /* MS_CTR0,2 */ ++ /*pmd 3 */ {{MSR_P4_MS_PERFCTR1, MSR_P4_MS_PERFCTR3}, 0, PFM_REGT_CTR}, /* MS_CTR1,3 */ ++ /*pmd 4 */ {{MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_PERFCTR2}, 0, PFM_REGT_CTR}, /* FLAME_CTR0,2 */ ++ /*pmd 5 */ {{MSR_P4_FLAME_PERFCTR1, MSR_P4_FLAME_PERFCTR3}, 0, PFM_REGT_CTR}, /* FLAME_CTR1,3 */ ++ /*pmd 6 */ {{MSR_P4_IQ_PERFCTR0, MSR_P4_IQ_PERFCTR2}, 0, PFM_REGT_CTR}, /* IQ_CTR0,2 */ ++ /*pmd 7 */ {{MSR_P4_IQ_PERFCTR1, MSR_P4_IQ_PERFCTR3}, 0, PFM_REGT_CTR}, /* IQ_CTR1,3 */ ++ /*pmd 8 */ {{MSR_P4_IQ_PERFCTR4, MSR_P4_IQ_PERFCTR5}, 0, PFM_REGT_CTR}, /* IQ_CTR4,5 */ ++ /* ++ * non HT extensions ++ */ ++ /*pmd 9 */ {{MSR_P4_BPU_PERFCTR2, 0}, 0, PFM_REGT_NHTCTR}, /* BPU_CTR2 */ ++ /*pmd 10*/ {{MSR_P4_BPU_PERFCTR3, 0}, 0, PFM_REGT_NHTCTR}, /* BPU_CTR3 */ ++ /*pmd 11*/ {{MSR_P4_MS_PERFCTR2, 0}, 0, PFM_REGT_NHTCTR}, /* MS_CTR2 */ ++ /*pmd 12*/ {{MSR_P4_MS_PERFCTR3, 0}, 0, PFM_REGT_NHTCTR}, /* MS_CTR3 */ ++ /*pmd 13*/ {{MSR_P4_FLAME_PERFCTR2, 0}, 0, PFM_REGT_NHTCTR}, /* FLAME_CTR2 */ ++ /*pmd 14*/ {{MSR_P4_FLAME_PERFCTR3, 0}, 0, PFM_REGT_NHTCTR}, /* FLAME_CTR3 */ ++ /*pmd 15*/ {{MSR_P4_IQ_PERFCTR2, 0}, 0, PFM_REGT_NHTCTR}, /* IQ_CTR2 */ ++ /*pmd 16*/ {{MSR_P4_IQ_PERFCTR3, 0}, 0, PFM_REGT_NHTCTR}, /* IQ_CTR3 */ ++ /*pmd 17*/ {{MSR_P4_IQ_PERFCTR5, 0}, 0, PFM_REGT_NHTCTR}, /* IQ_CTR5 */ ++}; ++ ++static struct pfm_arch_pmu_info pfm_p4_pmu_info = { ++ .write_pmc = pfm_p4_write_pmc, ++ .write_pmd = pfm_p4_write_pmd, ++ .read_pmc = pfm_p4_read_pmc, ++ .read_pmd = pfm_p4_read_pmd, ++ .create_context = pfm_p4_create_context, ++ .free_context = pfm_p4_free_context, ++ .has_ovfls = pfm_p4_has_ovfls, ++ .stop_save = pfm_p4_stop_save, ++ .restore_pmcs = pfm_p4_restore_pmcs, ++ .nmi_copy_state = pfm_p4_nmi_copy_state, ++ .quiesce = pfm_p4_quiesce ++}; ++ ++static struct pfm_regmap_desc pfm_p4_pmc_desc[] = { ++/* pmc0 */ PMC_D(PFM_REG_I, "BPU_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_BPU_ESCR0), ++/* pmc1 */ PMC_D(PFM_REG_I, "IS_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_IQ_ESCR0), ++/* pmc2 */ PMC_D(PFM_REG_I, "MOB_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_MOB_ESCR0), ++/* pmc3 */ PMC_D(PFM_REG_I, "ITLB_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_ITLB_ESCR0), ++/* pmc4 */ PMC_D(PFM_REG_I, "PMH_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_PMH_ESCR0), ++/* pmc5 */ PMC_D(PFM_REG_I, "IX_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_IX_ESCR0), ++/* pmc6 */ PMC_D(PFM_REG_I, "FSB_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_FSB_ESCR0), ++/* pmc7 */ PMC_D(PFM_REG_I, "BSU_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_BSU_ESCR0), ++/* pmc8 */ PMC_D(PFM_REG_I, "MS_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_MS_ESCR0), ++/* pmc9 */ PMC_D(PFM_REG_I, "TC_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_TC_ESCR0), ++/* pmc10 */ PMC_D(PFM_REG_I, "TBPU_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_TBPU_ESCR0), ++/* pmc11 */ PMC_D(PFM_REG_I, "FLAME_ESCR0", 0x0, PFM_ESCR_RSVD, 0, MSR_P4_FLAME_ESCR0), ++/* pmc12 */ PMC_D(PFM_REG_I, "FIRM_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_FIRM_ESCR0), ++/* pmc13 */ PMC_D(PFM_REG_I, "SAAT_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_SAAT_ESCR0), ++/* pmc14 */ PMC_D(PFM_REG_I, "U2L_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_U2L_ESCR0), ++/* pmc15 */ PMC_D(PFM_REG_I, "DAC_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_DAC_ESCR0), ++/* pmc16 */ PMC_D(PFM_REG_I, "IQ_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_IQ_ESCR0), /* only model 1 and 2*/ ++/* pmc17 */ PMC_D(PFM_REG_I, "ALF_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_ALF_ESCR0), ++/* pmc18 */ PMC_D(PFM_REG_I, "RAT_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_RAT_ESCR0), ++/* pmc19 */ PMC_D(PFM_REG_I, "SSU_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_SSU_ESCR0), ++/* pmc20 */ PMC_D(PFM_REG_I, "CRU_ESCR0" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_CRU_ESCR0), ++/* pmc21 */ PMC_D(PFM_REG_I, "CRU_ESCR2" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_CRU_ESCR2), ++/* pmc22 */ PMC_D(PFM_REG_I, "CRU_ESCR4" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_CRU_ESCR4), ++/* pmc23 */ PMC_D(PFM_REG_I64, "BPU_CCCR0" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_BPU_CCCR0), ++/* pmc24 */ PMC_D(PFM_REG_I64, "BPU_CCCR1" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_BPU_CCCR1), ++/* pmc25 */ PMC_D(PFM_REG_I64, "MS_CCCR0" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_MS_CCCR0), ++/* pmc26 */ PMC_D(PFM_REG_I64, "MS_CCCR1" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_MS_CCCR1), ++/* pmc27 */ PMC_D(PFM_REG_I64, "FLAME_CCCR0", PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_FLAME_CCCR0), ++/* pmc28 */ PMC_D(PFM_REG_I64, "FLAME_CCCR1", PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_FLAME_CCCR1), ++/* pmc29 */ PMC_D(PFM_REG_I64, "IQ_CCCR0" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_IQ_CCCR0), ++/* pmc30 */ PMC_D(PFM_REG_I64, "IQ_CCCR1" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_IQ_CCCR1), ++/* pmc31 */ PMC_D(PFM_REG_I64, "IQ_CCCR4" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_IQ_CCCR4), ++ /* No HT extension */ ++/* pmc32 */ PMC_D(PFM_REG_I, "BPU_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_BPU_ESCR1), ++/* pmc33 */ PMC_D(PFM_REG_I, "IS_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_IS_ESCR1), ++/* pmc34 */ PMC_D(PFM_REG_I, "MOB_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_MOB_ESCR1), ++/* pmc35 */ PMC_D(PFM_REG_I, "ITLB_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_ITLB_ESCR1), ++/* pmc36 */ PMC_D(PFM_REG_I, "PMH_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_PMH_ESCR1), ++/* pmc37 */ PMC_D(PFM_REG_I, "IX_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_IX_ESCR1), ++/* pmc38 */ PMC_D(PFM_REG_I, "FSB_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_FSB_ESCR1), ++/* pmc39 */ PMC_D(PFM_REG_I, "BSU_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_BSU_ESCR1), ++/* pmc40 */ PMC_D(PFM_REG_I, "MS_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_MS_ESCR1), ++/* pmc41 */ PMC_D(PFM_REG_I, "TC_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_TC_ESCR1), ++/* pmc42 */ PMC_D(PFM_REG_I, "TBPU_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_TBPU_ESCR1), ++/* pmc43 */ PMC_D(PFM_REG_I, "FLAME_ESCR1", 0x0, PFM_ESCR_RSVD, 0, MSR_P4_FLAME_ESCR1), ++/* pmc44 */ PMC_D(PFM_REG_I, "FIRM_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_FIRM_ESCR1), ++/* pmc45 */ PMC_D(PFM_REG_I, "SAAT_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_SAAT_ESCR1), ++/* pmc46 */ PMC_D(PFM_REG_I, "U2L_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_U2L_ESCR1), ++/* pmc47 */ PMC_D(PFM_REG_I, "DAC_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_DAC_ESCR1), ++/* pmc48 */ PMC_D(PFM_REG_I, "IQ_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_IQ_ESCR1), /* only model 1 and 2 */ ++/* pmc49 */ PMC_D(PFM_REG_I, "ALF_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_ALF_ESCR1), ++/* pmc50 */ PMC_D(PFM_REG_I, "RAT_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_RAT_ESCR1), ++/* pmc51 */ PMC_D(PFM_REG_I, "CRU_ESCR1" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_CRU_ESCR1), ++/* pmc52 */ PMC_D(PFM_REG_I, "CRU_ESCR3" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_CRU_ESCR3), ++/* pmc53 */ PMC_D(PFM_REG_I, "CRU_ESCR5" , 0x0, PFM_ESCR_RSVD, 0, MSR_P4_CRU_ESCR5), ++/* pmc54 */ PMC_D(PFM_REG_I64, "BPU_CCCR2" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_BPU_CCCR2), ++/* pmc55 */ PMC_D(PFM_REG_I64, "BPU_CCCR3" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_BPU_CCCR3), ++/* pmc56 */ PMC_D(PFM_REG_I64, "MS_CCCR2" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_MS_CCCR2), ++/* pmc57 */ PMC_D(PFM_REG_I64, "MS_CCCR3" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_MS_CCCR3), ++/* pmc58 */ PMC_D(PFM_REG_I64, "FLAME_CCCR2", PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_FLAME_CCCR2), ++/* pmc59 */ PMC_D(PFM_REG_I64, "FLAME_CCCR3", PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_FLAME_CCCR3), ++/* pmc60 */ PMC_D(PFM_REG_I64, "IQ_CCCR2" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_IQ_CCCR2), ++/* pmc61 */ PMC_D(PFM_REG_I64, "IQ_CCCR3" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_IQ_CCCR3), ++/* pmc62 */ PMC_D(PFM_REG_I64, "IQ_CCCR5" , PFM_CCCR_DFL, PFM_CCCR_RSVD, PFM_P4_NO64, MSR_P4_IQ_CCCR5), ++/* pmc63 */ PMC_D(PFM_REG_I, "PEBS_MATRIX_VERT", 0, 0xffffffffffffffecULL, 0, 0x3f2), ++/* pmc64 */ PMC_D(PFM_REG_I, "PEBS_ENABLE", 0, 0xfffffffff8ffe000ULL, 0, 0x3f1) ++}; ++#define PFM_P4_NUM_PMCS ARRAY_SIZE(pfm_p4_pmc_desc) ++ ++/* ++ * See section 15.10.6.6 for details about the IQ block ++ */ ++static struct pfm_regmap_desc pfm_p4_pmd_desc[] = { ++/* pmd0 */ PMD_D(PFM_REG_C, "BPU_CTR0", MSR_P4_BPU_PERFCTR0), ++/* pmd1 */ PMD_D(PFM_REG_C, "BPU_CTR1", MSR_P4_BPU_PERFCTR1), ++/* pmd2 */ PMD_D(PFM_REG_C, "MS_CTR0", MSR_P4_MS_PERFCTR0), ++/* pmd3 */ PMD_D(PFM_REG_C, "MS_CTR1", MSR_P4_MS_PERFCTR1), ++/* pmd4 */ PMD_D(PFM_REG_C, "FLAME_CTR0", MSR_P4_FLAME_PERFCTR0), ++/* pmd5 */ PMD_D(PFM_REG_C, "FLAME_CTR1", MSR_P4_FLAME_PERFCTR1), ++/* pmd6 */ PMD_D(PFM_REG_C, "IQ_CTR0", MSR_P4_IQ_PERFCTR0), ++/* pmd7 */ PMD_D(PFM_REG_C, "IQ_CTR1", MSR_P4_IQ_PERFCTR1), ++/* pmd8 */ PMD_D(PFM_REG_C, "IQ_CTR4", MSR_P4_IQ_PERFCTR4), ++ /* no HT extension */ ++/* pmd9 */ PMD_D(PFM_REG_C, "BPU_CTR2", MSR_P4_BPU_PERFCTR2), ++/* pmd10 */ PMD_D(PFM_REG_C, "BPU_CTR3", MSR_P4_BPU_PERFCTR3), ++/* pmd11 */ PMD_D(PFM_REG_C, "MS_CTR2", MSR_P4_MS_PERFCTR2), ++/* pmd12 */ PMD_D(PFM_REG_C, "MS_CTR3", MSR_P4_MS_PERFCTR3), ++/* pmd13 */ PMD_D(PFM_REG_C, "FLAME_CTR2", MSR_P4_FLAME_PERFCTR2), ++/* pmd14 */ PMD_D(PFM_REG_C, "FLAME_CTR3", MSR_P4_FLAME_PERFCTR3), ++/* pmd15 */ PMD_D(PFM_REG_C, "IQ_CTR2", MSR_P4_IQ_PERFCTR2), ++/* pmd16 */ PMD_D(PFM_REG_C, "IQ_CTR3", MSR_P4_IQ_PERFCTR3), ++/* pmd17 */ PMD_D(PFM_REG_C, "IQ_CTR5", MSR_P4_IQ_PERFCTR5) ++}; ++#define PFM_P4_NUM_PMDS ARRAY_SIZE(pfm_p4_pmd_desc) ++ ++/* ++ * Due to hotplug CPU support, threads may not necessarily ++ * be activated at the time the module is inserted. We need ++ * to check whether they could be activated by looking at ++ * the present CPU (present != online). ++ */ ++static int pfm_p4_probe_pmu(void) ++{ ++ unsigned int i; ++ int ht_enabled; ++ ++ /* ++ * only works on Intel processors ++ */ ++ if (current_cpu_data.x86_vendor != X86_VENDOR_INTEL) { ++ PFM_INFO("not running on Intel processor"); ++ return -1; ++ } ++ ++ if (current_cpu_data.x86 != 15) { ++ PFM_INFO("unsupported family=%d", current_cpu_data.x86); ++ return -1; ++ } ++ ++ switch (current_cpu_data.x86_model) { ++ case 0 ... 2: ++ break; ++ case 3 ... 6: ++ /* ++ * IQ_ESCR0, IQ_ESCR1 only present on model 1, 2 ++ */ ++ pfm_p4_pmc_desc[16].type = PFM_REG_NA; ++ pfm_p4_pmc_desc[48].type = PFM_REG_NA; ++ break; ++ default: ++ /* ++ * do not know if they all work the same, so reject ++ * for now ++ */ ++ if (!force) { ++ PFM_INFO("unsupported model %d", ++ current_cpu_data.x86_model); ++ return -1; ++ } ++ } ++ ++ /* ++ * check for local APIC (required) ++ */ ++ if (!cpu_has_apic) { ++ PFM_INFO("no local APIC, unsupported"); ++ return -1; ++ } ++#ifdef CONFIG_SMP ++ ht_enabled = (cpus_weight(__get_cpu_var(cpu_core_map)) ++ / current_cpu_data.x86_max_cores) > 1; ++#else ++ ht_enabled = 0; ++#endif ++ if (cpu_has_ht) { ++ ++ PFM_INFO("HyperThreading supported, status %s", ++ ht_enabled ? "on": "off"); ++ /* ++ * disable registers not supporting HT ++ */ ++ if (ht_enabled) { ++ PFM_INFO("disabling half the registers for HT"); ++ for (i = 0; i < PFM_P4_NUM_PMCS; i++) { ++ if (pmc_addrs[(i)].reg_type & PFM_REGT_NOHT) ++ pfm_p4_pmc_desc[i].type = PFM_REG_NA; ++ } ++ for (i = 0; i < PFM_P4_NUM_PMDS; i++) { ++ if (pmd_addrs[(i)].reg_type & PFM_REGT_NOHT) ++ pfm_p4_pmd_desc[i].type = PFM_REG_NA; ++ } ++ } ++ } ++ ++ if (cpu_has_ds) { ++ PFM_INFO("Data Save Area (DS) supported"); ++ ++ if (cpu_has_pebs) { ++ /* ++ * PEBS does not work with HyperThreading enabled ++ */ ++ if (ht_enabled) ++ PFM_INFO("PEBS supported, status off (because of HT)"); ++ else ++ PFM_INFO("PEBS supported, status on"); ++ } ++ } ++ ++ /* ++ * build enable mask ++ */ ++ for (i = 0; i < PFM_P4_NUM_PMCS; i++) { ++ if (pmc_addrs[(i)].reg_type & PFM_REGT_EN) { ++ __set_bit(i, cast_ulp(enable_mask)); ++ max_enable = i + 1; ++ } ++ } ++ ++ if (force_nmi) ++ pfm_p4_pmu_info.flags |= PFM_X86_FL_USE_NMI; ++ return 0; ++} ++static inline int get_smt_id(void) ++{ ++#ifdef CONFIG_SMP ++ int cpu = smp_processor_id(); ++ return (cpu != first_cpu(__get_cpu_var(cpu_sibling_map))); ++#else ++ return 0; ++#endif ++} ++ ++static void __pfm_write_reg_p4(const struct pfm_p4_regmap *xreg, u64 val) ++{ ++ u64 pmi; ++ int smt_id; ++ ++ smt_id = get_smt_id(); ++ /* ++ * HT is only supported by P4-style PMU ++ * ++ * Adjust for T1 if necessary: ++ * ++ * - move the T0_OS/T0_USR bits into T1 slots ++ * - move the OVF_PMI_T0 bits into T1 slot ++ * ++ * The P4/EM64T T1 is cleared by description table. ++ * User only works with T0. ++ */ ++ if (smt_id) { ++ if (xreg->reg_type & PFM_REGT_ESCR) { ++ ++ /* copy T0_USR & T0_OS to T1 */ ++ val |= ((val & 0xc) >> 2); ++ ++ /* clear bits T0_USR & T0_OS */ ++ val &= ~0xc; ++ ++ } else if (xreg->reg_type & PFM_REGT_CCCR) { ++ pmi = (val >> 26) & 0x1; ++ if (pmi) { ++ val &= ~(1UL<<26); ++ val |= 1UL<<27; ++ } ++ } ++ } ++ if (xreg->addrs[smt_id]) ++ wrmsrl(xreg->addrs[smt_id], val); ++} ++ ++void __pfm_read_reg_p4(const struct pfm_p4_regmap *xreg, u64 *val) ++{ ++ int smt_id; ++ ++ smt_id = get_smt_id(); ++ ++ if (likely(xreg->addrs[smt_id])) { ++ rdmsrl(xreg->addrs[smt_id], *val); ++ /* ++ * HT is only supported by P4-style PMU ++ * ++ * move the Tx_OS and Tx_USR bits into ++ * T0 slots setting the T1 slots to zero ++ */ ++ if (xreg->reg_type & PFM_REGT_ESCR) { ++ if (smt_id) ++ *val |= (((*val) & 0x3) << 2); ++ ++ /* ++ * zero out bits that are reserved ++ * (including T1_OS and T1_USR) ++ */ ++ *val &= PFM_ESCR_RSVD; ++ } ++ } else { ++ *val = 0; ++ } ++} ++static void pfm_p4_write_pmc(struct pfm_context *ctx, unsigned int cnum, u64 value) ++{ ++ __pfm_write_reg_p4(&pmc_addrs[cnum], value); ++} ++ ++static void pfm_p4_write_pmd(struct pfm_context *ctx, unsigned int cnum, u64 value) ++{ ++ __pfm_write_reg_p4(&pmd_addrs[cnum], value); ++} ++ ++static u64 pfm_p4_read_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ u64 tmp; ++ __pfm_read_reg_p4(&pmd_addrs[cnum], &tmp); ++ return tmp; ++} ++ ++static u64 pfm_p4_read_pmc(struct pfm_context *ctx, unsigned int cnum) ++{ ++ u64 tmp; ++ __pfm_read_reg_p4(&pmc_addrs[cnum], &tmp); ++ return tmp; ++} ++ ++struct pfm_ds_area_p4 { ++ unsigned long bts_buf_base; ++ unsigned long bts_index; ++ unsigned long bts_abs_max; ++ unsigned long bts_intr_thres; ++ unsigned long pebs_buf_base; ++ unsigned long pebs_index; ++ unsigned long pebs_abs_max; ++ unsigned long pebs_intr_thres; ++ u64 pebs_cnt_reset; ++}; ++ ++ ++static int pfm_p4_stop_save(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_ds_area_p4 *ds = NULL; ++ u64 used_mask[PFM_PMC_BV]; ++ u16 i, j, count, pebs_idx = ~0; ++ u16 max_pmc; ++ u64 cccr, ctr1, ctr2, ovfl_mask; ++ ++ pmu_info = &pfm_p4_pmu_info; ++ ctx_arch = pfm_ctx_arch(ctx); ++ max_pmc = ctx->regs.max_pmc; ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ ++ /* ++ * build used enable PMC bitmask ++ * if user did not set any CCCR, then mask is ++ * empty and there is nothing to do because nothing ++ * was started ++ */ ++ bitmap_and(cast_ulp(used_mask), ++ cast_ulp(set->used_pmcs), ++ cast_ulp(enable_mask), ++ max_enable); ++ ++ count = bitmap_weight(cast_ulp(used_mask), max_enable); ++ ++ PFM_DBG_ovfl("npend=%u ena_mask=0x%llx u_pmcs=0x%llx count=%u num=%u", ++ set->npend_ovfls, ++ (unsigned long long)enable_mask[0], ++ (unsigned long long)set->used_pmcs[0], ++ count, max_enable); ++ ++ /* ++ * ensures we do not destroy pending overflow ++ * information. If pended interrupts are already ++ * known, then we just stop monitoring. ++ */ ++ if (set->npend_ovfls) { ++ /* ++ * clear enable bit ++ * unfortunately, this is very expensive! ++ */ ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(used_mask))) { ++ __pfm_write_reg_p4(pmc_addrs+i, 0); ++ count--; ++ } ++ } ++ /* need save PMDs at upper level */ ++ return 1; ++ } ++ ++ if (ctx_arch->flags.use_pebs) { ++ ds = ctx_arch->ds_area; ++ pebs_idx = PEBS_PMD; ++ PFM_DBG("ds=%p pebs_idx=0x%llx thres=0x%llx", ++ ds, ++ (unsigned long long)ds->pebs_index, ++ (unsigned long long)ds->pebs_intr_thres); ++ } ++ ++ /* ++ * stop monitoring AND collect pending overflow information AND ++ * save pmds. ++ * ++ * We need to access the CCCR twice, once to get overflow info ++ * and a second to stop monitoring (which destroys the OVF flag) ++ * Similarly, we need to read the counter twice to check whether ++ * it did overflow between the CCR read and the CCCR write. ++ */ ++ for (i = 0; count; i++) { ++ if (i != pebs_idx && test_bit(i, cast_ulp(used_mask))) { ++ /* ++ * controlled counter ++ */ ++ j = pmc_addrs[i].ctr; ++ ++ /* read CCCR (PMC) value */ ++ __pfm_read_reg_p4(pmc_addrs+i, &cccr); ++ ++ /* read counter (PMD) controlled by PMC */ ++ __pfm_read_reg_p4(pmd_addrs+j, &ctr1); ++ ++ /* clear CCCR value: stop counter but destroy OVF */ ++ __pfm_write_reg_p4(pmc_addrs+i, 0); ++ ++ /* read counter controlled by CCCR again */ ++ __pfm_read_reg_p4(pmd_addrs+j, &ctr2); ++ ++ /* ++ * there is an overflow if either: ++ * - CCCR.ovf is set (and we just cleared it) ++ * - ctr2 < ctr1 ++ * in that case we set the bit corresponding to the ++ * overflowed PMD in povfl_pmds. ++ */ ++ if ((cccr & (1ULL<<31)) || (ctr2 < ctr1)) { ++ __set_bit(j, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ ctr2 = (set->pmds[j].value & ~ovfl_mask) | (ctr2 & ovfl_mask); ++ set->pmds[j].value = ctr2; ++ count--; ++ } ++ } ++ /* ++ * check for PEBS buffer full and set the corresponding PMD overflow ++ */ ++ if (ctx_arch->flags.use_pebs) { ++ PFM_DBG("ds=%p pebs_idx=0x%lx thres=0x%lx", ds, ds->pebs_index, ds->pebs_intr_thres); ++ if (ds->pebs_index >= ds->pebs_intr_thres ++ && test_bit(PEBS_PMD, cast_ulp(set->used_pmds))) { ++ __set_bit(PEBS_PMD, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ } ++ /* 0 means: no need to save the PMD at higher level */ ++ return 0; ++} ++ ++static int pfm_p4_create_context(struct pfm_context *ctx, u32 ctx_flags) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ ++ ctx_arch->data = kzalloc(sizeof(struct pfm_arch_p4_context), GFP_KERNEL); ++ if (!ctx_arch->data) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void pfm_p4_free_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ /* ++ * we do not check if P4, because it would be NULL and ++ * kfree can deal with NULL ++ */ ++ kfree(ctx_arch->data); ++} ++ ++/* ++ * detect is counters have overflowed. ++ * return: ++ * 0 : no overflow ++ * 1 : at least one overflow ++ * ++ * used by Intel P4 ++ */ ++static int __kprobes pfm_p4_has_ovfls(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_p4_regmap *xrc, *xrd; ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_arch_p4_context *p4; ++ u64 ena_mask[PFM_PMC_BV]; ++ u64 cccr, ctr1, ctr2; ++ int n, i, j; ++ ++ pmu_info = &pfm_p4_pmu_info; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ xrc = pmc_addrs; ++ xrd = pmd_addrs; ++ p4 = ctx_arch->data; ++ ++ bitmap_and(cast_ulp(ena_mask), ++ cast_ulp(ctx->regs.pmcs), ++ cast_ulp(enable_mask), ++ max_enable); ++ ++ n = bitmap_weight(cast_ulp(ena_mask), max_enable); ++ ++ for (i = 0; n; i++) { ++ if (!test_bit(i, cast_ulp(ena_mask))) ++ continue; ++ /* ++ * controlled counter ++ */ ++ j = xrc[i].ctr; ++ ++ /* read CCCR (PMC) value */ ++ __pfm_read_reg_p4(xrc+i, &cccr); ++ ++ /* read counter (PMD) controlled by PMC */ ++ __pfm_read_reg_p4(xrd+j, &ctr1); ++ ++ /* clear CCCR value: stop counter but destroy OVF */ ++ __pfm_write_reg_p4(xrc+i, 0); ++ ++ /* read counter controlled by CCCR again */ ++ __pfm_read_reg_p4(xrd+j, &ctr2); ++ ++ /* ++ * there is an overflow if either: ++ * - CCCR.ovf is set (and we just cleared it) ++ * - ctr2 < ctr1 ++ * in that case we set the bit corresponding to the ++ * overflowed PMD in povfl_pmds. ++ */ ++ if ((cccr & (1ULL<<31)) || (ctr2 < ctr1)) { ++ __set_bit(j, cast_ulp(p4->povfl_pmds)); ++ p4->npend_ovfls++; ++ } ++ p4->saved_cccrs[i] = cccr; ++ n--; ++ } ++ /* ++ * if there was no overflow, then it means the NMI was not really ++ * for us, so we have to resume monitoring ++ */ ++ if (unlikely(!p4->npend_ovfls)) { ++ for (i = 0; n; i++) { ++ if (!test_bit(i, cast_ulp(ena_mask))) ++ continue; ++ __pfm_write_reg_p4(xrc+i, p4->saved_cccrs[i]); ++ } ++ } ++ return 0; ++} ++ ++void pfm_p4_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_arch_context *ctx_arch; ++ u64 *mask; ++ u16 i, num; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * must restore DS pointer before restoring PMCs ++ * as this can potentially reactivate monitoring ++ */ ++ if (ctx_arch->flags.use_ds) ++ wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ctx_arch->ds_area); ++ ++ /* ++ * must restore everything because there are some dependencies ++ * (e.g., ESCR and CCCR) ++ */ ++ num = ctx->regs.num_pmcs; ++ mask = ctx->regs.pmcs; ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(mask))) { ++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]); ++ num--; ++ } ++ } ++} ++ ++/* ++ * invoked only when NMI is used. Called from the LOCAL_PERFMON_VECTOR ++ * handler to copy P4 overflow state captured when the NMI triggered. ++ * Given that on P4, stopping monitoring destroy the overflow information ++ * we save it in pfm_has_ovfl_p4() where monitoring is also stopped. ++ * ++ * Here we propagate the overflow state to current active set. The ++ * freeze_pmu() call we not overwrite this state because npend_ovfls ++ * is non-zero. ++ */ ++static void pfm_p4_nmi_copy_state(struct pfm_context *ctx) ++{ ++ struct pfm_arch_context *ctx_arch; ++ struct pfm_event_set *set; ++ struct pfm_arch_p4_context *p4; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ p4 = ctx_arch->data; ++ set = ctx->active_set; ++ ++ if (p4->npend_ovfls) { ++ set->npend_ovfls = p4->npend_ovfls; ++ ++ bitmap_copy(cast_ulp(set->povfl_pmds), ++ cast_ulp(p4->povfl_pmds), ++ ctx->regs.max_pmd); ++ ++ p4->npend_ovfls = 0; ++ } ++} ++ ++/** ++ * pfm_p4_quiesce - stop monitoring without grabbing any lock ++ * ++ * called from NMI interrupt handler to immediately stop monitoring ++ * cannot grab any lock, including perfmon related locks ++ */ ++static void __kprobes pfm_p4_quiesce(void) ++{ ++ u16 i; ++ /* ++ * quiesce PMU by clearing available registers that have ++ * the start/stop capability ++ */ ++ for (i = 0; i < pfm_pmu_conf->regs_all.max_pmc; i++) { ++ if (test_bit(i, cast_ulp(pfm_pmu_conf->regs_all.pmcs)) ++ && test_bit(i, cast_ulp(enable_mask))) ++ __pfm_write_reg_p4(pmc_addrs+i, 0); ++ } ++} ++ ++ ++static struct pfm_pmu_config pfm_p4_pmu_conf = { ++ .pmu_name = "Intel P4", ++ .counter_width = 40, ++ .pmd_desc = pfm_p4_pmd_desc, ++ .pmc_desc = pfm_p4_pmc_desc, ++ .num_pmc_entries = PFM_P4_NUM_PMCS, ++ .num_pmd_entries = PFM_P4_NUM_PMDS, ++ .probe_pmu = pfm_p4_probe_pmu, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_p4_pmu_info ++}; ++ ++static int __init pfm_p4_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_p4_pmu_conf); ++} ++ ++static void __exit pfm_p4_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_p4_pmu_conf); ++} ++ ++module_init(pfm_p4_pmu_init_module); ++module_exit(pfm_p4_pmu_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_p6.c +@@ -0,0 +1,310 @@ ++/* ++ * This file contains the P6 family processor PMU register description tables ++ * ++ * This module supports original P6 processors ++ * (Pentium II, Pentium Pro, Pentium III) and Pentium M. ++ * ++ * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("P6 PMU description table"); ++MODULE_LICENSE("GPL"); ++ ++static int force_nmi; ++MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt"); ++module_param(force_nmi, bool, 0600); ++ ++/* ++ * - upper 32 bits are reserved ++ * - INT: APIC enable bit is reserved (forced to 1) ++ * - bit 21 is reserved ++ * - bit 22 is reserved on PEREVNTSEL1 ++ * ++ * RSVD: reserved bits are 1 ++ */ ++#define PFM_P6_PMC0_RSVD ((~((1ULL<<32)-1)) | (1ULL<<20) | (1ULL<<21)) ++#define PFM_P6_PMC1_RSVD ((~((1ULL<<32)-1)) | (1ULL<<20) | (3ULL<<21)) ++ ++/* ++ * force Local APIC interrupt on overflow ++ * disable with NO_EMUL64 ++ */ ++#define PFM_P6_PMC_VAL (1ULL<<20) ++#define PFM_P6_NO64 (1ULL<<20) ++ ++ ++static void __kprobes pfm_p6_quiesce(void); ++static int pfm_p6_has_ovfls(struct pfm_context *ctx); ++static int pfm_p6_stop_save(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ ++static u64 enable_mask[PFM_MAX_PMCS]; ++static u16 max_enable; ++ ++/* ++ * PFM_X86_FL_NO_SHARING: because of the single enable bit on MSR_P6_EVNTSEL0 ++ * the PMU cannot be shared with NMI watchdog or Oprofile ++ */ ++struct pfm_arch_pmu_info pfm_p6_pmu_info = { ++ .stop_save = pfm_p6_stop_save, ++ .has_ovfls = pfm_p6_has_ovfls, ++ .quiesce = pfm_p6_quiesce, ++ .flags = PFM_X86_FL_NO_SHARING, ++}; ++ ++static struct pfm_regmap_desc pfm_p6_pmc_desc[] = { ++/* pmc0 */ PMC_D(PFM_REG_I64, "PERFEVTSEL0", PFM_P6_PMC_VAL, PFM_P6_PMC0_RSVD, PFM_P6_NO64, MSR_P6_EVNTSEL0), ++/* pmc1 */ PMC_D(PFM_REG_I64, "PERFEVTSEL1", PFM_P6_PMC_VAL, PFM_P6_PMC1_RSVD, PFM_P6_NO64, MSR_P6_EVNTSEL1) ++}; ++#define PFM_P6_NUM_PMCS ARRAY_SIZE(pfm_p6_pmc_desc) ++ ++#define PFM_P6_D(n) \ ++ { .type = PFM_REG_C, \ ++ .desc = "PERFCTR"#n, \ ++ .hw_addr = MSR_P6_PERFCTR0+n, \ ++ .rsvd_msk = 0, \ ++ .dep_pmcs[0] = 1ULL << n \ ++ } ++ ++static struct pfm_regmap_desc pfm_p6_pmd_desc[] = { ++/* pmd0 */ PFM_P6_D(0), ++/* pmd1 */ PFM_P6_D(1) ++}; ++#define PFM_P6_NUM_PMDS ARRAY_SIZE(pfm_p6_pmd_desc) ++ ++static int pfm_p6_probe_pmu(void) ++{ ++ int high, low; ++ ++ if (current_cpu_data.x86_vendor != X86_VENDOR_INTEL) { ++ PFM_INFO("not an Intel processor"); ++ return -1; ++ } ++ ++ /* ++ * check for P6 processor family ++ */ ++ if (current_cpu_data.x86 != 6) { ++ PFM_INFO("unsupported family=%d", current_cpu_data.x86); ++ return -1; ++ } ++ ++ switch (current_cpu_data.x86_model) { ++ case 1: /* Pentium Pro */ ++ case 3: ++ case 5: /* Pentium II Deschutes */ ++ case 7 ... 11: ++ break; ++ case 13: ++ /* for Pentium M, we need to check if PMU exist */ ++ rdmsr(MSR_IA32_MISC_ENABLE, low, high); ++ if (low & (1U << 7)) ++ break; ++ default: ++ PFM_INFO("unsupported CPU model %d", ++ current_cpu_data.x86_model); ++ return -1; ++ ++ } ++ ++ if (!cpu_has_apic) { ++ PFM_INFO("no Local APIC, try rebooting with lapic"); ++ return -1; ++ } ++ __set_bit(0, cast_ulp(enable_mask)); ++ __set_bit(1, cast_ulp(enable_mask)); ++ max_enable = 1 + 1; ++ /* ++ * force NMI interrupt? ++ */ ++ if (force_nmi) ++ pfm_p6_pmu_info.flags |= PFM_X86_FL_USE_NMI; ++ ++ return 0; ++} ++ ++/** ++ * pfm_p6_has_ovfls - check for pending overflow condition ++ * @ctx: context to work on ++ * ++ * detect if counters have overflowed. ++ * return: ++ * 0 : no overflow ++ * 1 : at least one overflow ++ */ ++static int __kprobes pfm_p6_has_ovfls(struct pfm_context *ctx) ++{ ++ u64 *cnt_mask; ++ u64 wmask, val; ++ u16 i, num; ++ ++ cnt_mask = ctx->regs.cnt_pmds; ++ num = ctx->regs.num_counters; ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ ++ /* ++ * we can leverage the fact that we know the mapping ++ * to hardcode the MSR address and avoid accessing ++ * more cachelines ++ * ++ * We need to check cnt_mask because not all registers ++ * may be available. ++ */ ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(cnt_mask))) { ++ rdmsrl(MSR_P6_PERFCTR0+i, val); ++ if (!(val & wmask)) ++ return 1; ++ num--; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * pfm_p6_stop_save -- stop monitoring and save PMD values ++ * @ctx: context to work on ++ * @set: current event set ++ * ++ * return value: ++ * 0 - no need to save PMDs in caller ++ * 1 - need to save PMDs in caller ++ */ ++static int pfm_p6_stop_save(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u64 used_mask[PFM_PMC_BV]; ++ u64 *cnt_pmds; ++ u64 val, wmask, ovfl_mask; ++ u32 i, count; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ wmask = 1ULL << pfm_pmu_conf->counter_width; ++ bitmap_and(cast_ulp(used_mask), ++ cast_ulp(set->used_pmcs), ++ cast_ulp(enable_mask), ++ max_enable); ++ ++ count = bitmap_weight(cast_ulp(used_mask), ctx->regs.max_pmc); ++ ++ /* ++ * stop monitoring ++ * Unfortunately, this is very expensive! ++ * wrmsrl() is serializing. ++ */ ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(used_mask))) { ++ wrmsrl(MSR_P6_EVNTSEL0+i, 0); ++ count--; ++ } ++ } ++ ++ /* ++ * if we already having a pending overflow condition, we simply ++ * return to take care of this first. ++ */ ++ if (set->npend_ovfls) ++ return 1; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ cnt_pmds = ctx->regs.cnt_pmds; ++ ++ /* ++ * check for pending overflows and save PMDs (combo) ++ * we employ used_pmds because we also need to save ++ * and not just check for pending interrupts. ++ * ++ * Must check for counting PMDs because of virtual PMDs ++ */ ++ count = set->nused_pmds; ++ for (i = 0; count; i++) { ++ if (test_bit(i, cast_ulp(set->used_pmds))) { ++ val = pfm_arch_read_pmd(ctx, i); ++ if (likely(test_bit(i, cast_ulp(cnt_pmds)))) { ++ if (!(val & wmask)) { ++ __set_bit(i, cast_ulp(set->povfl_pmds)); ++ set->npend_ovfls++; ++ } ++ val = (set->pmds[i].value & ~ovfl_mask) | (val & ovfl_mask); ++ } ++ set->pmds[i].value = val; ++ count--; ++ } ++ } ++ /* 0 means: no need to save PMDs at upper level */ ++ return 0; ++} ++ ++/** ++ * pfm_p6_quiesce_pmu -- stop monitoring without grabbing any lock ++ * ++ * called from NMI interrupt handler to immediately stop monitoring ++ * cannot grab any lock, including perfmon related locks ++ */ ++static void __kprobes pfm_p6_quiesce(void) ++{ ++ /* ++ * quiesce PMU by clearing available registers that have ++ * the start/stop capability ++ * ++ * P6 processors only have enable bit on PERFEVTSEL0 ++ */ ++ if (test_bit(0, cast_ulp(pfm_pmu_conf->regs_all.pmcs))) ++ wrmsrl(MSR_P6_EVNTSEL0, 0); ++} ++ ++/* ++ * Counters have 40 bits implemented. However they are designed such ++ * that bits [32-39] are sign extensions of bit 31. As such the ++ * effective width of a counter for P6-like PMU is 31 bits only. ++ * ++ * See IA-32 Intel Architecture Software developer manual Vol 3B ++ */ ++static struct pfm_pmu_config pfm_p6_pmu_conf = { ++ .pmu_name = "Intel P6 processor Family", ++ .counter_width = 31, ++ .pmd_desc = pfm_p6_pmd_desc, ++ .pmc_desc = pfm_p6_pmc_desc, ++ .num_pmc_entries = PFM_P6_NUM_PMCS, ++ .num_pmd_entries = PFM_P6_NUM_PMDS, ++ .probe_pmu = pfm_p6_probe_pmu, ++ .version = "1.0", ++ .flags = PFM_PMU_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++ .pmu_info = &pfm_p6_pmu_info ++}; ++ ++static int __init pfm_p6_pmu_init_module(void) ++{ ++ return pfm_pmu_register(&pfm_p6_pmu_conf); ++} ++ ++static void __exit pfm_p6_pmu_cleanup_module(void) ++{ ++ pfm_pmu_unregister(&pfm_p6_pmu_conf); ++} ++ ++module_init(pfm_p6_pmu_init_module); ++module_exit(pfm_p6_pmu_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_pebs_core_smpl.c +@@ -0,0 +1,256 @@ ++/* ++ * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file implements the Precise Event Based Sampling (PEBS) ++ * sampling format for Intel Core and Atom processors. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Intel Core Precise Event-Based Sampling (PEBS)"); ++MODULE_LICENSE("GPL"); ++ ++#define ALIGN_PEBS(a, order) \ ++ ((a)+(1UL<<(order))-1) & ~((1UL<<(order))-1) ++ ++#define PEBS_PADDING_ORDER 8 /* log2(256) padding for PEBS alignment constraint */ ++ ++static int pfm_pebs_core_fmt_validate(u32 flags, u16 npmds, void *data) ++{ ++ struct pfm_pebs_core_smpl_arg *arg = data; ++ size_t min_buf_size; ++ ++ /* ++ * need to define at least the size of the buffer ++ */ ++ if (data == NULL) { ++ PFM_DBG("no argument passed"); ++ return -EINVAL; ++ } ++ ++ /* ++ * compute min buf size. npmds is the maximum number ++ * of implemented PMD registers. ++ */ ++ min_buf_size = sizeof(struct pfm_pebs_core_smpl_hdr) ++ + sizeof(struct pfm_pebs_core_smpl_entry) ++ + (1UL<buf_size); ++ ++ /* ++ * must hold at least the buffer header + one minimally sized entry ++ */ ++ if (arg->buf_size < min_buf_size) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int pfm_pebs_core_fmt_get_size(unsigned int flags, void *data, size_t *size) ++{ ++ struct pfm_pebs_core_smpl_arg *arg = data; ++ ++ /* ++ * size has been validated in pfm_pebs_core_fmt_validate() ++ */ ++ *size = arg->buf_size + (1UL<ds; ++ ++ /* ++ * align PEBS buffer base ++ */ ++ pebs_start = ALIGN_PEBS((unsigned long)(hdr+1), PEBS_PADDING_ORDER); ++ pebs_end = pebs_start + arg->buf_size + 1; ++ ++ hdr->version = PFM_PEBS_CORE_SMPL_VERSION; ++ hdr->buf_size = arg->buf_size; ++ hdr->overflows = 0; ++ ++ /* ++ * express PEBS buffer base as offset from the end of the header ++ */ ++ hdr->start_offs = pebs_start - (unsigned long)(hdr+1); ++ ++ /* ++ * PEBS buffer boundaries ++ */ ++ ds->pebs_buf_base = pebs_start; ++ ds->pebs_abs_max = pebs_end; ++ ++ /* ++ * PEBS starting position ++ */ ++ ds->pebs_index = pebs_start; ++ ++ /* ++ * PEBS interrupt threshold ++ */ ++ ds->pebs_intr_thres = pebs_start ++ + arg->intr_thres ++ * sizeof(struct pfm_pebs_core_smpl_entry); ++ ++ /* ++ * save counter reset value for PEBS counter ++ */ ++ ds->pebs_cnt_reset = arg->cnt_reset; ++ ++ /* ++ * keep track of DS AREA ++ */ ++ ctx_arch->ds_area = ds; ++ ctx_arch->flags.use_ds = 1; ++ ctx_arch->flags.use_pebs = 1; ++ ++ PFM_DBG("buffer=%p buf_size=%llu offs=%llu pebs_start=0x%llx " ++ "pebs_end=0x%llx ds=%p pebs_thres=0x%llx cnt_reset=0x%llx", ++ buf, ++ (unsigned long long)hdr->buf_size, ++ (unsigned long long)hdr->start_offs, ++ (unsigned long long)pebs_start, ++ (unsigned long long)pebs_end, ++ ds, ++ (unsigned long long)ds->pebs_intr_thres, ++ (unsigned long long)ds->pebs_cnt_reset); ++ ++ return 0; ++} ++ ++static int pfm_pebs_core_fmt_handler(struct pfm_context *ctx, ++ unsigned long ip, u64 tstamp, void *data) ++{ ++ struct pfm_pebs_core_smpl_hdr *hdr; ++ struct pfm_ovfl_arg *arg; ++ ++ hdr = ctx->smpl_addr; ++ arg = &ctx->ovfl_arg; ++ ++ PFM_DBG_ovfl("buffer full"); ++ /* ++ * increment number of buffer overflows. ++ * important to detect duplicate set of samples. ++ */ ++ hdr->overflows++; ++ ++ /* ++ * request notification and masking of monitoring. ++ * Notification is still subject to the overflowed ++ * register having the FL_NOTIFY flag set. ++ */ ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_NOTIFY | PFM_OVFL_CTRL_MASK; ++ ++ return -ENOBUFS; /* we are full, sorry */ ++} ++ ++static int pfm_pebs_core_fmt_restart(int is_active, u32 *ovfl_ctrl, ++ void *buf) ++{ ++ struct pfm_pebs_core_smpl_hdr *hdr = buf; ++ ++ /* ++ * reset index to base of buffer ++ */ ++ hdr->ds.pebs_index = hdr->ds.pebs_buf_base; ++ ++ *ovfl_ctrl = PFM_OVFL_CTRL_RESET; ++ ++ return 0; ++} ++ ++static int pfm_pebs_core_fmt_exit(void *buf) ++{ ++ return 0; ++} ++ ++static struct pfm_smpl_fmt pebs_core_fmt = { ++ .fmt_name = PFM_PEBS_CORE_SMPL_NAME, ++ .fmt_version = 0x1, ++ .fmt_arg_size = sizeof(struct pfm_pebs_core_smpl_arg), ++ .fmt_validate = pfm_pebs_core_fmt_validate, ++ .fmt_getsize = pfm_pebs_core_fmt_get_size, ++ .fmt_init = pfm_pebs_core_fmt_init, ++ .fmt_handler = pfm_pebs_core_fmt_handler, ++ .fmt_restart = pfm_pebs_core_fmt_restart, ++ .fmt_exit = pfm_pebs_core_fmt_exit, ++ .fmt_flags = PFM_FMT_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init pfm_pebs_core_fmt_init_module(void) ++{ ++ if (!cpu_has_pebs) { ++ PFM_INFO("processor does not have PEBS support"); ++ return -1; ++ } ++ /* ++ * cpu_has_pebs is not enough to identify Intel Core PEBS ++ * which is different fro Pentium 4 PEBS. Therefore we do ++ * a more detailed check here ++ */ ++ if (current_cpu_data.x86 != 6) { ++ PFM_INFO("not a supported Intel processor"); ++ return -1; ++ } ++ ++ switch (current_cpu_data.x86_model) { ++ case 15: /* Merom */ ++ case 23: /* Penryn */ ++ case 28: /* Atom (Silverthorne) */ ++ case 29: /* Dunnington */ ++ break; ++ default: ++ PFM_INFO("not a supported Intel processor"); ++ return -1; ++ } ++ return pfm_fmt_register(&pebs_core_fmt); ++} ++ ++static void __exit pfm_pebs_core_fmt_cleanup_module(void) ++{ ++ pfm_fmt_unregister(&pebs_core_fmt); ++} ++ ++module_init(pfm_pebs_core_fmt_init_module); ++module_exit(pfm_pebs_core_fmt_cleanup_module); +--- /dev/null ++++ b/arch/x86/perfmon/perfmon_pebs_p4_smpl.c +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file implements the Precise Event Based Sampling (PEBS) ++ * sampling format. It supports the following processors: ++ * - 32-bit Pentium 4 or other Netburst-based processors ++ * - 64-bit Pentium 4 or other Netburst-based processors ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("Intel P4 Precise Event-Based Sampling (PEBS)"); ++MODULE_LICENSE("GPL"); ++ ++#define ALIGN_PEBS(a, order) \ ++ ((a)+(1UL<<(order))-1) & ~((1UL<<(order))-1) ++ ++#define PEBS_PADDING_ORDER 8 /* log2(256) padding for PEBS alignment constraint */ ++ ++static int pfm_pebs_p4_fmt_validate(u32 flags, u16 npmds, void *data) ++{ ++ struct pfm_pebs_p4_smpl_arg *arg = data; ++ size_t min_buf_size; ++ ++ /* ++ * need to define at least the size of the buffer ++ */ ++ if (data == NULL) { ++ PFM_DBG("no argument passed"); ++ return -EINVAL; ++ } ++ ++ /* ++ * compute min buf size. npmds is the maximum number ++ * of implemented PMD registers. ++ */ ++ min_buf_size = sizeof(struct pfm_pebs_p4_smpl_hdr) ++ + sizeof(struct pfm_pebs_p4_smpl_entry) ++ + (1UL<buf_size); ++ ++ /* ++ * must hold at least the buffer header + one minimally sized entry ++ */ ++ if (arg->buf_size < min_buf_size) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int pfm_pebs_p4_fmt_get_size(unsigned int flags, void *data, size_t *size) ++{ ++ struct pfm_pebs_p4_smpl_arg *arg = data; ++ ++ /* ++ * size has been validated in pfm_pebs_p4_fmt_validate() ++ */ ++ *size = arg->buf_size + (1UL<ds; ++ ++ /* ++ * align PEBS buffer base ++ */ ++ pebs_start = ALIGN_PEBS((unsigned long)(hdr+1), PEBS_PADDING_ORDER); ++ pebs_end = pebs_start + arg->buf_size + 1; ++ ++ hdr->version = PFM_PEBS_P4_SMPL_VERSION; ++ hdr->buf_size = arg->buf_size; ++ hdr->overflows = 0; ++ ++ /* ++ * express PEBS buffer base as offset from the end of the header ++ */ ++ hdr->start_offs = pebs_start - (unsigned long)(hdr+1); ++ ++ /* ++ * PEBS buffer boundaries ++ */ ++ ds->pebs_buf_base = pebs_start; ++ ds->pebs_abs_max = pebs_end; ++ ++ /* ++ * PEBS starting position ++ */ ++ ds->pebs_index = pebs_start; ++ ++ /* ++ * PEBS interrupt threshold ++ */ ++ ds->pebs_intr_thres = pebs_start ++ + arg->intr_thres * sizeof(struct pfm_pebs_p4_smpl_entry); ++ ++ /* ++ * save counter reset value for PEBS counter ++ */ ++ ds->pebs_cnt_reset = arg->cnt_reset; ++ ++ /* ++ * keep track of DS AREA ++ */ ++ ctx_arch->ds_area = ds; ++ ctx_arch->flags.use_pebs = 1; ++ ctx_arch->flags.use_ds = 1; ++ ++ PFM_DBG("buffer=%p buf_size=%llu offs=%llu pebs_start=0x%lx " ++ "pebs_end=0x%lx ds=%p pebs_thres=0x%lx cnt_reset=0x%llx", ++ buf, ++ (unsigned long long)hdr->buf_size, ++ (unsigned long long)hdr->start_offs, ++ pebs_start, ++ pebs_end, ++ ds, ++ ds->pebs_intr_thres, ++ (unsigned long long)ds->pebs_cnt_reset); ++ ++ return 0; ++} ++ ++static int pfm_pebs_p4_fmt_handler(struct pfm_context *ctx, ++ unsigned long ip, u64 tstamp, void *data) ++{ ++ struct pfm_pebs_p4_smpl_hdr *hdr; ++ struct pfm_ovfl_arg *arg; ++ ++ hdr = ctx->smpl_addr; ++ arg = &ctx->ovfl_arg; ++ ++ PFM_DBG_ovfl("buffer full"); ++ /* ++ * increment number of buffer overflows. ++ * important to detect duplicate set of samples. ++ */ ++ hdr->overflows++; ++ ++ /* ++ * request notification and masking of monitoring. ++ * Notification is still subject to the overflowed ++ * register having the FL_NOTIFY flag set. ++ */ ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_NOTIFY | PFM_OVFL_CTRL_MASK; ++ ++ return -ENOBUFS; /* we are full, sorry */ ++} ++ ++static int pfm_pebs_p4_fmt_restart(int is_active, u32 *ovfl_ctrl, ++ void *buf) ++{ ++ struct pfm_pebs_p4_smpl_hdr *hdr = buf; ++ ++ /* ++ * reset index to base of buffer ++ */ ++ hdr->ds.pebs_index = hdr->ds.pebs_buf_base; ++ ++ *ovfl_ctrl = PFM_OVFL_CTRL_RESET; ++ ++ return 0; ++} ++ ++static int pfm_pebs_p4_fmt_exit(void *buf) ++{ ++ return 0; ++} ++ ++static struct pfm_smpl_fmt pebs_p4_fmt = { ++ .fmt_name = PFM_PEBS_P4_SMPL_NAME, ++ .fmt_version = 0x1, ++ .fmt_arg_size = sizeof(struct pfm_pebs_p4_smpl_arg), ++ .fmt_validate = pfm_pebs_p4_fmt_validate, ++ .fmt_getsize = pfm_pebs_p4_fmt_get_size, ++ .fmt_init = pfm_pebs_p4_fmt_init, ++ .fmt_handler = pfm_pebs_p4_fmt_handler, ++ .fmt_restart = pfm_pebs_p4_fmt_restart, ++ .fmt_exit = pfm_pebs_p4_fmt_exit, ++ .fmt_flags = PFM_FMT_BUILTIN_FLAG, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init pfm_pebs_p4_fmt_init_module(void) ++{ ++ int ht_enabled; ++ ++ if (!cpu_has_pebs) { ++ PFM_INFO("processor does not have PEBS support"); ++ return -1; ++ } ++ if (current_cpu_data.x86 != 15) { ++ PFM_INFO("not an Intel Pentium 4"); ++ return -1; ++ } ++#ifdef CONFIG_SMP ++ ht_enabled = (cpus_weight(__get_cpu_var(cpu_core_map)) ++ / current_cpu_data.x86_max_cores) > 1; ++#else ++ ht_enabled = 0; ++#endif ++ if (ht_enabled) { ++ PFM_INFO("PEBS not available because HyperThreading is on"); ++ return -1; ++ } ++ return pfm_fmt_register(&pebs_p4_fmt); ++} ++ ++static void __exit pfm_pebs_p4_fmt_cleanup_module(void) ++{ ++ pfm_fmt_unregister(&pebs_p4_fmt); ++} ++ ++module_init(pfm_pebs_p4_fmt_init_module); ++module_exit(pfm_pebs_p4_fmt_cleanup_module); +--- a/include/asm-mips/Kbuild ++++ b/include/asm-mips/Kbuild +@@ -1,3 +1,4 @@ + include include/asm-generic/Kbuild.asm + + header-y += cachectl.h sgidefs.h sysmips.h ++header-y += perfmon.h +--- /dev/null ++++ b/include/asm-mips/perfmon.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file contains mips64 specific definitions for the perfmon ++ * interface. ++ * ++ * This file MUST never be included directly. Use linux/perfmon.h. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_MIPS64_PERFMON_H_ ++#define _ASM_MIPS64_PERFMON_H_ ++ ++/* ++ * arch-specific user visible interface definitions ++ */ ++ ++#define PFM_ARCH_MAX_PMCS (256+64) /* 256 HW 64 SW */ ++#define PFM_ARCH_MAX_PMDS (256+64) /* 256 HW 64 SW */ ++ ++#endif /* _ASM_MIPS64_PERFMON_H_ */ +--- /dev/null ++++ b/include/asm-mips/perfmon_kern.h +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (c) 2005 Philip Mucci. ++ * ++ * Based on other versions: ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file contains mips64 specific definitions for the perfmon ++ * interface. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_MIPS64_PERFMON_KERN_H_ ++#define _ASM_MIPS64_PERFMON_KERN_H_ ++ ++#ifdef __KERNEL__ ++ ++#ifdef CONFIG_PERFMON ++#include ++#include ++ ++#define PFM_ARCH_PMD_STK_ARG 2 ++#define PFM_ARCH_PMC_STK_ARG 2 ++ ++struct pfm_arch_pmu_info { ++ u32 pmu_style; ++}; ++ ++#define MIPS64_CONFIG_PMC_MASK (1 << 4) ++#define MIPS64_PMC_INT_ENABLE_MASK (1 << 4) ++#define MIPS64_PMC_CNT_ENABLE_MASK (0xf) ++#define MIPS64_PMC_EVT_MASK (0x7 << 6) ++#define MIPS64_PMC_CTR_MASK (1 << 31) ++#define MIPS64_PMD_INTERRUPT (1 << 31) ++ ++/* Coprocessor register 25 contains the PMU interface. */ ++/* Sel 0 is control for counter 0 */ ++/* Sel 1 is count for counter 0. */ ++/* Sel 2 is control for counter 1. */ ++/* Sel 3 is count for counter 1. */ ++ ++/* ++ ++31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ++M 0--------------------------------------------------------------0 Event-- IE U S K EXL ++ ++M 31 If this bit is one, another pair of Performance Control ++and Counter registers is implemented at a MTC0 ++ ++Event 8:5 Counter event enabled for this counter. Possible events ++are listed in Table 6-30. R/W Undefined ++ ++IE 4 Counter Interrupt Enable. This bit masks bit 31 of the ++associated count register from the interrupt exception ++request output. R/W 0 ++ ++U 3 Count in User Mode. When this bit is set, the specified ++event is counted in User Mode. R/W Undefined ++ ++S 2 Count in Supervisor Mode. When this bit is set, the ++specified event is counted in Supervisor Mode. R/W Undefined ++ ++K 1 Count in Kernel Mode. When this bit is set, count the ++event in Kernel Mode when EXL and ERL both are 0. R/W Undefined ++ ++EXL 0 Count when EXL. When this bit is set, count the event ++when EXL = 1 and ERL = 0. R/W Undefined ++*/ ++ ++static inline void pfm_arch_resend_irq(struct pfm_context *ctx) ++{} ++ ++static inline void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++static inline void pfm_arch_serialize(void) ++{} ++ ++ ++/* ++ * MIPS does not save the PMDs during pfm_arch_intr_freeze_pmu(), thus ++ * this routine needs to do it when switching sets on overflow ++ */ ++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_save_pmds(ctx, set); ++} ++ ++static inline void pfm_arch_write_pmc(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ /* ++ * we only write to the actual register when monitoring is ++ * active (pfm_start was issued) ++ */ ++ if (ctx && (ctx->flags.started == 0)) ++ return; ++ ++ switch (pfm_pmu_conf->pmc_desc[cnum].hw_addr) { ++ case 0: ++ write_c0_perfctrl0(value); ++ break; ++ case 1: ++ write_c0_perfctrl1(value); ++ break; ++ case 2: ++ write_c0_perfctrl2(value); ++ break; ++ case 3: ++ write_c0_perfctrl3(value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static inline void pfm_arch_write_pmd(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ value &= pfm_pmu_conf->ovfl_mask; ++ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case 0: ++ write_c0_perfcntr0(value); ++ break; ++ case 1: ++ write_c0_perfcntr1(value); ++ break; ++ case 2: ++ write_c0_perfcntr2(value); ++ break; ++ case 3: ++ write_c0_perfcntr3(value); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ switch (pfm_pmu_conf->pmd_desc[cnum].hw_addr) { ++ case 0: ++ return read_c0_perfcntr0(); ++ break; ++ case 1: ++ return read_c0_perfcntr1(); ++ break; ++ case 2: ++ return read_c0_perfcntr2(); ++ break; ++ case 3: ++ return read_c0_perfcntr3(); ++ break; ++ default: ++ BUG(); ++ return 0; ++ } ++} ++ ++static inline u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum) ++{ ++ switch (pfm_pmu_conf->pmc_desc[cnum].hw_addr) { ++ case 0: ++ return read_c0_perfctrl0(); ++ break; ++ case 1: ++ return read_c0_perfctrl1(); ++ break; ++ case 2: ++ return read_c0_perfctrl2(); ++ break; ++ case 3: ++ return read_c0_perfctrl3(); ++ break; ++ default: ++ BUG(); ++ return 0; ++ } ++} ++ ++/* ++ * For some CPUs, the upper bits of a counter must be set in order for the ++ * overflow interrupt to happen. On overflow, the counter has wrapped around, ++ * and the upper bits are cleared. This function may be used to set them back. ++ */ ++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, ++ unsigned int cnum) ++{ ++ u64 val; ++ val = pfm_arch_read_pmd(ctx, cnum); ++ /* This masks out overflow bit 31 */ ++ pfm_arch_write_pmd(ctx, cnum, val); ++} ++ ++/* ++ * At certain points, perfmon needs to know if monitoring has been ++ * explicitely started/stopped by user via pfm_start/pfm_stop. The ++ * information is tracked in ctx.flags.started. However on certain ++ * architectures, it may be possible to start/stop directly from ++ * user level with a single assembly instruction bypassing ++ * the kernel. This function must be used to determine by ++ * an arch-specific mean if monitoring is actually started/stopped. ++ */ ++static inline int pfm_arch_is_active(struct pfm_context *ctx) ++{ ++ return ctx->flags.started; ++} ++ ++static inline void pfm_arch_ctxswout_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++ ++static inline void pfm_arch_ctxswin_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++ ++static inline void pfm_arch_ctxswin_thread(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++int pfm_arch_ctxswout_thread(struct task_struct *task, ++ struct pfm_context *ctx); ++ ++int pfm_arch_is_monitoring_active(struct pfm_context *ctx); ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); ++char *pfm_arch_get_pmu_module_name(void); ++ ++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_arch_stop(current, ctx); ++ /* ++ * we mark monitoring as stopped to avoid ++ * certain side effects especially in ++ * pfm_switch_sets_from_intr() on ++ * pfm_arch_restore_pmcs() ++ */ ++ ctx->flags.started = 0; ++} ++ ++/* ++ * unfreeze PMU from pfm_do_interrupt_handler() ++ * ctx may be NULL for spurious ++ */ ++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx) ++{ ++ if (!ctx) ++ return; ++ ++ PFM_DBG_ovfl("state=%d", ctx->state); ++ ++ ctx->flags.started = 1; ++ ++ if (ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ pfm_arch_restore_pmcs(ctx, ctx->active_set); ++} ++ ++/* ++ * this function is called from the PMU interrupt handler ONLY. ++ * On MIPS, the PMU is frozen via arch_stop, masking would be implemented ++ * via arch-stop as well. Given that the PMU is already stopped when ++ * entering the interrupt handler, we do not need to stop it again, so ++ * this function is a nop. ++ */ ++static inline void pfm_arch_mask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++/* ++ * on MIPS masking/unmasking uses the start/stop mechanism, so we simply ++ * need to start here. ++ */ ++static inline void pfm_arch_unmask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_arch_start(current, ctx); ++} ++ ++static inline int pfm_arch_context_create(struct pfm_context *ctx, ++ u32 ctx_flags) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_context_free(struct pfm_context *ctx) ++{} ++ ++ ++ ++ ++ ++/* ++ * function called from pfm_setfl_sane(). Context is locked ++ * and interrupts are masked. ++ * The value of flags is the value of ctx_flags as passed by ++ * user. ++ * ++ * function must check arch-specific set flags. ++ * Return: ++ * 1 when flags are valid ++ * 0 on error ++ */ ++static inline int ++pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_init(void) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_init_percpu(void) ++{} ++ ++static inline int pfm_arch_load_context(struct pfm_context *ctx) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_unload_context(struct pfm_context *ctx) ++{} ++ ++static inline int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++ return 0; ++} ++ ++static inline void pfm_arch_pmu_release(void) ++{} ++ ++#ifdef CONFIG_PERFMON_FLUSH ++/* ++ * due to cache aliasing problem on MIPS, it is necessary to flush ++ * pages out of the cache when they are modified. ++ */ ++static inline void pfm_cacheflush(void *addr, unsigned int len) ++{ ++ unsigned long start, end; ++ ++ start = (unsigned long)addr & PAGE_MASK; ++ end = ((unsigned long)addr + len + PAGE_SIZE - 1) & PAGE_MASK; ++ ++ while (start < end) { ++ flush_data_cache_page(start); ++ start += PAGE_SIZE; ++ } ++} ++#else ++static inline void pfm_cacheflush(void *addr, unsigned int len) ++{} ++#endif ++ ++static inline void pfm_arch_arm_handle_work(struct task_struct *task) ++{} ++ ++static inline void pfm_arch_disarm_handle_work(struct task_struct *task) ++{} ++ ++static inline int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg) ++{ ++ return 0; ++} ++ ++static inline int pfm_arch_get_base_syscall(void) ++{ ++ if (test_thread_flag(TIF_32BIT_ADDR)) { ++ if (test_thread_flag(TIF_32BIT_REGS)) ++ return __NR_O32_Linux+330; ++ return __NR_N32_Linux+293; ++ } ++ return __NR_64_Linux+289; ++} ++ ++struct pfm_arch_context { ++ /* empty */ ++}; ++ ++#define PFM_ARCH_CTX_SIZE sizeof(struct pfm_arch_context) ++/* ++ * MIPS may need extra alignment requirements for the sampling buffer ++ */ ++#ifdef CONFIG_PERFMON_SMPL_ALIGN ++#define PFM_ARCH_SMPL_ALIGN_SIZE 0x4000 ++#else ++#define PFM_ARCH_SMPL_ALIGN_SIZE 0 ++#endif ++ ++#endif /* CONFIG_PERFMON */ ++ ++#endif /* __KERNEL__ */ ++#endif /* _ASM_MIPS64_PERFMON_KERN_H_ */ +--- a/include/asm-mips/system.h ++++ b/include/asm-mips/system.h +@@ -67,6 +67,10 @@ do { \ + __mips_mt_fpaff_switch_to(prev); \ + if (cpu_has_dsp) \ + __save_dsp(prev); \ ++ if (test_tsk_thread_flag(prev, TIF_PERFMON_CTXSW)) \ ++ pfm_ctxsw_out(prev, next); \ ++ if (test_tsk_thread_flag(next, TIF_PERFMON_CTXSW)) \ ++ pfm_ctxsw_in(prev, next); \ + (last) = resume(prev, next, task_thread_info(next)); \ + } while (0) + +--- a/include/asm-mips/thread_info.h ++++ b/include/asm-mips/thread_info.h +@@ -114,6 +114,7 @@ register struct thread_info *__current_t + #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ + #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ + #define TIF_SECCOMP 4 /* secure computing */ ++#define TIF_PERFMON_WORK 5 /* work for pfm_handle_work() */ + #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ + #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ + #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ +@@ -124,6 +125,7 @@ register struct thread_info *__current_t + #define TIF_32BIT_REGS 22 /* also implies 16/32 fprs */ + #define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */ + #define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */ ++#define TIF_PERFMON_CTXSW 25 /* perfmon needs ctxsw calls */ + #define TIF_SYSCALL_TRACE 31 /* syscall trace active */ + + #define _TIF_SYSCALL_TRACE (1< ++ * ++ * This file contains i386/x86_64 specific definitions for the perfmon ++ * interface. ++ * ++ * This file MUST never be included directly. Use linux/perfmon.h. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_X86_PERFMON__H_ ++#define _ASM_X86_PERFMON__H_ ++ ++/* ++ * arch-specific user visible interface definitions ++ */ ++ ++#define PFM_ARCH_MAX_PMCS (256+64) /* 256 HW 64 SW */ ++#define PFM_ARCH_MAX_PMDS (256+64) /* 256 HW 64 SW */ ++ ++#endif /* _ASM_X86_PERFMON_H_ */ +--- /dev/null ++++ b/include/asm-x86/perfmon_kern.h +@@ -0,0 +1,548 @@ ++/* ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * Copyright (c) 2007 Advanced Micro Devices, Inc. ++ * Contributed by Robert Richter ++ * ++ * This file contains X86 Processor Family specific definitions ++ * for the perfmon interface. This covers P6, Pentium M, P4/Xeon ++ * (32-bit and 64-bit, i.e., EM64T) and AMD X86-64. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef _ASM_X86_PERFMON_KERN_H_ ++#define _ASM_X86_PERFMON_KERN_H_ ++ ++#ifdef CONFIG_PERFMON ++#include ++#ifdef CONFIG_4KSTACKS ++#define PFM_ARCH_PMD_STK_ARG 2 ++#define PFM_ARCH_PMC_STK_ARG 2 ++#else ++#define PFM_ARCH_PMD_STK_ARG 4 /* about 700 bytes of stack space */ ++#define PFM_ARCH_PMC_STK_ARG 4 /* about 200 bytes of stack space */ ++#endif ++ ++struct pfm_arch_pmu_info { ++ u32 flags; /* PMU feature flags */ ++ /* ++ * mandatory model-specific callbacks ++ */ ++ int (*stop_save)(struct pfm_context *ctx, struct pfm_event_set *set); ++ int (*has_ovfls)(struct pfm_context *ctx); ++ void (*quiesce)(void); ++ ++ /* ++ * optional model-specific callbacks ++ */ ++ void (*acquire_pmu_percpu)(void); ++ void (*release_pmu_percpu)(void); ++ int (*create_context)(struct pfm_context *ctx, u32 ctx_flags); ++ void (*free_context)(struct pfm_context *ctx); ++ int (*load_context)(struct pfm_context *ctx); ++ void (*unload_context)(struct pfm_context *ctx); ++ void (*write_pmc)(struct pfm_context *ctx, unsigned int cnum, u64 value); ++ void (*write_pmd)(struct pfm_context *ctx, unsigned int cnum, u64 value); ++ u64 (*read_pmd)(struct pfm_context *ctx, unsigned int cnum); ++ u64 (*read_pmc)(struct pfm_context *ctx, unsigned int cnum); ++ void (*nmi_copy_state)(struct pfm_context *ctx); ++ void (*restore_pmcs)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++ void (*restore_pmds)(struct pfm_context *ctx, ++ struct pfm_event_set *set); ++}; ++ ++/* ++ * PMU feature flags ++ */ ++#define PFM_X86_FL_USE_NMI 0x01 /* user asking for NMI */ ++#define PFM_X86_FL_NO_SHARING 0x02 /* no sharing with other subsystems */ ++#define PFM_X86_FL_SHARING 0x04 /* PMU is being shared */ ++ ++struct pfm_x86_ctx_flags { ++ unsigned int insecure:1; /* rdpmc per-thread self-monitoring */ ++ unsigned int use_pebs:1; /* PEBS used */ ++ unsigned int use_ds:1; /* DS used */ ++ unsigned int reserved:29; /* for future use */ ++}; ++ ++struct pfm_arch_context { ++ u64 saved_real_iip; /* instr pointer of last NMI intr */ ++ struct pfm_x86_ctx_flags flags; /* flags */ ++ void *ds_area; /* address of DS area (to go away) */ ++ void *data; /* model-specific data */ ++}; ++ ++/* ++ * functions implemented as inline on x86 ++ */ ++ ++/** ++ * pfm_arch_write_pmc - write a single PMC register ++ * @ctx: context to work on ++ * @cnum: PMC index ++ * @value: PMC 64-bit value ++ * ++ * in certain situations, ctx may be NULL ++ */ ++static inline void pfm_arch_write_pmc(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * we only write to the actual register when monitoring is ++ * active (pfm_start was issued) ++ */ ++ if (ctx && ctx->flags.started == 0) ++ return; ++ ++ /* ++ * model-specific override, if any ++ */ ++ if (pmu_info->write_pmc) { ++ pmu_info->write_pmc(ctx, cnum, value); ++ return; ++ } ++ ++ PFM_DBG_ovfl("pfm_arch_write_pmc(0x%lx, 0x%Lx)", ++ pfm_pmu_conf->pmc_desc[cnum].hw_addr, ++ (unsigned long long) value); ++ ++ wrmsrl(pfm_pmu_conf->pmc_desc[cnum].hw_addr, value); ++} ++ ++/** ++ * pfm_arch_write_pmd - write a single PMD register ++ * @ctx: context to work on ++ * @cnum: PMD index ++ * @value: PMD 64-bit value ++ */ ++static inline void pfm_arch_write_pmd(struct pfm_context *ctx, ++ unsigned int cnum, u64 value) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * to make sure the counter overflows, we set the ++ * upper bits. we also clear any other unimplemented ++ * bits as this may cause crash on some processors. ++ */ ++ if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64) ++ value = (value | ~pfm_pmu_conf->ovfl_mask) ++ & ~pfm_pmu_conf->pmd_desc[cnum].rsvd_msk; ++ ++ PFM_DBG_ovfl("pfm_arch_write_pmd(0x%lx, 0x%Lx)", ++ pfm_pmu_conf->pmd_desc[cnum].hw_addr, ++ (unsigned long long) value); ++ ++ /* ++ * model-specific override, if any ++ */ ++ if (pmu_info->write_pmd) { ++ pmu_info->write_pmd(ctx, cnum, value); ++ return; ++ } ++ ++ wrmsrl(pfm_pmu_conf->pmd_desc[cnum].hw_addr, value); ++} ++ ++/** ++ * pfm_arch_read_pmd - read a single PMD register ++ * @ctx: context to work on ++ * @cnum: PMD index ++ * ++ * return value is register 64-bit value ++ */ ++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u64 tmp; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * model-specific override, if any ++ */ ++ if (pmu_info->read_pmd) ++ tmp = pmu_info->read_pmd(ctx, cnum); ++ else ++ rdmsrl(pfm_pmu_conf->pmd_desc[cnum].hw_addr, tmp); ++ ++ PFM_DBG_ovfl("pfm_arch_read_pmd(0x%lx) = 0x%Lx", ++ pfm_pmu_conf->pmd_desc[cnum].hw_addr, ++ (unsigned long long) tmp); ++ return tmp; ++} ++ ++/** ++ * pfm_arch_read_pmc - read a single PMC register ++ * @ctx: context to work on ++ * @cnum: PMC index ++ * ++ * return value is register 64-bit value ++ */ ++static inline u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ u64 tmp; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * model-specific override, if any ++ */ ++ if (pmu_info->read_pmc) ++ tmp = pmu_info->read_pmc(ctx, cnum); ++ else ++ rdmsrl(pfm_pmu_conf->pmc_desc[cnum].hw_addr, tmp); ++ ++ PFM_DBG_ovfl("pfm_arch_read_pmc(0x%lx) = 0x%016Lx", ++ pfm_pmu_conf->pmc_desc[cnum].hw_addr, ++ (unsigned long long) tmp); ++ return tmp; ++} ++ ++/** ++ * pfm_arch_is_active - return non-zero is monitoring has been started ++ * @ctx: context to check ++ * ++ * At certain points, perfmon needs to know if monitoring has been ++ * explicitly started. ++ * ++ * On x86, there is not other way but to use pfm_start/pfm_stop ++ * to activate monitoring, thus we can simply check flags.started ++ */ ++static inline int pfm_arch_is_active(struct pfm_context *ctx) ++{ ++ return ctx->flags.started; ++} ++ ++ ++/** ++ * pfm_arch_unload_context - detach context from thread or CPU ++ * @ctx: context to detach ++ * ++ * in system-wide ctx->task is NULL, otherwise it points to the ++ * attached thread ++ */ ++static inline void pfm_arch_unload_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_arch_context *ctx_arch; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ pmu_info = pfm_pmu_info(); ++ ++ if (ctx_arch->flags.insecure) { ++ PFM_DBG("clear cr4.pce"); ++ clear_in_cr4(X86_CR4_PCE); ++ } ++ ++ if (pmu_info->unload_context) ++ pmu_info->unload_context(ctx); ++} ++ ++/** ++ * pfm_arch_load_context - attach context to thread or CPU ++ * @ctx: context to attach ++ */ ++static inline int pfm_arch_load_context(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ struct pfm_arch_context *ctx_arch; ++ int ret = 0; ++ ++ ctx_arch = pfm_ctx_arch(ctx); ++ pmu_info = pfm_pmu_info(); ++ ++ /* ++ * RDPMC authorized in system-wide and ++ * per-thread self-monitoring. ++ * ++ * RDPMC only gives access to counts. ++ * ++ * The context-switch routine code does not restore ++ * all the PMD registers (optimization), thus there ++ * is a possible leak of counts there in per-thread ++ * mode. ++ */ ++ if (ctx->task == current || ctx->flags.system) { ++ PFM_DBG("set cr4.pce"); ++ set_in_cr4(X86_CR4_PCE); ++ ctx_arch->flags.insecure = 1; ++ } ++ ++ if (pmu_info->load_context) ++ ret = pmu_info->load_context(ctx); ++ ++ return ret; ++} ++ ++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx); ++ ++/** ++ * pfm_arch_unmask_monitoring - unmask monitoring ++ * @ctx: context to mask ++ * @set: current event set ++ * ++ * masking is slightly different from stopping in that, it does not undo ++ * the pfm_start() issued by user. This is used in conjunction with ++ * sampling. Masking means stop monitoring, but do not authorize user ++ * to issue pfm_start/stop during that time. Unmasking is achieved via ++ * pfm_restart() and also may also depend on the sampling format used. ++ * ++ * on x86 masking/unmasking use the start/stop mechanism, except ++ * that flags.started is not modified. ++ */ ++static inline void pfm_arch_unmask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ pfm_arch_start(current, ctx); ++} ++ ++/** ++ * pfm_arch_intr_freeze_pmu - stop monitoring when handling PMU interrupt ++ * @ctx: current context ++ * @set: current event set ++ * ++ * called from __pfm_interrupt_handler(). ++ * ctx is not NULL. ctx is locked. interrupts are masked ++ * ++ * The following actions must take place: ++ * - stop all monitoring to ensure handler has consistent view. ++ * - collect overflowed PMDs bitmask into povfls_pmds and ++ * npend_ovfls. If no interrupt detected then npend_ovfls ++ * must be set to zero. ++ */ ++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ /* ++ * on X86, freezing is equivalent to stopping ++ */ ++ pfm_arch_stop(current, ctx); ++ ++ /* ++ * we mark monitoring as stopped to avoid ++ * certain side effects especially in ++ * pfm_switch_sets_from_intr() and ++ * pfm_arch_restore_pmcs() ++ */ ++ ctx->flags.started = 0; ++} ++ ++/** ++ * pfm_arch_intr_unfreeze_pmu - conditionally reactive monitoring ++ * @ctx: current context ++ * ++ * current context may be not when dealing when spurious interrupts ++ * ++ * Must re-activate monitoring if context is not MASKED. ++ * interrupts are masked. ++ */ ++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx) ++{ ++ if (ctx == NULL) ++ return; ++ ++ PFM_DBG_ovfl("state=%d", ctx->state); ++ ++ /* ++ * restore flags.started which is cleared in ++ * pfm_arch_intr_freeze_pmu() ++ */ ++ ctx->flags.started = 1; ++ ++ if (ctx->state == PFM_CTX_MASKED) ++ return; ++ ++ pfm_arch_restore_pmcs(ctx, ctx->active_set); ++} ++ ++/** ++ * pfm_arch_setfl_sane - check arch/model specific event set flags ++ * @ctx: context to work on ++ * @flags: event set flags as passed by user ++ * ++ * called from pfm_setfl_sane(). Context is locked. Interrupts are masked. ++ * ++ * Return: ++ * 0 when flags are valid ++ * 1 on error ++ */ ++static inline int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags) ++{ ++ return 0; ++} ++ ++/** ++ * pfm_arch_ovfl_reset_pmd - reset pmd on overflow ++ * @ctx: current context ++ * @cnum: PMD index ++ * ++ * On some CPUs, the upper bits of a counter must be set in order for the ++ * overflow interrupt to happen. On overflow, the counter has wrapped around, ++ * and the upper bits are cleared. This function may be used to set them back. ++ * ++ * For x86, the current version loses whatever is remaining in the counter, ++ * which is usually has a small count. In order not to loose this count, ++ * we do a read-modify-write to set the upper bits while preserving the ++ * low-order bits. This is slow but works. ++ */ ++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ u64 val; ++ val = pfm_arch_read_pmd(ctx, cnum); ++ pfm_arch_write_pmd(ctx, cnum, val); ++} ++ ++/** ++ * pfm_arch_context_create - create context ++ * @ctx: newly created context ++ * @flags: context flags as passed by user ++ * ++ * called from __pfm_create_context() ++ */ ++static inline int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ if (pmu_info->create_context) ++ return pmu_info->create_context(ctx, ctx_flags); ++ ++ return 0; ++} ++ ++/** ++ * pfm_arch_context_free - free context ++ * @ctx: context to free ++ */ ++static inline void pfm_arch_context_free(struct pfm_context *ctx) ++{ ++ struct pfm_arch_pmu_info *pmu_info; ++ ++ pmu_info = pfm_pmu_info(); ++ ++ if (pmu_info->free_context) ++ pmu_info->free_context(ctx); ++} ++ ++/* ++ * pfm_arch_clear_pmd_ovfl_cond - alter the pmds in such a way that they ++ * will not cause cause interrupts when unused. ++ * ++ * This is a nop on x86 ++ */ ++static inline void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++/* ++ * functions implemented in arch/x86/perfmon/perfmon.c ++ */ ++int pfm_arch_init(void); ++void pfm_arch_resend_irq(struct pfm_context *ctx); ++ ++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx); ++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx); ++ ++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set); ++int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg); ++void pfm_arch_pmu_config_remove(void); ++char *pfm_arch_get_pmu_module_name(void); ++int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds); ++void pfm_arch_pmu_release(void); ++ ++/* ++ * pfm_arch_serialize - make PMU modifications visible to subsequent instructions ++ * ++ * This is a nop on x86 ++ */ ++static inline void pfm_arch_serialize(void) ++{} ++ ++/* ++ * on x86, the PMDs are already saved by pfm_arch_freeze_pmu() ++ * when entering the PMU interrupt handler, thus, we do not need ++ * to save them again in pfm_switch_sets_from_intr() ++ */ ++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++ ++static inline void pfm_arch_ctxswout_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++ ++static inline void pfm_arch_ctxswin_sys(struct task_struct *task, ++ struct pfm_context *ctx) ++{} ++ ++static inline void pfm_arch_init_percpu(void) ++{} ++ ++static inline void pfm_cacheflush(void *addr, unsigned int len) ++{} ++ ++/* ++ * this function is called from the PMU interrupt handler ONLY. ++ * On x86, the PMU is frozen via arch_stop, masking would be implemented ++ * via arch-stop as well. Given that the PMU is already stopped when ++ * entering the interrupt handler, we do not need to stop it again, so ++ * this function is a nop. ++ */ ++static inline void pfm_arch_mask_monitoring(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{} ++ ++ ++static inline void pfm_arch_arm_handle_work(struct task_struct *task) ++{} ++ ++static inline void pfm_arch_disarm_handle_work(struct task_struct *task) ++{} ++ ++static inline int pfm_arch_get_base_syscall(void) ++{ ++#ifdef __x86_64__ ++ /* 32-bit syscall definition coming from ia32_unistd.h */ ++ if (test_thread_flag(TIF_IA32)) ++ return __NR_ia32_pfm_create_context; ++#endif ++ return __NR_pfm_create_context; ++} ++ ++#define PFM_ARCH_CTX_SIZE (sizeof(struct pfm_arch_context)) ++/* ++ * x86 does not need extra alignment requirements for the sampling buffer ++ */ ++#define PFM_ARCH_SMPL_ALIGN_SIZE 0 ++ ++asmlinkage void pmu_interrupt(void); ++ ++#endif /* CONFIG_PEFMON */ ++ ++#endif /* _ASM_X86_PERFMON_KERN_H_ */ +--- /dev/null ++++ b/include/asm-x86/perfmon_pebs_core_smpl.h +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ * ++ * This file implements the sampling format to support Intel ++ * Precise Event Based Sampling (PEBS) feature of Intel Core ++ * processors, such as Intel Core 2. ++ * ++ * What is PEBS? ++ * ------------ ++ * This is a hardware feature to enhance sampling by providing ++ * better precision as to where a sample is taken. This avoids the ++ * typical skew in the instruction one can observe with any ++ * interrupt-based sampling technique. ++ * ++ * PEBS also lowers sampling overhead significantly by having the ++ * processor store samples instead of the OS. PMU interrupt are only ++ * generated after multiple samples are written. ++ * ++ * Another benefit of PEBS is that samples can be captured inside ++ * critical sections where interrupts are masked. ++ * ++ * How does it work? ++ * PEBS effectively implements a Hw buffer. The Os must pass a region ++ * of memory where samples are to be stored. The region can have any ++ * size. The OS must also specify the sampling period to reload. The PMU ++ * will interrupt when it reaches the end of the buffer or a specified ++ * threshold location inside the memory region. ++ * ++ * The description of the buffer is stored in the Data Save Area (DS). ++ * The samples are stored sequentially in the buffer. The format of the ++ * buffer is fixed and specified in the PEBS documentation. The sample ++ * format does not change between 32-bit and 64-bit modes unlike on the ++ * Pentium 4 version of PEBS. ++ * ++ * PEBS does not work when HyperThreading is enabled due to certain MSR ++ * being shared being to two threads. ++ * ++ * What does the format do? ++ * It provides access to the PEBS feature for both 32-bit and 64-bit ++ * processors that support it. ++ * ++ * The same code and data structures are used for both 32-bit and 64-bi ++ * modes. A single format name is used for both modes. In 32-bit mode, ++ * some of the extended registers are written to zero in each sample. ++ * ++ * It is important to realize that the format provides a zero-copy ++ * environment for the samples, i.e,, the OS never touches the ++ * samples. Whatever the processor write is directly accessible to ++ * the user. ++ * ++ * Parameters to the buffer can be passed via pfm_create_context() in ++ * the pfm_pebs_smpl_arg structure. ++ */ ++#ifndef __PERFMON_PEBS_CORE_SMPL_H__ ++#define __PERFMON_PEBS_CORE_SMPL_H__ 1 ++ ++/* ++ * The 32-bit and 64-bit formats are identical, thus we use only ++ * one name for the format. ++ */ ++#define PFM_PEBS_CORE_SMPL_NAME "pebs_core" ++ ++/* ++ * format specific parameters (passed at context creation) ++ * ++ * intr_thres: index from start of buffer of entry where the ++ * PMU interrupt must be triggered. It must be several samples ++ * short of the end of the buffer. ++ */ ++struct pfm_pebs_core_smpl_arg { ++ u64 cnt_reset; /* counter reset value */ ++ size_t buf_size; /* size of the PEBS buffer in bytes */ ++ size_t intr_thres;/* index of PEBS interrupt threshold entry */ ++ u64 reserved[6]; /* for future use */ ++}; ++ ++/* ++ * Data Save Area (32 and 64-bit mode) ++ * ++ * The DS area is exposed to the user. To determine the number ++ * of samples available in PEBS, it is necessary to substract ++ * pebs_index from pebs_base. ++ * ++ * Layout of the structure is mandated by hardware and specified ++ * in the Intel documentation. ++ */ ++struct pfm_ds_area_core { ++ u64 bts_buf_base; ++ u64 bts_index; ++ u64 bts_abs_max; ++ u64 bts_intr_thres; ++ u64 pebs_buf_base; ++ u64 pebs_index; ++ u64 pebs_abs_max; ++ u64 pebs_intr_thres; ++ u64 pebs_cnt_reset; ++}; ++ ++/* ++ * This header is at the beginning of the sampling buffer returned to the user. ++ * ++ * Because of PEBS alignement constraints, the actual PEBS buffer area does ++ * not necessarily begin right after the header. The hdr_start_offs must be ++ * used to compute the first byte of the buffer. The offset is defined as ++ * the number of bytes between the end of the header and the beginning of ++ * the buffer. As such the formula is: ++ * actual_buffer = (unsigned long)(hdr+1)+hdr->hdr_start_offs ++ */ ++struct pfm_pebs_core_smpl_hdr { ++ u64 overflows; /* #overflows for buffer */ ++ size_t buf_size; /* bytes in the buffer */ ++ size_t start_offs; /* actual buffer start offset */ ++ u32 version; /* smpl format version */ ++ u32 reserved1; /* for future use */ ++ u64 reserved2[5]; /* for future use */ ++ struct pfm_ds_area_core ds; /* data save area */ ++}; ++ ++/* ++ * Sample format as mandated by Intel documentation. ++ * The same format is used in both 32 and 64 bit modes. ++ */ ++struct pfm_pebs_core_smpl_entry { ++ u64 eflags; ++ u64 ip; ++ u64 eax; ++ u64 ebx; ++ u64 ecx; ++ u64 edx; ++ u64 esi; ++ u64 edi; ++ u64 ebp; ++ u64 esp; ++ u64 r8; /* 0 in 32-bit mode */ ++ u64 r9; /* 0 in 32-bit mode */ ++ u64 r10; /* 0 in 32-bit mode */ ++ u64 r11; /* 0 in 32-bit mode */ ++ u64 r12; /* 0 in 32-bit mode */ ++ u64 r13; /* 0 in 32-bit mode */ ++ u64 r14; /* 0 in 32-bit mode */ ++ u64 r15; /* 0 in 32-bit mode */ ++}; ++ ++#define PFM_PEBS_CORE_SMPL_VERSION_MAJ 1U ++#define PFM_PEBS_CORE_SMPL_VERSION_MIN 0U ++#define PFM_PEBS_CORE_SMPL_VERSION (((PFM_PEBS_CORE_SMPL_VERSION_MAJ&0xffff)<<16)|\ ++ (PFM_PEBS_CORE_SMPL_VERSION_MIN & 0xffff)) ++ ++#endif /* __PERFMON_PEBS_CORE_SMPL_H__ */ +--- /dev/null ++++ b/include/asm-x86/perfmon_pebs_p4_smpl.h +@@ -0,0 +1,193 @@ ++/* ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ * ++ * This file implements the sampling format to support Intel ++ * Precise Event Based Sampling (PEBS) feature of Pentium 4 ++ * and other Netburst-based processors. Not to be used for ++ * Intel Core-based processors. ++ * ++ * What is PEBS? ++ * ------------ ++ * This is a hardware feature to enhance sampling by providing ++ * better precision as to where a sample is taken. This avoids the ++ * typical skew in the instruction one can observe with any ++ * interrupt-based sampling technique. ++ * ++ * PEBS also lowers sampling overhead significantly by having the ++ * processor store samples instead of the OS. PMU interrupt are only ++ * generated after multiple samples are written. ++ * ++ * Another benefit of PEBS is that samples can be captured inside ++ * critical sections where interrupts are masked. ++ * ++ * How does it work? ++ * PEBS effectively implements a Hw buffer. The Os must pass a region ++ * of memory where samples are to be stored. The region can have any ++ * size. The OS must also specify the sampling period to reload. The PMU ++ * will interrupt when it reaches the end of the buffer or a specified ++ * threshold location inside the memory region. ++ * ++ * The description of the buffer is stored in the Data Save Area (DS). ++ * The samples are stored sequentially in the buffer. The format of the ++ * buffer is fixed and specified in the PEBS documentation. The sample ++ * format changes between 32-bit and 64-bit modes due to extended register ++ * file. ++ * ++ * PEBS does not work when HyperThreading is enabled due to certain MSR ++ * being shared being to two threads. ++ * ++ * What does the format do? ++ * It provides access to the PEBS feature for both 32-bit and 64-bit ++ * processors that support it. ++ * ++ * The same code is used for both 32-bit and 64-bit modes, but different ++ * format names are used because the two modes are not compatible due to ++ * data model and register file differences. Similarly the public data ++ * structures describing the samples are different. ++ * ++ * It is important to realize that the format provides a zero-copy environment ++ * for the samples, i.e,, the OS never touches the samples. Whatever the ++ * processor write is directly accessible to the user. ++ * ++ * Parameters to the buffer can be passed via pfm_create_context() in ++ * the pfm_pebs_smpl_arg structure. ++ * ++ * It is not possible to mix a 32-bit PEBS application on top of a 64-bit ++ * host kernel. ++ */ ++#ifndef __PERFMON_PEBS_P4_SMPL_H__ ++#define __PERFMON_PEBS_P4_SMPL_H__ 1 ++ ++#ifdef __i386__ ++/* ++ * The 32-bit and 64-bit formats are not compatible, thus we have ++ * two different identifications so that 32-bit programs running on ++ * 64-bit OS will fail to use the 64-bit PEBS support. ++ */ ++#define PFM_PEBS_P4_SMPL_NAME "pebs32_p4" ++#else ++#define PFM_PEBS_P4_SMPL_NAME "pebs64_p4" ++#endif ++ ++/* ++ * format specific parameters (passed at context creation) ++ * ++ * intr_thres: index from start of buffer of entry where the ++ * PMU interrupt must be triggered. It must be several samples ++ * short of the end of the buffer. ++ */ ++struct pfm_pebs_p4_smpl_arg { ++ u64 cnt_reset; /* counter reset value */ ++ size_t buf_size; /* size of the PEBS buffer in bytes */ ++ size_t intr_thres;/* index of PEBS interrupt threshold entry */ ++ u64 reserved[6]; /* for future use */ ++}; ++ ++/* ++ * Data Save Area (32 and 64-bit mode) ++ * ++ * The DS area must be exposed to the user because this is the only ++ * way to report on the number of valid entries recorded by the CPU. ++ * This is required when the buffer is not full, i..e, there was not ++ * PMU interrupt. ++ * ++ * Layout of the structure is mandated by hardware and specified in ++ * the Intel documentation. ++ */ ++struct pfm_ds_area_p4 { ++ unsigned long bts_buf_base; ++ unsigned long bts_index; ++ unsigned long bts_abs_max; ++ unsigned long bts_intr_thres; ++ unsigned long pebs_buf_base; ++ unsigned long pebs_index; ++ unsigned long pebs_abs_max; ++ unsigned long pebs_intr_thres; ++ u64 pebs_cnt_reset; ++}; ++ ++/* ++ * This header is at the beginning of the sampling buffer returned to the user. ++ * ++ * Because of PEBS alignement constraints, the actual PEBS buffer area does ++ * not necessarily begin right after the header. The hdr_start_offs must be ++ * used to compute the first byte of the buffer. The offset is defined as ++ * the number of bytes between the end of the header and the beginning of ++ * the buffer. As such the formula is: ++ * actual_buffer = (unsigned long)(hdr+1)+hdr->hdr_start_offs ++ */ ++struct pfm_pebs_p4_smpl_hdr { ++ u64 overflows; /* #overflows for buffer */ ++ size_t buf_size; /* bytes in the buffer */ ++ size_t start_offs; /* actual buffer start offset */ ++ u32 version; /* smpl format version */ ++ u32 reserved1; /* for future use */ ++ u64 reserved2[5]; /* for future use */ ++ struct pfm_ds_area_p4 ds; /* data save area */ ++}; ++ ++/* ++ * 64-bit PEBS record format is described in ++ * http://www.intel.com/technology/64bitextensions/30083502.pdf ++ * ++ * The format does not peek at samples. The sample structure is only ++ * used to ensure that the buffer is large enough to accomodate one ++ * sample. ++ */ ++#ifdef __i386__ ++struct pfm_pebs_p4_smpl_entry { ++ u32 eflags; ++ u32 ip; ++ u32 eax; ++ u32 ebx; ++ u32 ecx; ++ u32 edx; ++ u32 esi; ++ u32 edi; ++ u32 ebp; ++ u32 esp; ++}; ++#else ++struct pfm_pebs_p4_smpl_entry { ++ u64 eflags; ++ u64 ip; ++ u64 eax; ++ u64 ebx; ++ u64 ecx; ++ u64 edx; ++ u64 esi; ++ u64 edi; ++ u64 ebp; ++ u64 esp; ++ u64 r8; ++ u64 r9; ++ u64 r10; ++ u64 r11; ++ u64 r12; ++ u64 r13; ++ u64 r14; ++ u64 r15; ++}; ++#endif ++ ++#define PFM_PEBS_P4_SMPL_VERSION_MAJ 1U ++#define PFM_PEBS_P4_SMPL_VERSION_MIN 0U ++#define PFM_PEBS_P4_SMPL_VERSION (((PFM_PEBS_P4_SMPL_VERSION_MAJ&0xffff)<<16)|\ ++ (PFM_PEBS_P4_SMPL_VERSION_MIN & 0xffff)) ++ ++#endif /* __PERFMON_PEBS_P4_SMPL_H__ */ +--- a/include/asm-x86/thread_info.h ++++ b/include/asm-x86/thread_info.h +@@ -79,6 +79,7 @@ struct thread_info { + #define TIF_SYSCALL_EMU 6 /* syscall emulation active */ + #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ + #define TIF_SECCOMP 8 /* secure computing */ ++#define TIF_PERFMON_WORK 9 /* work for pfm_handle_work() */ + #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */ + #define TIF_NOTSC 16 /* TSC is not accessible in userland */ + #define TIF_IA32 17 /* 32bit process */ +@@ -92,6 +93,7 @@ struct thread_info { + #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ + #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ + #define TIF_BTS_TRACE_TS 27 /* record scheduling event timestamps */ ++#define TIF_PERFMON_CTXSW 28 /* perfmon needs ctxsw calls */ + + #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) + #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +@@ -114,6 +116,8 @@ struct thread_info { + #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) + #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) + #define _TIF_BTS_TRACE_TS (1 << TIF_BTS_TRACE_TS) ++#define _TIF_PERFMON_WORK (1 << TIF_PERFMON_WORK) ++#define _TIF_PERFMON_CTXSW (1 << TIF_PERFMON_CTXSW) + + /* work to do in syscall_trace_enter() */ + #define _TIF_WORK_SYSCALL_ENTRY \ +@@ -135,12 +139,12 @@ struct thread_info { + + /* Only used for 64 bit */ + #define _TIF_DO_NOTIFY_MASK \ +- (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME) ++ (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME|_TIF_PERFMON_WORK) + + /* flags to check in __switch_to() */ + #define _TIF_WORK_CTXSW \ + (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \ +- _TIF_NOTSC) ++ _TIF_NOTSC|_TIF_PERFMON_CTXSW) + + #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW + #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) +--- a/include/asm-x86/unistd_32.h ++++ b/include/asm-x86/unistd_32.h +@@ -338,9 +338,23 @@ + #define __NR_dup3 330 + #define __NR_pipe2 331 + #define __NR_inotify_init1 332 ++#define __NR_pfm_create_context 333 ++#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) ++#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) ++#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) ++#define __NR_pfm_load_context (__NR_pfm_create_context+4) ++#define __NR_pfm_start (__NR_pfm_create_context+5) ++#define __NR_pfm_stop (__NR_pfm_create_context+6) ++#define __NR_pfm_restart (__NR_pfm_create_context+7) ++#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) ++#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) ++#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) ++#define __NR_pfm_unload_context (__NR_pfm_create_context+11) + + #ifdef __KERNEL__ + ++#define NR_syscalls 345 ++ + #define __ARCH_WANT_IPC_PARSE_VERSION + #define __ARCH_WANT_OLD_READDIR + #define __ARCH_WANT_OLD_STAT +--- a/include/asm-x86/unistd_64.h ++++ b/include/asm-x86/unistd_64.h +@@ -653,7 +653,30 @@ __SYSCALL(__NR_dup3, sys_dup3) + __SYSCALL(__NR_pipe2, sys_pipe2) + #define __NR_inotify_init1 294 + __SYSCALL(__NR_inotify_init1, sys_inotify_init1) +- ++#define __NR_pfm_create_context 295 ++__SYSCALL(__NR_pfm_create_context, sys_pfm_create_context) ++#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1) ++__SYSCALL(__NR_pfm_write_pmcs, sys_pfm_write_pmcs) ++#define __NR_pfm_write_pmds (__NR_pfm_create_context+2) ++__SYSCALL(__NR_pfm_write_pmds, sys_pfm_write_pmds) ++#define __NR_pfm_read_pmds (__NR_pfm_create_context+3) ++ __SYSCALL(__NR_pfm_read_pmds, sys_pfm_read_pmds) ++#define __NR_pfm_load_context (__NR_pfm_create_context+4) ++__SYSCALL(__NR_pfm_load_context, sys_pfm_load_context) ++#define __NR_pfm_start (__NR_pfm_create_context+5) ++__SYSCALL(__NR_pfm_start, sys_pfm_start) ++#define __NR_pfm_stop (__NR_pfm_create_context+6) ++__SYSCALL(__NR_pfm_stop, sys_pfm_stop) ++#define __NR_pfm_restart (__NR_pfm_create_context+7) ++__SYSCALL(__NR_pfm_restart, sys_pfm_restart) ++#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8) ++__SYSCALL(__NR_pfm_create_evtsets, sys_pfm_create_evtsets) ++#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9) ++__SYSCALL(__NR_pfm_getinfo_evtsets, sys_pfm_getinfo_evtsets) ++#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10) ++__SYSCALL(__NR_pfm_delete_evtsets, sys_pfm_delete_evtsets) ++#define __NR_pfm_unload_context (__NR_pfm_create_context+11) ++__SYSCALL(__NR_pfm_unload_context, sys_pfm_unload_context) + + #ifndef __NO_STUBS + #define __ARCH_WANT_OLD_READDIR +--- a/include/linux/Kbuild ++++ b/include/linux/Kbuild +@@ -163,6 +163,8 @@ header-y += video_decoder.h + header-y += video_encoder.h + header-y += videotext.h + header-y += x25.h ++header-y += perfmon.h ++header-y += perfmon_dfl_smpl.h + + unifdef-y += acct.h + unifdef-y += adb.h +--- /dev/null ++++ b/include/linux/perfmon.h +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++ ++#ifndef __LINUX_PERFMON_H__ ++#define __LINUX_PERFMON_H__ ++ ++/* ++ * This file contains all the user visible generic definitions for the ++ * interface. Model-specific user-visible definitions are located in ++ * the asm/perfmon.h file. ++ */ ++ ++/* ++ * include arch-specific user interface definitions ++ */ ++#include ++ ++/* ++ * defined by each arch ++ */ ++#define PFM_MAX_PMCS PFM_ARCH_MAX_PMCS ++#define PFM_MAX_PMDS PFM_ARCH_MAX_PMDS ++ ++/* ++ * number of elements for each type of bitvector ++ * all bitvectors use u64 fixed size type on all architectures. ++ */ ++#define PFM_BVSIZE(x) (((x)+(sizeof(__u64)<<3)-1) / (sizeof(__u64)<<3)) ++#define PFM_PMD_BV PFM_BVSIZE(PFM_MAX_PMDS) ++#define PFM_PMC_BV PFM_BVSIZE(PFM_MAX_PMCS) ++ ++/* ++ * register flags layout: ++ * bit[00-15] : generic flags ++ * bit[16-31] : arch-specific flags ++ * ++ * PFM_REGFL_NO_EMUL64: must be set on the PMC controlling the PMD ++ */ ++#define PFM_REGFL_OVFL_NOTIFY 0x1 /* PMD: send notification on event */ ++#define PFM_REGFL_RANDOM 0x2 /* PMD: randomize value after event */ ++#define PFM_REGFL_NO_EMUL64 0x4 /* PMC: no 64-bit emulation */ ++ ++/* ++ * event set flags layout: ++ * bits[00-15] : generic flags ++ * bits[16-31] : arch-specific flags (see asm/perfmon.h) ++ */ ++#define PFM_SETFL_OVFL_SWITCH 0x01 /* enable switch on overflow */ ++#define PFM_SETFL_TIME_SWITCH 0x02 /* enable switch on timeout */ ++ ++/* ++ * argument to pfm_create_context() system call ++ * structure shared with user level ++ */ ++struct pfarg_ctx { ++ __u32 ctx_flags; /* noblock/block/syswide */ ++ __u32 ctx_reserved1; /* for future use */ ++ __u64 ctx_reserved2[7]; /* for future use */ ++}; ++ ++/* ++ * context flags layout: ++ * bits[00-15]: generic flags ++ * bits[16-31]: arch-specific flags (see perfmon_const.h) ++ */ ++#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user notifications */ ++#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ ++#define PFM_FL_OVFL_NO_MSG 0x80 /* no overflow msgs */ ++ ++/* ++ * argument to pfm_write_pmcs() system call. ++ * structure shared with user level ++ */ ++struct pfarg_pmc { ++ __u16 reg_num; /* which register */ ++ __u16 reg_set; /* event set for this register */ ++ __u32 reg_flags; /* REGFL flags */ ++ __u64 reg_value; /* pmc value */ ++ __u64 reg_reserved2[4]; /* for future use */ ++}; ++ ++/* ++ * argument to pfm_write_pmds() and pfm_read_pmds() system calls. ++ * structure shared with user level ++ */ ++struct pfarg_pmd { ++ __u16 reg_num; /* which register */ ++ __u16 reg_set; /* event set for this register */ ++ __u32 reg_flags; /* REGFL flags */ ++ __u64 reg_value; /* initial pmc/pmd value */ ++ __u64 reg_long_reset; /* value to reload after notification */ ++ __u64 reg_short_reset; /* reset after counter overflow */ ++ __u64 reg_last_reset_val; /* return: PMD last reset value */ ++ __u64 reg_ovfl_switch_cnt; /* #overflows before switch */ ++ __u64 reg_reset_pmds[PFM_PMD_BV]; /* reset on overflow */ ++ __u64 reg_smpl_pmds[PFM_PMD_BV]; /* record in sample */ ++ __u64 reg_smpl_eventid; /* opaque event identifier */ ++ __u64 reg_random_mask; /* bitmask used to limit random value */ ++ __u32 reg_random_seed; /* seed for randomization (OBSOLETE) */ ++ __u32 reg_reserved2[7]; /* for future use */ ++}; ++ ++/* ++ * optional argument to pfm_start() system call. Pass NULL if not needed. ++ * structure shared with user level ++ */ ++struct pfarg_start { ++ __u16 start_set; /* event set to start with */ ++ __u16 start_reserved1; /* for future use */ ++ __u32 start_reserved2; /* for future use */ ++ __u64 reserved3[3]; /* for future use */ ++}; ++ ++/* ++ * argument to pfm_load_context() system call. ++ * structure shared with user level ++ */ ++struct pfarg_load { ++ __u32 load_pid; /* thread or CPU to attach to */ ++ __u16 load_set; /* set to load first */ ++ __u16 load_reserved1; /* for future use */ ++ __u64 load_reserved2[3]; /* for future use */ ++}; ++ ++/* ++ * argument to pfm_create_evtsets() and pfm_delete_evtsets() system calls. ++ * structure shared with user level. ++ */ ++struct pfarg_setdesc { ++ __u16 set_id; /* which set */ ++ __u16 set_reserved1; /* for future use */ ++ __u32 set_flags; /* SETFL flags */ ++ __u64 set_timeout; /* switch timeout in nsecs */ ++ __u64 reserved[6]; /* for future use */ ++}; ++ ++/* ++ * argument to pfm_getinfo_evtsets() system call. ++ * structure shared with user level ++ */ ++struct pfarg_setinfo { ++ __u16 set_id; /* which set */ ++ __u16 set_reserved1; /* for future use */ ++ __u32 set_flags; /* out: SETFL flags */ ++ __u64 set_ovfl_pmds[PFM_PMD_BV]; /* out: last ovfl PMDs */ ++ __u64 set_runs; /* out: #times the set was active */ ++ __u64 set_timeout; /* out: eff/leftover timeout (nsecs) */ ++ __u64 set_act_duration; /* out: time set was active in nsecs */ ++ __u64 set_avail_pmcs[PFM_PMC_BV];/* out: available PMCs */ ++ __u64 set_avail_pmds[PFM_PMD_BV];/* out: available PMDs */ ++ __u64 set_reserved3[6]; /* for future use */ ++}; ++ ++/* ++ * default value for the user and group security parameters in ++ * /proc/sys/kernel/perfmon/sys_group ++ * /proc/sys/kernel/perfmon/task_group ++ */ ++#define PFM_GROUP_PERM_ANY -1 /* any user/group */ ++ ++/* ++ * overflow notification message. ++ * structure shared with user level ++ */ ++struct pfarg_ovfl_msg { ++ __u32 msg_type; /* message type: PFM_MSG_OVFL */ ++ __u32 msg_ovfl_pid; /* process id */ ++ __u16 msg_active_set; /* active set at overflow */ ++ __u16 msg_ovfl_cpu; /* cpu of PMU interrupt */ ++ __u32 msg_ovfl_tid; /* thread id */ ++ __u64 msg_ovfl_ip; /* IP on PMU intr */ ++ __u64 msg_ovfl_pmds[PFM_PMD_BV];/* overflowed PMDs */ ++}; ++ ++#define PFM_MSG_OVFL 1 /* an overflow happened */ ++#define PFM_MSG_END 2 /* task to which context was attached ended */ ++ ++/* ++ * generic notification message (union). ++ * union shared with user level ++ */ ++union pfarg_msg { ++ __u32 type; ++ struct pfarg_ovfl_msg pfm_ovfl_msg; ++}; ++ ++/* ++ * perfmon version number ++ */ ++#define PFM_VERSION_MAJ 2U ++#define PFM_VERSION_MIN 82U ++#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|\ ++ (PFM_VERSION_MIN & 0xffff)) ++#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) ++#define PFM_VERSION_MINOR(x) ((x) & 0xffff) ++ ++#endif /* __LINUX_PERFMON_H__ */ +--- /dev/null ++++ b/include/linux/perfmon_dfl_smpl.h +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file implements the new dfl sampling buffer format ++ * for perfmon2 subsystem. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef __PERFMON_DFL_SMPL_H__ ++#define __PERFMON_DFL_SMPL_H__ 1 ++ ++/* ++ * format specific parameters (passed at context creation) ++ */ ++struct pfm_dfl_smpl_arg { ++ __u64 buf_size; /* size of the buffer in bytes */ ++ __u32 buf_flags; /* buffer specific flags */ ++ __u32 reserved1; /* for future use */ ++ __u64 reserved[6]; /* for future use */ ++}; ++ ++/* ++ * This header is at the beginning of the sampling buffer returned to the user. ++ * It is directly followed by the first record. ++ */ ++struct pfm_dfl_smpl_hdr { ++ __u64 hdr_count; /* how many valid entries */ ++ __u64 hdr_cur_offs; /* current offset from top of buffer */ ++ __u64 hdr_overflows; /* #overflows for buffer */ ++ __u64 hdr_buf_size; /* bytes in the buffer */ ++ __u64 hdr_min_buf_space;/* minimal buffer size (internal use) */ ++ __u32 hdr_version; /* smpl format version */ ++ __u32 hdr_buf_flags; /* copy of buf_flags */ ++ __u64 hdr_reserved[10]; /* for future use */ ++}; ++ ++/* ++ * Entry header in the sampling buffer. The header is directly followed ++ * with the values of the PMD registers of interest saved in increasing ++ * index order: PMD4, PMD5, and so on. How many PMDs are present depends ++ * on how the session was programmed. ++ * ++ * In the case where multiple counters overflow at the same time, multiple ++ * entries are written consecutively. ++ * ++ * last_reset_value member indicates the initial value of the overflowed PMD. ++ */ ++struct pfm_dfl_smpl_entry { ++ __u32 pid; /* thread id (for NPTL, this is gettid()) */ ++ __u16 ovfl_pmd; /* index of overflowed PMD for this sample */ ++ __u16 reserved; /* for future use */ ++ __u64 last_reset_val; /* initial value of overflowed PMD */ ++ __u64 ip; /* where did the overflow intr happened */ ++ __u64 tstamp; /* overflow timetamp */ ++ __u16 cpu; /* cpu on which the overfow occurred */ ++ __u16 set; /* event set active when overflow ocurred */ ++ __u32 tgid; /* thread group id (getpid() for NPTL) */ ++}; ++ ++#define PFM_DFL_SMPL_VERSION_MAJ 1U ++#define PFM_DFL_SMPL_VERSION_MIN 0U ++#define PFM_DFL_SMPL_VERSION (((PFM_DFL_SMPL_VERSION_MAJ&0xffff)<<16)|\ ++ (PFM_DFL_SMPL_VERSION_MIN & 0xffff)) ++ ++#endif /* __PERFMON_DFL_SMPL_H__ */ +--- /dev/null ++++ b/include/linux/perfmon_fmt.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * Interface for custom sampling buffer format modules ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef __PERFMON_FMT_H__ ++#define __PERFMON_FMT_H__ 1 ++ ++#include ++ ++typedef int (*fmt_validate_t)(u32 flags, u16 npmds, void *arg); ++typedef int (*fmt_getsize_t)(u32 flags, void *arg, size_t *size); ++typedef int (*fmt_init_t)(struct pfm_context *ctx, void *buf, u32 flags, ++ u16 nmpds, void *arg); ++typedef int (*fmt_restart_t)(int is_active, u32 *ovfl_ctrl, void *buf); ++typedef int (*fmt_exit_t)(void *buf); ++typedef int (*fmt_handler_t)(struct pfm_context *ctx, ++ unsigned long ip, u64 stamp, void *data); ++ ++struct pfm_smpl_fmt { ++ char *fmt_name; /* name of the format (required) */ ++ size_t fmt_arg_size; /* size of fmt args for ctx create */ ++ u32 fmt_flags; /* format specific flags */ ++ u32 fmt_version; /* format version number */ ++ ++ fmt_validate_t fmt_validate; /* validate context flags */ ++ fmt_getsize_t fmt_getsize; /* get size for sampling buffer */ ++ fmt_init_t fmt_init; /* initialize buffer area */ ++ fmt_handler_t fmt_handler; /* overflow handler (required) */ ++ fmt_restart_t fmt_restart; /* restart after notification */ ++ fmt_exit_t fmt_exit; /* context termination */ ++ ++ struct list_head fmt_list; /* internal use only */ ++ ++ struct kobject kobj; /* sysfs internal use only */ ++ struct module *owner; /* pointer to module owner */ ++ u32 fmt_qdepth; /* Max notify queue depth (required) */ ++}; ++#define to_smpl_fmt(n) container_of(n, struct pfm_smpl_fmt, kobj) ++ ++#define PFM_FMTFL_IS_BUILTIN 0x1 /* fmt is compiled in */ ++/* ++ * we need to know whether the format is builtin or compiled ++ * as a module ++ */ ++#ifdef MODULE ++#define PFM_FMT_BUILTIN_FLAG 0 /* not built as a module */ ++#else ++#define PFM_FMT_BUILTIN_FLAG PFM_PMUFL_IS_BUILTIN /* built as a module */ ++#endif ++ ++int pfm_fmt_register(struct pfm_smpl_fmt *fmt); ++int pfm_fmt_unregister(struct pfm_smpl_fmt *fmt); ++void pfm_sysfs_builtin_fmt_add(void); ++ ++int pfm_sysfs_add_fmt(struct pfm_smpl_fmt *fmt); ++void pfm_sysfs_remove_fmt(struct pfm_smpl_fmt *fmt); ++ ++#endif /* __PERFMON_FMT_H__ */ +--- /dev/null ++++ b/include/linux/perfmon_kern.h +@@ -0,0 +1,551 @@ ++/* ++ * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++ ++#ifndef __LINUX_PERFMON_KERN_H__ ++#define __LINUX_PERFMON_KERN_H__ ++/* ++ * This file contains all the definitions of data structures, variables, macros ++ * that are to be shared between generic code and arch-specific code ++ * ++ * For generic only definitions, use perfmon/perfmon_priv.h ++ */ ++#ifdef CONFIG_PERFMON ++ ++#include ++#include ++#include ++ ++/* ++ * system adminstrator configuration controls available via ++ * the /sys/kerne/perfmon interface ++ */ ++struct pfm_controls { ++ u32 debug; /* debugging control bitmask */ ++ gid_t sys_group; /* gid to create a syswide context */ ++ gid_t task_group; /* gid to create a per-task context */ ++ u32 flags; /* control flags (see below) */ ++ size_t arg_mem_max; /* maximum vector argument size */ ++ size_t smpl_buffer_mem_max; /* max buf mem, -1 for infinity */ ++}; ++extern struct pfm_controls pfm_controls; ++ ++/* ++ * control flags ++ */ ++#define PFM_CTRL_FL_RW_EXPERT 0x1 /* bypass reserved fields on read/write */ ++ ++/* ++ * software PMD ++ */ ++struct pfm_pmd { ++ u64 value; /* 64-bit value */ ++ u64 lval; /* last reset value */ ++ u64 ovflsw_thres; /* #ovfls left before switch */ ++ u64 long_reset; /* long reset value on overflow */ ++ u64 short_reset; /* short reset value on overflow */ ++ u64 reset_pmds[PFM_PMD_BV]; /* pmds to reset on overflow */ ++ u64 smpl_pmds[PFM_PMD_BV]; /* pmds to record on overflow */ ++ u64 mask; /* range mask for random value */ ++ u64 ovflsw_ref_thres; /* #ovfls before next set */ ++ u64 eventid; /* opaque event identifier */ ++ u32 flags; /* notify/do not notify */ ++}; ++ ++/* ++ * event_set: encapsulates the full PMU state ++ */ ++struct pfm_event_set { ++ struct list_head list; /* ordered chain of sets */ ++ u16 id; /* set identification */ ++ u16 nused_pmds; /* max number of used PMDs */ ++ u16 nused_pmcs; /* max number of used PMCs */ ++ u16 pad1; /* paddding */ ++ u32 flags; /* public flags */ ++ u32 priv_flags; /* private flags (see below) */ ++ u64 runs; /* # of activations */ ++ u32 npend_ovfls; /* number of pending PMD overflow */ ++ u32 pad2; /* padding */ ++ u64 used_pmds[PFM_PMD_BV]; /* used PMDs */ ++ u64 povfl_pmds[PFM_PMD_BV]; /* pending overflowed PMDs */ ++ u64 ovfl_pmds[PFM_PMD_BV]; /* last overflowed PMDs */ ++ u64 reset_pmds[PFM_PMD_BV]; /* PMDs to reset after overflow */ ++ u64 ovfl_notify[PFM_PMD_BV]; /* notify on overflow */ ++ u64 used_pmcs[PFM_PMC_BV]; /* used PMCs */ ++ u64 pmcs[PFM_MAX_PMCS]; /* PMC values */ ++ ++ struct pfm_pmd pmds[PFM_MAX_PMDS]; ++ ++ ktime_t hrtimer_exp; /* switch timeout reference */ ++ ktime_t hrtimer_rem; /* per-thread remainder timeout */ ++ ++ u64 duration_start; /* start time in ns */ ++ u64 duration; /* total active ns */ ++}; ++ ++/* ++ * common private event set flags (priv_flags) ++ * ++ * upper 16 bits: for arch-specific use ++ * lower 16 bits: for common use ++ */ ++#define PFM_SETFL_PRIV_MOD_PMDS 0x1 /* PMD register(s) modified */ ++#define PFM_SETFL_PRIV_MOD_PMCS 0x2 /* PMC register(s) modified */ ++#define PFM_SETFL_PRIV_SWITCH 0x4 /* must switch set on restart */ ++#define PFM_SETFL_PRIV_MOD_BOTH (PFM_SETFL_PRIV_MOD_PMDS \ ++ | PFM_SETFL_PRIV_MOD_PMCS) ++ ++/* ++ * context flags ++ */ ++struct pfm_context_flags { ++ unsigned int block:1; /* task blocks on user notifications */ ++ unsigned int system:1; /* do system wide monitoring */ ++ unsigned int no_msg:1; /* no message sent on overflow */ ++ unsigned int switch_ovfl:1; /* switch set on counter ovfl */ ++ unsigned int switch_time:1; /* switch set on timeout */ ++ unsigned int started:1; /* pfm_start() issued */ ++ unsigned int work_type:2; /* type of work for pfm_handle_work */ ++ unsigned int mmap_nlock:1; /* no lock in pfm_release_buf_space */ ++ unsigned int ia64_v20_compat:1; /* context is IA-64 v2.0 mode */ ++ unsigned int can_restart:8; /* allowed to issue a PFM_RESTART */ ++ unsigned int reset_count:8; /* number of pending resets */ ++ unsigned int is_self:1; /* per-thread and self-montoring */ ++ unsigned int reserved:5; /* for future use */ ++}; ++ ++/* ++ * values for work_type (TIF_PERFMON_WORK must be set) ++ */ ++#define PFM_WORK_NONE 0 /* nothing to do */ ++#define PFM_WORK_RESET 1 /* reset overflowed counters */ ++#define PFM_WORK_BLOCK 2 /* block current thread */ ++#define PFM_WORK_ZOMBIE 3 /* cleanup zombie context */ ++ ++/* ++ * overflow description argument passed to sampling format ++ */ ++struct pfm_ovfl_arg { ++ u16 ovfl_pmd; /* index of overflowed PMD */ ++ u16 active_set; /* set active at the time of the overflow */ ++ u32 ovfl_ctrl; /* control flags */ ++ u64 pmd_last_reset; /* last reset value of overflowed PMD */ ++ u64 smpl_pmds_values[PFM_MAX_PMDS]; /* values of other PMDs */ ++ u64 pmd_eventid; /* eventid associated with PMD */ ++ u16 num_smpl_pmds; /* number of PMDS in smpl_pmd_values */ ++}; ++/* ++ * depth of message queue ++ * ++ * Depth cannot be bigger than 255 (see reset_count) ++ */ ++#define PFM_MSGS_ORDER 3 /* log2(number of messages) */ ++#define PFM_MSGS_COUNT (1</proc/sys/kernel/printk_ratelimit ++ * ++ * debug is a bitmask where bits are defined as follows: ++ * bit 0: enable non-interrupt code degbug messages ++ * bit 1: enable interrupt code debug messages ++ */ ++#ifdef CONFIG_PERFMON_DEBUG ++#define _PFM_DBG(lm, f, x...) \ ++ do { \ ++ if (unlikely((pfm_controls.debug & lm) && printk_ratelimit())) { \ ++ preempt_disable(); \ ++ printk("perfmon: %s.%d: CPU%d [%d]: " f "\n", \ ++ __func__, __LINE__, \ ++ smp_processor_id(), current->pid , ## x); \ ++ preempt_enable(); \ ++ } \ ++ } while (0) ++ ++#define PFM_DBG(f, x...) _PFM_DBG(0x1, f, ##x) ++#define PFM_DBG_ovfl(f, x...) _PFM_DBG(0x2, f, ## x) ++#else ++#define PFM_DBG(f, x...) do {} while (0) ++#define PFM_DBG_ovfl(f, x...) do {} while (0) ++#endif ++ ++extern struct pfm_pmu_config *pfm_pmu_conf; ++extern int perfmon_disabled; ++ ++static inline struct pfm_arch_context *pfm_ctx_arch(struct pfm_context *c) ++{ ++ return (struct pfm_arch_context *)(c+1); ++} ++ ++int pfm_get_args(void __user *ureq, size_t sz, size_t lsz, void *laddr, ++ void **req, void **to_free); ++ ++int pfm_get_smpl_arg(char __user *fmt_uname, void __user *uaddr, size_t usize, ++ void **arg, struct pfm_smpl_fmt **fmt); ++ ++int __pfm_write_pmcs(struct pfm_context *ctx, struct pfarg_pmc *req, ++ int count); ++int __pfm_write_pmds(struct pfm_context *ctx, struct pfarg_pmd *req, int count, ++ int compat); ++int __pfm_read_pmds(struct pfm_context *ctx, struct pfarg_pmd *req, int count); ++ ++int __pfm_load_context(struct pfm_context *ctx, struct pfarg_load *req, ++ struct task_struct *task); ++int __pfm_unload_context(struct pfm_context *ctx, int *can_release); ++ ++int __pfm_stop(struct pfm_context *ctx, int *release_info); ++int __pfm_restart(struct pfm_context *ctx, int *unblock); ++int __pfm_start(struct pfm_context *ctx, struct pfarg_start *start); ++ ++void pfm_free_context(struct pfm_context *ctx); ++ ++void pfm_smpl_buf_space_release(struct pfm_context *ctx, size_t size); ++ ++int pfm_check_task_state(struct pfm_context *ctx, int check_mask, ++ unsigned long *flags, void **resume); ++/* ++ * check_mask bitmask values for pfm_check_task_state() ++ */ ++#define PFM_CMD_STOPPED 0x01 /* command needs thread stopped */ ++#define PFM_CMD_UNLOADED 0x02 /* command needs ctx unloaded */ ++#define PFM_CMD_UNLOAD 0x04 /* command is unload */ ++ ++int __pfm_create_context(struct pfarg_ctx *req, ++ struct pfm_smpl_fmt *fmt, ++ void *fmt_arg, ++ int mode, ++ struct pfm_context **new_ctx); ++ ++struct pfm_event_set *pfm_find_set(struct pfm_context *ctx, u16 set_id, ++ int alloc); ++ ++int pfm_pmu_conf_get(int autoload); ++void pfm_pmu_conf_put(void); ++ ++int pfm_session_allcpus_acquire(void); ++void pfm_session_allcpus_release(void); ++ ++int pfm_smpl_buf_alloc(struct pfm_context *ctx, size_t rsize); ++void pfm_smpl_buf_free(struct pfm_context *ctx); ++ ++struct pfm_smpl_fmt *pfm_smpl_fmt_get(char *name); ++void pfm_smpl_fmt_put(struct pfm_smpl_fmt *fmt); ++ ++void pfm_interrupt_handler(unsigned long iip, struct pt_regs *regs); ++ ++void pfm_resume_task(struct task_struct *t, void *data); ++ ++#include ++#include ++ ++extern const struct file_operations pfm_file_ops; ++/* ++ * upper limit for count in calls that take vector arguments. This is used ++ * to prevent for multiplication overflow when we compute actual storage size ++ */ ++#define PFM_MAX_ARG_COUNT(m) (INT_MAX/sizeof(*(m))) ++ ++#define cast_ulp(_x) ((unsigned long *)_x) ++ ++#define PFM_NORMAL 0 ++#define PFM_COMPAT 1 ++ ++void __pfm_exit_thread(void); ++void pfm_ctxsw_in(struct task_struct *prev, struct task_struct *next); ++void pfm_ctxsw_out(struct task_struct *prev, struct task_struct *next); ++void pfm_handle_work(struct pt_regs *regs); ++void __pfm_init_percpu(void *dummy); ++void pfm_save_pmds(struct pfm_context *ctx, struct pfm_event_set *set); ++ ++static inline void pfm_exit_thread(void) ++{ ++ if (current->pfm_context) ++ __pfm_exit_thread(); ++} ++ ++/* ++ * include arch-specific kernel level definitions ++ */ ++#include ++ ++static inline void pfm_copy_thread(struct task_struct *task) ++{ ++ /* ++ * context or perfmon TIF state is NEVER inherited ++ * in child task. Holds for per-thread and system-wide ++ */ ++ task->pfm_context = NULL; ++ clear_tsk_thread_flag(task, TIF_PERFMON_CTXSW); ++ clear_tsk_thread_flag(task, TIF_PERFMON_WORK); ++ pfm_arch_disarm_handle_work(task); ++} ++ ++ ++/* ++ * read a single PMD register. ++ * ++ * virtual PMD registers have special handler. ++ * Depends on definitions in asm/perfmon_kern.h ++ */ ++static inline u64 pfm_read_pmd(struct pfm_context *ctx, unsigned int cnum) ++{ ++ if (unlikely(pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_V)) ++ return pfm_pmu_conf->pmd_sread(ctx, cnum); ++ ++ return pfm_arch_read_pmd(ctx, cnum); ++} ++/* ++ * write a single PMD register. ++ * ++ * virtual PMD registers have special handler. ++ * Depends on definitions in asm/perfmon_kern.h ++ */ ++static inline void pfm_write_pmd(struct pfm_context *ctx, unsigned int cnum, ++ u64 value) ++{ ++ /* ++ * PMD writes are ignored for read-only registers ++ */ ++ if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_RO) ++ return; ++ ++ if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_V) { ++ pfm_pmu_conf->pmd_swrite(ctx, cnum, value); ++ return; ++ } ++ /* ++ * clear unimplemented bits ++ */ ++ value &= ~pfm_pmu_conf->pmd_desc[cnum].rsvd_msk; ++ ++ pfm_arch_write_pmd(ctx, cnum, value); ++} ++ ++void __pfm_init_percpu(void *dummy); ++ ++static inline void pfm_init_percpu(void) ++{ ++ __pfm_init_percpu(NULL); ++} ++ ++/* ++ * pfm statistics are available via debugfs ++ * and perfmon subdir. ++ * ++ * When adding/removing new stats, make sure you also ++ * update the name table in perfmon_debugfs.c ++ */ ++enum pfm_stats_names { ++ PFM_ST_ovfl_intr_all_count = 0, ++ PFM_ST_ovfl_intr_ns, ++ PFM_ST_ovfl_intr_spurious_count, ++ PFM_ST_ovfl_intr_replay_count, ++ PFM_ST_ovfl_intr_regular_count, ++ PFM_ST_handle_work_count, ++ PFM_ST_ovfl_notify_count, ++ PFM_ST_reset_pmds_count, ++ PFM_ST_pfm_restart_count, ++ PFM_ST_fmt_handler_calls, ++ PFM_ST_fmt_handler_ns, ++ PFM_ST_set_switch_count, ++ PFM_ST_set_switch_ns, ++ PFM_ST_set_switch_exp, ++ PFM_ST_ctxswin_count, ++ PFM_ST_ctxswin_ns, ++ PFM_ST_handle_timeout_count, ++ PFM_ST_ovfl_intr_nmi_count, ++ PFM_ST_ctxswout_count, ++ PFM_ST_ctxswout_ns, ++ PFM_ST_LAST /* last entry marked */ ++}; ++#define PFM_NUM_STATS PFM_ST_LAST ++ ++struct pfm_stats { ++ u64 v[PFM_NUM_STATS]; ++ struct dentry *dirs[PFM_NUM_STATS]; ++ struct dentry *cpu_dir; ++ char cpu_name[8]; ++}; ++ ++#ifdef CONFIG_PERFMON_DEBUG_FS ++#define pfm_stats_get(x) __get_cpu_var(pfm_stats).v[PFM_ST_##x] ++#define pfm_stats_inc(x) __get_cpu_var(pfm_stats).v[PFM_ST_##x]++ ++#define pfm_stats_add(x, y) __get_cpu_var(pfm_stats).v[PFM_ST_##x] += (y) ++void pfm_reset_stats(int cpu); ++#else ++#define pfm_stats_get(x) ++#define pfm_stats_inc(x) ++#define pfm_stats_add(x, y) ++static inline void pfm_reset_stats(int cpu) ++{} ++#endif ++ ++ ++ ++DECLARE_PER_CPU(struct pfm_context *, pmu_ctx); ++DECLARE_PER_CPU(struct pfm_stats, pfm_stats); ++DECLARE_PER_CPU(struct task_struct *, pmu_owner); ++ ++void pfm_cpu_disable(void); ++ ++ ++/* ++ * max vector argument elements for local storage (no kmalloc/kfree) ++ * The PFM_ARCH_PM*_ARG should be defined in perfmon_kern.h. ++ * If not, default (conservative) values are used ++ */ ++#ifndef PFM_ARCH_PMC_STK_ARG ++#define PFM_ARCH_PMC_STK_ARG 1 ++#endif ++ ++#ifndef PFM_ARCH_PMD_STK_ARG ++#define PFM_ARCH_PMD_STK_ARG 1 ++#endif ++ ++#define PFM_PMC_STK_ARG PFM_ARCH_PMC_STK_ARG ++#define PFM_PMD_STK_ARG PFM_ARCH_PMD_STK_ARG ++ ++#else /* !CONFIG_PERFMON */ ++ ++ ++/* ++ * perfmon hooks are nops when CONFIG_PERFMON is undefined ++ */ ++static inline void pfm_cpu_disable(void) ++{} ++ ++static inline void pfm_exit_thread(void) ++{} ++ ++static inline void pfm_handle_work(struct pt_regs *regs) ++{} ++ ++static inline void pfm_copy_thread(struct task_struct *t) ++{} ++ ++static inline void pfm_ctxsw_in(struct task_struct *p, struct task_struct *n) ++{} ++ ++static inline void pfm_ctxsw_out(struct task_struct *p, struct task_struct *n) ++{} ++ ++static inline void pfm_session_allcpus_release(void) ++{} ++ ++static inline int pfm_session_allcpus_acquire(void) ++{ ++ return 0; ++} ++ ++static inline void pfm_init_percpu(void) ++{} ++ ++#endif /* CONFIG_PERFMON */ ++ ++#endif /* __LINUX_PERFMON_KERN_H__ */ +--- /dev/null ++++ b/include/linux/perfmon_pmu.h +@@ -0,0 +1,192 @@ ++/* ++ * Copyright (c) 2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * Interface for PMU description modules ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#ifndef __PERFMON_PMU_H__ ++#define __PERFMON_PMU_H__ 1 ++ ++/* ++ * generic information about a PMC or PMD register ++ * ++ * Dependency bitmasks: ++ * They are used to allow lazy save/restore in the context switch ++ * code. To avoid picking up stale configuration from a previous ++ * thread. Usng the bitmask, the generic read/write routines can ++ * ensure that all registers needed to support the measurement are ++ * restored properly on context switch in. ++ */ ++struct pfm_regmap_desc { ++ u16 type; /* role of the register */ ++ u16 reserved1; /* for future use */ ++ u32 reserved2; /* for future use */ ++ u64 dfl_val; /* power-on default value (quiescent) */ ++ u64 rsvd_msk; /* reserved bits: 1 means reserved */ ++ u64 no_emul64_msk; /* bits to clear for PFM_REGFL_NO_EMUL64 */ ++ unsigned long hw_addr; /* HW register address or index */ ++ struct kobject kobj; /* for internal use only */ ++ char *desc; /* HW register description string */ ++ u64 dep_pmcs[PFM_PMC_BV];/* depending PMC registers */ ++}; ++#define to_reg(n) container_of(n, struct pfm_regmap_desc, kobj) ++ ++/* ++ * pfm_reg_desc helper macros ++ */ ++#define PMC_D(t, d, v, r, n, h) \ ++ { .type = t, \ ++ .desc = d, \ ++ .dfl_val = v, \ ++ .rsvd_msk = r, \ ++ .no_emul64_msk = n, \ ++ .hw_addr = h \ ++ } ++ ++#define PMD_D(t, d, h) \ ++ { .type = t, \ ++ .desc = d, \ ++ .rsvd_msk = 0, \ ++ .no_emul64_msk = 0, \ ++ .hw_addr = h \ ++ } ++ ++#define PMD_DR(t, d, h, r) \ ++ { .type = t, \ ++ .desc = d, \ ++ .rsvd_msk = r, \ ++ .no_emul64_msk = 0, \ ++ .hw_addr = h \ ++ } ++ ++#define PMX_NA \ ++ { .type = PFM_REG_NA } ++ ++#define PMD_DP(t, d, h, p) \ ++ { .type = t, \ ++ .desc = d, \ ++ .rsvd_msk = 0, \ ++ .no_emul64_msk = 0, \ ++ .dep_pmcs[0] = p, \ ++ .hw_addr = h \ ++ } ++ ++/* ++ * type of a PMU register (16-bit bitmask) for use with pfm_reg_desc.type ++ */ ++#define PFM_REG_NA 0x00 /* not avail. (not impl.,no access) must be 0 */ ++#define PFM_REG_I 0x01 /* PMC/PMD: implemented */ ++#define PFM_REG_WC 0x02 /* PMC: has write_checker */ ++#define PFM_REG_C64 0x04 /* PMD: 64-bit virtualization */ ++#define PFM_REG_RO 0x08 /* PMD: read-only (writes ignored) */ ++#define PFM_REG_V 0x10 /* PMD: virtual reg */ ++#define PFM_REG_INTR 0x20 /* PMD: register can generate interrupt */ ++#define PFM_REG_SYS 0x40 /* PMC/PMD: register is for system-wide only */ ++#define PFM_REG_THR 0x80 /* PMC/PMD: register is for per-thread only */ ++#define PFM_REG_NO64 0x100 /* PMC: supports PFM_REGFL_NO_EMUL64 */ ++ ++/* ++ * define some shortcuts for common types ++ */ ++#define PFM_REG_W (PFM_REG_WC|PFM_REG_I) ++#define PFM_REG_W64 (PFM_REG_WC|PFM_REG_NO64|PFM_REG_I) ++#define PFM_REG_C (PFM_REG_C64|PFM_REG_INTR|PFM_REG_I) ++#define PFM_REG_I64 (PFM_REG_NO64|PFM_REG_I) ++#define PFM_REG_IRO (PFM_REG_I|PFM_REG_RO) ++ ++typedef int (*pfm_pmc_check_t)(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmc *req); ++ ++typedef int (*pfm_pmd_check_t)(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_pmd *req); ++ ++ ++typedef u64 (*pfm_sread_t)(struct pfm_context *ctx, unsigned int cnum); ++typedef void (*pfm_swrite_t)(struct pfm_context *ctx, unsigned int cnum, u64 val); ++ ++/* ++ * structure used by pmu description modules ++ * ++ * probe_pmu() routine return value: ++ * - 1 means recognized PMU ++ * - 0 means not recognized PMU ++ */ ++struct pfm_pmu_config { ++ char *pmu_name; /* PMU family name */ ++ char *version; /* config module version */ ++ ++ int counter_width; /* width of hardware counter */ ++ ++ struct pfm_regmap_desc *pmc_desc; /* PMC register descriptions */ ++ struct pfm_regmap_desc *pmd_desc; /* PMD register descriptions */ ++ ++ pfm_pmc_check_t pmc_write_check;/* write checker (optional) */ ++ pfm_pmd_check_t pmd_write_check;/* write checker (optional) */ ++ pfm_pmd_check_t pmd_read_check; /* read checker (optional) */ ++ ++ pfm_sread_t pmd_sread; /* virtual pmd read */ ++ pfm_swrite_t pmd_swrite; /* virtual pmd write */ ++ ++ int (*probe_pmu)(void);/* probe PMU routine */ ++ ++ u16 num_pmc_entries;/* #entries in pmc_desc */ ++ u16 num_pmd_entries;/* #entries in pmd_desc */ ++ ++ void *pmu_info; /* model-specific infos */ ++ u32 flags; /* set of flags */ ++ ++ struct module *owner; /* pointer to module struct */ ++ ++ /* ++ * fields computed internally, do not set in module ++ */ ++ struct pfm_regdesc regs_all; /* regs available to all */ ++ struct pfm_regdesc regs_thr; /* regs avail per-thread */ ++ struct pfm_regdesc regs_sys; /* regs avail system-wide */ ++ ++ u64 ovfl_mask; /* overflow mask */ ++}; ++ ++static inline void *pfm_pmu_info(void) ++{ ++ return pfm_pmu_conf->pmu_info; ++} ++ ++/* ++ * pfm_pmu_config flags ++ */ ++#define PFM_PMUFL_IS_BUILTIN 0x1 /* pmu config is compiled in */ ++ ++/* ++ * we need to know whether the PMU description is builtin or compiled ++ * as a module ++ */ ++#ifdef MODULE ++#define PFM_PMU_BUILTIN_FLAG 0 /* not built as a module */ ++#else ++#define PFM_PMU_BUILTIN_FLAG PFM_PMUFL_IS_BUILTIN /* built as a module */ ++#endif ++ ++int pfm_pmu_register(struct pfm_pmu_config *cfg); ++void pfm_pmu_unregister(struct pfm_pmu_config *cfg); ++ ++int pfm_sysfs_remove_pmu(struct pfm_pmu_config *pmu); ++int pfm_sysfs_add_pmu(struct pfm_pmu_config *pmu); ++ ++#endif /* __PERFMON_PMU_H__ */ +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -96,6 +96,7 @@ struct exec_domain; + struct futex_pi_state; + struct robust_list_head; + struct bio; ++struct pfm_context; + + /* + * List of flags we want to share for kernel threads, +@@ -1309,6 +1310,9 @@ struct task_struct { + struct latency_record latency_record[LT_SAVECOUNT]; + #endif + u64 instrumentation; ++#ifdef CONFIG_PERFMON ++ struct pfm_context *pfm_context; ++#endif + }; + + /* +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -29,6 +29,13 @@ struct msqid_ds; + struct new_utsname; + struct nfsctl_arg; + struct __old_kernel_stat; ++struct pfarg_ctx; ++struct pfarg_pmc; ++struct pfarg_pmd; ++struct pfarg_start; ++struct pfarg_load; ++struct pfarg_setinfo; ++struct pfarg_setdesc; + struct pollfd; + struct rlimit; + struct rusage; +@@ -690,4 +697,27 @@ asmlinkage long sys_pipe(int __user *); + + int kernel_execve(const char *filename, char *const argv[], char *const envp[]); + ++asmlinkage long sys_pfm_create_context(struct pfarg_ctx __user *ureq, ++ void __user *uarg, size_t smpl_size); ++asmlinkage long sys_pfm_write_pmcs(int fd, struct pfarg_pmc __user *ureq, ++ int count); ++asmlinkage long sys_pfm_write_pmds(int fd, struct pfarg_pmd __user *ureq, ++ int count); ++asmlinkage long sys_pfm_read_pmds(int fd, struct pfarg_pmd __user *ureq, ++ int count); ++asmlinkage long sys_pfm_restart(int fd); ++asmlinkage long sys_pfm_stop(int fd); ++asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *ureq); ++asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ureq); ++asmlinkage long sys_pfm_unload_context(int fd); ++asmlinkage long sys_pfm_delete_evtsets(int fd, ++ struct pfarg_setinfo __user *ureq, ++ int count); ++asmlinkage long sys_pfm_create_evtsets(int fd, ++ struct pfarg_setdesc __user *ureq, ++ int count); ++asmlinkage long sys_pfm_getinfo_evtsets(int fd, ++ struct pfarg_setinfo __user *ureq, ++ int count); ++ + #endif +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + + #include + #include +--- a/kernel/sys_ni.c ++++ b/kernel/sys_ni.c +@@ -127,6 +127,19 @@ cond_syscall(compat_sys_ipc); + cond_syscall(compat_sys_sysctl); + cond_syscall(sys_syslog); + ++cond_syscall(sys_pfm_create_context); ++cond_syscall(sys_pfm_write_pmcs); ++cond_syscall(sys_pfm_write_pmds); ++cond_syscall(sys_pfm_read_pmds); ++cond_syscall(sys_pfm_restart); ++cond_syscall(sys_pfm_start); ++cond_syscall(sys_pfm_stop); ++cond_syscall(sys_pfm_load_context); ++cond_syscall(sys_pfm_unload_context); ++cond_syscall(sys_pfm_create_evtsets); ++cond_syscall(sys_pfm_delete_evtsets); ++cond_syscall(sys_pfm_getinfo_evtsets); ++ + /* arch-specific weak syscall entries */ + cond_syscall(sys_pciconfig_read); + cond_syscall(sys_pciconfig_write); +--- /dev/null ++++ b/perfmon/Makefile +@@ -0,0 +1,12 @@ ++# ++# Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. ++# Contributed by Stephane Eranian ++# ++obj-y = perfmon_init.o perfmon_rw.o perfmon_res.o \ ++ perfmon_pmu.o perfmon_sysfs.o perfmon_syscalls.o \ ++ perfmon_file.o perfmon_ctxsw.o perfmon_intr.o \ ++ perfmon_dfl_smpl.o perfmon_sets.o perfmon_hotplug.o \ ++ perfmon_msg.o perfmon_smpl.o perfmon_attach.o \ ++ perfmon_activate.o perfmon_ctx.o perfmon_fmt.o ++ ++obj-$(CONFIG_PERFMON_DEBUG_FS) += perfmon_debugfs.o +--- /dev/null ++++ b/perfmon/perfmon_activate.c +@@ -0,0 +1,265 @@ ++/* ++ * perfmon_activate.c: perfmon2 start/stop functions ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include "perfmon_priv.h" ++ ++/** ++ * __pfm_start - activate monitoring ++ * @ctx: context to operate on ++ * @start: pfarg_start as passed by user ++ * ++ * When operating in per-thread mode and not self-monitoring, the monitored ++ * thread must be stopped. Activation will be effective next time the thread ++ * is context switched in. ++ * ++ * The pfarg_start argument is optional and may be used to designate ++ * the initial event set to activate. When not provided, the last active ++ * set is used. For the first activation, set0 is used when start is NULL. ++ * ++ * On some architectures, e.g., IA-64, it may be possible to start monitoring ++ * without calling this function under certain conditions (per-thread and self ++ * monitoring). In this case, either set0 or the last active set is used. ++ * ++ * the context is locked and interrupts are disabled. ++ */ ++int __pfm_start(struct pfm_context *ctx, struct pfarg_start *start) ++{ ++ struct task_struct *task, *owner_task; ++ struct pfm_event_set *new_set, *old_set; ++ int is_self; ++ ++ task = ctx->task; ++ ++ /* ++ * UNLOADED: error ++ * LOADED : normal start, nop if started unless set is different ++ * MASKED : nop or change set when unmasking ++ * ZOMBIE : cannot happen ++ */ ++ if (ctx->state == PFM_CTX_UNLOADED) ++ return -EINVAL; ++ ++ old_set = new_set = ctx->active_set; ++ ++ /* ++ * always the case for system-wide ++ */ ++ if (task == NULL) ++ task = current; ++ ++ is_self = task == current; ++ ++ /* ++ * argument is provided? ++ */ ++ if (start) { ++ /* ++ * find the set to load first ++ */ ++ new_set = pfm_find_set(ctx, start->start_set, 0); ++ if (new_set == NULL) { ++ PFM_DBG("event set%u does not exist", ++ start->start_set); ++ return -EINVAL; ++ } ++ } ++ ++ PFM_DBG("cur_set=%u req_set=%u", old_set->id, new_set->id); ++ ++ /* ++ * if we need to change the active set we need ++ * to check if we can access the PMU ++ */ ++ if (new_set != old_set) { ++ ++ owner_task = __get_cpu_var(pmu_owner); ++ /* ++ * system-wide: must run on the right CPU ++ * per-thread : must be the owner of the PMU context ++ * ++ * pfm_switch_sets() returns with monitoring stopped ++ */ ++ if (is_self) { ++ pfm_switch_sets(ctx, new_set, PFM_PMD_RESET_LONG, 1); ++ } else { ++ /* ++ * In a UP kernel, the PMU may contain the state ++ * of the task we want to operate on, yet the task ++ * may be switched out (lazy save). We need to save ++ * current state (old_set), switch active_set and ++ * mark it for reload. ++ */ ++ if (owner_task == task) ++ pfm_save_pmds(ctx, old_set); ++ ctx->active_set = new_set; ++ new_set->priv_flags |= PFM_SETFL_PRIV_MOD_BOTH; ++ } ++ } ++ ++ /* ++ * mark as started ++ * must be done before calling pfm_arch_start() ++ */ ++ ctx->flags.started = 1; ++ ++ pfm_arch_start(task, ctx); ++ ++ /* ++ * we check whether we had a pending ovfl before restarting. ++ * If so we need to regenerate the interrupt to make sure we ++ * keep recorded samples. For non-self monitoring this check ++ * is done in the pfm_ctxswin_thread() routine. ++ * ++ * we check new_set/old_set because pfm_switch_sets() already ++ * takes care of replaying the pending interrupts ++ */ ++ if (is_self && new_set != old_set && new_set->npend_ovfls) { ++ pfm_arch_resend_irq(ctx); ++ pfm_stats_inc(ovfl_intr_replay_count); ++ } ++ ++ /* ++ * always start with full timeout ++ */ ++ new_set->hrtimer_rem = new_set->hrtimer_exp; ++ ++ /* ++ * activate timeout for system-wide, self-montoring ++ * Always start with full timeout ++ * Timeout is at least one tick away, so no risk of ++ * having hrtimer_start() trying to wakeup softirqd ++ * and thus causing troubles. This cannot happen anmyway ++ * because cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ ++ */ ++ if (is_self && new_set->flags & PFM_SETFL_TIME_SWITCH) { ++ hrtimer_start(&__get_cpu_var(pfm_hrtimer), ++ new_set->hrtimer_rem, ++ HRTIMER_MODE_REL); ++ ++ PFM_DBG("set%u started timeout=%lld", ++ new_set->id, ++ (unsigned long long)new_set->hrtimer_rem.tv64); ++ } ++ ++ /* ++ * we restart total duration even if context was ++ * already started. In that case, counts are simply ++ * reset. ++ * ++ * For per-thread, if not self-monitoring, the statement ++ * below will have no effect because thread is stopped. ++ * The field is reset of ctxsw in. ++ */ ++ new_set->duration_start = sched_clock(); ++ ++ return 0; ++} ++ ++/** ++ * __pfm_stop - stop monitoring ++ * @ctx: context to operate on ++ * @release_info: infos for caller (see below) ++ * ++ * When operating in per-thread* mode and when not self-monitoring, ++ * the monitored thread must be stopped. ++ * ++ * the context is locked and interrupts are disabled. ++ * ++ * release_info value upon return: ++ * - bit 0 : unused ++ * - bit 1 : when set, must cancel hrtimer ++ */ ++int __pfm_stop(struct pfm_context *ctx, int *release_info) ++{ ++ struct pfm_event_set *set; ++ struct task_struct *task; ++ u64 now; ++ int state; ++ ++ *release_info = 0; ++ ++ now = sched_clock(); ++ state = ctx->state; ++ set = ctx->active_set; ++ ++ /* ++ * context must be attached (zombie cannot happen) ++ */ ++ if (state == PFM_CTX_UNLOADED) ++ return -EINVAL; ++ ++ task = ctx->task; ++ ++ PFM_DBG("ctx_task=[%d] ctx_state=%d is_system=%d", ++ task ? task->pid : -1, ++ state, ++ !task); ++ ++ /* ++ * this happens for system-wide context ++ */ ++ if (task == NULL) ++ task = current; ++ ++ /* ++ * compute elapsed time ++ * ++ * unless masked, compute elapsed duration, stop timeout ++ */ ++ if (task == current && state == PFM_CTX_LOADED) { ++ /* ++ * timeout cancel must be deferred until context is ++ * unlocked to avoid race with pfm_handle_switch_timeout() ++ */ ++ if (set->flags & PFM_SETFL_TIME_SWITCH) ++ *release_info |= 0x2; ++ ++ set->duration += now - set->duration_start; ++ } ++ ++ pfm_arch_stop(task, ctx); ++ ++ ctx->flags.started = 0; ++ /* ++ * starting now, in-flight PMU interrupt for this context ++ * are treated as spurious ++ */ ++ return 0; ++} +--- /dev/null ++++ b/perfmon/perfmon_attach.c +@@ -0,0 +1,474 @@ ++/* ++ * perfmon_attach.c: perfmon2 load/unload functions ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++/** ++ * __pfm_load_context_sys - attach context to a CPU in system-wide mode ++ * @ctx: context to operate on ++ * @set_id: set to activate first ++ * @cpu: CPU to monitor ++ * ++ * The cpu specified in the pfarg_load.load_pid argument must be the current ++ * CPU. ++ * ++ * The function must be called with the context locked and interrupts disabled. ++ */ ++static int pfm_load_ctx_sys(struct pfm_context *ctx, u16 set_id, u32 cpu) ++{ ++ struct pfm_event_set *set; ++ int mycpu; ++ int ret; ++ ++ mycpu = smp_processor_id(); ++ ++ /* ++ * system-wide: check we are running on the desired CPU ++ */ ++ if (cpu != mycpu) { ++ PFM_DBG("wrong CPU: asking %u but on %u", cpu, mycpu); ++ return -EINVAL; ++ } ++ ++ /* ++ * initialize sets ++ */ ++ set = pfm_prepare_sets(ctx, set_id); ++ if (!set) { ++ PFM_DBG("event set%u does not exist", set_id); ++ return -EINVAL; ++ } ++ ++ PFM_DBG("set=%u set_flags=0x%x", set->id, set->flags); ++ ++ ctx->cpu = mycpu; ++ ctx->task = NULL; ++ ctx->active_set = set; ++ ++ /* ++ * perform any architecture specific actions ++ */ ++ ret = pfm_arch_load_context(ctx); ++ if (ret) ++ goto error_noload; ++ ++ /* ++ * now reserve the session, before we can proceed with ++ * actually accessing the PMU hardware ++ */ ++ ret = pfm_session_acquire(1, mycpu); ++ if (ret) ++ goto error; ++ ++ ++ /* ++ * caller must be on monitored CPU to access PMU, thus this is ++ * a form of self-monitoring ++ */ ++ ctx->flags.is_self = 1; ++ ++ set->runs++; ++ ++ /* ++ * load PMD from set ++ * load PMC from set ++ */ ++ pfm_arch_restore_pmds(ctx, set); ++ pfm_arch_restore_pmcs(ctx, set); ++ ++ /* ++ * set new ownership ++ */ ++ pfm_set_pmu_owner(NULL, ctx); ++ ++ /* ++ * reset pending work ++ */ ++ ctx->flags.work_type = PFM_WORK_NONE; ++ ctx->flags.reset_count = 0; ++ ++ /* ++ * reset message queue ++ */ ++ ctx->msgq_head = ctx->msgq_tail = 0; ++ ++ ctx->state = PFM_CTX_LOADED; ++ ++ return 0; ++error: ++ pfm_arch_unload_context(ctx); ++error_noload: ++ return ret; ++} ++ ++/** ++ * __pfm_load_context_thread - attach context to a thread ++ * @ctx: context to operate on ++ * @set_id: first set ++ * @task: threadf to attach to ++ * ++ * The function must be called with the context locked and interrupts disabled. ++ */ ++static int pfm_load_ctx_thread(struct pfm_context *ctx, u16 set_id, ++ struct task_struct *task) ++{ ++ struct pfm_event_set *set; ++ struct pfm_context *old; ++ int ret; ++ ++ PFM_DBG("load_pid=%d set=%u", task->pid, set_id); ++ /* ++ * per-thread: ++ * - task to attach to is checked in sys_pfm_load_context() to avoid ++ * locking issues. if found, and not self, task refcount was ++ * incremented. ++ */ ++ old = cmpxchg(&task->pfm_context, NULL, ctx); ++ if (old) { ++ PFM_DBG("load_pid=%d has a context " ++ "old=%p new=%p cur=%p", ++ task->pid, ++ old, ++ ctx, ++ task->pfm_context); ++ return -EEXIST; ++ } ++ ++ /* ++ * initialize sets ++ */ ++ set = pfm_prepare_sets(ctx, set_id); ++ if (!set) { ++ PFM_DBG("event set%u does not exist", set_id); ++ return -EINVAL; ++ } ++ ++ ++ ctx->task = task; ++ ctx->cpu = -1; ++ ctx->active_set = set; ++ ++ /* ++ * perform any architecture specific actions ++ */ ++ ret = pfm_arch_load_context(ctx); ++ if (ret) ++ goto error_noload; ++ ++ /* ++ * now reserve the session, before we can proceed with ++ * actually accessing the PMU hardware ++ */ ++ ret = pfm_session_acquire(0, -1); ++ if (ret) ++ goto error; ++ ++ ++ set->runs++; ++ if (ctx->task != current) { ++ ++ ctx->flags.is_self = 0; ++ ++ /* force a full reload */ ++ ctx->last_act = PFM_INVALID_ACTIVATION; ++ ctx->last_cpu = -1; ++ set->priv_flags |= PFM_SETFL_PRIV_MOD_BOTH; ++ ++ } else { ++ pfm_check_save_prev_ctx(); ++ ++ ctx->last_cpu = smp_processor_id(); ++ __get_cpu_var(pmu_activation_number)++; ++ ctx->last_act = __get_cpu_var(pmu_activation_number); ++ ++ ctx->flags.is_self = 1; ++ ++ /* ++ * load PMD from set ++ * load PMC from set ++ */ ++ pfm_arch_restore_pmds(ctx, set); ++ pfm_arch_restore_pmcs(ctx, set); ++ ++ /* ++ * set new ownership ++ */ ++ pfm_set_pmu_owner(ctx->task, ctx); ++ } ++ set_tsk_thread_flag(task, TIF_PERFMON_CTXSW); ++ ++ /* ++ * reset pending work ++ */ ++ ctx->flags.work_type = PFM_WORK_NONE; ++ ctx->flags.reset_count = 0; ++ ++ /* ++ * reset message queue ++ */ ++ ctx->msgq_head = ctx->msgq_tail = 0; ++ ++ ctx->state = PFM_CTX_LOADED; ++ ++ return 0; ++ ++error: ++ pfm_arch_unload_context(ctx); ++ ctx->task = NULL; ++error_noload: ++ /* ++ * detach context ++ */ ++ task->pfm_context = NULL; ++ return ret; ++} ++ ++/** ++ * __pfm_load_context - attach context to a CPU or thread ++ * @ctx: context to operate on ++ * @load: pfarg_load as passed by user ++ * @task: thread to attach to, NULL for system-wide ++ */ ++int __pfm_load_context(struct pfm_context *ctx, struct pfarg_load *load, ++ struct task_struct *task) ++{ ++ if (ctx->flags.system) ++ return pfm_load_ctx_sys(ctx, load->load_set, load->load_pid); ++ return pfm_load_ctx_thread(ctx, load->load_set, task); ++} ++ ++/** ++ * pfm_update_ovfl_pmds - account for pending ovfls on PMDs ++ * @ctx: context to operate on ++ * ++ * This function is always called after pfm_stop has been issued ++ */ ++static void pfm_update_ovfl_pmds(struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ u64 *cnt_pmds; ++ u64 ovfl_mask; ++ u16 num_ovfls, i, first; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ first = ctx->regs.first_intr_pmd; ++ cnt_pmds = ctx->regs.cnt_pmds; ++ ++ /* ++ * look for pending interrupts and adjust PMD values accordingly ++ */ ++ list_for_each_entry(set, &ctx->set_list, list) { ++ ++ if (!set->npend_ovfls) ++ continue; ++ ++ num_ovfls = set->npend_ovfls; ++ PFM_DBG("set%u nintrs=%u", set->id, num_ovfls); ++ ++ for (i = first; num_ovfls; i++) { ++ if (test_bit(i, cast_ulp(set->povfl_pmds))) { ++ /* only correct value for counters */ ++ if (test_bit(i, cast_ulp(cnt_pmds))) ++ set->pmds[i].value += 1 + ovfl_mask; ++ num_ovfls--; ++ } ++ PFM_DBG("pmd%u set=%u val=0x%llx", ++ i, ++ set->id, ++ (unsigned long long)set->pmds[i].value); ++ } ++ /* ++ * we need to clear to prevent a pfm_getinfo_evtsets() from ++ * returning stale data even after the context is unloaded ++ */ ++ set->npend_ovfls = 0; ++ bitmap_zero(cast_ulp(set->povfl_pmds), ctx->regs.max_intr_pmd); ++ } ++} ++ ++ ++/** ++ * __pfm_unload_context - detach context from CPU or thread ++ * @ctx: context to operate on ++ * @release_info: pointer to return info (see below) ++ * ++ * The function must be called with the context locked and interrupts disabled. ++ * ++ * release_info value upon return: ++ * - bit 0: when set, must free context ++ * - bit 1: when set, must cancel hrtimer ++ */ ++int __pfm_unload_context(struct pfm_context *ctx, int *release_info) ++{ ++ struct task_struct *task; ++ int ret; ++ ++ PFM_DBG("ctx_state=%d task [%d]", ++ ctx->state, ++ ctx->task ? ctx->task->pid : -1); ++ ++ *release_info = 0; ++ ++ /* ++ * unload only when necessary ++ */ ++ if (ctx->state == PFM_CTX_UNLOADED) ++ return 0; ++ ++ task = ctx->task; ++ ++ /* ++ * stop monitoring ++ */ ++ ret = __pfm_stop(ctx, release_info); ++ if (ret) ++ return ret; ++ ++ ctx->state = PFM_CTX_UNLOADED; ++ ctx->flags.can_restart = 0; ++ ++ /* ++ * save active set ++ * UP: ++ * if not current task and due to lazy, state may ++ * still be live ++ * for system-wide, guaranteed to run on correct CPU ++ */ ++ if (__get_cpu_var(pmu_ctx) == ctx) { ++ /* ++ * pending overflows have been saved by pfm_stop() ++ */ ++ pfm_save_pmds(ctx, ctx->active_set); ++ pfm_set_pmu_owner(NULL, NULL); ++ PFM_DBG("released ownership"); ++ } ++ ++ /* ++ * account for pending overflows ++ */ ++ pfm_update_ovfl_pmds(ctx); ++ ++ /* ++ * arch-specific unload operations ++ */ ++ pfm_arch_unload_context(ctx); ++ ++ /* ++ * per-thread: disconnect from monitored task ++ */ ++ if (task) { ++ task->pfm_context = NULL; ++ ctx->task = NULL; ++ clear_tsk_thread_flag(task, TIF_PERFMON_CTXSW); ++ clear_tsk_thread_flag(task, TIF_PERFMON_WORK); ++ pfm_arch_disarm_handle_work(task); ++ } ++ /* ++ * session can be freed, must have interrupts enabled ++ * thus we release in the caller. Bit 0 signals to the ++ * caller that the session can be released. ++ */ ++ *release_info |= 0x1; ++ ++ return 0; ++} ++ ++/** ++ * __pfm_exit_thread - detach and free context on thread exit ++ */ ++void __pfm_exit_thread(void) ++{ ++ struct pfm_context *ctx; ++ unsigned long flags; ++ int free_ok = 0, release_info = 0; ++ int ret; ++ ++ ctx = current->pfm_context; ++ ++ BUG_ON(ctx->flags.system); ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ PFM_DBG("state=%d is_self=%d", ctx->state, ctx->flags.is_self); ++ ++ /* ++ * __pfm_unload_context() cannot fail ++ * in the context states we are interested in ++ */ ++ switch (ctx->state) { ++ case PFM_CTX_LOADED: ++ case PFM_CTX_MASKED: ++ __pfm_unload_context(ctx, &release_info); ++ /* ++ * end notification only sent for non ++ * self-monitoring context ++ */ ++ if (!ctx->flags.is_self) ++ pfm_end_notify(ctx); ++ break; ++ case PFM_CTX_ZOMBIE: ++ __pfm_unload_context(ctx, &release_info); ++ free_ok = 1; ++ break; ++ default: ++ BUG_ON(ctx->state != PFM_CTX_LOADED); ++ break; ++ } ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ /* ++ * cancel timer now that context is unlocked ++ */ ++ if (release_info & 0x2) { ++ ret = hrtimer_cancel(&__get_cpu_var(pfm_hrtimer)); ++ PFM_DBG("timeout cancel=%d", ret); ++ } ++ ++ if (release_info & 0x1) ++ pfm_session_release(0, 0); ++ ++ /* ++ * All memory free operations (especially for vmalloc'ed memory) ++ * MUST be done with interrupts ENABLED. ++ */ ++ if (free_ok) ++ pfm_free_context(ctx); ++} +--- /dev/null ++++ b/perfmon/perfmon_ctx.c +@@ -0,0 +1,314 @@ ++/* ++ * perfmon_ctx.c: perfmon2 context functions ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++/* ++ * context memory pool pointer ++ */ ++static struct kmem_cache *pfm_ctx_cachep; ++ ++/** ++ * pfm_free_context - de-allocate context and associated resources ++ * @ctx: context to free ++ */ ++void pfm_free_context(struct pfm_context *ctx) ++{ ++ pfm_arch_context_free(ctx); ++ ++ pfm_free_sets(ctx); ++ ++ pfm_smpl_buf_free(ctx); ++ ++ PFM_DBG("free ctx @0x%p", ctx); ++ kmem_cache_free(pfm_ctx_cachep, ctx); ++ /* ++ * decrease refcount on: ++ * - PMU description table ++ * - sampling format ++ */ ++ pfm_pmu_conf_put(); ++ pfm_pmu_release(); ++} ++ ++/** ++ * pfm_ctx_flags_sane - check if context flags passed by user are okay ++ * @ctx_flags: flags passed user on pfm_create_context ++ * ++ * return: ++ * 0 if successful ++ * <0 and error code otherwise ++ */ ++static inline int pfm_ctx_flags_sane(u32 ctx_flags) ++{ ++ if (ctx_flags & PFM_FL_SYSTEM_WIDE) { ++ if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { ++ PFM_DBG("cannot use blocking mode in syswide mode"); ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * pfm_ctx_permissions - check authorization to create new context ++ * @ctx_flags: context flags passed by user ++ * ++ * check for permissions to create a context. ++ * ++ * A sysadmin may decide to restrict creation of per-thread ++ * and/or system-wide context to a group of users using the ++ * group id via /sys/kernel/perfmon/task_group and ++ * /sys/kernel/perfmon/sys_group. ++ * ++ * Once we identify a user level package which can be used ++ * to grant/revoke Linux capabilites at login via PAM, we will ++ * be able to use capabilities. We would also need to increase ++ * the size of cap_t to support more than 32 capabilities (it ++ * is currently defined as u32 and 32 capabilities are alrady ++ * defined). ++ */ ++static inline int pfm_ctx_permissions(u32 ctx_flags) ++{ ++ if ((ctx_flags & PFM_FL_SYSTEM_WIDE) ++ && pfm_controls.sys_group != PFM_GROUP_PERM_ANY ++ && !in_group_p(pfm_controls.sys_group)) { ++ PFM_DBG("user group not allowed to create a syswide ctx"); ++ return -EPERM; ++ } else if (pfm_controls.task_group != PFM_GROUP_PERM_ANY ++ && !in_group_p(pfm_controls.task_group)) { ++ PFM_DBG("user group not allowed to create a task context"); ++ return -EPERM; ++ } ++ return 0; ++} ++ ++/** ++ * __pfm_create_context - allocate and initialize a perfmon context ++ * @req : pfarg_ctx from user ++ * @fmt : pointer sampling format, NULL if not used ++ * @fmt_arg: pointer to argument to sampling format, NULL if not used ++ * @mode: PFM_NORMAL or PFM_COMPAT(IA-64 v2.0 compatibility) ++ * @ctx : address of new context upon succesful return, undefined otherwise ++ * ++ * function used to allocate a new context. A context is allocated along ++ * with the default event set. If a sampling format is used, the buffer ++ * may be allocated and initialized. ++ * ++ * The file descriptor identifying the context is allocated and returned ++ * to caller. ++ * ++ * This function operates with no locks and interrupts are enabled. ++ * return: ++ * >=0: the file descriptor to identify the context ++ * <0 : the error code ++ */ ++int __pfm_create_context(struct pfarg_ctx *req, ++ struct pfm_smpl_fmt *fmt, ++ void *fmt_arg, ++ int mode, ++ struct pfm_context **new_ctx) ++{ ++ struct pfm_context *ctx; ++ struct file *filp = NULL; ++ u32 ctx_flags; ++ int fd = 0, ret; ++ ++ ctx_flags = req->ctx_flags; ++ ++ /* Increase refcount on PMU description */ ++ ret = pfm_pmu_conf_get(1); ++ if (ret < 0) ++ goto error_conf; ++ ++ ret = pfm_ctx_flags_sane(ctx_flags); ++ if (ret < 0) ++ goto error_alloc; ++ ++ ret = pfm_ctx_permissions(ctx_flags); ++ if (ret < 0) ++ goto error_alloc; ++ ++ /* ++ * we can use GFP_KERNEL and potentially sleep because we do ++ * not hold any lock at this point. ++ */ ++ might_sleep(); ++ ret = -ENOMEM; ++ ctx = kmem_cache_zalloc(pfm_ctx_cachep, GFP_KERNEL); ++ if (!ctx) ++ goto error_alloc; ++ ++ PFM_DBG("alloc ctx @0x%p", ctx); ++ ++ INIT_LIST_HEAD(&ctx->set_list); ++ spin_lock_init(&ctx->lock); ++ init_completion(&ctx->restart_complete); ++ init_waitqueue_head(&ctx->msgq_wait); ++ ++ /* ++ * context is unloaded ++ */ ++ ctx->state = PFM_CTX_UNLOADED; ++ ++ /* ++ * initialization of context's flags ++ * must be done before pfm_find_set() ++ */ ++ ctx->flags.block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; ++ ctx->flags.system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; ++ ctx->flags.no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; ++ ctx->flags.ia64_v20_compat = mode == PFM_COMPAT ? 1 : 0; ++ ++ ret = pfm_pmu_acquire(ctx); ++ if (ret) ++ goto error_file; ++ /* ++ * check if PMU is usable ++ */ ++ if (!(ctx->regs.num_pmcs && ctx->regs.num_pmcs)) { ++ PFM_DBG("no usable PMU registers"); ++ ret = -EBUSY; ++ goto error_file; ++ } ++ ++ /* ++ * link to format, must be done first for correct ++ * error handling in pfm_context_free() ++ */ ++ ctx->smpl_fmt = fmt; ++ ++ ret = -ENFILE; ++ fd = pfm_alloc_fd(&filp); ++ if (fd < 0) ++ goto error_file; ++ ++ /* ++ * initialize arch-specific section ++ * must be done before fmt_init() ++ */ ++ ret = pfm_arch_context_create(ctx, ctx_flags); ++ if (ret) ++ goto error_set; ++ ++ ret = -ENOMEM; ++ ++ /* ++ * add initial set ++ */ ++ if (pfm_create_initial_set(ctx)) ++ goto error_set; ++ ++ /* ++ * does the user want to sample? ++ * must be done after pfm_pmu_acquire() because ++ * needs ctx->regs ++ */ ++ if (fmt) { ++ ret = pfm_setup_smpl_fmt(ctx, ctx_flags, fmt_arg, filp); ++ if (ret) ++ goto error_set; ++ } ++ ++ filp->private_data = ctx; ++ ++ ctx->last_act = PFM_INVALID_ACTIVATION; ++ ctx->last_cpu = -1; ++ ++ /* ++ * initialize notification message queue ++ */ ++ ctx->msgq_head = ctx->msgq_tail = 0; ++ ++ PFM_DBG("flags=0x%x system=%d notify_block=%d no_msg=%d" ++ " use_fmt=%d ctx_fd=%d mode=%d", ++ ctx_flags, ++ ctx->flags.system, ++ ctx->flags.block, ++ ctx->flags.no_msg, ++ !!fmt, ++ fd, mode); ++ ++ if (new_ctx) ++ *new_ctx = ctx; ++ ++ /* ++ * we defer the fd_install until we are certain the call succeeded ++ * to ensure we do not have to undo its effect. Neither put_filp() ++ * nor put_unused_fd() undoes the effect of fd_install(). ++ */ ++ fd_install(fd, filp); ++ ++ return fd; ++ ++error_set: ++ put_filp(filp); ++ put_unused_fd(fd); ++error_file: ++ /* ++ * calls the right *_put() functions ++ * calls pfm_release_pmu() ++ */ ++ pfm_free_context(ctx); ++ return ret; ++error_alloc: ++ pfm_pmu_conf_put(); ++error_conf: ++ pfm_smpl_fmt_put(fmt); ++ return ret; ++} ++ ++/** ++ * pfm_init_ctx -- initialize context SLAB ++ * ++ * called from pfm_init ++ */ ++int __init pfm_init_ctx(void) ++{ ++ pfm_ctx_cachep = kmem_cache_create("pfm_context", ++ sizeof(struct pfm_context)+PFM_ARCH_CTX_SIZE, ++ SLAB_HWCACHE_ALIGN, 0, NULL); ++ if (!pfm_ctx_cachep) { ++ PFM_ERR("cannot initialize context slab"); ++ return -ENOMEM; ++ } ++ return 0; ++} +--- /dev/null ++++ b/perfmon/perfmon_ctxsw.c +@@ -0,0 +1,342 @@ ++/* ++ * perfmon_cxtsw.c: perfmon2 context switch code ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include "perfmon_priv.h" ++ ++void pfm_save_pmds(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 val, ovfl_mask; ++ u64 *used_pmds, *cnt_pmds; ++ u16 i, num; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ num = set->nused_pmds; ++ cnt_pmds = ctx->regs.cnt_pmds; ++ used_pmds = set->used_pmds; ++ ++ /* ++ * save HW PMD, for counters, reconstruct 64-bit value ++ */ ++ for (i = 0; num; i++) { ++ if (test_bit(i, cast_ulp(used_pmds))) { ++ val = pfm_read_pmd(ctx, i); ++ if (likely(test_bit(i, cast_ulp(cnt_pmds)))) ++ val = (set->pmds[i].value & ~ovfl_mask) | ++ (val & ovfl_mask); ++ set->pmds[i].value = val; ++ num--; ++ } ++ } ++ pfm_arch_clear_pmd_ovfl_cond(ctx, set); ++} ++ ++/* ++ * interrupts are disabled (no preemption) ++ */ ++void __pfm_ctxswin_thread(struct task_struct *task, ++ struct pfm_context *ctx, u64 now) ++{ ++ u64 cur_act; ++ struct pfm_event_set *set; ++ int reload_pmcs, reload_pmds; ++ int mycpu, is_active; ++ ++ mycpu = smp_processor_id(); ++ ++ cur_act = __get_cpu_var(pmu_activation_number); ++ /* ++ * we need to lock context because it could be accessed ++ * from another CPU. Normally the schedule() functions ++ * has masked interrupts which should be enough to ++ * protect against PMU interrupts. ++ */ ++ spin_lock(&ctx->lock); ++ ++ is_active = pfm_arch_is_active(ctx); ++ ++ set = ctx->active_set; ++ ++ /* ++ * in case fo zombie, we do not complete ctswin of the ++ * PMU, and we force a call to pfm_handle_work() to finish ++ * cleanup, i.e., free context + smpl_buff. The reason for ++ * deferring to pfm_handle_work() is that it is not possible ++ * to vfree() with interrupts disabled. ++ */ ++ if (unlikely(ctx->state == PFM_CTX_ZOMBIE)) { ++ pfm_post_work(task, ctx, PFM_WORK_ZOMBIE); ++ goto done; ++ } ++ ++ /* ++ * if we were the last user of the PMU on that CPU, ++ * then nothing to do except restore psr ++ */ ++ if (ctx->last_cpu == mycpu && ctx->last_act == cur_act) { ++ /* ++ * check for forced reload conditions ++ */ ++ reload_pmcs = set->priv_flags & PFM_SETFL_PRIV_MOD_PMCS; ++ reload_pmds = set->priv_flags & PFM_SETFL_PRIV_MOD_PMDS; ++ } else { ++#ifndef CONFIG_SMP ++ pfm_check_save_prev_ctx(); ++#endif ++ reload_pmcs = 1; ++ reload_pmds = 1; ++ } ++ /* consumed */ ++ set->priv_flags &= ~PFM_SETFL_PRIV_MOD_BOTH; ++ ++ if (reload_pmds) ++ pfm_arch_restore_pmds(ctx, set); ++ ++ /* ++ * need to check if had in-flight interrupt in ++ * pfm_ctxswout_thread(). If at least one bit set, then we must replay ++ * the interrupt to avoid losing some important performance data. ++ * ++ * npend_ovfls is cleared in interrupt handler ++ */ ++ if (set->npend_ovfls) { ++ pfm_arch_resend_irq(ctx); ++ pfm_stats_inc(ovfl_intr_replay_count); ++ } ++ ++ if (reload_pmcs) ++ pfm_arch_restore_pmcs(ctx, set); ++ ++ /* ++ * record current activation for this context ++ */ ++ __get_cpu_var(pmu_activation_number)++; ++ ctx->last_cpu = mycpu; ++ ctx->last_act = __get_cpu_var(pmu_activation_number); ++ ++ /* ++ * establish new ownership. ++ */ ++ pfm_set_pmu_owner(task, ctx); ++ ++ pfm_arch_ctxswin_thread(task, ctx); ++ /* ++ * set->duration does not count when context in MASKED state. ++ * set->duration_start is reset in unmask_monitoring() ++ */ ++ set->duration_start = now; ++ ++ /* ++ * re-arm switch timeout, if necessary ++ * Timeout is active only if monitoring is active, ++ * i.e., LOADED + started ++ * ++ * We reload the remainder timeout or the full timeout. ++ * Remainder is recorded on context switch out or in ++ * pfm_load_context() ++ */ ++ if (ctx->state == PFM_CTX_LOADED ++ && (set->flags & PFM_SETFL_TIME_SWITCH) && is_active) { ++ pfm_restart_timer(ctx, set); ++ /* careful here as pfm_restart_timer may switch sets */ ++ } ++done: ++ spin_unlock(&ctx->lock); ++} ++ ++/* ++ * interrupts are masked, runqueue lock is held. ++ * ++ * In UP. we simply stop monitoring and leave the state ++ * in place, i.e., lazy save ++ */ ++void __pfm_ctxswout_thread(struct task_struct *task, ++ struct pfm_context *ctx, u64 now) ++{ ++ struct pfm_event_set *set; ++ int need_save_pmds, is_active; ++ ++ /* ++ * we need to lock context because it could be accessed ++ * from another CPU. Normally the schedule() functions ++ * has masked interrupts which should be enough to ++ * protect against PMU interrupts. ++ */ ++ ++ spin_lock(&ctx->lock); ++ ++ is_active = pfm_arch_is_active(ctx); ++ set = ctx->active_set; ++ ++ /* ++ * stop monitoring and ++ * collect pending overflow information ++ * needed on ctxswin. We cannot afford to lose ++ * a PMU interrupt. ++ */ ++ need_save_pmds = pfm_arch_ctxswout_thread(task, ctx); ++ ++ if (ctx->state == PFM_CTX_LOADED) { ++ /* ++ * accumulate only when set is actively monitoring, ++ */ ++ set->duration += now - set->duration_start; ++ ++ /* ++ * record remaining timeout ++ * reload in pfm_ctxsw_in() ++ */ ++ if (is_active && (set->flags & PFM_SETFL_TIME_SWITCH)) { ++ struct hrtimer *h = NULL; ++ h = &__get_cpu_var(pfm_hrtimer); ++ hrtimer_cancel(h); ++ set->hrtimer_rem = hrtimer_get_remaining(h); ++ PFM_DBG_ovfl("hrtimer=%lld", ++ (long long)set->hrtimer_rem.tv64); ++ } ++ } ++ ++#ifdef CONFIG_SMP ++ /* ++ * in SMP, release ownership of this PMU. ++ * PMU interrupts are masked, so nothing ++ * can happen. ++ */ ++ pfm_set_pmu_owner(NULL, NULL); ++ ++ /* ++ * On some architectures, it is necessary to read the ++ * PMD registers to check for pending overflow in ++ * pfm_arch_ctxswout_thread(). In that case, saving of ++ * the PMDs may be done there and not here. ++ */ ++ if (need_save_pmds) ++ pfm_save_pmds(ctx, set); ++#endif ++ spin_unlock(&ctx->lock); ++} ++ ++/* ++ * ++ */ ++static void __pfm_ctxswout_sys(struct task_struct *prev, ++ struct task_struct *next) ++{ ++ struct pfm_context *ctx; ++ ++ ctx = __get_cpu_var(pmu_ctx); ++ BUG_ON(!ctx); ++ ++ /* ++ * propagate TIF_PERFMON_CTXSW to ensure that: ++ * - previous task has TIF_PERFMON_CTXSW cleared, in case it is ++ * scheduled onto another CPU where there is syswide monitoring ++ * - next task has TIF_PERFMON_CTXSW set to ensure it will come back ++ * here when context switched out ++ */ ++ clear_tsk_thread_flag(prev, TIF_PERFMON_CTXSW); ++ set_tsk_thread_flag(next, TIF_PERFMON_CTXSW); ++ ++ /* ++ * nothing to do until actually started ++ * XXX: assumes no mean to start from user level ++ */ ++ if (!ctx->flags.started) ++ return; ++ ++ pfm_arch_ctxswout_sys(prev, ctx); ++} ++ ++/* ++ * ++ */ ++static void __pfm_ctxswin_sys(struct task_struct *prev, ++ struct task_struct *next) ++{ ++ struct pfm_context *ctx; ++ ++ ctx = __get_cpu_var(pmu_ctx); ++ BUG_ON(!ctx); ++ ++ /* ++ * nothing to do until actually started ++ * XXX: assumes no mean to start from user level ++ */ ++ if (!ctx->flags.started) ++ return; ++ ++ pfm_arch_ctxswin_sys(next, ctx); ++} ++ ++void pfm_ctxsw_out(struct task_struct *prev, ++ struct task_struct *next) ++{ ++ struct pfm_context *ctxp; ++ u64 now; ++ ++ now = sched_clock(); ++ ++ ctxp = prev->pfm_context; ++ ++ if (ctxp) ++ __pfm_ctxswout_thread(prev, ctxp, now); ++ else ++ __pfm_ctxswout_sys(prev, next); ++ ++ pfm_stats_inc(ctxswout_count); ++ pfm_stats_add(ctxswout_ns, sched_clock() - now); ++} ++ ++void pfm_ctxsw_in(struct task_struct *prev, ++ struct task_struct *next) ++{ ++ struct pfm_context *ctxn; ++ u64 now; ++ ++ now = sched_clock(); ++ ++ ctxn = next->pfm_context; ++ ++ if (ctxn) ++ __pfm_ctxswin_thread(next, ctxn, now); ++ else ++ __pfm_ctxswin_sys(prev, next); ++ ++ pfm_stats_inc(ctxswin_count); ++ pfm_stats_add(ctxswin_ns, sched_clock() - now); ++} +--- /dev/null ++++ b/perfmon/perfmon_debugfs.c +@@ -0,0 +1,168 @@ ++/* ++ * perfmon_debugfs.c: perfmon2 statistics interface to debugfs ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 2007 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++ ++/* ++ * to make the statistics visible to user space: ++ * $ mount -t debugfs none /mnt ++ * $ cd /mnt/perfmon ++ * then choose a CPU subdir ++ */ ++DECLARE_PER_CPU(struct pfm_stats, pfm_stats); ++ ++static struct dentry *pfm_debugfs_dir; ++ ++void pfm_reset_stats(int cpu) ++{ ++ struct pfm_stats *st; ++ unsigned long flags; ++ ++ st = &per_cpu(pfm_stats, cpu); ++ ++ local_irq_save(flags); ++ memset(st->v, 0, sizeof(st->v)); ++ local_irq_restore(flags); ++} ++ ++static const char *pfm_stats_strs[] = { ++ "ovfl_intr_all_count", ++ "ovfl_intr_ns", ++ "ovfl_intr_spurious_count", ++ "ovfl_intr_replay_count", ++ "ovfl_intr_regular_count", ++ "handle_work_count", ++ "ovfl_notify_count", ++ "reset_pmds_count", ++ "pfm_restart_count", ++ "fmt_handler_calls", ++ "fmt_handler_ns", ++ "set_switch_count", ++ "set_switch_ns", ++ "set_switch_exp", ++ "ctxswin_count", ++ "ctxswin_ns", ++ "handle_timeout_count", ++ "ovfl_intr_nmi_count", ++ "ctxswout_count", ++ "ctxswout_ns", ++}; ++#define PFM_NUM_STRS ARRAY_SIZE(pfm_stats_strs) ++ ++void pfm_debugfs_del_cpu(int cpu) ++{ ++ struct pfm_stats *st; ++ int i; ++ ++ st = &per_cpu(pfm_stats, cpu); ++ ++ for (i = 0; i < PFM_NUM_STATS; i++) { ++ if (st->dirs[i]) ++ debugfs_remove(st->dirs[i]); ++ st->dirs[i] = NULL; ++ } ++ if (st->cpu_dir) ++ debugfs_remove(st->cpu_dir); ++ st->cpu_dir = NULL; ++} ++ ++int pfm_debugfs_add_cpu(int cpu) ++{ ++ struct pfm_stats *st; ++ int i; ++ ++ /* ++ * sanity check between stats names and the number ++ * of entries in the pfm_stats value array. ++ */ ++ if (PFM_NUM_STRS != PFM_NUM_STATS) { ++ PFM_ERR("PFM_NUM_STRS != PFM_NUM_STATS error"); ++ return -1; ++ } ++ ++ st = &per_cpu(pfm_stats, cpu); ++ sprintf(st->cpu_name, "cpu%d", cpu); ++ ++ st->cpu_dir = debugfs_create_dir(st->cpu_name, pfm_debugfs_dir); ++ if (!st->cpu_dir) ++ return -1; ++ ++ for (i = 0; i < PFM_NUM_STATS; i++) { ++ st->dirs[i] = debugfs_create_u64(pfm_stats_strs[i], ++ S_IRUGO, ++ st->cpu_dir, ++ &st->v[i]); ++ if (!st->dirs[i]) ++ goto error; ++ } ++ pfm_reset_stats(cpu); ++ return 0; ++error: ++ while (i >= 0) { ++ debugfs_remove(st->dirs[i]); ++ i--; ++ } ++ debugfs_remove(st->cpu_dir); ++ return -1; ++} ++ ++/* ++ * called once from pfm_init() ++ */ ++int __init pfm_init_debugfs(void) ++{ ++ int cpu1, cpu2, ret; ++ ++ pfm_debugfs_dir = debugfs_create_dir("perfmon", NULL); ++ if (!pfm_debugfs_dir) ++ return -1; ++ ++ for_each_online_cpu(cpu1) { ++ ret = pfm_debugfs_add_cpu(cpu1); ++ if (ret) ++ goto error; ++ } ++ return 0; ++error: ++ for_each_online_cpu(cpu2) { ++ if (cpu2 == cpu1) ++ break; ++ pfm_debugfs_del_cpu(cpu2); ++ } ++ return -1; ++} +--- /dev/null ++++ b/perfmon/perfmon_dfl_smpl.c +@@ -0,0 +1,298 @@ ++/* ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This file implements the new default sampling buffer format ++ * for the perfmon2 subsystem. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_AUTHOR("Stephane Eranian "); ++MODULE_DESCRIPTION("new perfmon default sampling format"); ++MODULE_LICENSE("GPL"); ++ ++static int pfm_dfl_fmt_validate(u32 ctx_flags, u16 npmds, void *data) ++{ ++ struct pfm_dfl_smpl_arg *arg = data; ++ u64 min_buf_size; ++ ++ if (data == NULL) { ++ PFM_DBG("no argument passed"); ++ return -EINVAL; ++ } ++ ++ /* ++ * sanity check in case size_t is smaller then u64 ++ */ ++#if BITS_PER_LONG == 4 ++#define MAX_SIZE_T (1ULL<<(sizeof(size_t)<<3)) ++ if (sizeof(size_t) < sizeof(arg->buf_size)) { ++ if (arg->buf_size >= MAX_SIZE_T) ++ return -ETOOBIG; ++ } ++#endif ++ ++ /* ++ * compute min buf size. npmds is the maximum number ++ * of implemented PMD registers. ++ */ ++ min_buf_size = sizeof(struct pfm_dfl_smpl_hdr) ++ + (sizeof(struct pfm_dfl_smpl_entry) + (npmds*sizeof(u64))); ++ ++ PFM_DBG("validate ctx_flags=0x%x flags=0x%x npmds=%u " ++ "min_buf_size=%llu buf_size=%llu\n", ++ ctx_flags, ++ arg->buf_flags, ++ npmds, ++ (unsigned long long)min_buf_size, ++ (unsigned long long)arg->buf_size); ++ ++ /* ++ * must hold at least the buffer header + one minimally sized entry ++ */ ++ if (arg->buf_size < min_buf_size) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int pfm_dfl_fmt_get_size(u32 flags, void *data, size_t *size) ++{ ++ struct pfm_dfl_smpl_arg *arg = data; ++ ++ /* ++ * size has been validated in default_validate ++ * we can never loose bits from buf_size. ++ */ ++ *size = (size_t)arg->buf_size; ++ ++ return 0; ++} ++ ++static int pfm_dfl_fmt_init(struct pfm_context *ctx, void *buf, u32 ctx_flags, ++ u16 npmds, void *data) ++{ ++ struct pfm_dfl_smpl_hdr *hdr; ++ struct pfm_dfl_smpl_arg *arg = data; ++ ++ hdr = buf; ++ ++ hdr->hdr_version = PFM_DFL_SMPL_VERSION; ++ hdr->hdr_buf_size = arg->buf_size; ++ hdr->hdr_buf_flags = arg->buf_flags; ++ hdr->hdr_cur_offs = sizeof(*hdr); ++ hdr->hdr_overflows = 0; ++ hdr->hdr_count = 0; ++ hdr->hdr_min_buf_space = sizeof(struct pfm_dfl_smpl_entry) + (npmds*sizeof(u64)); ++ /* ++ * due to cache aliasing, it may be necessary to flush the cache ++ * on certain architectures (e.g., MIPS) ++ */ ++ pfm_cacheflush(hdr, sizeof(*hdr)); ++ ++ PFM_DBG("buffer=%p buf_size=%llu hdr_size=%zu hdr_version=%u.%u " ++ "min_space=%llu npmds=%u", ++ buf, ++ (unsigned long long)hdr->hdr_buf_size, ++ sizeof(*hdr), ++ PFM_VERSION_MAJOR(hdr->hdr_version), ++ PFM_VERSION_MINOR(hdr->hdr_version), ++ (unsigned long long)hdr->hdr_min_buf_space, ++ npmds); ++ ++ return 0; ++} ++ ++/* ++ * called from pfm_overflow_handler() to record a new sample ++ * ++ * context is locked, interrupts are disabled (no preemption) ++ */ ++static int pfm_dfl_fmt_handler(struct pfm_context *ctx, ++ unsigned long ip, u64 tstamp, void *data) ++{ ++ struct pfm_dfl_smpl_hdr *hdr; ++ struct pfm_dfl_smpl_entry *ent; ++ struct pfm_ovfl_arg *arg; ++ void *cur, *last; ++ u64 *e; ++ size_t entry_size, min_size; ++ u16 npmds, i; ++ u16 ovfl_pmd; ++ void *buf; ++ ++ hdr = ctx->smpl_addr; ++ arg = &ctx->ovfl_arg; ++ ++ buf = hdr; ++ cur = buf+hdr->hdr_cur_offs; ++ last = buf+hdr->hdr_buf_size; ++ ovfl_pmd = arg->ovfl_pmd; ++ min_size = hdr->hdr_min_buf_space; ++ ++ /* ++ * precheck for sanity ++ */ ++ if ((last - cur) < min_size) ++ goto full; ++ ++ npmds = arg->num_smpl_pmds; ++ ++ ent = (struct pfm_dfl_smpl_entry *)cur; ++ ++ entry_size = sizeof(*ent) + (npmds << 3); ++ ++ /* position for first pmd */ ++ e = (u64 *)(ent+1); ++ ++ hdr->hdr_count++; ++ ++ PFM_DBG_ovfl("count=%llu cur=%p last=%p free_bytes=%zu ovfl_pmd=%d " ++ "npmds=%u", ++ (unsigned long long)hdr->hdr_count, ++ cur, last, ++ (last-cur), ++ ovfl_pmd, ++ npmds); ++ ++ /* ++ * current = task running at the time of the overflow. ++ * ++ * per-task mode: ++ * - this is usually the task being monitored. ++ * Under certain conditions, it might be a different task ++ * ++ * system-wide: ++ * - this is not necessarily the task controlling the session ++ */ ++ ent->pid = current->pid; ++ ent->ovfl_pmd = ovfl_pmd; ++ ent->last_reset_val = arg->pmd_last_reset; ++ ++ /* ++ * where did the fault happen (includes slot number) ++ */ ++ ent->ip = ip; ++ ++ ent->tstamp = tstamp; ++ ent->cpu = smp_processor_id(); ++ ent->set = arg->active_set; ++ ent->tgid = current->tgid; ++ ++ /* ++ * selectively store PMDs in increasing index number ++ */ ++ if (npmds) { ++ u64 *val = arg->smpl_pmds_values; ++ for (i = 0; i < npmds; i++) ++ *e++ = *val++; ++ } ++ ++ /* ++ * update position for next entry ++ */ ++ hdr->hdr_cur_offs += entry_size; ++ cur += entry_size; ++ ++ pfm_cacheflush(hdr, sizeof(*hdr)); ++ pfm_cacheflush(ent, entry_size); ++ ++ /* ++ * post check to avoid losing the last sample ++ */ ++ if ((last - cur) < min_size) ++ goto full; ++ ++ /* reset before returning from interrupt handler */ ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET; ++ ++ return 0; ++full: ++ PFM_DBG_ovfl("sampling buffer full free=%zu, count=%llu", ++ last-cur, ++ (unsigned long long)hdr->hdr_count); ++ ++ /* ++ * increment number of buffer overflows. ++ * important to detect duplicate set of samples. ++ */ ++ hdr->hdr_overflows++; ++ ++ /* ++ * request notification and masking of monitoring. ++ * Notification is still subject to the overflowed ++ * register having the FL_NOTIFY flag set. ++ */ ++ arg->ovfl_ctrl = PFM_OVFL_CTRL_NOTIFY | PFM_OVFL_CTRL_MASK; ++ ++ return -ENOBUFS; /* we are full, sorry */ ++} ++ ++static int pfm_dfl_fmt_restart(int is_active, u32 *ovfl_ctrl, void *buf) ++{ ++ struct pfm_dfl_smpl_hdr *hdr; ++ ++ hdr = buf; ++ ++ hdr->hdr_count = 0; ++ hdr->hdr_cur_offs = sizeof(*hdr); ++ ++ pfm_cacheflush(hdr, sizeof(*hdr)); ++ ++ *ovfl_ctrl = PFM_OVFL_CTRL_RESET; ++ ++ return 0; ++} ++ ++static int pfm_dfl_fmt_exit(void *buf) ++{ ++ return 0; ++} ++ ++static struct pfm_smpl_fmt dfl_fmt = { ++ .fmt_name = "default", ++ .fmt_version = 0x10000, ++ .fmt_arg_size = sizeof(struct pfm_dfl_smpl_arg), ++ .fmt_validate = pfm_dfl_fmt_validate, ++ .fmt_getsize = pfm_dfl_fmt_get_size, ++ .fmt_init = pfm_dfl_fmt_init, ++ .fmt_handler = pfm_dfl_fmt_handler, ++ .fmt_restart = pfm_dfl_fmt_restart, ++ .fmt_exit = pfm_dfl_fmt_exit, ++ .fmt_flags = PFM_FMT_BUILTIN_FLAG, ++ .owner = THIS_MODULE ++}; ++ ++static int pfm_dfl_fmt_init_module(void) ++{ ++ return pfm_fmt_register(&dfl_fmt); ++} ++ ++static void pfm_dfl_fmt_cleanup_module(void) ++{ ++ pfm_fmt_unregister(&dfl_fmt); ++} ++ ++module_init(pfm_dfl_fmt_init_module); ++module_exit(pfm_dfl_fmt_cleanup_module); +--- /dev/null ++++ b/perfmon/perfmon_file.c +@@ -0,0 +1,751 @@ ++/* ++ * perfmon_file.c: perfmon2 file input/output functions ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++#define PFMFS_MAGIC 0xa0b4d889 /* perfmon filesystem magic number */ ++ ++struct pfm_controls pfm_controls = { ++ .sys_group = PFM_GROUP_PERM_ANY, ++ .task_group = PFM_GROUP_PERM_ANY, ++ .arg_mem_max = PAGE_SIZE, ++ .smpl_buffer_mem_max = ~0, ++}; ++EXPORT_SYMBOL(pfm_controls); ++ ++static int __init enable_debug(char *str) ++{ ++ pfm_controls.debug = 1; ++ PFM_INFO("debug output enabled\n"); ++ return 1; ++} ++__setup("perfmon_debug", enable_debug); ++ ++static int pfmfs_delete_dentry(struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static struct dentry_operations pfmfs_dentry_operations = { ++ .d_delete = pfmfs_delete_dentry, ++}; ++ ++int pfm_buf_map_pagefault(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ void *kaddr; ++ unsigned long address; ++ struct pfm_context *ctx; ++ size_t size; ++ ++ address = (unsigned long)vmf->virtual_address; ++ ++ ctx = vma->vm_private_data; ++ if (ctx == NULL) { ++ PFM_DBG("no ctx"); ++ return VM_FAULT_SIGBUS; ++ } ++ /* ++ * size available to user (maybe different from real_smpl_size ++ */ ++ size = ctx->smpl_size; ++ ++ if ((address < vma->vm_start) || ++ (address >= (vma->vm_start + size))) ++ return VM_FAULT_SIGBUS; ++ ++ kaddr = ctx->smpl_addr + (address - vma->vm_start); ++ ++ vmf->page = vmalloc_to_page(kaddr); ++ get_page(vmf->page); ++ ++ PFM_DBG("[%d] start=%p ref_count=%d", ++ current->pid, ++ kaddr, page_count(vmf->page)); ++ ++ return 0; ++} ++ ++/* ++ * we need to determine whther or not we are closing the last reference ++ * to the file and thus are going to end up in pfm_close() which eventually ++ * calls pfm_release_buf_space(). In that function, we update the accouting ++ * for locked_vm given that we are actually freeing the sampling buffer. The ++ * issue is that there are multiple paths leading to pfm_release_buf_space(), ++ * from exit(), munmap(), close(). The path coming from munmap() is problematic ++ * becuse do_munmap() grabs mmap_sem in write-mode which is also what ++ * pfm_release_buf_space does. To avoid deadlock, we need to determine where ++ * we are calling from and skip the locking. The vm_ops->close() callback ++ * is invoked for each remove_vma() independently of the number of references ++ * left on the file descriptor, therefore simple reference counter does not ++ * work. We need to determine if this is the last call, and then set a flag ++ * to skip the locking. ++ */ ++static void pfm_buf_map_close(struct vm_area_struct *vma) ++{ ++ struct file *file; ++ struct pfm_context *ctx; ++ ++ file = vma->vm_file; ++ ctx = vma->vm_private_data; ++ ++ /* ++ * if file is going to close, then pfm_close() will ++ * be called, do not lock in pfm_release_buf ++ */ ++ if (atomic_read(&file->f_count) == 1) ++ ctx->flags.mmap_nlock = 1; ++} ++ ++/* ++ * we do not have a close callback because, the locked ++ * memory accounting must be done when the actual buffer ++ * is freed. Munmap does not free the page backing the vma ++ * because they may still be in use by the PMU interrupt handler. ++ */ ++struct vm_operations_struct pfm_buf_map_vm_ops = { ++ .fault = pfm_buf_map_pagefault, ++ .close = pfm_buf_map_close ++}; ++ ++static int pfm_mmap_buffer(struct pfm_context *ctx, struct vm_area_struct *vma, ++ size_t size) ++{ ++ if (ctx->smpl_addr == NULL) { ++ PFM_DBG("no sampling buffer to map"); ++ return -EINVAL; ++ } ++ ++ if (size > ctx->smpl_size) { ++ PFM_DBG("mmap size=%zu >= actual buf size=%zu", ++ size, ++ ctx->smpl_size); ++ return -EINVAL; ++ } ++ ++ vma->vm_ops = &pfm_buf_map_vm_ops; ++ vma->vm_private_data = ctx; ++ ++ return 0; ++} ++ ++static int pfm_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ size_t size; ++ struct pfm_context *ctx; ++ unsigned long flags; ++ int ret; ++ ++ PFM_DBG("pfm_file_ops"); ++ ++ ctx = file->private_data; ++ size = (vma->vm_end - vma->vm_start); ++ ++ if (ctx == NULL) ++ return -EINVAL; ++ ++ ret = -EINVAL; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ if (vma->vm_flags & VM_WRITE) { ++ PFM_DBG("cannot map buffer for writing"); ++ goto done; ++ } ++ ++ PFM_DBG("vm_pgoff=%lu size=%zu vm_start=0x%lx", ++ vma->vm_pgoff, ++ size, ++ vma->vm_start); ++ ++ ret = pfm_mmap_buffer(ctx, vma, size); ++ if (ret == 0) ++ vma->vm_flags |= VM_RESERVED; ++ ++ PFM_DBG("ret=%d vma_flags=0x%lx vma_start=0x%lx vma_size=%lu", ++ ret, ++ vma->vm_flags, ++ vma->vm_start, ++ vma->vm_end-vma->vm_start); ++done: ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ return ret; ++} ++ ++/* ++ * Extract one message from queue. ++ * ++ * return: ++ * -EAGAIN: when non-blocking and nothing is* in the queue. ++ * -ERESTARTSYS: when blocking and signal is pending ++ * Otherwise returns size of message (sizeof(pfarg_msg)) ++ */ ++ssize_t __pfm_read(struct pfm_context *ctx, union pfarg_msg *msg_buf, int non_block) ++{ ++ ssize_t ret = 0; ++ unsigned long flags; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ /* ++ * we must masks interrupts to avoid a race condition ++ * with the PMU interrupt handler. ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ while (pfm_msgq_is_empty(ctx)) { ++ ++ /* ++ * handle non-blocking reads ++ * return -EAGAIN ++ */ ++ ret = -EAGAIN; ++ if (non_block) ++ break; ++ ++ add_wait_queue(&ctx->msgq_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ schedule(); ++ ++ /* ++ * during this window, another thread may call ++ * pfm_read() and steal our message ++ */ ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ remove_wait_queue(&ctx->msgq_wait, &wait); ++ set_current_state(TASK_RUNNING); ++ ++ /* ++ * check for pending signals ++ * return -ERESTARTSYS ++ */ ++ ret = -ERESTARTSYS; ++ if (signal_pending(current)) ++ break; ++ ++ /* ++ * we may have a message ++ */ ++ ret = 0; ++ } ++ ++ /* ++ * extract message ++ */ ++ if (ret == 0) { ++ /* ++ * copy the oldest message into msg_buf. ++ * We cannot directly call copy_to_user() ++ * because interrupts masked. This is done ++ * in the caller ++ */ ++ pfm_get_next_msg(ctx, msg_buf); ++ ++ ret = sizeof(*msg_buf); ++ ++ PFM_DBG("extracted type=%d", msg_buf->type); ++ } ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ PFM_DBG("blocking=%d ret=%zd", non_block, ret); ++ ++ return ret; ++} ++ ++static ssize_t pfm_read(struct file *filp, char __user *buf, size_t size, ++ loff_t *ppos) ++{ ++ struct pfm_context *ctx; ++ union pfarg_msg msg_buf; ++ int non_block, ret; ++ ++ PFM_DBG_ovfl("buf=%p size=%zu", buf, size); ++ ++ ctx = filp->private_data; ++ if (ctx == NULL) { ++ PFM_ERR("no ctx for pfm_read"); ++ return -EINVAL; ++ } ++ ++ non_block = filp->f_flags & O_NONBLOCK; ++ ++#ifdef CONFIG_IA64_PERFMON_COMPAT ++ /* ++ * detect IA-64 v2.0 context read (message size is different) ++ * nops on all other architectures ++ */ ++ if (unlikely(ctx->flags.ia64_v20_compat)) ++ return pfm_arch_compat_read(ctx, buf, non_block, size); ++#endif ++ /* ++ * cannot extract partial messages. ++ * check even when there is no message ++ * ++ * cannot extract more than one message per call. Bytes ++ * above sizeof(msg) are ignored. ++ */ ++ if (size < sizeof(msg_buf)) { ++ PFM_DBG("message is too small size=%zu must be >=%zu)", ++ size, ++ sizeof(msg_buf)); ++ return -EINVAL; ++ } ++ ++ ret = __pfm_read(ctx, &msg_buf, non_block); ++ if (ret > 0) { ++ if (copy_to_user(buf, &msg_buf, sizeof(msg_buf))) ++ ret = -EFAULT; ++ } ++ PFM_DBG_ovfl("ret=%d", ret); ++ return ret; ++} ++ ++static ssize_t pfm_write(struct file *file, const char __user *ubuf, ++ size_t size, loff_t *ppos) ++{ ++ PFM_DBG("pfm_write called"); ++ return -EINVAL; ++} ++ ++static unsigned int pfm_poll(struct file *filp, poll_table *wait) ++{ ++ struct pfm_context *ctx; ++ unsigned long flags; ++ unsigned int mask = 0; ++ ++ PFM_DBG("pfm_file_ops"); ++ ++ if (filp->f_op != &pfm_file_ops) { ++ PFM_ERR("pfm_poll bad magic"); ++ return 0; ++ } ++ ++ ctx = filp->private_data; ++ if (ctx == NULL) { ++ PFM_ERR("pfm_poll no ctx"); ++ return 0; ++ } ++ ++ PFM_DBG("before poll_wait"); ++ ++ poll_wait(filp, &ctx->msgq_wait, wait); ++ ++ /* ++ * pfm_msgq_is_empty() is non-atomic ++ * ++ * filp is protected by fget() at upper level ++ * context cannot be closed by another thread. ++ * ++ * There may be a race with a PMU interrupt adding ++ * messages to the queue. But we are interested in ++ * queue not empty, so adding more messages should ++ * not really be a problem. ++ * ++ * There may be a race with another thread issuing ++ * a read() and stealing messages from the queue thus ++ * may return the wrong answer. This could potentially ++ * lead to a blocking read, because nothing is ++ * available in the queue ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ if (!pfm_msgq_is_empty(ctx)) ++ mask = POLLIN | POLLRDNORM; ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ PFM_DBG("after poll_wait mask=0x%x", mask); ++ ++ return mask; ++} ++ ++static int pfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ PFM_DBG("pfm_ioctl called"); ++ return -EINVAL; ++} ++ ++/* ++ * interrupt cannot be masked when entering this function ++ */ ++static inline int __pfm_fasync(int fd, struct file *filp, ++ struct pfm_context *ctx, int on) ++{ ++ int ret; ++ ++ PFM_DBG("in fd=%d on=%d async_q=%p", ++ fd, ++ on, ++ ctx->async_queue); ++ ++ ret = fasync_helper(fd, filp, on, &ctx->async_queue); ++ ++ PFM_DBG("out fd=%d on=%d async_q=%p ret=%d", ++ fd, ++ on, ++ ctx->async_queue, ret); ++ ++ return ret; ++} ++ ++static int pfm_fasync(int fd, struct file *filp, int on) ++{ ++ struct pfm_context *ctx; ++ int ret; ++ ++ PFM_DBG("pfm_file_ops"); ++ ++ ctx = filp->private_data; ++ if (ctx == NULL) { ++ PFM_ERR("pfm_fasync no ctx"); ++ return -EBADF; ++ } ++ ++ /* ++ * we cannot mask interrupts during this call because this may ++ * may go to sleep if memory is not readily avalaible. ++ * ++ * We are protected from the context disappearing by the ++ * get_fd()/put_fd() done in caller. Serialization of this function ++ * is ensured by caller. ++ */ ++ ret = __pfm_fasync(fd, filp, ctx, on); ++ ++ PFM_DBG("pfm_fasync called on fd=%d on=%d async_queue=%p ret=%d", ++ fd, ++ on, ++ ctx->async_queue, ret); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_SMP ++static void __pfm_close_remote_cpu(void *info) ++{ ++ struct pfm_context *ctx = info; ++ int can_release; ++ ++ BUG_ON(ctx != __get_cpu_var(pmu_ctx)); ++ ++ /* ++ * we are in IPI interrupt handler which has always higher ++ * priority than PMU interrupt, therefore we do not need to ++ * mask interrupts. context locking is not needed because we ++ * are in close(), no more user references. ++ * ++ * can_release is ignored, release done on calling CPU ++ */ ++ __pfm_unload_context(ctx, &can_release); ++ ++ /* ++ * we cannot free context here because we are in_interrupt(). ++ * we free on the calling CPU ++ */ ++} ++ ++static int pfm_close_remote_cpu(u32 cpu, struct pfm_context *ctx) ++{ ++ BUG_ON(irqs_disabled()); ++ return smp_call_function_single(cpu, __pfm_close_remote_cpu, ctx, 1); ++} ++#endif /* CONFIG_SMP */ ++ ++/* ++ * called either on explicit close() or from exit_files(). ++ * Only the LAST user of the file gets to this point, i.e., it is ++ * called only ONCE. ++ * ++ * IMPORTANT: we get called ONLY when the refcnt on the file gets to zero ++ * (fput()),i.e, last task to access the file. Nobody else can access the ++ * file at this point. ++ * ++ * When called from exit_files(), the VMA has been freed because exit_mm() ++ * is executed before exit_files(). ++ * ++ * When called from exit_files(), the current task is not yet ZOMBIE but we ++ * flush the PMU state to the context. ++ */ ++int __pfm_close(struct pfm_context *ctx, struct file *filp) ++{ ++ unsigned long flags; ++ int state; ++ int can_free = 1, can_unload = 1; ++ int is_system, can_release = 0; ++ u32 cpu; ++ ++ /* ++ * no risk of ctx of filp disappearing so we can operate outside ++ * of spin_lock(). fasync_helper() runs with interrupts masked, ++ * thus there is no risk with the PMU interrupt handler ++ * ++ * In case of zombie, we will not have the async struct anymore ++ * thus kill_fasync() will not do anything ++ * ++ * fd is not used when removing the entry so we pass -1 ++ */ ++ if (filp->f_flags & FASYNC) ++ __pfm_fasync (-1, filp, ctx, 0); ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ state = ctx->state; ++ is_system = ctx->flags.system; ++ cpu = ctx->cpu; ++ ++ PFM_DBG("state=%d", state); ++ ++ /* ++ * check if unload is needed ++ */ ++ if (state == PFM_CTX_UNLOADED) ++ goto doit; ++ ++#ifdef CONFIG_SMP ++ /* ++ * we need to release the resource on the ORIGINAL cpu. ++ * we need to release the context lock to avoid deadlocks ++ * on the original CPU, especially in the context switch ++ * routines. It is safe to unlock because we are in close(), ++ * in other words, there is no more access from user level. ++ * we can also unmask interrupts on this CPU because the ++ * context is running on the original CPU. Context will be ++ * unloaded and the session will be released on the original ++ * CPU. Upon return, the caller is guaranteed that the context ++ * is gone from original CPU. ++ */ ++ if (is_system && cpu != smp_processor_id()) { ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ pfm_close_remote_cpu(cpu, ctx); ++ can_release = 1; ++ goto free_it; ++ } ++ ++ if (!is_system && ctx->task != current) { ++ /* ++ * switch context to zombie state ++ */ ++ ctx->state = PFM_CTX_ZOMBIE; ++ ++ PFM_DBG("zombie ctx for [%d]", ctx->task->pid); ++ /* ++ * must check if other thread is using block overflow ++ * notification mode. If so make sure it will not block ++ * because there will not be any pfm_restart() issued. ++ * When the thread notices the ZOMBIE state, it will clean ++ * up what is left of the context ++ */ ++ if (state == PFM_CTX_MASKED && ctx->flags.block) { ++ /* ++ * force task to wake up from MASKED state ++ */ ++ PFM_DBG("waking up [%d]", ctx->task->pid); ++ ++ complete(&ctx->restart_complete); ++ } ++ /* ++ * PMU session will be release by monitored task when it notices ++ * ZOMBIE state as part of pfm_unload_context() ++ */ ++ can_unload = can_free = 0; ++ } ++#endif ++ if (can_unload) ++ __pfm_unload_context(ctx, &can_release); ++doit: ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++#ifdef CONFIG_SMP ++free_it: ++#endif ++ if (can_release) ++ pfm_session_release(is_system, cpu); ++ ++ if (can_free) ++ pfm_free_context(ctx); ++ ++ return 0; ++} ++ ++static int pfm_close(struct inode *inode, struct file *filp) ++{ ++ struct pfm_context *ctx; ++ ++ PFM_DBG("called filp=%p", filp); ++ ++ ctx = filp->private_data; ++ if (ctx == NULL) { ++ PFM_ERR("no ctx"); ++ return -EBADF; ++ } ++ return __pfm_close(ctx, filp); ++} ++ ++static int pfm_no_open(struct inode *irrelevant, struct file *dontcare) ++{ ++ PFM_DBG("pfm_file_ops"); ++ ++ return -ENXIO; ++} ++ ++ ++const struct file_operations pfm_file_ops = { ++ .llseek = no_llseek, ++ .read = pfm_read, ++ .write = pfm_write, ++ .poll = pfm_poll, ++ .ioctl = pfm_ioctl, ++ .open = pfm_no_open, /* special open to disallow open via /proc */ ++ .fasync = pfm_fasync, ++ .release = pfm_close, ++ .mmap = pfm_mmap ++}; ++ ++static int pfmfs_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, ++ void *data, struct vfsmount *mnt) ++{ ++ return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC, mnt); ++} ++ ++static struct file_system_type pfm_fs_type = { ++ .name = "pfmfs", ++ .get_sb = pfmfs_get_sb, ++ .kill_sb = kill_anon_super, ++}; ++ ++/* ++ * pfmfs should _never_ be mounted by userland - too much of security hassle, ++ * no real gain from having the whole whorehouse mounted. So we don't need ++ * any operations on the root directory. However, we need a non-trivial ++ * d_name - pfm: will go nicely and kill the special-casing in procfs. ++ */ ++static struct vfsmount *pfmfs_mnt; ++ ++int __init pfm_init_fs(void) ++{ ++ int err = register_filesystem(&pfm_fs_type); ++ if (!err) { ++ pfmfs_mnt = kern_mount(&pfm_fs_type); ++ err = PTR_ERR(pfmfs_mnt); ++ if (IS_ERR(pfmfs_mnt)) ++ unregister_filesystem(&pfm_fs_type); ++ else ++ err = 0; ++ } ++ return err; ++} ++ ++int pfm_alloc_fd(struct file **cfile) ++{ ++ int fd, ret = 0; ++ struct file *file = NULL; ++ struct inode * inode; ++ char name[32]; ++ struct qstr this; ++ ++ fd = get_unused_fd(); ++ if (fd < 0) ++ return -ENFILE; ++ ++ ret = -ENFILE; ++ ++ file = get_empty_filp(); ++ if (!file) ++ goto out; ++ ++ /* ++ * allocate a new inode ++ */ ++ inode = new_inode(pfmfs_mnt->mnt_sb); ++ if (!inode) ++ goto out; ++ ++ PFM_DBG("new inode ino=%ld @%p", inode->i_ino, inode); ++ ++ inode->i_sb = pfmfs_mnt->mnt_sb; ++ inode->i_mode = S_IFCHR|S_IRUGO; ++ inode->i_uid = current->fsuid; ++ inode->i_gid = current->fsgid; ++ ++ sprintf(name, "[%lu]", inode->i_ino); ++ this.name = name; ++ this.hash = inode->i_ino; ++ this.len = strlen(name); ++ ++ ret = -ENOMEM; ++ ++ /* ++ * allocate a new dcache entry ++ */ ++ file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); ++ if (!file->f_dentry) ++ goto out; ++ ++ file->f_dentry->d_op = &pfmfs_dentry_operations; ++ ++ d_add(file->f_dentry, inode); ++ file->f_vfsmnt = mntget(pfmfs_mnt); ++ file->f_mapping = inode->i_mapping; ++ ++ file->f_op = &pfm_file_ops; ++ file->f_mode = FMODE_READ; ++ file->f_flags = O_RDONLY; ++ file->f_pos = 0; ++ ++ *cfile = file; ++ ++ return fd; ++out: ++ if (file) ++ put_filp(file); ++ put_unused_fd(fd); ++ return ret; ++} +--- /dev/null ++++ b/perfmon/perfmon_fmt.c +@@ -0,0 +1,219 @@ ++/* ++ * perfmon_fmt.c: perfmon2 sampling buffer format management ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include "perfmon_priv.h" ++ ++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pfm_smpl_fmt_lock); ++static LIST_HEAD(pfm_smpl_fmt_list); ++ ++static inline int fmt_is_mod(struct pfm_smpl_fmt *f) ++{ ++ return !(f->fmt_flags & PFM_FMTFL_IS_BUILTIN); ++} ++ ++static struct pfm_smpl_fmt *pfm_find_fmt(char *name) ++{ ++ struct pfm_smpl_fmt *entry; ++ ++ list_for_each_entry(entry, &pfm_smpl_fmt_list, fmt_list) { ++ if (!strcmp(entry->fmt_name, name)) ++ return entry; ++ } ++ return NULL; ++} ++/* ++ * find a buffer format based on its name ++ */ ++struct pfm_smpl_fmt *pfm_smpl_fmt_get(char *name) ++{ ++ struct pfm_smpl_fmt *fmt; ++ ++ spin_lock(&pfm_smpl_fmt_lock); ++ ++ fmt = pfm_find_fmt(name); ++ ++ /* ++ * increase module refcount ++ */ ++ if (fmt && fmt_is_mod(fmt) && !try_module_get(fmt->owner)) ++ fmt = NULL; ++ ++ spin_unlock(&pfm_smpl_fmt_lock); ++ ++ return fmt; ++} ++ ++void pfm_smpl_fmt_put(struct pfm_smpl_fmt *fmt) ++{ ++ if (fmt == NULL || !fmt_is_mod(fmt)) ++ return; ++ BUG_ON(fmt->owner == NULL); ++ ++ spin_lock(&pfm_smpl_fmt_lock); ++ module_put(fmt->owner); ++ spin_unlock(&pfm_smpl_fmt_lock); ++} ++ ++int pfm_fmt_register(struct pfm_smpl_fmt *fmt) ++{ ++ int ret = 0; ++ ++ if (perfmon_disabled) { ++ PFM_INFO("perfmon disabled, cannot add sampling format"); ++ return -ENOSYS; ++ } ++ ++ /* some sanity checks */ ++ if (fmt == NULL) { ++ PFM_INFO("perfmon: NULL format for register"); ++ return -EINVAL; ++ } ++ ++ if (fmt->fmt_name == NULL) { ++ PFM_INFO("perfmon: format has no name"); ++ return -EINVAL; ++ } ++ ++ if (fmt->fmt_qdepth > PFM_MSGS_COUNT) { ++ PFM_INFO("perfmon: format %s requires %u msg queue depth (max %d)", ++ fmt->fmt_name, ++ fmt->fmt_qdepth, ++ PFM_MSGS_COUNT); ++ return -EINVAL; ++ } ++ ++ /* ++ * fmt is missing the initialization of .owner = THIS_MODULE ++ * this is only valid when format is compiled as a module ++ */ ++ if (fmt->owner == NULL && fmt_is_mod(fmt)) { ++ PFM_INFO("format %s has no module owner", fmt->fmt_name); ++ return -EINVAL; ++ } ++ /* ++ * we need at least a handler ++ */ ++ if (fmt->fmt_handler == NULL) { ++ PFM_INFO("format %s has no handler", fmt->fmt_name); ++ return -EINVAL; ++ } ++ ++ /* ++ * format argument size cannot be bigger than PAGE_SIZE ++ */ ++ if (fmt->fmt_arg_size > PAGE_SIZE) { ++ PFM_INFO("format %s arguments too big", fmt->fmt_name); ++ return -EINVAL; ++ } ++ ++ spin_lock(&pfm_smpl_fmt_lock); ++ ++ /* ++ * because of sysfs, we cannot have two formats with the same name ++ */ ++ if (pfm_find_fmt(fmt->fmt_name)) { ++ PFM_INFO("format %s already registered", fmt->fmt_name); ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ ret = pfm_sysfs_add_fmt(fmt); ++ if (ret) { ++ PFM_INFO("sysfs cannot add format entry for %s", fmt->fmt_name); ++ goto out; ++ } ++ ++ list_add(&fmt->fmt_list, &pfm_smpl_fmt_list); ++ ++ PFM_INFO("added sampling format %s", fmt->fmt_name); ++out: ++ spin_unlock(&pfm_smpl_fmt_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(pfm_fmt_register); ++ ++int pfm_fmt_unregister(struct pfm_smpl_fmt *fmt) ++{ ++ struct pfm_smpl_fmt *fmt2; ++ int ret = 0; ++ ++ if (!fmt || !fmt->fmt_name) { ++ PFM_DBG("invalid fmt"); ++ return -EINVAL; ++ } ++ ++ spin_lock(&pfm_smpl_fmt_lock); ++ ++ fmt2 = pfm_find_fmt(fmt->fmt_name); ++ if (!fmt) { ++ PFM_INFO("unregister failed, format not registered"); ++ ret = -EINVAL; ++ goto out; ++ } ++ list_del_init(&fmt->fmt_list); ++ ++ pfm_sysfs_remove_fmt(fmt); ++ ++ PFM_INFO("removed sampling format: %s", fmt->fmt_name); ++ ++out: ++ spin_unlock(&pfm_smpl_fmt_lock); ++ return ret; ++ ++} ++EXPORT_SYMBOL(pfm_fmt_unregister); ++ ++/* ++ * we defer adding the builtin formats to /sys/kernel/perfmon/formats ++ * until after the pfm sysfs subsystem is initialized. This function ++ * is called from pfm_init_sysfs() ++ */ ++void __init pfm_sysfs_builtin_fmt_add(void) ++{ ++ struct pfm_smpl_fmt *entry; ++ ++ /* ++ * locking not needed, kernel not fully booted ++ * when called ++ */ ++ list_for_each_entry(entry, &pfm_smpl_fmt_list, fmt_list) { ++ pfm_sysfs_add_fmt(entry); ++ } ++} +--- /dev/null ++++ b/perfmon/perfmon_hotplug.c +@@ -0,0 +1,151 @@ ++/* ++ * perfmon_hotplug.c: handling of CPU hotplug ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++#ifndef CONFIG_HOTPLUG_CPU ++void pfm_cpu_disable(void) ++{} ++ ++int __init pfm_init_hotplug(void) ++{ ++ return 0; ++} ++#else /* CONFIG_HOTPLUG_CPU */ ++/* ++ * CPU hotplug event nofication callback ++ * ++ * We use the callback to do manage the sysfs interface. ++ * Note that the actual shutdown of monitoring on the CPU ++ * is done in pfm_cpu_disable(), see comments there for more ++ * information. ++ */ ++static int pfm_cpu_notify(struct notifier_block *nfb, ++ unsigned long action, void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ int ret = NOTIFY_OK; ++ ++ pfm_pmu_conf_get(0); ++ ++ switch (action) { ++ case CPU_ONLINE: ++ pfm_debugfs_add_cpu(cpu); ++ PFM_INFO("CPU%d is online", cpu); ++ break; ++ case CPU_UP_PREPARE: ++ PFM_INFO("CPU%d prepare online", cpu); ++ break; ++ case CPU_UP_CANCELED: ++ pfm_debugfs_del_cpu(cpu); ++ PFM_INFO("CPU%d is up canceled", cpu); ++ break; ++ case CPU_DOWN_PREPARE: ++ PFM_INFO("CPU%d prepare offline", cpu); ++ break; ++ case CPU_DOWN_FAILED: ++ PFM_INFO("CPU%d is down failed", cpu); ++ break; ++ case CPU_DEAD: ++ pfm_debugfs_del_cpu(cpu); ++ PFM_INFO("CPU%d is offline", cpu); ++ break; ++ } ++ pfm_pmu_conf_put(); ++ return ret; ++} ++ ++/* ++ * called from cpu_disable() to detach the perfmon context ++ * from the CPU going down. ++ * ++ * We cannot use the cpu hotplug notifier because we MUST run ++ * on the CPU that is going down to save the PMU state ++ */ ++void pfm_cpu_disable(void) ++{ ++ struct pfm_context *ctx; ++ unsigned long flags; ++ int is_system, release_info = 0; ++ u32 cpu; ++ int r; ++ ++ ctx = __get_cpu_var(pmu_ctx); ++ if (ctx == NULL) ++ return; ++ ++ is_system = ctx->flags.system; ++ cpu = ctx->cpu; ++ ++ /* ++ * context is LOADED or MASKED ++ * ++ * we unload from CPU. That stops monitoring and does ++ * all the bookeeping of saving values and updating duration ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ if (is_system) ++ __pfm_unload_context(ctx, &release_info); ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ /* ++ * cancel timer ++ */ ++ if (release_info & 0x2) { ++ r = hrtimer_cancel(&__get_cpu_var(pfm_hrtimer)); ++ PFM_DBG("timeout cancel=%d", r); ++ } ++ ++ if (release_info & 0x1) ++ pfm_session_release(is_system, cpu); ++} ++ ++static struct notifier_block pfm_cpu_notifier = { ++ .notifier_call = pfm_cpu_notify ++}; ++ ++int __init pfm_init_hotplug(void) ++{ ++ int ret = 0; ++ /* ++ * register CPU hotplug event notifier ++ */ ++ ret = register_cpu_notifier(&pfm_cpu_notifier); ++ if (!ret) ++ PFM_LOG("CPU hotplug support enabled"); ++ return ret; ++} ++#endif /* CONFIG_HOTPLUG_CPU */ +--- /dev/null ++++ b/perfmon/perfmon_init.c +@@ -0,0 +1,131 @@ ++/* ++ * perfmon.c: perfmon2 global initialization functions ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include "perfmon_priv.h" ++ ++/* ++ * external variables ++ */ ++DEFINE_PER_CPU(struct task_struct *, pmu_owner); ++DEFINE_PER_CPU(struct pfm_context *, pmu_ctx); ++DEFINE_PER_CPU(u64, pmu_activation_number); ++DEFINE_PER_CPU(struct pfm_stats, pfm_stats); ++DEFINE_PER_CPU(struct hrtimer, pfm_hrtimer); ++ ++ ++int perfmon_disabled; /* >0 if perfmon is disabled */ ++ ++/* ++ * called from cpu_init() and pfm_pmu_register() ++ */ ++void __pfm_init_percpu(void *dummy) ++{ ++ struct hrtimer *h; ++ ++ h = &__get_cpu_var(pfm_hrtimer); ++ ++ pfm_arch_init_percpu(); ++ ++ /* ++ * initialize per-cpu high res timer ++ */ ++ hrtimer_init(h, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++#ifdef CONFIG_HIGH_RES_TIMERS ++ /* ++ * avoid potential deadlock on the runqueue lock ++ * during context switch when multiplexing. Situation ++ * arises on architectures which run switch_to() with ++ * the runqueue lock held, e.g., x86. On others, e.g., ++ * IA-64, the problem does not exist. ++ * Setting the callback mode to HRTIMER_CB_IRQSAFE_UNOCKED ++ * such that the callback routine is only called on hardirq ++ * context not on softirq, thus the context switch will not ++ * end up trying to wakeup the softirqd ++ */ ++ h->cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED; ++#endif ++ h->function = pfm_handle_switch_timeout; ++} ++ ++/* ++ * global initialization routine, executed only once ++ */ ++int __init pfm_init(void) ++{ ++ PFM_LOG("version %u.%u", PFM_VERSION_MAJ, PFM_VERSION_MIN); ++ ++ if (pfm_init_ctx()) ++ goto error_disable; ++ ++ ++ if (pfm_init_sets()) ++ goto error_disable; ++ ++ if (pfm_init_fs()) ++ goto error_disable; ++ ++ if (pfm_init_sysfs()) ++ goto error_disable; ++ ++ /* not critical, so no error checking */ ++ pfm_init_debugfs(); ++ ++ /* ++ * one time, arch-specific global initialization ++ */ ++ if (pfm_arch_init()) ++ goto error_disable; ++ ++ if (pfm_init_hotplug()) ++ goto error_disable; ++ return 0; ++ ++error_disable: ++ PFM_ERR("perfmon is disabled due to initialization error"); ++ perfmon_disabled = 1; ++ return -1; ++} ++ ++/* ++ * must use subsys_initcall() to ensure that the perfmon2 core ++ * is initialized before any PMU description module when they are ++ * compiled in. ++ */ ++subsys_initcall(pfm_init); +--- /dev/null ++++ b/perfmon/perfmon_intr.c +@@ -0,0 +1,648 @@ ++/* ++ * perfmon_intr.c: perfmon2 interrupt handling ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++/** ++ * pfm_intr_process_64bit_ovfls - handle 64-bit counter emulation ++ * @ctx: context to operate on ++ * @set: set to operate on ++ * ++ * The function returns the number of 64-bit overflows detected. ++ * ++ * 64-bit software pmds are updated for overflowed pmd registers ++ * the set->reset_pmds is updated to the list of pmds to reset ++ * ++ * In any case, set->npend_ovfls is cleared ++ */ ++static u16 pfm_intr_process_64bit_ovfls(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ u32 *ovfl_ctrl) ++{ ++ u16 i, num_ovfls, max_pmd, max_intr; ++ u16 num_64b_ovfls, has_ovfl_sw, must_switch; ++ u64 ovfl_thres, old_val, new_val, ovfl_mask; ++ ++ num_64b_ovfls = must_switch = 0; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ max_pmd = ctx->regs.max_pmd; ++ max_intr = ctx->regs.max_intr_pmd; ++ ++ num_ovfls = set->npend_ovfls; ++ has_ovfl_sw = set->flags & PFM_SETFL_OVFL_SWITCH; ++ ++ bitmap_zero(cast_ulp(set->reset_pmds), max_pmd); ++ ++ for (i = ctx->regs.first_intr_pmd; num_ovfls; i++) { ++ /* ++ * skip pmd which did not overflow ++ */ ++ if (!test_bit(i, cast_ulp(set->povfl_pmds))) ++ continue; ++ ++ num_ovfls--; ++ ++ /* ++ * Update software value for counters ONLY ++ * ++ * Note that the pmd is not necessarily 0 at this point as ++ * qualified events may have happened before the PMU was ++ * frozen. The residual count is not taken into consideration ++ * here but will be with any read of the pmd ++ */ ++ ovfl_thres = set->pmds[i].ovflsw_thres; ++ ++ if (likely(test_bit(i, cast_ulp(ctx->regs.cnt_pmds)))) { ++ old_val = new_val = set->pmds[i].value; ++ new_val += 1 + ovfl_mask; ++ set->pmds[i].value = new_val; ++ } else { ++ /* ++ * for non counters which interrupt, e.g., AMD IBS, ++ * we consider this equivalent to a 64-bit counter ++ * overflow. ++ */ ++ old_val = 1; new_val = 0; ++ } ++ ++ /* ++ * check for 64-bit overflow condition ++ */ ++ if (likely(old_val > new_val)) { ++ num_64b_ovfls++; ++ if (has_ovfl_sw && ovfl_thres > 0) { ++ if (ovfl_thres == 1) ++ must_switch = 1; ++ set->pmds[i].ovflsw_thres = ovfl_thres - 1; ++ } ++ ++ /* ++ * what to reset because of this overflow ++ * - the overflowed register ++ * - its reset_smpls ++ */ ++ __set_bit(i, cast_ulp(set->reset_pmds)); ++ ++ bitmap_or(cast_ulp(set->reset_pmds), ++ cast_ulp(set->reset_pmds), ++ cast_ulp(set->pmds[i].reset_pmds), ++ max_pmd); ++ } else { ++ /* ++ * only keep track of 64-bit overflows or ++ * assimilated ++ */ ++ __clear_bit(i, cast_ulp(set->povfl_pmds)); ++ ++ /* ++ * on some PMU, it may be necessary to re-arm the PMD ++ */ ++ pfm_arch_ovfl_reset_pmd(ctx, i); ++ } ++ ++ PFM_DBG_ovfl("ovfl=%s pmd%u new=0x%llx old=0x%llx " ++ "hw_pmd=0x%llx o_pmds=0x%llx must_switch=%u " ++ "o_thres=%llu o_thres_ref=%llu", ++ old_val > new_val ? "64-bit" : "HW", ++ i, ++ (unsigned long long)new_val, ++ (unsigned long long)old_val, ++ (unsigned long long)pfm_read_pmd(ctx, i), ++ (unsigned long long)set->povfl_pmds[0], ++ must_switch, ++ (unsigned long long)set->pmds[i].ovflsw_thres, ++ (unsigned long long)set->pmds[i].ovflsw_ref_thres); ++ } ++ /* ++ * update public bitmask of 64-bit overflowed pmds ++ */ ++ if (num_64b_ovfls) ++ bitmap_copy(cast_ulp(set->ovfl_pmds), cast_ulp(set->povfl_pmds), ++ max_intr); ++ ++ if (must_switch) ++ *ovfl_ctrl |= PFM_OVFL_CTRL_SWITCH; ++ ++ /* ++ * mark the overflows as consumed ++ */ ++ set->npend_ovfls = 0; ++ bitmap_zero(cast_ulp(set->povfl_pmds), max_intr); ++ ++ return num_64b_ovfls; ++} ++ ++/** ++ * pfm_intr_get_smpl_pmds_values - copy 64-bit pmd values for sampling format ++ * @ctx: context to work on ++ * @set: current event set ++ * @arg: overflow arg to be passed to format ++ * @smpl_pmds: list of PMDs of interest for the overflowed register ++ * ++ * build an array of 46-bit PMD values based on smpl_pmds. Values are ++ * stored in increasing order of the PMD indexes ++ */ ++static void pfm_intr_get_smpl_pmds_values(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfm_ovfl_arg *arg, ++ u64 *smpl_pmds) ++{ ++ u16 j, k, max_pmd; ++ u64 new_val, ovfl_mask; ++ u64 *cnt_pmds; ++ ++ cnt_pmds = ctx->regs.cnt_pmds; ++ max_pmd = ctx->regs.max_pmd; ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ ++ for (j = k = 0; j < max_pmd; j++) { ++ ++ if (!test_bit(j, cast_ulp(smpl_pmds))) ++ continue; ++ ++ new_val = pfm_read_pmd(ctx, j); ++ ++ /* for counters, build 64-bit value */ ++ if (test_bit(j, cast_ulp(cnt_pmds))) ++ new_val = (set->pmds[j].value & ~ovfl_mask) ++ | (new_val & ovfl_mask); ++ ++ arg->smpl_pmds_values[k++] = new_val; ++ ++ PFM_DBG_ovfl("s_pmd_val[%u]=pmd%u=0x%llx", k, j, ++ (unsigned long long)new_val); ++ } ++ arg->num_smpl_pmds = k; ++} ++ ++/** ++ * pfm_intr_process_smpl_fmt -- handle sampling format callback ++ * @ctx: context to work on ++ * @set: current event set ++ * @ip: interrupted instruction pointer ++ * @now: timestamp ++ * @num_ovfls: number of 64-bit overflows ++ * @ovfl_ctrl: set of controls for interrupt handler tail processing ++ * @regs: register state ++ * ++ * Prepare argument (ovfl_arg) to be passed to sampling format callback, then ++ * invoke the callback (fmt_handler) ++ */ ++static int pfm_intr_process_smpl_fmt(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ unsigned long ip, ++ u64 now, ++ u64 num_ovfls, ++ u32 *ovfl_ctrl, ++ struct pt_regs *regs) ++{ ++ struct pfm_ovfl_arg *ovfl_arg; ++ u64 start_cycles, end_cycles; ++ u16 i, max_pmd; ++ int ret = 0; ++ ++ ovfl_arg = &ctx->ovfl_arg; ++ ++ ovfl_arg->active_set = set->id; ++ max_pmd = ctx->regs.max_pmd; ++ ++ /* ++ * first_intr_pmd: first PMD which can generate PMU interrupts ++ */ ++ for (i = ctx->regs.first_intr_pmd; num_ovfls; i++) { ++ /* ++ * skip pmd which did not have 64-bit overflows ++ */ ++ if (!test_bit(i, cast_ulp(set->ovfl_pmds))) ++ continue; ++ ++ num_ovfls--; ++ ++ /* ++ * prepare argument to fmt_handler ++ */ ++ ovfl_arg->ovfl_pmd = i; ++ ovfl_arg->ovfl_ctrl = 0; ++ ++ ovfl_arg->pmd_last_reset = set->pmds[i].lval; ++ ovfl_arg->pmd_eventid = set->pmds[i].eventid; ++ ovfl_arg->num_smpl_pmds = 0; ++ ++ /* ++ * copy values of pmds of interest, if any ++ * Sampling format may use them ++ * We do not initialize the unused smpl_pmds_values ++ */ ++ if (!bitmap_empty(cast_ulp(set->pmds[i].smpl_pmds), max_pmd)) ++ pfm_intr_get_smpl_pmds_values(ctx, set, ovfl_arg, ++ set->pmds[i].smpl_pmds); ++ ++ pfm_stats_inc(fmt_handler_calls); ++ ++ /* ++ * call format record (handler) routine ++ */ ++ start_cycles = sched_clock(); ++ ret = (*ctx->smpl_fmt->fmt_handler)(ctx, ip, now, regs); ++ end_cycles = sched_clock(); ++ ++ /* ++ * The reset_pmds mask is constructed automatically ++ * on overflow. When the actual reset takes place ++ * depends on the masking, switch and notification ++ * status. It may be deferred until pfm_restart(). ++ */ ++ *ovfl_ctrl |= ovfl_arg->ovfl_ctrl; ++ ++ pfm_stats_add(fmt_handler_ns, end_cycles - start_cycles); ++ } ++ /* ++ * when the format cannot handle the rest of the overflow, we abort ++ */ ++ if (ret) ++ PFM_DBG_ovfl("handler aborted at PMD%u ret=%d", i, ret); ++ return ret; ++} ++/** ++ * pfm_overflow_handler - main overflow processing routine. ++ * @ctx: context to work on (always current context) ++ * @set: current event set ++ * @ip: interrupt instruction pointer ++ * @regs: machine state ++ * ++ * set->num_ovfl_pmds is 0 when returning from this function even though ++ * set->ovfl_pmds[] may have bits set. When leaving set->num_ovfl_pmds ++ * must never be used to determine if there was a pending overflow. ++ */ ++static void pfm_overflow_handler(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ unsigned long ip, ++ struct pt_regs *regs) ++{ ++ struct pfm_event_set *set_orig; ++ u64 now; ++ u32 ovfl_ctrl; ++ u16 max_intr, max_pmd; ++ u16 num_ovfls; ++ int ret, has_notify; ++ ++ /* ++ * take timestamp ++ */ ++ now = sched_clock(); ++ ++ max_pmd = ctx->regs.max_pmd; ++ max_intr = ctx->regs.max_intr_pmd; ++ ++ set_orig = set; ++ ovfl_ctrl = 0; ++ ++ /* ++ * skip ZOMBIE case ++ */ ++ if (unlikely(ctx->state == PFM_CTX_ZOMBIE)) ++ goto stop_monitoring; ++ ++ PFM_DBG_ovfl("intr_pmds=0x%llx npend=%u ip=%p, blocking=%d " ++ "u_pmds=0x%llx use_fmt=%u", ++ (unsigned long long)set->povfl_pmds[0], ++ set->npend_ovfls, ++ (void *)ip, ++ ctx->flags.block, ++ (unsigned long long)set->used_pmds[0], ++ !!ctx->smpl_fmt); ++ ++ /* ++ * return number of 64-bit overflows ++ */ ++ num_ovfls = pfm_intr_process_64bit_ovfls(ctx, set, &ovfl_ctrl); ++ ++ /* ++ * there were no 64-bit overflows ++ * nothing else to do ++ */ ++ if (!num_ovfls) ++ return; ++ ++ /* ++ * tmp_ovfl_notify = ovfl_pmds & ovfl_notify ++ * with: ++ * - ovfl_pmds: last 64-bit overflowed pmds ++ * - ovfl_notify: notify on overflow registers ++ */ ++ bitmap_and(cast_ulp(ctx->tmp_ovfl_notify), ++ cast_ulp(set->ovfl_pmds), ++ cast_ulp(set->ovfl_notify), ++ max_intr); ++ ++ has_notify = !bitmap_empty(cast_ulp(ctx->tmp_ovfl_notify), max_intr); ++ ++ /* ++ * check for sampling format and invoke fmt_handler ++ */ ++ if (likely(ctx->smpl_fmt)) { ++ pfm_intr_process_smpl_fmt(ctx, set, ip, now, num_ovfls, ++ &ovfl_ctrl, regs); ++ } else { ++ /* ++ * When no sampling format is used, the default ++ * is: ++ * - mask monitoring if not switching ++ * - notify user if requested ++ * ++ * If notification is not requested, monitoring is masked ++ * and overflowed registers are not reset (saturation). ++ * This mimics the behavior of the default sampling format. ++ */ ++ ovfl_ctrl |= PFM_OVFL_CTRL_NOTIFY; ++ if (has_notify || !(ovfl_ctrl & PFM_OVFL_CTRL_SWITCH)) ++ ovfl_ctrl |= PFM_OVFL_CTRL_MASK; ++ } ++ ++ PFM_DBG_ovfl("set%u o_notify=0x%llx o_pmds=0x%llx " ++ "r_pmds=0x%llx ovfl_ctrl=0x%x", ++ set->id, ++ (unsigned long long)ctx->tmp_ovfl_notify[0], ++ (unsigned long long)set->ovfl_pmds[0], ++ (unsigned long long)set->reset_pmds[0], ++ ovfl_ctrl); ++ ++ /* ++ * execute the various controls ++ * ORDER MATTERS ++ */ ++ ++ ++ /* ++ * mask monitoring ++ */ ++ if (ovfl_ctrl & PFM_OVFL_CTRL_MASK) { ++ pfm_mask_monitoring(ctx, set); ++ /* ++ * when masking, reset is deferred until ++ * pfm_restart() ++ */ ++ ovfl_ctrl &= ~PFM_OVFL_CTRL_RESET; ++ ++ /* ++ * when masking, switching is deferred until ++ * pfm_restart and we need to remember it ++ */ ++ if (ovfl_ctrl & PFM_OVFL_CTRL_SWITCH) { ++ set->priv_flags |= PFM_SETFL_PRIV_SWITCH; ++ ovfl_ctrl &= ~PFM_OVFL_CTRL_SWITCH; ++ } ++ } ++ ++ /* ++ * switch event set ++ */ ++ if (ovfl_ctrl & PFM_OVFL_CTRL_SWITCH) { ++ pfm_switch_sets_from_intr(ctx); ++ /* update view of active set */ ++ set = ctx->active_set; ++ } ++ /* ++ * send overflow notification ++ * ++ * only necessary if at least one overflowed ++ * register had the notify flag set ++ */ ++ if (has_notify && (ovfl_ctrl & PFM_OVFL_CTRL_NOTIFY)) { ++ /* ++ * block on notify, not on masking ++ */ ++ if (ctx->flags.block) ++ pfm_post_work(current, ctx, PFM_WORK_BLOCK); ++ ++ /* ++ * send notification and passed original set id ++ * if error, queue full, for instance, then default ++ * to masking monitoring, i.e., saturate ++ */ ++ ret = pfm_ovfl_notify(ctx, set_orig, ip); ++ if (unlikely(ret)) { ++ if (ctx->state == PFM_CTX_LOADED) { ++ pfm_mask_monitoring(ctx, set); ++ ovfl_ctrl &= ~PFM_OVFL_CTRL_RESET; ++ } ++ } else { ++ ctx->flags.can_restart++; ++ PFM_DBG_ovfl("can_restart=%u", ctx->flags.can_restart); ++ } ++ } ++ ++ /* ++ * reset overflowed registers ++ */ ++ if (ovfl_ctrl & PFM_OVFL_CTRL_RESET) { ++ u16 nn; ++ nn = bitmap_weight(cast_ulp(set->reset_pmds), max_pmd); ++ if (nn) ++ pfm_reset_pmds(ctx, set, nn, PFM_PMD_RESET_SHORT); ++ } ++ return; ++ ++stop_monitoring: ++ /* ++ * Does not happen for a system-wide context nor for a ++ * self-monitored context. We cannot attach to kernel-only ++ * thread, thus it is safe to set TIF bits, i.e., the thread ++ * will eventually leave the kernel or die and either we will ++ * catch the context and clean it up in pfm_handler_work() or ++ * pfm_exit_thread(). ++ * ++ * Mask until we get to pfm_handle_work() ++ */ ++ pfm_mask_monitoring(ctx, set); ++ ++ PFM_DBG_ovfl("ctx is zombie, converted to spurious"); ++ pfm_post_work(current, ctx, PFM_WORK_ZOMBIE); ++} ++ ++/** ++ * __pfm_interrupt_handler - 1st level interrupt handler ++ * @ip: interrupted instruction pointer ++ * @regs: machine state ++ * ++ * Function is static because we use a wrapper to easily capture timing infos. ++ * ++ * ++ * Context locking necessary to avoid concurrent accesses from other CPUs ++ * - For per-thread, we must prevent pfm_restart() which works when ++ * context is LOADED or MASKED ++ */ ++static void __pfm_interrupt_handler(unsigned long ip, struct pt_regs *regs) ++{ ++ struct task_struct *task; ++ struct pfm_context *ctx; ++ struct pfm_event_set *set; ++ ++ ++ task = __get_cpu_var(pmu_owner); ++ ctx = __get_cpu_var(pmu_ctx); ++ ++ /* ++ * verify if there is a context on this CPU ++ */ ++ if (unlikely(ctx == NULL)) { ++ PFM_DBG_ovfl("no ctx"); ++ goto spurious; ++ } ++ ++ /* ++ * we need to lock context because it could be accessed ++ * from another CPU. Depending on the priority level of ++ * the PMU interrupt or the arch, it may be necessary to ++ * mask interrupts alltogether to avoid race condition with ++ * the timer interrupt in case of time-based set switching, ++ * for instance. ++ */ ++ spin_lock(&ctx->lock); ++ ++ set = ctx->active_set; ++ ++ /* ++ * For SMP per-thread, it is not possible to have ++ * owner != NULL && task != current. ++ * ++ * For UP per-thread, because of lazy save, it ++ * is possible to receive an interrupt in another task ++ * which is not using the PMU. This means ++ * that the interrupt was in-flight at the ++ * time of pfm_ctxswout_thread(). In that ++ * case, it will be replayed when the task ++ * is scheduled again. Hence we convert to spurious. ++ * ++ * The basic rule is that an overflow is always ++ * processed in the context of the task that ++ * generated it for all per-thread contexts. ++ * ++ * for system-wide, task is always NULL ++ */ ++#ifndef CONFIG_SMP ++ if (unlikely((task && current->pfm_context != ctx))) { ++ PFM_DBG_ovfl("spurious: not owned by current task"); ++ goto spurious; ++ } ++#endif ++ if (unlikely(ctx->state == PFM_CTX_MASKED)) { ++ PFM_DBG_ovfl("spurious: monitoring masked"); ++ goto spurious; ++ } ++ ++ /* ++ * check that monitoring is active, otherwise convert ++ * to spurious ++ */ ++ if (unlikely(!pfm_arch_is_active(ctx))) { ++ PFM_DBG_ovfl("spurious: monitoring non active"); ++ goto spurious; ++ } ++ ++ /* ++ * freeze PMU and collect overflowed PMD registers ++ * into set->povfl_pmds. Number of overflowed PMDs ++ * reported in set->npend_ovfls ++ */ ++ pfm_arch_intr_freeze_pmu(ctx, set); ++ ++ /* ++ * no overflow detected, interrupt may have come ++ * from the previous thread running on this CPU ++ */ ++ if (unlikely(!set->npend_ovfls)) { ++ PFM_DBG_ovfl("no npend_ovfls"); ++ goto spurious; ++ } ++ ++ pfm_stats_inc(ovfl_intr_regular_count); ++ ++ /* ++ * invoke actual handler ++ */ ++ pfm_overflow_handler(ctx, set, ip, regs); ++ ++ /* ++ * unfreeze PMU, monitoring may not actual be restarted ++ * if context is MASKED ++ */ ++ pfm_arch_intr_unfreeze_pmu(ctx); ++ ++ spin_unlock(&ctx->lock); ++ ++ return; ++ ++spurious: ++ /* ctx may be NULL */ ++ pfm_arch_intr_unfreeze_pmu(ctx); ++ if (ctx) ++ spin_unlock(&ctx->lock); ++ ++ pfm_stats_inc(ovfl_intr_spurious_count); ++} ++ ++ ++/** ++ * pfm_interrupt_handler - 1st level interrupt handler ++ * @ip: interrupt instruction pointer ++ * @regs: machine state ++ * ++ * Function called from the low-level assembly code or arch-specific perfmon ++ * code. Simple wrapper used for timing purpose. Actual work done in ++ * __pfm_overflow_handler() ++ */ ++void pfm_interrupt_handler(unsigned long ip, struct pt_regs *regs) ++{ ++ u64 start; ++ ++ pfm_stats_inc(ovfl_intr_all_count); ++ ++ BUG_ON(!irqs_disabled()); ++ ++ start = sched_clock(); ++ ++ __pfm_interrupt_handler(ip, regs); ++ ++ pfm_stats_add(ovfl_intr_ns, sched_clock() - start); ++} ++EXPORT_SYMBOL(pfm_interrupt_handler); ++ +--- /dev/null ++++ b/perfmon/perfmon_msg.c +@@ -0,0 +1,229 @@ ++/* ++ * perfmon_msg.c: perfmon2 notification message queue management ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++ ++/** ++ * pfm_get_new_msg - get a new message slot from the queue ++ * @ctx: context to operate on ++ * ++ * if queue if full NULL is returned ++ */ ++static union pfarg_msg *pfm_get_new_msg(struct pfm_context *ctx) ++{ ++ int next; ++ ++ next = ctx->msgq_head & PFM_MSGQ_MASK; ++ ++ if ((ctx->msgq_head - ctx->msgq_tail) == PFM_MSGS_COUNT) ++ return NULL; ++ ++ /* ++ * move to next possible slot ++ */ ++ ctx->msgq_head++; ++ ++ PFM_DBG_ovfl("head=%d tail=%d msg=%d", ++ ctx->msgq_head & PFM_MSGQ_MASK, ++ ctx->msgq_tail & PFM_MSGQ_MASK, ++ next); ++ ++ return ctx->msgq+next; ++} ++ ++/** ++ * pfm_notify_user - wakeup any thread wiating on msg queue, post SIGIO ++ * @ctx: context to operate on ++ * ++ * message is already enqueued ++ */ ++static void pfm_notify_user(struct pfm_context *ctx) ++{ ++ if (ctx->state == PFM_CTX_ZOMBIE) { ++ PFM_DBG("no notification, context is zombie"); ++ return; ++ } ++ ++ PFM_DBG_ovfl("waking up"); ++ ++ wake_up_interruptible(&ctx->msgq_wait); ++ ++ /* ++ * it is safe to call kill_fasync() from an interrupt ++ * handler. kill_fasync() grabs two RW locks (fasync_lock, ++ * tasklist_lock) in read mode. There is conflict only in ++ * case the PMU interrupt occurs during a write mode critical ++ * section. This cannot happen because for both locks, the ++ * write mode is always using interrupt masking (write_lock_irq). ++ */ ++ kill_fasync(&ctx->async_queue, SIGIO, POLL_IN); ++} ++ ++/** ++ * pfm_ovfl_notify - send overflow notification ++ * @ctx: context to operate on ++ * @set: which set the overflow comes from ++ * @ip: overflow interrupt instruction address (IIP) ++ * ++ * Appends an overflow notification message to context queue. ++ * call pfm_notify() to wakeup any threads and/or send a signal ++ * ++ * Context is locked and interrupts are disabled (no preemption). ++ */ ++int pfm_ovfl_notify(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ unsigned long ip) ++{ ++ union pfarg_msg *msg = NULL; ++ u64 *ovfl_pmds; ++ ++ if (!ctx->flags.no_msg) { ++ msg = pfm_get_new_msg(ctx); ++ if (msg == NULL) { ++ /* ++ * when message queue fills up it is because the user ++ * did not extract the message, yet issued ++ * pfm_restart(). At this point, we stop sending ++ * notification, thus the user will not be able to get ++ * new samples when using the default format. ++ */ ++ PFM_DBG_ovfl("no more notification msgs"); ++ return -1; ++ } ++ ++ msg->pfm_ovfl_msg.msg_type = PFM_MSG_OVFL; ++ msg->pfm_ovfl_msg.msg_ovfl_pid = current->pid; ++ msg->pfm_ovfl_msg.msg_active_set = set->id; ++ ++ ovfl_pmds = msg->pfm_ovfl_msg.msg_ovfl_pmds; ++ ++ /* ++ * copy bitmask of all pmd that interrupted last ++ */ ++ bitmap_copy(cast_ulp(ovfl_pmds), cast_ulp(set->ovfl_pmds), ++ ctx->regs.max_intr_pmd); ++ ++ msg->pfm_ovfl_msg.msg_ovfl_cpu = smp_processor_id(); ++ msg->pfm_ovfl_msg.msg_ovfl_tid = current->tgid; ++ msg->pfm_ovfl_msg.msg_ovfl_ip = ip; ++ ++ pfm_stats_inc(ovfl_notify_count); ++ } ++ ++ PFM_DBG_ovfl("ip=0x%lx o_pmds=0x%llx", ++ ip, ++ (unsigned long long)set->ovfl_pmds[0]); ++ ++ pfm_notify_user(ctx); ++ return 0; ++} ++ ++/** ++ * pfm_end_notify_user - notify of thread termination ++ * @ctx: context to operate on ++ * ++ * In per-thread mode, when not self-monitoring, perfmon ++ * sends a 'end' notification message when the monitored ++ * thread where the context is attached is exiting. ++ * ++ * This helper message alleviates the need to track the activity ++ * of the thread/process when it is not directly related, i.e., ++ * was attached. In other words, no needto keep the thread ++ * ptraced. ++ * ++ * The context must be locked and interrupts disabled. ++ */ ++int pfm_end_notify(struct pfm_context *ctx) ++{ ++ union pfarg_msg *msg; ++ ++ msg = pfm_get_new_msg(ctx); ++ if (msg == NULL) { ++ PFM_ERR("%s no more msgs", __func__); ++ return -1; ++ } ++ /* no leak */ ++ memset(msg, 0, sizeof(*msg)); ++ ++ msg->type = PFM_MSG_END; ++ ++ PFM_DBG("end msg: msg=%p no_msg=%d", ++ msg, ++ ctx->flags.no_msg); ++ ++ pfm_notify_user(ctx); ++ return 0; ++} ++ ++/** ++ * pfm_get_next_msg - copy the oldest message from the queue and move tail ++ * @ctx: context to use ++ * @m: where to copy the message into ++ * ++ * The tail of the queue is moved as a consequence of this call ++ */ ++void pfm_get_next_msg(struct pfm_context *ctx, union pfarg_msg *m) ++{ ++ union pfarg_msg *next; ++ ++ PFM_DBG_ovfl("in head=%d tail=%d", ++ ctx->msgq_head & PFM_MSGQ_MASK, ++ ctx->msgq_tail & PFM_MSGQ_MASK); ++ ++ /* ++ * get oldest message ++ */ ++ next = ctx->msgq + (ctx->msgq_tail & PFM_MSGQ_MASK); ++ ++ /* ++ * move tail forward ++ */ ++ ctx->msgq_tail++; ++ ++ /* ++ * copy message, we cannot simply point to it ++ * as it may be re-used before we copy it out ++ */ ++ *m = *next; ++ ++ PFM_DBG_ovfl("out head=%d tail=%d type=%d", ++ ctx->msgq_head & PFM_MSGQ_MASK, ++ ctx->msgq_tail & PFM_MSGQ_MASK, ++ m->type); ++} +--- /dev/null ++++ b/perfmon/perfmon_pmu.c +@@ -0,0 +1,590 @@ ++/* ++ * perfmon_pmu.c: perfmon2 PMU configuration management ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include "perfmon_priv.h" ++ ++#ifndef CONFIG_MODULE_UNLOAD ++#define module_refcount(n) 1 ++#endif ++ ++static __cacheline_aligned_in_smp int request_mod_in_progress; ++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pfm_pmu_conf_lock); ++ ++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pfm_pmu_acq_lock); ++static u32 pfm_pmu_acquired; ++ ++/* ++ * perfmon core must acces PMU information ONLY through pfm_pmu_conf ++ * if pfm_pmu_conf is NULL, then no description is registered ++ */ ++struct pfm_pmu_config *pfm_pmu_conf; ++EXPORT_SYMBOL(pfm_pmu_conf); ++ ++static inline int pmu_is_module(struct pfm_pmu_config *c) ++{ ++ return !(c->flags & PFM_PMUFL_IS_BUILTIN); ++} ++/** ++ * pfm_pmu_regdesc_init -- initialize regdesc structure from PMU table ++ * @regs: the regdesc structure to initialize ++ * @excl_type: the register type(s) to exclude from this regdesc ++ * @unvail_pmcs: unavailable PMC registers ++ * @unavail_pmds: unavailable PMD registers ++ * ++ * Return: ++ * 0 success ++ * errno in case of error ++ */ ++static int pfm_pmu_regdesc_init(struct pfm_regdesc *regs, int excl_type, ++ u64 *unavail_pmcs, u64 *unavail_pmds) ++{ ++ struct pfm_regmap_desc *d; ++ u16 n, n2, n_counters, i; ++ int first_intr_pmd = -1, max1, max2, max3; ++ ++ /* ++ * compute the number of implemented PMC from the ++ * description table ++ */ ++ n = 0; ++ max1 = max2 = -1; ++ d = pfm_pmu_conf->pmc_desc; ++ for (i = 0; i < pfm_pmu_conf->num_pmc_entries; i++, d++) { ++ if (!(d->type & PFM_REG_I)) ++ continue; ++ ++ if (test_bit(i, cast_ulp(unavail_pmcs))) ++ continue; ++ ++ if (d->type & excl_type) ++ continue; ++ ++ __set_bit(i, cast_ulp(regs->pmcs)); ++ ++ max1 = i; ++ n++; ++ } ++ ++ if (!n) { ++ PFM_INFO("%s PMU description has no PMC registers", ++ pfm_pmu_conf->pmu_name); ++ return -EINVAL; ++ } ++ ++ regs->max_pmc = max1 + 1; ++ regs->num_pmcs = n; ++ ++ n = n_counters = n2 = 0; ++ max1 = max2 = max3 = -1; ++ d = pfm_pmu_conf->pmd_desc; ++ for (i = 0; i < pfm_pmu_conf->num_pmd_entries; i++, d++) { ++ if (!(d->type & PFM_REG_I)) ++ continue; ++ ++ if (test_bit(i, cast_ulp(unavail_pmds))) ++ continue; ++ ++ if (d->type & excl_type) ++ continue; ++ ++ __set_bit(i, cast_ulp(regs->pmds)); ++ max1 = i; ++ n++; ++ ++ /* ++ * read-write registers ++ */ ++ if (!(d->type & PFM_REG_RO)) { ++ __set_bit(i, cast_ulp(regs->rw_pmds)); ++ max3 = i; ++ n2++; ++ } ++ ++ /* ++ * counter registers ++ */ ++ if (d->type & PFM_REG_C64) { ++ __set_bit(i, cast_ulp(regs->cnt_pmds)); ++ n_counters++; ++ } ++ ++ /* ++ * PMD with intr capabilities ++ */ ++ if (d->type & PFM_REG_INTR) { ++ __set_bit(i, cast_ulp(regs->intr_pmds)); ++ if (first_intr_pmd == -1) ++ first_intr_pmd = i; ++ max2 = i; ++ } ++ } ++ ++ if (!n) { ++ PFM_INFO("%s PMU description has no PMD registers", ++ pfm_pmu_conf->pmu_name); ++ return -EINVAL; ++ } ++ ++ regs->max_pmd = max1 + 1; ++ regs->first_intr_pmd = first_intr_pmd; ++ regs->max_intr_pmd = max2 + 1; ++ ++ regs->num_counters = n_counters; ++ regs->num_pmds = n; ++ regs->max_rw_pmd = max3 + 1; ++ regs->num_rw_pmd = n2; ++ ++ return 0; ++} ++ ++/** ++ * pfm_pmu_regdesc_init_all -- initialize all regdesc structures ++ * @una_pmcs : unavailable PMC registers ++ * @una_pmds : unavailable PMD registers ++ * ++ * Return: ++ * 0 sucess ++ * errno if error ++ * ++ * We maintain 3 regdesc: ++ * regs_all: all available registers ++ * regs_sys: registers available to system-wide contexts only ++ * regs_thr: registers available to per-thread contexts only ++ */ ++static int pfm_pmu_regdesc_init_all(u64 *una_pmcs, u64 *una_pmds) ++{ ++ int ret; ++ ++ memset(&pfm_pmu_conf->regs_all, 0, sizeof(struct pfm_regdesc)); ++ memset(&pfm_pmu_conf->regs_thr, 0, sizeof(struct pfm_regdesc)); ++ memset(&pfm_pmu_conf->regs_sys, 0, sizeof(struct pfm_regdesc)); ++ ++ ret = pfm_pmu_regdesc_init(&pfm_pmu_conf->regs_all, ++ 0, ++ una_pmcs, una_pmds); ++ if (ret) ++ return ret; ++ ++ PFM_DBG("regs_all.pmcs=0x%llx", ++ (unsigned long long)pfm_pmu_conf->regs_all.pmcs[0]); ++ ++ ret = pfm_pmu_regdesc_init(&pfm_pmu_conf->regs_thr, ++ PFM_REG_SYS, ++ una_pmcs, una_pmds); ++ if (ret) ++ return ret; ++ PFM_DBG("regs.thr.pmcs=0x%llx", ++ (unsigned long long)pfm_pmu_conf->regs_thr.pmcs[0]); ++ ++ ret = pfm_pmu_regdesc_init(&pfm_pmu_conf->regs_sys, ++ PFM_REG_THR, ++ una_pmcs, una_pmds); ++ ++ PFM_DBG("regs_sys.pmcs=0x%llx", ++ (unsigned long long)pfm_pmu_conf->regs_sys.pmcs[0]); ++ ++ return ret; ++} ++ ++int pfm_pmu_register(struct pfm_pmu_config *cfg) ++{ ++ u16 i, nspec, nspec_ro, num_pmcs, num_pmds, num_wc = 0; ++ int type, ret = -EBUSY; ++ ++ if (perfmon_disabled) { ++ PFM_INFO("perfmon disabled, cannot add PMU description"); ++ return -ENOSYS; ++ } ++ ++ nspec = nspec_ro = num_pmds = num_pmcs = 0; ++ ++ /* some sanity checks */ ++ if (cfg == NULL || cfg->pmu_name == NULL) { ++ PFM_INFO("PMU config descriptor is invalid"); ++ return -EINVAL; ++ } ++ ++ /* must have a probe */ ++ if (cfg->probe_pmu == NULL) { ++ PFM_INFO("PMU config has no probe routine"); ++ return -EINVAL; ++ } ++ ++ /* ++ * execute probe routine before anything else as it ++ * may update configuration tables ++ */ ++ if ((*cfg->probe_pmu)() == -1) { ++ PFM_INFO("%s PMU detection failed", cfg->pmu_name); ++ return -EINVAL; ++ } ++ ++ if (!(cfg->flags & PFM_PMUFL_IS_BUILTIN) && cfg->owner == NULL) { ++ PFM_INFO("PMU config %s is missing owner", cfg->pmu_name); ++ return -EINVAL; ++ } ++ ++ if (!cfg->num_pmd_entries) { ++ PFM_INFO("%s needs to define num_pmd_entries", cfg->pmu_name); ++ return -EINVAL; ++ } ++ ++ if (!cfg->num_pmc_entries) { ++ PFM_INFO("%s needs to define num_pmc_entries", cfg->pmu_name); ++ return -EINVAL; ++ } ++ ++ if (!cfg->counter_width) { ++ PFM_INFO("PMU config %s, zero width counters", cfg->pmu_name); ++ return -EINVAL; ++ } ++ ++ /* ++ * REG_RO, REG_V not supported on PMC registers ++ */ ++ for (i = 0; i < cfg->num_pmc_entries; i++) { ++ ++ type = cfg->pmc_desc[i].type; ++ ++ if (type & PFM_REG_I) ++ num_pmcs++; ++ ++ if (type & PFM_REG_WC) ++ num_wc++; ++ ++ if (type & PFM_REG_V) { ++ PFM_INFO("PFM_REG_V is not supported on " ++ "PMCs (PMC%d)", i); ++ return -EINVAL; ++ } ++ if (type & PFM_REG_RO) { ++ PFM_INFO("PFM_REG_RO meaningless on " ++ "PMCs (PMC%u)", i); ++ return -EINVAL; ++ } ++ } ++ ++ if (num_wc && cfg->pmc_write_check == NULL) { ++ PFM_INFO("some PMCs have write-checker but no callback provided\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * check virtual PMD registers ++ */ ++ num_wc = 0; ++ for (i = 0; i < cfg->num_pmd_entries; i++) { ++ ++ type = cfg->pmd_desc[i].type; ++ ++ if (type & PFM_REG_I) ++ num_pmds++; ++ ++ if (type & PFM_REG_V) { ++ nspec++; ++ if (type & PFM_REG_RO) ++ nspec_ro++; ++ } ++ ++ if (type & PFM_REG_WC) ++ num_wc++; ++ } ++ ++ if (num_wc && cfg->pmd_write_check == NULL) { ++ PFM_INFO("PMD have write-checker but no callback provided\n"); ++ return -EINVAL; ++ } ++ ++ if (nspec && cfg->pmd_sread == NULL) { ++ PFM_INFO("PMU config is missing pmd_sread()"); ++ return -EINVAL; ++ } ++ ++ nspec = nspec - nspec_ro; ++ if (nspec && cfg->pmd_swrite == NULL) { ++ PFM_INFO("PMU config is missing pmd_swrite()"); ++ return -EINVAL; ++ } ++ ++ if (num_pmcs >= PFM_MAX_PMCS) { ++ PFM_INFO("%s PMCS registers exceed name space [0-%u]", ++ cfg->pmu_name, ++ PFM_MAX_PMCS); ++ return -EINVAL; ++ } ++ if (num_pmds >= PFM_MAX_PMDS) { ++ PFM_INFO("%s PMDS registers exceed name space [0-%u]", ++ cfg->pmu_name, ++ PFM_MAX_PMDS); ++ return -EINVAL; ++ } ++ spin_lock(&pfm_pmu_conf_lock); ++ ++ if (pfm_pmu_conf) ++ goto unlock; ++ ++ if (!cfg->version) ++ cfg->version = "0.0"; ++ ++ pfm_pmu_conf = cfg; ++ pfm_pmu_conf->ovfl_mask = (1ULL << cfg->counter_width) - 1; ++ ++ ret = pfm_arch_pmu_config_init(cfg); ++ if (ret) ++ goto unlock; ++ ++ ret = pfm_sysfs_add_pmu(pfm_pmu_conf); ++ if (ret) ++ pfm_pmu_conf = NULL; ++ ++unlock: ++ spin_unlock(&pfm_pmu_conf_lock); ++ ++ if (ret) { ++ PFM_INFO("register %s PMU error %d", cfg->pmu_name, ret); ++ } else { ++ PFM_INFO("%s PMU installed", cfg->pmu_name); ++ /* ++ * (re)initialize PMU on each PMU now that we have a description ++ */ ++ on_each_cpu(__pfm_init_percpu, cfg, 0); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(pfm_pmu_register); ++ ++/* ++ * remove PMU description. Caller must pass address of current ++ * configuration. This is mostly for sanity checking as only ++ * one config can exist at any time. ++ * ++ * We are using the module refcount mechanism to protect against ++ * removal while the configuration is being used. As long as there is ++ * one context, a PMU configuration cannot be removed. The protection is ++ * managed in module logic. ++ */ ++void pfm_pmu_unregister(struct pfm_pmu_config *cfg) ++{ ++ if (!(cfg || pfm_pmu_conf)) ++ return; ++ ++ spin_lock(&pfm_pmu_conf_lock); ++ ++ BUG_ON(module_refcount(pfm_pmu_conf->owner)); ++ ++ if (cfg->owner == pfm_pmu_conf->owner) { ++ pfm_sysfs_remove_pmu(pfm_pmu_conf); ++ pfm_pmu_conf = NULL; ++ } ++ ++ spin_unlock(&pfm_pmu_conf_lock); ++} ++EXPORT_SYMBOL(pfm_pmu_unregister); ++ ++static int pfm_pmu_request_module(void) ++{ ++ char *mod_name; ++ int ret; ++ ++ mod_name = pfm_arch_get_pmu_module_name(); ++ if (mod_name == NULL) ++ return -ENOSYS; ++ ++ ret = request_module(mod_name); ++ ++ PFM_DBG("mod=%s ret=%d\n", mod_name, ret); ++ return ret; ++} ++ ++/* ++ * autoload: ++ * 0 : do not try to autoload the PMU description module ++ * not 0 : try to autoload the PMU description module ++ */ ++int pfm_pmu_conf_get(int autoload) ++{ ++ int ret; ++ ++ spin_lock(&pfm_pmu_conf_lock); ++ ++ if (request_mod_in_progress) { ++ ret = -ENOSYS; ++ goto skip; ++ } ++ ++ if (autoload && pfm_pmu_conf == NULL) { ++ ++ request_mod_in_progress = 1; ++ ++ spin_unlock(&pfm_pmu_conf_lock); ++ ++ pfm_pmu_request_module(); ++ ++ spin_lock(&pfm_pmu_conf_lock); ++ ++ request_mod_in_progress = 0; ++ ++ /* ++ * request_module() may succeed but the module ++ * may not have registered properly so we need ++ * to check ++ */ ++ } ++ ++ ret = pfm_pmu_conf == NULL ? -ENOSYS : 0; ++ if (!ret && pmu_is_module(pfm_pmu_conf) ++ && !try_module_get(pfm_pmu_conf->owner)) ++ ret = -ENOSYS; ++ ++skip: ++ spin_unlock(&pfm_pmu_conf_lock); ++ ++ return ret; ++} ++ ++void pfm_pmu_conf_put(void) ++{ ++ if (pfm_pmu_conf == NULL || !pmu_is_module(pfm_pmu_conf)) ++ return; ++ ++ spin_lock(&pfm_pmu_conf_lock); ++ module_put(pfm_pmu_conf->owner); ++ spin_unlock(&pfm_pmu_conf_lock); ++} ++ ++ ++/* ++ * acquire PMU resource from lower-level PMU register allocator ++ * (currently perfctr-watchdog.c) ++ * ++ * acquisition is done when the first context is created (and not ++ * when it is loaded). We grab all that is defined in the description ++ * module and then we make adjustments at the arch-specific level. ++ * ++ * The PMU resource is released when the last perfmon context is ++ * destroyed. ++ * ++ * interrupts are not masked ++ */ ++int pfm_pmu_acquire(struct pfm_context *ctx) ++{ ++ u64 unavail_pmcs[PFM_PMC_BV]; ++ u64 unavail_pmds[PFM_PMD_BV]; ++ int ret = 0; ++ ++ spin_lock(&pfm_pmu_acq_lock); ++ ++ PFM_DBG("pmu_acquired=%u", pfm_pmu_acquired); ++ ++ pfm_pmu_acquired++; ++ ++ /* ++ * we need to initialize regdesc each time we re-acquire ++ * the PMU for the first time as there may have been changes ++ * in the list of available registers, e.g., NMI may have ++ * been disabled. Checking on PMU module insert is not ++ * enough ++ */ ++ if (pfm_pmu_acquired == 1) { ++ memset(unavail_pmcs, 0, sizeof(unavail_pmcs)); ++ memset(unavail_pmds, 0, sizeof(unavail_pmds)); ++ ++ ret = pfm_arch_pmu_acquire(unavail_pmcs, unavail_pmds); ++ if (ret) { ++ pfm_pmu_acquired--; ++ } else { ++ pfm_pmu_regdesc_init_all(unavail_pmcs, unavail_pmds); ++ ++ /* available PMU ressources */ ++ PFM_DBG("PMU acquired: %u PMCs, %u PMDs, %u counters", ++ pfm_pmu_conf->regs_all.num_pmcs, ++ pfm_pmu_conf->regs_all.num_pmds, ++ pfm_pmu_conf->regs_all.num_counters); ++ } ++ } ++ spin_unlock(&pfm_pmu_acq_lock); ++ ++ /* ++ * copy the regdesc that corresponds to the context ++ * we copy and not just point because it helps with ++ * memory locality. the regdesc structure is accessed ++ * very frequently in performance critical code such ++ * as context switch and interrupt handling. By using ++ * a local copy, we increase memory footprint, but ++ * increase chance to have local memory access, ++ * especially for system-wide contexts. ++ */ ++ if (ctx->flags.system) ++ ctx->regs = pfm_pmu_conf->regs_sys; ++ else ++ ctx->regs = pfm_pmu_conf->regs_thr; ++ ++ return ret; ++} ++ ++/* ++ * release the PMU resource ++ * ++ * actual release happens when last context is destroyed ++ * ++ * interrupts are not masked ++ */ ++void pfm_pmu_release(void) ++{ ++ BUG_ON(irqs_disabled()); ++ ++ /* ++ * we need to use a spinlock because release takes some time ++ * and we may have a race with pfm_pmu_acquire() ++ */ ++ spin_lock(&pfm_pmu_acq_lock); ++ ++ PFM_DBG("pmu_acquired=%d", pfm_pmu_acquired); ++ ++ /* ++ * we decouple test and decrement because if we had errors ++ * in pfm_pmu_acquire(), we still come here on pfm_context_free() ++ * but with pfm_pmu_acquire=0 ++ */ ++ if (pfm_pmu_acquired > 0 && --pfm_pmu_acquired == 0) { ++ pfm_arch_pmu_release(); ++ PFM_DBG("PMU released"); ++ } ++ spin_unlock(&pfm_pmu_acq_lock); ++} +--- /dev/null ++++ b/perfmon/perfmon_priv.h +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++ ++#ifndef __PERFMON_PRIV_H__ ++#define __PERFMON_PRIV_H__ ++/* ++ * This file contains all the definitions of data structures, variables, macros ++ * that are to private to the generic code, i.e., not shared with any code that ++ * lives under arch/ or include/asm-XX ++ * ++ * For shared definitions, use include/linux/perfmon_kern.h ++ */ ++ ++#ifdef CONFIG_PERFMON ++ ++/* ++ * type of PMD reset for pfm_reset_pmds() or pfm_switch_sets*() ++ */ ++#define PFM_PMD_RESET_SHORT 1 /* use short reset value */ ++#define PFM_PMD_RESET_LONG 2 /* use long reset value */ ++ ++/* ++ * context lazy save/restore activation count ++ */ ++#define PFM_INVALID_ACTIVATION ((u64)~0) ++ ++DECLARE_PER_CPU(u64, pmu_activation_number); ++DECLARE_PER_CPU(struct hrtimer, pfm_hrtimer); ++ ++static inline void pfm_set_pmu_owner(struct task_struct *task, ++ struct pfm_context *ctx) ++{ ++ __get_cpu_var(pmu_owner) = task; ++ __get_cpu_var(pmu_ctx) = ctx; ++} ++ ++static inline int pfm_msgq_is_empty(struct pfm_context *ctx) ++{ ++ return ctx->msgq_head == ctx->msgq_tail; ++} ++ ++void pfm_get_next_msg(struct pfm_context *ctx, union pfarg_msg *m); ++int pfm_end_notify(struct pfm_context *ctx); ++int pfm_ovfl_notify(struct pfm_context *ctx, struct pfm_event_set *set, ++ unsigned long ip); ++ ++int pfm_alloc_fd(struct file **cfile); ++ ++int __pfm_delete_evtsets(struct pfm_context *ctx, void *arg, int count); ++int __pfm_getinfo_evtsets(struct pfm_context *ctx, struct pfarg_setinfo *req, ++ int count); ++int __pfm_create_evtsets(struct pfm_context *ctx, struct pfarg_setdesc *req, ++ int count); ++ ++ ++int pfm_init_ctx(void); ++ ++int pfm_pmu_acquire(struct pfm_context *ctx); ++void pfm_pmu_release(void); ++ ++int pfm_session_acquire(int is_system, u32 cpu); ++void pfm_session_release(int is_system, u32 cpu); ++ ++int pfm_smpl_buf_space_acquire(struct pfm_context *ctx, size_t size); ++int pfm_smpl_buf_load_context(struct pfm_context *ctx); ++void pfm_smpl_buf_unload_context(struct pfm_context *ctx); ++ ++int pfm_init_sysfs(void); ++ ++#ifdef CONFIG_PERFMON_DEBUG_FS ++int pfm_init_debugfs(void); ++int pfm_debugfs_add_cpu(int mycpu); ++void pfm_debugfs_del_cpu(int mycpu); ++#else ++static inline int pfm_init_debugfs(void) ++{ ++ return 0; ++} ++static inline int pfm_debugfs_add_cpu(int mycpu) ++{ ++ return 0; ++} ++ ++static inline void pfm_debugfs_del_cpu(int mycpu) ++{} ++#endif ++ ++ ++void pfm_reset_pmds(struct pfm_context *ctx, struct pfm_event_set *set, ++ int num_pmds, ++ int reset_mode); ++ ++struct pfm_event_set *pfm_prepare_sets(struct pfm_context *ctx, u16 load_set); ++int pfm_init_sets(void); ++ ++ssize_t pfm_sysfs_res_show(char *buf, size_t sz, int what); ++ ++void pfm_free_sets(struct pfm_context *ctx); ++int pfm_create_initial_set(struct pfm_context *ctx); ++void pfm_switch_sets_from_intr(struct pfm_context *ctx); ++void pfm_restart_timer(struct pfm_context *ctx, struct pfm_event_set *set); ++enum hrtimer_restart pfm_handle_switch_timeout(struct hrtimer *t); ++ ++enum hrtimer_restart pfm_switch_sets(struct pfm_context *ctx, ++ struct pfm_event_set *new_set, ++ int reset_mode, ++ int no_restart); ++ ++/** ++ * pfm_save_prev_ctx - check if previous context exists and save state ++ * ++ * called from pfm_load_ctx_thread() and __pfm_ctxsin_thread() to ++ * check if previous context exists. If so saved its PMU state. This is used ++ * only for UP kernels. ++ * ++ * PMU ownership is not cleared because the function is always called while ++ * trying to install a new owner. ++ */ ++static inline void pfm_check_save_prev_ctx(void) ++{ ++#ifdef CONFIG_SMP ++ struct pfm_event_set *set; ++ struct pfm_context *ctxp; ++ ++ ctxp = __get_cpu_var(pmu_ctx); ++ if (!ctxp) ++ return; ++ /* ++ * in UP per-thread, due to lazy save ++ * there could be a context from another ++ * task. We need to push it first before ++ * installing our new state ++ */ ++ set = ctxp->active_set; ++ pfm_save_pmds(ctxp, set); ++ /* ++ * do not clear ownership because we rewrite ++ * right away ++ */ ++#endif ++} ++ ++ ++int pfm_init_fs(void); ++ ++int pfm_init_hotplug(void); ++ ++void pfm_mask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set); ++void pfm_resume_after_ovfl(struct pfm_context *ctx); ++int pfm_setup_smpl_fmt(struct pfm_context *ctx, u32 ctx_flags, void *fmt_arg, ++ struct file *filp); ++ ++static inline void pfm_post_work(struct task_struct *task, ++ struct pfm_context *ctx, int type) ++{ ++ ctx->flags.work_type = type; ++ set_tsk_thread_flag(task, TIF_PERFMON_WORK); ++ pfm_arch_arm_handle_work(task); ++} ++ ++#define PFM_PMC_STK_ARG PFM_ARCH_PMC_STK_ARG ++#define PFM_PMD_STK_ARG PFM_ARCH_PMD_STK_ARG ++ ++#endif /* CONFIG_PERFMON */ ++ ++#endif /* __PERFMON_PRIV_H__ */ +--- /dev/null ++++ b/perfmon/perfmon_res.c +@@ -0,0 +1,450 @@ ++/* ++ * perfmon_res.c: perfmon2 resource allocations ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++/* ++ * global information about all sessions ++ * mostly used to synchronize between system wide and per-process ++ */ ++struct pfm_resources { ++ size_t smpl_buf_mem_cur;/* current smpl buf mem usage */ ++ cpumask_t sys_cpumask; /* bitmask of used cpus */ ++ u32 thread_sessions; /* #num loaded per-thread sessions */ ++}; ++ ++static struct pfm_resources pfm_res; ++ ++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pfm_res_lock); ++ ++/** ++ * pfm_smpl_buf_space_acquire - check memory resource usage for sampling buffer ++ * @ctx: context of interest ++ * @size: size fo requested buffer ++ * ++ * sampling buffer allocated by perfmon must be ++ * checked against max locked memory usage thresholds ++ * for security reasons. ++ * ++ * The first level check is against the system wide limit ++ * as indicated by the system administrator in /sys/kernel/perfmon ++ * ++ * The second level check is on a per-process basis using ++ * RLIMIT_MEMLOCK limit. ++ * ++ * Operating on the current task only. ++ */ ++int pfm_smpl_buf_space_acquire(struct pfm_context *ctx, size_t size) ++{ ++ struct mm_struct *mm; ++ unsigned long locked; ++ unsigned long buf_mem, buf_mem_max; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ /* ++ * check against global buffer limit ++ */ ++ buf_mem_max = pfm_controls.smpl_buffer_mem_max; ++ buf_mem = pfm_res.smpl_buf_mem_cur + size; ++ ++ if (buf_mem <= buf_mem_max) { ++ pfm_res.smpl_buf_mem_cur = buf_mem; ++ ++ PFM_DBG("buf_mem_max=%lu current_buf_mem=%lu", ++ buf_mem_max, ++ buf_mem); ++ } ++ ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++ ++ if (buf_mem > buf_mem_max) { ++ PFM_DBG("smpl buffer memory threshold reached"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * check against per-process RLIMIT_MEMLOCK ++ */ ++ mm = get_task_mm(current); ++ ++ down_write(&mm->mmap_sem); ++ ++ locked = mm->locked_vm << PAGE_SHIFT; ++ locked += size; ++ ++ if (locked > current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur) { ++ ++ PFM_DBG("RLIMIT_MEMLOCK reached ask_locked=%lu rlim_cur=%lu", ++ locked, ++ current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur); ++ ++ up_write(&mm->mmap_sem); ++ mmput(mm); ++ goto unres; ++ } ++ ++ mm->locked_vm = locked >> PAGE_SHIFT; ++ ++ up_write(&mm->mmap_sem); ++ ++ mmput(mm); ++ ++ return 0; ++ ++unres: ++ /* ++ * remove global buffer memory allocation ++ */ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ pfm_res.smpl_buf_mem_cur -= size; ++ ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++ ++ return -ENOMEM; ++} ++/** ++ * pfm_smpl_buf_space_release - release resource usage for sampling buffer ++ * @ctx: perfmon context of interest ++ * ++ * There exist multiple paths leading to this function. We need to ++ * be very careful withlokcing on the mmap_sem as it may already be ++ * held by the time we come here. ++ * The following paths exist: ++ * ++ * exit path: ++ * sys_exit_group ++ * do_group_exit ++ * do_exit ++ * exit_mm ++ * mmput ++ * exit_mmap ++ * remove_vma ++ * fput ++ * __fput ++ * pfm_close ++ * __pfm_close ++ * pfm_context_free ++ * pfm_release_buf_space ++ * munmap path: ++ * sys_munmap ++ * do_munmap ++ * remove_vma ++ * fput ++ * __fput ++ * pfm_close ++ * __pfm_close ++ * pfm_context_free ++ * pfm_release_buf_space ++ * ++ * close path: ++ * sys_close ++ * filp_close ++ * fput ++ * __fput ++ * pfm_close ++ * __pfm_close ++ * pfm_context_free ++ * pfm_release_buf_space ++ * ++ * The issue is that on the munmap() path, the mmap_sem is already held ++ * in write-mode by the time we come here. To avoid the deadlock, we need ++ * to know where we are coming from and skip down_write(). If is fairly ++ * difficult to know this because of the lack of good hooks and ++ * the fact that, there may not have been any mmap() of the sampling buffer ++ * (i.e. create_context() followed by close() or exit()). ++ * ++ * We use a set flag ctx->flags.mmap_nlock which is toggled in the vm_ops ++ * callback in remove_vma() which is called systematically for the call, so ++ * on all but the pure close() path. The exit path does not already hold ++ * the lock but this is exit so there is no task->mm by the time we come here. ++ * ++ * The mmap_nlock is set only when unmapping and this is the LAST reference ++ * to the file (i.e., close() followed by munmap()). ++ */ ++void pfm_smpl_buf_space_release(struct pfm_context *ctx, size_t size) ++{ ++ unsigned long flags; ++ struct mm_struct *mm; ++ ++ mm = get_task_mm(current); ++ if (mm) { ++ if (ctx->flags.mmap_nlock == 0) { ++ PFM_DBG("doing down_write"); ++ down_write(&mm->mmap_sem); ++ } ++ ++ mm->locked_vm -= size >> PAGE_SHIFT; ++ ++ PFM_DBG("size=%zu locked_vm=%lu", size, mm->locked_vm); ++ ++ if (ctx->flags.mmap_nlock == 0) ++ up_write(&mm->mmap_sem); ++ ++ mmput(mm); ++ } ++ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ pfm_res.smpl_buf_mem_cur -= size; ++ ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++} ++ ++/** ++ * pfm_session_acquire - reserve a per-thread or per-cpu session ++ * @is_system: true if per-cpu session ++ * @cpu: cpu number for per-cpu session ++ * ++ * return: ++ * 0 : success ++ * -EBUSY: if conflicting session exist ++ */ ++int pfm_session_acquire(int is_system, u32 cpu) ++{ ++ unsigned long flags; ++ u32 nsys_cpus; ++ int ret = 0; ++ ++ /* ++ * validy checks on cpu_mask have been done upstream ++ */ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ nsys_cpus = cpus_weight(pfm_res.sys_cpumask); ++ ++ PFM_DBG("in sys=%u task=%u is_sys=%d cpu=%u", ++ nsys_cpus, ++ pfm_res.thread_sessions, ++ is_system, ++ cpu); ++ ++ if (is_system) { ++ /* ++ * cannot mix system wide and per-task sessions ++ */ ++ if (pfm_res.thread_sessions > 0) { ++ PFM_DBG("%u conflicting thread_sessions", ++ pfm_res.thread_sessions); ++ ret = -EBUSY; ++ goto abort; ++ } ++ ++ if (cpu_isset(cpu, pfm_res.sys_cpumask)) { ++ PFM_DBG("conflicting session on CPU%u", cpu); ++ ret = -EBUSY; ++ goto abort; ++ } ++ ++ PFM_DBG("reserved session on CPU%u", cpu); ++ ++ cpu_set(cpu, pfm_res.sys_cpumask); ++ nsys_cpus++; ++ } else { ++ if (nsys_cpus) { ++ ret = -EBUSY; ++ goto abort; ++ } ++ pfm_res.thread_sessions++; ++ } ++ ++ PFM_DBG("out sys=%u task=%u is_sys=%d cpu=%u", ++ nsys_cpus, ++ pfm_res.thread_sessions, ++ is_system, ++ cpu); ++ ++abort: ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++ ++ return ret; ++} ++ ++/** ++ * pfm_session_release - release a per-cpu or per-thread session ++ * @is_system: true if per-cpu session ++ * @cpu: cpu number for per-cpu session ++ * ++ * called from __pfm_unload_context() ++ */ ++void pfm_session_release(int is_system, u32 cpu) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ PFM_DBG("in sys_sessions=%u thread_sessions=%u syswide=%d cpu=%u", ++ cpus_weight(pfm_res.sys_cpumask), ++ pfm_res.thread_sessions, ++ is_system, cpu); ++ ++ if (is_system) ++ cpu_clear(cpu, pfm_res.sys_cpumask); ++ else ++ pfm_res.thread_sessions--; ++ ++ PFM_DBG("out sys_sessions=%u thread_sessions=%u syswide=%d cpu=%u", ++ cpus_weight(pfm_res.sys_cpumask), ++ pfm_res.thread_sessions, ++ is_system, cpu); ++ ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++} ++ ++/** ++ * pfm_session_allcpus_acquire - acquire per-cpu sessions on all available cpus ++ * ++ * currently used by Oprofile on X86 ++ */ ++int pfm_session_allcpus_acquire(void) ++{ ++ unsigned long flags; ++ u32 nsys_cpus, cpu; ++ int ret = -EBUSY; ++ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ nsys_cpus = cpus_weight(pfm_res.sys_cpumask); ++ ++ PFM_DBG("in sys=%u task=%u", ++ nsys_cpus, ++ pfm_res.thread_sessions); ++ ++ if (nsys_cpus) { ++ PFM_DBG("already some system-wide sessions"); ++ goto abort; ++ } ++ ++ /* ++ * cannot mix system wide and per-task sessions ++ */ ++ if (pfm_res.thread_sessions) { ++ PFM_DBG("%u conflicting thread_sessions", ++ pfm_res.thread_sessions); ++ goto abort; ++ } ++ ++ for_each_online_cpu(cpu) { ++ cpu_set(cpu, pfm_res.sys_cpumask); ++ nsys_cpus++; ++ } ++ ++ PFM_DBG("out sys=%u task=%u", ++ nsys_cpus, ++ pfm_res.thread_sessions); ++ ++ ret = 0; ++abort: ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++ ++ return ret; ++} ++EXPORT_SYMBOL(pfm_session_allcpus_acquire); ++ ++/** ++ * pfm_session_allcpus_release - relase per-cpu sessions on all cpus ++ * ++ * currently used by Oprofile code ++ */ ++void pfm_session_allcpus_release(void) ++{ ++ unsigned long flags; ++ u32 nsys_cpus, cpu; ++ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ nsys_cpus = cpus_weight(pfm_res.sys_cpumask); ++ ++ PFM_DBG("in sys=%u task=%u", ++ nsys_cpus, ++ pfm_res.thread_sessions); ++ ++ /* ++ * XXX: could use __cpus_clear() with nbits ++ */ ++ for_each_online_cpu(cpu) { ++ cpu_clear(cpu, pfm_res.sys_cpumask); ++ nsys_cpus--; ++ } ++ ++ PFM_DBG("out sys=%u task=%u", ++ nsys_cpus, ++ pfm_res.thread_sessions); ++ ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++} ++EXPORT_SYMBOL(pfm_session_allcpus_release); ++ ++/** ++ * pfm_sysfs_res_show - return currnt resourcde usage for sysfs ++ * @buf: buffer to hold string in return ++ * @sz: size of buf ++ * @what: what to produce ++ * what=0 : thread_sessions ++ * what=1 : cpus_weight(sys_cpumask) ++ * what=2 : smpl_buf_mem_cur ++ * what=3 : pmu model name ++ * ++ * called from perfmon_sysfs.c ++ * return number of bytes written into buf (up to sz) ++ */ ++ssize_t pfm_sysfs_res_show(char *buf, size_t sz, int what) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pfm_res_lock, flags); ++ ++ switch (what) { ++ case 0: snprintf(buf, sz, "%u\n", pfm_res.thread_sessions); ++ break; ++ case 1: snprintf(buf, sz, "%d\n", cpus_weight(pfm_res.sys_cpumask)); ++ break; ++ case 2: snprintf(buf, sz, "%zu\n", pfm_res.smpl_buf_mem_cur); ++ break; ++ case 3: ++ snprintf(buf, sz, "%s\n", ++ pfm_pmu_conf ? pfm_pmu_conf->pmu_name ++ : "unknown\n"); ++ } ++ spin_unlock_irqrestore(&pfm_res_lock, flags); ++ return strlen(buf); ++} +--- /dev/null ++++ b/perfmon/perfmon_rw.c +@@ -0,0 +1,733 @@ ++/* ++ * perfmon.c: perfmon2 PMC/PMD read/write system calls ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net/ ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++#define PFM_REGFL_PMC_ALL (PFM_REGFL_NO_EMUL64) ++#define PFM_REGFL_PMD_ALL (PFM_REGFL_RANDOM|PFM_REGFL_OVFL_NOTIFY) ++ ++/** ++ * update_used_reg -- updated used_pmcs for a single PMD ++ * @set: set to update ++ * @cnum: new PMD to add ++ * ++ * This function adds the pmds and pmcs depending on PMD cnum ++ */ ++static inline void update_used_reg(struct pfm_context *ctx, ++ struct pfm_event_set *set, u16 cnum) ++{ ++ bitmap_or(cast_ulp(set->used_pmcs), ++ cast_ulp(set->used_pmcs), ++ cast_ulp(pfm_pmu_conf->pmd_desc[cnum].dep_pmcs), ++ ctx->regs.max_pmc); ++} ++ ++/** ++ * update_used -- update used_pmcs bitmask ++ * @set: event set to update ++ * @bv: bitmask to inspect for new PMD registers ++ * ++ * This function updates the used_pmcs bitmask for ++ * the set using bv, a bitmask of pmds. For each pmd in bv, ++ * its depending pmcs are added to used_pmcs. ++ */ ++static void update_used_pmcs(struct pfm_context *ctx, ++ struct pfm_event_set *set, unsigned long *bv) ++{ ++ u16 max_pmd; ++ int n, p, q; ++ ++ max_pmd = ctx->regs.max_pmd; ++ ++ n = bitmap_weight(bv, max_pmd); ++ for(p = 0; n; n--, p = q+1) { ++ q = find_next_bit(bv, max_pmd, p); ++ update_used_reg(ctx, set, q); ++ } ++} ++ ++/** ++ * update_changes -- update nused_pmcs, nused_pmds, write newly touched pmcs ++ * @ctx: context to use ++ * @set: event set to use ++ * @old_used_pmcs: former used_pmc bitmask ++ * @can_access: non-zero if PMU is accessible, i.e., can be written to ++ * ++ * This function updates nused_pmcs and nused_pmds after the last modificiation ++ * to an event set. When new pmcs are used, then they must be initialized such ++ * that we do not pick up stale values from another session. ++ */ ++static inline int update_changes(struct pfm_context *ctx, struct pfm_event_set *set, ++ unsigned long *old_used_pmcs) ++{ ++ struct pfarg_pmc req; ++ u16 max_pmc, max_pmd; ++ int n, p, q, ret = 0; ++ ++ max_pmd = ctx->regs.max_pmd; ++ max_pmc = ctx->regs.max_pmc; ++ ++ /* ++ * update used counts ++ */ ++ set->nused_pmds = bitmap_weight(cast_ulp(set->used_pmds), max_pmd); ++ set->nused_pmcs = bitmap_weight(cast_ulp(set->used_pmcs), max_pmc); ++ ++ PFM_DBG("set%u u_pmds=0x%llx nu_pmds=%u u_pmcs=0x%llx nu_pmcs=%u", ++ set->id, ++ (unsigned long long)set->used_pmds[0], ++ set->nused_pmds, ++ (unsigned long long)set->used_pmcs[0], ++ set->nused_pmcs); ++ ++ memset(&req, 0, sizeof(req)); ++ ++ n = bitmap_weight(cast_ulp(set->used_pmcs), max_pmc); ++ for(p = 0; n; n--, p = q+1) { ++ q = find_next_bit(cast_ulp(set->used_pmcs), max_pmc, p); ++ ++ if (test_bit(q, cast_ulp(old_used_pmcs))) ++ continue; ++ ++ req.reg_num = q; ++ req.reg_value = set->pmcs[q]; ++ ++ ret = __pfm_write_pmcs(ctx, &req, 1); ++ if (ret) ++ break; ++ } ++ return ret; ++} ++ ++/** ++ * handle_smpl_bv - checks sampling bitmasks for new PMDs ++ * @ctx: context to use ++ * @set: set to use ++ * @bv: sampling bitmask ++ * ++ * scans the smpl bitmask looking for new PMDs (not yet used), if found ++ * invoke pfm_write_pmds() on them to get them initialized and marked used ++ */ ++static int handle_smpl_bv(struct pfm_context *ctx, struct pfm_event_set *set, ++ unsigned long *bv) ++{ ++ struct pfarg_pmd req; ++ int p, q, n, ret = 0; ++ u16 max_pmd; ++ ++ memset(&req, 0, sizeof(req)); ++ ++ max_pmd = ctx->regs.max_pmd; ++ ++ n = bitmap_weight(cast_ulp(bv), max_pmd); ++ ++ for(p = 0; n; n--, p = q+1) { ++ q = find_next_bit(cast_ulp(bv), max_pmd, p); ++ ++ if (test_bit(q, cast_ulp(set->used_pmds))) ++ continue; ++ ++ req.reg_num = q; ++ req.reg_value = 0; ++ ++ ret = __pfm_write_pmds(ctx, &req, 1, 0); ++ if (ret) ++ break; ++ } ++ return ret; ++} ++ ++/** ++ * is_invalid -- check if register index is within limits ++ * @cnum: register index ++ * @impl: bitmask of implemented registers ++ * @max: highest implemented registers + 1 ++ * ++ * return: ++ * 0 is register index is valid ++ * 1 if invalid ++ */ ++static inline int is_invalid(u16 cnum, unsigned long *impl, u16 max) ++{ ++ return cnum >= max || !test_bit(cnum, impl); ++} ++ ++/** ++ * __pfm_write_pmds - modified data registers ++ * @ctx: context to operate on ++ * @req: pfarg_pmd_t request from user ++ * @count: number of element in the pfarg_pmd_t vector ++ * @compat: used only on IA-64 to maintain backward compatibility with v2.0 ++ * ++ * The function succeeds whether the context is attached or not. ++ * When attached to another thread, that thread must be stopped. ++ * ++ * The context is locked and interrupts are disabled. ++ */ ++int __pfm_write_pmds(struct pfm_context *ctx, struct pfarg_pmd *req, int count, ++ int compat) ++{ ++ struct pfm_event_set *set, *active_set; ++ u64 old_used_pmcs[PFM_PMC_BV]; ++ unsigned long *smpl_pmds, *reset_pmds, *impl_pmds, *impl_rw_pmds; ++ u32 req_flags, flags; ++ u16 cnum, pmd_type, max_pmd; ++ u16 set_id; ++ int i, can_access_pmu; ++ int ret; ++ pfm_pmd_check_t wr_func; ++ ++ active_set = ctx->active_set; ++ max_pmd = ctx->regs.max_pmd; ++ impl_pmds = cast_ulp(ctx->regs.pmds); ++ impl_rw_pmds = cast_ulp(ctx->regs.rw_pmds); ++ wr_func = pfm_pmu_conf->pmd_write_check; ++ set = list_first_entry(&ctx->set_list, struct pfm_event_set, list); ++ ++ can_access_pmu = 0; ++ ++ /* ++ * we cannot access the actual PMD registers when monitoring is masked ++ */ ++ if (unlikely(ctx->state == PFM_CTX_LOADED)) ++ can_access_pmu = __get_cpu_var(pmu_owner) == ctx->task ++ || ctx->flags.system; ++ ++ bitmap_copy(cast_ulp(old_used_pmcs), ++ cast_ulp(set->used_pmcs), ++ ctx->regs.max_pmc); ++ ++ ret = -EINVAL; ++ for (i = 0; i < count; i++, req++) { ++ ++ cnum = req->reg_num; ++ set_id = req->reg_set; ++ req_flags = req->reg_flags; ++ smpl_pmds = cast_ulp(req->reg_smpl_pmds); ++ reset_pmds = cast_ulp(req->reg_reset_pmds); ++ flags = 0; ++ ++ /* ++ * cannot write to unexisting ++ * writes to read-only register are ignored ++ */ ++ if (unlikely(is_invalid(cnum, impl_pmds, max_pmd))) { ++ PFM_DBG("pmd%u is not available", cnum); ++ goto error; ++ } ++ ++ pmd_type = pfm_pmu_conf->pmd_desc[cnum].type; ++ ++ /* ++ * ensure only valid flags are set ++ */ ++ if (req_flags & ~(PFM_REGFL_PMD_ALL)) { ++ PFM_DBG("pmd%u: invalid flags=0x%x", ++ cnum, req_flags); ++ goto error; ++ } ++ ++ /* ++ * OVFL_NOTIFY is valid for all types of PMD. ++ * non counting PMD may trigger PMU interrupt ++ * and thus may trigger recording of a sample. ++ * This is true with IBS on AMD family 16. ++ */ ++ if (req_flags & PFM_REGFL_OVFL_NOTIFY) ++ flags |= PFM_REGFL_OVFL_NOTIFY; ++ ++ /* ++ * We allow randomization to non counting PMD ++ */ ++ if (req_flags & PFM_REGFL_RANDOM) ++ flags |= PFM_REGFL_RANDOM; ++ ++ /* ++ * verify validity of smpl_pmds ++ */ ++ if (unlikely(!bitmap_subset(smpl_pmds, impl_pmds, PFM_MAX_PMDS))) { ++ PFM_DBG("invalid smpl_pmds=0x%llx for pmd%u", ++ (unsigned long long)req->reg_smpl_pmds[0], ++ cnum); ++ goto error; ++ } ++ ++ /* ++ * verify validity of reset_pmds ++ * check against impl_rw_pmds because it is not ++ * possible to reset read-only PMDs ++ */ ++ if (unlikely(!bitmap_subset(reset_pmds, impl_rw_pmds, PFM_MAX_PMDS))) { ++ PFM_DBG("invalid reset_pmds=0x%llx for pmd%u", ++ (unsigned long long)req->reg_reset_pmds[0], ++ cnum); ++ goto error; ++ } ++ ++ /* ++ * locate event set ++ */ ++ if (set_id != set->id) { ++ /* update number of used register for previous set */ ++ if (i) { ++ ret = update_changes(ctx, set, cast_ulp(old_used_pmcs)); ++ if (ret) ++ goto error; ++ } ++ ++ set = pfm_find_set(ctx, set_id, 0); ++ if (set == NULL) { ++ PFM_DBG("event set%u does not exist", ++ set_id); ++ goto error; ++ } ++ bitmap_copy(cast_ulp(old_used_pmcs), ++ cast_ulp(set->used_pmcs), ++ ctx->regs.max_pmc); ++ } ++ ++ /* ++ * execute write checker, if any ++ */ ++ if (unlikely(wr_func && (pmd_type & PFM_REG_WC))) { ++ ret = (*wr_func)(ctx, set, req); ++ if (ret) ++ goto error; ++ ++ } ++ ++ ++ /* ++ * now commit changes to software state ++ */ ++ ++ if (unlikely(compat)) ++ goto skip_set; ++ ++ if (bitmap_weight(smpl_pmds, max_pmd)) { ++ ret = handle_smpl_bv(ctx, set, smpl_pmds); ++ if (ret) ++ goto error; ++ update_used_pmcs(ctx, set, cast_ulp(smpl_pmds)); ++ } ++ ++ bitmap_copy(cast_ulp(set->pmds[cnum].smpl_pmds), ++ smpl_pmds, ++ max_pmd); ++ ++ ++ if (bitmap_weight(reset_pmds, max_pmd)) { ++ ret = handle_smpl_bv(ctx, set, reset_pmds); ++ if (ret) ++ goto error; ++ update_used_pmcs(ctx, set, cast_ulp(reset_pmds)); ++ } ++ ++ bitmap_copy(cast_ulp(set->pmds[cnum].reset_pmds), ++ reset_pmds, ++ max_pmd); ++ ++ set->pmds[cnum].flags = flags; ++ ++ __set_bit(cnum, cast_ulp(set->used_pmds)); ++ update_used_reg(ctx, set, cnum); ++ ++ /* ++ * we reprogram the PMD hence, we clear any pending ++ * ovfl. Does affect ovfl switch on restart but new ++ * value has already been established here ++ */ ++ if (test_bit(cnum, cast_ulp(set->povfl_pmds))) { ++ set->npend_ovfls--; ++ __clear_bit(cnum, cast_ulp(set->povfl_pmds)); ++ } ++ __clear_bit(cnum, cast_ulp(set->ovfl_pmds)); ++ ++ /* ++ * update ovfl_notify ++ */ ++ if (flags & PFM_REGFL_OVFL_NOTIFY) ++ __set_bit(cnum, cast_ulp(set->ovfl_notify)); ++ else ++ __clear_bit(cnum, cast_ulp(set->ovfl_notify)); ++ ++ /* ++ * establish new switch count ++ */ ++ set->pmds[cnum].ovflsw_thres = req->reg_ovfl_switch_cnt; ++ set->pmds[cnum].ovflsw_ref_thres = req->reg_ovfl_switch_cnt; ++skip_set: ++ ++ /* ++ * set last value to new value for all types of PMD ++ */ ++ set->pmds[cnum].lval = req->reg_value; ++ set->pmds[cnum].value = req->reg_value; ++ ++ /* ++ * update reset values (not just for counters) ++ */ ++ set->pmds[cnum].long_reset = req->reg_long_reset; ++ set->pmds[cnum].short_reset = req->reg_short_reset; ++ ++ /* ++ * update randomization mask ++ */ ++ set->pmds[cnum].mask = req->reg_random_mask; ++ ++ set->pmds[cnum].eventid = req->reg_smpl_eventid; ++ ++ if (set == active_set) { ++ set->priv_flags |= PFM_SETFL_PRIV_MOD_PMDS; ++ if (can_access_pmu) ++ pfm_write_pmd(ctx, cnum, req->reg_value); ++ } ++ ++ ++ PFM_DBG("set%u pmd%u=0x%llx flags=0x%x a_pmu=%d " ++ "ctx_pmd=0x%llx s_reset=0x%llx " ++ "l_reset=0x%llx s_pmds=0x%llx " ++ "r_pmds=0x%llx o_pmds=0x%llx " ++ "o_thres=%llu compat=%d eventid=%llx", ++ set->id, ++ cnum, ++ (unsigned long long)req->reg_value, ++ set->pmds[cnum].flags, ++ can_access_pmu, ++ (unsigned long long)set->pmds[cnum].value, ++ (unsigned long long)set->pmds[cnum].short_reset, ++ (unsigned long long)set->pmds[cnum].long_reset, ++ (unsigned long long)set->pmds[cnum].smpl_pmds[0], ++ (unsigned long long)set->pmds[cnum].reset_pmds[0], ++ (unsigned long long)set->ovfl_pmds[0], ++ (unsigned long long)set->pmds[cnum].ovflsw_thres, ++ compat, ++ (unsigned long long)set->pmds[cnum].eventid); ++ } ++ ret = 0; ++ ++error: ++ update_changes(ctx, set, cast_ulp(old_used_pmcs)); ++ ++ /* ++ * make changes visible ++ */ ++ if (can_access_pmu) ++ pfm_arch_serialize(); ++ ++ return ret; ++} ++ ++/** ++ * __pfm_write_pmcs - modified config registers ++ * @ctx: context to operate on ++ * @req: pfarg_pmc_t request from user ++ * @count: number of element in the pfarg_pmc_t vector ++ * ++ * ++ * The function succeeds whether the context is * attached or not. ++ * When attached to another thread, that thread must be stopped. ++ * ++ * The context is locked and interrupts are disabled. ++ */ ++int __pfm_write_pmcs(struct pfm_context *ctx, struct pfarg_pmc *req, int count) ++{ ++ struct pfm_event_set *set, *active_set; ++ u64 value, dfl_val, rsvd_msk; ++ unsigned long *impl_pmcs; ++ int i, can_access_pmu; ++ int ret; ++ u16 set_id; ++ u16 cnum, pmc_type, max_pmc; ++ u32 flags, expert; ++ pfm_pmc_check_t wr_func; ++ ++ active_set = ctx->active_set; ++ ++ wr_func = pfm_pmu_conf->pmc_write_check; ++ max_pmc = ctx->regs.max_pmc; ++ impl_pmcs = cast_ulp(ctx->regs.pmcs); ++ set = list_first_entry(&ctx->set_list, struct pfm_event_set, list); ++ ++ expert = pfm_controls.flags & PFM_CTRL_FL_RW_EXPERT; ++ ++ can_access_pmu = 0; ++ ++ /* ++ * we cannot access the actual PMC registers when monitoring is masked ++ */ ++ if (unlikely(ctx->state == PFM_CTX_LOADED)) ++ can_access_pmu = __get_cpu_var(pmu_owner) == ctx->task ++ || ctx->flags.system; ++ ++ ret = -EINVAL; ++ ++ for (i = 0; i < count; i++, req++) { ++ ++ cnum = req->reg_num; ++ set_id = req->reg_set; ++ value = req->reg_value; ++ flags = req->reg_flags; ++ ++ /* ++ * no access to unavailable PMC register ++ */ ++ if (unlikely(is_invalid(cnum, impl_pmcs, max_pmc))) { ++ PFM_DBG("pmc%u is not available", cnum); ++ goto error; ++ } ++ ++ pmc_type = pfm_pmu_conf->pmc_desc[cnum].type; ++ dfl_val = pfm_pmu_conf->pmc_desc[cnum].dfl_val; ++ rsvd_msk = pfm_pmu_conf->pmc_desc[cnum].rsvd_msk; ++ ++ /* ++ * ensure only valid flags are set ++ */ ++ if (flags & ~PFM_REGFL_PMC_ALL) { ++ PFM_DBG("pmc%u: invalid flags=0x%x", cnum, flags); ++ goto error; ++ } ++ ++ /* ++ * locate event set ++ */ ++ if (set_id != set->id) { ++ set = pfm_find_set(ctx, set_id, 0); ++ if (set == NULL) { ++ PFM_DBG("event set%u does not exist", ++ set_id); ++ goto error; ++ } ++ } ++ ++ /* ++ * set reserved bits to default values ++ * (reserved bits must be 1 in rsvd_msk) ++ * ++ * bypass via /sys/kernel/perfmon/mode = 1 ++ */ ++ if (likely(!expert)) ++ value = (value & ~rsvd_msk) | (dfl_val & rsvd_msk); ++ ++ if (flags & PFM_REGFL_NO_EMUL64) { ++ if (!(pmc_type & PFM_REG_NO64)) { ++ PFM_DBG("pmc%u no support for " ++ "PFM_REGFL_NO_EMUL64", cnum); ++ goto error; ++ } ++ value &= ~pfm_pmu_conf->pmc_desc[cnum].no_emul64_msk; ++ } ++ ++ /* ++ * execute write checker, if any ++ */ ++ if (likely(wr_func && (pmc_type & PFM_REG_WC))) { ++ req->reg_value = value; ++ ret = (*wr_func)(ctx, set, req); ++ if (ret) ++ goto error; ++ value = req->reg_value; ++ } ++ ++ /* ++ * Now we commit the changes ++ */ ++ ++ /* ++ * mark PMC register as used ++ * We do not track associated PMC register based on ++ * the fact that they will likely need to be written ++ * in order to become useful at which point the statement ++ * below will catch that. ++ * ++ * The used_pmcs bitmask is only useful on architectures where ++ * the PMC needs to be modified for particular bits, especially ++ * on overflow or to stop/start. ++ */ ++ if (!test_bit(cnum, cast_ulp(set->used_pmcs))) { ++ __set_bit(cnum, cast_ulp(set->used_pmcs)); ++ set->nused_pmcs++; ++ } ++ ++ set->pmcs[cnum] = value; ++ ++ if (set == active_set) { ++ set->priv_flags |= PFM_SETFL_PRIV_MOD_PMCS; ++ if (can_access_pmu) ++ pfm_arch_write_pmc(ctx, cnum, value); ++ } ++ ++ PFM_DBG("set%u pmc%u=0x%llx a_pmu=%d " ++ "u_pmcs=0x%llx nu_pmcs=%u", ++ set->id, ++ cnum, ++ (unsigned long long)value, ++ can_access_pmu, ++ (unsigned long long)set->used_pmcs[0], ++ set->nused_pmcs); ++ } ++ ret = 0; ++error: ++ /* ++ * make sure the changes are visible ++ */ ++ if (can_access_pmu) ++ pfm_arch_serialize(); ++ ++ return ret; ++} ++ ++/** ++ * __pfm_read_pmds - read data registers ++ * @ctx: context to operate on ++ * @req: pfarg_pmd_t request from user ++ * @count: number of element in the pfarg_pmd_t vector ++ * ++ * ++ * The function succeeds whether the context is attached or not. ++ * When attached to another thread, that thread must be stopped. ++ * ++ * The context is locked and interrupts are disabled. ++ */ ++int __pfm_read_pmds(struct pfm_context *ctx, struct pfarg_pmd *req, int count) ++{ ++ u64 val = 0, lval, ovfl_mask, hw_val; ++ u64 sw_cnt; ++ unsigned long *impl_pmds; ++ struct pfm_event_set *set, *active_set; ++ int i, ret, can_access_pmu = 0; ++ u16 cnum, pmd_type, set_id, max_pmd; ++ ++ ovfl_mask = pfm_pmu_conf->ovfl_mask; ++ impl_pmds = cast_ulp(ctx->regs.pmds); ++ max_pmd = ctx->regs.max_pmd; ++ active_set = ctx->active_set; ++ set = list_first_entry(&ctx->set_list, struct pfm_event_set, list); ++ ++ if (likely(ctx->state == PFM_CTX_LOADED)) { ++ can_access_pmu = __get_cpu_var(pmu_owner) == ctx->task ++ || ctx->flags.system; ++ ++ if (can_access_pmu) ++ pfm_arch_serialize(); ++ } ++ ++ /* ++ * on both UP and SMP, we can only read the PMD from the hardware ++ * register when the task is the owner of the local PMU. ++ */ ++ ret = -EINVAL; ++ for (i = 0; i < count; i++, req++) { ++ ++ cnum = req->reg_num; ++ set_id = req->reg_set; ++ ++ if (unlikely(is_invalid(cnum, impl_pmds, max_pmd))) { ++ PFM_DBG("pmd%u is not implemented/unaccessible", cnum); ++ goto error; ++ } ++ ++ pmd_type = pfm_pmu_conf->pmd_desc[cnum].type; ++ ++ /* ++ * locate event set ++ */ ++ if (set_id != set->id) { ++ set = pfm_find_set(ctx, set_id, 0); ++ if (set == NULL) { ++ PFM_DBG("event set%u does not exist", ++ set_id); ++ goto error; ++ } ++ } ++ /* ++ * it is not possible to read a PMD which was not requested: ++ * - explicitly written via pfm_write_pmds() ++ * - provided as a reg_smpl_pmds[] to another PMD during ++ * pfm_write_pmds() ++ * ++ * This is motivated by security and for optimization purposes: ++ * - on context switch restore, we can restore only what ++ * we use (except when regs directly readable at user ++ * level, e.g., IA-64 self-monitoring, I386 RDPMC). ++ * - do not need to maintain PMC -> PMD dependencies ++ */ ++ if (unlikely(!test_bit(cnum, cast_ulp(set->used_pmds)))) { ++ PFM_DBG("pmd%u cannot read, because not used", cnum); ++ goto error; ++ } ++ ++ val = set->pmds[cnum].value; ++ lval = set->pmds[cnum].lval; ++ ++ /* ++ * extract remaining ovfl to switch ++ */ ++ sw_cnt = set->pmds[cnum].ovflsw_thres; ++ ++ /* ++ * If the task is not the current one, then we check if the ++ * PMU state is still in the local live register due to lazy ++ * ctxsw. If true, then we read directly from the registers. ++ */ ++ if (set == active_set && can_access_pmu) { ++ hw_val = pfm_read_pmd(ctx, cnum); ++ if (pmd_type & PFM_REG_C64) ++ val = (val & ~ovfl_mask) | (hw_val & ovfl_mask); ++ else ++ val = hw_val; ++ } ++ ++ PFM_DBG("set%u pmd%u=0x%llx sw_thr=%llu lval=0x%llx", ++ set->id, ++ cnum, ++ (unsigned long long)val, ++ (unsigned long long)sw_cnt, ++ (unsigned long long)lval); ++ ++ req->reg_value = val; ++ req->reg_last_reset_val = lval; ++ req->reg_ovfl_switch_cnt = sw_cnt; ++ } ++ ret = 0; ++error: ++ return ret; ++} +--- /dev/null ++++ b/perfmon/perfmon_sets.c +@@ -0,0 +1,873 @@ ++/* ++ * perfmon_sets.c: perfmon2 event sets and multiplexing functions ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include "perfmon_priv.h" ++ ++static struct kmem_cache *pfm_set_cachep; ++ ++/** ++ * pfm_reload_switch_thresholds - reload overflow-based switch thresholds per set ++ * @set: the set for which to reload thresholds ++ * ++ */ ++static void pfm_reload_switch_thresholds(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ u64 *used_pmds; ++ u16 i, max, first; ++ ++ used_pmds = set->used_pmds; ++ first = ctx->regs.first_intr_pmd; ++ max = ctx->regs.max_intr_pmd; ++ ++ for (i = first; i < max; i++) { ++ if (test_bit(i, cast_ulp(used_pmds))) { ++ set->pmds[i].ovflsw_thres = set->pmds[i].ovflsw_ref_thres; ++ ++ PFM_DBG("set%u pmd%u ovflsw_thres=%llu", ++ set->id, ++ i, ++ (unsigned long long)set->pmds[i].ovflsw_thres); ++ } ++ } ++} ++ ++/** ++ * pfm_prepare_sets - initialize sets on pfm_load_context ++ * @ctx : context to operate on ++ * @load_set: set to activate first ++ * ++ * connect all sets, reset internal fields ++ */ ++struct pfm_event_set *pfm_prepare_sets(struct pfm_context *ctx, u16 load_set) ++{ ++ struct pfm_event_set *set, *p; ++ u16 max; ++ ++ /* ++ * locate first set to activate ++ */ ++ set = pfm_find_set(ctx, load_set, 0); ++ if (!set) ++ return NULL; ++ ++ if (set->flags & PFM_SETFL_OVFL_SWITCH) ++ pfm_reload_switch_thresholds(ctx, set); ++ ++ max = ctx->regs.max_intr_pmd; ++ ++ list_for_each_entry(p, &ctx->set_list, list) { ++ /* ++ * cleanup bitvectors ++ */ ++ bitmap_zero(cast_ulp(p->ovfl_pmds), max); ++ bitmap_zero(cast_ulp(p->povfl_pmds), max); ++ ++ p->npend_ovfls = 0; ++ ++ /* ++ * we cannot just use plain clear because of arch-specific flags ++ */ ++ p->priv_flags &= ~(PFM_SETFL_PRIV_MOD_BOTH|PFM_SETFL_PRIV_SWITCH); ++ /* ++ * neither duration nor runs are reset because typically loading/unloading ++ * does not mean counts are reset. To reset, the set must be modified ++ */ ++ } ++ return set; ++} ++ ++/* ++ * called by hrtimer_interrupt() ++ * ++ * This is the only function where we come with ++ * cpu_base->lock held before ctx->lock ++ * ++ * interrupts are disabled ++ */ ++enum hrtimer_restart pfm_handle_switch_timeout(struct hrtimer *t) ++{ ++ struct pfm_event_set *set; ++ struct pfm_context *ctx; ++ unsigned long flags; ++ enum hrtimer_restart ret = HRTIMER_NORESTART; ++ ++ /* ++ * prevent against race with unload ++ */ ++ ctx = __get_cpu_var(pmu_ctx); ++ if (!ctx) ++ return HRTIMER_NORESTART; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ set = ctx->active_set; ++ ++ /* ++ * switching occurs only when context is attached ++ */ ++ if (ctx->state != PFM_CTX_LOADED) ++ goto done; ++ /* ++ * timer does not run while monitoring is inactive (not started) ++ */ ++ if (!pfm_arch_is_active(ctx)) ++ goto done; ++ ++ pfm_stats_inc(handle_timeout_count); ++ ++ ret = pfm_switch_sets(ctx, NULL, PFM_PMD_RESET_SHORT, 0); ++done: ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ return ret; ++} ++ ++/* ++ * ++ * always operating on the current task ++ * interrupts are masked ++ * ++ * input: ++ * - new_set: new set to switch to, if NULL follow normal chain ++ */ ++enum hrtimer_restart pfm_switch_sets(struct pfm_context *ctx, ++ struct pfm_event_set *new_set, ++ int reset_mode, ++ int no_restart) ++{ ++ struct pfm_event_set *set; ++ u64 now, end; ++ u32 new_flags; ++ int is_system, is_active, nn; ++ enum hrtimer_restart ret = HRTIMER_NORESTART; ++ ++ now = sched_clock(); ++ set = ctx->active_set; ++ is_active = pfm_arch_is_active(ctx); ++ ++ /* ++ * if no set is explicitly requested, ++ * use the set_switch_next field ++ */ ++ if (!new_set) { ++ /* ++ * we use round-robin unless the user specified ++ * a particular set to go to. ++ */ ++ new_set = list_first_entry(&set->list, struct pfm_event_set, list); ++ if (&new_set->list == &ctx->set_list) ++ new_set = list_first_entry(&ctx->set_list, struct pfm_event_set, list); ++ } ++ ++ PFM_DBG_ovfl("state=%d act=%d cur_set=%u cur_runs=%llu cur_npend=%d next_set=%u " ++ "next_runs=%llu new_npend=%d reset_mode=%d reset_pmds=%llx", ++ ctx->state, ++ is_active, ++ set->id, ++ (unsigned long long)set->runs, ++ set->npend_ovfls, ++ new_set->id, ++ (unsigned long long)new_set->runs, ++ new_set->npend_ovfls, ++ reset_mode, ++ (unsigned long long)new_set->reset_pmds[0]); ++ ++ is_system = ctx->flags.system; ++ new_flags = new_set->flags; ++ ++ /* ++ * nothing more to do ++ */ ++ if (new_set == set) ++ goto skip_same_set; ++ ++ if (is_active) { ++ pfm_arch_stop(current, ctx); ++ pfm_save_pmds(ctx, set); ++ /* ++ * compute elapsed ns for active set ++ */ ++ set->duration += now - set->duration_start; ++ } ++ ++ pfm_arch_restore_pmds(ctx, new_set); ++ /* ++ * if masked, we must restore the pmcs such that they ++ * do not capture anything. ++ */ ++ pfm_arch_restore_pmcs(ctx, new_set); ++ ++ if (new_set->npend_ovfls) { ++ pfm_arch_resend_irq(ctx); ++ pfm_stats_inc(ovfl_intr_replay_count); ++ } ++ ++ new_set->priv_flags &= ~PFM_SETFL_PRIV_MOD_BOTH; ++ ++skip_same_set: ++ new_set->runs++; ++ /* ++ * reset switch threshold ++ */ ++ if (new_flags & PFM_SETFL_OVFL_SWITCH) ++ pfm_reload_switch_thresholds(ctx, new_set); ++ ++ /* ++ * reset overflowed PMD registers in new set ++ */ ++ nn = bitmap_weight(cast_ulp(new_set->reset_pmds), ctx->regs.max_pmd); ++ if (nn) ++ pfm_reset_pmds(ctx, new_set, nn, reset_mode); ++ ++ ++ /* ++ * This is needed when coming from pfm_start() ++ * ++ * When switching to the same set, there is no ++ * need to restart ++ */ ++ if (no_restart) ++ goto skip_restart; ++ ++ if (is_active) { ++ /* ++ * do not need to restart when same set ++ */ ++ if (new_set != set) { ++ ctx->active_set = new_set; ++ new_set->duration_start = now; ++ pfm_arch_start(current, ctx); ++ } ++ /* ++ * install new timeout if necessary ++ */ ++ if (new_flags & PFM_SETFL_TIME_SWITCH) { ++ struct hrtimer *h; ++ h = &__get_cpu_var(pfm_hrtimer); ++ hrtimer_forward(h, h->base->get_time(), new_set->hrtimer_exp); ++ new_set->hrtimer_rem = new_set->hrtimer_exp; ++ ret = HRTIMER_RESTART; ++ } ++ } ++ ++skip_restart: ++ ctx->active_set = new_set; ++ ++ end = sched_clock(); ++ ++ pfm_stats_inc(set_switch_count); ++ pfm_stats_add(set_switch_ns, end - now); ++ ++ return ret; ++} ++ ++/* ++ * called from __pfm_overflow_handler() to switch event sets. ++ * monitoring is stopped, task is current, interrupts are masked. ++ * compared to pfm_switch_sets(), this version is simplified because ++ * it knows about the call path. There is no need to stop monitoring ++ * because it is already frozen by PMU handler. ++ */ ++void pfm_switch_sets_from_intr(struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set, *new_set; ++ u64 now, end; ++ u32 new_flags; ++ int is_system, n; ++ ++ now = sched_clock(); ++ set = ctx->active_set; ++ new_set = list_first_entry(&set->list, struct pfm_event_set, list); ++ if (&new_set->list == &ctx->set_list) ++ new_set = list_first_entry(&ctx->set_list, struct pfm_event_set, list); ++ ++ PFM_DBG_ovfl("state=%d cur_set=%u cur_runs=%llu cur_npend=%d next_set=%u " ++ "next_runs=%llu new_npend=%d new_r_pmds=%llx", ++ ctx->state, ++ set->id, ++ (unsigned long long)set->runs, ++ set->npend_ovfls, ++ new_set->id, ++ (unsigned long long)new_set->runs, ++ new_set->npend_ovfls, ++ (unsigned long long)new_set->reset_pmds[0]); ++ ++ is_system = ctx->flags.system; ++ new_flags = new_set->flags; ++ ++ /* ++ * nothing more to do ++ */ ++ if (new_set == set) ++ goto skip_same_set; ++ ++ /* ++ * switch on intr only when set has OVFL_SWITCH ++ */ ++ BUG_ON(set->flags & PFM_SETFL_TIME_SWITCH); ++ ++ /* ++ * when called from PMU intr handler, monitoring ++ * is already stopped ++ * ++ * save current PMD registers, we use a special ++ * form for performance reason. On some architectures, ++ * such as x86, the pmds are already saved when entering ++ * the PMU interrupt handler via pfm-arch_intr_freeze() ++ * so we don't need to save them again. On the contrary, ++ * on IA-64, they are not saved by freeze, thus we have to ++ * to it here. ++ */ ++ pfm_arch_save_pmds_from_intr(ctx, set); ++ ++ /* ++ * compute elapsed ns for active set ++ */ ++ set->duration += now - set->duration_start; ++ ++ pfm_arch_restore_pmds(ctx, new_set); ++ ++ /* ++ * must not be restored active as we are still executing in the ++ * PMU interrupt handler. activation is deferred to unfreeze PMU ++ */ ++ pfm_arch_restore_pmcs(ctx, new_set); ++ ++ /* ++ * check for pending interrupt on incoming set. ++ * interrupts are masked so handler call deferred ++ */ ++ if (new_set->npend_ovfls) { ++ pfm_arch_resend_irq(ctx); ++ pfm_stats_inc(ovfl_intr_replay_count); ++ } ++ /* ++ * no need to restore anything, that is already done ++ */ ++ new_set->priv_flags &= ~PFM_SETFL_PRIV_MOD_BOTH; ++ /* ++ * reset duration counter ++ */ ++ new_set->duration_start = now; ++ ++skip_same_set: ++ new_set->runs++; ++ ++ /* ++ * reset switch threshold ++ */ ++ if (new_flags & PFM_SETFL_OVFL_SWITCH) ++ pfm_reload_switch_thresholds(ctx, new_set); ++ ++ /* ++ * reset overflowed PMD registers ++ */ ++ n = bitmap_weight(cast_ulp(new_set->reset_pmds), ctx->regs.max_pmd); ++ if (n) ++ pfm_reset_pmds(ctx, new_set, n, PFM_PMD_RESET_SHORT); ++ ++ /* ++ * XXX: isactive? ++ * ++ * Came here following a interrupt which triggered a switch, i.e., ++ * previous set was using OVFL_SWITCH, thus we just need to arm ++ * check if the next set is using timeout, and if so arm the timer. ++ * ++ * Timeout is always at least one tick away. No risk of having to ++ * invoke the timeout handler right now. In any case, cb_mode is ++ * set to HRTIMER_CB_IRQSAFE_NO_SOFTIRQ such that hrtimer_start ++ * will not try to wakeup the softirqd which could cause a locking ++ * problem. ++ */ ++ if (new_flags & PFM_SETFL_TIME_SWITCH) { ++ hrtimer_start(&__get_cpu_var(pfm_hrtimer), set->hrtimer_exp, HRTIMER_MODE_REL); ++ PFM_DBG("armed new timeout for set%u", new_set->id); ++ } ++ ++ ctx->active_set = new_set; ++ ++ end = sched_clock(); ++ ++ pfm_stats_inc(set_switch_count); ++ pfm_stats_add(set_switch_ns, end - now); ++} ++ ++ ++static int pfm_setfl_sane(struct pfm_context *ctx, u32 flags) ++{ ++#define PFM_SETFL_BOTH_SWITCH (PFM_SETFL_OVFL_SWITCH|PFM_SETFL_TIME_SWITCH) ++ int ret; ++ ++ ret = pfm_arch_setfl_sane(ctx, flags); ++ if (ret) ++ return ret; ++ ++ if ((flags & PFM_SETFL_BOTH_SWITCH) == PFM_SETFL_BOTH_SWITCH) { ++ PFM_DBG("both switch ovfl and switch time are set"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++/* ++ * it is never possible to change the identification of an existing set ++ */ ++static int pfm_change_evtset(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ struct pfarg_setdesc *req) ++{ ++ struct timeval tv; ++ struct timespec ts; ++ ktime_t kt; ++ long d, res_ns; ++ s32 rem; ++ u32 flags; ++ int ret; ++ u16 set_id; ++ ++ BUG_ON(ctx->state == PFM_CTX_LOADED); ++ ++ set_id = req->set_id; ++ flags = req->set_flags; ++ ++ ret = pfm_setfl_sane(ctx, flags); ++ if (ret) { ++ PFM_DBG("invalid flags 0x%x set %u", flags, set_id); ++ return -EINVAL; ++ } ++ ++ /* ++ * compute timeout value ++ */ ++ if (flags & PFM_SETFL_TIME_SWITCH) { ++ /* ++ * timeout value of zero is illegal ++ */ ++ if (req->set_timeout == 0) { ++ PFM_DBG("invalid timeout 0"); ++ return -EINVAL; ++ } ++ ++ hrtimer_get_res(CLOCK_MONOTONIC, &ts); ++ res_ns = (long)ktime_to_ns(timespec_to_ktime(ts)); ++ ++ /* ++ * round-up to multiple of clock resolution ++ * timeout = ((req->set_timeout+res_ns-1)/res_ns)*res_ns; ++ * ++ * u64 division missing on 32-bit arch, so use div_s64_rem ++ */ ++ d = div_s64_rem(req->set_timeout, res_ns, &rem); ++ ++ PFM_DBG("set%u flags=0x%x req_timeout=%lluns " ++ "HZ=%u TICK_NSEC=%lu clock_res=%ldns rem=%dns", ++ set_id, ++ flags, ++ (unsigned long long)req->set_timeout, ++ HZ, TICK_NSEC, ++ res_ns, ++ rem); ++ ++ /* ++ * Only accept timeout, we can actually achieve. ++ * users can invoke clock_getres(CLOCK_MONOTONIC) ++ * to figure out resolution and adjust timeout ++ */ ++ if (rem) { ++ PFM_DBG("set%u invalid timeout=%llu", ++ set_id, ++ (unsigned long long)req->set_timeout); ++ return -EINVAL; ++ } ++ ++ tv = ns_to_timeval(req->set_timeout); ++ kt = timeval_to_ktime(tv); ++ set->hrtimer_exp = kt; ++ } else { ++ set->hrtimer_exp = ktime_set(0, 0); ++ } ++ ++ /* ++ * commit changes ++ */ ++ set->id = set_id; ++ set->flags = flags; ++ set->priv_flags = 0; ++ ++ /* ++ * activation and duration counters are reset as ++ * most likely major things will change in the set ++ */ ++ set->runs = 0; ++ set->duration = 0; ++ ++ return 0; ++} ++ ++/* ++ * this function does not modify the next field ++ */ ++static void pfm_initialize_set(struct pfm_context *ctx, ++ struct pfm_event_set *set) ++{ ++ u64 *impl_pmcs; ++ u16 i, max_pmc; ++ ++ max_pmc = ctx->regs.max_pmc; ++ impl_pmcs = ctx->regs.pmcs; ++ ++ /* ++ * install default values for all PMC registers ++ */ ++ for (i = 0; i < max_pmc; i++) { ++ if (test_bit(i, cast_ulp(impl_pmcs))) { ++ set->pmcs[i] = pfm_pmu_conf->pmc_desc[i].dfl_val; ++ PFM_DBG("set%u pmc%u=0x%llx", ++ set->id, ++ i, ++ (unsigned long long)set->pmcs[i]); ++ } ++ } ++ ++ /* ++ * PMD registers are set to 0 when the event set is allocated, ++ * hence we do not need to explicitly initialize them. ++ * ++ * For virtual PMD registers (i.e., those tied to a SW resource) ++ * their value becomes meaningful once the context is attached. ++ */ ++} ++ ++/* ++ * look for an event set using its identification. If the set does not ++ * exist: ++ * - if alloc == 0 then return error ++ * - if alloc == 1 then allocate set ++ * ++ * alloc is one ONLY when coming from pfm_create_evtsets() which can only ++ * be called when the context is detached, i.e. monitoring is stopped. ++ */ ++struct pfm_event_set *pfm_find_set(struct pfm_context *ctx, u16 set_id, int alloc) ++{ ++ struct pfm_event_set *set = NULL, *prev, *new_set; ++ ++ PFM_DBG("looking for set=%u", set_id); ++ ++ prev = NULL; ++ list_for_each_entry(set, &ctx->set_list, list) { ++ if (set->id == set_id) ++ return set; ++ if (set->id > set_id) ++ break; ++ prev = set; ++ } ++ ++ if (!alloc) ++ return NULL; ++ ++ /* ++ * we are holding the context spinlock and interrupts ++ * are unmasked. We must use GFP_ATOMIC as we cannot ++ * sleep while holding a spin lock. ++ */ ++ new_set = kmem_cache_zalloc(pfm_set_cachep, GFP_ATOMIC); ++ if (!new_set) ++ return NULL; ++ ++ new_set->id = set_id; ++ ++ INIT_LIST_HEAD(&new_set->list); ++ ++ if (prev == NULL) { ++ list_add(&(new_set->list), &ctx->set_list); ++ } else { ++ PFM_DBG("add after set=%u", prev->id); ++ list_add(&(new_set->list), &prev->list); ++ } ++ return new_set; ++} ++ ++/** ++ * pfm_create_initial_set - create initial set from __pfm_c reate_context ++ * @ctx: context to atatched the set to ++ */ ++int pfm_create_initial_set(struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set; ++ ++ /* ++ * create initial set0 ++ */ ++ if (!pfm_find_set(ctx, 0, 1)) ++ return -ENOMEM; ++ ++ set = list_first_entry(&ctx->set_list, struct pfm_event_set, list); ++ ++ pfm_initialize_set(ctx, set); ++ ++ return 0; ++} ++ ++/* ++ * context is unloaded for this command. Interrupts are enabled ++ */ ++int __pfm_create_evtsets(struct pfm_context *ctx, struct pfarg_setdesc *req, ++ int count) ++{ ++ struct pfm_event_set *set; ++ u16 set_id; ++ int i, ret; ++ ++ for (i = 0; i < count; i++, req++) { ++ set_id = req->set_id; ++ ++ PFM_DBG("set_id=%u", set_id); ++ ++ set = pfm_find_set(ctx, set_id, 1); ++ if (set == NULL) ++ goto error_mem; ++ ++ ret = pfm_change_evtset(ctx, set, req); ++ if (ret) ++ goto error_params; ++ ++ pfm_initialize_set(ctx, set); ++ } ++ return 0; ++error_mem: ++ PFM_DBG("cannot allocate set %u", set_id); ++ return -ENOMEM; ++error_params: ++ return ret; ++} ++ ++int __pfm_getinfo_evtsets(struct pfm_context *ctx, struct pfarg_setinfo *req, ++ int count) ++{ ++ struct pfm_event_set *set; ++ int i, is_system, is_loaded, is_self, ret; ++ u16 set_id; ++ u64 end; ++ ++ end = sched_clock(); ++ ++ is_system = ctx->flags.system; ++ is_loaded = ctx->state == PFM_CTX_LOADED; ++ is_self = ctx->task == current || is_system; ++ ++ ret = -EINVAL; ++ for (i = 0; i < count; i++, req++) { ++ ++ set_id = req->set_id; ++ ++ list_for_each_entry(set, &ctx->set_list, list) { ++ if (set->id == set_id) ++ goto found; ++ if (set->id > set_id) ++ goto error; ++ } ++found: ++ req->set_flags = set->flags; ++ ++ /* ++ * compute leftover timeout ++ * ++ * lockdep may complain about lock inversion ++ * because of get_remaining() however, this ++ * applies to self-montoring only, thus the ++ * thread cannot be in the timeout handler ++ * and here at the same time given that we ++ * run with interrupts disabled ++ */ ++ if (is_loaded && is_self) { ++ struct hrtimer *h; ++ h = &__get_cpu_var(pfm_hrtimer); ++ req->set_timeout = ktime_to_ns(hrtimer_get_remaining(h)); ++ } else { ++ /* ++ * hrtimer_rem zero when not using ++ * timeout-based switching ++ */ ++ req->set_timeout = ktime_to_ns(set->hrtimer_rem); ++ } ++ ++ req->set_runs = set->runs; ++ req->set_act_duration = set->duration; ++ ++ /* ++ * adjust for active set if needed ++ */ ++ if (is_system && is_loaded && ctx->flags.started ++ && set == ctx->active_set) ++ req->set_act_duration += end - set->duration_start; ++ ++ /* ++ * copy the list of pmds which last overflowed ++ */ ++ bitmap_copy(cast_ulp(req->set_ovfl_pmds), ++ cast_ulp(set->ovfl_pmds), ++ PFM_MAX_PMDS); ++ ++ /* ++ * copy bitmask of available PMU registers ++ * ++ * must copy over the entire vector to avoid ++ * returning bogus upper bits pass by user ++ */ ++ bitmap_copy(cast_ulp(req->set_avail_pmcs), ++ cast_ulp(ctx->regs.pmcs), ++ PFM_MAX_PMCS); ++ ++ bitmap_copy(cast_ulp(req->set_avail_pmds), ++ cast_ulp(ctx->regs.pmds), ++ PFM_MAX_PMDS); ++ ++ PFM_DBG("set%u flags=0x%x eff_usec=%llu runs=%llu " ++ "a_pmcs=0x%llx a_pmds=0x%llx", ++ set_id, ++ set->flags, ++ (unsigned long long)req->set_timeout, ++ (unsigned long long)set->runs, ++ (unsigned long long)ctx->regs.pmcs[0], ++ (unsigned long long)ctx->regs.pmds[0]); ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* ++ * context is unloaded for this command. Interrupts are enabled ++ */ ++int __pfm_delete_evtsets(struct pfm_context *ctx, void *arg, int count) ++{ ++ struct pfarg_setdesc *req = arg; ++ struct pfm_event_set *set; ++ u16 set_id; ++ int i, ret; ++ ++ ret = -EINVAL; ++ for (i = 0; i < count; i++, req++) { ++ set_id = req->set_id; ++ ++ list_for_each_entry(set, &ctx->set_list, list) { ++ if (set->id == set_id) ++ goto found; ++ if (set->id > set_id) ++ goto error; ++ } ++ goto error; ++found: ++ /* ++ * clear active set if necessary. ++ * will be updated when context is loaded ++ */ ++ if (set == ctx->active_set) ++ ctx->active_set = NULL; ++ ++ list_del(&set->list); ++ ++ kmem_cache_free(pfm_set_cachep, set); ++ ++ PFM_DBG("set%u deleted", set_id); ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* ++ * called from pfm_context_free() to free all sets ++ */ ++void pfm_free_sets(struct pfm_context *ctx) ++{ ++ struct pfm_event_set *set, *tmp; ++ ++ list_for_each_entry_safe(set, tmp, &ctx->set_list, list) { ++ list_del(&set->list); ++ kmem_cache_free(pfm_set_cachep, set); ++ } ++} ++ ++/** ++ * pfm_restart_timer - restart hrtimer taking care of expired timeout ++ * @ctx : context to work with ++ * @set : current active set ++ * ++ * Must be called on the processor on which the timer is to be armed. ++ * Assumes context is locked and interrupts are masked ++ * ++ * Upon return the active set for the context may have changed ++ */ ++void pfm_restart_timer(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ struct hrtimer *h; ++ enum hrtimer_restart ret; ++ ++ h = &__get_cpu_var(pfm_hrtimer); ++ ++ PFM_DBG_ovfl("hrtimer=%lld", (long long)ktime_to_ns(set->hrtimer_rem)); ++ ++ if (ktime_to_ns(set->hrtimer_rem) > 0) { ++ hrtimer_start(h, set->hrtimer_rem, HRTIMER_MODE_REL); ++ } else { ++ /* ++ * timer was not re-armed because it has already expired ++ * timer was not enqueued, we need to switch set now ++ */ ++ pfm_stats_inc(set_switch_exp); ++ ++ ret = pfm_switch_sets(ctx, NULL, 1, 0); ++ set = ctx->active_set; ++ if (ret == HRTIMER_RESTART) ++ hrtimer_start(h, set->hrtimer_rem, HRTIMER_MODE_REL); ++ } ++} ++ ++int __init pfm_init_sets(void) ++{ ++ pfm_set_cachep = kmem_cache_create("pfm_event_set", ++ sizeof(struct pfm_event_set), ++ SLAB_HWCACHE_ALIGN, 0, NULL); ++ if (!pfm_set_cachep) { ++ PFM_ERR("cannot initialize event set slab"); ++ return -ENOMEM; ++ } ++ return 0; ++} +--- /dev/null ++++ b/perfmon/perfmon_smpl.c +@@ -0,0 +1,865 @@ ++/* ++ * perfmon_smpl.c: perfmon2 sampling management ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "perfmon_priv.h" ++ ++/** ++ * pfm_smpl_buf_alloc - allocate memory for sampling buffer ++ * @ctx: context to operate on ++ * @rsize: requested size ++ * ++ * called from pfm_smpl_buffer_alloc_old() (IA64-COMPAT) ++ * and pfm_setup_smpl_fmt() ++ * ++ * interrupts are enabled, context is not locked. ++ * ++ * function is not static because it is called from the IA-64 ++ * compatibility module (perfmon_compat.c) ++ */ ++int pfm_smpl_buf_alloc(struct pfm_context *ctx, size_t rsize) ++{ ++#if PFM_ARCH_SMPL_ALIGN_SIZE > 0 ++#define PFM_ALIGN_SMPL(a, f) (void *)((((unsigned long)(a))+(f-1)) & ~(f-1)) ++#else ++#define PFM_ALIGN_SMPL(a, f) (a) ++#endif ++ void *addr, *real_addr; ++ size_t size, real_size; ++ int ret; ++ ++ might_sleep(); ++ ++ /* ++ * align page boundary ++ */ ++ size = PAGE_ALIGN(rsize); ++ ++ /* ++ * On some arch, it may be necessary to get an alignment greater ++ * than page size to avoid certain cache effects (e.g., MIPS). ++ * This is the reason for PFM_ARCH_SMPL_ALIGN_SIZE. ++ */ ++ real_size = size + PFM_ARCH_SMPL_ALIGN_SIZE; ++ ++ PFM_DBG("req_size=%zu size=%zu real_size=%zu", ++ rsize, ++ size, ++ real_size); ++ ++ ret = pfm_smpl_buf_space_acquire(ctx, real_size); ++ if (ret) ++ return ret; ++ ++ /* ++ * vmalloc can sleep. we do not hold ++ * any spinlock and interrupts are enabled ++ */ ++ real_addr = addr = vmalloc(real_size); ++ if (!real_addr) { ++ PFM_DBG("cannot allocate sampling buffer"); ++ goto unres; ++ } ++ ++ /* ++ * align the useable sampling buffer address to the arch requirement ++ * This is a nop on most architectures ++ */ ++ addr = PFM_ALIGN_SMPL(real_addr, PFM_ARCH_SMPL_ALIGN_SIZE); ++ ++ memset(addr, 0, real_size); ++ ++ /* ++ * due to cache aliasing, it may be necessary to flush the pages ++ * on certain architectures (e.g., MIPS) ++ */ ++ pfm_cacheflush(addr, real_size); ++ ++ /* ++ * what needs to be freed ++ */ ++ ctx->smpl_real_addr = real_addr; ++ ctx->smpl_real_size = real_size; ++ ++ /* ++ * what is actually available to user ++ */ ++ ctx->smpl_addr = addr; ++ ctx->smpl_size = size; ++ ++ PFM_DBG("addr=%p real_addr=%p", addr, real_addr); ++ ++ return 0; ++unres: ++ /* ++ * smpl_addr is NULL, no double freeing possible in pfm_context_free() ++ */ ++ pfm_smpl_buf_space_release(ctx, real_size); ++ ++ return -ENOMEM; ++} ++ ++/** ++ * pfm_smpl_buf_free - free resources associated with sampling ++ * @ctx: context to operate on ++ */ ++void pfm_smpl_buf_free(struct pfm_context *ctx) ++{ ++ struct pfm_smpl_fmt *fmt; ++ ++ fmt = ctx->smpl_fmt; ++ ++ /* ++ * some formats may not use a buffer, yet they may ++ * need to be called on exit ++ */ ++ if (fmt) { ++ if (fmt->fmt_exit) ++ (*fmt->fmt_exit)(ctx->smpl_addr); ++ /* ++ * decrease refcount of sampling format ++ */ ++ pfm_smpl_fmt_put(fmt); ++ } ++ ++ if (ctx->smpl_addr) { ++ pfm_smpl_buf_space_release(ctx, ctx->smpl_real_size); ++ ++ PFM_DBG("free buffer real_addr=0x%p real_size=%zu", ++ ctx->smpl_real_addr, ++ ctx->smpl_real_size); ++ ++ vfree(ctx->smpl_real_addr); ++ } ++} ++ ++/** ++ * pfm_setup_smpl_fmt - initialization of sampling format and buffer ++ * @ctx: context to operate on ++ * @fmt_arg: smapling format arguments ++ * @ctx_flags: context flags as passed by user ++ * @filp: file descriptor associated with context ++ * ++ * called from __pfm_create_context() ++ */ ++int pfm_setup_smpl_fmt(struct pfm_context *ctx, u32 ctx_flags, void *fmt_arg, ++ struct file *filp) ++{ ++ struct pfm_smpl_fmt *fmt; ++ size_t size = 0; ++ int ret = 0; ++ ++ fmt = ctx->smpl_fmt; ++ ++ /* ++ * validate parameters ++ */ ++ if (fmt->fmt_validate) { ++ ret = (*fmt->fmt_validate)(ctx_flags, ++ ctx->regs.num_pmds, ++ fmt_arg); ++ PFM_DBG("validate(0x%x,%p)=%d", ctx_flags, fmt_arg, ret); ++ if (ret) ++ goto error; ++ } ++ ++ /* ++ * check if buffer format needs buffer allocation ++ */ ++ size = 0; ++ if (fmt->fmt_getsize) { ++ ret = (*fmt->fmt_getsize)(ctx_flags, fmt_arg, &size); ++ if (ret) { ++ PFM_DBG("cannot get size ret=%d", ret); ++ goto error; ++ } ++ } ++ ++ /* ++ * allocate buffer ++ * v20_compat is for IA-64 backward compatibility with perfmon v2.0 ++ */ ++ if (size) { ++#ifdef CONFIG_IA64_PERFMON_COMPAT ++ /* ++ * backward compatibility with perfmon v2.0 on Ia-64 ++ */ ++ if (ctx->flags.ia64_v20_compat) ++ ret = pfm_smpl_buf_alloc_compat(ctx, size, filp); ++ else ++#endif ++ ret = pfm_smpl_buf_alloc(ctx, size); ++ ++ if (ret) ++ goto error; ++ ++ } ++ ++ if (fmt->fmt_init) { ++ ret = (*fmt->fmt_init)(ctx, ctx->smpl_addr, ctx_flags, ++ ctx->regs.num_pmds, ++ fmt_arg); ++ } ++ /* ++ * if there was an error, the buffer/resource will be freed by ++ * via pfm_context_free() ++ */ ++error: ++ return ret; ++} ++ ++void pfm_mask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ u64 now; ++ ++ now = sched_clock(); ++ ++ /* ++ * we save the PMD values such that we can read them while ++ * MASKED without having the thread stopped ++ * because monitoring is stopped ++ * ++ * pfm_save_pmds() could be avoided if we knew ++ * that pfm_arch_intr_freeze() had saved them already ++ */ ++ pfm_save_pmds(ctx, set); ++ pfm_arch_mask_monitoring(ctx, set); ++ /* ++ * accumulate the set duration up to this point ++ */ ++ set->duration += now - set->duration_start; ++ ++ ctx->state = PFM_CTX_MASKED; ++ ++ /* ++ * need to stop timer and remember remaining time ++ * will be reloaded in pfm_unmask_monitoring ++ * hrtimer is cancelled in the tail of the interrupt ++ * handler once the context is unlocked ++ */ ++ if (set->flags & PFM_SETFL_TIME_SWITCH) { ++ struct hrtimer *h = &__get_cpu_var(pfm_hrtimer); ++ hrtimer_cancel(h); ++ set->hrtimer_rem = hrtimer_get_remaining(h); ++ } ++ PFM_DBG_ovfl("can_restart=%u", ctx->flags.can_restart); ++} ++ ++/** ++ * pfm_unmask_monitoring - unmask monitoring ++ * @ctx: context to work with ++ * @set: current active set ++ * ++ * interrupts are masked when entering this function. ++ * context must be in MASKED state when calling. ++ * ++ * Upon return, the active set may have changed when using timeout ++ * based switching. ++ */ ++static void pfm_unmask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set) ++{ ++ if (ctx->state != PFM_CTX_MASKED) ++ return; ++ ++ PFM_DBG_ovfl("unmasking monitoring"); ++ ++ /* ++ * must be done before calling ++ * pfm_arch_unmask_monitoring() ++ */ ++ ctx->state = PFM_CTX_LOADED; ++ ++ /* ++ * we need to restore the PMDs because they ++ * may have been modified by user while MASKED in ++ * which case the actual registers have no yet ++ * been updated ++ */ ++ pfm_arch_restore_pmds(ctx, set); ++ ++ /* ++ * call arch specific handler ++ */ ++ pfm_arch_unmask_monitoring(ctx, set); ++ ++ /* ++ * clear force reload flag. May have been set ++ * in pfm_write_pmcs or pfm_write_pmds ++ */ ++ set->priv_flags &= ~PFM_SETFL_PRIV_MOD_BOTH; ++ ++ /* ++ * reset set duration timer ++ */ ++ set->duration_start = sched_clock(); ++ ++ /* ++ * restart hrtimer if needed ++ */ ++ if (set->flags & PFM_SETFL_TIME_SWITCH) { ++ pfm_restart_timer(ctx, set); ++ /* careful here as pfm_restart_timer may switch sets */ ++ } ++} ++ ++void pfm_reset_pmds(struct pfm_context *ctx, ++ struct pfm_event_set *set, ++ int num_pmds, ++ int reset_mode) ++{ ++ u64 val, mask, new_seed; ++ struct pfm_pmd *reg; ++ unsigned int i, not_masked; ++ ++ not_masked = ctx->state != PFM_CTX_MASKED; ++ ++ PFM_DBG_ovfl("%s r_pmds=0x%llx not_masked=%d", ++ reset_mode == PFM_PMD_RESET_LONG ? "long" : "short", ++ (unsigned long long)set->reset_pmds[0], ++ not_masked); ++ ++ pfm_stats_inc(reset_pmds_count); ++ ++ for (i = 0; num_pmds; i++) { ++ if (test_bit(i, cast_ulp(set->reset_pmds))) { ++ num_pmds--; ++ ++ reg = set->pmds + i; ++ ++ val = reset_mode == PFM_PMD_RESET_LONG ? ++ reg->long_reset : reg->short_reset; ++ ++ if (reg->flags & PFM_REGFL_RANDOM) { ++ mask = reg->mask; ++ new_seed = random32(); ++ ++ /* construct a full 64-bit random value: */ ++ if ((unlikely(mask >> 32) != 0)) ++ new_seed |= (u64)random32() << 32; ++ ++ /* counter values are negative numbers! */ ++ val -= (new_seed & mask); ++ } ++ ++ set->pmds[i].value = val; ++ reg->lval = val; ++ ++ /* ++ * not all PMD to reset are necessarily ++ * counters ++ */ ++ if (not_masked) ++ pfm_write_pmd(ctx, i, val); ++ ++ PFM_DBG_ovfl("set%u pmd%u sval=0x%llx", ++ set->id, ++ i, ++ (unsigned long long)val); ++ } ++ } ++ ++ /* ++ * done with reset ++ */ ++ bitmap_zero(cast_ulp(set->reset_pmds), i); ++ ++ /* ++ * make changes visible ++ */ ++ if (not_masked) ++ pfm_arch_serialize(); ++} ++ ++/* ++ * called from pfm_handle_work() and __pfm_restart() ++ * for system-wide and per-thread context to resume ++ * monitoring after a user level notification. ++ * ++ * In both cases, the context is locked and interrupts ++ * are disabled. ++ */ ++void pfm_resume_after_ovfl(struct pfm_context *ctx) ++{ ++ struct pfm_smpl_fmt *fmt; ++ u32 rst_ctrl; ++ struct pfm_event_set *set; ++ u64 *reset_pmds; ++ void *hdr; ++ int state, ret; ++ ++ hdr = ctx->smpl_addr; ++ fmt = ctx->smpl_fmt; ++ state = ctx->state; ++ set = ctx->active_set; ++ ret = 0; ++ ++ if (hdr) { ++ rst_ctrl = 0; ++ prefetch(hdr); ++ } else { ++ rst_ctrl = PFM_OVFL_CTRL_RESET; ++ } ++ ++ /* ++ * if using a sampling buffer format and it has a restart callback, ++ * then invoke it. hdr may be NULL, if the format does not use a ++ * perfmon buffer ++ */ ++ if (fmt && fmt->fmt_restart) ++ ret = (*fmt->fmt_restart)(state == PFM_CTX_LOADED, &rst_ctrl, ++ hdr); ++ ++ reset_pmds = set->reset_pmds; ++ ++ PFM_DBG("fmt_restart=%d reset_count=%d set=%u r_pmds=0x%llx switch=%d " ++ "ctx_state=%d", ++ ret, ++ ctx->flags.reset_count, ++ set->id, ++ (unsigned long long)reset_pmds[0], ++ (set->priv_flags & PFM_SETFL_PRIV_SWITCH), ++ state); ++ ++ if (!ret) { ++ /* ++ * switch set if needed ++ */ ++ if (set->priv_flags & PFM_SETFL_PRIV_SWITCH) { ++ set->priv_flags &= ~PFM_SETFL_PRIV_SWITCH; ++ pfm_switch_sets(ctx, NULL, PFM_PMD_RESET_LONG, 0); ++ set = ctx->active_set; ++ } else if (rst_ctrl & PFM_OVFL_CTRL_RESET) { ++ int nn; ++ nn = bitmap_weight(cast_ulp(set->reset_pmds), ++ ctx->regs.max_pmd); ++ if (nn) ++ pfm_reset_pmds(ctx, set, nn, PFM_PMD_RESET_LONG); ++ } ++ ++ if (!(rst_ctrl & PFM_OVFL_CTRL_MASK)) ++ pfm_unmask_monitoring(ctx, set); ++ else ++ PFM_DBG("stopping monitoring?"); ++ ctx->state = PFM_CTX_LOADED; ++ } ++} ++ ++/* ++ * This function is called when we need to perform asynchronous ++ * work on a context. This function is called ONLY when about to ++ * return to user mode (very much like with signal handling). ++ * ++ * There are several reasons why we come here: ++ * ++ * - per-thread mode, not self-monitoring, to reset the counters ++ * after a pfm_restart() ++ * ++ * - we are zombie and we need to cleanup our state ++ * ++ * - we need to block after an overflow notification ++ * on a context with the PFM_OVFL_NOTIFY_BLOCK flag ++ * ++ * This function is never called for a system-wide context. ++ * ++ * pfm_handle_work() can be called with interrupts enabled ++ * (TIF_NEED_RESCHED) or disabled. The down_interruptible ++ * call may sleep, therefore we must re-enable interrupts ++ * to avoid deadlocks. It is safe to do so because this function ++ * is called ONLY when returning to user level, in which case ++ * there is no risk of kernel stack overflow due to deep ++ * interrupt nesting. ++ */ ++void pfm_handle_work(struct pt_regs *regs) ++{ ++ struct pfm_context *ctx; ++ unsigned long flags, dummy_flags; ++ int type, ret, info; ++ ++#ifdef CONFIG_PPC ++ /* ++ * This is just a temporary fix. Obviously we'd like to fix the powerpc ++ * code to make that check before calling __pfm_handle_work() to ++ * prevent the function call overhead, but the call is made from ++ * assembly code, so it will take a little while to figure out how to ++ * perform the check correctly. ++ */ ++ if (!test_thread_flag(TIF_PERFMON_WORK)) ++ return; ++#endif ++ ++ if (!user_mode(regs)) ++ return; ++ ++ clear_thread_flag(TIF_PERFMON_WORK); ++ ++ pfm_stats_inc(handle_work_count); ++ ++ ctx = current->pfm_context; ++ if (ctx == NULL) { ++ PFM_DBG("[%d] has no ctx", current->pid); ++ return; ++ } ++ ++ BUG_ON(ctx->flags.system); ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ type = ctx->flags.work_type; ++ ctx->flags.work_type = PFM_WORK_NONE; ++ ++ PFM_DBG("work_type=%d reset_count=%d", ++ type, ++ ctx->flags.reset_count); ++ ++ switch (type) { ++ case PFM_WORK_ZOMBIE: ++ goto do_zombie; ++ case PFM_WORK_RESET: ++ /* simply reset, no blocking */ ++ goto skip_blocking; ++ case PFM_WORK_NONE: ++ PFM_DBG("unexpected PFM_WORK_NONE"); ++ goto nothing_todo; ++ case PFM_WORK_BLOCK: ++ break; ++ default: ++ PFM_DBG("unkown type=%d", type); ++ goto nothing_todo; ++ } ++ ++ /* ++ * restore interrupt mask to what it was on entry. ++ * Could be enabled/disabled. ++ */ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ /* ++ * force interrupt enable because of down_interruptible() ++ */ ++ local_irq_enable(); ++ ++ PFM_DBG("before block sleeping"); ++ ++ /* ++ * may go through without blocking on SMP systems ++ * if restart has been received already by the time we call down() ++ */ ++ ret = wait_for_completion_interruptible(&ctx->restart_complete); ++ ++ PFM_DBG("after block sleeping ret=%d", ret); ++ ++ /* ++ * lock context and mask interrupts again ++ * We save flags into a dummy because we may have ++ * altered interrupts mask compared to entry in this ++ * function. ++ */ ++ spin_lock_irqsave(&ctx->lock, dummy_flags); ++ ++ if (ctx->state == PFM_CTX_ZOMBIE) ++ goto do_zombie; ++ ++ /* ++ * in case of interruption of down() we don't restart anything ++ */ ++ if (ret < 0) ++ goto nothing_todo; ++ ++skip_blocking: ++ /* ++ * iterate over the number of pending resets ++ * There are certain situations where there may be ++ * multiple notifications sent before a pfm_restart(). ++ * As such, it may be that multiple pfm_restart() are ++ * issued before the monitored thread gets to ++ * pfm_handle_work(). To avoid losing restarts, pfm_restart() ++ * increments a counter (reset_counts). Here, we take this ++ * into account by potentially calling pfm_resume_after_ovfl() ++ * multiple times. It is up to the sampling format to take the ++ * appropriate actions. ++ */ ++ while (ctx->flags.reset_count) { ++ pfm_resume_after_ovfl(ctx); ++ /* careful as active set may have changed */ ++ ctx->flags.reset_count--; ++ } ++ ++nothing_todo: ++ /* ++ * restore flags as they were upon entry ++ */ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ return; ++ ++do_zombie: ++ PFM_DBG("context is zombie, bailing out"); ++ ++ __pfm_unload_context(ctx, &info); ++ ++ /* ++ * keep the spinlock check happy ++ */ ++ spin_unlock(&ctx->lock); ++ ++ /* ++ * enable interrupt for vfree() ++ */ ++ local_irq_enable(); ++ ++ /* ++ * cancel timer now that context is unlocked ++ */ ++ if (info & 0x2) { ++ ret = hrtimer_cancel(&__get_cpu_var(pfm_hrtimer)); ++ PFM_DBG("timeout cancel=%d", ret); ++ } ++ ++ /* ++ * actual context free ++ */ ++ pfm_free_context(ctx); ++ ++ /* ++ * restore interrupts as they were upon entry ++ */ ++ local_irq_restore(flags); ++ ++ /* always true */ ++ if (info & 0x1) ++ pfm_session_release(0, 0); ++} ++ ++/** ++ * __pfm_restart - resume monitoring after user-level notification ++ * @ctx: context to operate on ++ * @info: return information used to free resource once unlocked ++ * ++ * function called from sys_pfm_restart(). It is used when overflow ++ * notification is requested. For each notification received, the user ++ * must call pfm_restart() to indicate to the kernel that it is done ++ * processing the notification. ++ * ++ * When the caller is doing user level sampling, this function resets ++ * the overflowed counters and resumes monitoring which is normally stopped ++ * during notification (always the consequence of a counter overflow). ++ * ++ * When using a sampling format, the format restart() callback is invoked, ++ * overflowed PMDS may be reset based upon decision from sampling format. ++ * ++ * When operating in per-thread mode, and when not self-monitoring, the ++ * monitored thread DOES NOT need to be stopped, unlike for many other calls. ++ * ++ * This means that the effect of the restart may not necessarily be observed ++ * right when returning from the call. For instance, counters may not already ++ * be reset in the other thread. ++ * ++ * When operating in system-wide, the caller must be running on the monitored ++ * CPU. ++ * ++ * The context is locked and interrupts are disabled. ++ * ++ * info value upon return: ++ * - bit 0: when set, mudt issue complete() on restart semaphore ++ */ ++int __pfm_restart(struct pfm_context *ctx, int *info) ++{ ++ int state; ++ ++ state = ctx->state; ++ ++ PFM_DBG("state=%d can_restart=%d reset_count=%d", ++ state, ++ ctx->flags.can_restart, ++ ctx->flags.reset_count); ++ ++ *info = 0; ++ ++ switch (state) { ++ case PFM_CTX_MASKED: ++ break; ++ case PFM_CTX_LOADED: ++ if (ctx->smpl_addr && ctx->smpl_fmt->fmt_restart) ++ break; ++ default: ++ PFM_DBG("invalid state=%d", state); ++ return -EBUSY; ++ } ++ ++ /* ++ * first check if allowed to restart, i.e., notifications received ++ */ ++ if (!ctx->flags.can_restart) { ++ PFM_DBG("no restart can_restart=0"); ++ return -EBUSY; ++ } ++ ++ pfm_stats_inc(pfm_restart_count); ++ ++ /* ++ * at this point, the context is either LOADED or MASKED ++ */ ++ ctx->flags.can_restart--; ++ ++ /* ++ * handle self-monitoring case and system-wide ++ */ ++ if (ctx->task == current || ctx->flags.system) { ++ pfm_resume_after_ovfl(ctx); ++ return 0; ++ } ++ ++ /* ++ * restart another task ++ */ ++ ++ /* ++ * if blocking, then post the semaphore if PFM_CTX_MASKED, i.e. ++ * the task is blocked or on its way to block. That's the normal ++ * restart path. If the monitoring is not masked, then the task ++ * can be actively monitoring and we cannot directly intervene. ++ * Therefore we use the trap mechanism to catch the task and ++ * force it to reset the buffer/reset PMDs. ++ * ++ * if non-blocking, then we ensure that the task will go into ++ * pfm_handle_work() before returning to user mode. ++ * ++ * We cannot explicitly reset another task, it MUST always ++ * be done by the task itself. This works for system wide because ++ * the tool that is controlling the session is logically doing ++ * "self-monitoring". ++ */ ++ if (ctx->flags.block && state == PFM_CTX_MASKED) { ++ PFM_DBG("unblocking [%d]", ctx->task->pid); ++ /* ++ * It is not possible to call complete() with the context locked ++ * otherwise we have a potential deadlock with the PMU context ++ * switch code due to a lock inversion between task_rq_lock() ++ * and the context lock. ++ * Instead we mark whether or not we need to issue the complete ++ * and we invoke the function once the context lock is released ++ * in sys_pfm_restart() ++ */ ++ *info = 1; ++ } else { ++ PFM_DBG("[%d] armed exit trap", ctx->task->pid); ++ pfm_post_work(ctx->task, ctx, PFM_WORK_RESET); ++ } ++ ctx->flags.reset_count++; ++ return 0; ++} ++ ++/** ++ * pfm_get_smpl_arg -- copy user arguments to pfm_create_context() related to sampling format ++ * @name: format name as passed by user ++ * @fmt_arg: format optional argument as passed by user ++ * @uszie: size of structure pass in fmt_arg ++ * @arg: kernel copy of fmt_arg ++ * @fmt: pointer to sampling format upon success ++ * ++ * arg is kmalloc'ed, thus it needs a kfree by caller ++ */ ++int pfm_get_smpl_arg(char __user *fmt_uname, void __user *fmt_uarg, size_t usize, void **arg, ++ struct pfm_smpl_fmt **fmt) ++{ ++ struct pfm_smpl_fmt *f; ++ char *fmt_name; ++ void *addr = NULL; ++ size_t sz; ++ int ret; ++ ++ fmt_name = getname(fmt_uname); ++ if (!fmt_name) { ++ PFM_DBG("getname failed"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * find fmt and increase refcount ++ */ ++ f = pfm_smpl_fmt_get(fmt_name); ++ ++ putname(fmt_name); ++ ++ if (f == NULL) { ++ PFM_DBG("buffer format not found"); ++ return -EINVAL; ++ } ++ ++ /* ++ * expected format argument size ++ */ ++ sz = f->fmt_arg_size; ++ ++ /* ++ * check user size matches expected size ++ * usize = -1 is for IA-64 backward compatibility ++ */ ++ ret = -EINVAL; ++ if (sz != usize && usize != -1) { ++ PFM_DBG("invalid arg size %zu, format expects %zu", ++ usize, sz); ++ goto error; ++ } ++ ++ if (sz) { ++ ret = -ENOMEM; ++ addr = kmalloc(sz, GFP_KERNEL); ++ if (addr == NULL) ++ goto error; ++ ++ ret = -EFAULT; ++ if (copy_from_user(addr, fmt_uarg, sz)) ++ goto error; ++ } ++ *arg = addr; ++ *fmt = f; ++ return 0; ++ ++error: ++ kfree(addr); ++ pfm_smpl_fmt_put(f); ++ return ret; ++} +--- /dev/null ++++ b/perfmon/perfmon_syscalls.c +@@ -0,0 +1,1060 @@ ++/* ++ * perfmon_syscalls.c: perfmon2 system call interface ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include "perfmon_priv.h" ++ ++/* ++ * Context locking rules: ++ * --------------------- ++ * - any thread with access to the file descriptor of a context can ++ * potentially issue perfmon calls ++ * ++ * - calls must be serialized to guarantee correctness ++ * ++ * - as soon as a context is attached to a thread or CPU, it may be ++ * actively monitoring. On some architectures, such as IA-64, this ++ * is true even though the pfm_start() call has not been made. This ++ * comes from the fact that on some architectures, it is possible to ++ * start/stop monitoring from userland. ++ * ++ * - If monitoring is active, then there can PMU interrupts. Because ++ * context accesses must be serialized, the perfmon system calls ++ * must mask interrupts as soon as the context is attached. ++ * ++ * - perfmon system calls that operate with the context unloaded cannot ++ * assume it is actually unloaded when they are called. They first need ++ * to check and for that they need interrupts masked. Then, if the ++ * context is actually unloaded, they can unmask interrupts. ++ * ++ * - interrupt masking holds true for other internal perfmon functions as ++ * well. Except for PMU interrupt handler because those interrupts ++ * cannot be nested. ++ * ++ * - we mask ALL interrupts instead of just the PMU interrupt because we ++ * also need to protect against timer interrupts which could trigger ++ * a set switch. ++ */ ++#ifdef CONFIG_UTRACE ++#include ++ ++static u32 ++stopper_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) ++{ ++ PFM_DBG("quiesced [%d]", tsk->pid); ++ complete(engine->data); ++ return UTRACE_ACTION_RESUME; ++} ++ ++void ++pfm_resume_task(struct task_struct *t, void *data) ++{ ++ PFM_DBG("utrace detach [%d]", t->pid); ++ (void) utrace_detach(t, data); ++} ++ ++static const struct utrace_engine_ops utrace_ops = ++{ ++ .report_quiesce = stopper_quiesce, ++}; ++ ++static int pfm_wait_task_stopped(struct task_struct *task, void **data) ++{ ++ DECLARE_COMPLETION_ONSTACK(done); ++ struct utrace_attached_engine *eng; ++ int ret; ++ ++ eng = utrace_attach(task, UTRACE_ATTACH_CREATE, &utrace_ops, &done); ++ if (IS_ERR(eng)) ++ return PTR_ERR(eng); ++ ++ ret = utrace_set_flags(task, eng, ++ UTRACE_ACTION_QUIESCE | UTRACE_EVENT(QUIESCE)); ++ PFM_DBG("wait quiesce [%d]", task->pid); ++ if (!ret) ++ ret = wait_for_completion_interruptible(&done); ++ ++ if (ret) ++ (void) utrace_detach(task, eng); ++ else ++ *data = eng; ++ return 0; ++} ++#else /* !CONFIG_UTRACE */ ++static int pfm_wait_task_stopped(struct task_struct *task, void **data) ++{ ++ int ret; ++ ++ *data = NULL; ++ ++ /* ++ * returns 0 if cannot attach ++ */ ++ ret = ptrace_may_access(task, PTRACE_MODE_ATTACH); ++ PFM_DBG("may_attach=%d", ret); ++ if (!ret) ++ return -EPERM; ++ ++ ret = ptrace_check_attach(task, 0); ++ PFM_DBG("check_attach=%d", ret); ++ return ret; ++} ++void pfm_resume_task(struct task_struct *t, void *data) ++{} ++#endif ++ ++struct pfm_syscall_cookie { ++ struct file *filp; ++ int fput_needed; ++}; ++ ++/* ++ * cannot attach if : ++ * - kernel task ++ * - task not owned by caller (checked by ptrace_may_attach()) ++ * - task is dead or zombie ++ * - cannot use blocking notification when self-monitoring ++ */ ++static int pfm_task_incompatible(struct pfm_context *ctx, ++ struct task_struct *task) ++{ ++ /* ++ * cannot attach to a kernel thread ++ */ ++ if (!task->mm) { ++ PFM_DBG("cannot attach to kernel thread [%d]", task->pid); ++ return -EPERM; ++ } ++ ++ /* ++ * cannot use block on notification when ++ * self-monitoring. ++ */ ++ if (ctx->flags.block && task == current) { ++ PFM_DBG("cannot use block on notification when self-monitoring" ++ "[%d]", task->pid); ++ return -EINVAL; ++ } ++ /* ++ * cannot attach to a zombie task ++ */ ++ if (task->exit_state == EXIT_ZOMBIE || task->exit_state == EXIT_DEAD) { ++ PFM_DBG("cannot attach to zombie/dead task [%d]", task->pid); ++ return -EBUSY; ++ } ++ return 0; ++} ++ ++/** ++ * pfm_get_task -- check permission and acquire task to monitor ++ * @ctx: perfmon context ++ * @pid: identification of the task to check ++ * @task: upon return, a pointer to the task to monitor ++ * ++ * This function is used in per-thread mode only AND when not ++ * self-monitoring. It finds the task to monitor and checks ++ * that the caller has permissions to attach. It also checks ++ * that the task is stopped via ptrace so that we can safely ++ * modify its state. ++ * ++ * task refcount is incremented when succesful. ++ */ ++static int pfm_get_task(struct pfm_context *ctx, pid_t pid, ++ struct task_struct **task, void **data) ++{ ++ struct task_struct *p; ++ int ret = 0, ret1 = 0; ++ ++ *data = NULL; ++ ++ /* ++ * When attaching to another thread we must ensure ++ * that the thread is actually stopped. ++ * ++ * As a consequence, only the ptracing parent can actually ++ * attach a context to a thread. Obviously, this constraint ++ * does not exist for self-monitoring threads. ++ * ++ * We use ptrace_may_attach() to check for permission. ++ */ ++ read_lock(&tasklist_lock); ++ ++ p = find_task_by_vpid(pid); ++ if (p) ++ get_task_struct(p); ++ ++ read_unlock(&tasklist_lock); ++ ++ if (!p) { ++ PFM_DBG("task not found %d", pid); ++ return -ESRCH; ++ } ++ ++ ret = pfm_task_incompatible(ctx, p); ++ if (ret) ++ goto error; ++ ++ ret = pfm_wait_task_stopped(p, data); ++ if (ret) ++ goto error; ++ ++ *task = p; ++ ++ return 0; ++error: ++ if (!(ret1 || ret)) ++ ret = -EPERM; ++ ++ put_task_struct(p); ++ ++ return ret; ++} ++ ++/* ++ * context must be locked when calling this function ++ */ ++int pfm_check_task_state(struct pfm_context *ctx, int check_mask, ++ unsigned long *flags, void **resume) ++{ ++ struct task_struct *task; ++ unsigned long local_flags, new_flags; ++ int state, ret; ++ ++ *resume = NULL; ++ ++recheck: ++ /* ++ * task is NULL for system-wide context ++ */ ++ task = ctx->task; ++ state = ctx->state; ++ local_flags = *flags; ++ ++ PFM_DBG("state=%d check_mask=0x%x", state, check_mask); ++ /* ++ * if the context is detached, then we do not touch ++ * hardware, therefore there is not restriction on when we can ++ * access it. ++ */ ++ if (state == PFM_CTX_UNLOADED) ++ return 0; ++ /* ++ * no command can operate on a zombie context. ++ * A context becomes zombie when the file that identifies ++ * it is closed while the context is still attached to the ++ * thread it monitors. ++ */ ++ if (state == PFM_CTX_ZOMBIE) ++ return -EINVAL; ++ ++ /* ++ * at this point, state is PFM_CTX_LOADED or PFM_CTX_MASKED ++ */ ++ ++ /* ++ * some commands require the context to be unloaded to operate ++ */ ++ if (check_mask & PFM_CMD_UNLOADED) { ++ PFM_DBG("state=%d, cmd needs context unloaded", state); ++ return -EBUSY; ++ } ++ ++ /* ++ * self-monitoring always ok. ++ */ ++ if (task == current) ++ return 0; ++ ++ /* ++ * for syswide, the calling thread must be running on the cpu ++ * the context is bound to. ++ */ ++ if (ctx->flags.system) { ++ if (ctx->cpu != smp_processor_id()) ++ return -EBUSY; ++ return 0; ++ } ++ ++ /* ++ * at this point, monitoring another thread ++ */ ++ ++ /* ++ * the pfm_unload_context() command is allowed on masked context ++ */ ++ if (state == PFM_CTX_MASKED && !(check_mask & PFM_CMD_UNLOAD)) ++ return 0; ++ ++ /* ++ * When we operate on another thread, we must wait for it to be ++ * stopped and completely off any CPU as we need to access the ++ * PMU state (or machine state). ++ * ++ * A thread can be put in the STOPPED state in various ways ++ * including PTRACE_ATTACH, or when it receives a SIGSTOP signal. ++ * We enforce that the thread must be ptraced, so it is stopped ++ * AND it CANNOT wake up while we operate on it because this ++ * would require an action from the ptracing parent which is the ++ * thread that is calling this function. ++ * ++ * The dependency on ptrace, imposes that only the ptracing ++ * parent can issue command on a thread. This is unfortunate ++ * but we do not know of a better way of doing this. ++ */ ++ if (check_mask & PFM_CMD_STOPPED) { ++ ++ spin_unlock_irqrestore(&ctx->lock, local_flags); ++ ++ /* ++ * check that the thread is ptraced AND STOPPED ++ */ ++ ret = pfm_wait_task_stopped(task, resume); ++ ++ spin_lock_irqsave(&ctx->lock, new_flags); ++ ++ /* ++ * flags may be different than when we released the lock ++ */ ++ *flags = new_flags; ++ ++ if (ret) ++ return ret; ++ /* ++ * we must recheck to verify if state has changed ++ */ ++ if (unlikely(ctx->state != state)) { ++ PFM_DBG("old_state=%d new_state=%d", ++ state, ++ ctx->state); ++ goto recheck; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * pfm_get_args - Function used to copy the syscall argument into kernel memory. ++ * @ureq: user argument ++ * @sz: user argument size ++ * @lsz: size of stack buffer ++ * @laddr: stack buffer address ++ * @req: point to start of kernel copy of the argument ++ * @ptr_free: address of kernel copy to free ++ * ++ * There are two options: ++ * - use a stack buffer described by laddr (addresses) and lsz (size) ++ * - allocate memory ++ * ++ * return: ++ * < 0 : in case of error (ptr_free may not be updated) ++ * 0 : success ++ * - req: points to base of kernel copy of arguments ++ * - ptr_free: address of buffer to free by caller on exit. ++ * NULL if using the stack buffer ++ * ++ * when ptr_free is not NULL upon return, the caller must kfree() ++ */ ++int pfm_get_args(void __user *ureq, size_t sz, size_t lsz, void *laddr, ++ void **req, void **ptr_free) ++{ ++ void *addr; ++ ++ /* ++ * check syadmin argument limit ++ */ ++ if (unlikely(sz > pfm_controls.arg_mem_max)) { ++ PFM_DBG("argument too big %zu max=%zu", ++ sz, ++ pfm_controls.arg_mem_max); ++ return -E2BIG; ++ } ++ ++ /* ++ * check if vector fits on stack buffer ++ */ ++ if (sz > lsz) { ++ addr = kmalloc(sz, GFP_KERNEL); ++ if (unlikely(addr == NULL)) ++ return -ENOMEM; ++ *ptr_free = addr; ++ } else { ++ addr = laddr; ++ *req = laddr; ++ *ptr_free = NULL; ++ } ++ ++ /* ++ * bring the data in ++ */ ++ if (unlikely(copy_from_user(addr, ureq, sz))) { ++ if (addr != laddr) ++ kfree(addr); ++ return -EFAULT; ++ } ++ ++ /* ++ * base address of kernel buffer ++ */ ++ *req = addr; ++ ++ return 0; ++} ++ ++/** ++ * pfm_acquire_ctx_from_fd -- get ctx from file descriptor ++ * @fd: file descriptor ++ * @ctx: pointer to pointer of context updated on return ++ * @cookie: opaque structure to use for release ++ * ++ * This helper function extracts the ctx from the file descriptor. ++ * It also increments the refcount of the file structure. Thus ++ * it updates the cookie so the refcount can be decreased when ++ * leaving the perfmon syscall via pfm_release_ctx_from_fd ++ */ ++static int pfm_acquire_ctx_from_fd(int fd, struct pfm_context **ctx, ++ struct pfm_syscall_cookie *cookie) ++{ ++ struct file *filp; ++ int fput_needed; ++ ++ filp = fget_light(fd, &fput_needed); ++ if (unlikely(filp == NULL)) { ++ PFM_DBG("invalid fd %d", fd); ++ return -EBADF; ++ } ++ ++ *ctx = filp->private_data; ++ ++ if (unlikely(!*ctx || filp->f_op != &pfm_file_ops)) { ++ PFM_DBG("fd %d not related to perfmon", fd); ++ return -EBADF; ++ } ++ cookie->filp = filp; ++ cookie->fput_needed = fput_needed; ++ ++ return 0; ++} ++ ++/** ++ * pfm_release_ctx_from_fd -- decrease refcount of file associated with context ++ * @cookie: the cookie structure initialized by pfm_acquire_ctx_from_fd ++ */ ++static inline void pfm_release_ctx_from_fd(struct pfm_syscall_cookie *cookie) ++{ ++ fput_light(cookie->filp, cookie->fput_needed); ++} ++ ++/* ++ * unlike the other perfmon system calls, this one returns a file descriptor ++ * or a value < 0 in case of error, very much like open() or socket() ++ */ ++asmlinkage long sys_pfm_create_context(struct pfarg_ctx __user *ureq, ++ char __user *fmt_name, ++ void __user *fmt_uarg, size_t fmt_size) ++{ ++ struct pfarg_ctx req; ++ struct pfm_smpl_fmt *fmt = NULL; ++ void *fmt_arg = NULL; ++ int ret; ++ ++ PFM_DBG("req=%p fmt=%p fmt_arg=%p size=%zu", ++ ureq, fmt_name, fmt_uarg, fmt_size); ++ ++ if (perfmon_disabled) ++ return -ENOSYS; ++ ++ if (copy_from_user(&req, ureq, sizeof(req))) ++ return -EFAULT; ++ ++ if (fmt_name) { ++ ret = pfm_get_smpl_arg(fmt_name, fmt_uarg, fmt_size, &fmt_arg, &fmt); ++ if (ret) ++ goto abort; ++ } ++ ++ ret = __pfm_create_context(&req, fmt, fmt_arg, PFM_NORMAL, NULL); ++ ++ kfree(fmt_arg); ++abort: ++ return ret; ++} ++ ++asmlinkage long sys_pfm_write_pmcs(int fd, struct pfarg_pmc __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ struct pfarg_pmc pmcs[PFM_PMC_STK_ARG]; ++ struct pfarg_pmc *req; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p count=%d", fd, ureq, count); ++ ++ if (count < 0 || count >= PFM_MAX_ARG_COUNT(ureq)) { ++ PFM_DBG("invalid arg count %d", count); ++ return -EINVAL; ++ } ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ ret = pfm_get_args(ureq, sz, sizeof(pmcs), pmcs, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_write_pmcs(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ /* ++ * This function may be on the critical path. ++ * We want to avoid the branch if unecessary. ++ */ ++ if (fptr) ++ kfree(fptr); ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_write_pmds(int fd, struct pfarg_pmd __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ struct pfarg_pmd pmds[PFM_PMD_STK_ARG]; ++ struct pfarg_pmd *req; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p count=%d", fd, ureq, count); ++ ++ if (count < 0 || count >= PFM_MAX_ARG_COUNT(ureq)) { ++ PFM_DBG("invalid arg count %d", count); ++ return -EINVAL; ++ } ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ ret = pfm_get_args(ureq, sz, sizeof(pmds), pmds, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_write_pmds(ctx, req, count, 0); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (fptr) ++ kfree(fptr); ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_read_pmds(int fd, struct pfarg_pmd __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ struct pfarg_pmd pmds[PFM_PMD_STK_ARG]; ++ struct pfarg_pmd *req; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p count=%d", fd, ureq, count); ++ ++ if (count < 0 || count >= PFM_MAX_ARG_COUNT(ureq)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ ret = pfm_get_args(ureq, sz, sizeof(pmds), pmds, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_read_pmds(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (fptr) ++ kfree(fptr); ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_restart(int fd) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ void *resume; ++ unsigned long flags; ++ int ret, info; ++ ++ PFM_DBG("fd=%d", fd); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, 0, &flags, &resume); ++ if (!ret) ++ ret = __pfm_restart(ctx, &info); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ /* ++ * In per-thread mode with blocking notification, i.e. ++ * ctx->flags.blocking=1, we need to defer issuing the ++ * complete to unblock the blocked monitored thread. ++ * Otherwise we have a potential deadlock due to a lock ++ * inversion between the context lock and the task_rq_lock() ++ * which can happen if one thread is in this call and the other ++ * (the monitored thread) is in the context switch code. ++ * ++ * It is safe to access the context outside the critical section ++ * because: ++ * - we are protected by the fget_light(), thus the context ++ * cannot disappear ++ */ ++ if (ret == 0 && info == 1) ++ complete(&ctx->restart_complete); ++ ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_stop(int fd) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ void *resume; ++ unsigned long flags; ++ int ret; ++ int release_info; ++ ++ PFM_DBG("fd=%d", fd); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_stop(ctx, &release_info); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ /* ++ * defer cancellation of timer to avoid race ++ * with pfm_handle_switch_timeout() ++ * ++ * applies only when self-monitoring ++ */ ++ if (release_info & 0x2) ++ hrtimer_cancel(&__get_cpu_var(pfm_hrtimer)); ++ ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *ureq) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ void *resume; ++ struct pfarg_start req; ++ unsigned long flags; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p", fd, ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ /* ++ * the one argument is actually optional ++ */ ++ if (ureq && copy_from_user(&req, ureq, sizeof(req))) ++ return -EFAULT; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_start(ctx, ureq ? &req : NULL); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ureq) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ void *resume, *dummy_resume; ++ unsigned long flags; ++ struct pfarg_load req; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p", fd, ureq); ++ ++ if (copy_from_user(&req, ureq, sizeof(req))) ++ return -EFAULT; ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ task = current; ++ ++ /* ++ * in per-thread mode (not self-monitoring), get a reference ++ * on task to monitor. This must be done with interrupts enabled ++ * Upon succesful return, refcount on task is increased. ++ * ++ * fget_light() is protecting the context. ++ */ ++ if (!ctx->flags.system && req.load_pid != current->pid) { ++ ret = pfm_get_task(ctx, req.load_pid, &task, &resume); ++ if (ret) ++ goto error; ++ } ++ ++ /* ++ * irqsave is required to avoid race in case context is already ++ * loaded or with switch timeout in the case of self-monitoring ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_UNLOADED, &flags, &dummy_resume); ++ if (!ret) ++ ret = __pfm_load_context(ctx, &req, task); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ /* ++ * in per-thread mode (not self-monitoring), we need ++ * to decrease refcount on task to monitor: ++ * - load successful: we have a reference to the task in ctx->task ++ * - load failed : undo the effect of pfm_get_task() ++ */ ++ if (task != current) ++ put_task_struct(task); ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_unload_context(int fd) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ void *resume; ++ unsigned long flags; ++ int ret; ++ int is_system, release_info = 0; ++ u32 cpu; ++ ++ PFM_DBG("fd=%d", fd); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ is_system = ctx->flags.system; ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ cpu = ctx->cpu; ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED|PFM_CMD_UNLOAD, ++ &flags, &resume); ++ if (!ret) ++ ret = __pfm_unload_context(ctx, &release_info); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ /* ++ * cancel time now that context is unlocked ++ * avoid race with pfm_handle_switch_timeout() ++ */ ++ if (release_info & 0x2) { ++ int r; ++ r = hrtimer_cancel(&__get_cpu_var(pfm_hrtimer)); ++ PFM_DBG("timeout cancel=%d", r); ++ } ++ ++ if (release_info & 0x1) ++ pfm_session_release(is_system, cpu); ++ ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_create_evtsets(int fd, struct pfarg_setdesc __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct pfm_syscall_cookie cookie; ++ struct pfarg_setdesc *req; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p count=%d", fd, ureq, count); ++ ++ if (count < 0 || count >= PFM_MAX_ARG_COUNT(ureq)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ /* ++ * must mask interrupts because we do not know the state of context, ++ * could be attached and we could be getting PMU interrupts. So ++ * we mask and lock context and we check and possibly relax masking ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_UNLOADED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_create_evtsets(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ /* ++ * context must be unloaded for this command. The resume pointer ++ * is necessarily NULL, thus no need to call pfm_resume_task() ++ */ ++ kfree(fptr); ++ ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_getinfo_evtsets(int fd, struct pfarg_setinfo __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct task_struct *task; ++ struct pfm_syscall_cookie cookie; ++ struct pfarg_setinfo *req; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p count=%d", fd, ureq, count); ++ ++ if (count < 0 || count >= PFM_MAX_ARG_COUNT(ureq)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ /* ++ * this command operates even when context is loaded, so we need ++ * to keep interrupts masked to avoid a race with PMU interrupt ++ * which may switch the active set ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ task = ctx->task; ++ ++ ret = pfm_check_task_state(ctx, 0, &flags, &resume); ++ if (!ret) ++ ret = __pfm_getinfo_evtsets(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ ++ if (resume) ++ pfm_resume_task(task, resume); ++ ++ if (copy_to_user(ureq, req, sz)) ++ ret = -EFAULT; ++ ++ kfree(fptr); ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} ++ ++asmlinkage long sys_pfm_delete_evtsets(int fd, struct pfarg_setinfo __user *ureq, int count) ++{ ++ struct pfm_context *ctx; ++ struct pfm_syscall_cookie cookie; ++ struct pfarg_setinfo *req; ++ void *fptr, *resume; ++ unsigned long flags; ++ size_t sz; ++ int ret; ++ ++ PFM_DBG("fd=%d req=%p count=%d", fd, ureq, count); ++ ++ if (count < 0 || count >= PFM_MAX_ARG_COUNT(ureq)) ++ return -EINVAL; ++ ++ sz = count*sizeof(*ureq); ++ ++ ret = pfm_acquire_ctx_from_fd(fd, &ctx, &cookie); ++ if (ret) ++ return ret; ++ ++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr); ++ if (ret) ++ goto error; ++ ++ /* ++ * must mask interrupts because we do not know the state of context, ++ * could be attached and we could be getting PMU interrupts ++ */ ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ ret = pfm_check_task_state(ctx, PFM_CMD_UNLOADED, &flags, &resume); ++ if (!ret) ++ ret = __pfm_delete_evtsets(ctx, req, count); ++ ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ /* ++ * context must be unloaded for this command. The resume pointer ++ * is necessarily NULL, thus no need to call pfm_resume_task() ++ */ ++ kfree(fptr); ++ ++error: ++ pfm_release_ctx_from_fd(&cookie); ++ return ret; ++} +--- /dev/null ++++ b/perfmon/perfmon_sysfs.c +@@ -0,0 +1,525 @@ ++/* ++ * perfmon_sysfs.c: perfmon2 sysfs interface ++ * ++ * This file implements the perfmon2 interface which ++ * provides access to the hardware performance counters ++ * of the host processor. ++ * ++ * The initial version of perfmon.c was written by ++ * Ganesh Venkitachalam, IBM Corp. ++ * ++ * Then it was modified for perfmon-1.x by Stephane Eranian and ++ * David Mosberger, Hewlett Packard Co. ++ * ++ * Version Perfmon-2.x is a complete rewrite of perfmon-1.x ++ * by Stephane Eranian, Hewlett Packard Co. ++ * ++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P. ++ * Contributed by Stephane Eranian ++ * David Mosberger-Tang ++ * ++ * More information about perfmon available at: ++ * http://perfmon2.sf.net ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ * 02111-1307 USA ++ */ ++#include ++#include /* for EXPORT_SYMBOL */ ++#include ++#include "perfmon_priv.h" ++ ++struct pfm_attribute { ++ struct attribute attr; ++ ssize_t (*show)(void *, struct pfm_attribute *attr, char *); ++ ssize_t (*store)(void *, const char *, size_t); ++}; ++#define to_attr(n) container_of(n, struct pfm_attribute, attr); ++ ++#define PFM_RO_ATTR(_name, _show) \ ++ struct kobj_attribute attr_##_name = __ATTR(_name, 0444, _show, NULL) ++ ++#define PFM_RW_ATTR(_name, _show, _store) \ ++ struct kobj_attribute attr_##_name = __ATTR(_name, 0644, _show, _store) ++ ++#define PFM_ROS_ATTR(_name, _show) \ ++ struct pfm_attribute attr_##_name = __ATTR(_name, 0444, _show, NULL) ++ ++#define is_attr_name(a, n) (!strcmp((a)->attr.name, n)) ++int pfm_sysfs_add_pmu(struct pfm_pmu_config *pmu); ++ ++static struct kobject *pfm_kernel_kobj, *pfm_fmt_kobj; ++static struct kobject *pfm_pmu_kobj; ++ ++static ssize_t pfm_regs_attr_show(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ struct pfm_regmap_desc *reg = to_reg(kobj); ++ struct pfm_attribute *attribute = to_attr(attr); ++ return attribute->show ? attribute->show(reg, attribute, buf) : -EIO; ++} ++ ++static ssize_t pfm_fmt_attr_show(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ struct pfm_smpl_fmt *fmt = to_smpl_fmt(kobj); ++ struct pfm_attribute *attribute = to_attr(attr); ++ return attribute->show ? attribute->show(fmt, attribute, buf) : -EIO; ++} ++ ++static struct sysfs_ops pfm_regs_sysfs_ops = { ++ .show = pfm_regs_attr_show ++}; ++ ++static struct sysfs_ops pfm_fmt_sysfs_ops = { ++ .show = pfm_fmt_attr_show ++}; ++ ++static struct kobj_type pfm_regs_ktype = { ++ .sysfs_ops = &pfm_regs_sysfs_ops, ++}; ++ ++static struct kobj_type pfm_fmt_ktype = { ++ .sysfs_ops = &pfm_fmt_sysfs_ops, ++}; ++ ++static ssize_t pfm_controls_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ int base; ++ ++ if (is_attr_name(attr, "version")) ++ return snprintf(buf, PAGE_SIZE, "%u.%u\n", PFM_VERSION_MAJ, PFM_VERSION_MIN); ++ ++ if (is_attr_name(attr, "task_sessions_count")) ++ return pfm_sysfs_res_show(buf, PAGE_SIZE, 0); ++ ++ if (is_attr_name(attr, "debug")) ++ return snprintf(buf, PAGE_SIZE, "%d\n", pfm_controls.debug); ++ ++ if (is_attr_name(attr, "task_group")) ++ return snprintf(buf, PAGE_SIZE, "%d\n", pfm_controls.task_group); ++ ++ if (is_attr_name(attr, "mode")) ++ return snprintf(buf, PAGE_SIZE, "%d\n", pfm_controls.flags); ++ ++ if (is_attr_name(attr, "arg_mem_max")) ++ return snprintf(buf, PAGE_SIZE, "%zu\n", pfm_controls.arg_mem_max); ++ ++ if (is_attr_name(attr, "syscall")) { ++ base = pfm_arch_get_base_syscall(); ++ return snprintf(buf, PAGE_SIZE, "%d\n", base); ++ } ++ ++ if (is_attr_name(attr, "sys_sessions_count")) ++ return pfm_sysfs_res_show(buf, PAGE_SIZE, 1); ++ ++ if (is_attr_name(attr, "smpl_buffer_mem_max")) ++ return snprintf(buf, PAGE_SIZE, "%zu\n", pfm_controls.smpl_buffer_mem_max); ++ ++ if (is_attr_name(attr, "smpl_buffer_mem_cur")) ++ return pfm_sysfs_res_show(buf, PAGE_SIZE, 2); ++ ++ if (is_attr_name(attr, "sys_group")) ++ return snprintf(buf, PAGE_SIZE, "%d\n", pfm_controls.sys_group); ++ ++ /* XXX: could be set to write-only */ ++ if (is_attr_name(attr, "reset_stats")) { ++ buf[0] = '0'; ++ buf[1] = '\0'; ++ return strnlen(buf, PAGE_SIZE); ++ } ++ return 0; ++} ++ ++static ssize_t pfm_controls_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int i; ++ size_t d; ++ ++ if (sscanf(buf, "%zu", &d) != 1) ++ goto skip; ++ ++ if (is_attr_name(attr, "debug")) ++ pfm_controls.debug = d; ++ ++ if (is_attr_name(attr, "task_group")) ++ pfm_controls.task_group = d; ++ ++ if (is_attr_name(attr, "sys_group")) ++ pfm_controls.sys_group = d; ++ ++ if (is_attr_name(attr, "mode")) ++ pfm_controls.flags = d ? PFM_CTRL_FL_RW_EXPERT : 0; ++ ++ if (is_attr_name(attr, "arg_mem_max")) { ++ /* ++ * we impose a page as the minimum. ++ * ++ * This limit may be smaller than the stack buffer ++ * available and that is fine. ++ */ ++ if (d >= PAGE_SIZE) ++ pfm_controls.arg_mem_max = d; ++ } ++ if (is_attr_name(attr, "reset_stats")) { ++ for_each_online_cpu(i) { ++ pfm_reset_stats(i); ++ } ++ } ++ ++ if (is_attr_name(attr, "smpl_buffer_mem_max")) { ++ if (d >= PAGE_SIZE) ++ pfm_controls.smpl_buffer_mem_max = d; ++ } ++skip: ++ return count; ++} ++ ++/* ++ * /sys/kernel/perfmon attributes ++ */ ++static PFM_RO_ATTR(version, pfm_controls_show); ++static PFM_RO_ATTR(task_sessions_count, pfm_controls_show); ++static PFM_RO_ATTR(syscall, pfm_controls_show); ++static PFM_RO_ATTR(sys_sessions_count, pfm_controls_show); ++static PFM_RO_ATTR(smpl_buffer_mem_cur, pfm_controls_show); ++ ++static PFM_RW_ATTR(debug, pfm_controls_show, pfm_controls_store); ++static PFM_RW_ATTR(task_group, pfm_controls_show, pfm_controls_store); ++static PFM_RW_ATTR(mode, pfm_controls_show, pfm_controls_store); ++static PFM_RW_ATTR(sys_group, pfm_controls_show, pfm_controls_store); ++static PFM_RW_ATTR(arg_mem_max, pfm_controls_show, pfm_controls_store); ++static PFM_RW_ATTR(smpl_buffer_mem_max, pfm_controls_show, pfm_controls_store); ++static PFM_RW_ATTR(reset_stats, pfm_controls_show, pfm_controls_store); ++ ++static struct attribute *pfm_kernel_attrs[] = { ++ &attr_version.attr, ++ &attr_syscall.attr, ++ &attr_task_sessions_count.attr, ++ &attr_sys_sessions_count.attr, ++ &attr_smpl_buffer_mem_cur.attr, ++ &attr_debug.attr, ++ &attr_reset_stats.attr, ++ &attr_sys_group.attr, ++ &attr_task_group.attr, ++ &attr_mode.attr, ++ &attr_smpl_buffer_mem_max.attr, ++ &attr_arg_mem_max.attr, ++ NULL ++}; ++ ++static struct attribute_group pfm_kernel_attr_group = { ++ .attrs = pfm_kernel_attrs, ++}; ++ ++/* ++ * per-reg attributes ++ */ ++static ssize_t pfm_reg_show(void *data, struct pfm_attribute *attr, char *buf) ++{ ++ struct pfm_regmap_desc *reg; ++ int w; ++ ++ reg = data; ++ ++ if (is_attr_name(attr, "name")) ++ return snprintf(buf, PAGE_SIZE, "%s\n", reg->desc); ++ ++ if (is_attr_name(attr, "dfl_val")) ++ return snprintf(buf, PAGE_SIZE, "0x%llx\n", ++ (unsigned long long)reg->dfl_val); ++ ++ if (is_attr_name(attr, "width")) { ++ w = (reg->type & PFM_REG_C64) ? ++ pfm_pmu_conf->counter_width : 64; ++ return snprintf(buf, PAGE_SIZE, "%d\n", w); ++ } ++ ++ if (is_attr_name(attr, "rsvd_msk")) ++ return snprintf(buf, PAGE_SIZE, "0x%llx\n", ++ (unsigned long long)reg->rsvd_msk); ++ ++ if (is_attr_name(attr, "addr")) ++ return snprintf(buf, PAGE_SIZE, "0x%lx\n", reg->hw_addr); ++ ++ return 0; ++} ++ ++static PFM_ROS_ATTR(name, pfm_reg_show); ++static PFM_ROS_ATTR(dfl_val, pfm_reg_show); ++static PFM_ROS_ATTR(rsvd_msk, pfm_reg_show); ++static PFM_ROS_ATTR(width, pfm_reg_show); ++static PFM_ROS_ATTR(addr, pfm_reg_show); ++ ++static struct attribute *pfm_reg_attrs[] = { ++ &attr_name.attr, ++ &attr_dfl_val.attr, ++ &attr_rsvd_msk.attr, ++ &attr_width.attr, ++ &attr_addr.attr, ++ NULL ++}; ++ ++static struct attribute_group pfm_reg_attr_group = { ++ .attrs = pfm_reg_attrs, ++}; ++ ++static ssize_t pfm_pmu_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ if (is_attr_name(attr, "model")) ++ return snprintf(buf, PAGE_SIZE, "%s\n", pfm_pmu_conf->pmu_name); ++ return 0; ++} ++static PFM_RO_ATTR(model, pfm_pmu_show); ++ ++static struct attribute *pfm_pmu_desc_attrs[] = { ++ &attr_model.attr, ++ NULL ++}; ++ ++static struct attribute_group pfm_pmu_desc_attr_group = { ++ .attrs = pfm_pmu_desc_attrs, ++}; ++ ++static int pfm_sysfs_add_pmu_regs(struct pfm_pmu_config *pmu) ++{ ++ struct pfm_regmap_desc *reg; ++ unsigned int i, k; ++ int ret; ++ ++ reg = pmu->pmc_desc; ++ for (i = 0; i < pmu->num_pmc_entries; i++, reg++) { ++ ++ if (!(reg->type & PFM_REG_I)) ++ continue; ++ ++ ret = kobject_init_and_add(®->kobj, &pfm_regs_ktype, ++ pfm_pmu_kobj, "pmc%u", i); ++ if (ret) ++ goto undo_pmcs; ++ ++ ret = sysfs_create_group(®->kobj, &pfm_reg_attr_group); ++ if (ret) { ++ kobject_del(®->kobj); ++ goto undo_pmcs; ++ } ++ } ++ ++ reg = pmu->pmd_desc; ++ for (i = 0; i < pmu->num_pmd_entries; i++, reg++) { ++ ++ if (!(reg->type & PFM_REG_I)) ++ continue; ++ ++ ret = kobject_init_and_add(®->kobj, &pfm_regs_ktype, ++ pfm_pmu_kobj, "pmd%u", i); ++ if (ret) ++ goto undo_pmds; ++ ++ ret = sysfs_create_group(®->kobj, &pfm_reg_attr_group); ++ if (ret) { ++ kobject_del(®->kobj); ++ goto undo_pmds; ++ } ++ } ++ return 0; ++undo_pmds: ++ reg = pmu->pmd_desc; ++ for (k = 0; k < i; k++, reg++) { ++ if (!(reg->type & PFM_REG_I)) ++ continue; ++ sysfs_remove_group(®->kobj, &pfm_reg_attr_group); ++ kobject_del(®->kobj); ++ } ++ i = pmu->num_pmc_entries; ++ /* fall through */ ++undo_pmcs: ++ reg = pmu->pmc_desc; ++ for (k = 0; k < i; k++, reg++) { ++ if (!(reg->type & PFM_REG_I)) ++ continue; ++ sysfs_remove_group(®->kobj, &pfm_reg_attr_group); ++ kobject_del(®->kobj); ++ } ++ return ret; ++} ++ ++static int pfm_sysfs_del_pmu_regs(struct pfm_pmu_config *pmu) ++{ ++ struct pfm_regmap_desc *reg; ++ unsigned int i; ++ ++ reg = pmu->pmc_desc; ++ for (i = 0; i < pmu->num_pmc_entries; i++, reg++) { ++ ++ if (!(reg->type & PFM_REG_I)) ++ continue; ++ ++ sysfs_remove_group(®->kobj, &pfm_reg_attr_group); ++ kobject_del(®->kobj); ++ } ++ ++ reg = pmu->pmd_desc; ++ for (i = 0; i < pmu->num_pmd_entries; i++, reg++) { ++ ++ if (!(reg->type & PFM_REG_I)) ++ continue; ++ ++ sysfs_remove_group(®->kobj, &pfm_reg_attr_group); ++ kobject_del(®->kobj); ++ } ++ return 0; ++} ++ ++/* ++ * when a PMU description module is inserted, we create ++ * a pmu_desc subdir in sysfs and we populate it with ++ * PMU specific information, such as register mappings ++ */ ++int pfm_sysfs_add_pmu(struct pfm_pmu_config *pmu) ++{ ++ int ret; ++ ++ pfm_pmu_kobj = kobject_create_and_add("pmu_desc", pfm_kernel_kobj); ++ if (!pfm_pmu_kobj) ++ return -ENOMEM; ++ ++ ret = sysfs_create_group(pfm_pmu_kobj, &pfm_pmu_desc_attr_group); ++ if (ret) { ++ /* will release pfm_pmu_kobj */ ++ kobject_put(pfm_pmu_kobj); ++ return ret; ++ } ++ ++ ret = pfm_sysfs_add_pmu_regs(pmu); ++ if (ret) { ++ sysfs_remove_group(pfm_pmu_kobj, &pfm_pmu_desc_attr_group); ++ /* will release pfm_pmu_kobj */ ++ kobject_put(pfm_pmu_kobj); ++ } else ++ kobject_uevent(pfm_pmu_kobj, KOBJ_ADD); ++ ++ return ret; ++} ++ ++/* ++ * when a PMU description module is removed, we also remove ++ * all its information from sysfs, i.e., the pmu_desc subdir ++ * disappears ++ */ ++int pfm_sysfs_remove_pmu(struct pfm_pmu_config *pmu) ++{ ++ pfm_sysfs_del_pmu_regs(pmu); ++ sysfs_remove_group(pfm_pmu_kobj, &pfm_pmu_desc_attr_group); ++ kobject_uevent(pfm_pmu_kobj, KOBJ_REMOVE); ++ kobject_put(pfm_pmu_kobj); ++ pfm_pmu_kobj = NULL; ++ return 0; ++} ++ ++static ssize_t pfm_fmt_show(void *data, struct pfm_attribute *attr, char *buf) ++{ ++ struct pfm_smpl_fmt *fmt = data; ++ ++ if (is_attr_name(attr, "version")) ++ return snprintf(buf, PAGE_SIZE, "%u.%u\n", ++ fmt->fmt_version >> 16 & 0xffff, ++ fmt->fmt_version & 0xffff); ++ return 0; ++} ++ ++/* ++ * do not use predefined macros because of name conflict ++ * with /sys/kernel/perfmon/version ++ */ ++struct pfm_attribute attr_fmt_version = { ++ .attr = { .name = "version", .mode = 0444 }, ++ .show = pfm_fmt_show, ++}; ++ ++static struct attribute *pfm_fmt_attrs[] = { ++ &attr_fmt_version.attr, ++ NULL ++}; ++ ++static struct attribute_group pfm_fmt_attr_group = { ++ .attrs = pfm_fmt_attrs, ++}; ++ ++/* ++ * when a sampling format module is inserted, we populate ++ * sysfs with some information ++ */ ++int pfm_sysfs_add_fmt(struct pfm_smpl_fmt *fmt) ++{ ++ int ret; ++ ++ ret = kobject_init_and_add(&fmt->kobj, &pfm_fmt_ktype, ++ pfm_fmt_kobj, fmt->fmt_name); ++ if (ret) ++ return ret; ++ ++ ret = sysfs_create_group(&fmt->kobj, &pfm_fmt_attr_group); ++ if (ret) ++ kobject_del(&fmt->kobj); ++ else ++ kobject_uevent(&fmt->kobj, KOBJ_ADD); ++ ++ return ret; ++} ++ ++/* ++ * when a sampling format module is removed, its information ++ * must also be removed from sysfs ++ */ ++void pfm_sysfs_remove_fmt(struct pfm_smpl_fmt *fmt) ++{ ++ sysfs_remove_group(&fmt->kobj, &pfm_fmt_attr_group); ++ kobject_uevent(&fmt->kobj, KOBJ_REMOVE); ++ kobject_del(&fmt->kobj); ++} ++ ++int __init pfm_init_sysfs(void) ++{ ++ int ret; ++ ++ pfm_kernel_kobj = kobject_create_and_add("perfmon", kernel_kobj); ++ if (!pfm_kernel_kobj) { ++ PFM_ERR("cannot add kernel object: /sys/kernel/perfmon"); ++ return -ENOMEM; ++ } ++ ++ ret = sysfs_create_group(pfm_kernel_kobj, &pfm_kernel_attr_group); ++ if (ret) { ++ kobject_put(pfm_kernel_kobj); ++ return ret; ++ } ++ ++ pfm_fmt_kobj = kobject_create_and_add("formats", pfm_kernel_kobj); ++ if (ret) { ++ PFM_ERR("cannot add fmt object: %d", ret); ++ goto error_fmt; ++ } ++ if (pfm_pmu_conf) ++ pfm_sysfs_add_pmu(pfm_pmu_conf); ++ ++ pfm_sysfs_builtin_fmt_add(); ++ ++ return 0; ++ ++error_fmt: ++ kobject_del(pfm_kernel_kobj); ++ return ret; ++} diff --git a/src/patches/suse-2.6.27.31/patches.suse/ppc-no-LDFLAGS_MODULE.patch b/src/patches/suse-2.6.27.31/patches.suse/ppc-no-LDFLAGS_MODULE.patch new file mode 100644 index 000000000..50358de95 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ppc-no-LDFLAGS_MODULE.patch @@ -0,0 +1,32 @@ +Subject: arch/powerpc/lib/crtsavres.o is not available when linking external modules +From: olh@suse.de +Patch-mainline: never + +Maybe it helps. + +--- + arch/powerpc/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -83,15 +83,17 @@ ifeq ($(GCC_BROKEN_VEC),y) + KBUILD_CFLAGS += $(call cc-option,-mcpu=970) + else + KBUILD_CFLAGS += $(call cc-option,-mcpu=power4) ++# GCC_BROKEN_VEC + endif + else + KBUILD_CFLAGS += $(call cc-option,-mcpu=power4) ++# CONFIG_ALTIVEC + endif + else + KBUILD_CFLAGS += $(call cc-option,-mtune=power4) ++# CONFIG_POWER4_ONLY + endif +-else +-LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o ++# CONFIG_PPC64 + endif + + ifeq ($(CONFIG_TUNE_CELL),y) diff --git a/src/patches/suse-2.6.27.31/patches.suse/ppc-powerbook-usb-fn-key-default.patch b/src/patches/suse-2.6.27.31/patches.suse/ppc-powerbook-usb-fn-key-default.patch new file mode 100644 index 000000000..f8ae63471 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/ppc-powerbook-usb-fn-key-default.patch @@ -0,0 +1,31 @@ +Subject: Default value of usbhid.pb_fnmode module parameter +From: olh@suse.de +References: 220266 + + The kernel default value for usbhid.pb_fnmode is 1, which means that pressing + the Fn keys (F1..F10) without the fn key triggers the special functions + decrease/increase brightness, mute, decrease/increase volume, etc., which is + the default under MacOS. + + At least under 10.2 Beta2, only the volume related special functions work at + all. In addition, Ctrl-Alt-Fx is used to switch between consoles. with + pb_fnmode==1, the fn key needs to be pressed in addition. + + Therefore, pb_fnmode==2 (F1..F10 by default trigger Fn rather than the special + functions) makes more sense under Linux. + + + drivers/hid/hid-input.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -32,7 +32,7 @@ + #include + #include + +-static int hid_apple_fnmode = 1; ++static int hid_apple_fnmode = 2; + module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644); + MODULE_PARM_DESC(pb_fnmode, + "Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Add-callbacks-for-allocating-and-destroying-d.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Add-callbacks-for-allocating-and-destroying-d.patch new file mode 100644 index 000000000..6d5e1a8e4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Add-callbacks-for-allocating-and-destroying-d.patch @@ -0,0 +1,90 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 01/28] quota: Add callbacks for allocating and destroying dquot structures +Patch-mainline: 2.6.29? + +Some filesystems would like to keep private information together with each +dquot. Add callbacks alloc_dquot and destroy_dquot allowing filesystem to +allocate larger dquots from their private slab in a similar fashion we +currently allocate inodes. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 19 +++++++++++++++---- + include/linux/quota.h | 2 ++ + 2 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index 8ec4d6c..e1dac3e 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -417,6 +417,14 @@ out_dqlock: + return ret; + } + ++static void destroy_dquot(struct dquot *dquot) ++{ ++ if (dquot->dq_sb->dq_op->destroy_dquot) ++ dquot->dq_sb->dq_op->destroy_dquot(dquot); ++ else ++ kmem_cache_free(dquot_cachep, dquot); ++} ++ + /* Invalidate all dquots on the list. Note that this function is called after + * quota is disabled and pointers from inodes removed so there cannot be new + * quota users. There can still be some users of quotas due to inodes being +@@ -465,7 +473,7 @@ restart: + remove_dquot_hash(dquot); + remove_free_dquot(dquot); + remove_inuse(dquot); +- kmem_cache_free(dquot_cachep, dquot); ++ destroy_dquot(dquot); + } + spin_unlock(&dq_list_lock); + } +@@ -529,7 +537,7 @@ static void prune_dqcache(int count) + remove_dquot_hash(dquot); + remove_free_dquot(dquot); + remove_inuse(dquot); +- kmem_cache_free(dquot_cachep, dquot); ++ destroy_dquot(dquot); + count--; + head = free_dquots.prev; + } +@@ -631,7 +639,10 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) + { + struct dquot *dquot; + +- dquot = kmem_cache_zalloc(dquot_cachep, GFP_NOFS); ++ if (sb->dq_op->alloc_dquot) ++ dquot = sb->dq_op->alloc_dquot(sb, type); ++ else ++ dquot = kmem_cache_zalloc(dquot_cachep, GFP_NOFS); + if(!dquot) + return NODQUOT; + +@@ -684,7 +695,7 @@ we_slept: + dqstats.lookups++; + spin_unlock(&dq_list_lock); + if (empty) +- kmem_cache_free(dquot_cachep, empty); ++ destroy_dquot(empty); + } + /* Wait for dq_lock - after this we know that either dquot_release() is already + * finished or it will be canceled due to dq_count > 1 test */ +diff --git a/include/linux/quota.h b/include/linux/quota.h +index 376a050..eeae7a9 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -294,6 +294,8 @@ struct dquot_operations { + int (*free_inode) (const struct inode *, unsigned long); + int (*transfer) (struct inode *, struct iattr *); + int (*write_dquot) (struct dquot *); /* Ordinary dquot write */ ++ struct dquot *(*alloc_dquot)(struct super_block *, int); /* Allocate memory for new dquot (can be NULL if no special entries dquot are needed) */ ++ void (*destroy_dquot)(struct dquot *); /* Free memory for dquot (can be NULL if alloc_dquot is NULL) */ + int (*acquire_dquot) (struct dquot *); /* Quota is going to be created on disk */ + int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */ + int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Add-helpers-to-allow-ocfs2-specific-quota-ini.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Add-helpers-to-allow-ocfs2-specific-quota-ini.patch new file mode 100644 index 000000000..e09251797 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Add-helpers-to-allow-ocfs2-specific-quota-ini.patch @@ -0,0 +1,125 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 16/28] quota: Add helpers to allow ocfs2 specific quota initialization, freeing and recovery +Patch-mainline: 2.6.29? + +OCFS2 needs to peek whether quota structure is already in memory so +that it can avoid expensive cluster locking in that case. Similarly +when freeing dquots, it checks whether it is the last quota structure +user or not. Finally, it needs to get reference to dquot structure for +specified id and quota type when recovering quota file after crash. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 38 ++++++++++++++++++++++++++++++++------ + include/linux/quotaops.h | 4 ++++ + 2 files changed, 36 insertions(+), 6 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index 3fde18b..9fb1d71 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -213,8 +213,6 @@ static struct hlist_head *dquot_hash; + + struct dqstats dqstats; + +-static void dqput(struct dquot *dquot); +- + static inline unsigned int + hashfn(const struct super_block *sb, unsigned int id, int type) + { +@@ -568,7 +566,7 @@ static struct shrinker dqcache_shrinker = { + * NOTE: If you change this function please check whether dqput_blocks() works right... + * MUST be called with either dqptr_sem or dqonoff_mutex held + */ +-static void dqput(struct dquot *dquot) ++void dqput(struct dquot *dquot) + { + int ret; + +@@ -660,10 +658,28 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) + } + + /* ++ * Check whether dquot is in memory. ++ * MUST be called with either dqptr_sem or dqonoff_mutex held ++ */ ++int dquot_is_cached(struct super_block *sb, unsigned int id, int type) ++{ ++ unsigned int hashent = hashfn(sb, id, type); ++ int ret = 0; ++ ++ if (!sb_has_quota_active(sb, type)) ++ return 0; ++ spin_lock(&dq_list_lock); ++ if (find_dquot(hashent, sb, id, type) != NODQUOT) ++ ret = 1; ++ spin_unlock(&dq_list_lock); ++ return ret; ++} ++ ++/* + * Get reference to dquot + * MUST be called with either dqptr_sem or dqonoff_mutex held + */ +-static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) ++struct dquot *dqget(struct super_block *sb, unsigned int id, int type) + { + unsigned int hashent = hashfn(sb, id, type); + struct dquot *dquot, *empty = NODQUOT; +@@ -1184,17 +1200,23 @@ out_err: + * Release all quotas referenced by inode + * Transaction must be started at an entry + */ +-int dquot_drop(struct inode *inode) ++int dquot_drop_locked(struct inode *inode) + { + int cnt; + +- down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (inode->i_dquot[cnt] != NODQUOT) { + dqput(inode->i_dquot[cnt]); + inode->i_dquot[cnt] = NODQUOT; + } + } ++ return 0; ++} ++ ++int dquot_drop(struct inode *inode) ++{ ++ down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); ++ dquot_drop_locked(inode); + up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + return 0; + } +@@ -2306,7 +2328,11 @@ EXPORT_SYMBOL(dquot_release); + EXPORT_SYMBOL(dquot_mark_dquot_dirty); + EXPORT_SYMBOL(dquot_initialize); + EXPORT_SYMBOL(dquot_drop); ++EXPORT_SYMBOL(dquot_drop_locked); + EXPORT_SYMBOL(vfs_dq_drop); ++EXPORT_SYMBOL(dqget); ++EXPORT_SYMBOL(dqput); ++EXPORT_SYMBOL(dquot_is_cached); + EXPORT_SYMBOL(dquot_alloc_space); + EXPORT_SYMBOL(dquot_alloc_inode); + EXPORT_SYMBOL(dquot_free_space); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 94f00ec..1f990f2 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -27,6 +27,10 @@ void sync_dquots(struct super_block *sb, int type); + + int dquot_initialize(struct inode *inode, int type); + int dquot_drop(struct inode *inode); ++int dquot_drop_locked(struct inode *inode); ++struct dquot *dqget(struct super_block *sb, unsigned int id, int type); ++void dqput(struct dquot *dquot); ++int dquot_is_cached(struct super_block *sb, unsigned int id, int type); + + int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); + int dquot_alloc_inode(const struct inode *inode, qsize_t number); +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Allow-negative-usage-of-space-and-inodes.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Allow-negative-usage-of-space-and-inodes.patch new file mode 100644 index 000000000..38f976684 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Allow-negative-usage-of-space-and-inodes.patch @@ -0,0 +1,65 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 14/28] quota: Allow negative usage of space and inodes +Patch-mainline: 2.6.29? + +For clustered filesystems, it can happen that space / inode usage goes +negative temporarily (because some node is allocating another node +is freeing and they are not completely in sync). So let quota code +allow this and change qsize_t so a signed type so that we don't +underflow the variables. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 6 ++++-- + include/linux/quota.h | 3 ++- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index 904bd67..f4258fe 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -845,7 +845,8 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) + + static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) + { +- if (dquot->dq_dqb.dqb_curinodes > number) ++ if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || ++ dquot->dq_dqb.dqb_curinodes >= number) + dquot->dq_dqb.dqb_curinodes -= number; + else + dquot->dq_dqb.dqb_curinodes = 0; +@@ -856,7 +857,8 @@ static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) + + static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) + { +- if (dquot->dq_dqb.dqb_curspace > number) ++ if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NEGATIVE_USAGE || ++ dquot->dq_dqb.dqb_curspace >= number) + dquot->dq_dqb.dqb_curspace -= number; + else + dquot->dq_dqb.dqb_curspace = 0; +diff --git a/include/linux/quota.h b/include/linux/quota.h +index e05c30d..0ee2a55 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -170,7 +170,7 @@ enum { + #include + + typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ +-typedef __u64 qsize_t; /* Type in which we store sizes */ ++typedef __s64 qsize_t; /* Type in which we store sizes */ + + extern spinlock_t dq_data_lock; + +@@ -338,6 +338,7 @@ enum { + * responsible for setting + * S_NOQUOTA, S_NOATIME flags + */ ++#define DQUOT_NEGATIVE_USAGE (1 << 7) /* Allow negative quota usage */ + + static inline unsigned int dquot_state_flag(unsigned int flags, int type) + { +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Allow-to-separately-enable-quota-accounting-a.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Allow-to-separately-enable-quota-accounting-a.patch new file mode 100644 index 000000000..c9291e824 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Allow-to-separately-enable-quota-accounting-a.patch @@ -0,0 +1,746 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 05/28] quota: Allow to separately enable quota accounting and enforcing limits +Patch-mainline: 2.6.29? + +Split DQUOT_USR_ENABLED (and DQUOT_GRP_ENABLED) into DQUOT_USR_USAGE_ENABLED +and DQUOT_USR_LIMITS_ENABLED. This way we are able to separately enable / +disable whether we should: +1) ignore quotas completely +2) just keep uptodate information about usage +3) actually enforce quota limits + +This is going to be useful when quota is treated as filesystem metadata - we +then want to keep quota information uptodate all the time and just enable / +disable limits enforcement. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 222 ++++++++++++++++++++++++++++----------------- + fs/quota.c | 8 +- + include/linux/quota.h | 30 ++++++- + include/linux/quotaops.h | 86 ++++++++++++++---- + 4 files changed, 234 insertions(+), 112 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index aea7bf9..bdfae7d 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -489,7 +489,7 @@ int vfs_quota_sync(struct super_block *sb, int type) + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (type != -1 && cnt != type) + continue; +- if (!sb_has_quota_enabled(sb, cnt)) ++ if (!sb_has_quota_active(sb, cnt)) + continue; + spin_lock(&dq_list_lock); + dirty = &dqopt->info[cnt].dqi_dirty_list; +@@ -514,8 +514,8 @@ int vfs_quota_sync(struct super_block *sb, int type) + } + + for (cnt = 0; cnt < MAXQUOTAS; cnt++) +- if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) +- && info_dirty(&dqopt->info[cnt])) ++ if ((cnt == type || type == -1) && sb_has_quota_active(sb, cnt) ++ && info_dirty(&dqopt->info[cnt])) + sb->dq_op->write_info(sb, cnt); + spin_lock(&dq_list_lock); + dqstats.syncs++; +@@ -594,7 +594,7 @@ we_slept: + /* We have more than one user... nothing to do */ + atomic_dec(&dquot->dq_count); + /* Releasing dquot during quotaoff phase? */ +- if (!sb_has_quota_enabled(dquot->dq_sb, dquot->dq_type) && ++ if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) && + atomic_read(&dquot->dq_count) == 1) + wake_up(&dquot->dq_wait_unused); + spin_unlock(&dq_list_lock); +@@ -668,7 +668,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) + unsigned int hashent = hashfn(sb, id, type); + struct dquot *dquot, *empty = NODQUOT; + +- if (!sb_has_quota_enabled(sb, type)) ++ if (!sb_has_quota_active(sb, type)) + return NODQUOT; + we_slept: + spin_lock(&dq_list_lock); +@@ -1041,7 +1041,8 @@ static inline char ignore_hardlimit(struct dquot *dquot) + static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) + { + *warntype = QUOTA_NL_NOWARN; +- if (test_bit(DQ_FAKE_B, &dquot->dq_flags)) ++ if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || ++ test_bit(DQ_FAKE_B, &dquot->dq_flags)) + return QUOTA_OK; + + if (dquot->dq_dqb.dqb_ihardlimit && +@@ -1073,7 +1074,8 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) + static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) + { + *warntype = QUOTA_NL_NOWARN; +- if (test_bit(DQ_FAKE_B, &dquot->dq_flags)) ++ if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || ++ test_bit(DQ_FAKE_B, &dquot->dq_flags)) + return QUOTA_OK; + + if (dquot->dq_dqb.dqb_bhardlimit && +@@ -1114,7 +1116,8 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war + static int info_idq_free(struct dquot *dquot, qsize_t inodes) + { + if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || +- dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) ++ dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit || ++ !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type)) + return QUOTA_NL_NOWARN; + + if (dquot->dq_dqb.dqb_curinodes - inodes <= dquot->dq_dqb.dqb_isoftlimit) +@@ -1508,7 +1511,7 @@ warn_put_all: + /* Wrapper for transferring ownership of an inode */ + int vfs_dq_transfer(struct inode *inode, struct iattr *iattr) + { +- if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) { ++ if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) { + vfs_dq_init(inode); + if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) + return 1; +@@ -1549,53 +1552,22 @@ struct dquot_operations dquot_operations = { + .write_info = dquot_commit_info + }; + +-static inline void set_enable_flags(struct quota_info *dqopt, int type) +-{ +- switch (type) { +- case USRQUOTA: +- dqopt->flags |= DQUOT_USR_ENABLED; +- dqopt->flags &= ~DQUOT_USR_SUSPENDED; +- break; +- case GRPQUOTA: +- dqopt->flags |= DQUOT_GRP_ENABLED; +- dqopt->flags &= ~DQUOT_GRP_SUSPENDED; +- break; +- } +-} +- +-static inline void reset_enable_flags(struct quota_info *dqopt, int type, +- int remount) +-{ +- switch (type) { +- case USRQUOTA: +- if (remount) +- dqopt->flags |= DQUOT_USR_SUSPENDED; +- else { +- dqopt->flags &= ~DQUOT_USR_ENABLED; +- dqopt->flags &= ~DQUOT_USR_SUSPENDED; +- } +- break; +- case GRPQUOTA: +- if (remount) +- dqopt->flags |= DQUOT_GRP_SUSPENDED; +- else { +- dqopt->flags &= ~DQUOT_GRP_ENABLED; +- dqopt->flags &= ~DQUOT_GRP_SUSPENDED; +- } +- break; +- } +-} +- +- + /* + * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) + */ +-int vfs_quota_off(struct super_block *sb, int type, int remount) ++int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) + { + int cnt, ret = 0; + struct quota_info *dqopt = sb_dqopt(sb); + struct inode *toputinode[MAXQUOTAS]; + ++ /* Cannot turn off usage accounting without turning off limits, or ++ * suspend quotas and simultaneously turn quotas off. */ ++ if ((flags & DQUOT_USAGE_ENABLED && !(flags & DQUOT_LIMITS_ENABLED)) ++ || (flags & DQUOT_SUSPENDED && flags & (DQUOT_LIMITS_ENABLED | ++ DQUOT_USAGE_ENABLED))) ++ return -EINVAL; ++ + /* We need to serialize quota_off() for device */ + mutex_lock(&dqopt->dqonoff_mutex); + +@@ -1604,7 +1576,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) + * sometimes we are called when fill_super() failed and calling + * sync_fs() in such cases does no good. + */ +- if (!sb_any_quota_enabled(sb) && !sb_any_quota_suspended(sb)) { ++ if (!sb_any_quota_loaded(sb)) { + mutex_unlock(&dqopt->dqonoff_mutex); + return 0; + } +@@ -1612,17 +1584,28 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) + toputinode[cnt] = NULL; + if (type != -1 && cnt != type) + continue; +- /* If we keep inodes of quota files after remount and quotaoff +- * is called, drop kept inodes. */ +- if (!remount && sb_has_quota_suspended(sb, cnt)) { +- iput(dqopt->files[cnt]); +- dqopt->files[cnt] = NULL; +- reset_enable_flags(dqopt, cnt, 0); ++ if (!sb_has_quota_loaded(sb, cnt)) + continue; ++ ++ if (flags & DQUOT_SUSPENDED) { ++ dqopt->flags |= ++ dquot_state_flag(DQUOT_SUSPENDED, cnt); ++ } else { ++ dqopt->flags &= ~dquot_state_flag(flags, cnt); ++ /* Turning off suspended quotas? */ ++ if (!sb_has_quota_loaded(sb, cnt) && ++ sb_has_quota_suspended(sb, cnt)) { ++ dqopt->flags &= ~dquot_state_flag( ++ DQUOT_SUSPENDED, cnt); ++ iput(dqopt->files[cnt]); ++ dqopt->files[cnt] = NULL; ++ continue; ++ } + } +- if (!sb_has_quota_enabled(sb, cnt)) ++ ++ /* We still have to keep quota loaded? */ ++ if (sb_has_quota_loaded(sb, cnt) && !(flags & DQUOT_SUSPENDED)) + continue; +- reset_enable_flags(dqopt, cnt, remount); + + /* Note: these are blocking operations */ + drop_dquot_ref(sb, cnt); +@@ -1638,7 +1621,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) + put_quota_format(dqopt->info[cnt].dqi_format); + + toputinode[cnt] = dqopt->files[cnt]; +- if (!remount) ++ if (!sb_has_quota_loaded(sb, cnt)) + dqopt->files[cnt] = NULL; + dqopt->info[cnt].dqi_flags = 0; + dqopt->info[cnt].dqi_igrace = 0; +@@ -1661,7 +1644,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) + mutex_lock(&dqopt->dqonoff_mutex); + /* If quota was reenabled in the meantime, we have + * nothing to do */ +- if (!sb_has_quota_enabled(sb, cnt)) { ++ if (!sb_has_quota_loaded(sb, cnt)) { + mutex_lock_nested(&toputinode[cnt]->i_mutex, I_MUTEX_QUOTA); + toputinode[cnt]->i_flags &= ~(S_IMMUTABLE | + S_NOATIME | S_NOQUOTA); +@@ -1671,10 +1654,13 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) + } + mutex_unlock(&dqopt->dqonoff_mutex); + /* On remount RO, we keep the inode pointer so that we +- * can reenable quota on the subsequent remount RW. +- * But we have better not keep inode pointer when there +- * is pending delete on the quota file... */ +- if (!remount) ++ * can reenable quota on the subsequent remount RW. We ++ * have to check 'flags' variable and not use sb_has_ ++ * function because another quotaon / quotaoff could ++ * change global state before we got here. We refuse ++ * to suspend quotas when there is pending delete on ++ * the quota file... */ ++ if (!(flags & DQUOT_SUSPENDED)) + iput(toputinode[cnt]); + else if (!toputinode[cnt]->i_nlink) + ret = -EBUSY; +@@ -1684,12 +1670,22 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) + return ret; + } + ++int vfs_quota_off(struct super_block *sb, int type, int remount) ++{ ++ return vfs_quota_disable(sb, type, remount ? DQUOT_SUSPENDED : ++ (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED)); ++} ++ + /* + * Turn quotas on on a device + */ + +-/* Helper function when we already have the inode */ +-static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) ++/* ++ * Helper function to turn quotas on when we already have the inode of ++ * quota file and no quota information is loaded. ++ */ ++static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, ++ unsigned int flags) + { + struct quota_format_type *fmt = find_quota_format(format_id); + struct super_block *sb = inode->i_sb; +@@ -1711,6 +1707,11 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) + error = -EINVAL; + goto out_fmt; + } ++ /* Usage always has to be set... */ ++ if (!(flags & DQUOT_USAGE_ENABLED)) { ++ error = -EINVAL; ++ goto out_fmt; ++ } + + /* As we bypass the pagecache we must now flush the inode so that + * we see all the changes from userspace... */ +@@ -1719,8 +1720,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) + invalidate_bdev(sb->s_bdev); + mutex_lock(&inode->i_mutex); + mutex_lock(&dqopt->dqonoff_mutex); +- if (sb_has_quota_enabled(sb, type) || +- sb_has_quota_suspended(sb, type)) { ++ if (sb_has_quota_loaded(sb, type)) { + error = -EBUSY; + goto out_lock; + } +@@ -1752,7 +1752,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) + } + mutex_unlock(&dqopt->dqio_mutex); + mutex_unlock(&inode->i_mutex); +- set_enable_flags(dqopt, type); ++ dqopt->flags |= dquot_state_flag(flags, type); + + add_dquot_ref(sb, type); + mutex_unlock(&dqopt->dqonoff_mutex); +@@ -1785,20 +1785,23 @@ static int vfs_quota_on_remount(struct super_block *sb, int type) + struct quota_info *dqopt = sb_dqopt(sb); + struct inode *inode; + int ret; ++ unsigned int flags; + + mutex_lock(&dqopt->dqonoff_mutex); + if (!sb_has_quota_suspended(sb, type)) { + mutex_unlock(&dqopt->dqonoff_mutex); + return 0; + } +- BUG_ON(sb_has_quota_enabled(sb, type)); +- + inode = dqopt->files[type]; + dqopt->files[type] = NULL; +- reset_enable_flags(dqopt, type, 0); ++ flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED | ++ DQUOT_LIMITS_ENABLED, type); ++ dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, type); + mutex_unlock(&dqopt->dqonoff_mutex); + +- ret = vfs_quota_on_inode(inode, type, dqopt->info[type].dqi_fmt_id); ++ flags = dquot_generic_flag(flags, type); ++ ret = vfs_load_quota_inode(inode, type, dqopt->info[type].dqi_fmt_id, ++ flags); + iput(inode); + + return ret; +@@ -1814,12 +1817,12 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id, + if (path->mnt->mnt_sb != sb) + error = -EXDEV; + else +- error = vfs_quota_on_inode(path->dentry->d_inode, type, +- format_id); ++ error = vfs_load_quota_inode(path->dentry->d_inode, type, ++ format_id, DQUOT_USAGE_ENABLED | ++ DQUOT_LIMITS_ENABLED); + return error; + } + +-/* Actual function called from quotactl() */ + int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, + int remount) + { +@@ -1838,6 +1841,50 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, + } + + /* ++ * More powerful function for turning on quotas allowing setting ++ * of individual quota flags ++ */ ++int vfs_quota_enable(struct inode *inode, int type, int format_id, ++ unsigned int flags) ++{ ++ int ret = 0; ++ struct super_block *sb = inode->i_sb; ++ struct quota_info *dqopt = sb_dqopt(sb); ++ ++ /* Just unsuspend quotas? */ ++ if (flags & DQUOT_SUSPENDED) ++ return vfs_quota_on_remount(sb, type); ++ if (!flags) ++ return 0; ++ /* Just updating flags needed? */ ++ if (sb_has_quota_loaded(sb, type)) { ++ mutex_lock(&dqopt->dqonoff_mutex); ++ /* Now do a reliable test... */ ++ if (!sb_has_quota_loaded(sb, type)) { ++ mutex_unlock(&dqopt->dqonoff_mutex); ++ goto load_quota; ++ } ++ if (flags & DQUOT_USAGE_ENABLED && ++ sb_has_quota_usage_enabled(sb, type)) { ++ ret = -EBUSY; ++ goto out_lock; ++ } ++ if (flags & DQUOT_LIMITS_ENABLED && ++ sb_has_quota_limits_enabled(sb, type)) { ++ ret = -EBUSY; ++ goto out_lock; ++ } ++ sb_dqopt(sb)->flags |= dquot_state_flag(flags, type); ++out_lock: ++ mutex_unlock(&dqopt->dqonoff_mutex); ++ return ret; ++ } ++ ++load_quota: ++ return vfs_load_quota_inode(inode, type, format_id, flags); ++} ++ ++/* + * This function is used when filesystem needs to initialize quotas + * during mount time. + */ +@@ -1858,7 +1905,8 @@ int vfs_quota_on_mount(struct super_block *sb, char *qf_name, + + error = security_quota_on(dentry); + if (!error) +- error = vfs_quota_on_inode(dentry->d_inode, type, format_id); ++ error = vfs_load_quota_inode(dentry->d_inode, type, format_id, ++ DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); + + out: + dput(dentry); +@@ -1995,12 +2043,14 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d + int rc; + + mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); +- if (!(dquot = dqget(sb, id, type))) { +- mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); +- return -ESRCH; ++ dquot = dqget(sb, id, type); ++ if (!dquot) { ++ rc = -ESRCH; ++ goto out; + } + rc = do_set_dqblk(dquot, di); + dqput(dquot); ++out: + mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); + return rc; + } +@@ -2011,7 +2061,7 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) + struct mem_dqinfo *mi; + + mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); +- if (!sb_has_quota_enabled(sb, type)) { ++ if (!sb_has_quota_active(sb, type)) { + mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); + return -ESRCH; + } +@@ -2030,11 +2080,12 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) + int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) + { + struct mem_dqinfo *mi; ++ int err = 0; + + mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); +- if (!sb_has_quota_enabled(sb, type)) { +- mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); +- return -ESRCH; ++ if (!sb_has_quota_active(sb, type)) { ++ err = -ESRCH; ++ goto out; + } + mi = sb_dqopt(sb)->info + type; + spin_lock(&dq_data_lock); +@@ -2048,8 +2099,9 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) + mark_info_dirty(sb, type); + /* Force write to disk */ + sb->dq_op->write_info(sb, type); ++out: + mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); +- return 0; ++ return err; + } + + struct quotactl_ops vfs_quotactl_ops = { +@@ -2211,9 +2263,11 @@ EXPORT_SYMBOL(register_quota_format); + EXPORT_SYMBOL(unregister_quota_format); + EXPORT_SYMBOL(dqstats); + EXPORT_SYMBOL(dq_data_lock); ++EXPORT_SYMBOL(vfs_quota_enable); + EXPORT_SYMBOL(vfs_quota_on); + EXPORT_SYMBOL(vfs_quota_on_path); + EXPORT_SYMBOL(vfs_quota_on_mount); ++EXPORT_SYMBOL(vfs_quota_disable); + EXPORT_SYMBOL(vfs_quota_off); + EXPORT_SYMBOL(vfs_quota_sync); + EXPORT_SYMBOL(vfs_get_dqinfo); +diff --git a/fs/quota.c b/fs/quota.c +index 7f4386e..a8026f1 100644 +--- a/fs/quota.c ++++ b/fs/quota.c +@@ -73,7 +73,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid + case Q_SETQUOTA: + case Q_GETQUOTA: + /* This is just informative test so we are satisfied without a lock */ +- if (!sb_has_quota_enabled(sb, type)) ++ if (!sb_has_quota_active(sb, type)) + return -ESRCH; + } + +@@ -175,7 +175,7 @@ static void quota_sync_sb(struct super_block *sb, int type) + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (type != -1 && cnt != type) + continue; +- if (!sb_has_quota_enabled(sb, cnt)) ++ if (!sb_has_quota_active(sb, cnt)) + continue; + mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA); + truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); +@@ -201,7 +201,7 @@ restart: + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (type != -1 && type != cnt) + continue; +- if (!sb_has_quota_enabled(sb, cnt)) ++ if (!sb_has_quota_active(sb, cnt)) + continue; + if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && + list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) +@@ -245,7 +245,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void + __u32 fmt; + + down_read(&sb_dqopt(sb)->dqptr_sem); +- if (!sb_has_quota_enabled(sb, type)) { ++ if (!sb_has_quota_active(sb, type)) { + up_read(&sb_dqopt(sb)->dqptr_sem); + return -ESRCH; + } +diff --git a/include/linux/quota.h b/include/linux/quota.h +index 5167786..0e4b550 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -320,12 +320,34 @@ struct quota_format_type { + struct quota_format_type *qf_next; + }; + +-#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ +-#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ +-#define DQUOT_USR_SUSPENDED 0x04 /* User diskquotas are off, but ++/* Quota state flags - they actually come in two flavors - for users and groups */ ++enum { ++ _DQUOT_USAGE_ENABLED = 0, /* Track disk usage for users */ ++ _DQUOT_LIMITS_ENABLED, /* Enforce quota limits for users */ ++ _DQUOT_SUSPENDED, /* User diskquotas are off, but + * we have necessary info in + * memory to turn them on */ +-#define DQUOT_GRP_SUSPENDED 0x08 /* The same for group quotas */ ++ _DQUOT_STATE_FLAGS ++}; ++#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED) ++#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED) ++#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED) ++#define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ ++ DQUOT_SUSPENDED) ++ ++static inline unsigned int dquot_state_flag(unsigned int flags, int type) ++{ ++ if (type == USRQUOTA) ++ return flags; ++ return flags << _DQUOT_STATE_FLAGS; ++} ++ ++static inline unsigned int dquot_generic_flag(unsigned int flags, int type) ++{ ++ if (type == USRQUOTA) ++ return flags; ++ return flags >> _DQUOT_STATE_FLAGS; ++} + + struct quota_info { + unsigned int flags; /* Flags for diskquotas on this device */ +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 12363cc..f7dcc30 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -43,11 +43,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot); + + int vfs_quota_on(struct super_block *sb, int type, int format_id, + char *path, int remount); ++int vfs_quota_enable(struct inode *inode, int type, int format_id, ++ unsigned int flags); + int vfs_quota_on_path(struct super_block *sb, int type, int format_id, + struct path *path); + int vfs_quota_on_mount(struct super_block *sb, char *qf_name, + int format_id, int type); + int vfs_quota_off(struct super_block *sb, int type, int remount); ++int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags); + int vfs_quota_sync(struct super_block *sb, int type); + int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); + int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); +@@ -67,26 +70,22 @@ static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type) + * Functions for checking status of quota + */ + +-static inline int sb_has_quota_enabled(struct super_block *sb, int type) ++static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type) + { +- if (type == USRQUOTA) +- return (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) +- && !(sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED); +- return (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED) +- && !(sb_dqopt(sb)->flags & DQUOT_GROUP_SUSPENDED); ++ return sb_dqopt(sb)->flags & ++ dquot_state_flag(DQUOT_USAGE_ENABLED, type); + } + +-static inline int sb_any_quota_enabled(struct super_block *sb) ++static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type) + { +- return sb_has_quota_enabled(sb, USRQUOTA) || +- sb_has_quota_enabled(sb, GRPQUOTA); ++ return sb_dqopt(sb)->flags & ++ dquot_state_flag(DQUOT_LIMITS_ENABLED, type); + } + + static inline int sb_has_quota_suspended(struct super_block *sb, int type) + { +- if (type == USRQUOTA) +- return sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED; +- return sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED; ++ return sb_dqopt(sb)->flags & ++ dquot_state_flag(DQUOT_SUSPENDED, type); + } + + static inline int sb_any_quota_suspended(struct super_block *sb) +@@ -95,6 +94,34 @@ static inline int sb_any_quota_suspended(struct super_block *sb) + sb_has_quota_suspended(sb, GRPQUOTA); + } + ++/* Does kernel know about any quota information for given sb + type? */ ++static inline int sb_has_quota_loaded(struct super_block *sb, int type) ++{ ++ /* Currently if anything is on, then quota usage is on as well */ ++ return sb_has_quota_usage_enabled(sb, type); ++} ++ ++static inline int sb_any_quota_loaded(struct super_block *sb) ++{ ++ return sb_has_quota_loaded(sb, USRQUOTA) || ++ sb_has_quota_loaded(sb, GRPQUOTA); ++} ++ ++static inline int sb_has_quota_active(struct super_block *sb, int type) ++{ ++ return sb_has_quota_loaded(sb, type) && ++ !sb_has_quota_suspended(sb, type); ++} ++ ++static inline int sb_any_quota_active(struct super_block *sb) ++{ ++ return sb_has_quota_active(sb, USRQUOTA) || ++ sb_has_quota_active(sb, GRPQUOTA); ++} ++ ++/* For backward compatibility until we remove all users */ ++#define sb_any_quota_enabled(sb) sb_any_quota_active(sb) ++ + /* + * Operations supported for diskquotas. + */ +@@ -109,7 +136,7 @@ extern struct quotactl_ops vfs_quotactl_ops; + static inline void vfs_dq_init(struct inode *inode) + { + BUG_ON(!inode->i_sb); +- if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) ++ if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) + inode->i_sb->dq_op->initialize(inode, -1); + } + +@@ -117,7 +144,7 @@ static inline void vfs_dq_init(struct inode *inode) + * a transaction (deadlocks possible otherwise) */ + static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr) + { +- if (sb_any_quota_enabled(inode->i_sb)) { ++ if (sb_any_quota_active(inode->i_sb)) { + /* Used space is updated in alloc_space() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) + return 1; +@@ -137,7 +164,7 @@ static inline int vfs_dq_prealloc_space(struct inode *inode, qsize_t nr) + + static inline int vfs_dq_alloc_space_nodirty(struct inode *inode, qsize_t nr) + { +- if (sb_any_quota_enabled(inode->i_sb)) { ++ if (sb_any_quota_active(inode->i_sb)) { + /* Used space is updated in alloc_space() */ + if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) + return 1; +@@ -157,7 +184,7 @@ static inline int vfs_dq_alloc_space(struct inode *inode, qsize_t nr) + + static inline int vfs_dq_alloc_inode(struct inode *inode) + { +- if (sb_any_quota_enabled(inode->i_sb)) { ++ if (sb_any_quota_active(inode->i_sb)) { + vfs_dq_init(inode); + if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) + return 1; +@@ -167,7 +194,7 @@ static inline int vfs_dq_alloc_inode(struct inode *inode) + + static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) + { +- if (sb_any_quota_enabled(inode->i_sb)) ++ if (sb_any_quota_active(inode->i_sb)) + inode->i_sb->dq_op->free_space(inode, nr); + else + inode_sub_bytes(inode, nr); +@@ -181,7 +208,7 @@ static inline void vfs_dq_free_space(struct inode *inode, qsize_t nr) + + static inline void vfs_dq_free_inode(struct inode *inode) + { +- if (sb_any_quota_enabled(inode->i_sb)) ++ if (sb_any_quota_active(inode->i_sb)) + inode->i_sb->dq_op->free_inode(inode, 1); + } + +@@ -202,12 +229,12 @@ static inline int vfs_dq_off(struct super_block *sb, int remount) + + #else + +-static inline int sb_has_quota_enabled(struct super_block *sb, int type) ++static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type) + { + return 0; + } + +-static inline int sb_any_quota_enabled(struct super_block *sb) ++static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type) + { + return 0; + } +@@ -222,6 +249,25 @@ static inline int sb_any_quota_suspended(struct super_block *sb) + return 0; + } + ++/* Does kernel know about any quota information for given sb + type? */ ++static inline int sb_has_quota_loaded(struct super_block *sb, int type) ++{ ++ return 0; ++} ++ ++static inline int sb_any_quota_loaded(struct super_block *sb) ++{ ++ return 0; ++} ++ ++static inline int sb_any_quota_active(struct super_block *sb) ++{ ++ return 0; ++} ++ ++/* For backward compatibility until we remove all users */ ++#define sb_any_quota_enabled(sb) sb_any_quota_active(sb) ++ + /* + * NO-OP when quota not configured. + */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Convert-union-in-mem_dqinfo-to-a-pointer.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Convert-union-in-mem_dqinfo-to-a-pointer.patch new file mode 100644 index 000000000..3bb1e026a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Convert-union-in-mem_dqinfo-to-a-pointer.patch @@ -0,0 +1,190 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 13/28] quota: Convert union in mem_dqinfo to a pointer +Patch-mainline: 2.6.29? + +Coming quota support for OCFS2 is going to need quite a bit +of additional per-sb quota information. Moreover having fs.h +include all the types needed for this structure would be a +pain in the a**. So remove the union from mem_dqinfo and add +a private pointer for filesystem's use. + +Signed-off-by: Jan Kara +--- + fs/quota_v2.c | 53 +++++++++++++++++++++++++++++---------------- + include/linux/dqblk_v1.h | 4 --- + include/linux/dqblk_v2.h | 4 --- + include/linux/quota.h | 5 +--- + 4 files changed, 35 insertions(+), 31 deletions(-) + +diff --git a/fs/quota_v2.c b/fs/quota_v2.c +index a87f102..a371919 100644 +--- a/fs/quota_v2.c ++++ b/fs/quota_v2.c +@@ -71,6 +71,7 @@ static int v2_read_file_info(struct super_block *sb, int type) + { + struct v2_disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct qtree_mem_dqinfo *qinfo; + ssize_t size; + + size = sb->s_op->quota_read(sb, type, (char *)&dinfo, +@@ -80,22 +81,29 @@ static int v2_read_file_info(struct super_block *sb, int type) + sb->s_id); + return -1; + } ++ info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS); ++ if (!info->dqi_priv) { ++ printk(KERN_WARNING "Not enough memory for quota information" ++ "structure.\n"); ++ return -1; ++ } ++ qinfo = info->dqi_priv; + /* limits are stored as unsigned 32-bit data */ + info->dqi_maxblimit = 0xffffffff; + info->dqi_maxilimit = 0xffffffff; + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); +- info->u.v2_i.i.dqi_sb = sb; +- info->u.v2_i.i.dqi_type = type; +- info->u.v2_i.i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); +- info->u.v2_i.i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); +- info->u.v2_i.i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); +- info->u.v2_i.i.dqi_blocksize_bits = V2_DQBLKSIZE_BITS; +- info->u.v2_i.i.dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS; +- info->u.v2_i.i.dqi_qtree_depth = qtree_depth(&info->u.v2_i.i); +- info->u.v2_i.i.dqi_entry_size = sizeof(struct v2_disk_dqblk); +- info->u.v2_i.i.dqi_ops = &v2_qtree_ops; ++ qinfo->dqi_sb = sb; ++ qinfo->dqi_type = type; ++ qinfo->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); ++ qinfo->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); ++ qinfo->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); ++ qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS; ++ qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS; ++ qinfo->dqi_qtree_depth = qtree_depth(qinfo); ++ qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk); ++ qinfo->dqi_ops = &v2_qtree_ops; + return 0; + } + +@@ -104,6 +112,7 @@ static int v2_write_file_info(struct super_block *sb, int type) + { + struct v2_disk_dqinfo dinfo; + struct mem_dqinfo *info = sb_dqinfo(sb, type); ++ struct qtree_mem_dqinfo *qinfo = info->dqi_priv; + ssize_t size; + + spin_lock(&dq_data_lock); +@@ -112,9 +121,9 @@ static int v2_write_file_info(struct super_block *sb, int type) + dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); + dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); + spin_unlock(&dq_data_lock); +- dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.i.dqi_blocks); +- dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.i.dqi_free_blk); +- dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.i.dqi_free_entry); ++ dinfo.dqi_blocks = cpu_to_le32(qinfo->dqi_blocks); ++ dinfo.dqi_free_blk = cpu_to_le32(qinfo->dqi_free_blk); ++ dinfo.dqi_free_entry = cpu_to_le32(qinfo->dqi_free_entry); + size = sb->s_op->quota_write(sb, type, (char *)&dinfo, + sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); + if (size != sizeof(struct v2_disk_dqinfo)) { +@@ -150,7 +159,7 @@ static void v2_mem2diskdqb(void *dp, struct dquot *dquot) + struct v2_disk_dqblk *d = dp; + struct mem_dqblk *m = &dquot->dq_dqb; + struct qtree_mem_dqinfo *info = +- &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i; ++ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; + + d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); +@@ -169,7 +178,7 @@ static int v2_is_id(void *dp, struct dquot *dquot) + { + struct v2_disk_dqblk *d = dp; + struct qtree_mem_dqinfo *info = +- &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i; ++ sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; + + if (qtree_entry_unused(info, dp)) + return 0; +@@ -178,24 +187,30 @@ static int v2_is_id(void *dp, struct dquot *dquot) + + static int v2_read_dquot(struct dquot *dquot) + { +- return qtree_read_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); ++ return qtree_read_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); + } + + static int v2_write_dquot(struct dquot *dquot) + { +- return qtree_write_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); ++ return qtree_write_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); + } + + static int v2_release_dquot(struct dquot *dquot) + { +- return qtree_release_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); ++ return qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv, dquot); ++} ++ ++static int v2_free_file_info(struct super_block *sb, int type) ++{ ++ kfree(sb_dqinfo(sb, type)->dqi_priv); ++ return 0; + } + + static struct quota_format_ops v2_format_ops = { + .check_quota_file = v2_check_quota_file, + .read_file_info = v2_read_file_info, + .write_file_info = v2_write_file_info, +- .free_file_info = NULL, ++ .free_file_info = v2_free_file_info, + .read_dqblk = v2_read_dquot, + .commit_dqblk = v2_write_dquot, + .release_dqblk = v2_release_dquot, +diff --git a/include/linux/dqblk_v1.h b/include/linux/dqblk_v1.h +index 57f1250..9cea901 100644 +--- a/include/linux/dqblk_v1.h ++++ b/include/linux/dqblk_v1.h +@@ -17,8 +17,4 @@ + #define V1_DEL_ALLOC 0 + #define V1_DEL_REWRITE 2 + +-/* Special information about quotafile */ +-struct v1_mem_dqinfo { +-}; +- + #endif /* _LINUX_DQBLK_V1_H */ +diff --git a/include/linux/dqblk_v2.h b/include/linux/dqblk_v2.h +index e5e22a7..ff8af1b 100644 +--- a/include/linux/dqblk_v2.h ++++ b/include/linux/dqblk_v2.h +@@ -16,8 +16,4 @@ + #define V2_DEL_ALLOC QTREE_DEL_ALLOC + #define V2_DEL_REWRITE QTREE_DEL_REWRITE + +-struct v2_mem_dqinfo { +- struct qtree_mem_dqinfo i; +-}; +- + #endif /* _LINUX_DQBLK_V2_H */ +diff --git a/include/linux/quota.h b/include/linux/quota.h +index 8dd5333..e05c30d 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -210,10 +210,7 @@ struct mem_dqinfo { + unsigned int dqi_igrace; + qsize_t dqi_maxblimit; + qsize_t dqi_maxilimit; +- union { +- struct v1_mem_dqinfo v1_i; +- struct v2_mem_dqinfo v2_i; +- } u; ++ void *dqi_priv; + }; + + struct super_block; +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Implement-function-for-scanning-active-dquots.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Implement-function-for-scanning-active-dquots.patch new file mode 100644 index 000000000..4ae143a80 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Implement-function-for-scanning-active-dquots.patch @@ -0,0 +1,88 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 17/28] quota: Implement function for scanning active dquots +Patch-mainline: 2.6.29? + +OCFS2 needs to scan all active dquots once in a while and sync quota +information among cluster nodes. Provide a helper function for it so +that it does not have to reimplement internally a list which VFS +already has. Moreover this function is probably going to be useful +for other clustered filesystems if they decide to use VFS quotas. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/quotaops.h | 3 +++ + 2 files changed, 39 insertions(+), 0 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index 9fb1d71..6a17416 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -476,6 +476,41 @@ restart: + spin_unlock(&dq_list_lock); + } + ++/* Call callback for every active dquot on given filesystem */ ++int dquot_scan_active(struct super_block *sb, ++ int (*fn)(struct dquot *dquot, unsigned long priv), ++ unsigned long priv) ++{ ++ struct dquot *dquot, *old_dquot = NULL; ++ int ret = 0; ++ ++ mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); ++ spin_lock(&dq_list_lock); ++ list_for_each_entry(dquot, &inuse_list, dq_inuse) { ++ if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) ++ continue; ++ if (dquot->dq_sb != sb) ++ continue; ++ /* Now we have active dquot so we can just increase use count */ ++ atomic_inc(&dquot->dq_count); ++ dqstats.lookups++; ++ spin_unlock(&dq_list_lock); ++ dqput(old_dquot); ++ old_dquot = dquot; ++ ret = fn(dquot, priv); ++ if (ret < 0) ++ goto out; ++ spin_lock(&dq_list_lock); ++ /* We are safe to continue now because our dquot could not ++ * be moved out of the inuse list while we hold the reference */ ++ } ++ spin_unlock(&dq_list_lock); ++out: ++ dqput(old_dquot); ++ mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); ++ return ret; ++} ++ + int vfs_quota_sync(struct super_block *sb, int type) + { + struct list_head *dirty; +@@ -2316,6 +2351,7 @@ EXPORT_SYMBOL(vfs_quota_on_path); + EXPORT_SYMBOL(vfs_quota_on_mount); + EXPORT_SYMBOL(vfs_quota_disable); + EXPORT_SYMBOL(vfs_quota_off); ++EXPORT_SYMBOL(dquot_scan_active); + EXPORT_SYMBOL(vfs_quota_sync); + EXPORT_SYMBOL(vfs_get_dqinfo); + EXPORT_SYMBOL(vfs_set_dqinfo); +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 1f990f2..f2147eb 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -31,6 +31,9 @@ int dquot_drop_locked(struct inode *inode); + struct dquot *dqget(struct super_block *sb, unsigned int id, int type); + void dqput(struct dquot *dquot); + int dquot_is_cached(struct super_block *sb, unsigned int id, int type); ++int dquot_scan_active(struct super_block *sb, ++ int (*fn)(struct dquot *dquot, unsigned long priv), ++ unsigned long priv); + + int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); + int dquot_alloc_inode(const struct inode *inode, qsize_t number); +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Increase-size-of-variables-for-limits-and-ino.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Increase-size-of-variables-for-limits-and-ino.patch new file mode 100644 index 000000000..d582bb82f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Increase-size-of-variables-for-limits-and-ino.patch @@ -0,0 +1,359 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 02/28] quota: Increase size of variables for limits and inode usage +Patch-mainline: 2.6.29? + +So far quota was fine with quota block limits and inode limits/numbers in +a 32-bit type. Now with rapid increase in storage sizes there are coming +requests to be able to handle quota limits above 4TB / more that 2^32 inodes. +So bump up sizes of types in mem_dqblk structure to 64-bits to be able to +handle this. Also update inode allocation / checking functions to use qsize_t +and make global structure keep quota limits in bytes so that things are +consistent. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 50 ++++++++++++++++++++++++++------------------- + fs/quota_v1.c | 25 +++++++++++++++++----- + fs/quota_v2.c | 21 +++++++++++++++--- + include/linux/quota.h | 28 +++++++++++-------------- + include/linux/quotaops.h | 4 +- + 5 files changed, 79 insertions(+), 49 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index e1dac3e..758bf4a 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -833,7 +833,7 @@ static void drop_dquot_ref(struct super_block *sb, int type) + } + } + +-static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) ++static inline void dquot_incr_inodes(struct dquot *dquot, qsize_t number) + { + dquot->dq_dqb.dqb_curinodes += number; + } +@@ -843,7 +843,7 @@ static inline void dquot_incr_space(struct dquot *dquot, qsize_t number) + dquot->dq_dqb.dqb_curspace += number; + } + +-static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number) ++static inline void dquot_decr_inodes(struct dquot *dquot, qsize_t number) + { + if (dquot->dq_dqb.dqb_curinodes > number) + dquot->dq_dqb.dqb_curinodes -= number; +@@ -860,7 +860,7 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number) + dquot->dq_dqb.dqb_curspace -= number; + else + dquot->dq_dqb.dqb_curspace = 0; +- if (toqb(dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit) ++ if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit) + dquot->dq_dqb.dqb_btime = (time_t) 0; + clear_bit(DQ_BLKS_B, &dquot->dq_flags); + } +@@ -1038,7 +1038,7 @@ static inline char ignore_hardlimit(struct dquot *dquot) + } + + /* needs dq_data_lock */ +-static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) ++static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) + { + *warntype = QUOTA_NL_NOWARN; + if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) +@@ -1077,7 +1077,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war + return QUOTA_OK; + + if (dquot->dq_dqb.dqb_bhardlimit && +- toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit && ++ dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bhardlimit && + !ignore_hardlimit(dquot)) { + if (!prealloc) + *warntype = QUOTA_NL_BHARDWARN; +@@ -1085,7 +1085,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war + } + + if (dquot->dq_dqb.dqb_bsoftlimit && +- toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && ++ dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime && + !ignore_hardlimit(dquot)) { + if (!prealloc) +@@ -1094,7 +1094,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war + } + + if (dquot->dq_dqb.dqb_bsoftlimit && +- toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && ++ dquot->dq_dqb.dqb_curspace + space > dquot->dq_dqb.dqb_bsoftlimit && + dquot->dq_dqb.dqb_btime == 0) { + if (!prealloc) { + *warntype = QUOTA_NL_BSOFTWARN; +@@ -1111,7 +1111,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war + return QUOTA_OK; + } + +-static int info_idq_free(struct dquot *dquot, ulong inodes) ++static int info_idq_free(struct dquot *dquot, qsize_t inodes) + { + if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || + dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) +@@ -1128,15 +1128,13 @@ static int info_idq_free(struct dquot *dquot, ulong inodes) + static int info_bdq_free(struct dquot *dquot, qsize_t space) + { + if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || +- toqb(dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit) ++ dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit) + return QUOTA_NL_NOWARN; + +- if (toqb(dquot->dq_dqb.dqb_curspace - space) <= +- dquot->dq_dqb.dqb_bsoftlimit) ++ if (dquot->dq_dqb.dqb_curspace - space <= dquot->dq_dqb.dqb_bsoftlimit) + return QUOTA_NL_BSOFTBELOW; +- if (toqb(dquot->dq_dqb.dqb_curspace) >= dquot->dq_dqb.dqb_bhardlimit && +- toqb(dquot->dq_dqb.dqb_curspace - space) < +- dquot->dq_dqb.dqb_bhardlimit) ++ if (dquot->dq_dqb.dqb_curspace >= dquot->dq_dqb.dqb_bhardlimit && ++ dquot->dq_dqb.dqb_curspace - space < dquot->dq_dqb.dqb_bhardlimit) + return QUOTA_NL_BHARDBELOW; + return QUOTA_NL_NOWARN; + } +@@ -1279,7 +1277,7 @@ warn_put_all: + /* + * This operation can block, but only after everything is updated + */ +-int dquot_alloc_inode(const struct inode *inode, unsigned long number) ++int dquot_alloc_inode(const struct inode *inode, qsize_t number) + { + int cnt, ret = NO_QUOTA; + char warntype[MAXQUOTAS]; +@@ -1364,7 +1362,7 @@ out_sub: + /* + * This operation can block, but only after everything is updated + */ +-int dquot_free_inode(const struct inode *inode, unsigned long number) ++int dquot_free_inode(const struct inode *inode, qsize_t number) + { + unsigned int cnt; + char warntype[MAXQUOTAS]; +@@ -1881,14 +1879,24 @@ int vfs_dq_quota_on_remount(struct super_block *sb) + return ret; + } + ++static inline qsize_t qbtos(qsize_t blocks) ++{ ++ return blocks << QIF_DQBLKSIZE_BITS; ++} ++ ++static inline qsize_t stoqb(qsize_t space) ++{ ++ return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS; ++} ++ + /* Generic routine for getting common part of quota structure */ + static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) + { + struct mem_dqblk *dm = &dquot->dq_dqb; + + spin_lock(&dq_data_lock); +- di->dqb_bhardlimit = dm->dqb_bhardlimit; +- di->dqb_bsoftlimit = dm->dqb_bsoftlimit; ++ di->dqb_bhardlimit = stoqb(dm->dqb_bhardlimit); ++ di->dqb_bsoftlimit = stoqb(dm->dqb_bsoftlimit); + di->dqb_curspace = dm->dqb_curspace; + di->dqb_ihardlimit = dm->dqb_ihardlimit; + di->dqb_isoftlimit = dm->dqb_isoftlimit; +@@ -1935,8 +1943,8 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) + check_blim = 1; + } + if (di->dqb_valid & QIF_BLIMITS) { +- dm->dqb_bsoftlimit = di->dqb_bsoftlimit; +- dm->dqb_bhardlimit = di->dqb_bhardlimit; ++ dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit); ++ dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit); + check_blim = 1; + } + if (di->dqb_valid & QIF_INODES) { +@@ -1954,7 +1962,7 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) + dm->dqb_itime = di->dqb_itime; + + if (check_blim) { +- if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) { ++ if (!dm->dqb_bsoftlimit || dm->dqb_curspace < dm->dqb_bsoftlimit) { + dm->dqb_btime = 0; + clear_bit(DQ_BLKS_B, &dquot->dq_flags); + } +diff --git a/fs/quota_v1.c b/fs/quota_v1.c +index 5ae15b1..3e078ee 100644 +--- a/fs/quota_v1.c ++++ b/fs/quota_v1.c +@@ -14,14 +14,27 @@ MODULE_AUTHOR("Jan Kara"); + MODULE_DESCRIPTION("Old quota format support"); + MODULE_LICENSE("GPL"); + ++#define QUOTABLOCK_BITS 10 ++#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) ++ ++static inline qsize_t v1_stoqb(qsize_t space) ++{ ++ return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS; ++} ++ ++static inline qsize_t v1_qbtos(qsize_t blocks) ++{ ++ return blocks << QUOTABLOCK_BITS; ++} ++ + static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d) + { + m->dqb_ihardlimit = d->dqb_ihardlimit; + m->dqb_isoftlimit = d->dqb_isoftlimit; + m->dqb_curinodes = d->dqb_curinodes; +- m->dqb_bhardlimit = d->dqb_bhardlimit; +- m->dqb_bsoftlimit = d->dqb_bsoftlimit; +- m->dqb_curspace = ((qsize_t)d->dqb_curblocks) << QUOTABLOCK_BITS; ++ m->dqb_bhardlimit = v1_qbtos(d->dqb_bhardlimit); ++ m->dqb_bsoftlimit = v1_qbtos(d->dqb_bsoftlimit); ++ m->dqb_curspace = v1_qbtos(d->dqb_curblocks); + m->dqb_itime = d->dqb_itime; + m->dqb_btime = d->dqb_btime; + } +@@ -31,9 +44,9 @@ static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m) + d->dqb_ihardlimit = m->dqb_ihardlimit; + d->dqb_isoftlimit = m->dqb_isoftlimit; + d->dqb_curinodes = m->dqb_curinodes; +- d->dqb_bhardlimit = m->dqb_bhardlimit; +- d->dqb_bsoftlimit = m->dqb_bsoftlimit; +- d->dqb_curblocks = toqb(m->dqb_curspace); ++ d->dqb_bhardlimit = v1_stoqb(m->dqb_bhardlimit); ++ d->dqb_bsoftlimit = v1_stoqb(m->dqb_bsoftlimit); ++ d->dqb_curblocks = v1_stoqb(m->dqb_curspace); + d->dqb_itime = m->dqb_itime; + d->dqb_btime = m->dqb_btime; + } +diff --git a/fs/quota_v2.c b/fs/quota_v2.c +index b53827d..51c4717 100644 +--- a/fs/quota_v2.c ++++ b/fs/quota_v2.c +@@ -26,6 +26,19 @@ typedef char *dqbuf_t; + #define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) + #define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) + ++#define QUOTABLOCK_BITS 10 ++#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) ++ ++static inline qsize_t v2_stoqb(qsize_t space) ++{ ++ return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS; ++} ++ ++static inline qsize_t v2_qbtos(qsize_t blocks) ++{ ++ return blocks << QUOTABLOCK_BITS; ++} ++ + /* Check whether given file is really vfsv0 quotafile */ + static int v2_check_quota_file(struct super_block *sb, int type) + { +@@ -104,8 +117,8 @@ static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) + m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); + m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); + m->dqb_itime = le64_to_cpu(d->dqb_itime); +- m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit); +- m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit); ++ m->dqb_bhardlimit = v2_qbtos(le32_to_cpu(d->dqb_bhardlimit)); ++ m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit)); + m->dqb_curspace = le64_to_cpu(d->dqb_curspace); + m->dqb_btime = le64_to_cpu(d->dqb_btime); + } +@@ -116,8 +129,8 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); + d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); + d->dqb_itime = cpu_to_le64(m->dqb_itime); +- d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit); +- d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit); ++ d->dqb_bhardlimit = cpu_to_le32(v2_qbtos(m->dqb_bhardlimit)); ++ d->dqb_bsoftlimit = cpu_to_le32(v2_qbtos(m->dqb_bsoftlimit)); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_btime = cpu_to_le64(m->dqb_btime); + d->dqb_id = cpu_to_le32(id); +diff --git a/include/linux/quota.h b/include/linux/quota.h +index eeae7a9..5167786 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -41,15 +41,6 @@ + #define __DQUOT_VERSION__ "dquot_6.5.1" + #define __DQUOT_NUM_VERSION__ 6*10000+5*100+1 + +-/* Size of blocks in which are counted size limits */ +-#define QUOTABLOCK_BITS 10 +-#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) +- +-/* Conversion routines from and to quota blocks */ +-#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +-#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +-#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) +- + #define MAXQUOTAS 2 + #define USRQUOTA 0 /* element used for user quotas */ + #define GRPQUOTA 1 /* element used for group quotas */ +@@ -82,6 +73,11 @@ + #define Q_GETQUOTA 0x800007 /* get user quota structure */ + #define Q_SETQUOTA 0x800008 /* set user quota structure */ + ++/* Size of block in which space limits are passed through the quota ++ * interface */ ++#define QIF_DQBLKSIZE_BITS 10 ++#define QIF_DQBLKSIZE (1 << QIF_DQBLKSIZE_BITS) ++ + /* + * Quota structure used for communication with userspace via quotactl + * Following flags are used to specify which fields are valid +@@ -189,12 +185,12 @@ extern spinlock_t dq_data_lock; + * Data for one user/group kept in memory + */ + struct mem_dqblk { +- __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ +- __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ ++ qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ ++ qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */ + qsize_t dqb_curspace; /* current used space */ +- __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ +- __u32 dqb_isoftlimit; /* preferred inode limit */ +- __u32 dqb_curinodes; /* current # allocated inodes */ ++ qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */ ++ qsize_t dqb_isoftlimit; /* preferred inode limit */ ++ qsize_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive inode use */ + }; +@@ -289,9 +285,9 @@ struct dquot_operations { + int (*initialize) (struct inode *, int); + int (*drop) (struct inode *); + int (*alloc_space) (struct inode *, qsize_t, int); +- int (*alloc_inode) (const struct inode *, unsigned long); ++ int (*alloc_inode) (const struct inode *, qsize_t); + int (*free_space) (struct inode *, qsize_t); +- int (*free_inode) (const struct inode *, unsigned long); ++ int (*free_inode) (const struct inode *, qsize_t); + int (*transfer) (struct inode *, struct iattr *); + int (*write_dquot) (struct dquot *); /* Ordinary dquot write */ + struct dquot *(*alloc_dquot)(struct super_block *, int); /* Allocate memory for new dquot (can be NULL if no special entries dquot are needed) */ +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index ca6b9b5..9e7bc4b 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -29,10 +29,10 @@ int dquot_initialize(struct inode *inode, int type); + int dquot_drop(struct inode *inode); + + int dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc); +-int dquot_alloc_inode(const struct inode *inode, unsigned long number); ++int dquot_alloc_inode(const struct inode *inode, qsize_t number); + + int dquot_free_space(struct inode *inode, qsize_t number); +-int dquot_free_inode(const struct inode *inode, unsigned long number); ++int dquot_free_inode(const struct inode *inode, qsize_t number); + + int dquot_transfer(struct inode *inode, struct iattr *iattr); + int dquot_commit(struct dquot *dquot); +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Introduce-DQUOT_QUOTA_SYS_FILE-flag.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Introduce-DQUOT_QUOTA_SYS_FILE-flag.patch new file mode 100644 index 000000000..4eee9a436 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Introduce-DQUOT_QUOTA_SYS_FILE-flag.patch @@ -0,0 +1,135 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 10/28] quota: Introduce DQUOT_QUOTA_SYS_FILE flag +Patch-mainline: 2.6.29? + +If filesystem can handle quota files as system files hidden from users, we can +skip a lot of cache invalidation, syncing, inode flags setting etc. when +turning quotas on, off and quota_sync. Allow filesystem to indicate that it is +hiding quota files from users by DQUOT_QUOTA_SYS_FILE flag. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 45 ++++++++++++++++++++++++++++++--------------- + fs/quota.c | 3 +++ + include/linux/quota.h | 7 +++++++ + 3 files changed, 40 insertions(+), 15 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index bdfae7d..904bd67 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -1629,6 +1629,11 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) + dqopt->ops[cnt] = NULL; + } + mutex_unlock(&dqopt->dqonoff_mutex); ++ ++ /* Skip syncing and setting flags if quota files are hidden */ ++ if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) ++ goto put_inodes; ++ + /* Sync the superblock so that buffers with quota data are written to + * disk (and so userspace sees correct data afterwards). */ + if (sb->s_op->sync_fs) +@@ -1653,6 +1658,12 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) + mark_inode_dirty(toputinode[cnt]); + } + mutex_unlock(&dqopt->dqonoff_mutex); ++ } ++ if (sb->s_bdev) ++ invalidate_bdev(sb->s_bdev); ++put_inodes: ++ for (cnt = 0; cnt < MAXQUOTAS; cnt++) ++ if (toputinode[cnt]) { + /* On remount RO, we keep the inode pointer so that we + * can reenable quota on the subsequent remount RW. We + * have to check 'flags' variable and not use sb_has_ +@@ -1665,8 +1676,6 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) + else if (!toputinode[cnt]->i_nlink) + ret = -EBUSY; + } +- if (sb->s_bdev) +- invalidate_bdev(sb->s_bdev); + return ret; + } + +@@ -1713,25 +1722,31 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, + goto out_fmt; + } + +- /* As we bypass the pagecache we must now flush the inode so that +- * we see all the changes from userspace... */ +- write_inode_now(inode, 1); +- /* And now flush the block cache so that kernel sees the changes */ +- invalidate_bdev(sb->s_bdev); ++ if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) { ++ /* As we bypass the pagecache we must now flush the inode so ++ * that we see all the changes from userspace... */ ++ write_inode_now(inode, 1); ++ /* And now flush the block cache so that kernel sees the ++ * changes */ ++ invalidate_bdev(sb->s_bdev); ++ } + mutex_lock(&inode->i_mutex); + mutex_lock(&dqopt->dqonoff_mutex); + if (sb_has_quota_loaded(sb, type)) { + error = -EBUSY; + goto out_lock; + } +- /* We don't want quota and atime on quota files (deadlocks possible) +- * Also nobody should write to the file - we use special IO operations +- * which ignore the immutable bit. */ +- down_write(&dqopt->dqptr_sem); +- oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA); +- inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; +- up_write(&dqopt->dqptr_sem); +- sb->dq_op->drop(inode); ++ ++ if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) { ++ /* We don't want quota and atime on quota files (deadlocks ++ * possible) Also nobody should write to the file - we use ++ * special IO operations which ignore the immutable bit. */ ++ down_write(&dqopt->dqptr_sem); ++ oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA); ++ inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; ++ up_write(&dqopt->dqptr_sem); ++ sb->dq_op->drop(inode); ++ } + + error = -EIO; + dqopt->files[type] = igrab(inode); +diff --git a/fs/quota.c b/fs/quota.c +index a8026f1..2c6ea78 100644 +--- a/fs/quota.c ++++ b/fs/quota.c +@@ -160,6 +160,9 @@ static void quota_sync_sb(struct super_block *sb, int type) + int cnt; + + sb->s_qcop->quota_sync(sb, type); ++ ++ if (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE) ++ return; + /* This is not very clever (and fast) but currently I don't know about + * any other simple way of getting quota data to disk and we must get + * them there for userspace to be visible... */ +diff --git a/include/linux/quota.h b/include/linux/quota.h +index 0e4b550..8dd5333 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -334,6 +334,13 @@ enum { + #define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED) + #define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ + DQUOT_SUSPENDED) ++/* Other quota flags */ ++#define DQUOT_QUOTA_SYS_FILE (1 << 6) /* Quota file is a special ++ * system file and user cannot ++ * touch it. Filesystem is ++ * responsible for setting ++ * S_NOQUOTA, S_NOATIME flags ++ */ + + static inline unsigned int dquot_state_flag(unsigned int flags, int type) + { +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Keep-which-entries-were-set-by-SETQUOTA-quota.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Keep-which-entries-were-set-by-SETQUOTA-quota.patch new file mode 100644 index 000000000..5bcc1b1ef --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Keep-which-entries-were-set-by-SETQUOTA-quota.patch @@ -0,0 +1,106 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 15/28] quota: Keep which entries were set by SETQUOTA quotactl +Patch-mainline: 2.6.29? + +Quota in a clustered environment needs to synchronize quota information +among cluster nodes. This means we have to occasionally update some +information in dquot from disk / network. On the other hand we have to +be careful not to overwrite changes administrator did via SETQUOTA. +So indicate in dquot->dq_flags which entries have been set by SETQUOTA +and quota format can clear these flags when it properly propagated +the changes. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 12 ++++++++++-- + include/linux/quota.h | 26 ++++++++++++++++++++------ + 2 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index f4258fe..3fde18b 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -2008,25 +2008,33 @@ static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di) + if (di->dqb_valid & QIF_SPACE) { + dm->dqb_curspace = di->dqb_curspace; + check_blim = 1; ++ __set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags); + } + if (di->dqb_valid & QIF_BLIMITS) { + dm->dqb_bsoftlimit = qbtos(di->dqb_bsoftlimit); + dm->dqb_bhardlimit = qbtos(di->dqb_bhardlimit); + check_blim = 1; ++ __set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags); + } + if (di->dqb_valid & QIF_INODES) { + dm->dqb_curinodes = di->dqb_curinodes; + check_ilim = 1; ++ __set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags); + } + if (di->dqb_valid & QIF_ILIMITS) { + dm->dqb_isoftlimit = di->dqb_isoftlimit; + dm->dqb_ihardlimit = di->dqb_ihardlimit; + check_ilim = 1; ++ __set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags); + } +- if (di->dqb_valid & QIF_BTIME) ++ if (di->dqb_valid & QIF_BTIME) { + dm->dqb_btime = di->dqb_btime; +- if (di->dqb_valid & QIF_ITIME) ++ __set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags); ++ } ++ if (di->dqb_valid & QIF_ITIME) { + dm->dqb_itime = di->dqb_itime; ++ __set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags); ++ } + + if (check_blim) { + if (!dm->dqb_bsoftlimit || dm->dqb_curspace < dm->dqb_bsoftlimit) { +diff --git a/include/linux/quota.h b/include/linux/quota.h +index 0ee2a55..f81e80c 100644 +--- a/include/linux/quota.h ++++ b/include/linux/quota.h +@@ -82,12 +82,21 @@ + * Quota structure used for communication with userspace via quotactl + * Following flags are used to specify which fields are valid + */ +-#define QIF_BLIMITS 1 +-#define QIF_SPACE 2 +-#define QIF_ILIMITS 4 +-#define QIF_INODES 8 +-#define QIF_BTIME 16 +-#define QIF_ITIME 32 ++enum { ++ QIF_BLIMITS_B = 0, ++ QIF_SPACE_B, ++ QIF_ILIMITS_B, ++ QIF_INODES_B, ++ QIF_BTIME_B, ++ QIF_ITIME_B, ++}; ++ ++#define QIF_BLIMITS (1 << QIF_BLIMITS_B) ++#define QIF_SPACE (1 << QIF_SPACE_B) ++#define QIF_ILIMITS (1 << QIF_ILIMITS_B) ++#define QIF_INODES (1 << QIF_INODES_B) ++#define QIF_BTIME (1 << QIF_BTIME_B) ++#define QIF_ITIME (1 << QIF_ITIME_B) + #define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) + #define QIF_USAGE (QIF_SPACE | QIF_INODES) + #define QIF_TIMES (QIF_BTIME | QIF_ITIME) +@@ -244,6 +253,11 @@ extern struct dqstats dqstats; + #define DQ_FAKE_B 3 /* no limits only usage */ + #define DQ_READ_B 4 /* dquot was read into memory */ + #define DQ_ACTIVE_B 5 /* dquot is active (dquot_release not called) */ ++#define DQ_LASTSET_B 6 /* Following 6 bits (see QIF_) are reserved\ ++ * for the mask of entries set via SETQUOTA\ ++ * quotactl. They are set under dq_data_lock\ ++ * and the quota format handling dquot can\ ++ * clear them when it sees fit. */ + + struct dquot { + struct hlist_node dq_hash; /* Hash list in memory */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Make-_SUSPENDED-just-a-flag.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Make-_SUSPENDED-just-a-flag.patch new file mode 100644 index 000000000..5e5f1e176 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Make-_SUSPENDED-just-a-flag.patch @@ -0,0 +1,66 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 04/28] quota: Make _SUSPENDED just a flag +Patch-mainline: 2.6.29? + +Upto now, DQUOT_USR_SUSPENDED behaved like a state - i.e., either quota +was enabled or suspended or none. Now allowed states are 0, ENABLED, +ENABLED | SUSPENDED. This will be useful later when we implement separate +enabling of quota usage tracking and limits enforcement because we need to +keep track of a state which has been suspended. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 10 ++++++---- + include/linux/quotaops.h | 6 ++++-- + 2 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index e95ad55..aea7bf9 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -1568,18 +1568,20 @@ static inline void reset_enable_flags(struct quota_info *dqopt, int type, + { + switch (type) { + case USRQUOTA: +- dqopt->flags &= ~DQUOT_USR_ENABLED; + if (remount) + dqopt->flags |= DQUOT_USR_SUSPENDED; +- else ++ else { ++ dqopt->flags &= ~DQUOT_USR_ENABLED; + dqopt->flags &= ~DQUOT_USR_SUSPENDED; ++ } + break; + case GRPQUOTA: +- dqopt->flags &= ~DQUOT_GRP_ENABLED; + if (remount) + dqopt->flags |= DQUOT_GRP_SUSPENDED; +- else ++ else { ++ dqopt->flags &= ~DQUOT_GRP_ENABLED; + dqopt->flags &= ~DQUOT_GRP_SUSPENDED; ++ } + break; + } + } +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index 9e7bc4b..12363cc 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -70,8 +70,10 @@ static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type) + static inline int sb_has_quota_enabled(struct super_block *sb, int type) + { + if (type == USRQUOTA) +- return sb_dqopt(sb)->flags & DQUOT_USR_ENABLED; +- return sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED; ++ return (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) ++ && !(sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED); ++ return (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED) ++ && !(sb_dqopt(sb)->flags & DQUOT_GROUP_SUSPENDED); + } + + static inline int sb_any_quota_enabled(struct super_block *sb) +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Move-quotaio_v-12-.h-from-include-linux-to-f.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Move-quotaio_v-12-.h-from-include-linux-to-f.patch new file mode 100644 index 000000000..876b0e4d5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Move-quotaio_v-12-.h-from-include-linux-to-f.patch @@ -0,0 +1,325 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 11/28] quota: Move quotaio_v[12].h from include/linux/ to fs/ +Patch-mainline: 2.6.29? + +Since these include files are used only by implementation of quota formats, +there's no need to have them in include/linux/. + +Signed-off-by: Jan Kara +--- + fs/quota_v1.c | 3 +- + fs/quota_v2.c | 7 ++-- + fs/quotaio_v1.h | 33 ++++++++++++++++++ + fs/quotaio_v2.h | 79 ++++++++++++++++++++++++++++++++++++++++++++ + include/linux/quotaio_v1.h | 33 ------------------ + include/linux/quotaio_v2.h | 79 -------------------------------------------- + 6 files changed, 118 insertions(+), 116 deletions(-) + create mode 100644 fs/quotaio_v1.h + create mode 100644 fs/quotaio_v2.h + delete mode 100644 include/linux/quotaio_v1.h + delete mode 100644 include/linux/quotaio_v2.h + +diff --git a/fs/quota_v1.c b/fs/quota_v1.c +index 3e078ee..b4af1c6 100644 +--- a/fs/quota_v1.c ++++ b/fs/quota_v1.c +@@ -3,13 +3,14 @@ + #include + #include + #include +-#include + #include + #include + #include + + #include + ++#include "quotaio_v1.h" ++ + MODULE_AUTHOR("Jan Kara"); + MODULE_DESCRIPTION("Old quota format support"); + MODULE_LICENSE("GPL"); +diff --git a/fs/quota_v2.c b/fs/quota_v2.c +index 51c4717..a21d1a7 100644 +--- a/fs/quota_v2.c ++++ b/fs/quota_v2.c +@@ -6,7 +6,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -15,6 +14,8 @@ + + #include + ++#include "quotaio_v2.h" ++ + MODULE_AUTHOR("Jan Kara"); + MODULE_DESCRIPTION("Quota format v2 support"); + MODULE_LICENSE("GPL"); +@@ -129,8 +130,8 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); + d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); + d->dqb_itime = cpu_to_le64(m->dqb_itime); +- d->dqb_bhardlimit = cpu_to_le32(v2_qbtos(m->dqb_bhardlimit)); +- d->dqb_bsoftlimit = cpu_to_le32(v2_qbtos(m->dqb_bsoftlimit)); ++ d->dqb_bhardlimit = cpu_to_le32(v2_stoqb(m->dqb_bhardlimit)); ++ d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit)); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_btime = cpu_to_le64(m->dqb_btime); + d->dqb_id = cpu_to_le32(id); +diff --git a/fs/quotaio_v1.h b/fs/quotaio_v1.h +new file mode 100644 +index 0000000..746654b +--- /dev/null ++++ b/fs/quotaio_v1.h +@@ -0,0 +1,33 @@ ++#ifndef _LINUX_QUOTAIO_V1_H ++#define _LINUX_QUOTAIO_V1_H ++ ++#include ++ ++/* ++ * The following constants define the amount of time given a user ++ * before the soft limits are treated as hard limits (usually resulting ++ * in an allocation failure). The timer is started when the user crosses ++ * their soft limit, it is reset when they go below their soft limit. ++ */ ++#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ ++#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ ++ ++/* ++ * The following structure defines the format of the disk quota file ++ * (as it appears on disk) - the file is an array of these structures ++ * indexed by user or group number. ++ */ ++struct v1_disk_dqblk { ++ __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ ++ __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ ++ __u32 dqb_curblocks; /* current block count */ ++ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ ++ __u32 dqb_isoftlimit; /* preferred inode limit */ ++ __u32 dqb_curinodes; /* current # allocated inodes */ ++ time_t dqb_btime; /* time limit for excessive disk use */ ++ time_t dqb_itime; /* time limit for excessive inode use */ ++}; ++ ++#define v1_dqoff(UID) ((loff_t)((UID) * sizeof (struct v1_disk_dqblk))) ++ ++#endif /* _LINUX_QUOTAIO_V1_H */ +diff --git a/fs/quotaio_v2.h b/fs/quotaio_v2.h +new file mode 100644 +index 0000000..303d7cb +--- /dev/null ++++ b/fs/quotaio_v2.h +@@ -0,0 +1,79 @@ ++/* ++ * Definitions of structures for vfsv0 quota format ++ */ ++ ++#ifndef _LINUX_QUOTAIO_V2_H ++#define _LINUX_QUOTAIO_V2_H ++ ++#include ++#include ++ ++/* ++ * Definitions of magics and versions of current quota files ++ */ ++#define V2_INITQMAGICS {\ ++ 0xd9c01f11, /* USRQUOTA */\ ++ 0xd9c01927 /* GRPQUOTA */\ ++} ++ ++#define V2_INITQVERSIONS {\ ++ 0, /* USRQUOTA */\ ++ 0 /* GRPQUOTA */\ ++} ++ ++/* ++ * The following structure defines the format of the disk quota file ++ * (as it appears on disk) - the file is a radix tree whose leaves point ++ * to blocks of these structures. ++ */ ++struct v2_disk_dqblk { ++ __le32 dqb_id; /* id this quota applies to */ ++ __le32 dqb_ihardlimit; /* absolute limit on allocated inodes */ ++ __le32 dqb_isoftlimit; /* preferred inode limit */ ++ __le32 dqb_curinodes; /* current # allocated inodes */ ++ __le32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ ++ __le32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ ++ __le64 dqb_curspace; /* current space occupied (in bytes) */ ++ __le64 dqb_btime; /* time limit for excessive disk use */ ++ __le64 dqb_itime; /* time limit for excessive inode use */ ++}; ++ ++/* ++ * Here are header structures as written on disk and their in-memory copies ++ */ ++/* First generic header */ ++struct v2_disk_dqheader { ++ __le32 dqh_magic; /* Magic number identifying file */ ++ __le32 dqh_version; /* File version */ ++}; ++ ++/* Header with type and version specific information */ ++struct v2_disk_dqinfo { ++ __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ ++ __le32 dqi_igrace; /* Time before inode soft limit becomes hard limit */ ++ __le32 dqi_flags; /* Flags for quotafile (DQF_*) */ ++ __le32 dqi_blocks; /* Number of blocks in file */ ++ __le32 dqi_free_blk; /* Number of first free block in the list */ ++ __le32 dqi_free_entry; /* Number of block with at least one free entry */ ++}; ++ ++/* ++ * Structure of header of block with quota structures. It is padded to 16 bytes so ++ * there will be space for exactly 21 quota-entries in a block ++ */ ++struct v2_disk_dqdbheader { ++ __le32 dqdh_next_free; /* Number of next block with free entry */ ++ __le32 dqdh_prev_free; /* Number of previous block with free entry */ ++ __le16 dqdh_entries; /* Number of valid entries in block */ ++ __le16 dqdh_pad1; ++ __le32 dqdh_pad2; ++}; ++ ++#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ ++#define V2_DQBLKSIZE_BITS 10 ++#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ ++#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ ++#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ ++#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ ++ ++#endif /* _LINUX_QUOTAIO_V2_H */ +diff --git a/include/linux/quotaio_v1.h b/include/linux/quotaio_v1.h +deleted file mode 100644 +index 746654b..0000000 +--- a/include/linux/quotaio_v1.h ++++ /dev/null +@@ -1,33 +0,0 @@ +-#ifndef _LINUX_QUOTAIO_V1_H +-#define _LINUX_QUOTAIO_V1_H +- +-#include +- +-/* +- * The following constants define the amount of time given a user +- * before the soft limits are treated as hard limits (usually resulting +- * in an allocation failure). The timer is started when the user crosses +- * their soft limit, it is reset when they go below their soft limit. +- */ +-#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +-#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ +- +-/* +- * The following structure defines the format of the disk quota file +- * (as it appears on disk) - the file is an array of these structures +- * indexed by user or group number. +- */ +-struct v1_disk_dqblk { +- __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */ +- __u32 dqb_bsoftlimit; /* preferred limit on disk blks */ +- __u32 dqb_curblocks; /* current block count */ +- __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */ +- __u32 dqb_isoftlimit; /* preferred inode limit */ +- __u32 dqb_curinodes; /* current # allocated inodes */ +- time_t dqb_btime; /* time limit for excessive disk use */ +- time_t dqb_itime; /* time limit for excessive inode use */ +-}; +- +-#define v1_dqoff(UID) ((loff_t)((UID) * sizeof (struct v1_disk_dqblk))) +- +-#endif /* _LINUX_QUOTAIO_V1_H */ +diff --git a/include/linux/quotaio_v2.h b/include/linux/quotaio_v2.h +deleted file mode 100644 +index 303d7cb..0000000 +--- a/include/linux/quotaio_v2.h ++++ /dev/null +@@ -1,79 +0,0 @@ +-/* +- * Definitions of structures for vfsv0 quota format +- */ +- +-#ifndef _LINUX_QUOTAIO_V2_H +-#define _LINUX_QUOTAIO_V2_H +- +-#include +-#include +- +-/* +- * Definitions of magics and versions of current quota files +- */ +-#define V2_INITQMAGICS {\ +- 0xd9c01f11, /* USRQUOTA */\ +- 0xd9c01927 /* GRPQUOTA */\ +-} +- +-#define V2_INITQVERSIONS {\ +- 0, /* USRQUOTA */\ +- 0 /* GRPQUOTA */\ +-} +- +-/* +- * The following structure defines the format of the disk quota file +- * (as it appears on disk) - the file is a radix tree whose leaves point +- * to blocks of these structures. +- */ +-struct v2_disk_dqblk { +- __le32 dqb_id; /* id this quota applies to */ +- __le32 dqb_ihardlimit; /* absolute limit on allocated inodes */ +- __le32 dqb_isoftlimit; /* preferred inode limit */ +- __le32 dqb_curinodes; /* current # allocated inodes */ +- __le32 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ +- __le32 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ +- __le64 dqb_curspace; /* current space occupied (in bytes) */ +- __le64 dqb_btime; /* time limit for excessive disk use */ +- __le64 dqb_itime; /* time limit for excessive inode use */ +-}; +- +-/* +- * Here are header structures as written on disk and their in-memory copies +- */ +-/* First generic header */ +-struct v2_disk_dqheader { +- __le32 dqh_magic; /* Magic number identifying file */ +- __le32 dqh_version; /* File version */ +-}; +- +-/* Header with type and version specific information */ +-struct v2_disk_dqinfo { +- __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ +- __le32 dqi_igrace; /* Time before inode soft limit becomes hard limit */ +- __le32 dqi_flags; /* Flags for quotafile (DQF_*) */ +- __le32 dqi_blocks; /* Number of blocks in file */ +- __le32 dqi_free_blk; /* Number of first free block in the list */ +- __le32 dqi_free_entry; /* Number of block with at least one free entry */ +-}; +- +-/* +- * Structure of header of block with quota structures. It is padded to 16 bytes so +- * there will be space for exactly 21 quota-entries in a block +- */ +-struct v2_disk_dqdbheader { +- __le32 dqdh_next_free; /* Number of next block with free entry */ +- __le32 dqdh_prev_free; /* Number of previous block with free entry */ +- __le16 dqdh_entries; /* Number of valid entries in block */ +- __le16 dqdh_pad1; +- __le32 dqdh_pad2; +-}; +- +-#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +-#define V2_DQBLKSIZE_BITS 10 +-#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +-#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ +-#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +-#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ +- +-#endif /* _LINUX_QUOTAIO_V2_H */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Remove-bogus-optimization-in-check_idq-an.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Remove-bogus-optimization-in-check_idq-an.patch new file mode 100644 index 000000000..4859c2164 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Remove-bogus-optimization-in-check_idq-an.patch @@ -0,0 +1,39 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 03/28] quota: Remove bogus 'optimization' in check_idq() and check_bdq() +Patch-mainline: 2.6.29? + +Checks like <= 0 for an unsigned type do not make much sence. The value +could be only 0 and that does not happen often enough for the check +to be worth it. + +Signed-off-by: Jan Kara +--- + fs/dquot.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/dquot.c b/fs/dquot.c +index 758bf4a..e95ad55 100644 +--- a/fs/dquot.c ++++ b/fs/dquot.c +@@ -1041,7 +1041,7 @@ static inline char ignore_hardlimit(struct dquot *dquot) + static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) + { + *warntype = QUOTA_NL_NOWARN; +- if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) ++ if (test_bit(DQ_FAKE_B, &dquot->dq_flags)) + return QUOTA_OK; + + if (dquot->dq_dqb.dqb_ihardlimit && +@@ -1073,7 +1073,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) + static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) + { + *warntype = QUOTA_NL_NOWARN; +- if (space <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) ++ if (test_bit(DQ_FAKE_B, &dquot->dq_flags)) + return QUOTA_OK; + + if (dquot->dq_dqb.dqb_bhardlimit && +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Remove-compatibility-function-sb_any_quota_en.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Remove-compatibility-function-sb_any_quota_en.patch new file mode 100644 index 000000000..9df0a80fa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Remove-compatibility-function-sb_any_quota_en.patch @@ -0,0 +1,37 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 09/28] quota: Remove compatibility function sb_any_quota_enabled() +Patch-mainline: 2.6.29? + +Signed-off-by: Jan Kara +--- + include/linux/quotaops.h | 6 ------ + 1 files changed, 0 insertions(+), 6 deletions(-) + +diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h +index f7dcc30..94f00ec 100644 +--- a/include/linux/quotaops.h ++++ b/include/linux/quotaops.h +@@ -119,9 +119,6 @@ static inline int sb_any_quota_active(struct super_block *sb) + sb_has_quota_active(sb, GRPQUOTA); + } + +-/* For backward compatibility until we remove all users */ +-#define sb_any_quota_enabled(sb) sb_any_quota_active(sb) +- + /* + * Operations supported for diskquotas. + */ +@@ -265,9 +262,6 @@ static inline int sb_any_quota_active(struct super_block *sb) + return 0; + } + +-/* For backward compatibility until we remove all users */ +-#define sb_any_quota_enabled(sb) sb_any_quota_active(sb) +- + /* + * NO-OP when quota not configured. + */ +-- +1.5.2.4 + diff --git a/src/patches/suse-2.6.27.31/patches.suse/quota-Split-off-quota-tree-handling-into-a-separate.patch b/src/patches/suse-2.6.27.31/patches.suse/quota-Split-off-quota-tree-handling-into-a-separate.patch new file mode 100644 index 000000000..f6586ae8b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/quota-Split-off-quota-tree-handling-into-a-separate.patch @@ -0,0 +1,1570 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 12/28] quota: Split off quota tree handling into a separate file +Patch-mainline: 2.6.29? + +There is going to be a new version of quota format having 64-bit +quota limits and a new quota format for OCFS2. They are both +going to use the same tree structure as VFSv0 quota format. So +split out tree handling into a separate file and make size of +leaf blocks, amount of space usable in each block (needed for +checksumming) and structures contained in them configurable +so that the code can be shared. + +Signed-off-by: Jan Kara +--- + fs/Kconfig | 5 + fs/Makefile | 1 + fs/quota_tree.c | 645 ++++++++++++++++++++++++++++++++++++++++++++ + fs/quota_tree.h | 25 + + fs/quota_v2.c | 598 +++------------------------------------- + fs/quotaio_v2.h | 33 -- + include/linux/dqblk_qtree.h | 56 +++ + include/linux/dqblk_v2.h | 19 - + 8 files changed, 800 insertions(+), 582 deletions(-) + create mode 100644 fs/quota_tree.c + create mode 100644 fs/quota_tree.h + create mode 100644 include/linux/dqblk_qtree.h + +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -588,6 +588,10 @@ config PRINT_QUOTA_WARNING + Note that this behavior is currently deprecated and may go away in + future. Please use notification via netlink socket instead. + ++# Generic support for tree structured quota files. Seleted when needed. ++config QUOTA_TREE ++ tristate ++ + config QFMT_V1 + tristate "Old quota format support" + depends on QUOTA +@@ -599,6 +603,7 @@ config QFMT_V1 + config QFMT_V2 + tristate "Quota format v2 support" + depends on QUOTA ++ select QUOTA_TREE + help + This quota format allows using quotas with 32-bit UIDs/GIDs. If you + need this functionality say Y here. +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -53,6 +53,7 @@ obj-$(CONFIG_GENERIC_ACL) += generic_acl + obj-$(CONFIG_QUOTA) += dquot.o + obj-$(CONFIG_QFMT_V1) += quota_v1.o + obj-$(CONFIG_QFMT_V2) += quota_v2.o ++obj-$(CONFIG_QUOTA_TREE) += quota_tree.o + obj-$(CONFIG_QUOTACTL) += quota.o + + obj-$(CONFIG_DNOTIFY) += dnotify.o +--- /dev/null ++++ b/fs/quota_tree.c +@@ -0,0 +1,645 @@ ++/* ++ * vfsv0 quota IO operations on file ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "quota_tree.h" ++ ++MODULE_AUTHOR("Jan Kara"); ++MODULE_DESCRIPTION("Quota trie support"); ++MODULE_LICENSE("GPL"); ++ ++#define __QUOTA_QT_PARANOIA ++ ++typedef char *dqbuf_t; ++ ++static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) ++{ ++ unsigned int epb = info->dqi_usable_bs >> 2; ++ ++ depth = info->dqi_qtree_depth - depth - 1; ++ while (depth--) ++ id /= epb; ++ return id % epb; ++} ++ ++/* Number of entries in one blocks */ ++static inline int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) ++{ ++ return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) ++ / info->dqi_entry_size; ++} ++ ++static dqbuf_t getdqbuf(size_t size) ++{ ++ dqbuf_t buf = kmalloc(size, GFP_NOFS); ++ if (!buf) ++ printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); ++ return buf; ++} ++ ++static inline void freedqbuf(dqbuf_t buf) ++{ ++ kfree(buf); ++} ++ ++static inline ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf) ++{ ++ struct super_block *sb = info->dqi_sb; ++ ++ memset(buf, 0, info->dqi_usable_bs); ++ return sb->s_op->quota_read(sb, info->dqi_type, (char *)buf, ++ info->dqi_usable_bs, blk << info->dqi_blocksize_bits); ++} ++ ++static inline ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, dqbuf_t buf) ++{ ++ struct super_block *sb = info->dqi_sb; ++ ++ return sb->s_op->quota_write(sb, info->dqi_type, (char *)buf, ++ info->dqi_usable_bs, blk << info->dqi_blocksize_bits); ++} ++ ++/* Remove empty block from list and return it */ ++static int get_free_dqblk(struct qtree_mem_dqinfo *info) ++{ ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ int ret, blk; ++ ++ if (!buf) ++ return -ENOMEM; ++ if (info->dqi_free_blk) { ++ blk = info->dqi_free_blk; ++ ret = read_blk(info, blk, buf); ++ if (ret < 0) ++ goto out_buf; ++ info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); ++ } ++ else { ++ memset(buf, 0, info->dqi_usable_bs); ++ /* Assure block allocation... */ ++ ret = write_blk(info, info->dqi_blocks, buf); ++ if (ret < 0) ++ goto out_buf; ++ blk = info->dqi_blocks++; ++ } ++ mark_info_dirty(info->dqi_sb, info->dqi_type); ++ ret = blk; ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Insert empty block to the list */ ++static int put_free_dqblk(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) ++{ ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ int err; ++ ++ dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); ++ dh->dqdh_prev_free = cpu_to_le32(0); ++ dh->dqdh_entries = cpu_to_le16(0); ++ err = write_blk(info, blk, buf); ++ if (err < 0) ++ return err; ++ info->dqi_free_blk = blk; ++ mark_info_dirty(info->dqi_sb, info->dqi_type); ++ return 0; ++} ++ ++/* Remove given block from the list of blocks with free entries */ ++static int remove_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) ++{ ++ dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs); ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ uint nextblk = le32_to_cpu(dh->dqdh_next_free); ++ uint prevblk = le32_to_cpu(dh->dqdh_prev_free); ++ int err; ++ ++ if (!tmpbuf) ++ return -ENOMEM; ++ if (nextblk) { ++ err = read_blk(info, nextblk, tmpbuf); ++ if (err < 0) ++ goto out_buf; ++ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = ++ dh->dqdh_prev_free; ++ err = write_blk(info, nextblk, tmpbuf); ++ if (err < 0) ++ goto out_buf; ++ } ++ if (prevblk) { ++ err = read_blk(info, prevblk, tmpbuf); ++ if (err < 0) ++ goto out_buf; ++ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = ++ dh->dqdh_next_free; ++ err = write_blk(info, prevblk, tmpbuf); ++ if (err < 0) ++ goto out_buf; ++ } else { ++ info->dqi_free_entry = nextblk; ++ mark_info_dirty(info->dqi_sb, info->dqi_type); ++ } ++ freedqbuf(tmpbuf); ++ dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); ++ /* No matter whether write succeeds block is out of list */ ++ if (write_blk(info, blk, buf) < 0) ++ printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); ++ return 0; ++out_buf: ++ freedqbuf(tmpbuf); ++ return err; ++} ++ ++/* Insert given block to the beginning of list with free entries */ ++static int insert_free_dqentry(struct qtree_mem_dqinfo *info, dqbuf_t buf, uint blk) ++{ ++ dqbuf_t tmpbuf = getdqbuf(info->dqi_usable_bs); ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ int err; ++ ++ if (!tmpbuf) ++ return -ENOMEM; ++ dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); ++ dh->dqdh_prev_free = cpu_to_le32(0); ++ err = write_blk(info, blk, buf); ++ if (err < 0) ++ goto out_buf; ++ if (info->dqi_free_entry) { ++ err = read_blk(info, info->dqi_free_entry, tmpbuf); ++ if (err < 0) ++ goto out_buf; ++ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = ++ cpu_to_le32(blk); ++ err = write_blk(info, info->dqi_free_entry, tmpbuf); ++ if (err < 0) ++ goto out_buf; ++ } ++ freedqbuf(tmpbuf); ++ info->dqi_free_entry = blk; ++ mark_info_dirty(info->dqi_sb, info->dqi_type); ++ return 0; ++out_buf: ++ freedqbuf(tmpbuf); ++ return err; ++} ++ ++/* Is the entry in the block free? */ ++int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) ++{ ++ int i; ++ ++ for (i = 0; i < info->dqi_entry_size; i++) ++ if (disk[i]) ++ return 0; ++ return 1; ++} ++EXPORT_SYMBOL(qtree_entry_unused); ++ ++/* Find space for dquot */ ++static uint find_free_dqentry(struct qtree_mem_dqinfo *info, ++ struct dquot *dquot, int *err) ++{ ++ uint blk, i; ++ struct qt_disk_dqdbheader *dh; ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ char *ddquot; ++ ++ *err = 0; ++ if (!buf) { ++ *err = -ENOMEM; ++ return 0; ++ } ++ dh = (struct qt_disk_dqdbheader *)buf; ++ if (info->dqi_free_entry) { ++ blk = info->dqi_free_entry; ++ *err = read_blk(info, blk, buf); ++ if (*err < 0) ++ goto out_buf; ++ } else { ++ blk = get_free_dqblk(info); ++ if ((int)blk < 0) { ++ *err = blk; ++ freedqbuf(buf); ++ return 0; ++ } ++ memset(buf, 0, info->dqi_usable_bs); ++ /* This is enough as block is already zeroed and entry list is empty... */ ++ info->dqi_free_entry = blk; ++ mark_info_dirty(dquot->dq_sb, dquot->dq_type); ++ } ++ /* Block will be full? */ ++ if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { ++ *err = remove_free_dqentry(info, buf, blk); ++ if (*err < 0) { ++ printk(KERN_ERR "VFS: find_free_dqentry(): Can't " ++ "remove block (%u) from entry free list.\n", ++ blk); ++ goto out_buf; ++ } ++ } ++ le16_add_cpu(&dh->dqdh_entries, 1); ++ /* Find free structure in block */ ++ for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader); ++ i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); ++ i++, ddquot += info->dqi_entry_size); ++#ifdef __QUOTA_QT_PARANOIA ++ if (i == qtree_dqstr_in_blk(info)) { ++ printk(KERN_ERR "VFS: find_free_dqentry(): Data block full " ++ "but it shouldn't.\n"); ++ *err = -EIO; ++ goto out_buf; ++ } ++#endif ++ *err = write_blk(info, blk, buf); ++ if (*err < 0) { ++ printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota " ++ "data block %u.\n", blk); ++ goto out_buf; ++ } ++ dquot->dq_off = (blk << info->dqi_blocksize_bits) + ++ sizeof(struct qt_disk_dqdbheader) + ++ i * info->dqi_entry_size; ++ freedqbuf(buf); ++ return blk; ++out_buf: ++ freedqbuf(buf); ++ return 0; ++} ++ ++/* Insert reference to structure into the trie */ ++static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, ++ uint *treeblk, int depth) ++{ ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ int ret = 0, newson = 0, newact = 0; ++ __le32 *ref; ++ uint newblk; ++ ++ if (!buf) ++ return -ENOMEM; ++ if (!*treeblk) { ++ ret = get_free_dqblk(info); ++ if (ret < 0) ++ goto out_buf; ++ *treeblk = ret; ++ memset(buf, 0, info->dqi_usable_bs); ++ newact = 1; ++ } else { ++ ret = read_blk(info, *treeblk, buf); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't read tree quota block " ++ "%u.\n", *treeblk); ++ goto out_buf; ++ } ++ } ++ ref = (__le32 *)buf; ++ newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); ++ if (!newblk) ++ newson = 1; ++ if (depth == info->dqi_qtree_depth - 1) { ++#ifdef __QUOTA_QT_PARANOIA ++ if (newblk) { ++ printk(KERN_ERR "VFS: Inserting already present quota " ++ "entry (block %u).\n", ++ le32_to_cpu(ref[get_index(info, ++ dquot->dq_id, depth)])); ++ ret = -EIO; ++ goto out_buf; ++ } ++#endif ++ newblk = find_free_dqentry(info, dquot, &ret); ++ } else { ++ ret = do_insert_tree(info, dquot, &newblk, depth+1); ++ } ++ if (newson && ret >= 0) { ++ ref[get_index(info, dquot->dq_id, depth)] = ++ cpu_to_le32(newblk); ++ ret = write_blk(info, *treeblk, buf); ++ } else if (newact && ret < 0) { ++ put_free_dqblk(info, buf, *treeblk); ++ } ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Wrapper for inserting quota structure into tree */ ++static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, ++ struct dquot *dquot) ++{ ++ int tmp = QT_TREEOFF; ++ return do_insert_tree(info, dquot, &tmp, 0); ++} ++ ++/* ++ * We don't have to be afraid of deadlocks as we never have quotas on quota files... ++ */ ++int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ++{ ++ int type = dquot->dq_type; ++ struct super_block *sb = dquot->dq_sb; ++ ssize_t ret; ++ dqbuf_t ddquot = getdqbuf(info->dqi_entry_size); ++ ++ if (!ddquot) ++ return -ENOMEM; ++ ++ /* dq_off is guarded by dqio_mutex */ ++ if (!dquot->dq_off) { ++ ret = dq_insert_tree(info, dquot); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Error %zd occurred while " ++ "creating quota.\n", ret); ++ freedqbuf(ddquot); ++ return ret; ++ } ++ } ++ spin_lock(&dq_data_lock); ++ info->dqi_ops->mem2disk_dqblk(ddquot, dquot); ++ spin_unlock(&dq_data_lock); ++ ret = sb->s_op->quota_write(sb, type, (char *)ddquot, ++ info->dqi_entry_size, dquot->dq_off); ++ if (ret != info->dqi_entry_size) { ++ printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", ++ sb->s_id); ++ if (ret >= 0) ++ ret = -ENOSPC; ++ } else { ++ ret = 0; ++ } ++ dqstats.writes++; ++ freedqbuf(ddquot); ++ ++ return ret; ++} ++EXPORT_SYMBOL(qtree_write_dquot); ++ ++/* Free dquot entry in data block */ ++static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, ++ uint blk) ++{ ++ struct qt_disk_dqdbheader *dh; ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ int ret = 0; ++ ++ if (!buf) ++ return -ENOMEM; ++ if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { ++ printk(KERN_ERR "VFS: Quota structure has offset to other " ++ "block (%u) than it should (%u).\n", blk, ++ (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); ++ goto out_buf; ++ } ++ ret = read_blk(info, blk, buf); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); ++ goto out_buf; ++ } ++ dh = (struct qt_disk_dqdbheader *)buf; ++ le16_add_cpu(&dh->dqdh_entries, -1); ++ if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ ++ ret = remove_free_dqentry(info, buf, blk); ++ if (ret >= 0) ++ ret = put_free_dqblk(info, buf, blk); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't move quota data block (%u) " ++ "to free list.\n", blk); ++ goto out_buf; ++ } ++ } else { ++ memset(buf + ++ (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)), ++ 0, info->dqi_entry_size); ++ if (le16_to_cpu(dh->dqdh_entries) == ++ qtree_dqstr_in_blk(info) - 1) { ++ /* Insert will write block itself */ ++ ret = insert_free_dqentry(info, buf, blk); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't insert quota data " ++ "block (%u) to free entry list.\n", blk); ++ goto out_buf; ++ } ++ } else { ++ ret = write_blk(info, blk, buf); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't write quota data " ++ "block %u\n", blk); ++ goto out_buf; ++ } ++ } ++ } ++ dquot->dq_off = 0; /* Quota is now unattached */ ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Remove reference to dquot from tree */ ++static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, ++ uint *blk, int depth) ++{ ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ int ret = 0; ++ uint newblk; ++ __le32 *ref = (__le32 *)buf; ++ ++ if (!buf) ++ return -ENOMEM; ++ ret = read_blk(info, *blk, buf); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); ++ goto out_buf; ++ } ++ newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); ++ if (depth == info->dqi_qtree_depth - 1) { ++ ret = free_dqentry(info, dquot, newblk); ++ newblk = 0; ++ } else { ++ ret = remove_tree(info, dquot, &newblk, depth+1); ++ } ++ if (ret >= 0 && !newblk) { ++ int i; ++ ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); ++ /* Block got empty? */ ++ for (i = 0; ++ i < (info->dqi_usable_bs >> 2) && !ref[i]; ++ i++); ++ /* Don't put the root block into the free block list */ ++ if (i == (info->dqi_usable_bs >> 2) ++ && *blk != QT_TREEOFF) { ++ put_free_dqblk(info, buf, *blk); ++ *blk = 0; ++ } else { ++ ret = write_blk(info, *blk, buf); ++ if (ret < 0) ++ printk(KERN_ERR "VFS: Can't write quota tree " ++ "block %u.\n", *blk); ++ } ++ } ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Delete dquot from tree */ ++int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ++{ ++ uint tmp = QT_TREEOFF; ++ ++ if (!dquot->dq_off) /* Even not allocated? */ ++ return 0; ++ return remove_tree(info, dquot, &tmp, 0); ++} ++EXPORT_SYMBOL(qtree_delete_dquot); ++ ++/* Find entry in block */ ++static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, ++ struct dquot *dquot, uint blk) ++{ ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ loff_t ret = 0; ++ int i; ++ char *ddquot; ++ ++ if (!buf) ++ return -ENOMEM; ++ ret = read_blk(info, blk, buf); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); ++ goto out_buf; ++ } ++ for (i = 0, ddquot = ((char *)buf) + sizeof(struct qt_disk_dqdbheader); ++ i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); ++ i++, ddquot += info->dqi_entry_size); ++ if (i == qtree_dqstr_in_blk(info)) { ++ printk(KERN_ERR "VFS: Quota for id %u referenced " ++ "but not present.\n", dquot->dq_id); ++ ret = -EIO; ++ goto out_buf; ++ } else { ++ ret = (blk << info->dqi_blocksize_bits) + sizeof(struct ++ qt_disk_dqdbheader) + i * info->dqi_entry_size; ++ } ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Find entry for given id in the tree */ ++static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, ++ struct dquot *dquot, uint blk, int depth) ++{ ++ dqbuf_t buf = getdqbuf(info->dqi_usable_bs); ++ loff_t ret = 0; ++ __le32 *ref = (__le32 *)buf; ++ ++ if (!buf) ++ return -ENOMEM; ++ ret = read_blk(info, blk, buf); ++ if (ret < 0) { ++ printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); ++ goto out_buf; ++ } ++ ret = 0; ++ blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); ++ if (!blk) /* No reference? */ ++ goto out_buf; ++ if (depth < info->dqi_qtree_depth - 1) ++ ret = find_tree_dqentry(info, dquot, blk, depth+1); ++ else ++ ret = find_block_dqentry(info, dquot, blk); ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Find entry for given id in the tree - wrapper function */ ++static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info, ++ struct dquot *dquot) ++{ ++ return find_tree_dqentry(info, dquot, QT_TREEOFF, 0); ++} ++ ++int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ++{ ++ int type = dquot->dq_type; ++ struct super_block *sb = dquot->dq_sb; ++ loff_t offset; ++ dqbuf_t ddquot; ++ int ret = 0; ++ ++#ifdef __QUOTA_QT_PARANOIA ++ /* Invalidated quota? */ ++ if (!sb_dqopt(dquot->dq_sb)->files[type]) { ++ printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); ++ return -EIO; ++ } ++#endif ++ /* Do we know offset of the dquot entry in the quota file? */ ++ if (!dquot->dq_off) { ++ offset = find_dqentry(info, dquot); ++ if (offset <= 0) { /* Entry not present? */ ++ if (offset < 0) ++ printk(KERN_ERR "VFS: Can't read quota " ++ "structure for id %u.\n", dquot->dq_id); ++ dquot->dq_off = 0; ++ set_bit(DQ_FAKE_B, &dquot->dq_flags); ++ memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); ++ ret = offset; ++ goto out; ++ } ++ dquot->dq_off = offset; ++ } ++ ddquot = getdqbuf(info->dqi_entry_size); ++ if (!ddquot) ++ return -ENOMEM; ++ ret = sb->s_op->quota_read(sb, type, (char *)ddquot, ++ info->dqi_entry_size, dquot->dq_off); ++ if (ret != info->dqi_entry_size) { ++ if (ret >= 0) ++ ret = -EIO; ++ printk(KERN_ERR "VFS: Error while reading quota " ++ "structure for id %u.\n", dquot->dq_id); ++ set_bit(DQ_FAKE_B, &dquot->dq_flags); ++ memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); ++ freedqbuf(ddquot); ++ goto out; ++ } ++ spin_lock(&dq_data_lock); ++ info->dqi_ops->disk2mem_dqblk(dquot, ddquot); ++ if (!dquot->dq_dqb.dqb_bhardlimit && ++ !dquot->dq_dqb.dqb_bsoftlimit && ++ !dquot->dq_dqb.dqb_ihardlimit && ++ !dquot->dq_dqb.dqb_isoftlimit) ++ set_bit(DQ_FAKE_B, &dquot->dq_flags); ++ spin_unlock(&dq_data_lock); ++ freedqbuf(ddquot); ++out: ++ dqstats.reads++; ++ return ret; ++} ++EXPORT_SYMBOL(qtree_read_dquot); ++ ++/* Check whether dquot should not be deleted. We know we are ++ * the only one operating on dquot (thanks to dq_lock) */ ++int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ++{ ++ if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) ++ return qtree_delete_dquot(info, dquot); ++ return 0; ++} ++EXPORT_SYMBOL(qtree_release_dquot); +--- /dev/null ++++ b/fs/quota_tree.h +@@ -0,0 +1,25 @@ ++/* ++ * Definitions of structures for vfsv0 quota format ++ */ ++ ++#ifndef _LINUX_QUOTA_TREE_H ++#define _LINUX_QUOTA_TREE_H ++ ++#include ++#include ++ ++/* ++ * Structure of header of block with quota structures. It is padded to 16 bytes so ++ * there will be space for exactly 21 quota-entries in a block ++ */ ++struct qt_disk_dqdbheader { ++ __le32 dqdh_next_free; /* Number of next block with free entry */ ++ __le32 dqdh_prev_free; /* Number of previous block with free entry */ ++ __le16 dqdh_entries; /* Number of valid entries in block */ ++ __le16 dqdh_pad1; ++ __le32 dqdh_pad2; ++}; ++ ++#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ ++ ++#endif /* _LINUX_QUOTAIO_TREE_H */ +--- a/fs/quota_v2.c ++++ b/fs/quota_v2.c +@@ -14,6 +14,7 @@ + + #include + ++#include "quota_tree.h" + #include "quotaio_v2.h" + + MODULE_AUTHOR("Jan Kara"); +@@ -22,10 +23,15 @@ MODULE_LICENSE("GPL"); + + #define __QUOTA_V2_PARANOIA + +-typedef char *dqbuf_t; +- +-#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) +-#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) ++static void v2_mem2diskdqb(void *dp, struct dquot *dquot); ++static void v2_disk2memdqb(struct dquot *dquot, void *dp); ++static int v2_is_id(void *dp, struct dquot *dquot); ++ ++static struct qtree_fmt_operations v2_qtree_ops = { ++ .mem2disk_dqblk = v2_mem2diskdqb, ++ .disk2mem_dqblk = v2_disk2memdqb, ++ .is_id = v2_is_id, ++}; + + #define QUOTABLOCK_BITS 10 + #define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) +@@ -64,7 +70,7 @@ static int v2_check_quota_file(struct su + static int v2_read_file_info(struct super_block *sb, int type) + { + struct v2_disk_dqinfo dinfo; +- struct mem_dqinfo *info = sb_dqopt(sb)->info+type; ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); + ssize_t size; + + size = sb->s_op->quota_read(sb, type, (char *)&dinfo, +@@ -80,9 +86,16 @@ static int v2_read_file_info(struct supe + info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); + info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); + info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); +- info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); +- info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); +- info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); ++ info->u.v2_i.i.dqi_sb = sb; ++ info->u.v2_i.i.dqi_type = type; ++ info->u.v2_i.i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); ++ info->u.v2_i.i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); ++ info->u.v2_i.i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); ++ info->u.v2_i.i.dqi_blocksize_bits = V2_DQBLKSIZE_BITS; ++ info->u.v2_i.i.dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS; ++ info->u.v2_i.i.dqi_qtree_depth = qtree_depth(&info->u.v2_i.i); ++ info->u.v2_i.i.dqi_entry_size = sizeof(struct v2_disk_dqblk); ++ info->u.v2_i.i.dqi_ops = &v2_qtree_ops; + return 0; + } + +@@ -90,7 +103,7 @@ static int v2_read_file_info(struct supe + static int v2_write_file_info(struct super_block *sb, int type) + { + struct v2_disk_dqinfo dinfo; +- struct mem_dqinfo *info = sb_dqopt(sb)->info+type; ++ struct mem_dqinfo *info = sb_dqinfo(sb, type); + ssize_t size; + + spin_lock(&dq_data_lock); +@@ -99,9 +112,9 @@ static int v2_write_file_info(struct sup + dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); + dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); + spin_unlock(&dq_data_lock); +- dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks); +- dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk); +- dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry); ++ dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.i.dqi_blocks); ++ dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.i.dqi_free_blk); ++ dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.i.dqi_free_entry); + size = sb->s_op->quota_write(sb, type, (char *)&dinfo, + sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); + if (size != sizeof(struct v2_disk_dqinfo)) { +@@ -112,8 +125,11 @@ static int v2_write_file_info(struct sup + return 0; + } + +-static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) ++static void v2_disk2memdqb(struct dquot *dquot, void *dp) + { ++ struct v2_disk_dqblk *d = dp, empty; ++ struct mem_dqblk *m = &dquot->dq_dqb; ++ + m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); + m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); +@@ -122,10 +138,20 @@ static void disk2memdqb(struct mem_dqblk + m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit)); + m->dqb_curspace = le64_to_cpu(d->dqb_curspace); + m->dqb_btime = le64_to_cpu(d->dqb_btime); ++ /* We need to escape back all-zero structure */ ++ memset(&empty, 0, sizeof(struct v2_disk_dqblk)); ++ empty.dqb_itime = cpu_to_le64(1); ++ if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk))) ++ m->dqb_itime = 0; + } + +-static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) ++static void v2_mem2diskdqb(void *dp, struct dquot *dquot) + { ++ struct v2_disk_dqblk *d = dp; ++ struct mem_dqblk *m = &dquot->dq_dqb; ++ struct qtree_mem_dqinfo *info = ++ &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i; ++ + d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); + d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); + d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); +@@ -134,553 +160,35 @@ static void mem2diskdqb(struct v2_disk_d + d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit)); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_btime = cpu_to_le64(m->dqb_btime); +- d->dqb_id = cpu_to_le32(id); +-} +- +-static dqbuf_t getdqbuf(void) +-{ +- dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS); +- if (!buf) +- printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); +- return buf; +-} +- +-static inline void freedqbuf(dqbuf_t buf) +-{ +- kfree(buf); +-} +- +-static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf) +-{ +- memset(buf, 0, V2_DQBLKSIZE); +- return sb->s_op->quota_read(sb, type, (char *)buf, +- V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS); +-} +- +-static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf) +-{ +- return sb->s_op->quota_write(sb, type, (char *)buf, +- V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS); +-} +- +-/* Remove empty block from list and return it */ +-static int get_free_dqblk(struct super_block *sb, int type) +-{ +- dqbuf_t buf = getdqbuf(); +- struct mem_dqinfo *info = sb_dqinfo(sb, type); +- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; +- int ret, blk; +- +- if (!buf) +- return -ENOMEM; +- if (info->u.v2_i.dqi_free_blk) { +- blk = info->u.v2_i.dqi_free_blk; +- if ((ret = read_blk(sb, type, blk, buf)) < 0) +- goto out_buf; +- info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); +- } +- else { +- memset(buf, 0, V2_DQBLKSIZE); +- /* Assure block allocation... */ +- if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0) +- goto out_buf; +- blk = info->u.v2_i.dqi_blocks++; +- } +- mark_info_dirty(sb, type); +- ret = blk; +-out_buf: +- freedqbuf(buf); +- return ret; ++ d->dqb_id = cpu_to_le32(dquot->dq_id); ++ if (qtree_entry_unused(info, dp)) ++ d->dqb_itime = cpu_to_le64(1); + } + +-/* Insert empty block to the list */ +-static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk) ++static int v2_is_id(void *dp, struct dquot *dquot) + { +- struct mem_dqinfo *info = sb_dqinfo(sb, type); +- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; +- int err; +- +- dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk); +- dh->dqdh_prev_free = cpu_to_le32(0); +- dh->dqdh_entries = cpu_to_le16(0); +- info->u.v2_i.dqi_free_blk = blk; +- mark_info_dirty(sb, type); +- /* Some strange block. We had better leave it... */ +- if ((err = write_blk(sb, type, blk, buf)) < 0) +- return err; +- return 0; +-} ++ struct v2_disk_dqblk *d = dp; ++ struct qtree_mem_dqinfo *info = ++ &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i; + +-/* Remove given block from the list of blocks with free entries */ +-static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk) +-{ +- dqbuf_t tmpbuf = getdqbuf(); +- struct mem_dqinfo *info = sb_dqinfo(sb, type); +- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; +- uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free); +- int err; +- +- if (!tmpbuf) +- return -ENOMEM; +- if (nextblk) { +- if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0) +- goto out_buf; +- ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; +- if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0) +- goto out_buf; +- } +- if (prevblk) { +- if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0) +- goto out_buf; +- ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; +- if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0) +- goto out_buf; +- } +- else { +- info->u.v2_i.dqi_free_entry = nextblk; +- mark_info_dirty(sb, type); +- } +- freedqbuf(tmpbuf); +- dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); +- /* No matter whether write succeeds block is out of list */ +- if (write_blk(sb, type, blk, buf) < 0) +- printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); +- return 0; +-out_buf: +- freedqbuf(tmpbuf); +- return err; +-} +- +-/* Insert given block to the beginning of list with free entries */ +-static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk) +-{ +- dqbuf_t tmpbuf = getdqbuf(); +- struct mem_dqinfo *info = sb_dqinfo(sb, type); +- struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; +- int err; +- +- if (!tmpbuf) +- return -ENOMEM; +- dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry); +- dh->dqdh_prev_free = cpu_to_le32(0); +- if ((err = write_blk(sb, type, blk, buf)) < 0) +- goto out_buf; +- if (info->u.v2_i.dqi_free_entry) { +- if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) +- goto out_buf; +- ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk); +- if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) +- goto out_buf; +- } +- freedqbuf(tmpbuf); +- info->u.v2_i.dqi_free_entry = blk; +- mark_info_dirty(sb, type); +- return 0; +-out_buf: +- freedqbuf(tmpbuf); +- return err; +-} +- +-/* Find space for dquot */ +-static uint find_free_dqentry(struct dquot *dquot, int *err) +-{ +- struct super_block *sb = dquot->dq_sb; +- struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type; +- uint blk, i; +- struct v2_disk_dqdbheader *dh; +- struct v2_disk_dqblk *ddquot; +- struct v2_disk_dqblk fakedquot; +- dqbuf_t buf; +- +- *err = 0; +- if (!(buf = getdqbuf())) { +- *err = -ENOMEM; ++ if (qtree_entry_unused(info, dp)) + return 0; +- } +- dh = (struct v2_disk_dqdbheader *)buf; +- ddquot = GETENTRIES(buf); +- if (info->u.v2_i.dqi_free_entry) { +- blk = info->u.v2_i.dqi_free_entry; +- if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0) +- goto out_buf; +- } +- else { +- blk = get_free_dqblk(sb, dquot->dq_type); +- if ((int)blk < 0) { +- *err = blk; +- freedqbuf(buf); +- return 0; +- } +- memset(buf, 0, V2_DQBLKSIZE); +- /* This is enough as block is already zeroed and entry list is empty... */ +- info->u.v2_i.dqi_free_entry = blk; +- mark_info_dirty(sb, dquot->dq_type); +- } +- if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */ +- if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) { +- printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk); +- goto out_buf; +- } +- le16_add_cpu(&dh->dqdh_entries, 1); +- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); +- /* Find free structure in block */ +- for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++); +-#ifdef __QUOTA_V2_PARANOIA +- if (i == V2_DQSTRINBLK) { +- printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n"); +- *err = -EIO; +- goto out_buf; +- } +-#endif +- if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) { +- printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); +- goto out_buf; +- } +- dquot->dq_off = (blk<dq_sb; +- dqbuf_t buf; +- int ret = 0, newson = 0, newact = 0; +- __le32 *ref; +- uint newblk; +- +- if (!(buf = getdqbuf())) +- return -ENOMEM; +- if (!*treeblk) { +- ret = get_free_dqblk(sb, dquot->dq_type); +- if (ret < 0) +- goto out_buf; +- *treeblk = ret; +- memset(buf, 0, V2_DQBLKSIZE); +- newact = 1; +- } +- else { +- if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) { +- printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk); +- goto out_buf; +- } +- } +- ref = (__le32 *)buf; +- newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); +- if (!newblk) +- newson = 1; +- if (depth == V2_DQTREEDEPTH-1) { +-#ifdef __QUOTA_V2_PARANOIA +- if (newblk) { +- printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)])); +- ret = -EIO; +- goto out_buf; +- } +-#endif +- newblk = find_free_dqentry(dquot, &ret); +- } +- else +- ret = do_insert_tree(dquot, &newblk, depth+1); +- if (newson && ret >= 0) { +- ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk); +- ret = write_blk(sb, dquot->dq_type, *treeblk, buf); +- } +- else if (newact && ret < 0) +- put_free_dqblk(sb, dquot->dq_type, buf, *treeblk); +-out_buf: +- freedqbuf(buf); +- return ret; ++ return le32_to_cpu(d->dqb_id) == dquot->dq_id; + } + +-/* Wrapper for inserting quota structure into tree */ +-static inline int dq_insert_tree(struct dquot *dquot) ++static int v2_read_dquot(struct dquot *dquot) + { +- int tmp = V2_DQTREEOFF; +- return do_insert_tree(dquot, &tmp, 0); ++ return qtree_read_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); + } + +-/* +- * We don't have to be afraid of deadlocks as we never have quotas on quota files... +- */ + static int v2_write_dquot(struct dquot *dquot) + { +- int type = dquot->dq_type; +- ssize_t ret; +- struct v2_disk_dqblk ddquot, empty; +- +- /* dq_off is guarded by dqio_mutex */ +- if (!dquot->dq_off) +- if ((ret = dq_insert_tree(dquot)) < 0) { +- printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret); +- return ret; +- } +- spin_lock(&dq_data_lock); +- mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); +- /* Argh... We may need to write structure full of zeroes but that would be +- * treated as an empty place by the rest of the code. Format change would +- * be definitely cleaner but the problems probably are not worth it */ +- memset(&empty, 0, sizeof(struct v2_disk_dqblk)); +- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) +- ddquot.dqb_itime = cpu_to_le64(1); +- spin_unlock(&dq_data_lock); +- ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, +- (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off); +- if (ret != sizeof(struct v2_disk_dqblk)) { +- printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id); +- if (ret >= 0) +- ret = -ENOSPC; +- } +- else +- ret = 0; +- dqstats.writes++; +- +- return ret; +-} +- +-/* Free dquot entry in data block */ +-static int free_dqentry(struct dquot *dquot, uint blk) +-{ +- struct super_block *sb = dquot->dq_sb; +- int type = dquot->dq_type; +- struct v2_disk_dqdbheader *dh; +- dqbuf_t buf = getdqbuf(); +- int ret = 0; +- +- if (!buf) +- return -ENOMEM; +- if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) { +- printk(KERN_ERR "VFS: Quota structure has offset to other " +- "block (%u) than it should (%u).\n", blk, +- (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS)); +- goto out_buf; +- } +- if ((ret = read_blk(sb, type, blk, buf)) < 0) { +- printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); +- goto out_buf; +- } +- dh = (struct v2_disk_dqdbheader *)buf; +- le16_add_cpu(&dh->dqdh_entries, -1); +- if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ +- if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 || +- (ret = put_free_dqblk(sb, type, buf, blk)) < 0) { +- printk(KERN_ERR "VFS: Can't move quota data block (%u) " +- "to free list.\n", blk); +- goto out_buf; +- } +- } +- else { +- memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, +- sizeof(struct v2_disk_dqblk)); +- if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) { +- /* Insert will write block itself */ +- if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) { +- printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk); +- goto out_buf; +- } +- } +- else +- if ((ret = write_blk(sb, type, blk, buf)) < 0) { +- printk(KERN_ERR "VFS: Can't write quota data " +- "block %u\n", blk); +- goto out_buf; +- } +- } +- dquot->dq_off = 0; /* Quota is now unattached */ +-out_buf: +- freedqbuf(buf); +- return ret; +-} +- +-/* Remove reference to dquot from tree */ +-static int remove_tree(struct dquot *dquot, uint *blk, int depth) +-{ +- struct super_block *sb = dquot->dq_sb; +- int type = dquot->dq_type; +- dqbuf_t buf = getdqbuf(); +- int ret = 0; +- uint newblk; +- __le32 *ref = (__le32 *)buf; +- +- if (!buf) +- return -ENOMEM; +- if ((ret = read_blk(sb, type, *blk, buf)) < 0) { +- printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); +- goto out_buf; +- } +- newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); +- if (depth == V2_DQTREEDEPTH-1) { +- ret = free_dqentry(dquot, newblk); +- newblk = 0; +- } +- else +- ret = remove_tree(dquot, &newblk, depth+1); +- if (ret >= 0 && !newblk) { +- int i; +- ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0); +- for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ +- /* Don't put the root block into the free block list */ +- if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) { +- put_free_dqblk(sb, type, buf, *blk); +- *blk = 0; +- } +- else +- if ((ret = write_blk(sb, type, *blk, buf)) < 0) +- printk(KERN_ERR "VFS: Can't write quota tree " +- "block %u.\n", *blk); +- } +-out_buf: +- freedqbuf(buf); +- return ret; ++ return qtree_write_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); + } + +-/* Delete dquot from tree */ +-static int v2_delete_dquot(struct dquot *dquot) +-{ +- uint tmp = V2_DQTREEOFF; +- +- if (!dquot->dq_off) /* Even not allocated? */ +- return 0; +- return remove_tree(dquot, &tmp, 0); +-} +- +-/* Find entry in block */ +-static loff_t find_block_dqentry(struct dquot *dquot, uint blk) +-{ +- dqbuf_t buf = getdqbuf(); +- loff_t ret = 0; +- int i; +- struct v2_disk_dqblk *ddquot = GETENTRIES(buf); +- +- if (!buf) +- return -ENOMEM; +- if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) { +- printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); +- goto out_buf; +- } +- if (dquot->dq_id) +- for (i = 0; i < V2_DQSTRINBLK && +- le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++); +- else { /* ID 0 as a bit more complicated searching... */ +- struct v2_disk_dqblk fakedquot; +- +- memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); +- for (i = 0; i < V2_DQSTRINBLK; i++) +- if (!le32_to_cpu(ddquot[i].dqb_id) && +- memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk))) +- break; +- } +- if (i == V2_DQSTRINBLK) { +- printk(KERN_ERR "VFS: Quota for id %u referenced " +- "but not present.\n", dquot->dq_id); +- ret = -EIO; +- goto out_buf; +- } +- else +- ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct +- v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk); +-out_buf: +- freedqbuf(buf); +- return ret; +-} +- +-/* Find entry for given id in the tree */ +-static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth) +-{ +- dqbuf_t buf = getdqbuf(); +- loff_t ret = 0; +- __le32 *ref = (__le32 *)buf; +- +- if (!buf) +- return -ENOMEM; +- if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) { +- printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); +- goto out_buf; +- } +- ret = 0; +- blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); +- if (!blk) /* No reference? */ +- goto out_buf; +- if (depth < V2_DQTREEDEPTH-1) +- ret = find_tree_dqentry(dquot, blk, depth+1); +- else +- ret = find_block_dqentry(dquot, blk); +-out_buf: +- freedqbuf(buf); +- return ret; +-} +- +-/* Find entry for given id in the tree - wrapper function */ +-static inline loff_t find_dqentry(struct dquot *dquot) +-{ +- return find_tree_dqentry(dquot, V2_DQTREEOFF, 0); +-} +- +-static int v2_read_dquot(struct dquot *dquot) +-{ +- int type = dquot->dq_type; +- loff_t offset; +- struct v2_disk_dqblk ddquot, empty; +- int ret = 0; +- +-#ifdef __QUOTA_V2_PARANOIA +- /* Invalidated quota? */ +- if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) { +- printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); +- return -EIO; +- } +-#endif +- offset = find_dqentry(dquot); +- if (offset <= 0) { /* Entry not present? */ +- if (offset < 0) +- printk(KERN_ERR "VFS: Can't read quota " +- "structure for id %u.\n", dquot->dq_id); +- dquot->dq_off = 0; +- set_bit(DQ_FAKE_B, &dquot->dq_flags); +- memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); +- ret = offset; +- } +- else { +- dquot->dq_off = offset; +- if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, +- (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset)) +- != sizeof(struct v2_disk_dqblk)) { +- if (ret >= 0) +- ret = -EIO; +- printk(KERN_ERR "VFS: Error while reading quota " +- "structure for id %u.\n", dquot->dq_id); +- memset(&ddquot, 0, sizeof(struct v2_disk_dqblk)); +- } +- else { +- ret = 0; +- /* We need to escape back all-zero structure */ +- memset(&empty, 0, sizeof(struct v2_disk_dqblk)); +- empty.dqb_itime = cpu_to_le64(1); +- if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) +- ddquot.dqb_itime = 0; +- } +- disk2memdqb(&dquot->dq_dqb, &ddquot); +- if (!dquot->dq_dqb.dqb_bhardlimit && +- !dquot->dq_dqb.dqb_bsoftlimit && +- !dquot->dq_dqb.dqb_ihardlimit && +- !dquot->dq_dqb.dqb_isoftlimit) +- set_bit(DQ_FAKE_B, &dquot->dq_flags); +- } +- dqstats.reads++; +- +- return ret; +-} +- +-/* Check whether dquot should not be deleted. We know we are +- * the only one operating on dquot (thanks to dq_lock) */ + static int v2_release_dquot(struct dquot *dquot) + { +- if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) +- return v2_delete_dquot(dquot); +- return 0; ++ return qtree_release_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot); + } + + static struct quota_format_ops v2_format_ops = { +--- a/fs/quotaio_v2.h ++++ b/fs/quotaio_v2.h +@@ -21,6 +21,12 @@ + 0 /* GRPQUOTA */\ + } + ++/* First generic header */ ++struct v2_disk_dqheader { ++ __le32 dqh_magic; /* Magic number identifying file */ ++ __le32 dqh_version; /* File version */ ++}; ++ + /* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is a radix tree whose leaves point +@@ -38,15 +44,6 @@ struct v2_disk_dqblk { + __le64 dqb_itime; /* time limit for excessive inode use */ + }; + +-/* +- * Here are header structures as written on disk and their in-memory copies +- */ +-/* First generic header */ +-struct v2_disk_dqheader { +- __le32 dqh_magic; /* Magic number identifying file */ +- __le32 dqh_version; /* File version */ +-}; +- + /* Header with type and version specific information */ + struct v2_disk_dqinfo { + __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ +@@ -57,23 +54,7 @@ struct v2_disk_dqinfo { + __le32 dqi_free_entry; /* Number of block with at least one free entry */ + }; + +-/* +- * Structure of header of block with quota structures. It is padded to 16 bytes so +- * there will be space for exactly 21 quota-entries in a block +- */ +-struct v2_disk_dqdbheader { +- __le32 dqdh_next_free; /* Number of next block with free entry */ +- __le32 dqdh_prev_free; /* Number of previous block with free entry */ +- __le16 dqdh_entries; /* Number of valid entries in block */ +- __le16 dqdh_pad1; +- __le32 dqdh_pad2; +-}; +- + #define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +-#define V2_DQBLKSIZE_BITS 10 +-#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +-#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ +-#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +-#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ ++#define V2_DQBLKSIZE_BITS 10 /* Size of leaf block in tree */ + + #endif /* _LINUX_QUOTAIO_V2_H */ +--- /dev/null ++++ b/include/linux/dqblk_qtree.h +@@ -0,0 +1,56 @@ ++/* ++ * Definitions of structures and functions for quota formats using trie ++ */ ++ ++#ifndef _LINUX_DQBLK_QTREE_H ++#define _LINUX_DQBLK_QTREE_H ++ ++#include ++ ++/* Numbers of blocks needed for updates - we count with the smallest ++ * possible block size (1024) */ ++#define QTREE_INIT_ALLOC 4 ++#define QTREE_INIT_REWRITE 2 ++#define QTREE_DEL_ALLOC 0 ++#define QTREE_DEL_REWRITE 6 ++ ++struct dquot; ++ ++/* Operations */ ++struct qtree_fmt_operations { ++ void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); /* Convert given entry from in memory format to disk one */ ++ void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); /* Convert given entry from disk format to in memory one */ ++ int (*is_id)(void *disk, struct dquot *dquot); /* Is this structure for given id? */ ++}; ++ ++/* Inmemory copy of version specific information */ ++struct qtree_mem_dqinfo { ++ struct super_block *dqi_sb; /* Sb quota is on */ ++ int dqi_type; /* Quota type */ ++ unsigned int dqi_blocks; /* # of blocks in quota file */ ++ unsigned int dqi_free_blk; /* First block in list of free blocks */ ++ unsigned int dqi_free_entry; /* First block with free entry */ ++ unsigned int dqi_blocksize_bits; /* Block size of quota file */ ++ unsigned int dqi_entry_size; /* Size of quota entry in quota file */ ++ unsigned int dqi_usable_bs; /* Space usable in block for quota data */ ++ unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */ ++ struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */ ++}; ++ ++int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); ++int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); ++int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); ++int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); ++int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); ++static inline int qtree_depth(struct qtree_mem_dqinfo *info) ++{ ++ unsigned int epb = info->dqi_usable_bs >> 2; ++ unsigned long long entries = epb; ++ int i; ++ ++ for (i = 1; entries < (1ULL << 32); i++) ++ entries *= epb; ++ return i; ++} ++ ++#endif /* _LINUX_DQBLK_QTREE_H */ +--- a/include/linux/dqblk_v2.h ++++ b/include/linux/dqblk_v2.h +@@ -1,26 +1,23 @@ + /* +- * Definitions of structures for vfsv0 quota format ++ * Definitions for vfsv0 quota format + */ + + #ifndef _LINUX_DQBLK_V2_H + #define _LINUX_DQBLK_V2_H + +-#include ++#include + +-/* id numbers of quota format */ ++/* Id number of quota format */ + #define QFMT_VFS_V0 2 + + /* Numbers of blocks needed for updates */ +-#define V2_INIT_ALLOC 4 +-#define V2_INIT_REWRITE 2 +-#define V2_DEL_ALLOC 0 +-#define V2_DEL_REWRITE 6 ++#define V2_INIT_ALLOC QTREE_INIT_ALLOC ++#define V2_INIT_REWRITE QTREE_INIT_REWRITE ++#define V2_DEL_ALLOC QTREE_DEL_ALLOC ++#define V2_DEL_REWRITE QTREE_DEL_REWRITE + +-/* Inmemory copy of version specific information */ + struct v2_mem_dqinfo { +- unsigned int dqi_blocks; +- unsigned int dqi_free_blk; +- unsigned int dqi_free_entry; ++ struct qtree_mem_dqinfo i; + }; + + #endif /* _LINUX_DQBLK_V2_H */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/radeon-monitor-jsxx-quirk.patch b/src/patches/suse-2.6.27.31/patches.suse/radeon-monitor-jsxx-quirk.patch new file mode 100644 index 000000000..c6f7e961d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/radeon-monitor-jsxx-quirk.patch @@ -0,0 +1,64 @@ +Subject: [PATCH] Add quirk for the graphics adapter in some JSxx +From: Tony Breeds +References: 461002 - LTC50817 + +These devices are set to 640x480 by firmware, switch them to +800x600@60. + +Signed-off-by: Tony Breeds +Signed-off-by: Olaf Hering +--- + drivers/video/aty/radeon_monitor.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/drivers/video/aty/radeon_monitor.c ++++ b/drivers/video/aty/radeon_monitor.c +@@ -727,6 +727,25 @@ static void radeon_videomode_to_var(stru + var->vmode = mode->vmode; + } + ++#ifdef CONFIG_PPC_PSERIES ++static int is_powerblade(const char *model) ++{ ++ struct device_node *root; ++ const char* cp; ++ int len, l, rc = 0; ++ ++ root = of_find_node_by_path("/"); ++ if (root && model) { ++ l = strlen(model); ++ cp = of_get_property(root, "model", &len); ++ if (cp) ++ rc = memcmp(model, cp, min(len, l)) == 0; ++ of_node_put(root); ++ } ++ return rc; ++} ++#endif ++ + /* + * Build the modedb for head 1 (head 2 will come later), check panel infos + * from either BIOS or EDID, and pick up the default mode +@@ -862,6 +881,22 @@ void __devinit radeon_check_modes(struct + has_default_mode = 1; + } + ++#ifdef CONFIG_PPC_PSERIES ++ if (!has_default_mode && ( ++ is_powerblade("IBM,8842") || /* JS20 */ ++ is_powerblade("IBM,8844") || /* JS21 */ ++ is_powerblade("IBM,7998") || /* JS12/JS21/JS22 */ ++ is_powerblade("IBM,0792") || /* QS21 */ ++ is_powerblade("IBM,0793") /* QS22 */ ++ )) { ++ printk("Falling back to 800x600 on JSxx hardware\n"); ++ if (fb_find_mode(&info->var, info, "800x600@60", ++ info->monspecs.modedb, ++ info->monspecs.modedb_len, NULL, 8) != 0) ++ has_default_mode = 1; ++ } ++#endif ++ + /* + * Still no mode, let's pick up a default from the db + */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiser4-exports b/src/patches/suse-2.6.27.31/patches.suse/reiser4-exports new file mode 100644 index 000000000..04333b5cd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiser4-exports @@ -0,0 +1,53 @@ +From: ReiserFS Development +Subject: [PATCH] reiser4: add new exports for used symbols + + This patch exports the following symbols for use in reiser4: + + - __copy_from_user_ll_nocache + - __copy_from_user_ll_nocache_nozero + - __remove_from_page_cache + - remove_from_page_cache + - add_to_page_cache_lru + - find_get_pages + - handle_ra_miss + +Acked-by: Jeff Mahoney + +--- + mm/filemap.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -134,6 +134,7 @@ void __remove_from_page_cache(struct pag + dec_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE); + } + } ++EXPORT_SYMBOL_GPL(__remove_from_page_cache); + + void remove_from_page_cache(struct page *page) + { +@@ -145,6 +146,7 @@ void remove_from_page_cache(struct page + __remove_from_page_cache(page); + spin_unlock_irq(&mapping->tree_lock); + } ++EXPORT_SYMBOL_GPL(remove_from_page_cache); + + static int sync_page(void *word) + { +@@ -497,6 +499,7 @@ int add_to_page_cache_lru(struct page *p + lru_cache_add(page); + return ret; + } ++EXPORT_SYMBOL_GPL(add_to_page_cache_lru); + + #ifdef CONFIG_NUMA + struct page *__page_cache_alloc(gfp_t gfp) +@@ -796,6 +799,7 @@ repeat: + rcu_read_unlock(); + return ret; + } ++EXPORT_SYMBOL_GPL(find_get_pages); + + /** + * find_get_pages_contig - gang contiguous pagecache lookup diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiser4-sync_inodes b/src/patches/suse-2.6.27.31/patches.suse/reiser4-sync_inodes new file mode 100644 index 000000000..9892b79d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiser4-sync_inodes @@ -0,0 +1,39 @@ +From: ReiserFS Development +Subject: [PATCH] vfs: Add ->sync_inodes super operation for reiser4 + + This patch adds the ->sync_inodes superblock operation for use with reiser4. + + FIle systems without this operation will still use the generic implementation. + +Acked-by: Jeff Mahoney + +--- + fs/fs-writeback.c | 5 ++++- + include/linux/fs.h | 2 ++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -575,7 +575,10 @@ EXPORT_SYMBOL_GPL(generic_sync_sb_inodes + static void sync_sb_inodes(struct super_block *sb, + struct writeback_control *wbc) + { +- generic_sync_sb_inodes(sb, wbc); ++ if (sb->s_op->sync_inodes) ++ sb->s_op->sync_inodes(sb, wbc); ++ else ++ generic_sync_sb_inodes(sb, wbc); + } + + /* +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1332,6 +1332,8 @@ struct super_operations { + void (*clear_inode) (struct inode *); + void (*umount_begin) (struct super_block *); + ++ void (*sync_inodes) (struct super_block *sb, ++ struct writeback_control *wbc); + int (*show_options)(struct seq_file *, struct vfsmount *); + int (*show_stats)(struct seq_file *, struct vfsmount *); + #ifdef CONFIG_QUOTA diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-Use-sb_any_quota_loaded-instead-of-sb_an.patch b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-Use-sb_any_quota_loaded-instead-of-sb_an.patch new file mode 100644 index 000000000..a7efb3ed6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-Use-sb_any_quota_loaded-instead-of-sb_an.patch @@ -0,0 +1,41 @@ +From: Jan Kara +References: fate#302681 +Subject: [PATCH 08/28] reiserfs: Use sb_any_quota_loaded() instead of sb_any_quota_enabled(). +Patch-mainline: 2.6.29? + +Signed-off-by: Jan Kara +--- + fs/reiserfs/super.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/fs/reiserfs/super.c ++++ b/fs/reiserfs/super.c +@@ -1002,8 +1002,7 @@ static int reiserfs_parse_options(struct + if (c == 'u' || c == 'g') { + int qtype = c == 'u' ? USRQUOTA : GRPQUOTA; + +- if ((sb_any_quota_enabled(s) || +- sb_any_quota_suspended(s)) && ++ if (sb_any_quota_loaded(s) && + (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) { + reiserfs_warning(s, "super-6511", + "cannot change journaled " +@@ -1056,8 +1055,7 @@ static int reiserfs_parse_options(struct + "specified."); + return 0; + } +- if ((sb_any_quota_enabled(s) || +- sb_any_quota_suspended(s)) && ++ if (sb_any_quota_loaded(s) && + *qfmt != REISERFS_SB(s)->s_jquota_fmt) { + reiserfs_warning(s, "super-6515", + "cannot change journaled " +@@ -1084,7 +1082,7 @@ static int reiserfs_parse_options(struct + } + /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ + if (!(*mount_options & (1 << REISERFS_QUOTA)) +- && sb_any_quota_enabled(s)) { ++ && sb_any_quota_loaded(s)) { + reiserfs_warning(s, "super-6516", "quota options must " + "be present when quota is turned on."); + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-barrier-default b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-barrier-default new file mode 100644 index 000000000..bdfed7968 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-barrier-default @@ -0,0 +1,26 @@ +From: Chris Mason +Subject: Make reiserfs default to barrier=flush +X-Patch-Mainline: Submitted Fri Aug 4 09:55:00 EDT 2006 mason + +Change the default reiserfs mount option to barrier=flush + + fs/reiserfs/super.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/reiserfs/super.c ++++ b/fs/reiserfs/super.c +@@ -1714,9 +1714,12 @@ static int reiserfs_fill_super(struct su + } else { + reiserfs_info(s, "using writeback data mode\n"); + } +- if (reiserfs_barrier_flush(s)) { ++ /* make barrer=flush the default */ ++ ++ if (!reiserfs_barrier_none(s)) ++ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_BARRIER_FLUSH); ++ if (reiserfs_barrier_flush(s)) + printk("reiserfs: using flush barriers\n"); +- } + // set_device_ro(s->s_dev, 1) ; + if (journal_init(s, jdev_name, old_format, commit_max_age)) { + SWARN(silent, s, "sh-2022", diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-clean-up-xattrs b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-clean-up-xattrs new file mode 100644 index 000000000..410794c6c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-clean-up-xattrs @@ -0,0 +1,1004 @@ +From: Jeff Mahoney +Subject: reiserfs: Clean up xattrs when REISERFS_FS_XATTR is unset + + The current reiserfs xattr implementation will not clean up old xattr + files if files are deleted when REISERFS_FS_XATTR is unset. This results + in inaccessible lost files, wasting space. + + This patch compiles in basic xattr knowledge, such as how to delete them and + change ownership for quota tracking. If the file system has never used + xattrs, then the operation is quite fast: it returns immediately when + it sees there is no .reiserfs_priv directory. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/Makefile | 4 + fs/reiserfs/xattr.c | 801 +++++++++++++++++++++-------------------- + include/linux/reiserfs_fs_sb.h | 2 + include/linux/reiserfs_xattr.h | 29 - + 4 files changed, 423 insertions(+), 413 deletions(-) + +--- a/fs/reiserfs/Makefile ++++ b/fs/reiserfs/Makefile +@@ -7,10 +7,10 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o + reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ + super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ + hashes.o tail_conversion.o journal.o resize.o \ +- item_ops.o ioctl.o procfs.o ++ item_ops.o ioctl.o procfs.o xattr.o + + ifeq ($(CONFIG_REISERFS_FS_XATTR),y) +-reiserfs-objs += xattr.o xattr_user.o xattr_trusted.o ++reiserfs-objs += xattr_user.o xattr_trusted.o + endif + + ifeq ($(CONFIG_REISERFS_FS_SECURITY),y) +--- a/fs/reiserfs/xattr.c ++++ b/fs/reiserfs/xattr.c +@@ -50,9 +50,6 @@ + #define PRIVROOT_NAME ".reiserfs_priv" + #define XAROOT_NAME "xattrs" + +-static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char +- *prefix); +- + /* Returns the dentry referring to the root of the extended attribute + * directory tree. If it has already been retrieved, it is used. If it + * hasn't been created and the flags indicate creation is allowed, we +@@ -143,60 +140,6 @@ static struct dentry *open_xa_dir(const + return xadir; + } + +-/* Returns a dentry corresponding to a specific extended attribute file +- * for the inode. If flags allow, the file is created. Otherwise, a +- * valid or negative dentry, or an error is returned. */ +-static struct dentry *get_xa_file_dentry(const struct inode *inode, +- const char *name, int flags) +-{ +- struct dentry *xadir, *xafile; +- int err = 0; +- +- xadir = open_xa_dir(inode, flags); +- if (IS_ERR(xadir)) { +- return ERR_CAST(xadir); +- } else if (xadir && !xadir->d_inode) { +- dput(xadir); +- return ERR_PTR(-ENODATA); +- } +- +- xafile = lookup_one_len(name, xadir, strlen(name)); +- if (IS_ERR(xafile)) { +- dput(xadir); +- return ERR_CAST(xafile); +- } +- +- if (xafile->d_inode) { /* file exists */ +- if (flags & XATTR_CREATE) { +- err = -EEXIST; +- dput(xafile); +- goto out; +- } +- } else if (flags & XATTR_REPLACE || flags & FL_READONLY) { +- goto out; +- } else { +- /* inode->i_mutex is down, so nothing else can try to create +- * the same xattr */ +- err = xadir->d_inode->i_op->create(xadir->d_inode, xafile, +- 0700 | S_IFREG, NULL); +- +- if (err) { +- dput(xafile); +- goto out; +- } +- } +- +- out: +- dput(xadir); +- if (err) +- xafile = ERR_PTR(err); +- else if (!xafile->d_inode) { +- dput(xafile); +- xafile = ERR_PTR(-ENODATA); +- } +- return xafile; +-} +- + /* + * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but + * we need to drop the path before calling the filldir struct. That +@@ -369,6 +312,251 @@ int xattr_readdir(struct inode *inode, f + return res; + } + ++static int ++__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) ++{ ++ struct dentry *dentry; ++ struct inode *dir = xadir->d_inode; ++ int err = 0; ++ ++ dentry = lookup_one_len(name, xadir, namelen); ++ if (IS_ERR(dentry)) { ++ err = PTR_ERR(dentry); ++ goto out; ++ } else if (!dentry->d_inode) { ++ err = -ENODATA; ++ goto out_file; ++ } ++ ++ /* Skip directories.. */ ++ if (S_ISDIR(dentry->d_inode->i_mode)) ++ goto out_file; ++ ++ if (!IS_PRIVATE(dentry->d_inode)) { ++ reiserfs_error(dir->i_sb, "jdm-20003", ++ "OID %08x [%.*s/%.*s] doesn't have " ++ "priv flag set [parent is %sset].", ++ le32_to_cpu(INODE_PKEY(dentry->d_inode)-> ++ k_objectid), xadir->d_name.len, ++ xadir->d_name.name, namelen, name, ++ IS_PRIVATE(xadir->d_inode) ? "" : ++ "not "); ++ dput(dentry); ++ return -EIO; ++ } ++ ++ err = dir->i_op->unlink(dir, dentry); ++ if (!err) ++ d_delete(dentry); ++ ++out_file: ++ dput(dentry); ++ ++out: ++ return err; ++} ++ ++/* The following are side effects of other operations that aren't explicitly ++ * modifying extended attributes. This includes operations such as permissions ++ * or ownership changes, object deletions, etc. */ ++ ++static int ++reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct dentry *xadir = (struct dentry *)buf; ++ ++ return __reiserfs_xattr_del(xadir, name, namelen); ++ ++} ++ ++/* This is called w/ inode->i_mutex downed */ ++int reiserfs_delete_xattrs(struct inode *inode) ++{ ++ struct dentry *dir, *root; ++ int err = 0; ++ ++ /* Skip out, an xattr has no xattrs associated with it */ ++ if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) ++ return 0; ++ ++ reiserfs_read_lock_xattrs(inode->i_sb); ++ dir = open_xa_dir(inode, FL_READONLY); ++ reiserfs_read_unlock_xattrs(inode->i_sb); ++ if (IS_ERR(dir)) { ++ err = PTR_ERR(dir); ++ goto out; ++ } else if (!dir->d_inode) { ++ dput(dir); ++ return 0; ++ } ++ ++ lock_kernel(); ++ err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); ++ if (err) { ++ unlock_kernel(); ++ goto out_dir; ++ } ++ ++ /* Leftovers besides . and .. -- that's not good. */ ++ if (dir->d_inode->i_nlink <= 2) { ++ root = get_xa_root(inode->i_sb, XATTR_REPLACE); ++ reiserfs_write_lock_xattrs(inode->i_sb); ++ err = vfs_rmdir(root->d_inode, dir); ++ reiserfs_write_unlock_xattrs(inode->i_sb); ++ dput(root); ++ } else { ++ reiserfs_warning(inode->i_sb, "jdm-20006", ++ "Couldn't remove all entries in directory"); ++ } ++ unlock_kernel(); ++ ++out_dir: ++ dput(dir); ++ ++out: ++ if (!err) ++ REISERFS_I(inode)->i_flags = ++ REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; ++ return err; ++} ++ ++struct reiserfs_chown_buf { ++ struct inode *inode; ++ struct dentry *xadir; ++ struct iattr *attrs; ++}; ++ ++/* XXX: If there is a better way to do this, I'd love to hear about it */ ++static int ++reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; ++ struct dentry *xafile, *xadir = chown_buf->xadir; ++ struct iattr *attrs = chown_buf->attrs; ++ int err = 0; ++ ++ xafile = lookup_one_len(name, xadir, namelen); ++ if (IS_ERR(xafile)) ++ return PTR_ERR(xafile); ++ else if (!xafile->d_inode) { ++ dput(xafile); ++ return -ENODATA; ++ } ++ ++ if (!S_ISDIR(xafile->d_inode->i_mode)) ++ err = notify_change(xafile, attrs); ++ dput(xafile); ++ ++ return err; ++} ++ ++int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) ++{ ++ struct dentry *dir; ++ int err = 0; ++ struct reiserfs_chown_buf buf; ++ unsigned int ia_valid = attrs->ia_valid; ++ ++ /* Skip out, an xattr has no xattrs associated with it */ ++ if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) ++ return 0; ++ ++ reiserfs_read_lock_xattrs(inode->i_sb); ++ dir = open_xa_dir(inode, FL_READONLY); ++ reiserfs_read_unlock_xattrs(inode->i_sb); ++ if (IS_ERR(dir)) { ++ if (PTR_ERR(dir) != -ENODATA) ++ err = PTR_ERR(dir); ++ goto out; ++ } else if (!dir->d_inode) { ++ dput(dir); ++ goto out; ++ } ++ ++ lock_kernel(); ++ ++ attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); ++ buf.xadir = dir; ++ buf.attrs = attrs; ++ buf.inode = inode; ++ ++ err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); ++ if (err) { ++ unlock_kernel(); ++ goto out_dir; ++ } ++ ++ err = notify_change(dir, attrs); ++ unlock_kernel(); ++ ++out_dir: ++ dput(dir); ++ ++out: ++ attrs->ia_valid = ia_valid; ++ return err; ++} ++ ++#ifdef CONFIG_REISERFS_FS_XATTR ++static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char ++ *prefix); ++ ++/* Returns a dentry corresponding to a specific extended attribute file ++ * for the inode. If flags allow, the file is created. Otherwise, a ++ * valid or negative dentry, or an error is returned. */ ++static struct dentry *get_xa_file_dentry(const struct inode *inode, ++ const char *name, int flags) ++{ ++ struct dentry *xadir, *xafile; ++ int err = 0; ++ ++ xadir = open_xa_dir(inode, flags); ++ if (IS_ERR(xadir)) { ++ return ERR_CAST(xadir); ++ } else if (xadir && !xadir->d_inode) { ++ dput(xadir); ++ return ERR_PTR(-ENODATA); ++ } ++ ++ xafile = lookup_one_len(name, xadir, strlen(name)); ++ if (IS_ERR(xafile)) { ++ dput(xadir); ++ return ERR_CAST(xafile); ++ } ++ ++ if (xafile->d_inode) { /* file exists */ ++ if (flags & XATTR_CREATE) { ++ err = -EEXIST; ++ dput(xafile); ++ goto out; ++ } ++ } else if (flags & XATTR_REPLACE || flags & FL_READONLY) { ++ goto out; ++ } else { ++ /* inode->i_mutex is down, so nothing else can try to create ++ * the same xattr */ ++ err = xadir->d_inode->i_op->create(xadir->d_inode, xafile, ++ 0700 | S_IFREG, NULL); ++ ++ if (err) { ++ dput(xafile); ++ goto out; ++ } ++ } ++ ++out: ++ dput(xadir); ++ if (err) ++ xafile = ERR_PTR(err); ++ else if (!xafile->d_inode) { ++ dput(xafile); ++ xafile = ERR_PTR(-ENODATA); ++ } ++ return xafile; ++} ++ + /* Internal operations on file data */ + static inline void reiserfs_put_page(struct page *page) + { +@@ -554,274 +742,85 @@ reiserfs_xattr_get(const struct inode *i + goto out_dput; + } + +- while (file_pos < isize) { +- size_t chunk; +- char *data; +- size_t skip = 0; +- if (isize - file_pos > PAGE_CACHE_SIZE) +- chunk = PAGE_CACHE_SIZE; +- else +- chunk = isize - file_pos; +- +- page = reiserfs_get_page(dentry->d_inode, file_pos); +- if (IS_ERR(page)) { +- err = PTR_ERR(page); +- goto out_dput; +- } +- +- lock_page(page); +- data = page_address(page); +- if (file_pos == 0) { +- struct reiserfs_xattr_header *rxh = +- (struct reiserfs_xattr_header *)data; +- skip = file_pos = sizeof(struct reiserfs_xattr_header); +- chunk -= skip; +- /* Magic doesn't match up.. */ +- if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { +- unlock_page(page); +- reiserfs_put_page(page); +- reiserfs_warning(inode->i_sb, "jdm-20001", +- "Invalid magic for xattr (%s) " +- "associated with %k", name, +- INODE_PKEY(inode)); +- err = -EIO; +- goto out_dput; +- } +- hash = le32_to_cpu(rxh->h_hash); +- } +- memcpy(buffer + buffer_pos, data + skip, chunk); +- unlock_page(page); +- reiserfs_put_page(page); +- file_pos += chunk; +- buffer_pos += chunk; +- skip = 0; +- } +- err = isize - sizeof(struct reiserfs_xattr_header); +- +- if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != +- hash) { +- reiserfs_warning(inode->i_sb, "jdm-20002", +- "Invalid hash for xattr (%s) associated " +- "with %k", name, INODE_PKEY(inode)); +- err = -EIO; +- } +- +- out_dput: +- dput(dentry); +- +- out: +- return err; +-} +- +-static int +-__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) +-{ +- struct dentry *dentry; +- struct inode *dir = xadir->d_inode; +- int err = 0; +- +- dentry = lookup_one_len(name, xadir, namelen); +- if (IS_ERR(dentry)) { +- err = PTR_ERR(dentry); +- goto out; +- } else if (!dentry->d_inode) { +- err = -ENODATA; +- goto out_file; +- } +- +- /* Skip directories.. */ +- if (S_ISDIR(dentry->d_inode->i_mode)) +- goto out_file; +- +- if (!IS_PRIVATE(dentry->d_inode)) { +- reiserfs_error(dir->i_sb, "jdm-20003", +- "OID %08x [%.*s/%.*s] doesn't have " +- "priv flag set [parent is %sset].", +- le32_to_cpu(INODE_PKEY(dentry->d_inode)-> +- k_objectid), xadir->d_name.len, +- xadir->d_name.name, namelen, name, +- IS_PRIVATE(xadir->d_inode) ? "" : +- "not "); +- dput(dentry); +- return -EIO; +- } +- +- err = dir->i_op->unlink(dir, dentry); +- if (!err) +- d_delete(dentry); +- +- out_file: +- dput(dentry); +- +- out: +- return err; +-} +- +-int reiserfs_xattr_del(struct inode *inode, const char *name) +-{ +- struct dentry *dir; +- int err; +- +- dir = open_xa_dir(inode, FL_READONLY); +- if (IS_ERR(dir)) { +- err = PTR_ERR(dir); +- goto out; +- } +- +- err = __reiserfs_xattr_del(dir, name, strlen(name)); +- dput(dir); +- +- if (!err) { +- inode->i_ctime = CURRENT_TIME_SEC; +- mark_inode_dirty(inode); +- } +- +- out: +- return err; +-} +- +-/* The following are side effects of other operations that aren't explicitly +- * modifying extended attributes. This includes operations such as permissions +- * or ownership changes, object deletions, etc. */ +- +-static int +-reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, +- loff_t offset, u64 ino, unsigned int d_type) +-{ +- struct dentry *xadir = (struct dentry *)buf; +- +- return __reiserfs_xattr_del(xadir, name, namelen); +- +-} +- +-/* This is called w/ inode->i_mutex downed */ +-int reiserfs_delete_xattrs(struct inode *inode) +-{ +- struct dentry *dir, *root; +- int err = 0; +- +- /* Skip out, an xattr has no xattrs associated with it */ +- if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || +- !reiserfs_xattrs(inode->i_sb)) { +- return 0; +- } +- reiserfs_read_lock_xattrs(inode->i_sb); +- dir = open_xa_dir(inode, FL_READONLY); +- reiserfs_read_unlock_xattrs(inode->i_sb); +- if (IS_ERR(dir)) { +- err = PTR_ERR(dir); +- goto out; +- } else if (!dir->d_inode) { +- dput(dir); +- return 0; +- } +- +- lock_kernel(); +- err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); +- if (err) { +- unlock_kernel(); +- goto out_dir; +- } +- +- /* Leftovers besides . and .. -- that's not good. */ +- if (dir->d_inode->i_nlink <= 2) { +- root = get_xa_root(inode->i_sb, XATTR_REPLACE); +- reiserfs_write_lock_xattrs(inode->i_sb); +- err = vfs_rmdir(root->d_inode, dir); +- reiserfs_write_unlock_xattrs(inode->i_sb); +- dput(root); +- } else { +- reiserfs_warning(inode->i_sb, "jdm-20006", +- "Couldn't remove all entries in directory"); +- } +- unlock_kernel(); +- +- out_dir: +- dput(dir); +- +- out: +- if (!err) +- REISERFS_I(inode)->i_flags = +- REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; +- return err; +-} ++ while (file_pos < isize) { ++ size_t chunk; ++ char *data; ++ size_t skip = 0; ++ if (isize - file_pos > PAGE_CACHE_SIZE) ++ chunk = PAGE_CACHE_SIZE; ++ else ++ chunk = isize - file_pos; + +-struct reiserfs_chown_buf { +- struct inode *inode; +- struct dentry *xadir; +- struct iattr *attrs; +-}; ++ page = reiserfs_get_page(dentry->d_inode, file_pos); ++ if (IS_ERR(page)) { ++ err = PTR_ERR(page); ++ goto out_dput; ++ } + +-/* XXX: If there is a better way to do this, I'd love to hear about it */ +-static int +-reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, +- loff_t offset, u64 ino, unsigned int d_type) +-{ +- struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; +- struct dentry *xafile, *xadir = chown_buf->xadir; +- struct iattr *attrs = chown_buf->attrs; +- int err = 0; ++ lock_page(page); ++ data = page_address(page); ++ if (file_pos == 0) { ++ struct reiserfs_xattr_header *rxh = ++ (struct reiserfs_xattr_header *)data; ++ skip = file_pos = sizeof(struct reiserfs_xattr_header); ++ chunk -= skip; ++ /* Magic doesn't match up.. */ ++ if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) { ++ unlock_page(page); ++ reiserfs_put_page(page); ++ reiserfs_warning(inode->i_sb, "jdm-20001", ++ "Invalid magic for xattr (%s) " ++ "associated with %k", name, ++ INODE_PKEY(inode)); ++ err = -EIO; ++ goto out_dput; ++ } ++ hash = le32_to_cpu(rxh->h_hash); ++ } ++ memcpy(buffer + buffer_pos, data + skip, chunk); ++ unlock_page(page); ++ reiserfs_put_page(page); ++ file_pos += chunk; ++ buffer_pos += chunk; ++ skip = 0; ++ } ++ err = isize - sizeof(struct reiserfs_xattr_header); + +- xafile = lookup_one_len(name, xadir, namelen); +- if (IS_ERR(xafile)) +- return PTR_ERR(xafile); +- else if (!xafile->d_inode) { +- dput(xafile); +- return -ENODATA; ++ if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) != ++ hash) { ++ reiserfs_warning(inode->i_sb, "jdm-20002", ++ "Invalid hash for xattr (%s) associated " ++ "with %k", name, INODE_PKEY(inode)); ++ err = -EIO; + } + +- if (!S_ISDIR(xafile->d_inode->i_mode)) +- err = notify_change(xafile, attrs); +- dput(xafile); ++out_dput: ++ dput(dentry); + ++out: + return err; + } + +-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) ++int reiserfs_xattr_del(struct inode *inode, const char *name) + { + struct dentry *dir; +- int err = 0; +- struct reiserfs_chown_buf buf; +- unsigned int ia_valid = attrs->ia_valid; ++ int err; + +- /* Skip out, an xattr has no xattrs associated with it */ +- if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || +- !reiserfs_xattrs(inode->i_sb)) { +- return 0; +- } +- reiserfs_read_lock_xattrs(inode->i_sb); + dir = open_xa_dir(inode, FL_READONLY); +- reiserfs_read_unlock_xattrs(inode->i_sb); + if (IS_ERR(dir)) { +- if (PTR_ERR(dir) != -ENODATA) +- err = PTR_ERR(dir); +- goto out; +- } else if (!dir->d_inode) { +- dput(dir); ++ err = PTR_ERR(dir); + goto out; + } + +- lock_kernel(); +- +- attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); +- buf.xadir = dir; +- buf.attrs = attrs; +- buf.inode = inode; ++ err = __reiserfs_xattr_del(dir, name, strlen(name)); ++ dput(dir); + +- err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); +- if (err) { +- unlock_kernel(); +- goto out_dir; ++ if (!err) { ++ inode->i_ctime = CURRENT_TIME_SEC; ++ mark_inode_dirty(inode); + } + +- err = notify_change(dir, attrs); +- unlock_kernel(); +- +- out_dir: +- dput(dir); +- + out: +- attrs->ia_valid = ia_valid; + return err; + } + +@@ -1101,6 +1100,94 @@ void reiserfs_xattr_unregister_handlers( + write_unlock(&handler_lock); + } + ++static int reiserfs_check_acl(struct inode *inode, int mask) ++{ ++ struct posix_acl *acl; ++ int error = -EAGAIN; /* do regular unix permission checks by default */ ++ ++ reiserfs_read_lock_xattr_i(inode); ++ reiserfs_read_lock_xattrs(inode->i_sb); ++ ++ acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); ++ ++ reiserfs_read_unlock_xattrs(inode->i_sb); ++ reiserfs_read_unlock_xattr_i(inode); ++ ++ if (acl) { ++ if (!IS_ERR(acl)) { ++ error = posix_acl_permission(inode, acl, mask); ++ posix_acl_release(acl); ++ } else if (PTR_ERR(acl) != -ENODATA) ++ error = PTR_ERR(acl); ++ } ++ ++ return error; ++} ++ ++int reiserfs_permission(struct inode *inode, int mask) ++{ ++ /* ++ * We don't do permission checks on the internal objects. ++ * Permissions are determined by the "owning" object. ++ */ ++ if (IS_PRIVATE(inode)) ++ return 0; ++ /* ++ * Stat data v1 doesn't support ACLs. ++ */ ++ if (get_inode_sd_version(inode) == STAT_DATA_V1) ++ return generic_permission(inode, mask, NULL); ++ else ++ return generic_permission(inode, mask, reiserfs_check_acl); ++} ++ ++static int create_privroot(struct dentry *dentry) ++{ ++ int err; ++ struct inode *inode = dentry->d_parent->d_inode; ++ mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR); ++ err = inode->i_op->mkdir(inode, dentry, 0700); ++ mutex_unlock(&inode->i_mutex); ++ if (err) { ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++ if (dentry && dentry->d_inode) ++ reiserfs_info(dentry->d_sb, "Created %s - reserved for xattr " ++ "storage.\n", PRIVROOT_NAME); ++ ++ return err; ++} ++ ++static int xattr_mount_check(struct super_block *s) ++{ ++ /* We need generation numbers to ensure that the oid mapping is correct ++ * v3.5 filesystems don't have them. */ ++ if (!old_format_only(s)) { ++ set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); ++ } else if (reiserfs_xattrs_optional(s)) { ++ /* Old format filesystem, but optional xattrs have been enabled ++ * at mount time. Error out. */ ++ reiserfs_warning(s, "jdm-20005", ++ "xattrs/ACLs not supported on pre v3.6 " ++ "format filesystem. Failing mount."); ++ return -EOPNOTSUPP; ++ } else { ++ /* Old format filesystem, but no optional xattrs have ++ * been enabled. This means we silently disable xattrs ++ * on the filesystem. */ ++ clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); ++ } ++ ++ return 0; ++} ++ ++#else ++int __init reiserfs_xattr_register_handlers(void) { return 0; } ++void reiserfs_xattr_unregister_handlers(void) {} ++#endif ++ + /* This will catch lookups from the fs root to .reiserfs_priv */ + static int + xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) +@@ -1127,47 +1214,23 @@ int reiserfs_xattr_init(struct super_blo + { + int err = 0; + +- /* We need generation numbers to ensure that the oid mapping is correct +- * v3.5 filesystems don't have them. */ +- if (!old_format_only(s)) { +- set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); +- } else if (reiserfs_xattrs_optional(s)) { +- /* Old format filesystem, but optional xattrs have been enabled +- * at mount time. Error out. */ +- reiserfs_warning(s, "jdm-20005", +- "xattrs/ACLs not supported on pre v3.6 " +- "format filesystem. Failing mount."); +- err = -EOPNOTSUPP; ++#ifdef CONFIG_REISERFS_FS_XATTR ++ err = xattr_mount_check(s); ++ if (err) + goto error; +- } else { +- /* Old format filesystem, but no optional xattrs have been enabled. This +- * means we silently disable xattrs on the filesystem. */ +- clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); +- } ++#endif + + /* If we don't have the privroot located yet - go find it */ +- if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) { ++ if (!REISERFS_SB(s)->priv_root) { + struct dentry *dentry; + dentry = lookup_one_len(PRIVROOT_NAME, s->s_root, + strlen(PRIVROOT_NAME)); + if (!IS_ERR(dentry)) { +- if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) { +- struct inode *inode = dentry->d_parent->d_inode; +- mutex_lock_nested(&inode->i_mutex, +- I_MUTEX_XATTR); +- err = inode->i_op->mkdir(inode, dentry, 0700); +- mutex_unlock(&inode->i_mutex); +- if (err) { +- dput(dentry); +- dentry = NULL; +- } +- +- if (dentry && dentry->d_inode) +- reiserfs_info(s, "Created %s - " +- "reserved for xattr " +- "storage.\n", +- PRIVROOT_NAME); +- } else if (!dentry->d_inode) { ++#ifdef CONFIG_REISERFS_FS_XATTR ++ if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) ++ err = create_privroot(dentry); ++#endif ++ if (!dentry->d_inode) { + dput(dentry); + dentry = NULL; + } +@@ -1178,73 +1241,37 @@ int reiserfs_xattr_init(struct super_blo + s->s_root->d_op = &xattr_lookup_poison_ops; + dentry->d_inode->i_flags |= S_PRIVATE; + REISERFS_SB(s)->priv_root = dentry; +- } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */ +- /* If we're read-only it just means that the dir hasn't been +- * created. Not an error -- just no xattrs on the fs. We'll +- * check again if we go read-write */ ++#ifdef CONFIG_REISERFS_FS_XATTR ++ /* xattrs are unavailable */ ++ } else if (!(mount_flags & MS_RDONLY)) { ++ /* If we're read-only it just means that the dir ++ * hasn't been created. Not an error -- just no ++ * xattrs on the fs. We'll check again if we ++ * go read-write */ + reiserfs_warning(s, "jdm-20006", + "xattrs/ACLs enabled and couldn't " + "find/create .reiserfs_priv. " + "Failing mount."); + err = -EOPNOTSUPP; ++#endif + } + } + +- error: +- /* This is only nonzero if there was an error initializing the xattr +- * directory or if there is a condition where we don't support them. */ ++#ifdef CONFIG_REISERFS_FS_XATTR ++error: + if (err) { + clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt)); + clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt)); + clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt)); + } ++#endif + + /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */ + s->s_flags = s->s_flags & ~MS_POSIXACL; ++#ifdef CONFIG_REISERFS_FS_POSIX_ACL + if (reiserfs_posixacl(s)) + s->s_flags |= MS_POSIXACL; ++#endif + + return err; + } +- +-static int reiserfs_check_acl(struct inode *inode, int mask) +-{ +- struct posix_acl *acl; +- int error = -EAGAIN; /* do regular unix permission checks by default */ +- +- reiserfs_read_lock_xattr_i(inode); +- reiserfs_read_lock_xattrs(inode->i_sb); +- +- acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); +- +- reiserfs_read_unlock_xattrs(inode->i_sb); +- reiserfs_read_unlock_xattr_i(inode); +- +- if (acl) { +- if (!IS_ERR(acl)) { +- error = posix_acl_permission(inode, acl, mask); +- posix_acl_release(acl); +- } else if (PTR_ERR(acl) != -ENODATA) +- error = PTR_ERR(acl); +- } +- +- return error; +-} +- +-int reiserfs_permission(struct inode *inode, int mask) +-{ +- /* +- * We don't do permission checks on the internal objects. +- * Permissions are determined by the "owning" object. +- */ +- if (IS_PRIVATE(inode)) +- return 0; +- +- /* +- * Stat data v1 doesn't support ACLs. +- */ +- if (get_inode_sd_version(inode) == STAT_DATA_V1) +- return generic_permission(inode, mask, NULL); +- else +- return generic_permission(inode, mask, reiserfs_check_acl); +-} +--- a/include/linux/reiserfs_fs_sb.h ++++ b/include/linux/reiserfs_fs_sb.h +@@ -401,8 +401,8 @@ struct reiserfs_sb_info { + int reserved_blocks; /* amount of blocks reserved for further allocations */ + spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */ + struct dentry *priv_root; /* root of /.reiserfs_priv */ +-#ifdef CONFIG_REISERFS_FS_XATTR + struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */ ++#ifdef CONFIG_REISERFS_FS_XATTR + struct rw_semaphore xattr_dir_sem; + #endif + int j_errno; +--- a/include/linux/reiserfs_xattr.h ++++ b/include/linux/reiserfs_xattr.h +@@ -43,6 +43,12 @@ struct reiserfs_xattr_handler { + struct list_head handlers; + }; + ++int reiserfs_xattr_register_handlers(void) __init; ++void reiserfs_xattr_unregister_handlers(void); ++int reiserfs_xattr_init(struct super_block *sb, int mount_flags); ++int reiserfs_delete_xattrs(struct inode *inode); ++int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); ++ + #ifdef CONFIG_REISERFS_FS_XATTR + #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) + ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, +@@ -51,9 +57,6 @@ int reiserfs_setxattr(struct dentry *den + const void *value, size_t size, int flags); + ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size); + int reiserfs_removexattr(struct dentry *dentry, const char *name); +-int reiserfs_delete_xattrs(struct inode *inode); +-int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); +-int reiserfs_xattr_init(struct super_block *sb, int mount_flags); + int reiserfs_permission(struct inode *inode, int mask); + + int reiserfs_xattr_del(struct inode *, const char *); +@@ -64,9 +67,6 @@ extern struct reiserfs_xattr_handler use + extern struct reiserfs_xattr_handler trusted_handler; + extern struct reiserfs_xattr_handler security_handler; + +-int reiserfs_xattr_register_handlers(void) __init; +-void reiserfs_xattr_unregister_handlers(void); +- + static inline void reiserfs_write_lock_xattrs(struct super_block *sb) + { + down_write(&REISERFS_XATTR_DIR_SEM(sb)); +@@ -121,23 +121,6 @@ static inline void reiserfs_init_xattr_r + + #define reiserfs_permission NULL + +-#define reiserfs_xattr_register_handlers() 0 +-#define reiserfs_xattr_unregister_handlers() +- +-static inline int reiserfs_delete_xattrs(struct inode *inode) +-{ +- return 0; +-}; +-static inline int reiserfs_chown_xattrs(struct inode *inode, +- struct iattr *attrs) +-{ +- return 0; +-}; +-static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags) +-{ +- sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */ +- return 0; +-}; + static inline void reiserfs_init_xattr_rwsem(struct inode *inode) + { + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-inode-init b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-inode-init new file mode 100644 index 000000000..1cdbfc9e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-inode-init @@ -0,0 +1,119 @@ +From: Jeff Mahoney +Subject: reiserfs: move static initialization to cache constructor + + Currently reiserfs duplicates code in init_inode and reiserfs_new_inode. + Neither is called from the reiserfs_inode_cache constructor, init_once. + + This patch moves the static initialization there. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/inode.c | 26 -------------------------- + fs/reiserfs/super.c | 11 ++++++++++- + include/linux/reiserfs_xattr.h | 8 -------- + 3 files changed, 10 insertions(+), 35 deletions(-) + +--- a/fs/reiserfs/inode.c ++++ b/fs/reiserfs/inode.c +@@ -1123,17 +1123,6 @@ static void init_inode(struct inode *ino + + copy_key(INODE_PKEY(inode), &(ih->ih_key)); + +- INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list)); +- REISERFS_I(inode)->i_flags = 0; +- REISERFS_I(inode)->i_prealloc_block = 0; +- REISERFS_I(inode)->i_prealloc_count = 0; +- REISERFS_I(inode)->i_trans_id = 0; +- REISERFS_I(inode)->i_jl = NULL; +- mutex_init(&(REISERFS_I(inode)->i_mmap)); +- reiserfs_init_acl_access(inode); +- reiserfs_init_acl_default(inode); +- reiserfs_init_xattr_rwsem(inode); +- + if (stat_data_v1(ih)) { + struct stat_data_v1 *sd = + (struct stat_data_v1 *)B_I_PITEM(bh, ih); +@@ -1149,9 +1138,6 @@ static void init_inode(struct inode *ino + inode->i_atime.tv_sec = sd_v1_atime(sd); + inode->i_mtime.tv_sec = sd_v1_mtime(sd); + inode->i_ctime.tv_sec = sd_v1_ctime(sd); +- inode->i_atime.tv_nsec = 0; +- inode->i_ctime.tv_nsec = 0; +- inode->i_mtime.tv_nsec = 0; + + inode->i_blocks = sd_v1_blocks(sd); + inode->i_generation = le32_to_cpu(INODE_PKEY(inode)->k_dir_id); +@@ -1194,9 +1180,6 @@ static void init_inode(struct inode *ino + inode->i_mtime.tv_sec = sd_v2_mtime(sd); + inode->i_atime.tv_sec = sd_v2_atime(sd); + inode->i_ctime.tv_sec = sd_v2_ctime(sd); +- inode->i_ctime.tv_nsec = 0; +- inode->i_mtime.tv_nsec = 0; +- inode->i_atime.tv_nsec = 0; + inode->i_blocks = sd_v2_blocks(sd); + rdev = sd_v2_rdev(sd); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) +@@ -1821,18 +1804,9 @@ int reiserfs_new_inode(struct reiserfs_t + U32_MAX /*NO_BYTES_IN_DIRECT_ITEM */ ; + + INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list)); +- REISERFS_I(inode)->i_flags = 0; +- REISERFS_I(inode)->i_prealloc_block = 0; +- REISERFS_I(inode)->i_prealloc_count = 0; +- REISERFS_I(inode)->i_trans_id = 0; +- REISERFS_I(inode)->i_jl = NULL; + REISERFS_I(inode)->i_attrs = + REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; + sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); +- mutex_init(&(REISERFS_I(inode)->i_mmap)); +- reiserfs_init_acl_access(inode); +- reiserfs_init_acl_default(inode); +- reiserfs_init_xattr_rwsem(inode); + + if (old_format_only(sb)) + make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, +--- a/fs/reiserfs/super.c ++++ b/fs/reiserfs/super.c +@@ -524,8 +524,17 @@ static void init_once(void *foo) + { + struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; + +- INIT_LIST_HEAD(&ei->i_prealloc_list); + inode_init_once(&ei->vfs_inode); ++ INIT_LIST_HEAD(&ei->i_prealloc_list); ++ mutex_init(&ei->i_mmap); ++#ifdef CONFIG_REISERFS_FS_XATTR ++ init_rwsem(&ei->xattr_sem); ++#endif ++ ei->i_flags = 0; ++ ei->i_prealloc_block = 0; ++ ei->i_prealloc_count = 0; ++ ei->i_trans_id = 0; ++ ei->i_jl = NULL; + #ifdef CONFIG_REISERFS_FS_POSIX_ACL + ei->i_acl_access = NULL; + ei->i_acl_default = NULL; +--- a/include/linux/reiserfs_xattr.h ++++ b/include/linux/reiserfs_xattr.h +@@ -109,11 +109,6 @@ static inline void reiserfs_mark_inode_p + inode->i_flags |= S_PRIVATE; + } + +-static inline void reiserfs_init_xattr_rwsem(struct inode *inode) +-{ +- init_rwsem(&REISERFS_I(inode)->xattr_sem); +-} +- + #else + + #define is_reiserfs_priv_object(inode) 0 +@@ -146,9 +141,6 @@ static inline int reiserfs_xattr_init(st + sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */ + return 0; + }; +-static inline void reiserfs_init_xattr_rwsem(struct inode *inode) +-{ +-} + #endif /* CONFIG_REISERFS_FS_XATTR */ + + #endif /* __KERNEL__ */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-mount-count b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-mount-count new file mode 100644 index 000000000..4b71fcaed --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-mount-count @@ -0,0 +1,65 @@ +From: Jeff Mahoney +Subject: reiserfs: add support for mount count incrementing + + The following patch adds the fields for tracking mount counts and + last fsck timestamps to the superblock. It also increments the mount + count on every read-write mount. These fields have been reserved on + the reiserfs-devel list, and will be a part of the next reiserfsprogs + release. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/super.c | 6 +++++- + include/linux/reiserfs_fs.h | 6 +++++- + include/linux/reiserfs_fs_sb.h | 3 +++ + 3 files changed, 13 insertions(+), 2 deletions(-) + +--- a/fs/reiserfs/super.c ++++ b/fs/reiserfs/super.c +@@ -1278,6 +1278,8 @@ static int reiserfs_remount(struct super + REISERFS_SB(s)->s_mount_state = sb_umount_state(rs); + s->s_flags &= ~MS_RDONLY; + set_sb_umount_state(rs, REISERFS_ERROR_FS); ++ if (!old_format_only(s)) ++ set_sb_mnt_count(rs, sb_mnt_count(rs) + 1); + /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */ + journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); + REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS; +@@ -1817,7 +1819,9 @@ static int reiserfs_fill_super(struct su + } else if (!silent) { + reiserfs_info(s, "using 3.5.x disk format\n"); + } +- } ++ } else ++ set_sb_mnt_count(rs, sb_mnt_count(rs) + 1); ++ + + journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); + errval = journal_end(&th, s, 1); +--- a/include/linux/reiserfs_fs.h ++++ b/include/linux/reiserfs_fs.h +@@ -171,7 +171,11 @@ struct reiserfs_super_block { + __le32 s_flags; /* Right now used only by inode-attributes, if enabled */ + unsigned char s_uuid[16]; /* filesystem unique identifier */ + unsigned char s_label[16]; /* filesystem volume label */ +- char s_unused[88]; /* zero filled by mkreiserfs and ++ __le16 s_mnt_count; /* Count of mounts since last fsck */ ++ __le16 s_max_mnt_count; /* Maximum mounts before check */ ++ __le32 s_lastcheck; /* Timestamp of last fsck */ ++ __le32 s_check_interval; /* Interval between checks */ ++ char s_unused[76]; /* zero filled by mkreiserfs and + * reiserfs_convert_objectid_map_v1() + * so any additions must be updated + * there as well. */ +--- a/include/linux/reiserfs_fs_sb.h ++++ b/include/linux/reiserfs_fs_sb.h +@@ -73,6 +73,9 @@ typedef enum { + #define sb_version(sbp) (le16_to_cpu((sbp)->s_v1.s_version)) + #define set_sb_version(sbp,v) ((sbp)->s_v1.s_version = cpu_to_le16(v)) + ++#define sb_mnt_count(sbp) (le16_to_cpu((sbp)->s_mnt_count)) ++#define set_sb_mnt_count(sbp, v) ((sbp)->s_mnt_count = cpu_to_le16(v)) ++ + #define sb_reserved_for_journal(sbp) \ + (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal)) + #define set_sb_reserved_for_journal(sbp,v) \ diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-remove-xinode b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-remove-xinode new file mode 100644 index 000000000..e096c49cf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-remove-xinode @@ -0,0 +1,98 @@ +From: Jeff Mahoney +Subject: reiserfs: small variable cleanup + + This patch removes the xinode and mapping variables from + reiserfs_xattr_{get,set}. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/xattr.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +--- a/fs/reiserfs/xattr.c ++++ b/fs/reiserfs/xattr.c +@@ -420,10 +420,8 @@ reiserfs_xattr_set(struct inode *inode, + struct dentry *dentry; + struct page *page; + char *data; +- struct address_space *mapping; + size_t file_pos = 0; + size_t buffer_pos = 0; +- struct inode *xinode; + struct iattr newattrs; + __u32 xahash = 0; + +@@ -441,11 +439,10 @@ reiserfs_xattr_set(struct inode *inode, + goto out; + } + +- xinode = dentry->d_inode; + REISERFS_I(inode)->i_flags |= i_has_xattr_dir; + + /* we need to copy it off.. */ +- if (xinode->i_nlink > 1) { ++ if (dentry->d_inode->i_nlink > 1) { + dput(dentry); + err = reiserfs_xattr_del(inode, name); + if (err < 0) +@@ -459,12 +456,11 @@ reiserfs_xattr_set(struct inode *inode, + /* Resize it so we're ok to write there */ + newattrs.ia_size = buffer_size; + newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; +- mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR); ++ mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); + err = notify_change(dentry, &newattrs); + if (err) + goto out_filp; + +- mapping = xinode->i_mapping; + while (buffer_pos < buffer_size || buffer_pos == 0) { + size_t chunk; + size_t skip = 0; +@@ -474,7 +470,8 @@ reiserfs_xattr_set(struct inode *inode, + else + chunk = buffer_size - buffer_pos; + +- page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); ++ page = reiserfs_get_page(dentry->d_inode, ++ file_pos >> PAGE_CACHE_SHIFT); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto out_filp; +@@ -521,7 +518,7 @@ reiserfs_xattr_set(struct inode *inode, + } + + out_filp: +- mutex_unlock(&xinode->i_mutex); ++ mutex_unlock(&dentry->d_inode->i_mutex); + dput(dentry); + + out: +@@ -541,7 +538,6 @@ reiserfs_xattr_get(const struct inode *i + size_t file_pos = 0; + size_t buffer_pos = 0; + struct page *page; +- struct inode *xinode; + __u32 hash = 0; + + if (name == NULL) +@@ -558,8 +554,7 @@ reiserfs_xattr_get(const struct inode *i + goto out; + } + +- xinode = dentry->d_inode; +- isize = xinode->i_size; ++ isize = i_size_read(dentry->d_inode); + REISERFS_I(inode)->i_flags |= i_has_xattr_dir; + + /* Just return the size needed */ +@@ -582,7 +577,8 @@ reiserfs_xattr_get(const struct inode *i + else + chunk = isize - file_pos; + +- page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT); ++ page = reiserfs_get_page(dentry->d_inode, ++ file_pos >> PAGE_CACHE_SHIFT); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto out_dput; diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-xattr-S_PRIVATE b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-xattr-S_PRIVATE new file mode 100644 index 000000000..c7cc0f809 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-xattr-S_PRIVATE @@ -0,0 +1,235 @@ +From: Jeff Mahoney +Subject: reiserfs: remove IS_PRIVATE helpers + + There are a number of helper functions for marking a reiserfs inode + private that were leftover from reiserfs did its own thing wrt to + private inodes. S_PRIVATE has been in the kernel for some time, + so this patch removes the helpers and uses IS_PRIVATE instead. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/inode.c | 5 ++--- + fs/reiserfs/namei.c | 7 ++++--- + fs/reiserfs/xattr.c | 14 ++++++-------- + fs/reiserfs/xattr_acl.c | 6 +++--- + fs/reiserfs/xattr_security.c | 8 ++++---- + fs/reiserfs/xattr_trusted.c | 8 ++++---- + include/linux/reiserfs_xattr.h | 8 -------- + 7 files changed, 23 insertions(+), 33 deletions(-) + +--- a/fs/reiserfs/inode.c ++++ b/fs/reiserfs/inode.c +@@ -1932,9 +1932,8 @@ int reiserfs_new_inode(struct reiserfs_t + reiserfs_warning(inode->i_sb, "jdm-13090", + "ACLs aren't enabled in the fs, " + "but vfs thinks they are!"); +- } else if (is_reiserfs_priv_object(dir)) { +- reiserfs_mark_inode_private(inode); +- } ++ } else if (IS_PRIVATE(dir)) ++ inode->i_flags |= S_PRIVATE; + + insert_inode_hash(inode); + reiserfs_update_sd(th, inode); +--- a/fs/reiserfs/namei.c ++++ b/fs/reiserfs/namei.c +@@ -358,9 +358,10 @@ static struct dentry *reiserfs_lookup(st + return ERR_PTR(-EACCES); + } + +- /* Propogate the priv_object flag so we know we're in the priv tree */ +- if (is_reiserfs_priv_object(dir)) +- reiserfs_mark_inode_private(inode); ++ /* Propogate the private flag so we know we're ++ * in the priv tree */ ++ if (IS_PRIVATE(dir)) ++ inode->i_flags |= S_PRIVATE; + } + reiserfs_write_unlock(dir->i_sb); + if (retval == IO_ERROR) { +--- a/fs/reiserfs/xattr.c ++++ b/fs/reiserfs/xattr.c +@@ -633,14 +633,14 @@ __reiserfs_xattr_del(struct dentry *xadi + if (S_ISDIR(dentry->d_inode->i_mode)) + goto out_file; + +- if (!is_reiserfs_priv_object(dentry->d_inode)) { ++ if (!IS_PRIVATE(dentry->d_inode)) { + reiserfs_error(dir->i_sb, "jdm-20003", + "OID %08x [%.*s/%.*s] doesn't have " + "priv flag set [parent is %sset].", + le32_to_cpu(INODE_PKEY(dentry->d_inode)-> + k_objectid), xadir->d_name.len, + xadir->d_name.name, namelen, name, +- is_reiserfs_priv_object(xadir->d_inode) ? "" : ++ IS_PRIVATE(xadir->d_inode) ? "" : + "not "); + dput(dentry); + return -EIO; +@@ -701,8 +701,7 @@ int reiserfs_delete_xattrs(struct inode + int err = 0; + + /* Skip out, an xattr has no xattrs associated with it */ +- if (is_reiserfs_priv_object(inode) || +- get_inode_sd_version(inode) == STAT_DATA_V1 || ++ if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || + !reiserfs_xattrs(inode->i_sb)) { + return 0; + } +@@ -786,8 +785,7 @@ int reiserfs_chown_xattrs(struct inode * + unsigned int ia_valid = attrs->ia_valid; + + /* Skip out, an xattr has no xattrs associated with it */ +- if (is_reiserfs_priv_object(inode) || +- get_inode_sd_version(inode) == STAT_DATA_V1 || ++ if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1 || + !reiserfs_xattrs(inode->i_sb)) { + return 0; + } +@@ -1178,7 +1176,7 @@ int reiserfs_xattr_init(struct super_blo + + if (!err && dentry) { + s->s_root->d_op = &xattr_lookup_poison_ops; +- reiserfs_mark_inode_private(dentry->d_inode); ++ dentry->d_inode->i_flags |= S_PRIVATE; + REISERFS_SB(s)->priv_root = dentry; + } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */ + /* If we're read-only it just means that the dir hasn't been +@@ -1239,7 +1237,7 @@ int reiserfs_permission(struct inode *in + * We don't do permission checks on the internal objects. + * Permissions are determined by the "owning" object. + */ +- if (is_reiserfs_priv_object(inode)) ++ if (IS_PRIVATE(inode)) + return 0; + + /* +--- a/fs/reiserfs/xattr_acl.c ++++ b/fs/reiserfs/xattr_acl.c +@@ -335,8 +335,8 @@ reiserfs_inherit_default_acl(struct inod + /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This + * would be useless since permissions are ignored, and a pain because + * it introduces locking cycles */ +- if (is_reiserfs_priv_object(dir)) { +- reiserfs_mark_inode_private(inode); ++ if (IS_PRIVATE(dir)) { ++ inode->i_flags |= S_PRIVATE; + goto apply_umask; + } + +@@ -401,7 +401,7 @@ reiserfs_inherit_default_acl(struct inod + int reiserfs_cache_default_acl(struct inode *inode) + { + int ret = 0; +- if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) { ++ if (reiserfs_posixacl(inode->i_sb) && !IS_PRIVATE(inode)) { + struct posix_acl *acl; + reiserfs_read_lock_xattr_i(inode); + reiserfs_read_lock_xattrs(inode->i_sb); +--- a/fs/reiserfs/xattr_security.c ++++ b/fs/reiserfs/xattr_security.c +@@ -12,7 +12,7 @@ security_get(struct inode *inode, const + if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) + return -EINVAL; + +- if (is_reiserfs_priv_object(inode)) ++ if (IS_PRIVATE(inode)) + return -EPERM; + + return reiserfs_xattr_get(inode, name, buffer, size); +@@ -25,7 +25,7 @@ security_set(struct inode *inode, const + if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) + return -EINVAL; + +- if (is_reiserfs_priv_object(inode)) ++ if (IS_PRIVATE(inode)) + return -EPERM; + + return reiserfs_xattr_set(inode, name, buffer, size, flags); +@@ -36,7 +36,7 @@ static int security_del(struct inode *in + if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX)) + return -EINVAL; + +- if (is_reiserfs_priv_object(inode)) ++ if (IS_PRIVATE(inode)) + return -EPERM; + + return 0; +@@ -47,7 +47,7 @@ security_list(struct inode *inode, const + { + int len = namelen; + +- if (is_reiserfs_priv_object(inode)) ++ if (IS_PRIVATE(inode)) + return 0; + + if (out) +--- a/fs/reiserfs/xattr_trusted.c ++++ b/fs/reiserfs/xattr_trusted.c +@@ -16,7 +16,7 @@ trusted_get(struct inode *inode, const c + if (!reiserfs_xattrs(inode->i_sb)) + return -EOPNOTSUPP; + +- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) ++ if (!(capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))) + return -EPERM; + + return reiserfs_xattr_get(inode, name, buffer, size); +@@ -32,7 +32,7 @@ trusted_set(struct inode *inode, const c + if (!reiserfs_xattrs(inode->i_sb)) + return -EOPNOTSUPP; + +- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) ++ if (!(capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))) + return -EPERM; + + return reiserfs_xattr_set(inode, name, buffer, size, flags); +@@ -46,7 +46,7 @@ static int trusted_del(struct inode *ino + if (!reiserfs_xattrs(inode->i_sb)) + return -EOPNOTSUPP; + +- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) ++ if (!(capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))) + return -EPERM; + + return 0; +@@ -60,7 +60,7 @@ trusted_list(struct inode *inode, const + if (!reiserfs_xattrs(inode->i_sb)) + return 0; + +- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode))) ++ if (!(capable(CAP_SYS_ADMIN) || IS_PRIVATE(inode))) + return 0; + + if (out) +--- a/include/linux/reiserfs_xattr.h ++++ b/include/linux/reiserfs_xattr.h +@@ -44,7 +44,6 @@ struct reiserfs_xattr_handler { + }; + + #ifdef CONFIG_REISERFS_FS_XATTR +-#define is_reiserfs_priv_object(inode) IS_PRIVATE(inode) + #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) + ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, + void *buffer, size_t size); +@@ -104,11 +103,6 @@ static inline void reiserfs_read_unlock_ + up_read(&REISERFS_I(inode)->xattr_sem); + } + +-static inline void reiserfs_mark_inode_private(struct inode *inode) +-{ +- inode->i_flags |= S_PRIVATE; +-} +- + static inline void reiserfs_init_xattr_rwsem(struct inode *inode) + { + init_rwsem(&REISERFS_I(inode)->xattr_sem); +@@ -116,8 +110,6 @@ static inline void reiserfs_init_xattr_r + + #else + +-#define is_reiserfs_priv_object(inode) 0 +-#define reiserfs_mark_inode_private(inode) do {;} while(0) + #define reiserfs_getxattr NULL + #define reiserfs_setxattr NULL + #define reiserfs_listxattr NULL diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs-xattr-get-page b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-xattr-get-page new file mode 100644 index 000000000..4271f98ff --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs-xattr-get-page @@ -0,0 +1,51 @@ +From: Jeff Mahoney +Subject: reiserfs: xattr reiserfs_get_page takes offset instead of index + + This patch changes reiserfs_get_page to take an + offset rather than an index since no callers calculate the index + differently. + +Signed-off-by: Jeff Mahoney +--- + fs/reiserfs/xattr.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +--- a/fs/reiserfs/xattr.c ++++ b/fs/reiserfs/xattr.c +@@ -376,14 +376,14 @@ static inline void reiserfs_put_page(str + page_cache_release(page); + } + +-static struct page *reiserfs_get_page(struct inode *dir, unsigned long n) ++static struct page *reiserfs_get_page(struct inode *dir, size_t n) + { + struct address_space *mapping = dir->i_mapping; + struct page *page; + /* We can deadlock if we try to free dentries, + and an unlink/rmdir has just occured - GFP_NOFS avoids this */ + mapping_set_gfp_mask(mapping, GFP_NOFS); +- page = read_mapping_page(mapping, n, NULL); ++ page = read_mapping_page(mapping, n >> PAGE_CACHE_SHIFT, NULL); + if (!IS_ERR(page)) { + kmap(page); + if (PageError(page)) +@@ -470,8 +470,7 @@ reiserfs_xattr_set(struct inode *inode, + else + chunk = buffer_size - buffer_pos; + +- page = reiserfs_get_page(dentry->d_inode, +- file_pos >> PAGE_CACHE_SHIFT); ++ page = reiserfs_get_page(dentry->d_inode, file_pos); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto out_filp; +@@ -577,8 +576,7 @@ reiserfs_xattr_get(const struct inode *i + else + chunk = isize - file_pos; + +- page = reiserfs_get_page(dentry->d_inode, +- file_pos >> PAGE_CACHE_SHIFT); ++ page = reiserfs_get_page(dentry->d_inode, file_pos); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto out_dput; diff --git a/src/patches/suse-2.6.27.31/patches.suse/reiserfs_warning-reentrant b/src/patches/suse-2.6.27.31/patches.suse/reiserfs_warning-reentrant new file mode 100644 index 000000000..f0a1e2e6f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/reiserfs_warning-reentrant @@ -0,0 +1,37 @@ +From: Jeff Mahoney +Subject: [PATCH] reiserfs: eliminate reiserfs_warning from uniqueness functions + + uniqueness2type and type2uniquness issue a warning when the value is + unknown. When called from reiserfs_warning, this causes a re-entrancy + problem and deadlocks on the error buffer lock. + +Signed-off-by: Jeff Mahoney +--- + include/linux/reiserfs_fs.h | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/include/linux/reiserfs_fs.h ++++ b/include/linux/reiserfs_fs.h +@@ -560,10 +560,8 @@ static inline int uniqueness2type(__u32 + return TYPE_DIRECT; + case V1_DIRENTRY_UNIQUENESS: + return TYPE_DIRENTRY; +- default: +- reiserfs_warning(NULL, "vs-500", "unknown uniqueness %d", +- uniqueness); + case V1_ANY_UNIQUENESS: ++ default: + return TYPE_ANY; + } + } +@@ -580,9 +578,8 @@ static inline __u32 type2uniqueness(int + return V1_DIRECT_UNIQUENESS; + case TYPE_DIRENTRY: + return V1_DIRENTRY_UNIQUENESS; +- default: +- reiserfs_warning(NULL, "vs-501", "unknown type %d", type); + case TYPE_ANY: ++ default: + return V1_ANY_UNIQUENESS; + } + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/rlimit-memlock-64k.patch b/src/patches/suse-2.6.27.31/patches.suse/rlimit-memlock-64k.patch new file mode 100644 index 000000000..c5403795b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/rlimit-memlock-64k.patch @@ -0,0 +1,34 @@ +From: Kurt Garloff +Subject: Increase default RLIMIT_MEMLOCK to 64k +References: bnc#329675 +Patch-Mainline: mm-increase-the-default-mlock-limit-from-32k-to-64k.patch (2.6.28-rc-mm) + +By default, non-privileged tasks can only mlock() a small amount of +memory to avoid a DoS attack by ordinary users. The Linux kernel +defaulted to 32k (on a 4k page size system) to accommodate the +needs of gpg. +However, newer gpg2 needs 64k in various circumstances and otherwise +fails miserably, see bnc#329675. + +Change the default to 64k, and make it more agnostic to PAGE_SIZE. + +Signed-off-by: Kurt Garloff +Signed-off-by: Nick Piggin +--- +Index: linux-2.6.27/include/linux/resource.h +=================================================================== +--- linux-2.6.27.orig/include/linux/resource.h ++++ linux-2.6.27/include/linux/resource.h +@@ -59,10 +59,10 @@ struct rlimit { + #define _STK_LIM (8*1024*1024) + + /* +- * GPG wants 32kB of mlocked memory, to make sure pass phrases ++ * GPG2 wants 64kB of mlocked memory, to make sure pass phrases + * and other sensitive information are never written to disk. + */ +-#define MLOCK_LIMIT (8 * PAGE_SIZE) ++#define MLOCK_LIMIT ((PAGE_SIZE > 64*1024) ? PAGE_SIZE : 64*1024) + + /* + * Due to binary compatibility, the actual resource numbers diff --git a/src/patches/suse-2.6.27.31/patches.suse/rq-based-multipath b/src/patches/suse-2.6.27.31/patches.suse/rq-based-multipath new file mode 100644 index 000000000..2a9594b34 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/rq-based-multipath @@ -0,0 +1,1805 @@ +From: Kiyoshi Ueda +Subject: Request-based multipath patches +References: FATE#302108 + +This is the latest version of the request-based multipathing patches, +posted to dm-devel and linux-scsi on 03.10.2008. + +Signed-off-by: Hannes Reinecke + +--- + drivers/md/dm-ioctl.c | 13 + drivers/md/dm-mpath.c | 192 +++++--- + drivers/md/dm-table.c | 82 +++ + drivers/md/dm.c | 952 +++++++++++++++++++++++++++++++++++++++--- + drivers/md/dm.h | 17 + include/linux/device-mapper.h | 24 + + 6 files changed, 1158 insertions(+), 122 deletions(-) + +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -1046,6 +1046,12 @@ static int populate_table(struct dm_tabl + next = spec->next; + } + ++ r = dm_table_set_type(table); ++ if (r) { ++ DMWARN("unable to set table type"); ++ return r; ++ } ++ + return dm_table_complete(table); + } + +@@ -1069,6 +1075,13 @@ static int table_load(struct dm_ioctl *p + dm_table_put(t); + goto out; + } ++ ++ r = dm_init_md_mempool(md, dm_table_get_type(t)); ++ if (r) { ++ DMWARN("unable to initialize the md mempools for this table"); ++ dm_table_put(t); ++ goto out; ++ } + + down_write(&_hash_lock); + hc = dm_get_mdptr(md); +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -7,8 +7,6 @@ + + #include "dm.h" + #include "dm-path-selector.h" +-#include "dm-bio-list.h" +-#include "dm-bio-record.h" + #include "dm-uevent.h" + + #include +@@ -83,7 +81,7 @@ struct multipath { + unsigned pg_init_count; /* Number of times pg_init called */ + + struct work_struct process_queued_ios; +- struct bio_list queued_ios; ++ struct list_head queued_ios; + unsigned queue_size; + + struct work_struct trigger_event; +@@ -100,7 +98,6 @@ struct multipath { + */ + struct dm_mpath_io { + struct pgpath *pgpath; +- struct dm_bio_details details; + }; + + typedef int (*action_fn) (struct pgpath *pgpath); +@@ -197,6 +194,7 @@ static struct multipath *alloc_multipath + m = kzalloc(sizeof(*m), GFP_KERNEL); + if (m) { + INIT_LIST_HEAD(&m->priority_groups); ++ INIT_LIST_HEAD(&m->queued_ios); + spin_lock_init(&m->lock); + m->queue_io = 1; + INIT_WORK(&m->process_queued_ios, process_queued_ios); +@@ -321,12 +319,13 @@ static int __must_push_back(struct multi + dm_noflush_suspending(m->ti)); + } + +-static int map_io(struct multipath *m, struct bio *bio, ++static int map_io(struct multipath *m, struct request *clone, + struct dm_mpath_io *mpio, unsigned was_queued) + { + int r = DM_MAPIO_REMAPPED; + unsigned long flags; + struct pgpath *pgpath; ++ struct block_device *bdev; + + spin_lock_irqsave(&m->lock, flags); + +@@ -343,16 +342,18 @@ static int map_io(struct multipath *m, s + if ((pgpath && m->queue_io) || + (!pgpath && m->queue_if_no_path)) { + /* Queue for the daemon to resubmit */ +- bio_list_add(&m->queued_ios, bio); ++ list_add_tail(&clone->queuelist, &m->queued_ios); + m->queue_size++; + if ((m->pg_init_required && !m->pg_init_in_progress) || + !m->queue_io) + queue_work(kmultipathd, &m->process_queued_ios); + pgpath = NULL; + r = DM_MAPIO_SUBMITTED; +- } else if (pgpath) +- bio->bi_bdev = pgpath->path.dev->bdev; +- else if (__must_push_back(m)) ++ } else if (pgpath) { ++ bdev = pgpath->path.dev->bdev; ++ clone->q = bdev_get_queue(bdev); ++ clone->rq_disk = bdev->bd_disk; ++ } else if (__must_push_back(m)) + r = DM_MAPIO_REQUEUE; + else + r = -EIO; /* Failed */ +@@ -395,30 +396,31 @@ static void dispatch_queued_ios(struct m + { + int r; + unsigned long flags; +- struct bio *bio = NULL, *next; + struct dm_mpath_io *mpio; + union map_info *info; ++ struct request *clone, *n; ++ LIST_HEAD(cl); + + spin_lock_irqsave(&m->lock, flags); +- bio = bio_list_get(&m->queued_ios); ++ list_splice_init(&m->queued_ios, &cl); + spin_unlock_irqrestore(&m->lock, flags); + +- while (bio) { +- next = bio->bi_next; +- bio->bi_next = NULL; ++ list_for_each_entry_safe(clone, n, &cl, queuelist) { ++ list_del_init(&clone->queuelist); + +- info = dm_get_mapinfo(bio); ++ info = dm_get_rq_mapinfo(clone); + mpio = info->ptr; + +- r = map_io(m, bio, mpio, 1); +- if (r < 0) +- bio_endio(bio, r); +- else if (r == DM_MAPIO_REMAPPED) +- generic_make_request(bio); +- else if (r == DM_MAPIO_REQUEUE) +- bio_endio(bio, -EIO); +- +- bio = next; ++ r = map_io(m, clone, mpio, 1); ++ if (r < 0) { ++ mempool_free(mpio, m->mpio_pool); ++ dm_kill_request(clone, r); ++ } else if (r == DM_MAPIO_REMAPPED) ++ dm_dispatch_request(clone); ++ else if (r == DM_MAPIO_REQUEUE) { ++ mempool_free(mpio, m->mpio_pool); ++ dm_requeue_request(clone); ++ } + } + } + +@@ -844,21 +846,24 @@ static void multipath_dtr(struct dm_targ + } + + /* +- * Map bios, recording original fields for later in case we have to resubmit ++ * Map cloned requests + */ +-static int multipath_map(struct dm_target *ti, struct bio *bio, ++static int multipath_map(struct dm_target *ti, struct request *clone, + union map_info *map_context) + { + int r; + struct dm_mpath_io *mpio; + struct multipath *m = (struct multipath *) ti->private; + +- mpio = mempool_alloc(m->mpio_pool, GFP_NOIO); +- dm_bio_record(&mpio->details, bio); ++ mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC); ++ if (!mpio) ++ /* ENOMEM, requeue */ ++ return DM_MAPIO_REQUEUE; ++ memset(mpio, 0, sizeof(*mpio)); + + map_context->ptr = mpio; +- bio->bi_rw |= (1 << BIO_RW_FAILFAST_TRANSPORT); +- r = map_io(m, bio, mpio, 0); ++ clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; ++ r = map_io(m, clone, mpio, 0); + if (r < 0 || r == DM_MAPIO_REQUEUE) + mempool_free(mpio, m->mpio_pool); + +@@ -1140,53 +1145,41 @@ static void activate_path(struct work_st + /* + * end_io handling + */ +-static int do_end_io(struct multipath *m, struct bio *bio, ++static int do_end_io(struct multipath *m, struct request *clone, + int error, struct dm_mpath_io *mpio) + { ++ /* ++ * We don't queue any clone request inside the multipath target ++ * during end I/O handling, since those clone requests don't have ++ * bio clones. If we queue them inside the multipath target, ++ * we need to make bio clones, that requires memory allocation. ++ * (See drivers/md/dm.c:end_clone_bio() about why the clone requests ++ * don't have bio clones.) ++ * Instead of queueing the clone request here, we queue the original ++ * request into dm core, which will remake a clone request and ++ * clone bios for it and resubmit it later. ++ */ ++ int r = DM_ENDIO_REQUEUE; + unsigned long flags; + +- if (!error) ++ if (!error && !clone->errors) + return 0; /* I/O complete */ + +- if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) +- return error; +- + if (error == -EOPNOTSUPP) + return error; + +- spin_lock_irqsave(&m->lock, flags); +- if (!m->nr_valid_paths) { +- if (__must_push_back(m)) { +- spin_unlock_irqrestore(&m->lock, flags); +- return DM_ENDIO_REQUEUE; +- } else if (!m->queue_if_no_path) { +- spin_unlock_irqrestore(&m->lock, flags); +- return -EIO; +- } else { +- spin_unlock_irqrestore(&m->lock, flags); +- goto requeue; +- } +- } +- spin_unlock_irqrestore(&m->lock, flags); +- + if (mpio->pgpath) + fail_path(mpio->pgpath); + +- requeue: +- dm_bio_restore(&mpio->details, bio); +- +- /* queue for the daemon to resubmit or fail */ + spin_lock_irqsave(&m->lock, flags); +- bio_list_add(&m->queued_ios, bio); +- m->queue_size++; +- if (!m->queue_io) +- queue_work(kmultipathd, &m->process_queued_ios); ++ if (!m->nr_valid_paths && !m->queue_if_no_path && !__must_push_back(m)) ++ r = -EIO; + spin_unlock_irqrestore(&m->lock, flags); + +- return DM_ENDIO_INCOMPLETE; /* io not complete */ ++ return r; + } + +-static int multipath_end_io(struct dm_target *ti, struct bio *bio, ++static int multipath_end_io(struct dm_target *ti, struct request *clone, + int error, union map_info *map_context) + { + struct multipath *m = ti->private; +@@ -1195,14 +1188,13 @@ static int multipath_end_io(struct dm_ta + struct path_selector *ps; + int r; + +- r = do_end_io(m, bio, error, mpio); ++ r = do_end_io(m, clone, error, mpio); + if (pgpath) { + ps = &pgpath->pg->ps; + if (ps->type->end_io) + ps->type->end_io(ps, &pgpath->path); + } +- if (r != DM_ENDIO_INCOMPLETE) +- mempool_free(mpio, m->mpio_pool); ++ mempool_free(mpio, m->mpio_pool); + + return r; + } +@@ -1438,6 +1430,75 @@ static int multipath_ioctl(struct dm_tar + bdev->bd_disk, cmd, arg); + } + ++static int __pgpath_busy(struct pgpath *pgpath) ++{ ++ struct request_queue *q = bdev_get_queue(pgpath->path.dev->bdev); ++ ++ return dm_underlying_device_busy(q); ++} ++ ++/* ++ * We return "busy", only when we can map I/Os but underlying devices ++ * are busy (so even if we map I/Os now, the I/Os will wait on ++ * the underlying queue). ++ * In other words, if we want to kill I/Os or queue them inside us ++ * due to map unavailability, we don't return "busy". Otherwise, ++ * dm core won't give us the I/Os and we can't do what we want. ++ */ ++static int multipath_busy(struct dm_target *ti) ++{ ++ int busy = 0, has_active = 0; ++ struct multipath *m = (struct multipath *) ti->private; ++ struct priority_group *pg; ++ struct pgpath *pgpath; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&m->lock, flags); ++ ++ /* Guess which priority_group will be used at next mapping time */ ++ if (unlikely(!m->current_pgpath && m->next_pg)) ++ pg = m->next_pg; ++ else if (likely(m->current_pg)) ++ pg = m->current_pg; ++ else ++ /* ++ * We don't know which pg will be used at next mapping time. ++ * We don't call __choose_pgpath() here to avoid to trigger ++ * pg_init just by busy checking. ++ * So we don't know whether underlying devices we will be using ++ * at next mapping time are busy or not. Just try mapping. ++ */ ++ goto out; ++ ++ /* ++ * If there is one non-busy active path at least, the path selector ++ * will be able to select it. So we consider such a pg as not busy. ++ */ ++ busy = 1; ++ list_for_each_entry(pgpath, &pg->pgpaths, list) ++ if (pgpath->is_active) { ++ has_active = 1; ++ ++ if (!__pgpath_busy(pgpath)) { ++ busy = 0; ++ break; ++ } ++ } ++ ++ if (!has_active) ++ /* ++ * No active path in this pg, so this pg won't be used and ++ * the current_pg will be changed at next mapping time. ++ * We need to try mapping to determine it. ++ */ ++ busy = 0; ++ ++out: ++ spin_unlock_irqrestore(&m->lock, flags); ++ ++ return busy; ++} ++ + /*----------------------------------------------------------------- + * Module setup + *---------------------------------------------------------------*/ +@@ -1447,13 +1508,14 @@ static struct target_type multipath_targ + .module = THIS_MODULE, + .ctr = multipath_ctr, + .dtr = multipath_dtr, +- .map = multipath_map, +- .end_io = multipath_end_io, ++ .map_rq = multipath_map, ++ .rq_end_io = multipath_end_io, + .presuspend = multipath_presuspend, + .resume = multipath_resume, + .status = multipath_status, + .message = multipath_message, + .ioctl = multipath_ioctl, ++ .busy = multipath_busy, + }; + + static int __init dm_multipath_init(void) +--- a/drivers/md/dm-table.c ++++ b/drivers/md/dm-table.c +@@ -108,6 +108,8 @@ static void combine_restrictions_low(str + lhs->bounce_pfn = min_not_zero(lhs->bounce_pfn, rhs->bounce_pfn); + + lhs->no_cluster |= rhs->no_cluster; ++ ++ lhs->no_request_stacking |= rhs->no_request_stacking; + } + + /* +@@ -522,6 +524,8 @@ void dm_set_device_limits(struct dm_targ + rs->bounce_pfn = min_not_zero(rs->bounce_pfn, q->bounce_pfn); + + rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); ++ ++ rs->no_request_stacking |= !blk_queue_stackable(q); + } + EXPORT_SYMBOL_GPL(dm_set_device_limits); + +@@ -731,6 +735,66 @@ int dm_table_add_target(struct dm_table + return r; + } + ++int dm_table_set_type(struct dm_table *t) ++{ ++ int i; ++ int bio_based = 0, request_based = 0; ++ struct dm_target *tgt; ++ ++ for (i = 0; i < t->num_targets; i++) { ++ tgt = t->targets + i; ++ if (tgt->type->map_rq) ++ request_based = 1; ++ else ++ bio_based = 1; ++ ++ if (bio_based && request_based) { ++ DMWARN("Inconsistent table: different target types" ++ " can't be mixed up"); ++ return -EINVAL; ++ } ++ } ++ ++ if (bio_based) { ++ /* We must use this table as bio-based */ ++ t->limits.no_request_stacking = 1; ++ return 0; ++ } ++ ++ BUG_ON(!request_based); /* No targets in this table */ ++ ++ /* Non-request-stackable devices can't be used for request-based dm */ ++ if (t->limits.no_request_stacking) { ++ DMWARN("table load rejected: including non-request-stackable" ++ " devices"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Request-based dm supports only tables that have a single target now. ++ * To support multiple targets, request splitting support is needed, ++ * and that needs lots of changes in the block-layer. ++ * (e.g. request completion process for partial completion.) ++ */ ++ if (t->num_targets > 1) { ++ DMWARN("Request-based dm doesn't support multiple targets yet"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int dm_table_get_type(struct dm_table *t) ++{ ++ return t->limits.no_request_stacking ? ++ DM_TYPE_BIO_BASED : DM_TYPE_REQUEST_BASED; ++} ++ ++int dm_table_request_based(struct dm_table *t) ++{ ++ return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED; ++} ++ + static int setup_indexes(struct dm_table *t) + { + int i; +@@ -861,6 +925,10 @@ void dm_table_set_restrictions(struct dm + else + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); + ++ if (t->limits.no_request_stacking) ++ queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, q); ++ else ++ queue_flag_set_unlocked(QUEUE_FLAG_STACKABLE, q); + } + + unsigned int dm_table_get_num_targets(struct dm_table *t) +@@ -949,6 +1017,20 @@ int dm_table_any_congested(struct dm_tab + return r; + } + ++int dm_table_any_busy_target(struct dm_table *t) ++{ ++ int i; ++ struct dm_target *ti; ++ ++ for (i = 0; i < t->num_targets; i++) { ++ ti = t->targets + i; ++ if (ti->type->busy && ti->type->busy(ti)) ++ return 1; ++ } ++ ++ return 0; ++} ++ + void dm_table_unplug_all(struct dm_table *t) + { + struct dm_dev *dd; +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -32,6 +32,7 @@ static unsigned int _major = 0; + + static DEFINE_SPINLOCK(_minor_lock); + /* ++ * For bio based dm. + * One of these is allocated per bio. + */ + struct dm_io { +@@ -43,6 +44,7 @@ struct dm_io { + }; + + /* ++ * For bio based dm. + * One of these is allocated per target within a bio. Hopefully + * this will be simplified out one day. + */ +@@ -52,6 +54,31 @@ struct dm_target_io { + union map_info info; + }; + ++/* ++ * For request based dm. ++ * One of these is allocated per request. ++ * ++ * Since assuming "original request : cloned request = 1 : 1" and ++ * a counter for number of clones like struct dm_io.io_count isn't needed, ++ * struct dm_io and struct target_io can be merged. ++ */ ++struct dm_rq_target_io { ++ struct mapped_device *md; ++ struct dm_target *ti; ++ struct request *orig, clone; ++ int error; ++ union map_info info; ++}; ++ ++/* ++ * For request based dm. ++ * One of these is allocated per bio. ++ */ ++struct dm_clone_bio_info { ++ struct bio *orig; ++ struct request *rq; ++}; ++ + union map_info *dm_get_mapinfo(struct bio *bio) + { + if (bio && bio->bi_private) +@@ -59,6 +86,14 @@ union map_info *dm_get_mapinfo(struct bi + return NULL; + } + ++union map_info *dm_get_rq_mapinfo(struct request *rq) ++{ ++ if (rq && rq->end_io_data) ++ return &((struct dm_rq_target_io *)rq->end_io_data)->info; ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo); ++ + #define MINOR_ALLOCED ((void *)-1) + + /* +@@ -76,7 +111,6 @@ union map_info *dm_get_mapinfo(struct bi + */ + struct dm_wq_req { + enum { +- DM_WQ_FLUSH_ALL, + DM_WQ_FLUSH_DEFERRED, + } type; + struct work_struct work; +@@ -126,6 +160,8 @@ struct mapped_device { + + struct bio_set *bs; + ++ unsigned int mempool_type; /* Type of mempools above. */ ++ + /* + * Event handling. + */ +@@ -143,52 +179,74 @@ struct mapped_device { + + /* forced geometry settings */ + struct hd_geometry geometry; ++ ++ /* marker of flush suspend for request-based dm */ ++ struct request suspend_rq; ++ ++ /* For saving the address of __make_request for request based dm */ ++ make_request_fn *saved_make_request_fn; + }; + + #define MIN_IOS 256 + static struct kmem_cache *_io_cache; + static struct kmem_cache *_tio_cache; ++static struct kmem_cache *_rq_tio_cache; ++static struct kmem_cache *_bio_info_cache; + + static int __init local_init(void) + { +- int r; ++ int r = -ENOMEM; + + /* allocate a slab for the dm_ios */ + _io_cache = KMEM_CACHE(dm_io, 0); + if (!_io_cache) +- return -ENOMEM; ++ return r; + + /* allocate a slab for the target ios */ + _tio_cache = KMEM_CACHE(dm_target_io, 0); +- if (!_tio_cache) { +- kmem_cache_destroy(_io_cache); +- return -ENOMEM; +- } ++ if (!_tio_cache) ++ goto out_free_io_cache; ++ ++ _rq_tio_cache = KMEM_CACHE(dm_rq_target_io, 0); ++ if (!_rq_tio_cache) ++ goto out_free_tio_cache; ++ ++ _bio_info_cache = KMEM_CACHE(dm_clone_bio_info, 0); ++ if (!_bio_info_cache) ++ goto out_free_rq_tio_cache; + + r = dm_uevent_init(); +- if (r) { +- kmem_cache_destroy(_tio_cache); +- kmem_cache_destroy(_io_cache); +- return r; +- } ++ if (r) ++ goto out_free_bio_info_cache; + + _major = major; + r = register_blkdev(_major, _name); +- if (r < 0) { +- kmem_cache_destroy(_tio_cache); +- kmem_cache_destroy(_io_cache); +- dm_uevent_exit(); +- return r; +- } ++ if (r < 0) ++ goto out_uevent_exit; + + if (!_major) + _major = r; + + return 0; ++ ++out_uevent_exit: ++ dm_uevent_exit(); ++out_free_bio_info_cache: ++ kmem_cache_destroy(_bio_info_cache); ++out_free_rq_tio_cache: ++ kmem_cache_destroy(_rq_tio_cache); ++out_free_tio_cache: ++ kmem_cache_destroy(_tio_cache); ++out_free_io_cache: ++ kmem_cache_destroy(_io_cache); ++ ++ return r; + } + + static void local_exit(void) + { ++ kmem_cache_destroy(_bio_info_cache); ++ kmem_cache_destroy(_rq_tio_cache); + kmem_cache_destroy(_tio_cache); + kmem_cache_destroy(_io_cache); + unregister_blkdev(_major, _name); +@@ -380,6 +438,28 @@ static void free_tio(struct mapped_devic + mempool_free(tio, md->tio_pool); + } + ++static inline struct dm_rq_target_io *alloc_rq_tio(struct mapped_device *md) ++{ ++ return mempool_alloc(md->tio_pool, GFP_ATOMIC); ++} ++ ++static inline void free_rq_tio(struct mapped_device *md, ++ struct dm_rq_target_io *tio) ++{ ++ mempool_free(tio, md->tio_pool); ++} ++ ++static inline struct dm_clone_bio_info *alloc_bio_info(struct mapped_device *md) ++{ ++ return mempool_alloc(md->io_pool, GFP_ATOMIC); ++} ++ ++static inline void free_bio_info(struct mapped_device *md, ++ struct dm_clone_bio_info *info) ++{ ++ mempool_free(info, md->io_pool); ++} ++ + static void start_io_acct(struct dm_io *io) + { + struct mapped_device *md = io->md; +@@ -568,6 +648,266 @@ static void clone_endio(struct bio *bio, + free_tio(md, tio); + } + ++/* ++ * Partial completion handling for request-based dm ++ */ ++static void end_clone_bio(struct bio *clone, int error) ++{ ++ struct dm_clone_bio_info *info = clone->bi_private; ++ struct dm_rq_target_io *tio = info->rq->end_io_data; ++ struct bio *bio = info->orig; ++ unsigned int nr_bytes = info->orig->bi_size; ++ ++ free_bio_info(tio->md, info); ++ clone->bi_private = tio->md->bs; ++ bio_put(clone); ++ ++ if (tio->error) { ++ /* ++ * An error has already been detected on the request. ++ * Once error occurred, just let clone->end_io() handle ++ * the remainder. ++ */ ++ return; ++ } else if (error) { ++ /* ++ * Don't notice the error to the upper layer yet. ++ * The error handling decision is made by the target driver, ++ * when the request is completed. ++ */ ++ tio->error = error; ++ return; ++ } ++ ++ /* ++ * I/O for the bio successfully completed. ++ * Notice the data completion to the upper layer. ++ */ ++ ++ /* ++ * bios are processed from the head of the list. ++ * So the completing bio should always be rq->bio. ++ * If it's not, something wrong is happening. ++ */ ++ if (tio->orig->bio != bio) ++ DMERR("bio completion is going in the middle of the request"); ++ ++ /* ++ * Update the original request. ++ * Do not use blk_end_request() here, because it may complete ++ * the original request before the clone, and break the ordering. ++ */ ++ blk_update_request(tio->orig, 0, nr_bytes); ++} ++ ++static void free_bio_clone(struct request *clone) ++{ ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ struct mapped_device *md = tio->md; ++ struct bio *bio; ++ struct dm_clone_bio_info *info; ++ ++ while ((bio = clone->bio) != NULL) { ++ clone->bio = bio->bi_next; ++ ++ info = bio->bi_private; ++ free_bio_info(md, info); ++ ++ bio->bi_private = md->bs; ++ bio_put(bio); ++ } ++} ++ ++static void dec_rq_pending(struct dm_rq_target_io *tio) ++{ ++ if (!atomic_dec_return(&tio->md->pending)) ++ /* nudge anyone waiting on suspend queue */ ++ wake_up(&tio->md->wait); ++} ++ ++static void dm_unprep_request(struct request *rq) ++{ ++ struct request *clone = rq->special; ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ ++ rq->special = NULL; ++ rq->cmd_flags &= ~REQ_DONTPREP; ++ ++ free_bio_clone(clone); ++ dec_rq_pending(tio); ++ free_rq_tio(tio->md, tio); ++} ++ ++/* ++ * Requeue the original request of a clone. ++ */ ++void dm_requeue_request(struct request *clone) ++{ ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ struct request *rq = tio->orig; ++ struct request_queue *q = rq->q; ++ unsigned long flags; ++ ++ dm_unprep_request(rq); ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ if (elv_queue_empty(q)) ++ blk_plug_device(q); ++ blk_requeue_request(q, rq); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++} ++EXPORT_SYMBOL_GPL(dm_requeue_request); ++ ++static inline void __stop_queue(struct request_queue *q) ++{ ++ blk_stop_queue(q); ++} ++ ++static void stop_queue(struct request_queue *q) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ __stop_queue(q); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++} ++ ++static inline void __start_queue(struct request_queue *q) ++{ ++ if (blk_queue_stopped(q)) ++ blk_start_queue(q); ++} ++ ++static void start_queue(struct request_queue *q) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ __start_queue(q); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++} ++ ++/* ++ * Complete the clone and the original request ++ */ ++static void dm_end_request(struct request *clone, int error) ++{ ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ struct request *rq = tio->orig; ++ struct request_queue *q = rq->q; ++ unsigned int nr_bytes = blk_rq_bytes(rq); ++ ++ if (blk_pc_request(rq)) { ++ rq->errors = clone->errors; ++ rq->data_len = clone->data_len; ++ ++ if (rq->sense) ++ /* ++ * We are using the sense buffer of the original ++ * request. ++ * So setting the length of the sense data is enough. ++ */ ++ rq->sense_len = clone->sense_len; ++ } ++ ++ free_bio_clone(clone); ++ dec_rq_pending(tio); ++ free_rq_tio(tio->md, tio); ++ ++ if (unlikely(blk_end_request(rq, error, nr_bytes))) ++ BUG(); ++ ++ blk_run_queue(q); ++} ++ ++/* ++ * Request completion handler for request-based dm ++ */ ++static void dm_softirq_done(struct request *rq) ++{ ++ struct request *clone = rq->completion_data; ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io; ++ int error = tio->error; ++ int r; ++ ++ if (rq->cmd_flags & REQ_FAILED) ++ goto end_request; ++ ++ if (rq_end_io) { ++ r = rq_end_io(tio->ti, clone, error, &tio->info); ++ if (r <= 0) ++ /* The target wants to complete the I/O */ ++ error = r; ++ else if (r == DM_ENDIO_INCOMPLETE) ++ /* The target will handle the I/O */ ++ return; ++ else if (r == DM_ENDIO_REQUEUE) { ++ /* ++ * The target wants to requeue the I/O. ++ * Don't invoke blk_run_queue() so that the requeued ++ * request won't be dispatched again soon. ++ */ ++ dm_requeue_request(clone); ++ return; ++ } else { ++ DMWARN("unimplemented target endio return value: %d", ++ r); ++ BUG(); ++ } ++ } ++ ++end_request: ++ dm_end_request(clone, error); ++} ++ ++/* ++ * Called with the queue lock held ++ */ ++static void end_clone_request(struct request *clone, int error) ++{ ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ struct request *rq = tio->orig; ++ ++ /* ++ * For just cleaning up the information of the queue in which ++ * the clone was dispatched. ++ * The clone is *NOT* freed actually here because it is alloced from ++ * dm own mempool and REQ_ALLOCED isn't set in clone->cmd_flags. ++ */ ++ __blk_put_request(clone->q, clone); ++ ++ /* ++ * Actual request completion is done in a softirq context which doesn't ++ * hold the queue lock. Otherwise, deadlock could occur because: ++ * - another request may be submitted by the upper level driver ++ * of the stacking during the completion ++ * - the submission which requires queue lock may be done ++ * against this queue ++ */ ++ tio->error = error; ++ rq->completion_data = clone; ++ blk_complete_request(rq); ++} ++ ++/* ++ * Complete the original request of a clone with an error status. ++ * Target's rq_end_io() function isn't called. ++ * This may be used by target's map_rq() function when the mapping fails. ++ */ ++void dm_kill_request(struct request *clone, int error) ++{ ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ struct request *rq = tio->orig; ++ ++ tio->error = error; ++ /* Avoid printing "I/O error" message, since we didn't I/O actually */ ++ rq->cmd_flags |= (REQ_FAILED | REQ_QUIET); ++ rq->completion_data = clone; ++ blk_complete_request(rq); ++} ++EXPORT_SYMBOL_GPL(dm_kill_request); ++ + static sector_t max_io_len(struct mapped_device *md, + sector_t sector, struct dm_target *ti) + { +@@ -886,7 +1226,7 @@ out: + * The request function that just remaps the bio built up by + * dm_merge_bvec. + */ +-static int dm_request(struct request_queue *q, struct bio *bio) ++static int _dm_request(struct request_queue *q, struct bio *bio) + { + int r = -EIO; + int rw = bio_data_dir(bio); +@@ -936,12 +1276,335 @@ out_req: + return 0; + } + ++static int dm_make_request(struct request_queue *q, struct bio *bio) ++{ ++ struct mapped_device *md = (struct mapped_device *)q->queuedata; ++ ++ if (unlikely(bio_barrier(bio))) { ++ bio_endio(bio, -EOPNOTSUPP); ++ return 0; ++ } ++ ++ if (unlikely(!md->map)) { ++ bio_endio(bio, -EIO); ++ return 0; ++ } ++ ++ return md->saved_make_request_fn(q, bio); /* call __make_request() */ ++} ++ ++static inline int dm_request_based(struct mapped_device *md) ++{ ++ return blk_queue_stackable(md->queue); ++} ++ ++static int dm_request(struct request_queue *q, struct bio *bio) ++{ ++ struct mapped_device *md = q->queuedata; ++ ++ if (dm_request_based(md)) ++ return dm_make_request(q, bio); ++ ++ return _dm_request(q, bio); ++} ++ ++void dm_dispatch_request(struct request *rq) ++{ ++ int r; ++ ++ rq->start_time = jiffies; ++ r = blk_insert_cloned_request(rq->q, rq); ++ if (r) ++ dm_kill_request(rq, r); ++} ++EXPORT_SYMBOL_GPL(dm_dispatch_request); ++ ++static void copy_request_info(struct request *clone, struct request *rq) ++{ ++ clone->cmd_flags = (rq_data_dir(rq) | REQ_NOMERGE); ++ clone->cmd_type = rq->cmd_type; ++ clone->sector = rq->sector; ++ clone->hard_sector = rq->hard_sector; ++ clone->nr_sectors = rq->nr_sectors; ++ clone->hard_nr_sectors = rq->hard_nr_sectors; ++ clone->current_nr_sectors = rq->current_nr_sectors; ++ clone->hard_cur_sectors = rq->hard_cur_sectors; ++ clone->nr_phys_segments = rq->nr_phys_segments; ++ clone->ioprio = rq->ioprio; ++ clone->buffer = rq->buffer; ++ clone->cmd_len = rq->cmd_len; ++ if (rq->cmd_len) ++ clone->cmd = rq->cmd; ++ clone->data_len = rq->data_len; ++ clone->extra_len = rq->extra_len; ++ clone->sense_len = rq->sense_len; ++ clone->data = rq->data; ++ clone->sense = rq->sense; ++} ++ ++static int clone_request_bios(struct request *clone, struct request *rq, ++ struct mapped_device *md) ++{ ++ struct bio *bio, *clone_bio; ++ struct dm_clone_bio_info *info; ++ ++ for (bio = rq->bio; bio; bio = bio->bi_next) { ++ info = alloc_bio_info(md); ++ if (!info) ++ goto free_and_out; ++ ++ clone_bio = bio_alloc_bioset(GFP_ATOMIC, bio->bi_max_vecs, ++ md->bs); ++ if (!clone_bio) { ++ free_bio_info(md, info); ++ goto free_and_out; ++ } ++ ++ __bio_clone(clone_bio, bio); ++ clone_bio->bi_destructor = dm_bio_destructor; ++ clone_bio->bi_end_io = end_clone_bio; ++ info->rq = clone; ++ info->orig = bio; ++ clone_bio->bi_private = info; ++ ++ if (clone->bio) { ++ clone->biotail->bi_next = clone_bio; ++ clone->biotail = clone_bio; ++ } else ++ clone->bio = clone->biotail = clone_bio; ++ } ++ ++ return 0; ++ ++free_and_out: ++ free_bio_clone(clone); ++ ++ return -ENOMEM; ++} ++ ++static int setup_clone(struct request *clone, struct request *rq, ++ struct dm_rq_target_io *tio) ++{ ++ int r; ++ ++ blk_rq_init(NULL, clone); ++ ++ r = clone_request_bios(clone, rq, tio->md); ++ if (r) ++ return r; ++ ++ copy_request_info(clone, rq); ++ clone->start_time = jiffies; ++ clone->end_io = end_clone_request; ++ clone->end_io_data = tio; ++ ++ return 0; ++} ++ ++static inline int dm_flush_suspending(struct mapped_device *md) ++{ ++ return !md->suspend_rq.data; ++} ++ ++/* ++ * Called with the queue lock held. ++ */ ++static int dm_prep_fn(struct request_queue *q, struct request *rq) ++{ ++ struct mapped_device *md = (struct mapped_device *)q->queuedata; ++ struct dm_rq_target_io *tio; ++ struct request *clone; ++ ++ if (unlikely(rq == &md->suspend_rq)) { /* Flush suspend marker */ ++ if (dm_flush_suspending(md)) { ++ if (q->in_flight) ++ return BLKPREP_DEFER; ++ else { ++ /* This device should be quiet now */ ++ __stop_queue(q); ++ smp_mb(); ++ BUG_ON(atomic_read(&md->pending)); ++ wake_up(&md->wait); ++ return BLKPREP_KILL; ++ } ++ } else ++ /* ++ * The suspend process was interrupted. ++ * So no need to suspend now. ++ */ ++ return BLKPREP_KILL; ++ } ++ ++ if (unlikely(rq->special)) { ++ DMWARN("Already has something in rq->special."); ++ return BLKPREP_KILL; ++ } ++ ++ if (unlikely(!dm_request_based(md))) { ++ DMWARN("Request was queued into bio-based device"); ++ return BLKPREP_KILL; ++ } ++ ++ tio = alloc_rq_tio(md); /* Only one for each original request */ ++ if (!tio) ++ /* -ENOMEM */ ++ return BLKPREP_DEFER; ++ ++ tio->md = md; ++ tio->ti = NULL; ++ tio->orig = rq; ++ tio->error = 0; ++ memset(&tio->info, 0, sizeof(tio->info)); ++ ++ clone = &tio->clone; ++ if (setup_clone(clone, rq, tio)) { ++ /* -ENOMEM */ ++ free_rq_tio(md, tio); ++ return BLKPREP_DEFER; ++ } ++ ++ rq->special = clone; ++ rq->cmd_flags |= REQ_DONTPREP; ++ ++ return BLKPREP_OK; ++} ++ ++static void map_request(struct dm_target *ti, struct request *rq, ++ struct mapped_device *md) ++{ ++ int r; ++ struct request *clone = rq->special; ++ struct dm_rq_target_io *tio = clone->end_io_data; ++ ++ tio->ti = ti; ++ atomic_inc(&md->pending); ++ ++ /* ++ * Although submitted requests to the md->queue are checked against ++ * the table/queue limitations at the submission time, the limitations ++ * may be changed by a table swapping while those already checked ++ * requests are in the md->queue. ++ * If the limitations have been shrunk in such situations, we may be ++ * dispatching requests violating the current limitations here. ++ * Since struct request is a reliable one in the block-layer ++ * and device drivers, dispatching such requests is dangerous. ++ * (e.g. it may cause kernel panic easily.) ++ * Avoid to dispatch such problematic requests in request-based dm. ++ * ++ * Since dm_kill_request() decrements the md->pending, this have to ++ * be done after incrementing the md->pending. ++ */ ++ r = blk_rq_check_limits(rq->q, rq); ++ if (unlikely(r)) { ++ DMWARN("violating the queue limitation. the limitation may be" ++ " shrunk while there are some requests in the queue."); ++ dm_kill_request(clone, r); ++ return; ++ } ++ ++ r = ti->type->map_rq(ti, clone, &tio->info); ++ switch (r) { ++ case DM_MAPIO_SUBMITTED: ++ /* The target has taken the I/O to submit by itself later */ ++ break; ++ case DM_MAPIO_REMAPPED: ++ /* The target has remapped the I/O so dispatch it */ ++ dm_dispatch_request(clone); ++ break; ++ case DM_MAPIO_REQUEUE: ++ /* The target wants to requeue the I/O */ ++ dm_requeue_request(clone); ++ break; ++ default: ++ if (r > 0) { ++ DMWARN("unimplemented target map return value: %d", r); ++ BUG(); ++ } ++ ++ /* The target wants to complete the I/O */ ++ dm_kill_request(clone, r); ++ break; ++ } ++} ++ ++/* ++ * q->request_fn for request-based dm. ++ * Called with the queue lock held. ++ */ ++static void dm_request_fn(struct request_queue *q) ++{ ++ struct mapped_device *md = (struct mapped_device *)q->queuedata; ++ struct dm_table *map = dm_get_table(md); ++ struct dm_target *ti; ++ struct request *rq; ++ ++ /* ++ * The check for blk_queue_stopped() needs here, because: ++ * - device suspend uses blk_stop_queue() and expects that ++ * no I/O will be dispatched any more after the queue stop ++ * - generic_unplug_device() doesn't call q->request_fn() ++ * when the queue is stopped, so no problem ++ * - but underlying device drivers may call q->request_fn() ++ * without the check through blk_run_queue() ++ */ ++ while (!blk_queue_plugged(q) && !blk_queue_stopped(q)) { ++ rq = elv_next_request(q); ++ if (!rq) ++ goto plug_and_out; ++ ++ ti = dm_table_find_target(map, rq->sector); ++ if (ti->type->busy && ti->type->busy(ti)) ++ goto plug_and_out; ++ ++ blkdev_dequeue_request(rq); ++ spin_unlock(q->queue_lock); ++ map_request(ti, rq, md); ++ spin_lock_irq(q->queue_lock); ++ } ++ ++ goto out; ++ ++plug_and_out: ++ if (!elv_queue_empty(q)) ++ /* Some requests still remain, retry later */ ++ blk_plug_device(q); ++ ++out: ++ dm_table_put(map); ++ ++ return; ++} ++ ++int dm_underlying_device_busy(struct request_queue *q) ++{ ++ return blk_lld_busy(q); ++} ++EXPORT_SYMBOL_GPL(dm_underlying_device_busy); ++ ++static int dm_lld_busy(struct request_queue *q) ++{ ++ int r; ++ struct mapped_device *md = q->queuedata; ++ struct dm_table *map = dm_get_table(md); ++ ++ if (!map || test_bit(DMF_BLOCK_IO, &md->flags)) ++ r = 1; ++ else ++ r = dm_table_any_busy_target(map); ++ ++ dm_table_put(map); ++ return r; ++} ++ + static void dm_unplug_all(struct request_queue *q) + { + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + + if (map) { ++ if (dm_request_based(md)) ++ generic_unplug_device(q); ++ + dm_table_unplug_all(map); + dm_table_put(map); + } +@@ -955,6 +1618,12 @@ static int dm_any_congested(void *conges + + if (!map || test_bit(DMF_BLOCK_IO, &md->flags)) + r = bdi_bits; ++ else if (dm_request_based(md)) ++ /* ++ * Request-based dm cares about only own queue for ++ * the query about congestion status of request_queue ++ */ ++ r = md->queue->backing_dev_info.state & bdi_bits; + else + r = dm_table_any_congested(map, bdi_bits); + +@@ -1075,10 +1744,22 @@ static struct mapped_device *alloc_dev(i + INIT_LIST_HEAD(&md->uevent_list); + spin_lock_init(&md->uevent_lock); + +- md->queue = blk_alloc_queue(GFP_KERNEL); ++ md->queue = blk_init_queue(dm_request_fn, NULL); + if (!md->queue) + goto bad_queue; + ++ /* ++ * Request-based dm devices cannot be stacked on top of bio-based dm ++ * devices. The type of this dm device has not been decided yet, ++ * although we initialized the queue using blk_init_queue(). ++ * The type is decided at the first table loading time. ++ * To prevent problematic device stacking, clear the queue flag ++ * for request stacking support until then. ++ * ++ * This queue is new, so no concurrency on the queue_flags. ++ */ ++ queue_flag_clear_unlocked(QUEUE_FLAG_STACKABLE, md->queue); ++ md->saved_make_request_fn = md->queue->make_request_fn; + md->queue->queuedata = md; + md->queue->backing_dev_info.congested_fn = dm_any_congested; + md->queue->backing_dev_info.congested_data = md; +@@ -1086,18 +1767,9 @@ static struct mapped_device *alloc_dev(i + blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); + md->queue->unplug_fn = dm_unplug_all; + blk_queue_merge_bvec(md->queue, dm_merge_bvec); +- +- md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache); +- if (!md->io_pool) +- goto bad_io_pool; +- +- md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache); +- if (!md->tio_pool) +- goto bad_tio_pool; +- +- md->bs = bioset_create(16, 16); +- if (!md->bs) +- goto bad_no_bioset; ++ blk_queue_softirq_done(md->queue, dm_softirq_done); ++ blk_queue_prep_rq(md->queue, dm_prep_fn); ++ blk_queue_lld_busy(md->queue, dm_lld_busy); + + md->disk = alloc_disk(1); + if (!md->disk) +@@ -1132,12 +1804,6 @@ static struct mapped_device *alloc_dev(i + bad_thread: + put_disk(md->disk); + bad_disk: +- bioset_free(md->bs); +-bad_no_bioset: +- mempool_destroy(md->tio_pool); +-bad_tio_pool: +- mempool_destroy(md->io_pool); +-bad_io_pool: + blk_cleanup_queue(md->queue); + bad_queue: + free_minor(minor); +@@ -1159,9 +1825,12 @@ static void free_dev(struct mapped_devic + bdput(md->suspended_bdev); + } + destroy_workqueue(md->wq); +- mempool_destroy(md->tio_pool); +- mempool_destroy(md->io_pool); +- bioset_free(md->bs); ++ if (md->tio_pool) ++ mempool_destroy(md->tio_pool); ++ if (md->io_pool) ++ mempool_destroy(md->io_pool); ++ if (md->bs) ++ bioset_free(md->bs); + del_gendisk(md->disk); + free_minor(minor); + +@@ -1224,6 +1893,16 @@ static int __bind(struct mapped_device * + dm_table_get(t); + dm_table_event_callback(t, event_callback, md); + ++ /* ++ * The queue hasn't been stopped yet, if the old table type wasn't ++ * for request-based during suspension. So stop it to prevent ++ * I/O mapping before resume. ++ * This must be done before setting the queue restrictions, ++ * because request-based dm may be run just after the setting. ++ */ ++ if (dm_table_request_based(t) && !blk_queue_stopped(q)) ++ stop_queue(q); ++ + write_lock(&md->map_lock); + md->map = t; + dm_table_set_restrictions(t, q); +@@ -1346,7 +2025,11 @@ static int dm_wait_for_completion(struct + set_current_state(TASK_INTERRUPTIBLE); + + smp_mb(); +- if (!atomic_read(&md->pending)) ++ if (dm_request_based(md)) { ++ if (!atomic_read(&md->pending) && ++ blk_queue_stopped(md->queue)) ++ break; ++ } else if (!atomic_read(&md->pending)) + break; + + if (signal_pending(current)) { +@@ -1369,7 +2052,13 @@ static void __flush_deferred_io(struct m + struct bio *c; + + while ((c = bio_list_pop(&md->deferred))) { +- if (__split_bio(md, c)) ++ /* ++ * Some bios might have been queued here during suspension ++ * before setting of request-based dm in resume ++ */ ++ if (dm_request_based(md)) ++ generic_make_request(c); ++ else if (__split_bio(md, c)) + bio_io_error(c); + } + +@@ -1394,9 +2083,6 @@ static void dm_wq_work(struct work_struc + + down_write(&md->io_lock); + switch (req->type) { +- case DM_WQ_FLUSH_ALL: +- __merge_pushback_list(md); +- /* pass through */ + case DM_WQ_FLUSH_DEFERRED: + __flush_deferred_io(md); + break; +@@ -1451,6 +2137,88 @@ out: + return r; + } + ++static inline void dm_invalidate_flush_suspend(struct mapped_device *md) ++{ ++ md->suspend_rq.data = (void *)0x1; ++} ++ ++static void dm_abort_suspend(struct mapped_device *md, int noflush) ++{ ++ struct request_queue *q = md->queue; ++ unsigned long flags; ++ ++ /* ++ * For flush suspend, invalidation and queue restart must be protected ++ * by a single queue lock to prevent a race with dm_prep_fn(). ++ */ ++ spin_lock_irqsave(q->queue_lock, flags); ++ if (!noflush) ++ dm_invalidate_flush_suspend(md); ++ __start_queue(q); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++} ++ ++/* ++ * Additional suspend work for request-based dm. ++ * ++ * In request-based dm, stopping request_queue prevents mapping. ++ * Even after stopping the request_queue, submitted requests from upper-layer ++ * can be inserted to the request_queue. So original (unmapped) requests are ++ * kept in the request_queue during suspension. ++ */ ++static void dm_start_suspend(struct mapped_device *md, int noflush) ++{ ++ struct request *rq = &md->suspend_rq; ++ struct request_queue *q = md->queue; ++ unsigned long flags; ++ ++ if (noflush) { ++ stop_queue(q); ++ return; ++ } ++ ++ /* ++ * For flush suspend, we need a marker to indicate the border line ++ * between flush needed I/Os and deferred I/Os, since all I/Os are ++ * queued in the request_queue during suspension. ++ * ++ * This marker must be inserted after setting DMF_BLOCK_IO, ++ * because dm_prep_fn() considers no DMF_BLOCK_IO to be ++ * a suspend interruption. ++ */ ++ spin_lock_irqsave(q->queue_lock, flags); ++ if (unlikely(rq->ref_count)) { ++ /* ++ * This can happen when the previous suspend was interrupted, ++ * the inserted suspend_rq for the previous suspend has still ++ * been in the queue and this suspend has been invoked. ++ * ++ * We could re-insert the suspend_rq by deleting it from ++ * the queue forcibly using list_del_init(&rq->queuelist). ++ * But it would break the block-layer easily. ++ * So we don't re-insert the suspend_rq again in such a case. ++ * The suspend_rq should be already invalidated during ++ * the previous suspend interruption, so just wait for it ++ * to be completed. ++ * ++ * This suspend will never complete, so warn the user to ++ * interrupt this suspend and retry later. ++ */ ++ BUG_ON(!rq->data); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ ++ DMWARN("Invalidating the previous suspend is still in" ++ " progress. This suspend will be never done." ++ " Please interrupt this suspend and retry later."); ++ return; ++ } ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ ++ /* Now no user of the suspend_rq */ ++ blk_rq_init(q, rq); ++ blk_insert_request(q, rq, 0, NULL); ++} ++ + /* + * Functions to lock and unlock any filesystem running on the + * device. +@@ -1526,7 +2294,7 @@ int dm_suspend(struct mapped_device *md, + if (!md->suspended_bdev) { + DMWARN("bdget failed in dm_suspend"); + r = -ENOMEM; +- goto flush_and_out; ++ goto out; + } + + /* +@@ -1549,6 +2317,9 @@ int dm_suspend(struct mapped_device *md, + add_wait_queue(&md->wait, &wait); + up_write(&md->io_lock); + ++ if (dm_request_based(md)) ++ dm_start_suspend(md, noflush); ++ + /* unplug */ + if (map) + dm_table_unplug_all(map); +@@ -1561,14 +2332,22 @@ int dm_suspend(struct mapped_device *md, + down_write(&md->io_lock); + remove_wait_queue(&md->wait, &wait); + +- if (noflush) +- __merge_pushback_list(md); ++ if (noflush) { ++ if (dm_request_based(md)) ++ /* All requeued requests are already in md->queue */ ++ clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); ++ else ++ __merge_pushback_list(md); ++ } + up_write(&md->io_lock); + + /* were we interrupted ? */ + if (r < 0) { + dm_queue_flush(md, DM_WQ_FLUSH_DEFERRED, NULL); + ++ if (dm_request_based(md)) ++ dm_abort_suspend(md, noflush); ++ + unlock_fs(md); + goto out; /* pushback list is already flushed, so skip flush */ + } +@@ -1577,14 +2356,6 @@ int dm_suspend(struct mapped_device *md, + + set_bit(DMF_SUSPENDED, &md->flags); + +-flush_and_out: +- if (r && noflush) +- /* +- * Because there may be already I/Os in the pushback list, +- * flush them before return. +- */ +- dm_queue_flush(md, DM_WQ_FLUSH_ALL, NULL); +- + out: + if (r && md->suspended_bdev) { + bdput(md->suspended_bdev); +@@ -1617,6 +2388,14 @@ int dm_resume(struct mapped_device *md) + + dm_queue_flush(md, DM_WQ_FLUSH_DEFERRED, NULL); + ++ /* ++ * Flushing deferred I/Os must be done after targets are resumed ++ * so that mapping of targets can work correctly. ++ * Request-based dm is queueing the deferred I/Os in its request_queue. ++ */ ++ if (dm_request_based(md)) ++ start_queue(md->queue); ++ + unlock_fs(md); + + if (md->suspended_bdev) { +@@ -1698,6 +2477,65 @@ int dm_noflush_suspending(struct dm_targ + } + EXPORT_SYMBOL_GPL(dm_noflush_suspending); + ++int dm_init_md_mempool(struct mapped_device *md, int type) ++{ ++ if (unlikely(type == DM_TYPE_NONE)) { ++ DMWARN("no type is specified, can't initialize mempool"); ++ return -EINVAL; ++ } ++ ++ if (md->mempool_type == type) ++ return 0; ++ ++ if (md->map) { ++ /* The md has been using, can't change the mempool type */ ++ DMWARN("can't change mempool type after a table is bound"); ++ return -EINVAL; ++ } ++ ++ /* Not using the md yet, we can still change the mempool type */ ++ if (md->mempool_type != DM_TYPE_NONE) { ++ mempool_destroy(md->io_pool); ++ md->io_pool = NULL; ++ mempool_destroy(md->tio_pool); ++ md->tio_pool = NULL; ++ bioset_free(md->bs); ++ md->bs = NULL; ++ md->mempool_type = DM_TYPE_NONE; ++ } ++ ++ md->io_pool = (type == DM_TYPE_BIO_BASED) ? ++ mempool_create_slab_pool(MIN_IOS, _io_cache) : ++ mempool_create_slab_pool(MIN_IOS, _bio_info_cache); ++ if (!md->io_pool) ++ return -ENOMEM; ++ ++ md->tio_pool = (type == DM_TYPE_BIO_BASED) ? ++ mempool_create_slab_pool(MIN_IOS, _tio_cache) : ++ mempool_create_slab_pool(MIN_IOS, _rq_tio_cache); ++ if (!md->tio_pool) ++ goto free_io_pool_and_out; ++ ++ md->bs = (type == DM_TYPE_BIO_BASED) ? ++ bioset_create(16, 16) : bioset_create(MIN_IOS, MIN_IOS); ++ if (!md->bs) ++ goto free_tio_pool_and_out; ++ ++ md->mempool_type = type; ++ ++ return 0; ++ ++free_tio_pool_and_out: ++ mempool_destroy(md->tio_pool); ++ md->tio_pool = NULL; ++ ++free_io_pool_and_out: ++ mempool_destroy(md->io_pool); ++ md->io_pool = NULL; ++ ++ return -ENOMEM; ++} ++ + static struct block_device_operations dm_blk_dops = { + .open = dm_blk_open, + .release = dm_blk_close, +--- a/drivers/md/dm.h ++++ b/drivers/md/dm.h +@@ -23,6 +23,13 @@ + #define DM_SUSPEND_NOFLUSH_FLAG (1 << 1) + + /* ++ * Type of table and mapped_device's mempool ++ */ ++#define DM_TYPE_NONE 0 ++#define DM_TYPE_BIO_BASED 1 ++#define DM_TYPE_REQUEST_BASED 2 ++ ++/* + * List of devices that a metadevice uses and should open/close. + */ + struct dm_dev { +@@ -49,6 +56,10 @@ void dm_table_presuspend_targets(struct + void dm_table_postsuspend_targets(struct dm_table *t); + int dm_table_resume_targets(struct dm_table *t); + int dm_table_any_congested(struct dm_table *t, int bdi_bits); ++int dm_table_any_busy_target(struct dm_table *t); ++int dm_table_set_type(struct dm_table *t); ++int dm_table_get_type(struct dm_table *t); ++int dm_table_request_based(struct dm_table *t); + void dm_table_unplug_all(struct dm_table *t); + + /* +@@ -97,10 +108,16 @@ void *dm_vcalloc(unsigned long nmemb, un + union map_info *dm_get_mapinfo(struct bio *bio); + int dm_open_count(struct mapped_device *md); + int dm_lock_for_deletion(struct mapped_device *md); ++union map_info *dm_get_rq_mapinfo(struct request *rq); + + void dm_kobject_uevent(struct mapped_device *md); + + int dm_kcopyd_init(void); + void dm_kcopyd_exit(void); + ++/* ++ * Mempool initializer for a mapped_device ++ */ ++int dm_init_md_mempool(struct mapped_device *md, int type); ++ + #endif +--- a/include/linux/device-mapper.h ++++ b/include/linux/device-mapper.h +@@ -46,6 +46,8 @@ typedef void (*dm_dtr_fn) (struct dm_tar + */ + typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio, + union map_info *map_context); ++typedef int (*dm_map_request_fn) (struct dm_target *ti, struct request *clone, ++ union map_info *map_context); + + /* + * Returns: +@@ -58,6 +60,9 @@ typedef int (*dm_map_fn) (struct dm_targ + typedef int (*dm_endio_fn) (struct dm_target *ti, + struct bio *bio, int error, + union map_info *map_context); ++typedef int (*dm_request_endio_fn) (struct dm_target *ti, ++ struct request *clone, int error, ++ union map_info *map_context); + + typedef void (*dm_flush_fn) (struct dm_target *ti); + typedef void (*dm_presuspend_fn) (struct dm_target *ti); +@@ -77,6 +82,13 @@ typedef int (*dm_ioctl_fn) (struct dm_ta + typedef int (*dm_merge_fn) (struct dm_target *ti, struct bvec_merge_data *bvm, + struct bio_vec *biovec, int max_size); + ++/* ++ * Returns: ++ * 0: The target can handle the next I/O immediately. ++ * 1: The target can't handle the next I/O immediately. ++ */ ++typedef int (*dm_busy_fn) (struct dm_target *ti); ++ + void dm_error(const char *message); + + /* +@@ -103,7 +115,9 @@ struct target_type { + dm_ctr_fn ctr; + dm_dtr_fn dtr; + dm_map_fn map; ++ dm_map_request_fn map_rq; + dm_endio_fn end_io; ++ dm_request_endio_fn rq_end_io; + dm_flush_fn flush; + dm_presuspend_fn presuspend; + dm_postsuspend_fn postsuspend; +@@ -113,6 +127,7 @@ struct target_type { + dm_message_fn message; + dm_ioctl_fn ioctl; + dm_merge_fn merge; ++ dm_busy_fn busy; + }; + + struct io_restrictions { +@@ -125,6 +140,7 @@ struct io_restrictions { + unsigned short max_hw_segments; + unsigned short max_phys_segments; + unsigned char no_cluster; /* inverted so that 0 is default */ ++ unsigned char no_request_stacking; + }; + + struct dm_target { +@@ -348,4 +364,12 @@ static inline unsigned long to_bytes(sec + return (n << SECTOR_SHIFT); + } + ++/*----------------------------------------------------------------- ++ * Helper for block layer and dm core operations ++ *---------------------------------------------------------------*/ ++void dm_dispatch_request(struct request *rq); ++void dm_requeue_request(struct request *rq); ++void dm_kill_request(struct request *rq, int error); ++int dm_underlying_device_busy(struct request_queue *q); ++ + #endif /* _LINUX_DEVICE_MAPPER_H */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/rwlocks-enable-interrupts b/src/patches/suse-2.6.27.31/patches.suse/rwlocks-enable-interrupts new file mode 100644 index 000000000..1f47cabaa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/rwlocks-enable-interrupts @@ -0,0 +1,237 @@ +From: Petr Tesarik +Subject: Allow rwlocks to re-enable interrupts +References: bnc#387784 +Mainline: no + +Pass the original flags to rwlock arch-code, so that it can re-enable +interrupts if desired. + +Signed-off-by: Petr Tesarik + +--- + arch/alpha/include/asm/spinlock.h | 3 +++ + arch/arm/include/asm/spinlock.h | 3 +++ + arch/ia64/include/asm/spinlock.h | 3 +++ + arch/powerpc/include/asm/spinlock.h | 3 +++ + arch/s390/include/asm/spinlock.h | 3 +++ + arch/sh/include/asm/spinlock.h | 3 +++ + arch/sparc/include/asm/spinlock_32.h | 2 ++ + arch/sparc/include/asm/spinlock_64.h | 2 ++ + include/asm-cris/arch-v32/spinlock.h | 2 ++ + include/asm-m32r/spinlock.h | 3 +++ + include/asm-mips/spinlock.h | 2 ++ + include/asm-parisc/spinlock.h | 3 +++ + include/asm-x86/spinlock.h | 3 +++ + include/linux/spinlock.h | 6 ++++++ + kernel/spinlock.c | 8 ++++++++ + 15 files changed, 49 insertions(+) + +--- linux-2.6.26.orig/arch/alpha/include/asm/spinlock.h 2008-09-26 12:13:24.000000000 +0200 ++++ linux-2.6.26/arch/alpha/include/asm/spinlock.h 2008-09-26 13:01:43.000000000 +0200 +@@ -166,6 +166,9 @@ static inline void __raw_write_unlock(ra + lock->lock = 0; + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/arch/arm/include/asm/spinlock.h 2008-09-26 10:21:46.000000000 +0200 ++++ linux-2.6.26/arch/arm/include/asm/spinlock.h 2008-09-26 13:01:25.000000000 +0200 +@@ -217,6 +217,9 @@ static inline int __raw_read_trylock(raw + /* read_can_lock - would read_trylock() succeed? */ + #define __raw_read_can_lock(x) ((x)->lock < 0x80000000) + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/arch/ia64/include/asm/spinlock.h 2008-09-26 10:21:47.000000000 +0200 ++++ linux-2.6.26/arch/ia64/include/asm/spinlock.h 2008-09-26 13:02:50.000000000 +0200 +@@ -213,6 +213,9 @@ static inline int __raw_read_trylock(raw + return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word; + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/arch/powerpc/include/asm/spinlock.h 2008-09-26 10:21:48.000000000 +0200 ++++ linux-2.6.26/arch/powerpc/include/asm/spinlock.h 2008-09-26 13:00:32.000000000 +0200 +@@ -287,6 +287,9 @@ static inline void __raw_write_unlock(ra + rw->lock = 0; + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) __spin_yield(lock) + #define _raw_read_relax(lock) __rw_yield(lock) + #define _raw_write_relax(lock) __rw_yield(lock) +--- linux-2.6.26.orig/arch/s390/include/asm/spinlock.h 2008-09-26 10:21:49.000000000 +0200 ++++ linux-2.6.26/arch/s390/include/asm/spinlock.h 2008-09-26 13:00:02.000000000 +0200 +@@ -172,6 +172,9 @@ static inline int __raw_write_trylock(ra + return _raw_write_trylock_retry(rw); + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() + +--- linux-2.6.26.orig/arch/sh/include/asm/spinlock.h 2008-09-26 10:21:49.000000000 +0200 ++++ linux-2.6.26/arch/sh/include/asm/spinlock.h 2008-09-26 12:59:32.000000000 +0200 +@@ -216,6 +216,9 @@ static inline int __raw_write_trylock(ra + return (oldval > (RW_LOCK_BIAS - 1)); + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/arch/sparc/include/asm/spinlock_32.h 2008-09-26 10:21:49.000000000 +0200 ++++ linux-2.6.26/arch/sparc/include/asm/spinlock_32.h 2008-09-26 12:51:28.000000000 +0200 +@@ -179,6 +179,8 @@ static inline int __read_trylock(raw_rwl + #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0) + + #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) ++#define __raw_read_lock_flags(rw, flags) __raw_read_lock(rw) ++#define __raw_write_lock_flags(rw, flags) __raw_write_lock(rw) + + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() +--- linux-2.6.26.orig/arch/sparc/include/asm/spinlock_64.h 2008-09-26 10:21:49.000000000 +0200 ++++ linux-2.6.26/arch/sparc/include/asm/spinlock_64.h 2008-09-26 12:52:31.000000000 +0200 +@@ -232,9 +232,11 @@ static int inline __write_trylock(raw_rw + } + + #define __raw_read_lock(p) __read_lock(p) ++#define __raw_read_lock_flags(p, f) __read_lock(p) + #define __raw_read_trylock(p) __read_trylock(p) + #define __raw_read_unlock(p) __read_unlock(p) + #define __raw_write_lock(p) __write_lock(p) ++#define __raw_write_lock_flags(p, f) __write_lock(p) + #define __raw_write_unlock(p) __write_unlock(p) + #define __raw_write_trylock(p) __write_trylock(p) + +--- linux-2.6.26.orig/include/asm-cris/arch-v32/spinlock.h 2008-07-13 23:51:29.000000000 +0200 ++++ linux-2.6.26/include/asm-cris/arch-v32/spinlock.h 2008-09-26 12:54:11.000000000 +0200 +@@ -121,6 +121,8 @@ static inline int __raw_write_trylock(r + return 1; + } + ++#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock) ++#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock) + + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() +--- linux-2.6.26.orig/include/asm-m32r/spinlock.h 2008-07-13 23:51:29.000000000 +0200 ++++ linux-2.6.26/include/asm-m32r/spinlock.h 2008-09-26 12:55:46.000000000 +0200 +@@ -316,6 +316,9 @@ static inline int __raw_write_trylock(ra + return 0; + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/include/asm-mips/spinlock.h 2008-07-13 23:51:29.000000000 +0200 ++++ linux-2.6.26/include/asm-mips/spinlock.h 2008-09-26 12:56:28.000000000 +0200 +@@ -368,6 +368,8 @@ static inline int __raw_write_trylock(ra + return ret; + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) + + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() +--- linux-2.6.26.orig/include/asm-parisc/spinlock.h 2008-07-13 23:51:29.000000000 +0200 ++++ linux-2.6.26/include/asm-parisc/spinlock.h 2008-09-26 12:57:22.000000000 +0200 +@@ -187,6 +187,9 @@ static __inline__ int __raw_write_can_lo + return !rw->counter; + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/include/asm-x86/spinlock.h 2008-09-26 10:22:12.000000000 +0200 ++++ linux-2.6.26/include/asm-x86/spinlock.h 2008-09-26 12:58:07.000000000 +0200 +@@ -362,6 +362,9 @@ static inline void __raw_write_unlock(ra + : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory"); + } + ++#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) ++#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) ++ + #define _raw_spin_relax(lock) cpu_relax() + #define _raw_read_relax(lock) cpu_relax() + #define _raw_write_relax(lock) cpu_relax() +--- linux-2.6.26.orig/include/linux/spinlock.h 2008-09-26 10:22:12.000000000 +0200 ++++ linux-2.6.26/include/linux/spinlock.h 2008-09-26 13:04:17.000000000 +0200 +@@ -148,9 +148,11 @@ do { \ + extern int _raw_spin_trylock(spinlock_t *lock); + extern void _raw_spin_unlock(spinlock_t *lock); + extern void _raw_read_lock(rwlock_t *lock); ++#define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock) + extern int _raw_read_trylock(rwlock_t *lock); + extern void _raw_read_unlock(rwlock_t *lock); + extern void _raw_write_lock(rwlock_t *lock); ++#define _raw_write_lock_flags(lock, flags) _raw_write_lock(lock) + extern int _raw_write_trylock(rwlock_t *lock); + extern void _raw_write_unlock(rwlock_t *lock); + #else +@@ -160,9 +162,13 @@ do { \ + # define _raw_spin_trylock(lock) __raw_spin_trylock(&(lock)->raw_lock) + # define _raw_spin_unlock(lock) __raw_spin_unlock(&(lock)->raw_lock) + # define _raw_read_lock(rwlock) __raw_read_lock(&(rwlock)->raw_lock) ++# define _raw_read_lock_flags(lock, flags) \ ++ __raw_read_lock_flags(&(lock)->raw_lock, *(flags)) + # define _raw_read_trylock(rwlock) __raw_read_trylock(&(rwlock)->raw_lock) + # define _raw_read_unlock(rwlock) __raw_read_unlock(&(rwlock)->raw_lock) + # define _raw_write_lock(rwlock) __raw_write_lock(&(rwlock)->raw_lock) ++# define _raw_write_lock_flags(lock, flags) \ ++ __raw_write_lock_flags(&(lock)->raw_lock, *(flags)) + # define _raw_write_trylock(rwlock) __raw_write_trylock(&(rwlock)->raw_lock) + # define _raw_write_unlock(rwlock) __raw_write_unlock(&(rwlock)->raw_lock) + #endif +--- linux-2.6.26.orig/kernel/spinlock.c 2008-09-26 10:22:13.000000000 +0200 ++++ linux-2.6.26/kernel/spinlock.c 2008-09-26 13:10:35.000000000 +0200 +@@ -121,7 +121,11 @@ unsigned long __lockfunc _read_lock_irqs + local_irq_save(flags); + preempt_disable(); + rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); ++#ifdef CONFIG_LOCKDEP + LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock); ++#else ++ _raw_read_lock_flags(lock, &flags); ++#endif + return flags; + } + EXPORT_SYMBOL(_read_lock_irqsave); +@@ -151,7 +155,11 @@ unsigned long __lockfunc _write_lock_irq + local_irq_save(flags); + preempt_disable(); + rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); ++#ifdef CONFIG_LOCKDEP + LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock); ++#else ++ _raw_write_lock_flags(lock, &flags); ++#endif + return flags; + } + EXPORT_SYMBOL(_write_lock_irqsave); diff --git a/src/patches/suse-2.6.27.31/patches.suse/scsi-check-removed-device-for-offline b/src/patches/suse-2.6.27.31/patches.suse/scsi-check-removed-device-for-offline new file mode 100644 index 000000000..8bbd61c36 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/scsi-check-removed-device-for-offline @@ -0,0 +1,24 @@ +From: Hannes Reinecke +Subject: Check if device is removed in scsi_device_online() +References: bnc#456747 + +scsi_device_online() only checks if the device is not offline; +however, any device in SDEV_DEL or SDEV_CANCEL also should be +taken into account here. + +Signed-off-by: Hannes Reinecke + +diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h +index e96daf6..63b58d2 100644 +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -401,7 +401,8 @@ static inline unsigned int sdev_id(struct scsi_device *sdev) + */ + static inline int scsi_device_online(struct scsi_device *sdev) + { +- return sdev->sdev_state != SDEV_OFFLINE; ++ return (sdev->sdev_state != SDEV_OFFLINE && ++ sdev->sdev_state != SDEV_DEL); + } + static inline int scsi_device_blocked(struct scsi_device *sdev) + { diff --git a/src/patches/suse-2.6.27.31/patches.suse/scsi-error-test-unit-ready-timeout b/src/patches/suse-2.6.27.31/patches.suse/scsi-error-test-unit-ready-timeout new file mode 100644 index 000000000..009479654 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/scsi-error-test-unit-ready-timeout @@ -0,0 +1,34 @@ +From: garloff@suse.de +Subject: Introduce own timeout for TEST_UNIT_READY +Reference: SUSE41689 + +In error recovery, a SCSI device may need more than the 10s SENSE_TIMEOUT +to respond to TEST_UNIT_READY, as reported in novell bugzilla #56689. +The patch introduces an own timeout for TEST_UNIT_READY which is set +to 30s and used. + +Signed-off-by: Kurt Garloff + +--- + drivers/scsi/scsi_error.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -42,6 +42,7 @@ + #include "scsi_transport_api.h" + + #define SENSE_TIMEOUT (10*HZ) ++#define TEST_UNIT_READY_TIMEOUT (30*HZ) + + /* + * These should *probably* be handled by the host itself. +@@ -938,7 +939,7 @@ static int scsi_eh_tur(struct scsi_cmnd + int retry_cnt = 1, rtn; + + retry_tur: +- rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); ++ rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, TEST_UNIT_READY_TIMEOUT, 0); + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", + __func__, scmd, rtn)); diff --git a/src/patches/suse-2.6.27.31/patches.suse/scsi-netlink-ml b/src/patches/suse-2.6.27.31/patches.suse/scsi-netlink-ml new file mode 100644 index 000000000..2478b7235 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/scsi-netlink-ml @@ -0,0 +1,215 @@ +Subject: Netlink interface for SCSI sense codes +From: Hannes Reinecke +Date: Fri Nov 21 10:08:01 2008 +0100: +Git: 97746dc5543ef9113c927022dc54ccd26915563d + +Inform the userspace about SCSI sense codes; some of them +carry vital information where userspace should react to. + +Signed-off-by: Hannes Reinecke + +diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c +index 3863617..266e5a5 100644 +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -24,6 +24,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -33,6 +35,7 @@ + #include + #include + #include ++#include + + #include "scsi_priv.h" + #include "scsi_logging.h" +@@ -224,6 +227,80 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, + } + #endif + ++#ifdef CONFIG_SCSI_NETLINK ++/** ++ * scsi_post_sense_event - called to post a 'Sense Code' event ++ * ++ * @sdev: SCSI device the sense code occured on ++ * @sshdr: SCSI sense code ++ * ++ * Returns: ++ * 0 on succesful return ++ * otherwise, failing error code ++ * ++ */ ++static void scsi_post_sense_event(struct scsi_device *sdev, ++ struct scsi_sense_hdr *sshdr) ++{ ++ struct sk_buff *skb; ++ struct nlmsghdr *nlh; ++ struct scsi_nl_sense_msg *msg; ++ u32 len, skblen; ++ int err; ++ ++ if (!scsi_nl_sock) { ++ err = -ENOENT; ++ goto send_fail; ++ } ++ ++ len = SCSI_NL_MSGALIGN(sizeof(*msg)); ++ skblen = NLMSG_SPACE(len); ++ ++ skb = alloc_skb(skblen, GFP_ATOMIC); ++ if (!skb) { ++ err = -ENOBUFS; ++ goto send_fail; ++ } ++ ++ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, ++ skblen - sizeof(*nlh), 0); ++ if (!nlh) { ++ err = -ENOBUFS; ++ goto send_fail_skb; ++ } ++ msg = NLMSG_DATA(nlh); ++ ++ INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT_ML, ++ ML_NL_SCSI_SENSE, len); ++ msg->host_no = sdev->host->host_no; ++ msg->channel = sdev->channel; ++ msg->id = sdev->id; ++ msg->lun = sdev->lun; ++ msg->sense = (sshdr->response_code << 24) | (sshdr->sense_key << 16) | ++ (sshdr->asc << 8) | sshdr->ascq; ++ ++ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_ML_EVENTS, ++ GFP_ATOMIC); ++ if (err && (err != -ESRCH)) ++ /* nlmsg_multicast already kfree_skb'd */ ++ goto send_fail; ++ ++ return; ++ ++send_fail_skb: ++ kfree_skb(skb); ++send_fail: ++ sdev_printk(KERN_WARNING, sdev, ++ "Dropped SCSI Msg %02x/%02x/%02x/%02x: err %d\n", ++ sshdr->response_code, sshdr->sense_key, ++ sshdr->asc, sshdr->ascq, err); ++ return; ++} ++#else ++static inline void scsi_post_sense_event(struct scsi_device *sdev, ++ struct scsi_sense_hdr *sshdr) {} ++#endif ++ + /** + * scsi_check_sense - Examine scsi cmd sense + * @scmd: Cmd to have sense checked. +@@ -246,6 +323,8 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) + if (scsi_sense_is_deferred(&sshdr)) + return NEEDS_RETRY; + ++ scsi_post_sense_event(sdev, &sshdr); ++ + if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && + sdev->scsi_dh_data->scsi_dh->check_sense) { + int rc; +diff --git a/include/scsi/scsi_netlink.h b/include/scsi/scsi_netlink.h +index 536752c..ac7c766 100644 +--- a/include/scsi/scsi_netlink.h ++++ b/include/scsi/scsi_netlink.h +@@ -35,7 +35,8 @@ + /* SCSI Transport Broadcast Groups */ + /* leaving groups 0 and 1 unassigned */ + #define SCSI_NL_GRP_FC_EVENTS (1<<2) /* Group 2 */ +-#define SCSI_NL_GRP_CNT 3 ++#define SCSI_NL_GRP_ML_EVENTS (1<<3) /* Group 3 */ ++#define SCSI_NL_GRP_CNT 4 + + + /* SCSI_TRANSPORT_MSG event message header */ +@@ -56,7 +57,8 @@ struct scsi_nl_hdr { + /* scsi_nl_hdr->transport value */ + #define SCSI_NL_TRANSPORT 0 + #define SCSI_NL_TRANSPORT_FC 1 +-#define SCSI_NL_MAX_TRANSPORTS 2 ++#define SCSI_NL_TRANSPORT_ML 2 ++#define SCSI_NL_MAX_TRANSPORTS 3 + + /* Transport-based scsi_nl_hdr->msgtype values are defined in each transport */ + +diff --git a/include/scsi/scsi_netlink_ml.h b/include/scsi/scsi_netlink_ml.h +new file mode 100644 +index 0000000..c988458 +--- /dev/null ++++ b/include/scsi/scsi_netlink_ml.h +@@ -0,0 +1,64 @@ ++/* ++ * SCSI Midlayer Netlink Interface ++ * ++ * Copyright (C) 2008 Hannes Reinecke, SuSE Linux Products 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++#ifndef SCSI_NETLINK_ML_H ++#define SCSI_NETLINK_ML_H ++ ++#include ++ ++/* ++ * This file intended to be included by both kernel and user space ++ */ ++ ++/* ++ * FC Transport Message Types ++ */ ++ /* kernel -> user */ ++#define ML_NL_SCSI_SENSE 0x0100 ++ /* user -> kernel */ ++/* none */ ++ ++ ++/* ++ * Message Structures : ++ */ ++ ++/* macro to round up message lengths to 8byte boundary */ ++#define SCSI_NL_MSGALIGN(len) (((len) + 7) & ~7) ++ ++ ++/* ++ * SCSI Midlayer SCSI Sense messages : ++ * SCSI_NL_SCSI_SENSE ++ * ++ */ ++struct scsi_nl_sense_msg { ++ struct scsi_nl_hdr snlh; /* must be 1st element ! */ ++ uint64_t seconds; ++ u64 id; ++ u64 lun; ++ u16 host_no; ++ u16 channel; ++ u32 sense; ++} __attribute__((aligned(sizeof(uint64_t)))); ++ ++ ++#endif /* SCSI_NETLINK_ML_H */ ++ diff --git a/src/patches/suse-2.6.27.31/patches.suse/self-ptrace.patch b/src/patches/suse-2.6.27.31/patches.suse/self-ptrace.patch new file mode 100644 index 000000000..78ef7c8d8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/self-ptrace.patch @@ -0,0 +1,142 @@ +From: Gerald Schaefer +Subject: [PATCH] system call notification with self_ptrace +References: bnc#417299 + +PTRACE SELF + +This patch adds a new functionality to ptrace: system call notification to +the current process. +When a process requests self ptrace, with the new request PTRACE_SELF_ON: + + 1. the next system call performed by the process will not be executed + 2. self ptrace will be disabled for the process + 3. a SIGSYS signal will be sent to the process. + +With an appropriate SIGSYS signal handler, the process can access its own +data structures to + + 1. get the system call number from the siginfo structure + 2. get the system call arguments from the stack + 3. instrument the system call with other system calls + 4. emulate the system call with other system calls + 5. change the arguments of the system call + 6. perform the system call for good + 7. change the return value of the system call + 8. request self ptrace again before returning. + +The new request PTRACE_SELF_OFF disables self ptrace. + + +Signed-off-by: Pierre Morel +Signed-off-by: Volker Sameske + +Acked-by: John Jolly +--- + + include/asm-generic/siginfo.h | 6 ++++++ + include/linux/ptrace.h | 18 ++++++++++++++++++ + include/linux/sched.h | 1 + + kernel/ptrace.c | 32 ++++++++++++++++++++++++++++++++ + 4 files changed, 57 insertions(+) + +--- a/include/asm-generic/siginfo.h ++++ b/include/asm-generic/siginfo.h +@@ -224,6 +224,12 @@ typedef struct siginfo { + #define NSIGPOLL 6 + + /* ++ * SIGSYS si_codes ++ */ ++#define SYS_SYSCALL (__SI_FAULT|1) /* system call notification */ ++#define NSIGSYS 1 ++ ++/* + * sigevent definitions + * + * It seems likely that SIGEV_THREAD will have to be handled from +--- a/include/linux/ptrace.h ++++ b/include/linux/ptrace.h +@@ -27,6 +27,10 @@ + #define PTRACE_GETSIGINFO 0x4202 + #define PTRACE_SETSIGINFO 0x4203 + ++/* PTRACE SELF requests */ ++#define PTRACE_SELF_ON 0x4281 ++#define PTRACE_SELF_OFF 0x4282 ++ + /* options set using PTRACE_SETOPTIONS */ + #define PTRACE_O_TRACESYSGOOD 0x00000001 + #define PTRACE_O_TRACEFORK 0x00000002 +@@ -78,7 +82,21 @@ + + #include /* For unlikely. */ + #include /* For struct task_struct. */ ++#include /* For syscall definitions */ ++ ++#define PTS_INSTRUMENTED 0x00000001 ++#define PTS_SELF 0x00000002 + ++static inline int is_self_ptracing(unsigned long syscall) ++{ ++ if (!(current->instrumentation & PTS_SELF)) ++ return 0; ++ if (syscall == __NR_rt_sigreturn) ++ return 0; ++ if (syscall == __NR_ptrace) ++ return 0; ++ return 1; ++} + + extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); + extern struct task_struct *ptrace_get_task_struct(pid_t pid); +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1308,6 +1308,7 @@ struct task_struct { + int latency_record_count; + struct latency_record latency_record[LT_SAVECOUNT]; + #endif ++ u64 instrumentation; + }; + + /* +--- a/kernel/ptrace.c ++++ b/kernel/ptrace.c +@@ -554,6 +554,38 @@ SYSCALL_DEFINE4(ptrace, long, request, l + * This lock_kernel fixes a subtle race with suid exec + */ + lock_kernel(); ++ if (request == PTRACE_SELF_ON) { ++ task_lock(current); ++ if (current->ptrace) { ++ task_unlock(current); ++ ret = -EPERM; ++ goto out; ++ } ++ set_thread_flag(TIF_SYSCALL_TRACE); ++ current->instrumentation |= PTS_INSTRUMENTED|PTS_SELF; ++ task_unlock(current); ++ ret = 0; ++ goto out; ++ } ++ if (request == PTRACE_SELF_OFF) { ++ task_lock(current); ++ if (current->ptrace) { ++ task_unlock(current); ++ ret = -EPERM; ++ goto out; ++ } ++ clear_thread_flag(TIF_SYSCALL_TRACE); ++ current->instrumentation &= ~PTS_SELF; ++ task_unlock(current); ++ ret = 0; ++ goto out; ++ } ++ ++ if (current->instrumentation) { ++ ret = -EPERM; ++ goto out; ++ } ++ + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); + if (!ret) diff --git a/src/patches/suse-2.6.27.31/patches.suse/setuid-dumpable-wrongdir b/src/patches/suse-2.6.27.31/patches.suse/setuid-dumpable-wrongdir new file mode 100644 index 000000000..3816380f5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/setuid-dumpable-wrongdir @@ -0,0 +1,49 @@ +From: Kurt Garloff +Subject: suid-dumpable ended up in wrong sysctl dir +Patch-mainline: never + +Diffing in sysctl.c is tricky, using more context is recommended. +suid_dumpable ended up in fs/ instead of kernel/ and the reason +is likely a patch with too little context. + +NOTE: This has been in the wrong dir fs/ since it was introduced by +Alan Cox into mainline on 2005-06-23. However, SUSE shipped it +in the correct directory kernel/ in SLES9. + +By now, it's just something that we are going to have to drag along for +a long time until SLES 11/12/13 time frame... + +Signed-off-by: Kurt Garloff + +--- + kernel/sysctl.c | 8 ++++++++ + kernel/sysctl_check.c | 1 + + 2 files changed, 9 insertions(+) + +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -723,6 +723,14 @@ static struct ctl_table kern_table[] = { + .proc_handler = &proc_dointvec, + }, + #endif ++ { ++ .ctl_name = KERN_SETUID_DUMPABLE, ++ .procname = "suid_dumpable", ++ .data = &suid_dumpable, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, + #if defined(CONFIG_S390) && defined(CONFIG_SMP) + { + .ctl_name = KERN_SPIN_RETRY, +--- a/kernel/sysctl_check.c ++++ b/kernel/sysctl_check.c +@@ -104,6 +104,7 @@ static const struct trans_ctl_table tran + { KERN_MAX_LOCK_DEPTH, "max_lock_depth" }, + { KERN_NMI_WATCHDOG, "nmi_watchdog" }, + { KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" }, ++ { KERN_SETUID_DUMPABLE, "suid_dumpable" }, + {} + }; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/shmall-bigger b/src/patches/suse-2.6.27.31/patches.suse/shmall-bigger new file mode 100644 index 000000000..32c56c184 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/shmall-bigger @@ -0,0 +1,49 @@ +From: Chris Mason +Subject: increase defaults for shmmall, shmmax, msgmax and msgmnb +References: 146656 + +The defaults are too small for most users. + +Acked-by: Jeff Mahoney + +--- + include/linux/msg.h | 4 ++-- + include/linux/sem.h | 2 +- + include/linux/shm.h | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +--- a/include/linux/msg.h ++++ b/include/linux/msg.h +@@ -60,8 +60,8 @@ struct msginfo { + #define MSG_MEM_SCALE 32 + + #define MSGMNI 16 /* <= IPCMNI */ /* max # of msg queue identifiers */ +-#define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */ +-#define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */ ++#define MSGMAX 65536 /* <= INT_MAX */ /* max size of message (bytes) */ ++#define MSGMNB 65536 /* <= INT_MAX */ /* default max size of a message queue */ + + /* unused */ + #define MSGPOOL (MSGMNI * MSGMNB / 1024) /* size in kbytes of message pool */ +--- a/include/linux/sem.h ++++ b/include/linux/sem.h +@@ -63,7 +63,7 @@ struct seminfo { + int semaem; + }; + +-#define SEMMNI 128 /* <= IPCMNI max # of semaphore identifiers */ ++#define SEMMNI 1024 /* <= IPCMNI max # of semaphore identifiers */ + #define SEMMSL 250 /* <= 8 000 max num of semaphores per id */ + #define SEMMNS (SEMMNI*SEMMSL) /* <= INT_MAX max # of semaphores in system */ + #define SEMOPM 32 /* <= 1 000 max num of ops per semop call */ +--- a/include/linux/shm.h ++++ b/include/linux/shm.h +@@ -14,7 +14,7 @@ + * be increased by sysctl + */ + +-#define SHMMAX 0x2000000 /* max shared seg size (bytes) */ ++#define SHMMAX ULONG_MAX /* max shared seg size (bytes) */ + #define SHMMIN 1 /* min shared seg size (bytes) */ + #define SHMMNI 4096 /* max num of segs system wide */ + #ifdef __KERNEL__ diff --git a/src/patches/suse-2.6.27.31/patches.suse/silent-stack-overflow b/src/patches/suse-2.6.27.31/patches.suse/silent-stack-overflow new file mode 100644 index 000000000..fec803016 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/silent-stack-overflow @@ -0,0 +1,466 @@ +From: Andrea Arcangeli +Subject: avoid silent stack overflow over the heap +Patch-mainline: no +References: bnc#44807 bnc#211997 + +x + +Signed-off-by: Andrea Arcangeli +Updated-by: Jeff Mahoney +--- + + arch/alpha/mm/fault.c | 2 - + arch/arm/mm/fault.c | 2 - + arch/cris/mm/fault.c | 2 - + arch/frv/mm/fault.c | 2 - + arch/ia64/mm/fault.c | 2 - + arch/m32r/mm/fault.c | 2 - + arch/m68k/mm/fault.c | 2 - + arch/mips/mm/fault.c | 2 - + arch/parisc/mm/fault.c | 2 - + arch/powerpc/mm/fault.c | 5 ++- + arch/powerpc/platforms/cell/spu_fault.c | 2 - + arch/s390/mm/fault.c | 2 - + arch/sh/mm/fault_32.c | 2 - + arch/sh/mm/tlbflush_64.c | 2 - + arch/sparc/mm/fault.c | 4 +-- + arch/sparc64/mm/fault.c | 2 - + arch/um/kernel/trap.c | 9 ++++-- + arch/x86/kernel/sys_x86_64.c | 10 ++++++- + arch/x86/mm/fault.c | 10 ++++++- + arch/xtensa/mm/fault.c | 2 - + include/linux/mm.h | 5 +++ + kernel/sysctl.c | 8 ++++++ + mm/mmap.c | 42 +++++++++++++++++++++++++------- + 23 files changed, 88 insertions(+), 35 deletions(-) + +--- a/arch/alpha/mm/fault.c ++++ b/arch/alpha/mm/fault.c +@@ -123,7 +123,7 @@ do_page_fault(unsigned long address, uns + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + + /* Ok, we have a good vm_area for this memory access, so +--- a/arch/arm/mm/fault.c ++++ b/arch/arm/mm/fault.c +@@ -233,7 +233,7 @@ out_of_memory: + goto survive; + + check_stack: +- if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) ++ if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr, NULL)) + goto good_area; + out: + return fault; +--- a/arch/cris/mm/fault.c ++++ b/arch/cris/mm/fault.c +@@ -133,7 +133,7 @@ do_page_fault(unsigned long address, str + if (address + PAGE_SIZE < rdusp()) + goto bad_area; + } +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + + /* +--- a/arch/frv/mm/fault.c ++++ b/arch/frv/mm/fault.c +@@ -121,7 +121,7 @@ asmlinkage void do_page_fault(int datamm + } + } + +- if (expand_stack(vma, ear0)) ++ if (expand_stack(vma, ear0, NULL)) + goto bad_area; + + /* +--- a/arch/ia64/mm/fault.c ++++ b/arch/ia64/mm/fault.c +@@ -185,7 +185,7 @@ ia64_do_page_fault (unsigned long addres + if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start) + || REGION_OFFSET(address) >= RGN_MAP_LIMIT) + goto bad_area; +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL /* FIXME? */)) + goto bad_area; + } else { + vma = prev_vma; +--- a/arch/m32r/mm/fault.c ++++ b/arch/m32r/mm/fault.c +@@ -159,7 +159,7 @@ asmlinkage void do_page_fault(struct pt_ + goto bad_area; + } + +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +--- a/arch/m68k/mm/fault.c ++++ b/arch/m68k/mm/fault.c +@@ -121,7 +121,7 @@ int do_page_fault(struct pt_regs *regs, + if (address + 256 < rdusp()) + goto map_err; + } +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto map_err; + + /* +--- a/arch/mips/mm/fault.c ++++ b/arch/mips/mm/fault.c +@@ -80,7 +80,7 @@ asmlinkage void do_page_fault(struct pt_ + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +--- a/arch/parisc/mm/fault.c ++++ b/arch/parisc/mm/fault.c +@@ -196,7 +196,7 @@ good_area: + + check_expansion: + vma = prev_vma; +- if (vma && (expand_stack(vma, address) == 0)) ++ if (vma && (expand_stack(vma, address, NULL) == 0)) + goto good_area; + + /* +--- a/arch/powerpc/mm/fault.c ++++ b/arch/powerpc/mm/fault.c +@@ -116,7 +116,7 @@ static int store_updates_sp(struct pt_re + int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) + { +- struct vm_area_struct * vma; ++ struct vm_area_struct * vma, * prev_vma; + struct mm_struct *mm = current->mm; + siginfo_t info; + int code = SEGV_MAPERR; +@@ -230,7 +230,8 @@ int __kprobes do_page_fault(struct pt_re + && (!user_mode(regs) || !store_updates_sp(regs))) + goto bad_area; + } +- if (expand_stack(vma, address)) ++ find_vma_prev(mm, address, &prev_vma); ++ if (expand_stack(vma, address, prev_vma)) + goto bad_area; + + good_area: +--- a/arch/powerpc/platforms/cell/spu_fault.c ++++ b/arch/powerpc/platforms/cell/spu_fault.c +@@ -59,7 +59,7 @@ int spu_handle_mm_fault(struct mm_struct + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if (expand_stack(vma, ea)) ++ if (expand_stack(vma, ea, NULL)) + goto bad_area; + good_area: + is_write = dsisr & MFC_DSISR_ACCESS_PUT; +--- a/arch/s390/mm/fault.c ++++ b/arch/s390/mm/fault.c +@@ -350,7 +350,7 @@ do_exception(struct pt_regs *regs, unsig + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL /* FIXME? */)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +--- a/arch/sh/mm/fault_32.c ++++ b/arch/sh/mm/fault_32.c +@@ -108,7 +108,7 @@ asmlinkage void __kprobes do_page_fault( + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +--- a/arch/sh/mm/tlbflush_64.c ++++ b/arch/sh/mm/tlbflush_64.c +@@ -153,7 +153,7 @@ asmlinkage void do_page_fault(struct pt_ + #endif + goto bad_area; + } +- if (expand_stack(vma, address)) { ++ if (expand_stack(vma, address, NULL)) { + #ifdef DEBUG_FAULT + print_task(tsk); + printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", +--- a/arch/sparc/mm/fault.c ++++ b/arch/sparc/mm/fault.c +@@ -219,7 +219,7 @@ asmlinkage void do_sparc_fault(struct pt + goto good_area; + if(!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if(expand_stack(vma, address)) ++ if(expand_stack(vma, address, NULL)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +@@ -472,7 +472,7 @@ static void force_user_fault(unsigned lo + goto good_area; + if(!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if(expand_stack(vma, address)) ++ if(expand_stack(vma, address, NULL)) + goto bad_area; + good_area: + info.si_code = SEGV_ACCERR; +--- a/arch/sparc64/mm/fault.c ++++ b/arch/sparc64/mm/fault.c +@@ -367,7 +367,7 @@ continue_fault: + goto bad_area; + } + } +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +--- a/arch/um/kernel/trap.c ++++ b/arch/um/kernel/trap.c +@@ -24,7 +24,7 @@ int handle_page_fault(unsigned long addr + int is_write, int is_user, int *code_out) + { + struct mm_struct *mm = current->mm; +- struct vm_area_struct *vma; ++ struct vm_area_struct *vma, *prev_vma; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; +@@ -50,8 +50,11 @@ int handle_page_fault(unsigned long addr + goto out; + else if (is_user && !ARCH_IS_STACKGROW(address)) + goto out; +- else if (expand_stack(vma, address)) +- goto out; ++ else { ++ find_vma_prev(mm, address, &prev_vma); ++ if(expand_stack(vma, address, prev_vma)) ++ goto out; ++ } + + good_area: + *code_out = SEGV_ACCERR; +--- a/arch/x86/kernel/sys_x86_64.c ++++ b/arch/x86/kernel/sys_x86_64.c +@@ -106,6 +106,7 @@ arch_get_unmapped_area(struct file *filp + + full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { ++ unsigned long __heap_stack_gap; + /* At this point: (!vma || addr < vma->vm_end). */ + if (end - len < addr) { + /* +@@ -119,7 +120,14 @@ full_search: + } + return -ENOMEM; + } +- if (!vma || addr + len <= vma->vm_start) { ++ if (!vma) ++ goto got_it; ++ __heap_stack_gap = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ __heap_stack_gap = min(end-(addr+len), ++ (unsigned long) heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + __heap_stack_gap <= vma->vm_start) { ++ got_it: + /* + * Remember the place where we stopped the search: + */ +--- a/arch/x86/mm/fault.c ++++ b/arch/x86/mm/fault.c +@@ -585,7 +585,7 @@ void __kprobes do_page_fault(struct pt_r + { + struct task_struct *tsk; + struct mm_struct *mm; +- struct vm_area_struct *vma; ++ struct vm_area_struct *vma, *prev_vma; + unsigned long address; + int write, si_code; + int fault; +@@ -719,7 +719,13 @@ again: + if (address + 65536 + 32 * sizeof(unsigned long) < regs->sp) + goto bad_area; + } +- if (expand_stack(vma, address)) ++ /* ++ * find_vma_prev is just a bit slower, because it cannot ++ * use the mmap_cache, so we run it only in the growsdown ++ * slow path and we leave find_vma in the fast path. ++ */ ++ find_vma_prev(current->mm, address, &prev_vma); ++ if (expand_stack(vma, address, prev_vma)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so +--- a/arch/xtensa/mm/fault.c ++++ b/arch/xtensa/mm/fault.c +@@ -80,7 +80,7 @@ void do_page_fault(struct pt_regs *regs) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; +- if (expand_stack(vma, address)) ++ if (expand_stack(vma, address, NULL)) + goto bad_area; + + /* Ok, we have a good vm_area for this memory access, so +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1208,7 +1208,10 @@ void page_cache_async_readahead(struct a + unsigned long max_sane_readahead(unsigned long nr); + + /* Do stack extension */ +-extern int expand_stack(struct vm_area_struct *vma, unsigned long address); ++#define EXPAND_STACK_HAS_3_ARGS ++extern int heap_stack_gap; ++extern int expand_stack(struct vm_area_struct * vma, unsigned long address, ++ struct vm_area_struct * prev_vma); + #ifdef CONFIG_IA64 + extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); + #endif +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -1208,6 +1208,14 @@ static struct ctl_table vm_table[] = { + .extra2 = &one, + }, + #endif ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "heap-stack-gap", ++ .data = &heap_stack_gap, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, + /* + * NOTE: do not add new entries to this table unless you have read + * Documentation/sysctl/ctl_unnumbered.txt +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -85,6 +85,7 @@ int sysctl_overcommit_memory = OVERCOMMI + int sysctl_overcommit_ratio = 50; /* default is 50% */ + int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; + atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0); ++int heap_stack_gap = 1; + + /* + * Check that a process has enough memory to allocate a new virtual +@@ -1291,6 +1292,7 @@ arch_get_unmapped_area(struct file *filp + full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ ++ unsigned long __heap_stack_gap; + if (TASK_SIZE - len < addr) { + /* + * Start a new search - just in case we missed +@@ -1304,7 +1306,14 @@ full_search: + } + return -ENOMEM; + } +- if (!vma || addr + len <= vma->vm_start) { ++ if (!vma) ++ goto got_it; ++ __heap_stack_gap = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ __heap_stack_gap = min(TASK_SIZE-(addr+len), ++ (unsigned long) heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + __heap_stack_gap <= vma->vm_start) { ++ got_it: + /* + * Remember the place where we stopped the search: + */ +@@ -1633,11 +1642,9 @@ int expand_upwards(struct vm_area_struct + } + #endif /* CONFIG_STACK_GROWSUP || CONFIG_IA64 */ + +-/* +- * vma is the first one with address < vma->vm_start. Have to extend vma. +- */ + static inline int expand_downwards(struct vm_area_struct *vma, +- unsigned long address) ++ unsigned long address, ++ struct vm_area_struct *prev_vma) + { + int error; + +@@ -1665,6 +1672,13 @@ static inline int expand_downwards(struc + if (address < vma->vm_start) { + unsigned long size, grow; + ++ error = -ENOMEM; ++ if (prev_vma) { ++ unsigned long __heap_stack_gap = min(TASK_SIZE-prev_vma->vm_end, ++ (unsigned long) heap_stack_gap << PAGE_SHIFT); ++ if (unlikely(prev_vma->vm_end + __heap_stack_gap > address)) ++ goto out_unlock; ++ } + size = vma->vm_end - address; + grow = (vma->vm_start - address) >> PAGE_SHIFT; + +@@ -1674,6 +1688,7 @@ static inline int expand_downwards(struc + vma->vm_pgoff -= grow; + } + } ++ out_unlock: + anon_vma_unlock(vma); + return error; + } +@@ -1684,8 +1699,16 @@ int expand_stack_downwards(struct vm_are + } + + #ifdef CONFIG_STACK_GROWSUP +-int expand_stack(struct vm_area_struct *vma, unsigned long address) ++int expand_stack(struct vm_area_struct * vma, unsigned long address, ++ struct vm_area_struct * prev_vma) + { ++ /* ++ * If you re-use the heap-stack-gap for a growsup stack you ++ * should implement the feature for growsup too and remove ++ * this WARN_ON. ++ */ ++ WARN_ON(prev_vma); ++ + return expand_upwards(vma, address); + } + +@@ -1698,7 +1721,7 @@ find_extend_vma(struct mm_struct *mm, un + vma = find_vma_prev(mm, addr, &prev); + if (vma && (vma->vm_start <= addr)) + return vma; +- if (!prev || expand_stack(prev, addr)) ++ if (!prev || expand_stack(prev, addr, NULL)) + return NULL; + if (prev->vm_flags & VM_LOCKED) + make_pages_present(addr, prev->vm_end); +@@ -1713,7 +1736,7 @@ int expand_stack(struct vm_area_struct * + struct vm_area_struct * + find_extend_vma(struct mm_struct * mm, unsigned long addr) + { +- struct vm_area_struct * vma; ++ struct vm_area_struct * vma, * prev_vma; + unsigned long start; + + addr &= PAGE_MASK; +@@ -1725,7 +1748,8 @@ find_extend_vma(struct mm_struct * mm, u + if (!(vma->vm_flags & VM_GROWSDOWN)) + return NULL; + start = vma->vm_start; +- if (expand_stack(vma, addr)) ++ find_vma_prev(mm, addr, &prev_vma); ++ if (expand_stack(vma, addr, prev_vma)) + return NULL; + if (vma->vm_flags & VM_LOCKED) + make_pages_present(addr, start); diff --git a/src/patches/suse-2.6.27.31/patches.suse/silent-stack-overflow-2.patch b/src/patches/suse-2.6.27.31/patches.suse/silent-stack-overflow-2.patch new file mode 100644 index 000000000..768373755 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/silent-stack-overflow-2.patch @@ -0,0 +1,493 @@ +From: Nick Piggin +Subject: avoid silent stack overflow over the heap +Patch-mainline: no +References: bnc#44807 bnc#211997 + +This is a rewrite of Andrea Arcangeli's patch, which implements a stack +guard feature. That is, it prevents the stack from growing right next +to another vma, and prevents other vmas being allocated right next to the +stack. This will cause a segfault rather than the stack silently overwriting +other memory areas (eg. the heap) in the case that the app has a stack +overflow. + +I have rewritten it so as not to require changes to expand_stack prototype, +support for growsup stacks, and support for powerpc and ia64. + + +Signed-off-by: Nick Piggin +--- + arch/ia64/kernel/sys_ia64.c | 11 +++++ + arch/powerpc/mm/slice.c | 82 +++++++++++++++++++++++++----------------- + arch/x86/kernel/sys_x86_64.c | 52 ++++++++++++++++++++------ + include/linux/mm.h | 1 + kernel/sysctl.c | 8 ++++ + mm/mmap.c | 83 ++++++++++++++++++++++++++++++++++++------- + 6 files changed, 178 insertions(+), 59 deletions(-) + +--- a/arch/ia64/kernel/sys_ia64.c ++++ b/arch/ia64/kernel/sys_ia64.c +@@ -59,6 +59,8 @@ arch_get_unmapped_area (struct file *fil + start_addr = addr = (addr + align_mask) & ~align_mask; + + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { ++ unsigned long guard; ++ + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr || RGN_MAP_LIMIT - len < REGION_OFFSET(addr)) { + if (start_addr != TASK_UNMAPPED_BASE) { +@@ -68,7 +70,14 @@ arch_get_unmapped_area (struct file *fil + } + return -ENOMEM; + } +- if (!vma || addr + len <= vma->vm_start) { ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(TASK_SIZE - (addr + len), ++ (unsigned long)guard << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* Remember the address where we stopped this search: */ + mm->free_area_cache = addr + len; + return addr; +--- a/arch/powerpc/mm/slice.c ++++ b/arch/powerpc/mm/slice.c +@@ -94,11 +94,21 @@ static int slice_area_is_free(struct mm_ + unsigned long len) + { + struct vm_area_struct *vma; ++ unsigned long guard; + + if ((mm->task_size - len) < addr) + return 0; + vma = find_vma(mm, addr); +- return (!vma || (addr + len) <= vma->vm_start); ++ if (!vma) ++ return 1; ++ ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(mm->task_size - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) ++ return 1; ++ return 0; + } + + static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice) +@@ -242,8 +252,10 @@ static unsigned long slice_find_area_bot + + full_search: + for (;;) { ++ unsigned long guard; ++ + addr = _ALIGN_UP(addr, 1ul << pshift); +- if ((TASK_SIZE - len) < addr) ++ if ((mm->task_size - len) < addr) + break; + vma = find_vma(mm, addr); + BUG_ON(vma && (addr >= vma->vm_end)); +@@ -256,7 +268,14 @@ full_search: + addr = _ALIGN_UP(addr + 1, 1ul << SLICE_HIGH_SHIFT); + continue; + } +- if (!vma || addr + len <= vma->vm_start) { ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(mm->task_size - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* + * Remember the place where we stopped the search: + */ +@@ -264,8 +283,8 @@ full_search: + mm->free_area_cache = addr + len; + return addr; + } +- if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start) +- mm->cached_hole_size = vma->vm_start - addr; ++ if (use_cache && (addr + guard + mm->cached_hole_size) < vma->vm_start) ++ mm->cached_hole_size = vma->vm_start - (addr + guard); + addr = vma->vm_end; + } + +@@ -284,37 +303,23 @@ static unsigned long slice_find_area_top + int psize, int use_cache) + { + struct vm_area_struct *vma; +- unsigned long addr; ++ unsigned long start_addr, addr; + struct slice_mask mask; + int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT); + +- /* check if free_area_cache is useful for us */ + if (use_cache) { + if (len <= mm->cached_hole_size) { ++ start_addr = addr = mm->mmap_base; + mm->cached_hole_size = 0; +- mm->free_area_cache = mm->mmap_base; +- } +- +- /* either no address requested or can't fit in requested +- * address hole +- */ +- addr = mm->free_area_cache; +- +- /* make sure it can fit in the remaining address space */ +- if (addr > len) { +- addr = _ALIGN_DOWN(addr - len, 1ul << pshift); +- mask = slice_range_to_mask(addr, len); +- if (slice_check_fit(mask, available) && +- slice_area_is_free(mm, addr, len)) +- /* remember the address as a hint for +- * next time +- */ +- return (mm->free_area_cache = addr); +- } +- } ++ } else ++ start_addr = addr = mm->free_area_cache; ++ } else ++ start_addr = addr = mm->mmap_base; + +- addr = mm->mmap_base; ++full_search: + while (addr > len) { ++ unsigned long guard; ++ + /* Go down by chunk size */ + addr = _ALIGN_DOWN(addr - len, 1ul << pshift); + +@@ -336,7 +341,15 @@ static unsigned long slice_find_area_top + * return with success: + */ + vma = find_vma(mm, addr); +- if (!vma || (addr + len) <= vma->vm_start) { ++ ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(mm->task_size - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* remember the address as a hint for next time */ + if (use_cache) + mm->free_area_cache = addr; +@@ -344,11 +357,16 @@ static unsigned long slice_find_area_top + } + + /* remember the largest hole we saw so far */ +- if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start) +- mm->cached_hole_size = vma->vm_start - addr; ++ if (use_cache && (addr + guard + mm->cached_hole_size) < vma->vm_start) ++ mm->cached_hole_size = vma->vm_start - (addr + guard); + + /* try just below the current vma->vm_start */ +- addr = vma->vm_start; ++ addr = vma->vm_start - guard; ++ } ++ if (start_addr != mm->mmap_base) { ++ start_addr = addr = mm->mmap_base; ++ mm->cached_hole_size = 0; ++ goto full_search; + } + + /* +--- a/arch/x86/kernel/sys_x86_64.c ++++ b/arch/x86/kernel/sys_x86_64.c +@@ -106,6 +106,8 @@ arch_get_unmapped_area(struct file *filp + + full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { ++ unsigned long guard; ++ + /* At this point: (!vma || addr < vma->vm_end). */ + if (end - len < addr) { + /* +@@ -119,15 +121,22 @@ full_search: + } + return -ENOMEM; + } +- if (!vma || addr + len <= vma->vm_start) { ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(end - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* + * Remember the place where we stopped the search: + */ + mm->free_area_cache = addr + len; + return addr; + } +- if (addr + mm->cached_hole_size < vma->vm_start) +- mm->cached_hole_size = vma->vm_start - addr; ++ if (addr + guard + mm->cached_hole_size < vma->vm_start) ++ mm->cached_hole_size = vma->vm_start - (addr + guard); + + addr = vma->vm_end; + } +@@ -174,34 +183,51 @@ arch_get_unmapped_area_topdown(struct fi + + /* make sure it can fit in the remaining address space */ + if (addr > len) { +- vma = find_vma(mm, addr-len); +- if (!vma || addr <= vma->vm_start) +- /* remember the address as a hint for next time */ +- return (mm->free_area_cache = addr-len); ++ unsigned long guard; ++ ++ addr -= len; ++ vma = find_vma(mm, addr); ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(TASK_SIZE - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) ++ goto got_it; + } + + if (mm->mmap_base < len) + goto bottomup; + + addr = mm->mmap_base-len; +- + do { ++ unsigned long guard; + /* + * Lookup failure means no vma is above this address, + * else if new region fits below vma->vm_start, + * return with success: + */ + vma = find_vma(mm, addr); +- if (!vma || addr+len <= vma->vm_start) ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(TASK_SIZE - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* remember the address as a hint for next time */ +- return (mm->free_area_cache = addr); ++ mm->free_area_cache = addr; ++ return addr; ++ } + + /* remember the largest hole we saw so far */ +- if (addr + mm->cached_hole_size < vma->vm_start) +- mm->cached_hole_size = vma->vm_start - addr; ++ if (addr + guard + mm->cached_hole_size < vma->vm_start) ++ mm->cached_hole_size = vma->vm_start - (addr + guard); + + /* try just below the current vma->vm_start */ +- addr = vma->vm_start-len; ++ addr = vma->vm_start - (len + guard); + } while (len < vma->vm_start); + + bottomup: +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1194,6 +1194,7 @@ void page_cache_async_readahead(struct a + unsigned long max_sane_readahead(unsigned long nr); + + /* Do stack extension */ ++extern int heap_stack_gap; + extern int expand_stack(struct vm_area_struct *vma, unsigned long address); + #ifdef CONFIG_IA64 + extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -1207,6 +1207,14 @@ static struct ctl_table vm_table[] = { + .extra2 = &one, + }, + #endif ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "heap-stack-gap", ++ .data = &heap_stack_gap, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, + /* + * NOTE: do not add new entries to this table unless you have read + * Documentation/sysctl/ctl_unnumbered.txt +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -85,6 +85,7 @@ int sysctl_overcommit_memory = OVERCOMMI + int sysctl_overcommit_ratio = 50; /* default is 50% */ + int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; + atomic_long_t vm_committed_space = ATOMIC_LONG_INIT(0); ++int heap_stack_gap __read_mostly = 1; + + /* amount of vm to protect from userspace access */ + unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; +@@ -1293,6 +1294,8 @@ arch_get_unmapped_area(struct file *filp + + full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { ++ unsigned long guard; ++ + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) { + /* +@@ -1307,15 +1310,23 @@ full_search: + } + return -ENOMEM; + } +- if (!vma || addr + len <= vma->vm_start) { ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(TASK_SIZE - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* + * Remember the place where we stopped the search: + */ + mm->free_area_cache = addr + len; + return addr; + } +- if (addr + mm->cached_hole_size < vma->vm_start) +- mm->cached_hole_size = vma->vm_start - addr; ++ if (addr + guard + mm->cached_hole_size < vma->vm_start) ++ mm->cached_hole_size = vma->vm_start - (addr + guard); ++ + addr = vma->vm_end; + } + } +@@ -1373,34 +1384,51 @@ arch_get_unmapped_area_topdown(struct fi + + /* make sure it can fit in the remaining address space */ + if (addr > len) { +- vma = find_vma(mm, addr-len); +- if (!vma || addr <= vma->vm_start) +- /* remember the address as a hint for next time */ +- return (mm->free_area_cache = addr-len); ++ unsigned long guard; ++ ++ addr -= len; ++ vma = find_vma(mm, addr); ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(TASK_SIZE - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) ++ goto got_it; + } + + if (mm->mmap_base < len) + goto bottomup; + + addr = mm->mmap_base-len; +- + do { ++ unsigned long guard; + /* + * Lookup failure means no vma is above this address, + * else if new region fits below vma->vm_start, + * return with success: + */ + vma = find_vma(mm, addr); +- if (!vma || addr+len <= vma->vm_start) ++ if (!vma) ++ goto got_it; ++ guard = 0; ++ if (vma->vm_flags & VM_GROWSDOWN) ++ guard = min(TASK_SIZE - (addr + len), ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (addr + len + guard <= vma->vm_start) { ++got_it: + /* remember the address as a hint for next time */ +- return (mm->free_area_cache = addr); ++ mm->free_area_cache = addr; ++ return addr; ++ } + + /* remember the largest hole we saw so far */ +- if (addr + mm->cached_hole_size < vma->vm_start) +- mm->cached_hole_size = vma->vm_start - addr; ++ if (addr + guard + mm->cached_hole_size < vma->vm_start) ++ mm->cached_hole_size = vma->vm_start - (addr + guard); + + /* try just below the current vma->vm_start */ +- addr = vma->vm_start-len; ++ addr = vma->vm_start - (len + guard); + } while (len < vma->vm_start); + + bottomup: +@@ -1623,6 +1651,19 @@ int expand_upwards(struct vm_area_struct + /* Somebody else might have raced and expanded it already */ + if (address > vma->vm_end) { + unsigned long size, grow; ++#ifdef CONFIG_STACK_GROWSUP ++ unsigned long guard; ++ struct vm_area_struct *vm_next; ++ ++ error = -ENOMEM; ++ guard = min(TASK_SIZE - address, ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ vm_next = find_vma(vma->vm_mm, address + guard); ++ if (unlikely(vm_next && vm_next != vma)) { ++ /* stack collision with another vma */ ++ goto out_unlock; ++ } ++#endif + + size = address - vma->vm_start; + grow = (address - vma->vm_end) >> PAGE_SHIFT; +@@ -1631,6 +1672,7 @@ int expand_upwards(struct vm_area_struct + if (!error) + vma->vm_end = address; + } ++out_unlock: __maybe_unused + anon_vma_unlock(vma); + return error; + } +@@ -1667,7 +1709,21 @@ static inline int expand_downwards(struc + /* Somebody else might have raced and expanded it already */ + if (address < vma->vm_start) { + unsigned long size, grow; ++ struct vm_area_struct *prev_vma; ++ ++ find_vma_prev(vma->vm_mm, address, &prev_vma); + ++ error = -ENOMEM; ++ if (prev_vma) { ++ unsigned long guard; ++ ++ guard = min(TASK_SIZE - prev_vma->vm_end, ++ (unsigned long)heap_stack_gap << PAGE_SHIFT); ++ if (unlikely(prev_vma->vm_end + guard > address)) { ++ /* stack collision with another vma */ ++ goto out_unlock; ++ } ++ } + size = vma->vm_end - address; + grow = (vma->vm_start - address) >> PAGE_SHIFT; + +@@ -1677,6 +1733,7 @@ static inline int expand_downwards(struc + vma->vm_pgoff -= grow; + } + } ++ out_unlock: + anon_vma_unlock(vma); + return error; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/squashfs-3.4.patch b/src/patches/suse-2.6.27.31/patches.suse/squashfs-3.4.patch new file mode 100644 index 000000000..ae00bc755 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/squashfs-3.4.patch @@ -0,0 +1,4230 @@ +From: Phillip Lougher +Subject: squashfs v3.4 +Patch-mainline: Who knows? + +This patch contains the SquashFS file system. + +Acked-by: Greg Kroah-Hartman + +--- + fs/Kconfig | 50 + fs/Makefile | 1 + fs/squashfs/Makefile | 7 + fs/squashfs/inode.c | 2174 +++++++++++++++++++++++++++++++++++++++++ + fs/squashfs/squashfs.h | 86 + + fs/squashfs/squashfs2_0.c | 740 +++++++++++++ + include/linux/squashfs_fs.h | 935 +++++++++++++++++ + include/linux/squashfs_fs_i.h | 45 + include/linux/squashfs_fs_sb.h | 79 + + init/do_mounts_rd.c | 16 + 10 files changed, 4133 insertions(+) + +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -1391,6 +1391,56 @@ config CRAMFS + + If unsure, say N. + ++config SQUASHFS ++ tristate "SquashFS 3.4 - Squashed file system support" ++ select ZLIB_INFLATE ++ help ++ Saying Y here includes support for SquashFS 3.4 (a Compressed ++ Read-Only File System). Squashfs is a highly compressed read-only ++ filesystem for Linux. It uses zlib compression to compress both ++ files, inodes and directories. Inodes in the system are very small ++ and all blocks are packed to minimise data overhead. Block sizes ++ greater than 4K are supported up to a maximum of 1 Mbytes (default ++ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files ++ (larger than 4GB), full uid/gid information, hard links and timestamps. ++ ++ Squashfs is intended for general read-only filesystem use, for ++ archival use (i.e. in cases where a .tar.gz file may be used), and in ++ embedded systems where low overhead is needed. Further information ++ and filesystem tools are available from http://squashfs.sourceforge.net. ++ ++ If you want to compile this as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want), ++ say M here and read . The module ++ will be called squashfs. Note that the root file system (the one ++ containing the directory /) cannot be compiled as a module. ++ ++ If unsure, say N. ++ ++config SQUASHFS_EMBEDDED ++ ++ bool "Additional option for memory-constrained systems" ++ depends on SQUASHFS ++ default n ++ help ++ Saying Y here allows you to specify cache size. ++ ++ If unsure, say N. ++ ++config SQUASHFS_FRAGMENT_CACHE_SIZE ++ int "Number of fragments cached" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default "3" ++ help ++ By default SquashFS caches the last 3 fragments read from ++ the filesystem. Increasing this amount may mean SquashFS ++ has to re-read fragments less often from disk, at the expense ++ of extra system memory. Decreasing this amount will mean ++ SquashFS uses less memory at the expense of extra reads from disk. ++ ++ Note there must be at least one cached fragment. Anything ++ much more than three will probably not make much difference. ++ + config VXFS_FS + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + depends on BLOCK +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -77,6 +77,7 @@ obj-$(CONFIG_JBD) += jbd/ + obj-$(CONFIG_JBD2) += jbd2/ + obj-$(CONFIG_EXT2_FS) += ext2/ + obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ + obj-y += ramfs/ + obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ + obj-$(CONFIG_CODA_FS) += coda/ +--- /dev/null ++++ b/fs/squashfs/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for the linux squashfs routines. ++# ++ ++obj-$(CONFIG_SQUASHFS) += squashfs.o ++squashfs-y += inode.o ++squashfs-y += squashfs2_0.o +--- /dev/null ++++ b/fs/squashfs/inode.c +@@ -0,0 +1,2174 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 ++ * Phillip Lougher ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * inode.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs.h" ++ ++static struct dentry *squashfs_fh_to_dentry(struct super_block *s, ++ struct fid *fid, int fh_len, int fh_type); ++static struct dentry *squashfs_fh_to_parent(struct super_block *s, ++ struct fid *fid, int fh_len, int fh_type); ++static struct dentry *squashfs_get_parent(struct dentry *child); ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); ++static int squashfs_statfs(struct dentry *, struct kstatfs *); ++static int squashfs_symlink_readpage(struct file *file, struct page *page); ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize); ++static int squashfs_readpage(struct file *file, struct page *page); ++static int squashfs_readdir(struct file *, void *, filldir_t); ++static struct dentry *squashfs_lookup(struct inode *, struct dentry *, ++ struct nameidata *); ++static int squashfs_remount(struct super_block *s, int *flags, char *data); ++static void squashfs_put_super(struct super_block *); ++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, ++ struct vfsmount *); ++static struct inode *squashfs_alloc_inode(struct super_block *sb); ++static void squashfs_destroy_inode(struct inode *inode); ++static int init_inodecache(void); ++static void destroy_inodecache(void); ++ ++static struct file_system_type squashfs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "squashfs", ++ .get_sb = squashfs_get_sb, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV ++}; ++ ++static const unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static struct super_operations squashfs_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .remount_fs = squashfs_remount ++}; ++ ++static struct export_operations squashfs_export_ops = { ++ .fh_to_dentry = squashfs_fh_to_dentry, ++ .fh_to_parent = squashfs_fh_to_parent, ++ .get_parent = squashfs_get_parent ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = { ++ .readpage = squashfs_symlink_readpage ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_aops = { ++ .readpage = squashfs_readpage ++}; ++ ++static const struct file_operations squashfs_dir_ops = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir ++}; ++ ++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = { ++ .lookup = squashfs_lookup ++}; ++ ++ ++static struct buffer_head *get_block_length(struct super_block *s, ++ int *cur_index, int *offset, int *c_byte) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned short temp; ++ struct buffer_head *bh; ++ ++ if (!(bh = sb_bread(s, *cur_index))) ++ goto out; ++ ++ if (msblk->devblksize - *offset == 1) { ++ if (msblk->swap) ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ else ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ if (msblk->swap) ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ bh->b_data); ++ else ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ bh->b_data); ++ *c_byte = temp; ++ *offset = 1; ++ } else { ++ if (msblk->swap) { ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } else { ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } ++ *c_byte = temp; ++ *offset += 2; ++ } ++ ++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) { ++ if (*offset == msblk->devblksize) { ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ *offset = 0; ++ } ++ if (*((unsigned char *) (bh->b_data + *offset)) != ++ SQUASHFS_MARKER_BYTE) { ++ ERROR("Metadata block marker corrupt @ %x\n", ++ *cur_index); ++ brelse(bh); ++ goto out; ++ } ++ (*offset)++; ++ } ++ return bh; ++ ++out: ++ return NULL; ++} ++ ++ ++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ struct buffer_head **bh; ++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); ++ unsigned int cur_index = index >> msblk->devblksize_log2; ++ int bytes, avail_bytes, b = 0, k = 0; ++ unsigned int compressed; ++ unsigned int c_byte = length; ++ ++ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) * ++ sizeof(struct buffer_head *), GFP_KERNEL); ++ if (bh == NULL) ++ goto read_failure; ++ ++ if (c_byte) { ++ bytes = -offset; ++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, ++ compressed ? "" : "un", (unsigned int) c_byte, srclength); ++ ++ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ for (b = 0; bytes < (int) c_byte; b++, cur_index++) { ++ bh[b] = sb_getblk(s, cur_index); ++ if (bh[b] == NULL) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b, bh); ++ } else { ++ if (index < 0 || (index + 2) > sblk->bytes_used) ++ goto read_failure; ++ ++ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte); ++ if (bh[0] == NULL) ++ goto read_failure; ++ b = 1; ++ ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed ++ ? "" : "un", (unsigned int) c_byte); ++ ++ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) ++ goto block_release; ++ ++ for (; bytes < c_byte; b++) { ++ bh[b] = sb_getblk(s, ++cur_index); ++ if (bh[b] == NULL) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b - 1, bh + 1); ++ } ++ ++ if (compressed) { ++ int zlib_err = 0; ++ ++ /* ++ * uncompress block ++ */ ++ ++ mutex_lock(&msblk->read_data_mutex); ++ ++ msblk->stream.next_out = buffer; ++ msblk->stream.avail_out = srclength; ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); ++ ++ wait_on_buffer(bh[k]); ++ if (!buffer_uptodate(bh[k])) ++ goto release_mutex; ++ ++ msblk->stream.next_in = bh[k]->b_data + offset; ++ msblk->stream.avail_in = avail_bytes; ++ ++ if (k == 0) { ++ zlib_err = zlib_inflateInit(&msblk->stream); ++ if (zlib_err != Z_OK) { ++ ERROR("zlib_inflateInit returned unexpected result 0x%x," ++ " srclength %d\n", zlib_err, srclength); ++ goto release_mutex; ++ } ++ ++ if (avail_bytes == 0) { ++ offset = 0; ++ brelse(bh[k]); ++ continue; ++ } ++ } ++ ++ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); ++ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) { ++ ERROR("zlib_inflate returned unexpected result 0x%x," ++ " srclength %d, avail_in %d, avail_out %d\n", zlib_err, ++ srclength, msblk->stream.avail_in, msblk->stream.avail_out); ++ goto release_mutex; ++ } ++ ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ ++ if (zlib_err != Z_STREAM_END) ++ goto release_mutex; ++ ++ zlib_err = zlib_inflateEnd(&msblk->stream); ++ if (zlib_err != Z_OK) { ++ ERROR("zlib_inflateEnd returned unexpected result 0x%x," ++ " srclength %d\n", zlib_err, srclength); ++ goto release_mutex; ++ } ++ bytes = msblk->stream.total_out; ++ mutex_unlock(&msblk->read_data_mutex); ++ } else { ++ int i; ++ ++ for(i = 0; i < b; i++) { ++ wait_on_buffer(bh[i]); ++ if (!buffer_uptodate(bh[i])) ++ goto block_release; ++ } ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); ++ ++ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ } ++ ++ if (next_index) ++ *next_index = index + c_byte + (length ? 0 : ++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2)); ++ ++ kfree(bh); ++ return bytes; ++ ++release_mutex: ++ mutex_unlock(&msblk->read_data_mutex); ++ ++block_release: ++ for (; k < b; k++) ++ brelse(bh[k]); ++ ++read_failure: ++ ERROR("sb_bread failed reading block 0x%x\n", cur_index); ++ kfree(bh); ++ return 0; ++} ++ ++ ++static struct squashfs_cache_entry *squashfs_cache_get(struct super_block *s, ++ struct squashfs_cache *cache, long long block, int length) ++{ ++ int i, n; ++ struct squashfs_cache_entry *entry; ++ ++ spin_lock(&cache->lock); ++ ++ while (1) { ++ for (i = 0; i < cache->entries && cache->entry[i].block != block; i++); ++ ++ if (i == cache->entries) { ++ if (cache->unused_blks == 0) { ++ cache->waiting ++; ++ spin_unlock(&cache->lock); ++ wait_event(cache->wait_queue, cache->unused_blks); ++ spin_lock(&cache->lock); ++ cache->waiting --; ++ continue; ++ } ++ ++ i = cache->next_blk; ++ for (n = 0; n < cache->entries; n++) { ++ if (cache->entry[i].locked == 0) ++ break; ++ i = (i + 1) % cache->entries; ++ } ++ ++ cache->next_blk = (i + 1) % cache->entries; ++ entry = &cache->entry[i]; ++ ++ cache->unused_blks --; ++ entry->block = block; ++ entry->locked = 1; ++ entry->pending = 1; ++ entry->waiting = 0; ++ entry->error = 0; ++ spin_unlock(&cache->lock); ++ ++ entry->length = squashfs_read_data(s, entry->data, ++ block, length, &entry->next_index, cache->block_size); ++ ++ spin_lock(&cache->lock); ++ ++ if (entry->length == 0) ++ entry->error = 1; ++ ++ entry->pending = 0; ++ spin_unlock(&cache->lock); ++ if (entry->waiting) ++ wake_up_all(&entry->wait_queue); ++ goto out; ++ } ++ ++ entry = &cache->entry[i]; ++ if (entry->locked == 0) ++ cache->unused_blks --; ++ entry->locked++; ++ ++ if (entry->pending) { ++ entry->waiting ++; ++ spin_unlock(&cache->lock); ++ wait_event(entry->wait_queue, !entry->pending); ++ goto out; ++ } ++ ++ spin_unlock(&cache->lock); ++ goto out; ++ } ++ ++out: ++ TRACE("Got %s %d, start block %lld, locked %d, error %d\n", i, ++ cache->name, entry->block, entry->locked, entry->error); ++ if (entry->error) ++ ERROR("Unable to read %s cache entry [%llx]\n", cache->name, block); ++ return entry; ++} ++ ++ ++static void squashfs_cache_put(struct squashfs_cache *cache, ++ struct squashfs_cache_entry *entry) ++{ ++ spin_lock(&cache->lock); ++ entry->locked --; ++ if (entry->locked == 0) { ++ cache->unused_blks ++; ++ spin_unlock(&cache->lock); ++ if (cache->waiting) ++ wake_up(&cache->wait_queue); ++ } else ++ spin_unlock(&cache->lock); ++} ++ ++ ++static void squashfs_cache_delete(struct squashfs_cache *cache) ++{ ++ int i; ++ ++ if (cache == NULL) ++ return; ++ ++ for (i = 0; i < cache->entries; i++) ++ if (cache->entry[i].data) { ++ if (cache->use_vmalloc) ++ vfree(cache->entry[i].data); ++ else ++ kfree(cache->entry[i].data); ++ } ++ ++ kfree(cache); ++} ++ ++ ++static struct squashfs_cache *squashfs_cache_init(char *name, int entries, ++ int block_size, int use_vmalloc) ++{ ++ int i; ++ struct squashfs_cache *cache = kzalloc(sizeof(struct squashfs_cache) + ++ entries * sizeof(struct squashfs_cache_entry), GFP_KERNEL); ++ if (cache == NULL) { ++ ERROR("Failed to allocate %s cache\n", name); ++ goto failed; ++ } ++ ++ cache->next_blk = 0; ++ cache->unused_blks = entries; ++ cache->entries = entries; ++ cache->block_size = block_size; ++ cache->use_vmalloc = use_vmalloc; ++ cache->name = name; ++ cache->waiting = 0; ++ spin_lock_init(&cache->lock); ++ init_waitqueue_head(&cache->wait_queue); ++ ++ for (i = 0; i < entries; i++) { ++ init_waitqueue_head(&cache->entry[i].wait_queue); ++ cache->entry[i].block = SQUASHFS_INVALID_BLK; ++ cache->entry[i].data = use_vmalloc ? vmalloc(block_size) : ++ kmalloc(block_size, GFP_KERNEL); ++ if (cache->entry[i].data == NULL) { ++ ERROR("Failed to allocate %s cache entry\n", name); ++ goto cleanup; ++ } ++ } ++ ++ return cache; ++ ++cleanup: ++ squashfs_cache_delete(cache); ++failed: ++ return NULL; ++} ++ ++ ++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ int bytes, return_length = length; ++ struct squashfs_cache_entry *entry; ++ ++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); ++ ++ while (1) { ++ entry = squashfs_cache_get(s, msblk->block_cache, block, 0); ++ bytes = entry->length - offset; ++ ++ if (entry->error || bytes < 1) { ++ return_length = 0; ++ goto finish; ++ } else if (bytes >= length) { ++ if (buffer) ++ memcpy(buffer, entry->data + offset, length); ++ if (entry->length - offset == length) { ++ *next_block = entry->next_index; ++ *next_offset = 0; ++ } else { ++ *next_block = block; ++ *next_offset = offset + length; ++ } ++ goto finish; ++ } else { ++ if (buffer) { ++ memcpy(buffer, entry->data + offset, bytes); ++ buffer = (char *) buffer + bytes; ++ } ++ block = entry->next_index; ++ squashfs_cache_put(msblk->block_cache, entry); ++ length -= bytes; ++ offset = 0; ++ } ++ } ++ ++finish: ++ squashfs_cache_put(msblk->block_cache, entry); ++ return return_length; ++} ++ ++ ++static int get_fragment_location(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); ++ struct squashfs_fragment_entry fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset, ++ sizeof(sfragment_entry), &start_block, &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset, ++ sizeof(fragment_entry), &start_block, &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, ++ struct squashfs_cache_entry *fragment) ++{ ++ squashfs_cache_put(msblk->fragment_cache, fragment); ++} ++ ++ ++SQSH_EXTERN ++struct squashfs_cache_entry *get_cached_fragment(struct super_block *s, ++ long long start_block, int length) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ ++ return squashfs_cache_get(s, msblk->fragment_cache, start_block, length); ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header *inodeb) ++{ ++ i->i_ino = inodeb->inode_number; ++ i->i_mtime.tv_sec = inodeb->mtime; ++ i->i_atime.tv_sec = inodeb->mtime; ++ i->i_ctime.tv_sec = inodeb->mtime; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_size = 0; ++ ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; ++ int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); ++ squashfs_inode_t inode; ++ ++ TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino); ++ ++ if (msblk->swap) { ++ squashfs_inode_t sinode; ++ ++ if (!squashfs_get_cached_block(s, &sinode, start, offset, ++ sizeof(sinode), &start, &offset)) ++ goto out; ++ SQUASHFS_SWAP_INODE_T((&inode), &sinode); ++ } else if (!squashfs_get_cached_block(s, &inode, start, offset, ++ sizeof(inode), &start, &offset)) ++ goto out; ++ ++ TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode); ++ ++ return inode; ++ ++out: ++ return SQUASHFS_INVALID_BLK; ++} ++ ++ ++ ++static struct dentry *squashfs_export_iget(struct super_block *s, ++ unsigned int inode_number) ++{ ++ squashfs_inode_t inode; ++ struct inode *i; ++ struct dentry *dentry; ++ ++ TRACE("Entered squashfs_export_iget\n"); ++ ++ inode = squashfs_inode_lookup(s, inode_number); ++ if(inode == SQUASHFS_INVALID_BLK) { ++ dentry = ERR_PTR(-ENOENT); ++ goto failure; ++ } ++ ++ i = squashfs_iget(s, inode, inode_number); ++ if(i == NULL) { ++ dentry = ERR_PTR(-EACCES); ++ goto failure; ++ } ++ ++ dentry = d_alloc_anon(i); ++ if (dentry == NULL) { ++ iput(i); ++ dentry = ERR_PTR(-ENOMEM); ++ } ++ ++failure: ++ return dentry; ++} ++ ++ ++static struct dentry *squashfs_fh_to_dentry(struct super_block *s, ++ struct fid *fid, int fh_len, int fh_type) ++{ ++ if((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) || ++ fh_len < 2) ++ return NULL; ++ ++ return squashfs_export_iget(s, fid->i32.ino); ++} ++ ++ ++static struct dentry *squashfs_fh_to_parent(struct super_block *s, ++ struct fid *fid, int fh_len, int fh_type) ++{ ++ if(fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4) ++ return NULL; ++ ++ return squashfs_export_iget(s, fid->i32.parent_ino); ++} ++ ++ ++static struct dentry *squashfs_get_parent(struct dentry *child) ++{ ++ struct inode *i = child->d_inode; ++ ++ TRACE("Entered squashfs_get_parent\n"); ++ ++ return squashfs_export_iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); ++} ++ ++ ++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, ++ squashfs_inode_t inode, unsigned int inode_number) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct inode *i = iget_locked(s, inode_number); ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if(i && (i->i_state & I_NEW)) { ++ (msblk->read_inode)(i, inode); ++ unlock_new_inode(i); ++ } ++ ++ return i; ++} ++ ++ ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header id, sid; ++ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_read_inode\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodeb, block, offset, ++ sizeof(*sinodeb), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, inodeb, block, offset, ++ sizeof(*inodeb), &next_block, &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_reg_inode_header *inodep = &id.reg; ++ struct squashfs_reg_inode_header *sinodep = &sid.reg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG) ++ if(!get_fragment_location(s, inodep->fragment, &frag_blk, ++ &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ i->i_data.a_ops = &squashfs_aops; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_LREG_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_lreg_inode_header *inodep = &id.lreg; ++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG) ++ if (!get_fragment_location(s, inodep->fragment, &frag_blk, ++ &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ i->i_data.a_ops = &squashfs_aops; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header *inodep = &id.dir; ++ struct squashfs_dir_inode_header *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header *inodep = &id.symlink; ++ struct squashfs_symlink_inode_header *sinodep = &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header *inodep = &id.dev; ++ struct squashfs_dev_inode_header *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? ++ S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ struct squashfs_ipc_inode_header *inodep = &id.ipc; ++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%llx:%x]\n", block, offset); ++ ++failed_read1: ++ make_bad_inode(i); ++ return 0; ++} ++ ++ ++static int read_inode_lookup_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); ++ ++ TRACE("In read_inode_lookup_table, length %d\n", length); ++ ++ /* Allocate inode lookup table */ ++ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL); ++ if (msblk->inode_lookup_table == NULL) { ++ ERROR("Failed to allocate inode lookup table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, ++ sblk->lookup_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read inode lookup table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long block; ++ ++ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { ++ /* XXX */ ++ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), ++ &msblk->inode_lookup_table[i], 1); ++ msblk->inode_lookup_table[i] = block; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int read_fragment_index_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); ++ ++ if(length == 0) ++ return 1; ++ ++ /* Allocate fragment index table */ ++ msblk->fragment_index = kmalloc(length, GFP_KERNEL); ++ if (msblk->fragment_index == NULL) { ++ ERROR("Failed to allocate fragment index table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->fragment_index, ++ sblk->fragment_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { ++ /* XXX */ ++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), ++ &msblk->fragment_index[i], 1); ++ msblk->fragment_index[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode; ++ msblk->read_blocklist = read_blocklist; ++ msblk->read_fragment_index_table = read_fragment_index_table; ++ ++ if (sblk->s_major == 1) { ++ if (!squashfs_1_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with Squashfs 1.0 support enabled\n"); ++ return 0; ++ } ++ } else if (sblk->s_major == 2) { ++ if (!squashfs_2_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with Squashfs 2.0 support enabled\n"); ++ return 0; ++ } ++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > ++ SQUASHFS_MINOR) { ++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d " ++ "filesystem\n", sblk->s_major, sblk->s_minor); ++ SERROR("Please update your kernel\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static int squashfs_fill_super(struct super_block *s, void *data, int silent) ++{ ++ struct squashfs_sb_info *msblk; ++ struct squashfs_super_block *sblk; ++ char b[BDEVNAME_SIZE]; ++ struct inode *root; ++ ++ TRACE("Entered squashfs_fill_superblock\n"); ++ ++ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL); ++ if (s->s_fs_info == NULL) { ++ ERROR("Failed to allocate superblock\n"); ++ goto failure; ++ } ++ msblk = s->s_fs_info; ++ ++ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()); ++ if (msblk->stream.workspace == NULL) { ++ ERROR("Failed to allocate zlib workspace\n"); ++ goto failure; ++ } ++ sblk = &msblk->sblk; ++ ++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); ++ msblk->devblksize_log2 = ffz(~msblk->devblksize); ++ ++ mutex_init(&msblk->read_data_mutex); ++ mutex_init(&msblk->read_page_mutex); ++ mutex_init(&msblk->meta_index_mutex); ++ ++ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not ++ * beyond filesystem end. As we're using squashfs_read_data to read sblk here, ++ * first set sblk->bytes_used to a useful value */ ++ sblk->bytes_used = sizeof(struct squashfs_super_block); ++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, ++ sizeof(struct squashfs_super_block) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { ++ SERROR("unable to read superblock\n"); ++ goto failed_mount; ++ } ++ ++ /* Check it is a SQUASHFS superblock */ ++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { ++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { ++ struct squashfs_super_block ssblk; ++ ++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", ++ bdevname(s->s_bdev, b)); ++ ++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); ++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); ++ msblk->swap = 1; ++ } else { ++ SERROR("Can't find a SQUASHFS superblock on %s\n", ++ bdevname(s->s_bdev, b)); ++ goto failed_mount; ++ } ++ } ++ ++ /* Check the MAJOR & MINOR versions */ ++ if(!supported_squashfs_filesystem(msblk, silent)) ++ goto failed_mount; ++ ++ /* Check the filesystem does not extend beyond the end of the ++ block device */ ++ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) ++ goto failed_mount; ++ ++ /* Check the root inode for sanity */ ++ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) ++ goto failed_mount; ++ ++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); ++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags) ++ ? "un" : ""); ++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) ++ ? "un" : ""); ++ TRACE("Check data is %spresent in the filesystem\n", ++ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not "); ++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); ++ TRACE("Block size %d\n", sblk->block_size); ++ TRACE("Number of inodes %d\n", sblk->inodes); ++ if (sblk->s_major > 1) ++ TRACE("Number of fragments %d\n", sblk->fragments); ++ TRACE("Number of uids %d\n", sblk->no_uids); ++ TRACE("Number of gids %d\n", sblk->no_guids); ++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); ++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); ++ if (sblk->s_major > 1) ++ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start); ++ TRACE("sblk->uid_start %llx\n", sblk->uid_start); ++ ++ s->s_maxbytes = MAX_LFS_FILESIZE; ++ s->s_flags |= MS_RDONLY; ++ s->s_op = &squashfs_super_ops; ++ ++ msblk->block_cache = squashfs_cache_init("metadata", SQUASHFS_CACHED_BLKS, ++ SQUASHFS_METADATA_SIZE, 0); ++ if (msblk->block_cache == NULL) ++ goto failed_mount; ++ ++ /* Allocate read_page block */ ++ msblk->read_page = vmalloc(sblk->block_size); ++ if (msblk->read_page == NULL) { ++ ERROR("Failed to allocate read_page block\n"); ++ goto failed_mount; ++ } ++ ++ /* Allocate uid and gid tables */ ++ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int), GFP_KERNEL); ++ if (msblk->uid == NULL) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount; ++ } ++ msblk->guid = msblk->uid + sblk->no_uids; ++ ++ if (msblk->swap) { ++ unsigned int suid[sblk->no_uids + sblk->no_guids]; ++ ++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + ++ sblk->no_guids), (sizeof(unsigned int) * 8)); ++ } else ++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ ++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) ++ goto allocate_root; ++ ++ msblk->fragment_cache = squashfs_cache_init("fragment", ++ SQUASHFS_CACHED_FRAGMENTS, sblk->block_size, 1); ++ if (msblk->fragment_cache == NULL) ++ goto failed_mount; ++ ++ /* Allocate and read fragment index table */ ++ if (msblk->read_fragment_index_table(s) == 0) ++ goto failed_mount; ++ ++ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK) ++ goto allocate_root; ++ ++ /* Allocate and read inode lookup table */ ++ if (read_inode_lookup_table(s) == 0) ++ goto failed_mount; ++ ++ s->s_export_op = &squashfs_export_ops; ++ ++allocate_root: ++ root = new_inode(s); ++ if ((msblk->read_inode)(root, sblk->root_inode) == 0) ++ goto failed_mount; ++ insert_inode_hash(root); ++ ++ s->s_root = d_alloc_root(root); ++ if (s->s_root == NULL) { ++ ERROR("Root inode create failed\n"); ++ iput(root); ++ goto failed_mount; ++ } ++ ++ TRACE("Leaving squashfs_fill_super\n"); ++ return 0; ++ ++failed_mount: ++ kfree(msblk->inode_lookup_table); ++ kfree(msblk->fragment_index); ++ squashfs_cache_delete(msblk->fragment_cache); ++ kfree(msblk->uid); ++ vfree(msblk->read_page); ++ squashfs_cache_delete(msblk->block_cache); ++ kfree(msblk->fragment_index_2); ++ vfree(msblk->stream.workspace); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ return -EINVAL; ++ ++failure: ++ return -ENOMEM; ++} ++ ++ ++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ TRACE("Entered squashfs_statfs\n"); ++ ++ buf->f_type = SQUASHFS_MAGIC; ++ buf->f_bsize = sblk->block_size; ++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; ++ buf->f_bfree = buf->f_bavail = 0; ++ buf->f_files = sblk->inodes; ++ buf->f_ffree = 0; ++ buf->f_namelen = SQUASHFS_NAME_LEN; ++ ++ return 0; ++} ++ ++ ++static int squashfs_symlink_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes; ++ long long block = SQUASHFS_I(inode)->start_block; ++ int offset = SQUASHFS_I(inode)->offset; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " ++ "%llx, offset %x\n", page->index, ++ SQUASHFS_I(inode)->start_block, ++ SQUASHFS_I(inode)->offset); ++ ++ for (length = 0; length < index; length += bytes) { ++ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, ++ offset, PAGE_CACHE_SIZE, &block, &offset); ++ if (bytes == 0) { ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); ++ goto skip_read; ++ } ++ } ++ ++ if (length != index) { ++ ERROR("(squashfs_symlink_readpage) length != index\n"); ++ bytes = 0; ++ goto skip_read; ++ } ++ ++ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE); ++ ++ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, ++ avail_bytes, &block, &offset); ++ if (bytes == 0) ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++static struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) ++{ ++ struct meta_index *meta = NULL; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset); ++ ++ if (msblk->meta_index == NULL) ++ goto not_allocated; ++ ++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) { ++ if (msblk->meta_index[i].inode_number == inode->i_ino && ++ msblk->meta_index[i].offset >= offset && ++ msblk->meta_index[i].offset <= index && ++ msblk->meta_index[i].locked == 0) { ++ TRACE("locate_meta_index: entry %d, offset %d\n", i, ++ msblk->meta_index[i].offset); ++ meta = &msblk->meta_index[i]; ++ offset = meta->offset; ++ } ++ } ++ ++ if (meta) ++ meta->locked = 1; ++ ++not_allocated: ++ mutex_unlock(&msblk->meta_index_mutex); ++ ++ return meta; ++} ++ ++ ++static struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct meta_index *meta = NULL; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); ++ ++ if (msblk->meta_index == NULL) { ++ msblk->meta_index = kmalloc(sizeof(struct meta_index) * ++ SQUASHFS_META_NUMBER, GFP_KERNEL); ++ if (msblk->meta_index == NULL) { ++ ERROR("Failed to allocate meta_index\n"); ++ goto failed; ++ } ++ for (i = 0; i < SQUASHFS_META_NUMBER; i++) { ++ msblk->meta_index[i].inode_number = 0; ++ msblk->meta_index[i].locked = 0; ++ } ++ msblk->next_meta_index = 0; ++ } ++ ++ for (i = SQUASHFS_META_NUMBER; i && ++ msblk->meta_index[msblk->next_meta_index].locked; i --) ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ if (i == 0) { ++ TRACE("empty_meta_index: failed!\n"); ++ goto failed; ++ } ++ ++ TRACE("empty_meta_index: returned meta entry %d, %p\n", ++ msblk->next_meta_index, ++ &msblk->meta_index[msblk->next_meta_index]); ++ ++ meta = &msblk->meta_index[msblk->next_meta_index]; ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ meta->inode_number = inode->i_ino; ++ meta->offset = offset; ++ meta->skip = skip; ++ meta->entries = 0; ++ meta->locked = 1; ++ ++failed: ++ mutex_unlock(&msblk->meta_index_mutex); ++ return meta; ++} ++ ++ ++static void release_meta_index(struct inode *inode, struct meta_index *meta) ++{ ++ meta->locked = 0; ++ smp_mb(); ++} ++ ++ ++static int read_block_index(struct super_block *s, int blocks, char *block_list, ++ long long *start_block, int *offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned int *block_listp; ++ int block = 0; ++ ++ if (msblk->swap) { ++ char sblock_list[blocks << 2]; ++ ++ if (!squashfs_get_cached_block(s, sblock_list, *start_block, ++ *offset, blocks << 2, start_block, offset)) { ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); ++ goto failure; ++ } ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ++ ((unsigned int *)sblock_list), blocks); ++ } else { ++ if (!squashfs_get_cached_block(s, block_list, *start_block, ++ *offset, blocks << 2, start_block, offset)) { ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); ++ goto failure; ++ } ++ } ++ ++ for (block_listp = (unsigned int *) block_list; blocks; ++ block_listp++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); ++ ++ return block; ++ ++failure: ++ return -1; ++} ++ ++ ++#define SIZE 256 ++ ++static inline int calculate_skip(int blocks) { ++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); ++ return skip >= 7 ? 7 : skip + 1; ++} ++ ++ ++static int get_meta_index(struct inode *inode, int index, ++ long long *index_block, int *index_offset, ++ long long *data_block, char *block_list) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); ++ int offset = 0; ++ struct meta_index *meta; ++ struct meta_entry *meta_entry; ++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; ++ int cur_offset = SQUASHFS_I(inode)->offset; ++ long long cur_data_block = SQUASHFS_I(inode)->start_block; ++ int i; ++ ++ index /= SQUASHFS_META_INDEXES * skip; ++ ++ while (offset < index) { ++ meta = locate_meta_index(inode, index, offset + 1); ++ ++ if (meta == NULL) { ++ meta = empty_meta_index(inode, offset + 1, skip); ++ if (meta == NULL) ++ goto all_done; ++ } else { ++ if(meta->entries == 0) ++ goto failed; ++ /* XXX */ ++ offset = index < meta->offset + meta->entries ? index : ++ meta->offset + meta->entries - 1; ++ /* XXX */ ++ meta_entry = &meta->meta_entry[offset - meta->offset]; ++ cur_index_block = meta_entry->index_block + sblk->inode_table_start; ++ cur_offset = meta_entry->offset; ++ cur_data_block = meta_entry->data_block; ++ TRACE("get_meta_index: offset %d, meta->offset %d, " ++ "meta->entries %d\n", offset, meta->offset, meta->entries); ++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" ++ " data_block 0x%llx\n", cur_index_block, ++ cur_offset, cur_data_block); ++ } ++ ++ for (i = meta->offset + meta->entries; i <= index && ++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) { ++ int blocks = skip * SQUASHFS_META_INDEXES; ++ ++ while (blocks) { ++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks; ++ int res = read_block_index(inode->i_sb, block, block_list, ++ &cur_index_block, &cur_offset); ++ ++ if (res == -1) ++ goto failed; ++ ++ cur_data_block += res; ++ blocks -= block; ++ } ++ ++ meta_entry = &meta->meta_entry[i - meta->offset]; ++ meta_entry->index_block = cur_index_block - sblk->inode_table_start; ++ meta_entry->offset = cur_offset; ++ meta_entry->data_block = cur_data_block; ++ meta->entries ++; ++ offset ++; ++ } ++ ++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", ++ meta->offset, meta->entries); ++ ++ release_meta_index(inode, meta); ++ } ++ ++all_done: ++ *index_block = cur_index_block; ++ *index_offset = cur_offset; ++ *data_block = cur_data_block; ++ ++ return offset * SQUASHFS_META_INDEXES * skip; ++ ++failed: ++ release_meta_index(inode, meta); ++ return -1; ++} ++ ++ ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize) ++{ ++ long long block_ptr; ++ int offset; ++ long long block; ++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block, ++ block_list); ++ ++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" ++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block); ++ ++ if(res == -1) ++ goto failure; ++ ++ index -= res; ++ ++ while (index) { ++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; ++ int res = read_block_index(inode->i_sb, blocks, block_list, ++ &block_ptr, &offset); ++ if (res == -1) ++ goto failure; ++ block += res; ++ index -= blocks; ++ } ++ ++ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1) ++ goto failure; ++ *bsize = *((unsigned int *) block_list); ++ ++ return block; ++ ++failure: ++ return 0; ++} ++ ++ ++static int squashfs_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned char *block_list = NULL; ++ long long block; ++ unsigned int bsize, i; ++ int bytes; ++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); ++ void *pageaddr; ++ struct squashfs_cache_entry *fragment = NULL; ++ char *data_ptr = msblk->read_page; ++ ++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; ++ int start_index = page->index & ~mask; ++ int end_index = start_index | mask; ++ int file_end = i_size_read(inode) >> sblk->block_log; ++ int sparse = 0; ++ ++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", ++ page->index, SQUASHFS_I(inode)->start_block); ++ ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> ++ PAGE_CACHE_SHIFT)) ++ goto out; ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < file_end) { ++ block_list = kmalloc(SIZE, GFP_KERNEL); ++ if (block_list == NULL) { ++ ERROR("Failed to allocate block_list\n"); ++ goto error_out; ++ } ++ ++ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize); ++ if (block == 0) ++ goto error_out; ++ ++ if (bsize == 0) { /* hole */ ++ bytes = index == file_end ? ++ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size; ++ sparse = 1; ++ } else { ++ mutex_lock(&msblk->read_page_mutex); ++ ++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, ++ bsize, NULL, sblk->block_size); ++ ++ if (bytes == 0) { ++ ERROR("Unable to read page, block %llx, size %x\n", block, bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ goto error_out; ++ } ++ } ++ } else { ++ fragment = get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> u.s1.fragment_start_block, ++ SQUASHFS_I(inode)->u.s1.fragment_size); ++ ++ if (fragment->error) { ++ ERROR("Unable to read page, block %llx, size %x\n", ++ SQUASHFS_I(inode)->u.s1.fragment_start_block, ++ (int) SQUASHFS_I(inode)->u.s1.fragment_size); ++ release_cached_fragment(msblk, fragment); ++ goto error_out; ++ } ++ bytes = i_size_read(inode) & (sblk->block_size - 1); ++ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset; ++ } ++ ++ for (i = start_index; i <= end_index && bytes > 0; i++, ++ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) { ++ struct page *push_page; ++ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE); ++ ++ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); ++ ++ push_page = (i == page->index) ? page : ++ grab_cache_page_nowait(page->mapping, i); ++ ++ if (!push_page) ++ continue; ++ ++ if (PageUptodate(push_page)) ++ goto skip_page; ++ ++ pageaddr = kmap_atomic(push_page, KM_USER0); ++ memcpy(pageaddr, data_ptr, avail); ++ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(push_page); ++ SetPageUptodate(push_page); ++skip_page: ++ unlock_page(push_page); ++ if(i != page->index) ++ page_cache_release(push_page); ++ } ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < file_end) { ++ if (!sparse) ++ mutex_unlock(&msblk->read_page_mutex); ++ kfree(block_list); ++ } else ++ release_cached_fragment(msblk, fragment); ++ ++ return 0; ++ ++error_out: ++ SetPageError(page); ++out: ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memset(pageaddr, 0, PAGE_CACHE_SIZE); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(page); ++ if (!PageError(page)) ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ kfree(block_list); ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, ++ long long *next_block, unsigned int *next_offset, ++ long long index_start, unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ f_pos -= 3; ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset, ++ sizeof(sindex), &index_start, &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, &index, index_start, index_offset, ++ sizeof(index), &index_start, &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length + 3; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, ++ long long *next_block, unsigned int *next_offset, ++ long long index_start, unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL); ++ if (str == NULL) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset, ++ sizeof(sindex), &index_start, &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, index, index_start, index_offset, ++ sizeof(struct squashfs_dir_index), &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, index_offset, ++ index->size + 1, &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++ ++failure: ++ return length + 3; ++} ++ ++ ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); ++ ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); ++ if (dire == NULL) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ while(file->f_pos < 3) { ++ char *name; ++ int size, i_ino; ++ ++ if(file->f_pos == 0) { ++ name = "."; ++ size = 1; ++ i_ino = i->i_ino; ++ } else { ++ name = ".."; ++ size = 2; ++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode; ++ } ++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", ++ (unsigned int) dirent, name, size, (int) ++ file->f_pos, i_ino, squashfs_filetype_table[1]); ++ ++ if (filldir(dirent, name, size, file->f_pos, i_ino, ++ squashfs_filetype_table[1]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos += size; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block, ++ next_offset, sizeof(*dire), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", ++ (unsigned int) dirent, dire->name, dire->size + 1, ++ (int) file->f_pos, dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); ++ ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); ++ if (dire == NULL) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_lookup; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_lookup; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block, ++ next_offset, sizeof(*dire), &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (name[0] < dire->name[0]) ++ goto exit_lookup; ++ ++ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { ++ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory entry %s, inode" ++ " %x:%x, %d\n", name, dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number); ++ ++ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); ++ ++ goto exit_lookup; ++ } ++ } ++ } ++ ++exit_lookup: ++ kfree(dire); ++ if (inode) ++ return d_splice_alias(inode, dentry); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_lookup; ++} ++ ++ ++static int squashfs_remount(struct super_block *s, int *flags, char *data) ++{ ++ *flags |= MS_RDONLY; ++ return 0; ++} ++ ++ ++static void squashfs_put_super(struct super_block *s) ++{ ++ if (s->s_fs_info) { ++ struct squashfs_sb_info *sbi = s->s_fs_info; ++ squashfs_cache_delete(sbi->block_cache); ++ squashfs_cache_delete(sbi->fragment_cache); ++ vfree(sbi->read_page); ++ kfree(sbi->uid); ++ kfree(sbi->fragment_index); ++ kfree(sbi->fragment_index_2); ++ kfree(sbi->meta_index); ++ vfree(sbi->stream.workspace); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ } ++} ++ ++ ++static int squashfs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data, struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, ++ mnt); ++} ++ ++ ++static int __init init_squashfs_fs(void) ++{ ++ int err = init_inodecache(); ++ if (err) ++ goto out; ++ ++ printk(KERN_INFO "squashfs: version 3.4 (2008/08/26) " ++ "Phillip Lougher\n"); ++ ++ err = register_filesystem(&squashfs_fs_type); ++ if (err) ++ destroy_inodecache(); ++ ++out: ++ return err; ++} ++ ++ ++static void __exit exit_squashfs_fs(void) ++{ ++ unregister_filesystem(&squashfs_fs_type); ++ destroy_inodecache(); ++} ++ ++ ++static struct kmem_cache * squashfs_inode_cachep; ++ ++ ++static struct inode *squashfs_alloc_inode(struct super_block *sb) ++{ ++ struct squashfs_inode_info *ei; ++ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); ++ return ei ? &ei->vfs_inode : NULL; ++} ++ ++ ++static void squashfs_destroy_inode(struct inode *inode) ++{ ++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); ++} ++ ++ ++static void init_once(void *foo) ++{ ++ struct squashfs_inode_info *ei = foo; ++ ++ inode_init_once(&ei->vfs_inode); ++} ++ ++ ++static int __init init_inodecache(void) ++{ ++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", ++ sizeof(struct squashfs_inode_info), 0, ++ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); ++ if (squashfs_inode_cachep == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++ ++static void destroy_inodecache(void) ++{ ++ kmem_cache_destroy(squashfs_inode_cachep); ++} ++ ++ ++module_init(init_squashfs_fs); ++module_exit(exit_squashfs_fs); ++MODULE_DESCRIPTION("squashfs 3.4, a compressed read-only filesystem"); ++MODULE_AUTHOR("Phillip Lougher "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/fs/squashfs/squashfs.h +@@ -0,0 +1,86 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 ++ * Phillip Lougher ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs.h ++ */ ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#endif ++ ++#ifdef SQUASHFS_TRACE ++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) ++#else ++#define TRACE(s, args...) {} ++#endif ++ ++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++ ++#define SERROR(s, args...) do { \ ++ if (!silent) \ ++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\ ++ } while(0) ++ ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) ++ ++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) ++{ ++ return list_entry(inode, struct squashfs_inode_info, vfs_inode); ++} ++ ++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) ++#define SQSH_EXTERN ++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength); ++extern int squashfs_get_cached_block(struct super_block *s, void *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset); ++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct ++ squashfs_cache_entry *fragment); ++extern struct squashfs_cache_entry *get_cached_fragment(struct super_block ++ *s, long long start_block, ++ int length); ++extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); ++extern const struct address_space_operations squashfs_symlink_aops; ++extern const struct address_space_operations squashfs_aops; ++extern struct inode_operations squashfs_dir_inode_ops; ++#else ++#define SQSH_EXTERN static ++#endif ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif +--- /dev/null ++++ b/fs/squashfs/squashfs2_0.c +@@ -0,0 +1,740 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 ++ * Phillip Lougher ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs2_0.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "squashfs.h" ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); ++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, ++ struct nameidata *); ++ ++static struct file_operations squashfs_dir_ops_2 = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir_2 ++}; ++ ++static struct inode_operations squashfs_dir_inode_ops_2 = { ++ .lookup = squashfs_lookup_2 ++}; ++ ++static unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static int read_fragment_index_table_2(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ return 0; ++ } ++ ++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && ++ !squashfs_read_data(s, (char *) ++ msblk->fragment_index_2, ++ sblk->fragment_table_start, ++ SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ unsigned int fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); ++ i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), ++ &msblk->fragment_index_2[i], 1); ++ msblk->fragment_index_2[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int get_fragment_location_2(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); ++ struct squashfs_fragment_entry_2 fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry_2 sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, ++ start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, ++ start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ i->i_ino = ino; ++ i->i_mtime.tv_sec = sblk->mkfs_time; ++ i->i_atime.tv_sec = sblk->mkfs_time; ++ i->i_ctime.tv_sec = sblk->mkfs_time; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_nlink = 1; ++ i->i_size = 0; ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int block = SQUASHFS_INODE_BLK(inode) + ++ sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ unsigned int ino = SQUASHFS_MK_VFS_INODE(block - ++ sblk->inode_table_start, offset); ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header_2 id, sid; ++ struct squashfs_base_inode_header_2 *inodeb = &id.base, ++ *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_read_inode_2\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, ++ offset, sizeof(*sinodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, ++ sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block, ++ offset, sizeof(*inodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb, ino); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ struct squashfs_reg_inode_header_2 *inodep = &id.reg; ++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; ++ long long frag_blk; ++ unsigned int frag_size = 0; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location_2(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ i->i_data.a_ops = &squashfs_aops; ++ ++ TRACE("File inode %x:%x, start_block %x, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header_2 *inodep = &id.dir; ++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = ++ next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = ++ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header_2 *inodep = ++ &id.symlink; ++ struct squashfs_symlink_inode_header_2 *sinodep = ++ &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header_2 *inodep = &id.dev; ++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_mode |= (inodeb->inode_type == ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : ++ S_IFBLK; ++ init_special_inode(i, i->i_mode, ++ old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) &index, ++ index_start, index_offset, ++ sizeof(index), &index_start, ++ &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, ++ &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) index, ++ index_start, index_offset, ++ sizeof(struct squashfs_dir_index_2), ++ &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, ++ index_offset, index->size + 1, ++ &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++failure: ++ return length; ++} ++ ++ ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ ++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, ++ file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block, next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block, next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, ++ dire->size + 1, &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", ++ (unsigned int) dirent, dire->name, ++ dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, ++ file->f_pos, SQUASHFS_MK_VFS_INODE( ++ dirh.start_block, dire->offset), ++ squashfs_filetype_table[dire->type]) ++ < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; ++ ++ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_loop; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_loop; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, ++ len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block,next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block,next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (sorted && name[0] < dire->name[0]) ++ goto exit_loop; ++ ++ if ((len == dire->size + 1) && !strncmp(name, ++ dire->name, len)) { ++ squashfs_inode_t ino = ++ SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory " ++ "entry %s, inode %x:%x, %lld\n", name, ++ dirh.start_block, dire->offset, ino); ++ ++ inode = squashfs_iget(i->i_sb, ino, inode_number); ++ ++ goto exit_loop; ++ } ++ } ++ } ++ ++exit_loop: ++ kfree(dire); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_loop; ++} ++ ++ ++int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode_2; ++ msblk->read_fragment_index_table = read_fragment_index_table_2; ++ ++ sblk->bytes_used = sblk->bytes_used_2; ++ sblk->uid_start = sblk->uid_start_2; ++ sblk->guid_start = sblk->guid_start_2; ++ sblk->inode_table_start = sblk->inode_table_start_2; ++ sblk->directory_table_start = sblk->directory_table_start_2; ++ sblk->fragment_table_start = sblk->fragment_table_start_2; ++ ++ return 1; ++} +--- /dev/null ++++ b/include/linux/squashfs_fs.h +@@ -0,0 +1,935 @@ ++#ifndef SQUASHFS_FS ++#define SQUASHFS_FS ++ ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 ++ * Phillip Lougher ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs.h ++ */ ++ ++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#endif ++ ++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE ++#define SQUASHFS_MAJOR 3 ++#define SQUASHFS_MINOR 1 ++#define SQUASHFS_MAGIC 0x73717368 ++#define SQUASHFS_MAGIC_SWAP 0x68737173 ++#define SQUASHFS_START 0 ++ ++/* size of metadata (inode and directory) blocks */ ++#define SQUASHFS_METADATA_SIZE 8192 ++#define SQUASHFS_METADATA_LOG 13 ++ ++/* default size of data blocks */ ++#define SQUASHFS_FILE_SIZE 131072 ++#define SQUASHFS_FILE_LOG 17 ++ ++#define SQUASHFS_FILE_MAX_SIZE 1048576 ++ ++/* Max number of uids and gids */ ++#define SQUASHFS_UIDS 256 ++#define SQUASHFS_GUIDS 255 ++ ++/* Max length of filename (not 255) */ ++#define SQUASHFS_NAME_LEN 256 ++ ++#define SQUASHFS_INVALID ((long long) 0xffffffffffff) ++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) ++#define SQUASHFS_INVALID_BLK ((long long) -1) ++#define SQUASHFS_USED_BLK ((long long) -2) ++ ++/* Filesystem flags */ ++#define SQUASHFS_NOI 0 ++#define SQUASHFS_NOD 1 ++#define SQUASHFS_CHECK 2 ++#define SQUASHFS_NOF 3 ++#define SQUASHFS_NO_FRAG 4 ++#define SQUASHFS_ALWAYS_FRAG 5 ++#define SQUASHFS_DUPLICATE 6 ++#define SQUASHFS_EXPORT 7 ++ ++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) ++ ++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOI) ++ ++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOD) ++ ++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOF) ++ ++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NO_FRAG) ++ ++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_ALWAYS_FRAG) ++ ++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_DUPLICATE) ++ ++#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_EXPORT) ++ ++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_CHECK) ++ ++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ ++ duplicate_checking, exportable) (noi | (nod << 1) | (check_data << 2) \ ++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ ++ (duplicate_checking << 6) | (exportable << 7)) ++ ++/* Max number of types and file types */ ++#define SQUASHFS_DIR_TYPE 1 ++#define SQUASHFS_FILE_TYPE 2 ++#define SQUASHFS_SYMLINK_TYPE 3 ++#define SQUASHFS_BLKDEV_TYPE 4 ++#define SQUASHFS_CHRDEV_TYPE 5 ++#define SQUASHFS_FIFO_TYPE 6 ++#define SQUASHFS_SOCKET_TYPE 7 ++#define SQUASHFS_LDIR_TYPE 8 ++#define SQUASHFS_LREG_TYPE 9 ++ ++/* 1.0 filesystem type definitions */ ++#define SQUASHFS_TYPES 5 ++#define SQUASHFS_IPC_TYPE 0 ++ ++/* Flag whether block is compressed or uncompressed, bit is set if block is ++ * uncompressed */ ++#define SQUASHFS_COMPRESSED_BIT (1 << 15) ++ ++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ ++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) ++ ++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) ++ ++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) ++ ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ++ ++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) ++ ++/* ++ * Inode number ops. Inodes consist of a compressed block number, and an ++ * uncompressed offset within that block ++ */ ++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) ++ ++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) ++ ++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ ++ << 16) + (B))) ++ ++/* Compute 32 bit VFS inode number from squashfs inode number */ ++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ ++ ((b) >> 2) + 1)) ++/* XXX */ ++ ++/* Translate between VFS mode and squashfs mode */ ++#define SQUASHFS_MODE(a) ((a) & 0xfff) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) ++ ++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ ++ sizeof(long long)) ++ ++/* inode lookup table defines */ ++#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) ++ ++#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ ++ sizeof(long long)) ++ ++/* cached data constants for filesystem */ ++#define SQUASHFS_CACHED_BLKS 8 ++ ++#define SQUASHFS_MAX_FILE_SIZE_LOG 64 ++ ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ ++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) ++ ++#define SQUASHFS_MARKER_BYTE 0xff ++ ++/* meta index cache */ ++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) ++#define SQUASHFS_META_ENTRIES 31 ++#define SQUASHFS_META_NUMBER 8 ++#define SQUASHFS_SLOTS 4 ++ ++struct meta_entry { ++ long long data_block; ++ unsigned int index_block; ++ unsigned short offset; ++ unsigned short pad; ++}; ++ ++struct meta_index { ++ unsigned int inode_number; ++ unsigned int offset; ++ unsigned short entries; ++ unsigned short skip; ++ unsigned short locked; ++ unsigned short pad; ++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; ++}; ++ ++ ++/* ++ * definitions for structures on disk ++ */ ++ ++typedef long long squashfs_block_t; ++typedef long long squashfs_inode_t; ++ ++struct squashfs_super_block { ++ unsigned int s_magic; ++ unsigned int inodes; ++ unsigned int bytes_used_2; ++ unsigned int uid_start_2; ++ unsigned int guid_start_2; ++ unsigned int inode_table_start_2; ++ unsigned int directory_table_start_2; ++ unsigned int s_major:16; ++ unsigned int s_minor:16; ++ unsigned int block_size_1:16; ++ unsigned int block_log:16; ++ unsigned int flags:8; ++ unsigned int no_uids:8; ++ unsigned int no_guids:8; ++ unsigned int mkfs_time /* time of filesystem creation */; ++ squashfs_inode_t root_inode; ++ unsigned int block_size; ++ unsigned int fragments; ++ unsigned int fragment_table_start_2; ++ long long bytes_used; ++ long long uid_start; ++ long long guid_start; ++ long long inode_table_start; ++ long long directory_table_start; ++ long long fragment_table_start; ++ long long lookup_table_start; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_index { ++ unsigned int index; ++ unsigned int start_block; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_BASE_INODE_HEADER \ ++ unsigned int inode_type:4; \ ++ unsigned int mode:12; \ ++ unsigned int uid:8; \ ++ unsigned int guid:8; \ ++ unsigned int mtime; \ ++ unsigned int inode_number; ++ ++struct squashfs_base_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_lreg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ long long file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int parent_inode; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int i_count:16; ++ unsigned int parent_inode; ++ struct squashfs_dir_index index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header { ++ struct squashfs_base_inode_header base; ++ struct squashfs_dev_inode_header dev; ++ struct squashfs_symlink_inode_header symlink; ++ struct squashfs_reg_inode_header reg; ++ struct squashfs_lreg_inode_header lreg; ++ struct squashfs_dir_inode_header dir; ++ struct squashfs_ldir_inode_header ldir; ++ struct squashfs_ipc_inode_header ipc; ++}; ++ ++struct squashfs_dir_entry { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ int inode_number:16; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_header { ++ unsigned int count:8; ++ unsigned int start_block; ++ unsigned int inode_number; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry { ++ long long start_block; ++ unsigned int size; ++ unsigned int unused; ++} __attribute__ ((packed)); ++ ++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); ++extern int squashfs_uncompress_init(void); ++extern int squashfs_uncompress_exit(void); ++ ++/* ++ * macros to convert each packed bitfield structure from little endian to big ++ * endian and vice versa. These are needed when creating or using a filesystem ++ * on a machine with different byte ordering to the target architecture. ++ * ++ */ ++ ++#define SQUASHFS_SWAP_START \ ++ int bits;\ ++ int b_pos;\ ++ unsigned long long val;\ ++ unsigned char *s;\ ++ unsigned char *d; ++ ++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ ++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ ++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ ++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ ++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ ++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ ++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ ++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ ++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ ++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ ++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ ++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ ++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ ++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ ++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ ++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ ++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ ++ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ ++} ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header))\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dev_inode_header)); \ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_reg_inode_header));\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_lreg_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ ++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 8);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 32);\ ++} ++ ++#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) ++ ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 2);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 16)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ ++} ++ ++#define SQUASHFS_SWAP_INTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 4);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 32)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 64)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * bits / 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ bits)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++ ++struct squashfs_base_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int type:4; ++ unsigned int offset:4; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header_1 { ++ struct squashfs_base_inode_header_1 base; ++ struct squashfs_dev_inode_header_1 dev; ++ struct squashfs_symlink_inode_header_1 symlink; ++ struct squashfs_reg_inode_header_1 reg; ++ struct squashfs_dir_inode_header_1 dir; ++ struct squashfs_ipc_inode_header_1 ipc; ++}; ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ ++ SQUASHFS_SWAP((s)->guid, d, 20, 4); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header_1));\ ++ SQUASHFS_SWAP((s)->type, d, 24, 4);\ ++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_1));\ ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_1));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_1));\ ++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_1));\ ++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ ++} ++ ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++ ++struct squashfs_dir_index_2 { ++ unsigned int index:27; ++ unsigned int start_block:29; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_base_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++ unsigned int i_count:16; ++ struct squashfs_dir_index_2 index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header_2 { ++ struct squashfs_base_inode_header_2 base; ++ struct squashfs_dev_inode_header_2 dev; ++ struct squashfs_symlink_inode_header_2 symlink; ++ struct squashfs_reg_inode_header_2 reg; ++ struct squashfs_dir_inode_header_2 dir; ++ struct squashfs_ldir_inode_header_2 ldir; ++ struct squashfs_ipc_inode_header_2 ipc; ++}; ++ ++struct squashfs_dir_header_2 { ++ unsigned int count:8; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_entry_2 { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry_2 { ++ unsigned int start_block; ++ unsigned int size; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_2)); \ ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_2));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_2));\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ ++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 27);\ ++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ ++ SQUASHFS_SWAP((s)->size, d, 56, 8);\ ++} ++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) ++ ++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ ++ sizeof(int)) ++ ++#endif ++ ++#ifdef __KERNEL__ ++ ++/* ++ * macros used to swap each structure entry, taking into account ++ * bitfields and different bitfield placing conventions on differing ++ * architectures ++ */ ++ ++#include ++ ++#ifdef __BIG_ENDIAN ++ /* convert from little endian to big endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, b_pos) ++#else ++ /* convert from big endian to little endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, 64 - tbits - b_pos) ++#endif ++ ++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ ++ b_pos = pos % 8;\ ++ val = 0;\ ++ s = (unsigned char *)p + (pos / 8);\ ++ d = ((unsigned char *) &val) + 7;\ ++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ ++ *d-- = *s++;\ ++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ ++} ++ ++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); ++ ++#endif ++#endif +--- /dev/null ++++ b/include/linux/squashfs_fs_i.h +@@ -0,0 +1,45 @@ ++#ifndef SQUASHFS_FS_I ++#define SQUASHFS_FS_I ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 ++ * Phillip Lougher ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_i.h ++ */ ++ ++struct squashfs_inode_info { ++ long long start_block; ++ unsigned int offset; ++ union { ++ struct { ++ long long fragment_start_block; ++ unsigned int fragment_size; ++ unsigned int fragment_offset; ++ long long block_list_start; ++ } s1; ++ struct { ++ long long directory_index_start; ++ unsigned int directory_index_offset; ++ unsigned int directory_index_count; ++ unsigned int parent_inode; ++ } s2; ++ } u; ++ struct inode vfs_inode; ++}; ++#endif +--- /dev/null ++++ b/include/linux/squashfs_fs_sb.h +@@ -0,0 +1,79 @@ ++#ifndef SQUASHFS_FS_SB ++#define SQUASHFS_FS_SB ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 ++ * Phillip Lougher ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_sb.h ++ */ ++ ++#include ++ ++struct squashfs_cache_entry { ++ long long block; ++ int length; ++ int locked; ++ long long next_index; ++ char pending; ++ char error; ++ int waiting; ++ wait_queue_head_t wait_queue; ++ char *data; ++}; ++ ++struct squashfs_cache { ++ char *name; ++ int entries; ++ int block_size; ++ int next_blk; ++ int waiting; ++ int unused_blks; ++ int use_vmalloc; ++ spinlock_t lock; ++ wait_queue_head_t wait_queue; ++ struct squashfs_cache_entry entry[0]; ++}; ++ ++struct squashfs_sb_info { ++ struct squashfs_super_block sblk; ++ int devblksize; ++ int devblksize_log2; ++ int swap; ++ struct squashfs_cache *block_cache; ++ struct squashfs_cache *fragment_cache; ++ int next_meta_index; ++ unsigned int *uid; ++ unsigned int *guid; ++ long long *fragment_index; ++ unsigned int *fragment_index_2; ++ char *read_page; ++ struct mutex read_data_mutex; ++ struct mutex read_page_mutex; ++ struct mutex meta_index_mutex; ++ struct meta_index *meta_index; ++ z_stream stream; ++ long long *inode_lookup_table; ++ int (*read_inode)(struct inode *i, squashfs_inode_t \ ++ inode); ++ long long (*read_blocklist)(struct inode *inode, int \ ++ index, int readahead_blks, char *block_list, \ ++ unsigned short **block_p, unsigned int *bsize); ++ int (*read_fragment_index_table)(struct super_block *s); ++}; ++#endif +--- a/init/do_mounts_rd.c ++++ b/init/do_mounts_rd.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -37,6 +38,7 @@ static int __init crd_load(int in_fd, in + * numbers could not be found. + * + * We currently check for the following magic numbers: ++ * squashfs + * minix + * ext2 + * romfs +@@ -51,6 +53,7 @@ identify_ramdisk_image(int fd, int start + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -62,6 +65,7 @@ identify_ramdisk_image(int fd, int start + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + memset(buf, 0xe5, size); + + /* +@@ -99,6 +103,18 @@ identify_ramdisk_image(int fd, int start + goto done; + } + ++ /* squashfs is at block zero too */ ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) { ++ printk(KERN_NOTICE ++ "RAMDISK: squashfs filesystem found at block %d\n", ++ start_block); ++ if (squashfsb->s_major < 3) ++ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ else ++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ goto done; ++ } ++ + /* + * Read block 1 to test for minix and ext2 superblock + */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/stack-unwind b/src/patches/suse-2.6.27.31/patches.suse/stack-unwind new file mode 100644 index 000000000..4e8f82868 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/stack-unwind @@ -0,0 +1,2003 @@ +Subject: DWARF2 EH-frame based stack unwinding +From: jbeulich@novell.com +Patch-mainline: no + +--- + Makefile | 5 + arch/x86/Kconfig | 2 + arch/x86/Makefile | 2 + arch/x86/kernel/entry_32.S | 32 + arch/x86/kernel/entry_64.S | 33 + arch/x86/kernel/traps_32.c | 82 ++ + arch/x86/kernel/traps_64.c | 85 ++ + include/asm-generic/vmlinux.lds.h | 22 + include/asm-x86/unwind.h | 159 ++++ + include/linux/unwind.h | 63 + + kernel/Makefile | 1 + kernel/unwind.c | 1303 ++++++++++++++++++++++++++++++++++++++ + lib/Kconfig.debug | 18 + 13 files changed, 1804 insertions(+), 3 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -553,6 +553,11 @@ else + KBUILD_CFLAGS += -fomit-frame-pointer + endif + ++ifdef CONFIG_UNWIND_INFO ++KBUILD_CFLAGS += -fasynchronous-unwind-tables ++LDFLAGS_vmlinux += --eh-frame-hdr ++endif ++ + ifdef CONFIG_DEBUG_INFO + KBUILD_CFLAGS += -g + KBUILD_AFLAGS += -gdwarf-2 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -373,7 +373,7 @@ config X86_RDC321X + config SCHED_NO_NO_OMIT_FRAME_POINTER + def_bool y + prompt "Single-depth WCHAN output" +- depends on X86_32 ++ depends on X86_32 && !STACK_UNWIND + help + Calculate simpler /proc//wchan values. If this option + is disabled then wchan values will recurse back to the +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -98,7 +98,9 @@ KBUILD_CFLAGS += -pipe + # Workaround for a gcc prelease that unfortunately was shipped in a suse release + KBUILD_CFLAGS += -Wno-sign-compare + # ++ifneq ($(CONFIG_UNWIND_INFO),y) + KBUILD_CFLAGS += -fno-asynchronous-unwind-tables ++endif + # prevent gcc from generating any FP code by mistake + KBUILD_CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,) + +--- a/arch/x86/kernel/entry_32.S ++++ b/arch/x86/kernel/entry_32.S +@@ -1067,6 +1067,38 @@ ENTRY(spurious_interrupt_bug) + CFI_ENDPROC + END(spurious_interrupt_bug) + ++#ifdef CONFIG_STACK_UNWIND ++ENTRY(arch_unwind_init_running) ++ CFI_STARTPROC ++ movl 4(%esp), %edx ++ movl (%esp), %ecx ++ leal 4(%esp), %eax ++ movl %ebx, PT_EBX(%edx) ++ xorl %ebx, %ebx ++ movl %ebx, PT_ECX(%edx) ++ movl %ebx, PT_EDX(%edx) ++ movl %esi, PT_ESI(%edx) ++ movl %edi, PT_EDI(%edx) ++ movl %ebp, PT_EBP(%edx) ++ movl %ebx, PT_EAX(%edx) ++ movl $__USER_DS, PT_DS(%edx) ++ movl $__USER_DS, PT_ES(%edx) ++ movl $__KERNEL_PERCPU, PT_FS(%edx) ++ movl %ebx, PT_ORIG_EAX(%edx) ++ movl %ecx, PT_EIP(%edx) ++ movl 12(%esp), %ecx ++ movl $__KERNEL_CS, PT_CS(%edx) ++ movl %ebx, PT_EFLAGS(%edx) ++ movl %eax, PT_OLDESP(%edx) ++ movl 8(%esp), %eax ++ movl %ecx, 8(%esp) ++ movl PT_EBX(%edx), %ebx ++ movl $__KERNEL_DS, PT_OLDSS(%edx) ++ jmpl *%eax ++ CFI_ENDPROC ++ENDPROC(arch_unwind_init_running) ++#endif ++ + ENTRY(kernel_thread_helper) + pushl $0 # fake return address for unwinder + CFI_STARTPROC +--- a/arch/x86/kernel/entry_64.S ++++ b/arch/x86/kernel/entry_64.S +@@ -1368,6 +1368,39 @@ KPROBE_ENTRY(ignore_sysret) + CFI_ENDPROC + ENDPROC(ignore_sysret) + ++#ifdef CONFIG_STACK_UNWIND ++ENTRY(arch_unwind_init_running) ++ CFI_STARTPROC ++ movq %r15, R15(%rdi) ++ movq %r14, R14(%rdi) ++ xchgq %rsi, %rdx ++ movq %r13, R13(%rdi) ++ movq %r12, R12(%rdi) ++ xorl %eax, %eax ++ movq %rbp, RBP(%rdi) ++ movq %rbx, RBX(%rdi) ++ movq (%rsp), %rcx ++ movq %rax, R11(%rdi) ++ movq %rax, R10(%rdi) ++ movq %rax, R9(%rdi) ++ movq %rax, R8(%rdi) ++ movq %rax, RAX(%rdi) ++ movq %rax, RCX(%rdi) ++ movq %rax, RDX(%rdi) ++ movq %rax, RSI(%rdi) ++ movq %rax, RDI(%rdi) ++ movq %rax, ORIG_RAX(%rdi) ++ movq %rcx, RIP(%rdi) ++ leaq 8(%rsp), %rcx ++ movq $__KERNEL_CS, CS(%rdi) ++ movq %rax, EFLAGS(%rdi) ++ movq %rcx, RSP(%rdi) ++ movq $__KERNEL_DS, SS(%rdi) ++ jmpq *%rdx ++ CFI_ENDPROC ++ENDPROC(arch_unwind_init_running) ++#endif ++ + #ifdef CONFIG_XEN + ENTRY(xen_hypervisor_callback) + zeroentry xen_do_hypervisor_callback +--- a/arch/x86/kernel/traps_32.c ++++ b/arch/x86/kernel/traps_32.c +@@ -85,6 +85,11 @@ gate_desc idt_table[256] + int panic_on_unrecovered_nmi; + int kstack_depth_to_print = 24; + static unsigned int code_bytes = 64; ++#ifdef CONFIG_STACK_UNWIND ++static int call_trace = 1; ++#else ++#define call_trace (-1) ++#endif + static int ignore_nmis; + static int die_counter; + +@@ -155,6 +160,33 @@ print_context_stack(struct thread_info * + return bp; + } + ++struct ops_and_data { ++ const struct stacktrace_ops *ops; ++ void *data; ++}; ++ ++static asmlinkage int ++dump_trace_unwind(struct unwind_frame_info *info, void *data) ++{ ++ struct ops_and_data *oad = (struct ops_and_data *)data; ++ int n = 0; ++ unsigned long sp = UNW_SP(info); ++ ++ if (arch_unw_user_mode(info)) ++ return -1; ++ while (unwind(info) == 0 && UNW_PC(info)) { ++ n++; ++ oad->ops->address(oad->data, UNW_PC(info), 1); ++ if (arch_unw_user_mode(info)) ++ break; ++ if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1)) ++ && sp > UNW_SP(info)) ++ break; ++ sp = UNW_SP(info); ++ } ++ return n; ++} ++ + void dump_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, unsigned long bp, + const struct stacktrace_ops *ops, void *data) +@@ -162,6 +194,40 @@ void dump_trace(struct task_struct *task + if (!task) + task = current; + ++ if (call_trace >= 0) { ++ int unw_ret = 0; ++ struct unwind_frame_info info; ++ struct ops_and_data oad = { .ops = ops, .data = data }; ++ ++ if (regs) { ++ if (unwind_init_frame_info(&info, task, regs) == 0) ++ unw_ret = dump_trace_unwind(&info, &oad); ++ } else if (task == current) ++ unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); ++ else { ++ if (unwind_init_blocked(&info, task) == 0) ++ unw_ret = dump_trace_unwind(&info, &oad); ++ } ++ if (unw_ret > 0) { ++ if (call_trace == 1 && !arch_unw_user_mode(&info)) { ++ ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", ++ UNW_PC(&info)); ++ if (UNW_SP(&info) >= PAGE_OFFSET) { ++ ops->warning(data, "Leftover inexact backtrace:\n"); ++ stack = (void *)UNW_SP(&info); ++ if (!stack) ++ return; ++ bp = UNW_FP(&info); ++ } else ++ ops->warning(data, "Full inexact backtrace again:\n"); ++ } else if (call_trace >= 1) ++ return; ++ else ++ ops->warning(data, "Full inexact backtrace again:\n"); ++ } else ++ ops->warning(data, "Inexact backtrace:\n"); ++ } ++ + if (!stack) { + unsigned long dummy; + stack = &dummy; +@@ -1302,3 +1368,19 @@ static int __init code_bytes_setup(char + return 1; + } + __setup("code_bytes=", code_bytes_setup); ++ ++#ifdef CONFIG_STACK_UNWIND ++static int __init call_trace_setup(char *s) ++{ ++ if (strcmp(s, "old") == 0) ++ call_trace = -1; ++ else if (strcmp(s, "both") == 0) ++ call_trace = 0; ++ else if (strcmp(s, "newfallback") == 0) ++ call_trace = 1; ++ else if (strcmp(s, "new") == 2) ++ call_trace = 2; ++ return 1; ++} ++__setup("call_trace=", call_trace_setup); ++#endif +--- a/arch/x86/kernel/traps_64.c ++++ b/arch/x86/kernel/traps_64.c +@@ -58,6 +58,11 @@ + int panic_on_unrecovered_nmi; + int kstack_depth_to_print = 12; + static unsigned int code_bytes = 64; ++#ifdef CONFIG_STACK_UNWIND ++static int call_trace = 1; ++#else ++#define call_trace (-1) ++#endif + static int ignore_nmis; + static int die_counter; + +@@ -162,6 +167,32 @@ static unsigned long *in_exception_stack + return NULL; + } + ++struct ops_and_data { ++ const struct stacktrace_ops *ops; ++ void *data; ++}; ++ ++static int dump_trace_unwind(struct unwind_frame_info *info, void *context) ++{ ++ struct ops_and_data *oad = (struct ops_and_data *)context; ++ int n = 0; ++ unsigned long sp = UNW_SP(info); ++ ++ if (arch_unw_user_mode(info)) ++ return -1; ++ while (unwind(info) == 0 && UNW_PC(info)) { ++ n++; ++ oad->ops->address(oad->data, UNW_PC(info), 1); ++ if (arch_unw_user_mode(info)) ++ break; ++ if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1)) ++ && sp > UNW_SP(info)) ++ break; ++ sp = UNW_SP(info); ++ } ++ return n; ++} ++ + /* + * x86-64 can have up to three kernel stacks: + * process stack +@@ -226,6 +257,42 @@ void dump_trace(struct task_struct *task + if (!task) + task = current; + ++ if (call_trace >= 0) { ++ int unw_ret = 0; ++ struct unwind_frame_info info; ++ struct ops_and_data oad = { .ops = ops, .data = data }; ++ ++ if (regs) { ++ if (unwind_init_frame_info(&info, task, regs) == 0) ++ unw_ret = dump_trace_unwind(&info, &oad); ++ } else if (task == current) ++ unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); ++ else { ++ if (unwind_init_blocked(&info, task) == 0) ++ unw_ret = dump_trace_unwind(&info, &oad); ++ } ++ if (unw_ret > 0) { ++ if (call_trace == 1 && !arch_unw_user_mode(&info)) { ++ ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", ++ UNW_PC(&info)); ++ if ((long)UNW_SP(&info) < 0) { ++ ops->warning(data, "Leftover inexact backtrace:\n"); ++ stack = (unsigned long *)UNW_SP(&info); ++ if (!stack) { ++ put_cpu(); ++ return; ++ } ++ } else ++ ops->warning(data, "Full inexact backtrace again:\n"); ++ } else if (call_trace >= 1) { ++ put_cpu(); ++ return; ++ } else ++ ops->warning(data, "Full inexact backtrace again:\n"); ++ } else ++ ops->warning(data, "Inexact backtrace:\n"); ++ } ++ + if (!stack) { + unsigned long dummy; + stack = &dummy; +@@ -1214,3 +1281,21 @@ static int __init code_bytes_setup(char + return 1; + } + __setup("code_bytes=", code_bytes_setup); ++ ++#ifdef CONFIG_STACK_UNWIND ++static int __init call_trace_setup(char *s) ++{ ++ if (!s) ++ return -EINVAL; ++ if (strcmp(s, "old") == 0) ++ call_trace = -1; ++ else if (strcmp(s, "both") == 0) ++ call_trace = 0; ++ else if (strcmp(s, "newfallback") == 0) ++ call_trace = 1; ++ else if (strcmp(s, "new") == 0) ++ call_trace = 2; ++ return 0; ++} ++early_param("call_trace", call_trace_setup); ++#endif +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -196,6 +196,8 @@ + MEM_KEEP(exit.rodata) \ + } \ + \ ++ EH_FRAME \ ++ \ + /* Built-in module parameters. */ \ + __param : AT(ADDR(__param) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start___param) = .; \ +@@ -299,6 +301,26 @@ + CPU_DISCARD(exit.text) \ + MEM_DISCARD(exit.text) + ++#ifdef CONFIG_STACK_UNWIND ++#define EH_FRAME \ ++ /* Unwind data binary search table */ \ ++ . = ALIGN(8); \ ++ .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start_unwind_hdr) = .; \ ++ *(.eh_frame_hdr) \ ++ VMLINUX_SYMBOL(__end_unwind_hdr) = .; \ ++ } \ ++ /* Unwind data */ \ ++ . = ALIGN(8); \ ++ .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) { \ ++ VMLINUX_SYMBOL(__start_unwind) = .; \ ++ *(.eh_frame) \ ++ VMLINUX_SYMBOL(__end_unwind) = .; \ ++ } ++#else ++#define EH_FRAME ++#endif ++ + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to + the beginning of the section so we begin them at 0. */ +--- a/include/asm-x86/unwind.h ++++ b/include/asm-x86/unwind.h +@@ -1,6 +1,163 @@ + #ifndef _ASM_X86_UNWIND_H + #define _ASM_X86_UNWIND_H + ++/* ++ * Copyright (C) 2002-2007 Novell, Inc. ++ * Jan Beulich ++ * This code is released under version 2 of the GNU GPL. ++ */ ++ ++#ifdef CONFIG_STACK_UNWIND ++ ++#include ++#include ++#include ++ ++struct unwind_frame_info ++{ ++ struct pt_regs regs; ++ struct task_struct *task; ++ unsigned call_frame:1; ++}; ++ ++#ifdef CONFIG_X86_64 ++ ++#include ++ ++#define UNW_PC(frame) (frame)->regs.ip ++#define UNW_SP(frame) (frame)->regs.sp ++#ifdef CONFIG_FRAME_POINTER ++#define UNW_FP(frame) (frame)->regs.bp ++#define FRAME_RETADDR_OFFSET 8 ++#define FRAME_LINK_OFFSET 0 ++#define STACK_BOTTOM(tsk) (((tsk)->thread.sp0 - 1) & ~(THREAD_SIZE - 1)) ++#define TSK_STACK_TOP(tsk) ((tsk)->thread.sp0) ++#endif ++/* Might need to account for the special exception and interrupt handling ++ stacks here, since normally ++ EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER, ++ but the construct is needed only for getting across the stack switch to ++ the interrupt stack - thus considering the IRQ stack itself is unnecessary, ++ and the overhead of comparing against all exception handling stacks seems ++ not desirable. */ ++#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) ++ ++#define UNW_REGISTER_INFO \ ++ PTREGS_INFO(ax), \ ++ PTREGS_INFO(dx), \ ++ PTREGS_INFO(cx), \ ++ PTREGS_INFO(bx), \ ++ PTREGS_INFO(si), \ ++ PTREGS_INFO(di), \ ++ PTREGS_INFO(bp), \ ++ PTREGS_INFO(sp), \ ++ PTREGS_INFO(r8), \ ++ PTREGS_INFO(r9), \ ++ PTREGS_INFO(r10), \ ++ PTREGS_INFO(r11), \ ++ PTREGS_INFO(r12), \ ++ PTREGS_INFO(r13), \ ++ PTREGS_INFO(r14), \ ++ PTREGS_INFO(r15), \ ++ PTREGS_INFO(ip) ++ ++#else ++ ++#include ++ ++#define UNW_PC(frame) (frame)->regs.ip ++#define UNW_SP(frame) (frame)->regs.sp ++#ifdef CONFIG_FRAME_POINTER ++#define UNW_FP(frame) (frame)->regs.bp ++#define FRAME_RETADDR_OFFSET 4 ++#define FRAME_LINK_OFFSET 0 ++#define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.sp0) ++#define TSK_STACK_TOP(tsk) ((tsk)->thread.sp0) ++#else ++#define UNW_FP(frame) ((void)(frame), 0UL) ++#endif ++#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) ++ ++#define UNW_REGISTER_INFO \ ++ PTREGS_INFO(ax), \ ++ PTREGS_INFO(cx), \ ++ PTREGS_INFO(dx), \ ++ PTREGS_INFO(bx), \ ++ PTREGS_INFO(sp), \ ++ PTREGS_INFO(bp), \ ++ PTREGS_INFO(si), \ ++ PTREGS_INFO(di), \ ++ PTREGS_INFO(ip) ++ ++#endif ++ ++#define UNW_DEFAULT_RA(raItem, dataAlign) \ ++ ((raItem).where == Memory && \ ++ !((raItem).value * (dataAlign) + sizeof(void *))) ++ ++static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, ++ /*const*/ struct pt_regs *regs) ++{ ++#ifdef CONFIG_X86_64 ++ info->regs = *regs; ++#else ++ if (user_mode_vm(regs)) ++ info->regs = *regs; ++ else { ++ memcpy(&info->regs, regs, offsetof(struct pt_regs, sp)); ++ info->regs.sp = (unsigned long)®s->sp; ++ info->regs.ss = __KERNEL_DS; ++ } ++#endif ++} ++ ++static inline void arch_unw_init_blocked(struct unwind_frame_info *info) ++{ ++#ifdef CONFIG_X86_64 ++ extern const char thread_return[]; ++ ++ memset(&info->regs, 0, sizeof(info->regs)); ++ info->regs.ip = (unsigned long)thread_return; ++ info->regs.cs = __KERNEL_CS; ++ probe_kernel_address(info->task->thread.sp, info->regs.bp); ++ info->regs.sp = info->task->thread.sp; ++ info->regs.ss = __KERNEL_DS; ++#else ++ memset(&info->regs, 0, sizeof(info->regs)); ++ info->regs.ip = info->task->thread.ip; ++ info->regs.cs = __KERNEL_CS; ++ probe_kernel_address(info->task->thread.sp, info->regs.bp); ++ info->regs.sp = info->task->thread.sp; ++ info->regs.ss = __KERNEL_DS; ++ info->regs.ds = __USER_DS; ++ info->regs.es = __USER_DS; ++#endif ++} ++ ++extern asmlinkage int ++arch_unwind_init_running(struct unwind_frame_info *, ++ asmlinkage int (*callback)(struct unwind_frame_info *, ++ void *arg), ++ void *arg); ++ ++static inline int arch_unw_user_mode(/*const*/ struct unwind_frame_info *info) ++{ ++#ifdef CONFIG_X86_64 ++ return user_mode(&info->regs) ++ || (long)info->regs.ip >= 0 ++ || (info->regs.ip >= VSYSCALL_START && info->regs.ip < VSYSCALL_END) ++ || (long)info->regs.sp >= 0; ++#else ++ return user_mode_vm(&info->regs) ++ || info->regs.ip < PAGE_OFFSET ++ || (info->regs.ip >= __fix_to_virt(FIX_VDSO) ++ && info->regs.ip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE) ++ || info->regs.sp < PAGE_OFFSET; ++#endif ++} ++ ++#else ++ + #define UNW_PC(frame) ((void)(frame), 0UL) + #define UNW_SP(frame) ((void)(frame), 0UL) + #define UNW_FP(frame) ((void)(frame), 0UL) +@@ -10,4 +167,6 @@ static inline int arch_unw_user_mode(con + return 0; + } + ++#endif ++ + #endif /* _ASM_X86_UNWIND_H */ +--- a/include/linux/unwind.h ++++ b/include/linux/unwind.h +@@ -14,6 +14,63 @@ + + struct module; + ++#ifdef CONFIG_STACK_UNWIND ++ ++#include ++ ++#ifndef ARCH_UNWIND_SECTION_NAME ++#define ARCH_UNWIND_SECTION_NAME ".eh_frame" ++#endif ++ ++/* ++ * Initialize unwind support. ++ */ ++extern void unwind_init(void); ++extern void unwind_setup(void); ++ ++#ifdef CONFIG_MODULES ++ ++extern void *unwind_add_table(struct module *, ++ const void *table_start, ++ unsigned long table_size); ++ ++extern void unwind_remove_table(void *handle, int init_only); ++ ++#endif ++ ++extern int unwind_init_frame_info(struct unwind_frame_info *, ++ struct task_struct *, ++ /*const*/ struct pt_regs *); ++ ++/* ++ * Prepare to unwind a blocked task. ++ */ ++extern int unwind_init_blocked(struct unwind_frame_info *, ++ struct task_struct *); ++ ++/* ++ * Prepare to unwind the currently running thread. ++ */ ++extern int unwind_init_running(struct unwind_frame_info *, ++ asmlinkage int (*callback)(struct unwind_frame_info *, ++ void *arg), ++ void *arg); ++ ++/* ++ * Unwind to previous to frame. Returns 0 if successful, negative ++ * number in case of an error. ++ */ ++extern int unwind(struct unwind_frame_info *); ++ ++/* ++ * Unwind until the return pointer is in user-land (or until an error ++ * occurs). Returns 0 if successful, negative number in case of ++ * error. ++ */ ++extern int unwind_to_user(struct unwind_frame_info *); ++ ++#else ++ + struct unwind_frame_info {}; + + static inline void unwind_init(void) {} +@@ -28,12 +85,12 @@ static inline void *unwind_add_table(str + return NULL; + } + ++#endif ++ + static inline void unwind_remove_table(void *handle, int init_only) + { + } + +-#endif +- + static inline int unwind_init_frame_info(struct unwind_frame_info *info, + struct task_struct *tsk, + const struct pt_regs *regs) +@@ -65,4 +122,6 @@ static inline int unwind_to_user(struct + return -ENOSYS; + } + ++#endif ++ + #endif /* _LINUX_UNWIND_H */ +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -46,6 +46,7 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock. + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += module.o + obj-$(CONFIG_KALLSYMS) += kallsyms.o ++obj-$(CONFIG_STACK_UNWIND) += unwind.o + obj-$(CONFIG_PM) += power/ + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +--- /dev/null ++++ b/kernel/unwind.c +@@ -0,0 +1,1303 @@ ++/* ++ * Copyright (C) 2002-2006 Novell, Inc. ++ * Jan Beulich ++ * This code is released under version 2 of the GNU GPL. ++ * ++ * A simple API for unwinding kernel stacks. This is used for ++ * debugging and error reporting purposes. The kernel doesn't need ++ * full-blown stack unwinding with all the bells and whistles, so there ++ * is not much point in implementing the full Dwarf2 unwind API. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern const char __start_unwind[], __end_unwind[]; ++extern const u8 __start_unwind_hdr[], __end_unwind_hdr[]; ++ ++#define MAX_STACK_DEPTH 8 ++ ++#define EXTRA_INFO(f) { \ ++ BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \ ++ % FIELD_SIZEOF(struct unwind_frame_info, f)) \ ++ + offsetof(struct unwind_frame_info, f) \ ++ / FIELD_SIZEOF(struct unwind_frame_info, f), \ ++ FIELD_SIZEOF(struct unwind_frame_info, f) \ ++ } ++#define PTREGS_INFO(f) EXTRA_INFO(regs.f) ++ ++static const struct { ++ unsigned offs:BITS_PER_LONG / 2; ++ unsigned width:BITS_PER_LONG / 2; ++} reg_info[] = { ++ UNW_REGISTER_INFO ++}; ++ ++#undef PTREGS_INFO ++#undef EXTRA_INFO ++ ++#ifndef REG_INVALID ++#define REG_INVALID(r) (reg_info[r].width == 0) ++#endif ++ ++#define DW_CFA_nop 0x00 ++#define DW_CFA_set_loc 0x01 ++#define DW_CFA_advance_loc1 0x02 ++#define DW_CFA_advance_loc2 0x03 ++#define DW_CFA_advance_loc4 0x04 ++#define DW_CFA_offset_extended 0x05 ++#define DW_CFA_restore_extended 0x06 ++#define DW_CFA_undefined 0x07 ++#define DW_CFA_same_value 0x08 ++#define DW_CFA_register 0x09 ++#define DW_CFA_remember_state 0x0a ++#define DW_CFA_restore_state 0x0b ++#define DW_CFA_def_cfa 0x0c ++#define DW_CFA_def_cfa_register 0x0d ++#define DW_CFA_def_cfa_offset 0x0e ++#define DW_CFA_def_cfa_expression 0x0f ++#define DW_CFA_expression 0x10 ++#define DW_CFA_offset_extended_sf 0x11 ++#define DW_CFA_def_cfa_sf 0x12 ++#define DW_CFA_def_cfa_offset_sf 0x13 ++#define DW_CFA_val_offset 0x14 ++#define DW_CFA_val_offset_sf 0x15 ++#define DW_CFA_val_expression 0x16 ++#define DW_CFA_lo_user 0x1c ++#define DW_CFA_GNU_window_save 0x2d ++#define DW_CFA_GNU_args_size 0x2e ++#define DW_CFA_GNU_negative_offset_extended 0x2f ++#define DW_CFA_hi_user 0x3f ++ ++#define DW_EH_PE_FORM 0x07 ++#define DW_EH_PE_native 0x00 ++#define DW_EH_PE_leb128 0x01 ++#define DW_EH_PE_data2 0x02 ++#define DW_EH_PE_data4 0x03 ++#define DW_EH_PE_data8 0x04 ++#define DW_EH_PE_signed 0x08 ++#define DW_EH_PE_ADJUST 0x70 ++#define DW_EH_PE_abs 0x00 ++#define DW_EH_PE_pcrel 0x10 ++#define DW_EH_PE_textrel 0x20 ++#define DW_EH_PE_datarel 0x30 ++#define DW_EH_PE_funcrel 0x40 ++#define DW_EH_PE_aligned 0x50 ++#define DW_EH_PE_indirect 0x80 ++#define DW_EH_PE_omit 0xff ++ ++typedef unsigned long uleb128_t; ++typedef signed long sleb128_t; ++#define sleb128abs __builtin_labs ++ ++static struct unwind_table { ++ struct { ++ unsigned long pc; ++ unsigned long range; ++ } core, init; ++ const void *address; ++ unsigned long size; ++ const unsigned char *header; ++ unsigned long hdrsz; ++ struct unwind_table *link; ++ const char *name; ++} root_table; ++ ++struct unwind_item { ++ enum item_location { ++ Nowhere, ++ Memory, ++ Register, ++ Value ++ } where; ++ uleb128_t value; ++}; ++ ++struct unwind_state { ++ uleb128_t loc, org; ++ const u8 *cieStart, *cieEnd; ++ uleb128_t codeAlign; ++ sleb128_t dataAlign; ++ struct cfa { ++ uleb128_t reg, offs; ++ } cfa; ++ struct unwind_item regs[ARRAY_SIZE(reg_info)]; ++ unsigned stackDepth:8; ++ unsigned version:8; ++ const u8 *label; ++ const u8 *stack[MAX_STACK_DEPTH]; ++}; ++ ++static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; ++ ++static unsigned unwind_debug; ++static int __init unwind_debug_setup(char *s) ++{ ++ unwind_debug = simple_strtoul(s, NULL, 0); ++ return 1; ++} ++__setup("unwind_debug=", unwind_debug_setup); ++#define dprintk(lvl, fmt, args...) \ ++ ((void)(lvl > unwind_debug \ ++ || printk(KERN_DEBUG "unwind: " fmt "\n", ##args))) ++ ++static struct unwind_table *find_table(unsigned long pc) ++{ ++ struct unwind_table *table; ++ ++ for (table = &root_table; table; table = table->link) ++ if ((pc >= table->core.pc ++ && pc < table->core.pc + table->core.range) ++ || (pc >= table->init.pc ++ && pc < table->init.pc + table->init.range)) ++ break; ++ ++ return table; ++} ++ ++static unsigned long read_pointer(const u8 **pLoc, ++ const void *end, ++ signed ptrType, ++ unsigned long text_base, ++ unsigned long data_base); ++ ++static void init_unwind_table(struct unwind_table *table, ++ const char *name, ++ const void *core_start, ++ unsigned long core_size, ++ const void *init_start, ++ unsigned long init_size, ++ const void *table_start, ++ unsigned long table_size, ++ const u8 *header_start, ++ unsigned long header_size) ++{ ++ const u8 *ptr = header_start + 4; ++ const u8 *end = header_start + header_size; ++ ++ table->core.pc = (unsigned long)core_start; ++ table->core.range = core_size; ++ table->init.pc = (unsigned long)init_start; ++ table->init.range = init_size; ++ table->address = table_start; ++ table->size = table_size; ++ /* See if the linker provided table looks valid. */ ++ if (header_size <= 4 ++ || header_start[0] != 1 ++ || (void *)read_pointer(&ptr, end, header_start[1], 0, 0) ++ != table_start ++ || !read_pointer(&ptr, end, header_start[2], 0, 0) ++ || !read_pointer(&ptr, end, header_start[3], 0, ++ (unsigned long)header_start) ++ || !read_pointer(&ptr, end, header_start[3], 0, ++ (unsigned long)header_start)) ++ header_start = NULL; ++ table->hdrsz = header_size; ++ smp_wmb(); ++ table->header = header_start; ++ table->link = NULL; ++ table->name = name; ++} ++ ++void __init unwind_init(void) ++{ ++ init_unwind_table(&root_table, "kernel", ++ _text, _end - _text, ++ NULL, 0, ++ __start_unwind, __end_unwind - __start_unwind, ++ __start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr); ++} ++ ++static const u32 bad_cie, not_fde; ++static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *); ++static signed fde_pointer_type(const u32 *cie); ++ ++struct eh_frame_hdr_table_entry { ++ unsigned long start, fde; ++}; ++ ++static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2) ++{ ++ const struct eh_frame_hdr_table_entry *e1 = p1; ++ const struct eh_frame_hdr_table_entry *e2 = p2; ++ ++ return (e1->start > e2->start) - (e1->start < e2->start); ++} ++ ++static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size) ++{ ++ struct eh_frame_hdr_table_entry *e1 = p1; ++ struct eh_frame_hdr_table_entry *e2 = p2; ++ unsigned long v; ++ ++ v = e1->start; ++ e1->start = e2->start; ++ e2->start = v; ++ v = e1->fde; ++ e1->fde = e2->fde; ++ e2->fde = v; ++} ++ ++static void __init setup_unwind_table(struct unwind_table *table, ++ void *(*alloc)(unsigned long)) ++{ ++ const u8 *ptr; ++ unsigned long tableSize = table->size, hdrSize; ++ unsigned n; ++ const u32 *fde; ++ struct { ++ u8 version; ++ u8 eh_frame_ptr_enc; ++ u8 fde_count_enc; ++ u8 table_enc; ++ unsigned long eh_frame_ptr; ++ unsigned int fde_count; ++ struct eh_frame_hdr_table_entry table[]; ++ } __attribute__((__packed__)) *header; ++ ++ if (table->header) ++ return; ++ ++ if (table->hdrsz) ++ printk(KERN_WARNING ".eh_frame_hdr for '%s' present but unusable\n", ++ table->name); ++ ++ if (tableSize & (sizeof(*fde) - 1)) ++ return; ++ ++ for (fde = table->address, n = 0; ++ tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; ++ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { ++ const u32 *cie = cie_for_fde(fde, table); ++ signed ptrType; ++ ++ if (cie == ¬_fde) ++ continue; ++ if (cie == NULL ++ || cie == &bad_cie ++ || (ptrType = fde_pointer_type(cie)) < 0) ++ return; ++ ptr = (const u8 *)(fde + 2); ++ if (!read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType, 0, 0)) ++ return; ++ ++n; ++ } ++ ++ if (tableSize || !n) ++ return; ++ ++ hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) ++ + 2 * n * sizeof(unsigned long); ++ dprintk(2, "Binary lookup table size for %s: %lu bytes", table->name, hdrSize); ++ header = alloc(hdrSize); ++ if (!header) ++ return; ++ header->version = 1; ++ header->eh_frame_ptr_enc = DW_EH_PE_abs|DW_EH_PE_native; ++ header->fde_count_enc = DW_EH_PE_abs|DW_EH_PE_data4; ++ header->table_enc = DW_EH_PE_abs|DW_EH_PE_native; ++ put_unaligned((unsigned long)table->address, &header->eh_frame_ptr); ++ BUILD_BUG_ON(offsetof(typeof(*header), fde_count) ++ % __alignof(typeof(header->fde_count))); ++ header->fde_count = n; ++ ++ BUILD_BUG_ON(offsetof(typeof(*header), table) ++ % __alignof(typeof(*header->table))); ++ for (fde = table->address, tableSize = table->size, n = 0; ++ tableSize; ++ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) { ++ const u32 *cie = fde + 1 - fde[1] / sizeof(*fde); ++ ++ if (!fde[1]) ++ continue; /* this is a CIE */ ++ ptr = (const u8 *)(fde + 2); ++ header->table[n].start = read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ fde_pointer_type(cie), 0, 0); ++ header->table[n].fde = (unsigned long)fde; ++ ++n; ++ } ++ WARN_ON(n != header->fde_count); ++ ++ sort(header->table, ++ n, ++ sizeof(*header->table), ++ cmp_eh_frame_hdr_table_entries, ++ swap_eh_frame_hdr_table_entries); ++ ++ table->hdrsz = hdrSize; ++ smp_wmb(); ++ table->header = (const void *)header; ++} ++ ++static void *__init balloc(unsigned long sz) ++{ ++ return __alloc_bootmem_nopanic(sz, ++ sizeof(unsigned int), ++ __pa(MAX_DMA_ADDRESS)); ++} ++ ++void __init unwind_setup(void) ++{ ++ setup_unwind_table(&root_table, balloc); ++} ++ ++#ifdef CONFIG_MODULES ++ ++static struct unwind_table *last_table; ++ ++/* Must be called with module_mutex held. */ ++void *unwind_add_table(struct module *module, ++ const void *table_start, ++ unsigned long table_size) ++{ ++ struct unwind_table *table; ++ ++ if (table_size <= 0) ++ return NULL; ++ ++ table = kmalloc(sizeof(*table), GFP_KERNEL); ++ if (!table) ++ return NULL; ++ ++ init_unwind_table(table, module->name, ++ module->module_core, module->core_size, ++ module->module_init, module->init_size, ++ table_start, table_size, ++ NULL, 0); ++ ++ if (last_table) ++ last_table->link = table; ++ else ++ root_table.link = table; ++ last_table = table; ++ ++ return table; ++} ++ ++struct unlink_table_info ++{ ++ struct unwind_table *table; ++ int init_only; ++}; ++ ++static int unlink_table(void *arg) ++{ ++ struct unlink_table_info *info = arg; ++ struct unwind_table *table = info->table, *prev; ++ ++ for (prev = &root_table; prev->link && prev->link != table; prev = prev->link) ++ ; ++ ++ if (prev->link) { ++ if (info->init_only) { ++ table->init.pc = 0; ++ table->init.range = 0; ++ info->table = NULL; ++ } else { ++ prev->link = table->link; ++ if (!prev->link) ++ last_table = prev; ++ } ++ } else ++ info->table = NULL; ++ ++ return 0; ++} ++ ++/* Must be called with module_mutex held. */ ++void unwind_remove_table(void *handle, int init_only) ++{ ++ struct unwind_table *table = handle; ++ struct unlink_table_info info; ++ ++ if (!table || table == &root_table) ++ return; ++ ++ if (init_only && table == last_table) { ++ table->init.pc = 0; ++ table->init.range = 0; ++ return; ++ } ++ ++ info.table = table; ++ info.init_only = init_only; ++ stop_machine(unlink_table, &info, NULL); ++ ++ if (info.table) ++ kfree(table); ++} ++ ++#endif /* CONFIG_MODULES */ ++ ++static uleb128_t get_uleb128(const u8 **pcur, const u8 *end) ++{ ++ const u8 *cur = *pcur; ++ uleb128_t value; ++ unsigned shift; ++ ++ for (shift = 0, value = 0; cur < end; shift += 7) { ++ if (shift + 7 > 8 * sizeof(value) ++ && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { ++ cur = end + 1; ++ break; ++ } ++ value |= (uleb128_t)(*cur & 0x7f) << shift; ++ if (!(*cur++ & 0x80)) ++ break; ++ } ++ *pcur = cur; ++ ++ return value; ++} ++ ++static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) ++{ ++ const u8 *cur = *pcur; ++ sleb128_t value; ++ unsigned shift; ++ ++ for (shift = 0, value = 0; cur < end; shift += 7) { ++ if (shift + 7 > 8 * sizeof(value) ++ && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { ++ cur = end + 1; ++ break; ++ } ++ value |= (sleb128_t)(*cur & 0x7f) << shift; ++ if (!(*cur & 0x80)) { ++ value |= -(*cur++ & 0x40) << shift; ++ break; ++ } ++ } ++ *pcur = cur; ++ ++ return value; ++} ++ ++static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table) ++{ ++ const u32 *cie; ++ ++ if (!*fde || (*fde & (sizeof(*fde) - 1))) ++ return &bad_cie; ++ if (!fde[1]) ++ return ¬_fde; /* this is a CIE */ ++ if ((fde[1] & (sizeof(*fde) - 1)) ++ || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) ++ return NULL; /* this is not a valid FDE */ ++ cie = fde + 1 - fde[1] / sizeof(*fde); ++ if (*cie <= sizeof(*cie) + 4 ++ || *cie >= fde[1] - sizeof(*fde) ++ || (*cie & (sizeof(*cie) - 1)) ++ || cie[1]) ++ return NULL; /* this is not a (valid) CIE */ ++ return cie; ++} ++ ++static unsigned long read_pointer(const u8 **pLoc, ++ const void *end, ++ signed ptrType, ++ unsigned long text_base, ++ unsigned long data_base) ++{ ++ unsigned long value = 0; ++ union { ++ const u8 *p8; ++ const u16 *p16u; ++ const s16 *p16s; ++ const u32 *p32u; ++ const s32 *p32s; ++ const unsigned long *pul; ++ } ptr; ++ ++ if (ptrType < 0 || ptrType == DW_EH_PE_omit) { ++ dprintk(1, "Invalid pointer encoding %02X (%p,%p).", ptrType, *pLoc, end); ++ return 0; ++ } ++ ptr.p8 = *pLoc; ++ switch (ptrType & DW_EH_PE_FORM) { ++ case DW_EH_PE_data2: ++ if (end < (const void *)(ptr.p16u + 1)) { ++ dprintk(1, "Data16 overrun (%p,%p).", ptr.p8, end); ++ return 0; ++ } ++ if (ptrType & DW_EH_PE_signed) ++ value = get_unaligned(ptr.p16s++); ++ else ++ value = get_unaligned(ptr.p16u++); ++ break; ++ case DW_EH_PE_data4: ++#ifdef CONFIG_64BIT ++ if (end < (const void *)(ptr.p32u + 1)) { ++ dprintk(1, "Data32 overrun (%p,%p).", ptr.p8, end); ++ return 0; ++ } ++ if (ptrType & DW_EH_PE_signed) ++ value = get_unaligned(ptr.p32s++); ++ else ++ value = get_unaligned(ptr.p32u++); ++ break; ++ case DW_EH_PE_data8: ++ BUILD_BUG_ON(sizeof(u64) != sizeof(value)); ++#else ++ BUILD_BUG_ON(sizeof(u32) != sizeof(value)); ++#endif ++ case DW_EH_PE_native: ++ if (end < (const void *)(ptr.pul + 1)) { ++ dprintk(1, "DataUL overrun (%p,%p).", ptr.p8, end); ++ return 0; ++ } ++ value = get_unaligned(ptr.pul++); ++ break; ++ case DW_EH_PE_leb128: ++ BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value)); ++ value = ptrType & DW_EH_PE_signed ++ ? get_sleb128(&ptr.p8, end) ++ : get_uleb128(&ptr.p8, end); ++ if ((const void *)ptr.p8 > end) { ++ dprintk(1, "DataLEB overrun (%p,%p).", ptr.p8, end); ++ return 0; ++ } ++ break; ++ default: ++ dprintk(2, "Cannot decode pointer type %02X (%p,%p).", ++ ptrType, ptr.p8, end); ++ return 0; ++ } ++ switch (ptrType & DW_EH_PE_ADJUST) { ++ case DW_EH_PE_abs: ++ break; ++ case DW_EH_PE_pcrel: ++ value += (unsigned long)*pLoc; ++ break; ++ case DW_EH_PE_textrel: ++ if (likely(text_base)) { ++ value += text_base; ++ break; ++ } ++ dprintk(2, "Text-relative encoding %02X (%p,%p), but zero text base.", ++ ptrType, *pLoc, end); ++ return 0; ++ case DW_EH_PE_datarel: ++ if (likely(data_base)) { ++ value += data_base; ++ break; ++ } ++ dprintk(2, "Data-relative encoding %02X (%p,%p), but zero data base.", ++ ptrType, *pLoc, end); ++ return 0; ++ default: ++ dprintk(2, "Cannot adjust pointer type %02X (%p,%p).", ++ ptrType, *pLoc, end); ++ return 0; ++ } ++ if ((ptrType & DW_EH_PE_indirect) ++ && probe_kernel_address(value, value)) { ++ dprintk(1, "Cannot read indirect value %lx (%p,%p).", ++ value, *pLoc, end); ++ return 0; ++ } ++ *pLoc = ptr.p8; ++ ++ return value; ++} ++ ++static signed fde_pointer_type(const u32 *cie) ++{ ++ const u8 *ptr = (const u8 *)(cie + 2); ++ unsigned version = *ptr; ++ ++ if (version != 1) ++ return -1; /* unsupported */ ++ if (*++ptr) { ++ const char *aug; ++ const u8 *end = (const u8 *)(cie + 1) + *cie; ++ uleb128_t len; ++ ++ /* check if augmentation size is first (and thus present) */ ++ if (*ptr != 'z') ++ return -1; ++ /* check if augmentation string is nul-terminated */ ++ if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL) ++ return -1; ++ ++ptr; /* skip terminator */ ++ get_uleb128(&ptr, end); /* skip code alignment */ ++ get_sleb128(&ptr, end); /* skip data alignment */ ++ /* skip return address column */ ++ version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end); ++ len = get_uleb128(&ptr, end); /* augmentation length */ ++ if (ptr + len < ptr || ptr + len > end) ++ return -1; ++ end = ptr + len; ++ while (*++aug) { ++ if (ptr >= end) ++ return -1; ++ switch (*aug) { ++ case 'L': ++ ++ptr; ++ break; ++ case 'P': { ++ signed ptrType = *ptr++; ++ ++ if (!read_pointer(&ptr, end, ptrType, 0, 0) ++ || ptr > end) ++ return -1; ++ } ++ break; ++ case 'R': ++ return *ptr; ++ default: ++ return -1; ++ } ++ } ++ } ++ return DW_EH_PE_native|DW_EH_PE_abs; ++} ++ ++static int advance_loc(unsigned long delta, struct unwind_state *state) ++{ ++ state->loc += delta * state->codeAlign; ++ ++ return delta > 0; ++} ++ ++static void set_rule(uleb128_t reg, ++ enum item_location where, ++ uleb128_t value, ++ struct unwind_state *state) ++{ ++ if (reg < ARRAY_SIZE(state->regs)) { ++ state->regs[reg].where = where; ++ state->regs[reg].value = value; ++ } ++} ++ ++static int processCFI(const u8 *start, ++ const u8 *end, ++ unsigned long targetLoc, ++ signed ptrType, ++ struct unwind_state *state) ++{ ++ union { ++ const u8 *p8; ++ const u16 *p16; ++ const u32 *p32; ++ } ptr; ++ int result = 1; ++ ++ if (start != state->cieStart) { ++ state->loc = state->org; ++ result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state); ++ if (targetLoc == 0 && state->label == NULL) ++ return result; ++ } ++ for (ptr.p8 = start; result && ptr.p8 < end; ) { ++ switch (*ptr.p8 >> 6) { ++ uleb128_t value; ++ ++ case 0: ++ switch (*ptr.p8++) { ++ case DW_CFA_nop: ++ break; ++ case DW_CFA_set_loc: ++ state->loc = read_pointer(&ptr.p8, end, ptrType, 0, 0); ++ if (state->loc == 0) ++ result = 0; ++ break; ++ case DW_CFA_advance_loc1: ++ result = ptr.p8 < end && advance_loc(*ptr.p8++, state); ++ break; ++ case DW_CFA_advance_loc2: ++ result = ptr.p8 <= end + 2 ++ && advance_loc(*ptr.p16++, state); ++ break; ++ case DW_CFA_advance_loc4: ++ result = ptr.p8 <= end + 4 ++ && advance_loc(*ptr.p32++, state); ++ break; ++ case DW_CFA_offset_extended: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Memory, get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_val_offset: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Value, get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_offset_extended_sf: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Memory, get_sleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_val_offset_sf: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Value, get_sleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_restore_extended: ++ case DW_CFA_undefined: ++ case DW_CFA_same_value: ++ set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state); ++ break; ++ case DW_CFA_register: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, ++ Register, ++ get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_remember_state: ++ if (ptr.p8 == state->label) { ++ state->label = NULL; ++ return 1; ++ } ++ if (state->stackDepth >= MAX_STACK_DEPTH) { ++ dprintk(1, "State stack overflow (%p,%p).", ptr.p8, end); ++ return 0; ++ } ++ state->stack[state->stackDepth++] = ptr.p8; ++ break; ++ case DW_CFA_restore_state: ++ if (state->stackDepth) { ++ const uleb128_t loc = state->loc; ++ const u8 *label = state->label; ++ ++ state->label = state->stack[state->stackDepth - 1]; ++ memcpy(&state->cfa, &badCFA, sizeof(state->cfa)); ++ memset(state->regs, 0, sizeof(state->regs)); ++ state->stackDepth = 0; ++ result = processCFI(start, end, 0, ptrType, state); ++ state->loc = loc; ++ state->label = label; ++ } else { ++ dprintk(1, "State stack underflow (%p,%p).", ptr.p8, end); ++ return 0; ++ } ++ break; ++ case DW_CFA_def_cfa: ++ state->cfa.reg = get_uleb128(&ptr.p8, end); ++ /*nobreak*/ ++ case DW_CFA_def_cfa_offset: ++ state->cfa.offs = get_uleb128(&ptr.p8, end); ++ break; ++ case DW_CFA_def_cfa_sf: ++ state->cfa.reg = get_uleb128(&ptr.p8, end); ++ /*nobreak*/ ++ case DW_CFA_def_cfa_offset_sf: ++ state->cfa.offs = get_sleb128(&ptr.p8, end) ++ * state->dataAlign; ++ break; ++ case DW_CFA_def_cfa_register: ++ state->cfa.reg = get_uleb128(&ptr.p8, end); ++ break; ++ /*todo case DW_CFA_def_cfa_expression: */ ++ /*todo case DW_CFA_expression: */ ++ /*todo case DW_CFA_val_expression: */ ++ case DW_CFA_GNU_args_size: ++ get_uleb128(&ptr.p8, end); ++ break; ++ case DW_CFA_GNU_negative_offset_extended: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, ++ Memory, ++ (uleb128_t)0 - get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_GNU_window_save: ++ default: ++ dprintk(1, "Unrecognized CFI op %02X (%p,%p).", ptr.p8[-1], ptr.p8 - 1, end); ++ result = 0; ++ break; ++ } ++ break; ++ case 1: ++ result = advance_loc(*ptr.p8++ & 0x3f, state); ++ break; ++ case 2: ++ value = *ptr.p8++ & 0x3f; ++ set_rule(value, Memory, get_uleb128(&ptr.p8, end), state); ++ break; ++ case 3: ++ set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); ++ break; ++ } ++ if (ptr.p8 > end) { ++ dprintk(1, "Data overrun (%p,%p).", ptr.p8, end); ++ result = 0; ++ } ++ if (result && targetLoc != 0 && targetLoc < state->loc) ++ return 1; ++ } ++ ++ if (result && ptr.p8 < end) ++ dprintk(1, "Data underrun (%p,%p).", ptr.p8, end); ++ ++ return result ++ && ptr.p8 == end ++ && (targetLoc == 0 ++ || (/*todo While in theory this should apply, gcc in practice omits ++ everything past the function prolog, and hence the location ++ never reaches the end of the function. ++ targetLoc < state->loc &&*/ state->label == NULL)); ++} ++ ++/* Unwind to previous to frame. Returns 0 if successful, negative ++ * number in case of an error. */ ++int unwind(struct unwind_frame_info *frame) ++{ ++#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) ++ const u32 *fde = NULL, *cie = NULL; ++ const u8 *ptr = NULL, *end = NULL; ++ unsigned long pc = UNW_PC(frame) - frame->call_frame, sp; ++ unsigned long startLoc = 0, endLoc = 0, cfa; ++ unsigned i; ++ signed ptrType = -1; ++ uleb128_t retAddrReg = 0; ++ const struct unwind_table *table; ++ struct unwind_state state; ++ ++ if (UNW_PC(frame) == 0) ++ return -EINVAL; ++ if ((table = find_table(pc)) != NULL ++ && !(table->size & (sizeof(*fde) - 1))) { ++ const u8 *hdr = table->header; ++ unsigned long tableSize; ++ ++ smp_rmb(); ++ if (hdr && hdr[0] == 1) { ++ switch (hdr[3] & DW_EH_PE_FORM) { ++ case DW_EH_PE_native: tableSize = sizeof(unsigned long); break; ++ case DW_EH_PE_data2: tableSize = 2; break; ++ case DW_EH_PE_data4: tableSize = 4; break; ++ case DW_EH_PE_data8: tableSize = 8; break; ++ default: tableSize = 0; break; ++ } ++ ptr = hdr + 4; ++ end = hdr + table->hdrsz; ++ if (tableSize ++ && read_pointer(&ptr, end, hdr[1], 0, 0) ++ == (unsigned long)table->address ++ && (i = read_pointer(&ptr, end, hdr[2], 0, 0)) > 0 ++ && i == (end - ptr) / (2 * tableSize) ++ && !((end - ptr) % (2 * tableSize))) { ++ do { ++ const u8 *cur = ptr + (i / 2) * (2 * tableSize); ++ ++ startLoc = read_pointer(&cur, ++ cur + tableSize, ++ hdr[3], 0, ++ (unsigned long)hdr); ++ if (pc < startLoc) ++ i /= 2; ++ else { ++ ptr = cur - tableSize; ++ i = (i + 1) / 2; ++ } ++ } while (startLoc && i > 1); ++ if (i == 1 ++ && (startLoc = read_pointer(&ptr, ++ ptr + tableSize, ++ hdr[3], 0, ++ (unsigned long)hdr)) != 0 ++ && pc >= startLoc) ++ fde = (void *)read_pointer(&ptr, ++ ptr + tableSize, ++ hdr[3], 0, ++ (unsigned long)hdr); ++ } ++ } ++ if (hdr && !fde) ++ dprintk(3, "Binary lookup for %lx failed.", pc); ++ ++ if (fde != NULL) { ++ cie = cie_for_fde(fde, table); ++ ptr = (const u8 *)(fde + 2); ++ if (cie != NULL ++ && cie != &bad_cie ++ && cie != ¬_fde ++ && (ptrType = fde_pointer_type(cie)) >= 0 ++ && read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType, 0, 0) == startLoc) { ++ if (!(ptrType & DW_EH_PE_indirect)) ++ ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; ++ endLoc = startLoc ++ + read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType, 0, 0); ++ if (pc >= endLoc) ++ fde = NULL; ++ } else ++ fde = NULL; ++ if (!fde) ++ dprintk(1, "Binary lookup result for %lx discarded.", pc); ++ } ++ if (fde == NULL) { ++ for (fde = table->address, tableSize = table->size; ++ cie = NULL, tableSize > sizeof(*fde) ++ && tableSize - sizeof(*fde) >= *fde; ++ tableSize -= sizeof(*fde) + *fde, ++ fde += 1 + *fde / sizeof(*fde)) { ++ cie = cie_for_fde(fde, table); ++ if (cie == &bad_cie) { ++ cie = NULL; ++ break; ++ } ++ if (cie == NULL ++ || cie == ¬_fde ++ || (ptrType = fde_pointer_type(cie)) < 0) ++ continue; ++ ptr = (const u8 *)(fde + 2); ++ startLoc = read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType, 0, 0); ++ if (!startLoc) ++ continue; ++ if (!(ptrType & DW_EH_PE_indirect)) ++ ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed; ++ endLoc = startLoc ++ + read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType, 0, 0); ++ if (pc >= startLoc && pc < endLoc) ++ break; ++ } ++ if (!fde) ++ dprintk(3, "Linear lookup for %lx failed.", pc); ++ } ++ } ++ if (cie != NULL) { ++ memset(&state, 0, sizeof(state)); ++ state.cieEnd = ptr; /* keep here temporarily */ ++ ptr = (const u8 *)(cie + 2); ++ end = (const u8 *)(cie + 1) + *cie; ++ frame->call_frame = 1; ++ if ((state.version = *ptr) != 1) ++ cie = NULL; /* unsupported version */ ++ else if (*++ptr) { ++ /* check if augmentation size is first (and thus present) */ ++ if (*ptr == 'z') { ++ while (++ptr < end && *ptr) { ++ switch (*ptr) { ++ /* check for ignorable (or already handled) ++ * nul-terminated augmentation string */ ++ case 'L': ++ case 'P': ++ case 'R': ++ continue; ++ case 'S': ++ frame->call_frame = 0; ++ continue; ++ default: ++ break; ++ } ++ break; ++ } ++ } ++ if (ptr >= end || *ptr) ++ cie = NULL; ++ } ++ if (!cie) ++ dprintk(1, "CIE unusable (%p,%p).", ptr, end); ++ ++ptr; ++ } ++ if (cie != NULL) { ++ /* get code aligment factor */ ++ state.codeAlign = get_uleb128(&ptr, end); ++ /* get data aligment factor */ ++ state.dataAlign = get_sleb128(&ptr, end); ++ if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) ++ cie = NULL; ++ else if (UNW_PC(frame) % state.codeAlign ++ || UNW_SP(frame) % sleb128abs(state.dataAlign)) { ++ dprintk(1, "Input pointer(s) misaligned (%lx,%lx).", ++ UNW_PC(frame), UNW_SP(frame)); ++ return -EPERM; ++ } else { ++ retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); ++ /* skip augmentation */ ++ if (((const char *)(cie + 2))[1] == 'z') { ++ uleb128_t augSize = get_uleb128(&ptr, end); ++ ++ ptr += augSize; ++ } ++ if (ptr > end ++ || retAddrReg >= ARRAY_SIZE(reg_info) ++ || REG_INVALID(retAddrReg) ++ || reg_info[retAddrReg].width != sizeof(unsigned long)) ++ cie = NULL; ++ } ++ if (!cie) ++ dprintk(1, "CIE validation failed (%p,%p).", ptr, end); ++ } ++ if (cie != NULL) { ++ state.cieStart = ptr; ++ ptr = state.cieEnd; ++ state.cieEnd = end; ++ end = (const u8 *)(fde + 1) + *fde; ++ /* skip augmentation */ ++ if (((const char *)(cie + 2))[1] == 'z') { ++ uleb128_t augSize = get_uleb128(&ptr, end); ++ ++ if ((ptr += augSize) > end) ++ fde = NULL; ++ } ++ if (!fde) ++ dprintk(1, "FDE validation failed (%p,%p).", ptr, end); ++ } ++ if (cie == NULL || fde == NULL) { ++#ifdef CONFIG_FRAME_POINTER ++ unsigned long top, bottom; ++ ++ if ((UNW_SP(frame) | UNW_FP(frame)) % sizeof(unsigned long)) ++ return -EPERM; ++ top = TSK_STACK_TOP(frame->task); ++ bottom = STACK_BOTTOM(frame->task); ++# if FRAME_RETADDR_OFFSET < 0 ++ if (UNW_SP(frame) < top ++ && UNW_FP(frame) <= UNW_SP(frame) ++ && bottom < UNW_FP(frame) ++# else ++ if (UNW_SP(frame) > top ++ && UNW_FP(frame) >= UNW_SP(frame) ++ && bottom > UNW_FP(frame) ++# endif ++ && !((UNW_SP(frame) | UNW_FP(frame)) ++ & (sizeof(unsigned long) - 1))) { ++ unsigned long link; ++ ++ if (!probe_kernel_address(UNW_FP(frame) + FRAME_LINK_OFFSET, ++ link) ++# if FRAME_RETADDR_OFFSET < 0 ++ && link > bottom && link < UNW_FP(frame) ++# else ++ && link > UNW_FP(frame) && link < bottom ++# endif ++ && !(link & (sizeof(link) - 1)) ++ && !probe_kernel_address(UNW_FP(frame) + FRAME_RETADDR_OFFSET, ++ UNW_PC(frame))) { ++ UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET ++# if FRAME_RETADDR_OFFSET < 0 ++ - ++# else ++ + ++# endif ++ sizeof(UNW_PC(frame)); ++ UNW_FP(frame) = link; ++ return 0; ++ } ++ } ++#endif ++ return -ENXIO; ++ } ++ state.org = startLoc; ++ memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); ++ /* process instructions */ ++ if (!processCFI(ptr, end, pc, ptrType, &state) ++ || state.loc > endLoc ++ || state.regs[retAddrReg].where == Nowhere ++ || state.cfa.reg >= ARRAY_SIZE(reg_info) ++ || reg_info[state.cfa.reg].width != sizeof(unsigned long) ++ || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long) ++ || state.cfa.offs % sizeof(unsigned long)) { ++ dprintk(1, "Unusable unwind info (%p,%p).", ptr, end); ++ return -EIO; ++ } ++ /* update frame */ ++#ifndef CONFIG_AS_CFI_SIGNAL_FRAME ++ if (frame->call_frame ++ && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign)) ++ frame->call_frame = 0; ++#endif ++ cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; ++ startLoc = min((unsigned long)UNW_SP(frame), cfa); ++ endLoc = max((unsigned long)UNW_SP(frame), cfa); ++ if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) { ++ startLoc = min(STACK_LIMIT(cfa), cfa); ++ endLoc = max(STACK_LIMIT(cfa), cfa); ++ } ++#ifndef CONFIG_64BIT ++# define CASES CASE(8); CASE(16); CASE(32) ++#else ++# define CASES CASE(8); CASE(16); CASE(32); CASE(64) ++#endif ++ pc = UNW_PC(frame); ++ sp = UNW_SP(frame); ++ for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { ++ if (REG_INVALID(i)) { ++ if (state.regs[i].where == Nowhere) ++ continue; ++ dprintk(1, "Cannot restore register %u (%d).", ++ i, state.regs[i].where); ++ return -EIO; ++ } ++ switch (state.regs[i].where) { ++ default: ++ break; ++ case Register: ++ if (state.regs[i].value >= ARRAY_SIZE(reg_info) ++ || REG_INVALID(state.regs[i].value) ++ || reg_info[i].width > reg_info[state.regs[i].value].width) { ++ dprintk(1, "Cannot restore register %u from register %lu.", ++ i, state.regs[i].value); ++ return -EIO; ++ } ++ switch (reg_info[state.regs[i].value].width) { ++#define CASE(n) \ ++ case sizeof(u##n): \ ++ state.regs[i].value = FRAME_REG(state.regs[i].value, \ ++ const u##n); \ ++ break ++ CASES; ++#undef CASE ++ default: ++ dprintk(1, "Unsupported register size %u (%lu).", ++ reg_info[state.regs[i].value].width, ++ state.regs[i].value); ++ return -EIO; ++ } ++ break; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { ++ if (REG_INVALID(i)) ++ continue; ++ switch (state.regs[i].where) { ++ case Nowhere: ++ if (reg_info[i].width != sizeof(UNW_SP(frame)) ++ || &FRAME_REG(i, __typeof__(UNW_SP(frame))) ++ != &UNW_SP(frame)) ++ continue; ++ UNW_SP(frame) = cfa; ++ break; ++ case Register: ++ switch (reg_info[i].width) { ++#define CASE(n) case sizeof(u##n): \ ++ FRAME_REG(i, u##n) = state.regs[i].value; \ ++ break ++ CASES; ++#undef CASE ++ default: ++ dprintk(1, "Unsupported register size %u (%u).", ++ reg_info[i].width, i); ++ return -EIO; ++ } ++ break; ++ case Value: ++ if (reg_info[i].width != sizeof(unsigned long)) { ++ dprintk(1, "Unsupported value size %u (%u).", ++ reg_info[i].width, i); ++ return -EIO; ++ } ++ FRAME_REG(i, unsigned long) = cfa + state.regs[i].value ++ * state.dataAlign; ++ break; ++ case Memory: { ++ unsigned long addr = cfa + state.regs[i].value ++ * state.dataAlign; ++ ++ if ((state.regs[i].value * state.dataAlign) ++ % sizeof(unsigned long) ++ || addr < startLoc ++ || addr + sizeof(unsigned long) < addr ++ || addr + sizeof(unsigned long) > endLoc) { ++ dprintk(1, "Bad memory location %lx (%lx).", ++ addr, state.regs[i].value); ++ return -EIO; ++ } ++ switch (reg_info[i].width) { ++#define CASE(n) case sizeof(u##n): \ ++ if (probe_kernel_address(addr, \ ++ FRAME_REG(i, u##n))) \ ++ return -EFAULT; \ ++ break ++ CASES; ++#undef CASE ++ default: ++ dprintk(1, "Unsupported memory size %u (%u).", ++ reg_info[i].width, i); ++ return -EIO; ++ } ++ } ++ break; ++ } ++ } ++ ++ if (UNW_PC(frame) % state.codeAlign ++ || UNW_SP(frame) % sleb128abs(state.dataAlign)) { ++ dprintk(1, "Output pointer(s) misaligned (%lx,%lx).", ++ UNW_PC(frame), UNW_SP(frame)); ++ return -EIO; ++ } ++ if (pc == UNW_PC(frame) && sp == UNW_SP(frame)) { ++ dprintk(1, "No progress (%lx,%lx).", pc, sp); ++ return -EIO; ++ } ++ ++ return 0; ++#undef CASES ++#undef FRAME_REG ++} ++EXPORT_SYMBOL_GPL(unwind); ++ ++int unwind_init_frame_info(struct unwind_frame_info *info, ++ struct task_struct *tsk, ++ /*const*/ struct pt_regs *regs) ++{ ++ info->task = tsk; ++ info->call_frame = 0; ++ arch_unw_init_frame_info(info, regs); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(unwind_init_frame_info); ++ ++/* ++ * Prepare to unwind a blocked task. ++ */ ++int unwind_init_blocked(struct unwind_frame_info *info, ++ struct task_struct *tsk) ++{ ++ info->task = tsk; ++ info->call_frame = 0; ++ arch_unw_init_blocked(info); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(unwind_init_blocked); ++ ++/* ++ * Prepare to unwind the currently running thread. ++ */ ++int unwind_init_running(struct unwind_frame_info *info, ++ asmlinkage int (*callback)(struct unwind_frame_info *, ++ void *arg), ++ void *arg) ++{ ++ info->task = current; ++ info->call_frame = 0; ++ ++ return arch_unwind_init_running(info, callback, arg); ++} ++EXPORT_SYMBOL_GPL(unwind_init_running); ++ ++/* ++ * Unwind until the return pointer is in user-land (or until an error ++ * occurs). Returns 0 if successful, negative number in case of ++ * error. ++ */ ++int unwind_to_user(struct unwind_frame_info *info) ++{ ++ while (!arch_unw_user_mode(info)) { ++ int err = unwind(info); ++ ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(unwind_to_user); +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -548,6 +548,24 @@ config FRAME_POINTER + some architectures or if you use external debuggers. + If you don't debug the kernel, you can say N. + ++config UNWIND_INFO ++ bool "Compile the kernel with frame unwind information" ++ depends on !IA64 && !PARISC && !ARM ++ depends on !MODULES || !(MIPS || PPC || SUPERH || V850) ++ help ++ If you say Y here the resulting kernel image will be slightly larger ++ but not slower, and it will give very useful debugging information. ++ If you don't debug the kernel, you can say N, but we may not be able ++ to solve problems without frame unwind information or frame pointers. ++ ++config STACK_UNWIND ++ bool "Stack unwind support" ++ depends on UNWIND_INFO ++ depends on X86 ++ help ++ This enables more precise stack traces, omitting all unrelated ++ occurrences of pointers into kernel code from the dump. ++ + config BOOT_PRINTK_DELAY + bool "Delay each boot printk message by N milliseconds" + depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY diff --git a/src/patches/suse-2.6.27.31/patches.suse/supported-flag b/src/patches/suse-2.6.27.31/patches.suse/supported-flag new file mode 100644 index 000000000..6cc9f04fb --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/supported-flag @@ -0,0 +1,351 @@ +From: Andreas Gruenbacher +Subject: Novell/external support flag in modules + +Upon module load, check if a module is supported, and set the +N (TAINT_NO_SUPPORT) or X (TAINT_EXTERNAL_SUPPORT) tail flags +for unsupported or externally suported modules. + +Changes: +* Feb 21 2008 - jeffm +- 2.6.25 claimed -S and bumped the flags up a bit, modpost now uses -N + +Signed-off-by: Andreas Gruenbacher + +--- + + Documentation/kernel-parameters.txt | 6 +++ + Documentation/sysctl/kernel.txt | 12 ++++++ + Makefile | 5 ++ + include/linux/kernel.h | 8 ++++ + kernel/module.c | 41 ++++++++++++++++++++++ + kernel/panic.c | 8 +++- + kernel/sysctl.c | 10 +++++ + scripts/Makefile.modpost | 4 +- + scripts/mod/modpost.c | 65 +++++++++++++++++++++++++++++++++++- + 9 files changed, 155 insertions(+), 4 deletions(-) + +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -2113,6 +2113,12 @@ and is between 256 and 4096 characters. + pernode one pool for each NUMA node (equivalent + to global on non-NUMA machines) + ++ unsupported Allow loading of unsupported kernel modules: ++ 0 = only allow supported modules, ++ 1 = warn when loading unsupported modules, ++ 2 = don't warn. ++ ++ + swiotlb= [IA-64] Number of I/O TLB slabs + + switches= [HW,M68k] +--- a/Documentation/sysctl/kernel.txt ++++ b/Documentation/sysctl/kernel.txt +@@ -369,4 +369,16 @@ can be ORed together: + 2 - A module was force loaded by insmod -f. + Set by modutils >= 2.4.9 and module-init-tools. + 4 - Unsafe SMP processors: SMP with CPUs not designed for SMP. ++ 0x40000000 - An unsupported kernel module was loaded. ++ 0x80000000 - An kernel module with external support was loaded. ++ ++============================================================== ++ ++unsupported: ++ ++Allow to load unsupported kernel modules: ++ ++ 0 - refuse to load unsupported modules, ++ 1 - warn when loading unsupported modules, ++ 2 - don't warn. + +--- a/Makefile ++++ b/Makefile +@@ -344,6 +344,11 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstric + -fno-delete-null-pointer-checks + KBUILD_AFLAGS := -D__ASSEMBLY__ + ++# Warn about unsupported modules in kernels built inside Autobuild ++ifneq ($(wildcard /.buildenv),) ++CFLAGS += -DUNSUPPORTED_MODULES=2 ++endif ++ + # Read KERNELRELEASE from include/config/kernel.release (if it exists) + KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) + KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -236,6 +236,7 @@ extern int panic_timeout; + extern int panic_on_oops; + extern int panic_on_unrecovered_nmi; + extern int tainted; ++extern int unsupported; + extern const char *print_tainted(void); + extern void add_taint(unsigned); + extern int root_mountflags; +@@ -261,6 +262,13 @@ extern enum system_states { + #define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8) + #define TAINT_WARN (1<<9) + ++/* ++ * Take the upper bits to hopefully allow them ++ * to stay the same for more than one release. ++ */ ++#define TAINT_NO_SUPPORT (1<<30) ++#define TAINT_EXTERNAL_SUPPORT (1<<31) ++ + extern void dump_stack(void) __cold; + + enum { +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -60,6 +60,20 @@ + /* If this is set, the section belongs in the init part of the module */ + #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) + ++/* Allow unsupported modules switch. */ ++#ifdef UNSUPPORTED_MODULES ++int unsupported = UNSUPPORTED_MODULES; ++#else ++int unsupported = 2; /* don't warn when loading unsupported modules. */ ++#endif ++ ++static int __init unsupported_setup(char *str) ++{ ++ get_option(&str, &unsupported); ++ return 1; ++} ++__setup("unsupported=", unsupported_setup); ++ + /* List of modules, protected by module_mutex or preempt_disable + * (add/delete uses stop_machine). */ + static DEFINE_MUTEX(module_mutex); +@@ -1806,6 +1820,7 @@ static noinline struct module *load_modu + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + char *secstrings, *args, *modmagic, *strtab = NULL; ++ char *supported; + unsigned int i; + unsigned int symindex = 0; + unsigned int strindex = 0; +@@ -1960,6 +1975,28 @@ static noinline struct module *load_modu + goto free_hdr; + } + ++ supported = get_modinfo(sechdrs, infoindex, "supported"); ++ if (supported) { ++ if (!strcmp(supported, "external")) ++ add_taint_module(mod, TAINT_EXTERNAL_SUPPORT); ++ else if (strcmp(supported, "yes")) ++ supported = NULL; ++ } ++ if (!supported) { ++ if (unsupported == 0) { ++ printk(KERN_WARNING "%s: module not supported by " ++ "Novell, refusing to load. To override, echo " ++ "1 > /proc/sys/kernel/unsupported\n", mod->name); ++ err = -ENOEXEC; ++ goto free_hdr; ++ } ++ add_taint_module(mod, TAINT_NO_SUPPORT); ++ if (unsupported == 1) { ++ printk(KERN_WARNING "%s: module not supported by " ++ "Novell, setting U taint flag.\n", mod->name); ++ } ++ } ++ + /* Now copy in args */ + args = strndup_user(uargs, ~0UL >> 1); + if (IS_ERR(args)) { +@@ -2554,6 +2591,10 @@ static char *module_flags(struct module + buf[bx++] = 'P'; + if (mod->taints & TAINT_FORCED_MODULE) + buf[bx++] = 'F'; ++ if (mod->taints & TAINT_NO_SUPPORT) ++ buf[bx++] = 'N'; ++ if (mod->taints & TAINT_EXTERNAL_SUPPORT) ++ buf[bx++] = 'X'; + /* + * TAINT_FORCED_RMMOD: could be added. + * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -155,6 +155,8 @@ EXPORT_SYMBOL(panic); + * 'U' - Userspace-defined naughtiness. + * 'A' - ACPI table overridden. + * 'W' - Taint on warning. ++ * 'N' - Unsuported modules loaded. ++ * 'X' - Modules with external support loaded. + * + * The string is overwritten by the next call to print_taint(). + */ +@@ -163,7 +165,7 @@ const char *print_tainted(void) + { + static char buf[20]; + if (tainted) { +- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c", ++ snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c%c%c", + tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', +@@ -173,7 +175,9 @@ const char *print_tainted(void) + tainted & TAINT_USER ? 'U' : ' ', + tainted & TAINT_DIE ? 'D' : ' ', + tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ', +- tainted & TAINT_WARN ? 'W' : ' '); ++ tainted & TAINT_WARN ? 'W' : ' ', ++ tainted & TAINT_NO_SUPPORT ? 'N' : ' ', ++ tainted & TAINT_EXTERNAL_SUPPORT ? 'X' : ' '); + } + else + snprintf(buf, sizeof(buf), "Not tainted"); +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -550,6 +550,16 @@ static struct ctl_table kern_table[] = { + .mode = 0644, + .proc_handler = &proc_dointvec, + }, ++#ifdef CONFIG_MODULES ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "unsupported", ++ .data = &unsupported, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif + { + .ctl_name = KERN_RANDOM, + .procname = "random", +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -88,7 +88,9 @@ modpost = scripts/mod/modpost + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \ + $(if $(CONFIG_MARKERS),-M $(markersfile)) \ + $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ +- $(if $(cross_build),-c) ++ $(if $(cross_build),-c) \ ++ -N $(firstword $(wildcard $(dir $(MODVERDIR))/Module.supported \ ++ $(objtree)/Module.supported /dev/null)) + + quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules + cmd_modpost = $(modpost) -s +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -1545,6 +1545,48 @@ static void get_markers(struct elf_info + } + } + ++void *supported_file; ++unsigned long supported_size; ++ ++const char *supported(struct module *mod) ++{ ++ unsigned long pos = 0; ++ char *line; ++ ++ /* In a first shot, do a simple linear scan. */ ++ while ((line = get_next_line(&pos, supported_file, ++ supported_size))) { ++ const char *basename, *how = "yes"; ++ char *l = line; ++ ++ /* optional type-of-support flag */ ++ for (l = line; *l != '\0'; l++) { ++ if (*l == ' ' || *l == '\t') { ++ *l = '\0'; ++ how = l + 1; ++ break; ++ } ++ } ++ ++ /* skip directory components */ ++ if ((l = strrchr(line, '/'))) ++ line = l + 1; ++ /* strip .ko extension */ ++ l = line + strlen(line); ++ if (l - line > 3 && !strcmp(l-3, ".ko")) ++ *(l-3) = '\0'; ++ ++ /* skip directory components */ ++ if ((basename = strrchr(mod->name, '/'))) ++ basename++; ++ else ++ basename = mod->name; ++ if (!strcmp(basename, line)) ++ return how; ++ } ++ return NULL; ++} ++ + static void read_symbols(char *modname) + { + const char *symname; +@@ -1726,6 +1768,13 @@ static void add_header(struct buffer *b, + buf_printf(b, "};\n"); + } + ++void add_supported_flag(struct buffer *b, struct module *mod) ++{ ++ const char *how = supported(mod); ++ if (how) ++ buf_printf(b, "\nMODULE_INFO(supported, \"%s\");\n", how); ++} ++ + /** + * Record CRCs for unresolved symbols + **/ +@@ -1866,6 +1915,13 @@ static void write_if_changed(struct buff + fclose(file); + } + ++void read_supported(const char *fname) ++{ ++ supported_file = grab_file(fname, &supported_size); ++ if (!supported_file) ++ ; /* ignore error */ ++} ++ + /* parse Module.symvers file. line format: + * 0x12345678symbolmodule[[export]something] + **/ +@@ -2051,12 +2107,13 @@ int main(int argc, char **argv) + char *dump_write = NULL; + char *markers_read = NULL; + char *markers_write = NULL; ++ const char *supported = NULL; + int opt; + int err; + struct ext_sym_list *extsym_iter; + struct ext_sym_list *extsym_start = NULL; + +- while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) { ++ while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:N:")) != -1) { + switch (opt) { + case 'i': + kernel_read = optarg; +@@ -2100,11 +2157,16 @@ int main(int argc, char **argv) + case 'K': + markers_read = optarg; + break; ++ case 'N': ++ supported = optarg; ++ break; + default: + exit(1); + } + } + ++ if (supported) ++ read_supported(supported); + if (kernel_read) + read_dump(kernel_read, 1); + if (module_read) +@@ -2136,6 +2198,7 @@ int main(int argc, char **argv) + buf.pos = 0; + + add_header(&buf, mod); ++ add_supported_flag(&buf, mod); + err |= add_versions(&buf, mod); + add_depends(&buf, mod, modules); + add_moddevtable(&buf, mod); diff --git a/src/patches/suse-2.6.27.31/patches.suse/supported-flag-sysfs b/src/patches/suse-2.6.27.31/patches.suse/supported-flag-sysfs new file mode 100644 index 000000000..4a8529250 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/supported-flag-sysfs @@ -0,0 +1,177 @@ +From: Jeff Mahoney +Subject: Export supported status via sysfs + + This patch adds a /sys/kernel/supported file indicating the supportability + status of the entire kernel. + + It also adds a /sys/module//supported file indicating the + supportability status of individual modules. + + This is useful because it can be used to obtain the supported status + of a running system without current modules (ie: immediately after + a kernel update but before a reboot) and without generating an oops. + +Signed-off-by: Jeff Mahoney + +--- + + include/linux/module.h | 1 + kernel/ksysfs.c | 18 ++++++++++++ + kernel/module.c | 70 ++++++++++++++++++++++++++++++++----------------- + 3 files changed, 66 insertions(+), 23 deletions(-) + +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -363,6 +363,7 @@ static inline int module_is_live(struct + struct module *module_text_address(unsigned long addr); + struct module *__module_text_address(unsigned long addr); + int is_module_address(unsigned long addr); ++const char *supported_printable(int taint); + + /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if + symnum out of range. */ +--- a/kernel/ksysfs.c ++++ b/kernel/ksysfs.c +@@ -104,6 +104,23 @@ static struct bin_attribute notes_attr = + struct kobject *kernel_kobj; + EXPORT_SYMBOL_GPL(kernel_kobj); + ++const char *supported_printable(int taint) ++{ ++ if (taint & TAINT_NO_SUPPORT) ++ return "No"; ++ else if (taint & TAINT_EXTERNAL_SUPPORT) ++ return "Yes, External"; ++ else ++ return "Yes"; ++} ++ ++static ssize_t supported_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%s\n", supported_printable(tainted)); ++} ++KERNEL_ATTR_RO(supported); ++ + static struct attribute * kernel_attrs[] = { + #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) + &uevent_seqnum_attr.attr, +@@ -114,6 +131,7 @@ static struct attribute * kernel_attrs[] + &kexec_crash_loaded_attr.attr, + &vmcoreinfo_attr.attr, + #endif ++ &supported_attr.attr, + NULL + }; + +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -922,10 +922,36 @@ static struct module_attribute initstate + .show = show_initstate, + }; + ++static void setup_modinfo_supported(struct module *mod, const char *s) ++{ ++ if (!s) { ++ mod->taints |= TAINT_NO_SUPPORT; ++ return; ++ } ++ ++ if (strcmp(s, "external") == 0) ++ mod->taints |= TAINT_EXTERNAL_SUPPORT; ++ else if (strcmp(s, "yes")) ++ mod->taints |= TAINT_NO_SUPPORT; ++} ++ ++static ssize_t show_modinfo_supported(struct module_attribute *mattr, ++ struct module *mod, char *buffer) ++{ ++ return sprintf(buffer, "%s\n", supported_printable(mod->taints)); ++} ++ ++static struct module_attribute modinfo_supported = { ++ .attr = { .name = "supported", .mode = 0444 }, ++ .show = show_modinfo_supported, ++ .setup = setup_modinfo_supported, ++}; ++ + static struct module_attribute *modinfo_attrs[] = { + &modinfo_version, + &modinfo_srcversion, + &initstate, ++ &modinfo_supported, + #ifdef CONFIG_MODULE_UNLOAD + &refcnt, + #endif +@@ -1820,7 +1846,6 @@ static noinline struct module *load_modu + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + char *secstrings, *args, *modmagic, *strtab = NULL; +- char *supported; + unsigned int i; + unsigned int symindex = 0; + unsigned int strindex = 0; +@@ -1975,28 +2000,6 @@ static noinline struct module *load_modu + goto free_hdr; + } + +- supported = get_modinfo(sechdrs, infoindex, "supported"); +- if (supported) { +- if (!strcmp(supported, "external")) +- add_taint_module(mod, TAINT_EXTERNAL_SUPPORT); +- else if (strcmp(supported, "yes")) +- supported = NULL; +- } +- if (!supported) { +- if (unsupported == 0) { +- printk(KERN_WARNING "%s: module not supported by " +- "Novell, refusing to load. To override, echo " +- "1 > /proc/sys/kernel/unsupported\n", mod->name); +- err = -ENOEXEC; +- goto free_hdr; +- } +- add_taint_module(mod, TAINT_NO_SUPPORT); +- if (unsupported == 1) { +- printk(KERN_WARNING "%s: module not supported by " +- "Novell, setting U taint flag.\n", mod->name); +- } +- } +- + /* Now copy in args */ + args = strndup_user(uargs, ~0UL >> 1); + if (IS_ERR(args)) { +@@ -2256,6 +2259,26 @@ static noinline struct module *load_modu + add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); + add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs); + ++ /* We don't use add_taint() here because it also disables lockdep. */ ++ if (mod->taints & TAINT_EXTERNAL_SUPPORT) ++ tainted |= TAINT_EXTERNAL_SUPPORT; ++ else if (mod->taints == TAINT_NO_SUPPORT) { ++ if (unsupported == 0) { ++ printk(KERN_WARNING "%s: module not supported by " ++ "Novell, refusing to load. To override, echo " ++ "1 > /proc/sys/kernel/unsupported\n", mod->name); ++ err = -ENOEXEC; ++ goto free_hdr; ++ } ++ tainted |= TAINT_NO_SUPPORT; ++ if (unsupported == 1) { ++ printk(KERN_WARNING "%s: module is not supported by " ++ "Novell. Novell Technical Services may decline " ++ "your support request if it involves a kernel " ++ "fault.\n", mod->name); ++ } ++ } ++ + /* Size of section 0 is 0, so this works well if no unwind info. */ + mod->unwind_info = unwind_add_table(mod, + (void *)sechdrs[unwindex].sh_addr, +@@ -2735,6 +2758,7 @@ void print_modules(void) + if (last_unloaded_module[0]) + printk(" [last unloaded: %s]", last_unloaded_module); + printk("\n"); ++ printk("Supported: %s\n", supported_printable(tainted)); + } + + #ifdef CONFIG_MODVERSIONS diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-BIT b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-BIT new file mode 100644 index 000000000..d62701f57 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-BIT @@ -0,0 +1,357 @@ +Subject: mol build fix +From: schwab@suse.de + +--- + drivers/macintosh/mol/context.c | 4 - + drivers/macintosh/mol/emu.c | 2 + drivers/macintosh/mol/fault.c | 20 +++---- + drivers/macintosh/mol/include/asmdbg.h | 2 + drivers/macintosh/mol/include/asmdefs.h | 2 + drivers/macintosh/mol/include/mac_registers.h | 20 +++---- + drivers/macintosh/mol/include/processor.h | 66 +++++++++++++------------- + drivers/macintosh/mol/mmu_fb.c | 2 + drivers/macintosh/mol/mmu_io.c | 6 +- + drivers/macintosh/mol/mtable.c | 12 ++-- + drivers/macintosh/mol/ptaccess.c | 6 +- + 11 files changed, 71 insertions(+), 71 deletions(-) + +--- a/drivers/macintosh/mol/context.c ++++ b/drivers/macintosh/mol/context.c +@@ -37,9 +37,9 @@ flush_all_PTEs( kernel_vars_t *kv ) + + for( pte=ptehash.base, i=0; i> 7; ++ v = (v & ~MOL_BIT(0)) >> 7; + v = (v - ((v & 0xf) * MUNGE_ESID_ADD)) * MUNGE_MUL_INVERSE; + v = (v>>4) & CTX_MASK; + +--- a/drivers/macintosh/mol/emu.c ++++ b/drivers/macintosh/mol/emu.c +@@ -60,7 +60,7 @@ do_mtsdr1( kernel_vars_t *kv, ulong valu + /* the mask must be a valid one; we hade better make sure we are + * not tricked by a bogus sdr1 value + */ +- for( mask=BIT(23); mask && !(mask & value) ; mask=mask>>1 ) ++ for( mask=MOL_BIT(23); mask && !(mask & value) ; mask=mask>>1 ) + ; + mask = mask? ((mask | (mask-1)) << 16) | 0xffff : 0xffff; + mbase = value & ~mask; +--- a/drivers/macintosh/mol/fault.c ++++ b/drivers/macintosh/mol/fault.c +@@ -31,10 +31,10 @@ + #include "hash.h" + + /* exception bits (srr1/dsisr and a couple of mol defined bits) */ +-#define EBIT_PAGE_FAULT BIT(1) /* I/D, PTE missing */ +-#define EBIT_NO_EXEC BIT(3) /* I, no-execute or guarded */ +-#define EBIT_PROT_VIOL BIT(4) /* I/D, protection violation */ +-#define EBIT_IS_WRITE BIT(6) /* D */ ++#define EBIT_PAGE_FAULT MOL_BIT(1) /* I/D, PTE missing */ ++#define EBIT_NO_EXEC MOL_BIT(3) /* I, no-execute or guarded */ ++#define EBIT_PROT_VIOL MOL_BIT(4) /* I/D, protection violation */ ++#define EBIT_IS_WRITE MOL_BIT(6) /* D */ + #define EBIT_IS_DSI 1 /* D, virtual bit */ + #define EBIT_USE_MMU 2 /* I/D, virtual bit */ + +@@ -135,7 +135,7 @@ lookup_603_pte( kernel_vars_t *kv, ulong + MREGS.spr[S_HASH2] = MMU.hash_mbase + (pteg ^ (mask << 6)); + + /* construct compare word */ +- cmp = BIT(0) | (vsid <<7) | (cmp_ea >> 22); ++ cmp = MOL_BIT(0) | (vsid <<7) | (cmp_ea >> 22); + if( is_dsi ) { + MREGS.spr[S_DCMP] = cmp; + MREGS.spr[S_DMISS] = ea; +@@ -167,7 +167,7 @@ lookup_mac_pte( kernel_vars_t *kv, ulong + pteg = ((phash & mask) << 6); + + /* construct compare word */ +- cmp = BIT(0) | (vsid <<7) | ((ea&0x0fffffff)>>22); ++ cmp = MOL_BIT(0) | (vsid <<7) | ((ea&0x0fffffff)>>22); + + /* look in primary PTEG */ + p = (ulong*)((ulong)MMU.hash_base + pteg); +@@ -177,7 +177,7 @@ lookup_mac_pte( kernel_vars_t *kv, ulong + + /* look in secondary PTEG */ + p = (ulong*)( (ulong)MMU.hash_base + (pteg ^ (mask << 6)) ); +- cmp |= BIT(25); ++ cmp |= MOL_BIT(25); + + for( i=0; i<8; i++,p+=2 ) + if( cmp == *p ) +@@ -300,7 +300,7 @@ find_pte_slot( ulong ea, ulong *pte0, in + + /* look in secondary PTEG */ + p = secondary; +- cmp |= BIT(25); ++ cmp |= MOL_BIT(25); + for( i=0; i<8; i++, p+=2 ) + if( cmp == *p ) { + *pte0 |= PTE0_H; +@@ -314,12 +314,12 @@ find_pte_slot( ulong ea, ulong *pte0, in + + /* free slot in primary PTEG? */ + for( p=primary, i=0; i<8; i++, p+=2 ) +- if( !(*p & BIT(0)) ) ++ if( !(*p & MOL_BIT(0)) ) + return p; + + /* free slot in secondary PTEG? */ + for( p=secondary, i=0; i<8; i++, p+=2 ) +- if( !(*p & BIT(0)) ) { ++ if( !(*p & MOL_BIT(0)) ) { + *pte0 |= PTE0_H; + return p; + } +--- a/drivers/macintosh/mol/include/asmdbg.h ++++ b/drivers/macintosh/mol/include/asmdbg.h +@@ -124,7 +124,7 @@ MACRO(PERF_MONITOR_GET, [ + lwz r5,xDEBUG_SCR1(r1) + ]) + MACRO(PERF_MONITOR_SETUP, [scr], [ +- LOADI _scr,BIT(2) | BIT(3) | BIT(31) // count in SV-mode if PM is zero. ++ LOADI _scr,MOL_BIT(2) | MOL_BIT(3) | MOL_BIT(31) // count in SV-mode if PM is zero. + mtspr S_MMCR0,_scr + li _scr,0 + mtspr S_MMCR1,_scr +--- a/drivers/macintosh/mol/include/asmdefs.h ++++ b/drivers/macintosh/mol/include/asmdefs.h +@@ -391,7 +391,7 @@ MACRO(ori_, [reg1, reg2, value], [ + #define EXTERN( name ) _##name + #endif + +-#define BIT(n) (1<<(31-(n))) ++#define MOL_BIT(n) (1<<(31-(n))) + + #endif /* _H_ASMDEFS */ + +--- a/drivers/macintosh/mol/include/mac_registers.h ++++ b/drivers/macintosh/mol/include/mac_registers.h +@@ -111,7 +111,7 @@ typedef struct mac_regs { /* this stru + + #define NUM_MREGS_PAGES ((sizeof(mac_regs_t)+0xfff)/0x1000) + +-#define BIT(n) (1U<<(31-(n))) /* bit 0 is MSB */ ++#define MOL_BIT(n) (1U<<(31-(n))) /* bit 0 is MSB */ + + #ifndef __KERNEL__ + extern mac_regs_t *mregs; +@@ -152,17 +152,17 @@ extern mac_regs_t *mregs; + + + #ifdef __KERNEL__ +-#define fb_DbgTrace BIT( FBIT_DbgTrace ) +-#define fb_Trace BIT( FBIT_Trace ) +-#define fb_PrepareSplitmode BIT( FBIT_PrepareSplitmode ) +-#define fb_InSplitmode BIT( FBIT_InSplitmode ) +-#define fb_LoadSegreg BIT( FBIT_LoadSegreg ) ++#define fb_DbgTrace MOL_BIT( FBIT_DbgTrace ) ++#define fb_Trace MOL_BIT( FBIT_Trace ) ++#define fb_PrepareSplitmode MOL_BIT( FBIT_PrepareSplitmode ) ++#define fb_InSplitmode MOL_BIT( FBIT_InSplitmode ) ++#define fb_LoadSegreg MOL_BIT( FBIT_LoadSegreg ) + #endif +-#define fb_MsrModified BIT( FBIT_MsrModified ) +-#define fb_RecalcDecInt BIT( FBIT_RecalcDecInt ) +-#define fb_IRQPending BIT( FBIT_IRQPending ) ++#define fb_MsrModified MOL_BIT( FBIT_MsrModified ) ++#define fb_RecalcDecInt MOL_BIT( FBIT_RecalcDecInt ) ++#define fb_IRQPending MOL_BIT( FBIT_IRQPending ) + #ifdef EMULATE_603 +-#define fb_603_AltGPR BIT( FBIT_603_AltGPR ) ++#define fb_603_AltGPR MOL_BIT( FBIT_603_AltGPR ) + #endif + + #endif /* _MAC_REGISTERS_H */ +--- a/drivers/macintosh/mol/include/processor.h ++++ b/drivers/macintosh/mol/include/processor.h +@@ -18,16 +18,16 @@ + + + #define PTE0_VSID(s) (((s)>>7) & 0xffffff) +-#define PTE0_V BIT(0) +-#define PTE0_H BIT(25) ++#define PTE0_V MOL_BIT(0) ++#define PTE0_H MOL_BIT(25) + #define PTE0_API 0x3f + +-#define PTE1_R BIT(23) +-#define PTE1_C BIT(24) +-#define PTE1_W BIT(25) +-#define PTE1_I BIT(26) +-#define PTE1_M BIT(27) +-#define PTE1_G BIT(28) ++#define PTE1_R MOL_BIT(23) ++#define PTE1_C MOL_BIT(24) ++#define PTE1_W MOL_BIT(25) ++#define PTE1_I MOL_BIT(26) ++#define PTE1_M MOL_BIT(27) ++#define PTE1_G MOL_BIT(28) + #ifdef CONFIG_AMIGAONE + /* Memory coherence locks up A1 compatible systems. */ + #define PTE1_WIMG (PTE1_W | PTE1_I | PTE1_G) +@@ -37,9 +37,9 @@ + #define PTE1_PP 0x3 + #define PTE1_RPN (~0xfffUL) + +-#define VSID_Ks BIT(1) +-#define VSID_Kp BIT(2) +-#define VSID_N BIT(3) ++#define VSID_Ks MOL_BIT(1) ++#define VSID_Kp MOL_BIT(2) ++#define VSID_N MOL_BIT(3) + + + +@@ -236,30 +236,30 @@ + #define HID0_BHT (1<<2) /* Branch History Table Enable */ + #define HID0_BTCD (1<<1) /* Branch target cache disable */ + +-#define L2CR_L2E BIT(0) /* L2 enable */ +-#define L2CR_L2PE BIT(1) /* L2 data parity generation and checking */ +-#define L2CR_L2SIZ_512K BIT(2) +-#define L2CR_L2SIZ_256K BIT(3) +-#define L2CR_L2SIZ_1MB (BIT(2)|BIT(3)) +-#define L2CR_L2CLK_1 BIT(6) /* L2 clock ration */ +-#define L2CR_L2CLK_15 (BIT(6)*2) +-#define L2CR_L2CLK_2 (BIT(6)*4) +-#define L2CR_L2CLK_25 (BIT(6)*5) +-#define L2CR_L2CLK_3 (BIT(6)*6) ++#define L2CR_L2E MOL_BIT(0) /* L2 enable */ ++#define L2CR_L2PE MOL_BIT(1) /* L2 data parity generation and checking */ ++#define L2CR_L2SIZ_512K MOL_BIT(2) ++#define L2CR_L2SIZ_256K MOL_BIT(3) ++#define L2CR_L2SIZ_1MB (MOL_BIT(2)|MOL_BIT(3)) ++#define L2CR_L2CLK_1 MOL_BIT(6) /* L2 clock ration */ ++#define L2CR_L2CLK_15 (MOL_BIT(6)*2) ++#define L2CR_L2CLK_2 (MOL_BIT(6)*4) ++#define L2CR_L2CLK_25 (MOL_BIT(6)*5) ++#define L2CR_L2CLK_3 (MOL_BIT(6)*6) + #define L2CR_L2RAM_FT 0 /* flow-through (reg-buf) synchronous SRAM */ +-#define L2CR_L2RAM_PB BIT(7) /* Piplined (reg-reg) synchronous burst SRAM */ +-#define L2CR_L2RAM_PLW (BIT(7)|BIT(8)) /* Piplined (reg-reg) synchronous late-write */ +-#define L2CR_L2DO BIT(9) /* L2 data-only */ +-#define L2CR_L2I BIT(10) /* L2 global invalidate */ +-#define L2CR_L2CTL BIT(11) /* L2 RAM control (ZZ enable, low-power mode) */ +-#define L2CR_L2WT BIT(12) /* L2 write-through */ +-#define L2CR_L2TS BIT(13) /* L2 test support */ ++#define L2CR_L2RAM_PB MOL_BIT(7) /* Piplined (reg-reg) synchronous burst SRAM */ ++#define L2CR_L2RAM_PLW (MOL_BIT(7)|MOL_BIT(8)) /* Piplined (reg-reg) synchronous late-write */ ++#define L2CR_L2DO MOL_BIT(9) /* L2 data-only */ ++#define L2CR_L2I MOL_BIT(10) /* L2 global invalidate */ ++#define L2CR_L2CTL MOL_BIT(11) /* L2 RAM control (ZZ enable, low-power mode) */ ++#define L2CR_L2WT MOL_BIT(12) /* L2 write-through */ ++#define L2CR_L2TS MOL_BIT(13) /* L2 test support */ + #define L2CR_L2OH_05 0 /* L2 output hold 0.5 nS */ +-#define L2CR_L2OH_10 BIT(15) /* L2 output hold 1.0 nS */ +-#define L2CR_L2SL BIT(16) /* L2 DLL slow (use if bus freq < 150 MHz) */ +-#define L2CR_L2DF BIT(17) /* L2 differential clock */ +-#define L2CR_L2BYP BIT(18) /* L2 DLL bypass */ +-#define L2CR_L2IP BIT(31) /* L2 global invalidate in progress */ ++#define L2CR_L2OH_10 MOL_BIT(15) /* L2 output hold 1.0 nS */ ++#define L2CR_L2SL MOL_BIT(16) /* L2 DLL slow (use if bus freq < 150 MHz) */ ++#define L2CR_L2DF MOL_BIT(17) /* L2 differential clock */ ++#define L2CR_L2BYP MOL_BIT(18) /* L2 DLL bypass */ ++#define L2CR_L2IP MOL_BIT(31) /* L2 global invalidate in progress */ + + /* SPR_THRM1 */ + #define THRM1_TIN (1 << 31) +--- a/drivers/macintosh/mol/mmu_fb.c ++++ b/drivers/macintosh/mol/mmu_fb.c +@@ -160,7 +160,7 @@ get_dirty_fb_lines( kernel_vars_t *kv, s + p->slot = NULL; + p->dirty = 1; + __tlbie( p->ea ); +- } else if( p->slot[1] & BIT(24) ) { /* C-BIT */ ++ } else if( p->slot[1] & MOL_BIT(24) ) { /* C-BIT */ + p->dirty = 1; + __store_PTE( p->ea, p->slot, p->pte0, p->pte1 ); + BUMP(fb_ptec_flush); +--- a/drivers/macintosh/mol/mmu_io.c ++++ b/drivers/macintosh/mol/mmu_io.c +@@ -129,13 +129,13 @@ bat_align( int flags, ulong ea, ulong lp + bat[1] = (lphys & ~(s-1)) | 2; /* pp=10, R/W */ + + #ifndef CONFIG_AMIGAONE +- bat[1] |= BIT(27); /* [M] (memory coherence) */ ++ bat[1] |= MOL_BIT(27); /* [M] (memory coherence) */ + #endif + + if( !(flags & MAPPING_FORCE_CACHE) ) { +- bat[1] |= BIT(26); /* [I] (inhibit cache) */ ++ bat[1] |= MOL_BIT(26); /* [I] (inhibit cache) */ + } else { +- bat[1] |= BIT(25); /* [W] (write through) */ ++ bat[1] |= MOL_BIT(25); /* [W] (write through) */ + } + return 0; + } +--- a/drivers/macintosh/mol/mtable.c ++++ b/drivers/macintosh/mol/mtable.c +@@ -45,10 +45,10 @@ struct pterec { + uint pent; /* defined below */ + }; + +-#define PENT_LV_HEAD BIT(0) /* Resident - do not put on free list */ +-#define PENT_UNUSED BIT(1) /* (lvhead) PTE index is not valid */ +-#define PENT_EA_BIT14 BIT(2) /* for the partial ea used by tlbie */ +-#define PENT_EA_LAST BIT(3) /* next entry is the pelist pointer */ ++#define PENT_LV_HEAD MOL_BIT(0) /* Resident - do not put on free list */ ++#define PENT_UNUSED MOL_BIT(1) /* (lvhead) PTE index is not valid */ ++#define PENT_EA_BIT14 MOL_BIT(2) /* for the partial ea used by tlbie */ ++#define PENT_EA_LAST MOL_BIT(3) /* next entry is the pelist pointer */ + #define PENT_TOPEA_MASK 0x0f800000 /* bit 4-8 of ea */ + #define PENT_SV_BIT 0x00400000 /* PTE uses vsid_sv */ + #define PENT_INDEX_MASK 0x003fffff /* PTE index (there can be at most 2^22 PTEs) */ +@@ -675,7 +675,7 @@ pte_inserted( kernel_vars_t *kv, ulong e + + /* get_free_pent inserts the entry into the lvring and sets a few pent bits */ + pr = get_free_pent(vi, lvrange, lvptr); +- pr->pent |= PTE_TO_IND(pte) | pent_cmp | ((ea & BIT(14)) ? PENT_EA_BIT14 : 0); ++ pr->pent |= PTE_TO_IND(pte) | pent_cmp | ((ea & MOL_BIT(14)) ? PENT_EA_BIT14 : 0); + + /* insert in (non-empty) ea ring */ + pr->ea_next = *pp; +@@ -684,7 +684,7 @@ pte_inserted( kernel_vars_t *kv, ulong e + /* ea ring was empty */ + pr = *pp = get_free_pent(vi, lvrange, lvptr); + pr->pent |= PENT_EA_LAST | PTE_TO_IND(pte) | pent_cmp +- | ((ea & BIT(14)) ? PENT_EA_BIT14 : 0); ++ | ((ea & MOL_BIT(14)) ? PENT_EA_BIT14 : 0); + pr->ea_next = (pterec_t*)pp; + } + out: +--- a/drivers/macintosh/mol/ptaccess.c ++++ b/drivers/macintosh/mol/ptaccess.c +@@ -39,7 +39,7 @@ do_intercept_tlbie( kernel_vars_t *kv, u + clear_bit_mol( pteoffs >> 3, MMU.pthash_inuse_bits ); + + v = (pteoffs >> 6); +- if( pte0 & BIT(25) ) /* secondary hash? */ ++ if( pte0 & MOL_BIT(25) ) /* secondary hash? */ + v = ~v; + v ^= (pte0 >> 7); + v = ((pte0 << 10) & 0xfc00) | (v & 0x3ff); +@@ -93,7 +93,7 @@ do_tlbli( kernel_vars_t *kv, ulong ea ) + mPTE_t *p; + + //printk("do_tlbli %08lX : %08lX %08lX\n", ea, MREGS.spr[S_ICMP], MREGS.spr[S_RPA] ); +- if( MREGS.spr[S_SRR1] & BIT(14) ) ++ if( MREGS.spr[S_SRR1] & MOL_BIT(14) ) + ind += 32; + + p = &MMU.ptes_i_603[ind]; +@@ -114,7 +114,7 @@ do_tlbld( kernel_vars_t *kv, ulong ea ) + + //printk("do_tlbld %08lX\n", ea ); + +- if( MREGS.spr[S_SRR1] & BIT(14) ) ++ if( MREGS.spr[S_SRR1] & MOL_BIT(14) ) + ind += 32; + + p = &MMU.ptes_d_603[ind]; diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-get-property b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-get-property new file mode 100644 index 000000000..7003228aa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-get-property @@ -0,0 +1,18 @@ +Subject: mol build fix +From: schwab@suse.de + +--- + drivers/macintosh/mol/_dev.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/macintosh/mol/_dev.c ++++ b/drivers/macintosh/mol/_dev.c +@@ -85,7 +85,7 @@ find_physical_rom( int *base, int *size + } + #endif /* < Linux 2.6.21 */ + do { +- if( !(p=(int*)get_property(dn, "reg", &len)) || len != sizeof(int[2]) ) { ++ if( !(p=of_get_property(dn, "reg", &len)) || len != sizeof(int[2]) ) { + of_node_put(dn); + return 0; + } diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-handle-mm-fault b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-handle-mm-fault new file mode 100644 index 000000000..bd42e9365 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-handle-mm-fault @@ -0,0 +1,25 @@ +From: Jeff Mahoney +Subject: [PATCH] mm: re-export handle_mm_fault for Mac On Linux +Patch-mainline: probably never + + This patch reverts git commit 41f9dc5c871600f53c8912b2975971d2a11c1c25, + which removed the handle_mm_fault export when spufs became a builtin. + + Mac On Linux requires this to be exported. + +Signed-off-by: Jeff Mahoney + +--- + mm/memory.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2803,6 +2803,7 @@ int handle_mm_fault(struct mm_struct *mm + + return handle_pte_fault(mm, vma, address, pte, pmd, write_access); + } ++EXPORT_SYMBOL_GPL(handle_mm_fault); /* For MoL */ + + #ifndef __PAGETABLE_PUD_FOLDED + /* diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-ioctl b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-ioctl new file mode 100644 index 000000000..f47af8046 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-ioctl @@ -0,0 +1,18 @@ +From: schwab@suse.de +Subject: mol build fix +Patch-mainline: never + + drivers/macintosh/mol/include/mol-ioctl.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/macintosh/mol/include/mol-ioctl.h ++++ b/drivers/macintosh/mol/include/mol-ioctl.h +@@ -17,6 +17,8 @@ + #ifndef _H_MOL_IOCTL + #define _H_MOL_IOCTL + ++#include ++ + #ifndef __ASSEMBLY__ + #include "mmutypes.h" + diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-kbuild.patch b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-kbuild.patch new file mode 100644 index 000000000..76129dc73 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-kbuild.patch @@ -0,0 +1,96 @@ +From: olh@suse.de +Subject: kbuild part +Patch-mainline: never + + drivers/macintosh/Kconfig | 6 ++++ + drivers/macintosh/Makefile | 2 + + drivers/macintosh/mol/Makefile | 60 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 68 insertions(+) + +--- a/drivers/macintosh/Kconfig ++++ b/drivers/macintosh/Kconfig +@@ -253,4 +253,10 @@ config PMAC_RACKMETER + This driver provides some support to control the front panel + blue LEDs "vu-meter" of the XServer macs. + ++config MACONLINUX ++ tristate "Mac on Linux kernel module" ++ depends on PPC32 && PPC_PMAC && MODULES && NET ++ help ++ call helpdesk ++ + endif # MACINTOSH_DRIVERS +--- a/drivers/macintosh/Makefile ++++ b/drivers/macintosh/Makefile +@@ -4,6 +4,8 @@ + + # Each configuration option enables a list of files. + ++obj-$(CONFIG_MACONLINUX) += mol/ ++ + obj-$(CONFIG_PPC_PMAC) += macio_asic.o macio_sysfs.o + + obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o +--- /dev/null ++++ b/drivers/macintosh/mol/Makefile +@@ -0,0 +1,60 @@ ++ ++MOL_OBJS = \ ++ _fault.o \ ++ _dev.o \ ++ _misc.o \ ++ _mmu.o \ ++ _hostirq.o \ ++ init.o \ ++ hash.o \ ++ emu.o \ ++ mmu.o \ ++ mmu_fb.o \ ++ mmu_io.o \ ++ mmu_tracker.o \ ++ skiplist.o \ ++ mtable.o \ ++ fault.o \ ++ context.o \ ++ ptaccess.o \ ++ misc.o \ ++ _traps.o \ ++ actions.o ++ ++ ++mol-objs := $(MOL_OBJS) ++obj-m := mol.o sheep.o ++ ++MOL_SRC_INCLUDE_DIR := $(srctree)/$(src)/include ++MOL_OBJ_INCLUDE_DIR := $(obj)/include ++MOL_ASMFLAGS := $(ASMFLAGS) $(INCLUDES) -D__ASSEMBLY__ -D__KERNEL__ ++EXTRA_CFLAGS := -I$(MOL_SRC_INCLUDE_DIR) -I$(MOL_OBJ_INCLUDE_DIR) ++ ++$(obj)/asm_offsets.c: $(srctree)/$(src)/asm_offsets.c $(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h ++ rm -f $@ ++ cat $(srctree)/$(src)/asm_offsets.c $(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h > $@ ++ ++$(obj)/_traps.o: $(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h $(srctree)/$(src)/asm-files/*.S ++ ++$(obj)/_%.o: $(src)/asm-files/%.S ++ echo " AS [x] $@" ++ rm -f $@ $@.s ++ $(CPP) $(LINUXINCLUDE) -I$(MOL_SRC_INCLUDE_DIR) -I$(MOL_OBJ_INCLUDE_DIR) $(MOL_ASMFLAGS) $< | m4 > $@.m4 ++ cat $@.m4 > $@.s ++ $(AS) $@.s $(AS_FLAGS) -o $@ ++ rm -f $@.s $@.m4 ++ ++$(addprefix $(obj)/,$(MOL_OBJS)): $(obj)/%.o: $(MOL_OBJ_INCLUDE_DIR)/kconfig.h ++$(MOL_OBJ_INCLUDE_DIR)/kconfig.h: ++ mkdir -vp $(MOL_OBJ_INCLUDE_DIR) ++ rm -fv $@ ++ echo "/* nothing */" > $@ ++ ++$(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h: $(MOL_SRC_INCLUDE_DIR)/archinclude.h $(MOL_SRC_INCLUDE_DIR)/kernel_vars.h $(MOL_SRC_INCLUDE_DIR)/mac_registers.h $(MOL_OBJ_INCLUDE_DIR)/kconfig.h ++$(MOL_OBJ_INCLUDE_DIR)/asm_offsets.h: $(srctree)/$(src)/asm_offsets.c $(MOL_SRC_INCLUDE_DIR)/asm_offsets.inc ++ rm -fv $(obj)/tmp-offsets.c $@ ; cat $^ > $(obj)/tmp-offsets.c ++ $(CC) -D__KERNEL__ $(CFLAGS) $(LINUXINCLUDE) -I$(MOL_SRC_INCLUDE_DIR) -I$(MOL_OBJ_INCLUDE_DIR) -Wall -S $(obj)/tmp-offsets.c ++ echo "/* WARNING! Automatically generated from 'shared/asm_offsets.c' - DO NOT EDIT! */" > $@ ++ grep '^#' tmp-offsets.s >> $@ ++ rm -fv $(obj)/tmp-offsets.* ++ diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-semaphore b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-semaphore new file mode 100644 index 000000000..be4459d7a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-semaphore @@ -0,0 +1,19 @@ +Subject: mol build fix +From: schwab@suse.de + +--- + drivers/macintosh/mol/include/archinclude.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/macintosh/mol/include/archinclude.h ++++ b/drivers/macintosh/mol/include/archinclude.h +@@ -42,6 +42,9 @@ + + #ifndef __ASSEMBLY__ + #include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++#include ++#endif + #include + #include /* needed by */ + #include diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-sheep b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-sheep new file mode 100644 index 000000000..9908c4b4c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol-sheep @@ -0,0 +1,27 @@ +Subject: mol build fix +From: schwab@suse.de + +--- + drivers/macintosh/mol/sheep.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/macintosh/mol/sheep.c ++++ b/drivers/macintosh/mol/sheep.c +@@ -82,7 +82,7 @@ struct SheepVars { + #ifdef LINUX_26 + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) +-#define compat_sk_alloc(a,b,c) sk_alloc( (a), (b), &mol_proto, 1 ) ++#define compat_sk_alloc(a,b,c) sk_alloc(&init_net, (a), (b), &mol_proto) + #else + #define compat_sk_alloc(a,b,c) sk_alloc( (a), (b), (c), NULL ) + #endif +@@ -558,7 +558,7 @@ sheep_net_ioctl( struct inode *inode, st + name[19] = 0; + + // Find card +- if( !(v->ether=dev_get_by_name(name)) ) ++ if( !(v->ether=dev_get_by_name(&init_net, name)) ) + return -ENODEV; + + // Is it Ethernet? diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol.patch b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol.patch new file mode 100644 index 000000000..8b401f57b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc32-mol.patch @@ -0,0 +1,14751 @@ +From: olh@suse.de +Subject: vanilla sources from www.maconlinux.org +Patch-mainline: never + +to avoid the km_ mess + +Never modify this patch! Create new patches for build fixes. + +--- + drivers/macintosh/mol/_dev.c | 376 ++++++++++ + drivers/macintosh/mol/_fault.c | 159 ++++ + drivers/macintosh/mol/_hostirq.c | 116 +++ + drivers/macintosh/mol/_kuname.c | 48 + + drivers/macintosh/mol/_misc.c | 147 +++ + drivers/macintosh/mol/_mmu.c | 41 + + drivers/macintosh/mol/actions.c | 548 ++++++++++++++ + drivers/macintosh/mol/asm-files/603.S | 218 +++++ + drivers/macintosh/mol/asm-files/dec.S | 228 ++++++ + drivers/macintosh/mol/asm-files/emuaccel.S | 188 +++++ + drivers/macintosh/mol/asm-files/emulation.S | 714 +++++++++++++++++++ + drivers/macintosh/mol/asm-files/entry.S | 433 +++++++++++ + drivers/macintosh/mol/asm-files/iopage.S | 89 ++ + drivers/macintosh/mol/asm-files/linux.S | 129 +++ + drivers/macintosh/mol/asm-files/ptintercept.S | 303 ++++++++ + drivers/macintosh/mol/asm-files/splitmode.S | 428 +++++++++++ + drivers/macintosh/mol/asm-files/traps.S | 501 +++++++++++++ + drivers/macintosh/mol/asm-files/vsid.S | 123 +++ + drivers/macintosh/mol/asm_offsets.c | 161 ++++ + drivers/macintosh/mol/context.c | 99 ++ + drivers/macintosh/mol/emu.c | 228 ++++++ + drivers/macintosh/mol/fault.c | 601 ++++++++++++++++ + drivers/macintosh/mol/hash.c | 126 +++ + drivers/macintosh/mol/include/actions.h | 177 ++++ + drivers/macintosh/mol/include/alloc.h | 70 + + drivers/macintosh/mol/include/archinclude.h | 77 ++ + drivers/macintosh/mol/include/asm.m4 | 141 +++ + drivers/macintosh/mol/include/asm_offsets.inc | 136 +++ + drivers/macintosh/mol/include/asmdbg.h | 184 ++++ + drivers/macintosh/mol/include/asmdefs.h | 397 ++++++++++ + drivers/macintosh/mol/include/asmfuncs.h | 80 ++ + drivers/macintosh/mol/include/atomic.h | 26 + drivers/macintosh/mol/include/config.h | 90 ++ + drivers/macintosh/mol/include/constants.h | 36 + drivers/macintosh/mol/include/context.h | 62 + + drivers/macintosh/mol/include/dbg.h | 31 + drivers/macintosh/mol/include/debugger.h | 96 ++ + drivers/macintosh/mol/include/emu.h | 29 + drivers/macintosh/mol/include/emuaccel_sh.h | 41 + + drivers/macintosh/mol/include/extralib.h | 70 + + drivers/macintosh/mol/include/hash.h | 36 + drivers/macintosh/mol/include/kernel_vars.h | 225 ++++++ + drivers/macintosh/mol/include/locks.h | 39 + + drivers/macintosh/mol/include/mac_registers.h | 168 ++++ + drivers/macintosh/mol/include/map.h | 43 + + drivers/macintosh/mol/include/misc.h | 105 ++ + drivers/macintosh/mol/include/mmu.h | 102 ++ + drivers/macintosh/mol/include/mmu_contexts.h | 55 + + drivers/macintosh/mol/include/mmu_mappings.h | 48 + + drivers/macintosh/mol/include/mmutypes.h | 76 ++ + drivers/macintosh/mol/include/mol-ioctl.h | 121 +++ + drivers/macintosh/mol/include/mol_config.h | 76 ++ + drivers/macintosh/mol/include/molasm.h | 138 +++ + drivers/macintosh/mol/include/molversion.h | 6 + drivers/macintosh/mol/include/mtable.h | 71 + + drivers/macintosh/mol/include/osi.h | 170 ++++ + drivers/macintosh/mol/include/osi_calls.h | 475 ++++++++++++ + drivers/macintosh/mol/include/performance.h | 71 + + drivers/macintosh/mol/include/platform.h | 73 + + drivers/macintosh/mol/include/processor.h | 409 +++++++++++ + drivers/macintosh/mol/include/prom.h | 46 + + drivers/macintosh/mol/include/rvec.h | 147 +++ + drivers/macintosh/mol/include/skiplist.h | 87 ++ + drivers/macintosh/mol/include/tlbie.h | 102 ++ + drivers/macintosh/mol/include/uaccess.h | 36 + drivers/macintosh/mol/include/vector.h | 189 +++++ + drivers/macintosh/mol/include/version.h | 11 + drivers/macintosh/mol/include/weaksym.h | 39 + + drivers/macintosh/mol/init.c | 191 +++++ + drivers/macintosh/mol/misc.c | 255 ++++++ + drivers/macintosh/mol/mmu.c | 251 ++++++ + drivers/macintosh/mol/mmu_fb.c | 186 +++++ + drivers/macintosh/mol/mmu_io.c | 470 ++++++++++++ + drivers/macintosh/mol/mmu_tracker.c | 128 +++ + drivers/macintosh/mol/mtable.c | 960 ++++++++++++++++++++++++++ + drivers/macintosh/mol/ptaccess.c | 153 ++++ + drivers/macintosh/mol/sheep.c | 701 ++++++++++++++++++ + drivers/macintosh/mol/skiplist.c | 222 ++++++ + 78 files changed, 14428 insertions(+) + +--- /dev/null ++++ b/drivers/macintosh/mol/_dev.c +@@ -0,0 +1,376 @@ ++/* ++ * Creation Date: <2003/08/20 17:31:44 samuel> ++ * Time-stamp: <2004/02/14 14:43:13 samuel> ++ * ++ * ++ * ++ * misc device ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#include "archinclude.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "kernel_vars.h" ++#include "mol-ioctl.h" ++#include "version.h" ++#include "mmu.h" ++#include "misc.h" ++#include "mtable.h" ++#include "atomic.h" ++ ++MODULE_AUTHOR("Samuel Rydh "); ++MODULE_DESCRIPTION("Mac-on-Linux kernel module"); ++MODULE_LICENSE("GPL"); ++ ++static DECLARE_MUTEX( initmutex ); ++static int opencnt; ++ ++ ++/************************************************************************/ ++/* misc */ ++/************************************************************************/ ++ ++#ifdef CONFIG_SMP ++#define HAS_SMP 1 ++ ++static void ++dummy_ipi( void *dummy ) ++{ ++ /* we don't need to _do_ anything, the exception itself is sufficient */ ++} ++static inline void ++send_ipi( void ) ++{ ++ smp_call_function( dummy_ipi, NULL, 1, 0 ); ++} ++#else /* CONFIG_SMP */ ++ ++#define HAS_SMP 0 ++#define send_ipi() do {} while(0) ++ ++#endif /* CONFIG_SMP */ ++ ++ ++static int ++find_physical_rom( int *base, int *size ) ++{ ++#ifndef CONFIG_AMIGAONE ++ struct device_node *dn; ++ int len, *p; ++ int by_type = 0; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) ++ if( !(dn=find_devices("boot-rom")) && !(dn=find_type_devices("rom")) ) ++ return 0; ++#else ++ if (! (dn = of_find_node_by_name(NULL, "boot-rom"))) { ++ by_type = 1; ++ if (! (dn = of_find_node_by_type(NULL, "rom"))) ++ return 0; ++ } ++#endif /* < Linux 2.6.21 */ ++ do { ++ if( !(p=(int*)get_property(dn, "reg", &len)) || len != sizeof(int[2]) ) { ++ of_node_put(dn); ++ return 0; ++ } ++ if( (unsigned int)(0xfff00100 - p[0]) < (unsigned int)p[1] ) { ++ *base = p[0]; ++ *size = p[1]; ++ of_node_put(dn); ++ return 1; ++ } ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21) ++ dn = dn->next; ++#else ++ dn = by_type ? of_find_node_by_type(dn, "rom") : ++ of_find_node_by_name(dn, "boot-rom"); ++#endif /* < Linux 2.6.21 */ ++ } while( dn ); ++#endif /* CONFIG_AMIGA_ONE */ ++ return 0; ++} ++ ++static int ++get_info( mol_kmod_info_t *user_retinfo, int size ) ++{ ++ mol_kmod_info_t info; ++ ++ memset( &info, 0, sizeof(info) ); ++ asm volatile("mfpvr %0" : "=r" (info.pvr) : ); ++ info.version = MOL_VERSION; ++ find_physical_rom( &info.rombase, &info.romsize ); ++ info.tb_freq = HZ * tb_ticks_per_jiffy; ++ info.smp_kernel = HAS_SMP; ++ ++ if( (uint)size > sizeof(info) ) ++ size = sizeof(info); ++ ++ if( copy_to_user(user_retinfo, &info, size) ) ++ return -EFAULT; ++ return 0; ++} ++ ++ ++void ++prevent_mod_unload( void ) ++{ ++#ifndef LINUX_26 ++ MOD_INC_USE_COUNT; ++#else ++ __module_get( THIS_MODULE ); ++#endif ++} ++ ++int ++get_irqs( kernel_vars_t *kv, irq_bitfield_t *irq_info_p ) ++{ ++ irq_bitfield_t irq_mask; ++ int i; ++ ++ /* copy the interrupt mask from userspace */ ++ if (copy_from_user(&irq_mask, irq_info_p, sizeof(irq_mask))) ++ return -EFAULT; ++ ++ /* see which of the mapped interrupts need to be enabled */ ++ for (i = 0; i < NR_HOST_IRQS; i++) { ++ if (check_bit_mol(i, (char *) kv->mregs.mapped_irqs.irqs) ++ && check_bit_mol(i, (char *) irq_mask.irqs) ++ && check_bit_mol(i, (char *) kv->mregs.active_irqs.irqs)) { ++ if (test_and_clear_bit(i, kv->mregs.active_irqs.irqs)) ++ atomic_dec_mol((mol_atomic_t *) &(kv->mregs.hostirq_active_cnt)); ++ enable_irq(i); ++ } ++ } ++ ++ /* if one of the enabled interrupts was pending, it should have fired ++ * now, updating active_irqs */ ++ if (copy_to_user(irq_info_p, &(kv->mregs.active_irqs), sizeof(kv->mregs.active_irqs))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/************************************************************************/ ++/* ioctl */ ++/************************************************************************/ ++ ++static int ++debugger_op( kernel_vars_t *kv, dbg_op_params_t *upb ) ++{ ++ dbg_op_params_t pb; ++ int ret; ++ ++ if( copy_from_user(&pb, upb, sizeof(pb)) ) ++ return -EFAULT; ++ ++ switch( pb.operation ) { ++ case DBG_OP_GET_PHYS_PAGE: ++ ret = dbg_get_linux_page( pb.ea, &pb.ret.page ); ++ break; ++ default: ++ ret = do_debugger_op( kv, &pb ); ++ break; ++ } ++ ++ if( copy_to_user(upb, &pb, sizeof(pb)) ) ++ return -EFAULT; ++ return ret; ++} ++ ++static int ++arch_handle_ioctl( kernel_vars_t *kv, int cmd, int p1, int p2, int p3 ) ++{ ++ char *rompage; ++ int ret = -EFAULT; ++ ++ switch( cmd ) { ++ case MOL_IOCTL_GET_IRQS: ++ return get_irqs( kv, (irq_bitfield_t *) p1 ); ++ ++ case MOL_IOCTL_GET_DIRTY_FBLINES: /* short *retbuf, int size -- npairs */ ++ if( compat_verify_area(VERIFY_WRITE, (short*)p1, p2) ) ++ break; ++ ret = get_dirty_fb_lines( kv, (short*)p1, p2 ); ++ break; ++ ++ case MOL_IOCTL_DEBUGGER_OP: ++ ret = debugger_op( kv, (dbg_op_params_t*)p1 ); ++ break; ++ ++ case MOL_IOCTL_GRAB_IRQ: ++ ret = grab_host_irq(kv, p1); ++ break; ++ ++ case MOL_IOCTL_RELEASE_IRQ: ++ ret = release_host_irq(kv, p1); ++ break; ++ ++ case MOL_IOCTL_COPY_LAST_ROMPAGE: /* p1 = dest */ ++ ret = -ENODEV; ++ if( (rompage=ioremap(0xfffff000, 0x1000)) ) { ++ ret = copy_to_user( (char*)p1, rompage, 0x1000 ); ++ iounmap( rompage ); ++ } ++ break; ++ ++ case MOL_IOCTL_SET_RAM: /* void ( char *lvbase, size_t size ) */ ++ if( compat_verify_area(VERIFY_WRITE, (char*)p1, p2) ) ++ break; ++ ret = 0; ++ kv->mmu.userspace_ram_base = p1; ++ kv->mmu.ram_size = p2; ++ mtable_tune_alloc_limit( kv, p2/(1024 * 1024) ); ++ break; ++ ++ case MOL_IOCTL_GET_MREGS_PHYS: ++ ret = virt_to_phys( &kv->mregs ); ++ break; ++ ++ default: ++ ret = handle_ioctl( kv, cmd, p1, p2, p3 ); ++ break; ++ } ++ return ret; ++} ++ ++ ++/************************************************************************/ ++/* device interface */ ++/************************************************************************/ ++ ++static int ++mol_open( struct inode *inode, struct file *file ) ++{ ++ int ret=0; ++ ++ if( !(file->f_mode & FMODE_READ) ) ++ return -EPERM; ++ ++ down( &initmutex ); ++ if( !opencnt++ ) { ++ if( common_init() ) { ++ ret = -ENOMEM; ++ opencnt = 0; ++ } ++ } ++ up( &initmutex ); ++ ++ file->private_data = NULL; ++ return ret; ++} ++ ++static int ++mol_release( struct inode *inode, struct file *file ) ++{ ++ kernel_vars_t *kv = (kernel_vars_t*)file->private_data; ++ ++ down( &initmutex ); ++ if( kv ) ++ destroy_session( kv->session_index ); ++ ++ if( !--opencnt ) ++ common_cleanup(); ++ up( &initmutex ); ++ return 0; ++} ++ ++static int ++mol_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) ++{ ++ mol_ioctl_pb_t pb; ++ kernel_vars_t *kv; ++ int ret; ++ uint session; ++ ++ /* fast path */ ++ if( cmd == MOL_IOCTL_SMP_SEND_IPI ) { ++ send_ipi(); ++ return 0; ++ } ++ ++ if( copy_from_user(&pb, (void*)arg, sizeof(pb)) ) ++ return -EFAULT; ++ ++ switch( cmd ) { ++ case MOL_IOCTL_GET_INFO: ++ return get_info( (mol_kmod_info_t*)pb.arg1, pb.arg2 ); ++ ++ case MOL_IOCTL_CREATE_SESSION: ++ if( !(file->f_mode & FMODE_WRITE) || !capable(CAP_SYS_ADMIN) ) ++ return -EPERM; ++ ret = -EINVAL; ++ down( &initmutex ); ++ if( (uint)pb.arg1 < MAX_NUM_SESSIONS && !file->private_data ) { ++ if( !(ret=initialize_session(pb.arg1)) ) { ++ kv = g_sesstab->kvars[pb.arg1]; ++ init_MUTEX( &kv->ioctl_sem ); ++ file->private_data = kv; ++ } ++ } ++ up( &initmutex ); ++ return ret; ++ ++ case MOL_IOCTL_DBG_COPY_KVARS: ++ session = pb.arg1; ++ ret = -EINVAL; ++ down( &initmutex ); ++ if( session < MAX_NUM_SESSIONS && (kv=g_sesstab->kvars[session]) ) ++ ret = copy_to_user( (char*)pb.arg2, kv, sizeof(*kv) ); ++ up( &initmutex ); ++ return ret; ++ } ++ ++ if( !(kv=(kernel_vars_t*)file->private_data) ) ++ return -EINVAL; ++ ++ down( &kv->ioctl_sem ); ++ ret = arch_handle_ioctl( kv, cmd, pb.arg1, pb.arg2, pb.arg3 ); ++ up( &kv->ioctl_sem ); ++ ++ return ret; ++} ++ ++static struct file_operations mol_device_fops = { ++ .owner = THIS_MODULE, ++ .open = mol_open, ++ .release = mol_release, ++ .ioctl = mol_ioctl, ++// .poll = mol_poll, ++// .mmap: = mol_mmap, ++}; ++ ++static struct miscdevice mol_device = { ++ MISC_DYNAMIC_MINOR, "mol", &mol_device_fops ++}; ++ ++static int __init ++dev_register( void ) ++{ ++ printk("MOL %s kernel module loaded\n", MOL_RELEASE ); ++ return misc_register( &mol_device ); ++} ++ ++static void __exit ++dev_unregister( void ) ++{ ++ misc_deregister( &mol_device ); ++} ++ ++module_init( dev_register ); ++module_exit( dev_unregister ); +--- /dev/null ++++ b/drivers/macintosh/mol/_fault.c +@@ -0,0 +1,159 @@ ++/* ++ * Creation Date: <2002/06/08 21:01:54 samuel> ++ * Time-stamp: <2004/02/19 11:54:33 samuel> ++ * ++ * ++ * ++ * Linux part ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "mmu.h" ++#include "mmu_contexts.h" ++#include "asmfuncs.h" ++#include "emu.h" ++#include "misc.h" ++#include "rvec.h" ++#include "performance.h" ++#include "mol-ioctl.h" ++#include "mtable.h" ++ ++#ifdef CONFIG_HIGHPTE ++#error "MOL is currently incompatible with CONFIG_HIGHPTE" ++#endif ++ ++static inline ulong ++fix_pte( ulong *p, ulong set, ulong flags ) ++{ ++ unsigned long ret, tmp; ++ ++ __asm__ __volatile__("\n" ++ "1: lwarx %0,0,%3 \n" ++ " andc. %1,%5,%0 \n" ++ " addi %1,0,0 \n" ++ " bne- 2f \n" ++ " or %1,%0,%4 \n" ++ " stwcx. %1,0,%3 \n" ++ " bne- 1b \n" ++ "2: \n" ++ : "=&r" (tmp), "=&r" (ret), "=m" (*p) ++ : "r" (p), "r" (set), "r" (flags), "m" (*p) ++ : "cc" ); ++ return ret; ++} ++ ++/* ++ * Get physical page corresponding to linux virtual address. Invokes linux page ++ * fault handler if the page is missing. This function never fails since we ++ * know there is a valid mapping... ++ */ ++#define PAGE_BITS_WRITE (_PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HASHPTE ) ++#define PAGE_BITS_READ (_PAGE_ACCESSED | _PAGE_HASHPTE ) ++ ++ulong ++get_phys_page( kernel_vars_t *kv, ulong va, int request_rw ) ++{ ++ char *lvptr = (char*)va; ++ ulong lpte, uptr, *ptr; ++ ulong flags; ++ struct mm_struct *mm; ++ struct vm_area_struct *vma; ++ ++ /* pte bits that must be set */ ++ flags = request_rw ? (_PAGE_USER | _PAGE_RW | _PAGE_PRESENT) ++ : (_PAGE_USER | _PAGE_PRESENT); ++ ++ uptr = ((ulong*)current->thread.pgdir)[va>>22]; /* top 10 bits */ ++ ptr = (ulong*)(uptr & ~0xfff); ++ if( !ptr ) ++ goto no_page; ++#ifdef LINUX_26 ++ ptr = phys_to_virt( (int)ptr ); ++#endif ++ ptr = ptr + ((va>>12) & 0x3ff); /* next 10 bits */ ++ ++ /* this allows us to keep track of this page until we have ++ * added a full mtable entry for it. The reservation is lost if ++ * a TLB invalidation occurs. ++ */ ++ make_lvptr_reservation( kv, lvptr ); ++ ++ /* we atomically set _PAGE_HASHPTE after checking PAGE_PRESENT and PAGE_RW. ++ * We are then guaranteed to be notified about a TLB invalidation through the ++ * flush_hash_page hook. ++ */ ++ lpte = fix_pte( ptr, (request_rw? PAGE_BITS_WRITE : PAGE_BITS_READ), flags ); ++ ++ /* permissions violation */ ++ if( !lpte ) ++ goto no_page; ++ ++ return lpte & ~0xfff; ++ ++no_page: ++ BUMP( page_missing ); ++ ++ /* no mac page found... */ ++ mm = current->mm; ++ down_read( &mm->mmap_sem ); ++ ++ if( !(vma=find_vma(mm,va)) || vma->vm_start > va ) ++ goto bad_area; ++ if( !(vma->vm_flags & (request_rw ? VM_WRITE : (VM_READ | VM_EXEC))) ) ++ goto bad_area; ++ ++ handle_mm_fault( mm, vma, va, request_rw ); ++ ++ up_read( &mm->mmap_sem ); ++ return get_phys_page(kv, va, request_rw); ++ ++bad_area: ++ up_read( &mm->mmap_sem ); ++ printk("get_phys_page: BAD AREA, lvptr = %08lx\n", va ); ++ force_sig(SIGSEGV, current); ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* Debugger functions */ ++/************************************************************************/ ++ ++int ++dbg_get_linux_page( ulong va, dbg_page_info_t *r ) ++{ ++ ulong val, uptr, *ptr; ++ ++ uptr = ((ulong*)current->thread.pgdir)[va>>22]; /* top 10 bits */ ++ ptr = (ulong*)(uptr & ~0xfff); ++ if( !ptr ) ++ return 1; ++#ifdef LINUX_26 ++ ptr = phys_to_virt( (int)ptr ); ++#endif ++ val = ptr[ (va>>12)&0x3ff ]; /* next 10 bits */ ++ ++ r->phys = val & ~0xfff; ++ r->mflags = ++ DBG_TRANSL_PAGE_FLAG( val, _PAGE_PRESENT ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_USER ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_GUARDED ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_COHERENT ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_NO_CACHE ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_WRITETHRU ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_DIRTY ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_ACCESSED ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_RW ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_HASHPTE ) ++ | DBG_TRANSL_PAGE_FLAG( val, _PAGE_EXEC ); ++ return 0; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/_hostirq.c +@@ -0,0 +1,116 @@ ++/* ++ * ++ * ++ * host IRQ handling (for pciproxied devices) ++ * ++ * Copyright (C) 2005 Mattias Nissler ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#include "archinclude.h" ++#include "kernel_vars.h" ++#include "misc.h" ++#include "atomic.h" ++ ++irqreturn_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) ++hostirq_handler(int irq, void *pkv) ++#else ++hostirq_handler(int irq, void *pkv, struct pt_regs *regs) ++#endif ++{ ++ siginfo_t si; ++ kernel_vars_t *kv = (kernel_vars_t *) pkv; ++ ++ /* disable the irq */ ++ disable_irq_nosync(irq); ++ /* have the interrupt handled */ ++ if (!test_and_set_bit(irq, kv->mregs.active_irqs.irqs)) ++ atomic_inc_mol((mol_atomic_t *) &(kv->mregs.hostirq_active_cnt)); ++ kv->mregs.hostirq_update = 1; ++ kv->mregs.interrupt = 1; ++ /* signal the main thread (it might be DOZEing) */ ++ if (kv->main_thread != NULL) { ++ memset(&si, 0, sizeof(si)); ++ si.si_signo = SIGHUP; ++ si.si_code = irq; ++ send_sig_info(SIGHUP, &si, kv->main_thread); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static char *molirqdescstring = "MOL irq mapping"; ++ ++int ++grab_host_irq(kernel_vars_t *kv, int irq) ++{ ++ int ret; ++ ++ /* sanity check */ ++ if (irq < 0 || irq >= NR_HOST_IRQS ++ || check_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs)) ++ return 0; ++ ++ /* request the irq */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) ++ ret = request_irq(irq, hostirq_handler, IRQF_DISABLED | IRQF_SHARED, molirqdescstring, kv); ++#else ++ ret = request_irq(irq, hostirq_handler, SA_INTERRUPT | SA_SHIRQ, molirqdescstring, kv); ++#endif ++ if (!ret) { ++// printk(KERN_INFO "mapped irq line %d\n", irq); ++ set_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs); ++ } ++ ++ return ret; ++} ++ ++int ++release_host_irq(kernel_vars_t *kv, int irq) ++{ ++ /* sanity check */ ++ if (irq < 0 || irq >= NR_HOST_IRQS ++ || !check_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs)) ++ return 0; ++ ++ clear_bit_mol(irq, (char *) kv->mregs.mapped_irqs.irqs); ++ disable_irq(irq); ++ free_irq(irq, kv); ++ ++ return 1; ++} ++ ++void ++init_host_irqs(kernel_vars_t *kv) ++{ ++ memset(&(kv->mregs.mapped_irqs), 0, sizeof(kv->mregs.mapped_irqs)); ++ kv->main_thread = current; ++ kv->mregs.hostirq_update = 0; ++} ++ ++void ++cleanup_host_irqs(kernel_vars_t *kv) ++{ ++ int n; ++ ++ for (n = 0; n < NR_HOST_IRQS; n++) { ++ if (check_bit_mol(n, (char *) kv->mregs.mapped_irqs.irqs)) ++ release_host_irq(kv, n); ++ } ++} ++ +--- /dev/null ++++ b/drivers/macintosh/mol/_kuname.c +@@ -0,0 +1,48 @@ ++/* ++ * Creation Date: <2001/08/15 01:11:01 samuel> ++ * Time-stamp: <2003/10/24 10:22:00 samuel> ++ * ++ * ++ * ++ * Extract from the kernel source ++ * ++ * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#include ++#endif ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++#include ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ++#ifdef CONFIG_SMP ++#define SMP_STRING "-smp" ++#else ++#define SMP_STRING "" ++#endif ++ ++#ifndef CONFIG_ALTIVEC ++#define ALTIVEC_STRING "-noav" ++#else ++#define ALTIVEC_STRING "" ++#endif ++ ++#else ++#define SMP_STRING "" ++#define ALTIVEC_STRING "" ++#endif ++ ++char *cross_compiling_magic = "-MAGIC-" UTS_RELEASE SMP_STRING ALTIVEC_STRING ; +--- /dev/null ++++ b/drivers/macintosh/mol/_misc.c +@@ -0,0 +1,147 @@ ++/* ++ * Creation Date: <97/05/26 02:10:43 samuel> ++ * Time-stamp: <2004/03/13 14:14:20 samuel> ++ * ++ * ++ * ++ * Kernel interface ++ * ++ * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include ++#include ++#include ++#include ++#include "kernel_vars.h" ++#include "misc.h" ++#include "performance.h" ++#include "map.h" ++ ++#define MMU kv->mmu ++ ++kernel_vars_t * ++alloc_kvar_pages( void ) ++{ ++ kernel_vars_t *kv; ++ int i, order; ++ char *ptr; ++ ++ for( i=1, order=0; i kernel C-code switching */ ++/************************************************************************/ ++ ++typedef int (*kernelfunc_t)( kernel_vars_t *, ulong, ulong, ulong ); ++typedef void (*trampoline_t)( struct pt_regs *regs ); ++static trampoline_t old_trampoline; ++ ++static void ++mol_trampoline_vector( struct pt_regs *r ) ++{ ++ kernel_vars_t *kv = (kernel_vars_t*)r->gpr[8]; ++ ++#ifndef LINUX_26 ++ /* the 0x2f00 trap does not enable MSR_EE */ ++ local_irq_enable(); ++#endif ++ TICK_CNTR_PUSH( kv ); ++ r->gpr[3] = (*(kernelfunc_t)r->gpr[3])( kv, r->gpr[4], r->gpr[5], r->gpr[6] ); ++ TICK_CNTR_POP( kv, in_kernel ); ++} ++ ++static trampoline_t ++set_trampoline( trampoline_t tramp ) ++{ ++ trampoline_t old; ++#ifdef LINUX_26 ++ extern trampoline_t mol_trampoline; ++ old = mol_trampoline; ++ mol_trampoline = tramp; ++#else ++ /* we steal the unused 0x2f00 exception vector... */ ++ u32 *p = (u32*)(KERNELBASE + 0x2f00); ++ static trampoline_t *tptr = NULL; ++ int i; ++ ++ /* look for bl xxxx ; .long vector; .long exception_return */ ++ for( i=0; !tptr && i<0x100/4; i++ ) { ++ if( (p[i] & ~0xffff) != 0x48000000 ) ++ continue; ++ if( (p[i+1] & ~0x7fffff) != KERNELBASE || (p[i+2] & ~0x0fffff) != KERNELBASE ) ++ continue; ++ tptr = (trampoline_t*)&p[i+1]; ++ } ++ if( !tptr ) { ++ printk("MOL trampoline not found!\n"); ++ return NULL; ++ } ++ old = *tptr; ++ *tptr = tramp; ++#endif ++ return old; ++} ++ ++int ++arch_common_init( void ) ++{ ++ old_trampoline = set_trampoline( mol_trampoline_vector ); ++ return !old_trampoline; ++} ++ ++void ++arch_common_cleanup( void ) ++{ ++ set_trampoline( old_trampoline ); ++} +--- /dev/null ++++ b/drivers/macintosh/mol/_mmu.c +@@ -0,0 +1,41 @@ ++/* ++ * Creation Date: <2002/07/13 13:58:00 samuel> ++ * Time-stamp: <2004/02/14 12:47:09 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "mmu.h" ++#include "asmfuncs.h" ++ ++#define MMU (kv->mmu) ++ ++#ifdef CONFIG_SMP ++void (*xx_tlbie_lowmem)( void ); ++void (*xx_store_pte_lowmem)( void ); ++#else ++void (*xx_store_pte_lowmem)( ulong *slot, int pte0, int pte1 ); ++#endif ++ ++int ++arch_mmu_init( kernel_vars_t *kv ) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++ MMU.emulator_context = current->mm->context.id; ++#else ++ MMU.emulator_context = current->mm->context; ++#endif ++ return 0; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/actions.c +@@ -0,0 +1,548 @@ ++/* ++ * Creation Date: <2001/04/07 17:33:52 samuel> ++ * Time-stamp: <2004/03/13 14:17:40 samuel> ++ * ++ * ++ * ++ * Handle assambly actions (relocations, exception vector ++ * hooking, lowmem relocations and other stuff) ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "misc.h" ++#include "asmfuncs.h" ++#include "actions.h" ++#include "map.h" ++ ++ ++/* globals */ ++int reloc_virt_offs; ++ ++static char *code_base; ++static uint code_size; ++ ++/* some opcodes */ ++#define OPCODE_ADDIS( dreg, sreg, hi_val ) ((15<<26) | ((dreg)<<21) | ((sreg)<<16) | (hi_val)) ++#define OPCODE_LIS( dreg, hi_val ) OPCODE_ADDIS( dreg, 0, hi_val ) ++#define OPCODE_ORI( dreg, sreg, val ) ((24<<26) | ((dreg)<<16) | ((sreg)<<21) | (val)) ++#define OPCODE_MTSPRG2( sreg ) (0x7c1243a6 + ((sreg)<<21)) ++ ++ ++/************************************************************************/ ++/* lowmem allocations (allocates within the first 32 MB of RAM) */ ++/************************************************************************/ ++ ++/* The low-level assembly code need to be located in memory which is ++ * physically continuous. The kernel exception vector are patched ++ * through pseudo symbols (action symbols). ++ */ ++ ++#define MAX_NUM_CLEANUP_HANDLERS 32 ++ ++typedef struct { ++ char *lowmem_addr; ++ int alloc_size; ++ int alloc_method; ++ ++ ulong *inst_addr; /* these fields are used */ ++ ulong opcode; /* be the hook code */ ++} cleanup_entry_t; ++ ++static int num_cleanup_entries; ++static cleanup_entry_t cleanup_table[ MAX_NUM_CLEANUP_HANDLERS ]; ++static ulong lowmem_phys_cursor; ++ ++/* Memory mapping of exception vectors */ ++static ulong lowmem_phys_base; ++static char *lowmem_virt_base; ++static void *lowmem_mapping; ++ ++ ++static inline ulong * ++lowmem_phys_to_virt( ulong paddr ) { ++ return (ulong*)(lowmem_virt_base + (paddr - lowmem_phys_base)); ++} ++ ++static inline ulong ++lowmem_tophys( void *vaddr ) { ++ return lowmem_phys_base + ((ulong)vaddr - (ulong)lowmem_virt_base); ++} ++ ++ ++static void ++lowmem_initialize( void ) ++{ ++ if( num_cleanup_entries ) { ++ printk("Internal error in lowmem_initialize\n"); ++ return; ++ } ++ lowmem_phys_cursor = 0x100; ++ ++ /* In Darwin, the mapping will fail if we put lowmem_phys_base to zero */ ++ lowmem_phys_base = 0x100; ++ lowmem_mapping = map_phys_range( lowmem_phys_base, 0x4000, &lowmem_virt_base ); ++} ++ ++static char * ++lowmem_alloc( int size, cleanup_entry_t **ret_ce ) ++{ ++ ulong *pstart; ++ cleanup_entry_t ce; ++ int found=0; ++ ++ memset( &ce, 0, sizeof(ce) ); ++ if( ret_ce ) ++ *ret_ce = NULL; ++ ++ if( num_cleanup_entries >= MAX_NUM_CLEANUP_HANDLERS ) { ++ printk("MOL: Need more cleanup slots!\n"); ++ return NULL; ++ } ++ ++ /* Find big enough empty piece of memory */ ++ if( size < 0x10 ) ++ size = 0x10; ++ ++ pstart = lowmem_phys_to_virt(lowmem_phys_cursor); ++ pstart = (ulong*)(((ulong)pstart + 0xf) & ~0xf); ++ for( ; lowmem_phys_cursor < 0x3000; lowmem_phys_cursor+=4 ) { ++ ulong *p = lowmem_phys_to_virt(lowmem_phys_cursor); ++ if( ((int)p - (int)pstart) >= size ) { ++ found = 1; ++ break; ++ } ++ if( *p ) { ++ pstart = (ulong*)(((ulong)p + sizeof(ulong) + 0xf) & ~0xf); ++ continue; ++ } ++ } ++ if( !found ) { ++ printk("MOL: Did not find an empty piece of lowmem memory!\n"); ++ return NULL; ++ } ++ /* printk("lowmem alloc: %08lX\n", pstart ); */ ++ ++ ce.lowmem_addr = (char*)pstart; ++ ce.alloc_method = 0; ++ ce.alloc_size = size; ++ /* printk("lowmem-alloc SPACE %X bytes at %08lX\n", size, (ulong)pstart ); */ ++ ++ cleanup_table[num_cleanup_entries] = ce; ++ if( ret_ce ) ++ *ret_ce = &cleanup_table[num_cleanup_entries]; ++ num_cleanup_entries++; ++ ++ return ce.lowmem_addr; ++} ++ ++static void ++lowmem_free_all( void ) ++{ ++ cleanup_entry_t *ce = &cleanup_table[0]; ++ int i; ++ ++ for(i=0; ilowmem_addr, 0, ce->alloc_size ); ++ ++ num_cleanup_entries = 0; ++ ++ if( lowmem_mapping ) { ++ unmap_phys_range( lowmem_mapping ); ++ lowmem_mapping = NULL; ++ } ++} ++ ++ ++/************************************************************************/ ++/* helper functions */ ++/************************************************************************/ ++ ++static action_pb_t * ++find_action( int action, int index ) ++{ ++ extern int r__actions_offs_section[], r__actions_offs_section_end[]; ++ extern char *r__actions_section[]; ++ const int n = ((int)r__actions_offs_section_end - (int)r__actions_offs_section)/sizeof(int); ++ int i, *op = r__actions_offs_section; ++ ++ for( i=0; iaction != action || index-- ) ++ continue; ++ return p; ++ } ++ return NULL; ++} ++ ++static int ++relocate_inst( ulong *opc_ptr, ulong from, ulong to ) ++{ ++ ulong opcode = *opc_ptr; ++ int offs=-1; ++ ++ /* XXX: UNTESTED if target instruction is a branch */ ++ ++ /* Since we use this on the _first_ instruction of the ++ * exception vector, it can't touch LR/CR. Thus, we ++ * only look for unconditional, relative branches. ++ */ ++ ++ /* relativ branch b */ ++ if( (opcode & 0xfc000003) == (18<<26) ){ ++ offs = (opcode & 0x03fffffc); ++ /* sign extend */ ++ if( offs & 0x03000000 ) ++ offs |= ~0x03ffffff; ++ } ++ /* unconditional, relativ bc branch (b 0100 001z1zz ...) */ ++ if( (opcode & 0xfe800003) == 0x42800000 ){ ++ offs = (opcode & 0xfffc); ++ if( offs & 0x8000 ) ++ offs |= ~0xffff; ++ } ++ /* construct the absolute branch */ ++ if( offs != -1 ) { ++ int dest = from + offs; ++ if( dest < 0 || dest > 33554431 ) { ++ printk("relocation of branch at %08lX to %08lX failed\n", from, to); ++ return 1; ++ } ++ /* absolute branch */ ++ *opc_ptr = ((18<<26) + 2) | dest; ++ } ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* actions */ ++/************************************************************************/ ++ ++typedef int (*action_func_t)( int action, ulong *target, const int *pb ); ++ ++static int ++action_li_phys( int action, ulong *target, const int *pb ) ++{ ++ int r = pb[0] & 0x1f; ++ ulong addr = pb[1] + tophys_mol( code_base ); ++ ++ /* target[0] = addis r,0,addr@h ; target[1] = ori r,r,addr@l */ ++ target[0] = (15 << 26) | (r << 21) | (addr >> 16); ++ target[1] = (24 << 26) | (r << 21) | (r << 16) | (addr & 0xffff); ++ ++ /* printk("ACTION_LI_PHYS %d %08lX\n", dreg, addr ); */ ++ return 0; ++} ++ ++static int ++action_lwz_physaddr_r( int action, ulong *target, const int *pb ) ++{ ++ ulong addr = pb[1] + tophys_mol( code_base ); ++ int dr = (pb[0] >> 5) & 0x1f; ++ int r = pb[0] & 0x1f; ++ short low = (addr & 0xffff); ++ ++ /* target[0] = addis dr,r,addr@h ; target[1] = lwz dr,addr@l(dr) */ ++ target[0] = (15 << 26) | (dr << 21) | (r << 16) | ((addr - low) >> 16); ++ target[1] = (32 << 26) | (dr << 21) | (dr << 16) | ((int)low & 0xffff); ++ ++ /* printk("ACTION_LI_PHYS %d %08lX\n", dreg, addr ); */ ++ return 0; ++} ++ ++static int ++action_specvar( int action, ulong *target, const int *pb ) ++{ ++ int r = pb[0] & 0x1f; ++ ulong addr; ++ ++ switch( pb[1] ) { ++ case SPECVAR_SESSION_TABLE: ++ addr = tophys_mol(g_sesstab); ++ break; ++ default: ++ return 1; ++ } ++ ++ if( action == ACTION_LIS_SPECVAR_H ) { ++ /* target[0] = addis r,0,addr@h */ ++ target[0] = OPCODE_LIS( r, (addr >> 16) & 0xffff ); ++ return 0; ++ } ++ if( action == ACTION_ORI_SPECVAR_L ) { ++ /* target[0] = ori rD,rS,addr@l */ ++ int rD = (pb[0] >> 5) & 0x1f; ++ target[0] = OPCODE_ORI( rD, r, (addr & 0xffff)); ++ return 0; ++ } ++ return 1; ++} ++ ++ ++/* Note: this only works under linux */ ++static int ++action_tophysvirt( int action, ulong *target, const int *pb ) ++{ ++ ulong addr = tophys_mol(0); ++ int dr = (pb[0] >> 5) & 0x1f; ++ int sr = pb[0] & 0x1f; ++ ++ if( action == ACTION_TOVIRT ) ++ addr = -addr; ++ ++ /* target[0] = addis dr,sr,(tophys(0))@hi */ ++ target[0] = OPCODE_ADDIS( dr, sr, (addr >> 16) & 0xffff ); ++ return 0; ++} ++ ++/* pb[] = { vector, size, vret_offs, ...hook_code... } */ ++static int ++action_reloc_hook( int action, ulong *hookcode, const int *pb ) ++{ ++ ulong addr, inst, vector=pb[0], size=pb[1], vret_offs=pb[2]; ++ cleanup_entry_t *clean; ++ ulong *vector_virt, *target; ++ action_pb_t *apb; ++ char *lowmem; ++ int i; ++ ++ /* Virtual address of exception vector */ ++ vector_virt = lowmem_phys_to_virt(vector); ++ ++ /* address of the vector hook code */ ++ addr = tophys_mol( (char*)hookcode ); ++ ++ /* allocate lowmem and add cleanup handler */ ++ if( !(lowmem=lowmem_alloc(size, &clean)) ) ++ return 1; ++ ++ /* printk("ACTION_RELOC_HOOK: %lx, %lx, %lx, %lx %p\n", vector, size, vret_action, vret_offs, lowmem); */ ++ ++ memcpy( lowmem, &pb[3], size ); ++ ++ /* perform the vret_action */ ++ for( i=0; (apb=find_action(ACTION_VRET, i)); i++ ) { ++ if( apb->params[0] != vector ) ++ continue; ++ ++ /* insert the absolut branch */ ++ target = (ulong*)(code_base + apb->offs); ++ *target = ((18<<26) + 2) | lowmem_tophys(lowmem + vret_offs); ++ flush_icache_mol( (ulong)target, (ulong)target + 4 ); ++ /* printk("'ba xxx' added (opcode %08lX at %p)\n", *target, target ); */ ++ } ++ ++ /* fix the hook address in the glue code */ ++ target = (ulong*)lowmem; ++ target[1] = (target[1] & ~0xffff) | (addr >> 16); /* target[0] = addis r3,0,0 */ ++ target[3] = (target[3] & ~0xffff) | (addr & 0xffff); /* target[1] = ori r3,r3,0 */ ++ ++ /* relocate instruction to be overwritten with a branch */ ++ inst = *vector_virt; ++ clean->opcode = inst; ++ if( relocate_inst( &inst, vector, lowmem_tophys(lowmem+vret_offs) )) ++ return 1; ++ *(ulong*)(lowmem + vret_offs) = inst; ++ flush_icache_mol( (ulong)lowmem, (ulong)lowmem + size ); ++ ++ /* insert branch, 'ba lowmem_ph' */ ++ *(volatile ulong*)vector_virt = 0x48000002 + lowmem_tophys(lowmem); ++ flush_icache_mol( (ulong)vector_virt, (ulong)vector_virt+4 ); ++ ++ /* we are in business! */ ++ clean->inst_addr = vector_virt; ++ return 0; ++} ++ ++ ++/* pb = { size, where_to_store_lowmem_addr, ...code... } */ ++static int ++action_reloc_low( int action, ulong *dummy, const int *pb ) ++{ ++ int size = pb[0]; ++ char **func_ptr = (char**)pb[1]; ++ char *lowmem; ++ ++ if( !(lowmem=lowmem_alloc(size, NULL)) ) ++ return 1; ++ memcpy( lowmem, (char*)&pb[2], size ); ++ ++ flush_icache_mol( (ulong)lowmem, (ulong)lowmem+size ); ++ *func_ptr = lowmem; ++ return 0; ++} ++ ++/* pb = { symind, size, fret_offset, codeglue... } */ ++static int ++action_hook_function( int action, ulong *hookcode, const int *pb ) ++{ ++ ulong addr, fhook=pb[0], size=pb[1], fret_offs=pb[2]; ++ ulong *target, inst; ++ char *lowmem, *func_addr=NULL; ++ cleanup_entry_t *clean; ++ ++ switch( fhook ) { ++#ifdef __linux__ ++ case FHOOK_FLUSH_HASH_PAGE: ++ func_addr = (char*)compat_flush_hash_pages; ++ break; ++#endif ++ default: ++ printk("Bad fhook index %ld\n", fhook ); ++ return 1; ++ } ++ ++ /* this does not have to be in lowmem, but it is simpler with a unified approach */ ++ if( !(lowmem=lowmem_alloc(size, &clean)) ) ++ return 1; ++ ++ /* printk("ACTION_HOOK_FUNCTION: %lx, %lx, %lx %p\n", fhook, size, fret_offs, lowmem); */ ++ ++ memcpy( lowmem, &pb[3], size ); ++ ++ /* fix the hook address in the glue code */ ++ target = (ulong*)lowmem; ++ addr = (ulong)hookcode; ++ target[1] = (target[1] & ~0xffff) | (addr >> 16); /* target[1] = addis rX,0,0 */ ++ target[2] = (target[2] & ~0xffff) | (addr & 0xffff); /* target[2] = ori rX,rX,0 */ ++ ++ /* relocate overwritten instruction and add relative return branch */ ++ inst = *(ulong*)func_addr; ++ clean->opcode = inst; ++ if( relocate_inst(&inst, (ulong)func_addr, (ulong)lowmem + fret_offs) ) ++ return 1; ++ target = (ulong*)(lowmem + fret_offs); ++ target[0] = inst; ++ target[1] = (18<<26) | (((ulong)func_addr - (ulong)&target[1] + sizeof(long)) & 0x03fffffc); ++ flush_icache_mol( (ulong)lowmem, (ulong)lowmem + size ); ++ _sync(); ++ ++ /* insert relative branch, 'b lowmem' */ ++ *(volatile ulong*)func_addr = (18<<26) | ((lowmem - func_addr) & 0x03fffffc); ++ flush_icache_mol( (ulong)func_addr, (ulong)func_addr+4 ); ++ ++ _sync(); ++ ++ /* we are in business! */ ++ clean->inst_addr = (ulong*)func_addr; ++ return 0; ++} ++ ++static int ++action_fix_sprg2( int action, ulong *target, const int *pb ) ++{ ++#ifdef __darwin__ ++ int sprg2; ++ int r = pb[0] & 0x1f; ++ asm volatile("mfspr %0,274" : "=r" (sprg2) ); ++ target[0] = OPCODE_LIS( r, (sprg2 >> 16) & 0xffff ); ++ target[1] = OPCODE_ORI( r, r, (sprg2 & 0xffff) ); ++ target[2] = OPCODE_MTSPRG2( r ); ++#endif ++ return 0; ++} ++ ++static int ++action_noaction( int action, ulong *hookcode, const int *pb ) ++{ ++ return 0; ++} ++ ++static action_func_t actiontable[MAX_NUM_ACTIONS] = { ++ [ACTION_LI_PHYS] = action_li_phys, ++ [ACTION_LWZ_PHYSADDR_R] = action_lwz_physaddr_r, ++ [ACTION_TOPHYS] = action_tophysvirt, ++ [ACTION_TOVIRT] = action_tophysvirt, ++ [ACTION_RELOC_HOOK] = action_reloc_hook, ++ [ACTION_RELOCATE_LOW] = action_reloc_low, ++ [ACTION_HOOK_FUNCTION] = action_hook_function, ++ [ACTION_VRET] = action_noaction, ++ [ACTION_FIX_SPRG2] = action_fix_sprg2, ++ ++ [ACTION_LIS_SPECVAR_H] = action_specvar, ++ [ACTION_ORI_SPECVAR_L] = action_specvar, ++}; ++ ++ ++/************************************************************************/ ++/* write/remove hooks */ ++/************************************************************************/ ++ ++static int ++relocate_code( void ) ++{ ++ extern char r__reloctable_start[], r__reloctable_end[]; ++ ++ code_size = r__reloctable_end - r__reloctable_start; ++ ++ if( !(code_base=kmalloc_cont_mol(code_size)) ) ++ return 1; ++ ++ memcpy( code_base, r__reloctable_start, code_size ); ++ reloc_virt_offs = (int)code_base - (int)r__reloctable_start; ++ return 0; ++} ++ ++int ++perform_actions( void ) ++{ ++ action_pb_t *pb; ++ int action, i; ++ ++ if( relocate_code() ) ++ return 1; ++ lowmem_initialize(); ++ ++ for( action=0; action < MAX_NUM_ACTIONS; action++ ) { ++ for( i=0; (pb=find_action(action,i)); i++ ) { ++ ulong *target = (ulong*)(code_base + pb->offs); ++ ++ if( pb->offs > code_size ) { ++ printk("OFFSET ERROR!\n"); ++ goto error; ++ } ++ ++ if( !actiontable[action] ) ++ goto error; ++ if( (*actiontable[action])(action, target, pb->params) ) ++ goto error; ++ } ++ ++ /* we need to flush the icache before the hook actions are performed */ ++ if( action == FLUSH_CACHE_ACTION ) ++ flush_icache_mol( (ulong)code_base, (ulong)code_base + code_size ); ++ } ++ /* to be on the safe side, flush the cache once more */ ++ flush_icache_mol( (ulong)code_base, (ulong)code_base + code_size ); ++ return 0; ++ error: ++ printk("MOL: action %d error\n", action ); ++ cleanup_actions(); ++ return 1; ++} ++ ++void ++cleanup_actions( void ) ++{ ++ cleanup_entry_t *ce = &cleanup_table[0]; ++ int i; ++ ++ for( i=0; iinst_addr ) { ++ *(volatile ulong*)ce->inst_addr = cleanup_table[i].opcode; ++ flush_icache_mol( (ulong)ce->inst_addr, (ulong)ce->inst_addr + 4 ); ++ } ++ } ++ lowmem_free_all(); ++ kfree_cont_mol( code_base ); ++} +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/603.S +@@ -0,0 +1,218 @@ ++/* ++ * Creation Date: <2001/06/15 20:10:49 samuel> ++ * Time-stamp: <2001/06/16 15:35:22 samuel> ++ * ++ * <603.S> ++ * ++ * 603 MMU support ++ * ++ * Copyright (C) 2001 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#define P603_USE_G_BIT ++#define P603_USE_R_BIT ++#define P603_USE_C_BIT ++ ++/* NOTE: The 603 vectors are called with ctr saved in r0. ++ * Secondary interrupts are not detected automatically. ++ */ ++ ++/************************************************************************/ ++/* Instruction TLB Miss (603 specific vector) */ ++/************************************************************************/ ++ ++VECTOR_603( 0x1000, "Instruction TLB Miss - 603" ) ++// mfctr r0 // Need to save this - CTR can't be touched! ++ mfspr r2,HASH1 // Get PTE pointer ++ mfspr r3,ICMP // Partial item compare value ++00: li r1,8 // 8 items / bucket ++ mtctr r1 ++ subi r2,r2,8 // Preset pointer ++10: lwzu r1,8(r2) // Get next PTE ++ cmp 0,r1,r3 // Found entry yet? ++ bdnzf 2,10b // Jump back if not, until CTR==0 ++ bne 30f // Try secondary hash if CTR==0 ++ lwz r1,4(r2) // Get second word of entry ++#ifdef P603_USE_G_BIT ++ andi. r3,r1,8 // check G-bit ++ bne DoISI_603_G // if guarded, take an ISI ++#endif ++ mtctr r0 // Restore CTR ++ mfspr r3,SRR1 // Need to restore CR0 ++ mtcrf 0x80,r3 ++ mfspr r0,IMISS // Set to update TLB ++ mtspr RPA,r1 ++#ifdef P603_USE_R_BIT ++ ori r1,r1,0x100 // Set reference bit ++ srwi r1,r1,8 // Get byte 7 of pte ++ tlbli r0 // Load the ITLB ++ stb r1,6(r2) // update page table ++#else ++ tlbli r0 // Load the ITLB ++#endif ++ rfi // All done ++ ++ // Secondary hash ++30: andi. r1,r3,0x40 // Already doing secondary hash? ++ bne DoISI_603 // Yes - item not in hash table ++ mfspr r2,HASH2 // Get hash table pointer ++ ori r3,r3,0x40 // Set secondary hash ++ b 00b // Try lookup again ++ ++ ++/************************************************************************/ ++/* Data Store TLB Miss (603 specific vector) */ ++/************************************************************************/ ++ ++VECTOR_603( 0x1200, "Data Store TLB Miss - 603" ) ++// mfctr r0 // Need to save this - CTR can't be touched! ++ mfspr r2,HASH1 // Get PTE pointer ++ mfspr r3,DCMP // Partial item compare value ++00: li r1,8 // 8 items / bucket ++ mtctr r1 ++ subi r2,r2,8 // Preset pointer ++10: lwzu r1,8(r2) // Get next PTE ++ cmp 0,r1,r3 // Found entry yet? ++ bdnzf 2,10b // Jump back if not, until CTR==0 ++ bne 30f // Try secondary hash if CTR==0 ++ lwz r1,4(r2) // Get second word of entry ++#ifdef P603_USE_C_BIT ++ andi. r3,r1,0x80 // Check the C-bit ++ beq CheckProt_603 ++16: ++#endif ++20: mtctr r0 // Restore CTR ++ mfspr r3,SRR1 // Need to restore CR0 ++ mtcrf 0x80,r3 ++ mfspr r0,DMISS // Set to update TLB ++ mtspr RPA,r1 ++ tlbld r0 ++ rfi // All done ++ ++ // Secondary hash ++30: andi. r1,r3,0x40 // Already doing secondary hash? ++ bne DoDSI_603 // Yes - item not in hash table ++ mfspr r2,HASH2 // Get hash table pointer ++ ori r3,r3,0x40 // Set secondary hash ++ b 00b // Try lookup again ++ ++#ifdef P603_USE_C_BIT ++ // Entry found and PTE[c] == 0. Check protection before setting PTE[c] ++ // r0 = saved ctr, r1 = second word of PTE, r2 = pointer to pteg, r3 = trash ++CheckProt_603: ++ rlwinm. r3,r1,30,0,1 // test PP ++ bge- 50f // if (PP == 00 or PP == 01) goto 50 ++ andi. r3,r1,1 // test PP[0] ++ beq+ 60f // return if PP[0] == 0 ++ b DoDSI_603_P // else DSI_P, (PP==11, read-only) ++ ++50: mfspr r3,SRR1 // get old msr ++ andis. r3,r3,0x0008 // test the KEY bit (SRR1-bit 12) ++ beq 60f // if KEY==0, goto 60 ++ b DoDSI_603_P // else DSI_P ++ ++60: ori r1,r1,0x180 // set reference and change bit ++ sth r1,6(r2) // update page table ++ b 16b // and back we go ++#endif ++ ++ ++/************************************************************************/ ++/* Data Load TLB Miss (603 specific vector) */ ++/************************************************************************/ ++ ++VECTOR_603( 0x1100, "Data Load TLB Miss - 603" ) ++// mfctr r0 // Need to save this - CTR can't be touched! ++ mfspr r2,HASH1 // Get PTE pointer ++ mfspr r3,DCMP // Partial item compare value ++00: li r1,8 // 8 items / bucket ++ mtctr r1 ++ subi r2,r2,8 // Preset pointer ++10: lwzu r1,8(r2) // Get next PTE ++ cmp 0,r1,r3 // Found entry yet? ++ bdnzf 2,10b // Jump back if not, until CTR==0 ++ bne 30f // Try secondary hash if CTR==0 ++ lwz r1,4(r2) // Get second word of entry ++20: mtctr r0 // Restore CTR ++ mfspr r3,SRR1 // Need to restore CR0 ++ mtcrf 0x80,r3 ++ mfspr r0,DMISS // Set to update TLB ++ mtspr RPA,r1 ++#ifdef P603_USE_R_BIT ++ ori r1,r1,0x100 // set reference bit ++ srwi r1,r1,8 ++ tlbld r0 ++ stb r1,6(r2) ++#else ++ tlbld r0 ++#endif ++ rfi // All done ++ ++// Secondary hash ++30: andi. r1,r3,0x40 // Already doing secondary hash? ++ bne DoDSI_603 // Yes - item not in hash table ++ mfspr r2,HASH2 // Get hash table pointer ++ ori r3,r3,0x40 // Set secondary hash ++ b 00b // Try lookup again ++ ++ ++/************************************************************************/ ++/* Synthesize an ISI Exception */ ++/************************************************************************/ ++ ++DoISI_603: ++ mfspr r3,SRR1 ++ andi. r2,r3,0xFFFF // Clear upper bits of SRR1 ++ addis r2,r2,0x4000 // Set bit 1 -> PTE not found (in HTAB) ++ mtctr r0 // Restore CTR ++40: mtspr SRR1,r2 ++ mfmsr r0 // Restore "normal" registers ++ xoris r0,r0,MSR_TGPR>>16 ++ mtcrf 0x80,r3 // Restore CR0 ++ sync // Some chip revs have problems here... ++ mtmsr r0 ++ SOFT_VECTOR_ENTRY_603( 0x400 ) // Jump to the ISI vector ++ ++ ++#ifdef P603_USE_G_BIT ++DoISI_603_G: ++ mfspr r3,SRR1 ++ andi. r2,r3,0xFFFF // Clear upper bits of SRR1 ++// addis r2,r2,0x0800 // Page protection violation ++ addis r2,r2,0x1000 // Guarded memory access ++ b 40b ++#endif ++ ++ ++/************************************************************************/ ++/* Synthesize a DSI exception */ ++/************************************************************************/ ++ ++DoDSI_603: ++ mfspr r3,SRR1 ++ rlwinm r1,r3,9,6,6 // Get load/store bit ++ addis r1,r1,0x4000 // Set bit 1 -> PTE not found ++ ++10: mtspr DSISR,r1 ++ mtctr r0 // Restore CTR ++ andi. r2,r3,0xFFFF // Clear upper bits of SRR1 ++ mtspr SRR1,r2 ++ mfspr r1,DMISS // Get failing address ++ mtspr DAR,r1 // Set fault address ++ mfmsr r0 // Restore "normal" registers ++ xoris r0,r0,MSR_TGPR>>16 ++ mtcrf 0x80,r3 // Restore CR0 ++ sync // Some chip revs have problems here... ++ mtmsr r0 ++ SOFT_VECTOR_ENTRY_603( 0x300 ) // Jump to the DSI vector ++ ++DoDSI_603_P: ++ mfspr r3,SRR1 ++ rlwinm r1,r3,9,6,6 // get load/store bit ++ addis r1,r1,0x800 // Set bit 4 (prot. violation) ++ b 10b +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/dec.S +@@ -0,0 +1,228 @@ ++/* ++ * Creation Date: <2001/06/21 17:10:35 samuel> ++ * Time-stamp: <2004/03/07 13:16:58 samuel> ++ * ++ * ++ * ++ * DEC / TimeBase stuff ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++/************************************************************************/ ++/* TBWU / TBWL */ ++/************************************************************************/ ++ ++#if 0 ++spr_tbwu: ++ blr // read (won't come here) ++ mr r3,r0 ++ mftb r4 ++ b update_tb ++ ++spr_tbwl: ++ blr // read (won't come here) ++ mftbu r3 ++ mr r4,r0 ++ // ...fall through... ++ ++// r3 = tbu, r4 = tbl, r0,r2,r5 free. ++update_tb: ++ lwz r5,K_LOADED_DEC(r1) ++ mfdec r2 ++ sub r5,r5,r2 // r5 = elapsed ticks ++ ++ li r2,0 // Set timebase ++ mttbl r4 ++ mttbu r3 ++ mttbl r4 ++ ++ mfxer r2 ++ subfc r4,r5,r4 ++ addme r3,r3 ++ stw r4,xTBL(r1) ++ stw r3,xTBU(r1) ++ mtxer r2 ++ b emulation_done ++#endif ++ ++ ++/************************************************************************/ ++/* Load/restore DEC and TB */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////////// ++ // recalc_int_stamp ++ // ++ // May modify: r0,r2-r5 ++ // ++ ++recalc_int_stamp: ++ crclr FBIT_RecalcDecInt ++ ++ lwz r5,xTIMER_STAMP(r1) ++ bf FBIT_DecSeenZero, 1f // FBIT_DecSeenZero must be set when DEC is loaded ++ bt FBIT_DecINT, 1f // interrupt might already be flagged... ++ mftb r3 ++ lwz r4,xDEC_STAMP(r1) // Has the xDEC overflown already? ++ sub. r0,r4,r3 ++ blt 2f // branch if xDEC < 0 ++ sub. r0,r4,r5 ++ blt 2f // branch if xDEC < xTIMER ++1: mr r4,r5 ++2: stw r4,K_INT_STAMP(r1) // dec = xTIMER ++ blr ++ ++ ++ ////////////////////////////////////////////////////////////// ++ // set_mol_dec ++ // ++ // May modify: r0,r2-r5 ++ // ++ // Old 2.4 kernels assume that linux-DEC never ticks faster ++ // than the DEC interval measured from TB. Unfortunately, ++ // it is virtually impossible to keep DEC/TB in sync. ++ // ++ // Experimentally, the "worst case" senario is a linux DEC tick ++ // beeing delayed 0.04 ms (to be compare with the 20 ms period). ++ // ++ // Sequences similar to ++ // ++ // 1: mftb r2; mfdec r3; mftb r4; cmp r2,r4; bne 1b ++ // ++ // do *not* work - DEC and TB probably ticks on different edges. ++ ++set_mol_dec: ++ lwz r5,K_INT_STAMP(r1) // DEC = K_INT_STAMP - tbl ++ mfdec r3 // Make sure linux interrupts *never* ++ mftb r2 // occur too fast ++ ++ sub r4,r5,r2 ++ cmpw r4,r3 ++ bgtlr ++ add r5,r3,r2 // K_DEC_STAMP = DEC + tbl ++ mtdec r4 ++ ++ stw r5,K_DEC_STAMP(r1) ++ crset FBIT_MolDecLoaded ++ blr ++ ++ /////////////////////////////////////////////////////////////// ++ // set_kernel_dec ++ // ++ // May modify: r0,r2, cr ++ // ++ ++set_kernel_dec: ++ lwz r0,K_DEC_STAMP(r1) ++ crclr FBIT_MolDecLoaded ++ mftb r2 // Keep linux-DEC coherent ++ sub r2,r0,r2 // DEC = stamp - tbl ++ mtdec r2 ++ blr ++ ++ ++ ++/************************************************************************/ ++/* DEC read/write */ ++/************************************************************************/ ++ ++_dec_read: ++ lwz r4,xDEC_STAMP(r1) ++ mftb r3 ++ sub r0,r4,r3 ++ ++ BUMP("dec_read") ++ GET_TICK_CNT(entry,"dec_read") ++ b simple_mfspr ++ ++spr_dec: ++ b _dec_read ++ ++ // dec write. r0 = spr_value ++ BUMP("mtdec") ++ rlwinm. r5,r0,0,0,0 // seen zero? ++ mftb r4 ++ cror FBIT_DecSeenZero,FBIT_DecSeenZero,eq ++ add r5,r4,r0 ++ stw r5,xDEC_STAMP(r1) // set new dec value ++ bf FBIT_DecSeenZero, emulation_done ++ bl recalc_int_stamp // M: r0,r2-r5 ++ btl FBIT_MolDecLoaded, set_kernel_dec // M: r0,r2 ++ bl set_mol_dec // M: r0,r2-r5 ++ b emulation_done ++ ++ ++/************************************************************************/ ++/* Decrementer Exception */ ++/************************************************************************/ ++ ++ // __dec_VECTOR (non-MOL dec exception) ++ // ++ // r3=cr, sprg1=saved_r1, sprg0=saved_r3 ++ // ++ // An exception with DEC>=0 can occur if a mac-DEC overflows occurs ++ // just prior to a context switch. These exceptions should be ++ // dropped silently. ++ ++__dec_VECTOR: ++ mfdec r1 ++ cmpwi r1,0 ++ blt+ 1f ++ mtcr r3 // Restore and exit ++ ABORT_TRAP( 0x900 ) ++1: ++ mtcr r3 // Restore and continue trap ++ CONTINUE_TRAP( 0x900 ) ++ ++VECTOR_( 0x900, "Decrementer", secint_bad, __dec_VECTOR ) ++ EXCEPTION_PREAMBLE // r0-r5, CR, LR, r6/r7 = msr/nip ++ TRACE(0x900, "Decrementer") ++ mfdec r4 ++ cmpwi r4,0 ++ bge exception_return ++ bf FBIT_MolDecLoaded, take_linux_dec_exception ++ ++ mftb r3 ++ lis r2,0x1000 // r2 = DEC rearm constant ++ ++ bf FBIT_DecSeenZero, 1f // check for xDEC overflow ++ lwz r4,xDEC_STAMP(r1) ++ sub. r0,r4,r3 // lt set if xDEC has overflown ++ cror FBIT_DecINT, FBIT_DecINT, lt // dec_int |= lt ++ crandc FBIT_DecSeenZero, FBIT_DecSeenZero, lt // szero &= ~lt ++1: ++ lwz r5,xTIMER_STAMP(r1) // r5 = xTIMER_STAMP ++ sub. r0,r5,r3 // lt set if xTIMER has overflown ++ mtdec r2 // rearm DEC ++ blt- 2f // xTIMER has higher priority... ++ ++ // mac-dec interrupt ++ BUMP("DEC-overflow") ++ bl set_kernel_dec ++ bl recalc_int_stamp ++ bl set_mol_dec ++ GET_TICK_CNT(entry,"dec-overflow") ++ bf- FBIT_DecINT,exception_return // could occur if xTIMER has changed on us ++ lwz r4,xMSR(r1) ++ rlwinm. r0,r4,0,MSR_EE ++ beq- exception_return // no... simply return ++ BUMP("DEC-exception") ++ b mac_dec_trap ++ ++ // timer interrupt ++2: BUMP("Timer-interrupt") ++ crset FBIT_RecalcDecInt // dec must be recalced ++ GET_TICK_CNT(entry,"timer-overflow") ++ MAC_EXIT_SAVE( RVEC_TIMER ) ++ ++ ++take_linux_dec_exception: ++ BUMP("Linux-DEC") ++ bl save_middle_regs ++ TAKE_EXCEPTION( 0x900 ) +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/emuaccel.S +@@ -0,0 +1,188 @@ ++/* ++ * Creation Date: <2003/01/24 13:54:52 samuel> ++ * Time-stamp: <2003/08/14 03:12:00 samuel> ++ * ++ * ++ * ++ * Emulation acceleration ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "emuaccel_sh.h" ++ ++ // emuaccel registers: ++ // ++ // r2 = emuaccel_slot ++ // r6,r7 = nip(return address)/mregs ++ // ++ ++ balign_8 ++emuaccel_mtmsr_rNN: ++mFORLOOP([i],0,31,[ ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtmsr_accel ++]) ++emuaccel_mtsrr0_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtsrr0_accel ++ .else ++ stw rPREFIX[]i,xSRR0(r1) ++ b emulation_done_noinc ++ .endif ++]) ++emuaccel_mtsrr1_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtsrr1_accel ++ .else ++ stw rPREFIX[]i,xSRR1(r1) ++ b emulation_done_noinc ++ .endif ++]) ++emuaccel_mtsprg0_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtsprg0_accel ++ .else ++ stw rPREFIX[]i,xSPRG0(r1) ++ b emulation_done_noinc ++ .endif ++]) ++emuaccel_mtsprg1_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtsprg1_accel ++ .else ++ stw rPREFIX[]i,xSPRG1(r1) ++ b emulation_done_noinc ++ .endif ++]) ++emuaccel_mtsprg2_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtsprg2_accel ++ .else ++ stw rPREFIX[]i,xSPRG2(r1) ++ b emulation_done_noinc ++ .endif ++]) ++emuaccel_mtsprg3_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mtsprg3_accel ++ .else ++ stw rPREFIX[]i,xSPRG3(r1) ++ b emulation_done_noinc ++ .endif ++]) ++emuaccel_mthid0_rNN: ++mFORLOOP([i],0,31,[ ++ .if (i <= 7) ++ LOAD_EMUGPR_IM r0,i ++ b emulate_mthid0_accel ++ .else ++ stw rPREFIX[]i,xHID0(r1) ++ b emulation_done_noinc ++ .endif ++]) ++ ++emuaccel_nop: ++ b emulation_done_noinc ++ ++emuaccel_rfi: ++ addi r6,r6,-4 // point nip to the rfi instruction ++ b emulate_rfi ++ ++emuaccel_update_dec: ++ lwz r4,xDEC_STAMP(r1) ++ mftb r3 ++ sub r0,r4,r3 ++ stw r0,xDEC(r1) ++ b emulation_done_noinc ++ ++ balign_8 ++emuaccel_mtsr: ++ lwz r4,12(r2) // emuaccel paramamter (opcode) ++ addi r6,r6,-4 // back NIP ++ rlwinm r5,r4,14,24,28 // reg_num << 3 ++ b emulate_mtsr ++ ++ ++/************************************************************************/ ++/* implementation */ ++/************************************************************************/ ++ ++emulate_mtsrr0_accel: ++ stw r0,xSRR0(r1) ++ b emulation_done_noinc ++emulate_mtsrr1_accel: ++ stw r0,xSRR1(r1) ++ b emulation_done_noinc ++emulate_mtsprg0_accel: ++ stw r0,xSPRG0(r1) ++ b emulation_done_noinc ++emulate_mtsprg1_accel: ++ stw r0,xSPRG1(r1) ++ b emulation_done_noinc ++emulate_mtsprg2_accel: ++ stw r0,xSPRG2(r1) ++ b emulation_done_noinc ++emulate_mtsprg3_accel: ++ stw r0,xSPRG3(r1) ++ b emulation_done_noinc ++emulate_mthid0_accel: ++ stw r0,xHID0(r1) ++ b emulation_done_noinc ++ ++ balign_32 ++emulate_mtmsr_accel: ++ lwz r3,xMSR(r1) // r3 = old MSR ++ bl msr_altered ++ ++ GET_TICK_CNT(entry, "mtmsr-accel") ++ BUMP("emulate_mtmsr-accel") ++ ++ beq+ cr1,emulation_done_noinc // no doze... we are done ++ MAC_EXIT_SAVE( RVEC_MSR_POW ) // doze ++ ++ ++ ++/************************************************************************/ ++/* setup */ ++/************************************************************************/ ++ ++#define EMUACCEL_REL(s) s - emuaccel_table ++ ++#ifdef __linux__ ++ .text 70 /* this table does not need to be relocated */ ++#endif ++ // format: emuaccel_inst, offset, table_index_mask ++GLOBAL_SYMBOL(emuaccel_table): ++ .long EMUACCEL_MTMSR, EMUACCEL_REL( emuaccel_mtmsr_rNN ), 0x1f ++ .long EMUACCEL_MTSRR0, EMUACCEL_REL( emuaccel_mtsrr0_rNN ), 0x1f ++ .long EMUACCEL_MTSRR1, EMUACCEL_REL( emuaccel_mtsrr1_rNN ), 0x1f ++ .long EMUACCEL_MTSPRG0, EMUACCEL_REL( emuaccel_mtsprg0_rNN ), 0x1f ++ .long EMUACCEL_MTSPRG1, EMUACCEL_REL( emuaccel_mtsprg1_rNN ), 0x1f ++ .long EMUACCEL_MTSPRG2, EMUACCEL_REL( emuaccel_mtsprg2_rNN ), 0x1f ++ .long EMUACCEL_MTSPRG3, EMUACCEL_REL( emuaccel_mtsprg3_rNN ), 0x1f ++ .long EMUACCEL_MTHID0, EMUACCEL_REL( emuaccel_mthid0_rNN ), 0x1f ++ .long EMUACCEL_RFI, EMUACCEL_REL( emuaccel_rfi ), 0 ++ .long EMUACCEL_UPDATE_DEC, EMUACCEL_REL( emuaccel_update_dec ), 0 ++ .long EMUACCEL_MTSR, EMUACCEL_REL( emuaccel_mtsr ), 0 ++ .long EMUACCEL_NOP, EMUACCEL_REL( emuaccel_nop ), 0 ++ .long 0, 0, 0 /* end marker */ ++ ++ .text +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/emulation.S +@@ -0,0 +1,714 @@ ++/* ++ * Creation Date: <97/07/26 18:23:02 samuel> ++ * Time-stamp: <2004/02/22 13:12:14 samuel> ++ * ++ * ++ * ++ * Low-level emulation of some privileged instructions ++ * ++ * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++MACRO_0(INC_NIP, [ ++ addi r6,r6,4 ++]) ++ ++ ++/************************************************************************/ ++/* program exception vector */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////////// ++ // exception preamble ++ // r1 stack (mregs) ++ // r6,r7 nip / srr1 ++ // cr4-7 flag_bits ++ // ++ // Saved r0-r5 (NOT SAVED: ctr, xer) ++ ++VECTOR_( 0x700, "Program", secint_bad, mac_entry ) ++ EXCEPTION_PREAMBLE // 46 cycles on a G3 ++ TRACE(0x700, "Program") ++ ++ mtcrf 0x10,r7 // put srr1 bits (12-15) into cr3 ++ bt 14,mac_program_trap ++ GET_INSTR_OPCODE // r6=nip, r2-r3, r4=opcode (cr not touched) ++ bt+ 13,emulate_priv_instr ++ bt+ 12,emulate_illegal_instr ++ mtcrf 0x20,r7 // put srr1 bits (8-11) into cr2 ++ bt+ 11,mac_program_trap // bit 11 = fpu_exception ++ ++ // we should not come here ++ MAC_EXIT_SAVE( RVEC_UNUSUAL_PROGRAM_EXCEP ) ++ ++unhandled_priv_inst: ++ MAC_EXIT_SAVE( RVEC_PRIV_INST ) // r4 = opcode ++ ++emulate_illegal_instr: ++ rlwinm r2,r4,32-1,22,31 ++ lwz r3,xMSR(r1) ++ rlwinm r5,r4,14,24,28 // r5 = reg_num << 3 (instr. bits 6-10) ++ rlwimi r2,r4,16,16,21 // r2 = opcode ++ ++ rlwinm r0,r2,0,~0x80 // clear mtspr/mfspr bit ++ cmpwi r0,OPCODE(31,339) // mfspr/mtspr ++ bne 1f ++ ++ rlwinm r7,r7,0,14,10 // clear srr1 bit 11-13 ++ cmpwi cr1,r2,OPCODE(31,339) // mfspr ++ oris r7,r7,0x4 // set bit 13 (privileged instr) ++ ++ beq- cr1,emulate_mfspr // r3=xMSR, r4=opcode, r5=reg_num ++ b emulate_mtspr // must be mtspr ++1: ++#ifdef EMULATE_603 ++ bl emulate_603_instr ++#endif ++ MAC_EXIT_SAVE( RVEC_ILLEGAL_INST ) // r4 = opcode ++ ++ ++/************************************************************************/ ++/* mac exceptions */ ++/************************************************************************/ ++ ++ ///////////////////////////////////////////////////////////// ++ // mac_trap ++ // ++ // r2 exception vector ++ // r6 nip ++ // r7 reason bits (0-15) ++ // ++ // r0,r2-r5 may be modified ++ ++mac_irq_trap: ++ li r2,0x500 ++ li r7,0 // no reason bits ++ b mac_trap ++ ++mac_dec_trap: ++ li r2,0x900 ++ crclr FBIT_DecINT ++ li r7,0 // no reason bits ++ b mac_trap ++ ++ balign_32 ++mac_program_trap: // the reason bits already in r7 are used ++ __BUMP("mac_trap") ++ li r2,0x700 ++mac_trap: ++ lwz r3,xMSR(r1) ++ stw r6,xSRR0(r1) // mac-srr0 = nip ++ mr r4,r3 // copy xMSR to SRR1 ++ mr r6,r2 // new nip ++ rlwinm r5,r3,25+1,31,31 // put MSR_IP (bit 25) in r5[31] ++ rlwimi r4,r7,0,0,15 // copy reason bits from r7 to SRR1 ++ rlwimi r4,r3,0,6,6 // copy MSR_VEC bit of xMSR to SRR1 ++ stw r4,xSRR1(r1) // srr1 = (msr & (0xffff|MSR_VEC)) | (srr1 & ~(0xffff|MSR_VEC)) ++ rlwinm r4,r3,0,25,25 // copy MSR_IP to xMSR ++ neg r5,r5 // r5 = 0xffffffff * MSR_IP ++ rlwimi r4,r3,0,19,19 // copy MSR_ME to xMSR ++ rlwimi r6,r5,0,0,11 // insert exception prefix ++ stw r4,xMSR(r1) ++ GET_TICK_CNT(entry,"mac-expception") ++ b msr_exception_return ++ ++rvec_trace_trap: ++ MAC_EXIT_SAVE( RVEC_TRACE_TRAP ) ++ ++ ++/************************************************************************/ ++/* decode privileged instruction */ ++/************************************************************************/ ++ ++ ///////////////////////////////////////////////////////////// ++ // emulate_priv_instr ++ // r4 opcode ++ // r6,r7 nip/srr1 ++ // ++ // r0,r2-r5,lr free ++ ++ balign_32 ++emulate_priv_instr: ++ rlwinm r2,r4,32-1,22,31 ++ lwz r3,xMSR(r1) ++ rlwinm r5,r4,14,24,28 // r5 = reg_num << 3 (instr. bits 6-10) ++ rlwimi r2,r4,16,16,21 // r2 = opcode ++ ++ GET_TICK_CNT(entry,"get_inst") ++ BUMP("decode_priv_inst") ++ ++ cmpwi cr1,r2,OPCODE(31,339) // mfspr (both user and supervisor mode) ++ beq- cr1,emulate_mfspr // r3=xMSR, r4=opcode, r5=reg_num ++ ++ cmpwi cr2,r2,OPCODE(31,467) // mtspr (both user and supervisor mode) ++ beq- cr2,emulate_mtspr ++ ++ andi. r3,r3,MSR_PR // only emulate in supervisor mode ++ bne- mac_program_trap ++ ++ cmpwi cr3,r2,OPCODE(31,83) // mfmsr ++ beq- cr3,emulate_mfmsr ++ ++ cmpwi cr0,r2,OPCODE(31,146) // mtmsr ++ beq- cr0,emulate_mtmsr ++ ++ cmpwi cr1,r2,OPCODE(19,50) // rfi ++ beq- cr1,emulate_rfi ++ ++ cmpwi cr2,r2,OPCODE(31,595) // mfsr ++ beq- cr2,emulate_mfsr ++ ++ cmpwi cr3,r2,OPCODE(31,659) // mfsrin ++ beq- cr3,emulate_mfsrin ++ ++ cmpwi cr0,r2,OPCODE(31,210) // mtsr ++ beq- cr0,emulate_mtsr ++ ++ cmpwi cr1,r2,OPCODE(31,242) // mtsrin ++ beq- cr1,emulate_mtsrin ++ ++ cmpwi cr2,r2,OPCODE(31,306) // tlbie ++ beq- cr2,emulate_tlbie ++ ++ cmpwi cr3,r2,OPCODE(31,566) // tlbsync ++ beq- cr3,emulate_tlbsync ++ ++ cmpwi cr0,r2,OPCODE(31,467) // dcbi ++ beq- cr0,emulate_dcbi ++#ifdef EMULATE_603 ++ cmpwi cr1,r2,OPCODE(31,978) // tlbld ++ beq- cr1,emulate_tlbld ++ ++ cmpwi cr2,r2,OPCODE(31,1010) // tlbli ++ beq- cr2,emulate_tlbli ++#endif ++ // Program-trap, illegal instruction ++ b unhandled_priv_inst // r4 = opcode ++ ++ ++#ifdef EMULATE_603 ++emulate_603_instr: ++ rlwinm r2,r4,32-1,22,31 ++ rlwimi r2,r4,16,16,21 // r2 = opcode ++ ++ cmpwi cr0,r2,OPCODE(31,978) // tlbld ++ beq cr0,2f ++ cmpwi cr1,r2,OPCODE(31,1010) // tlbli ++ beq cr1,2f ++ cmpwi cr2,r2,OPCODE(31,339) // mfspr ++ beq cr2,1f ++ cmpwi cr3,r2,OPCODE(31,467) // mtspr ++ bnelr cr3 ++1: rlwinm r3,r4,32-16,27,31 ++ rlwimi r3,r4,32-6,22,26 // r3 = spr# ++ cmpwi r3,976 // first 603 SPR ++ bltlr ++ cmpwi r3,982 // last 603 SPR ++ bgtlr ++2: ++ rlwinm r7,r7,0,14,10 // clear bit 11-13 ++ oris r7,r7,0x4 // set bit 13 ++ b emulate_priv_instr ++ ++#endif /* EMULATE_603 */ ++ ++ ++/************************************************************************/ ++/* mac register access */ ++/************************************************************************/ ++ ++MACRO(LOAD_EMUGPR_IM, [dreg,ereg], [ ++.if _ereg <= 7 ++ lwz _dreg,xGPR0+_ereg[]*4(r1) ++.else ++ mr _dreg,rPREFIX[]_ereg ++.endif ++]) ++ ++MACRO(STORE_EMUGPR_IM, [sreg,ereg], [ ++.if _ereg <= 7 ++ stw _sreg,xGPR0+_ereg[]*4(r1) ++.else ++ mr rPREFIX[]_ereg, _sreg ++.endif ++]) ++ ++ balign_32 ++store_gpr_table: ++mFORLOOP([i],0,31,[ ++ STORE_EMUGPR_IM r0,i ++ blr ++]) ++ ++load_gpr_table: ++mFORLOOP([i],0,31,[ ++ LOAD_EMUGPR_IM r0,i ++ blr ++]) ++ ++MACRO(EMU_LOAD_GPR, [reg, scr], [ ++ LI_PHYS( _scr, load_gpr_table ) ++ add rPREFIX[]_scr,_reg,rPREFIX[]_scr ++ mtlr rPREFIX[]_scr ++ blrl ++]) ++ ++MACRO(EMU_STORE_GPR, [reg, scr], [ ++ LI_PHYS( _scr, store_gpr_table ) ++ add rPREFIX[]_scr,_reg,rPREFIX[]_scr ++ mtlr rPREFIX[]_scr ++ blrl ++]) ++ ++ ++ ++/************************************************************************/ ++/* instruction emulation */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////// ++ // emulate_xxxxx ++ // r3 xMSR ++ // r4 opcode ++ // r5 regnum<<3 (from opcode bits 6-10) ++ // ++ // May modify: r0,r2-r5 (lr) ++ ++/********************************************************************/ ++emulate_mfmsr: ++ lwz r0,xMSR(r1) ++ EMU_STORE_GPR r5, /**/ R2 ++ GET_TICK_CNT( entry, "mfmsr" ) ++ b emulation_done ++ ++/********************************************************************/ ++emulate_mfspr: // r3 = xMSR ++ BUMP("emulate_mfspr") ++ rlwimi r4,r4,32-10,21,25 // flip spr ++ rlwinm r0,r3,32-14,31,31 // r0(bit31) = MSR_PR ++ addi r3,r1,K_SPR_HOOKS ++ rlwinm r2,r4,32-4,20,29 // r2 = spr# << 2 ++ addi r4,r1,xSPR_BASE ++ lwzx r3,r2,r3 // hook in r3 ++ and. r0,r0,r3 // privileged SPR? ++ bne- mac_program_trap ++ lwzx r0,r2,r4 // value in r0 ++ mtlr r3 ++ blr // call hook ++ ++/********************************************************************/ ++emulate_mtspr: // r3 = xMSR ++ BUMP("emulate_mtspr") ++ rlwimi r4,r4,32-10,21,25 // flip spr ++ EMU_LOAD_GPR r5, /**/ R2 // value in r0 ++ rlwinm r2,r4,32-4,20,29 // r2 = spr# << 2 ++ addi r4,r1,K_SPR_HOOKS ++ rlwinm r3,r3,32-14,31,31 // r3(bit31) = MSR_PR ++ lwzx r4,r2,r4 // hook in r4 ++ addi r5,r2,xSPR_BASE // r5+r1 points to SPR reg ++ addi r4,r4,4 // branch to hook +4 ++ and. r3,r3,r4 // privileged SPR? ++ bne- mac_program_trap // privileged exception ++ mtlr r4 // lsb is discarded... ++ blr // call hook ++ ++ ++/********************************************************************/ ++ balign_32 ++emulate_mtmsr: ++ lwz r3,xMSR(r1) // r3 = old MSR ++ LI_PHYS( R2, load_gpr_table ) ++ add r2,r5,r2 ++ mtlr r2 ++ blrl // r0 = new MSR ++ ++ INC_NIP ++ bl msr_altered ++ ++ GET_TICK_CNT(entry, "mtmsr") ++ BUMP("emulate_mtmsr") ++ ++ beq+ cr1,emulation_done_noinc ++ MAC_EXIT_SAVE( RVEC_MSR_POW ) // POW 1 => doze ++ ++ ++/********************************************************************/ ++emulate_rfi: ++ BUMP("rfi") ++ lis r4,(MSR_VEC)>>16 ++ lwz r0,xSRR1(r1) ++ ori r4,r4,0xffff ++#ifdef EMULATE_603 ++ oris r4,r4,(MSR_TGPR)>>16 ++#endif ++ lwz r3,xMSR(r1) // r3 = old MSR ++ and r0,r0,r4 ++ andc r5,r3,r4 ++ lwz r6,xSRR0(r1) // new nip = SRR0 ++ or r0,r0,r5 ++ ++ bl msr_altered // r0,r2-r5, r7 [srr1] updated ++ ++ GET_TICK_CNT(entry,"rfi") ++ ++ lwz r3,K_BREAK_FLAGS(r1) // break at rfi support ++ andi. r3,r3,BREAK_RFI ++ beq+ exception_return ++ li r4,BREAK_RFI // r4 = flag causing the break ++ MAC_EXIT_SAVE( RVEC_BREAK ) ++ ++ ++/********************************************************************/ ++#ifdef EMULATE_603 ++emulate_tlbli: ++ LOADI r3,EXTERN(do_tlbli) ++ b 1f ++emulate_tlbld: ++ LOADI r3,EXTERN(do_tlbld) ++ b 1f ++emulate_tlbie: ++ LOADI r3,EXTERN(do_tlbie) ++1: INC_NIP ++ rlwinm r5,r4,32-8,24,28 // r5 = #B << 3 ++ EMU_LOAD_GPR r5, /**/ R2 // value ret. in r0 ++ mr r4,r0 // r4 = ea ++ b call_kernel_save ++#else ++emulate_tlbie: ++ b emulation_done ++#endif /* EMULATE_603 */ ++ ++/********************************************************************/ ++emulate_tlbsync: ++ b emulation_done ++ ++/********************************************************************/ ++emulate_dcbi: ++ b unhandled_priv_inst // r4 = opcode ++ ++/********************************************************************/ ++emulate_mfsrin: ++ rlwinm r2,r4,32-8,24,28 // r2 = #B << 3 ++ EMU_LOAD_GPR r2, /**/ R3 // r0 = reg B ++ rlwinm r3,r0,6,26,29 // r3 = #sr << 2 ++ b 1f ++emulate_mfsr: ++ rlwinm r3,r4,32-14,26,29 // r3 = #sr << 2 ++1: addi r2,r1,xSEGR_BASE ++ lwzx r0,r3,r2 ++ EMU_STORE_GPR r5, /**/ R2 ++ GET_TICK_CNT(entry, "mfsr") ++ BUMP("mfsr_") ++ b emulation_done ++ ++ ++ ++/************************************************************************/ ++/* SPR - emulation */ ++/************************************************************************/ ++ ++ //////////////////////////////////////////////////////////// ++ // read (offset 0) ++ // r0 spr_value ++ // r2 spr << 2 ++ // r5 dreg << 3 ++ // ++ // write (offset 4) ++ // r0 gpr_value ++ // r2 spr << 2 ++ // r5 spr offset (relative r1) ++ // ++ // Safe to modify: r2-r5, lr ++ // NOT SAVED: ctr, xer ++ ++/********************************************************************/ ++simple_mfspr: ++ EMU_STORE_GPR r5, /**/ R3 ++ GET_TICK_CNT(entry,"simple_mfspr") ++ b emulation_done ++ ++GLOBAL_SYMBOL(r__spr_read_write): ++spr_read_write: ++ b simple_mfspr ++ stwx r0,r5,r1 // value in r0 ++ GET_TICK_CNT(entry,"simple_mtspr") ++ b emulation_done ++ ++ ++/********************************************************************/ ++GLOBAL_SYMBOL(r__spr_read_only): ++spr_read_only: ++ b simple_mfspr // allow read ++ b emulation_done // ignore write ++ ++/********************************************************************/ ++GLOBAL_SYMBOL(r__spr_illegal): ++spr_illegal: ++ nop // spr read entry ++ rlwinm r7,r7,0,15,10 // clear srr1 bit 11-14 ++ oris r7,r7,0x8 // set bit 12 (privileged instr) ++ b mac_program_trap ++ ++ ++/********************************************************************/ ++unhandled_spr_read: ++ srwi r4,r2,2 ++ srwi r5,r5,3 ++ // r4 = spr# ++ // r5 = dest gpr ++ MAC_EXIT_SAVE( RVEC_SPR_READ ) ++ ++unhandled_spr: ++ b unhandled_spr_read // read hook (offs 0) ++unhandled_spr_write: // write hook (offs 4) ++ srwi r4,r2,2 ++ mr r5,r0 ++ // r4 = spr# ++ // r5 = register-value ++ MAC_EXIT_SAVE( RVEC_SPR_WRITE ) ++ ++/********************************************************************/ ++spr_bat: ++ b simple_mfspr // read has no side-effects ++ INC_NIP ++ LOADI r3,EXTERN(do_mtbat) ++ bl save_middle_regs // Must do this before touching r6-r12 ++ srwi r4,r2,2 // r4 = spr# ++ mr r5,r0 // r5 = value ++ li r6,0 // not forced ++ b call_kernel ++ ++/********************************************************************/ ++spr_sdr1: ++ b simple_mfspr // read has no side-effects ++ INC_NIP ++ LOADI r3,EXTERN(do_mtsdr1) ++ mr r4,r0 // r4 = value ++ b call_kernel_save ++ ++ ++ ++ ++/************************************************************************/ ++/* handle MSR changes */ ++/************************************************************************/ ++ ++ //////////////////////////////////////////////////////////// ++ // msr_exception_return (exception taken) ++ // ++ // r6, r7: nip / srr1 ++ // ++ // modifies: r0,r2-r5 (r7 updated) ++ ++ balign_16 ++msr_exception_return: ++ addi r3,r1,K_UNMAPPED_SR_BASE // set unmapped context ++ li r7,(MSR_ME | MSR_SE | MSR_IR | MSR_DR | MSR_PR) ++ stw r3,K_CUR_SR_BASE(r1) ++ li r5,(fb_DbgTrace | fb_Trace) ++ ori r7,r7,MSR_EE ++ ++ bt+ FBIT_DbgTrace, 1f ++ li r5,0 ++ rlwinm r7,r7,0,~MSR_SE ++1: ++ stw r3,K_SR_DATA(r1) ++ li r4,fb_LoadSegreg ++ ++ stw r3,K_SR_INST(r1) ++ mtcrf TRACE_CR_FIELD,r5 // set singlestep bits [cr6] ++ mtcrf MMU_CR_FIELD,r4 ++ ++ stw r7,K_MSR(r1) ++ b exception_return ++ ++ ++ //////////////////////////////////////////////////////////// ++ // msr_altered ++ // ++ // r6, r7: nip / srr1 ++ // ++ // r0 = new msr ++ // r3 = old msr ++ // ++ // Sets cr1.ne if we MSR_POW is set ++ // ++ // M: r2-r5 (r7 updated). ++ // r0 may _NOT_ be modified ++ ++#define MSR_CLEARBITS (MSR_FP | MSR_FE0 | MSR_FE1 | MSR_BE | MSR_SE) ++#define MSR_COPYBITS (MSR_BE | MSR_SE) ++ ++ balign_32 ++msr_altered: ++#ifdef EMULATE_603 ++ bf+ FBIT_603_AltGPR,7f // 603 alternate GPR support ++ rlwinm. r5,r0,0,MSR_TGPR ++ bne+ 7f ++ lwz r2,xGPRSAVE0_603(r1) // MSR_TGPR cleared... ++ lwz r4,xGPRSAVE1_603(r1) ++ lwz r5,xGPRSAVE2_603(r1) ++ stw r2,xGPR0(r1) ++ lwz r2,xGPRSAVE3_603(r1) ++ stw r4,xGPR1(r1) ++ stw r5,xGPR2(r1) ++ stw r2,xGPR3(r1) ++ crclr FBIT_603_AltGPR ++7: ++#endif ++ li r7,(MSR_ME | MSR_SE | MSR_IR | MSR_DR | MSR_PR) ++ stw r0,xMSR(r1) ++ xor r3,r3,r0 // r3 == MSR bit toggle ++ bt- FBIT_IRQPending,test_for_irq // M: r2 ++irq_test_ret: ++ rlwinm r4,r0,0,MSR_POW // MSR_POW ++ ori r7,r7,MSR_EE ++ andi. r3,r3,(MSR_DR|MSR_IR|MSR_PR) // MMU change (cr unused)? ++ bt- FBIT_DecINT,test_for_dec // M: r2 ++dec_test_ret: ++ cmpwi cr1,r4,0 // MSR_POW set? ++ li r2,(fb_DbgTrace | fb_Trace) ++ cmpwi cr2,r3,0 ++ bt- FBIT_DbgTrace,1f ++ rlwinm r2,r0,(21+32-FBIT_Trace),fb_Trace // MSR_SE[21] -> FBIT_Trace ++ rlwimi r7,r0,0,(MSR_SE|MSR_BE) // no debugger; copy MSR_SE and MSR_BE ++1: ++ stw r7,K_MSR(r1) ++ mtcrf TRACE_CR_FIELD,r2 // set singlestep bits [cr6] ++ ++ bne cr2,1f // bnelr is slower... ++ blr ++1: ++ /* MMU change */ ++ BUMP("MMU-change") ++ ++ andi. r3,r0,(MSR_IR | MSR_DR) // IR DR part of index ++ addi r5,r1,K_MSR_SR_TABLE ++ addi r4,r3,MSR_DR // splitmode (MSR_DR != MSR_IR) testing ++ rlwimi r3,r0,32-8,25,25 // [PR IR DR] index to K_MSR_SR_TABLE ++ lwzux r3,r5,r3 // set sr bases from K_MSR_SR_TABLE ++ andi. r4,r4,MSR_IR // non-zero if in splitmode ++ lwz r2,4(r5) ++ li r4,(fb_InSplitmode | fb_LoadSegreg | fb_PrepareSplitmode) ++ lwz r5,8(r5) ++ stw r3,K_CUR_SR_BASE(r1) // new sr base in r3 (used below) ++ stw r2,K_SR_DATA(r1) ++ bne- 1f ++ li r4,fb_LoadSegreg // cur_sr_base changed ++1: stw r5,K_SR_INST(r1) ++ mtcrf MMU_CR_FIELD,r4 ++ blr ++ ++test_for_irq: ++ BUMP("test-for-irq") ++ and r2,r3,r0 // check whether we are turning external interrupts on ++ andi. r2,r2,MSR_EE // we need to recheck IRQs in userspace then ++ beq+ 1f ++ lwz r4,xHOSTIRQ_ACTIVE_CNT(r1) ++ cmpwi r4,0 // only return if some host irq is up ++ beq+ 1f ++ MAC_EXIT_SAVE(RVEC_CHECK_IRQS) ++ ++1: andi. r2,r0,MSR_EE ++ beq irq_test_ret ++ b mac_irq_trap ++ ++test_for_dec: ++ BUMP("test-for-dec") ++ andi. r2,r0,MSR_EE ++ beq dec_test_ret ++ b mac_dec_trap ++ ++force_msr_altered: ++ BUMP("force-msr-altered") ++ lwz r0,xMSR(r1) // r0 = new MSR ++ xori r3,r0,(MSR_DR|MSR_IR) // r3 = faked old MSR ++ b msr_altered // might throw an exception... ++ ++ // msr_altered( kv ) ++GLOBAL_SYMBOL(r__msr_altered): ++ lwz r5,xFLAG_BITS(r3) ++ ori r5,r5,fb_MsrModified ++ stw r5,xFLAG_BITS(r3) ++ blr ++ ++ ++/************************************************************************/ ++/* initialize special purpose register table */ ++/************************************************************************/ ++ ++MACRO(SPR_HOOK, [spr, hook], [ LI_PHYS( R8, _hook ) ; stw r8,(((_spr)*4)+K_SPR_HOOKS)(r3) ]) ++ ++// The LSB of a SPR hook specifies that the SPR is privileged (these bits are ++// set from C-code). ++ ++ // r3 = kvars ++GLOBAL_SYMBOL(r__initialize_spr_table): ++ LI_PHYS( R7, unhandled_spr ) ++ addi r8,r3,K_SPR_HOOKS-4 ++ li r9,1024 ++ mtctr r9 ++1: stwu r7,4(r8) ++ bdnz 1b ++ ++ // XXX for now... ++ SPR_HOOK TBWU, spr_read_write ++ SPR_HOOK TBWL, spr_read_write ++ ++ // SPRs that have side effects ++ SPR_HOOK SDR1, spr_sdr1 ++ SPR_HOOK DEC, spr_dec ++ ++ // BATs ++ mFORLOOP([nn],0,15,[ ++ SPR_HOOK eval(nn+IBAT0U), spr_bat ++ ]) ++ blr ++ ++ ++/************************************************************************/ ++/* initialize msr segment register table */ ++/************************************************************************/ ++ ++ ///////////////////////////////////////////////////////////// ++ // initialize_sr_offs_table ++ // ++ // Copy sr_offs_table to K_MSR_SR_TABLE ++ // r1 is added to each element ++ ++initialize_msr_sr_table: ++ mflr r8 // Get address of table ++ bl sr_offs_table ++ mflr r3 ++ mtlr r8 ++ ++ li r5,4*8 // #words in table ++ mtctr r5 ++ addi r3,r3,-4 ++ addi r4,r1,K_MSR_SR_TABLE-4 ++1: ++ lwzu r6,4(r3) ++ add r6,r6,r1 // And add r1 ++ stwu r6,4(r4) ++ bdnz 1b ++ blr ++ ++ // Used to construct msr_sr_table (mbase is added) ++sr_offs_table: ++ blrl ++ /* K_CUR_SR_BASE, K_SR_DATA_BASE, K_SR_INST_BASE, dummy */ ++ ++ .long K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, 0 ++ .long K_SPLIT_SR_BASE, K_SV_SR_BASE, K_UNMAPPED_SR_BASE, 0 /* DR */ ++ .long K_SPLIT_SR_BASE, K_UNMAPPED_SR_BASE, K_SV_SR_BASE, 0 /* IR */ ++ .long K_SV_SR_BASE, K_SV_SR_BASE, K_SV_SR_BASE, 0 /* DR|IR */ ++ ++ .long K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, K_UNMAPPED_SR_BASE, 0 /* PR */ ++ .long K_SPLIT_SR_BASE, K_USER_SR_BASE, K_UNMAPPED_SR_BASE, 0 /* PR|DR */ ++ .long K_SPLIT_SR_BASE, K_UNMAPPED_SR_BASE, K_USER_SR_BASE, 0 /* PR|IR */ ++ .long K_USER_SR_BASE, K_USER_SR_BASE, K_USER_SR_BASE, 0 /* PR|DR|IR */ +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/entry.S +@@ -0,0 +1,433 @@ ++/* ++ * Creation Date: <2001/01/30 00:22:35 samuel> ++ * Time-stamp: <2004/03/07 13:33:39 samuel> ++ * ++ * ++ * ++ * Emulator/mac switching ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++/* Short note about DEC. Due to the kernel implementation of the DEC ++ * exception handler (and get_time_of_day) in the 2.3/2.4 kernel, we ++ * must try to maintain coherency between DEC and TB. In any case, ++ * we must NEVER let DEC tick faster than TB, or get_time_of_day will ++ * occasionally return bogus values (the result is usually ++ * misbehaving X). ++ */ ++ ++/************************************************************************/ ++/* Mac Entry */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////// ++ // mac_entry_initialize ++ // ++ // Run once in order to store certain things (segment ++ // registers and NIP) ++ // ++ // sprg1 userspace stack ++ // r6 emulator return point after 'call_kernel' ++ // ++ // Safe to modify: r0-r12, lr, ctr ++ ++mac_entry_initialize: ++ __ZERO_TICK_CNT(entry) ++ ++ // Save emulator return point (skip over illegal inst) ++ mfsrr0 r5 ++ addi r5,r5,4 ++ stw r5,K_EMULATOR_NIP(r1) // This sets the return point once and for all ++ stw r2,K_EMULATOR_TOC(r1) // r2==TOC (not on linux though) ++ stw r6,K_EMULATOR_KCALL_NIP(r1) // Return point after 'call_kernel' ++ mfsrr1 r6 ++ mfsprg_a1 r3 ++ stw r6,K_EMULATOR_MSR(r1) // we want to return through mac_exit ++ stw r3,K_EMULATOR_STACK(r1) ++ ++ lwz r3,xFLAG_BITS(r1) // Best to initialize the flag bits ++ mtcr r3 ++ ++ // msr to be used in mac-mode ++ LOADI r3,(MSR_ME | MSR_IR | MSR_DR | MSR_PR | MSR_EE) ++ stw r3,K_MSR(r1) ++ ++ PERF_MONITOR_SETUP /**/ r4 ++ ++ addi r3,r1,K_EMULATOR_SR // Save segment registers ++ SAVE_SEGMENT_REGS r3, /**/ r4,r5 ++ SAVE_IBATS K_IBAT0U_SAVE, /**/ r3 // And save linux BAT registers ++ SAVE_DBATS K_DBAT0U_SAVE, /**/ r3 ++ ++ bl initialize_msr_sr_table ++ ++ addi r3,r1,K_EMULATOR_SR ++ LOAD_SEGMENT_REGS r3, /**/ r4,r5 ++ ++ li r3,RVEC_EXIT ++ b exit_ ++ ++ ++ //////////////////////////////////////////////////////////////////// ++ // mac_entry [ENTRYPOINT] ++ // ++ // sprg1 userspace stack ++ // r4 MOL_ENTRY_R4_MAGIC ++ // r5 magic ++ // r6 call_kernel return point (if initializing) ++ // r7 session number | initialize flag ++ // ++ // srr1 emulator msr ++ // r13-r31 mac gprs ++ // fr14-fr31 mac fp registers ++ // fr0-fr12 mac fp registers (see xFPU_STATE) ++ ++1: li r4,1 ++ stw r4,ST_MAGIC(r1) ++2: mtcr r3 // restore registers ++ CONTINUE_TRAP( 0x700 ) // not MOL, take the trap ++ ++ balign_32 ++mac_entry: ++ lis_svh R1,SPECVAR_SESSION_TABLE ++ cmpwi r4,MOL_ENTRY_R4_MAGIC // MOL switch magic. ++ ori_svl R1,R1,SPECVAR_SESSION_TABLE ++ bne- 2b ++ lwz r4,ST_MAGIC(r1) // check that the magic match ++ cmplwi r5,1 // and is greater than 1 ++ cmpw cr1,r5,r4 ++ ble- 2b ++ addi r5,r1,ST_KVARS_PH // get kvars for this session ++ rlwinm r4,r7,2,((MAX_NUM_SESSIONS-1)*4) ++ bne- cr1,1b // r1 must point to session table ++ lwzx r1,r4,r5 // set r1 to kvars ++ cmpwi cr1,r1,0 ++ cmplwi r7,MAX_NUM_SESSIONS ++ beq- cr1,2b // kvars == NULL ++ bge- mac_entry_initialize // initialize flag set ++ ++ // ===================================================================== ++ // entrypoint ++ // ===================================================================== ++ ++ __ZERO_TICK_CNT(entry) ++ TRACE(0x1111, "mac_entry") ++ ++ // Save emulator registers (r1,msr) and restore flag bits ++ mfsprg_a1 r3 ++ lwz r4,xFLAG_BITS(r1) ++ stw r3,K_EMULATOR_STACK(r1) ++ mfsrr1 r6 ++ mtcr r4 ++ stw r6,K_EMULATOR_MSR(r1) // The MSR_FP/MSR_VEC bits are of interest... ++ ++ // Setup mac-environment ++ ++ btl FBIT_RecalcDecInt, recalc_int_stamp // M: r0,r2-r5 ++ bl set_mac_context // M: r0,r2-r12,XER ++ bl set_mol_dec // M: r0,r2-r5 ++ ++ crset FBIT_LoadSegreg // Load segment registers below ++ ++ RESTORE_MIDDLE_REGS // Loads r6,r7 (nip/msr) r8-r12, ctr, xer, ++ ++ rlwinm r7,r7,0,~MSR_VEC // We always clear MSR_VEC (MSR_FP should be off already) ++ stw r7,K_MSR(r1) // (enabling MSR_VEC is relatively cheap) ++ btl- FBIT_MsrModified,msr_altered_entry ++ ++ GET_TICK_CNT(entry, "mac_entry") ++ ++ bt- FBIT_DecINT,test_for_dec_int // check for DEC interrupts ++ b exception_return ++ ++test_for_dec_int: ++ lwz r3,xMSR(r1) ++ rlwinm. r3,r3,0,MSR_EE // MSR_EE is set? ++ bne mac_dec_trap // if so take a DEC interrupt ++ b exception_return ++ ++msr_altered_entry: ++ crclr FBIT_MsrModified ++ b force_msr_altered ++ ++ ++ ///////////////////////////////////////////////////////////// ++ // All paths back to mac-mode goes through one of these ++ // functions. ++ // ++ // emulation_done ++ // emulation_done_noinc ++ // exception_return ++ ++ balign_32 ++emulation_done: ++ addi r6,r6,4 // increase NIP ++emulation_done_noinc: ++ bt- FBIT_Trace, rvec_trace_trap ++ GET_TICK_CNT(entry,"emulation_done") ++exception_return: ++ btl- FBIT_LoadSegreg,reload_sr // M: r3-r5, r6=nip ++ mtsrr1 r7 // setup SRR1 ++ lwz r0,xCR(r1) ++ lwz r3,xLINK(r1) ++ mtsrr0 r6 ++ lwz r4,xGPR4(r1) ++ lwz r5,xGPR5(r1) ++ mfcr r2 // Save flag bits ++ lwz r6,xGPR6(r1) ++ lwz r7,xGPR7(r1) ++ mtlr r3 ++ stw r2,xFLAG_BITS(r1) ++ lwz r2,xGPR2(r1) ++ lwz r3,xGPR3(r1) ++ mtcr r0 ++ lwz r0,xGPR0(r1) ++ __GET_TICK_CNT(entry,"asm-all") // performance measurements ++ __BUMP("asm-all") ++ lwz r1,xGPR1(r1) ++ rfi ++ ++ ++/************************************************************************/ ++/* Exit Mac-Mode Paths */ ++/************************************************************************/ ++ ++ // THESE ARE _ALL_ THE POSSIBLE EXIT PATHS. KEEP IT THAT WAY ++ // OR HAVE A *VERY GOOD* REASON TO INTRODUCE A NEW ONE. ++ ++ ///////////////////////////////////////////////////////// ++ // giveup_fpu ++ // ++ // Save fpscr and fpr13 and clear the MSR_FP bit. ++ // Restore the emulator fpscr value. ++ // ++ // IMPORTANT: Call this function only if FBIT_FPUInUse is set ++ // ++ // modifies: r7,r8 (turns on MSR_FP if FP is set in K_MSR) ++ ++giveup_fpu: ++ li r8,MSR_FP | MSR_FE0 | MSR_FE1 ++ lwz r7,K_MSR(r1) ++ andc r8,r7,r8 // Clear MSR_FEx bits ++ stw r8,K_MSR(r1) ++ ++ mfmsr r7 // Temporary enable FPU in order to ++ ori r8,r7,MSR_FP // save fpscr and fpr13 ++ mtmsr r8 ++ isync ++ stfd fr13,xFPR13(r1) ++ mffs fr13 ++ stfd fr13,xFPSCR-4(r1) ++ li r7,FPU_STATE_DIRTY ++ lfd fr13,xEMULATOR_FPSCR-4(r1) // We must restore FPSCR before since the emulator might ++ mtfsf 0xff,fr13 // use the FPU at any time, for instance in a signal handler. ++ stw r7,xFPU_STATE(r1) // Go to FPU_STATE_DIRTY ++ ++ crclr FBIT_FPUInUse // FPU no longer in use ++ blr ++ ++ ++ //////////////////////////////////////////////////////// ++ // PREPARE_ERET ++ // ++ // M: r0,r2, r9-r11 ++ ++MACRO(PREP_ERET,[nip_variable], [ ++ btl FBIT_MolDecLoaded, set_kernel_dec // M: r0,r2,r9-r11 ++ ++ lwz r10,_nip_variable[](r1) ++ mfcr r9 ++ lwz r11,K_EMULATOR_MSR(r1) ++ mtsrr0 r10 ++ lwz r2,K_EMULATOR_TOC(r1) ++ stw r9,xFLAG_BITS(r1) ++ mtsrr1 r11 ++]) ++ ++ //////////////////////////////////////////////////////// ++ // mac_exit (return to emulator) ++ // r3 RVEC return code ++ // ++ // On stack: nip, ctr, lr, xer, r0-r12 ++ // In registers: r13-r31 ++ ++mac_exit: ++ TRACE(0x2220, "mac_exit") ++ bl set_emulator_context // M: r0,r2,r7-r11,XER ++exit_: ++ PREP_ERET K_EMULATOR_NIP // M: r0-r2,r9-r11 ++ GET_TICK_CNT(entry, "mac_exit") ++ lwz r1,K_EMULATOR_STACK(r1) ++ rfi ++ ++ ++ //////////////////////////////////////////////////////// ++ // take_exception (take a linux exception) ++ // ++ // On stack: nip, ctr, lr, xer, r0-r12 ++ // In registers: r13-r31 ++ ++take_exception: ++ TRACE(0x2221, "take_exception") ++ ++ mflr r12 ++ bl set_emulator_context // M: r0,r2,r7-r11,XER ++ ++ PREP_ERET K_EMULATOR_NIP // M: r0,r2,r9-r11 ++ GET_TICK_CNT(entry, "take_exception") ++ lwz r1,K_EMULATOR_STACK(r1) ++ mtlr r12 ++ li r3,RVEC_NOP ++ blr ++ ++ ++ ////////////////////////////////////////////////////////////// ++ // call_kernel (call mol kernel routine) ++ // r3 kernel routine ++ // r4..r6 args ++ // ++ // On stack: nip, ctr, lr, xer, r0-r12 ++ // In registers: r13-r31 ++ ++#ifdef __linux__ ++call_kernel_save: ++ bl save_middle_regs // saves r8-r11, nip, ctr, xer ++call_kernel: ++ bl set_emulator_context // M: r0,r2,r7-r11,XER ++ ++ TRACE(0x2222, "call_kernel") ++ ++ lwz r8,K_KERNEL_VARS(r1) // r8 = kvars (lvptr) ++ PREP_ERET K_EMULATOR_KCALL_NIP // M: r0,r2,r9-r11 ++ GET_TICK_CNT(entry, "call_kernel_save") ++ lwz r1,K_EMULATOR_STACK(r1) ++ ba 0x2f00 // MOL trampoline ++#endif ++ ++/************************************************************************/ ++/* Set Mac/Emulator Context */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////////// ++ // set_mac_context [r0,r2-r12, ctr, --->XER<---] ++ // ++ // - clear BATs (except DBAT0) ++ // - setup sprgs ++ // - reload_sr loads segment registers later on ++ // ++ // Currently unmodified r8-r12, ctr ++ ++set_mac_context: ++ // Save and setup SPRG2 (magic) and SPRG3 (mol stack) ++ mfsprg_a2 r6 ++ mfsprg_a3 r7 ++ stw r6,K_EMULATOR_SPRG2(r1) ++ stw r7,K_EMULATOR_SPRG3(r1) ++ li r2,MOL_SPRG2_MAGIC ++ mtsprg_a3 r1 ++ mtsprg_a2 r2 ++ ++ li r4,0 ++ mtspr IBAT0U,r4 ++ mtspr IBAT1U,r4 ++ mtspr IBAT2U,r4 ++ mtspr IBAT3U,r4 ++ // DBAT0 set from reload_sr ++ mtspr DBAT1U,r4 ++ mtspr DBAT2U,r4 ++ mtspr DBAT3U,r4 ++#ifdef __darwin__ ++ lwz r4,K_MOL_SDR1(r1) ++ mtsdr1 r4 ++#endif ++ blr ++ ++ ++ /////////////////////////////////////////////////////////////// ++ // set_emulator_context [r0,r2,r7-r11,cr, --->XER<---] ++ // ++ // - load segr 0-15 with emulator context ++ // - restore BATs ++ // - restore DEC register ++ ++set_emulator_context: ++ lwz r0,K_EMULATOR_SPRG2(r1) ++ lwz r2,K_EMULATOR_SPRG3(r1) ++ mtsprg_a2 r0 ++ mtsprg_a3 r2 ++ ++ // Restore segment registers ++ addi r8,r1,K_EMULATOR_SR ++ LOAD_SEGMENT_REGS r8, /**/ r2,r10 ++ ++ // BATS, r11 = linux DEC ++ ++ lwz r7,K_IBAT0U_SAVE(r1) ++ mtspr IBAT0U,r7 ++ lwz r2,K_IBAT1U_SAVE(r1) ++ mtspr IBAT1U,r2 ++ lwz r7,K_IBAT2U_SAVE(r1) ++ mtspr IBAT2U,r7 ++ lwz r2,K_IBAT3U_SAVE(r1) ++ mtspr IBAT3U,r2 ++ ++ lwz r7,K_DBAT0U_SAVE(r1) ++ mtspr DBAT0U,r7 ++ lwz r7,K_DBAT0L_SAVE(r1) // must also restore lower bat... ++ mtspr DBAT0L,r7 ++ lwz r2,K_DBAT1U_SAVE(r1) ++ mtspr DBAT1U,r2 ++ lwz r7,K_DBAT2U_SAVE(r1) ++ mtspr DBAT2U,r7 ++ lwz r2,K_DBAT3U_SAVE(r1) ++ mtspr DBAT3U,r2 ++#ifdef __darwin__ ++ lwz r2,K_OS_SDR1(r1) ++ mtsdr1 r2 ++ fix_sprg2 /**/ R2 // must not modify sprg2 (i.e. sprg_a0) under OSX 10.3 ++#endif ++ blr ++ ++ ++/************************************************************************/ ++/* Reload Segment Registers */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////////// ++ // reload_sr ++ // ++ // r6 = mac-nip ++ // ++ // - loads segr 0-15 with mac context [modifies r3-r5] ++ // - reloads DBAT0 (used for splitmode) ++ // ++ // Modifies: r3-r5 ++ ++reload_sr: ++ bt FBIT_InSplitmode,prepare_splitmode // M: r0,r3-r5, r6=mac-nip ++ ++ lwz r3,K_TRANSL_DBAT0L(r1) ++ lwz r4,K_TRANSL_DBAT0U(r1) ++ li r5,0 ++ mtspr DBAT0L,r3 ++ mtcrf MMU_CR_FIELD,r5 // clear FBIT_LoadSegreg (and splitmode stuff) ++ mtspr DBAT0U,r4 ++1: ++ lwz r4,K_CUR_SR_BASE(r1) ++ LOAD_SEGMENT_REGS r4, /**/ r3,r5 ++ blr ++ ++ret_from_prep_splitmode: ++ lwz r3,K_SPLIT_DBAT0L(r1) ++ lwz r4,K_SPLIT_DBAT0U(r1) ++ li r5,fb_InSplitmode ++ mtspr DBAT0L,r3 ++ mtcrf MMU_CR_FIELD,r5 // clear FBIT_LoadSegreg and FBIT_PrepareSplitmode ++ mtspr DBAT0U,r4 ++ b 1b +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/iopage.S +@@ -0,0 +1,89 @@ ++/* ++ * Creation Date: <97/07/26 18:23:02 samuel> ++ * Time-stamp: <2002/07/06 12:12:10 samuel> ++ * ++ * ++ * ++ * IO low-level support ++ * ++ * Copyright (C) 2002 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++ // NOTE: This function is also called from the splitmode secondary interrupt ++ // handler (splitmode segment registers are resetup at return). ++ ++ ++ /////////////////////////////////////////////////////////////////// ++ // check_io_page ++ // ++ // xINST_OPCODE is always valid at this point ++ // ++ // Examine if the page (which DAR points to) is an I/O page. ++ // Safe to modify: r0,r2-r12 ++ ++check_io_page: ++ // Is this is an IO-page? IMPORTANT: we must *never* insert mappings ++ // that are unreadable by supervisor (will cause a freeze right here). ++ ++ mfdsisr r10 // r10 = DSISR ++ rlwinm. r3,r10,0,1,1 // BIT 1 set if no PTE (or BAT mapping) ++ bnelr ++ mfdar r8 ++ ++ mfmsr r7 ++ ori r3,r7,MSR_DR // set MSR_DR ++ mtmsr r3 ++ isync ++ ++ rlwinm r5,r8,0,0,19 // mask page index ++ ++ // XXX: TO BE FIXED. These instruction will _never_ cause an exceptions on a ++ // single processor system. However, on a SMP machine we *could* receive a ++ // tlbie invalidate broadcast. Thus we must implement a secondary ++ // interrupt handler to cover that case. ++ ++ lwz r2,IOP_MAGIC(r5) ++ lwz r3,IOP_MAGIC2(r5) // These should _never_ cause any exceptions ++ lwz r9,IOP_ME_PHYS(r5) // r9 = physical addr of iopage ++ ++ mtmsr r7 // restore MSR ++ isync ++ ++ lis r6,HI(IO_PAGE_MAGIC_1) // check MAGIC 1 ++ ori r6,r6,LO(IO_PAGE_MAGIC_1) ++ cmplw r6,r2 ++ bnelr ++ ++ lis r7,HI(IO_PAGE_MAGIC_2) // check MAGIC 2 ++ ori r7,r7,LO(IO_PAGE_MAGIC_2) ++ cmplw r7,r3 ++ bnelr ++ ++ // Obtain translation info from the iopage: ++ // ++ // r4 = mphys_ioaddr = iop->mphys | (dar & 0xfff); ++ // r5 = usr_data = iop->usr_data[ (dar & 0xfff) >> 3 ]; ++ // ++ lwz r4,IOP_MPHYS(r9) ++ rlwimi r4,r8,0,20,31 // insert page offset ++ ++ rlwinm r7,r8,32-1,21,29 // grain = double word ++ addi r7,r7,IOP_USR_DATA // usr_data[ (dar&0xfff) ] ++ lwzx r5,r9,r7 // r5 = usr_data ++ ++ rlwinm. r2,r10,0,6,6 // was it a write? (r10=DSISR) ++ bne handle_write ++ ++ // r4 = mphys_ioaddr ++ // r5 = usr_data ++ MAC_EXIT( RVEC_IO_READ ) ++ ++handle_write: ++ // r4 = mphys_ioaddr ++ // r5 = usr_data ++ MAC_EXIT( RVEC_IO_WRITE ) +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/linux.S +@@ -0,0 +1,129 @@ ++/* ++ * Creation Date: <2001/02/24 14:08:28 samuel> ++ * Time-stamp: <2003/09/03 12:34:20 samuel> ++ * ++ * ++ * ++ * Linux Kernel Hooks ++ * ++ * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++ //////////////////////////////////////////////////////// ++ // flush_hash_page_hook ++ // ++ // Kernel hook ++ // ++ // r3: context ++ // r4: virtual address ++ // r5: 2.4.6 pointer to linux PTE (2.4.6 or later) ++ // 2.6 pmdval ++ // r6: 2.6 count ++ // r10: return address ++ // ++ // [must not modify: r3-r5,r10 - otherwise normal C-function] ++ // MMU is ON ++ ++.set STACK_SPACE, 32 ++.set STACK_LR, STACK_SPACE+4 ++.set STACK_V0, 8 ++.set STACK_V1, 12 ++.set STACK_V2, 16 ++.set STACK_V3, 20 ++.set STACK_V4, 24 ++.set STACK_V5, 28 ++ ++FHOOK( FHOOK_FLUSH_HASH_PAGE ) ++GLOBAL_SYMBOL( r__flush_hash_page_hook ): ++ stwu r1,-STACK_SPACE(r1) // Push stackframe ++ mflr r0 ++ stw r0,STACK_LR(r1) ++ ++ LOADI r7,EXTERN(do_flush) ++ mtctr r7 ++ ++ stw r10,STACK_V1(r1) // Save registers ++ stw r3,STACK_V2(r1) ++ stw r4,STACK_V3(r1) ++ stw r5,STACK_V4(r1) ++#ifdef LINUX_26 ++ stw r6,STACK_V5(r1) ++#else ++ li r6,1 ++#endif ++ bctrl ++ ++ lwz r10,STACK_V1(r1) // Restore registers ++ lwz r3,STACK_V2(r1) ++ lwz r4,STACK_V3(r1) ++ lwz r5,STACK_V4(r1) ++#ifdef LINUX_26 ++ lwz r6,STACK_V5(r1) ++#endif ++ ++ lwz r0,STACK_LR(r1) // Pop stackframe ++ addi r1,r1,STACK_SPACE ++ mtlr r0 ++ blr ++ ++ ++/************************************************************************/ ++/* lowmem reallocations */ ++/************************************************************************/ ++ ++#ifdef CONFIG_SMP ++ ++ /* r3=ea, r4=pte_slot, r5=pte1, r6=pte2, r7=lock, r8=lockval, M: r0 */ ++RELOC_LOW(xx_store_pte_lowmem) ++1: lwarx r0,0,r7 ++ cmpwi r0,0 ++ bne- 1b ++ stwcx. r8,0,r7 // take hash lock ++ bne- 1b ++ // isync // sync below is sufficient ++ stw r0,0(r4) // clear old PTE[V] (if we evict something) ++ sync // probably not needed - no other CPU uses this PTE ++ stw r6,4(r4) // store PTE2 ++ eieio ++ stw r5,0(r4) // store PTE1 ++ tlbie r3 // flush old pte ++ eieio // order tlbie before tlbsync ++ tlbsync // ensure tlbie finish on all processors ++ sync // ensure tlbsync completed ++ stw r0,0(r7) // release hash lock ++ blr ++RELOC_LOW_END(xx_store_pte_lowmem) ++ ++ ++ /* r3=ea, r7=lock, r8=lockval, M: r0 */ ++RELOC_LOW(xx_tlbie_lowmem) ++1: lwarx r0,0,r7 ++ cmpwi r0,0 ++ bne- 1b ++ stwcx. r8,0,r7 // take hash lock ++ bne- 1b ++ //isync // needed if we get rid of the sync ++ sync // make sure any PTE zero-outs have finished ++ tlbie r3 // flush old pte ++ eieio // order tlbie before tlbsync ++ tlbsync // ensure tlbie finish on all processors ++ sync // ensure tlbsync completed ++ stw r0,0(r7) // release hash lock ++ blr ++RELOC_LOW_END(xx_tlbie_lowmem) ++ ++#else ++ ++ /* r3=pte_slot, r4=pte0, r5=pte1 */ ++RELOC_LOW(xx_store_pte_lowmem) ++ stw r4,0(r3) // interrupts are off and we won't take a page fault ++ stw r5,4(r3) // so this is safe... ++ blr ++RELOC_LOW_END(xx_store_pte_lowmem) ++ ++#endif +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/ptintercept.S +@@ -0,0 +1,303 @@ ++/* ++ * Creation Date: <2001/03/17 18:00:05 samuel> ++ * Time-stamp: <2003/05/26 00:08:48 samuel> ++ * ++ * ++ * ++ * Handles writes to the (mac) hash table ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++////////////////////////////////////////////////////////////////////// ++// Implementing the tlbie instruction properly is tricky. ++// The tlbie is supposed to invalidate an equivalence ++// class of PTEs and this does not map well to the huge TLB ++// MOL uses (the linux PTE hash, a lot bigger than the 2x64 ++// table found in most CPUs). ++// ++// The solution is intercepting PTE writes and maintain ++// coherence without relying on the tlbie instruction (which ++// can safely be replaced by a nop). ++// ++// Splitmode: The instruction sr might be active. DBAT0 does ++// _not_ have the supervisor valid bit set so we have to load ++// the data segment register. ++////////////////////////////////////////////////////////////////////// ++ ++MACRO(SET_MSR_DR, [scr], [ ++ li _scr,MSR_DR ++ mtmsr _scr ++ isync ++]) ++MACRO(CLEAR_MSR_DR, [scr], [ ++ li _scr,0 ++ mtmsr _scr ++ isync ++]) ++ ++ // r3 = exception vector ++secint_pt_store: ++ bf+ FBIT_InSplitmode,1f ++ mfdar r2 ++ lwz r4,K_TMP_SCRATCH0(r1) // in splitmode (might be ++ mtsrin r4,r2 // the instrucion sr) ++1: ++ lwz r6,xNIP(r1) // restore NIP & MSR ++ lwz r7,K_MSR(r1) ++ cmpwi r3,0x300 ++ beq 1f ++ cmpwi r3,0x600 // Alignment ++ beq 2f ++ DEBUGGER_SAVE( 0x6909 ) ++1: bl save_middle_regs ++ b dsi_cont ++2: bl save_middle_regs ++ b alignment_cont ++ ++ //////////////////////////////////////////////////////////////////////// ++ // check_pthash_hit ++ // ++ // m: r0,r2-r5, cr ++ ++check_pthash_hit: ++ mfdsisr r3 ++ rlwinm. r4,r3,0,4,4 // Is this a protection violation? ++ beqlr ++ rlwinm. r4,r3,0,6,6 // and a write? ++ beqlr- ++ ++ mfdar r2 // Is this a pthash hit? ++ lwz r3,K_TLBHASH_BASE_EA(r1) // First check EA... ++ lwz r4,K_HASH_MASK(r1) ++ sub r5,r2,r3 ++ cmplw r5,r4 ++ bgtlr+ ++ ++ lwz r5,K_SR_DATA(r1) // Correct context for EA? ++ rlwinm r3,r2,4+2,26,29 // #sr << 2 ++ lwz r4,K_TLBHASH_SR(r1) ++ lwzx r3,r3,r5 ++ cmpw r3,r4 ++ bnelr- ++ ++ ///////////////////////////////////////////////// ++ // Handle page table write, r2=dar, r4=segreg ++ ///////////////////////////////////////////////// ++ ++ bf+ FBIT_InSplitmode,1f ++ mfsrin r3,r2 // save old segment register ++ stw r3,K_TMP_SCRATCH0(r1) // in splitmode (might be ++ mtsrin r4,r2 // the instrucion sr) ++1: ++ lwz r3,xINST_OPCODE(r1) ++ LI_PHYS( R4,secint_pt_store ) // r4 = secondary exception handler ++ stw r6,xNIP(r1) ++ ++ // r2 = dar, r3 = opcode ++ rlwinm r0,r3,6,0x3e // primary opcode & ~1 ++ rlwinm r5,r3,6+5+3,(0x1f<<3) // r5 = rS << 3 ++ cmpwi r0,30 // 31 & ~1 ++ beq- do_opcode_31 ++ mtcrf 0x40,r3 // cr[5] = update bit ++ cmpwi r0,36 // 36, stw/stwu ++ beq do_stw ++ cmpwi r0,38 // 38, stb/stbu ++ beq do_stb ++ cmpwi r0,44 // 44, stb/stbu ++ beq do_sth ++ cmpwi r0,52 // 52, stfs/stsu ++ beq do_stfs ++ cmpwi r0,54 // 54, stfd/stfdu ++ beq do_stfd ++ cmpwi r0,46 // 47, stmw ++ beq do_stmw ++ b do_st_bad // ??? ++ ++do_opcode_31: ++ rlwinm r0,r3,32-1,22,31 // secondary opcode ++ rlwinm. r6,r3,0,(32<<1) // update form? ++ rlwinm r0,r0,0,~32 // clear update bit ++ crnot 5,eq ++ ++ cmpwi r0,151 // stwx/stwxu ++ beq+ do_stw ++ cmpwi r0,215 // stbx / stbxu ++ beq- do_stb ++ cmpwi r0,150 // stwcx. ++ beq- do_stwcx ++ cmpwi r0,407 // sthx / sthxu ++ beq- do_sth ++ cmpwi r0,727 // stfdx / stfdxu ++ beq- do_stfd ++ cmpwi r0,663 // stfsx / stfsxu ++ beq- do_stfs ++ crclr 5 ++ rlwinm r0,r3,32-1,22,31 // unmasked secondary opcode ++ cmpwi r0,470 // dcbi ++ beq- do_dcbi ++ cmpwi r0,1014 // dcbz ++ beq- do_dcbz ++ cmpwi r0,983 // stfiwx [optional] ++ beq- do_stfiw ++ cmpwi r0,725 // stswi ++ beq- do_stswi ++ cmpwi r0,661 ++ beq- do_stswx ++ b do_st_bad // float, cache or altivec ++ ++do_st_bad: ++do_stfd: ++do_stfs: ++do_stfiw: ++do_stswi: ++do_stswx: ++ lwz r6,xNIP(r1) ++ DEBUGGER_SAVE(0x1882) // unimplemented store instruction ++ ++ // r2=dar, r3=opcode, r4=secint_handler, r5=rS_offs ++do_dcbi: ++do_dcbz: ++ mtlr r4 ++ SET_MSR_DR /**/ r6 ++ rlwinm r6,r2,0,~0x7 ++ lwz r4,0(r6) ++ lwz r5,4(r6) ++ dcbz 0,r2 ++ CLEAR_MSR_DR /**/ r0 ++ b st_continue_2 ++do_stwcx: ++ EMU_LOAD_GPR r5, /**/ R6 // r0 = value ++ mtlr r4 ++ SET_MSR_DR /**/ r6 ++ rlwinm r6,r2,0,~0x7 ++ lwz r4,0(r6) ++ lwz r5,4(r6) ++ stwcx. r0,0,r2 ++ CLEAR_MSR_DR /**/ r0 ++ lwz r6,xCR(r1) ++ mfcr r0 ++ rlwimi r6,r0,0,0,3 ++ stw r6,xCR(r1) ++ b st_continue_2 ++do_sth: ++ EMU_LOAD_GPR r5, /**/ R6 // r0 = value ++ mtlr r4 ++ SET_MSR_DR /**/ r6 ++ rlwinm r6,r2,0,~0x7 ++ lwz r4,0(r6) ++ lwz r5,4(r6) ++ sth r0,0(r2) ++ b st_continue ++do_stb: ++ EMU_LOAD_GPR r5, /**/ R6 // r0 = value ++ mtlr r4 ++ SET_MSR_DR /**/ r6 ++ rlwinm r6,r2,0,~0x7 ++ lwz r4,0(r6) ++ lwz r5,4(r6) ++ stb r0,0(r2) ++ b st_continue ++do_stw: ++ EMU_LOAD_GPR r5, /**/ R6 // r0 = value ++ mtlr r4 ++ SET_MSR_DR /**/ r6 ++ rlwinm r6,r2,0,~0x7 ++ lwz r4,0(r6) ++ lwz r5,4(r6) ++ stw r0,0(r2) ++ b st_continue ++ ++ // r4=PTE0, r5=PTE1, r3=opcode, r2=dar, scratch: r0 ++st_continue: ++ CLEAR_MSR_DR /**/ r0 ++ bf+ 5,st_continue_2 // update form? ++ rlwinm r3,r3,6+5+5+3,(31<<3) ++ mr r0,r2 ++ EMU_STORE_GPR r3, /**/ R6 // r0 = value ++st_continue_2: ++ // check if the old PTE has been used (r2=dar,r4/r5=PTE) ++ lwz r3,K_TLBHASH_BASE_EA(r1) // Calculate tlb offset ++ sub r0,r2,r3 // r0 = pte_nr * 8 ++ lwz r6,K_PTHASH_INUSE_PH(r1) ++ rlwinm r3,r0,32-6,6,29 // r3 = word offset ++ cmpwi r6,0 ++ beq- 1f ++ lwzx r3,r3,r6 ++ rlwinm r6,r2,32-3,27,31 // pte_nr & 0x1f ++ li r0,1 ++ slw r6,r0,r6 // r6 = bit ++ and. r6,r6,r3 ++ GET_TICK_CNT(entry,"ptintercept-1") ++ bne- pt_intercept ++1: ++ BUMP("pt_intercept_not_taken") ++ // return from exception [r2=dar] ++ lwz r6,xNIP(r1) // restore r6 ++ bf+ FBIT_InSplitmode,emulation_done ++ lwz r3,K_TMP_SCRATCH0(r1) // in splitmode (might be ++ mtsrin r3,r2 // the instrucion sr) ++ b emulation_done ++ ++ // transfer to C-function [r2=dar, r3/r4=pte] ++pt_intercept: ++ BUMP("pt_intercept_taken") ++ lwz r6,xNIP(r1) // restore r6 ++ lwz r3,K_TLBHASH_BASE_EA(r1) // calculate tlb offset ++ addi r6,r6,4 // inc NIP ++ bl save_middle_regs ++ sub r6,r2,r3 ++ rlwinm r6,r6,0,0,28 // argument pteoffs (dword aligned) ++ ++ // r4=PTE0, r5=PTE1 ++ LOADI r3,EXTERN(do_intercept_tlbie) ++ b call_kernel ++ ++ // stmw uses another emulator entry point because it might overwrite a bunch of PTEs ++do_stmw: ++ mtlr r4 ++ ++ // save some debugging info ++// stw r2,xDBG_TRACE_SPACE(r1) ++ ++ SET_MSR_DR /**/ r6 ++ ++ // now do the stmw. we do that manually since we have to access emulator regs. ++ mr r4,r2 // r4: memory pointer ++ srwi r6,r5,3 // r6: rS ++1: cmpwi r5,32 << 3 // loop condition ++ bge 2f ++ EMU_LOAD_GPR r5, /**/ R3 // r0 = value ++ stw r0,0(r4) // store the value ++ addi r5,r5,1 << 3 // update register counter ++ addi r4,r4,4 // and memory pointer ++ b 1b ++ ++2: CLEAR_MSR_DR /**/ r0 ++ ++ // load up r4 and r5 for do_intercept_tlbie_block (see below) ++ subfic r5,r6,32 // number of registers (=words) stored ++ slwi r5,r5,2 // number of bytes stored ++ add r4,r2,r5 // last byte stored ++ addi r4,r4,7 // alignment to ++ rlwinm r5,r4,0,~0x7 // PTE size ++ rlwinm r4,r2,0,~0x7 // pte block pointer ++ sub r5,r5,r4 // substract block pointer -> length (in bytes) ++ lwz r3,K_TLBHASH_BASE_EA(r1) // calculate tlb offset ++ sub r4,r4,r3 // tlb offset ++ b st_block_continue ++ ++ // transfer to C-function [r2=dar, r4=pte block offset, r5=pte block length] ++st_block_continue: ++ BUMP("pt_intercept_taken") ++ lwz r6,xNIP(r1) ++ addi r6,r6,4 // inc NIP ++ bl save_middle_regs ++ ++ LOADI r3,EXTERN(do_intercept_tlbie_block) ++ b call_kernel +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/splitmode.S +@@ -0,0 +1,428 @@ ++/* ++ * Creation Date: <2000/07/11 03:38:32 samuel> ++ * Time-stamp: <2003/08/20 16:37:04 samuel> ++ * ++ * ++ * ++ * Handles splitmode (MSR_IR != MSR_DR) ++ * ++ * Copyright (C) 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++MACRO(SM_SET_MSR_DR, [scr], [ ++ li _scr,MSR_DR ++ mtmsr _scr ++ isync ++]) ++MACRO(SM_CLEAR_MSR_DR, [scr], [ ++ li _scr,0 ++ mtmsr _scr ++ isync ++]) ++MACRO(SPLITMODE_SMP_LOCK, [scr1,scr2], [ ++#ifdef CONFIG_SMP ++ LI_PHYS( _scr1,splitmode_lock ) ++7: lwarx _scr2,0,_scr1 ++ cmpwi _scr2,0 ++ li _scr2,1 ++ bne- 7b ++ stwcx. _scr2,0,_scr1 ++ bne- 7b ++ isync ++#endif ++]) ++MACRO(SPLITMODE_SMP_UNLOCK, [scr1,scr2], [ ++#ifdef CONFIG_SMP ++ LI_PHYS( _scr1,splitmode_lock ) ++ li _scr2,0 ++ stw _scr2,0(_scr1) ++#endif ++]) ++ ++ ///////////////////////////////////////////////////////////// ++ // prepare_splitmode ++ // ++ // r6,r7: nip/srr1 ++ // ++ // M: r0,r3-r5 ++ // ++ // Fill in splitmode segment register table. The segment register ++ // containing xNIP is set up for instruction access (if xNIP does ++ // not hold nip, an extra ISI exception will occur). The instruction ++ // segment is protected from data access through the use of a DBAT ++ // register. ++ // ++ // It MUST be safe to call this function even if we are *not* in ++ // splitmode. ++ ++prepare_splitmode: ++ bf FBIT_PrepareSplitmode, ret_from_prep_splitmode ++ ++ ZERO_TICK_CNT(splitmode_prep) ++ ++ // fill split mode table with data segment registers ++ lwz r3,K_SR_DATA(r1) // physical addr ++ addi r4,r1,K_SPLIT_SR_BASE-4 ++ li r5,16 ++ mfctr r0 // save ctr in r0 ++ mtctr r5 ++ addi r3,r3,-4 ++1: lwzu r5,4(r3) ++ oris r5,r5,0x1000 // no-execute segment bit ++ stwu r5,4(r4) ++ bdnz 1b ++ mtctr r0 // restore ctr ++ ++ // insert instruction mode segment ++ rlwinm r3,r6,0,0,3 ++ stw r3,K_SPLIT_NIP_SEGMENT(r1) ++ rlwinm r3,r6,4+2,26,29 // r3 = offset, ((sr & 0xf000000) >> 28 ) * 4 ++ lwz r5,K_SR_INST(r1) ++ lwzx r5,r3,r5 // segment register for instructions ++ addi r4,r1,K_SPLIT_SR_BASE ++ stwx r5,r3,r4 ++ ++ // and protect it with DBAT0. ++ // ++ // The supervisor valid bit must be cleared ++ // - we don't want to block get_opcode. ++ ++ rlwinm r3,r6,0,0,3 // segment base ++ ori r3,r3,0x1ffd // user valid bit | 256MB mask ++ stw r3,K_SPLIT_DBAT0U(r1) ++ li r4,0 ++ stw r4,K_SPLIT_DBAT0L(r1) // pp=0, wimg=0 ++ GET_TICK_CNT(splitmode_prep, "splitmode_prep") ++ b ret_from_prep_splitmode ++ ++ ++ /////////////////////////////////////////////////////////////////// ++ // split_sr_no_execute ++ // ++ // r6,r7: nip/srr1 ++ // ++ // An instruction is to be fetched from one of the no-execute ++ // segments. This function reinitializes the segment registers. ++ // ++ // M: r0, r3-r5 ++ ++split_sr_no_execute: ++ rlwinm. r0,r7,0,3,3 // Guarded access or no-execute? ++ beqlr ++ ++ rlwinm r3,r6,0,0,3 // segment ++ lwz r4,K_SPLIT_NIP_SEGMENT(r1) ++ cmpw r3,r4 ++ beqlr // guarded PTE/mac-guarded segment ++ ++ crset FBIT_PrepareSplitmode ++ crset FBIT_LoadSegreg ++ b exception_return ++ ++ ++ ++ ////////////////////////////////////////////////////////////////// ++ // splitmode_dsi ++ // ++ // r6/r7: nip/srr1 ++ // ++ // An DSI exception occured (DBAT protection violation). ++ // That is, a load/store instruction targeted the segment ++ // instructions was fetched from. ++ // ++ // Safe to modify: r0,r2-r5, (lr) ++ ++splitmode_dsi: ++ mfdsisr r3 // DBAT/page protection violation? ++ rlwinm. r0,r3,0,4,4 ++ beqlr- // If not, it does not concern us ++ ++ mfdar r2 // Normal page protected exception? ++ lwz r4,K_SPLIT_NIP_SEGMENT(r1) // the instruction segment? ++ rlwinm r5,r2,0,0,3 // data segment ++ cmpw r4,r5 ++ bnelr // exit - not in the instruction segment ++ ++ // splitmode write, r2=dar ++ mfsrin r0,r2 // r0 = old segment register ++ stw r6,xNIP(r1) // need one additional reg ++ rlwinm r4,r2,4+2,26,29 // sr_offset = sr_num * 4 ++ lwz r5,K_SR_DATA(r1) ++ lwzx r4,r4,r5 ++ stw r0,K_TMP_SCRATCH0(r1) // save old segment register ++ oris r4,r4,0x4000 // set supervisor key bit (Ks) ++ mtsrin r4,r2 ++ ++ rlwinm. r3,r3,0,6,6 // cr[eq] set if this a read ++ lwz r3,xINST_OPCODE(r1) ++ LI_PHYS( R4, secint_splitm ) // r4 = secint handler ++ ++ // handle simple stores r2=seg#, r3=opcode, r4=secint ++ beq splitm_load ++ ++ rlwinm r5,r3,6+5+3,(0x1f<<3) // r5 = rS << 3 ++ EMU_LOAD_GPR r5, /**/ R6 // r0 = value ++ mtlr r4 // secint handler ++ SM_SET_MSR_DR /**/ r5 ++ ++ rlwinm r6,r3,6,0x3e // primary opcode & ~1 ++ mtcrf 0x40,r3 // cr[5] = update bit (if opcode != 31) ++ cmpwi r6,30 // 31 & ~1 ++ beq- splitm_store_op31 ++ cmpwi r6,36 // 36, stw/stwu ++ beq splitm_stw ++ cmpwi r6,38 // 38, stb/stbu ++ beq splitm_stb ++ cmpwi r6,44 // 44, stb/stbu ++ beq splitm_sth ++ b splitm_fallback ++splitm_store_op31: ++ rlwinm. r6,r3,0,(32<<1) // update form? ++ rlwinm r6,r3,32-1,22,31 // secondary opcode ++ rlwinm r6,r6,0,~32 // clear update bit ++ crnot 5,eq ++ cmpwi r6,151 // stwx/stwxu ++ beq+ splitm_stw ++ cmpwi r6,215 // stbx / stbxu ++ beq- splitm_stb ++ cmpwi r6,407 // sthx / sthxu ++ beq- splitm_sth ++ rlwinm r6,r3,32-1,22,31 // secondary opcode ++ cmpwi r6,150 // stwcx. ++ beq- splitm_stwcx ++ cmpwi r6,1014 // 1014, dcbz ++ beq- splitm_dcbz ++ cmpwi r6,662 // 662, stwbrx ++ beq- splitm_stwbrx ++ b splitm_fallback ++ ++splitm_load: ++ mtlr r4 // secint handler ++ SM_SET_MSR_DR /**/ r5 ++ rlwinm r6,r3,6,0x3e // primary opcode & ~1 ++ mtcrf 0x40,r3 // cr[5] = update bit (if opcode != 31) ++ cmpwi r6,30 // 31 & ~1 ++ beq- splitm_load_op31 ++ cmpwi r6,32 // 32, lwz/lwzu ++ beq+ splitm_lwz ++ cmpwi r6,34 // 34, lbz/lbzu ++ beq- splitm_lbz ++ cmpwi r6,40 // 40, lhz/lhzu ++ beq- splitm_lhz ++ b splitm_fallback ++splitm_load_op31: ++ rlwinm. r6,r3,0,(32<<1) // update form? ++ rlwinm r6,r3,32-1,22,31 // secondary opcode ++ rlwinm r6,r6,0,~32 // clear update bit ++ crnot 5,eq ++ cmpwi r6,23 // 23, lwzx/lwzux ++ beq+ splitm_lwz ++ cmpwi r6,87 // 87, lbzx/lbzux ++ beq- splitm_lbz ++ cmpwi r6,279 // 279, lhzx/lhzux ++ beq- splitm_lhz ++ rlwinm r6,r3,32-1,22,31 // secondary opcode ++ crclr 5 ++ cmpwi r6,20 // 20, lwarx ++ beq- splitm_lwarx ++ cmpwi r6,86 // 86, dcbf ++ beq- splitm_dcbf ++ cmpwi r6,982 // 982, icbi ++ beq- splitm_icbi ++ cmpwi r6,534 // 534, lwbrx ++ beq- splitm_lwbrx ++ b splitm_fallback ++ ++ ++ // r0=value, r2=ea, r3=opcode ++splitm_stwcx: ++ stwcx. r0,0,r2 ++ SM_CLEAR_MSR_DR /**/ r0 ++ lwz r6,xCR(r1) ++ mfcr r0 ++ rlwimi r6,r0,0,0,3 ++ stw r6,xCR(r1) ++ b splitm_done2 ++splitm_sth: ++ sth r0,0(r2) ++ b splitm_store_continue ++splitm_stb: ++ stb r0,0(r2) ++ b splitm_store_continue ++splitm_stw: ++ stw r0,0(r2) ++ b splitm_store_continue ++splitm_lwz: ++ lwz r0,0(r2) ++ b splitm_load_continue ++splitm_lhz: ++ lhz r0,0(r2) ++ b splitm_load_continue ++splitm_lbz: ++ lbz r0,0(r2) ++ b splitm_load_continue ++splitm_lwarx: ++ lwarx r0,0,r2 ++ b splitm_load_continue ++splitm_lwbrx: ++ lwbrx r0,0,r2 ++ b splitm_load_continue ++splitm_dcbz: ++ dcbz 0,r2 ++ b splitm_done ++splitm_icbi: ++ icbi 0,r2 ++ b splitm_done ++splitm_dcbf: ++ dcbf 0,r2 ++ b splitm_done ++splitm_stwbrx: ++ stwbrx r0,0,r2 ++ b splitm_done ++ ++splitm_load_continue: ++ SM_CLEAR_MSR_DR /**/ r4 ++ BUMP("splitm_load") ++ rlwinm r4,r3,6+5+3,(0x1f<<3) // r5 = rS << 3 ++ EMU_STORE_GPR r4, /**/ R6 // r0 = value ++ bf+ 5,splitm_done2 // update form? ++ b 1f ++ ++splitm_store_continue: ++ SM_CLEAR_MSR_DR /**/ r0 ++ BUMP("splitm_store") ++ bf+ 5,splitm_done2 // update form? ++1: rlwinm r3,r3,6+5+5+3,(31<<3) ++ mr r0,r2 ++ EMU_STORE_GPR r3, /**/ R6 // r0 = value ++ b splitm_done2 ++splitm_done: ++ SM_CLEAR_MSR_DR /**/ r0 ++splitm_done2: ++ lwz r3,K_TMP_SCRATCH0(r1) ++ lwz r6,xNIP(r1) // restore NIP ++ mtsrin r3,r2 ++ b emulation_done ++ ++ ++ // fallback, store and execute the instruction, r3=opcode ++splitm_fallback: ++ SM_CLEAR_MSR_DR /**/ r0 ++#if 0 ++ stw r3,xDEBUG1(r1) ++ stw r6,xDEBUG0(r1) ++ lwz r6,xNIP(r1) ++ DEBUGGER_SAVE(0x1111) ++#endif ++ SPLITMODE_SMP_LOCK /**/ r0,r2 ++ ++ BUMP("splitm_fallback") ++ bl secint_splitm_fallback // set secondary exception handler ++ ++ LI_PHYS( R2,split_store_patch ) // r2 = addr of split_store_patch ++ stw r3,0(r2) // store instruction ++ dcbst 0,r2 ++ sync ++ icbi 0,r2 ++ sync // 74xx needs this ++ ++ mtsrr0 r2 // The simplest thing is to do an RFI ++ LOADI r3,(MSR_EE | MSR_PR | MSR_IR | MSR_SE | MSR_BE) ++ andc r4,r7,r3 // Clear msr bits (r7=srr1) ++ xGPR_LOAD R6 ++ xGPR_LOAD R7 ++ mtsrr1 r4 ++ xGPR_LOAD_RANGE R2,R5,r1 // Restore registers (except r1) ++ xGPR_LOAD R0 ++ xGPR_LOAD R1 ++ rfi ++ ++split_store_patch: ++ nop ++ ++ mtsprg_a0 r1 // restore MSR ++ li r1,MSR_ME ++ mtmsr r1 ++ isync ++ mfsprg_a3 r1 // and stack pointer ++ ++ xGPR_SAVE_RANGE R2,R7,r1 ++ SPLITMODE_SMP_UNLOCK /**/ r3,r4 ++ ++ mfsprg_a0 r2 // r1 - to be saved ++ lwz r6,xNIP(r1) // restore r6,r7 and segment register ++ lwz r7,K_MSR(r1) ++ stw r0,xGPR0(r1) ++ stw r2,xGPR1(r1) ++ lwz r2,K_TMP_SCRATCH0(r1) ++ mtsrin r2,r6 ++ ++ GET_TICK_CNT( entry, "splitmode_dsi" ) ++ b emulation_done ++ ++ ++ ////////////////////////////////////////////////////////////////////// ++ // secint_splitm / secint_splitm_fallback ++ // r1: stack (sprg1 = old r1) ++ // r3: vector index (sprg0 = old r3) ++ // srr0/srr1: kernel nip/msr ++ // ++ // xGPR(0-5) are valid (unless this is a trace exception) ++ ++secint_splitm_fallback: ++ blrl ++ SPLITMODE_SMP_UNLOCK /**/ R2,R4 ++ ++secint_splitm: ++ lwz r6,xNIP(r1) // Restore nip/msr ++ lwz r7,K_MSR(r1) ++ ++ cmpwi r3,0x300 // ** DSI ** ++ bne- 1f ++ mfsrin r2,r6 // r6 = NIP ++ rlwinm r2,r2,0,2,0 // Clear Ks [bit1] (supervisor key bit) ++ mtsrin r2,r6 ++ bl save_middle_regs // Note: If dsi_cont ever returns immediately, ++ bl check_io_page // we will need to fix the segment registers before ++ b dsi_cont // the last dsi_cont branch. ++ ++1: lwz r2,K_TMP_SCRATCH0(r1) // We might return immediately... ++ mtsrin r2,r6 ++ ++ cmpwi r3,0x600 // ** Alignment ** ++ bne 2f ++ bl save_middle_regs ++ b alignment_cont ++ ++2: cmpwi r3,0x800 // ** FPU Unavailable ** ++ beq fpu_cont ++ cmpwi r3,0xf20 // ** AltiVec Unavailable ** ++ beq altivec_cont ++ ++ DEBUGGER_SAVE( 0x5918 ) // ERROR... ++ ++ ++ //////////////////////////////////////////////////////////////////////// ++ // invalidate_splitmode( kernel_vars_t *kv ) ++ // ++ // This function must be called whenever the segment registers are ++ // modified. A flag is set which will force a refresh of the slitmode ++ // segment registers (at mac context switch in). We could rewrite this ++ // in C but it might be better to keep things centralized. ++ ++GLOBAL_SYMBOL(r__invalidate_splitmode_sr): ++ // this will have no effect if fb_InSplitmode is not set ++ lwz r4,xFLAG_BITS(r3) ++ ori r4,r4,fb_PrepareSplitmode | fb_LoadSegreg ++ stw r4,xFLAG_BITS(r3) ++ blr ++ ++#ifdef CONFIG_SMP ++splitmode_lock: ++ .long 0 ++#endif +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/traps.S +@@ -0,0 +1,501 @@ ++/* ++ * Creation Date: <2001/01/27 16:25:14 samuel> ++ * Time-stamp: <2004/03/07 21:58:48 samuel> ++ * ++ * ++ * ++ * Exception Vectors ++ * ++ * Copyright (C) 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#define DBG_TRACE 0 // enable TRACE macro? ++ ++#include "archinclude.h" ++#include "processor.h" /* avoid (bogus SPRN_TBWU/L) */ ++#include "asm_offsets.h" ++#include "asmdefs.h" ++#include "molasm.h" ++#include "asmdbg.h" ++#include "actions.h" ++#include "vector.h" ++#include "rvec.h" ++#include "constants.h" ++#include "mac_registers.h" ++#include "mmu.h" ++#include "osi.h" ++#include "kernel_vars.h" ++ ++ ++/************************************************************************/ ++/* Exception Vector Definitions */ ++/************************************************************************/ ++ ++ ACTIONS_SECTION ++GLOBAL_SYMBOL(r__actions_section): ++ ACTIONS_OFFS_SECTION ++GLOBAL_SYMBOL(r__actions_offs_section): ++ ++ .text ++GLOBAL_SYMBOL(r__reloctable_start): ++ ++MACRO_0(EXCEPTION_PREAMBLE, [ ++ // SPRG1 = r1, SPRG0 = r3, r3=CR, r1=MOL_STACK ++ __ZERO_TICK_CNT(entry) ++ stw r4,xGPR4(r1) // store instruction are store serializing ++ lwz r4,xFLAG_BITS(r1) ++ stw r5,xGPR5(r1) // and mix very badly with execution serializing ++ stw r6,xGPR6(r1) // instructions (like mfspr) ++ mfsrr0 r6 ++ stw r7,xGPR7(r1) ++ mfsrr1 r7 ++ stw r0,xGPR0(r1) ++ mtcr r4 ++ stw r2,xGPR2(r1) ++ mflr r2 ++ stw r3,xCR(r1) ++ mfsprg_a1 r5 // SPRG1 = r1 ++ stw r2,xLINK(r1) ++ mfsprg_a0 r3 // SPRG0 = r3 ++ stw r5,xGPR1(r1) ++ stw r3,xGPR3(r1) ++ ++ // saved: r0-r7, cr, lr ++ // r1 = stack, cr5-7=flag_bits, r6/r7 = nip/msr ++]) ++ ++ balign_32 ++save_middle_regs: // save r8-r12 and nip (r13-r31 should always be in regs) ++ stw r6,xNIP(r1) ++ mfxer r7 ++ mfctr r6 ++ stw r8,xGPR8(r1) ++ stw r9,xGPR9(r1) ++ stw r10,xGPR10(r1) ++ stw r11,xGPR11(r1) ++ stw r12,xGPR12(r1) ++ stw r6,xCTR(r1) ++ stw r7,xXER(r1) ++ bt- FBIT_FPUInUse,giveup_fpu // modifies r7/r8 ++ blr ++ ++MACRO_0(RESTORE_MIDDLE_REGS, [ // reverse save_middle_regs, restores registers ++ lwz r11,xCTR(r1) // r8-r12, ctr, xer, r6/r7 = nip/msr ++ lwz r12,xXER(r1) ++ lwz r8,xGPR8(r1) ++ lwz r9,xGPR9(r1) ++ mtctr r11 ++ lwz r10,xGPR10(r1) ++ lwz r11,xGPR11(r1) ++ mtxer r12 ++ lwz r12,xGPR12(r1) ++ lwz r6,xNIP(r1) ++ lwz r7,K_MSR(r1) ++]) ++ ++#define EXCEPTION_SAVE_ALL \ ++ EXCEPTION_PREAMBLE ;\ ++ bl save_middle_regs ; ++ ++#define VECTOR_KERNEL( v, dummy_name, secint ) \ ++ VECTOR( v, dummy_name, secint ) ;\ ++ EXCEPTION_SAVE_ALL ;\ ++ TAKE_EXCEPTION( v ) ; ++ ++#define VECTOR_RESERVED( v, dummy_name, secint ) \ ++ VECTOR( v, dummy_name, secint ) ;\ ++ DEBUGGER_SAVE( v ) ; ++ ++#define MAC_EXIT( rvec_code ) \ ++ li r3,rvec_code ;\ ++ b mac_exit ; ++ ++#define MAC_EXIT_SAVE( rvec_code ) \ ++ bl save_middle_regs ;\ ++ li r3,rvec_code ;\ ++ b mac_exit ; ++ ++#define MAC_TRAP( trap_num ) \ ++ li r2,trap_num ;\ ++ b mac_trap ; ++ ++#define DEBUGGER(n) li r4,n ; MAC_EXIT( RVEC_DEBUGGER ); ++#define DEBUGGER_SAVE(n) li r4,n ; MAC_EXIT_SAVE( RVEC_DEBUGGER ); ++ ++ ++/************************************************************************/ ++/* Misc macros */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////////// ++ // _get_instr_opcode ++ // r6 nip ++ // ret: r4 opcode ++ // ++ // Modifies: r2,r3. ++ // Side-effects: Might return from the exception ++ ++MACRO(GET_INSTR_OPCODE, [dummy], [ ++ mfmsr r3 // r3 = exception MSR ++ ori r2,r3,MSR_DR ++ bl 8f ++ ++ // secondary interrupt entry (we _know_ this must be a DSI) ++#ifdef CONFIG_SMP ++ LOADI r5,EXTERN(compat_hash_table_lock) ++ li r4,1 ++ tophys r5,r5 ++7: lwarx r0,0,r5 // lock ++ cmpwi r0,0 ++ bne- 7b ++ stwcx. r4,0,r5 ++ bne- 7b ++ isync ++ tlbie r6 ++ eieio ++ tlbsync ++ sync ++ stw r0,0(r5) // release lock ++#else ++ tlbie r6 // flush PTE from ITLB ++#endif ++ b exception_return ++8: ++ mtmsr r2 ++ isync ++ ++ lwz r4,0(r6) // get opcode ++ ++ mtmsr r3 // restore exception MSR ++ isync ++]) ++ ++/************************************************************************/ ++/* Reserved / Kernel Vectors */ ++/************************************************************************/ ++ ++VECTOR_KERNEL( 0x100, "System Reset", secint_bad ) ++VECTOR_KERNEL( 0x500, "External Interrupt", secint_bad ) ++VECTOR_KERNEL( 0x1400, "System Management Interrupt", secint_bad ) ++VECTOR_KERNEL( 0x1700, "Thermal Management Interrupt", secint_bad ) ++ ++VECTOR_RESERVED( 0x200, "Machine Check", secint_bad ) ++VECTOR_RESERVED( 0xa00, "Reserved", secint_bad ) ++VECTOR_RESERVED( 0xb00, "Reserved", secint_bad ) ++VECTOR_RESERVED( 0xe00, "FPU Assist", secint_bad ) ++ ++PERFMON_VECTOR_RELOCATION( PERFMON_VECTOR ) ++VECTOR_RESERVED( PERFMON_VECTOR, "Performance Monitor Interrupt", secint_bad ) ++ ++//VECTOR_RESERVED( 0x1000, "InstructionTLBMiss-603", secint_bad ) ++//VECTOR_RESERVED( 0x1100, "DataLoadTLBMiss-603", secint_bad ) ++//VECTOR_RESERVED( 0x1200, "DataLoadTLBMiss-603", secint_bad ) ++ ++/************************************************************************/ ++/* DSI Exceptions */ ++/************************************************************************/ ++ ++VECTOR( 0x300, "DSI", secint_lr_call ) ++ EXCEPTION_PREAMBLE ++ TRACE(0x300, "DSI") ++ ++ GET_INSTR_OPCODE // m: r2-r3, ret: r4=opcode, r6=nip ++ stw r4,xINST_OPCODE(r1) ++ bl check_pthash_hit // m: r0,r2-r5 ++ btl- FBIT_InSplitmode,splitmode_dsi ++ bl save_middle_regs ++ bl check_io_page ++ ++dsi_cont: ++ LOADI r3,EXTERN(dsi_exception) ++ mfdar r4 // We might need to do this earlier ++ mfdsisr r5 // when the splitmode code is activated... ++ b call_kernel ++ ++ ++/************************************************************************/ ++/* ISI Exceptions */ ++/************************************************************************/ ++ ++VECTOR( 0x400, "ISI", secint_bad ) ++ EXCEPTION_PREAMBLE ++ TRACE(0x400, "ISI") ++ ++ // emuaccel engine ++ rlwinm. r0,r7,0,4,4 // protection violation ++ beq- 1f ++ lwz r3,K_EMUACCEL_MPHYS(r1) ++ rlwinm r4,r6,0,~0x0fff // nip page ++ rlwinm r2,r6,0,0x0ff8 // nip offset (dword align) ++ lwz r5,K_EMUACCEL_PAGE_PHYS(r1) ++ cmpw r3,r4 ++ bne- 1f ++ lwzux r0,r2,r5 // r0 = handler ++ mtlr r0 ++ lwz r6,4(r2) // address of next instruction ++ blr // parameters: r2 == emuaccel_slot ++1: ++ btl- FBIT_InSplitmode, split_sr_no_execute ++ bl save_middle_regs ++ ++ LOADI r3,EXTERN(isi_exception) ++ mfsrr0 r4 ++ mfsrr1 r5 ++ b call_kernel ++ ++ ++/************************************************************************/ ++/* Alignement Exception */ ++/************************************************************************/ ++ ++VECTOR( 0x600, "Alignment", secint_lr_call ) ++ EXCEPTION_SAVE_ALL ++ TRACE(0x400, "Alignment") ++ ++alignment_cont: ++ mfdar r4 ++ mfdsisr r5 ++ MAC_EXIT( RVEC_ALIGNMENT_TRAP ) ++ ++ ++/************************************************************************/ ++/* FPU Unavailable Exception */ ++/************************************************************************/ ++ ++ // xFPU_STATE has only meaning when FBIT_FPUInUse is not set ++ // ++ // FPU_STATE_DIRTY - fr13 & fpscr are not loaded (everything else is). ++ // FPU_STATE_HALF_SAVED - fr14-fr31 are loaded. ++ // FPU_STATE_SAVED - fr14-fr31 are loaded (but also saved in mregs). ++ // ++ // FPU_STATE_DIRTY in the *emulator* means that all floating point ++ // registers *EXCEPT* fr13 and fpscr are valid. ++ // ++ // Implementation note: When we do not own the fpu, the MSR_FEx bits ++ // must be cleared. Otherwise we might experience bogus FPU exceptions. ++ // ++ // MOL will never throw FPU exceptions went the FP bit is off. This ++ // is a small violation of the standard but the alternative would be ++ // always loading FPSCR (which requires FPU ownership...) ++ // ++ ++VECTOR( 0x800, "FPU Unavailable", secint_lr_call ) ++ EXCEPTION_PREAMBLE ++ TRACE(0x800, "FPU Unavailable") ++fpu_cont: ++ ++ lwz r2,xMSR(r1) // r2 = xMSR (used below too) ++ andi. r4,r2,MSR_FP ++ beq- mac_fpu_unavailable // mac trap? ++ bt FBIT_FPUInUse,2f // FPU ready for use? ++ ++ lwz r3,K_EMULATOR_MSR(r1) // FPU owned by our userland process? ++ andi. r4,r3,MSR_FP ++ bne+ 1f ++ MAC_EXIT_SAVE( RVEC_ENABLE_FPU ) // No... grab FPU in userspace ++ ++mac_fpu_unavailable: ++ BUMP( "mac-fpu-trap" ) ++ MAC_TRAP( 0x800 ) ++ ++ // userland process owns FPU ++1: BUMP( "enable-fpu" ) ++ ENABLE_MSR_FP /**/ r4 // enable kernel FPU ++ // flag the fpu dirty ++ lwz r3,xFPU_STATE(r1) ++ lfd fr13,xFPSCR-4(r1) // fp13 and fpscr are *ALWAYS* saved ++ crset FBIT_FPUInUse // we own the FPU now ++ cmpwi r3,FPU_STATE_HALF_SAVED ++ mtfsf 0xff,fr13 ++ lfd fr13,xFPR13(r1) ++ bne 2f ++ xLOAD_LOW_FPU r1 // load fr0-fr12 ++2: ++ li r3,MSR_FP| MSR_FE0 | MSR_FE1 // FPU bits ++ lwz r7,K_MSR(r1) // enable MSR_FP ++ and r2,r2,r3 // r2 = (xMSR & MSR_FEx) ++ andc r7,r7,r3 // K_MSR &= ~MSR_FEx ++ or r7,r7,r2 // K_MSR |= (xMSR & MSR_FEx) ++ stw r7,K_MSR(r1) ++ GET_TICK_CNT(entry,"enable_fpu") ++ b exception_return ++ ++ ++/************************************************************************/ ++/* Decrementer Exception */ ++/************************************************************************/ ++ ++// The 0x900 decrementer vector is in dec.S ++ ++/************************************************************************/ ++/* System Call Exception */ ++/************************************************************************/ ++ ++VECTOR( 0xc00, "System Call", secint_bad ) ++ EXCEPTION_PREAMBLE ++ TRACE( 0xc00, "System Call") ++ ++ lwz r3,xGPR3(r1) ++ LOADI r5,OSI_SC_MAGIC_R3 ++ lwz r4,xGPR4(r1) ++ LOADI r2,OSI_SC_MAGIC_R4 ++ cmpw cr1,r3,r5 ++ cmpw cr0,r4,r2 ++ crand eq,eq,cr1_eq ++ beq+ 2f ++ ++ MAC_TRAP(0xc00) // r7 reason bits used (zero) ++2: ++ MAC_EXIT_SAVE( RVEC_OSI_SYSCALL ) ++ ++ ++/************************************************************************/ ++/* Trace Exception */ ++/************************************************************************/ ++ ++VECTOR( 0xd00, "Trace", secint_bad ) ++trace_vector: ++ EXCEPTION_PREAMBLE ++ TRACE(0xd00, "Trace") ++ ++ MAC_EXIT_SAVE( RVEC_TRACE_TRAP ); ++ ++ ++/************************************************************************/ ++/* AltiVec Exception */ ++/************************************************************************/ ++ ++VECTOR( 0xf20, "AltiVec", secint_lr_call ) ++ EXCEPTION_PREAMBLE ++ TRACE(0xf20, "AltiVec") ++altivec_cont: ++ ++ lwz r4,xNO_ALTIVEC(r1) // AltiVec support disabled? ++ cmpwi r4,0 ++ bne- mac_altivec_unavailable ++ ++ lwz r2,xMSR(r1) ++ rlwinm. r4,r2,0,6,6 // bit 6 = MSR_VEC ++ beq- mac_altivec_unavailable ++ ++ lwz r3,K_EMULATOR_MSR(r1) ++ rlwinm. r4,r3,0,6,6 // bit 6 = MSR_VEC ++ bne+ enable_altivec ++ MAC_EXIT_SAVE( RVEC_ENABLE_ALTIVEC ) ++ ++mac_altivec_unavailable: ++ MAC_EXIT_SAVE( RVEC_ALTIVEC_UNAVAIL_TRAP ) ++ ++enable_altivec: ++ // We don't need to load any registers since the emulator ++ // won't touch the altivec unit (at least for now). ++ ++ lwz r7,K_MSR(r1) ++ oris r7,r7,HI(MSR_VEC) ++ stw r7,K_MSR(r1) ++ b exception_return ++ ++ ++VECTOR( 0x1600, "AltiVec Assist", secint_bad ) ++ EXCEPTION_SAVE_ALL ++ TRACE(0x1600, "AltiVec Assist") ++ ++ mr r4,r7 ++ MAC_EXIT( RVEC_ALTIVEC_ASSIST ) // r4 = srr1 ++ ++ ++/************************************************************************/ ++/* Instruction Breakpoint */ ++/************************************************************************/ ++ ++VECTOR( 0x1300, "Instruction Breakpoint", secint_bad ) ++ EXCEPTION_SAVE_ALL ++ TRACE(0x1300, "IABR") ++ ++ DEBUGGER(0x1300) ++ ++ ++/************************************************************************/ ++/* RunMode-601 (trace) */ ++/************************************************************************/ ++ ++VECTOR( 0x2000, "RunMode-601", secint_bad ) ++ b trace_vector ++ ++ ++/************************************************************************/ ++/* Secondary Interrupt Handlers */ ++/************************************************************************/ ++ ++ ////////////////////////////////////////////////////////////////////// ++ // secint_xxx ++ // ++ // r1: stack (sprg1 = old r1) ++ // r3: vector addr (sprg0 = old r3) ++ // srr0/srr1: kernel nip/msr ++ // ++ // secint_lr_call: ++ // lr secondary interrupt handler ++ ++secint_bad: ++ TRACE(0xbad, "secint_bad") ++ mr r4,r3 ++ MAC_EXIT( RVEC_INTERNAL_ERROR ) ++ ++secint_lr_call: ++ blrl ++ li r4,0x6666 ++ MAC_EXIT( RVEC_INTERNAL_ERROR ) ++ ++ ++/************************************************************** ++* Includes ++**************************************************************/ ++ ++// We need to be sure this code is contiguous, the simplest/safest ++// method is using only a single file. This will also effectively ++// reduce the size of the relocation table. ++ ++#ifdef __darwin__ ++#include "darwin.S" ++#endif ++#include "entry.S" ++#include "dec.S" ++#include "emulation.S" ++#include "emuaccel.S" ++#include "iopage.S" ++#include "splitmode.S" ++#include "ptintercept.S" ++#include "vsid.S" ++#ifdef __MPC107__ ++#include "./mpc107/mpc107.S" ++#else ++#ifdef __linux__ ++#include "linux.S" ++#include "603.S" ++#endif ++#endif ++ ++#ifdef __linux__ ++ .text 50 ++#endif ++GLOBAL_SYMBOL(r__reloctable_end): ++ ++ ACTIONS_OFFS_SECTION ++GLOBAL_SYMBOL(r__actions_offs_section_end): ++ ++// The BUMP("counter") macro adds entries to text subsection 90. ++// This adds labels before the counter entries. ++ ++#ifdef __linux__ ++ .text 89 ++GLOBAL_SYMBOL(__start_bumptable): ++ .text 91 ++GLOBAL_SYMBOL(__end_bumptable): ++ .text ++#endif +--- /dev/null ++++ b/drivers/macintosh/mol/asm-files/vsid.S +@@ -0,0 +1,123 @@ ++/* ++ * Creation Date: <2003/03/06 22:03:59 samuel> ++ * Time-stamp: <2004/02/21 16:30:45 samuel> ++ * ++ * ++ * ++ * VSID lookup (skiplist search) ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "mtable.h" ++ ++#if (SKIPLIST_LEVELSIZE == 4) ++#define SLEVEL_SHIFT 2 ++#endif ++#if (SKIPLIST_LEVELSIZE == 8) ++#define SLEVEL_SHIFT 3 ++#endif ++ ++emulate_mtsrin: ++ rlwinm r2,r4,32-8,24,28 // r2 = #B << 8 ++ EMU_LOAD_GPR r2, /**/ R3 // r0 = reg B ++ rlwinm r4,r0,0,0,3 // #sr top 4 bits of r4 ++ b 1f ++emulate_mtsr: ++ rlwinm r4,r4,12,0,3 // #sr in top 4 bits of r4 ++1: EMU_LOAD_GPR r5, /**/ R2 // r0 = new segr value ++ ++ stw r8,xGPR8(r1) // save r8 ++ rlwinm r8,r4,6,26,29 // r8 = #sr << 2 ++ stw r9,xGPR9(r1) // save r9 ++ add r8,r8,r1 // r8 = r1 + sr_offset ++ stw r6,xNIP(r1) // save r6 (need more registers) ++ rlwinm r9,r0,0,0,3 // r9 = [T Ks Kp N] ++ stw r0,xSEGR_BASE(r8) // store new value ++ rlwinm r0,r0,0,8,31 // mask VSID ++ ++ /******* vsid lookup (skiplist search) *******/ ++ ++ lwz r2,K_VSID_SL_SLEVEL(r1) // n = search level (0..15) ++ rlwinm r2,r2,SLEVEL_SHIFT,0,29 // n *= 4 (or n *= 8 on darwin) ++ ++ addi r3,r1,K_VSID_SL_ROOT_ELEM // p = root element ++1: add r5,r2,r3 // ++2: lwz r3,SKIPLIST_NEXT(r5) // r3 = p->next[n] ++#ifdef __linux__ ++ tophys R3,R3 ++#endif ++ lwz r4,SKIPLIST_KEY(r3) // r0 = p->next[n].key ++ cmpw cr1,r4,r0 ++ bge- cr1,3f ++ b 1b ++3: ++ addi r2,r2,-SKIPLIST_LEVELSIZE // r2 -= 4|8 ++ beq- cr1,vsid_found // jump if key matches ++ cmpwi r2,0 ++ addi r5,r5,-SKIPLIST_LEVELSIZE // r5 -= 4|8 ++ bge+ 2b ++ ++ /******* vsid missing *******/ ++ BUMP("vsid_missing") ++ // r8 used ++ lwz r2,K_ILLEGAL_SR(r1) // vsid unallocated... ++ li r4,0 // no entry... ++ stw r2,K_SV_SR_BASE(r8) ++ stw r2,K_USER_SR_BASE(r8) ++ stw r2,K_SPLIT_SR_BASE(r8) // this way we can forget the splitmode case ++ stw r4,K_VSID_ENT_BASE(r8) ++ sub r5,r8,r1 // r5 = VSID offset ++ lwz r0,K_CUR_SR_BASE(r1) // r0 = cur_sr_table ++ b 6f ++ ++ /******* vsid found *******/ ++vsid_found: ++ ++ BUMP("vsid_found") ++ // match, r3 points to the skiplist element ++ addi r4,r3,-SIZEOF_VSID_ENT // sizeof(vsid_ent_t) ++ lwz r2,VSID_USER_OFFS(r4) // vsid_user ++ lwz r3,VSID_SV_OFFS(r4) // vsid_sv ++#ifdef __linux__ ++ tovirt R4,R4 // r4 = vsid_element ++#else ++ lwz r4,VSID_MYSELF_VIRT(r4) ++#endif ++ rlwinm r6,r9,2,31,31 // r6 = Ks ? 1:0 ++ stw r4,K_VSID_ENT_BASE(r8) // store vsid entry (possibly NULL) ++ rlwinm r4,r9,3,31,31 // r4 = Kp ? 1:0 ++ rlwimi r2,r9,0,3,3 // copy the N-bit (no-execute) ++ rlwimi r3,r9,0,3,3 // copy the N-bit (no-execute) ++ cror FBIT_LoadSegreg, FBIT_LoadSegreg, FBIT_InSplitmode ++ addi r6,r6,-1 // r6 = Ks-mask ++ addi r4,r4,-1 // r4 = Kp-mask ++ andc r0,r2,r6 // Kp == 1 case ++ and r6,r3,r6 // Kp == 0 case ++ crmove FBIT_PrepareSplitmode, FBIT_InSplitmode ++ andc r9,r2,r4 // Ks == 1 case ++ or r6,r6,r0 ++ lwz r0,K_CUR_SR_BASE(r1) // r0 = cur_sr_table ++ and r4,r3,r4 // Ks == 0 case ++ stw r6,K_SV_SR_BASE(r8) // sv_sr set ++ or r4,r4,r9 ++ sub r5,r8,r1 // r5 = VSID offset ++ stw r4,K_USER_SR_BASE(r8) // user_sr set ++6: ++ // r0,r5 used ++ rlwinm r2,r5,32-6,0,3 // r2 = sr# in bits 0-3 ++ lwzx r3,r5,r0 // r3 = sr to be loaded into sr# ++ mtsrin r3,r2 // update segment register ++ ++ lwz r6,xNIP(r1) // restore r6 ++ lwz r8,xGPR8(r1) // restore r8 ++ lwz r9,xGPR9(r1) // restore r9 ++ GET_TICK_CNT(entry, "mtsr") ++ BUMP("mtsr_") ++ b emulation_done ++ +--- /dev/null ++++ b/drivers/macintosh/mol/asm_offsets.c +@@ -0,0 +1,161 @@ ++/* ++ * This program is used to generate definitions needed by ++ * some assembly functions. ++ * ++ * We use the technique used in the OSF Mach kernel code: ++ * generate asm statements containing #defines, ++ * compile this file to assembler, and then extract the ++ * #defines from the assembly-language output. ++ */ ++ ++#ifdef __KERNEL__ ++#include "archinclude.h" ++#include "kernel_vars.h" ++#include "mmu.h" ++#else ++#include "mol_config.h" ++#include ++#include "mac_registers.h" ++#endif ++ ++#include "processor.h" ++ ++#define DEFINE(sym, val) \ ++ asm volatile("\n#define\t" #sym "\t%0" : : "i" (val)) ++ ++#define K_DEF(sym, val ) \ ++ DEFINE(sym, offsetof(kernel_vars_t, val )) ++ ++#define ST_DEF(sym, val ) \ ++ DEFINE(sym, offsetof(session_table_t, val )) ++ ++#define M_DEF(sym, val ) \ ++ DEFINE(sym, XOFFS + offsetof(mac_regs_t, val )) ++ ++#define IO_DEF(sym, val) \ ++ DEFINE(sym, offsetof(struct io_page, val )) ++ ++int main( void ) ++{ ++#ifdef __KERNEL__ ++ #define XOFFS offsetof(kernel_vars_t, mregs) ++#else ++ #define XOFFS 0 ++#endif ++ /* --- mac_regs offsets --- */ ++ ++ M_DEF( xVEC_BASE, vec[0] ); ++ M_DEF( xVEC0, vec[0] ); ++ M_DEF( xVEC1, vec[1] ); ++ M_DEF( xVEC2, vec[2] ); ++ M_DEF( xVSCR, vscr ); ++ M_DEF( xVRSAVE, spr[S_VRSAVE] ); ++ ++ M_DEF( xGPR_BASE, gpr[0] ); ++ M_DEF( xGPR0, gpr[0] ); ++ M_DEF( xGPR1, gpr[1] ); ++ M_DEF( xGPR2, gpr[2] ); ++ M_DEF( xGPR3, gpr[3] ); ++ M_DEF( xGPR4, gpr[4] ); ++ M_DEF( xGPR5, gpr[5] ); ++ M_DEF( xGPR6, gpr[6] ); ++ M_DEF( xGPR7, gpr[7] ); ++ M_DEF( xGPR8, gpr[8] ); ++ M_DEF( xGPR9, gpr[9] ); ++ M_DEF( xGPR10, gpr[10] ); ++ M_DEF( xGPR11, gpr[11] ); ++ M_DEF( xGPR12, gpr[12] ); ++ M_DEF( xGPR13, gpr[13] ); ++ M_DEF( xGPR14, gpr[14] ); ++ M_DEF( xGPR15, gpr[15] ); ++ M_DEF( xGPR16, gpr[16] ); ++ M_DEF( xGPR17, gpr[17] ); ++ M_DEF( xGPR18, gpr[18] ); ++ M_DEF( xGPR19, gpr[19] ); ++ M_DEF( xGPR20, gpr[20] ); ++ M_DEF( xGPR21, gpr[21] ); ++ M_DEF( xGPR22, gpr[22] ); ++ M_DEF( xGPR23, gpr[23] ); ++ M_DEF( xGPR24, gpr[24] ); ++ M_DEF( xGPR25, gpr[25] ); ++ M_DEF( xGPR26, gpr[26] ); ++ M_DEF( xGPR27, gpr[27] ); ++ M_DEF( xGPR28, gpr[28] ); ++ M_DEF( xGPR29, gpr[29] ); ++ M_DEF( xGPR30, gpr[30] ); ++ M_DEF( xGPR31, gpr[31] ); ++ ++ M_DEF( xNIP, nip); ++ M_DEF( xCR, cr); ++ M_DEF( xFPR_BASE, fpr[0]); ++ M_DEF( xFPR13, fpr[13]); ++ M_DEF( xFPSCR, fpscr ); ++ M_DEF( xEMULATOR_FPSCR, emulator_fpscr ); ++ M_DEF( xFPU_STATE, fpu_state ); ++ ++ M_DEF( xLINK, link); ++ M_DEF( xXER, xer); ++ M_DEF( xCTR, ctr); ++ M_DEF( xFLAG_BITS, flag_bits ); ++ M_DEF( xDEC, spr[S_DEC]); ++ M_DEF( xDEC_STAMP, dec_stamp); ++ M_DEF( xTIMER_STAMP, timer_stamp); ++ M_DEF( xMSR, msr); ++ M_DEF( xSPR_BASE, spr[0]); ++ ++ M_DEF( xHID0, spr[S_HID0]); ++ ++ M_DEF( xSRR0, spr[S_SRR0]); ++ M_DEF( xSRR1, spr[S_SRR1]); ++ ++ M_DEF( xSPRG0, spr[S_SPRG0]); ++ M_DEF( xSPRG1, spr[S_SPRG1]); ++ M_DEF( xSPRG2, spr[S_SPRG2]); ++ M_DEF( xSPRG3, spr[S_SPRG3]); ++ ++ M_DEF( xSEGR_BASE, segr[0]); ++ M_DEF( xIBAT_BASE, spr[S_IBAT0U] ); ++ M_DEF( xSDR1, spr[S_SDR1] ); ++ ++ M_DEF( xINST_OPCODE, inst_opcode ); ++ M_DEF( xALTIVEC_USED, altivec_used ); ++ M_DEF( xNO_ALTIVEC, no_altivec ); ++ ++ M_DEF( xINTERRUPT, interrupt ); ++ M_DEF( xIN_VIRTUAL_MODE, in_virtual_mode ); ++ ++ M_DEF( xRVEC_PARAM0, rvec_param[0] ); ++ M_DEF( xRVEC_PARAM1, rvec_param[1] ); ++ M_DEF( xRVEC_PARAM2, rvec_param[2] ); ++ ++#ifdef EMULATE_603 ++ M_DEF( xGPRSAVE0_603, gprsave_603[0] ); ++ M_DEF( xGPRSAVE1_603, gprsave_603[1] ); ++ M_DEF( xGPRSAVE2_603, gprsave_603[2] ); ++ M_DEF( xGPRSAVE3_603, gprsave_603[3] ); ++#endif ++ ++ M_DEF( xDEBUG0, debug[0] ); ++ M_DEF( xDEBUG1, debug[1] ); ++ M_DEF( xDEBUG2, debug[2] ); ++ M_DEF( xDEBUG3, debug[3] ); ++ M_DEF( xDEBUG4, debug[4] ); ++ M_DEF( xDEBUG5, debug[5] ); ++ M_DEF( xDEBUG6, debug[6] ); ++ M_DEF( xDEBUG7, debug[7] ); ++ M_DEF( xDEBUG8, debug[8] ); ++ M_DEF( xDEBUG9, debug[9] ); ++ ++ M_DEF( xDEBUG_SCR1, debug_scr1 ); ++ M_DEF( xDEBUG_SCR2, debug_scr2 ); ++ M_DEF( xDEBUG_TRACE, debug_trace ); ++ M_DEF( xDBG_TRACE_SPACE, dbg_trace_space[0] ); ++ M_DEF( xDBG_LAST_RVEC, dbg_last_rvec ); ++ ++ M_DEF( xKERNEL_DBG_STOP, kernel_dbg_stop ); ++ ++ M_DEF( xHOSTIRQ_ACTIVE_CNT, hostirq_active_cnt ); ++ ++ return 0; ++} ++ +--- /dev/null ++++ b/drivers/macintosh/mol/context.c +@@ -0,0 +1,99 @@ ++/* ++ * Creation Date: <1998-11-20 16:18:20 samuel> ++ * Time-stamp: <2004/02/28 19:16:44 samuel> ++ * ++ * ++ * ++ * MMU context allocation ++ * ++ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "mmu.h" ++#include "mmu_contexts.h" ++#include "misc.h" ++#include "asmfuncs.h" ++#include "emu.h" ++#include "mtable.h" ++#include "performance.h" ++#include "context.h" ++#include "hash.h" ++ ++#define MMU (kv->mmu) ++ ++ ++static int ++flush_all_PTEs( kernel_vars_t *kv ) ++{ ++ int i, count=0, npte=(ptehash.pte_mask + 8)/8; ++ ulong *pte, ea, v; ++ ++ for( pte=ptehash.base, i=0; i> 7; ++ v = (v - ((v & 0xf) * MUNGE_ESID_ADD)) * MUNGE_MUL_INVERSE; ++ v = (v>>4) & CTX_MASK; ++ ++ if( v >= MMU.first_mol_context && v <= MMU.last_mol_context ) { ++ *pte = 0; ++ count++; ++ } ++ } ++ ++ /* perform a tlbia */ ++ for( ea=0; ea <= (0x3f << 12); ea += 0x1000 ) ++ __tlbie( ea ); ++ ++ if( count ) ++ printk("%d stale PTEs flushed (something is wrong)\n", count ); ++ return count; ++} ++ ++int ++init_contexts( kernel_vars_t *kv ) ++{ ++ MMU.first_mol_context = FIRST_MOL_CONTEXT( kv->session_index ); ++ MMU.last_mol_context = LAST_MOL_CONTEXT( kv->session_index ); ++ MMU.next_mol_context = MMU.first_mol_context; ++ ++ MMU.illegal_sr = alloc_context(kv) | VSID_Kp | VSID_N; ++ ++ flush_all_PTEs( kv ); ++ return 0; ++} ++ ++void ++cleanup_contexts( kernel_vars_t *kv ) ++{ ++ flush_all_PTEs( kv ); ++} ++ ++void ++handle_context_wrap( kernel_vars_t *kv, int n ) ++{ ++ if( MMU.next_mol_context + n > MMU.last_mol_context ) { ++ printk("MOL context wrap\n"); ++ ++ clear_all_vsids( kv ); ++ init_contexts( kv ); ++ } ++} ++ ++int ++alloc_context( kernel_vars_t *kv ) ++{ ++ int mol_context = MMU.next_mol_context++; ++ int vsid = MUNGE_CONTEXT(mol_context >> 4); ++ ++ vsid += MUNGE_ESID_ADD * (mol_context & 0xf); ++ return (vsid & VSID_MASK); ++} +--- /dev/null ++++ b/drivers/macintosh/mol/emu.c +@@ -0,0 +1,228 @@ ++/* ++ * Creation Date: <1998-11-21 16:07:47 samuel> ++ * Time-stamp: <2004/03/13 14:08:18 samuel> ++ * ++ * ++ * ++ * Emulation of some assembly instructions ++ * ++ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "mmu.h" ++#include "kernel_vars.h" ++#include "emu.h" ++#include "asmfuncs.h" ++#include "rvec.h" ++#include "processor.h" ++#include "mtable.h" ++#include "performance.h" ++#include "emuaccel_sh.h" ++#include "misc.h" ++#include "map.h" ++ ++#define BAT_PERFORMANCE_HACK ++// #define DEBUG ++ ++/* If BAT_PERFORMANCE_HACK is defined, PTEs corresponding to a mac bat ++ * mapping will not necessary be flushed when the bat registers are ++ * touched. This gives a huge performance gain in MacOS 9.1 (which ++ * clears the bat registers in the idle loop). Of course, this break ++ * compatibility (although most operating systems initializes the ++ * BATs once and for all). ++ */ ++ ++#ifdef BAT_PERFORMANCE_HACK ++ #define BAT_HACK(kv) (!MREGS.use_bat_hack || kv->mmu.bat_hack_count++ < 0x100) ++#else ++ #define BAT_HACK(kv) 1 ++#endif ++ ++#define MREGS (kv->mregs) ++#define MMU (kv->mmu) ++ ++ ++int ++do_mtsdr1( kernel_vars_t *kv, ulong value ) ++{ ++ ulong mbase, mask; ++ int s; ++ ++ MREGS.spr[S_SDR1] = value; ++ ++ /* the mask must be a valid one; we hade better make sure we are ++ * not tricked by a bogus sdr1 value ++ */ ++ for( mask=BIT(23); mask && !(mask & value) ; mask=mask>>1 ) ++ ; ++ mask = mask? ((mask | (mask-1)) << 16) | 0xffff : 0xffff; ++ mbase = value & ~mask; ++ ++ if( mbase + mask >= MMU.ram_size ) { ++ /* S_SDR1 out of range, fallback to a safe setting */ ++ printk("WARNING, S_SDR1, %08lX is out of range\n", value); ++ mbase = 0; ++ mask = 0xffff; ++ } ++ ++ MMU.hash_mbase = mbase; ++ MMU.hash_mask = mask; ++ MMU.pthash_sr = -1; /* clear old tlbhash matching */ ++ ++ if( MMU.hash_base ) ++ unmap_emulated_hash( kv ); ++ MMU.hash_base = map_emulated_hash( kv, MMU.hash_mbase, mask+1 ); ++ ++ /* try to allocate the PTE bitfield table (16K/128 MB ram). The worst ++ * case is 512K which will fail since the kmalloc limit is 128K. ++ * If the allocation fails, we simply don't use the bitfield table. ++ */ ++ s = (mask+1)/8/8; ++ if( MMU.pthash_inuse_bits ) ++ kfree_cont_mol( MMU.pthash_inuse_bits ); ++ if( !(MMU.pthash_inuse_bits=kmalloc_cont_mol(s)) ) ++ MMU.pthash_inuse_bits_ph = 0; ++ else { ++ memset( MMU.pthash_inuse_bits, 0, s ); ++ MMU.pthash_inuse_bits_ph = tophys_mol( MMU.pthash_inuse_bits ); ++ } ++ ++ /* make sure the unmapped ram range is flushed... */ ++ flush_lv_range( kv, MMU.userspace_ram_base + mbase, mask+1 ); ++ ++ /* ...as well as any MMU mappings */ ++ clear_pte_hash_table( kv ); ++ ++ BUMP(do_mtsdr1); ++ return RVEC_NOP; ++} ++ ++/* This function is _very_ slow, since it must destroy a lot of PTEs. ++ * Fortunately, BAT-maps are normally static. ++ */ ++int ++do_mtbat( kernel_vars_t *kv, int sprnum, ulong value, int force ) ++{ ++ mac_bat_t *d; ++ int batnum; ++ mBAT *p; ++ ++ BUMP(do_mtbat); ++ ++ if( !force && MREGS.spr[sprnum] == value ) ++ return RVEC_NOP; ++ ++ /* printk("do_mtbat %d %08lX\n", sprnum, value); */ ++ ++ MREGS.spr[sprnum] = value; ++ ++ /* upper bat register have an even number */ ++ batnum = (sprnum - S_IBAT0U) >>1; ++ d = &MMU.bats[batnum]; ++ ++ /* First we must make sure that all PTEs corresponding to ++ * the old BAT-mapping are purged from the hash table. ++ */ ++ if( BAT_HACK(kv) && d->valid ) ++ flush_ea_range(kv, d->base & ~0xf0000000, d->size ); ++ ++ p = (mBAT*)&MREGS.spr[sprnum & ~1]; ++ d->valid = p->batu.vs | p->batu.vp; ++ d->vs = p->batu.vs; ++ d->vp = p->batu.vp; ++ d->wimg = (p->batl.w<<3) | (p->batl.i<<2) | (p->batl.m<<1) | p->batl.g; ++ d->ks = d->ku = 1; /* IBAT/DBATs, behaves as if key==1 */ ++ d->pp = p->batl.pp; ++ d->size = (p->batu.bl+1)<<17; ++ d->base = (p->batu.bepi & ~p->batu.bl)<<17; ++ d->mbase = (p->batl.brpn & ~p->batu.bl)<<17; ++ ++ /* Next, we must make sure that no PTEs refer to the new ++ * BAT-mapped area. ++ */ ++ ++ if( BAT_HACK(kv) && d->valid ) ++ flush_ea_range( kv, d->base & ~0xf0000000, d->size ); ++ ++ return RVEC_NOP; ++} ++ ++ ++/************************************************************************/ ++/* Emulation acceleration */ ++/************************************************************************/ ++ ++static ulong ++lookup_emuaccel_handler( int emuaccel ) ++{ ++ extern ulong emuaccel_table[]; ++ ulong handler, *p = emuaccel_table; ++ ++ for( ; p[0]; p+=3 ) { ++ if( (emuaccel & EMUACCEL_INST_MASK) != p[0] ) ++ continue; ++ emuaccel &= p[2]; /* offset mask */ ++ handler = p[1] + (ulong)emuaccel_table + emuaccel * 8; ++ return tophys_mol( (ulong*)reloc_ptr(handler) ); ++ } ++ return 0; ++} ++ ++int ++alloc_emuaccel_slot( kernel_vars_t *kv, int emuaccel, int param, int inst_addr ) ++{ ++ ulong *p = (ulong*)((char*)kv->emuaccel_page + kv->emuaccel_size); ++ ulong handler = lookup_emuaccel_handler( emuaccel ); ++ int size, ret; ++ ++ size = (emuaccel & EMUACCEL_HAS_PARAM)? 16 : 8; ++ if( !handler || !p || kv->emuaccel_size + size > 0x1000 ) ++ return 0; ++ ++ ret = kv->emuaccel_mphys + kv->emuaccel_size; ++ p[0] = handler; ++ p[1] = inst_addr + 4; ++ ++ if( emuaccel & EMUACCEL_HAS_PARAM ) { ++ /* p[2] is already EMUACCEL_NOP */ ++ p[3] = param; ++ } ++ ++ kv->emuaccel_size += size; ++ return ret; ++} ++ ++int ++mapin_emuaccel_page( kernel_vars_t *kv, int mphys ) ++{ ++ int i, handler; ++ ulong *p; ++ ++ if( kv->emuaccel_page || (mphys & 0xfff) ) ++ return 0; ++ ++ if( !(kv->emuaccel_page=alloc_page_mol()) ) ++ return 0; ++ ++ kv->emuaccel_page_phys = tophys_mol( (char*)kv->emuaccel_page ); ++ kv->emuaccel_mphys = mphys; ++ p = (ulong*)kv->emuaccel_page; ++ ++ handler = lookup_emuaccel_handler( EMUACCEL_NOP ); ++ for( i=0; i<0x1000/sizeof(int); i+=2 ) { ++ p[i] = handler; ++ p[i+1] = 0; ++ } ++ ++ /* flush translations - an old translation is overridden */ ++ clear_pte_hash_table( kv ); ++ /* printk("emuaccel_mapin: %08x\n", mphys ); */ ++ return mphys; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/fault.c +@@ -0,0 +1,601 @@ ++/* ++ * Creation Date: <2002/06/08 20:53:20 samuel> ++ * Time-stamp: <2004/02/22 13:07:50 samuel> ++ * ++ * ++ * ++ * Page fault handler ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++ ++#include "kernel_vars.h" ++#include "mmu.h" ++#include "mmu_contexts.h" ++#include "asmfuncs.h" ++#include "emu.h" ++#include "misc.h" ++#include "constants.h" ++#include "rvec.h" ++#include "mtable.h" ++#include "performance.h" ++#include "processor.h" ++#include "hash.h" ++ ++/* exception bits (srr1/dsisr and a couple of mol defined bits) */ ++#define EBIT_PAGE_FAULT BIT(1) /* I/D, PTE missing */ ++#define EBIT_NO_EXEC BIT(3) /* I, no-execute or guarded */ ++#define EBIT_PROT_VIOL BIT(4) /* I/D, protection violation */ ++#define EBIT_IS_WRITE BIT(6) /* D */ ++#define EBIT_IS_DSI 1 /* D, virtual bit */ ++#define EBIT_USE_MMU 2 /* I/D, virtual bit */ ++ ++#define use_mmu(ebits) ((ebits) & EBIT_USE_MMU) ++#define is_write(ebits) ((ebits) & EBIT_IS_WRITE) ++#define is_dsi(ebits) ((ebits) & EBIT_IS_DSI) ++#define is_prot_viol(ebits) ((ebits) & EBIT_PROT_VIOL) ++#define is_page_fault(ebits) ((ebits) & EBIT_PAGE_FAULT) ++ ++typedef struct { ++ /* filled in by exception handler */ ++ ulong ea; ++ ulong *sr_base; ++ struct vsid_ent **vsid_eptr; /* pointer to MMU.vsid or MMU.unmapped_vsid */ ++ ++ /* filled in by lookup_mphys */ ++ mPTE_t *mpte; /* lvptr to mac-pte (if != NULL) */ ++ ulong mphys_page; /* ea of mphys page */ ++ int pte1; /* RPN | 000 | R | C | WIMG | 00 | PP */ ++ int key; /* pp key bit */ ++} fault_param_t; ++ ++static const char priv_viol_table[16] = { /* [is_write | key | PP] */ ++ 0,0,0,0,1,0,0,0, /* read (1 == violation) */ ++ 0,0,0,1,1,1,0,1 /* write */ ++}; ++ ++#define NO_MMU_PTE1 (PTE1_R | PTE1_C /*| PTE1_M*/ | 0x2 /*pp*/ ) ++ ++#define MREGS (kv->mregs) ++#define MMU (kv->mmu) ++ ++#ifdef CONFIG_SMP ++#define SMP_PTE1_M PTE1_M ++#else ++#define SMP_PTE1_M 0 ++#endif ++ ++ ++/************************************************************************/ ++/* Debugging */ ++/************************************************************************/ ++ ++static inline void ++DEBUG_print_inserted_pte( ulong *slot, ulong pte0, ulong pte1, ulong ea ) ++{ ++#if 0 ++ mPTE_t pte; ++ ulong *p = (ulong)&pte; ++ p[0] = pte0; ++ p[1] = pte1; ++ ++ printk("[%p] ", slot ); ++ printk("RPN %08X API %08X EA %08lX ", pte.rpn << 12, pte.api<<12, ea ); ++ printk("%c%c %c%c; PP %d\n", ++ pte.h ? 'H' : 'h', ++ pte.v ? 'V' : 'v', ++ pte.r ? 'R' : 'r', ++ pte.c ? 'C' : 'c', pte.pp ); ++#endif ++} ++ ++ ++/************************************************************************/ ++/* MMU virtualization and page fault handling */ ++/************************************************************************/ ++ ++#ifdef EMULATE_603 ++static inline int ++lookup_603_pte( kernel_vars_t *kv, ulong vsid, ulong ea, int is_dsi, mPTE_t **ret_pte ) ++{ ++ int ind = (ea >> 12) & 0x1f; /* 32x2 PTEs */ ++ ulong mask, phash, cmp, pteg, cmp_ea, *eap; ++ mPTE_t *p; ++ ++ // printk("lookup_603_pte %08lX\n", ea); ++ ++ if( is_dsi ) { ++ p = &MMU.ptes_d_603[ind]; ++ eap = &MMU.ptes_d_ea_603[ind]; ++ } else { ++ p = &MMU.ptes_i_603[ind]; ++ eap = &MMU.ptes_i_ea_603[ind]; ++ } ++ cmp_ea = ea & 0x0ffff000; ++ for( ; ind < 64 ; ind += 32, p += 32, eap += 32 ) { ++ if( *eap == cmp_ea && p->vsid == vsid ) { ++ *ret_pte = p; ++ return 0; ++ } ++ } ++ mask = MMU.hash_mask >> 6; ++ ++ /* calculate primary and secondary PTEG */ ++ phash = (cmp_ea >> 12) ^ (vsid & 0x7ffff); ++ pteg = ((phash & mask) << 6); ++ MREGS.spr[S_HASH1] = MMU.hash_mbase + pteg; ++ MREGS.spr[S_HASH2] = MMU.hash_mbase + (pteg ^ (mask << 6)); ++ ++ /* construct compare word */ ++ cmp = BIT(0) | (vsid <<7) | (cmp_ea >> 22); ++ if( is_dsi ) { ++ MREGS.spr[S_DCMP] = cmp; ++ MREGS.spr[S_DMISS] = ea; ++ } else { ++ MREGS.spr[S_ICMP] = cmp; ++ MREGS.spr[S_IMISS] = ea; ++ } ++ return 1; ++} ++#endif ++ ++static inline mPTE_t * ++lookup_mac_pte( kernel_vars_t *kv, ulong vsid, ulong ea ) ++{ ++ ulong phash, cmp, pteg, *p; ++ ulong mask; ++ int i; ++ ++ /* make sure the hash is mapped... */ ++ if( !MMU.hash_base ) ++ return NULL; ++ ++ /* we are only interested in the page index */ ++ ea &= 0x0ffff000; ++ mask = MMU.hash_mask>>6; ++ ++ /* calculate primary hash function */ ++ phash = (ea >> 12) ^ (vsid & 0x7ffff); ++ pteg = ((phash & mask) << 6); ++ ++ /* construct compare word */ ++ cmp = BIT(0) | (vsid <<7) | ((ea&0x0fffffff)>>22); ++ ++ /* look in primary PTEG */ ++ p = (ulong*)((ulong)MMU.hash_base + pteg); ++ for( i=0; i<8; i++, p+=2 ) ++ if( cmp == *p ) ++ return (mPTE_t*)p; ++ ++ /* look in secondary PTEG */ ++ p = (ulong*)( (ulong)MMU.hash_base + (pteg ^ (mask << 6)) ); ++ cmp |= BIT(25); ++ ++ for( i=0; i<8; i++,p+=2 ) ++ if( cmp == *p ) ++ return (mPTE_t*)p; ++ return NULL; ++} ++ ++static int ++lookup_mphys( kernel_vars_t *kv, fault_param_t *pb, const int ebits ) ++{ ++ ulong ea = (pb->ea & ~0xfff); ++ mSEGREG segr; ++ mac_bat_t *bp; ++ int sv_mode, i, sbits; ++ mPTE_t *mpte; ++ ++ pb->mpte = NULL; ++ ++ if( !use_mmu(ebits) ) { ++ pb->mphys_page = ea; ++ pb->pte1 = NO_MMU_PTE1; ++ pb->key = 0; ++ return 0; ++ } ++ ++ segr = *(mSEGREG*)&MREGS.segr[ea>>28]; ++ sv_mode = !(MREGS.msr & MSR_PR); ++ ++ /* I/O segment? */ ++ if( segr.t ) { ++ /* Memory forced (601/604)? Note that the 601 uses I/O segments ++ * even if translation is off(!). We don't implement this though. ++ */ ++ ulong sr = MREGS.segr[ea>>28]; ++ BUMP( memory_forced_segment ); ++ ++ if( ((sr >> 20) & 0x1ff) != 0x7f ) ++ return RVEC_MMU_IO_SEG_ACCESS; ++ pb->mphys_page = (ea & 0x0ffff000) | ((sr & 0xf)<<28); ++ pb->pte1 = NO_MMU_PTE1; ++ pb->key = 0; ++ return 0; ++ } ++ ++ /* BAT translation? 0-3 = IBATs, 4-7 = DBATs. Separated I/D BATS, hace 3/8/99 */ ++ bp = is_dsi(ebits) ? &MMU.bats[4] : &MMU.bats[0]; ++ for( i=0; i<4; i++, bp++ ) { ++ if( !bp->valid ) ++ continue; ++ if( (sv_mode && !bp->vs) || (!sv_mode && !bp->vp) ) ++ continue; ++ if( ea < bp->base || ea > bp->base+bp->size-1 ) ++ continue; ++ ++ pb->mphys_page = ea - bp->base + bp->mbase; ++ pb->pte1 = bp->pp | (bp->wimg << 3) | PTE1_R | PTE1_C; ++ pb->key = sv_mode ? bp->ks : bp->ku; ++ return 0; ++ } ++ ++#ifdef EMULATE_603 ++ if( (MREGS.spr[S_PVR] >> 16) == 3 ) { ++ if( lookup_603_pte(kv, segr.vsid, ea, is_dsi(ebits), &mpte) ) ++ return is_dsi(ebits) ? (is_write(ebits) ? RVEC_DMISS_STORE_TRAP : ++ RVEC_DMISS_LOAD_TRAP) : RVEC_IMISS_TRAP; ++ ++ pb->mpte = NULL; /* imporant */ ++ pb->mphys_page = (mpte->rpn << 12); ++ pb->pte1 = ((ulong*)mpte)[1] & (PTE1_PP | PTE1_WIMG | PTE1_R | PTE1_C); ++ pb->key = sv_mode ? segr.ks : segr.kp; ++ return 0; ++ } ++#endif ++ /* mac page table lookup */ ++ if( (mpte=lookup_mac_pte(kv, segr.vsid, ea)) ) { ++ pb->mpte = mpte; ++ pb->mphys_page = (mpte->rpn << 12); ++ pb->pte1 = ((ulong*)mpte)[1] & (PTE1_PP | PTE1_WIMG | PTE1_R | PTE1_C); ++ pb->key = sv_mode ? segr.ks : segr.kp; ++ return 0; ++ } ++ /* mac page fault */ ++ sbits = EBIT_PAGE_FAULT | (ebits & EBIT_IS_WRITE); /* r/w bit + page_fault */ ++ RVEC_RETURN_2( &MREGS, is_dsi(ebits) ? RVEC_DSI_TRAP : RVEC_ISI_TRAP, pb->ea, sbits ); ++} ++ ++ ++/* PTE0 must be fully initialized on entry (with V=1 and H=0). ++ * The pte_present flag should be set from srr1/dsisr bit and indicates ++ * that a valid PTE might already be present in the hash table. ++ */ ++static inline ulong * ++find_pte_slot( ulong ea, ulong *pte0, int pte_present, int *pte_replaced ) ++{ ++ static int grab_add=0; ++ ulong phash, pteg, *p, cmp = *pte0; ++ ulong *primary, *secondary; ++ int i; ++ ++ /* we are only interested in the page index */ ++ ea &= 0x0ffff000; ++ ++ /* primary hash function */ ++ phash = (ea >> 12) ^ (PTE0_VSID(cmp) & 0x7ffff); ++ ++ pteg = (phash << 6) & ptehash.pteg_mask; ++ primary = (ulong*)((ulong)ptehash.base + pteg); ++ ++ pteg = pteg ^ ptehash.pteg_mask; ++ secondary = (ulong*)((ulong)ptehash.base + pteg); ++ ++ if( pte_present ) { ++ *pte_replaced = 1; ++ ++ /* look in primary PTEG */ ++ p = primary; ++ for( i=0; i<8; i++, p+=2 ) ++ if( cmp == *p ) ++ return p; ++ ++ /* look in secondary PTEG */ ++ p = secondary; ++ cmp |= BIT(25); ++ for( i=0; i<8; i++, p+=2 ) ++ if( cmp == *p ) { ++ *pte0 |= PTE0_H; ++ return p; ++ } ++ /* we will actually come here if the previous PTE ++ * was only available in the on-chip cache. ++ */ ++ } ++ *pte_replaced = 0; ++ ++ /* free slot in primary PTEG? */ ++ for( p=primary, i=0; i<8; i++, p+=2 ) ++ if( !(*p & BIT(0)) ) ++ return p; ++ ++ /* free slot in secondary PTEG? */ ++ for( p=secondary, i=0; i<8; i++, p+=2 ) ++ if( !(*p & BIT(0)) ) { ++ *pte0 |= PTE0_H; ++ return p; ++ } ++ ++ /* steal a primary PTEG slot */ ++ grab_add = (grab_add+1) & 0x7; ++ ++ /* printk("Grabbing slot %d, EA %08X\n",grab_add, ea ); */ ++ return (ulong*)((ulong)primary + grab_add * sizeof(ulong[2])); ++} ++ ++static inline int ++insert_pte( kernel_vars_t *kv, fault_param_t *pb, const int ebits ) ++{ ++ ulong ea=pb->ea, mphys=pb->mphys_page; ++ ulong sr=pb->sr_base[ea>>28]; ++ int status, pte_replaced; ++ pte_lvrange_t *lvrange; ++ ulong pte0, pte1, *slot; ++ ulong lvptr; ++ ++#ifdef CONFIG_AMIGAONE ++ pte1 = PTE1_R | (pb->pte1 & (PTE1_R | PTE1_C | PTE1_WIMG)) ++ | (is_write(ebits) ? 2:3); ++#else ++ pte1 = PTE1_M | PTE1_R | (pb->pte1 & (PTE1_R | PTE1_C | PTE1_WIMG)) ++ | (is_write(ebits) ? 2:3); ++#endif ++ ++ /* PP and WIMG bits must set before the call to mphys_to_pte */ ++ status = mphys_to_pte( kv, mphys, &pte1, is_write(ebits), &lvrange ); ++ ++ if( !status || (is_write(ebits) && (status & MAPPING_RO)) ) { ++ ulong addr = (mphys | (ea & 0xfff)); ++ if( is_dsi(ebits) ) { ++ int rvec = is_write(ebits) ? RVEC_IO_WRITE : RVEC_IO_READ; ++ BUMP( io_read_write ); ++ RVEC_RETURN_2( &MREGS, rvec, addr, NULL ); ++ } else { ++ RVEC_RETURN_1( &MREGS, RVEC_BAD_NIP, addr ); ++ } ++ } ++ ++ /* tlbhash table hit? */ ++ if( (ulong)(pb->mphys_page - MMU.hash_mbase) < (ulong)MMU.hash_mask ) { ++ /* printk("hash_table_hit at %08lX\n", pb->ea ); */ ++ MMU.pthash_sr = sr; ++ MMU.pthash_ea_base = ea & ~MMU.hash_mask; ++ ++ /* user read (always), superuser r/w */ ++ pte1 &= ~PTE1_PP; ++ pte1 |= is_write(ebits) ? 1:3; ++ /* write accesses of the page table are handled in ptintercept.S */ ++ } ++ ++ pte0 = PTE0_V | (sr << 7) | ((ea>>22) & PTE0_API); ++ slot = find_pte_slot( ea, &pte0, !is_page_fault(ebits), &pte_replaced ); ++ ++ lvptr = (status & MAPPING_PHYSICAL) ? 0 : (pte1 & PTE1_RPN); ++ ++ /* the RC bits should correspond to the is_write flag; this prevents the ++ * CPU from stamping RC bits unnecessary (besides, the kernel seems to ++ * assume no RC-stamps will ever occur so RC-stamping is unsafe). ++ */ ++ if( is_write(ebits) ) ++ pte1 |= PTE1_C; ++ pte1 |= SMP_PTE1_M; ++ ++ /* if a page-out occurs between prepare_pte_insert() and the pte_inserted() ++ * call, then the PTE slot is zeroed out. ++ */ ++ if( !(status & MAPPING_PHYSICAL) ) { ++#if 0 ++ if( is_write(ebits) ) ++ lvpage_dirty( kv, lvptr ); ++#endif ++ pte1 &= ~PTE1_RPN; ++ ++ /* zero pages should work just fine now... */ ++ pte1 |= get_phys_page( kv, lvptr, is_write(ebits) ); ++ /* pte1 |= get_phys_page( kv, lvptr, !(status & MAPPING_RO) ); */ ++ } ++ ++ if( status & MAPPING_FB_ACCEL ) ++ video_pte_inserted( kv, lvptr, slot, pte0, pte1, ea ); ++ ++ BUMP( page_fault_ctr ); ++ DEBUG_print_inserted_pte( slot, pte0, pte1, ea ); ++ ++ __store_PTE( ea, slot, pte0, pte1 ); ++ ++ pte_inserted( kv, ea, (char*)lvptr, lvrange, slot, pb->vsid_eptr[ea>>28], sr ); ++ ++ /* debugger support */ ++ if( (kv->break_flags & BREAK_EA_PAGE) && (ea & ~0xfff) == MREGS.mdbg_ea_break ) ++ RVEC_RETURN_1( &MREGS, RVEC_BREAK, BREAK_EA_PAGE ); ++ ++ return RVEC_NOP; ++} ++ ++static int ++page_fault( kernel_vars_t *kv, fault_param_t *pb, const int ebits ) ++{ ++ int topind = pb->ea >> 28; ++ int ind, ret; ++ ++ BUMP( access_exception_ctr ); ++ ++ if( (ret=lookup_mphys(kv, pb, ebits)) ) { ++ BUMP(mac_page_fault); ++ return ret; ++ } ++ ++ /* printk("MPHYS_PAGE: %08lX, pp %d, key %d, wimg %d, mpte %p\n", ++ pb->mphys_page, (pb->pte1 & 3), pb->key, ((pb->pte1 >> 3) & 0xf), pb->mpte ); */ ++ ++ /* check privileges */ ++ ind = (is_write(ebits) ? 8:0) | (pb->pte1 & PTE1_PP) | (pb->key?4:0); ++ if( priv_viol_table[ind] ) { ++ /* r/w bit + priv. violation */ ++ int sbits = EBIT_PROT_VIOL | (ebits & EBIT_IS_WRITE); ++ BUMP(mac_priv_violation); ++ RVEC_RETURN_2( &MREGS, is_dsi(ebits) ? RVEC_DSI_TRAP : RVEC_ISI_TRAP, pb->ea, sbits ); ++ } ++ ++ /* stamp R/C bits (mpte is NULL if this is not a page translation). */ ++ if( pb->mpte ) { ++ pb->mpte->r = 1; ++ if( is_write(ebits) ) ++ pb->mpte->c = 1; ++ ++ /* stamp pthash_inuse_bit */ ++ if( MMU.pthash_inuse_bits ) { ++ int nr = ((int)pb->mpte - (int)MMU.hash_base) >> 3; ++ set_bit_mol( nr, MMU.pthash_inuse_bits ); ++ } ++ } ++ ++ /* perform memory allocations if necessary; we are not allowed to ++ * do this later (the mtable insertion must be atomic) ++ */ ++ if( mtable_memory_check(kv) ) ++ return RVEC_NOP; /* out of memory */ ++ ++ /* the vsid entry might have been released */ ++ if( !pb->vsid_eptr[topind] ) ++ return RVEC_NOP; ++ ++ return insert_pte( kv, pb, ebits ); ++} ++ ++ ++/************************************************************************/ ++/* VSID allocation (the normal VSID lookup occurs in vsid.S) */ ++/************************************************************************/ ++ ++static void ++fix_sr( kernel_vars_t *kv, int sr, int mapped ) ++{ ++ int macvsid = mapped ? (MREGS.segr[sr] & VSID_MASK) : VSID_MASK + 1 + sr; ++ ulong user_sr, sv_sr; ++ vsid_ent_t *r = vsid_get_user_sv( kv, macvsid, &user_sr, &sv_sr ); ++ ++ BUMP(fix_sr); ++ if( !r ) ++ return; ++ ++ if( mapped ) { ++ int value = MREGS.segr[sr]; ++ int nbit = value & VSID_N; ++ MMU.vsid[sr] = r; ++ MMU.user_sr[sr] = ((value & VSID_Kp) ? user_sr : sv_sr) | nbit; ++ MMU.sv_sr[sr] = ((value & VSID_Ks) ? user_sr : sv_sr) | nbit; ++ } else { ++ MMU.unmapped_vsid[sr] = r; ++ MMU.unmapped_sr[sr] = user_sr; ++ } ++ invalidate_splitmode_sr( kv ); ++} ++ ++ ++/************************************************************************/ ++/* Exception entrypoints (called from assembly) */ ++/************************************************************************/ ++ ++extern int dsi_exception( kernel_vars_t *kv, ulong dar, ulong dsisr ); ++extern int isi_exception( kernel_vars_t *kv, ulong nip, ulong srr1 ); ++ ++int ++dsi_exception( kernel_vars_t *kv, ulong dar, ulong dsisr ) ++{ ++ int ebits, topind = dar >> 28; ++ fault_param_t pb; ++ ++ /* printk("DSI: EA %08lX, DSISR %08lX\n", dar, dsisr ); */ ++ if( dsisr & 0x84500000 ) /* 0,5,9,11 */ ++ RVEC_RETURN_2( &MREGS, RVEC_UNUSUAL_DSISR_BITS, dar, dsisr ); ++ ++ pb.ea = dar; ++ ebits = EBIT_IS_DSI | (dsisr & (EBIT_PAGE_FAULT | EBIT_PROT_VIOL | EBIT_IS_WRITE)) ++ | ((MREGS.msr & MSR_DR) ? EBIT_USE_MMU : 0); ++ ++ pb.vsid_eptr = (MREGS.msr & MSR_DR) ? MMU.vsid : MMU.unmapped_vsid; ++ pb.sr_base = (ulong*)((ulong)MMU.sr_data - kv->kvars_tophys_offs); ++ ++ /* segment register switch-in required? */ ++ if( !pb.vsid_eptr[topind] ) { ++ fix_sr( kv, topind, use_mmu(ebits) ); ++ return RVEC_NOP; ++ } ++ BUMP(dsi); ++ return page_fault( kv, &pb, ebits ); ++} ++ ++int ++isi_exception( kernel_vars_t *kv, ulong nip, ulong srr1 ) ++{ ++ fault_param_t pb; ++ /* printk("ISI: NIP %08lX, SRR1 %08lX\n", nip, srr1 ); */ ++ ++ pb.vsid_eptr = (MREGS.msr & MSR_IR) ? MMU.vsid : MMU.unmapped_vsid; ++ ++ if( srr1 & EBIT_PAGE_FAULT ) { ++ int ebits = EBIT_PAGE_FAULT | ((MREGS.msr & MSR_IR) ? EBIT_USE_MMU : 0); ++ pb.ea = nip; ++ pb.sr_base = (ulong*)((ulong)MMU.sr_inst - kv->kvars_tophys_offs); ++ BUMP(isi_page_fault); ++ return page_fault( kv, &pb, ebits ); ++ } ++ if( srr1 & EBIT_NO_EXEC ) { ++ int sr = nip >> 28; ++ if( !pb.vsid_eptr[sr] ) { ++ fix_sr( kv, sr, (MREGS.msr & MSR_IR) ); ++ return RVEC_NOP; ++ } ++ /* printk("Guarded memory access at %08lX\n", nip ); */ ++ RVEC_RETURN_2( &MREGS, RVEC_ISI_TRAP, nip, EBIT_NO_EXEC ); ++ } ++ ++ BUMP(isi_prot_violation); ++ /* must be privileges violation */ ++ RVEC_RETURN_2( &MREGS, RVEC_ISI_TRAP, nip, EBIT_PROT_VIOL ); ++} ++ ++ ++/************************************************************************/ ++/* debugger functions */ ++/************************************************************************/ ++ ++int ++dbg_translate_ea( kernel_vars_t *kv, int context, ulong va, int *ret_mphys, int data_access ) ++{ ++ int ebits = data_access ? EBIT_IS_DSI : 0; ++ fault_param_t pb; ++ ++ memset( &pb, 0, sizeof(pb) ); ++ pb.ea = va; ++ ++ switch( context ) { ++ case kContextUnmapped: ++ pb.sr_base = MMU.unmapped_sr; ++ break; ++ case kContextMapped_S: ++ pb.sr_base = MMU.sv_sr; ++ ebits |= EBIT_USE_MMU; ++ break; ++ case kContextMapped_U: ++ pb.sr_base = MMU.user_sr; ++ ebits |= EBIT_USE_MMU; ++ break; ++ default: ++ return 1; ++ } ++ ++ if( lookup_mphys(kv, &pb, ebits) ) ++ return 1; ++ *ret_mphys = pb.mphys_page | (va & 0xfff); ++ return 0; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/hash.c +@@ -0,0 +1,126 @@ ++/* ++ * Creation Date: <2004/02/14 11:42:19 samuel> ++ * Time-stamp: <2004/03/13 14:25:00 samuel> ++ * ++ * ++ * ++ * CPU PTE hash handling ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "mmu.h" ++#include "mmu_contexts.h" ++#include "asmfuncs.h" ++#include "emu.h" ++#include "misc.h" ++#include "mtable.h" ++#include "performance.h" ++#include "context.h" ++#include "hash.h" ++#include "map.h" ++ ++/* GLOBALS */ ++hash_info_t ptehash; ++ ++static struct { ++ int hash_mapped; ++ int sdr1_loaded; ++ char *allocation; ++} hs; ++ ++ ++static int ++create_pte_hash( void ) ++{ ++ ulong size = 1024*128; /* 128K is the kmalloc limit */ ++ ulong sdr1, mask, base, physbase; ++ char *p; ++ ++ if( !(p=kmalloc_cont_mol(size)) ) ++ return 1; ++ memset( p, 0, size ); ++ base = (ulong)p; ++ physbase = tophys_mol( (char*)base ); ++ ++ if( (physbase & (size-1)) ) { ++ int offs; ++ printk("Badly aligned SDR1 allocation - 64K wasted\n"); ++ size /= 2; ++ offs = ((physbase + size) & ~(size-1)) - physbase; ++ physbase += offs; ++ base += offs; ++ } ++ mask = (size-1) >> 6; ++ sdr1 = mask >> 10; ++ sdr1 |= physbase; ++ ++ hs.allocation = p; ++ ptehash.sdr1 = sdr1; ++ ptehash.base = (ulong*)base; ++ ++ printk("SDR1 = %08lX\n", sdr1 ); ++ return 0; ++} ++ ++int ++init_hash( void ) ++{ ++ ulong sdr1; ++ ++ memset( &ptehash, 0, sizeof(ptehash) ); ++ ++ if( IS_LINUX ) { ++ sdr1 = _get_sdr1(); ++ ++ /* linux does not use SDR1 on the 603[e] */ ++ if( !sdr1 ) { ++ create_pte_hash(); ++ sdr1 = ptehash.sdr1; ++ _set_sdr1( sdr1 ); ++ hs.sdr1_loaded = 1; ++ } ++ } else { ++ /* sharing the hash under darwin is too complicated */ ++ create_pte_hash(); ++ sdr1 = ptehash.sdr1; ++ } ++ ++ if( !sdr1 ) ++ return 1; ++ ++ ptehash.sdr1 = sdr1; ++ ptehash.pteg_mask = (((sdr1 & 0x1ff) << 10) | 0x3ff) << 6; ++ ptehash.pte_mask = ptehash.pteg_mask | 0x38; ++ ptehash.physbase = sdr1 & ~0xffff; ++ ++ if( !ptehash.base ) { ++ hs.hash_mapped = 1; ++ ptehash.base = map_hw_hash( ptehash.physbase, ptehash.pte_mask + 8 ); ++ } ++ ++ return !ptehash.base; ++} ++ ++void ++cleanup_hash( void ) ++{ ++ if( hs.hash_mapped ) ++ unmap_hw_hash( ptehash.base ); ++ ++ if( hs.sdr1_loaded ) ++ _set_sdr1( 0 ); ++ if( hs.allocation ) ++ kfree_cont_mol( hs.allocation ); ++ ++ memset( &ptehash, 0, sizeof(ptehash) ); ++ memset( &hs, 0, sizeof(hs) ); ++} +--- /dev/null ++++ b/drivers/macintosh/mol/include/actions.h +@@ -0,0 +1,177 @@ ++/* ++ * Creation Date: <2004/01/31 13:08:42 samuel> ++ * Time-stamp: <2004/03/07 14:25:23 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_ACTIONS ++#define _H_ACTIONS ++ ++/* Certain assembly macros (like LI_PHYS) adds meta information to a special ++ * ELF segment. This information is parsed when the module is loaded/used and ++ * the appropriate action is performed (a few assembly instruction are typically ++ * modified). ++ * ++ * Actions with lower opcodes are performed before actions with higher opcodes. ++ */ ++ ++#define ACTION_LIS_SPECVAR_H 1 /* dreg, special_var_index */ ++#define ACTION_ORI_SPECVAR_L 2 /* dreg*32 + sreg, special_var_index */ ++#define ACTION_LI_PHYS 3 /* dreg, addr_offs */ ++#define ACTION_LWZ_PHYSADDR_R 4 /* dreg*32 + reg, addr_offs */ ++#define ACTION_TOPHYS 5 /* dreg*32 + sreg */ ++#define ACTION_TOVIRT 6 /* dreg*32 + sreg */ ++#define ACTION_RELOCATE_LOW 7 /* code_size, destvar, code... */ ++#define ACTION_VRET 8 /* vector [special, used by RELOC_HOOK] */ ++#define ACTION_FIX_SPRG2 9 /* scratch_reg */ ++ ++#define FLUSH_CACHE_ACTION 9 /* flush the icache at this point */ ++ ++#define ACTION_HOOK_FUNCTION 10 ++#define ACTION_RELOC_HOOK 11 /* trigger, size, vret_action#, vret_offs */ ++#define MAX_NUM_ACTIONS 12 ++ ++/* Special vars (ACTION_*_SPECVAR) */ ++#define SPECVAR_SESSION_TABLE 1 ++ ++/* Function hooks (ACTION_HOOK_FUNCTION) */ ++#define FHOOK_FLUSH_HASH_PAGE 1 ++ ++#ifndef __ASSEMBLY__ ++typedef struct { ++ int action; /* ACTION_xxx */ ++ int offs; /* target instruction offset (from r__reloctable_start) */ ++ int params[1]; /* parameters */ ++} action_pb_t; ++#endif /* __ASSEMBLY__ */ ++ ++ ++/************************************************************************/ ++/* assembly macros */ ++/************************************************************************/ ++ ++/* ++ * WARNING: These macros uses the 9 label (the OSX assembler ++ * can only use labels (0-9). ++ */ ++ ++#ifdef __ASSEMBLY__ ++ ++#ifdef __linux__ ++#define ACTIONS_SECTION .text 95 ++#define ACTIONS_OFFS_SECTION .text 96 ++#endif ++#ifdef __darwin__ ++#define ACTIONS_SECTION .section __TEXT,__areloc ++#define ACTIONS_OFFS_SECTION .section __DATA,__areloc_offs ++#endif ++ ++mDEFINE(ACTION_PB, [action], [ ++ .text ++9: ++ ACTIONS_SECTION ++ .long _action /* action */ ++ .long (9b - r__reloctable_start) /* target PC */ ++9: ++ ACTIONS_OFFS_SECTION ++ .long (9b - r__actions_section - 8) /* store pointer to PB */ ++ ACTIONS_SECTION ++]) ++ ++mDEFINE(ACTION_1, [action, p1], [ ++ ACTION_PB( _action ) ++ .long _p1 ++ .text ++ nop /* replaced */ ++]) ++ ++mDEFINE(ACTION_21, [action, p1, p2], [ ++ ACTION_PB( _action ) ++ .long _p1, _p2 ++ .text ++ nop /* replaced */ ++]) ++ ++mDEFINE(ACTION_2, [action, p1, p2], [ ++ ACTION_PB( _action ) ++ .long _p1, _p2 ++ .text ++ nop /* replaced */ ++ nop /* replaced */ ++]) ++ ++mDEFINE(ACTION_13, [action, p1], [ ++ ACTION_PB( _action ) ++ .long _p1 ++ .text ++ nop /* replaced */ ++ nop /* replaced */ ++ nop /* replaced */ ++]) ++ ++ ++ /* replaced with lis dreg,addr@ha ; addi dreg,dreg,addr@l */ ++#define LI_PHYS( dreg, addr ) \ ++ ACTION_2( ACTION_LI_PHYS, dreg, (addr - r__reloctable_start) ) ++ ++ /* replaced with addis dreg,reg,addr@ha ; lwz dreg,addr@lo(dreg). */ ++#define LWZ_PHYSADDR_R( dreg, addr, reg ) \ ++ ACTION_2( ACTION_LWZ_PHYSADDR_R, (dreg*32 + reg), (addr - r__reloctable_start) ) ++ ++#define LWZ_PHYS( dreg, addr ) \ ++ LWZ_PHYSADDR_R( dreg, addr, 0 ); ++ ++ /* syntax: tophys rD,rS */ ++MACRO(tophys, [dreg, sreg], [ ++ ACTION_1( ACTION_TOPHYS, (_dreg * 32 + _sreg) ) ++]) ++ /* syntax: tovirt rD,rS */ ++MACRO(tovirt, [dreg, sreg], [ ++ ACTION_1( ACTION_TOVIRT, (_dreg * 32 + _sreg) ) ++]) ++ ++ /* syntax: lis_specvar_ha rD,SPECIAL_VAR */ ++MACRO(lis_svh, [dreg, specvariable], [ ++ ACTION_21( ACTION_LIS_SPECVAR_H, _dreg, _specvariable ) ++]) ++ ++ /* syntax: addi_specvar_ha rD,rS,SPECIAL_VAR */ ++MACRO(ori_svl, [dreg, sreg, specvariable], [ ++ ACTION_21( ACTION_ORI_SPECVAR_L, (_dreg * 32)+_sreg, _specvariable ) ++]) ++ ++ /* syntax: FIX_SPRG2 rN */ ++MACRO(fix_sprg2, [reg], [ ++ /* only darwin needs this (sprg_a0 holds bits describing the CPU) */ ++#ifdef __darwin__ ++ ACTION_13( ACTION_FIX_SPRG2, _reg ) ++#endif ++]) ++ ++mDEFINE(RELOC_LOW, [destvar], [ ++ ACTION_PB( ACTION_RELOCATE_LOW ) ++ .long _destvar[]_end - _destvar[]_start ++ .long EXTERN([]_destvar) ++_destvar[]_start: ++]) ++ ++mDEFINE(RELOC_LOW_END, [destvar], [ ++_destvar[]_end: ++ .text ++]) ++ ++ ++#endif /* __ASSEMBLY__ */ ++ ++ ++#endif /* _H_ACTIONS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/alloc.h +@@ -0,0 +1,70 @@ ++/* ++ * Creation Date: <2002/01/13 16:35:18 samuel> ++ * Time-stamp: <2004/01/25 17:36:49 samuel> ++ * ++ * ++ * ++ * Memory allocation and mappings ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_ALLOC ++#define _H_ALLOC ++ ++#include ++#include ++#include ++#include ++ ++#ifdef LINUX_26 ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) ++#include ++#endif ++#endif ++ ++static inline void *kmalloc_mol( int size ) { ++ return kmalloc( size, GFP_KERNEL ); ++} ++static inline void kfree_mol( void *p ) { ++ kfree( p ); ++} ++static inline void *vmalloc_mol( int size ) { ++ return vmalloc( size ); ++} ++static inline void vfree_mol( void *p ) { ++ vfree( p ); ++} ++static inline ulong alloc_page_mol( void ) { ++ return get_zeroed_page( GFP_KERNEL ); ++} ++static inline void free_page_mol( ulong addr ) { ++ free_page( addr ); ++} ++static inline void *kmalloc_cont_mol( int size ) { ++ return kmalloc( size, GFP_KERNEL ); ++} ++static inline void kfree_cont_mol( void *addr ) { ++ kfree( addr ); ++} ++static inline ulong tophys_mol( void *addr ) { ++ return virt_to_phys(addr); ++} ++static inline void flush_icache_mol( ulong start, ulong stop ) { ++ flush_icache_range( start, stop ); ++} ++static inline void *map_phys_range( ulong paddr, ulong size, char **ret_addr ) { ++ /* Warning: This works only for certain addresses... */ ++ *ret_addr = phys_to_virt(paddr); ++ return (void*)(-2); /* dummy */ ++} ++static inline void unmap_phys_range( void *handle ) {} ++ ++ ++#endif /* _H_ALLOC */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/archinclude.h +@@ -0,0 +1,77 @@ ++/* ++ * Creation Date: <2002/01/12 22:11:51 samuel> ++ * Time-stamp: <2004/04/10 22:27:41 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_ARCHINCLUDE ++#define _H_ARCHINCLUDE ++ ++//#define PERF_MONITOR ++//#define PERFORMANCE_INFO /* collect performance statistics */ ++//#define PERFORMANCE_INFO_LIGHT /* sample only the most important counters */ ++ ++#include "mol_config.h" ++#include "kconfig.h" ++ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) ++#include ++#endif ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) ++#include ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ++#define LINUX_26 ++#endif ++ ++#ifndef __ASSEMBLY__ ++#include ++#include ++#include /* needed by */ ++#include ++#include ++ ++#include "dbg.h" ++ ++/* these are declared, but we just want to be sure the definition does not change */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ++extern int flush_hash_pages( unsigned context, unsigned long va, unsigned long pmdval, int count ); /* 2.6 */ ++#else ++extern int flush_hash_page( unsigned context, unsigned long va, pte_t *ptep ); /* 2.5 */ ++#endif /* Linux 2.6 */ ++ ++#endif /* __ASSEMBLY__ */ ++ ++#ifdef LINUX_26 ++#define compat_flush_hash_pages flush_hash_pages ++#define compat_hash_table_lock mmu_hash_lock ++#else ++#define compat_flush_hash_pages flush_hash_page ++#define compat_hash_table_lock hash_table_lock ++#endif ++ ++ ++#define ENOSYS_MOL ENOSYS ++#define EFAULT_MOL EFAULT ++ ++#define IS_LINUX 1 ++#define IS_DARWIN 0 ++ ++ ++#endif /* _H_ARCHINCLUDE */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/asm.m4 +@@ -0,0 +1,141 @@ ++/* -*- asm -*- ++ * Creation Date: <2001/12/30 20:08:53 samuel> ++ * Time-stamp: <2002/01/14 00:48:09 samuel> ++ * ++ * ++ * ++ * m4 initialization (m4 is used as an assembly preprocessor) ++ * ++ * Copyright (C) 2001, 2002, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++/* This end-of-quote matches the start-of-quote in mol_config.h */ ++]]]]] ++divert(-1) ++changequote([,]) ++ ++dnl m4 macros to avoid in header files (we can not rename these) ++dnl ========================================================== ++dnl shift, eval, expr, decr, incr, ifelse, popdef, pushdef ++ ++ ++dnl ************************************************************** ++dnl * Rename to reduce namespace conflicts ++dnl ************************************************************** ++ ++dnl *** Changing the name of built-in macros using defn does not always work *** ++ ++undefine([changecom]) ++undefine([changequote]) ++dnl undefine([decr]) ++undefine([defn]) ++dnl undefine([divert]) ++undefine([divnum]) ++undefine([errprint]) ++dnl undefine([eval]) ++dnl undefine([expr]) ++undefine([file]) ++undefine([format]) ++undefine([len]) ++undefine([line]) ++dnl undefine([ifelse]) ++dnl undefine([incr]) ++undefine([indir]) ++undefine([include]) ++undefine([index]) ++undefine([maketemp]) ++undefine([paste]) ++undefine([patsubst]) ++dnl undefine([popdef]) ++dnl undefine([pushdef]) ++undefine([regexp]) ++dnl undefine([shift]) ++undefine([sinclude]) ++undefine([spaste]) ++undefine([substr]) ++undefine([syscmd]) ++undefine([sysval]) ++undefine([translit]) ++undefine([traceoff]) ++undefine([traceon]) ++undefine([undivert]) ++undefine([unix]) ++dnl undefine([__gnu__]) ++dnl undefine([__unix__]) ++ ++dnl Uncomment to list m4 definitions ++dnl dumpdef m4exit ++ ++/************************************************************************/ ++/* M4 Macros */ ++/************************************************************************/ ++ ++dnl ++dnl WARNING - M4 BUG IN MacOS X (10.1.2): ++dnl eval() in MacOS X (10.1.2) handles '&' as '&&' and '|' as '||'. ++dnl ++ ++/* FORLOOP(var, from, to, [body var...]) */ ++define([mFORLOOP], [pushdef([$1], [$2])_mFORLOOP([$1], [$2], [$3], [$4])popdef([$1])]) ++define([_mFORLOOP], [$4[]ifelse($1, [$3], , ++ [define([$1], incr($1))_mFORLOOP([$1], [$2], [$3], [$4])])]) ++ ++define([mFIRST],[$1]) ++define([mCONCAT_C],[ [$@] ]) ++ ++/* FOREACH(var, [item1, ...], [body var ...]) */ ++define([mFOREACH],[pushdef([$1],mFIRST($2))_mFOREACH([$1],[shift($2)],[$3])popdef([$1])]) ++define([_mFOREACH],[$3] [ifelse(mFIRST($2),,,[define([$1],mFIRST($2)) _mFOREACH([$1],[shift($2)],[$3])])]) ++ ++ ++/******************** Nice macro definitions **************************/ ++ ++/* MACRO(name, [param1, ...], [body _param1 ...]) */ ++#ifdef __linux__ ++define([MACRO], [ ++ .macro [$1] $2 ++ mFOREACH([i],[$2],[ pushdef(_[]i,\i) ]) ++ $3 ++ .endm ++ mFOREACH([i],[$2],[ popdef(_[]i) ]) ++]) ++#else ++define([MACRO], [ ++ .macro [$1] ++ pushdef([_n],0) ++ mFOREACH([i],[$2],[ pushdef(_[]i,[$[]]_n) define([_n],incr(_n)) ]) ++ $3 ++ .endmacro ++ mFOREACH([i],[$2],[ popdef(_[]i) ]) ++ popdef([_n]) ++]) ++#endif ++define([MACRO_0], [MACRO([$1],[_dummy_param_],[$2])]) ++ ++ ++/* mDEFINE(name, [param1, ...], [body _param1 ...]) */ ++define([mDEFINE], [ ++ pushdef([_n],1) ++ mFOREACH([i],[$2],[ pushdef(_[]i,[$[]]_n) define([_n],incr(_n)) ]) ++ define([$1], mCONCAT_C($3) ) ++ mFOREACH([i],[$2],[ popdef(_[]i) ]) ++ popdef([_n]) ++]) ++ ++ ++/* rLABEL(label): b label_b ; b label_f */ ++define(rLABEL,[dnl ++ifdef([$1]_curnum,,[$1[]f:])dnl ++ define([_tmp_curnum],ifdef($1[]_curnum, [eval($1_curnum+1)], 1)) dnl ++ define([$1]_curnum,_tmp_curnum)dnl ++ define([$1]f,$1_[]eval($1_curnum[]+1) )dnl ++ define([$1]b,$1_[]$1_curnum[] ) ++$1[]_[]$1_curnum[]dnl ++]) ++ ++divert(0)dnl +--- /dev/null ++++ b/drivers/macintosh/mol/include/asm_offsets.inc +@@ -0,0 +1,136 @@ ++/* -*-c-*- ++ * Creation Date: <2001/10/20 17:51:10 samuel> ++ * Time-stamp: <2004/02/21 21:38:27 samuel> ++ * ++ * ++ * ++ * Extra offsets (included from asm_offsets.c) ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++extern void extra( void ); ++ ++void ++extra( void ) ++{ ++ DEFINE(SIZE_OF_KERNEL_VARS, sizeof( kernel_vars_t )); ++ ++ ST_DEF( ST_MAGIC, magic ); ++ ST_DEF( ST_KVARS_PH, kvars_ph ); ++ ++ K_DEF( K_EMUACCEL_PAGE, emuaccel_page ); ++ K_DEF( K_EMUACCEL_PAGE_PHYS, emuaccel_page_phys ); ++ K_DEF( K_EMUACCEL_MPHYS, emuaccel_mphys ); ++ K_DEF( K_EMUACCEL_SIZE, emuaccel_size ); ++ ++ K_DEF( K_KERNEL_VARS, kvars_virt ); ++ K_DEF( K_BREAK_FLAGS, break_flags ); ++#ifdef PERFORMANCE_INFO ++ K_DEF( K_ASM_BUMP_CNTRS, asm_bump_cntr ); ++ K_DEF( K_ASM_TICK_STAMPS, asm_tick_stamp ); ++#endif ++ /* MMU */ ++ K_DEF( K_ILLEGAL_SR, mmu.illegal_sr ); ++ K_DEF( K_CUR_SR_BASE, mmu.cur_sr_base ); ++ K_DEF( K_SR_DATA, mmu.sr_data ); ++ K_DEF( K_SR_INST, mmu.sr_inst ); ++ ++ K_DEF( K_UNMAPPED_SR_BASE, mmu.unmapped_sr[0] ); ++ K_DEF( K_USER_SR_BASE, mmu.user_sr[0] ); ++ K_DEF( K_SV_SR_BASE, mmu.sv_sr[0] ); ++ K_DEF( K_SPLIT_SR_BASE, mmu.split_sr[0] ); ++ K_DEF( K_VSID_ENT_BASE, mmu.vsid[0] ); ++ ++#ifdef __darwin__ ++ K_DEF( K_OS_SDR1, mmu.os_sdr1 ); ++ K_DEF( K_MOL_SDR1, mmu.mol_sdr1 ); ++ DEFINE( SKIPLIST_NEXT, offsetof(skiplist_el_t, level[0].next_phys) ); ++#endif ++#ifdef __linux__ ++ DEFINE( SKIPLIST_NEXT, offsetof(skiplist_el_t, level[0].next) ); ++#endif ++ DEFINE( SKIPLIST_LEVELSIZE, sizeof(skiplist_level_t) ); ++ DEFINE( SKIPLIST_KEY, offsetof(skiplist_el_t, key) ); ++ DEFINE( K_VSID_SL_ROOT_ELEM, offsetof(kernel_vars_t, mmu.vsid_sl.root) ++ - offsetof(skiplist_el_t, level)); ++ K_DEF( K_VSID_SL_SLEVEL, mmu.vsid_sl.slevel ); ++ ++ K_DEF( K_IBAT0U_SAVE, _bp.ibat_save[0].word[0] ); ++ K_DEF( K_IBAT0L_SAVE, _bp.ibat_save[0].word[1] ); ++ K_DEF( K_IBAT1U_SAVE, _bp.ibat_save[1].word[0] ); ++ K_DEF( K_IBAT1L_SAVE, _bp.ibat_save[1].word[1] ); ++ K_DEF( K_IBAT2U_SAVE, _bp.ibat_save[2].word[0] ); ++ K_DEF( K_IBAT2L_SAVE, _bp.ibat_save[2].word[1] ); ++ K_DEF( K_IBAT3U_SAVE, _bp.ibat_save[3].word[0] ); ++ K_DEF( K_IBAT3L_SAVE, _bp.ibat_save[3].word[1] ); ++ ++ K_DEF( K_DBAT0U_SAVE, _bp.dbat_save[0].word[0] ); ++ K_DEF( K_DBAT0L_SAVE, _bp.dbat_save[0].word[1] ); ++ K_DEF( K_DBAT1U_SAVE, _bp.dbat_save[1].word[0] ); ++ K_DEF( K_DBAT1L_SAVE, _bp.dbat_save[1].word[1] ); ++ K_DEF( K_DBAT2U_SAVE, _bp.dbat_save[2].word[0] ); ++ K_DEF( K_DBAT2L_SAVE, _bp.dbat_save[2].word[1] ); ++ K_DEF( K_DBAT3U_SAVE, _bp.dbat_save[3].word[0] ); ++ K_DEF( K_DBAT3L_SAVE, _bp.dbat_save[3].word[1] ); ++ ++ K_DEF( K_SPLIT_DBAT0U, mmu.split_dbat0.word[0] ); ++ K_DEF( K_SPLIT_DBAT0L, mmu.split_dbat0.word[1] ); ++ K_DEF( K_TRANSL_DBAT0U, mmu.transl_dbat0.word[0] ); ++ K_DEF( K_TRANSL_DBAT0L, mmu.transl_dbat0.word[1] ); ++ ++ K_DEF( K_TLBHASH_SR, mmu.pthash_sr ); ++ K_DEF( K_TLBHASH_BASE_EA, mmu.pthash_ea_base ); ++ K_DEF( K_HASH_MASK, mmu.hash_mask ); ++ K_DEF( K_PTHASH_INUSE_PH, mmu.pthash_inuse_bits_ph ); ++ ++ /* fields private to the assembly files */ ++ K_DEF( K_MSR, _bp._msr ); ++ ++ K_DEF( K_DEC_STAMP, _bp.dec_stamp ); ++ K_DEF( K_INT_STAMP, _bp.int_stamp); ++ ++ K_DEF( K_TMP_SCRATCH0, _bp.tmp_scratch[0] ); ++ K_DEF( K_TMP_SCRATCH1, _bp.tmp_scratch[1] ); ++ K_DEF( K_TMP_SCRATCH2, _bp.tmp_scratch[2] ); ++ K_DEF( K_TMP_SCRATCH3, _bp.tmp_scratch[3] ); ++ ++ K_DEF( K_SPLIT_NIP_SEGMENT, _bp.split_nip_segment ); ++ ++ K_DEF( K_SPR_HOOKS, _bp.spr_hooks ); ++ ++ /* private to emulation.S */ ++ K_DEF( K_MSR_SR_TABLE, _bp.msr_sr_table[0] ); ++ ++ /* io_page_t type */ ++ IO_DEF( IOP_MAGIC, magic ); ++ IO_DEF( IOP_MAGIC2, magic2 ); ++ IO_DEF( IOP_MPHYS, mphys ); ++ IO_DEF( IOP_ME_PHYS, me_phys ); ++ IO_DEF( IOP_NEXT, next ); ++ IO_DEF( IOP_USR_DATA, usr_data ); ++ ++ /****** New Low-level assembly implementation ***********/ ++ ++ K_DEF( K_EMULATOR_STACK, _bp.emulator_stack ); ++ K_DEF( K_EMULATOR_TOC, _bp.emulator_toc ); ++ K_DEF( K_EMULATOR_NIP, _bp.emulator_nip ); ++ K_DEF( K_EMULATOR_MSR, _bp.emulator_msr ); ++ K_DEF( K_EMULATOR_SPRG2, _bp.emulator_sprg2 ); ++ K_DEF( K_EMULATOR_SPRG3, _bp.emulator_sprg3 ); ++ K_DEF( K_EMULATOR_KCALL_NIP, _bp.emulator_kcall_nip ); ++ ++ K_DEF( K_EMULATOR_SR, mmu.emulator_sr ); ++ ++#ifdef __darwin__ ++ K_DEF( K_KCALL_ROUTINE, kcall_routine ); ++ K_DEF( K_KCALL_ARG0, kcall_args[0] ); ++ K_DEF( K_KCALL_ARG1, kcall_args[1] ); ++ K_DEF( K_KCALL_ARG2, kcall_args[2] ); ++#endif ++} +--- /dev/null ++++ b/drivers/macintosh/mol/include/asmdbg.h +@@ -0,0 +1,184 @@ ++/* ++ * Creation Date: <2004/01/29 20:12:41 samuel> ++ * Time-stamp: <2004/03/06 13:17:36 samuel> ++ * ++ * ++ * ++ * debug support ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_ASMDBG ++#define _H_ASMDBG ++ ++ ++/************************************************************************/ ++/* Performance Statistics */ ++/************************************************************************/ ++ ++#ifdef PERFORMANCE_INFO ++ define([_bump_ind_], 0) ++ ++#define __BUMP( str ) \ ++ .text 92 ;\ ++debug_str_[]_bump_ind_: ;\ ++ .if (_bump_ind_ >= NUM_ASM_BUMP_CNTRS) ;\ ++ .print "** too many BUMP counters **" ; .fail 1 ;\ ++ .endif ;\ ++ .ascii str "\0" ;\ ++ balign_4 ;\ ++ .text 90 ;\ ++ .long (debug_str_[]_bump_ind_-__start_bumptable) ;\ ++ .text ;\ ++ stw r3,xDEBUG_SCR1(r1) ;\ ++ lwz r3,(K_ASM_BUMP_CNTRS+4*_bump_ind_)(r1) ;\ ++ addi r3,r3,1 ;\ ++ stw r3,(K_ASM_BUMP_CNTRS+4*_bump_ind_)(r1) ;\ ++ lwz r3,xDEBUG_SCR1(r1) ;\ ++ define([_bump_ind_],eval(_bump_ind_+1)) ++ ++ ++ define([_tick_ind_], 0) ++ ++#define __ZERO_TICK_CNT(cntr) \ ++ ifdef([##cntr##_ind_],[],[ \ ++ define([##cntr##_ind_], _tick_ind_) \ ++ define([_tick_ind_], eval(_tick_ind_+1)) \ ++ ]) \ ++ .if (_tick_ind_ > NUM_ASM_TICK_CNTRS) ;\ ++ .print "** too many TICK counters **" ; .fail 1 ;\ ++ .endif ;\ ++ stw r3,xDEBUG_SCR1(r1) ;\ ++ mftb r3 ;\ ++ stw r3,(K_ASM_TICK_STAMPS + 4*cntr##_ind_)(r1) ;\ ++ lwz r3,xDEBUG_SCR1(r1) ++ ++#define __GET_TICK_CNT(cntr, name) \ ++ .text 92 ;\ ++debug_str_[]_bump_ind_: ;\ ++ .if (_bump_ind_ >= NUM_ASM_BUMP_CNTRS) ;\ ++ .print "** too many BUMP counters **" ; .fail 1 ;\ ++ .endif ;\ ++ .ascii name "_ticks\0" ;\ ++ balign_4 ;\ ++ .text 90 ;\ ++ .long (debug_str_[]_bump_ind_-__start_bumptable) ;\ ++ .text ;\ ++ ifdef([##cntr##_ind_],[],[ \ ++ define([##cntr##_ind_], _tick_ind_) \ ++ define([_tick_ind_], eval(_tick_ind_+1)) \ ++ ]) \ ++ .if (_tick_ind_ > NUM_ASM_TICK_CNTRS) ;\ ++ .print "** too many TICK counters **" ; .fail 1 ;\ ++ .endif ;\ ++ stw r3,xDEBUG_SCR1(r1) ;\ ++ mftb r3 ;\ ++ stw r4,xDEBUG_SCR2(r1) ;\ ++ lwz r4,(K_ASM_TICK_STAMPS + 4*cntr##_ind_)(r1) ;\ ++ sub r3,r3,r4 ;\ ++ lwz r4,(K_ASM_BUMP_CNTRS+4*_bump_ind_)(r1) ;\ ++ add r4,r4,r3 ;\ ++ stw r4,(K_ASM_BUMP_CNTRS+4*_bump_ind_)(r1) ;\ ++ lwz r3,xDEBUG_SCR1(r1) ;\ ++ mftb r4 ;\ ++ stw r4,(K_ASM_TICK_STAMPS + 4*cntr##_ind_)(r1) ;\ ++ lwz r4,xDEBUG_SCR2(r1) ;\ ++ define([_bump_ind_],eval(_bump_ind_+1)) ++ ++#endif /* PERFORMANCE_INFO */ ++ ++#ifndef PERFORMANCE_INFO_LIGHT ++#define BUMP(s) __BUMP(s) ++#define ZERO_TICK_CNT(c) __ZERO_TICK_CNT(c) ++#define GET_TICK_CNT(c, name) __GET_TICK_CNT(c,name) ++#else ++#define BUMP(s) ++#define ZERO_TICK_CNT(c) ++#define GET_TICK_CNT(c, name) ++#endif ++ ++#ifndef __BUMP ++#define __BUMP(str) ++#define __ZERO_TICK_CNT(cntr) ++#define __GET_TICK_CNT(cntr, name) ++#endif ++ ++#ifdef PERF_MONITOR ++MACRO(PERF_MONITOR_GET, [ ++ stw r5,xDEBUG_SCR1(r1) ++ mfspr r5,S_PMC2 ++ stw r4,xDEBUG_SCR2(r1) ++ mfmsr r4 ++ ori r4,r4,MSR_PE ++ mtmsr r4 ++ stw r5,xDEBUG0(r1) ++ li r5,0 ++ mtspr S_PMC2,r5 ++ lwz r4,xDEBUG_SCR2(r1) ++ lwz r5,xDEBUG_SCR1(r1) ++]) ++MACRO(PERF_MONITOR_SETUP, [scr], [ ++ LOADI _scr,BIT(2) | BIT(3) | BIT(31) // count in SV-mode if PM is zero. ++ mtspr S_MMCR0,_scr ++ li _scr,0 ++ mtspr S_MMCR1,_scr ++ li _scr,0 ++ mtspr S_PMC2,_scr ++]) ++#else /* PERF_MONITOR */ ++#define PERF_MONITOR_GET ++MACRO(PERF_MONITOR_SETUP, [scr], []) ++#endif ++ ++ ++/************************************************************************/ ++/* debug */ ++/************************************************************************/ ++ ++MACRO(STOP_EMULATION, [val], [ ++ stw r3,xDEBUG_SCR1(r1) ++ li r3,_val ++ stw r3,xKERNEL_DBG_STOP(r1) ++ li r3,1 ++ stw r3,xINTERRUPT(r1) ++ lwz r3,xDEBUG_SCR1(r1) ++]) ++ ++MACRO(DEBUG_TRACE, [num, dummy], [ ++ stw r3,xDEBUG_SCR1(r1) ++ lwz r3,xDEBUG_TRACE(r1) ++ addi r3,r3,1 ++ stw r3,xDEBUG_TRACE(r1) ++ stw r3,(xDEBUG0+4*_num)(r1) ++ lwz r3,xDEBUG_SCR1(r1) ++]) ++ ++MACRO(TRACE_VAL, [val, dummy], [ ++#if DBG_TRACE ++ stw r30,xDEBUG_SCR1(r1) ++ stw r29,xDEBUG_SCR2(r1) ++ lwz r30,xDEBUG_TRACE(r1) ++ rlwinm r30,r30,0,24,31 // 256 entries ++ rlwinm r30,r30,2,22,29 ++ addi r30,r30,xDBG_TRACE_SPACE ++ lis r29,HA(_val) ++ addi r29,r29,LO(_val) ++ stwx r29,r30,r1 ++ lwz r30,xDEBUG_TRACE(r1) ++ addi r30,r30,1 ++ rlwinm r30,r30,0,24,31 // 256 entries ++ stw r30,xDEBUG_TRACE(r1) ++ lwz r29,xDEBUG_SCR2(r1) ++ lwz r30,xDEBUG_SCR1(r1) ++#endif ++]) ++#define TRACE( a,b ) TRACE_VAL a,b ++ ++ ++#endif /* _H_ASMDBG */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/asmdefs.h +@@ -0,0 +1,397 @@ ++/* -*- asm -*- ++ * ++ * Creation Date: <2001/02/03 19:38:07 samuel> ++ * Time-stamp: <2004/02/22 15:36:20 samuel> ++ * ++ * ++ * ++ * Common assembly definitions ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_ASMDEFS ++#define _H_ASMDEFS ++ ++#include "asm.m4" ++ ++#ifndef __ASSEMBLY__ ++#error This file is only to be included from assembler code! ++#endif ++ ++ ++/************************************************************************/ ++/* High/low halfword compatibility macros */ ++/************************************************************************/ ++ ++#ifdef __linux__ ++#define ha16( v ) (v)##@ha ++#define hi16( v ) (v)##@h ++#define lo16( v ) (v)##@l ++#endif ++#define HA(v) ha16(v) ++#define HI(v) hi16(v) ++#define LO(v) lo16(v) ++ ++/************************************************************************/ ++/* Stack Frame */ ++/************************************************************************/ ++ ++#ifdef __linux__ ++#define STACK_LR_OFFSET 4 ++#endif ++ ++#ifdef __darwin__ ++#define STACK_LR_OFFSET 8 /* 4 is the CR offset */ ++#endif ++ ++/************************************************************************/ ++/* Register name prefix */ ++/************************************************************************/ ++ ++#ifdef __linux__ ++define([rPREFIX], []) ++define([fPREFIX], []) ++define([srPREFIX], []) ++#else ++define([rPREFIX], [r]) ++define([fPREFIX], [f]) ++define([srPREFIX], [sr]) ++/* frN -> fN */ ++mFORLOOP([i],0,31,[define(fr[]i,f[]i)]) ++#endif ++ ++/************************************************************************/ ++/* Macros and definitions */ ++/************************************************************************/ ++ ++#ifdef __darwin__ ++#define balign_4 .align 2,0 ++#define balign_8 .align 3,0 ++#define balign_16 .align 4,0 ++#define balign_32 .align 5,0 ++#endif ++ ++#ifdef __linux__ ++#define balign_4 .balign 4,0 ++#define balign_8 .balign 8,0 ++#define balign_16 .balign 16,0 ++#define balign_32 .balign 32,0 ++#endif ++ ++MACRO(LOADVAR, [dreg, variable], [ ++ lis _dreg,HA(_variable) ++ lwz _dreg,LO(_variable)(_dreg) ++]) ++ ++MACRO(LOADI, [dreg, addr], [ ++ lis _dreg,HA(_addr) ++ addi _dreg,_dreg,LO(_addr) ++]) ++ ++MACRO(LOAD_GPR_RANGE, [start, endx, offs, base], [ ++ mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) ++ lwz rPREFIX[]i,_offs+i[]*4(_base) ++ .endif ++])]) ++ ++MACRO(STORE_GPR_RANGE, [start, endx, offs, base], [ ++ mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) ++ stw rPREFIX[]i,_offs+i[]*4(_base) ++ .endif ++])]) ++ ++MACRO(LOAD_FPR_RANGE, [start, endx, offs, base], [ ++ mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) ++ lfd fPREFIX[]i,_offs+i[]*8(_base) ++ .endif ++])]) ++ ++MACRO(STORE_FPR_RANGE, [start, endx, offs, base], [ ++ mFORLOOP([i],0,31,[ .if (i >= _start) & (i <= _endx) ++ stfd fPREFIX[]i,_offs+i[]*8(_base) ++ .endif ++])]) ++ ++/************************************************************************/ ++/* FPU load/save macros */ ++/************************************************************************/ ++ ++ // The FPU macros are used both in the kernel and in ++ // mainloop_asm.h. ++ ++MACRO(xFPR_LOAD_RANGE, [from, to, mbase], [ ++ LOAD_FPR_RANGE _from,_to,xFPR_BASE,_mbase ++]) ++MACRO(xFPR_SAVE_RANGE, [from, to, mbase], [ ++ STORE_FPR_RANGE _from,_to,xFPR_BASE,_mbase ++]) ++ // The low half of the fpu is fr0-fr12. I.e. the FPU registers ++ // that might be overwritten when a function call is taken ++ // (fr13 and fpscr are treated specially). ++ ++MACRO(xLOAD_LOW_FPU, [mbase], [ ++ xFPR_LOAD_RANGE 0,12,_mbase ++]) ++ ++MACRO(xLOAD_TOPHALF_FPU, [mbase], [ ++ xFPR_LOAD_RANGE 14,31,_mbase ++]) ++MACRO(xLOAD_FULL_FPU, [mbase], [ ++ xLOAD_LOW_FPU _mbase ++ xLOAD_TOPHALF_FPU _mbase ++]) ++ ++MACRO(xSAVE_LOW_FPU, [mbase], [ ++ xFPR_SAVE_RANGE 0,12,_mbase ++]) ++MACRO(xSAVE_TOPHALF_FPU, [mbase], [ ++ xFPR_SAVE_RANGE 14,31,_mbase ++]) ++MACRO(xSAVE_FULL_FPU, [mbase], [ ++ xSAVE_LOW_FPU _mbase ++ xSAVE_TOPHALF_FPU _mbase ++]) ++ ++ ++/************************************************************************/ ++/* GPR load/save macros */ ++/************************************************************************/ ++ ++MACRO(xGPR_SAVE_RANGE, [from, to, mbase], [ ++ STORE_GPR_RANGE _from, _to, xGPR0, _mbase ++]) ++ ++MACRO(xGPR_LOAD_RANGE, [from, to, mbase], [ ++ LOAD_GPR_RANGE _from, _to, xGPR0, _mbase ++]) ++ ++ ++/************************************************************************/ ++/* AltiVec */ ++/************************************************************************/ ++ ++#ifdef __linux__ ++ ++define(vPREFIX,[]) ++ ++#ifndef HAVE_ALTIVEC ++#define VEC_OPCODE( op1,op2,A,B,C ) \ ++ .long (((op1) << (32-6)) | (op2) | ((A) << (32-11)) | ((B) << (32-16)) | ((C) << (32-21))) ; ++ ++#define __stvx( vS,rA,rB ) VEC_OPCODE( 31,0x1ce,vS,rA,rB ) ++#define __lvx( vD,rA,rB ) VEC_OPCODE( 31,0xce, vD,rA,rB ) ++#define __mfvscr( vD ) VEC_OPCODE( 4,1540,vD,0,0 ) ++#define __mtvscr( vB ) VEC_OPCODE( 4,1604,0,0,vB ) ++#define __stvewx( vS,rA,rB ) VEC_OPCODE( 31,(199<<1), vS,rA,rB ) ++ ++mFORLOOP([i],0,31,[define(v[]i,[]i)]) ++MACRO(stvx, [vS,rA,rB], [ __stvx( _vS,_rA,_rB ) ; ]) ++MACRO(lvx, [vD,rA,rB], [ __lvx( _vD,_rA,_rB ) ; ]) ++MACRO(mfvscr, [vD], [ __mfvscr( _vD ) ; ]) ++MACRO(mtvscr, [vB], [ __mtvscr( _vB ) ; ]) ++MACRO(stvewx, [vS,rA,rB], [ __stvewx( _vS,_rA,_rB ) ; ]) ++#endif ++#else /* __linux__ */ ++ ++define(vPREFIX,[v]) ++ ++#endif /* __linux__ */ ++ ++ ++// NOTE: Writing to VSCR won't cause exceptions (this ++// is different compared to FPSCR). ++ ++MACRO(xVEC_SAVE, [mbase, scr], [ ++ addi _scr,_mbase,xVEC_BASE ++ mFORLOOP([i],0,31,[ ++ stvx vPREFIX[]i,0,_scr ++ addi _scr,_scr,16 ++ ]) ++ addi _scr,_mbase,xVSCR-12 ++ mfvscr v0 ++ stvx v0,0,_scr ++ addi _scr,_mbase,xVEC0 ++ lvx v0,0,_scr ++ mfspr _scr,S_VRSAVE ++ stw _scr,xVRSAVE(_mbase) ++]) ++ ++MACRO(xVEC_LOAD, [mbase, scr], [ ++ addi _scr,_mbase,xVSCR-12 ++ lvx v0,0,_scr ++ mtvscr v0 ++ addi _scr,_mbase,xVEC_BASE ++ mFORLOOP([i],0,31,[ ++ lvx vPREFIX[]i,0,_scr ++ addi _scr,_scr,16 ++ ]) ++ lwz _scr,xVRSAVE(_mbase) ++ mtspr S_VRSAVE,_scr ++]) ++ ++/************************************************************************/ ++/* Instructions */ ++/************************************************************************/ ++ ++#ifdef __darwin__ ++MACRO(mtsprg0, [reg], [mtspr SPRG0,_reg] ) ++MACRO(mtsprg1, [reg], [mtspr SPRG1,_reg] ) ++MACRO(mtsprg2, [reg], [mtspr SPRG2,_reg] ) ++MACRO(mtsprg3, [reg], [mtspr SPRG3,_reg] ) ++MACRO(mfsprg0, [reg], [mfspr _reg,SPRG0] ) ++MACRO(mfsprg1, [reg], [mfspr _reg,SPRG1] ) ++MACRO(mfsprg2, [reg], [mfspr _reg,SPRG2] ) ++MACRO(mfsprg3, [reg], [mfspr _reg,SPRG3] ) ++#endif ++ ++/************************************************************************/ ++/* Register names */ ++/************************************************************************/ ++ ++#define cr0_lt 0 ++#define cr0_gt 1 ++#define cr0_eq 2 ++#define cr0_so 3 ++ ++#define cr1_lt 4 ++#define cr1_gt 5 ++#define cr1_eq 6 ++#define cr1_so 7 ++ ++#define cr2_lt 8 ++#define cr2_gt 9 ++#define cr2_eq 10 ++#define cr2_so 11 ++ ++#define cr3_lt 12 ++#define cr3_gt 13 ++#define cr3_eq 14 ++#define cr3_so 15 ++ ++#ifdef __darwin__ ++/* IMPORTANT: we may *not* define crN on darwin; If we do, the ++ * assembler will generate bogus code. For instance, ++ * bne cr1,1f is not equivalent to bne 1,1f but to ++ * bne 4,1f... ++ */ ++#define lt 0 /* Less than */ ++#define gt 1 /* Greater than */ ++#define eq 2 /* Equal */ ++#define so 3 /* Summary Overflow */ ++#define un 3 /* Unordered (after floating point) */ ++#endif ++ ++/* FPU register names (to be used as macro arguments) */ ++#define FR0 0 ++#define FR1 1 ++#define FR2 2 ++#define FR3 3 ++#define FR4 4 ++#define FR5 5 ++#define FR6 6 ++#define FR7 7 ++#define FR8 8 ++#define FR9 9 ++#define FR10 10 ++#define FR11 11 ++#define FR12 12 ++#define FR13 13 ++#define FR14 14 ++#define FR15 15 ++#define FR16 16 ++#define FR17 17 ++#define FR18 18 ++#define FR19 19 ++#define FR20 20 ++#define FR21 21 ++#define FR22 22 ++#define FR23 23 ++#define FR24 24 ++#define FR25 25 ++#define FR26 26 ++#define FR27 27 ++#define FR28 28 ++#define FR29 29 ++#define FR30 30 ++#define FR31 31 ++ ++/* GPR register names (to be used as macro arguments) */ ++#define R0 0 ++#define R1 1 ++#define R2 2 ++#define R3 3 ++#define R4 4 ++#define R5 5 ++#define R6 6 ++#define R7 7 ++#define R8 8 ++#define R9 9 ++#define R10 10 ++#define R11 11 ++#define R12 12 ++#define R13 13 ++#define R14 14 ++#define R15 15 ++#define R16 16 ++#define R17 17 ++#define R18 18 ++#define R19 19 ++#define R20 20 ++#define R21 21 ++#define R22 22 ++#define R23 23 ++#define R24 24 ++#define R25 25 ++#define R26 26 ++#define R27 27 ++#define R28 28 ++#define R29 29 ++#define R30 30 ++#define R31 31 ++ ++#ifndef __darwin__ ++ ++/* GPR register names, rN -> N, frN -> N, vN -> N */ ++mFORLOOP([i],0,31,[define(r[]i,[]i)]) ++mFORLOOP([i],0,31,[define(fr[]i,[]i)]) ++mFORLOOP([i],0,31,[define(v[]i,[]i)]) ++ ++#endif /* __darwin__ */ ++ ++ ++/************************************************************************/ ++/* useful macros */ ++/************************************************************************/ ++ ++MACRO(ori_, [reg1, reg2, value], [ ++ .if (_value & 0xffff) ++ ori _reg1, _reg2, (_value) & 0xffff ++ .endif ++ .if (_value & ~0xffff) ++ oris _reg1, _reg2, (_value) >> 16 ++ .endif ++]) ++ ++/************************************************************************/ ++/* MISC */ ++/************************************************************************/ ++ ++#ifdef __linux__ ++#define GLOBL( name ) .globl name ; name ++#define EXTERN( name ) name ++#else ++/* an underscore is needed on Darwin */ ++#define GLOBL( name ) .globl _##name ; name: ; _##name ++#define EXTERN( name ) _##name ++#endif ++ ++#define BIT(n) (1<<(31-(n))) ++ ++#endif /* _H_ASMDEFS */ ++ +--- /dev/null ++++ b/drivers/macintosh/mol/include/asmfuncs.h +@@ -0,0 +1,80 @@ ++/* ++ * Creation Date: <1999/09/26 01:02:58 samuel> ++ * Time-stamp: <2003/07/27 19:20:24 samuel> ++ * ++ * ++ * ++ * Exports from ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_ASMFUNCS ++#define _H_ASMFUNCS ++ ++#include "kernel_vars.h" ++#include "tlbie.h" ++ ++ ++/* globl variable defined in actions.c */ ++extern int reloc_virt_offs; ++#define reloc_ptr( v ) ((ulong)(v) + (ulong)reloc_virt_offs) ++ ++ ++/* The code in base.o (all low-level assembly) are copied to a physically ++ * continuous memory area. The following inline functions maps function calls ++ * to the relocated area. ++ */ ++ ++static inline void msr_altered( kernel_vars_t *kv ) { ++ typedef void ftype( kernel_vars_t * ); ++ extern ftype r__msr_altered; ++ (*(ftype*)reloc_ptr( r__msr_altered ))( kv ); ++} ++ ++static inline void invalidate_splitmode_sr( kernel_vars_t *kv ) { ++ typedef void ftype( kernel_vars_t *); ++ extern ftype r__invalidate_splitmode_sr; ++ (*(ftype*)reloc_ptr( r__invalidate_splitmode_sr ))( kv ); ++} ++ ++static inline void initialize_spr_table( kernel_vars_t *kv ) { ++ typedef void ftype( kernel_vars_t *); ++ extern ftype r__initialize_spr_table; ++ (*(ftype*)reloc_ptr( r__initialize_spr_table ))( kv ); ++} ++ ++ ++/************************************************************************/ ++/* misc inlines */ ++/************************************************************************/ ++ ++#define _sync() ({ asm volatile("sync ;\n isync" : : ); }) ++ ++static inline ulong _get_sdr1( void ) { ++ ulong sdr1; ++ asm volatile("mfsdr1 %0" : "=r" (sdr1) : ); ++ return sdr1; ++} ++static inline void _set_sdr1( ulong sdr1 ) { ++ asm volatile("mtsdr1 %0" : : "r" (sdr1) ); ++} ++ ++static inline int cpu_is_601( void ) { ++ ulong pvr; ++ asm volatile("mfpvr %0" : "=r" (pvr) : ); ++ return (pvr>>16)==1; ++} ++ ++static inline int cpu_is_603( void ) { ++ ulong pvr; ++ asm volatile("mfpvr %0" : "=r" (pvr) : ); ++ pvr = pvr >> 16; ++ return pvr==3 || pvr==6 || pvr==7; /* 603, 603e, 603ev */ ++} ++#endif /* _H_ASMFUNCS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/atomic.h +@@ -0,0 +1,26 @@ ++/* ++ * Creation Date: <2004/01/25 17:00:12 samuel> ++ * Time-stamp: <2004/01/29 22:32:30 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_ATOMIC ++#define _H_ATOMIC ++ ++#define mol_atomic_t atomic_t ++#define atomic_inc_return_mol(x) atomic_inc_return(x) ++#define atomic_inc_mol(x) atomic_inc(x) ++#define atomic_dec_mol(x) atomic_dec(x) ++#define atomic_read_mol(x) atomic_read(x) ++ ++#endif /* _H_ATOMIC */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/config.h +@@ -0,0 +1,90 @@ ++/* config.h. Generated from config.h.in by configure. */ ++/* config.h.in. Generated from configure.in by autoheader. */ ++ ++/* Define if _syscall macro is borken */ ++#define BROKEN_SYSCALL 1 ++ ++/* Defined if ALSA support is available */ ++#define HAVE_ALSA 1 ++ ++/* Define if clearenv is available */ ++#define HAVE_CLEARENV 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_GETOPT_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_INTTYPES_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_MEMORY_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_OBSTACK_H 1 ++ ++/* Define if libpng support is to be included */ ++#define HAVE_PNG 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_POLL_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STDINT_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STDLIB_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STRINGS_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STRING_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_SYS_STAT_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_SYS_TYPES_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_UNISTD_H 1 ++ ++/* Define if X11 is available */ ++#define HAVE_X11 1 ++ ++/* Define if XDGA support is to be included */ ++#define HAVE_XDGA 1 ++ ++/* Defined for the MOL user binary */ ++#define MOL_PROPER 1 ++ ++/* Define if off_t is known to be 64-bit */ ++#define OFF_T_IS_64 1 ++ ++/* Define to the address where bug reports for this package should be sent. */ ++#define PACKAGE_BUGREPORT "" ++ ++/* Define to the full name of this package. */ ++#define PACKAGE_NAME "" ++ ++/* Define to the full name and version of this package. */ ++#define PACKAGE_STRING "" ++ ++/* Define to the one symbol short name of this package. */ ++#define PACKAGE_TARNAME "" ++ ++/* Define to the version of this package. */ ++#define PACKAGE_VERSION "" ++ ++/* Define to 1 if you have the ANSI C header files. */ ++#define STDC_HEADERS 1 ++ ++/* Define if uc_context has gregs field */ ++/* #undef UCCONTEXT_HAS_GREGS */ ++ ++/* Define to 1 if the X Window System is missing or not being used. */ ++/* #undef X_DISPLAY_MISSING */ ++ ++/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a ++ `char[]'. */ ++#define YYTEXT_POINTER 1 +--- /dev/null ++++ b/drivers/macintosh/mol/include/constants.h +@@ -0,0 +1,36 @@ ++/* ++ * Creation Date: <2001/02/11 18:19:42 samuel> ++ * Time-stamp: <2003/07/27 18:58:35 samuel> ++ * ++ * ++ * ++ * Constants used both in the kernel module and in the emulator ++ * ++ * Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_CONSTANTS ++#define _H_CONSTANTS ++ ++/* flags for _breakpoint_flags() */ ++#define BREAK_RFI 1 /* break at next rfi */ ++#define BREAK_SINGLE_STEP 2 /* singlestep */ ++#define BREAK_EA_PAGE 4 /* break when mdbg_break_ea is mapped */ ++#define BREAK_USER 8 /* break when MSR_PR is set */ ++#define BREAK_SINGLE_STEP_CONT 16 /* single step (but don't continue running) */ ++ ++/* action for _tune_spr() */ ++#define kTuneSPR_Illegal 1 /* SPR is illegal */ ++#define kTuneSPR_Privileged 2 /* SPR is privileged */ ++#define kTuneSPR_Unprivileged 3 /* SPR is unprivileged */ ++#define kTuneSPR_ReadWrite 4 /* SPR is read-write */ ++#define kTuneSPR_ReadOnly 5 /* SPR is read-only */ ++ ++#endif /* _H_CONSTANTS */ ++ ++ +--- /dev/null ++++ b/drivers/macintosh/mol/include/context.h +@@ -0,0 +1,62 @@ ++/* ++ * Creation Date: <2004/01/25 17:48:51 samuel> ++ * Time-stamp: <2004/01/25 22:12:13 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_CONTEXT ++#define _H_CONTEXT ++ ++#define CTX_MASK 0xfffff /* VSID_MASK >> 4 */ ++ ++/* ++ * Three types of contexts are used: ++ * ++ * VSIDs (24 bit, loaded into the CPU register) ++ * mol_contexts (number between FIRST_ and LAST_MOL_CONTEXT) ++ * arch_contexts (context number used by the kernel) ++ * ++ * The relation between them is ++ * ++ * mol_context = (os_context << 4) + segment# ++ * VSID_context = MUNGE_CONTEXT(mol_context>>4) + ESID_ADD * (mol_context & 0xf) ++ */ ++ ++/* ++ * The new MM implementation (about 2.4.14 (?)) uses the following algorithm ++ * ++ * VSID = (((context * 897) << 4) + ((va>>28) * 0x111)) & 0xffffff ++ * ++ * Only context 0..32767 are used. We can use context 32768..0xfffff. ++ * The old MM implementation used ++ * ++ * VSID = (((context * 897) << 4) + (va>>28)) & 0xffffff ++ */ ++ ++#define MUNGE_ADD_NEXT 897 ++#define MUNGE_MUL_INVERSE 2899073 /* Multiplicative inverse of 897 (modulo VSID_MASK+1) */ ++#define MUNGE_ESID_ADD 0x111 ++#define MUNGE_CONTEXT(c) (((c) * (MUNGE_ADD_NEXT * 16)) & (CTX_MASK <<4)) ++ ++/* mol_contexts == linux_context * 16 + esid */ ++#define PER_SESSION_CONTEXTS 0x10000 /* more than we will need (10^6) */ ++#define FIRST_MOL_CONTEXT(sess) ((CTX_MASK - PER_SESSION_CONTEXTS*((sess)+1)) << 4) ++#define LAST_MOL_CONTEXT(sess) (((CTX_MASK - PER_SESSION_CONTEXTS*(sess)) << 4) | 0xf) ++ ++ ++#if FIRST_MOL_CONTEXT(MAX_NUM_SESSIONS-1) < (32768 << 4) ++#error "Too many MOL contexts..." ++#endif ++ ++ ++#endif /* _H_CONTEXT */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/dbg.h +@@ -0,0 +1,31 @@ ++/* ++ * Creation Date: <2004/04/10 22:14:43 samuel> ++ * Time-stamp: <2004/04/10 22:26:24 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ */ ++ ++#ifndef _H_DBG ++#define _H_DBG ++ ++#ifdef CONFIG_MOL_HOSTED ++ ++#ifdef printk ++#undef printk ++#endif ++ ++#define printk printm ++extern int printm( const char *fmt, ... ); ++extern void debugger( int n ); ++ ++#endif /* CONFIG_MOL_HOSTED */ ++ ++#endif /* _H_DBG */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/debugger.h +@@ -0,0 +1,96 @@ ++/* ++ * Creation Date: <1999/02/22 22:46:22 samuel> ++ * Time-stamp: <2003/07/27 14:42:05 samuel> ++ * ++ * ++ * ++ * World interface of the debugger ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_DEBUGGER ++#define _H_DEBUGGER ++ ++#ifdef CONFIG_DEBUGGER ++extern void debugger_init( void ); ++extern void debugger_cleanup( void ); ++extern int debugger_enabled( void ); ++extern int debugger_attached( void ); ++#else ++static inline int debugger_enabled( void ) { return 0; } ++static inline int debugger_attached( void ) { return 0; } ++static inline void debugger_init( void ) {} ++static inline void debugger_cleanup( void ) {} ++#endif ++ ++/*******************************************/ ++/* montior.c / nub.c */ ++/*******************************************/ ++ ++extern void refresh_debugger_window( void ); ++extern void refresh_debugger( void ); ++extern void redraw_inst_win( void ); ++extern int debugger_in_68k_mode( void ); ++extern void debugger_nub_poll( void ); ++ ++/* debug actions */ ++enum{ ++ kDbgNOP=0, kDbgGo, kDbgGoRFI, kDbgStep, kDbgExit, kDbgStop, kDbgGoUser ++}; ++ ++ ++/*******************************************/ ++/* cmdline.c / nub.c */ ++/*******************************************/ ++ ++/* put functions used exclusively in debugger mode in the dbg section */ ++#ifdef __linux__ ++#ifdef CONFIG_DEBUGGER ++#define __dbg __attribute__ ((__section__ (".moldbg"))) ++#define __dcmd __dbg ++#else ++#define __dbg __attribute__ ((__section__ (".moldbg"))) ++#define __dcmd inline __attribute__ ((__section__ (".moldbg"))) ++#endif ++#else ++#define __dbg ++#define __dcmd inline ++#endif ++ ++typedef struct { ++ const char *name; ++ int (*func)( int argc, char **argv ); ++ const char *help; ++} dbg_cmd_t; ++ ++typedef int (*dbg_cmd_fp)( int argc, char **argv ); ++ ++#ifdef CONFIG_DEBUGGER ++extern void add_cmd( const char *cmdname, const char *help, ++ int dummy, dbg_cmd_fp func ); ++extern void add_dbg_cmds( dbg_cmd_t *table, int tablesize ); ++#else ++#define add_cmd( a,b,c,d ) do {} while(0) ++static inline void add_dbg_cmds( dbg_cmd_t *table, int tablesize ) {} ++#endif ++ ++/* for debugging */ ++#define HARD_BREAKPOINT \ ++ ({ printm("Hardcoded breakpoint in '"__FILE__"'\n"); stop_emulation(); }) ++ ++ ++/*******************************************/ ++/* mmu_cmds.c */ ++/*******************************************/ ++ ++extern int __dbg get_inst_context( void ); ++extern int __dbg get_data_context( void ); ++extern int __dbg ea_to_lvptr( ulong ea, int context, char **lvptr, int data_access ); ++ ++#endif /* _H_DEBUGGER */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/emu.h +@@ -0,0 +1,29 @@ ++/* ++ * Creation Date: <2003/01/26 00:45:55 samuel> ++ * Time-stamp: <2003/01/27 01:26:25 samuel> ++ * ++ * ++ * ++ * Emulation of some assembly functions ++ * ++ * Copyright (C) 1998, 2000, 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_EMU ++#define _H_EMU ++ ++#include "mmu.h" ++ ++extern int do_mtsdr1( kernel_vars_t *kv, ulong value ); ++extern int do_mtbat( kernel_vars_t *kv, int sprnum, ulong value, int force ); ++ ++extern int alloc_emuaccel_slot( kernel_vars_t *kv, int inst_flags, int param, int inst_addr ); ++extern int mapin_emuaccel_page( kernel_vars_t *kv, int mphys ); ++ ++ ++#endif /* _H_EMU */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/emuaccel_sh.h +@@ -0,0 +1,41 @@ ++/* ++ * Creation Date: <2003/01/25 14:57:36 samuel> ++ * Time-stamp: <2003/01/27 23:11:29 samuel> ++ * ++ * ++ * ++ * Acceleration of the emulation of certain privileged instructions ++ * ++ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_EMUACCEL ++#define _H_EMUACCEL ++ ++/* OSI_AllocInstAccelSlot( EMULATE_xxx + source_reg, NIP ) */ ++ ++#define EMUACCEL_MAPIN_PAGE 0 ++#define EMUACCEL_MTSRR0 (1 << 5) ++#define EMUACCEL_MTSRR1 (2 << 5) ++#define EMUACCEL_MTSPRG0 (3 << 5) ++#define EMUACCEL_MTSPRG1 (4 << 5) ++#define EMUACCEL_MTSPRG2 (5 << 5) ++#define EMUACCEL_MTSPRG3 (6 << 5) ++#define EMUACCEL_MTMSR (7 << 5) ++#define EMUACCEL_RFI (8 << 5) ++#define EMUACCEL_UPDATE_DEC (9 << 5) /* update xDEC */ ++#define EMUACCEL_MTSR ((10 << 5) | EMUACCEL_HAS_PARAM) ++#define EMUACCEL_NOP (11 << 5) ++#define EMUACCEL_MTHID0 (12 << 5) ++ ++#define EMUACCEL_HAS_PARAM (1 << 10) ++#define EMUACCEL_INST_MASK 0xffe0 ++#define EMUACCEL_DESTREG_MASK 0x1f ++ ++ ++#endif /* _H_EMUACCEL */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/extralib.h +@@ -0,0 +1,70 @@ ++/* ++ * Creation Date: <1997/07/02 19:52:18 samuel> ++ * Time-stamp: <2004/04/03 18:29:26 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_EXTRALIB ++#define _H_EXTRALIB ++ ++#define CLEAR( x ) memset( &x, 0, sizeof(x)) ++ ++/* in extralib.h */ ++extern int ilog2( int val ); ++ ++extern char *num_to_string( ulong num ); ++extern int is_number_str( char *str ); ++extern ulong string_to_ulong( char * ); ++extern ulong hexbin( int num ); ++ ++extern char *strncpy0( char *dest, const char *str, size_t n ); ++extern char *strncat0( char *dest, const char *str, size_t n ); ++extern char *strncat3( char *dest, const char *s1, const char *s2, size_t n ); ++extern char *strnpad( char *dest, const char *s1, size_t n ); ++ ++struct iovec; ++extern int memcpy_tovec( const struct iovec *vec, size_t nvec, const char *src, unsigned int len ); ++extern int memcpy_fromvec( char *dst, const struct iovec *vec, size_t nvec, unsigned int len ); ++extern int iovec_getbyte( int offs, const struct iovec *vec, size_t nvec ); ++extern int iovec_skip( int skip, struct iovec *vec, size_t nvec ); ++ ++extern void open_logfile( const char *filename ); ++extern void close_logfile( void ); ++ ++#define __printf_format __attribute__ ((format (printf, 1, 2))) ++extern int printm( const char *fmt,...) __printf_format; ++extern int aprint( const char *fmt,... ) __printf_format; ++extern void perrorm(const char *fmt,... ) __printf_format; ++extern void fatal(const char *fmt,... ) __printf_format __attribute__((noreturn)); ++#define fatal_err(fmt, args...) \ ++ do { printm("Fatal error: "); perrorm(fmt, ## args ); exit(1); } while(0) ++extern void fail_nil( void *p ); ++extern void set_print_hook( int (*hook)(char *buf) ); ++extern void set_print_guard( void (*hook)(void) ); ++ ++extern int script_exec( char *name, char *arg1, char *arg2 ); ++ ++/* in unicode.c */ ++extern int asc2uni( unsigned char *ustr, const char *astr, int maxlen ); ++extern int uni2asc( char *astr, const unsigned char *ustr, int ustrlen, int maxlen ); ++ ++/* in backtrace.c */ ++extern void print_btrace_sym( ulong addr, const char *sym_filename ); ++ ++/* color output support */ ++#define C_GREEN "\33[1;32m" ++#define C_YELLOW "\33[1;33m" ++#define C_NORMAL "\33[0;39m" ++#define C_RED "\33[1;31m" ++ ++#endif /* _H_EXTRALIB */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/hash.h +@@ -0,0 +1,36 @@ ++/* ++ * Creation Date: <2004/02/14 11:45:23 samuel> ++ * Time-stamp: <2004/02/21 21:24:46 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_HASH ++#define _H_HASH ++ ++typedef struct { ++ ulong sdr1; /* sdr1 used by MOL */ ++ ++ ulong pteg_mask; /* pteg offset mask (e.g. 0xffc0) */ ++ ulong pte_mask; /* pte offset mask (e.g. 0xfff8) */ ++ ++ ulong *base; /* kernel mapping of hash */ ++ ulong physbase; /* physical address of hash */ ++} hash_info_t; ++ ++extern hash_info_t ptehash; ++ ++extern int init_hash( void ); ++extern void cleanup_hash( void ); ++ ++ ++#endif /* _H_HASH */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/kernel_vars.h +@@ -0,0 +1,225 @@ ++/* ++ * Creation Date: <97/07/14 15:53:06 samuel> ++ * Time-stamp: <2004/02/21 21:37:37 samuel> ++ * ++ * ++ * ++ * Variables used by the kernel ++ * ++ * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef H_KERNEL_VARS ++#define H_KERNEL_VARS ++ ++#define MAX_NUM_SESSIONS 8 ++ ++#include "mac_registers.h" ++ ++#ifdef PERFORMANCE_INFO ++#define NUM_ASM_BUMP_CNTRS 64 ++#define NUM_ASM_TICK_CNTRS 6 ++#endif ++ ++#ifndef __ASSEMBLY__ ++#include "mmu_mappings.h" ++#include "skiplist.h" ++ ++#ifndef DUMPVARS ++#include "alloc.h" ++#include "locks.h" ++#include "atomic.h" ++#else ++typedef int mol_mutex_t; ++typedef int mol_atomic_t; ++#endif ++ ++typedef struct { ++ ulong word[2]; /* upper, lower */ ++} ppc_bat_t; ++ ++typedef struct mac_bat { ++ int valid; /* record in use */ ++ ulong base; ++ ulong mbase; ++ ulong size; ++ ++ ulong wimg:4; /* WIMG-bits */ ++ ulong vs:1; /* valid supervisor mode */ ++ ulong vp:1; /* valid user mode */ ++ ulong ks:1; /* key superuser */ ++ ulong ku:1; /* key user */ ++ ulong pp:2; /* page protection */ ++ ++ /* possibly we should track inserted PTEs here... */ ++} mac_bat_t; ++ ++typedef struct { ++ struct vsid_ent *vsid[16]; /* entries might be NULL */ ++ struct vsid_ent *unmapped_vsid[16]; /* entries might be NULL, linux_vsid_sv used */ ++ ++ ulong emulator_sr[16]; /* segment registers used by the userspace process */ ++ ++ ulong user_sr[16]; /* segment registers for MSR=user */ ++ ulong sv_sr[16]; /* segment registers for MSR=sv */ ++ ulong unmapped_sr[16]; /* segment registers for unmapped mode */ ++ ulong split_sr[16]; /* segment registers used in split mode */ ++ ++ ulong cur_sr_base; /* (physical) pointer to user_sr or sv_sr */ ++ ulong sr_inst; /* (physical) pointer to us user_sr or sv_sr */ ++ ulong sr_data; /* (physical) pointer to us user_sr or sv_sr */ ++ ++ ulong illegal_sr; /* used for the lazy segment register impl. */ ++ ++ ppc_bat_t split_dbat0; /* loaded to DBAT0 (used in splitmode) */ ++ ppc_bat_t transl_dbat0; /* DBAT0 mapping the framebuffer */ ++ ++ ulong emulator_context; /* context of emulator (equals VSID >> 4) in Linux */ ++ ++ ulong userspace_ram_base; /* userspace RAM base */ ++ size_t ram_size; ++ ++ ulong bat_hack_count; /* HACK to speed up MacOS 9.1 */ ++ mac_bat_t bats[8]; /* 4 IBAT + 4 DBAT */ ++ ++#ifdef EMULATE_603 ++ ulong ptes_d_ea_603[64]; /* EA4-EA19 of dPTE */ ++ mPTE_t ptes_d_603[64]; /* Data on-chip PTEs (603-emulation) */ ++ ulong ptes_i_ea_603[64]; /* EA4-EA19 of iPTE */ ++ mPTE_t ptes_i_603[64]; /* Instruction on-chip PTEs (603-emulation) */ ++#endif ++ /* emulated PTE hash */ ++ ulong hash_mbase; /* mac physical hash base */ ++ ulong *hash_base; /* kernel pointer to mac hash */ ++ ulong hash_mask; /* hash mask (0x000fffff etc) */ ++ ++ /* context number allocation */ ++ int next_mol_context; /* in the range FIRST .. LAST_MOL_CONTEXT(n) */ ++ int first_mol_context; /* first context number this session may use */ ++ int last_mol_context; /* last context number this session may use */ ++ ++ ulong pthash_sr; /* segment register corresponding to */ ++ ulong pthash_ea_base; /* pthash_ea_base */ ++ void *pthash_inuse_bits; /* bitvector (one bit per PTE) */ ++ ulong pthash_inuse_bits_ph; /* physical base address */ ++ ++ /* various tables */ ++ struct io_data *io_data; /* translation info */ ++ struct fb_data *fb_data; /* ea -> PTE table */ ++ struct tracker_data *tracker_data; /* Keeps track of modified pages */ ++ ++ /* mtable stuff */ ++ skiplist_t vsid_sl; /* skiplist (with vsid_ent_t objects) */ ++ struct vsid_info *vsid_info; /* mtable data */ ++ ++ char *lvptr_reservation; /* lvptr associated with PTE to be inserted */ ++ int lvptr_reservation_lost; /* set if reservation is lost (page out) */ ++ ++#ifdef __darwin__ ++ ulong os_sdr1; /* SDR1 used by the host OS */ ++ ulong mol_sdr1; /* SDR1 used by MOL */ ++#endif ++} mmu_vars_t; ++ ++ ++/* variables which are private to the low level assembly code */ ++typedef struct { ++ ulong spr_hooks[NUM_SPRS]; /* hooks */ ++ ++ ppc_bat_t ibat_save[4]; /* kernel values of the BAT-registers */ ++ ppc_bat_t dbat_save[4]; ++ ++ ulong _msr; /* MSR used in mac-mode (_not_ the emulated msr) */ ++ ++ /* saved kernel/emulator registers */ ++ ulong emulator_nip; ++ ulong emulator_msr; ++ ulong emulator_sprg2; ++ ulong emulator_sprg3; ++ ulong emulator_kcall_nip; ++ ulong emulator_stack; ++ ulong emulator_toc; /* == r2 on certain systems */ ++ ++ /* DEC and timebase */ ++ ulong dec_stamp; /* linux DEC = dec_stamp - tbl */ ++ ulong int_stamp; /* next DEC event = int_stamp - tbl */ ++ ++ /* splitmode */ ++ int split_nip_segment; /* segment (top 4) used for inst. fetches */ ++ ++ /* segment register offset table */ ++ ulong msr_sr_table[ 4*8 ]; /* see emulation.S */ ++ ++ ulong tmp_scratch[4]; /* temporary storage */ ++} base_private_t; ++ ++ ++#ifdef PERFORMANCE_INFO ++#define MAX_ACC_CNTR_DEPTH 8 ++typedef struct acc_counter { ++ ulong stamp; ++ ulong subticks; ++} acc_counter_t; ++#endif ++ ++typedef struct kernel_vars { ++ struct mac_regs mregs; /* must go first */ ++ char page_filler[0x1000 - (sizeof(mac_regs_t)&0xfff) ]; ++ ++ base_private_t _bp; ++ char aligner[32 - (sizeof(base_private_t)&0x1f) ]; ++ mmu_vars_t mmu; ++ char aligner2[16 - (sizeof(mmu_vars_t)&0xf) ]; ++ ++ ulong emuaccel_mphys; /* mphys address of emuaccel_page */ ++ int emuaccel_size; /* size used */ ++ ulong emuaccel_page_phys; /* phys address of page */ ++ ulong emuaccel_page; /* page used for instruction acceleration */ ++ ++ int break_flags; ++ ulong kvars_tophys_offs; /* physical - virtual address of kvars */ ++ struct kernel_vars *kvars_virt; /* me */ ++ int session_index; ++ ++ mol_mutex_t ioctl_sem; /* ioctl lock */ ++#ifdef __darwin__ ++ void *kcall_routine; ++ int kcall_args[3]; ++ char *mregs_virtual; /* mregs address used by client */ ++ ++#endif ++ ++#ifdef PERFORMANCE_INFO ++ ulong asm_bump_cntr[NUM_ASM_BUMP_CNTRS]; ++ ulong asm_tick_stamp[NUM_ASM_TICK_CNTRS]; ++ int num_acntrs; ++ acc_counter_t acntrs[MAX_ACC_CNTR_DEPTH]; ++#endif ++ ++ void *main_thread; /* pointer to the main thread task_struct */ ++ ++} kernel_vars_t; ++ ++#define NUM_KVARS_PAGES ((sizeof(kernel_vars_t)+0xfff)/0x1000) ++ ++typedef struct { ++ kernel_vars_t *kvars[MAX_NUM_SESSIONS]; ++ int magic; ++ ulong kvars_ph[MAX_NUM_SESSIONS]; ++ mol_mutex_t lock; ++ mol_atomic_t external_thread_cnt; ++} session_table_t; ++ ++#define SESSION_LOCK down_mol( &g_sesstab->lock ) ++#define SESSION_UNLOCK up_mol( &g_sesstab->lock ) ++ ++extern session_table_t *g_sesstab; ++ ++ ++#endif /* __ASSEMBLY__ */ ++#endif +--- /dev/null ++++ b/drivers/macintosh/mol/include/locks.h +@@ -0,0 +1,39 @@ ++/* ++ * Creation Date: <2004/01/25 16:31:13 samuel> ++ * Time-stamp: <2004/01/29 22:33:29 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_LOCKS ++#define _H_LOCKS ++ ++/* mutex locks */ ++ ++typedef struct semaphore mol_mutex_t; ++#define init_MUTEX_mol(mu) init_MUTEX( mu ) ++#define free_MUTEX_mol(mu) do {} while(0) ++#define down_mol(x) down(x) ++#define up_mol(x) up(x) ++ ++ ++/* spinlocks */ ++ ++typedef spinlock_t mol_spinlock_t; ++#define spin_lock_mol(x) spin_lock(x) ++#define spin_unlock_mol(x) spin_unlock(x) ++//#define spin_lock_irqsave_mol(x, flags) spin_lock_irqsave(x, flags) ++//#define spin_unlock_irqrestore_mol(x,flags) spin_unlock_irqrestore(x, flags) ++#define spin_lock_init_mol(x) spin_lock_init(x) ++ ++ ++#endif /* _H_LOCKS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/mac_registers.h +@@ -0,0 +1,168 @@ ++/* ++ * Creation Date: <97/06/24 22:25:04 samuel> ++ * Time-stamp: <2004/02/08 20:32:59 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _MAC_REGISTERS_H ++#define _MAC_REGISTERS_H ++ ++#ifndef __ASSEMBLY__ ++ ++#include "mmutypes.h" ++#include "processor.h" ++ ++typedef struct { ++ unsigned long h,l; ++} fpu_register; ++ ++#define NUM_DEBUG_REGS 10 ++ ++typedef struct { ++ unsigned long words[4]; ++} altivec_reg_t; ++ ++#define NR_HOST_IRQS 64 ++ ++typedef struct irq_bitfield { ++ unsigned long irqs[(NR_HOST_IRQS - 1) / sizeof(unsigned long) + 1]; ++} irq_bitfield_t; ++ ++typedef struct mac_regs { /* this struct is page aligned */ ++ /* the sprs should be page aligned (occupies one page) */ ++ unsigned long spr[NUM_SPRS]; /* special purpose registers */ ++ ++ unsigned long segr[16]; /* segment registers */ ++ altivec_reg_t vec[32]; /* AltiVec vector registers */ ++ fpu_register fpr[32]; /* FPU registers (64 bits) */ ++ ++ unsigned long vscr_pad[3], vscr; /* AltiVec status control register */ ++ unsigned long pad_fpscr, fpscr; /* fp. status and control register */ ++ unsigned long pad_ef, emulator_fpscr; /* emulator fp. status and control reg */ ++ ++ /* Keep this cache-block aligned (typcically 8 words) */ ++ unsigned long cr; /* Condition register */ ++ unsigned long link; /* Link register */ ++ unsigned long flag_bits; /* Various flags (fbXXXXX) */ ++ unsigned long inst_opcode; /* opcode of instruction */ ++ unsigned long gpr[32]; /* gprs */ ++ ++ unsigned long ctr; /* Count register */ ++ unsigned long xer; /* Integer exception register */ ++ unsigned long nip; /* Instruction pointer */ ++ unsigned long msr; /* Machine state register (virtual) */ ++ ++ /* interrupts and timers */ ++ int interrupt; /* set if the kernel should return to the emulator */ ++ int in_virtual_mode; /* set while MOL is in virtualization mode */ ++ ulong dec_stamp; /* xDEC = dec_stamp - tbl */ ++ ulong timer_stamp; /* TIMER = dec_stamp - tbl */ ++ int obsolete_irq; /* unused */ ++ ++ /* RVEC parameters */ ++#ifdef __darwin__ ++ ulong rvec_vector; /* Used in kernel C-mode */ ++#endif ++ ulong rvec_param[3]; /* Used in kernel C-mode */ ++ ++ /* misc */ ++ int fpu_state; /* FPU_STATE_xxx (see below) */ ++ int processor; /* processor to emulate, 1=601, 4=604 */ ++ int altivec_used; /* useful for altivec detection */ ++ int no_altivec; /* Don't use altivec (e.g. no kernel support) */ ++ ++ int use_bat_hack; /* Newworld BAT optimization (HACK) */ ++ ++#ifdef EMULATE_603 ++ unsigned long gprsave_603[4]; /* GPR0-3 (for 603 DMISS/IMISS) */ ++#endif ++ /* moldeb support */ ++ unsigned long mdbg_ea_break; /* used together with BREAK_EA_PAGE */ ++ ++ /* DEBUG */ ++ unsigned long debug[NUM_DEBUG_REGS]; ++ unsigned long debug_scr1; /* dbg scratch register */ ++ unsigned long debug_scr2; /* dbg scratch register */ ++ unsigned long debug_trace; /* dbg trace register */ ++ unsigned long dbg_trace_space[256]; ++ unsigned long dbg_last_rvec; /* useful for tracing segfaults etc. */ ++ unsigned long dbg_last_osi; ++ ++ unsigned long kernel_dbg_stop; /* stop emulation flag */ ++ ++ /* host irq mapping data */ ++ irq_bitfield_t mapped_irqs; /* keeps track of used host irqs */ ++ irq_bitfield_t active_irqs; /* irqs that are up are marked here */ ++ int hostirq_update; /* whether userspace should update the pic */ ++ /* should be mol_atomic_t but causes trouble... */ ++ int hostirq_active_cnt; /* number of active host irq lines */ ++ ++} mac_regs_t; ++ ++#define NUM_MREGS_PAGES ((sizeof(mac_regs_t)+0xfff)/0x1000) ++ ++#define BIT(n) (1U<<(31-(n))) /* bit 0 is MSB */ ++ ++#ifndef __KERNEL__ ++extern mac_regs_t *mregs; ++#endif ++#endif /* __ASSEMBLY__ */ ++ ++/* mregs->fpu_state (only valid when FBIT_FPUInUse is false) */ ++#define FPU_STATE_HALF_SAVED 0 /* fpscr & fr0-fr13 saved */ ++#define FPU_STATE_DIRTY 1 /* fpscr & fr13 saved */ ++#define FPU_STATE_SAVED 3 /* everything is saved to mregs */ ++ ++/* flag_bits (loaded into cr4-7). TOUCH THESE *ONLY* FROM THE MAIN THREAD! */ ++#ifdef __KERNEL__ ++/* these must be in cr7 (set through a mtcrf) */ ++#define MMU_CR_FIELD 0x01 ++#define FBIT_InSplitmode 31 /* (S) */ ++#define FBIT_PrepareSplitmode 30 /* (S) */ ++#define FBIT_LoadSegreg 29 /* (S) */ ++ ++/* must be in cr6; (set through a mtcrf) */ ++#define TRACE_CR_FIELD 0x02 ++#define FBIT_DbgTrace 27 /* (S) equals BREAK_SINGLE_STEP */ ++#define FBIT_Trace 26 /* (S) */ ++ ++#define FBIT_MolDecLoaded 23 /* (S) */ ++#define FBIT_DecSeenZero 22 /* (S) */ ++#define FBIT_DecINT 21 /* (S) */ ++#define FBIT_FPUInUse 20 /* (S) Set when fpu is mac-owned (only valid in the kernel) */ ++ ++#endif ++ ++#define FBIT_MsrModified 19 /* (U) */ ++#define FBIT_RecalcDecInt 18 /* (U) */ ++#define FBIT_IRQPending 17 /* (U) IRQ is pending */ ++#ifdef EMULATE_603 ++#define FBIT_603_AltGPR 16 /* (U) Alternate GPR0-3 in use */ ++#endif ++ ++ ++#ifdef __KERNEL__ ++#define fb_DbgTrace BIT( FBIT_DbgTrace ) ++#define fb_Trace BIT( FBIT_Trace ) ++#define fb_PrepareSplitmode BIT( FBIT_PrepareSplitmode ) ++#define fb_InSplitmode BIT( FBIT_InSplitmode ) ++#define fb_LoadSegreg BIT( FBIT_LoadSegreg ) ++#endif ++#define fb_MsrModified BIT( FBIT_MsrModified ) ++#define fb_RecalcDecInt BIT( FBIT_RecalcDecInt ) ++#define fb_IRQPending BIT( FBIT_IRQPending ) ++#ifdef EMULATE_603 ++#define fb_603_AltGPR BIT( FBIT_603_AltGPR ) ++#endif ++ ++#endif /* _MAC_REGISTERS_H */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/map.h +@@ -0,0 +1,43 @@ ++/* ++ * Creation Date: <2004/03/13 13:25:42 samuel> ++ * Time-stamp: <2004/03/13 14:07:11 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ */ ++ ++#ifndef _H_MAP ++#define _H_MAP ++ ++/* map a userspace address into the kernel address space */ ++extern void *map_phys_range( ulong paddr, ulong size, char **ret_addr ); ++extern void unmap_phys_range( void *handle ); ++ ++/* map a userspace address into the kernel address space */ ++extern void *map_virt_range( ulong va, ulong size, char **ret_addr ); ++extern void unmap_virt_range( void *handle ); ++ ++/* map the virtualized PTE hash into the kernel address space */ ++extern ulong *map_emulated_hash( kernel_vars_t *kv, ulong mbase, ulong size ); ++extern void unmap_emulated_hash( kernel_vars_t *kv ); ++ ++#ifdef __linux__ ++static inline ulong* map_hw_hash( ulong physbase, int size ) { ++ return phys_to_virt( physbase ); ++} ++static inline void unmap_hw_hash( ulong *base ) {} ++#endif ++ ++#ifdef __darwin__ ++static inline void *map_hw_hash( ulong physbase, int size ) { return NULL; } ++static inline void unmap_hw_hash( ulong *base ) {} ++#endif ++ ++#endif /* _H_MAP */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/misc.h +@@ -0,0 +1,105 @@ ++/* ++ * Creation Date: <97/06/16 18:02:12 samuel> ++ * Time-stamp: <2004/03/13 14:03:30 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 1997-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MOD ++#define _H_MOD ++ ++#ifdef __linux__ ++ ++#include ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ++#define compat_verify_area(a,b,c) ( ! access_ok(a,b,c) ) ++#else ++#define compat_verify_area(a,b,c) verify_area(a,b,c) ++#endif ++ ++#endif /* __linux__ */ ++ ++extern int g_num_sessions; /* number of active sessions */ ++ ++struct kernel_vars; ++ ++/* init.c */ ++extern int common_init( void ); ++extern void common_cleanup( void ); ++extern int initialize_session( unsigned int sess_index ); ++extern void destroy_session( unsigned int sess_index ); ++extern uint get_session_magic( uint random_magic ); ++ ++/* arch specific functions */ ++extern int arch_common_init( void ); ++extern void arch_common_cleanup( void ); ++extern struct kernel_vars *alloc_kvar_pages( void ); ++extern void free_kvar_pages( struct kernel_vars *kv ); ++extern void prevent_mod_unload( void ); ++ ++/* misc.c */ ++struct dbg_op_params; ++struct perf_ctr; ++extern int do_debugger_op( kernel_vars_t *kv, struct dbg_op_params *pb ); ++extern int handle_ioctl( kernel_vars_t *kv, int what, int arg1, int arg2, int arg3 ); ++ ++/* hostirq.c */ ++extern int grab_host_irq(kernel_vars_t *kv, int irq); ++extern int release_host_irq(kernel_vars_t *kv, int irq); ++extern void init_host_irqs(kernel_vars_t *kv); ++extern void cleanup_host_irqs(kernel_vars_t *kv); ++ ++/* actions.c */ ++extern int perform_actions( void ); ++extern void cleanup_actions( void ); ++ ++/* bit table manipulation */ ++static inline void ++set_bit_mol( int nr, char *addr ) ++{ ++ ulong mask = 1 << (nr & 0x1f); ++ ulong *p = ((ulong*)addr) + (nr >> 5); ++ *p |= mask; ++} ++ ++static inline void ++clear_bit_mol( int nr, char *addr ) ++{ ++ ulong mask = 1 << (nr & 0x1f); ++ ulong *p = ((ulong*)addr) + (nr >> 5); ++ *p &= ~mask; ++} ++ ++static inline int ++check_bit_mol( int nr, char *addr ) ++{ ++ ulong mask = 1 << (nr & 0x1f); ++ ulong *p = ((ulong*)addr) + (nr >> 5); ++ return (*p & mask) != 0; ++} ++ ++/* typesafe min/max (stolen from kernel.h) */ ++#define min_mol(x,y) ({ \ ++ const typeof(x) _x = (x); \ ++ const typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x < _y ? _x : _y; }) ++ ++#define max_mol(x,y) ({ \ ++ const typeof(x) _x = (x); \ ++ const typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x > _y ? _x : _y; }) ++ ++#endif +--- /dev/null ++++ b/drivers/macintosh/mol/include/mmu.h +@@ -0,0 +1,102 @@ ++/* ++ * Creation Date: <1998-11-11 13:55:49 samuel> ++ * Time-stamp: <2004/02/28 19:20:23 samuel> ++ * ++ * ++ * ++ * MMU related things ++ * ++ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MMU ++#define _H_MMU ++ ++#ifndef __ASSEMBLY__ ++#include "kernel_vars.h" ++#include "mac_registers.h" ++#include "mmu_mappings.h" ++#endif ++ ++#ifdef CONFIG_MOL_HOSTED ++#define IO_PAGE_MAGIC_1 0x10BADA57 ++#define IO_PAGE_MAGIC_2 0x136AB779 ++#else ++#define IO_PAGE_MAGIC_1 0x10BACA57 ++#define IO_PAGE_MAGIC_2 0x135AB779 ++#endif ++ ++#ifndef __ASSEMBLY__ ++typedef struct io_page { /* Must fit within a single 4K page */ ++ ulong magic; /* identifier 1 */ ++ ulong magic2; /* identifier 2 */ ++ ++ ulong me_phys; /* physical address of this block */ ++ ulong mphys; /* mac-physical address of block */ ++ struct io_page *next; /* next io_page */ ++ ++ void *usr_data[512]; /* usr data (grain=double word) */ ++} io_page_t; ++ ++/* from mmu.c */ ++extern int init_mmu( kernel_vars_t *kv ); ++extern void cleanup_mmu( kernel_vars_t *kv ); ++extern void do_flush( ulong vsid, ulong va, ulong *dummy, int num ); ++extern void mmu_altered( kernel_vars_t *kv ); ++extern void clear_vsid_refs( kernel_vars_t *kv ); ++ ++/* arch/mmu.c */ ++extern int arch_mmu_init( kernel_vars_t *kv ); ++ ++/* from mmu_io.c */ ++struct pte_lvrange; ++extern int init_mmu_io( kernel_vars_t *kv ); ++extern void cleanup_mmu_io( kernel_vars_t *kv ); ++extern int add_io_trans( kernel_vars_t *kv, ulong mbase, int size, void *usr_data ); ++extern int remove_io_trans( kernel_vars_t *kv, ulong mbase, int size ); ++extern int mphys_to_pte( kernel_vars_t *kv, ulong mphys, ulong *pte1, int is_write, struct pte_lvrange **lvrange ); ++extern void mmu_add_map( kernel_vars_t *kv, struct mmu_mapping *m ); ++extern void mmu_remove_map( kernel_vars_t *kv, struct mmu_mapping *m ); ++ ++/* from context.c */ ++extern int init_contexts( kernel_vars_t *kv ); ++extern void cleanup_contexts( kernel_vars_t *kv ); ++extern int alloc_context( kernel_vars_t *kv ); ++extern void handle_context_wrap( kernel_vars_t *kv, int nvsid_needed ); ++ ++/* from mmu_fb.c */ ++extern int init_mmu_fb( kernel_vars_t *kv ); ++extern void cleanup_mmu_fb( kernel_vars_t *kv ); ++extern void video_pte_inserted( kernel_vars_t *kv, ulong lvptr, ulong *slot, ++ ulong pte0, ulong pte1, ulong ea ); ++extern void setup_fb_acceleration( kernel_vars_t *kv, char *lvbase, int bytes_per_row, int height ); ++extern int get_dirty_fb_lines( kernel_vars_t *kv, short *retbuf, int num_bytes ); ++ ++/* from mmu_tracker.c */ ++extern int init_mmu_tracker( kernel_vars_t *kv ); ++extern void cleanup_mmu_tracker( kernel_vars_t *kv ); ++extern int track_lvrange( kernel_vars_t *kv ); ++extern size_t get_track_buffer( kernel_vars_t *kv, char *retbuf ); ++extern void set_track_buffer( kernel_vars_t *kv, char *buf ); ++extern void lvpage_dirty( kernel_vars_t *kv, ulong lvpage ); ++ ++/* These functions should be used by the debugger only */ ++struct dbg_page_info; ++extern int dbg_get_PTE( kernel_vars_t *kv, int context, ulong va, mPTE_t *ret ); ++extern int dbg_get_linux_page( ulong va, struct dbg_page_info *r ); ++extern int dbg_translate_ea( kernel_vars_t *kv, int context, ulong va, int *ret_mphys, int data_access ); ++ ++/* arch functions */ ++extern ulong get_phys_page( kernel_vars_t *kv, ulong lvptr, int request_rw ); ++ ++/* VSID stuff */ ++#define VSID_MASK 0xffffff ++ ++ ++#endif /* __ASSEMBLY__ */ ++#endif /* _H_MMU */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/mmu_contexts.h +@@ -0,0 +1,55 @@ ++/* ++ * Creation Date: <97/07/17 14:26:14 samuel> ++ * Time-stamp: <2003/06/06 19:17:26 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 1997, 2001, 2002, 2003 Samuel Rydh ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_MMU_CONTEXTS ++#define _H_MMU_CONTEXTS ++ ++/********************************************************** ++ * EVERYTHING IN THIS FILE IS UESED FOR DEBUGGING ONLY ++ *********************************************************/ ++ ++/* MMU context identifiers */ ++#define kContextUnmapped 1 ++#define kContextMapped_S 2 ++#define kContextMapped_U 3 ++ ++#define kContextEmulator 20 /* for debugging purposes ONLY !!!! */ ++#define kContextKernel 21 /* for debugging purposes ONLY !!!! */ ++ ++ ++/* Flags returned by _get_physical_page(). The first flags should ++ * equal the _PAGE_XXX of the old MM implementation (<2.4.6). ++ */ ++#define M_PAGE_PRESENT 0x001 /* software: pte contains a translation */ ++#define M_PAGE_USER 0x002 /* usermode access allowed */ ++#define M_PAGE_RW 0x004 /* usermode access allowed */ ++#define M_PAGE_GUARDED 0x008 /* G: prohibit speculative access */ ++#define M_PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */ ++#define M_PAGE_NO_CACHE 0x020 /* I: cache inhibit */ ++#define M_PAGE_WRITETHRU 0x040 /* W: cache write-through */ ++#define M_PAGE_DIRTY 0x080 /* C: page changed */ ++#define M_PAGE_ACCESSED 0x100 /* R: page referenced */ ++/* new linux-MM implementation */ ++#define M_PAGE_HASHPTE 0x1000 /* hash_page has made an HPTE for this pte */ ++#define M_PAGE_EXEC 0x2000 /* software: i-cache coherency required */ ++ ++#ifdef __KERNEL__ ++#define DBG_TRANSL_PAGE_FLAG( val, flagname ) \ ++ (((val) & flagname )? M##flagname : 0) ++#endif ++ ++ ++#endif /* _H_MMU_CONTEXTS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/mmu_mappings.h +@@ -0,0 +1,48 @@ ++/* ++ * Creation Date: <1998-10-31 03:11:06 samuel> ++ * Time-stamp: <2004/03/13 16:44:58 samuel> ++ * ++ * ++ * ++ * Mappings mac physical <-> linux virtual ++ * ++ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MMU_MAPPINGS ++#define _H_MMU_MAPPINGS ++ ++typedef struct mmu_mapping { ++ ulong mbase; /* mac physical base */ ++ char *lvbase; /* linux virtual base */ ++ size_t size; /* size (in bytes) */ ++ int flags; /* MAPPING_xxx */ ++ ++ int id; /* set to zero, returned by the kerrnel module */ ++} mmu_mapping_t; ++ ++/* mmu_mapping flags */ ++ ++#define MAPPING_RO 1 /* read only memory (ROM etc) */ ++#define MAPPING_PHYSICAL 2 /* physical (ROM etc) */ ++#define MAPPING_SCRATCH 4 /* (block transl) scratch area */ ++#define MAPPING_FORCE_CACHE 8 /* force write-through caching */ ++#define MAPPING_FB_ACCEL 16 /* offscreen framebuffer, track changes */ ++#define MAPPING_FB 32 /* framebuffer (ea assumed to be constant) */ ++#define MAPPING_DBAT 64 /* allow use of a DBAT register */ ++#define MAPPING_MACOS_CONTROLS_CACHE 128 /* do not force WIM bits to 001 */ ++#define MAPPING_PUT_FIRST 256 /* take precedence over other translations */ ++#define MAPPING_MREGS 512 /* map mregs into emulated process */ ++#define MAPPING_FORCE_WRITABLE 4096 /* guess what... */ ++ ++#ifdef __KERNEL__ ++#define MAPPING_IO 1024 /* I/O translation */ ++#define MAPPING_VALID 2048 /* valid bit */ ++#endif ++ ++#endif /* _H_MMU_MAPPINGS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/mmutypes.h +@@ -0,0 +1,76 @@ ++/* ++ * Creation Date: <2002/01/13 13:53:14 samuel> ++ * Time-stamp: <2002/01/27 19:56:11 samuel> ++ * ++ * ++ * ++ * MMU definitions ++ * ++ * Most of these declarations originate from the Linux Kernel ++ * ++ * Copyright (C) 2002 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MMUTYPES ++#define _H_MMUTYPES ++ ++/* Hardware Page Table Entry */ ++typedef struct mPTE { ++ unsigned long v:1; /* Entry is valid */ ++ unsigned long vsid:24; /* Virtual segment identifier */ ++ unsigned long h:1; /* Hash algorithm indicator */ ++ unsigned long api:6; /* Abbreviated page index */ ++ ++ unsigned long rpn:20; /* Real (physical) page number */ ++ unsigned long :3; /* Unused */ ++ unsigned long r:1; /* Referenced */ ++ unsigned long c:1; /* Changed */ ++ unsigned long w:1; /* Write-thru cache mode */ ++ unsigned long i:1; /* Cache inhibited */ ++ unsigned long m:1; /* Memory coherence */ ++ unsigned long g:1; /* Guarded */ ++ unsigned long :1; /* Unused */ ++ unsigned long pp:2; /* Page protection */ ++} mPTE_t; ++ ++ ++typedef struct _mBATU { /* Upper part of BAT (all except 601) */ ++ unsigned long bepi:15; /* Effective page index (virtual address) */ ++ unsigned long :4; /* Unused */ ++ unsigned long bl:11; /* Block size mask */ ++ unsigned long vs:1; /* Supervisor valid */ ++ unsigned long vp:1; /* User valid */ ++} mBATU; ++ ++typedef struct _mBATL { /* Lower part of BAT (all except 601) */ ++ unsigned long brpn:15; /* Real page index (physical address) */ ++ unsigned long :10; /* Unused */ ++ unsigned long w:1; /* Write-thru cache */ ++ unsigned long i:1; /* Cache inhibit */ ++ unsigned long m:1; /* Memory coherence */ ++ unsigned long g:1; /* Guarded (MBZ in IBAT) */ ++ unsigned long :1; /* Unused */ ++ unsigned long pp:2; /* Page access protections */ ++} mBATL; ++ ++typedef struct _mBAT { ++ mBATU batu; /* Upper register */ ++ mBATL batl; /* Lower register */ ++} mBAT; ++ ++typedef struct _mSEGREG { ++ unsigned long t:1; /* Normal or I/O type */ ++ unsigned long ks:1; /* Supervisor 'key' (normally 0) */ ++ unsigned long kp:1; /* User 'key' (normally 1) */ ++ unsigned long n:1; /* No-execute */ ++ unsigned long :4; /* Unused */ ++ unsigned long vsid:24; /* Virtual Segment Identifier */ ++} mSEGREG; ++ ++ ++#endif /* _H_MMUTYPES */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/mol-ioctl.h +@@ -0,0 +1,121 @@ ++/* ++ * Creation Date: <2003/08/26 10:53:07 samuel> ++ * Time-stamp: <2004/02/08 20:17:58 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_MOL_IOCTL ++#define _H_MOL_IOCTL ++ ++#ifndef __ASSEMBLY__ ++#include "mmutypes.h" ++ ++typedef struct { ++ int version; /* MOL version */ ++ int smp_kernel; /* compiled with CONFIG_SMP */ ++ int pvr; /* cpu version/revision (PVR) */ ++ int rombase; ++ int romsize; ++ unsigned int tb_freq; ++} mol_kmod_info_t; ++ ++typedef struct perf_ctr { ++ unsigned int ctr; ++ char name[40]; ++} perf_ctr_t; ++ ++typedef struct dbg_page_info { ++ int phys; ++ int mflags; /* M_PAGE_XXX */ ++} dbg_page_info_t; ++ ++typedef struct dbg_op_params { ++ /* input */ ++ int operation; /* DBG_OP_xxx */ ++ int ea; ++ int context; ++ int param; ++ ++ /* output */ ++ union { ++ int phys; ++ dbg_page_info_t page; ++ mPTE_t pte; ++ } ret; ++} dbg_op_params_t; ++ ++typedef struct mol_ioctl_pb { ++ int arg1, arg2, arg3; ++#ifdef __darwin__ ++ int ret; ++#endif ++} mol_ioctl_pb_t; ++ ++#endif /* __ASSEMBLY__ */ ++ ++/* ioctls that do not use the mol_ioctl_pb arg */ ++#define MOL_IOCTL_SMP_SEND_IPI _IO('M', 1) /* void ( void ) */ ++#ifdef __darwin__ ++#define MOL_IOCTL_CALL_KERNEL _IO('M', 2) /* void ( void ) */ ++#endif ++ ++/* debugger ioctls */ ++#define MOL_IOCTL_DEBUGGER_OP _IOWR('M', 10, mol_ioctl_pb_t) /* int ( dbg_op_params *p ) */ ++#define DBG_OP_EMULATE_TLBIE 1 /* void ( ulong pageindex ) */ ++#define DBG_OP_EMULATE_TLBIA 2 /* void ( void ) */ ++#define DBG_OP_GET_PTE 3 /* lvptr, context, int ( ulong vsid, ulong va, PTE *retpte ) */ ++#define DBG_OP_GET_PHYS_PAGE 4 /* int ( ulong lvptr, ulong *retptr ) */ ++#define DBG_OP_BREAKPOINT_FLAGS 5 /* void ( ulong flags ) */ ++#define DBG_OP_TRANSLATE_EA 6 /* ea, context, is_data -- mphys */ ++#define MOL_IOCTL_CLEAR_PERF_INFO _IOWR('M', 11, mol_ioctl_pb_t) /* void ( void ) */ ++#define MOL_IOCTL_GET_PERF_INFO _IOWR('M', 12, mol_ioctl_pb_t) /* int ( int index, perf_ctr_t *ctr ) */ ++ ++/* config selectors */ ++#define MOL_IOCTL_CREATE_SESSION _IOWR('M', 30, mol_ioctl_pb_t) /* int ( int session_index ) */ ++#define MOL_IOCTL_GET_INFO _IOWR('M', 31, mol_ioctl_pb_t) /* int ( mol_kmod_info_t *retinfo, int size ) */ ++#define MOL_IOCTL_SET_RAM _IOWR('M', 33, mol_ioctl_pb_t) /* void ( ulong ram_start, ulong ram_end ) */ ++#define MOL_IOCTL_COPY_LAST_ROMPAGE _IOWR('M', 34, mol_ioctl_pb_t) /* void ( char *destpage ) */ ++#define MOL_IOCTL_SPR_CHANGED _IOWR('M', 35, mol_ioctl_pb_t) /* void ( void ) */ ++#define MOL_IOCTL_IDLE_RECLAIM_MEMORY _IOWR('M', 36, mol_ioctl_pb_t) /* void ( void ) */ ++#define MOL_IOCTL_MMU_MAP _IOWR('M', 37, mol_ioctl_pb_t) /* void ( struct mmu_mapping *m, int add_map ) */ ++#define MOL_IOCTL_ADD_IORANGE _IOWR('M', 39, mol_ioctl_pb_t) /* void ( ulong mbase, size_t size, io_ops_t *) */ ++#define MOL_IOCTL_REMOVE_IORANGE _IOWR('M', 40, mol_ioctl_pb_t) /* void ( ulong mbase, size_t size ) */ ++#define MOL_IOCTL_SETUP_FBACCEL _IOWR('M', 41, mol_ioctl_pb_t) /* void * ( char *lvbase, int bytes_per_row, int height ) */ ++#define MOL_IOCTL_GET_DIRTY_FBLINES _IOWR('M', 42, mol_ioctl_pb_t) /* int ( short *rettable, int table_size_in_bytes ) */ ++#define MOL_IOCTL_TRACK_DIRTY_RAM _IOWR('M', 43, mol_ioctl_pb_t) /* int ( char *lvbase, size_t size ) */ ++#define MOL_IOCTL_GET_DIRTY_RAM _IOWR('M', 44, mol_ioctl_pb_t) /* size_t ( char *retbuf ) */ ++#define MOL_IOCTL_SET_DIRTY_RAM _IOWR('M', 45, mol_ioctl_pb_t) /* void ( char *dirtybuf ) */ ++#define MOL_IOCTL_GET_MREGS_PHYS _IOWR('M', 46, mol_ioctl_pb_t) /* ulong ( void ) */ ++#define MOL_IOCTL_ALLOC_EMUACCEL_SLOT _IOWR('M', 47, mol_ioctl_pb_t) /* int ( int inst_flags, int param, int inst_addr ) */ ++#define MOL_IOCTL_MAPIN_EMUACCEL_PAGE _IOWR('M', 48, mol_ioctl_pb_t) /* int ( int mphys ) */ ++#define MOL_IOCTL_TUNE_SPR _IOWR('M', 49, mol_ioctl_pb_t) /* int ( int spr, int action ) */ ++#define MOL_IOCTL_GET_SESSION_MAGIC _IOWR('M', 50, mol_ioctl_pb_t) /* uint ( uint new_random_magic ) */ ++ ++#define MOL_IOCTL_DBG_COPY_KVARS _IOWR('M', 51, mol_ioctl_pb_t) /* int ( int session, kernel_vars_t *dest ) */ ++ ++#ifdef __darwin__ ++#define MOL_IOCTL_GET_MREGS_VIRT _IOWR('M', 52, mol_ioctl_pb_t) /* int ( mac_regs_t **ret ) */ ++#endif ++ ++#define MOL_IOCTL_GRAB_IRQ _IOWR('M', 53, mol_ioctl_pb_t) /* int ( int irq ) */ ++#define MOL_IOCTL_RELEASE_IRQ _IOWR('M', 54, mol_ioctl_pb_t) /* int ( int irq ) */ ++#define MOL_IOCTL_GET_IRQS _IOWR('M', 55, mol_ioctl_pb_t) /* int ( irq_bitfield_t * ) */ ++ ++ ++/* MOL error codes */ ++#define EMOLGENERAL 100 ++#define EMOLINUSE 101 ++#define EMOLINVAL 102 ++#define EMOLSECURITY 103 ++ ++#endif /* _H_MOL_IOCTL */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/mol_config.h +@@ -0,0 +1,76 @@ ++/* ++ * Creation Date: <1999/05/30 15:30:25 samuel> ++ * Time-stamp: <2004/06/05 19:47:33 samuel> ++ * ++ * ++ * ++ * Header to be included first... ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MOL_CONFIG ++#define _H_MOL_CONFIG ++ ++/* Some debugging flags */ ++#define COLLECT_RVEC_STATISTICS ++//#define EMULATE_603 ++//#define ENABLE_ASSERT ++ ++#define _GNU_SOURCE ++#define _REENTRANT ++#define _LARGEFILE64_SOURCE ++ ++#if defined(__powerpc__) && !defined(__ppc__) ++#define __ppc__ ++#endif ++#if defined(__ppc__) && !defined(__powerpc__) ++#define __powerpc__ ++#endif ++ ++#if !defined(__linux__) && !defined(__ASSEMBLY__) ++typedef unsigned long ulong; ++#endif ++ ++#if !defined(__ASSEMBLY__) && !defined(__KERNEL__) ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "config.h" ++#include "autoconf.h" ++#include "unconfig.h" ++ ++#ifdef CONFIG_OLDWORLD ++#define OLDWORLD_SUPPORT ++#endif ++ ++#include "platform.h" ++ ++/* from emulaiton/main.c */ ++extern int in_security_mode; ++ ++/* common MOL header fiels */ ++ ++#include "debugger.h" /* for printm */ ++#include "extralib.h" ++ ++#endif /* __ASSEMBLY__ && __KERNEL__ */ ++ ++#ifdef __ASSEMBLY__ ++changequote([[[[[,]]]]]) ++[[[[[ /* shield includes from m4-expansion */ ++#endif ++ ++#endif /* _H_MOL_CONFIG */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/molasm.h +@@ -0,0 +1,138 @@ ++/* -*- asm -*- ++ * ++ * Creation Date: <2001/01/28 20:33:22 samuel> ++ * Time-stamp: <2004/01/29 19:29:10 samuel> ++ * ++ * ++ * ++ * Utility assembly macros ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MOLASM ++#define _H_MOLASM ++ ++#define GLOBAL_SYMBOL( sym_name ) \ ++GLOBL(sym_name) ++ ++ ++/************************************************************************/ ++/* SPRG usage */ ++/************************************************************************/ ++ ++/* Darwin and Linux uses the sprg's differently. Linux uses sprg0/1 in ++ * the exception vectors while Darwin uses sprg2/3. ++ */ ++#ifdef __linux__ ++define([mfsprg_a0], [mfsprg0]) ++define([mfsprg_a1], [mfsprg1]) ++define([mfsprg_a2], [mfsprg2]) ++define([mfsprg_a3], [mfsprg3]) ++define([mtsprg_a0], [mtsprg0]) ++define([mtsprg_a1], [mtsprg1]) ++define([mtsprg_a2], [mtsprg2]) ++define([mtsprg_a3], [mtsprg3]) ++#else ++define([mfsprg_a0], [mfsprg2]) ++define([mfsprg_a1], [mfsprg3]) ++define([mfsprg_a2], [mfsprg0]) ++define([mfsprg_a3], [mfsprg1]) ++define([mtsprg_a0], [mtsprg2]) ++define([mtsprg_a1], [mtsprg3]) ++define([mtsprg_a2], [mtsprg0]) ++define([mtsprg_a3], [mtsprg1]) ++#endif ++ ++ ++/************************************************************************/ ++/* Utility */ ++/************************************************************************/ ++ ++MACRO(LOAD_VARIABLE, [reg, offs], [ ++ lis _reg,HA(k_mol_stack + _offs) ++ lwz _reg,LO(k_mol_stack + _offs)(_reg) ++]) ++ ++MACRO(SET_SESSION_TABLE, [reg], [ ++ lis _reg,HA(EXTERN(Symbol_SESSION_TABLE)) ++ addi _reg,_reg,LO(EXTERN(Symbol_SESSION_TABLE)) ++]) ++ ++ ++/************************************************************************/ ++/* GPR save / restore */ ++/************************************************************************/ ++ ++MACRO(xGPR_SAVE, [reg], [ ++ stw rPREFIX[]_reg,(xGPR0 + _reg*4)(r1) ++]) ++ ++MACRO(xGPR_LOAD, [reg], [ ++ lwz rPREFIX[]_reg,(xGPR0 + _reg*4)(r1) ++]) ++ ++ ++/************************************************************************/ ++/* FPU misc */ ++/************************************************************************/ ++ ++MACRO(ENABLE_MSR_FP, [scr], [ ++ mfmsr _scr ++ ori _scr,_scr,MSR_FP ++ mtmsr _scr ++ isync ++]) ++ ++/************************************************************************/ ++/* Segment registers */ ++/************************************************************************/ ++ ++MACRO(LOAD_SEGMENT_REGS, [base, scr, scr2], [ ++ mFORLOOP([i],0,7,[ ++ lwz _scr,eval(i * 8)(_base) ++ lwz _scr2,eval((i * 8)+4)(_base) ++ mtsr srPREFIX[]eval(i*2),_scr ++ mtsr srPREFIX[]eval(i*2+1),_scr2 ++ ]) ++]) ++ ++MACRO(SAVE_SEGMENT_REGS, [base, scr, scr2], [ ++ mFORLOOP([i],0,7,[ ++ mfsr _scr,srPREFIX[]eval(i*2) ++ mfsr _scr2,srPREFIX[]eval(i*2+1) ++ stw _scr,eval(i * 8)(_base) ++ stw _scr2,eval((i * 8) + 4)(_base) ++ ]) ++]) ++ ++/************************************************************************/ ++/* BAT register */ ++/************************************************************************/ ++ ++MACRO(SAVE_DBATS, [varoffs, scr1], [ ++ mfpvr _scr1 ++ srwi _scr1,_scr1,16 ++ cmpwi r3,1 ++ beq 9f ++ mFORLOOP([nn],0,7,[ ++ mfspr _scr1, S_DBAT0U + nn ++ stw _scr1,(_varoffs + (4 * nn))(r1) ++ ]) ++9: ++]) ++ ++MACRO(SAVE_IBATS, [varoffs, scr1], [ ++ mFORLOOP([nn],0,7,[ ++ mfspr _scr1, S_IBAT0U + nn ++ stw _scr1,(_varoffs + (4 * nn))(r1) ++ ]) ++]) ++ ++ ++#endif /* _H_MOLASM */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/molversion.h +@@ -0,0 +1,6 @@ ++#define MOL_BUILD_DATE "Okt 13 2007 11:49" ++#define MOL_VERSION_STR "0.9.73" ++#define MOL_RELEASE "0.9.73-SVN" ++#define MOL_MAJOR_VERSION 0 ++#define MOL_MINOR_VERSION 9 ++#define MOL_PATCHLEVEL 73 +--- /dev/null ++++ b/drivers/macintosh/mol/include/mtable.h +@@ -0,0 +1,71 @@ ++/* ++ * Creation Date: <2002/05/26 15:52:50 samuel> ++ * Time-stamp: <2004/02/21 16:18:11 samuel> ++ * ++ * ++ * ++ * Keeps track of the PTEs ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_MTABLE ++#define _H_MTABLE ++ ++#ifndef __ASSEMBLY__ ++typedef struct pte_lvrange pte_lvrange_t; ++typedef struct vsid_info vsid_info_t; ++typedef struct vsid_ent vsid_ent_t; ++ ++extern int init_mtable( kernel_vars_t *kv ); ++extern void cleanup_mtable( kernel_vars_t *kv ); ++ ++extern pte_lvrange_t *register_lvrange( kernel_vars_t *kv, char *lvbase, int size ); ++extern void free_lvrange( kernel_vars_t *kv, pte_lvrange_t *pte_range ); ++ ++extern vsid_ent_t *vsid_get_user_sv( kernel_vars_t *kv, int mac_vsid, ulong *user_sr, ulong *sv_sr ); ++ ++extern int mtable_memory_check( kernel_vars_t *kv ); ++extern void pte_inserted( kernel_vars_t *kv, ulong ea, char *lvptr, ++ pte_lvrange_t *lvrange, ulong *pte, vsid_ent_t *r, ++ int segreg ); ++ ++extern void flush_vsid_ea( kernel_vars_t *kv, int vsid, ulong ea ); ++extern void flush_ea_range( kernel_vars_t *kv, ulong ea, int size ); ++extern void flush_lvptr( kernel_vars_t *kv, ulong lvptr ); ++extern void flush_lv_range( kernel_vars_t *kv, ulong lvbase, int size ); ++ ++extern void clear_all_vsids( kernel_vars_t *kv ); ++extern void clear_pte_hash_table( kernel_vars_t *kv ); ++ ++extern void mtable_reclaim( kernel_vars_t *kv ); ++extern void mtable_tune_alloc_limit( kernel_vars_t *kv, int ramsize_mb ); ++ ++static inline void ++make_lvptr_reservation( kernel_vars_t *kv, char *lvptr ) { ++ kv->mmu.lvptr_reservation = lvptr; ++ kv->mmu.lvptr_reservation_lost = 0; ++} ++ ++ ++#endif /* __ASSEMBLY__ */ ++ ++/* offsets to linux_vsid and linux_vsid_sv (used from assembly) */ ++#define VSID_MYSELF_VIRT 0 ++#define VSID_USER_OFFS 4 ++#define VSID_SV_OFFS 8 ++#define SIZEOF_VSID_ENT (64*4 + 12) ++ ++#define VSID_OFFSETS_OK \ ++ ((offsetof(vsid_ent_t, linux_vsid) == VSID_USER_OFFS ) || \ ++ (offsetof(vsid_ent_t, linux_vsid_sv) == VSID_SV_OFFS ) || \ ++ (sizeof(vsid_ent_t) == SIZEOF_VSID_ENT)) ++ ++#endif /* _H_MTABLE */ ++ ++ +--- /dev/null ++++ b/drivers/macintosh/mol/include/osi.h +@@ -0,0 +1,170 @@ ++/* ++ * Creation Date: <1999/03/18 03:19:43 samuel> ++ * Time-stamp: <2003/12/26 16:58:19 samuel> ++ * ++ * ++ * ++ * This file includes definitions for drivers ++ * running in the "emulated" OS. (Mainly the 'sc' ++ * mechanism of communicating) ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_OSI ++#define _H_OSI ++ ++/* Magic register values loaded into r3 and r4 before the 'sc' assembly instruction */ ++#define OSI_SC_MAGIC_R3 0x113724FA ++#define OSI_SC_MAGIC_R4 0x77810F9B ++ ++ ++/************************************************************************/ ++/* Selectors (passed in r5) */ ++/************************************************************************/ ++ ++#define OSI_CALL_AVAILABLE 0 ++#define OSI_DEBUGGER 1 /* enter debugger */ ++/* obsolete OSI_LOG_STR 3 */ ++#define OSI_CMOUNT_DRV_VOL 4 /* conditionally mount driver volume */ ++/* obsolete OSI_SCSI_xxx 5-6 */ ++#define OSI_GET_GMT_TIME 7 ++#define OSI_MOUSE_CNTRL 8 ++#define OSI_GET_LOCALTIME 9 /* return time in secs from 01/01/04 */ ++ ++#define OSI_ENET_OPEN 10 ++#define OSI_ENET_CLOSE 11 ++#define OSI_ENET_GET_ADDR 12 ++#define OSI_ENET_GET_STATUS 13 ++#define OSI_ENET_CONTROL 14 ++#define OSI_ENET_ADD_MULTI 16 ++#define OSI_ENET_DEL_MULTI 17 ++#define OSI_ENET_GET_PACKET 18 ++#define OSI_ENET_SEND_PACKET 19 ++ ++#define OSI_OF_INTERFACE 20 ++#define OSI_OF_TRAP 21 ++#define OSI_OF_RTAS 22 ++ ++#define OSI_SCSI_CNTRL 23 ++#define OSI_SCSI_SUBMIT 24 ++#define OSI_SCSI_ACK 25 ++ ++#define OSI_GET_MOUSE 26 /* -- r3 status, r4-r8 mouse data */ ++#define OSI_ACK_MOUSE_IRQ 27 /* -- int */ ++ ++#define OSI_SET_VMODE 28 /* modeID, depth -- error */ ++#define OSI_GET_VMODE_INFO 29 /* mode, depth -- r3 status, r4-r9 pb */ ++#define OSI_GET_MOUSE_DPI 30 /* -- mouse_dpi */ ++ ++#define OSI_SET_VIDEO_POWER 31 ++#define OSI_GET_FB_INFO 32 /* void -- r3 status, r4-r8 video data */ ++ ++#define OSI_SOUND_WRITE 33 ++/* #define OSI_SOUND_FORMAT 34 */ ++#define OSI_SOUND_SET_VOLUME 35 ++#define OSI_SOUND_CNTL 36 ++/* obsolete OSI_SOUND call 37 */ ++ ++#define OSI_VIDEO_ACK_IRQ 38 ++#define OSI_VIDEO_CNTRL 39 ++ ++#define OSI_SOUND_IRQ_ACK 40 ++#define OSI_SOUND_START_STOP 41 ++ ++#define OSI_REGISTER_IRQ 42 /* reg_property[0] appl_int -- irq_cookie */ ++/* obsolete OSI_IRQ 43-46 */ ++ ++#define OSI_LOG_PUTC 47 /* char -- */ ++ ++#define OSI_KBD_CNTRL 50 ++#define OSI_GET_ADB_KEY 51 /* -- adb_keycode (keycode | keycode_id in r4) */ ++ ++#define OSI_WRITE_NVRAM_BYTE 52 /* offs, byte -- */ ++#define OSI_READ_NVRAM_BYTE 53 /* offs -- byte */ ++ ++#define OSI_EXIT 54 ++ ++#define OSI_KEYCODE_TO_ADB 55 /* (keycode | keycode_id) -- adb_keycode */ ++#define OSI_MAP_ADB_KEY 56 /* keycode, adbcode -- */ ++#define OSI_SAVE_KEYMAPPING 57 /* -- */ ++#define OSI_USLEEP 58 /* usecs -- */ ++#define OSI_SET_COLOR 59 /* index value -- */ ++ ++#define OSI_PIC_MASK_IRQ 60 /* irq -- */ ++#define OSI_PIC_UNMASK_IRQ 61 /* irq -- */ ++#define OSI_PIC_ACK_IRQ 62 /* irq mask_flag -- */ ++#define OSI_PIC_GET_ACTIVE_IRQ 63 ++ ++#define OSI_GET_COLOR 64 /* index -- value */ ++ ++/* 65-67 old ablk implementation */ ++#define OSI_IRQTEST 65 ++ ++#define OSI_ENET2_OPEN 68 ++#define OSI_ENET2_CLOSE 69 ++#define OSI_ENET2_CNTRL 70 ++#define OSI_ENET2_RING_SETUP 71 ++#define OSI_ENET2_KICK 72 ++#define OSI_ENET2_GET_HWADDR 73 ++#define OSI_ENET2_IRQ_ACK 74 ++ ++#define OSI_PROM_IFACE 76 ++#define kPromClose 0 ++#define kPromPeer 1 ++#define kPromChild 2 ++#define kPromParent 3 ++#define kPromPackageToPath 4 ++#define kPromGetPropLen 5 ++#define kPromGetProp 6 ++#define kPromNextProp 7 ++#define kPromSetProp 8 ++#define kPromChangePHandle 9 ++ ++#define OSI_PROM_PATH_IFACE 77 ++#define kPromCreateNode 16 ++#define kPromFindDevice 17 ++ ++#define OSI_BOOT_HELPER 78 ++#define kBootHAscii2Unicode 32 ++#define kBootHUnicode2Ascii 33 ++#define kBootHGetStrResInd 34 /* key, buf, len -- buf */ ++#define kBootHGetRAMSize 35 /* -- ramsize */ ++ ++#define OSI_ABLK_RING_SETUP 79 ++#define OSI_ABLK_CNTRL 80 ++#define OSI_ABLK_DISK_INFO 81 ++#define OSI_ABLK_KICK 82 ++#define OSI_ABLK_IRQ_ACK 83 ++#define OSI_ABLK_SYNC_READ 84 ++#define OSI_ABLK_SYNC_WRITE 85 ++#define OSI_ABLK_BLESS_DISK 86 ++ ++#define OSI_EMUACCEL 89 /* EMULATE_xxx, nip -- index */ ++#define OSI_MAPIN_MREGS 90 /* mphys */ ++#define OSI_NVRAM_SIZE 91 ++ ++#define OSI_MTICKS_TO_USECS 92 ++#define OSI_USECS_TO_MTICKS 93 ++ ++/* obsolete OSI_BLK 94-95 */ ++ ++#define OSI_PSEUDO_FS 96 ++#define kPseudoFSOpen 1 ++#define kPseudoFSClose 2 ++#define kPseudoFSGetSize 3 ++#define kPseudoFSRead 4 ++#define kPseudoFSIndex2Name 5 ++ ++#define OSI_TTY_PUTC 97 ++#define OSI_TTY_GETC 98 ++#define OSI_TTY_IRQ_ACK 99 ++ ++#define NUM_OSI_SELECTORS 100 /* remember to increase this... */ ++ ++#endif /* _H_OSI */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/osi_calls.h +@@ -0,0 +1,475 @@ ++/* ++ * Creation Date: <2002/06/16 01:40:57 samuel> ++ * Time-stamp: <2004/02/23 01:04:31 samuel> ++ * ++ * ++ * ++ * OSI call inlines ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_OSI_CALLS ++#define _H_OSI_CALLS ++ ++#include "osi.h" ++ ++/* Old gcc versions have a limit on the number of registers used. ++ * Newer gcc versions (gcc 3.3) require that the clobber list does ++ * not overlap declared registers. ++ */ ++#if __GNUC__ == 2 || ( __GNUC__ == 3 && __GNUC_MINOR__ < 3 ) ++#define SHORT_REGLIST ++#endif ++ ++ ++/************************************************************************/ ++/* OSI call instantiation macros */ ++/************************************************************************/ ++ ++#define dreg(n) __oc_##n __asm__ (#n) ++#define ir(n) "r" (__oc_##n) ++#define rr(n) "=r" (__oc_##n) ++ ++#define _oc_head( input_regs... ) \ ++{ \ ++ int _ret=0; \ ++ { \ ++ register unsigned long dreg(r3); \ ++ register unsigned long dreg(r4); \ ++ register unsigned long dreg(r5) \ ++ ,##input_regs ; ++ ++#define _oc_syscall( number, extra_ret_regs... ) \ ++ __oc_r3 = OSI_SC_MAGIC_R3; \ ++ __oc_r4 = OSI_SC_MAGIC_R4; \ ++ __oc_r5 = number; \ ++ __asm__ __volatile__ ( \ ++ "sc " : rr(r3) ,## extra_ret_regs ++ ++#define _oc_input( regs... ) \ ++ : ir(r3), ir(r4), ir(r5) \ ++ , ## regs \ ++ : "memory" ); ++ ++/* the tail memory clobber is necessary since we violate the strict ++ * aliasing rules when we return structs through the registers. ++ */ ++#define _oc_tail \ ++ asm volatile ( "" : : : "memory" ); \ ++ _ret = __oc_r3; \ ++ } \ ++ return _ret; \ ++} ++ ++ ++/************************************************************************/ ++/* Alternatives */ ++/************************************************************************/ ++ ++#ifdef SHORT_REGLIST ++#ifdef __linux__ ++#define _oc_syscall_r10w6( number, inputregs... ) \ ++ __oc_r3 = OSI_SC_MAGIC_R3; \ ++ __oc_r4 = OSI_SC_MAGIC_R4; \ ++ __oc_r5 = number; \ ++ __asm__ __volatile__ ( \ ++ "sc \n" \ ++ "stw 4,0(10) \n" \ ++ "stw 5,4(10) \n" \ ++ "stw 6,8(10) \n" \ ++ "stw 7,12(10) \n" \ ++ "stw 8,16(10) \n" \ ++ "stw 9,20(10) \n" \ ++ : rr(r3) \ ++ : ir(r3), ir(r4), ir(r5), ir(r10) \ ++ ,## inputregs \ ++ : "memory", \ ++ "r4", "r5", "r6", "r7", "r8", "r9" ); ++#endif ++#ifdef __darwin__ ++#define _oc_syscall_r10w6( number, inputregs... ) \ ++ __oc_r3 = OSI_SC_MAGIC_R3; \ ++ __oc_r4 = OSI_SC_MAGIC_R4; \ ++ __oc_r5 = number; \ ++ __asm__ __volatile__ ( \ ++ "sc \n" \ ++ "stw r4,0(r10) \n" \ ++ "stw r5,4(r10) \n" \ ++ "stw r6,8(r10) \n" \ ++ "stw r7,12(r10) \n" \ ++ "stw r8,16(r10) \n" \ ++ "stw r9,20(r10) \n" \ ++ : rr(r3) \ ++ : ir(r3), ir(r4), ir(r5), ir(r10) \ ++ ,## inputregs \ ++ : "memory", \ ++ "r4", "r5", "r6", "r7", "r8", "r9" ); ++#endif ++#endif ++ ++ ++/************************************************************************/ ++/* Common helper functions */ ++/************************************************************************/ ++ ++#define _osi_call0( type, name, number ) \ ++type name( void ) \ ++ _oc_head() \ ++ _oc_syscall( number ) \ ++ _oc_input() \ ++ _oc_tail ++ ++#define _osi_call1( type, name, number, type1, arg1 ) \ ++type name( type1 arg1 ) \ ++ _oc_head( dreg(r6) ) \ ++ __oc_r6 = (ulong)arg1; \ ++ _oc_syscall( number ) \ ++ _oc_input( ir(r6) ) \ ++ _oc_tail ++ ++#define _osi_call2( type, name, number, t1, a1, t2, a2 ) \ ++type name( t1 a1, t2 a2 ) \ ++ _oc_head( dreg(r6), dreg(r7) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ _oc_syscall( number ) \ ++ _oc_input( ir(r6), ir(r7) ) \ ++ _oc_tail ++ ++#define _osi_call3( type, name, number, t1, a1, t2, a2, t3, a3 ) \ ++type name( t1 a1, t2 a2, t3 a3 ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r8) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ __oc_r8 = (ulong)a3; \ ++ _oc_syscall( number ) \ ++ _oc_input( ir(r6), ir(r7), ir(r8) ) \ ++ _oc_tail ++ ++#define _osi_call4( type, name, number, t1, a1, t2, a2, t3, a3, t4, a4 ) \ ++type name( t1 a1, t2 a2, t3 a3, t4 a4 ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ __oc_r8 = (ulong)a3; \ ++ __oc_r9 = (ulong)a4; \ ++ _oc_syscall( number ) \ ++ _oc_input( ir(r6), ir(r7), ir(r8), ir(r9) ) \ ++ _oc_tail ++ ++#define _osi_call5( type, name, number, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5 ) \ ++type name( t1 a1, t2 a2, t3 a3, t4 a4, t5 a5 ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9), dreg(r10) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ __oc_r8 = (ulong)a3; \ ++ __oc_r9 = (ulong)a4; \ ++ __oc_r10 = (ulong)a5; \ ++ _oc_syscall( number ) \ ++ _oc_input( ir(r6), ir(r7), ir(r8), ir(r9), ir(r10) ) \ ++ _oc_tail ++ ++#define _osi_call6( type, name, number, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6 ) \ ++type name( t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6 ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9), dreg(r10), dreg(r11) )\ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ __oc_r8 = (ulong)a3; \ ++ __oc_r9 = (ulong)a4; \ ++ __oc_r10 = (ulong)a5; \ ++ __oc_r11 = (ulong)a6; \ ++ _oc_syscall( number ) \ ++ _oc_input( ir(r6), ir(r7), ir(r8), ir(r9), ir(r10), ir(r11) ) \ ++ _oc_tail ++ ++ ++/************************************************************************/ ++/* Special */ ++/************************************************************************/ ++ ++/* r4 returned in retarg1 pointer */ ++#define _osi_call0_w1( type, name, number, type1, retarg1 ) \ ++type name( type1 retarg1 ) \ ++ _oc_head() \ ++ _oc_syscall( number, rr(r4) ) \ ++ _oc_input() \ ++ *retarg1 = __oc_r4; \ ++ _oc_tail ++ ++#define _osi_call0_w2( type, name, number, type1, retarg1 ) \ ++type name( type1 retarg1 ) \ ++ _oc_head() \ ++ _oc_syscall( number, rr(r4), rr(r5) ) \ ++ _oc_input() \ ++ ((ulong*)retarg1)[0] = __oc_r4; \ ++ ((ulong*)retarg1)[1] = __oc_r5; \ ++ _oc_tail ++ ++/* r4-r8 returned in retarg1 pointer */ ++#define _osi_call0_w5( type, name, number, type1, retarg1 ) \ ++type name( type1 retarg1 ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r8) ) \ ++ _oc_syscall( number, \ ++ rr(r4), rr(r5), rr(r6), rr(r7), rr(r8) ) \ ++ _oc_input() \ ++ ((ulong*)retarg1)[0] = __oc_r4; \ ++ ((ulong*)retarg1)[1] = __oc_r5; \ ++ ((ulong*)retarg1)[2] = __oc_r6; \ ++ ((ulong*)retarg1)[3] = __oc_r7; \ ++ ((ulong*)retarg1)[4] = __oc_r8; \ ++ _oc_tail ++ ++/* r4 returned in retarg pointer */ ++#define _osi_call1_w1( type, name, number, t1, a1, t2, retarg ) \ ++type name( t1 a1, t2 retarg ) \ ++ _oc_head( dreg(r6) ) \ ++ __oc_r6 = (ulong)a1; \ ++ _oc_syscall( number, rr(r4) ) \ ++ _oc_input( ir(r6) ) \ ++ ((ulong*)retarg)[0] = __oc_r4; \ ++ _oc_tail ++ ++/* r4,r5 returned in retarg1, retarg2 */ ++#define _osi_call1_w1w1( type, name, number, t1, a1, t2, retarg1, t3, retarg2 ) \ ++type name( t1 a1, t2 retarg1, t3 retarg2 ) \ ++ _oc_head( dreg(r6) ) \ ++ __oc_r6 = (ulong)a1; \ ++ _oc_syscall( number, rr(r4), rr(r5) ) \ ++ _oc_input( ir(r6) ) \ ++ ((ulong*)retarg1)[0] = __oc_r4; \ ++ ((ulong*)retarg2)[0] = __oc_r5; \ ++ _oc_tail ++ ++/* r4,r5 returned in retarg1, retarg2, retarg3 */ ++#define _osi_call1_w1w1w1( type, name, number, t1, a1, t2, retarg1, t3, retarg2, t4, retarg3 ) \ ++type name( t1 a1, t2 retarg1, t3 retarg2, t4 retarg3 ) \ ++ _oc_head( dreg(r6) ) \ ++ __oc_r6 = (ulong)a1; \ ++ _oc_syscall( number, rr(r4), rr(r5), rr(r6) ) \ ++ _oc_input( ir(r6) ) \ ++ ((ulong*)retarg1)[0] = __oc_r4; \ ++ ((ulong*)retarg2)[0] = __oc_r5; \ ++ ((ulong*)retarg3)[0] = __oc_r6; \ ++ _oc_tail ++ ++/* r4,r5 returned in retarg pointer */ ++#define _osi_call1_w2( type, name, number, t1, a1, t2, retarg ) \ ++type name( t1 a1, t2 retarg ) \ ++ _oc_head( dreg(r6) ) \ ++ __oc_r6 = (ulong)a1; \ ++ _oc_syscall( number, rr(r4), rr(r5) ) \ ++ _oc_input( ir(r6) ) \ ++ ((ulong*)retarg)[0] = __oc_r4; \ ++ ((ulong*)retarg)[1] = __oc_r5; \ ++ _oc_tail ++ ++/* r4-r7 returned in retarg pointer */ ++#define _osi_call1_w4( type, name, number, t1, a1, t2, retarg ) \ ++type name( t1 a1, t2 retarg ) \ ++ _oc_head( dreg(r6), dreg(r7) ) \ ++ __oc_r6 = (ulong)a1; \ ++ _oc_syscall( number, rr(r4), rr(r5), rr(r6), rr(r7) ) \ ++ _oc_input( ir(r6) ) \ ++ ((ulong*)retarg)[0] = __oc_r4; \ ++ ((ulong*)retarg)[1] = __oc_r5; \ ++ ((ulong*)retarg)[2] = __oc_r6; \ ++ ((ulong*)retarg)[3] = __oc_r7; \ ++ _oc_tail ++ ++ ++/* r4-r5 returned in retarg pointer */ ++#define _osi_call2_w2( type, name, number, t1, a1, t2, a2, t3, retarg ) \ ++type name( t1 a1, t2 a2, t3 retarg ) \ ++ _oc_head( dreg(r6), dreg(r7) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ _oc_syscall( number, rr(r4), rr(r5) ) \ ++ _oc_input( ir(r6), ir(r7) ) \ ++ ((ulong*)retarg)[0] = __oc_r4; \ ++ ((ulong*)retarg)[1] = __oc_r5; \ ++ _oc_tail ++ ++/* r4-r7 returned in retarg pointer */ ++#define _osi_call2_w4( type, name, number, t1, a1, t2, a2, t3, retarg ) \ ++type name( t1 a1, t2 a2, t3 retarg ) \ ++ _oc_head( dreg(r6), dreg(r7) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ _oc_syscall( number, rr(r4), rr(r5), rr(r6), rr(r7) ) \ ++ _oc_input( ir(r6), ir(r7) ) \ ++ ((ulong*)retarg)[0] = __oc_r4; \ ++ ((ulong*)retarg)[1] = __oc_r5; \ ++ ((ulong*)retarg)[2] = __oc_r6; \ ++ ((ulong*)retarg)[3] = __oc_r7; \ ++ _oc_tail ++ ++#ifdef SHORT_REGLIST ++/* r4-r9 returned in retarg pointer */ ++#define _osi_call2_w6( type, name, number, t1, a1, t2, a2, t3, retarg ) \ ++type name( t1 a1, t2 a2, t3 retarg ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r10) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ __oc_r10 = (ulong)retarg; \ ++ _oc_syscall_r10w6( number, ir(r6), ir(r7) ) \ ++ _oc_tail ++ ++#else /* SHORT_REGLIST */ ++ ++/* r4-r9 returned in retarg pointer */ ++#define _osi_call2_w6( type, name, number, t1, a1, t2, a2, t3, retarg ) \ ++type name( t1 a1, t2 a2, t3 retarg ) \ ++ _oc_head( dreg(r6), dreg(r7), dreg(r8), dreg(r9) ) \ ++ __oc_r6 = (ulong)a1; \ ++ __oc_r7 = (ulong)a2; \ ++ _oc_syscall( number, rr(r4), rr(r5), rr(r6), rr(r7), rr(r8), rr(r9) ) \ ++ _oc_input( ir(r6), ir(r7) ) \ ++ ((ulong*)retarg)[0] = __oc_r4; \ ++ ((ulong*)retarg)[1] = __oc_r5; \ ++ ((ulong*)retarg)[2] = __oc_r6; \ ++ ((ulong*)retarg)[3] = __oc_r7; \ ++ ((ulong*)retarg)[4] = __oc_r8; \ ++ ((ulong*)retarg)[5] = __oc_r9; \ ++ _oc_tail ++ ++#endif /* SHORT_REGLIST */ ++ ++ ++/************************************************************************/ ++/* OSI call inlines */ ++/************************************************************************/ ++ ++static inline _osi_call1( int, OSI_CallAvailable, OSI_CALL_AVAILABLE, int, osi_num ); ++ ++static inline _osi_call1( int, OSI_PutC, OSI_LOG_PUTC, int, ch ); ++ ++static inline _osi_call1( int, OSI_Debugger, OSI_DEBUGGER, int, num ); ++static inline _osi_call0( int, OSI_Exit, OSI_EXIT ); ++ ++/* misc */ ++static inline _osi_call0( ulong, OSI_GetLocalTime, OSI_GET_LOCALTIME ); ++static inline _osi_call0( ulong, OSI_GetGMTTime, OSI_GET_GMT_TIME ); ++static inline _osi_call1( int, OSI_USleep, OSI_USLEEP, int, usecs ); ++ ++/* NVRAM */ ++static inline _osi_call0( int, OSI_NVRamSize, OSI_NVRAM_SIZE ); ++static inline _osi_call1( int, OSI_ReadNVRamByte, OSI_READ_NVRAM_BYTE, int, offs ); ++static inline _osi_call2( int, OSI_WriteNVRamByte, OSI_WRITE_NVRAM_BYTE, int, offs, ++ unsigned char, ch ); ++ ++/* keyboard stuff */ ++static inline _osi_call0_w1( int, OSI_GetAdbKey2, OSI_GET_ADB_KEY, int *, raw_key ); ++static inline _osi_call1( int, OSI_KbdCntrl, OSI_KBD_CNTRL, int, cmd ); ++ ++static inline int OSI_GetAdbKey( void ) ++ { int dummy_raw_key; return OSI_GetAdbKey2( &dummy_raw_key ); } ++static inline _osi_call2( int, OSI_MapAdbKey, OSI_MAP_ADB_KEY, int, keycode, int, adbkey ) ++static inline _osi_call1( int, OSI_KeycodeToAdb, OSI_KEYCODE_TO_ADB, int, keycode ); ++static inline _osi_call0( int, OSI_SaveKeymapping, OSI_SAVE_KEYMAPPING ); ++ ++/* mouse support */ ++struct osi_mouse; ++static inline _osi_call0_w5( int, OSI_GetMouse, OSI_GET_MOUSE, struct osi_mouse *, ret ); ++static inline _osi_call0( int, OSI_GetMouseDPI, OSI_GET_MOUSE_DPI ); ++ ++/* video */ ++static inline _osi_call2( int, OSI_SetVMode_, OSI_SET_VMODE, int, mode, int, depth_mode ); ++struct osi_get_vmode_info; ++static inline _osi_call2_w6( int, OSI_GetVModeInfo_, OSI_GET_VMODE_INFO, int, mode, int, depth_mode, ++ struct osi_get_vmode_info *, ret ); ++static inline _osi_call1( int, OSI_SetVPowerState, OSI_SET_VIDEO_POWER, int, power_state ); ++static inline _osi_call2( int, OSI_SetColor, OSI_SET_COLOR, int, index, int, rgb ); ++static inline _osi_call0_w1( int, OSI_VideoAckIRQ, OSI_VIDEO_ACK_IRQ, int *, events ); ++ ++static inline void OSI_RefreshPalette( void ) { OSI_SetColor(-1,0); } ++ ++/* PIC (mac-io replacement) */ ++static inline _osi_call1( int, OSI_PICMaskIRQ, OSI_PIC_MASK_IRQ, int, irq ); ++static inline _osi_call1( int, OSI_PICUnmaskIRQ, OSI_PIC_UNMASK_IRQ, int, irq ); ++static inline _osi_call2( int, OSI_PICAckIRQ, OSI_PIC_ACK_IRQ, int, irq, int, mask_it ); ++static inline _osi_call0( int, OSI_PICGetActiveIRQ, OSI_PIC_GET_ACTIVE_IRQ ); ++ ++/* sound */ ++static inline _osi_call1( int, OSI_SoundCntl, OSI_SOUND_CNTL, int, cmd ); ++static inline _osi_call2( int, OSI_SoundCntl1, OSI_SOUND_CNTL, int, cmd, int, p1 ); ++static inline _osi_call3( int, OSI_SoundCntl2, OSI_SOUND_CNTL, int, cmd, int, p1, int, p2 ); ++static inline _osi_call0_w2( int, OSI_SoundIRQAck, OSI_SOUND_IRQ_ACK, ulong *, timestamp ); ++static inline _osi_call3( int, OSI_SoundWrite, OSI_SOUND_WRITE, int, physbuf, int, len, int, restart ); ++static inline _osi_call3( int, OSI_SoundSetVolume, OSI_SOUND_SET_VOLUME, int, hwvol, int, speakervol, int, mute ); ++ ++/* async block driver */ ++struct ablk_disk_info; ++static inline _osi_call2_w4( int, OSI_ABlkDiskInfo, OSI_ABLK_DISK_INFO, int, channel, int, unit, ++ struct ablk_disk_info *, retinfo ); ++static inline _osi_call1( int, OSI_ABlkKick, OSI_ABLK_KICK, int, channel ); ++static inline _osi_call1_w1w1w1( int, OSI_ABlkIRQAck, OSI_ABLK_IRQ_ACK, int, channel, int *, req_count, ++ int *, active, int *, events ); ++static inline _osi_call3( int, OSI_ABlkRingSetup, OSI_ABLK_RING_SETUP, int, channel, int, mphys, int, n_el ); ++static inline _osi_call2( int, OSI_ABlkCntrl, OSI_ABLK_CNTRL, int, channel, int, cmd ); ++static inline _osi_call3( int, OSI_ABlkCntrl1, OSI_ABLK_CNTRL, int, channel, int, cmd, int, param ); ++static inline _osi_call5( int, OSI_ABlkSyncRead, OSI_ABLK_SYNC_READ, int, channel, int, unit, ++ int, blk, ulong, mphys, int, size ); ++static inline _osi_call5( int, OSI_ABlkSyncWrite, OSI_ABLK_SYNC_WRITE, int, channel, int, unit, ++ int, blk, ulong, mphys, int, size ); ++static inline _osi_call2( int, OSI_ABlkBlessDisk, OSI_ABLK_BLESS_DISK, int, channel, int, unit ); ++ ++static inline _osi_call0( int, OSI_CMountDrvVol, OSI_CMOUNT_DRV_VOL ); ++ ++/* enet2 */ ++static inline _osi_call0( int, OSI_Enet2Open, OSI_ENET2_OPEN ); ++static inline _osi_call0( int, OSI_Enet2Close, OSI_ENET2_CLOSE ); ++static inline _osi_call3( int, OSI_Enet2RingSetup, OSI_ENET2_RING_SETUP, int, which_ring, ++ int, ring_mphys, int, n_el ); ++static inline _osi_call2( int, OSI_Enet2Cntrl1, OSI_ENET2_CNTRL, int, cmd, int, param ); ++static inline _osi_call1( int, OSI_Enet2Cntrl, OSI_ENET2_CNTRL, int, cmd ); ++static inline _osi_call0( int, OSI_Enet2Kick, OSI_ENET2_KICK ); ++ ++static inline _osi_call0_w2( int, OSI_Enet2GetHWAddr__, OSI_ENET2_GET_HWADDR, ulong *, retbuf ); ++static inline int OSI_Enet2GetHWAddr( unsigned char *addr ) { ++ int ret; ++ ulong buf[2]; ++ ++ ret = OSI_Enet2GetHWAddr__( buf ); ++ ++ ((ulong*)addr)[0] = buf[0]; ++ ((ushort*)addr)[2] = (buf[1] >> 16); ++ return ret; ++} ++static inline _osi_call2( int, OSI_Enet2IRQAck, OSI_ENET2_IRQ_ACK, int, irq_enable, int, rx_head ); ++ ++/* PROM (device-tree) */ ++static inline _osi_call2( int, OSI_PromIface, OSI_PROM_IFACE, int, what, int, ph ); ++static inline _osi_call3( int, OSI_PromIface1, OSI_PROM_IFACE, int, what, int, ph, int, p1 ); ++static inline _osi_call4( int, OSI_PromIface2, OSI_PROM_IFACE, int, what, int, ph, int, p1, int, p2 ); ++static inline _osi_call5( int, OSI_PromIface3, OSI_PROM_IFACE, int, what, int, ph, int, p1, int, p2, int, p3 ); ++static inline _osi_call2( int, OSI_PromPathIface, OSI_PROM_PATH_IFACE, int, what, const char *, p ); ++ ++/* emulation acceleration */ ++static inline _osi_call1( int, OSI_MapinMregs, OSI_MAPIN_MREGS, ulong, mphys ); ++static inline _osi_call3( int, OSI_EmuAccel, OSI_EMUACCEL, int, emuaccel_flags, int, param, int, inst_addr ); ++ ++/* timer frequency */ ++static inline _osi_call1( int, OSI_MticksToUsecs, OSI_MTICKS_TO_USECS, ulong, mticks ); ++static inline _osi_call1( int, OSI_UsecsToMticks, OSI_USECS_TO_MTICKS, ulong, usecs ); ++ ++/* fb info */ ++struct osi_fb_info; ++static inline _osi_call0_w5( int, OSI_GetFBInfo, OSI_GET_FB_INFO, struct osi_fb_info *, retinfo ); ++ ++/* SCSI */ ++static inline _osi_call0( int, OSI_SCSIAck, OSI_SCSI_ACK ); ++static inline _osi_call1( int, OSI_SCSISubmit, OSI_SCSI_SUBMIT, int, req_mphys ); ++static inline _osi_call2( int, OSI_SCSIControl, OSI_SCSI_CNTRL, int, sel, int, param ); ++ ++/* TTY */ ++static inline _osi_call0( int, OSI_TTYGetc, OSI_TTY_GETC ); ++static inline _osi_call1( int, OSI_TTYPutc, OSI_TTY_PUTC, int, ch ); ++static inline _osi_call0( int, OSI_TTYIRQAck, OSI_TTY_IRQ_ACK ); ++ ++#endif /* _H_OSI_CALLS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/performance.h +@@ -0,0 +1,71 @@ ++/* ++ * Creation Date: <2001/04/01 00:44:40 samuel> ++ * Time-stamp: <2003/01/27 02:42:03 samuel> ++ * ++ * ++ * ++ * performance counters ++ * ++ * Copyright (C) 2001, 2002 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_PERFORMANCE ++#define _H_PERFORMANCE ++ ++typedef struct { ++ char *name; ++ unsigned long *ctrptr; ++} perf_info_t; ++ ++extern perf_info_t g_perf_info_table[]; ++ ++#if defined(PERFORMANCE_INFO) && !defined(PERFORMANCE_INFO_LIGHT) ++#define BUMP(x) do { extern int gPerf__##x; gPerf__##x++; } while(0) ++#define BUMP_N(x,n) do { extern int gPerf__##x; gPerf__##x+=(n); } while(0) ++#else ++#define BUMP(x) do {} while(0) ++#define BUMP_N(x,n) do {} while(0) ++#endif ++ ++ ++/************************************************************************/ ++/* tick counters */ ++/************************************************************************/ ++ ++#ifdef PERFORMANCE_INFO ++ ++#define TICK_CNTR_PUSH( kv ) do { \ ++ int ind = (kv)->num_acntrs; \ ++ acc_counter_t *c = &(kv)->acntrs[ind]; \ ++ if( ind < MAX_ACC_CNTR_DEPTH ) { \ ++ c->subticks=0; \ ++ (kv)->num_acntrs++; \ ++ asm volatile( "mftb %0" : "=r" (c->stamp) : ); \ ++ } \ ++} while(0) ++ ++#define TICK_CNTR_POP( kv, name ) do { \ ++ int ind = (kv)->num_acntrs; \ ++ ulong now, ticks; \ ++ asm volatile( "mftb %0" : "=r" (now) : ); \ ++ if( --ind >= 0 ) { \ ++ acc_counter_t *c = &(kv)->acntrs[ind]; \ ++ (kv)->num_acntrs = ind; \ ++ ticks = now - c->stamp - c->subticks; \ ++ BUMP_N( name##_ticks, ticks ); \ ++ if( ind ) \ ++ (kv)->acntrs[ind-1].subticks += ticks; \ ++ } \ ++} while(0) ++ ++#else ++#define TICK_CNTR_PUSH( kv ) do {} while(0) ++#define TICK_CNTR_POP( kv, name ) do {} while(0) ++#endif ++ ++#endif /* _H_PERFORMANCE */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/platform.h +@@ -0,0 +1,73 @@ ++/* ++ * Creation Date: <2001/12/29 19:46:46 samuel> ++ * Time-stamp: <2004/02/07 16:51:57 samuel> ++ * ++ * ++ * ++ * Misc definitions needed on certain platforms ++ * ++ * Copyright (C) 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_PLATFORM ++#define _H_PLATFORM ++ ++#ifndef NULL ++#define NULL 0 ++#endif /* NULL */ ++ ++typedef unsigned long long ullong; ++typedef long long llong; ++ ++typedef signed char s8; ++typedef unsigned char u8; ++typedef signed short s16; ++typedef unsigned short u16; ++typedef signed int s32; ++typedef unsigned int u32; ++typedef signed long long s64; ++typedef unsigned long long u64; ++ ++#define TO_ULLONG( hi, lo ) (((ullong)(hi)<< 32 ) | (lo) ) ++#define TO_LLONG( hi, lo ) (((llong)(hi)<< 32 ) | (lo) ) ++ ++#ifndef TEMP_FAILURE_RETRY ++# define TEMP_FAILURE_RETRY(expression) \ ++ (__extension__ \ ++ ({ long int __result; \ ++ do __result = (long int) (expression); \ ++ while (__result == -1L && errno == EINTR); \ ++ __result; })) ++#endif ++ ++/* ++ * Allow us to mark functions as 'deprecated' and have gcc emit a nice ++ * warning for each use, in hopes of speeding the functions removal. ++ * Usage is: ++ * int __deprecated foo(void) ++ */ ++#if __GNUC__ == 2 && __GNUC_MINOR__ < 96 ++#define __builtin_expect(x, expected_value) (x) ++#endif ++ ++#define likely(x) __builtin_expect((x),1) ++#define unlikely(x) __builtin_expect((x),0) ++ ++#ifndef HAVE_CLEARENV ++static inline int clearenv( void ) { extern char **environ; environ=NULL; return 0; } ++#endif ++ ++#ifdef __darwin__ ++#define ARCH_STR "osx" ++#endif ++ ++#ifdef __linux__ ++#define ARCH_STR "linux" ++#endif ++ ++#endif /* _H_PLATFORM */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/processor.h +@@ -0,0 +1,409 @@ ++/* ++ * Creation Date: <2000/10/29 01:43:29 samuel> ++ * Time-stamp: <2003/07/27 22:37:49 samuel> ++ * ++ * ++ * ++ * Extract from ++ * ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_PROCESSOR ++#define _H_PROCESSOR ++ ++ ++#define PTE0_VSID(s) (((s)>>7) & 0xffffff) ++#define PTE0_V BIT(0) ++#define PTE0_H BIT(25) ++#define PTE0_API 0x3f ++ ++#define PTE1_R BIT(23) ++#define PTE1_C BIT(24) ++#define PTE1_W BIT(25) ++#define PTE1_I BIT(26) ++#define PTE1_M BIT(27) ++#define PTE1_G BIT(28) ++#ifdef CONFIG_AMIGAONE ++/* Memory coherence locks up A1 compatible systems. */ ++#define PTE1_WIMG (PTE1_W | PTE1_I | PTE1_G) ++#else ++#define PTE1_WIMG (PTE1_W | PTE1_I | PTE1_M | PTE1_G) ++#endif ++#define PTE1_PP 0x3 ++#define PTE1_RPN (~0xfffUL) ++ ++#define VSID_Ks BIT(1) ++#define VSID_Kp BIT(2) ++#define VSID_N BIT(3) ++ ++ ++ ++#ifndef MSR_VEC ++ ++#define MSR_VEC (1<<25) /* 6: Enable AltiVec */ ++#define MSR_POW (1<<18) /* 13: Enable Power Management */ ++#define MSR_TGPR (1<<17) /* 14: TLB Update registers in use */ ++#define MSR_ILE (1<<16) /* 15: Interrupt Little Endian */ ++#define MSR_EE (1<<15) /* 16: External Interrupt Enable */ ++#define MSR_PR (1<<14) /* 17: Privilege Level */ ++#define MSR_FP (1<<13) /* 18: Floating Point enable */ ++#define MSR_ME (1<<12) /* 19: Machine Check Enable */ ++#define MSR_FE0 (1<<11) /* 20: Floating Exception mode 0 */ ++#define MSR_SE (1<<10) /* 21: Single Step */ ++#define MSR_BE (1<<9) /* 22: Branch Trace */ ++#define MSR_FE1 (1<<8) /* 23: Floating Exception mode 1 */ ++#define MSR_IP (1<<6) /* 25: Exception prefix 0x000/0xFFF */ ++#define MSR_IR (1<<5) /* 26: Instruction Relocate */ ++#define MSR_DR (1<<4) /* 27: Data Relocate */ ++#define MSR_PE (1<<2) /* 29: Performance Monitor Flag */ ++#define MSR_RI (1<<1) /* 30: Recoverable Exception */ ++#define MSR_LE (1<<0) /* 31: Little Endian */ ++ ++#endif /* MSR_VEC */ ++ ++#ifndef S_SPRG0 ++ ++#define NUM_SPRS 1024 ++//#define S_XER 1 ++#define S_RTCU_R 4 /* 601 RTC Upper/Lower (Reading) */ ++#define S_RTCL_R 5 ++//#define S_LR 8 ++//#define S_CTR 9 ++#define S_DSISR 18 /* Source Instruction Service Register */ ++#define S_DAR 19 /* Data Address Register */ ++#define S_RTCU_W 20 /* 601 RTC Upper/Lower (Writing) */ ++#define S_RTCL_W 21 ++#define S_DEC 22 /* Decrementer Register */ ++#define S_SDR1 25 /* Table Search Description Register */ ++#define S_SRR0 26 /* Save and Restore Register 0 */ ++#define S_SRR1 27 /* Save and Restore Register 1 */ ++#define S_VRSAVE 256 /* (AltiVec) Vector Register Save Register */ ++#define S_TBRL 268 /* Time base Upper/Lower (Reading) */ ++#define S_TBRU 269 ++#define S_SPRG0 272 /* SPR General 0-3 */ ++#define S_SPRG1 273 ++#define S_SPRG2 274 ++#define S_SPRG3 275 ++#define S_SPRG4 276 /* SPR General 4-7 (7445/7455) */ ++#define S_SPRG5 277 ++#define S_SPRG6 278 ++#define S_SPRG7 279 ++#define S_EAR 282 /* External Access Register */ ++#define S_TBWL 284 /* Time base Upper/Lower (Writing) */ ++#define S_TBWU 285 ++#define S_PVR 287 /* Processor Version Register */ ++#define S_IBAT0U 528 ++#define S_IBAT0L 529 ++#define S_IBAT1U 530 ++#define S_IBAT1L 531 ++#define S_IBAT2U 532 ++#define S_IBAT2L 533 ++#define S_IBAT3U 534 ++#define S_IBAT3L 535 ++#define S_DBAT0U 536 ++#define S_DBAT0L 537 ++#define S_DBAT1U 538 ++#define S_DBAT1L 539 ++#define S_DBAT2U 540 ++#define S_DBAT2L 541 ++#define S_DBAT3U 542 ++#define S_DBAT3L 543 ++#define S_UMMCR2 928 ++#define S_UPMC5 929 /* User Performance Monitor Counter Register */ ++#define S_UPMC6 930 ++#define S_UBAMR 935 ++#define S_UMMCR0 936 /* User Monitor Mode Control Register */ ++#define S_UPMC1 937 ++#define S_UPMC2 938 ++#define S_USIAR 939 /* User Sampled Instruction Address Register */ ++#define S_UMMCR1 940 ++#define S_UPMC3 941 ++#define S_UPMC4 942 /* User Performance Monitor Counter Register 4 */ ++#define S_USDAR 943 /* User Sampled Data Address Register */ ++#define S_MMCR2 944 /* Monitor Mode Control Register */ ++#define S_PMC5 945 ++#define S_PMC6 946 ++#define S_BAMR 951 /* Breakpoint Address Mask Register (74xx) */ ++#define S_MMCR0 952 /* Monitor Mode Control Register 0 */ ++#define S_PMC1 953 /* Performance Counter Register */ ++#define S_PMC2 954 ++#define S_SIAR 955 /* Sampled Instruction Address Register */ ++#define S_MMCR1 956 ++#define S_PMC3 957 ++#define S_PMC4 958 ++#define S_SDAR 959 /* Sampled Data Address Register */ ++#define S_DMISS 976 /* 603 */ ++#define S_DCMP 977 /* 603 */ ++#define S_HASH1 978 /* 603 */ ++#define S_HASH2 979 /* 603 */ ++#define S_IMISS 980 /* 603 */ ++#define S_TLBMISS 980 /* 7445/7455 */ ++#define S_ICMP 981 /* 603 */ ++#define S_PTEHI 981 /* 7445/7455 */ ++#define S_RPA 982 /* 603 */ ++#define S_PTELO 982 /* 7445/7455 */ ++#define S_L3PM 983 /* L3 Private Memory Address Control Register */ ++#define S_L3ITCR0 984 /* ??? */ ++#define S_L3OHCR 1000 /* ??? */ ++#define S_L3ITCR1 1001 /* ??? */ ++#define S_L3ITCR2 1002 /* ??? */ ++#define S_L3ITCR3 1003 /* ??? */ ++#define S_HID0 1008 /* Hardware Implementation Registers */ ++#define S_HID1 1009 ++#define S_HID2 1010 ++#define S_IABR S_HID2 /* HID2 - Instruction Address Breakpoint Register */ ++#define S_ICTRL 1011 /* HID3 - Instruction Cache & Interrupt control reg */ ++#define S_HID4 1012 /* HID4 - Instruction Address Compare 1 (?) */ ++#define S_HID5 1013 ++#define S_DABR S_HID5 /* HID5 - Data Address Breakpoint */ ++#define S_MSSCR0 1014 /* HID6 - Memory Subsystem Control Register 0 */ ++#define S_MSSCR1 1015 /* HID7 - Memory Subsystem Control Register 1 */ ++#define S_LDSTCR 1016 /* HID8 - Load/Store Control Register */ ++#define S_L2CR 1017 /* HID9 - Level 2 Cache Control Regsiter */ ++#define S_L3CR 1018 /* HID10 - Level 3 Cache Control Regsiter (7450) */ ++#define S_HID11 1019 ++#define S_ICTC S_HID11 /* HID11 - Instruction Cache Throttling Control Reg */ ++#define S_ICCR S_HID11 /* Instruction Cache Cacheability Reigster */ ++#define S_THRM1 1020 /* HID12 - Thermal Management Register 1 */ ++#define S_THRM2 1021 /* HID13 - Thermal Management Register 2 */ ++#define S_THRM3 1022 /* HID14 - Thermal Management Register 3 */ ++#define S_HID15 1023 ++#define S_PIR S_HID15 /* HID15 - Processor Identification Register */ ++ ++#endif /* S_SPRG0 */ ++ ++/* the kernel might define these too... */ ++#if !defined(__KERNEL__) || defined(__ASSEMBLY__) ++ ++/* Floating Point Status and Control Register (FPSCR) Fields */ ++#define FPSCR_FX 0x80000000 /* FPU exception summary */ ++#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */ ++#define FPSCR_VX 0x20000000 /* Invalid operation summary */ ++#define FPSCR_OX 0x10000000 /* Overflow exception summary */ ++#define FPSCR_UX 0x08000000 /* Underflow exception summary */ ++#define FPSCR_ZX 0x04000000 /* Zero-devide exception summary */ ++#define FPSCR_XX 0x02000000 /* Inexact exception summary */ ++#define FPSCR_VXSNAN 0x01000000 /* Invalid op for SNaN */ ++#define FPSCR_VXISI 0x00800000 /* Invalid op for Inv - Inv */ ++#define FPSCR_VXIDI 0x00400000 /* Invalid op for Inv / Inv */ ++#define FPSCR_VXZDZ 0x00200000 /* Invalid op for Zero / Zero */ ++#define FPSCR_VXIMZ 0x00100000 /* Invalid op for Inv * Zero */ ++#define FPSCR_VXVC 0x00080000 /* Invalid op for Compare */ ++#define FPSCR_FR 0x00040000 /* Fraction rounded */ ++#define FPSCR_FI 0x00020000 /* Fraction inexact */ ++#define FPSCR_FPRF 0x0001f000 /* FPU Result Flags */ ++#define FPSCR_FPCC 0x0000f000 /* FPU Condition Codes */ ++#define FPSCR_VXSOFT 0x00000400 /* Invalid op for software request */ ++#define FPSCR_VXSQRT 0x00000200 /* Invalid op for square root */ ++#define FPSCR_VXCVI 0x00000100 /* Invalid op for integer convert */ ++#define FPSCR_VE 0x00000080 /* Invalid op exception enable */ ++#define FPSCR_OE 0x00000040 /* IEEE overflow exception enable */ ++#define FPSCR_UE 0x00000020 /* IEEE underflow exception enable */ ++#define FPSCR_ZE 0x00000010 /* IEEE zero divide exception enable */ ++#define FPSCR_XE 0x00000008 /* FP inexact exception enable */ ++#define FPSCR_NI 0x00000004 /* FPU non IEEE-Mode */ ++#define FPSCR_RN 0x00000003 /* FPU rounding control */ ++ ++/* SPR_HID0 */ ++#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ ++#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ ++#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ ++#define HID0_SBCLK (1<<27) ++#define HID0_EICE (1<<26) ++#define HID0_ECLK (1<<25) ++#define HID0_PAR (1<<24) ++#define HID0_DOZE (1<<23) ++#define HID0_NAP (1<<22) ++#define HID0_SLEEP (1<<21) ++#define HID0_DPM (1<<20) ++#define HID0_NHR (1<<16) /* Not Hard Reset */ ++#define HID0_ICE (1<<15) /* Instruction Cache Enable */ ++#define HID0_DCE (1<<14) /* Data Cache Enable */ ++#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ ++#define HID0_DLOCK (1<<12) /* Data Cache Lock */ ++#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */ ++#define HID0_DCFI (1<<10) /* Data Cache Flash Invalidate */ ++#define HID0_SPD (1<<9) /* Speculative disable */ ++#define HID0_SGE (1<<7) /* Store Gathering Enable */ ++#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */ ++#define HID0_BTIC (1<<5) /* Branch Target Instruction Cache Enable */ ++#define HID0_ABE (1<<3) /* Address Broadcast Enable */ ++#define HID0_BHT (1<<2) /* Branch History Table Enable */ ++#define HID0_BTCD (1<<1) /* Branch target cache disable */ ++ ++#define L2CR_L2E BIT(0) /* L2 enable */ ++#define L2CR_L2PE BIT(1) /* L2 data parity generation and checking */ ++#define L2CR_L2SIZ_512K BIT(2) ++#define L2CR_L2SIZ_256K BIT(3) ++#define L2CR_L2SIZ_1MB (BIT(2)|BIT(3)) ++#define L2CR_L2CLK_1 BIT(6) /* L2 clock ration */ ++#define L2CR_L2CLK_15 (BIT(6)*2) ++#define L2CR_L2CLK_2 (BIT(6)*4) ++#define L2CR_L2CLK_25 (BIT(6)*5) ++#define L2CR_L2CLK_3 (BIT(6)*6) ++#define L2CR_L2RAM_FT 0 /* flow-through (reg-buf) synchronous SRAM */ ++#define L2CR_L2RAM_PB BIT(7) /* Piplined (reg-reg) synchronous burst SRAM */ ++#define L2CR_L2RAM_PLW (BIT(7)|BIT(8)) /* Piplined (reg-reg) synchronous late-write */ ++#define L2CR_L2DO BIT(9) /* L2 data-only */ ++#define L2CR_L2I BIT(10) /* L2 global invalidate */ ++#define L2CR_L2CTL BIT(11) /* L2 RAM control (ZZ enable, low-power mode) */ ++#define L2CR_L2WT BIT(12) /* L2 write-through */ ++#define L2CR_L2TS BIT(13) /* L2 test support */ ++#define L2CR_L2OH_05 0 /* L2 output hold 0.5 nS */ ++#define L2CR_L2OH_10 BIT(15) /* L2 output hold 1.0 nS */ ++#define L2CR_L2SL BIT(16) /* L2 DLL slow (use if bus freq < 150 MHz) */ ++#define L2CR_L2DF BIT(17) /* L2 differential clock */ ++#define L2CR_L2BYP BIT(18) /* L2 DLL bypass */ ++#define L2CR_L2IP BIT(31) /* L2 global invalidate in progress */ ++ ++/* SPR_THRM1 */ ++#define THRM1_TIN (1 << 31) ++#define THRM1_TIV (1 << 30) ++#define THRM1_THRES(x) ((x&0x7f)<<23) ++#define THRM3_SITV(x) ((x&0x3fff)<<1) ++#define THRM1_TID (1<<2) ++#define THRM1_TIE (1<<1) ++#define THRM1_V (1<<0) ++ ++/* SPR_THRM3 */ ++#define THRM3_E (1<<0) ++ ++/* Processor Version Numbers */ ++ ++#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ ++#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ ++ ++#define PVR_403GA 0x00200000 ++#define PVR_403GB 0x00200100 ++#define PVR_403GC 0x00200200 ++#define PVR_403GCX 0x00201400 ++#define PVR_405GP 0x40110000 ++#define PVR_601 0x00010000 ++#define PVR_602 0x00050000 ++#define PVR_603 0x00030000 ++#define PVR_603e 0x00060000 ++#define PVR_603ev 0x00070000 ++#define PVR_603r 0x00071000 ++#define PVR_604 0x00040000 ++#define PVR_604e 0x00090000 ++#define PVR_604r 0x000A0000 ++#define PVR_620 0x00140000 ++#define PVR_740 0x00080000 ++#define PVR_750 PVR_740 ++#define PVR_740P 0x10080000 ++#define PVR_750P PVR_740P ++#define PVR_821 0x00500000 ++#define PVR_823 PVR_821 ++#define PVR_850 PVR_821 ++#define PVR_860 PVR_821 ++#define PVR_7400 0x000C0000 ++#define PVR_8240 0x00810100 ++#define PVR_8260 PVR_8240 ++ ++/* Vector VSCR register */ ++#define VSCR_NJ 0x10000 ++#define VSCR_SAT 0x1 ++ ++#endif /* __KERNEL__ */ ++ ++ ++#ifdef __ASSEMBLY__ ++ ++#define CTR S_CTR /* Counter Register */ ++#define DAR S_DAR /* Data Address Register */ ++#define DABR S_DABR /* Data Address Breakpoint Register */ ++#define DBAT0L S_DBAT0L /* Data BAT 0 Lower Register */ ++#define DBAT0U S_DBAT0U /* Data BAT 0 Upper Register */ ++#define DBAT1L S_DBAT1L /* Data BAT 1 Lower Register */ ++#define DBAT1U S_DBAT1U /* Data BAT 1 Upper Register */ ++#define DBAT2L S_DBAT2L /* Data BAT 2 Lower Register */ ++#define DBAT2U S_DBAT2U /* Data BAT 2 Upper Register */ ++#define DBAT3L S_DBAT3L /* Data BAT 3 Lower Register */ ++#define DBAT3U S_DBAT3U /* Data BAT 3 Upper Register */ ++#define DCMP S_DCMP /* Data TLB Compare Register */ ++#define DEC S_DEC /* Decrement Register */ ++#define DMISS S_DMISS /* Data TLB Miss Register */ ++#define DSISR S_DSISR /* Data Storage Interrupt Status Register */ ++#define EAR S_EAR /* External Address Register */ ++#define HASH1 S_HASH1 /* Primary Hash Address Register */ ++#define HASH2 S_HASH2 /* Secondary Hash Address Register */ ++#define HID0 S_HID0 /* Hardware Implementation Register 0 */ ++#define HID1 S_HID1 /* Hardware Implementation Register 1 */ ++#define IABR S_IABR /* Instruction Address Breakpoint Register */ ++#define IBAT0L S_IBAT0L /* Instruction BAT 0 Lower Register */ ++#define IBAT0U S_IBAT0U /* Instruction BAT 0 Upper Register */ ++#define IBAT1L S_IBAT1L /* Instruction BAT 1 Lower Register */ ++#define IBAT1U S_IBAT1U /* Instruction BAT 1 Upper Register */ ++#define IBAT2L S_IBAT2L /* Instruction BAT 2 Lower Register */ ++#define IBAT2U S_IBAT2U /* Instruction BAT 2 Upper Register */ ++#define IBAT3L S_IBAT3L /* Instruction BAT 3 Lower Register */ ++#define IBAT3U S_IBAT3U /* Instruction BAT 3 Upper Register */ ++#define ICMP S_ICMP /* Instruction TLB Compare Register */ ++#define IMISS S_IMISS /* Instruction TLB Miss Register */ ++#define IMMR S_IMMR /* PPC 860/821 Internal Memory Map Register */ ++#define L2CR S_L2CR /* PPC 750 L2 control register */ ++#define PVR S_PVR /* Processor Version */ ++#define RPA S_RPA /* Required Physical Address Register */ ++#define SDR1 S_SDR1 /* MMU hash base register */ ++#define SPR0 S_SPRG0 /* Supervisor Private Registers */ ++#define SPR1 S_SPRG1 ++#define SPR2 S_SPRG2 ++#define SPR3 S_SPRG3 ++#define SPRG0 S_SPRG0 ++#define SPRG1 S_SPRG1 ++#define SPRG2 S_SPRG2 ++#define SPRG3 S_SPRG3 ++#define SRR0 S_SRR0 /* Save and Restore Register 0 */ ++#define SRR1 S_SRR1 /* Save and Restore Register 1 */ ++#define TBRL S_STBRL /* Time Base Read Lower Register */ ++#define TBRU S_TBRU /* Time Base Read Upper Register */ ++#define TBWL S_TBWL /* Time Base Write Lower Register */ ++#define TBWU S_TBWU /* Time Base Write Upper Register */ ++#define ICTC S_ICTC ++#define THRM1 S_THRM1 /* Thermal Management Register 1 */ ++#define THRM2 S_THRM2 /* Thermal Management Register 2 */ ++#define THRM3 S_THRM3 /* Thermal Management Register 3 */ ++#define SIAR S_SIAR ++#define SDAR S_SDAR ++#define XER 1 ++ ++#define SR0 0 /* Segment registers */ ++#define SR1 1 ++#define SR2 2 ++#define SR3 3 ++#define SR4 4 ++#define SR5 5 ++#define SR6 6 ++#define SR7 7 ++#define SR8 8 ++#define SR9 9 ++#define SR10 10 ++#define SR11 11 ++#define SR12 12 ++#define SR13 13 ++#define SR14 14 ++#define SR15 15 ++ ++#endif /* __ASSEMBLY__ */ ++ ++/* opcode macros */ ++ ++#define OPCODE_PRIM(n) ( ((ulong)(n)) >> 26 ) ++#define OPCODE_EXT(n) ( (((ulong)(n)) >> 1) & 0x3ff ) ++#define OPCODE(op,op_ext) ( ((op)<<10) + op_ext ) ++ ++#define B1(n) ( (((ulong)(n)) >> 21) & 0x1f ) ++#define B2(n) ( (((ulong)(n)) >> 16) & 0x1f ) ++#define B3(n) ( (((ulong)(n)) >> 11) & 0x1f ) ++ ++#define BD(n) ((ulong)((n) & 0x7fff) + (((n) & 0x8000) ? (ulong)0xffff8000 : 0)) ++ ++#define SPRNUM_FLIP( v ) ( (((v)>>5) & 0x1f) | (((v)<<5) & 0x3e0) ) ++ ++#endif /* _H_PROCESSOR */ ++ +--- /dev/null ++++ b/drivers/macintosh/mol/include/prom.h +@@ -0,0 +1,46 @@ ++/* ++ * Creation Date: <1999/02/22 23:22:17 samuel> ++ * Time-stamp: <2003/06/02 16:17:36 samuel> ++ * ++ * ++ * ++ * OF device tree structs ++ * ++ * Copyright (C) 1999, 2000, 2002, 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_PROM ++#define _H_PROM ++ ++typedef void *p_phandle_t; ++ ++typedef struct { ++ int nirq; ++ int irq[5]; ++ unsigned long controller[5]; ++} irq_info_t; ++ ++typedef struct p_property { ++ char *name; ++ int length; ++ unsigned char *value; ++ struct p_property *next; ++} p_property_t; ++ ++typedef struct mol_device_node { ++ p_phandle_t node; ++ struct p_property *properties; ++ struct mol_device_node *parent; ++ struct mol_device_node *child; ++ struct mol_device_node *sibling; ++ struct mol_device_node *next; /* next device of same type */ ++ struct mol_device_node *allnext; /* next in list of all nodes */ ++ char *unit_string; ++} mol_device_node_t; ++ ++#endif /* _H_PROM */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/rvec.h +@@ -0,0 +1,147 @@ ++/* ++ * Creation Date: <2001/01/26 21:33:45 samuel> ++ * Time-stamp: <2004/02/08 20:08:20 samuel> ++ * ++ * ++ * ++ * Possible mac-return vectors (see mainloop.S) ++ * ++ * Copyright (C) 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_RVEC ++#define _H_RVEC ++ ++ ++/* ---------------------------------------------------------------------------- */ ++ ++#define NRVECS_LOG2 6 ++#define NUM_RVECS 64 /* = 2 ^ NRVECS_LOG2 */ ++#define RVEC_MASK (NUM_RVECS-1) ++ ++/* ---------------------------------------------------------------------------- */ ++ ++#define RVEC_NOP 0 /* Must be zero */ ++#ifdef __darwin__ ++#define RVEC_CALL_KERNEL 1 /* call kernel */ ++#endif ++#define RVEC_ENABLE_FPU 3 /* Load up FPU */ ++ ++#define RVEC_TRACE_TRAP 6 ++#define RVEC_ISI_TRAP 7 /* r4=nip, r5=srr1 */ ++#define RVEC_DSI_TRAP 8 /* r4=dar, r5=srr1 */ ++#define RVEC_ALIGNMENT_TRAP 9 /* r4=dar, r5=srr1 */ ++#ifdef EMULATE_603 ++#define RVEC_DMISS_LOAD_TRAP 10 ++#define RVEC_DMISS_STORE_TRAP 11 ++#define RVEC_IMISS_TRAP 12 ++#endif ++ ++#define RVEC_SPR_READ 13 /* r4=spr#, r5=gprnum */ ++#define RVEC_SPR_WRITE 14 /* r4=spr#, r5=value */ ++#define RVEC_PRIV_INST 15 /* r4=opcode */ ++#define RVEC_ILLEGAL_INST 16 /* r4=opcode */ ++ ++#define RVEC_UNUSUAL_PROGRAM_EXCEP 17 /* r4=opcode, r5=srr1 */ ++ ++#define RVEC_ALTIVEC_UNAVAIL_TRAP 18 ++#define RVEC_ALTIVEC_ASSIST 19 /* r4=srr1 */ ++#define RVEC_ENABLE_ALTIVEC 20 ++ ++#define RVEC_EXIT 21 ++/* 22 was RVEC_INTERRUPT */ ++#define RVEC_OSI_SYSCALL 23 ++#define RVEC_TIMER 24 ++ ++#define RVEC_IO_READ 25 ++#define RVEC_IO_WRITE 26 ++ ++#define RVEC_MSR_POW 27 /* (MSR_POW 0->1) => doze */ ++ ++/* error/debug */ ++#define RVEC_UNUSUAL_DSISR_BITS 28 /* dar, dsisr (bit 0,5,9 or 11 was set) */ ++#define RVEC_MMU_IO_SEG_ACCESS 29 /* IO segment access (more or less unused) */ ++#define RVEC_INTERNAL_ERROR 30 ++#define RVEC_DEBUGGER 31 ++#define RVEC_BREAK 32 /* r4 = break_flag */ ++#define RVEC_BAD_NIP 33 /* r4 = phys_nip */ ++#define RVEC_OUT_OF_MEMORY 34 /* fatal out of memory... */ ++ ++#define RVEC_CHECK_IRQS 35 /* check interrupts */ ++ ++ ++/************************************************************************/ ++/* MOL kernel/emulator switch magic */ ++/************************************************************************/ ++ ++/* magic to be loaded into r4/r5 before the illegal instruction is issued */ ++#define MOL_ENTRY_R4_MAGIC 0x7ba5 ++#define MOL_INITIALIZE_FLAG 0x8000 ++#define MOL_KERNEL_ENTRY_MAGIC mfmsr r0 /* any privileged instruction will do */ ++ ++ ++/************************************************************************/ ++/* Kernel definitions */ ++/************************************************************************/ ++ ++#if defined(__KERNEL__) && !defined( __ASSEMBLY__ ) ++ ++#define RVEC_RETURN_1( mregsptr, rvec, arg1 ) \ ++ ({ (mregsptr)->rvec_param[0] = (ulong)(arg1); \ ++ return rvec; }) ++ ++#define RVEC_RETURN_2( mregsptr, rvec, arg1, arg2 ) \ ++ ({ (mregsptr)->rvec_param[0] = (ulong)(arg1); \ ++ (mregsptr)->rvec_param[1] = (ulong)(arg2); \ ++ return rvec; }) ++ ++#define RVEC_RETURN_3( mregsptr, rvec, arg1, arg2, arg3 ) \ ++ ({ (mregsptr)->rvec_param[0] = (ulong)(arg1); \ ++ (mregsptr)->rvec_param[1] = (ulong)(arg2); \ ++ (mregsptr)->rvec_param[2] = (ulong)(arg3); \ ++ return rvec; }) ++ ++#endif /* !__ASSEMBLY__ && __KERNEL__ */ ++ ++ ++/************************************************************************/ ++/* userspace definitions */ ++/************************************************************************/ ++ ++#if !defined(__KERNEL__) || defined(__MPC107__) ++ ++#if !defined(__ASSEMBLY__) ++#if !defined(__KERNEL__) ++ ++typedef struct { ++ int vnum; ++ void *vector; ++ const char *name; ++} rvec_entry_t; ++ ++extern void rvec_init( void ); ++extern void rvec_cleanup( void ); ++extern void set_rvector( uint vnum, void *vector, const char *vector_name ); ++extern void set_rvecs( rvec_entry_t *table, int tablesize ); ++#endif ++ ++/* this struct is private to rvec.c/mainloop.S (offsets are HARDCODED) */ ++typedef struct { ++ int (*rvec)( int rvec /*, arguments */ ); ++ int dbg_count; ++ const char *name; ++ int filler; ++} priv_rvec_entry_t; ++#endif /* __ASSEMBLY__ */ ++ ++#define RVEC_ESIZE_LOG2 4 /* 2^n = sizeof(priv_rvec_entry_t) */ ++#define RVEC_ESIZE 16 /* sizeof(priv_rvec_entry_t) */ ++ ++#endif /* __KERNEL__ || __MPC107__ */ ++ ++#endif /* _H_RVEC */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/skiplist.h +@@ -0,0 +1,87 @@ ++/* ++ * Creation Date: <2003/03/03 22:59:04 samuel> ++ * Time-stamp: <2004/02/21 12:17:38 samuel> ++ * ++ * ++ * ++ * Skiplist implementation ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_SKIPLIST ++#define _H_SKIPLIST ++ ++#define SKIPLIST_MAX_HEIGHT 16 ++ ++typedef struct skiplist_el skiplist_el_t; ++ ++typedef struct { ++#ifdef __darwin__ ++ ulong next_phys; /* for usage from assembly */ ++#endif ++ skiplist_el_t *next; ++} skiplist_level_t; ++ ++/* data (of datasize) is stored before the skiplist_el */ ++typedef struct skiplist_el { ++ int key; ++ skiplist_level_t level[1]; /* level 0 */ ++ /* level 1..n are optionally stored here */ ++} *skiplist_iter_t; ++ ++typedef struct { ++ int nel; ++ int slevel; /* start level */ ++ int datasize; /* size of data (stored before each key) */ ++ ++ skiplist_level_t root[SKIPLIST_MAX_HEIGHT]; ++ skiplist_el_t nil_el; ++ ++ skiplist_level_t freelist; /* key = level, linked list in next[0] */ ++} skiplist_t; ++ ++static inline int ++skiplist_getnext( skiplist_t *sl, skiplist_iter_t *iterator, char **data ) ++{ ++ skiplist_el_t *el = *iterator; ++ *data = (char*)el - sl->datasize; ++ *iterator = el->level[0].next; ++ return el != &sl->nil_el; ++} ++ ++static inline int ++skiplist_iter_getkey( skiplist_t *sl, char *data ) ++{ ++ return ((skiplist_el_t*)(data + sl->datasize))->key; ++} ++ ++static inline skiplist_iter_t ++skiplist_iterate( skiplist_t *sl ) ++{ ++ return sl->root[0].next; ++} ++ ++static inline int ++skiplist_needalloc( skiplist_t *sl ) ++{ ++ return !sl->freelist.next; ++} ++ ++typedef void (*skiplist_el_callback)( char *data, int ind, int n, void *usr1, void *usr2 ); ++ ++extern void skiplist_init( skiplist_t *sl, int datasize ); ++extern int skiplist_prealloc( skiplist_t *sl, char *buf, unsigned int size, ++ skiplist_el_callback callback, void *usr1, void *usr2 ); ++ ++extern char *skiplist_insert( skiplist_t *sl, int key ); ++extern char *skiplist_delete( skiplist_t *sl, int key ); ++extern char *skiplist_lookup( skiplist_t *sl, int key ); ++ ++ ++#endif /* _H_SKIPLIST */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/tlbie.h +@@ -0,0 +1,102 @@ ++/* ++ * Creation Date: <2003/05/27 16:56:10 samuel> ++ * Time-stamp: <2003/08/16 16:55:31 samuel> ++ * ++ * ++ * ++ * tlbie and PTE operations ++ * ++ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_TLBIE ++#define _H_TLBIE ++ ++ ++#ifdef CONFIG_SMP ++extern void (*xx_tlbie_lowmem)( void /* special */ ); ++extern void (*xx_store_pte_lowmem)( void /* special */ ); ++extern int compat_hash_table_lock; ++ ++static inline void ++__tlbie( int ea ) ++{ ++ register ulong _ea __asm__ ("r3"); ++ register ulong _lock __asm__ ("r7"); ++ register ulong _func __asm__ ("r9"); ++ ++ _func = (ulong)xx_tlbie_lowmem; ++ _lock = (ulong)&compat_hash_table_lock; ++ _ea = ea; ++ ++ asm volatile ( ++ "mtctr 9 \n" ++ "li 8,0x1235 \n" /* lock value */ ++ "mfmsr 10 \n" ++ "rlwinm 0,10,0,17,15 \n" /* clear MSR_EE */ ++ "mtmsr 0 \n" ++ "bctrl \n" /* modifies r0 */ ++ "mtmsr 10 \n" ++ : ++ : "r" (_ea), "r" (_lock), "r" (_func) ++ : "ctr", "lr", "cc", "r8", "r0", "r10" ++ ); ++} ++ ++static inline void ++__store_PTE( int ea, unsigned long *slot, int pte0, int pte1 ) ++{ ++ register ulong _ea __asm__ ("r3"); ++ register ulong _pte_slot __asm__ ("r4"); ++ register ulong _pte0 __asm__ ("r5"); ++ register ulong _pte1 __asm__ ("r6"); ++ register ulong _lock __asm__ ("r7"); ++ register ulong _func __asm__ ("r9"); ++ ++ _func = (ulong)xx_store_pte_lowmem; ++ _ea = ea; ++ _pte_slot = (ulong)slot; ++ _pte0 = pte0; ++ _pte1 = pte1; ++ _lock = (ulong)&compat_hash_table_lock; ++ ++ asm volatile ( ++ "mtctr 9 \n" ++ "li 8,0x1234 \n" /* lock value */ ++ "mfmsr 10 \n" ++ "rlwinm 0,10,0,17,15 \n" /* clear MSR_EE */ ++ "mtmsr 0 \n" ++ "bctrl \n" /* modifies r0 */ ++ "mtmsr 10 \n" ++ : ++ : "r" (_ea), "r" (_pte_slot), "r" (_pte0), "r" (_pte1), "r" (_lock), "r" (_func) ++ : "ctr", "lr", "cc", "r0", "r8", "r10" ++ ); ++} ++ ++#else /* CONFIG_SMP */ ++extern void (*xx_store_pte_lowmem)( unsigned long *slot, int pte0, int pte1 ); ++ ++static inline void __tlbie( int ea ) { ++ asm volatile ("tlbie %0" : : "r"(ea)); ++} ++ ++static inline void ++__store_PTE( int ea, unsigned long *slot, int pte0, int pte1 ) ++{ ++ ulong flags; ++ local_irq_save(flags); ++ (*xx_store_pte_lowmem)( slot, pte0, pte1 ); ++ local_irq_restore(flags); ++ __tlbie( ea ); ++} ++ ++#endif /* CONFIG_SMP */ ++ ++ ++#endif /* _H_TLBIE */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/uaccess.h +@@ -0,0 +1,36 @@ ++/* ++ * Creation Date: <2004/02/01 20:02:11 samuel> ++ * Time-stamp: <2004/02/01 20:02:11 samuel> ++ * ++ * ++ * ++ * ++ * ++ * Copyright (C) 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_UACCESS ++#define _H_UACCESS ++ ++ ++static inline unsigned int copy_to_user_mol( void *to, const void *from, ulong len ) { ++ return copy_to_user( to, from, len ); ++} ++static inline unsigned int copy_from_user_mol( void *to, const void *from, ulong len ) { ++ return copy_from_user( to, from, len ); ++} ++ ++static inline unsigned int copy_int_to_user( int *to, int val ) { ++ return copy_to_user_mol( to, &val, sizeof(int) ); ++} ++static inline unsigned int copy_int_from_user( int *retint, int *userptr ) { ++ return copy_from_user_mol( retint, userptr, sizeof(int) ); ++} ++ ++ ++#endif /* _H_UACCESS */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/vector.h +@@ -0,0 +1,189 @@ ++/* ++ * Creation Date: <2003/05/26 00:00:28 samuel> ++ * Time-stamp: <2004/03/07 14:44:50 samuel> ++ * ++ * ++ * ++ * Vector hooks ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#ifndef _H_VECTOR ++#define _H_VECTOR ++ ++#define MOL_SPRG2_MAGIC 0x1779 ++ ++#ifdef __MPC107__ ++#include "mpcvector.h" ++#else ++ ++#define PERFMON_VECTOR 0xf00 ++ ++ ++/************************************************************************/ ++/* Vector entry point definitions */ ++/************************************************************************/ ++ ++/* ++ * This code uses the dynamic linkage/action symbol functionality of ++ * the MOL kernel loader to automatically install the hooks. Refer to ++ * hook.c for the actual implementation. ++ */ ++ ++/* Description of ACTION_RELOC_HOOK: ++ * ++ * .long ACTION_RELOC_HOOK ++ * .long vector ++ * .long #bytes to copy to lowmem ++ * .long offset to vret function ++ * -- offsets are calculated from here -- ++ */ ++ ++mDEFINE(VECTOR_HOOK, [v], [ ++ balign_32 ++ ACTION_PB( ACTION_RELOC_HOOK ) ++ .long _v ++ .long vhook_end_[]_v - vhook_[]_v ++ .long vret_[]_v - vhook_[]_v ++vhook_[]_v: ++ mtsprg_a0 r3 ++ addis r3,0,0 /* [1] hook address inserted */ ++ mtsprg_a1 r1 ++ ori r3,r3,0 /* [3] at module initialization */ ++ mfctr r1 ++ mtctr r3 ++ bctr ++ ++vret_[]_v: ++ nop /* overwritten instruction is inserted here */ ++ ba _v + 0x4 ++vhook_end_[]_v: ++ ++ .text ++ /* entrypoint */ ++]) ++ ++/* these macros are to be used from the not_mol vector hook */ ++#define CONTINUE_TRAP( v ) \ ++ mfsprg_a0 r3 ; \ ++ fix_sprg2 /**/ R1 /* sprg2 == sprg_a0 */ ; \ ++ mfsprg_a1 r1 ; \ ++ ACTION_1( ACTION_VRET, v ) /* ba vret_xxx */ ++ ++#define ABORT_TRAP( dummy_v ) \ ++ mfsprg_a0 r3 ; \ ++ fix_sprg2 /**/ R1 /* sprg2 == sprg_a0 */ ; \ ++ mfsprg_a1 r1 ; \ ++ rfi ++ ++/* SPRG0,1 = saved r3,r1, r1 = saved lr */ ++mDEFINE(VECTOR_, [v, dummy_str, secondary, not_mol_label], [ ++ ++not_mol_[]_v: ++ mtcr r3 ++ CONTINUE_TRAP( _v ) ++ ++secondary_int_[]_v: ++ li r3,_v ++ b _secondary ++ ++ VECTOR_HOOK( _v ) ++ ++ /* entrypoint */ ++ mtctr r1 ++ mfcr r3 ++ mfsprg_a2 r1 ++ cmpwi r1,MOL_SPRG2_MAGIC ++ bne- _not_mol_label ++soft_603_entry_[]_v: ++ mfsrr1 r1 ++ andi. r1,r1,MSR_PR /* MSR_PR set? */ ++ mfsprg_a3 r1 ++ beq- secondary_int_[]_v /* if not, take a secondary trap? */ ++]) ++ ++#define VECTOR(v, dummy_str, secondary) \ ++ VECTOR_(v, dummy_str, secondary, not_mol_##v ) ++ ++/* this macro takes an exception from mac mode (call save_middle_regs first) */ ++#define TAKE_EXCEPTION( v ) \ ++ bl take_exception ; \ ++ ACTION_1( ACTION_VRET, v ) ++ ++/* no need to relocate the 0xf00 trap */ ++#define PERFMON_VECTOR_RELOCATION( newvec ) ++ ++ ++/************************************************************************/ ++/* 603 vector HOOKs (r0-r3, cr0 saved by hardware) */ ++/************************************************************************/ ++ ++mDEFINE(VECTOR_603, [v, dummy_str], [ ++ balign_32 ++ ACTION_PB( ACTION_RELOC_HOOK ) ++ .long _v ++ .long vhook_end_[]_v - vhook_[]_v ++ .long vret_[]_v - vhook_[]_v ++vhook_[]_v: ++ mfsprg_a2 r1 ++ addis r3,0,0 /* [1] hook address inserted */ ++ cmpwi r1,MOL_SPRG2_MAGIC ++ ori r3,r3,0 /* [3] at module initialization */ ++ bne vret_[]_v ++ mfctr r0 ++ mtctr r3 ++ bctr ++ ++vret_[]_v: ++ nop /* overwritten instruction is inserted here */ ++ ba _v + 0x4 ++vhook_end_[]_v: ++ ++ .text ++ /* entrypoint */ ++]) ++ ++ ++/* all register are assumed to be unmodified */ ++mDEFINE(SOFT_VECTOR_ENTRY_603, [v], [ ++ mtsprg_a0 r3 ++ mtsprg_a1 r1 ++ mfcr r3 ++ b soft_603_entry_[]_v ++]) ++ ++ ++/************************************************************************/ ++/* FUNCTION_HOOK */ ++/************************************************************************/ ++ ++mDEFINE(FHOOK, [symind], [ ++ ACTION_PB( ACTION_HOOK_FUNCTION ) ++ .long _symind ++ .long fhook_end_[]_symind - fhook_[]_symind ++ .long fret_[]_symind - fhook_[]_symind ++fhook_[]_symind: ++ mflr r10 ++ addis r9,0,0 /* [1] address inserted */ ++ ori r9,r9,0 /* [2] at runtime */ ++ mtctr r9 ++ bctrl ++ mtlr r10 ++fret_[]_symind: ++ nop /* overwritten instruction is inserted here */ ++ nop /* return (through a relative branch) */ ++fhook_end_[]_symind: ++ ++ .text ++ /* hook goes here */ ++]) ++ ++ ++#endif /* MOLMPC */ ++#endif /* _H_VECTOR */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/version.h +@@ -0,0 +1,11 @@ ++ ++#ifndef _H_VERSION ++#define _H_VERSION ++ ++#include "molversion.h" ++ ++#define MOL_VERSION ((MOL_MAJOR_VERSION << 16) \ ++ + (MOL_MINOR_VERSION << 8) \ ++ + MOL_PATCHLEVEL ) ++ ++#endif /* _H_VERSION */ +--- /dev/null ++++ b/drivers/macintosh/mol/include/weaksym.h +@@ -0,0 +1,39 @@ ++/* ++ * Creation Date: <2001/08/02 23:53:57 samuel> ++ * Time-stamp: <2001/08/03 00:30:23 samuel> ++ * ++ * ++ * ++ * Support of weak symbols (extract, stolen from glibc) ++ * ++ * 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 ++ * ++ */ ++ ++#ifndef _H_WEAKSYM ++#define _H_WEAKSYM ++ ++ ++/* Define ALIASNAME as a strong alias for NAME. */ ++#define strong_alias(name, aliasname) _strong_alias(name, aliasname) ++#define _strong_alias(name, aliasname) \ ++ extern __typeof (name) aliasname __attribute__ ((alias (#name))); ++ ++/* This comes between the return type and function name in ++ a function definition to make that definition weak. */ ++#define weak_function __attribute__ ((weak)) ++#define weak_const_function __attribute__ ((weak, __const__)) ++ ++/* Define ALIASNAME as a weak alias for NAME. */ ++#define weak_alias(name, aliasname) _weak_alias (name, aliasname) ++#define _weak_alias(name, aliasname) \ ++ extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))); ++ ++/* Declare SYMBOL as weak undefined symbol (resolved to 0 if not defined). */ ++#define weak_extern(symbol) _weak_extern (symbol) ++# define _weak_extern(symbol) asm (".weak " #symbol); ++ ++ ++#endif /* _H_WEAKSYM */ +--- /dev/null ++++ b/drivers/macintosh/mol/init.c +@@ -0,0 +1,191 @@ ++/* ++ * Creation Date: <2002/01/13 20:45:37 samuel> ++ * Time-stamp: <2004/02/14 14:01:09 samuel> ++ * ++ * ++ * ++ * Kernel module initialization ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "misc.h" ++#include "mmu.h" ++#include "asmfuncs.h" ++#include "performance.h" ++#include "mol-ioctl.h" ++#include "version.h" ++#include "hash.h" ++ ++/* globals */ ++session_table_t *g_sesstab; ++int g_num_sessions; ++ ++ ++/************************************************************************/ ++/* init/cleanup kernel module */ ++/************************************************************************/ ++ ++int ++common_init( void ) ++{ ++ if( init_hash() ) ++ return 1; ++ ++ if( !(g_sesstab=kmalloc_cont_mol(sizeof(*g_sesstab))) ) { ++ cleanup_hash(); ++ return 1; ++ } ++ ++ memset( g_sesstab, 0, sizeof(*g_sesstab) ); ++ init_MUTEX_mol( &g_sesstab->lock ); ++ ++ if( arch_common_init() ) { ++ free_MUTEX_mol( &g_sesstab->lock ); ++ kfree_cont_mol( g_sesstab ); ++ cleanup_hash(); ++ return 1; ++ } ++ return 0; ++} ++ ++void ++common_cleanup( void ) ++{ ++ arch_common_cleanup(); ++ ++ free_MUTEX_mol( &g_sesstab->lock ); ++ kfree_cont_mol( g_sesstab ); ++ g_sesstab = NULL; ++ ++ cleanup_hash(); ++} ++ ++ ++/************************************************************************/ ++/* initialize / destroy session */ ++/************************************************************************/ ++ ++static int ++initialize_session_( uint index ) ++{ ++ kernel_vars_t *kv; ++ ulong kv_phys; ++ ++ if( g_sesstab->magic == 1 ) ++ return -EMOLSECURITY; ++ ++ /* printk("initialize_session\n" ); */ ++ if( g_sesstab->kvars[index] ) ++ return -EMOLINUSE; ++ ++ if( !g_num_sessions && perform_actions() ) ++ return -EMOLGENERAL; ++ ++ if( !(kv=alloc_kvar_pages()) ) ++ goto error; ++ ++ memset( kv, 0, NUM_KVARS_PAGES * 0x1000 ); ++ kv->session_index = index; ++ kv->kvars_virt = kv; ++ kv_phys = tophys_mol(kv); ++ kv->kvars_tophys_offs = kv_phys - (ulong)kv; ++ ++ if( init_mmu(kv) ) ++ goto error; ++ ++ init_host_irqs(kv); ++ initialize_spr_table( kv ); ++ ++ msr_altered( kv ); ++ ++ g_num_sessions++; ++ ++ g_sesstab->kvars_ph[index] = kv_phys; ++ g_sesstab->kvars[index] = kv; ++ ++ return 0; ++ error: ++ if( !g_num_sessions ) ++ cleanup_actions(); ++ if( kv ) ++ free_kvar_pages( kv ); ++ return -EMOLGENERAL; ++} ++ ++int ++initialize_session( uint index ) ++{ ++ int ret; ++ if( index >= MAX_NUM_SESSIONS ) ++ return -EMOLINVAL; ++ ++ SESSION_LOCK; ++ ret = initialize_session_( index ); ++ SESSION_UNLOCK; ++ ++ return ret; ++} ++ ++void ++destroy_session( uint index ) ++{ ++ kernel_vars_t *kv; ++ ++ if( index >= MAX_NUM_SESSIONS ) ++ return; ++ ++ if( g_sesstab->magic == 1 ) { ++ printk("Security alert! Somebody other than MOL has tried to invoke\n" ++ "the MOL switch magic. The MOL infrastructure has been disabled.\n" ++ "Reboot in order to get MOL running again\n"); ++ /* make it impossible to unload the module */ ++ prevent_mod_unload(); ++ } ++ ++ SESSION_LOCK; ++ if( (kv=g_sesstab->kvars[index]) ) { ++ ++ g_sesstab->kvars[index] = NULL; ++ g_sesstab->kvars_ph[index] = 0; ++ ++ /* decrease before freeing anything (simplifies deallocation of shared resources) */ ++ g_num_sessions--; ++ cleanup_host_irqs(kv); ++ cleanup_mmu( kv ); ++ ++ if( kv->emuaccel_page ) ++ free_page_mol( kv->emuaccel_page ); ++ ++ memset( kv, 0, NUM_KVARS_PAGES * 0x1000 ); ++ free_kvar_pages( kv ); ++ ++ if( !g_num_sessions ) ++ cleanup_actions(); ++ } ++ SESSION_UNLOCK; ++} ++ ++uint ++get_session_magic( uint random_magic ) ++{ ++ if( random_magic < 2 ) ++ random_magic = 2; ++ /* negative return values are interpreted as errors */ ++ random_magic &= 0x7fffffff; ++ ++ SESSION_LOCK; ++ if( !g_sesstab->magic ) ++ g_sesstab->magic = random_magic; ++ SESSION_UNLOCK; ++ ++ return g_sesstab->magic; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/misc.c +@@ -0,0 +1,255 @@ ++/* ++ * Creation Date: <2003/06/06 20:00:52 samuel> ++ * Time-stamp: <2004/03/06 13:54:26 samuel> ++ * ++ * ++ * ++ * Miscellaneous ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "mol-ioctl.h" ++#include "mmu.h" ++#include "mtable.h" ++#include "constants.h" ++#include "asmfuncs.h" ++#include "performance.h" ++#include "misc.h" ++#include "emu.h" ++#include "alloc.h" ++#include "uaccess.h" ++ ++ ++/************************************************************************/ ++/* Performance Info */ ++/************************************************************************/ ++ ++#ifdef PERFORMANCE_INFO ++ ++static void ++clear_performance_info( kernel_vars_t *kv ) ++{ ++ perf_info_t *p = g_perf_info_table; ++ int i; ++ ++ for( ; p->name ; p++ ) ++ *p->ctrptr = 0; ++ for( i=0; iasm_bump_cntr[i] = 0; ++ kv->num_acntrs = 0; ++} ++ ++static int ++get_performance_info( kernel_vars_t *kv, uint ind, perf_ctr_t *r ) ++{ ++ perf_info_t *p; ++ int len; ++ char *name; ++ ++ for( p=g_perf_info_table; p->name && ind; p++, ind-- ) ++ ; ++ if( !p->name ) { ++ extern int __start_bumptable[], __end_bumptable[]; ++ if( ind >= __end_bumptable - __start_bumptable ) ++ return 1; ++ name = (char*)__start_bumptable + __start_bumptable[ind]; ++ r->ctr = kv->asm_bump_cntr[ind]; ++ } else { ++ name = p->name; ++ r->ctr = *p->ctrptr; ++ } ++ ++ if( (len=strlen(name)+1) > sizeof(r->name) ) ++ len = sizeof(r->name); ++ memcpy( r->name, name, len ); ++ return 0; ++} ++ ++#else /* PERFORMANCE_INFO */ ++ ++static void ++clear_performance_info( kernel_vars_t *kv ) ++{ ++} ++ ++static int ++get_performance_info( kernel_vars_t *kv, uint ind, perf_ctr_t *r ) ++{ ++ return 1; ++} ++ ++#endif /* PERFORMANCE_INFO */ ++ ++ ++ ++/************************************************************************/ ++/* misc */ ++/************************************************************************/ ++ ++int ++do_debugger_op( kernel_vars_t *kv, dbg_op_params_t *pb ) ++{ ++ int ret = 0; ++ ++ switch( pb->operation ) { ++ case DBG_OP_EMULATE_TLBIE: ++ flush_ea_range( kv, (pb->ea & ~0xf0000000), 0x1000 ); ++ break; ++ ++ case DBG_OP_EMULATE_TLBIA: ++ clear_all_vsids( kv ); ++ break; ++ ++ case DBG_OP_GET_PTE: ++ ret = dbg_get_PTE( kv, pb->context, pb->ea, &pb->ret.pte ); ++ break; ++ ++ case DBG_OP_BREAKPOINT_FLAGS: ++ kv->break_flags = pb->param; ++ kv->mregs.flag_bits &= ~fb_DbgTrace; ++ kv->mregs.flag_bits |= (pb->param & BREAK_SINGLE_STEP)? fb_DbgTrace : 0; ++ msr_altered( kv ); ++ break; ++ ++ case DBG_OP_TRANSLATE_EA: ++ /* param == is_data_access */ ++ ret = dbg_translate_ea( kv, pb->context, pb->ea, &pb->ret.phys, pb->param ); ++ break; ++ ++ default: ++ printk("Unimplemended debugger operation %d\n", pb->operation ); ++ ret = -ENOSYS_MOL; ++ break; ++ } ++ return ret; ++} ++ ++static void ++tune_spr( kernel_vars_t *kv, uint spr, int action ) ++{ ++ extern int r__spr_illegal[], r__spr_read_only[], r__spr_read_write[]; ++ int hook, newhook=0; ++ ++ if( spr >= 1024 ) ++ return; ++ ++ hook = kv->_bp.spr_hooks[spr]; ++ ++ /* LSB of hook specifies whether the SPR is privileged */ ++ switch( action ) { ++ case kTuneSPR_Illegal: ++ newhook = (int)r__spr_illegal; ++ hook &= ~1; ++ break; ++ ++ case kTuneSPR_Privileged: ++ hook |= 1; ++ break; ++ ++ case kTuneSPR_Unprivileged: ++ hook &= ~1; ++ break; ++ ++ case kTuneSPR_ReadWrite: ++ newhook = (int)r__spr_read_write; ++ break; ++ ++ case kTuneSPR_ReadOnly: ++ newhook = (int)r__spr_read_only; ++ break; ++ } ++ if( newhook ) ++ hook = (hook & 1) | tophys_mol( (char*)reloc_ptr(newhook) ); ++ kv->_bp.spr_hooks[spr] = hook; ++} ++ ++/* return value: <0: system error, >=0: ret value */ ++int ++handle_ioctl( kernel_vars_t *kv, int cmd, int arg1, int arg2, int arg3 ) ++{ ++ struct mmu_mapping map; ++ perf_ctr_t pctr; ++ int ret = 0; ++ ++ switch( cmd ) { ++ case MOL_IOCTL_GET_SESSION_MAGIC: ++ ret = get_session_magic( arg1 ); ++ break; ++ ++ case MOL_IOCTL_IDLE_RECLAIM_MEMORY: ++ mtable_reclaim( kv ); ++ break; ++ ++ case MOL_IOCTL_SPR_CHANGED: ++ msr_altered(kv); ++ mmu_altered(kv); ++ break; ++ ++ case MOL_IOCTL_ADD_IORANGE: /* void ( ulong mbase, int size, void *usr_data )*/ ++ add_io_trans( kv, arg1, arg2, (void*)arg3 ); ++ break; ++ case MOL_IOCTL_REMOVE_IORANGE: /* void ( ulong mbase, int size ) */ ++ remove_io_trans( kv, arg1, arg2 ); ++ break; ++ ++ case MOL_IOCTL_ALLOC_EMUACCEL_SLOT: /* EMULATE_xxx, param, ret_addr -- mphys */ ++ ret = alloc_emuaccel_slot( kv, arg1, arg2, arg3 ); ++ break; ++ case MOL_IOCTL_MAPIN_EMUACCEL_PAGE: /* arg1 = mphys */ ++ ret = mapin_emuaccel_page( kv, arg1 ); ++ break; ++ ++ case MOL_IOCTL_SETUP_FBACCEL: /* lvbase, bytes_per_row, height */ ++ setup_fb_acceleration( kv, (char*)arg1, arg2, arg3 ); ++ break; ++ case MOL_IOCTL_TUNE_SPR: /* spr#, action */ ++ tune_spr( kv, arg1, arg2 ); ++ break; ++ ++ case MOL_IOCTL_MMU_MAP: /* arg1=struct mmu_mapping *m, arg2=map/unmap */ ++ if( copy_from_user_mol(&map, (struct mmu_mapping*)arg1, sizeof(map)) ) ++ break; ++ if( arg2 ) ++ mmu_add_map( kv, &map ); ++ else ++ mmu_remove_map( kv, &map ); ++ if( copy_to_user_mol((struct mmu_mapping*)arg1, &map, sizeof(map)) ) ++ ret = -EFAULT_MOL; ++ break; ++ ++ case MOL_IOCTL_GET_PERF_INFO: ++ ret = get_performance_info( kv, arg1, &pctr ); ++ if( copy_to_user_mol((perf_ctr_t*)arg2, &pctr, sizeof(pctr)) ) ++ ret = -EFAULT_MOL; ++ break; ++ ++#if 0 ++ case MOL_IOCTL_TRACK_DIRTY_RAM: ++ ret = track_lvrange( kv ); ++ break; ++ case MOL_IOCTL_GET_DIRTY_RAM: ++ ret = get_track_buffer( kv, (char*)arg1 ); ++ break; ++ case MOL_IOCTL_SET_DIRTY_RAM: ++ set_track_buffer( kv, (char*)arg1 ); ++ break; ++#endif ++ /* ---------------- performance statistics ------------------ */ ++ ++ case MOL_IOCTL_CLEAR_PERF_INFO: ++ clear_performance_info( kv ); ++ break; ++ ++ default: ++ printk("unsupported MOL ioctl %d\n", cmd ); ++ ret = -ENOSYS_MOL; ++ } ++ return ret; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/mmu.c +@@ -0,0 +1,251 @@ ++/* ++ * Creation Date: <1998-11-11 11:56:45 samuel> ++ * Time-stamp: <2004/03/13 14:25:26 samuel> ++ * ++ * ++ * ++ * Handles page mappings and the mac MMU ++ * ++ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "mmu.h" ++#include "mmu_contexts.h" ++#include "asmfuncs.h" ++#include "emu.h" ++#include "misc.h" ++#include "mtable.h" ++#include "performance.h" ++#include "context.h" ++#include "hash.h" ++#include "map.h" ++ ++#define MREGS (kv->mregs) ++#define MMU (kv->mmu) ++ ++ ++/************************************************************************/ ++/* init / cleanup */ ++/************************************************************************/ ++ ++int ++init_mmu( kernel_vars_t *kv ) ++{ ++ int success; ++ ++ success = ++ !arch_mmu_init( kv ) && ++ !init_contexts( kv ) && ++ !init_mtable( kv ) && ++ !init_mmu_io( kv ) && ++ !init_mmu_fb( kv ) && ++ !init_mmu_tracker( kv ); ++ ++ if( !success ) { ++ cleanup_mmu( kv ); ++ return 1; ++ } ++ ++ clear_vsid_refs( kv ); ++ ++ /* SDR1 is set from fStartEmulation */ ++ return 0; ++} ++ ++void ++cleanup_mmu( kernel_vars_t *kv ) ++{ ++ /* We have to make sure the flush thread are not using the mtable ++ * facilities. The kvars entry has been clear so we just have ++ * to wait around until no threads are using it. ++ */ ++ while( atomic_read_mol(&g_sesstab->external_thread_cnt) ) ++ ; ++ ++ cleanup_mmu_tracker( kv ); ++ cleanup_mmu_fb( kv ); ++ cleanup_mmu_io( kv ); ++ cleanup_mtable( kv ); ++ cleanup_contexts( kv ); ++ ++ if( MMU.pthash_inuse_bits ) ++ kfree_cont_mol( MMU.pthash_inuse_bits ); ++ if( MMU.hash_base ) ++ unmap_emulated_hash( kv ); ++ ++ memset( &MMU, 0, sizeof(mmu_vars_t) ); ++} ++ ++ ++/************************************************************************/ ++/* misc */ ++/************************************************************************/ ++ ++/* All vsid entries have been flushed; clear dangling pointers */ ++void ++clear_vsid_refs( kernel_vars_t *kv ) ++{ ++ int i; ++ for( i=0; i<16; i++ ) { ++ MMU.vsid[i] = NULL; ++ MMU.unmapped_vsid[i] = NULL; ++ ++ MMU.user_sr[i] = MMU.illegal_sr; ++ MMU.sv_sr[i] = MMU.illegal_sr; ++ MMU.unmapped_sr[i] = MMU.illegal_sr; ++ MMU.split_sr[i] = MMU.illegal_sr; ++ } ++ invalidate_splitmode_sr( kv ); ++} ++ ++/* ++ * This function is called whenever the mac MMU-registers have ++ * been manipulated externally. ++ */ ++void ++mmu_altered( kernel_vars_t *kv ) ++{ ++ int i; ++ ++ for( i=0; i<16; i++ ) { ++ MMU.vsid[i] = NULL; ++ MMU.user_sr[i] = MMU.illegal_sr; ++ MMU.sv_sr[i] = MMU.illegal_sr; ++ } ++ invalidate_splitmode_sr( kv ); ++ ++ do_mtsdr1( kv, MREGS.spr[S_SDR1] ); ++ ++ for( i=0; i<16; i++ ) ++ do_mtbat( kv, S_IBAT0U+i, MREGS.spr[ S_IBAT0U+i ], 1 ); ++} ++ ++/* ++ * A page we might be using is about to be destroyed (e.g. swapped out). ++ * Any PTEs referencing this page must be flushed. The context parameter ++ * is vsid >> 4. ++ * ++ * ENTRYPOINT! ++ */ ++void ++do_flush( ulong context, ulong va, ulong *dummy, int n ) ++{ ++ int i; ++ kernel_vars_t *kv; ++ BUMP( do_flush ); ++ ++ atomic_inc_mol( &g_sesstab->external_thread_cnt ); ++ ++ for( i=0; ikvars[i]) || context != kv->mmu.emulator_context ) ++ continue; ++ ++ BUMP_N( block_destroyed_ctr, n ); ++ for( ; n-- ; va += 0x1000 ) ++ flush_lvptr( kv, va ); ++ break; ++ } ++ ++ atomic_dec_mol( &g_sesstab->external_thread_cnt ); ++} ++ ++ ++/************************************************************************/ ++/* Debugger functions */ ++/************************************************************************/ ++ ++int ++dbg_get_PTE( kernel_vars_t *kv, int context, ulong va, mPTE_t *retptr ) ++{ ++ ulong base, mask; ++ ulong vsid, ptmp, stmp, *pteg, *steg; ++ ulong cmp; ++ ulong *uret = (ulong*)retptr; ++ int i, num_match=0; ++ ++ switch( context ) { ++ case kContextUnmapped: ++ vsid = MMU.unmapped_sr[va>>28]; ++ break; ++ case kContextMapped_S: ++ vsid = MMU.sv_sr[va>>28]; ++ break; ++ case kContextMapped_U: ++ vsid = MMU.user_sr[va>>28]; ++ break; ++ case kContextEmulator: ++ vsid = (MUNGE_CONTEXT(MMU.emulator_context) + ((va>>28) * MUNGE_ESID_ADD)) & 0xffffff; ++ break; ++ case kContextKernel: ++ vsid = 0; ++ break; ++ default: ++ printk("get_PTE: no such context: %d\n", context ); ++ return 0; ++ } ++ ++ /* mask vsid and va */ ++ vsid &= 0xffffff; ++ va &= 0x0ffff000; ++ ++ /* get hash base and hash mask */ ++ base = (ulong)ptehash.base; ++ mask = ptehash.pteg_mask >> 6; ++ ++ /* hash function */ ++ ptmp = (vsid ^ (va>>12)) & mask; ++ stmp = mask & ~ptmp; ++ pteg = (ulong*)((ptmp << 6) + base); ++ steg = (ulong*)((stmp << 6) + base); ++ ++ /* construct compare word */ ++ cmp = 0x80000000 | (vsid <<7) | (va>>22); ++ ++ /* look in primary PTEG */ ++ for( i=0; i<8; i++ ) { ++ if( cmp == pteg[i*2] ) { ++ if( !num_match++ && uret ) { ++ uret[0] = pteg[i*2]; ++ uret[1] = pteg[i*2+1]; ++ } ++ if( num_match == 2 ) { ++ printk("Internal ERROR: duplicate PTEs!\n"); ++ printk("p-hash: low_pte: %08lX high_pte: %08lX\n", ++ uret ? uret[0]:0, retptr? uret[1]:0 ); ++ } ++ if( num_match >= 2 ) { ++ printk("p-hash: low_pte: %08lX high_pte: %08lX\n", ++ pteg[i*2], pteg[i*2+1] ); ++ } ++ } ++ } ++ ++ /* look in secondary PTEG */ ++ cmp |= 0x40; ++ for( i=0; i<8; i++ ) { ++ if( cmp == steg[i*2] ) { ++ if( !num_match++ && uret ) { ++ uret[0] = steg[i*2]; ++ uret[1] = steg[i*2+1]; ++ } ++ if( num_match == 2 ) { ++ printk("Internal ERROR: duplicate PTEs!\n"); ++ printk("?-hash: low_pte: %08lX high_pte: %08lX\n", ++ uret? uret[0]:0, uret? uret[1]:0 ); ++ } ++ if( num_match >= 2 ) { ++ printk("s-hash: low_pte: %08lX high_pte: %08lX\n", ++ steg[i*2], steg[i*2+1] ); ++ } ++ } ++ } ++ return num_match; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/mmu_fb.c +@@ -0,0 +1,186 @@ ++/* ++ * Creation Date: <1999-12-28 14:03:18 samuel> ++ * Time-stamp: <2004/02/14 14:52:52 samuel> ++ * ++ * ++ * ++ * Offscreen framebuffer acceleration ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "uaccess.h" ++#include "mmu.h" ++#include "asmfuncs.h" ++#include "performance.h" ++#include "misc.h" ++ ++typedef struct line_entry { ++ short y1, y2; ++ int dirty; ++ ulong *slot; ++ ulong pte0; ++ ulong pte1; ++ ulong ea; ++} line_entry_t; ++ ++typedef struct fb_data { ++ line_entry_t *line_table; ++ int nrec; ++ char *lv_base; /* linux virtual of first entry in table */ ++} fb_data_t; ++ ++#define MMU (kv->mmu) ++#define DECLARE_FB fb_data_t *fb = MMU.fb_data ++ ++#ifdef __darwin__ ++static inline void ++__put_user( short val, short *destptr ) ++{ ++ copy_to_user_mol( destptr, &val, sizeof(short) ); ++} ++#endif ++ ++ ++int ++init_mmu_fb( kernel_vars_t *kv ) ++{ ++ /* setup_fb_acceleration does the initialization */ ++ return 0; ++} ++ ++void ++cleanup_mmu_fb( kernel_vars_t *kv ) ++{ ++ DECLARE_FB; ++ if( !fb ) ++ return; ++ if( fb->line_table ) ++ vfree_mol( fb->line_table ); ++ ++ kfree_mol( fb ); ++ MMU.fb_data = NULL; ++} ++ ++void ++video_pte_inserted( kernel_vars_t *kv, ulong lvptr, ulong *slot, ulong pte0, ulong pte1, ulong ea ) ++{ ++ DECLARE_FB; ++ int i; ++ ++ if( !fb ) ++ return; ++ ++ i = (lvptr - (ulong)fb->lv_base) >> 12; ++ if( i >= 0 && i < fb->nrec ) { ++ line_entry_t *p = &fb->line_table[i]; ++ ++ /* allow at most one video PTE to be mapped at any time */ ++ if( p->slot && (p->slot != slot || p->pte0 != pte0) ) { ++ BUMP( video_pte_reinsert ); ++ if( p->slot != slot ) ++ p->slot[0] = 0; ++ __tlbie(p->ea); ++ p->dirty = 1; ++ } ++ ++ p->slot = slot; ++ p->pte0 = pte0; ++ p->pte1 = pte1 & ~PTE1_C; ++ p->ea = ea; ++ } else { ++ printk("Warning: video_page outside range, %lx %p\n", lvptr, fb->lv_base ); ++ } ++} ++ ++/* setup/remove framebuffer acceleration */ ++void ++setup_fb_acceleration( kernel_vars_t *kv, char *lvbase, int bytes_per_row, int height ) ++{ ++ DECLARE_FB; ++ int i, offs = (ulong)lvbase & 0xfff; ++ line_entry_t *p; ++ ++ if( fb ) ++ cleanup_mmu_fb( kv ); ++ if( !lvbase ) ++ return; ++ if( !(fb=kmalloc_mol(sizeof(fb_data_t))) ) ++ return; ++ memset( fb, 0, sizeof(fb_data_t) ); ++ MMU.fb_data = fb; ++ ++ fb->nrec = (bytes_per_row * height + offs + 0xfff) >> 12; ++ if( !(p=(line_entry_t*)vmalloc_mol(sizeof(line_entry_t) * fb->nrec)) ) { ++ cleanup_mmu_fb( kv ); ++ return; ++ } ++ memset( p, 0, sizeof(line_entry_t) * fb->nrec ); ++ fb->line_table = p; ++ ++ fb->lv_base = (char*)((ulong)lvbase & ~0xfff); ++ for( i=0; inrec; i++, p++ ){ ++ p->y1 = (0x1000*i - offs) / bytes_per_row; ++ p->y2 = (0x1000*(i+1)-1 -offs) / bytes_per_row; ++ if( p->y1 < 0 ) ++ p->y1 = 0; ++ if( p->y2 >= height ) ++ p->y2 = height-1; ++ ++ /* we should make sure the page is really unmapped here! */ ++ p->slot = NULL; ++ } ++} ++ ++/* return format is {startline,endline} pairs */ ++int ++get_dirty_fb_lines( kernel_vars_t *kv, short *userbuf, int num_bytes ) ++{ ++ DECLARE_FB; ++ int i, n, s, start; ++ line_entry_t *p; ++ ++ s = num_bytes/sizeof(short[2]) - 1; ++ ++ if( !fb || (uint)s <= 0 ) ++ return -1; ++ ++ p = fb->line_table; ++ for( start=-1, n=0, i=0; inrec; i++, p++ ) { ++ if( p->slot ) { ++ if( p->slot[0] != p->pte0 ) { ++ /* evicted FB PTE */ ++ p->slot = NULL; ++ p->dirty = 1; ++ __tlbie( p->ea ); ++ } else if( p->slot[1] & BIT(24) ) { /* C-BIT */ ++ p->dirty = 1; ++ __store_PTE( p->ea, p->slot, p->pte0, p->pte1 ); ++ BUMP(fb_ptec_flush); ++ } ++ } ++ if( p->dirty && start < 0 ) ++ start = p->y1; ++ else if( !p->dirty && start >= 0 ) { ++ __put_user( start, userbuf++ ); ++ __put_user( p->y2, userbuf++ ); ++ start = -1; ++ if( ++n >= s ) ++ break; ++ } ++ p->dirty = 0; ++ } ++ if( start >= 0 ) { ++ __put_user( start, userbuf++ ); ++ __put_user( fb->line_table[fb->nrec-1].y2, userbuf++ ); ++ n++; ++ } ++ return n; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/mmu_io.c +@@ -0,0 +1,470 @@ ++/* ++ * Creation Date: <1998-12-02 03:23:31 samuel> ++ * Time-stamp: <2004/03/13 16:57:31 samuel> ++ * ++ * ++ * ++ * Translate mac_phys to whatever has been mapped in at ++ * a particular address (linux ram, framebuffer, ROM, etc.) ++ * ++ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "mmu.h" ++#include "misc.h" ++#include "mtable.h" ++#include "performance.h" ++#include "processor.h" ++ ++#define MAX_BLOCK_TRANS 6 ++ ++/* Block translations are used for ROM, RAM, VRAM and similar things. ++ * ++ * IO-translations are a different type of mappings. Whenever an IO-area ++ * is accessed, a page fault occurs. If there is a page present (although ++ * r/w prohibited), then the low-level exception handler examines if the ++ * page has a magic signature in the first 8 bytes. If there is a match, ++ * then the page is of the type io_page_t and contains the information ++ * necessary to emulate the IO. If no page is present, then the corresponding ++ * IO-page is looked up and hashed. ++ */ ++ ++typedef struct { ++ ulong mbase; ++ char *lvbase; ++ pte_lvrange_t *lvrange; ++ ++ size_t size; ++ int flags; ++ ++ int id; ++} block_trans_t; ++ ++typedef struct io_data { ++ block_trans_t btable[MAX_BLOCK_TRANS]; ++ int num_btrans; ++ int next_free_id; ++ io_page_t *io_page_head; ++} io_data_t; ++ ++static char *scratch_page; ++ ++#define MMU (kv->mmu) ++#define DECLARE_IOD io_data_t *iod = kv->mmu.io_data ++ ++ ++ ++int ++init_mmu_io( kernel_vars_t *kv ) ++{ ++ if( !(MMU.io_data=kmalloc_mol(sizeof(io_data_t))) ) ++ return 1; ++ memset( MMU.io_data, 0, sizeof(io_data_t) ); ++ return 0; ++} ++ ++void ++cleanup_mmu_io( kernel_vars_t *kv ) ++{ ++ DECLARE_IOD; ++ io_page_t *next2, *p2; ++ int i; ++ ++ if( !iod ) ++ return; ++ ++ for( p2=iod->io_page_head; p2; p2=next2 ) { ++ next2 = p2->next; ++ free_page_mol( (ulong)p2 ); ++ } ++ iod->io_page_head = 0; ++ ++ /* release the scratch page (not always allocated) */ ++ if( !g_num_sessions && scratch_page ) { ++ free_page_mol( (int)scratch_page ); ++ scratch_page = 0; ++ } ++ ++ /* release any lvranges */ ++ for( i=0; inum_btrans; i++ ) ++ if( iod->btable[i].lvrange ) ++ free_lvrange( kv, iod->btable[i].lvrange ); ++ ++ kfree_mol( iod ); ++ MMU.io_data = NULL; ++} ++ ++ ++/* This is primarily intended for framebuffers */ ++static int ++bat_align( int flags, ulong ea, ulong lphys, ulong size, ulong bat[2] ) ++{ ++ ulong s; ++ ulong offs1, offs2; ++ ++ s=0x20000; /* 128K */ ++ if( s> size ) ++ return 1; ++ /* Limit to 128MB in order not to cross segments (256MB is bat-max) */ ++ if( size > 0x10000000 ) ++ size = 0x10000000; ++ for( ; s>17) << 2) | 3; ++ bat[1] = (lphys & ~(s-1)) | 2; /* pp=10, R/W */ ++ ++#ifndef CONFIG_AMIGAONE ++ bat[1] |= BIT(27); /* [M] (memory coherence) */ ++#endif ++ ++ if( !(flags & MAPPING_FORCE_CACHE) ) { ++ bat[1] |= BIT(26); /* [I] (inhibit cache) */ ++ } else { ++ bat[1] |= BIT(25); /* [W] (write through) */ ++ } ++ return 0; ++} ++ ++ ++/* ++ * Handle block translations (translations of mac-physical ++ * blocks to linux virtual physical addresses) ++ */ ++static int ++add_block_trans( kernel_vars_t *kv, ulong mbase, char *lvbase, ulong size, int flags ) ++{ ++ DECLARE_IOD; ++ block_trans_t *bt; ++ pte_lvrange_t *lvrange = NULL; ++ int ind, i; ++ ++ /* warn if things are not aligned properly */ ++ if( (size & 0xfff) || ((int)lvbase & 0xfff) || (mbase & 0xfff) ) ++ printk("Bad block translation alignement\n"); ++ ++ /* we keep an unsorted list - RAM should be added first, then ROM, then VRAM etc */ ++ if( iod->num_btrans >= MAX_BLOCK_TRANS ) { ++ printk("Maximal number of block translations exceeded!\n"); ++ return -1; ++ } ++ ++ /* remove illegal combinations */ ++ flags &= ~MAPPING_IO; ++ if( (flags & MAPPING_DBAT) && !(flags & MAPPING_PHYSICAL) ) ++ flags &= ~MAPPING_DBAT; ++ ++ /* scratch pages are always physical - lvbase isn't used */ ++ if( (flags & MAPPING_SCRATCH) ) { ++ lvbase = NULL; ++ flags |= MAPPING_PHYSICAL; ++ flags &= ~MAPPING_DBAT; ++ } ++ ++ /* IMPORTANT: DBATs can _only_ be used when we KNOW that ea == mphys. */ ++ if( (flags & MAPPING_DBAT) ) { ++ ulong bat[2]; ++ if( !bat_align(flags, mbase, (ulong)lvbase, size, bat) ) { ++ /* printk("BATS: %08lX %08lX\n", bat[0], bat[1] ); */ ++ MMU.transl_dbat0.word[0] = bat[0]; ++ MMU.transl_dbat0.word[1] = bat[1]; ++ } ++ } ++ ++ if( !(flags & MAPPING_PHYSICAL) ) ++ if( !(lvrange=register_lvrange(kv, lvbase, size)) ) ++ return -1; ++ ++ /* Determine where to insert the translation in the table. ++ * RAM should go right efter entries marked with MAPPING_PUT_FIRST. ++ * The MAPPING_PUT_FIRST flag is used to do magic things like ++ * embedding a copy of mregs in RAM. ++ */ ++ ind = (!mbase || (flags & MAPPING_PUT_FIRST)) ? 0 : iod->num_btrans; ++ for( i=0; inum_btrans && ind <= i; i++ ) ++ if( iod->btable[i].flags & MAPPING_PUT_FIRST ) ++ ind++; ++ bt = &iod->btable[ind]; ++ if( ind < iod->num_btrans ) ++ memmove( &iod->btable[ind+1], bt, sizeof(iod->btable[0]) * (iod->num_btrans - ind) ); ++ iod->num_btrans++; ++ memset( bt, 0, sizeof(block_trans_t) ); ++ ++ bt->mbase = mbase; ++ bt->lvbase = lvbase; ++ bt->lvrange = lvrange; ++ bt->size = size; ++ bt->flags = flags | MAPPING_VALID; ++ bt->id = ++iod->next_free_id; ++ ++ /* flush everything if we a translation was overridden */ ++ if( flags & MAPPING_PUT_FIRST ) ++ clear_pte_hash_table( kv ); ++ ++ return bt->id; ++} ++ ++static void ++remove_block_trans( kernel_vars_t *kv, int id ) ++{ ++ DECLARE_IOD; ++ block_trans_t *p; ++ int i; ++ ++ /* Remove all mappings in the TLB table... ++ * (too difficult to find the entries we need to flush) ++ */ ++ BUMP(remove_block_trans); ++ clear_pte_hash_table( kv ); ++ ++ for( p=iod->btable, i=0; inum_btrans; i++, p++ ) { ++ if( id == p->id ) { ++ if( p->flags & MAPPING_DBAT ) { ++ MMU.transl_dbat0.word[0] = 0; ++ MMU.transl_dbat0.word[1] = 0; ++ } ++ if( p->lvrange ) ++ free_lvrange( kv, p->lvrange ); ++ ++ memmove( p,p+1, (iod->num_btrans-1-i)*sizeof(block_trans_t) ); ++ iod->num_btrans--; ++ return; ++ } ++ } ++ printk("Trying to remove nonexistent block mapping!\n"); ++} ++ ++/* adds an I/O-translation. It is legal to add the same ++ * range multiple times (for instance, to alter usr_data) ++ */ ++int ++add_io_trans( kernel_vars_t *kv, ulong mbase, int size, void *usr_data ) ++{ ++ DECLARE_IOD; ++ io_page_t *ip, **pre_next; ++ ulong mb; ++ int i, num; ++ ++ /* align mbase and size to double word boundarys */ ++ size += mbase & 7; ++ mbase -= mbase & 7; ++ size = (size+7) & ~7; ++ ++ while( size > 0 ) { ++ mb = mbase & 0xfffff000; ++ ++ pre_next = &iod->io_page_head; ++ for( ip=iod->io_page_head; ip && ip->mphys < mb; ip=ip->next ) ++ pre_next = &ip->next; ++ ++ if( !ip || ip->mphys != mb ) { ++ /* create new page */ ++ if( !(ip=(io_page_t*)alloc_page_mol()) ) { ++ printk("Failed allocating IO-page\n"); ++ return 1; ++ } ++ ip->next = *pre_next; ++ *pre_next = ip; ++ ++ /* setup block */ ++ ip->magic = IO_PAGE_MAGIC_1; ++ ip->magic2 = IO_PAGE_MAGIC_2; ++ ip->me_phys = tophys_mol(ip); ++ ip->mphys = mb; ++ } ++ /* fill in IO */ ++ num = size>>3; ++ i = (mbase & 0xfff) >> 3; ++ if( i+num > 512 ) ++ num = 512-i; ++ mbase += num<<3; ++ size -= num<<3; ++ while( num-- ) ++ ip->usr_data[i++] = usr_data; ++ } ++ return 0; ++} ++ ++int ++remove_io_trans( kernel_vars_t *kv, ulong mbase, int size ) ++{ ++ DECLARE_IOD; ++ io_page_t *ip, **pre_next; ++ ulong mb; ++ int i, num; ++ ++ /* To remove an unused IO-page, we must make sure there are no ++ * dangling references to it. Hence we must search the PTE hash ++ * table and remove all references. We must also issue a ++ * tlbia to make sure it is not in the on-chip DTLB/ITLB cashe. ++ * ++ * XXX: Instead of seraching the hash, we simply make sure the magic ++ * constants are invalid. This is perfectly safe since the exception ++ * handler doesn't write to the page in question - and the physical ++ * page always exists even if it is allocated by somebody else. ++ * It is better to make sure there are no references of it though. ++ * ++ * XXX: This needs to be fixed... commonly, we reallocate ++ * the page ourselves for I/O so the magic constants might ++ * be valid... ++ */ ++ ++ /* align mbase and size to double word boundarys */ ++ size += mbase & 7; ++ mbase -= mbase & 7; ++ size = (size+7) & ~7; ++ ++ while( size > 0 ) { ++ mb = mbase & 0xfffff000; ++ ++ pre_next = &iod->io_page_head; ++ for( ip=iod->io_page_head; ip && ip->mphys < mb; ip=ip->next ) ++ pre_next = &ip->next; ++ ++ if( !ip || ip->mphys != mb ) { ++ /* no page... */ ++ size -= 0x1000 - (mbase & 0xfff); ++ mbase += 0x1000 - (mbase & 0xfff); ++ continue; ++ } ++ /* clear IO */ ++ num = size>>3; ++ i = (mbase & 0xfff) >> 3; ++ if( i+num > 512 ) ++ num = 512-i; ++ mbase += num<<3; ++ size -= num<<3; ++ while( num-- ) ++ ip->usr_data[i++] = 0; ++ ++ /* May we free the page? */ ++ for( i=0; i<512 && !ip->usr_data[i]; i++ ) ++ ; ++ if( i==512 ) { ++ /* Free page (XXX: Remove page fram hash, see above ) */ ++ *pre_next = ip->next; ++ ip->magic2 = ip->magic = 0; /* IMPORTANT */ ++ free_page_mol( (ulong)ip ); ++ } ++ } ++ return 0; ++ ++} ++ ++ ++/* Translate a mac-physical address (32 bit, not page-index) ++ * and fill in rpn (and _possibly_ other fields) of the pte. ++ * The WIMG bits are not modified after this call. ++ * The calling function is not supposed to alter the pte after ++ * this function call. ++ * ++ * Retuns: ++ * 0 no translation found ++ * block_flags translation found ++ */ ++ ++int ++mphys_to_pte( kernel_vars_t *kv, ulong mphys, ulong *the_pte1, int is_write, pte_lvrange_t **lvrange ) ++{ ++ DECLARE_IOD; ++ int i, num_btrans; ++ block_trans_t *p; ++ io_page_t *p2; ++ int pte1 = *the_pte1; ++ ++ num_btrans = iod->num_btrans; ++ mphys &= ~0xfff; ++ ++ /* check for emuaccel page */ ++ if( mphys == kv->emuaccel_mphys && kv->emuaccel_page_phys ) { ++ /* printk("emuaccel - PTE-insert\n"); */ ++ pte1 |= kv->emuaccel_page_phys; ++ /* supervisor r/w, no user access */ ++ pte1 &= ~(PTE1_W | PTE1_I | PTE1_PP); ++ *lvrange = NULL; ++ *the_pte1 = pte1; ++ return MAPPING_VALID | MAPPING_PHYSICAL; ++ } ++ ++ /* check for a block mapping. */ ++ for( p=iod->btable, i=0; imbase < (ulong)p->size ) { ++ if( (p->flags & MAPPING_SCRATCH) ) { ++ /* it is OK to return silently if we run out of memory */ ++ if( !scratch_page && !(scratch_page=(char*)alloc_page_mol()) ) ++ return 0; ++ pte1 |= tophys_mol(scratch_page); ++ } else ++ pte1 |= (mphys - p->mbase + (ulong)p->lvbase) & PTE1_RPN; ++ ++ if( p->flags & MAPPING_FORCE_CACHE ) { ++ /* use write through for now */ ++ pte1 |= PTE1_W; ++ pte1 &= ~PTE1_I; ++ } else if( !(p->flags & MAPPING_MACOS_CONTROLS_CACHE) ) ++ pte1 &= ~(PTE1_W | PTE1_I); ++ ++ /* well, just a try... */ ++ if ( p->flags & MAPPING_FORCE_WRITABLE ) { ++ /* printk("forcing mphys page %lx writable\n", mphys); */ ++ pte1 = (pte1 & ~3) | 2; ++ } ++ ++ *lvrange = p->lvrange; ++ *the_pte1 = pte1; ++ return p->flags; ++ } ++ } ++ ++ /* check for an I/O mapping. */ ++ for( p2=iod->io_page_head; p2 && p2->mphys<=mphys; p2=p2->next ) { ++ if( p2->mphys != mphys ) ++ continue; ++ pte1 |= p2->me_phys; ++ /* supervisor R/W */ ++ pte1 &= ~(PTE1_PP | PTE1_W | PTE1_I); ++ *lvrange = NULL; ++ *the_pte1 = pte1; ++ return MAPPING_VALID | MAPPING_IO | MAPPING_PHYSICAL; ++ } ++ return 0; ++} ++ ++void ++mmu_add_map( kernel_vars_t *kv, struct mmu_mapping *m ) ++{ ++ if( m->flags & MAPPING_MREGS ) { ++ char *start = (char*)tophys_mol(&kv->mregs); ++ uint offs = (uint)m->lvbase; ++ m->flags &= ~MAPPING_MREGS; ++ m->flags |= MAPPING_PHYSICAL; ++ m->lvbase = start + offs; ++ m->id = -1; ++ if( offs + (uint)m->size > NUM_MREGS_PAGES * 0x1000 ) { ++ printk("Invalid mregs mapping\n"); ++ return; ++ } ++ } ++ m->id = add_block_trans( kv, m->mbase, m->lvbase, m->size, m->flags ); ++} ++ ++void ++mmu_remove_map( kernel_vars_t *kv, struct mmu_mapping *m ) ++{ ++ remove_block_trans( kv, m->id ); ++ m->id = 0; ++} +--- /dev/null ++++ b/drivers/macintosh/mol/mmu_tracker.c +@@ -0,0 +1,128 @@ ++/* ++ * Creation Date: <2000/09/07 20:36:54 samuel> ++ * Time-stamp: <2004/02/14 14:45:33 samuel> ++ * ++ * ++ * ++ * Keeps track of dirty RAM pages ++ * ++ * Copyright (C) 2000, 2001, 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "alloc.h" ++#include "uaccess.h" ++#include "mmu.h" ++ ++ ++typedef struct tracker_data { ++ char *table; ++ size_t table_size; ++ ++ int npages; ++ ulong lvbase; ++} tracker_data_t; ++ ++#define MMU (kv->mmu) ++#define DECLARE_TS tracker_data_t *ts = MMU.tracker_data ++ ++ ++ ++int ++init_mmu_tracker( kernel_vars_t *kv ) ++{ ++ /* track_lvrange does the initialization */ ++ return 0; ++} ++ ++void ++cleanup_mmu_tracker( kernel_vars_t *kv ) ++{ ++ DECLARE_TS; ++ if( !ts ) ++ return; ++ ++ if( ts->table ) ++ vfree_mol( ts->table ); ++ ++ kfree_mol( ts ); ++ MMU.tracker_data = NULL; ++} ++ ++int ++track_lvrange( kernel_vars_t *kv ) ++{ ++ ulong lvbase = MMU.userspace_ram_base; ++ int size = MMU.ram_size; ++ ++ DECLARE_TS; ++ if( ts ) ++ cleanup_mmu_tracker( kv ); ++ if( !size ) ++ return 0; ++ ++ if( !(ts=kmalloc_mol(sizeof(tracker_data_t))) ) ++ return 1; ++ memset( ts, 0, sizeof(tracker_data_t) ); ++ MMU.tracker_data = ts; ++ ++ ts->npages = size >> 12; ++ ts->table_size = (ts->npages+7)/8; ++ ts->lvbase = lvbase; ++ if( !(ts->table=vmalloc_mol(ts->table_size)) ) { ++ cleanup_mmu_tracker( kv ); ++ return 1; ++ } ++ memset( ts->table, 0, ts->table_size ); ++ return 0; ++} ++ ++void ++lvpage_dirty( kernel_vars_t *kv, ulong lvbase ) ++{ ++ DECLARE_TS; ++ int pgindex; ++ ++ if( !ts ) ++ return; ++ ++ pgindex = (lvbase - ts->lvbase) >> 12; ++ ++ if( pgindex >=0 && pgindex < ts->npages ) ++ ts->table[pgindex >> 3] |= (1 << (pgindex & 7)); ++} ++ ++ ++size_t ++get_track_buffer( kernel_vars_t *kv, char *retbuf ) ++{ ++ DECLARE_TS; ++ ++ if( !ts ) ++ return 0; ++ if( !retbuf ) ++ return ts->table_size; ++ ++ if( copy_to_user_mol(retbuf, ts->table, ts->table_size) ) ++ return 0; ++ return ts->table_size; ++} ++ ++void ++set_track_buffer( kernel_vars_t *kv, char *buf ) ++{ ++ DECLARE_TS; ++ ++ if( !ts || !buf ) { ++ printk("set_track_buffer: error\n"); ++ return; ++ } ++ if( copy_from_user_mol(ts->table, buf, ts->table_size) ) { ++ printk("set_track_buffer: Bad access\n"); ++ } ++} +--- /dev/null ++++ b/drivers/macintosh/mol/mtable.c +@@ -0,0 +1,960 @@ ++/* ++ * Creation Date: <2002/05/26 14:46:42 samuel> ++ * Time-stamp: <2004/02/28 19:33:21 samuel> ++ * ++ * ++ * ++ * Keeps track of all PTEs MOL uses. ++ * ++ * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#ifdef UL_DEBUG ++#include "mtable_dbg.c" ++#else ++#include "archinclude.h" ++#include "alloc.h" ++#include "kernel_vars.h" ++#include "asmfuncs.h" ++#include "mmu.h" ++#include "performance.h" ++#endif ++#include "mtable.h" ++#include "hash.h" ++ ++/* #define DEBUG */ ++ ++/* ++ * Implementation notes: ++ * ++ * - It is assumed bit the ITLB/DTLB is addressed by ea bits 14-19. ++ * This holds true for all CPUs at the moment (603, 604, 750, 7400, ++ * 7410, 7450) except the 601 (which uses bits 13-19). ++ */ ++ ++typedef struct pterec pterec_t; ++ ++struct pterec { ++ pterec_t *ea_next; /* ea ring (MUST GO FIRST) */ ++ pterec_t *lv_next; /* lv ring */ ++ uint pent; /* defined below */ ++}; ++ ++#define PENT_LV_HEAD BIT(0) /* Resident - do not put on free list */ ++#define PENT_UNUSED BIT(1) /* (lvhead) PTE index is not valid */ ++#define PENT_EA_BIT14 BIT(2) /* for the partial ea used by tlbie */ ++#define PENT_EA_LAST BIT(3) /* next entry is the pelist pointer */ ++#define PENT_TOPEA_MASK 0x0f800000 /* bit 4-8 of ea */ ++#define PENT_SV_BIT 0x00400000 /* PTE uses vsid_sv */ ++#define PENT_INDEX_MASK 0x003fffff /* PTE index (there can be at most 2^22 PTEs) */ ++#define PENT_CMP_MASK (PENT_TOPEA_MASK | PENT_SV_BIT) ++ ++/* The index below corresponds to bit 15-19 of the ea. Bit 14 of the ea ++ * is stored in the pent field. Thus bits 14-19 of the ea can hence always ++ * be reconstructed (this struct is always properly aligned). Note that the ++ * pelist forms a ring (this is the reason why ea_next must be ++ * the first element in the pterec struct). ++ */ ++ ++typedef struct { ++ pterec_t *pelist[32]; /* always NULL if ring is empty */ ++} pent_table_t; ++ ++struct vsid_ent { /* record which describes a mac vsid */ ++ vsid_ent_t *myself_virt; /* virtual address of this struct */ ++ int linux_vsid; /* munged mac context | VSID(Kp) */ ++ int linux_vsid_sv; /* munged privileged mac context | VSID(Kp) */ ++ pent_table_t *lev2[64]; /* bit 9-14 of ea */ ++}; ++ ++#define LEV2_MASK 0x0001ffff /* bit 15-31 */ ++ ++#define LEV2_IND(ea) (((ea) >> (12+5)) & 0x3f) /* lev2 index is bit 9-14 */ ++#define PELIST_IND(ea) (((ea) >> 12) & 0x1f) /* pelist index is 15-19 */ ++ ++#define PTE_TO_IND(pte) ((((int)pte - (int)ptehash.base) & ptehash.pte_mask) >> 3) ++ ++#define ZERO_PTE(pent) *((ulong*)ptehash.base + ((pent & PENT_INDEX_MASK) << 1)) = 0 ++ ++ ++struct pte_lvrange { ++ pterec_t *pents; ++ ulong base; /* we want to do unsigned compares */ ++ ulong size; ++ pte_lvrange_t *next; /* linked list */ ++}; ++ ++typedef struct alloc_ent { ++ struct alloc_ent *next; ++ char *ptr; ++ int what; /* ALLOC_CONTENTS_XXX */ ++} alloc_ent_t; ++ ++struct vsid_info { ++ mol_spinlock_t lock; /* lvrange and pent ring lock */ ++ ++ pte_lvrange_t *lvrange_head; ++ pterec_t *free_pents; /* free list (lv_next is used) */ ++ pent_table_t *free_pent_tables; /* pelist[0] is used for the linked list */ ++ ++ alloc_ent_t *allocations; /* the allocations we have performed */ ++ int alloc_size; /* total size of allocations */ ++ int alloc_limit; /* imposed limit */ ++}; ++ ++/* don't change the CHUNK_SIZE unless you know what you are doing... */ ++#define CHUNK_SIZE (0x1000 - sizeof(alloc_ent_t)) ++ ++#define ALLOC_CONT_ANY 0 ++#define ALLOC_CONT_VSID 1 ++#define ALLOC_CONT_PENT 2 ++#define ALLOC_CONT_LEV2 3 ++ ++#define MMU (kv->mmu) ++ ++#define LOCK spin_lock_mol( &vi->lock ) ++#define UNLOCK spin_unlock_mol( &vi->lock ) ++ ++/* ++ * Remarks about locking: There is one asynchronous entrypoint ++ * (flush_lvptr). This function touches the lvranges as well ++ * as all pent rings. It will not free vsids or unlink ++ * level2 tables (but pents are put on the free list). ++ */ ++ ++ ++/************************************************************************/ ++/* Table Flushing */ ++/************************************************************************/ ++ ++#define vsid_ent_lookup( kv, mvsid ) ((vsid_ent_t*)skiplist_lookup( &kv->mmu.vsid_sl, mvsid )) ++ ++static void ++flush_vsid_ea_( vsid_info_t *vi, vsid_ent_t *r, ulong ea ) ++{ ++ pent_table_t *t = r->lev2[LEV2_IND(ea)]; ++ pterec_t **pp, **headp, *pr, *next, *lvp; ++ uint topea, pent; ++ int worked; ++ ++ if( !t || !(*(pp=&t->pelist[PELIST_IND(ea)])) ) ++ return; ++ ++ topea = (ea & PENT_TOPEA_MASK); ++ worked = 0; ++ headp = pp; ++ pr = *pp; ++ do { ++ pent = pr->pent; ++ next = pr->ea_next; ++ ++ if( (pent & PENT_TOPEA_MASK) == topea ) { ++ worked = 1; ++ /* unlink ea */ ++ *pp = pr->ea_next; ++ ++ /* unlink it from lv ring (unless it is the lv-head) */ ++ if( pent & PENT_LV_HEAD ) { ++ pr->pent = PENT_UNUSED | PENT_LV_HEAD; ++ } else { ++ /* it is not certain it belong to a lv ring at all... */ ++ if( pr->lv_next ) { ++ for( lvp=pr->lv_next ; lvp->lv_next != pr ; lvp=lvp->lv_next ) ++ ; ++ lvp->lv_next = pr->lv_next; ++ } ++ /* ...and put it on the free list */ ++ //printk("pent released\n"); ++ pr->lv_next = vi->free_pents; ++ vi->free_pents = pr; ++ } ++ ZERO_PTE( pent ); ++ ++ if( pent & PENT_EA_LAST ) { ++ if( pp == headp ) { ++ /* ring empty, set pelist pointer to NULL */ ++ *headp = NULL; ++ } else { ++ /* put marker on previous entry */ ++ ((pterec_t*)pp)->pent |= PENT_EA_LAST; ++ } ++ } ++ } else { ++ pp = &pr->ea_next; ++ } ++ pr = next; ++ } while( !(pent & PENT_EA_LAST) ); ++ ++ if( worked ) ++ __tlbie( ea ); ++} ++ ++void ++flush_vsid_ea( kernel_vars_t *kv, int mac_vsid, ulong ea ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ vsid_ent_t *r; ++ ++ LOCK; ++ if( (r=vsid_ent_lookup(kv, mac_vsid)) ) ++ flush_vsid_ea_( vi, r, ea ); ++ UNLOCK; ++} ++ ++ ++static void ++pent_flush_unlink_ea( pterec_t *pr ) ++{ ++ pterec_t **head, *prev; ++ uint ea; ++ ++ //BUMP( pent_flush_unlink_ea ); ++#ifdef DEBUG ++ if( pr->pent & PENT_UNUSED ) ++ printk("pent_flush_unlink_ea: Internal error\n"); ++#endif ++ /* find head and previous pent in ea ring */ ++ for( prev=pr; !(prev->pent & PENT_EA_LAST); prev=prev->ea_next ) ++ ; ++ head = (pterec_t**)prev->ea_next; ++ for( ; prev->ea_next != pr ; prev=prev->ea_next ) ++ ; ++ ++ if( (pr->pent & PENT_EA_LAST) ) { ++ /* just a single entry in the ea ring? */ ++ if( prev == (pterec_t*)head ) { ++ pr->ea_next = NULL; /* prev->ea_next is set to this below */ ++ } else { ++ prev->pent |= PENT_EA_LAST; ++ } ++ } ++ prev->ea_next = pr->ea_next; ++ ++ /* OK... it is unlinked. Reconstruct EA and flush it */ ++ ZERO_PTE( pr->pent ); ++ ea = ((uint)head >> 2) & 0x1f; /* Bits 15-19 of ea */ ++ if( pr->pent & PENT_EA_BIT14 ) ++ ea |= 0x20; ++ ea = ea << 12; ++ __tlbie(ea); /* Bits 14-19 used */ ++ ++ // printk("lvflush: ea (bit 14-19) %08X (pent %08X)\n", ea, pr->pent ); ++ ++ /* caller's responsibility to free the pent */ ++} ++ ++static void ++flush_lvptr_( vsid_info_t *vi, ulong lvptr ) ++{ ++ pterec_t *head, *last, *first; ++ pte_lvrange_t *lvr; ++ ++ //BUMP( pent_flush_lvptr ); ++ ++ for( lvr=vi->lvrange_head; lvr && lvptr - lvr->base >= lvr->size ; lvr=lvr->next ) ++ ; ++ if( !lvr ) ++ return; ++ // printk("flush_lvptr: %08lX\n", lvptr ); ++ ++ head = lvr->pents + ((lvptr - lvr->base) >> 12); ++#ifdef DEBUG ++ if( !(head->pent & PENT_LV_HEAD) ) { ++ printk("flush: Internal error\n"); ++ return; ++ } ++#endif ++ /* first pent to be put on the free list */ ++ first = head->lv_next; ++ ++ /* not just a single entry? */ ++ if( first != head ) { ++ last = head; ++ do { ++ last = last->lv_next; ++ pent_flush_unlink_ea( last ); ++ } while( last->lv_next != head ); ++ ++ last->lv_next = vi->free_pents; ++ vi->free_pents = first; ++ } ++ if( !(head->pent & PENT_UNUSED) ) ++ pent_flush_unlink_ea( head ); ++ ++ //head->ea_next = NULL; ++ head->lv_next = head; ++ head->pent = PENT_UNUSED | PENT_LV_HEAD; ++} ++ ++/* asynchronous entrypoint (caused e.g. a swapout) */ ++void ++flush_lvptr( kernel_vars_t *kv, ulong lvptr ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ LOCK; ++ if( (char*)lvptr == MMU.lvptr_reservation ) ++ MMU.lvptr_reservation_lost = 1; ++ flush_lvptr_( vi, lvptr ); ++ UNLOCK; ++} ++ ++ ++void ++flush_lv_range( kernel_vars_t *kv, ulong lvbase, int size ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ LOCK; ++ /* this is quite inefficient but the function is seldom used */ ++ for( ; size > 0 ; lvbase += 0x1000, size -= 0x1000 ) ++ flush_lvptr_( vi, lvbase ); ++ UNLOCK; ++} ++ ++void ++flush_ea_range( kernel_vars_t *kv, ulong org_ea, int size ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ skiplist_iter_t iter; ++ pent_table_t *t; ++ char *userdata; ++ ulong ea, end; ++ int i; ++ ++ //BUMP( flush_ea_range ); ++ //printk("flush_ea_range\n"); ++ ++ LOCK; ++#ifdef DEBUG ++ if( size > 0x10000000 || org_ea & 0xf0000000 ) { ++ printk("flush_ea_range: Bad parameters %08lX %08X\n", org_ea, size); ++ size=0x10000000; ++ org_ea=0; ++ } ++#endif ++ end = org_ea + size; ++ ++ /* XXX: This is horribly inefficient */ ++ iter = skiplist_iterate( &MMU.vsid_sl ); ++ while( skiplist_getnext(&MMU.vsid_sl, &iter, &userdata) ) { ++ vsid_ent_t *r = (vsid_ent_t*)userdata; ++ ea = org_ea; ++ while( ea < end ) { ++ if( !(t=r->lev2[LEV2_IND(ea)]) ) { ++ ea = (ea & ~LEV2_MASK) + LEV2_MASK + 1; ++ continue; ++ } ++ for( i=PELIST_IND(ea); i<32 && ea < end; i++, ea += 0x1000 ) { ++ if( t->pelist[i] ) ++ flush_vsid_ea_( vi, r, ea ); ++ } ++ } ++ } ++ UNLOCK; ++} ++ ++/* clear all pte entries belonging to this vsid */ ++static void ++flush_vsid( vsid_info_t *vi, vsid_ent_t *r ) ++{ ++ pent_table_t *t; ++ ulong ea=0; ++ int i; ++ ++ //BUMP( flush_vsid ); ++ ++ /* not very efficient */ ++ while( ea < 0x10000000 ) { ++ if( !(t=r->lev2[LEV2_IND(ea)]) ) { ++ ea = (ea & ~LEV2_MASK) + LEV2_MASK + 1; ++ continue; ++ } ++ for( i=PELIST_IND(ea); i<32; i++, ea += 0x1000 ) { ++ if( t->pelist[i] ) ++ flush_vsid_ea_( vi, r, ea ); ++ } ++ } ++ /* free level2 tables */ ++ for( i=0; i<64; i++ ) { ++ pent_table_t *t = r->lev2[i]; ++ r->lev2[i] = NULL; ++ ++ /* XXX: The lev2 table _should_ be empty but we ++ * might want to verify this... ++ */ ++ if( t ) { ++ t->pelist[0] = (void*)vi->free_pent_tables; ++ vi->free_pent_tables = t; ++ } ++ } ++} ++ ++ ++/************************************************************************/ ++/* Allocations */ ++/************************************************************************/ ++ ++/* this function allocates 0x1000 - sizeof(alloc_ent_t) zeroed bytes */ ++static void * ++do_chunk_kmalloc( vsid_info_t *vi, int what ) ++{ ++ alloc_ent_t *mp; ++ char *ptr; ++ ++ if( vi->alloc_size > vi->alloc_limit ) ++ return NULL; ++ if( !(ptr=(char*)alloc_page_mol()) ) ++ return NULL; ++ mp = (alloc_ent_t*)((char*)ptr + 0x1000 - sizeof(alloc_ent_t)); ++ ++ mp->next = vi->allocations; ++ mp->ptr = ptr; ++ mp->what = what; ++ vi->allocations = mp; ++ ++ vi->alloc_size += 0x1000; ++ BUMP_N( alloced, 0x1000 ); ++ return ptr; ++} ++ ++static void ++do_kfree( vsid_info_t *vi, int what ) ++{ ++ alloc_ent_t *p, **mp = &vi->allocations; ++ ++ while( *mp ) { ++ p = *mp; ++ if( p->what == what || what == ALLOC_CONT_ANY ) { ++ *mp = p->next; ++ free_page_mol( (ulong)p->ptr ); ++ ++ vi->alloc_size -= 0x1000; ++ BUMP_N( released, 0x1000 ); ++ } else { ++ mp = &p->next; ++ } ++ } ++} ++ ++/* Note: mtable_memory_check() must have been called previously */ ++static inline pent_table_t * ++get_free_lev2( vsid_info_t *vi ) ++{ ++ pent_table_t *t = vi->free_pent_tables; ++ ++ vi->free_pent_tables = (pent_table_t*)vi->free_pent_tables->pelist[0]; ++ t->pelist[0] = NULL; ++ return t; ++} ++ ++/* this function is responsible for setting PENT_LV_HEAD and lv_next */ ++static pterec_t * ++get_free_pent( vsid_info_t *vi, pte_lvrange_t *lvrange, char *lvptr ) ++{ ++ pterec_t *pr, *pr2; ++ int pent = 0; ++ int ind; ++ ++ if( lvrange ) { ++ ind = (((int)lvptr - lvrange->base) >> 12); ++ pr2 = &lvrange->pents[ind]; ++ ++ if( (pr2->pent & PENT_UNUSED) ) { ++ pr = pr2; ++ pent = PENT_LV_HEAD; ++ } else { ++ /* alloc new entry */ ++ pr = vi->free_pents; ++ vi->free_pents = pr->lv_next; ++ ++ /* add to lv ring (after the head element) */ ++ pr->lv_next = pr2->lv_next; ++ pr2->lv_next = pr; ++ } ++ } else { ++ /* alloc new entry */ ++ pr = vi->free_pents; ++ vi->free_pents = pr->lv_next; ++ ++ pr->lv_next = NULL; ++ } ++ ++ /* allocate pterec_t and insert into the lv ring */ ++ pr->pent = pent; ++ return pr; ++} ++ ++static int ++lev2_alloc( vsid_info_t *vi ) ++{ ++ const int m = sizeof(pent_table_t) - 1; ++ pent_table_t *t; ++ int i, n = CHUNK_SIZE/sizeof(pent_table_t); ++ ++ //BUMP( lev2_alloc ); ++ ++ if( !(t=do_chunk_kmalloc(vi, ALLOC_CONT_LEV2)) ) ++ return 1; ++ ++ /* the alignment must be correct (the ea calculation will fail otherwise) */ ++ if( (int)t & m ) { ++ t = (pent_table_t*)((int)t + m + 1 - ((int)t & m)); ++ n--; ++ } ++ ++ memset( t, 0, n*sizeof(pent_table_t) ); ++ for( i=0; ifree_pent_tables; ++ vi->free_pent_tables = &t[0]; ++ UNLOCK; ++ return 0; ++} ++ ++static int ++pent_alloc( vsid_info_t *vi ) ++{ ++ const int n = CHUNK_SIZE/sizeof(pterec_t); ++ pterec_t *pr; ++ int i; ++ ++ //BUMP( pent_alloc ); ++ ++ if( !(pr=do_chunk_kmalloc(vi, ALLOC_CONT_PENT)) ) ++ return 1; ++ memset( pr, 0, CHUNK_SIZE ); ++ ++ for( i=0; ifree_pents; ++ vi->free_pents = &pr[0]; ++ UNLOCK; ++ return 0; ++} ++ ++ ++/* This function is to be called at a safe time (it might allocate ++ * memory). It ensures the next pte_inserted call will succeed. ++ */ ++int ++mtable_memory_check( kernel_vars_t *kv ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ ++ /* optimize the common case */ ++ if( vi->free_pents && vi->free_pent_tables ) ++ return 0; ++ ++ if( !vi->free_pent_tables ) ++ lev2_alloc(vi); ++ if( !vi->free_pents ) ++ pent_alloc(vi); ++ ++ if( !vi->free_pents || !vi->free_pent_tables ) { ++ clear_all_vsids( kv ); ++ return 1; ++ } ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* pte_insert */ ++/************************************************************************/ ++ ++static inline void ++relink_lv( vsid_info_t *vi, pterec_t *pr, pte_lvrange_t *lvrange, char *lvptr ) ++{ ++ int ind = (((int)lvptr - lvrange->base) >> 12); ++ pterec_t *pnew, *p, *lv_head = &lvrange->pents[ind]; ++ ++ if( !pr->lv_next ) { ++ //printk("Not previously on lvlist\n"); ++ pr->lv_next = lv_head->lv_next; ++ lv_head->lv_next = pr; ++ return; ++ } ++ ++ if( pr->pent & PENT_LV_HEAD ) { ++ if( pr == lv_head ) { ++ //printk("lvptr is head (correct lv ring)\n"); ++ return; ++ } ++ ++ /* unlink from ea ring and add new pent */ ++ for( p=pr->ea_next; p->ea_next != pr ; p=p->ea_next ) ++ ; ++ pnew = get_free_pent( vi, lvrange, lvptr ); ++ pnew->ea_next = pr->ea_next; ++ p->ea_next = pnew; ++ ++ pnew->pent |= (pr->pent & ~(PENT_UNUSED | PENT_LV_HEAD)); ++ ++ /* clear old lvhead */ ++ // pr->ea_next = NULL; ++ pr->pent = PENT_LV_HEAD | PENT_UNUSED; ++ ++ //printk("lvptr is head\n"); ++ return; ++ } else { ++ for( p=pr->lv_next; !(p->pent & PENT_LV_HEAD) ; p=p->lv_next ) ++ ; ++ if( p == lv_head ) { ++ //printk("lvptr is on the correct lv ring\n"); ++ return; ++ } ++ ++ /* lvptr has chagned, unlink */ ++ for( ; p->lv_next != pr ; p=p->lv_next ) ++ ; ++ p->lv_next = pr->lv_next; ++ ++ /* add to lv ring */ ++ pr->lv_next = lv_head->lv_next; ++ lv_head->lv_next = pr; ++ } ++} ++ ++/* Note: If lvrange is NULL then lvptr should be ignored */ ++void ++pte_inserted( kernel_vars_t *kv, ulong ea, char *lvptr, pte_lvrange_t *lvrange, ++ ulong *pte, vsid_ent_t *r, int segreg ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ int pl_ind = PELIST_IND(ea); ++ uint pent, pent_cmp; ++ pterec_t *pr, **pp; ++ pent_table_t **tt; ++ ++ LOCK; ++ if( lvrange && MMU.lvptr_reservation_lost ) { ++ printk("mtable: lvptr reservation lost %08x\n", (int)lvptr ); ++ pte[0] = 0; ++ __tlbie(ea); ++ goto out; ++ } ++ ++ tt = &r->lev2[ LEV2_IND(ea) ]; ++ ++ pent_cmp = (ea & PENT_TOPEA_MASK); ++ if( (r->linux_vsid_sv & VSID_MASK) == (segreg & VSID_MASK) ) ++ pent_cmp |= PENT_SV_BIT; ++ ++ if( !*tt ) ++ *tt = get_free_lev2(vi); ++ ++ pp = &(**tt).pelist[ pl_ind ]; ++ if( (pr=*pp) ) { ++ do { ++ pent = pr->pent; ++ if( (pent & PENT_CMP_MASK) == pent_cmp ) { ++ pent &= ~PENT_INDEX_MASK; ++ pent |= PTE_TO_IND(pte); ++ pr->pent = pent; ++ ++ /* the lvptr might have changed */ ++ if( lvrange ) ++ relink_lv( vi, pr, lvrange, lvptr ); ++ else { ++ /* The pent might belong to a lvring unnecessarily. ++ * It is not worth the extra overhead addressing this ++ * (uncommon) case ++ */ ++ } ++ //printk("PTE entry reused\n"); ++ goto out; ++ } ++ pr=pr->ea_next; ++ } while( !(pent & PENT_EA_LAST) ); ++ ++ /* get_free_pent inserts the entry into the lvring and sets a few pent bits */ ++ pr = get_free_pent(vi, lvrange, lvptr); ++ pr->pent |= PTE_TO_IND(pte) | pent_cmp | ((ea & BIT(14)) ? PENT_EA_BIT14 : 0); ++ ++ /* insert in (non-empty) ea ring */ ++ pr->ea_next = *pp; ++ *pp = pr; ++ } else { ++ /* ea ring was empty */ ++ pr = *pp = get_free_pent(vi, lvrange, lvptr); ++ pr->pent |= PENT_EA_LAST | PTE_TO_IND(pte) | pent_cmp ++ | ((ea & BIT(14)) ? PENT_EA_BIT14 : 0); ++ pr->ea_next = (pterec_t*)pp; ++ } ++ out: ++ UNLOCK; ++} ++ ++ ++/************************************************************************/ ++/* VSID allocation */ ++/************************************************************************/ ++ ++/* initialize vsid element callback (ind loops from 0 to n-1) */ ++static void ++_vsid_el_callback( char *data, int ind, int n, void *usr1_kv, void *dummy ) ++{ ++ kernel_vars_t *kv = (kernel_vars_t*)usr1_kv; ++ vsid_ent_t *r = (vsid_ent_t*)data; ++ ++ r->linux_vsid = alloc_context(kv) | VSID_Kp; ++ r->linux_vsid_sv = alloc_context(kv) | VSID_Kp; ++ r->myself_virt = r; ++} ++ ++/* mac_vsid might be negative (used as vsid for unmapped access). ++ * Thus, do not apply this VSID mask anywhere... ++ */ ++static vsid_ent_t * ++alloc_vsid_ent( kernel_vars_t *kv, int mac_vsid ) ++{ ++ char *buf; ++ ++ if( skiplist_needalloc(&MMU.vsid_sl) ) { ++ /* this check might invoke clear_all_vsids() */ ++ handle_context_wrap( kv, CHUNK_SIZE/sizeof(vsid_ent_t)*2 ); ++ ++ if( !(buf=do_chunk_kmalloc(MMU.vsid_info, ALLOC_CONT_VSID)) ) ++ return NULL; ++ memset( buf, 0, CHUNK_SIZE ); ++ ++ (void) skiplist_prealloc( &MMU.vsid_sl, buf, CHUNK_SIZE, _vsid_el_callback, kv, NULL ); ++ } ++ return (vsid_ent_t*)skiplist_insert( &MMU.vsid_sl, mac_vsid ); ++} ++ ++/* flushes all vsids (including the fake no-MMU vsids) */ ++void ++clear_all_vsids( kernel_vars_t *kv ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ skiplist_iter_t iter; ++ char *userdata; ++ ++ LOCK; ++ iter = skiplist_iterate( &MMU.vsid_sl ); ++ while( skiplist_getnext(&MMU.vsid_sl, &iter, &userdata) ) ++ flush_vsid( vi, (vsid_ent_t*)userdata ); ++ ++ skiplist_init( &MMU.vsid_sl, sizeof(vsid_ent_t) ); ++ ++ /* flush any dangling pointers */ ++ clear_vsid_refs( kv ); ++ ++ /* all vsids cleared -> all lev2 cleared -> no pents in use */ ++ vi->free_pents = NULL; ++ vi->free_pent_tables = NULL; ++ UNLOCK; ++ do_kfree( vi, ALLOC_CONT_ANY ); ++ ++ BUMP(clear_all_vsids); ++} ++ ++/* This function flushes *ALL* PTEs inserted by MOL. It is primarily ++ * used when it is too difficult to make a more specific invalidation. ++ */ ++void ++clear_pte_hash_table( kernel_vars_t *kv ) ++{ ++ /* this will free the vsids too... */ ++ clear_all_vsids( kv ); ++} ++ ++vsid_ent_t * ++vsid_get_user_sv( kernel_vars_t *kv, int mac_vsid, ulong *user_ret, ulong *sv_ret ) ++{ ++ vsid_ent_t *r = vsid_ent_lookup( kv, mac_vsid ); ++ ++ if( !r && !(r=alloc_vsid_ent(kv, mac_vsid)) ) { ++ clear_all_vsids( kv ); ++ if( !(r=alloc_vsid_ent(kv, mac_vsid)) ) { ++ printk("VSID allocation failure\n"); ++ return NULL; ++ } ++ } ++ *user_ret = r->linux_vsid; ++ *sv_ret = r->linux_vsid_sv; ++ return r; ++} ++ ++/************************************************************************/ ++/* resource reclaiming */ ++/************************************************************************/ ++ ++void ++mtable_reclaim( kernel_vars_t *kv ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ skiplist_iter_t iter; ++ pent_table_t *t; ++ char *userdata; ++ int i,j; ++ ++ /* This thread runs on the main thread, thus the skiplist stuff does ++ * not need locking. In fact, it is only the free_pent_tables ++ * list that needs spinlock protection. ++ */ ++ LOCK; ++ iter = skiplist_iterate( &MMU.vsid_sl ); ++ while( skiplist_getnext(&MMU.vsid_sl, &iter, &userdata) ) { ++ vsid_ent_t *r = (vsid_ent_t*)userdata; ++ const int n1 = sizeof(r->lev2)/sizeof(r->lev2[0]); ++ const int n2 = sizeof(t->pelist)/sizeof(t->pelist[0]); ++ ++ for( i=0; ilev2[i]) ) ++ continue; ++ for( j=0; jpelist[j]) ; j++ ) ++ ; ++ if( j != n2 ) ++ break; ++ /* level2 empty... */ ++ r->lev2[i]->pelist[0] = (void*)vi->free_pent_tables; ++ vi->free_pent_tables = r->lev2[i]; ++ r->lev2[i] = NULL; ++ ++ BUMP(lev2_reclaim); ++ } ++ if( i == n1 ) { ++ int vsid = skiplist_iter_getkey( &MMU.vsid_sl, (char*)r ); ++ ++ /* the segment might be in use... */ ++ for( i=0; i<16 && MMU.vsid[i] != r; i++ ) ++ ; ++ if( i != 16 || (uint)vsid > VSID_MASK ) ++ continue; ++ skiplist_delete( &MMU.vsid_sl, vsid ); ++ BUMP(vsid_reclaim); ++ } ++ } ++ UNLOCK; ++} ++ ++/************************************************************************/ ++/* lvrange allocation */ ++/************************************************************************/ ++ ++pte_lvrange_t * ++register_lvrange( kernel_vars_t *kv, char *lvbase, int size ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ pte_lvrange_t *lvr; ++ int i, nel = (size >> 12); ++ int s = sizeof(pterec_t) * nel; ++ ++ /* printk("register_lvrange\n"); */ ++ ++ if( !(lvr=kmalloc_mol(sizeof(pte_lvrange_t))) ) ++ return NULL; ++ memset( lvr, 0, sizeof(pte_lvrange_t) ); ++ ++ if( !(lvr->pents=vmalloc_mol(s)) ) { ++ kfree_mol( lvr ); ++ return NULL; ++ } ++ /* setup empty lvrings */ ++ for( i=0; ipents[i].pent = PENT_LV_HEAD | PENT_UNUSED; ++ lvr->pents[i].lv_next = &lvr->pents[i]; ++ lvr->pents[i].ea_next = NULL; ++ } ++ lvr->base = (ulong)lvbase; ++ lvr->size = size; ++ ++ LOCK; ++ /* add to linked list */ ++ lvr->next = vi->lvrange_head; ++ vi->lvrange_head = lvr; ++ UNLOCK; ++ ++ return lvr; ++} ++ ++void ++free_lvrange( kernel_vars_t *kv, pte_lvrange_t *lvrange ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ pte_lvrange_t **lvr; ++ ++ lvr = &vi->lvrange_head; ++ for( ; *lvr && *lvr != lvrange; lvr=&(**lvr).next ) ++ ; ++ if( !*lvr ) { ++ printk("free_lvrange: Internal error\n"); ++ return; ++ } ++ flush_lv_range( kv, (**lvr).base, (**lvr).size ); ++ LOCK; ++ *lvr = (**lvr).next; ++ UNLOCK; ++ ++ vfree_mol( lvrange->pents ); ++ kfree_mol( lvrange ); ++} ++ ++/************************************************************************/ ++/* init / cleanup */ ++/************************************************************************/ ++ ++void ++mtable_tune_alloc_limit( kernel_vars_t *kv, int ramsize_mb ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ vi->alloc_limit = (ramsize_mb + 160) * 4096; ++ /* printk("alloc_limit: %d K\n", vi->alloc_limit/1024 ); */ ++} ++ ++int ++init_mtable( kernel_vars_t *kv ) ++{ ++ vsid_info_t *vi = kmalloc_mol( sizeof(vsid_info_t) ); ++ ++ MMU.vsid_info = vi; ++ if( !vi ) ++ return 1; ++ memset( vi, 0, sizeof(vsid_info_t) ); ++ spin_lock_init_mol( &vi->lock ); ++ ++ /* will be tuned when we know how much RAM we have */ ++ vi->alloc_limit = 2 * 1024 * 1024; ++ ++ skiplist_init( &MMU.vsid_sl, sizeof(vsid_ent_t) ); ++ ++ if( !VSID_OFFSETS_OK ) { ++ printk("VSID offsets are BAD (fix offset in source)!\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++void ++cleanup_mtable( kernel_vars_t *kv ) ++{ ++ vsid_info_t *vi = MMU.vsid_info; ++ ++ if( vi ) { ++ while( vi->lvrange_head ) { ++ printk("Bug: lvrange unreleased!\n"); ++ free_lvrange( kv, vi->lvrange_head ); ++ } ++ do_kfree( vi, ALLOC_CONT_ANY ); ++ kfree_mol( vi ); ++ } ++ memset( &MMU.vsid_sl, 0, sizeof(MMU.vsid_sl) ); ++ MMU.vsid_info = NULL; ++} ++ ++ ++/************************************************************************/ ++/* userland debug */ ++/************************************************************************/ ++ ++#ifdef UL_DEBUG ++#include "mtable_dbg.c" ++#endif +--- /dev/null ++++ b/drivers/macintosh/mol/ptaccess.c +@@ -0,0 +1,153 @@ ++/* ++ * Creation Date: <2001/03/25 18:04:45 samuel> ++ * Time-stamp: <2002/08/03 17:43:10 samuel> ++ * ++ * ++ * ++ * Handle stores to the (emulated) page table ++ * ++ * Copyright (C) 2001, 2002 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "mmu.h" ++#include "rvec.h" ++#include "mtable.h" ++#include "misc.h" ++#include "performance.h" ++ ++extern int do_intercept_tlbie( kernel_vars_t *kv, ulong pte0, ulong pte1, ulong pteoffs ); ++extern int do_intercept_tlbie_block( kernel_vars_t *kv, ulong pteoffs, ulong length ); ++ ++#define MMU (kv->mmu) ++#define MREGS (kv->mregs) ++ ++int ++do_intercept_tlbie( kernel_vars_t *kv, ulong pte0, ulong pte1, ulong pteoffs ) ++{ ++ int vsid = (pte0 >> 7) & VSID_MASK; ++ ulong v; ++ ++ BUMP( do_intercept_tlbie ); ++ ++ if( MMU.pthash_inuse_bits ) ++ clear_bit_mol( pteoffs >> 3, MMU.pthash_inuse_bits ); ++ ++ v = (pteoffs >> 6); ++ if( pte0 & BIT(25) ) /* secondary hash? */ ++ v = ~v; ++ v ^= (pte0 >> 7); ++ v = ((pte0 << 10) & 0xfc00) | (v & 0x3ff); ++ ++ //printk("do_intercept_tlbie: vsid %08lX, ea %08lX\n", vsid, (v<<12) ); ++ flush_vsid_ea( kv, vsid, (v<<12) ); ++ ++ return RVEC_NOP; ++} ++ ++int ++do_intercept_tlbie_block( kernel_vars_t *kv, ulong pteoffs, ulong length ) ++{ ++ unsigned int finish; ++ ++ //printk("do_intercept_tlbie_block: pteoffs %08lX length %08lX\n", pteoffs, length); ++ ++ if (pteoffs + length > MMU.hash_mask) { ++ printk("do_intercept_tlbie_block: length exceeding hash!\n"); ++ finish = MMU.hash_mask + 1; ++ } else ++ finish = pteoffs + length; ++ ++ if (MMU.pthash_inuse_bits == NULL) ++ return RVEC_NOP; ++ ++ while (pteoffs < finish) { ++ if (check_bit_mol(pteoffs >> 3, MMU.pthash_inuse_bits)) { ++ ulong pte0, pte1; ++ ++ pte0 = *((unsigned int *) (MMU.hash_base + pteoffs)); ++ pte1 = *((unsigned int *) (MMU.hash_base + pteoffs + 4)); ++ do_intercept_tlbie(kv, pte0, pte1, pteoffs); ++ } ++ ++ pteoffs += 8; ++ } ++ ++ return RVEC_NOP; ++} ++ ++#ifdef EMULATE_603 ++ ++extern int do_tlbli( kernel_vars_t *kv, ulong ea ); ++extern int do_tlbld( kernel_vars_t *kv, ulong ea ); ++ ++int ++do_tlbli( kernel_vars_t *kv, ulong ea ) ++{ ++ int ind = (ea >> 12) & 0x1f; ++ mPTE_t *p; ++ ++ //printk("do_tlbli %08lX : %08lX %08lX\n", ea, MREGS.spr[S_ICMP], MREGS.spr[S_RPA] ); ++ if( MREGS.spr[S_SRR1] & BIT(14) ) ++ ind += 32; ++ ++ p = &MMU.ptes_i_603[ind]; ++ if( p->v ) ++ flush_vsid_ea( kv, p->vsid, MMU.ptes_i_ea_603[ind] ); ++ MMU.ptes_i_ea_603[ind] = ea & 0x0ffff000; ++ *(ulong*)p = MREGS.spr[ S_ICMP ]; ++ *((ulong*)p+1) = MREGS.spr[ S_RPA ]; ++ ++ return RVEC_NOP; ++} ++ ++int ++do_tlbld( kernel_vars_t *kv, ulong ea ) ++{ ++ int ind = (ea >> 12) & 0x1f; ++ mPTE_t *p; ++ ++ //printk("do_tlbld %08lX\n", ea ); ++ ++ if( MREGS.spr[S_SRR1] & BIT(14) ) ++ ind += 32; ++ ++ p = &MMU.ptes_d_603[ind]; ++ if( p->v ) ++ flush_vsid_ea( kv, p->vsid, MMU.ptes_d_ea_603[ind] ); ++ MMU.ptes_d_ea_603[ind] = ea & 0x0ffff000; ++ *(ulong*)p = MREGS.spr[ S_DCMP ]; ++ *((ulong*)p+1) = MREGS.spr[ S_RPA ]; ++ ++ return RVEC_NOP; ++} ++ ++int ++do_tlbie( kernel_vars_t *kv, ulong ea ) ++{ ++ int ind = (ea >> 12) & 0x1f; ++ mPTE_t *pi, *pd; ++ ulong *iea, *dea; ++ ++ pi = &MMU.ptes_i_603[ind]; ++ pd = &MMU.ptes_d_603[ind]; ++ iea = &MMU.ptes_i_ea_603[ind]; ++ dea = &MMU.ptes_d_ea_603[ind]; ++ for( ; ind < 64; ind +=32, pd += 32, pi += 32, iea += 32, dea +=32 ) { ++ if( pi->v ) ++ flush_vsid_ea( kv, pi->vsid, *iea ); ++ if( pd->v ) ++ flush_vsid_ea( kv, pd->vsid, *dea ); ++ *(ulong*)pi = 0; ++ *(ulong*)pd = 0; ++ } ++ return RVEC_NOP; ++} ++ ++#endif /* EMULATE_603 */ ++ +--- /dev/null ++++ b/drivers/macintosh/mol/sheep.c +@@ -0,0 +1,701 @@ ++/* ++ * sheep_net.c - Linux driver for SheepShaver/Basilisk II networking (access to raw Ethernet packets) ++ * ++ * SheepShaver (C) 1997-1999 Mar"c" Hellwig and Christian Bauer ++ * Basilisk II (C) 1997-1999 Christian Bauer ++ * ++ * Ported to 2.4 and reworked, Samuel Rydh 1999-2003 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Marc Hellwig and Christian Bauer"); ++MODULE_DESCRIPTION("SheepShaver/Basilisk II networking"); ++MODULE_LICENSE("GPL"); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ++#define LINUX_26 ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) ++#define ETH_HDR(skb) eth_hdr((skb)) ++#else ++#define ETH_HDR(skb) (skb)->mac.ethernet ++#endif ++ ++#define DEBUG 0 ++ ++#define bug printk ++#if DEBUG ++#define D(x) (x); ++#else ++#define D(x) ; ++#endif ++ ++#define SHEEP_NET_MINOR 198 // Driver minor number ++#define MAX_QUEUE 32 // Maximum number of packets in queue ++#define PROT_MAGIC 1520 // Our "magic" protocol type ++ ++#define ETH_ADDR_MULTICAST 0x1 ++#define ETH_ADDR_LOCALLY_DEFINED 0x2 ++ ++#define SIOC_MOL_GET_IPFILTER SIOCDEVPRIVATE ++#define SIOC_MOL_SET_IPFILTER (SIOCDEVPRIVATE + 1) ++ ++struct SheepVars { ++ /* IMPORTANT: the packet_type struct must go first. It no longer (2.6) contains ++ * a data field so we typecast to get the SheepVars struct ++ */ ++ struct packet_type pt; // Receiver packet type ++ struct net_device *ether; // The Ethernet device we're attached to ++ struct sock *skt; // Socket for communication with Ethernet card ++ struct sk_buff_head queue; // Receiver packet queue ++ wait_queue_head_t wait; // Wait queue for blocking read operations ++ unsigned long ipfilter; // only receive ip packets destined for this address ++ char fake_addr[6]; ++}; ++ ++/* ++ * How various hosts address MOL ++ * ++ * External hosts: eth_addr, MOL_IP ++ * Local host: fake_addr, MOL_IP ++ * MOL: fake_addr, MOL_IP ++ */ ++ ++#ifdef LINUX_26 ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) ++#define compat_sk_alloc(a,b,c) sk_alloc( (a), (b), &mol_proto, 1 ) ++#else ++#define compat_sk_alloc(a,b,c) sk_alloc( (a), (b), (c), NULL ) ++#endif ++ ++#define skt_set_dead(skt) do {} while(0) ++#define wmem_alloc sk_wmem_alloc ++#else ++#define compat_sk_alloc sk_alloc ++#define skt_set_dead(skt) (skt)->dead = 1 ++#endif ++ ++/************************************************************************/ ++/* ethernet address masquerading */ ++/************************************************************************/ ++ ++static inline int ++addrcmp( const char *a1, const char *a2 ) ++{ ++ if( *(u32*)a1 != *(u32*)a2 ) ++ return 1; ++ return *((u16*)a1+2) != *((u16*)a2+2); ++} ++ ++/* Outgoing packet. Replace the fake enet addr with the real one. */ ++static inline void ++cpyaddr( char *d, const char *s ) ++{ ++ *(u32*)d = *(u32*)s; ++ *(u16*)&d[4] = *(u16*)&s[4]; ++} ++ ++static void ++demasquerade( struct sk_buff *skb, struct SheepVars *v ) ++{ ++ const char *local_addr = v->ether->dev_addr; ++ const char *fake_addr = v->fake_addr; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) ++ char *p = skb_mac_header(skb); ++#else ++ char *p = skb->mac.raw; ++#endif ++ int proto = *(short*)&p[12]; ++ ++ cpyaddr( &p[6], local_addr ); // Source address ++ ++ // Need to fix ARP packets ++ if( proto == htons(ETH_P_ARP) ) ++ if( !addrcmp(&p[14+8], fake_addr) ) // sender HW-addr ++ cpyaddr( &p[14+8], local_addr ); ++ ++ // ...and AARPs (snap code: 0x00,0x00,0x00,0x80,0xF3) ++ if( !p[17] && *(u32*)&p[18] == 0x000080F3 ){ ++ // XXX: we should perhaps look for the 802 frame too ++ if( !addrcmp(&p[30], fake_addr) ) ++ cpyaddr( &p[30], local_addr ); // sender HW-addr ++ } ++} ++ ++ ++/************************************************************************/ ++/* receive filter (also intercepts outgoing packets) */ ++/************************************************************************/ ++ ++/* This function filters both outgoing and incoming traffic. ++ * ++ * - Outgoing PROT_MAGIC packets are outgoing mol packets ++ * addressed to the world (not to the local host). ++ * ++ * - Outgoing packets addressed to the fake address ++ * are incoming MOL packets (from the local host). ++ * These packets will be seen on the wire, since we can't ++ * block them... ++ * ++ * - Incoming packets which originate from the fake address ++ * are MOL packets addressed to the local host. ++ * ++ * - Incomming external traffic to the MOL IP address are incoming ++ * MOL packets. Linux will see these packets too. (Hmm... if ++ * we change protocol to PROT_MAGIC then linux ought to ignore ++ * them; currently linux responds to ICMP packets even though ++ * the IP address is wrong.) ++ */ ++ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) ++static int ++sheep_net_receiver( struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev ) ++#else ++static int ++sheep_net_receiver( struct sk_buff *skb, struct net_device *dev, struct packet_type *pt ) ++#endif ++{ ++ int multicast = (ETH_HDR(skb)->h_dest[0] & ETH_ADDR_MULTICAST); ++ const char *laddr = dev->dev_addr; ++ struct sk_buff *skb2; ++ struct SheepVars *v = (struct SheepVars*)pt; ++ ++ D(bug("sheep_net: packet received\n")); ++ ++ if( skb->pkt_type == PACKET_OUTGOING ) { ++ // Is this an MOL packet to the world? ++ if( skb->protocol == PROT_MAGIC ) ++ goto drop; ++ ++ if( !multicast ) { ++ // Drop, unless this is a localhost -> MOL transmission */ ++ if( addrcmp((char*)Ð_HDR(skb)->h_dest, v->fake_addr) ) ++ goto drop; ++ ++ /* XXX: If it were possible, we would prevent the packet from beeing sent out ++ * on the wire (after having put it on our packet reception queue). ++ * A transmission to a non-existent mac address will unfortunately ++ * be subnet-visible (having a switched network doesn't help). As a ++ * workaround, we change the destination address to the address of ++ * the controller. This way, the packet ought to be discarded by ++ * switches. ++ */ ++ cpyaddr( Ð_HDR(skb)->h_dest[0], laddr ); ++ } ++ } else { ++ // is this a packet to the local host from MOL? ++ if( !addrcmp((char*)Ð_HDR(skb)->h_source, v->fake_addr) ) ++ goto drop; ++ ++ if( !multicast ) { ++ // if the packet is not meant for this host, discard it ++ if( addrcmp((char*)Ð_HDR(skb)->h_dest, laddr) ) ++ goto drop; ++ ++ // filter IP-traffic ++ if( (skb->protocol == htons(ETH_P_IP)) ) { ++ // drop if not addreesed to MOL? ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) ++ if( !v->ipfilter || (ipip_hdr(skb)->daddr != v->ipfilter) ) ++#else ++ if( !v->ipfilter || (skb->h.ipiph->daddr != v->ipfilter) ) ++#endif ++ goto drop; ++ // we don't want this packet interpreted by linux... ++ skb->protocol = PROT_MAGIC; ++ } ++ } ++ } ++ // Discard packets if queue gets too full ++ if( skb_queue_len(&v->queue) > MAX_QUEUE ) ++ goto drop; ++ ++ /* masquerade. The skb is typically has a refcount != 1 so we play safe ++ * and make a copy before modifying it. This also takes care of fragmented ++ * skbuffs (we might receive those if we are attached to a device with support ++ * for it) ++ */ ++ if( !(skb2=skb_copy(skb, GFP_ATOMIC)) ) ++ goto drop; ++ kfree_skb( skb ); ++ skb = skb2; ++ ++ if( !multicast ) ++ cpyaddr( Ð_HDR(skb)->h_dest[0], v->fake_addr ); ++ ++ // We also want the Ethernet header ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) ++ skb_push( skb, skb->data - skb_mac_header(skb) ); ++#else ++ skb_push( skb, skb->data - skb->mac.raw ); ++#endif ++ ++ // Enqueue packet ++ skb_queue_tail( &v->queue, skb ); ++ ++ // Unblock blocked read ++ wake_up_interruptible( &v->wait ); ++ return 0; ++ ++drop: ++ kfree_skb( skb ); ++ return 0; ++} ++ ++ ++/************************************************************************/ ++/* misc device ops */ ++/************************************************************************/ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) ++static struct proto mol_proto = ++{ ++ .name = "MOL", ++ .owner = THIS_MODULE, ++ .obj_size = sizeof(struct sock) ++}; ++#endif ++ ++ ++static int ++sheep_net_open( struct inode *inode, struct file *f ) ++{ ++ static char fake_addr_[6] = { 0xFE, 0xFD, 0xDE, 0xAD, 0xBE, 0xEF }; ++ struct SheepVars *v; ++ D(bug("sheep_net: open\n")); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) ++ if (proto_register(&mol_proto,0) < 0) ++ { ++ printk(KERN_INFO "Unable to register protocol type\n"); ++ return -1; ++ } ++#endif ++ ++ // Must be opened with read permissions ++ if( (f->f_flags & O_ACCMODE) == O_WRONLY ) ++ return -EPERM; ++ ++ // Allocate private variables ++ f->private_data = kmalloc(sizeof(struct SheepVars), GFP_USER); ++ if( f->private_data == NULL) ++ return -ENOMEM; ++ ++ v = (struct SheepVars *) f->private_data; ++ ++ memset( v, 0, sizeof(*v) ); ++ memcpy( v->fake_addr, fake_addr_, 6 ); ++ ++ skb_queue_head_init( &v->queue ); ++ init_waitqueue_head( &v->wait ); ++ return 0; ++} ++ ++ ++static int ++sheep_net_release( struct inode *inode, struct file *f ) ++{ ++ struct SheepVars *v = (struct SheepVars *)f->private_data; ++ struct sk_buff *skb; ++ D(bug("sheep_net: close\n")); ++ ++ // Detach from Ethernet card ++ if( v->ether ) { ++ dev_remove_pack( &v->pt ); ++ sk_free( v->skt ); ++ v->skt = NULL; ++ dev_put( v->ether ); ++ v->ether = NULL; ++ } ++ ++ // Empty packet queue ++ while( (skb=skb_dequeue(&v->queue)) ) ++ kfree_skb(skb); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) ++ proto_unregister(&mol_proto); ++#endif ++ ++ // Free private variables ++ kfree(v); ++ return 0; ++} ++ ++static inline int ++get_iovsize( const struct iovec *iv, int count ) ++{ ++ int s; ++ for( s=0; count-- ; iv++ ) ++ s += iv->iov_len; ++ return s; ++} ++ ++static int ++memcpy_tov( const struct iovec *iv, const char *buf, int s ) ++{ ++ while( s > 0 ) { ++ int len = min_t( unsigned int, iv->iov_len, s ); ++ ++ if( copy_to_user(iv->iov_base, buf, len) ) ++ return -EFAULT; ++ s -= len; ++ buf += len; ++ iv++; ++ } ++ return 0; ++} ++ ++static int ++memcpy_fromv( char *buf, const struct iovec *iv, int s ) ++{ ++ while( s > 0 ) { ++ int len = min_t( unsigned int, iv->iov_len, s ); ++ ++ if( copy_from_user(buf, iv->iov_base, len) ) ++ return -EFAULT; ++ s -= len; ++ buf += len; ++ iv++; ++ } ++ return 0; ++} ++ ++static ssize_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++sheep_net_aio_read(struct kiocb *iocb, const struct iovec *iv, unsigned long count, loff_t pos) ++{ ++ struct file *f = iocb->ki_filp; ++#else /* Linux 2.6.18 or older */ ++sheep_net_readv( struct file *f, const struct iovec *iv, unsigned long count, loff_t *pos ) ++{ ++#endif ++ struct SheepVars *v = (struct SheepVars *)f->private_data; ++ struct sk_buff *skb; ++ int size = get_iovsize( iv, count ); ++ ++ D(bug("sheep_net: read\n")); ++ ++ while( !(skb=skb_dequeue(&v->queue)) ) { ++ // wait around... ++ if( (f->f_flags & O_NONBLOCK)) ++ return -EAGAIN; ++ ++ interruptible_sleep_on( &v->wait ); ++ ++ if( signal_pending(current) ) ++ return -EINTR; ++ } ++ ++ // Pass packet to caller ++ if( size > skb->len ) ++ size = skb->len; ++ if( memcpy_tov(iv, skb->data, size) ) ++ size = -EFAULT; ++ ++ kfree_skb( skb ); ++ return size; ++} ++ ++static ssize_t ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++sheep_net_aio_write(struct kiocb *iocb, const struct iovec *iv, unsigned long count, loff_t off) ++{ ++ struct file *f = iocb->ki_filp; ++#else /* Linux 2.6.18 or older */ ++sheep_net_writev( struct file *f, const struct iovec *iv, unsigned long count, loff_t *off ) ++{ ++#endif ++ struct SheepVars *v = (struct SheepVars *)f->private_data; ++ struct sk_buff *skb; ++ int size = get_iovsize( iv, count ); ++ char *p, *laddr; ++ D(bug("sheep_net: write\n")); ++ ++ // Check packet size ++ if( size < sizeof(struct ethhdr) ) ++ return -EINVAL; ++ if( size > 1514 ) { ++ printk("sheep_net_write: packet > 1514!\n"); ++ size = 1514; ++ } ++ ++ // Interface active? ++ if( !v->ether ) ++ return size; ++ laddr = v->ether->dev_addr; ++ ++ // Allocate buffer for packet ++ if( !(skb=dev_alloc_skb(size)) ) ++ return -ENOBUFS; ++ ++ // Stuff packet in buffer ++ p = skb_put( skb, size ); ++ if( memcpy_fromv(p, iv, size) ) { ++ kfree_skb(skb); ++ return -EFAULT; ++ } ++ ++ // Transmit packet ++ atomic_add( skb->truesize, &v->skt->wmem_alloc ); ++ skb->sk = v->skt; ++ skb->dev = v->ether; ++ skb->priority = 0; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) ++ skb_set_network_header(skb, v->ether->hard_header_len); ++ skb_set_transport_header(skb, v->ether->hard_header_len); ++ skb_reset_mac_header(skb); ++#else ++ skb->nh.raw = skb->h.raw = skb->data + v->ether->hard_header_len; ++ skb->mac.raw = skb->data; ++#endif ++ ++ // Base the IP-filter on the IP address of outgoing ARPs ++ if( ETH_HDR(skb)->h_proto == htons(ETH_P_ARP) ) { ++ char *s = &skb->data[14+14]; /* source IP-address */ ++ int n[4]; ++ if( *(long*)s != v->ipfilter ) { ++ v->ipfilter = *(long*)s; ++ n[0]=s[0], n[1]=s[1], n[2]=s[2], n[3]=s[3]; ++ printk("IP-filter: %d.%d.%d.%d\n", n[0], n[1], n[2], n[3] ); ++ } ++ } ++ ++ // Is this package addressed solely to the local host? ++ if( !addrcmp(skb->data, laddr) && !(skb->data[0] & ETH_ADDR_MULTICAST) ) { ++ skb->protocol = eth_type_trans( skb, v->ether ); ++ netif_rx_ni( skb ); ++ return size; ++ } ++ if( skb->data[0] & ETH_ADDR_MULTICAST ) { ++ // We can't clone the skb since we will manipulate the data below ++ struct sk_buff *lskb = skb_copy( skb, GFP_ATOMIC ); ++ if( lskb ) { ++ lskb->protocol = eth_type_trans( lskb, v->ether ); ++ netif_rx_ni( lskb ); ++ } ++ } ++ // Outgoing packet (will be seen on the wire) ++ demasquerade( skb, v ); ++ ++ skb->protocol = PROT_MAGIC; // Magic value (we can recognize the packet in sheep_net_receiver) ++ dev_queue_xmit( skb ); ++ return size; ++} ++ ++/* We take care of this using do_sync_* instead in 2.6.19 and newer */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) ++static ssize_t ++sheep_net_read( struct file *f, char *buf, size_t count, loff_t *off ) ++{ ++ struct iovec iv; ++ iv.iov_base = buf; ++ iv.iov_len = count; ++ return sheep_net_readv( f, &iv, 1, off ); ++} ++ ++static ssize_t ++sheep_net_write( struct file *f, const char *buf, size_t count, loff_t *off ) ++{ ++ struct iovec iv; ++ iv.iov_len = count; ++ iv.iov_base = (char *)buf; ++ return sheep_net_writev( f, &iv, 1, off ); ++} ++#endif ++ ++static unsigned int ++sheep_net_poll( struct file *f, struct poll_table_struct *wait ) ++{ ++ struct SheepVars *v = (struct SheepVars *)f->private_data; ++ D(bug("sheep_net: poll\n")); ++ ++ poll_wait( f, &v->wait, wait ); ++ ++ if( !skb_queue_empty(&v->queue) ) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++static int ++sheep_net_ioctl( struct inode *inode, struct file *f, unsigned int code, unsigned long arg ) ++{ ++ struct SheepVars *v = (struct SheepVars *)f->private_data; ++ D(bug("sheep_net: ioctl %04x\n", code)); ++ ++ switch( code ) { ++ // Attach to Ethernet card ++ // arg: pointer to name of Ethernet device (char[20]) ++ case SIOCSIFLINK: { ++ char name[20]; ++ int err; ++ ++ // Already attached? ++ if( v->ether ) ++ return -EBUSY; ++ ++ // Get Ethernet card name ++ if( copy_from_user(name, (void *)arg, 20) ) ++ return -EFAULT; ++ name[19] = 0; ++ ++ // Find card ++ if( !(v->ether=dev_get_by_name(name)) ) ++ return -ENODEV; ++ ++ // Is it Ethernet? ++ if( v->ether->type != ARPHRD_ETHER) { ++ err = -EINVAL; ++ goto error; ++ } ++ ++ // Allocate socket ++ if( !(v->skt=compat_sk_alloc(0, GFP_USER, 1)) ) { ++ err = -ENOMEM; ++ goto error; ++ } ++ skt_set_dead( v->skt ); ++ ++ // Attach packet handler ++ v->pt.type = htons(ETH_P_ALL); ++ v->pt.dev = v->ether; ++ v->pt.func = sheep_net_receiver; ++ //v->pt.data = v; ++ dev_add_pack( &v->pt ); ++ return 0; ++error: ++ if( v->ether ) ++ dev_put( v->ether ); ++ v->ether = NULL; ++ return err; ++ } ++ ++ // Get hardware address of Ethernet card ++ // arg: pointer to buffer (6 bytes) to store address ++ case SIOCGIFADDR: ++ if( copy_to_user((void *)arg, v->fake_addr, 6)) ++ return -EFAULT; ++ return 0; ++ ++ // Set the fake HW-address the client will see ++ case SIOCSIFADDR: ++ if( copy_from_user(v->fake_addr, (void*)arg, 6 )) ++ return -EFAULT; ++ return 0; ++ ++ // Add multicast address ++ // arg: pointer to address (6 bytes) ++ case SIOCADDMULTI: { ++ char addr[6]; ++ int ret; ++ if( !v->ether ) ++ return -ENODEV; ++ if( copy_from_user(addr, (void *)arg, 6)) ++ return -EFAULT; ++ ret = dev_mc_add(v->ether, addr, 6, 0); ++ return ret; ++ } ++ ++ // Remove multicast address ++ // arg: pointer to address (6 bytes) ++ case SIOCDELMULTI: { ++ char addr[6]; ++ if( !v->ether ) ++ return -ENODEV; ++ if( copy_from_user(addr, (void *)arg, 6)) ++ return -EFAULT; ++ return dev_mc_delete(v->ether, addr, 6, 0); ++ } ++ ++#if 0 ++ // Return size of first packet in queue ++ case FIONREAD: { ++ int count = 0; ++ struct sk_buff *skb; ++ long flags; ++ spin_lock_irqsave(&v->queue.lock, flags ); ++ ++ skb = skb_peek(&v->queue); ++ if( skb ) ++ count = skb->len; ++ ++ spin_unlock_irqrestore(&v->queue.lock, flags ); ++ return put_user(count, (int *)arg); ++ } ++#endif ++ case SIOC_MOL_GET_IPFILTER: ++ return put_user(v->ipfilter, (int *)arg ); ++ ++ case SIOC_MOL_SET_IPFILTER: ++ v->ipfilter = arg; ++ return 0; ++ } ++ return -ENOIOCTLCMD; ++} ++ ++ ++/************************************************************************/ ++/* init / cleanup */ ++/************************************************************************/ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) ++static struct file_operations sheep_net_fops = { ++ .owner = THIS_MODULE, ++ .read = do_sync_read, ++ .aio_read = sheep_net_aio_read, ++ .write = do_sync_write, ++ .aio_write = sheep_net_aio_write, ++ .poll = sheep_net_poll, ++ .ioctl = sheep_net_ioctl, ++ .open = sheep_net_open, ++ .release = sheep_net_release, ++}; ++#else ++static struct file_operations sheep_net_fops = { ++ .owner = THIS_MODULE, ++ .read = sheep_net_read, ++ .write = sheep_net_write, ++ .readv = sheep_net_readv, ++ .writev = sheep_net_writev, ++ .poll = sheep_net_poll, ++ .ioctl = sheep_net_ioctl, ++ .open = sheep_net_open, ++ .release = sheep_net_release, ++}; ++#endif ++ ++static struct miscdevice sheep_net_device = { ++ .minor = SHEEP_NET_MINOR, ++ .name = "sheep_net", ++ .fops = &sheep_net_fops ++}; ++ ++int ++init_module( void ) ++{ ++ return misc_register( &sheep_net_device ); ++} ++ ++void ++cleanup_module( void ) ++{ ++ (void) misc_deregister( &sheep_net_device ); ++} +--- /dev/null ++++ b/drivers/macintosh/mol/skiplist.c +@@ -0,0 +1,222 @@ ++/* ++ * Creation Date: <2003/03/03 23:19:47 samuel> ++ * Time-stamp: <2004/02/21 16:24:56 samuel> ++ * ++ * ++ * ++ * Skiplist implementation ++ * ++ * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) ++ * ++ * 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 ++ * ++ */ ++ ++#include "archinclude.h" ++#include "skiplist.h" ++#include "alloc.h" ++ ++#define SKIPLIST_END INT_MAX /* this key is reserved */ ++ ++/* ++ * Skiplist Example: ++ * ++ * level 0 -> el1 -> el2 -> el3 --> el4 --> null_el ++ * level 1 --> el2 -> el3 --> el4 --> null_el ++ * level 2 --> el2 --> el4 --> null_el ++ * level 3 --> el2 -----> null_el ++ * level 4 ------------> null_el ++ * ... ++ * SKIPLIST_MAX_HEIGHT-1 ------------> null_el ++ */ ++ ++static unsigned int mol_rand_seed = 152; ++ ++static inline int ++_cntlz( int val ) ++{ ++ int ret; ++ asm volatile("cntlzw %0,%1" : "=r" (ret) : "r"(val) ); ++ return ret; ++} ++ ++static unsigned long ++mol_random( void ) ++{ ++ unsigned int t; ++ asm( "mftb %0" : "=r"(t) : ); ++ mol_rand_seed = mol_rand_seed*69069L+1; ++ return mol_rand_seed^t; ++} ++ ++static void ++mol_random_entropy( void ) ++{ ++ unsigned int entropy; ++ asm( "mftb %0" : "=r" (entropy) : ); ++ mol_rand_seed ^= entropy; ++} ++ ++static inline void ++set_level_next( skiplist_level_t *level, skiplist_el_t *el ) ++{ ++ level->next = el; ++#ifdef __darwin__ ++ level->next_phys = el ? tophys_mol(el) : 0; ++#endif ++} ++ ++ ++/************************************************************************/ ++/* skiplist operations */ ++/************************************************************************/ ++ ++int ++skiplist_prealloc( skiplist_t *sl, char *buf, unsigned int size, ++ skiplist_el_callback callback, void *usr1, void *usr2 ) ++{ ++ skiplist_el_t *p, *head; ++ unsigned int s; ++ int n, count; ++ ++ head = NULL; ++ for( count=0 ;; size -= s, buf += s, count++ ) { ++ for( n=0; ndatasize + sizeof(skiplist_t) + n*sizeof(skiplist_level_t); ++ if( s > size ) ++ break; ++ p = (skiplist_el_t*)(buf + sl->datasize); ++ p->key = n; ++ set_level_next( &p->level[0], head ); ++ head = p; ++ } ++ ++ /* note: the callback is allowed to manipulate the skiplist */ ++ for( n=0, p=head; p; p=p->level[0].next, n++ ) { ++ if( callback ) ++ (*callback)( (char*)p - sl->datasize, n, count, usr1, usr2 ); ++ if( !p->level[0].next ) { ++ p->level[0] = sl->freelist; ++ set_level_next( &sl->freelist, head ); ++ break; ++ } ++ } ++ return count; ++} ++ ++char * ++skiplist_insert( skiplist_t *sl, int key ) ++{ ++ skiplist_el_t *pleft = (skiplist_el_t*)((char*)&sl->root[0] - offsetof(skiplist_el_t, level)); ++ skiplist_level_t el = sl->freelist; ++ skiplist_el_t *p = el.next; ++ int n, slev; ++ ++ if( !p ) ++ return NULL; ++ sl->freelist = p->level[0]; ++ n = p->key; ++ p->key = key; ++ ++ /* pick a good search level (the -3 is benchmarked) */ ++ sl->nel++; ++ slev = 31 - _cntlz(sl->nel) - 3; ++ if( slev > SKIPLIST_MAX_HEIGHT-1 ) ++ slev = SKIPLIST_MAX_HEIGHT-1; ++ else if( slev < 0 ) ++ slev = 0; ++ sl->slevel = slev; ++ ++ /* insert element */ ++ if( slev < n ) ++ slev = n; ++ for( ; slev >= 0; slev-- ) { ++ for( ; pleft->level[slev].next->key < key ; pleft=pleft->level[slev].next ) ++ ; ++ if( slev <= n ) { ++ p->level[slev] = pleft->level[slev]; ++ pleft->level[slev] = el; ++ } ++ } ++ ++ return (char*)p - sl->datasize; ++} ++ ++char * ++skiplist_delete( skiplist_t *sl, int key ) ++{ ++ skiplist_el_t *p = (skiplist_el_t*)((char*)&sl->root[0] - offsetof(skiplist_el_t, level)); ++ skiplist_level_t delptr; ++ int n, level = -1; ++ ++ delptr.next = 0; ++ ++ for( n=SKIPLIST_MAX_HEIGHT-1; n>=0; n-- ) { ++ for( ; p->level[n].next->key < key ; p=p->level[n].next ) ++ ; ++ if( p->level[n].next->key != key ) ++ continue; ++ ++ if( level < 0 ) { ++ delptr = p->level[n]; ++ level = n; ++ } ++ p->level[n] = delptr.next->level[n]; ++ } ++ if( level < 0 ) ++ return NULL; ++ ++ /* put on freelist */ ++ p = delptr.next; ++ p->key = level; ++ p->level[0] = sl->freelist; ++ sl->freelist = delptr; ++ sl->nel--; ++ ++ return (char*)p - sl->datasize; ++} ++ ++char * ++skiplist_lookup( skiplist_t *sl, int key ) ++{ ++ skiplist_el_t *p = (skiplist_el_t*)((char*)&sl->root[0] - offsetof(skiplist_el_t, level)); ++ int n = sl->slevel; ++ ++ for( ;; ) { ++ if( p->level[n].next->key < key ) { ++ p = p->level[n].next; ++ continue; ++ } ++ if( p->level[n].next->key > key ) { ++ if( --n < 0 ) ++ break; ++ continue; ++ } ++ return (char*)p->level[n].next - sl->datasize; ++ } ++ return NULL; ++} ++ ++void ++skiplist_init( skiplist_t *sl, int datasize ) ++{ ++ skiplist_level_t nilptr; ++ int i; ++ ++ mol_random_entropy(); ++ ++ memset( sl, 0, sizeof(*sl) ); ++ ++ sl->nil_el.key = SKIPLIST_END; ++ sl->datasize = datasize; ++ ++ /* remember: the nil element is of level 0 */ ++ set_level_next( &nilptr, &sl->nil_el ); ++ sl->nil_el.level[0] = nilptr; ++ ++ for( i=0; i < SKIPLIST_MAX_HEIGHT ; i++ ) ++ sl->root[i] = nilptr; ++} diff --git a/src/patches/suse-2.6.27.31/patches.suse/suse-ppc64-branding b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc64-branding new file mode 100644 index 000000000..3855edef1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/suse-ppc64-branding @@ -0,0 +1,25 @@ +From: +Subject: display the product in the frontpanel LCD +Patch-mainline: never + +display the product in the frontpanel LCD +also the uname -r output instead of uname -v. + + arch/powerpc/platforms/pseries/setup.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/arch/powerpc/platforms/pseries/setup.c ++++ b/arch/powerpc/platforms/pseries/setup.c +@@ -299,7 +299,11 @@ static void __init pSeries_setup_arch(vo + static int __init pSeries_init_panel(void) + { + /* Manually leave the kernel version on the panel. */ +- ppc_md.progress("Linux ppc64\n", 0); ++#ifdef CONFIG_CRASH_DUMP ++ ppc_md.progress("SuSE Linux crashed :-(\n", 0); ++#else ++ ppc_md.progress("SuSE Linux\n", 0); ++#endif + ppc_md.progress(init_utsname()->version, 0); + + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.suse/sysctl-add-affinity_load_balancing b/src/patches/suse-2.6.27.31/patches.suse/sysctl-add-affinity_load_balancing new file mode 100644 index 000000000..c7f821281 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/sysctl-add-affinity_load_balancing @@ -0,0 +1,102 @@ +Subject: add affinity_load_balancing sysctl +From: kraxel@suse.de +References: 176738 + +Add a sysctl to tweak how the kernel initially schedules threads to cpus. + +By default the kernel tries to keep threads on the local cpu (and local +node on NUMA machines). Depending on the application this may not deliver +the best performance, especially applications with a large working set for +each thread tend to perform better when being scheduled to different nodes +because they can use caches of multiple nodes then. + +With this sysctl enabled the kernel will spread threads over the cpus given +and doesn't try to keep them local. + +usage: + - set sysctl kernel.affinity_load_balancing = 1 + - use taskset or numactl to specify which cpus your task should be + scheduled on. + +--- + kernel/sched.c | 28 ++++++++++++++++++++++++++++ + kernel/sysctl.c | 12 ++++++++++++ + 2 files changed, 40 insertions(+) + +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -2107,6 +2107,28 @@ find_idlest_cpu(struct sched_group *grou + return idlest; + } + ++static int ++find_idlest_cpu_nodomain(struct task_struct *p, int this_cpu) ++{ ++ cpumask_t tmp; ++ unsigned long load, min_load = ULONG_MAX; ++ int idlest = -1; ++ int i; ++ ++ /* Traverse only the allowed CPUs */ ++ cpus_and(tmp, cpu_online_map, p->cpus_allowed); ++ ++ for_each_cpu_mask(i, tmp) { ++ load = target_load(i, 1); ++ ++ if (load < min_load) { ++ min_load = load; ++ idlest = i; ++ } ++ } ++ return idlest; ++} ++ + /* + * sched_balance_self: balance the current task (running on cpu) in domains + * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and +@@ -2118,11 +2140,17 @@ find_idlest_cpu(struct sched_group *grou + * + * preempt must be disabled. + */ ++ ++int affinity_load_balancing = 0; ++ + static int sched_balance_self(int cpu, int flag) + { + struct task_struct *t = current; + struct sched_domain *tmp, *sd = NULL; + ++ if (affinity_load_balancing && !cpus_full(t->cpus_allowed)) ++ return find_idlest_cpu_nodomain(t, cpu); ++ + for_each_domain(cpu, tmp) { + /* + * If power savings logic is enabled for a domain, stop there. +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -237,6 +237,8 @@ static int min_wakeup_granularity_ns; + static int max_wakeup_granularity_ns = NSEC_PER_SEC; /* 1 second */ + #endif + ++extern int affinity_load_balancing; ++ + static struct ctl_table kern_table[] = { + #ifdef CONFIG_SCHED_DEBUG + { +@@ -872,6 +874,16 @@ static struct ctl_table kern_table[] = { + * NOTE: do not add new entries to this table unless you have read + * Documentation/sysctl/ctl_unnumbered.txt + */ ++#ifdef CONFIG_SMP ++ { ++ .ctl_name = CTL_UNNUMBERED, ++ .procname = "affinity_load_balancing", ++ .data = &affinity_load_balancing, ++ .maxlen = sizeof(affinity_load_balancing), ++ .mode = 0644, ++ .proc_handler = &proc_dointvec, ++ }, ++#endif + { .ctl_name = 0 } + }; + diff --git a/src/patches/suse-2.6.27.31/patches.suse/twofish-2.6 b/src/patches/suse-2.6.27.31/patches.suse/twofish-2.6 new file mode 100644 index 000000000..98a6e84a6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/twofish-2.6 @@ -0,0 +1,661 @@ +Subject: Twofish encryption for loop device for old S.u.S.E. crypto partitions +From: kraxel@suse.de + +See $subject, used up to 9.2 on new installs. + +--- + drivers/block/Kconfig | 6 + drivers/block/Makefile | 1 + drivers/block/loop_fish2.c | 625 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 632 insertions(+) + +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -409,6 +409,12 @@ config SUNVDC + Support for virtual disk devices as a client under Sun + Logical Domains. + ++config CIPHER_TWOFISH ++ tristate "Twofish encryption for loop device for old S.u.S.E. crypto partitions" ++ depends on BLK_DEV_LOOP ++ help ++ Say Y here if you want to support old S.u.S.E. crypto partitions. ++ + source "drivers/s390/block/Kconfig" + + config XILINX_SYSACE +--- a/drivers/block/Makefile ++++ b/drivers/block/Makefile +@@ -32,3 +32,4 @@ obj-$(CONFIG_BLK_DEV_UB) += ub.o + obj-$(CONFIG_BLK_DEV_HD) += hd.o + + obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o ++obj-$(CONFIG_CIPHER_TWOFISH) += loop_fish2.o +--- /dev/null ++++ b/drivers/block/loop_fish2.c +@@ -0,0 +1,625 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ROL(x,c) (((x) << (c)) | ((x) >> (32-(c)))) ++#define ROR(x,c) (((x) >> (c)) | ((x) << (32-(c)))) ++#define Bswap(x) __le32_to_cpu(x) ++ ++#define DWORD __u32 ++#define BYTE unsigned char ++ ++typedef struct fish2_key ++{ int keyLen; /* Key Length in Bit */ ++ DWORD sboxKeys[4]; ++ DWORD subKeys[40]; ++ BYTE key[32]; ++ DWORD sbox_full[1024]; /* This have to be 1024 DWORDs */ ++} fish2_key; ++ ++ ++/* Mul_5B[i] is 0x5B * i in GF(256), whatever that means... */ ++ ++static unsigned char Mul_5B[256] = { ++ 0x00,0x5B,0xB6,0xED,0x05,0x5E,0xB3,0xE8, ++ 0x0A,0x51,0xBC,0xE7,0x0F,0x54,0xB9,0xE2, ++ 0x14,0x4F,0xA2,0xF9,0x11,0x4A,0xA7,0xFC, ++ 0x1E,0x45,0xA8,0xF3,0x1B,0x40,0xAD,0xF6, ++ 0x28,0x73,0x9E,0xC5,0x2D,0x76,0x9B,0xC0, ++ 0x22,0x79,0x94,0xCF,0x27,0x7C,0x91,0xCA, ++ 0x3C,0x67,0x8A,0xD1,0x39,0x62,0x8F,0xD4, ++ 0x36,0x6D,0x80,0xDB,0x33,0x68,0x85,0xDE, ++ 0x50,0x0B,0xE6,0xBD,0x55,0x0E,0xE3,0xB8, ++ 0x5A,0x01,0xEC,0xB7,0x5F,0x04,0xE9,0xB2, ++ 0x44,0x1F,0xF2,0xA9,0x41,0x1A,0xF7,0xAC, ++ 0x4E,0x15,0xF8,0xA3,0x4B,0x10,0xFD,0xA6, ++ 0x78,0x23,0xCE,0x95,0x7D,0x26,0xCB,0x90, ++ 0x72,0x29,0xC4,0x9F,0x77,0x2C,0xC1,0x9A, ++ 0x6C,0x37,0xDA,0x81,0x69,0x32,0xDF,0x84, ++ 0x66,0x3D,0xD0,0x8B,0x63,0x38,0xD5,0x8E, ++ 0xA0,0xFB,0x16,0x4D,0xA5,0xFE,0x13,0x48, ++ 0xAA,0xF1,0x1C,0x47,0xAF,0xF4,0x19,0x42, ++ 0xB4,0xEF,0x02,0x59,0xB1,0xEA,0x07,0x5C, ++ 0xBE,0xE5,0x08,0x53,0xBB,0xE0,0x0D,0x56, ++ 0x88,0xD3,0x3E,0x65,0x8D,0xD6,0x3B,0x60, ++ 0x82,0xD9,0x34,0x6F,0x87,0xDC,0x31,0x6A, ++ 0x9C,0xC7,0x2A,0x71,0x99,0xC2,0x2F,0x74, ++ 0x96,0xCD,0x20,0x7B,0x93,0xC8,0x25,0x7E, ++ 0xF0,0xAB,0x46,0x1D,0xF5,0xAE,0x43,0x18, ++ 0xFA,0xA1,0x4C,0x17,0xFF,0xA4,0x49,0x12, ++ 0xE4,0xBF,0x52,0x09,0xE1,0xBA,0x57,0x0C, ++ 0xEE,0xB5,0x58,0x03,0xEB,0xB0,0x5D,0x06, ++ 0xD8,0x83,0x6E,0x35,0xDD,0x86,0x6B,0x30, ++ 0xD2,0x89,0x64,0x3F,0xD7,0x8C,0x61,0x3A, ++ 0xCC,0x97,0x7A,0x21,0xC9,0x92,0x7F,0x24, ++ 0xC6,0x9D,0x70,0x2B,0xC3,0x98,0x75,0x2E }; ++ ++ ++/* Mul_EF[i] is 0xEF * i in GF(256), whatever that means... */ ++ ++static unsigned char Mul_EF[256] = { ++ 0x00,0xEF,0xB7,0x58,0x07,0xE8,0xB0,0x5F, ++ 0x0E,0xE1,0xB9,0x56,0x09,0xE6,0xBE,0x51, ++ 0x1C,0xF3,0xAB,0x44,0x1B,0xF4,0xAC,0x43, ++ 0x12,0xFD,0xA5,0x4A,0x15,0xFA,0xA2,0x4D, ++ 0x38,0xD7,0x8F,0x60,0x3F,0xD0,0x88,0x67, ++ 0x36,0xD9,0x81,0x6E,0x31,0xDE,0x86,0x69, ++ 0x24,0xCB,0x93,0x7C,0x23,0xCC,0x94,0x7B, ++ 0x2A,0xC5,0x9D,0x72,0x2D,0xC2,0x9A,0x75, ++ 0x70,0x9F,0xC7,0x28,0x77,0x98,0xC0,0x2F, ++ 0x7E,0x91,0xC9,0x26,0x79,0x96,0xCE,0x21, ++ 0x6C,0x83,0xDB,0x34,0x6B,0x84,0xDC,0x33, ++ 0x62,0x8D,0xD5,0x3A,0x65,0x8A,0xD2,0x3D, ++ 0x48,0xA7,0xFF,0x10,0x4F,0xA0,0xF8,0x17, ++ 0x46,0xA9,0xF1,0x1E,0x41,0xAE,0xF6,0x19, ++ 0x54,0xBB,0xE3,0x0C,0x53,0xBC,0xE4,0x0B, ++ 0x5A,0xB5,0xED,0x02,0x5D,0xB2,0xEA,0x05, ++ 0xE0,0x0F,0x57,0xB8,0xE7,0x08,0x50,0xBF, ++ 0xEE,0x01,0x59,0xB6,0xE9,0x06,0x5E,0xB1, ++ 0xFC,0x13,0x4B,0xA4,0xFB,0x14,0x4C,0xA3, ++ 0xF2,0x1D,0x45,0xAA,0xF5,0x1A,0x42,0xAD, ++ 0xD8,0x37,0x6F,0x80,0xDF,0x30,0x68,0x87, ++ 0xD6,0x39,0x61,0x8E,0xD1,0x3E,0x66,0x89, ++ 0xC4,0x2B,0x73,0x9C,0xC3,0x2C,0x74,0x9B, ++ 0xCA,0x25,0x7D,0x92,0xCD,0x22,0x7A,0x95, ++ 0x90,0x7F,0x27,0xC8,0x97,0x78,0x20,0xCF, ++ 0x9E,0x71,0x29,0xC6,0x99,0x76,0x2E,0xC1, ++ 0x8C,0x63,0x3B,0xD4,0x8B,0x64,0x3C,0xD3, ++ 0x82,0x6D,0x35,0xDA,0x85,0x6A,0x32,0xDD, ++ 0xA8,0x47,0x1F,0xF0,0xAF,0x40,0x18,0xF7, ++ 0xA6,0x49,0x11,0xFE,0xA1,0x4E,0x16,0xF9, ++ 0xB4,0x5B,0x03,0xEC,0xB3,0x5C,0x04,0xEB, ++ 0xBA,0x55,0x0D,0xE2,0xBD,0x52,0x0A,0xE5 }; ++ ++static inline DWORD mds_mul(BYTE *y) ++{ DWORD z; ++ ++ z=Mul_EF[y[0]] ^ y[1] ^ Mul_EF[y[2]] ^ Mul_5B[y[3]]; ++ z<<=8; ++ z|=Mul_EF[y[0]] ^ Mul_5B[y[1]] ^ y[2] ^ Mul_EF[y[3]]; ++ z<<=8; ++ z|=Mul_5B[y[0]] ^ Mul_EF[y[1]] ^ Mul_EF[y[2]] ^ y[3]; ++ z<<=8; ++ z|=y[0] ^ Mul_EF[y[1]] ^ Mul_5B[y[2]] ^ Mul_5B[y[3]]; ++ ++ return z; ++} ++ ++/* q0 and q1 are the lookup substitutions done in twofish */ ++ ++static unsigned char q0[256] = ++{ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, ++ 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, ++ 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, ++ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, ++ 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, ++ 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, ++ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, ++ 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, ++ 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, ++ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, ++ 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, ++ 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, ++ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, ++ 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, ++ 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, ++ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, ++ 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, ++ 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, ++ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, ++ 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, ++ 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, ++ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, ++ 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, ++ 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, ++ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, ++ 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, ++ 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, ++ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, ++ 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, ++ 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, ++ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, ++ 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0}; ++ ++static unsigned char q1[256] = ++{ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, ++ 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, ++ 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, ++ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, ++ 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, ++ 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, ++ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, ++ 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, ++ 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, ++ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, ++ 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, ++ 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, ++ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, ++ 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, ++ 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, ++ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, ++ 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, ++ 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, ++ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, ++ 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, ++ 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, ++ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, ++ 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, ++ 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, ++ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, ++ 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, ++ 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, ++ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, ++ 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, ++ 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, ++ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, ++ 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 ++ }; ++ ++ ++static DWORD f32(DWORD x, const DWORD * k32, int keyLen) ++{ ++ BYTE b[4]; ++ ++ /* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */ ++ /* Note that each byte goes through a different combination of S-boxes. */ ++ ++ *((DWORD *) b) = Bswap(x); /* make b[0] = LSB, b[3] = MSB */ ++ ++ switch (((keyLen + 63) / 64) & 3) ++ { ++ case 0: /* 256 bits of key */ ++ b[0] = q1[b[0]]; ++ b[1] = q0[b[1]]; ++ b[2] = q0[b[2]]; ++ b[3] = q1[b[3]]; ++ ++ *((DWORD *) b) ^= k32[3]; ++ ++ /* fall thru, having pre-processed b[0]..b[3] with k32[3] */ ++ case 3: /* 192 bits of key */ ++ b[0] = q1[b[0]]; ++ b[1] = q1[b[1]]; ++ b[2] = q0[b[2]]; ++ b[3] = q0[b[3]]; ++ ++ *((DWORD *) b) ^= k32[2]; ++ ++ /* fall thru, having pre-processed b[0]..b[3] with k32[2] */ ++ case 2: /* 128 bits of key */ ++ b[0] = q0[b[0]]; ++ b[1] = q1[b[1]]; ++ b[2] = q0[b[2]]; ++ b[3] = q1[b[3]]; ++ ++ *((DWORD *) b) ^= k32[1]; ++ ++ b[0] = q0[b[0]]; ++ b[1] = q0[b[1]]; ++ b[2] = q1[b[2]]; ++ b[3] = q1[b[3]]; ++ ++ *((DWORD *) b) ^= k32[0]; ++ ++ b[0] = q1[b[0]]; ++ b[1] = q0[b[1]]; ++ b[2] = q1[b[2]]; ++ b[3] = q0[b[3]]; ++ } ++ ++ ++ /* Now perform the MDS matrix multiply inline. */ ++ return mds_mul(b); ++} ++ ++ ++static void init_sbox(fish2_key *key) ++{ DWORD x,*sbox,z,*k32; ++ int i,keyLen; ++ BYTE b[4]; ++ ++ k32=key->sboxKeys; ++ keyLen=key->keyLen; ++ sbox=key->sbox_full; ++ ++ x=0; ++ for (i=0;i<256;i++,x+=0x01010101) ++ { ++ *((DWORD *) b) = Bswap(x); /* make b[0] = LSB, b[3] = MSB */ ++ ++ switch (((keyLen + 63) / 64) & 3) ++ { ++ case 0: /* 256 bits of key */ ++ b[0] = q1[b[0]]; ++ b[1] = q0[b[1]]; ++ b[2] = q0[b[2]]; ++ b[3] = q1[b[3]]; ++ ++ *((DWORD *) b) ^= k32[3]; ++ ++ /* fall thru, having pre-processed b[0]..b[3] with k32[3] */ ++ case 3: /* 192 bits of key */ ++ b[0] = q1[b[0]]; ++ b[1] = q1[b[1]]; ++ b[2] = q0[b[2]]; ++ b[3] = q0[b[3]]; ++ ++ *((DWORD *) b) ^= k32[2]; ++ ++ /* fall thru, having pre-processed b[0]..b[3] with k32[2] */ ++ case 2: /* 128 bits of key */ ++ b[0] = q0[b[0]]; ++ b[1] = q1[b[1]]; ++ b[2] = q0[b[2]]; ++ b[3] = q1[b[3]]; ++ ++ *((DWORD *) b) ^= k32[1]; ++ ++ b[0] = q0[b[0]]; ++ b[1] = q0[b[1]]; ++ b[2] = q1[b[2]]; ++ b[3] = q1[b[3]]; ++ ++ *((DWORD *) b) ^= k32[0]; ++ ++ b[0] = q1[b[0]]; ++ b[1] = q0[b[1]]; ++ b[2] = q1[b[2]]; ++ b[3] = q0[b[3]]; ++ } ++ ++ z=Mul_EF[b[0]]; ++ z<<=8; ++ z|=Mul_EF[b[0]]; ++ z<<=8; ++ z|=Mul_5B[b[0]]; ++ z<<=8; ++ z|=b[0]; ++ ++ sbox[i]=z; ++ ++ z=b[1]; ++ z<<=8; ++ z|=Mul_5B[b[1]]; ++ z<<=8; ++ z|=Mul_EF[b[1]]; ++ z<<=8; ++ z|=Mul_EF[b[1]]; ++ ++ sbox[i+256]=z; ++ ++ z=Mul_EF[b[2]]; ++ z<<=8; ++ z|=b[2]; ++ z<<=8; ++ z|=Mul_EF[b[2]]; ++ z<<=8; ++ z|=Mul_5B[b[2]]; ++ ++ sbox[i+512]=z; ++ ++ z=Mul_5B[b[3]]; ++ z<<=8; ++ z|=Mul_EF[b[3]]; ++ z<<=8; ++ z|=b[3]; ++ z<<=8; ++ z|=Mul_5B[b[3]]; ++ ++ sbox[i+768]=z; ++ } ++} ++ ++ ++/* Reed-Solomon code parameters: (12,8) reversible code ++ g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1 ++ where a = primitive root of field generator 0x14D */ ++#define RS_GF_FDBK 0x14D /* field generator */ ++#define RS_rem(x) \ ++ { BYTE b = x >> 24; \ ++ DWORD g2 = ((b << 1) ^ ((b & 0x80) ? RS_GF_FDBK : 0 )) & 0xFF; \ ++ DWORD g3 = ((b >> 1) & 0x7F) ^ ((b & 1) ? RS_GF_FDBK >> 1 : 0 ) ^ g2 ; \ ++ x = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; \ ++ } ++ ++static DWORD rs_mds(DWORD k0, DWORD k1) ++{ ++ int i, j; ++ DWORD r; ++ ++ for (i = r = 0; i < 2; i++) ++ { ++ r ^= (i) ? k0 : k1; /* merge in 32 more key bits */ ++ for (j = 0; j < 4; j++) /* shift one byte at a time */ ++ RS_rem(r); ++ } ++ return r; ++} ++ ++ ++#define INPUT_WHITEN 0 /* subkey array indices */ ++#define OUTPUT_WHITEN 4 ++#define ROUND_SUBKEYS 8 /* use 2 * (# rounds) */ ++#define TOTAL_SUBKEYS 40 ++ ++static void init_key(fish2_key * key) ++{ ++ int i, k64Cnt; ++ int keyLen = key->keyLen; ++ int subkeyCnt = TOTAL_SUBKEYS; ++ DWORD A, B; ++ DWORD k32e[4], k32o[4]; /* even/odd key dwords */ ++ ++ k64Cnt = (keyLen + 63) / 64; /* round up to next multiple of 64 bits */ ++ for (i = 0; i < k64Cnt; i++) ++ { /* split into even/odd key dwords */ ++ k32e[i] = ((DWORD *)key->key)[2 * i]; ++ k32o[i] = ((DWORD *)key->key)[2 * i + 1]; ++ /* compute S-box keys using (12,8) Reed-Solomon code over GF(256) */ ++ /* store in reverse order */ ++ key->sboxKeys[k64Cnt - 1 - i] = ++ Bswap(rs_mds(Bswap(k32e[i]), Bswap(k32o[i]))); ++ ++ } ++ ++ for (i = 0; i < subkeyCnt / 2; i++) /* compute round subkeys for PHT */ ++ { ++ A = f32(i * 0x02020202, k32e, keyLen); /* A uses even key dwords */ ++ B = f32(i * 0x02020202 + 0x01010101, k32o, keyLen); /* B uses odd key ++ dwords */ ++ B = ROL(B, 8); ++ key->subKeys[2 * i] = A + B; /* combine with a PHT */ ++ key->subKeys[2 * i + 1] = ROL(A + 2 * B, 9); ++ } ++ ++ init_sbox(key); ++} ++ ++ ++static inline DWORD f32_sbox(DWORD x,DWORD *sbox) ++{ ++ /* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */ ++ /* Note that each byte goes through a different combination of S-boxes. */ ++ ++ return (sbox[ (x) &0xff]^ ++ sbox[256 + (((x)>> 8)&0xff)]^ ++ sbox[512 + (((x)>>16)&0xff)]^ ++ sbox[768 + (((x)>>24)&0xff)]); ++} ++ ++#define roundE_m(x0,x1,x2,x3,rnd) \ ++ t0 = f32_sbox( x0, key->sbox_full ) ; \ ++ t1 = f32_sbox( ROL(x1,8), key->sbox_full ); \ ++ x2 ^= t0 + t1 + key->subKeys[2*rnd+8]; \ ++ x3 = ROL(x3,1); \ ++ x3 ^= t0 + 2*t1 + key->subKeys[2*rnd+9]; \ ++ x2 = ROR(x2,1); ++ ++ ++static int blockEncrypt_CBC(fish2_key *key,BYTE *src,BYTE *dst,int len) ++{ DWORD xx0,xx1,xx2,xx3,t0,t1,iv0,iv1,iv2,iv3; ++ ++ if (len & 0xF) return -1; ++ ++ iv0=0; ++ iv1=0; ++ iv2=0; ++ iv3=0; ++ for (;len>=16;len-=16) ++ ++ { ++ if ( ( len & 0x1FF) == 0) ++ { iv0=0; ++ iv1=0; ++ iv2=0; ++ iv3=0; ++ } ++ ++ xx0=Bswap(((DWORD *)src)[0]) ^ key->subKeys[0] ^ iv0; ++ xx1=Bswap(((DWORD *)src)[1]) ^ key->subKeys[1] ^ iv1; ++ xx2=Bswap(((DWORD *)src)[2]) ^ key->subKeys[2] ^ iv2; ++ xx3=Bswap(((DWORD *)src)[3]) ^ key->subKeys[3] ^ iv3; ++ ++ src+=16; ++ ++ roundE_m(xx0,xx1,xx2,xx3,0); ++ roundE_m(xx2,xx3,xx0,xx1,1); ++ roundE_m(xx0,xx1,xx2,xx3,2); ++ roundE_m(xx2,xx3,xx0,xx1,3); ++ roundE_m(xx0,xx1,xx2,xx3,4); ++ roundE_m(xx2,xx3,xx0,xx1,5); ++ roundE_m(xx0,xx1,xx2,xx3,6); ++ roundE_m(xx2,xx3,xx0,xx1,7); ++ roundE_m(xx0,xx1,xx2,xx3,8); ++ roundE_m(xx2,xx3,xx0,xx1,9); ++ roundE_m(xx0,xx1,xx2,xx3,10); ++ roundE_m(xx2,xx3,xx0,xx1,11); ++ roundE_m(xx0,xx1,xx2,xx3,12); ++ roundE_m(xx2,xx3,xx0,xx1,13); ++ roundE_m(xx0,xx1,xx2,xx3,14); ++ roundE_m(xx2,xx3,xx0,xx1,15); ++ ++ iv0=xx2 ^ key->subKeys[4]; ++ iv1=xx3 ^ key->subKeys[5]; ++ iv2=xx0 ^ key->subKeys[6]; ++ iv3=xx1 ^ key->subKeys[7]; ++ ++ ((DWORD *)dst)[0] = Bswap(iv0); ++ ((DWORD *)dst)[1] = Bswap(iv1); ++ ((DWORD *)dst)[2] = Bswap(iv2); ++ ((DWORD *)dst)[3] = Bswap(iv3); ++ dst+=16; ++ } ++ return len; ++} ++ ++#define roundD_m(x0,x1,x2,x3,rnd) \ ++ t0 = f32_sbox( x0, key->sbox_full); \ ++ t1 = f32_sbox( ROL(x1,8),key->sbox_full); \ ++ x2 = ROL(x2,1); \ ++ x3 ^= t0 + 2*t1 + key->subKeys[rnd*2+9]; \ ++ x3 = ROR(x3,1); \ ++ x2 ^= t0 + t1 + key->subKeys[rnd*2+8]; ++ ++ ++static int blockDecrypt_CBC(fish2_key *key,BYTE *src,BYTE *dst,int len) ++{ DWORD xx0,xx1,xx2,xx3,t0,t1,lx0,lx1,lx2,lx3,iv0,iv1,iv2,iv3; ++ ++ if (len & 0xF) return -1; ++ ++ iv0=0; ++ iv1=0; ++ iv2=0; ++ iv3=0; ++ ++ for (;len>=16;len-=16) ++ { ++ if ( ( len & 0x1FF) == 0) ++ { iv0=0; ++ iv1=0; ++ iv2=0; ++ iv3=0; ++ } ++ ++ lx0=iv0;iv0=Bswap(((DWORD *)src)[0]);xx0=iv0 ^ key->subKeys[4]; ++ lx1=iv1;iv1=Bswap(((DWORD *)src)[1]);xx1=iv1 ^ key->subKeys[5]; ++ lx2=iv2;iv2=Bswap(((DWORD *)src)[2]);xx2=iv2 ^ key->subKeys[6]; ++ lx3=iv3;iv3=Bswap(((DWORD *)src)[3]);xx3=iv3 ^ key->subKeys[7]; ++ src+=16; ++ ++ roundD_m(xx0,xx1,xx2,xx3,15); ++ roundD_m(xx2,xx3,xx0,xx1,14); ++ roundD_m(xx0,xx1,xx2,xx3,13); ++ roundD_m(xx2,xx3,xx0,xx1,12); ++ roundD_m(xx0,xx1,xx2,xx3,11); ++ roundD_m(xx2,xx3,xx0,xx1,10); ++ roundD_m(xx0,xx1,xx2,xx3,9); ++ roundD_m(xx2,xx3,xx0,xx1,8); ++ roundD_m(xx0,xx1,xx2,xx3,7); ++ roundD_m(xx2,xx3,xx0,xx1,6); ++ roundD_m(xx0,xx1,xx2,xx3,5); ++ roundD_m(xx2,xx3,xx0,xx1,4); ++ roundD_m(xx0,xx1,xx2,xx3,3); ++ roundD_m(xx2,xx3,xx0,xx1,2); ++ roundD_m(xx0,xx1,xx2,xx3,1); ++ roundD_m(xx2,xx3,xx0,xx1,0); ++ ++ ((DWORD *)dst)[0] = Bswap(xx2 ^ key->subKeys[0] ^ lx0); ++ ((DWORD *)dst)[1] = Bswap(xx3 ^ key->subKeys[1] ^ lx1); ++ ((DWORD *)dst)[2] = Bswap(xx0 ^ key->subKeys[2] ^ lx2); ++ ((DWORD *)dst)[3] = Bswap(xx1 ^ key->subKeys[3] ^ lx3); ++ dst+=16; ++ } ++ return len; ++} ++ ++ ++int transfer_fish2(struct loop_device *lo, int cmd, ++ struct page *raw_page, unsigned raw_off, ++ struct page *loop_page, unsigned loop_off, ++ int size, sector_t IV) ++{ ++ char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; ++ char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; ++ ++ if (cmd == READ) ++ blockDecrypt_CBC((fish2_key *)lo->key_data,raw_buf,loop_buf,size); ++ else ++ blockEncrypt_CBC((fish2_key *)lo->key_data,loop_buf,raw_buf,size); ++ ++ kunmap_atomic(raw_buf, KM_USER0); ++ kunmap_atomic(loop_buf, KM_USER1); ++ cond_resched(); ++ ++ return 0; ++} ++ ++int fish2_init(struct loop_device *lo,const struct loop_info64 *info) ++{ fish2_key *key; ++ ++ if (info->lo_encrypt_key_size<16 || info->lo_encrypt_key_size>32) ++ return -EINVAL; ++ ++ key=(fish2_key *)kmalloc(sizeof(fish2_key),GFP_KERNEL); ++ ++ if (key==NULL) ++ return -ENOMEM; ++ ++ lo->key_data=key; ++ ++ memset(key->key,0,32); ++ ++ key->keyLen=info->lo_encrypt_key_size << 3; ++ memcpy(key->key,info->lo_encrypt_key,info->lo_encrypt_key_size); ++ ++ init_key(key); ++ ++ return 0; ++} ++ ++static int fish2_release(struct loop_device *lo) ++{ if (lo->key_data!=NULL) ++ { ++ kfree(lo->key_data); ++ lo->key_data=NULL; ++ } ++ return(0); ++} ++ ++static struct loop_func_table fish2_funcs = ++{ .number = LO_CRYPT_FISH2, ++ .transfer = transfer_fish2, ++ .init = fish2_init, ++ .release = fish2_release, ++ .owner = THIS_MODULE ++}; ++ ++int __init loop_fish2_init(void) ++{ ++ int err; ++ ++ if ((err=loop_register_transfer(&fish2_funcs))) ++ { ++ printk(KERN_WARNING "Couldn't register Twofish encryption\n"); ++ return err; ++ } ++ printk(KERN_INFO "loop: registered Twofish encryption \n"); ++ return 0; ++} ++ ++void __exit loop_fish2_exit(void) ++{ ++ if (loop_unregister_transfer(LO_CRYPT_FISH2)) ++ printk(KERN_WARNING "Couldn't unregister Twofish encryption\n"); ++ printk(KERN_INFO "loop: unregistered Twofish encryption \n"); ++} ++ ++module_init(loop_fish2_init); ++module_exit(loop_fish2_exit); ++MODULE_LICENSE("GPL"); diff --git a/src/patches/suse-2.6.27.31/patches.suse/unlock_page-speedup.patch b/src/patches/suse-2.6.27.31/patches.suse/unlock_page-speedup.patch new file mode 100644 index 000000000..629bf035a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/unlock_page-speedup.patch @@ -0,0 +1,265 @@ +From: Nick Piggin +Subject: mm: unlock_page speedup +References: bnc#436953 +Patch-upstream: no (could be submitted) + +Introduce a new page flag, PG_waiters, to signal there are processes waiting on +PG_lock; and use it to avoid memory barriers and waitqueue hash lookup in the +unlock_page fastpath. + +lat_mmap profile goes from looking like this (after the mnt_want_write patches) +CPU: AMD64 family10, speed 2000 MHz (estimated) +Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 10000 +samples % symbol name +254150 14.5889 __do_fault +163003 9.3568 unmap_vmas +110232 6.3276 mark_page_accessed +77864 4.4696 __up_read +75864 4.3548 page_waitqueue <<<< +69984 4.0173 handle_mm_fault +66945 3.8428 do_page_fault +66457 3.8148 retint_swapgs +65413 3.7549 shmem_getpage +62904 3.6109 file_update_time +61430 3.5262 set_page_dirty +53425 3.0667 unlock_page <<<< + +To this: +3119 0.1430 unlock_page +0 0.0000 page_waitqueue + +--- + include/linux/page-flags.h | 4 + + include/linux/pagemap.h | 7 ++- + kernel/wait.c | 3 - + mm/filemap.c | 94 +++++++++++++++++++++++++++++++++++---------- + 4 files changed, 83 insertions(+), 25 deletions(-) + +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -71,6 +71,7 @@ + */ + enum pageflags { + PG_locked, /* Page is locked. Don't touch. */ ++ PG_waiters, /* Page has PG_locked waiters. */ + PG_error, + PG_referenced, + PG_uptodate, +@@ -171,6 +172,7 @@ static inline int PAGEMASK_##uname(void) + struct page; /* forward declaration */ + + TESTPAGEFLAG(Locked, locked) ++PAGEFLAG(Waiters, waiters) + PAGEFLAG(Error, error) + PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced) + PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty) +@@ -340,7 +342,7 @@ PAGEFLAG_FALSE(MemError) + #endif + + #define PAGE_FLAGS (1 << PG_lru | 1 << PG_private | 1 << PG_locked | \ +- 1 << PG_buddy | 1 << PG_writeback | \ ++ 1 << PG_buddy | 1 << PG_writeback | 1 << PG_waiters | \ + 1 << PG_slab | 1 << PG_swapcache | 1 << PG_active) + + /* +--- a/include/linux/pagemap.h ++++ b/include/linux/pagemap.h +@@ -161,7 +161,7 @@ static inline int page_cache_add_specula + if (unlikely(!atomic_add_unless(&page->_count, count, 0))) + return 0; + #endif +- VM_BUG_ON(PageCompound(page) && page != compound_head(page)); ++ VM_BUG_ON(PageTail(page)); + + return 1; + } +@@ -326,6 +326,7 @@ static inline void lock_page_nosync(stru + * Never use this directly! + */ + extern void wait_on_page_bit(struct page *page, int bit_nr); ++extern void __wait_on_page_locked(struct page *page); + + /* + * Wait for a page to be unlocked. +@@ -336,8 +337,9 @@ extern void wait_on_page_bit(struct page + */ + static inline void wait_on_page_locked(struct page *page) + { ++ might_sleep(); + if (PageLocked(page)) +- wait_on_page_bit(page, PG_locked); ++ __wait_on_page_locked(page); + } + + /* +@@ -345,6 +347,7 @@ static inline void wait_on_page_locked(s + */ + static inline void wait_on_page_writeback(struct page *page) + { ++ might_sleep(); + if (PageWriteback(page)) + wait_on_page_bit(page, PG_writeback); + } +--- a/kernel/wait.c ++++ b/kernel/wait.c +@@ -186,8 +186,7 @@ int wake_bit_function(wait_queue_t *wait + = container_of(wait, struct wait_bit_queue, wait); + + if (wait_bit->key.flags != key->flags || +- wait_bit->key.bit_nr != key->bit_nr || +- test_bit(key->bit_nr, key->flags)) ++ wait_bit->key.bit_nr != key->bit_nr) + return 0; + else + return autoremove_wake_function(wait, mode, sync, key); +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -181,6 +181,7 @@ static int sync_page(void *word) + if (mapping && mapping->a_ops && mapping->a_ops->sync_page) + mapping->a_ops->sync_page(page); + io_schedule(); ++ + return 0; + } + +@@ -513,12 +514,6 @@ struct page *__page_cache_alloc(gfp_t gf + EXPORT_SYMBOL(__page_cache_alloc); + #endif + +-static int __sleep_on_page_lock(void *word) +-{ +- io_schedule(); +- return 0; +-} +- + /* + * In order to wait for pages to become available there must be + * waitqueues associated with pages. By using a hash table of +@@ -551,6 +546,22 @@ void wait_on_page_bit(struct page *page, + } + EXPORT_SYMBOL(wait_on_page_bit); + ++/* ++ * If PageWaiters was found to be set at unlock time, __wake_page_waiters ++ * should be called to actually perform the wakeup of waiters. ++ */ ++static void __wake_page_waiters(struct page *page) ++{ ++ ClearPageWaiters(page); ++ /* ++ * The smp_mb() is necessary to enforce ordering between the clear_bit ++ * and the read of the waitqueue (to avoid SMP races with a parallel ++ * __wait_on_page_locked()). ++ */ ++ smp_mb__after_clear_bit(); ++ wake_up_page(page, PG_locked); ++} ++ + /** + * unlock_page - unlock a locked page + * @page: the page +@@ -567,11 +578,10 @@ EXPORT_SYMBOL(wait_on_page_bit); + */ + void unlock_page(struct page *page) + { +- smp_mb__before_clear_bit(); +- if (!test_and_clear_bit(PG_locked, &page->flags)) +- BUG(); +- smp_mb__after_clear_bit(); +- wake_up_page(page, PG_locked); ++ VM_BUG_ON(!PageLocked(page)); ++ clear_bit_unlock(PG_locked, &page->flags); ++ if (unlikely(PageWaiters(page))) ++ __wake_page_waiters(page); + } + EXPORT_SYMBOL(unlock_page); + +@@ -601,23 +611,60 @@ EXPORT_SYMBOL(end_page_writeback); + * chances are that on the second loop, the block layer's plug list is empty, + * so sync_page() will then return in state TASK_UNINTERRUPTIBLE. + */ +-void __lock_page(struct page *page) ++void __lock_page(struct page *page) + { ++ wait_queue_head_t *wq = page_waitqueue(page); + DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); + +- __wait_on_bit_lock(page_waitqueue(page), &wait, sync_page, +- TASK_UNINTERRUPTIBLE); ++ do { ++ prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); ++ SetPageWaiters(page); ++ if (likely(PageLocked(page))) ++ sync_page(page); ++ } while (!trylock_page(page)); ++ finish_wait(wq, &wait.wait); + } + EXPORT_SYMBOL(__lock_page); + +-int __lock_page_killable(struct page *page) ++int __lock_page_killable(struct page *page) + { ++ wait_queue_head_t *wq = page_waitqueue(page); + DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); ++ int err = 0; + +- return __wait_on_bit_lock(page_waitqueue(page), &wait, +- sync_page_killable, TASK_KILLABLE); ++ do { ++ prepare_to_wait(wq, &wait.wait, TASK_KILLABLE); ++ SetPageWaiters(page); ++ if (likely(PageLocked(page))) { ++ err = sync_page_killable(page); ++ if (err) ++ break; ++ } ++ } while (!trylock_page(page)); ++ finish_wait(wq, &wait.wait); ++ ++ return err; + } + ++void __wait_on_page_locked(struct page *page) ++{ ++ wait_queue_head_t *wq = page_waitqueue(page); ++ DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); ++ ++ do { ++ prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); ++ SetPageWaiters(page); ++ if (likely(PageLocked(page))) ++ sync_page(page); ++ } while (PageLocked(page)); ++ finish_wait(wq, &wait.wait); ++ ++ /* Clean up a potentially dangling PG_waiters */ ++ if (unlikely(PageWaiters(page))) ++ __wake_page_waiters(page); ++} ++EXPORT_SYMBOL(__wait_on_page_locked); ++ + /** + * __lock_page_nosync - get a lock on the page, without calling sync_page() + * @page: the page to lock +@@ -625,11 +672,18 @@ int __lock_page_killable(struct page *pa + * Variant of lock_page that does not require the caller to hold a reference + * on the page's mapping. + */ +-void __lock_page_nosync(struct page *page) ++void __lock_page_nosync(struct page *page) + { ++ wait_queue_head_t *wq = page_waitqueue(page); + DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); +- __wait_on_bit_lock(page_waitqueue(page), &wait, __sleep_on_page_lock, +- TASK_UNINTERRUPTIBLE); ++ ++ do { ++ prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); ++ SetPageWaiters(page); ++ if (likely(PageLocked(page))) ++ io_schedule(); ++ } while (!trylock_page(page)); ++ finish_wait(wq, &wait.wait); + } + + /** diff --git a/src/patches/suse-2.6.27.31/patches.suse/unmap_vmas-lat b/src/patches/suse-2.6.27.31/patches.suse/unmap_vmas-lat new file mode 100644 index 000000000..532f1ffc3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/unmap_vmas-lat @@ -0,0 +1,32 @@ +From: andrea@suse.de +Subject: low-latency stuff + + +My point is that preempt and no-preempt should do the same thing there, +otherwise when you benchmark -preempt, you'll get better latency, +but not because of the preempt feature, but just because of unrelated +latency improvements that have nothing to do with preempt. + + +--- + mm/memory.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -855,11 +855,11 @@ static unsigned long unmap_page_range(st + return addr; + } + +-#ifdef CONFIG_PREEMPT +-# define ZAP_BLOCK_SIZE (8 * PAGE_SIZE) ++#ifdef CONFIG_SMP ++/* zap one pte page at a time */ ++#define ZAP_BLOCK_SIZE (FREE_PTE_NR * PAGE_SIZE) + #else +-/* No preempt: go for improved straight-line efficiency */ +-# define ZAP_BLOCK_SIZE (1024 * PAGE_SIZE) ++#define ZAP_BLOCK_SIZE (253 * PAGE_SIZE) + #endif + + /** diff --git a/src/patches/suse-2.6.27.31/patches.suse/usb-move-ehci-reg-def.patch b/src/patches/suse-2.6.27.31/patches.suse/usb-move-ehci-reg-def.patch new file mode 100644 index 000000000..c1ba6917a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/usb-move-ehci-reg-def.patch @@ -0,0 +1,339 @@ +From 0af36739af81f152cc24a0fdfa0754ef657afe3d Mon Sep 17 00:00:00 2001 +From: Yinghai Lu +Date: Thu, 24 Jul 2008 17:27:57 -0700 +Subject: usb: move ehci reg def +Patch-mainline: 2.6.28 + +From: Yinghai Lu + +commit 0af36739af81f152cc24a0fdfa0754ef657afe3d upstream. + +prepare x86: usb debug port early console + +move ehci struct def to linux/usrb/ehci_def.h from host/ehci.h + +Signed-off-by: Yinghai Lu +Acked-by: David Brownell +Cc: Andrew Morton +Cc: Andi Kleen +Cc: "Arjan van de Ven" +Cc: "Eric W. Biederman" +Cc: "Greg KH" +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/ehci.h | 138 ------------------------------------- + include/linux/usb/ehci_def.h | 160 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 161 insertions(+), 137 deletions(-) + +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -216,143 +216,7 @@ static void free_cached_itd_list(struct + + /*-------------------------------------------------------------------------*/ + +-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ +- +-/* Section 2.2 Host Controller Capability Registers */ +-struct ehci_caps { +- /* these fields are specified as 8 and 16 bit registers, +- * but some hosts can't perform 8 or 16 bit PCI accesses. +- */ +- u32 hc_capbase; +-#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ +-#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ +- u32 hcs_params; /* HCSPARAMS - offset 0x4 */ +-#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */ +-#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ +-#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */ +-#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */ +-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ +-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +-#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ +- +- u32 hcc_params; /* HCCPARAMS - offset 0x8 */ +-#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */ +-#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ +-#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ +-#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ +-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ +-#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ +- u8 portroute [8]; /* nibbles for routing - offset 0xC */ +-} __attribute__ ((packed)); +- +- +-/* Section 2.3 Host Controller Operational Registers */ +-struct ehci_regs { +- +- /* USBCMD: offset 0x00 */ +- u32 command; +-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ +-#define CMD_PARK (1<<11) /* enable "park" on async qh */ +-#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ +-#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ +-#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ +-#define CMD_ASE (1<<5) /* async schedule enable */ +-#define CMD_PSE (1<<4) /* periodic schedule enable */ +-/* 3:2 is periodic frame list size */ +-#define CMD_RESET (1<<1) /* reset HC not bus */ +-#define CMD_RUN (1<<0) /* start/stop HC */ +- +- /* USBSTS: offset 0x04 */ +- u32 status; +-#define STS_ASS (1<<15) /* Async Schedule Status */ +-#define STS_PSS (1<<14) /* Periodic Schedule Status */ +-#define STS_RECL (1<<13) /* Reclamation */ +-#define STS_HALT (1<<12) /* Not running (any reason) */ +-/* some bits reserved */ +- /* these STS_* flags are also intr_enable bits (USBINTR) */ +-#define STS_IAA (1<<5) /* Interrupted on async advance */ +-#define STS_FATAL (1<<4) /* such as some PCI access errors */ +-#define STS_FLR (1<<3) /* frame list rolled over */ +-#define STS_PCD (1<<2) /* port change detect */ +-#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ +-#define STS_INT (1<<0) /* "normal" completion (short, ...) */ +- +- /* USBINTR: offset 0x08 */ +- u32 intr_enable; +- +- /* FRINDEX: offset 0x0C */ +- u32 frame_index; /* current microframe number */ +- /* CTRLDSSEGMENT: offset 0x10 */ +- u32 segment; /* address bits 63:32 if needed */ +- /* PERIODICLISTBASE: offset 0x14 */ +- u32 frame_list; /* points to periodic list */ +- /* ASYNCLISTADDR: offset 0x18 */ +- u32 async_next; /* address of next async queue head */ +- +- u32 reserved [9]; +- +- /* CONFIGFLAG: offset 0x40 */ +- u32 configured_flag; +-#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ +- +- /* PORTSC: offset 0x44 */ +- u32 port_status [0]; /* up to N_PORTS */ +-/* 31:23 reserved */ +-#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ +-#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ +-#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */ +-/* 19:16 for port testing */ +-#define PORT_LED_OFF (0<<14) +-#define PORT_LED_AMBER (1<<14) +-#define PORT_LED_GREEN (2<<14) +-#define PORT_LED_MASK (3<<14) +-#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +-#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */ +-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ +-/* 9 reserved */ +-#define PORT_RESET (1<<8) /* reset port */ +-#define PORT_SUSPEND (1<<7) /* suspend port */ +-#define PORT_RESUME (1<<6) /* resume it */ +-#define PORT_OCC (1<<5) /* over current change */ +-#define PORT_OC (1<<4) /* over current active */ +-#define PORT_PEC (1<<3) /* port enable change */ +-#define PORT_PE (1<<2) /* port enable */ +-#define PORT_CSC (1<<1) /* connect status change */ +-#define PORT_CONNECT (1<<0) /* device connected */ +-#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) +-} __attribute__ ((packed)); +- +-#define USBMODE 0x68 /* USB Device mode */ +-#define USBMODE_SDIS (1<<3) /* Stream disable */ +-#define USBMODE_BE (1<<2) /* BE/LE endianness select */ +-#define USBMODE_CM_HC (3<<0) /* host controller mode */ +-#define USBMODE_CM_IDLE (0<<0) /* idle state */ +- +-/* Appendix C, Debug port ... intended for use with special "debug devices" +- * that can help if there's no serial console. (nonstandard enumeration.) +- */ +-struct ehci_dbg_port { +- u32 control; +-#define DBGP_OWNER (1<<30) +-#define DBGP_ENABLED (1<<28) +-#define DBGP_DONE (1<<16) +-#define DBGP_INUSE (1<<10) +-#define DBGP_ERRCODE(x) (((x)>>7)&0x07) +-# define DBGP_ERR_BAD 1 +-# define DBGP_ERR_SIGNAL 2 +-#define DBGP_ERROR (1<<6) +-#define DBGP_GO (1<<5) +-#define DBGP_OUT (1<<4) +-#define DBGP_LEN(x) (((x)>>0)&0x0f) +- u32 pids; +-#define DBGP_PID_GET(x) (((x)>>16)&0xff) +-#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok)) +- u32 data03; +- u32 data47; +- u32 address; +-#define DBGP_EPADDR(dev,ep) (((dev)<<8)|(ep)) +-} __attribute__ ((packed)); ++#include + + /*-------------------------------------------------------------------------*/ + +--- /dev/null ++++ b/include/linux/usb/ehci_def.h +@@ -0,0 +1,160 @@ ++/* ++ * Copyright (c) 2001-2002 by David Brownell ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software Foundation, ++ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef __LINUX_USB_EHCI_DEF_H ++#define __LINUX_USB_EHCI_DEF_H ++ ++/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ ++ ++/* Section 2.2 Host Controller Capability Registers */ ++struct ehci_caps { ++ /* these fields are specified as 8 and 16 bit registers, ++ * but some hosts can't perform 8 or 16 bit PCI accesses. ++ */ ++ u32 hc_capbase; ++#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ ++#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ ++ u32 hcs_params; /* HCSPARAMS - offset 0x4 */ ++#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */ ++#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ ++#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */ ++#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */ ++#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ ++#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ ++#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ ++ ++ u32 hcc_params; /* HCCPARAMS - offset 0x8 */ ++#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */ ++#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ ++#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ ++#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ ++#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ ++#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ ++ u8 portroute [8]; /* nibbles for routing - offset 0xC */ ++} __attribute__ ((packed)); ++ ++ ++/* Section 2.3 Host Controller Operational Registers */ ++struct ehci_regs { ++ ++ /* USBCMD: offset 0x00 */ ++ u32 command; ++/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ ++#define CMD_PARK (1<<11) /* enable "park" on async qh */ ++#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ ++#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ ++#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ ++#define CMD_ASE (1<<5) /* async schedule enable */ ++#define CMD_PSE (1<<4) /* periodic schedule enable */ ++/* 3:2 is periodic frame list size */ ++#define CMD_RESET (1<<1) /* reset HC not bus */ ++#define CMD_RUN (1<<0) /* start/stop HC */ ++ ++ /* USBSTS: offset 0x04 */ ++ u32 status; ++#define STS_ASS (1<<15) /* Async Schedule Status */ ++#define STS_PSS (1<<14) /* Periodic Schedule Status */ ++#define STS_RECL (1<<13) /* Reclamation */ ++#define STS_HALT (1<<12) /* Not running (any reason) */ ++/* some bits reserved */ ++ /* these STS_* flags are also intr_enable bits (USBINTR) */ ++#define STS_IAA (1<<5) /* Interrupted on async advance */ ++#define STS_FATAL (1<<4) /* such as some PCI access errors */ ++#define STS_FLR (1<<3) /* frame list rolled over */ ++#define STS_PCD (1<<2) /* port change detect */ ++#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ ++#define STS_INT (1<<0) /* "normal" completion (short, ...) */ ++ ++ /* USBINTR: offset 0x08 */ ++ u32 intr_enable; ++ ++ /* FRINDEX: offset 0x0C */ ++ u32 frame_index; /* current microframe number */ ++ /* CTRLDSSEGMENT: offset 0x10 */ ++ u32 segment; /* address bits 63:32 if needed */ ++ /* PERIODICLISTBASE: offset 0x14 */ ++ u32 frame_list; /* points to periodic list */ ++ /* ASYNCLISTADDR: offset 0x18 */ ++ u32 async_next; /* address of next async queue head */ ++ ++ u32 reserved [9]; ++ ++ /* CONFIGFLAG: offset 0x40 */ ++ u32 configured_flag; ++#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ ++ ++ /* PORTSC: offset 0x44 */ ++ u32 port_status [0]; /* up to N_PORTS */ ++/* 31:23 reserved */ ++#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ ++#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ ++#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */ ++/* 19:16 for port testing */ ++#define PORT_LED_OFF (0<<14) ++#define PORT_LED_AMBER (1<<14) ++#define PORT_LED_GREEN (2<<14) ++#define PORT_LED_MASK (3<<14) ++#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ ++#define PORT_POWER (1<<12) /* true: has power (see PPC) */ ++#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ ++/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ ++/* 9 reserved */ ++#define PORT_RESET (1<<8) /* reset port */ ++#define PORT_SUSPEND (1<<7) /* suspend port */ ++#define PORT_RESUME (1<<6) /* resume it */ ++#define PORT_OCC (1<<5) /* over current change */ ++#define PORT_OC (1<<4) /* over current active */ ++#define PORT_PEC (1<<3) /* port enable change */ ++#define PORT_PE (1<<2) /* port enable */ ++#define PORT_CSC (1<<1) /* connect status change */ ++#define PORT_CONNECT (1<<0) /* device connected */ ++#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) ++} __attribute__ ((packed)); ++ ++#define USBMODE 0x68 /* USB Device mode */ ++#define USBMODE_SDIS (1<<3) /* Stream disable */ ++#define USBMODE_BE (1<<2) /* BE/LE endianness select */ ++#define USBMODE_CM_HC (3<<0) /* host controller mode */ ++#define USBMODE_CM_IDLE (0<<0) /* idle state */ ++ ++/* Appendix C, Debug port ... intended for use with special "debug devices" ++ * that can help if there's no serial console. (nonstandard enumeration.) ++ */ ++struct ehci_dbg_port { ++ u32 control; ++#define DBGP_OWNER (1<<30) ++#define DBGP_ENABLED (1<<28) ++#define DBGP_DONE (1<<16) ++#define DBGP_INUSE (1<<10) ++#define DBGP_ERRCODE(x) (((x)>>7)&0x07) ++# define DBGP_ERR_BAD 1 ++# define DBGP_ERR_SIGNAL 2 ++#define DBGP_ERROR (1<<6) ++#define DBGP_GO (1<<5) ++#define DBGP_OUT (1<<4) ++#define DBGP_LEN(x) (((x)>>0)&0x0f) ++ u32 pids; ++#define DBGP_PID_GET(x) (((x)>>16)&0xff) ++#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) ++ u32 data03; ++ u32 data47; ++ u32 address; ++#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) ++} __attribute__ ((packed)); ++ ++#endif /* __LINUX_USB_EHCI_DEF_H */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/usb-storage-disable-delay.patch b/src/patches/suse-2.6.27.31/patches.suse/usb-storage-disable-delay.patch new file mode 100644 index 000000000..ec8a0dba0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/usb-storage-disable-delay.patch @@ -0,0 +1,29 @@ +From: Greg Kroah-Hartman +Subject: USB: change default delay time for usb-storage devices +Patch-mainline: no + +This reduces the amount of time someone has to wait for a usb-storage +device to be usable from 5 seconds to 1 second. Some very old and buggy +devices might still need the longer timeout, so they can change this +with the sysfs option. + +Change made at the request of the desktop developers who were tired of +us taking longer than Windows for no good reason. + +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/storage/usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/storage/usb.c ++++ b/drivers/usb/storage/usb.c +@@ -109,7 +109,7 @@ MODULE_AUTHOR("Matthew Dharm +Subject: Enable GB mapped linear KVA on x86 +References: bnc#437674 +Patch-upstream: should be in 2.6.28 or 29 + +GBPAGES should be turned on in SUSE x86-64 kernels. + +Signed-off-by: Nick Piggin +--- +--- + arch/x86/Kconfig | 9 +++++++++ + arch/x86/Kconfig.debug | 12 ------------ + 2 files changed, 9 insertions(+), 12 deletions(-) + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -960,6 +960,15 @@ config X86_PAE + has the cost of more pagetable lookup overhead, and also + consumes more pagetable space per process. + ++config DIRECT_GBPAGES ++ bool "Enable 1GB pages for kernel pagetables" if EMBEDDED ++ default y ++ depends on X86_64 ++ help ++ Allow the kernel linear mapping to use 1GB pages on CPUs that ++ support it. This can improve the kernel's performance a tiny bit by ++ reducing TLB pressure. If in doubt, say "Y". ++ + # Common NUMA Features + config NUMA + bool "Numa Memory Allocation and Scheduler Support (EXPERIMENTAL)" +--- a/arch/x86/Kconfig.debug ++++ b/arch/x86/Kconfig.debug +@@ -114,18 +114,6 @@ config DEBUG_RODATA + data. This is recommended so that we can catch kernel bugs sooner. + If in doubt, say "Y". + +-config DIRECT_GBPAGES +- bool "Enable gbpages-mapped kernel pagetables" +- depends on DEBUG_KERNEL && EXPERIMENTAL && X86_64 +- help +- Enable gigabyte pages support (if the CPU supports it). This can +- improve the kernel's performance a tiny bit by reducing TLB +- pressure. +- +- This is experimental code. +- +- If in doubt, say "N". +- + config DEBUG_RODATA_TEST + bool "Testcase for the DEBUG_RODATA feature" + depends on DEBUG_RODATA diff --git a/src/patches/suse-2.6.27.31/patches.suse/x86-mark_rodata_rw-2.patch b/src/patches/suse-2.6.27.31/patches.suse/x86-mark_rodata_rw-2.patch new file mode 100644 index 000000000..7cc5c2256 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/x86-mark_rodata_rw-2.patch @@ -0,0 +1,30 @@ +From: Andres Gruenbacher +Subject: Also mark rodata pages executable in mark_rodata_rw() + +For review: do we also need to mark rodata pages executable in +mark_rodata_rw() to fully undo mark_rodata_ro()? + +Signed-off-by: Andres Gruenbacher + +--- + arch/x86/mm/init_64-xen.c | 6 ++++++ + arch/x86/mm/init_64.c | 6 ++++++ + 2 files changed, 12 insertions(+) + +Index: b/arch/x86/mm/init_64.c +=================================================================== +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -912,6 +912,12 @@ void mark_rodata_rw(void) + printk(KERN_INFO "Write enabling the kernel read-only data: %luk\n", + (end - start) >> 10); + set_memory_rw_force(start, (end - start) >> PAGE_SHIFT); ++ ++ /* ++ * The rodata section should also be executable. (The kernel text ++ * still is!) ++ */ ++ set_memory_x_force(rodata_start, (end - rodata_start) >> PAGE_SHIFT); + } + EXPORT_SYMBOL(mark_rodata_rw); + #endif diff --git a/src/patches/suse-2.6.27.31/patches.suse/x86-mark_rodata_rw.patch b/src/patches/suse-2.6.27.31/patches.suse/x86-mark_rodata_rw.patch new file mode 100644 index 000000000..4f8527ba6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/x86-mark_rodata_rw.patch @@ -0,0 +1,169 @@ +From: Nick Piggin +Subject: Add mark_rodata_rw() to un-protect read-only kernel code pages +References: bnc#439348 + +CONFIG_RODATA presents a problem for antivirus vendors who do not have a +clean user-space interface for getting virus scanning triggered, and +currently resort to patching the kernel code instead (presumably the +ystem call table). With CONFIG_RODATA enabled, the kernel rejects such +write accesses. + +Add a new mark_rodata_rw() function to un-protect the read-only kernel code +pages for now, and export mark_rodata_ro() and mark_rodata_rw() to modules. + +This is not meant as a permanent workaround, and will be removed again in the +next release! + +Acked-by: Andres Gruenbacher + +--- + arch/x86/mm/init_32.c | 22 ++++++++++++++++++++++ + arch/x86/mm/init_64.c | 17 +++++++++++++++++ + arch/x86/mm/pageattr.c | 30 ++++++++++++++++++++++++++++-- + include/asm-x86/cacheflush.h | 3 +++ + 4 files changed, 70 insertions(+), 2 deletions(-) + +--- a/arch/x86/mm/init_32.c ++++ b/arch/x86/mm/init_32.c +@@ -1073,6 +1073,28 @@ void mark_rodata_ro(void) + set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); + #endif + } ++EXPORT_SYMBOL(mark_rodata_ro); ++ ++void mark_rodata_rw(void) ++{ ++ unsigned long start = PFN_ALIGN(_text); ++ unsigned long size = PFN_ALIGN(_etext) - start; ++ ++#ifndef CONFIG_DYNAMIC_FTRACE ++ /* Dynamic tracing modifies the kernel text section */ ++ set_pages_rw_force(virt_to_page(start), size >> PAGE_SHIFT); ++ printk(KERN_INFO "Write enabling the kernel text: %luk\n", ++ size >> 10); ++ ++#endif /* CONFIG_DYNAMIC_FTRACE */ ++ ++ start += size; ++ size = (unsigned long)__end_rodata - start; ++ set_pages_rw_force(virt_to_page(start), size >> PAGE_SHIFT); ++ printk(KERN_INFO "Write enabling the kernel read-only data: %luk\n", ++ size >> 10); ++} ++EXPORT_SYMBOL(mark_rodata_rw); + #endif + + void free_init_pages(char *what, unsigned long begin, unsigned long end) +--- a/arch/x86/mm/init_64.c ++++ b/arch/x86/mm/init_64.c +@@ -896,7 +896,24 @@ void mark_rodata_ro(void) + set_memory_ro(start, (end-start) >> PAGE_SHIFT); + #endif + } ++EXPORT_SYMBOL(mark_rodata_ro); + ++void mark_rodata_rw(void) ++{ ++ unsigned long start = PFN_ALIGN(_stext), end = PFN_ALIGN(__end_rodata); ++ unsigned long rodata_start = ++ ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK; ++ ++#ifdef CONFIG_DYNAMIC_FTRACE ++ /* Dynamic tracing modifies the kernel text section */ ++ start = rodata_start; ++#endif ++ ++ printk(KERN_INFO "Write enabling the kernel read-only data: %luk\n", ++ (end - start) >> 10); ++ set_memory_rw_force(start, (end - start) >> PAGE_SHIFT); ++} ++EXPORT_SYMBOL(mark_rodata_rw); + #endif + + #ifdef CONFIG_BLK_DEV_INITRD +--- a/arch/x86/mm/pageattr.c ++++ b/arch/x86/mm/pageattr.c +@@ -190,6 +190,8 @@ static void cpa_flush_range(unsigned lon + } + } + ++static int static_protections_allow_rodata __read_mostly; ++ + /* + * Certain areas of memory on x86 require very specific protection flags, + * for example the BIOS area or kernel text. Callers don't always get this +@@ -221,8 +223,10 @@ static inline pgprot_t static_protection + * catches all aliases. + */ + if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT, +- __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) +- pgprot_val(forbidden) |= _PAGE_RW; ++ __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) { ++ if (!static_protections_allow_rodata) ++ pgprot_val(forbidden) |= _PAGE_RW; ++ } + + prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); + +@@ -956,6 +960,21 @@ int set_memory_rw(unsigned long addr, in + return change_page_attr_set(addr, numpages, __pgprot(_PAGE_RW)); + } + ++/* hack: bypass kernel rodata section static_protections check. */ ++int set_memory_rw_force(unsigned long addr, int numpages) ++{ ++ static DEFINE_MUTEX(lock); ++ int ret; ++ ++ mutex_lock(&lock); ++ static_protections_allow_rodata = 1; ++ ret = change_page_attr_set(addr, numpages, __pgprot(_PAGE_RW)); ++ static_protections_allow_rodata = 0; ++ mutex_unlock(&lock); ++ ++ return ret; ++} ++ + int set_memory_np(unsigned long addr, int numpages) + { + return change_page_attr_clear(addr, numpages, __pgprot(_PAGE_PRESENT)); +@@ -1013,6 +1032,13 @@ int set_pages_rw(struct page *page, int + return set_memory_rw(addr, numpages); + } + ++int set_pages_rw_force(struct page *page, int numpages) ++{ ++ unsigned long addr = (unsigned long)page_address(page); ++ ++ return set_memory_rw_force(addr, numpages); ++} ++ + #ifdef CONFIG_DEBUG_PAGEALLOC + + static int __set_pages_p(struct page *page, int numpages) +--- a/include/asm-x86/cacheflush.h ++++ b/include/asm-x86/cacheflush.h +@@ -63,6 +63,7 @@ int set_memory_x(unsigned long addr, int + int set_memory_nx(unsigned long addr, int numpages); + int set_memory_ro(unsigned long addr, int numpages); + int set_memory_rw(unsigned long addr, int numpages); ++int set_memory_rw_force(unsigned long addr, int numpages); + int set_memory_np(unsigned long addr, int numpages); + int set_memory_4k(unsigned long addr, int numpages); + +@@ -92,6 +93,7 @@ int set_pages_x(struct page *page, int n + int set_pages_nx(struct page *page, int numpages); + int set_pages_ro(struct page *page, int numpages); + int set_pages_rw(struct page *page, int numpages); ++int set_pages_rw_force(struct page *page, int numpages); + + + void clflush_cache_range(void *addr, unsigned int size); +@@ -100,6 +102,7 @@ void cpa_init(void); + + #ifdef CONFIG_DEBUG_RODATA + void mark_rodata_ro(void); ++void mark_rodata_rw(void); + extern const int rodata_test_data; + #endif + diff --git a/src/patches/suse-2.6.27.31/patches.suse/x86-usb-debug-port-early-console-v4.patch b/src/patches/suse-2.6.27.31/patches.suse/x86-usb-debug-port-early-console-v4.patch new file mode 100644 index 000000000..9ead2a16d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/x86-usb-debug-port-early-console-v4.patch @@ -0,0 +1,906 @@ +From 5c05917e7fe313a187ad6ebb94c1c6cf42862a0b Mon Sep 17 00:00:00 2001 +From: Yinghai Lu +Date: Thu, 24 Jul 2008 17:29:40 -0700 +Subject: x86: usb debug port early console, v4 +Patch-mainline: 2.6.28 + +From: Yinghai Lu + +commit 5c05917e7fe313a187ad6ebb94c1c6cf42862a0b upstream. + +based on work from Eric, and add some timeout so don't dead loop when debug +device is not installed + +v2: fix checkpatch warning +v3: move ehci struct def to linux/usrb/ehci_def.h from host/ehci.h + also add CONFIG_EARLY_PRINTK_DBGP to disable it by default +v4: address comments from Ingo, seperate ehci reg def moving to another patch + also add auto detect port that connect to debug device for Nvidia + southbridge + +Signed-off-by: Yinghai Lu +Cc: Andrew Morton +Cc: Andi Kleen +Cc: "Arjan van de Ven" +Cc: "Eric W. Biederman" +Cc: "Greg KH" +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/kernel-parameters.txt | 3 + arch/x86/Kconfig.debug | 13 + arch/x86/kernel/early_printk.c | 762 +++++++++++++++++++++++++++++++++++- + 3 files changed, 774 insertions(+), 4 deletions(-) + +--- a/arch/x86/Kconfig.debug ++++ b/arch/x86/Kconfig.debug +@@ -43,6 +43,19 @@ config EARLY_PRINTK + with klogd/syslogd or the X server. You should normally N here, + unless you want to debug such a crash. + ++config EARLY_PRINTK_DBGP ++ bool "Early printk via EHCI debug port" ++ default n ++ depends on EARLY_PRINTK ++ help ++ Write kernel log output directly into the EHCI debug port. ++ ++ This is useful for kernel debugging when your machine crashes very ++ early before the console code is initialized. For normal operation ++ it is not recommended because it looks ugly and doesn't cooperate ++ with klogd/syslogd or the X server. You should normally N here, ++ unless you want to debug such a crash. You need usb debug device. ++ + config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL +--- a/arch/x86/kernel/early_printk.c ++++ b/arch/x86/kernel/early_printk.c +@@ -3,11 +3,19 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include + #include + #include ++#include ++#include ++#include ++#include + + /* Simple VGA output */ + #define VGABASE (__ISA_IO_base + 0xb8000) +@@ -78,6 +86,7 @@ static int early_serial_base = 0x3f8; / + static int early_serial_putc(unsigned char ch) + { + unsigned timeout = 0xffff; ++ + while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) + cpu_relax(); + outb(ch, early_serial_base + TXR); +@@ -151,6 +160,721 @@ static struct console early_serial_conso + .index = -1, + }; + ++#ifdef CONFIG_EARLY_PRINTK_DBGP ++ ++static struct ehci_caps __iomem *ehci_caps; ++static struct ehci_regs __iomem *ehci_regs; ++static struct ehci_dbg_port __iomem *ehci_debug; ++static unsigned int dbgp_endpoint_out; ++ ++struct ehci_dev { ++ u32 bus; ++ u32 slot; ++ u32 func; ++}; ++ ++static struct ehci_dev ehci_dev; ++ ++#define USB_DEBUG_DEVNUM 127 ++ ++#define DBGP_DATA_TOGGLE 0x8800 ++ ++static inline u32 dbgp_pid_update(u32 x, u32 tok) ++{ ++ return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff); ++} ++ ++static inline u32 dbgp_len_update(u32 x, u32 len) ++{ ++ return (x & ~0x0f) | (len & 0x0f); ++} ++ ++/* ++ * USB Packet IDs (PIDs) ++ */ ++ ++/* token */ ++#define USB_PID_OUT 0xe1 ++#define USB_PID_IN 0x69 ++#define USB_PID_SOF 0xa5 ++#define USB_PID_SETUP 0x2d ++/* handshake */ ++#define USB_PID_ACK 0xd2 ++#define USB_PID_NAK 0x5a ++#define USB_PID_STALL 0x1e ++#define USB_PID_NYET 0x96 ++/* data */ ++#define USB_PID_DATA0 0xc3 ++#define USB_PID_DATA1 0x4b ++#define USB_PID_DATA2 0x87 ++#define USB_PID_MDATA 0x0f ++/* Special */ ++#define USB_PID_PREAMBLE 0x3c ++#define USB_PID_ERR 0x3c ++#define USB_PID_SPLIT 0x78 ++#define USB_PID_PING 0xb4 ++#define USB_PID_UNDEF_0 0xf0 ++ ++#define USB_PID_DATA_TOGGLE 0x88 ++#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE) ++ ++#define PCI_CAP_ID_EHCI_DEBUG 0xa ++ ++#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ ++#define HUB_SHORT_RESET_TIME 10 ++#define HUB_LONG_RESET_TIME 200 ++#define HUB_RESET_TIMEOUT 500 ++ ++#define DBGP_MAX_PACKET 8 ++ ++static int dbgp_wait_until_complete(void) ++{ ++ u32 ctrl; ++ int loop = 0x100000; ++ ++ do { ++ ctrl = readl(&ehci_debug->control); ++ /* Stop when the transaction is finished */ ++ if (ctrl & DBGP_DONE) ++ break; ++ } while (--loop > 0); ++ ++ if (!loop) ++ return -1; ++ ++ /* ++ * Now that we have observed the completed transaction, ++ * clear the done bit. ++ */ ++ writel(ctrl | DBGP_DONE, &ehci_debug->control); ++ return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl); ++} ++ ++static void dbgp_mdelay(int ms) ++{ ++ int i; ++ ++ while (ms--) { ++ for (i = 0; i < 1000; i++) ++ outb(0x1, 0x80); ++ } ++} ++ ++static void dbgp_breath(void) ++{ ++ /* Sleep to give the debug port a chance to breathe */ ++} ++ ++static int dbgp_wait_until_done(unsigned ctrl) ++{ ++ u32 pids, lpid; ++ int ret; ++ int loop = 3; ++ ++retry: ++ writel(ctrl | DBGP_GO, &ehci_debug->control); ++ ret = dbgp_wait_until_complete(); ++ pids = readl(&ehci_debug->pids); ++ lpid = DBGP_PID_GET(pids); ++ ++ if (ret < 0) ++ return ret; ++ ++ /* ++ * If the port is getting full or it has dropped data ++ * start pacing ourselves, not necessary but it's friendly. ++ */ ++ if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET)) ++ dbgp_breath(); ++ ++ /* If I get a NACK reissue the transmission */ ++ if (lpid == USB_PID_NAK) { ++ if (--loop > 0) ++ goto retry; ++ } ++ ++ return ret; ++} ++ ++static void dbgp_set_data(const void *buf, int size) ++{ ++ const unsigned char *bytes = buf; ++ u32 lo, hi; ++ int i; ++ ++ lo = hi = 0; ++ for (i = 0; i < 4 && i < size; i++) ++ lo |= bytes[i] << (8*i); ++ for (; i < 8 && i < size; i++) ++ hi |= bytes[i] << (8*(i - 4)); ++ writel(lo, &ehci_debug->data03); ++ writel(hi, &ehci_debug->data47); ++} ++ ++static void dbgp_get_data(void *buf, int size) ++{ ++ unsigned char *bytes = buf; ++ u32 lo, hi; ++ int i; ++ ++ lo = readl(&ehci_debug->data03); ++ hi = readl(&ehci_debug->data47); ++ for (i = 0; i < 4 && i < size; i++) ++ bytes[i] = (lo >> (8*i)) & 0xff; ++ for (; i < 8 && i < size; i++) ++ bytes[i] = (hi >> (8*(i - 4))) & 0xff; ++} ++ ++static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, ++ const char *bytes, int size) ++{ ++ u32 pids, addr, ctrl; ++ int ret; ++ ++ if (size > DBGP_MAX_PACKET) ++ return -1; ++ ++ addr = DBGP_EPADDR(devnum, endpoint); ++ ++ pids = readl(&ehci_debug->pids); ++ pids = dbgp_pid_update(pids, USB_PID_OUT); ++ ++ ctrl = readl(&ehci_debug->control); ++ ctrl = dbgp_len_update(ctrl, size); ++ ctrl |= DBGP_OUT; ++ ctrl |= DBGP_GO; ++ ++ dbgp_set_data(bytes, size); ++ writel(addr, &ehci_debug->address); ++ writel(pids, &ehci_debug->pids); ++ ++ ret = dbgp_wait_until_done(ctrl); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, ++ int size) ++{ ++ u32 pids, addr, ctrl; ++ int ret; ++ ++ if (size > DBGP_MAX_PACKET) ++ return -1; ++ ++ addr = DBGP_EPADDR(devnum, endpoint); ++ ++ pids = readl(&ehci_debug->pids); ++ pids = dbgp_pid_update(pids, USB_PID_IN); ++ ++ ctrl = readl(&ehci_debug->control); ++ ctrl = dbgp_len_update(ctrl, size); ++ ctrl &= ~DBGP_OUT; ++ ctrl |= DBGP_GO; ++ ++ writel(addr, &ehci_debug->address); ++ writel(pids, &ehci_debug->pids); ++ ret = dbgp_wait_until_done(ctrl); ++ if (ret < 0) ++ return ret; ++ ++ if (size > ret) ++ size = ret; ++ dbgp_get_data(data, size); ++ return ret; ++} ++ ++static int dbgp_control_msg(unsigned devnum, int requesttype, int request, ++ int value, int index, void *data, int size) ++{ ++ u32 pids, addr, ctrl; ++ struct usb_ctrlrequest req; ++ int read; ++ int ret; ++ ++ read = (requesttype & USB_DIR_IN) != 0; ++ if (size > (read ? DBGP_MAX_PACKET:0)) ++ return -1; ++ ++ /* Compute the control message */ ++ req.bRequestType = requesttype; ++ req.bRequest = request; ++ req.wValue = value; ++ req.wIndex = index; ++ req.wLength = size; ++ ++ pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP); ++ addr = DBGP_EPADDR(devnum, 0); ++ ++ ctrl = readl(&ehci_debug->control); ++ ctrl = dbgp_len_update(ctrl, sizeof(req)); ++ ctrl |= DBGP_OUT; ++ ctrl |= DBGP_GO; ++ ++ /* Send the setup message */ ++ dbgp_set_data(&req, sizeof(req)); ++ writel(addr, &ehci_debug->address); ++ writel(pids, &ehci_debug->pids); ++ ret = dbgp_wait_until_done(ctrl); ++ if (ret < 0) ++ return ret; ++ ++ /* Read the result */ ++ return dbgp_bulk_read(devnum, 0, data, size); ++} ++ ++ ++/* Find a PCI capability */ ++static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap) ++{ ++ u8 pos; ++ int bytes; ++ ++ if (!(read_pci_config_16(num, slot, func, PCI_STATUS) & ++ PCI_STATUS_CAP_LIST)) ++ return 0; ++ ++ pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST); ++ for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { ++ u8 id; ++ ++ pos &= ~3; ++ id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID); ++ if (id == 0xff) ++ break; ++ if (id == cap) ++ return pos; ++ ++ pos = read_pci_config_byte(num, slot, func, ++ pos+PCI_CAP_LIST_NEXT); ++ } ++ return 0; ++} ++ ++static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func) ++{ ++ u32 class; ++ ++ class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); ++ if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI) ++ return 0; ++ ++ return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG); ++} ++ ++static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc) ++{ ++ u32 bus, slot, func; ++ ++ for (bus = 0; bus < 256; bus++) { ++ for (slot = 0; slot < 32; slot++) { ++ for (func = 0; func < 8; func++) { ++ unsigned cap; ++ ++ cap = __find_dbgp(bus, slot, func); ++ ++ if (!cap) ++ continue; ++ if (ehci_num-- != 0) ++ continue; ++ *rbus = bus; ++ *rslot = slot; ++ *rfunc = func; ++ return cap; ++ } ++ } ++ } ++ return 0; ++} ++ ++static int ehci_reset_port(int port) ++{ ++ u32 portsc; ++ u32 delay_time, delay; ++ int loop; ++ ++ /* Reset the usb debug port */ ++ portsc = readl(&ehci_regs->port_status[port - 1]); ++ portsc &= ~PORT_PE; ++ portsc |= PORT_RESET; ++ writel(portsc, &ehci_regs->port_status[port - 1]); ++ ++ delay = HUB_ROOT_RESET_TIME; ++ for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; ++ delay_time += delay) { ++ dbgp_mdelay(delay); ++ ++ portsc = readl(&ehci_regs->port_status[port - 1]); ++ if (portsc & PORT_RESET) { ++ /* force reset to complete */ ++ loop = 2; ++ writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), ++ &ehci_regs->port_status[port - 1]); ++ do { ++ portsc = readl(&ehci_regs->port_status[port-1]); ++ } while ((portsc & PORT_RESET) && (--loop > 0)); ++ } ++ ++ /* Device went away? */ ++ if (!(portsc & PORT_CONNECT)) ++ return -ENOTCONN; ++ ++ /* bomb out completely if something weird happend */ ++ if ((portsc & PORT_CSC)) ++ return -EINVAL; ++ ++ /* If we've finished resetting, then break out of the loop */ ++ if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) ++ return 0; ++ } ++ return -EBUSY; ++} ++ ++static int ehci_wait_for_port(int port) ++{ ++ u32 status; ++ int ret, reps; ++ ++ for (reps = 0; reps < 3; reps++) { ++ dbgp_mdelay(100); ++ status = readl(&ehci_regs->status); ++ if (status & STS_PCD) { ++ ret = ehci_reset_port(port); ++ if (ret == 0) ++ return 0; ++ } ++ } ++ return -ENOTCONN; ++} ++ ++#ifdef DBGP_DEBUG ++# define dbgp_printk early_printk ++#else ++static inline void dbgp_printk(const char *fmt, ...) { } ++#endif ++ ++typedef void (*set_debug_port_t)(int port); ++ ++static void default_set_debug_port(int port) ++{ ++} ++ ++static set_debug_port_t set_debug_port = default_set_debug_port; ++ ++static void nvidia_set_debug_port(int port) ++{ ++ u32 dword; ++ dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, ++ 0x74); ++ dword &= ~(0x0f<<12); ++ dword |= ((port & 0x0f)<<12); ++ write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74, ++ dword); ++ dbgp_printk("set debug port to %d\n", port); ++} ++ ++static void __init detect_set_debug_port(void) ++{ ++ u32 vendorid; ++ ++ vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, ++ 0x00); ++ ++ if ((vendorid & 0xffff) == 0x10de) { ++ dbgp_printk("using nvidia set_debug_port\n"); ++ set_debug_port = nvidia_set_debug_port; ++ } ++} ++ ++static int __init ehci_setup(void) ++{ ++ struct usb_debug_descriptor dbgp_desc; ++ u32 cmd, ctrl, status, portsc, hcs_params; ++ u32 debug_port, new_debug_port = 0, n_ports; ++ u32 devnum; ++ int ret, i; ++ int loop; ++ int port_map_tried; ++ int playtimes = 3; ++ ++try_next_time: ++ port_map_tried = 0; ++ ++try_next_port: ++ ++ hcs_params = readl(&ehci_caps->hcs_params); ++ debug_port = HCS_DEBUG_PORT(hcs_params); ++ n_ports = HCS_N_PORTS(hcs_params); ++ ++ dbgp_printk("debug_port: %d\n", debug_port); ++ dbgp_printk("n_ports: %d\n", n_ports); ++ ++ for (i = 1; i <= n_ports; i++) { ++ portsc = readl(&ehci_regs->port_status[i-1]); ++ dbgp_printk("portstatus%d: %08x\n", i, portsc); ++ } ++ ++ if (port_map_tried && (new_debug_port != debug_port)) { ++ if (--playtimes) { ++ set_debug_port(new_debug_port); ++ goto try_next_time; ++ } ++ return -1; ++ } ++ ++ loop = 10; ++ /* Reset the EHCI controller */ ++ cmd = readl(&ehci_regs->command); ++ cmd |= CMD_RESET; ++ writel(cmd, &ehci_regs->command); ++ do { ++ cmd = readl(&ehci_regs->command); ++ } while ((cmd & CMD_RESET) && (--loop > 0)); ++ ++ if (!loop) { ++ dbgp_printk("can not reset ehci\n"); ++ return -1; ++ } ++ dbgp_printk("ehci reset done\n"); ++ ++ /* Claim ownership, but do not enable yet */ ++ ctrl = readl(&ehci_debug->control); ++ ctrl |= DBGP_OWNER; ++ ctrl &= ~(DBGP_ENABLED | DBGP_INUSE); ++ writel(ctrl, &ehci_debug->control); ++ ++ /* Start the ehci running */ ++ cmd = readl(&ehci_regs->command); ++ cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET); ++ cmd |= CMD_RUN; ++ writel(cmd, &ehci_regs->command); ++ ++ /* Ensure everything is routed to the EHCI */ ++ writel(FLAG_CF, &ehci_regs->configured_flag); ++ ++ /* Wait until the controller is no longer halted */ ++ loop = 10; ++ do { ++ status = readl(&ehci_regs->status); ++ } while ((status & STS_HALT) && (--loop > 0)); ++ ++ if (!loop) { ++ dbgp_printk("ehci can be started\n"); ++ return -1; ++ } ++ dbgp_printk("ehci started\n"); ++ ++ /* Wait for a device to show up in the debug port */ ++ ret = ehci_wait_for_port(debug_port); ++ if (ret < 0) { ++ dbgp_printk("No device found in debug port\n"); ++ goto next_debug_port; ++ } ++ dbgp_printk("ehci wait for port done\n"); ++ ++ /* Enable the debug port */ ++ ctrl = readl(&ehci_debug->control); ++ ctrl |= DBGP_CLAIM; ++ writel(ctrl, &ehci_debug->control); ++ ctrl = readl(&ehci_debug->control); ++ if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) { ++ dbgp_printk("No device in debug port\n"); ++ writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control); ++ goto err; ++ } ++ dbgp_printk("debug ported enabled\n"); ++ ++ /* Completely transfer the debug device to the debug controller */ ++ portsc = readl(&ehci_regs->port_status[debug_port - 1]); ++ portsc &= ~PORT_PE; ++ writel(portsc, &ehci_regs->port_status[debug_port - 1]); ++ ++ dbgp_mdelay(100); ++ ++ /* Find the debug device and make it device number 127 */ ++ for (devnum = 0; devnum <= 127; devnum++) { ++ ret = dbgp_control_msg(devnum, ++ USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, ++ USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0, ++ &dbgp_desc, sizeof(dbgp_desc)); ++ if (ret > 0) ++ break; ++ } ++ if (devnum > 127) { ++ dbgp_printk("Could not find attached debug device\n"); ++ goto err; ++ } ++ if (ret < 0) { ++ dbgp_printk("Attached device is not a debug device\n"); ++ goto err; ++ } ++ dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; ++ ++ /* Move the device to 127 if it isn't already there */ ++ if (devnum != USB_DEBUG_DEVNUM) { ++ ret = dbgp_control_msg(devnum, ++ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, ++ USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0); ++ if (ret < 0) { ++ dbgp_printk("Could not move attached device to %d\n", ++ USB_DEBUG_DEVNUM); ++ goto err; ++ } ++ devnum = USB_DEBUG_DEVNUM; ++ dbgp_printk("debug device renamed to 127\n"); ++ } ++ ++ /* Enable the debug interface */ ++ ret = dbgp_control_msg(USB_DEBUG_DEVNUM, ++ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, ++ USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0); ++ if (ret < 0) { ++ dbgp_printk(" Could not enable the debug device\n"); ++ goto err; ++ } ++ dbgp_printk("debug interface enabled\n"); ++ ++ /* Perform a small write to get the even/odd data state in sync ++ */ ++ ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1); ++ if (ret < 0) { ++ dbgp_printk("dbgp_bulk_write failed: %d\n", ret); ++ goto err; ++ } ++ dbgp_printk("small write doned\n"); ++ ++ return 0; ++err: ++ /* Things didn't work so remove my claim */ ++ ctrl = readl(&ehci_debug->control); ++ ctrl &= ~(DBGP_CLAIM | DBGP_OUT); ++ writel(ctrl, &ehci_debug->control); ++ return -1; ++ ++next_debug_port: ++ port_map_tried |= (1<<(debug_port - 1)); ++ new_debug_port = ((debug_port-1+1)%n_ports) + 1; ++ if (port_map_tried != ((1<> 29) & 0x7; ++ bar = (bar * 4) + 0xc; ++ offset = (debug_port >> 16) & 0xfff; ++ dbgp_printk("bar: %02x offset: %03x\n", bar, offset); ++ if (bar != PCI_BASE_ADDRESS_0) { ++ dbgp_printk("only debug ports on bar 1 handled.\n"); ++ ++ return -1; ++ } ++ ++ bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); ++ dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset); ++ if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) { ++ dbgp_printk("only simple 32bit mmio bars supported\n"); ++ ++ return -1; ++ } ++ ++ /* double check if the mem space is enabled */ ++ byte = read_pci_config_byte(bus, slot, func, 0x04); ++ if (!(byte & 0x2)) { ++ byte |= 0x02; ++ write_pci_config_byte(bus, slot, func, 0x04, byte); ++ dbgp_printk("mmio for ehci enabled\n"); ++ } ++ ++ /* ++ * FIXME I don't have the bar size so just guess PAGE_SIZE is more ++ * than enough. 1K is the biggest I have seen. ++ */ ++ set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK); ++ ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE); ++ ehci_bar += bar_val & ~PAGE_MASK; ++ dbgp_printk("ehci_bar: %p\n", ehci_bar); ++ ++ ehci_caps = ehci_bar; ++ ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase)); ++ ehci_debug = ehci_bar + offset; ++ ehci_dev.bus = bus; ++ ehci_dev.slot = slot; ++ ehci_dev.func = func; ++ ++ detect_set_debug_port(); ++ ++ ret = ehci_setup(); ++ if (ret < 0) { ++ dbgp_printk("ehci_setup failed\n"); ++ ehci_debug = 0; ++ ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void early_dbgp_write(struct console *con, const char *str, u32 n) ++{ ++ int chunk, ret; ++ ++ if (!ehci_debug) ++ return; ++ while (n > 0) { ++ chunk = n; ++ if (chunk > DBGP_MAX_PACKET) ++ chunk = DBGP_MAX_PACKET; ++ ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, ++ dbgp_endpoint_out, str, chunk); ++ str += chunk; ++ n -= chunk; ++ } ++} ++ ++static struct console early_dbgp_console = { ++ .name = "earlydbg", ++ .write = early_dbgp_write, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++}; ++#endif ++ + /* Console interface to a host file on AMD's SimNow! */ + + static int simnow_fd; +@@ -165,6 +889,7 @@ enum { + static noinline long simnow(long cmd, long a, long b, long c) + { + long ret; ++ + asm volatile("cpuid" : + "=a" (ret) : + "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); +@@ -174,6 +899,7 @@ static noinline long simnow(long cmd, lo + static void __init simnow_init(char *str) + { + char *fn = "klog"; ++ + if (*str == '=') + fn = ++str; + /* error ignored */ +@@ -208,10 +934,11 @@ asmlinkage void early_printk(const char + va_end(ap); + } + +-static int __initdata keep_early; + + static int __init setup_early_printk(char *buf) + { ++ int keep_early; ++ + if (!buf) + return 0; + +@@ -219,8 +946,7 @@ static int __init setup_early_printk(cha + return 0; + early_console_initialized = 1; + +- if (strstr(buf, "keep")) +- keep_early = 1; ++ keep_early = (strstr(buf, "keep") != NULL); + + if (!strncmp(buf, "serial", 6)) { + early_serial_init(buf + 6); +@@ -238,6 +964,17 @@ static int __init setup_early_printk(cha + simnow_init(buf + 6); + early_console = &simnow_console; + keep_early = 1; ++#ifdef CONFIG_EARLY_PRINTK_DBGP ++ } else if (!strncmp(buf, "dbgp", 4)) { ++ if (early_dbgp_init(buf+4) < 0) ++ return 0; ++ early_console = &early_dbgp_console; ++ /* ++ * usb subsys will reset ehci controller, so don't keep ++ * that early console ++ */ ++ keep_early = 0; ++#endif + #ifdef CONFIG_HVC_XEN + } else if (!strncmp(buf, "xen", 3)) { + early_console = &xenboot_console; +@@ -251,4 +988,23 @@ static int __init setup_early_printk(cha + register_console(early_console); + return 0; + } ++ ++void __init enable_debug_console(char *buf) ++{ ++#ifdef DBGP_DEBUG ++ struct console *old_early_console = NULL; ++ ++ if (early_console_initialized && early_console) { ++ old_early_console = early_console; ++ unregister_console(early_console); ++ early_console_initialized = 0; ++ } ++ ++ setup_early_printk(buf); ++ ++ if (early_console == old_early_console && old_early_console) ++ register_console(old_early_console); ++#endif ++} ++ + early_param("earlyprintk", setup_early_printk); +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -661,11 +661,12 @@ and is between 256 and 4096 characters. + earlyprintk= [X86-32,X86-64,SH,BLACKFIN] + earlyprintk=vga + earlyprintk=serial[,ttySn[,baudrate]] ++ earlyprintk=dbgp + + Append ",keep" to not disable it when the real console + takes over. + +- Only vga or serial at a time, not both. ++ Only vga or serial or usb debug port at a time. + + Currently only ttyS0 and ttyS1 are supported. + diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-account-for-allocated-blocks-when-expanding-directories b/src/patches/suse-2.6.27.31/patches.suse/xfs-account-for-allocated-blocks-when-expanding-directories new file mode 100644 index 000000000..fb3d10112 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-account-for-allocated-blocks-when-expanding-directories @@ -0,0 +1,94 @@ +From: David Chinner +References: bnc#450658 +Subject: [XFS] Account for allocated blocks when expanding directories +Patch-mainline: ? + +When we create a directory, we reserve a number of blocks for the maximum +possible expansion of of the directory due to various btree splits, +freespace allocation, etc. Unfortunately, each allocation is not reflected +in the total number of blocks still available to the transaction, so the +maximal reservation is used over and over again. + +This leads to problems where an allocation group has only enough blocks +for *some* of the allocations required for the directory modification. +After the first N allocations, the remaining blocks in the allocation +group drops below the total reservation, and subsequent allocations fail +because the allocator will not allow the allocation to proceed if the AG +does not have the enough blocks available for the entire allocation total. + +This results in an ENOSPC occurring after an allocation has already +occurred. This results in aborting the directory operation (leaving the +directory in an inconsistent state) and cancelling a dirty transaction, +which results in a filesystem shutdown. + +Avoid the problem by reflecting the number of blocks allocated in any +directory expansion in the total number of blocks available to the +modification in progress. This prevents a directory modification from +being aborted part way through with an ENOSPC. + +SGI-PV: 988144 + +SGI-Modid: xfs-linux-melb:xfs-kern:32340a + +Signed-off-by: David Chinner +Signed-off-by: Lachlan McIlroy +Acked-by: Jan Kara + +diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c +index 9e561a9..a11a839 100644 +--- a/fs/xfs/xfs_da_btree.c ++++ b/fs/xfs/xfs_da_btree.c +@@ -1566,11 +1566,14 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) + int nmap, error, w, count, c, got, i, mapi; + xfs_trans_t *tp; + xfs_mount_t *mp; ++ xfs_drfsbno_t nblks; + + dp = args->dp; + mp = dp->i_mount; + w = args->whichfork; + tp = args->trans; ++ nblks = dp->i_d.di_nblocks; ++ + /* + * For new directories adjust the file offset and block count. + */ +@@ -1647,6 +1650,8 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) + } + if (mapp != &map) + kmem_free(mapp); ++ /* account for newly allocated blocks in reserved blocks total */ ++ args->total -= dp->i_d.di_nblocks - nblks; + *new_blkno = (xfs_dablk_t)bno; + return 0; + } +diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c +index 80e0dc5..1afb122 100644 +--- a/fs/xfs/xfs_dir2.c ++++ b/fs/xfs/xfs_dir2.c +@@ -525,11 +525,13 @@ xfs_dir2_grow_inode( + xfs_mount_t *mp; + int nmap; /* number of bmap entries */ + xfs_trans_t *tp; ++ xfs_drfsbno_t nblks; + + xfs_dir2_trace_args_s("grow_inode", args, space); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; ++ nblks = dp->i_d.di_nblocks; + /* + * Set lowest possible block in the space requested. + */ +@@ -622,7 +624,11 @@ xfs_dir2_grow_inode( + */ + if (mapp != &map) + kmem_free(mapp); ++ ++ /* account for newly allocated blocks in reserved blocks total */ ++ args->total -= dp->i_d.di_nblocks - nblks; + *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); ++ + /* + * Update file's size if this is the data space and it grew. + */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-check-for-valid-transaction-headers-in-recovery b/src/patches/suse-2.6.27.31/patches.suse/xfs-check-for-valid-transaction-headers-in-recovery new file mode 100644 index 000000000..33bed36ce --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-check-for-valid-transaction-headers-in-recovery @@ -0,0 +1,43 @@ +From: David Chinner +Subject: [XFS] XFS: Check for valid transaction headers in recovery +References: bnc#450658 +Patch-mainline: ? + +When we are about to add a new item to a transaction in recovery, we need +to check that it is valid first. Currently we just assert that header +magic number matches, but in production systems that is not present and we +add a corrupted transaction to the list to be processed. This results in a +kernel oops later when processing the corrupted transaction. + +Instead, if we detect a corrupted transaction, abort recovery and leave +the user to clean up the mess that has occurred. + +SGI-PV: 988145 + +SGI-Modid: xfs-linux-melb:xfs-kern:32356a + +Signed-off-by: David Chinner +Signed-off-by: Tim Shimmin +Signed-off-by: Eric Sandeen +Signed-off-by: Lachlan McIlroy +Acked-by: Jan Kara + +Index: linux-2.6.27.5-2/fs/xfs/xfs_log_recover.c +=================================================================== +--- linux-2.6.27.5-2.orig/fs/xfs/xfs_log_recover.c 2008-12-03 11:58:01.136714829 +1100 ++++ linux-2.6.27.5-2/fs/xfs/xfs_log_recover.c 2008-12-03 11:59:11.531741273 +1100 +@@ -1419,7 +1419,13 @@ xlog_recover_add_to_trans( + return 0; + item = trans->r_itemq; + if (item == NULL) { +- ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC); ++ /* we need to catch log corruptions here */ ++ if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { ++ xlog_warn("XFS: xlog_recover_add_to_trans: " ++ "bad header magic number"); ++ ASSERT(0); ++ return XFS_ERROR(EIO); ++ } + if (len == sizeof(xfs_trans_header_t)) + xlog_recover_add_item(&trans->r_itemq); + memcpy(&trans->r_theader, dp, len); /* d, s, l */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-enable b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-enable new file mode 100644 index 000000000..d3b530df7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-enable @@ -0,0 +1,130 @@ +Date: Thu, 09 Oct 2008 17:11:14 +1100 +From: Donald Douwsma +Subject: VFS changes to support DMAPI +Patch-mainline: ? +References: bnc#450658 + +VFS changes to support DMAPI including open_exec(), mprotect() +and build infastructure. + +Acked-by: Jan Kara + +--- + MAINTAINERS | 7 +++++++ + fs/Kconfig | 19 +++++++++++++++++++ + fs/Makefile | 2 ++ + fs/exec.c | 8 ++++++++ + include/linux/fs.h | 2 ++ + include/linux/mm.h | 3 +++ + mm/mprotect.c | 5 +++++ + 7 files changed, 46 insertions(+) + +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -690,6 +690,14 @@ struct file *open_exec(const char *name) + if (IS_ERR(file)) + return file; + ++ if (file->f_op && file->f_op->open_exec) { ++ err = file->f_op->open_exec(nd.path.dentry->d_inode); ++ if (err) { ++ fput(file); ++ goto out; ++ } ++ } ++ + err = deny_write_access(file); + if (err) { + fput(file); +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -557,6 +557,25 @@ config INOTIFY_USER + + If unsure, say Y. + ++config DMAPI ++ tristate "DMAPI support" ++ help ++ The Data Management API is a system interface used to implement ++ the interface defined in the X/Open document: ++ "Systems Management: Data Storage Management (XDSM) API", ++ dated February 1997. This interface is used by hierarchical ++ storage management systems. ++ ++ If any DMAPI-capable filesystem is built into the kernel, then ++ DMAPI must also be built into the kernel. ++ ++config DMAPI_DEBUG ++ bool "DMAPI debugging support" ++ depends on DMAPI ++ help ++ If you don't know whether you need it, then you don't need it: ++ answer N. ++ + config QUOTA + bool "Quota support" + help +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -56,6 +56,8 @@ obj-$(CONFIG_QFMT_V2) += quota_v2.o + obj-$(CONFIG_QUOTA_TREE) += quota_tree.o + obj-$(CONFIG_QUOTACTL) += quota.o + ++obj-$(CONFIG_DMAPI) += dmapi/ ++ + obj-$(CONFIG_DNOTIFY) += dnotify.o + + obj-$(CONFIG_PROC_FS) += proc/ +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1271,6 +1271,8 @@ struct file_operations { + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); ++#define HAVE_FOP_OPEN_EXEC ++ int (*open_exec) (struct inode *); + int (*setlease)(struct file *, long, struct file_lock **); + }; + +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -173,6 +173,9 @@ struct vm_operations_struct { + void (*close)(struct vm_area_struct * area); + int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); + ++#define HAVE_VMOP_MPROTECT ++ int (*mprotect)(struct vm_area_struct * area, unsigned int newflags); ++ + #ifdef __GENKSYMS__ + int (*page_mkwrite)(struct vm_area_struct *, struct page *); + #else +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -4584,6 +4584,13 @@ W: http://oss.sgi.com/projects/xfs + T: git git://oss.sgi.com:8090/xfs/xfs-2.6.git + S: Supported + ++DMAPI ++P: Silicon Graphics Inc ++M: xfs-masters@oss.sgi.com ++L: xfs@oss.sgi.com ++W: http://oss.sgi.com/projects/xfs ++S: Supported ++ + XILINX SYSTEMACE DRIVER + P: Grant Likely + M: grant.likely@secretlab.ca +--- a/mm/mprotect.c ++++ b/mm/mprotect.c +@@ -294,6 +294,11 @@ SYSCALL_DEFINE3(mprotect, unsigned long, + if (error) + goto out; + ++ if (vma->vm_ops && vma->vm_ops->mprotect) { ++ error = vma->vm_ops->mprotect(vma, newflags); ++ if (error < 0) ++ goto out; ++ } + tmp = vma->vm_end; + if (tmp > end) + tmp = end; diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-src b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-src new file mode 100644 index 000000000..ab7b43349 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-src @@ -0,0 +1,10845 @@ +Date: Thu, 09 Oct 2008 17:11:31 +1100 +From: Donald Douwsma +Subject: DMAPI Source +Patch-mainline: ? +References: bnc#450658 + +Acked-by: Jan Kara + +--- + fs/dmapi/Makefile | 53 + + fs/dmapi/Status | 128 +++ + fs/dmapi/dmapi.h | 1086 ++++++++++++++++++++++++++ + fs/dmapi/dmapi_attr.c | 93 ++ + fs/dmapi/dmapi_bulkattr.c | 170 ++++ + fs/dmapi/dmapi_config.c | 117 ++ + fs/dmapi/dmapi_dmattr.c | 228 +++++ + fs/dmapi/dmapi_event.c | 860 +++++++++++++++++++++ + fs/dmapi/dmapi_handle.c | 119 ++ + fs/dmapi/dmapi_hole.c | 119 ++ + fs/dmapi/dmapi_io.c | 142 +++ + fs/dmapi/dmapi_kern.h | 599 ++++++++++++++ + fs/dmapi/dmapi_mountinfo.c | 527 ++++++++++++ + fs/dmapi/dmapi_port.h | 138 +++ + fs/dmapi/dmapi_private.h | 619 +++++++++++++++ + fs/dmapi/dmapi_region.c | 91 ++ + fs/dmapi/dmapi_register.c | 1644 ++++++++++++++++++++++++++++++++++++++++ + fs/dmapi/dmapi_right.c | 1256 ++++++++++++++++++++++++++++++ + fs/dmapi/dmapi_session.c | 1825 +++++++++++++++++++++++++++++++++++++++++++++ + fs/dmapi/dmapi_sysent.c | 805 +++++++++++++++++++ + fs/dmapi/sv.h | 89 ++ + 21 files changed, 10708 insertions(+) + +Index: linux-2.6.26/fs/dmapi/dmapi_attr.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_attr.c +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++/* Retrieve attributes for a single file, directory or symlink. */ ++ ++int ++dm_get_fileattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_stat_t __user *statp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_fileattr(tdp->td_ip, tdp->td_right, ++ mask, statp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++/* Set one or more file attributes of a file, directory, or symlink. */ ++ ++int ++dm_set_fileattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_fileattr_t __user *attrp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->set_fileattr(tdp->td_ip, tdp->td_right, ++ mask, attrp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_bulkattr.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_bulkattr.c +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++int ++dm_init_attrloc( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrloc_t __user *locp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS|DM_TDT_DIR, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->init_attrloc(tdp->td_ip, tdp->td_right, locp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++/* ++ * Retrieves both standard and DM specific file attributes for the file ++ * system indicated by the handle. (The FS has to be mounted). ++ * Syscall returns 1 to indicate SUCCESS and more information is available. ++ * -1 is returned on error, and errno will be set appropriately. ++ * 0 is returned upon successful completion. ++ */ ++ ++int ++dm_get_bulkattr_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_bulkattr_rvp(tdp->td_ip, tdp->td_right, ++ mask, locp, buflen, bufp, rlenp, rvp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++/* ++ * Retrieves attributes of directory entries given a handle to that ++ * directory. Iterative. ++ * Syscall returns 1 to indicate SUCCESS and more information is available. ++ * -1 is returned on error, and errno will be set appropriately. ++ * 0 is returned upon successful completion. ++ */ ++ ++int ++dm_get_dirattrs_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_DIR, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_dirattrs_rvp(tdp->td_ip, tdp->td_right, ++ mask, locp, buflen, bufp, rlenp, rvp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_get_bulkall_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_attrname_t __user *attrnamep, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_bulkall_rvp(tdp->td_ip, tdp->td_right, ++ mask, attrnamep, locp, buflen, bufp, rlenp, rvp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_config.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_config.c +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#include ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++int ++dm_get_config( ++ void __user *hanp, ++ size_t hlen, ++ dm_config_t flagname, ++ dm_size_t __user *retvalp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ dm_size_t retval; ++ int system = 1; ++ int error; ++ ++ /* Trap and process configuration parameters which are system-wide. */ ++ ++ switch (flagname) { ++ case DM_CONFIG_LEGACY: ++ case DM_CONFIG_PENDING: ++ case DM_CONFIG_OBJ_REF: ++ retval = DM_TRUE; ++ break; ++ case DM_CONFIG_MAX_MESSAGE_DATA: ++ retval = DM_MAX_MSG_DATA; ++ break; ++ default: ++ system = 0; ++ break; ++ } ++ if (system) { ++ if (copy_to_user(retvalp, &retval, sizeof(retval))) ++ return(-EFAULT); ++ return(0); ++ } ++ ++ /* Must be filesystem-specific. Convert the handle into an inode. */ ++ ++ if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0) ++ return(error); ++ ++ /* Now call the filesystem-specific routine to determine the ++ value of the configuration option for that filesystem. ++ */ ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_config(tdp->td_ip, tdp->td_right, ++ flagname, retvalp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_get_config_events( ++ void __user *hanp, ++ size_t hlen, ++ u_int nelem, ++ dm_eventset_t __user *eventsetp, ++ u_int __user *nelemp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ /* Convert the handle into an inode. */ ++ ++ if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0) ++ return(error); ++ ++ /* Now call the filesystem-specific routine to determine the ++ events supported by that filesystem. ++ */ ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_config_events(tdp->td_ip, tdp->td_right, ++ nelem, eventsetp, nelemp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_dmattr.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_dmattr.c +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++int ++dm_clear_inherit( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->clear_inherit(tdp->td_ip, tdp->td_right, ++ attrnamep); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_get_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_dmattr(tdp->td_ip, tdp->td_right, ++ attrnamep, buflen, bufp, rlenp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_getall_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->getall_dmattr(tdp->td_ip, tdp->td_right, ++ buflen, bufp, rlenp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_getall_inherit( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int nelem, ++ dm_inherit_t __user *inheritbufp, ++ u_int __user *nelemp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->getall_inherit(tdp->td_ip, tdp->td_right, ++ nelem, inheritbufp, nelemp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_remove_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ int setdtime, ++ dm_attrname_t __user *attrnamep) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->remove_dmattr(tdp->td_ip, tdp->td_right, ++ setdtime, attrnamep); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_set_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ int setdtime, ++ size_t buflen, ++ void __user *bufp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->set_dmattr(tdp->td_ip, tdp->td_right, ++ attrnamep, setdtime, buflen, bufp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_set_inherit( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ mode_t mode) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->set_inherit(tdp->td_ip, tdp->td_right, ++ attrnamep, mode); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_event.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_event.c +@@ -0,0 +1,860 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++/* The "rights" portion of the DMAPI spec is not currently implemented. A ++ framework for rights is provided in the code, but turns out to be a noop ++ in practice. The following comments are a brain dump to serve as input to ++ the poor soul that eventually has to get DMAPI rights working in IRIX. ++ ++ A DMAPI right is similar but not identical to the mrlock_t mechanism ++ already used within the kernel. The similarities are that it is a ++ sleeping lock, and that a multiple-reader, single-writer protocol is used. ++ How locks are obtained and dropped are different however. With a mrlock_t, ++ a thread grabs the lock, does some stuff, then drops the lock, and all other ++ threads block in the meantime (assuming a write lock). There is a one-to- ++ one relationship between the lock and the thread which obtained the lock. ++ Not so with DMAPI right locks. A DMAPI lock is associated with a particular ++ session/token/hanp/hlen quad; since there is a dm_tokdata_t structure for ++ each such quad, you can think of it as a one-to-one relationship between the ++ lock and a dm_tokdata_t. Any application thread which presents the correct ++ quad is entitled to grab or release the lock, or to use the rights ++ associated with that lock. The thread that grabs the lock does not have to ++ be the one to use the lock, nor does it have to be the thread which drops ++ the lock. The lock can be held for very long periods of time, even across ++ multiple systems calls by multiple application threads. The idea is that a ++ coordinated group of DMAPI application threads can grab the lock, issue a ++ series of inode accesses and/or updates, then drop the lock, and be assured ++ that no other thread in the system could be modifying the inode at the same ++ time. The kernel is expected to blindly trust that the application will ++ not forget to unlock inodes it has locked, and will not deadlock itself ++ against the kernel. ++ ++ There are two types of DMAPI rights, file object (inode) and filesystem ++ object (superblock?). An inode right is the equivalent of the combination ++ of both the XFS ilock and iolock; if held exclusively, no data or metadata ++ within the file can be changed by non-lock-holding threads. The filesystem ++ object lock is a little fuzzier; I think that if it is held, things like ++ unmounts can be blocked, plus there is an event mask associated with the ++ filesystem which can't be updated without the lock. (By the way, that ++ event mask is supposed to be persistent in the superblock; add that to ++ your worklist :-) ++ ++ All events generated by XFS currently arrive with no rights, i.e. ++ DM_RIGHT_NULL, and return to the filesystem with no rights. It would be ++ smart to leave it this way if possible, because it otherwise becomes more ++ likely that an application thread will deadlock against the kernel if the ++ one responsible for calling dm_get_events() happens to touch a file which ++ was locked at the time the event was queued. Since the thread is blocked, ++ it can't read the event in order to find and drop the lock. Catch-22. If ++ you do have events that arrive with non-null rights, then dm_enqueue() needs ++ to have code added for synchronous events which atomically switches the ++ right from being a thread-based right to a dm_tokdata_t-based right without ++ allowing the lock to drop in between. You will probably have to add a new ++ dm_fsys_vector entry point to do this. The lock can't be lost during the ++ switch, or other threads might change the inode or superblock in between. ++ Likewise, if you need to return to the filesystem holding a right, then ++ you need a DMAPI-to-thread atomic switch to occur, most likely in ++ dm_change_right(). Again, the lock must not be lost during the switch; the ++ DMAPI spec spends a couple of pages stressing this. Another dm_fsys_vector ++ entry point is probably the answer. ++ ++ There are several assumptions implied in the current layout of the code. ++ First of all, if an event returns to the filesystem with a return value of ++ zero, then the filesystem can assume that any locks (rights) held at the ++ start of the event are still in effect at the end of the event. (Note that ++ the application could have temporarily dropped and reaquired the right ++ while the event was outstanding, however). If the event returns to the ++ filesystem with an errno, then the filesystem must assume that it has lost ++ any and all rights associated with any of the objects in the event. This ++ was done for a couple of reasons. First of all, since an errno is being ++ returned, most likely the filesystem is going to immediately drop all the ++ locks anyway. If the DMAPI code was required to unconditionally reobtain ++ all locks before returning to the filesystem, then dm_pending() wouldn't ++ work for NFS server threads because the process would block indefinitely ++ trying to get its thread-based rights back, because the DMAPI-rights ++ associated with the dm_tokdata_t in the outstanding event would prevent ++ the rights from being obtained. That would be a bad thing. We wouldn't ++ be able to let users Cntl-C out of read/write/truncate events either. ++ ++ If a case should ever surface where the thread has lost its rights even ++ though it has a zero return status, or where the thread has rights even ++ though it is returning with an errno, then this logic will have to be ++ reworked. This could be done by changing the 'right' parameters on all ++ the event calls to (dm_right_t *), so that they could serve both as IN ++ and OUT parameters. ++ ++ Some events such as DM_EVENT_DESTROY arrive without holding an inode ++ reference; if you don't have an inode reference, you can't have a right ++ on the file. ++ ++ One more quirk. The DM_EVENT_UNMOUNT event is defined to be synchronous ++ when it's behavior is asynchronous. If an unmount event arrives with ++ rights, the event should return with the same rights and should NOT leave ++ any rights in the dm_tokdata_t where the application could use them. ++*/ ++ ++ ++#define GETNEXTOFF(vdat) ((vdat).vd_offset + (vdat).vd_length) ++#define HANDLE_SIZE(tdp) \ ++ ((tdp)->td_type & DM_TDT_VFS ? DM_FSHSIZE : DM_HSIZE((tdp)->td_handle)) ++ ++ ++/* Given an inode pointer in a filesystem known to support DMAPI, ++ build a tdp structure for the corresponding inode. ++*/ ++ ++static dm_tokdata_t * ++dm_ip_data( ++ struct inode *ip, ++ dm_right_t right, ++ int referenced) /* != 0, caller holds inode reference */ ++{ ++ int error; ++ dm_tokdata_t *tdp; ++ int filetype; ++ ++ tdp = kmem_cache_alloc(dm_tokdata_cachep, GFP_KERNEL); ++ if (tdp == NULL) { ++ printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return NULL; ++ } ++ ++ tdp->td_next = NULL; ++ tdp->td_tevp = NULL; ++ tdp->td_app_ref = 0; ++ tdp->td_orig_right = right; ++ tdp->td_right = right; ++ tdp->td_flags = DM_TDF_ORIG; ++ if (referenced) { ++ tdp->td_flags |= DM_TDF_EVTREF; ++ } ++ ++ filetype = ip->i_mode & S_IFMT; ++ if (filetype == S_IFREG) { ++ tdp->td_type = DM_TDT_REG; ++ } else if (filetype == S_IFDIR) { ++ tdp->td_type = DM_TDT_DIR; ++ } else if (filetype == S_IFLNK) { ++ tdp->td_type = DM_TDT_LNK; ++ } else { ++ tdp->td_type = DM_TDT_OTH; ++ } ++ ++ if (referenced) { ++ tdp->td_ip = ip; ++ } else { ++ tdp->td_ip = NULL; ++ } ++ tdp->td_vcount = 0; ++ ++ if ((error = dm_ip_to_handle(ip, &tdp->td_handle)) != 0) { ++ panic("dm_ip_data: dm_ip_to_handle failed for ip %p in " ++ "a DMAPI filesystem, errno %d\n", ip, error); ++ } ++ ++ return(tdp); ++} ++ ++ ++/* Given a sb pointer to a filesystem known to support DMAPI, build a tdp ++ structure for that sb. ++*/ ++static dm_tokdata_t * ++dm_sb_data( ++ struct super_block *sb, ++ struct inode *ip, /* will be NULL for DM_EVENT_UNMOUNT */ ++ dm_right_t right) ++{ ++ dm_tokdata_t *tdp; ++ struct filesystem_dmapi_operations *dops; ++ dm_fsid_t fsid; ++ ++ dops = dm_fsys_ops(sb); ++ ASSERT(dops); ++ dops->get_fsid(sb, &fsid); ++ ++ tdp = kmem_cache_alloc(dm_tokdata_cachep, GFP_KERNEL); ++ if (tdp == NULL) { ++ printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return NULL; ++ } ++ ++ tdp->td_next = NULL; ++ tdp->td_tevp = NULL; ++ tdp->td_app_ref = 0; ++ tdp->td_orig_right = right; ++ tdp->td_right = right; ++ tdp->td_flags = DM_TDF_ORIG; ++ if (ip) { ++ tdp->td_flags |= DM_TDF_EVTREF; ++ } ++ tdp->td_type = DM_TDT_VFS; ++ tdp->td_ip = ip; ++ tdp->td_vcount = 0; ++ ++ memcpy(&tdp->td_handle.ha_fsid, &fsid, sizeof(fsid)); ++ memset((char *)&tdp->td_handle.ha_fsid + sizeof(fsid), 0, ++ sizeof(tdp->td_handle) - sizeof(fsid)); ++ ++ return(tdp); ++} ++ ++ ++/* Link a tdp structure into the tevp. */ ++ ++static void ++dm_add_handle_to_event( ++ dm_tokevent_t *tevp, ++ dm_tokdata_t *tdp) ++{ ++ tdp->td_next = tevp->te_tdp; ++ tevp->te_tdp = tdp; ++ tdp->td_tevp = tevp; ++} ++ ++ ++/* Generate the given data event for the inode, and wait for a reply. The ++ caller must guarantee that the inode's reference count is greater than zero ++ so that the filesystem can't disappear while the request is outstanding. ++*/ ++ ++int ++dm_send_data_event( ++ dm_eventtype_t event, ++ struct inode *ip, ++ dm_right_t vp_right, /* current right for ip */ ++ dm_off_t offset, ++ size_t length, ++ int flags) /* 0 or DM_FLAGS_NDELAY */ ++{ ++ dm_data_event_t *datap; ++ dm_tokevent_t *tevp; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ tdp = dm_ip_data(ip, vp_right, /* reference held */ 1); ++ if (tdp == NULL) ++ return -ENOMEM; ++ ++ /* Calculate the size of the event in bytes, create an event structure ++ for it, and insert the file's handle into the event. ++ */ ++ ++ tevp = dm_evt_create_tevp(event, HANDLE_SIZE(tdp), (void **)&datap); ++ if (tevp == NULL) { ++ kmem_cache_free(dm_tokdata_cachep, tdp); ++ return(-ENOMEM); ++ } ++ dm_add_handle_to_event(tevp, tdp); ++ ++ /* Now fill in all the dm_data_event_t fields. */ ++ ++ datap->de_handle.vd_offset = sizeof(*datap); ++ datap->de_handle.vd_length = HANDLE_SIZE(tdp); ++ memcpy((char *)datap + datap->de_handle.vd_offset, &tdp->td_handle, ++ datap->de_handle.vd_length); ++ datap->de_offset = offset; ++ datap->de_length = length; ++ ++ /* Queue the message and wait for the reply. */ ++ ++ error = dm_enqueue_normal_event(ip->i_sb, &tevp, flags); ++ ++ /* If no errors occurred, we must leave with the same rights we had ++ upon entry. If errors occurred, we must leave with no rights. ++ */ ++ ++ dm_evt_rele_tevp(tevp, error); ++ ++ return(error); ++} ++ ++ ++/* Generate the destroy event for the inode and wait until the request has been ++ queued. The caller does not hold an inode reference or a right on the inode, ++ but it must otherwise lock down the inode such that the filesystem can't ++ disappear while the request is waiting to be queued. While waiting to be ++ queued, the inode must not be referenceable either by path or by a call ++ to dm_handle_to_ip(). ++*/ ++ ++int ++dm_send_destroy_event( ++ struct inode *ip, ++ dm_right_t vp_right) /* always DM_RIGHT_NULL */ ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokevent_t *tevp; ++ dm_tokdata_t *tdp; ++ dm_destroy_event_t *destp; ++ dm_attrname_t attrname; ++ char *value; ++ int value_len; ++ int error; ++ ++ tdp = dm_ip_data(ip, vp_right, /* no reference held */ 0); ++ if (tdp == NULL) ++ return -ENOMEM; ++ ++ if ((error = dm_waitfor_destroy_attrname(ip->i_sb, &attrname)) != 0) ++ return(error); ++ ++ /* If a return-on-destroy attribute name exists for this filesystem, ++ see if the object being deleted has this attribute. If the object ++ doesn't have the attribute or if we encounter an error, then send ++ the event without the attribute. ++ */ ++ ++ value_len = -1; /* because zero is a valid attribute length */ ++ if (attrname.an_chars[0] != '\0') { ++ fsys_vector = dm_fsys_vector(ip); ++ error = fsys_vector->get_destroy_dmattr(ip, vp_right, &attrname, ++ &value, &value_len); ++ if (error && error != -ENODATA) ++ return error; ++ } ++ ++ /* Now that we know the size of the attribute value, if any, calculate ++ the size of the event in bytes, create an event structure for it, ++ and insert the handle into the event. ++ */ ++ ++ tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, ++ HANDLE_SIZE(tdp) + (value_len >= 0 ? value_len : 0), ++ (void **)&destp); ++ if (tevp == NULL) { ++ kmem_cache_free(dm_tokdata_cachep, tdp); ++ if (value_len > 0) ++ kfree(value); ++ return(-ENOMEM); ++ } ++ dm_add_handle_to_event(tevp, tdp); ++ ++ /* Now fill in all the dm_destroy_event_t fields. */ ++ ++ destp->ds_handle.vd_offset = sizeof(*destp); ++ destp->ds_handle.vd_length = HANDLE_SIZE(tdp); ++ memcpy((char *)destp + destp->ds_handle.vd_offset, &tdp->td_handle, ++ destp->ds_handle.vd_length); ++ if (value_len >= 0) { ++ destp->ds_attrname = attrname; ++ destp->ds_attrcopy.vd_length = value_len; ++ if (value_len == 0) { ++ destp->ds_attrcopy.vd_offset = 0; ++ } else { ++ destp->ds_attrcopy.vd_offset = GETNEXTOFF(destp->ds_handle); ++ memcpy((char *)destp + destp->ds_attrcopy.vd_offset, value, ++ value_len); ++ kfree(value); ++ } ++ } ++ ++ /* Queue the message asynchronously. */ ++ ++ error = dm_enqueue_normal_event(ip->i_sb, &tevp, 0); ++ ++ /* Since we had no rights upon entry, we have none to reobtain before ++ leaving. ++ */ ++ ++ dm_evt_rele_tevp(tevp, 1); ++ ++ return(error); ++} ++ ++ ++/* The dm_mount_event_t event is sent in turn to all sessions that have asked ++ for it until one either rejects it or accepts it. The filesystem is not ++ going anywhere because the mount is blocked until the event is answered. ++*/ ++ ++int ++dm_send_mount_event( ++ struct super_block *sb, /* filesystem being mounted */ ++ dm_right_t vfsp_right, ++ struct inode *ip, /* mounted on directory */ ++ dm_right_t vp_right, ++ struct inode *rootip, ++ dm_right_t rootvp_right, ++ char *name1, /* mount path */ ++ char *name2) /* filesystem device name */ ++{ ++ int error; ++ dm_tokevent_t *tevp = NULL; ++ dm_tokdata_t *tdp1 = NULL; /* filesystem handle for event */ ++ dm_tokdata_t *tdp2 = NULL; /* file handle for mounted-on dir. */ ++ dm_tokdata_t *tdp3 = NULL; /* file handle for root inode */ ++ dm_mount_event_t *mp; ++ size_t nextoff; ++ ++ /* Convert the sb to a filesystem handle, and ip and rootip into ++ file handles. ip (the mounted-on directory) may not have a handle ++ if it is a different filesystem type which does not support DMAPI. ++ */ ++ ++ tdp1 = dm_sb_data(sb, rootip, vfsp_right); ++ if (tdp1 == NULL) ++ goto out_nomem; ++ ++ if ((ip == NULL) || dm_check_dmapi_ip(ip)) { ++ ip = NULL; /* we are mounting on non-DMAPI FS */ ++ } else { ++ tdp2 = dm_ip_data(ip, vp_right, /* reference held */ 1); ++ if (tdp2 == NULL) ++ goto out_nomem; ++ } ++ ++ tdp3 = dm_ip_data(rootip, rootvp_right, /* reference held */ 1); ++ if (tdp3 == NULL) ++ goto out_nomem; ++ ++ /* Calculate the size of the event in bytes, create an event structure ++ for it, and insert the handles into the event. ++ */ ++ ++ tevp = dm_evt_create_tevp(DM_EVENT_MOUNT, ++ HANDLE_SIZE(tdp1) + (ip ? HANDLE_SIZE(tdp2) : 0) + ++ HANDLE_SIZE(tdp3) + strlen(name1) + 1 + ++ strlen(name2) + 1, (void **)&mp); ++ if (tevp == NULL) ++ goto out_nomem; ++ ++ dm_add_handle_to_event(tevp, tdp1); ++ if (ip) ++ dm_add_handle_to_event(tevp, tdp2); ++ dm_add_handle_to_event(tevp, tdp3); ++ ++ /* Now fill in all the dm_mount_event_t fields. */ ++ ++ mp->me_handle1.vd_offset = sizeof(*mp); ++ mp->me_handle1.vd_length = HANDLE_SIZE(tdp1); ++ memcpy((char *) mp + mp->me_handle1.vd_offset, &tdp1->td_handle, ++ mp->me_handle1.vd_length); ++ nextoff = GETNEXTOFF(mp->me_handle1); ++ ++ if (ip) { ++ mp->me_handle2.vd_offset = nextoff; ++ mp->me_handle2.vd_length = HANDLE_SIZE(tdp2); ++ memcpy((char *)mp + mp->me_handle2.vd_offset, &tdp2->td_handle, ++ mp->me_handle2.vd_length); ++ nextoff = GETNEXTOFF(mp->me_handle2); ++ } ++ ++ mp->me_name1.vd_offset = nextoff; ++ mp->me_name1.vd_length = strlen(name1) + 1; ++ memcpy((char *)mp + mp->me_name1.vd_offset, name1, mp->me_name1.vd_length); ++ nextoff = GETNEXTOFF(mp->me_name1); ++ ++ mp->me_name2.vd_offset = nextoff; ++ mp->me_name2.vd_length = strlen(name2) + 1; ++ memcpy((char *)mp + mp->me_name2.vd_offset, name2, mp->me_name2.vd_length); ++ nextoff = GETNEXTOFF(mp->me_name2); ++ ++ mp->me_roothandle.vd_offset = nextoff; ++ mp->me_roothandle.vd_length = HANDLE_SIZE(tdp3); ++ memcpy((char *)mp + mp->me_roothandle.vd_offset, &tdp3->td_handle, ++ mp->me_roothandle.vd_length); ++ ++ mp->me_mode = (sb->s_flags & MS_RDONLY ? DM_MOUNT_RDONLY : 0); ++ ++ /* Queue the message and wait for the reply. */ ++ ++ error = dm_enqueue_mount_event(sb, tevp); ++ ++ /* If no errors occurred, we must leave with the same rights we had ++ upon entry. If errors occurred, we must leave with no rights. ++ */ ++ ++ dm_evt_rele_tevp(tevp, error); ++ ++ return(error); ++ ++out_nomem: ++ if (tevp) ++ kfree(tevp); ++ if (tdp1) ++ kmem_cache_free(dm_tokdata_cachep, tdp1); ++ if (tdp2) ++ kmem_cache_free(dm_tokdata_cachep, tdp2); ++ if (tdp3) ++ kmem_cache_free(dm_tokdata_cachep, tdp3); ++ return -ENOMEM; ++} ++ ++ ++/* Generate an DM_EVENT_UNMOUNT event and wait for a reply. The 'retcode' ++ field indicates whether this is a successful or unsuccessful unmount. ++ If successful, the filesystem is already unmounted, and any pending handle ++ reference to the filesystem will be failed. If the unmount was ++ unsuccessful, then the filesystem will be placed back into full service. ++ ++ The DM_EVENT_UNMOUNT event should really be asynchronous, because the ++ application has no control over whether or not the unmount succeeds. (The ++ DMAPI spec defined it that way because asynchronous events aren't always ++ guaranteed to be delivered.) ++ ++ Since the filesystem is already unmounted in the successful case, the ++ DM_EVENT_UNMOUNT event can't make available any inode to be used in ++ subsequent sid/hanp/hlen/token calls by the application. The event will ++ hang around until the application does a DM_RESP_CONTINUE, but the handle ++ within the event is unusable by the application. ++*/ ++ ++void ++dm_send_unmount_event( ++ struct super_block *sb, ++ struct inode *ip, /* NULL if unmount successful */ ++ dm_right_t vfsp_right, ++ mode_t mode, ++ int retcode, /* errno, if unmount failed */ ++ int flags) ++{ ++ dm_namesp_event_t *np; ++ dm_tokevent_t *tevp; ++ dm_tokdata_t *tdp1; ++ ++ /* If the unmount failed, put the filesystem back into full service, ++ allowing blocked handle references to finish. If it succeeded, put ++ the filesystem into the DM_STATE_UNMOUNTED state and fail all ++ blocked DM_NO_TOKEN handle accesses. ++ */ ++ ++ if (retcode != 0) { /* unmount was unsuccessful */ ++ dm_change_fsys_entry(sb, DM_STATE_MOUNTED); ++ } else { ++ dm_change_fsys_entry(sb, DM_STATE_UNMOUNTED); ++ } ++ ++ /* If the event wasn't in the filesystem dm_eventset_t, just remove ++ the filesystem from the list of DMAPI filesystems and return. ++ */ ++ ++ if (flags & DM_FLAGS_UNWANTED) { ++ if (retcode == 0) ++ dm_remove_fsys_entry(sb); ++ return; ++ } ++ ++ /* Calculate the size of the event in bytes and allocate zeroed memory ++ for it. ++ */ ++ ++ tdp1 = dm_sb_data(sb, ip, vfsp_right); ++ if (tdp1 == NULL) ++ return; ++ ++ tevp = dm_evt_create_tevp(DM_EVENT_UNMOUNT, HANDLE_SIZE(tdp1), ++ (void **)&np); ++ if (tevp == NULL) { ++ kmem_cache_free(dm_tokdata_cachep, tdp1); ++ return; ++ } ++ ++ dm_add_handle_to_event(tevp, tdp1); ++ ++ /* Now copy in all the dm_namesp_event_t specific fields. */ ++ ++ np->ne_handle1.vd_offset = sizeof(*np); ++ np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); ++ memcpy((char *) np + np->ne_handle1.vd_offset, &tdp1->td_handle, ++ np->ne_handle1.vd_length); ++ np->ne_mode = mode; ++ np->ne_retcode = retcode; ++ ++ /* Since DM_EVENT_UNMOUNT is effectively asynchronous, queue the ++ message and ignore any error return for DM_EVENT_UNMOUNT. ++ */ ++ ++ (void)dm_enqueue_normal_event(sb, &tevp, flags); ++ ++ if (retcode == 0) ++ dm_remove_fsys_entry(sb); ++ ++ dm_evt_rele_tevp(tevp, 0); ++} ++ ++ ++/* Generate the given namespace event and wait for a reply (if synchronous) or ++ until the event has been queued (asynchronous). The caller must guarantee ++ that at least one inode within the filesystem has had its reference count ++ bumped so that the filesystem can't disappear while the event is ++ outstanding. ++*/ ++ ++int ++dm_send_namesp_event( ++ dm_eventtype_t event, ++ struct super_block *sb, /* used by PREUNMOUNT */ ++ struct inode *ip1, ++ dm_right_t vp1_right, ++ struct inode *ip2, ++ dm_right_t vp2_right, ++ const char *name1, ++ const char *name2, ++ mode_t mode, ++ int retcode, ++ int flags) ++{ ++ dm_namesp_event_t *np; ++ dm_tokevent_t *tevp; ++ dm_tokdata_t *tdp1 = NULL; /* primary handle for event */ ++ dm_tokdata_t *tdp2 = NULL; /* additional handle for event */ ++ size_t nextoff; ++ int error; ++ ++ if (sb == NULL) ++ sb = ip1->i_sb; ++ ++ switch (event) { ++ case DM_EVENT_PREUNMOUNT: ++ /* ++ * PREUNMOUNT - Send the file system handle in handle1, ++ * and the handle for the root dir in the second. Otherwise ++ * it's a normal sync message; i.e. succeeds or fails ++ * depending on the app's return code. ++ * ip1 and ip2 are both the root dir of mounted FS ++ * vp1_right is the filesystem right. ++ * vp2_right is the root inode right. ++ */ ++ ++ if (flags & DM_FLAGS_UNWANTED) { ++ dm_change_fsys_entry(sb, DM_STATE_UNMOUNTING); ++ return(0); ++ } ++ if (ip1 == NULL) { ++ /* If preunmount happens after kill_super then ++ * it's too late; there's nothing left with which ++ * to construct an event. ++ */ ++ return(0); ++ } ++ tdp1 = dm_sb_data(sb, ip1, vp1_right); ++ if (tdp1 == NULL) ++ return -ENOMEM; ++ tdp2 = dm_ip_data(ip2, vp2_right, /* reference held */ 1); ++ if (tdp2 == NULL) { ++ kmem_cache_free(dm_tokdata_cachep, tdp1); ++ return -ENOMEM; ++ } ++ break; ++ ++ case DM_EVENT_NOSPACE: ++ /* vp1_right is the filesystem right. */ ++ ++ tdp1 = dm_sb_data(sb, ip1, vp1_right); ++ if (tdp1 == NULL) ++ return -ENOMEM; ++ tdp2 = dm_ip_data(ip2, vp2_right, /* reference held */ 1); /* additional info - not in the spec */ ++ if (tdp2 == NULL) { ++ kmem_cache_free(dm_tokdata_cachep, tdp1); ++ return -ENOMEM; ++ } ++ break; ++ ++ default: ++ /* All other events only pass in inodes and don't require any ++ special cases. ++ */ ++ ++ tdp1 = dm_ip_data(ip1, vp1_right, /* reference held */ 1); ++ if (tdp1 == NULL) ++ return -ENOMEM; ++ if (ip2) { ++ tdp2 = dm_ip_data(ip2, vp2_right, /* reference held */ 1); ++ if (tdp2 == NULL) { ++ kmem_cache_free(dm_tokdata_cachep, tdp1); ++ return -ENOMEM; ++ } ++ } ++ } ++ ++ /* Calculate the size of the event in bytes and allocate zeroed memory ++ for it. ++ */ ++ ++ tevp = dm_evt_create_tevp(event, ++ HANDLE_SIZE(tdp1) + (ip2 ? HANDLE_SIZE(tdp2) : 0) + ++ (name1 ? strlen(name1) + 1 : 0) + ++ (name2 ? strlen(name2) + 1 : 0), (void **)&np); ++ if (tevp == NULL) { ++ if (tdp1) ++ kmem_cache_free(dm_tokdata_cachep, tdp1); ++ if (tdp2) ++ kmem_cache_free(dm_tokdata_cachep, tdp2); ++ return(-ENOMEM); ++ } ++ ++ dm_add_handle_to_event(tevp, tdp1); ++ if (ip2) ++ dm_add_handle_to_event(tevp, tdp2); ++ ++ /* Now copy in all the dm_namesp_event_t specific fields. */ ++ ++ np->ne_handle1.vd_offset = sizeof(*np); ++ np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); ++ memcpy((char *) np + np->ne_handle1.vd_offset, &tdp1->td_handle, ++ np->ne_handle1.vd_length); ++ nextoff = GETNEXTOFF(np->ne_handle1); ++ if (ip2) { ++ np->ne_handle2.vd_offset = nextoff; ++ np->ne_handle2.vd_length = HANDLE_SIZE(tdp2); ++ memcpy((char *)np + np->ne_handle2.vd_offset, &tdp2->td_handle, ++ np->ne_handle2.vd_length); ++ nextoff = GETNEXTOFF(np->ne_handle2); ++ } ++ if (name1) { ++ np->ne_name1.vd_offset = nextoff; ++ np->ne_name1.vd_length = strlen(name1) + 1; ++ memcpy((char *)np + np->ne_name1.vd_offset, name1, ++ np->ne_name1.vd_length); ++ nextoff = GETNEXTOFF(np->ne_name1); ++ } ++ if (name2) { ++ np->ne_name2.vd_offset = nextoff; ++ np->ne_name2.vd_length = strlen(name2) + 1; ++ memcpy((char *)np + np->ne_name2.vd_offset, name2, ++ np->ne_name2.vd_length); ++ } ++ np->ne_mode = mode; ++ np->ne_retcode = retcode; ++ ++ /* Queue the message and wait for the reply. */ ++ ++ error = dm_enqueue_normal_event(sb, &tevp, flags); ++ ++ /* If no errors occurred, we must leave with the same rights we had ++ upon entry. If errors occurred, we must leave with no rights. ++ */ ++ ++ dm_evt_rele_tevp(tevp, error); ++ ++ if (!error && event == DM_EVENT_PREUNMOUNT) { ++ dm_change_fsys_entry(sb, DM_STATE_UNMOUNTING); ++ } ++ ++ return(error); ++} ++ ++ ++/* ++ * Send a message of type "DM_EVENT_USER". Since no inode is involved, we ++ * don't have to worry about rights here. ++ */ ++ ++int ++dm_send_msg( ++ dm_sessid_t targetsid, ++ dm_msgtype_t msgtype, /* SYNC or ASYNC */ ++ size_t buflen, ++ void __user *bufp) ++{ ++ dm_tokevent_t *tevp; ++ int sync; ++ void *msgp; ++ int error; ++ ++ if (buflen > DM_MAX_MSG_DATA) ++ return(-E2BIG); ++ if (msgtype == DM_MSGTYPE_ASYNC) { ++ sync = 0; ++ } else if (msgtype == DM_MSGTYPE_SYNC) { ++ sync = 1; ++ } else { ++ return(-EINVAL); ++ } ++ ++ tevp = dm_evt_create_tevp(DM_EVENT_USER, buflen, (void **)&msgp); ++ if (tevp == NULL) ++ return -ENOMEM; ++ ++ if (buflen && copy_from_user(msgp, bufp, buflen)) { ++ dm_evt_rele_tevp(tevp, 0); ++ return(-EFAULT); ++ } ++ ++ /* Enqueue the request and wait for the reply. */ ++ ++ error = dm_enqueue_sendmsg_event(targetsid, tevp, sync); ++ ++ /* Destroy the tevp and return the reply. (dm_pending is not ++ supported here.) ++ */ ++ ++ dm_evt_rele_tevp(tevp, error); ++ ++ return(error); ++} ++ ++ ++/* ++ * Send a message of type "DM_EVENT_USER". Since no inode is involved, we ++ * don't have to worry about rights here. ++ */ ++ ++int ++dm_create_userevent( ++ dm_sessid_t sid, ++ size_t msglen, ++ void __user *msgdatap, ++ dm_token_t __user *tokenp) /* return token created */ ++{ ++ dm_tokevent_t *tevp; ++ dm_token_t token; ++ int error; ++ void *msgp; ++ ++ if (msglen > DM_MAX_MSG_DATA) ++ return(-E2BIG); ++ ++ tevp = dm_evt_create_tevp(DM_EVENT_USER, msglen, (void **)&msgp); ++ if (tevp == NULL) ++ return(-ENOMEM); ++ ++ if (msglen && copy_from_user(msgp, msgdatap, msglen)) { ++ dm_evt_rele_tevp(tevp, 0); ++ return(-EFAULT); ++ } ++ ++ /* Queue the message. If that didn't work, free the tevp structure. */ ++ ++ if ((error = dm_enqueue_user_event(sid, tevp, &token)) != 0) ++ dm_evt_rele_tevp(tevp, 0); ++ ++ if (!error && copy_to_user(tokenp, &token, sizeof(token))) ++ error = -EFAULT; ++ ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi.h +@@ -0,0 +1,1086 @@ ++/* ++ * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2.1 of the GNU Lesser General Public License ++ * as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this program; if not, write the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, ++ * USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#ifndef __DMAPI_H__ ++#define __DMAPI_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifndef __KERNEL__ ++#include ++#endif ++#include ++ ++#ifndef __user ++#define __user ++#endif ++ ++/************************************************************************** ++ * * ++ * The SGI implementation of DMAPI is based upon the X/Open document * ++ * Systems Management: Data Storage Managment (XDSM) API * ++ * dated February 1997. Not all DMAPI functions and structure fields * ++ * have been implemented. Most importantly, the DMAPI functions * ++ * dm_request_right, dm_release_right, dm_query_right, dm_upgrade_right * ++ * and dm_downgrade_right do not work as described in the specification. * ++ * * ++ * The XFS filesystem currently does not allow its locking mechanisms to * ++ * be externally accessed from user space. While the above-mentioned * ++ * dm_xxx_right functions exist and can be called by applications, they * ++ * always return successfully without actually obtaining any locks * ++ * within the filesystem. * ++ * * ++ * Applications which do not need full rights support and which only * ++ * make dm_xxx_right calls in order to satisfy the input requirements of * ++ * other DMAPI calls should be able to use these routines to avoid * ++ * having to implement special-case code for SGI platforms. Applications * ++ * which truely need the capabilities of a full implementation of rights * ++ * will unfortunately have to come up with alternate software solutions * ++ * until such time as rights can be completely implemented. * ++ * * ++ * Functions and structure fields defined within this file which are not * ++ * supported in the SGI implementation of DMAPI are indicated by comments * ++ * following their definitions such as "not supported", or "not * ++ * completely supported". Any function or field not so marked may be * ++ * assumed to work exactly according to the spec. * ++ * * ++ **************************************************************************/ ++ ++ ++ ++/* The first portion of this file contains defines and typedefs that are ++ DMAPI implementation-dependent, and could be different on other platforms. ++*/ ++ ++typedef __s64 dm_attrloc_t; ++typedef unsigned int dm_boolean_t; ++typedef __u64 dm_eventset_t; ++typedef __u64 dm_fsid_t; ++typedef __u64 dm_ino_t; ++typedef __u32 dm_igen_t; ++typedef __s64 dm_off_t; ++typedef unsigned int dm_sequence_t; ++typedef int dm_sessid_t; ++typedef __u64 dm_size_t; ++typedef __s64 dm_ssize_t; ++typedef int dm_token_t; ++ ++/* XXX dev_t, mode_t, and nlink_t are not the same size in kernel space ++ and user space. This affects the field offsets for dm_stat_t. ++ The following solution is temporary. ++ ++ user space sizes: dev_t=8 mode_t=4 nlink_t=4 ++ kernel space : dev_t=2 mode_t=2 nlink_t=2 ++ ++*/ ++typedef __s64 dm_dev_t; ++typedef int dm_mode_t; ++typedef int dm_nlink_t; ++ ++ ++#define DM_REGION_NOEVENT 0x0 ++#define DM_REGION_READ 0x1 ++#define DM_REGION_WRITE 0x2 ++#define DM_REGION_TRUNCATE 0x4 ++ ++/* Values for the mask argument used with dm_get_fileattr, dm_get_bulkattr, ++ dm_get_dirattrs, and dm_set_fileattr. ++*/ ++ ++#define DM_AT_MODE 0x0001 ++#define DM_AT_UID 0x0002 ++#define DM_AT_GID 0x0004 ++#define DM_AT_ATIME 0x0008 ++#define DM_AT_MTIME 0x0010 ++#define DM_AT_CTIME 0x0020 ++#define DM_AT_SIZE 0x0040 ++#define DM_AT_DTIME 0x0080 ++#define DM_AT_HANDLE 0x0100 ++#define DM_AT_EMASK 0x0200 ++#define DM_AT_PMANR 0x0400 ++#define DM_AT_PATTR 0x0800 ++#define DM_AT_STAT 0x1000 ++#define DM_AT_CFLAG 0x2000 ++ ++#define DM_EV_WAIT 0x1 /* used in dm_get_events() */ ++ ++#define DM_MOUNT_RDONLY 0x1 /* me_mode field in dm_mount_event_t */ ++ ++#define DM_RR_WAIT 0x1 ++ ++#define DM_UNMOUNT_FORCE 0x1 /* ne_mode field in dm_namesp_event_t */ ++ ++#define DM_WRITE_SYNC 0x1 /* used in dm_write_invis() */ ++ ++#define DM_SESSION_INFO_LEN 256 ++#define DM_NO_SESSION 0 ++#define DM_TRUE 1 ++#define DM_FALSE 0 ++#define DM_INVALID_TOKEN 0 ++#define DM_NO_TOKEN (-1) ++#define DM_INVALID_HANP NULL ++#define DM_INVALID_HLEN 0 ++#define DM_GLOBAL_HANP ((void *)(1LL)) ++#define DM_GLOBAL_HLEN ((size_t)(1)) ++#define DM_VER_STR_CONTENTS "SGI DMAPI (XDSM) API, Release 1.1." ++ ++ ++#define DMEV_SET(event_type, event_list) \ ++ ((event_list) |= (1 << (event_type))) ++#define DMEV_CLR(event_type, event_list) \ ++ ((event_list) &= ~(1 << (event_type))) ++#define DMEV_ISSET(event_type, event_list) \ ++ (int)(((event_list) & (1 << (event_type))) != 0) ++#define DMEV_ZERO(event_list) \ ++ (event_list) = 0 ++ ++ ++typedef struct { ++ int vd_offset; /* offset from start of containing struct */ ++ unsigned int vd_length; /* length of data starting at vd_offset */ ++} dm_vardata_t; ++ ++#define DM_GET_VALUE(p, field, type) \ ++ ((type) ((char *)(p) + (p)->field.vd_offset)) ++ ++#define DM_GET_LEN(p, field) \ ++ ((p)->field.vd_length) ++ ++#define DM_STEP_TO_NEXT(p, type) \ ++ ((type) ((p)->_link ? (char *)(p) + (p)->_link : NULL)) ++ ++ ++ ++ ++/* The remainder of this include file contains defines, typedefs, and ++ structures which are strictly defined by the DMAPI 2.3 specification. ++ ++ (The _link field which appears in several structures is an ++ implementation-specific way to implement DM_STEP_TO_NEXT, and ++ should not be referenced directly by application code.) ++*/ ++ ++ ++#define DM_ATTR_NAME_SIZE 8 ++ ++ ++struct dm_attrname { ++ unsigned char an_chars[DM_ATTR_NAME_SIZE]; ++}; ++typedef struct dm_attrname dm_attrname_t; ++ ++ ++struct dm_attrlist { ++ int _link; ++ dm_attrname_t al_name; ++ dm_vardata_t al_data; ++}; ++typedef struct dm_attrlist dm_attrlist_t; ++ ++ ++typedef enum { ++ DM_CONFIG_INVALID, ++ DM_CONFIG_BULKALL, ++ DM_CONFIG_CREATE_BY_HANDLE, ++ DM_CONFIG_DTIME_OVERLOAD, ++ DM_CONFIG_LEGACY, ++ DM_CONFIG_LOCK_UPGRADE, ++ DM_CONFIG_MAX_ATTR_ON_DESTROY, ++ DM_CONFIG_MAX_ATTRIBUTE_SIZE, ++ DM_CONFIG_MAX_HANDLE_SIZE, ++ DM_CONFIG_MAX_MANAGED_REGIONS, ++ DM_CONFIG_MAX_MESSAGE_DATA, ++ DM_CONFIG_OBJ_REF, ++ DM_CONFIG_PENDING, ++ DM_CONFIG_PERS_ATTRIBUTES, ++ DM_CONFIG_PERS_EVENTS, ++ DM_CONFIG_PERS_INHERIT_ATTRIBS, ++ DM_CONFIG_PERS_MANAGED_REGIONS, ++ DM_CONFIG_PUNCH_HOLE, ++ DM_CONFIG_TOTAL_ATTRIBUTE_SPACE, ++ DM_CONFIG_WILL_RETRY ++} dm_config_t; ++ ++ ++struct dm_dioinfo { /* non-standard SGI addition */ ++ unsigned int d_mem; ++ unsigned int d_miniosz; ++ unsigned int d_maxiosz; ++ dm_boolean_t d_dio_only; ++}; ++typedef struct dm_dioinfo dm_dioinfo_t; ++ ++ ++struct dm_dispinfo { ++ int _link; ++ unsigned int di_pad1; /* reserved; do not reference */ ++ dm_vardata_t di_fshandle; ++ dm_eventset_t di_eventset; ++}; ++typedef struct dm_dispinfo dm_dispinfo_t; ++ ++ ++#ifndef HAVE_DM_EVENTTYPE_T ++#define HAVE_DM_EVENTTYPE_T ++typedef enum { ++ DM_EVENT_INVALID = -1, ++ DM_EVENT_CANCEL = 0, /* not supported */ ++ DM_EVENT_MOUNT = 1, ++ DM_EVENT_PREUNMOUNT = 2, ++ DM_EVENT_UNMOUNT = 3, ++ DM_EVENT_DEBUT = 4, /* not supported */ ++ DM_EVENT_CREATE = 5, ++ DM_EVENT_CLOSE = 6, /* not supported */ ++ DM_EVENT_POSTCREATE = 7, ++ DM_EVENT_REMOVE = 8, ++ DM_EVENT_POSTREMOVE = 9, ++ DM_EVENT_RENAME = 10, ++ DM_EVENT_POSTRENAME = 11, ++ DM_EVENT_LINK = 12, ++ DM_EVENT_POSTLINK = 13, ++ DM_EVENT_SYMLINK = 14, ++ DM_EVENT_POSTSYMLINK = 15, ++ DM_EVENT_READ = 16, ++ DM_EVENT_WRITE = 17, ++ DM_EVENT_TRUNCATE = 18, ++ DM_EVENT_ATTRIBUTE = 19, ++ DM_EVENT_DESTROY = 20, ++ DM_EVENT_NOSPACE = 21, ++ DM_EVENT_USER = 22, ++ DM_EVENT_MAX = 23 ++} dm_eventtype_t; ++#endif ++ ++ ++struct dm_eventmsg { ++ int _link; ++ dm_eventtype_t ev_type; ++ dm_token_t ev_token; ++ dm_sequence_t ev_sequence; ++ dm_vardata_t ev_data; ++}; ++typedef struct dm_eventmsg dm_eventmsg_t; ++ ++ ++struct dm_cancel_event { /* not supported */ ++ dm_sequence_t ce_sequence; ++ dm_token_t ce_token; ++}; ++typedef struct dm_cancel_event dm_cancel_event_t; ++ ++ ++struct dm_data_event { ++ dm_vardata_t de_handle; ++ dm_off_t de_offset; ++ dm_size_t de_length; ++}; ++typedef struct dm_data_event dm_data_event_t; ++ ++struct dm_destroy_event { ++ dm_vardata_t ds_handle; ++ dm_attrname_t ds_attrname; ++ dm_vardata_t ds_attrcopy; ++}; ++typedef struct dm_destroy_event dm_destroy_event_t; ++ ++struct dm_mount_event { ++ dm_mode_t me_mode; ++ dm_vardata_t me_handle1; ++ dm_vardata_t me_handle2; ++ dm_vardata_t me_name1; ++ dm_vardata_t me_name2; ++ dm_vardata_t me_roothandle; ++}; ++typedef struct dm_mount_event dm_mount_event_t; ++ ++struct dm_namesp_event { ++ dm_mode_t ne_mode; ++ dm_vardata_t ne_handle1; ++ dm_vardata_t ne_handle2; ++ dm_vardata_t ne_name1; ++ dm_vardata_t ne_name2; ++ int ne_retcode; ++}; ++typedef struct dm_namesp_event dm_namesp_event_t; ++ ++ ++typedef enum { ++ DM_EXTENT_INVALID, ++ DM_EXTENT_RES, ++ DM_EXTENT_HOLE ++} dm_extenttype_t; ++ ++ ++struct dm_extent { ++ dm_extenttype_t ex_type; ++ unsigned int ex_pad1; /* reserved; do not reference */ ++ dm_off_t ex_offset; ++ dm_size_t ex_length; ++}; ++typedef struct dm_extent dm_extent_t; ++ ++struct dm_fileattr { ++ dm_mode_t fa_mode; ++ uid_t fa_uid; ++ gid_t fa_gid; ++ time_t fa_atime; ++ time_t fa_mtime; ++ time_t fa_ctime; ++ time_t fa_dtime; ++ unsigned int fa_pad1; /* reserved; do not reference */ ++ dm_off_t fa_size; ++}; ++typedef struct dm_fileattr dm_fileattr_t; ++ ++ ++struct dm_inherit { /* not supported */ ++ dm_attrname_t ih_name; ++ dm_mode_t ih_filetype; ++}; ++typedef struct dm_inherit dm_inherit_t; ++ ++ ++typedef enum { ++ DM_MSGTYPE_INVALID, ++ DM_MSGTYPE_SYNC, ++ DM_MSGTYPE_ASYNC ++} dm_msgtype_t; ++ ++ ++struct dm_region { ++ dm_off_t rg_offset; ++ dm_size_t rg_size; ++ unsigned int rg_flags; ++ unsigned int rg_pad1; /* reserved; do not reference */ ++}; ++typedef struct dm_region dm_region_t; ++ ++ ++typedef enum { ++ DM_RESP_INVALID, ++ DM_RESP_CONTINUE, ++ DM_RESP_ABORT, ++ DM_RESP_DONTCARE ++} dm_response_t; ++ ++ ++#ifndef HAVE_DM_RIGHT_T ++#define HAVE_DM_RIGHT_T ++typedef enum { ++ DM_RIGHT_NULL, ++ DM_RIGHT_SHARED, ++ DM_RIGHT_EXCL ++} dm_right_t; ++#endif ++ ++ ++struct dm_stat { ++ int _link; ++ dm_vardata_t dt_handle; ++ dm_vardata_t dt_compname; ++ int dt_nevents; ++ dm_eventset_t dt_emask; ++ int dt_pers; /* field not supported */ ++ int dt_pmanreg; ++ time_t dt_dtime; ++ unsigned int dt_change; /* field not supported */ ++ unsigned int dt_pad1; /* reserved; do not reference */ ++ dm_dev_t dt_dev; ++ dm_ino_t dt_ino; ++ dm_mode_t dt_mode; ++ dm_nlink_t dt_nlink; ++ uid_t dt_uid; ++ gid_t dt_gid; ++ dm_dev_t dt_rdev; ++ unsigned int dt_pad2; /* reserved; do not reference */ ++ dm_off_t dt_size; ++ time_t dt_atime; ++ time_t dt_mtime; ++ time_t dt_ctime; ++ unsigned int dt_blksize; ++ dm_size_t dt_blocks; ++ ++ /* Non-standard filesystem-specific fields. Currently XFS is the only ++ supported filesystem type. ++ */ ++ ++ __u64 dt_pad3; /* reserved; do not reference */ ++ int dt_fstype; /* filesystem index; see sysfs(2) */ ++ union { ++ struct { ++ dm_igen_t igen; ++ unsigned int xflags; ++ unsigned int extsize; ++ unsigned int extents; ++ unsigned short aextents; ++ unsigned short dmstate; ++ } sgi_xfs; ++ } fsys_dep; ++}; ++typedef struct dm_stat dm_stat_t; ++ ++#define dt_xfs_igen fsys_dep.sgi_xfs.igen ++#define dt_xfs_xflags fsys_dep.sgi_xfs.xflags ++#define dt_xfs_extsize fsys_dep.sgi_xfs.extsize ++#define dt_xfs_extents fsys_dep.sgi_xfs.extents ++#define dt_xfs_aextents fsys_dep.sgi_xfs.aextents ++#define dt_xfs_dmstate fsys_dep.sgi_xfs.dmstate ++ ++/* Flags for the non-standard dt_xfs_xflags field. */ ++ ++#define DM_XFLAG_REALTIME 0x00000001 ++#define DM_XFLAG_PREALLOC 0x00000002 ++#define DM_XFLAG_IMMUTABLE 0x00000008 ++#define DM_XFLAG_APPEND 0x00000010 ++#define DM_XFLAG_SYNC 0x00000020 ++#define DM_XFLAG_NOATIME 0x00000040 ++#define DM_XFLAG_NODUMP 0x00000080 ++#define DM_XFLAG_HASATTR 0x80000000 ++ ++ ++struct dm_timestruct { ++ time_t dm_tv_sec; ++ int dm_tv_nsec; ++}; ++typedef struct dm_timestruct dm_timestruct_t; ++ ++ ++struct dm_xstat { /* not supported */ ++ dm_stat_t dx_statinfo; ++ dm_vardata_t dx_attrdata; ++}; ++typedef struct dm_xstat dm_xstat_t; ++ ++ ++#define MAXDMFSFIDSZ 46 ++ ++struct dm_fid { ++ __u16 dm_fid_len; /* length of remainder */ ++ __u16 dm_fid_pad; ++ __u32 dm_fid_gen; /* generation number */ ++ __u64 dm_fid_ino; /* 64 bits inode number */ ++}; ++typedef struct dm_fid dm_fid_t; ++ ++ ++struct dm_handle { ++ union { ++ __s64 align; /* force alignment of ha_fid */ ++ dm_fsid_t _ha_fsid; /* unique file system identifier */ ++ } ha_u; ++ dm_fid_t ha_fid; /* file system specific file ID */ ++}; ++typedef struct dm_handle dm_handle_t; ++#define ha_fsid ha_u._ha_fsid ++ ++#define DM_HSIZE(handle) (((char *) &(handle).ha_fid.dm_fid_pad \ ++ - (char *) &(handle)) \ ++ + (handle).ha_fid.dm_fid_len) ++ ++#define DM_HANDLE_CMP(h1, h2) memcmp(h1, h2, sizeof(dm_handle_t)) ++ ++#define DM_FSHSIZE sizeof(dm_fsid_t) ++ ++ ++/* The following list provides the prototypes for all functions defined in ++ the DMAPI interface. ++*/ ++ ++extern int ++dm_clear_inherit( /* not supported */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep); ++ ++extern int ++dm_create_by_handle( /* not supported */ ++ dm_sessid_t sid, ++ void __user *dirhanp, ++ size_t dirhlen, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname); ++ ++extern int ++dm_create_session( ++ dm_sessid_t oldsid, ++ char __user *sessinfop, ++ dm_sessid_t __user *newsidp); ++ ++extern int ++dm_create_userevent( ++ dm_sessid_t sid, ++ size_t msglen, ++ void __user *msgdatap, ++ dm_token_t __user *tokenp); ++ ++extern int ++dm_destroy_session( ++ dm_sessid_t sid); ++ ++extern int ++dm_downgrade_right( /* not completely supported; see caveat above */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++extern int ++dm_fd_to_handle( ++ int fd, ++ void **hanpp, ++ size_t *hlenp); ++ ++extern int ++dm_find_eventmsg( ++ dm_sessid_t sid, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern int ++dm_get_allocinfo( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t *offp, ++ unsigned int nelem, ++ dm_extent_t *extentp, ++ unsigned int *nelemp); ++ ++extern int ++dm_get_bulkall( /* not supported */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int mask, ++ dm_attrname_t *attrnamep, ++ dm_attrloc_t *locp, ++ size_t buflen, ++ void *bufp, ++ size_t *rlenp); ++ ++extern int ++dm_get_bulkattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int mask, ++ dm_attrloc_t *locp, ++ size_t buflen, ++ void *bufp, ++ size_t *rlenp); ++ ++extern int ++dm_get_config( ++ void __user *hanp, ++ size_t hlen, ++ dm_config_t flagname, ++ dm_size_t __user *retvalp); ++ ++extern int ++dm_get_config_events( ++ void __user *hanp, ++ size_t hlen, ++ unsigned int nelem, ++ dm_eventset_t __user *eventsetp, ++ unsigned int __user *nelemp); ++ ++extern int ++dm_get_dirattrs( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int mask, ++ dm_attrloc_t *locp, ++ size_t buflen, ++ void *bufp, ++ size_t *rlenp); ++ ++extern int ++dm_get_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern int ++dm_get_eventlist( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int nelem, ++ dm_eventset_t __user *eventsetp, ++ unsigned int __user *nelemp); ++ ++extern int ++dm_get_events( ++ dm_sessid_t sid, ++ unsigned int maxmsgs, ++ unsigned int flags, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern int ++dm_get_fileattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int mask, ++ dm_stat_t __user *statp); ++ ++extern int ++dm_get_mountinfo( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern int ++dm_get_region( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int nelem, ++ dm_region_t __user *regbufp, ++ unsigned int __user *nelemp); ++ ++extern int ++dm_getall_disp( ++ dm_sessid_t sid, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern int ++dm_getall_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern int ++dm_getall_inherit( /* not supported */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int nelem, ++ dm_inherit_t __user *inheritbufp, ++ unsigned int __user *nelemp); ++ ++extern int ++dm_getall_sessions( ++ unsigned int nelem, ++ dm_sessid_t __user *sidbufp, ++ unsigned int __user *nelemp); ++ ++extern int ++dm_getall_tokens( ++ dm_sessid_t sid, ++ unsigned int nelem, ++ dm_token_t __user *tokenbufp, ++ unsigned int __user *nelemp); ++ ++extern int ++dm_handle_cmp( ++ void *hanp1, ++ size_t hlen1, ++ void *hanp2, ++ size_t hlen2); ++ ++extern void ++dm_handle_free( ++ void *hanp, ++ size_t hlen); ++ ++extern u_int ++dm_handle_hash( ++ void *hanp, ++ size_t hlen); ++ ++extern dm_boolean_t ++dm_handle_is_valid( ++ void *hanp, ++ size_t hlen); ++ ++extern int ++dm_handle_to_fshandle( ++ void *hanp, ++ size_t hlen, ++ void **fshanpp, ++ size_t *fshlenp); ++ ++extern int ++dm_handle_to_fsid( ++ void *hanp, ++ size_t hlen, ++ dm_fsid_t *fsidp); ++ ++extern int ++dm_handle_to_igen( ++ void *hanp, ++ size_t hlen, ++ dm_igen_t *igenp); ++ ++extern int ++dm_handle_to_ino( ++ void *hanp, ++ size_t hlen, ++ dm_ino_t *inop); ++ ++extern int ++dm_handle_to_path( ++ void *dirhanp, ++ size_t dirhlen, ++ void *targhanp, ++ size_t targhlen, ++ size_t buflen, ++ char *pathbufp, ++ size_t *rlenp); ++ ++extern int ++dm_init_attrloc( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrloc_t __user *locp); ++ ++extern int ++dm_init_service( ++ char **versionstrpp); ++ ++extern int ++dm_make_handle( ++ dm_fsid_t *fsidp, ++ dm_ino_t *inop, ++ dm_igen_t *igenp, ++ void **hanpp, ++ size_t *hlenp); ++ ++extern int ++dm_make_fshandle( ++ dm_fsid_t *fsidp, ++ void **hanpp, ++ size_t *hlenp); ++ ++extern int ++dm_mkdir_by_handle( /* not supported */ ++ dm_sessid_t sid, ++ void __user *dirhanp, ++ size_t dirhlen, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname); ++ ++extern int ++dm_move_event( ++ dm_sessid_t srcsid, ++ dm_token_t token, ++ dm_sessid_t targetsid, ++ dm_token_t __user *rtokenp); ++ ++extern int ++dm_obj_ref_hold( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen); ++ ++extern int ++dm_obj_ref_query( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void *hanp, ++ size_t hlen); ++ ++extern int ++dm_obj_ref_rele( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen); ++ ++extern int ++dm_path_to_fshandle( ++ char *path, ++ void **hanpp, ++ size_t *hlenp); ++ ++extern int ++dm_path_to_handle( ++ char *path, ++ void **hanpp, ++ size_t *hlenp); ++ ++extern int ++dm_pending( ++ dm_sessid_t sid, ++ dm_token_t token, ++ dm_timestruct_t __user *delay); ++ ++extern int ++dm_probe_hole( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len, ++ dm_off_t __user *roffp, ++ dm_size_t __user *rlenp); ++ ++extern int ++dm_punch_hole( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len); ++ ++extern int ++dm_query_right( /* not completely supported; see caveat above */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_right_t __user *rightp); ++ ++extern int ++dm_query_session( ++ dm_sessid_t sid, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++extern dm_ssize_t ++dm_read_invis( ++ dm_sessid_t sid, ++ void *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len, ++ void *bufp); ++ ++extern int ++dm_release_right( /* not completely supported; see caveat above */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++extern int ++dm_remove_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ int setdtime, ++ dm_attrname_t __user *attrnamep); ++ ++extern int ++dm_request_right( /* not completely supported; see caveat above */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int flags, ++ dm_right_t right); ++ ++extern int ++dm_respond_event( ++ dm_sessid_t sid, ++ dm_token_t token, ++ dm_response_t response, ++ int reterror, ++ size_t buflen, ++ void __user *respbufp); ++ ++extern int ++dm_send_msg( ++ dm_sessid_t targetsid, ++ dm_msgtype_t msgtype, ++ size_t buflen, ++ void __user *bufp); ++ ++extern int ++dm_set_disp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_eventset_t __user *eventsetp, ++ unsigned int maxevent); ++ ++extern int ++dm_set_dmattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ int setdtime, ++ size_t buflen, ++ void __user *bufp); ++ ++extern int ++dm_set_eventlist( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_eventset_t __user *eventsetp, ++ unsigned int maxevent); ++ ++extern int ++dm_set_fileattr( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int mask, ++ dm_fileattr_t __user *attrp); ++ ++extern int ++dm_set_inherit( /* not supported */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ mode_t mode); ++ ++extern int ++dm_set_region( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ unsigned int nelem, ++ dm_region_t __user *regbufp, ++ dm_boolean_t __user *exactflagp); ++ ++extern int ++dm_set_return_on_destroy( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ dm_boolean_t enable); ++ ++extern int ++dm_symlink_by_handle( /* not supported */ ++ dm_sessid_t sid, ++ void __user *dirhanp, ++ size_t dirhlen, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname, ++ char __user *path); ++ ++extern int ++dm_sync_by_handle( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++extern int ++dm_upgrade_right( /* not completely supported; see caveat above */ ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++extern dm_ssize_t ++dm_write_invis( ++ dm_sessid_t sid, ++ void *hanp, ++ size_t hlen, ++ dm_token_t token, ++ int flags, ++ dm_off_t off, ++ dm_size_t len, ++ void *bufp); ++ ++/* Non-standard SGI additions to the DMAPI interface. */ ++ ++int ++dm_open_by_handle( ++ void __user *hanp, ++ size_t hlen, ++ int mode); ++ ++extern int ++dm_get_dioinfo( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_dioinfo_t __user *diop); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __DMAPI_H__ */ +Index: linux-2.6.26/fs/dmapi/dmapi_handle.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_handle.c +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++int ++dm_create_by_handle( ++ dm_sessid_t sid, ++ void __user *dirhanp, ++ size_t dirhlen, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->create_by_handle(tdp->td_ip, tdp->td_right, ++ hanp, hlen, cname); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_mkdir_by_handle( ++ dm_sessid_t sid, ++ void __user *dirhanp, ++ size_t dirhlen, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->mkdir_by_handle(tdp->td_ip, tdp->td_right, ++ hanp, hlen, cname); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_symlink_by_handle( ++ dm_sessid_t sid, ++ void __user *dirhanp, ++ size_t dirhlen, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname, ++ char __user *path) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->symlink_by_handle(tdp->td_ip, tdp->td_right, ++ hanp, hlen, cname, path); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_hole.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_hole.c +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++int ++dm_get_allocinfo_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t __user *offp, ++ u_int nelem, ++ dm_extent_t __user *extentp, ++ u_int __user *nelemp, ++ int *rvp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_allocinfo_rvp(tdp->td_ip, tdp->td_right, ++ offp, nelem, extentp, nelemp, rvp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_probe_hole( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len, ++ dm_off_t __user *roffp, ++ dm_size_t __user *rlenp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->probe_hole(tdp->td_ip, tdp->td_right, ++ off, len, roffp, rlenp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_punch_hole( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->punch_hole(tdp->td_ip, tdp->td_right, off, len); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_io.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_io.c +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++int ++dm_read_invis_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->read_invis_rvp(tdp->td_ip, tdp->td_right, ++ off, len, bufp, rvp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_write_invis_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ int flags, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->write_invis_rvp(tdp->td_ip, tdp->td_right, ++ flags, off, len, bufp, rvp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_sync_by_handle ( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->sync_by_handle(tdp->td_ip, tdp->td_right); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_get_dioinfo ( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_dioinfo_t __user *diop) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_dioinfo(tdp->td_ip, tdp->td_right, diop); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_kern.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_kern.h +@@ -0,0 +1,599 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#ifndef __DMAPI_KERN_H__ ++#define __DMAPI_KERN_H__ ++ ++#include ++ ++union sys_dmapi_uarg { ++ void *p; ++ __u64 u; ++}; ++typedef union sys_dmapi_uarg sys_dmapi_u; ++ ++struct sys_dmapi_args { ++ sys_dmapi_u uarg1, uarg2, uarg3, uarg4, uarg5, uarg6, uarg7, uarg8, ++ uarg9, uarg10, uarg11; ++}; ++typedef struct sys_dmapi_args sys_dmapi_args_t; ++ ++#define DM_Uarg(uap,i) uap->uarg##i.u ++#define DM_Parg(uap,i) uap->uarg##i.p ++ ++#ifdef __KERNEL__ ++ ++struct dm_handle_t; ++ ++/* The first group of definitions and prototypes define the filesystem's ++ interface into the DMAPI code. ++*/ ++ ++ ++/* Definitions used for the flags field on dm_send_data_event(), ++ dm_send_unmount_event(), and dm_send_namesp_event() calls. ++*/ ++ ++#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ ++#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ ++ ++/* Possible code levels reported by dm_code_level(). */ ++ ++#define DM_CLVL_INIT 0 /* DMAPI prior to X/Open compliance */ ++#define DM_CLVL_XOPEN 1 /* X/Open compliant DMAPI */ ++ ++ ++/* ++ * Filesystem operations accessed by the DMAPI core. ++ */ ++struct filesystem_dmapi_operations { ++ int (*get_fsys_vector)(struct super_block *sb, void *addr); ++ int (*fh_to_inode)(struct super_block *sb, struct inode **ip, ++ dm_fid_t *fid); ++ const struct file_operations * (*get_invis_ops)(struct inode *ip); ++ int (*inode_to_fh)(struct inode *ip, dm_fid_t *fid, ++ dm_fsid_t *fsid ); ++ void (*get_fsid)(struct super_block *sb, dm_fsid_t *fsid); ++#define HAVE_DM_QUEUE_FLUSH ++ int (*flushing)(struct inode *ip); ++}; ++ ++ ++/* Prototypes used outside of the DMI module/directory. */ ++ ++int dm_send_data_event( ++ dm_eventtype_t event, ++ struct inode *ip, ++ dm_right_t vp_right, ++ dm_off_t off, ++ size_t len, ++ int flags); ++ ++int dm_send_destroy_event( ++ struct inode *ip, ++ dm_right_t vp_right); ++ ++int dm_send_mount_event( ++ struct super_block *sb, ++ dm_right_t vfsp_right, ++ struct inode *ip, ++ dm_right_t vp_right, ++ struct inode *rootip, ++ dm_right_t rootvp_right, ++ char *name1, ++ char *name2); ++ ++int dm_send_namesp_event( ++ dm_eventtype_t event, ++ struct super_block *sb, ++ struct inode *ip1, ++ dm_right_t vp1_right, ++ struct inode *ip2, ++ dm_right_t vp2_right, ++ const char *name1, ++ const char *name2, ++ mode_t mode, ++ int retcode, ++ int flags); ++ ++void dm_send_unmount_event( ++ struct super_block *sbp, ++ struct inode *ip, ++ dm_right_t sbp_right, ++ mode_t mode, ++ int retcode, ++ int flags); ++ ++int dm_code_level(void); ++ ++int dm_ip_to_handle ( ++ struct inode *ip, ++ dm_handle_t *handlep); ++ ++#define HAVE_DM_RELEASE_THREADS_ERRNO ++int dm_release_threads( ++ struct super_block *sb, ++ struct inode *inode, ++ int errno); ++ ++void dmapi_register( ++ struct file_system_type *fstype, ++ struct filesystem_dmapi_operations *dmapiops); ++ ++void dmapi_unregister( ++ struct file_system_type *fstype); ++ ++int dmapi_registered( ++ struct file_system_type *fstype, ++ struct filesystem_dmapi_operations **dmapiops); ++ ++ ++/* The following prototypes and definitions are used by DMAPI as its ++ interface into the filesystem code. Communication between DMAPI and the ++ filesystem are established as follows: ++ 1. DMAPI uses the VFS_DMAPI_FSYS_VECTOR to ask for the addresses ++ of all the functions within the filesystem that it may need to call. ++ 2. The filesystem returns an array of function name/address pairs which ++ DMAPI builds into a function vector. ++ The VFS_DMAPI_FSYS_VECTOR call is only made one time for a particular ++ filesystem type. From then on, DMAPI uses its function vector to call the ++ filesystem functions directly. Functions in the array which DMAPI doesn't ++ recognize are ignored. A dummy function which returns ENOSYS is used for ++ any function that DMAPI needs but which was not provided by the filesystem. ++ If XFS doesn't recognize the VFS_DMAPI_FSYS_VECTOR, DMAPI assumes that it ++ doesn't have the X/Open support code; in this case DMAPI uses the XFS-code ++ originally bundled within DMAPI. ++ ++ The goal of this interface is allow incremental changes to be made to ++ both the filesystem and to DMAPI while minimizing inter-patch dependencies, ++ and to eventually allow DMAPI to support multiple filesystem types at the ++ same time should that become necessary. ++*/ ++ ++typedef enum { ++ DM_FSYS_CLEAR_INHERIT = 0, ++ DM_FSYS_CREATE_BY_HANDLE = 1, ++ DM_FSYS_DOWNGRADE_RIGHT = 2, ++ DM_FSYS_GET_ALLOCINFO_RVP = 3, ++ DM_FSYS_GET_BULKALL_RVP = 4, ++ DM_FSYS_GET_BULKATTR_RVP = 5, ++ DM_FSYS_GET_CONFIG = 6, ++ DM_FSYS_GET_CONFIG_EVENTS = 7, ++ DM_FSYS_GET_DESTROY_DMATTR = 8, ++ DM_FSYS_GET_DIOINFO = 9, ++ DM_FSYS_GET_DIRATTRS_RVP = 10, ++ DM_FSYS_GET_DMATTR = 11, ++ DM_FSYS_GET_EVENTLIST = 12, ++ DM_FSYS_GET_FILEATTR = 13, ++ DM_FSYS_GET_REGION = 14, ++ DM_FSYS_GETALL_DMATTR = 15, ++ DM_FSYS_GETALL_INHERIT = 16, ++ DM_FSYS_INIT_ATTRLOC = 17, ++ DM_FSYS_MKDIR_BY_HANDLE = 18, ++ DM_FSYS_PROBE_HOLE = 19, ++ DM_FSYS_PUNCH_HOLE = 20, ++ DM_FSYS_READ_INVIS_RVP = 21, ++ DM_FSYS_RELEASE_RIGHT = 22, ++ DM_FSYS_REMOVE_DMATTR = 23, ++ DM_FSYS_REQUEST_RIGHT = 24, ++ DM_FSYS_SET_DMATTR = 25, ++ DM_FSYS_SET_EVENTLIST = 26, ++ DM_FSYS_SET_FILEATTR = 27, ++ DM_FSYS_SET_INHERIT = 28, ++ DM_FSYS_SET_REGION = 29, ++ DM_FSYS_SYMLINK_BY_HANDLE = 30, ++ DM_FSYS_SYNC_BY_HANDLE = 31, ++ DM_FSYS_UPGRADE_RIGHT = 32, ++ DM_FSYS_WRITE_INVIS_RVP = 33, ++ DM_FSYS_OBJ_REF_HOLD = 34, ++ DM_FSYS_MAX = 35 ++} dm_fsys_switch_t; ++ ++ ++#define DM_FSYS_OBJ 0x1 /* object refers to a fsys handle */ ++ ++ ++/* ++ * Prototypes for filesystem-specific functions. ++ */ ++ ++typedef int (*dm_fsys_clear_inherit_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep); ++ ++typedef int (*dm_fsys_create_by_handle_t)( ++ struct inode *ip, ++ dm_right_t right, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname); ++ ++typedef int (*dm_fsys_downgrade_right_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int type); /* DM_FSYS_OBJ or zero */ ++ ++typedef int (*dm_fsys_get_allocinfo_rvp_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_off_t __user *offp, ++ u_int nelem, ++ dm_extent_t __user *extentp, ++ u_int __user *nelemp, ++ int *rvalp); ++ ++typedef int (*dm_fsys_get_bulkall_rvp_t)( ++ struct inode *ip, /* root inode */ ++ dm_right_t right, ++ u_int mask, ++ dm_attrname_t __user *attrnamep, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvalp); ++ ++typedef int (*dm_fsys_get_bulkattr_rvp_t)( ++ struct inode *ip, /* root inode */ ++ dm_right_t right, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvalp); ++ ++typedef int (*dm_fsys_get_config_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_config_t flagname, ++ dm_size_t __user *retvalp); ++ ++typedef int (*dm_fsys_get_config_events_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int nelem, ++ dm_eventset_t __user *eventsetp, ++ u_int __user *nelemp); ++ ++typedef int (*dm_fsys_get_destroy_dmattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_attrname_t *attrnamep, ++ char **valuepp, ++ int *vlenp); ++ ++typedef int (*dm_fsys_get_dioinfo_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_dioinfo_t __user *diop); ++ ++typedef int (*dm_fsys_get_dirattrs_rvp_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvalp); ++ ++typedef int (*dm_fsys_get_dmattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++typedef int (*dm_fsys_get_eventlist_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int type, ++ u_int nelem, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int *nelemp); /* in kernel space! */ ++ ++typedef int (*dm_fsys_get_fileattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int mask, ++ dm_stat_t __user *statp); ++ ++typedef int (*dm_fsys_get_region_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int nelem, ++ dm_region_t __user *regbufp, ++ u_int __user *nelemp); ++ ++typedef int (*dm_fsys_getall_dmattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++typedef int (*dm_fsys_getall_inherit_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int nelem, ++ dm_inherit_t __user *inheritbufp, ++ u_int __user *nelemp); ++ ++typedef int (*dm_fsys_init_attrloc_t)( ++ struct inode *ip, /* sometimes root inode */ ++ dm_right_t right, ++ dm_attrloc_t __user *locp); ++ ++typedef int (*dm_fsys_mkdir_by_handle_t)( ++ struct inode *ip, ++ dm_right_t right, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname); ++ ++typedef int (*dm_fsys_probe_hole_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_off_t off, ++ dm_size_t len, ++ dm_off_t __user *roffp, ++ dm_size_t __user *rlenp); ++ ++typedef int (*dm_fsys_punch_hole_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_off_t off, ++ dm_size_t len); ++ ++typedef int (*dm_fsys_read_invis_rvp_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp); ++ ++typedef int (*dm_fsys_release_right_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int type); ++ ++typedef int (*dm_fsys_remove_dmattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ int setdtime, ++ dm_attrname_t __user *attrnamep); ++ ++typedef int (*dm_fsys_request_right_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int type, /* DM_FSYS_OBJ or zero */ ++ u_int flags, ++ dm_right_t newright); ++ ++typedef int (*dm_fsys_set_dmattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep, ++ int setdtime, ++ size_t buflen, ++ void __user *bufp); ++ ++typedef int (*dm_fsys_set_eventlist_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int type, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int maxevent); ++ ++typedef int (*dm_fsys_set_fileattr_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int mask, ++ dm_fileattr_t __user *attrp); ++ ++typedef int (*dm_fsys_set_inherit_t)( ++ struct inode *ip, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep, ++ mode_t mode); ++ ++typedef int (*dm_fsys_set_region_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int nelem, ++ dm_region_t __user *regbufp, ++ dm_boolean_t __user *exactflagp); ++ ++typedef int (*dm_fsys_symlink_by_handle_t)( ++ struct inode *ip, ++ dm_right_t right, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname, ++ char __user *path); ++ ++typedef int (*dm_fsys_sync_by_handle_t)( ++ struct inode *ip, ++ dm_right_t right); ++ ++typedef int (*dm_fsys_upgrade_right_t)( ++ struct inode *ip, ++ dm_right_t right, ++ u_int type); /* DM_FSYS_OBJ or zero */ ++ ++typedef int (*dm_fsys_write_invis_rvp_t)( ++ struct inode *ip, ++ dm_right_t right, ++ int flags, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp); ++ ++typedef void (*dm_fsys_obj_ref_hold_t)( ++ struct inode *ip); ++ ++ ++/* Structure definitions used by the VFS_DMAPI_FSYS_VECTOR call. */ ++ ++typedef struct { ++ dm_fsys_switch_t func_no; /* function number */ ++ union { ++ dm_fsys_clear_inherit_t clear_inherit; ++ dm_fsys_create_by_handle_t create_by_handle; ++ dm_fsys_downgrade_right_t downgrade_right; ++ dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; ++ dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; ++ dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; ++ dm_fsys_get_config_t get_config; ++ dm_fsys_get_config_events_t get_config_events; ++ dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; ++ dm_fsys_get_dioinfo_t get_dioinfo; ++ dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; ++ dm_fsys_get_dmattr_t get_dmattr; ++ dm_fsys_get_eventlist_t get_eventlist; ++ dm_fsys_get_fileattr_t get_fileattr; ++ dm_fsys_get_region_t get_region; ++ dm_fsys_getall_dmattr_t getall_dmattr; ++ dm_fsys_getall_inherit_t getall_inherit; ++ dm_fsys_init_attrloc_t init_attrloc; ++ dm_fsys_mkdir_by_handle_t mkdir_by_handle; ++ dm_fsys_probe_hole_t probe_hole; ++ dm_fsys_punch_hole_t punch_hole; ++ dm_fsys_read_invis_rvp_t read_invis_rvp; ++ dm_fsys_release_right_t release_right; ++ dm_fsys_remove_dmattr_t remove_dmattr; ++ dm_fsys_request_right_t request_right; ++ dm_fsys_set_dmattr_t set_dmattr; ++ dm_fsys_set_eventlist_t set_eventlist; ++ dm_fsys_set_fileattr_t set_fileattr; ++ dm_fsys_set_inherit_t set_inherit; ++ dm_fsys_set_region_t set_region; ++ dm_fsys_symlink_by_handle_t symlink_by_handle; ++ dm_fsys_sync_by_handle_t sync_by_handle; ++ dm_fsys_upgrade_right_t upgrade_right; ++ dm_fsys_write_invis_rvp_t write_invis_rvp; ++ dm_fsys_obj_ref_hold_t obj_ref_hold; ++ } u_fc; ++} fsys_function_vector_t; ++ ++struct dm_fcntl_vector { ++ int code_level; ++ int count; /* Number of functions in the vector */ ++ fsys_function_vector_t *vecp; ++}; ++typedef struct dm_fcntl_vector dm_fcntl_vector_t; ++ ++struct dm_fcntl_mapevent { ++ size_t length; /* length of transfer */ ++ dm_eventtype_t max_event; /* Maximum (WRITE or READ) event */ ++ int error; /* returned error code */ ++}; ++typedef struct dm_fcntl_mapevent dm_fcntl_mapevent_t; ++ ++#endif /* __KERNEL__ */ ++ ++ ++/* The following definitions are needed both by the kernel and by the ++ library routines. ++*/ ++ ++#define DM_MAX_HANDLE_SIZE 56 /* maximum size for a file handle */ ++ ++ ++/* ++ * Opcodes for dmapi ioctl. ++ */ ++ ++#define DM_CLEAR_INHERIT 1 ++#define DM_CREATE_BY_HANDLE 2 ++#define DM_CREATE_SESSION 3 ++#define DM_CREATE_USEREVENT 4 ++#define DM_DESTROY_SESSION 5 ++#define DM_DOWNGRADE_RIGHT 6 ++#define DM_FD_TO_HANDLE 7 ++#define DM_FIND_EVENTMSG 8 ++#define DM_GET_ALLOCINFO 9 ++#define DM_GET_BULKALL 10 ++#define DM_GET_BULKATTR 11 ++#define DM_GET_CONFIG 12 ++#define DM_GET_CONFIG_EVENTS 13 ++#define DM_GET_DIOINFO 14 ++#define DM_GET_DIRATTRS 15 ++#define DM_GET_DMATTR 16 ++#define DM_GET_EVENTLIST 17 ++#define DM_GET_EVENTS 18 ++#define DM_GET_FILEATTR 19 ++#define DM_GET_MOUNTINFO 20 ++#define DM_GET_REGION 21 ++#define DM_GETALL_DISP 22 ++#define DM_GETALL_DMATTR 23 ++#define DM_GETALL_INHERIT 24 ++#define DM_GETALL_SESSIONS 25 ++#define DM_GETALL_TOKENS 26 ++#define DM_INIT_ATTRLOC 27 ++#define DM_MKDIR_BY_HANDLE 28 ++#define DM_MOVE_EVENT 29 ++#define DM_OBJ_REF_HOLD 30 ++#define DM_OBJ_REF_QUERY 31 ++#define DM_OBJ_REF_RELE 32 ++#define DM_PATH_TO_FSHANDLE 33 ++#define DM_PATH_TO_HANDLE 34 ++#define DM_PENDING 35 ++#define DM_PROBE_HOLE 36 ++#define DM_PUNCH_HOLE 37 ++#define DM_QUERY_RIGHT 38 ++#define DM_QUERY_SESSION 39 ++#define DM_READ_INVIS 40 ++#define DM_RELEASE_RIGHT 41 ++#define DM_REMOVE_DMATTR 42 ++#define DM_REQUEST_RIGHT 43 ++#define DM_RESPOND_EVENT 44 ++#define DM_SEND_MSG 45 ++#define DM_SET_DISP 46 ++#define DM_SET_DMATTR 47 ++#define DM_SET_EVENTLIST 48 ++#define DM_SET_FILEATTR 49 ++#define DM_SET_INHERIT 50 ++#define DM_SET_REGION 51 ++#define DM_SET_RETURN_ON_DESTROY 52 ++#define DM_SYMLINK_BY_HANDLE 53 ++#define DM_SYNC_BY_HANDLE 54 ++#define DM_UPGRADE_RIGHT 55 ++#define DM_WRITE_INVIS 56 ++#define DM_OPEN_BY_HANDLE 57 ++ ++#endif /* __DMAPI_KERN_H__ */ +Index: linux-2.6.26/fs/dmapi/dmapi_mountinfo.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_mountinfo.c +@@ -0,0 +1,527 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++static LIST_HEAD(dm_fsys_map); ++static spinlock_t dm_fsys_lock = SPIN_LOCK_UNLOCKED; ++ ++int ++dm_code_level(void) ++{ ++ return DM_CLVL_XOPEN; /* initial X/Open compliant release */ ++} ++ ++ ++/* Dummy routine which is stored in each function vector slot for which the ++ filesystem provides no function of its own. If an application calls the ++ function, he will just get ENOSYS. ++*/ ++ ++static int ++dm_enosys(void) ++{ ++ return -ENOSYS; /* function not supported by filesystem */ ++} ++ ++ ++/* dm_query_fsys_for_vector() asks a filesystem for its list of supported ++ DMAPI functions, and builds a dm_vector_map_t structure based upon the ++ reply. We ignore functions supported by the filesystem which we do not ++ know about, and we substitute the subroutine 'dm_enosys' for each function ++ we know about but the filesystem does not support. ++*/ ++ ++static void ++dm_query_fsys_for_vector( ++ dm_vector_map_t *map) ++{ ++ struct super_block *sb = map->sb; ++ fsys_function_vector_t *vecp; ++ dm_fcntl_vector_t vecrq; ++ dm_fsys_vector_t *vptr; ++ struct filesystem_dmapi_operations *dmapiops = map->dmapiops; ++ int error; ++ int i; ++ ++ ++ /* Allocate a function vector and initialize all fields with a ++ dummy function that returns ENOSYS. ++ */ ++ ++ vptr = map->vptr = kmem_cache_alloc(dm_fsys_vptr_cachep, GFP_KERNEL); ++ if (vptr == NULL) { ++ printk("%s/%d: kmem_cache_alloc(dm_fsys_vptr_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return; ++ } ++ ++ vptr->code_level = 0; ++ vptr->clear_inherit = (dm_fsys_clear_inherit_t)dm_enosys; ++ vptr->create_by_handle = (dm_fsys_create_by_handle_t)dm_enosys; ++ vptr->downgrade_right = (dm_fsys_downgrade_right_t)dm_enosys; ++ vptr->get_allocinfo_rvp = (dm_fsys_get_allocinfo_rvp_t)dm_enosys; ++ vptr->get_bulkall_rvp = (dm_fsys_get_bulkall_rvp_t)dm_enosys; ++ vptr->get_bulkattr_rvp = (dm_fsys_get_bulkattr_rvp_t)dm_enosys; ++ vptr->get_config = (dm_fsys_get_config_t)dm_enosys; ++ vptr->get_config_events = (dm_fsys_get_config_events_t)dm_enosys; ++ vptr->get_destroy_dmattr = (dm_fsys_get_destroy_dmattr_t)dm_enosys; ++ vptr->get_dioinfo = (dm_fsys_get_dioinfo_t)dm_enosys; ++ vptr->get_dirattrs_rvp = (dm_fsys_get_dirattrs_rvp_t)dm_enosys; ++ vptr->get_dmattr = (dm_fsys_get_dmattr_t)dm_enosys; ++ vptr->get_eventlist = (dm_fsys_get_eventlist_t)dm_enosys; ++ vptr->get_fileattr = (dm_fsys_get_fileattr_t)dm_enosys; ++ vptr->get_region = (dm_fsys_get_region_t)dm_enosys; ++ vptr->getall_dmattr = (dm_fsys_getall_dmattr_t)dm_enosys; ++ vptr->getall_inherit = (dm_fsys_getall_inherit_t)dm_enosys; ++ vptr->init_attrloc = (dm_fsys_init_attrloc_t)dm_enosys; ++ vptr->mkdir_by_handle = (dm_fsys_mkdir_by_handle_t)dm_enosys; ++ vptr->probe_hole = (dm_fsys_probe_hole_t)dm_enosys; ++ vptr->punch_hole = (dm_fsys_punch_hole_t)dm_enosys; ++ vptr->read_invis_rvp = (dm_fsys_read_invis_rvp_t)dm_enosys; ++ vptr->release_right = (dm_fsys_release_right_t)dm_enosys; ++ vptr->request_right = (dm_fsys_request_right_t)dm_enosys; ++ vptr->remove_dmattr = (dm_fsys_remove_dmattr_t)dm_enosys; ++ vptr->set_dmattr = (dm_fsys_set_dmattr_t)dm_enosys; ++ vptr->set_eventlist = (dm_fsys_set_eventlist_t)dm_enosys; ++ vptr->set_fileattr = (dm_fsys_set_fileattr_t)dm_enosys; ++ vptr->set_inherit = (dm_fsys_set_inherit_t)dm_enosys; ++ vptr->set_region = (dm_fsys_set_region_t)dm_enosys; ++ vptr->symlink_by_handle = (dm_fsys_symlink_by_handle_t)dm_enosys; ++ vptr->sync_by_handle = (dm_fsys_sync_by_handle_t)dm_enosys; ++ vptr->upgrade_right = (dm_fsys_upgrade_right_t)dm_enosys; ++ vptr->write_invis_rvp = (dm_fsys_write_invis_rvp_t)dm_enosys; ++ vptr->obj_ref_hold = (dm_fsys_obj_ref_hold_t)dm_enosys; ++ ++ /* Issue a call to the filesystem in order to obtain ++ its vector of filesystem-specific DMAPI routines. ++ */ ++ ++ vecrq.count = 0; ++ vecrq.vecp = NULL; ++ ++ error = -ENOSYS; ++ ASSERT(dmapiops); ++ if (dmapiops->get_fsys_vector) ++ error = dmapiops->get_fsys_vector(sb, (caddr_t)&vecrq); ++ ++ /* If we still have an error at this point, then the filesystem simply ++ does not support DMAPI, so we give up with all functions set to ++ ENOSYS. ++ */ ++ ++ if (error || vecrq.count == 0) { ++ kmem_cache_free(dm_fsys_vptr_cachep, vptr); ++ map->vptr = NULL; ++ return; ++ } ++ ++ /* The request succeeded and we were given a vector which we need to ++ map to our current level. Overlay the dummy function with every ++ filesystem function we understand. ++ */ ++ ++ vptr->code_level = vecrq.code_level; ++ vecp = vecrq.vecp; ++ for (i = 0; i < vecrq.count; i++) { ++ switch (vecp[i].func_no) { ++ case DM_FSYS_CLEAR_INHERIT: ++ vptr->clear_inherit = vecp[i].u_fc.clear_inherit; ++ break; ++ case DM_FSYS_CREATE_BY_HANDLE: ++ vptr->create_by_handle = vecp[i].u_fc.create_by_handle; ++ break; ++ case DM_FSYS_DOWNGRADE_RIGHT: ++ vptr->downgrade_right = vecp[i].u_fc.downgrade_right; ++ break; ++ case DM_FSYS_GET_ALLOCINFO_RVP: ++ vptr->get_allocinfo_rvp = vecp[i].u_fc.get_allocinfo_rvp; ++ break; ++ case DM_FSYS_GET_BULKALL_RVP: ++ vptr->get_bulkall_rvp = vecp[i].u_fc.get_bulkall_rvp; ++ break; ++ case DM_FSYS_GET_BULKATTR_RVP: ++ vptr->get_bulkattr_rvp = vecp[i].u_fc.get_bulkattr_rvp; ++ break; ++ case DM_FSYS_GET_CONFIG: ++ vptr->get_config = vecp[i].u_fc.get_config; ++ break; ++ case DM_FSYS_GET_CONFIG_EVENTS: ++ vptr->get_config_events = vecp[i].u_fc.get_config_events; ++ break; ++ case DM_FSYS_GET_DESTROY_DMATTR: ++ vptr->get_destroy_dmattr = vecp[i].u_fc.get_destroy_dmattr; ++ break; ++ case DM_FSYS_GET_DIOINFO: ++ vptr->get_dioinfo = vecp[i].u_fc.get_dioinfo; ++ break; ++ case DM_FSYS_GET_DIRATTRS_RVP: ++ vptr->get_dirattrs_rvp = vecp[i].u_fc.get_dirattrs_rvp; ++ break; ++ case DM_FSYS_GET_DMATTR: ++ vptr->get_dmattr = vecp[i].u_fc.get_dmattr; ++ break; ++ case DM_FSYS_GET_EVENTLIST: ++ vptr->get_eventlist = vecp[i].u_fc.get_eventlist; ++ break; ++ case DM_FSYS_GET_FILEATTR: ++ vptr->get_fileattr = vecp[i].u_fc.get_fileattr; ++ break; ++ case DM_FSYS_GET_REGION: ++ vptr->get_region = vecp[i].u_fc.get_region; ++ break; ++ case DM_FSYS_GETALL_DMATTR: ++ vptr->getall_dmattr = vecp[i].u_fc.getall_dmattr; ++ break; ++ case DM_FSYS_GETALL_INHERIT: ++ vptr->getall_inherit = vecp[i].u_fc.getall_inherit; ++ break; ++ case DM_FSYS_INIT_ATTRLOC: ++ vptr->init_attrloc = vecp[i].u_fc.init_attrloc; ++ break; ++ case DM_FSYS_MKDIR_BY_HANDLE: ++ vptr->mkdir_by_handle = vecp[i].u_fc.mkdir_by_handle; ++ break; ++ case DM_FSYS_PROBE_HOLE: ++ vptr->probe_hole = vecp[i].u_fc.probe_hole; ++ break; ++ case DM_FSYS_PUNCH_HOLE: ++ vptr->punch_hole = vecp[i].u_fc.punch_hole; ++ break; ++ case DM_FSYS_READ_INVIS_RVP: ++ vptr->read_invis_rvp = vecp[i].u_fc.read_invis_rvp; ++ break; ++ case DM_FSYS_RELEASE_RIGHT: ++ vptr->release_right = vecp[i].u_fc.release_right; ++ break; ++ case DM_FSYS_REMOVE_DMATTR: ++ vptr->remove_dmattr = vecp[i].u_fc.remove_dmattr; ++ break; ++ case DM_FSYS_REQUEST_RIGHT: ++ vptr->request_right = vecp[i].u_fc.request_right; ++ break; ++ case DM_FSYS_SET_DMATTR: ++ vptr->set_dmattr = vecp[i].u_fc.set_dmattr; ++ break; ++ case DM_FSYS_SET_EVENTLIST: ++ vptr->set_eventlist = vecp[i].u_fc.set_eventlist; ++ break; ++ case DM_FSYS_SET_FILEATTR: ++ vptr->set_fileattr = vecp[i].u_fc.set_fileattr; ++ break; ++ case DM_FSYS_SET_INHERIT: ++ vptr->set_inherit = vecp[i].u_fc.set_inherit; ++ break; ++ case DM_FSYS_SET_REGION: ++ vptr->set_region = vecp[i].u_fc.set_region; ++ break; ++ case DM_FSYS_SYMLINK_BY_HANDLE: ++ vptr->symlink_by_handle = vecp[i].u_fc.symlink_by_handle; ++ break; ++ case DM_FSYS_SYNC_BY_HANDLE: ++ vptr->sync_by_handle = vecp[i].u_fc.sync_by_handle; ++ break; ++ case DM_FSYS_UPGRADE_RIGHT: ++ vptr->upgrade_right = vecp[i].u_fc.upgrade_right; ++ break; ++ case DM_FSYS_WRITE_INVIS_RVP: ++ vptr->write_invis_rvp = vecp[i].u_fc.write_invis_rvp; ++ break; ++ case DM_FSYS_OBJ_REF_HOLD: ++ vptr->obj_ref_hold = vecp[i].u_fc.obj_ref_hold; ++ break; ++ default: /* ignore ones we don't understand */ ++ break; ++ } ++ } ++} ++ ++ ++/* Must hold dm_fsys_lock. ++ * This returns the prototype for all instances of the fstype. ++ */ ++static dm_vector_map_t * ++dm_fsys_map_by_fstype( ++ struct file_system_type *fstype) ++{ ++ struct list_head *p; ++ dm_vector_map_t *proto = NULL; ++ dm_vector_map_t *m; ++ ++ ASSERT_ALWAYS(fstype); ++ list_for_each(p, &dm_fsys_map) { ++ m = list_entry(p, dm_vector_map_t, ftype_list); ++ if (m->f_type == fstype) { ++ proto = m; ++ break; ++ } ++ } ++ return proto; ++} ++ ++ ++/* Must hold dm_fsys_lock */ ++static dm_vector_map_t * ++dm_fsys_map_by_sb( ++ struct super_block *sb) ++{ ++ struct list_head *p; ++ dm_vector_map_t *proto; ++ dm_vector_map_t *m; ++ dm_vector_map_t *foundmap = NULL; ++ ++ proto = dm_fsys_map_by_fstype(sb->s_type); ++ if(proto == NULL) { ++ return NULL; ++ } ++ ++ list_for_each(p, &proto->sb_list) { ++ m = list_entry(p, dm_vector_map_t, sb_list); ++ if (m->sb == sb) { ++ foundmap = m; ++ break; ++ } ++ } ++ return foundmap; ++} ++ ++ ++#ifdef CONFIG_DMAPI_DEBUG ++static void ++sb_list( ++ struct super_block *sb) ++{ ++ struct list_head *p; ++ dm_vector_map_t *proto; ++ dm_vector_map_t *m; ++ ++ proto = dm_fsys_map_by_fstype(sb->s_type); ++ ASSERT(proto); ++ ++printk("%s/%d: Current sb_list\n", __FUNCTION__, __LINE__); ++ list_for_each(p, &proto->sb_list) { ++ m = list_entry(p, dm_vector_map_t, sb_list); ++printk("%s/%d: map 0x%p, sb 0x%p, vptr 0x%p, dmapiops 0x%p\n", __FUNCTION__, __LINE__, m, m->sb, m->vptr, m->dmapiops); ++ } ++printk("%s/%d: Done sb_list\n", __FUNCTION__, __LINE__); ++} ++#else ++#define sb_list(x) ++#endif ++ ++#ifdef CONFIG_DMAPI_DEBUG ++static void ++ftype_list(void) ++{ ++ struct list_head *p; ++ dm_vector_map_t *m; ++ ++printk("%s/%d: Current ftype_list\n", __FUNCTION__, __LINE__); ++ list_for_each(p, &dm_fsys_map) { ++ m = list_entry(p, dm_vector_map_t, ftype_list); ++ printk("%s/%d: FS 0x%p, ftype 0x%p %s\n", __FUNCTION__, __LINE__, m, m->f_type, m->f_type->name); ++ } ++printk("%s/%d: Done ftype_list\n", __FUNCTION__, __LINE__); ++} ++#else ++#define ftype_list() ++#endif ++ ++/* Ask for vptr for this filesystem instance. ++ * The caller knows this inode is on a dmapi-managed filesystem. ++ */ ++dm_fsys_vector_t * ++dm_fsys_vector( ++ struct inode *ip) ++{ ++ dm_vector_map_t *map; ++ ++ spin_lock(&dm_fsys_lock); ++ ftype_list(); ++ map = dm_fsys_map_by_sb(ip->i_sb); ++ spin_unlock(&dm_fsys_lock); ++ ASSERT(map); ++ ASSERT(map->vptr); ++ return map->vptr; ++} ++ ++ ++/* Ask for the dmapiops for this filesystem instance. The caller is ++ * also asking if this is a dmapi-managed filesystem. ++ */ ++struct filesystem_dmapi_operations * ++dm_fsys_ops( ++ struct super_block *sb) ++{ ++ dm_vector_map_t *proto = NULL; ++ dm_vector_map_t *map; ++ ++ spin_lock(&dm_fsys_lock); ++ ftype_list(); ++ sb_list(sb); ++ map = dm_fsys_map_by_sb(sb); ++ if (map == NULL) ++ proto = dm_fsys_map_by_fstype(sb->s_type); ++ spin_unlock(&dm_fsys_lock); ++ ++ if ((map == NULL) && (proto == NULL)) ++ return NULL; ++ ++ if (map == NULL) { ++ /* Find out if it's dmapi-managed */ ++ dm_vector_map_t *m; ++ ++ ASSERT(proto); ++ m = kmem_cache_alloc(dm_fsys_map_cachep, GFP_KERNEL); ++ if (m == NULL) { ++ printk("%s/%d: kmem_cache_alloc(dm_fsys_map_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return NULL; ++ } ++ memset(m, 0, sizeof(*m)); ++ m->dmapiops = proto->dmapiops; ++ m->f_type = sb->s_type; ++ m->sb = sb; ++ INIT_LIST_HEAD(&m->sb_list); ++ INIT_LIST_HEAD(&m->ftype_list); ++ ++ dm_query_fsys_for_vector(m); ++ if (m->vptr == NULL) { ++ /* This isn't dmapi-managed */ ++ kmem_cache_free(dm_fsys_map_cachep, m); ++ return NULL; ++ } ++ ++ spin_lock(&dm_fsys_lock); ++ if ((map = dm_fsys_map_by_sb(sb)) == NULL) ++ list_add(&m->sb_list, &proto->sb_list); ++ spin_unlock(&dm_fsys_lock); ++ ++ if (map) { ++ kmem_cache_free(dm_fsys_vptr_cachep, m->vptr); ++ kmem_cache_free(dm_fsys_map_cachep, m); ++ } ++ else { ++ map = m; ++ } ++ } ++ ++ return map->dmapiops; ++} ++ ++ ++ ++/* Called when a filesystem instance is unregistered from dmapi */ ++void ++dm_fsys_ops_release( ++ struct super_block *sb) ++{ ++ dm_vector_map_t *map; ++ ++ spin_lock(&dm_fsys_lock); ++ ASSERT(!list_empty(&dm_fsys_map)); ++ map = dm_fsys_map_by_sb(sb); ++ ASSERT(map); ++ list_del(&map->sb_list); ++ spin_unlock(&dm_fsys_lock); ++ ++ ASSERT(map->vptr); ++ kmem_cache_free(dm_fsys_vptr_cachep, map->vptr); ++ kmem_cache_free(dm_fsys_map_cachep, map); ++} ++ ++ ++/* Called by a filesystem module that is loading into the kernel. ++ * This creates a new dm_vector_map_t which serves as the prototype ++ * for instances of this fstype and also provides the list_head ++ * for instances of this fstype. The prototypes are the only ones ++ * on the fstype_list, and will never be on the sb_list. ++ */ ++void ++dmapi_register( ++ struct file_system_type *fstype, ++ struct filesystem_dmapi_operations *dmapiops) ++{ ++ dm_vector_map_t *proto; ++ ++ proto = kmem_cache_alloc(dm_fsys_map_cachep, GFP_KERNEL); ++ if (proto == NULL) { ++ printk("%s/%d: kmem_cache_alloc(dm_fsys_map_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return; ++ } ++ memset(proto, 0, sizeof(*proto)); ++ proto->dmapiops = dmapiops; ++ proto->f_type = fstype; ++ INIT_LIST_HEAD(&proto->sb_list); ++ INIT_LIST_HEAD(&proto->ftype_list); ++ ++ spin_lock(&dm_fsys_lock); ++ ASSERT(dm_fsys_map_by_fstype(fstype) == NULL); ++ list_add(&proto->ftype_list, &dm_fsys_map); ++ ftype_list(); ++ spin_unlock(&dm_fsys_lock); ++} ++ ++/* Called by a filesystem module that is unloading from the kernel */ ++void ++dmapi_unregister( ++ struct file_system_type *fstype) ++{ ++ struct list_head *p; ++ dm_vector_map_t *proto; ++ dm_vector_map_t *m; ++ ++ spin_lock(&dm_fsys_lock); ++ ASSERT(!list_empty(&dm_fsys_map)); ++ proto = dm_fsys_map_by_fstype(fstype); ++ ASSERT(proto); ++ list_del(&proto->ftype_list); ++ spin_unlock(&dm_fsys_lock); ++ ++ p = &proto->sb_list; ++ while (!list_empty(p)) { ++ m = list_entry(p->next, dm_vector_map_t, sb_list); ++ list_del(&m->sb_list); ++ ASSERT(m->vptr); ++ kmem_cache_free(dm_fsys_vptr_cachep, m->vptr); ++ kmem_cache_free(dm_fsys_map_cachep, m); ++ } ++ kmem_cache_free(dm_fsys_map_cachep, proto); ++} ++ ++ ++int ++dmapi_registered( ++ struct file_system_type *fstype, ++ struct filesystem_dmapi_operations **dmapiops) ++{ ++ return 0; ++} +Index: linux-2.6.26/fs/dmapi/dmapi_port.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_port.h +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#ifndef _DMAPI_PORT_H ++#define _DMAPI_PORT_H ++ ++#include ++#include "sv.h" ++ ++#include /* preempt needs this */ ++#include ++ ++typedef spinlock_t lock_t; ++ ++#define spinlock_init(lock, name) spin_lock_init(lock) ++#define spinlock_destroy(lock) ++ ++#define mutex_spinlock(lock) ({ spin_lock(lock); 0; }) ++#define mutex_spinunlock(lock, s) spin_unlock(lock) ++#define nested_spinlock(lock) spin_lock(lock) ++#define nested_spinunlock(lock) spin_unlock(lock) ++ ++typedef signed int __int32_t; ++typedef unsigned int __uint32_t; ++typedef signed long long int __int64_t; ++typedef unsigned long long int __uint64_t; ++ ++ ++/* __psint_t is the same size as a pointer */ ++#if (BITS_PER_LONG == 32) ++typedef __int32_t __psint_t; ++typedef __uint32_t __psunsigned_t; ++#elif (BITS_PER_LONG == 64) ++typedef __int64_t __psint_t; ++typedef __uint64_t __psunsigned_t; ++#else ++#error BITS_PER_LONG must be 32 or 64 ++#endif ++ ++static inline void ++assfail(char *a, char *f, int l) ++{ ++ printk("DMAPI assertion failed: %s, file: %s, line: %d\n", a, f, l); ++ BUG(); ++} ++ ++#ifdef DEBUG ++#define doass 1 ++# ifdef lint ++# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */ ++# else ++# define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__)) ++# endif /* lint */ ++#else ++# define ASSERT(x) ((void)0) ++#endif /* DEBUG */ ++ ++#define ASSERT_ALWAYS(EX) ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__)) ++ ++ ++#if defined __i386__ ++ ++/* Side effect free 64 bit mod operation */ ++static inline __u32 dmapi_do_mod(void *a, __u32 b, int n) ++{ ++ switch (n) { ++ case 4: ++ return *(__u32 *)a % b; ++ case 8: ++ { ++ unsigned long __upper, __low, __high, __mod; ++ __u64 c = *(__u64 *)a; ++ __upper = __high = c >> 32; ++ __low = c; ++ if (__high) { ++ __upper = __high % (b); ++ __high = __high / (b); ++ } ++ asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); ++ asm("":"=A" (c):"a" (__low),"d" (__high)); ++ return __mod; ++ } ++ } ++ ++ /* NOTREACHED */ ++ return 0; ++} ++#else ++ ++/* Side effect free 64 bit mod operation */ ++static inline __u32 dmapi_do_mod(void *a, __u32 b, int n) ++{ ++ switch (n) { ++ case 4: ++ return *(__u32 *)a % b; ++ case 8: ++ { ++ __u64 c = *(__u64 *)a; ++ return do_div(c, b); ++ } ++ } ++ ++ /* NOTREACHED */ ++ return 0; ++} ++#endif ++ ++#define do_mod(a, b) dmapi_do_mod(&(a), (b), sizeof(a)) ++ ++#endif /* _DMAPI_PORT_H */ +Index: linux-2.6.26/fs/dmapi/dmapi_private.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_private.h +@@ -0,0 +1,619 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#ifndef _DMAPI_PRIVATE_H ++#define _DMAPI_PRIVATE_H ++ ++#include ++#include "dmapi_port.h" ++#include "sv.h" ++ ++#ifdef CONFIG_PROC_FS ++#define DMAPI_PROCFS "orig/fs/dmapi_v2" /* DMAPI device in /proc. */ ++#define DMAPI_DBG_PROCFS "orig/fs/dmapi_d" /* DMAPI debugging dir */ ++#endif ++ ++extern struct kmem_cache *dm_fsreg_cachep; ++extern struct kmem_cache *dm_tokdata_cachep; ++extern struct kmem_cache *dm_session_cachep; ++extern struct kmem_cache *dm_fsys_map_cachep; ++extern struct kmem_cache *dm_fsys_vptr_cachep; ++ ++typedef struct dm_tokdata { ++ struct dm_tokdata *td_next; ++ struct dm_tokevent *td_tevp; /* pointer to owning tevp */ ++ int td_app_ref; /* # app threads currently active */ ++ dm_right_t td_orig_right; /* original right held when created */ ++ dm_right_t td_right; /* current right held for this handle */ ++ short td_flags; ++ short td_type; /* object type */ ++ int td_vcount; /* # of current application VN_HOLDs */ ++ struct inode *td_ip; /* inode pointer */ ++ dm_handle_t td_handle; /* handle for ip or sb */ ++} dm_tokdata_t; ++ ++/* values for td_type */ ++ ++#define DM_TDT_NONE 0x00 /* td_handle is empty */ ++#define DM_TDT_VFS 0x01 /* td_handle points to a sb */ ++#define DM_TDT_REG 0x02 /* td_handle points to a file */ ++#define DM_TDT_DIR 0x04 /* td_handle points to a directory */ ++#define DM_TDT_LNK 0x08 /* td_handle points to a symlink */ ++#define DM_TDT_OTH 0x10 /* some other object eg. pipe, socket */ ++ ++#define DM_TDT_VNO (DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH) ++#define DM_TDT_ANY (DM_TDT_VFS|DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH) ++ ++/* values for td_flags */ ++ ++#define DM_TDF_ORIG 0x0001 /* part of the original event */ ++#define DM_TDF_EVTREF 0x0002 /* event thread holds inode reference */ ++#define DM_TDF_STHREAD 0x0004 /* only one app can use this handle */ ++#define DM_TDF_RIGHT 0x0008 /* vcount bumped for dm_request_right */ ++#define DM_TDF_HOLD 0x0010 /* vcount bumped for dm_obj_ref_hold */ ++ ++ ++/* Because some events contain __u64 fields, we force te_msg and te_event ++ to always be 8-byte aligned. In order to send more than one message in ++ a single dm_get_events() call, we also ensure that each message is an ++ 8-byte multiple. ++*/ ++ ++typedef struct dm_tokevent { ++ struct dm_tokevent *te_next; ++ struct dm_tokevent *te_hashnext; /* hash chain */ ++ lock_t te_lock; /* lock for all fields but te_*next. ++ * te_next and te_hashnext are ++ * protected by the session lock. ++ */ ++ short te_flags; ++ short te_allocsize; /* alloc'ed size of this structure */ ++ sv_t te_evt_queue; /* queue waiting for dm_respond_event */ ++ sv_t te_app_queue; /* queue waiting for handle access */ ++ int te_evt_ref; /* number of event procs using token */ ++ int te_app_ref; /* number of app procs using token */ ++ int te_app_slp; /* number of app procs sleeping */ ++ int te_reply; /* return errno for sync messages */ ++ dm_tokdata_t *te_tdp; /* list of handle/right pairs */ ++ union { ++ __u64 align; /* force alignment of te_msg */ ++ dm_eventmsg_t te_msg; /* user visible part */ ++ } te_u; ++ __u64 te_event; /* start of dm_xxx_event_t message */ ++} dm_tokevent_t; ++ ++#define te_msg te_u.te_msg ++ ++/* values for te_flags */ ++ ++#define DM_TEF_LOCKED 0x0001 /* event "locked" by dm_get_events() */ ++#define DM_TEF_INTERMED 0x0002 /* a dm_pending reply was received */ ++#define DM_TEF_FINAL 0x0004 /* dm_respond_event has been received */ ++#define DM_TEF_HASHED 0x0010 /* event is on hash chain */ ++#define DM_TEF_FLUSH 0x0020 /* flushing threads from queues */ ++ ++ ++#ifdef CONFIG_DMAPI_DEBUG ++#define DM_SHASH_DEBUG ++#endif ++ ++typedef struct dm_sesshash { ++ dm_tokevent_t *h_next; /* ptr to chain of tokevents */ ++#ifdef DM_SHASH_DEBUG ++ int maxlength; ++ int curlength; ++ int num_adds; ++ int num_dels; ++ int dup_hits; ++#endif ++} dm_sesshash_t; ++ ++ ++typedef struct dm_eventq { ++ dm_tokevent_t *eq_head; ++ dm_tokevent_t *eq_tail; ++ int eq_count; /* size of queue */ ++} dm_eventq_t; ++ ++ ++typedef struct dm_session { ++ struct dm_session *sn_next; /* sessions linkage */ ++ dm_sessid_t sn_sessid; /* user-visible session number */ ++ u_int sn_flags; ++ lock_t sn_qlock; /* lock for newq/delq related fields */ ++ sv_t sn_readerq; /* waiting for message on sn_newq */ ++ sv_t sn_writerq; /* waiting for room on sn_newq */ ++ u_int sn_readercnt; /* count of waiting readers */ ++ u_int sn_writercnt; /* count of waiting readers */ ++ dm_eventq_t sn_newq; /* undelivered event queue */ ++ dm_eventq_t sn_delq; /* delivered event queue */ ++ dm_eventq_t sn_evt_writerq; /* events of thrds in sn_writerq */ ++ dm_sesshash_t *sn_sesshash; /* buckets for tokevent hash chains */ ++#ifdef DM_SHASH_DEBUG ++ int sn_buckets_in_use; ++ int sn_max_buckets_in_use; ++#endif ++ char sn_info[DM_SESSION_INFO_LEN]; /* user-supplied info */ ++} dm_session_t; ++ ++/* values for sn_flags */ ++ ++#define DM_SN_WANTMOUNT 0x0001 /* session wants to get mount events */ ++ ++ ++typedef enum { ++ DM_STATE_MOUNTING, ++ DM_STATE_MOUNTED, ++ DM_STATE_UNMOUNTING, ++ DM_STATE_UNMOUNTED ++} dm_fsstate_t; ++ ++ ++typedef struct dm_fsreg { ++ struct dm_fsreg *fr_next; ++ struct super_block *fr_sb; /* filesystem pointer */ ++ dm_tokevent_t *fr_tevp; ++ dm_fsid_t fr_fsid; /* filesystem ID */ ++ void *fr_msg; /* dm_mount_event_t for filesystem */ ++ int fr_msgsize; /* size of dm_mount_event_t */ ++ dm_fsstate_t fr_state; ++ sv_t fr_dispq; ++ int fr_dispcnt; ++ dm_eventq_t fr_evt_dispq; /* events of thrds in fr_dispq */ ++ sv_t fr_queue; /* queue for hdlcnt/sbcnt/unmount */ ++ lock_t fr_lock; ++ int fr_hdlcnt; /* threads blocked during unmount */ ++ int fr_vfscnt; /* threads in VFS_VGET or VFS_ROOT */ ++ int fr_unmount; /* if non-zero, umount is sleeping */ ++ dm_attrname_t fr_rattr; /* dm_set_return_on_destroy attribute */ ++ dm_session_t *fr_sessp [DM_EVENT_MAX]; ++} dm_fsreg_t; ++ ++ ++ ++ ++/* events valid in dm_set_disp() when called with a filesystem handle. */ ++ ++#define DM_VALID_DISP_EVENTS ( \ ++ (1 << DM_EVENT_PREUNMOUNT) | \ ++ (1 << DM_EVENT_UNMOUNT) | \ ++ (1 << DM_EVENT_NOSPACE) | \ ++ (1 << DM_EVENT_DEBUT) | \ ++ (1 << DM_EVENT_CREATE) | \ ++ (1 << DM_EVENT_POSTCREATE) | \ ++ (1 << DM_EVENT_REMOVE) | \ ++ (1 << DM_EVENT_POSTREMOVE) | \ ++ (1 << DM_EVENT_RENAME) | \ ++ (1 << DM_EVENT_POSTRENAME) | \ ++ (1 << DM_EVENT_LINK) | \ ++ (1 << DM_EVENT_POSTLINK) | \ ++ (1 << DM_EVENT_SYMLINK) | \ ++ (1 << DM_EVENT_POSTSYMLINK) | \ ++ (1 << DM_EVENT_READ) | \ ++ (1 << DM_EVENT_WRITE) | \ ++ (1 << DM_EVENT_TRUNCATE) | \ ++ (1 << DM_EVENT_ATTRIBUTE) | \ ++ (1 << DM_EVENT_DESTROY) ) ++ ++ ++/* isolate the read/write/trunc events of a dm_tokevent_t */ ++ ++#define DM_EVENT_RDWRTRUNC(tevp) ( \ ++ ((tevp)->te_msg.ev_type == DM_EVENT_READ) || \ ++ ((tevp)->te_msg.ev_type == DM_EVENT_WRITE) || \ ++ ((tevp)->te_msg.ev_type == DM_EVENT_TRUNCATE) ) ++ ++ ++/* ++ * Global handle hack isolation. ++ */ ++ ++#define DM_GLOBALHAN(hanp, hlen) (((hanp) == DM_GLOBAL_HANP) && \ ++ ((hlen) == DM_GLOBAL_HLEN)) ++ ++ ++#define DM_MAX_MSG_DATA 3960 ++ ++ ++ ++/* Supported filesystem function vector functions. */ ++ ++ ++typedef struct { ++ int code_level; ++ dm_fsys_clear_inherit_t clear_inherit; ++ dm_fsys_create_by_handle_t create_by_handle; ++ dm_fsys_downgrade_right_t downgrade_right; ++ dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; ++ dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; ++ dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; ++ dm_fsys_get_config_t get_config; ++ dm_fsys_get_config_events_t get_config_events; ++ dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; ++ dm_fsys_get_dioinfo_t get_dioinfo; ++ dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; ++ dm_fsys_get_dmattr_t get_dmattr; ++ dm_fsys_get_eventlist_t get_eventlist; ++ dm_fsys_get_fileattr_t get_fileattr; ++ dm_fsys_get_region_t get_region; ++ dm_fsys_getall_dmattr_t getall_dmattr; ++ dm_fsys_getall_inherit_t getall_inherit; ++ dm_fsys_init_attrloc_t init_attrloc; ++ dm_fsys_mkdir_by_handle_t mkdir_by_handle; ++ dm_fsys_probe_hole_t probe_hole; ++ dm_fsys_punch_hole_t punch_hole; ++ dm_fsys_read_invis_rvp_t read_invis_rvp; ++ dm_fsys_release_right_t release_right; ++ dm_fsys_remove_dmattr_t remove_dmattr; ++ dm_fsys_request_right_t request_right; ++ dm_fsys_set_dmattr_t set_dmattr; ++ dm_fsys_set_eventlist_t set_eventlist; ++ dm_fsys_set_fileattr_t set_fileattr; ++ dm_fsys_set_inherit_t set_inherit; ++ dm_fsys_set_region_t set_region; ++ dm_fsys_symlink_by_handle_t symlink_by_handle; ++ dm_fsys_sync_by_handle_t sync_by_handle; ++ dm_fsys_upgrade_right_t upgrade_right; ++ dm_fsys_write_invis_rvp_t write_invis_rvp; ++ dm_fsys_obj_ref_hold_t obj_ref_hold; ++} dm_fsys_vector_t; ++ ++ ++typedef struct { ++ struct list_head ftype_list; /* list of fstypes */ ++ struct list_head sb_list; /* list of sb's per fstype */ ++ struct file_system_type *f_type; ++ struct filesystem_dmapi_operations *dmapiops; ++ dm_fsys_vector_t *vptr; ++ struct super_block *sb; ++} dm_vector_map_t; ++ ++ ++extern dm_session_t *dm_sessions; /* head of session list */ ++extern dm_fsreg_t *dm_registers; ++extern lock_t dm_reg_lock; /* lock for registration list */ ++ ++/* ++ * Kernel only prototypes. ++ */ ++ ++int dm_find_session_and_lock( ++ dm_sessid_t sid, ++ dm_session_t **sessionpp, ++ unsigned long *lcp); ++ ++int dm_find_msg_and_lock( ++ dm_sessid_t sid, ++ dm_token_t token, ++ dm_tokevent_t **tevpp, ++ unsigned long *lcp); ++ ++dm_tokevent_t * dm_evt_create_tevp( ++ dm_eventtype_t event, ++ int variable_size, ++ void **msgpp); ++ ++int dm_app_get_tdp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ short types, ++ dm_right_t right, ++ dm_tokdata_t **tdpp); ++ ++int dm_get_config_tdp( ++ void __user *hanp, ++ size_t hlen, ++ dm_tokdata_t **tdpp); ++ ++void dm_app_put_tdp( ++ dm_tokdata_t *tdp); ++ ++void dm_put_tevp( ++ dm_tokevent_t *tevp, ++ dm_tokdata_t *tdp); ++ ++void dm_evt_rele_tevp( ++ dm_tokevent_t *tevp, ++ int droprights); ++ ++int dm_enqueue_normal_event( ++ struct super_block *sbp, ++ dm_tokevent_t **tevpp, ++ int flags); ++ ++int dm_enqueue_mount_event( ++ struct super_block *sbp, ++ dm_tokevent_t *tevp); ++ ++int dm_enqueue_sendmsg_event( ++ dm_sessid_t targetsid, ++ dm_tokevent_t *tevp, ++ int synch); ++ ++int dm_enqueue_user_event( ++ dm_sessid_t sid, ++ dm_tokevent_t *tevp, ++ dm_token_t *tokenp); ++ ++int dm_obj_ref_query_rvp( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ int *rvp); ++ ++int dm_read_invis_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp); ++ ++int dm_write_invis_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ int flags, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp); ++ ++int dm_get_bulkattr_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp); ++ ++int dm_get_bulkall_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_attrname_t __user *attrnamep, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp); ++ ++int dm_get_dirattrs_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp); ++ ++int dm_get_allocinfo_rvp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_off_t __user *offp, ++ u_int nelem, ++ dm_extent_t __user *extentp, ++ u_int __user *nelemp, ++ int *rvp); ++ ++int dm_waitfor_destroy_attrname( ++ struct super_block *sb, ++ dm_attrname_t *attrnamep); ++ ++void dm_clear_fsreg( ++ dm_session_t *s); ++ ++int dm_add_fsys_entry( ++ struct super_block *sb, ++ dm_tokevent_t *tevp); ++ ++void dm_change_fsys_entry( ++ struct super_block *sb, ++ dm_fsstate_t newstate); ++ ++void dm_remove_fsys_entry( ++ struct super_block *sb); ++ ++dm_fsys_vector_t *dm_fsys_vector( ++ struct inode *ip); ++ ++struct filesystem_dmapi_operations *dm_fsys_ops( ++ struct super_block *sb); ++ ++void dm_fsys_ops_release( ++ struct super_block *sb); ++ ++int dm_waitfor_disp_session( ++ struct super_block *sb, ++ dm_tokevent_t *tevp, ++ dm_session_t **sessionpp, ++ unsigned long *lcp); ++ ++struct inode * dm_handle_to_ip ( ++ dm_handle_t *handlep, ++ short *typep); ++ ++int dm_check_dmapi_ip( ++ struct inode *ip); ++ ++dm_tokevent_t * dm_find_mount_tevp_and_lock( ++ dm_fsid_t *fsidp, ++ unsigned long *lcp); ++ ++int dm_path_to_hdl( ++ char __user *path, ++ void __user *hanp, ++ size_t __user *hlenp); ++ ++int dm_path_to_fshdl( ++ char __user *path, ++ void __user *hanp, ++ size_t __user *hlenp); ++ ++int dm_fd_to_hdl( ++ int fd, ++ void __user *hanp, ++ size_t __user *hlenp); ++ ++int dm_upgrade_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++int dm_downgrade_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++int dm_request_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int flags, ++ dm_right_t right); ++ ++int dm_release_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token); ++ ++int dm_query_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_right_t __user *rightp); ++ ++ ++int dm_set_eventlist( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_eventset_t __user *eventsetp, ++ u_int maxevent); ++ ++int dm_obj_ref_hold( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen); ++ ++int dm_obj_ref_rele( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen); ++ ++int dm_get_eventlist( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int nelem, ++ dm_eventset_t __user *eventsetp, ++ u_int __user *nelemp); ++ ++ ++int dm_set_disp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_eventset_t __user *eventsetp, ++ u_int maxevent); ++ ++ ++int dm_set_return_on_destroy( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ dm_boolean_t enable); ++ ++ ++int dm_get_mountinfo( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp); ++ ++void dm_link_event( ++ dm_tokevent_t *tevp, ++ dm_eventq_t *queue); ++ ++void dm_unlink_event( ++ dm_tokevent_t *tevp, ++ dm_eventq_t *queue); ++ ++int dm_open_by_handle_rvp( ++ unsigned int fd, ++ void __user *hanp, ++ size_t hlen, ++ int mode, ++ int *rvp); ++ ++int dm_copyin_handle( ++ void __user *hanp, ++ size_t hlen, ++ dm_handle_t *handlep); ++ ++int dm_release_disp_threads( ++ dm_fsid_t *fsid, ++ struct inode *inode, ++ int errno); ++ ++#endif /* _DMAPI_PRIVATE_H */ +Index: linux-2.6.26/fs/dmapi/dmapi_region.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_region.c +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++int ++dm_get_region( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int nelem, ++ dm_region_t __user *regbufp, ++ u_int __user *nelemp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_region(tdp->td_ip, tdp->td_right, ++ nelem, regbufp, nelemp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++ ++int ++dm_set_region( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int nelem, ++ dm_region_t __user *regbufp, ++ dm_boolean_t __user *exactflagp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->set_region(tdp->td_ip, tdp->td_right, ++ nelem, regbufp, exactflagp); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_register.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_register.c +@@ -0,0 +1,1644 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++/* LOOKUP_POSTIVE was removed in Linux 2.6 */ ++#ifndef LOOKUP_POSITIVE ++#define LOOKUP_POSITIVE 0 ++#endif ++ ++dm_fsreg_t *dm_registers; /* head of filesystem registration list */ ++int dm_fsys_cnt; /* number of filesystems on dm_registers list */ ++lock_t dm_reg_lock = SPIN_LOCK_UNLOCKED;/* lock for dm_registers */ ++ ++ ++ ++#ifdef CONFIG_PROC_FS ++static int ++fsreg_read_pfs(char *buffer, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len; ++ int i; ++ dm_fsreg_t *fsrp = (dm_fsreg_t*)data; ++ char statebuf[30]; ++ ++#define CHKFULL if(len >= count) break; ++#define ADDBUF(a,b) len += sprintf(buffer + len, a, b); CHKFULL; ++ ++ switch (fsrp->fr_state) { ++ case DM_STATE_MOUNTING: sprintf(statebuf, "mounting"); break; ++ case DM_STATE_MOUNTED: sprintf(statebuf, "mounted"); break; ++ case DM_STATE_UNMOUNTING: sprintf(statebuf, "unmounting"); break; ++ case DM_STATE_UNMOUNTED: sprintf(statebuf, "unmounted"); break; ++ default: ++ sprintf(statebuf, "unknown:%d", (int)fsrp->fr_state); ++ break; ++ } ++ ++ len=0; ++ while(1){ ++ ADDBUF("fsrp=0x%p\n", fsrp); ++ ADDBUF("fr_next=0x%p\n", fsrp->fr_next); ++ ADDBUF("fr_sb=0x%p\n", fsrp->fr_sb); ++ ADDBUF("fr_tevp=0x%p\n", fsrp->fr_tevp); ++ ADDBUF("fr_fsid=%c\n", '?'); ++ ADDBUF("fr_msg=0x%p\n", fsrp->fr_msg); ++ ADDBUF("fr_msgsize=%d\n", fsrp->fr_msgsize); ++ ADDBUF("fr_state=%s\n", statebuf); ++ ADDBUF("fr_dispq=%c\n", '?'); ++ ADDBUF("fr_dispcnt=%d\n", fsrp->fr_dispcnt); ++ ++ ADDBUF("fr_evt_dispq.eq_head=0x%p\n", fsrp->fr_evt_dispq.eq_head); ++ ADDBUF("fr_evt_dispq.eq_tail=0x%p\n", fsrp->fr_evt_dispq.eq_tail); ++ ADDBUF("fr_evt_dispq.eq_count=%d\n", fsrp->fr_evt_dispq.eq_count); ++ ++ ADDBUF("fr_queue=%c\n", '?'); ++ ADDBUF("fr_lock=%c\n", '?'); ++ ADDBUF("fr_hdlcnt=%d\n", fsrp->fr_hdlcnt); ++ ADDBUF("fr_vfscnt=%d\n", fsrp->fr_vfscnt); ++ ADDBUF("fr_unmount=%d\n", fsrp->fr_unmount); ++ ++ len += sprintf(buffer + len, "fr_rattr="); ++ CHKFULL; ++ for(i = 0; i <= DM_ATTR_NAME_SIZE; ++i){ ++ ADDBUF("%c", fsrp->fr_rattr.an_chars[i]); ++ } ++ CHKFULL; ++ len += sprintf(buffer + len, "\n"); ++ CHKFULL; ++ ++ for(i = 0; i < DM_EVENT_MAX; i++){ ++ if( fsrp->fr_sessp[i] != NULL ){ ++ ADDBUF("fr_sessp[%d]=", i); ++ ADDBUF("0x%p\n", fsrp->fr_sessp[i]); ++ } ++ } ++ CHKFULL; ++ ++ break; ++ } ++ ++ if (offset >= len) { ++ *start = buffer; ++ *eof = 1; ++ return 0; ++ } ++ *start = buffer + offset; ++ if ((len -= offset) > count) ++ return count; ++ *eof = 1; ++ ++ return len; ++} ++#endif ++ ++ ++/* Returns a pointer to the filesystem structure for the filesystem ++ referenced by fsidp. The caller is responsible for obtaining dm_reg_lock ++ before calling this routine. ++*/ ++ ++static dm_fsreg_t * ++dm_find_fsreg( ++ dm_fsid_t *fsidp) ++{ ++ dm_fsreg_t *fsrp; ++ ++ for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) { ++ if (!memcmp(&fsrp->fr_fsid, fsidp, sizeof(*fsidp))) ++ break; ++ } ++ return(fsrp); ++} ++ ++ ++/* Given a fsid_t, dm_find_fsreg_and_lock() finds the dm_fsreg_t structure ++ for that filesytem if one exists, and returns a pointer to the structure ++ after obtaining its 'fr_lock' so that the caller can safely modify the ++ dm_fsreg_t. The caller is responsible for releasing 'fr_lock'. ++*/ ++ ++static dm_fsreg_t * ++dm_find_fsreg_and_lock( ++ dm_fsid_t *fsidp, ++ unsigned long *lcp) /* address of returned lock cookie */ ++{ ++ dm_fsreg_t *fsrp; ++ ++ for (;;) { ++ *lcp = mutex_spinlock(&dm_reg_lock); ++ ++ if ((fsrp = dm_find_fsreg(fsidp)) == NULL) { ++ mutex_spinunlock(&dm_reg_lock, *lcp); ++ return(NULL); ++ } ++ if (spin_trylock(&fsrp->fr_lock)) { ++ nested_spinunlock(&dm_reg_lock); ++ return(fsrp); /* success */ ++ } ++ ++ /* If the second lock is not available, drop the first and ++ start over. This gives the CPU a chance to process any ++ interrupts, and also allows processes which want a fr_lock ++ for a different filesystem to proceed. ++ */ ++ ++ mutex_spinunlock(&dm_reg_lock, *lcp); ++ } ++} ++ ++ ++/* dm_add_fsys_entry() is called when a DM_EVENT_MOUNT event is about to be ++ sent. It creates a dm_fsreg_t structure for the filesystem and stores a ++ pointer to a copy of the mount event within that structure so that it is ++ available for subsequent dm_get_mountinfo() calls. ++*/ ++ ++int ++dm_add_fsys_entry( ++ struct super_block *sb, ++ dm_tokevent_t *tevp) ++{ ++ dm_fsreg_t *fsrp; ++ int msgsize; ++ void *msg; ++ unsigned long lc; /* lock cookie */ ++ dm_fsid_t fsid; ++ struct filesystem_dmapi_operations *dops; ++ ++ dops = dm_fsys_ops(sb); ++ ASSERT(dops); ++ dops->get_fsid(sb, &fsid); ++ ++ /* Allocate and initialize a dm_fsreg_t structure for the filesystem. */ ++ ++ msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_event); ++ msg = kmalloc(msgsize, GFP_KERNEL); ++ if (msg == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ memcpy(msg, &tevp->te_event, msgsize); ++ ++ fsrp = kmem_cache_alloc(dm_fsreg_cachep, GFP_KERNEL); ++ if (fsrp == NULL) { ++ kfree(msg); ++ printk("%s/%d: kmem_cache_alloc(dm_fsreg_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ memset(fsrp, 0, sizeof(*fsrp)); ++ ++ fsrp->fr_sb = sb; ++ fsrp->fr_tevp = tevp; ++ memcpy(&fsrp->fr_fsid, &fsid, sizeof(fsid)); ++ fsrp->fr_msg = msg; ++ fsrp->fr_msgsize = msgsize; ++ fsrp->fr_state = DM_STATE_MOUNTING; ++ sv_init(&fsrp->fr_dispq, SV_DEFAULT, "fr_dispq"); ++ sv_init(&fsrp->fr_queue, SV_DEFAULT, "fr_queue"); ++ spinlock_init(&fsrp->fr_lock, "fr_lock"); ++ ++ /* If no other mounted DMAPI filesystem already has this same ++ fsid_t, then add this filesystem to the list. ++ */ ++ ++ lc = mutex_spinlock(&dm_reg_lock); ++ ++ if (!dm_find_fsreg(&fsid)) { ++ fsrp->fr_next = dm_registers; ++ dm_registers = fsrp; ++ dm_fsys_cnt++; ++ mutex_spinunlock(&dm_reg_lock, lc); ++#ifdef CONFIG_PROC_FS ++ { ++ char buf[100]; ++ struct proc_dir_entry *entry; ++ ++ sprintf(buf, DMAPI_DBG_PROCFS "/fsreg/0x%p", fsrp); ++ entry = create_proc_read_entry(buf, 0, NULL, fsreg_read_pfs, fsrp); ++ entry->owner = THIS_MODULE; ++ } ++#endif ++ return(0); ++ } ++ ++ /* A fsid_t collision occurred, so prevent this new filesystem from ++ mounting. ++ */ ++ ++ mutex_spinunlock(&dm_reg_lock, lc); ++ ++ sv_destroy(&fsrp->fr_dispq); ++ sv_destroy(&fsrp->fr_queue); ++ spinlock_destroy(&fsrp->fr_lock); ++ kfree(msg); ++ kmem_cache_free(dm_fsreg_cachep, fsrp); ++ return(-EBUSY); ++} ++ ++ ++/* dm_change_fsys_entry() is called whenever a filesystem's mount state is ++ about to change. The state is changed to DM_STATE_MOUNTED after a ++ successful DM_EVENT_MOUNT event or after a failed unmount. It is changed ++ to DM_STATE_UNMOUNTING after a successful DM_EVENT_PREUNMOUNT event. ++ Finally, the state is changed to DM_STATE_UNMOUNTED after a successful ++ unmount. It stays in this state until the DM_EVENT_UNMOUNT event is ++ queued, at which point the filesystem entry is removed. ++*/ ++ ++void ++dm_change_fsys_entry( ++ struct super_block *sb, ++ dm_fsstate_t newstate) ++{ ++ dm_fsreg_t *fsrp; ++ int seq_error; ++ unsigned long lc; /* lock cookie */ ++ dm_fsid_t fsid; ++ struct filesystem_dmapi_operations *dops; ++ ++ /* Find the filesystem referenced by the sb's fsid_t. This should ++ always succeed. ++ */ ++ ++ dops = dm_fsys_ops(sb); ++ ASSERT(dops); ++ dops->get_fsid(sb, &fsid); ++ ++ if ((fsrp = dm_find_fsreg_and_lock(&fsid, &lc)) == NULL) { ++ panic("dm_change_fsys_entry: can't find DMAPI fsrp for " ++ "sb %p\n", sb); ++ } ++ ++ /* Make sure that the new state is acceptable given the current state ++ of the filesystem. Any error here is a major DMAPI/filesystem ++ screwup. ++ */ ++ ++ seq_error = 0; ++ switch (newstate) { ++ case DM_STATE_MOUNTED: ++ if (fsrp->fr_state != DM_STATE_MOUNTING && ++ fsrp->fr_state != DM_STATE_UNMOUNTING) { ++ seq_error++; ++ } ++ break; ++ case DM_STATE_UNMOUNTING: ++ if (fsrp->fr_state != DM_STATE_MOUNTED) ++ seq_error++; ++ break; ++ case DM_STATE_UNMOUNTED: ++ if (fsrp->fr_state != DM_STATE_UNMOUNTING) ++ seq_error++; ++ break; ++ default: ++ seq_error++; ++ break; ++ } ++ if (seq_error) { ++ panic("dm_change_fsys_entry: DMAPI sequence error: old state " ++ "%d, new state %d, fsrp %p\n", fsrp->fr_state, ++ newstate, fsrp); ++ } ++ ++ /* If the old state was DM_STATE_UNMOUNTING, then processes could be ++ sleeping in dm_handle_to_ip() waiting for their DM_NO_TOKEN handles ++ to be translated to inodes. Wake them up so that they either ++ continue (new state is DM_STATE_MOUNTED) or fail (new state is ++ DM_STATE_UNMOUNTED). ++ */ ++ ++ if (fsrp->fr_state == DM_STATE_UNMOUNTING) { ++ if (fsrp->fr_hdlcnt) ++ sv_broadcast(&fsrp->fr_queue); ++ } ++ ++ /* Change the filesystem's mount state to its new value. */ ++ ++ fsrp->fr_state = newstate; ++ fsrp->fr_tevp = NULL; /* not valid after DM_STATE_MOUNTING */ ++ ++ /* If the new state is DM_STATE_UNMOUNTING, wait until any application ++ threads currently in the process of making VFS_VGET and VFS_ROOT ++ calls are done before we let this unmount thread continue the ++ unmount. (We want to make sure that the unmount will see these ++ inode references during its scan.) ++ */ ++ ++ if (newstate == DM_STATE_UNMOUNTING) { ++ while (fsrp->fr_vfscnt) { ++ fsrp->fr_unmount++; ++ sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); ++ lc = mutex_spinlock(&fsrp->fr_lock); ++ fsrp->fr_unmount--; ++ } ++ } ++ ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++} ++ ++ ++/* dm_remove_fsys_entry() gets called after a failed mount or after an ++ DM_EVENT_UNMOUNT event has been queued. (The filesystem entry must stay ++ until the DM_EVENT_UNMOUNT reply is queued so that the event can use the ++ 'fr_sessp' list to see which session to send the event to.) ++*/ ++ ++void ++dm_remove_fsys_entry( ++ struct super_block *sb) ++{ ++ dm_fsreg_t **fsrpp; ++ dm_fsreg_t *fsrp; ++ unsigned long lc; /* lock cookie */ ++ struct filesystem_dmapi_operations *dops; ++ dm_fsid_t fsid; ++ ++ dops = dm_fsys_ops(sb); ++ ASSERT(dops); ++ dops->get_fsid(sb, &fsid); ++ ++ /* Find the filesystem referenced by the sb's fsid_t and dequeue ++ it after verifying that the fr_state shows a filesystem that is ++ either mounting or unmounted. ++ */ ++ ++ lc = mutex_spinlock(&dm_reg_lock); ++ ++ fsrpp = &dm_registers; ++ while ((fsrp = *fsrpp) != NULL) { ++ if (!memcmp(&fsrp->fr_fsid, &fsid, sizeof(fsrp->fr_fsid))) ++ break; ++ fsrpp = &fsrp->fr_next; ++ } ++ if (fsrp == NULL) { ++ mutex_spinunlock(&dm_reg_lock, lc); ++ panic("dm_remove_fsys_entry: can't find DMAPI fsrp for " ++ "sb %p\n", sb); ++ } ++ ++ nested_spinlock(&fsrp->fr_lock); ++ ++ /* Verify that it makes sense to remove this entry. */ ++ ++ if (fsrp->fr_state != DM_STATE_MOUNTING && ++ fsrp->fr_state != DM_STATE_UNMOUNTED) { ++ nested_spinunlock(&fsrp->fr_lock); ++ mutex_spinunlock(&dm_reg_lock, lc); ++ panic("dm_remove_fsys_entry: DMAPI sequence error: old state " ++ "%d, fsrp %p\n", fsrp->fr_state, fsrp); ++ } ++ ++ *fsrpp = fsrp->fr_next; ++ dm_fsys_cnt--; ++ ++ nested_spinunlock(&dm_reg_lock); ++ ++ /* Since the filesystem is about to finish unmounting, we must be sure ++ that no inodes are being referenced within the filesystem before we ++ let this event thread continue. If the filesystem is currently in ++ state DM_STATE_MOUNTING, then we know by definition that there can't ++ be any references. If the filesystem is DM_STATE_UNMOUNTED, then ++ any application threads referencing handles with DM_NO_TOKEN should ++ have already been awakened by dm_change_fsys_entry and should be ++ long gone by now. Just in case they haven't yet left, sleep here ++ until they are really gone. ++ */ ++ ++ while (fsrp->fr_hdlcnt) { ++ fsrp->fr_unmount++; ++ sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); ++ lc = mutex_spinlock(&fsrp->fr_lock); ++ fsrp->fr_unmount--; ++ } ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ ++ /* Release all memory. */ ++ ++#ifdef CONFIG_PROC_FS ++ { ++ char buf[100]; ++ sprintf(buf, DMAPI_DBG_PROCFS "/fsreg/0x%p", fsrp); ++ remove_proc_entry(buf, NULL); ++ } ++#endif ++ dm_fsys_ops_release(sb); ++ sv_destroy(&fsrp->fr_dispq); ++ sv_destroy(&fsrp->fr_queue); ++ spinlock_destroy(&fsrp->fr_lock); ++ kfree(fsrp->fr_msg); ++ kmem_cache_free(dm_fsreg_cachep, fsrp); ++} ++ ++ ++/* Get an inode for the object referenced by handlep. We cannot use ++ altgetvfs() because it fails if the VFS_OFFLINE bit is set, which means ++ that any call to dm_handle_to_ip() while a umount is in progress would ++ return an error, even if the umount can't possibly succeed because users ++ are in the filesystem. The requests would start to fail as soon as the ++ umount begins, even before the application receives the DM_EVENT_PREUNMOUNT ++ event. ++ ++ dm_handle_to_ip() emulates the behavior of lookup() while an unmount is ++ in progress. Any call to dm_handle_to_ip() while the filesystem is in the ++ DM_STATE_UNMOUNTING state will block. If the unmount eventually succeeds, ++ the requests will wake up and fail. If the unmount fails, the requests will ++ wake up and complete normally. ++ ++ While a filesystem is in state DM_STATE_MOUNTING, dm_handle_to_ip() will ++ fail all requests. Per the DMAPI spec, the only handles in the filesystem ++ which are valid during a mount event are the handles within the event ++ itself. ++*/ ++ ++struct inode * ++dm_handle_to_ip( ++ dm_handle_t *handlep, ++ short *typep) ++{ ++ dm_fsreg_t *fsrp; ++ short type; ++ unsigned long lc; /* lock cookie */ ++ int error = 0; ++ dm_fid_t *fidp; ++ struct super_block *sb; ++ struct inode *ip; ++ int filetype; ++ struct filesystem_dmapi_operations *dmapiops; ++ ++ if ((fsrp = dm_find_fsreg_and_lock(&handlep->ha_fsid, &lc)) == NULL) ++ return NULL; ++ ++ fidp = (dm_fid_t*)&handlep->ha_fid; ++ /* If mounting, and we are not asking for a filesystem handle, ++ * then fail the request. (dm_fid_len==0 for fshandle) ++ */ ++ if ((fsrp->fr_state == DM_STATE_MOUNTING) && ++ (fidp->dm_fid_len != 0)) { ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ return NULL; ++ } ++ ++ for (;;) { ++ if (fsrp->fr_state == DM_STATE_MOUNTING) ++ break; ++ if (fsrp->fr_state == DM_STATE_MOUNTED) ++ break; ++ if (fsrp->fr_state == DM_STATE_UNMOUNTED) { ++ if (fsrp->fr_unmount && fsrp->fr_hdlcnt == 0) ++ sv_broadcast(&fsrp->fr_queue); ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ return NULL; ++ } ++ ++ /* Must be DM_STATE_UNMOUNTING. */ ++ ++ fsrp->fr_hdlcnt++; ++ sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); ++ lc = mutex_spinlock(&fsrp->fr_lock); ++ fsrp->fr_hdlcnt--; ++ } ++ ++ fsrp->fr_vfscnt++; ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ ++ /* Now that the mutex is released, wait until we have access to the ++ inode. ++ */ ++ ++ sb = fsrp->fr_sb; ++ error = -ENOSYS; ++ dmapiops = dm_fsys_ops(sb); ++ ASSERT(dmapiops); ++ if (dmapiops->fh_to_inode) ++ error = dmapiops->fh_to_inode(sb, &ip, (void*)fidp); ++ ++ lc = mutex_spinlock(&fsrp->fr_lock); ++ ++ fsrp->fr_vfscnt--; ++ if (fsrp->fr_unmount && fsrp->fr_vfscnt == 0) ++ sv_broadcast(&fsrp->fr_queue); ++ ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ if (error || ip == NULL) ++ return NULL; ++ ++ filetype = ip->i_mode & S_IFMT; ++ if (fidp->dm_fid_len == 0) { ++ type = DM_TDT_VFS; ++ } else if (filetype == S_IFREG) { ++ type = DM_TDT_REG; ++ } else if (filetype == S_IFDIR) { ++ type = DM_TDT_DIR; ++ } else if (filetype == S_IFLNK) { ++ type = DM_TDT_LNK; ++ } else { ++ type = DM_TDT_OTH; ++ } ++ *typep = type; ++ return ip; ++} ++ ++ ++int ++dm_ip_to_handle( ++ struct inode *ip, ++ dm_handle_t *handlep) ++{ ++ int error; ++ dm_fid_t fid; ++ dm_fsid_t fsid; ++ int hsize; ++ struct filesystem_dmapi_operations *dops; ++ ++ dops = dm_fsys_ops(ip->i_sb); ++ ASSERT(dops); ++ ++ error = dops->inode_to_fh(ip, &fid, &fsid); ++ if (error) ++ return error; ++ ++ memcpy(&handlep->ha_fsid, &fsid, sizeof(fsid)); ++ memcpy(&handlep->ha_fid, &fid, fid.dm_fid_len + sizeof fid.dm_fid_len); ++ hsize = DM_HSIZE(*handlep); ++ memset((char *)handlep + hsize, 0, sizeof(*handlep) - hsize); ++ return 0; ++} ++ ++ ++/* Given an inode, check if that inode resides in filesystem that supports ++ DMAPI. Returns zero if the inode is in a DMAPI filesystem, otherwise ++ returns an errno. ++*/ ++ ++int ++dm_check_dmapi_ip( ++ struct inode *ip) ++{ ++ dm_handle_t handle; ++ /* REFERENCED */ ++ dm_fsreg_t *fsrp; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ if ((error = dm_ip_to_handle(ip, &handle)) != 0) ++ return(error); ++ ++ if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL) ++ return(-EBADF); ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ return(0); ++} ++ ++ ++/* Return a pointer to the DM_EVENT_MOUNT event while a mount is still in ++ progress. This is only called by dm_get_config and dm_get_config_events ++ which need to access the filesystem during a mount but which don't have ++ a session and token to use. ++*/ ++ ++dm_tokevent_t * ++dm_find_mount_tevp_and_lock( ++ dm_fsid_t *fsidp, ++ unsigned long *lcp) /* address of returned lock cookie */ ++{ ++ dm_fsreg_t *fsrp; ++ ++ if ((fsrp = dm_find_fsreg_and_lock(fsidp, lcp)) == NULL) ++ return(NULL); ++ ++ if (!fsrp->fr_tevp || fsrp->fr_state != DM_STATE_MOUNTING) { ++ mutex_spinunlock(&fsrp->fr_lock, *lcp); ++ return(NULL); ++ } ++ nested_spinlock(&fsrp->fr_tevp->te_lock); ++ nested_spinunlock(&fsrp->fr_lock); ++ return(fsrp->fr_tevp); ++} ++ ++ ++/* Wait interruptibly until a session registers disposition for 'event' in ++ filesystem 'sb'. Upon successful exit, both the filesystem's dm_fsreg_t ++ structure and the session's dm_session_t structure are locked. The caller ++ is responsible for unlocking both structures using the returned cookies. ++ ++ Warning: The locks can be dropped in any order, but the 'lc2p' cookie MUST ++ BE USED FOR THE FIRST UNLOCK, and the lc1p cookie must be used for the ++ second unlock. If this is not done, the CPU will be interruptible while ++ holding a mutex, which could deadlock the machine! ++*/ ++ ++static int ++dm_waitfor_disp( ++ struct super_block *sb, ++ dm_tokevent_t *tevp, ++ dm_fsreg_t **fsrpp, ++ unsigned long *lc1p, /* addr of first returned lock cookie */ ++ dm_session_t **sessionpp, ++ unsigned long *lc2p) /* addr of 2nd returned lock cookie */ ++{ ++ dm_eventtype_t event = tevp->te_msg.ev_type; ++ dm_session_t *s; ++ dm_fsreg_t *fsrp; ++ dm_fsid_t fsid; ++ struct filesystem_dmapi_operations *dops; ++ ++ dops = dm_fsys_ops(sb); ++ ASSERT(dops); ++ ++ dops->get_fsid(sb, &fsid); ++ if ((fsrp = dm_find_fsreg_and_lock(&fsid, lc1p)) == NULL) ++ return -ENOENT; ++ ++ /* If no session is registered for this event in the specified ++ filesystem, then sleep interruptibly until one does. ++ */ ++ ++ for (;;) { ++ int rc = 0; ++ ++ /* The dm_find_session_and_lock() call is needed because a ++ session that is in the process of being removed might still ++ be in the dm_fsreg_t structure but won't be in the ++ dm_sessions list. ++ */ ++ ++ if ((s = fsrp->fr_sessp[event]) != NULL && ++ dm_find_session_and_lock(s->sn_sessid, &s, lc2p) == 0) { ++ break; ++ } ++ ++ /* Noone is currently registered. DM_EVENT_UNMOUNT events ++ don't wait for anyone to register because the unmount is ++ already past the point of no return. ++ */ ++ ++ if (event == DM_EVENT_UNMOUNT) { ++ mutex_spinunlock(&fsrp->fr_lock, *lc1p); ++ return -ENOENT; ++ } ++ ++ /* Wait until a session registers for disposition of this ++ event. ++ */ ++ ++ fsrp->fr_dispcnt++; ++ dm_link_event(tevp, &fsrp->fr_evt_dispq); ++ ++ sv_wait_sig(&fsrp->fr_dispq, 1, &fsrp->fr_lock, *lc1p); ++ rc = signal_pending(current); ++ ++ *lc1p = mutex_spinlock(&fsrp->fr_lock); ++ fsrp->fr_dispcnt--; ++ dm_unlink_event(tevp, &fsrp->fr_evt_dispq); ++#ifdef HAVE_DM_QUEUE_FLUSH ++ if (tevp->te_flags & DM_TEF_FLUSH) { ++ mutex_spinunlock(&fsrp->fr_lock, *lc1p); ++ return tevp->te_reply; ++ } ++#endif /* HAVE_DM_QUEUE_FLUSH */ ++ if (rc) { /* if signal was received */ ++ mutex_spinunlock(&fsrp->fr_lock, *lc1p); ++ return -EINTR; ++ } ++ } ++ *sessionpp = s; ++ *fsrpp = fsrp; ++ return 0; ++} ++ ++ ++/* Returns the session pointer for the session registered for an event ++ in the given sb. If successful, the session is locked upon return. The ++ caller is responsible for releasing the lock. If no session is currently ++ registered for the event, dm_waitfor_disp_session() will sleep interruptibly ++ until a registration occurs. ++*/ ++ ++int ++dm_waitfor_disp_session( ++ struct super_block *sb, ++ dm_tokevent_t *tevp, ++ dm_session_t **sessionpp, ++ unsigned long *lcp) ++{ ++ dm_fsreg_t *fsrp; ++ unsigned long lc2; ++ int error; ++ ++ if (tevp->te_msg.ev_type < 0 || tevp->te_msg.ev_type > DM_EVENT_MAX) ++ return(-EIO); ++ ++ error = dm_waitfor_disp(sb, tevp, &fsrp, lcp, sessionpp, &lc2); ++ if (!error) ++ mutex_spinunlock(&fsrp->fr_lock, lc2); /* rev. cookie order*/ ++ return(error); ++} ++ ++ ++/* Find the session registered for the DM_EVENT_DESTROY event on the specified ++ filesystem, sleeping if necessary until registration occurs. Once found, ++ copy the session's return-on-destroy attribute name, if any, back to the ++ caller. ++*/ ++ ++int ++dm_waitfor_destroy_attrname( ++ struct super_block *sbp, ++ dm_attrname_t *attrnamep) ++{ ++ dm_tokevent_t *tevp; ++ dm_session_t *s; ++ dm_fsreg_t *fsrp; ++ int error; ++ unsigned long lc1; /* first lock cookie */ ++ unsigned long lc2; /* second lock cookie */ ++ void *msgp; ++ ++ tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, 1, (void**)&msgp); ++ error = dm_waitfor_disp(sbp, tevp, &fsrp, &lc1, &s, &lc2); ++ if (!error) { ++ *attrnamep = fsrp->fr_rattr; /* attribute or zeros */ ++ mutex_spinunlock(&s->sn_qlock, lc2); /* rev. cookie order */ ++ mutex_spinunlock(&fsrp->fr_lock, lc1); ++ } ++ dm_evt_rele_tevp(tevp,0); ++ return(error); ++} ++ ++ ++/* Unregisters the session for the disposition of all events on all ++ filesystems. This routine is not called until the session has been ++ dequeued from the session list and its session lock has been dropped, ++ but before the actual structure is freed, so it is safe to grab the ++ 'dm_reg_lock' here. If dm_waitfor_disp_session() happens to be called ++ by another thread, it won't find this session on the session list and ++ will wait until a new session registers. ++*/ ++ ++void ++dm_clear_fsreg( ++ dm_session_t *s) ++{ ++ dm_fsreg_t *fsrp; ++ int event; ++ unsigned long lc; /* lock cookie */ ++ ++ lc = mutex_spinlock(&dm_reg_lock); ++ ++ for (fsrp = dm_registers; fsrp != NULL; fsrp = fsrp->fr_next) { ++ nested_spinlock(&fsrp->fr_lock); ++ for (event = 0; event < DM_EVENT_MAX; event++) { ++ if (fsrp->fr_sessp[event] != s) ++ continue; ++ fsrp->fr_sessp[event] = NULL; ++ if (event == DM_EVENT_DESTROY) ++ memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr)); ++ } ++ nested_spinunlock(&fsrp->fr_lock); ++ } ++ ++ mutex_spinunlock(&dm_reg_lock, lc); ++} ++ ++ ++/* ++ * Return the handle for the object named by path. ++ */ ++ ++int ++dm_path_to_hdl( ++ char __user *path, /* any path name */ ++ void __user *hanp, /* user's data buffer */ ++ size_t __user *hlenp) /* set to size of data copied */ ++{ ++ /* REFERENCED */ ++ dm_fsreg_t *fsrp; ++ dm_handle_t handle; ++ size_t hlen; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ struct nameidata nd; ++ struct inode *inode; ++ size_t len; ++ char *name; ++ struct filesystem_dmapi_operations *dops; ++ ++ /* XXX get things straightened out so getname() works here? */ ++ if (!(len = strnlen_user(path, PATH_MAX))) ++ return(-EFAULT); ++ if (len == 1) ++ return(-ENOENT); ++ if (len > PATH_MAX) ++ return(-ENAMETOOLONG); ++ name = kmalloc(len, GFP_KERNEL); ++ if (name == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return(-ENOMEM); ++ } ++ if (copy_from_user(name, path, len)) { ++ kfree(name); ++ return(-EFAULT); ++ } ++ ++ error = path_lookup(name, LOOKUP_POSITIVE, &nd); ++ kfree(name); ++ if (error) ++ return error; ++ ++ ASSERT(nd.path.dentry); ++ ASSERT(nd.path.dentry->d_inode); ++ inode = igrab(nd.path.dentry->d_inode); ++ path_put(&nd.path); ++ ++ dops = dm_fsys_ops(inode->i_sb); ++ if (dops == NULL) { ++ /* No longer in a dmapi-capable filesystem...Toto */ ++ iput(inode); ++ return -EINVAL; ++ } ++ ++ /* we need the inode */ ++ error = dm_ip_to_handle(inode, &handle); ++ iput(inode); ++ if (error) ++ return(error); ++ ++ if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL) ++ return(-EBADF); ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ ++ hlen = DM_HSIZE(handle); ++ ++ if (copy_to_user(hanp, &handle, (int)hlen)) ++ return(-EFAULT); ++ if (put_user(hlen,hlenp)) ++ return(-EFAULT); ++ return 0; ++} ++ ++ ++/* ++ * Return the handle for the file system containing the object named by path. ++ */ ++ ++int ++dm_path_to_fshdl( ++ char __user *path, /* any path name */ ++ void __user *hanp, /* user's data buffer */ ++ size_t __user *hlenp) /* set to size of data copied */ ++{ ++ /* REFERENCED */ ++ dm_fsreg_t *fsrp; ++ dm_handle_t handle; ++ size_t hlen; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ struct nameidata nd; ++ struct inode *inode; ++ size_t len; ++ char *name; ++ struct filesystem_dmapi_operations *dops; ++ ++ /* XXX get things straightened out so getname() works here? */ ++ if(!(len = strnlen_user(path, PATH_MAX))) ++ return(-EFAULT); ++ if (len == 1) ++ return(-ENOENT); ++ if (len > PATH_MAX) ++ return(-ENAMETOOLONG); ++ name = kmalloc(len, GFP_KERNEL); ++ if (name == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return(-ENOMEM); ++ } ++ if (copy_from_user(name, path, len)) { ++ kfree(name); ++ return(-EFAULT); ++ } ++ ++ error = path_lookup(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd); ++ kfree(name); ++ if (error) ++ return error; ++ ++ ASSERT(nd.path.dentry); ++ ASSERT(nd.path.dentry->d_inode); ++ ++ inode = igrab(nd.path.dentry->d_inode); ++ path_put(&nd.path); ++ ++ dops = dm_fsys_ops(inode->i_sb); ++ if (dops == NULL) { ++ /* No longer in a dmapi-capable filesystem...Toto */ ++ iput(inode); ++ return -EINVAL; ++ } ++ ++ error = dm_ip_to_handle(inode, &handle); ++ iput(inode); ++ ++ if (error) ++ return(error); ++ ++ if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL) ++ return(-EBADF); ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ ++ hlen = DM_FSHSIZE; ++ if(copy_to_user(hanp, &handle, (int)hlen)) ++ return(-EFAULT); ++ if(put_user(hlen,hlenp)) ++ return(-EFAULT); ++ return 0; ++} ++ ++ ++int ++dm_fd_to_hdl( ++ int fd, /* any file descriptor */ ++ void __user *hanp, /* user's data buffer */ ++ size_t __user *hlenp) /* set to size of data copied */ ++{ ++ /* REFERENCED */ ++ dm_fsreg_t *fsrp; ++ dm_handle_t handle; ++ size_t hlen; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ struct file *filep = fget(fd); ++ struct inode *ip = filep->f_dentry->d_inode; ++ ++ if (!filep) ++ return(-EBADF); ++ if ((error = dm_ip_to_handle(ip, &handle)) != 0) ++ return(error); ++ ++ if ((fsrp = dm_find_fsreg_and_lock(&handle.ha_fsid, &lc)) == NULL) ++ return(-EBADF); ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ ++ hlen = DM_HSIZE(handle); ++ if (copy_to_user(hanp, &handle, (int)hlen)) ++ return(-EFAULT); ++ fput(filep); ++ if(put_user(hlen, hlenp)) ++ return(-EFAULT); ++ return 0; ++} ++ ++ ++/* Enable events on an object. */ ++ ++int ++dm_set_eventlist( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_eventset_t __user *eventsetp, ++ u_int maxevent) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_eventset_t eventset; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ if (copy_from_user(&eventset, eventsetp, sizeof(eventset))) ++ return(-EFAULT); ++ ++ /* Do some minor sanity checking. */ ++ ++ if (maxevent == 0 || maxevent > DM_EVENT_MAX) ++ return(-EINVAL); ++ ++ /* Access the specified object. */ ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->set_eventlist(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), ++ &eventset, maxevent); ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++/* Return the list of enabled events for an object. */ ++ ++int ++dm_get_eventlist( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int nelem, ++ dm_eventset_t __user *eventsetp, ++ u_int __user *nelemp) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ dm_eventset_t eventset; ++ u_int elem; ++ int error; ++ ++ if (nelem == 0) ++ return(-EINVAL); ++ ++ /* Access the specified object. */ ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ /* Get the object's event list. */ ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->get_eventlist(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), ++ nelem, &eventset, &elem); ++ ++ dm_app_put_tdp(tdp); ++ ++ if (error) ++ return(error); ++ ++ if (copy_to_user(eventsetp, &eventset, sizeof(eventset))) ++ return(-EFAULT); ++ if (put_user(nelem, nelemp)) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* Register for disposition of events. The handle must either be the ++ global handle or must be the handle of a file system. The list of events ++ is pointed to by eventsetp. ++*/ ++ ++int ++dm_set_disp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_eventset_t __user *eventsetp, ++ u_int maxevent) ++{ ++ dm_session_t *s; ++ dm_fsreg_t *fsrp; ++ dm_tokdata_t *tdp; ++ dm_eventset_t eventset; ++ int error; ++ unsigned long lc1; /* first lock cookie */ ++ unsigned long lc2; /* second lock cookie */ ++ u_int i; ++ ++ /* Copy in and validate the event mask. Only the lower maxevent bits ++ are meaningful, so clear any bits set above maxevent. ++ */ ++ ++ if (maxevent == 0 || maxevent > DM_EVENT_MAX) ++ return(-EINVAL); ++ if (copy_from_user(&eventset, eventsetp, sizeof(eventset))) ++ return(-EFAULT); ++ eventset &= (1 << maxevent) - 1; ++ ++ /* If the caller specified the global handle, then the only valid token ++ is DM_NO_TOKEN, and the only valid event in the event mask is ++ DM_EVENT_MOUNT. If it is set, add the session to the list of ++ sessions that want to receive mount events. If it is clear, remove ++ the session from the list. Since DM_EVENT_MOUNT events never block ++ waiting for a session to register, there is noone to wake up if we ++ do add the session to the list. ++ */ ++ ++ if (DM_GLOBALHAN(hanp, hlen)) { ++ if (token != DM_NO_TOKEN) ++ return(-EINVAL); ++ if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0) ++ return(error); ++ if (eventset == 0) { ++ s->sn_flags &= ~DM_SN_WANTMOUNT; ++ error = 0; ++ } else if (eventset == 1 << DM_EVENT_MOUNT) { ++ s->sn_flags |= DM_SN_WANTMOUNT; ++ error = 0; ++ } else { ++ error = -EINVAL; ++ } ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ return(error); ++ } ++ ++ /* Since it's not the global handle, it had better be a filesystem ++ handle. Verify that the first 'maxevent' events in the event list ++ are all valid for a filesystem handle. ++ */ ++ ++ if (eventset & ~DM_VALID_DISP_EVENTS) ++ return(-EINVAL); ++ ++ /* Verify that the session is valid, that the handle is a filesystem ++ handle, and that the filesystem is capable of sending events. (If ++ a dm_fsreg_t structure exists, then the filesystem can issue events.) ++ */ ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsrp = dm_find_fsreg_and_lock(&tdp->td_handle.ha_fsid, &lc1); ++ if (fsrp == NULL) { ++ dm_app_put_tdp(tdp); ++ return(-EINVAL); ++ } ++ ++ /* Now that we own 'fsrp->fr_lock', get the lock on the session so that ++ it can't disappear while we add it to the filesystem's event mask. ++ */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { ++ mutex_spinunlock(&fsrp->fr_lock, lc1); ++ dm_app_put_tdp(tdp); ++ return(error); ++ } ++ ++ /* Update the event disposition array for this filesystem, adding ++ and/or removing the session as appropriate. If this session is ++ dropping registration for DM_EVENT_DESTROY, or is overriding some ++ other session's registration for DM_EVENT_DESTROY, then clear any ++ any attr-on-destroy attribute name also. ++ */ ++ ++ for (i = 0; i < DM_EVENT_MAX; i++) { ++ if (DMEV_ISSET(i, eventset)) { ++ if (i == DM_EVENT_DESTROY && fsrp->fr_sessp[i] != s) ++ memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr)); ++ fsrp->fr_sessp[i] = s; ++ } else if (fsrp->fr_sessp[i] == s) { ++ if (i == DM_EVENT_DESTROY) ++ memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr)); ++ fsrp->fr_sessp[i] = NULL; ++ } ++ } ++ mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ ++ ++ /* Wake up all processes waiting for a disposition on this filesystem ++ in case any of them happen to be waiting for an event which we just ++ added. ++ */ ++ ++ if (fsrp->fr_dispcnt) ++ sv_broadcast(&fsrp->fr_dispq); ++ ++ mutex_spinunlock(&fsrp->fr_lock, lc1); ++ ++ dm_app_put_tdp(tdp); ++ return(0); ++} ++ ++ ++/* ++ * Register a specific attribute name with a filesystem. The value of ++ * the attribute is to be returned with an asynchronous destroy event. ++ */ ++ ++int ++dm_set_return_on_destroy( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_attrname_t __user *attrnamep, ++ dm_boolean_t enable) ++{ ++ dm_attrname_t attrname; ++ dm_tokdata_t *tdp; ++ dm_fsreg_t *fsrp; ++ dm_session_t *s; ++ int error; ++ unsigned long lc1; /* first lock cookie */ ++ unsigned long lc2; /* second lock cookie */ ++ ++ /* If a dm_attrname_t is provided, copy it in and validate it. */ ++ ++ if (enable && (error = copy_from_user(&attrname, attrnamep, sizeof(attrname))) != 0) ++ return(error); ++ ++ /* Validate the filesystem handle and use it to get the filesystem's ++ disposition structure. ++ */ ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_EXCL, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsrp = dm_find_fsreg_and_lock(&tdp->td_handle.ha_fsid, &lc1); ++ if (fsrp == NULL) { ++ dm_app_put_tdp(tdp); ++ return(-EINVAL); ++ } ++ ++ /* Now that we own 'fsrp->fr_lock', get the lock on the session so that ++ it can't disappear while we add it to the filesystem's event mask. ++ */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { ++ mutex_spinunlock(&fsrp->fr_lock, lc1); ++ dm_app_put_tdp(tdp); ++ return(error); ++ } ++ ++ /* A caller cannot disable return-on-destroy if he is not registered ++ for DM_EVENT_DESTROY. Enabling return-on-destroy is an implicit ++ dm_set_disp() for DM_EVENT_DESTROY; we wake up all processes ++ waiting for a disposition in case any was waiting for a ++ DM_EVENT_DESTROY event. ++ */ ++ ++ error = 0; ++ if (enable) { ++ fsrp->fr_sessp[DM_EVENT_DESTROY] = s; ++ fsrp->fr_rattr = attrname; ++ if (fsrp->fr_dispcnt) ++ sv_broadcast(&fsrp->fr_dispq); ++ } else if (fsrp->fr_sessp[DM_EVENT_DESTROY] != s) { ++ error = -EINVAL; ++ } else { ++ memset(&fsrp->fr_rattr, 0, sizeof(fsrp->fr_rattr)); ++ } ++ mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ ++ mutex_spinunlock(&fsrp->fr_lock, lc1); ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_get_mountinfo( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_fsreg_t *fsrp; ++ dm_tokdata_t *tdp; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ /* Make sure that the caller's buffer is 8-byte aligned. */ ++ ++ if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0) ++ return(-EFAULT); ++ ++ /* Verify that the handle is a filesystem handle, and that the ++ filesystem is capable of sending events. If not, return an error. ++ */ ++ ++ error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, ++ DM_RIGHT_SHARED, &tdp); ++ if (error != 0) ++ return(error); ++ ++ /* Find the filesystem entry. This should always succeed as the ++ dm_app_get_tdp call created a filesystem reference. Once we find ++ the entry, drop the lock. The mountinfo message is never modified, ++ the filesystem entry can't disappear, and we don't want to hold a ++ spinlock while doing copyout calls. ++ */ ++ ++ fsrp = dm_find_fsreg_and_lock(&tdp->td_handle.ha_fsid, &lc); ++ if (fsrp == NULL) { ++ dm_app_put_tdp(tdp); ++ return(-EINVAL); ++ } ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ ++ /* Copy the message into the user's buffer and update his 'rlenp'. */ ++ ++ if (put_user(fsrp->fr_msgsize, rlenp)) { ++ error = -EFAULT; ++ } else if (fsrp->fr_msgsize > buflen) { /* user buffer not big enough */ ++ error = -E2BIG; ++ } else if (copy_to_user(bufp, fsrp->fr_msg, fsrp->fr_msgsize)) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_getall_disp( ++ dm_sessid_t sid, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_session_t *s; /* pointer to session given by sid */ ++ unsigned long lc1; /* first lock cookie */ ++ unsigned long lc2; /* second lock cookie */ ++ int totalsize; ++ int msgsize; ++ int fsyscnt; ++ dm_dispinfo_t *prevmsg; ++ dm_fsreg_t *fsrp; ++ int error; ++ char *kbuf; ++ ++ int tmp3; ++ int tmp4; ++ ++ /* Because the dm_getall_disp structure contains a __u64 field, ++ make sure that the buffer provided by the caller is aligned so ++ that he can read such fields successfully. ++ */ ++ ++ if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0) ++ return(-EFAULT); ++ ++ /* Compute the size of a dm_dispinfo structure, rounding up to an ++ 8-byte boundary so that any subsequent structures will also be ++ aligned. ++ */ ++ ++#if 0 ++ /* XXX ug, what is going on here? */ ++ msgsize = (sizeof(dm_dispinfo_t) + DM_FSHSIZE + sizeof(uint64_t) - 1) & ++ ~(sizeof(uint64_t) - 1); ++#else ++ tmp3 = sizeof(dm_dispinfo_t) + DM_FSHSIZE; ++ tmp3 += sizeof(__u64); ++ tmp3 -= 1; ++ tmp4 = ~((int)sizeof(__u64) - 1); ++ msgsize = tmp3 & tmp4; ++#endif ++ ++ /* Loop until we can get the right amount of temp space, being careful ++ not to hold a mutex during the allocation. Usually only one trip. ++ */ ++ ++ for (;;) { ++ if ((fsyscnt = dm_fsys_cnt) == 0) { ++ /*if (dm_cpoutsizet(rlenp, 0))*/ ++ if (put_user(0,rlenp)) ++ return(-EFAULT); ++ return(0); ++ } ++ kbuf = kmalloc(fsyscnt * msgsize, GFP_KERNEL); ++ if (kbuf == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ lc1 = mutex_spinlock(&dm_reg_lock); ++ if (fsyscnt == dm_fsys_cnt) ++ break; ++ ++ mutex_spinunlock(&dm_reg_lock, lc1); ++ kfree(kbuf); ++ } ++ ++ /* Find the indicated session and lock it. */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { ++ mutex_spinunlock(&dm_reg_lock, lc1); ++ kfree(kbuf); ++ return(error); ++ } ++ ++ /* Create a dm_dispinfo structure for each filesystem in which ++ this session has at least one event selected for disposition. ++ */ ++ ++ totalsize = 0; /* total bytes to transfer to the user */ ++ prevmsg = NULL; ++ ++ for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) { ++ dm_dispinfo_t *disp; ++ int event; ++ int found; ++ ++ disp = (dm_dispinfo_t *)(kbuf + totalsize); ++ ++ DMEV_ZERO(disp->di_eventset); ++ ++ for (event = 0, found = 0; event < DM_EVENT_MAX; event++) { ++ if (fsrp->fr_sessp[event] != s) ++ continue; ++ DMEV_SET(event, disp->di_eventset); ++ found++; ++ } ++ if (!found) ++ continue; ++ ++ disp->_link = 0; ++ disp->di_fshandle.vd_offset = sizeof(dm_dispinfo_t); ++ disp->di_fshandle.vd_length = DM_FSHSIZE; ++ ++ memcpy((char *)disp + disp->di_fshandle.vd_offset, ++ &fsrp->fr_fsid, disp->di_fshandle.vd_length); ++ ++ if (prevmsg) ++ prevmsg->_link = msgsize; ++ ++ prevmsg = disp; ++ totalsize += msgsize; ++ } ++ mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ ++ mutex_spinunlock(&dm_reg_lock, lc1); ++ ++ if (put_user(totalsize, rlenp)) { ++ error = -EFAULT; ++ } else if (totalsize > buflen) { /* no more room */ ++ error = -E2BIG; ++ } else if (totalsize && copy_to_user(bufp, kbuf, totalsize)) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ ++ kfree(kbuf); ++ return(error); ++} ++ ++int ++dm_open_by_handle_rvp( ++ unsigned int fd, ++ void __user *hanp, ++ size_t hlen, ++ int flags, ++ int *rvp) ++{ ++ dm_handle_t handle; ++ int error; ++ short td_type; ++ struct dentry *dentry; ++ struct inode *inodep; ++ int new_fd; ++ struct file *mfilp; ++ struct file *filp; ++ ++ if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) { ++ return(error); ++ } ++ ++ if ((inodep = dm_handle_to_ip(&handle, &td_type)) == NULL) { ++ return(-EBADF); ++ } ++ if ((td_type == DM_TDT_VFS) || (td_type == DM_TDT_OTH)) { ++ iput(inodep); ++ return(-EBADF); ++ } ++ ++ if ((new_fd = get_unused_fd()) < 0) { ++ iput(inodep); ++ return(-EMFILE); ++ } ++ ++ dentry = d_alloc_anon(inodep); ++ if (dentry == NULL) { ++ iput(inodep); ++ put_unused_fd(new_fd); ++ return(-ENOMEM); ++ } ++ ++ mfilp = fget(fd); ++ if (!mfilp) { ++ dput(dentry); ++ put_unused_fd(new_fd); ++ return(-EBADF); ++ } ++ ++ mntget(mfilp->f_vfsmnt); ++ ++ /* Create file pointer */ ++ filp = dentry_open(dentry, mfilp->f_vfsmnt, flags); ++ if (IS_ERR(filp)) { ++ put_unused_fd(new_fd); ++ fput(mfilp); ++ return PTR_ERR(filp); ++ } ++ ++ if (td_type == DM_TDT_REG) { ++ struct filesystem_dmapi_operations *dmapiops; ++ dmapiops = dm_fsys_ops(inodep->i_sb); ++ if (dmapiops && dmapiops->get_invis_ops) { ++ /* invisible operation should not change atime */ ++ filp->f_flags |= O_NOATIME; ++ filp->f_op = dmapiops->get_invis_ops(inodep); ++ } ++ } ++ fd_install(new_fd, filp); ++ fput(mfilp); ++ *rvp = new_fd; ++ return 0; ++} ++ ++ ++#ifdef HAVE_DM_QUEUE_FLUSH ++/* Find the threads that have a reference to our filesystem and force ++ them to return with the specified errno. ++ We look for them in each dm_fsreg_t's fr_evt_dispq. ++*/ ++ ++int ++dm_release_disp_threads( ++ dm_fsid_t *fsidp, ++ struct inode *inode, /* may be null */ ++ int errno) ++{ ++ unsigned long lc; ++ dm_fsreg_t *fsrp; ++ dm_tokevent_t *tevp; ++ dm_tokdata_t *tdp; ++ dm_eventq_t *queue; ++ int found_events = 0; ++ ++ if ((fsrp = dm_find_fsreg_and_lock(fsidp, &lc)) == NULL){ ++ return 0; ++ } ++ ++ queue = &fsrp->fr_evt_dispq; ++ for (tevp = queue->eq_head; tevp; tevp = tevp->te_next) { ++ nested_spinlock(&tevp->te_lock); ++ if (inode) { ++ for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { ++ if( tdp->td_ip == inode ) { ++ tevp->te_flags |= DM_TEF_FLUSH; ++ tevp->te_reply = errno; ++ found_events = 1; ++ break; ++ } ++ } ++ } ++ else { ++ tevp->te_flags |= DM_TEF_FLUSH; ++ tevp->te_reply = errno; ++ found_events = 1; ++ } ++ nested_spinunlock(&tevp->te_lock); ++ } ++ ++ if (found_events && fsrp->fr_dispcnt) ++ sv_broadcast(&fsrp->fr_dispq); ++ mutex_spinunlock(&fsrp->fr_lock, lc); ++ return 0; ++} ++#endif /* HAVE_DM_QUEUE_FLUSH */ +Index: linux-2.6.26/fs/dmapi/dmapi_right.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_right.c +@@ -0,0 +1,1256 @@ ++/* ++ * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#include ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++ ++#define DM_FG_STHREAD 0x001 /* keep other threads from using tdp */ ++#define DM_FG_MUSTEXIST 0x002 /* handle must exist in the event */ ++#define DM_FG_DONTADD 0x004 /* don't add handle if not in event */ ++ ++/* Get a handle of the form (void *, size_t) from user space and convert it to ++ a handle_t. Do as much validation of the result as possible; any error ++ other than a bad address should return EBADF per the DMAPI spec. ++*/ ++ ++int ++dm_copyin_handle( ++ void __user *hanp, /* input, handle data */ ++ size_t hlen, /* input, size of handle data */ ++ dm_handle_t *handlep) /* output, copy of data */ ++{ ++ u_short len; ++ dm_fid_t *fidp; ++ ++ fidp = (dm_fid_t*)&handlep->ha_fid; ++ ++ if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) ++ return -EBADF; ++ ++ if (copy_from_user(handlep, hanp, hlen)) ++ return -EFAULT; ++ ++ if (hlen < sizeof(*handlep)) ++ memset((char *)handlep + hlen, 0, sizeof(*handlep) - hlen); ++ ++ if (hlen == sizeof(handlep->ha_fsid)) ++ return 0; /* FS handle, nothing more to check */ ++ ++ len = hlen - sizeof(handlep->ha_fsid) - sizeof(fidp->dm_fid_len); ++ ++ if ((fidp->dm_fid_len != len) || fidp->dm_fid_pad) ++ return -EBADF; ++ return 0; ++} ++ ++/* Allocate and initialize a tevp structure. Called from both application and ++ event threads. ++*/ ++ ++static dm_tokevent_t * ++dm_init_tevp( ++ int ev_size, /* size of event structure */ ++ int var_size) /* size of variable-length data */ ++{ ++ dm_tokevent_t *tevp; ++ int msgsize; ++ ++ /* Calculate the size of the event in bytes and allocate memory for it. ++ Zero all but the variable portion of the message, which will be ++ eventually overlaid by the caller with data. ++ */ ++ ++ msgsize = offsetof(dm_tokevent_t, te_event) + ev_size + var_size; ++ tevp = kmalloc(msgsize, GFP_KERNEL); ++ if (tevp == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return NULL; ++ } ++ memset(tevp, 0, msgsize - var_size); ++ ++ /* Now initialize all the non-zero fields. */ ++ ++ spinlock_init(&tevp->te_lock, "te_lock"); ++ sv_init(&tevp->te_evt_queue, SV_DEFAULT, "te_evt_queue"); ++ sv_init(&tevp->te_app_queue, SV_DEFAULT, "te_app_queue"); ++ tevp->te_allocsize = msgsize; ++ tevp->te_msg.ev_type = DM_EVENT_INVALID; ++ tevp->te_flags = 0; ++ ++ return(tevp); ++} ++ ++ ++/* Given the event type and the number of bytes of variable length data that ++ will follow the event, dm_evt_create_tevp() creates a dm_tokevent_t ++ structure to hold the event and initializes all the common event fields. ++ ++ No locking is required for this routine because the caller is an event ++ thread, and is therefore the only thread that can see the event. ++*/ ++ ++dm_tokevent_t * ++dm_evt_create_tevp( ++ dm_eventtype_t event, ++ int variable_size, ++ void **msgpp) ++{ ++ dm_tokevent_t *tevp; ++ int evsize; ++ ++ switch (event) { ++ case DM_EVENT_READ: ++ case DM_EVENT_WRITE: ++ case DM_EVENT_TRUNCATE: ++ evsize = sizeof(dm_data_event_t); ++ break; ++ ++ case DM_EVENT_DESTROY: ++ evsize = sizeof(dm_destroy_event_t); ++ break; ++ ++ case DM_EVENT_MOUNT: ++ evsize = sizeof(dm_mount_event_t); ++ break; ++ ++ case DM_EVENT_PREUNMOUNT: ++ case DM_EVENT_UNMOUNT: ++ case DM_EVENT_NOSPACE: ++ case DM_EVENT_CREATE: ++ case DM_EVENT_REMOVE: ++ case DM_EVENT_RENAME: ++ case DM_EVENT_SYMLINK: ++ case DM_EVENT_LINK: ++ case DM_EVENT_POSTCREATE: ++ case DM_EVENT_POSTREMOVE: ++ case DM_EVENT_POSTRENAME: ++ case DM_EVENT_POSTSYMLINK: ++ case DM_EVENT_POSTLINK: ++ case DM_EVENT_ATTRIBUTE: ++ case DM_EVENT_DEBUT: /* currently not supported */ ++ case DM_EVENT_CLOSE: /* currently not supported */ ++ evsize = sizeof(dm_namesp_event_t); ++ break; ++ ++ case DM_EVENT_CANCEL: /* currently not supported */ ++ evsize = sizeof(dm_cancel_event_t); ++ break; ++ ++ case DM_EVENT_USER: ++ evsize = 0; ++ break; ++ ++ default: ++ panic("dm_create_tevp: called with unknown event type %d\n", ++ event); ++ } ++ ++ /* Allocate and initialize an event structure of the correct size. */ ++ ++ tevp = dm_init_tevp(evsize, variable_size); ++ if (tevp == NULL) ++ return NULL; ++ tevp->te_evt_ref = 1; ++ ++ /* Fields ev_token, ev_sequence, and _link are all filled in when the ++ event is queued onto a session. Initialize all other fields here. ++ */ ++ ++ tevp->te_msg.ev_type = event; ++ tevp->te_msg.ev_data.vd_offset = offsetof(dm_tokevent_t, te_event) - ++ offsetof(dm_tokevent_t, te_msg); ++ tevp->te_msg.ev_data.vd_length = evsize + variable_size; ++ ++ /* Give the caller a pointer to the event-specific structure. */ ++ ++ *msgpp = ((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset); ++ return(tevp); ++} ++ ++ ++/* Given a pointer to an event (tevp) and a pointer to a handle_t, look for a ++ tdp structure within the event which contains the handle_t. Either verify ++ that the event contains the tdp, or optionally add the tdp to the ++ event. Called only from application threads. ++ ++ On entry, tevp->te_lock is held; it is dropped prior to return. ++*/ ++ ++static int ++dm_app_lookup_tdp( ++ dm_handle_t *handlep, /* the handle we are looking for */ ++ dm_tokevent_t *tevp, /* the event to search for the handle */ ++ unsigned long *lcp, /* address of active lock cookie */ ++ short types, /* acceptable object types */ ++ dm_right_t right, /* minimum right the object must have */ ++ u_int flags, ++ dm_tokdata_t **tdpp) /* if ! NULL, pointer to matching tdp */ ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ struct inode *ip; ++ int error; ++ ++ /* Bump the tevp application reference counter so that the event ++ can't disappear in case we have to drop the lock for a while. ++ */ ++ ++ tevp->te_app_ref++; ++ *tdpp = NULL; /* assume failure */ ++ ++ for (;;) { ++ /* Look for a matching tdp in the tevp. */ ++ ++ for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { ++ if (DM_HANDLE_CMP(&tdp->td_handle, handlep) == 0) ++ break; ++ } ++ ++ /* If the tdp exists, but either we need single-thread access ++ to the handle and can't get it, or some other thread already ++ has single-thread access, then sleep until we can try again. ++ */ ++ ++ if (tdp != NULL && tdp->td_app_ref && ++ ((flags & DM_FG_STHREAD) || ++ (tdp->td_flags & DM_TDF_STHREAD))) { ++ tevp->te_app_slp++; ++ sv_wait(&tevp->te_app_queue, 1, ++ &tevp->te_lock, *lcp); ++ *lcp = mutex_spinlock(&tevp->te_lock); ++ tevp->te_app_slp--; ++ continue; ++ } ++ ++ if (tdp != NULL && ++ (tdp->td_vcount > 0 || tdp->td_flags & DM_TDF_EVTREF)) { ++ /* We have an existing tdp with a non-zero inode ++ reference count. If it's the wrong type, return ++ an appropriate errno. ++ */ ++ ++ if (!(tdp->td_type & types)) { ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ dm_put_tevp(tevp, NULL); /* no destroy events */ ++ return(-EOPNOTSUPP); ++ } ++ ++ /* If the current access right isn't high enough, ++ complain. ++ */ ++ ++ if (tdp->td_right < right) { ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ dm_put_tevp(tevp, NULL); /* no destroy events */ ++ return(-EACCES); ++ } ++ ++ /* The handle is acceptable. Increment the tdp ++ application and inode references and mark the tdp ++ as single-threaded if necessary. ++ */ ++ ++ tdp->td_app_ref++; ++ if (flags & DM_FG_STHREAD) ++ tdp->td_flags |= DM_TDF_STHREAD; ++ tdp->td_vcount++; ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ (void)fsys_vector->obj_ref_hold(tdp->td_ip); ++ ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ *tdpp = tdp; ++ return(0); ++ } ++ ++ /* If the tdp is not in the tevp or does not have an inode ++ reference, check to make sure it is okay to add/update it. ++ */ ++ ++ if (flags & DM_FG_MUSTEXIST) { ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ dm_put_tevp(tevp, NULL); /* no destroy events */ ++ return(-EACCES); /* i.e. an insufficient right */ ++ } ++ if (flags & DM_FG_DONTADD) { ++ tevp->te_app_ref--; ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ return(0); ++ } ++ ++ /* If a tdp structure doesn't yet exist, create one and link ++ it into the tevp. Drop the lock while we are doing this as ++ zallocs can go to sleep. Once we have the memory, make ++ sure that another thread didn't simultaneously add the same ++ handle to the same event. If so, toss ours and start over. ++ */ ++ ++ if (tdp == NULL) { ++ dm_tokdata_t *tmp; ++ ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ ++ tdp = kmem_cache_alloc(dm_tokdata_cachep, GFP_KERNEL); ++ if (tdp == NULL){ ++ printk("%s/%d: kmem_cache_alloc(dm_tokdata_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return(-ENOMEM); ++ } ++ memset(tdp, 0, sizeof(*tdp)); ++ ++ *lcp = mutex_spinlock(&tevp->te_lock); ++ ++ for (tmp = tevp->te_tdp; tmp; tmp = tmp->td_next) { ++ if (DM_HANDLE_CMP(&tmp->td_handle, handlep) == 0) ++ break; ++ } ++ if (tmp) { ++ kmem_cache_free(dm_tokdata_cachep, tdp); ++ continue; ++ } ++ ++ tdp->td_next = tevp->te_tdp; ++ tevp->te_tdp = tdp; ++ tdp->td_tevp = tevp; ++ tdp->td_handle = *handlep; ++ } ++ ++ /* Temporarily single-thread access to the tdp so that other ++ threads don't touch it while we are filling the rest of the ++ fields in. ++ */ ++ ++ tdp->td_app_ref = 1; ++ tdp->td_flags |= DM_TDF_STHREAD; ++ ++ /* Drop the spinlock while we access, validate, and obtain the ++ proper rights to the object. This can take a very long time ++ if the inode is not in memory, if the filesystem is ++ unmounting, or if the request_right() call should block ++ because some other tdp or kernel thread is holding a right. ++ */ ++ ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ ++ if ((ip = dm_handle_to_ip(handlep, &tdp->td_type)) == NULL) { ++ error = -EBADF; ++ } else { ++ tdp->td_vcount = 1; ++ tdp->td_ip = ip; ++ ++ /* The handle is usable. Check that the type of the ++ object matches one of the types that the caller ++ will accept. ++ */ ++ ++ if (!(types & tdp->td_type)) { ++ error = -EOPNOTSUPP; ++ } else if (right > DM_RIGHT_NULL) { ++ /* Attempt to get the rights required by the ++ caller. If rights can't be obtained, return ++ an error. ++ */ ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->request_right(tdp->td_ip, ++ DM_RIGHT_NULL, ++ (tdp->td_type == DM_TDT_VFS ? ++ DM_FSYS_OBJ : 0), ++ DM_RR_WAIT, right); ++ if (!error) { ++ tdp->td_right = right; ++ } ++ } else { ++ error = 0; ++ } ++ } ++ if (error != 0) { ++ dm_put_tevp(tevp, tdp); /* destroy event risk, although tiny */ ++ return(error); ++ } ++ ++ *lcp = mutex_spinlock(&tevp->te_lock); ++ ++ /* Wake up any threads which may have seen our tdp while we ++ were filling it in. ++ */ ++ ++ if (!(flags & DM_FG_STHREAD)) { ++ tdp->td_flags &= ~DM_TDF_STHREAD; ++ if (tevp->te_app_slp) ++ sv_broadcast(&tevp->te_app_queue); ++ } ++ ++ mutex_spinunlock(&tevp->te_lock, *lcp); ++ *tdpp = tdp; ++ return(0); ++ } ++} ++ ++ ++/* dm_app_get_tdp_by_token() is called whenever the application request ++ contains a session ID and contains a token other than DM_NO_TOKEN. ++ Most of the callers provide a right that is either DM_RIGHT_SHARED or ++ DM_RIGHT_EXCL, but a few of the callers such as dm_obj_ref_hold() may ++ specify a right of DM_RIGHT_NULL. ++*/ ++ ++static int ++dm_app_get_tdp_by_token( ++ dm_sessid_t sid, /* an existing session ID */ ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, /* an existing token */ ++ short types, /* acceptable object types */ ++ dm_right_t right, /* minimum right the object must have */ ++ u_int flags, ++ dm_tokdata_t **tdpp) ++{ ++ dm_tokevent_t *tevp; ++ dm_handle_t handle; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ if (right < DM_RIGHT_NULL || right > DM_RIGHT_EXCL) ++ return(-EINVAL); ++ ++ if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) ++ return(error); ++ ++ /* Find and lock the event which corresponds to the specified ++ session/token pair. ++ */ ++ ++ if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) ++ return(error); ++ ++ return(dm_app_lookup_tdp(&handle, tevp, &lc, types, ++ right, flags, tdpp)); ++} ++ ++ ++/* Function dm_app_get_tdp() must ONLY be called from routines associated with ++ application calls, e.g. dm_read_invis, dm_set_disp, etc. It must not be ++ called by a thread responsible for generating an event such as ++ dm_send_data_event()! ++ ++ dm_app_get_tdp() is the interface used by all application calls other than ++ dm_get_events, dm_respond_event, dm_get_config, dm_get_config_events, and by ++ the dm_obj_ref_* and dm_*_right families of requests. ++ ++ dm_app_get_tdp() converts a sid/hanp/hlen/token quad into a tdp pointer, ++ increments the number of active application threads in the event, and ++ increments the number of active application threads using the tdp. The ++ 'right' parameter must be either DM_RIGHT_SHARED or DM_RIGHT_EXCL. The ++ token may either be DM_NO_TOKEN, or can be a token received in a synchronous ++ event. ++*/ ++ ++int ++dm_app_get_tdp( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ short types, ++ dm_right_t right, /* minimum right */ ++ dm_tokdata_t **tdpp) ++{ ++ dm_session_t *s; ++ dm_handle_t handle; ++ dm_tokevent_t *tevp; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ ASSERT(right >= DM_RIGHT_SHARED); ++ ++ /* If a token other than DM_NO_TOKEN is specified, find the event on ++ this session which owns the token and increment its reference count. ++ */ ++ ++ if (token != DM_NO_TOKEN) { /* look up existing tokevent struct */ ++ return(dm_app_get_tdp_by_token(sid, hanp, hlen, token, types, ++ right, DM_FG_MUSTEXIST, tdpp)); ++ } ++ ++ /* The token is DM_NO_TOKEN. In this case we only want to verify that ++ the session ID is valid, and do not need to continue holding the ++ session lock after we know that to be true. ++ */ ++ ++ if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) ++ return(error); ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) ++ return(error); ++ mutex_spinunlock(&s->sn_qlock, lc); ++ ++ /* When DM_NO_TOKEN is used, we simply block until we can obtain the ++ right that we want (since the tevp contains no tdp structures). ++ The blocking when we eventually support it will occur within ++ fsys_vector->request_right(). ++ */ ++ ++ tevp = dm_init_tevp(0, 0); ++ lc = mutex_spinlock(&tevp->te_lock); ++ ++ return(dm_app_lookup_tdp(&handle, tevp, &lc, types, right, 0, tdpp)); ++} ++ ++ ++/* dm_get_config_tdp() is only called by dm_get_config() and ++ dm_get_config_events(), which neither have a session ID nor a token. ++ Both of these calls are supposed to work even if the filesystem is in the ++ process of being mounted, as long as the caller only uses handles within ++ the mount event. ++*/ ++ ++int ++dm_get_config_tdp( ++ void __user *hanp, ++ size_t hlen, ++ dm_tokdata_t **tdpp) ++{ ++ dm_handle_t handle; ++ dm_tokevent_t *tevp; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) ++ return(error); ++ ++ tevp = dm_init_tevp(0, 0); ++ lc = mutex_spinlock(&tevp->te_lock); ++ ++ /* Try to use the handle provided by the caller and assume DM_NO_TOKEN. ++ This will fail if the filesystem is in the process of being mounted. ++ */ ++ ++ error = dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY, ++ DM_RIGHT_NULL, 0, tdpp); ++ ++ if (!error) { ++ return(0); ++ } ++ ++ /* Perhaps the filesystem is still mounting, in which case we need to ++ see if this is one of the handles in the DM_EVENT_MOUNT tevp. ++ */ ++ ++ if ((tevp = dm_find_mount_tevp_and_lock(&handle.ha_fsid, &lc)) == NULL) ++ return(-EBADF); ++ ++ return(dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY, ++ DM_RIGHT_NULL, DM_FG_MUSTEXIST, tdpp)); ++} ++ ++ ++/* dm_put_tdp() is called to release any right held on the inode, and to ++ VN_RELE() all references held on the inode. It is the caller's ++ responsibility to ensure that no other application threads are using the ++ tdp, and if necessary to unlink the tdp from the tevp before calling ++ this routine and to free the tdp afterwards. ++*/ ++ ++static void ++dm_put_tdp( ++ dm_tokdata_t *tdp) ++{ ++ ASSERT(tdp->td_app_ref <= 1); ++ ++ /* If the application thread is holding a right, or if the event ++ thread had a right but it has disappeared because of a dm_pending ++ or Cntl-C, then we need to release it here. ++ */ ++ ++ if (tdp->td_right != DM_RIGHT_NULL) { ++ dm_fsys_vector_t *fsys_vector; ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ (void)fsys_vector->release_right(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); ++ tdp->td_right = DM_RIGHT_NULL; ++ } ++ ++ /* Given that we wouldn't be here if there was still an event thread, ++ this VN_RELE loop has the potential of generating a DM_EVENT_DESTROY ++ event if some other thread has unlinked the file. ++ */ ++ ++ while (tdp->td_vcount > 0) { ++ iput(tdp->td_ip); ++ tdp->td_vcount--; ++ } ++ ++ tdp->td_flags &= ~(DM_TDF_HOLD|DM_TDF_RIGHT); ++ tdp->td_ip = NULL; ++} ++ ++ ++/* Function dm_put_tevp() must ONLY be called from routines associated with ++ application threads, e.g. dm_read_invis, dm_get_events, etc. It must not be ++ called by a thread responsible for generating an event, such as ++ dm_send_data_event. ++ ++ PLEASE NOTE: It is possible for this routine to generate DM_EVENT_DESTROY ++ events, because its calls to dm_put_tdp drop inode references, and another ++ thread may have already unlinked a file whose inode we are de-referencing. ++ This sets the stage for various types of deadlock if the thread calling ++ dm_put_tevp is the same thread that calls dm_respond_event! In particular, ++ the dm_sent_destroy_event routine needs to obtain the dm_reg_lock, ++ dm_session_lock, and sn_qlock in order to queue the destroy event. No ++ caller of dm_put_tevp can hold any of these locks! ++ ++ Other possible deadlocks are that dm_send_destroy_event could block waiting ++ for a thread to register for the event using dm_set_disp() and/or ++ dm_set_return_on_destroy, or it could block because the session's sn_newq ++ is at the dm_max_queued_msgs event limit. The only safe solution ++ (unimplemented) is to have a separate kernel thread for each filesystem ++ whose only job is to do the inode-dereferencing. That way dm_respond_event ++ will not block, so the application can keep calling dm_get_events to read ++ events even if the filesystem thread should block. (If the filesystem ++ thread blocks, so will all subsequent destroy events for the same ++ filesystem.) ++*/ ++ ++void ++dm_put_tevp( ++ dm_tokevent_t *tevp, ++ dm_tokdata_t *tdp) ++{ ++ int free_tdp = 0; ++ unsigned long lc; /* lock cookie */ ++ ++ lc = mutex_spinlock(&tevp->te_lock); ++ ++ if (tdp != NULL) { ++ if (tdp->td_vcount > 1 || (tdp->td_flags & DM_TDF_EVTREF)) { ++ ASSERT(tdp->td_app_ref > 0); ++ ++ iput(tdp->td_ip); ++ tdp->td_vcount--; ++ } else { ++ ASSERT(tdp->td_app_ref == 1); ++ ++ /* The inode reference count is either already at ++ zero (e.g. a failed dm_handle_to_ip() call in ++ dm_app_lookup_tdp()) or is going to zero. We can't ++ hold the lock while we decrement the count because ++ we could potentially end up being busy for a long ++ time in VOP_INACTIVATE. Use single-threading to ++ lock others out while we clean house. ++ */ ++ ++ tdp->td_flags |= DM_TDF_STHREAD; ++ ++ /* WARNING - A destroy event is possible here if we are ++ giving up the last reference on an inode which has ++ been previously unlinked by some other thread! ++ */ ++ ++ mutex_spinunlock(&tevp->te_lock, lc); ++ dm_put_tdp(tdp); ++ lc = mutex_spinlock(&tevp->te_lock); ++ ++ /* If this tdp is not one of the original tdps in the ++ event, then remove it from the tevp. ++ */ ++ ++ if (!(tdp->td_flags & DM_TDF_ORIG)) { ++ dm_tokdata_t **tdpp = &tevp->te_tdp; ++ ++ while (*tdpp && *tdpp != tdp) { ++ tdpp = &(*tdpp)->td_next; ++ } ++ if (*tdpp == NULL) { ++ panic("dm_remove_tdp_from_tevp: tdp " ++ "%p not in tevp %p\n", tdp, ++ tevp); ++ } ++ *tdpp = tdp->td_next; ++ free_tdp++; ++ } ++ } ++ ++ /* If this is the last app thread actively using the tdp, clear ++ any single-threading and wake up any other app threads who ++ might be waiting to use this tdp, single-threaded or ++ otherwise. ++ */ ++ ++ if (--tdp->td_app_ref == 0) { ++ if (tdp->td_flags & DM_TDF_STHREAD) { ++ tdp->td_flags &= ~DM_TDF_STHREAD; ++ if (tevp->te_app_slp) ++ sv_broadcast(&tevp->te_app_queue); ++ } ++ } ++ ++ if (free_tdp) { ++ kmem_cache_free(dm_tokdata_cachep, tdp); ++ } ++ } ++ ++ /* If other application threads are using this token/event, they will ++ do the cleanup. ++ */ ++ ++ if (--tevp->te_app_ref > 0) { ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return; ++ } ++ ++ /* If event generation threads are waiting for this thread to go away, ++ wake them up and let them do the cleanup. ++ */ ++ ++ if (tevp->te_evt_ref > 0) { ++ sv_broadcast(&tevp->te_evt_queue); ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return; ++ } ++ ++ /* This thread is the last active thread using the token/event. No ++ lock can be held while we disassemble the tevp because we could ++ potentially end up being busy for a long time in VOP_INACTIVATE. ++ */ ++ ++ mutex_spinunlock(&tevp->te_lock, lc); ++ ++ /* WARNING - One or more destroy events are possible here if we are ++ giving up references on inodes which have been previously unlinked ++ by other kernel threads! ++ */ ++ ++ while ((tdp = tevp->te_tdp) != NULL) { ++ tevp->te_tdp = tdp->td_next; ++ dm_put_tdp(tdp); ++ kmem_cache_free(dm_tokdata_cachep, tdp); ++ } ++ spinlock_destroy(&tevp->te_lock); ++ sv_destroy(&tevp->te_evt_queue); ++ sv_destroy(&tevp->te_app_queue); ++ kfree(tevp); ++} ++ ++ ++/* No caller of dm_app_put_tevp can hold either of the locks dm_reg_lock, ++ dm_session_lock, or any sn_qlock! (See dm_put_tevp for details.) ++*/ ++ ++void ++dm_app_put_tdp( ++ dm_tokdata_t *tdp) ++{ ++ dm_put_tevp(tdp->td_tevp, tdp); ++} ++ ++ ++/* dm_change_right is only called if the event thread is the one doing the ++ cleanup on a completed event. It looks at the current rights of a tdp ++ and compares that with the rights it had on the tdp when the event was ++ created. If different, it reaquires the original rights, then transfers ++ the rights back to being thread-based. ++*/ ++ ++static void ++dm_change_right( ++ dm_tokdata_t *tdp) ++{ ++#ifdef HAVE_DMAPI_RIGHTS ++ dm_fsys_vector_t *fsys_vector; ++ int error; ++ u_int type; ++#endif ++ ++ /* If the event doesn't have an inode reference, if the original right ++ was DM_RIGHT_NULL, or if the rights were never switched from being ++ thread-based to tdp-based, then there is nothing to do. ++ */ ++ ++ if (!(tdp->td_flags & DM_TDF_EVTREF)) ++ return; ++ ++ if (tdp->td_orig_right == DM_RIGHT_NULL) ++ return; ++ ++ /* DEBUG - Need a check here for event-based rights. */ ++ ++#ifdef HAVE_DMAPI_RIGHTS ++ /* The "rights" vectors are stubs now anyway. When they are ++ * implemented then bhv locking will have to be sorted out. ++ */ ++ ++ /* If the current right is not the same as it was when the event was ++ created, first get back the original right. ++ */ ++ ++ if (tdp->td_right != tdp->td_orig_right) { ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ type = (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0); ++ ++ switch (tdp->td_orig_right) { ++ case DM_RIGHT_SHARED: ++ if (tdp->td_right == DM_RIGHT_EXCL) { ++ error = fsys_vector->downgrade_right( ++ tdp->td_ip, tdp->td_right, type); ++ if (!error) ++ break; ++ (void)fsys_vector->release_right(tdp->td_ip, ++ tdp->td_right, type); ++ } ++ (void)fsys_vector->request_right(tdp->td_ip, ++ tdp->td_right, type, DM_RR_WAIT, ++ tdp->td_orig_right); ++ break; ++ ++ case DM_RIGHT_EXCL: ++ if (tdp->td_right == DM_RIGHT_SHARED) { ++ error = fsys_vector->upgrade_right(tdp->td_ip, ++ tdp->td_right, type); ++ if (!error) ++ break; ++ (void)fsys_vector->release_right(tdp->td_ip, ++ tdp->td_right, type); ++ } ++ (void)fsys_vector->request_right(tdp->td_ip, ++ tdp->td_right, type, DM_RR_WAIT, ++ tdp->td_orig_right); ++ break; ++ case DM_RIGHT_NULL: ++ break; ++ } ++ } ++#endif ++ ++ /* We now have back the same level of rights as we had when the event ++ was generated. Now transfer the rights from being tdp-based back ++ to thread-based. ++ */ ++ ++ /* DEBUG - Add a call here to transfer rights back to thread-based. */ ++ ++ /* Finally, update the tdp so that we don't mess with the rights when ++ we eventually call dm_put_tdp. ++ */ ++ ++ tdp->td_right = DM_RIGHT_NULL; ++} ++ ++ ++/* This routine is only called by event threads. The calls to dm_put_tdp ++ are not a deadlock risk here because this is an event thread, and it is ++ okay for such a thread to block on an induced destroy event. Okay, maybe ++ there is a slight risk; say that the event contains three inodes all of ++ which have DM_RIGHT_EXCL, and say that we are at the dm_max_queued_msgs ++ limit, and that the first inode is already unlinked. In that case the ++ destroy event will block waiting to be queued, and the application thread ++ could happen to reference one of the other locked inodes. Deadlock. ++*/ ++ ++void ++dm_evt_rele_tevp( ++ dm_tokevent_t *tevp, ++ int droprights) /* non-zero, evt thread loses rights */ ++{ ++ dm_tokdata_t *tdp; ++ unsigned long lc; /* lock cookie */ ++ ++ lc = mutex_spinlock(&tevp->te_lock); ++ ++ /* If we are here without DM_TEF_FINAL set and with at least one ++ application reference still remaining, then one of several ++ possibilities is true: ++ 1. This is an asynchronous event which has been queued but has not ++ yet been delivered, or which is in the process of being delivered. ++ 2. This is an unmount event (pseudo-asynchronous) yet to be ++ delivered or in the process of being delivered. ++ 3. This event had DM_FLAGS_NDELAY specified, and the application ++ has sent a dm_pending() reply for the event. ++ 4. This is a DM_EVENT_READ, DM_EVENT_WRITE, or DM_EVENT_TRUNCATE ++ event and the user typed a Cntl-C. ++ In all of these cases, the correct behavior is to leave the ++ responsibility of releasing any rights to the application threads ++ when they are done. ++ */ ++ ++ if (tevp->te_app_ref > 0 && !(tevp->te_flags & DM_TEF_FINAL)) { ++ tevp->te_evt_ref--; ++ for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { ++ if (tdp->td_flags & DM_TDF_EVTREF) { ++ tdp->td_flags &= ~DM_TDF_EVTREF; ++ if (tdp->td_vcount == 0) { ++ tdp->td_ip = NULL; ++ } ++ } ++ } ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return; /* not the last thread */ ++ } ++ ++ /* If the application reference count is non-zero here, that can only ++ mean that dm_respond_event() has been called, but the application ++ still has one or more threads in the kernel that haven't let go of ++ the tevp. In these cases, the event thread must wait until all ++ application threads have given up their references, and their ++ rights to handles within the event. ++ */ ++ ++ while (tevp->te_app_ref) { ++ sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); ++ lc = mutex_spinlock(&tevp->te_lock); ++ } ++ ++ /* This thread is the last active thread using the token/event. Reset ++ the rights of any inode that was part of the original event back ++ to their initial values before returning to the filesystem. The ++ exception is if the event failed (droprights is non-zero), in which ++ case we chose to return to the filesystem with all rights released. ++ Release the rights on any inode that was not part of the original ++ event. Give up all remaining application inode references ++ regardless of whether or not the inode was part of the original ++ event. ++ */ ++ ++ mutex_spinunlock(&tevp->te_lock, lc); ++ ++ while ((tdp = tevp->te_tdp) != NULL) { ++ tevp->te_tdp = tdp->td_next; ++ if ((tdp->td_flags & DM_TDF_ORIG) && ++ (tdp->td_flags & DM_TDF_EVTREF) && ++ (!droprights)) { ++ dm_change_right(tdp); ++ } ++ dm_put_tdp(tdp); ++ kmem_cache_free(dm_tokdata_cachep, tdp); ++ } ++ spinlock_destroy(&tevp->te_lock); ++ sv_destroy(&tevp->te_evt_queue); ++ sv_destroy(&tevp->te_app_queue); ++ kfree(tevp); ++} ++ ++ ++/* dm_obj_ref_hold() is just a fancy way to get an inode reference on an object ++ to hold it in kernel memory. ++*/ ++ ++int ++dm_obj_ref_hold( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_NULL, DM_FG_STHREAD, &tdp); ++ ++ /* The tdp is single-threaded, so no mutex lock needed for update. */ ++ ++ if (error == 0) { ++ if (tdp->td_flags & DM_TDF_HOLD) { /* if already held */ ++ error = -EBUSY; ++ } else { ++ tdp->td_flags |= DM_TDF_HOLD; ++ tdp->td_vcount++; ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ (void)fsys_vector->obj_ref_hold(tdp->td_ip); ++ } ++ dm_app_put_tdp(tdp); ++ } ++ return(error); ++} ++ ++ ++int ++dm_obj_ref_rele( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen) ++{ ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_NULL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); ++ ++ /* The tdp is single-threaded, so no mutex lock needed for update. */ ++ ++ if (error == 0) { ++ if (!(tdp->td_flags & DM_TDF_HOLD)) { /* if not held */ ++ error = -EACCES; /* use the DM_FG_MUSTEXIST errno */ ++ } else { ++ tdp->td_flags &= ~DM_TDF_HOLD; ++ iput(tdp->td_ip); ++ tdp->td_vcount--; ++ } ++ dm_app_put_tdp(tdp); ++ } ++ return(error); ++} ++ ++ ++int ++dm_obj_ref_query_rvp( ++ dm_sessid_t sid, ++ dm_token_t token, ++ void __user *hanp, ++ size_t hlen, ++ int *rvp) ++{ ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, ++ DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp); ++ if (error != 0) ++ return(error); ++ ++ /* If the request is valid but the handle just isn't present in the ++ event or the hold flag isn't set, return zero, else return one. ++ */ ++ ++ if (tdp) { ++ if (tdp->td_flags & DM_TDF_HOLD) { /* if held */ ++ *rvp = 1; ++ } else { ++ *rvp = 0; ++ } ++ dm_app_put_tdp(tdp); ++ } else { ++ *rvp = 0; ++ } ++ return(0); ++} ++ ++ ++int ++dm_downgrade_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_EXCL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); ++ if (error != 0) ++ return(error); ++ ++ /* Attempt the downgrade. Filesystems which support rights but not ++ the downgrading of rights will return ENOSYS. ++ */ ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->downgrade_right(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); ++ ++ /* The tdp is single-threaded, so no mutex lock needed for update. */ ++ ++ if (error == 0) ++ tdp->td_right = DM_RIGHT_SHARED; ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_query_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ dm_right_t __user *rightp) ++{ ++ dm_tokdata_t *tdp; ++ dm_right_t right; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp); ++ if (error != 0) ++ return(error); ++ ++ /* Get the current right and copy it to the caller. The tdp is ++ single-threaded, so no mutex lock is needed. If the tdp is not in ++ the event we are supposed to return DM_RIGHT_NULL in order to be ++ compatible with Veritas. ++ */ ++ ++ if (tdp) { ++ right = tdp->td_right; ++ dm_app_put_tdp(tdp); ++ } else { ++ right = DM_RIGHT_NULL; ++ } ++ if (copy_to_user(rightp, &right, sizeof(right))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++int ++dm_release_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->release_right(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); ++ ++ /* The tdp is single-threaded, so no mutex lock needed for update. */ ++ ++ if (error == 0) { ++ tdp->td_right = DM_RIGHT_NULL; ++ if (tdp->td_flags & DM_TDF_RIGHT) { ++ tdp->td_flags &= ~DM_TDF_RIGHT; ++ iput(tdp->td_ip); ++ tdp->td_vcount--; ++ } ++ } ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_request_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token, ++ u_int flags, ++ dm_right_t right) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_NULL, DM_FG_STHREAD, &tdp); ++ if (error != 0) ++ return(error); ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->request_right(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), flags, right); ++ ++ /* The tdp is single-threaded, so no mutex lock is needed for update. ++ ++ If this is the first dm_request_right call for this inode, then we ++ need to bump the inode reference count for two reasons. First of ++ all, it is supposed to be impossible for the file to disappear or ++ for the filesystem to be unmounted while a right is held on a file; ++ bumping the file's inode reference count ensures this. Second, if ++ rights are ever actually implemented, it will most likely be done ++ without changes to the on-disk inode, which means that we can't let ++ the inode become unreferenced while a right on it is held. ++ */ ++ ++ if (error == 0) { ++ if (!(tdp->td_flags & DM_TDF_RIGHT)) { /* if first call */ ++ tdp->td_flags |= DM_TDF_RIGHT; ++ tdp->td_vcount++; ++ (void)fsys_vector->obj_ref_hold(tdp->td_ip); ++ } ++ tdp->td_right = right; ++ } ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} ++ ++ ++int ++dm_upgrade_right( ++ dm_sessid_t sid, ++ void __user *hanp, ++ size_t hlen, ++ dm_token_t token) ++{ ++ dm_fsys_vector_t *fsys_vector; ++ dm_tokdata_t *tdp; ++ int error; ++ ++ error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, ++ DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); ++ if (error != 0) ++ return(error); ++ ++ /* If the object already has the DM_RIGHT_EXCL right, no need to ++ attempt an upgrade. ++ */ ++ ++ if (tdp->td_right == DM_RIGHT_EXCL) { ++ dm_app_put_tdp(tdp); ++ return(0); ++ } ++ ++ /* Attempt the upgrade. Filesystems which support rights but not ++ the upgrading of rights will return ENOSYS. ++ */ ++ ++ fsys_vector = dm_fsys_vector(tdp->td_ip); ++ error = fsys_vector->upgrade_right(tdp->td_ip, tdp->td_right, ++ (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); ++ ++ /* The tdp is single-threaded, so no mutex lock needed for update. */ ++ ++ if (error == 0) ++ tdp->td_right = DM_RIGHT_EXCL; ++ ++ dm_app_put_tdp(tdp); ++ return(error); ++} +Index: linux-2.6.26/fs/dmapi/dmapi_session.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_session.c +@@ -0,0 +1,1825 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#include ++#include ++#include ++#ifdef CONFIG_PROC_FS ++#include ++#endif ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++dm_session_t *dm_sessions = NULL; /* head of session list */ ++u_int dm_sessions_active = 0; /* # sessions currently active */ ++dm_sessid_t dm_next_sessid = 1; /* next session ID to use */ ++lock_t dm_session_lock = SPIN_LOCK_UNLOCKED;/* lock for session list */ ++ ++dm_token_t dm_next_token = 1; /* next token ID to use */ ++dm_sequence_t dm_next_sequence = 1; /* next sequence number to use */ ++lock_t dm_token_lock = SPIN_LOCK_UNLOCKED;/* dm_next_token/dm_next_sequence lock */ ++ ++int dm_max_queued_msgs = 2048; /* max # undelivered msgs/session */ ++ ++int dm_hash_buckets = 1009; /* prime -- number of buckets */ ++ ++#define DM_SHASH(sess,inodenum) \ ++ ((sess)->sn_sesshash + do_mod((inodenum), dm_hash_buckets)) ++ ++ ++#ifdef CONFIG_PROC_FS ++static int ++sessions_read_pfs(char *buffer, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len; ++ dm_session_t *sessp = (dm_session_t*)data; ++ ++#define CHKFULL if(len >= count) break; ++#define ADDBUF(a,b) len += sprintf(buffer + len, a, b); CHKFULL; ++ ++ len=0; ++ while(1){ ++ ADDBUF("sessp=0x%p\n", sessp); ++ ADDBUF("sn_next=0x%p\n", sessp->sn_next); ++ ADDBUF("sn_sessid=%d\n", sessp->sn_sessid); ++ ADDBUF("sn_flags=%x\n", sessp->sn_flags); ++ ADDBUF("sn_qlock=%c\n", '?'); ++ ADDBUF("sn_readerq=%c\n", '?'); ++ ADDBUF("sn_writerq=%c\n", '?'); ++ ADDBUF("sn_readercnt=%u\n", sessp->sn_readercnt); ++ ADDBUF("sn_writercnt=%u\n", sessp->sn_writercnt); ++ ++ ADDBUF("sn_newq.eq_head=0x%p\n", sessp->sn_newq.eq_head); ++ ADDBUF("sn_newq.eq_tail=0x%p\n", sessp->sn_newq.eq_tail); ++ ADDBUF("sn_newq.eq_count=%d\n", sessp->sn_newq.eq_count); ++ ++ ADDBUF("sn_delq.eq_head=0x%p\n", sessp->sn_delq.eq_head); ++ ADDBUF("sn_delq.eq_tail=0x%p\n", sessp->sn_delq.eq_tail); ++ ADDBUF("sn_delq.eq_count=%d\n", sessp->sn_delq.eq_count); ++ ++ ADDBUF("sn_evt_writerq.eq_head=0x%p\n", sessp->sn_evt_writerq.eq_head); ++ ADDBUF("sn_evt_writerq.eq_tail=0x%p\n", sessp->sn_evt_writerq.eq_tail); ++ ADDBUF("sn_evt_writerq.eq_count=%d\n", sessp->sn_evt_writerq.eq_count); ++ ++ ADDBUF("sn_info=\"%s\"\n", sessp->sn_info); ++ ++ break; ++ } ++ ++ if (offset >= len) { ++ *start = buffer; ++ *eof = 1; ++ return 0; ++ } ++ *start = buffer + offset; ++ if ((len -= offset) > count) ++ return count; ++ *eof = 1; ++ ++ return len; ++} ++#endif ++ ++ ++/* Link a session to the end of the session list. New sessions are always ++ added at the end of the list so that dm_enqueue_mount_event() doesn't ++ miss a session. The caller must have obtained dm_session_lock before ++ calling this routine. ++*/ ++ ++static void ++link_session( ++ dm_session_t *s) ++{ ++ dm_session_t *tmp; ++ ++ if ((tmp = dm_sessions) == NULL) { ++ dm_sessions = s; ++ } else { ++ while (tmp->sn_next != NULL) ++ tmp = tmp->sn_next; ++ tmp->sn_next = s; ++ } ++ s->sn_next = NULL; ++ dm_sessions_active++; ++} ++ ++ ++/* Remove a session from the session list. The caller must have obtained ++ dm_session_lock before calling this routine. unlink_session() should only ++ be used in situations where the session is known to be on the dm_sessions ++ list; otherwise it panics. ++*/ ++ ++static void ++unlink_session( ++ dm_session_t *s) ++{ ++ dm_session_t *tmp; ++ ++ if (dm_sessions == s) { ++ dm_sessions = dm_sessions->sn_next; ++ } else { ++ for (tmp = dm_sessions; tmp; tmp = tmp->sn_next) { ++ if (tmp->sn_next == s) ++ break; ++ } ++ if (tmp == NULL) { ++ panic("unlink_session: corrupt DMAPI session list, " ++ "dm_sessions %p, session %p\n", ++ dm_sessions, s); ++ } ++ tmp->sn_next = s->sn_next; ++ } ++ s->sn_next = NULL; ++ dm_sessions_active--; ++} ++ ++ ++/* Link an event to the end of an event queue. The caller must have obtained ++ the session's sn_qlock before calling this routine. ++*/ ++ ++void ++dm_link_event( ++ dm_tokevent_t *tevp, ++ dm_eventq_t *queue) ++{ ++ if (queue->eq_tail) { ++ queue->eq_tail->te_next = tevp; ++ queue->eq_tail = tevp; ++ } else { ++ queue->eq_head = queue->eq_tail = tevp; ++ } ++ tevp->te_next = NULL; ++ queue->eq_count++; ++} ++ ++ ++/* Remove an event from an event queue. The caller must have obtained the ++ session's sn_qlock before calling this routine. dm_unlink_event() should ++ only be used in situations where the event is known to be on the queue; ++ otherwise it panics. ++*/ ++ ++void ++dm_unlink_event( ++ dm_tokevent_t *tevp, ++ dm_eventq_t *queue) ++{ ++ dm_tokevent_t *tmp; ++ ++ if (queue->eq_head == tevp) { ++ queue->eq_head = tevp->te_next; ++ if (queue->eq_head == NULL) ++ queue->eq_tail = NULL; ++ } else { ++ tmp = queue->eq_head; ++ while (tmp && tmp->te_next != tevp) ++ tmp = tmp->te_next; ++ if (tmp == NULL) { ++ panic("dm_unlink_event: corrupt DMAPI queue %p, " ++ "tevp %p\n", queue, tevp); ++ } ++ tmp->te_next = tevp->te_next; ++ if (tmp->te_next == NULL) ++ queue->eq_tail = tmp; ++ } ++ tevp->te_next = NULL; ++ queue->eq_count--; ++} ++ ++/* Link a regular file event to a hash bucket. The caller must have obtained ++ the session's sn_qlock before calling this routine. ++ The tokevent must be for a regular file object--DM_TDT_REG. ++*/ ++ ++static void ++hash_event( ++ dm_session_t *s, ++ dm_tokevent_t *tevp) ++{ ++ dm_sesshash_t *sh; ++ dm_ino_t ino; ++ ++ if (s->sn_sesshash == NULL) { ++ s->sn_sesshash = kmalloc(dm_hash_buckets * sizeof(dm_sesshash_t), GFP_KERNEL); ++ if (s->sn_sesshash == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return; ++ } ++ memset(s->sn_sesshash, 0, dm_hash_buckets * sizeof(dm_sesshash_t)); ++ } ++ ++ ino = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino; ++ sh = DM_SHASH(s, ino); ++ ++#ifdef DM_SHASH_DEBUG ++ if (sh->h_next == NULL) { ++ s->sn_buckets_in_use++; ++ if (s->sn_buckets_in_use > s->sn_max_buckets_in_use) ++ s->sn_max_buckets_in_use++; ++ } ++ sh->maxlength++; ++ sh->curlength++; ++ sh->num_adds++; ++#endif ++ ++ tevp->te_flags |= DM_TEF_HASHED; ++ tevp->te_hashnext = sh->h_next; ++ sh->h_next = tevp; ++} ++ ++ ++/* Remove a regular file event from a hash bucket. The caller must have ++ obtained the session's sn_qlock before calling this routine. ++ The tokevent must be for a regular file object--DM_TDT_REG. ++*/ ++ ++static void ++unhash_event( ++ dm_session_t *s, ++ dm_tokevent_t *tevp) ++{ ++ dm_sesshash_t *sh; ++ dm_tokevent_t *tmp; ++ dm_ino_t ino; ++ ++ if (s->sn_sesshash == NULL) ++ return; ++ ++ ino = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino; ++ sh = DM_SHASH(s, ino); ++ ++ if (sh->h_next == tevp) { ++ sh->h_next = tevp->te_hashnext; /* leap frog */ ++ } else { ++ tmp = sh->h_next; ++ while (tmp->te_hashnext != tevp) { ++ tmp = tmp->te_hashnext; ++ } ++ tmp->te_hashnext = tevp->te_hashnext; /* leap frog */ ++ } ++ tevp->te_hashnext = NULL; ++ tevp->te_flags &= ~DM_TEF_HASHED; ++ ++#ifdef DM_SHASH_DEBUG ++ if (sh->h_next == NULL) ++ s->sn_buckets_in_use--; ++ sh->curlength--; ++ sh->num_dels++; ++#endif ++} ++ ++ ++/* Determine if this is a repeat event. The caller MUST be holding ++ the session lock. ++ The tokevent must be for a regular file object--DM_TDT_REG. ++ Returns: ++ 0 == match not found ++ 1 == match found ++*/ ++ ++static int ++repeated_event( ++ dm_session_t *s, ++ dm_tokevent_t *tevp) ++{ ++ dm_sesshash_t *sh; ++ dm_data_event_t *d_event1; ++ dm_data_event_t *d_event2; ++ dm_tokevent_t *tevph; ++ dm_ino_t ino1; ++ dm_ino_t ino2; ++ ++ if ((!s->sn_newq.eq_tail) && (!s->sn_delq.eq_tail)) { ++ return(0); ++ } ++ if (s->sn_sesshash == NULL) { ++ return(0); ++ } ++ ++ ino1 = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino; ++ sh = DM_SHASH(s, ino1); ++ ++ if (sh->h_next == NULL) { ++ /* bucket is empty, no match here */ ++ return(0); ++ } ++ ++ d_event1 = (dm_data_event_t *)((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset); ++ tevph = sh->h_next; ++ while (tevph) { ++ /* find something with the same event type and handle type */ ++ if ((tevph->te_msg.ev_type == tevp->te_msg.ev_type) && ++ (tevph->te_tdp->td_type == tevp->te_tdp->td_type)) { ++ ++ ino2 = (&tevp->te_tdp->td_handle.ha_fid)->dm_fid_ino; ++ d_event2 = (dm_data_event_t *)((char *)&tevph->te_msg + tevph->te_msg.ev_data.vd_offset); ++ ++ /* If the two events are operating on the same file, ++ and the same part of that file, then we have a ++ match. ++ */ ++ if ((ino1 == ino2) && ++ (d_event2->de_offset == d_event1->de_offset) && ++ (d_event2->de_length == d_event1->de_length)) { ++ /* found a match */ ++#ifdef DM_SHASH_DEBUG ++ sh->dup_hits++; ++#endif ++ return(1); ++ } ++ } ++ tevph = tevph->te_hashnext; ++ } ++ ++ /* No match found */ ++ return(0); ++} ++ ++ ++/* Return a pointer to a session given its session ID, or EINVAL if no session ++ has the session ID (per the DMAPI spec). The caller must have obtained ++ dm_session_lock before calling this routine. ++*/ ++ ++static int ++dm_find_session( ++ dm_sessid_t sid, ++ dm_session_t **sessionpp) ++{ ++ dm_session_t *s; ++ ++ for (s = dm_sessions; s; s = s->sn_next) { ++ if (s->sn_sessid == sid) { ++ *sessionpp = s; ++ return(0); ++ } ++ } ++ return(-EINVAL); ++} ++ ++ ++/* Return a pointer to a locked session given its session ID. '*lcp' is ++ used to obtain the session's sn_qlock. Caller is responsible for eventually ++ unlocking it. ++*/ ++ ++int ++dm_find_session_and_lock( ++ dm_sessid_t sid, ++ dm_session_t **sessionpp, ++ unsigned long *lcp) /* addr of returned lock cookie */ ++{ ++ int error; ++ ++ for (;;) { ++ *lcp = mutex_spinlock(&dm_session_lock); ++ ++ if ((error = dm_find_session(sid, sessionpp)) != 0) { ++ mutex_spinunlock(&dm_session_lock, *lcp); ++ return(error); ++ } ++ if (spin_trylock(&(*sessionpp)->sn_qlock)) { ++ nested_spinunlock(&dm_session_lock); ++ return(0); /* success */ ++ } ++ ++ /* If the second lock is not available, drop the first and ++ start over. This gives the CPU a chance to process any ++ interrupts, and also allows processes which want a sn_qlock ++ for a different session to proceed. ++ */ ++ ++ mutex_spinunlock(&dm_session_lock, *lcp); ++ } ++} ++ ++ ++/* Return a pointer to the event on the specified session's sn_delq which ++ contains the given token. The caller must have obtained the session's ++ sn_qlock before calling this routine. ++*/ ++ ++static int ++dm_find_msg( ++ dm_session_t *s, ++ dm_token_t token, ++ dm_tokevent_t **tevpp) ++{ ++ dm_tokevent_t *tevp; ++ ++ if (token <= DM_INVALID_TOKEN) ++ return(-EINVAL); ++ ++ for (tevp = s->sn_delq.eq_head; tevp; tevp = tevp->te_next) { ++ if (tevp->te_msg.ev_token == token) { ++ *tevpp = tevp; ++ return(0); ++ } ++ } ++ return(-ESRCH); ++} ++ ++ ++/* Given a session ID and token, find the tevp on the specified session's ++ sn_delq which corresponds to that session ID/token pair. If a match is ++ found, lock the tevp's te_lock and return a pointer to the tevp. ++ '*lcp' is used to obtain the tevp's te_lock. The caller is responsible ++ for eventually unlocking it. ++*/ ++ ++int ++dm_find_msg_and_lock( ++ dm_sessid_t sid, ++ dm_token_t token, ++ dm_tokevent_t **tevpp, ++ unsigned long *lcp) /* address of returned lock cookie */ ++{ ++ dm_session_t *s; ++ int error; ++ ++ if ((error = dm_find_session_and_lock(sid, &s, lcp)) != 0) ++ return(error); ++ ++ if ((error = dm_find_msg(s, token, tevpp)) != 0) { ++ mutex_spinunlock(&s->sn_qlock, *lcp); ++ return(error); ++ } ++ nested_spinlock(&(*tevpp)->te_lock); ++ nested_spinunlock(&s->sn_qlock); ++ return(0); ++} ++ ++ ++/* Create a new session, or resume an old session if one is given. */ ++ ++int ++dm_create_session( ++ dm_sessid_t old, ++ char __user *info, ++ dm_sessid_t __user *new) ++{ ++ dm_session_t *s; ++ dm_sessid_t sid; ++ char sessinfo[DM_SESSION_INFO_LEN]; ++ size_t len; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ len = strnlen_user(info, DM_SESSION_INFO_LEN-1); ++ if (copy_from_user(sessinfo, info, len)) ++ return(-EFAULT); ++ lc = mutex_spinlock(&dm_session_lock); ++ sid = dm_next_sessid++; ++ mutex_spinunlock(&dm_session_lock, lc); ++ if (copy_to_user(new, &sid, sizeof(sid))) ++ return(-EFAULT); ++ ++ if (old == DM_NO_SESSION) { ++ s = kmem_cache_alloc(dm_session_cachep, GFP_KERNEL); ++ if (s == NULL) { ++ printk("%s/%d: kmem_cache_alloc(dm_session_cachep) returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ memset(s, 0, sizeof(*s)); ++ ++ sv_init(&s->sn_readerq, SV_DEFAULT, "dmreadq"); ++ sv_init(&s->sn_writerq, SV_DEFAULT, "dmwritq"); ++ spinlock_init(&s->sn_qlock, "sn_qlock"); ++ } else { ++ lc = mutex_spinlock(&dm_session_lock); ++ if ((error = dm_find_session(old, &s)) != 0) { ++ mutex_spinunlock(&dm_session_lock, lc); ++ return(error); ++ } ++ unlink_session(s); ++ mutex_spinunlock(&dm_session_lock, lc); ++#ifdef CONFIG_PROC_FS ++ { ++ char buf[100]; ++ sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s); ++ remove_proc_entry(buf, NULL); ++ } ++#endif ++ } ++ memcpy(s->sn_info, sessinfo, len); ++ s->sn_info[len-1] = 0; /* if not NULL, then now 'tis */ ++ s->sn_sessid = sid; ++ lc = mutex_spinlock(&dm_session_lock); ++ link_session(s); ++ mutex_spinunlock(&dm_session_lock, lc); ++#ifdef CONFIG_PROC_FS ++ { ++ char buf[100]; ++ struct proc_dir_entry *entry; ++ ++ sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s); ++ entry = create_proc_read_entry(buf, 0, NULL, sessions_read_pfs, s); ++ entry->owner = THIS_MODULE; ++ } ++#endif ++ return(0); ++} ++ ++ ++int ++dm_destroy_session( ++ dm_sessid_t sid) ++{ ++ dm_session_t *s; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ /* The dm_session_lock must be held until the session is unlinked. */ ++ ++ lc = mutex_spinlock(&dm_session_lock); ++ ++ if ((error = dm_find_session(sid, &s)) != 0) { ++ mutex_spinunlock(&dm_session_lock, lc); ++ return(error); ++ } ++ nested_spinlock(&s->sn_qlock); ++ ++ /* The session exists. Check to see if it is still in use. If any ++ messages still exist on the sn_newq or sn_delq, or if any processes ++ are waiting for messages to arrive on the session, then the session ++ must not be destroyed. ++ */ ++ ++ if (s->sn_newq.eq_head || s->sn_readercnt || s->sn_delq.eq_head) { ++ nested_spinunlock(&s->sn_qlock); ++ mutex_spinunlock(&dm_session_lock, lc); ++ return(-EBUSY); ++ } ++ ++ /* The session is not in use. Dequeue it from the session chain. */ ++ ++ unlink_session(s); ++ nested_spinunlock(&s->sn_qlock); ++ mutex_spinunlock(&dm_session_lock, lc); ++ ++#ifdef CONFIG_PROC_FS ++ { ++ char buf[100]; ++ sprintf(buf, DMAPI_DBG_PROCFS "/sessions/0x%p", s); ++ remove_proc_entry(buf, NULL); ++ } ++#endif ++ ++ /* Now clear the sessions's disposition registration, and then destroy ++ the session structure. ++ */ ++ ++ dm_clear_fsreg(s); ++ ++ spinlock_destroy(&s->sn_qlock); ++ sv_destroy(&s->sn_readerq); ++ sv_destroy(&s->sn_writerq); ++ if (s->sn_sesshash) ++ kfree(s->sn_sesshash); ++ kmem_cache_free(dm_session_cachep, s); ++ return(0); ++} ++ ++ ++/* ++ * Return a list of all active sessions. ++ */ ++ ++int ++dm_getall_sessions( ++ u_int nelem, ++ dm_sessid_t __user *sidp, ++ u_int __user *nelemp) ++{ ++ dm_session_t *s; ++ u_int sesscnt; ++ dm_sessid_t *sesslist; ++ unsigned long lc; /* lock cookie */ ++ int error; ++ int i; ++ ++ /* Loop until we can get the right amount of temp space, being careful ++ not to hold a mutex during the allocation. Usually only one trip. ++ */ ++ ++ for (;;) { ++ if ((sesscnt = dm_sessions_active) == 0) { ++ /*if (suword(nelemp, 0))*/ ++ if (put_user(0, nelemp)) ++ return(-EFAULT); ++ return(0); ++ } ++ sesslist = kmalloc(sesscnt * sizeof(*sidp), GFP_KERNEL); ++ if (sesslist == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ lc = mutex_spinlock(&dm_session_lock); ++ if (sesscnt == dm_sessions_active) ++ break; ++ ++ mutex_spinunlock(&dm_session_lock, lc); ++ kfree(sesslist); ++ } ++ ++ /* Make a temp copy of the data, then release the mutex. */ ++ ++ for (i = 0, s = dm_sessions; i < sesscnt; i++, s = s->sn_next) ++ sesslist[i] = s->sn_sessid; ++ ++ mutex_spinunlock(&dm_session_lock, lc); ++ ++ /* Now copy the data to the user. */ ++ ++ if(put_user(sesscnt, nelemp)) { ++ error = -EFAULT; ++ } else if (sesscnt > nelem) { ++ error = -E2BIG; ++ } else if (copy_to_user(sidp, sesslist, sesscnt * sizeof(*sidp))) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ kfree(sesslist); ++ return(error); ++} ++ ++ ++/* ++ * Return the descriptive string associated with a session. ++ */ ++ ++int ++dm_query_session( ++ dm_sessid_t sid, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_session_t *s; /* pointer to session given by sid */ ++ int len; /* length of session info string */ ++ int error; ++ char sessinfo[DM_SESSION_INFO_LEN]; ++ unsigned long lc; /* lock cookie */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) ++ return(error); ++ ++ len = strlen(s->sn_info) + 1; /* NULL terminated when created */ ++ memcpy(sessinfo, s->sn_info, len); ++ ++ mutex_spinunlock(&s->sn_qlock, lc); ++ ++ /* Now that the mutex is released, copy the sessinfo to the user. */ ++ ++ if (put_user(len, rlenp)) { ++ error = -EFAULT; ++ } else if (len > buflen) { ++ error = -E2BIG; ++ } else if (copy_to_user(bufp, sessinfo, len)) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ return(error); ++} ++ ++ ++/* ++ * Return all of the previously delivered tokens (that is, their IDs) ++ * for the given session. ++ */ ++ ++int ++dm_getall_tokens( ++ dm_sessid_t sid, /* session obtaining tokens from */ ++ u_int nelem, /* size of tokenbufp */ ++ dm_token_t __user *tokenbufp,/* buffer to copy token IDs to */ ++ u_int __user *nelemp) /* return number copied to tokenbufp */ ++{ ++ dm_session_t *s; /* pointer to session given by sid */ ++ dm_tokevent_t *tevp; /* event message queue traversal */ ++ unsigned long lc; /* lock cookie */ ++ int tokcnt; ++ dm_token_t *toklist; ++ int error; ++ int i; ++ ++ /* Loop until we can get the right amount of temp space, being careful ++ not to hold a mutex during the allocation. Usually only one trip. ++ */ ++ ++ for (;;) { ++ if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) ++ return(error); ++ tokcnt = s->sn_delq.eq_count; ++ mutex_spinunlock(&s->sn_qlock, lc); ++ ++ if (tokcnt == 0) { ++ /*if (suword(nelemp, 0))*/ ++ if (put_user(0, nelemp)) ++ return(-EFAULT); ++ return(0); ++ } ++ toklist = kmalloc(tokcnt * sizeof(*tokenbufp), GFP_KERNEL); ++ if (toklist == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) { ++ kfree(toklist); ++ return(error); ++ } ++ ++ if (tokcnt == s->sn_delq.eq_count) ++ break; ++ ++ mutex_spinunlock(&s->sn_qlock, lc); ++ kfree(toklist); ++ } ++ ++ /* Make a temp copy of the data, then release the mutex. */ ++ ++ tevp = s->sn_delq.eq_head; ++ for (i = 0; i < tokcnt; i++, tevp = tevp->te_next) ++ toklist[i] = tevp->te_msg.ev_token; ++ ++ mutex_spinunlock(&s->sn_qlock, lc); ++ ++ /* Now copy the data to the user. */ ++ ++ if (put_user(tokcnt, nelemp)) { ++ error = -EFAULT; ++ } else if (tokcnt > nelem) { ++ error = -E2BIG; ++ } else if (copy_to_user(tokenbufp,toklist,tokcnt*sizeof(*tokenbufp))) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ kfree(toklist); ++ return(error); ++} ++ ++ ++/* ++ * Return the message identified by token. ++ */ ++ ++int ++dm_find_eventmsg( ++ dm_sessid_t sid, ++ dm_token_t token, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_tokevent_t *tevp; /* message identified by token */ ++ int msgsize; /* size of message to copy out */ ++ void *msg; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ /* Because some of the events (dm_data_event_t in particular) contain ++ __u64 fields, we need to make sure that the buffer provided by the ++ caller is aligned such that he can read those fields successfully. ++ */ ++ ++ if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0) ++ return(-EFAULT); ++ ++ /* Allocate the right amount of temp space, being careful not to hold ++ a mutex during the allocation. ++ */ ++ ++ if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) ++ return(error); ++ msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg); ++ mutex_spinunlock(&tevp->te_lock, lc); ++ ++ msg = kmalloc(msgsize, GFP_KERNEL); ++ if (msg == NULL) { ++ printk("%s/%d: kmalloc returned NULL\n", __FUNCTION__, __LINE__); ++ return -ENOMEM; ++ } ++ ++ if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) { ++ kfree(msg); ++ return(error); ++ } ++ ++ /* Make a temp copy of the data, then release the mutex. */ ++ ++ memcpy(msg, &tevp->te_msg, msgsize); ++ mutex_spinunlock(&tevp->te_lock, lc); ++ ++ /* Now copy the data to the user. */ ++ ++ if (put_user(msgsize,rlenp)) { ++ error = -EFAULT; ++ } else if (msgsize > buflen) { /* user buffer not big enough */ ++ error = -E2BIG; ++ } else if (copy_to_user( bufp, msg, msgsize )) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ kfree(msg); ++ return(error); ++} ++ ++ ++int ++dm_move_event( ++ dm_sessid_t srcsid, ++ dm_token_t token, ++ dm_sessid_t targetsid, ++ dm_token_t __user *rtokenp) ++{ ++ dm_session_t *s1; ++ dm_session_t *s2; ++ dm_tokevent_t *tevp; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ int hash_it = 0; ++ ++ lc = mutex_spinlock(&dm_session_lock); ++ ++ if ((error = dm_find_session(srcsid, &s1)) != 0 || ++ (error = dm_find_session(targetsid, &s2)) != 0 || ++ (error = dm_find_msg(s1, token, &tevp)) != 0) { ++ mutex_spinunlock(&dm_session_lock, lc); ++ return(error); ++ } ++ dm_unlink_event(tevp, &s1->sn_delq); ++ if (tevp->te_flags & DM_TEF_HASHED) { ++ unhash_event(s1, tevp); ++ hash_it = 1; ++ } ++ dm_link_event(tevp, &s2->sn_delq); ++ if (hash_it) ++ hash_event(s2, tevp); ++ mutex_spinunlock(&dm_session_lock, lc); ++ ++ if (copy_to_user(rtokenp, &token, sizeof(token))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* ARGSUSED */ ++int ++dm_pending( ++ dm_sessid_t sid, ++ dm_token_t token, ++ dm_timestruct_t __user *delay) /* unused */ ++{ ++ dm_tokevent_t *tevp; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) ++ return(error); ++ ++ tevp->te_flags |= DM_TEF_INTERMED; ++ if (tevp->te_evt_ref > 0) /* if event generation threads exist */ ++ sv_broadcast(&tevp->te_evt_queue); ++ ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return(0); ++} ++ ++ ++int ++dm_get_events( ++ dm_sessid_t sid, ++ u_int maxmsgs, ++ u_int flags, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_session_t *s; /* pointer to session given by sid */ ++ dm_tokevent_t *tevp; /* next event message on queue */ ++ int error; ++ unsigned long lc1; /* first lock cookie */ ++ unsigned long lc2 = 0; /* second lock cookie */ ++ int totalsize; ++ int msgsize; ++ dm_eventmsg_t __user *prevmsg; ++ int prev_msgsize = 0; ++ u_int msgcnt; ++ ++ /* Because some of the events (dm_data_event_t in particular) contain ++ __u64 fields, we need to make sure that the buffer provided by the ++ caller is aligned such that he can read those fields successfully. ++ */ ++ ++ if (((unsigned long)bufp & (sizeof(__u64) - 1)) != 0) ++ return(-EFAULT); ++ ++ /* Find the indicated session and lock it. */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0) ++ return(error); ++ ++ /* Check for messages on sn_newq. If there aren't any that haven't ++ already been grabbed by another process, and if we are supposed to ++ to wait until one shows up, then go to sleep interruptibly on the ++ sn_readerq semaphore. The session can't disappear out from under ++ us as long as sn_readerq is non-zero. ++ */ ++ ++ for (;;) { ++ int rc; ++ ++ for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) { ++ lc2 = mutex_spinlock(&tevp->te_lock); ++ if (!(tevp->te_flags & DM_TEF_LOCKED)) ++ break; ++ mutex_spinunlock(&tevp->te_lock, lc2); ++ } ++ if (tevp) ++ break; /* got one! */ ++ ++ if (!(flags & DM_EV_WAIT)) { ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ return(-EAGAIN); ++ } ++ s->sn_readercnt++; ++ ++ sv_wait_sig(&s->sn_readerq, 1, &s->sn_qlock, lc1); ++ rc = signal_pending(current); ++ ++ lc1 = mutex_spinlock(&s->sn_qlock); ++ s->sn_readercnt--; ++ if (rc) { /* if signal was received */ ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ return(-EINTR); ++ } ++ } ++ ++ /* At least one message is available for delivery, and we have both the ++ session lock and event lock. Mark the event so that it is not ++ grabbed by other daemons, then drop both locks prior copying the ++ data to the caller's buffer. Leaving the event on the queue in a ++ marked state prevents both the session and the event from ++ disappearing out from under us while we don't have the locks. ++ */ ++ ++ tevp->te_flags |= DM_TEF_LOCKED; ++ mutex_spinunlock(&tevp->te_lock, lc2); /* reverse cookie order */ ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ ++ /* Continue to deliver messages until there are no more, the ++ user's buffer becomes full, or we hit his maxmsgs limit. ++ */ ++ ++ totalsize = 0; /* total bytes transferred to the user */ ++ prevmsg = NULL; ++ msgcnt = 0; ++ ++ while (tevp) { ++ /* Compute the number of bytes to be moved, rounding up to an ++ 8-byte boundary so that any subsequent messages will also be ++ aligned. ++ */ ++ ++ msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg); ++ msgsize = (msgsize + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1); ++ totalsize += msgsize; ++ ++ /* If it fits, copy the message into the user's buffer and ++ update his 'rlenp'. Update the _link pointer for any ++ previous message. ++ */ ++ ++ if (totalsize > buflen) { /* no more room */ ++ error = -E2BIG; ++ } else if (put_user(totalsize, rlenp)) { ++ error = -EFAULT; ++ } else if (copy_to_user(bufp, &tevp->te_msg, msgsize)) { ++ error = -EFAULT; ++ } else if (prevmsg && put_user(prev_msgsize, &prevmsg->_link)) { ++ error = -EFAULT; ++ } else { ++ error = 0; ++ } ++ ++ /* If an error occurred, just unmark the event and leave it on ++ the queue for someone else. Note that other daemons may ++ have gone to sleep because this event was marked, so wake ++ them up. Also, if at least one message has already been ++ delivered, then an error here is not really an error. ++ */ ++ ++ lc1 = mutex_spinlock(&s->sn_qlock); ++ lc2 = mutex_spinlock(&tevp->te_lock); ++ tevp->te_flags &= ~DM_TEF_LOCKED; /* drop the mark */ ++ ++ if (error) { ++ if (s->sn_readercnt) ++ sv_signal(&s->sn_readerq); ++ ++ mutex_spinunlock(&tevp->te_lock, lc2); /* rev. order */ ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ if (prevmsg) ++ return(0); ++ if (error == -E2BIG && put_user(totalsize,rlenp)) ++ error = -EFAULT; ++ return(error); ++ } ++ ++ /* The message was successfully delivered. Unqueue it. */ ++ ++ dm_unlink_event(tevp, &s->sn_newq); ++ ++ /* Wake up the first of any processes waiting for room on the ++ sn_newq. ++ */ ++ ++ if (s->sn_writercnt) ++ sv_signal(&s->sn_writerq); ++ ++ /* If the message is synchronous, add it to the sn_delq while ++ still holding the lock. If it is asynchronous, free it. ++ */ ++ ++ if (tevp->te_msg.ev_token != DM_INVALID_TOKEN) { /* synch */ ++ dm_link_event(tevp, &s->sn_delq); ++ mutex_spinunlock(&tevp->te_lock, lc2); ++ } else { ++ tevp->te_flags |= DM_TEF_FINAL; ++ if (tevp->te_flags & DM_TEF_HASHED) ++ unhash_event(s, tevp); ++ mutex_spinunlock(&tevp->te_lock, lc2); ++ dm_put_tevp(tevp, NULL);/* can't cause destroy events */ ++ } ++ ++ /* Update our notion of where we are in the user's buffer. If ++ he doesn't want any more messages, then stop. ++ */ ++ ++ prevmsg = (dm_eventmsg_t __user *)bufp; ++ prev_msgsize = msgsize; ++ bufp = (char __user *)bufp + msgsize; ++ ++ msgcnt++; ++ if (maxmsgs && msgcnt >= maxmsgs) { ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ break; ++ } ++ ++ /* While still holding the sn_qlock, see if any additional ++ messages are available for delivery. ++ */ ++ ++ for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) { ++ lc2 = mutex_spinlock(&tevp->te_lock); ++ if (!(tevp->te_flags & DM_TEF_LOCKED)) { ++ tevp->te_flags |= DM_TEF_LOCKED; ++ mutex_spinunlock(&tevp->te_lock, lc2); ++ break; ++ } ++ mutex_spinunlock(&tevp->te_lock, lc2); ++ } ++ mutex_spinunlock(&s->sn_qlock, lc1); ++ } ++ return(0); ++} ++ ++ ++/* ++ * Remove an event message from the delivered queue, set the returned ++ * error where the event generator wants it, and wake up the generator. ++ * Also currently have the user side release any locks it holds... ++ */ ++ ++/* ARGSUSED */ ++int ++dm_respond_event( ++ dm_sessid_t sid, ++ dm_token_t token, ++ dm_response_t response, ++ int reterror, ++ size_t buflen, /* unused */ ++ void __user *respbufp) /* unused */ ++{ ++ dm_session_t *s; /* pointer to session given by sid */ ++ dm_tokevent_t *tevp; /* event message queue traversal */ ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ /* Sanity check the input parameters. */ ++ ++ switch (response) { ++ case DM_RESP_CONTINUE: /* continue must have reterror == 0 */ ++ if (reterror != 0) ++ return(-EINVAL); ++ break; ++ case DM_RESP_ABORT: /* abort must have errno set */ ++ if (reterror <= 0) ++ return(-EINVAL); ++ break; ++ case DM_RESP_DONTCARE: ++ reterror = -1; /* to distinguish DM_RESP_DONTCARE */ ++ break; ++ default: ++ return(-EINVAL); ++ } ++ ++ /* Hold session lock until the event is unqueued. */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) ++ return(error); ++ ++ if ((error = dm_find_msg(s, token, &tevp)) != 0) { ++ mutex_spinunlock(&s->sn_qlock, lc); ++ return(error); ++ } ++ nested_spinlock(&tevp->te_lock); ++ ++ if ((response == DM_RESP_DONTCARE) && ++ (tevp->te_msg.ev_type != DM_EVENT_MOUNT)) { ++ error = -EINVAL; ++ nested_spinunlock(&tevp->te_lock); ++ mutex_spinunlock(&s->sn_qlock, lc); ++ } else { ++ dm_unlink_event(tevp, &s->sn_delq); ++ if (tevp->te_flags & DM_TEF_HASHED) ++ unhash_event(s, tevp); ++ tevp->te_reply = -reterror; /* linux wants negative errno */ ++ tevp->te_flags |= DM_TEF_FINAL; ++ if (tevp->te_evt_ref) ++ sv_broadcast(&tevp->te_evt_queue); ++ nested_spinunlock(&tevp->te_lock); ++ mutex_spinunlock(&s->sn_qlock, lc); ++ error = 0; ++ ++ /* Absolutely no locks can be held when calling dm_put_tevp! */ ++ ++ dm_put_tevp(tevp, NULL); /* this can generate destroy events */ ++ } ++ return(error); ++} ++ ++/* The caller must hold sn_qlock. ++ This will return the tokevent locked. ++ */ ++static dm_tokevent_t * ++__find_match_event_no_waiters_locked( ++ dm_tokevent_t *tevp1, ++ dm_eventq_t *queue) ++{ ++ dm_tokevent_t *tevp2, *next_tevp; ++ dm_tokdata_t *tdp1 = tevp1->te_tdp; ++ dm_tokdata_t *tdp2; ++ dm_data_event_t *d_event1; ++ dm_data_event_t *d_event2; ++ ++ d_event1 = (dm_data_event_t *)((char *)&tevp1->te_msg + tevp1->te_msg.ev_data.vd_offset); ++ ++ for(tevp2 = queue->eq_head; tevp2; tevp2 = next_tevp) { ++ nested_spinlock(&tevp2->te_lock); ++ next_tevp = tevp2->te_next; ++ ++ /* Just compare the first tdp's in each--there should ++ be just one, if it's the match we want. ++ */ ++ tdp2 = tevp2->te_tdp; ++ if ((tevp2->te_msg.ev_type == tevp1->te_msg.ev_type) && ++ (tevp2->te_tdp->td_type == tevp1->te_tdp->td_type) && ++ (tevp2->te_evt_ref == 0) && (tdp2->td_next == NULL) && ++ (memcmp(&tdp1->td_handle, &tdp2->td_handle, ++ sizeof(dm_handle_t)) == 0)) { ++ ++ d_event2 = (dm_data_event_t *)((char *)&tevp2->te_msg + tevp2->te_msg.ev_data.vd_offset); ++ ++ ++ if ((d_event2->de_offset == d_event1->de_offset) && ++ (d_event2->de_length == d_event1->de_length)) { ++ /* Match -- return it locked */ ++ return tevp2; ++ } ++ } ++ nested_spinunlock(&tevp2->te_lock); ++ } ++ return NULL; ++} ++ ++/* The caller must hold the sn_qlock. ++ The returned tokevent will be locked with nested_spinlock. ++ */ ++static dm_tokevent_t * ++find_match_event_no_waiters_locked( ++ dm_session_t *s, ++ dm_tokevent_t *tevp) ++{ ++ dm_tokevent_t *tevp2; ++ ++ if ((!s->sn_newq.eq_tail) && (!s->sn_delq.eq_tail)) ++ return NULL; ++ if (!tevp->te_tdp) ++ return NULL; ++ if (tevp->te_tdp->td_next) { ++ /* If it has multiple tdp's then don't bother trying to ++ find a match. ++ */ ++ return NULL; ++ } ++ tevp2 = __find_match_event_no_waiters_locked(tevp, &s->sn_newq); ++ if (tevp2 == NULL) ++ tevp2 = __find_match_event_no_waiters_locked(tevp, &s->sn_delq); ++ /* returns a locked tokevent */ ++ return tevp2; ++} ++ ++ ++ ++/* Queue the filled in event message pointed to by tevp on the session s, and ++ (if a synchronous event) wait for the reply from the DMAPI application. ++ The caller MUST be holding the session lock before calling this routine! ++ The session lock is always released upon exit. ++ Returns: ++ -1 == don't care ++ 0 == success (or async event) ++ > 0 == errno describing reason for failure ++*/ ++ ++static int ++dm_enqueue( ++ dm_session_t *s, ++ unsigned long lc, /* input lock cookie */ ++ dm_tokevent_t **tevpp, /* in/out parameter */ ++ int sync, ++ int flags, ++ int interruptable) ++{ ++ int is_unmount = 0; ++ int is_hashable = 0; ++ int reply; ++ dm_tokevent_t *tevp = *tevpp; ++ ++ /* If the caller isn't planning to stick around for the result ++ and this request is identical to one that is already on the ++ queues then just give the caller an EAGAIN. Release the ++ session lock before returning. ++ ++ We look only at NDELAY requests with an event type of READ, ++ WRITE, or TRUNCATE on objects that are regular files. ++ */ ++ ++ if ((flags & DM_FLAGS_NDELAY) && DM_EVENT_RDWRTRUNC(tevp) && ++ (tevp->te_tdp->td_type == DM_TDT_REG)) { ++ if (repeated_event(s, tevp)) { ++ mutex_spinunlock(&s->sn_qlock, lc); ++ return -EAGAIN; ++ } ++ is_hashable = 1; ++ } ++ ++ /* If the caller is a sync event then look for a matching sync ++ event. If there is a match and it doesn't currently have ++ event threads waiting on it, then we will drop our own ++ tokevent and jump on the matching event. ++ */ ++ if (((flags & DM_FLAGS_NDELAY) == 0) && DM_EVENT_RDWRTRUNC(tevp) && ++ (tevp->te_tdp->td_type == DM_TDT_REG)) { ++ dm_tokevent_t *tevp2; ++ if ((tevp2 = find_match_event_no_waiters_locked(s, tevp))) { ++ ASSERT(tevp2->te_evt_ref == 0); ++ tevp2->te_evt_ref++; ++ nested_spinunlock(&tevp2->te_lock); ++ nested_spinlock(&tevp->te_lock); ++ tevp->te_evt_ref--; ++ nested_spinunlock(&tevp->te_lock); ++ mutex_spinunlock(&s->sn_qlock, lc); ++ /* All locks have been released */ ++ dm_evt_rele_tevp(tevp, 1); ++ *tevpp = tevp = tevp2; ++ goto wait_on_tevp; ++ } ++ } ++ ++ if (tevp->te_msg.ev_type == DM_EVENT_UNMOUNT) ++ is_unmount = 1; ++ ++ /* Check for room on sn_newq. If there is no room for new messages, ++ then go to sleep on the sn_writerq semaphore. The ++ session cannot disappear out from under us as long as sn_writercnt ++ is non-zero. ++ */ ++ ++ while (s->sn_newq.eq_count >= dm_max_queued_msgs) { /* no room */ ++ s->sn_writercnt++; ++ dm_link_event(tevp, &s->sn_evt_writerq); ++ if (interruptable) { ++ sv_wait_sig(&s->sn_writerq, 1, &s->sn_qlock, lc); ++ if (signal_pending(current)) { ++ s->sn_writercnt--; ++ return -EINTR; ++ } ++ } else { ++ sv_wait(&s->sn_writerq, 1, &s->sn_qlock, lc); ++ } ++ lc = mutex_spinlock(&s->sn_qlock); ++ s->sn_writercnt--; ++ dm_unlink_event(tevp, &s->sn_evt_writerq); ++#ifdef HAVE_DM_QUEUE_FLUSH ++ /* We hold the sn_qlock, from here to after we get into ++ * the sn_newq. Any thread going through ++ * dm_release_threads() looking for us is already past us ++ * and has set the DM_TEF_FLUSH flag for us or is blocked on ++ * sn_qlock and will find us in sn_newq after we release ++ * the sn_qlock. ++ * We check for dop->flushing anyway, in case the ++ * dm_release_threads() already completed before we ++ * could enter dmapi. ++ */ ++ if (!sync) { ++ /* async events are forced into the newq */ ++ break; ++ } ++ if (tevp->te_flags & DM_TEF_FLUSH) { ++ mutex_spinunlock(&s->sn_qlock, lc); ++ return tevp->te_reply; ++ } ++ else { ++ struct filesystem_dmapi_operations *dops; ++ dm_tokdata_t *tdp; ++ int errno = 0; ++ ++ nested_spinlock(&tevp->te_lock); ++ for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { ++ if (tdp->td_ip) { ++ dops = dm_fsys_ops(tdp->td_ip->i_sb); ++ ASSERT(dops); ++ if (dops->flushing) ++ errno = dops->flushing(tdp->td_ip); ++ if (errno) { ++ nested_spinunlock(&tevp->te_lock); ++ mutex_spinunlock(&s->sn_qlock, lc); ++ return errno; ++ } ++ } ++ } ++ nested_spinunlock(&tevp->te_lock); ++ } ++#endif /* HAVE_DM_QUEUE_FLUSH */ ++ } ++ ++ /* Assign a sequence number and token to the event and bump the ++ application reference count by one. We don't need 'te_lock' here ++ because this thread is still the only thread that can see the event. ++ */ ++ ++ nested_spinlock(&dm_token_lock); ++ tevp->te_msg.ev_sequence = dm_next_sequence++; ++ if (sync) { ++ tevp->te_msg.ev_token = dm_next_token++; ++ } else { ++ tevp->te_msg.ev_token = DM_INVALID_TOKEN; ++ } ++ nested_spinunlock(&dm_token_lock); ++ ++ tevp->te_app_ref++; ++ ++ /* Room exists on the sn_newq queue, so add this request. If the ++ queue was previously empty, wake up the first of any processes ++ that are waiting for an event. ++ */ ++ ++ dm_link_event(tevp, &s->sn_newq); ++ if (is_hashable) ++ hash_event(s, tevp); ++ ++ if (s->sn_readercnt) ++ sv_signal(&s->sn_readerq); ++ ++ mutex_spinunlock(&s->sn_qlock, lc); ++ ++ /* Now that the message is queued, processes issuing asynchronous ++ events or DM_EVENT_UNMOUNT events are ready to continue. ++ */ ++ ++ if (!sync || is_unmount) ++ return 0; ++ ++ /* Synchronous requests wait until a final reply is received. If the ++ caller supplied the DM_FLAGS_NDELAY flag, the process will return ++ EAGAIN if dm_pending() sets DM_TEF_INTERMED. We also let users ++ Cntl-C out of a read, write, and truncate requests. ++ */ ++ ++wait_on_tevp: ++ lc = mutex_spinlock(&tevp->te_lock); ++ ++ while (!(tevp->te_flags & DM_TEF_FINAL)) { ++ if ((tevp->te_flags & DM_TEF_INTERMED) && ++ (flags & DM_FLAGS_NDELAY)) { ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return -EAGAIN; ++ } ++ if (tevp->te_msg.ev_type == DM_EVENT_READ || ++ tevp->te_msg.ev_type == DM_EVENT_WRITE || ++ tevp->te_msg.ev_type == DM_EVENT_TRUNCATE) { ++ sv_wait_sig(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); ++ if (signal_pending(current)){ ++ return -EINTR; ++ } ++ } else { ++ sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); ++ } ++ lc = mutex_spinlock(&tevp->te_lock); ++#ifdef HAVE_DM_QUEUE_FLUSH ++ /* Did we pop out because of queue flushing? */ ++ if (tevp->te_flags & DM_TEF_FLUSH) { ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return tevp->te_reply; ++ } ++#endif /* HAVE_DM_QUEUE_FLUSH */ ++ } ++ ++ /* Return both the tevp and the reply which was stored in the tevp by ++ dm_respond_event. The tevp structure has already been removed from ++ the reply queue by this point in dm_respond_event(). ++ */ ++ ++ reply = tevp->te_reply; ++ mutex_spinunlock(&tevp->te_lock, lc); ++ return reply; ++} ++ ++ ++/* The filesystem is guaranteed to stay mounted while this event is ++ outstanding. ++*/ ++ ++int ++dm_enqueue_normal_event( ++ struct super_block *sb, ++ dm_tokevent_t **tevpp, ++ int flags) ++{ ++ dm_session_t *s; ++ int error; ++ int sync; ++ unsigned long lc; /* lock cookie */ ++ ++ switch ((*tevpp)->te_msg.ev_type) { ++ case DM_EVENT_READ: ++ case DM_EVENT_WRITE: ++ case DM_EVENT_TRUNCATE: ++ case DM_EVENT_PREUNMOUNT: ++ case DM_EVENT_UNMOUNT: ++ case DM_EVENT_NOSPACE: ++ case DM_EVENT_CREATE: ++ case DM_EVENT_REMOVE: ++ case DM_EVENT_RENAME: ++ case DM_EVENT_SYMLINK: ++ case DM_EVENT_LINK: ++ case DM_EVENT_DEBUT: /* not currently supported */ ++ sync = 1; ++ break; ++ ++ case DM_EVENT_DESTROY: ++ case DM_EVENT_POSTCREATE: ++ case DM_EVENT_POSTREMOVE: ++ case DM_EVENT_POSTRENAME: ++ case DM_EVENT_POSTSYMLINK: ++ case DM_EVENT_POSTLINK: ++ case DM_EVENT_ATTRIBUTE: ++ case DM_EVENT_CLOSE: /* not currently supported */ ++ case DM_EVENT_CANCEL: /* not currently supported */ ++ sync = 0; ++ break; ++ ++ default: ++ return(-EIO); /* garbage event number */ ++ } ++ ++ /* Wait until a session selects disposition for the event. The session ++ is locked upon return from dm_waitfor_disp_session(). ++ */ ++ ++ if ((error = dm_waitfor_disp_session(sb, *tevpp, &s, &lc)) != 0) ++ return(error); ++ ++ return(dm_enqueue(s, lc, tevpp, sync, flags, 0)); ++} ++ ++ ++/* Traverse the session list checking for sessions with the WANTMOUNT flag ++ set. When one is found, send it the message. Possible responses to the ++ message are one of DONTCARE, CONTINUE, or ABORT. The action taken in each ++ case is: ++ DONTCARE (-1) - Send the event to the next session with WANTMOUNT set ++ CONTINUE ( 0) - Proceed with the mount, errno zero. ++ ABORT (>0) - Fail the mount, return the returned errno. ++ ++ The mount request is sent to sessions in ascending session ID order. ++ Since the session list can change dramatically while this process is ++ sleeping in dm_enqueue(), this routine must use session IDs rather than ++ session pointers when keeping track of where it is in the list. Since ++ new sessions are always added at the end of the queue, and have increasing ++ session ID values, we don't have to worry about missing any session. ++*/ ++ ++int ++dm_enqueue_mount_event( ++ struct super_block *sb, ++ dm_tokevent_t *tevp) ++{ ++ dm_session_t *s; ++ dm_sessid_t sid; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ /* Make the mounting filesystem visible to other DMAPI calls. */ ++ ++ if ((error = dm_add_fsys_entry(sb, tevp)) != 0){ ++ return(error); ++ } ++ ++ /* Walk through the session list presenting the mount event to each ++ session that is interested until a session accepts or rejects it, ++ or until all sessions ignore it. ++ */ ++ ++ for (sid = DM_NO_SESSION, error = 1; error > 0; sid = s->sn_sessid) { ++ ++ lc = mutex_spinlock(&dm_session_lock); ++ for (s = dm_sessions; s; s = s->sn_next) { ++ if (s->sn_sessid > sid && s->sn_flags & DM_SN_WANTMOUNT) { ++ nested_spinlock(&s->sn_qlock); ++ nested_spinunlock(&dm_session_lock); ++ break; ++ } ++ } ++ if (s == NULL) { ++ mutex_spinunlock(&dm_session_lock, lc); ++ break; /* noone wants it; proceed with mount */ ++ } ++ error = dm_enqueue(s, lc, &tevp, 1, 0, 0); ++ } ++ ++ /* If the mount will be allowed to complete, then update the fsrp entry ++ accordingly. If the mount is to be aborted, remove the fsrp entry. ++ */ ++ ++ if (error >= 0) { ++ dm_change_fsys_entry(sb, DM_STATE_MOUNTED); ++ error = 0; ++ } else { ++ dm_remove_fsys_entry(sb); ++ } ++ return(error); ++} ++ ++int ++dm_enqueue_sendmsg_event( ++ dm_sessid_t targetsid, ++ dm_tokevent_t *tevp, ++ int sync) ++{ ++ dm_session_t *s; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ if ((error = dm_find_session_and_lock(targetsid, &s, &lc)) != 0) ++ return(error); ++ ++ return(dm_enqueue(s, lc, &tevp, sync, 0, 1)); ++} ++ ++ ++dm_token_t ++dm_enqueue_user_event( ++ dm_sessid_t sid, ++ dm_tokevent_t *tevp, ++ dm_token_t *tokenp) ++{ ++ dm_session_t *s; ++ int error; ++ unsigned long lc; /* lock cookie */ ++ ++ /* Atomically find and lock the session whose session id is 'sid'. */ ++ ++ if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) ++ return(error); ++ ++ /* Assign a sequence number and token to the event, bump the ++ application reference count by one, and decrement the event ++ count because the caller gives up all ownership of the event. ++ We don't need 'te_lock' here because this thread is still the ++ only thread that can see the event. ++ */ ++ ++ nested_spinlock(&dm_token_lock); ++ tevp->te_msg.ev_sequence = dm_next_sequence++; ++ *tokenp = tevp->te_msg.ev_token = dm_next_token++; ++ nested_spinunlock(&dm_token_lock); ++ ++ tevp->te_flags &= ~(DM_TEF_INTERMED|DM_TEF_FINAL); ++ tevp->te_app_ref++; ++ tevp->te_evt_ref--; ++ ++ /* Add the request to the tail of the sn_delq. Now it's visible. */ ++ ++ dm_link_event(tevp, &s->sn_delq); ++ mutex_spinunlock(&s->sn_qlock, lc); ++ ++ return(0); ++} ++ ++#ifdef HAVE_DM_QUEUE_FLUSH ++/* If inode is non-null, find any tdp referencing that inode and flush the ++ * thread waiting on that inode and set DM_TEF_FLUSH for that tokevent. ++ * Otherwise, if inode is null, find any tdp referencing the specified fsid ++ * and flush that thread and set DM_TEF_FLUSH for that tokevent. ++ */ ++static int ++dm_flush_events( ++ dm_session_t *s, ++ dm_fsid_t *fsidp, ++ struct inode *inode, /* may be null */ ++ dm_eventq_t *queue, ++ int is_writerq, ++ int errno) ++{ ++ dm_tokevent_t *tevp, *next_tevp; ++ dm_tokdata_t *tdp; ++ int found_events = 0; ++ ++ ASSERT(fsidp); ++ for (tevp = queue->eq_head; tevp; tevp = next_tevp) { ++ nested_spinlock(&tevp->te_lock); ++ next_tevp = tevp->te_next; ++ ++ for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { ++ if( inode ) { ++ if( tdp->td_ip == inode ) { ++ break; ++ } ++ } ++ else if(memcmp(fsidp, &tdp->td_handle.ha_fsid, sizeof(*fsidp)) == 0) { ++ break; ++ } ++ } ++ ++ if (tdp != NULL) { ++ /* found a handle reference in this event */ ++ ++found_events; ++ tevp->te_flags |= DM_TEF_FLUSH; ++ ++ /* Set the reply value, unless dm_get_events is ++ already on this one. ++ */ ++ if (! (tevp->te_flags & DM_TEF_LOCKED)) ++ tevp->te_reply = errno; ++ ++ /* If it is on the sn_evt_writerq or is being ++ used by dm_get_events then we're done with it. ++ */ ++ if (is_writerq || (tevp->te_flags & DM_TEF_LOCKED)) { ++ nested_spinunlock(&tevp->te_lock); ++ continue; ++ } ++ ++ /* If there is a thread waiting on a synchronous ++ event then be like dm_respond_event. ++ */ ++ ++ if ((tevp->te_evt_ref) && ++ (tevp->te_msg.ev_token != DM_INVALID_TOKEN)) { ++ ++ tevp->te_flags |= DM_TEF_FINAL; ++ dm_unlink_event(tevp, queue); ++ if (tevp->te_flags & DM_TEF_HASHED) ++ unhash_event(s, tevp); ++ sv_broadcast(&tevp->te_evt_queue); ++ nested_spinunlock(&tevp->te_lock); ++ dm_put_tevp(tevp, NULL); ++ continue; ++ } ++ } ++ nested_spinunlock(&tevp->te_lock); ++ } ++ ++ return(found_events); ++} ++ ++ ++/* If inode is non-null then find any threads that have a reference to that ++ * inode and flush them with the specified errno. ++ * Otherwise,if inode is null, then find any threads that have a reference ++ * to that sb and flush them with the specified errno. ++ * We look for these threads in each session's sn_evt_writerq, sn_newq, ++ * and sn_delq. ++ */ ++int ++dm_release_threads( ++ struct super_block *sb, ++ struct inode *inode, /* may be null */ ++ int errno) ++{ ++ dm_sessid_t sid; ++ dm_session_t *s; ++ unsigned long lc; ++ u_int sesscnt; ++ dm_sessid_t *sidlist; ++ int i; ++ int found_events = 0; ++ dm_fsid_t fsid; ++ struct filesystem_dmapi_operations *dops; ++ ++ ASSERT(sb); ++ dops = dm_fsys_ops(sb); ++ ASSERT(dops); ++ dops->get_fsid(sb, &fsid); ++ dm_release_disp_threads(&fsid, inode, errno); ++ ++ /* Loop until we can get the right amount of temp space, being careful ++ not to hold a mutex during the allocation. Usually only one trip. ++ */ ++ ++ for (;;) { ++ lc = mutex_spinlock(&dm_session_lock); ++ sesscnt = dm_sessions_active; ++ mutex_spinunlock(&dm_session_lock, lc); ++ ++ if (sesscnt == 0) ++ return 0; ++ ++ sidlist = kmalloc(sesscnt * sizeof(sid), GFP_KERNEL); ++ ++ lc = mutex_spinlock(&dm_session_lock); ++ if (sesscnt == dm_sessions_active) ++ break; ++ ++ mutex_spinunlock(&dm_session_lock, lc); ++ kfree(sidlist); ++ } ++ ++ for (i = 0, s = dm_sessions; i < sesscnt; i++, s = s->sn_next) ++ sidlist[i] = s->sn_sessid; ++ ++ mutex_spinunlock(&dm_session_lock, lc); ++ ++ ++ for (i = 0; i < sesscnt; i++) { ++ sid = sidlist[i]; ++ if( dm_find_session_and_lock( sid, &s, &lc ) == 0 ){ ++ found_events = dm_flush_events( s, &fsid, inode, ++ &s->sn_evt_writerq, 1, ++ errno ); ++ if (found_events) ++ sv_broadcast(&s->sn_writerq); ++ ++ dm_flush_events(s, &fsid, inode, &s->sn_newq, 0, errno); ++ dm_flush_events(s, &fsid, inode, &s->sn_delq, 0, errno); ++ ++ mutex_spinunlock( &s->sn_qlock, lc ); ++ } ++ } ++ kfree(sidlist); ++ ++ return 0; ++} ++#endif /* HAVE_DM_QUEUE_FLUSH */ +Index: linux-2.6.26/fs/dmapi/dmapi_sysent.c +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/dmapi_sysent.c +@@ -0,0 +1,805 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++/* Data Migration API (DMAPI) ++ */ ++ ++ ++/* We're using MISC_MAJOR / MISC_DYNAMIC_MINOR. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dmapi.h" ++#include "dmapi_kern.h" ++#include "dmapi_private.h" ++ ++struct kmem_cache *dm_fsreg_cachep = NULL; ++struct kmem_cache *dm_tokdata_cachep = NULL; ++struct kmem_cache *dm_session_cachep = NULL; ++struct kmem_cache *dm_fsys_map_cachep = NULL; ++struct kmem_cache *dm_fsys_vptr_cachep = NULL; ++ ++static int ++dmapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ sys_dmapi_args_t kargs; ++ sys_dmapi_args_t *uap = &kargs; ++ int error = 0; ++ int rvp = -ENOSYS; ++ int use_rvp = 0; ++ ++ if (!capable(CAP_MKNOD)) ++ return -EPERM; ++ ++ if( copy_from_user( &kargs, (sys_dmapi_args_t __user *)arg, ++ sizeof(sys_dmapi_args_t) ) ) ++ return -EFAULT; ++ ++ unlock_kernel(); ++ ++ switch (cmd) { ++ case DM_CLEAR_INHERIT: ++ error = dm_clear_inherit( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_attrname_t __user *) DM_Parg(uap,5));/* attrnamep */ ++ break; ++ case DM_CREATE_BY_HANDLE: ++ error = dm_create_by_handle( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* dirhanp */ ++ (size_t) DM_Uarg(uap,3), /* dirhlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (void __user *) DM_Parg(uap,5), /* hanp */ ++ (size_t) DM_Uarg(uap,6), /* hlen */ ++ (char __user *) DM_Parg(uap,7));/* cname */ ++ break; ++ case DM_CREATE_SESSION: ++ error = dm_create_session( ++ (dm_sessid_t) DM_Uarg(uap,1), /* oldsid */ ++ (char __user *) DM_Parg(uap,2), /* sessinfop */ ++ (dm_sessid_t __user *) DM_Parg(uap,3));/* newsidp */ ++ break; ++ case DM_CREATE_USEREVENT: ++ error = dm_create_userevent( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (size_t) DM_Uarg(uap,2), /* msglen */ ++ (void __user *) DM_Parg(uap,3), /* msgdatap */ ++ (dm_token_t __user *) DM_Parg(uap,4));/* tokenp */ ++ break; ++ case DM_DESTROY_SESSION: ++ error = dm_destroy_session( ++ (dm_sessid_t) DM_Uarg(uap,1));/* sid */ ++ break; ++ case DM_DOWNGRADE_RIGHT: ++ error = dm_downgrade_right( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4));/* token */ ++ break; ++ case DM_FD_TO_HANDLE: ++ error = dm_fd_to_hdl( ++ (int) DM_Uarg(uap,1), /* fd */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t __user *) DM_Parg(uap,3));/* hlenp */ ++ break; ++ case DM_FIND_EVENTMSG: ++ error = dm_find_eventmsg( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (size_t) DM_Uarg(uap,3), /* buflen */ ++ (void __user *) DM_Parg(uap,4), /* bufp */ ++ (size_t __user *) DM_Parg(uap,5));/* rlenp */ ++ break; ++ case DM_GET_ALLOCINFO: ++ use_rvp = 1; ++ error = dm_get_allocinfo_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_off_t __user *) DM_Parg(uap,5), /* offp */ ++ (u_int) DM_Uarg(uap,6), /* nelem */ ++ (dm_extent_t __user *) DM_Parg(uap,7), /* extentp */ ++ (u_int __user *) DM_Parg(uap,8), /* nelemp */ ++ &rvp); ++ break; ++ case DM_GET_BULKALL: ++ use_rvp = 1; ++ error = dm_get_bulkall_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* mask */ ++ (dm_attrname_t __user *) DM_Parg(uap,6),/* attrnamep */ ++ (dm_attrloc_t __user *) DM_Parg(uap,7),/* locp */ ++ (size_t) DM_Uarg(uap,8), /* buflen */ ++ (void __user *) DM_Parg(uap,9), /* bufp */ ++ (size_t __user *) DM_Parg(uap,10),/* rlenp */ ++ &rvp); ++ break; ++ case DM_GET_BULKATTR: ++ use_rvp = 1; ++ error = dm_get_bulkattr_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* mask */ ++ (dm_attrloc_t __user *)DM_Parg(uap,6), /* locp */ ++ (size_t) DM_Uarg(uap,7), /* buflen */ ++ (void __user *) DM_Parg(uap,8), /* bufp */ ++ (size_t __user *) DM_Parg(uap,9), /* rlenp */ ++ &rvp); ++ break; ++ case DM_GET_CONFIG: ++ error = dm_get_config( ++ (void __user *) DM_Parg(uap,1), /* hanp */ ++ (size_t) DM_Uarg(uap,2), /* hlen */ ++ (dm_config_t) DM_Uarg(uap,3), /* flagname */ ++ (dm_size_t __user *)DM_Parg(uap,4));/* retvalp */ ++ break; ++ case DM_GET_CONFIG_EVENTS: ++ error = dm_get_config_events( ++ (void __user *) DM_Parg(uap,1), /* hanp */ ++ (size_t) DM_Uarg(uap,2), /* hlen */ ++ (u_int) DM_Uarg(uap,3), /* nelem */ ++ (dm_eventset_t __user *) DM_Parg(uap,4),/* eventsetp */ ++ (u_int __user *) DM_Parg(uap,5));/* nelemp */ ++ break; ++ case DM_GET_DIOINFO: ++ error = dm_get_dioinfo( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_dioinfo_t __user *)DM_Parg(uap,5));/* diop */ ++ break; ++ case DM_GET_DIRATTRS: ++ use_rvp = 1; ++ error = dm_get_dirattrs_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* mask */ ++ (dm_attrloc_t __user *)DM_Parg(uap,6), /* locp */ ++ (size_t) DM_Uarg(uap,7), /* buflen */ ++ (void __user *) DM_Parg(uap,8), /* bufp */ ++ (size_t __user *) DM_Parg(uap,9), /* rlenp */ ++ &rvp); ++ break; ++ case DM_GET_DMATTR: ++ error = dm_get_dmattr( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_attrname_t __user *) DM_Parg(uap,5),/* attrnamep */ ++ (size_t) DM_Uarg(uap,6), /* buflen */ ++ (void __user *) DM_Parg(uap,7), /* bufp */ ++ (size_t __user *) DM_Parg(uap,8));/* rlenp */ ++ ++ break; ++ case DM_GET_EVENTLIST: ++ error = dm_get_eventlist( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* nelem */ ++ (dm_eventset_t __user *) DM_Parg(uap,6),/* eventsetp */ ++ (u_int __user *) DM_Parg(uap,7));/* nelemp */ ++ break; ++ case DM_GET_EVENTS: ++ error = dm_get_events( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (u_int) DM_Uarg(uap,2), /* maxmsgs */ ++ (u_int) DM_Uarg(uap,3), /* flags */ ++ (size_t) DM_Uarg(uap,4), /* buflen */ ++ (void __user *) DM_Parg(uap,5), /* bufp */ ++ (size_t __user *) DM_Parg(uap,6));/* rlenp */ ++ break; ++ case DM_GET_FILEATTR: ++ error = dm_get_fileattr( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* mask */ ++ (dm_stat_t __user *) DM_Parg(uap,6));/* statp */ ++ break; ++ case DM_GET_MOUNTINFO: ++ error = dm_get_mountinfo( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (size_t) DM_Uarg(uap,5), /* buflen */ ++ (void __user *) DM_Parg(uap,6), /* bufp */ ++ (size_t __user *) DM_Parg(uap,7));/* rlenp */ ++ break; ++ case DM_GET_REGION: ++ error = dm_get_region( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* nelem */ ++ (dm_region_t __user *) DM_Parg(uap,6), /* regbufp */ ++ (u_int __user *) DM_Parg(uap,7));/* nelemp */ ++ break; ++ case DM_GETALL_DISP: ++ error = dm_getall_disp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (size_t) DM_Uarg(uap,2), /* buflen */ ++ (void __user *) DM_Parg(uap,3), /* bufp */ ++ (size_t __user *) DM_Parg(uap,4));/* rlenp */ ++ break; ++ case DM_GETALL_DMATTR: ++ error = dm_getall_dmattr( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (size_t) DM_Uarg(uap,5), /* buflen */ ++ (void __user *) DM_Parg(uap,6), /* bufp */ ++ (size_t __user *) DM_Parg(uap,7));/* rlenp */ ++ break; ++ case DM_GETALL_INHERIT: ++ error = dm_getall_inherit( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* nelem */ ++ (dm_inherit_t __user *)DM_Parg(uap,6), /* inheritbufp*/ ++ (u_int __user *) DM_Parg(uap,7));/* nelemp */ ++ break; ++ case DM_GETALL_SESSIONS: ++ error = dm_getall_sessions( ++ (u_int) DM_Uarg(uap,1), /* nelem */ ++ (dm_sessid_t __user *) DM_Parg(uap,2), /* sidbufp */ ++ (u_int __user *) DM_Parg(uap,3));/* nelemp */ ++ break; ++ case DM_GETALL_TOKENS: ++ error = dm_getall_tokens( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (u_int) DM_Uarg(uap,2), /* nelem */ ++ (dm_token_t __user *) DM_Parg(uap,3), /* tokenbufp */ ++ (u_int __user *) DM_Parg(uap,4));/* nelemp */ ++ break; ++ case DM_INIT_ATTRLOC: ++ error = dm_init_attrloc( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_attrloc_t __user *) DM_Parg(uap,5));/* locp */ ++ break; ++ case DM_MKDIR_BY_HANDLE: ++ error = dm_mkdir_by_handle( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* dirhanp */ ++ (size_t) DM_Uarg(uap,3), /* dirhlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (void __user *) DM_Parg(uap,5), /* hanp */ ++ (size_t) DM_Uarg(uap,6), /* hlen */ ++ (char __user *) DM_Parg(uap,7));/* cname */ ++ break; ++ case DM_MOVE_EVENT: ++ error = dm_move_event( ++ (dm_sessid_t) DM_Uarg(uap,1), /* srcsid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (dm_sessid_t) DM_Uarg(uap,3), /* targetsid */ ++ (dm_token_t __user *) DM_Parg(uap,4));/* rtokenp */ ++ break; ++ case DM_OBJ_REF_HOLD: ++ error = dm_obj_ref_hold( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (void __user *) DM_Parg(uap,3), /* hanp */ ++ (size_t) DM_Uarg(uap,4));/* hlen */ ++ break; ++ case DM_OBJ_REF_QUERY: ++ use_rvp = 1; ++ error = dm_obj_ref_query_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (void __user *) DM_Parg(uap,3), /* hanp */ ++ (size_t) DM_Uarg(uap,4), /* hlen */ ++ &rvp); ++ break; ++ case DM_OBJ_REF_RELE: ++ error = dm_obj_ref_rele( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (void __user *) DM_Parg(uap,3), /* hanp */ ++ (size_t) DM_Uarg(uap,4));/* hlen */ ++ break; ++ case DM_PATH_TO_FSHANDLE: ++ error = dm_path_to_fshdl( ++ (char __user *) DM_Parg(uap,1), /* path */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t __user *) DM_Parg(uap,3));/* hlenp */ ++ break; ++ case DM_PATH_TO_HANDLE: ++ error = dm_path_to_hdl( ++ (char __user *) DM_Parg(uap,1), /* path */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t __user *) DM_Parg(uap,3));/* hlenp */ ++ break; ++ case DM_PENDING: ++ error = dm_pending( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (dm_timestruct_t __user *) DM_Parg(uap,3));/* delay */ ++ break; ++ case DM_PROBE_HOLE: ++ error = dm_probe_hole( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_off_t) DM_Uarg(uap,5), /* off */ ++ (dm_size_t) DM_Uarg(uap,6), /* len */ ++ (dm_off_t __user *) DM_Parg(uap,7), /* roffp */ ++ (dm_size_t __user *) DM_Parg(uap,8));/* rlenp */ ++ break; ++ case DM_PUNCH_HOLE: ++ error = dm_punch_hole( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_off_t) DM_Uarg(uap,5), /* off */ ++ (dm_size_t) DM_Uarg(uap,6));/* len */ ++ break; ++ case DM_QUERY_RIGHT: ++ error = dm_query_right( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_right_t __user *) DM_Parg(uap,5));/* rightp */ ++ break; ++ case DM_QUERY_SESSION: ++ error = dm_query_session( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (size_t) DM_Uarg(uap,2), /* buflen */ ++ (void __user *) DM_Parg(uap,3), /* bufp */ ++ (size_t __user *) DM_Parg(uap,4));/* rlenp */ ++ break; ++ case DM_READ_INVIS: ++ use_rvp = 1; ++ error = dm_read_invis_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_off_t) DM_Uarg(uap,5), /* off */ ++ (dm_size_t) DM_Uarg(uap,6), /* len */ ++ (void __user *) DM_Parg(uap,7), /* bufp */ ++ &rvp); ++ break; ++ case DM_RELEASE_RIGHT: ++ error = dm_release_right( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4));/* token */ ++ break; ++ case DM_REMOVE_DMATTR: ++ error = dm_remove_dmattr( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (int) DM_Uarg(uap,5), /* setdtime */ ++ (dm_attrname_t __user *) DM_Parg(uap,6));/* attrnamep */ ++ break; ++ case DM_REQUEST_RIGHT: ++ error = dm_request_right( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* flags */ ++ (dm_right_t) DM_Uarg(uap,6));/* right */ ++ break; ++ case DM_RESPOND_EVENT: ++ error = dm_respond_event( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (dm_token_t) DM_Uarg(uap,2), /* token */ ++ (dm_response_t) DM_Uarg(uap,3), /* response */ ++ (int) DM_Uarg(uap,4), /* reterror */ ++ (size_t) DM_Uarg(uap,5), /* buflen */ ++ (void __user *) DM_Parg(uap,6));/* respbufp */ ++ break; ++ case DM_SEND_MSG: ++ error = dm_send_msg( ++ (dm_sessid_t) DM_Uarg(uap,1), /* targetsid */ ++ (dm_msgtype_t) DM_Uarg(uap,2), /* msgtype */ ++ (size_t) DM_Uarg(uap,3), /* buflen */ ++ (void __user *) DM_Parg(uap,4));/* bufp */ ++ break; ++ case DM_SET_DISP: ++ error = dm_set_disp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_eventset_t __user *) DM_Parg(uap,5),/* eventsetp */ ++ (u_int) DM_Uarg(uap,6));/* maxevent */ ++ break; ++ case DM_SET_DMATTR: ++ error = dm_set_dmattr( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_attrname_t __user *) DM_Parg(uap,5),/* attrnamep */ ++ (int) DM_Uarg(uap,6), /* setdtime */ ++ (size_t) DM_Uarg(uap,7), /* buflen */ ++ (void __user *) DM_Parg(uap,8));/* bufp */ ++ break; ++ case DM_SET_EVENTLIST: ++ error = dm_set_eventlist( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_eventset_t __user *) DM_Parg(uap,5),/* eventsetp */ ++ (u_int) DM_Uarg(uap,6));/* maxevent */ ++ break; ++ case DM_SET_FILEATTR: ++ error = dm_set_fileattr( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* mask */ ++ (dm_fileattr_t __user *)DM_Parg(uap,6));/* attrp */ ++ break; ++ case DM_SET_INHERIT: ++ error = dm_set_inherit( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_attrname_t __user *)DM_Parg(uap,5),/* attrnamep */ ++ (mode_t) DM_Uarg(uap,6));/* mode */ ++ break; ++ case DM_SET_REGION: ++ error = dm_set_region( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (u_int) DM_Uarg(uap,5), /* nelem */ ++ (dm_region_t __user *) DM_Parg(uap,6), /* regbufp */ ++ (dm_boolean_t __user *) DM_Parg(uap,7));/* exactflagp */ ++ break; ++ case DM_SET_RETURN_ON_DESTROY: ++ error = dm_set_return_on_destroy( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (dm_attrname_t __user *) DM_Parg(uap,5),/* attrnamep */ ++ (dm_boolean_t) DM_Uarg(uap,6));/* enable */ ++ break; ++ case DM_SYMLINK_BY_HANDLE: ++ error = dm_symlink_by_handle( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* dirhanp */ ++ (size_t) DM_Uarg(uap,3), /* dirhlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (void __user *) DM_Parg(uap,5), /* hanp */ ++ (size_t) DM_Uarg(uap,6), /* hlen */ ++ (char __user *) DM_Parg(uap,7), /* cname */ ++ (char __user *) DM_Parg(uap,8));/* path */ ++ break; ++ case DM_SYNC_BY_HANDLE: ++ error = dm_sync_by_handle( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4));/* token */ ++ break; ++ case DM_UPGRADE_RIGHT: ++ error = dm_upgrade_right( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4));/* token */ ++ break; ++ case DM_WRITE_INVIS: ++ use_rvp = 1; ++ error = dm_write_invis_rvp( ++ (dm_sessid_t) DM_Uarg(uap,1), /* sid */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (dm_token_t) DM_Uarg(uap,4), /* token */ ++ (int) DM_Uarg(uap,5), /* flags */ ++ (dm_off_t) DM_Uarg(uap,6), /* off */ ++ (dm_size_t) DM_Uarg(uap,7), /* len */ ++ (void __user *) DM_Parg(uap,8), /* bufp */ ++ &rvp); ++ break; ++ case DM_OPEN_BY_HANDLE: ++ use_rvp = 1; ++ error = dm_open_by_handle_rvp( ++ (unsigned int) DM_Uarg(uap,1), /* fd */ ++ (void __user *) DM_Parg(uap,2), /* hanp */ ++ (size_t) DM_Uarg(uap,3), /* hlen */ ++ (int) DM_Uarg(uap,4), /* flags */ ++ &rvp); ++ break; ++ default: ++ error = -ENOSYS; ++ break; ++ } ++ ++ lock_kernel(); ++ ++ /* If it was an *_rvp() function, then ++ if error==0, return |rvp| ++ */ ++ if( use_rvp && (error == 0) ) ++ return rvp; ++ else ++ return error; ++} ++ ++ ++ ++static int ++dmapi_open(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++ ++static int ++dmapi_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++ ++/* say hello, and let me know the device is hooked up */ ++static ssize_t ++dmapi_dump(struct file *file, char __user *buf, size_t count, loff_t *ppos) ++{ ++ char tmp[50]; ++ int len; ++ if( *ppos == 0 ){ ++ len = sprintf( tmp, "# " DM_VER_STR_CONTENTS "\n" ); ++ if( copy_to_user(buf, tmp, len) ) ++ return -EFAULT; ++ *ppos += 1; ++ return len; ++ } ++ return 0; ++} ++ ++static struct file_operations dmapi_fops = { ++ .open = dmapi_open, ++ .ioctl = dmapi_ioctl, ++ .read = dmapi_dump, ++ .release = dmapi_release ++}; ++ ++static struct miscdevice dmapi_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "dmapi", ++ .fops = &dmapi_fops ++}; ++ ++ ++ ++#ifdef CONFIG_PROC_FS ++static int ++dmapi_summary(char *buffer, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ extern u_int dm_sessions_active; ++ extern dm_sessid_t dm_next_sessid; ++ extern dm_token_t dm_next_token; ++ extern dm_sequence_t dm_next_sequence; ++ extern int dm_fsys_cnt; ++ ++#define CHKFULL if(len >= count) break; ++#define ADDBUF(a,b) len += sprintf(buffer + len, a, b); CHKFULL; ++ ++ len=0; ++ while(1){ ++ ADDBUF("dm_sessions_active=%u\n", dm_sessions_active); ++ ADDBUF("dm_next_sessid=%d\n", (int)dm_next_sessid); ++ ADDBUF("dm_next_token=%d\n", (int)dm_next_token); ++ ADDBUF("dm_next_sequence=%u\n", (u_int)dm_next_sequence); ++ ADDBUF("dm_fsys_cnt=%d\n", dm_fsys_cnt); ++ ++ break; ++ } ++ ++ if (offset >= len) { ++ *start = buffer; ++ *eof = 1; ++ return 0; ++ } ++ *start = buffer + offset; ++ if ((len -= offset) > count) ++ return count; ++ *eof = 1; ++ ++ return len; ++} ++#endif ++ ++ ++static void __init ++dmapi_init_procfs(int dmapi_minor) ++{ ++#ifdef CONFIG_PROC_FS ++ struct proc_dir_entry *entry; ++ ++ if ((entry = proc_mkdir( DMAPI_DBG_PROCFS, NULL)) == NULL ) ++ return; ++ entry->owner = THIS_MODULE; ++ entry->mode = S_IFDIR | S_IRUSR | S_IXUSR; ++ ++ if ((entry = proc_mkdir( DMAPI_DBG_PROCFS "/fsreg", NULL)) == NULL ) ++ return; ++ entry->owner = THIS_MODULE; ++ ++ if ((entry = proc_mkdir( DMAPI_DBG_PROCFS "/sessions", NULL)) == NULL ) ++ return; ++ entry->owner = THIS_MODULE; ++ ++ entry = create_proc_read_entry( DMAPI_DBG_PROCFS "/summary", ++ 0, NULL, dmapi_summary, NULL); ++ entry->owner = THIS_MODULE; ++#endif ++} ++ ++#if 0 ++static void __exit ++dmapi_cleanup_procfs(void) ++{ ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry( DMAPI_DBG_PROCFS "/summary", NULL); ++ remove_proc_entry( DMAPI_DBG_PROCFS "/fsreg", NULL); ++ remove_proc_entry( DMAPI_DBG_PROCFS "/sessions", NULL); ++ remove_proc_entry( DMAPI_DBG_PROCFS, NULL); ++#endif ++} ++#endif ++ ++int __init dmapi_init(void) ++{ ++ int ret; ++ ++ dm_tokdata_cachep = kmem_cache_create("dm_tokdata", ++ sizeof(struct dm_tokdata), 0, 0, NULL); ++ if (dm_tokdata_cachep == NULL) ++ goto out; ++ ++ dm_fsreg_cachep = kmem_cache_create("dm_fsreg", ++ sizeof(struct dm_fsreg), 0, 0, NULL); ++ if (dm_fsreg_cachep == NULL) ++ goto out_free_tokdata_cachep; ++ ++ dm_session_cachep = kmem_cache_create("dm_session", ++ sizeof(struct dm_session), 0, 0, NULL); ++ if (dm_session_cachep == NULL) ++ goto out_free_fsreg_cachep; ++ ++ dm_fsys_map_cachep = kmem_cache_create("dm_fsys_map", ++ sizeof(dm_vector_map_t), 0, 0, NULL); ++ if (dm_fsys_map_cachep == NULL) ++ goto out_free_session_cachep; ++ dm_fsys_vptr_cachep = kmem_cache_create("dm_fsys_vptr", ++ sizeof(dm_fsys_vector_t), 0, 0, NULL); ++ if (dm_fsys_vptr_cachep == NULL) ++ goto out_free_fsys_map_cachep; ++ ++ ret = misc_register(&dmapi_dev); ++ if (ret) { ++ printk(KERN_ERR "dmapi_init: misc_register returned %d\n", ret); ++ goto out_free_fsys_vptr_cachep; ++ } ++ ++ dmapi_init_procfs(dmapi_dev.minor); ++ return 0; ++ ++ out_free_fsys_vptr_cachep: ++ kmem_cache_destroy(dm_fsys_vptr_cachep); ++ out_free_fsys_map_cachep: ++ kmem_cache_destroy(dm_fsys_map_cachep); ++ out_free_session_cachep: ++ kmem_cache_destroy(dm_session_cachep); ++ out_free_fsreg_cachep: ++ kmem_cache_destroy(dm_fsreg_cachep); ++ out_free_tokdata_cachep: ++ kmem_cache_destroy(dm_tokdata_cachep); ++ out: ++ return -ENOMEM; ++} ++ ++#if 0 ++void __exit dmapi_uninit(void) ++{ ++ misc_deregister(&dmapi_dev); ++ dmapi_cleanup_procfs(); ++ kmem_cache_destroy(dm_tokdata_cachep); ++ kmem_cache_destroy(dm_fsreg_cachep); ++ kmem_cache_destroy(dm_session_cachep); ++ kmem_cache_destroy(dm_fsys_map_cachep); ++ kmem_cache_destroy(dm_fsys_vptr_cachep); ++} ++#endif ++ ++module_init(dmapi_init); ++/*module_exit(dmapi_uninit);*/ /* Some other day */ ++ ++MODULE_AUTHOR("Silicon Graphics, Inc."); ++MODULE_DESCRIPTION("SGI Data Migration Subsystem"); ++MODULE_LICENSE("GPL"); ++ ++EXPORT_SYMBOL(dm_send_mount_event); ++EXPORT_SYMBOL(dm_send_namesp_event); ++EXPORT_SYMBOL(dm_send_unmount_event); ++EXPORT_SYMBOL(dm_send_data_event); ++EXPORT_SYMBOL(dm_send_destroy_event); ++EXPORT_SYMBOL(dm_ip_to_handle); ++EXPORT_SYMBOL(dmapi_register); ++EXPORT_SYMBOL(dmapi_unregister); ++EXPORT_SYMBOL(dmapi_registered); ++EXPORT_SYMBOL(dm_release_threads); +Index: linux-2.6.26/fs/dmapi/Makefile +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/Makefile +@@ -0,0 +1,53 @@ ++# ++# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License along ++# with this program; if not, write the Free Software Foundation, Inc., 59 ++# Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++# Mountain View, CA 94043, or: ++# ++# http://www.sgi.com ++# ++# For further information regarding this notice, see: ++# ++# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++# ++ ++ifeq ($(CONFIG_DMAPI_DEBUG),y) ++ EXTRA_CFLAGS += -DDEBUG ++ EXTRA_CFLAGS += -g ++endif ++ ++obj-$(CONFIG_DMAPI) += dmapi.o ++ ++dmapi-y += dmapi_sysent.o \ ++ dmapi_attr.o \ ++ dmapi_config.o \ ++ dmapi_bulkattr.o \ ++ dmapi_dmattr.o \ ++ dmapi_event.o \ ++ dmapi_handle.o \ ++ dmapi_hole.o \ ++ dmapi_io.o \ ++ dmapi_mountinfo.o \ ++ dmapi_region.o \ ++ dmapi_register.o \ ++ dmapi_right.o \ ++ dmapi_session.o +Index: linux-2.6.26/fs/dmapi/Status +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/Status +@@ -0,0 +1,128 @@ ++Jan21,04 - dm_get_bulkall is now implemented. roehrich ++ ++for linux: ++ ++ ++68 external interfaces in libdm ++ ++ 56 of those interfaces go through to dmi(), the kernel side of DMAPI ++ ++ ++ ++Functions known to work ++---------------------------------------------- ++ ++dm_create_session ++dm_create_userevent ++dm_destroy_session ++dm_getall_sessions ++dm_getall_tokens ++dm_get_allocinfo ++dm_get_bulkall ++dm_get_bulkattr ++dm_get_config_events ++dm_get_dmattr ++dm_get_eventlist ++dm_get_events ++dm_get_fileattr ++dm_get_region ++dm_handle_free ++dm_init_attrloc ++dm_init_service ++dm_obj_ref_hold ++dm_obj_ref_query ++dm_obj_ref_rele ++dm_path_to_fshandle ++dm_path_to_handle ++dm_punch_hole ++dm_query_session ++dm_read_invis ++dm_remove_dmattr ++dm_respond_event ++dm_send_msg ++dm_set_disp ++dm_set_dmattr ++dm_set_eventlist ++dm_set_fileattr ++dm_set_region ++dm_sync_by_handle ++dm_write_invis ++35 ++ ++Functions that seem to work (would like more rigorous test case) ++------------------------------------------ ++ ++dm_pending ++dm_probe_hole - one test case of test_hole.c fails ++dm_request_right ++3 ++ ++Functions untested but probably work ++---------------------------------------------- ++ ++dm_find_eventmsg ++dm_handle_cmp ++dm_handle_to_fshandle ++dm_handle_to_ino ++dm_release_right ++5 ++ ++Functions that do not work ++----------------------------------------- ++ ++dm_get_dioinfo - directio not implemented ++1 ++ ++Functions not supported in SGI DMAPI ++------------------------------------------------------------- ++ ++dm_clear_inherit ++dm_create_by_handle ++dm_getall_inherit ++dm_mkdir_by_handle ++dm_set_inherit ++dm_symlink_by_handle ++ ++ ++ ++ ++Functions that seem to work (would like more rigorous test case) ++---------------------------------------------------------------- ++ ++dm_get_config ++dm_downgrade_right ++dm_get_mountinfo ++dm_set_return_on_destory ++dm_upgrade_right ++ ++ ++ ++Functions that do not work ++----------------------------------------------------------------- ++ ++dm_fd_to_handle - Irix getf not implemented on linux ++dm_get_dirattrs - null pointer reference ++dm_handle_to_path ++dm_getall_dmattr - needs a copy_from_user in place of useracc ++ ++ ++Functions that are untested, but probably work ++----------------------------------------------------------------- ++ ++dm_getall_disp ++dm_handle_hash ++dm_handle_is_valid ++dm_handle_to_fsid ++dm_handle_to_igen ++dm_make_fshandle ++dm_make_handle ++dm_move_event ++dm_query_right ++ ++ ++ ++Other things not working ++---------------------------------- ++ ++- read/write events for memory-mapped I/O? ++ +Index: linux-2.6.26/fs/dmapi/sv.h +=================================================================== +--- /dev/null ++++ linux-2.6.26/fs/dmapi/sv.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., 59 ++ * Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++#ifndef __DMAPI_SV_H__ ++#define __DMAPI_SV_H__ ++ ++#include ++#include ++#include ++ ++/* ++ * Synchronisation variables. ++ * ++ * (Parameters "pri", "svf" and "rts" are not implemented) ++ */ ++ ++typedef struct sv_s { ++ wait_queue_head_t waiters; ++} sv_t; ++ ++#define SV_FIFO 0x0 /* sv_t is FIFO type */ ++#define SV_LIFO 0x2 /* sv_t is LIFO type */ ++#define SV_PRIO 0x4 /* sv_t is PRIO type */ ++#define SV_KEYED 0x6 /* sv_t is KEYED type */ ++#define SV_DEFAULT SV_FIFO ++ ++ ++static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state, ++ unsigned long timeout) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ add_wait_queue_exclusive(&sv->waiters, &wait); ++ __set_current_state(state); ++ spin_unlock(lock); ++ ++ schedule_timeout(timeout); ++ ++ remove_wait_queue(&sv->waiters, &wait); ++} ++ ++#define init_sv(sv,type,name,flag) \ ++ init_waitqueue_head(&(sv)->waiters) ++#define sv_init(sv,flag,name) \ ++ init_waitqueue_head(&(sv)->waiters) ++#define sv_destroy(sv) \ ++ /*NOTHING*/ ++#define sv_wait(sv, pri, lock, s) \ ++ _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT) ++#define sv_wait_sig(sv, pri, lock, s) \ ++ _sv_wait(sv, lock, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT) ++#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \ ++ _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, timespec_to_jiffies(ts)) ++#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \ ++ _sv_wait(sv, lock, TASK_INTERRUPTIBLE, timespec_to_jiffies(ts)) ++#define sv_signal(sv) \ ++ wake_up(&(sv)->waiters) ++#define sv_broadcast(sv) \ ++ wake_up_all(&(sv)->waiters) ++ ++#endif /* __DMAPI_SV_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-xfs-enable b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-xfs-enable new file mode 100644 index 000000000..10e266bbc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-dmapi-xfs-enable @@ -0,0 +1,3789 @@ +Date: Thu, 09 Oct 2008 17:11:53 +1100 +From: Donald Douwsma +Subject: DMAPI support for xfs +Patch-mainline: ? +References: bnc#450658 + +Acked-by: Jan Kara + +--- + fs/xfs/Kconfig | 13 + fs/xfs/Makefile | 5 + fs/xfs/dmapi/Makefile | 28 + fs/xfs/dmapi/xfs_dm.c | 3337 +++++++++++++++++++++++++++++++++++++++++++ + fs/xfs/dmapi/xfs_dm.h | 23 + fs/xfs/linux-2.6/xfs_file.c | 76 + fs/xfs/linux-2.6/xfs_ksyms.c | 99 + + fs/xfs/linux-2.6/xfs_linux.h | 4 + fs/xfs/linux-2.6/xfs_super.c | 13 + fs/xfs/xfs_dmops.c | 20 + fs/xfs/xfs_mount.h | 1 + 11 files changed, 3613 insertions(+), 6 deletions(-) + +Index: linux-2.6.27/fs/xfs/dmapi/Makefile +=================================================================== +--- /dev/null ++++ linux-2.6.27/fs/xfs/dmapi/Makefile +@@ -0,0 +1,28 @@ ++# ++# Copyright (c) 2006 Silicon Graphics, Inc. ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++# ++ ++EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../linux-2.6 ++EXTRA_CFLAGS += -I$(TOPDIR)/fs/dmapi ++ ++ifeq ($(CONFIG_XFS_DEBUG),y) ++ EXTRA_CFLAGS += -g -DDEBUG ++endif ++ ++obj-$(CONFIG_XFS_DMAPI) += xfs_dmapi.o ++ ++xfs_dmapi-y += xfs_dm.o +Index: linux-2.6.27/fs/xfs/dmapi/xfs_dm.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/fs/xfs/dmapi/xfs_dm.c +@@ -0,0 +1,3337 @@ ++/* ++ * Copyright (c) 2000-2006 Silicon Graphics, Inc. ++ * All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include "xfs.h" ++#include "xfs_fs.h" ++#include "xfs_types.h" ++#include "xfs_bit.h" ++#include "xfs_log.h" ++#include "xfs_inum.h" ++#include "xfs_clnt.h" ++#include "xfs_trans.h" ++#include "xfs_sb.h" ++#include "xfs_ag.h" ++#include "xfs_dir2.h" ++#include "xfs_alloc.h" ++#include "xfs_dmapi.h" ++#include "xfs_mount.h" ++#include "xfs_da_btree.h" ++#include "xfs_bmap_btree.h" ++#include "xfs_alloc_btree.h" ++#include "xfs_ialloc_btree.h" ++#include "xfs_dir2_sf.h" ++#include "xfs_attr_sf.h" ++#include "xfs_dinode.h" ++#include "xfs_inode.h" ++#include "xfs_btree.h" ++#include "xfs_ialloc.h" ++#include "xfs_itable.h" ++#include "xfs_bmap.h" ++#include "xfs_rw.h" ++#include "xfs_acl.h" ++#include "xfs_attr.h" ++#include "xfs_attr_leaf.h" ++#include "xfs_inode_item.h" ++#include "xfs_vfsops.h" ++#include "xfs_vnodeops.h" ++#include ++#include ++#include "xfs_dm.h" ++ ++#include ++ ++#define MAXNAMLEN MAXNAMELEN ++ ++#define MIN_DIO_SIZE(mp) ((mp)->m_sb.sb_sectsize) ++#define MAX_DIO_SIZE(mp) (INT_MAX & ~(MIN_DIO_SIZE(mp) - 1)) ++ ++static void up_rw_sems(struct inode *ip, int flags) ++{ ++ if (flags & DM_FLAGS_IALLOCSEM_WR) ++ up_write(&ip->i_alloc_sem); ++ if (flags & DM_FLAGS_IMUX) ++ mutex_unlock(&ip->i_mutex); ++} ++ ++static void down_rw_sems(struct inode *ip, int flags) ++{ ++ if (flags & DM_FLAGS_IMUX) ++ mutex_lock(&ip->i_mutex); ++ if (flags & DM_FLAGS_IALLOCSEM_WR) ++ down_write(&ip->i_alloc_sem); ++} ++ ++ ++/* Structure used to hold the on-disk version of a dm_attrname_t. All ++ on-disk attribute names start with the 8-byte string "SGI_DMI_". ++*/ ++ ++typedef struct { ++ char dan_chars[DMATTR_PREFIXLEN + DM_ATTR_NAME_SIZE + 1]; ++} dm_dkattrname_t; ++ ++/* Structure used by xfs_dm_get_bulkall(), used as the "private_data" ++ * that we want xfs_bulkstat to send to our formatter. ++ */ ++typedef struct { ++ dm_fsid_t fsid; ++ void __user *laststruct; ++ dm_dkattrname_t attrname; ++} dm_bulkstat_one_t; ++ ++/* In the on-disk inode, DMAPI attribute names consist of the user-provided ++ name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be ++ changed! ++*/ ++ ++static const char dmattr_prefix[DMATTR_PREFIXLEN + 1] = DMATTR_PREFIXSTRING; ++ ++static dm_size_t dm_min_dio_xfer = 0; /* direct I/O disabled for now */ ++ ++ ++/* See xfs_dm_get_dmattr() for a description of why this is needed. */ ++ ++#define XFS_BUG_KLUDGE 256 /* max size of an in-inode attribute value */ ++ ++#define DM_MAX_ATTR_BYTES_ON_DESTROY 256 ++ ++#define DM_STAT_SIZE(dmtype,namelen) \ ++ (sizeof(dmtype) + sizeof(dm_handle_t) + namelen) ++ ++#define DM_STAT_ALIGN (sizeof(__uint64_t)) ++ ++/* DMAPI's E2BIG == EA's ERANGE */ ++#define DM_EA_XLATE_ERR(err) { if (err == ERANGE) err = E2BIG; } ++ ++static inline size_t dm_stat_align(size_t size) ++{ ++ return (size + (DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++} ++ ++static inline size_t dm_stat_size(size_t namelen) ++{ ++ return dm_stat_align(sizeof(dm_stat_t) + sizeof(dm_handle_t) + namelen); ++} ++ ++/* ++ * xfs_dm_send_data_event() ++ * ++ * Send data event to DMAPI. Drop IO lock (if specified) before ++ * the dm_send_data_event() call and reacquire it afterwards. ++ */ ++int ++xfs_dm_send_data_event( ++ dm_eventtype_t event, ++ xfs_inode_t *ip, ++ xfs_off_t offset, ++ size_t length, ++ int flags, ++ int *lock_flags) ++{ ++ struct inode *inode = ip->i_vnode; ++ int error; ++ uint16_t dmstate; ++ ++ /* Returns positive errors to XFS */ ++ ++ do { ++ dmstate = ip->i_d.di_dmstate; ++ if (lock_flags) ++ xfs_iunlock(ip, *lock_flags); ++ ++ up_rw_sems(inode, flags); ++ ++ error = dm_send_data_event(event, inode, DM_RIGHT_NULL, ++ offset, length, flags); ++ error = -error; /* DMAPI returns negative errors */ ++ ++ down_rw_sems(inode, flags); ++ ++ if (lock_flags) ++ xfs_ilock(ip, *lock_flags); ++ } while (!error && (ip->i_d.di_dmstate != dmstate)); ++ ++ return error; ++} ++ ++/* prohibited_mr_events ++ * ++ * Return event bits representing any events which cannot have managed ++ * region events set due to memory mapping of the file. If the maximum ++ * protection allowed in any pregion includes PROT_WRITE, and the region ++ * is shared and not text, then neither READ nor WRITE events can be set. ++ * Otherwise if the file is memory mapped, no READ event can be set. ++ * ++ */ ++STATIC int ++prohibited_mr_events( ++ struct address_space *mapping) ++{ ++ int prohibited = (1 << DM_EVENT_READ); ++ ++ if (!mapping_mapped(mapping)) ++ return 0; ++ ++ spin_lock(&mapping->i_mmap_lock); ++ if (mapping_writably_mapped(mapping)) ++ prohibited |= (1 << DM_EVENT_WRITE); ++ spin_unlock(&mapping->i_mmap_lock); ++ ++ return prohibited; ++} ++ ++#ifdef DEBUG_RIGHTS ++STATIC int ++xfs_vp_to_hexhandle( ++ struct inode *inode, ++ u_int type, ++ char *buffer) ++{ ++ dm_handle_t handle; ++ u_char *ip; ++ int length; ++ int error; ++ int i; ++ ++ /* ++ * XXX: dm_vp_to_handle doesn't exist. ++ * Looks like this debug code is rather dead. ++ */ ++ if ((error = dm_vp_to_handle(inode, &handle))) ++ return(error); ++ ++ if (type == DM_FSYS_OBJ) { /* a filesystem handle */ ++ length = DM_FSHSIZE; ++ } else { ++ length = DM_HSIZE(handle); ++ } ++ for (ip = (u_char *)&handle, i = 0; i < length; i++) { ++ *buffer++ = "0123456789abcdef"[ip[i] >> 4]; ++ *buffer++ = "0123456789abcdef"[ip[i] & 0xf]; ++ } ++ *buffer = '\0'; ++ return(0); ++} ++#endif /* DEBUG_RIGHTS */ ++ ++ ++ ++ ++/* Copy in and validate an attribute name from user space. It should be a ++ string of at least one and at most DM_ATTR_NAME_SIZE characters. Because ++ the dm_attrname_t structure doesn't provide room for the trailing NULL ++ byte, we just copy in one extra character and then zero it if it ++ happens to be non-NULL. ++*/ ++ ++STATIC int ++xfs_copyin_attrname( ++ dm_attrname_t __user *from, /* dm_attrname_t in user space */ ++ dm_dkattrname_t *to) /* name buffer in kernel space */ ++{ ++ int error = 0; ++ size_t len; ++ ++ strcpy(to->dan_chars, dmattr_prefix); ++ ++ len = strnlen_user((char __user *)from, DM_ATTR_NAME_SIZE); ++ if (len == 0) ++ error = EFAULT; ++ else { ++ if (copy_from_user(&to->dan_chars[DMATTR_PREFIXLEN], from, len)) ++ to->dan_chars[sizeof(to->dan_chars) - 1] = '\0'; ++ else if (to->dan_chars[DMATTR_PREFIXLEN] == '\0') ++ error = EINVAL; ++ else ++ to->dan_chars[DMATTR_PREFIXLEN + len - 1] = '\0'; ++ } ++ ++ return error; ++} ++ ++ ++/* ++ * Convert the XFS flags into their DMAPI flag equivalent for export ++ */ ++STATIC uint ++_xfs_dic2dmflags( ++ __uint16_t di_flags) ++{ ++ uint flags = 0; ++ ++ if (di_flags & XFS_DIFLAG_ANY) { ++ if (di_flags & XFS_DIFLAG_REALTIME) ++ flags |= DM_XFLAG_REALTIME; ++ if (di_flags & XFS_DIFLAG_PREALLOC) ++ flags |= DM_XFLAG_PREALLOC; ++ if (di_flags & XFS_DIFLAG_IMMUTABLE) ++ flags |= DM_XFLAG_IMMUTABLE; ++ if (di_flags & XFS_DIFLAG_APPEND) ++ flags |= DM_XFLAG_APPEND; ++ if (di_flags & XFS_DIFLAG_SYNC) ++ flags |= DM_XFLAG_SYNC; ++ if (di_flags & XFS_DIFLAG_NOATIME) ++ flags |= DM_XFLAG_NOATIME; ++ if (di_flags & XFS_DIFLAG_NODUMP) ++ flags |= DM_XFLAG_NODUMP; ++ } ++ return flags; ++} ++ ++STATIC uint ++xfs_ip2dmflags( ++ xfs_inode_t *ip) ++{ ++ return _xfs_dic2dmflags(ip->i_d.di_flags) | ++ (XFS_IFORK_Q(ip) ? DM_XFLAG_HASATTR : 0); ++} ++ ++STATIC uint ++xfs_dic2dmflags( ++ xfs_dinode_t *dip) ++{ ++ return _xfs_dic2dmflags(be16_to_cpu(dip->di_core.di_flags)) | ++ (XFS_DFORK_Q(dip) ? DM_XFLAG_HASATTR : 0); ++} ++ ++/* ++ * This copies selected fields in an inode into a dm_stat structure. Because ++ * these fields must return the same values as they would in stat(), the ++ * majority of this code was copied directly from xfs_getattr(). Any future ++ * changes to xfs_gettattr() must also be reflected here. ++ */ ++STATIC void ++xfs_dip_to_stat( ++ xfs_mount_t *mp, ++ xfs_ino_t ino, ++ xfs_dinode_t *dip, ++ dm_stat_t *buf) ++{ ++ xfs_dinode_core_t *dic = &dip->di_core; ++ ++ /* ++ * The inode format changed when we moved the link count and ++ * made it 32 bits long. If this is an old format inode, ++ * convert it in memory to look like a new one. If it gets ++ * flushed to disk we will convert back before flushing or ++ * logging it. We zero out the new projid field and the old link ++ * count field. We'll handle clearing the pad field (the remains ++ * of the old uuid field) when we actually convert the inode to ++ * the new format. We don't change the version number so that we ++ * can distinguish this from a real new format inode. ++ */ ++ if (dic->di_version == XFS_DINODE_VERSION_1) { ++ buf->dt_nlink = be16_to_cpu(dic->di_onlink); ++ /*buf->dt_xfs_projid = 0;*/ ++ } else { ++ buf->dt_nlink = be32_to_cpu(dic->di_nlink); ++ /*buf->dt_xfs_projid = be16_to_cpu(dic->di_projid);*/ ++ } ++ buf->dt_ino = ino; ++ buf->dt_dev = new_encode_dev(mp->m_ddev_targp->bt_dev); ++ buf->dt_mode = be16_to_cpu(dic->di_mode); ++ buf->dt_uid = be32_to_cpu(dic->di_uid); ++ buf->dt_gid = be32_to_cpu(dic->di_gid); ++ buf->dt_size = be64_to_cpu(dic->di_size); ++ buf->dt_atime = be32_to_cpu(dic->di_atime.t_sec); ++ buf->dt_mtime = be32_to_cpu(dic->di_mtime.t_sec); ++ buf->dt_ctime = be32_to_cpu(dic->di_ctime.t_sec); ++ buf->dt_xfs_xflags = xfs_dic2dmflags(dip); ++ buf->dt_xfs_extsize = ++ be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog; ++ buf->dt_xfs_extents = be32_to_cpu(dic->di_nextents); ++ buf->dt_xfs_aextents = be16_to_cpu(dic->di_anextents); ++ buf->dt_xfs_igen = be32_to_cpu(dic->di_gen); ++ buf->dt_xfs_dmstate = be16_to_cpu(dic->di_dmstate); ++ ++ switch (dic->di_format) { ++ case XFS_DINODE_FMT_DEV: ++ buf->dt_rdev = be32_to_cpu(dip->di_u.di_dev); ++ buf->dt_blksize = BLKDEV_IOSIZE; ++ buf->dt_blocks = 0; ++ break; ++ case XFS_DINODE_FMT_LOCAL: ++ case XFS_DINODE_FMT_UUID: ++ buf->dt_rdev = 0; ++ buf->dt_blksize = mp->m_sb.sb_blocksize; ++ buf->dt_blocks = 0; ++ break; ++ case XFS_DINODE_FMT_EXTENTS: ++ case XFS_DINODE_FMT_BTREE: ++ buf->dt_rdev = 0; ++ buf->dt_blksize = mp->m_sb.sb_blocksize; ++ buf->dt_blocks = ++ XFS_FSB_TO_BB(mp, be64_to_cpu(dic->di_nblocks)); ++ break; ++ } ++ ++ memset(&buf->dt_pad1, 0, sizeof(buf->dt_pad1)); ++ memset(&buf->dt_pad2, 0, sizeof(buf->dt_pad2)); ++ memset(&buf->dt_pad3, 0, sizeof(buf->dt_pad3)); ++ ++ /* Finally fill in the DMAPI specific fields */ ++ buf->dt_pers = 0; ++ buf->dt_change = 0; ++ buf->dt_nevents = DM_EVENT_MAX; ++ buf->dt_emask = be32_to_cpu(dic->di_dmevmask); ++ buf->dt_dtime = be32_to_cpu(dic->di_ctime.t_sec); ++ /* Set if one of READ, WRITE or TRUNCATE bits is set in emask */ ++ buf->dt_pmanreg = (DMEV_ISSET(DM_EVENT_READ, buf->dt_emask) || ++ DMEV_ISSET(DM_EVENT_WRITE, buf->dt_emask) || ++ DMEV_ISSET(DM_EVENT_TRUNCATE, buf->dt_emask)) ? 1 : 0; ++} ++ ++/* ++ * Pull out both ondisk and incore fields, incore has preference. ++ * The inode must be kept locked SHARED by the caller. ++ */ ++STATIC void ++xfs_ip_to_stat( ++ xfs_mount_t *mp, ++ xfs_ino_t ino, ++ xfs_inode_t *ip, ++ dm_stat_t *buf) ++{ ++ xfs_icdinode_t *dic = &ip->i_d; ++ ++ buf->dt_ino = ino; ++ buf->dt_nlink = dic->di_nlink; ++ /*buf->dt_xfs_projid = dic->di_projid;*/ ++ buf->dt_mode = dic->di_mode; ++ buf->dt_uid = dic->di_uid; ++ buf->dt_gid = dic->di_gid; ++ buf->dt_size = XFS_ISIZE(ip); ++ buf->dt_dev = new_encode_dev(mp->m_ddev_targp->bt_dev); ++ vn_atime_to_time_t(VFS_I(ip), &buf->dt_atime); ++ buf->dt_mtime = dic->di_mtime.t_sec; ++ buf->dt_ctime = dic->di_ctime.t_sec; ++ buf->dt_xfs_xflags = xfs_ip2dmflags(ip); ++ buf->dt_xfs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog; ++ buf->dt_xfs_extents = dic->di_nextents; ++ buf->dt_xfs_aextents = dic->di_anextents; ++ buf->dt_xfs_igen = dic->di_gen; ++ buf->dt_xfs_dmstate = dic->di_dmstate; ++ ++ switch (dic->di_format) { ++ case XFS_DINODE_FMT_DEV: ++ buf->dt_rdev = ip->i_df.if_u2.if_rdev; ++ buf->dt_blksize = BLKDEV_IOSIZE; ++ buf->dt_blocks = 0; ++ break; ++ case XFS_DINODE_FMT_LOCAL: ++ case XFS_DINODE_FMT_UUID: ++ buf->dt_rdev = 0; ++ buf->dt_blksize = mp->m_sb.sb_blocksize; ++ buf->dt_blocks = 0; ++ break; ++ case XFS_DINODE_FMT_EXTENTS: ++ case XFS_DINODE_FMT_BTREE: ++ buf->dt_rdev = 0; ++ buf->dt_blksize = mp->m_sb.sb_blocksize; ++ buf->dt_blocks = XFS_FSB_TO_BB(mp, ++ (dic->di_nblocks + ip->i_delayed_blks)); ++ break; ++ } ++ ++ memset(&buf->dt_pad1, 0, sizeof(buf->dt_pad1)); ++ memset(&buf->dt_pad2, 0, sizeof(buf->dt_pad2)); ++ memset(&buf->dt_pad3, 0, sizeof(buf->dt_pad3)); ++ ++ /* Finally fill in the DMAPI specific fields */ ++ buf->dt_pers = 0; ++ buf->dt_change = 0; ++ buf->dt_nevents = DM_EVENT_MAX; ++ buf->dt_emask = dic->di_dmevmask; ++ buf->dt_dtime = dic->di_ctime.t_sec; ++ /* Set if one of READ, WRITE or TRUNCATE bits is set in emask */ ++ buf->dt_pmanreg = (DMEV_ISSET(DM_EVENT_READ, buf->dt_emask) || ++ DMEV_ISSET(DM_EVENT_WRITE, buf->dt_emask) || ++ DMEV_ISSET(DM_EVENT_TRUNCATE, buf->dt_emask)) ? 1 : 0; ++} ++ ++/* ++ * Take the handle and put it at the end of a dm_xstat buffer. ++ * dt_compname is unused in bulkstat - so we zero it out. ++ * Finally, update link in dm_xstat_t to point to next struct. ++ */ ++STATIC void ++xfs_dm_handle_to_xstat( ++ dm_xstat_t *xbuf, ++ size_t xstat_sz, ++ dm_handle_t *handle, ++ size_t handle_sz) ++{ ++ dm_stat_t *sbuf = &xbuf->dx_statinfo; ++ ++ memcpy(xbuf + 1, handle, handle_sz); ++ sbuf->dt_handle.vd_offset = (ssize_t) sizeof(dm_xstat_t); ++ sbuf->dt_handle.vd_length = (size_t) DM_HSIZE(*handle); ++ memset(&sbuf->dt_compname, 0, sizeof(dm_vardata_t)); ++ sbuf->_link = xstat_sz; ++} ++ ++STATIC int ++xfs_dm_bulkall_iget_one( ++ xfs_mount_t *mp, ++ xfs_ino_t ino, ++ xfs_daddr_t bno, ++ int *value_lenp, ++ dm_xstat_t *xbuf, ++ u_int *xstat_szp, ++ char *attr_name, ++ caddr_t attr_buf) ++{ ++ xfs_inode_t *ip; ++ dm_handle_t handle; ++ u_int xstat_sz = *xstat_szp; ++ int value_len = *value_lenp; ++ int error; ++ ++ error = xfs_iget(mp, NULL, ino, ++ XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno); ++ if (error) ++ return error; ++ ++ xfs_ip_to_stat(mp, ino, ip, &xbuf->dx_statinfo); ++ dm_ip_to_handle(ip->i_vnode, &handle); ++ xfs_dm_handle_to_xstat(xbuf, xstat_sz, &handle, sizeof(handle)); ++ ++ /* Drop ILOCK_SHARED for call to xfs_attr_get */ ++ xfs_iunlock(ip, XFS_ILOCK_SHARED); ++ ++ memset(&xbuf->dx_attrdata, 0, sizeof(dm_vardata_t)); ++ error = xfs_attr_get(ip, attr_name, attr_buf, &value_len, ATTR_ROOT); ++ iput(ip->i_vnode); ++ ++ DM_EA_XLATE_ERR(error); ++ if (error && (error != ENOATTR)) { ++ if (error == E2BIG) ++ error = ENOMEM; ++ return error; ++ } ++ ++ /* How much space was in the attr? */ ++ if (error != ENOATTR) { ++ xbuf->dx_attrdata.vd_offset = xstat_sz; ++ xbuf->dx_attrdata.vd_length = value_len; ++ xstat_sz += (value_len+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++ } ++ *xstat_szp = xbuf->dx_statinfo._link = xstat_sz; ++ *value_lenp = value_len; ++ return 0; ++} ++ ++ ++STATIC int ++xfs_dm_inline_attr( ++ xfs_mount_t *mp, ++ xfs_dinode_t *dip, ++ char *attr_name, ++ caddr_t attr_buf, ++ int *value_lenp) ++{ ++ if (dip->di_core.di_aformat == XFS_DINODE_FMT_LOCAL) { ++ xfs_attr_shortform_t *sf; ++ xfs_attr_sf_entry_t *sfe; ++ unsigned int namelen = strlen(attr_name); ++ unsigned int valuelen = *value_lenp; ++ int i; ++ ++ sf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); ++ sfe = &sf->list[0]; ++ for (i = 0; i < sf->hdr.count; ++ sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { ++ if (sfe->namelen != namelen) ++ continue; ++ if (!(sfe->flags & XFS_ATTR_ROOT)) ++ continue; ++ if (memcmp(attr_name, sfe->nameval, namelen) != 0) ++ continue; ++ if (valuelen < sfe->valuelen) ++ return ERANGE; ++ valuelen = sfe->valuelen; ++ memcpy(attr_buf, &sfe->nameval[namelen], valuelen); ++ *value_lenp = valuelen; ++ return 0; ++ } ++ } ++ *value_lenp = 0; ++ return ENOATTR; ++} ++ ++STATIC void ++dm_dip_to_handle( ++ xfs_ino_t ino, ++ xfs_dinode_t *dip, ++ dm_fsid_t *fsid, ++ dm_handle_t *handlep) ++{ ++ dm_fid_t fid; ++ int hsize; ++ ++ fid.dm_fid_len = sizeof(struct dm_fid) - sizeof(fid.dm_fid_len); ++ fid.dm_fid_pad = 0; ++ fid.dm_fid_ino = ino; ++ fid.dm_fid_gen = be32_to_cpu(dip->di_core.di_gen); ++ ++ memcpy(&handlep->ha_fsid, fsid, sizeof(*fsid)); ++ memcpy(&handlep->ha_fid, &fid, fid.dm_fid_len + sizeof(fid.dm_fid_len)); ++ hsize = DM_HSIZE(*handlep); ++ memset((char *)handlep + hsize, 0, sizeof(*handlep) - hsize); ++} ++ ++STATIC int ++xfs_dm_bulkall_inline_one( ++ xfs_mount_t *mp, ++ xfs_ino_t ino, ++ xfs_dinode_t *dip, ++ dm_fsid_t *fsid, ++ int *value_lenp, ++ dm_xstat_t *xbuf, ++ u_int *xstat_szp, ++ char *attr_name, ++ caddr_t attr_buf) ++{ ++ dm_handle_t handle; ++ u_int xstat_sz = *xstat_szp; ++ int value_len = *value_lenp; ++ int error; ++ ++ if (dip->di_core.di_mode == 0) ++ return ENOENT; ++ ++ xfs_dip_to_stat(mp, ino, dip, &xbuf->dx_statinfo); ++ dm_dip_to_handle(ino, dip, fsid, &handle); ++ xfs_dm_handle_to_xstat(xbuf, xstat_sz, &handle, sizeof(handle)); ++ ++ memset(&xbuf->dx_attrdata, 0, sizeof(dm_vardata_t)); ++ error = xfs_dm_inline_attr(mp, dip, attr_name, attr_buf, &value_len); ++ DM_EA_XLATE_ERR(error); ++ if (error && (error != ENOATTR)) { ++ if (error == E2BIG) ++ error = ENOMEM; ++ return error; ++ } ++ ++ /* How much space was in the attr? */ ++ if (error != ENOATTR) { ++ xbuf->dx_attrdata.vd_offset = xstat_sz; ++ xbuf->dx_attrdata.vd_length = value_len; ++ xstat_sz += (value_len+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++ } ++ *xstat_szp = xbuf->dx_statinfo._link = xstat_sz; ++ *value_lenp = value_len; ++ return 0; ++} ++ ++/* ++ * This is used by dm_get_bulkall(). ++ * Given a inumber, it igets the inode and fills the given buffer ++ * with the dm_xstat structure for the file. ++ */ ++STATIC int ++xfs_dm_bulkall_one( ++ xfs_mount_t *mp, /* mount point for filesystem */ ++ xfs_ino_t ino, /* inode number to get data for */ ++ void __user *buffer, /* buffer to place output in */ ++ int ubsize, /* size of buffer */ ++ void *private_data, /* my private data */ ++ xfs_daddr_t bno, /* starting block of inode cluster */ ++ int *ubused, /* amount of buffer we used */ ++ void *dibuff, /* on-disk inode buffer */ ++ int *res) /* bulkstat result code */ ++{ ++ dm_xstat_t *xbuf; ++ u_int xstat_sz; ++ int error; ++ int value_len; ++ int kern_buf_sz; ++ int attr_buf_sz; ++ caddr_t attr_buf; ++ void __user *attr_user_buf; ++ dm_bulkstat_one_t *dmb = (dm_bulkstat_one_t*)private_data; ++ ++ /* Returns positive errors to XFS */ ++ ++ *res = BULKSTAT_RV_NOTHING; ++ ++ if (!buffer || xfs_internal_inum(mp, ino)) ++ return EINVAL; ++ ++ xstat_sz = DM_STAT_SIZE(*xbuf, 0); ++ xstat_sz = (xstat_sz + (DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++ if (xstat_sz > ubsize) ++ return ENOMEM; ++ ++ kern_buf_sz = xstat_sz; ++ xbuf = kmem_alloc(kern_buf_sz, KM_SLEEP); ++ ++ /* Determine place to drop attr value, and available space. */ ++ value_len = ubsize - xstat_sz; ++ if (value_len > ATTR_MAX_VALUELEN) ++ value_len = ATTR_MAX_VALUELEN; ++ ++ attr_user_buf = buffer + xstat_sz; ++ attr_buf_sz = value_len; ++ attr_buf = kmem_alloc(attr_buf_sz, KM_SLEEP); ++ ++ if (!dibuff) ++ error = xfs_dm_bulkall_iget_one(mp, ino, bno, ++ &value_len, xbuf, &xstat_sz, ++ dmb->attrname.dan_chars, ++ attr_buf); ++ else ++ error = xfs_dm_bulkall_inline_one(mp, ino, ++ (xfs_dinode_t *)dibuff, ++ &dmb->fsid, ++ &value_len, xbuf, &xstat_sz, ++ dmb->attrname.dan_chars, ++ attr_buf); ++ if (error) ++ goto out_free_buffers; ++ ++ if (copy_to_user(buffer, xbuf, kern_buf_sz)) { ++ error = EFAULT; ++ goto out_free_buffers; ++ } ++ if (copy_to_user(attr_user_buf, attr_buf, value_len)) { ++ error = EFAULT; ++ goto out_free_buffers; ++ } ++ ++ kmem_free(attr_buf); ++ kmem_free(xbuf); ++ ++ *res = BULKSTAT_RV_DIDONE; ++ if (ubused) ++ *ubused = xstat_sz; ++ dmb->laststruct = buffer; ++ return 0; ++ ++ out_free_buffers: ++ kmem_free(attr_buf); ++ kmem_free(xbuf); ++ return error; ++} ++ ++/* ++ * Take the handle and put it at the end of a dm_stat buffer. ++ * dt_compname is unused in bulkstat - so we zero it out. ++ * Finally, update link in dm_stat_t to point to next struct. ++ */ ++STATIC void ++xfs_dm_handle_to_stat( ++ dm_stat_t *sbuf, ++ size_t stat_sz, ++ dm_handle_t *handle, ++ size_t handle_sz) ++{ ++ memcpy(sbuf + 1, handle, handle_sz); ++ sbuf->dt_handle.vd_offset = (ssize_t) sizeof(dm_stat_t); ++ sbuf->dt_handle.vd_length = (size_t) DM_HSIZE(*handle); ++ memset(&sbuf->dt_compname, 0, sizeof(dm_vardata_t)); ++ sbuf->_link = stat_sz; ++} ++ ++STATIC int ++xfs_dm_bulkattr_iget_one( ++ xfs_mount_t *mp, ++ xfs_ino_t ino, ++ xfs_daddr_t bno, ++ dm_stat_t *sbuf, ++ u_int stat_sz) ++{ ++ xfs_inode_t *ip; ++ dm_handle_t handle; ++ int error; ++ ++ error = xfs_iget(mp, NULL, ino, ++ XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno); ++ if (error) ++ return error; ++ ++ xfs_ip_to_stat(mp, ino, ip, sbuf); ++ dm_ip_to_handle(ip->i_vnode, &handle); ++ xfs_dm_handle_to_stat(sbuf, stat_sz, &handle, sizeof(handle)); ++ ++ xfs_iput(ip, XFS_ILOCK_SHARED); ++ return 0; ++} ++ ++STATIC int ++xfs_dm_bulkattr_inline_one( ++ xfs_mount_t *mp, ++ xfs_ino_t ino, ++ xfs_dinode_t *dip, ++ dm_fsid_t *fsid, ++ dm_stat_t *sbuf, ++ u_int stat_sz) ++{ ++ dm_handle_t handle; ++ ++ if (dip->di_core.di_mode == 0) ++ return ENOENT; ++ xfs_dip_to_stat(mp, ino, dip, sbuf); ++ dm_dip_to_handle(ino, dip, fsid, &handle); ++ xfs_dm_handle_to_stat(sbuf, stat_sz, &handle, sizeof(handle)); ++ return 0; ++} ++ ++/* ++ * This is used by dm_get_bulkattr(). ++ * Given a inumber, it igets the inode and fills the given buffer ++ * with the dm_stat structure for the file. ++ */ ++STATIC int ++xfs_dm_bulkattr_one( ++ xfs_mount_t *mp, /* mount point for filesystem */ ++ xfs_ino_t ino, /* inode number to get data for */ ++ void __user *buffer, /* buffer to place output in */ ++ int ubsize, /* size of buffer */ ++ void *private_data, /* my private data */ ++ xfs_daddr_t bno, /* starting block of inode cluster */ ++ int *ubused, /* amount of buffer we used */ ++ void *dibuff, /* on-disk inode buffer */ ++ int *res) /* bulkstat result code */ ++{ ++ dm_stat_t *sbuf; ++ u_int stat_sz; ++ int error; ++ dm_bulkstat_one_t *dmb = (dm_bulkstat_one_t*)private_data; ++ ++ /* Returns positive errors to XFS */ ++ ++ *res = BULKSTAT_RV_NOTHING; ++ ++ if (!buffer || xfs_internal_inum(mp, ino)) ++ return EINVAL; ++ ++ stat_sz = DM_STAT_SIZE(*sbuf, 0); ++ stat_sz = (stat_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++ if (stat_sz > ubsize) ++ return ENOMEM; ++ ++ sbuf = kmem_alloc(stat_sz, KM_SLEEP); ++ ++ if (!dibuff) ++ error = xfs_dm_bulkattr_iget_one(mp, ino, bno, sbuf, stat_sz); ++ else ++ error = xfs_dm_bulkattr_inline_one(mp, ino, ++ (xfs_dinode_t *)dibuff, ++ &dmb->fsid, sbuf, stat_sz); ++ if (error) ++ goto out_free_buffer; ++ ++ if (copy_to_user(buffer, sbuf, stat_sz)) { ++ error = EFAULT; ++ goto out_free_buffer; ++ } ++ ++ kmem_free(sbuf); ++ *res = BULKSTAT_RV_DIDONE; ++ if (ubused) ++ *ubused = stat_sz; ++ dmb->laststruct = buffer; ++ return 0; ++ ++ out_free_buffer: ++ kmem_free(sbuf); ++ return error; ++} ++ ++/* xfs_dm_f_get_eventlist - return the dm_eventset_t mask for inode ip. */ ++ ++STATIC int ++xfs_dm_f_get_eventlist( ++ xfs_inode_t *ip, ++ dm_right_t right, ++ u_int nelem, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int *nelemp) /* in kernel space! */ ++{ ++ dm_eventset_t eventset; ++ ++ if (right < DM_RIGHT_SHARED) ++ return(EACCES); ++ ++ /* Note that we MUST return a regular file's managed region bits as ++ part of the mask because dm_get_eventlist is supposed to return the ++ union of all managed region flags in those bits. Since we only ++ support one region, we can just return the bits as they are. For ++ all other object types, the bits will already be zero. Handy, huh? ++ */ ++ ++ eventset = ip->i_d.di_dmevmask; ++ ++ /* Now copy the event mask and event count back to the caller. We ++ return the lesser of nelem and DM_EVENT_MAX. ++ */ ++ ++ if (nelem > DM_EVENT_MAX) ++ nelem = DM_EVENT_MAX; ++ eventset &= (1 << nelem) - 1; ++ ++ *eventsetp = eventset; ++ *nelemp = nelem; ++ return(0); ++} ++ ++ ++/* xfs_dm_f_set_eventlist - update the dm_eventset_t mask in the inode vp. Only the ++ bits from zero to maxevent-1 are being replaced; higher bits are preserved. ++*/ ++ ++STATIC int ++xfs_dm_f_set_eventlist( ++ xfs_inode_t *ip, ++ dm_right_t right, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int maxevent) ++{ ++ dm_eventset_t eventset; ++ dm_eventset_t max_mask; ++ dm_eventset_t valid_events; ++ xfs_trans_t *tp; ++ xfs_mount_t *mp; ++ int error; ++ ++ if (right < DM_RIGHT_EXCL) ++ return(EACCES); ++ ++ eventset = *eventsetp; ++ if (maxevent >= sizeof(ip->i_d.di_dmevmask) * NBBY) ++ return(EINVAL); ++ max_mask = (1 << maxevent) - 1; ++ ++ if (S_ISDIR(ip->i_d.di_mode)) { ++ valid_events = DM_XFS_VALID_DIRECTORY_EVENTS; ++ } else { /* file or symlink */ ++ valid_events = DM_XFS_VALID_FILE_EVENTS; ++ } ++ if ((eventset & max_mask) & ~valid_events) ++ return(EINVAL); ++ ++ /* Adjust the event mask so that the managed region bits will not ++ be altered. ++ */ ++ ++ max_mask &= ~(1 <i_mount; ++ tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); ++ error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); ++ if (error) { ++ xfs_trans_cancel(tp, 0); ++ return(error); ++ } ++ xfs_ilock(ip, XFS_ILOCK_EXCL); ++ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); ++ ++ ip->i_d.di_dmevmask = (eventset & max_mask) | (ip->i_d.di_dmevmask & ~max_mask); ++ ++ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); ++ igrab(ip->i_vnode); ++ xfs_trans_commit(tp, 0); ++ ++ return(0); ++} ++ ++ ++/* xfs_dm_fs_get_eventlist - return the dm_eventset_t mask for filesystem vfsp. */ ++ ++STATIC int ++xfs_dm_fs_get_eventlist( ++ xfs_mount_t *mp, ++ dm_right_t right, ++ u_int nelem, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int *nelemp) /* in kernel space! */ ++{ ++ dm_eventset_t eventset; ++ ++ if (right < DM_RIGHT_SHARED) ++ return(EACCES); ++ ++ eventset = mp->m_dmevmask; ++ ++ /* Now copy the event mask and event count back to the caller. We ++ return the lesser of nelem and DM_EVENT_MAX. ++ */ ++ ++ if (nelem > DM_EVENT_MAX) ++ nelem = DM_EVENT_MAX; ++ eventset &= (1 << nelem) - 1; ++ ++ *eventsetp = eventset; ++ *nelemp = nelem; ++ return(0); ++} ++ ++ ++/* xfs_dm_fs_set_eventlist - update the dm_eventset_t mask in the mount structure for ++ filesystem vfsp. Only the bits from zero to maxevent-1 are being replaced; ++ higher bits are preserved. ++*/ ++ ++STATIC int ++xfs_dm_fs_set_eventlist( ++ xfs_mount_t *mp, ++ dm_right_t right, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int maxevent) ++{ ++ dm_eventset_t eventset; ++ dm_eventset_t max_mask; ++ ++ if (right < DM_RIGHT_EXCL) ++ return(EACCES); ++ ++ eventset = *eventsetp; ++ ++ if (maxevent >= sizeof(mp->m_dmevmask) * NBBY) ++ return(EINVAL); ++ max_mask = (1 << maxevent) - 1; ++ ++ if ((eventset & max_mask) & ~DM_XFS_VALID_FS_EVENTS) ++ return(EINVAL); ++ ++ mp->m_dmevmask = (eventset & max_mask) | (mp->m_dmevmask & ~max_mask); ++ return(0); ++} ++ ++ ++/* Code in this routine must exactly match the logic in xfs_diordwr() in ++ order for this to work! ++*/ ++ ++STATIC int ++xfs_dm_direct_ok( ++ xfs_inode_t *ip, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp) ++{ ++ xfs_mount_t *mp; ++ ++ mp = ip->i_mount; ++ ++ /* Realtime files can ONLY do direct I/O. */ ++ ++ if (XFS_IS_REALTIME_INODE(ip)) ++ return(1); ++ ++ /* If direct I/O is disabled, or if the request is too small, use ++ buffered I/O. ++ */ ++ ++ if (!dm_min_dio_xfer || len < dm_min_dio_xfer) ++ return(0); ++ ++#if 0 ++ /* If the request is not well-formed or is too large, use ++ buffered I/O. ++ */ ++ ++ if ((__psint_t)bufp & scache_linemask) /* if buffer not aligned */ ++ return(0); ++ if (off & mp->m_blockmask) /* if file offset not aligned */ ++ return(0); ++ if (len & mp->m_blockmask) /* if xfer length not aligned */ ++ return(0); ++ if (len > ctooff(v.v_maxdmasz - 1)) /* if transfer too large */ ++ return(0); ++ ++ /* A valid direct I/O candidate. */ ++ ++ return(1); ++#else ++ return(0); ++#endif ++} ++ ++ ++/* We need to be able to select various combinations of O_NONBLOCK, ++ O_DIRECT, and O_SYNC, yet we don't have a file descriptor and we don't have ++ the file's pathname. All we have is a handle. ++*/ ++ ++STATIC int ++xfs_dm_rdwr( ++ struct inode *inode, ++ uint fflag, ++ mode_t fmode, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp) ++{ ++ xfs_inode_t *ip = XFS_I(inode); ++ int error; ++ int oflags; ++ ssize_t xfer; ++ struct file *file; ++ struct dentry *dentry; ++ ++ if ((off < 0) || (off > i_size_read(inode)) || !S_ISREG(inode->i_mode)) ++ return EINVAL; ++ ++ if (fmode & FMODE_READ) { ++ oflags = O_RDONLY; ++ } else { ++ oflags = O_WRONLY; ++ } ++ ++ /* ++ * Build file descriptor flags and I/O flags. O_NONBLOCK is needed so ++ * that we don't block on mandatory file locks. This is an invisible IO, ++ * don't change the atime. ++ */ ++ ++ oflags |= O_LARGEFILE | O_NONBLOCK | O_NOATIME; ++ if (xfs_dm_direct_ok(ip, off, len, bufp)) ++ oflags |= O_DIRECT; ++ ++ if (fflag & O_SYNC) ++ oflags |= O_SYNC; ++ ++ if (inode->i_fop == NULL) { ++ /* no iput; caller did get, and will do put */ ++ return EINVAL; ++ } ++ ++ igrab(inode); ++ ++ dentry = d_alloc_anon(inode); ++ if (dentry == NULL) { ++ iput(inode); ++ return ENOMEM; ++ } ++ ++ file = dentry_open(dentry, mntget(ip->i_mount->m_vfsmount), oflags); ++ if (IS_ERR(file)) { ++ return -PTR_ERR(file); ++ } ++ file->f_op = &xfs_invis_file_operations; ++ ++ if (fmode & FMODE_READ) { ++ xfer = file->f_op->read(file, bufp, len, (loff_t*)&off); ++ } else { ++ xfer = file->f_op->write(file, bufp, len, (loff_t*)&off); ++ } ++ ++ if (xfer >= 0) { ++ *rvp = xfer; ++ error = 0; ++ } else { ++ /* xfs_read/xfs_write return negative error--flip it */ ++ error = -(int)xfer; ++ } ++ ++ fput(file); ++ return error; ++} ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_clear_inherit( ++ struct inode *inode, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep) ++{ ++ return(-ENOSYS); /* Return negative error to DMAPI */ ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_create_by_handle( ++ struct inode *inode, ++ dm_right_t right, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname) ++{ ++ return(-ENOSYS); /* Return negative error to DMAPI */ ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_downgrade_right( ++ struct inode *inode, ++ dm_right_t right, ++ u_int type) /* DM_FSYS_OBJ or zero */ ++{ ++#ifdef DEBUG_RIGHTS ++ char buffer[sizeof(dm_handle_t) * 2 + 1]; ++ ++ if (!xfs_vp_to_hexhandle(inode, type, buffer)) { ++ printf("dm_downgrade_right: old %d new %d type %d handle %s\n", ++ right, DM_RIGHT_SHARED, type, buffer); ++ } else { ++ printf("dm_downgrade_right: old %d new %d type %d handle " ++ "\n", right, DM_RIGHT_SHARED, type); ++ } ++#endif /* DEBUG_RIGHTS */ ++ return(0); ++} ++ ++ ++/* Note: xfs_dm_get_allocinfo() makes no attempt to coalesce two adjacent ++ extents when both are of type DM_EXTENT_RES; this is left to the caller. ++ XFS guarantees that there will never be two adjacent DM_EXTENT_HOLE extents. ++ ++ In order to provide the caller with all extents in a file including ++ those beyond the file's last byte offset, we have to use the xfs_bmapi() ++ interface. ++*/ ++ ++STATIC int ++xfs_dm_get_allocinfo_rvp( ++ struct inode *inode, ++ dm_right_t right, ++ dm_off_t __user *offp, ++ u_int nelem, ++ dm_extent_t __user *extentp, ++ u_int __user *nelemp, ++ int *rvp) ++{ ++ xfs_inode_t *ip = XFS_I(inode); ++ xfs_mount_t *mp; /* file system mount point */ ++ xfs_fileoff_t fsb_offset; ++ xfs_filblks_t fsb_length; ++ dm_off_t startoff; ++ int elem; ++ xfs_bmbt_irec_t *bmp = NULL; ++ u_int bmpcnt = 50; ++ u_int bmpsz = sizeof(xfs_bmbt_irec_t) * bmpcnt; ++ int error = 0; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ if ((inode->i_mode & S_IFMT) != S_IFREG) ++ return(-EINVAL); ++ ++ if (copy_from_user( &startoff, offp, sizeof(startoff))) ++ return(-EFAULT); ++ ++ mp = ip->i_mount; ++ ASSERT(mp); ++ ++ if (startoff > XFS_MAXIOFFSET(mp)) ++ return(-EINVAL); ++ ++ if (nelem == 0) ++ return(-EINVAL); ++ ++ /* Convert the caller's starting offset into filesystem allocation ++ units as required by xfs_bmapi(). Round the offset down so that ++ it is sure to be included in the reply. ++ */ ++ ++ fsb_offset = XFS_B_TO_FSBT(mp, startoff); ++ fsb_length = XFS_B_TO_FSB(mp, XFS_MAXIOFFSET(mp)) - fsb_offset; ++ elem = 0; ++ ++ if (fsb_length) ++ bmp = kmem_alloc(bmpsz, KM_SLEEP); ++ ++ while (fsb_length && elem < nelem) { ++ dm_extent_t extent; ++ xfs_filblks_t fsb_bias; ++ dm_size_t bias; ++ int lock; ++ int num; ++ int i; ++ ++ /* Compute how many getbmap structures to use on the xfs_bmapi ++ call. ++ */ ++ ++ num = MIN((u_int)(nelem - elem), bmpcnt); ++ ++ xfs_ilock(ip, XFS_IOLOCK_SHARED); ++ lock = xfs_ilock_map_shared(ip); ++ ++ error = xfs_bmapi(NULL, ip, fsb_offset, fsb_length, ++ XFS_BMAPI_ENTIRE, NULL, 0, bmp, &num, NULL, NULL); ++ ++ xfs_iunlock_map_shared(ip, lock); ++ xfs_iunlock(ip, XFS_IOLOCK_SHARED); ++ ++ if (error) { ++ error = -error; /* Return negative error to DMAPI */ ++ goto finish_out; ++ } ++ ++ /* Fill in the caller's extents, adjusting the bias in the ++ first entry if necessary. ++ */ ++ ++ for (i = 0; i < num; i++, extentp++) { ++ bias = startoff - XFS_FSB_TO_B(mp, bmp[i].br_startoff); ++ extent.ex_offset = startoff; ++ extent.ex_length = ++ XFS_FSB_TO_B(mp, bmp[i].br_blockcount) - bias; ++ if (bmp[i].br_startblock == HOLESTARTBLOCK) { ++ extent.ex_type = DM_EXTENT_HOLE; ++ } else { ++ extent.ex_type = DM_EXTENT_RES; ++ } ++ startoff = extent.ex_offset + extent.ex_length; ++ ++ if (copy_to_user( extentp, &extent, sizeof(extent))) { ++ error = -EFAULT; ++ goto finish_out; ++ } ++ ++ fsb_bias = fsb_offset - bmp[i].br_startoff; ++ fsb_offset += bmp[i].br_blockcount - fsb_bias; ++ fsb_length -= bmp[i].br_blockcount - fsb_bias; ++ elem++; ++ } ++ } ++ ++ if (fsb_length == 0) { ++ startoff = 0; ++ } ++ if (copy_to_user( offp, &startoff, sizeof(startoff))) { ++ error = -EFAULT; ++ goto finish_out; ++ } ++ ++ if (copy_to_user( nelemp, &elem, sizeof(elem))) { ++ error = -EFAULT; ++ goto finish_out; ++ } ++ ++ *rvp = (fsb_length == 0 ? 0 : 1); ++ ++finish_out: ++ if (bmp) ++ kmem_free(bmp); ++ return(error); ++} ++ ++ ++STATIC int ++xfs_dm_zero_xstatinfo_link( ++ dm_xstat_t __user *dxs) ++{ ++ dm_xstat_t *ldxs; ++ int error = 0; ++ ++ if (!dxs) ++ return 0; ++ ldxs = kmalloc(sizeof(*ldxs), GFP_KERNEL); ++ if (!ldxs) ++ return -ENOMEM; ++ if (copy_from_user(ldxs, dxs, sizeof(*dxs))) { ++ error = -EFAULT; ++ } else { ++ ldxs->dx_statinfo._link = 0; ++ if (copy_to_user(dxs, ldxs, sizeof(*dxs))) ++ error = -EFAULT; ++ } ++ kfree(ldxs); ++ return error; ++} ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_get_bulkall_rvp( ++ struct inode *inode, ++ dm_right_t right, ++ u_int mask, ++ dm_attrname_t __user *attrnamep, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, /* address of buffer in user space */ ++ size_t __user *rlenp, /* user space address */ ++ int *rvalp) ++{ ++ int error, done; ++ int nelems; ++ u_int statstruct_sz; ++ dm_attrloc_t loc; ++ xfs_mount_t *mp = XFS_I(inode)->i_mount; ++ dm_attrname_t attrname; ++ dm_bulkstat_one_t dmb; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (copy_from_user(&attrname, attrnamep, sizeof(attrname)) || ++ copy_from_user(&loc, locp, sizeof(loc))) ++ return -EFAULT; ++ ++ if (attrname.an_chars[0] == '\0') ++ return(-EINVAL); ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ /* Because we will write directly to the user's buffer, make sure that ++ the buffer is properly aligned. ++ */ ++ ++ if (((unsigned long)bufp & (DM_STAT_ALIGN - 1)) != 0) ++ return(-EFAULT); ++ ++ /* Size of the handle is constant for this function. ++ * If there are no files with attributes, then this will be the ++ * maximum number of inodes we can get. ++ */ ++ ++ statstruct_sz = DM_STAT_SIZE(dm_xstat_t, 0); ++ statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++ ++ nelems = buflen / statstruct_sz; ++ if (nelems < 1) { ++ if (put_user( statstruct_sz, rlenp )) ++ return(-EFAULT); ++ return(-E2BIG); ++ } ++ ++ /* Build the on-disk version of the attribute name. */ ++ strcpy(dmb.attrname.dan_chars, dmattr_prefix); ++ strncpy(&dmb.attrname.dan_chars[DMATTR_PREFIXLEN], ++ attrname.an_chars, DM_ATTR_NAME_SIZE + 1); ++ dmb.attrname.dan_chars[sizeof(dmb.attrname.dan_chars) - 1] = '\0'; ++ ++ /* ++ * fill the buffer with dm_xstat_t's ++ */ ++ ++ dmb.laststruct = NULL; ++ memcpy(&dmb.fsid, mp->m_fixedfsid, sizeof(dm_fsid_t)); ++ error = xfs_bulkstat(mp, (xfs_ino_t *)&loc, &nelems, ++ xfs_dm_bulkall_one, (void*)&dmb, statstruct_sz, ++ bufp, BULKSTAT_FG_INLINE, &done); ++ if (error) ++ return(-error); /* Return negative error to DMAPI */ ++ ++ *rvalp = !done ? 1 : 0; ++ ++ if (put_user( statstruct_sz * nelems, rlenp )) ++ return(-EFAULT); ++ ++ if (copy_to_user( locp, &loc, sizeof(loc))) ++ return(-EFAULT); ++ /* ++ * If we didn't do any, we must not have any more to do. ++ */ ++ if (nelems < 1) ++ return(0); ++ /* ++ * Set _link in the last struct to zero ++ */ ++ return xfs_dm_zero_xstatinfo_link((dm_xstat_t __user *)dmb.laststruct); ++} ++ ++ ++STATIC int ++xfs_dm_zero_statinfo_link( ++ dm_stat_t __user *dxs) ++{ ++ dm_stat_t *ldxs; ++ int error = 0; ++ ++ if (!dxs) ++ return 0; ++ ldxs = kmalloc(sizeof(*ldxs), GFP_KERNEL); ++ if (!ldxs) ++ return -ENOMEM; ++ if (copy_from_user(ldxs, dxs, sizeof(*dxs))) { ++ error = -EFAULT; ++ } else { ++ ldxs->_link = 0; ++ if (copy_to_user(dxs, ldxs, sizeof(*dxs))) ++ error = -EFAULT; ++ } ++ kfree(ldxs); ++ return error; ++} ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_get_bulkattr_rvp( ++ struct inode *inode, ++ dm_right_t right, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvalp) ++{ ++ int error, done; ++ int nelems; ++ u_int statstruct_sz; ++ dm_attrloc_t loc; ++ xfs_mount_t *mp = XFS_I(inode)->i_mount; ++ dm_bulkstat_one_t dmb; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ if (copy_from_user( &loc, locp, sizeof(loc))) ++ return(-EFAULT); ++ ++ /* Because we will write directly to the user's buffer, make sure that ++ the buffer is properly aligned. ++ */ ++ ++ if (((unsigned long)bufp & (DM_STAT_ALIGN - 1)) != 0) ++ return(-EFAULT); ++ ++ /* size of the handle is constant for this function */ ++ ++ statstruct_sz = DM_STAT_SIZE(dm_stat_t, 0); ++ statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); ++ ++ nelems = buflen / statstruct_sz; ++ if (nelems < 1) { ++ if (put_user( statstruct_sz, rlenp )) ++ return(-EFAULT); ++ return(-E2BIG); ++ } ++ ++ dmb.laststruct = NULL; ++ memcpy(&dmb.fsid, mp->m_fixedfsid, sizeof(dm_fsid_t)); ++ error = xfs_bulkstat(mp, (xfs_ino_t *)&loc, &nelems, ++ xfs_dm_bulkattr_one, (void*)&dmb, ++ statstruct_sz, bufp, BULKSTAT_FG_INLINE, &done); ++ if (error) ++ return(-error); /* Return negative error to DMAPI */ ++ ++ *rvalp = !done ? 1 : 0; ++ ++ if (put_user( statstruct_sz * nelems, rlenp )) ++ return(-EFAULT); ++ ++ if (copy_to_user( locp, &loc, sizeof(loc))) ++ return(-EFAULT); ++ ++ /* ++ * If we didn't do any, we must not have any more to do. ++ */ ++ if (nelems < 1) ++ return(0); ++ /* ++ * Set _link in the last struct to zero ++ */ ++ return xfs_dm_zero_statinfo_link((dm_stat_t __user *)dmb.laststruct); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_get_config( ++ struct inode *inode, ++ dm_right_t right, ++ dm_config_t flagname, ++ dm_size_t __user *retvalp) ++{ ++ dm_size_t retval; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ switch (flagname) { ++ case DM_CONFIG_DTIME_OVERLOAD: ++ case DM_CONFIG_PERS_ATTRIBUTES: ++ case DM_CONFIG_PERS_EVENTS: ++ case DM_CONFIG_PERS_MANAGED_REGIONS: ++ case DM_CONFIG_PUNCH_HOLE: ++ case DM_CONFIG_WILL_RETRY: ++ retval = DM_TRUE; ++ break; ++ ++ case DM_CONFIG_CREATE_BY_HANDLE: /* these will never be done */ ++ case DM_CONFIG_LOCK_UPGRADE: ++ case DM_CONFIG_PERS_INHERIT_ATTRIBS: ++ retval = DM_FALSE; ++ break; ++ ++ case DM_CONFIG_BULKALL: ++ retval = DM_TRUE; ++ break; ++ case DM_CONFIG_MAX_ATTR_ON_DESTROY: ++ retval = DM_MAX_ATTR_BYTES_ON_DESTROY; ++ break; ++ ++ case DM_CONFIG_MAX_ATTRIBUTE_SIZE: ++ retval = ATTR_MAX_VALUELEN; ++ break; ++ ++ case DM_CONFIG_MAX_HANDLE_SIZE: ++ retval = DM_MAX_HANDLE_SIZE; ++ break; ++ ++ case DM_CONFIG_MAX_MANAGED_REGIONS: ++ retval = 1; ++ break; ++ ++ case DM_CONFIG_TOTAL_ATTRIBUTE_SPACE: ++ retval = 0x7fffffff; /* actually it's unlimited */ ++ break; ++ ++ default: ++ return(-EINVAL); ++ } ++ ++ /* Copy the results back to the user. */ ++ ++ if (copy_to_user( retvalp, &retval, sizeof(retval))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_get_config_events( ++ struct inode *inode, ++ dm_right_t right, ++ u_int nelem, ++ dm_eventset_t __user *eventsetp, ++ u_int __user *nelemp) ++{ ++ dm_eventset_t eventset; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (nelem == 0) ++ return(-EINVAL); ++ ++ eventset = DM_XFS_SUPPORTED_EVENTS; ++ ++ /* Now copy the event mask and event count back to the caller. We ++ return the lesser of nelem and DM_EVENT_MAX. ++ */ ++ ++ if (nelem > DM_EVENT_MAX) ++ nelem = DM_EVENT_MAX; ++ eventset &= (1 << nelem) - 1; ++ ++ if (copy_to_user( eventsetp, &eventset, sizeof(eventset))) ++ return(-EFAULT); ++ ++ if (put_user(nelem, nelemp)) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_get_destroy_dmattr( ++ struct inode *inode, ++ dm_right_t right, ++ dm_attrname_t *attrnamep, ++ char **valuepp, ++ int *vlenp) ++{ ++ dm_dkattrname_t dkattrname; ++ int alloc_size; ++ int value_len; ++ char *value; ++ int error; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ *vlenp = -1; /* assume failure by default */ ++ ++ if (attrnamep->an_chars[0] == '\0') ++ return(-EINVAL); ++ ++ /* Build the on-disk version of the attribute name. */ ++ ++ strcpy(dkattrname.dan_chars, dmattr_prefix); ++ strncpy(&dkattrname.dan_chars[DMATTR_PREFIXLEN], ++ (char *)attrnamep->an_chars, DM_ATTR_NAME_SIZE + 1); ++ dkattrname.dan_chars[sizeof(dkattrname.dan_chars) - 1] = '\0'; ++ ++ /* xfs_attr_get will not return anything if the buffer is too small, ++ and we don't know how big to make the buffer, so this may take ++ two tries to get it right. The initial try must use a buffer of ++ at least XFS_BUG_KLUDGE bytes to prevent buffer overflow because ++ of a bug in XFS. ++ */ ++ ++ alloc_size = XFS_BUG_KLUDGE; ++ value = kmalloc(alloc_size, GFP_KERNEL); ++ if (value == NULL) ++ return(-ENOMEM); ++ ++ error = xfs_attr_get(XFS_I(inode), dkattrname.dan_chars, value, ++ &value_len, ATTR_ROOT); ++ if (error == ERANGE) { ++ kfree(value); ++ alloc_size = value_len; ++ value = kmalloc(alloc_size, GFP_KERNEL); ++ if (value == NULL) ++ return(-ENOMEM); ++ ++ error = xfs_attr_get(XFS_I(inode), dkattrname.dan_chars, value, ++ &value_len, ATTR_ROOT); ++ } ++ if (error) { ++ kfree(value); ++ DM_EA_XLATE_ERR(error); ++ return(-error); /* Return negative error to DMAPI */ ++ } ++ ++ /* The attribute exists and has a value. Note that a value_len of ++ zero is valid! ++ */ ++ ++ if (value_len == 0) { ++ kfree(value); ++ *vlenp = 0; ++ return(0); ++ } else if (value_len > DM_MAX_ATTR_BYTES_ON_DESTROY) { ++ char *value2; ++ ++ value2 = kmalloc(DM_MAX_ATTR_BYTES_ON_DESTROY, GFP_KERNEL); ++ if (value2 == NULL) { ++ kfree(value); ++ return(-ENOMEM); ++ } ++ memcpy(value2, value, DM_MAX_ATTR_BYTES_ON_DESTROY); ++ kfree(value); ++ value = value2; ++ value_len = DM_MAX_ATTR_BYTES_ON_DESTROY; ++ } ++ *vlenp = value_len; ++ *valuepp = value; ++ return(0); ++} ++ ++/* This code was taken from xfs_fcntl(F_DIOINFO) and modified slightly because ++ we don't have a flags parameter (no open file). ++ Taken from xfs_ioctl(XFS_IOC_DIOINFO) on Linux. ++*/ ++ ++STATIC int ++xfs_dm_get_dioinfo( ++ struct inode *inode, ++ dm_right_t right, ++ dm_dioinfo_t __user *diop) ++{ ++ dm_dioinfo_t dio; ++ xfs_mount_t *mp; ++ xfs_inode_t *ip = XFS_I(inode); ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ mp = ip->i_mount; ++ ++ dio.d_miniosz = dio.d_mem = MIN_DIO_SIZE(mp); ++ dio.d_maxiosz = MAX_DIO_SIZE(mp); ++ dio.d_dio_only = DM_FALSE; ++ ++ if (copy_to_user(diop, &dio, sizeof(dio))) ++ return(-EFAULT); ++ return(0); ++} ++ ++typedef struct dm_readdir_cb { ++ xfs_mount_t *mp; ++ char __user *ubuf; ++ dm_stat_t __user *lastbuf; ++ size_t spaceleft; ++ size_t nwritten; ++ int error; ++ dm_stat_t kstat; ++} dm_readdir_cb_t; ++ ++STATIC int ++dm_filldir(void *__buf, const char *name, int namelen, loff_t offset, ++ u64 ino, unsigned int d_type) ++{ ++ dm_readdir_cb_t *cb = __buf; ++ dm_stat_t *statp = &cb->kstat; ++ size_t len; ++ int error; ++ int needed; ++ ++ /* ++ * Make sure we have enough space. ++ */ ++ needed = dm_stat_size(namelen + 1); ++ if (cb->spaceleft < needed) { ++ cb->spaceleft = 0; ++ return -ENOSPC; ++ } ++ ++ error = -EINVAL; ++ if (xfs_internal_inum(cb->mp, ino)) ++ goto out_err; ++ ++ memset(statp, 0, dm_stat_size(MAXNAMLEN)); ++ error = -xfs_dm_bulkattr_iget_one(cb->mp, ino, 0, ++ statp, needed); ++ if (error) ++ goto out_err; ++ ++ /* ++ * On return from bulkstat_one(), stap->_link points ++ * at the end of the handle in the stat structure. ++ */ ++ statp->dt_compname.vd_offset = statp->_link; ++ statp->dt_compname.vd_length = namelen + 1; ++ ++ len = statp->_link; ++ ++ /* Word-align the record */ ++ statp->_link = dm_stat_align(len + namelen + 1); ++ ++ error = -EFAULT; ++ if (copy_to_user(cb->ubuf, statp, len)) ++ goto out_err; ++ if (copy_to_user(cb->ubuf + len, name, namelen)) ++ goto out_err; ++ if (put_user(0, cb->ubuf + len + namelen)) ++ goto out_err; ++ ++ cb->lastbuf = (dm_stat_t __user *)cb->ubuf; ++ cb->spaceleft -= statp->_link; ++ cb->nwritten += statp->_link; ++ cb->ubuf += statp->_link; ++ ++ return 0; ++ ++ out_err: ++ cb->error = error; ++ return error; ++} ++ ++/* Returns negative errors to DMAPI */ ++STATIC int ++xfs_dm_get_dirattrs_rvp( ++ struct inode *inode, ++ dm_right_t right, ++ u_int mask, ++ dm_attrloc_t __user *locp, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp, ++ int *rvp) ++{ ++ xfs_inode_t *dp = XFS_I(inode); ++ xfs_mount_t *mp = dp->i_mount; ++ dm_readdir_cb_t *cb; ++ dm_attrloc_t loc; ++ int error; ++ ++ if (right < DM_RIGHT_SHARED) ++ return -EACCES; ++ ++ /* ++ * Make sure that the buffer is properly aligned. ++ */ ++ if (((unsigned long)bufp & (DM_STAT_ALIGN - 1)) != 0) ++ return -EFAULT; ++ ++ if (mask & ~(DM_AT_HANDLE|DM_AT_EMASK|DM_AT_PMANR|DM_AT_PATTR| ++ DM_AT_DTIME|DM_AT_CFLAG|DM_AT_STAT)) ++ return -EINVAL; ++ ++ if (!S_ISDIR(inode->i_mode)) ++ return -EINVAL; ++ ++ /* ++ * bufp should be able to fit at least one dm_stat entry including ++ * dt_handle and full size MAXNAMLEN dt_compname. ++ */ ++ if (buflen < dm_stat_size(MAXNAMLEN)) ++ return -ENOMEM; ++ ++ if (copy_from_user(&loc, locp, sizeof(loc))) ++ return -EFAULT; ++ ++ cb = kzalloc(sizeof(*cb) + dm_stat_size(MAXNAMLEN), GFP_KERNEL); ++ if (!cb) ++ return -ENOMEM; ++ ++ cb->mp = mp; ++ cb->spaceleft = buflen; ++ cb->ubuf = bufp; ++ ++ mutex_lock(&inode->i_mutex); ++ error = -ENOENT; ++ if (!IS_DEADDIR(inode)) { ++ error = -xfs_readdir(dp, cb, dp->i_size, ++ (xfs_off_t *)&loc, dm_filldir); ++ } ++ mutex_unlock(&inode->i_mutex); ++ ++ if (error) ++ goto out_kfree; ++ if (cb->error) { ++ error = cb->error; ++ goto out_kfree; ++ } ++ ++ error = -EFAULT; ++ if (cb->lastbuf && put_user(0, &cb->lastbuf->_link)) ++ goto out_kfree; ++ if (put_user(cb->nwritten, rlenp)) ++ goto out_kfree; ++ if (copy_to_user(locp, &loc, sizeof(loc))) ++ goto out_kfree; ++ ++ if (cb->nwritten) ++ *rvp = 1; ++ else ++ *rvp = 0; ++ error = 0; ++ ++ out_kfree: ++ kfree(cb); ++ return error; ++} ++ ++STATIC int ++xfs_dm_get_dmattr( ++ struct inode *inode, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ dm_dkattrname_t name; ++ char *value; ++ int value_len; ++ int alloc_size; ++ int error; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) ++ return(-error); /* Return negative error to DMAPI */ ++ ++ /* Allocate a buffer to receive the attribute's value. We allocate ++ at least one byte even if the caller specified a buflen of zero. ++ (A buflen of zero is considered valid.) ++ ++ Allocating a minimum of XFS_BUG_KLUDGE bytes temporarily works ++ around a bug within XFS in which in-inode attribute values are not ++ checked to see if they will fit in the buffer before they are ++ copied. Since no in-core attribute value can be larger than 256 ++ bytes (an 8-bit size field), we allocate that minimum size here to ++ prevent buffer overrun in both the kernel's and user's buffers. ++ */ ++ ++ alloc_size = buflen; ++ if (alloc_size < XFS_BUG_KLUDGE) ++ alloc_size = XFS_BUG_KLUDGE; ++ if (alloc_size > ATTR_MAX_VALUELEN) ++ alloc_size = ATTR_MAX_VALUELEN; ++ value = kmem_alloc(alloc_size, KM_SLEEP | KM_LARGE); ++ ++ /* Get the attribute's value. */ ++ ++ value_len = alloc_size; /* in/out parameter */ ++ ++ error = xfs_attr_get(XFS_I(inode), name.dan_chars, value, &value_len, ++ ATTR_ROOT); ++ DM_EA_XLATE_ERR(error); ++ ++ /* DMAPI requires an errno of ENOENT if an attribute does not exist, ++ so remap ENOATTR here. ++ */ ++ ++ if (error == ENOATTR) ++ error = ENOENT; ++ if (!error && value_len > buflen) ++ error = E2BIG; ++ if (!error && copy_to_user(bufp, value, value_len)) ++ error = EFAULT; ++ if (!error || error == E2BIG) { ++ if (put_user(value_len, rlenp)) ++ error = EFAULT; ++ } ++ ++ kmem_free(value); ++ return(-error); /* Return negative error to DMAPI */ ++} ++ ++STATIC int ++xfs_dm_get_eventlist( ++ struct inode *inode, ++ dm_right_t right, ++ u_int type, ++ u_int nelem, ++ dm_eventset_t *eventsetp, ++ u_int *nelemp) ++{ ++ int error; ++ xfs_inode_t *ip = XFS_I(inode); ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (type == DM_FSYS_OBJ) { ++ error = xfs_dm_fs_get_eventlist(ip->i_mount, right, nelem, ++ eventsetp, nelemp); ++ } else { ++ error = xfs_dm_f_get_eventlist(ip, right, nelem, ++ eventsetp, nelemp); ++ } ++ return(-error); /* Returns negative error to DMAPI */ ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_get_fileattr( ++ struct inode *inode, ++ dm_right_t right, ++ u_int mask, /* not used; always return everything */ ++ dm_stat_t __user *statp) ++{ ++ dm_stat_t stat; ++ xfs_inode_t *ip = XFS_I(inode); ++ xfs_mount_t *mp; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ /* Find the mount point. */ ++ ++ mp = ip->i_mount; ++ ++ xfs_ilock(ip, XFS_ILOCK_SHARED); ++ xfs_ip_to_stat(mp, ip->i_ino, ip, &stat); ++ xfs_iunlock(ip, XFS_ILOCK_SHARED); ++ ++ if (copy_to_user( statp, &stat, sizeof(stat))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* We currently only support a maximum of one managed region per file, and ++ use the DM_EVENT_READ, DM_EVENT_WRITE, and DM_EVENT_TRUNCATE events in ++ the file's dm_eventset_t event mask to implement the DM_REGION_READ, ++ DM_REGION_WRITE, and DM_REGION_TRUNCATE flags for that single region. ++*/ ++ ++STATIC int ++xfs_dm_get_region( ++ struct inode *inode, ++ dm_right_t right, ++ u_int nelem, ++ dm_region_t __user *regbufp, ++ u_int __user *nelemp) ++{ ++ dm_eventset_t evmask; ++ dm_region_t region; ++ xfs_inode_t *ip = XFS_I(inode); ++ u_int elem; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ evmask = ip->i_d.di_dmevmask; /* read the mask "atomically" */ ++ ++ /* Get the file's current managed region flags out of the ++ dm_eventset_t mask and use them to build a managed region that ++ covers the entire file, i.e. set rg_offset and rg_size to zero. ++ */ ++ ++ memset((char *)®ion, 0, sizeof(region)); ++ ++ if (evmask & (1 << DM_EVENT_READ)) ++ region.rg_flags |= DM_REGION_READ; ++ if (evmask & (1 << DM_EVENT_WRITE)) ++ region.rg_flags |= DM_REGION_WRITE; ++ if (evmask & (1 << DM_EVENT_TRUNCATE)) ++ region.rg_flags |= DM_REGION_TRUNCATE; ++ ++ elem = (region.rg_flags ? 1 : 0); ++ ++ if (copy_to_user( nelemp, &elem, sizeof(elem))) ++ return(-EFAULT); ++ if (elem > nelem) ++ return(-E2BIG); ++ if (elem && copy_to_user(regbufp, ®ion, sizeof(region))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++STATIC int ++xfs_dm_getall_dmattr( ++ struct inode *inode, ++ dm_right_t right, ++ size_t buflen, ++ void __user *bufp, ++ size_t __user *rlenp) ++{ ++ attrlist_cursor_kern_t cursor; ++ attrlist_t *attrlist; ++ dm_attrlist_t __user *ulist; ++ int *last_link; ++ int alignment; ++ int total_size; ++ int list_size = 8192; /* should be big enough */ ++ int error; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ /* Verify that the user gave us a buffer that is 4-byte aligned, lock ++ it down, and work directly within that buffer. As a side-effect, ++ values of buflen < sizeof(int) return EINVAL. ++ */ ++ ++ alignment = sizeof(int) - 1; ++ if ((((__psint_t)bufp & alignment) != 0) || ++ !access_ok(VERIFY_WRITE, bufp, buflen)) { ++ return(-EFAULT); ++ } ++ buflen &= ~alignment; /* round down the alignment */ ++ ++ /* Initialize all the structures and variables for the main loop. */ ++ ++ memset(&cursor, 0, sizeof(cursor)); ++ attrlist = (attrlist_t *)kmem_alloc(list_size, KM_SLEEP); ++ total_size = 0; ++ ulist = (dm_attrlist_t *)bufp; ++ last_link = NULL; ++ ++ /* Use vop_attr_list to get the names of DMAPI attributes, and use ++ vop_attr_get to get their values. There is a risk here that the ++ DMAPI attributes could change between the vop_attr_list and ++ vop_attr_get calls. If we can detect it, we return EIO to notify ++ the user. ++ */ ++ ++ do { ++ int i; ++ ++ /* Get a buffer full of attribute names. If there aren't any ++ more or if we encounter an error, then finish up. ++ */ ++ ++ error = xfs_attr_list(XFS_I(inode), (char *)attrlist, list_size, ++ ATTR_ROOT, &cursor); ++ DM_EA_XLATE_ERR(error); ++ ++ if (error || attrlist->al_count == 0) ++ break; ++ ++ for (i = 0; i < attrlist->al_count; i++) { ++ attrlist_ent_t *entry; ++ char *user_name; ++ int size_needed; ++ int value_len; ++ ++ /* Skip over all non-DMAPI attributes. If the ++ attribute name is too long, we assume it is ++ non-DMAPI even if it starts with the correct ++ prefix. ++ */ ++ ++ entry = ATTR_ENTRY(attrlist, i); ++ if (strncmp(entry->a_name, dmattr_prefix, DMATTR_PREFIXLEN)) ++ continue; ++ user_name = &entry->a_name[DMATTR_PREFIXLEN]; ++ if (strlen(user_name) > DM_ATTR_NAME_SIZE) ++ continue; ++ ++ /* We have a valid DMAPI attribute to return. If it ++ won't fit in the user's buffer, we still need to ++ keep track of the number of bytes for the user's ++ next call. ++ */ ++ ++ ++ size_needed = sizeof(*ulist) + entry->a_valuelen; ++ size_needed = (size_needed + alignment) & ~alignment; ++ ++ total_size += size_needed; ++ if (total_size > buflen) ++ continue; ++ ++ /* Start by filling in all the fields in the ++ dm_attrlist_t structure. ++ */ ++ ++ strncpy((char *)ulist->al_name.an_chars, user_name, ++ DM_ATTR_NAME_SIZE); ++ ulist->al_data.vd_offset = sizeof(*ulist); ++ ulist->al_data.vd_length = entry->a_valuelen; ++ ulist->_link = size_needed; ++ last_link = &ulist->_link; ++ ++ /* Next read the attribute's value into its correct ++ location after the dm_attrlist structure. Any sort ++ of error indicates that the data is moving under us, ++ so we return EIO to let the user know. ++ */ ++ ++ value_len = entry->a_valuelen; ++ ++ error = xfs_attr_get(XFS_I(inode), entry->a_name, ++ (void *)(ulist + 1), &value_len, ++ ATTR_ROOT); ++ DM_EA_XLATE_ERR(error); ++ ++ if (error || value_len != entry->a_valuelen) { ++ error = EIO; ++ break; ++ } ++ ++ ulist = (dm_attrlist_t *)((char *)ulist + ulist->_link); ++ } ++ } while (!error && attrlist->al_more); ++ if (last_link) ++ *last_link = 0; ++ ++ if (!error && total_size > buflen) ++ error = E2BIG; ++ if (!error || error == E2BIG) { ++ if (put_user(total_size, rlenp)) ++ error = EFAULT; ++ } ++ ++ kmem_free(attrlist); ++ return(-error); /* Return negative error to DMAPI */ ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_getall_inherit( ++ struct inode *inode, ++ dm_right_t right, ++ u_int nelem, ++ dm_inherit_t __user *inheritbufp, ++ u_int __user *nelemp) ++{ ++ return(-ENOSYS); /* Return negative error to DMAPI */ ++} ++ ++ ++/* Initialize location pointer for subsequent dm_get_dirattrs, ++ dm_get_bulkattr, and dm_get_bulkall calls. The same initialization must ++ work for inode-based routines (dm_get_dirattrs) and filesystem-based ++ routines (dm_get_bulkattr and dm_get_bulkall). Filesystem-based functions ++ call this routine using the filesystem's root inode. ++*/ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_init_attrloc( ++ struct inode *inode, ++ dm_right_t right, ++ dm_attrloc_t __user *locp) ++{ ++ dm_attrloc_t loc = 0; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ if (copy_to_user( locp, &loc, sizeof(loc))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_mkdir_by_handle( ++ struct inode *inode, ++ dm_right_t right, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname) ++{ ++ return(-ENOSYS); /* Return negative error to DMAPI */ ++} ++ ++ ++/* ++ * Probe and Punch ++ * ++ * Hole punching alignment is based on the underlying device base ++ * allocation size. Because it is not defined in the DMAPI spec, we ++ * can align how we choose here. Round inwards (offset up and length ++ * down) to the block, extent or page size whichever is bigger. Our ++ * DMAPI implementation rounds the hole geometry strictly inwards. If ++ * this is not possible, return EINVAL for both for xfs_dm_probe_hole ++ * and xfs_dm_punch_hole which differs from the DMAPI spec. Note that ++ * length = 0 is special - it means "punch to EOF" and at that point ++ * we treat the punch as remove everything past offset (including ++ * preallocation past EOF). ++ */ ++ ++STATIC int ++xfs_dm_round_hole( ++ dm_off_t offset, ++ dm_size_t length, ++ dm_size_t align, ++ xfs_fsize_t filesize, ++ dm_off_t *roff, ++ dm_size_t *rlen) ++{ ++ ++ dm_off_t off = offset; ++ dm_size_t len = length; ++ ++ /* Try to round offset up to the nearest boundary */ ++ *roff = roundup_64(off, align); ++ if ((*roff >= filesize) || (len && (len < align))) ++ return -EINVAL; ++ ++ if ((len == 0) || ((off + len) == filesize)) { ++ /* punch to EOF */ ++ *rlen = 0; ++ } else { ++ /* Round length down to the nearest boundary. */ ++ ASSERT(len >= align); ++ ASSERT(align > (*roff - off)); ++ len -= *roff - off; ++ *rlen = len - do_mod(len, align); ++ if (*rlen == 0) ++ return -EINVAL; /* requested length is too small */ ++ } ++#ifdef CONFIG_DMAPI_DEBUG ++ printk("xfs_dm_round_hole: off %lu, len %ld, align %lu, " ++ "filesize %llu, roff %ld, rlen %ld\n", ++ offset, length, align, filesize, *roff, *rlen); ++#endif ++ return 0; /* hole geometry successfully rounded */ ++} ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_probe_hole( ++ struct inode *inode, ++ dm_right_t right, ++ dm_off_t off, ++ dm_size_t len, ++ dm_off_t __user *roffp, ++ dm_size_t __user *rlenp) ++{ ++ dm_off_t roff; ++ dm_size_t rlen; ++ xfs_inode_t *ip = XFS_I(inode); ++ xfs_mount_t *mp; ++ uint lock_flags; ++ xfs_fsize_t realsize; ++ dm_size_t align; ++ int error; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return -EACCES; ++ ++ if ((ip->i_d.di_mode & S_IFMT) != S_IFREG) ++ return -EINVAL; ++ ++ mp = ip->i_mount; ++ lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; ++ xfs_ilock(ip, lock_flags); ++ realsize = ip->i_size; ++ xfs_iunlock(ip, lock_flags); ++ ++ if ((off + len) > realsize) ++ return -E2BIG; ++ ++ align = 1 << mp->m_sb.sb_blocklog; ++ ++ error = xfs_dm_round_hole(off, len, align, realsize, &roff, &rlen); ++ if (error) ++ return error; ++ ++ if (copy_to_user( roffp, &roff, sizeof(roff))) ++ return -EFAULT; ++ if (copy_to_user( rlenp, &rlen, sizeof(rlen))) ++ return -EFAULT; ++ return(0); ++} ++ ++ ++STATIC int ++xfs_dm_punch_hole( ++ struct inode *inode, ++ dm_right_t right, ++ dm_off_t off, ++ dm_size_t len) ++{ ++ xfs_flock64_t bf; ++ int error = 0; ++ xfs_inode_t *ip = XFS_I(inode); ++ xfs_mount_t *mp; ++ dm_size_t align; ++ xfs_fsize_t realsize; ++ dm_off_t roff; ++ dm_size_t rlen; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_EXCL) ++ return -EACCES; ++ ++ /* Make sure there are no leases. */ ++ error = break_lease(inode, FMODE_WRITE); ++ if (error) ++ return -EBUSY; ++ ++ error = get_write_access(inode); ++ if (error) ++ return -EBUSY; ++ ++ mp = ip->i_mount; ++ ++ down_rw_sems(inode, DM_SEM_FLAG_WR); ++ ++ xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); ++ realsize = ip->i_size; ++ xfs_iunlock(ip, XFS_ILOCK_EXCL); ++ align = xfs_get_extsz_hint(ip); ++ if (align == 0) ++ align = 1; ++ ++ align <<= mp->m_sb.sb_blocklog; ++ ++ if ((off + len) > realsize) { ++ xfs_iunlock(ip, XFS_IOLOCK_EXCL); ++ error = -E2BIG; ++ goto up_and_out; ++ } ++ ++ if ((off + len) == realsize) ++ len = 0; ++ ++ error = xfs_dm_round_hole(off, len, align, realsize, &roff, &rlen); ++ if (error || (off != roff) || (len != rlen)) { ++ xfs_iunlock(ip, XFS_IOLOCK_EXCL); ++ error = -EINVAL; ++ goto up_and_out; ++ } ++ ++ bf.l_type = 0; ++ bf.l_whence = 0; ++ bf.l_start = (xfs_off_t)off; ++ if (len) { ++ bf.l_len = len; ++ } ++ else { ++ /* ++ * When we are punching to EOF, we have to make sure we punch ++ * the last partial block that contains EOF. Round up ++ * the length to make sure we punch the block and not just ++ * zero it. ++ */ ++ bf.l_len = roundup_64((realsize - off), mp->m_sb.sb_blocksize); ++ } ++ ++#ifdef CONFIG_DMAPI_DEBUG ++ printk("xfs_dm_punch_hole: off %lu, len %ld, align %lu\n", ++ off, len, align); ++#endif ++ ++ error = xfs_change_file_space(ip, XFS_IOC_UNRESVSP, &bf, ++ (xfs_off_t)off, sys_cred, ++ XFS_ATTR_DMI|XFS_ATTR_NOLOCK); ++ ++ /* ++ * if punching to end of file, kill any blocks past EOF that ++ * may have been (speculatively) preallocated. No point in ++ * leaving them around if we are migrating the file.... ++ */ ++ if (!error && (len == 0)) { ++ error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_NOLOCK); ++ } ++ ++ /* ++ * negate the error for return here as core XFS functions return ++ * positive error numbers ++ */ ++ if (error) ++ error = -error; ++ ++ /* Let threads in send_data_event know we punched the file. */ ++ ip->i_d.di_dmstate++; ++ xfs_iunlock(ip, XFS_IOLOCK_EXCL); ++ xfs_iflags_set(ip, XFS_IMODIFIED); ++ ++up_and_out: ++ up_rw_sems(inode, DM_SEM_FLAG_WR); ++ put_write_access(inode); ++ ++ return error; ++} ++ ++ ++STATIC int ++xfs_dm_read_invis_rvp( ++ struct inode *inode, ++ dm_right_t right, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp) ++{ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_SHARED) ++ return(-EACCES); ++ ++ return(-xfs_dm_rdwr(inode, 0, FMODE_READ, off, len, bufp, rvp)); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_release_right( ++ struct inode *inode, ++ dm_right_t right, ++ u_int type) /* DM_FSYS_OBJ or zero */ ++{ ++#ifdef DEBUG_RIGHTS ++ char buffer[sizeof(dm_handle_t) * 2 + 1]; ++ ++ if (!xfs_vp_to_hexhandle(inode, type, buffer)) { ++ printf("dm_release_right: old %d type %d handle %s\n", ++ right, type, buffer); ++ } else { ++ printf("dm_release_right: old %d type %d handle " ++ " \n", right, type); ++ } ++#endif /* DEBUG_RIGHTS */ ++ return(0); ++} ++ ++ ++STATIC int ++xfs_dm_remove_dmattr( ++ struct inode *inode, ++ dm_right_t right, ++ int setdtime, ++ dm_attrname_t __user *attrnamep) ++{ ++ dm_dkattrname_t name; ++ int error; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_EXCL) ++ return(-EACCES); ++ ++ if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) ++ return(-error); /* Return negative error to DMAPI */ ++ ++ /* Remove the attribute from the object. */ ++ ++ error = xfs_attr_remove(XFS_I(inode), name.dan_chars, setdtime ? ++ ATTR_ROOT : (ATTR_ROOT|ATTR_KERNOTIME)); ++ DM_EA_XLATE_ERR(error); ++ ++ if (error == ENOATTR) ++ error = ENOENT; ++ return(-error); /* Return negative error to DMAPI */ ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_request_right( ++ struct inode *inode, ++ dm_right_t right, ++ u_int type, /* DM_FSYS_OBJ or zero */ ++ u_int flags, ++ dm_right_t newright) ++{ ++#ifdef DEBUG_RIGHTS ++ char buffer[sizeof(dm_handle_t) * 2 + 1]; ++ ++ if (!xfs_vp_to_hexhandle(inode, type, buffer)) { ++ printf("dm_request_right: old %d new %d type %d flags 0x%x " ++ "handle %s\n", right, newright, type, flags, buffer); ++ } else { ++ printf("dm_request_right: old %d new %d type %d flags 0x%x " ++ "handle \n", right, newright, type, flags); ++ } ++#endif /* DEBUG_RIGHTS */ ++ return(0); ++} ++ ++ ++STATIC int ++xfs_dm_set_dmattr( ++ struct inode *inode, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep, ++ int setdtime, ++ size_t buflen, ++ void __user *bufp) ++{ ++ dm_dkattrname_t name; ++ char *value; ++ int alloc_size; ++ int error; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_EXCL) ++ return(-EACCES); ++ ++ if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) ++ return(-error); /* Return negative error to DMAPI */ ++ if (buflen > ATTR_MAX_VALUELEN) ++ return(-E2BIG); ++ ++ /* Copy in the attribute's value and store the pair in ++ the object. We allocate a buffer of at least one byte even if the ++ caller specified a buflen of zero. (A buflen of zero is considered ++ valid.) ++ */ ++ ++ alloc_size = (buflen == 0) ? 1 : buflen; ++ value = kmem_alloc(alloc_size, KM_SLEEP); ++ if (copy_from_user( value, bufp, buflen)) { ++ error = EFAULT; ++ } else { ++ error = xfs_attr_set(XFS_I(inode), name.dan_chars, value, buflen, ++ setdtime ? ATTR_ROOT : ++ (ATTR_ROOT|ATTR_KERNOTIME)); ++ DM_EA_XLATE_ERR(error); ++ } ++ kmem_free(value); ++ return(-error); /* Return negative error to DMAPI */ ++} ++ ++STATIC int ++xfs_dm_set_eventlist( ++ struct inode *inode, ++ dm_right_t right, ++ u_int type, ++ dm_eventset_t *eventsetp, /* in kernel space! */ ++ u_int maxevent) ++{ ++ int error; ++ xfs_inode_t *ip = XFS_I(inode); ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (type == DM_FSYS_OBJ) { ++ error = xfs_dm_fs_set_eventlist(ip->i_mount, right, eventsetp, maxevent); ++ } else { ++ error = xfs_dm_f_set_eventlist(ip, right, eventsetp, maxevent); ++ } ++ return(-error); /* Return negative error to DMAPI */ ++} ++ ++ ++/* ++ * This turned out not XFS-specific, but leave it here with get_fileattr. ++ */ ++ ++STATIC int ++xfs_dm_set_fileattr( ++ struct inode *inode, ++ dm_right_t right, ++ u_int mask, ++ dm_fileattr_t __user *statp) ++{ ++ dm_fileattr_t stat; ++ struct iattr iattr; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_EXCL) ++ return(-EACCES); ++ ++ if (copy_from_user( &stat, statp, sizeof(stat))) ++ return(-EFAULT); ++ ++ iattr.ia_valid = 0; ++ ++ if (mask & DM_AT_MODE) { ++ iattr.ia_valid |= ATTR_MODE; ++ iattr.ia_mode = stat.fa_mode; ++ } ++ if (mask & DM_AT_UID) { ++ iattr.ia_valid |= ATTR_UID; ++ iattr.ia_uid = stat.fa_uid; ++ } ++ if (mask & DM_AT_GID) { ++ iattr.ia_valid |= ATTR_GID; ++ iattr.ia_gid = stat.fa_gid; ++ } ++ if (mask & DM_AT_ATIME) { ++ iattr.ia_valid |= ATTR_ATIME; ++ iattr.ia_atime.tv_sec = stat.fa_atime; ++ iattr.ia_atime.tv_nsec = 0; ++ inode->i_atime.tv_sec = stat.fa_atime; ++ } ++ if (mask & DM_AT_MTIME) { ++ iattr.ia_valid |= ATTR_MTIME; ++ iattr.ia_mtime.tv_sec = stat.fa_mtime; ++ iattr.ia_mtime.tv_nsec = 0; ++ } ++ if (mask & DM_AT_CTIME) { ++ iattr.ia_valid |= ATTR_CTIME; ++ iattr.ia_ctime.tv_sec = stat.fa_ctime; ++ iattr.ia_ctime.tv_nsec = 0; ++ } ++ ++ /* ++ * DM_AT_DTIME only takes effect if DM_AT_CTIME is not specified. We ++ * overload ctime to also act as dtime, i.e. DM_CONFIG_DTIME_OVERLOAD. ++ */ ++ if ((mask & DM_AT_DTIME) && !(mask & DM_AT_CTIME)) { ++ iattr.ia_valid |= ATTR_CTIME; ++ iattr.ia_ctime.tv_sec = stat.fa_dtime; ++ iattr.ia_ctime.tv_nsec = 0; ++ } ++ if (mask & DM_AT_SIZE) { ++ iattr.ia_valid |= ATTR_SIZE; ++ iattr.ia_size = stat.fa_size; ++ } ++ ++ return -xfs_setattr(XFS_I(inode), &iattr, XFS_ATTR_DMI, NULL); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_set_inherit( ++ struct inode *inode, ++ dm_right_t right, ++ dm_attrname_t __user *attrnamep, ++ mode_t mode) ++{ ++ return(-ENOSYS); /* Return negative error to DMAPI */ ++} ++ ++ ++STATIC int ++xfs_dm_set_region( ++ struct inode *inode, ++ dm_right_t right, ++ u_int nelem, ++ dm_region_t __user *regbufp, ++ dm_boolean_t __user *exactflagp) ++{ ++ xfs_inode_t *ip = XFS_I(inode); ++ xfs_trans_t *tp; ++ xfs_mount_t *mp; ++ dm_region_t region; ++ dm_eventset_t new_mask; ++ dm_eventset_t mr_mask; ++ int error; ++ u_int exactflag; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_EXCL) ++ return(-EACCES); ++ ++ /* If the caller gave us more than one dm_region_t structure, complain. ++ (He has to call dm_get_config() to find out what our limit is.) ++ */ ++ ++ if (nelem > 1) ++ return(-E2BIG); ++ ++ /* If the user provided a dm_region_t structure, then copy it in, ++ validate it, and convert its flags to the corresponding bits in a ++ dm_set_eventlist() event mask. A call with zero regions is ++ equivalent to clearing all region flags. ++ */ ++ ++ new_mask = 0; ++ if (nelem == 1) { ++ if (copy_from_user( ®ion, regbufp, sizeof(region))) ++ return(-EFAULT); ++ ++ if (region.rg_flags & ~(DM_REGION_READ|DM_REGION_WRITE|DM_REGION_TRUNCATE)) ++ return(-EINVAL); ++ if (region.rg_flags & DM_REGION_READ) ++ new_mask |= 1 << DM_EVENT_READ; ++ if (region.rg_flags & DM_REGION_WRITE) ++ new_mask |= 1 << DM_EVENT_WRITE; ++ if (region.rg_flags & DM_REGION_TRUNCATE) ++ new_mask |= 1 << DM_EVENT_TRUNCATE; ++ } ++ mr_mask = (1 << DM_EVENT_READ) | (1 << DM_EVENT_WRITE) | (1 << DM_EVENT_TRUNCATE); ++ ++ /* Get the file's existing event mask, clear the old managed region ++ bits, add in the new ones, and update the file's mask. ++ */ ++ ++ if (new_mask & prohibited_mr_events(inode->i_mapping)) { ++ /* If the change is simply to remove the READ ++ * bit, then that's always okay. Otherwise, it's busy. ++ */ ++ dm_eventset_t m1; ++ m1 = ip->i_d.di_dmevmask & ((1 << DM_EVENT_WRITE) | (1 << DM_EVENT_TRUNCATE)); ++ if (m1 != new_mask) { ++ return -EBUSY; ++ } ++ } ++ ++ mp = ip->i_mount; ++ tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); ++ error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); ++ if (error) { ++ xfs_trans_cancel(tp, 0); ++ return(-error); /* Return negative error to DMAPI */ ++ } ++ xfs_ilock(ip, XFS_ILOCK_EXCL); ++ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); ++ ++ ip->i_d.di_dmevmask = (ip->i_d.di_dmevmask & ~mr_mask) | new_mask; ++ ++ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); ++ igrab(inode); ++ xfs_trans_commit(tp, 0); ++ ++ /* Return the proper value for *exactflagp depending upon whether or not ++ we "changed" the user's managed region. In other words, if the user ++ specified a non-zero value for either rg_offset or rg_size, we ++ round each of those values back to zero. ++ */ ++ ++ if (nelem && (region.rg_offset || region.rg_size)) { ++ exactflag = DM_FALSE; /* user region was changed */ ++ } else { ++ exactflag = DM_TRUE; /* user region was unchanged */ ++ } ++ if (copy_to_user( exactflagp, &exactflag, sizeof(exactflag))) ++ return(-EFAULT); ++ return(0); ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_symlink_by_handle( ++ struct inode *inode, ++ dm_right_t right, ++ void __user *hanp, ++ size_t hlen, ++ char __user *cname, ++ char __user *path) ++{ ++ return(-ENOSYS); /* Return negative errors to DMAPI */ ++} ++ ++ ++/* ++ * xfs_dm_sync_by_handle needs to do the same thing as sys_fsync() ++ */ ++STATIC int ++xfs_dm_sync_by_handle( ++ struct inode *inode, ++ dm_right_t right) ++{ ++ int err, ret; ++ xfs_inode_t *ip = XFS_I(inode); ++ ++ /* Returns negative errors to DMAPI */ ++ if (right < DM_RIGHT_EXCL) ++ return(-EACCES); ++ ++ /* We need to protect against concurrent writers.. */ ++ ret = filemap_fdatawrite(inode->i_mapping); ++ down_rw_sems(inode, DM_FLAGS_IMUX); ++ err = -xfs_fsync(ip); ++ if (!ret) ++ ret = err; ++ up_rw_sems(inode, DM_FLAGS_IMUX); ++ err = filemap_fdatawait(inode->i_mapping); ++ if (!ret) ++ ret = err; ++ xfs_iflags_clear(ip, XFS_ITRUNCATED); ++ return ret; ++} ++ ++ ++/* ARGSUSED */ ++STATIC int ++xfs_dm_upgrade_right( ++ struct inode *inode, ++ dm_right_t right, ++ u_int type) /* DM_FSYS_OBJ or zero */ ++{ ++#ifdef DEBUG_RIGHTS ++ char buffer[sizeof(dm_handle_t) * 2 + 1]; ++ ++ if (!xfs_vp_to_hexhandle(inode, type, buffer)) { ++ printf("dm_upgrade_right: old %d new %d type %d handle %s\n", ++ right, DM_RIGHT_EXCL, type, buffer); ++ } else { ++ printf("dm_upgrade_right: old %d new %d type %d handle " ++ "\n", right, DM_RIGHT_EXCL, type); ++ } ++#endif /* DEBUG_RIGHTS */ ++ return(0); ++} ++ ++ ++STATIC int ++xfs_dm_write_invis_rvp( ++ struct inode *inode, ++ dm_right_t right, ++ int flags, ++ dm_off_t off, ++ dm_size_t len, ++ void __user *bufp, ++ int *rvp) ++{ ++ int fflag = 0; ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (right < DM_RIGHT_EXCL) ++ return(-EACCES); ++ ++ if (flags & DM_WRITE_SYNC) ++ fflag |= O_SYNC; ++ return(-xfs_dm_rdwr(inode, fflag, FMODE_WRITE, off, len, bufp, rvp)); ++} ++ ++ ++STATIC void ++xfs_dm_obj_ref_hold( ++ struct inode *inode) ++{ ++ igrab(inode); ++} ++ ++ ++static fsys_function_vector_t xfs_fsys_vector[DM_FSYS_MAX]; ++ ++ ++STATIC int ++xfs_dm_get_dmapiops( ++ struct super_block *sb, ++ void *addr) ++{ ++ static int initialized = 0; ++ dm_fcntl_vector_t *vecrq; ++ fsys_function_vector_t *vecp; ++ int i = 0; ++ ++ vecrq = (dm_fcntl_vector_t *)addr; ++ vecrq->count = ++ sizeof(xfs_fsys_vector) / sizeof(xfs_fsys_vector[0]); ++ vecrq->vecp = xfs_fsys_vector; ++ if (initialized) ++ return(0); ++ vecrq->code_level = DM_CLVL_XOPEN; ++ vecp = xfs_fsys_vector; ++ ++ vecp[i].func_no = DM_FSYS_CLEAR_INHERIT; ++ vecp[i++].u_fc.clear_inherit = xfs_dm_clear_inherit; ++ vecp[i].func_no = DM_FSYS_CREATE_BY_HANDLE; ++ vecp[i++].u_fc.create_by_handle = xfs_dm_create_by_handle; ++ vecp[i].func_no = DM_FSYS_DOWNGRADE_RIGHT; ++ vecp[i++].u_fc.downgrade_right = xfs_dm_downgrade_right; ++ vecp[i].func_no = DM_FSYS_GET_ALLOCINFO_RVP; ++ vecp[i++].u_fc.get_allocinfo_rvp = xfs_dm_get_allocinfo_rvp; ++ vecp[i].func_no = DM_FSYS_GET_BULKALL_RVP; ++ vecp[i++].u_fc.get_bulkall_rvp = xfs_dm_get_bulkall_rvp; ++ vecp[i].func_no = DM_FSYS_GET_BULKATTR_RVP; ++ vecp[i++].u_fc.get_bulkattr_rvp = xfs_dm_get_bulkattr_rvp; ++ vecp[i].func_no = DM_FSYS_GET_CONFIG; ++ vecp[i++].u_fc.get_config = xfs_dm_get_config; ++ vecp[i].func_no = DM_FSYS_GET_CONFIG_EVENTS; ++ vecp[i++].u_fc.get_config_events = xfs_dm_get_config_events; ++ vecp[i].func_no = DM_FSYS_GET_DESTROY_DMATTR; ++ vecp[i++].u_fc.get_destroy_dmattr = xfs_dm_get_destroy_dmattr; ++ vecp[i].func_no = DM_FSYS_GET_DIOINFO; ++ vecp[i++].u_fc.get_dioinfo = xfs_dm_get_dioinfo; ++ vecp[i].func_no = DM_FSYS_GET_DIRATTRS_RVP; ++ vecp[i++].u_fc.get_dirattrs_rvp = xfs_dm_get_dirattrs_rvp; ++ vecp[i].func_no = DM_FSYS_GET_DMATTR; ++ vecp[i++].u_fc.get_dmattr = xfs_dm_get_dmattr; ++ vecp[i].func_no = DM_FSYS_GET_EVENTLIST; ++ vecp[i++].u_fc.get_eventlist = xfs_dm_get_eventlist; ++ vecp[i].func_no = DM_FSYS_GET_FILEATTR; ++ vecp[i++].u_fc.get_fileattr = xfs_dm_get_fileattr; ++ vecp[i].func_no = DM_FSYS_GET_REGION; ++ vecp[i++].u_fc.get_region = xfs_dm_get_region; ++ vecp[i].func_no = DM_FSYS_GETALL_DMATTR; ++ vecp[i++].u_fc.getall_dmattr = xfs_dm_getall_dmattr; ++ vecp[i].func_no = DM_FSYS_GETALL_INHERIT; ++ vecp[i++].u_fc.getall_inherit = xfs_dm_getall_inherit; ++ vecp[i].func_no = DM_FSYS_INIT_ATTRLOC; ++ vecp[i++].u_fc.init_attrloc = xfs_dm_init_attrloc; ++ vecp[i].func_no = DM_FSYS_MKDIR_BY_HANDLE; ++ vecp[i++].u_fc.mkdir_by_handle = xfs_dm_mkdir_by_handle; ++ vecp[i].func_no = DM_FSYS_PROBE_HOLE; ++ vecp[i++].u_fc.probe_hole = xfs_dm_probe_hole; ++ vecp[i].func_no = DM_FSYS_PUNCH_HOLE; ++ vecp[i++].u_fc.punch_hole = xfs_dm_punch_hole; ++ vecp[i].func_no = DM_FSYS_READ_INVIS_RVP; ++ vecp[i++].u_fc.read_invis_rvp = xfs_dm_read_invis_rvp; ++ vecp[i].func_no = DM_FSYS_RELEASE_RIGHT; ++ vecp[i++].u_fc.release_right = xfs_dm_release_right; ++ vecp[i].func_no = DM_FSYS_REMOVE_DMATTR; ++ vecp[i++].u_fc.remove_dmattr = xfs_dm_remove_dmattr; ++ vecp[i].func_no = DM_FSYS_REQUEST_RIGHT; ++ vecp[i++].u_fc.request_right = xfs_dm_request_right; ++ vecp[i].func_no = DM_FSYS_SET_DMATTR; ++ vecp[i++].u_fc.set_dmattr = xfs_dm_set_dmattr; ++ vecp[i].func_no = DM_FSYS_SET_EVENTLIST; ++ vecp[i++].u_fc.set_eventlist = xfs_dm_set_eventlist; ++ vecp[i].func_no = DM_FSYS_SET_FILEATTR; ++ vecp[i++].u_fc.set_fileattr = xfs_dm_set_fileattr; ++ vecp[i].func_no = DM_FSYS_SET_INHERIT; ++ vecp[i++].u_fc.set_inherit = xfs_dm_set_inherit; ++ vecp[i].func_no = DM_FSYS_SET_REGION; ++ vecp[i++].u_fc.set_region = xfs_dm_set_region; ++ vecp[i].func_no = DM_FSYS_SYMLINK_BY_HANDLE; ++ vecp[i++].u_fc.symlink_by_handle = xfs_dm_symlink_by_handle; ++ vecp[i].func_no = DM_FSYS_SYNC_BY_HANDLE; ++ vecp[i++].u_fc.sync_by_handle = xfs_dm_sync_by_handle; ++ vecp[i].func_no = DM_FSYS_UPGRADE_RIGHT; ++ vecp[i++].u_fc.upgrade_right = xfs_dm_upgrade_right; ++ vecp[i].func_no = DM_FSYS_WRITE_INVIS_RVP; ++ vecp[i++].u_fc.write_invis_rvp = xfs_dm_write_invis_rvp; ++ vecp[i].func_no = DM_FSYS_OBJ_REF_HOLD; ++ vecp[i++].u_fc.obj_ref_hold = xfs_dm_obj_ref_hold; ++ ++ return(0); ++} ++ ++ ++/* xfs_dm_send_mmap_event - send events needed for memory mapping a file. ++ * ++ * This is a workaround called for files that are about to be ++ * mapped. DMAPI events are not being generated at a low enough level ++ * in the kernel for page reads/writes to generate the correct events. ++ * So for memory-mapped files we generate read or write events for the ++ * whole byte range being mapped. If the mmap call can never cause a ++ * write to the file, then only a read event is sent. ++ * ++ * Code elsewhere prevents adding managed regions to a file while it ++ * is still mapped. ++ */ ++ ++STATIC int ++xfs_dm_send_mmap_event( ++ struct vm_area_struct *vma, ++ unsigned int wantflag) ++{ ++ xfs_inode_t *ip; ++ int error = 0; ++ dm_eventtype_t max_event = DM_EVENT_READ; ++ xfs_fsize_t filesize; ++ xfs_off_t length, end_of_area, evsize, offset; ++ int iolock; ++ ++ if (!vma->vm_file) ++ return 0; ++ ++ ip = XFS_I(vma->vm_file->f_dentry->d_inode); ++ ++ if (!S_ISREG(vma->vm_file->f_dentry->d_inode->i_mode) || ++ !(ip->i_mount->m_flags & XFS_MOUNT_DMAPI)) ++ return 0; ++ ++ /* If they specifically asked for 'read', then give it to them. ++ * Otherwise, see if it's possible to give them 'write'. ++ */ ++ if( wantflag & VM_READ ){ ++ max_event = DM_EVENT_READ; ++ } ++ else if( ! (vma->vm_flags & VM_DENYWRITE) ) { ++ if((wantflag & VM_WRITE) || (vma->vm_flags & VM_WRITE)) ++ max_event = DM_EVENT_WRITE; ++ } ++ ++ if( (wantflag & VM_WRITE) && (max_event != DM_EVENT_WRITE) ){ ++ return -EACCES; ++ } ++ ++ /* Figure out how much of the file is being requested by the user. */ ++ offset = 0; /* beginning of file, for now */ ++ length = 0; /* whole file, for now */ ++ ++ filesize = ip->i_new_size; ++ if (filesize < ip->i_size) { ++ filesize = ip->i_size; ++ } ++ ++ /* Set first byte number beyond the map area. */ ++ ++ if (length) { ++ end_of_area = offset + length; ++ if (end_of_area > filesize) ++ end_of_area = filesize; ++ } else { ++ end_of_area = filesize; ++ } ++ ++ /* Set the real amount being mapped. */ ++ evsize = end_of_area - offset; ++ if (evsize < 0) ++ evsize = 0; ++ ++ if (max_event == DM_EVENT_READ) ++ iolock = XFS_IOLOCK_SHARED; ++ else ++ iolock = XFS_IOLOCK_EXCL; ++ ++ xfs_ilock(ip, iolock); ++ /* If write possible, try a DMAPI write event */ ++ if (max_event == DM_EVENT_WRITE && DM_EVENT_ENABLED(ip, max_event)) { ++ error = xfs_dm_send_data_event(max_event, ip, offset, ++ evsize, 0, &iolock); ++ goto out_unlock; ++ } ++ ++ /* Try a read event if max_event was != DM_EVENT_WRITE or if it ++ * was DM_EVENT_WRITE but the WRITE event was not enabled. ++ */ ++ if (DM_EVENT_ENABLED(ip, DM_EVENT_READ)) { ++ error = xfs_dm_send_data_event(DM_EVENT_READ, ip, offset, ++ evsize, 0, &iolock); ++ } ++out_unlock: ++ xfs_iunlock(ip, iolock); ++ return -error; ++} ++ ++ ++STATIC int ++xfs_dm_send_destroy_event( ++ xfs_inode_t *ip, ++ dm_right_t vp_right) /* always DM_RIGHT_NULL */ ++{ ++ /* Returns positive errors to XFS */ ++ return -dm_send_destroy_event(ip->i_vnode, vp_right); ++} ++ ++ ++STATIC int ++xfs_dm_send_namesp_event( ++ dm_eventtype_t event, ++ struct xfs_mount *mp, ++ xfs_inode_t *ip1, ++ dm_right_t vp1_right, ++ xfs_inode_t *ip2, ++ dm_right_t vp2_right, ++ const char *name1, ++ const char *name2, ++ mode_t mode, ++ int retcode, ++ int flags) ++{ ++ /* Returns positive errors to XFS */ ++ return -dm_send_namesp_event(event, mp ? mp->m_super : NULL, ++ ip1->i_vnode, vp1_right, ++ ip2 ? ip2->i_vnode : NULL, vp2_right, ++ name1, name2, ++ mode, retcode, flags); ++} ++ ++STATIC int ++xfs_dm_send_mount_event( ++ struct xfs_mount *mp, ++ dm_right_t root_right, ++ char *mtpt, ++ char *fsname) ++{ ++ return dm_send_mount_event(mp->m_super, root_right, ++ NULL, DM_RIGHT_NULL, ++ mp->m_rootip ? VFS_I(mp->m_rootip) : NULL, ++ DM_RIGHT_NULL, mtpt, fsname); ++} ++ ++STATIC void ++xfs_dm_send_unmount_event( ++ struct xfs_mount *mp, ++ xfs_inode_t *ip, /* NULL if unmount successful */ ++ dm_right_t vfsp_right, ++ mode_t mode, ++ int retcode, /* errno, if unmount failed */ ++ int flags) ++{ ++ dm_send_unmount_event(mp->m_super, ip ? ip->i_vnode : NULL, ++ vfsp_right, mode, retcode, flags); ++} ++ ++ ++/* ++ * Data migration operations accessed by the rest of XFS. ++ * When DMAPI support is configured in, this vector is used. ++ */ ++ ++xfs_dmops_t xfs_dmcore_xfs = { ++ .xfs_send_data = xfs_dm_send_data_event, ++ .xfs_send_mmap = xfs_dm_send_mmap_event, ++ .xfs_send_destroy = xfs_dm_send_destroy_event, ++ .xfs_send_namesp = xfs_dm_send_namesp_event, ++ .xfs_send_mount = xfs_dm_send_mount_event, ++ .xfs_send_unmount = xfs_dm_send_unmount_event, ++}; ++EXPORT_SYMBOL(xfs_dmcore_xfs); ++ ++STATIC const struct file_operations * ++xfs_dm_get_invis_ops( ++ struct inode *ip) ++{ ++ return &xfs_invis_file_operations; ++} ++ ++STATIC int ++xfs_dm_fh_to_inode( ++ struct super_block *sb, ++ struct inode **inode, ++ dm_fid_t *dmfid) ++{ ++ xfs_mount_t *mp = XFS_M(sb); ++ xfs_inode_t *ip; ++ xfs_ino_t ino; ++ unsigned int igen; ++ int error; ++ ++ *inode = NULL; ++ ++ if (!dmfid->dm_fid_len) { ++ /* filesystem handle */ ++ *inode = igrab(mp->m_rootip->i_vnode); ++ if (!*inode) ++ return -ENOENT; ++ return 0; ++ } ++ ++ if (dmfid->dm_fid_len != sizeof(*dmfid) - sizeof(dmfid->dm_fid_len)) ++ return -EINVAL; ++ ++ ino = dmfid->dm_fid_ino; ++ igen = dmfid->dm_fid_gen; ++ ++ /* fail requests for ino 0 gracefully. */ ++ if (ino == 0) ++ return -ESTALE; ++ ++ error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); ++ if (error) ++ return -error; ++ if (!ip) ++ return -EIO; ++ ++ if (!ip->i_d.di_mode || ip->i_d.di_gen != igen) { ++ xfs_iput_new(ip, XFS_ILOCK_SHARED); ++ return -ENOENT; ++ } ++ ++ *inode = ip->i_vnode; ++ xfs_iunlock(ip, XFS_ILOCK_SHARED); ++ return 0; ++} ++ ++STATIC int ++xfs_dm_inode_to_fh( ++ struct inode *inode, ++ dm_fid_t *dmfid, ++ dm_fsid_t *dmfsid) ++{ ++ xfs_inode_t *ip = XFS_I(inode); ++ ++ /* Returns negative errors to DMAPI */ ++ ++ if (ip->i_mount->m_fixedfsid == NULL) ++ return -EINVAL; ++ ++ dmfid->dm_fid_len = sizeof(dm_fid_t) - sizeof(dmfid->dm_fid_len); ++ dmfid->dm_fid_pad = 0; ++ /* ++ * use memcpy because the inode is a long long and there's no ++ * assurance that dmfid->dm_fid_ino is properly aligned. ++ */ ++ memcpy(&dmfid->dm_fid_ino, &ip->i_ino, sizeof(dmfid->dm_fid_ino)); ++ dmfid->dm_fid_gen = ip->i_d.di_gen; ++ ++ memcpy(dmfsid, ip->i_mount->m_fixedfsid, sizeof(*dmfsid)); ++ return 0; ++} ++ ++STATIC void ++xfs_dm_get_fsid( ++ struct super_block *sb, ++ dm_fsid_t *fsid) ++{ ++ memcpy(fsid, XFS_M(sb)->m_fixedfsid, sizeof(*fsid)); ++} ++ ++/* ++ * Filesystem operations accessed by the DMAPI core. ++ */ ++static struct filesystem_dmapi_operations xfs_dmapiops = { ++ .get_fsys_vector = xfs_dm_get_dmapiops, ++ .fh_to_inode = xfs_dm_fh_to_inode, ++ .get_invis_ops = xfs_dm_get_invis_ops, ++ .inode_to_fh = xfs_dm_inode_to_fh, ++ .get_fsid = xfs_dm_get_fsid, ++}; ++ ++static int __init ++xfs_dm_init(void) ++{ ++ printk(KERN_INFO "SGI XFS Data Management API subsystem\n"); ++ ++ dmapi_register(&xfs_fs_type, &xfs_dmapiops); ++ return 0; ++} ++ ++static void __exit ++xfs_dm_exit(void) ++{ ++ dmapi_unregister(&xfs_fs_type); ++} ++ ++MODULE_AUTHOR("Silicon Graphics, Inc."); ++MODULE_DESCRIPTION("SGI XFS dmapi subsystem"); ++MODULE_LICENSE("GPL"); ++ ++module_init(xfs_dm_init); ++module_exit(xfs_dm_exit); +Index: linux-2.6.27/fs/xfs/dmapi/xfs_dm.h +=================================================================== +--- /dev/null ++++ linux-2.6.27/fs/xfs/dmapi/xfs_dm.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (c) 2006 Silicon Graphics, Inc. ++ * All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#ifndef __XFS_DM_H__ ++#define __XFS_DM_H__ ++ ++extern struct file_system_type xfs_fs_type; ++ ++#endif /* __XFS_DM_H__ */ +Index: linux-2.6.27/fs/xfs/Makefile +=================================================================== +--- linux-2.6.27.orig/fs/xfs/Makefile ++++ linux-2.6.27/fs/xfs/Makefile +@@ -38,6 +38,8 @@ ifeq ($(CONFIG_XFS_QUOTA),y) + xfs-$(CONFIG_PROC_FS) += quota/xfs_qm_stats.o + endif + ++obj-$(CONFIG_XFS_DMAPI) += dmapi/ ++ + xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o + xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o + xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o +@@ -107,7 +109,8 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \ + xfs_lrw.o \ + xfs_super.o \ + xfs_vnode.o \ +- xfs_xattr.o) ++ xfs_xattr.o \ ++ xfs_ksyms.o) + + # Objects in support/ + xfs-y += $(addprefix support/, \ +Index: linux-2.6.27/fs/xfs/Kconfig +=================================================================== +--- linux-2.6.27.orig/fs/xfs/Kconfig ++++ linux-2.6.27/fs/xfs/Kconfig +@@ -35,6 +35,19 @@ config XFS_QUOTA + with or without the generic quota support enabled (CONFIG_QUOTA) - + they are completely independent subsystems. + ++config XFS_DMAPI ++ tristate "XFS DMAPI support" ++ depends on XFS_FS ++ select DMAPI ++ help ++ The Data Management API is a system interface used to implement ++ the interface defined in the X/Open document: ++ "Systems Management: Data Storage Management (XDSM) API", ++ dated February 1997. This interface is used by hierarchical ++ storage management systems. ++ ++ If unsure, say N. ++ + config XFS_POSIX_ACL + bool "XFS POSIX ACL support" + depends on XFS_FS +Index: linux-2.6.27/fs/xfs/xfs_mount.h +=================================================================== +--- linux-2.6.27.orig/fs/xfs/xfs_mount.h ++++ linux-2.6.27/fs/xfs/xfs_mount.h +@@ -341,6 +341,7 @@ typedef struct xfs_mount { + spinlock_t m_sync_lock; /* work item list lock */ + int m_sync_seq; /* sync thread generation no. */ + wait_queue_head_t m_wait_single_sync_task; ++ struct vfsmount *m_vfsmount; + } xfs_mount_t; + + /* +Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_super.c +=================================================================== +--- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_super.c ++++ linux-2.6.27/fs/xfs/linux-2.6/xfs_super.c +@@ -1835,8 +1835,16 @@ xfs_fs_get_sb( + void *data, + struct vfsmount *mnt) + { +- return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super, ++ int error; ++ ++ error = get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super, + mnt); ++ if (!error) { ++ xfs_mount_t *mp = XFS_M(mnt->mnt_sb); ++ mp->m_vfsmount = mnt; ++ } ++ ++ return error; + } + + static struct super_operations xfs_super_operations = { +@@ -1861,13 +1869,14 @@ static struct quotactl_ops xfs_quotactl_ + .set_xquota = xfs_fs_setxquota, + }; + +-static struct file_system_type xfs_fs_type = { ++struct file_system_type xfs_fs_type = { + .owner = THIS_MODULE, + .name = "xfs", + .get_sb = xfs_fs_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, + }; ++EXPORT_SYMBOL(xfs_fs_type); + + STATIC int __init + xfs_alloc_trace_bufs(void) +Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_file.c +=================================================================== +--- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_file.c ++++ linux-2.6.27/fs/xfs/linux-2.6/xfs_file.c +@@ -43,6 +43,9 @@ + #include + + static struct vm_operations_struct xfs_file_vm_ops; ++#ifdef HAVE_DMAPI ++static struct vm_operations_struct xfs_dmapi_file_vm_ops; ++#endif + + STATIC_INLINE ssize_t + __xfs_file_read( +@@ -204,6 +207,23 @@ xfs_file_fsync( + return -xfs_fsync(XFS_I(dentry->d_inode)); + } + ++#ifdef HAVE_DMAPI ++STATIC int ++xfs_vm_fault( ++ struct vm_area_struct *vma, ++ struct vm_fault *vmf) ++{ ++ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; ++ struct xfs_mount *mp = XFS_M(inode->i_sb); ++ ++ ASSERT_ALWAYS(mp->m_flags & XFS_MOUNT_DMAPI); ++ ++ if (XFS_SEND_MMAP(mp, vma, 0)) ++ return VM_FAULT_SIGBUS; ++ return filemap_fault(vma, vmf); ++} ++#endif /* HAVE_DMAPI */ ++ + /* + * Unfortunately we can't just use the clean and simple readdir implementation + * below, because nfs might call back into ->lookup from the filldir callback +@@ -372,6 +392,11 @@ xfs_file_mmap( + vma->vm_ops = &xfs_file_vm_ops; + vma->vm_flags |= VM_CAN_NONLINEAR | VM_PAGE_MKWRITE2; + ++#ifdef HAVE_DMAPI ++ if (XFS_M(filp->f_path.dentry->d_inode->i_sb)->m_flags & XFS_MOUNT_DMAPI) ++ vma->vm_ops = &xfs_dmapi_file_vm_ops; ++#endif /* HAVE_DMAPI */ ++ + file_accessed(filp); + return 0; + } +@@ -418,6 +443,47 @@ xfs_file_ioctl_invis( + return error; + } + ++#ifdef HAVE_DMAPI ++#ifdef HAVE_VMOP_MPROTECT ++STATIC int ++xfs_vm_mprotect( ++ struct vm_area_struct *vma, ++ unsigned int newflags) ++{ ++ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; ++ struct xfs_mount *mp = XFS_M(inode->i_sb); ++ int error = 0; ++ ++ if (mp->m_flags & XFS_MOUNT_DMAPI) { ++ if ((vma->vm_flags & VM_MAYSHARE) && ++ (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE)) ++ error = XFS_SEND_MMAP(mp, vma, VM_WRITE); ++ } ++ return error; ++} ++#endif /* HAVE_VMOP_MPROTECT */ ++#endif /* HAVE_DMAPI */ ++ ++#ifdef HAVE_FOP_OPEN_EXEC ++/* If the user is attempting to execute a file that is offline then ++ * we have to trigger a DMAPI READ event before the file is marked as busy ++ * otherwise the invisible I/O will not be able to write to the file to bring ++ * it back online. ++ */ ++STATIC int ++xfs_file_open_exec( ++ struct inode *inode) ++{ ++ struct xfs_mount *mp = XFS_M(inode->i_sb); ++ struct xfs_inode *ip = XFS_I(inode); ++ ++ if (unlikely(mp->m_flags & XFS_MOUNT_DMAPI) && ++ DM_EVENT_ENABLED(ip, DM_EVENT_READ)) ++ return -XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL); ++ return 0; ++} ++#endif /* HAVE_FOP_OPEN_EXEC */ ++ + /* + * mmap()d file has taken write protection fault and is being made + * writable. We can set the page state up correctly for a writable +@@ -487,3 +553,13 @@ static struct vm_operations_struct xfs_f + .fault = filemap_fault, + ._pmkw.page_mkwrite2 = xfs_vm_page_mkwrite, + }; ++ ++#ifdef HAVE_DMAPI ++static struct vm_operations_struct xfs_dmapi_file_vm_ops = { ++ .fault = xfs_vm_fault, ++ ._pmkw.page_mkwrite2 = xfs_vm_page_mkwrite, ++#ifdef HAVE_VMOP_MPROTECT ++ .mprotect = xfs_vm_mprotect, ++#endif ++}; ++#endif /* HAVE_DMAPI */ +Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_linux.h +=================================================================== +--- linux-2.6.27.orig/fs/xfs/linux-2.6/xfs_linux.h ++++ linux-2.6.27/fs/xfs/linux-2.6/xfs_linux.h +@@ -180,6 +180,10 @@ + #define xfs_itruncate_data(ip, off) \ + (-vmtruncate(VFS_I(ip), (off))) + ++#undef HAVE_DMAPI ++#if defined(CONFIG_XFS_DMAPI) || defined(CONFIG_XFS_DMAPI_MODULE) ++#define HAVE_DMAPI ++#endif + + /* Move the kernel do_div definition off to one side */ + +Index: linux-2.6.27/fs/xfs/xfs_dmops.c +=================================================================== +--- linux-2.6.27.orig/fs/xfs/xfs_dmops.c ++++ linux-2.6.27/fs/xfs/xfs_dmops.c +@@ -41,9 +41,21 @@ int + xfs_dmops_get(struct xfs_mount *mp, struct xfs_mount_args *args) + { + if (args->flags & XFSMNT_DMAPI) { +- cmn_err(CE_WARN, +- "XFS: dmapi support not available in this kernel."); +- return EINVAL; ++ struct xfs_dmops *ops; ++ ++ ops = symbol_get(xfs_dmcore_xfs); ++ if (!ops) { ++ request_module("xfs_dmapi"); ++ ops = symbol_get(xfs_dmcore_xfs); ++ } ++ ++ if (!ops) { ++ cmn_err(CE_WARN, "XFS: no dmapi support available."); ++ return EINVAL; ++ } ++ mp->m_dm_ops = ops; ++ } else { ++ mp->m_dm_ops = &xfs_dmcore_stub; + } + + mp->m_dm_ops = &xfs_dmcore_stub; +@@ -53,4 +65,6 @@ xfs_dmops_get(struct xfs_mount *mp, stru + void + xfs_dmops_put(struct xfs_mount *mp) + { ++ if (mp->m_dm_ops != &xfs_dmcore_stub) ++ symbol_put(xfs_dmcore_xfs); + } +Index: linux-2.6.27/fs/xfs/linux-2.6/xfs_ksyms.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/fs/xfs/linux-2.6/xfs_ksyms.c +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (c) 2004-2008 Silicon Graphics, Inc. ++ * All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include "xfs.h" ++#include "xfs_fs.h" ++#include "xfs_bit.h" ++#include "xfs_buf.h" ++#include "xfs_log.h" ++#include "xfs_imap.h" ++#include "xfs_inum.h" ++#include "xfs_clnt.h" ++#include "xfs_trans.h" ++#include "xfs_sb.h" ++#include "xfs_ag.h" ++#include "xfs_dir2.h" ++#include "xfs_alloc.h" ++#include "xfs_dmapi.h" ++#include "xfs_quota.h" ++#include "xfs_mount.h" ++#include "xfs_da_btree.h" ++#include "xfs_bmap_btree.h" ++#include "xfs_alloc_btree.h" ++#include "xfs_ialloc_btree.h" ++#include "xfs_dir2_sf.h" ++#include "xfs_attr_sf.h" ++#include "xfs_dinode.h" ++#include "xfs_inode.h" ++#include "xfs_btree.h" ++#include "xfs_ialloc.h" ++#include "xfs_bmap.h" ++#include "xfs_rtalloc.h" ++#include "xfs_error.h" ++#include "xfs_itable.h" ++#include "xfs_rw.h" ++#include "xfs_dir2_data.h" ++#include "xfs_dir2_leaf.h" ++#include "xfs_dir2_block.h" ++#include "xfs_dir2_node.h" ++#include "xfs_dir2_trace.h" ++#include "xfs_acl.h" ++#include "xfs_attr.h" ++#include "xfs_attr_leaf.h" ++#include "xfs_inode_item.h" ++#include "xfs_buf_item.h" ++#include "xfs_extfree_item.h" ++#include "xfs_log_priv.h" ++#include "xfs_trans_priv.h" ++#include "xfs_trans_space.h" ++#include "xfs_utils.h" ++#include "xfs_iomap.h" ++#include "xfs_filestream.h" ++#include "xfs_vnodeops.h" ++#include "xfs_vfsops.h" ++#include "support/ktrace.h" ++ ++EXPORT_SYMBOL(xfs_iunlock); ++EXPORT_SYMBOL(xfs_invis_file_operations); ++EXPORT_SYMBOL(xfs_attr_remove); ++EXPORT_SYMBOL(xfs_iunlock_map_shared); ++EXPORT_SYMBOL(xfs_iget); ++EXPORT_SYMBOL(xfs_bmapi); ++EXPORT_SYMBOL(xfs_internal_inum); ++EXPORT_SYMBOL(sys_cred); ++EXPORT_SYMBOL(xfs_attr_set); ++EXPORT_SYMBOL(xfs_trans_reserve); ++EXPORT_SYMBOL(xfs_trans_ijoin); ++EXPORT_SYMBOL(xfs_free_eofblocks); ++EXPORT_SYMBOL(kmem_free); ++EXPORT_SYMBOL(_xfs_trans_commit); ++EXPORT_SYMBOL(xfs_ilock); ++EXPORT_SYMBOL(xfs_attr_get); ++EXPORT_SYMBOL(xfs_readdir); ++EXPORT_SYMBOL(xfs_setattr); ++EXPORT_SYMBOL(xfs_trans_alloc); ++EXPORT_SYMBOL(xfs_trans_cancel); ++EXPORT_SYMBOL(xfs_fsync); ++EXPORT_SYMBOL(xfs_iput_new); ++EXPORT_SYMBOL(xfs_bulkstat); ++EXPORT_SYMBOL(xfs_ilock_map_shared); ++EXPORT_SYMBOL(xfs_iput); ++EXPORT_SYMBOL(xfs_trans_log_inode); ++EXPORT_SYMBOL(xfs_attr_list); ++EXPORT_SYMBOL(kmem_alloc); ++EXPORT_SYMBOL(xfs_change_file_space); diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-handle-memory-allocation-failures-during-log-initialisation b/src/patches/suse-2.6.27.31/patches.suse/xfs-handle-memory-allocation-failures-during-log-initialisation new file mode 100644 index 000000000..2ac69a8ee --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-handle-memory-allocation-failures-during-log-initialisation @@ -0,0 +1,116 @@ +From: Dave Chinner +Subject: [XFS] handle memory allocation failures during log initialisation +References: bnc#450658 +Patch-mainline: ? + +When there is no memory left in the system, xfs_buf_get_noaddr() +can fail. If this happens at mount time during xlog_alloc_log() +we fail to catch the error and oops. + +Catch the error from xfs_buf_get_noaddr(), and allow other memory +allocations to fail and catch those errors too. Report the error +to the console and fail the mount with ENOMEM. + +Tested by manually injecting errors into xfs_buf_get_noaddr() and +xlog_alloc_log(). + +Version 2: +o remove unnecessary casts of the returned pointer from kmem_zalloc() + +SGI-PV: 987246 + +Signed-off-by: Dave Chinner +Reviewed-by: Christoph Hellwig +Signed-off-by: Lachlan McIlroy +Acked-by: Jan Kara + +diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c +index 5184017..92c20a8 100644 +--- a/fs/xfs/xfs_log.c ++++ b/fs/xfs/xfs_log.c +@@ -563,6 +563,11 @@ xfs_log_mount( + } + + mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); ++ if (!mp->m_log) { ++ cmn_err(CE_WARN, "XFS: Log allocation failed: No memory!"); ++ error = ENOMEM; ++ goto out; ++ } + + /* + * Initialize the AIL now we have a log. +@@ -601,6 +606,7 @@ xfs_log_mount( + return 0; + error: + xfs_log_unmount_dealloc(mp); ++out: + return error; + } /* xfs_log_mount */ + +@@ -1217,7 +1223,9 @@ xlog_alloc_log(xfs_mount_t *mp, + int i; + int iclogsize; + +- log = (xlog_t *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP); ++ log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL); ++ if (!log) ++ return NULL; + + log->l_mp = mp; + log->l_targ = log_target; +@@ -1249,6 +1257,8 @@ xlog_alloc_log(xfs_mount_t *mp, + xlog_get_iclog_buffer_size(mp, log); + + bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp); ++ if (!bp) ++ goto out_free_log; + XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); +@@ -1275,13 +1285,17 @@ xlog_alloc_log(xfs_mount_t *mp, + iclogsize = log->l_iclog_size; + ASSERT(log->l_iclog_size >= 4096); + for (i=0; i < log->l_iclog_bufs; i++) { +- *iclogp = (xlog_in_core_t *) +- kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); ++ *iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL); ++ if (!*iclogp) ++ goto out_free_iclog; ++ + iclog = *iclogp; + iclog->ic_prev = prev_iclog; + prev_iclog = iclog; + + bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp); ++ if (!bp) ++ goto out_free_iclog; + if (!XFS_BUF_CPSEMA(bp)) + ASSERT(0); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); +@@ -1323,6 +1337,25 @@ xlog_alloc_log(xfs_mount_t *mp, + log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ + + return log; ++ ++out_free_iclog: ++ for (iclog = log->l_iclog; iclog; iclog = prev_iclog) { ++ prev_iclog = iclog->ic_next; ++ if (iclog->ic_bp) { ++ sv_destroy(&iclog->ic_force_wait); ++ sv_destroy(&iclog->ic_write_wait); ++ xfs_buf_free(iclog->ic_bp); ++ xlog_trace_iclog_dealloc(iclog); ++ } ++ kmem_free(iclog); ++ } ++ spinlock_destroy(&log->l_icloglock); ++ spinlock_destroy(&log->l_grant_lock); ++ xlog_trace_loggrant_dealloc(log); ++ xfs_buf_free(log->l_xbuf); ++out_free_log: ++ kmem_free(log); ++ return NULL; + } /* xlog_alloc_log */ + + diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-nfsd-dmapi-aware b/src/patches/suse-2.6.27.31/patches.suse/xfs-nfsd-dmapi-aware new file mode 100644 index 000000000..253bdf2b9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-nfsd-dmapi-aware @@ -0,0 +1,181 @@ +From: Greg Banks +Subject: Make NFSD DMAPI aware +References: 74107, 173874, bnc#450658 +Patch-mainline: obstruction... + +G'day, + +The NFSv3 protocol specifies an error, NFS3ERR_JUKEBOX, which a server +should return when an I/O operation will take a very long time. +This causes a different pattern of retries in clients, and avoids +a number of serious problems associated with I/Os which take longer +than an RPC timeout. The Linux knfsd server has code to generate the +jukebox error and many NFS clients are known to have working code to +handle it. + +One scenario in which a server should emit the JUKEBOX error is when +a file data which the client is attempting to access is managed by +an HSM (Hierarchical Storage Manager) and is not present on the disk +and needs to be brought in from tape. Due to the nature of tapes this +operation can take minutes rather than the milliseconds normally seen +for local file data. + +Currently the Linux knfsd handles this situation poorly. A READ NFS +call will cause the nfsd thread handling it to block until the file +is available, without sending a reply to the NFS client. After a +few seconds the client retries, and this second READ call causes +another nfsd to block behind the first one. A few seconds later and +the client's retries have blocked *all* the nfsd threads, and all NFS +service from the server stops until the original file arrives on disk. + +WRITEs and SETATTRs which truncate the file are marginally better, in +that the knfsd dupcache will catch the retries and drop them without +blocking an nfsd (the dupcache *will* catch the retries because the +cache entry remains in RC_INPROG state and is not reused until the +first call finishes). However the first call still blocks, so given +WRITEs to enough offline files the server can still be locked up. + +There are also client-side implications, depending on the client +implementation. For example, on a Linux client an RPC retry loop uses +an RPC request slot, so reads from enough separate offline files can +lock up a mountpoint. + +This patch seeks to remedy the interaction between knfsd and HSMs by +providing mechanisms to allow knfsd to tell an underlying filesystem +(which supports HSMs) not to block for reads, writes and truncates +of offline files. It's a port of a Linux 2.4 patch used in SGI's +ProPack distro for the last 12 months. The patch: + +* provides a new ATTR_NO_BLOCK flag which the kernel can + use to tell a filesystem's inode_ops->setattr() operation not + to block when truncating an offline file. XFS already obeys + this flag (inside a #ifdef) + +* changes knfsd to provide ATTR_NO_BLOCK when it does the VFS + calls to implement the SETATTR NFS call. + +* changes knfsd to supply the O_NONBLOCK flag in the temporary + struct file it uses for VFS reads and writes, in order to ask + the filesystem not to block when reading or writing an offline + file. XFS already obeys this new semantic for O_NONBLOCK + (and in SLES9 so does JFS). + +* adds code to translate the -EAGAIN the filesystem returns when + it would have blocked, to the -ETIMEDOUT that knfsd expects. + + +Signed-off-by: Greg Banks +(SLES9 patch Acked-by: okir@suse.de) +Signed-off-by: NeilBrown +Acked-by: Jan Kara + + fs/nfsd/vfs.c | 32 ++++++++++++++++++++++++++++++-- + fs/xfs/linux-2.6/xfs_iops.c | 7 ++++++- + include/linux/fs.h | 1 + + 3 files changed, 37 insertions(+), 3 deletions(-) + + +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -358,6 +358,15 @@ nfsd_setattr(struct svc_rqst *rqstp, str + goto out_nfserr; + } + DQUOT_INIT(inode); ++ ++ /* ++ * Tell a Hierarchical Storage Manager (e.g. via DMAPI) to ++ * return EAGAIN when an action would take minutes instead of ++ * milliseconds so that NFS can reply to the client with ++ * NFSERR_JUKEBOX instead of blocking an nfsd thread. ++ */ ++ if (rqstp->rq_vers >= 3) ++ iap->ia_valid |= ATTR_NO_BLOCK; + } + + /* sanitize the mode change */ +@@ -389,6 +398,9 @@ nfsd_setattr(struct svc_rqst *rqstp, str + if (!check_guard || guardtime == inode->i_ctime.tv_sec) { + fh_lock(fhp); + host_err = notify_change(dentry, iap); ++ /* to get NFSERR_JUKEBOX on the wire, need -ETIMEDOUT */ ++ if (host_err == -EAGAIN) ++ host_err = -ETIMEDOUT; + err = nfserrno(host_err); + fh_unlock(fhp); + } +@@ -906,6 +918,10 @@ nfsd_vfs_read(struct svc_rqst *rqstp, st + if (ra && ra->p_set) + file->f_ra = ra->p_ra; + ++ /* Support HSMs -- see comment in nfsd_setattr() */ ++ if (rqstp->rq_vers >= 3) ++ file->f_flags |= O_NONBLOCK; ++ + if (file->f_op->splice_read && rqstp->rq_splice_ok) { + struct splice_desc sd = { + .len = 0, +@@ -938,8 +954,12 @@ nfsd_vfs_read(struct svc_rqst *rqstp, st + *count = host_err; + err = 0; + fsnotify_access(file->f_path.dentry); +- } else ++ } else { ++ /* to get NFSERR_JUKEBOX on the wire, need -ETIMEDOUT */ ++ if (host_err == -EAGAIN) ++ host_err = -ETIMEDOUT; + err = nfserrno(host_err); ++ } + out: + return err; + } +@@ -998,6 +1018,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s + if (stable && !EX_WGATHER(exp)) + file->f_flags |= O_SYNC; + ++ /* Support HSMs -- see comment in nfsd_setattr() */ ++ if (rqstp->rq_vers >= 3) ++ file->f_flags |= O_NONBLOCK; ++ + /* Write the data. */ + oldfs = get_fs(); set_fs(KERNEL_DS); + host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); +@@ -1050,8 +1074,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s + dprintk("nfsd: write complete host_err=%d\n", host_err); + if (host_err >= 0) + err = 0; +- else ++ else { ++ /* to get NFSERR_JUKEBOX on the wire, need -ETIMEDOUT */ ++ if (host_err == -EAGAIN) ++ host_err = -ETIMEDOUT; + err = nfserrno(host_err); ++ } + out: + return err; + } +--- a/fs/xfs/linux-2.6/xfs_iops.c ++++ b/fs/xfs/linux-2.6/xfs_iops.c +@@ -601,7 +601,12 @@ xfs_vn_setattr( + struct dentry *dentry, + struct iattr *iattr) + { +- return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL); ++ int flags = 0; ++#ifdef ATTR_NO_BLOCK ++ if (iattr->ia_valid & ATTR_NO_BLOCK) ++ flags |= O_NONBLOCK; ++#endif ++ return -xfs_setattr(XFS_I(dentry->d_inode), iattr, flags, NULL); + } + + /* +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -342,6 +342,7 @@ typedef void (dio_iodone_t)(struct kiocb + #define ATTR_KILL_PRIV (1 << 14) + #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ + #define ATTR_TIMES_SET (1 << 16) ++#define ATTR_NO_BLOCK (1 << 17) /* Return EAGAIN and don't block on long truncates */ + + /* + * This is the Inode Attributes structure, used for notify_change(). It diff --git a/src/patches/suse-2.6.27.31/patches.suse/xfs-wait-for-all-IO-on-truncate-to-zero b/src/patches/suse-2.6.27.31/patches.suse/xfs-wait-for-all-IO-on-truncate-to-zero new file mode 100644 index 000000000..7b3c8a518 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.suse/xfs-wait-for-all-IO-on-truncate-to-zero @@ -0,0 +1,39 @@ +From: Lachlan McIlroy +Subject: [XFS] Wait for all I/O on truncate to zero file size +Patch-mainline: ? +References: bnc#450658 + +It's possible to have outstanding xfs_ioend_t's queued when the file size +is zero. This can happen in the direct I/O path when a direct I/O write +fails due to ENOSPC. In this case the xfs_ioend_t will still be queued (ie +xfs_end_io_direct() does not know that the I/O failed so can't force the +xfs_ioend_t to be flushed synchronously). + +When we truncate a file on unlink we don't know to wait for these +xfs_ioend_ts and we can have a use-after-free situation if the inode is +reclaimed before the xfs_ioend_t is finally processed. + +As was suggested by Dave Chinner lets wait for all I/Os to complete when +truncating the file size to zero. + +SGI-PV: 981668 + +SGI-Modid: xfs-linux-melb:xfs-kern:32216a + +Signed-off-by: Lachlan McIlroy +Signed-off-by: Christoph Hellwig +Acked-by: Jan Kara + +Index: linux-2.6.27.5-2/fs/xfs/xfs_inode.c +=================================================================== +--- linux-2.6.27.5-2.orig/fs/xfs/xfs_inode.c 2008-12-03 11:58:00.992733026 +1100 ++++ linux-2.6.27.5-2/fs/xfs/xfs_inode.c 2008-12-03 11:59:17.542975042 +1100 +@@ -1414,7 +1414,7 @@ xfs_itruncate_start( + mp = ip->i_mount; + + /* wait for the completion of any pending DIOs */ +- if (new_size < ip->i_size) ++ if (new_size == 0 || new_size < ip->i_size) + vn_iowait(ip); + + /* diff --git a/src/patches/suse-2.6.27.31/patches.trace/ftrace-port-to-tracepoints.patch b/src/patches/suse-2.6.27.31/patches.trace/ftrace-port-to-tracepoints.patch new file mode 100644 index 000000000..9c84d742b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/ftrace-port-to-tracepoints.patch @@ -0,0 +1,491 @@ +From: Mathieu Desnoyers +Subject: ftrace port to tracepoints + +Porting the trace_mark() used by ftrace to tracepoints. (cleanup) + +Changelog : +- Change error messages : marker -> tracepoint + +Signed-off-by: Mathieu Desnoyers +CC: Masami Hiramatsu +CC: 'Peter Zijlstra' +CC: "Frank Ch. Eigler" +CC: 'Ingo Molnar' +CC: 'Hideo AOKI' +CC: Takashi Nishiie +CC: 'Steven Rostedt' +CC: Eduard - Gabriel Munteanu +Acked-by: Jan Blunck +--- + kernel/trace/trace_sched_switch.c | 120 ++++++--------------------------- + kernel/trace/trace_sched_wakeup.c | 135 +++++++++----------------------------- + 2 files changed, 58 insertions(+), 197 deletions(-) + +Index: linux-2.6-lttng/kernel/trace/trace_sched_switch.c +=================================================================== +--- linux-2.6-lttng.orig/kernel/trace/trace_sched_switch.c 2008-08-06 00:41:47.000000000 -0400 ++++ linux-2.6-lttng/kernel/trace/trace_sched_switch.c 2008-08-06 13:12:10.000000000 -0400 +@@ -9,8 +9,8 @@ + #include + #include + #include +-#include + #include ++#include + + #include "trace.h" + +@@ -19,16 +19,17 @@ static int __read_mostly tracer_enabled; + static atomic_t sched_ref; + + static void +-sched_switch_func(void *private, void *__rq, struct task_struct *prev, ++probe_sched_switch(struct rq *__rq, struct task_struct *prev, + struct task_struct *next) + { +- struct trace_array **ptr = private; +- struct trace_array *tr = *ptr; + struct trace_array_cpu *data; + unsigned long flags; + long disabled; + int cpu; + ++ if (!atomic_read(&sched_ref)) ++ return; ++ + tracing_record_cmdline(prev); + tracing_record_cmdline(next); + +@@ -37,95 +38,42 @@ sched_switch_func(void *private, void *_ + + local_irq_save(flags); + cpu = raw_smp_processor_id(); +- data = tr->data[cpu]; ++ data = ctx_trace->data[cpu]; + disabled = atomic_inc_return(&data->disabled); + + if (likely(disabled == 1)) +- tracing_sched_switch_trace(tr, data, prev, next, flags); ++ tracing_sched_switch_trace(ctx_trace, data, prev, next, flags); + + atomic_dec(&data->disabled); + local_irq_restore(flags); + } + +-static notrace void +-sched_switch_callback(void *probe_data, void *call_data, +- const char *format, va_list *args) +-{ +- struct task_struct *prev; +- struct task_struct *next; +- struct rq *__rq; +- +- if (!atomic_read(&sched_ref)) +- return; +- +- /* skip prev_pid %d next_pid %d prev_state %ld */ +- (void)va_arg(*args, int); +- (void)va_arg(*args, int); +- (void)va_arg(*args, long); +- __rq = va_arg(*args, typeof(__rq)); +- prev = va_arg(*args, typeof(prev)); +- next = va_arg(*args, typeof(next)); +- +- /* +- * If tracer_switch_func only points to the local +- * switch func, it still needs the ptr passed to it. +- */ +- sched_switch_func(probe_data, __rq, prev, next); +-} +- + static void +-wakeup_func(void *private, void *__rq, struct task_struct *wakee, struct +- task_struct *curr) ++probe_sched_wakeup(struct rq *__rq, struct task_struct *wakee) + { +- struct trace_array **ptr = private; +- struct trace_array *tr = *ptr; + struct trace_array_cpu *data; + unsigned long flags; + long disabled; + int cpu; + +- if (!tracer_enabled) ++ if (!likely(tracer_enabled)) + return; + +- tracing_record_cmdline(curr); ++ tracing_record_cmdline(current); + + local_irq_save(flags); + cpu = raw_smp_processor_id(); +- data = tr->data[cpu]; ++ data = ctx_trace->data[cpu]; + disabled = atomic_inc_return(&data->disabled); + + if (likely(disabled == 1)) +- tracing_sched_wakeup_trace(tr, data, wakee, curr, flags); ++ tracing_sched_wakeup_trace(ctx_trace, data, wakee, current, ++ flags); + + atomic_dec(&data->disabled); + local_irq_restore(flags); + } + +-static notrace void +-wake_up_callback(void *probe_data, void *call_data, +- const char *format, va_list *args) +-{ +- struct task_struct *curr; +- struct task_struct *task; +- struct rq *__rq; +- +- if (likely(!tracer_enabled)) +- return; +- +- /* Skip pid %d state %ld */ +- (void)va_arg(*args, int); +- (void)va_arg(*args, long); +- /* now get the meat: "rq %p task %p rq->curr %p" */ +- __rq = va_arg(*args, typeof(__rq)); +- task = va_arg(*args, typeof(task)); +- curr = va_arg(*args, typeof(curr)); +- +- tracing_record_cmdline(task); +- tracing_record_cmdline(curr); +- +- wakeup_func(probe_data, __rq, task, curr); +-} +- + static void sched_switch_reset(struct trace_array *tr) + { + int cpu; +@@ -140,60 +88,40 @@ static int tracing_sched_register(void) + { + int ret; + +- ret = marker_probe_register("kernel_sched_wakeup", +- "pid %d state %ld ## rq %p task %p rq->curr %p", +- wake_up_callback, +- &ctx_trace); ++ ret = register_trace_sched_wakeup(probe_sched_wakeup); + if (ret) { +- pr_info("wakeup trace: Couldn't add marker" ++ pr_info("wakeup trace: Couldn't activate tracepoint" + " probe to kernel_sched_wakeup\n"); + return ret; + } + +- ret = marker_probe_register("kernel_sched_wakeup_new", +- "pid %d state %ld ## rq %p task %p rq->curr %p", +- wake_up_callback, +- &ctx_trace); ++ ret = register_trace_sched_wakeup_new(probe_sched_wakeup); + if (ret) { +- pr_info("wakeup trace: Couldn't add marker" ++ pr_info("wakeup trace: Couldn't activate tracepoint" + " probe to kernel_sched_wakeup_new\n"); + goto fail_deprobe; + } + +- ret = marker_probe_register("kernel_sched_schedule", +- "prev_pid %d next_pid %d prev_state %ld " +- "## rq %p prev %p next %p", +- sched_switch_callback, +- &ctx_trace); ++ ret = register_trace_sched_switch(probe_sched_switch); + if (ret) { +- pr_info("sched trace: Couldn't add marker" ++ pr_info("sched trace: Couldn't activate tracepoint" + " probe to kernel_sched_schedule\n"); + goto fail_deprobe_wake_new; + } + + return ret; + fail_deprobe_wake_new: +- marker_probe_unregister("kernel_sched_wakeup_new", +- wake_up_callback, +- &ctx_trace); ++ unregister_trace_sched_wakeup_new(probe_sched_wakeup); + fail_deprobe: +- marker_probe_unregister("kernel_sched_wakeup", +- wake_up_callback, +- &ctx_trace); ++ unregister_trace_sched_wakeup(probe_sched_wakeup); + return ret; + } + + static void tracing_sched_unregister(void) + { +- marker_probe_unregister("kernel_sched_schedule", +- sched_switch_callback, +- &ctx_trace); +- marker_probe_unregister("kernel_sched_wakeup_new", +- wake_up_callback, +- &ctx_trace); +- marker_probe_unregister("kernel_sched_wakeup", +- wake_up_callback, +- &ctx_trace); ++ unregister_trace_sched_switch(probe_sched_switch); ++ unregister_trace_sched_wakeup_new(probe_sched_wakeup); ++ unregister_trace_sched_wakeup(probe_sched_wakeup); + } + + static void tracing_start_sched_switch(void) +Index: linux-2.6-lttng/kernel/trace/trace_sched_wakeup.c +=================================================================== +--- linux-2.6-lttng.orig/kernel/trace/trace_sched_wakeup.c 2008-08-06 00:41:47.000000000 -0400 ++++ linux-2.6-lttng/kernel/trace/trace_sched_wakeup.c 2008-08-06 13:18:26.000000000 -0400 +@@ -15,7 +15,7 @@ + #include + #include + #include +-#include ++#include + + #include "trace.h" + +@@ -112,18 +112,18 @@ static int report_latency(cycle_t delta) + } + + static void notrace +-wakeup_sched_switch(void *private, void *rq, struct task_struct *prev, ++probe_wakeup_sched_switch(struct rq *rq, struct task_struct *prev, + struct task_struct *next) + { + unsigned long latency = 0, t0 = 0, t1 = 0; +- struct trace_array **ptr = private; +- struct trace_array *tr = *ptr; + struct trace_array_cpu *data; + cycle_t T0, T1, delta; + unsigned long flags; + long disabled; + int cpu; + ++ tracing_record_cmdline(prev); ++ + if (unlikely(!tracer_enabled)) + return; + +@@ -140,11 +140,11 @@ wakeup_sched_switch(void *private, void + return; + + /* The task we are waiting for is waking up */ +- data = tr->data[wakeup_cpu]; ++ data = wakeup_trace->data[wakeup_cpu]; + + /* disable local data, not wakeup_cpu data */ + cpu = raw_smp_processor_id(); +- disabled = atomic_inc_return(&tr->data[cpu]->disabled); ++ disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled); + if (likely(disabled != 1)) + goto out; + +@@ -155,7 +155,7 @@ wakeup_sched_switch(void *private, void + if (unlikely(!tracer_enabled || next != wakeup_task)) + goto out_unlock; + +- trace_function(tr, data, CALLER_ADDR1, CALLER_ADDR2, flags); ++ trace_function(wakeup_trace, data, CALLER_ADDR1, CALLER_ADDR2, flags); + + /* + * usecs conversion is slow so we try to delay the conversion +@@ -174,39 +174,14 @@ wakeup_sched_switch(void *private, void + t0 = nsecs_to_usecs(T0); + t1 = nsecs_to_usecs(T1); + +- update_max_tr(tr, wakeup_task, wakeup_cpu); ++ update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu); + + out_unlock: +- __wakeup_reset(tr); ++ __wakeup_reset(wakeup_trace); + __raw_spin_unlock(&wakeup_lock); + local_irq_restore(flags); + out: +- atomic_dec(&tr->data[cpu]->disabled); +-} +- +-static notrace void +-sched_switch_callback(void *probe_data, void *call_data, +- const char *format, va_list *args) +-{ +- struct task_struct *prev; +- struct task_struct *next; +- struct rq *__rq; +- +- /* skip prev_pid %d next_pid %d prev_state %ld */ +- (void)va_arg(*args, int); +- (void)va_arg(*args, int); +- (void)va_arg(*args, long); +- __rq = va_arg(*args, typeof(__rq)); +- prev = va_arg(*args, typeof(prev)); +- next = va_arg(*args, typeof(next)); +- +- tracing_record_cmdline(prev); +- +- /* +- * If tracer_switch_func only points to the local +- * switch func, it still needs the ptr passed to it. +- */ +- wakeup_sched_switch(probe_data, __rq, prev, next); ++ atomic_dec(&wakeup_trace->data[cpu]->disabled); + } + + static void __wakeup_reset(struct trace_array *tr) +@@ -240,19 +215,24 @@ static void wakeup_reset(struct trace_ar + } + + static void +-wakeup_check_start(struct trace_array *tr, struct task_struct *p, +- struct task_struct *curr) ++probe_wakeup(struct rq *rq, struct task_struct *p) + { + int cpu = smp_processor_id(); + unsigned long flags; + long disabled; + ++ if (likely(!tracer_enabled)) ++ return; ++ ++ tracing_record_cmdline(p); ++ tracing_record_cmdline(current); ++ + if (likely(!rt_task(p)) || + p->prio >= wakeup_prio || +- p->prio >= curr->prio) ++ p->prio >= current->prio) + return; + +- disabled = atomic_inc_return(&tr->data[cpu]->disabled); ++ disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled); + if (unlikely(disabled != 1)) + goto out; + +@@ -264,7 +244,7 @@ wakeup_check_start(struct trace_array *t + goto out_locked; + + /* reset the trace */ +- __wakeup_reset(tr); ++ __wakeup_reset(wakeup_trace); + + wakeup_cpu = task_cpu(p); + wakeup_prio = p->prio; +@@ -274,74 +254,37 @@ wakeup_check_start(struct trace_array *t + + local_save_flags(flags); + +- tr->data[wakeup_cpu]->preempt_timestamp = ftrace_now(cpu); +- trace_function(tr, tr->data[wakeup_cpu], ++ wakeup_trace->data[wakeup_cpu]->preempt_timestamp = ftrace_now(cpu); ++ trace_function(wakeup_trace, wakeup_trace->data[wakeup_cpu], + CALLER_ADDR1, CALLER_ADDR2, flags); + + out_locked: + __raw_spin_unlock(&wakeup_lock); + out: +- atomic_dec(&tr->data[cpu]->disabled); +-} +- +-static notrace void +-wake_up_callback(void *probe_data, void *call_data, +- const char *format, va_list *args) +-{ +- struct trace_array **ptr = probe_data; +- struct trace_array *tr = *ptr; +- struct task_struct *curr; +- struct task_struct *task; +- struct rq *__rq; +- +- if (likely(!tracer_enabled)) +- return; +- +- /* Skip pid %d state %ld */ +- (void)va_arg(*args, int); +- (void)va_arg(*args, long); +- /* now get the meat: "rq %p task %p rq->curr %p" */ +- __rq = va_arg(*args, typeof(__rq)); +- task = va_arg(*args, typeof(task)); +- curr = va_arg(*args, typeof(curr)); +- +- tracing_record_cmdline(task); +- tracing_record_cmdline(curr); +- +- wakeup_check_start(tr, task, curr); ++ atomic_dec(&wakeup_trace->data[cpu]->disabled); + } + + static void start_wakeup_tracer(struct trace_array *tr) + { + int ret; + +- ret = marker_probe_register("kernel_sched_wakeup", +- "pid %d state %ld ## rq %p task %p rq->curr %p", +- wake_up_callback, +- &wakeup_trace); ++ ret = register_trace_sched_wakeup(probe_wakeup); + if (ret) { +- pr_info("wakeup trace: Couldn't add marker" ++ pr_info("wakeup trace: Couldn't activate tracepoint" + " probe to kernel_sched_wakeup\n"); + return; + } + +- ret = marker_probe_register("kernel_sched_wakeup_new", +- "pid %d state %ld ## rq %p task %p rq->curr %p", +- wake_up_callback, +- &wakeup_trace); ++ ret = register_trace_sched_wakeup_new(probe_wakeup); + if (ret) { +- pr_info("wakeup trace: Couldn't add marker" ++ pr_info("wakeup trace: Couldn't activate tracepoint" + " probe to kernel_sched_wakeup_new\n"); + goto fail_deprobe; + } + +- ret = marker_probe_register("kernel_sched_schedule", +- "prev_pid %d next_pid %d prev_state %ld " +- "## rq %p prev %p next %p", +- sched_switch_callback, +- &wakeup_trace); ++ ret = register_trace_sched_switch(probe_wakeup_sched_switch); + if (ret) { +- pr_info("sched trace: Couldn't add marker" ++ pr_info("sched trace: Couldn't activate tracepoint" + " probe to kernel_sched_schedule\n"); + goto fail_deprobe_wake_new; + } +@@ -363,28 +306,18 @@ static void start_wakeup_tracer(struct t + + return; + fail_deprobe_wake_new: +- marker_probe_unregister("kernel_sched_wakeup_new", +- wake_up_callback, +- &wakeup_trace); ++ unregister_trace_sched_wakeup_new(probe_wakeup); + fail_deprobe: +- marker_probe_unregister("kernel_sched_wakeup", +- wake_up_callback, +- &wakeup_trace); ++ unregister_trace_sched_wakeup(probe_wakeup); + } + + static void stop_wakeup_tracer(struct trace_array *tr) + { + tracer_enabled = 0; + unregister_ftrace_function(&trace_ops); +- marker_probe_unregister("kernel_sched_schedule", +- sched_switch_callback, +- &wakeup_trace); +- marker_probe_unregister("kernel_sched_wakeup_new", +- wake_up_callback, +- &wakeup_trace); +- marker_probe_unregister("kernel_sched_wakeup", +- wake_up_callback, +- &wakeup_trace); ++ unregister_trace_sched_switch(probe_wakeup_sched_switch); ++ unregister_trace_sched_wakeup_new(probe_wakeup); ++ unregister_trace_sched_wakeup(probe_wakeup); + } + + static void wakeup_tracer_init(struct trace_array *tr) diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-filemap.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-filemap.patch new file mode 100644 index 000000000..b923d60aa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-filemap.patch @@ -0,0 +1,72 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - filemap + +Original patch header: + LTTng instrumentation - filemap + + Instrumentation of waits caused by memory accesses on mmap regions. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: linux-mm@kvack.org + CC: Dave Hansen + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- + include/trace/filemap.h | 13 +++++++++++++ + mm/filemap.c | 3 +++ + 2 files changed, 16 insertions(+) + +--- /dev/null ++++ b/include/trace/filemap.h +@@ -0,0 +1,13 @@ ++#ifndef _TRACE_FILEMAP_H ++#define _TRACE_FILEMAP_H ++ ++#include ++ ++DEFINE_TRACE(wait_on_page_start, ++ TPPROTO(struct page *page, int bit_nr), ++ TPARGS(page, bit_nr)); ++DEFINE_TRACE(wait_on_page_end, ++ TPPROTO(struct page *page, int bit_nr), ++ TPARGS(page, bit_nr)); ++ ++#endif +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -34,6 +34,7 @@ + #include /* for BUG_ON(!in_atomic()) only */ + #include + #include "internal.h" ++#include + + /* + * FIXME: remove all knowledge of the buffer layer from the core VM +@@ -540,9 +541,11 @@ void wait_on_page_bit(struct page *page, + { + DEFINE_WAIT_BIT(wait, &page->flags, bit_nr); + ++ trace_wait_on_page_start(page, bit_nr); + if (test_bit(bit_nr, &page->flags)) + __wait_on_bit(page_waitqueue(page), &wait, sync_page, + TASK_UNINTERRUPTIBLE); ++ trace_wait_on_page_end(page, bit_nr); + } + EXPORT_SYMBOL(wait_on_page_bit); + diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-fs.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-fs.patch new file mode 100644 index 000000000..20b263f17 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-fs.patch @@ -0,0 +1,345 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - fs + +Original patch header: + LTTng instrumentation - fs + + Core filesystem tracepoints. + + Tracepoints added : + + fs_buffer_wait_end + fs_buffer_wait_start + fs_close + fs_exec + fs_ioctl + fs_llseek + fs_lseek + fs_open + fs_poll + fs_pread64 + fs_pwrite64 + fs_read + fs_readv + fs_select + fs_write + fs_writev + + Instrument the core FS events, extracting the information when it is available. + e.g. the instrumentation of "reads" is inserted _after_ the read, when + the information is ready. This would not be possible if the instrumentation + would be placed elsewhere (at the beginning of the system call for instance). + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Alexander Viro + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + fs/buffer.c | 3 ++ + fs/compat.c | 2 + + fs/exec.c | 2 + + fs/ioctl.c | 3 ++ + fs/open.c | 3 ++ + fs/read_write.c | 19 +++++++++++++-- + fs/select.c | 3 ++ + include/trace/fs.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 8 files changed, 98 insertions(+), 2 deletions(-) + +--- a/fs/buffer.c ++++ b/fs/buffer.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); + +@@ -89,7 +90,9 @@ void unlock_buffer(struct buffer_head *b + */ + void __wait_on_buffer(struct buffer_head * bh) + { ++ trace_fs_buffer_wait_start(bh); + wait_on_bit(&bh->b_state, BH_Lock, sync_buffer, TASK_UNINTERRUPTIBLE); ++ trace_fs_buffer_wait_end(bh); + } + + static void +--- a/fs/compat.c ++++ b/fs/compat.c +@@ -51,6 +51,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1411,6 +1412,7 @@ int compat_do_execve(char * filename, + + retval = search_binary_handler(bprm, regs); + if (retval >= 0) { ++ trace_fs_exec(filename); + /* execve success */ + security_bprm_free(bprm); + acct_update_integrals(current); +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -50,6 +50,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1353,6 +1354,7 @@ int do_execve(char * filename, + current->flags &= ~PF_KTHREAD; + retval = search_binary_handler(bprm,regs); + if (retval >= 0) { ++ trace_fs_exec(filename); + /* execve success */ + security_bprm_free(bprm); + acct_update_integrals(current); +--- a/fs/ioctl.c ++++ b/fs/ioctl.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + +@@ -205,6 +206,8 @@ SYSCALL_DEFINE3(ioctl, unsigned int, fd, + if (!filp) + goto out; + ++ trace_fs_ioctl(fd, cmd, arg); ++ + error = security_file_ioctl(filp, cmd, arg); + if (error) + goto out_fput; +--- a/fs/open.c ++++ b/fs/open.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) + { +@@ -1044,6 +1045,7 @@ long do_sys_open(int dfd, const char __u + fsnotify_open(f->f_path.dentry); + fd_install(fd, f); + } ++ trace_fs_open(fd, tmp); + } + putname(tmp); + } +@@ -1133,6 +1135,7 @@ SYSCALL_DEFINE1(close, unsigned int, fd) + filp = fdt->fd[fd]; + if (!filp) + goto out_unlock; ++ trace_fs_close(fd); + rcu_assign_pointer(fdt->fd[fd], NULL); + FD_CLR(fd, fdt->close_on_exec); + __put_unused_fd(files, fd); +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include "read_write.h" + + #include +@@ -130,6 +131,9 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, + if (res != (loff_t)retval) + retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ + } ++ ++ trace_fs_lseek(fd, offset, origin); ++ + fput_light(file, fput_needed); + bad: + return retval; +@@ -157,6 +161,8 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd + offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low, + origin); + ++ trace_fs_llseek(fd, offset, origin); ++ + retval = (int)offset; + if (offset >= 0) { + retval = -EFAULT; +@@ -344,6 +350,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, + if (file) { + loff_t pos = file_pos_read(file); + ret = vfs_read(file, buf, count, &pos); ++ trace_fs_read(fd, buf, count, ret); + file_pos_write(file, pos); + fput_light(file, fput_needed); + } +@@ -362,6 +369,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, + if (file) { + loff_t pos = file_pos_read(file); + ret = vfs_write(file, buf, count, &pos); ++ trace_fs_write(fd, buf, count, ret); + file_pos_write(file, pos); + fput_light(file, fput_needed); + } +@@ -382,8 +390,11 @@ SYSCALL_DEFINE(pread64)(unsigned int fd, + file = fget_light(fd, &fput_needed); + if (file) { + ret = -ESPIPE; +- if (file->f_mode & FMODE_PREAD) ++ if (file->f_mode & FMODE_PREAD) { + ret = vfs_read(file, buf, count, &pos); ++ trace_fs_pread64(fd, buf, count, pos, ret); ++ } ++ + fput_light(file, fput_needed); + } + +@@ -411,8 +422,10 @@ SYSCALL_DEFINE(pwrite64)(unsigned int fd + file = fget_light(fd, &fput_needed); + if (file) { + ret = -ESPIPE; +- if (file->f_mode & FMODE_PWRITE) ++ if (file->f_mode & FMODE_PWRITE) { + ret = vfs_write(file, buf, count, &pos); ++ trace_fs_pwrite64(fd, buf, count, pos, ret); ++ } + fput_light(file, fput_needed); + } + +@@ -665,6 +678,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd + if (file) { + loff_t pos = file_pos_read(file); + ret = vfs_readv(file, vec, vlen, &pos); ++ trace_fs_readv(fd, vec, vlen, ret); + file_pos_write(file, pos); + fput_light(file, fput_needed); + } +@@ -686,6 +700,7 @@ SYSCALL_DEFINE3(writev, unsigned long, f + if (file) { + loff_t pos = file_pos_read(file); + ret = vfs_writev(file, vec, vlen, &pos); ++ trace_fs_writev(fd, vec, vlen, ret); + file_pos_write(file, pos); + fput_light(file, fput_needed); + } +--- a/fs/select.c ++++ b/fs/select.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include + +@@ -232,6 +233,7 @@ int do_select(int n, fd_set_bits *fds, s + file = fget_light(i, &fput_needed); + if (file) { + f_op = file->f_op; ++ trace_fs_select(i, *timeout); + mask = DEFAULT_POLLMASK; + if (f_op && f_op->poll) + mask = (*f_op->poll)(file, retval ? NULL : wait); +@@ -561,6 +563,7 @@ static inline unsigned int do_pollfd(str + file = fget_light(fd, &fput_needed); + mask = POLLNVAL; + if (file != NULL) { ++ trace_fs_poll(fd); + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file, pwait); +--- /dev/null ++++ b/include/trace/fs.h +@@ -0,0 +1,65 @@ ++#ifndef _TRACE_FS_H ++#define _TRACE_FS_H ++ ++#include ++#include ++ ++DEFINE_TRACE(fs_buffer_wait_start, ++ TPPROTO(struct buffer_head *bh), ++ TPARGS(bh)); ++DEFINE_TRACE(fs_buffer_wait_end, ++ TPPROTO(struct buffer_head *bh), ++ TPARGS(bh)); ++DEFINE_TRACE(fs_exec, ++ TPPROTO(char *filename), ++ TPARGS(filename)); ++DEFINE_TRACE(fs_ioctl, ++ TPPROTO(unsigned int fd, unsigned int cmd, unsigned long arg), ++ TPARGS(fd, cmd, arg)); ++DEFINE_TRACE(fs_open, ++ TPPROTO(int fd, char *filename), ++ TPARGS(fd, filename)); ++DEFINE_TRACE(fs_close, ++ TPPROTO(unsigned int fd), ++ TPARGS(fd)); ++DEFINE_TRACE(fs_lseek, ++ TPPROTO(unsigned int fd, long offset, unsigned int origin), ++ TPARGS(fd, offset, origin)); ++DEFINE_TRACE(fs_llseek, ++ TPPROTO(unsigned int fd, loff_t offset, unsigned int origin), ++ TPARGS(fd, offset, origin)); ++ ++/* ++ * Probes must be aware that __user * may be modified by concurrent userspace ++ * or kernel threads. ++ */ ++DEFINE_TRACE(fs_read, ++ TPPROTO(unsigned int fd, char __user *buf, size_t count, ssize_t ret), ++ TPARGS(fd, buf, count, ret)); ++DEFINE_TRACE(fs_write, ++ TPPROTO(unsigned int fd, const char __user *buf, size_t count, ++ ssize_t ret), ++ TPARGS(fd, buf, count, ret)); ++DEFINE_TRACE(fs_pread64, ++ TPPROTO(unsigned int fd, char __user *buf, size_t count, loff_t pos, ++ ssize_t ret), ++ TPARGS(fd, buf, count, pos, ret)); ++DEFINE_TRACE(fs_pwrite64, ++ TPPROTO(unsigned int fd, const char __user *buf, size_t count, ++ loff_t pos, ssize_t ret), ++ TPARGS(fd, buf, count, pos, ret)); ++DEFINE_TRACE(fs_readv, ++ TPPROTO(unsigned long fd, const struct iovec __user *vec, ++ unsigned long vlen, ssize_t ret), ++ TPARGS(fd, vec, vlen, ret)); ++DEFINE_TRACE(fs_writev, ++ TPPROTO(unsigned long fd, const struct iovec __user *vec, ++ unsigned long vlen, ssize_t ret), ++ TPARGS(fd, vec, vlen, ret)); ++DEFINE_TRACE(fs_select, ++ TPPROTO(int fd, s64 timeout), ++ TPARGS(fd, timeout)); ++DEFINE_TRACE(fs_poll, ++ TPPROTO(int fd), ++ TPARGS(fd)); ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-hugetlb.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-hugetlb.patch new file mode 100644 index 000000000..4d4b582f9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-hugetlb.patch @@ -0,0 +1,221 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - hugetlb + +Original patch header: + LTTng instrumentation - hugetlb + + Instrumentation of hugetlb activity (alloc/free/reserve/grab/release). + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Changelog : + - instrument page grab, buddy allocator alloc, page release. + + Signed-off-by: Mathieu Desnoyers + CC: William Lee Irwin III + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/hugetlb.h | 28 ++++++++++++++++++++++++ + mm/hugetlb.c | 56 +++++++++++++++++++++++++++++++++--------------- + 2 files changed, 67 insertions(+), 17 deletions(-) + +--- /dev/null ++++ b/include/trace/hugetlb.h +@@ -0,0 +1,28 @@ ++#ifndef _TRACE_HUGETLB_H ++#define _TRACE_HUGETLB_H ++ ++#include ++ ++DEFINE_TRACE(hugetlb_page_release, ++ TPPROTO(struct page *page), ++ TPARGS(page)); ++DEFINE_TRACE(hugetlb_page_grab, ++ TPPROTO(struct page *page), ++ TPARGS(page)); ++DEFINE_TRACE(hugetlb_buddy_pgalloc, ++ TPPROTO(struct page *page), ++ TPARGS(page)); ++DEFINE_TRACE(hugetlb_page_alloc, ++ TPPROTO(struct page *page), ++ TPARGS(page)); ++DEFINE_TRACE(hugetlb_page_free, ++ TPPROTO(struct page *page), ++ TPARGS(page)); ++DEFINE_TRACE(hugetlb_pages_reserve, ++ TPPROTO(struct inode *inode, long from, long to, int ret), ++ TPARGS(inode, from, to, ret)); ++DEFINE_TRACE(hugetlb_pages_unreserve, ++ TPPROTO(struct inode *inode, long offset, long freed), ++ TPARGS(inode, offset, freed)); ++ ++#endif +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -492,6 +493,7 @@ static void update_and_free_page(struct + + VM_BUG_ON(h->order >= MAX_ORDER); + ++ trace_hugetlb_page_release(page); + h->nr_huge_pages--; + h->nr_huge_pages_node[page_to_nid(page)]--; + for (i = 0; i < pages_per_huge_page(h); i++) { +@@ -526,6 +528,7 @@ static void free_huge_page(struct page * + int nid = page_to_nid(page); + struct address_space *mapping; + ++ trace_hugetlb_page_free(page); + mapping = (struct address_space *) page_private(page); + set_page_private(page, 0); + BUG_ON(page_count(page)); +@@ -593,8 +596,10 @@ static struct page *alloc_fresh_huge_pag + { + struct page *page; + +- if (h->order >= MAX_ORDER) +- return NULL; ++ if (h->order >= MAX_ORDER) { ++ page = NULL; ++ goto end; ++ } + + page = alloc_pages_node(nid, + htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE| +@@ -603,11 +608,13 @@ static struct page *alloc_fresh_huge_pag + if (page) { + if (arch_prepare_hugepage(page)) { + __free_pages(page, huge_page_order(h)); +- return NULL; ++ page = NULL; ++ goto end; + } + prep_new_huge_page(h, page, nid); + } +- ++end: ++ trace_hugetlb_page_grab(page); + return page; + } + +@@ -691,7 +698,8 @@ static struct page *alloc_buddy_huge_pag + spin_lock(&hugetlb_lock); + if (h->surplus_huge_pages >= h->nr_overcommit_huge_pages) { + spin_unlock(&hugetlb_lock); +- return NULL; ++ page = NULL; ++ goto end; + } else { + h->nr_huge_pages++; + h->surplus_huge_pages++; +@@ -729,7 +737,8 @@ static struct page *alloc_buddy_huge_pag + __count_vm_event(HTLB_BUDDY_PGALLOC_FAIL); + } + spin_unlock(&hugetlb_lock); +- ++end: ++ trace_hugetlb_buddy_pgalloc(page); + return page; + } + +@@ -968,6 +977,7 @@ static struct page *alloc_huge_page(stru + + vma_commit_reservation(h, vma, addr); + ++ trace_hugetlb_page_alloc(page); + return page; + } + +@@ -2233,11 +2243,12 @@ int hugetlb_reserve_pages(struct inode * + long from, long to, + struct vm_area_struct *vma) + { +- long ret, chg; ++ int ret = 0; ++ long chg; + struct hstate *h = hstate_inode(inode); + + if (vma && vma->vm_flags & VM_NORESERVE) +- return 0; ++ goto end; + + /* + * Shared mappings base their reservation on the number of pages that +@@ -2249,8 +2260,10 @@ int hugetlb_reserve_pages(struct inode * + chg = region_chg(&inode->i_mapping->private_list, from, to); + else { + struct resv_map *resv_map = resv_map_alloc(); +- if (!resv_map) +- return -ENOMEM; ++ if (!resv_map) { ++ ret = -ENOMEM; ++ goto end; ++ } + + chg = to - from; + +@@ -2258,25 +2271,34 @@ int hugetlb_reserve_pages(struct inode * + set_vma_resv_flags(vma, HPAGE_RESV_OWNER); + } + +- if (chg < 0) +- return chg; ++ if (chg < 0) { ++ ret = chg; ++ goto end; ++ } + +- if (hugetlb_get_quota(inode->i_mapping, chg)) +- return -ENOSPC; ++ if (hugetlb_get_quota(inode->i_mapping, chg)) { ++ ret = -ENOSPC; ++ goto end; ++ } + ret = hugetlb_acct_memory(h, chg); + if (ret < 0) { + hugetlb_put_quota(inode->i_mapping, chg); +- return ret; ++ goto end; + } + if (!vma || vma->vm_flags & VM_MAYSHARE) + region_add(&inode->i_mapping->private_list, from, to); +- return 0; ++end: ++ trace_hugetlb_pages_reserve(inode, from, to, ret); ++ return ret; + } + + void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) + { + struct hstate *h = hstate_inode(inode); +- long chg = region_truncate(&inode->i_mapping->private_list, offset); ++ long chg; ++ ++ trace_hugetlb_pages_unreserve(inode, offset, freed); ++ chg = region_truncate(&inode->i_mapping->private_list, offset); + + spin_lock(&inode->i_lock); + inode->i_blocks -= (blocks_per_huge_page(h) * freed); diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipc.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipc.patch new file mode 100644 index 000000000..e9fef7307 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipc.patch @@ -0,0 +1,147 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - ipc + +Original patch header: + LTTng instrumentation - ipc + + Interprocess communication, core events. + + Added tracepoints : + + ipc_msg_create + ipc_sem_create + ipc_shm_create + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +Index: linux-2.6-lttng/ipc/msg.c +=================================================================== +--- linux-2.6-lttng.orig/ipc/msg.c 2008-08-06 00:41:47.000000000 -0400 ++++ linux-2.6-lttng/ipc/msg.c 2008-08-06 01:04:20.000000000 -0400 +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -314,6 +315,7 @@ asmlinkage long sys_msgget(key_t key, in + struct ipc_namespace *ns; + struct ipc_ops msg_ops; + struct ipc_params msg_params; ++ long ret; + + ns = current->nsproxy->ipc_ns; + +@@ -324,7 +326,9 @@ asmlinkage long sys_msgget(key_t key, in + msg_params.key = key; + msg_params.flg = msgflg; + +- return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); ++ ret = ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); ++ trace_ipc_msg_create(ret, msgflg); ++ return ret; + } + + static inline unsigned long +Index: linux-2.6-lttng/ipc/sem.c +=================================================================== +--- linux-2.6-lttng.orig/ipc/sem.c 2008-08-06 00:41:47.000000000 -0400 ++++ linux-2.6-lttng/ipc/sem.c 2008-08-06 01:04:20.000000000 -0400 +@@ -83,6 +83,7 @@ + #include + #include + #include ++#include + + #include + #include "util.h" +@@ -313,6 +314,7 @@ asmlinkage long sys_semget(key_t key, in + struct ipc_namespace *ns; + struct ipc_ops sem_ops; + struct ipc_params sem_params; ++ long err; + + ns = current->nsproxy->ipc_ns; + +@@ -327,7 +329,9 @@ asmlinkage long sys_semget(key_t key, in + sem_params.flg = semflg; + sem_params.u.nsems = nsems; + +- return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); ++ err = ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); ++ trace_ipc_sem_create(err, semflg); ++ return err; + } + + /* +Index: linux-2.6-lttng/ipc/shm.c +=================================================================== +--- linux-2.6-lttng.orig/ipc/shm.c 2008-08-06 00:41:47.000000000 -0400 ++++ linux-2.6-lttng/ipc/shm.c 2008-08-06 01:04:20.000000000 -0400 +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #include + +@@ -445,6 +446,7 @@ asmlinkage long sys_shmget (key_t key, s + struct ipc_namespace *ns; + struct ipc_ops shm_ops; + struct ipc_params shm_params; ++ long err; + + ns = current->nsproxy->ipc_ns; + +@@ -456,7 +458,9 @@ asmlinkage long sys_shmget (key_t key, s + shm_params.flg = shmflg; + shm_params.u.size = size; + +- return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params); ++ err = ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params); ++ trace_ipc_shm_create(err, shmflg); ++ return err; + } + + static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) +Index: linux-2.6-lttng/include/trace/ipc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/include/trace/ipc.h 2008-08-06 01:04:20.000000000 -0400 +@@ -0,0 +1,15 @@ ++#ifndef _TRACE_IPC_H ++#define _TRACE_IPC_H ++ ++#include ++ ++DEFINE_TRACE(ipc_msg_create, ++ TPPROTO(long id, int flags), ++ TPARGS(id, flags)); ++DEFINE_TRACE(ipc_sem_create, ++ TPPROTO(long id, int flags), ++ TPARGS(id, flags)); ++DEFINE_TRACE(ipc_shm_create, ++ TPPROTO(long id, int flags), ++ TPARGS(id, flags)); ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipv4.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipv4.patch new file mode 100644 index 000000000..813350fe3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipv4.patch @@ -0,0 +1,81 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - ipv4 + +Original patch header: + LTTng instrumentation - ipv4 + + Keep track of interface up/down for ipv4. Allows to keep track of interface + address changes in a trace. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: netdev@vger.kernel.org + CC: David S. Miller + CC: Alexey Kuznetsov + CC: + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/ipv4.h | 14 ++++++++++++++ + net/ipv4/devinet.c | 3 +++ + 2 files changed, 17 insertions(+) + +--- /dev/null ++++ b/include/trace/ipv4.h +@@ -0,0 +1,14 @@ ++#ifndef _TRACE_IPV4_H ++#define _TRACE_IPV4_H ++ ++#include ++#include ++ ++DEFINE_TRACE(ipv4_addr_add, ++ TPPROTO(struct in_ifaddr *ifa), ++ TPARGS(ifa)); ++DEFINE_TRACE(ipv4_addr_del, ++ TPPROTO(struct in_ifaddr *ifa), ++ TPARGS(ifa)); ++ ++#endif +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + + static struct ipv4_devconf ipv4_devconf = { + .data = { +@@ -257,6 +258,7 @@ static void __inet_del_ifa(struct in_dev + struct in_ifaddr **ifap1 = &ifa1->ifa_next; + + while ((ifa = *ifap1) != NULL) { ++ trace_ipv4_addr_del(ifa); + if (!(ifa->ifa_flags & IFA_F_SECONDARY) && + ifa1->ifa_scope <= ifa->ifa_scope) + last_prim = ifa; +@@ -363,6 +365,7 @@ static int __inet_insert_ifa(struct in_i + } + ifa->ifa_flags |= IFA_F_SECONDARY; + } ++ trace_ipv4_addr_add(ifa); + } + + if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipv6.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipv6.patch new file mode 100644 index 000000000..c2d21078b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-ipv6.patch @@ -0,0 +1,82 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - ipv6 + +Original patch header: + LTTng instrumentation - ipv6 + + Instrument addr_add and del of network interfaces. Lets a tracer know the + interface address changes. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Pekka Savola + CC: netdev@vger.kernel.org + CC: David S. Miller + CC: Alexey Kuznetsov + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/ipv6.h | 14 ++++++++++++++ + net/ipv6/addrconf.c | 4 ++++ + 2 files changed, 18 insertions(+) + +--- /dev/null ++++ b/include/trace/ipv6.h +@@ -0,0 +1,14 @@ ++#ifndef _TRACE_IPV6_H ++#define _TRACE_IPV6_H ++ ++#include ++#include ++ ++DEFINE_TRACE(ipv6_addr_add, ++ TPPROTO(struct inet6_ifaddr *ifa), ++ TPARGS(ifa)); ++DEFINE_TRACE(ipv6_addr_del, ++ TPPROTO(struct inet6_ifaddr *ifa), ++ TPARGS(ifa)); ++ ++#endif +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -85,6 +85,7 @@ + + #include + #include ++#include + + /* Set to 3 to get tracing... */ + #define ACONF_DEBUG 2 +@@ -653,6 +654,8 @@ ipv6_add_addr(struct inet6_dev *idev, co + /* For caller */ + in6_ifa_hold(ifa); + ++ trace_ipv6_addr_add(ifa); ++ + /* Add to big hash table */ + hash = ipv6_addr_hash(addr); + +@@ -2167,6 +2170,7 @@ static int inet6_addr_del(struct net *ne + in6_ifa_hold(ifp); + read_unlock_bh(&idev->lock); + ++ trace_ipv6_addr_del(ifp); + ipv6_del_addr(ifp); + + /* If the last address is deleted administratively, diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-irq.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-irq.patch new file mode 100644 index 000000000..4e08a7b1d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-irq.patch @@ -0,0 +1,162 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - irq + +Original patch header: + LTTng instrumentation - irq + + Instrumentation of IRQ related events : irq, softirq, tasklet entry and exit and + softirq "raise" events. + + It allows tracers to perform latency analysis on those various types of + interrupts and to detect interrupts with max/min/avg duration. It helps + detecting driver or hardware problems which cause an ISR to take ages to + execute. It has been shown to be the case with bogus hardware causing an mmio + read to take a few milliseconds. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Changelog: + - Add retval as irq_exit argument. + + Signed-off-by: Mathieu Desnoyers + CC: Thomas Gleixner + CC: Russell King + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/irq.h | 36 ++++++++++++++++++++++++++++++++++++ + kernel/irq/handle.c | 6 ++++++ + kernel/softirq.c | 8 ++++++++ + 3 files changed, 50 insertions(+) + +--- /dev/null ++++ b/include/trace/irq.h +@@ -0,0 +1,36 @@ ++#ifndef _TRACE_IRQ_H ++#define _TRACE_IRQ_H ++ ++#include ++#include ++#include ++ ++DEFINE_TRACE(irq_entry, ++ TPPROTO(unsigned int id, struct pt_regs *regs), ++ TPARGS(id, regs)); ++DEFINE_TRACE(irq_exit, ++ TPPROTO(irqreturn_t retval), ++ TPARGS(retval)); ++DEFINE_TRACE(irq_softirq_entry, ++ TPPROTO(struct softirq_action *h, struct softirq_action *softirq_vec), ++ TPARGS(h, softirq_vec)); ++DEFINE_TRACE(irq_softirq_exit, ++ TPPROTO(struct softirq_action *h, struct softirq_action *softirq_vec), ++ TPARGS(h, softirq_vec)); ++DEFINE_TRACE(irq_softirq_raise, ++ TPPROTO(unsigned int nr), ++ TPARGS(nr)); ++DEFINE_TRACE(irq_tasklet_low_entry, ++ TPPROTO(struct tasklet_struct *t), ++ TPARGS(t)); ++DEFINE_TRACE(irq_tasklet_low_exit, ++ TPPROTO(struct tasklet_struct *t), ++ TPARGS(t)); ++DEFINE_TRACE(irq_tasklet_high_entry, ++ TPPROTO(struct tasklet_struct *t), ++ TPARGS(t)); ++DEFINE_TRACE(irq_tasklet_high_exit, ++ TPPROTO(struct tasklet_struct *t), ++ TPARGS(t)); ++ ++#endif +--- a/kernel/irq/handle.c ++++ b/kernel/irq/handle.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include "internals.h" + +@@ -130,6 +131,9 @@ irqreturn_t handle_IRQ_event(unsigned in + { + irqreturn_t ret, retval = IRQ_NONE; + unsigned int status = 0; ++ struct pt_regs *regs = get_irq_regs(); ++ ++ trace_irq_entry(irq, regs); + + handle_dynamic_tick(action); + +@@ -148,6 +152,8 @@ irqreturn_t handle_IRQ_event(unsigned in + add_interrupt_randomness(irq); + local_irq_disable(); + ++ trace_irq_exit(retval); ++ + return retval; + } + +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include + /* +@@ -205,7 +206,9 @@ restart: + + do { + if (pending & 1) { ++ trace_irq_softirq_entry(h, softirq_vec); + h->action(h); ++ trace_irq_softirq_exit(h, softirq_vec); + rcu_bh_qsctr_inc(cpu); + } + h++; +@@ -297,6 +300,7 @@ void irq_exit(void) + */ + inline void raise_softirq_irqoff(unsigned int nr) + { ++ trace_irq_softirq_raise(nr); + __raise_softirq_irqoff(nr); + + /* +@@ -383,7 +387,9 @@ static void tasklet_action(struct softir + if (!atomic_read(&t->count)) { + if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + BUG(); ++ trace_irq_tasklet_low_entry(t); + t->func(t->data); ++ trace_irq_tasklet_low_exit(t); + tasklet_unlock(t); + continue; + } +@@ -418,7 +424,9 @@ static void tasklet_hi_action(struct sof + if (!atomic_read(&t->count)) { + if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + BUG(); ++ trace_irq_tasklet_high_entry(t); + t->func(t->data); ++ trace_irq_tasklet_high_exit(t); + tasklet_unlock(t); + continue; + } diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-kernel.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-kernel.patch new file mode 100644 index 000000000..a83562da0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-kernel.patch @@ -0,0 +1,80 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - kernel + +Original patch header: + LTTng instrumentation - kernel + + Instrument the core kernel : module load/free and printk events. It helps the + tracer to keep track of module related events and to export valuable printk + information into the traces. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Andrew Morton + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/kernel.h | 13 +++++++++++++ + kernel/module.c | 5 +++++ + 2 files changed, 18 insertions(+) + +--- /dev/null ++++ b/include/trace/kernel.h +@@ -0,0 +1,13 @@ ++#ifndef _TRACE_KERNEL_H ++#define _TRACE_KERNEL_H ++ ++#include ++ ++DEFINE_TRACE(kernel_module_free, ++ TPPROTO(struct module *mod), ++ TPARGS(mod)); ++DEFINE_TRACE(kernel_module_load, ++ TPPROTO(struct module *mod), ++ TPARGS(mod)); ++ ++#endif +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -47,6 +47,7 @@ + #include + #include + #include ++#include + + #if 0 + #define DEBUGP printk +@@ -1473,6 +1474,8 @@ static int __unlink_module(void *_mod) + /* Free a module, remove from lists, etc (must hold module_mutex). */ + static void free_module(struct module *mod) + { ++ trace_kernel_module_free(mod); ++ + /* Delete from various lists */ + stop_machine(__unlink_module, mod, NULL); + remove_notes_attrs(mod); +@@ -2354,6 +2357,8 @@ static noinline struct module *load_modu + /* Get rid of temporary copy */ + vfree(hdr); + ++ trace_kernel_module_load(mod); ++ + /* Done! */ + return mod; + diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-memory.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-memory.patch new file mode 100644 index 000000000..bafaf7288 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-memory.patch @@ -0,0 +1,118 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - memory page faults + +Original patch header: + LTTng instrumentation - memory page faults + + Instrument the page fault entry and exit. Useful to detect delays caused by page + faults and bad memory usage patterns. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Andi Kleen + CC: linux-mm@kvack.org + CC: Dave Hansen + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/memory.h | 14 ++++++++++++++ + mm/memory.c | 33 ++++++++++++++++++++++++--------- + 2 files changed, 38 insertions(+), 9 deletions(-) + +--- /dev/null ++++ b/include/trace/memory.h +@@ -0,0 +1,14 @@ ++#ifndef _TRACE_MEMORY_H ++#define _TRACE_MEMORY_H ++ ++#include ++ ++DEFINE_TRACE(memory_handle_fault_entry, ++ TPPROTO(struct mm_struct *mm, struct vm_area_struct *vma, ++ unsigned long address, int write_access), ++ TPARGS(mm, vma, address, write_access)); ++DEFINE_TRACE(memory_handle_fault_exit, ++ TPPROTO(int res), ++ TPARGS(res)); ++ ++#endif +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -61,6 +61,7 @@ + + #include + #include ++#include + + #include "internal.h" + +@@ -2869,30 +2870,44 @@ unlock: + int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, int write_access) + { ++ int res; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + ++ trace_memory_handle_fault_entry(mm, vma, address, write_access); ++ + __set_current_state(TASK_RUNNING); + + count_vm_event(PGFAULT); + +- if (unlikely(is_vm_hugetlb_page(vma))) +- return hugetlb_fault(mm, vma, address, write_access); ++ if (unlikely(is_vm_hugetlb_page(vma))) { ++ res = hugetlb_fault(mm, vma, address, write_access); ++ goto end; ++ } + + pgd = pgd_offset(mm, address); + pud = pud_alloc(mm, pgd, address); +- if (!pud) +- return VM_FAULT_OOM; ++ if (!pud) { ++ res = VM_FAULT_OOM; ++ goto end; ++ } + pmd = pmd_alloc(mm, pud, address); +- if (!pmd) +- return VM_FAULT_OOM; ++ if (!pmd) { ++ res = VM_FAULT_OOM; ++ goto end; ++ } + pte = pte_alloc_map(mm, pmd, address); +- if (!pte) +- return VM_FAULT_OOM; ++ if (!pte) { ++ res = VM_FAULT_OOM; ++ goto end; ++ } + +- return handle_pte_fault(mm, vma, address, pte, pmd, write_access); ++ res = handle_pte_fault(mm, vma, address, pte, pmd, write_access); ++end: ++ trace_memory_handle_fault_exit(res); ++ return res; + } + EXPORT_SYMBOL_GPL(handle_mm_fault); /* For MoL */ + diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-net.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-net.patch new file mode 100644 index 000000000..200e6b604 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-net.patch @@ -0,0 +1,84 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - net + +Original patch header: + LTTng instrumentation - net + + Network device activity instrumentation (xmit/receive). Allows to detect when a + packet had arrived on the network card or when it is going to be sent. This is + the instrumentation point outside of the drivers that is the closest to the + hardware. It allows to detect the amount of time taken by a packet to go through + the kernel between the system call and the actual delivery to the network card + (given that system calls are instrumented). + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Andrew Morton + CC: netdev@vger.kernel.org + CC: Jeff Garzik + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/net.h | 14 ++++++++++++++ + net/core/dev.c | 3 +++ + 2 files changed, 17 insertions(+) + +--- /dev/null ++++ b/include/trace/net.h +@@ -0,0 +1,14 @@ ++#ifndef _TRACE_NET_H ++#define _TRACE_NET_H ++ ++#include ++#include ++ ++DEFINE_TRACE(net_dev_xmit, ++ TPPROTO(struct sk_buff *skb), ++ TPARGS(skb)); ++DEFINE_TRACE(net_dev_receive, ++ TPPROTO(struct sk_buff *skb), ++ TPARGS(skb)); ++ ++#endif +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -127,6 +127,7 @@ + #include + #include + #include ++#include + + #include "net-sysfs.h" + +@@ -1794,6 +1795,7 @@ int dev_queue_xmit(struct sk_buff *skb) + } + + gso: ++ trace_net_dev_xmit(skb); + /* Disable soft irqs for various locks below. Also + * stops preemption for RCU. + */ +@@ -2215,6 +2217,7 @@ int netif_receive_skb(struct sk_buff *sk + + __get_cpu_var(netdev_rx_stat).total++; + ++ trace_net_dev_receive(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + skb->mac_len = skb->network_header - skb->mac_header; diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-page_alloc.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-page_alloc.patch new file mode 100644 index 000000000..86fe4f0bd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-page_alloc.patch @@ -0,0 +1,92 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - page_alloc + +Original patch header: + LTTng instrumentation - page_alloc + + Paging activity instrumentation. Instruments page allocation/free to keep track + of page allocation. This does not cover hugetlb activity, which is covered by a + separate patch. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: Martin Bligh + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/page_alloc.h | 16 ++++++++++++++++ + mm/page_alloc.c | 7 +++++++ + 2 files changed, 23 insertions(+) + +--- /dev/null ++++ b/include/trace/page_alloc.h +@@ -0,0 +1,16 @@ ++#ifndef _TRACE_PAGE_ALLOC_H ++#define _TRACE_PAGE_ALLOC_H ++ ++#include ++ ++/* ++ * mm_page_alloc : page can be NULL. ++ */ ++DEFINE_TRACE(page_alloc, ++ TPPROTO(struct page *page, unsigned int order), ++ TPARGS(page, order)); ++DEFINE_TRACE(page_free, ++ TPPROTO(struct page *page, unsigned int order), ++ TPARGS(page, order)); ++ ++#endif +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -51,6 +51,8 @@ + #include + #include "internal.h" + ++#include ++ + /* + * Array of node states. + */ +@@ -528,6 +530,8 @@ static void __free_pages_ok(struct page + int i; + int reserved = 0; + ++ trace_page_free(page, order); ++ + for (i = 0 ; i < (1 << order) ; ++i) + reserved += free_pages_check(page + i); + if (reserved) +@@ -991,6 +995,8 @@ static void free_hot_cold_page(struct pa + struct per_cpu_pages *pcp; + unsigned long flags; + ++ trace_page_free(page, 0); ++ + if (PageAnon(page)) + page->mapping = NULL; + if (free_pages_check(page)) +@@ -1663,6 +1669,7 @@ nopage: + show_mem(); + } + got_pg: ++ trace_page_alloc(page, order); + return page; + } + EXPORT_SYMBOL(__alloc_pages_internal); diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-scheduler.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-scheduler.patch new file mode 100644 index 000000000..f79f5a5bc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-scheduler.patch @@ -0,0 +1,262 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - scheduler + +Original patch header: + LTTng instrumentation - scheduler + + Instrument the scheduler activity (sched_switch, migration, wakeups, wait for a + task, signal delivery) and process/thread creation/destruction (fork, exit, + kthread stop). Actually, kthread creation is not instrumented in this patch + because it is architecture dependent. It allows to connect tracers such as + ftrace which detects scheduling latencies, good/bad scheduler decisions. Tools + like LTTng can export this scheduler information along with instrumentation of + the rest of the kernel activity to perform post-mortem analysis on the scheduler + activity. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Changelog : + - Change instrumentation location and parameter to match ftrace instrumentation, + previously done with kernel markers. + + Signed-off-by: Mathieu Desnoyers + CC: 'Peter Zijlstra' + CC: 'Steven Rostedt' + CC: Thomas Gleixner + CC: Masami Hiramatsu + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/sched.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ + kernel/exit.c | 10 +++++++++- + kernel/fork.c | 3 +++ + kernel/kthread.c | 5 +++++ + kernel/sched.c | 17 ++++++----------- + kernel/signal.c | 3 +++ + 6 files changed, 71 insertions(+), 12 deletions(-) + +--- /dev/null ++++ b/include/trace/sched.h +@@ -0,0 +1,45 @@ ++#ifndef _TRACE_SCHED_H ++#define _TRACE_SCHED_H ++ ++#include ++#include ++ ++DEFINE_TRACE(sched_kthread_stop, ++ TPPROTO(struct task_struct *t), ++ TPARGS(t)); ++DEFINE_TRACE(sched_kthread_stop_ret, ++ TPPROTO(int ret), ++ TPARGS(ret)); ++DEFINE_TRACE(sched_wait_task, ++ TPPROTO(struct rq *rq, struct task_struct *p), ++ TPARGS(rq, p)); ++DEFINE_TRACE(sched_wakeup, ++ TPPROTO(struct rq *rq, struct task_struct *p), ++ TPARGS(rq, p)); ++DEFINE_TRACE(sched_wakeup_new, ++ TPPROTO(struct rq *rq, struct task_struct *p), ++ TPARGS(rq, p)); ++DEFINE_TRACE(sched_switch, ++ TPPROTO(struct rq *rq, struct task_struct *prev, ++ struct task_struct *next), ++ TPARGS(rq, prev, next)); ++DEFINE_TRACE(sched_migrate_task, ++ TPPROTO(struct rq *rq, struct task_struct *p, int dest_cpu), ++ TPARGS(rq, p, dest_cpu)); ++DEFINE_TRACE(sched_process_free, ++ TPPROTO(struct task_struct *p), ++ TPARGS(p)); ++DEFINE_TRACE(sched_process_exit, ++ TPPROTO(struct task_struct *p), ++ TPARGS(p)); ++DEFINE_TRACE(sched_process_wait, ++ TPPROTO(struct pid *pid), ++ TPARGS(pid)); ++DEFINE_TRACE(sched_process_fork, ++ TPPROTO(struct task_struct *parent, struct task_struct *child), ++ TPARGS(parent, child)); ++DEFINE_TRACE(sched_signal_send, ++ TPPROTO(int sig, struct task_struct *p), ++ TPARGS(sig, p)); ++ ++#endif +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -50,6 +50,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -152,7 +153,10 @@ static void __exit_signal(struct task_st + + static void delayed_put_task_struct(struct rcu_head *rhp) + { +- put_task_struct(container_of(rhp, struct task_struct, rcu)); ++ struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); ++ ++ trace_sched_process_free(tsk); ++ put_task_struct(tsk); + } + + +@@ -1076,6 +1080,8 @@ NORET_TYPE void do_exit(long code) + + if (group_dead) + acct_process(); ++ trace_sched_process_exit(tsk); ++ + exit_sem(tsk); + exit_files(tsk); + exit_fs(tsk); +@@ -1679,6 +1685,8 @@ static long do_wait(enum pid_type type, + struct task_struct *tsk; + int retval; + ++ trace_sched_process_wait(pid); ++ + add_wait_queue(¤t->signal->wait_chldexit,&wait); + repeat: + /* +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1363,6 +1364,8 @@ long do_fork(unsigned long clone_flags, + if (!IS_ERR(p)) { + struct completion vfork; + ++ trace_sched_process_fork(current, p); ++ + nr = task_pid_vnr(p); + + if (clone_flags & CLONE_PARENT_SETTID) +--- a/kernel/kthread.c ++++ b/kernel/kthread.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #define KTHREAD_NICE_LEVEL (-5) + +@@ -206,6 +207,8 @@ int kthread_stop(struct task_struct *k) + /* It could exit after stop_info.k set, but before wake_up_process. */ + get_task_struct(k); + ++ trace_sched_kthread_stop(k); ++ + /* Must init completion *before* thread sees kthread_stop_info.k */ + init_completion(&kthread_stop_info.done); + smp_wmb(); +@@ -221,6 +224,8 @@ int kthread_stop(struct task_struct *k) + ret = kthread_stop_info.err; + mutex_unlock(&kthread_stop_lock); + ++ trace_sched_kthread_stop_ret(ret); ++ + return ret; + } + EXPORT_SYMBOL(kthread_stop); +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1914,6 +1915,7 @@ unsigned long wait_task_inactive(struct + * just go back and repeat. + */ + rq = task_rq_lock(p, &flags); ++ trace_sched_wait_task(rq, p); + running = task_running(rq, p); + on_rq = p->se.on_rq; + ncsw = 0; +@@ -2306,9 +2308,7 @@ out_activate: + success = 1; + + out_running: +- trace_mark(kernel_sched_wakeup, +- "pid %d state %ld ## rq %p task %p rq->curr %p", +- p->pid, p->state, rq, p, rq->curr); ++ trace_sched_wakeup(rq, p); + check_preempt_curr(rq, p); + + p->state = TASK_RUNNING; +@@ -2441,9 +2441,7 @@ void wake_up_new_task(struct task_struct + p->sched_class->task_new(rq, p); + inc_nr_running(rq); + } +- trace_mark(kernel_sched_wakeup_new, +- "pid %d state %ld ## rq %p task %p rq->curr %p", +- p->pid, p->state, rq, p, rq->curr); ++ trace_sched_wakeup_new(rq, p); + check_preempt_curr(rq, p); + #ifdef CONFIG_SMP + if (p->sched_class->task_wake_up) +@@ -2616,11 +2614,7 @@ context_switch(struct rq *rq, struct tas + struct mm_struct *mm, *oldmm; + + prepare_task_switch(rq, prev, next); +- trace_mark(kernel_sched_schedule, +- "prev_pid %d next_pid %d prev_state %ld " +- "## rq %p prev %p next %p", +- prev->pid, next->pid, prev->state, +- rq, prev, next); ++ trace_sched_switch(rq, prev, next); + mm = next->mm; + oldmm = prev->active_mm; + /* +@@ -2860,6 +2854,7 @@ static void sched_migrate_task(struct ta + || unlikely(!cpu_active(dest_cpu))) + goto out; + ++ trace_sched_migrate_task(rq, p, dest_cpu); + /* force the process onto the specified CPU */ + if (migrate_task(p, dest_cpu, &req)) { + /* Need to wait for migration thread (might exit: take ref). */ +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -803,6 +804,8 @@ static int send_signal(int sig, struct s + struct sigpending *pending; + struct sigqueue *q; + ++ trace_sched_signal_send(sig, t); ++ + assert_spin_locked(&t->sighand->siglock); + if (!prepare_signal(sig, t)) + return 0; diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-socket.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-socket.patch new file mode 100644 index 000000000..6a58c8af4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-socket.patch @@ -0,0 +1,113 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - socket + +Original patch header: + LTTng instrumentation - socket + + Instrument socket creation and activity (msg send, receive). Socket "call" + instrumentation should be completed. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: netdev@vger.kernel.org + CC: David S. Miller + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/socket.h | 26 ++++++++++++++++++++++++++ + net/socket.c | 7 +++++++ + 2 files changed, 33 insertions(+) + +--- /dev/null ++++ b/include/trace/socket.h +@@ -0,0 +1,26 @@ ++#ifndef _TRACE_SOCKET_H ++#define _TRACE_SOCKET_H ++ ++#include ++#include ++ ++DEFINE_TRACE(socket_sendmsg, ++ TPPROTO(struct socket *sock, struct msghdr *msg, size_t size, int ret), ++ TPARGS(sock, msg, size, ret)); ++DEFINE_TRACE(socket_recvmsg, ++ TPPROTO(struct socket *sock, struct msghdr *msg, size_t size, int flags, ++ int ret), ++ TPARGS(sock, msg, size, flags, ret)); ++DEFINE_TRACE(socket_create, ++ TPPROTO(struct socket *sock, int fd), ++ TPARGS(sock, fd)); ++/* ++ * socket_call ++ * ++ * TODO : This tracepoint should be expanded to cover each element of the ++ * switch in sys_socketcall(). ++ */ ++DEFINE_TRACE(socket_call, ++ TPPROTO(int call, unsigned long a0), ++ TPARGS(call, a0)); ++#endif +--- a/net/socket.c ++++ b/net/socket.c +@@ -96,6 +96,7 @@ + + #include + #include ++#include + + static int sock_no_open(struct inode *irrelevant, struct file *dontcare); + static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, +@@ -575,6 +576,7 @@ int sock_sendmsg(struct socket *sock, st + ret = __sock_sendmsg(&iocb, sock, msg, size); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&iocb); ++ trace_socket_sendmsg(sock, msg, size, ret); + return ret; + } + +@@ -654,10 +656,12 @@ int sock_recvmsg(struct socket *sock, st + int ret; + + init_sync_kiocb(&iocb, NULL); ++ + iocb.private = &siocb; + ret = __sock_recvmsg(&iocb, sock, msg, size, flags); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&iocb); ++ trace_socket_recvmsg(sock, msg, size, flags, ret); + return ret; + } + +@@ -1244,6 +1248,7 @@ SYSCALL_DEFINE3(socket, int, family, int + if (retval < 0) + goto out_release; + ++ trace_socket_create(sock, retval); + out: + /* It may be already another descriptor 8) Not kernel problem. */ + return retval; +@@ -2131,6 +2136,8 @@ SYSCALL_DEFINE2(socketcall, int, call, u + a0 = a[0]; + a1 = a[1]; + ++ trace_socket_call(call, a0); ++ + switch (call) { + case SYS_SOCKET: + err = sys_socket(a0, a1, a[2]); diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-swap.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-swap.patch new file mode 100644 index 000000000..d57cb1043 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-swap.patch @@ -0,0 +1,124 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - swap + +Original patch header: + LTTng instrumentation - swap + + Instrumentation of waits caused by swap activity. Also instrumentation + swapon/swapoff events to keep track of active swap partitions. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: linux-mm@kvack.org + CC: Dave Hansen + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Ingo Molnar' + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/swap.h | 20 ++++++++++++++++++++ + mm/memory.c | 3 +++ + mm/page_io.c | 2 ++ + mm/swapfile.c | 3 +++ + 4 files changed, 28 insertions(+) + +--- /dev/null ++++ b/include/trace/swap.h +@@ -0,0 +1,20 @@ ++#ifndef _TRACE_SWAP_H ++#define _TRACE_SWAP_H ++ ++#include ++#include ++ ++DEFINE_TRACE(swap_in, ++ TPPROTO(struct page *page, swp_entry_t entry), ++ TPARGS(page, entry)); ++DEFINE_TRACE(swap_out, ++ TPPROTO(struct page *page), ++ TPARGS(page)); ++DEFINE_TRACE(swap_file_open, ++ TPPROTO(struct file *file, char *filename), ++ TPARGS(file, filename)); ++DEFINE_TRACE(swap_file_close, ++ TPPROTO(struct file *file), ++ TPARGS(file)); ++ ++#endif +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -64,6 +64,8 @@ + + #include "internal.h" + ++#include ++ + #ifndef CONFIG_NEED_MULTIPLE_NODES + /* use the per-pgdat data instead for discontigmem - mbligh */ + unsigned long max_mapnr; +@@ -2441,6 +2443,7 @@ static int do_swap_page(struct mm_struct + /* Had to read the page from swap area: Major fault */ + ret = VM_FAULT_MAJOR; + count_vm_event(PGMAJFAULT); ++ trace_swap_in(page, entry); + } + + if (mem_cgroup_charge(page, mm, GFP_KERNEL)) { +--- a/mm/page_io.c ++++ b/mm/page_io.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + static struct bio *get_swap_bio(gfp_t gfp_flags, pgoff_t index, +@@ -114,6 +115,7 @@ int swap_writepage(struct page *page, st + rw |= (1 << BIO_RW_SYNC); + count_vm_event(PSWPOUT); + set_page_writeback(page); ++ trace_swap_out(page); + unlock_page(page); + submit_bio(rw, bio); + out: +--- a/mm/swapfile.c ++++ b/mm/swapfile.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + static DEFINE_SPINLOCK(swap_lock); + static unsigned int nr_swapfiles; +@@ -1325,6 +1326,7 @@ SYSCALL_DEFINE1(swapoff, const char __us + swap_map = p->swap_map; + p->swap_map = NULL; + p->flags = 0; ++ trace_swap_file_close(swap_file); + spin_unlock(&swap_lock); + mutex_unlock(&swapon_mutex); + vfree(swap_map); +@@ -1704,6 +1706,7 @@ SYSCALL_DEFINE2(swapon, const char __use + } else { + swap_info[prev].next = p - swap_info; + } ++ trace_swap_file_open(swap_file, name); + spin_unlock(&swap_lock); + mutex_unlock(&swapon_mutex); + error = 0; diff --git a/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-timer.patch b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-timer.patch new file mode 100644 index 000000000..1ed4cc649 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/lttng-instrumentation-timer.patch @@ -0,0 +1,137 @@ +From: Mathieu Desnoyers +Subject: LTTng instrumentation - timer + +Original patch header: + LTTng instrumentation - timer + + Instrument timer activity (timer set, expired, current time updates) to keep + information about the "real time" flow within the kernel. It can be used by a + trace analysis tool to synchronize information coming from various sources, e.g. + to merge traces with system logs. + + Those tracepoints are used by LTTng. + + About the performance impact of tracepoints (which is comparable to markers), + even without immediate values optimizations, tests done by Hideo Aoki on ia64 + show no regression. His test case was using hackbench on a kernel where + scheduler instrumentation (about 5 events in code scheduler code) was added. + See the "Tracepoints" patch header for performance result detail. + + Signed-off-by: Mathieu Desnoyers + CC: 'Ingo Molnar' + CC: "David S. Miller" + CC: Masami Hiramatsu + CC: 'Peter Zijlstra' + CC: "Frank Ch. Eigler" + CC: 'Hideo AOKI' + CC: Takashi Nishiie + CC: 'Steven Rostedt' + CC: Eduard - Gabriel Munteanu + +Acked-by: Jan Blunck +--- +--- + include/trace/timer.h | 24 ++++++++++++++++++++++++ + kernel/itimer.c | 5 +++++ + kernel/timer.c | 8 +++++++- + 3 files changed, 36 insertions(+), 1 deletion(-) + +--- /dev/null ++++ b/include/trace/timer.h +@@ -0,0 +1,24 @@ ++#ifndef _TRACE_TIMER_H ++#define _TRACE_TIMER_H ++ ++#include ++ ++DEFINE_TRACE(timer_itimer_expired, ++ TPPROTO(struct signal_struct *sig), ++ TPARGS(sig)); ++DEFINE_TRACE(timer_itimer_set, ++ TPPROTO(int which, struct itimerval *value), ++ TPARGS(which, value)); ++DEFINE_TRACE(timer_set, ++ TPPROTO(struct timer_list *timer), ++ TPARGS(timer)); ++/* ++ * xtime_lock is taken when kernel_timer_update_time tracepoint is reached. ++ */ ++DEFINE_TRACE(timer_update_time, ++ TPPROTO(struct timespec *_xtime, struct timespec *_wall_to_monotonic), ++ TPARGS(_xtime, _wall_to_monotonic)); ++DEFINE_TRACE(timer_timeout, ++ TPPROTO(struct task_struct *p), ++ TPARGS(p)); ++#endif +--- a/kernel/itimer.c ++++ b/kernel/itimer.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + +@@ -132,6 +133,8 @@ enum hrtimer_restart it_real_fn(struct h + struct signal_struct *sig = + container_of(timer, struct signal_struct, real_timer); + ++ trace_timer_itimer_expired(sig); ++ + kill_pid_info(SIGALRM, SEND_SIG_PRIV, sig->leader_pid); + + return HRTIMER_NORESTART; +@@ -157,6 +160,8 @@ int do_setitimer(int which, struct itime + !timeval_valid(&value->it_interval)) + return -EINVAL; + ++ trace_timer_itimer_set(which, value); ++ + switch (which) { + case ITIMER_REAL: + again: +--- a/kernel/timer.c ++++ b/kernel/timer.c +@@ -37,12 +37,14 @@ + #include + #include + #include ++#include + + #include + #include + #include + #include + #include ++#include + + u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; + +@@ -357,6 +359,7 @@ static void internal_add_timer(struct tv + i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; + vec = base->tv5.vec + i; + } ++ trace_timer_set(timer); + /* + * Timers are FIFO: + */ +@@ -1135,6 +1138,7 @@ void do_timer(unsigned long ticks) + { + jiffies_64 += ticks; + update_times(ticks); ++ trace_timer_update_time(&xtime, &wall_to_monotonic); + } + + #ifdef __ARCH_WANT_SYS_ALARM +@@ -1216,7 +1220,9 @@ SYSCALL_DEFINE0(getegid) + + static void process_timeout(unsigned long __data) + { +- wake_up_process((struct task_struct *)__data); ++ struct task_struct *task = (struct task_struct *)__data; ++ trace_timer_timeout(task); ++ wake_up_process(task); + } + + /** diff --git a/src/patches/suse-2.6.27.31/patches.trace/markers-use-rcu-read-lock-sched.patch b/src/patches/suse-2.6.27.31/patches.trace/markers-use-rcu-read-lock-sched.patch new file mode 100644 index 000000000..9082b10a4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/markers-use-rcu-read-lock-sched.patch @@ -0,0 +1,72 @@ +From: Mathieu Desnoyers +Subject: Markers use rcu_read_lock_sched() + +Use the new rcu_read_lock_sched/unlock_sched() in marker code around the call +site instead of preempt_disable/enable(). It helps reviewing the code more +easily. + +Signed-off-by: Mathieu Desnoyers +CC: Peter Zijlstra +CC: Paul E McKenney +CC: akpm@linux-foundation.org +Acked-by: Jan Blunck +--- + kernel/marker.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +Index: b/kernel/marker.c +=================================================================== +--- a/kernel/marker.c ++++ b/kernel/marker.c +@@ -103,11 +103,11 @@ void marker_probe_cb(const struct marker + char ptype; + + /* +- * preempt_disable does two things : disabling preemption to make sure +- * the teardown of the callbacks can be done correctly when they are in +- * modules and they insure RCU read coherency. ++ * rcu_read_lock_sched does two things : disabling preemption to make ++ * sure the teardown of the callbacks can be done correctly when they ++ * are in modules and they insure RCU read coherency. + */ +- preempt_disable(); ++ rcu_read_lock_sched(); + ptype = mdata->ptype; + if (likely(!ptype)) { + marker_probe_func *func; +@@ -145,7 +145,7 @@ void marker_probe_cb(const struct marker + va_end(args); + } + } +- preempt_enable(); ++ rcu_read_unlock_sched(); + } + EXPORT_SYMBOL_GPL(marker_probe_cb); + +@@ -162,7 +162,7 @@ void marker_probe_cb_noarg(const struct + va_list args; /* not initialized */ + char ptype; + +- preempt_disable(); ++ rcu_read_lock_sched(); + ptype = mdata->ptype; + if (likely(!ptype)) { + marker_probe_func *func; +@@ -195,7 +195,7 @@ void marker_probe_cb_noarg(const struct + multi[i].func(multi[i].probe_private, call_private, + mdata->format, &args); + } +- preempt_enable(); ++ rcu_read_unlock_sched(); + } + EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); + +@@ -560,7 +560,7 @@ static int set_marker(struct marker_entr + * Disable a marker and its probe callback. + * Note: only waiting an RCU period after setting elem->call to the empty + * function insures that the original callback is not used anymore. This insured +- * by preempt_disable around the call site. ++ * by rcu_read_lock_sched around the call site. + */ + static void disable_marker(struct marker *elem) + { diff --git a/src/patches/suse-2.6.27.31/patches.trace/rcu-read-sched.patch b/src/patches/suse-2.6.27.31/patches.trace/rcu-read-sched.patch new file mode 100644 index 000000000..8e1a806c8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/rcu-read-sched.patch @@ -0,0 +1,49 @@ +From: Mathieu Desnoyers +Subject: RCU read sched + +Add rcu_read_lock_sched() and rcu_read_unlock_sched() to rcupdate.h to match the +recently added write-side call_rcu_sched() and rcu_barrier_sched(). They also +match the no-so-recently-added synchronize_sched(). + +It will help following matching use of the update/read lock primitives. Those +new read lock will replace preempt_disable()/enable() used in pair with +RCU-classic synchronization. + +Signed-off-by: Mathieu Desnoyers +Acked-by: Peter Zijlstra +CC: Paul E McKenney +CC: akpm@linux-foundation.org +Acked-by: Jan Blunck +--- + include/linux/rcupdate.h | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/include/linux/rcupdate.h ++++ b/include/linux/rcupdate.h +@@ -133,6 +133,26 @@ struct rcu_head { + #define rcu_read_unlock_bh() __rcu_read_unlock_bh() + + /** ++ * rcu_read_lock_sched - mark the beginning of a RCU-classic critical section ++ * ++ * Should be used with either ++ * - synchronize_sched() ++ * or ++ * - call_rcu_sched() and rcu_barrier_sched() ++ * on the write-side to insure proper synchronization. ++ */ ++#define rcu_read_lock_sched() preempt_disable() ++ ++/* ++ * rcu_read_unlock_sched - marks the end of a RCU-classic critical section ++ * ++ * See rcu_read_lock_sched for more information. ++ */ ++#define rcu_read_unlock_sched() preempt_enable() ++ ++ ++ ++/** + * rcu_dereference - fetch an RCU-protected pointer in an + * RCU read-side critical section. This pointer may later + * be safely dereferenced. diff --git a/src/patches/suse-2.6.27.31/patches.trace/s390-utrace-enablement.patch b/src/patches/suse-2.6.27.31/patches.trace/s390-utrace-enablement.patch new file mode 100644 index 000000000..7bc47522c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/s390-utrace-enablement.patch @@ -0,0 +1,498 @@ +Subject: Backport s390 kernel components required for utrace enablement + +From: Ananth N. Mavinakayanahalli + +References: bnc#442709 + +Acked-by: John Jolly +--- + arch/s390/Kconfig | 1 + arch/s390/include/asm/ptrace.h | 1 + arch/s390/include/asm/syscall.h | 80 ++++++++++++++++++++++++++++++++++++ + arch/s390/include/asm/thread_info.h | 2 + arch/s390/kernel/entry.S | 50 ++++++++++++++++++---- + arch/s390/kernel/entry64.S | 42 ++++++++++++++---- + arch/s390/kernel/ptrace.c | 75 +++++++++++++++++++++------------ + arch/s390/kernel/signal.c | 13 +++++ + 8 files changed, 216 insertions(+), 48 deletions(-) + +--- a/arch/s390/include/asm/ptrace.h ++++ b/arch/s390/include/asm/ptrace.h +@@ -490,6 +490,7 @@ extern void user_disable_single_step(str + + #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) + #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) ++#define user_stack_pointer(regs)((regs)->gprs[15]) + #define regs_return_value(regs)((regs)->gprs[2]) + #define profile_pc(regs) instruction_pointer(regs) + extern void show_regs(struct pt_regs * regs); +--- /dev/null ++++ b/arch/s390/include/asm/syscall.h +@@ -0,0 +1,80 @@ ++/* ++ * Access to user system call parameters and results ++ * ++ * Copyright IBM Corp. 2008 ++ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License (version 2 only) ++ * as published by the Free Software Foundation. ++ */ ++ ++#ifndef _ASM_SYSCALL_H ++#define _ASM_SYSCALL_H 1 ++ ++#include ++ ++static inline long syscall_get_nr(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ if (regs->trap != __LC_SVC_OLD_PSW) ++ return -1; ++ return regs->gprs[2]; ++} ++ ++static inline void syscall_rollback(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ regs->gprs[2] = regs->orig_gpr2; ++} ++ ++static inline long syscall_get_error(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0; ++} ++ ++static inline long syscall_get_return_value(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++ return regs->gprs[2]; ++} ++ ++static inline void syscall_set_return_value(struct task_struct *task, ++ struct pt_regs *regs, ++ int error, long val) ++{ ++ regs->gprs[2] = error ? -error : val; ++} ++ ++static inline void syscall_get_arguments(struct task_struct *task, ++ struct pt_regs *regs, ++ unsigned int i, unsigned int n, ++ unsigned long *args) ++{ ++ BUG_ON(i + n > 6); ++#ifdef CONFIG_COMPAT ++ if (test_tsk_thread_flag(task, TIF_31BIT)) { ++ if (i + n == 6) ++ args[--n] = (u32) regs->args[0]; ++ while (n-- > 0) ++ args[n] = (u32) regs->gprs[2 + i + n]; ++ } ++#endif ++ if (i + n == 6) ++ args[--n] = regs->args[0]; ++ memcpy(args, ®s->gprs[2 + i], n * sizeof(args[0])); ++} ++ ++static inline void syscall_set_arguments(struct task_struct *task, ++ struct pt_regs *regs, ++ unsigned int i, unsigned int n, ++ const unsigned long *args) ++{ ++ BUG_ON(i + n > 6); ++ if (i + n == 6) ++ regs->args[0] = args[--n]; ++ memcpy(®s->gprs[2 + i], args, n * sizeof(args[0])); ++} ++ ++#endif /* _ASM_SYSCALL_H */ +--- a/arch/s390/include/asm/thread_info.h ++++ b/arch/s390/include/asm/thread_info.h +@@ -86,6 +86,7 @@ static inline struct thread_info *curren + * thread information flags bit numbers + */ + #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ ++#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ + #define TIF_SIGPENDING 2 /* signal pending */ + #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ + #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ +@@ -101,6 +102,7 @@ static inline struct thread_info *curren + #define TIF_FREEZE 21 + + #define _TIF_SYSCALL_TRACE (1< + #include + #include ++#include + + #include + #include +@@ -639,40 +640,58 @@ long compat_arch_ptrace(struct task_stru + } + #endif + +-asmlinkage void +-syscall_trace(struct pt_regs *regs, int entryexit) ++asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) + { +- if (unlikely(current->audit_context) && entryexit) +- audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); +- +- if (!test_thread_flag(TIF_SYSCALL_TRACE)) +- goto out; +- if (!(current->ptrace & PT_PTRACED)) +- goto out; +- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) +- ? 0x80 : 0)); ++ long ret; + + /* +- * If the debuffer has set an invalid system call number, +- * we prepare to skip the system call restart handling. ++ * The sysc_tracesys code in entry.S stored the system ++ * call number to gprs[2]. + */ +- if (!entryexit && regs->gprs[2] >= NR_syscalls) ++ ++ if (is_self_ptracing(regs->gprs[2])) { ++ struct siginfo info; ++ ++ memset(&info, 0, sizeof(struct siginfo)); ++ info.si_signo = SIGSYS; ++ info.si_code = SYS_SYSCALL; ++ info.si_errno = regs->gprs[2]; ++ info.si_addr = (void *)regs->orig_gpr2; ++ send_sig_info(SIGSYS, &info, current); ++ regs->gprs[2] = -1; ++ return -1L; ++ } ++ ++ ret = regs->gprs[2]; ++ if (test_thread_flag(TIF_SYSCALL_TRACE) && ++ (tracehook_report_syscall_entry(regs) || ++ regs->gprs[2] >= NR_syscalls)) { ++ /* ++ * Tracing decided this syscall should not happen or the ++ * debugger stored an invalid system call number. Skip ++ * the system call and the system call restart handling. ++ */ + regs->trap = -1; ++ ret = -1; ++ } + +- /* +- * this isn't the same as continuing with a signal, but it will do +- * for normal use. strace only continues with a signal if the +- * stopping signal is not SIGTRAP. -brl +- */ +- if (current->exit_code) { +- send_sig(current->exit_code, current, 1); +- current->exit_code = 0; +- } +- out: +- if (unlikely(current->audit_context) && !entryexit) +- audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, +- regs->gprs[2], regs->orig_gpr2, regs->gprs[3], +- regs->gprs[4], regs->gprs[5]); ++ if (unlikely(current->audit_context)) ++ audit_syscall_entry(test_thread_flag(TIF_31BIT) ? ++ AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, ++ regs->gprs[2], regs->orig_gpr2, ++ regs->gprs[3], regs->gprs[4], ++ regs->gprs[5]); ++ return ret; ++} ++ ++asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) ++{ ++ if (unlikely(current->audit_context)) ++ audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), ++ regs->gprs[2]); ++ ++ if (test_thread_flag(TIF_SYSCALL_TRACE)) ++ tracehook_report_syscall_exit(regs, 0); + } + + /* +--- a/arch/s390/kernel/signal.c ++++ b/arch/s390/kernel/signal.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -504,6 +505,12 @@ void do_signal(struct pt_regs *regs) + */ + if (current->thread.per_info.single_step) + set_thread_flag(TIF_SINGLE_STEP); ++ ++ /* ++ * Let tracing know that we've done the handler setup. ++ */ ++ tracehook_signal_handler(signr, &info, &ka, regs, ++ test_thread_flag(TIF_SINGLE_STEP)); + } + return; + } +@@ -523,3 +530,9 @@ void do_signal(struct pt_regs *regs) + set_thread_flag(TIF_RESTART_SVC); + } + } ++ ++void do_notify_resume(struct pt_regs *regs) ++{ ++ clear_thread_flag(TIF_NOTIFY_RESUME); ++ tracehook_notify_resume(regs); ++} diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints-documentation-fix-teardown.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-documentation-fix-teardown.patch new file mode 100644 index 000000000..8090db48a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-documentation-fix-teardown.patch @@ -0,0 +1,39 @@ +From: Mathieu Desnoyers +Subject: Tracepoints : documentation fix teardown + +Need a tracepoint_synchronize_unregister() before the end of exit() to make sure +every probe callers have exited the non preemptible section and thus are not +executing the probe code anymore. + +Signed-off-by: Mathieu Desnoyers +CC: Rusty Russell +CC: "Frank Ch. Eigler" +CC: Ingo Molnar +CC: Peter Zijlstra +CC: Steven Rostedt +Acked-by: Jan Blunck +--- + Documentation/tracepoints.txt | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +Index: linux-2.6-lttng/Documentation/tracepoints.txt +=================================================================== +--- linux-2.6-lttng.orig/Documentation/tracepoints.txt 2008-07-31 09:22:56.000000000 -0400 ++++ linux-2.6-lttng/Documentation/tracepoints.txt 2008-07-31 09:24:54.000000000 -0400 +@@ -68,10 +68,12 @@ Where : + Connecting a function (probe) to a tracepoint is done by providing a probe + (function to call) for the specific tracepoint through + register_trace_subsys_eventname(). Removing a probe is done through +-unregister_trace_subsys_eventname(); it will remove the probe sure there is no +-caller left using the probe when it returns. Probe removal is preempt-safe +-because preemption is disabled around the probe call. See the "Probe example" +-section below for a sample probe module. ++unregister_trace_subsys_eventname(); it will remove the probe. ++marker_synchronize_unregister() must be called before the end of the module exit ++function to make sure there is no caller left using the probe. This, and the ++fact that preemption is disabled around the probe call, make sure that probe ++removal and module unload are safe. See the "Probe example" section below for a ++sample probe module. + + The tracepoint mechanism supports inserting multiple instances of the same + tracepoint, but a single definition must be made of a given tracepoint name over diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints-documentation.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-documentation.patch new file mode 100644 index 000000000..981da8345 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-documentation.patch @@ -0,0 +1,125 @@ +From: Mathieu Desnoyers +Subject: Tracepoints Documentation + +Documentation of tracepoint usage. + +Signed-off-by: Mathieu Desnoyers +Acked-by: 'Peter Zijlstra' +CC: Masami Hiramatsu +CC: "Frank Ch. Eigler" +CC: 'Ingo Molnar' +CC: 'Hideo AOKI' +CC: Takashi Nishiie +CC: 'Steven Rostedt' +CC: Eduard - Gabriel Munteanu +Acked-by: Jan Blunck +--- + Documentation/tracepoints.txt | 101 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 101 insertions(+) + +Index: linux-2.6-lttng/Documentation/tracepoints.txt +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/Documentation/tracepoints.txt 2008-07-18 12:15:32.000000000 -0400 +@@ -0,0 +1,101 @@ ++ Using the Linux Kernel Tracepoints ++ ++ Mathieu Desnoyers ++ ++ ++This document introduces Linux Kernel Tracepoints and their use. It provides ++examples of how to insert tracepoints in the kernel and connect probe functions ++to them and provides some examples of probe functions. ++ ++ ++* Purpose of tracepoints ++ ++A tracepoint placed in code provides a hook to call a function (probe) that you ++can provide at runtime. A tracepoint can be "on" (a probe is connected to it) or ++"off" (no probe is attached). When a tracepoint is "off" it has no effect, ++except for adding a tiny time penalty (checking a condition for a branch) and ++space penalty (adding a few bytes for the function call at the end of the ++instrumented function and adds a data structure in a separate section). When a ++tracepoint is "on", the function you provide is called each time the tracepoint ++is executed, in the execution context of the caller. When the function provided ++ends its execution, it returns to the caller (continuing from the tracepoint ++site). ++ ++You can put tracepoints at important locations in the code. They are ++lightweight hooks that can pass an arbitrary number of parameters, ++which prototypes are described in a tracepoint declaration placed in a header ++file. ++ ++They can be used for tracing and performance accounting. ++ ++ ++* Usage ++ ++Two elements are required for tracepoints : ++ ++- A tracepoint definition, placed in a header file. ++- The tracepoint statement, in C code. ++ ++In order to use tracepoints, you should include linux/tracepoint.h. ++ ++In include/trace/subsys.h : ++ ++#include ++ ++DEFINE_TRACE(subsys_eventname, ++ TPPTOTO(int firstarg, struct task_struct *p), ++ TPARGS(firstarg, p)); ++ ++In subsys/file.c (where the tracing statement must be added) : ++ ++#include ++ ++void somefct(void) ++{ ++ ... ++ trace_subsys_eventname(arg, task); ++ ... ++} ++ ++Where : ++- subsys_eventname is an identifier unique to your event ++ - subsys is the name of your subsystem. ++ - eventname is the name of the event to trace. ++- TPPTOTO(int firstarg, struct task_struct *p) is the prototype of the function ++ called by this tracepoint. ++- TPARGS(firstarg, p) are the parameters names, same as found in the prototype. ++ ++Connecting a function (probe) to a tracepoint is done by providing a probe ++(function to call) for the specific tracepoint through ++register_trace_subsys_eventname(). Removing a probe is done through ++unregister_trace_subsys_eventname(); it will remove the probe sure there is no ++caller left using the probe when it returns. Probe removal is preempt-safe ++because preemption is disabled around the probe call. See the "Probe example" ++section below for a sample probe module. ++ ++The tracepoint mechanism supports inserting multiple instances of the same ++tracepoint, but a single definition must be made of a given tracepoint name over ++all the kernel to make sure no type conflict will occur. Name mangling of the ++tracepoints is done using the prototypes to make sure typing is correct. ++Verification of probe type correctness is done at the registration site by the ++compiler. Tracepoints can be put in inline functions, inlined static functions, ++and unrolled loops as well as regular functions. ++ ++The naming scheme "subsys_event" is suggested here as a convention intended ++to limit collisions. Tracepoint names are global to the kernel: they are ++considered as being the same whether they are in the core kernel image or in ++modules. ++ ++ ++* Probe / tracepoint example ++ ++See the example provided in samples/tracepoints/src ++ ++Compile them with your kernel. ++ ++Run, as root : ++modprobe tracepoint-example (insmod order is not important) ++modprobe tracepoint-probe-example ++cat /proc/tracepoint-example (returns an expected error) ++rmmod tracepoint-example tracepoint-probe-example ++dmesg diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints-samples-fix-teardown.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-samples-fix-teardown.patch new file mode 100644 index 000000000..95dd907be --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-samples-fix-teardown.patch @@ -0,0 +1,43 @@ +From: Mathieu Desnoyers +Subject: Tracepoints : Samples fix teardown + +Need a tracepoint_synchronize_unregister() before the end of exit() to make sure +every probe callers have exited the non preemptible section and thus are not +executing the probe code anymore. + +Signed-off-by: Mathieu Desnoyers +CC: Rusty Russell +CC: "Frank Ch. Eigler" +CC: Ingo Molnar +CC: Peter Zijlstra +CC: Steven Rostedt +Acked-by: Jan Blunck +--- + samples/tracepoints/tracepoint-probe-sample.c | 1 + + samples/tracepoints/tracepoint-probe-sample2.c | 1 + + 2 files changed, 2 insertions(+) + +Index: linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample.c +=================================================================== +--- linux-2.6-lttng.orig/samples/tracepoints/tracepoint-probe-sample.c 2008-07-31 09:26:51.000000000 -0400 ++++ linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample.c 2008-07-31 09:26:52.000000000 -0400 +@@ -46,6 +46,7 @@ void __exit tp_sample_trace_exit(void) + { + unregister_trace_subsys_eventb(probe_subsys_eventb); + unregister_trace_subsys_event(probe_subsys_event); ++ tracepoint_synchronize_unregister(); + } + + module_exit(tp_sample_trace_exit); +Index: linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample2.c +=================================================================== +--- linux-2.6-lttng.orig/samples/tracepoints/tracepoint-probe-sample2.c 2008-07-31 09:26:51.000000000 -0400 ++++ linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample2.c 2008-07-31 09:26:52.000000000 -0400 +@@ -33,6 +33,7 @@ module_init(tp_sample_trace_init); + void __exit tp_sample_trace_exit(void) + { + unregister_trace_subsys_event(probe_subsys_event); ++ tracepoint_synchronize_unregister(); + } + + module_exit(tp_sample_trace_exit); diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints-samples.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-samples.patch new file mode 100644 index 000000000..35a282911 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-samples.patch @@ -0,0 +1,245 @@ +From: Mathieu Desnoyers +Subject: Tracepoints Samples + +Tracepoint example code under samples/. + +Signed-off-by: Mathieu Desnoyers +Acked-by: 'Peter Zijlstra' +CC: Masami Hiramatsu +CC: "Frank Ch. Eigler" +CC: 'Ingo Molnar' +CC: 'Hideo AOKI' +CC: Takashi Nishiie +CC: 'Steven Rostedt' +CC: Eduard - Gabriel Munteanu +Acked-by: Jan Blunck +--- + samples/Kconfig | 6 ++ + samples/Makefile | 2 + samples/tracepoints/Makefile | 6 ++ + samples/tracepoints/tp-samples-trace.h | 13 +++++ + samples/tracepoints/tracepoint-probe-sample.c | 55 +++++++++++++++++++++++++ + samples/tracepoints/tracepoint-probe-sample2.c | 42 +++++++++++++++++++ + samples/tracepoints/tracepoint-sample.c | 53 ++++++++++++++++++++++++ + 7 files changed, 176 insertions(+), 1 deletion(-) + +Index: linux-2.6-lttng/samples/Kconfig +=================================================================== +--- linux-2.6-lttng.orig/samples/Kconfig 2008-07-07 09:59:25.000000000 -0400 ++++ linux-2.6-lttng/samples/Kconfig 2008-07-07 10:00:07.000000000 -0400 +@@ -13,6 +13,12 @@ config SAMPLE_MARKERS + help + This build markers example modules. + ++config SAMPLE_TRACEPOINTS ++ tristate "Build tracepoints examples -- loadable modules only" ++ depends on TRACEPOINTS && m ++ help ++ This build tracepoints example modules. ++ + config SAMPLE_KOBJECT + tristate "Build kobject examples" + help +Index: linux-2.6-lttng/samples/tracepoints/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/samples/tracepoints/Makefile 2008-07-07 10:53:09.000000000 -0400 +@@ -0,0 +1,6 @@ ++# builds the tracepoint example kernel modules; ++# then to use one (as root): insmod ++ ++obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-sample.o ++obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample.o ++obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample2.o +Index: linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample.c 2008-07-07 10:50:26.000000000 -0400 +@@ -0,0 +1,55 @@ ++/* ++ * tracepoint-probe-sample.c ++ * ++ * sample tracepoint probes. ++ */ ++ ++#include ++#include ++#include ++#include "tp-samples-trace.h" ++ ++/* ++ * Here the caller only guarantees locking for struct file and struct inode. ++ * Locking must therefore be done in the probe to use the dentry. ++ */ ++static void probe_subsys_event(struct inode *inode, struct file *file) ++{ ++ path_get(&file->f_path); ++ dget(file->f_path.dentry); ++ printk(KERN_INFO "Event is encountered with filename %s\n", ++ file->f_path.dentry->d_name.name); ++ dput(file->f_path.dentry); ++ path_put(&file->f_path); ++} ++ ++static void probe_subsys_eventb(void) ++{ ++ printk(KERN_INFO "Event B is encountered\n"); ++} ++ ++int __init tp_sample_trace_init(void) ++{ ++ int ret; ++ ++ ret = register_trace_subsys_event(probe_subsys_event); ++ WARN_ON(ret); ++ ret = register_trace_subsys_eventb(probe_subsys_eventb); ++ WARN_ON(ret); ++ ++ return 0; ++} ++ ++module_init(tp_sample_trace_init); ++ ++void __exit tp_sample_trace_exit(void) ++{ ++ unregister_trace_subsys_eventb(probe_subsys_eventb); ++ unregister_trace_subsys_event(probe_subsys_event); ++} ++ ++module_exit(tp_sample_trace_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mathieu Desnoyers"); ++MODULE_DESCRIPTION("Tracepoint Probes Samples"); +Index: linux-2.6-lttng/samples/tracepoints/tracepoint-sample.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/samples/tracepoints/tracepoint-sample.c 2008-07-07 10:04:16.000000000 -0400 +@@ -0,0 +1,53 @@ ++/* tracepoint-sample.c ++ * ++ * Executes a tracepoint when /proc/tracepoint-example is opened. ++ * ++ * (C) Copyright 2007 Mathieu Desnoyers ++ * ++ * This file is released under the GPLv2. ++ * See the file COPYING for more details. ++ */ ++ ++#include ++#include ++#include ++#include "tp-samples-trace.h" ++ ++struct proc_dir_entry *pentry_example; ++ ++static int my_open(struct inode *inode, struct file *file) ++{ ++ int i; ++ ++ trace_subsys_event(inode, file); ++ for (i = 0; i < 10; i++) ++ trace_subsys_eventb(); ++ return -EPERM; ++} ++ ++static struct file_operations mark_ops = { ++ .open = my_open, ++}; ++ ++static int example_init(void) ++{ ++ printk(KERN_ALERT "example init\n"); ++ pentry_example = proc_create("tracepoint-example", 0444, NULL, ++ &mark_ops); ++ if (!pentry_example) ++ return -EPERM; ++ return 0; ++} ++ ++static void example_exit(void) ++{ ++ printk(KERN_ALERT "example exit\n"); ++ remove_proc_entry("tracepoint-example", NULL); ++} ++ ++module_init(example_init) ++module_exit(example_exit) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mathieu Desnoyers"); ++MODULE_DESCRIPTION("Tracepoint example"); +Index: linux-2.6-lttng/samples/tracepoints/tp-samples-trace.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/samples/tracepoints/tp-samples-trace.h 2008-07-07 10:06:26.000000000 -0400 +@@ -0,0 +1,13 @@ ++#ifndef _TP_SAMPLES_TRACE_H ++#define _TP_SAMPLES_TRACE_H ++ ++#include /* for struct inode and struct file */ ++#include ++ ++DEFINE_TRACE(subsys_event, ++ TPPROTO(struct inode *inode, struct file *file), ++ TPARGS(inode, file)); ++DEFINE_TRACE(subsys_eventb, ++ TPPROTO(void), ++ TPARGS()); ++#endif +Index: linux-2.6-lttng/samples/Makefile +=================================================================== +--- linux-2.6-lttng.orig/samples/Makefile 2008-07-07 10:44:50.000000000 -0400 ++++ linux-2.6-lttng/samples/Makefile 2008-07-07 10:44:59.000000000 -0400 +@@ -1,3 +1,3 @@ + # Makefile for Linux samples code + +-obj-$(CONFIG_SAMPLES) += markers/ kobject/ kprobes/ ++obj-$(CONFIG_SAMPLES) += markers/ kobject/ kprobes/ tracepoints/ +Index: linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample2.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6-lttng/samples/tracepoints/tracepoint-probe-sample2.c 2008-07-07 10:56:09.000000000 -0400 +@@ -0,0 +1,42 @@ ++/* ++ * tracepoint-probe-sample2.c ++ * ++ * 2nd sample tracepoint probes. ++ */ ++ ++#include ++#include ++#include "tp-samples-trace.h" ++ ++/* ++ * Here the caller only guarantees locking for struct file and struct inode. ++ * Locking must therefore be done in the probe to use the dentry. ++ */ ++static void probe_subsys_event(struct inode *inode, struct file *file) ++{ ++ printk(KERN_INFO "Event is encountered with inode number %lu\n", ++ inode->i_ino); ++} ++ ++int __init tp_sample_trace_init(void) ++{ ++ int ret; ++ ++ ret = register_trace_subsys_event(probe_subsys_event); ++ WARN_ON(ret); ++ ++ return 0; ++} ++ ++module_init(tp_sample_trace_init); ++ ++void __exit tp_sample_trace_exit(void) ++{ ++ unregister_trace_subsys_event(probe_subsys_event); ++} ++ ++module_exit(tp_sample_trace_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Mathieu Desnoyers"); ++MODULE_DESCRIPTION("Tracepoint Probes Samples"); diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints-tracepoint-synchronize-unregister.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-tracepoint-synchronize-unregister.patch new file mode 100644 index 000000000..7866e1bb4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-tracepoint-synchronize-unregister.patch @@ -0,0 +1,34 @@ +From: Mathieu Desnoyers +Subject: Tracepoints : tracepoint_synchronize_unregister() + +Create tracepoint_synchronize_unregister() which must be called before the end +of exit() to make sure every probe callers have exited the non preemptible +section and thus are not executing the probe code anymore. + +Signed-off-by: Mathieu Desnoyers +CC: Rusty Russell +CC: "Frank Ch. Eigler" +CC: Ingo Molnar +CC: Peter Zijlstra +CC: Steven Rostedt +Acked-by: Jan Blunck +--- + include/linux/tracepoint.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: linux-2.6-lttng/include/linux/tracepoint.h +=================================================================== +--- linux-2.6-lttng.orig/include/linux/tracepoint.h 2008-07-31 09:21:40.000000000 -0400 ++++ linux-2.6-lttng/include/linux/tracepoint.h 2008-07-31 09:22:27.000000000 -0400 +@@ -124,4 +124,11 @@ extern void tracepoint_iter_reset(struct + extern int tracepoint_get_iter_range(struct tracepoint **tracepoint, + struct tracepoint *begin, struct tracepoint *end); + ++/* ++ * tracepoint_synchronize_unregister must be called between the last tracepoint ++ * probe unregistration and the end of module exit to make sure there is no ++ * caller executing a probe when it is freed. ++ */ ++#define tracepoint_synchronize_unregister() synchronize_sched() ++ + #endif diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints-use-table-size-macro.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-use-table-size-macro.patch new file mode 100644 index 000000000..63f17720f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints-use-table-size-macro.patch @@ -0,0 +1,58 @@ +From: Mathieu Desnoyers +Subject: Tracepoints use TABLE_SIZE macro + +Steven Rostedt : + +Wouldn't it look nicer to have: (TRACEPOINT_TABLE_SIZE - 1) ? + +me : + +Sure, + +Signed-off-by: Mathieu Desnoyers +CC: Steven Rostedt +CC: akpm@linux-foundation.org +CC: Ingo Molnar +CC: Peter Zijlstra +CC: Masami Hiramatsu +CC: "Frank Ch. Eigler" +CC: Hideo AOKI +CC: Takashi Nishiie +CC: Alexander Viro +CC: Eduard - Gabriel Munteanu +Acked-by: Jan Blunck +--- + kernel/tracepoint.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +Index: linux-2.6-lttng/kernel/tracepoint.c +=================================================================== +--- linux-2.6-lttng.orig/kernel/tracepoint.c 2008-07-24 16:33:52.000000000 -0400 ++++ linux-2.6-lttng/kernel/tracepoint.c 2008-07-24 16:34:57.000000000 -0400 +@@ -177,7 +177,7 @@ static struct tracepoint_entry *get_trac + struct tracepoint_entry *e; + u32 hash = jhash(name, strlen(name), 0); + +- head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)]; ++ head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; + hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) + return e; +@@ -197,7 +197,7 @@ static struct tracepoint_entry *add_trac + size_t name_len = strlen(name) + 1; + u32 hash = jhash(name, name_len-1, 0); + +- head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)]; ++ head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; + hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) { + printk(KERN_NOTICE +@@ -233,7 +233,7 @@ static int remove_tracepoint(const char + size_t len = strlen(name) + 1; + u32 hash = jhash(name, len-1, 0); + +- head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)]; ++ head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; + hlist_for_each_entry(e, node, head, hlist) { + if (!strcmp(name, e->name)) { + found = 1; diff --git a/src/patches/suse-2.6.27.31/patches.trace/tracepoints.patch b/src/patches/suse-2.6.27.31/patches.trace/tracepoints.patch new file mode 100644 index 000000000..316815aa1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/tracepoints.patch @@ -0,0 +1,1020 @@ +From: Mathieu Desnoyers +Subject: Kernel Tracepoints + +Implementation of kernel tracepoints. Inspired from the Linux Kernel Markers. +Allows complete typing verification by declaring both tracing statement inline +functions and probe registration/unregistration static inline functions within +the same macro "DEFINE_TRACE". No format string is required. See the +tracepoint Documentation and Samples patches for usage examples. + +Taken from the documentation patch : + +"A tracepoint placed in code provides a hook to call a function (probe) that you +can provide at runtime. A tracepoint can be "on" (a probe is connected to it) or +"off" (no probe is attached). When a tracepoint is "off" it has no effect, +except for adding a tiny time penalty (checking a condition for a branch) and +space penalty (adding a few bytes for the function call at the end of the +instrumented function and adds a data structure in a separate section). When a +tracepoint is "on", the function you provide is called each time the tracepoint +is executed, in the execution context of the caller. When the function provided +ends its execution, it returns to the caller (continuing from the tracepoint +site). + +You can put tracepoints at important locations in the code. They are lightweight +hooks that can pass an arbitrary number of parameters, which prototypes are +described in a tracepoint declaration placed in a header file." + +Addition and removal of tracepoints is synchronized by RCU using the +scheduler (and preempt_disable) as guarantees to find a quiescent state +(this is really RCU "classic"). The update side uses rcu_barrier_sched() +with call_rcu_sched() and the read/execute side uses +"preempt_disable()/preempt_enable()". + +We make sure the previous array containing probes, which has been scheduled for +deletion by the rcu callback, is indeed freed before we proceed to the next +update. It therefore limits the rate of modification of a single tracepoint to +one update per RCU period. The objective here is to permit fast batch +add/removal of probes on _different_ tracepoints. + +Changelog : +- Use #name ":" #proto as string to identify the tracepoint in the + tracepoint table. This will make sure not type mismatch happens due to + connexion of a probe with the wrong type to a tracepoint declared with + the same name in a different header. +- Add tracepoint_entry_free_old. +- Change __TO_TRACE to get rid of the 'i' iterator. + +Masami Hiramatsu : +Tested on x86-64. + +Performance impact of a tracepoint : same as markers, except that it adds about +70 bytes of instructions in an unlikely branch of each instrumented function +(the for loop, the stack setup and the function call). It currently adds a +memory read, a test and a conditional branch at the instrumentation site (in the +hot path). Immediate values will eventually change this into a load immediate, +test and branch, which removes the memory read which will make the i-cache +impact smaller (changing the memory read for a load immediate removes 3-4 bytes +per site on x86_32 (depending on mov prefixes), or 7-8 bytes on x86_64, it also +saves the d-cache hit). + +About the performance impact of tracepoints (which is comparable to markers), +even without immediate values optimizations, tests done by Hideo Aoki on ia64 +show no regression. His test case was using hackbench on a kernel where +scheduler instrumentation (about 5 events in code scheduler code) was added. + + +Quoting Hideo Aoki about Markers : + +I evaluated overhead of kernel marker using linux-2.6-sched-fixes +git tree, which includes several markers for LTTng, using an ia64 +server. + +While the immediate trace mark feature isn't implemented on ia64, +there is no major performance regression. So, I think that we +don't have any issues to propose merging marker point patches +into Linus's tree from the viewpoint of performance impact. + +I prepared two kernels to evaluate. The first one was compiled +without CONFIG_MARKERS. The second one was enabled CONFIG_MARKERS. + +I downloaded the original hackbench from the following URL: +http://devresources.linux-foundation.org/craiger/hackbench/src/hackbench.c + +I ran hackbench 5 times in each condition and calculated the +average and difference between the kernels. + + The parameter of hackbench: every 50 from 50 to 800 + The number of CPUs of the server: 2, 4, and 8 + +Below is the results. As you can see, major performance +regression wasn't found in any case. Even if number of processes +increases, differences between marker-enabled kernel and marker- +disabled kernel doesn't increase. Moreover, if number of CPUs +increases, the differences doesn't increase either. + +Curiously, marker-enabled kernel is better than marker-disabled +kernel in more than half cases, although I guess it comes from +the difference of memory access pattern. + + +* 2 CPUs + +Number of | without | with | diff | diff | +processes | Marker [Sec] | Marker [Sec] | [Sec] | [%] | +-------------------------------------------------------------- + 50 | 4.811 | 4.872 | +0.061 | +1.27 | + 100 | 9.854 | 10.309 | +0.454 | +4.61 | + 150 | 15.602 | 15.040 | -0.562 | -3.6 | + 200 | 20.489 | 20.380 | -0.109 | -0.53 | + 250 | 25.798 | 25.652 | -0.146 | -0.56 | + 300 | 31.260 | 30.797 | -0.463 | -1.48 | + 350 | 36.121 | 35.770 | -0.351 | -0.97 | + 400 | 42.288 | 42.102 | -0.186 | -0.44 | + 450 | 47.778 | 47.253 | -0.526 | -1.1 | + 500 | 51.953 | 52.278 | +0.325 | +0.63 | + 550 | 58.401 | 57.700 | -0.701 | -1.2 | + 600 | 63.334 | 63.222 | -0.112 | -0.18 | + 650 | 68.816 | 68.511 | -0.306 | -0.44 | + 700 | 74.667 | 74.088 | -0.579 | -0.78 | + 750 | 78.612 | 79.582 | +0.970 | +1.23 | + 800 | 85.431 | 85.263 | -0.168 | -0.2 | +-------------------------------------------------------------- + +* 4 CPUs + +Number of | without | with | diff | diff | +processes | Marker [Sec] | Marker [Sec] | [Sec] | [%] | +-------------------------------------------------------------- + 50 | 2.586 | 2.584 | -0.003 | -0.1 | + 100 | 5.254 | 5.283 | +0.030 | +0.56 | + 150 | 8.012 | 8.074 | +0.061 | +0.76 | + 200 | 11.172 | 11.000 | -0.172 | -1.54 | + 250 | 13.917 | 14.036 | +0.119 | +0.86 | + 300 | 16.905 | 16.543 | -0.362 | -2.14 | + 350 | 19.901 | 20.036 | +0.135 | +0.68 | + 400 | 22.908 | 23.094 | +0.186 | +0.81 | + 450 | 26.273 | 26.101 | -0.172 | -0.66 | + 500 | 29.554 | 29.092 | -0.461 | -1.56 | + 550 | 32.377 | 32.274 | -0.103 | -0.32 | + 600 | 35.855 | 35.322 | -0.533 | -1.49 | + 650 | 39.192 | 38.388 | -0.804 | -2.05 | + 700 | 41.744 | 41.719 | -0.025 | -0.06 | + 750 | 45.016 | 44.496 | -0.520 | -1.16 | + 800 | 48.212 | 47.603 | -0.609 | -1.26 | +-------------------------------------------------------------- + +* 8 CPUs + +Number of | without | with | diff | diff | +processes | Marker [Sec] | Marker [Sec] | [Sec] | [%] | +-------------------------------------------------------------- + 50 | 2.094 | 2.072 | -0.022 | -1.07 | + 100 | 4.162 | 4.273 | +0.111 | +2.66 | + 150 | 6.485 | 6.540 | +0.055 | +0.84 | + 200 | 8.556 | 8.478 | -0.078 | -0.91 | + 250 | 10.458 | 10.258 | -0.200 | -1.91 | + 300 | 12.425 | 12.750 | +0.325 | +2.62 | + 350 | 14.807 | 14.839 | +0.032 | +0.22 | + 400 | 16.801 | 16.959 | +0.158 | +0.94 | + 450 | 19.478 | 19.009 | -0.470 | -2.41 | + 500 | 21.296 | 21.504 | +0.208 | +0.98 | + 550 | 23.842 | 23.979 | +0.137 | +0.57 | + 600 | 26.309 | 26.111 | -0.198 | -0.75 | + 650 | 28.705 | 28.446 | -0.259 | -0.9 | + 700 | 31.233 | 31.394 | +0.161 | +0.52 | + 750 | 34.064 | 33.720 | -0.344 | -1.01 | + 800 | 36.320 | 36.114 | -0.206 | -0.57 | +-------------------------------------------------------------- + +Best regards, +Hideo + + +P.S. When I compiled the linux-2.6-sched-fixes tree on ia64, I +had to revert the following git commit since pteval_t is defined +on x86 only. + +commit 8686f2b37e7394b51dd6593678cbfd85ecd28c65 +Date: Tue May 6 15:42:40 2008 -0700 + + generic, x86, PAT: fix mprotect + + +Signed-off-by: Mathieu Desnoyers +Acked-by: Masami Hiramatsu +Acked-by: 'Peter Zijlstra' +CC: "Frank Ch. Eigler" +CC: 'Ingo Molnar' +CC: 'Hideo AOKI' +CC: Takashi Nishiie +CC: 'Steven Rostedt' +CC: Alexander Viro +CC: Eduard - Gabriel Munteanu +Acked-by: Jan Blunck +--- + include/asm-generic/vmlinux.lds.h | 6 + include/linux/module.h | 18 + + include/linux/tracepoint.h | 127 ++++++++++ + init/Kconfig | 7 + kernel/Makefile | 1 + kernel/module.c | 67 +++++ + kernel/tracepoint.c | 476 ++++++++++++++++++++++++++++++++++++++ + 7 files changed, 700 insertions(+), 2 deletions(-) + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -52,7 +52,10 @@ + . = ALIGN(8); \ + VMLINUX_SYMBOL(__start___markers) = .; \ + *(__markers) \ +- VMLINUX_SYMBOL(__stop___markers) = .; ++ VMLINUX_SYMBOL(__stop___markers) = .; \ ++ VMLINUX_SYMBOL(__start___tracepoints) = .; \ ++ *(__tracepoints) \ ++ VMLINUX_SYMBOL(__stop___tracepoints) = .; + + #define RO_DATA(align) \ + . = ALIGN((align)); \ +@@ -61,6 +64,7 @@ + *(.rodata) *(.rodata.*) \ + *(__vermagic) /* Kernel version magic */ \ + *(__markers_strings) /* Markers: strings */ \ ++ *(__tracepoints_strings)/* Tracepoints: strings */ \ + } \ + \ + .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -332,6 +333,11 @@ struct module + unsigned int num_markers; + #endif + ++#ifdef CONFIG_TRACEPOINTS ++ struct tracepoint *tracepoints; ++ unsigned int num_tracepoints; ++#endif ++ + #ifdef CONFIG_MODULE_UNLOAD + /* What modules depend on me? */ + struct list_head modules_which_use_me; +@@ -453,6 +459,9 @@ extern void print_modules(void); + + extern void module_update_markers(void); + ++extern void module_update_tracepoints(void); ++extern int module_get_iter_tracepoints(struct tracepoint_iter *iter); ++ + #else /* !CONFIG_MODULES... */ + #define EXPORT_SYMBOL(sym) + #define EXPORT_SYMBOL_GPL(sym) +@@ -557,6 +566,15 @@ static inline void module_update_markers + { + } + ++static inline void module_update_tracepoints(void) ++{ ++} ++ ++static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter) ++{ ++ return 0; ++} ++ + #endif /* CONFIG_MODULES */ + + struct device_driver; +--- /dev/null ++++ b/include/linux/tracepoint.h +@@ -0,0 +1,127 @@ ++#ifndef _LINUX_TRACEPOINT_H ++#define _LINUX_TRACEPOINT_H ++ ++/* ++ * Kernel Tracepoint API. ++ * ++ * See Documentation/tracepoint.txt. ++ * ++ * (C) Copyright 2008 Mathieu Desnoyers ++ * ++ * Heavily inspired from the Linux Kernel Markers. ++ * ++ * This file is released under the GPLv2. ++ * See the file COPYING for more details. ++ */ ++ ++#include ++#include ++ ++struct module; ++struct tracepoint; ++ ++struct tracepoint { ++ const char *name; /* Tracepoint name */ ++ int state; /* State. */ ++ void **funcs; ++} __attribute__((aligned(8))); ++ ++ ++#define TPPROTO(args...) args ++#define TPARGS(args...) args ++ ++#ifdef CONFIG_TRACEPOINTS ++ ++/* ++ * it_func[0] is never NULL because there is at least one element in the array ++ * when the array itself is non NULL. ++ */ ++#define __DO_TRACE(tp, proto, args) \ ++ do { \ ++ void **it_func; \ ++ \ ++ rcu_read_lock_sched(); \ ++ it_func = rcu_dereference((tp)->funcs); \ ++ if (it_func) { \ ++ do { \ ++ ((void(*)(proto))(*it_func))(args); \ ++ } while (*(++it_func)); \ ++ } \ ++ rcu_read_unlock_sched(); \ ++ } while (0) ++ ++/* ++ * Make sure the alignment of the structure in the __tracepoints section will ++ * not add unwanted padding between the beginning of the section and the ++ * structure. Force alignment to the same alignment as the section start. ++ */ ++#define DEFINE_TRACE(name, proto, args) \ ++ static inline void trace_##name(proto) \ ++ { \ ++ static const char __tpstrtab_##name[] \ ++ __attribute__((section("__tracepoints_strings"))) \ ++ = #name ":" #proto; \ ++ static struct tracepoint __tracepoint_##name \ ++ __attribute__((section("__tracepoints"), aligned(8))) = \ ++ { __tpstrtab_##name, 0, NULL }; \ ++ if (unlikely(__tracepoint_##name.state)) \ ++ __DO_TRACE(&__tracepoint_##name, \ ++ TPPROTO(proto), TPARGS(args)); \ ++ } \ ++ static inline int register_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return tracepoint_probe_register(#name ":" #proto, \ ++ (void *)probe); \ ++ } \ ++ static inline void unregister_trace_##name(void (*probe)(proto))\ ++ { \ ++ tracepoint_probe_unregister(#name ":" #proto, \ ++ (void *)probe); \ ++ } ++ ++extern void tracepoint_update_probe_range(struct tracepoint *begin, ++ struct tracepoint *end); ++ ++#else /* !CONFIG_TRACEPOINTS */ ++#define DEFINE_TRACE(name, proto, args) \ ++ static inline void _do_trace_##name(struct tracepoint *tp, proto) \ ++ { } \ ++ static inline void trace_##name(proto) \ ++ { } \ ++ static inline int register_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline void unregister_trace_##name(void (*probe)(proto))\ ++ { } ++ ++static inline void tracepoint_update_probe_range(struct tracepoint *begin, ++ struct tracepoint *end) ++{ } ++#endif /* CONFIG_TRACEPOINTS */ ++ ++/* ++ * Connect a probe to a tracepoint. ++ * Internal API, should not be used directly. ++ */ ++extern int tracepoint_probe_register(const char *name, void *probe); ++ ++/* ++ * Disconnect a probe from a tracepoint. ++ * Internal API, should not be used directly. ++ */ ++extern int tracepoint_probe_unregister(const char *name, void *probe); ++ ++struct tracepoint_iter { ++ struct module *module; ++ struct tracepoint *tracepoint; ++}; ++ ++extern void tracepoint_iter_start(struct tracepoint_iter *iter); ++extern void tracepoint_iter_next(struct tracepoint_iter *iter); ++extern void tracepoint_iter_stop(struct tracepoint_iter *iter); ++extern void tracepoint_iter_reset(struct tracepoint_iter *iter); ++extern int tracepoint_get_iter_range(struct tracepoint **tracepoint, ++ struct tracepoint *begin, struct tracepoint *end); ++ ++#endif +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -782,6 +782,13 @@ config PROFILING + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + ++config TRACEPOINTS ++ bool "Activate tracepoints" ++ default y ++ help ++ Place an empty function call at each tracepoint site. Can be ++ dynamically changed for a probe function. ++ + config MARKERS + bool "Activate markers" + help +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -84,6 +84,7 @@ obj-$(CONFIG_SYSCTL) += utsname_sysctl.o + obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o + obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o + obj-$(CONFIG_MARKERS) += marker.o ++obj-$(CONFIG_TRACEPOINTS) += tracepoint.o + obj-$(CONFIG_LATENCYTOP) += latencytop.o + obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o + obj-$(CONFIG_FTRACE) += trace/ +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + + #if 0 + #define DEBUGP printk +@@ -1915,6 +1916,8 @@ static noinline struct module *load_modu + #endif + unsigned int markersindex; + unsigned int markersstringsindex; ++ unsigned int tracepointsindex; ++ unsigned int tracepointsstringsindex; + unsigned int verboseindex; + struct module *mod; + long err = 0; +@@ -2206,6 +2209,10 @@ static noinline struct module *load_modu + "__markers_strings"); + verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose"); + ++ tracepointsindex = find_sec(hdr, sechdrs, secstrings, "__tracepoints"); ++ tracepointsstringsindex = find_sec(hdr, sechdrs, secstrings, ++ "__tracepoints_strings"); ++ + /* Now do relocations. */ + for (i = 1; i < hdr->e_shnum; i++) { + const char *strtab = (char *)sechdrs[strindex].sh_addr; +@@ -2232,6 +2239,12 @@ static noinline struct module *load_modu + mod->num_markers = + sechdrs[markersindex].sh_size / sizeof(*mod->markers); + #endif ++#ifdef CONFIG_TRACEPOINTS ++ mod->tracepoints = (void *)sechdrs[tracepointsindex].sh_addr; ++ mod->num_tracepoints = ++ sechdrs[tracepointsindex].sh_size / sizeof(*mod->tracepoints); ++#endif ++ + + /* Find duplicate symbols */ + err = verify_export_symbols(mod); +@@ -2250,11 +2263,16 @@ static noinline struct module *load_modu + + add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); + ++ if (!mod->taints) { + #ifdef CONFIG_MARKERS +- if (!mod->taints) + marker_update_probe_range(mod->markers, + mod->markers + mod->num_markers); + #endif ++#ifdef CONFIG_TRACEPOINTS ++ tracepoint_update_probe_range(mod->tracepoints, ++ mod->tracepoints + mod->num_tracepoints); ++#endif ++ } + dynamic_printk_setup(sechdrs, verboseindex); + err = module_finalize(hdr, sechdrs, mod); + if (err < 0) +@@ -2842,3 +2860,50 @@ void module_update_markers(void) + mutex_unlock(&module_mutex); + } + #endif ++ ++#ifdef CONFIG_TRACEPOINTS ++void module_update_tracepoints(void) ++{ ++ struct module *mod; ++ ++ mutex_lock(&module_mutex); ++ list_for_each_entry(mod, &modules, list) ++ if (!mod->taints) ++ tracepoint_update_probe_range(mod->tracepoints, ++ mod->tracepoints + mod->num_tracepoints); ++ mutex_unlock(&module_mutex); ++} ++ ++/* ++ * Returns 0 if current not found. ++ * Returns 1 if current found. ++ */ ++int module_get_iter_tracepoints(struct tracepoint_iter *iter) ++{ ++ struct module *iter_mod; ++ int found = 0; ++ ++ mutex_lock(&module_mutex); ++ list_for_each_entry(iter_mod, &modules, list) { ++ if (!iter_mod->taints) { ++ /* ++ * Sorted module list ++ */ ++ if (iter_mod < iter->module) ++ continue; ++ else if (iter_mod > iter->module) ++ iter->tracepoint = NULL; ++ found = tracepoint_get_iter_range(&iter->tracepoint, ++ iter_mod->tracepoints, ++ iter_mod->tracepoints ++ + iter_mod->num_tracepoints); ++ if (found) { ++ iter->module = iter_mod; ++ break; ++ } ++ } ++ } ++ mutex_unlock(&module_mutex); ++ return found; ++} ++#endif +--- /dev/null ++++ b/kernel/tracepoint.c +@@ -0,0 +1,476 @@ ++/* ++ * Copyright (C) 2008 Mathieu Desnoyers ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern struct tracepoint __start___tracepoints[]; ++extern struct tracepoint __stop___tracepoints[]; ++ ++/* Set to 1 to enable tracepoint debug output */ ++static const int tracepoint_debug; ++ ++/* ++ * tracepoints_mutex nests inside module_mutex. Tracepoints mutex protects the ++ * builtin and module tracepoints and the hash table. ++ */ ++static DEFINE_MUTEX(tracepoints_mutex); ++ ++/* ++ * Tracepoint hash table, containing the active tracepoints. ++ * Protected by tracepoints_mutex. ++ */ ++#define TRACEPOINT_HASH_BITS 6 ++#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) ++ ++/* ++ * Note about RCU : ++ * It is used to to delay the free of multiple probes array until a quiescent ++ * state is reached. ++ * Tracepoint entries modifications are protected by the tracepoints_mutex. ++ */ ++struct tracepoint_entry { ++ struct hlist_node hlist; ++ void **funcs; ++ int refcount; /* Number of times armed. 0 if disarmed. */ ++ struct rcu_head rcu; ++ void *oldptr; ++ unsigned char rcu_pending:1; ++ char name[0]; ++}; ++ ++static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; ++ ++static void free_old_closure(struct rcu_head *head) ++{ ++ struct tracepoint_entry *entry = container_of(head, ++ struct tracepoint_entry, rcu); ++ kfree(entry->oldptr); ++ /* Make sure we free the data before setting the pending flag to 0 */ ++ smp_wmb(); ++ entry->rcu_pending = 0; ++} ++ ++static void tracepoint_entry_free_old(struct tracepoint_entry *entry, void *old) ++{ ++ if (!old) ++ return; ++ entry->oldptr = old; ++ entry->rcu_pending = 1; ++ /* write rcu_pending before calling the RCU callback */ ++ smp_wmb(); ++#ifdef CONFIG_PREEMPT_RCU ++ synchronize_sched(); /* Until we have the call_rcu_sched() */ ++#endif ++ call_rcu(&entry->rcu, free_old_closure); ++} ++ ++static void debug_print_probes(struct tracepoint_entry *entry) ++{ ++ int i; ++ ++ if (!tracepoint_debug) ++ return; ++ ++ for (i = 0; entry->funcs[i]; i++) ++ printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]); ++} ++ ++static void * ++tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe) ++{ ++ int nr_probes = 0; ++ void **old, **new; ++ ++ WARN_ON(!probe); ++ ++ debug_print_probes(entry); ++ old = entry->funcs; ++ if (old) { ++ /* (N -> N+1), (N != 0, 1) probes */ ++ for (nr_probes = 0; old[nr_probes]; nr_probes++) ++ if (old[nr_probes] == probe) ++ return ERR_PTR(-EEXIST); ++ } ++ /* + 2 : one for new probe, one for NULL func */ ++ new = kzalloc((nr_probes + 2) * sizeof(void *), GFP_KERNEL); ++ if (new == NULL) ++ return ERR_PTR(-ENOMEM); ++ if (old) ++ memcpy(new, old, nr_probes * sizeof(void *)); ++ new[nr_probes] = probe; ++ entry->refcount = nr_probes + 1; ++ entry->funcs = new; ++ debug_print_probes(entry); ++ return old; ++} ++ ++static void * ++tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe) ++{ ++ int nr_probes = 0, nr_del = 0, i; ++ void **old, **new; ++ ++ old = entry->funcs; ++ ++ debug_print_probes(entry); ++ /* (N -> M), (N > 1, M >= 0) probes */ ++ for (nr_probes = 0; old[nr_probes]; nr_probes++) { ++ if ((!probe || old[nr_probes] == probe)) ++ nr_del++; ++ } ++ ++ if (nr_probes - nr_del == 0) { ++ /* N -> 0, (N > 1) */ ++ entry->funcs = NULL; ++ entry->refcount = 0; ++ debug_print_probes(entry); ++ return old; ++ } else { ++ int j = 0; ++ /* N -> M, (N > 1, M > 0) */ ++ /* + 1 for NULL */ ++ new = kzalloc((nr_probes - nr_del + 1) ++ * sizeof(void *), GFP_KERNEL); ++ if (new == NULL) ++ return ERR_PTR(-ENOMEM); ++ for (i = 0; old[i]; i++) ++ if ((probe && old[i] != probe)) ++ new[j++] = old[i]; ++ entry->refcount = nr_probes - nr_del; ++ entry->funcs = new; ++ } ++ debug_print_probes(entry); ++ return old; ++} ++ ++/* ++ * Get tracepoint if the tracepoint is present in the tracepoint hash table. ++ * Must be called with tracepoints_mutex held. ++ * Returns NULL if not present. ++ */ ++static struct tracepoint_entry *get_tracepoint(const char *name) ++{ ++ struct hlist_head *head; ++ struct hlist_node *node; ++ struct tracepoint_entry *e; ++ u32 hash = jhash(name, strlen(name), 0); ++ ++ head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)]; ++ hlist_for_each_entry(e, node, head, hlist) { ++ if (!strcmp(name, e->name)) ++ return e; ++ } ++ return NULL; ++} ++ ++/* ++ * Add the tracepoint to the tracepoint hash table. Must be called with ++ * tracepoints_mutex held. ++ */ ++static struct tracepoint_entry *add_tracepoint(const char *name) ++{ ++ struct hlist_head *head; ++ struct hlist_node *node; ++ struct tracepoint_entry *e; ++ size_t name_len = strlen(name) + 1; ++ u32 hash = jhash(name, name_len-1, 0); ++ ++ head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)]; ++ hlist_for_each_entry(e, node, head, hlist) { ++ if (!strcmp(name, e->name)) { ++ printk(KERN_NOTICE ++ "tracepoint %s busy\n", name); ++ return ERR_PTR(-EEXIST); /* Already there */ ++ } ++ } ++ /* ++ * Using kmalloc here to allocate a variable length element. Could ++ * cause some memory fragmentation if overused. ++ */ ++ e = kmalloc(sizeof(struct tracepoint_entry) + name_len, GFP_KERNEL); ++ if (!e) ++ return ERR_PTR(-ENOMEM); ++ memcpy(&e->name[0], name, name_len); ++ e->funcs = NULL; ++ e->refcount = 0; ++ e->rcu_pending = 0; ++ hlist_add_head(&e->hlist, head); ++ return e; ++} ++ ++/* ++ * Remove the tracepoint from the tracepoint hash table. Must be called with ++ * mutex_lock held. ++ */ ++static int remove_tracepoint(const char *name) ++{ ++ struct hlist_head *head; ++ struct hlist_node *node; ++ struct tracepoint_entry *e; ++ int found = 0; ++ size_t len = strlen(name) + 1; ++ u32 hash = jhash(name, len-1, 0); ++ ++ head = &tracepoint_table[hash & ((1 << TRACEPOINT_HASH_BITS)-1)]; ++ hlist_for_each_entry(e, node, head, hlist) { ++ if (!strcmp(name, e->name)) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) ++ return -ENOENT; ++ if (e->refcount) ++ return -EBUSY; ++ hlist_del(&e->hlist); ++ /* Make sure the call_rcu has been executed */ ++ if (e->rcu_pending) ++ rcu_barrier(); ++ kfree(e); ++ return 0; ++} ++ ++/* ++ * Sets the probe callback corresponding to one tracepoint. ++ */ ++static void set_tracepoint(struct tracepoint_entry **entry, ++ struct tracepoint *elem, int active) ++{ ++ WARN_ON(strcmp((*entry)->name, elem->name) != 0); ++ ++ /* ++ * rcu_assign_pointer has a smp_wmb() which makes sure that the new ++ * probe callbacks array is consistent before setting a pointer to it. ++ * This array is referenced by __DO_TRACE from ++ * include/linux/tracepoints.h. A matching smp_read_barrier_depends() ++ * is used. ++ */ ++ rcu_assign_pointer(elem->funcs, (*entry)->funcs); ++ elem->state = active; ++} ++ ++/* ++ * Disable a tracepoint and its probe callback. ++ * Note: only waiting an RCU period after setting elem->call to the empty ++ * function insures that the original callback is not used anymore. This insured ++ * by preempt_disable around the call site. ++ */ ++static void disable_tracepoint(struct tracepoint *elem) ++{ ++ elem->state = 0; ++} ++ ++/** ++ * tracepoint_update_probe_range - Update a probe range ++ * @begin: beginning of the range ++ * @end: end of the range ++ * ++ * Updates the probe callback corresponding to a range of tracepoints. ++ */ ++void tracepoint_update_probe_range(struct tracepoint *begin, ++ struct tracepoint *end) ++{ ++ struct tracepoint *iter; ++ struct tracepoint_entry *mark_entry; ++ ++ mutex_lock(&tracepoints_mutex); ++ for (iter = begin; iter < end; iter++) { ++ mark_entry = get_tracepoint(iter->name); ++ if (mark_entry) { ++ set_tracepoint(&mark_entry, iter, ++ !!mark_entry->refcount); ++ } else { ++ disable_tracepoint(iter); ++ } ++ } ++ mutex_unlock(&tracepoints_mutex); ++} ++ ++/* ++ * Update probes, removing the faulty probes. ++ */ ++static void tracepoint_update_probes(void) ++{ ++ /* Core kernel tracepoints */ ++ tracepoint_update_probe_range(__start___tracepoints, ++ __stop___tracepoints); ++ /* tracepoints in modules. */ ++ module_update_tracepoints(); ++} ++ ++/** ++ * tracepoint_probe_register - Connect a probe to a tracepoint ++ * @name: tracepoint name ++ * @probe: probe handler ++ * ++ * Returns 0 if ok, error value on error. ++ * The probe address must at least be aligned on the architecture pointer size. ++ */ ++int tracepoint_probe_register(const char *name, void *probe) ++{ ++ struct tracepoint_entry *entry; ++ int ret = 0; ++ void *old; ++ ++ mutex_lock(&tracepoints_mutex); ++ entry = get_tracepoint(name); ++ if (!entry) { ++ entry = add_tracepoint(name); ++ if (IS_ERR(entry)) { ++ ret = PTR_ERR(entry); ++ goto end; ++ } ++ } ++ /* ++ * If we detect that a call_rcu is pending for this tracepoint, ++ * make sure it's executed now. ++ */ ++ if (entry->rcu_pending) ++ rcu_barrier(); ++ old = tracepoint_entry_add_probe(entry, probe); ++ if (IS_ERR(old)) { ++ ret = PTR_ERR(old); ++ goto end; ++ } ++ mutex_unlock(&tracepoints_mutex); ++ tracepoint_update_probes(); /* may update entry */ ++ mutex_lock(&tracepoints_mutex); ++ entry = get_tracepoint(name); ++ WARN_ON(!entry); ++ tracepoint_entry_free_old(entry, old); ++end: ++ mutex_unlock(&tracepoints_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(tracepoint_probe_register); ++ ++/** ++ * tracepoint_probe_unregister - Disconnect a probe from a tracepoint ++ * @name: tracepoint name ++ * @probe: probe function pointer ++ * ++ * We do not need to call a synchronize_sched to make sure the probes have ++ * finished running before doing a module unload, because the module unload ++ * itself uses stop_machine(), which insures that every preempt disabled section ++ * have finished. ++ */ ++int tracepoint_probe_unregister(const char *name, void *probe) ++{ ++ struct tracepoint_entry *entry; ++ void *old; ++ int ret = -ENOENT; ++ ++ mutex_lock(&tracepoints_mutex); ++ entry = get_tracepoint(name); ++ if (!entry) ++ goto end; ++ if (entry->rcu_pending) ++ rcu_barrier(); ++ old = tracepoint_entry_remove_probe(entry, probe); ++ mutex_unlock(&tracepoints_mutex); ++ tracepoint_update_probes(); /* may update entry */ ++ mutex_lock(&tracepoints_mutex); ++ entry = get_tracepoint(name); ++ if (!entry) ++ goto end; ++ tracepoint_entry_free_old(entry, old); ++ remove_tracepoint(name); /* Ignore busy error message */ ++ ret = 0; ++end: ++ mutex_unlock(&tracepoints_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); ++ ++/** ++ * tracepoint_get_iter_range - Get a next tracepoint iterator given a range. ++ * @tracepoint: current tracepoints (in), next tracepoint (out) ++ * @begin: beginning of the range ++ * @end: end of the range ++ * ++ * Returns whether a next tracepoint has been found (1) or not (0). ++ * Will return the first tracepoint in the range if the input tracepoint is ++ * NULL. ++ */ ++int tracepoint_get_iter_range(struct tracepoint **tracepoint, ++ struct tracepoint *begin, struct tracepoint *end) ++{ ++ if (!*tracepoint && begin != end) { ++ *tracepoint = begin; ++ return 1; ++ } ++ if (*tracepoint >= begin && *tracepoint < end) ++ return 1; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(tracepoint_get_iter_range); ++ ++static void tracepoint_get_iter(struct tracepoint_iter *iter) ++{ ++ int found = 0; ++ ++ /* Core kernel tracepoints */ ++ if (!iter->module) { ++ found = tracepoint_get_iter_range(&iter->tracepoint, ++ __start___tracepoints, __stop___tracepoints); ++ if (found) ++ goto end; ++ } ++ /* tracepoints in modules. */ ++ found = module_get_iter_tracepoints(iter); ++end: ++ if (!found) ++ tracepoint_iter_reset(iter); ++} ++ ++void tracepoint_iter_start(struct tracepoint_iter *iter) ++{ ++ tracepoint_get_iter(iter); ++} ++EXPORT_SYMBOL_GPL(tracepoint_iter_start); ++ ++void tracepoint_iter_next(struct tracepoint_iter *iter) ++{ ++ iter->tracepoint++; ++ /* ++ * iter->tracepoint may be invalid because we blindly incremented it. ++ * Make sure it is valid by marshalling on the tracepoints, getting the ++ * tracepoints from following modules if necessary. ++ */ ++ tracepoint_get_iter(iter); ++} ++EXPORT_SYMBOL_GPL(tracepoint_iter_next); ++ ++void tracepoint_iter_stop(struct tracepoint_iter *iter) ++{ ++} ++EXPORT_SYMBOL_GPL(tracepoint_iter_stop); ++ ++void tracepoint_iter_reset(struct tracepoint_iter *iter) ++{ ++ iter->module = NULL; ++ iter->tracepoint = NULL; ++} ++EXPORT_SYMBOL_GPL(tracepoint_iter_reset); diff --git a/src/patches/suse-2.6.27.31/patches.trace/utrace-core b/src/patches/suse-2.6.27.31/patches.trace/utrace-core new file mode 100644 index 000000000..887a9daaf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.trace/utrace-core @@ -0,0 +1,4120 @@ +From: Roland McGrath +Date: Mon Aug 25 17:22:07 2008 -0700 +Subject: utrace core +References: FATE#304321 +Patch-mainline: no + +This adds the utrace facility, a new modular interface in the kernel for +implementing user thread tracing and debugging. This fits on top of the +tracehook_* layer, so the new code is well-isolated. + +The new interface is in and the DocBook utrace book +describes it. It allows for multiple separate tracing engines to work in +parallel without interfering with each other. Higher-level tracing +facilities can be implemented as loadable kernel modules using this layer. + +The new facility is made optional under CONFIG_UTRACE. +When this is not enabled, no new code is added. +It can only be enabled on machines that have all the +prerequisites and select CONFIG_HAVE_ARCH_TRACEHOOK. + +In this initial version, utrace and ptrace do not play well together. +If both utrace and ptrace are attached to the same thread, they can +confuse each other about the stopping and resuming of that thread. +The old ptrace code is unchanged and nothing using ptrace should be +affected by this patch as long as utrace is not used at the same time. +A later patch will make them cooperate properly. + +Signed-off-by: Roland McGrath +Signed-off-by: Petr Tesarik + +--- + Documentation/DocBook/Makefile | 2 + Documentation/DocBook/utrace.tmpl | 566 ++++++++ + fs/proc/array.c | 3 + include/linux/sched.h | 5 + include/linux/tracehook.h | 71 + + include/linux/utrace.h | 711 ++++++++++ + init/Kconfig | 10 + kernel/Makefile | 1 + kernel/utrace.c | 2495 ++++++++++++++++++++++++++++++++++++++ + 9 files changed, 3862 insertions(+), 2 deletions(-) + +--- a/Documentation/DocBook/Makefile ++++ b/Documentation/DocBook/Makefile +@@ -7,7 +7,7 @@ + # list of DOCBOOKS. + + DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ +- kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ ++ kernel-hacking.xml kernel-locking.xml deviceiobook.xml utrace.xml \ + procfs-guide.xml writing_usb_driver.xml networking.xml \ + kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ + gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ +--- /dev/null ++++ b/Documentation/DocBook/utrace.tmpl +@@ -0,0 +1,566 @@ ++ ++ ++ ++ ++ ++ The utrace User Debugging Infrastructure ++ ++ ++ ++ ++ utrace concepts ++ ++ Introduction ++ ++ ++ utrace is infrastructure code for tracing ++ and controlling user threads. This is the foundation for writing ++ tracing engines, which can be loadable kernel modules. ++ ++ ++ ++ The basic actors in utrace are the thread ++ and the tracing engine. A tracing engine is some body of code that ++ calls into the <linux/utrace.h> ++ interfaces, represented by a struct ++ utrace_engine_ops. (Usually it's a kernel module, ++ though the legacy ptrace support is a tracing ++ engine that is not in a kernel module.) The interface operates on ++ individual threads (struct task_struct). ++ If an engine wants to treat several threads as a group, that is up ++ to its higher-level code. ++ ++ ++ ++ Tracing begins by attaching an engine to a thread, using ++ utrace_attach_task or ++ utrace_attach_pid. If successful, it returns a ++ pointer that is the handle used in all other calls. ++ ++ ++ ++ ++ Events and Callbacks ++ ++ ++ An attached engine does nothing by default. An engine makes something ++ happen by requesting callbacks via utrace_set_events ++ and poking the thread with utrace_control. ++ The synchronization issues related to these two calls ++ are discussed further below in . ++ ++ ++ ++ Events are specified using the macro ++ UTRACE_EVENT(type). ++ Each event type is associated with a callback in struct ++ utrace_engine_ops. A tracing engine can leave unused ++ callbacks NULL. The only callbacks required ++ are those used by the event flags it sets. ++ ++ ++ ++ Many engines can be attached to each thread. When a thread has an ++ event, each engine gets a callback if it has set the event flag for ++ that event type. Engines are called in the order they attached. ++ ++ ++ ++ Event reporting callbacks have details particular to the event type, ++ but are all called in similar environments and have the same ++ constraints. Callbacks are made from safe points, where no locks ++ are held, no special resources are pinned (usually), and the ++ user-mode state of the thread is accessible. So, callback code has ++ a pretty free hand. But to be a good citizen, callback code should ++ never block for long periods. It is fine to block in ++ kmalloc and the like, but never wait for i/o or ++ for user mode to do something. If you need the thread to wait, use ++ UTRACE_STOP and return from the callback ++ quickly. When your i/o finishes or whatever, you can use ++ utrace_control to resume the thread. ++ ++ ++ ++ ++ Stopping Safely ++ ++ Writing well-behaved callbacks ++ ++ ++ Well-behaved callbacks are important to maintain two essential ++ properties of the interface. The first of these is that unrelated ++ tracing engines should not interfere with each other. If your engine's ++ event callback does not return quickly, then another engine won't get ++ the event notification in a timely manner. The second important ++ property is that tracing should be as noninvasive as possible to the ++ normal operation of the system overall and of the traced thread in ++ particular. That is, attached tracing engines should not perturb a ++ thread's behavior, except to the extent that changing its user-visible ++ state is explicitly what you want to do. (Obviously some perturbation ++ is unavoidable, primarily timing changes, ranging from small delays due ++ to the overhead of tracing, to arbitrary pauses in user code execution ++ when a user stops a thread with a debugger for examination.) Even when ++ you explicitly want the perturbation of making the traced thread block, ++ just blocking directly in your callback has more unwanted effects. For ++ example, the CLONE event callbacks are called when ++ the new child thread has been created but not yet started running; the ++ child can never be scheduled until the CLONE ++ tracing callbacks return. (This allows engines tracing the parent to ++ attach to the child.) If a CLONE event callback ++ blocks the parent thread, it also prevents the child thread from ++ running (even to process a SIGKILL). If what you ++ want is to make both the parent and child block, then use ++ utrace_attach_task on the child and then use ++ UTRACE_STOP on both threads. A more crucial ++ problem with blocking in callbacks is that it can prevent ++ SIGKILL from working. A thread that is blocking ++ due to UTRACE_STOP will still wake up and die ++ immediately when sent a SIGKILL, as all threads ++ should. Relying on the utrace ++ infrastructure rather than on private synchronization calls in event ++ callbacks is an important way to help keep tracing robustly ++ noninvasive. ++ ++ ++ ++ ++ Using <constant>UTRACE_STOP</constant> ++ ++ ++ To control another thread and access its state, it must be stopped ++ with UTRACE_STOP. This means that it is ++ stopped and won't start running again while we access it. When a ++ thread is not already stopped, utrace_control ++ returns -EINPROGRESS and an engine must wait ++ for an event callback when the thread is ready to stop. The thread ++ may be running on another CPU or may be blocked. When it is ready ++ to be examined, it will make callbacks to engines that set the ++ UTRACE_EVENT(QUIESCE) event bit. To wake up an ++ interruptible wait, use UTRACE_INTERRUPT. ++ ++ ++ ++ As long as some engine has used UTRACE_STOP and ++ not called utrace_control to resume the thread, ++ then the thread will remain stopped. SIGKILL ++ will wake it up, but it will not run user code. When the stop is ++ cleared with utrace_control or a callback ++ return value, the thread starts running again. ++ (See also .) ++ ++ ++ ++ ++ ++ ++ Tear-down Races ++ ++ Primacy of <constant>SIGKILL</constant> ++ ++ Ordinarily synchronization issues for tracing engines are kept fairly ++ straightforward by using UTRACE_STOP. You ask a ++ thread to stop, and then once it makes the ++ report_quiesce callback it cannot do anything else ++ that would result in another callback, until you let it with a ++ utrace_control call. This simple arrangement ++ avoids complex and error-prone code in each one of a tracing engine's ++ event callbacks to keep them serialized with the engine's other ++ operations done on that thread from another thread of control. ++ However, giving tracing engines complete power to keep a traced thread ++ stuck in place runs afoul of a more important kind of simplicity that ++ the kernel overall guarantees: nothing can prevent or delay ++ SIGKILL from making a thread die and release its ++ resources. To preserve this important property of ++ SIGKILL, it as a special case can break ++ UTRACE_STOP like nothing else normally can. This ++ includes both explicit SIGKILL signals and the ++ implicit SIGKILL sent to each other thread in the ++ same thread group by a thread doing an exec, or processing a fatal ++ signal, or making an exit_group system call. A ++ tracing engine can prevent a thread from beginning the exit or exec or ++ dying by signal (other than SIGKILL) if it is ++ attached to that thread, but once the operation begins, no tracing ++ engine can prevent or delay all other threads in the same thread group ++ dying. ++ ++ ++ ++ Final callbacks ++ ++ The report_reap callback is always the final event ++ in the life cycle of a traced thread. Tracing engines can use this as ++ the trigger to clean up their own data structures. The ++ report_death callback is always the penultimate ++ event a tracing engine might see; it's seen unless the thread was ++ already in the midst of dying when the engine attached. Many tracing ++ engines will have no interest in when a parent reaps a dead process, ++ and nothing they want to do with a zombie thread once it dies; for ++ them, the report_death callback is the natural ++ place to clean up data structures and detach. To facilitate writing ++ such engines robustly, given the asynchrony of ++ SIGKILL, and without error-prone manual ++ implementation of synchronization schemes, the ++ utrace infrastructure provides some special ++ guarantees about the report_death and ++ report_reap callbacks. It still takes some care ++ to be sure your tracing engine is robust to tear-down races, but these ++ rules make it reasonably straightforward and concise to handle a lot of ++ corner cases correctly. ++ ++ ++ ++ Engine and task pointers ++ ++ The first sort of guarantee concerns the core data structures ++ themselves. struct utrace_attached_engine is ++ a reference-counted data structure. While you hold a reference, an ++ engine pointer will always stay valid so that you can safely pass it to ++ any utrace call. Each call to ++ utrace_attach_task or ++ utrace_attach_pid returns an engine pointer with a ++ reference belonging to the caller. You own that reference until you ++ drop it using utrace_engine_put. There is an ++ implicit reference on the engine while it is attached. So if you drop ++ your only reference, and then use ++ utrace_attach_task without ++ UTRACE_ATTACH_CREATE to look up that same engine, ++ you will get the same pointer with a new reference to replace the one ++ you dropped, just like calling utrace_engine_get. ++ When an engine has been detached, either explicitly with ++ UTRACE_DETACH or implicitly after ++ report_reap, then any references you hold are all ++ that keep the old engine pointer alive. ++ ++ ++ ++ There is nothing a kernel module can do to keep a struct ++ task_struct alive outside of ++ rcu_read_lock. When the task dies and is reaped ++ by its parent (or itself), that structure can be freed so that any ++ dangling pointers you have stored become invalid. ++ utrace will not prevent this, but it can ++ help you detect it safely. By definition, a task that has been reaped ++ has had all its engines detached. All ++ utrace calls can be safely called on a ++ detached engine if the caller holds a reference on that engine pointer, ++ even if the task pointer passed in the call is invalid. All calls ++ return -ESRCH for a detached engine, which tells ++ you that the task pointer you passed could be invalid now. Since ++ utrace_control and ++ utrace_set_events do not block, you can call those ++ inside a rcu_read_lock section and be sure after ++ they don't return -ESRCH that the task pointer is ++ still valid until rcu_read_unlock. The ++ infrastructure never holds task references of its own. Though neither ++ rcu_read_lock nor any other lock is held while ++ making a callback, it's always guaranteed that the struct ++ task_struct and the struct ++ utrace_attached_engine passed as arguments remain valid ++ until the callback function returns. ++ ++ ++ ++ The common means for safely holding task pointers that is available to ++ kernel modules is to use struct pid, which ++ permits put_pid from kernel modules. When using ++ that, the calls utrace_attach_pid, ++ utrace_control_pid, ++ utrace_set_events_pid, and ++ utrace_barrier_pid are available. ++ ++ ++ ++ ++ ++ Serialization of <constant>DEATH</constant> and <constant>REAP</constant> ++ ++ ++ The second guarantee is the serialization of ++ DEATH and REAP event ++ callbacks for a given thread. The actual reaping by the parent ++ (release_task call) can occur simultaneously ++ while the thread is still doing the final steps of dying, including ++ the report_death callback. If a tracing engine ++ has requested both DEATH and ++ REAP event reports, it's guaranteed that the ++ report_reap callback will not be made until ++ after the report_death callback has returned. ++ If the report_death callback itself detaches ++ from the thread, then the report_reap callback ++ will never be made. Thus it is safe for a ++ report_death callback to clean up data ++ structures and detach. ++ ++ ++ ++ Interlock with final callbacks ++ ++ The final sort of guarantee is that a tracing engine will know for sure ++ whether or not the report_death and/or ++ report_reap callbacks will be made for a certain ++ thread. These tear-down races are disambiguated by the error return ++ values of utrace_set_events and ++ utrace_control. Normally ++ utrace_control called with ++ UTRACE_DETACH returns zero, and this means that no ++ more callbacks will be made. If the thread is in the midst of dying, ++ it returns -EALREADY to indicate that the ++ report_death callback may already be in progress; ++ when you get this error, you know that any cleanup your ++ report_death callback does is about to happen or ++ has just happened--note that if the report_death ++ callback does not detach, the engine remains attached until the thread ++ gets reaped. If the thread is in the midst of being reaped, ++ utrace_control returns -ESRCH ++ to indicate that the report_reap callback may ++ already be in progress; this means the engine is implicitly detached ++ when the callback completes. This makes it possible for a tracing ++ engine that has decided asynchronously to detach from a thread to ++ safely clean up its data structures, knowing that no ++ report_death or report_reap ++ callback will try to do the same. utrace_detach ++ returns -ESRCH when the struct ++ utrace_attached_engine has already been detached, but is ++ still a valid pointer because of its reference count. A tracing engine ++ can use this to safely synchronize its own independent multiple threads ++ of control with each other and with its event callbacks that detach. ++ ++ ++ ++ In the same vein, utrace_set_events normally ++ returns zero; if the target thread was stopped before the call, then ++ after a successful call, no event callbacks not requested in the new ++ flags will be made. It fails with -EALREADY if ++ you try to clear UTRACE_EVENT(DEATH) when the ++ report_death callback may already have begun, if ++ you try to clear UTRACE_EVENT(REAP) when the ++ report_reap callback may already have begun, or if ++ you try to newly set UTRACE_EVENT(DEATH) or ++ UTRACE_EVENT(QUIESCE) when the target is already ++ dead or dying. Like utrace_control, it returns ++ -ESRCH when the thread has already been detached ++ (including forcible detach on reaping). This lets the tracing engine ++ know for sure which event callbacks it will or won't see after ++ utrace_set_events has returned. By checking for ++ errors, it can know whether to clean up its data structures immediately ++ or to let its callbacks do the work. ++ ++ ++ ++ Using <function>utrace_barrier</function> ++ ++ When a thread is safely stopped, calling ++ utrace_control with UTRACE_DETACH ++ or calling utrace_set_events to disable some events ++ ensures synchronously that your engine won't get any more of the callbacks ++ that have been disabled (none at all when detaching). But these can also ++ be used while the thread is not stopped, when it might be simultaneously ++ making a callback to your engine. For this situation, these calls return ++ -EINPROGRESS when it's possible a callback is in ++ progress. If you are not prepared to have your old callbacks still run, ++ then you can synchronize to be sure all the old callbacks are finished, ++ using utrace_barrier. This is necessary if the ++ kernel module containing your callback code is going to be unloaded. ++ ++ ++ After using UTRACE_DETACH once, further calls to ++ utrace_control with the same engine pointer will ++ return -ESRCH. In contrast, after getting ++ -EINPROGRESS from ++ utrace_set_events, you can call ++ utrace_set_events again later and if it returns zero ++ then know the old callbacks have finished. ++ ++ ++ Unlike all other calls, utrace_barrier (and ++ utrace_barrier_pid) will accept any engine pointer you ++ hold a reference on, even if UTRACE_DETACH has already ++ been used. After any utrace_control or ++ utrace_set_events call (these do not block), you can ++ call utrace_barrier to block until callbacks have ++ finished. This returns -ESRCH only if the engine is ++ completely detached (finished all callbacks). Otherwise returns it waits ++ until the thread is definitely not in the midst of a callback to this ++ engine and then returns zero, but can return ++ -ERESTARTSYS if its wait is interrupted. ++ ++ ++ ++ ++ ++ ++ ++utrace core API ++ ++ ++ The utrace API is declared in <linux/utrace.h>. ++ ++ ++!Iinclude/linux/utrace.h ++!Ekernel/utrace.c ++ ++ ++ ++Machine State ++ ++ ++ The task_current_syscall function can be used on any ++ valid struct task_struct at any time, and does ++ not even require that utrace_attach_task was used at all. ++ ++ ++ ++ The other ways to access the registers and other machine-dependent state of ++ a task can only be used on a task that is at a known safe point. The safe ++ points are all the places where utrace_set_events can ++ request callbacks (except for the DEATH and ++ REAP events). So at any event callback, it is safe to ++ examine current. ++ ++ ++ ++ One task can examine another only after a callback in the target task that ++ returns UTRACE_STOP so that task will not return to user ++ mode after the safe point. This guarantees that the task will not resume ++ until the same engine uses utrace_control, unless the ++ task dies suddenly. To examine safely, one must use a pair of calls to ++ utrace_prepare_examine and ++ utrace_finish_examine surrounding the calls to ++ struct user_regset functions or direct examination ++ of task data structures. utrace_prepare_examine returns ++ an error if the task is not properly stopped and not dead. After a ++ successful examination, the paired utrace_finish_examine ++ call returns an error if the task ever woke up during the examination. If ++ so, any data gathered may be scrambled and should be discarded. This means ++ there was a spurious wake-up (which should not happen), or a sudden death. ++ ++ ++<structname>struct user_regset</structname> ++ ++ ++ The struct user_regset API ++ is declared in <linux/regset.h>. ++ ++ ++!Finclude/linux/regset.h ++ ++ ++ ++ ++ <filename>System Call Information</filename> ++ ++ ++ This function is declared in <linux/ptrace.h>. ++ ++ ++!Elib/syscall.c ++ ++ ++ ++<filename>System Call Tracing</filename> ++ ++ ++ The arch API for system call information is declared in ++ <asm/syscall.h>. ++ Each of these calls can be used only at system call entry tracing, ++ or can be used only at system call exit and the subsequent safe points ++ before returning to user mode. ++ At system call entry tracing means either during a ++ report_syscall_entry callback, ++ or any time after that callback has returned UTRACE_STOP. ++ ++ ++!Finclude/asm-generic/syscall.h ++ ++ ++ ++ ++ ++Kernel Internals ++ ++ ++ This chapter covers the interface to the tracing infrastructure ++ from the core of the kernel and the architecture-specific code. ++ This is for maintainers of the kernel and arch code, and not relevant ++ to using the tracing facilities described in preceding chapters. ++ ++ ++Core Calls In ++ ++ ++ These calls are declared in <linux/tracehook.h>. ++ The core kernel calls these functions at various important places. ++ ++ ++!Finclude/linux/tracehook.h ++ ++ ++ ++Architecture Calls Out ++ ++ ++ An arch that has done all these things sets ++ CONFIG_HAVE_ARCH_TRACEHOOK. ++ This is required to enable the utrace code. ++ ++ ++<filename><asm/ptrace.h></filename> ++ ++ ++ An arch defines these in <asm/ptrace.h> ++ if it supports hardware single-step or block-step features. ++ ++ ++!Finclude/linux/ptrace.h arch_has_single_step arch_has_block_step ++!Finclude/linux/ptrace.h user_enable_single_step user_enable_block_step ++!Finclude/linux/ptrace.h user_disable_single_step ++ ++ ++ ++ ++ <filename><asm/syscall.h></filename> ++ ++ ++ An arch provides <asm/syscall.h> that ++ defines these as inlines, or declares them as exported functions. ++ These interfaces are described in . ++ ++ ++ ++ ++ ++ <filename><linux/tracehook.h></filename> ++ ++ ++ An arch must define TIF_NOTIFY_RESUME ++ and TIF_SYSCALL_TRACE ++ in its <asm/thread_info.h>. ++ The arch code must call the following functions, all declared ++ in <linux/tracehook.h> and ++ described in : ++ ++ ++ ++ tracehook_notify_resume ++ ++ ++ tracehook_report_syscall_entry ++ ++ ++ tracehook_report_syscall_exit ++ ++ ++ tracehook_signal_handler ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +--- a/fs/proc/array.c ++++ b/fs/proc/array.c +@@ -82,6 +82,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -191,6 +192,8 @@ static inline void task_state(struct seq + p->uid, p->euid, p->suid, p->fsuid, + p->gid, p->egid, p->sgid, p->fsgid); + ++ task_utrace_proc_status(m, p); ++ + task_lock(p); + if (p->files) + fdt = files_fdtable(p->files); +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -1202,6 +1202,11 @@ struct task_struct { + #endif + seccomp_t seccomp; + ++#ifdef CONFIG_UTRACE ++ struct utrace *utrace; ++ unsigned long utrace_flags; ++#endif ++ + /* Thread group tracking */ + u32 parent_exec_id; + u32 self_exec_id; +--- a/include/linux/tracehook.h ++++ b/include/linux/tracehook.h +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + struct linux_binprm; + + /** +@@ -63,6 +64,8 @@ struct linux_binprm; + */ + static inline int tracehook_expect_breakpoints(struct task_struct *task) + { ++ if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_CORE))) ++ return 1; + return (task_ptrace(task) & PT_PTRACED) != 0; + } + +@@ -111,6 +114,9 @@ static inline void ptrace_report_syscall + static inline __must_check int tracehook_report_syscall_entry( + struct pt_regs *regs) + { ++ if ((task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_ENTRY)) && ++ utrace_report_syscall_entry(regs)) ++ return 1; + ptrace_report_syscall(regs); + return 0; + } +@@ -134,6 +140,8 @@ static inline __must_check int tracehook + */ + static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) + { ++ if (task_utrace_flags(current) & UTRACE_EVENT(SYSCALL_EXIT)) ++ utrace_report_syscall_exit(regs); + ptrace_report_syscall(regs); + } + +@@ -155,6 +163,8 @@ static inline int tracehook_unsafe_exec( + else + unsafe |= LSM_UNSAFE_PTRACE; + } ++ if (unlikely(task_utrace_flags(task))) ++ unsafe |= utrace_unsafe_exec(task); + return unsafe; + } + +@@ -173,6 +183,8 @@ static inline struct task_struct *traceh + { + if (task_ptrace(tsk) & PT_PTRACED) + return rcu_dereference(tsk->parent); ++ if (unlikely(task_utrace_flags(tsk))) ++ return utrace_tracer_task(tsk); + return NULL; + } + +@@ -194,6 +206,8 @@ static inline void tracehook_report_exec + struct linux_binprm *bprm, + struct pt_regs *regs) + { ++ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXEC))) ++ utrace_report_exec(fmt, bprm, regs); + if (!ptrace_event(PT_TRACE_EXEC, PTRACE_EVENT_EXEC, 0) && + unlikely(task_ptrace(current) & PT_PTRACED)) + send_sig(SIGTRAP, current, 0); +@@ -211,6 +225,8 @@ static inline void tracehook_report_exec + */ + static inline void tracehook_report_exit(long *exit_code) + { ++ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(EXIT))) ++ utrace_report_exit(exit_code); + ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); + } + +@@ -254,6 +270,7 @@ static inline int tracehook_prepare_clon + static inline void tracehook_finish_clone(struct task_struct *child, + unsigned long clone_flags, int trace) + { ++ utrace_init_task(child); + ptrace_init_task(child, (clone_flags & CLONE_PTRACE) || trace); + } + +@@ -280,6 +297,8 @@ static inline void tracehook_report_clon + unsigned long clone_flags, + pid_t pid, struct task_struct *child) + { ++ if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE))) ++ utrace_report_clone(clone_flags, child); + if (unlikely(trace) || unlikely(clone_flags & CLONE_PTRACE)) { + /* + * The child starts up with an immediate SIGSTOP. +@@ -345,6 +364,11 @@ static inline void tracehook_report_vfor + */ + static inline void tracehook_prepare_release_task(struct task_struct *task) + { ++#ifdef CONFIG_UTRACE ++ smp_mb(); ++ if (task_utrace_struct(task) != NULL) ++ utrace_release_task(task); ++#endif + } + + /** +@@ -358,7 +382,25 @@ static inline void tracehook_prepare_rel + */ + static inline void tracehook_finish_release_task(struct task_struct *task) + { ++#ifdef CONFIG_UTRACE ++ int bad = 0; ++#endif + ptrace_release_task(task); ++#ifdef CONFIG_UTRACE ++ BUG_ON(task->exit_state != EXIT_DEAD); ++ if (unlikely(task_utrace_struct(task) != NULL)) { ++ /* ++ * In a race condition, utrace_attach() will temporarily set ++ * it, but then check @task->exit_state and clear it. It does ++ * all this under task_lock(), so we take the lock to check ++ * that there is really a bug and not just that known race. ++ */ ++ task_lock(task); ++ bad = unlikely(task_utrace_struct(task) != NULL); ++ task_unlock(task); ++ } ++ BUG_ON(bad); ++#endif + } + + /** +@@ -380,6 +422,8 @@ static inline void tracehook_signal_hand + const struct k_sigaction *ka, + struct pt_regs *regs, int stepping) + { ++ if (task_utrace_flags(current)) ++ utrace_signal_handler(current, stepping); + if (stepping) + ptrace_notify(SIGTRAP); + } +@@ -400,6 +444,8 @@ static inline int tracehook_consider_ign + int sig, + void __user *handler) + { ++ if (unlikely(task_utrace_flags(task) & UTRACE_EVENT(SIGNAL_IGN))) ++ return 1; + return (task_ptrace(task) & PT_PTRACED) != 0; + } + +@@ -421,6 +467,9 @@ static inline int tracehook_consider_fat + int sig, + void __user *handler) + { ++ if (unlikely(task_utrace_flags(task) & (UTRACE_EVENT(SIGNAL_TERM) | ++ UTRACE_EVENT(SIGNAL_CORE)))) ++ return 1; + return (task_ptrace(task) & PT_PTRACED) != 0; + } + +@@ -435,6 +484,8 @@ static inline int tracehook_consider_fat + */ + static inline int tracehook_force_sigpending(void) + { ++ if (unlikely(task_utrace_flags(current))) ++ return utrace_interrupt_pending(); + return 0; + } + +@@ -464,6 +515,8 @@ static inline int tracehook_get_signal(s + siginfo_t *info, + struct k_sigaction *return_ka) + { ++ if (unlikely(task_utrace_flags(task))) ++ return utrace_get_signal(task, regs, info, return_ka); + return 0; + } + +@@ -484,6 +537,8 @@ static inline int tracehook_get_signal(s + */ + static inline int tracehook_notify_jctl(int notify, int why) + { ++ if (task_utrace_flags(current) & UTRACE_EVENT(JCTL)) ++ utrace_report_jctl(notify, why); + return notify || (current->ptrace & PT_PTRACED); + } + +@@ -507,6 +562,10 @@ static inline int tracehook_notify_jctl( + static inline int tracehook_notify_death(struct task_struct *task, + void **death_cookie, int group_dead) + { ++#ifdef CONFIG_UTRACE ++ *death_cookie = task_utrace_struct(task); ++#endif ++ + if (task->exit_signal == -1) + return task->ptrace ? SIGCHLD : DEATH_REAP; + +@@ -543,6 +602,12 @@ static inline void tracehook_report_deat + int signal, void *death_cookie, + int group_dead) + { ++#ifdef CONFIG_UTRACE ++ smp_mb(); ++ if (task_utrace_flags(task) & (UTRACE_EVENT(DEATH) | ++ UTRACE_EVENT(QUIESCE))) ++ utrace_report_death(task, death_cookie, group_dead, signal); ++#endif + } + + #ifdef TIF_NOTIFY_RESUME +@@ -572,10 +637,14 @@ static inline void set_notify_resume(str + * asynchronously, this will be called again before we return to + * user mode. + * +- * Called without locks. ++ * Called without locks. However, on some machines this may be ++ * called with interrupts disabled. + */ + static inline void tracehook_notify_resume(struct pt_regs *regs) + { ++ struct task_struct *task = current; ++ if (task_utrace_flags(task)) ++ utrace_resume(task, regs); + } + #endif /* TIF_NOTIFY_RESUME */ + +--- /dev/null ++++ b/include/linux/utrace.h +@@ -0,0 +1,711 @@ ++/* ++ * utrace infrastructure interface for debugging user processes ++ * ++ * Copyright (C) 2006, 2007, 2008 Red Hat, Inc. All rights reserved. ++ * ++ * This copyrighted material is made available to anyone wishing to use, ++ * modify, copy, or redistribute it subject to the terms and conditions ++ * of the GNU General Public License v.2. ++ * ++ * Red Hat Author: Roland McGrath. ++ * ++ * This interface allows for notification of interesting events in a ++ * thread. It also mediates access to thread state such as registers. ++ * Multiple unrelated users can be associated with a single thread. ++ * We call each of these a tracing engine. ++ * ++ * A tracing engine starts by calling utrace_attach_task() or ++ * utrace_attach_pid() on the chosen thread, passing in a set of hooks ++ * (&struct utrace_engine_ops), and some associated data. This produces a ++ * &struct utrace_attached_engine, which is the handle used for all other ++ * operations. An attached engine has its ops vector, its data, and an ++ * event mask controlled by utrace_set_events(). ++ * ++ * For each event bit that is set, that engine will get the ++ * appropriate ops->report_*() callback when the event occurs. The ++ * &struct utrace_engine_ops need not provide callbacks for an event ++ * unless the engine sets one of the associated event bits. ++ */ ++ ++#ifndef _LINUX_UTRACE_H ++#define _LINUX_UTRACE_H 1 ++ ++#include ++#include ++#include ++#include ++ ++struct linux_binprm; ++struct pt_regs; ++struct utrace; ++struct utrace_engine_ops; ++struct utrace_attached_engine; ++struct utrace_examiner; ++struct user_regset; ++struct user_regset_view; ++enum utrace_resume_action; ++ ++/* ++ * Event bits passed to utrace_set_events(). ++ * These appear in &struct task_struct.@utrace_flags ++ * and &struct utrace_attached_engine.@flags. ++ */ ++enum utrace_events { ++ _UTRACE_EVENT_QUIESCE, /* Thread is available for examination. */ ++ _UTRACE_EVENT_REAP, /* Zombie reaped, no more tracing possible. */ ++ _UTRACE_EVENT_CLONE, /* Successful clone/fork/vfork just done. */ ++ _UTRACE_EVENT_EXEC, /* Successful execve just completed. */ ++ _UTRACE_EVENT_EXIT, /* Thread exit in progress. */ ++ _UTRACE_EVENT_DEATH, /* Thread has died. */ ++ _UTRACE_EVENT_SYSCALL_ENTRY, /* User entered kernel for system call. */ ++ _UTRACE_EVENT_SYSCALL_EXIT, /* Returning to user after system call. */ ++ _UTRACE_EVENT_SIGNAL, /* Signal delivery will run a user handler. */ ++ _UTRACE_EVENT_SIGNAL_IGN, /* No-op signal to be delivered. */ ++ _UTRACE_EVENT_SIGNAL_STOP, /* Signal delivery will suspend. */ ++ _UTRACE_EVENT_SIGNAL_TERM, /* Signal delivery will terminate. */ ++ _UTRACE_EVENT_SIGNAL_CORE, /* Signal delivery will dump core. */ ++ _UTRACE_EVENT_JCTL, /* Job control stop or continue completed. */ ++ _UTRACE_NEVENTS ++}; ++#define UTRACE_EVENT(type) (1UL << _UTRACE_EVENT_##type) ++ ++/* ++ * All the kinds of signal events. ++ * These all use the @report_signal() callback. ++ */ ++#define UTRACE_EVENT_SIGNAL_ALL (UTRACE_EVENT(SIGNAL) \ ++ | UTRACE_EVENT(SIGNAL_IGN) \ ++ | UTRACE_EVENT(SIGNAL_STOP) \ ++ | UTRACE_EVENT(SIGNAL_TERM) \ ++ | UTRACE_EVENT(SIGNAL_CORE)) ++/* ++ * Both kinds of syscall events; these call the @report_syscall_entry() ++ * and @report_syscall_exit() callbacks, respectively. ++ */ ++#define UTRACE_EVENT_SYSCALL \ ++ (UTRACE_EVENT(SYSCALL_ENTRY) | UTRACE_EVENT(SYSCALL_EXIT)) ++ ++/* ++ * Hooks in call these entry points to the ++ * utrace dispatch. They are weak references here only so ++ * tracehook.h doesn't need to #ifndef CONFIG_UTRACE them to ++ * avoid external references in case of unoptimized compilation. ++ */ ++void utrace_release_task(struct task_struct *) ++ __attribute__((weak)); ++bool utrace_interrupt_pending(void) ++ __attribute__((weak)); ++void utrace_resume(struct task_struct *, struct pt_regs *) ++ __attribute__((weak)); ++int utrace_get_signal(struct task_struct *, struct pt_regs *, ++ siginfo_t *, struct k_sigaction *) ++ __attribute__((weak)); ++void utrace_report_clone(unsigned long, struct task_struct *) ++ __attribute__((weak)); ++void utrace_report_exit(long *exit_code) ++ __attribute__((weak)); ++void utrace_report_death(struct task_struct *, struct utrace *, bool, int) ++ __attribute__((weak)); ++void utrace_report_jctl(int notify, int type) ++ __attribute__((weak)); ++void utrace_report_exec(struct linux_binfmt *, struct linux_binprm *, ++ struct pt_regs *regs) ++ __attribute__((weak)); ++bool utrace_report_syscall_entry(struct pt_regs *) ++ __attribute__((weak)); ++void utrace_report_syscall_exit(struct pt_regs *) ++ __attribute__((weak)); ++struct task_struct *utrace_tracer_task(struct task_struct *) ++ __attribute__((weak)); ++int utrace_unsafe_exec(struct task_struct *) ++ __attribute__((weak)); ++void utrace_signal_handler(struct task_struct *, int) ++ __attribute__((weak)); ++ ++#ifndef CONFIG_UTRACE ++ ++/* ++ * uses these accessors to avoid #ifdef CONFIG_UTRACE. ++ */ ++static inline unsigned long task_utrace_flags(struct task_struct *task) ++{ ++ return 0; ++} ++static inline struct utrace *task_utrace_struct(struct task_struct *task) ++{ ++ return NULL; ++} ++static inline void utrace_init_task(struct task_struct *child) ++{ ++} ++ ++static inline void task_utrace_proc_status(struct seq_file *m, ++ struct task_struct *p) ++{ ++} ++ ++#else /* CONFIG_UTRACE */ ++ ++static inline unsigned long task_utrace_flags(struct task_struct *task) ++{ ++ return task->utrace_flags; ++} ++ ++static inline struct utrace *task_utrace_struct(struct task_struct *task) ++{ ++ return task->utrace; ++} ++ ++static inline void utrace_init_task(struct task_struct *child) ++{ ++ child->utrace_flags = 0; ++ child->utrace = NULL; ++} ++ ++void task_utrace_proc_status(struct seq_file *m, struct task_struct *p); ++ ++/* ++ * These are the exported entry points for tracing engines to use. ++ * See kernel/utrace.c for their kerneldoc comments with interface details. ++ */ ++struct utrace_attached_engine *utrace_attach_task( ++ struct task_struct *, int, const struct utrace_engine_ops *, void *); ++struct utrace_attached_engine *utrace_attach_pid( ++ struct pid *, int, const struct utrace_engine_ops *, void *); ++int __must_check utrace_control(struct task_struct *, ++ struct utrace_attached_engine *, ++ enum utrace_resume_action); ++int __must_check utrace_set_events(struct task_struct *, ++ struct utrace_attached_engine *, ++ unsigned long eventmask); ++int __must_check utrace_barrier(struct task_struct *, ++ struct utrace_attached_engine *); ++int __must_check utrace_prepare_examine(struct task_struct *, ++ struct utrace_attached_engine *, ++ struct utrace_examiner *); ++int __must_check utrace_finish_examine(struct task_struct *, ++ struct utrace_attached_engine *, ++ struct utrace_examiner *); ++void __utrace_engine_release(struct kref *); ++ ++/** ++ * enum utrace_resume_action - engine's choice of action for a traced task ++ * @UTRACE_STOP: Stay quiescent after callbacks. ++ * @UTRACE_REPORT: Make some callback soon. ++ * @UTRACE_INTERRUPT: Make @report_signal() callback soon. ++ * @UTRACE_SINGLESTEP: Resume in user mode for one instruction. ++ * @UTRACE_BLOCKSTEP: Resume in user mode until next branch. ++ * @UTRACE_RESUME: Resume normally in user mode. ++ * @UTRACE_DETACH: Detach my engine (implies %UTRACE_RESUME). ++ * ++ * See utrace_control() for detailed descriptions of each action. This is ++ * encoded in the @action argument and the return value for every callback ++ * with a &u32 return value. ++ * ++ * The order of these is important. When there is more than one engine, ++ * each supplies its choice and the smallest value prevails. ++ */ ++enum utrace_resume_action { ++ UTRACE_STOP, ++ UTRACE_REPORT, ++ UTRACE_INTERRUPT, ++ UTRACE_SINGLESTEP, ++ UTRACE_BLOCKSTEP, ++ UTRACE_RESUME, ++ UTRACE_DETACH ++}; ++#define UTRACE_RESUME_MASK 0x0f ++ ++/** ++ * utrace_resume_action - &enum utrace_resume_action from callback action ++ * @action: &u32 callback @action argument or return value ++ * ++ * This extracts the &enum utrace_resume_action from @action, ++ * which is the @action argument to a &struct utrace_engine_ops ++ * callback or the return value from one. ++ */ ++static inline enum utrace_resume_action utrace_resume_action(u32 action) ++{ ++ return action & UTRACE_RESUME_MASK; ++} ++ ++/** ++ * enum utrace_signal_action - disposition of signal ++ * @UTRACE_SIGNAL_DELIVER: Deliver according to sigaction. ++ * @UTRACE_SIGNAL_IGN: Ignore the signal. ++ * @UTRACE_SIGNAL_TERM: Terminate the process. ++ * @UTRACE_SIGNAL_CORE: Terminate with core dump. ++ * @UTRACE_SIGNAL_STOP: Deliver as absolute stop. ++ * @UTRACE_SIGNAL_TSTP: Deliver as job control stop. ++ * @UTRACE_SIGNAL_REPORT: Reporting before pending signals. ++ * @UTRACE_SIGNAL_HANDLER: Reporting after signal handler setup. ++ * ++ * This is encoded in the @action argument and the return value for ++ * a @report_signal() callback. It says what will happen to the ++ * signal described by the &siginfo_t parameter to the callback. ++ * ++ * The %UTRACE_SIGNAL_REPORT value is used in an @action argument when ++ * a tracing report is being made before dequeuing any pending signal. ++ * If this is immediately after a signal handler has been set up, then ++ * %UTRACE_SIGNAL_HANDLER is used instead. A @report_signal callback ++ * that uses %UTRACE_SIGNAL_DELIVER|%UTRACE_SINGLESTEP will ensure ++ * it sees a %UTRACE_SIGNAL_HANDLER report. ++ */ ++enum utrace_signal_action { ++ UTRACE_SIGNAL_DELIVER = 0x00, ++ UTRACE_SIGNAL_IGN = 0x10, ++ UTRACE_SIGNAL_TERM = 0x20, ++ UTRACE_SIGNAL_CORE = 0x30, ++ UTRACE_SIGNAL_STOP = 0x40, ++ UTRACE_SIGNAL_TSTP = 0x50, ++ UTRACE_SIGNAL_REPORT = 0x60, ++ UTRACE_SIGNAL_HANDLER = 0x70 ++}; ++#define UTRACE_SIGNAL_MASK 0xf0 ++#define UTRACE_SIGNAL_HOLD 0x100 /* Flag, push signal back on queue. */ ++ ++/** ++ * utrace_signal_action - &enum utrace_signal_action from callback action ++ * @action: @report_signal callback @action argument or return value ++ * ++ * This extracts the &enum utrace_signal_action from @action, which ++ * is the @action argument to a @report_signal callback or the ++ * return value from one. ++ */ ++static inline enum utrace_signal_action utrace_signal_action(u32 action) ++{ ++ return action & UTRACE_SIGNAL_MASK; ++} ++ ++/** ++ * enum utrace_syscall_action - disposition of system call attempt ++ * @UTRACE_SYSCALL_RUN: Run the system call. ++ * @UTRACE_SYSCALL_ABORT: Don't run the system call. ++ * ++ * This is encoded in the @action argument and the return value for ++ * a @report_syscall_entry callback. ++ */ ++enum utrace_syscall_action { ++ UTRACE_SYSCALL_RUN = 0x00, ++ UTRACE_SYSCALL_ABORT = 0x10 ++}; ++#define UTRACE_SYSCALL_MASK 0xf0 ++ ++/** ++ * utrace_syscall_action - &enum utrace_syscall_action from callback action ++ * @action: @report_syscall_entry callback @action or return value ++ * ++ * This extracts the &enum utrace_syscall_action from @action, which ++ * is the @action argument to a @report_syscall_entry callback or the ++ * return value from one. ++ */ ++static inline enum utrace_syscall_action utrace_syscall_action(u32 action) ++{ ++ return action & UTRACE_SYSCALL_MASK; ++} ++ ++/* ++ * Flags for utrace_attach_task() and utrace_attach_pid(). ++ */ ++#define UTRACE_ATTACH_CREATE 0x0010 /* Attach a new engine. */ ++#define UTRACE_ATTACH_EXCLUSIVE 0x0020 /* Refuse if existing match. */ ++#define UTRACE_ATTACH_MATCH_OPS 0x0001 /* Match engines on ops. */ ++#define UTRACE_ATTACH_MATCH_DATA 0x0002 /* Match engines on data. */ ++#define UTRACE_ATTACH_MATCH_MASK 0x000f ++ ++/** ++ * struct utrace_attached_engine - per-engine structure ++ * @ops: &struct utrace_engine_ops pointer passed to utrace_attach_task() ++ * @data: engine-private &void * passed to utrace_attach_task() ++ * @flags: event mask set by utrace_set_events() plus internal flag bits ++ * ++ * The task itself never has to worry about engines detaching while ++ * it's doing event callbacks. These structures are removed from the ++ * task's active list only when it's stopped, or by the task itself. ++ * ++ * utrace_engine_get() and utrace_engine_put() maintain a reference count. ++ * When it drops to zero, the structure is freed. One reference is held ++ * implicitly while the engine is attached to its task. ++ */ ++struct utrace_attached_engine { ++/* private: */ ++ struct kref kref; ++ struct list_head entry; ++ ++/* public: */ ++ const struct utrace_engine_ops *ops; ++ void *data; ++ ++ unsigned long flags; ++}; ++ ++/** ++ * utrace_engine_get - acquire a reference on a &struct utrace_attached_engine ++ * @engine: &struct utrace_attached_engine pointer ++ * ++ * You must hold a reference on @engine, and you get another. ++ */ ++static inline void utrace_engine_get(struct utrace_attached_engine *engine) ++{ ++ kref_get(&engine->kref); ++} ++ ++/** ++ * utrace_engine_put - release a reference on a &struct utrace_attached_engine ++ * @engine: &struct utrace_attached_engine pointer ++ * ++ * You must hold a reference on @engine, and you lose that reference. ++ * If it was the last one, @engine becomes an invalid pointer. ++ */ ++static inline void utrace_engine_put(struct utrace_attached_engine *engine) ++{ ++ kref_put(&engine->kref, __utrace_engine_release); ++} ++ ++/** ++ * struct utrace_engine_ops - tracing engine callbacks ++ * ++ * Each @report_*() callback corresponds to an %UTRACE_EVENT(*) bit. ++ * utrace_set_events() calls on @engine choose which callbacks will be made ++ * to @engine from @task. ++ * ++ * Most callbacks take an @action argument, giving the resume action ++ * chosen by other tracing engines. All callbacks take an @engine ++ * argument, and a @task argument, which is always equal to @current. ++ * For some calls, @action also includes bits specific to that event ++ * and utrace_resume_action() is used to extract the resume action. ++ * This shows what would happen if @engine wasn't there, or will if ++ * the callback's return value uses %UTRACE_RESUME. This always ++ * starts as %UTRACE_RESUME when no other tracing is being done on ++ * this task. ++ * ++ * All return values contain &enum utrace_resume_action bits. For ++ * some calls, other bits specific to that kind of event are added to ++ * the resume action bits with OR. These are the same bits used in ++ * the @action argument. The resume action returned by a callback ++ * does not override previous engines' choices, it only says what ++ * @engine wants done. What @task actually does is the action that's ++ * most constrained among the choices made by all attached engines. ++ * See utrace_control() for more information on the actions. ++ * ++ * When %UTRACE_STOP is used in @report_syscall_entry, then @task ++ * stops before attempting the system call. In other cases, the ++ * resume action does not take effect until @task is ready to check ++ * for signals and return to user mode. If there are more callbacks ++ * to be made, the last round of calls determines the final action. ++ * A @report_quiesce callback with @event zero, or a @report_signal ++ * callback, will always be the last one made before @task resumes. ++ * Only %UTRACE_STOP is "sticky"--if @engine returned %UTRACE_STOP ++ * then @task stays stopped unless @engine returns different from a ++ * following callback. ++ * ++ * The report_death() and report_reap() callbacks do not take @action ++ * arguments, and only %UTRACE_DETACH is meaningful in the return value ++ * from a report_death() callback. None of the resume actions applies ++ * to a dead thread. ++ * ++ * All @report_*() hooks are called with no locks held, in a generally ++ * safe environment when we will be returning to user mode soon (or just ++ * entered the kernel). It is fine to block for memory allocation and ++ * the like, but all hooks are asynchronous and must not block on ++ * external events! If you want the thread to block, use %UTRACE_STOP ++ * in your hook's return value; then later wake it up with utrace_control(). ++ * ++ * The @unsafe_exec and @tracer_task hooks are not associated with ++ * event reports. These may be %NULL if the engine has nothing to say. ++ * These hooks are called in more constrained environments and should ++ * not block or do very much. ++ * ++ * @report_quiesce: ++ * Requested by %UTRACE_EVENT(%QUIESCE). ++ * This does not indicate any event, but just that @task (the current ++ * thread) is in a safe place for examination. This call is made ++ * before each specific event callback, except for @report_reap. ++ * The @event argument gives the %UTRACE_EVENT(@which) value for ++ * the event occurring. This callback might be made for events @engine ++ * has not requested, if some other engine is tracing the event; ++ * calling utrace_set_events() call here can request the immediate ++ * callback for this occurrence of @event. @event is zero when there ++ * is no other event, @task is now ready to check for signals and ++ * return to user mode, and some engine has used %UTRACE_REPORT or ++ * %UTRACE_INTERRUPT to request this callback. For this case, ++ * if @report_signal is not %NULL, the @report_quiesce callback ++ * may be replaced with a @report_signal callback passing ++ * %UTRACE_SIGNAL_REPORT in its @action argument, whenever @task is ++ * entering the signal-check path anyway. ++ * ++ * @report_signal: ++ * Requested by %UTRACE_EVENT(%SIGNAL_*) or %UTRACE_EVENT(%QUIESCE). ++ * Use utrace_signal_action() and utrace_resume_action() on @action. ++ * The signal action is %UTRACE_SIGNAL_REPORT when some engine has ++ * used %UTRACE_REPORT or %UTRACE_INTERRUPT; the callback can choose ++ * to stop or to deliver an artificial signal, before pending signals. ++ * It's %UTRACE_SIGNAL_HANDLER instead when signal handler setup just ++ * finished (after a previous %UTRACE_SIGNAL_DELIVER return); this ++ * serves in lieu of any %UTRACE_SIGNAL_REPORT callback requested by ++ * %UTRACE_REPORT or %UTRACE_INTERRUPT, and is also implicitly ++ * requested by %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP into the ++ * signal delivery. The other signal actions indicate a signal about ++ * to be delivered; the previous engine's return value sets the signal ++ * action seen by the the following engine's callback. The @info data ++ * can be changed at will, including @info->si_signo. The settings in ++ * @return_ka determines what %UTRACE_SIGNAL_DELIVER does. @orig_ka ++ * is what was in force before other tracing engines intervened, and ++ * it's %NULL when this report began as %UTRACE_SIGNAL_REPORT or ++ * %UTRACE_SIGNAL_HANDLER. For a report without a new signal, @info ++ * is left uninitialized and must be set completely by an engine that ++ * chooses to deliver a signal; if there was a previous @report_signal ++ * callback ending in %UTRACE_STOP and it was just resumed using ++ * %UTRACE_REPORT or %UTRACE_INTERRUPT, then @info is left unchanged ++ * from the previous callback. In this way, the original signal can ++ * be left in @info while returning %UTRACE_STOP|%UTRACE_SIGNAL_IGN ++ * and then found again when resuming @task with %UTRACE_INTERRUPT. ++ * The %UTRACE_SIGNAL_HOLD flag bit can be OR'd into the return value, ++ * and might be in @action if the previous engine returned it. This ++ * flag asks that the signal in @info be pushed back on @task's queue ++ * so that it will be seen again after whatever action is taken now. ++ * ++ * @report_clone: ++ * Requested by %UTRACE_EVENT(%CLONE). ++ * Event reported for parent, before the new task @child might run. ++ * @clone_flags gives the flags used in the clone system call, ++ * or equivalent flags for a fork() or vfork() system call. ++ * This function can use utrace_attach_task() on @child. It's guaranteed ++ * that asynchronous utrace_attach_task() calls will be ordered after ++ * any calls in @report_clone callbacks for the parent. Thus ++ * when using %UTRACE_ATTACH_EXCLUSIVE in the asynchronous calls, ++ * you can be sure that the parent's @report_clone callback has ++ * already attached to @child or chosen not to. Passing %UTRACE_STOP ++ * to utrace_control() on @child here keeps the child stopped before ++ * it ever runs in user mode, %UTRACE_REPORT or %UTRACE_INTERRUPT ++ * ensures a callback from @child before it starts in user mode. ++ * ++ * @report_jctl: ++ * Requested by %UTRACE_EVENT(%JCTL). ++ * Job control event; @type is %CLD_STOPPED or %CLD_CONTINUED, ++ * indicating whether we are stopping or resuming now. If @notify ++ * is nonzero, @task is the last thread to stop and so will send ++ * %SIGCHLD to its parent after this callback; @notify reflects ++ * what the parent's %SIGCHLD has in @si_code, which can sometimes ++ * be %CLD_STOPPED even when @type is %CLD_CONTINUED. ++ * ++ * @report_exec: ++ * Requested by %UTRACE_EVENT(%EXEC). ++ * An execve system call has succeeded and the new program is about to ++ * start running. The initial user register state is handy to be tweaked ++ * directly in @regs. @fmt and @bprm gives the details of this exec. ++ * ++ * @report_syscall_entry: ++ * Requested by %UTRACE_EVENT(%SYSCALL_ENTRY). ++ * Thread has entered the kernel to request a system call. ++ * The user register state is handy to be tweaked directly in @regs. ++ * The @action argument contains an &enum utrace_syscall_action, ++ * use utrace_syscall_action() to extract it. The return value ++ * overrides the last engine's action for the system call. ++ * If the final action is %UTRACE_SYSCALL_ABORT, no system call ++ * is made. The details of the system call being attempted can ++ * be fetched here with syscall_get_nr() and syscall_get_arguments(). ++ * The parameter registers can be changed with syscall_set_arguments(). ++ * ++ * @report_syscall_exit: ++ * Requested by %UTRACE_EVENT(%SYSCALL_EXIT). ++ * Thread is about to leave the kernel after a system call request. ++ * The user register state is handy to be tweaked directly in @regs. ++ * The results of the system call attempt can be examined here using ++ * syscall_get_error() and syscall_get_return_value(). It is safe ++ * here to call syscall_set_return_value() or syscall_rollback(). ++ * ++ * @report_exit: ++ * Requested by %UTRACE_EVENT(%EXIT). ++ * Thread is exiting and cannot be prevented from doing so, ++ * but all its state is still live. The @code value will be ++ * the wait result seen by the parent, and can be changed by ++ * this engine or others. The @orig_code value is the real ++ * status, not changed by any tracing engine. Returning %UTRACE_STOP ++ * here keeps @task stopped before it cleans up its state and dies, ++ * so it can be examined by other processes. When @task is allowed ++ * to run, it will die and get to the @report_death callback. ++ * ++ * @report_death: ++ * Requested by %UTRACE_EVENT(%DEATH). ++ * Thread is really dead now. It might be reaped by its parent at ++ * any time, or self-reap immediately. Though the actual reaping ++ * may happen in parallel, a report_reap() callback will always be ++ * ordered after a report_death() callback. ++ * ++ * @report_reap: ++ * Requested by %UTRACE_EVENT(%REAP). ++ * Called when someone reaps the dead task (parent, init, or self). ++ * This means the parent called wait, or else this was a detached ++ * thread or a process whose parent ignores SIGCHLD. ++ * No more callbacks are made after this one. ++ * The engine is always detached. ++ * There is nothing more a tracing engine can do about this thread. ++ * After this callback, the @engine pointer will become invalid. ++ * The @task pointer may become invalid if get_task_struct() hasn't ++ * been used to keep it alive. ++ * An engine should always request this callback if it stores the ++ * @engine pointer or stores any pointer in @engine->data, so it ++ * can clean up its data structures. ++ * Unlike other callbacks, this can be called from the parent's context ++ * rather than from the traced thread itself--it must not delay the ++ * parent by blocking. ++ * ++ * @unsafe_exec: ++ * Used if not %NULL. ++ * Return %LSM_UNSAFE_* bits that apply to the exec in progress ++ * due to tracing done by this engine. These bits indicate that ++ * someone is able to examine the process and so a set-UID or similar ++ * privilege escalation may not be safe to permit. ++ * Called with task_lock() held. ++ * ++ * @tracer_task: ++ * Used if not %NULL. ++ * Return the &struct task_struct for the task using ptrace() on ++ * @task, or %NULL. Always called with rcu_read_lock() held to ++ * keep the returned struct alive. At exec time, this may be ++ * called with task_lock() still held from when unsafe_exec() was ++ * just called. In that case it must give results consistent ++ * with those unsafe_exec() results, i.e. non-%NULL if any ++ * %LSM_UNSAFE_PTRACE_* bits were set. The value is also used to ++ * display after "TracerPid:" in /proc/PID/status, where it is ++ * called with only rcu_read_lock() held. If this engine returns ++ * %NULL, another engine may supply the result. ++ */ ++struct utrace_engine_ops { ++ u32 (*report_quiesce)(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ unsigned long event); ++ u32 (*report_signal)(u32 action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ struct pt_regs *regs, ++ siginfo_t *info, ++ const struct k_sigaction *orig_ka, ++ struct k_sigaction *return_ka); ++ u32 (*report_clone)(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *parent, ++ unsigned long clone_flags, ++ struct task_struct *child); ++ u32 (*report_jctl)(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ int type, int notify); ++ u32 (*report_exec)(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ const struct linux_binfmt *fmt, ++ const struct linux_binprm *bprm, ++ struct pt_regs *regs); ++ u32 (*report_syscall_entry)(u32 action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ struct pt_regs *regs); ++ u32 (*report_syscall_exit)(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ struct pt_regs *regs); ++ u32 (*report_exit)(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ long orig_code, long *code); ++ u32 (*report_death)(struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ bool group_dead, int signal); ++ void (*report_reap)(struct utrace_attached_engine *engine, ++ struct task_struct *task); ++ ++ int (*unsafe_exec)(struct utrace_attached_engine *engine, ++ struct task_struct *task); ++ struct task_struct *(*tracer_task)( ++ struct utrace_attached_engine *engine, ++ struct task_struct *task); ++}; ++ ++/** ++ * struct utrace_examiner - private state for using utrace_prepare_examine() ++ * @dummy: all fields are private, none described here ++ * ++ * The members of &struct utrace_examiner are private to the implementation. ++ * This data type holds the state from a call to utrace_prepare_examine() ++ * to be used by a call to utrace_finish_examine(). ++ */ ++struct utrace_examiner { ++/* private: */ ++ long state; /* cache of task_struct.state */ ++ unsigned long ncsw; /* cache of wait_task_inactive() return value */ ++/* public: */ ++ struct {} dummy; ++}; ++ ++/** ++ * utrace_control_pid - control a thread being traced by a tracing engine ++ * @pid: thread to affect ++ * @engine: attached engine to affect ++ * @action: &enum utrace_resume_action for thread to do ++ * ++ * This is the same as utrace_control(), but takes a &struct pid ++ * pointer rather than a &struct task_struct pointer. The caller must ++ * hold a ref on @pid, but does not need to worry about the task ++ * staying valid. If it's been reaped so that @pid points nowhere, ++ * then this call returns -%ESRCH. ++ */ ++static inline __must_check int utrace_control_pid( ++ struct pid *pid, struct utrace_attached_engine *engine, ++ enum utrace_resume_action action) ++{ ++ /* ++ * We don't bother with rcu_read_lock() here to protect the ++ * task_struct pointer, because utrace_control will return ++ * -ESRCH without looking at that pointer if the engine is ++ * already detached. A task_struct pointer can't die before ++ * all the engines are detached in release_task() first. ++ */ ++ struct task_struct *task = pid_task(pid, PIDTYPE_PID); ++ return unlikely(!task) ? -ESRCH : utrace_control(task, engine, action); ++} ++ ++/** ++ * utrace_set_events_pid - choose which event reports a tracing engine gets ++ * @pid: thread to affect ++ * @engine: attached engine to affect ++ * @eventmask: new event mask ++ * ++ * This is the same as utrace_set_events(), but takes a &struct pid ++ * pointer rather than a &struct task_struct pointer. The caller must ++ * hold a ref on @pid, but does not need to worry about the task ++ * staying valid. If it's been reaped so that @pid points nowhere, ++ * then this call returns -%ESRCH. ++ */ ++static inline __must_check int utrace_set_events_pid( ++ struct pid *pid, struct utrace_attached_engine *engine, ++ unsigned long eventmask) ++{ ++ struct task_struct *task = pid_task(pid, PIDTYPE_PID); ++ return unlikely(!task) ? -ESRCH : ++ utrace_set_events(task, engine, eventmask); ++} ++ ++/** ++ * utrace_barrier_pid - synchronize with simultaneous tracing callbacks ++ * @pid: thread to affect ++ * @engine: engine to affect (can be detached) ++ * ++ * This is the same as utrace_barrier(), but takes a &struct pid ++ * pointer rather than a &struct task_struct pointer. The caller must ++ * hold a ref on @pid, but does not need to worry about the task ++ * staying valid. If it's been reaped so that @pid points nowhere, ++ * then this call returns -%ESRCH. ++ */ ++static inline __must_check int utrace_barrier_pid( ++ struct pid *pid, struct utrace_attached_engine *engine) ++{ ++ struct task_struct *task = pid_task(pid, PIDTYPE_PID); ++ return unlikely(!task) ? -ESRCH : utrace_barrier(task, engine); ++} ++ ++#endif /* CONFIG_UTRACE */ ++ ++#endif /* linux/utrace.h */ +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -916,6 +916,16 @@ config STOP_MACHINE + help + Need stop_machine() primitive. + ++menuconfig UTRACE ++ bool "Infrastructure for tracing and debugging user processes" ++ depends on EXPERIMENTAL ++ depends on HAVE_ARCH_TRACEHOOK ++ depends on MODULES ++ help ++ Enable the utrace process tracing interface. This is an internal ++ kernel interface exported to kernel modules, to track events in ++ user threads, extract and change user thread state. ++ + source "block/Kconfig" + + config PREEMPT_NOTIFIERS +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -65,6 +65,7 @@ obj-$(CONFIG_IKCONFIG) += configs.o + obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o + obj-$(CONFIG_STOP_MACHINE) += stop_machine.o + obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o ++obj-$(CONFIG_UTRACE) += utrace.o + obj-$(CONFIG_AUDIT) += audit.o auditfilter.o + obj-$(CONFIG_AUDITSYSCALL) += auditsc.o + obj-$(CONFIG_AUDIT_TREE) += audit_tree.o +--- /dev/null ++++ b/kernel/utrace.c +@@ -0,0 +1,2495 @@ ++/* ++ * utrace infrastructure interface for debugging user processes ++ * ++ * Copyright (C) 2006, 2007, 2008 Red Hat, Inc. All rights reserved. ++ * ++ * This copyrighted material is made available to anyone wishing to use, ++ * modify, copy, or redistribute it subject to the terms and conditions ++ * of the GNU General Public License v.2. ++ * ++ * Red Hat Author: Roland McGrath. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define UTRACE_DEBUG 1 ++#ifdef UTRACE_DEBUG ++#define CHECK_INIT(p) atomic_set(&(p)->check_dead, 1) ++#define CHECK_DEAD(p) BUG_ON(!atomic_dec_and_test(&(p)->check_dead)) ++#else ++#define CHECK_INIT(p) do { } while (0) ++#define CHECK_DEAD(p) do { } while (0) ++#endif ++ ++/* ++ * Per-thread structure task_struct.utrace points to. ++ * ++ * The task itself never has to worry about this going away after ++ * some event is found set in task_struct.utrace_flags. ++ * Once created, this pointer is changed only when the task is quiescent ++ * (TASK_TRACED or TASK_STOPPED with the siglock held, or dead). ++ * ++ * For other parties, the pointer to this is protected by RCU and ++ * task_lock. Since call_rcu is never used while the thread is alive and ++ * using this struct utrace, we can overlay the RCU data structure used ++ * only for a dead struct with some local state used only for a live utrace ++ * on an active thread. ++ * ++ * The two lists @attached and @attaching work together for smooth ++ * asynchronous attaching with low overhead. Modifying either list ++ * requires @lock. The @attaching list can be modified any time while ++ * holding @lock. New engines being attached always go on this list. ++ * ++ * The @attached list is what the task itself uses for its reporting ++ * loops. When the task itself is not quiescent, it can use the ++ * @attached list without taking any lock. Noone may modify the list ++ * when the task is not quiescent. When it is quiescent, that means ++ * that it won't run again without taking @lock itself before using ++ * the list. ++ * ++ * At each place where we know the task is quiescent (or it's current), ++ * while holding @lock, we call splice_attaching(), below. This moves ++ * the @attaching list members on to the end of the @attached list. ++ * Since this happens at the start of any reporting pass, any new ++ * engines attached asynchronously go on the stable @attached list ++ * in time to have their callbacks seen. ++ */ ++struct utrace { ++ union { ++ struct rcu_head dead; ++ struct { ++ struct task_struct *cloning; ++ } live; ++ } u; ++ ++ struct list_head attached, attaching; ++ spinlock_t lock; ++#ifdef UTRACE_DEBUG ++ atomic_t check_dead; ++#endif ++ ++ struct utrace_attached_engine *reporting; ++ ++ unsigned int stopped:1; ++ unsigned int report:1; ++ unsigned int interrupt:1; ++ unsigned int signal_handler:1; ++ unsigned int death:1; /* in utrace_report_death() now */ ++ unsigned int reap:1; /* release_task() has run */ ++}; ++ ++static struct kmem_cache *utrace_cachep; ++static struct kmem_cache *utrace_engine_cachep; ++static const struct utrace_engine_ops utrace_detached_ops; /* forward decl */ ++ ++static int __init utrace_init(void) ++{ ++ utrace_cachep = KMEM_CACHE(utrace, SLAB_PANIC); ++ utrace_engine_cachep = KMEM_CACHE(utrace_attached_engine, SLAB_PANIC); ++ return 0; ++} ++subsys_initcall(utrace_init); ++ ++ ++/* ++ * Make sure target->utrace is allocated, and return with it locked on ++ * success. This function mediates startup races. The creating parent ++ * task has priority, and other callers will delay here to let its call ++ * succeed and take the new utrace lock first. ++ */ ++static struct utrace *utrace_first_engine(struct task_struct *target, ++ struct utrace_attached_engine *engine) ++ __acquires(utrace->lock) ++{ ++ struct utrace *utrace; ++ ++ /* ++ * If this is a newborn thread and we are not the creator, ++ * we have to wait for it. The creator gets the first chance ++ * to attach. The PF_STARTING flag is cleared after its ++ * report_clone hook has had a chance to run. ++ */ ++ if (target->flags & PF_STARTING) { ++ utrace = current->utrace; ++ if (utrace == NULL || utrace->u.live.cloning != target) { ++ yield(); ++ if (signal_pending(current)) ++ return ERR_PTR(-ERESTARTNOINTR); ++ return NULL; ++ } ++ } ++ ++ utrace = kmem_cache_zalloc(utrace_cachep, GFP_KERNEL); ++ if (unlikely(utrace == NULL)) ++ return ERR_PTR(-ENOMEM); ++ ++ INIT_LIST_HEAD(&utrace->attached); ++ INIT_LIST_HEAD(&utrace->attaching); ++ list_add(&engine->entry, &utrace->attached); ++ spin_lock_init(&utrace->lock); ++ CHECK_INIT(utrace); ++ ++ spin_lock(&utrace->lock); ++ task_lock(target); ++ if (likely(target->utrace == NULL)) { ++ rcu_assign_pointer(target->utrace, utrace); ++ ++ /* ++ * The task_lock protects us against another thread doing ++ * the same thing. We might still be racing against ++ * tracehook_release_task. It's called with ->exit_state ++ * set to EXIT_DEAD and then checks ->utrace with an ++ * smp_mb() in between. If EXIT_DEAD is set, then ++ * release_task might have checked ->utrace already and saw ++ * it NULL; we can't attach. If we see EXIT_DEAD not yet ++ * set after our barrier, then we know release_task will ++ * see our target->utrace pointer. ++ */ ++ smp_mb(); ++ if (likely(target->exit_state != EXIT_DEAD)) { ++ task_unlock(target); ++ return utrace; ++ } ++ ++ /* ++ * The target has already been through release_task. ++ * Our caller will restart and notice it's too late now. ++ */ ++ target->utrace = NULL; ++ } ++ ++ /* ++ * Another engine attached first, so there is a struct already. ++ * A null return says to restart looking for the existing one. ++ */ ++ task_unlock(target); ++ spin_unlock(&utrace->lock); ++ kmem_cache_free(utrace_cachep, utrace); ++ ++ return NULL; ++} ++ ++static void utrace_free(struct rcu_head *rhead) ++{ ++ struct utrace *utrace = container_of(rhead, struct utrace, u.dead); ++ kmem_cache_free(utrace_cachep, utrace); ++} ++ ++/* ++ * Called with utrace locked. Clean it up and free it via RCU. ++ */ ++static void rcu_utrace_free(struct utrace *utrace) ++ __releases(utrace->lock) ++{ ++ CHECK_DEAD(utrace); ++ spin_unlock(&utrace->lock); ++ call_rcu(&utrace->u.dead, utrace_free); ++} ++ ++/* ++ * This is the exported function used by the utrace_engine_put() inline. ++ */ ++void __utrace_engine_release(struct kref *kref) ++{ ++ struct utrace_attached_engine *engine = ++ container_of(kref, struct utrace_attached_engine, kref); ++ BUG_ON(!list_empty(&engine->entry)); ++ kmem_cache_free(utrace_engine_cachep, engine); ++} ++EXPORT_SYMBOL_GPL(__utrace_engine_release); ++ ++static bool engine_matches(struct utrace_attached_engine *engine, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ if ((flags & UTRACE_ATTACH_MATCH_OPS) && engine->ops != ops) ++ return false; ++ if ((flags & UTRACE_ATTACH_MATCH_DATA) && engine->data != data) ++ return false; ++ return engine->ops && engine->ops != &utrace_detached_ops; ++} ++ ++static struct utrace_attached_engine *matching_engine( ++ struct utrace *utrace, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ struct utrace_attached_engine *engine; ++ list_for_each_entry(engine, &utrace->attached, entry) ++ if (engine_matches(engine, flags, ops, data)) ++ return engine; ++ list_for_each_entry(engine, &utrace->attaching, entry) ++ if (engine_matches(engine, flags, ops, data)) ++ return engine; ++ return NULL; ++} ++ ++/* ++ * Allocate a new engine structure. It starts out with two refs: ++ * one ref for utrace_attach_task() to return, and ref for being attached. ++ */ ++static struct utrace_attached_engine *alloc_engine(void) ++{ ++ struct utrace_attached_engine *engine; ++ engine = kmem_cache_alloc(utrace_engine_cachep, GFP_KERNEL); ++ if (likely(engine)) { ++ engine->flags = 0; ++ kref_set(&engine->kref, 2); ++ } ++ return engine; ++} ++ ++/** ++ * utrace_attach_task - attach new engine, or look up an attached engine ++ * @target: thread to attach to ++ * @flags: flag bits combined with OR, see below ++ * @ops: callback table for new engine ++ * @data: engine private data pointer ++ * ++ * The caller must ensure that the @target thread does not get freed, ++ * i.e. hold a ref or be its parent. It is always safe to call this ++ * on @current, or on the @child pointer in a @report_clone callback. ++ * For most other cases, it's easier to use utrace_attach_pid() instead. ++ * ++ * UTRACE_ATTACH_CREATE: ++ * Create a new engine. If %UTRACE_ATTACH_CREATE is not specified, you ++ * only look up an existing engine already attached to the thread. ++ * ++ * UTRACE_ATTACH_EXCLUSIVE: ++ * Attempting to attach a second (matching) engine fails with -%EEXIST. ++ * ++ * UTRACE_ATTACH_MATCH_OPS: Only consider engines matching @ops. ++ * UTRACE_ATTACH_MATCH_DATA: Only consider engines matching @data. ++ */ ++struct utrace_attached_engine *utrace_attach_task( ++ struct task_struct *target, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ struct utrace *utrace; ++ struct utrace_attached_engine *engine; ++ ++restart: ++ rcu_read_lock(); ++ utrace = rcu_dereference(target->utrace); ++ smp_rmb(); ++ if (unlikely(target->exit_state == EXIT_DEAD)) { ++ /* ++ * The target has already been reaped. ++ * Check this first; a race with reaping may lead to restart. ++ */ ++ rcu_read_unlock(); ++ if (!(flags & UTRACE_ATTACH_CREATE)) ++ return ERR_PTR(-ENOENT); ++ return ERR_PTR(-ESRCH); ++ } ++ ++ if (utrace == NULL) { ++ rcu_read_unlock(); ++ ++ if (!(flags & UTRACE_ATTACH_CREATE)) ++ return ERR_PTR(-ENOENT); ++ ++ if (unlikely(target->flags & PF_KTHREAD)) ++ /* ++ * Silly kernel, utrace is for users! ++ */ ++ return ERR_PTR(-EPERM); ++ ++ engine = alloc_engine(); ++ if (unlikely(!engine)) ++ return ERR_PTR(-ENOMEM); ++ ++ goto first; ++ } ++ ++ if (!(flags & UTRACE_ATTACH_CREATE)) { ++ spin_lock(&utrace->lock); ++ engine = matching_engine(utrace, flags, ops, data); ++ if (engine) ++ utrace_engine_get(engine); ++ spin_unlock(&utrace->lock); ++ rcu_read_unlock(); ++ return engine ?: ERR_PTR(-ENOENT); ++ } ++ rcu_read_unlock(); ++ ++ if (unlikely(!ops) || unlikely(ops == &utrace_detached_ops)) ++ return ERR_PTR(-EINVAL); ++ ++ engine = alloc_engine(); ++ if (unlikely(!engine)) ++ return ERR_PTR(-ENOMEM); ++ ++ rcu_read_lock(); ++ utrace = rcu_dereference(target->utrace); ++ if (unlikely(utrace == NULL)) { /* Race with detach. */ ++ rcu_read_unlock(); ++ goto first; ++ } ++ spin_lock(&utrace->lock); ++ ++ if (flags & UTRACE_ATTACH_EXCLUSIVE) { ++ struct utrace_attached_engine *old; ++ old = matching_engine(utrace, flags, ops, data); ++ if (old) { ++ spin_unlock(&utrace->lock); ++ rcu_read_unlock(); ++ kmem_cache_free(utrace_engine_cachep, engine); ++ return ERR_PTR(-EEXIST); ++ } ++ } ++ ++ if (unlikely(rcu_dereference(target->utrace) != utrace)) { ++ /* ++ * We lost a race with other CPUs doing a sequence ++ * of detach and attach before we got in. ++ */ ++ spin_unlock(&utrace->lock); ++ rcu_read_unlock(); ++ kmem_cache_free(utrace_engine_cachep, engine); ++ goto restart; ++ } ++ rcu_read_unlock(); ++ ++ list_add_tail(&engine->entry, &utrace->attaching); ++ utrace->report = 1; ++ goto finish; ++ ++first: ++ utrace = utrace_first_engine(target, engine); ++ if (IS_ERR(utrace) || unlikely(utrace == NULL)) { ++ kmem_cache_free(utrace_engine_cachep, engine); ++ if (unlikely(utrace == NULL)) /* Race condition. */ ++ goto restart; ++ return ERR_PTR(PTR_ERR(utrace)); ++ } ++ ++finish: ++ engine->ops = ops; ++ engine->data = data; ++ ++ spin_unlock(&utrace->lock); ++ ++ return engine; ++} ++EXPORT_SYMBOL_GPL(utrace_attach_task); ++ ++/** ++ * utrace_attach_pid - attach new engine, or look up an attached engine ++ * @pid: &struct pid pointer representing thread to attach to ++ * @flags: flag bits combined with OR, see utrace_attach_task() ++ * @ops: callback table for new engine ++ * @data: engine private data pointer ++ * ++ * This is the same as utrace_attach_task(), but takes a &struct pid ++ * pointer rather than a &struct task_struct pointer. The caller must ++ * hold a ref on @pid, but does not need to worry about the task ++ * staying valid. If it's been reaped so that @pid points nowhere, ++ * then this call returns -%ESRCH. ++ */ ++struct utrace_attached_engine *utrace_attach_pid( ++ struct pid *pid, int flags, ++ const struct utrace_engine_ops *ops, void *data) ++{ ++ struct utrace_attached_engine *engine = ERR_PTR(-ESRCH); ++ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); ++ if (task) { ++ engine = utrace_attach_task(task, flags, ops, data); ++ put_task_struct(task); ++ } ++ return engine; ++} ++EXPORT_SYMBOL_GPL(utrace_attach_pid); ++ ++/* ++ * This is called with @utrace->lock held when the task is safely ++ * quiescent, i.e. it won't consult utrace->attached without the lock. ++ * Move any engines attached asynchronously from @utrace->attaching ++ * onto the @utrace->attached list. ++ */ ++static void splice_attaching(struct utrace *utrace) ++{ ++ list_splice_tail_init(&utrace->attaching, &utrace->attached); ++} ++ ++/* ++ * When an engine is detached, the target thread may still see it and ++ * make callbacks until it quiesces. We install a special ops vector ++ * with these two callbacks. When the target thread quiesces, it can ++ * safely free the engine itself. For any event we will always get ++ * the report_quiesce() callback first, so we only need this one ++ * pointer to be set. The only exception is report_reap(), so we ++ * supply that callback too. ++ */ ++static u32 utrace_detached_quiesce(enum utrace_resume_action action, ++ struct utrace_attached_engine *engine, ++ struct task_struct *task, ++ unsigned long event) ++{ ++ return UTRACE_DETACH; ++} ++ ++static void utrace_detached_reap(struct utrace_attached_engine *engine, ++ struct task_struct *task) ++{ ++} ++ ++static const struct utrace_engine_ops utrace_detached_ops = { ++ .report_quiesce = &utrace_detached_quiesce, ++ .report_reap = &utrace_detached_reap ++}; ++ ++/* ++ * Only these flags matter any more for a dead task (exit_state set). ++ * We use this mask on flags installed in ->utrace_flags after ++ * exit_notify (and possibly utrace_report_death) has run. ++ * This ensures that utrace_release_task knows positively that ++ * utrace_report_death will not run later. ++ */ ++#define DEAD_FLAGS_MASK (UTRACE_EVENT(REAP)) ++#define LIVE_FLAGS_MASK (~0UL) ++ ++/* ++ * Perform %UTRACE_STOP, i.e. block in TASK_TRACED until woken up. ++ * @task == current, @utrace == current->utrace, which is not locked. ++ * Return true if we were woken up by SIGKILL even though some utrace ++ * engine may still want us to stay stopped. ++ */ ++static bool utrace_stop(struct task_struct *task, struct utrace *utrace) ++{ ++ /* ++ * @utrace->stopped is the flag that says we are safely ++ * inside this function. It should never be set on entry. ++ */ ++ BUG_ON(utrace->stopped); ++ ++ /* ++ * The siglock protects us against signals. As well as SIGKILL ++ * waking us up, we must synchronize with the signal bookkeeping ++ * for stop signals and SIGCONT. ++ */ ++ spin_lock(&utrace->lock); ++ spin_lock_irq(&task->sighand->siglock); ++ ++ if (unlikely(sigismember(&task->pending.signal, SIGKILL))) { ++ spin_unlock_irq(&task->sighand->siglock); ++ spin_unlock(&utrace->lock); ++ return true; ++ } ++ ++ utrace->stopped = 1; ++ __set_current_state(TASK_TRACED); ++ ++ /* ++ * If there is a group stop in progress, ++ * we must participate in the bookkeeping. ++ */ ++ if (task->signal->group_stop_count > 0) ++ --task->signal->group_stop_count; ++ ++ spin_unlock_irq(&task->sighand->siglock); ++ spin_unlock(&utrace->lock); ++ ++ schedule(); ++ ++ /* ++ * While in TASK_TRACED, we were considered "frozen enough". ++ * Now that we woke up, it's crucial if we're supposed to be ++ * frozen that we freeze now before running anything substantial. ++ */ ++ try_to_freeze(); ++ ++ /* ++ * utrace_wakeup() clears @utrace->stopped before waking us up. ++ * We're officially awake if it's clear. ++ */ ++ if (likely(!utrace->stopped)) ++ return false; ++ ++ /* ++ * If we're here with it still set, it must have been ++ * signal_wake_up() instead, waking us up for a SIGKILL. ++ */ ++ spin_lock(&utrace->lock); ++ utrace->stopped = 0; ++ spin_unlock(&utrace->lock); ++ return true; ++} ++ ++/* ++ * The caller has to hold a ref on the engine. If the attached flag is ++ * true (all but utrace_barrier() calls), the engine is supposed to be ++ * attached. If the attached flag is false (utrace_barrier() only), ++ * then return -ERESTARTSYS for an engine marked for detach but not yet ++ * fully detached. The task pointer can be invalid if the engine is ++ * detached. ++ * ++ * Get the utrace lock for the target task. ++ * Returns the struct if locked, or ERR_PTR(-errno). ++ * ++ * This has to be robust against races with: ++ * utrace_control(target, UTRACE_DETACH) calls ++ * UTRACE_DETACH after reports ++ * utrace_report_death ++ * utrace_release_task ++ */ ++static struct utrace *get_utrace_lock(struct task_struct *target, ++ struct utrace_attached_engine *engine, ++ bool attached) ++ __acquires(utrace->lock) ++{ ++ struct utrace *utrace; ++ ++ /* ++ * You must hold a ref to be making a call. A call from within ++ * a report_* callback in @target might only have the ref for ++ * being attached, not a second one of its own. ++ */ ++ if (unlikely(atomic_read(&engine->kref.refcount) < 1)) ++ return ERR_PTR(-EINVAL); ++ ++ rcu_read_lock(); ++ ++ /* ++ * If this engine was already detached, bail out before we look at ++ * the task_struct pointer at all. If it's detached after this ++ * check, then RCU is still keeping this task_struct pointer valid. ++ * ++ * The ops pointer is NULL when the engine is fully detached. ++ * It's &utrace_detached_ops when it's marked detached but still ++ * on the list. In the latter case, utrace_barrier() still works, ++ * since the target might be in the middle of an old callback. ++ */ ++ if (unlikely(!engine->ops)) { ++ rcu_read_unlock(); ++ return ERR_PTR(-ESRCH); ++ } ++ ++ if (unlikely(engine->ops == &utrace_detached_ops)) { ++ rcu_read_unlock(); ++ return attached ? ERR_PTR(-ESRCH) : ERR_PTR(-ERESTARTSYS); ++ } ++ ++ utrace = rcu_dereference(target->utrace); ++ smp_rmb(); ++ if (unlikely(!utrace) || unlikely(target->exit_state == EXIT_DEAD)) { ++ /* ++ * If all engines detached already, utrace is clear. ++ * Otherwise, we're called after utrace_release_task might ++ * have started. A call to this engine's report_reap ++ * callback might already be in progress. ++ */ ++ utrace = ERR_PTR(-ESRCH); ++ } else { ++ spin_lock(&utrace->lock); ++ if (unlikely(rcu_dereference(target->utrace) != utrace) || ++ unlikely(!engine->ops) || ++ unlikely(engine->ops == &utrace_detached_ops)) { ++ /* ++ * By the time we got the utrace lock, ++ * it had been reaped or detached already. ++ */ ++ spin_unlock(&utrace->lock); ++ utrace = ERR_PTR(-ESRCH); ++ if (!attached && engine->ops == &utrace_detached_ops) ++ utrace = ERR_PTR(-ERESTARTSYS); ++ } ++ } ++ rcu_read_unlock(); ++ ++ return utrace; ++} ++ ++/* ++ * Now that we don't hold any locks, run through any ++ * detached engines and free their references. Each ++ * engine had one implicit ref while it was attached. ++ */ ++static void put_detached_list(struct list_head *list) ++{ ++ struct utrace_attached_engine *engine, *next; ++ list_for_each_entry_safe(engine, next, list, entry) { ++ list_del_init(&engine->entry); ++ utrace_engine_put(engine); ++ } ++} ++ ++/* ++ * Called with utrace->lock held. ++ * Notify and clean up all engines, then free utrace. ++ */ ++static void utrace_reap(struct task_struct *target, struct utrace *utrace) ++ __releases(utrace->lock) ++{ ++ struct utrace_attached_engine *engine, *next; ++ const struct utrace_engine_ops *ops; ++ LIST_HEAD(detached); ++ ++restart: ++ splice_attaching(utrace); ++ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { ++ ops = engine->ops; ++ engine->ops = NULL; ++ list_move(&engine->entry, &detached); ++ ++ /* ++ * If it didn't need a callback, we don't need to drop ++ * the lock. Now nothing else refers to this engine. ++ */ ++ if (!(engine->flags & UTRACE_EVENT(REAP))) ++ continue; ++ ++ utrace->reporting = engine; ++ spin_unlock(&utrace->lock); ++ ++ (*ops->report_reap)(engine, target); ++ ++ utrace->reporting = NULL; ++ ++ put_detached_list(&detached); ++ ++ spin_lock(&utrace->lock); ++ goto restart; ++ } ++ ++ rcu_utrace_free(utrace); /* Releases the lock. */ ++ ++ put_detached_list(&detached); ++} ++ ++#define DEATH_EVENTS (UTRACE_EVENT(DEATH) | UTRACE_EVENT(QUIESCE)) ++ ++/* ++ * Called by release_task. After this, target->utrace must be cleared. ++ */ ++void utrace_release_task(struct task_struct *target) ++{ ++ struct utrace *utrace; ++ ++ task_lock(target); ++ utrace = rcu_dereference(target->utrace); ++ rcu_assign_pointer(target->utrace, NULL); ++ task_unlock(target); ++ ++ if (unlikely(utrace == NULL)) ++ return; ++ ++ spin_lock(&utrace->lock); ++ /* ++ * If the list is empty, utrace is already on its way to be freed. ++ * We raced with detach and we won the task_lock race but lost the ++ * utrace->lock race. All we have to do is let RCU run. ++ */ ++ if (likely(!list_empty(&utrace->attached))) { ++ utrace->reap = 1; ++ ++ if (!(target->utrace_flags & DEATH_EVENTS)) { ++ utrace_reap(target, utrace); /* Unlocks and frees. */ ++ return; ++ } ++ ++ /* ++ * The target will do some final callbacks but hasn't ++ * finished them yet. We know because it clears these ++ * event bits after it's done. Instead of cleaning up here ++ * and requiring utrace_report_death to cope with it, we ++ * delay the REAP report and the teardown until after the ++ * target finishes its death reports. ++ */ ++ } ++ spin_unlock(&utrace->lock); ++} ++ ++/* ++ * We use an extra bit in utrace_attached_engine.flags past the event bits, ++ * to record whether the engine is keeping the target thread stopped. ++ */ ++#define ENGINE_STOP (1UL << _UTRACE_NEVENTS) ++ ++static void mark_engine_wants_stop(struct utrace_attached_engine *engine) ++{ ++ engine->flags |= ENGINE_STOP; ++} ++ ++static void clear_engine_wants_stop(struct utrace_attached_engine *engine) ++{ ++ engine->flags &= ~ENGINE_STOP; ++} ++ ++static bool engine_wants_stop(struct utrace_attached_engine *engine) ++{ ++ return (engine->flags & ENGINE_STOP) != 0; ++} ++ ++/** ++ * utrace_set_events - choose which event reports a tracing engine gets ++ * @target: thread to affect ++ * @engine: attached engine to affect ++ * @events: new event mask ++ * ++ * This changes the set of events for which @engine wants callbacks made. ++ * ++ * This fails with -%EALREADY and does nothing if you try to clear ++ * %UTRACE_EVENT(%DEATH) when the @report_death callback may already have ++ * begun, if you try to clear %UTRACE_EVENT(%REAP) when the @report_reap ++ * callback may already have begun, or if you try to newly set ++ * %UTRACE_EVENT(%DEATH) or %UTRACE_EVENT(%QUIESCE) when @target is ++ * already dead or dying. ++ * ++ * This can fail with -%ESRCH when @target has already been detached, ++ * including forcible detach on reaping. ++ * ++ * If @target was stopped before the call, then after a successful call, ++ * no event callbacks not requested in @events will be made; if ++ * %UTRACE_EVENT(%QUIESCE) is included in @events, then a @report_quiesce ++ * callback will be made when @target resumes. If @target was not stopped, ++ * and was about to make a callback to @engine, this returns -%EINPROGRESS. ++ * In this case, the callback in progress might be one excluded from the ++ * new @events setting. When this returns zero, you can be sure that no ++ * event callbacks you've disabled in @events can be made. ++ * ++ * To synchronize after an -%EINPROGRESS return, see utrace_barrier(). ++ * ++ * These rules provide for coherent synchronization based on %UTRACE_STOP, ++ * even when %SIGKILL is breaking its normal simple rules. ++ */ ++int utrace_set_events(struct task_struct *target, ++ struct utrace_attached_engine *engine, ++ unsigned long events) ++{ ++ struct utrace *utrace; ++ unsigned long old_flags, old_utrace_flags, set_utrace_flags; ++ struct sighand_struct *sighand; ++ unsigned long flags; ++ int ret; ++ ++ utrace = get_utrace_lock(target, engine, true); ++ if (unlikely(IS_ERR(utrace))) ++ return PTR_ERR(utrace); ++ ++ old_utrace_flags = target->utrace_flags; ++ set_utrace_flags = events; ++ old_flags = engine->flags; ++ ++ if (target->exit_state && ++ (((events & ~old_flags) & DEATH_EVENTS) || ++ (utrace->death && ((old_flags & ~events) & DEATH_EVENTS)) || ++ (utrace->reap && ((old_flags & ~events) & UTRACE_EVENT(REAP))))) { ++ spin_unlock(&utrace->lock); ++ return -EALREADY; ++ } ++ ++ /* ++ * When it's in TASK_STOPPED state and UTRACE_EVENT(JCTL) is set, ++ * utrace_do_stop() will think it is still running and needs to ++ * finish utrace_report_jctl() before it's really stopped. But ++ * if the bit wasn't already set, it can't be running in there ++ * and really is quiescent now in its existing job control stop. ++ */ ++ if (!utrace->stopped && ++ ((set_utrace_flags & ~old_utrace_flags) & UTRACE_EVENT(JCTL))) { ++ sighand = lock_task_sighand(target, &flags); ++ if (likely(sighand)) { ++ if (task_is_stopped(target)) ++ utrace->stopped = 1; ++ unlock_task_sighand(target, &flags); ++ } ++ } ++ ++ /* ++ * When setting these flags, it's essential that we really ++ * synchronize with exit_notify(). They cannot be set after ++ * exit_notify() takes the tasklist_lock. By holding the read ++ * lock here while setting the flags, we ensure that the calls ++ * to tracehook_notify_death() and tracehook_report_death() will ++ * see the new flags. This ensures that utrace_release_task() ++ * knows positively that utrace_report_death() will be called or ++ * that it won't. ++ */ ++ if ((set_utrace_flags & ~old_utrace_flags) & DEATH_EVENTS) { ++ read_lock(&tasklist_lock); ++ if (unlikely(target->exit_state)) { ++ read_unlock(&tasklist_lock); ++ spin_unlock(&utrace->lock); ++ return -EALREADY; ++ } ++ target->utrace_flags |= set_utrace_flags; ++ read_unlock(&tasklist_lock); ++ } ++ ++ engine->flags = events | (engine->flags & ENGINE_STOP); ++ target->utrace_flags |= set_utrace_flags; ++ ++ if ((set_utrace_flags & UTRACE_EVENT_SYSCALL) && ++ !(old_utrace_flags & UTRACE_EVENT_SYSCALL)) ++ set_tsk_thread_flag(target, TIF_SYSCALL_TRACE); ++ ++ ret = 0; ++ if (!utrace->stopped && target != current) { ++ smp_mb(); ++ if (utrace->reporting == engine) ++ ret = -EINPROGRESS; ++ } ++ ++ spin_unlock(&utrace->lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(utrace_set_events); ++ ++/* ++ * Asynchronously mark an engine as being detached. ++ * ++ * This must work while the target thread races with us doing ++ * start_callback(), defined below. It uses smp_rmb() between checking ++ * @engine->flags and using @engine->ops. Here we change @engine->ops ++ * first, then use smp_wmb() before changing @engine->flags. This ensures ++ * it can check the old flags before using the old ops, or check the old ++ * flags before using the new ops, or check the new flags before using the ++ * new ops, but can never check the new flags before using the old ops. ++ * Hence, utrace_detached_ops might be used with any old flags in place. ++ * It has report_quiesce() and report_reap() callbacks to handle all cases. ++ */ ++static void mark_engine_detached(struct utrace_attached_engine *engine) ++{ ++ engine->ops = &utrace_detached_ops; ++ smp_wmb(); ++ engine->flags = UTRACE_EVENT(QUIESCE); ++} ++ ++/* ++ * Get @target to stop and return true if it is already stopped now. ++ * If we return false, it will make some event callback soonish. ++ * Called with @utrace locked. ++ */ ++static bool utrace_do_stop(struct task_struct *target, struct utrace *utrace) ++{ ++ bool stopped; ++ ++ /* ++ * If it will call utrace_report_jctl() but has not gotten ++ * through it yet, then don't consider it quiescent yet. ++ * utrace_report_jctl() will take @utrace->lock and ++ * set @utrace->stopped itself once it finishes. After that, ++ * it is considered quiescent; when it wakes up, it will go ++ * through utrace_get_signal() before doing anything else. ++ */ ++ if (task_is_stopped(target) && ++ !(target->utrace_flags & UTRACE_EVENT(JCTL))) { ++ utrace->stopped = 1; ++ return true; ++ } ++ ++ stopped = false; ++ spin_lock_irq(&target->sighand->siglock); ++ if (unlikely(target->exit_state)) { ++ /* ++ * On the exit path, it's only truly quiescent ++ * if it has already been through ++ * utrace_report_death(), or never will. ++ */ ++ if (!(target->utrace_flags & DEATH_EVENTS)) ++ utrace->stopped = stopped = true; ++ } else if (task_is_stopped(target)) { ++ if (!(target->utrace_flags & UTRACE_EVENT(JCTL))) ++ utrace->stopped = stopped = true; ++ } else if (!utrace->report && !utrace->interrupt) { ++ utrace->report = 1; ++ set_notify_resume(target); ++ } ++ spin_unlock_irq(&target->sighand->siglock); ++ ++ return stopped; ++} ++ ++/* ++ * If the target is not dead it should not be in tracing ++ * stop any more. Wake it unless it's in job control stop. ++ * ++ * Called with @utrace->lock held and @utrace->stopped set. ++ */ ++static void utrace_wakeup(struct task_struct *target, struct utrace *utrace) ++{ ++ struct sighand_struct *sighand; ++ unsigned long irqflags; ++ ++ utrace->stopped = 0; ++ ++ sighand = lock_task_sighand(target, &irqflags); ++ if (unlikely(!sighand)) ++ return; ++ ++ if (likely(task_is_stopped_or_traced(target))) { ++ if (target->signal->flags & SIGNAL_STOP_STOPPED) ++ target->state = TASK_STOPPED; ++ else ++ wake_up_state(target, __TASK_STOPPED | __TASK_TRACED); ++ } ++ ++ unlock_task_sighand(target, &irqflags); ++} ++ ++/* ++ * This is called when there might be some detached engines on the list or ++ * some stale bits in @task->utrace_flags. Clean them up and recompute the ++ * flags. ++ * ++ * @wake is false when @task is current. @wake is true when @task is ++ * stopped and @utrace->stopped is set; wake it up if it should not be. ++ * ++ * Called with @utrace->lock held, returns with it released. ++ */ ++static void utrace_reset(struct task_struct *task, struct utrace *utrace, ++ bool wake) ++ __releases(utrace->lock) ++{ ++ struct utrace_attached_engine *engine, *next; ++ unsigned long flags = 0; ++ LIST_HEAD(detached); ++ ++ splice_attaching(utrace); ++ ++ /* ++ * Update the set of events of interest from the union ++ * of the interests of the remaining tracing engines. ++ * For any engine marked detached, remove it from the list. ++ * We'll collect them on the detached list. ++ */ ++ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { ++ if (engine->ops == &utrace_detached_ops) { ++ engine->ops = NULL; ++ list_move(&engine->entry, &detached); ++ } else { ++ flags |= engine->flags | UTRACE_EVENT(REAP); ++ wake = wake && !engine_wants_stop(engine); ++ } ++ } ++ ++ if (task->exit_state) { ++ BUG_ON(utrace->death); ++ flags &= DEAD_FLAGS_MASK; ++ wake = false; ++ } else if (!(flags & UTRACE_EVENT_SYSCALL) && ++ test_tsk_thread_flag(task, TIF_SYSCALL_TRACE)) { ++ clear_tsk_thread_flag(task, TIF_SYSCALL_TRACE); ++ } ++ ++ task->utrace_flags = flags; ++ ++ if (wake) ++ utrace_wakeup(task, utrace); ++ ++ /* ++ * If any engines are left, we're done. ++ */ ++ if (flags) { ++ spin_unlock(&utrace->lock); ++ goto done; ++ } ++ ++ /* ++ * No more engines, clear out the utrace. Here we can race with ++ * utrace_release_task(). If it gets task_lock() first, then it ++ * cleans up this struct for us. ++ */ ++ ++ task_lock(task); ++ ++ if (unlikely(task->utrace != utrace)) { ++ task_unlock(task); ++ spin_unlock(&utrace->lock); ++ goto done; ++ } ++ ++ rcu_assign_pointer(task->utrace, NULL); ++ ++ task_unlock(task); ++ ++ rcu_utrace_free(utrace); ++ ++done: ++ put_detached_list(&detached); ++} ++ ++/** ++ * utrace_control - control a thread being traced by a tracing engine ++ * @target: thread to affect ++ * @engine: attached engine to affect ++ * @action: &enum utrace_resume_action for thread to do ++ * ++ * This is how a tracing engine asks a traced thread to do something. ++ * This call is controlled by the @action argument, which has the ++ * same meaning as the &enum utrace_resume_action value returned by ++ * event reporting callbacks. ++ * ++ * If @target is already dead (@target->exit_state nonzero), ++ * all actions except %UTRACE_DETACH fail with -%ESRCH. ++ * ++ * The following sections describe each option for the @action argument. ++ * ++ * UTRACE_DETACH: ++ * ++ * After this, the @engine data structure is no longer accessible, ++ * and the thread might be reaped. The thread will start running ++ * again if it was stopped and no longer has any attached engines ++ * that want it stopped. ++ * ++ * If the @report_reap callback may already have begun, this fails ++ * with -%ESRCH. If the @report_death callback may already have ++ * begun, this fails with -%EALREADY. ++ * ++ * If @target is not already stopped, then a callback to this engine ++ * might be in progress or about to start on another CPU. If so, ++ * then this returns -%EINPROGRESS; the detach happens as soon as ++ * the pending callback is finished. To synchronize after an ++ * -%EINPROGRESS return, see utrace_barrier(). ++ * ++ * If @target is properly stopped before utrace_control() is called, ++ * then after successful return it's guaranteed that no more callbacks ++ * to the @engine->ops vector will be made. ++ * ++ * The only exception is %SIGKILL (and exec or group-exit by another ++ * thread in the group), which can cause asynchronous @report_death ++ * and/or @report_reap callbacks even when %UTRACE_STOP was used. ++ * (In that event, this fails with -%ESRCH or -%EALREADY, see above.) ++ * ++ * UTRACE_STOP: ++ * This asks that @target stop running. This returns 0 only if ++ * @target is already stopped, either for tracing or for job ++ * control. Then @target will remain stopped until another ++ * utrace_control() call is made on @engine; @target can be woken ++ * only by %SIGKILL (or equivalent, such as exec or termination by ++ * another thread in the same thread group). ++ * ++ * This returns -%EINPROGRESS if @target is not already stopped. ++ * Then the effect is like %UTRACE_REPORT. A @report_quiesce or ++ * @report_signal callback will be made soon. Your callback can ++ * then return %UTRACE_STOP to keep @target stopped. ++ * ++ * This does not interrupt system calls in progress, including ones ++ * that sleep for a long time. For that, use %UTRACE_INTERRUPT. ++ * To interrupt system calls and then keep @target stopped, your ++ * @report_signal callback can return %UTRACE_STOP. ++ * ++ * UTRACE_RESUME: ++ * ++ * Just let @target continue running normally, reversing the effect ++ * of a previous %UTRACE_STOP. If another engine is keeping @target ++ * stopped, then it remains stopped until all engines let it resume. ++ * If @target was not stopped, this has no effect. ++ * ++ * UTRACE_REPORT: ++ * ++ * This is like %UTRACE_RESUME, but also ensures that there will be ++ * a @report_quiesce or @report_signal callback made soon. If ++ * @target had been stopped, then there will be a callback before it ++ * resumes running normally. If another engine is keeping @target ++ * stopped, then there might be no callbacks until all engines let ++ * it resume. ++ * ++ * UTRACE_INTERRUPT: ++ * ++ * This is like %UTRACE_REPORT, but ensures that @target will make a ++ * @report_signal callback before it resumes or delivers signals. ++ * If @target was in a system call or about to enter one, work in ++ * progress will be interrupted as if by %SIGSTOP. If another ++ * engine is keeping @target stopped, then there might be no ++ * callbacks until all engines let it resume. ++ * ++ * This gives @engine an opportunity to introduce a forced signal ++ * disposition via its @report_signal callback. ++ * ++ * UTRACE_SINGLESTEP: ++ * ++ * It's invalid to use this unless arch_has_single_step() returned true. ++ * This is like %UTRACE_RESUME, but resumes for one user instruction ++ * only. It's invalid to use this in utrace_control() unless @target ++ * had been stopped by @engine previously. ++ * ++ * Note that passing %UTRACE_SINGLESTEP or %UTRACE_BLOCKSTEP to ++ * utrace_control() or returning it from an event callback alone does ++ * not necessarily ensure that stepping will be enabled. If there are ++ * more callbacks made to any engine before returning to user mode, ++ * then the resume action is chosen only by the last set of callbacks. ++ * To be sure, enable %UTRACE_EVENT(%QUIESCE) and look for the ++ * @report_quiesce callback with a zero event mask, or the ++ * @report_signal callback with %UTRACE_SIGNAL_REPORT. ++ * ++ * UTRACE_BLOCKSTEP: ++ * ++ * It's invalid to use this unless arch_has_block_step() returned true. ++ * This is like %UTRACE_SINGLESTEP, but resumes for one whole basic ++ * block of user instructions. ++ * ++ * %UTRACE_BLOCKSTEP devolves to %UTRACE_SINGLESTEP when another ++ * tracing engine is using %UTRACE_SINGLESTEP at the same time. ++ */ ++int utrace_control(struct task_struct *target, ++ struct utrace_attached_engine *engine, ++ enum utrace_resume_action action) ++{ ++ struct utrace *utrace; ++ bool resume; ++ int ret; ++ ++ if (unlikely(action > UTRACE_DETACH)) ++ return -EINVAL; ++ ++ utrace = get_utrace_lock(target, engine, true); ++ if (unlikely(IS_ERR(utrace))) ++ return PTR_ERR(utrace); ++ ++ if (target->exit_state) { ++ /* ++ * You can't do anything to a dead task but detach it. ++ * If release_task() has been called, you can't do that. ++ * ++ * On the exit path, DEATH and QUIESCE event bits are ++ * set only before utrace_report_death() has taken the ++ * lock. At that point, the death report will come ++ * soon, so disallow detach until it's done. This ++ * prevents us from racing with it detaching itself. ++ */ ++ if (action != UTRACE_DETACH || ++ unlikely(utrace->reap)) { ++ spin_unlock(&utrace->lock); ++ return -ESRCH; ++ } else if (unlikely(target->utrace_flags & DEATH_EVENTS) || ++ unlikely(utrace->death)) { ++ /* ++ * We have already started the death report, or ++ * are about to very soon. We can't prevent ++ * the report_death and report_reap callbacks, ++ * so tell the caller they will happen. ++ */ ++ spin_unlock(&utrace->lock); ++ return -EALREADY; ++ } ++ } ++ ++ resume = utrace->stopped; ++ ret = 0; ++ ++ clear_engine_wants_stop(engine); ++ switch (action) { ++ case UTRACE_STOP: ++ mark_engine_wants_stop(engine); ++ if (!resume && !utrace_do_stop(target, utrace)) ++ ret = -EINPROGRESS; ++ resume = false; ++ break; ++ ++ case UTRACE_DETACH: ++ mark_engine_detached(engine); ++ resume = resume || utrace_do_stop(target, utrace); ++ if (!resume) { ++ smp_mb(); ++ if (utrace->reporting == engine) ++ ret = -EINPROGRESS; ++ break; ++ } ++ /* Fall through. */ ++ ++ case UTRACE_RESUME: ++ /* ++ * This and all other cases imply resuming if stopped. ++ * There might not be another report before it just ++ * resumes, so make sure single-step is not left set. ++ */ ++ if (likely(resume)) ++ user_disable_single_step(target); ++ break; ++ ++ case UTRACE_REPORT: ++ /* ++ * Make the thread call tracehook_notify_resume() soon. ++ * But don't bother if it's already been stopped or ++ * interrupted. In those cases, utrace_get_signal() ++ * will be reporting soon. ++ */ ++ if (!utrace->report && !utrace->interrupt && !utrace->stopped) { ++ utrace->report = 1; ++ set_notify_resume(target); ++ } ++ break; ++ ++ case UTRACE_INTERRUPT: ++ /* ++ * Make the thread call tracehook_get_signal() soon. ++ */ ++ if (utrace->interrupt) ++ break; ++ utrace->interrupt = 1; ++ ++ /* ++ * If it's not already stopped, interrupt it now. ++ * We need the siglock here in case it calls ++ * recalc_sigpending() and clears its own ++ * TIF_SIGPENDING. By taking the lock, we've ++ * serialized any later recalc_sigpending() after ++ * our setting of utrace->interrupt to force it on. ++ */ ++ if (resume) { ++ /* ++ * This is really just to keep the invariant ++ * that TIF_SIGPENDING is set with utrace->interrupt. ++ * When it's stopped, we know it's always going ++ * through utrace_get_signal and will recalculate. ++ */ ++ set_tsk_thread_flag(target, TIF_SIGPENDING); ++ } else { ++ struct sighand_struct *sighand; ++ unsigned long irqflags; ++ sighand = lock_task_sighand(target, &irqflags); ++ if (likely(sighand)) { ++ signal_wake_up(target, 0); ++ unlock_task_sighand(target, &irqflags); ++ } ++ } ++ break; ++ ++ case UTRACE_BLOCKSTEP: ++ /* ++ * Resume from stopped, step one block. ++ */ ++ if (unlikely(!arch_has_block_step())) { ++ WARN_ON(1); ++ /* Fall through to treat it as SINGLESTEP. */ ++ } else if (likely(resume)) { ++ user_enable_block_step(target); ++ break; ++ } ++ ++ case UTRACE_SINGLESTEP: ++ /* ++ * Resume from stopped, step one instruction. ++ */ ++ if (unlikely(!arch_has_single_step())) { ++ WARN_ON(1); ++ resume = false; ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ if (likely(resume)) ++ user_enable_single_step(target); ++ else ++ /* ++ * You were supposed to stop it before asking ++ * it to step. ++ */ ++ ret = -EAGAIN; ++ break; ++ } ++ ++ /* ++ * Let the thread resume running. If it's not stopped now, ++ * there is nothing more we need to do. ++ */ ++ if (resume) ++ utrace_reset(target, utrace, true); ++ else ++ spin_unlock(&utrace->lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(utrace_control); ++ ++/** ++ * utrace_barrier - synchronize with simultaneous tracing callbacks ++ * @target: thread to affect ++ * @engine: engine to affect (can be detached) ++ * ++ * This blocks while @target might be in the midst of making a callback to ++ * @engine. It can be interrupted by signals and will return -%ERESTARTSYS. ++ * A return value of zero means no callback from @target to @engine was ++ * in progress. ++ * ++ * It's not necessary to keep the @target pointer alive for this call. ++ * It's only necessary to hold a ref on @engine. This will return ++ * safely even if @target has been reaped and has no task refs. ++ * ++ * A successful return from utrace_barrier() guarantees its ordering ++ * with respect to utrace_set_events() and utrace_control() calls. If ++ * @target was not properly stopped, event callbacks just disabled might ++ * still be in progress; utrace_barrier() waits until there is no chance ++ * an unwanted callback can be in progress. ++ */ ++int utrace_barrier(struct task_struct *target, ++ struct utrace_attached_engine *engine) ++{ ++ struct utrace *utrace; ++ int ret = -ERESTARTSYS; ++ ++ if (unlikely(target == current)) ++ return 0; ++ ++ do { ++ utrace = get_utrace_lock(target, engine, false); ++ if (unlikely(IS_ERR(utrace))) { ++ ret = PTR_ERR(utrace); ++ if (ret != -ERESTARTSYS) ++ break; ++ } else { ++ if (utrace->stopped || utrace->reporting != engine) ++ ret = 0; ++ spin_unlock(&utrace->lock); ++ if (!ret) ++ break; ++ } ++ schedule_timeout_interruptible(1); ++ } while (!signal_pending(current)); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(utrace_barrier); ++ ++/* ++ * This is local state used for reporting loops, perhaps optimized away. ++ */ ++struct utrace_report { ++ enum utrace_resume_action action; ++ u32 result; ++ bool detaches; ++ bool takers; ++ bool killed; ++}; ++ ++#define INIT_REPORT(var) \ ++ struct utrace_report var = { UTRACE_RESUME, 0, false, false, false } ++ ++/* ++ * We are now making the report, so clear the flag saying we need one. ++ */ ++static void start_report(struct utrace *utrace) ++{ ++ BUG_ON(utrace->stopped); ++ if (utrace->report) { ++ spin_lock(&utrace->lock); ++ utrace->report = 0; ++ splice_attaching(utrace); ++ spin_unlock(&utrace->lock); ++ } ++} ++ ++/* ++ * Complete a normal reporting pass, pairing with a start_report() call. ++ * This handles any UTRACE_DETACH or UTRACE_REPORT or UTRACE_INTERRUPT ++ * returns from engine callbacks. If any engine's last callback used ++ * UTRACE_STOP, we do UTRACE_REPORT here to ensure we stop before user ++ * mode. If there were no callbacks made, it will recompute ++ * @task->utrace_flags to avoid another false-positive. ++ */ ++static void finish_report(struct utrace_report *report, ++ struct task_struct *task, struct utrace *utrace) ++{ ++ bool clean = (report->takers && !report->detaches); ++ ++ if (report->action <= UTRACE_REPORT && !utrace->report) { ++ spin_lock(&utrace->lock); ++ utrace->report = 1; ++ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); ++ } else if (report->action == UTRACE_INTERRUPT && !utrace->interrupt) { ++ spin_lock(&utrace->lock); ++ utrace->interrupt = 1; ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ } else if (clean) { ++ return; ++ } else { ++ spin_lock(&utrace->lock); ++ } ++ ++ if (clean) ++ spin_unlock(&utrace->lock); ++ else ++ utrace_reset(task, utrace, false); ++} ++ ++/* ++ * Apply the return value of one engine callback to @report. ++ * Returns true if @engine detached and should not get any more callbacks. ++ */ ++static bool finish_callback(struct utrace *utrace, ++ struct utrace_report *report, ++ struct utrace_attached_engine *engine, ++ u32 ret) ++{ ++ enum utrace_resume_action action = utrace_resume_action(ret); ++ ++ utrace->reporting = NULL; ++ ++ /* ++ * This is a good place to make sure tracing engines don't ++ * introduce too much latency under voluntary preemption. ++ */ ++ if (need_resched()) ++ cond_resched(); ++ ++ report->result = ret & ~UTRACE_RESUME_MASK; ++ ++ /* ++ * If utrace_control() was used, treat that like UTRACE_DETACH here. ++ */ ++ if (action == UTRACE_DETACH || engine->ops == &utrace_detached_ops) { ++ engine->ops = &utrace_detached_ops; ++ report->detaches = true; ++ return true; ++ } ++ ++ if (action < report->action) ++ report->action = action; ++ ++ if (action == UTRACE_STOP) { ++ if (!engine_wants_stop(engine)) { ++ spin_lock(&utrace->lock); ++ mark_engine_wants_stop(engine); ++ spin_unlock(&utrace->lock); ++ } ++ } else if (engine_wants_stop(engine)) { ++ spin_lock(&utrace->lock); ++ clear_engine_wants_stop(engine); ++ spin_unlock(&utrace->lock); ++ } ++ ++ return false; ++} ++ ++/* ++ * Start the callbacks for @engine to consider @event (a bit mask). ++ * This makes the report_quiesce() callback first. If @engine wants ++ * a specific callback for @event, we return the ops vector to use. ++ * If not, we return NULL. The return value from the ops->callback ++ * function called should be passed to finish_callback(). ++ */ ++static const struct utrace_engine_ops *start_callback( ++ struct utrace *utrace, struct utrace_report *report, ++ struct utrace_attached_engine *engine, struct task_struct *task, ++ unsigned long event) ++{ ++ const struct utrace_engine_ops *ops; ++ unsigned long want; ++ ++ utrace->reporting = engine; ++ smp_mb(); ++ ++ /* ++ * This pairs with the barrier in mark_engine_detached(). ++ * It makes sure that we never see the old ops vector with ++ * the new flags, in case the original vector had no report_quiesce. ++ */ ++ want = engine->flags; ++ smp_rmb(); ++ ops = engine->ops; ++ ++ if (want & UTRACE_EVENT(QUIESCE)) { ++ if (finish_callback(utrace, report, engine, ++ (*ops->report_quiesce)(report->action, ++ engine, task, ++ event))) ++ goto nocall; ++ ++ utrace->reporting = engine; ++ smp_mb(); ++ want = engine->flags; ++ } ++ ++ if (want & ENGINE_STOP) ++ report->action = UTRACE_STOP; ++ ++ if (want & event) { ++ report->takers = true; ++ return ops; ++ } ++ ++nocall: ++ utrace->reporting = NULL; ++ return NULL; ++} ++ ++/* ++ * Do a normal reporting pass for engines interested in @event. ++ * @callback is the name of the member in the ops vector, and remaining ++ * args are the extras it takes after the standard three args. ++ */ ++#define REPORT(task, utrace, report, event, callback, ...) \ ++ do { \ ++ start_report(utrace); \ ++ REPORT_CALLBACKS(task, utrace, report, event, callback, \ ++ (report)->action, engine, current, \ ++ ## __VA_ARGS__); \ ++ finish_report(report, task, utrace); \ ++ } while (0) ++#define REPORT_CALLBACKS(task, utrace, report, event, callback, ...) \ ++ do { \ ++ struct utrace_attached_engine *engine, *next; \ ++ const struct utrace_engine_ops *ops; \ ++ list_for_each_entry_safe(engine, next, \ ++ &utrace->attached, entry) { \ ++ ops = start_callback(utrace, report, engine, task, \ ++ event); \ ++ if (!ops) \ ++ continue; \ ++ finish_callback(utrace, report, engine, \ ++ (*ops->callback)(__VA_ARGS__)); \ ++ } \ ++ } while (0) ++ ++/* ++ * Called iff UTRACE_EVENT(EXEC) flag is set. ++ */ ++void utrace_report_exec(struct linux_binfmt *fmt, struct linux_binprm *bprm, ++ struct pt_regs *regs) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ ++ REPORT(task, utrace, &report, UTRACE_EVENT(EXEC), ++ report_exec, fmt, bprm, regs); ++} ++ ++/* ++ * Called iff UTRACE_EVENT(SYSCALL_ENTRY) flag is set. ++ * Return true to prevent the system call. ++ */ ++bool utrace_report_syscall_entry(struct pt_regs *regs) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ ++ start_report(utrace); ++ REPORT_CALLBACKS(task, utrace, &report, UTRACE_EVENT(SYSCALL_ENTRY), ++ report_syscall_entry, report.result | report.action, ++ engine, current, regs); ++ finish_report(&report, task, utrace); ++ ++ if (report.action == UTRACE_STOP && unlikely(utrace_stop(task, utrace))) ++ /* ++ * We are continuing despite UTRACE_STOP because of a ++ * SIGKILL. Don't let the system call actually proceed. ++ */ ++ return true; ++ ++ if (unlikely(report.result == UTRACE_SYSCALL_ABORT)) ++ return true; ++ ++ if (signal_pending(task)) { ++ /* ++ * Clear TIF_SIGPENDING if it no longer needs to be set. ++ * It may have been set as part of quiescence, and won't ++ * ever have been cleared by another thread. For other ++ * reports, we can just leave it set and will go through ++ * utrace_get_signal() to reset things. But here we are ++ * about to enter a syscall, which might bail out with an ++ * -ERESTART* error if it's set now. ++ */ ++ spin_lock_irq(&task->sighand->siglock); ++ recalc_sigpending(); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ return false; ++} ++ ++/* ++ * Called iff UTRACE_EVENT(SYSCALL_EXIT) flag is set. ++ */ ++void utrace_report_syscall_exit(struct pt_regs *regs) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ ++ REPORT(task, utrace, &report, UTRACE_EVENT(SYSCALL_EXIT), ++ report_syscall_exit, regs); ++} ++ ++/* ++ * Called iff UTRACE_EVENT(CLONE) flag is set. ++ * This notification call blocks the wake_up_new_task call on the child. ++ * So we must not quiesce here. tracehook_report_clone_complete will do ++ * a quiescence check momentarily. ++ */ ++void utrace_report_clone(unsigned long clone_flags, struct task_struct *child) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ ++ utrace->u.live.cloning = child; ++ ++ REPORT(task, utrace, &report, UTRACE_EVENT(CLONE), ++ report_clone, clone_flags, child); ++ ++ utrace->u.live.cloning = NULL; ++} ++ ++/* ++ * Called iff UTRACE_EVENT(JCTL) flag is set. ++ */ ++void utrace_report_jctl(int notify, int what) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ bool was_stopped = task_is_stopped(task); ++ ++ /* ++ * We get here with CLD_STOPPED when we've just entered ++ * TASK_STOPPED, or with CLD_CONTINUED when we've just come ++ * out but not yet been through utrace_get_signal() again. ++ * ++ * While in TASK_STOPPED, we can be considered safely ++ * stopped by utrace_do_stop() and detached asynchronously. ++ * If we woke up and checked task->utrace_flags before that ++ * was finished, we might be here with utrace already ++ * removed or in the middle of being removed. ++ * ++ * RCU makes it safe to get the utrace->lock even if it's ++ * being freed. Once we have that lock, either an external ++ * detach has finished and this struct has been freed, or ++ * else we know we are excluding any other detach attempt. ++ * ++ * If we are indeed attached, then make sure we are no ++ * longer considered stopped while we run callbacks. ++ */ ++ rcu_read_lock(); ++ utrace = rcu_dereference(task->utrace); ++ if (unlikely(!utrace)) { ++ rcu_read_unlock(); ++ return; ++ } ++ spin_lock(&utrace->lock); ++ utrace->stopped = 0; ++ utrace->report = 0; ++ spin_unlock(&utrace->lock); ++ rcu_read_unlock(); ++ ++ REPORT(task, utrace, &report, UTRACE_EVENT(JCTL), ++ report_jctl, was_stopped ? CLD_STOPPED : CLD_CONTINUED, what); ++ ++ if (was_stopped && !task_is_stopped(task)) { ++ /* ++ * The event report hooks could have blocked, though ++ * it should have been briefly. Make sure we're in ++ * TASK_STOPPED state again to block properly, unless ++ * we've just come back out of job control stop. ++ */ ++ spin_lock_irq(&task->sighand->siglock); ++ if (task->signal->flags & SIGNAL_STOP_STOPPED) ++ __set_current_state(TASK_STOPPED); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ if (task_is_stopped(current)) { ++ /* ++ * While in TASK_STOPPED, we can be considered safely ++ * stopped by utrace_do_stop() only once we set this. ++ */ ++ spin_lock(&utrace->lock); ++ utrace->stopped = 1; ++ spin_unlock(&utrace->lock); ++ } ++} ++ ++/* ++ * Called iff UTRACE_EVENT(EXIT) flag is set. ++ */ ++void utrace_report_exit(long *exit_code) ++{ ++ struct task_struct *task = current; ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ long orig_code = *exit_code; ++ ++ REPORT(task, utrace, &report, UTRACE_EVENT(EXIT), ++ report_exit, orig_code, exit_code); ++ ++ if (report.action == UTRACE_STOP) ++ utrace_stop(task, utrace); ++} ++ ++/* ++ * Called iff UTRACE_EVENT(DEATH) or UTRACE_EVENT(QUIESCE) flag is set. ++ * ++ * It is always possible that we are racing with utrace_release_task here. ++ * For this reason, utrace_release_task checks for the event bits that get ++ * us here, and delays its cleanup for us to do. ++ */ ++void utrace_report_death(struct task_struct *task, struct utrace *utrace, ++ bool group_dead, int signal) ++{ ++ INIT_REPORT(report); ++ ++ BUG_ON(!task->exit_state); ++ ++ /* ++ * We are presently considered "quiescent"--which is accurate ++ * inasmuch as we won't run any more user instructions ever again. ++ * But for utrace_control and utrace_set_events to be robust, they ++ * must be sure whether or not we will run any more callbacks. If ++ * a call comes in before we do, taking the lock here synchronizes ++ * us so we don't run any callbacks just disabled. Calls that come ++ * in while we're running the callbacks will see the exit.death ++ * flag and know that we are not yet fully quiescent for purposes ++ * of detach bookkeeping. ++ */ ++ spin_lock(&utrace->lock); ++ BUG_ON(utrace->death); ++ utrace->death = 1; ++ utrace->report = 0; ++ utrace->interrupt = 0; ++ spin_unlock(&utrace->lock); ++ ++ REPORT_CALLBACKS(task, utrace, &report, UTRACE_EVENT(DEATH), ++ report_death, engine, task, group_dead, signal); ++ ++ spin_lock(&utrace->lock); ++ ++ /* ++ * After we unlock (possibly inside utrace_reap for callbacks) with ++ * this flag clear, competing utrace_control/utrace_set_events calls ++ * know that we've finished our callbacks and any detach bookkeeping. ++ */ ++ utrace->death = 0; ++ ++ if (utrace->reap) ++ /* ++ * utrace_release_task() was already called in parallel. ++ * We must complete its work now. ++ */ ++ utrace_reap(task, utrace); ++ else ++ utrace_reset(task, utrace, false); ++} ++ ++/* ++ * Finish the last reporting pass before returning to user mode. ++ * ++ * Returns true if we might have been in TASK_TRACED and then resumed. ++ * In that event, signal_pending() might not be set when it should be, ++ * as the signals code passes us over while we're in TASK_TRACED. ++ */ ++static bool finish_resume_report(struct utrace_report *report, ++ struct task_struct *task, ++ struct utrace *utrace) ++{ ++ if (report->detaches || !report->takers) { ++ spin_lock(&utrace->lock); ++ utrace_reset(task, utrace, false); ++ } ++ ++ switch (report->action) { ++ case UTRACE_INTERRUPT: ++ if (!signal_pending(task)) ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ break; ++ ++ case UTRACE_SINGLESTEP: ++ user_enable_single_step(task); ++ break; ++ ++ case UTRACE_BLOCKSTEP: ++ user_enable_block_step(task); ++ break; ++ ++ case UTRACE_STOP: ++ report->killed = utrace_stop(task, utrace); ++ return likely(!report->killed); ++ ++ case UTRACE_REPORT: ++ case UTRACE_RESUME: ++ default: ++ user_disable_single_step(task); ++ break; ++ } ++ ++ return false; ++} ++ ++/* ++ * This is called when TIF_NOTIFY_RESUME had been set (and is now clear). ++ * We are close to user mode, and this is the place to report or stop. ++ * When we return, we're going to user mode or into the signals code. ++ */ ++void utrace_resume(struct task_struct *task, struct pt_regs *regs) ++{ ++ struct utrace *utrace = task->utrace; ++ INIT_REPORT(report); ++ struct utrace_attached_engine *engine, *next; ++ ++ /* ++ * Some machines get here with interrupts disabled. The same arch ++ * code path leads to calling into get_signal_to_deliver(), which ++ * implicitly reenables them by virtue of spin_unlock_irq. ++ */ ++ local_irq_enable(); ++ ++ /* ++ * If this flag is still set it's because there was a signal ++ * handler setup done but no report_signal following it. Clear ++ * the flag before we get to user so it doesn't confuse us later. ++ */ ++ if (unlikely(utrace->signal_handler)) { ++ int skip; ++ spin_lock(&utrace->lock); ++ utrace->signal_handler = 0; ++ skip = !utrace->report; ++ spin_unlock(&utrace->lock); ++ if (skip) ++ return; ++ } ++ ++ /* ++ * If UTRACE_INTERRUPT was just used, we don't bother with a ++ * report here. We will report and stop in utrace_get_signal(). ++ */ ++ if (unlikely(utrace->interrupt)) { ++ BUG_ON(!signal_pending(task)); ++ return; ++ } ++ ++ /* ++ * Do a simple reporting pass, with no callback after report_quiesce. ++ */ ++ start_report(utrace); ++ ++ list_for_each_entry_safe(engine, next, &utrace->attached, entry) ++ start_callback(utrace, &report, engine, task, 0); ++ ++ /* ++ * Finish the report and either stop or get ready to resume. ++ * If we stop and then signal_pending() is clear, we ++ * should recompute it before returning to user mode. ++ */ ++ if (finish_resume_report(&report, task, utrace) && ++ !signal_pending(task)) { ++ spin_lock_irq(&task->sighand->siglock); ++ recalc_sigpending(); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++} ++ ++/* ++ * Return true if current has forced signal_pending(). ++ * ++ * This is called only when current->utrace_flags is nonzero, so we know ++ * that current->utrace must be set. It's not inlined in tracehook.h ++ * just so that struct utrace can stay opaque outside this file. ++ */ ++bool utrace_interrupt_pending(void) ++{ ++ return current->utrace->interrupt; ++} ++ ++/* ++ * Take the siglock and push @info back on our queue. ++ * Returns with @task->sighand->siglock held. ++ */ ++static void push_back_signal(struct task_struct *task, siginfo_t *info) ++ __acquires(task->sighand->siglock) ++{ ++ struct sigqueue *q; ++ ++ if (unlikely(!info->si_signo)) { /* Oh, a wise guy! */ ++ spin_lock_irq(&task->sighand->siglock); ++ return; ++ } ++ ++ q = sigqueue_alloc(); ++ if (likely(q)) { ++ q->flags = 0; ++ copy_siginfo(&q->info, info); ++ } ++ ++ spin_lock_irq(&task->sighand->siglock); ++ ++ sigaddset(&task->pending.signal, info->si_signo); ++ if (likely(q)) ++ list_add(&q->list, &task->pending.list); ++ ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++} ++ ++/* ++ * This is the hook from the signals code, called with the siglock held. ++ * Here is the ideal place to stop. We also dequeue and intercept signals. ++ */ ++int utrace_get_signal(struct task_struct *task, struct pt_regs *regs, ++ siginfo_t *info, struct k_sigaction *return_ka) ++ __releases(task->sighand->siglock) ++ __acquires(task->sighand->siglock) ++{ ++ struct utrace *utrace; ++ struct k_sigaction *ka; ++ INIT_REPORT(report); ++ struct utrace_attached_engine *engine, *next; ++ const struct utrace_engine_ops *ops; ++ unsigned long event, want; ++ u32 ret; ++ int signr; ++ ++ /* ++ * We could have been considered quiescent while we were in ++ * TASK_STOPPED, and detached asynchronously. If we woke up ++ * and checked task->utrace_flags before that was finished, ++ * we might be here with utrace already removed or in the ++ * middle of being removed. ++ */ ++ rcu_read_lock(); ++ utrace = rcu_dereference(task->utrace); ++ if (unlikely(utrace == NULL)) { ++ rcu_read_unlock(); ++ return 0; ++ } ++ ++ if (utrace->interrupt || utrace->report || utrace->signal_handler) { ++ /* ++ * We've been asked for an explicit report before we ++ * even check for pending signals. ++ */ ++ ++ spin_unlock_irq(&task->sighand->siglock); ++ ++ /* ++ * RCU makes it safe to get the utrace->lock even if ++ * it's being freed. Once we have that lock, either an ++ * external detach has finished and this struct has been ++ * freed, or else we know we are excluding any other ++ * detach attempt. ++ */ ++ spin_lock(&utrace->lock); ++ rcu_read_unlock(); ++ ++ if (unlikely(task->utrace != utrace)) { ++ spin_unlock(&utrace->lock); ++ cond_resched(); ++ return -1; ++ } ++ ++ splice_attaching(utrace); ++ ++ if (unlikely(!utrace->interrupt) && unlikely(!utrace->report)) ++ report.result = UTRACE_SIGNAL_IGN; ++ else if (utrace->signal_handler) ++ report.result = UTRACE_SIGNAL_HANDLER; ++ else ++ report.result = UTRACE_SIGNAL_REPORT; ++ ++ /* ++ * We are now making the report and it's on the ++ * interrupt path, so clear the flags asking for those. ++ */ ++ utrace->interrupt = utrace->report = utrace->signal_handler = 0; ++ ++ /* ++ * Make sure signal_pending() only returns true ++ * if there are real signals pending. ++ */ ++ if (signal_pending(task)) { ++ spin_lock_irq(&task->sighand->siglock); ++ recalc_sigpending(); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ spin_unlock(&utrace->lock); ++ ++ if (unlikely(report.result == UTRACE_SIGNAL_IGN)) ++ /* ++ * We only got here to clear utrace->signal_handler. ++ */ ++ return -1; ++ ++ /* ++ * Do a reporting pass for no signal, just for EVENT(QUIESCE). ++ * The engine callbacks can fill in *info and *return_ka. ++ * We'll pass NULL for the @orig_ka argument to indicate ++ * that there was no original signal. ++ */ ++ event = 0; ++ ka = NULL; ++ memset(return_ka, 0, sizeof *return_ka); ++ } else if ((task->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) == 0) { ++ /* ++ * If noone is interested in intercepting signals, ++ * let the caller just dequeue them normally. ++ */ ++ rcu_read_unlock(); ++ return 0; ++ } else { ++ if (unlikely(utrace->stopped)) { ++ /* ++ * We were just in TASK_STOPPED, so we have to ++ * check for the race mentioned above. ++ * ++ * RCU makes it safe to get the utrace->lock even ++ * if it's being freed. Once we have that lock, ++ * either an external detach has finished and this ++ * struct has been freed, or else we know we are ++ * excluding any other detach attempt. Since we ++ * are no longer in TASK_STOPPED now, all we needed ++ * the lock for was to order any utrace_do_stop() ++ * call after us. ++ */ ++ spin_unlock_irq(&task->sighand->siglock); ++ spin_lock(&utrace->lock); ++ rcu_read_unlock(); ++ if (unlikely(task->utrace != utrace)) { ++ spin_unlock(&utrace->lock); ++ cond_resched(); ++ return -1; ++ } ++ utrace->stopped = 0; ++ spin_unlock(&utrace->lock); ++ spin_lock_irq(&task->sighand->siglock); ++ } else { ++ rcu_read_unlock(); ++ } ++ ++ /* ++ * Steal the next signal so we can let tracing engines ++ * examine it. From the signal number and sigaction, ++ * determine what normal delivery would do. If no ++ * engine perturbs it, we'll do that by returning the ++ * signal number after setting *return_ka. ++ */ ++ signr = dequeue_signal(task, &task->blocked, info); ++ if (signr == 0) ++ return signr; ++ BUG_ON(signr != info->si_signo); ++ ++ ka = &task->sighand->action[signr - 1]; ++ *return_ka = *ka; ++ ++ /* ++ * We are never allowed to interfere with SIGKILL. ++ * Just punt after filling in *return_ka for our caller. ++ */ ++ if (signr == SIGKILL) ++ return signr; ++ ++ if (ka->sa.sa_handler == SIG_IGN) { ++ event = UTRACE_EVENT(SIGNAL_IGN); ++ report.result = UTRACE_SIGNAL_IGN; ++ } else if (ka->sa.sa_handler != SIG_DFL) { ++ event = UTRACE_EVENT(SIGNAL); ++ report.result = UTRACE_SIGNAL_DELIVER; ++ } else if (sig_kernel_coredump(signr)) { ++ event = UTRACE_EVENT(SIGNAL_CORE); ++ report.result = UTRACE_SIGNAL_CORE; ++ } else if (sig_kernel_ignore(signr)) { ++ event = UTRACE_EVENT(SIGNAL_IGN); ++ report.result = UTRACE_SIGNAL_IGN; ++ } else if (signr == SIGSTOP) { ++ event = UTRACE_EVENT(SIGNAL_STOP); ++ report.result = UTRACE_SIGNAL_STOP; ++ } else if (sig_kernel_stop(signr)) { ++ event = UTRACE_EVENT(SIGNAL_STOP); ++ report.result = UTRACE_SIGNAL_TSTP; ++ } else { ++ event = UTRACE_EVENT(SIGNAL_TERM); ++ report.result = UTRACE_SIGNAL_TERM; ++ } ++ ++ /* ++ * Now that we know what event type this signal is, ++ * we can short-circuit if noone cares about those. ++ */ ++ if ((task->utrace_flags & (event | UTRACE_EVENT(QUIESCE))) == 0) ++ return signr; ++ ++ /* ++ * We have some interested engines, so tell them about ++ * the signal and let them change its disposition. ++ */ ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ /* ++ * This reporting pass chooses what signal disposition we'll act on. ++ */ ++ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { ++ utrace->reporting = engine; ++ smp_mb(); ++ ++ /* ++ * This pairs with the barrier in mark_engine_detached(), ++ * see start_callback() comments. ++ */ ++ want = engine->flags; ++ smp_rmb(); ++ ops = engine->ops; ++ ++ if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) { ++ utrace->reporting = NULL; ++ continue; ++ } ++ ++ if (ops->report_signal) ++ ret = (*ops->report_signal)( ++ report.result | report.action, engine, task, ++ regs, info, ka, return_ka); ++ else ++ ret = (report.result | (*ops->report_quiesce)( ++ report.action, engine, task, event)); ++ ++ /* ++ * Avoid a tight loop reporting again and again if some ++ * engine is too stupid. ++ */ ++ switch (utrace_resume_action(ret)) { ++ default: ++ break; ++ case UTRACE_INTERRUPT: ++ case UTRACE_REPORT: ++ ret = (ret & ~UTRACE_RESUME_MASK) | UTRACE_RESUME; ++ break; ++ } ++ ++ finish_callback(utrace, &report, engine, ret); ++ } ++ ++ /* ++ * We express the chosen action to the signals code in terms ++ * of a representative signal whose default action does it. ++ * Our caller uses our return value (signr) to decide what to ++ * do, but uses info->si_signo as the signal number to report. ++ */ ++ switch (utrace_signal_action(report.result)) { ++ case UTRACE_SIGNAL_TERM: ++ signr = SIGTERM; ++ break; ++ ++ case UTRACE_SIGNAL_CORE: ++ signr = SIGQUIT; ++ break; ++ ++ case UTRACE_SIGNAL_STOP: ++ signr = SIGSTOP; ++ break; ++ ++ case UTRACE_SIGNAL_TSTP: ++ signr = SIGTSTP; ++ break; ++ ++ case UTRACE_SIGNAL_DELIVER: ++ signr = info->si_signo; ++ ++ if (return_ka->sa.sa_handler == SIG_DFL) { ++ /* ++ * We'll do signr's normal default action. ++ * For ignore, we'll fall through below. ++ * For stop/death, break locks and returns it. ++ */ ++ if (likely(signr) && !sig_kernel_ignore(signr)) ++ break; ++ } else if (return_ka->sa.sa_handler != SIG_IGN && ++ likely(signr)) { ++ /* ++ * The handler will run. If an engine wanted to ++ * stop or step, then make sure we do another ++ * report after signal handler setup. ++ */ ++ if (report.action != UTRACE_RESUME) { ++ spin_lock(&utrace->lock); ++ utrace->interrupt = 1; ++ spin_unlock(&utrace->lock); ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ } ++ ++ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) ++ push_back_signal(task, info); ++ else ++ spin_lock_irq(&task->sighand->siglock); ++ ++ /* ++ * We do the SA_ONESHOT work here since the ++ * normal path will only touch *return_ka now. ++ */ ++ if (unlikely(return_ka->sa.sa_flags & SA_ONESHOT)) { ++ return_ka->sa.sa_flags &= ~SA_ONESHOT; ++ if (likely(valid_signal(signr))) { ++ ka = &task->sighand->action[signr - 1]; ++ ka->sa.sa_handler = SIG_DFL; ++ } ++ } ++ ++ return signr; ++ } ++ ++ /* Fall through for an ignored signal. */ ++ ++ case UTRACE_SIGNAL_IGN: ++ case UTRACE_SIGNAL_REPORT: ++ default: ++ /* ++ * If the signal is being ignored, then we are on the way ++ * directly back to user mode. We can stop here, or step, ++ * as in utrace_resume(), above. After we've dealt with that, ++ * our caller will relock and come back through here. ++ */ ++ finish_resume_report(&report, task, utrace); ++ ++ if (unlikely(report.killed)) { ++ /* ++ * The only reason we woke up now was because of a ++ * SIGKILL. Don't do normal dequeuing in case it ++ * might get a signal other than SIGKILL. That would ++ * perturb the death state so it might differ from ++ * what the debugger would have allowed to happen. ++ * Instead, pluck out just the SIGKILL to be sure ++ * we'll die immediately with nothing else different ++ * from the quiescent state the debugger wanted us in. ++ */ ++ sigset_t sigkill_only; ++ siginitsetinv(&sigkill_only, sigmask(SIGKILL)); ++ spin_lock_irq(&task->sighand->siglock); ++ signr = dequeue_signal(task, &sigkill_only, info); ++ BUG_ON(signr != SIGKILL); ++ *return_ka = task->sighand->action[SIGKILL - 1]; ++ return signr; ++ } ++ ++ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) { ++ push_back_signal(task, info); ++ spin_unlock_irq(&task->sighand->siglock); ++ } ++ ++ return -1; ++ } ++ ++ return_ka->sa.sa_handler = SIG_DFL; ++ ++ if (unlikely(report.result & UTRACE_SIGNAL_HOLD)) ++ push_back_signal(task, info); ++ else ++ spin_lock_irq(&task->sighand->siglock); ++ ++ if (sig_kernel_stop(signr)) ++ task->signal->flags |= SIGNAL_STOP_DEQUEUED; ++ ++ return signr; ++} ++ ++/* ++ * This gets called after a signal handler has been set up. ++ * We set a flag so the next report knows it happened. ++ * If we're already stepping, make sure we do a report_signal. ++ * If not, make sure we get into utrace_resume() where we can ++ * clear the signal_handler flag before resuming. ++ */ ++void utrace_signal_handler(struct task_struct *task, int stepping) ++{ ++ struct utrace *utrace = task->utrace; ++ ++ spin_lock(&utrace->lock); ++ ++ utrace->signal_handler = 1; ++ if (stepping) { ++ utrace->interrupt = 1; ++ set_tsk_thread_flag(task, TIF_SIGPENDING); ++ } else { ++ set_notify_resume(task); ++ } ++ ++ spin_unlock(&utrace->lock); ++} ++ ++/** ++ * utrace_prepare_examine - prepare to examine thread state ++ * @target: thread of interest, a &struct task_struct pointer ++ * @engine: engine pointer returned by utrace_attach_task() ++ * @exam: temporary state, a &struct utrace_examiner pointer ++ * ++ * This call prepares to safely examine the thread @target using ++ * &struct user_regset calls, or direct access to thread-synchronous fields. ++ * ++ * When @target is current, this call is superfluous. When @target is ++ * another thread, it must held stopped via %UTRACE_STOP by @engine. ++ * ++ * This call may block the caller until @target stays stopped, so it must ++ * be called only after the caller is sure @target is about to unschedule. ++ * This means a zero return from a utrace_control() call on @engine giving ++ * %UTRACE_STOP, or a report_quiesce() or report_signal() callback to ++ * @engine that used %UTRACE_STOP in its return value. ++ * ++ * Returns -%ESRCH if @target is dead or -%EINVAL if %UTRACE_STOP was ++ * not used. If @target has started running again despite %UTRACE_STOP ++ * (for %SIGKILL or a spurious wakeup), this call returns -%EAGAIN. ++ * ++ * When this call returns zero, it's safe to use &struct user_regset ++ * calls and task_user_regset_view() on @target and to examine some of ++ * its fields directly. When the examination is complete, a ++ * utrace_finish_examine() call must follow to check whether it was ++ * completed safely. ++ */ ++int utrace_prepare_examine(struct task_struct *target, ++ struct utrace_attached_engine *engine, ++ struct utrace_examiner *exam) ++{ ++ int ret = 0; ++ ++ if (unlikely(target == current)) ++ return 0; ++ ++ rcu_read_lock(); ++ if (unlikely(!engine_wants_stop(engine))) ++ ret = -EINVAL; ++ else if (unlikely(target->exit_state)) ++ ret = -ESRCH; ++ else { ++ exam->state = target->state; ++ if (unlikely(exam->state == TASK_RUNNING)) ++ ret = -EAGAIN; ++ else ++ get_task_struct(target); ++ } ++ rcu_read_unlock(); ++ ++ if (likely(!ret)) { ++ exam->ncsw = wait_task_inactive(target, exam->state); ++ put_task_struct(target); ++ if (unlikely(!exam->ncsw)) ++ ret = -EAGAIN; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(utrace_prepare_examine); ++ ++/** ++ * utrace_finish_examine - complete an examination of thread state ++ * @target: thread of interest, a &struct task_struct pointer ++ * @engine: engine pointer returned by utrace_attach_task() ++ * @exam: pointer passed to utrace_prepare_examine() call ++ * ++ * This call completes an examination on the thread @target begun by a ++ * paired utrace_prepare_examine() call with the same arguments that ++ * returned success (zero). ++ * ++ * When @target is current, this call is superfluous. When @target is ++ * another thread, this returns zero if @target has remained unscheduled ++ * since the paired utrace_prepare_examine() call returned zero. ++ * ++ * When this returns an error, any examination done since the paired ++ * utrace_prepare_examine() call is unreliable and the data extracted ++ * should be discarded. The error is -%EINVAL if @engine is not ++ * keeping @target stopped, or -%EAGAIN if @target woke up unexpectedly. ++ */ ++int utrace_finish_examine(struct task_struct *target, ++ struct utrace_attached_engine *engine, ++ struct utrace_examiner *exam) ++{ ++ int ret = 0; ++ ++ if (unlikely(target == current)) ++ return 0; ++ ++ rcu_read_lock(); ++ if (unlikely(!engine_wants_stop(engine))) ++ ret = -EINVAL; ++ else if (unlikely(target->state != exam->state)) ++ ret = -EAGAIN; ++ else ++ get_task_struct(target); ++ rcu_read_unlock(); ++ ++ if (likely(!ret)) { ++ unsigned long ncsw = wait_task_inactive(target, exam->state); ++ if (unlikely(ncsw != exam->ncsw)) ++ ret = -EAGAIN; ++ put_task_struct(target); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(utrace_finish_examine); ++ ++/* ++ * This is declared in linux/regset.h and defined in machine-dependent ++ * code. We put the export here to ensure no machine forgets it. ++ */ ++EXPORT_SYMBOL_GPL(task_user_regset_view); ++ ++/* ++ * Return the &struct task_struct for the task using ptrace on this one, ++ * or %NULL. Must be called with rcu_read_lock() held to keep the returned ++ * struct alive. ++ * ++ * At exec time, this may be called with task_lock() still held from when ++ * tracehook_unsafe_exec() was just called. In that case it must give ++ * results consistent with those unsafe_exec() results, i.e. non-%NULL if ++ * any %LSM_UNSAFE_PTRACE_* bits were set. ++ * ++ * The value is also used to display after "TracerPid:" in /proc/PID/status, ++ * where it is called with only rcu_read_lock() held. ++ */ ++struct task_struct *utrace_tracer_task(struct task_struct *target) ++{ ++ struct utrace *utrace; ++ struct task_struct *tracer = NULL; ++ ++ utrace = rcu_dereference(target->utrace); ++ if (utrace != NULL) { ++ struct list_head *pos, *next; ++ struct utrace_attached_engine *engine; ++ const struct utrace_engine_ops *ops; ++ list_for_each_safe(pos, next, &utrace->attached) { ++ engine = list_entry(pos, struct utrace_attached_engine, ++ entry); ++ ops = rcu_dereference(engine->ops); ++ if (ops->tracer_task) { ++ tracer = (*ops->tracer_task)(engine, target); ++ if (tracer != NULL) ++ break; ++ } ++ } ++ } ++ ++ return tracer; ++} ++ ++/* ++ * Called on the current task to return LSM_UNSAFE_* bits implied by tracing. ++ * Called with task_lock() held. ++ */ ++int utrace_unsafe_exec(struct task_struct *task) ++{ ++ struct utrace *utrace = task->utrace; ++ struct utrace_attached_engine *engine, *next; ++ const struct utrace_engine_ops *ops; ++ int unsafe = 0; ++ ++ list_for_each_entry_safe(engine, next, &utrace->attached, entry) { ++ ops = rcu_dereference(engine->ops); ++ if (ops->unsafe_exec) ++ unsafe |= (*ops->unsafe_exec)(engine, task); ++ } ++ ++ return unsafe; ++} ++ ++/* ++ * Called with rcu_read_lock() held. ++ */ ++void task_utrace_proc_status(struct seq_file *m, struct task_struct *p) ++{ ++ struct utrace *utrace = rcu_dereference(p->utrace); ++ if (unlikely(utrace)) ++ seq_printf(m, "Utrace: %lx%s%s%s\n", ++ p->utrace_flags, ++ utrace->stopped ? " (stopped)" : "", ++ utrace->report ? " (report)" : "", ++ utrace->interrupt ? " (interrupt)" : ""); ++} diff --git a/src/patches/suse-2.6.27.31/patches.xen/735-balloon-exit.patch b/src/patches/suse-2.6.27.31/patches.xen/735-balloon-exit.patch new file mode 100644 index 000000000..3054c1836 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/735-balloon-exit.patch @@ -0,0 +1,80 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/163a3807cb1f +# HG changeset 735+738 patch +# User Keir Fraser +# Date 1227525200 0 +# Node ID 163a3807cb1fb4f35304a99c63f4deac322df2da +# Parent 412b24a36929b7cbedc793b4aad06b334bea021b +Subject: linux: remove sysfs files during balloon module exit +Patch-mainline: obsolete + +Relevant when building pv drivers. + +Also adjust some section attributes of the sysfs code. + +Signed-off-by: Jan Beulich + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/bf8b1ee634e2 +balloon: Fix the build by including + +Signed-off-by: Keir Fraser + +Index: head-2008-11-25/drivers/xen/balloon/balloon.c +=================================================================== +--- head-2008-11-25.orig/drivers/xen/balloon/balloon.c 2008-07-21 11:00:33.000000000 +0200 ++++ head-2008-11-25/drivers/xen/balloon/balloon.c 2008-11-25 13:31:07.000000000 +0100 +@@ -577,8 +577,8 @@ subsys_initcall(balloon_init); + + static void __exit balloon_exit(void) + { +- /* XXX - release balloon here */ +- return; ++ balloon_sysfs_exit(); ++ /* XXX - release balloon here */ + } + + module_exit(balloon_exit); +Index: head-2008-11-25/drivers/xen/balloon/sysfs.c +=================================================================== +--- head-2008-11-25.orig/drivers/xen/balloon/sysfs.c 2008-04-02 12:34:02.000000000 +0200 ++++ head-2008-11-25/drivers/xen/balloon/sysfs.c 2008-11-25 13:31:07.000000000 +0100 +@@ -30,6 +30,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -111,7 +112,7 @@ static struct sysdev_class balloon_sysde + + static struct sys_device balloon_sysdev; + +-static int register_balloon(struct sys_device *sysdev) ++static int __init register_balloon(struct sys_device *sysdev) + { + int i, error; + +@@ -148,7 +149,7 @@ static int register_balloon(struct sys_d + return error; + } + +-static void unregister_balloon(struct sys_device *sysdev) ++static __exit void unregister_balloon(struct sys_device *sysdev) + { + int i; + +@@ -159,12 +160,12 @@ static void unregister_balloon(struct sy + sysdev_class_unregister(&balloon_sysdev_class); + } + +-int balloon_sysfs_init(void) ++int __init balloon_sysfs_init(void) + { + return register_balloon(&balloon_sysdev); + } + +-void balloon_sysfs_exit(void) ++void __exit balloon_sysfs_exit(void) + { + unregister_balloon(&balloon_sysdev); + } diff --git a/src/patches/suse-2.6.27.31/patches.xen/737-kexec-free.patch b/src/patches/suse-2.6.27.31/patches.xen/737-kexec-free.patch new file mode 100644 index 000000000..8b5a7a453 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/737-kexec-free.patch @@ -0,0 +1,26 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/6bb7f500d5e4 +# HG changeset 737 patch +# User Keir Fraser +# Date 1227611796 0 +# Node ID 6bb7f500d5e4a68007607863fa7bfe0c69d6eec7 +# Parent 1b68d09b868fdcd724c6b86eb2790748a9fd0bb7 +Subject: kexec: Don't pass limit_pages_to_max_mfn() regions to xen_destroy_contiguous_region(). +Patch-mainline: obsolete + +Signed-off-by: Keir Fraser +Acked-by: jbeulich@novell.com + +Index: head-2008-11-25/kernel/kexec.c +=================================================================== +--- head-2008-11-25.orig/kernel/kexec.c 2008-11-25 12:35:50.000000000 +0100 ++++ head-2008-11-25/kernel/kexec.c 2008-11-25 13:31:12.000000000 +0100 +@@ -397,9 +397,6 @@ static void kimage_free_pages(struct pag + count = 1 << order; + for (i = 0; i < count; i++) + ClearPageReserved(page + i); +-#ifdef CONFIG_XEN +- xen_destroy_contiguous_region((unsigned long)page_address(page), order); +-#endif + __free_pages(page, order); + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/740-blkback-resource-leak.patch b/src/patches/suse-2.6.27.31/patches.xen/740-blkback-resource-leak.patch new file mode 100644 index 000000000..c4cdb9f2d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/740-blkback-resource-leak.patch @@ -0,0 +1,58 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/5012c470f875 +# HG changeset 740 patch +# User Keir Fraser +# Date 1227697833 0 +# Node ID 5012c470f8757e97c2e0f7eccfafcb1e2367443e +# Parent f236d7def9944909bf40015ff4a08817b0803ed9 +Subject: blkback, blktap: Fix potential resource leak. +Patch-mainline: obsolete + +Signed-off-by: Keir Fraser +Acked-by: jbeulich@novell.com + +Index: head-2008-12-01/drivers/xen/blkback/blkback.c +=================================================================== +--- head-2008-12-01.orig/drivers/xen/blkback/blkback.c 2008-11-10 11:44:21.000000000 +0100 ++++ head-2008-12-01/drivers/xen/blkback/blkback.c 2008-12-01 11:21:10.000000000 +0100 +@@ -317,14 +317,14 @@ static int do_block_io_op(blkif_t *blkif + if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc)) + break; + +- pending_req = alloc_req(); +- if (NULL == pending_req) { +- blkif->st_oo_req++; ++ if (kthread_should_stop()) { + more_to_do = 1; + break; + } + +- if (kthread_should_stop()) { ++ pending_req = alloc_req(); ++ if (NULL == pending_req) { ++ blkif->st_oo_req++; + more_to_do = 1; + break; + } +Index: head-2008-12-01/drivers/xen/blktap/blktap.c +=================================================================== +--- head-2008-12-01.orig/drivers/xen/blktap/blktap.c 2008-11-10 11:44:21.000000000 +0100 ++++ head-2008-12-01/drivers/xen/blktap/blktap.c 2008-12-01 11:21:10.000000000 +0100 +@@ -1286,14 +1286,14 @@ static int do_block_io_op(blkif_t *blkif + break; + } + +- pending_req = alloc_req(); +- if (NULL == pending_req) { +- blkif->st_oo_req++; ++ if (kthread_should_stop()) { + more_to_do = 1; + break; + } + +- if (kthread_should_stop()) { ++ pending_req = alloc_req(); ++ if (NULL == pending_req) { ++ blkif->st_oo_req++; + more_to_do = 1; + break; + } diff --git a/src/patches/suse-2.6.27.31/patches.xen/746-pirq-status-page.patch b/src/patches/suse-2.6.27.31/patches.xen/746-pirq-status-page.patch new file mode 100644 index 000000000..7c193d4d3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/746-pirq-status-page.patch @@ -0,0 +1,177 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/d545a95fca73 +# HG changeset 746+749+751+760 patch +# User Keir Fraser +# Date 1227879027 0 +# Node ID d545a95fca739d0b1963b73a9eb64ea64a244e76 +# Parent 2268be46c75ec6eddb7cd387af8a236a565f6140 +Subject: linux/x86: use shared page indicating the need for an EOI notification +Patch-mainline: obsolete + +Signed-off-by: Jan Beulich + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/cdc6729dc702 +Subject: evtchn: Fix the build. +Signed-off-by: Keir Fraser + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/ca213a56dba1 +Subject: evtchn, phydev: rename PHYSDEVOP_pirq_eoi_mfn to PHYSDEVOP_pirq_eoi_gmfn + +Signed-off-by: Isaku Yamahata +Signed-off-by: Keir Fraser + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/0d10be086a78 +Subject: linux/evtchn: allocate pirq_needs_eoi bitmap dynamically + +Original patch from: Isaku Yamahata +Signed-off-by: Jan Beulich + +--- head-2008-12-15.orig/drivers/xen/core/evtchn.c 2008-11-10 11:44:21.000000000 +0100 ++++ head-2008-12-15/drivers/xen/core/evtchn.c 2008-12-15 11:06:31.000000000 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -123,9 +124,6 @@ DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) + /* Reference counts for bindings to IRQs. */ + static int irq_bindcount[NR_IRQS]; + +-/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */ +-static DECLARE_BITMAP(pirq_needs_eoi, NR_PIRQS); +- + #ifdef CONFIG_SMP + + static u8 cpu_evtchn[NR_EVENT_CHANNELS]; +@@ -756,16 +754,47 @@ static struct hw_interrupt_type dynirq_t + .retrigger = resend_irq_on_evtchn, + }; + +-static inline void pirq_unmask_notify(int irq) ++/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */ ++static int pirq_eoi_does_unmask; ++static unsigned long *pirq_needs_eoi; ++ ++static void pirq_unmask_and_notify(unsigned int evtchn, unsigned int irq) + { + struct physdev_eoi eoi = { .irq = evtchn_get_xen_pirq(irq) }; +- if (unlikely(test_bit(irq - PIRQ_BASE, pirq_needs_eoi))) +- VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi)); ++ ++ if (pirq_eoi_does_unmask) { ++ if (test_bit(eoi.irq, pirq_needs_eoi)) ++ VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi)); ++ else ++ unmask_evtchn(evtchn); ++ } else if (test_bit(irq - PIRQ_BASE, pirq_needs_eoi)) { ++ if (smp_processor_id() != cpu_from_evtchn(evtchn)) { ++ struct evtchn_unmask unmask = { .port = evtchn }; ++ struct multicall_entry mcl[2]; ++ ++ mcl[0].op = __HYPERVISOR_event_channel_op; ++ mcl[0].args[0] = EVTCHNOP_unmask; ++ mcl[0].args[1] = (unsigned long)&unmask; ++ mcl[1].op = __HYPERVISOR_physdev_op; ++ mcl[1].args[0] = PHYSDEVOP_eoi; ++ mcl[1].args[1] = (unsigned long)&eoi; ++ ++ if (HYPERVISOR_multicall(mcl, 2)) ++ BUG(); ++ } else { ++ unmask_evtchn(evtchn); ++ VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi)); ++ } ++ } else ++ unmask_evtchn(evtchn); + } + + static inline void pirq_query_unmask(int irq) + { + struct physdev_irq_status_query irq_status; ++ ++ if (pirq_eoi_does_unmask) ++ return; + irq_status.irq = evtchn_get_xen_pirq(irq); + if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status)) + irq_status.flags = 0; +@@ -806,8 +835,7 @@ static unsigned int startup_pirq(unsigne + irq_info[irq] = mk_irq_info(IRQT_PIRQ, bind_pirq.pirq, evtchn); + + out: +- unmask_evtchn(evtchn); +- pirq_unmask_notify(irq); ++ pirq_unmask_and_notify(evtchn, irq); + + return 0; + } +@@ -859,10 +887,8 @@ static void end_pirq(unsigned int irq) + if ((irq_desc[irq].status & (IRQ_DISABLED|IRQ_PENDING)) == + (IRQ_DISABLED|IRQ_PENDING)) { + shutdown_pirq(irq); +- } else if (VALID_EVTCHN(evtchn)) { +- unmask_evtchn(evtchn); +- pirq_unmask_notify(irq); +- } ++ } else if (VALID_EVTCHN(evtchn)) ++ pirq_unmask_and_notify(evtchn, irq); + } + + static struct hw_interrupt_type pirq_type = { +@@ -1012,6 +1038,14 @@ void irq_resume(void) + + init_evtchn_cpu_bindings(); + ++ if (pirq_eoi_does_unmask) { ++ struct physdev_pirq_eoi_gmfn eoi_gmfn; ++ ++ eoi_gmfn.gmfn = virt_to_machine(pirq_needs_eoi) >> PAGE_SHIFT; ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn, &eoi_gmfn)) ++ BUG(); ++ } ++ + /* New event-channel space is not 'live' yet. */ + for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) + mask_evtchn(evtchn); +@@ -1098,9 +1132,16 @@ int evtchn_get_xen_pirq(int irq) + void __init xen_init_IRQ(void) + { + unsigned int i; ++ struct physdev_pirq_eoi_gmfn eoi_gmfn; + + init_evtchn_cpu_bindings(); + ++ pirq_needs_eoi = alloc_bootmem_pages(sizeof(unsigned long) ++ * BITS_TO_LONGS(ALIGN(NR_PIRQS, PAGE_SIZE * 8))); ++ eoi_gmfn.gmfn = virt_to_machine(pirq_needs_eoi) >> PAGE_SHIFT; ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn, &eoi_gmfn) == 0) ++ pirq_eoi_does_unmask = 1; ++ + /* No event channels are 'live' right now. */ + for (i = 0; i < NR_EVENT_CHANNELS; i++) + mask_evtchn(i); +--- head-2008-12-15.orig/include/xen/interface/physdev.h 2008-11-25 12:35:56.000000000 +0100 ++++ head-2008-12-15/include/xen/interface/physdev.h 2008-12-08 13:22:39.000000000 +0100 +@@ -41,6 +41,21 @@ typedef struct physdev_eoi physdev_eoi_t + DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t); + + /* ++ * Register a shared page for the hypervisor to indicate whether the guest ++ * must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly ++ * once the guest used this function in that the associated event channel ++ * will automatically get unmasked. The page registered is used as a bit ++ * array indexed by Xen's PIRQ value. ++ */ ++#define PHYSDEVOP_pirq_eoi_gmfn 17 ++struct physdev_pirq_eoi_gmfn { ++ /* IN */ ++ xen_pfn_t gmfn; ++}; ++typedef struct physdev_pirq_eoi_gmfn physdev_pirq_eoi_gmfn_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_pirq_eoi_gmfn_t); ++ ++/* + * Query the status of an IRQ line. + * @arg == pointer to physdev_irq_status_query structure. + */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/747-x86-undo-mfn-limit.patch b/src/patches/suse-2.6.27.31/patches.xen/747-x86-undo-mfn-limit.patch new file mode 100644 index 000000000..16d2b015c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/747-x86-undo-mfn-limit.patch @@ -0,0 +1,205 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/39a8680e7a70 +# HG changeset 747 patch +# User Keir Fraser +# Date 1227879058 0 +# Node ID 39a8680e7a70a28ce639c507fb6a9bc0aa7d8f14 +# Parent d545a95fca739d0b1963b73a9eb64ea64a244e76 +Subject: linux/x86: revert the effect of xen_limit_pages_to_max_mfn() +Patch-mainline: obsolete + +Signed-off-by: Jan Beulich + +--- sle11-2009-07-31.orig/arch/x86/mm/hypervisor.c 2009-07-31 14:49:21.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/mm/hypervisor.c 2008-12-01 11:25:57.000000000 +0100 +@@ -374,6 +374,15 @@ void xen_destroy_contiguous_region(unsig + } + EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); + ++static void undo_limit_pages(struct page *pages, unsigned int order) ++{ ++ BUG_ON(xen_feature(XENFEAT_auto_translated_physmap)); ++ BUG_ON(order > MAX_CONTIG_ORDER); ++ xen_limit_pages_to_max_mfn(pages, order, 0); ++ ClearPageForeign(pages); ++ __free_pages(pages, order); ++} ++ + int xen_limit_pages_to_max_mfn( + struct page *pages, unsigned int order, unsigned int address_bits) + { +@@ -402,16 +411,28 @@ int xen_limit_pages_to_max_mfn( + if (unlikely(order > MAX_CONTIG_ORDER)) + return -ENOMEM; + +- bitmap_zero(limit_map, 1U << order); ++ if (address_bits) { ++ if (address_bits < PAGE_SHIFT) ++ return -EINVAL; ++ bitmap_zero(limit_map, 1U << order); ++ } else if (order) { ++ BUILD_BUG_ON(sizeof(pages->index) != sizeof(*limit_map)); ++ for (i = 0; i < BITS_TO_LONGS(1U << order); ++i) ++ limit_map[i] = pages[i + 1].index; ++ } else ++ __set_bit(0, limit_map); ++ + set_xen_guest_handle(exchange.in.extent_start, in_frames); + set_xen_guest_handle(exchange.out.extent_start, out_frames); + + /* 0. Scrub the pages. */ + for (i = 0, n = 0; i < 1U<> (address_bits - PAGE_SHIFT))) +- continue; +- __set_bit(i, limit_map); ++ if (address_bits) { ++ if (!(pfn_to_mfn(page_to_pfn(page)) >> (address_bits - PAGE_SHIFT))) ++ continue; ++ __set_bit(i, limit_map); ++ } + + if (!PageHighMem(page)) + scrub_pages(page_address(page), 1); +@@ -497,7 +518,19 @@ int xen_limit_pages_to_max_mfn( + + balloon_unlock(flags); + +- return success ? 0 : -ENOMEM; ++ if (!success) ++ return -ENOMEM; ++ ++ if (address_bits) { ++ if (order) { ++ BUILD_BUG_ON(sizeof(*limit_map) != sizeof(pages->index)); ++ for (i = 0; i < BITS_TO_LONGS(1U << order); ++i) ++ pages[i + 1].index = limit_map[i]; ++ } ++ SetPageForeign(pages, undo_limit_pages); ++ } ++ ++ return 0; + } + EXPORT_SYMBOL_GPL(xen_limit_pages_to_max_mfn); + +--- sle11-2009-07-31.orig/arch/x86/mm/pgtable_32-xen.c 2009-07-31 14:49:21.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/mm/pgtable_32-xen.c 2008-12-01 11:25:57.000000000 +0100 +@@ -152,6 +152,12 @@ pte_t *pte_alloc_one_kernel(struct mm_st + return pte; + } + ++static void _pte_free(struct page *page, unsigned int order) ++{ ++ BUG_ON(order); ++ pte_free(page); ++} ++ + struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) + { + struct page *pte; +@@ -162,7 +168,7 @@ struct page *pte_alloc_one(struct mm_str + pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); + #endif + if (pte) { +- SetPageForeign(pte, pte_free); ++ SetPageForeign(pte, _pte_free); + init_page_count(pte); + } + return pte; +--- sle11-2009-07-31.orig/arch/x86/mm/pageattr_64-xen.c 2009-07-31 14:49:21.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/mm/pageattr_64-xen.c 2008-12-01 11:25:57.000000000 +0100 +@@ -248,13 +248,19 @@ void _arch_exit_mmap(struct mm_struct *m + mm_unpin(mm); + } + ++static void _pte_free(struct page *page, unsigned int order) ++{ ++ BUG_ON(order); ++ pte_free(page); ++} ++ + struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) + { + struct page *pte; + + pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); + if (pte) { +- SetPageForeign(pte, pte_free); ++ SetPageForeign(pte, _pte_free); + init_page_count(pte); + } + return pte; +--- sle11-2009-07-31.orig/drivers/xen/core/gnttab.c 2009-07-31 14:49:21.000000000 +0200 ++++ sle11-2009-07-31/drivers/xen/core/gnttab.c 2008-12-01 11:25:57.000000000 +0100 +@@ -505,8 +505,9 @@ static int gnttab_map(unsigned int start + return 0; + } + +-static void gnttab_page_free(struct page *page) ++static void gnttab_page_free(struct page *page, unsigned int order) + { ++ BUG_ON(order); + ClearPageForeign(page); + gnttab_reset_grant_page(page); + put_page(page); +--- sle11-2009-07-31.orig/drivers/xen/netback/netback.c 2009-07-31 14:49:21.000000000 +0200 ++++ sle11-2009-07-31/drivers/xen/netback/netback.c 2008-12-01 11:25:57.000000000 +0100 +@@ -55,7 +55,6 @@ struct netbk_tx_pending_inuse { + }; + + static void netif_idx_release(u16 pending_idx); +-static void netif_page_release(struct page *page); + static void make_tx_response(netif_t *netif, + netif_tx_request_t *txp, + s8 st); +@@ -1436,8 +1435,9 @@ static void netif_idx_release(u16 pendin + tasklet_schedule(&net_tx_tasklet); + } + +-static void netif_page_release(struct page *page) ++static void netif_page_release(struct page *page, unsigned int order) + { ++ BUG_ON(order); + netif_idx_release(netif_page_index(page)); + } + +--- sle11-2009-07-31.orig/include/linux/page-flags.h 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-07-31/include/linux/page-flags.h 2009-01-16 10:20:18.000000000 +0100 +@@ -277,15 +277,15 @@ CLEARPAGEFLAG(Uptodate, uptodate) + #define PageForeign(page) test_bit(PG_foreign, &(page)->flags) + #define SetPageForeign(_page, dtor) do { \ + set_bit(PG_foreign, &(_page)->flags); \ +- BUG_ON((dtor) == (void (*)(struct page *))0); \ ++ BUG_ON((dtor) == (void (*)(struct page *, unsigned int))0); \ + (_page)->index = (long)(dtor); \ + } while (0) + #define ClearPageForeign(page) do { \ + clear_bit(PG_foreign, &(page)->flags); \ + (page)->index = 0; \ + } while (0) +-#define PageForeignDestructor(_page) \ +- ((void (*)(struct page *))(_page)->index)(_page) ++#define PageForeignDestructor(_page, order) \ ++ ((void (*)(struct page *, unsigned int))(_page)->index)(_page, order) + + extern void cancel_dirty_page(struct page *page, unsigned int account_size); + +--- sle11-2009-07-31.orig/mm/page_alloc.c 2009-07-31 14:50:10.000000000 +0200 ++++ sle11-2009-07-31/mm/page_alloc.c 2009-07-31 14:50:39.000000000 +0200 +@@ -535,7 +535,7 @@ static void __free_pages_ok(struct page + + #ifdef CONFIG_XEN + if (PageForeign(page)) { +- PageForeignDestructor(page); ++ PageForeignDestructor(page, order); + return; + } + #endif +@@ -1006,7 +1006,7 @@ static void free_hot_cold_page(struct pa + + #ifdef CONFIG_XEN + if (PageForeign(page)) { +- PageForeignDestructor(page); ++ PageForeignDestructor(page, 0); + return; + } + #endif diff --git a/src/patches/suse-2.6.27.31/patches.xen/748-x86-ioapic-cleanup.patch b/src/patches/suse-2.6.27.31/patches.xen/748-x86-ioapic-cleanup.patch new file mode 100644 index 000000000..fff10fd93 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/748-x86-ioapic-cleanup.patch @@ -0,0 +1,134 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/2892ca2b9c17 +# HG changeset 748 patch +# User Keir Fraser +# Date 1227879081 0 +# Node ID 2892ca2b9c17857f6922e803406711881988d850 +# Parent 39a8680e7a70a28ce639c507fb6a9bc0aa7d8f14 +Subject: linux/x86: cleanup IO-APIC code +Patch-mainline: obsolete + +- get 32-bit code in sync with 64-bit wrt ExtINT pin detection being + unnecessary +- eliminate build warnings resulting from c/s 725 + +Signed-off-by: Jan Beulich + +Index: head-2008-12-01/arch/x86/kernel/io_apic_32-xen.c +=================================================================== +--- head-2008-12-01.orig/arch/x86/kernel/io_apic_32-xen.c 2008-11-25 12:22:34.000000000 +0100 ++++ head-2008-12-01/arch/x86/kernel/io_apic_32-xen.c 2008-12-01 11:28:17.000000000 +0100 +@@ -87,8 +87,10 @@ static inline void xen_io_apic_write(uns + int (*ioapic_renumber_irq)(int ioapic, int irq); + atomic_t irq_mis_count; + ++#ifndef CONFIG_XEN + /* Where if anywhere is the i8259 connect in external int mode */ + static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; ++#endif + + static DEFINE_SPINLOCK(ioapic_lock); + static DEFINE_SPINLOCK(vector_lock); +@@ -793,6 +795,7 @@ static int find_irq_entry(int apic, int + return -1; + } + ++#ifndef CONFIG_XEN + /* + * Find the pin to which IRQ[irq] (ISA) is connected + */ +@@ -842,6 +845,7 @@ static int __init find_isa_irq_apic(int + + return -1; + } ++#endif + + /* + * Find a specific PCI IRQ entry. +@@ -1687,7 +1691,9 @@ void /*__init*/ print_PIC(void) + static void __init enable_IO_APIC(void) + { + union IO_APIC_reg_01 reg_01; ++#ifndef CONFIG_XEN + int i8259_apic, i8259_pin; ++#endif + int i, apic; + unsigned long flags; + +@@ -1708,6 +1714,7 @@ static void __init enable_IO_APIC(void) + spin_unlock_irqrestore(&ioapic_lock, flags); + nr_ioapic_registers[apic] = reg_01.bits.entries+1; + } ++#ifndef CONFIG_XEN + for(apic = 0; apic < nr_ioapics; apic++) { + int pin; + /* See if any of the pins is in ExtINT mode */ +@@ -1749,6 +1756,7 @@ static void __init enable_IO_APIC(void) + { + printk(KERN_WARNING "ExtINT in hardware and MP table differ\n"); + } ++#endif + + /* + * Do not trust the IO-APIC being empty at bootup +@@ -2517,6 +2525,8 @@ static int __init io_apic_bug_finalize(v + + late_initcall(io_apic_bug_finalize); + ++#ifndef CONFIG_XEN ++ + struct sysfs_ioapic_data { + struct sys_device dev; + struct IO_APIC_route_entry entry[0]; +@@ -2570,10 +2580,8 @@ static int ioapic_resume(struct sys_devi + + static struct sysdev_class ioapic_sysdev_class = { + set_kset_name("ioapic"), +-#ifndef CONFIG_XEN + .suspend = ioapic_suspend, + .resume = ioapic_resume, +-#endif + }; + + static int __init ioapic_init_sysfs(void) +@@ -2611,6 +2619,8 @@ static int __init ioapic_init_sysfs(void + + device_initcall(ioapic_init_sysfs); + ++#endif /* CONFIG_XEN */ ++ + /* -------------------------------------------------------------------------- + ACPI-based IOAPIC Configuration + -------------------------------------------------------------------------- */ +Index: head-2008-12-01/arch/x86/kernel/io_apic_64-xen.c +=================================================================== +--- head-2008-12-01.orig/arch/x86/kernel/io_apic_64-xen.c 2008-11-25 12:22:34.000000000 +0100 ++++ head-2008-12-01/arch/x86/kernel/io_apic_64-xen.c 2008-12-01 11:28:17.000000000 +0100 +@@ -2054,6 +2054,8 @@ void __init setup_IO_APIC(void) + print_IO_APIC(); + } + ++#ifndef CONFIG_XEN ++ + struct sysfs_ioapic_data { + struct sys_device dev; + struct IO_APIC_route_entry entry[0]; +@@ -2107,10 +2109,8 @@ static int ioapic_resume(struct sys_devi + + static struct sysdev_class ioapic_sysdev_class = { + set_kset_name("ioapic"), +-#ifndef CONFIG_XEN + .suspend = ioapic_suspend, + .resume = ioapic_resume, +-#endif + }; + + static int __init ioapic_init_sysfs(void) +@@ -2148,6 +2148,8 @@ static int __init ioapic_init_sysfs(void + + device_initcall(ioapic_init_sysfs); + ++#endif /* CONFIG_XEN */ ++ + /* -------------------------------------------------------------------------- + ACPI-based IOAPIC Configuration + -------------------------------------------------------------------------- */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/761-highpte.patch b/src/patches/suse-2.6.27.31/patches.xen/761-highpte.patch new file mode 100644 index 000000000..9004844d8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/761-highpte.patch @@ -0,0 +1,86 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/5e1269aa5c29 +# HG changeset 761 patch +# User Keir Fraser +# Date 1228915952 0 +# Node ID 5e1269aa5c2933e0cb0272bf5867e1214174bfde +# Parent 0d10be086a781afa2dd220e247e4a8047a296b38 +Subject: blktap, gntdev: fix highpte handling +Patch-mainline: obsolete + +In case of highpte, virt_to_machine() can't be used. Introduce +ptep_to_machine() and use it, also to simplify xen_l1_entry_update(). + +Original patch from: Isaku Yamahata +Signed-off-by: Jan Beulich + +--- head-2008-12-15.orig/arch/x86/mm/hypervisor.c 2008-12-15 11:13:20.000000000 +0100 ++++ head-2008-12-15/arch/x86/mm/hypervisor.c 2008-12-15 11:13:45.000000000 +0100 +@@ -47,12 +47,7 @@ + void xen_l1_entry_update(pte_t *ptr, pte_t val) + { + mmu_update_t u; +-#ifdef CONFIG_HIGHPTE +- u.ptr = ((unsigned long)ptr >= (unsigned long)high_memory) ? +- arbitrary_virt_to_machine(ptr) : virt_to_machine(ptr); +-#else +- u.ptr = virt_to_machine(ptr); +-#endif ++ u.ptr = ptep_to_machine(ptr); + u.val = __pte_val(val); + BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); + } +--- head-2008-12-15.orig/drivers/xen/blktap/blktap.c 2008-12-15 11:13:20.000000000 +0100 ++++ head-2008-12-15/drivers/xen/blktap/blktap.c 2008-12-15 11:13:45.000000000 +0100 +@@ -364,7 +364,7 @@ static pte_t blktap_clear_pte(struct vm_ + BUG_ON(xen_feature(XENFEAT_auto_translated_physmap)); + + copy = *ptep; +- gnttab_set_unmap_op(&unmap[count], virt_to_machine(ptep), ++ gnttab_set_unmap_op(&unmap[count], ptep_to_machine(ptep), + GNTMAP_host_map + | GNTMAP_application_map + | GNTMAP_contains_pte, +--- head-2008-12-15.orig/drivers/xen/gntdev/gntdev.c 2008-12-15 11:13:20.000000000 +0100 ++++ head-2008-12-15/drivers/xen/gntdev/gntdev.c 2008-12-15 11:13:45.000000000 +0100 +@@ -769,7 +769,7 @@ static pte_t gntdev_clear_pte(struct vm_ + GNTDEV_INVALID_HANDLE && + !xen_feature(XENFEAT_auto_translated_physmap)) { + /* NOT USING SHADOW PAGE TABLES. */ +- gnttab_set_unmap_op(&op, virt_to_machine(ptep), ++ gnttab_set_unmap_op(&op, ptep_to_machine(ptep), + GNTMAP_contains_pte, + private_data->grants[slot_index] + .u.valid.user_handle); +--- head-2008-12-15.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:13:20.000000000 +0100 ++++ head-2008-12-15/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:13:45.000000000 +0100 +@@ -488,6 +488,19 @@ void make_pages_writable(void *va, unsig + (((maddr_t)pte_mfn(*virt_to_ptep(va)) << PAGE_SHIFT) \ + | ((unsigned long)(va) & (PAGE_SIZE - 1))) + ++#ifdef CONFIG_HIGHPTE ++#include ++struct page *kmap_atomic_to_page(void *); ++#define ptep_to_machine(ptep) \ ++({ \ ++ pte_t *__ptep = (ptep); \ ++ page_to_phys(kmap_atomic_to_page(__ptep)) \ ++ | ((unsigned long)__ptep & (PAGE_SIZE - 1)); \ ++}) ++#else ++#define ptep_to_machine(ptep) virt_to_machine(ptep) ++#endif ++ + #endif /* !__ASSEMBLY__ */ + + #ifdef CONFIG_FLATMEM +--- head-2008-12-15.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:13:20.000000000 +0100 ++++ head-2008-12-15/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:13:45.000000000 +0100 +@@ -30,6 +30,8 @@ extern pte_t *lookup_address(unsigned lo + #define arbitrary_virt_to_machine(va) \ + (((maddr_t)pte_mfn(*virt_to_ptep(va)) << PAGE_SHIFT) \ + | ((unsigned long)(va) & (PAGE_SIZE - 1))) ++ ++#define ptep_to_machine(ptep) virt_to_machine(ptep) + #endif + + extern pud_t level3_kernel_pgt[512]; diff --git a/src/patches/suse-2.6.27.31/patches.xen/762-xencons-hvc.patch b/src/patches/suse-2.6.27.31/patches.xen/762-xencons-hvc.patch new file mode 100644 index 000000000..15a1ba7ec --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/762-xencons-hvc.patch @@ -0,0 +1,84 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/a070228ac76e +# HG changeset 762 patch +# User Ian Campbell +# Date 1229002728 0 +# Node ID a070228ac76e3f6cd2483e0cad03f1cccae7a0c8 +# Parent 5e1269aa5c2933e0cb0272bf5867e1214174bfde +Subject: add hvc compatibility mode to xencons +Patch-mainline: obsolete + +Makes switching back and forth with a pvops kernel easier. Taken from +http://lists.alioth.debian.org/pipermail/pkg-xen-devel/2008-October/002098.html +http://svn.debian.org/viewsvn/kernel?rev=12337&view=rev with thanks to +Bastian Blank. + +Signed-off-by: Ian Campbell +Acked-by: jbeulich@novell.com + +--- head-2008-12-15.orig/drivers/xen/console/console.c 2008-12-15 11:13:20.000000000 +0100 ++++ head-2008-12-15/drivers/xen/console/console.c 2008-12-15 11:13:47.000000000 +0100 +@@ -66,13 +66,14 @@ + * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'. + * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'. + * 'xencons=xvc' [XC_XVC]: Console attached to '/dev/xvc0'. ++ * 'xencons=hvc' [XC_HVC]: Console attached to '/dev/hvc0'. + * default: XC_XVC + * + * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses + * warnings from standard distro startup scripts. + */ + static enum { +- XC_OFF, XC_TTY, XC_SERIAL, XC_XVC ++ XC_OFF, XC_TTY, XC_SERIAL, XC_XVC, XC_HVC + } xc_mode = XC_XVC; + static int xc_num = -1; + +@@ -80,6 +81,10 @@ static int xc_num = -1; + #define XEN_XVC_MAJOR 204 + #define XEN_XVC_MINOR 191 + ++/* /dev/hvc0 device number */ ++#define XEN_HVC_MAJOR 229 ++#define XEN_HVC_MINOR 0 ++ + #ifdef CONFIG_MAGIC_SYSRQ + static unsigned long sysrq_requested; + extern int sysrq_enabled; +@@ -102,6 +107,9 @@ static int __init xencons_setup(char *st + } else if (!strncmp(str, "xvc", 3)) { + xc_mode = XC_XVC; + str += 3; ++ } else if (!strncmp(str, "hvc", 3)) { ++ xc_mode = XC_HVC; ++ str += 3; + } else if (!strncmp(str, "off", 3)) { + xc_mode = XC_OFF; + str += 3; +@@ -210,6 +218,14 @@ static int __init xen_console_init(void) + xc_num = 0; + break; + ++ case XC_HVC: ++ strcpy(kcons_info.name, "hvc"); ++ if (xc_num == -1) ++ xc_num = 0; ++ if (!is_initial_xendomain()) ++ add_preferred_console(kcons_info.name, xc_num, NULL); ++ break; ++ + case XC_SERIAL: + strcpy(kcons_info.name, "ttyS"); + if (xc_num == -1) +@@ -685,6 +701,12 @@ static int __init xencons_init(void) + DRV(xencons_driver)->minor_start = XEN_XVC_MINOR; + DRV(xencons_driver)->name_base = xc_num; + break; ++ case XC_HVC: ++ DRV(xencons_driver)->name = "hvc"; ++ DRV(xencons_driver)->major = XEN_HVC_MAJOR; ++ DRV(xencons_driver)->minor_start = XEN_HVC_MINOR; ++ DRV(xencons_driver)->name_base = xc_num; ++ break; + case XC_SERIAL: + DRV(xencons_driver)->name = "ttyS"; + DRV(xencons_driver)->minor_start = 64 + xc_num; diff --git a/src/patches/suse-2.6.27.31/patches.xen/764-netback-foreign-pages.patch b/src/patches/suse-2.6.27.31/patches.xen/764-netback-foreign-pages.patch new file mode 100644 index 000000000..58db1f6c9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/764-netback-foreign-pages.patch @@ -0,0 +1,96 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/618fc299e2f1 +# HG changeset 764 patch +# User Keir Fraser +# Date 1229601096 0 +# Node ID 618fc299e2f1e222686bc234c48ac70e1104e18d +# Parent ff9683032b76f533509191bb9532df10cbb9830b +Subject: netback: handle non-netback foreign pages +Patch-mainline: obsolete + +An SKB can contain pages which are foreign but not tracked by netback, +such as those created by gnttab_copy_grant_page when in +NETBK_DELAYED_COPY_SKB mode. These pages do not have a mapping field +which points to a valid offset in the pending_tx_info array. + +Signed-off-by: Ian Campbell +Acked-by: jbeulich@novell.com + +--- head-2008-12-23.orig/drivers/xen/netback/netback.c 2008-12-01 11:25:57.000000000 +0100 ++++ head-2008-12-23/drivers/xen/netback/netback.c 2008-12-23 09:31:07.000000000 +0100 +@@ -40,9 +40,6 @@ + + /*define NETBE_DEBUG_INTERRUPT*/ + +-/* extra field used in struct page */ +-#define netif_page_index(pg) (*(long *)&(pg)->mapping) +- + struct netbk_rx_meta { + skb_frag_t frag; + int id; +@@ -89,6 +86,25 @@ static inline unsigned long idx_to_kaddr + return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx)); + } + ++/* extra field used in struct page */ ++static inline void netif_set_page_index(struct page *pg, unsigned int index) ++{ ++ *(unsigned long *)&pg->mapping = index; ++} ++ ++static inline int netif_page_index(struct page *pg) ++{ ++ unsigned long idx = (unsigned long)pg->mapping; ++ ++ if (!PageForeign(pg)) ++ return -1; ++ ++ if ((idx >= MAX_PENDING_REQS) || (mmap_pages[idx] != pg)) ++ return -1; ++ ++ return idx; ++} ++ + #define PKT_PROT_LEN 64 + + static struct pending_tx_info { +@@ -370,6 +386,7 @@ static u16 netbk_gop_frag(netif_t *netif + multicall_entry_t *mcl; + netif_rx_request_t *req; + unsigned long old_mfn, new_mfn; ++ int idx = netif_page_index(page); + + old_mfn = virt_to_mfn(page_address(page)); + +@@ -380,9 +397,8 @@ static u16 netbk_gop_frag(netif_t *netif + meta->copy = 1; + copy_gop = npo->copy + npo->copy_prod++; + copy_gop->flags = GNTCOPY_dest_gref; +- if (PageForeign(page)) { +- struct pending_tx_info *src_pend = +- &pending_tx_info[netif_page_index(page)]; ++ if (idx > -1) { ++ struct pending_tx_info *src_pend = &pending_tx_info[idx]; + copy_gop->source.domid = src_pend->netif->domid; + copy_gop->source.u.ref = src_pend->req.gref; + copy_gop->flags |= GNTCOPY_source_gref; +@@ -1437,8 +1453,10 @@ static void netif_idx_release(u16 pendin + + static void netif_page_release(struct page *page, unsigned int order) + { ++ int idx = netif_page_index(page); + BUG_ON(order); +- netif_idx_release(netif_page_index(page)); ++ BUG_ON(idx < 0); ++ netif_idx_release(idx); + } + + irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs) +@@ -1572,7 +1590,7 @@ static int __init netback_init(void) + for (i = 0; i < MAX_PENDING_REQS; i++) { + page = mmap_pages[i]; + SetPageForeign(page, netif_page_release); +- netif_page_index(page) = i; ++ netif_set_page_index(page, i); + INIT_LIST_HEAD(&pending_inuse[i].list); + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/769-evtchn-CPU-offline.patch b/src/patches/suse-2.6.27.31/patches.xen/769-evtchn-CPU-offline.patch new file mode 100644 index 000000000..19fe4d1bd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/769-evtchn-CPU-offline.patch @@ -0,0 +1,48 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/79e82ae1bad0 +# HG changeset 769 patch +# User Keir Fraser +# Date 1231154982 0 +# Node ID 79e82ae1bad02c0dfb504db3153599e52a0affb3 +# Parent cfb171ddbb333df9671a1da62e40122a56213ab4 +Subject: evtchn: Fix CPU offlining to switch all affected ports +belonging to a particular /dev/evcthn user. +Patch-mainline: obsolete + +Original patch by James Harper + +Signed-off-by: Keir Fraser +Acked-by: jbeulich@novell.com + +--- head-2009-01-06.orig/drivers/xen/evtchn/evtchn.c 2008-09-01 12:20:11.000000000 +0200 ++++ head-2009-01-06/drivers/xen/evtchn/evtchn.c 2009-01-05 12:29:42.000000000 +0100 +@@ -497,20 +497,22 @@ static int __cpuinit evtchn_cpu_notify(s + { + int hotcpu = (unsigned long)hcpu; + cpumask_t map = cpu_online_map; +- int port, newcpu; ++ int i, j, newcpu; + struct per_user_data *u; + + switch (action) { + case CPU_DOWN_PREPARE: + cpu_clear(hotcpu, map); + spin_lock_irq(&port_user_lock); +- for (port = 0; port < NR_EVENT_CHANNELS; port++) { +- if ((u = port_user[port]) != NULL && +- u->bind_cpu == hotcpu && +- (newcpu = next_bind_cpu(map)) < NR_CPUS) { +- rebind_evtchn_to_cpu(port, newcpu); +- u->bind_cpu = newcpu; +- } ++ for (i = 0; i < NR_EVENT_CHANNELS; i++) { ++ u = port_user[i]; ++ if ((u == NULL) || (u->bind_cpu != hotcpu)) ++ continue; ++ newcpu = next_bind_cpu(map); ++ for (j = i; j < NR_EVENT_CHANNELS; j++) ++ if (port_user[j] == u) ++ rebind_evtchn_to_cpu(j, newcpu); ++ u->bind_cpu = newcpu; + } + spin_unlock_irq(&port_user_lock); + break; diff --git a/src/patches/suse-2.6.27.31/patches.xen/781-fbfront-bogus-rect.patch b/src/patches/suse-2.6.27.31/patches.xen/781-fbfront-bogus-rect.patch new file mode 100644 index 000000000..cb30ea5dc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/781-fbfront-bogus-rect.patch @@ -0,0 +1,149 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/c9783c08495c +# HG changeset 781+783+788+789 patch +# User Keir Fraser +# Date 1233150093 0 +# Node ID c9783c08495c56337dec371582b3f948e3b5ed8d +# Parent 83b71f4b5cb216d09856391d8616ee2cb6525c73 +Subject: xenfb: fix xenfb_update_screen bogus rect +References: bnc#474335 + +Signed-off-by: Keir Fraser + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/8197c86e6729 +# HG changeset patch +# User Keir Fraser +# Date 1233228538 0 +# Node ID 8197c86e67294835c9d90540cf776c373664c3ef +# Parent 51decc39e5e73ea201d0b96108f8a893106a6864 +xenfb: eliminate the update_wanted field. + +Signed-off-by: Akio Takebe + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/26ddc59c674d +# HG changeset patch +# User Keir Fraser +# Date 1233312850 0 +# Node ID 26ddc59c674df460cb36651ffe58bf30e46b1638 +# Parent 98897f04b338f08686eba199d6234a95cf0939f1 +xenfb: Revert mm_lock changes. They're not needed. +Signed-off-by: Akio Takebe + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/25cc543a02e8 +# HG changeset patch +# User Keir Fraser +# Date 1233669557 0 +# Node ID 25cc543a02e88c090d117ee362ad006d1930f47b +# Parent 26ddc59c674df460cb36651ffe58bf30e46b1638 +fbfront: Improve diagnostics when kthread_run() fails + +Failure is reported with xenbus_dev_fatal(..."register_framebuffer"), +which was already suboptimal before it got moved away from +register_framebuffer(), and is outright misleading now. + +Signed-off-by: Markus Armbruster + +Acked-by: jbeulich@novell.com + +--- sle11-2009-02-16.orig/drivers/xen/fbfront/xenfb.c 2009-02-16 15:55:51.000000000 +0100 ++++ sle11-2009-02-16/drivers/xen/fbfront/xenfb.c 2009-02-16 15:59:55.000000000 +0100 +@@ -61,7 +61,6 @@ struct xenfb_info + int irq; + struct xenfb_page *page; + unsigned long *mfns; +- int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + int feature_resize; /* Backend has resize feature */ + struct xenfb_resize resize; + int resize_dpy; +@@ -208,20 +207,25 @@ static void xenfb_update_screen(struct x + int y1, y2, x1, x2; + struct xenfb_mapping *map; + +- if (!info->update_wanted) +- return; + if (xenfb_queue_full(info)) + return; + + mutex_lock(&info->mm_lock); + + spin_lock_irqsave(&info->dirty_lock, flags); +- y1 = info->y1; +- y2 = info->y2; +- x1 = info->x1; +- x2 = info->x2; +- info->x1 = info->y1 = INT_MAX; +- info->x2 = info->y2 = 0; ++ if (info->dirty){ ++ info->dirty = 0; ++ y1 = info->y1; ++ y2 = info->y2; ++ x1 = info->x1; ++ x2 = info->x2; ++ info->x1 = info->y1 = INT_MAX; ++ info->x2 = info->y2 = 0; ++ } else { ++ spin_unlock_irqrestore(&info->dirty_lock, flags); ++ mutex_unlock(&info->mm_lock); ++ return; ++ } + spin_unlock_irqrestore(&info->dirty_lock, flags); + + list_for_each_entry(map, &info->mappings, link) { +@@ -262,10 +266,7 @@ static int xenfb_thread(void *data) + + while (!kthread_should_stop()) { + xenfb_handle_resize_dpy(info); +- if (info->dirty) { +- info->dirty = 0; +- xenfb_update_screen(info); +- } ++ xenfb_update_screen(info); + wait_event_interruptible(info->wq, + kthread_should_stop() || info->dirty); + try_to_freeze(); +@@ -666,15 +667,6 @@ static int __devinit xenfb_probe(struct + if (ret < 0) + goto error; + +- /* FIXME should this be delayed until backend XenbusStateConnected? */ +- info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); +- if (IS_ERR(info->kthread)) { +- ret = PTR_ERR(info->kthread); +- info->kthread = NULL; +- xenbus_dev_fatal(dev, ret, "register_framebuffer"); +- goto error; +- } +- + return 0; + + error_nomem: +@@ -829,16 +821,25 @@ static void xenfb_backend_changed(struct + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + +- if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, +- "request-update", "%d", &val) < 0) +- val = 0; +- if (val) +- info->update_wanted = 1; + + if (xenbus_scanf(XBT_NIL, dev->otherend, + "feature-resize", "%d", &val) < 0) + val = 0; + info->feature_resize = val; ++ ++ if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, ++ "request-update", "%d", &val) < 0) ++ val = 0; ++ ++ if (val){ ++ info->kthread = kthread_run(xenfb_thread, info, ++ "xenfb thread"); ++ if (IS_ERR(info->kthread)) { ++ info->kthread = NULL; ++ xenbus_dev_fatal(dev, PTR_ERR(info->kthread), ++ "xenfb_thread"); ++ } ++ } + break; + + case XenbusStateClosing: diff --git a/src/patches/suse-2.6.27.31/patches.xen/782-netback-error-handling.patch b/src/patches/suse-2.6.27.31/patches.xen/782-netback-error-handling.patch new file mode 100644 index 000000000..7d07c4e55 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/782-netback-error-handling.patch @@ -0,0 +1,27 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/51decc39e5e7 +# HG changeset 782 patch +# User Keir Fraser +# Date 1233150129 0 +# Node ID 51decc39e5e73ea201d0b96108f8a893106a6864 +# Parent c9783c08495c56337dec371582b3f948e3b5ed8d +Subject: linux/netback: unmap tx ring gref when mapping of rx ring gref failed +Patch-mainline: obsolete + +Signed-off-by: Jan Beulich + +--- head-2009-02-02.orig/drivers/xen/netback/interface.c 2009-02-02 09:28:02.000000000 +0100 ++++ head-2009-02-02/drivers/xen/netback/interface.c 2009-02-02 09:40:43.000000000 +0100 +@@ -219,6 +219,13 @@ static int map_frontend_pages( + BUG(); + + if (op.status) { ++ struct gnttab_unmap_grant_ref unop; ++ ++ gnttab_set_unmap_op(&unop, ++ (unsigned long)netif->tx_comms_area->addr, ++ GNTMAP_host_map, netif->tx_shmem_handle); ++ VOID(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, ++ &unop, 1)); + DPRINTK(" Gnttab failure mapping rx_ring_ref!\n"); + return op.status; + } diff --git a/src/patches/suse-2.6.27.31/patches.xen/791-x86-pcifront-register-pirq.patch b/src/patches/suse-2.6.27.31/patches.xen/791-x86-pcifront-register-pirq.patch new file mode 100644 index 000000000..36441868d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/791-x86-pcifront-register-pirq.patch @@ -0,0 +1,47 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/4f998fd102e2 +# HG changeset 791 patch +# User Keir Fraser +# Date 1233750360 0 +# Node ID 4f998fd102e24daa471482730d1a3ff68faa1ad6 +# Parent 77e3b255381e02021d460d535e44b1040a180773 +Subject: linux: fix IRQ handling for PV passthrough +References: bnc#463596 +Patch-mainline: obsolete + +For DomU-s registering PIRQ-s must be done separately, as they don't +use the IO-APIC code. + +Additionally make sure the IRQ chip doesn't get set twice (and the +event channel information overwritten) for an IRQ possibly in use by +more than one device. + +Signed-off-by: Jan Beulich + +--- sle11-2009-02-05.orig/arch/x86/pci/pcifront.c 2009-02-05 10:01:48.000000000 +0100 ++++ sle11-2009-02-05/arch/x86/pci/pcifront.c 2009-02-05 10:20:20.000000000 +0100 +@@ -8,12 +8,14 @@ + #include + #include + #include ++#include + #include "pci.h" + + static int pcifront_enable_irq(struct pci_dev *dev) + { + u8 irq; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); ++ evtchn_register_pirq(irq); + dev->irq = irq; + + return 0; +--- sle11-2009-02-05.orig/drivers/xen/core/evtchn.c 2009-02-05 10:20:03.000000000 +0100 ++++ sle11-2009-02-05/drivers/xen/core/evtchn.c 2009-02-05 10:20:20.000000000 +0100 +@@ -1078,7 +1078,7 @@ void irq_resume(void) + void evtchn_register_pirq(int irq) + { + BUG_ON(irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS); +- if (identity_mapped_irq(irq)) ++ if (identity_mapped_irq(irq) || type_from_irq(irq) != IRQT_UNBOUND) + return; + irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0); + irq_desc[irq].chip = &pirq_type; diff --git a/src/patches/suse-2.6.27.31/patches.xen/797-pirq-range-check.patch b/src/patches/suse-2.6.27.31/patches.xen/797-pirq-range-check.patch new file mode 100644 index 000000000..4faeedd65 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/797-pirq-range-check.patch @@ -0,0 +1,49 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/2f1b770d84e5 +# HG changeset 797,804 patch +# User Keir Fraser +# Date 1234870273 0 +# Node ID 2f1b770d84e54f76185181b0cc74337bf79a2a83 +# Parent f0db1ac7ca8d55defe710ab0539bdc8578772677 +Subject: linux/x86: fix off-by-one error in the pirq range checks +Patch-mainline: obsolete + +Signed-off-by: Jan Beulich + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/f3de83c4677f +Subject: linux/evtchn: fix off-by-one error in the pirq range check + +Signed-off-by: Jan Beulich + +--- sle11-2009-03-16.orig/arch/x86/kernel/io_apic_32-xen.c 2009-03-16 16:13:42.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/kernel/io_apic_32-xen.c 2009-03-16 16:13:45.000000000 +0100 +@@ -1220,7 +1220,7 @@ int assign_irq_vector(int irq) + + BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); + +- if (irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS) ++ if (irq < PIRQ_BASE || irq - PIRQ_BASE >= NR_PIRQS) + return -EINVAL; + + spin_lock_irqsave(&vector_lock, flags); +--- sle11-2009-03-16.orig/arch/x86/kernel/io_apic_64-xen.c 2009-03-16 16:13:42.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/kernel/io_apic_64-xen.c 2009-03-16 16:13:45.000000000 +0100 +@@ -895,7 +895,7 @@ int assign_irq_vector(int irq) + + BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); + +- if (irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS) ++ if (irq < PIRQ_BASE || irq - PIRQ_BASE >= NR_PIRQS) + return -EINVAL; + + spin_lock_irqsave(&vector_lock, flags); +--- sle11-2009-03-16.orig/drivers/xen/core/evtchn.c 2009-03-16 16:06:43.000000000 +0100 ++++ sle11-2009-03-16/drivers/xen/core/evtchn.c 2009-03-16 16:14:12.000000000 +0100 +@@ -1077,7 +1077,7 @@ void irq_resume(void) + + void evtchn_register_pirq(int irq) + { +- BUG_ON(irq < PIRQ_BASE || irq - PIRQ_BASE > NR_PIRQS); ++ BUG_ON(irq < PIRQ_BASE || irq - PIRQ_BASE >= NR_PIRQS); + if (identity_mapped_irq(irq) || type_from_irq(irq) != IRQT_UNBOUND) + return; + irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0); diff --git a/src/patches/suse-2.6.27.31/patches.xen/801-pciback-no-pci_match_id.patch b/src/patches/suse-2.6.27.31/patches.xen/801-pciback-no-pci_match_id.patch new file mode 100644 index 000000000..1eee203e8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/801-pciback-no-pci_match_id.patch @@ -0,0 +1,45 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/5b779f810966 +# HG changeset 801 patch +# User Keir Fraser +# Date 1235991476 0 +# Node ID 5b779f8109662803b7d292ef1effbf68be3319d2 +# Parent ae2cf9ef03acd34c2fd747c924aa9660467055a1 +Subject: pciback: Fix invalid use of pci_match_id() + +We cannot use pci_match_id() because the first argument (tmp_quirk->devid) +is not an array of pci device ids. Instead this patch adds a utility +function to compare a pci_device_id and a pci_dev. + +Signed-off-by: Yosuke Iwamatsu +Acked-by: jbeulich@novell.com + +--- sle11-2009-03-04.orig/drivers/xen/pciback/conf_space_quirks.c 2008-09-01 12:20:11.000000000 +0200 ++++ sle11-2009-03-04/drivers/xen/pciback/conf_space_quirks.c 2009-03-04 11:25:24.000000000 +0100 +@@ -13,13 +13,25 @@ + + LIST_HEAD(pciback_quirks); + ++static inline const struct pci_device_id * ++match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) ++{ ++ if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && ++ (id->device == PCI_ANY_ID || id->device == dev->device) && ++ (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) && ++ (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) && ++ !((id->class ^ dev->class) & id->class_mask)) ++ return id; ++ return NULL; ++} ++ + struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev) + { + struct pciback_config_quirk *tmp_quirk; + + list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list) +- if (pci_match_id(&tmp_quirk->devid, dev)) +- goto out; ++ if (match_one_device(&tmp_quirk->devid, dev) != NULL) ++ goto out; + tmp_quirk = NULL; + printk(KERN_DEBUG + "quirk didn't match any device pciback knows about\n"); diff --git a/src/patches/suse-2.6.27.31/patches.xen/803-netfront-unregister-notifier.patch b/src/patches/suse-2.6.27.31/patches.xen/803-netfront-unregister-notifier.patch new file mode 100644 index 000000000..10756e086 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/803-netfront-unregister-notifier.patch @@ -0,0 +1,44 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/86e119bc82c5 +# HG changeset 803 patch +# User Keir Fraser +# Date 1235992012 0 +# Node ID 86e119bc82c5137e502bc8f68f65aba37f0a1a02 +# Parent 979f8ccc314cd873e853fa9be6a72324c8ad119c +Subject: netfront: Unregister inetdev notifiers on failure +If you attempt to modprobe the pv-on-hvm netfront driver on a machine +not running under Xen (say, bare-metal, or under another hypervisor), the +netfront code correctly returns an ENODEV and fails to load. However, if you +then shutdown that machine, you will oops while tearing down the network. +This is because we forget to unregister the the inetaddr_notifier on failure, +and so the kernel takes a fatal page fault. The attached patch just unregisters +the notifier on failure, and solves the problem for me. + +Signed-off-by: Chris Lalancette +Acked-by: jbeulich@novell.com + +--- sle11-2009-03-04.orig/drivers/xen/netfront/netfront.c 2009-03-04 10:50:17.000000000 +0100 ++++ sle11-2009-03-04/drivers/xen/netfront/netfront.c 2009-03-04 11:25:33.000000000 +0100 +@@ -2199,6 +2199,8 @@ static struct xenbus_driver netfront_dri + + static int __init netif_init(void) + { ++ int err; ++ + if (!is_running_on_xen()) + return -ENODEV; + +@@ -2220,7 +2222,13 @@ static int __init netif_init(void) + (void)register_inetaddr_notifier(¬ifier_inetdev); + #endif + +- return xenbus_register_frontend(&netfront_driver); ++ err = xenbus_register_frontend(&netfront_driver); ++ if (err) { ++#ifdef CONFIG_INET ++ unregister_inetaddr_notifier(¬ifier_inetdev); ++#endif ++ } ++ return err; + } + module_init(netif_init); + diff --git a/src/patches/suse-2.6.27.31/patches.xen/805-blkfront-map-sg.patch b/src/patches/suse-2.6.27.31/patches.xen/805-blkfront-map-sg.patch new file mode 100644 index 000000000..bbd160edf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/805-blkfront-map-sg.patch @@ -0,0 +1,106 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/63be3e5e2f1a +# HG changeset 805+806 patch +# User Keir Fraser +# Date 1236264120 0 +# Node ID 63be3e5e2f1a132ce062c446a7d742e3523cf16b +# Parent f3de83c4677ff77eaf445b3182f00169f6982ce3 +Subject: linux/blkfront: use blk_rq_map_sg to generate ring entries +Patch-mainline: 2.6.29 +References: bnc#470238 + +Signed-off-by: Jens Axboe +Signed-off-by: Jeremy Fitzhardinge +Signed-off-by: Jan Beulich + +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/0430b1dbfb3a +blkfront: Fix the build by expanding sg_init_table() in place. + +Signed-off-by: Keir Fraser + +--- sle11-2009-03-24.orig/drivers/xen/blkfront/blkfront.c 2009-03-24 10:00:15.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/blkfront/blkfront.c 2009-03-05 15:42:00.000000000 +0100 +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -232,6 +233,8 @@ static int setup_blkring(struct xenbus_d + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); + ++ memset(info->sg, 0, sizeof(info->sg)); ++ + err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); + if (err < 0) { + free_page((unsigned long)sring); +@@ -587,13 +590,11 @@ static int blkif_queue_request(struct re + struct blkfront_info *info = req->rq_disk->private_data; + unsigned long buffer_mfn; + blkif_request_t *ring_req; +- struct bio *bio; +- struct bio_vec *bvec; +- int idx; + unsigned long id; + unsigned int fsect, lsect; +- int ref; ++ int i, ref; + grant_ref_t gref_head; ++ struct scatterlist *sg; + + if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) + return 1; +@@ -622,14 +623,13 @@ static int blkif_queue_request(struct re + if (blk_barrier_rq(req)) + ring_req->operation = BLKIF_OP_WRITE_BARRIER; + +- ring_req->nr_segments = 0; +- rq_for_each_bio (bio, req) { +- bio_for_each_segment (bvec, bio, idx) { +- BUG_ON(ring_req->nr_segments +- == BLKIF_MAX_SEGMENTS_PER_REQUEST); +- buffer_mfn = page_to_phys(bvec->bv_page) >> PAGE_SHIFT; +- fsect = bvec->bv_offset >> 9; +- lsect = fsect + (bvec->bv_len >> 9) - 1; ++ ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); ++ BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); ++ for (i = 0; i < ring_req->nr_segments; ++i) { ++ sg = info->sg + i; ++ buffer_mfn = page_to_phys(sg->page) >> PAGE_SHIFT; ++ fsect = sg->offset >> 9; ++ lsect = fsect + (sg->length >> 9) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); +@@ -640,17 +640,12 @@ static int blkif_queue_request(struct re + buffer_mfn, + rq_data_dir(req) ? GTF_readonly : 0 ); + +- info->shadow[id].frame[ring_req->nr_segments] = +- mfn_to_pfn(buffer_mfn); +- +- ring_req->seg[ring_req->nr_segments] = ++ info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn); ++ ring_req->seg[i] = + (struct blkif_request_segment) { + .gref = ref, + .first_sect = fsect, + .last_sect = lsect }; +- +- ring_req->nr_segments++; +- } + } + + info->ring.req_prod_pvt++; +--- sle11-2009-03-24.orig/drivers/xen/blkfront/block.h 2009-03-24 10:00:15.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/blkfront/block.h 2009-03-05 15:42:00.000000000 +0100 +@@ -103,6 +103,7 @@ struct blkfront_info + int connected; + int ring_ref; + blkif_front_ring_t ring; ++ struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + unsigned int irq; + struct xlbd_major_info *mi; + request_queue_t *rq; diff --git a/src/patches/suse-2.6.27.31/patches.xen/821-xenbus-state-strings.patch b/src/patches/suse-2.6.27.31/patches.xen/821-xenbus-state-strings.patch new file mode 100644 index 000000000..b6ef6ee6d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/821-xenbus-state-strings.patch @@ -0,0 +1,26 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/6669e480cb59 +# HG changeset 821 patch +# User Keir Fraser +# Date 1237300051 0 +# Node ID 6669e480cb59e70767d835bbd0294ed5266692a9 +# Parent 8b86d11a6eb39550304ab118dcade4902927a1c8 +Subject: xenbus: Add new states to xenbus_strstate() + +This patch adds the following states to the xenbus_strstate(). +- XenbusStateReconfiguring +- XenbusStateReconfigured + +Signed-off-by: Noboru Iwamatsu +Acked-by: jbeulich@novell.com + +--- sle11-2009-03-24.orig/drivers/xen/xenbus/xenbus_client.c 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/xenbus/xenbus_client.c 2009-03-17 15:27:31.000000000 +0100 +@@ -53,6 +53,8 @@ const char *xenbus_strstate(enum xenbus_ + [ XenbusStateConnected ] = "Connected", + [ XenbusStateClosing ] = "Closing", + [ XenbusStateClosed ] = "Closed", ++ [ XenbusStateReconfiguring ] = "Reconfiguring", ++ [ XenbusStateReconfigured ] = "Reconfigured", + }; + return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; + } diff --git a/src/patches/suse-2.6.27.31/patches.xen/832-ntp-interaction.patch b/src/patches/suse-2.6.27.31/patches.xen/832-ntp-interaction.patch new file mode 100644 index 000000000..b0460f7e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/832-ntp-interaction.patch @@ -0,0 +1,40 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/c0f2f398aa3c +# HG changeset 832 patch +# User Keir Fraser +# Date 1237377065 0 +# Node ID c0f2f398aa3cab195b632531447e95110e9d8282 +# Parent c1f0373ff44ea3f9ba3845e05faf3d27d7d52731 +Subject: x86: Fix interaction of NTP and dom0->xen time updates + +Don't discard NTP sync when updating Xen wallclock time from dom0, +as that's almost the first thing we do when we become synced. +Move the call to ntp_clear() into do_settimeofday(), which is the +only caller of __update_wallclock() that looks like it should break +NTP sync. + +This fixes the timer chain that sets Xen's wallclock every minute when +dom0 is NTP synced, which in turn greatly improves wallclock accuracy +in PV domU. + +Signed-off-by: Tim Deegan +Acked-by: jbeulich@novell.com + +--- sle11-2009-03-24.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:00:15.000000000 +0100 ++++ sle11-2009-03-24/arch/x86/kernel/time_32-xen.c 2009-03-18 12:51:05.000000000 +0100 +@@ -286,8 +286,6 @@ static void __update_wallclock(time_t se + + set_normalized_timespec(&xtime, xtime_sec, xtime_nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); +- +- ntp_clear(); + } + + static void update_wallclock(void) +@@ -496,6 +494,7 @@ int do_settimeofday(struct timespec *tv) + __normalize_time(&sec, &nsec); + __update_wallclock(sec, nsec); + } ++ ntp_clear(); + + /* Reset monotonic gettimeofday() timeval. */ + spin_lock(&monotonic_lock); diff --git a/src/patches/suse-2.6.27.31/patches.xen/844-swiotlb-alloc.patch b/src/patches/suse-2.6.27.31/patches.xen/844-swiotlb-alloc.patch new file mode 100644 index 000000000..e07d08e0a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/844-swiotlb-alloc.patch @@ -0,0 +1,41 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/87c84f7dd850 +# HG changeset 844 patch +# User Keir Fraser +# Date 1237539658 0 +# Node ID 87c84f7dd8507edc58c13f1debfad5a05aa03128 +# Parent 0a9cdf1dbad6127156609dcf389afeac09081210 +Subject: swiotlb allocations do not need to come from low memory +References: bnc#482614 + +Other than on native, where using the _low variants of alloc_bootmem() +is indeed a requirement for swiotlb, on Xen this is not needed. Using +the _low variants has the potential of preventing systems from booting +when they have lots of memory, due to the way the bootmem allocator +works: It allocates memory from bottom to top. Thus, if other large +(but not _low) allocations (memmap, large system hash tables) +mostly consume the memory below 4Gb, the swiotlb allocations can +fail. (This is equally so for native, but cannot be that easily fixed +there.) + +Signed-off-by: Jan Beulich + +--- sle11-2009-03-24.orig/lib/swiotlb-xen.c 2009-03-24 10:00:15.000000000 +0100 ++++ sle11-2009-03-24/lib/swiotlb-xen.c 2009-03-20 10:00:58.000000000 +0100 +@@ -151,7 +151,7 @@ swiotlb_init_with_default_size (size_t d + /* + * Get IO TLB memory from the low pages + */ +- iotlb_virt_start = alloc_bootmem_low_pages(bytes); ++ iotlb_virt_start = alloc_bootmem_pages(bytes); + if (!iotlb_virt_start) + panic("Cannot allocate SWIOTLB buffer!\n"); + +@@ -196,7 +196,7 @@ swiotlb_init_with_default_size (size_t d + /* + * Get the overflow emergency buffer + */ +- io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); ++ io_tlb_overflow_buffer = alloc_bootmem(io_tlb_overflow); + if (!io_tlb_overflow_buffer) + panic("Cannot allocate SWIOTLB overflow buffer!\n"); + diff --git a/src/patches/suse-2.6.27.31/patches.xen/848-sfc-vif-states-lock.patch b/src/patches/suse-2.6.27.31/patches.xen/848-sfc-vif-states-lock.patch new file mode 100644 index 000000000..de9de63dc --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/848-sfc-vif-states-lock.patch @@ -0,0 +1,596 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/ab1d4fbbe4bf +# HG changeset 848 patch +# User Keir Fraser +# Date 1238497203 -3600 +# Node ID ab1d4fbbe4bf93f203e0c4d62c18bd248e4f1d4a +# Parent ad4d307bf9ced378d0b49d4559ae33ecbff3c1b7 +Subject: netfront accel: Simplify, document, and fix a theoretical bug in use +of spin locks by netfront acceleration plugins +References: bnc#489109 +Patch-mainline: obsolete + +Signed-off-by: Kieran Mansley +Acked-by: jbeulich@novell.com + +--- sle11-2009-04-09.orig/drivers/xen/netfront/accel.c 2009-04-09 14:41:04.000000000 +0200 ++++ sle11-2009-04-09/drivers/xen/netfront/accel.c 2009-04-09 14:43:45.000000000 +0200 +@@ -57,9 +57,6 @@ static int netfront_load_accelerator(str + */ + static struct list_head accelerators_list; + +-/* Lock to protect access to accelerators_list */ +-static spinlock_t accelerators_lock; +- + /* Workqueue to process acceleration configuration changes */ + struct workqueue_struct *accel_watch_workqueue; + +@@ -69,7 +66,6 @@ DEFINE_MUTEX(accelerator_mutex); + void netif_init_accel(void) + { + INIT_LIST_HEAD(&accelerators_list); +- spin_lock_init(&accelerators_lock); + + accel_watch_workqueue = create_workqueue("net_accel"); + } +@@ -77,13 +73,11 @@ void netif_init_accel(void) + void netif_exit_accel(void) + { + struct netfront_accelerator *accelerator, *tmp; +- unsigned long flags; + + flush_workqueue(accel_watch_workqueue); + destroy_workqueue(accel_watch_workqueue); + +- spin_lock_irqsave(&accelerators_lock, flags); +- ++ /* No lock required as everything else should be quiet by now */ + list_for_each_entry_safe(accelerator, tmp, &accelerators_list, link) { + BUG_ON(!list_empty(&accelerator->vif_states)); + +@@ -91,8 +85,6 @@ void netif_exit_accel(void) + kfree(accelerator->frontend); + kfree(accelerator); + } +- +- spin_unlock_irqrestore(&accelerators_lock, flags); + } + + +@@ -245,16 +237,12 @@ static int match_accelerator(const char + + /* + * Add a frontend vif to the list of vifs that is using a netfront +- * accelerator plugin module. ++ * accelerator plugin module. Must be called with the accelerator ++ * mutex held. + */ + static void add_accelerator_vif(struct netfront_accelerator *accelerator, + struct netfront_info *np) + { +- unsigned long flags; +- +- /* Need lock to write list */ +- spin_lock_irqsave(&accelerator->vif_states_lock, flags); +- + if (np->accelerator == NULL) { + np->accelerator = accelerator; + +@@ -267,13 +255,13 @@ static void add_accelerator_vif(struct n + */ + BUG_ON(np->accelerator != accelerator); + } +- +- spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + } + + + /* + * Initialise the state to track an accelerator plugin module. ++ * ++ * Must be called with the accelerator mutex held. + */ + static int init_accelerator(const char *frontend, + struct netfront_accelerator **result, +@@ -281,7 +269,6 @@ static int init_accelerator(const char * + { + struct netfront_accelerator *accelerator = + kmalloc(sizeof(struct netfront_accelerator), GFP_KERNEL); +- unsigned long flags; + int frontend_len; + + if (!accelerator) { +@@ -303,9 +290,7 @@ static int init_accelerator(const char * + + accelerator->hooks = hooks; + +- spin_lock_irqsave(&accelerators_lock, flags); + list_add(&accelerator->link, &accelerators_list); +- spin_unlock_irqrestore(&accelerators_lock, flags); + + *result = accelerator; + +@@ -316,11 +301,14 @@ static int init_accelerator(const char * + /* + * Modify the hooks stored in the per-vif state to match that in the + * netfront accelerator's state. ++ * ++ * Takes the vif_states_lock spinlock and may sleep. + */ + static void + accelerator_set_vif_state_hooks(struct netfront_accel_vif_state *vif_state) + { +- /* This function must be called with the vif_states_lock held */ ++ struct netfront_accelerator *accelerator; ++ unsigned long flags; + + DPRINTK("%p\n",vif_state); + +@@ -328,19 +316,25 @@ accelerator_set_vif_state_hooks(struct n + netif_poll_disable(vif_state->np->netdev); + netif_tx_lock_bh(vif_state->np->netdev); + +- vif_state->hooks = vif_state->np->accelerator->hooks; ++ accelerator = vif_state->np->accelerator; ++ spin_lock_irqsave(&accelerator->vif_states_lock, flags); ++ vif_state->hooks = accelerator->hooks; ++ spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + + netif_tx_unlock_bh(vif_state->np->netdev); + netif_poll_enable(vif_state->np->netdev); + } + + ++/* ++ * Must be called with the accelerator mutex held. Takes the ++ * vif_states_lock spinlock. ++ */ + static void accelerator_probe_new_vif(struct netfront_info *np, + struct xenbus_device *dev, + struct netfront_accelerator *accelerator) + { + struct netfront_accel_hooks *hooks; +- unsigned long flags; + + DPRINTK("\n"); + +@@ -349,17 +343,8 @@ static void accelerator_probe_new_vif(st + + hooks = accelerator->hooks; + +- if (hooks) { +- if (hooks->new_device(np->netdev, dev) == 0) { +- spin_lock_irqsave +- (&accelerator->vif_states_lock, flags); +- +- accelerator_set_vif_state_hooks(&np->accel_vif_state); +- +- spin_unlock_irqrestore +- (&accelerator->vif_states_lock, flags); +- } +- } ++ if (hooks && hooks->new_device(np->netdev, dev) == 0) ++ accelerator_set_vif_state_hooks(&np->accel_vif_state); + + return; + } +@@ -368,7 +353,10 @@ static void accelerator_probe_new_vif(st + /* + * Request that a particular netfront accelerator plugin is loaded. + * Usually called as a result of the vif configuration specifying +- * which one to use. Must be called with accelerator_mutex held ++ * which one to use. ++ * ++ * Must be called with accelerator_mutex held. Takes the ++ * vif_states_lock spinlock. + */ + static int netfront_load_accelerator(struct netfront_info *np, + struct xenbus_device *dev, +@@ -407,13 +395,15 @@ static int netfront_load_accelerator(str + * this accelerator. Notify the accelerator plugin of the relevant + * device if so. Called when an accelerator plugin module is first + * loaded and connects to netfront. ++ * ++ * Must be called with accelerator_mutex held. Takes the ++ * vif_states_lock spinlock. + */ + static void + accelerator_probe_vifs(struct netfront_accelerator *accelerator, + struct netfront_accel_hooks *hooks) + { + struct netfront_accel_vif_state *vif_state, *tmp; +- unsigned long flags; + + DPRINTK("%p\n", accelerator); + +@@ -425,29 +415,22 @@ accelerator_probe_vifs(struct netfront_a + BUG_ON(hooks == NULL); + accelerator->hooks = hooks; + +- /* +- * currently hold accelerator_mutex, so don't need +- * vif_states_lock to read the list +- */ ++ /* Holds accelerator_mutex to iterate list */ + list_for_each_entry_safe(vif_state, tmp, &accelerator->vif_states, + link) { + struct netfront_info *np = vif_state->np; + +- if (hooks->new_device(np->netdev, vif_state->dev) == 0) { +- spin_lock_irqsave +- (&accelerator->vif_states_lock, flags); +- ++ if (hooks->new_device(np->netdev, vif_state->dev) == 0) + accelerator_set_vif_state_hooks(vif_state); +- +- spin_unlock_irqrestore +- (&accelerator->vif_states_lock, flags); +- } + } + } + + + /* +- * Called by the netfront accelerator plugin module when it has loaded ++ * Called by the netfront accelerator plugin module when it has ++ * loaded. ++ * ++ * Takes the accelerator_mutex and vif_states_lock spinlock. + */ + int netfront_accelerator_loaded(int version, const char *frontend, + struct netfront_accel_hooks *hooks) +@@ -503,15 +486,21 @@ EXPORT_SYMBOL_GPL(netfront_accelerator_l + + /* + * Remove the hooks from a single vif state. ++ * ++ * Takes the vif_states_lock spinlock and may sleep. + */ + static void + accelerator_remove_single_hook(struct netfront_accelerator *accelerator, + struct netfront_accel_vif_state *vif_state) + { ++ unsigned long flags; ++ + /* Make sure there are no data path operations going on */ + netif_poll_disable(vif_state->np->netdev); + netif_tx_lock_bh(vif_state->np->netdev); + ++ spin_lock_irqsave(&accelerator->vif_states_lock, flags); ++ + /* + * Remove the hooks, but leave the vif_state on the + * accelerator's list as that signifies this vif is +@@ -520,6 +509,8 @@ accelerator_remove_single_hook(struct ne + */ + vif_state->hooks = NULL; + ++ spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); ++ + netif_tx_unlock_bh(vif_state->np->netdev); + netif_poll_enable(vif_state->np->netdev); + } +@@ -527,25 +518,25 @@ accelerator_remove_single_hook(struct ne + + /* + * Safely remove the accelerator function hooks from a netfront state. ++ * ++ * Must be called with the accelerator mutex held. Takes the ++ * vif_states_lock spinlock. + */ + static void accelerator_remove_hooks(struct netfront_accelerator *accelerator) + { +- struct netfront_accel_hooks *hooks; + struct netfront_accel_vif_state *vif_state, *tmp; + unsigned long flags; + +- /* Mutex is held so don't need vif_states_lock to iterate list */ ++ /* Mutex is held to iterate list */ + list_for_each_entry_safe(vif_state, tmp, + &accelerator->vif_states, + link) { +- spin_lock_irqsave(&accelerator->vif_states_lock, flags); +- + if(vif_state->hooks) { +- hooks = vif_state->hooks; +- ++ spin_lock_irqsave(&accelerator->vif_states_lock, flags); ++ + /* Last chance to get statistics from the accelerator */ +- hooks->get_stats(vif_state->np->netdev, +- &vif_state->np->stats); ++ vif_state->hooks->get_stats(vif_state->np->netdev, ++ &vif_state->np->stats); + + spin_unlock_irqrestore(&accelerator->vif_states_lock, + flags); +@@ -553,9 +544,6 @@ static void accelerator_remove_hooks(str + accelerator_remove_single_hook(accelerator, vif_state); + + accelerator->hooks->remove(vif_state->dev); +- } else { +- spin_unlock_irqrestore(&accelerator->vif_states_lock, +- flags); + } + } + +@@ -567,47 +555,47 @@ static void accelerator_remove_hooks(str + * Called by a netfront accelerator when it is unloaded. This safely + * removes the hooks into the plugin and blocks until all devices have + * finished using it, so on return it is safe to unload. ++ * ++ * Takes the accelerator mutex, and vif_states_lock spinlock. + */ + void netfront_accelerator_stop(const char *frontend) + { + struct netfront_accelerator *accelerator; +- unsigned long flags; + + mutex_lock(&accelerator_mutex); +- spin_lock_irqsave(&accelerators_lock, flags); + + list_for_each_entry(accelerator, &accelerators_list, link) { + if (match_accelerator(frontend, accelerator)) { +- spin_unlock_irqrestore(&accelerators_lock, flags); +- + accelerator_remove_hooks(accelerator); +- + goto out; + } + } +- spin_unlock_irqrestore(&accelerators_lock, flags); + out: + mutex_unlock(&accelerator_mutex); + } + EXPORT_SYMBOL_GPL(netfront_accelerator_stop); + + +-/* Helper for call_remove and do_suspend */ +-static int do_remove(struct netfront_info *np, struct xenbus_device *dev, +- unsigned long *lock_flags) ++/* ++ * Helper for call_remove and do_suspend ++ * ++ * Must be called with the accelerator mutex held. Takes the ++ * vif_states_lock spinlock. ++ */ ++static int do_remove(struct netfront_info *np, struct xenbus_device *dev) + { + struct netfront_accelerator *accelerator = np->accelerator; +- struct netfront_accel_hooks *hooks; ++ unsigned long flags; + int rc = 0; + + if (np->accel_vif_state.hooks) { +- hooks = np->accel_vif_state.hooks; ++ spin_lock_irqsave(&accelerator->vif_states_lock, flags); + + /* Last chance to get statistics from the accelerator */ +- hooks->get_stats(np->netdev, &np->stats); ++ np->accel_vif_state.hooks->get_stats(np->netdev, &np->stats); + + spin_unlock_irqrestore(&accelerator->vif_states_lock, +- *lock_flags); ++ flags); + + /* + * Try and do the opposite of accelerator_probe_new_vif +@@ -618,20 +606,21 @@ static int do_remove(struct netfront_inf + &np->accel_vif_state); + + rc = accelerator->hooks->remove(dev); +- +- spin_lock_irqsave(&accelerator->vif_states_lock, *lock_flags); + } + + return rc; + } + + ++/* ++ * Must be called with the accelerator mutex held. Takes the ++ * vif_states_lock spinlock ++ */ + static int netfront_remove_accelerator(struct netfront_info *np, + struct xenbus_device *dev) + { + struct netfront_accelerator *accelerator; + struct netfront_accel_vif_state *tmp_vif_state; +- unsigned long flags; + int rc = 0; + + /* Check that we've got a device that was accelerated */ +@@ -640,8 +629,6 @@ static int netfront_remove_accelerator(s + + accelerator = np->accelerator; + +- spin_lock_irqsave(&accelerator->vif_states_lock, flags); +- + list_for_each_entry(tmp_vif_state, &accelerator->vif_states, + link) { + if (tmp_vif_state == &np->accel_vif_state) { +@@ -650,16 +637,18 @@ static int netfront_remove_accelerator(s + } + } + +- rc = do_remove(np, dev, &flags); ++ rc = do_remove(np, dev); + + np->accelerator = NULL; + +- spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); +- + return rc; + } + + ++/* ++ * No lock pre-requisites. Takes the accelerator mutex and the ++ * vif_states_lock spinlock. ++ */ + int netfront_accelerator_call_remove(struct netfront_info *np, + struct xenbus_device *dev) + { +@@ -671,11 +660,14 @@ int netfront_accelerator_call_remove(str + return rc; + } + +- ++ ++/* ++ * No lock pre-requisites. Takes the accelerator mutex and the ++ * vif_states_lock spinlock. ++ */ + int netfront_accelerator_suspend(struct netfront_info *np, + struct xenbus_device *dev) + { +- unsigned long flags; + int rc = 0; + + netfront_accelerator_remove_watch(np); +@@ -690,11 +682,7 @@ int netfront_accelerator_suspend(struct + * Call the remove accelerator hook, but leave the vif_state + * on the accelerator's list in case there is a suspend_cancel. + */ +- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags); +- +- rc = do_remove(np, dev, &flags); +- +- spin_unlock_irqrestore(&np->accelerator->vif_states_lock, flags); ++ rc = do_remove(np, dev); + out: + mutex_unlock(&accelerator_mutex); + return rc; +@@ -713,15 +701,16 @@ int netfront_accelerator_suspend_cancel( + netfront_accelerator_add_watch(np); + return 0; + } +- +- ++ ++ ++/* ++ * No lock pre-requisites. Takes the accelerator mutex ++ */ + void netfront_accelerator_resume(struct netfront_info *np, + struct xenbus_device *dev) + { + struct netfront_accel_vif_state *accel_vif_state = NULL; +- spinlock_t *vif_states_lock; +- unsigned long flags; +- ++ + mutex_lock(&accelerator_mutex); + + /* Check that we've got a device that was accelerated */ +@@ -734,9 +723,6 @@ void netfront_accelerator_resume(struct + if (accel_vif_state->dev == dev) { + BUG_ON(accel_vif_state != &np->accel_vif_state); + +- vif_states_lock = &np->accelerator->vif_states_lock; +- spin_lock_irqsave(vif_states_lock, flags); +- + /* + * Remove it from the accelerator's list so + * state is consistent for probing new vifs +@@ -744,9 +730,7 @@ void netfront_accelerator_resume(struct + */ + list_del(&accel_vif_state->link); + np->accelerator = NULL; +- +- spin_unlock_irqrestore(vif_states_lock, flags); +- ++ + break; + } + } +@@ -757,11 +741,13 @@ void netfront_accelerator_resume(struct + } + + ++/* ++ * No lock pre-requisites. Takes the vif_states_lock spinlock ++ */ + int netfront_check_accelerator_queue_ready(struct net_device *dev, + struct netfront_info *np) + { + struct netfront_accelerator *accelerator; +- struct netfront_accel_hooks *hooks; + int rc = 1; + unsigned long flags; + +@@ -770,8 +756,8 @@ int netfront_check_accelerator_queue_rea + /* Call the check_ready accelerator hook. */ + if (np->accel_vif_state.hooks && accelerator) { + spin_lock_irqsave(&accelerator->vif_states_lock, flags); +- hooks = np->accel_vif_state.hooks; +- if (hooks && np->accelerator == accelerator) ++ if (np->accel_vif_state.hooks && ++ np->accelerator == accelerator) + rc = np->accel_vif_state.hooks->check_ready(dev); + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + } +@@ -780,11 +766,13 @@ int netfront_check_accelerator_queue_rea + } + + ++/* ++ * No lock pre-requisites. Takes the vif_states_lock spinlock ++ */ + void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np, + struct net_device *dev) + { + struct netfront_accelerator *accelerator; +- struct netfront_accel_hooks *hooks; + unsigned long flags; + + accelerator = np->accelerator; +@@ -792,19 +780,21 @@ void netfront_accelerator_call_stop_napi + /* Call the stop_napi_interrupts accelerator hook. */ + if (np->accel_vif_state.hooks && accelerator != NULL) { + spin_lock_irqsave(&accelerator->vif_states_lock, flags); +- hooks = np->accel_vif_state.hooks; +- if (hooks && np->accelerator == accelerator) ++ if (np->accel_vif_state.hooks && ++ np->accelerator == accelerator) + np->accel_vif_state.hooks->stop_napi_irq(dev); + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + } + } + + ++/* ++ * No lock pre-requisites. Takes the vif_states_lock spinlock ++ */ + int netfront_accelerator_call_get_stats(struct netfront_info *np, + struct net_device *dev) + { + struct netfront_accelerator *accelerator; +- struct netfront_accel_hooks *hooks; + unsigned long flags; + int rc = 0; + +@@ -813,8 +803,8 @@ int netfront_accelerator_call_get_stats( + /* Call the get_stats accelerator hook. */ + if (np->accel_vif_state.hooks && accelerator != NULL) { + spin_lock_irqsave(&accelerator->vif_states_lock, flags); +- hooks = np->accel_vif_state.hooks; +- if (hooks && np->accelerator == accelerator) ++ if (np->accel_vif_state.hooks && ++ np->accelerator == accelerator) + rc = np->accel_vif_state.hooks->get_stats(dev, + &np->stats); + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); +--- sle11-2009-04-09.orig/drivers/xen/netfront/netfront.c 2009-04-09 14:41:04.000000000 +0200 ++++ sle11-2009-04-09/drivers/xen/netfront/netfront.c 2009-04-09 14:41:33.000000000 +0200 +@@ -2238,10 +2238,9 @@ static void __exit netif_exit(void) + #ifdef CONFIG_INET + unregister_inetaddr_notifier(¬ifier_inetdev); + #endif ++ xenbus_unregister_driver(&netfront_driver); + + netif_exit_accel(); +- +- return xenbus_unregister_driver(&netfront_driver); + } + module_exit(netif_exit); + diff --git a/src/patches/suse-2.6.27.31/patches.xen/849-sfc-tx-skb-lock.patch b/src/patches/suse-2.6.27.31/patches.xen/849-sfc-tx-skb-lock.patch new file mode 100644 index 000000000..74f6647b6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/849-sfc-tx-skb-lock.patch @@ -0,0 +1,113 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/3a4410c4504e +# HG changeset 849 patch +# User Keir Fraser +# Date 1238497253 -3600 +# Node ID 3a4410c4504ea64f2c1e873df3234938366050ad +# Parent ab1d4fbbe4bf93f203e0c4d62c18bd248e4f1d4a +Subject: sfc_netfront: Only clear tx_skb when ready for netif_wake_queue +(doing otherwise could result in a lost packet) and document use of +locks to protect tx_skb +References: bnc#489721 +Patch-mainline: obsolete + +Signed-off-by: Kieran Mansley +Acked-by: jbeulich@novell.com + +--- sle11-2009-04-09.orig/drivers/xen/sfc_netfront/accel.h 2009-04-09 14:23:18.000000000 +0200 ++++ sle11-2009-04-09/drivers/xen/sfc_netfront/accel.h 2009-04-09 14:41:38.000000000 +0200 +@@ -261,8 +261,10 @@ typedef struct netfront_accel_vnic { + + int poll_enabled; + +- /** A spare slot for a TX packet. This is treated as an extension +- * of the DMA queue. */ ++ /** A spare slot for a TX packet. This is treated as an ++ * extension of the DMA queue. Reads require either ++ * netfront's tx_lock or the vnic tx_lock; writes require both ++ * locks */ + struct sk_buff *tx_skb; + + /** Keep track of fragments of SSR packets */ +--- sle11-2009-04-09.orig/drivers/xen/sfc_netfront/accel_netfront.c 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-04-09/drivers/xen/sfc_netfront/accel_netfront.c 2009-04-09 14:42:13.000000000 +0200 +@@ -65,7 +65,7 @@ static int netfront_accel_netdev_start_x + BUG_ON(vnic->net_dev != net_dev); + DPRINTK("%s stopping queue\n", __FUNCTION__); + +- /* Netfront's lock protects tx_skb */ ++ /* Need netfront's tx_lock and vnic tx_lock to write tx_skb */ + spin_lock_irqsave(&np->tx_lock, flags2); + BUG_ON(vnic->tx_skb != NULL); + vnic->tx_skb = skb; +@@ -183,7 +183,7 @@ static int netfront_accel_check_ready(st + + BUG_ON(vnic == NULL); + +- /* This is protected by netfront's lock */ ++ /* Read of tx_skb is protected by netfront's tx_lock */ + return vnic->tx_skb == NULL; + } + +--- sle11-2009-04-09.orig/drivers/xen/sfc_netfront/accel_vi.c 2009-04-09 14:23:18.000000000 +0200 ++++ sle11-2009-04-09/drivers/xen/sfc_netfront/accel_vi.c 2009-04-09 14:41:38.000000000 +0200 +@@ -980,39 +980,35 @@ static void netfront_accel_vi_not_busy(n + { + struct netfront_info *np = ((struct netfront_info *) + netdev_priv(vnic->net_dev)); +- struct sk_buff *skb; + int handled; + unsigned long flags; +- ++ + /* +- * TODO if we could safely check tx_skb == NULL and return +- * early without taking the lock, that would obviously help +- * performance ++ * We hold the vnic tx_lock which is sufficient to exclude ++ * writes to tx_skb + */ + +- /* Take the netfront lock which protects tx_skb. */ +- spin_lock_irqsave(&np->tx_lock, flags); + if (vnic->tx_skb != NULL) { + DPRINTK("%s trying to send spare buffer\n", __FUNCTION__); + +- skb = vnic->tx_skb; +- vnic->tx_skb = NULL; +- +- spin_unlock_irqrestore(&np->tx_lock, flags); +- +- handled = netfront_accel_vi_tx_post(vnic, skb); ++ handled = netfront_accel_vi_tx_post(vnic, vnic->tx_skb); + +- spin_lock_irqsave(&np->tx_lock, flags); +- + if (handled != NETFRONT_ACCEL_STATUS_BUSY) { + DPRINTK("%s restarting tx\n", __FUNCTION__); ++ ++ /* Need netfront tx_lock and vnic tx_lock to ++ * write tx_skb */ ++ spin_lock_irqsave(&np->tx_lock, flags); ++ ++ vnic->tx_skb = NULL; ++ + if (netfront_check_queue_ready(vnic->net_dev)) { + netif_wake_queue(vnic->net_dev); + NETFRONT_ACCEL_STATS_OP + (vnic->stats.queue_wakes++); + } +- } else { +- vnic->tx_skb = skb; ++ spin_unlock_irqrestore(&np->tx_lock, flags); ++ + } + + /* +@@ -1021,7 +1017,6 @@ static void netfront_accel_vi_not_busy(n + */ + BUG_ON(handled == NETFRONT_ACCEL_STATUS_CANT); + } +- spin_unlock_irqrestore(&np->tx_lock, flags); + } + + diff --git a/src/patches/suse-2.6.27.31/patches.xen/863-blktap-vma-close.patch b/src/patches/suse-2.6.27.31/patches.xen/863-blktap-vma-close.patch new file mode 100644 index 000000000..bb573bb4e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/863-blktap-vma-close.patch @@ -0,0 +1,196 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/464a925d73f1 +# HG changeset 863 patch +# User Keir Fraser +# Date 1239969802 -3600 +# Node ID 464a925d73f141d8ca568026ee2e6635489affa2 +# Parent dfd2adc5874021b52c13d317df1f55b46ec38e3d +Subject: blktap: don't access deallocated data +References: bnc#484210, bnc#485652 +Patch-mainline: obsolete + +Dereferencing filp->private_data->vma in the file_operations.release +actor isn't permitted, as the vma generally has been destroyed by that +time. The kfree()ing of vma->vm_private_data must be done in the +vm_operations.close actor, and the call to zap_page_range() seems +redundant with the caller of that actor altogether. + +Signed-off-by: Jan Beulich + +--- sle11-2009-04-20.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:35:28.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/blktap/blktap.c 2009-04-20 11:35:40.000000000 +0200 +@@ -293,6 +293,10 @@ static inline int OFFSET_TO_SEG(int offs + /****************************************************************** + * BLKTAP VM OPS + */ ++struct tap_vma_priv { ++ tap_blkif_t *info; ++ struct page *map[]; ++}; + + static struct page *blktap_nopage(struct vm_area_struct *vma, + unsigned long address, +@@ -315,7 +319,7 @@ static pte_t blktap_clear_pte(struct vm_ + int offset, seg, usr_idx, pending_idx, mmap_idx; + unsigned long uvstart = vma->vm_start + (RING_PAGES << PAGE_SHIFT); + unsigned long kvaddr; +- struct page **map; ++ struct tap_vma_priv *priv; + struct page *pg; + struct grant_handle_pair *khandle; + struct gnttab_unmap_grant_ref unmap[2]; +@@ -330,12 +334,12 @@ static pte_t blktap_clear_pte(struct vm_ + ptep, is_fullmm); + + info = vma->vm_file->private_data; +- map = vma->vm_private_data; ++ priv = vma->vm_private_data; + + /* TODO Should these be changed to if statements? */ + BUG_ON(!info); + BUG_ON(!info->idx_map); +- BUG_ON(!map); ++ BUG_ON(!priv); + + offset = (int) ((uvaddr - uvstart) >> PAGE_SHIFT); + usr_idx = OFFSET_TO_USR_IDX(offset); +@@ -347,7 +351,7 @@ static pte_t blktap_clear_pte(struct vm_ + kvaddr = idx_to_kaddr(mmap_idx, pending_idx, seg); + pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); + ClearPageReserved(pg); +- map[offset + RING_PAGES] = NULL; ++ priv->map[offset + RING_PAGES] = NULL; + + khandle = &pending_handle(mmap_idx, pending_idx, seg); + +@@ -388,9 +392,20 @@ static pte_t blktap_clear_pte(struct vm_ + return copy; + } + ++static void blktap_vma_close(struct vm_area_struct *vma) ++{ ++ struct tap_vma_priv *priv = vma->vm_private_data; ++ ++ if (priv) { ++ priv->info->vma = NULL; ++ kfree(priv); ++ } ++} ++ + struct vm_operations_struct blktap_vm_ops = { + nopage: blktap_nopage, + zap_pte: blktap_clear_pte, ++ close: blktap_vma_close, + }; + + /****************************************************************** +@@ -609,21 +624,6 @@ static int blktap_release(struct inode * + ClearPageReserved(virt_to_page(info->ufe_ring.sring)); + free_page((unsigned long) info->ufe_ring.sring); + +- /* Clear any active mappings and free foreign map table */ +- if (info->vma) { +- struct mm_struct *mm = info->vma->vm_mm; +- +- down_write(&mm->mmap_sem); +- zap_page_range( +- info->vma, info->vma->vm_start, +- info->vma->vm_end - info->vma->vm_start, NULL); +- up_write(&mm->mmap_sem); +- +- kfree(info->vma->vm_private_data); +- +- info->vma = NULL; +- } +- + if (info->idx_map) { + kfree(info->idx_map); + info->idx_map = NULL; +@@ -662,8 +662,7 @@ static int blktap_release(struct inode * + static int blktap_mmap(struct file *filp, struct vm_area_struct *vma) + { + int size; +- struct page **map; +- int i; ++ struct tap_vma_priv *priv; + tap_blkif_t *info = filp->private_data; + int ret; + +@@ -700,18 +699,16 @@ static int blktap_mmap(struct file *filp + } + + /* Mark this VM as containing foreign pages, and set up mappings. */ +- map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) +- * sizeof(struct page *), +- GFP_KERNEL); +- if (map == NULL) { ++ priv = kzalloc(sizeof(*priv) + ((vma->vm_end - vma->vm_start) ++ >> PAGE_SHIFT) * sizeof(*priv->map), ++ GFP_KERNEL); ++ if (priv == NULL) { + WPRINTK("Couldn't alloc VM_FOREIGN map.\n"); + goto fail; + } ++ priv->info = info; + +- for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++) +- map[i] = NULL; +- +- vma->vm_private_data = map; ++ vma->vm_private_data = priv; + vma->vm_flags |= VM_FOREIGN; + vma->vm_flags |= VM_DONTCOPY; + +@@ -1190,7 +1187,7 @@ static int blktap_read_ufe_ring(tap_blki + for (j = 0; j < pending_req->nr_pages; j++) { + + unsigned long kvaddr, uvaddr; +- struct page **map = info->vma->vm_private_data; ++ struct tap_vma_priv *priv = info->vma->vm_private_data; + struct page *pg; + int offset; + +@@ -1201,7 +1198,7 @@ static int blktap_read_ufe_ring(tap_blki + ClearPageReserved(pg); + offset = (uvaddr - info->vma->vm_start) + >> PAGE_SHIFT; +- map[offset] = NULL; ++ priv->map[offset] = NULL; + } + fast_flush_area(pending_req, pending_idx, usr_idx, info->minor); + info->idx_map[usr_idx] = INVALID_REQ; +@@ -1359,6 +1356,7 @@ static void dispatch_rw_block_io(blkif_t + unsigned int nseg; + int ret, i, nr_sects = 0; + tap_blkif_t *info; ++ struct tap_vma_priv *priv; + blkif_request_t *target; + int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx); + int usr_idx; +@@ -1407,6 +1405,7 @@ static void dispatch_rw_block_io(blkif_t + pending_req->status = BLKIF_RSP_OKAY; + pending_req->nr_pages = nseg; + op = 0; ++ priv = info->vma->vm_private_data; + mm = info->vma->vm_mm; + if (!xen_feature(XENFEAT_auto_translated_physmap)) + down_write(&mm->mmap_sem); +@@ -1490,8 +1489,7 @@ static void dispatch_rw_block_io(blkif_t + >> PAGE_SHIFT)); + offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; + pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); +- ((struct page **)info->vma->vm_private_data)[offset] = +- pg; ++ priv->map[offset] = pg; + } + } else { + for (i = 0; i < nseg; i++) { +@@ -1518,8 +1516,7 @@ static void dispatch_rw_block_io(blkif_t + + offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; + pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); +- ((struct page **)info->vma->vm_private_data)[offset] = +- pg; ++ priv->map[offset] = pg; + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/870-i386-critical-section.patch b/src/patches/suse-2.6.27.31/patches.xen/870-i386-critical-section.patch new file mode 100644 index 000000000..2d7b7f8e4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/870-i386-critical-section.patch @@ -0,0 +1,129 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/9b9454800544 +# HG changeset 870 patch +# User Keir Fraser +# Date 1242292120 -3600 +# Node ID 9b945480054430882b60bb5e5f660822a1c07b70 +# Parent 271d9b9bee40657b1714b2bb62531e989c7b5813 +Subject: i386: hypervisor_callback adjustments +References: bnc#503457 CVE-2009-1758 +Patch-mainline: obsolete + +The missing check of the interrupted code's code selector in +hypervisor_callback() allowed a user mode application to oops (and +perhaps crash) the kernel. + +Further adjustments: +- the 'main' critical region does not include the jmp following the + disabling of interrupts +- the sysexit_[se]crit range checks got broken at some point - the + sysexit ciritcal region is always at higher addresses than the + 'main' + one, yielding the check pointless (but consuming execution time); + since the supervisor mode kernel isn't actively used afaict, I moved + that code into an #ifdef using a hypothetical config option +- the use of a numeric label across more than 300 lines of code always + seemed pretty fragile to me, so the patch replaces this with a local + named label +- streamlined the critical_region_fixup code to eliminate a branch + +Signed-off-by: Jan Beulich + +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32-xen.S 2009-05-15 08:44:13.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/entry_32-xen.S 2009-05-15 08:45:36.000000000 +0200 +@@ -529,8 +529,8 @@ scrit: /**** START OF CRITICAL REGION ** + .previous + 14: __DISABLE_INTERRUPTS + TRACE_IRQS_OFF +- jmp 11f + ecrit: /**** END OF CRITICAL REGION ****/ ++ jmp .Ldo_upcall + + CFI_RESTORE_STATE + hypervisor_iret: +@@ -788,17 +788,23 @@ ENTRY(hypervisor_callback) + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL ++ testb $2,CS(%esp) + movl EIP(%esp),%eax ++ jnz .Ldo_upcall + cmpl $scrit,%eax +- jb 11f ++ jb 0f + cmpl $ecrit,%eax + jb critical_region_fixup ++0: ++#ifdef CONFIG_XEN_SUPERVISOR_MODE_KERNEL + cmpl $sysexit_scrit,%eax +- jb 11f ++ jb .Ldo_upcall + cmpl $sysexit_ecrit,%eax +- ja 11f ++ ja .Ldo_upcall + addl $OLDESP,%esp # Remove eflags...ebx from stack frame. +-11: push %esp ++#endif ++.Ldo_upcall: ++ push %esp + CFI_ADJUST_CFA_OFFSET 4 + call evtchn_do_upcall + add $4,%esp +@@ -814,39 +820,35 @@ ENTRY(hypervisor_callback) + # provides the number of bytes which have already been popped from the + # interrupted stack frame. + critical_region_fixup: +- movzbl critical_fixup_table-scrit(%eax),%ecx # %eax contains num bytes popped +- cmpb $0xff,%cl # 0xff => vcpu_info critical region +- jne 15f +- xorl %ecx,%ecx +-15: leal (%esp,%ecx),%esi # %esi points at end of src region ++ movsbl critical_fixup_table-scrit(%eax),%ecx # %ecx contains num slots popped ++ testl %ecx,%ecx ++ leal (%esp,%ecx,4),%esi # %esi points at end of src region + leal OLDESP(%esp),%edi # %edi points at end of dst region +- shrl $2,%ecx # convert words to bytes +- je 17f # skip loop if nothing to copy ++ jle 17f # skip loop if nothing to copy + 16: subl $4,%esi # pre-decrementing copy loop + subl $4,%edi + movl (%esi),%eax + movl %eax,(%edi) + loop 16b + 17: movl %edi,%esp # final %edi is top of merged stack +- jmp 11b ++ jmp .Ldo_upcall + + .section .rodata,"a" + critical_fixup_table: +- .byte 0xff,0xff,0xff # testb $0xff,(%esi) = __TEST_PENDING +- .byte 0xff,0xff # jnz 14f +- .byte 0x00 # pop %ebx +- .byte 0x04 # pop %ecx +- .byte 0x08 # pop %edx +- .byte 0x0c # pop %esi +- .byte 0x10 # pop %edi +- .byte 0x14 # pop %ebp +- .byte 0x18 # pop %eax +- .byte 0x1c # pop %ds +- .byte 0x20 # pop %es +- .byte 0x24,0x24,0x24 # add $4,%esp +- .byte 0x28 # iret +- .byte 0xff,0xff,0xff,0xff # movb $1,1(%esi) +- .byte 0x00,0x00 # jmp 11b ++ .byte -1,-1,-1 # testb $0xff,(%esi) = __TEST_PENDING ++ .byte -1,-1 # jnz 14f ++ .byte 0 # pop %ebx ++ .byte 1 # pop %ecx ++ .byte 2 # pop %edx ++ .byte 3 # pop %esi ++ .byte 4 # pop %edi ++ .byte 5 # pop %ebp ++ .byte 6 # pop %eax ++ .byte 7 # pop %ds ++ .byte 8 # pop %es ++ .byte 9,9,9 # add $4,%esp ++ .byte 10 # iret ++ .byte -1,-1,-1,-1 # movb $1,1(%esi) = __DISABLE_INTERRUPTS + .previous + + # Hypervisor uses this for application faults while it executes. diff --git a/src/patches/suse-2.6.27.31/patches.xen/897-balloon-keep-trying.patch b/src/patches/suse-2.6.27.31/patches.xen/897-balloon-keep-trying.patch new file mode 100644 index 000000000..304745f59 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/897-balloon-keep-trying.patch @@ -0,0 +1,160 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/329ea0ccb344 +# HG changeset patch +# User Keir Fraser +# Date 1244206880 -3600 +# Node ID 329ea0ccb344c636e918cc3cd2677c24b03af5bd +# Parent f59c5daed527f3a7ddf1270480ec63028c206f31 +Subject: balloon: try harder to balloon up under memory pressure. +Patch-mainline: obsolete + +Currently if the balloon driver is unable to increase the guest's +reservation it assumes the failure was due to reaching its full +allocation, gives up on the ballooning operation and records the limit +it reached as the "hard limit". The driver will not try again until +the target is set again (even to the same value). + +However it is possible that ballooning has in fact failed due to +memory pressure in the host and therefore it is desirable to keep +attempting to reach the target in case memory becomes available. The +most likely scenario is that some guests are ballooning down while +others are ballooning up and therefore there is temporary memory +pressure while things stabilise. You would not expect a well behaved +toolstack to ask a domain to balloon to more than its allocation nor +would you expect it to deliberately over-commit memory by setting +balloon targets which exceed the total host memory. + +This patch drops the concept of a hard limit and causes the balloon +driver to retry increasing the reservation on a timer in the same +manner as when decreasing the reservation. + +Also if we partially succeed in increasing the reservation +(i.e. receive less pages than we asked for) then we may as well keep +those pages rather than returning them to Xen. + +Signed-off-by: Ian Campbell +Acked-by: jbeulich@novell.com + +--- sle11-2009-06-29.orig/drivers/xen/balloon/balloon.c 2008-11-25 13:31:07.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/balloon/balloon.c 2009-06-29 15:24:00.000000000 +0200 +@@ -188,7 +188,7 @@ static void balloon_alarm(unsigned long + + static unsigned long current_target(void) + { +- unsigned long target = min(bs.target_pages, bs.hard_limit); ++ unsigned long target = bs.target_pages; + if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high)) + target = bs.current_pages + bs.balloon_low + bs.balloon_high; + return target; +@@ -255,26 +255,12 @@ static int increase_reservation(unsigned + } + + set_xen_guest_handle(reservation.extent_start, frame_list); +- reservation.nr_extents = nr_pages; +- rc = HYPERVISOR_memory_op( +- XENMEM_populate_physmap, &reservation); +- if (rc < nr_pages) { +- if (rc > 0) { +- int ret; +- +- /* We hit the Xen hard limit: reprobe. */ +- reservation.nr_extents = rc; +- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, +- &reservation); +- BUG_ON(ret != rc); +- } +- if (rc >= 0) +- bs.hard_limit = (bs.current_pages + rc - +- bs.driver_pages); ++ reservation.nr_extents = nr_pages; ++ rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); ++ if (rc < 0) + goto out; +- } + +- for (i = 0; i < nr_pages; i++) { ++ for (i = 0; i < rc; i++) { + page = balloon_retrieve(); + BUG_ON(page == NULL); + +@@ -302,13 +288,13 @@ static int increase_reservation(unsigned + balloon_free_page(page); + } + +- bs.current_pages += nr_pages; ++ bs.current_pages += rc; + totalram_pages = bs.current_pages; + + out: + balloon_unlock(flags); + +- return 0; ++ return rc < 0 ? rc : rc != nr_pages; + } + + static int decrease_reservation(unsigned long nr_pages) +@@ -420,7 +406,6 @@ static void balloon_process(void *unused + void balloon_set_new_target(unsigned long target) + { + /* No need for lock. Not read-modify-write updates. */ +- bs.hard_limit = ~0UL; + bs.target_pages = max(target, minimum_target()); + schedule_work(&balloon_worker); + } +@@ -498,17 +483,11 @@ static int balloon_read(char *page, char + "Requested target: %8lu kB\n" + "Low-mem balloon: %8lu kB\n" + "High-mem balloon: %8lu kB\n" +- "Driver pages: %8lu kB\n" +- "Xen hard limit: ", ++ "Driver pages: %8lu kB\n", + PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages), + PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high), + PAGES2KB(bs.driver_pages)); + +- if (bs.hard_limit != ~0UL) +- len += sprintf(page + len, "%8lu kB\n", +- PAGES2KB(bs.hard_limit)); +- else +- len += sprintf(page + len, " ??? kB\n"); + + *eof = 1; + return len; +@@ -539,7 +518,6 @@ static int __init balloon_init(void) + bs.balloon_low = 0; + bs.balloon_high = 0; + bs.driver_pages = 0UL; +- bs.hard_limit = ~0UL; + + init_timer(&balloon_timer); + balloon_timer.data = 0; +--- sle11-2009-06-29.orig/drivers/xen/balloon/common.h 2009-06-29 15:14:51.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/balloon/common.h 2009-06-29 15:24:00.000000000 +0200 +@@ -35,8 +35,6 @@ struct balloon_stats { + /* We aim for 'current allocation' == 'target allocation'. */ + unsigned long current_pages; + unsigned long target_pages; +- /* We may hit the hard limit in Xen. If we do then we remember it. */ +- unsigned long hard_limit; + /* + * Drivers may alter the memory reservation independently, but they + * must inform the balloon driver so we avoid hitting the hard limit. +--- sle11-2009-06-29.orig/drivers/xen/balloon/sysfs.c 2008-11-25 13:31:07.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/balloon/sysfs.c 2009-06-29 15:24:00.000000000 +0200 +@@ -53,9 +53,6 @@ + BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages)); + BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low)); + BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high)); +-BALLOON_SHOW(hard_limit_kb, +- (bs.hard_limit!=~0UL) ? "%lu\n" : "???\n", +- (bs.hard_limit!=~0UL) ? PAGES2KB(bs.hard_limit) : 0); + BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages)); + + static ssize_t show_target_kb(struct sys_device *dev, char *buf) +@@ -96,7 +93,6 @@ static struct attribute *balloon_info_at + &attr_current_kb.attr, + &attr_low_kb.attr, + &attr_high_kb.attr, +- &attr_hard_limit_kb.attr, + &attr_driver_kb.attr, + NULL + }; diff --git a/src/patches/suse-2.6.27.31/patches.xen/899-kbuild-extmod.patch b/src/patches/suse-2.6.27.31/patches.xen/899-kbuild-extmod.patch new file mode 100644 index 000000000..d5b68b3ae --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/899-kbuild-extmod.patch @@ -0,0 +1,35 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/214ff2a7c990 +# HG changeset patch +# User Keir Fraser +# Date 1245146770 -3600 +# Node ID 214ff2a7c9900f5d8bac55a569224a0029173a0f +# Parent ca12928cdafe3fcb024520c4fe2479448f2c5f46 +Subject: Fix Makefile.xen generation when building external modules +Patch-mainline: obsolete + +Otherwise, the file will be (attempted to be) put in the (possibly +read-only) source tree. + +Signed-off-by: Jan Beulich + +--- sle11-2009-06-29.orig/scripts/Makefile.build 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/scripts/Makefile.build 2009-06-29 15:27:22.000000000 +0200 +@@ -74,7 +74,8 @@ $(warning kbuild: Makefile.build is incl + endif + + ifeq ($(CONFIG_XEN),y) +-$(objtree)/scripts/Makefile.xen: $(srctree)/scripts/Makefile.xen.awk $(srctree)/scripts/Makefile.build ++Makefile.xen := $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD),$(objtree)/scripts)/Makefile.xen ++$(Makefile.xen): $(srctree)/scripts/Makefile.xen.awk $(srctree)/scripts/Makefile.build + @echo ' Updating $@' + $(if $(shell echo a | $(AWK) '{ print gensub(/a/, "AA", "g"); }'),\ + ,$(error 'Your awk program does not define gensub. Use gawk or another awk with gensub')) +@@ -84,7 +85,7 @@ xen-src-single-used-m := $(patsubst $(sr + xen-single-used-m := $(xen-src-single-used-m:-xen.c=.o) + single-used-m := $(filter-out $(xen-single-used-m),$(single-used-m)) + +--include $(objtree)/scripts/Makefile.xen ++-include $(Makefile.xen) + endif + + # =========================================================================== diff --git a/src/patches/suse-2.6.27.31/patches.xen/914-dynamic-Cx-change.patch b/src/patches/suse-2.6.27.31/patches.xen/914-dynamic-Cx-change.patch new file mode 100644 index 000000000..dd004db75 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/914-dynamic-Cx-change.patch @@ -0,0 +1,24 @@ +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/c27fe3158f21 +# HG changeset patch +# User Keir Fraser +# Date 1246890052 -3600 +# Node ID c27fe3158f211e6b331827084916fe6d464910a2 +# Parent b086278a440602f2509380d0f718343e910483eb +Subject: x86: Handle dynamic Cx state changes correctly. +Patch-mainline: obsolete + +Signed-off-by: Keir Fraser +Acked-by: jbeulich@novell.com + +--- sle11-2009-07-31.orig/arch/x86/kernel/acpi/processor_extcntl_xen.c 2009-07-31 14:49:20.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/kernel/acpi/processor_extcntl_xen.c 2009-07-31 14:52:14.000000000 +0200 +@@ -44,9 +44,6 @@ static int xen_cx_notifier(struct acpi_p + struct xen_processor_cx *data, *buf; + struct acpi_processor_cx *cx; + +- if (action == PROCESSOR_PM_CHANGE) +- return -EINVAL; +- + /* Convert to Xen defined structure and hypercall */ + buf = kzalloc(pr->power.count * sizeof(struct xen_processor_cx), + GFP_KERNEL); diff --git a/src/patches/suse-2.6.27.31/patches.xen/add-console-use-vt b/src/patches/suse-2.6.27.31/patches.xen/add-console-use-vt new file mode 100644 index 000000000..2fa3e9164 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/add-console-use-vt @@ -0,0 +1,58 @@ +Subject: add console_use_vt +From: kraxel@suse.de +Patch-mainline: no + +$subject says all + +--- + drivers/char/tty_io.c | 7 ++++++- + include/linux/console.h | 1 + + 2 files changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/char/tty_io.c ++++ b/drivers/char/tty_io.c +@@ -136,6 +136,8 @@ LIST_HEAD(tty_drivers); /* linked list + DEFINE_MUTEX(tty_mutex); + EXPORT_SYMBOL(tty_mutex); + ++int console_use_vt = 1; ++ + #ifdef CONFIG_UNIX98_PTYS + extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ + static int ptmx_open(struct inode *, struct file *); +@@ -2200,7 +2202,7 @@ retry_open: + goto got_driver; + } + #ifdef CONFIG_VT +- if (device == MKDEV(TTY_MAJOR, 0)) { ++ if (console_use_vt && device == MKDEV(TTY_MAJOR, 0)) { + extern struct tty_driver *console_driver; + driver = console_driver; + index = fg_console; +@@ -3729,6 +3731,8 @@ static int __init tty_init(void) + #endif + + #ifdef CONFIG_VT ++ if (!console_use_vt) ++ goto out_vt; + cdev_init(&vc0_cdev, &console_fops); + if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || + register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) +@@ -3736,6 +3740,7 @@ static int __init tty_init(void) + device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + + vty_init(); ++ out_vt: + #endif + return 0; + } +--- a/include/linux/console.h ++++ b/include/linux/console.h +@@ -63,6 +63,7 @@ extern const struct consw dummy_con; /* + extern const struct consw vga_con; /* VGA text console */ + extern const struct consw newport_con; /* SGI Newport console */ + extern const struct consw prom_con; /* SPARC PROM console */ ++extern int console_use_vt; + + int con_is_bound(const struct consw *csw); + int register_con_driver(const struct consw *csw, int first, int last); diff --git a/src/patches/suse-2.6.27.31/patches.xen/gso-size-check.patch b/src/patches/suse-2.6.27.31/patches.xen/gso-size-check.patch new file mode 100644 index 000000000..9fe2bce18 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/gso-size-check.patch @@ -0,0 +1,71 @@ +From: http://patchwork.ozlabs.org/patch/18346/ +Subject: gso: Ensure that the packet is long enough +See also http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/d490aa798cc4 + +When we get a GSO packet from an untrusted source, we need to +ensure that it is sufficiently long so that we don't end up +crashing. + +Based on discovery and patch by Ian Campbell. + +Signed-off-by: Herbert Xu +Tested-by: Ian Campbell +Acked-by: jbeulich@novell.com + +--- + net/ipv4/tcp.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -2390,7 +2390,7 @@ struct sk_buff *tcp_tso_segment(struct s + unsigned int seq; + __be32 delta; + unsigned int oldlen; +- unsigned int len; ++ unsigned int mss; + + if (!pskb_may_pull(skb, sizeof(*th))) + goto out; +@@ -2406,10 +2406,13 @@ struct sk_buff *tcp_tso_segment(struct s + oldlen = (u16)~skb->len; + __skb_pull(skb, thlen); + ++ mss = skb_shinfo(skb)->gso_size; ++ if (unlikely(skb->len <= mss)) ++ goto out; ++ + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + int type = skb_shinfo(skb)->gso_type; +- int mss; + + if (unlikely(type & + ~(SKB_GSO_TCPV4 | +@@ -2420,7 +2423,6 @@ struct sk_buff *tcp_tso_segment(struct s + !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) + goto out; + +- mss = skb_shinfo(skb)->gso_size; + skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); + + segs = NULL; +@@ -2431,8 +2433,7 @@ struct sk_buff *tcp_tso_segment(struct s + if (IS_ERR(segs)) + goto out; + +- len = skb_shinfo(skb)->gso_size; +- delta = htonl(oldlen + (thlen + len)); ++ delta = htonl(oldlen + (thlen + mss)); + + skb = segs; + th = tcp_hdr(skb); +@@ -2448,7 +2449,7 @@ struct sk_buff *tcp_tso_segment(struct s + csum_fold(csum_partial(skb_transport_header(skb), + thlen, skb->csum)); + +- seq += len; ++ seq += mss; + skb = skb->next; + th = tcp_hdr(skb); + diff --git a/src/patches/suse-2.6.27.31/patches.xen/ipv6-no-autoconf b/src/patches/suse-2.6.27.31/patches.xen/ipv6-no-autoconf new file mode 100644 index 000000000..10ff1df66 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/ipv6-no-autoconf @@ -0,0 +1,39 @@ +From: Olaf Kirch +Subject: Allow to bring up network interface w/o ipv6 autoconf +References: 161888 + +When bringing up a xen bridge device, it will always be configured to +use a MAC address of ff:ff:ff:ff:ff:fe. This greatly confuses IPv6 DAD, +which starts logging lots and lots of useless messages to syslog. + +We really want to disable IPv6 on these interfaces, and there doesn't +seem to be a reliable way to do this without bringing the interface +up first (and triggering IPv6 autoconf). + +This patch makes autoconf (DAD and router discovery) depend on the +interface's ability to do multicast. Turning off multicast for an +interface before bringing it up will suppress autoconfiguration. + + net/ipv6/addrconf.c | 2 ++ + 1 files changed, 2 insertions(+) + +Index: head-2008-09-25/net/ipv6/addrconf.c +=================================================================== +--- head-2008-09-25.orig/net/ipv6/addrconf.c 2008-09-25 13:56:12.000000000 +0200 ++++ head-2008-09-25/net/ipv6/addrconf.c 2008-09-25 14:15:19.000000000 +0200 +@@ -2781,6 +2781,7 @@ static void addrconf_dad_start(struct in + spin_lock_bh(&ifp->lock); + + if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || ++ !(dev->flags&IFF_MULTICAST) || + idev->cnf.accept_dad < 1 || + !(ifp->flags&IFA_F_TENTATIVE) || + ifp->flags & IFA_F_NODAD) { +@@ -2878,6 +2879,7 @@ static void addrconf_dad_completed(struc + if (ifp->idev->cnf.forwarding == 0 && + ifp->idev->cnf.rtr_solicits > 0 && + (dev->flags&IFF_LOOPBACK) == 0 && ++ (dev->flags & IFF_MULTICAST) && + (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { + /* + * If a host as already performed a random delay diff --git a/src/patches/suse-2.6.27.31/patches.xen/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch b/src/patches/suse-2.6.27.31/patches.xen/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch new file mode 100644 index 000000000..1439e0349 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch @@ -0,0 +1,178 @@ +Subject: kexec: Move asm segment handling code to the assembly file (i386) +From: http://xenbits.xensource.com/xen-unstable.hg (tip 13816) +Patch-mainline: obsolete + +This patch moves the idt, gdt, and segment handling code from machine_kexec.c +to relocate_kernel.S. The main reason behind this move is to avoid code +duplication in the Xen hypervisor. With this patch all code required to kexec +is put on the control page. + +On top of that this patch also counts as a cleanup - I think it is much +nicer to write assembly directly in assembly files than wrap inline assembly +in C functions for no apparent reason. + +Signed-off-by: Magnus Damm +Acked-by: jbeulich@novell.com +--- + + Applies to 2.6.19-rc1. + + machine_kexec.c | 59 ----------------------------------------------------- + relocate_kernel.S | 58 +++++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 53 insertions(+), 64 deletions(-) + +Index: head-2008-11-17/arch/x86/kernel/machine_kexec_32.c +=================================================================== +--- head-2008-11-17.orig/arch/x86/kernel/machine_kexec_32.c 2008-11-17 13:15:56.000000000 +0100 ++++ head-2008-11-17/arch/x86/kernel/machine_kexec_32.c 2008-11-17 13:38:03.000000000 +0100 +@@ -34,48 +34,6 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED + static u32 kexec_pte0[1024] PAGE_ALIGNED; + static u32 kexec_pte1[1024] PAGE_ALIGNED; + +-static void set_idt(void *newidt, __u16 limit) +-{ +- struct desc_ptr curidt; +- +- /* ia32 supports unaliged loads & stores */ +- curidt.size = limit; +- curidt.address = (unsigned long)newidt; +- +- load_idt(&curidt); +-} +- +- +-static void set_gdt(void *newgdt, __u16 limit) +-{ +- struct desc_ptr curgdt; +- +- /* ia32 supports unaligned loads & stores */ +- curgdt.size = limit; +- curgdt.address = (unsigned long)newgdt; +- +- load_gdt(&curgdt); +-} +- +-static void load_segments(void) +-{ +-#define __STR(X) #X +-#define STR(X) __STR(X) +- +- __asm__ __volatile__ ( +- "\tljmp $"STR(__KERNEL_CS)",$1f\n" +- "\t1:\n" +- "\tmovl $"STR(__KERNEL_DS)",%%eax\n" +- "\tmovl %%eax,%%ds\n" +- "\tmovl %%eax,%%es\n" +- "\tmovl %%eax,%%fs\n" +- "\tmovl %%eax,%%gs\n" +- "\tmovl %%eax,%%ss\n" +- ::: "eax", "memory"); +-#undef STR +-#undef __STR +-} +- + /* + * A architecture hook called to validate the + * proposed image and prepare the control pages +@@ -167,23 +125,6 @@ void machine_kexec(struct kimage *image) + page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page) + << PAGE_SHIFT); + +- /* The segment registers are funny things, they have both a +- * visible and an invisible part. Whenever the visible part is +- * set to a specific selector, the invisible part is loaded +- * with from a table in memory. At no other time is the +- * descriptor table in memory accessed. +- * +- * I take advantage of this here by force loading the +- * segments, before I zap the gdt with an invalid value. +- */ +- load_segments(); +- /* The gdt & idt are now invalid. +- * If you want to load them you must set up your own idt & gdt. +- */ +- set_gdt(phys_to_virt(0),0); +- set_idt(phys_to_virt(0),0); +- +- /* now call it */ + image->start = relocate_kernel_ptr((unsigned long)image->head, + (unsigned long)page_list, + image->start, cpu_has_pae, +Index: head-2008-11-17/arch/x86/kernel/relocate_kernel_32.S +=================================================================== +--- head-2008-11-17.orig/arch/x86/kernel/relocate_kernel_32.S 2008-11-17 13:15:56.000000000 +0100 ++++ head-2008-11-17/arch/x86/kernel/relocate_kernel_32.S 2008-11-17 13:38:03.000000000 +0100 +@@ -199,14 +199,45 @@ relocate_new_kernel: + movl PTR(PA_PGD)(%ebp), %eax + movl %eax, %cr3 + ++ /* setup idt */ ++ movl %edi, %eax ++ addl $(idt_48 - relocate_kernel), %eax ++ lidtl (%eax) ++ ++ /* setup gdt */ ++ movl %edi, %eax ++ addl $(gdt - relocate_kernel), %eax ++ movl %edi, %esi ++ addl $((gdt_48 - relocate_kernel) + 2), %esi ++ movl %eax, (%esi) ++ ++ movl %edi, %eax ++ addl $(gdt_48 - relocate_kernel), %eax ++ lgdtl (%eax) ++ ++ /* setup data segment registers */ ++ mov $(gdt_ds - gdt), %eax ++ mov %eax, %ds ++ mov %eax, %es ++ mov %eax, %fs ++ mov %eax, %gs ++ mov %eax, %ss ++ + /* setup a new stack at the end of the physical control page */ + lea PAGE_SIZE(%edi), %esp + +- /* jump to identity mapped page */ +- movl %edi, %eax +- addl $(identity_mapped - relocate_kernel), %eax +- pushl %eax +- ret ++ /* load new code segment and jump to identity mapped page */ ++ movl %edi, %esi ++ xorl %eax, %eax ++ pushl %eax ++ pushl %esi ++ pushl %eax ++ movl $(gdt_cs - gdt), %eax ++ pushl %eax ++ movl %edi, %eax ++ addl $(identity_mapped - relocate_kernel),%eax ++ pushl %eax ++ iretl + + identity_mapped: + /* store the start address on the stack */ +@@ -378,5 +409,22 @@ swap_pages: + popl %ebp + ret + ++ .align 16 ++gdt: ++ .quad 0x0000000000000000 /* NULL descriptor */ ++gdt_cs: ++ .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ ++gdt_ds: ++ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ ++gdt_end: ++ ++gdt_48: ++ .word gdt_end - gdt - 1 /* limit */ ++ .long 0 /* base - filled in by code above */ ++ ++idt_48: ++ .word 0 /* limit */ ++ .long 0 /* base */ ++ + .globl kexec_control_code_size + .set kexec_control_code_size, . - relocate_kernel diff --git a/src/patches/suse-2.6.27.31/patches.xen/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch b/src/patches/suse-2.6.27.31/patches.xen/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch new file mode 100644 index 000000000..5235a0399 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch @@ -0,0 +1,168 @@ +Subject: kexec: Move asm segment handling code to the assembly file (x86_64) +From: http://xenbits.xensource.com/xen-unstable.hg (tip 13816) +Patch-mainline: obsolete + +This patch moves the idt, gdt, and segment handling code from machine_kexec.c +to relocate_kernel.S. The main reason behind this move is to avoid code +duplication in the Xen hypervisor. With this patch all code required to kexec +is put on the control page. + +On top of that this patch also counts as a cleanup - I think it is much +nicer to write assembly directly in assembly files than wrap inline assembly +in C functions for no apparent reason. + +Signed-off-by: Magnus Damm +Acked-by: jbeulich@novell.com +--- + + Applies to 2.6.19-rc1. + + machine_kexec.c | 58 ----------------------------------------------------- + relocate_kernel.S | 50 +++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 45 insertions(+), 63 deletions(-) + +Index: head-2008-08-18/arch/x86/kernel/machine_kexec_64.c +=================================================================== +--- head-2008-08-18.orig/arch/x86/kernel/machine_kexec_64.c 2008-08-18 09:05:04.000000000 +0200 ++++ head-2008-08-18/arch/x86/kernel/machine_kexec_64.c 2008-08-18 10:13:08.000000000 +0200 +@@ -115,47 +115,6 @@ static int init_pgtable(struct kimage *i + return init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT); + } + +-static void set_idt(void *newidt, u16 limit) +-{ +- struct desc_ptr curidt; +- +- /* x86-64 supports unaliged loads & stores */ +- curidt.size = limit; +- curidt.address = (unsigned long)newidt; +- +- __asm__ __volatile__ ( +- "lidtq %0\n" +- : : "m" (curidt) +- ); +-}; +- +- +-static void set_gdt(void *newgdt, u16 limit) +-{ +- struct desc_ptr curgdt; +- +- /* x86-64 supports unaligned loads & stores */ +- curgdt.size = limit; +- curgdt.address = (unsigned long)newgdt; +- +- __asm__ __volatile__ ( +- "lgdtq %0\n" +- : : "m" (curgdt) +- ); +-}; +- +-static void load_segments(void) +-{ +- __asm__ __volatile__ ( +- "\tmovl %0,%%ds\n" +- "\tmovl %0,%%es\n" +- "\tmovl %0,%%ss\n" +- "\tmovl %0,%%fs\n" +- "\tmovl %0,%%gs\n" +- : : "a" (__KERNEL_DS) : "memory" +- ); +-} +- + int machine_kexec_prepare(struct kimage *image) + { + unsigned long start_pgtable; +@@ -214,23 +173,6 @@ void machine_kexec(struct kimage *image) + page_list[PA_TABLE_PAGE] = + (unsigned long)__pa(page_address(image->control_code_page)); + +- /* The segment registers are funny things, they have both a +- * visible and an invisible part. Whenever the visible part is +- * set to a specific selector, the invisible part is loaded +- * with from a table in memory. At no other time is the +- * descriptor table in memory accessed. +- * +- * I take advantage of this here by force loading the +- * segments, before I zap the gdt with an invalid value. +- */ +- load_segments(); +- /* The gdt & idt are now invalid. +- * If you want to load them you must set up your own idt & gdt. +- */ +- set_gdt(phys_to_virt(0),0); +- set_idt(phys_to_virt(0),0); +- +- /* now call it */ + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start); + } +Index: head-2008-08-18/arch/x86/kernel/relocate_kernel_64.S +=================================================================== +--- head-2008-08-18.orig/arch/x86/kernel/relocate_kernel_64.S 2008-07-13 23:51:29.000000000 +0200 ++++ head-2008-08-18/arch/x86/kernel/relocate_kernel_64.S 2008-08-18 10:13:08.000000000 +0200 +@@ -160,13 +160,39 @@ relocate_new_kernel: + movq PTR(PA_PGD)(%rsi), %r9 + movq %r9, %cr3 + ++ /* setup idt */ ++ movq %r8, %rax ++ addq $(idt_80 - relocate_kernel), %rax ++ lidtq (%rax) ++ ++ /* setup gdt */ ++ movq %r8, %rax ++ addq $(gdt - relocate_kernel), %rax ++ movq %r8, %r9 ++ addq $((gdt_80 - relocate_kernel) + 2), %r9 ++ movq %rax, (%r9) ++ ++ movq %r8, %rax ++ addq $(gdt_80 - relocate_kernel), %rax ++ lgdtq (%rax) ++ ++ /* setup data segment registers */ ++ xorl %eax, %eax ++ movl %eax, %ds ++ movl %eax, %es ++ movl %eax, %fs ++ movl %eax, %gs ++ movl %eax, %ss ++ + /* setup a new stack at the end of the physical control page */ + lea PAGE_SIZE(%r8), %rsp + +- /* jump to identity mapped page */ +- addq $(identity_mapped - relocate_kernel), %r8 +- pushq %r8 +- ret ++ /* load new code segment and jump to identity mapped page */ ++ movq %r8, %rax ++ addq $(identity_mapped - relocate_kernel), %rax ++ pushq $(gdt_cs - gdt) ++ pushq %rax ++ lretq + + identity_mapped: + /* store the start address on the stack */ +@@ -262,5 +288,19 @@ identity_mapped: + xorq %r13, %r13 + xorq %r14, %r14 + xorq %r15, %r15 +- + ret ++ ++ .align 16 ++gdt: ++ .quad 0x0000000000000000 /* NULL descriptor */ ++gdt_cs: ++ .quad 0x00af9a000000ffff ++gdt_end: ++ ++gdt_80: ++ .word gdt_end - gdt - 1 /* limit */ ++ .quad 0 /* base - filled in by code above */ ++ ++idt_80: ++ .word 0 /* limit */ ++ .quad 0 /* base */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/pci-reassign-resources b/src/patches/suse-2.6.27.31/patches.xen/pci-reassign-resources new file mode 100644 index 000000000..1fc6cc959 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/pci-reassign-resources @@ -0,0 +1,310 @@ +Subject: xen/dom0: Reassign memory resources to device for pci passthrough +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 852:571229e265e2) +Patch-mainline: obsolete +Acked-by: jbeulich@novell.com + +--- sle11-2009-04-09.orig/drivers/pci/Kconfig 2009-04-09 14:29:05.000000000 +0200 ++++ sle11-2009-04-09/drivers/pci/Kconfig 2008-11-10 11:49:15.000000000 +0100 +@@ -21,6 +21,9 @@ config PCI_MSI + + If you don't know what to do here, say N. + ++config PCI_REASSIGN ++ bool ++ + config PCI_LEGACY + bool "Enable deprecated pci_find_* API" + depends on PCI +--- sle11-2009-04-09.orig/drivers/pci/Makefile 2009-04-09 14:29:05.000000000 +0200 ++++ sle11-2009-04-09/drivers/pci/Makefile 2008-10-21 13:09:46.000000000 +0200 +@@ -4,6 +4,7 @@ + + obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \ + pci-driver.o search.o pci-sysfs.o rom.o setup-res.o ++obj-$(CONFIG_PCI_REASSIGN) += reassigndev.o + obj-$(CONFIG_PROC_FS) += proc.o + + # Build PCI Express stuff if needed +--- sle11-2009-04-09.orig/drivers/pci/pci.h 2009-04-09 14:29:05.000000000 +0200 ++++ sle11-2009-04-09/drivers/pci/pci.h 2008-10-21 13:09:01.000000000 +0200 +@@ -145,3 +145,9 @@ struct pci_slot_attribute { + }; + #define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr) + ++#ifdef CONFIG_PCI_REASSIGN ++extern int is_reassigndev(struct pci_dev *dev); ++extern void pci_disable_bridge_window(struct pci_dev *dev); ++#else ++#define is_reassigndev(dev) 0 ++#endif +--- sle11-2009-04-09.orig/drivers/pci/quirks.c 2009-04-09 14:29:05.000000000 +0200 ++++ sle11-2009-04-09/drivers/pci/quirks.c 2009-04-09 14:34:32.000000000 +0200 +@@ -25,6 +25,57 @@ + #include + #include "pci.h" + ++#ifdef CONFIG_PCI_REASSIGN ++/* ++ * This quirk function disables memory decoding and releases memory ++ * resources which is specified by kernel's boot parameter 'reassigndev'. ++ * Later on, kernel will assign page-aligned memory resource back ++ * to the device. ++ */ ++static void __devinit quirk_release_resources(struct pci_dev *dev) ++{ ++ int i; ++ struct resource *r; ++ u16 command; ++ ++ if (is_reassigndev(dev)) { ++ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL && ++ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { ++ /* PCI Host Bridge isn't a target device */ ++ return; ++ } ++ printk(KERN_INFO ++ "PCI: Disable memory decoding and release memory resources [%s].\n", ++ pci_name(dev)); ++ pci_read_config_word(dev, PCI_COMMAND, &command); ++ command &= ~PCI_COMMAND_MEMORY; ++ pci_write_config_word(dev, PCI_COMMAND, command); ++ ++ for (i=0; i < PCI_NUM_RESOURCES; i++) { ++ r = &dev->resource[i]; ++ if (!(r->flags & IORESOURCE_MEM)) ++ continue; ++ ++ r->end = r->end - r->start; ++ r->start = 0; ++ ++ if (i < PCI_BRIDGE_RESOURCES) { ++ pci_update_resource(dev, r, i); ++ } ++ } ++ /* need to disable bridge's resource window, ++ * to make kernel enable to reassign new resource ++ * window later on. ++ */ ++ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && ++ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { ++ pci_disable_bridge_window(dev); ++ } ++ } ++} ++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_release_resources); ++#endif ++ + /* The Mellanox Tavor device gives false positive parity errors + * Mark this device with a broken_parity_status, to allow + * PCI scanning code to "skip" this now blacklisted device. +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-04-09/drivers/pci/reassigndev.c 2008-10-21 13:13:38.000000000 +0200 +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (c) 2008, NEC Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple ++ * Place - Suite 330, Boston, MA 02111-1307 USA. ++ */ ++ ++#include ++#include ++#include ++#include "pci.h" ++ ++ ++#define REASSIGNDEV_PARAM_MAX (2048) ++#define TOKEN_MAX (12) /* "SSSS:BB:DD.F" length is 12 */ ++ ++static char param_reassigndev[REASSIGNDEV_PARAM_MAX] = {0}; ++ ++static int __init reassigndev_setup(char *str) ++{ ++ strncpy(param_reassigndev, str, REASSIGNDEV_PARAM_MAX); ++ param_reassigndev[REASSIGNDEV_PARAM_MAX - 1] = '\0'; ++ return 1; ++} ++__setup("reassigndev=", reassigndev_setup); ++ ++int is_reassigndev(struct pci_dev *dev) ++{ ++ char dev_str[TOKEN_MAX+1]; ++ int seg, bus, slot, func; ++ int len; ++ char *p, *next_str; ++ ++ p = param_reassigndev; ++ for (; p; p = next_str + 1) { ++ next_str = strpbrk(p, ","); ++ if (next_str) { ++ len = next_str - p; ++ } else { ++ len = strlen(p); ++ } ++ if (len > 0 && len <= TOKEN_MAX) { ++ strncpy(dev_str, p, len); ++ *(dev_str + len) = '\0'; ++ ++ if (sscanf(dev_str, "%x:%x:%x.%x", ++ &seg, &bus, &slot, &func) != 4) { ++ if (sscanf(dev_str, "%x:%x.%x", ++ &bus, &slot, &func) == 3) { ++ seg = 0; ++ } else { ++ /* failed to scan strings */ ++ seg = -1; ++ bus = -1; ++ } ++ } ++ if (seg == pci_domain_nr(dev->bus) && ++ bus == dev->bus->number && ++ slot == PCI_SLOT(dev->devfn) && ++ func == PCI_FUNC(dev->devfn)) { ++ /* It's a target device */ ++ return 1; ++ } ++ } ++ if (!next_str) ++ break; ++ } ++ ++ return 0; ++} +--- sle11-2009-04-09.orig/drivers/pci/setup-bus.c 2009-04-09 14:29:05.000000000 +0200 ++++ sle11-2009-04-09/drivers/pci/setup-bus.c 2008-10-21 13:09:01.000000000 +0200 +@@ -26,6 +26,7 @@ + #include + #include + ++#include "pci.h" + + static void pbus_assign_resources_sorted(struct pci_bus *bus) + { +@@ -343,7 +344,8 @@ static int pbus_size_mem(struct pci_bus + + list_for_each_entry(dev, &bus->devices, bus_list) { + int i; +- ++ int reassign = is_reassigndev(dev); ++ + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + resource_size_t r_size; +@@ -351,6 +353,10 @@ static int pbus_size_mem(struct pci_bus + if (r->parent || (r->flags & mask) != type) + continue; + r_size = r->end - r->start + 1; ++ ++ if ((i < PCI_BRIDGE_RESOURCES) && reassign) ++ r_size = ALIGN(r_size, PAGE_SIZE); ++ + /* For bridges size != alignment */ + align = resource_alignment(r); + order = __ffs(align) - 20; +--- sle11-2009-04-09.orig/drivers/pci/setup-res.c 2009-04-09 14:29:05.000000000 +0200 ++++ sle11-2009-04-09/drivers/pci/setup-res.c 2008-12-01 11:10:02.000000000 +0100 +@@ -126,6 +126,21 @@ int pci_claim_resource(struct pci_dev *d + return err; + } + ++#ifdef CONFIG_PCI_REASSIGN ++void pci_disable_bridge_window(struct pci_dev *dev) ++{ ++ printk(KERN_DEBUG "PCI: Disable bridge window on %s\n", pci_name(dev)); ++ ++ /* MMIO Base/Limit */ ++ pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0); ++ ++ /* Prefetchable MMIO Base/Limit */ ++ pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0); ++ pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0); ++ pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff); ++} ++#endif ++ + int pci_assign_resource(struct pci_dev *dev, int resno) + { + struct pci_bus *bus = dev->bus; +@@ -144,6 +159,10 @@ int pci_assign_resource(struct pci_dev * + (unsigned long long)res->end, res->flags); + return -EINVAL; + } ++ if (resno < PCI_BRIDGE_RESOURCES ++ && is_reassigndev(dev) ++ && (res->flags & IORESOURCE_MEM)) ++ align = ALIGN(align, PAGE_SIZE); + + /* First, try exact prefetching match.. */ + ret = pci_bus_alloc_resource(bus, res, size, align, min, +@@ -169,8 +188,15 @@ int pci_assign_resource(struct pci_dev * + (unsigned long long)res->end); + } else { + res->flags &= ~IORESOURCE_STARTALIGN; +- if (resno < PCI_BRIDGE_RESOURCES) ++ if (resno < PCI_BRIDGE_RESOURCES) { ++#ifdef CONFIG_PCI_REASSIGN ++ printk(KERN_DEBUG "PCI: Assign resource(%d) on %s " ++ "%016llx - %016llx\n", resno, pci_name(dev), ++ (unsigned long long)res->start, ++ (unsigned long long)res->end); ++#endif + pci_update_resource(dev, res, resno); ++ } + } + + return ret; +@@ -208,6 +234,12 @@ int pci_assign_resource_fixed(struct pci + (unsigned long long)res->start, + (unsigned long long)res->end); + } else if (resno < PCI_BRIDGE_RESOURCES) { ++#ifdef CONFIG_PCI_REASSIGN ++ printk(KERN_DEBUG "PCI: Assign resource(%d) on %s " ++ "%016llx - %016llx\n", resno, pci_name(dev), ++ (unsigned long long)res->start, ++ (unsigned long long)res->end); ++#endif + pci_update_resource(dev, res, resno); + } + +@@ -220,6 +252,7 @@ EXPORT_SYMBOL_GPL(pci_assign_resource_fi + void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) + { + int i; ++ int reassigndev = is_reassigndev(dev); + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *r; +@@ -242,12 +275,22 @@ void pdev_sort_resources(struct pci_dev + (unsigned long long)r->end, r->flags); + continue; + } ++ if (i < PCI_BRIDGE_RESOURCES && (r->flags & IORESOURCE_MEM) && ++ reassigndev) ++ r_align = ALIGN(r_align, PAGE_SIZE); ++ + for (list = head; ; list = list->next) { + resource_size_t align = 0; + struct resource_list *ln = list->next; + +- if (ln) ++ if (ln) { + align = resource_alignment(ln->res); ++ if (ln->res - ln->dev->resource < ++ PCI_BRIDGE_RESOURCES && ++ (ln->res->flags & IORESOURCE_MEM) && ++ is_reassigndev(ln->dev)) ++ align = ALIGN(align, PAGE_SIZE); ++ } + + if (r_align > align) { + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); diff --git a/src/patches/suse-2.6.27.31/patches.xen/sfc-driverlink b/src/patches/suse-2.6.27.31/patches.xen/sfc-driverlink new file mode 100644 index 000000000..7e0ac85f4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/sfc-driverlink @@ -0,0 +1,1155 @@ +From: David Riddoch +commit d96c061bfd1839e34e136de0555564520acc97af +Author: Steve Hodgson +Date: Mon Jul 14 15:38:47 2008 +0100 + +Subject: sfc: Driverlink API for exporting hardware features to client drivers + +References: FATE#303479 +Acked-by: jbeulich@novell.com + +Index: head-2008-08-18/drivers/net/sfc/Makefile +=================================================================== +--- head-2008-08-18.orig/drivers/net/sfc/Makefile 2008-08-18 10:16:43.000000000 +0200 ++++ head-2008-08-18/drivers/net/sfc/Makefile 2008-08-18 10:16:46.000000000 +0200 +@@ -1,5 +1,5 @@ + sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \ + selftest.o ethtool.o xfp_phy.o \ +- mdio_10g.o tenxpress.o boards.o sfe4001.o +- ++ mdio_10g.o tenxpress.o boards.o sfe4001.o \ ++ driverlink.o + obj-$(CONFIG_SFC) += sfc.o +Index: head-2008-08-18/drivers/net/sfc/driverlink.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-08-18/drivers/net/sfc/driverlink.c 2008-08-18 10:16:46.000000000 +0200 +@@ -0,0 +1,367 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005 Fen Systems Ltd. ++ * Copyright 2005-2008 Solarflare Communications Inc. ++ * ++ * 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, incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "net_driver.h" ++#include "efx.h" ++#include "driverlink_api.h" ++#include "driverlink.h" ++ ++/* Protects @efx_driverlink_lock and @efx_driver_list */ ++static DEFINE_MUTEX(efx_driverlink_lock); ++ ++/* List of all registered drivers */ ++static LIST_HEAD(efx_driver_list); ++ ++/* List of all registered Efx ports */ ++static LIST_HEAD(efx_port_list); ++ ++/** ++ * Driver link handle used internally to track devices ++ * @efx_dev: driverlink device handle exported to consumers ++ * @efx: efx_nic backing the driverlink device ++ * @port_node: per-device list head ++ * @driver_node: per-driver list head ++ */ ++struct efx_dl_handle { ++ struct efx_dl_device efx_dev; ++ struct efx_nic *efx; ++ struct list_head port_node; ++ struct list_head driver_node; ++}; ++ ++static struct efx_dl_handle *efx_dl_handle(struct efx_dl_device *efx_dev) ++{ ++ return container_of(efx_dev, struct efx_dl_handle, efx_dev); ++} ++ ++/* Remove an Efx device, and call the driver's remove() callback if ++ * present. The caller must hold @efx_driverlink_lock. */ ++static void efx_dl_del_device(struct efx_dl_device *efx_dev) ++{ ++ struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); ++ ++ EFX_INFO(efx_handle->efx, "%s driverlink client unregistering\n", ++ efx_dev->driver->name); ++ ++ if (efx_dev->driver->remove) ++ efx_dev->driver->remove(efx_dev); ++ ++ list_del(&efx_handle->driver_node); ++ list_del(&efx_handle->port_node); ++ ++ kfree(efx_handle); ++} ++ ++/* Attempt to probe the given device with the driver, creating a ++ * new &struct efx_dl_device. If the probe routine returns an error, ++ * then the &struct efx_dl_device is destroyed */ ++static void efx_dl_try_add_device(struct efx_nic *efx, ++ struct efx_dl_driver *driver) ++{ ++ struct efx_dl_handle *efx_handle; ++ struct efx_dl_device *efx_dev; ++ int rc; ++ ++ efx_handle = kzalloc(sizeof(*efx_handle), GFP_KERNEL); ++ if (!efx_handle) ++ goto fail; ++ efx_dev = &efx_handle->efx_dev; ++ efx_handle->efx = efx; ++ efx_dev->driver = driver; ++ efx_dev->pci_dev = efx->pci_dev; ++ INIT_LIST_HEAD(&efx_handle->port_node); ++ INIT_LIST_HEAD(&efx_handle->driver_node); ++ ++ rc = driver->probe(efx_dev, efx->net_dev, ++ efx->dl_info, efx->silicon_rev); ++ if (rc) ++ goto fail; ++ ++ list_add_tail(&efx_handle->driver_node, &driver->device_list); ++ list_add_tail(&efx_handle->port_node, &efx->dl_device_list); ++ ++ EFX_INFO(efx, "%s driverlink client registered\n", driver->name); ++ return; ++ ++ fail: ++ EFX_INFO(efx, "%s driverlink client skipped\n", driver->name); ++ ++ kfree(efx_handle); ++} ++ ++/* Unregister a driver from the driverlink layer, calling the ++ * driver's remove() callback for every attached device */ ++void efx_dl_unregister_driver(struct efx_dl_driver *driver) ++{ ++ struct efx_dl_handle *efx_handle, *efx_handle_n; ++ ++ printk(KERN_INFO "Efx driverlink unregistering %s driver\n", ++ driver->name); ++ ++ mutex_lock(&efx_driverlink_lock); ++ ++ list_for_each_entry_safe(efx_handle, efx_handle_n, ++ &driver->device_list, driver_node) ++ efx_dl_del_device(&efx_handle->efx_dev); ++ ++ list_del(&driver->node); ++ ++ mutex_unlock(&efx_driverlink_lock); ++} ++EXPORT_SYMBOL(efx_dl_unregister_driver); ++ ++/* Register a new driver with the driverlink layer. The driver's ++ * probe routine will be called for every attached nic. */ ++int efx_dl_register_driver(struct efx_dl_driver *driver) ++{ ++ struct efx_nic *efx; ++ int rc; ++ ++ printk(KERN_INFO "Efx driverlink registering %s driver\n", ++ driver->name); ++ ++ INIT_LIST_HEAD(&driver->node); ++ INIT_LIST_HEAD(&driver->device_list); ++ ++ rc = mutex_lock_interruptible(&efx_driverlink_lock); ++ if (rc) ++ return rc; ++ ++ list_add_tail(&driver->node, &efx_driver_list); ++ list_for_each_entry(efx, &efx_port_list, dl_node) ++ efx_dl_try_add_device(efx, driver); ++ ++ mutex_unlock(&efx_driverlink_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_dl_register_driver); ++ ++void efx_dl_unregister_nic(struct efx_nic *efx) ++{ ++ struct efx_dl_handle *efx_handle, *efx_handle_n; ++ ++ mutex_lock(&efx_driverlink_lock); ++ ++ list_for_each_entry_safe_reverse(efx_handle, efx_handle_n, ++ &efx->dl_device_list, ++ port_node) ++ efx_dl_del_device(&efx_handle->efx_dev); ++ ++ list_del(&efx->dl_node); ++ ++ mutex_unlock(&efx_driverlink_lock); ++} ++ ++int efx_dl_register_nic(struct efx_nic *efx) ++{ ++ struct efx_dl_driver *driver; ++ int rc; ++ ++ rc = mutex_lock_interruptible(&efx_driverlink_lock); ++ if (rc) ++ return rc; ++ ++ list_add_tail(&efx->dl_node, &efx_port_list); ++ list_for_each_entry(driver, &efx_driver_list, node) ++ efx_dl_try_add_device(efx, driver); ++ ++ mutex_unlock(&efx_driverlink_lock); ++ ++ return 0; ++} ++ ++/* Dummy callback implementations. ++ * To avoid a branch point on the fast-path, the callbacks are always ++ * implemented - they are never NULL. ++ */ ++static enum efx_veto efx_dummy_tx_packet_callback(struct efx_dl_device *efx_dev, ++ struct sk_buff *skb) ++{ ++ return EFX_ALLOW_PACKET; ++} ++ ++static enum efx_veto efx_dummy_rx_packet_callback(struct efx_dl_device *efx_dev, ++ const char *pkt_buf, int len) ++{ ++ return EFX_ALLOW_PACKET; ++} ++ ++static int efx_dummy_request_mtu_callback(struct efx_dl_device *efx_dev, ++ int new_mtu) ++{ ++ return 0; ++} ++ ++static void efx_dummy_mtu_changed_callback(struct efx_dl_device *efx_dev, ++ int mtu) ++{ ++ return; ++} ++ ++static void efx_dummy_event_callback(struct efx_dl_device *efx_dev, void *event) ++{ ++ return; ++} ++ ++struct efx_dl_callbacks efx_default_callbacks = { ++ .tx_packet = efx_dummy_tx_packet_callback, ++ .rx_packet = efx_dummy_rx_packet_callback, ++ .request_mtu = efx_dummy_request_mtu_callback, ++ .mtu_changed = efx_dummy_mtu_changed_callback, ++ .event = efx_dummy_event_callback, ++}; ++ ++void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev, ++ struct efx_dl_callbacks *callbacks) ++{ ++ struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); ++ struct efx_nic *efx = efx_handle->efx; ++ ++ efx_suspend(efx); ++ ++ EFX_INFO(efx, "removing callback hooks into %s driver\n", ++ efx_dev->driver->name); ++ ++ if (callbacks->tx_packet) { ++ BUG_ON(efx->dl_cb_dev.tx_packet != efx_dev); ++ efx->dl_cb.tx_packet = efx_default_callbacks.tx_packet; ++ efx->dl_cb_dev.tx_packet = NULL; ++ } ++ if (callbacks->rx_packet) { ++ BUG_ON(efx->dl_cb_dev.rx_packet != efx_dev); ++ efx->dl_cb.rx_packet = efx_default_callbacks.rx_packet; ++ efx->dl_cb_dev.rx_packet = NULL; ++ } ++ if (callbacks->request_mtu) { ++ BUG_ON(efx->dl_cb_dev.request_mtu != efx_dev); ++ efx->dl_cb.request_mtu = efx_default_callbacks.request_mtu; ++ efx->dl_cb_dev.request_mtu = NULL; ++ } ++ if (callbacks->mtu_changed) { ++ BUG_ON(efx->dl_cb_dev.mtu_changed != efx_dev); ++ efx->dl_cb.mtu_changed = efx_default_callbacks.mtu_changed; ++ efx->dl_cb_dev.mtu_changed = NULL; ++ } ++ if (callbacks->event) { ++ BUG_ON(efx->dl_cb_dev.event != efx_dev); ++ efx->dl_cb.event = efx_default_callbacks.event; ++ efx->dl_cb_dev.event = NULL; ++ } ++ ++ efx_resume(efx); ++} ++EXPORT_SYMBOL(efx_dl_unregister_callbacks); ++ ++int efx_dl_register_callbacks(struct efx_dl_device *efx_dev, ++ struct efx_dl_callbacks *callbacks) ++{ ++ struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); ++ struct efx_nic *efx = efx_handle->efx; ++ int rc = 0; ++ ++ efx_suspend(efx); ++ ++ /* Check that the requested callbacks are not already hooked. */ ++ if ((callbacks->tx_packet && efx->dl_cb_dev.tx_packet) || ++ (callbacks->rx_packet && efx->dl_cb_dev.rx_packet) || ++ (callbacks->request_mtu && efx->dl_cb_dev.request_mtu) || ++ (callbacks->mtu_changed && efx->dl_cb_dev.mtu_changed) || ++ (callbacks->event && efx->dl_cb_dev.event)) { ++ rc = -EBUSY; ++ goto out; ++ } ++ ++ EFX_INFO(efx, "adding callback hooks to %s driver\n", ++ efx_dev->driver->name); ++ ++ /* Hook in the requested callbacks, leaving any NULL members ++ * referencing the members of @efx_default_callbacks */ ++ if (callbacks->tx_packet) { ++ efx->dl_cb.tx_packet = callbacks->tx_packet; ++ efx->dl_cb_dev.tx_packet = efx_dev; ++ } ++ if (callbacks->rx_packet) { ++ efx->dl_cb.rx_packet = callbacks->rx_packet; ++ efx->dl_cb_dev.rx_packet = efx_dev; ++ } ++ if (callbacks->request_mtu) { ++ efx->dl_cb.request_mtu = callbacks->request_mtu; ++ efx->dl_cb_dev.request_mtu = efx_dev; ++ } ++ if (callbacks->mtu_changed) { ++ efx->dl_cb.mtu_changed = callbacks->mtu_changed; ++ efx->dl_cb_dev.mtu_changed = efx_dev; ++ } ++ if (callbacks->event) { ++ efx->dl_cb.event = callbacks->event; ++ efx->dl_cb_dev.event = efx_dev; ++ } ++ ++ out: ++ efx_resume(efx); ++ ++ return rc; ++} ++EXPORT_SYMBOL(efx_dl_register_callbacks); ++ ++void efx_dl_schedule_reset(struct efx_dl_device *efx_dev) ++{ ++ struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); ++ struct efx_nic *efx = efx_handle->efx; ++ ++ efx_schedule_reset(efx, RESET_TYPE_ALL); ++} ++EXPORT_SYMBOL(efx_dl_schedule_reset); ++ ++void efx_dl_reset_unlock(void) ++{ ++ mutex_unlock(&efx_driverlink_lock); ++} ++ ++/* Suspend ready for reset, serialising against all the driverlink interfacse ++ * and calling the suspend() callback of every registered driver */ ++void efx_dl_reset_suspend(struct efx_nic *efx) ++{ ++ struct efx_dl_handle *efx_handle; ++ struct efx_dl_device *efx_dev; ++ ++ mutex_lock(&efx_driverlink_lock); ++ ++ list_for_each_entry_reverse(efx_handle, ++ &efx->dl_device_list, ++ port_node) { ++ efx_dev = &efx_handle->efx_dev; ++ if (efx_dev->driver->reset_suspend) ++ efx_dev->driver->reset_suspend(efx_dev); ++ } ++} ++ ++/* Resume after a reset, calling the resume() callback of every registered ++ * driver, and releasing @Efx_driverlink_lock acquired in ++ * efx_dl_reset_resume() */ ++void efx_dl_reset_resume(struct efx_nic *efx, int ok) ++{ ++ struct efx_dl_handle *efx_handle; ++ struct efx_dl_device *efx_dev; ++ ++ list_for_each_entry(efx_handle, &efx->dl_device_list, ++ port_node) { ++ efx_dev = &efx_handle->efx_dev; ++ if (efx_dev->driver->reset_resume) ++ efx_dev->driver->reset_resume(efx_dev, ok); ++ } ++ ++ mutex_unlock(&efx_driverlink_lock); ++} +Index: head-2008-08-18/drivers/net/sfc/driverlink.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-08-18/drivers/net/sfc/driverlink.h 2008-08-18 10:16:46.000000000 +0200 +@@ -0,0 +1,43 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005 Fen Systems Ltd. ++ * Copyright 2006-2008 Solarflare Communications Inc. ++ * ++ * 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, incorporated herein by reference. ++ */ ++ ++#ifndef EFX_DRIVERLINK_H ++#define EFX_DRIVERLINK_H ++ ++/* Forward declarations */ ++struct efx_dl_device; ++struct efx_nic; ++ ++/* Efx callback devices ++ * ++ * A list of the devices that own each callback. The partner to ++ * struct efx_dl_callbacks. ++ */ ++struct efx_dl_cb_devices { ++ struct efx_dl_device *tx_packet; ++ struct efx_dl_device *rx_packet; ++ struct efx_dl_device *request_mtu; ++ struct efx_dl_device *mtu_changed; ++ struct efx_dl_device *event; ++}; ++ ++extern struct efx_dl_callbacks efx_default_callbacks; ++ ++#define EFX_DL_CALLBACK(_port, _name, ...) \ ++ (_port)->dl_cb._name((_port)->dl_cb_dev._name, __VA_ARGS__) ++ ++extern int efx_dl_register_nic(struct efx_nic *efx); ++extern void efx_dl_unregister_nic(struct efx_nic *efx); ++ ++/* Suspend and resume client drivers over a hardware reset */ ++extern void efx_dl_reset_suspend(struct efx_nic *efx); ++extern void efx_dl_reset_resume(struct efx_nic *efx, int ok); ++ ++#endif /* EFX_DRIVERLINK_H */ +Index: head-2008-08-18/drivers/net/sfc/driverlink_api.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-08-18/drivers/net/sfc/driverlink_api.h 2008-08-18 10:16:46.000000000 +0200 +@@ -0,0 +1,303 @@ ++/**************************************************************************** ++ * Driver for Solarflare Solarstorm network controllers and boards ++ * Copyright 2005-2006 Fen Systems Ltd. ++ * Copyright 2005-2008 Solarflare Communications Inc. ++ * ++ * 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, incorporated herein by reference. ++ */ ++ ++#ifndef EFX_DRIVERLINK_API_H ++#define EFX_DRIVERLINK_API_H ++ ++#include ++ ++/* Forward declarations */ ++struct pci_dev; ++struct net_device; ++struct sk_buff; ++struct efx_dl_device; ++struct efx_dl_device_info; ++ ++/* An extra safeguard in addition to symbol versioning */ ++#define EFX_DRIVERLINK_API_VERSION 2 ++ ++/** ++ * struct efx_dl_driver - An Efx driverlink device driver ++ * ++ * A driverlink client defines and initializes as many instances of ++ * efx_dl_driver as required, registering each one with ++ * efx_dl_register_driver(). ++ * ++ * @name: Name of the driver ++ * @probe: Called when device added ++ * The client should use the @def_info linked list and @silicon_rev ++ * to determine if they wish to attach to this device. ++ * Context: process, driverlink semaphore held ++ * @remove: Called when device removed ++ * The client must ensure the finish all operations with this ++ * device before returning from this method. ++ * Context: process, driverlink semaphore held ++ * @reset_suspend: Called before device is reset ++ * Called immediately before a hardware reset. The client must stop all ++ * hardware processing before returning from this method. Callbacks will ++ * be inactive when this method is called. ++ * Context: process, driverlink semaphore held. rtnl_lock may be held ++ * @reset_resume: Called after device is reset ++ * Called after a hardware reset. If @ok is true, the client should ++ * state and resume normal operations. If @ok is false, the client should ++ * abandon use of the hardware resources. remove() will still be called. ++ * Context: process, driverlink semaphore held. rtnl_lock may be held ++ */ ++struct efx_dl_driver { ++ const char *name; ++ ++ int (*probe) (struct efx_dl_device *efx_dl_dev, ++ const struct net_device *net_dev, ++ const struct efx_dl_device_info *dev_info, ++ const char *silicon_rev); ++ void (*remove) (struct efx_dl_device *efx_dev); ++ void (*reset_suspend) (struct efx_dl_device *efx_dev); ++ void (*reset_resume) (struct efx_dl_device *efx_dev, int ok); ++ ++/* private: */ ++ struct list_head node; ++ struct list_head device_list; ++}; ++ ++/** ++ * enum efx_dl_device_info_type - Device information identifier. ++ * ++ * Used to identify each item in the &struct efx_dl_device_info linked list ++ * provided to each driverlink client in the probe() @dev_info member. ++ * ++ * @EFX_DL_FALCON_RESOURCES: Information type is &struct efx_dl_falcon_resources ++ */ ++enum efx_dl_device_info_type { ++ /** Falcon resources available for export */ ++ EFX_DL_FALCON_RESOURCES = 0, ++}; ++ ++/** ++ * struct efx_dl_device_info - device information structure ++ * ++ * @next: Link to next structure, if any ++ * @type: Type code for this structure ++ */ ++struct efx_dl_device_info { ++ struct efx_dl_device_info *next; ++ enum efx_dl_device_info_type type; ++}; ++ ++/** ++ * enum efx_dl_falcon_resource_flags - Falcon resource information flags. ++ * ++ * Flags that describe hardware variations for the current Falcon device. ++ * ++ * @EFX_DL_FALCON_DUAL_FUNC: Port is dual-function. ++ * Certain silicon revisions have two pci functions, and require ++ * certain hardware resources to be accessed via the secondary ++ * function ++ * @EFX_DL_FALCON_USE_MSI: Port is initialised to use MSI/MSI-X interrupts. ++ * Falcon supports traditional legacy interrupts and MSI/MSI-X ++ * interrupts. The choice is made at run time by the sfc driver, and ++ * notified to the clients by this enumeration ++ */ ++enum efx_dl_falcon_resource_flags { ++ EFX_DL_FALCON_DUAL_FUNC = 0x1, ++ EFX_DL_FALCON_USE_MSI = 0x2, ++}; ++ ++/** ++ * struct efx_dl_falcon_resources - Falcon resource information. ++ * ++ * This structure describes Falcon hardware resources available for ++ * use by a driverlink driver. ++ * ++ * @hdr: Resource linked list header ++ * @biu_lock: Register access lock. ++ * Some Falcon revisions require register access for configuration ++ * registers to be serialised between ports and PCI functions. ++ * The sfc driver will provide the appropriate lock semantics for ++ * the underlying hardware. ++ * @buffer_table_min: First available buffer table entry ++ * @buffer_table_lim: Last available buffer table entry + 1 ++ * @evq_timer_min: First available event queue with timer ++ * @evq_timer_lim: Last available event queue with timer + 1 ++ * @evq_int_min: First available event queue with interrupt ++ * @evq_int_lim: Last available event queue with interrupt + 1 ++ * @rxq_min: First available RX queue ++ * @rxq_lim: Last available RX queue + 1 ++ * @txq_min: First available TX queue ++ * @txq_lim: Last available TX queue + 1 ++ * @flags: Hardware variation flags ++ */ ++struct efx_dl_falcon_resources { ++ struct efx_dl_device_info hdr; ++ spinlock_t *biu_lock; ++ unsigned buffer_table_min; ++ unsigned buffer_table_lim; ++ unsigned evq_timer_min; ++ unsigned evq_timer_lim; ++ unsigned evq_int_min; ++ unsigned evq_int_lim; ++ unsigned rxq_min; ++ unsigned rxq_lim; ++ unsigned txq_min; ++ unsigned txq_lim; ++ enum efx_dl_falcon_resource_flags flags; ++}; ++ ++/** ++ * struct efx_dl_device - An Efx driverlink device. ++ * ++ * @pci_dev: PCI device used by the sfc driver. ++ * @priv: Driver private data ++ * Driverlink clients can use this to store a pointer to their ++ * internal per-device data structure. Each (driver, device) ++ * tuple has a separate &struct efx_dl_device, so clients can use ++ * this @priv field independently. ++ * @driver: Efx driverlink driver for this device ++ */ ++struct efx_dl_device { ++ struct pci_dev *pci_dev; ++ void *priv; ++ struct efx_dl_driver *driver; ++}; ++ ++/** ++ * enum efx_veto - Packet veto request flag. ++ * ++ * This is the return type for the rx_packet() and tx_packet() methods ++ * in &struct efx_dl_callbacks. ++ * ++ * @EFX_ALLOW_PACKET: Packet may be transmitted/received ++ * @EFX_VETO_PACKET: Packet must not be transmitted/received ++ */ ++enum efx_veto { ++ EFX_ALLOW_PACKET = 0, ++ EFX_VETO_PACKET = 1, ++}; ++ ++/** ++ * struct efx_dl_callbacks - Efx callbacks ++ * ++ * This is a tighly controlled set of simple callbacks, that are attached ++ * to the sfc driver via efx_dl_register_callbacks(). They export just enough ++ * state to allow clients to make use of the available hardware resources. ++ * ++ * For efficiency, only one client can hook each callback. Since these ++ * callbacks are called on packet transmit and reception paths, and the ++ * sfc driver may have multiple tx and rx queues per port, clients should ++ * avoid acquiring locks or allocating memory. ++ * ++ * @tx_packet: Called when packet is about to be transmitted ++ * Called for every packet about to be transmitted, providing means ++ * for the client to snoop traffic, and veto transmission by returning ++ * %EFX_VETO_PACKET (the sfc driver will subsequently free the skb). ++ * Context: tasklet, netif_tx_lock held ++ * @rx_packet: Called when packet is received ++ * Called for every received packet (after LRO), allowing the client ++ * to snoop every received packet (on every rx queue), and veto ++ * reception by returning %EFX_VETO_PACKET. ++ * Context: tasklet ++ * @request_mtu: Called to request MTU change. ++ * Called whenever the user requests the net_dev mtu to be changed. ++ * If the client returns an error, the mtu change is aborted. The sfc ++ * driver guarantees that no other callbacks are running. ++ * Context: process, rtnl_lock held. ++ * @mtu_changed: Called when MTU has been changed. ++ * Called after the mtu has been successfully changed, always after ++ * a previous call to request_mtu(). The sfc driver guarantees that no ++ * other callbacks are running. ++ * Context: process, rtnl_lock held. ++ * @event: Called when a hardware NIC event is not understood by the sfc driver. ++ * Context: tasklet. ++ */ ++struct efx_dl_callbacks { ++ enum efx_veto (*tx_packet) (struct efx_dl_device *efx_dev, ++ struct sk_buff *skb); ++ enum efx_veto (*rx_packet) (struct efx_dl_device *efx_dev, ++ const char *pkt_hdr, int pkt_len); ++ int (*request_mtu) (struct efx_dl_device *efx_dev, int new_mtu); ++ void (*mtu_changed) (struct efx_dl_device *efx_dev, int mtu); ++ void (*event) (struct efx_dl_device *efx_dev, void *p_event); ++}; ++ ++/* Include API version number in symbol used for efx_dl_register_driver */ ++#define efx_dl_stringify_1(x, y) x ## y ++#define efx_dl_stringify_2(x, y) efx_dl_stringify_1(x, y) ++#define efx_dl_register_driver \ ++ efx_dl_stringify_2(efx_dl_register_driver_api_ver_, \ ++ EFX_DRIVERLINK_API_VERSION) ++ ++/* Exported driverlink api used to register and unregister the client driver ++ * and any callbacks [only one per port allowed], and to allow a client driver ++ * to request reset to recover from an error condition. ++ * ++ * All of these functions acquire the driverlink semaphore, so must not be ++ * called from an efx_dl_driver or efx_dl_callbacks member, and must be called ++ * from process context. ++ */ ++extern int efx_dl_register_driver(struct efx_dl_driver *driver); ++ ++extern void efx_dl_unregister_driver(struct efx_dl_driver *driver); ++ ++extern int efx_dl_register_callbacks(struct efx_dl_device *efx_dev, ++ struct efx_dl_callbacks *callbacks); ++ ++extern void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev, ++ struct efx_dl_callbacks *callbacks); ++ ++/* Schedule a reset without grabbing any locks */ ++extern void efx_dl_schedule_reset(struct efx_dl_device *efx_dev); ++ ++/** ++ * efx_dl_for_each_device_info_matching - iterate an efx_dl_device_info list ++ * @_dev_info: Pointer to first &struct efx_dl_device_info ++ * @_type: Type code to look for ++ * @_info_type: Structure type corresponding to type code ++ * @_field: Name of &struct efx_dl_device_info field in the type ++ * @_p: Iterator variable ++ * ++ * Example: ++ * struct efx_dl_falcon_resources *res; ++ * efx_dl_for_each_device_info_matching(dev_info, EFX_DL_FALCON_RESOURCES, ++ * struct efx_dl_falcon_resources, ++ * hdr, res) { ++ * if (res->flags & EFX_DL_FALCON_DUAL_FUNC) ++ * .... ++ * } ++ */ ++#define efx_dl_for_each_device_info_matching(_dev_info, _type, \ ++ _info_type, _field, _p) \ ++ for ((_p) = container_of((_dev_info), _info_type, _field); \ ++ (_p) != NULL; \ ++ (_p) = container_of((_p)->_field.next, _info_type, _field))\ ++ if ((_p)->_field.type != _type) \ ++ continue; \ ++ else ++ ++/** ++ * efx_dl_search_device_info - search an efx_dl_device_info list ++ * @_dev_info: Pointer to first &struct efx_dl_device_info ++ * @_type: Type code to look for ++ * @_info_type: Structure type corresponding to type code ++ * @_field: Name of &struct efx_dl_device_info member in this type ++ * @_p: Result variable ++ * ++ * Example: ++ * struct efx_dl_falcon_resources *res; ++ * efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES, ++ * struct efx_dl_falcon_resources, hdr, res); ++ * if (res) ++ * .... ++ */ ++#define efx_dl_search_device_info(_dev_info, _type, _info_type, \ ++ _field, _p) \ ++ efx_dl_for_each_device_info_matching((_dev_info), (_type), \ ++ _info_type, _field, (_p)) \ ++ break; ++ ++#endif /* EFX_DRIVERLINK_API_H */ +Index: head-2008-08-18/drivers/net/sfc/efx.c +=================================================================== +--- head-2008-08-18.orig/drivers/net/sfc/efx.c 2008-08-18 10:16:43.000000000 +0200 ++++ head-2008-08-18/drivers/net/sfc/efx.c 2008-08-18 10:16:46.000000000 +0200 +@@ -1427,6 +1427,11 @@ static int efx_change_mtu(struct net_dev + + efx_stop_all(efx); + ++ /* Ask driverlink client if we can change MTU */ ++ rc = EFX_DL_CALLBACK(efx, request_mtu, new_mtu); ++ if (rc) ++ goto out; ++ + EFX_LOG(efx, "changing MTU to %d\n", new_mtu); + + efx_fini_channels(efx); +@@ -1435,6 +1440,10 @@ static int efx_change_mtu(struct net_dev + if (rc) + goto fail; + ++ /* Notify driverlink client of new MTU */ ++ EFX_DL_CALLBACK(efx, mtu_changed, new_mtu); ++ ++ out: + efx_start_all(efx); + return rc; + +@@ -1587,6 +1596,23 @@ static void efx_unregister_netdev(struct + * Device reset and suspend + * + **************************************************************************/ ++/* Serialise access to the driverlink callbacks, by quiescing event processing ++ * (without flushing the descriptor queues), and acquiring the rtnl_lock */ ++void efx_suspend(struct efx_nic *efx) ++{ ++ EFX_LOG(efx, "suspending operations\n"); ++ ++ rtnl_lock(); ++ efx_stop_all(efx); ++} ++ ++void efx_resume(struct efx_nic *efx) ++{ ++ EFX_LOG(efx, "resuming operations\n"); ++ ++ efx_start_all(efx); ++ rtnl_unlock(); ++} + + /* The final hardware and software finalisation before reset. */ + static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) +@@ -1649,8 +1675,8 @@ static int efx_reset(struct efx_nic *efx + enum reset_type method = efx->reset_pending; + int rc; + +- /* Serialise with kernel interfaces */ + rtnl_lock(); ++ efx_dl_reset_suspend(efx); + + /* If we're not RUNNING then don't reset. Leave the reset_pending + * flag set so that efx_pci_probe_main will be retried */ +@@ -1717,6 +1743,7 @@ static int efx_reset(struct efx_nic *efx + efx_start_all(efx); + + unlock_rtnl: ++ efx_dl_reset_resume(efx, 1); + rtnl_unlock(); + return 0; + +@@ -1729,6 +1756,7 @@ static int efx_reset(struct efx_nic *efx + efx->state = STATE_DISABLED; + + mutex_unlock(&efx->mac_lock); ++ efx_dl_reset_resume(efx, 0); + rtnl_unlock(); + efx_unregister_netdev(efx); + efx_fini_port(efx); +@@ -1871,6 +1899,9 @@ static int efx_init_struct(struct efx_ni + mutex_init(&efx->mac_lock); + efx->phy_op = &efx_dummy_phy_operations; + efx->mii.dev = net_dev; ++ INIT_LIST_HEAD(&efx->dl_node); ++ INIT_LIST_HEAD(&efx->dl_device_list); ++ efx->dl_cb = efx_default_callbacks; + INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); + atomic_set(&efx->netif_stop_count, 1); + +@@ -1990,6 +2021,7 @@ static void efx_pci_remove(struct pci_de + efx = pci_get_drvdata(pci_dev); + if (!efx) + return; ++ efx_dl_unregister_nic(efx); + + /* Mark the NIC as fini, then stop the interface */ + rtnl_lock(); +@@ -2157,8 +2189,15 @@ static int __devinit efx_pci_probe(struc + + EFX_LOG(efx, "initialisation successful\n"); + ++ /* Register with driverlink layer */ ++ rc = efx_dl_register_nic(efx); ++ if (rc) ++ goto fail6; ++ + return 0; + ++ fail6: ++ efx_unregister_netdev(efx); + fail5: + efx_pci_remove_main(efx); + fail4: +Index: head-2008-08-18/drivers/net/sfc/falcon.c +=================================================================== +--- head-2008-08-18.orig/drivers/net/sfc/falcon.c 2008-08-18 10:16:43.000000000 +0200 ++++ head-2008-08-18/drivers/net/sfc/falcon.c 2008-08-18 10:16:46.000000000 +0200 +@@ -36,12 +36,12 @@ + + /** + * struct falcon_nic_data - Falcon NIC state +- * @next_buffer_table: First available buffer table id ++ * @resources: Resource information for driverlink client + * @pci_dev2: The secondary PCI device if present + * @i2c_data: Operations and state for I2C bit-bashing algorithm + */ + struct falcon_nic_data { +- unsigned next_buffer_table; ++ struct efx_dl_falcon_resources resources; + struct pci_dev *pci_dev2; + struct i2c_algo_bit_data i2c_data; + }; +@@ -322,8 +322,8 @@ static int falcon_alloc_special_buffer(s + memset(buffer->addr, 0xff, len); + + /* Select new buffer ID */ +- buffer->index = nic_data->next_buffer_table; +- nic_data->next_buffer_table += buffer->entries; ++ buffer->index = nic_data->resources.buffer_table_min; ++ nic_data->resources.buffer_table_min += buffer->entries; + + EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " + "(virt %p phys %lx)\n", buffer->index, +@@ -1115,10 +1115,12 @@ static void falcon_handle_driver_event(s + case TX_DESCQ_FLS_DONE_EV_DECODE: + EFX_TRACE(efx, "channel %d TXQ %d flushed\n", + channel->channel, ev_sub_data); ++ EFX_DL_CALLBACK(efx, event, event); + break; + case RX_DESCQ_FLS_DONE_EV_DECODE: + EFX_TRACE(efx, "channel %d RXQ %d flushed\n", + channel->channel, ev_sub_data); ++ EFX_DL_CALLBACK(efx, event, event); + break; + case EVQ_INIT_DONE_EV_DECODE: + EFX_LOG(efx, "channel %d EVQ %d initialised\n", +@@ -1127,14 +1129,17 @@ static void falcon_handle_driver_event(s + case SRM_UPD_DONE_EV_DECODE: + EFX_TRACE(efx, "channel %d SRAM update done\n", + channel->channel); ++ EFX_DL_CALLBACK(efx, event, event); + break; + case WAKE_UP_EV_DECODE: + EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", + channel->channel, ev_sub_data); ++ EFX_DL_CALLBACK(efx, event, event); + break; + case TIMER_EV_DECODE: + EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", + channel->channel, ev_sub_data); ++ EFX_DL_CALLBACK(efx, event, event); + break; + case RX_RECOVERY_EV_DECODE: + EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " +@@ -1159,6 +1164,7 @@ static void falcon_handle_driver_event(s + EFX_TRACE(efx, "channel %d unknown driver event code %d " + "data %04x\n", channel->channel, ev_sub_code, + ev_sub_data); ++ EFX_DL_CALLBACK(efx, event, event); + break; + } + } +@@ -2371,6 +2377,59 @@ static int falcon_probe_nvconfig(struct + return rc; + } + ++/* Looks at available SRAM resources and silicon revision, and works out ++ * how many queues we can support, and where things like descriptor caches ++ * should live. */ ++static int falcon_dimension_resources(struct efx_nic *efx) ++{ ++ unsigned internal_dcs_entries; ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ struct efx_dl_falcon_resources *res = &nic_data->resources; ++ ++ /* Fill out the driverlink resource list */ ++ res->hdr.type = EFX_DL_FALCON_RESOURCES; ++ res->biu_lock = &efx->biu_lock; ++ efx->dl_info = &res->hdr; ++ ++ /* NB. The minimum values get increased as this driver initialises ++ * its resources, so this should prevent any overlap. ++ */ ++ switch (falcon_rev(efx)) { ++ case FALCON_REV_A1: ++ res->rxq_min = 16; ++ res->txq_min = 16; ++ res->evq_int_min = 4; ++ res->evq_int_lim = 5; ++ res->evq_timer_min = 5; ++ res->evq_timer_lim = 4096; ++ internal_dcs_entries = 8192; ++ break; ++ case FALCON_REV_B0: ++ default: ++ res->rxq_min = 0; ++ res->txq_min = 0; ++ res->evq_int_min = 0; ++ res->evq_int_lim = 64; ++ res->evq_timer_min = 64; ++ res->evq_timer_lim = 4096; ++ internal_dcs_entries = 4096; ++ break; ++ } ++ ++ /* Internal SRAM only for now */ ++ res->rxq_lim = internal_dcs_entries / RX_DC_ENTRIES; ++ res->txq_lim = internal_dcs_entries / TX_DC_ENTRIES; ++ res->buffer_table_lim = 8192; ++ ++ if (FALCON_IS_DUAL_FUNC(efx)) ++ res->flags |= EFX_DL_FALCON_DUAL_FUNC; ++ ++ if (EFX_INT_MODE_USE_MSI(efx)) ++ res->flags |= EFX_DL_FALCON_USE_MSI; ++ ++ return 0; ++} ++ + /* Probe the NIC variant (revision, ASIC vs FPGA, function count, port + * count, port speed). Set workaround and feature flags accordingly. + */ +@@ -2403,10 +2462,12 @@ static int falcon_probe_nic_variant(stru + EFX_ERR(efx, "1G mode not supported\n"); + return -ENODEV; + } ++ efx->silicon_rev = "falcon/a1"; + break; + } + + case FALCON_REV_B0: ++ efx->silicon_rev = "falcon/b0"; + break; + + default: +@@ -2472,6 +2533,10 @@ int falcon_probe_nic(struct efx_nic *efx + if (rc) + goto fail5; + ++ rc = falcon_dimension_resources(efx); ++ if (rc) ++ goto fail6; ++ + /* Initialise I2C adapter */ + efx->i2c_adap.owner = THIS_MODULE; + nic_data->i2c_data = falcon_i2c_bit_operations; +@@ -2481,10 +2546,12 @@ int falcon_probe_nic(struct efx_nic *efx + strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name)); + rc = i2c_bit_add_bus(&efx->i2c_adap); + if (rc) +- goto fail5; ++ goto fail6; + + return 0; + ++ fail6: ++ efx->dl_info = NULL; + fail5: + falcon_free_buffer(efx, &efx->irq_status); + fail4: +@@ -2675,6 +2742,7 @@ void falcon_remove_nic(struct efx_nic *e + /* Tear down the private nic state */ + kfree(efx->nic_data); + efx->nic_data = NULL; ++ efx->dl_info = NULL; + } + + void falcon_update_nic_stats(struct efx_nic *efx) +Index: head-2008-08-18/drivers/net/sfc/net_driver.h +=================================================================== +--- head-2008-08-18.orig/drivers/net/sfc/net_driver.h 2008-08-18 10:16:43.000000000 +0200 ++++ head-2008-08-18/drivers/net/sfc/net_driver.h 2008-08-18 10:16:46.000000000 +0200 +@@ -30,6 +30,8 @@ + + #include "enum.h" + #include "bitfield.h" ++#include "driverlink_api.h" ++#include "driverlink.h" + + #define EFX_MAX_LRO_DESCRIPTORS 8 + #define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS +@@ -676,6 +678,12 @@ union efx_multicast_hash { + * @loopback_mode: Loopback status + * @loopback_modes: Supported loopback mode bitmask + * @loopback_selftest: Offline self-test private state ++ * @silicon_rev: Silicon revision description for driverlink ++ * @dl_info: Linked list of hardware parameters exposed through driverlink ++ * @dl_node: Driverlink port list ++ * @dl_device_list: Driverlink device list ++ * @dl_cb: Driverlink callbacks table ++ * @dl_cb_dev: Driverlink callback owner devices + * + * The @priv field of the corresponding &struct net_device points to + * this. +@@ -752,6 +760,13 @@ struct efx_nic { + unsigned int loopback_modes; + + void *loopback_selftest; ++ ++ const char *silicon_rev; ++ struct efx_dl_device_info *dl_info; ++ struct list_head dl_node; ++ struct list_head dl_device_list; ++ struct efx_dl_callbacks dl_cb; ++ struct efx_dl_cb_devices dl_cb_dev; + }; + + static inline int efx_dev_registered(struct efx_nic *efx) +Index: head-2008-08-18/drivers/net/sfc/rx.c +=================================================================== +--- head-2008-08-18.orig/drivers/net/sfc/rx.c 2008-08-18 10:16:43.000000000 +0200 ++++ head-2008-08-18/drivers/net/sfc/rx.c 2008-08-18 10:16:46.000000000 +0200 +@@ -549,8 +549,22 @@ static inline void efx_rx_packet__check_ + static inline void efx_rx_packet_lro(struct efx_channel *channel, + struct efx_rx_buffer *rx_buf) + { ++ struct efx_nic *efx = channel->efx; + struct net_lro_mgr *lro_mgr = &channel->lro_mgr; + void *priv = channel; ++ enum efx_veto veto; ++ ++ /* It would be faster if we had access to packets at the ++ * other side of generic LRO. Unfortunately, there isn't ++ * an obvious interface to this, so veto packets before LRO */ ++ veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len); ++ if (unlikely(veto)) { ++ EFX_TRACE(efx, "LRO RX vetoed by driverlink %s driver\n", ++ efx->dl_cb_dev.rx_packet->driver->name); ++ /* Free the buffer now */ ++ efx_free_rx_buffer(efx, rx_buf); ++ return; ++ } + + /* Pass the skb/page into the LRO engine */ + if (rx_buf->page) { +@@ -686,6 +700,7 @@ void __efx_rx_packet(struct efx_channel + struct efx_rx_buffer *rx_buf, int checksummed) + { + struct efx_nic *efx = channel->efx; ++ enum efx_veto veto; + struct sk_buff *skb; + int lro = efx->net_dev->features & NETIF_F_LRO; + +@@ -723,6 +738,16 @@ void __efx_rx_packet(struct efx_channel + goto done; + } + ++ /* Allow callback to veto the packet */ ++ veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len); ++ if (unlikely(veto)) { ++ EFX_LOG(efx, "RX vetoed by driverlink %s driver\n", ++ efx->dl_cb_dev.rx_packet->driver->name); ++ /* Free the buffer now */ ++ efx_free_rx_buffer(efx, rx_buf); ++ goto done; ++ } ++ + /* Form an skb if required */ + if (rx_buf->page) { + int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS); +Index: head-2008-08-18/drivers/net/sfc/tx.c +=================================================================== +--- head-2008-08-18.orig/drivers/net/sfc/tx.c 2008-08-18 10:16:43.000000000 +0200 ++++ head-2008-08-18/drivers/net/sfc/tx.c 2008-08-18 10:16:46.000000000 +0200 +@@ -368,7 +368,21 @@ inline int efx_xmit(struct efx_nic *efx, + int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) + { + struct efx_nic *efx = net_dev->priv; +- return efx_xmit(efx, &efx->tx_queue[0], skb); ++ struct efx_tx_queue *tx_queue = &efx->tx_queue[0]; ++ enum efx_veto veto; ++ ++ /* See if driverlink wants to veto the packet. */ ++ veto = EFX_DL_CALLBACK(efx, tx_packet, skb); ++ if (unlikely(veto)) { ++ EFX_TRACE(efx, "TX queue %d packet vetoed by " ++ "driverlink %s driver\n", tx_queue->queue, ++ efx->dl_cb_dev.tx_packet->driver->name); ++ /* Free the skb; nothing else will do it */ ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++ return efx_xmit(efx, tx_queue, skb); + } + + void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) diff --git a/src/patches/suse-2.6.27.31/patches.xen/sfc-driverlink-conditional b/src/patches/suse-2.6.27.31/patches.xen/sfc-driverlink-conditional new file mode 100644 index 000000000..412c5d538 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/sfc-driverlink-conditional @@ -0,0 +1,264 @@ +From: jbeulich@novell.com +Subject: conditionalize driverlink additions to Solarflare driver +Patch-mainline: obsolete +References: FATE#303479 + +At once converted the EFX_TRACE() invocations after vetoed RX/TX +callbacks to ...LOG() ones, which is consistent with Solarflare's +current code according to David Riddoch (2008-09-12). + +Index: head-2008-09-01/drivers/net/sfc/Kconfig +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/Kconfig 2008-07-17 16:18:07.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/Kconfig 2008-09-12 14:01:48.000000000 +0200 +@@ -13,8 +13,12 @@ config SFC + To compile this driver as a module, choose M here. The module + will be called sfc. + ++config SFC_DRIVERLINK ++ bool ++ + config SFC_RESOURCE + depends on SFC && X86 ++ select SFC_DRIVERLINK + tristate "Solarflare Solarstorm SFC4000 resource driver" + help + This module provides the SFC resource manager driver. +Index: head-2008-09-01/drivers/net/sfc/Makefile +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/Makefile 2008-07-17 16:18:07.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/Makefile 2008-09-12 12:22:05.000000000 +0200 +@@ -1,7 +1,7 @@ + sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \ + selftest.o ethtool.o xfp_phy.o \ +- mdio_10g.o tenxpress.o boards.o sfe4001.o \ +- driverlink.o ++ mdio_10g.o tenxpress.o boards.o sfe4001.o ++sfc-$(CONFIG_SFC_DRIVERLINK) += driverlink.o + obj-$(CONFIG_SFC) += sfc.o + + obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/ +Index: head-2008-09-01/drivers/net/sfc/driverlink.c +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/driverlink.c 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/driverlink.c 2008-09-12 13:57:29.000000000 +0200 +@@ -14,7 +14,6 @@ + #include + #include "net_driver.h" + #include "efx.h" +-#include "driverlink_api.h" + #include "driverlink.h" + + /* Protects @efx_driverlink_lock and @efx_driver_list */ +Index: head-2008-09-01/drivers/net/sfc/driverlink.h +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/driverlink.h 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/driverlink.h 2008-09-12 16:14:04.000000000 +0200 +@@ -15,6 +15,10 @@ + struct efx_dl_device; + struct efx_nic; + ++#ifdef CONFIG_SFC_DRIVERLINK ++ ++#include "driverlink_api.h" ++ + /* Efx callback devices + * + * A list of the devices that own each callback. The partner to +@@ -40,4 +44,23 @@ extern void efx_dl_unregister_nic(struct + extern void efx_dl_reset_suspend(struct efx_nic *efx); + extern void efx_dl_reset_resume(struct efx_nic *efx, int ok); + ++#define EFX_DL_LOG EFX_LOG ++ ++#else /* CONFIG_SFC_DRIVERLINK */ ++ ++enum efx_veto { EFX_ALLOW_PACKET = 0 }; ++ ++static inline int efx_nop_callback(struct efx_nic *efx) { return 0; } ++#define EFX_DL_CALLBACK(port, name, ...) efx_nop_callback(port) ++ ++static inline int efx_dl_register_nic(struct efx_nic *efx) { return 0; } ++static inline void efx_dl_unregister_nic(struct efx_nic *efx) {} ++ ++static inline void efx_dl_reset_suspend(struct efx_nic *efx) {} ++static inline void efx_dl_reset_resume(struct efx_nic *efx, int ok) {} ++ ++#define EFX_DL_LOG(efx, fmt, args...) ((void)(efx)) ++ ++#endif /* CONFIG_SFC_DRIVERLINK */ ++ + #endif /* EFX_DRIVERLINK_H */ +Index: head-2008-09-01/drivers/net/sfc/efx.c +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/efx.c 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/efx.c 2008-09-12 12:42:32.000000000 +0200 +@@ -1596,6 +1596,7 @@ static void efx_unregister_netdev(struct + * Device reset and suspend + * + **************************************************************************/ ++#ifdef CONFIG_SFC_DRIVERLINK + /* Serialise access to the driverlink callbacks, by quiescing event processing + * (without flushing the descriptor queues), and acquiring the rtnl_lock */ + void efx_suspend(struct efx_nic *efx) +@@ -1613,6 +1614,7 @@ void efx_resume(struct efx_nic *efx) + efx_start_all(efx); + rtnl_unlock(); + } ++#endif + + /* The final hardware and software finalisation before reset. */ + static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) +@@ -1899,9 +1901,11 @@ static int efx_init_struct(struct efx_ni + mutex_init(&efx->mac_lock); + efx->phy_op = &efx_dummy_phy_operations; + efx->mii.dev = net_dev; ++#ifdef CONFIG_SFC_DRIVERLINK + INIT_LIST_HEAD(&efx->dl_node); + INIT_LIST_HEAD(&efx->dl_device_list); + efx->dl_cb = efx_default_callbacks; ++#endif + INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); + atomic_set(&efx->netif_stop_count, 1); + +Index: head-2008-09-01/drivers/net/sfc/falcon.c +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/falcon.c 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/falcon.c 2008-09-12 13:51:32.000000000 +0200 +@@ -36,12 +36,17 @@ + + /** + * struct falcon_nic_data - Falcon NIC state ++ * @next_buffer_table: First available buffer table id + * @resources: Resource information for driverlink client + * @pci_dev2: The secondary PCI device if present + * @i2c_data: Operations and state for I2C bit-bashing algorithm + */ + struct falcon_nic_data { ++#ifndef CONFIG_SFC_DRIVERLINK ++ unsigned next_buffer_table; ++#else + struct efx_dl_falcon_resources resources; ++#endif + struct pci_dev *pci_dev2; + struct i2c_algo_bit_data i2c_data; + }; +@@ -322,8 +327,13 @@ static int falcon_alloc_special_buffer(s + memset(buffer->addr, 0xff, len); + + /* Select new buffer ID */ ++#ifndef CONFIG_SFC_DRIVERLINK ++ buffer->index = nic_data->next_buffer_table; ++ nic_data->next_buffer_table += buffer->entries; ++#else + buffer->index = nic_data->resources.buffer_table_min; + nic_data->resources.buffer_table_min += buffer->entries; ++#endif + + EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " + "(virt %p phys %lx)\n", buffer->index, +@@ -2382,6 +2392,7 @@ static int falcon_probe_nvconfig(struct + * should live. */ + static int falcon_dimension_resources(struct efx_nic *efx) + { ++#ifdef CONFIG_SFC_DRIVERLINK + unsigned internal_dcs_entries; + struct falcon_nic_data *nic_data = efx->nic_data; + struct efx_dl_falcon_resources *res = &nic_data->resources; +@@ -2426,6 +2437,7 @@ static int falcon_dimension_resources(st + + if (EFX_INT_MODE_USE_MSI(efx)) + res->flags |= EFX_DL_FALCON_USE_MSI; ++#endif + + return 0; + } +@@ -2551,7 +2563,9 @@ int falcon_probe_nic(struct efx_nic *efx + return 0; + + fail6: ++#ifdef CONFIG_SFC_DRIVERLINK + efx->dl_info = NULL; ++#endif + fail5: + falcon_free_buffer(efx, &efx->irq_status); + fail4: +@@ -2742,7 +2756,9 @@ void falcon_remove_nic(struct efx_nic *e + /* Tear down the private nic state */ + kfree(efx->nic_data); + efx->nic_data = NULL; ++#ifdef CONFIG_SFC_DRIVERLINK + efx->dl_info = NULL; ++#endif + } + + void falcon_update_nic_stats(struct efx_nic *efx) +Index: head-2008-09-01/drivers/net/sfc/net_driver.h +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/net_driver.h 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/net_driver.h 2008-09-12 13:57:19.000000000 +0200 +@@ -30,7 +30,6 @@ + + #include "enum.h" + #include "bitfield.h" +-#include "driverlink_api.h" + #include "driverlink.h" + + #define EFX_MAX_LRO_DESCRIPTORS 8 +@@ -762,11 +761,13 @@ struct efx_nic { + void *loopback_selftest; + + const char *silicon_rev; ++#ifdef CONFIG_SFC_DRIVERLINK + struct efx_dl_device_info *dl_info; + struct list_head dl_node; + struct list_head dl_device_list; + struct efx_dl_callbacks dl_cb; + struct efx_dl_cb_devices dl_cb_dev; ++#endif + }; + + static inline int efx_dev_registered(struct efx_nic *efx) +Index: head-2008-09-01/drivers/net/sfc/rx.c +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/rx.c 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/rx.c 2008-09-12 16:13:49.000000000 +0200 +@@ -559,8 +559,8 @@ static inline void efx_rx_packet_lro(str + * an obvious interface to this, so veto packets before LRO */ + veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len); + if (unlikely(veto)) { +- EFX_TRACE(efx, "LRO RX vetoed by driverlink %s driver\n", +- efx->dl_cb_dev.rx_packet->driver->name); ++ EFX_DL_LOG(efx, "LRO RX vetoed by driverlink %s driver\n", ++ efx->dl_cb_dev.rx_packet->driver->name); + /* Free the buffer now */ + efx_free_rx_buffer(efx, rx_buf); + return; +@@ -741,8 +741,8 @@ void __efx_rx_packet(struct efx_channel + /* Allow callback to veto the packet */ + veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len); + if (unlikely(veto)) { +- EFX_LOG(efx, "RX vetoed by driverlink %s driver\n", +- efx->dl_cb_dev.rx_packet->driver->name); ++ EFX_DL_LOG(efx, "RX vetoed by driverlink %s driver\n", ++ efx->dl_cb_dev.rx_packet->driver->name); + /* Free the buffer now */ + efx_free_rx_buffer(efx, rx_buf); + goto done; +Index: head-2008-09-01/drivers/net/sfc/tx.c +=================================================================== +--- head-2008-09-01.orig/drivers/net/sfc/tx.c 2008-08-18 10:16:46.000000000 +0200 ++++ head-2008-09-01/drivers/net/sfc/tx.c 2008-09-12 16:13:34.000000000 +0200 +@@ -374,9 +374,9 @@ int efx_hard_start_xmit(struct sk_buff * + /* See if driverlink wants to veto the packet. */ + veto = EFX_DL_CALLBACK(efx, tx_packet, skb); + if (unlikely(veto)) { +- EFX_TRACE(efx, "TX queue %d packet vetoed by " +- "driverlink %s driver\n", tx_queue->queue, +- efx->dl_cb_dev.tx_packet->driver->name); ++ EFX_DL_LOG(efx, "TX queue %d packet vetoed by " ++ "driverlink %s driver\n", tx_queue->queue, ++ efx->dl_cb_dev.tx_packet->driver->name); + /* Free the skb; nothing else will do it */ + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; diff --git a/src/patches/suse-2.6.27.31/patches.xen/sfc-external-sram b/src/patches/suse-2.6.27.31/patches.xen/sfc-external-sram new file mode 100644 index 000000000..6baf31d16 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/sfc-external-sram @@ -0,0 +1,302 @@ +From: Kieran Mansley +Subject: enable access to Falcon's external SRAM +References: bnc#489105 + +Include ability to reference external SRAM on Solarflare Falcon NICs to +allow event queues to be accessed by virtualised guests. + +Acked-by: bphilips@novell.com + +--- sle11-2009-04-09.orig/drivers/net/sfc/falcon.c 2009-03-30 15:58:20.000000000 +0200 ++++ sle11-2009-04-09/drivers/net/sfc/falcon.c 2009-03-30 15:58:59.000000000 +0200 +@@ -36,12 +36,18 @@ + + /** + * struct falcon_nic_data - Falcon NIC state ++ * @sram_cfg: SRAM configuration value ++ * @tx_dc_base: Base address in SRAM of TX queue descriptor caches ++ * @rx_dc_base: Base address in SRAM of RX queue descriptor caches + * @next_buffer_table: First available buffer table id + * @resources: Resource information for driverlink client + * @pci_dev2: The secondary PCI device if present + * @i2c_data: Operations and state for I2C bit-bashing algorithm + */ + struct falcon_nic_data { ++ int sram_cfg; ++ unsigned tx_dc_base; ++ unsigned rx_dc_base; + #ifndef CONFIG_SFC_DRIVERLINK + unsigned next_buffer_table; + #else +@@ -69,11 +75,11 @@ static int disable_dma_stats; + */ + #define TX_DC_ENTRIES 16 + #define TX_DC_ENTRIES_ORDER 0 +-#define TX_DC_BASE 0x130000 ++#define TX_DC_INTERNAL_BASE 0x130000 + + #define RX_DC_ENTRIES 64 + #define RX_DC_ENTRIES_ORDER 2 +-#define RX_DC_BASE 0x100000 ++#define RX_DC_INTERNAL_BASE 0x100000 + + /* RX FIFO XOFF watermark + * +@@ -454,9 +460,17 @@ void falcon_push_buffers(struct efx_tx_q + int falcon_probe_tx(struct efx_tx_queue *tx_queue) + { + struct efx_nic *efx = tx_queue->efx; +- return falcon_alloc_special_buffer(efx, &tx_queue->txd, +- FALCON_TXD_RING_SIZE * +- sizeof(efx_qword_t)); ++ int rc = falcon_alloc_special_buffer(efx, &tx_queue->txd, ++ FALCON_TXD_RING_SIZE * ++ sizeof(efx_qword_t)); ++#ifdef CONFIG_SFC_DRIVERLINK ++ if (rc == 0) { ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ nic_data->resources.txq_min = max(nic_data->resources.txq_min, ++ (unsigned)tx_queue->queue + 1); ++ } ++#endif ++ return rc; + } + + int falcon_init_tx(struct efx_tx_queue *tx_queue) +@@ -643,9 +657,17 @@ void falcon_notify_rx_desc(struct efx_rx + int falcon_probe_rx(struct efx_rx_queue *rx_queue) + { + struct efx_nic *efx = rx_queue->efx; +- return falcon_alloc_special_buffer(efx, &rx_queue->rxd, +- FALCON_RXD_RING_SIZE * +- sizeof(efx_qword_t)); ++ int rc = falcon_alloc_special_buffer(efx, &rx_queue->rxd, ++ FALCON_RXD_RING_SIZE * ++ sizeof(efx_qword_t)); ++#ifdef CONFIG_SFC_DRIVERLINK ++ if (rc == 0) { ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ nic_data->resources.rxq_min = max(nic_data->resources.rxq_min, ++ (unsigned)rx_queue->queue + 1); ++ } ++#endif ++ return rc; + } + + int falcon_init_rx(struct efx_rx_queue *rx_queue) +@@ -1276,9 +1298,18 @@ int falcon_probe_eventq(struct efx_chann + { + struct efx_nic *efx = channel->efx; + unsigned int evq_size; ++ int rc; + + evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t); +- return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size); ++ rc = falcon_alloc_special_buffer(efx, &channel->eventq, evq_size); ++#ifdef CONFIG_SFC_DRIVERLINK ++ if (rc == 0) { ++ struct falcon_nic_data *nic_data = efx->nic_data; ++ nic_data->resources.evq_int_min = max(nic_data->resources.evq_int_min, ++ (unsigned)channel->evqnum + 1); ++ } ++#endif ++ return rc; + } + + int falcon_init_eventq(struct efx_channel *channel) +@@ -2285,19 +2316,22 @@ fail5: + */ + static int falcon_reset_sram(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker; +- int count; ++ int count, onchip, sram_cfg_val; + + /* Set the SRAM wake/sleep GPIO appropriately. */ ++ onchip = (nic_data->sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY); + falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1); +- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1); ++ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, onchip); + falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER); + + /* Initiate SRAM reset */ ++ sram_cfg_val = onchip ? 0 : nic_data->sram_cfg; + EFX_POPULATE_OWORD_2(srm_cfg_reg_ker, + SRAM_OOB_BT_INIT_EN, 1, +- SRM_NUM_BANKS_AND_BANK_SIZE, 0); ++ SRM_NUM_BANKS_AND_BANK_SIZE, sram_cfg_val); + falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER); + + /* Wait for SRAM reset to complete */ +@@ -2324,12 +2358,14 @@ static int falcon_reset_sram(struct efx_ + /* Extract non-volatile configuration */ + static int falcon_probe_nvconfig(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + struct falcon_nvconfig *nvconfig; + efx_oword_t nic_stat; + int device_id; + unsigned addr_len; + size_t offset, len; + int magic_num, struct_ver, board_rev; ++ bool onchip_sram; + int rc; + + /* Find the boot device. */ +@@ -2370,18 +2406,41 @@ static int falcon_probe_nvconfig(struct + efx->phy_type = PHY_TYPE_NONE; + efx->mii.phy_id = PHY_ADDR_INVALID; + board_rev = 0; ++ onchip_sram = true; + } else { + struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2; + + efx->phy_type = v2->port0_phy_type; + efx->mii.phy_id = v2->port0_phy_addr; + board_rev = le16_to_cpu(v2->board_revision); ++#ifdef CONFIG_SFC_DRIVERLINK ++ onchip_sram = EFX_OWORD_FIELD(nvconfig->nic_stat_reg, ++ ONCHIP_SRAM); ++#else ++ /* We have no use for external SRAM */ ++ onchip_sram = true; ++#endif + } + + EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id); + + efx_set_board_info(efx, board_rev); + ++ /* Read the SRAM configuration. The register is initialised ++ * automatically but might may been reset since boot. ++ */ ++ if (onchip_sram) { ++ nic_data->sram_cfg = SRM_NB_BSZ_ONCHIP_ONLY; ++ } else { ++ nic_data->sram_cfg = ++ EFX_OWORD_FIELD(nvconfig->srm_cfg_reg, ++ SRM_NUM_BANKS_AND_BANK_SIZE); ++ WARN_ON(nic_data->sram_cfg == SRM_NB_BSZ_RESERVED); ++ /* Replace invalid setting with the smallest defaults */ ++ if (nic_data->sram_cfg == SRM_NB_BSZ_DEFAULT) ++ nic_data->sram_cfg = SRM_NB_BSZ_1BANKS_2M; ++ } ++ + out: + kfree(nvconfig); + return rc; +@@ -2392,9 +2451,9 @@ static int falcon_probe_nvconfig(struct + * should live. */ + static int falcon_dimension_resources(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + #ifdef CONFIG_SFC_DRIVERLINK + unsigned internal_dcs_entries; +- struct falcon_nic_data *nic_data = efx->nic_data; + struct efx_dl_falcon_resources *res = &nic_data->resources; + + /* Fill out the driverlink resource list */ +@@ -2427,16 +2486,64 @@ static int falcon_dimension_resources(st + break; + } + +- /* Internal SRAM only for now */ +- res->rxq_lim = internal_dcs_entries / RX_DC_ENTRIES; +- res->txq_lim = internal_dcs_entries / TX_DC_ENTRIES; +- res->buffer_table_lim = 8192; ++ if (nic_data->sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY) { ++ res->rxq_lim = internal_dcs_entries / RX_DC_ENTRIES; ++ res->txq_lim = internal_dcs_entries / TX_DC_ENTRIES; ++ res->buffer_table_lim = 8192; ++ nic_data->tx_dc_base = TX_DC_INTERNAL_BASE; ++ nic_data->rx_dc_base = RX_DC_INTERNAL_BASE; ++ } else { ++ unsigned sram_bytes, vnic_bytes, max_vnics, n_vnics, dcs; ++ ++ /* Determine how much SRAM we have to play with. We have ++ * to fit buffer table and descriptor caches in. ++ */ ++ switch (nic_data->sram_cfg) { ++ case SRM_NB_BSZ_1BANKS_2M: ++ default: ++ sram_bytes = 2 * 1024 * 1024; ++ break; ++ case SRM_NB_BSZ_1BANKS_4M: ++ case SRM_NB_BSZ_2BANKS_4M: ++ sram_bytes = 4 * 1024 * 1024; ++ break; ++ case SRM_NB_BSZ_1BANKS_8M: ++ case SRM_NB_BSZ_2BANKS_8M: ++ sram_bytes = 8 * 1024 * 1024; ++ break; ++ case SRM_NB_BSZ_2BANKS_16M: ++ sram_bytes = 16 * 1024 * 1024; ++ break; ++ } ++ /* For each VNIC allow at least 512 buffer table entries ++ * and descriptor cache for an rxq and txq. Buffer table ++ * space for evqs and dmaqs is relatively trivial, so not ++ * considered in this calculation. ++ */ ++ vnic_bytes = 512 * 8 + RX_DC_ENTRIES * 8 + TX_DC_ENTRIES * 8; ++ max_vnics = sram_bytes / vnic_bytes; ++ for (n_vnics = 1; n_vnics < res->evq_timer_min + max_vnics;) ++ n_vnics *= 2; ++ res->rxq_lim = n_vnics; ++ res->txq_lim = n_vnics; ++ ++ dcs = n_vnics * TX_DC_ENTRIES * 8; ++ nic_data->tx_dc_base = sram_bytes - dcs; ++ dcs = n_vnics * RX_DC_ENTRIES * 8; ++ nic_data->rx_dc_base = nic_data->tx_dc_base - dcs; ++ res->buffer_table_lim = nic_data->rx_dc_base / 8; ++ } + + if (FALCON_IS_DUAL_FUNC(efx)) + res->flags |= EFX_DL_FALCON_DUAL_FUNC; + + if (EFX_INT_MODE_USE_MSI(efx)) + res->flags |= EFX_DL_FALCON_USE_MSI; ++#else ++ /* We ignore external SRAM */ ++ EFX_BUG_ON_PARANOID(nic_data->sram_cfg != SRM_NB_BSZ_ONCHIP_ONLY); ++ nic_data->tx_dc_base = TX_DC_INTERNAL_BASE; ++ nic_data->rx_dc_base = RX_DC_INTERNAL_BASE; + #endif + + return 0; +@@ -2586,6 +2693,7 @@ int falcon_probe_nic(struct efx_nic *efx + */ + int falcon_init_nic(struct efx_nic *efx) + { ++ struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t temp; + unsigned thresh; + int rc; +@@ -2599,9 +2707,10 @@ int falcon_init_nic(struct efx_nic *efx) + ADR_REGION3, (3 << 16)); + falcon_write(efx, &temp, ADR_REGION_REG_KER); + +- /* Use on-chip SRAM */ ++ /* Use on-chip SRAM if wanted. */ + falcon_read(efx, &temp, NIC_STAT_REG); +- EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1); ++ EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, ++ nic_data->sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY); + falcon_write(efx, &temp, NIC_STAT_REG); + + /* Set buffer table mode */ +@@ -2613,9 +2722,9 @@ int falcon_init_nic(struct efx_nic *efx) + return rc; + + /* Set positions of descriptor caches in SRAM. */ +- EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8); ++ EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, nic_data->tx_dc_base / 8); + falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER); +- EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8); ++ EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, nic_data->rx_dc_base / 8); + falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER); + + /* Set TX descriptor cache size. */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/sfc-resource-driver b/src/patches/suse-2.6.27.31/patches.xen/sfc-resource-driver new file mode 100644 index 000000000..a07bfd0b8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/sfc-resource-driver @@ -0,0 +1,15194 @@ +From: David Riddoch +# replaces http://xenbits.xensource.com/linux-2.6.18-xen.hg c/s 421: +# HG changeset patch +# User Keir Fraser +# Date 1203330569 0 +# Node ID e4dd072db2595c420bb21d9e835416f4fd543526 +# Parent fc90e9b2c12b316b5460ece28f013e6de881af1a +Subject: Solarflare: Resource driver. +References: FATE#303479 +Acked-by: jbeulich@novell.com + +Index: head-2008-07-15/drivers/net/sfc/Kconfig +=================================================================== +--- head-2008-07-15.orig/drivers/net/sfc/Kconfig 2008-07-17 16:17:36.000000000 +0200 ++++ head-2008-07-15/drivers/net/sfc/Kconfig 2008-07-17 16:18:07.000000000 +0200 +@@ -12,3 +12,9 @@ config SFC + + To compile this driver as a module, choose M here. The module + will be called sfc. ++ ++config SFC_RESOURCE ++ depends on SFC && X86 ++ tristate "Solarflare Solarstorm SFC4000 resource driver" ++ help ++ This module provides the SFC resource manager driver. +Index: head-2008-07-15/drivers/net/sfc/Makefile +=================================================================== +--- head-2008-07-15.orig/drivers/net/sfc/Makefile 2008-07-17 16:17:53.000000000 +0200 ++++ head-2008-07-15/drivers/net/sfc/Makefile 2008-07-17 16:18:07.000000000 +0200 +@@ -3,3 +3,5 @@ sfc-y += efx.o falcon.o tx.o rx.o falc + mdio_10g.o tenxpress.o boards.o sfe4001.o \ + driverlink.o + obj-$(CONFIG_SFC) += sfc.o ++ ++obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/Makefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/Makefile 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,14 @@ ++obj-$(CONFIG_SFC_RESOURCE) := sfc_resource.o ++ ++EXTRA_CFLAGS += -D__CI_HARDWARE_CONFIG_FALCON__ ++EXTRA_CFLAGS += -D__ci_driver__ ++EXTRA_CFLAGS += -Werror ++EXTRA_CFLAGS += -Idrivers/net/sfc -Idrivers/net/sfc/sfc_resource ++ ++sfc_resource-objs := resource_driver.o iopage.o efx_vi_shm.o \ ++ driverlink_new.o kernel_proc.o kfifo.o \ ++ nic.o eventq.o falcon.o falcon_hash.o \ ++ assert_valid.o buddy.o buffer_table.o filter_resource.o \ ++ iobufset_resource.o resource_manager.o resources.o \ ++ vi_resource_alloc.o vi_resource_event.o vi_resource_flush.o \ ++ vi_resource_manager.o driver_object.o kernel_compat.o +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/assert_valid.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/assert_valid.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,92 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains functions to assert validness of resources and ++ * resource manager in DEBUG build of the resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++ ++#ifndef NDEBUG ++#include ++#include ++#include ++ ++void ++efrm_resource_manager_assert_valid(struct efrm_resource_manager *rm, ++ const char *file, int line) ++{ ++ _EFRM_ASSERT(rm, file, line); ++ _EFRM_ASSERT(rm->rm_name, file, line); ++ _EFRM_ASSERT(rm->rm_type < EFRM_RESOURCE_NUM, file, line); ++ _EFRM_ASSERT(rm->rm_dtor, file, line); ++} ++EXPORT_SYMBOL(efrm_resource_manager_assert_valid); ++ ++/* ++ * \param rs resource to validate ++ * \param ref_count_is_zero One of 3 values ++ * > 0 - check ref count is zero ++ * = 0 - check ref count is non-zero ++ * < 0 - ref count could be any value ++ */ ++void ++efrm_resource_assert_valid(struct efrm_resource *rs, int ref_count_is_zero, ++ const char *file, int line) ++{ ++ struct efrm_resource_manager *rm; ++ ++ _EFRM_ASSERT(rs, file, line); ++ ++ if (ref_count_is_zero >= 0) { ++ if (!(ref_count_is_zero || rs->rs_ref_count > 0) ++ || !(!ref_count_is_zero || rs->rs_ref_count == 0)) ++ EFRM_WARN("%s: check %szero ref=%d " EFRM_RESOURCE_FMT, ++ __func__, ++ ref_count_is_zero == 0 ? "non-" : "", ++ rs->rs_ref_count, ++ EFRM_RESOURCE_PRI_ARG(rs->rs_handle)); ++ ++ _EFRM_ASSERT(!(ref_count_is_zero == 0) || ++ rs->rs_ref_count != 0, file, line); ++ _EFRM_ASSERT(!(ref_count_is_zero > 0) || ++ rs->rs_ref_count == 0, file, line); ++ } ++ ++ rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)]; ++ efrm_resource_manager_assert_valid(rm, file, line); ++} ++EXPORT_SYMBOL(efrm_resource_assert_valid); ++ ++#endif +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/buddy.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/buddy.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,220 @@ ++ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains implementation of a buddy allocator. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include /* get uintXX types on win32 */ ++#include ++#include ++#include ++ ++#if 1 ++#define DEBUG_ALLOC(x) ++#else ++#define DEBUG_ALLOC(x) x ++ ++static inline void efrm_buddy_dump(struct efrm_buddy_allocator *b) ++{ ++ unsigned o; ++ ++ EFRM_NOTICE("%s: dump allocator with order %u", ++ __func__, b->order); ++ for (o = 0; o <= b->order; o++) { ++ struct list_head *l = &b->free_lists[o]; ++ while (l->next != &b->free_lists[o]) { ++ l = l->next; ++ EFRM_NOTICE("%s: order %x: %zx", __func__, o, ++ l - b->links); ++ } ++ } ++} ++#endif ++ ++/* ++ * The purpose of the following inline functions is to give the ++ * understandable names to the simple actions. ++ */ ++static inline void ++efrm_buddy_free_list_add(struct efrm_buddy_allocator *b, ++ unsigned order, unsigned addr) ++{ ++ list_add(&b->links[addr], &b->free_lists[order]); ++ b->orders[addr] = (uint8_t) order; ++} ++static inline void ++efrm_buddy_free_list_del(struct efrm_buddy_allocator *b, unsigned addr) ++{ ++ list_del(&b->links[addr]); ++ b->links[addr].next = NULL; ++} ++static inline int ++efrm_buddy_free_list_empty(struct efrm_buddy_allocator *b, unsigned order) ++{ ++ return list_empty(&b->free_lists[order]); ++} ++static inline unsigned ++efrm_buddy_free_list_pop(struct efrm_buddy_allocator *b, unsigned order) ++{ ++ struct list_head *l = list_pop(&b->free_lists[order]); ++ l->next = NULL; ++ return (unsigned)(l - b->links); ++} ++static inline int ++efrm_buddy_addr_in_free_list(struct efrm_buddy_allocator *b, unsigned addr) ++{ ++ return b->links[addr].next != NULL; ++} ++static inline unsigned ++efrm_buddy_free_list_first(struct efrm_buddy_allocator *b, unsigned order) ++{ ++ return (unsigned)(b->free_lists[order].next - b->links); ++} ++ ++int efrm_buddy_ctor(struct efrm_buddy_allocator *b, unsigned order) ++{ ++ unsigned o; ++ unsigned size = 1 << order; ++ ++ DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __func__, order)); ++ EFRM_ASSERT(b); ++ EFRM_ASSERT(order <= sizeof(unsigned) * 8 - 1); ++ ++ b->order = order; ++ b->free_lists = vmalloc((order + 1) * sizeof(struct list_head)); ++ if (b->free_lists == NULL) ++ goto fail1; ++ ++ b->links = vmalloc(size * sizeof(struct list_head)); ++ if (b->links == NULL) ++ goto fail2; ++ ++ b->orders = vmalloc(size); ++ if (b->orders == NULL) ++ goto fail3; ++ ++ memset(b->links, 0, size * sizeof(struct list_head)); ++ ++ for (o = 0; o <= b->order; ++o) ++ INIT_LIST_HEAD(b->free_lists + o); ++ ++ efrm_buddy_free_list_add(b, b->order, 0); ++ ++ return 0; ++ ++fail3: ++ vfree(b->links); ++fail2: ++ vfree(b->free_lists); ++fail1: ++ return -ENOMEM; ++} ++ ++void efrm_buddy_dtor(struct efrm_buddy_allocator *b) ++{ ++ EFRM_ASSERT(b); ++ ++ vfree(b->free_lists); ++ vfree(b->links); ++ vfree(b->orders); ++} ++ ++int efrm_buddy_alloc(struct efrm_buddy_allocator *b, unsigned order) ++{ ++ unsigned smallest; ++ unsigned addr; ++ ++ DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __func__, order)); ++ EFRM_ASSERT(b); ++ ++ /* Find smallest chunk that is big enough. ?? Can optimise this by ++ ** keeping array of pointers to smallest chunk for each order. ++ */ ++ smallest = order; ++ while (smallest <= b->order && ++ efrm_buddy_free_list_empty(b, smallest)) ++ ++smallest; ++ ++ if (smallest > b->order) { ++ DEBUG_ALLOC(EFRM_NOTICE ++ ("buddy - alloc order %d failed - max order %d", ++ order, b->order);); ++ return -ENOMEM; ++ } ++ ++ /* Split blocks until we get one of the correct size. */ ++ addr = efrm_buddy_free_list_pop(b, smallest); ++ ++ DEBUG_ALLOC(EFRM_NOTICE("buddy - alloc %x order %d cut from order %d", ++ addr, order, smallest);); ++ while (smallest-- > order) ++ efrm_buddy_free_list_add(b, smallest, addr + (1 << smallest)); ++ ++ EFRM_DO_DEBUG(b->orders[addr] = (uint8_t) order); ++ ++ EFRM_ASSERT(addr < 1u << b->order); ++ return addr; ++} ++ ++void ++efrm_buddy_free(struct efrm_buddy_allocator *b, unsigned addr, ++ unsigned order) ++{ ++ unsigned buddy_addr; ++ ++ DEBUG_ALLOC(EFRM_NOTICE("%s(%u, %u)", __func__, addr, order)); ++ EFRM_ASSERT(b); ++ EFRM_ASSERT(order <= b->order); ++ EFRM_ASSERT((unsigned long)addr + ((unsigned long)1 << order) <= ++ (unsigned long)1 << b->order); ++ EFRM_ASSERT(!efrm_buddy_addr_in_free_list(b, addr)); ++ EFRM_ASSERT(b->orders[addr] == order); ++ ++ /* merge free blocks */ ++ while (order < b->order) { ++ buddy_addr = addr ^ (1 << order); ++ if (!efrm_buddy_addr_in_free_list(b, buddy_addr) || ++ b->orders[buddy_addr] != order) ++ break; ++ efrm_buddy_free_list_del(b, buddy_addr); ++ if (buddy_addr < addr) ++ addr = buddy_addr; ++ ++order; ++ } ++ ++ DEBUG_ALLOC(EFRM_NOTICE ++ ("buddy - free %x merged into order %d", addr, order);); ++ efrm_buddy_free_list_add(b, order, addr); ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/buffer_table.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/buffer_table.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,209 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains abstraction of the buffer table on the NIC. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++/* ++** Might be worth keeping a bitmap of which entries are clear. Then we ++** wouldn't need to clear them all again when we free an allocation. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/*! Comment? */ ++struct efrm_buffer_table { ++ spinlock_t lock; ++ struct efrm_buddy_allocator buddy; ++}; ++ ++/* Efab buffer state. */ ++static struct efrm_buffer_table efrm_buffers; ++ ++int efrm_buffer_table_ctor(unsigned low, unsigned high) ++{ ++ int log2_n_entries, rc, i; ++ ++ EFRM_ASSERT(high > 0); ++ EFRM_ASSERT(low < high); ++ ++ EFRM_TRACE("%s: low=%u high=%u", __func__, low, high); ++ EFRM_NOTICE("%s: low=%u high=%u", __func__, low, high); ++ ++ log2_n_entries = fls(high - 1); ++ ++ rc = efrm_buddy_ctor(&efrm_buffers.buddy, log2_n_entries); ++ if (rc < 0) { ++ EFRM_ERR("efrm_buffer_table_ctor: efrm_buddy_ctor(%d) " ++ "failed (%d)", log2_n_entries, rc); ++ return rc; ++ } ++ for (i = 0; i < (1 << log2_n_entries); ++i) { ++ rc = efrm_buddy_alloc(&efrm_buffers.buddy, 0); ++ EFRM_ASSERT(rc >= 0); ++ EFRM_ASSERT(rc < (1 << log2_n_entries)); ++ } ++ for (i = low; i < (int) high; ++i) ++ efrm_buddy_free(&efrm_buffers.buddy, i, 0); ++ ++ spin_lock_init(&efrm_buffers.lock); ++ ++ EFRM_TRACE("%s: done", __func__); ++ ++ return 0; ++} ++ ++void efrm_buffer_table_dtor(void) ++{ ++ /* ?? debug check that all allocations have been freed? */ ++ ++ spin_lock_destroy(&efrm_buffers.lock); ++ efrm_buddy_dtor(&efrm_buffers.buddy); ++ ++ EFRM_TRACE("%s: done", __func__); ++} ++ ++/**********************************************************************/ ++ ++int ++efrm_buffer_table_alloc(unsigned order, ++ struct efhw_buffer_table_allocation *a) ++{ ++ irq_flags_t lock_flags; ++ int rc; ++ ++ EFRM_ASSERT(&efrm_buffers.buddy); ++ EFRM_ASSERT(a); ++ ++ /* Round up to multiple of two, as the buffer clear logic works in ++ * pairs when not in "full" mode. */ ++ order = max_t(unsigned, order, 1); ++ ++ spin_lock_irqsave(&efrm_buffers.lock, lock_flags); ++ rc = efrm_buddy_alloc(&efrm_buffers.buddy, order); ++ spin_unlock_irqrestore(&efrm_buffers.lock, lock_flags); ++ ++ if (rc < 0) { ++ EFRM_ERR("efrm_buffer_table_alloc: failed (n=%ld) rc %d", ++ 1ul << order, rc); ++ return rc; ++ } ++ ++ EFRM_TRACE("efrm_buffer_table_alloc: base=%d n=%ld", ++ rc, 1ul << order); ++ a->order = order; ++ a->base = (unsigned)rc; ++ return 0; ++} ++ ++void efrm_buffer_table_free(struct efhw_buffer_table_allocation *a) ++{ ++ irq_flags_t lock_flags; ++ struct efhw_nic *nic; ++ int nic_i; ++ ++ EFRM_ASSERT(&efrm_buffers.buddy); ++ EFRM_ASSERT(a); ++ EFRM_ASSERT(a->base != -1); ++ EFRM_ASSERT((unsigned long)a->base + (1ul << a->order) <= ++ efrm_buddy_size(&efrm_buffers.buddy)); ++ ++ EFRM_TRACE("efrm_buffer_table_free: base=%d n=%ld", ++ a->base, (1ul << a->order)); ++ ++ EFRM_FOR_EACH_NIC(nic_i, nic) ++ efhw_nic_buffer_table_clear(nic, a->base, 1ul << a->order); ++ ++ spin_lock_irqsave(&efrm_buffers.lock, lock_flags); ++ efrm_buddy_free(&efrm_buffers.buddy, a->base, a->order); ++ spin_unlock_irqrestore(&efrm_buffers.lock, lock_flags); ++ ++ EFRM_DO_DEBUG(a->base = a->order = -1); ++} ++ ++/**********************************************************************/ ++ ++void ++efrm_buffer_table_set(struct efhw_buffer_table_allocation *a, ++ struct efhw_nic *nic, ++ unsigned i, dma_addr_t dma_addr, int owner) ++{ ++ EFRM_ASSERT(a); ++ EFRM_ASSERT(i < (unsigned)1 << a->order); ++ ++ efhw_nic_buffer_table_set(nic, dma_addr, EFHW_NIC_PAGE_SIZE, ++ 0, owner, a->base + i); ++} ++ ++ ++int efrm_buffer_table_size(void) ++{ ++ return efrm_buddy_size(&efrm_buffers.buddy); ++} ++ ++/**********************************************************************/ ++ ++int ++efrm_page_register(struct efhw_nic *nic, dma_addr_t dma_addr, int owner, ++ efhw_buffer_addr_t *buf_addr_out) ++{ ++ struct efhw_buffer_table_allocation alloc; ++ int rc; ++ ++ rc = efrm_buffer_table_alloc(0, &alloc); ++ if (rc == 0) { ++ efrm_buffer_table_set(&alloc, nic, 0, dma_addr, owner); ++ efrm_buffer_table_commit(); ++ *buf_addr_out = EFHW_BUFFER_ADDR(alloc.base, 0); ++ } ++ return rc; ++} ++EXPORT_SYMBOL(efrm_page_register); ++ ++void efrm_page_unregister(efhw_buffer_addr_t buf_addr) ++{ ++ struct efhw_buffer_table_allocation alloc; ++ ++ alloc.order = 0; ++ alloc.base = EFHW_BUFFER_PAGE(buf_addr); ++ efrm_buffer_table_free(&alloc); ++} ++EXPORT_SYMBOL(efrm_page_unregister); ++ ++void efrm_buffer_table_commit(void) ++{ ++ struct efhw_nic *nic; ++ int nic_i; ++ ++ EFRM_FOR_EACH_NIC(nic_i, nic) ++ efhw_nic_buffer_table_commit(nic); ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,188 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC hardware interface. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_EFAB_HARDWARE_H__ ++#define __CI_DRIVER_EFAB_HARDWARE_H__ ++ ++#include "ci/driver/efab/hardware/workarounds.h" ++#include ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Common EtherFabric definitions ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#include ++#include ++#include ++ ++/*---------------------------------------------------------------------------- ++ * ++ * EtherFabric varients ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#include ++ ++/*---------------------------------------------------------------------------- ++ * ++ * EtherFabric Portable Hardware Layer defines ++ * ++ *---------------------------------------------------------------------------*/ ++ ++ /*-------------- Initialisation ------------ */ ++#define efhw_nic_close_hardware(nic) \ ++ ((nic)->efhw_func->close_hardware(nic)) ++ ++#define efhw_nic_init_hardware(nic, ev_handlers, mac_addr, non_irq_evq) \ ++ ((nic)->efhw_func->init_hardware((nic), (ev_handlers), (mac_addr), \ ++ (non_irq_evq))) ++ ++/*-------------- Interrupt support ------------ */ ++/** Handle interrupt. Return 0 if not handled, 1 if handled. */ ++#define efhw_nic_interrupt(nic) \ ++ ((nic)->efhw_func->interrupt(nic)) ++ ++#define efhw_nic_interrupt_enable(nic) \ ++ ((nic)->efhw_func->interrupt_enable(nic)) ++ ++#define efhw_nic_interrupt_disable(nic) \ ++ ((nic)->efhw_func->interrupt_disable(nic)) ++ ++#define efhw_nic_set_interrupt_moderation(nic, evq, val) \ ++ ((nic)->efhw_func->set_interrupt_moderation(nic, evq, val)) ++ ++/*-------------- Event support ------------ */ ++ ++#define efhw_nic_event_queue_enable(nic, evq, size, q_base, buf_base, \ ++ interrupting) \ ++ ((nic)->efhw_func->event_queue_enable((nic), (evq), (size), (q_base), \ ++ (buf_base), (interrupting))) ++ ++#define efhw_nic_event_queue_disable(nic, evq, timer_only) \ ++ ((nic)->efhw_func->event_queue_disable(nic, evq, timer_only)) ++ ++#define efhw_nic_wakeup_request(nic, q_base, index, evq) \ ++ ((nic)->efhw_func->wakeup_request(nic, q_base, index, evq)) ++ ++#define efhw_nic_sw_event(nic, data, ev) \ ++ ((nic)->efhw_func->sw_event(nic, data, ev)) ++ ++/*-------------- Filter support ------------ */ ++#define efhw_nic_ipfilter_set(nic, type, index, dmaq, \ ++ saddr, sport, daddr, dport) \ ++ ((nic)->efhw_func->ipfilter_set(nic, type, index, dmaq, \ ++ saddr, sport, daddr, dport)) ++ ++#define efhw_nic_ipfilter_clear(nic, index) \ ++ ((nic)->efhw_func->ipfilter_clear(nic, index)) ++ ++/*-------------- DMA support ------------ */ ++#define efhw_nic_dmaq_tx_q_init(nic, dmaq, evq, owner, tag, \ ++ dmaq_size, index, flags) \ ++ ((nic)->efhw_func->dmaq_tx_q_init(nic, dmaq, evq, owner, tag, \ ++ dmaq_size, index, flags)) ++ ++#define efhw_nic_dmaq_rx_q_init(nic, dmaq, evq, owner, tag, \ ++ dmaq_size, index, flags) \ ++ ((nic)->efhw_func->dmaq_rx_q_init(nic, dmaq, evq, owner, tag, \ ++ dmaq_size, index, flags)) ++ ++#define efhw_nic_dmaq_tx_q_disable(nic, dmaq) \ ++ ((nic)->efhw_func->dmaq_tx_q_disable(nic, dmaq)) ++ ++#define efhw_nic_dmaq_rx_q_disable(nic, dmaq) \ ++ ((nic)->efhw_func->dmaq_rx_q_disable(nic, dmaq)) ++ ++#define efhw_nic_flush_tx_dma_channel(nic, dmaq) \ ++ ((nic)->efhw_func->flush_tx_dma_channel(nic, dmaq)) ++ ++#define efhw_nic_flush_rx_dma_channel(nic, dmaq) \ ++ ((nic)->efhw_func->flush_rx_dma_channel(nic, dmaq)) ++ ++/*-------------- MAC Low level interface ---- */ ++#define efhw_gmac_get_mac_addr(nic) \ ++ ((nic)->gmac->get_mac_addr((nic)->gmac)) ++ ++/*-------------- Buffer table -------------- */ ++#define efhw_nic_buffer_table_set(nic, addr, bufsz, region, \ ++ own_id, buf_id) \ ++ ((nic)->efhw_func->buffer_table_set(nic, addr, bufsz, region, \ ++ own_id, buf_id)) ++ ++#define efhw_nic_buffer_table_set_n(nic, buf_id, addr, bufsz, \ ++ region, n_pages, own_id) \ ++ ((nic)->efhw_func->buffer_table_set_n(nic, buf_id, addr, bufsz, \ ++ region, n_pages, own_id)) ++ ++#define efhw_nic_buffer_table_clear(nic, id, num) \ ++ ((nic)->efhw_func->buffer_table_clear(nic, id, num)) ++ ++#define efhw_nic_buffer_table_commit(nic) \ ++ ((nic)->efhw_func->buffer_table_commit(nic)) ++ ++/*-------------- New filter API ------------ */ ++#define efhw_nic_filter_set(nic, spec, index_out) \ ++ ((nic)->efhw_func->filter_set(nic, spec, index_out)) ++ ++#define efhw_nic_filter_clear(nic, type, index_out) \ ++ ((nic)->efhw_func->filter_clear(nic, type, index_out)) ++ ++ ++/* --- DMA --- */ ++#define EFHW_DMA_ADDRMASK (0xffffffffffffffffULL) ++ ++/* --- Buffers --- */ ++#define EFHW_BUFFER_ADDR FALCON_BUFFER_4K_ADDR ++#define EFHW_BUFFER_PAGE FALCON_BUFFER_4K_PAGE ++#define EFHW_BUFFER_OFF FALCON_BUFFER_4K_OFF ++ ++/* --- Filters --- */ ++#define EFHW_IP_FILTER_NUM FALCON_FILTER_TBL_NUM ++ ++#define EFHW_MAX_PAGE_SIZE FALCON_MAX_PAGE_SIZE ++ ++#if PAGE_SIZE <= EFHW_MAX_PAGE_SIZE ++#define EFHW_NIC_PAGE_SIZE PAGE_SIZE ++#else ++#define EFHW_NIC_PAGE_SIZE EFHW_MAX_PAGE_SIZE ++#endif ++#define EFHW_NIC_PAGE_MASK (~(EFHW_NIC_PAGE_SIZE-1)) ++ ++#endif /* __CI_DRIVER_EFAB_HARDWARE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/common.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/common.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,68 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC hardware interface common ++ * definitions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_EFAB_HARDWARE_COMMON_H__ ++#define __CI_DRIVER_EFAB_HARDWARE_COMMON_H__ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * EtherFabric constants ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#define EFHW_1K 0x00000400u ++#define EFHW_2K 0x00000800u ++#define EFHW_4K 0x00001000u ++#define EFHW_8K 0x00002000u ++#define EFHW_16K 0x00004000u ++#define EFHW_32K 0x00008000u ++#define EFHW_64K 0x00010000u ++#define EFHW_128K 0x00020000u ++#define EFHW_256K 0x00040000u ++#define EFHW_512K 0x00080000u ++#define EFHW_1M 0x00100000u ++#define EFHW_2M 0x00200000u ++#define EFHW_4M 0x00400000u ++#define EFHW_8M 0x00800000u ++#define EFHW_16M 0x01000000u ++#define EFHW_32M 0x02000000u ++#define EFHW_48M 0x03000000u ++#define EFHW_64M 0x04000000u ++#define EFHW_128M 0x08000000u ++#define EFHW_256M 0x10000000u ++#define EFHW_512M 0x20000000u ++#define EFHW_1G 0x40000000u ++#define EFHW_2G 0x80000000u ++#define EFHW_4G 0x100000000ULL ++#define EFHW_8G 0x200000000ULL ++ ++#endif /* __CI_DRIVER_EFAB_HARDWARE_COMMON_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,422 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) specific ++ * definitions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_EFAB_HARDWARE_FALCON_H__ ++#define __CI_DRIVER_EFAB_HARDWARE_FALCON_H__ ++ ++/*---------------------------------------------------------------------------- ++ * Compile options ++ *---------------------------------------------------------------------------*/ ++ ++/* Falcon has an 8K maximum page size. */ ++#define FALCON_MAX_PAGE_SIZE EFHW_8K ++ ++/* include the register definitions */ ++#include ++#include ++#include ++#include ++ ++#define FALCON_DMA_TX_DESC_BYTES 8 ++#define FALCON_DMA_RX_PHYS_DESC_BYTES 8 ++#define FALCON_DMA_RX_BUF_DESC_BYTES 4 ++ ++ ++/* ---- efhw_event_t helpers --- */ ++ ++#ifndef EFHW_IS_LITTLE_ENDIAN ++#error This needs lots of cpu_to_le64s() in ++#endif ++ ++/*!\ TODO look at whether there is an efficiency gain to be had by ++ treating the event codes to 32bit masks as is done for EF1 ++ ++ These masks apply to the full 64 bits of the event to extract the ++ event code - followed by the common event codes to expect ++ */ ++#define __FALCON_OPEN_MASK(WIDTH) ((((uint64_t)1) << (WIDTH)) - 1) ++#define FALCON_EVENT_CODE_MASK \ ++ (__FALCON_OPEN_MASK(EV_CODE_WIDTH) << EV_CODE_LBN) ++#define FALCON_EVENT_EV_Q_ID_MASK \ ++ (__FALCON_OPEN_MASK(DRIVER_EV_EVQ_ID_WIDTH) << DRIVER_EV_EVQ_ID_LBN) ++#define FALCON_EVENT_TX_FLUSH_Q_ID_MASK \ ++ (__FALCON_OPEN_MASK(DRIVER_EV_TX_DESCQ_ID_WIDTH) << \ ++ DRIVER_EV_TX_DESCQ_ID_LBN) ++#define FALCON_EVENT_RX_FLUSH_Q_ID_MASK \ ++ (__FALCON_OPEN_MASK(DRIVER_EV_RX_DESCQ_ID_WIDTH) << \ ++ DRIVER_EV_RX_DESCQ_ID_LBN) ++#define FALCON_EVENT_DRV_SUBCODE_MASK \ ++ (__FALCON_OPEN_MASK(DRIVER_EV_SUB_CODE_WIDTH) << \ ++ DRIVER_EV_SUB_CODE_LBN) ++ ++#define FALCON_EVENT_FMT "[ev:%x:%08x:%08x]" ++#define FALCON_EVENT_PRI_ARG(e) \ ++ ((unsigned)(((e).u64 & FALCON_EVENT_CODE_MASK) >> EV_CODE_LBN)), \ ++ ((unsigned)((e).u64 >> 32)), ((unsigned)((e).u64 & 0xFFFFFFFF)) ++ ++#define FALCON_EVENT_CODE(evp) ((evp)->u64 & FALCON_EVENT_CODE_MASK) ++#define FALCON_EVENT_WAKE_EVQ_ID(evp) \ ++ (((evp)->u64 & FALCON_EVENT_EV_Q_ID_MASK) >> DRIVER_EV_EVQ_ID_LBN) ++#define FALCON_EVENT_TX_FLUSH_Q_ID(evp) \ ++ (((evp)->u64 & FALCON_EVENT_TX_FLUSH_Q_ID_MASK) >> \ ++ DRIVER_EV_TX_DESCQ_ID_LBN) ++#define FALCON_EVENT_RX_FLUSH_Q_ID(evp) \ ++ (((evp)->u64 & FALCON_EVENT_RX_FLUSH_Q_ID_MASK) >> \ ++ DRIVER_EV_RX_DESCQ_ID_LBN) ++#define FALCON_EVENT_DRIVER_SUBCODE(evp) \ ++ (((evp)->u64 & FALCON_EVENT_DRV_SUBCODE_MASK) >> \ ++ DRIVER_EV_SUB_CODE_LBN) ++ ++#define FALCON_EVENT_CODE_CHAR ((uint64_t)DRIVER_EV_DECODE << EV_CODE_LBN) ++#define FALCON_EVENT_CODE_SW ((uint64_t)DRV_GEN_EV_DECODE << EV_CODE_LBN) ++ ++ ++/* so this is the size in bytes of an awful lot of things */ ++#define FALCON_REGISTER128 (16) ++ ++/* we define some unique dummy values as a debug aid */ ++#ifdef _WIN32 ++#define FALCON_ATOMIC_BASE 0xdeadbeef00000000ui64 ++#else ++#define FALCON_ATOMIC_BASE 0xdeadbeef00000000ULL ++#endif ++#define FALCON_ATOMIC_UPD_REG (FALCON_ATOMIC_BASE | 0x1) ++#define FALCON_ATOMIC_PTR_TBL_REG (FALCON_ATOMIC_BASE | 0x2) ++#define FALCON_ATOMIC_SRPM_UDP_EVQ_REG (FALCON_ATOMIC_BASE | 0x3) ++#define FALCON_ATOMIC_RX_FLUSH_DESCQ (FALCON_ATOMIC_BASE | 0x4) ++#define FALCON_ATOMIC_TX_FLUSH_DESCQ (FALCON_ATOMIC_BASE | 0x5) ++#define FALCON_ATOMIC_INT_EN_REG (FALCON_ATOMIC_BASE | 0x6) ++#define FALCON_ATOMIC_TIMER_CMD_REG (FALCON_ATOMIC_BASE | 0x7) ++#define FALCON_ATOMIC_PACE_REG (FALCON_ATOMIC_BASE | 0x8) ++#define FALCON_ATOMIC_INT_ACK_REG (FALCON_ATOMIC_BASE | 0x9) ++/* XXX It crashed with odd value in FALCON_ATOMIC_INT_ADR_REG */ ++#define FALCON_ATOMIC_INT_ADR_REG (FALCON_ATOMIC_BASE | 0xa) ++ ++/*---------------------------------------------------------------------------- ++ * ++ * PCI control blocks for Falcon - ++ * (P) primary is for NET ++ * (S) secondary is for CHAR ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#define FALCON_P_CTR_AP_BAR 2 ++#define FALCON_S_CTR_AP_BAR 0 ++#define FALCON_S_DEVID 0x6703 ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Falcon constants ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* Note: the following constants have moved to values in struct efhw_nic: ++ * FALCON_EVQ_TBL_NUM -> nic->num_evqs ++ * FALCON_DMAQ_NUM -> nic->num_dmaqs ++ * FALCON_TIMERS_NUM -> nic->num_times ++ * These replacement constants are used as sanity checks in assertions in ++ * certain functions that don't have access to struct efhw_nic. ++ */ ++#define FALCON_DMAQ_NUM_SANITY (EFHW_4K) ++#define FALCON_EVQ_TBL_NUM_SANITY (EFHW_4K) ++#define FALCON_TIMERS_NUM_SANITY (EFHW_4K) ++ ++/* This value is an upper limit on the total number of filter table ++ * entries. The actual size of filter table is determined at runtime, as ++ * it can vary. ++ */ ++#define FALCON_FILTER_TBL_NUM (EFHW_8K) ++ ++/* max number of buffers which can be pushed before commiting */ ++#define FALCON_BUFFER_UPD_MAX (128) ++ ++/* We can tell falcon to write its RX buffers in 32 byte quantums, ++ and since we pad packets 2 bytes to the right we can't use ++ a full page (not unless we use jumbo mode for all queues) ++ ++ NOTE: tests/nic/dma.c assumes that the value here is the real NIC ++ value, so we explicitly round it down to the nearest 32 bytes */ ++ ++/* #define FALCON_RX_USR_BUF_SIZE round_down(4096-2,32) */ ++#define FALCON_RX_USR_BUF_SIZE 4064 ++ ++#define FALCON_EVQ_RPTR_REG_P0 0x400 ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Falcon requires user-space descriptor pushes to be: ++ * dword[0-2]; wiob(); dword[3] ++ * ++ * Driver register access must be locked against other threads from ++ * the same driver but can be in any order: i.e dword[0-3]; wiob() ++ * ++ * The following helpers ensure that valid dword orderings are exercised ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* A union to allow writting 64bit values as 32bit values, without ++ * hitting the compilers aliasing rules. We hope the compiler optimises ++ * away the copy's anyway */ ++union __u64to32 { ++ uint64_t u64; ++ struct { ++#ifdef EFHW_IS_LITTLE_ENDIAN ++ uint32_t a; ++ uint32_t b; ++#else ++ uint32_t b; ++ uint32_t a; ++#endif ++ } s; ++}; ++ ++static inline void ++falcon_write_ddd_d(volatile char __iomem *kva, ++ uint32_t d0, uint32_t d1, uint32_t d2, uint32_t d3) ++{ ++ writel(d0, kva + 0); ++ writel(d1, kva + 4); ++ writel(d2, kva + 8); ++ mmiowb(); ++ writel(d3, kva + 12); ++} ++ ++static inline void falcon_write_q(volatile char __iomem *kva, uint64_t q) ++{ ++ union __u64to32 u; ++ u.u64 = q; ++ ++ writel(u.s.a, kva); ++ mmiowb(); ++ writel(u.s.b, kva + 4); ++} ++ ++static inline void falcon_read_q(volatile char __iomem *addr, uint64_t *q0) ++{ ++ /* It is essential that we read dword0 first, so that ++ * the shadow register is updated with the latest value ++ * and we get a self consistent value. ++ */ ++ union __u64to32 u; ++ u.s.a = readl(addr); ++ rmb(); ++ u.s.b = readl(addr + 4); ++ ++ *q0 = u.u64; ++} ++ ++static inline void ++falcon_write_qq(volatile char __iomem *kva, uint64_t q0, uint64_t q1) ++{ ++ writeq(q0, kva + 0); ++ falcon_write_q(kva + 8, q1); ++} ++ ++static inline void ++falcon_read_qq(volatile char __iomem *addr, uint64_t *q0, uint64_t *q1) ++{ ++ falcon_read_q(addr, q0); ++ *q1 = readq(addr + 8); ++} ++ ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Buffer virtual addresses (4K buffers) ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* Form a buffer virtual address from buffer ID and offset. If the offset ++** is larger than the buffer size, then the buffer indexed will be ++** calculated appropriately. It is the responsibility of the caller to ++** ensure that they have valid buffers programmed at that address. ++*/ ++#define FALCON_VADDR_8K_S (13) ++#define FALCON_VADDR_4K_S (12) ++#define FALCON_VADDR_M 0xfffff /* post shift mask */ ++ ++#define FALCON_BUFFER_8K_ADDR(id, off) (((id) << FALCON_VADDR_8K_S) + (off)) ++#define FALCON_BUFFER_8K_PAGE(vaddr) \ ++ (((vaddr) >> FALCON_VADDR_8K_S) & FALCON_VADDR_M) ++#define FALCON_BUFFER_8K_OFF(vaddr) \ ++ ((vaddr) & __FALCON_MASK32(FALCON_VADDR_8K_S)) ++ ++#define FALCON_BUFFER_4K_ADDR(id, off) (((id) << FALCON_VADDR_4K_S) + (off)) ++#define FALCON_BUFFER_4K_PAGE(vaddr) \ ++ (((vaddr) >> FALCON_VADDR_4K_S) & FALCON_VADDR_M) ++#define FALCON_BUFFER_4K_OFF(vaddr) \ ++ ((vaddr) & __FALCON_MASK32(FALCON_VADDR_4K_S)) ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Timer helpers ++ * ++ *---------------------------------------------------------------------------*/ ++ ++static inline int falcon_timer_page_addr(uint idx) ++{ ++ ++ EFHW_ASSERT(TIMER_CMD_REG_KER_OFST == ++ (TIMER_CMD_REG_PAGE4_OFST - 4 * EFHW_8K)); ++ ++ EFHW_ASSERT(idx < FALCON_TIMERS_NUM_SANITY); ++ ++ if (idx < 4) ++ return TIMER_CMD_REG_KER_OFST + (idx * EFHW_8K); ++ else if (idx < 1024) ++ return TIMER_CMD_REG_PAGE4_OFST + ((idx - 4) * EFHW_8K); ++ else ++ return TIMER_CMD_REG_PAGE123K_OFST + ((idx - 1024) * EFHW_8K); ++} ++ ++#define FALCON_TIMER_PAGE_MASK (EFHW_8K-1) ++ ++static inline int falcon_timer_page_offset(uint idx) ++{ ++ return falcon_timer_page_addr(idx) & FALCON_TIMER_PAGE_MASK; ++} ++ ++/*---------------------------------------------------------------------------- ++ * ++ * DMA Queue helpers ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* iSCSI queue for A1; see bug 5427 for more details. */ ++#define FALCON_A1_ISCSI_DMAQ 4 ++ ++/*! returns an address within a bar of the TX DMA doorbell */ ++static inline uint falcon_tx_dma_page_addr(uint dmaq_idx) ++{ ++ uint page; ++ ++ EFHW_ASSERT((((TX_DESC_UPD_REG_PAGE123K_OFST) & (EFHW_8K - 1)) == ++ (((TX_DESC_UPD_REG_PAGE4_OFST) & (EFHW_8K - 1))))); ++ ++ EFHW_ASSERT(dmaq_idx < FALCON_DMAQ_NUM_SANITY); ++ ++ if (dmaq_idx < 1024) ++ page = TX_DESC_UPD_REG_PAGE4_OFST + ((dmaq_idx - 4) * EFHW_8K); ++ else ++ page = ++ TX_DESC_UPD_REG_PAGE123K_OFST + ++ ((dmaq_idx - 1024) * EFHW_8K); ++ ++ return page; ++} ++ ++/*! returns an address within a bar of the RX DMA doorbell */ ++static inline uint falcon_rx_dma_page_addr(uint dmaq_idx) ++{ ++ uint page; ++ ++ EFHW_ASSERT((((RX_DESC_UPD_REG_PAGE123K_OFST) & (EFHW_8K - 1)) == ++ ((RX_DESC_UPD_REG_PAGE4_OFST) & (EFHW_8K - 1)))); ++ ++ EFHW_ASSERT(dmaq_idx < FALCON_DMAQ_NUM_SANITY); ++ ++ if (dmaq_idx < 1024) ++ page = RX_DESC_UPD_REG_PAGE4_OFST + ((dmaq_idx - 4) * EFHW_8K); ++ else ++ page = ++ RX_DESC_UPD_REG_PAGE123K_OFST + ++ ((dmaq_idx - 1024) * EFHW_8K); ++ ++ return page; ++} ++ ++/*! "page"=NIC-dependent register set size */ ++#define FALCON_DMA_PAGE_MASK (EFHW_8K-1) ++ ++/*! returns an address within a bar of the start of the "page" ++ containing the TX DMA doorbell */ ++static inline int falcon_tx_dma_page_base(uint dma_idx) ++{ ++ return falcon_tx_dma_page_addr(dma_idx) & ~FALCON_DMA_PAGE_MASK; ++} ++ ++/*! returns an address within a bar of the start of the "page" ++ containing the RX DMA doorbell */ ++static inline int falcon_rx_dma_page_base(uint dma_idx) ++{ ++ return falcon_rx_dma_page_addr(dma_idx) & ~FALCON_DMA_PAGE_MASK; ++} ++ ++/*! returns an offset within a "page" of the TX DMA doorbell */ ++static inline int falcon_tx_dma_page_offset(uint dma_idx) ++{ ++ return falcon_tx_dma_page_addr(dma_idx) & FALCON_DMA_PAGE_MASK; ++} ++ ++/*! returns an offset within a "page" of the RX DMA doorbell */ ++static inline int falcon_rx_dma_page_offset(uint dma_idx) ++{ ++ return falcon_rx_dma_page_addr(dma_idx) & FALCON_DMA_PAGE_MASK; ++} ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Events ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* Falcon nails down the event queue mappings */ ++#define FALCON_EVQ_KERNEL0 (0) /* hardwired for net driver */ ++#define FALCON_EVQ_CHAR (4) /* char driver's event queue */ ++ ++/* reserved by the drivers */ ++#define FALCON_EVQ_TBL_RESERVED (8) ++ ++/* default DMA-Q sizes */ ++#define FALCON_DMA_Q_DEFAULT_TX_SIZE 512 ++ ++#define FALCON_DMA_Q_DEFAULT_RX_SIZE 512 ++ ++#define FALCON_DMA_Q_DEFAULT_MMAP \ ++ (FALCON_DMA_Q_DEFAULT_TX_SIZE * (FALCON_DMA_TX_DESC_BYTES * 2)) ++ ++/*---------------------------------------------------------------------------- ++ * ++ * DEBUG - Analyser trigger ++ * ++ *---------------------------------------------------------------------------*/ ++ ++static inline void ++falcon_deadbeef(volatile char __iomem *efhw_kva, unsigned what) ++{ ++ writel(what, efhw_kva + 0x300); ++ mmiowb(); ++} ++#endif /* __CI_DRIVER_EFAB_HARDWARE_FALCON_H__ */ ++/*! \cidoxg_end */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_core.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_core.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,1147 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) core register ++ * definitions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#define FALCON_EXTENDED_P_BAR 1 ++ ++/*************---- Bus Interface Unit Registers C Header ----*************/ ++#define IOM_IND_ADR_REG_OFST 0x0 /* IO-mapped indirect access address ++ register */ ++ #define IOM_AUTO_ADR_INC_EN_LBN 16 ++ #define IOM_AUTO_ADR_INC_EN_WIDTH 1 ++ #define IOM_IND_ADR_LBN 0 ++ #define IOM_IND_ADR_WIDTH 16 ++#define IOM_IND_DAT_REG_OFST 0x4 /* IO-mapped indirect access data register */ ++ #define IOM_IND_DAT_LBN 0 ++ #define IOM_IND_DAT_WIDTH 32 ++#define ADR_REGION_REG_KER_OFST 0x0 /* Address region register */ ++#define ADR_REGION_REG_OFST 0x0 /* Address region register */ ++ #define ADR_REGION3_LBN 96 ++ #define ADR_REGION3_WIDTH 18 ++ #define ADR_REGION2_LBN 64 ++ #define ADR_REGION2_WIDTH 18 ++ #define ADR_REGION1_LBN 32 ++ #define ADR_REGION1_WIDTH 18 ++ #define ADR_REGION0_LBN 0 ++ #define ADR_REGION0_WIDTH 18 ++#define INT_EN_REG_KER_OFST 0x10 /* Kernel driver Interrupt enable register */ ++ #define KER_INT_CHAR_LBN 4 ++ #define KER_INT_CHAR_WIDTH 1 ++ #define KER_INT_KER_LBN 3 ++ #define KER_INT_KER_WIDTH 1 ++ #define ILL_ADR_ERR_INT_EN_KER_LBN 2 ++ #define ILL_ADR_ERR_INT_EN_KER_WIDTH 1 ++ #define SRM_PERR_INT_EN_KER_LBN 1 ++ #define SRM_PERR_INT_EN_KER_WIDTH 1 ++ #define DRV_INT_EN_KER_LBN 0 ++ #define DRV_INT_EN_KER_WIDTH 1 ++#define INT_EN_REG_CHAR_OFST 0x20 /* Char Driver interrupt enable register */ ++ #define CHAR_INT_CHAR_LBN 4 ++ #define CHAR_INT_CHAR_WIDTH 1 ++ #define CHAR_INT_KER_LBN 3 ++ #define CHAR_INT_KER_WIDTH 1 ++ #define ILL_ADR_ERR_INT_EN_CHAR_LBN 2 ++ #define ILL_ADR_ERR_INT_EN_CHAR_WIDTH 1 ++ #define SRM_PERR_INT_EN_CHAR_LBN 1 ++ #define SRM_PERR_INT_EN_CHAR_WIDTH 1 ++ #define DRV_INT_EN_CHAR_LBN 0 ++ #define DRV_INT_EN_CHAR_WIDTH 1 ++#define INT_ADR_REG_KER_OFST 0x30 /* Interrupt host address for Kernel driver */ ++ #define INT_ADR_KER_LBN 0 ++ #define INT_ADR_KER_WIDTH 64 ++ #define DRV_INT_KER_LBN 32 ++ #define DRV_INT_KER_WIDTH 1 ++ #define EV_FF_HALF_INT_KER_LBN 3 ++ #define EV_FF_HALF_INT_KER_WIDTH 1 ++ #define EV_FF_FULL_INT_KER_LBN 2 ++ #define EV_FF_FULL_INT_KER_WIDTH 1 ++ #define ILL_ADR_ERR_INT_KER_LBN 1 ++ #define ILL_ADR_ERR_INT_KER_WIDTH 1 ++ #define SRAM_PERR_INT_KER_LBN 0 ++ #define SRAM_PERR_INT_KER_WIDTH 1 ++#define INT_ADR_REG_CHAR_OFST 0x40 /* Interrupt host address for Char driver */ ++ #define INT_ADR_CHAR_LBN 0 ++ #define INT_ADR_CHAR_WIDTH 64 ++ #define DRV_INT_CHAR_LBN 32 ++ #define DRV_INT_CHAR_WIDTH 1 ++ #define EV_FF_HALF_INT_CHAR_LBN 3 ++ #define EV_FF_HALF_INT_CHAR_WIDTH 1 ++ #define EV_FF_FULL_INT_CHAR_LBN 2 ++ #define EV_FF_FULL_INT_CHAR_WIDTH 1 ++ #define ILL_ADR_ERR_INT_CHAR_LBN 1 ++ #define ILL_ADR_ERR_INT_CHAR_WIDTH 1 ++ #define SRAM_PERR_INT_CHAR_LBN 0 ++ #define SRAM_PERR_INT_CHAR_WIDTH 1 ++#define INT_ISR0_B0_OFST 0x90 /* B0 only */ ++#define INT_ISR1_B0_OFST 0xA0 ++#define INT_ACK_REG_KER_A1_OFST 0x50 /* Kernel interrupt acknowledge register */ ++ #define RESERVED_LBN 0 ++ #define RESERVED_WIDTH 32 ++#define INT_ACK_REG_CHAR_A1_OFST 0x60 /* CHAR interrupt acknowledge register */ ++ #define RESERVED_LBN 0 ++ #define RESERVED_WIDTH 32 ++/*************---- Global CSR Registers C Header ----*************/ ++#define NIC_STAT_REG_KER_OFST 0x200 /* ASIC strap status register */ ++#define NIC_STAT_REG_OFST 0x200 /* ASIC strap status register */ ++ #define ONCHIP_SRAM_LBN 16 ++ #define ONCHIP_SRAM_WIDTH 0 ++ #define STRAP_PINS_LBN 0 ++ #define STRAP_PINS_WIDTH 3 ++#define GPIO_CTL_REG_KER_OFST 0x210 /* GPIO control register */ ++#define GPIO_CTL_REG_OFST 0x210 /* GPIO control register */ ++ #define GPIO_OEN_LBN 24 ++ #define GPIO_OEN_WIDTH 4 ++ #define GPIO_OUT_LBN 16 ++ #define GPIO_OUT_WIDTH 4 ++ #define GPIO_IN_LBN 8 ++ #define GPIO_IN_WIDTH 4 ++ #define GPIO_PWRUP_VALUE_LBN 0 ++ #define GPIO_PWRUP_VALUE_WIDTH 4 ++#define GLB_CTL_REG_KER_OFST 0x220 /* Global control register */ ++#define GLB_CTL_REG_OFST 0x220 /* Global control register */ ++ #define SWRST_LBN 0 ++ #define SWRST_WIDTH 1 ++#define FATAL_INTR_REG_KER_OFST 0x230 /* Fatal interrupt register for Kernel */ ++ #define PCI_BUSERR_INT_KER_EN_LBN 43 ++ #define PCI_BUSERR_INT_KER_EN_WIDTH 1 ++ #define SRAM_OOB_INT_KER_EN_LBN 42 ++ #define SRAM_OOB_INT_KER_EN_WIDTH 1 ++ #define BUFID_OOB_INT_KER_EN_LBN 41 ++ #define BUFID_OOB_INT_KER_EN_WIDTH 1 ++ #define MEM_PERR_INT_KER_EN_LBN 40 ++ #define MEM_PERR_INT_KER_EN_WIDTH 1 ++ #define RBUF_OWN_INT_KER_EN_LBN 39 ++ #define RBUF_OWN_INT_KER_EN_WIDTH 1 ++ #define TBUF_OWN_INT_KER_EN_LBN 38 ++ #define TBUF_OWN_INT_KER_EN_WIDTH 1 ++ #define RDESCQ_OWN_INT_KER_EN_LBN 37 ++ #define RDESCQ_OWN_INT_KER_EN_WIDTH 1 ++ #define TDESCQ_OWN_INT_KER_EN_LBN 36 ++ #define TDESCQ_OWN_INT_KER_EN_WIDTH 1 ++ #define EVQ_OWN_INT_KER_EN_LBN 35 ++ #define EVQ_OWN_INT_KER_EN_WIDTH 1 ++ #define EVFF_OFLO_INT_KER_EN_LBN 34 ++ #define EVFF_OFLO_INT_KER_EN_WIDTH 1 ++ #define ILL_ADR_INT_KER_EN_LBN 33 ++ #define ILL_ADR_INT_KER_EN_WIDTH 1 ++ #define SRM_PERR_INT_KER_EN_LBN 32 ++ #define SRM_PERR_INT_KER_EN_WIDTH 1 ++ #define PCI_BUSERR_INT_KER_LBN 11 ++ #define PCI_BUSERR_INT_KER_WIDTH 1 ++ #define SRAM_OOB_INT_KER_LBN 10 ++ #define SRAM_OOB_INT_KER_WIDTH 1 ++ #define BUFID_OOB_INT_KER_LBN 9 ++ #define BUFID_OOB_INT_KER_WIDTH 1 ++ #define MEM_PERR_INT_KER_LBN 8 ++ #define MEM_PERR_INT_KER_WIDTH 1 ++ #define RBUF_OWN_INT_KER_LBN 7 ++ #define RBUF_OWN_INT_KER_WIDTH 1 ++ #define TBUF_OWN_INT_KER_LBN 6 ++ #define TBUF_OWN_INT_KER_WIDTH 1 ++ #define RDESCQ_OWN_INT_KER_LBN 5 ++ #define RDESCQ_OWN_INT_KER_WIDTH 1 ++ #define TDESCQ_OWN_INT_KER_LBN 4 ++ #define TDESCQ_OWN_INT_KER_WIDTH 1 ++ #define EVQ_OWN_INT_KER_LBN 3 ++ #define EVQ_OWN_INT_KER_WIDTH 1 ++ #define EVFF_OFLO_INT_KER_LBN 2 ++ #define EVFF_OFLO_INT_KER_WIDTH 1 ++ #define ILL_ADR_INT_KER_LBN 1 ++ #define ILL_ADR_INT_KER_WIDTH 1 ++ #define SRM_PERR_INT_KER_LBN 0 ++ #define SRM_PERR_INT_KER_WIDTH 1 ++#define FATAL_INTR_REG_OFST 0x240 /* Fatal interrupt register for Char */ ++ #define PCI_BUSERR_INT_CHAR_EN_LBN 43 ++ #define PCI_BUSERR_INT_CHAR_EN_WIDTH 1 ++ #define SRAM_OOB_INT_CHAR_EN_LBN 42 ++ #define SRAM_OOB_INT_CHAR_EN_WIDTH 1 ++ #define BUFID_OOB_INT_CHAR_EN_LBN 41 ++ #define BUFID_OOB_INT_CHAR_EN_WIDTH 1 ++ #define MEM_PERR_INT_CHAR_EN_LBN 40 ++ #define MEM_PERR_INT_CHAR_EN_WIDTH 1 ++ #define RBUF_OWN_INT_CHAR_EN_LBN 39 ++ #define RBUF_OWN_INT_CHAR_EN_WIDTH 1 ++ #define TBUF_OWN_INT_CHAR_EN_LBN 38 ++ #define TBUF_OWN_INT_CHAR_EN_WIDTH 1 ++ #define RDESCQ_OWN_INT_CHAR_EN_LBN 37 ++ #define RDESCQ_OWN_INT_CHAR_EN_WIDTH 1 ++ #define TDESCQ_OWN_INT_CHAR_EN_LBN 36 ++ #define TDESCQ_OWN_INT_CHAR_EN_WIDTH 1 ++ #define EVQ_OWN_INT_CHAR_EN_LBN 35 ++ #define EVQ_OWN_INT_CHAR_EN_WIDTH 1 ++ #define EVFF_OFLO_INT_CHAR_EN_LBN 34 ++ #define EVFF_OFLO_INT_CHAR_EN_WIDTH 1 ++ #define ILL_ADR_INT_CHAR_EN_LBN 33 ++ #define ILL_ADR_INT_CHAR_EN_WIDTH 1 ++ #define SRM_PERR_INT_CHAR_EN_LBN 32 ++ #define SRM_PERR_INT_CHAR_EN_WIDTH 1 ++ #define FATAL_INTR_REG_EN_BITS 0xffffffffffffffffULL ++ #define PCI_BUSERR_INT_CHAR_LBN 11 ++ #define PCI_BUSERR_INT_CHAR_WIDTH 1 ++ #define SRAM_OOB_INT_CHAR_LBN 10 ++ #define SRAM_OOB_INT_CHAR_WIDTH 1 ++ #define BUFID_OOB_INT_CHAR_LBN 9 ++ #define BUFID_OOB_INT_CHAR_WIDTH 1 ++ #define MEM_PERR_INT_CHAR_LBN 8 ++ #define MEM_PERR_INT_CHAR_WIDTH 1 ++ #define RBUF_OWN_INT_CHAR_LBN 7 ++ #define RBUF_OWN_INT_CHAR_WIDTH 1 ++ #define TBUF_OWN_INT_CHAR_LBN 6 ++ #define TBUF_OWN_INT_CHAR_WIDTH 1 ++ #define RDESCQ_OWN_INT_CHAR_LBN 5 ++ #define RDESCQ_OWN_INT_CHAR_WIDTH 1 ++ #define TDESCQ_OWN_INT_CHAR_LBN 4 ++ #define TDESCQ_OWN_INT_CHAR_WIDTH 1 ++ #define EVQ_OWN_INT_CHAR_LBN 3 ++ #define EVQ_OWN_INT_CHAR_WIDTH 1 ++ #define EVFF_OFLO_INT_CHAR_LBN 2 ++ #define EVFF_OFLO_INT_CHAR_WIDTH 1 ++ #define ILL_ADR_INT_CHAR_LBN 1 ++ #define ILL_ADR_INT_CHAR_WIDTH 1 ++ #define SRM_PERR_INT_CHAR_LBN 0 ++ #define SRM_PERR_INT_CHAR_WIDTH 1 ++#define DP_CTRL_REG_OFST 0x250 /* Datapath control register */ ++ #define FLS_EVQ_ID_LBN 0 ++ #define FLS_EVQ_ID_WIDTH 12 ++#define MEM_STAT_REG_KER_OFST 0x260 /* Memory status register */ ++#define MEM_STAT_REG_OFST 0x260 /* Memory status register */ ++ #define MEM_PERR_VEC_LBN 53 ++ #define MEM_PERR_VEC_WIDTH 38 ++ #define MBIST_CORR_LBN 38 ++ #define MBIST_CORR_WIDTH 15 ++ #define MBIST_ERR_LBN 0 ++ #define MBIST_ERR_WIDTH 38 ++#define DEBUG_REG_KER_OFST 0x270 /* Debug register */ ++#define DEBUG_REG_OFST 0x270 /* Debug register */ ++ #define DEBUG_BLK_SEL2_LBN 47 ++ #define DEBUG_BLK_SEL2_WIDTH 3 ++ #define DEBUG_BLK_SEL1_LBN 44 ++ #define DEBUG_BLK_SEL1_WIDTH 3 ++ #define DEBUG_BLK_SEL0_LBN 41 ++ #define DEBUG_BLK_SEL0_WIDTH 3 ++ #define MISC_DEBUG_ADDR_LBN 36 ++ #define MISC_DEBUG_ADDR_WIDTH 5 ++ #define SERDES_DEBUG_ADDR_LBN 31 ++ #define SERDES_DEBUG_ADDR_WIDTH 5 ++ #define EM_DEBUG_ADDR_LBN 26 ++ #define EM_DEBUG_ADDR_WIDTH 5 ++ #define SR_DEBUG_ADDR_LBN 21 ++ #define SR_DEBUG_ADDR_WIDTH 5 ++ #define EV_DEBUG_ADDR_LBN 16 ++ #define EV_DEBUG_ADDR_WIDTH 5 ++ #define RX_DEBUG_ADDR_LBN 11 ++ #define RX_DEBUG_ADDR_WIDTH 5 ++ #define TX_DEBUG_ADDR_LBN 6 ++ #define TX_DEBUG_ADDR_WIDTH 5 ++ #define BIU_DEBUG_ADDR_LBN 1 ++ #define BIU_DEBUG_ADDR_WIDTH 5 ++ #define DEBUG_EN_LBN 0 ++ #define DEBUG_EN_WIDTH 1 ++#define DRIVER_REG0_KER_OFST 0x280 /* Driver scratch register 0 */ ++#define DRIVER_REG0_OFST 0x280 /* Driver scratch register 0 */ ++ #define DRIVER_DW0_LBN 0 ++ #define DRIVER_DW0_WIDTH 32 ++#define DRIVER_REG1_KER_OFST 0x290 /* Driver scratch register 1 */ ++#define DRIVER_REG1_OFST 0x290 /* Driver scratch register 1 */ ++ #define DRIVER_DW1_LBN 0 ++ #define DRIVER_DW1_WIDTH 32 ++#define DRIVER_REG2_KER_OFST 0x2A0 /* Driver scratch register 2 */ ++#define DRIVER_REG2_OFST 0x2A0 /* Driver scratch register 2 */ ++ #define DRIVER_DW2_LBN 0 ++ #define DRIVER_DW2_WIDTH 32 ++#define DRIVER_REG3_KER_OFST 0x2B0 /* Driver scratch register 3 */ ++#define DRIVER_REG3_OFST 0x2B0 /* Driver scratch register 3 */ ++ #define DRIVER_DW3_LBN 0 ++ #define DRIVER_DW3_WIDTH 32 ++#define DRIVER_REG4_KER_OFST 0x2C0 /* Driver scratch register 4 */ ++#define DRIVER_REG4_OFST 0x2C0 /* Driver scratch register 4 */ ++ #define DRIVER_DW4_LBN 0 ++ #define DRIVER_DW4_WIDTH 32 ++#define DRIVER_REG5_KER_OFST 0x2D0 /* Driver scratch register 5 */ ++#define DRIVER_REG5_OFST 0x2D0 /* Driver scratch register 5 */ ++ #define DRIVER_DW5_LBN 0 ++ #define DRIVER_DW5_WIDTH 32 ++#define DRIVER_REG6_KER_OFST 0x2E0 /* Driver scratch register 6 */ ++#define DRIVER_REG6_OFST 0x2E0 /* Driver scratch register 6 */ ++ #define DRIVER_DW6_LBN 0 ++ #define DRIVER_DW6_WIDTH 32 ++#define DRIVER_REG7_KER_OFST 0x2F0 /* Driver scratch register 7 */ ++#define DRIVER_REG7_OFST 0x2F0 /* Driver scratch register 7 */ ++ #define DRIVER_DW7_LBN 0 ++ #define DRIVER_DW7_WIDTH 32 ++#define ALTERA_BUILD_REG_OFST 0x300 /* Altera build register */ ++#define ALTERA_BUILD_REG_OFST 0x300 /* Altera build register */ ++ #define ALTERA_BUILD_VER_LBN 0 ++ #define ALTERA_BUILD_VER_WIDTH 32 ++ ++/* so called CSR spare register ++ - contains separate parity enable bits for the various internal memory ++ blocks */ ++#define MEM_PARITY_ERR_EN_REG_KER 0x310 ++#define MEM_PARITY_ALL_BLOCKS_EN_LBN 64 ++#define MEM_PARITY_ALL_BLOCKS_EN_WIDTH 38 ++#define MEM_PARITY_TX_DATA_EN_LBN 72 ++#define MEM_PARITY_TX_DATA_EN_WIDTH 2 ++ ++/*************---- Event & Timer Module Registers C Header ----*************/ ++ ++#if FALCON_EXTENDED_P_BAR ++#define EVQ_RPTR_REG_KER_OFST 0x11B00 /* Event queue read pointer register */ ++#else ++#define EVQ_RPTR_REG_KER_OFST 0x1B00 /* Event queue read pointer register */ ++#endif ++ ++#define EVQ_RPTR_REG_OFST 0xFA0000 /* Event queue read pointer register ++ array. */ ++ #define EVQ_RPTR_LBN 0 ++ #define EVQ_RPTR_WIDTH 15 ++ ++#if FALCON_EXTENDED_P_BAR ++#define EVQ_PTR_TBL_KER_OFST 0x11A00 /* Event queue pointer table for kernel ++ access */ ++#else ++#define EVQ_PTR_TBL_KER_OFST 0x1A00 /* Event queue pointer table for kernel ++ access */ ++#endif ++ ++#define EVQ_PTR_TBL_CHAR_OFST 0xF60000 /* Event queue pointer table for char ++ direct access */ ++ #define EVQ_WKUP_OR_INT_EN_LBN 39 ++ #define EVQ_WKUP_OR_INT_EN_WIDTH 1 ++ #define EVQ_NXT_WPTR_LBN 24 ++ #define EVQ_NXT_WPTR_WIDTH 15 ++ #define EVQ_EN_LBN 23 ++ #define EVQ_EN_WIDTH 1 ++ #define EVQ_SIZE_LBN 20 ++ #define EVQ_SIZE_WIDTH 3 ++ #define EVQ_BUF_BASE_ID_LBN 0 ++ #define EVQ_BUF_BASE_ID_WIDTH 20 ++#define TIMER_CMD_REG_KER_OFST 0x420 /* Timer table for kernel access. ++ Page-mapped */ ++#define TIMER_CMD_REG_PAGE4_OFST 0x8420 /* Timer table for user-level access. ++ Page-mapped. For lowest 1K queues. ++ */ ++#define TIMER_CMD_REG_PAGE123K_OFST 0x1000420 /* Timer table for user-level ++ access. Page-mapped. ++ For upper 3K queues. */ ++#define TIMER_TBL_OFST 0xF70000 /* Timer table for char driver direct access */ ++ #define TIMER_MODE_LBN 12 ++ #define TIMER_MODE_WIDTH 2 ++ #define TIMER_VAL_LBN 0 ++ #define TIMER_VAL_WIDTH 12 ++ #define TIMER_MODE_INT_HLDOFF 2 ++ #define EVQ_BUF_SIZE_LBN 0 ++ #define EVQ_BUF_SIZE_WIDTH 1 ++#define DRV_EV_REG_KER_OFST 0x440 /* Driver generated event register */ ++#define DRV_EV_REG_OFST 0x440 /* Driver generated event register */ ++ #define DRV_EV_QID_LBN 64 ++ #define DRV_EV_QID_WIDTH 12 ++ #define DRV_EV_DATA_LBN 0 ++ #define DRV_EV_DATA_WIDTH 64 ++#define EVQ_CTL_REG_KER_OFST 0x450 /* Event queue control register */ ++#define EVQ_CTL_REG_OFST 0x450 /* Event queue control register */ ++ #define RX_EVQ_WAKEUP_MASK_B0_LBN 15 ++ #define RX_EVQ_WAKEUP_MASK_B0_WIDTH 6 ++ #define EVQ_OWNERR_CTL_LBN 14 ++ #define EVQ_OWNERR_CTL_WIDTH 1 ++ #define EVQ_FIFO_AF_TH_LBN 8 ++ #define EVQ_FIFO_AF_TH_WIDTH 6 ++ #define EVQ_FIFO_NOTAF_TH_LBN 0 ++ #define EVQ_FIFO_NOTAF_TH_WIDTH 6 ++/*************---- SRAM Module Registers C Header ----*************/ ++#define BUF_TBL_CFG_REG_KER_OFST 0x600 /* Buffer table configuration register */ ++#define BUF_TBL_CFG_REG_OFST 0x600 /* Buffer table configuration register */ ++ #define BUF_TBL_MODE_LBN 3 ++ #define BUF_TBL_MODE_WIDTH 1 ++#define SRM_RX_DC_CFG_REG_KER_OFST 0x610 /* SRAM receive descriptor cache ++ configuration register */ ++#define SRM_RX_DC_CFG_REG_OFST 0x610 /* SRAM receive descriptor cache ++ configuration register */ ++ #define SRM_RX_DC_BASE_ADR_LBN 0 ++ #define SRM_RX_DC_BASE_ADR_WIDTH 21 ++#define SRM_TX_DC_CFG_REG_KER_OFST 0x620 /* SRAM transmit descriptor cache ++ configuration register */ ++#define SRM_TX_DC_CFG_REG_OFST 0x620 /* SRAM transmit descriptor cache ++ configuration register */ ++ #define SRM_TX_DC_BASE_ADR_LBN 0 ++ #define SRM_TX_DC_BASE_ADR_WIDTH 21 ++#define SRM_CFG_REG_KER_OFST 0x630 /* SRAM configuration register */ ++#define SRM_CFG_REG_OFST 0x630 /* SRAM configuration register */ ++ #define SRAM_OOB_ADR_INTEN_LBN 5 ++ #define SRAM_OOB_ADR_INTEN_WIDTH 1 ++ #define SRAM_OOB_BUF_INTEN_LBN 4 ++ #define SRAM_OOB_BUF_INTEN_WIDTH 1 ++ #define SRAM_BT_INIT_EN_LBN 3 ++ #define SRAM_BT_INIT_EN_WIDTH 1 ++ #define SRM_NUM_BANK_LBN 2 ++ #define SRM_NUM_BANK_WIDTH 1 ++ #define SRM_BANK_SIZE_LBN 0 ++ #define SRM_BANK_SIZE_WIDTH 2 ++#define BUF_TBL_UPD_REG_KER_OFST 0x650 /* Buffer table update register */ ++#define BUF_TBL_UPD_REG_OFST 0x650 /* Buffer table update register */ ++ #define BUF_UPD_CMD_LBN 63 ++ #define BUF_UPD_CMD_WIDTH 1 ++ #define BUF_CLR_CMD_LBN 62 ++ #define BUF_CLR_CMD_WIDTH 1 ++ #define BUF_CLR_END_ID_LBN 32 ++ #define BUF_CLR_END_ID_WIDTH 20 ++ #define BUF_CLR_START_ID_LBN 0 ++ #define BUF_CLR_START_ID_WIDTH 20 ++#define SRM_UPD_EVQ_REG_KER_OFST 0x660 /* Buffer table update register */ ++#define SRM_UPD_EVQ_REG_OFST 0x660 /* Buffer table update register */ ++ #define SRM_UPD_EVQ_ID_LBN 0 ++ #define SRM_UPD_EVQ_ID_WIDTH 12 ++#define SRAM_PARITY_REG_KER_OFST 0x670 /* SRAM parity register. */ ++#define SRAM_PARITY_REG_OFST 0x670 /* SRAM parity register. */ ++ #define FORCE_SRAM_PERR_LBN 0 ++ #define FORCE_SRAM_PERR_WIDTH 1 ++ ++#if FALCON_EXTENDED_P_BAR ++#define BUF_HALF_TBL_KER_OFST 0x18000 /* Buffer table in half buffer table ++ mode direct access by kernel driver */ ++#else ++#define BUF_HALF_TBL_KER_OFST 0x8000 /* Buffer table in half buffer table ++ mode direct access by kernel driver */ ++#endif ++ ++ ++#define BUF_HALF_TBL_OFST 0x800000 /* Buffer table in half buffer table mode ++ direct access by char driver */ ++ #define BUF_ADR_HBUF_ODD_LBN 44 ++ #define BUF_ADR_HBUF_ODD_WIDTH 20 ++ #define BUF_OWNER_ID_HBUF_ODD_LBN 32 ++ #define BUF_OWNER_ID_HBUF_ODD_WIDTH 12 ++ #define BUF_ADR_HBUF_EVEN_LBN 12 ++ #define BUF_ADR_HBUF_EVEN_WIDTH 20 ++ #define BUF_OWNER_ID_HBUF_EVEN_LBN 0 ++ #define BUF_OWNER_ID_HBUF_EVEN_WIDTH 12 ++ ++ ++#if FALCON_EXTENDED_P_BAR ++#define BUF_FULL_TBL_KER_OFST 0x18000 /* Buffer table in full buffer table ++ mode direct access by kernel driver */ ++#else ++#define BUF_FULL_TBL_KER_OFST 0x8000 /* Buffer table in full buffer table mode ++ direct access by kernel driver */ ++#endif ++ ++ ++ ++ ++#define BUF_FULL_TBL_OFST 0x800000 /* Buffer table in full buffer table mode ++ direct access by char driver */ ++ #define IP_DAT_BUF_SIZE_LBN 50 ++ #define IP_DAT_BUF_SIZE_WIDTH 1 ++ #define BUF_ADR_REGION_LBN 48 ++ #define BUF_ADR_REGION_WIDTH 2 ++ #define BUF_ADR_FBUF_LBN 14 ++ #define BUF_ADR_FBUF_WIDTH 34 ++ #define BUF_OWNER_ID_FBUF_LBN 0 ++ #define BUF_OWNER_ID_FBUF_WIDTH 14 ++#define SRM_DBG_REG_OFST 0x3000000 /* SRAM debug access */ ++ #define SRM_DBG_LBN 0 ++ #define SRM_DBG_WIDTH 64 ++/*************---- RX Datapath Registers C Header ----*************/ ++ ++#define RX_CFG_REG_KER_OFST 0x800 /* Receive configuration register */ ++#define RX_CFG_REG_OFST 0x800 /* Receive configuration register */ ++ ++#if !defined(FALCON_64K_RXFIFO) && !defined(FALCON_PRE_02020029) ++# if !defined(FALCON_128K_RXFIFO) ++# define FALCON_128K_RXFIFO ++# endif ++#endif ++ ++#if defined(FALCON_128K_RXFIFO) ++ ++/* new for B0 */ ++ #define RX_TOEP_TCP_SUPPRESS_B0_LBN 48 ++ #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1 ++ #define RX_INGR_EN_B0_LBN 47 ++ #define RX_INGR_EN_B0_WIDTH 1 ++ #define RX_TOEP_IPV4_B0_LBN 46 ++ #define RX_TOEP_IPV4_B0_WIDTH 1 ++ #define RX_HASH_ALG_B0_LBN 45 ++ #define RX_HASH_ALG_B0_WIDTH 1 ++ #define RX_HASH_INSERT_HDR_B0_LBN 44 ++ #define RX_HASH_INSERT_HDR_B0_WIDTH 1 ++/* moved for B0 */ ++ #define RX_DESC_PUSH_EN_B0_LBN 43 ++ #define RX_DESC_PUSH_EN_B0_WIDTH 1 ++ #define RX_RDW_PATCH_EN_LBN 42 /* Non head of line blocking */ ++ #define RX_RDW_PATCH_EN_WIDTH 1 ++ #define RX_PCI_BURST_SIZE_B0_LBN 39 ++ #define RX_PCI_BURST_SIZE_B0_WIDTH 3 ++ #define RX_OWNERR_CTL_B0_LBN 38 ++ #define RX_OWNERR_CTL_B0_WIDTH 1 ++ #define RX_XON_TX_TH_B0_LBN 33 ++ #define RX_XON_TX_TH_B0_WIDTH 5 ++ #define RX_XOFF_TX_TH_B0_LBN 28 ++ #define RX_XOFF_TX_TH_B0_WIDTH 5 ++ #define RX_USR_BUF_SIZE_B0_LBN 19 ++ #define RX_USR_BUF_SIZE_B0_WIDTH 9 ++ #define RX_XON_MAC_TH_B0_LBN 10 ++ #define RX_XON_MAC_TH_B0_WIDTH 9 ++ #define RX_XOFF_MAC_TH_B0_LBN 1 ++ #define RX_XOFF_MAC_TH_B0_WIDTH 9 ++ #define RX_XOFF_MAC_EN_B0_LBN 0 ++ #define RX_XOFF_MAC_EN_B0_WIDTH 1 ++ ++#elif !defined(FALCON_PRE_02020029) ++/* new for B0 */ ++ #define RX_TOEP_TCP_SUPPRESS_B0_LBN 46 ++ #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1 ++ #define RX_INGR_EN_B0_LBN 45 ++ #define RX_INGR_EN_B0_WIDTH 1 ++ #define RX_TOEP_IPV4_B0_LBN 44 ++ #define RX_TOEP_IPV4_B0_WIDTH 1 ++ #define RX_HASH_ALG_B0_LBN 43 ++ #define RX_HASH_ALG_B0_WIDTH 41 ++ #define RX_HASH_INSERT_HDR_B0_LBN 42 ++ #define RX_HASH_INSERT_HDR_B0_WIDTH 1 ++/* moved for B0 */ ++ #define RX_DESC_PUSH_EN_B0_LBN 41 ++ #define RX_DESC_PUSH_EN_B0_WIDTH 1 ++ #define RX_PCI_BURST_SIZE_B0_LBN 37 ++ #define RX_PCI_BURST_SIZE_B0_WIDTH 3 ++ #define RX_OWNERR_CTL_B0_LBN 36 ++ #define RX_OWNERR_CTL_B0_WIDTH 1 ++ #define RX_XON_TX_TH_B0_LBN 31 ++ #define RX_XON_TX_TH_B0_WIDTH 5 ++ #define RX_XOFF_TX_TH_B0_LBN 26 ++ #define RX_XOFF_TX_TH_B0_WIDTH 5 ++ #define RX_USR_BUF_SIZE_B0_LBN 17 ++ #define RX_USR_BUF_SIZE_B0_WIDTH 9 ++ #define RX_XON_MAC_TH_B0_LBN 9 ++ #define RX_XON_MAC_TH_B0_WIDTH 8 ++ #define RX_XOFF_MAC_TH_B0_LBN 1 ++ #define RX_XOFF_MAC_TH_B0_WIDTH 8 ++ #define RX_XOFF_MAC_EN_B0_LBN 0 ++ #define RX_XOFF_MAC_EN_B0_WIDTH 1 ++ ++#else ++/* new for B0 */ ++ #define RX_TOEP_TCP_SUPPRESS_B0_LBN 44 ++ #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1 ++ #define RX_INGR_EN_B0_LBN 43 ++ #define RX_INGR_EN_B0_WIDTH 1 ++ #define RX_TOEP_IPV4_B0_LBN 42 ++ #define RX_TOEP_IPV4_B0_WIDTH 1 ++ #define RX_HASH_ALG_B0_LBN 41 ++ #define RX_HASH_ALG_B0_WIDTH 41 ++ #define RX_HASH_INSERT_HDR_B0_LBN 40 ++ #define RX_HASH_INSERT_HDR_B0_WIDTH 1 ++/* moved for B0 */ ++ #define RX_DESC_PUSH_EN_B0_LBN 35 ++ #define RX_DESC_PUSH_EN_B0_WIDTH 1 ++ #define RX_PCI_BURST_SIZE_B0_LBN 35 ++ #define RX_PCI_BURST_SIZE_B0_WIDTH 2 ++ #define RX_OWNERR_CTL_B0_LBN 34 ++ #define RX_OWNERR_CTL_B0_WIDTH 1 ++ #define RX_XON_TX_TH_B0_LBN 29 ++ #define RX_XON_TX_TH_B0_WIDTH 5 ++ #define RX_XOFF_TX_TH_B0_LBN 24 ++ #define RX_XOFF_TX_TH_B0_WIDTH 5 ++ #define RX_USR_BUF_SIZE_B0_LBN 15 ++ #define RX_USR_BUF_SIZE_B0_WIDTH 9 ++ #define RX_XON_MAC_TH_B0_LBN 8 ++ #define RX_XON_MAC_TH_B0_WIDTH 7 ++ #define RX_XOFF_MAC_TH_B0_LBN 1 ++ #define RX_XOFF_MAC_TH_B0_WIDTH 7 ++ #define RX_XOFF_MAC_EN_B0_LBN 0 ++ #define RX_XOFF_MAC_EN_B0_WIDTH 1 ++ ++#endif ++ ++/* A0/A1 */ ++ #define RX_PUSH_EN_A1_LBN 35 ++ #define RX_PUSH_EN_A1_WIDTH 1 ++ #define RX_PCI_BURST_SIZE_A1_LBN 31 ++ #define RX_PCI_BURST_SIZE_A1_WIDTH 3 ++ #define RX_OWNERR_CTL_A1_LBN 30 ++ #define RX_OWNERR_CTL_A1_WIDTH 1 ++ #define RX_XON_TX_TH_A1_LBN 25 ++ #define RX_XON_TX_TH_A1_WIDTH 5 ++ #define RX_XOFF_TX_TH_A1_LBN 20 ++ #define RX_XOFF_TX_TH_A1_WIDTH 5 ++ #define RX_USR_BUF_SIZE_A1_LBN 11 ++ #define RX_USR_BUF_SIZE_A1_WIDTH 9 ++ #define RX_XON_MAC_TH_A1_LBN 6 ++ #define RX_XON_MAC_TH_A1_WIDTH 5 ++ #define RX_XOFF_MAC_TH_A1_LBN 1 ++ #define RX_XOFF_MAC_TH_A1_WIDTH 5 ++ #define RX_XOFF_MAC_EN_A1_LBN 0 ++ #define RX_XOFF_MAC_EN_A1_WIDTH 1 ++ ++#define RX_FILTER_CTL_REG_OFST 0x810 /* Receive filter control registers */ ++ #define SCATTER_ENBL_NO_MATCH_Q_B0_LBN 40 ++ #define SCATTER_ENBL_NO_MATCH_Q_B0_WIDTH 1 ++ #define UDP_FULL_SRCH_LIMIT_LBN 32 ++ #define UDP_FULL_SRCH_LIMIT_WIDTH 8 ++ #define NUM_KER_LBN 24 ++ #define NUM_KER_WIDTH 2 ++ #define UDP_WILD_SRCH_LIMIT_LBN 16 ++ #define UDP_WILD_SRCH_LIMIT_WIDTH 8 ++ #define TCP_WILD_SRCH_LIMIT_LBN 8 ++ #define TCP_WILD_SRCH_LIMIT_WIDTH 8 ++ #define TCP_FULL_SRCH_LIMIT_LBN 0 ++ #define TCP_FULL_SRCH_LIMIT_WIDTH 8 ++#define RX_FLUSH_DESCQ_REG_KER_OFST 0x820 /* Receive flush descriptor queue ++ register */ ++#define RX_FLUSH_DESCQ_REG_OFST 0x820 /* Receive flush descriptor queue ++ register */ ++ #define RX_FLUSH_DESCQ_CMD_LBN 24 ++ #define RX_FLUSH_DESCQ_CMD_WIDTH 1 ++ #define RX_FLUSH_EVQ_ID_LBN 12 ++ #define RX_FLUSH_EVQ_ID_WIDTH 12 ++ #define RX_FLUSH_DESCQ_LBN 0 ++ #define RX_FLUSH_DESCQ_WIDTH 12 ++#define RX_DESC_UPD_REG_KER_OFST 0x830 /* Kernel receive descriptor update ++ register. Page-mapped */ ++#define RX_DESC_UPD_REG_PAGE4_OFST 0x8830 /* Char & user receive descriptor ++ update register. Page-mapped. ++ For lowest 1K queues. */ ++#define RX_DESC_UPD_REG_PAGE123K_OFST 0x1000830 /* Char & user receive ++ descriptor update register. ++ Page-mapped. For upper ++ 3K queues. */ ++ #define RX_DESC_WPTR_LBN 96 ++ #define RX_DESC_WPTR_WIDTH 12 ++ #define RX_DESC_PUSH_CMD_LBN 95 ++ #define RX_DESC_PUSH_CMD_WIDTH 1 ++ #define RX_DESC_LBN 0 ++ #define RX_DESC_WIDTH 64 ++ #define RX_KER_DESC_LBN 0 ++ #define RX_KER_DESC_WIDTH 64 ++ #define RX_USR_DESC_LBN 0 ++ #define RX_USR_DESC_WIDTH 32 ++#define RX_DC_CFG_REG_KER_OFST 0x840 /* Receive descriptor cache ++ configuration register */ ++#define RX_DC_CFG_REG_OFST 0x840 /* Receive descriptor cache ++ configuration register */ ++ #define RX_DC_SIZE_LBN 0 ++ #define RX_DC_SIZE_WIDTH 2 ++#define RX_DC_PF_WM_REG_KER_OFST 0x850 /* Receive descriptor cache pre-fetch ++ watermark register */ ++#define RX_DC_PF_WM_REG_OFST 0x850 /* Receive descriptor cache pre-fetch ++ watermark register */ ++ #define RX_DC_PF_LWM_LO_LBN 0 ++ #define RX_DC_PF_LWM_LO_WIDTH 6 ++ ++#define RX_RSS_TKEY_B0_OFST 0x860 /* RSS Toeplitz hash key (B0 only) */ ++ ++#define RX_NODESC_DROP_REG 0x880 ++ #define RX_NODESC_DROP_CNT_LBN 0 ++ #define RX_NODESC_DROP_CNT_WIDTH 16 ++ ++#define XM_TX_CFG_REG_OFST 0x1230 ++ #define XM_AUTO_PAD_LBN 5 ++ #define XM_AUTO_PAD_WIDTH 1 ++ ++#define RX_FILTER_TBL0_OFST 0xF00000 /* Receive filter table - even entries */ ++ #define RSS_EN_0_B0_LBN 110 ++ #define RSS_EN_0_B0_WIDTH 1 ++ #define SCATTER_EN_0_B0_LBN 109 ++ #define SCATTER_EN_0_B0_WIDTH 1 ++ #define TCP_UDP_0_LBN 108 ++ #define TCP_UDP_0_WIDTH 1 ++ #define RXQ_ID_0_LBN 96 ++ #define RXQ_ID_0_WIDTH 12 ++ #define DEST_IP_0_LBN 64 ++ #define DEST_IP_0_WIDTH 32 ++ #define DEST_PORT_TCP_0_LBN 48 ++ #define DEST_PORT_TCP_0_WIDTH 16 ++ #define SRC_IP_0_LBN 16 ++ #define SRC_IP_0_WIDTH 32 ++ #define SRC_TCP_DEST_UDP_0_LBN 0 ++ #define SRC_TCP_DEST_UDP_0_WIDTH 16 ++#define RX_FILTER_TBL1_OFST 0xF00010 /* Receive filter table - odd entries */ ++ #define RSS_EN_1_B0_LBN 110 ++ #define RSS_EN_1_B0_WIDTH 1 ++ #define SCATTER_EN_1_B0_LBN 109 ++ #define SCATTER_EN_1_B0_WIDTH 1 ++ #define TCP_UDP_1_LBN 108 ++ #define TCP_UDP_1_WIDTH 1 ++ #define RXQ_ID_1_LBN 96 ++ #define RXQ_ID_1_WIDTH 12 ++ #define DEST_IP_1_LBN 64 ++ #define DEST_IP_1_WIDTH 32 ++ #define DEST_PORT_TCP_1_LBN 48 ++ #define DEST_PORT_TCP_1_WIDTH 16 ++ #define SRC_IP_1_LBN 16 ++ #define SRC_IP_1_WIDTH 32 ++ #define SRC_TCP_DEST_UDP_1_LBN 0 ++ #define SRC_TCP_DEST_UDP_1_WIDTH 16 ++ ++#if FALCON_EXTENDED_P_BAR ++#define RX_DESC_PTR_TBL_KER_OFST 0x11800 /* Receive descriptor pointer ++ kernel access */ ++#else ++#define RX_DESC_PTR_TBL_KER_OFST 0x1800 /* Receive descriptor pointer ++ kernel access */ ++#endif ++ ++ ++#define RX_DESC_PTR_TBL_OFST 0xF40000 /* Receive descriptor pointer table */ ++ #define RX_ISCSI_DDIG_EN_LBN 88 ++ #define RX_ISCSI_DDIG_EN_WIDTH 1 ++ #define RX_ISCSI_HDIG_EN_LBN 87 ++ #define RX_ISCSI_HDIG_EN_WIDTH 1 ++ #define RX_DESC_PREF_ACT_LBN 86 ++ #define RX_DESC_PREF_ACT_WIDTH 1 ++ #define RX_DC_HW_RPTR_LBN 80 ++ #define RX_DC_HW_RPTR_WIDTH 6 ++ #define RX_DESCQ_HW_RPTR_LBN 68 ++ #define RX_DESCQ_HW_RPTR_WIDTH 12 ++ #define RX_DESCQ_SW_WPTR_LBN 56 ++ #define RX_DESCQ_SW_WPTR_WIDTH 12 ++ #define RX_DESCQ_BUF_BASE_ID_LBN 36 ++ #define RX_DESCQ_BUF_BASE_ID_WIDTH 20 ++ #define RX_DESCQ_EVQ_ID_LBN 24 ++ #define RX_DESCQ_EVQ_ID_WIDTH 12 ++ #define RX_DESCQ_OWNER_ID_LBN 10 ++ #define RX_DESCQ_OWNER_ID_WIDTH 14 ++ #define RX_DESCQ_LABEL_LBN 5 ++ #define RX_DESCQ_LABEL_WIDTH 5 ++ #define RX_DESCQ_SIZE_LBN 3 ++ #define RX_DESCQ_SIZE_WIDTH 2 ++ #define RX_DESCQ_TYPE_LBN 2 ++ #define RX_DESCQ_TYPE_WIDTH 1 ++ #define RX_DESCQ_JUMBO_LBN 1 ++ #define RX_DESCQ_JUMBO_WIDTH 1 ++ #define RX_DESCQ_EN_LBN 0 ++ #define RX_DESCQ_EN_WIDTH 1 ++ ++ ++#define RX_RSS_INDIR_TBL_B0_OFST 0xFB0000 /* RSS indirection table (B0 only) */ ++ #define RX_RSS_INDIR_ENT_B0_LBN 0 ++ #define RX_RSS_INDIR_ENT_B0_WIDTH 6 ++ ++/*************---- TX Datapath Registers C Header ----*************/ ++#define TX_FLUSH_DESCQ_REG_KER_OFST 0xA00 /* Transmit flush descriptor ++ queue register */ ++#define TX_FLUSH_DESCQ_REG_OFST 0xA00 /* Transmit flush descriptor queue ++ register */ ++ #define TX_FLUSH_DESCQ_CMD_LBN 12 ++ #define TX_FLUSH_DESCQ_CMD_WIDTH 1 ++ #define TX_FLUSH_DESCQ_LBN 0 ++ #define TX_FLUSH_DESCQ_WIDTH 12 ++#define TX_DESC_UPD_REG_KER_OFST 0xA10 /* Kernel transmit descriptor update ++ register. Page-mapped */ ++#define TX_DESC_UPD_REG_PAGE4_OFST 0x8A10 /* Char & user transmit descriptor ++ update register. Page-mapped */ ++#define TX_DESC_UPD_REG_PAGE123K_OFST 0x1000A10 /* Char & user transmit ++ descriptor update register. ++ Page-mapped */ ++ #define TX_DESC_WPTR_LBN 96 ++ #define TX_DESC_WPTR_WIDTH 12 ++ #define TX_DESC_PUSH_CMD_LBN 95 ++ #define TX_DESC_PUSH_CMD_WIDTH 1 ++ #define TX_DESC_LBN 0 ++ #define TX_DESC_WIDTH 95 ++ #define TX_KER_DESC_LBN 0 ++ #define TX_KER_DESC_WIDTH 64 ++ #define TX_USR_DESC_LBN 0 ++ #define TX_USR_DESC_WIDTH 64 ++#define TX_DC_CFG_REG_KER_OFST 0xA20 /* Transmit descriptor cache ++ configuration register */ ++#define TX_DC_CFG_REG_OFST 0xA20 /* Transmit descriptor cache configuration ++ register */ ++ #define TX_DC_SIZE_LBN 0 ++ #define TX_DC_SIZE_WIDTH 2 ++ ++#if FALCON_EXTENDED_P_BAR ++#define TX_DESC_PTR_TBL_KER_OFST 0x11900 /* Transmit descriptor pointer. */ ++#else ++#define TX_DESC_PTR_TBL_KER_OFST 0x1900 /* Transmit descriptor pointer. */ ++#endif ++ ++ ++#define TX_DESC_PTR_TBL_OFST 0xF50000 /* Transmit descriptor pointer */ ++ #define TX_NON_IP_DROP_DIS_B0_LBN 91 ++ #define TX_NON_IP_DROP_DIS_B0_WIDTH 1 ++ #define TX_IP_CHKSM_DIS_B0_LBN 90 ++ #define TX_IP_CHKSM_DIS_B0_WIDTH 1 ++ #define TX_TCP_CHKSM_DIS_B0_LBN 89 ++ #define TX_TCP_CHKSM_DIS_B0_WIDTH 1 ++ #define TX_DESCQ_EN_LBN 88 ++ #define TX_DESCQ_EN_WIDTH 1 ++ #define TX_ISCSI_DDIG_EN_LBN 87 ++ #define TX_ISCSI_DDIG_EN_WIDTH 1 ++ #define TX_ISCSI_HDIG_EN_LBN 86 ++ #define TX_ISCSI_HDIG_EN_WIDTH 1 ++ #define TX_DC_HW_RPTR_LBN 80 ++ #define TX_DC_HW_RPTR_WIDTH 6 ++ #define TX_DESCQ_HW_RPTR_LBN 68 ++ #define TX_DESCQ_HW_RPTR_WIDTH 12 ++ #define TX_DESCQ_SW_WPTR_LBN 56 ++ #define TX_DESCQ_SW_WPTR_WIDTH 12 ++ #define TX_DESCQ_BUF_BASE_ID_LBN 36 ++ #define TX_DESCQ_BUF_BASE_ID_WIDTH 20 ++ #define TX_DESCQ_EVQ_ID_LBN 24 ++ #define TX_DESCQ_EVQ_ID_WIDTH 12 ++ #define TX_DESCQ_OWNER_ID_LBN 10 ++ #define TX_DESCQ_OWNER_ID_WIDTH 14 ++ #define TX_DESCQ_LABEL_LBN 5 ++ #define TX_DESCQ_LABEL_WIDTH 5 ++ #define TX_DESCQ_SIZE_LBN 3 ++ #define TX_DESCQ_SIZE_WIDTH 2 ++ #define TX_DESCQ_TYPE_LBN 1 ++ #define TX_DESCQ_TYPE_WIDTH 2 ++ #define TX_DESCQ_FLUSH_LBN 0 ++ #define TX_DESCQ_FLUSH_WIDTH 1 ++#define TX_CFG_REG_KER_OFST 0xA50 /* Transmit configuration register */ ++#define TX_CFG_REG_OFST 0xA50 /* Transmit configuration register */ ++ #define TX_IP_ID_P1_OFS_LBN 32 ++ #define TX_IP_ID_P1_OFS_WIDTH 15 ++ #define TX_IP_ID_P0_OFS_LBN 16 ++ #define TX_IP_ID_P0_OFS_WIDTH 15 ++ #define TX_TURBO_EN_LBN 3 ++ #define TX_TURBO_EN_WIDTH 1 ++ #define TX_OWNERR_CTL_LBN 2 ++ #define TX_OWNERR_CTL_WIDTH 2 ++ #define TX_NON_IP_DROP_DIS_LBN 1 ++ #define TX_NON_IP_DROP_DIS_WIDTH 1 ++ #define TX_IP_ID_REP_EN_LBN 0 ++ #define TX_IP_ID_REP_EN_WIDTH 1 ++#define TX_RESERVED_REG_KER_OFST 0xA80 /* Transmit configuration register */ ++#define TX_RESERVED_REG_OFST 0xA80 /* Transmit configuration register */ ++ #define TX_CSR_PUSH_EN_LBN 89 ++ #define TX_CSR_PUSH_EN_WIDTH 1 ++ #define TX_RX_SPACER_LBN 64 ++ #define TX_RX_SPACER_WIDTH 8 ++ #define TX_SW_EV_EN_LBN 59 ++ #define TX_SW_EV_EN_WIDTH 1 ++ #define TX_RX_SPACER_EN_LBN 57 ++ #define TX_RX_SPACER_EN_WIDTH 1 ++ #define TX_CSR_PREF_WD_TMR_LBN 24 ++ #define TX_CSR_PREF_WD_TMR_WIDTH 16 ++ #define TX_CSR_ONLY1TAG_LBN 21 ++ #define TX_CSR_ONLY1TAG_WIDTH 1 ++ #define TX_PREF_THRESHOLD_LBN 19 ++ #define TX_PREF_THRESHOLD_WIDTH 2 ++ #define TX_ONE_PKT_PER_Q_LBN 18 ++ #define TX_ONE_PKT_PER_Q_WIDTH 1 ++ #define TX_DIS_NON_IP_EV_LBN 17 ++ #define TX_DIS_NON_IP_EV_WIDTH 1 ++ #define TX_DMA_SPACER_LBN 8 ++ #define TX_DMA_SPACER_WIDTH 8 ++ #define TX_FLUSH_MIN_LEN_EN_B0_LBN 7 ++ #define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1 ++ #define TX_TCP_DIS_A1_LBN 7 ++ #define TX_TCP_DIS_A1_WIDTH 1 ++ #define TX_IP_DIS_A1_LBN 6 ++ #define TX_IP_DIS_A1_WIDTH 1 ++ #define TX_MAX_CPL_LBN 2 ++ #define TX_MAX_CPL_WIDTH 2 ++ #define TX_MAX_PREF_LBN 0 ++ #define TX_MAX_PREF_WIDTH 2 ++#define TX_VLAN_REG_OFST 0xAE0 /* Transmit VLAN tag register */ ++ #define TX_VLAN_EN_LBN 127 ++ #define TX_VLAN_EN_WIDTH 1 ++ #define TX_VLAN7_PORT1_EN_LBN 125 ++ #define TX_VLAN7_PORT1_EN_WIDTH 1 ++ #define TX_VLAN7_PORT0_EN_LBN 124 ++ #define TX_VLAN7_PORT0_EN_WIDTH 1 ++ #define TX_VLAN7_LBN 112 ++ #define TX_VLAN7_WIDTH 12 ++ #define TX_VLAN6_PORT1_EN_LBN 109 ++ #define TX_VLAN6_PORT1_EN_WIDTH 1 ++ #define TX_VLAN6_PORT0_EN_LBN 108 ++ #define TX_VLAN6_PORT0_EN_WIDTH 1 ++ #define TX_VLAN6_LBN 96 ++ #define TX_VLAN6_WIDTH 12 ++ #define TX_VLAN5_PORT1_EN_LBN 93 ++ #define TX_VLAN5_PORT1_EN_WIDTH 1 ++ #define TX_VLAN5_PORT0_EN_LBN 92 ++ #define TX_VLAN5_PORT0_EN_WIDTH 1 ++ #define TX_VLAN5_LBN 80 ++ #define TX_VLAN5_WIDTH 12 ++ #define TX_VLAN4_PORT1_EN_LBN 77 ++ #define TX_VLAN4_PORT1_EN_WIDTH 1 ++ #define TX_VLAN4_PORT0_EN_LBN 76 ++ #define TX_VLAN4_PORT0_EN_WIDTH 1 ++ #define TX_VLAN4_LBN 64 ++ #define TX_VLAN4_WIDTH 12 ++ #define TX_VLAN3_PORT1_EN_LBN 61 ++ #define TX_VLAN3_PORT1_EN_WIDTH 1 ++ #define TX_VLAN3_PORT0_EN_LBN 60 ++ #define TX_VLAN3_PORT0_EN_WIDTH 1 ++ #define TX_VLAN3_LBN 48 ++ #define TX_VLAN3_WIDTH 12 ++ #define TX_VLAN2_PORT1_EN_LBN 45 ++ #define TX_VLAN2_PORT1_EN_WIDTH 1 ++ #define TX_VLAN2_PORT0_EN_LBN 44 ++ #define TX_VLAN2_PORT0_EN_WIDTH 1 ++ #define TX_VLAN2_LBN 32 ++ #define TX_VLAN2_WIDTH 12 ++ #define TX_VLAN1_PORT1_EN_LBN 29 ++ #define TX_VLAN1_PORT1_EN_WIDTH 1 ++ #define TX_VLAN1_PORT0_EN_LBN 28 ++ #define TX_VLAN1_PORT0_EN_WIDTH 1 ++ #define TX_VLAN1_LBN 16 ++ #define TX_VLAN1_WIDTH 12 ++ #define TX_VLAN0_PORT1_EN_LBN 13 ++ #define TX_VLAN0_PORT1_EN_WIDTH 1 ++ #define TX_VLAN0_PORT0_EN_LBN 12 ++ #define TX_VLAN0_PORT0_EN_WIDTH 1 ++ #define TX_VLAN0_LBN 0 ++ #define TX_VLAN0_WIDTH 12 ++#define TX_FIL_CTL_REG_OFST 0xAF0 /* Transmit filter control register */ ++ #define TX_MADR1_FIL_EN_LBN 65 ++ #define TX_MADR1_FIL_EN_WIDTH 1 ++ #define TX_MADR0_FIL_EN_LBN 64 ++ #define TX_MADR0_FIL_EN_WIDTH 1 ++ #define TX_IPFIL31_PORT1_EN_LBN 63 ++ #define TX_IPFIL31_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL31_PORT0_EN_LBN 62 ++ #define TX_IPFIL31_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL30_PORT1_EN_LBN 61 ++ #define TX_IPFIL30_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL30_PORT0_EN_LBN 60 ++ #define TX_IPFIL30_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL29_PORT1_EN_LBN 59 ++ #define TX_IPFIL29_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL29_PORT0_EN_LBN 58 ++ #define TX_IPFIL29_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL28_PORT1_EN_LBN 57 ++ #define TX_IPFIL28_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL28_PORT0_EN_LBN 56 ++ #define TX_IPFIL28_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL27_PORT1_EN_LBN 55 ++ #define TX_IPFIL27_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL27_PORT0_EN_LBN 54 ++ #define TX_IPFIL27_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL26_PORT1_EN_LBN 53 ++ #define TX_IPFIL26_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL26_PORT0_EN_LBN 52 ++ #define TX_IPFIL26_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL25_PORT1_EN_LBN 51 ++ #define TX_IPFIL25_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL25_PORT0_EN_LBN 50 ++ #define TX_IPFIL25_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL24_PORT1_EN_LBN 49 ++ #define TX_IPFIL24_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL24_PORT0_EN_LBN 48 ++ #define TX_IPFIL24_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL23_PORT1_EN_LBN 47 ++ #define TX_IPFIL23_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL23_PORT0_EN_LBN 46 ++ #define TX_IPFIL23_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL22_PORT1_EN_LBN 45 ++ #define TX_IPFIL22_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL22_PORT0_EN_LBN 44 ++ #define TX_IPFIL22_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL21_PORT1_EN_LBN 43 ++ #define TX_IPFIL21_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL21_PORT0_EN_LBN 42 ++ #define TX_IPFIL21_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL20_PORT1_EN_LBN 41 ++ #define TX_IPFIL20_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL20_PORT0_EN_LBN 40 ++ #define TX_IPFIL20_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL19_PORT1_EN_LBN 39 ++ #define TX_IPFIL19_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL19_PORT0_EN_LBN 38 ++ #define TX_IPFIL19_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL18_PORT1_EN_LBN 37 ++ #define TX_IPFIL18_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL18_PORT0_EN_LBN 36 ++ #define TX_IPFIL18_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL17_PORT1_EN_LBN 35 ++ #define TX_IPFIL17_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL17_PORT0_EN_LBN 34 ++ #define TX_IPFIL17_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL16_PORT1_EN_LBN 33 ++ #define TX_IPFIL16_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL16_PORT0_EN_LBN 32 ++ #define TX_IPFIL16_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL15_PORT1_EN_LBN 31 ++ #define TX_IPFIL15_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL15_PORT0_EN_LBN 30 ++ #define TX_IPFIL15_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL14_PORT1_EN_LBN 29 ++ #define TX_IPFIL14_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL14_PORT0_EN_LBN 28 ++ #define TX_IPFIL14_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL13_PORT1_EN_LBN 27 ++ #define TX_IPFIL13_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL13_PORT0_EN_LBN 26 ++ #define TX_IPFIL13_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL12_PORT1_EN_LBN 25 ++ #define TX_IPFIL12_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL12_PORT0_EN_LBN 24 ++ #define TX_IPFIL12_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL11_PORT1_EN_LBN 23 ++ #define TX_IPFIL11_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL11_PORT0_EN_LBN 22 ++ #define TX_IPFIL11_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL10_PORT1_EN_LBN 21 ++ #define TX_IPFIL10_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL10_PORT0_EN_LBN 20 ++ #define TX_IPFIL10_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL9_PORT1_EN_LBN 19 ++ #define TX_IPFIL9_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL9_PORT0_EN_LBN 18 ++ #define TX_IPFIL9_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL8_PORT1_EN_LBN 17 ++ #define TX_IPFIL8_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL8_PORT0_EN_LBN 16 ++ #define TX_IPFIL8_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL7_PORT1_EN_LBN 15 ++ #define TX_IPFIL7_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL7_PORT0_EN_LBN 14 ++ #define TX_IPFIL7_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL6_PORT1_EN_LBN 13 ++ #define TX_IPFIL6_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL6_PORT0_EN_LBN 12 ++ #define TX_IPFIL6_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL5_PORT1_EN_LBN 11 ++ #define TX_IPFIL5_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL5_PORT0_EN_LBN 10 ++ #define TX_IPFIL5_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL4_PORT1_EN_LBN 9 ++ #define TX_IPFIL4_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL4_PORT0_EN_LBN 8 ++ #define TX_IPFIL4_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL3_PORT1_EN_LBN 7 ++ #define TX_IPFIL3_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL3_PORT0_EN_LBN 6 ++ #define TX_IPFIL3_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL2_PORT1_EN_LBN 5 ++ #define TX_IPFIL2_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL2_PORT0_EN_LBN 4 ++ #define TX_IPFIL2_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL1_PORT1_EN_LBN 3 ++ #define TX_IPFIL1_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL1_PORT0_EN_LBN 2 ++ #define TX_IPFIL1_PORT0_EN_WIDTH 1 ++ #define TX_IPFIL0_PORT1_EN_LBN 1 ++ #define TX_IPFIL0_PORT1_EN_WIDTH 1 ++ #define TX_IPFIL0_PORT0_EN_LBN 0 ++ #define TX_IPFIL0_PORT0_EN_WIDTH 1 ++#define TX_IPFIL_TBL_OFST 0xB00 /* Transmit IP source address filter table */ ++ #define TX_IPFIL_MASK_LBN 32 ++ #define TX_IPFIL_MASK_WIDTH 32 ++ #define TX_IP_SRC_ADR_LBN 0 ++ #define TX_IP_SRC_ADR_WIDTH 32 ++#define TX_PACE_REG_A1_OFST 0xF80000 /* Transmit pace control register */ ++#define TX_PACE_REG_B0_OFST 0xA90 /* Transmit pace control register */ ++ #define TX_PACE_SB_NOTAF_LBN 19 ++ #define TX_PACE_SB_NOTAF_WIDTH 10 ++ #define TX_PACE_SB_AF_LBN 9 ++ #define TX_PACE_SB_AF_WIDTH 10 ++ #define TX_PACE_FB_BASE_LBN 5 ++ #define TX_PACE_FB_BASE_WIDTH 4 ++ #define TX_PACE_BIN_TH_LBN 0 ++ #define TX_PACE_BIN_TH_WIDTH 5 ++#define TX_PACE_TBL_A1_OFST 0xF80040 /* Transmit pacing table */ ++#define TX_PACE_TBL_FIRST_QUEUE_A1 4 ++#define TX_PACE_TBL_B0_OFST 0xF80000 /* Transmit pacing table */ ++#define TX_PACE_TBL_FIRST_QUEUE_B0 0 ++ #define TX_PACE_LBN 0 ++ #define TX_PACE_WIDTH 5 ++ ++/*************---- EE/Flash Registers C Header ----*************/ ++#define EE_SPI_HCMD_REG_KER_OFST 0x100 /* SPI host command register */ ++#define EE_SPI_HCMD_REG_OFST 0x100 /* SPI host command register */ ++ #define EE_SPI_HCMD_CMD_EN_LBN 31 ++ #define EE_SPI_HCMD_CMD_EN_WIDTH 1 ++ #define EE_WR_TIMER_ACTIVE_LBN 28 ++ #define EE_WR_TIMER_ACTIVE_WIDTH 1 ++ #define EE_SPI_HCMD_SF_SEL_LBN 24 ++ #define EE_SPI_HCMD_SF_SEL_WIDTH 1 ++ #define EE_SPI_HCMD_DABCNT_LBN 16 ++ #define EE_SPI_HCMD_DABCNT_WIDTH 5 ++ #define EE_SPI_HCMD_READ_LBN 15 ++ #define EE_SPI_HCMD_READ_WIDTH 1 ++ #define EE_SPI_HCMD_DUBCNT_LBN 12 ++ #define EE_SPI_HCMD_DUBCNT_WIDTH 2 ++ #define EE_SPI_HCMD_ADBCNT_LBN 8 ++ #define EE_SPI_HCMD_ADBCNT_WIDTH 2 ++ #define EE_SPI_HCMD_ENC_LBN 0 ++ #define EE_SPI_HCMD_ENC_WIDTH 8 ++#define EE_SPI_HADR_REG_KER_OFST 0X110 /* SPI host address register */ ++#define EE_SPI_HADR_REG_OFST 0X110 /* SPI host address register */ ++ #define EE_SPI_HADR_DUBYTE_LBN 24 ++ #define EE_SPI_HADR_DUBYTE_WIDTH 8 ++ #define EE_SPI_HADR_ADR_LBN 0 ++ #define EE_SPI_HADR_ADR_WIDTH 24 ++#define EE_SPI_HDATA_REG_KER_OFST 0x120 /* SPI host data register */ ++#define EE_SPI_HDATA_REG_OFST 0x120 /* SPI host data register */ ++ #define EE_SPI_HDATA3_LBN 96 ++ #define EE_SPI_HDATA3_WIDTH 32 ++ #define EE_SPI_HDATA2_LBN 64 ++ #define EE_SPI_HDATA2_WIDTH 32 ++ #define EE_SPI_HDATA1_LBN 32 ++ #define EE_SPI_HDATA1_WIDTH 32 ++ #define EE_SPI_HDATA0_LBN 0 ++ #define EE_SPI_HDATA0_WIDTH 32 ++#define EE_BASE_PAGE_REG_KER_OFST 0x130 /* Expansion ROM base mirror register */ ++#define EE_BASE_PAGE_REG_OFST 0x130 /* Expansion ROM base mirror register */ ++ #define EE_EXP_ROM_WINDOW_BASE_LBN 16 ++ #define EE_EXP_ROM_WINDOW_BASE_WIDTH 13 ++ #define EE_EXPROM_MASK_LBN 0 ++ #define EE_EXPROM_MASK_WIDTH 13 ++#define EE_VPD_CFG0_REG_KER_OFST 0X140 /* SPI/VPD configuration register */ ++#define EE_VPD_CFG0_REG_OFST 0X140 /* SPI/VPD configuration register */ ++ #define EE_SF_FASTRD_EN_LBN 127 ++ #define EE_SF_FASTRD_EN_WIDTH 1 ++ #define EE_SF_CLOCK_DIV_LBN 120 ++ #define EE_SF_CLOCK_DIV_WIDTH 7 ++ #define EE_VPD_WIP_POLL_LBN 119 ++ #define EE_VPD_WIP_POLL_WIDTH 1 ++ #define EE_VPDW_LENGTH_LBN 80 ++ #define EE_VPDW_LENGTH_WIDTH 15 ++ #define EE_VPDW_BASE_LBN 64 ++ #define EE_VPDW_BASE_WIDTH 15 ++ #define EE_VPD_WR_CMD_EN_LBN 56 ++ #define EE_VPD_WR_CMD_EN_WIDTH 8 ++ #define EE_VPD_BASE_LBN 32 ++ #define EE_VPD_BASE_WIDTH 24 ++ #define EE_VPD_LENGTH_LBN 16 ++ #define EE_VPD_LENGTH_WIDTH 13 ++ #define EE_VPD_AD_SIZE_LBN 8 ++ #define EE_VPD_AD_SIZE_WIDTH 5 ++ #define EE_VPD_ACCESS_ON_LBN 5 ++ #define EE_VPD_ACCESS_ON_WIDTH 1 ++#define EE_VPD_SW_CNTL_REG_KER_OFST 0X150 /* VPD access SW control register */ ++#define EE_VPD_SW_CNTL_REG_OFST 0X150 /* VPD access SW control register */ ++ #define EE_VPD_CYCLE_PENDING_LBN 31 ++ #define EE_VPD_CYCLE_PENDING_WIDTH 1 ++ #define EE_VPD_CYC_WRITE_LBN 28 ++ #define EE_VPD_CYC_WRITE_WIDTH 1 ++ #define EE_VPD_CYC_ADR_LBN 0 ++ #define EE_VPD_CYC_ADR_WIDTH 15 ++#define EE_VPD_SW_DATA_REG_KER_OFST 0x160 /* VPD access SW data register */ ++#define EE_VPD_SW_DATA_REG_OFST 0x160 /* VPD access SW data register */ ++ #define EE_VPD_CYC_DAT_LBN 0 ++ #define EE_VPD_CYC_DAT_WIDTH 32 +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_desc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_desc.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,75 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) descriptor ++ * definitions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++/*************---- Descriptors C Headers ----*************/ ++/* Receive Kernel IP Descriptor */ ++ #define RX_KER_BUF_SIZE_LBN 48 ++ #define RX_KER_BUF_SIZE_WIDTH 14 ++ #define RX_KER_BUF_REGION_LBN 46 ++ #define RX_KER_BUF_REGION_WIDTH 2 ++ #define RX_KER_BUF_REGION0_DECODE 0 ++ #define RX_KER_BUF_REGION1_DECODE 1 ++ #define RX_KER_BUF_REGION2_DECODE 2 ++ #define RX_KER_BUF_REGION3_DECODE 3 ++ #define RX_KER_BUF_ADR_LBN 0 ++ #define RX_KER_BUF_ADR_WIDTH 46 ++/* Receive User IP Descriptor */ ++ #define RX_USR_2BYTE_OFS_LBN 20 ++ #define RX_USR_2BYTE_OFS_WIDTH 12 ++ #define RX_USR_BUF_ID_LBN 0 ++ #define RX_USR_BUF_ID_WIDTH 20 ++/* Transmit Kernel IP Descriptor */ ++ #define TX_KER_PORT_LBN 63 ++ #define TX_KER_PORT_WIDTH 1 ++ #define TX_KER_CONT_LBN 62 ++ #define TX_KER_CONT_WIDTH 1 ++ #define TX_KER_BYTE_CNT_LBN 48 ++ #define TX_KER_BYTE_CNT_WIDTH 14 ++ #define TX_KER_BUF_REGION_LBN 46 ++ #define TX_KER_BUF_REGION_WIDTH 2 ++ #define TX_KER_BUF_REGION0_DECODE 0 ++ #define TX_KER_BUF_REGION1_DECODE 1 ++ #define TX_KER_BUF_REGION2_DECODE 2 ++ #define TX_KER_BUF_REGION3_DECODE 3 ++ #define TX_KER_BUF_ADR_LBN 0 ++ #define TX_KER_BUF_ADR_WIDTH 46 ++/* Transmit User IP Descriptor */ ++ #define TX_USR_PORT_LBN 47 ++ #define TX_USR_PORT_WIDTH 1 ++ #define TX_USR_CONT_LBN 46 ++ #define TX_USR_CONT_WIDTH 1 ++ #define TX_USR_BYTE_CNT_LBN 33 ++ #define TX_USR_BYTE_CNT_WIDTH 13 ++ #define TX_USR_BUF_ID_LBN 13 ++ #define TX_USR_BUF_ID_WIDTH 20 ++ #define TX_USR_BYTE_OFS_LBN 0 ++ #define TX_USR_BYTE_OFS_WIDTH 13 +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_event.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_event.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,155 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) event ++ * definitions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++/*************---- Events Format C Header ----*************/ ++/*************---- Event entry ----*************/ ++ #define EV_CODE_LBN 60 ++ #define EV_CODE_WIDTH 4 ++ #define RX_IP_EV_DECODE 0 ++ #define TX_IP_EV_DECODE 2 ++ #define DRIVER_EV_DECODE 5 ++ #define GLOBAL_EV_DECODE 6 ++ #define DRV_GEN_EV_DECODE 7 ++ #define EV_DATA_LBN 0 ++ #define EV_DATA_WIDTH 60 ++/******---- Receive IP events for both Kernel & User event queues ----******/ ++ #define RX_EV_PKT_OK_LBN 56 ++ #define RX_EV_PKT_OK_WIDTH 1 ++ #define RX_EV_BUF_OWNER_ID_ERR_LBN 54 ++ #define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1 ++ #define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52 ++ #define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1 ++ #define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51 ++ #define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1 ++ #define RX_EV_ETH_CRC_ERR_LBN 50 ++ #define RX_EV_ETH_CRC_ERR_WIDTH 1 ++ #define RX_EV_FRM_TRUNC_LBN 49 ++ #define RX_EV_FRM_TRUNC_WIDTH 1 ++ #define RX_EV_DRIB_NIB_LBN 48 ++ #define RX_EV_DRIB_NIB_WIDTH 1 ++ #define RX_EV_TOBE_DISC_LBN 47 ++ #define RX_EV_TOBE_DISC_WIDTH 1 ++ #define RX_EV_PKT_TYPE_LBN 44 ++ #define RX_EV_PKT_TYPE_WIDTH 3 ++ #define RX_EV_PKT_TYPE_ETH_DECODE 0 ++ #define RX_EV_PKT_TYPE_LLC_DECODE 1 ++ #define RX_EV_PKT_TYPE_JUMBO_DECODE 2 ++ #define RX_EV_PKT_TYPE_VLAN_DECODE 3 ++ #define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4 ++ #define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5 ++ #define RX_EV_HDR_TYPE_LBN 42 ++ #define RX_EV_HDR_TYPE_WIDTH 2 ++ #define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0 ++ #define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1 ++ #define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2 ++ #define RX_EV_HDR_TYPE_NON_IP_DECODE 3 ++ #define RX_EV_DESC_Q_EMPTY_LBN 41 ++ #define RX_EV_DESC_Q_EMPTY_WIDTH 1 ++ #define RX_EV_MCAST_HASH_MATCH_LBN 40 ++ #define RX_EV_MCAST_HASH_MATCH_WIDTH 1 ++ #define RX_EV_MCAST_PKT_LBN 39 ++ #define RX_EV_MCAST_PKT_WIDTH 1 ++ #define RX_EV_Q_LABEL_LBN 32 ++ #define RX_EV_Q_LABEL_WIDTH 5 ++ #define RX_JUMBO_CONT_LBN 31 ++ #define RX_JUMBO_CONT_WIDTH 1 ++ #define RX_SOP_LBN 15 ++ #define RX_SOP_WIDTH 1 ++ #define RX_PORT_LBN 30 ++ #define RX_PORT_WIDTH 1 ++ #define RX_EV_BYTE_CNT_LBN 16 ++ #define RX_EV_BYTE_CNT_WIDTH 14 ++ #define RX_iSCSI_PKT_OK_LBN 14 ++ #define RX_iSCSI_PKT_OK_WIDTH 1 ++ #define RX_ISCSI_DDIG_ERR_LBN 13 ++ #define RX_ISCSI_DDIG_ERR_WIDTH 1 ++ #define RX_ISCSI_HDIG_ERR_LBN 12 ++ #define RX_ISCSI_HDIG_ERR_WIDTH 1 ++ #define RX_EV_DESC_PTR_LBN 0 ++ #define RX_EV_DESC_PTR_WIDTH 12 ++/******---- Transmit IP events for both Kernel & User event queues ----******/ ++ #define TX_EV_PKT_ERR_LBN 38 ++ #define TX_EV_PKT_ERR_WIDTH 1 ++ #define TX_EV_PKT_TOO_BIG_LBN 37 ++ #define TX_EV_PKT_TOO_BIG_WIDTH 1 ++ #define TX_EV_Q_LABEL_LBN 32 ++ #define TX_EV_Q_LABEL_WIDTH 5 ++ #define TX_EV_PORT_LBN 16 ++ #define TX_EV_PORT_WIDTH 1 ++ #define TX_EV_WQ_FF_FULL_LBN 15 ++ #define TX_EV_WQ_FF_FULL_WIDTH 1 ++ #define TX_EV_BUF_OWNER_ID_ERR_LBN 14 ++ #define TX_EV_BUF_OWNER_ID_ERR_WIDTH 1 ++ #define TX_EV_COMP_LBN 12 ++ #define TX_EV_COMP_WIDTH 1 ++ #define TX_EV_DESC_PTR_LBN 0 ++ #define TX_EV_DESC_PTR_WIDTH 12 ++/*************---- Char or Kernel driver events ----*************/ ++ #define DRIVER_EV_SUB_CODE_LBN 56 ++ #define DRIVER_EV_SUB_CODE_WIDTH 4 ++ #define TX_DESCQ_FLS_DONE_EV_DECODE 0x0 ++ #define RX_DESCQ_FLS_DONE_EV_DECODE 0x1 ++ #define EVQ_INIT_DONE_EV_DECODE 0x2 ++ #define EVQ_NOT_EN_EV_DECODE 0x3 ++ #define RX_DESCQ_FLSFF_OVFL_EV_DECODE 0x4 ++ #define SRM_UPD_DONE_EV_DECODE 0x5 ++ #define WAKE_UP_EV_DECODE 0x6 ++ #define TX_PKT_NON_TCP_UDP_DECODE 0x9 ++ #define TIMER_EV_DECODE 0xA ++ #define RX_DSC_ERROR_EV_DECODE 0xE ++ #define DRIVER_EV_TX_DESCQ_ID_LBN 0 ++ #define DRIVER_EV_TX_DESCQ_ID_WIDTH 12 ++ #define DRIVER_EV_RX_DESCQ_ID_LBN 0 ++ #define DRIVER_EV_RX_DESCQ_ID_WIDTH 12 ++ #define DRIVER_EV_EVQ_ID_LBN 0 ++ #define DRIVER_EV_EVQ_ID_WIDTH 12 ++ #define DRIVER_TMR_ID_LBN 0 ++ #define DRIVER_TMR_ID_WIDTH 12 ++ #define DRIVER_EV_SRM_UPD_LBN 0 ++ #define DRIVER_EV_SRM_UPD_WIDTH 2 ++ #define SRM_CLR_EV_DECODE 0 ++ #define SRM_UPD_EV_DECODE 1 ++ #define SRM_ILLCLR_EV_DECODE 2 ++/********---- Global events. Sent to both event queue 0 and 4. ----********/ ++ #define XFP_PHY_INTR_LBN 10 ++ #define XFP_PHY_INTR_WIDTH 1 ++ #define XG_PHY_INTR_LBN 9 ++ #define XG_PHY_INTR_WIDTH 1 ++ #define G_PHY1_INTR_LBN 8 ++ #define G_PHY1_INTR_WIDTH 1 ++ #define G_PHY0_INTR_LBN 7 ++ #define G_PHY0_INTR_WIDTH 1 ++/*************---- Driver generated events ----*************/ ++ #define DRV_GEN_EV_CODE_LBN 60 ++ #define DRV_GEN_EV_CODE_WIDTH 4 ++ #define DRV_GEN_EV_DATA_LBN 0 ++ #define DRV_GEN_EV_DATA_WIDTH 60 +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_intr_vec.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_intr_vec.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,44 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) interrupt ++ * vector definitions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++/*************---- Interrupt Vector Format C Header ----*************/ ++#define DW0_OFST 0x0 /* Double-word 0: Event queue FIFO interrupts */ ++ #define EVQ_FIFO_HF_LBN 1 ++ #define EVQ_FIFO_HF_WIDTH 1 ++ #define EVQ_FIFO_AF_LBN 0 ++ #define EVQ_FIFO_AF_WIDTH 1 ++#define DW1_OFST 0x4 /* Double-word 1: Interrupt indicator */ ++ #define INT_FLAG_LBN 0 ++ #define INT_FLAG_WIDTH 1 ++#define DW2_OFST 0x8 /* Double-word 2: Fatal interrupts */ ++ #define FATAL_INT_LBN 0 ++ #define FATAL_INT_WIDTH 1 +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/workarounds.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/workarounds.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,67 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides workaround settings for EtherFabric NICs. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_EFAB_WORKAROUNDS_H__ ++#define __CI_DRIVER_EFAB_WORKAROUNDS_H__ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Hardware workarounds which have global scope ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#if defined(__CI_HARDWARE_CONFIG_FALCON_B0__) ++/*------------------------------- B0 ---------------------------------------*/ ++ ++#define BUG2175_WORKAROUND 0 /* TX event batching for dual port operation. ++ This removes the effect (dup TX events) ++ of the fix ++ (TX event per packet + batch events) */ ++#define BUG5302_WORKAROUND 0 /* unstick TX DMAQ after out-of-range wr ptr */ ++#define BUG5762_WORKAROUND 0 /* Set all queues to jumbo mode */ ++#define BUG5391_WORKAROUND 0 /* Misaligned TX can't span 512-byte boundary */ ++#define BUG7916_WORKAROUND 0 /* RX flush gets lost */ ++ ++#else ++/*------------------------------- A0/A1 ------------------------------------*/ ++ ++#define BUG2175_WORKAROUND 1 /* TX event batching for dual port operation. ++ This removes the effect (dup TX events) ++ of the fix ++ (TX event per packet + batch events) */ ++#define BUG5302_WORKAROUND 1 /* unstick TX DMAQ after out-of-range wr ptr */ ++#define BUG5762_WORKAROUND 1 /* Set all queues to jumbo mode */ ++#define BUG5391_WORKAROUND 1 /* Misaligned TX can't span 512-byte boundary */ ++#define BUG7916_WORKAROUND 1 /* RX flush gets lost */ ++ ++#endif /* B0/A01 */ ++ ++#endif /* __CI_DRIVER_EFAB_WORKAROUNDS_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/resource/efx_vi.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/resource/efx_vi.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,273 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains public EFX VI API to Solarflare resource manager. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_RESOURCE_EFX_VI_H__ ++#define __CI_DRIVER_RESOURCE_EFX_VI_H__ ++ ++/* Default size of event queue in the efx_vi resource. Copied from ++ * CI_CFG_NETIF_EVENTQ_SIZE */ ++#define EFX_VI_EVENTQ_SIZE_DEFAULT 1024 ++ ++extern int efx_vi_eventq_size; ++ ++/************************************************************************** ++ * efx_vi_state types, allocation and free ++ **************************************************************************/ ++ ++/*! Handle for refering to a efx_vi */ ++struct efx_vi_state; ++ ++/*! ++ * Allocate an efx_vi, including event queue and pt_endpoint ++ * ++ * \param vih_out Pointer to a handle that is set on success ++ * \param ifindex Index of the network interface desired ++ * \return Zero on success (and vih_out set), non-zero on failure. ++ */ ++extern int ++efx_vi_alloc(struct efx_vi_state **vih_out, int ifindex); ++ ++/*! ++ * Free a previously allocated efx_vi ++ * ++ * \param vih The handle of the efx_vi to free ++ */ ++extern void ++efx_vi_free(struct efx_vi_state *vih); ++ ++/*! ++ * Reset a previously allocated efx_vi ++ * ++ * \param vih The handle of the efx_vi to reset ++ */ ++extern void ++efx_vi_reset(struct efx_vi_state *vih); ++ ++/************************************************************************** ++ * efx_vi_eventq types and functions ++ **************************************************************************/ ++ ++/*! ++ * Register a function to receive callbacks when event queue timeouts ++ * or wakeups occur. Only one function per efx_vi can be registered ++ * at once. ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param callback The function to callback ++ * \param context An argument to pass to the callback function ++ * \return Zero on success, non-zero on failure. ++ */ ++extern int ++efx_vi_eventq_register_callback(struct efx_vi_state *vih, ++ void (*callback)(void *context, int is_timeout), ++ void *context); ++ ++/*! ++ * Remove the current eventq timeout or wakeup callback function ++ * ++ * \param vih The handle to identify the efx_vi ++ * \return Zero on success, non-zero on failure ++ */ ++extern int ++efx_vi_eventq_kill_callback(struct efx_vi_state *vih); ++ ++/************************************************************************** ++ * efx_vi_dma_map types and functions ++ **************************************************************************/ ++ ++/*! ++ * Handle for refering to a efx_vi ++ */ ++struct efx_vi_dma_map_state; ++ ++/*! ++ * Map a list of buffer pages so they are registered with the hardware ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param addrs An array of page pointers to map ++ * \param n_addrs Length of the page pointer array. Must be a power of two. ++ * \param dmh_out Set on success to a handle used to refer to this mapping ++ * \return Zero on success, non-zero on failure. ++ */ ++extern int ++efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages, ++ int n_pages, struct efx_vi_dma_map_state **dmh_out); ++extern int ++efx_vi_dma_map_addrs(struct efx_vi_state *vih, ++ unsigned long long *dev_bus_addrs, int n_pages, ++ struct efx_vi_dma_map_state **dmh_out); ++ ++/*! ++ * Unmap a previously mapped set of pages so they are no longer registered ++ * with the hardware. ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param dmh The handle to identify the dma mapping ++ */ ++extern void ++efx_vi_dma_unmap_pages(struct efx_vi_state *vih, ++ struct efx_vi_dma_map_state *dmh); ++extern void ++efx_vi_dma_unmap_addrs(struct efx_vi_state *vih, ++ struct efx_vi_dma_map_state *dmh); ++ ++/*! ++ * Retrieve the buffer address of the mapping ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param dmh The handle to identify the buffer mapping ++ * \return The buffer address on success, or zero on failure ++ */ ++extern unsigned ++efx_vi_dma_get_map_addr(struct efx_vi_state *vih, ++ struct efx_vi_dma_map_state *dmh); ++ ++/************************************************************************** ++ * efx_vi filter functions ++ **************************************************************************/ ++ ++#define EFX_VI_STATIC_FILTERS 32 ++ ++/*! Handle to refer to a filter instance */ ++struct filter_resource_t; ++ ++/*! ++ * Allocate and add a filter ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param protocol The protocol of the new filter: UDP or TCP ++ * \param ip_addr_be32 The local ip address of the filter ++ * \param port_le16 The local port of the filter ++ * \param fh_out Set on success to be a handle to refer to this filter ++ * \return Zero on success, non-zero on failure. ++ */ ++extern int ++efx_vi_filter(struct efx_vi_state *vih, int protocol, unsigned ip_addr_be32, ++ int port_le16, struct filter_resource_t **fh_out); ++ ++/*! ++ * Remove a filter and free resources associated with it ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param fh The handle to identify the filter ++ * \return Zero on success, non-zero on failure ++ */ ++extern int ++efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh); ++ ++/************************************************************************** ++ * efx_vi hw resources types and functions ++ **************************************************************************/ ++ ++/*! Constants for the type field in efx_vi_hw_resource */ ++#define EFX_VI_HW_RESOURCE_TXDMAQ 0x0 /* PFN of TX DMA Q */ ++#define EFX_VI_HW_RESOURCE_RXDMAQ 0x1 /* PFN of RX DMA Q */ ++#define EFX_VI_HW_RESOURCE_EVQTIMER 0x4 /* Address of event q timer */ ++ ++/* Address of event q pointer (EF1) */ ++#define EFX_VI_HW_RESOURCE_EVQPTR 0x5 ++/* Address of register pointer (Falcon A) */ ++#define EFX_VI_HW_RESOURCE_EVQRPTR 0x6 ++/* Offset of register pointer (Falcon B) */ ++#define EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET 0x7 ++/* Address of mem KVA */ ++#define EFX_VI_HW_RESOURCE_EVQMEMKVA 0x8 ++/* PFN of doorbell page (Falcon) */ ++#define EFX_VI_HW_RESOURCE_BELLPAGE 0x9 ++ ++/*! How large an array to allocate for the get_() functions - smaller ++ than the total number of constants as some are mutually exclusive */ ++#define EFX_VI_HW_RESOURCE_MAXSIZE 0x7 ++ ++/*! Constants for the mem_type field in efx_vi_hw_resource */ ++#define EFX_VI_HW_RESOURCE_IOBUFFER 0 /* Host memory */ ++#define EFX_VI_HW_RESOURCE_PERIPHERAL 1 /* Card memory/registers */ ++ ++/*! ++ * Data structure providing information on a hardware resource mapping ++ */ ++struct efx_vi_hw_resource { ++ u8 type; /*!< What this resource represents */ ++ u8 mem_type; /*!< What type of memory is it in, eg, ++ * host or iomem */ ++ u8 more_to_follow; /*!< Is this part of a multi-region resource */ ++ u32 length; /*!< Length of the resource in bytes */ ++ unsigned long address; /*!< Address of this resource */ ++}; ++ ++/*! ++ * Metadata concerning the list of hardware resource mappings ++ */ ++struct efx_vi_hw_resource_metadata { ++ int evq_order; ++ int evq_offs; ++ int evq_capacity; ++ int instance; ++ unsigned rx_capacity; ++ unsigned tx_capacity; ++ int nic_arch; ++ int nic_revision; ++ char nic_variant; ++}; ++ ++/*! ++ * Obtain a list of hardware resource mappings, using virtual addresses ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param mdata Pointer to a structure to receive the metadata ++ * \param hw_res_array An array to receive the list of hardware resources ++ * \param length The length of hw_res_array. Updated on success to contain ++ * the number of entries in the supplied array that were used. ++ * \return Zero on success, non-zero on failure ++ */ ++extern int ++efx_vi_hw_resource_get_virt(struct efx_vi_state *vih, ++ struct efx_vi_hw_resource_metadata *mdata, ++ struct efx_vi_hw_resource *hw_res_array, ++ int *length); ++ ++/*! ++ * Obtain a list of hardware resource mappings, using physical addresses ++ * ++ * \param vih The handle to identify the efx_vi ++ * \param mdata Pointer to a structure to receive the metadata ++ * \param hw_res_array An array to receive the list of hardware resources ++ * \param length The length of hw_res_array. Updated on success to contain ++ * the number of entries in the supplied array that were used. ++ * \return Zero on success, non-zero on failure ++ */ ++extern int ++efx_vi_hw_resource_get_phys(struct efx_vi_state *vih, ++ struct efx_vi_hw_resource_metadata *mdata, ++ struct efx_vi_hw_resource *hw_res_array, ++ int *length); ++ ++#endif /* __CI_DRIVER_RESOURCE_EFX_VI_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/resource/linux_efhw_nic.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/driver/resource/linux_efhw_nic.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,69 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains definition of the public type struct linux_efhw_nic. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_RESOURCE_LINUX_RESOURCE__ ++#define __CI_DRIVER_RESOURCE_LINUX_RESOURCE__ ++ ++#include ++#include ++ ++ ++/************************************************************************ ++ * Per-nic structure in the resource driver * ++ ************************************************************************/ ++ ++struct linux_efhw_nic { ++ struct efrm_nic efrm_nic; ++ ++ struct pci_dev *pci_dev; /*!< pci descriptor */ ++ struct tasklet_struct tasklet; /*!< for interrupt bottom half */ ++ ++ /* Physical addresses of the control aperture bar. */ ++ unsigned long ctr_ap_pci_addr; ++ ++ /*! Callbacks for driverlink, when needed. */ ++ struct efx_dl_callbacks *dl_callbacks; ++ ++ /*! Event handlers. */ ++ struct efhw_ev_handler *ev_handlers; ++ ++}; ++ ++#define linux_efhw_nic(_efhw_nic) \ ++ container_of(_efhw_nic, struct linux_efhw_nic, efrm_nic.efhw_nic) ++ ++#endif /* __CI_DRIVER_RESOURCE_LINUX_RESOURCE__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/checks.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/checks.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,118 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides helpers to turn bit shifts into dword shifts and ++ * check that the bit fields haven't overflown the dword etc. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_CHECK_H__ ++#define __CI_EFHW_CHECK_H__ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Helpers to turn bit shifts into dword shifts and check that the bit fields ++ * haven't overflown the dword etc. Aim is to preserve consistency with the ++ * autogenerated headers - once stable we could hard code. ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* mask constructors */ ++#define __FALCON_MASK(WIDTH, T) ((((T)1) << (WIDTH)) - 1) ++#define __FALCON_MASK32(WIDTH) __FALCON_MASK((WIDTH), uint32_t) ++#define __FALCON_MASK64(WIDTH) __FALCON_MASK((WIDTH), uint64_t) ++ ++#define __FALCON_MASKFIELD32(LBN, WIDTH) \ ++ ((uint32_t)(__FALCON_MASK32(WIDTH) << (LBN))) ++ ++/* constructors for fields which span the first and second dwords */ ++#define __LW(LBN) (32 - LBN) ++#define __LOW(v, LBN, WIDTH) \ ++ ((uint32_t)(((v) & __FALCON_MASK64(__LW((LBN)))) << (LBN))) ++#define __HIGH(v, LBN, WIDTH) \ ++ ((uint32_t)(((v) >> __LW((LBN))) & \ ++ __FALCON_MASK64((WIDTH - __LW((LBN)))))) ++/* constructors for fields within the second dword */ ++#define __DW2(LBN) ((LBN) - 32) ++ ++/* constructors for fields which span the second and third dwords */ ++#define __LW2(LBN) (64 - LBN) ++#define __LOW2(v, LBN, WIDTH) \ ++ ((uint32_t)(((v) & __FALCON_MASK64(__LW2((LBN)))) << ((LBN) - 32))) ++#define __HIGH2(v, LBN, WIDTH) \ ++ ((uint32_t)(((v) >> __LW2((LBN))) & \ ++ __FALCON_MASK64((WIDTH - __LW2((LBN)))))) ++ ++/* constructors for fields within the third dword */ ++#define __DW3(LBN) ((LBN) - 64) ++ ++/* constructors for fields which span the third and fourth dwords */ ++#define __LW3(LBN) (96 - LBN) ++#define __LOW3(v, LBN, WIDTH) \ ++ ((uint32_t)(((v) & __FALCON_MASK64(__LW3((LBN)))) << ((LBN) - 64))) ++#define __HIGH3(v, LBN, WIDTH) \ ++ ((ci_unit32)(((v) >> __LW3((LBN))) & \ ++ __FALCON_MASK64((WIDTH - __LW3((LBN)))))) ++ ++/* constructors for fields within the fourth dword */ ++#define __DW4(LBN) ((LBN) - 96) ++ ++/* checks that the autogenerated headers are consistent with our model */ ++#define __WIDTHCHCK(a, b) EFHW_ASSERT((a) == (b)) ++#define __RANGECHCK(v, WIDTH) \ ++ EFHW_ASSERT(((uint64_t)(v) & ~(__FALCON_MASK64((WIDTH)))) == 0) ++ ++/* fields within the first dword */ ++#define __DWCHCK(LBN, WIDTH) \ ++ EFHW_ASSERT(((LBN) >= 0) && (((LBN)+(WIDTH)) <= 32)) ++ ++/* fields which span the first and second dwords */ ++#define __LWCHK(LBN, WIDTH) EFHW_ASSERT(WIDTH >= __LW(LBN)) ++ ++/* fields within the second dword */ ++#define __DW2CHCK(LBN, WIDTH) \ ++ EFHW_ASSERT(((LBN) >= 32) && (((LBN)+(WIDTH)) <= 64)) ++ ++/* fields which span the second and third dwords */ ++#define __LW2CHK(LBN, WIDTH) EFHW_ASSERT(WIDTH >= __LW2(LBN)) ++ ++/* fields within the third dword */ ++#define __DW3CHCK(LBN, WIDTH) \ ++ EFHW_ASSERT(((LBN) >= 64) && (((LBN)+(WIDTH)) <= 96)) ++ ++/* fields which span the third and fourth dwords */ ++#define __LW3CHK(LBN, WIDTH) EFHW_ASSERT(WIDTH >= __LW3(LBN)) ++ ++/* fields within the fourth dword */ ++#define __DW4CHCK(LBN, WIDTH) \ ++ EFHW_ASSERT(((LBN) >= 96) && (((LBN)+(WIDTH)) <= 128)) ++ ++/* fields in the first qword */ ++#define __QWCHCK(LBN, WIDTH) \ ++ EFHW_ASSERT(((LBN) >= 0) && (((LBN)+(WIDTH)) <= 64)) ++ ++#endif /* __CI_EFHW_CHECK_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/common.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/common.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,93 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides API of the efhw library which may be used both from ++ * the kernel and from the user-space code. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_COMMON_H__ ++#define __CI_EFHW_COMMON_H__ ++ ++#include ++ ++typedef uint32_t efhw_buffer_addr_t; ++#define EFHW_BUFFER_ADDR_FMT "[ba:%"PRIx32"]" ++ ++/*! Comment? */ ++typedef union { ++ uint64_t u64; ++ struct { ++ uint32_t a; ++ uint32_t b; ++ } opaque; ++} efhw_event_t; ++ ++/* Flags for TX/RX queues */ ++#define EFHW_VI_JUMBO_EN 0x01 /*! scatter RX over multiple desc */ ++#define EFHW_VI_ISCSI_RX_HDIG_EN 0x02 /*! iscsi rx header digest */ ++#define EFHW_VI_ISCSI_TX_HDIG_EN 0x04 /*! iscsi tx header digest */ ++#define EFHW_VI_ISCSI_RX_DDIG_EN 0x08 /*! iscsi rx data digest */ ++#define EFHW_VI_ISCSI_TX_DDIG_EN 0x10 /*! iscsi tx data digest */ ++#define EFHW_VI_TX_PHYS_ADDR_EN 0x20 /*! TX physical address mode */ ++#define EFHW_VI_RX_PHYS_ADDR_EN 0x40 /*! RX physical address mode */ ++#define EFHW_VI_RM_WITH_INTERRUPT 0x80 /*! VI with an interrupt */ ++#define EFHW_VI_TX_IP_CSUM_DIS 0x100 /*! enable ip checksum generation */ ++#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum ++ generation */ ++#define EFHW_VI_TX_TCPUDP_ONLY 0x400 /*! drop non-tcp/udp packets */ ++ ++/* Types of hardware filter */ ++/* Each of these values implicitly selects scatter filters on B0 - or in ++ EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK if a non-scatter filter is required */ ++#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD (0) /* dest host only */ ++#define EFHW_IP_FILTER_TYPE_UDP_FULL (1) /* dest host and port */ ++#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD (2) /* dest based filter */ ++#define EFHW_IP_FILTER_TYPE_TCP_FULL (3) /* src filter */ ++/* Same again, but with RSS (for B0 only) */ ++#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD_RSS_B0 (4) ++#define EFHW_IP_FILTER_TYPE_UDP_FULL_RSS_B0 (5) ++#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD_RSS_B0 (6) ++#define EFHW_IP_FILTER_TYPE_TCP_FULL_RSS_B0 (7) ++ ++#define EFHW_IP_FILTER_TYPE_FULL_MASK (0x1) /* Mask for full / wildcard */ ++#define EFHW_IP_FILTER_TYPE_TCP_MASK (0x2) /* Mask for TCP type */ ++#define EFHW_IP_FILTER_TYPE_RSS_B0_MASK (0x4) /* Mask for B0 RSS enable */ ++#define EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK (0x8) /* Mask for B0 SCATTER dsbl */ ++ ++#define EFHW_IP_FILTER_TYPE_MASK (0xffff) /* Mask of types above */ ++ ++#define EFHW_IP_FILTER_BROADCAST (0x10000) /* driverlink filter ++ support */ ++ ++#endif /* __CI_EFHW_COMMON_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/common_sysdep.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/common_sysdep.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,61 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides version-independent Linux kernel API for ++ * userland-to-kernel interfaces. ++ * Only kernels >=2.6.9 are supported. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_COMMON_LINUX_H__ ++#define __CI_EFHW_COMMON_LINUX_H__ ++ ++#include ++ ++/* Dirty hack, but Linux kernel does not provide DMA_ADDR_T_FMT */ ++#if BITS_PER_LONG == 64 || defined(CONFIG_HIGHMEM64G) ++#define DMA_ADDR_T_FMT "%llx" ++#else ++#define DMA_ADDR_T_FMT "%x" ++#endif ++ ++/* Linux kernel also does not provide PRIx32... Sigh. */ ++#define PRIx32 "x" ++ ++#ifdef __ia64__ ++# define PRIx64 "lx" ++#else ++# define PRIx64 "llx" ++#endif ++ ++#endif /* __CI_EFHW_COMMON_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/debug.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/debug.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,84 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides debug-related API for efhw library using Linux kernel ++ * primitives. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_DEBUG_LINUX_H__ ++#define __CI_EFHW_DEBUG_LINUX_H__ ++ ++#define EFHW_PRINTK_PREFIX "[sfc efhw] " ++ ++#define EFHW_PRINTK(level, fmt, ...) \ ++ printk(level EFHW_PRINTK_PREFIX fmt "\n", __VA_ARGS__) ++ ++/* Following macros should be used with non-zero format parameters ++ * due to __VA_ARGS__ limitations. Use "%s" with __func__ if you can't ++ * find better parameters. */ ++#define EFHW_ERR(fmt, ...) EFHW_PRINTK(KERN_ERR, fmt, __VA_ARGS__) ++#define EFHW_WARN(fmt, ...) EFHW_PRINTK(KERN_WARNING, fmt, __VA_ARGS__) ++#define EFHW_NOTICE(fmt, ...) EFHW_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__) ++#if 0 && !defined(NDEBUG) ++#define EFHW_TRACE(fmt, ...) EFHW_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__) ++#else ++#define EFHW_TRACE(fmt, ...) ++#endif ++ ++#ifndef NDEBUG ++#define EFHW_ASSERT(cond) BUG_ON((cond) == 0) ++#define EFHW_DO_DEBUG(expr) expr ++#else ++#define EFHW_ASSERT(cond) ++#define EFHW_DO_DEBUG(expr) ++#endif ++ ++#define EFHW_TEST(expr) \ ++ do { \ ++ if (unlikely(!(expr))) \ ++ BUG(); \ ++ } while (0) ++ ++/* Build time asserts. We paste the line number into the type name ++ * so that the macro can be used more than once per file even if the ++ * compiler objects to multiple identical typedefs. Collisions ++ * between use in different header files is still possible. */ ++#ifndef EFHW_BUILD_ASSERT ++#define __EFHW_BUILD_ASSERT_NAME(_x) __EFHW_BUILD_ASSERT_ILOATHECPP(_x) ++#define __EFHW_BUILD_ASSERT_ILOATHECPP(_x) __EFHW_BUILD_ASSERT__ ##_x ++#define EFHW_BUILD_ASSERT(e) \ ++ typedef char __EFHW_BUILD_ASSERT_NAME(__LINE__)[(e) ? 1 : -1] ++#endif ++ ++#endif /* __CI_EFHW_DEBUG_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/efhw_config.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/efhw_config.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,43 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides some limits used in both kernel and userland code. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_EFAB_CONFIG_H__ ++#define __CI_EFHW_EFAB_CONFIG_H__ ++ ++#define EFHW_MAX_NR_DEVS 5 /* max number of efhw devices supported */ ++ ++#endif /* __CI_EFHW_EFAB_CONFIG_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/efhw_types.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/efhw_types.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,382 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides struct efhw_nic and some related types. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_EFAB_TYPES_H__ ++#define __CI_EFHW_EFAB_TYPES_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * forward type declarations ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_nic; ++ ++/*-------------------------------------------------------------------- ++ * ++ * Managed interface ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_buffer_table_allocation{ ++ unsigned base; ++ unsigned order; ++}; ++ ++struct eventq_resource_hardware { ++ /*!iobuffer allocated for eventq - can be larger than eventq */ ++ struct efhw_iopages iobuff; ++ unsigned iobuff_off; ++ struct efhw_buffer_table_allocation buf_tbl_alloc; ++ int capacity; /*!< capacity of event queue */ ++}; ++ ++/*-------------------------------------------------------------------- ++ * ++ * event queues and event driven callbacks ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_keventq { ++ int lock; ++ caddr_t evq_base; ++ int32_t evq_ptr; ++ uint32_t evq_mask; ++ unsigned instance; ++ struct eventq_resource_hardware hw; ++ struct efhw_ev_handler *ev_handlers; ++}; ++ ++/*-------------------------------------------------------------------- ++ * ++ * filters ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_filter_spec { ++ uint dmaq_id; ++ uint32_t saddr_le32; ++ uint32_t daddr_le32; ++ uint16_t sport_le16; ++ uint16_t dport_le16; ++ unsigned tcp : 1; ++ unsigned full : 1; ++ unsigned rss : 1; /* not supported on A1 */ ++ unsigned scatter : 1; /* not supported on A1 */ ++}; ++ ++struct efhw_filter_depth { ++ unsigned needed; ++ unsigned max; ++}; ++ ++struct efhw_filter_search_limits { ++ unsigned tcp_full; ++ unsigned tcp_wild; ++ unsigned udp_full; ++ unsigned udp_wild; ++}; ++ ++ ++/********************************************************************** ++ * Portable HW interface. *************************************** ++ **********************************************************************/ ++ ++/*-------------------------------------------------------------------- ++ * ++ * EtherFabric Functional units - configuration and control ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_func_ops { ++ ++ /*-------------- Initialisation ------------ */ ++ ++ /*! close down all hardware functional units - leaves NIC in a safe ++ state for driver unload */ ++ void (*close_hardware) (struct efhw_nic *nic); ++ ++ /*! initialise all hardware functional units */ ++ int (*init_hardware) (struct efhw_nic *nic, ++ struct efhw_ev_handler *, ++ const uint8_t *mac_addr, int non_irq_evq); ++ ++ /*-------------- Interrupt support ------------ */ ++ ++ /*! Main interrupt routine ++ ** This function returns, ++ ** - zero, if the IRQ was not generated by EF1 ++ ** - non-zero, if EF1 was the source of the IRQ ++ ** ++ ** ++ ** opaque is an OS provided pointer for use by the OS callbacks ++ ** e.g in Windows used to indicate DPC scheduled ++ */ ++ int (*interrupt) (struct efhw_nic *nic); ++ ++ /*! Enable the interrupt */ ++ void (*interrupt_enable) (struct efhw_nic *nic); ++ ++ /*! Disable the interrupt */ ++ void (*interrupt_disable) (struct efhw_nic *nic); ++ ++ /*! Set interrupt moderation strategy for the given IRQ unit ++ ** val is in usec ++ */ ++ void (*set_interrupt_moderation)(struct efhw_nic *nic, int evq, ++ uint val); ++ ++ /*-------------- Event support ------------ */ ++ ++ /*! Enable the given event queue ++ depending on the underlying implementation (EF1 or Falcon) then ++ either a q_base_addr in host memory, or a buffer base id should ++ be proivded ++ */ ++ void (*event_queue_enable) (struct efhw_nic *nic, ++ uint evq, /* evnt queue index */ ++ uint evq_size, /* units of #entries */ ++ dma_addr_t q_base_addr, uint buf_base_id, ++ int interrupting); ++ ++ /*! Disable the given event queue (and any associated timer) */ ++ void (*event_queue_disable) (struct efhw_nic *nic, uint evq, ++ int timer_only); ++ ++ /*! request wakeup from the NIC on a given event Q */ ++ void (*wakeup_request) (struct efhw_nic *nic, dma_addr_t q_base_addr, ++ int next_i, int evq); ++ ++ /*! Push a SW event on a given eventQ */ ++ void (*sw_event) (struct efhw_nic *nic, int data, int evq); ++ ++ /*-------------- IP Filter API ------------ */ ++ ++ /*! Setup a given filter - The software can request a filter_i, ++ * but some EtherFabric implementations will override with ++ * a more suitable index ++ */ ++ int (*ipfilter_set) (struct efhw_nic *nic, int type, ++ int *filter_i, int dmaq, ++ unsigned saddr_be32, unsigned sport_be16, ++ unsigned daddr_be32, unsigned dport_be16); ++ ++ /*! Clear down a given filter */ ++ void (*ipfilter_clear) (struct efhw_nic *nic, int filter_idx); ++ ++ /*-------------- DMA support ------------ */ ++ ++ /*! Initialise NIC state for a given TX DMAQ */ ++ void (*dmaq_tx_q_init) (struct efhw_nic *nic, ++ uint dmaq, uint evq, uint owner, uint tag, ++ uint dmaq_size, uint buf_idx, uint flags); ++ ++ /*! Initialise NIC state for a given RX DMAQ */ ++ void (*dmaq_rx_q_init) (struct efhw_nic *nic, ++ uint dmaq, uint evq, uint owner, uint tag, ++ uint dmaq_size, uint buf_idx, uint flags); ++ ++ /*! Disable a given TX DMAQ */ ++ void (*dmaq_tx_q_disable) (struct efhw_nic *nic, uint dmaq); ++ ++ /*! Disable a given RX DMAQ */ ++ void (*dmaq_rx_q_disable) (struct efhw_nic *nic, uint dmaq); ++ ++ /*! Flush a given TX DMA channel */ ++ int (*flush_tx_dma_channel) (struct efhw_nic *nic, uint dmaq); ++ ++ /*! Flush a given RX DMA channel */ ++ int (*flush_rx_dma_channel) (struct efhw_nic *nic, uint dmaq); ++ ++ /*-------------- Buffer table Support ------------ */ ++ ++ /*! Initialise a buffer table page */ ++ void (*buffer_table_set) (struct efhw_nic *nic, ++ dma_addr_t dma_addr, ++ uint bufsz, uint region, ++ int own_id, int buffer_id); ++ ++ /*! Initialise a block of buffer table pages */ ++ void (*buffer_table_set_n) (struct efhw_nic *nic, int buffer_id, ++ dma_addr_t dma_addr, ++ uint bufsz, uint region, ++ int n_pages, int own_id); ++ ++ /*! Clear a block of buffer table pages */ ++ void (*buffer_table_clear) (struct efhw_nic *nic, int buffer_id, ++ int num); ++ ++ /*! Commit a buffer table update */ ++ void (*buffer_table_commit) (struct efhw_nic *nic); ++ ++ /*-------------- New filter API ------------ */ ++ ++ /*! Set a given filter */ ++ int (*filter_set) (struct efhw_nic *nic, struct efhw_filter_spec *spec, ++ int *filter_idx_out); ++ ++ /*! Clear a given filter */ ++ void (*filter_clear) (struct efhw_nic *nic, int filter_idx); ++}; ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * NIC type ++ * ++ *---------------------------------------------------------------------------*/ ++ ++struct efhw_device_type { ++ int arch; /* enum efhw_arch */ ++ char variant; /* 'A', 'B', ... */ ++ int revision; /* 0, 1, ... */ ++}; ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * EtherFabric NIC instance - nic.c for HW independent functions ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/*! */ ++struct efhw_nic { ++ /*! zero base index in efrm_nic_tablep->nic array */ ++ int index; ++ int ifindex; /*!< OS level nic index */ ++ struct net *nd_net; ++ ++ struct efhw_device_type devtype; ++ ++ /*! Options that can be set by user. */ ++ unsigned options; ++# define NIC_OPT_EFTEST 0x1 /* owner is an eftest app */ ++ ++# define NIC_OPT_DEFAULT 0 ++ ++ /*! Internal flags that indicate hardware properties at runtime. */ ++ unsigned flags; ++# define NIC_FLAG_NO_INTERRUPT 0x01 /* to be set at init time only */ ++# define NIC_FLAG_TRY_MSI 0x02 ++# define NIC_FLAG_MSI 0x04 ++# define NIC_FLAG_OS_IRQ_EN 0x08 ++ ++ unsigned mtu; /*!< MAC MTU (includes MAC hdr) */ ++ ++ /* hardware resources */ ++ ++ /*! I/O address of the start of the bar */ ++ volatile char __iomem *bar_ioaddr; ++ ++ /*! Bar number of control aperture. */ ++ unsigned ctr_ap_bar; ++ /*! Length of control aperture in bytes. */ ++ unsigned ctr_ap_bytes; ++ ++ uint8_t mac_addr[ETH_ALEN]; /*!< mac address */ ++ ++ /*! EtherFabric Functional Units -- functions */ ++ const struct efhw_func_ops *efhw_func; ++ ++ /*! This lock protects a number of misc NIC resources. It should ++ * only be used for things that can be at the bottom of the lock ++ * order. ie. You mustn't attempt to grab any other lock while ++ * holding this one. ++ */ ++ spinlock_t *reg_lock; ++ spinlock_t the_reg_lock; ++ ++ int buf_commit_outstanding; /*!< outstanding buffer commits */ ++ ++ /*! interrupt callbacks (hard-irq) */ ++ void (*irq_handler) (struct efhw_nic *, int unit); ++ ++ /*! event queues per driver */ ++ struct efhw_keventq interrupting_evq; ++ ++/* for marking when we are not using an IRQ unit ++ - 0 is a valid offset to an IRQ unit on EF1! */ ++#define EFHW_IRQ_UNIT_UNUSED 0xffff ++ /*! interrupt unit in use for the interrupting event queue */ ++ unsigned int irq_unit; ++ ++ struct efhw_keventq non_interrupting_evq; ++ ++ struct efhw_iopage irq_iobuff; /*!< Falcon SYSERR interrupt */ ++ ++ /* The new driverlink infrastructure. */ ++ struct efx_dl_device *net_driver_dev; ++ struct efx_dlfilt_cb_s *dlfilter_cb; ++ ++ /*! Bit masks of the sizes of event queues and dma queues supported ++ * by the nic. */ ++ unsigned evq_sizes; ++ unsigned rxq_sizes; ++ unsigned txq_sizes; ++ ++ /* Size of filter table. */ ++ unsigned ip_filter_tbl_size; ++ ++ /* Number of filters currently used */ ++ unsigned ip_filter_tbl_used; ++ ++ /* Dynamically allocated filter state. */ ++ uint8_t *filter_in_use; ++ struct efhw_filter_spec *filter_spec_cache; ++ ++ /* Currently required and maximum filter table search depths. */ ++ struct efhw_filter_depth tcp_full_srch; ++ struct efhw_filter_depth tcp_wild_srch; ++ struct efhw_filter_depth udp_full_srch; ++ struct efhw_filter_depth udp_wild_srch; ++ ++ /* Number of event queues, DMA queues and timers. */ ++ unsigned num_evqs; ++ unsigned num_dmaqs; ++ unsigned num_timers; ++}; ++ ++ ++#define EFHW_KVA(nic) ((nic)->bar_ioaddr) ++ ++ ++#endif /* __CI_EFHW_EFHW_TYPES_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/eventq.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/eventq.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,72 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains API provided by efhw/eventq.c file. This file is not ++ * designed for use outside of the SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_EVENTQ_H__ ++#define __CI_EFHW_EVENTQ_H__ ++ ++#include ++#include ++ ++/*! Poll the event queue. */ ++extern int efhw_keventq_poll(struct efhw_nic *, struct efhw_keventq *); ++ ++/*! Callbacks for handling events. */ ++struct efhw_ev_handler { ++ void (*wakeup_fn)(struct efhw_nic *nic, unsigned); ++ void (*timeout_fn)(struct efhw_nic *nic, unsigned); ++ void (*dmaq_flushed_fn) (struct efhw_nic *, unsigned, int); ++}; ++ ++extern int efhw_keventq_ctor(struct efhw_nic *, int instance, ++ struct efhw_keventq *, struct efhw_ev_handler *); ++extern void efhw_keventq_dtor(struct efhw_nic *, struct efhw_keventq *); ++ ++extern void efhw_handle_txdmaq_flushed(struct efhw_nic *, ++ struct efhw_ev_handler *, ++ efhw_event_t *); ++extern void efhw_handle_rxdmaq_flushed(struct efhw_nic *, ++ struct efhw_ev_handler *, ++ efhw_event_t *); ++extern void efhw_handle_wakeup_event(struct efhw_nic *, ++ struct efhw_ev_handler *, ++ efhw_event_t *); ++extern void efhw_handle_timeout_event(struct efhw_nic *, ++ struct efhw_ev_handler *, ++ efhw_event_t *); ++ ++#endif /* __CI_EFHW_EVENTQ_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/eventq_macros.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/eventq_macros.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,77 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides some event-related macros. This file is designed for ++ * use from kernel and from the userland contexts. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_EVENTQ_MACROS_H__ ++#define __CI_EFHW_EVENTQ_MACROS_H__ ++ ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * Event Queue manipulation ++ * ++ *--------------------------------------------------------------------*/ ++ ++#define EFHW_EVENT_OFFSET(q, s, i) \ ++ (((s)->evq_ptr - (i) * (int32_t)sizeof(efhw_event_t)) \ ++ & (q)->evq_mask) ++ ++#define EFHW_EVENT_PTR(q, s, i) \ ++ ((efhw_event_t *)((q)->evq_base + EFHW_EVENT_OFFSET(q, s, i))) ++ ++#define EFHW_EVENTQ_NEXT(s) \ ++ do { ((s)->evq_ptr += sizeof(efhw_event_t)); } while (0) ++ ++#define EFHW_EVENTQ_PREV(s) \ ++ do { ((s)->evq_ptr -= sizeof(efhw_event_t)); } while (0) ++ ++/* Be worried about this on byteswapped machines */ ++/* Due to crazy chipsets, we see the event words being written in ++** arbitrary order (bug4539). So test for presence of event must ensure ++** that both halves have changed from the null. ++*/ ++#define EFHW_IS_EVENT(evp) \ ++ (((evp)->opaque.a != (uint32_t)-1) && \ ++ ((evp)->opaque.b != (uint32_t)-1)) ++#define EFHW_CLEAR_EVENT(evp) ((evp)->u64 = (uint64_t)-1) ++#define EFHW_CLEAR_EVENT_VALUE 0xff ++ ++#define EFHW_EVENT_OVERFLOW(evq, s) \ ++ (EFHW_IS_EVENT(EFHW_EVENT_PTR(evq, s, 1))) ++ ++#endif /* __CI_EFHW_EVENTQ_MACROS_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/falcon.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/falcon.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,94 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains API provided by efhw/falcon.c file. This file is not ++ * designed for use outside of the SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_FALCON_H__ ++#define __CI_EFHW_FALCON_H__ ++ ++#include ++#include ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Locks - unfortunately required ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#define FALCON_LOCK_DECL irq_flags_t lock_state ++#define FALCON_LOCK_LOCK(nic) \ ++ spin_lock_irqsave((nic)->reg_lock, lock_state) ++#define FALCON_LOCK_UNLOCK(nic) \ ++ spin_unlock_irqrestore((nic)->reg_lock, lock_state) ++ ++extern struct efhw_func_ops falcon_char_functional_units; ++ ++/*! specify a pace value for a TX DMA Queue */ ++extern void falcon_nic_pace(struct efhw_nic *nic, uint dmaq, uint pace); ++ ++/*! configure the pace engine */ ++extern void falcon_nic_pace_cfg(struct efhw_nic *nic, int fb_base, ++ int bin_thresh); ++ ++/*! confirm buffer table updates - should be used for items where ++ loss of data would be unacceptable. E.g for the buffers that back ++ an event or DMA queue */ ++extern void falcon_nic_buffer_table_confirm(struct efhw_nic *nic); ++ ++/*! Reset the all the TX DMA queue pointers. */ ++extern void falcon_clobber_tx_dma_ptrs(struct efhw_nic *nic, uint dmaq); ++ ++extern int ++falcon_handle_char_event(struct efhw_nic *nic, ++ struct efhw_ev_handler *h, efhw_event_t *evp); ++ ++/*! Acknowledge to HW that processing is complete on a given event queue */ ++extern void falcon_nic_evq_ack(struct efhw_nic *nic, uint evq, /* evq id */ ++ uint rptr, /* new read pointer update */ ++ bool wakeup /* request a wakeup event if ++ ptr's != */ ++ ); ++ ++extern void ++falcon_nic_buffer_table_set_n(struct efhw_nic *nic, int buffer_id, ++ dma_addr_t dma_addr, uint bufsz, uint region, ++ int n_pages, int own_id); ++ ++extern int falcon_nic_filter_ctor(struct efhw_nic *nic); ++ ++extern void falcon_nic_filter_dtor(struct efhw_nic *nic); ++ ++#endif /* __CI_EFHW_FALCON_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/falcon_hash.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/falcon_hash.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,58 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains API provided by efhw/falcon_hash.c file. ++ * Function declared in this file are not exported from the Linux ++ * sfc_resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_FALCON_HASH_H__ ++#define __CI_EFHW_FALCON_HASH_H__ ++ ++extern unsigned int ++falcon_hash_get_ip_key(unsigned int src_ip, unsigned int src_port, ++ unsigned int dest_ip, unsigned int dest_port, ++ int tcp, int full); ++ ++extern unsigned int ++falcon_hash_function1(unsigned int key, unsigned int nfilters); ++ ++extern unsigned int ++falcon_hash_function2(unsigned int key, unsigned int nfilters); ++ ++extern unsigned int ++falcon_hash_iterator(unsigned int hash1, unsigned int hash2, ++ unsigned int n_search, unsigned int nfilters); ++ ++#endif /* __CI_EFHW_FALCON_HASH_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/hardware_sysdep.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/hardware_sysdep.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,69 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides version-independent Linux kernel API for header files ++ * with hardware-related definitions (in ci/driver/efab/hardware*). ++ * Only kernels >=2.6.9 are supported. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_HARDWARE_LINUX_H__ ++#define __CI_EFHW_HARDWARE_LINUX_H__ ++ ++#include ++ ++#ifdef __LITTLE_ENDIAN ++#define EFHW_IS_LITTLE_ENDIAN ++#elif __BIG_ENDIAN ++#define EFHW_IS_BIG_ENDIAN ++#else ++#error Unknown endianness ++#endif ++ ++#ifndef readq ++static inline uint64_t __readq(volatile void __iomem *addr) ++{ ++ return *(volatile uint64_t *)addr; ++} ++#define readq(x) __readq(x) ++#endif ++ ++#ifndef writeq ++static inline void __writeq(uint64_t v, volatile void __iomem *addr) ++{ ++ *(volatile uint64_t *)addr = v; ++} ++#define writeq(val, addr) __writeq((val), (addr)) ++#endif ++ ++#endif /* __CI_EFHW_HARDWARE_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/iopage.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/iopage.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,58 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains OS-independent API for allocating iopage types. ++ * The implementation of these functions is highly OS-dependent. ++ * This file is not designed for use outside of the SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_RESOURCE_IOPAGE_H__ ++#define __CI_DRIVER_RESOURCE_IOPAGE_H__ ++ ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * memory allocation ++ * ++ *--------------------------------------------------------------------*/ ++ ++extern int efhw_iopage_alloc(struct efhw_nic *, struct efhw_iopage *p); ++extern void efhw_iopage_free(struct efhw_nic *, struct efhw_iopage *p); ++ ++extern int efhw_iopages_alloc(struct efhw_nic *, struct efhw_iopages *p, ++ unsigned order); ++extern void efhw_iopages_free(struct efhw_nic *, struct efhw_iopages *p); ++ ++#endif /* __CI_DRIVER_RESOURCE_IOPAGE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/iopage_types.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/iopage_types.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,190 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides struct efhw_page and struct efhw_iopage for Linux ++ * kernel. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_IOPAGE_LINUX_H__ ++#define __CI_EFHW_IOPAGE_LINUX_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * struct efhw_page: A single page of memory. Directly mapped in the ++ * driver, and can be mapped to userlevel. ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_page { ++ unsigned long kva; ++}; ++ ++static inline int efhw_page_alloc(struct efhw_page *p) ++{ ++ p->kva = __get_free_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL); ++ return p->kva ? 0 : -ENOMEM; ++} ++ ++static inline int efhw_page_alloc_zeroed(struct efhw_page *p) ++{ ++ p->kva = get_zeroed_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL); ++ return p->kva ? 0 : -ENOMEM; ++} ++ ++static inline void efhw_page_free(struct efhw_page *p) ++{ ++ free_page(p->kva); ++ EFHW_DO_DEBUG(memset(p, 0, sizeof(*p))); ++} ++ ++static inline char *efhw_page_ptr(struct efhw_page *p) ++{ ++ return (char *)p->kva; ++} ++ ++static inline unsigned efhw_page_pfn(struct efhw_page *p) ++{ ++ return (unsigned)(__pa(p->kva) >> PAGE_SHIFT); ++} ++ ++static inline void efhw_page_mark_invalid(struct efhw_page *p) ++{ ++ p->kva = 0; ++} ++ ++static inline int efhw_page_is_valid(struct efhw_page *p) ++{ ++ return p->kva != 0; ++} ++ ++static inline void efhw_page_init_from_va(struct efhw_page *p, void *va) ++{ ++ p->kva = (unsigned long)va; ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * struct efhw_iopage: A single page of memory. Directly mapped in the driver, ++ * and can be mapped to userlevel. Can also be accessed by the NIC. ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_iopage { ++ struct efhw_page p; ++ dma_addr_t dma_addr; ++}; ++ ++static inline dma_addr_t efhw_iopage_dma_addr(struct efhw_iopage *p) ++{ ++ return p->dma_addr; ++} ++ ++#define efhw_iopage_ptr(iop) efhw_page_ptr(&(iop)->p) ++#define efhw_iopage_pfn(iop) efhw_page_pfn(&(iop)->p) ++#define efhw_iopage_mark_invalid(iop) efhw_page_mark_invalid(&(iop)->p) ++#define efhw_iopage_is_valid(iop) efhw_page_is_valid(&(iop)->p) ++ ++/*-------------------------------------------------------------------- ++ * ++ * struct efhw_iopages: A set of pages that are contiguous in physical ++ * memory. Directly mapped in the driver, and can be mapped to userlevel. ++ * Can also be accessed by the NIC. ++ * ++ * NB. The O/S may be unwilling to allocate many, or even any of these. So ++ * only use this type where the NIC really needs a physically contiguous ++ * buffer. ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_iopages { ++ caddr_t kva; ++ unsigned order; ++ dma_addr_t dma_addr; ++}; ++ ++static inline caddr_t efhw_iopages_ptr(struct efhw_iopages *p) ++{ ++ return p->kva; ++} ++ ++static inline unsigned efhw_iopages_pfn(struct efhw_iopages *p) ++{ ++ return (unsigned)(__pa(p->kva) >> PAGE_SHIFT); ++} ++ ++static inline dma_addr_t efhw_iopages_dma_addr(struct efhw_iopages *p) ++{ ++ return p->dma_addr; ++} ++ ++static inline unsigned efhw_iopages_size(struct efhw_iopages *p) ++{ ++ return 1u << (p->order + PAGE_SHIFT); ++} ++ ++/* struct efhw_iopage <-> struct efhw_iopages conversions for handling ++ * physically contiguous allocations in iobufsets for iSCSI. This allows ++ * the essential information about contiguous allocations from ++ * efhw_iopages_alloc() to be saved away in the struct efhw_iopage array in ++ * an iobufset. (Changing the iobufset resource to use a union type would ++ * involve a lot of code changes, and make the iobufset's metadata larger ++ * which could be bad as it's supposed to fit into a single page on some ++ * platforms.) ++ */ ++static inline void ++efhw_iopage_init_from_iopages(struct efhw_iopage *iopage, ++ struct efhw_iopages *iopages, unsigned pageno) ++{ ++ iopage->p.kva = ((unsigned long)efhw_iopages_ptr(iopages)) ++ + (pageno * PAGE_SIZE); ++ iopage->dma_addr = efhw_iopages_dma_addr(iopages) + ++ (pageno * PAGE_SIZE); ++} ++ ++static inline void ++efhw_iopages_init_from_iopage(struct efhw_iopages *iopages, ++ struct efhw_iopage *iopage, unsigned order) ++{ ++ iopages->kva = (caddr_t) efhw_iopage_ptr(iopage); ++ EFHW_ASSERT(iopages->kva); ++ iopages->order = order; ++ iopages->dma_addr = efhw_iopage_dma_addr(iopage); ++} ++ ++#endif /* __CI_EFHW_IOPAGE_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/nic.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/nic.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,62 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains API provided by efhw/nic.c file. This file is not ++ * designed for use outside of the SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_NIC_H__ ++#define __CI_EFHW_NIC_H__ ++ ++#include ++#include ++ ++ ++/* Convert PCI info to device type. Returns false when device is not ++ * recognised. ++ */ ++extern int efhw_device_type_init(struct efhw_device_type *dt, ++ int vendor_id, int device_id, int revision); ++ ++/* Initialise fields that do not involve touching hardware. */ ++extern void efhw_nic_init(struct efhw_nic *nic, unsigned flags, ++ unsigned options, struct efhw_device_type dev_type); ++ ++/*! Destruct NIC resources */ ++extern void efhw_nic_dtor(struct efhw_nic *nic); ++ ++/*! Shutdown interrupts */ ++extern void efhw_nic_close_interrupts(struct efhw_nic *nic); ++ ++#endif /* __CI_EFHW_NIC_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/public.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/public.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,104 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public API of efhw library exported from the SFC ++ * resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_PUBLIC_H__ ++#define __CI_EFHW_PUBLIC_H__ ++ ++#include ++#include ++ ++/*! Returns true if we have some EtherFabric functional units - ++ whether configured or not */ ++static inline int efhw_nic_have_functional_units(struct efhw_nic *nic) ++{ ++ return nic->efhw_func != 0; ++} ++ ++/*! Returns true if the EtherFabric functional units have been configured */ ++static inline int efhw_nic_have_hw(struct efhw_nic *nic) ++{ ++ return efhw_nic_have_functional_units(nic) && (EFHW_KVA(nic) != 0); ++} ++ ++/*! Helper function to allocate the iobuffer needed by an eventq ++ * - it ensures the eventq has the correct alignment for the NIC ++ * ++ * \param rm Event-queue resource manager ++ * \param instance Event-queue instance (index) ++ * \param buf_bytes Requested size of eventq ++ * \return < 0 if iobuffer allocation fails ++ */ ++int efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic, ++ struct eventq_resource_hardware *h, ++ int evq_instance, unsigned buf_bytes); ++ ++extern void falcon_nic_set_rx_usr_buf_size(struct efhw_nic *, ++ int rx_usr_buf_size); ++ ++/*! Get RX filter search limits from RX_FILTER_CTL_REG. ++ * use_raw_values = 0 to get actual depth of search, or 1 to get raw values ++ * from register. ++ */ ++extern void ++falcon_nic_get_rx_filter_search_limits(struct efhw_nic *nic, ++ struct efhw_filter_search_limits *lim, ++ int use_raw_values); ++ ++/*! Set RX filter search limits in RX_FILTER_CTL_REG. ++ * use_raw_values = 0 if specifying actual depth of search, or 1 if specifying ++ * raw values to write to the register. ++ */ ++extern void ++falcon_nic_set_rx_filter_search_limits(struct efhw_nic *nic, ++ struct efhw_filter_search_limits *lim, ++ int use_raw_values); ++ ++ ++/*! Legacy RX IP filter search depth control interface */ ++extern void ++falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full, ++ uint32_t tcp_wild, ++ uint32_t udp_full, uint32_t udp_wild); ++ ++/*! Legacy RX IP filter search depth control interface */ ++extern void ++falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full, ++ uint32_t *tcp_wild, ++ uint32_t *udp_full, uint32_t *udp_wild); ++ ++#endif /* __CI_EFHW_PUBLIC_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/sysdep.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efhw/sysdep.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,55 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides version-independent Linux kernel API for efhw library. ++ * Only kernels >=2.6.9 are supported. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFHW_SYSDEP_LINUX_H__ ++#define __CI_EFHW_SYSDEP_LINUX_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include /* necessary for etherdevice.h on some kernels */ ++#include ++ ++typedef unsigned long irq_flags_t; ++ ++#define spin_lock_destroy(l_) do {} while (0) ++ ++#endif /* __CI_EFHW_SYSDEP_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/buddy.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/buddy.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,68 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides private API for buddy allocator. This API is not ++ * designed for use outside of SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_BUDDY_H__ ++#define __CI_EFRM_BUDDY_H__ ++ ++#include ++ ++/*! Comment? */ ++struct efrm_buddy_allocator { ++ struct list_head *free_lists; /* array[order+1] */ ++ struct list_head *links; /* array[1<order; ++} ++ ++int efrm_buddy_ctor(struct efrm_buddy_allocator *b, unsigned order); ++void efrm_buddy_dtor(struct efrm_buddy_allocator *b); ++int efrm_buddy_alloc(struct efrm_buddy_allocator *b, unsigned order); ++void efrm_buddy_free(struct efrm_buddy_allocator *b, unsigned addr, ++ unsigned order); ++ ++ ++#endif /* __CI_EFRM_BUDDY_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/buffer_table.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/buffer_table.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,81 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides private buffer table API. This API is not designed ++ * for use outside of SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_BUFFER_TABLE_H__ ++#define __CI_EFRM_BUFFER_TABLE_H__ ++ ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * NIC's buffer table. ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Managed interface. */ ++ ++/*! construct a managed buffer table object, allocated over a region of ++ * the NICs buffer table space ++ */ ++extern int efrm_buffer_table_ctor(unsigned low, unsigned high); ++/*! destructor for above */ ++extern void efrm_buffer_table_dtor(void); ++ ++/*! allocate a contiguous region of buffer table space */ ++extern int efrm_buffer_table_alloc(unsigned order, ++ struct efhw_buffer_table_allocation *a); ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * buffer table operations through the HW independent API ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! free a previously allocated region of buffer table space */ ++extern void efrm_buffer_table_free(struct efhw_buffer_table_allocation *a); ++ ++/*! commit the update of a buffer table entry to every NIC */ ++extern void efrm_buffer_table_commit(void); ++ ++extern void efrm_buffer_table_set(struct efhw_buffer_table_allocation *, ++ struct efhw_nic *, ++ unsigned i, dma_addr_t dma_addr, int owner); ++ ++ ++#endif /* __CI_EFRM_BUFFER_TABLE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/debug.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/debug.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,78 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides debug-related API for efrm library using Linux kernel ++ * primitives. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_DEBUG_LINUX_H__ ++#define __CI_EFRM_DEBUG_LINUX_H__ ++ ++#define EFRM_PRINTK_PREFIX "[sfc efrm] " ++ ++#define EFRM_PRINTK(level, fmt, ...) \ ++ printk(level EFRM_PRINTK_PREFIX fmt "\n", __VA_ARGS__) ++ ++/* Following macros should be used with non-zero format parameters ++ * due to __VA_ARGS__ limitations. Use "%s" with __func__ if you can't ++ * find better parameters. */ ++#define EFRM_ERR(fmt, ...) EFRM_PRINTK(KERN_ERR, fmt, __VA_ARGS__) ++#define EFRM_WARN(fmt, ...) EFRM_PRINTK(KERN_WARNING, fmt, __VA_ARGS__) ++#define EFRM_NOTICE(fmt, ...) EFRM_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__) ++#if !defined(NDEBUG) ++#define EFRM_TRACE(fmt, ...) EFRM_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__) ++#else ++#define EFRM_TRACE(fmt, ...) ++#endif ++ ++#ifndef NDEBUG ++#define EFRM_ASSERT(cond) BUG_ON((cond) == 0) ++#define _EFRM_ASSERT(cond, file, line) \ ++ do { \ ++ if (unlikely(!(cond))) { \ ++ EFRM_ERR("assertion \"%s\" failed at %s %d", \ ++ #cond, file, line); \ ++ BUG(); \ ++ } \ ++ } while (0) ++ ++#define EFRM_DO_DEBUG(expr) expr ++#define EFRM_VERIFY_EQ(expr, val) EFRM_ASSERT((expr) == (val)) ++#else ++#define EFRM_ASSERT(cond) ++#define EFRM_DO_DEBUG(expr) ++#define EFRM_VERIFY_EQ(expr, val) expr ++#endif ++ ++#endif /* __CI_EFRM_DEBUG_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/driver_private.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/driver_private.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,89 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides private API of efrm library to be used from the SFC ++ * resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_DRIVER_PRIVATE_H__ ++#define __CI_EFRM_DRIVER_PRIVATE_H__ ++ ++#include ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * global variables ++ * ++ *--------------------------------------------------------------------*/ ++ ++/* Internal structure for resource driver */ ++extern struct efrm_resource_manager *efrm_rm_table[]; ++ ++/*-------------------------------------------------------------------- ++ * ++ * efrm_nic_table handling ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efrm_nic; ++ ++extern void efrm_driver_ctor(void); ++extern void efrm_driver_dtor(void); ++extern int efrm_driver_register_nic(struct efrm_nic *, int nic_index, ++ int ifindex); ++extern int efrm_driver_unregister_nic(struct efrm_nic *); ++ ++/*-------------------------------------------------------------------- ++ * ++ * create/destroy resource managers ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct vi_resource_dimensions { ++ unsigned evq_int_min, evq_int_lim; ++ unsigned evq_timer_min, evq_timer_lim; ++ unsigned rxq_min, rxq_lim; ++ unsigned txq_min, txq_lim; ++}; ++ ++/*! Initialise resources */ ++extern int ++efrm_resources_init(const struct vi_resource_dimensions *, ++ int buffer_table_min, int buffer_table_lim); ++ ++/*! Tear down resources */ ++extern void efrm_resources_fini(void); ++ ++#endif /* __CI_EFRM_DRIVER_PRIVATE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/efrm_client.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/efrm_client.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,32 @@ ++#ifndef __EFRM_CLIENT_H__ ++#define __EFRM_CLIENT_H__ ++ ++ ++struct efrm_client; ++ ++ ++struct efrm_client_callbacks { ++ /* Called before device is reset. Callee may block. */ ++ void (*pre_reset)(struct efrm_client *, void *user_data); ++ void (*stop)(struct efrm_client *, void *user_data); ++ void (*restart)(struct efrm_client *, void *user_data); ++}; ++ ++ ++#define EFRM_IFINDEX_DEFAULT -1 ++ ++ ++/* NB. Callbacks may be invoked even before this returns. */ ++extern int efrm_client_get(int ifindex, struct efrm_client_callbacks *, ++ void *user_data, struct efrm_client **client_out); ++extern void efrm_client_put(struct efrm_client *); ++ ++extern struct efhw_nic *efrm_client_get_nic(struct efrm_client *); ++ ++#if 0 ++/* For each resource type... */ ++extern void efrm_x_resource_resume(struct x_resource *); ++#endif ++ ++ ++#endif /* __EFRM_CLIENT_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/efrm_nic.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/efrm_nic.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,26 @@ ++#ifndef __EFRM_NIC_H__ ++#define __EFRM_NIC_H__ ++ ++#include ++ ++ ++struct efrm_nic_per_vi { ++ unsigned long state; ++ struct vi_resource *vi; ++}; ++ ++ ++struct efrm_nic { ++ struct efhw_nic efhw_nic; ++ struct list_head link; ++ struct list_head clients; ++ struct efrm_nic_per_vi *vis; ++}; ++ ++ ++#define efrm_nic(_efhw_nic) \ ++ container_of(_efhw_nic, struct efrm_nic, efhw_nic) ++ ++ ++ ++#endif /* __EFRM_NIC_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/filter.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/filter.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,122 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public API for filter resource. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_FILTER_H__ ++#define __CI_EFRM_FILTER_H__ ++ ++#include ++#include ++ ++ ++struct filter_resource; ++struct vi_resource; ++struct efrm_client; ++ ++ ++/*! ++ * Allocate filter resource. ++ * ++ * \param vi_parent VI resource to use as parent. The function takes ++ * reference to the VI resource on success. ++ * \param frs_out pointer to return the new filter resource ++ * ++ * \return status code; if non-zero, frs_out is unchanged ++ */ ++extern int ++efrm_filter_resource_alloc(struct vi_resource *vi_parent, ++ struct filter_resource **frs_out); ++ ++extern void ++efrm_filter_resource_release(struct filter_resource *); ++ ++ ++extern int efrm_filter_resource_clear(struct filter_resource *frs); ++ ++extern int __efrm_filter_resource_set(struct filter_resource *frs, int type, ++ unsigned saddr_be32, uint16_t sport_be16, ++ unsigned daddr_be32, uint16_t dport_be16); ++ ++static inline int ++efrm_filter_resource_tcp_set(struct filter_resource *frs, ++ unsigned saddr, uint16_t sport, ++ unsigned daddr, uint16_t dport) ++{ ++ int type; ++ ++ EFRM_ASSERT((saddr && sport) || (!saddr && !sport)); ++ ++ type = ++ saddr ? EFHW_IP_FILTER_TYPE_TCP_FULL : ++ EFHW_IP_FILTER_TYPE_TCP_WILDCARD; ++ ++ return __efrm_filter_resource_set(frs, type, ++ saddr, sport, daddr, dport); ++} ++ ++static inline int ++efrm_filter_resource_udp_set(struct filter_resource *frs, ++ unsigned saddr, uint16_t sport, ++ unsigned daddr, uint16_t dport) ++{ ++ int type; ++ ++ EFRM_ASSERT((saddr && sport) || (!saddr && !sport)); ++ ++ type = ++ saddr ? EFHW_IP_FILTER_TYPE_UDP_FULL : ++ EFHW_IP_FILTER_TYPE_UDP_WILDCARD; ++ ++ return __efrm_filter_resource_set(frs, ++ type, saddr, sport, daddr, dport); ++} ++ ++ ++extern int ++efrm_filter_resource_instance(struct filter_resource *); ++ ++extern struct efrm_resource * ++efrm_filter_resource_to_resource(struct filter_resource *); ++ ++extern struct filter_resource * ++efrm_filter_resource_from_resource(struct efrm_resource *); ++ ++extern void ++efrm_filter_resource_free(struct filter_resource *); ++ ++ ++#endif /* __CI_EFRM_FILTER_H__ */ ++/*! \cidoxg_end */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/iobufset.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/iobufset.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,110 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public API for iobufset resource. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_IOBUFSET_H__ ++#define __CI_EFRM_IOBUFSET_H__ ++ ++#include ++ ++/*! Iobufset resource structture. ++ * Users should not access the structure fields directly, but use the API ++ * below. ++ * However, this structure should not be moved out of public headers, ++ * because part of API (ex. efrm_iobufset_dma_addr function) is inline and ++ * is used in the fast-path code. ++ */ ++struct iobufset_resource { ++ struct efrm_resource rs; ++ struct vi_resource *evq; ++ struct iobufset_resource *linked; ++ struct efhw_buffer_table_allocation buf_tbl_alloc; ++ unsigned int n_bufs; ++ unsigned int pages_per_contiguous_chunk; ++ unsigned chunk_order; ++ struct efhw_iopage bufs[1]; ++ /*!< up to n_bufs can follow this, so this must be the last member */ ++}; ++ ++#define iobufset_resource(rs1) \ ++ container_of((rs1), struct iobufset_resource, rs) ++ ++/*! ++ * Allocate iobufset resource. ++ * ++ * \param vi VI that "owns" these buffers. Grabs a reference ++ * on success. ++ * \param linked Uses memory from an existing iobufset. Grabs a ++ * reference on success. ++ * \param iobrs_out pointer to return the new filter resource ++ * ++ * \return status code; if non-zero, frs_out is unchanged ++ */ ++extern int ++efrm_iobufset_resource_alloc(int32_t n_pages, ++ int32_t pages_per_contiguous_chunk, ++ struct vi_resource *vi, ++ struct iobufset_resource *linked, ++ bool phys_addr_mode, ++ struct iobufset_resource **iobrs_out); ++ ++extern void efrm_iobufset_resource_free(struct iobufset_resource *); ++extern void efrm_iobufset_resource_release(struct iobufset_resource *); ++ ++static inline char * ++efrm_iobufset_ptr(struct iobufset_resource *rs, unsigned offs) ++{ ++ EFRM_ASSERT(offs < (unsigned)(rs->n_bufs << PAGE_SHIFT)); ++ return efhw_iopage_ptr(&rs->bufs[offs >> PAGE_SHIFT]) ++ + (offs & (PAGE_SIZE - 1)); ++} ++ ++static inline char *efrm_iobufset_page_ptr(struct iobufset_resource *rs, ++ unsigned page_i) ++{ ++ EFRM_ASSERT(page_i < (unsigned)rs->n_bufs); ++ return efhw_iopage_ptr(&rs->bufs[page_i]); ++} ++ ++static inline dma_addr_t ++efrm_iobufset_dma_addr(struct iobufset_resource *rs, unsigned offs) ++{ ++ EFRM_ASSERT(offs < (unsigned)(rs->n_bufs << PAGE_SHIFT)); ++ return efhw_iopage_dma_addr(&rs->bufs[offs >> PAGE_SHIFT]) ++ + (offs & (PAGE_SIZE - 1)); ++} ++ ++#endif /* __CI_EFRM_IOBUFSET_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/nic_set.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/nic_set.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,104 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public API for NIC sets. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_NIC_SET_H__ ++#define __CI_EFRM_NIC_SET_H__ ++ ++#include ++#include ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * efrm_nic_set_t - tracks which NICs something has been done on ++ * ++ *--------------------------------------------------------------------*/ ++ ++/* Internal suructure of efrm_nic_set_t should not be referenced outside of ++ * this file. Add a new accessor if you should do it. */ ++typedef struct { ++ uint32_t nics; ++} efrm_nic_set_t; ++ ++#if EFHW_MAX_NR_DEVS > 32 ++#error change efrm_nic_set to handle EFHW_MAX_NR_DEVS number of devices ++#endif ++ ++static inline bool ++efrm_nic_set_read(const efrm_nic_set_t *nic_set, unsigned index) ++{ ++ EFRM_ASSERT(nic_set); ++ EFRM_ASSERT(index < EFHW_MAX_NR_DEVS && index < 32); ++ return (nic_set->nics & (1 << index)) ? true : false; ++} ++ ++static inline void ++efrm_nic_set_write(efrm_nic_set_t *nic_set, unsigned index, bool value) ++{ ++ EFRM_ASSERT(nic_set); ++ EFRM_ASSERT(index < EFHW_MAX_NR_DEVS && index < 32); ++ EFRM_ASSERT(value == false || value == true); ++ nic_set->nics = (nic_set->nics & (~(1 << index))) + (value << index); ++} ++ ++static inline void efrm_nic_set_clear(efrm_nic_set_t *nic_set) ++{ ++ nic_set->nics = 0; ++} ++ ++static inline void efrm_nic_set_all(efrm_nic_set_t *nic_set) ++{ ++ nic_set->nics = 0xffffffff; ++} ++ ++static inline bool efrm_nic_set_is_all_clear(efrm_nic_set_t *nic_set) ++{ ++ return nic_set->nics == 0 ? true : false; ++} ++ ++#define EFRM_NIC_SET_FMT "%x" ++ ++static inline uint32_t efrm_nic_set_pri_arg(efrm_nic_set_t *nic_set) ++{ ++ return nic_set->nics; ++} ++ ++#define EFRM_FOR_EACH_NIC_INDEX_IN_SET(_set, _nic_i) \ ++ for ((_nic_i) = 0; (_nic_i) < EFHW_MAX_NR_DEVS; ++(_nic_i)) \ ++ if (efrm_nic_set_read((_set), (_nic_i))) ++ ++#endif /* __CI_EFRM_NIC_SET_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/nic_table.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/nic_table.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,98 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public API for NIC table. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_NIC_TABLE_H__ ++#define __CI_EFRM_NIC_TABLE_H__ ++ ++#include ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * struct efrm_nic_table - top level driver object keeping all NICs - ++ * implemented in driver_object.c ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Comment? */ ++struct efrm_nic_table { ++ /*! nics attached to this driver */ ++ struct efhw_nic *nic[EFHW_MAX_NR_DEVS]; ++ /*! pointer to an arbitrary struct efhw_nic if one exists; ++ * for code which does not care which NIC it wants but ++ * still needs one. Note you cannot assume nic[0] exists. */ ++ struct efhw_nic *a_nic; ++ uint32_t nic_count; /*!< number of nics attached to this driver */ ++ spinlock_t lock; /*!< lock for table modifications */ ++ atomic_t ref_count; /*!< refcount for users of nic table */ ++}; ++ ++/* Resource driver structures used by other drivers as well */ ++extern struct efrm_nic_table *efrm_nic_tablep; ++ ++static inline void efrm_nic_table_hold(void) ++{ ++ atomic_inc(&efrm_nic_tablep->ref_count); ++} ++ ++static inline void efrm_nic_table_rele(void) ++{ ++ atomic_dec(&efrm_nic_tablep->ref_count); ++} ++ ++static inline int efrm_nic_table_held(void) ++{ ++ return atomic_read(&efrm_nic_tablep->ref_count) != 0; ++} ++ ++/* Run code block _x multiple times with variable nic set to each ++ * registered NIC in turn. ++ * DO NOT "break" out of this loop early. */ ++#define EFRM_FOR_EACH_NIC(_nic_i, _nic) \ ++ for ((_nic_i) = (efrm_nic_table_hold(), 0); \ ++ (_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \ ++ (_nic_i)++) \ ++ if (((_nic) = efrm_nic_tablep->nic[_nic_i])) ++ ++#define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic) \ ++ for ((_i) = (efrm_nic_table_hold(), 0); \ ++ (_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \ ++ ++(_i)) \ ++ if (((_nic) = efrm_nic_tablep->nic[_i]) && \ ++ efrm_nic_set_read((_set), (_i))) ++ ++#endif /* __CI_EFRM_NIC_TABLE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/private.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/private.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,118 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides private API of efrm library -- resource handling. ++ * This API is not designed for use outside of SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_PRIVATE_H__ ++#define __CI_EFRM_PRIVATE_H__ ++ ++#include ++#include ++#include ++#include ++ ++/*-------------------------------------------------------------------- ++ * ++ * create resource managers ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Create a resource manager for various types of resources ++ */ ++extern int ++efrm_create_iobufset_resource_manager(struct efrm_resource_manager **out); ++ ++extern int ++efrm_create_filter_resource_manager(struct efrm_resource_manager **out); ++ ++extern int ++efrm_create_vi_resource_manager(struct efrm_resource_manager **out, ++ const struct vi_resource_dimensions *); ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * Instance pool management ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Allocate instance pool. Use kfifo_vfree to destroy it. */ ++static inline int ++efrm_kfifo_id_ctor(struct kfifo **ids_out, ++ unsigned int base, unsigned int limit, spinlock_t *lock) ++{ ++ unsigned int i; ++ struct kfifo *ids; ++ unsigned char *buffer; ++ unsigned int size = roundup_pow_of_two((limit - base) * sizeof(int)); ++ EFRM_ASSERT(base <= limit); ++ buffer = vmalloc(size); ++ ids = kfifo_init(buffer, size, GFP_KERNEL, lock); ++ if (IS_ERR(ids)) ++ return PTR_ERR(ids); ++ for (i = base; i < limit; i++) ++ EFRM_VERIFY_EQ(__kfifo_put(ids, (unsigned char *)&i, ++ sizeof(i)), sizeof(i)); ++ ++ *ids_out = ids; ++ return 0; ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Various private functions ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Initialize the fields in the provided resource manager memory area ++ * \param rm The area of memory to be initialized ++ * \param dtor A method to destroy the resource manager ++ * \param name A Textual name for the resource manager ++ * \param type The type of resource managed ++ * \param initial_table_size Initial size of the ID table ++ * \param auto_destroy Destroy resource manager on driver onload iff true ++ * ++ * A default table size is provided if the value 0 is provided. ++ */ ++extern int ++efrm_resource_manager_ctor(struct efrm_resource_manager *rm, ++ void (*dtor)(struct efrm_resource_manager *), ++ const char *name, unsigned type); ++ ++extern void efrm_resource_manager_dtor(struct efrm_resource_manager *rm); ++ ++ ++#endif /* __CI_EFRM_PRIVATE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/resource.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/resource.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,119 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public interface of efrm library -- resource handling. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_RESOURCE_H__ ++#define __CI_EFRM_RESOURCE_H__ ++ ++/*-------------------------------------------------------------------- ++ * ++ * headers for type dependencies ++ * ++ *--------------------------------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++ ++#ifndef __ci_driver__ ++#error "Driver-only file" ++#endif ++ ++/*-------------------------------------------------------------------- ++ * ++ * struct efrm_resource - represents an allocated resource ++ * (eg. pinned pages of memory, or resource on a NIC) ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Representation of an allocated resource */ ++struct efrm_resource { ++ int rs_ref_count; ++ efrm_resource_handle_t rs_handle; ++ struct efrm_client *rs_client; ++ struct list_head rs_client_link; ++ struct list_head rs_manager_link; ++}; ++ ++/*-------------------------------------------------------------------- ++ * ++ * managed resource abstraction ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Factory for resources of a specific type */ ++struct efrm_resource_manager { ++ const char *rm_name; /*!< human readable only */ ++ spinlock_t rm_lock; ++#ifndef NDEBUG ++ unsigned rm_type; ++#endif ++ int rm_resources; ++ int rm_resources_hiwat; ++ struct list_head rm_resources_list; ++ /** ++ * Destructor for the resource manager. Other resource managers ++ * might be already dead, although the system guarantees that ++ * managers are destructed in the order by which they were created ++ */ ++ void (*rm_dtor)(struct efrm_resource_manager *); ++}; ++ ++#ifdef NDEBUG ++# define EFRM_RESOURCE_ASSERT_VALID(rs, rc_mbz) ++# define EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm) ++#else ++/*! Check validity of resource and report on failure */ ++extern void efrm_resource_assert_valid(struct efrm_resource *, ++ int rc_may_be_zero, ++ const char *file, int line); ++# define EFRM_RESOURCE_ASSERT_VALID(rs, rc_mbz) \ ++ efrm_resource_assert_valid((rs), (rc_mbz), __FILE__, __LINE__) ++ ++/*! Check validity of resource manager and report on failure */ ++extern void efrm_resource_manager_assert_valid(struct efrm_resource_manager *, ++ const char *file, int line); ++# define EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm) \ ++ efrm_resource_manager_assert_valid((rm), __FILE__, __LINE__) ++#endif ++ ++ ++extern void efrm_resource_ref(struct efrm_resource *rs); ++extern int __efrm_resource_release(struct efrm_resource *); ++ ++ ++#endif /* __CI_EFRM_RESOURCE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/resource_id.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/resource_id.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,104 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides public type and definitions resource handle, and the ++ * definitions of resource types. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_EFRM_RESOURCE_ID_H__ ++#define __CI_DRIVER_EFRM_RESOURCE_ID_H__ ++ ++/*********************************************************************** ++ * Resource handles ++ * ++ * Resource handles are intended for identifying resources at kernel ++ * level, within the context of a particular NIC. particularly because ++ * for some resource types, the low 16 bites correspond to hardware ++ * IDs. They were historically also used at user level, with a nonce ++ * stored in the bits 16 to 27 (inclusive), but that approach is ++ * deprecated (but sill alive!). ++ * ++ * The handle value 0 is used to mean "no resource". ++ * Identify resources within the context of a file descriptor at user ++ * level. ++ ***********************************************************************/ ++ ++typedef struct { ++ uint32_t handle; ++} efrm_resource_handle_t; ++ ++/* You may think these following functions should all have ++ * _HANDLE_ in their names, but really we are providing an abstract set ++ * of methods on a (hypothetical) efrm_resource_t object, with ++ * efrm_resource_handle_t being just the reference one holds to access ++ * the object (aka "this" or "self"). ++ */ ++ ++/* Below I use inline instead of macros where possible in order to get ++ * more type checking help from the compiler; hopefully we'll never ++ * have to rewrite these to use #define as we've found some horrible ++ * compiler on which we cannot make static inline do the Right Thing (tm). ++ * ++ * For consistency and to avoid pointless change I spell these ++ * routines as macro names (CAPTILIZE_UNDERSCORED), which also serves ++ * to remind people they are compact and inlined. ++ */ ++ ++#define EFRM_RESOURCE_FMT "[rs:%08x]" ++ ++static inline unsigned EFRM_RESOURCE_PRI_ARG(efrm_resource_handle_t h) ++{ ++ return h.handle; ++} ++ ++static inline unsigned EFRM_RESOURCE_INSTANCE(efrm_resource_handle_t h) ++{ ++ return h.handle & 0x0000ffff; ++} ++ ++static inline unsigned EFRM_RESOURCE_TYPE(efrm_resource_handle_t h) ++{ ++ return (h.handle & 0xf0000000) >> 28; ++} ++ ++/*********************************************************************** ++ * Resource type codes ++ ***********************************************************************/ ++ ++#define EFRM_RESOURCE_IOBUFSET 0x0 ++#define EFRM_RESOURCE_VI 0x1 ++#define EFRM_RESOURCE_FILTER 0x2 ++#define EFRM_RESOURCE_NUM 0x3 /* This isn't a resource! */ ++ ++#define EFRM_RESOURCE_NAME(type) \ ++ ((type) == EFRM_RESOURCE_IOBUFSET? "IOBUFSET" : \ ++ (type) == EFRM_RESOURCE_VI? "VI" : \ ++ (type) == EFRM_RESOURCE_FILTER? "FILTER" : \ ++ "") ++ ++#endif /* __CI_DRIVER_EFRM_RESOURCE_ID_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/sysdep.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/sysdep.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,46 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides Linux-like system-independent API for efrm library. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_SYSDEP_H__ ++#define __CI_EFRM_SYSDEP_H__ ++ ++/* Spinlocks are defined in efhw/sysdep.h */ ++#include ++ ++#include ++ ++#endif /* __CI_EFRM_SYSDEP_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/sysdep_linux.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/sysdep_linux.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,93 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides version-independent Linux kernel API for efrm library. ++ * Only kernels >=2.6.9 are supported. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Kfifo API is partially stolen from linux-2.6.22/include/linux/list.h ++ * Copyright (C) 2004 Stelian Pop ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_SYSDEP_LINUX_H__ ++#define __CI_EFRM_SYSDEP_LINUX_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/******************************************************************** ++ * ++ * List API ++ * ++ ********************************************************************/ ++ ++static inline struct list_head *list_pop(struct list_head *list) ++{ ++ struct list_head *link = list->next; ++ list_del(link); ++ return link; ++} ++ ++static inline struct list_head *list_pop_tail(struct list_head *list) ++{ ++ struct list_head *link = list->prev; ++ list_del(link); ++ return link; ++} ++ ++/******************************************************************** ++ * ++ * Kfifo API ++ * ++ ********************************************************************/ ++ ++static inline void kfifo_vfree(struct kfifo *fifo) ++{ ++ vfree(fifo->buffer); ++ kfree(fifo); ++} ++ ++#endif /* __CI_EFRM_SYSDEP_LINUX_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,157 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains public API for VI resource. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_VI_RESOURCE_H__ ++#define __CI_EFRM_VI_RESOURCE_H__ ++ ++#include ++#include ++#include ++ ++struct vi_resource; ++ ++/* Make these inline instead of macros for type checking */ ++static inline struct vi_resource * ++efrm_to_vi_resource(struct efrm_resource *rs) ++{ ++ EFRM_ASSERT(EFRM_RESOURCE_TYPE(rs->rs_handle) == EFRM_RESOURCE_VI); ++ return (struct vi_resource *) rs; ++} ++static inline struct ++efrm_resource *efrm_from_vi_resource(struct vi_resource *rs) ++{ ++ return (struct efrm_resource *)rs; ++} ++ ++#define EFAB_VI_RESOURCE_INSTANCE(virs) \ ++ EFRM_RESOURCE_INSTANCE(efrm_from_vi_resource(virs)->rs_handle) ++ ++#define EFAB_VI_RESOURCE_PRI_ARG(virs) \ ++ EFRM_RESOURCE_PRI_ARG(efrm_from_vi_resource(virs)->rs_handle) ++ ++extern int ++efrm_vi_resource_alloc(struct efrm_client *client, ++ struct vi_resource *evq_virs, ++ uint16_t vi_flags, int32_t evq_capacity, ++ int32_t txq_capacity, int32_t rxq_capacity, ++ uint8_t tx_q_tag, uint8_t rx_q_tag, ++ struct vi_resource **virs_in_out, ++ uint32_t *out_io_mmap_bytes, ++ uint32_t *out_mem_mmap_bytes, ++ uint32_t *out_txq_capacity, ++ uint32_t *out_rxq_capacity); ++ ++extern void efrm_vi_resource_free(struct vi_resource *); ++extern void efrm_vi_resource_release(struct vi_resource *); ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * eventq handling ++ * ++ *--------------------------------------------------------------------*/ ++ ++/*! Reset an event queue and clear any associated timers */ ++extern void efrm_eventq_reset(struct vi_resource *virs); ++ ++/*! Register a kernel-level handler for the event queue. This function is ++ * called whenever a timer expires, or whenever the event queue is woken ++ * but no thread is blocked on it. ++ * ++ * This function returns -EBUSY if a callback is already installed. ++ * ++ * \param rs Event-queue resource ++ * \param handler Callback-handler ++ * \param arg Argument to pass to callback-handler ++ * \return Status code ++ */ ++extern int ++efrm_eventq_register_callback(struct vi_resource *rs, ++ void (*handler)(void *arg, int is_timeout, ++ struct efhw_nic *nic), ++ void *arg); ++ ++/*! Kill the kernel-level callback. ++ * ++ * This function stops the timer from running and unregisters the callback ++ * function. It waits for any running timeout handlers to complete before ++ * returning. ++ * ++ * \param rs Event-queue resource ++ * \return Nothing ++ */ ++extern void efrm_eventq_kill_callback(struct vi_resource *rs); ++ ++/*! Ask the NIC to generate a wakeup when an event is next delivered. */ ++extern void efrm_eventq_request_wakeup(struct vi_resource *rs, ++ unsigned current_ptr); ++ ++/*! Register a kernel-level handler for flush completions. ++ * \TODO Currently, it is unsafe to install a callback more than once. ++ * ++ * \param rs VI resource being flushed. ++ * \param handler Callback handler function. ++ * \param arg Argument to be passed to handler. ++ */ ++extern void ++efrm_vi_register_flush_callback(struct vi_resource *rs, ++ void (*handler)(void *), ++ void *arg); ++ ++int efrm_vi_resource_flush_retry(struct vi_resource *virs); ++ ++/*! Comment? */ ++extern int efrm_pt_flush(struct vi_resource *); ++ ++/*! Comment? */ ++extern int efrm_pt_pace(struct vi_resource *, unsigned int val); ++ ++uint32_t efrm_vi_rm_txq_bytes(struct vi_resource *virs ++ /*,struct efhw_nic *nic */); ++uint32_t efrm_vi_rm_rxq_bytes(struct vi_resource *virs ++ /*,struct efhw_nic *nic */); ++uint32_t efrm_vi_rm_evq_bytes(struct vi_resource *virs ++ /*,struct efhw_nic *nic */); ++ ++ ++/* Fill [out_vi_data] with information required to allow a VI to be init'd. ++ * [out_vi_data] must ref at least VI_MAPPINGS_SIZE bytes. ++ */ ++extern void efrm_vi_resource_mappings(struct vi_resource *, void *out_vi_data); ++ ++ ++#endif /* __CI_EFRM_VI_RESOURCE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_manager.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_manager.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,155 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains type definitions for VI resource. These types ++ * may be used outside of the SFC resource driver, but such use is not ++ * recommended. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__ ++#define __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__ ++ ++#include ++#include ++ ++ ++#define EFRM_VI_RM_DMA_QUEUE_COUNT 2 ++#define EFRM_VI_RM_DMA_QUEUE_TX 0 ++#define EFRM_VI_RM_DMA_QUEUE_RX 1 ++ ++/** Numbers of bits which can be set in the evq_state member of ++ * vi_resource_evq_info. */ ++enum { ++ /** This bit is set if a wakeup has been requested on the NIC. */ ++ VI_RESOURCE_EVQ_STATE_WAKEUP_PENDING, ++ /** This bit is set if the wakeup is valid for the sleeping ++ * process. */ ++ VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED, ++ /** This bit is set if a wakeup or timeout event is currently being ++ * processed. */ ++ VI_RESOURCE_EVQ_STATE_BUSY, ++}; ++#define VI_RESOURCE_EVQ_STATE(X) \ ++ (((int32_t)1) << (VI_RESOURCE_EVQ_STATE_##X)) ++ ++ ++/*! Global information for the VI resource manager. */ ++struct vi_resource_manager { ++ struct efrm_resource_manager rm; ++ ++ struct kfifo *instances_with_timer; ++ int with_timer_base; ++ int with_timer_limit; ++ struct kfifo *instances_with_interrupt; ++ int with_interrupt_base; ++ int with_interrupt_limit; ++ ++ bool iscsi_dmaq_instance_is_free; ++ ++ /* We keep VI resources which need flushing on these lists. The VI ++ * is put on the outstanding list when the flush request is issued ++ * to the hardware and removed when the flush event arrives. The ++ * hardware can only handle a limited number of RX flush requests at ++ * once, so VIs are placed in the waiting list until the flush can ++ * be issued. Flushes can be requested by the client or internally ++ * by the VI resource manager. In the former case, the reference ++ * count must be non-zero for the duration of the flush and in the ++ * later case, the reference count must be zero. */ ++ struct list_head rx_flush_waiting_list; ++ struct list_head rx_flush_outstanding_list; ++ struct list_head tx_flush_outstanding_list; ++ int rx_flush_outstanding_count; ++ ++ /* once the flush has happened we push the close into the work queue ++ * so its OK on Windows to free the resources (Bug 3469). Resources ++ * on this list have zero reference count. ++ */ ++ struct list_head close_pending; ++ struct work_struct work_item; ++ struct workqueue_struct *workqueue; ++}; ++ ++struct vi_resource_nic_info { ++ struct eventq_resource_hardware evq_pages; ++ struct efhw_iopages dmaq_pages[EFRM_VI_RM_DMA_QUEUE_COUNT]; ++}; ++ ++struct vi_resource { ++ /* Some macros make the assumption that the struct efrm_resource is ++ * the first member of a struct vi_resource. */ ++ struct efrm_resource rs; ++ atomic_t evq_refs; /*!< Number of users of the event queue. */ ++ ++ uint32_t bar_mmap_bytes; ++ uint32_t mem_mmap_bytes; ++ ++ int32_t evq_capacity; ++ int32_t dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_COUNT]; ++ ++ uint8_t dmaq_tag[EFRM_VI_RM_DMA_QUEUE_COUNT]; ++ uint16_t flags; ++ ++ /* we keep PT endpoints that have been destroyed on a list ++ * until we have seen their TX and RX DMAQs flush complete ++ * (see Bug 1217) ++ */ ++ struct list_head rx_flush_link; ++ struct list_head tx_flush_link; ++ int rx_flushing; ++ int rx_flush_outstanding; ++ int tx_flushing; ++ uint64_t flush_time; ++ int flush_count; ++ ++ void (*flush_callback_fn)(void *); ++ void *flush_callback_arg; ++ ++ void (*evq_callback_fn) (void *arg, int is_timeout, ++ struct efhw_nic *nic); ++ void *evq_callback_arg; ++ ++ struct vi_resource *evq_virs; /*!< EVQ for DMA queues */ ++ ++ struct efhw_buffer_table_allocation ++ dmaq_buf_tbl_alloc[EFRM_VI_RM_DMA_QUEUE_COUNT]; ++ ++ struct vi_resource_nic_info nic_info; ++}; ++ ++#undef vi_resource ++#define vi_resource(rs1) container_of((rs1), struct vi_resource, rs) ++ ++static inline dma_addr_t ++efrm_eventq_dma_addr(struct vi_resource *virs) ++{ ++ struct eventq_resource_hardware *hw; ++ hw = &virs->nic_info.evq_pages; ++ return efhw_iopages_dma_addr(&hw->iobuff) + hw->iobuff_off; ++} ++ ++#endif /* __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_private.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_private.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,65 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains private API for VI resource. The API is not designed ++ * to be used outside of the SFC resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __CI_EFRM_VI_RESOURCE_PRIVATE_H__ ++#define __CI_EFRM_VI_RESOURCE_PRIVATE_H__ ++ ++#include ++#include ++ ++extern struct vi_resource_manager *efrm_vi_manager; ++ ++/*************************************************************************/ ++ ++extern void efrm_vi_rm_delayed_free(struct work_struct *data); ++ ++extern void efrm_vi_rm_salvage_flushed_vis(void); ++ ++void efrm_vi_rm_free_flushed_resource(struct vi_resource *virs); ++ ++void efrm_vi_rm_init_dmaq(struct vi_resource *virs, int queue_index, ++ struct efhw_nic *nic); ++ ++/*! Wakeup handler */ ++extern void efrm_handle_wakeup_event(struct efhw_nic *nic, unsigned id); ++ ++/*! Timeout handler */ ++extern void efrm_handle_timeout_event(struct efhw_nic *nic, unsigned id); ++ ++/*! DMA flush handler */ ++extern void efrm_handle_dmaq_flushed(struct efhw_nic *nic, unsigned id, ++ int rx_flush); ++ ++/*! SRAM update handler */ ++extern void efrm_handle_sram_event(struct efhw_nic *nic); ++ ++#endif /* __CI_EFRM_VI_RESOURCE_PRIVATE_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/driver_object.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/driver_object.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,328 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains support for the global driver variables. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++/* We use #define rather than static inline here so that the Windows ++ * "prefast" compiler can see its own locking primitive when these ++ * two function are used (and then perform extra checking where they ++ * are used) ++ * ++ * Both macros operate on an irq_flags_t ++*/ ++ ++#define efrm_driver_lock(irqlock_state) \ ++ spin_lock_irqsave(&efrm_nic_tablep->lock, irqlock_state) ++ ++#define efrm_driver_unlock(irqlock_state) \ ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, \ ++ irqlock_state); ++ ++/* These routines are all methods on the architecturally singleton ++ global variables: efrm_nic_table, efrm_rm_table. ++ ++ I hope we never find a driver model that does not allow global ++ structure variables :) (but that would break almost every driver I've ++ ever seen). ++*/ ++ ++/*! Exported driver state */ ++static struct efrm_nic_table efrm_nic_table; ++struct efrm_nic_table *efrm_nic_tablep; ++EXPORT_SYMBOL(efrm_nic_tablep); ++ ++ ++/* Internal table with resource managers. ++ * We'd like to not export it, but we are still using efrm_rm_table ++ * in the char driver. So, it is declared in the private header with ++ * a purpose. */ ++struct efrm_resource_manager *efrm_rm_table[EFRM_RESOURCE_NUM]; ++EXPORT_SYMBOL(efrm_rm_table); ++ ++ ++/* List of registered nics. */ ++static LIST_HEAD(efrm_nics); ++ ++ ++void efrm_driver_ctor(void) ++{ ++ efrm_nic_tablep = &efrm_nic_table; ++ spin_lock_init(&efrm_nic_tablep->lock); ++ EFRM_TRACE("%s: driver created", __func__); ++} ++ ++void efrm_driver_dtor(void) ++{ ++ EFRM_ASSERT(!efrm_nic_table_held()); ++ ++ spin_lock_destroy(&efrm_nic_tablep->lock); ++ memset(&efrm_nic_table, 0, sizeof(efrm_nic_table)); ++ memset(&efrm_rm_table, 0, sizeof(efrm_rm_table)); ++ EFRM_TRACE("%s: driver deleted", __func__); ++} ++ ++int efrm_driver_register_nic(struct efrm_nic *rnic, int nic_index, ++ int ifindex) ++{ ++ struct efhw_nic *nic = &rnic->efhw_nic; ++ struct efrm_nic_per_vi *vis; ++ int max_vis, rc = 0; ++ irq_flags_t lock_flags; ++ ++ EFRM_ASSERT(nic_index >= 0); ++ EFRM_ASSERT(ifindex >= 0); ++ ++ max_vis = 4096; /* TODO: Get runtime value. */ ++ vis = vmalloc(max_vis * sizeof(rnic->vis[0])); ++ if (vis == NULL) { ++ EFRM_ERR("%s: Out of memory", __func__); ++ return -ENOMEM; ++ } ++ ++ efrm_driver_lock(lock_flags); ++ ++ if (efrm_nic_table_held()) { ++ EFRM_ERR("%s: driver object is in use", __func__); ++ rc = -EBUSY; ++ goto done; ++ } ++ ++ if (efrm_nic_tablep->nic_count == EFHW_MAX_NR_DEVS) { ++ EFRM_ERR("%s: filled up NIC table size %d", __func__, ++ EFHW_MAX_NR_DEVS); ++ rc = -E2BIG; ++ goto done; ++ } ++ ++ rnic->vis = vis; ++ ++ EFRM_ASSERT(efrm_nic_tablep->nic[nic_index] == NULL); ++ efrm_nic_tablep->nic[nic_index] = nic; ++ nic->index = nic_index; ++ nic->ifindex = ifindex; ++ ++ if (efrm_nic_tablep->a_nic == NULL) ++ efrm_nic_tablep->a_nic = nic; ++ ++ efrm_nic_tablep->nic_count++; ++ ++ INIT_LIST_HEAD(&rnic->clients); ++ list_add(&rnic->link, &efrm_nics); ++ ++ efrm_driver_unlock(lock_flags); ++ return 0; ++ ++done: ++ efrm_driver_unlock(lock_flags); ++ vfree(vis); ++ return rc; ++} ++ ++int efrm_driver_unregister_nic(struct efrm_nic *rnic) ++{ ++ struct efhw_nic *nic = &rnic->efhw_nic; ++ int rc = 0; ++ int nic_index = nic->index; ++ irq_flags_t lock_flags; ++ ++ EFRM_ASSERT(nic_index >= 0); ++ ++ efrm_driver_lock(lock_flags); ++ ++ if (efrm_nic_table_held()) { ++ EFRM_ERR("%s: driver object is in use", __func__); ++ rc = -EBUSY; ++ goto done; ++ } ++ if (!list_empty(&rnic->clients)) { ++ EFRM_ERR("%s: nic has active clients", __func__); ++ rc = -EBUSY; ++ goto done; ++ } ++ ++ EFRM_ASSERT(efrm_nic_tablep->nic[nic_index] == nic); ++ EFRM_ASSERT(list_empty(&rnic->clients)); ++ ++ list_del(&rnic->link); ++ ++ nic->index = -1; ++ efrm_nic_tablep->nic[nic_index] = NULL; ++ ++ --efrm_nic_tablep->nic_count; ++ ++ if (efrm_nic_tablep->a_nic == nic) { ++ if (efrm_nic_tablep->nic_count == 0) { ++ efrm_nic_tablep->a_nic = NULL; ++ } else { ++ for (nic_index = 0; nic_index < EFHW_MAX_NR_DEVS; ++ nic_index++) { ++ if (efrm_nic_tablep->nic[nic_index] != NULL) ++ efrm_nic_tablep->a_nic = ++ efrm_nic_tablep->nic[nic_index]; ++ } ++ EFRM_ASSERT(efrm_nic_tablep->a_nic); ++ } ++ } ++ ++done: ++ efrm_driver_unlock(lock_flags); ++ return rc; ++} ++ ++ ++int efrm_nic_pre_reset(struct efhw_nic *nic) ++{ ++ struct efrm_nic *rnic = efrm_nic(nic); ++ struct efrm_client *client; ++ struct efrm_resource *rs; ++ struct list_head *client_link; ++ struct list_head *rs_link; ++ irq_flags_t lock_flags; ++ ++ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags); ++ list_for_each(client_link, &rnic->clients) { ++ client = container_of(client_link, struct efrm_client, link); ++ EFRM_ERR("%s: client %p", __func__, client); ++ if (client->callbacks->pre_reset) ++ client->callbacks->pre_reset(client, client->user_data); ++ list_for_each(rs_link, &client->resources) { ++ rs = container_of(rs_link, struct efrm_resource, ++ rs_client_link); ++ EFRM_ERR("%s: resource %p", __func__, rs); ++ /* TODO: mark rs defunct */ ++ } ++ } ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags); ++ ++ return 0; ++} ++ ++ ++int efrm_nic_stop(struct efhw_nic *nic) ++{ ++ /* TODO */ ++ return 0; ++} ++ ++ ++int efrm_nic_resume(struct efhw_nic *nic) ++{ ++ /* TODO */ ++ return 0; ++} ++ ++ ++static void efrm_client_nullcb(struct efrm_client *client, void *user_data) ++{ ++} ++ ++static struct efrm_client_callbacks efrm_null_callbacks = { ++ efrm_client_nullcb, ++ efrm_client_nullcb, ++ efrm_client_nullcb ++}; ++ ++ ++int efrm_client_get(int ifindex, struct efrm_client_callbacks *callbacks, ++ void *user_data, struct efrm_client **client_out) ++{ ++ struct efrm_nic *n, *rnic = NULL; ++ irq_flags_t lock_flags; ++ struct list_head *link; ++ struct efrm_client *client; ++ ++ if (callbacks == NULL) ++ callbacks = &efrm_null_callbacks; ++ ++ client = kmalloc(sizeof(*client), GFP_KERNEL); ++ if (client == NULL) ++ return -ENOMEM; ++ ++ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags); ++ list_for_each(link, &efrm_nics) { ++ n = container_of(link, struct efrm_nic, link); ++ if (n->efhw_nic.ifindex == ifindex || ifindex < 0) { ++ rnic = n; ++ break; ++ } ++ } ++ if (rnic) { ++ client->user_data = user_data; ++ client->callbacks = callbacks; ++ client->nic = &rnic->efhw_nic; ++ client->ref_count = 1; ++ INIT_LIST_HEAD(&client->resources); ++ list_add(&client->link, &rnic->clients); ++ } ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags); ++ ++ if (rnic == NULL) ++ return -ENODEV; ++ ++ *client_out = client; ++ return 0; ++} ++EXPORT_SYMBOL(efrm_client_get); ++ ++ ++void efrm_client_put(struct efrm_client *client) ++{ ++ irq_flags_t lock_flags; ++ ++ EFRM_ASSERT(client->ref_count > 0); ++ ++ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags); ++ if (--client->ref_count > 0) ++ client = NULL; ++ else ++ list_del(&client->link); ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags); ++ kfree(client); ++} ++EXPORT_SYMBOL(efrm_client_put); ++ ++ ++struct efhw_nic *efrm_client_get_nic(struct efrm_client *client) ++{ ++ return client->nic; ++} ++EXPORT_SYMBOL(efrm_client_get_nic); +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/driverlink_new.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/driverlink_new.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,260 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains driverlink code which interacts with the sfc network ++ * driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include "linux_resource_internal.h" ++#include "driverlink_api.h" ++#include "kernel_compat.h" ++#include ++ ++#include ++#include ++#include ++ ++/* The DL driver and associated calls */ ++static int efrm_dl_probe(struct efx_dl_device *efrm_dev, ++ const struct net_device *net_dev, ++ const struct efx_dl_device_info *dev_info, ++ const char *silicon_rev); ++ ++static void efrm_dl_remove(struct efx_dl_device *efrm_dev); ++ ++static void efrm_dl_reset_suspend(struct efx_dl_device *efrm_dev); ++ ++static void efrm_dl_reset_resume(struct efx_dl_device *efrm_dev, int ok); ++ ++static void efrm_dl_mtu_changed(struct efx_dl_device *, int); ++static void efrm_dl_event_falcon(struct efx_dl_device *efx_dev, void *p_event); ++ ++static struct efx_dl_driver efrm_dl_driver = { ++ .name = "resource", ++ .probe = efrm_dl_probe, ++ .remove = efrm_dl_remove, ++ .reset_suspend = efrm_dl_reset_suspend, ++ .reset_resume = efrm_dl_reset_resume ++}; ++ ++static void ++init_vi_resource_dimensions(struct vi_resource_dimensions *rd, ++ const struct efx_dl_falcon_resources *res) ++{ ++ rd->evq_timer_min = res->evq_timer_min; ++ rd->evq_timer_lim = res->evq_timer_lim; ++ rd->evq_int_min = res->evq_int_min; ++ rd->evq_int_lim = res->evq_int_lim; ++ rd->rxq_min = res->rxq_min; ++ rd->rxq_lim = res->rxq_lim; ++ rd->txq_min = res->txq_min; ++ rd->txq_lim = res->txq_lim; ++ EFRM_TRACE ++ ("Using evq_int(%d-%d) evq_timer(%d-%d) RXQ(%d-%d) TXQ(%d-%d)", ++ res->evq_int_min, res->evq_int_lim, res->evq_timer_min, ++ res->evq_timer_lim, res->rxq_min, res->rxq_lim, res->txq_min, ++ res->txq_lim); ++} ++ ++static int ++efrm_dl_probe(struct efx_dl_device *efrm_dev, ++ const struct net_device *net_dev, ++ const struct efx_dl_device_info *dev_info, ++ const char *silicon_rev) ++{ ++ struct vi_resource_dimensions res_dim; ++ struct efx_dl_falcon_resources *res; ++ struct linux_efhw_nic *lnic; ++ struct pci_dev *dev; ++ struct efhw_nic *nic; ++ unsigned probe_flags = 0; ++ int non_irq_evq; ++ int rc; ++ ++ efrm_dev->priv = NULL; ++ ++ efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES, ++ struct efx_dl_falcon_resources, ++ hdr, res); ++ ++ if (res == NULL) { ++ EFRM_ERR("%s: Unable to find falcon driverlink resources", ++ __func__); ++ return -EINVAL; ++ } ++ ++ if (res->flags & EFX_DL_FALCON_USE_MSI) ++ probe_flags |= NIC_FLAG_TRY_MSI; ++ ++ dev = efrm_dev->pci_dev; ++ if (res->flags & EFX_DL_FALCON_DUAL_FUNC) { ++ unsigned vendor = dev->vendor; ++ EFRM_ASSERT(dev->bus != NULL); ++ dev = NULL; ++ ++ while ((dev = pci_get_device(vendor, FALCON_S_DEVID, dev)) ++ != NULL) { ++ EFRM_ASSERT(dev->bus != NULL); ++ /* With PCIe (since it's point to point) ++ * the slot ID is usually 0 and ++ * the bus ID changes NIC to NIC, so we really ++ * need to check both. */ ++ if (PCI_SLOT(dev->devfn) == ++ PCI_SLOT(efrm_dev->pci_dev->devfn) ++ && dev->bus->number == ++ efrm_dev->pci_dev->bus->number) ++ break; ++ } ++ if (dev == NULL) { ++ EFRM_ERR("%s: Unable to find falcon secondary " ++ "PCI device.", __func__); ++ return -ENODEV; ++ } ++ pci_dev_put(dev); ++ } ++ ++ init_vi_resource_dimensions(&res_dim, res); ++ ++ EFRM_ASSERT(res_dim.evq_timer_lim > res_dim.evq_timer_min); ++ res_dim.evq_timer_lim--; ++ non_irq_evq = res_dim.evq_timer_lim; ++ ++ rc = efrm_nic_add(dev, probe_flags, net_dev->dev_addr, &lnic, ++ res->biu_lock, ++ res->buffer_table_min, res->buffer_table_lim, ++ non_irq_evq, &res_dim); ++ if (rc != 0) ++ return rc; ++ ++ nic = &lnic->efrm_nic.efhw_nic; ++ nic->mtu = net_dev->mtu + ETH_HLEN; ++ nic->net_driver_dev = efrm_dev; ++ nic->ifindex = net_dev->ifindex; ++#ifdef CONFIG_NET_NS ++ nic->nd_net = net_dev->nd_net; ++#endif ++ efrm_dev->priv = nic; ++ ++ /* Register a callback so we're told when MTU changes. ++ * We dynamically allocate efx_dl_callbacks, because ++ * the callbacks that we want depends on the NIC type. ++ */ ++ lnic->dl_callbacks = ++ kmalloc(sizeof(struct efx_dl_callbacks), GFP_KERNEL); ++ if (!lnic->dl_callbacks) { ++ EFRM_ERR("Out of memory (%s)", __func__); ++ efrm_nic_del(lnic); ++ return -ENOMEM; ++ } ++ memset(lnic->dl_callbacks, 0, sizeof(*lnic->dl_callbacks)); ++ lnic->dl_callbacks->mtu_changed = efrm_dl_mtu_changed; ++ ++ if ((res->flags & EFX_DL_FALCON_DUAL_FUNC) == 0) { ++ /* Net driver receives all management events. ++ * Register a callback to receive the ones ++ * we're interested in. */ ++ lnic->dl_callbacks->event = efrm_dl_event_falcon; ++ } ++ ++ rc = efx_dl_register_callbacks(efrm_dev, lnic->dl_callbacks); ++ if (rc < 0) { ++ EFRM_ERR("%s: efx_dl_register_callbacks failed (%d)", ++ __func__, rc); ++ kfree(lnic->dl_callbacks); ++ efrm_nic_del(lnic); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++/* When we unregister ourselves on module removal, this function will be ++ * called for all the devices we claimed */ ++static void efrm_dl_remove(struct efx_dl_device *efrm_dev) ++{ ++ struct efhw_nic *nic = efrm_dev->priv; ++ struct linux_efhw_nic *lnic = linux_efhw_nic(nic); ++ EFRM_TRACE("%s called", __func__); ++ if (lnic->dl_callbacks) { ++ efx_dl_unregister_callbacks(efrm_dev, lnic->dl_callbacks); ++ kfree(lnic->dl_callbacks); ++ } ++ if (efrm_dev->priv) ++ efrm_nic_del(lnic); ++ EFRM_TRACE("%s OK", __func__); ++} ++ ++static void efrm_dl_reset_suspend(struct efx_dl_device *efrm_dev) ++{ ++ EFRM_NOTICE("%s:", __func__); ++} ++ ++static void efrm_dl_reset_resume(struct efx_dl_device *efrm_dev, int ok) ++{ ++ EFRM_NOTICE("%s: ok=%d", __func__, ok); ++} ++ ++int efrm_driverlink_register(void) ++{ ++ EFRM_TRACE("%s:", __func__); ++ return efx_dl_register_driver(&efrm_dl_driver); ++} ++ ++void efrm_driverlink_unregister(void) ++{ ++ EFRM_TRACE("%s:", __func__); ++ efx_dl_unregister_driver(&efrm_dl_driver); ++} ++ ++static void efrm_dl_mtu_changed(struct efx_dl_device *efx_dev, int mtu) ++{ ++ struct efhw_nic *nic = efx_dev->priv; ++ ++ ASSERT_RTNL(); /* Since we're looking at efx_dl_device::port_net_dev */ ++ ++ EFRM_TRACE("%s: old=%d new=%d", __func__, nic->mtu, mtu + ETH_HLEN); ++ /* If this happened we must have agreed to it above */ ++ nic->mtu = mtu + ETH_HLEN; ++} ++ ++static void efrm_dl_event_falcon(struct efx_dl_device *efx_dev, void *p_event) ++{ ++ struct efhw_nic *nic = efx_dev->priv; ++ struct linux_efhw_nic *lnic = linux_efhw_nic(nic); ++ efhw_event_t *ev = p_event; ++ ++ switch (FALCON_EVENT_CODE(ev)) { ++ case FALCON_EVENT_CODE_CHAR: ++ falcon_handle_char_event(nic, lnic->ev_handlers, ev); ++ break; ++ default: ++ EFRM_WARN("%s: unknown event type=%x", __func__, ++ (unsigned)FALCON_EVENT_CODE(ev)); ++ break; ++ } ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/efrm_internal.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/efrm_internal.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,41 @@ ++#ifndef __EFRM_INTERNAL_H__ ++#define __EFRM_INTERNAL_H__ ++ ++ ++struct filter_resource { ++ struct efrm_resource rs; ++ struct vi_resource *pt; ++ int filter_idx; ++}; ++ ++#define filter_resource(rs1) container_of((rs1), struct filter_resource, rs) ++ ++ ++struct efrm_client { ++ void *user_data; ++ struct list_head link; ++ struct efrm_client_callbacks *callbacks; ++ struct efhw_nic *nic; ++ int ref_count; ++ struct list_head resources; ++}; ++ ++ ++extern void efrm_client_add_resource(struct efrm_client *, ++ struct efrm_resource *); ++ ++extern int efrm_buffer_table_size(void); ++ ++ ++static inline void efrm_resource_init(struct efrm_resource *rs, ++ int type, int instance) ++{ ++ EFRM_ASSERT(instance >= 0); ++ EFRM_ASSERT(type >= 0 && type < EFRM_RESOURCE_NUM); ++ rs->rs_ref_count = 1; ++ rs->rs_handle.handle = (type << 28u) | ++ (((unsigned)jiffies & 0xfff) << 16) | instance; ++} ++ ++ ++#endif /* __EFRM_INTERNAL_H__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/efx_vi_shm.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/efx_vi_shm.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,707 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides implementation of EFX VI API, used from Xen ++ * acceleration driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include "linux_resource_internal.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "kernel_compat.h" ++ ++#if EFX_VI_STATIC_FILTERS ++struct filter_list_t { ++ struct filter_list_t *next; ++ struct filter_resource *fres; ++}; ++#endif ++ ++struct efx_vi_state { ++ struct vi_resource *vi_res; ++ ++ int ifindex; ++ struct efrm_client *efrm_client; ++ struct efhw_nic *nic; ++ ++ void (*callback_fn)(void *arg, int is_timeout); ++ void *callback_arg; ++ ++ struct completion flush_completion; ++ ++#if EFX_VI_STATIC_FILTERS ++ struct filter_list_t fres[EFX_VI_STATIC_FILTERS]; ++ struct filter_list_t *free_fres; ++ struct filter_list_t *used_fres; ++#endif ++}; ++ ++static void efx_vi_flush_complete(void *state_void) ++{ ++ struct efx_vi_state *state = (struct efx_vi_state *)state_void; ++ ++ complete(&state->flush_completion); ++} ++ ++static inline int alloc_ep(struct efx_vi_state *state) ++{ ++ int rc; ++ ++ rc = efrm_vi_resource_alloc(state->efrm_client, NULL, EFHW_VI_JUMBO_EN, ++ efx_vi_eventq_size, ++ FALCON_DMA_Q_DEFAULT_TX_SIZE, ++ FALCON_DMA_Q_DEFAULT_RX_SIZE, ++ 0, 0, &state->vi_res, NULL, NULL, NULL, ++ NULL); ++ if (rc < 0) { ++ EFRM_ERR("%s: ERROR efrm_vi_resource_alloc error %d", ++ __func__, rc); ++ return rc; ++ } ++ ++ efrm_vi_register_flush_callback(state->vi_res, &efx_vi_flush_complete, ++ (void *)state); ++ ++ return 0; ++} ++ ++static int free_ep(struct efx_vi_state *efx_state) ++{ ++ efrm_vi_resource_release(efx_state->vi_res); ++ ++ return 0; ++} ++ ++#if EFX_VI_STATIC_FILTERS ++static int efx_vi_alloc_static_filters(struct efx_vi_state *efx_state) ++{ ++ int i; ++ int rc; ++ ++ efx_state->free_fres = efx_state->used_fres = NULL; ++ ++ for (i = 0; i < EFX_VI_STATIC_FILTERS; i++) { ++ rc = efrm_filter_resource_alloc(efx_state->vi_res, ++ &efx_state->fres[i].fres); ++ if (rc < 0) { ++ EFRM_ERR("%s: efrm_filter_resource_alloc failed: %d", ++ __func__, rc); ++ while (i > 0) { ++ i--; ++ efrm_filter_resource_release(efx_state-> ++ fres[i].fres); ++ } ++ efx_state->free_fres = NULL; ++ return rc; ++ } ++ efx_state->fres[i].next = efx_state->free_fres; ++ efx_state->free_fres = &efx_state->fres[i]; ++ } ++ ++ return 0; ++} ++#endif ++ ++int efx_vi_alloc(struct efx_vi_state **vih_out, int ifindex) ++{ ++ struct efx_vi_state *efx_state; ++ int rc; ++ ++ efx_state = kmalloc(sizeof(struct efx_vi_state), GFP_KERNEL); ++ ++ if (!efx_state) { ++ EFRM_ERR("%s: failed to allocate memory for efx_vi_state", ++ __func__); ++ rc = -ENOMEM; ++ goto fail; ++ } ++ ++ efx_state->ifindex = ifindex; ++ rc = efrm_client_get(ifindex, NULL, NULL, &efx_state->efrm_client); ++ if (rc < 0) { ++ EFRM_ERR("%s: efrm_client_get(%d) failed: %d", __func__, ++ ifindex, rc); ++ rc = -ENODEV; ++ goto fail_no_ifindex; ++ } ++ efx_state->nic = efrm_client_get_nic(efx_state->efrm_client); ++ ++ init_completion(&efx_state->flush_completion); ++ ++ /* basically allocate_pt_endpoint() */ ++ rc = alloc_ep(efx_state); ++ if (rc) { ++ EFRM_ERR("%s: alloc_ep failed: %d", __func__, rc); ++ goto fail_no_pt; ++ } ++#if EFX_VI_STATIC_FILTERS ++ /* Statically allocate a set of filter resources - removes the ++ restriction on not being able to use efx_vi_filter() from ++ in_atomic() */ ++ rc = efx_vi_alloc_static_filters(efx_state); ++ if (rc) ++ goto fail_no_filters; ++#endif ++ ++ *vih_out = efx_state; ++ ++ return 0; ++#if EFX_VI_STATIC_FILTERS ++fail_no_filters: ++ free_ep(efx_state); ++#endif ++fail_no_pt: ++ efrm_client_put(efx_state->efrm_client); ++fail_no_ifindex: ++ kfree(efx_state); ++fail: ++ return rc; ++} ++EXPORT_SYMBOL(efx_vi_alloc); ++ ++void efx_vi_free(struct efx_vi_state *vih) ++{ ++ struct efx_vi_state *efx_state = vih; ++ ++ /* TODO flush dma channels, init dma queues?. See ef_free_vnic() */ ++#if EFX_VI_STATIC_FILTERS ++ int i; ++ ++ for (i = 0; i < EFX_VI_STATIC_FILTERS; i++) ++ efrm_filter_resource_release(efx_state->fres[i].fres); ++#endif ++ ++ if (efx_state->vi_res) ++ free_ep(efx_state); ++ ++ efrm_client_put(efx_state->efrm_client); ++ ++ kfree(efx_state); ++} ++EXPORT_SYMBOL(efx_vi_free); ++ ++void efx_vi_reset(struct efx_vi_state *vih) ++{ ++ struct efx_vi_state *efx_state = vih; ++ ++ efrm_pt_flush(efx_state->vi_res); ++ ++ while (wait_for_completion_timeout(&efx_state->flush_completion, HZ) ++ == 0) ++ efrm_vi_resource_flush_retry(efx_state->vi_res); ++ ++ /* Bosch the eventq */ ++ efrm_eventq_reset(efx_state->vi_res); ++ return; ++} ++EXPORT_SYMBOL(efx_vi_reset); ++ ++static void ++efx_vi_eventq_callback(void *context, int is_timeout, struct efhw_nic *nic) ++{ ++ struct efx_vi_state *efx_state = (struct efx_vi_state *)context; ++ ++ EFRM_ASSERT(efx_state->callback_fn); ++ ++ return efx_state->callback_fn(efx_state->callback_arg, is_timeout); ++} ++ ++int ++efx_vi_eventq_register_callback(struct efx_vi_state *vih, ++ void (*callback)(void *context, int is_timeout), ++ void *context) ++{ ++ struct efx_vi_state *efx_state = vih; ++ ++ efx_state->callback_fn = callback; ++ efx_state->callback_arg = context; ++ ++ /* Register the eventq timeout event callback */ ++ efrm_eventq_register_callback(efx_state->vi_res, ++ efx_vi_eventq_callback, efx_state); ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_vi_eventq_register_callback); ++ ++int efx_vi_eventq_kill_callback(struct efx_vi_state *vih) ++{ ++ struct efx_vi_state *efx_state = vih; ++ ++ if (efx_state->vi_res->evq_callback_fn) ++ efrm_eventq_kill_callback(efx_state->vi_res); ++ ++ efx_state->callback_fn = NULL; ++ efx_state->callback_arg = NULL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_vi_eventq_kill_callback); ++ ++struct efx_vi_dma_map_state { ++ struct efhw_buffer_table_allocation bt_handle; ++ int n_pages; ++ dma_addr_t *dma_addrs; ++}; ++ ++int ++efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages, ++ int n_pages, struct efx_vi_dma_map_state **dmh_out) ++{ ++ struct efx_vi_state *efx_state = vih; ++ int order = fls(n_pages - 1), rc, i, evq_id; ++ dma_addr_t dma_addr; ++ struct efx_vi_dma_map_state *dm_state; ++ ++ if (n_pages != (1 << order)) { ++ EFRM_WARN("%s: Can only allocate buffers in power of 2 " ++ "sizes (not %d)", __func__, n_pages); ++ return -EINVAL; ++ } ++ ++ dm_state = kmalloc(sizeof(struct efx_vi_dma_map_state), GFP_KERNEL); ++ if (!dm_state) ++ return -ENOMEM; ++ ++ dm_state->dma_addrs = kmalloc(sizeof(dma_addr_t) * n_pages, ++ GFP_KERNEL); ++ if (!dm_state->dma_addrs) { ++ kfree(dm_state); ++ return -ENOMEM; ++ } ++ ++ rc = efrm_buffer_table_alloc(order, &dm_state->bt_handle); ++ if (rc < 0) { ++ kfree(dm_state->dma_addrs); ++ kfree(dm_state); ++ return rc; ++ } ++ ++ evq_id = EFRM_RESOURCE_INSTANCE(efx_state->vi_res->rs.rs_handle); ++ for (i = 0; i < n_pages; i++) { ++ /* TODO do we need to get_page() here ? */ ++ ++ dma_addr = pci_map_page(linux_efhw_nic(efx_state->nic)-> ++ pci_dev, pages[i], 0, PAGE_SIZE, ++ PCI_DMA_TODEVICE); ++ ++ efrm_buffer_table_set(&dm_state->bt_handle, efx_state->nic, ++ i, dma_addr, evq_id); ++ ++ dm_state->dma_addrs[i] = dma_addr; ++ ++ /* Would be nice to not have to call commit each time, but ++ * comment says there are hardware restrictions on how often ++ * you can go without it, so do this to be safe */ ++ efrm_buffer_table_commit(); ++ } ++ ++ dm_state->n_pages = n_pages; ++ ++ *dmh_out = dm_state; ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_vi_dma_map_pages); ++ ++/* Function needed as Xen can't get pages for grants in dom0, but can ++ get dma address */ ++int ++efx_vi_dma_map_addrs(struct efx_vi_state *vih, ++ unsigned long long *bus_dev_addrs, ++ int n_pages, struct efx_vi_dma_map_state **dmh_out) ++{ ++ struct efx_vi_state *efx_state = vih; ++ int order = fls(n_pages - 1), rc, i, evq_id; ++ dma_addr_t dma_addr; ++ struct efx_vi_dma_map_state *dm_state; ++ ++ if (n_pages != (1 << order)) { ++ EFRM_WARN("%s: Can only allocate buffers in power of 2 " ++ "sizes (not %d)", __func__, n_pages); ++ return -EINVAL; ++ } ++ ++ dm_state = kmalloc(sizeof(struct efx_vi_dma_map_state), GFP_KERNEL); ++ if (!dm_state) ++ return -ENOMEM; ++ ++ dm_state->dma_addrs = kmalloc(sizeof(dma_addr_t) * n_pages, ++ GFP_KERNEL); ++ if (!dm_state->dma_addrs) { ++ kfree(dm_state); ++ return -ENOMEM; ++ } ++ ++ rc = efrm_buffer_table_alloc(order, &dm_state->bt_handle); ++ if (rc < 0) { ++ kfree(dm_state->dma_addrs); ++ kfree(dm_state); ++ return rc; ++ } ++ ++ evq_id = EFRM_RESOURCE_INSTANCE(efx_state->vi_res->rs.rs_handle); ++#if 0 ++ EFRM_WARN("%s: mapping %d pages to evq %d, bt_ids %d-%d\n", ++ __func__, n_pages, evq_id, ++ dm_state->bt_handle.base, ++ dm_state->bt_handle.base + n_pages); ++#endif ++ for (i = 0; i < n_pages; i++) { ++ ++ dma_addr = (dma_addr_t)bus_dev_addrs[i]; ++ ++ efrm_buffer_table_set(&dm_state->bt_handle, efx_state->nic, ++ i, dma_addr, evq_id); ++ ++ dm_state->dma_addrs[i] = dma_addr; ++ ++ /* Would be nice to not have to call commit each time, but ++ * comment says there are hardware restrictions on how often ++ * you can go without it, so do this to be safe */ ++ efrm_buffer_table_commit(); ++ } ++ ++ dm_state->n_pages = n_pages; ++ ++ *dmh_out = dm_state; ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_vi_dma_map_addrs); ++ ++void ++efx_vi_dma_unmap_pages(struct efx_vi_state *vih, ++ struct efx_vi_dma_map_state *dmh) ++{ ++ struct efx_vi_state *efx_state = vih; ++ struct efx_vi_dma_map_state *dm_state = ++ (struct efx_vi_dma_map_state *)dmh; ++ int i; ++ ++ efrm_buffer_table_free(&dm_state->bt_handle); ++ ++ for (i = 0; i < dm_state->n_pages; ++i) ++ pci_unmap_page(linux_efhw_nic(efx_state->nic)->pci_dev, ++ dm_state->dma_addrs[i], PAGE_SIZE, ++ PCI_DMA_TODEVICE); ++ ++ kfree(dm_state->dma_addrs); ++ kfree(dm_state); ++ ++ return; ++} ++EXPORT_SYMBOL(efx_vi_dma_unmap_pages); ++ ++void ++efx_vi_dma_unmap_addrs(struct efx_vi_state *vih, ++ struct efx_vi_dma_map_state *dmh) ++{ ++ struct efx_vi_dma_map_state *dm_state = ++ (struct efx_vi_dma_map_state *)dmh; ++ ++ efrm_buffer_table_free(&dm_state->bt_handle); ++ ++ kfree(dm_state->dma_addrs); ++ kfree(dm_state); ++ ++ return; ++} ++EXPORT_SYMBOL(efx_vi_dma_unmap_addrs); ++ ++unsigned ++efx_vi_dma_get_map_addr(struct efx_vi_state *vih, ++ struct efx_vi_dma_map_state *dmh) ++{ ++ struct efx_vi_dma_map_state *dm_state = ++ (struct efx_vi_dma_map_state *)dmh; ++ ++ return EFHW_BUFFER_ADDR(dm_state->bt_handle.base, 0); ++} ++EXPORT_SYMBOL(efx_vi_dma_get_map_addr); ++ ++#if EFX_VI_STATIC_FILTERS ++static int ++get_filter(struct efx_vi_state *efx_state, ++ efrm_resource_handle_t pthandle, struct filter_resource **fres_out) ++{ ++ struct filter_list_t *flist; ++ if (efx_state->free_fres == NULL) ++ return -ENOMEM; ++ else { ++ flist = efx_state->free_fres; ++ efx_state->free_fres = flist->next; ++ flist->next = efx_state->used_fres; ++ efx_state->used_fres = flist; ++ *fres_out = flist->fres; ++ return 0; ++ } ++} ++#endif ++ ++static void ++release_filter(struct efx_vi_state *efx_state, struct filter_resource *fres) ++{ ++#if EFX_VI_STATIC_FILTERS ++ struct filter_list_t *flist = efx_state->used_fres, *prev = NULL; ++ while (flist) { ++ if (flist->fres == fres) { ++ if (prev) ++ prev->next = flist->next; ++ else ++ efx_state->used_fres = flist->next; ++ flist->next = efx_state->free_fres; ++ efx_state->free_fres = flist; ++ return; ++ } ++ prev = flist; ++ flist = flist->next; ++ } ++ EFRM_ERR("%s: couldn't find filter", __func__); ++#else ++ return efrm_filter_resource_release(fres); ++#endif ++} ++ ++int ++efx_vi_filter(struct efx_vi_state *vih, int protocol, ++ unsigned ip_addr_be32, int port_le16, ++ struct filter_resource_t **fh_out) ++{ ++ struct efx_vi_state *efx_state = vih; ++ struct filter_resource *uninitialized_var(frs); ++ int rc; ++ ++#if EFX_VI_STATIC_FILTERS ++ rc = get_filter(efx_state, efx_state->vi_res->rs.rs_handle, &frs); ++#else ++ rc = efrm_filter_resource_alloc(efx_state->vi_res, &frs); ++#endif ++ if (rc < 0) ++ return rc; ++ ++ /* Add the hardware filter. We pass in the source port and address ++ * as 0 (wildcard) to minimise the number of filters needed. */ ++ if (protocol == IPPROTO_TCP) { ++ rc = efrm_filter_resource_tcp_set(frs, 0, 0, ip_addr_be32, ++ port_le16); ++ } else { ++ rc = efrm_filter_resource_udp_set(frs, 0, 0, ip_addr_be32, ++ port_le16); ++ } ++ ++ *fh_out = (struct filter_resource_t *)frs; ++ ++ return rc; ++} ++EXPORT_SYMBOL(efx_vi_filter); ++ ++int ++efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh) ++{ ++ struct efx_vi_state *efx_state = vih; ++ struct filter_resource *frs = (struct filter_resource *)fh; ++ int rc; ++ ++ rc = efrm_filter_resource_clear(frs); ++ release_filter(efx_state, frs); ++ ++ return rc; ++} ++EXPORT_SYMBOL(efx_vi_filter_stop); ++ ++int ++efx_vi_hw_resource_get_virt(struct efx_vi_state *vih, ++ struct efx_vi_hw_resource_metadata *mdata, ++ struct efx_vi_hw_resource *hw_res_array, ++ int *length) ++{ ++ EFRM_NOTICE("%s: TODO!", __func__); ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_vi_hw_resource_get_virt); ++ ++int ++efx_vi_hw_resource_get_phys(struct efx_vi_state *vih, ++ struct efx_vi_hw_resource_metadata *mdata, ++ struct efx_vi_hw_resource *hw_res_array, ++ int *length) ++{ ++ struct efx_vi_state *efx_state = vih; ++ struct linux_efhw_nic *lnic = linux_efhw_nic(efx_state->nic); ++ unsigned long phys = lnic->ctr_ap_pci_addr; ++ struct efrm_resource *ep_res = &efx_state->vi_res->rs; ++ unsigned ep_mmap_bytes; ++ int i; ++ ++ if (*length < EFX_VI_HW_RESOURCE_MAXSIZE) ++ return -EINVAL; ++ ++ mdata->nic_arch = efx_state->nic->devtype.arch; ++ mdata->nic_variant = efx_state->nic->devtype.variant; ++ mdata->nic_revision = efx_state->nic->devtype.revision; ++ ++ mdata->evq_order = ++ efx_state->vi_res->nic_info.evq_pages.iobuff.order; ++ mdata->evq_offs = efx_state->vi_res->nic_info.evq_pages.iobuff_off; ++ mdata->evq_capacity = efx_vi_eventq_size; ++ mdata->instance = EFRM_RESOURCE_INSTANCE(ep_res->rs_handle); ++ mdata->rx_capacity = FALCON_DMA_Q_DEFAULT_RX_SIZE; ++ mdata->tx_capacity = FALCON_DMA_Q_DEFAULT_TX_SIZE; ++ ++ ep_mmap_bytes = FALCON_DMA_Q_DEFAULT_MMAP; ++ EFRM_ASSERT(ep_mmap_bytes == PAGE_SIZE * 2); ++ ++#ifndef NDEBUG ++ { ++ /* Sanity about doorbells */ ++ unsigned long tx_dma_page_addr, rx_dma_page_addr; ++ ++ /* get rx doorbell address */ ++ rx_dma_page_addr = ++ phys + falcon_rx_dma_page_addr(mdata->instance); ++ /* get tx doorbell address */ ++ tx_dma_page_addr = ++ phys + falcon_tx_dma_page_addr(mdata->instance); ++ ++ /* Check the lower bits of the TX doorbell will be ++ * consistent. */ ++ EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & ++ FALCON_DMA_PAGE_MASK) == ++ (TX_DESC_UPD_REG_PAGE123K_OFST & ++ FALCON_DMA_PAGE_MASK)); ++ ++ /* Check the lower bits of the RX doorbell will be ++ * consistent. */ ++ EFRM_ASSERT((RX_DESC_UPD_REG_PAGE4_OFST & ++ FALCON_DMA_PAGE_MASK) == ++ (RX_DESC_UPD_REG_PAGE123K_OFST & ++ FALCON_DMA_PAGE_MASK)); ++ ++ /* Check that the doorbells will be in the same page. */ ++ EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & PAGE_MASK) == ++ (RX_DESC_UPD_REG_PAGE4_OFST & PAGE_MASK)); ++ ++ /* Check that the doorbells are in the same page. */ ++ EFRM_ASSERT((tx_dma_page_addr & PAGE_MASK) == ++ (rx_dma_page_addr & PAGE_MASK)); ++ ++ /* Check that the TX doorbell offset is correct. */ ++ EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & ~PAGE_MASK) == ++ (tx_dma_page_addr & ~PAGE_MASK)); ++ ++ /* Check that the RX doorbell offset is correct. */ ++ EFRM_ASSERT((RX_DESC_UPD_REG_PAGE4_OFST & ~PAGE_MASK) == ++ (rx_dma_page_addr & ~PAGE_MASK)); ++ } ++#endif ++ ++ i = 0; ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_TXDMAQ; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = ++ (unsigned long)efx_state->vi_res->nic_info. ++ dmaq_pages[EFRM_VI_RM_DMA_QUEUE_TX].kva; ++ ++ i++; ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_RXDMAQ; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = ++ (unsigned long)efx_state->vi_res->nic_info. ++ dmaq_pages[EFRM_VI_RM_DMA_QUEUE_RX].kva; ++ ++ i++; ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQTIMER; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = ++ (unsigned long)phys + falcon_timer_page_addr(mdata->instance); ++ ++ /* NB EFX_VI_HW_RESOURCE_EVQPTR not used on Falcon */ ++ ++ i++; ++ switch (efx_state->nic->devtype.variant) { ++ case 'A': ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQRPTR; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = (unsigned long)phys + ++ EVQ_RPTR_REG_OFST + ++ (FALCON_REGISTER128 * mdata->instance); ++ break; ++ case 'B': ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = ++ (unsigned long)FALCON_EVQ_RPTR_REG_P0; ++ break; ++ default: ++ EFRM_ASSERT(0); ++ break; ++ } ++ ++ i++; ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQMEMKVA; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_IOBUFFER; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = (unsigned long)efx_state->vi_res-> ++ nic_info.evq_pages.iobuff.kva; ++ ++ i++; ++ hw_res_array[i].type = EFX_VI_HW_RESOURCE_BELLPAGE; ++ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL; ++ hw_res_array[i].more_to_follow = 0; ++ hw_res_array[i].length = PAGE_SIZE; ++ hw_res_array[i].address = ++ (unsigned long)(phys + ++ falcon_tx_dma_page_addr(mdata->instance)) ++ >> PAGE_SHIFT; ++ ++ i++; ++ ++ EFRM_ASSERT(i <= *length); ++ ++ *length = i; ++ ++ return 0; ++} ++EXPORT_SYMBOL(efx_vi_hw_resource_get_phys); +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/eventq.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/eventq.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,321 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains event queue support. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define KEVENTQ_MAGIC 0x07111974 ++ ++/*! Helper function to allocate the iobuffer needed by an eventq ++ * - it ensures the eventq has the correct alignment for the NIC ++ * ++ * \param rm Event-queue resource manager ++ * \param instance Event-queue instance (index) ++ * \param buf_bytes Requested size of eventq ++ * \return < 0 if iobuffer allocation fails ++ */ ++int ++efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic, ++ struct eventq_resource_hardware *h, ++ int evq_instance, unsigned buf_bytes) ++{ ++ unsigned int page_order; ++ int rc; ++ ++ /* Allocate an iobuffer. */ ++ page_order = get_order(buf_bytes); ++ ++ h->iobuff_off = 0; ++ ++ EFHW_TRACE("allocating eventq size %x", ++ 1u << (page_order + PAGE_SHIFT)); ++ rc = efhw_iopages_alloc(nic, &h->iobuff, page_order); ++ if (rc < 0) { ++ EFHW_WARN("%s: failed to allocate %u pages", ++ __func__, 1u << page_order); ++ return rc; ++ } ++ ++ /* Set the eventq pages to match EFHW_CLEAR_EVENT() */ ++ if (EFHW_CLEAR_EVENT_VALUE) ++ memset(efhw_iopages_ptr(&h->iobuff) + h->iobuff_off, ++ EFHW_CLEAR_EVENT_VALUE, (1u << page_order) * PAGE_SIZE); ++ ++ EFHW_TRACE("%s: allocated %u pages", __func__, 1u << (page_order)); ++ ++ /* For Falcon the NIC is programmed with the base buffer address of a ++ * contiguous region of buffer space. This means that larger than a ++ * PAGE event queues can be expected to allocate even when the host's ++ * physical memory is fragmented */ ++ EFHW_ASSERT(efhw_nic_have_hw(nic)); ++ EFHW_ASSERT(page_order <= h->buf_tbl_alloc.order); ++ ++ /* Initialise the buffer table entries. */ ++ falcon_nic_buffer_table_set_n(nic, h->buf_tbl_alloc.base, ++ efhw_iopages_dma_addr(&h->iobuff) + ++ h->iobuff_off, EFHW_NIC_PAGE_SIZE, 0, ++ 1 << page_order, 0); ++ ++ if (evq_instance >= FALCON_EVQ_TBL_RESERVED) ++ falcon_nic_buffer_table_confirm(nic); ++ return 0; ++} ++ ++/********************************************************************** ++ * Kernel event queue management. ++ */ ++ ++/* Values for [struct efhw_keventq::lock] field. */ ++#define KEVQ_UNLOCKED 0 ++#define KEVQ_LOCKED 1 ++#define KEVQ_RECHECK 2 ++ ++int ++efhw_keventq_ctor(struct efhw_nic *nic, int instance, ++ struct efhw_keventq *evq, ++ struct efhw_ev_handler *ev_handlers) ++{ ++ int rc; ++ unsigned buf_bytes = evq->hw.capacity * sizeof(efhw_event_t); ++ ++ evq->instance = instance; ++ evq->ev_handlers = ev_handlers; ++ ++ /* allocate an IObuffer for the eventq */ ++ rc = efhw_nic_event_queue_alloc_iobuffer(nic, &evq->hw, evq->instance, ++ buf_bytes); ++ if (rc < 0) ++ return rc; ++ ++ /* Zero the timer-value for this queue. ++ AND Tell the nic about the event queue. */ ++ efhw_nic_event_queue_enable(nic, evq->instance, evq->hw.capacity, ++ efhw_iopages_dma_addr(&evq->hw.iobuff) + ++ evq->hw.iobuff_off, ++ evq->hw.buf_tbl_alloc.base, ++ 1 /* interrupting */); ++ ++ evq->lock = KEVQ_UNLOCKED; ++ evq->evq_base = efhw_iopages_ptr(&evq->hw.iobuff) + evq->hw.iobuff_off; ++ evq->evq_ptr = 0; ++ evq->evq_mask = (evq->hw.capacity * sizeof(efhw_event_t)) - 1u; ++ ++ EFHW_TRACE("%s: [%d] base=%p end=%p", __func__, evq->instance, ++ evq->evq_base, evq->evq_base + buf_bytes); ++ ++ return 0; ++} ++ ++void efhw_keventq_dtor(struct efhw_nic *nic, struct efhw_keventq *evq) ++{ ++ EFHW_ASSERT(evq); ++ ++ EFHW_TRACE("%s: [%d]", __func__, evq->instance); ++ ++ /* Zero the timer-value for this queue. ++ And Tell NIC to stop using this event queue. */ ++ efhw_nic_event_queue_disable(nic, evq->instance, 0); ++ ++ /* free the pages used by the eventq itself */ ++ efhw_iopages_free(nic, &evq->hw.iobuff); ++} ++ ++void ++efhw_handle_txdmaq_flushed(struct efhw_nic *nic, struct efhw_ev_handler *h, ++ efhw_event_t *evp) ++{ ++ int instance = (int)FALCON_EVENT_TX_FLUSH_Q_ID(evp); ++ EFHW_TRACE("%s: instance=%d", __func__, instance); ++ ++ if (!h->dmaq_flushed_fn) { ++ EFHW_WARN("%s: no handler registered", __func__); ++ return; ++ } ++ ++ h->dmaq_flushed_fn(nic, instance, false); ++} ++ ++void ++efhw_handle_rxdmaq_flushed(struct efhw_nic *nic, struct efhw_ev_handler *h, ++ efhw_event_t *evp) ++{ ++ unsigned instance = (unsigned)FALCON_EVENT_RX_FLUSH_Q_ID(evp); ++ EFHW_TRACE("%s: instance=%d", __func__, instance); ++ ++ if (!h->dmaq_flushed_fn) { ++ EFHW_WARN("%s: no handler registered", __func__); ++ return; ++ } ++ ++ h->dmaq_flushed_fn(nic, instance, true); ++} ++ ++void ++efhw_handle_wakeup_event(struct efhw_nic *nic, struct efhw_ev_handler *h, ++ efhw_event_t *evp) ++{ ++ unsigned instance = (unsigned)FALCON_EVENT_WAKE_EVQ_ID(evp); ++ ++ if (!h->wakeup_fn) { ++ EFHW_WARN("%s: no handler registered", __func__); ++ return; ++ } ++ ++ h->wakeup_fn(nic, instance); ++} ++ ++void ++efhw_handle_timeout_event(struct efhw_nic *nic, struct efhw_ev_handler *h, ++ efhw_event_t *evp) ++{ ++ unsigned instance = (unsigned)FALCON_EVENT_WAKE_EVQ_ID(evp); ++ ++ if (!h->timeout_fn) { ++ EFHW_WARN("%s: no handler registered", __func__); ++ return; ++ } ++ ++ h->timeout_fn(nic, instance); ++} ++ ++/********************************************************************** ++ * Kernel event queue event handling. ++ */ ++ ++int efhw_keventq_poll(struct efhw_nic *nic, struct efhw_keventq *q) ++{ ++ efhw_event_t *ev; ++ int l, count = 0; ++ ++ EFHW_ASSERT(nic); ++ EFHW_ASSERT(q); ++ EFHW_ASSERT(q->ev_handlers); ++ ++ /* Acquire the lock, or mark the queue as needing re-checking. */ ++ for (;;) { ++ l = q->lock; ++ if (l == KEVQ_UNLOCKED) { ++ if ((int)cmpxchg(&q->lock, l, KEVQ_LOCKED) == l) ++ break; ++ } else if (l == KEVQ_LOCKED) { ++ if ((int)cmpxchg(&q->lock, l, KEVQ_RECHECK) == l) ++ return 0; ++ } else { /* already marked for re-checking */ ++ EFHW_ASSERT(l == KEVQ_RECHECK); ++ return 0; ++ } ++ } ++ ++ if (unlikely(EFHW_EVENT_OVERFLOW(q, q))) ++ goto overflow; ++ ++ ev = EFHW_EVENT_PTR(q, q, 0); ++ ++#ifndef NDEBUG ++ if (!EFHW_IS_EVENT(ev)) ++ EFHW_TRACE("%s: %d NO EVENTS!", __func__, q->instance); ++#endif ++ ++ for (;;) { ++ /* Convention for return codes for handlers is: ++ ** 0 - no error, event consumed ++ ** 1 - no error, event not consumed ++ ** -ve - error, event not consumed ++ */ ++ if (likely(EFHW_IS_EVENT(ev))) { ++ count++; ++ ++ switch (FALCON_EVENT_CODE(ev)) { ++ ++ case FALCON_EVENT_CODE_CHAR: ++ falcon_handle_char_event(nic, q->ev_handlers, ++ ev); ++ break; ++ ++ default: ++ EFHW_ERR("efhw_keventq_poll: [%d] UNEXPECTED " ++ "EVENT:"FALCON_EVENT_FMT, ++ q->instance, ++ FALCON_EVENT_PRI_ARG(*ev)); ++ } ++ ++ EFHW_CLEAR_EVENT(ev); ++ EFHW_EVENTQ_NEXT(q); ++ ++ ev = EFHW_EVENT_PTR(q, q, 0); ++ } else { ++ /* No events left. Release the lock (checking if we ++ * need to re-poll to avoid race). */ ++ l = q->lock; ++ if (l == KEVQ_LOCKED) { ++ if ((int)cmpxchg(&q->lock, l, KEVQ_UNLOCKED) ++ == l) { ++ EFHW_TRACE ++ ("efhw_keventq_poll: %d clean exit", ++ q->instance); ++ goto clean_exit; ++ } ++ } ++ ++ /* Potentially more work to do. */ ++ l = q->lock; ++ EFHW_ASSERT(l == KEVQ_RECHECK); ++ EFHW_TEST((int)cmpxchg(&q->lock, l, KEVQ_LOCKED) == l); ++ EFHW_TRACE("efhw_keventq_poll: %d re-poll required", ++ q->instance); ++ } ++ } ++ ++ /* shouldn't get here */ ++ EFHW_ASSERT(0); ++ ++overflow: ++ /* ?? Oh dear. Should we poll everything that could have possibly ++ ** happened? Or merely cry out in anguish... ++ */ ++ EFHW_WARN("efhw_keventq_poll: %d ***** OVERFLOW nic %d *****", ++ q->instance, nic->index); ++ ++ q->lock = KEVQ_UNLOCKED; ++ return count; ++ ++clean_exit: ++ /* Ack the processed events so that this event queue can potentially ++ raise interrupts again */ ++ falcon_nic_evq_ack(nic, q->instance, ++ (EFHW_EVENT_OFFSET(q, q, 0) / sizeof(efhw_event_t)), ++ false); ++ return count; ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/falcon.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/falcon.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,2525 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains Falcon hardware support. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Workarounds and options ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/* Keep a software copy of the filter table and check for duplicates. */ ++#define FALCON_FULL_FILTER_CACHE 1 ++ ++/* Read filters back from the hardware to detect corruption. */ ++#define FALCON_VERIFY_FILTERS 0 ++ ++/* Options */ ++#define RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL 8 /* default search limit */ ++#define RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD 8 /* default search limit */ ++#define RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL 8 /* default search limit */ ++#define RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD 8 /* default search limit */ ++ ++#define FALCON_MAC_SET_TYPE_BY_SPEED 0 ++ ++/* FIXME: We should detect mode at runtime. */ ++#define FALCON_BUFFER_TABLE_FULL_MODE 1 ++ ++/* "Fudge factors" - difference between programmed value and actual depth */ ++#define RX_FILTER_CTL_SRCH_FUDGE_WILD 3 /* increase the search limit */ ++#define RX_FILTER_CTL_SRCH_FUDGE_FULL 1 /* increase the search limit */ ++#define TX_FILTER_CTL_SRCH_FUDGE_WILD 3 /* increase the search limit */ ++#define TX_FILTER_CTL_SRCH_FUDGE_FULL 1 /* increase the search limit */ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Debug Macros ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#define _DEBUG_SYM_ static ++ ++ /*---------------------------------------------------------------------------- ++ * ++ * Macros and forward declarations ++ * ++ *--------------------------------------------------------------------------*/ ++ ++#define FALCON_REGION_NUM 4 /* number of supported memory regions */ ++ ++#define FALCON_BUFFER_TBL_HALF_BYTES 4 ++#define FALCON_BUFFER_TBL_FULL_BYTES 8 ++ ++/* Shadow buffer table - hack for testing only */ ++#if FALCON_BUFFER_TABLE_FULL_MODE == 0 ++# define FALCON_USE_SHADOW_BUFFER_TABLE 1 ++#else ++# define FALCON_USE_SHADOW_BUFFER_TABLE 0 ++#endif ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Header assertion checks ++ * ++ *---------------------------------------------------------------------------*/ ++ ++#define FALCON_ASSERT_VALID() /* nothing yet */ ++ ++/* Falcon has a 128bit register model but most registers have useful ++ defaults or only implement a small number of bits. Some registers ++ can be programmed 32bits UNLOCKED all others should be interlocked ++ against other threads within the same protection domain. ++ ++ Aim is for software to perform the minimum number of writes and ++ also to minimise the read-modify-write activity (which generally ++ indicates a lack of clarity in the use model). ++ ++ Registers which are programmed in this module are listed below ++ together with the method of access. Care must be taken to ensure ++ remain adequate if the register spec changes. ++ ++ All 128bits programmed ++ FALCON_BUFFER_TBL_HALF ++ RX_FILTER_TBL ++ TX_DESC_PTR_TBL ++ RX_DESC_PTR_TBL ++ DRV_EV_REG ++ ++ All 64bits programmed ++ FALCON_BUFFER_TBL_FULL ++ ++ 32 bits are programmed (UNLOCKED) ++ EVQ_RPTR_REG ++ ++ Low 64bits programmed remainder are written with a random number ++ RX_DC_CFG_REG ++ TX_DC_CFG_REG ++ SRM_RX_DC_CFG_REG ++ SRM_TX_DC_CFG_REG ++ BUF_TBL_CFG_REG ++ BUF_TBL_UPD_REG ++ SRM_UPD_EVQ_REG ++ EVQ_PTR_TBL ++ TIMER_CMD_REG ++ TX_PACE_TBL ++ FATAL_INTR_REG ++ INT_EN_REG (When enabling interrupts) ++ TX_FLUSH_DESCQ_REG ++ RX_FLUSH_DESCQ ++ ++ Read Modify Write on low 32bits remainder are written with a random number ++ INT_EN_REG (When sending a driver interrupt) ++ DRIVER_REGX ++ ++ Read Modify Write on low 64bits remainder are written with a random number ++ SRM_CFG_REG_OFST ++ RX_CFG_REG_OFST ++ RX_FILTER_CTL_REG ++ ++ Read Modify Write on full 128bits ++ TXDP_RESERVED_REG (aka TXDP_UNDOCUMENTED) ++ TX_CFG_REG ++ ++*/ ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * DMAQ low-level register interface ++ * ++ *---------------------------------------------------------------------------*/ ++ ++static unsigned dmaq_sizes[] = { ++ 512, ++ EFHW_1K, ++ EFHW_2K, ++ EFHW_4K, ++}; ++ ++#define N_DMAQ_SIZES (sizeof(dmaq_sizes) / sizeof(dmaq_sizes[0])) ++ ++static inline ulong falcon_dma_tx_q_offset(struct efhw_nic *nic, unsigned dmaq) ++{ ++ EFHW_ASSERT(dmaq < nic->num_dmaqs); ++ return TX_DESC_PTR_TBL_OFST + dmaq * FALCON_REGISTER128; ++} ++ ++static inline uint falcon_dma_tx_q_size_index(uint dmaq_size) ++{ ++ uint i; ++ ++ /* size must be one of the various options, otherwise we assert */ ++ for (i = 0; i < N_DMAQ_SIZES; i++) { ++ if (dmaq_size == dmaq_sizes[i]) ++ break; ++ } ++ EFHW_ASSERT(i < N_DMAQ_SIZES); ++ return i; ++} ++ ++static void ++falcon_dmaq_tx_q_init(struct efhw_nic *nic, ++ uint dmaq, uint evq_id, uint own_id, ++ uint tag, uint dmaq_size, uint buf_idx, uint flags) ++{ ++ FALCON_LOCK_DECL; ++ uint index, desc_type; ++ uint64_t val1, val2, val3; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ /* Q attributes */ ++ int iscsi_hdig_en = ((flags & EFHW_VI_ISCSI_TX_HDIG_EN) != 0); ++ int iscsi_ddig_en = ((flags & EFHW_VI_ISCSI_TX_DDIG_EN) != 0); ++ int csum_ip_dis = ((flags & EFHW_VI_TX_IP_CSUM_DIS) != 0); ++ int csum_tcp_dis = ((flags & EFHW_VI_TX_TCPUDP_CSUM_DIS) != 0); ++ int non_ip_drop_dis = ((flags & EFHW_VI_TX_TCPUDP_ONLY) == 0); ++ ++ /* initialise the TX descriptor queue pointer table */ ++ ++ /* NB physical vs buffer addressing is determined by the Queue ID. */ ++ ++ offset = falcon_dma_tx_q_offset(nic, dmaq); ++ index = falcon_dma_tx_q_size_index(dmaq_size); ++ ++ /* allow VI flag to override this queue's descriptor type */ ++ desc_type = (flags & EFHW_VI_TX_PHYS_ADDR_EN) ? 0 : 1; ++ ++ /* bug9403: It is dangerous to allow buffer-addressed queues to ++ * have owner_id=0. */ ++ EFHW_ASSERT((own_id > 0) || desc_type == 0); ++ ++ /* dword 1 */ ++ __DWCHCK(TX_DESCQ_FLUSH_LBN, TX_DESCQ_FLUSH_WIDTH); ++ __DWCHCK(TX_DESCQ_TYPE_LBN, TX_DESCQ_TYPE_WIDTH); ++ __DWCHCK(TX_DESCQ_SIZE_LBN, TX_DESCQ_SIZE_WIDTH); ++ __DWCHCK(TX_DESCQ_LABEL_LBN, TX_DESCQ_LABEL_WIDTH); ++ __DWCHCK(TX_DESCQ_OWNER_ID_LBN, TX_DESCQ_OWNER_ID_WIDTH); ++ ++ __LWCHK(TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH); ++ ++ __RANGECHCK(1, TX_DESCQ_FLUSH_WIDTH); ++ __RANGECHCK(desc_type, TX_DESCQ_TYPE_WIDTH); ++ __RANGECHCK(index, TX_DESCQ_SIZE_WIDTH); ++ __RANGECHCK(tag, TX_DESCQ_LABEL_WIDTH); ++ __RANGECHCK(own_id, TX_DESCQ_OWNER_ID_WIDTH); ++ __RANGECHCK(evq_id, TX_DESCQ_EVQ_ID_WIDTH); ++ ++ val1 = ((desc_type << TX_DESCQ_TYPE_LBN) | ++ (index << TX_DESCQ_SIZE_LBN) | ++ (tag << TX_DESCQ_LABEL_LBN) | ++ (own_id << TX_DESCQ_OWNER_ID_LBN) | ++ (__LOW(evq_id, TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH))); ++ ++ /* dword 2 */ ++ __DW2CHCK(TX_DESCQ_BUF_BASE_ID_LBN, TX_DESCQ_BUF_BASE_ID_WIDTH); ++ __RANGECHCK(buf_idx, TX_DESCQ_BUF_BASE_ID_WIDTH); ++ ++ val2 = ((__HIGH(evq_id, TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH)) | ++ (buf_idx << __DW2(TX_DESCQ_BUF_BASE_ID_LBN))); ++ ++ /* dword 3 */ ++ __DW3CHCK(TX_ISCSI_HDIG_EN_LBN, TX_ISCSI_HDIG_EN_WIDTH); ++ __DW3CHCK(TX_ISCSI_DDIG_EN_LBN, TX_ISCSI_DDIG_EN_WIDTH); ++ __RANGECHCK(iscsi_hdig_en, TX_ISCSI_HDIG_EN_WIDTH); ++ __RANGECHCK(iscsi_ddig_en, TX_ISCSI_DDIG_EN_WIDTH); ++ ++ val3 = ((iscsi_hdig_en << __DW3(TX_ISCSI_HDIG_EN_LBN)) | ++ (iscsi_ddig_en << __DW3(TX_ISCSI_DDIG_EN_LBN)) | ++ (1 << __DW3(TX_DESCQ_EN_LBN))); /* queue enable bit */ ++ ++ switch (nic->devtype.variant) { ++ case 'B': ++ __DW3CHCK(TX_NON_IP_DROP_DIS_B0_LBN, ++ TX_NON_IP_DROP_DIS_B0_WIDTH); ++ __DW3CHCK(TX_IP_CHKSM_DIS_B0_LBN, TX_IP_CHKSM_DIS_B0_WIDTH); ++ __DW3CHCK(TX_TCP_CHKSM_DIS_B0_LBN, TX_TCP_CHKSM_DIS_B0_WIDTH); ++ ++ val3 |= ((non_ip_drop_dis << __DW3(TX_NON_IP_DROP_DIS_B0_LBN))| ++ (csum_ip_dis << __DW3(TX_IP_CHKSM_DIS_B0_LBN)) | ++ (csum_tcp_dis << __DW3(TX_TCP_CHKSM_DIS_B0_LBN))); ++ break; ++ case 'A': ++ if (csum_ip_dis || csum_tcp_dis || !non_ip_drop_dis) ++ EFHW_WARN ++ ("%s: bad settings for A1 csum_ip_dis=%d " ++ "csum_tcp_dis=%d non_ip_drop_dis=%d", ++ __func__, csum_ip_dis, ++ csum_tcp_dis, non_ip_drop_dis); ++ break; ++ default: ++ EFHW_ASSERT(0); ++ break; ++ } ++ ++ EFHW_TRACE("%s: txq %x evq %u tag %x id %x buf %x " ++ "%x:%x:%x->%" PRIx64 ":%" PRIx64 ":%" PRIx64, ++ __func__, ++ dmaq, evq_id, tag, own_id, buf_idx, dmaq_size, ++ iscsi_hdig_en, iscsi_ddig_en, val1, val2, val3); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return; ++} ++ ++static inline ulong ++falcon_dma_rx_q_offset(struct efhw_nic *nic, unsigned dmaq) ++{ ++ EFHW_ASSERT(dmaq < nic->num_dmaqs); ++ return RX_DESC_PTR_TBL_OFST + dmaq * FALCON_REGISTER128; ++} ++ ++static void ++falcon_dmaq_rx_q_init(struct efhw_nic *nic, ++ uint dmaq, uint evq_id, uint own_id, ++ uint tag, uint dmaq_size, uint buf_idx, uint flags) ++{ ++ FALCON_LOCK_DECL; ++ uint i, desc_type = 1; ++ uint64_t val1, val2, val3; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ /* Q attributes */ ++#if BUG5762_WORKAROUND ++ int jumbo = 1; /* Queues must not have mixed types */ ++#else ++ int jumbo = ((flags & EFHW_VI_JUMBO_EN) != 0); ++#endif ++ int iscsi_hdig_en = ((flags & EFHW_VI_ISCSI_RX_HDIG_EN) != 0); ++ int iscsi_ddig_en = ((flags & EFHW_VI_ISCSI_RX_DDIG_EN) != 0); ++ ++ /* initialise the TX descriptor queue pointer table */ ++ offset = falcon_dma_rx_q_offset(nic, dmaq); ++ ++ /* size must be one of the various options, otherwise we assert */ ++ for (i = 0; i < N_DMAQ_SIZES; i++) { ++ if (dmaq_size == dmaq_sizes[i]) ++ break; ++ } ++ EFHW_ASSERT(i < N_DMAQ_SIZES); ++ ++ /* allow VI flag to override this queue's descriptor type */ ++ desc_type = (flags & EFHW_VI_RX_PHYS_ADDR_EN) ? 0 : 1; ++ ++ /* bug9403: It is dangerous to allow buffer-addressed queues to have ++ * owner_id=0 */ ++ EFHW_ASSERT((own_id > 0) || desc_type == 0); ++ ++ /* dword 1 */ ++ __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH); ++ __DWCHCK(RX_DESCQ_JUMBO_LBN, RX_DESCQ_JUMBO_WIDTH); ++ __DWCHCK(RX_DESCQ_TYPE_LBN, RX_DESCQ_TYPE_WIDTH); ++ __DWCHCK(RX_DESCQ_SIZE_LBN, RX_DESCQ_SIZE_WIDTH); ++ __DWCHCK(RX_DESCQ_LABEL_LBN, RX_DESCQ_LABEL_WIDTH); ++ __DWCHCK(RX_DESCQ_OWNER_ID_LBN, RX_DESCQ_OWNER_ID_WIDTH); ++ ++ __LWCHK(RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH); ++ ++ __RANGECHCK(1, RX_DESCQ_EN_WIDTH); ++ __RANGECHCK(jumbo, RX_DESCQ_JUMBO_WIDTH); ++ __RANGECHCK(desc_type, RX_DESCQ_TYPE_WIDTH); ++ __RANGECHCK(i, RX_DESCQ_SIZE_WIDTH); ++ __RANGECHCK(tag, RX_DESCQ_LABEL_WIDTH); ++ __RANGECHCK(own_id, RX_DESCQ_OWNER_ID_WIDTH); ++ __RANGECHCK(evq_id, RX_DESCQ_EVQ_ID_WIDTH); ++ ++ val1 = ((1 << RX_DESCQ_EN_LBN) | ++ (jumbo << RX_DESCQ_JUMBO_LBN) | ++ (desc_type << RX_DESCQ_TYPE_LBN) | ++ (i << RX_DESCQ_SIZE_LBN) | ++ (tag << RX_DESCQ_LABEL_LBN) | ++ (own_id << RX_DESCQ_OWNER_ID_LBN) | ++ (__LOW(evq_id, RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH))); ++ ++ /* dword 2 */ ++ __DW2CHCK(RX_DESCQ_BUF_BASE_ID_LBN, RX_DESCQ_BUF_BASE_ID_WIDTH); ++ __RANGECHCK(buf_idx, RX_DESCQ_BUF_BASE_ID_WIDTH); ++ ++ val2 = ((__HIGH(evq_id, RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH)) | ++ (buf_idx << __DW2(RX_DESCQ_BUF_BASE_ID_LBN))); ++ ++ /* dword 3 */ ++ __DW3CHCK(RX_ISCSI_HDIG_EN_LBN, RX_ISCSI_HDIG_EN_WIDTH); ++ __DW3CHCK(RX_ISCSI_DDIG_EN_LBN, RX_ISCSI_DDIG_EN_WIDTH); ++ __RANGECHCK(iscsi_hdig_en, RX_ISCSI_HDIG_EN_WIDTH); ++ __RANGECHCK(iscsi_ddig_en, RX_ISCSI_DDIG_EN_WIDTH); ++ ++ val3 = (iscsi_hdig_en << __DW3(RX_ISCSI_HDIG_EN_LBN)) | ++ (iscsi_ddig_en << __DW3(RX_ISCSI_DDIG_EN_LBN)); ++ ++ EFHW_TRACE("%s: rxq %x evq %u tag %x id %x buf %x %s " ++ "%x:%x:%x -> %" PRIx64 ":%" PRIx64 ":%" PRIx64, ++ __func__, ++ dmaq, evq_id, tag, own_id, buf_idx, ++ jumbo ? "jumbo" : "normal", dmaq_size, ++ iscsi_hdig_en, iscsi_ddig_en, val1, val2, val3); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return; ++} ++ ++static void falcon_dmaq_tx_q_disable(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ uint64_t val1, val2, val3; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ /* initialise the TX descriptor queue pointer table */ ++ ++ offset = falcon_dma_tx_q_offset(nic, dmaq); ++ ++ /* dword 1 */ ++ __DWCHCK(TX_DESCQ_TYPE_LBN, TX_DESCQ_TYPE_WIDTH); ++ ++ val1 = ((uint64_t) 1 << TX_DESCQ_TYPE_LBN); ++ ++ /* dword 2 */ ++ val2 = 0; ++ ++ /* dword 3 */ ++ val3 = (0 << __DW3(TX_DESCQ_EN_LBN)); /* queue enable bit */ ++ ++ EFHW_TRACE("%s: %x->%" PRIx64 ":%" PRIx64 ":%" PRIx64, ++ __func__, dmaq, val1, val2, val3); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return; ++} ++ ++static void falcon_dmaq_rx_q_disable(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ uint64_t val1, val2, val3; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ /* initialise the TX descriptor queue pointer table */ ++ offset = falcon_dma_rx_q_offset(nic, dmaq); ++ ++ /* dword 1 */ ++ __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH); ++ __DWCHCK(RX_DESCQ_TYPE_LBN, RX_DESCQ_TYPE_WIDTH); ++ ++ val1 = ((0 << RX_DESCQ_EN_LBN) | (1 << RX_DESCQ_TYPE_LBN)); ++ ++ /* dword 2 */ ++ val2 = 0; ++ ++ /* dword 3 */ ++ val3 = 0; ++ ++ EFHW_TRACE("falcon_dmaq_rx_q_disable: %x->%" ++ PRIx64 ":%" PRIx64 ":%" PRIx64, ++ dmaq, val1, val2, val3); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return; ++} ++ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Buffer Table low-level register interface ++ * ++ *---------------------------------------------------------------------------*/ ++ ++/*! Convert a (potentially) 64-bit physical address to 32-bits. Every use ++** of this function is a place where we're not 64-bit clean. ++*/ ++static inline uint32_t dma_addr_to_u32(dma_addr_t addr) ++{ ++ /* Top bits had better be zero! */ ++ EFHW_ASSERT(addr == (addr & 0xffffffff)); ++ return (uint32_t) addr; ++} ++ ++static inline uint32_t ++falcon_nic_buffer_table_entry32_mk(dma_addr_t dma_addr, int own_id) ++{ ++ uint32_t dma_addr32 = FALCON_BUFFER_4K_PAGE(dma_addr_to_u32(dma_addr)); ++ ++ /* don't do this to me */ ++ EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_LBN == BUF_ADR_HBUF_EVEN_LBN + 32); ++ EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_LBN == ++ BUF_OWNER_ID_HBUF_EVEN_LBN + 32); ++ ++ EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_WIDTH == ++ BUF_OWNER_ID_HBUF_EVEN_WIDTH); ++ EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_WIDTH == BUF_ADR_HBUF_EVEN_WIDTH); ++ ++ __DWCHCK(BUF_ADR_HBUF_EVEN_LBN, BUF_ADR_HBUF_EVEN_WIDTH); ++ __DWCHCK(BUF_OWNER_ID_HBUF_EVEN_LBN, BUF_OWNER_ID_HBUF_EVEN_WIDTH); ++ ++ __RANGECHCK(dma_addr32, BUF_ADR_HBUF_EVEN_WIDTH); ++ __RANGECHCK(own_id, BUF_OWNER_ID_HBUF_EVEN_WIDTH); ++ ++ return (dma_addr32 << BUF_ADR_HBUF_EVEN_LBN) | ++ (own_id << BUF_OWNER_ID_HBUF_EVEN_LBN); ++} ++ ++static inline uint64_t ++falcon_nic_buffer_table_entry64_mk(dma_addr_t dma_addr, ++ int bufsz, /* bytes */ ++ int region, int own_id) ++{ ++ __DW2CHCK(IP_DAT_BUF_SIZE_LBN, IP_DAT_BUF_SIZE_WIDTH); ++ __DW2CHCK(BUF_ADR_REGION_LBN, BUF_ADR_REGION_WIDTH); ++ __LWCHK(BUF_ADR_FBUF_LBN, BUF_ADR_FBUF_WIDTH); ++ __DWCHCK(BUF_OWNER_ID_FBUF_LBN, BUF_OWNER_ID_FBUF_WIDTH); ++ ++ EFHW_ASSERT((bufsz == EFHW_4K) || (bufsz == EFHW_8K)); ++ ++ dma_addr = (dma_addr >> 12) & __FALCON_MASK64(BUF_ADR_FBUF_WIDTH); ++ ++ __RANGECHCK(dma_addr, BUF_ADR_FBUF_WIDTH); ++ __RANGECHCK(1, IP_DAT_BUF_SIZE_WIDTH); ++ __RANGECHCK(region, BUF_ADR_REGION_WIDTH); ++ __RANGECHCK(own_id, BUF_OWNER_ID_FBUF_WIDTH); ++ ++ return ((uint64_t) (bufsz == EFHW_8K) << IP_DAT_BUF_SIZE_LBN) | ++ ((uint64_t) region << BUF_ADR_REGION_LBN) | ++ ((uint64_t) dma_addr << BUF_ADR_FBUF_LBN) | ++ ((uint64_t) own_id << BUF_OWNER_ID_FBUF_LBN); ++} ++ ++static inline void ++_falcon_nic_buffer_table_set32(struct efhw_nic *nic, ++ dma_addr_t dma_addr, uint bufsz, ++ uint region, /* not used */ ++ int own_id, int buffer_id) ++{ ++ /* programming the half table needs to be done in pairs. */ ++ uint64_t entry, val, shift; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ volatile char __iomem *offset; ++ ++ EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_LBN == BUF_ADR_HBUF_EVEN_LBN + 32); ++ EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_LBN == ++ BUF_OWNER_ID_HBUF_EVEN_LBN + 32); ++ ++ shift = (buffer_id & 1) ? 32 : 0; ++ ++ offset = (efhw_kva + BUF_HALF_TBL_OFST + ++ ((buffer_id & ~1) * FALCON_BUFFER_TBL_HALF_BYTES)); ++ ++ entry = falcon_nic_buffer_table_entry32_mk(dma_addr_to_u32(dma_addr), ++ own_id); ++ ++#if FALCON_USE_SHADOW_BUFFER_TABLE ++ val = _falcon_buffer_table[buffer_id & ~1]; ++#else ++ /* This will not work unless we've completed ++ * the buffer table updates */ ++ falcon_read_q(offset, &val); ++#endif ++ val &= ~(((uint64_t) 0xffffffff) << shift); ++ val |= (entry << shift); ++ ++ EFHW_TRACE("%s[%x]: %lx:%x:%" PRIx64 "->%x = %" ++ PRIx64, __func__, buffer_id, (unsigned long) dma_addr, ++ own_id, entry, (unsigned)(offset - efhw_kva), val); ++ ++ /* Falcon requires that access to this register is serialised */ ++ falcon_write_q(offset, val); ++ ++ /* NB. No mmiowb(). Caller should do that e.g by calling commit */ ++ ++#if FALCON_USE_SHADOW_BUFFER_TABLE ++ _falcon_buffer_table[buffer_id & ~1] = val; ++#endif ++ ++ /* Confirm the entry if the event queues haven't been set up. */ ++ if (!nic->irq_handler) { ++ uint64_t new_val; ++ int count = 0; ++ while (1) { ++ mmiowb(); ++ falcon_read_q(offset, &new_val); ++ if (new_val == val) ++ break; ++ count++; ++ if (count > 1000) { ++ EFHW_WARN("%s: poll Timeout", __func__); ++ break; ++ } ++ udelay(1); ++ } ++ } ++} ++ ++static inline void ++_falcon_nic_buffer_table_set64(struct efhw_nic *nic, ++ dma_addr_t dma_addr, uint bufsz, ++ uint region, int own_id, int buffer_id) ++{ ++ volatile char __iomem *offset; ++ uint64_t entry; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ EFHW_ASSERT(region < FALCON_REGION_NUM); ++ ++ EFHW_ASSERT((bufsz == EFHW_4K) || ++ (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE)); ++ ++ offset = (efhw_kva + BUF_FULL_TBL_OFST + ++ (buffer_id * FALCON_BUFFER_TBL_FULL_BYTES)); ++ ++ entry = falcon_nic_buffer_table_entry64_mk(dma_addr, bufsz, region, ++ own_id); ++ ++ EFHW_TRACE("%s[%x]: %lx:bufsz=%x:region=%x:ownid=%x", ++ __func__, buffer_id, (unsigned long) dma_addr, bufsz, ++ region, own_id); ++ ++ EFHW_TRACE("%s: BUF[%x]:NIC[%x]->%" PRIx64, ++ __func__, buffer_id, ++ (unsigned int)(offset - efhw_kva), entry); ++ ++ /* Falcon requires that access to this register is serialised */ ++ falcon_write_q(offset, entry); ++ ++ /* NB. No mmiowb(). Caller should do that e.g by calling commit */ ++ ++ /* Confirm the entry if the event queues haven't been set up. */ ++ if (!nic->irq_handler) { ++ uint64_t new_entry; ++ int count = 0; ++ while (1) { ++ mmiowb(); ++ falcon_read_q(offset, &new_entry); ++ if (new_entry == entry) ++ return; ++ count++; ++ if (count > 1000) { ++ EFHW_WARN("%s: poll Timeout waiting for " ++ "value %"PRIx64 ++ " (last was %"PRIx64")", ++ __func__, entry, new_entry); ++ break; ++ } ++ udelay(1); ++ } ++ } ++} ++ ++#if FALCON_BUFFER_TABLE_FULL_MODE ++#define _falcon_nic_buffer_table_set _falcon_nic_buffer_table_set64 ++#else ++#define _falcon_nic_buffer_table_set _falcon_nic_buffer_table_set32 ++#endif ++ ++static inline void _falcon_nic_buffer_table_commit(struct efhw_nic *nic) ++{ ++ /* MUST be called holding the FALCON_LOCK */ ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ uint64_t cmd; ++ ++ EFHW_BUILD_ASSERT(BUF_TBL_UPD_REG_KER_OFST == BUF_TBL_UPD_REG_OFST); ++ ++ __DW2CHCK(BUF_UPD_CMD_LBN, BUF_UPD_CMD_WIDTH); ++ __RANGECHCK(1, BUF_UPD_CMD_WIDTH); ++ ++ cmd = ((uint64_t) 1 << BUF_UPD_CMD_LBN); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ falcon_write_qq(efhw_kva + BUF_TBL_UPD_REG_OFST, ++ cmd, FALCON_ATOMIC_UPD_REG); ++ mmiowb(); ++ ++ nic->buf_commit_outstanding++; ++ EFHW_TRACE("COMMIT REQ out=%d", nic->buf_commit_outstanding); ++} ++ ++static void falcon_nic_buffer_table_commit(struct efhw_nic *nic) ++{ ++ /* nothing to do */ ++} ++ ++static inline void ++_falcon_nic_buffer_table_clear(struct efhw_nic *nic, int buffer_id, int num) ++{ ++ uint64_t cmd; ++ uint64_t start_id = buffer_id; ++ uint64_t end_id = buffer_id + num - 1; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ volatile char __iomem *offset = (efhw_kva + BUF_TBL_UPD_REG_OFST); ++ ++ EFHW_BUILD_ASSERT(BUF_TBL_UPD_REG_KER_OFST == BUF_TBL_UPD_REG_OFST); ++ ++#if !FALCON_BUFFER_TABLE_FULL_MODE ++ /* buffer_ids in half buffer mode reference pairs of buffers */ ++ EFHW_ASSERT(buffer_id % 1 == 0); ++ EFHW_ASSERT(num % 1 == 0); ++ start_id = start_id >> 1; ++ end_id = end_id >> 1; ++#endif ++ ++ EFHW_ASSERT(num >= 1); ++ ++ __DWCHCK(BUF_CLR_START_ID_LBN, BUF_CLR_START_ID_WIDTH); ++ __DW2CHCK(BUF_CLR_END_ID_LBN, BUF_CLR_END_ID_WIDTH); ++ ++ __DW2CHCK(BUF_CLR_CMD_LBN, BUF_CLR_CMD_WIDTH); ++ __RANGECHCK(1, BUF_CLR_CMD_WIDTH); ++ ++ __RANGECHCK(start_id, BUF_CLR_START_ID_WIDTH); ++ __RANGECHCK(end_id, BUF_CLR_END_ID_WIDTH); ++ ++ cmd = (((uint64_t) 1 << BUF_CLR_CMD_LBN) | ++ (start_id << BUF_CLR_START_ID_LBN) | ++ (end_id << BUF_CLR_END_ID_LBN)); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ falcon_write_qq(offset, cmd, FALCON_ATOMIC_UPD_REG); ++ mmiowb(); ++ ++ nic->buf_commit_outstanding++; ++ EFHW_TRACE("COMMIT CLEAR out=%d", nic->buf_commit_outstanding); ++} ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Events low-level register interface ++ * ++ *---------------------------------------------------------------------------*/ ++ ++static unsigned eventq_sizes[] = { ++ 512, ++ EFHW_1K, ++ EFHW_2K, ++ EFHW_4K, ++ EFHW_8K, ++ EFHW_16K, ++ EFHW_32K ++}; ++ ++#define N_EVENTQ_SIZES (sizeof(eventq_sizes) / sizeof(eventq_sizes[0])) ++ ++static inline void falcon_nic_srm_upd_evq(struct efhw_nic *nic, int evq) ++{ ++ /* set up the eventq which will receive events from the SRAM module. ++ * i.e buffer table updates and clears, TX and RX aperture table ++ * updates */ ++ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ EFHW_BUILD_ASSERT(SRM_UPD_EVQ_REG_OFST == SRM_UPD_EVQ_REG_KER_OFST); ++ ++ __DWCHCK(SRM_UPD_EVQ_ID_LBN, SRM_UPD_EVQ_ID_WIDTH); ++ __RANGECHCK(evq, SRM_UPD_EVQ_ID_WIDTH); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + SRM_UPD_EVQ_REG_OFST, ++ ((uint64_t) evq << SRM_UPD_EVQ_ID_LBN), ++ FALCON_ATOMIC_SRPM_UDP_EVQ_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++static void ++falcon_nic_evq_ptr_tbl(struct efhw_nic *nic, ++ uint evq, /* evq id */ ++ uint enable, /* 1 to enable, 0 to disable */ ++ uint buf_base_id,/* Buffer table base for EVQ */ ++ uint evq_size /* Number of events */) ++{ ++ FALCON_LOCK_DECL; ++ uint i, val; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ /* size must be one of the various options, otherwise we assert */ ++ for (i = 0; i < N_EVENTQ_SIZES; i++) { ++ if (evq_size <= eventq_sizes[i]) ++ break; ++ } ++ EFHW_ASSERT(i < N_EVENTQ_SIZES); ++ ++ __DWCHCK(EVQ_BUF_BASE_ID_LBN, EVQ_BUF_BASE_ID_WIDTH); ++ __DWCHCK(EVQ_SIZE_LBN, EVQ_SIZE_WIDTH); ++ __DWCHCK(EVQ_EN_LBN, EVQ_EN_WIDTH); ++ ++ __RANGECHCK(i, EVQ_SIZE_WIDTH); ++ __RANGECHCK(buf_base_id, EVQ_BUF_BASE_ID_WIDTH); ++ __RANGECHCK(1, EVQ_EN_WIDTH); ++ ++ /* if !enable then only evq needs to be correct, although valid ++ * values need to be passed in for other arguments to prevent ++ * assertions */ ++ ++ val = ((i << EVQ_SIZE_LBN) | (buf_base_id << EVQ_BUF_BASE_ID_LBN) | ++ (enable ? (1 << EVQ_EN_LBN) : 0)); ++ ++ EFHW_ASSERT(evq < nic->num_evqs); ++ ++ offset = EVQ_PTR_TBL_CHAR_OFST; ++ offset += evq * FALCON_REGISTER128; ++ ++ EFHW_TRACE("%s: evq %u en=%x:buf=%x:size=%x->%x at %lx", ++ __func__, evq, enable, buf_base_id, evq_size, val, ++ offset); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, val, FALCON_ATOMIC_PTR_TBL_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ /* caller must wait for an update done event before writing any more ++ table entries */ ++ ++ return; ++} ++ ++void ++falcon_nic_evq_ack(struct efhw_nic *nic, ++ uint evq, /* evq id */ ++ uint rptr, /* new read pointer update */ ++ bool wakeup /* request a wakeup event if ptr's != */ ++ ) ++{ ++ uint val; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ EFHW_BUILD_ASSERT(FALCON_EVQ_CHAR == 4); ++ ++ __DWCHCK(EVQ_RPTR_LBN, EVQ_RPTR_WIDTH); ++ __RANGECHCK(rptr, EVQ_RPTR_WIDTH); ++ ++ val = (rptr << EVQ_RPTR_LBN); ++ ++ EFHW_ASSERT(evq < nic->num_evqs); ++ ++ if (evq < FALCON_EVQ_CHAR) { ++ offset = EVQ_RPTR_REG_KER_OFST; ++ offset += evq * FALCON_REGISTER128; ++ ++ EFHW_ASSERT(!wakeup); /* don't try this at home */ ++ } else { ++ offset = EVQ_RPTR_REG_OFST + (FALCON_EVQ_CHAR * ++ FALCON_REGISTER128); ++ offset += (evq - FALCON_EVQ_CHAR) * FALCON_REGISTER128; ++ ++ /* nothing to do for interruptless event queues which do ++ * not want a wakeup */ ++ if (evq != FALCON_EVQ_CHAR && !wakeup) ++ return; ++ } ++ ++ EFHW_TRACE("%s: %x %x %x->%x", __func__, evq, rptr, wakeup, val); ++ ++ writel(val, efhw_kva + offset); ++ mmiowb(); ++} ++ ++/*---------------------------------------------------------------------------*/ ++ ++static inline void ++falcon_drv_ev(struct efhw_nic *nic, uint64_t data, uint qid) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ /* send an event from one driver to the other */ ++ EFHW_BUILD_ASSERT(DRV_EV_REG_KER_OFST == DRV_EV_REG_OFST); ++ EFHW_BUILD_ASSERT(DRV_EV_DATA_LBN == 0); ++ EFHW_BUILD_ASSERT(DRV_EV_DATA_WIDTH == 64); ++ EFHW_BUILD_ASSERT(DRV_EV_QID_LBN == 64); ++ EFHW_BUILD_ASSERT(DRV_EV_QID_WIDTH == 12); ++ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + DRV_EV_REG_OFST, data, qid); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++_DEBUG_SYM_ void ++falcon_ab_timer_tbl_set(struct efhw_nic *nic, ++ uint evq, /* timer id */ ++ uint mode, /* mode bits */ ++ uint countdown /* counting value to set */) ++{ ++ FALCON_LOCK_DECL; ++ uint val; ++ ulong offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ EFHW_BUILD_ASSERT(TIMER_VAL_LBN == 0); ++ ++ __DWCHCK(TIMER_MODE_LBN, TIMER_MODE_WIDTH); ++ __DWCHCK(TIMER_VAL_LBN, TIMER_VAL_WIDTH); ++ ++ __RANGECHCK(mode, TIMER_MODE_WIDTH); ++ __RANGECHCK(countdown, TIMER_VAL_WIDTH); ++ ++ val = ((mode << TIMER_MODE_LBN) | (countdown << TIMER_VAL_LBN)); ++ ++ if (evq < FALCON_EVQ_CHAR) { ++ offset = TIMER_CMD_REG_KER_OFST; ++ offset += evq * EFHW_8K; /* PAGE mapped register */ ++ } else { ++ offset = TIMER_TBL_OFST; ++ offset += evq * FALCON_REGISTER128; ++ } ++ EFHW_ASSERT(evq < nic->num_evqs); ++ ++ EFHW_TRACE("%s: evq %u mode %x (%s) time %x -> %08x", ++ __func__, evq, mode, ++ mode == 0 ? "DISABLE" : ++ mode == 1 ? "IMMED" : ++ mode == 2 ? (evq < 5 ? "HOLDOFF" : "RX_TRIG") : ++ "", countdown, val); ++ ++ /* Falcon requires 128 bit atomic access for this register when ++ * accessed from the driver. User access to timers is paged mapped ++ */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, val, FALCON_ATOMIC_TIMER_CMD_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return; ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * Rate pacing - Low level interface ++ * ++ *--------------------------------------------------------------------*/ ++void falcon_nic_pace(struct efhw_nic *nic, uint dmaq, uint pace) ++{ ++ /* Pace specified in 2^(units of microseconds). This is the minimum ++ additional delay imposed over and above the IPG. ++ ++ Pacing only available on the virtual interfaces ++ */ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ulong offset; ++ ++ if (pace > 20) ++ pace = 20; /* maxm supported value */ ++ ++ __DWCHCK(TX_PACE_LBN, TX_PACE_WIDTH); ++ __RANGECHCK(pace, TX_PACE_WIDTH); ++ ++ switch (nic->devtype.variant) { ++ case 'A': ++ EFHW_ASSERT(dmaq >= TX_PACE_TBL_FIRST_QUEUE_A1); ++ offset = TX_PACE_TBL_A1_OFST; ++ offset += (dmaq - TX_PACE_TBL_FIRST_QUEUE_A1) * 16; ++ break; ++ case 'B': ++ /* Would be nice to assert this, but as dmaq is unsigned and ++ * TX_PACE_TBL_FIRST_QUEUE_B0 is 0, it makes no sense ++ * EFHW_ASSERT(dmaq >= TX_PACE_TBL_FIRST_QUEUE_B0); ++ */ ++ offset = TX_PACE_TBL_B0_OFST; ++ offset += (dmaq - TX_PACE_TBL_FIRST_QUEUE_B0) * 16; ++ break; ++ default: ++ EFHW_ASSERT(0); ++ offset = 0; ++ break; ++ } ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, pace, FALCON_ATOMIC_PACE_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ EFHW_TRACE("%s: txq %d offset=%lx pace=2^%x", ++ __func__, dmaq, offset, pace); ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Interrupt - Low level interface ++ * ++ *--------------------------------------------------------------------*/ ++ ++static void falcon_nic_handle_fatal_int(struct efhw_nic *nic) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ uint64_t val; ++ ++ offset = (efhw_kva + FATAL_INTR_REG_OFST); ++ ++ /* Falcon requires 32 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ val = readl(offset); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ /* ?? BUG3249 - need to disable illegal address interrupt */ ++ /* ?? BUG3114 - need to backport interrupt storm protection code */ ++ EFHW_ERR("fatal interrupt: %s%s%s%s%s%s%s%s%s%s%s%s[%" PRIx64 "]", ++ val & (1 << PCI_BUSERR_INT_CHAR_LBN) ? "PCI-bus-error " : "", ++ val & (1 << SRAM_OOB_INT_CHAR_LBN) ? "SRAM-oob " : "", ++ val & (1 << BUFID_OOB_INT_CHAR_LBN) ? "bufid-oob " : "", ++ val & (1 << MEM_PERR_INT_CHAR_LBN) ? "int-parity " : "", ++ val & (1 << RBUF_OWN_INT_CHAR_LBN) ? "rx-bufid-own " : "", ++ val & (1 << TBUF_OWN_INT_CHAR_LBN) ? "tx-bufid-own " : "", ++ val & (1 << RDESCQ_OWN_INT_CHAR_LBN) ? "rx-desc-own " : "", ++ val & (1 << TDESCQ_OWN_INT_CHAR_LBN) ? "tx-desc-own " : "", ++ val & (1 << EVQ_OWN_INT_CHAR_LBN) ? "evq-own " : "", ++ val & (1 << EVFF_OFLO_INT_CHAR_LBN) ? "evq-fifo " : "", ++ val & (1 << ILL_ADR_INT_CHAR_LBN) ? "ill-addr " : "", ++ val & (1 << SRM_PERR_INT_CHAR_LBN) ? "sram-parity " : "", val); ++} ++ ++static void falcon_nic_interrupt_hw_enable(struct efhw_nic *nic) ++{ ++ FALCON_LOCK_DECL; ++ uint val; ++ volatile char __iomem *offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ EFHW_BUILD_ASSERT(DRV_INT_EN_CHAR_WIDTH == 1); ++ ++ if (nic->flags & NIC_FLAG_NO_INTERRUPT) ++ return; ++ ++ offset = (efhw_kva + INT_EN_REG_CHAR_OFST); ++ val = 1 << DRV_INT_EN_CHAR_LBN; ++ ++ EFHW_NOTICE("%s: %x -> %x", __func__, (int)(offset - efhw_kva), ++ val); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(offset, val, FALCON_ATOMIC_INT_EN_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++static void falcon_nic_interrupt_hw_disable(struct efhw_nic *nic) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ EFHW_BUILD_ASSERT(SRAM_PERR_INT_KER_WIDTH == 1); ++ EFHW_BUILD_ASSERT(DRV_INT_EN_KER_LBN == 0); ++ EFHW_BUILD_ASSERT(SRAM_PERR_INT_CHAR_WIDTH == 1); ++ EFHW_BUILD_ASSERT(DRV_INT_EN_CHAR_LBN == 0); ++ EFHW_BUILD_ASSERT(SRAM_PERR_INT_KER_LBN == SRAM_PERR_INT_CHAR_LBN); ++ EFHW_BUILD_ASSERT(DRV_INT_EN_KER_LBN == DRV_INT_EN_CHAR_LBN); ++ ++ if (nic->flags & NIC_FLAG_NO_INTERRUPT) ++ return; ++ ++ offset = (efhw_kva + INT_EN_REG_CHAR_OFST); ++ ++ EFHW_NOTICE("%s: %x -> 0", __func__, (int)(offset - efhw_kva)); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(offset, 0, FALCON_ATOMIC_INT_EN_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++static void falcon_nic_irq_addr_set(struct efhw_nic *nic, dma_addr_t dma_addr) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *offset; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ++ offset = (efhw_kva + INT_ADR_REG_CHAR_OFST); ++ ++ EFHW_NOTICE("%s: %x -> " DMA_ADDR_T_FMT, __func__, ++ (int)(offset - efhw_kva), dma_addr); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(offset, dma_addr, FALCON_ATOMIC_INT_ADR_REG); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * RXDP - low level interface ++ * ++ *--------------------------------------------------------------------*/ ++ ++void ++falcon_nic_set_rx_usr_buf_size(struct efhw_nic *nic, int usr_buf_bytes) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ uint64_t val, val2, usr_buf_size = usr_buf_bytes / 32; ++ int rubs_lbn, rubs_width, roec_lbn; ++ ++ EFHW_BUILD_ASSERT(RX_CFG_REG_OFST == RX_CFG_REG_KER_OFST); ++ ++ switch (nic->devtype.variant) { ++ default: ++ EFHW_ASSERT(0); ++ /* Fall-through to avoid compiler warnings. */ ++ case 'A': ++ rubs_lbn = RX_USR_BUF_SIZE_A1_LBN; ++ rubs_width = RX_USR_BUF_SIZE_A1_WIDTH; ++ roec_lbn = RX_OWNERR_CTL_A1_LBN; ++ break; ++ case 'B': ++ rubs_lbn = RX_USR_BUF_SIZE_B0_LBN; ++ rubs_width = RX_USR_BUF_SIZE_B0_WIDTH; ++ roec_lbn = RX_OWNERR_CTL_B0_LBN; ++ break; ++ } ++ ++ __DWCHCK(rubs_lbn, rubs_width); ++ __QWCHCK(roec_lbn, 1); ++ __RANGECHCK(usr_buf_size, rubs_width); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + RX_CFG_REG_OFST, &val, &val2); ++ ++ val &= ~((__FALCON_MASK64(rubs_width)) << rubs_lbn); ++ val |= (usr_buf_size << rubs_lbn); ++ ++ /* shouldn't be needed for a production driver */ ++ val |= ((uint64_t) 1 << roec_lbn); ++ ++ falcon_write_qq(efhw_kva + RX_CFG_REG_OFST, val, val2); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++EXPORT_SYMBOL(falcon_nic_set_rx_usr_buf_size); ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * TXDP - low level interface ++ * ++ *--------------------------------------------------------------------*/ ++ ++_DEBUG_SYM_ void falcon_nic_tx_cfg(struct efhw_nic *nic, int unlocked) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ uint64_t val1, val2; ++ ++ EFHW_BUILD_ASSERT(TX_CFG_REG_OFST == TX_CFG_REG_KER_OFST); ++ __DWCHCK(TX_OWNERR_CTL_LBN, TX_OWNERR_CTL_WIDTH); ++ __DWCHCK(TX_NON_IP_DROP_DIS_LBN, TX_NON_IP_DROP_DIS_WIDTH); ++ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + TX_CFG_REG_OFST, &val1, &val2); ++ ++ /* Will flag fatal interrupts on owner id errors. This should not be ++ on for production code because there is otherwise a denial of ++ serivce attack possible */ ++ val1 |= (1 << TX_OWNERR_CTL_LBN); ++ ++ /* Setup user queue TCP/UDP only packet security */ ++ if (unlocked) ++ val1 |= (1 << TX_NON_IP_DROP_DIS_LBN); ++ else ++ val1 &= ~(1 << TX_NON_IP_DROP_DIS_LBN); ++ ++ falcon_write_qq(efhw_kva + TX_CFG_REG_OFST, val1, val2); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Random thresholds - Low level interface (Would like these to be op ++ * defaults wherever possible) ++ * ++ *--------------------------------------------------------------------*/ ++ ++void falcon_nic_pace_cfg(struct efhw_nic *nic, int fb_base, int bin_thresh) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ unsigned offset = 0; ++ uint64_t val; ++ ++ __DWCHCK(TX_PACE_FB_BASE_LBN, TX_PACE_FB_BASE_WIDTH); ++ __DWCHCK(TX_PACE_BIN_TH_LBN, TX_PACE_BIN_TH_WIDTH); ++ ++ switch (nic->devtype.variant) { ++ case 'A': offset = TX_PACE_REG_A1_OFST; break; ++ case 'B': offset = TX_PACE_REG_B0_OFST; break; ++ default: EFHW_ASSERT(0); break; ++ } ++ ++ val = (0x15 << TX_PACE_SB_NOTAF_LBN); ++ val |= (0xb << TX_PACE_SB_AF_LBN); ++ ++ val |= ((fb_base & __FALCON_MASK64(TX_PACE_FB_BASE_WIDTH)) << ++ TX_PACE_FB_BASE_LBN); ++ val |= ((bin_thresh & __FALCON_MASK64(TX_PACE_BIN_TH_WIDTH)) << ++ TX_PACE_BIN_TH_LBN); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + offset, val, 0); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++ ++/********************************************************************** ++ * Implementation of the HAL. ******************************************** ++ **********************************************************************/ ++ ++/*---------------------------------------------------------------------------- ++ * ++ * Initialisation and configuration discovery ++ * ++ *---------------------------------------------------------------------------*/ ++ ++static int falcon_nic_init_irq_channel(struct efhw_nic *nic, int enable) ++{ ++ /* create a buffer for the irq channel */ ++ int rc; ++ ++ if (enable) { ++ rc = efhw_iopage_alloc(nic, &nic->irq_iobuff); ++ if (rc < 0) ++ return rc; ++ ++ falcon_nic_irq_addr_set(nic, ++ efhw_iopage_dma_addr(&nic->irq_iobuff)); ++ } else { ++ if (efhw_iopage_is_valid(&nic->irq_iobuff)) ++ efhw_iopage_free(nic, &nic->irq_iobuff); ++ ++ efhw_iopage_mark_invalid(&nic->irq_iobuff); ++ falcon_nic_irq_addr_set(nic, 0); ++ } ++ ++ EFHW_TRACE("%s: %lx %sable", __func__, ++ (unsigned long) efhw_iopage_dma_addr(&nic->irq_iobuff), ++ enable ? "en" : "dis"); ++ ++ return 0; ++} ++ ++static void falcon_nic_close_hardware(struct efhw_nic *nic) ++{ ++ /* check we are in possession of some hardware */ ++ if (!efhw_nic_have_hw(nic)) ++ return; ++ ++ falcon_nic_init_irq_channel(nic, 0); ++ falcon_nic_filter_dtor(nic); ++ ++ EFHW_NOTICE("%s:", __func__); ++} ++ ++static int ++falcon_nic_init_hardware(struct efhw_nic *nic, ++ struct efhw_ev_handler *ev_handlers, ++ const uint8_t *mac_addr, int non_irq_evq) ++{ ++ int rc; ++ ++ /* header sanity checks */ ++ FALCON_ASSERT_VALID(); ++ ++ /* Initialise supporting modules */ ++ rc = falcon_nic_filter_ctor(nic); ++ if (rc < 0) ++ return rc; ++ ++#if FALCON_USE_SHADOW_BUFFER_TABLE ++ CI_ZERO_ARRAY(_falcon_buffer_table, FALCON_BUFFER_TBL_NUM); ++#endif ++ ++ /* Initialise the top level hardware blocks */ ++ memcpy(nic->mac_addr, mac_addr, ETH_ALEN); ++ ++ EFHW_TRACE("%s:", __func__); ++ ++ /* nic.c:efhw_nic_init marks all the interrupt units as unused. ++ ++ ?? TODO we should be able to request the non-interrupting event ++ queue and the net driver's (for a net driver that is using libefhw) ++ additional RSS queues here. ++ ++ Result would be that that net driver could call ++ nic.c:efhw_nic_allocate_common_hardware_resources() and that the ++ IFDEF FALCON's can be removed from ++ nic.c:efhw_nic_allocate_common_hardware_resources() ++ */ ++ nic->irq_unit = INT_EN_REG_CHAR_OFST; ++ ++ /***************************************************************** ++ * The rest of this function deals with initialization of the NICs ++ * hardware (as opposed to the initialization of the ++ * struct efhw_nic data structure */ ++ ++ /* char driver grabs SRM events onto the non interrupting ++ * event queue */ ++ falcon_nic_srm_upd_evq(nic, non_irq_evq); ++ ++ /* RXDP tweaks */ ++ ++ /* ?? bug2396 rx_cfg should be ok so long as the net driver ++ * always pushes buffers big enough for the link MTU */ ++ ++ /* set the RX buffer cutoff size to be the same as PAGE_SIZE. ++ * Use this value when we think that there will be a lot of ++ * jumbo frames. ++ * ++ * The default value 1600 is useful when packets are small, ++ * but would means that jumbo frame RX queues would need more ++ * descriptors pushing */ ++ falcon_nic_set_rx_usr_buf_size(nic, FALCON_RX_USR_BUF_SIZE); ++ ++ /* TXDP tweaks */ ++ /* ?? bug2396 looks ok */ ++ falcon_nic_tx_cfg(nic, /*unlocked(for non-UDP/TCP)= */ 0); ++ falcon_nic_pace_cfg(nic, 4, 2); ++ ++ /* ?? bug2396 ++ * netdriver must load first or else must RMW this register */ ++ falcon_nic_rx_filter_ctl_set(nic, RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL, ++ RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD, ++ RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL, ++ RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD); ++ ++ if (!(nic->flags & NIC_FLAG_NO_INTERRUPT)) { ++ rc = efhw_keventq_ctor(nic, FALCON_EVQ_CHAR, ++ &nic->interrupting_evq, ev_handlers); ++ if (rc < 0) { ++ EFHW_ERR("%s: efhw_keventq_ctor() failed (%d) evq=%d", ++ __func__, rc, FALCON_EVQ_CHAR); ++ return rc; ++ } ++ } ++ rc = efhw_keventq_ctor(nic, non_irq_evq, ++ &nic->non_interrupting_evq, NULL); ++ if (rc < 0) { ++ EFHW_ERR("%s: efhw_keventq_ctor() failed (%d) evq=%d", ++ __func__, rc, non_irq_evq); ++ return rc; ++ } ++ ++ /* allocate IRQ channel */ ++ rc = falcon_nic_init_irq_channel(nic, 1); ++ /* ignore failure at user-level for eftest */ ++ if ((rc < 0) && !(nic->options & NIC_OPT_EFTEST)) ++ return rc; ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Interrupt ++ * ++ *--------------------------------------------------------------------*/ ++ ++static void ++falcon_nic_interrupt_enable(struct efhw_nic *nic) ++{ ++ struct efhw_keventq *q; ++ unsigned rdptr; ++ ++ if (nic->flags & NIC_FLAG_NO_INTERRUPT) ++ return; ++ ++ /* Enable driver interrupts */ ++ EFHW_NOTICE("%s: enable master interrupt", __func__); ++ falcon_nic_interrupt_hw_enable(nic); ++ ++ /* An interrupting eventq must start of day ack its read pointer */ ++ q = &nic->interrupting_evq; ++ rdptr = EFHW_EVENT_OFFSET(q, q, 1) / sizeof(efhw_event_t); ++ falcon_nic_evq_ack(nic, FALCON_EVQ_CHAR, rdptr, false); ++ EFHW_NOTICE("%s: ACK evq[%d]:%x", __func__, ++ FALCON_EVQ_CHAR, rdptr); ++} ++ ++static void falcon_nic_interrupt_disable(struct efhw_nic *nic) ++{ ++ /* NB. No need to check for NIC_FLAG_NO_INTERRUPT, as ++ ** falcon_nic_interrupt_hw_disable() will do it. */ ++ falcon_nic_interrupt_hw_disable(nic); ++} ++ ++static void ++falcon_nic_set_interrupt_moderation(struct efhw_nic *nic, int evq, ++ uint32_t val) ++{ ++ if (evq < 0) ++ evq = FALCON_EVQ_CHAR; ++ ++ falcon_ab_timer_tbl_set(nic, evq, TIMER_MODE_INT_HLDOFF, val / 5); ++} ++ ++static inline void legacy_irq_ack(struct efhw_nic *nic) ++{ ++ EFHW_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT)); ++ ++ if (!(nic->flags & NIC_FLAG_MSI)) { ++ writel(1, EFHW_KVA(nic) + INT_ACK_REG_CHAR_A1_OFST); ++ mmiowb(); ++ /* ?? FIXME: We should be doing a read here to ensure IRQ is ++ * thoroughly acked before we return from ISR. */ ++ } ++} ++ ++static int falcon_nic_interrupt(struct efhw_nic *nic) ++{ ++ uint32_t *syserr_ptr = ++ (uint32_t *) efhw_iopage_ptr(&nic->irq_iobuff); ++ int handled = 0; ++ int done_ack = 0; ++ ++ EFHW_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT)); ++ EFHW_ASSERT(syserr_ptr); ++ ++ /* FIFO fill level interrupt - just log it. */ ++ if (unlikely(*(syserr_ptr + (DW0_OFST / 4)))) { ++ EFHW_WARN("%s: *** FIFO *** %x", __func__, ++ *(syserr_ptr + (DW0_OFST / 4))); ++ *(syserr_ptr + (DW0_OFST / 4)) = 0; ++ handled++; ++ } ++ ++ /* Fatal interrupts. */ ++ if (unlikely(*(syserr_ptr + (DW2_OFST / 4)))) { ++ *(syserr_ptr + (DW2_OFST / 4)) = 0; ++ falcon_nic_handle_fatal_int(nic); ++ handled++; ++ } ++ ++ /* Event queue interrupt. For legacy interrupts we have to check ++ * that the interrupt is for us, because it could be shared. */ ++ if (*(syserr_ptr + (DW1_OFST / 4))) { ++ *(syserr_ptr + (DW1_OFST / 4)) = 0; ++ /* ACK must come before callback to handler fn. */ ++ legacy_irq_ack(nic); ++ done_ack = 1; ++ handled++; ++ if (nic->irq_handler) ++ nic->irq_handler(nic, 0); ++ } ++ ++ if (unlikely(!done_ack)) { ++ if (!handled) ++ /* Shared interrupt line (hopefully). */ ++ return 0; ++ legacy_irq_ack(nic); ++ } ++ ++ EFHW_TRACE("%s: handled %d", __func__, handled); ++ return 1; ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Event Management - and SW event posting ++ * ++ *--------------------------------------------------------------------*/ ++ ++static void ++falcon_nic_event_queue_enable(struct efhw_nic *nic, uint evq, uint evq_size, ++ dma_addr_t q_base_addr, /* not used */ ++ uint buf_base_id, int interrupting) ++{ ++ EFHW_ASSERT(nic); ++ ++ /* Whether or not queue has an interrupt depends on ++ * instance number and h/w variant, so [interrupting] is ++ * ignored. ++ */ ++ falcon_ab_timer_tbl_set(nic, evq, 0/*disable*/, 0); ++ ++ falcon_nic_evq_ptr_tbl(nic, evq, 1, buf_base_id, evq_size); ++ EFHW_TRACE("%s: enable evq %u size %u", __func__, evq, evq_size); ++} ++ ++static void ++falcon_nic_event_queue_disable(struct efhw_nic *nic, uint evq, int timer_only) ++{ ++ EFHW_ASSERT(nic); ++ ++ falcon_ab_timer_tbl_set(nic, evq, 0 /* disable */ , 0); ++ ++ if (!timer_only) ++ falcon_nic_evq_ptr_tbl(nic, evq, 0, 0, 0); ++ EFHW_TRACE("%s: disenable evq %u", __func__, evq); ++} ++ ++static void ++falcon_nic_wakeup_request(struct efhw_nic *nic, dma_addr_t q_base_addr, ++ int next_i, int evq) ++{ ++ EFHW_ASSERT(evq > FALCON_EVQ_CHAR); ++ falcon_nic_evq_ack(nic, evq, next_i, true); ++ EFHW_TRACE("%s: evq %d next_i %d", __func__, evq, next_i); ++} ++ ++static void falcon_nic_sw_event(struct efhw_nic *nic, int data, int evq) ++{ ++ uint64_t ev_data = data; ++ ++ ev_data &= ~FALCON_EVENT_CODE_MASK; ++ ev_data |= FALCON_EVENT_CODE_SW; ++ ++ falcon_drv_ev(nic, ev_data, evq); ++ EFHW_NOTICE("%s: evq[%d]->%x", __func__, evq, data); ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * Buffer table - helpers ++ * ++ *--------------------------------------------------------------------*/ ++ ++#define FALCON_LAZY_COMMIT_HWM (FALCON_BUFFER_UPD_MAX - 16) ++ ++/* Note re.: ++ * falcon_nic_buffer_table_lazy_commit(struct efhw_nic *nic) ++ * falcon_nic_buffer_table_update_poll(struct efhw_nic *nic) ++ * falcon_nic_buffer_table_confirm(struct efhw_nic *nic) ++ * -- these are no-ops in the user-level driver because it would need to ++ * coordinate with the real driver on the number of outstanding commits. ++ * ++ * An exception is made for eftest apps, which manage the hardware without ++ * using the char driver. ++ */ ++ ++static inline void falcon_nic_buffer_table_lazy_commit(struct efhw_nic *nic) ++{ ++ /* Do nothing if operating in synchronous mode. */ ++ if (!nic->irq_handler) ++ return; ++} ++ ++static inline void falcon_nic_buffer_table_update_poll(struct efhw_nic *nic) ++{ ++ FALCON_LOCK_DECL; ++ int count = 0, rc = 0; ++ ++ /* We can be called here early days */ ++ if (!nic->irq_handler) ++ return; ++ ++ /* If we need to gather buffer update events then poll the ++ non-interrupting event queue */ ++ ++ /* For each _buffer_table_commit there will be an update done ++ event. We don't keep track of how many buffers each commit has ++ committed, just make sure that all the expected events have been ++ gathered */ ++ FALCON_LOCK_LOCK(nic); ++ ++ EFHW_TRACE("%s: %d", __func__, nic->buf_commit_outstanding); ++ ++ while (nic->buf_commit_outstanding > 0) { ++ /* we're not expecting to handle any events that require ++ * upcalls into the core driver */ ++ struct efhw_ev_handler handler; ++ memset(&handler, 0, sizeof(handler)); ++ nic->non_interrupting_evq.ev_handlers = &handler; ++ rc = efhw_keventq_poll(nic, &nic->non_interrupting_evq); ++ nic->non_interrupting_evq.ev_handlers = NULL; ++ ++ if (rc < 0) { ++ EFHW_ERR("%s: poll ERROR (%d:%d) ***** ", ++ __func__, rc, ++ nic->buf_commit_outstanding); ++ goto out; ++ } ++ ++ FALCON_LOCK_UNLOCK(nic); ++ ++ if (count++) ++ udelay(1); ++ ++ if (count > 1000) { ++ EFHW_WARN("%s: poll Timeout ***** (%d)", __func__, ++ nic->buf_commit_outstanding); ++ nic->buf_commit_outstanding = 0; ++ return; ++ } ++ FALCON_LOCK_LOCK(nic); ++ } ++ ++out: ++ FALCON_LOCK_UNLOCK(nic); ++ return; ++} ++ ++void falcon_nic_buffer_table_confirm(struct efhw_nic *nic) ++{ ++ /* confirm buffer table updates - should be used for items where ++ loss of data would be unacceptable. E.g for the buffers that back ++ an event or DMA queue */ ++ FALCON_LOCK_DECL; ++ ++ /* Do nothing if operating in synchronous mode. */ ++ if (!nic->irq_handler) ++ return; ++ ++ FALCON_LOCK_LOCK(nic); ++ ++ _falcon_nic_buffer_table_commit(nic); ++ ++ FALCON_LOCK_UNLOCK(nic); ++ ++ falcon_nic_buffer_table_update_poll(nic); ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Buffer table - API ++ * ++ *--------------------------------------------------------------------*/ ++ ++static void ++falcon_nic_buffer_table_clear(struct efhw_nic *nic, int buffer_id, int num) ++{ ++ FALCON_LOCK_DECL; ++ FALCON_LOCK_LOCK(nic); ++ _falcon_nic_buffer_table_clear(nic, buffer_id, num); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++static void ++falcon_nic_buffer_table_set(struct efhw_nic *nic, dma_addr_t dma_addr, ++ uint bufsz, uint region, ++ int own_id, int buffer_id) ++{ ++ FALCON_LOCK_DECL; ++ ++ EFHW_ASSERT(region < FALCON_REGION_NUM); ++ ++ EFHW_ASSERT((bufsz == EFHW_4K) || ++ (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE)); ++ ++ falcon_nic_buffer_table_update_poll(nic); ++ ++ FALCON_LOCK_LOCK(nic); ++ ++ _falcon_nic_buffer_table_set(nic, dma_addr, bufsz, region, own_id, ++ buffer_id); ++ ++ falcon_nic_buffer_table_lazy_commit(nic); ++ ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++void ++falcon_nic_buffer_table_set_n(struct efhw_nic *nic, int buffer_id, ++ dma_addr_t dma_addr, uint bufsz, uint region, ++ int n_pages, int own_id) ++{ ++ /* used to set up a contiguous range of buffers */ ++ FALCON_LOCK_DECL; ++ ++ EFHW_ASSERT(region < FALCON_REGION_NUM); ++ ++ EFHW_ASSERT((bufsz == EFHW_4K) || ++ (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE)); ++ ++ while (n_pages--) { ++ ++ falcon_nic_buffer_table_update_poll(nic); ++ ++ FALCON_LOCK_LOCK(nic); ++ ++ _falcon_nic_buffer_table_set(nic, dma_addr, bufsz, region, ++ own_id, buffer_id++); ++ ++ falcon_nic_buffer_table_lazy_commit(nic); ++ ++ FALCON_LOCK_UNLOCK(nic); ++ ++ dma_addr += bufsz; ++ } ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * DMA Queues - mid level API ++ * ++ *--------------------------------------------------------------------*/ ++ ++#if BUG5302_WORKAROUND ++ ++/* Tx queues can get stuck if the software write pointer is set to an index ++ * beyond the configured size of the queue, such that they will not flush. ++ * This code can be run before attempting a flush; it will detect the bogus ++ * value and reset it. This fixes most instances of this problem, although ++ * sometimes it does not work, or we may not detect it in the first place, ++ * if the out-of-range value was replaced by an in-range value earlier. ++ * (In those cases we have to apply a bigger hammer later, if we see that ++ * the queue is still not flushing.) ++ */ ++static void ++falcon_check_for_bogus_tx_dma_wptr(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ uint64_t val_low64, val_high64; ++ uint64_t size, hwptr, swptr, val; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ulong offset = falcon_dma_tx_q_offset(nic, dmaq); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ size = (val_low64 >> TX_DESCQ_SIZE_LBN) ++ & __FALCON_MASK64(TX_DESCQ_SIZE_WIDTH); ++ size = (1 << size) * 512; ++ hwptr = (val_high64 >> __DW3(TX_DESCQ_HW_RPTR_LBN)) ++ & __FALCON_MASK64(TX_DESCQ_HW_RPTR_WIDTH); ++ swptr = (val_low64 >> TX_DESCQ_SW_WPTR_LBN) ++ & __FALCON_MASK64(__LW2(TX_DESCQ_SW_WPTR_LBN)); ++ val = (val_high64) ++ & ++ __FALCON_MASK64(__DW3 ++ (TX_DESCQ_SW_WPTR_LBN + TX_DESCQ_SW_WPTR_WIDTH)); ++ val = val << __LW2(TX_DESCQ_SW_WPTR_LBN); ++ swptr = swptr | val; ++ ++ if (swptr >= size) { ++ EFHW_WARN("Resetting bad write pointer for TXQ[%d]", dmaq); ++ writel((uint32_t) ((hwptr + 0) & (size - 1)), ++ efhw_kva + falcon_tx_dma_page_addr(dmaq) + 12); ++ mmiowb(); ++ } ++} ++ ++/* Here's that "bigger hammer": we reset all the pointers (hardware read, ++ * hardware descriptor cache read, software write) to zero. ++ */ ++void falcon_clobber_tx_dma_ptrs(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ uint64_t val_low64, val_high64; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ulong offset = falcon_dma_tx_q_offset(nic, dmaq); ++ ++ EFHW_WARN("Recovering stuck TXQ[%d]", dmaq); ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64); ++ val_high64 &= ~(__FALCON_MASK64(TX_DESCQ_HW_RPTR_WIDTH) ++ << __DW3(TX_DESCQ_HW_RPTR_LBN)); ++ val_high64 &= ~(__FALCON_MASK64(TX_DC_HW_RPTR_WIDTH) ++ << __DW3(TX_DC_HW_RPTR_LBN)); ++ falcon_write_qq(efhw_kva + offset, val_low64, val_high64); ++ mmiowb(); ++ writel(0, efhw_kva + falcon_tx_dma_page_addr(dmaq) + 12); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++#endif ++ ++static inline int ++__falcon_really_flush_tx_dma_channel(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ uint val; ++ ++ EFHW_BUILD_ASSERT(TX_FLUSH_DESCQ_REG_KER_OFST == ++ TX_FLUSH_DESCQ_REG_OFST); ++ ++ __DWCHCK(TX_FLUSH_DESCQ_CMD_LBN, TX_FLUSH_DESCQ_CMD_WIDTH); ++ __DWCHCK(TX_FLUSH_DESCQ_LBN, TX_FLUSH_DESCQ_WIDTH); ++ __RANGECHCK(dmaq, TX_FLUSH_DESCQ_WIDTH); ++ ++ val = ((1 << TX_FLUSH_DESCQ_CMD_LBN) | (dmaq << TX_FLUSH_DESCQ_LBN)); ++ ++ EFHW_TRACE("TX DMA flush[%d]", dmaq); ++ ++#if BUG5302_WORKAROUND ++ falcon_check_for_bogus_tx_dma_wptr(nic, dmaq); ++#endif ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + TX_FLUSH_DESCQ_REG_OFST, ++ val, FALCON_ATOMIC_TX_FLUSH_DESCQ); ++ ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return 0; ++} ++ ++static inline int ++__falcon_is_tx_dma_channel_flushed(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ uint64_t val_low64, val_high64; ++ uint64_t enable, flush_pending; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ulong offset = falcon_dma_tx_q_offset(nic, dmaq); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ /* should see one of three values for these 2 bits ++ * 1, queue enabled no flush pending ++ * - i.e. first flush request ++ * 2, queue enabled, flush pending ++ * - i.e. request to reflush before flush finished ++ * 3, queue disabled (no flush pending) ++ * - flush complete ++ */ ++ __DWCHCK(TX_DESCQ_FLUSH_LBN, TX_DESCQ_FLUSH_WIDTH); ++ __DW3CHCK(TX_DESCQ_EN_LBN, TX_DESCQ_EN_WIDTH); ++ enable = val_high64 & (1 << __DW3(TX_DESCQ_EN_LBN)); ++ flush_pending = val_low64 & (1 << TX_DESCQ_FLUSH_LBN); ++ ++ if (enable && !flush_pending) ++ return 0; ++ ++ EFHW_TRACE("%d, %s: %s, %sflush pending", dmaq, __func__, ++ enable ? "enabled" : "disabled", ++ flush_pending ? "" : "NO "); ++ /* still in progress */ ++ if (enable && flush_pending) ++ return -EALREADY; ++ ++ return -EAGAIN; ++} ++ ++static int falcon_flush_tx_dma_channel(struct efhw_nic *nic, uint dmaq) ++{ ++ int rc; ++ rc = __falcon_is_tx_dma_channel_flushed(nic, dmaq); ++ if (rc < 0) { ++ EFHW_WARN("%s: failed %d", __func__, rc); ++ return rc; ++ } ++ return __falcon_really_flush_tx_dma_channel(nic, dmaq); ++} ++ ++static int ++__falcon_really_flush_rx_dma_channel(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ uint val; ++ ++ EFHW_BUILD_ASSERT(RX_FLUSH_DESCQ_REG_KER_OFST == ++ RX_FLUSH_DESCQ_REG_OFST); ++ ++ __DWCHCK(RX_FLUSH_DESCQ_CMD_LBN, RX_FLUSH_DESCQ_CMD_WIDTH); ++ __DWCHCK(RX_FLUSH_DESCQ_LBN, RX_FLUSH_DESCQ_WIDTH); ++ __RANGECHCK(dmaq, RX_FLUSH_DESCQ_WIDTH); ++ ++ val = ((1 << RX_FLUSH_DESCQ_CMD_LBN) | (dmaq << RX_FLUSH_DESCQ_LBN)); ++ ++ EFHW_TRACE("RX DMA flush[%d]", dmaq); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_write_qq(efhw_kva + RX_FLUSH_DESCQ_REG_OFST, val, ++ FALCON_ATOMIC_RX_FLUSH_DESCQ); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++ return 0; ++} ++ ++static inline int ++__falcon_is_rx_dma_channel_flushed(struct efhw_nic *nic, uint dmaq) ++{ ++ FALCON_LOCK_DECL; ++ uint64_t val; ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ ulong offset = falcon_dma_rx_q_offset(nic, dmaq); ++ ++ /* Falcon requires 128 bit atomic access for this register */ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_q(efhw_kva + offset, &val); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH); ++ ++ /* is it enabled? */ ++ return (val & (1 << RX_DESCQ_EN_LBN)) ++ ? 0 : -EAGAIN; ++} ++ ++static int falcon_flush_rx_dma_channel(struct efhw_nic *nic, uint dmaq) ++{ ++ int rc; ++ rc = __falcon_is_rx_dma_channel_flushed(nic, dmaq); ++ if (rc < 0) { ++ EFHW_ERR("%s: failed %d", __func__, rc); ++ return rc; ++ } ++ return __falcon_really_flush_rx_dma_channel(nic, dmaq); ++} ++ ++/*-------------------------------------------------------------------- ++ * ++ * Falcon specific event callbacks ++ * ++ *--------------------------------------------------------------------*/ ++ ++int ++falcon_handle_char_event(struct efhw_nic *nic, struct efhw_ev_handler *h, ++ efhw_event_t *ev) ++{ ++ EFHW_TRACE("DRIVER EVENT: "FALCON_EVENT_FMT, ++ FALCON_EVENT_PRI_ARG(*ev)); ++ ++ switch (FALCON_EVENT_DRIVER_SUBCODE(ev)) { ++ ++ case TX_DESCQ_FLS_DONE_EV_DECODE: ++ EFHW_TRACE("TX[%d] flushed", ++ (int)FALCON_EVENT_TX_FLUSH_Q_ID(ev)); ++ efhw_handle_txdmaq_flushed(nic, h, ev); ++ break; ++ ++ case RX_DESCQ_FLS_DONE_EV_DECODE: ++ EFHW_TRACE("RX[%d] flushed", ++ (int)FALCON_EVENT_TX_FLUSH_Q_ID(ev)); ++ efhw_handle_rxdmaq_flushed(nic, h, ev); ++ break; ++ ++ case SRM_UPD_DONE_EV_DECODE: ++ nic->buf_commit_outstanding = ++ max(0, nic->buf_commit_outstanding - 1); ++ EFHW_TRACE("COMMIT DONE %d", nic->buf_commit_outstanding); ++ break; ++ ++ case EVQ_INIT_DONE_EV_DECODE: ++ EFHW_TRACE("%sEVQ INIT", ""); ++ break; ++ ++ case WAKE_UP_EV_DECODE: ++ EFHW_TRACE("%sWAKE UP", ""); ++ efhw_handle_wakeup_event(nic, h, ev); ++ break; ++ ++ case TIMER_EV_DECODE: ++ EFHW_TRACE("%sTIMER", ""); ++ efhw_handle_timeout_event(nic, h, ev); ++ break; ++ ++ case RX_DESCQ_FLSFF_OVFL_EV_DECODE: ++ /* This shouldn't happen. */ ++ EFHW_ERR("%s: RX flush fifo overflowed", __func__); ++ return -EINVAL; ++ ++ default: ++ EFHW_TRACE("UNKOWN DRIVER EVENT: " FALCON_EVENT_FMT, ++ FALCON_EVENT_PRI_ARG(*ev)); ++ break; ++ } ++ return 0; ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * Filter search depth control ++ * ++ *--------------------------------------------------------------------*/ ++ ++ ++#define Q0_READ(q0, name) \ ++ ((unsigned)(((q0) >> name##_LBN) & (__FALCON_MASK64(name##_WIDTH)))) ++#define Q0_MASK(name) \ ++ ((__FALCON_MASK64(name##_WIDTH)) << name##_LBN) ++#define Q0_VALUE(name, value) \ ++ (((uint64_t)(value)) << name##_LBN) ++ ++#define Q1_READ(q1, name) \ ++ ((unsigned)(((q1) >> (name##_LBN - 64)) & \ ++ (__FALCON_MASK64(name##_WIDTH)))) ++#define Q1_MASK(name) \ ++ ((__FALCON_MASK64(name##_WIDTH)) << (name##_LBN - 64)) ++#define Q1_VALUE(name, value) \ ++ (((uint64_t)(value)) << (name##_LBN - 64)) ++ ++ ++void ++falcon_nic_get_rx_filter_search_limits(struct efhw_nic *nic, ++ struct efhw_filter_search_limits *lim, ++ int use_raw_values) ++{ ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ FALCON_LOCK_DECL; ++ uint64_t q0, q1; ++ unsigned ff = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_FULL); ++ unsigned wf = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_WILD); ++ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, &q0, &q1); ++ FALCON_LOCK_UNLOCK(nic); ++ ++ lim->tcp_full = Q0_READ(q0, TCP_FULL_SRCH_LIMIT) - ff; ++ lim->tcp_wild = Q0_READ(q0, TCP_WILD_SRCH_LIMIT) - wf; ++ lim->udp_full = Q0_READ(q0, UDP_FULL_SRCH_LIMIT) - ff; ++ lim->udp_wild = Q0_READ(q0, UDP_WILD_SRCH_LIMIT) - wf; ++} ++EXPORT_SYMBOL(falcon_nic_get_rx_filter_search_limits); ++ ++ ++void ++falcon_nic_set_rx_filter_search_limits(struct efhw_nic *nic, ++ struct efhw_filter_search_limits *lim, ++ int use_raw_values) ++{ ++ volatile char __iomem *efhw_kva = EFHW_KVA(nic); ++ FALCON_LOCK_DECL; ++ uint64_t q0, q1; ++ unsigned ff = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_FULL); ++ unsigned wf = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_WILD); ++ ++ FALCON_LOCK_LOCK(nic); ++ falcon_read_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, &q0, &q1); ++ ++ q0 &= ~Q0_MASK(TCP_FULL_SRCH_LIMIT); ++ q0 &= ~Q0_MASK(TCP_WILD_SRCH_LIMIT); ++ q0 &= ~Q0_MASK(UDP_FULL_SRCH_LIMIT); ++ q0 &= ~Q0_MASK(UDP_WILD_SRCH_LIMIT); ++ q0 |= Q0_VALUE(TCP_FULL_SRCH_LIMIT, lim->tcp_full + ff); ++ q0 |= Q0_VALUE(TCP_WILD_SRCH_LIMIT, lim->tcp_wild + wf); ++ q0 |= Q0_VALUE(UDP_FULL_SRCH_LIMIT, lim->udp_full + ff); ++ q0 |= Q0_VALUE(UDP_WILD_SRCH_LIMIT, lim->udp_wild + wf); ++ nic->tcp_full_srch.max = lim->tcp_full + ff ++ - RX_FILTER_CTL_SRCH_FUDGE_FULL; ++ nic->tcp_wild_srch.max = lim->tcp_wild + wf ++ - RX_FILTER_CTL_SRCH_FUDGE_WILD; ++ nic->udp_full_srch.max = lim->udp_full + ff ++ - RX_FILTER_CTL_SRCH_FUDGE_FULL; ++ nic->udp_wild_srch.max = lim->udp_wild + wf ++ - RX_FILTER_CTL_SRCH_FUDGE_WILD; ++ ++ falcon_write_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, q0, q1); ++ mmiowb(); ++ FALCON_LOCK_UNLOCK(nic); ++} ++EXPORT_SYMBOL(falcon_nic_set_rx_filter_search_limits); ++ ++ ++#undef READ_Q0 ++#undef Q0_MASK ++#undef Q0_VALUE ++#undef READ_Q1 ++#undef Q1_MASK ++#undef Q1_VALUE ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * New unified filter API ++ * ++ *--------------------------------------------------------------------*/ ++ ++ ++#if FALCON_FULL_FILTER_CACHE ++static inline struct efhw_filter_spec * ++filter_spec_cache_entry(struct efhw_nic *nic, int filter_idx) ++{ ++ EFHW_ASSERT(nic->filter_spec_cache); ++ return &nic->filter_spec_cache[filter_idx]; ++} ++#endif ++ ++ ++static int filter_is_active(struct efhw_nic *nic, int filter_idx) ++{ ++ return nic->filter_in_use[filter_idx]; ++} ++ ++ ++static void set_filter_cache_entry(struct efhw_nic *nic, ++ struct efhw_filter_spec *spec, ++ int filter_idx) ++{ ++ nic->filter_in_use[filter_idx] = 1; ++#if FALCON_FULL_FILTER_CACHE ++ memcpy(filter_spec_cache_entry(nic, filter_idx), spec, ++ sizeof(struct efhw_filter_spec)); ++#endif ++} ++ ++ ++static void clear_filter_cache_entry(struct efhw_nic *nic, ++ int filter_idx) ++{ ++ nic->filter_in_use[filter_idx] = 0; ++#if FALCON_FULL_FILTER_CACHE ++ memset(filter_spec_cache_entry(nic, filter_idx), 0, ++ sizeof(struct efhw_filter_spec)); ++#endif ++} ++ ++ ++#if FALCON_FULL_FILTER_CACHE ++static int filter_is_duplicate(struct efhw_nic *nic, ++ struct efhw_filter_spec *spec, int filter_idx) ++{ ++ struct efhw_filter_spec *cmp; ++ ++ cmp = filter_spec_cache_entry(nic, filter_idx); ++ ++ EFHW_ASSERT(filter_is_active(nic, filter_idx)); ++ ++ return (spec->saddr_le32 == cmp->saddr_le32) && ++ (spec->daddr_le32 == cmp->daddr_le32) && ++ (spec->sport_le16 == cmp->sport_le16) && ++ (spec->dport_le16 == cmp->dport_le16) && ++ (spec->tcp == cmp->tcp) && ++ (spec->full == cmp->full); ++} ++#endif ++ ++ ++static void common_build_ip_filter(struct efhw_nic *nic, int tcp, int full, ++ int rss, int scatter, uint dmaq_id, ++ unsigned saddr_le32, unsigned sport_le16, ++ unsigned daddr_le32, unsigned dport_le16, ++ uint64_t *q0, uint64_t *q1) ++{ ++ uint64_t v1, v2, v3, v4; ++ unsigned tmp_port_le16; ++ ++ if (!full) { ++ saddr_le32 = 0; ++ sport_le16 = 0; ++ if (!tcp) { ++ tmp_port_le16 = sport_le16; ++ sport_le16 = dport_le16; ++ dport_le16 = tmp_port_le16; ++ } ++ } ++ ++ v4 = (((!tcp) << __DW4(TCP_UDP_0_LBN)) | ++ (dmaq_id << __DW4(RXQ_ID_0_LBN))); ++ ++ switch (nic->devtype.variant) { ++ case 'A': ++ EFHW_ASSERT(!rss); ++ break; ++ case 'B': ++ v4 |= scatter << __DW4(SCATTER_EN_0_B0_LBN); ++ v4 |= rss << __DW4(RSS_EN_0_B0_LBN); ++ break; ++ default: ++ EFHW_ASSERT(0); ++ break; ++ } ++ ++ v3 = daddr_le32; ++ v2 = ((dport_le16 << __DW2(DEST_PORT_TCP_0_LBN)) | ++ (__HIGH(saddr_le32, SRC_IP_0_LBN, SRC_IP_0_WIDTH))); ++ v1 = ((__LOW(saddr_le32, SRC_IP_0_LBN, SRC_IP_0_WIDTH)) | ++ (sport_le16 << SRC_TCP_DEST_UDP_0_LBN)); ++ ++ *q0 = (v2 << 32) | v1; ++ *q1 = (v4 << 32) | v3; ++} ++ ++ ++static void build_filter(struct efhw_nic *nic, struct efhw_filter_spec *spec, ++ unsigned *key, unsigned *tbl_size, ++ struct efhw_filter_depth **depth, ++ uint64_t *q0, uint64_t *q1) ++{ ++ *key = falcon_hash_get_ip_key(spec->saddr_le32, ++ spec->sport_le16, ++ spec->daddr_le32, ++ spec->dport_le16, ++ spec->tcp, ++ spec->full); ++ *tbl_size = nic->ip_filter_tbl_size; ++ if (spec->tcp && spec->full) ++ *depth = &nic->tcp_full_srch; ++ else if (spec->tcp && !spec->full) ++ *depth = &nic->tcp_wild_srch; ++ else if (!spec->tcp && spec->full) ++ *depth = &nic->udp_full_srch; ++ else ++ *depth = &nic->udp_wild_srch; ++ common_build_ip_filter(nic, spec->tcp, spec->full, ++ spec->rss, spec->scatter, ++ spec->dmaq_id, ++ spec->saddr_le32, ++ spec->sport_le16, ++ spec->daddr_le32, ++ spec->dport_le16, ++ q0, q1); ++} ++ ++ ++#if FALCON_VERIFY_FILTERS ++static void verify_filters(struct efhw_nic *nic) ++{ ++ unsigned table_offset, table_stride; ++ unsigned i, dummy_key, dummy_tbl_size; ++ struct efhw_filter_depth *dummy_depth; ++ unsigned filter_tbl_size; ++ struct efhw_filter_spec *spec; ++ uint64_t q0_expect, q1_expect, q0_got, q1_got; ++ ++ filter_tbl_size = nic->ip_filter_tbl_size; ++ table_offset = RX_FILTER_TBL0_OFST; ++ table_stride = 2 * FALCON_REGISTER128; ++ ++ for (i = 0; i < filter_tbl_size; i++) { ++ if (!filter_is_active(nic, type, i)) ++ continue; ++ ++ spec = filter_spec_cache_entry(nic, type, i); ++ ++ build_filter(nic, spec, &dummy_key, &dummy_tbl_size, ++ &dummy_depth, &q0_expect, &q1_expect); ++ ++ falcon_read_qq(EFHW_KVA(nic) + table_offset + i * table_stride, ++ &q0_got, &q1_got); ++ ++ if ((q0_got != q0_expect) || (q1_got != q1_expect)) { ++ falcon_write_qq(EFHW_KVA(nic) + 0x300, ++ q0_got, q1_got); ++ EFHW_ERR("ERROR: RX-filter[%d][%d] was " ++ "%"PRIx64":%" PRIx64" expected " ++ "%"PRIx64":%"PRIx64, ++ nic->index, i, q0_got, q1_got, ++ q0_expect, q1_expect); ++ } ++ } ++} ++#endif ++ ++ ++static void write_filter_table_entry(struct efhw_nic *nic, ++ unsigned filter_idx, ++ uint64_t q0, uint64_t q1) ++{ ++ unsigned table_offset, table_stride, offset; ++ ++ EFHW_ASSERT(filter_idx < nic->ip_filter_tbl_size); ++ table_offset = RX_FILTER_TBL0_OFST; ++ table_stride = 2 * FALCON_REGISTER128; ++ ++ offset = table_offset + filter_idx * table_stride; ++ falcon_write_qq(EFHW_KVA(nic) + offset, q0, q1); ++ mmiowb(); ++ ++#if FALCON_VERIFY_FILTERS ++ { ++ uint64_t q0read, q1read; ++ ++ /* Read a different entry first - ensure BIU flushed shadow */ ++ falcon_read_qq(EFHW_KVA(nic) + offset + 0x10, &q0read, &q1read); ++ falcon_read_qq(EFHW_KVA(nic) + offset, &q0read, &q1read); ++ EFHW_ASSERT(q0read == q0); ++ EFHW_ASSERT(q1read == q1); ++ ++ verify_filters(nic, type); ++ } ++#endif ++} ++ ++ ++static int falcon_nic_filter_set(struct efhw_nic *nic, ++ struct efhw_filter_spec *spec, ++ int *filter_idx_out) ++{ ++ FALCON_LOCK_DECL; ++ unsigned key = 0, tbl_size = 0, hash1, hash2, k; ++ struct efhw_filter_depth *depth = NULL; ++ int filter_idx = -1; ++ int rc = 0; ++ uint64_t q0, q1; ++ ++ build_filter(nic, spec, &key, &tbl_size, &depth, &q0, &q1); ++ ++ if (tbl_size == 0) ++ return -EINVAL; ++ ++ EFHW_TRACE("%s: depth->max=%d", __func__, depth->max); ++ ++ hash1 = falcon_hash_function1(key, tbl_size); ++ hash2 = falcon_hash_function2(key, tbl_size); ++ ++ FALCON_LOCK_LOCK(nic); ++ ++ for (k = 0; k < depth->max; k++) { ++ filter_idx = falcon_hash_iterator(hash1, hash2, k, tbl_size); ++ if (!filter_is_active(nic, filter_idx)) ++ break; ++#if FALCON_FULL_FILTER_CACHE ++ if (filter_is_duplicate(nic, spec, filter_idx)) { ++ EFHW_WARN("%s: ERROR: duplicate filter (disabling " ++ "interrupts)", __func__); ++ falcon_nic_interrupt_hw_disable(nic); ++ rc = -EINVAL; ++ goto fail1; ++ } ++#endif ++ } ++ if (k == depth->max) { ++ rc = -EADDRINUSE; ++ filter_idx = -1; ++ goto fail1; ++ } else if (depth->needed < (k + 1)) { ++ depth->needed = k + 1; ++ } ++ ++ EFHW_ASSERT(filter_idx < (int)tbl_size); ++ ++ set_filter_cache_entry(nic, spec, filter_idx); ++ write_filter_table_entry(nic, filter_idx, q0, q1); ++ ++ ++nic->ip_filter_tbl_used; ++ ++ *filter_idx_out = filter_idx; ++ ++ EFHW_TRACE("%s: filter index %d rxq %u set in %u", ++ __func__, filter_idx, spec->dmaq_id, k); ++ ++fail1: ++ FALCON_LOCK_UNLOCK(nic); ++ return rc; ++} ++ ++ ++static void falcon_nic_filter_clear(struct efhw_nic *nic, ++ int filter_idx) ++{ ++ FALCON_LOCK_DECL; ++ ++ if (filter_idx < 0) ++ return; ++ ++ FALCON_LOCK_LOCK(nic); ++ if (filter_is_active(nic, filter_idx)) { ++ if (--nic->ip_filter_tbl_used == 0) { ++ nic->tcp_full_srch.needed = 0; ++ nic->tcp_wild_srch.needed = 0; ++ nic->udp_full_srch.needed = 0; ++ nic->udp_wild_srch.needed = 0; ++ } ++ } ++ clear_filter_cache_entry(nic, filter_idx); ++ write_filter_table_entry(nic, filter_idx, 0, 0); ++ FALCON_LOCK_UNLOCK(nic); ++} ++ ++ ++int ++falcon_nic_filter_ctor(struct efhw_nic *nic) ++{ ++ nic->ip_filter_tbl_size = 8 * 1024; ++ nic->ip_filter_tbl_used = 0; ++ ++ nic->tcp_full_srch.needed = 0; ++ nic->tcp_full_srch.max = RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL ++ - RX_FILTER_CTL_SRCH_FUDGE_FULL; ++ nic->tcp_wild_srch.needed = 0; ++ nic->tcp_wild_srch.max = RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD ++ - RX_FILTER_CTL_SRCH_FUDGE_WILD; ++ nic->udp_full_srch.needed = 0; ++ nic->udp_full_srch.max = RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL ++ - RX_FILTER_CTL_SRCH_FUDGE_FULL; ++ nic->udp_wild_srch.needed = 0; ++ nic->udp_wild_srch.max = RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD ++ - RX_FILTER_CTL_SRCH_FUDGE_WILD; ++ ++ nic->filter_in_use = vmalloc(FALCON_FILTER_TBL_NUM); ++ if (nic->filter_in_use == NULL) ++ return -ENOMEM; ++ memset(nic->filter_in_use, 0, FALCON_FILTER_TBL_NUM); ++#if FALCON_FULL_FILTER_CACHE ++ nic->filter_spec_cache = vmalloc(FALCON_FILTER_TBL_NUM ++ * sizeof(struct efhw_filter_spec)); ++ if (nic->filter_spec_cache == NULL) ++ return -ENOMEM; ++ memset(nic->filter_spec_cache, 0, FALCON_FILTER_TBL_NUM ++ * sizeof(struct efhw_filter_spec)); ++#endif ++ ++ return 0; ++} ++ ++ ++void ++falcon_nic_filter_dtor(struct efhw_nic *nic) ++{ ++#if FALCON_FULL_FILTER_CACHE ++ if (nic->filter_spec_cache) ++ vfree(nic->filter_spec_cache); ++#endif ++ if (nic->filter_in_use) ++ vfree(nic->filter_in_use); ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * Compatibility with old filter API ++ * ++ *--------------------------------------------------------------------*/ ++ ++void ++falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full, ++ uint32_t *tcp_wild, ++ uint32_t *udp_full, uint32_t *udp_wild) ++{ ++ struct efhw_filter_search_limits lim; ++ ++ falcon_nic_get_rx_filter_search_limits(nic, &lim, 0); ++ *tcp_full = (uint32_t)lim.tcp_full; ++ *tcp_wild = (uint32_t)lim.tcp_wild; ++ *udp_full = (uint32_t)lim.udp_full; ++ *udp_wild = (uint32_t)lim.udp_wild; ++} ++EXPORT_SYMBOL(falcon_nic_rx_filter_ctl_get); ++ ++ ++void ++falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full, ++ uint32_t tcp_wild, ++ uint32_t udp_full, uint32_t udp_wild) ++{ ++ struct efhw_filter_search_limits lim; ++ ++ lim.tcp_full = (unsigned)tcp_full; ++ lim.tcp_wild = (unsigned)tcp_wild; ++ lim.udp_full = (unsigned)udp_full; ++ lim.udp_wild = (unsigned)udp_wild; ++ falcon_nic_set_rx_filter_search_limits(nic, &lim, 0); ++} ++EXPORT_SYMBOL(falcon_nic_rx_filter_ctl_set); ++ ++ ++static int ++falcon_nic_ipfilter_set(struct efhw_nic *nic, int type, int *_filter_idx, ++ int dmaq, ++ unsigned saddr_be32, unsigned sport_be16, ++ unsigned daddr_be32, unsigned dport_be16) ++{ ++ struct efhw_filter_spec spec; ++ ++ spec.dmaq_id = dmaq; ++ spec.saddr_le32 = ntohl(saddr_be32); ++ spec.daddr_le32 = ntohl(daddr_be32); ++ spec.sport_le16 = ntohs((unsigned short) sport_be16); ++ spec.dport_le16 = ntohs((unsigned short) dport_be16); ++ spec.tcp = ((type & EFHW_IP_FILTER_TYPE_TCP_MASK) != 0); ++ spec.full = ((type & EFHW_IP_FILTER_TYPE_FULL_MASK) != 0); ++ spec.rss = ((type & EFHW_IP_FILTER_TYPE_RSS_B0_MASK) != 0); ++ spec.scatter = ((type & EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK) == 0); ++ return falcon_nic_filter_set(nic, &spec, _filter_idx); ++} ++ ++static void falcon_nic_ipfilter_clear(struct efhw_nic *nic, int filter_idx) ++{ ++ falcon_nic_filter_clear(nic, filter_idx); ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * Abstraction Layer Hooks ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_func_ops falcon_char_functional_units = { ++ falcon_nic_close_hardware, ++ falcon_nic_init_hardware, ++ falcon_nic_interrupt, ++ falcon_nic_interrupt_enable, ++ falcon_nic_interrupt_disable, ++ falcon_nic_set_interrupt_moderation, ++ falcon_nic_event_queue_enable, ++ falcon_nic_event_queue_disable, ++ falcon_nic_wakeup_request, ++ falcon_nic_sw_event, ++ falcon_nic_ipfilter_set, ++ falcon_nic_ipfilter_clear, ++ falcon_dmaq_tx_q_init, ++ falcon_dmaq_rx_q_init, ++ falcon_dmaq_tx_q_disable, ++ falcon_dmaq_rx_q_disable, ++ falcon_flush_tx_dma_channel, ++ falcon_flush_rx_dma_channel, ++ falcon_nic_buffer_table_set, ++ falcon_nic_buffer_table_set_n, ++ falcon_nic_buffer_table_clear, ++ falcon_nic_buffer_table_commit, ++ falcon_nic_filter_set, ++ falcon_nic_filter_clear, ++}; ++ ++ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/falcon_hash.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/falcon_hash.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,159 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains EtherFabric NIC hash algorithms implementation. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++ ++ ++static unsigned int ++common_get_ip_key(unsigned int src_ip, unsigned int src_port, ++ unsigned int dest_ip, unsigned int dest_port, ++ int tcp, int full, int tx, unsigned int masked_q_id) ++{ ++ ++ unsigned int tmp_port, result; ++ ++ EFHW_ASSERT(tcp == 0 || tcp == 1); ++ EFHW_ASSERT(full == 0 || full == 1); ++ EFHW_ASSERT(masked_q_id < (1 << 10)); ++ ++ /* m=masked_q_id(TX)/0(RX) u=UDP S,D=src/dest addr s,d=src/dest port ++ * ++ * Wildcard filters have src(TX)/dest(RX) addr and port = 0; ++ * and UDP wildcard filters have the src and dest port fields swapped. ++ * ++ * Addr/port fields are little-endian. ++ * ++ * 3322222222221111111111 ++ * 10987654321098765432109876543210 ++ * ++ * 000000000000000000000mmmmmmmmmmu ^ ++ * DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ^ ++ * ddddddddddddddddSSSSSSSSSSSSSSSS ^ ++ * SSSSSSSSSSSSSSSSssssssssssssssss ++ */ ++ ++ if (!tx) ++ masked_q_id = 0; ++ ++ if (!full) { ++ if (tx) { ++ dest_ip = 0; ++ dest_port = 0; ++ } else { ++ src_ip = 0; ++ src_port = 0; ++ } ++ if (!tcp) { ++ tmp_port = src_port; ++ src_port = dest_port; ++ dest_port = tmp_port; ++ } ++ } ++ ++ result = ((masked_q_id << 1) | (!tcp)) ^ ++ (dest_ip) ^ ++ (((dest_port & 0xffff) << 16) | ((src_ip >> 16) & 0xffff)) ^ ++ (((src_ip & 0xffff) << 16) | (src_port & 0xffff)); ++ ++ EFHW_TRACE("%s: IP %s %s %x", __func__, tcp ? "TCP" : "UDP", ++ full ? "Full" : "Wildcard", result); ++ ++ return result; ++} ++ ++ ++unsigned int ++falcon_hash_get_ip_key(unsigned int src_ip, unsigned int src_port, ++ unsigned int dest_ip, unsigned int dest_port, ++ int tcp, int full) ++{ ++ return common_get_ip_key(src_ip, src_port, dest_ip, dest_port, tcp, ++ full, 0, 0); ++} ++ ++ ++/* This function generates the First Hash key */ ++unsigned int falcon_hash_function1(unsigned int key, unsigned int nfilters) ++{ ++ ++ unsigned short int lfsr_reg; ++ unsigned int tmp_key; ++ int index; ++ ++ unsigned short int lfsr_input; ++ unsigned short int single_bit_key; ++ unsigned short int bit16_lfsr; ++ unsigned short int bit3_lfsr; ++ ++ lfsr_reg = 0xFFFF; ++ tmp_key = key; ++ ++ /* For Polynomial equation X^16+X^3+1 */ ++ for (index = 0; index < 32; index++) { ++ /* Get the bit from key and shift the key */ ++ single_bit_key = (tmp_key & 0x80000000) >> 31; ++ tmp_key = tmp_key << 1; ++ ++ /* get the Tap bits to XOR operation */ ++ bit16_lfsr = (lfsr_reg & 0x8000) >> 15; ++ bit3_lfsr = (lfsr_reg & 0x0004) >> 2; ++ ++ /* Get the Input value to the LFSR */ ++ lfsr_input = ((bit16_lfsr ^ bit3_lfsr) ^ single_bit_key); ++ ++ /* Shift and store out of the two TAPs */ ++ lfsr_reg = lfsr_reg << 1; ++ lfsr_reg = lfsr_reg | (lfsr_input & 0x0001); ++ ++ } ++ ++ lfsr_reg = lfsr_reg & (nfilters - 1); ++ ++ return lfsr_reg; ++} ++ ++/* This function generates the Second Hash */ ++unsigned int ++falcon_hash_function2(unsigned int key, unsigned int nfilters) ++{ ++ return (unsigned int)(((unsigned long long)key * 2 - 1) & ++ (nfilters - 1)); ++} ++ ++/* This function iterates through the hash table */ ++unsigned int ++falcon_hash_iterator(unsigned int hash1, unsigned int hash2, ++ unsigned int n_search, unsigned int nfilters) ++{ ++ return (hash1 + (n_search * hash2)) & (nfilters - 1); ++} ++ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/filter_resource.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/filter_resource.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,250 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains filters support. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++ ++struct filter_resource_manager { ++ struct efrm_resource_manager rm; ++ struct kfifo *free_ids; ++}; ++ ++static struct filter_resource_manager *efrm_filter_manager; ++ ++ ++void efrm_filter_resource_free(struct filter_resource *frs) ++{ ++ struct efhw_nic *nic = frs->rs.rs_client->nic; ++ int id; ++ ++ EFRM_RESOURCE_ASSERT_VALID(&frs->rs, 1); ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle)); ++ ++ efhw_nic_ipfilter_clear(nic, frs->filter_idx); ++ frs->filter_idx = -1; ++ efrm_vi_resource_release(frs->pt); ++ ++ /* Free this filter. */ ++ id = EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle); ++ EFRM_VERIFY_EQ(kfifo_put(efrm_filter_manager->free_ids, ++ (unsigned char *)&id, sizeof(id)), ++ sizeof(id)); ++ ++ efrm_client_put(frs->rs.rs_client); ++ EFRM_DO_DEBUG(memset(frs, 0, sizeof(*frs))); ++ kfree(frs); ++} ++EXPORT_SYMBOL(efrm_filter_resource_free); ++ ++ ++void efrm_filter_resource_release(struct filter_resource *frs) ++{ ++ if (__efrm_resource_release(&frs->rs)) ++ efrm_filter_resource_free(frs); ++} ++EXPORT_SYMBOL(efrm_filter_resource_release); ++ ++ ++static void filter_rm_dtor(struct efrm_resource_manager *rm) ++{ ++ EFRM_TRACE("%s:", __func__); ++ ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_filter_manager->rm); ++ EFRM_ASSERT(&efrm_filter_manager->rm == rm); ++ ++ kfifo_vfree(efrm_filter_manager->free_ids); ++ EFRM_TRACE("%s: done", __func__); ++} ++ ++/**********************************************************************/ ++/**********************************************************************/ ++/**********************************************************************/ ++ ++int efrm_create_filter_resource_manager(struct efrm_resource_manager **rm_out) ++{ ++ int rc; ++ ++ EFRM_ASSERT(rm_out); ++ ++ efrm_filter_manager = ++ kmalloc(sizeof(struct filter_resource_manager), GFP_KERNEL); ++ if (efrm_filter_manager == 0) ++ return -ENOMEM; ++ memset(efrm_filter_manager, 0, sizeof(*efrm_filter_manager)); ++ ++ rc = efrm_resource_manager_ctor(&efrm_filter_manager->rm, ++ filter_rm_dtor, "FILTER", ++ EFRM_RESOURCE_FILTER); ++ if (rc < 0) ++ goto fail1; ++ ++ /* Create a pool of free instances */ ++ rc = efrm_kfifo_id_ctor(&efrm_filter_manager->free_ids, ++ 0, EFHW_IP_FILTER_NUM, ++ &efrm_filter_manager->rm.rm_lock); ++ if (rc != 0) ++ goto fail2; ++ ++ *rm_out = &efrm_filter_manager->rm; ++ EFRM_TRACE("%s: filter resources created - %d IDs", ++ __func__, kfifo_len(efrm_filter_manager->free_ids)); ++ return 0; ++ ++fail2: ++ efrm_resource_manager_dtor(&efrm_filter_manager->rm); ++fail1: ++ memset(efrm_filter_manager, 0, sizeof(*efrm_filter_manager)); ++ kfree(efrm_filter_manager); ++ return rc; ++ ++} ++ ++ ++int efrm_filter_resource_clear(struct filter_resource *frs) ++{ ++ struct efhw_nic *nic = frs->rs.rs_client->nic; ++ ++ efhw_nic_ipfilter_clear(nic, frs->filter_idx); ++ frs->filter_idx = -1; ++ return 0; ++} ++EXPORT_SYMBOL(efrm_filter_resource_clear); ++ ++ ++int ++__efrm_filter_resource_set(struct filter_resource *frs, int type, ++ unsigned saddr, uint16_t sport, ++ unsigned daddr, uint16_t dport) ++{ ++ struct efhw_nic *nic = frs->rs.rs_client->nic; ++ int vi_instance; ++ ++ EFRM_ASSERT(frs); ++ ++ if (efrm_nic_tablep->a_nic->devtype.variant >= 'B' && ++ (frs->pt->flags & EFHW_VI_JUMBO_EN) == 0) ++ type |= EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK; ++ vi_instance = EFRM_RESOURCE_INSTANCE(frs->pt->rs.rs_handle); ++ ++ return efhw_nic_ipfilter_set(nic, type, &frs->filter_idx, ++ vi_instance, saddr, sport, daddr, dport); ++} ++EXPORT_SYMBOL(__efrm_filter_resource_set);; ++ ++ ++int ++efrm_filter_resource_alloc(struct vi_resource *vi_parent, ++ struct filter_resource **frs_out) ++{ ++ struct filter_resource *frs; ++ int rc, instance; ++ ++ EFRM_ASSERT(frs_out); ++ EFRM_ASSERT(efrm_filter_manager); ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_filter_manager->rm); ++ EFRM_ASSERT(vi_parent != NULL); ++ EFRM_ASSERT(EFRM_RESOURCE_TYPE(vi_parent->rs.rs_handle) == ++ EFRM_RESOURCE_VI); ++ ++ /* Allocate resource data structure. */ ++ frs = kmalloc(sizeof(struct filter_resource), GFP_KERNEL); ++ if (!frs) ++ return -ENOMEM; ++ ++ /* Allocate an instance. */ ++ rc = kfifo_get(efrm_filter_manager->free_ids, ++ (unsigned char *)&instance, sizeof(instance)); ++ if (rc != sizeof(instance)) { ++ EFRM_TRACE("%s: out of instances", __func__); ++ EFRM_ASSERT(rc == 0); ++ rc = -EBUSY; ++ goto fail1; ++ } ++ ++ /* Initialise the resource DS. */ ++ efrm_resource_init(&frs->rs, EFRM_RESOURCE_FILTER, instance); ++ frs->pt = vi_parent; ++ efrm_resource_ref(&frs->pt->rs); ++ frs->filter_idx = -1; ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " VI %d", __func__, ++ EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle), ++ EFRM_RESOURCE_INSTANCE(vi_parent->rs.rs_handle)); ++ ++ efrm_client_add_resource(vi_parent->rs.rs_client, &frs->rs); ++ *frs_out = frs; ++ return 0; ++ ++fail1: ++ memset(frs, 0, sizeof(*frs)); ++ kfree(frs); ++ return rc; ++} ++EXPORT_SYMBOL(efrm_filter_resource_alloc); ++ ++ ++int efrm_filter_resource_instance(struct filter_resource *frs) ++{ ++ return EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle); ++} ++EXPORT_SYMBOL(efrm_filter_resource_instance); ++ ++ ++struct efrm_resource * ++efrm_filter_resource_to_resource(struct filter_resource *frs) ++{ ++ return &frs->rs; ++} ++EXPORT_SYMBOL(efrm_filter_resource_to_resource); ++ ++ ++struct filter_resource * ++efrm_filter_resource_from_resource(struct efrm_resource *rs) ++{ ++ return filter_resource(rs); ++} ++EXPORT_SYMBOL(efrm_filter_resource_from_resource); +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/iobufset_resource.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/iobufset_resource.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,404 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains non-contiguous I/O buffers support. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++ ++#define EFRM_IOBUFSET_MAX_NUM_INSTANCES 0x00010000 ++ ++struct iobufset_resource_manager { ++ struct efrm_resource_manager rm; ++ struct kfifo *free_ids; ++}; ++ ++struct iobufset_resource_manager *efrm_iobufset_manager; ++ ++#define iobsrs(rs1) iobufset_resource(rs1) ++ ++/* Returns size of iobufset resource data structure. */ ++static inline size_t iobsrs_size(int n_pages) ++{ ++ return offsetof(struct iobufset_resource, bufs) + ++ n_pages * sizeof(struct efhw_iopage); ++} ++ ++void efrm_iobufset_resource_free(struct iobufset_resource *rs) ++{ ++ unsigned int i; ++ int id; ++ ++ EFRM_RESOURCE_ASSERT_VALID(&rs->rs, 1); ++ ++ if (!rs->linked && rs->buf_tbl_alloc.base != (unsigned) -1) ++ efrm_buffer_table_free(&rs->buf_tbl_alloc); ++ ++ /* see comment on call to efhw_iopage_alloc in the alloc routine above ++ for discussion on use of efrm_nic_tablep->a_nic here */ ++ EFRM_ASSERT(efrm_nic_tablep->a_nic); ++ if (rs->linked) { ++ /* Nothing to do. */ ++ } else if (rs->chunk_order == 0) { ++ for (i = 0; i < rs->n_bufs; ++i) ++ efhw_iopage_free(efrm_nic_tablep->a_nic, &rs->bufs[i]); ++ } else { ++ /* it is important that this is executed in increasing page ++ * order because some implementations of ++ * efhw_iopages_init_from_iopage() assume this */ ++ for (i = 0; i < rs->n_bufs; ++ i += rs->pages_per_contiguous_chunk) { ++ struct efhw_iopages iopages; ++ efhw_iopages_init_from_iopage(&iopages, &rs->bufs[i], ++ rs->chunk_order); ++ efhw_iopages_free(efrm_nic_tablep->a_nic, &iopages); ++ } ++ } ++ ++ /* free the instance number */ ++ id = EFRM_RESOURCE_INSTANCE(rs->rs.rs_handle); ++ EFRM_VERIFY_EQ(kfifo_put(efrm_iobufset_manager->free_ids, ++ (unsigned char *)&id, sizeof(id)), sizeof(id)); ++ ++ efrm_vi_resource_release(rs->evq); ++ if (rs->linked) ++ efrm_iobufset_resource_release(rs->linked); ++ ++ efrm_client_put(rs->rs.rs_client); ++ if (iobsrs_size(rs->n_bufs) < PAGE_SIZE) { ++ EFRM_DO_DEBUG(memset(rs, 0, sizeof(*rs))); ++ kfree(rs); ++ } else { ++ EFRM_DO_DEBUG(memset(rs, 0, sizeof(*rs))); ++ vfree(rs); ++ } ++} ++EXPORT_SYMBOL(efrm_iobufset_resource_free); ++ ++ ++void efrm_iobufset_resource_release(struct iobufset_resource *iobrs) ++{ ++ if (__efrm_resource_release(&iobrs->rs)) ++ efrm_iobufset_resource_free(iobrs); ++} ++EXPORT_SYMBOL(efrm_iobufset_resource_release); ++ ++ ++ ++int ++efrm_iobufset_resource_alloc(int32_t n_pages, ++ int32_t pages_per_contiguous_chunk, ++ struct vi_resource *vi_evq, ++ struct iobufset_resource *linked, ++ bool phys_addr_mode, ++ struct iobufset_resource **iobrs_out) ++{ ++ struct iobufset_resource *iobrs; ++ int rc, instance, object_size; ++ unsigned int i; ++ ++ EFRM_ASSERT(iobrs_out); ++ EFRM_ASSERT(efrm_iobufset_manager); ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_iobufset_manager->rm); ++ EFRM_RESOURCE_ASSERT_VALID(&vi_evq->rs, 0); ++ EFRM_ASSERT(EFRM_RESOURCE_TYPE(vi_evq->rs.rs_handle) == ++ EFRM_RESOURCE_VI); ++ EFRM_ASSERT(efrm_nic_tablep->a_nic); ++ ++ if (linked) { ++ /* This resource will share properties and memory with ++ * another. Only difference is that we'll program it into ++ * the buffer table of another nic. ++ */ ++ n_pages = linked->n_bufs; ++ pages_per_contiguous_chunk = linked->pages_per_contiguous_chunk; ++ phys_addr_mode = linked->buf_tbl_alloc.base == (unsigned) -1; ++ } ++ ++ /* allocate the resource data structure. */ ++ object_size = iobsrs_size(n_pages); ++ if (object_size < PAGE_SIZE) { ++ /* this should be OK from a tasklet */ ++ /* Necessary to do atomic alloc() as this ++ can be called from a weird-ass iSCSI context that is ++ !in_interrupt but is in_atomic - See BUG3163 */ ++ iobrs = kmalloc(object_size, GFP_ATOMIC); ++ } else { /* can't do this within a tasklet */ ++#ifndef NDEBUG ++ if (in_interrupt() || in_atomic()) { ++ EFRM_ERR("%s(): alloc->u.iobufset.in_n_pages=%d", ++ __func__, n_pages); ++ EFRM_ASSERT(!in_interrupt()); ++ EFRM_ASSERT(!in_atomic()); ++ } ++#endif ++ iobrs = (struct iobufset_resource *) vmalloc(object_size); ++ } ++ if (iobrs == NULL) { ++ EFRM_WARN("%s: failed to allocate container", __func__); ++ rc = -ENOMEM; ++ goto fail1; ++ } ++ ++ /* Allocate an instance number. */ ++ rc = kfifo_get(efrm_iobufset_manager->free_ids, ++ (unsigned char *)&instance, sizeof(instance)); ++ if (rc != sizeof(instance)) { ++ EFRM_WARN("%s: out of instances", __func__); ++ EFRM_ASSERT(rc == 0); ++ rc = -EBUSY; ++ goto fail3; ++ } ++ ++ efrm_resource_init(&iobrs->rs, EFRM_RESOURCE_IOBUFSET, instance); ++ ++ iobrs->evq = vi_evq; ++ iobrs->linked = linked; ++ iobrs->n_bufs = n_pages; ++ iobrs->pages_per_contiguous_chunk = pages_per_contiguous_chunk; ++ iobrs->chunk_order = fls(iobrs->pages_per_contiguous_chunk - 1); ++ iobrs->buf_tbl_alloc.base = (unsigned) -1; ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " %u pages", __func__, ++ EFRM_RESOURCE_PRI_ARG(iobrs->rs.rs_handle), iobrs->n_bufs); ++ ++ /* Allocate the iobuffers. */ ++ if (linked) { ++ memcpy(iobrs->bufs, linked->bufs, ++ iobrs->n_bufs * sizeof(iobrs->bufs[0])); ++ } else if (iobrs->chunk_order == 0) { ++ memset(iobrs->bufs, 0, iobrs->n_bufs * sizeof(iobrs->bufs[0])); ++ for (i = 0; i < iobrs->n_bufs; ++i) { ++ /* due to bug2426 we have to specifiy a NIC when ++ * allocating a DMAable page, which is a bit messy. ++ * For now we assume that if the page is suitable ++ * (e.g. DMAable) by one nic (efrm_nic_tablep->a_nic), ++ * it is suitable for all NICs. ++ * XXX I bet that breaks in Solaris. ++ */ ++ rc = efhw_iopage_alloc(efrm_nic_tablep->a_nic, ++ &iobrs->bufs[i]); ++ if (rc < 0) { ++ EFRM_WARN("%s: failed (rc %d) to allocate " ++ "page (i=%u)", __func__, rc, i); ++ goto fail4; ++ } ++ } ++ } else { ++ struct efhw_iopages iopages; ++ unsigned j; ++ ++ memset(iobrs->bufs, 0, iobrs->n_bufs * sizeof(iobrs->bufs[0])); ++ for (i = 0; i < iobrs->n_bufs; ++ i += iobrs->pages_per_contiguous_chunk) { ++ rc = efhw_iopages_alloc(efrm_nic_tablep->a_nic, ++ &iopages, iobrs->chunk_order); ++ if (rc < 0) { ++ EFRM_WARN("%s: failed (rc %d) to allocate " ++ "pages (i=%u order %d)", ++ __func__, rc, i, ++ iobrs->chunk_order); ++ goto fail4; ++ } ++ for (j = 0; j < iobrs->pages_per_contiguous_chunk; ++ j++) { ++ /* some implementation of ++ * efhw_iopage_init_from_iopages() rely on ++ * this function being called for ++ * _all_ pages in the chunk */ ++ efhw_iopage_init_from_iopages( ++ &iobrs->bufs[i + j], ++ &iopages, j); ++ } ++ } ++ } ++ ++ if (!phys_addr_mode) { ++ unsigned owner_id = EFAB_VI_RESOURCE_INSTANCE(iobrs->evq); ++ ++ if (!linked) { ++ /* Allocate space in the NIC's buffer table. */ ++ rc = efrm_buffer_table_alloc(fls(iobrs->n_bufs - 1), ++ &iobrs->buf_tbl_alloc); ++ if (rc < 0) { ++ EFRM_WARN("%s: failed (%d) to alloc %d buffer " ++ "table entries", __func__, rc, ++ iobrs->n_bufs); ++ goto fail5; ++ } ++ EFRM_ASSERT(((unsigned)1 << iobrs->buf_tbl_alloc.order) ++ >= (unsigned) iobrs->n_bufs); ++ } else { ++ iobrs->buf_tbl_alloc = linked->buf_tbl_alloc; ++ } ++ ++ /* Initialise the buffer table entries. */ ++ for (i = 0; i < iobrs->n_bufs; ++i) { ++ /*\ ?? \TODO burst them! */ ++ efrm_buffer_table_set(&iobrs->buf_tbl_alloc, ++ vi_evq->rs.rs_client->nic, ++ i, ++ efhw_iopage_dma_addr(&iobrs-> ++ bufs[i]), ++ owner_id); ++ } ++ efrm_buffer_table_commit(); ++ } ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " %d pages @ " ++ EFHW_BUFFER_ADDR_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(iobrs->rs.rs_handle), ++ iobrs->n_bufs, EFHW_BUFFER_ADDR(iobrs->buf_tbl_alloc.base, ++ 0)); ++ efrm_resource_ref(&iobrs->evq->rs); ++ if (linked != NULL) ++ efrm_resource_ref(&linked->rs); ++ efrm_client_add_resource(vi_evq->rs.rs_client, &iobrs->rs); ++ *iobrs_out = iobrs; ++ return 0; ++ ++fail5: ++ i = iobrs->n_bufs; ++fail4: ++ /* see comment on call to efhw_iopage_alloc above for a discussion ++ * on use of efrm_nic_tablep->a_nic here */ ++ if (linked) { ++ /* Nothing to do. */ ++ } else if (iobrs->chunk_order == 0) { ++ while (i--) { ++ struct efhw_iopage *page = &iobrs->bufs[i]; ++ efhw_iopage_free(efrm_nic_tablep->a_nic, page); ++ } ++ } else { ++ unsigned int j; ++ for (j = 0; j < i; j += iobrs->pages_per_contiguous_chunk) { ++ struct efhw_iopages iopages; ++ ++ EFRM_ASSERT(j % iobrs->pages_per_contiguous_chunk ++ == 0); ++ /* it is important that this is executed in increasing ++ * page order because some implementations of ++ * efhw_iopages_init_from_iopage() assume this */ ++ efhw_iopages_init_from_iopage(&iopages, ++ &iobrs->bufs[j], ++ iobrs->chunk_order); ++ efhw_iopages_free(efrm_nic_tablep->a_nic, &iopages); ++ } ++ } ++fail3: ++ if (object_size < PAGE_SIZE) ++ kfree(iobrs); ++ else ++ vfree(iobrs); ++fail1: ++ return rc; ++} ++EXPORT_SYMBOL(efrm_iobufset_resource_alloc); ++ ++static void iobufset_rm_dtor(struct efrm_resource_manager *rm) ++{ ++ EFRM_ASSERT(&efrm_iobufset_manager->rm == rm); ++ kfifo_vfree(efrm_iobufset_manager->free_ids); ++} ++ ++int ++efrm_create_iobufset_resource_manager(struct efrm_resource_manager **rm_out) ++{ ++ int rc, max; ++ ++ EFRM_ASSERT(rm_out); ++ ++ efrm_iobufset_manager = ++ kmalloc(sizeof(*efrm_iobufset_manager), GFP_KERNEL); ++ if (efrm_iobufset_manager == 0) ++ return -ENOMEM; ++ memset(efrm_iobufset_manager, 0, sizeof(*efrm_iobufset_manager)); ++ ++ /* ++ * Bug 1145, 1370: We need to set initial size of both the resource ++ * table and instance id table so they never need to grow as we ++ * want to be allocate new iobufset at tasklet time. Lets make ++ * a pessimistic guess at maximum number of iobufsets possible. ++ * Could be less because ++ * - jumbo frames have same no of packets per iobufset BUT more ++ * pages per buffer ++ * - buffer table entries used independently of iobufsets by ++ * sendfile ++ * ++ * Based on TCP/IP stack setting of PKTS_PER_SET_S=5 ... ++ * - can't use this define here as it breaks the layering. ++ */ ++#define MIN_PAGES_PER_IOBUFSET (1 << 4) ++ ++ max = efrm_buffer_table_size() / MIN_PAGES_PER_IOBUFSET; ++ max = min_t(int, max, EFRM_IOBUFSET_MAX_NUM_INSTANCES); ++ ++ /* HACK: There currently exists an option to allocate buffers that ++ * are not programmed into the buffer table, so the max number is ++ * not limited by the buffer table size. I'm hoping this usage ++ * will go away eventually. ++ */ ++ max = 32768; ++ ++ rc = efrm_kfifo_id_ctor(&efrm_iobufset_manager->free_ids, ++ 0, max, &efrm_iobufset_manager->rm.rm_lock); ++ if (rc != 0) ++ goto fail1; ++ ++ rc = efrm_resource_manager_ctor(&efrm_iobufset_manager->rm, ++ iobufset_rm_dtor, "IOBUFSET", ++ EFRM_RESOURCE_IOBUFSET); ++ if (rc < 0) ++ goto fail2; ++ ++ *rm_out = &efrm_iobufset_manager->rm; ++ return 0; ++ ++fail2: ++ kfifo_vfree(efrm_iobufset_manager->free_ids); ++fail1: ++ EFRM_DO_DEBUG(memset(efrm_iobufset_manager, 0, ++ sizeof(*efrm_iobufset_manager))); ++ kfree(efrm_iobufset_manager); ++ return rc; ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/iopage.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/iopage.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,103 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides Linux-specific implementation for iopage API used ++ * from efhw library. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include "kernel_compat.h" ++#include /* for dma_addr_t */ ++ ++int efhw_iopage_alloc(struct efhw_nic *nic, struct efhw_iopage *p) ++{ ++ struct linux_efhw_nic *lnic = linux_efhw_nic(nic); ++ dma_addr_t handle; ++ void *kva; ++ ++ kva = efrm_pci_alloc_consistent(lnic->pci_dev, PAGE_SIZE, ++ &handle); ++ if (kva == 0) ++ return -ENOMEM; ++ ++ EFHW_ASSERT((handle & ~PAGE_MASK) == 0); ++ ++ memset((void *)kva, 0, PAGE_SIZE); ++ efhw_page_init_from_va(&p->p, kva); ++ ++ p->dma_addr = handle; ++ ++ return 0; ++} ++ ++void efhw_iopage_free(struct efhw_nic *nic, struct efhw_iopage *p) ++{ ++ struct linux_efhw_nic *lnic = linux_efhw_nic(nic); ++ EFHW_ASSERT(efhw_page_is_valid(&p->p)); ++ ++ efrm_pci_free_consistent(lnic->pci_dev, PAGE_SIZE, ++ efhw_iopage_ptr(p), p->dma_addr); ++} ++ ++int ++efhw_iopages_alloc(struct efhw_nic *nic, struct efhw_iopages *p, ++ unsigned order) ++{ ++ unsigned bytes = 1u << (order + PAGE_SHIFT); ++ struct linux_efhw_nic *lnic = linux_efhw_nic(nic); ++ dma_addr_t handle; ++ caddr_t addr; ++ int gfp_flag; ++ ++ /* Set __GFP_COMP if available to make reference counting work. ++ * This is recommended here: ++ * http://www.forbiddenweb.org/viewtopic.php?id=83167&page=4#348331 ++ */ ++ gfp_flag = ((in_atomic() ? GFP_ATOMIC : GFP_KERNEL) | __GFP_COMP); ++ addr = efrm_dma_alloc_coherent(&lnic->pci_dev->dev, bytes, &handle, ++ gfp_flag); ++ if (addr == NULL) ++ return -ENOMEM; ++ ++ EFHW_ASSERT((handle & ~PAGE_MASK) == 0); ++ ++ p->order = order; ++ p->dma_addr = handle; ++ p->kva = addr; ++ ++ return 0; ++} ++ ++void efhw_iopages_free(struct efhw_nic *nic, struct efhw_iopages *p) ++{ ++ unsigned bytes = 1u << (p->order + PAGE_SHIFT); ++ struct linux_efhw_nic *lnic = linux_efhw_nic(nic); ++ ++ efrm_dma_free_coherent(&lnic->pci_dev->dev, bytes, ++ (void *)p->kva, p->dma_addr); ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/kernel_compat.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/kernel_compat.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,118 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file provides compatibility layer for various Linux kernel versions ++ * (starting from 2.6.9 RHEL kernel). ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#define IN_KERNEL_COMPAT_C ++#include ++#include ++#include "kernel_compat.h" ++ ++/* Set this to 1 to enable very basic counting of iopage(s) allocations, then ++ * call dump_iopage_counts() to show the number of current allocations of ++ * orders 0-7. ++ */ ++#define EFRM_IOPAGE_COUNTS_ENABLED 0 ++ ++ ++/**************************************************************************** ++ * ++ * allocate a buffer suitable for DMA to/from the NIC ++ * ++ ****************************************************************************/ ++ ++#if EFRM_IOPAGE_COUNTS_ENABLED ++ ++static int iopage_counts[8]; ++ ++void dump_iopage_counts(void) ++{ ++ EFRM_NOTICE("iopage counts: %d %d %d %d %d %d %d %d", iopage_counts[0], ++ iopage_counts[1], iopage_counts[2], iopage_counts[3], ++ iopage_counts[4], iopage_counts[5], iopage_counts[6], ++ iopage_counts[7]); ++} ++ ++#endif ++ ++ ++ ++/*********** pci_alloc_consistent / pci_free_consistent ***********/ ++ ++void *efrm_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_addr, int flag) ++{ ++ void *ptr; ++ unsigned order; ++ ++ order = __ffs(size/PAGE_SIZE); ++ EFRM_ASSERT(size == (PAGE_SIZE< ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H ++#define DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H ++ ++#include ++#include ++#include ++#include ++ ++/********* pci_map_*() ********************/ ++ ++extern void *efrm_dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_addr, int flag); ++ ++extern void efrm_dma_free_coherent(struct device *dev, size_t size, ++ void *ptr, dma_addr_t dma_addr); ++ ++static inline void *efrm_pci_alloc_consistent(struct pci_dev *hwdev, ++ size_t size, ++ dma_addr_t *dma_addr) ++{ ++ return efrm_dma_alloc_coherent(&hwdev->dev, size, dma_addr, ++ GFP_ATOMIC); ++} ++ ++static inline void efrm_pci_free_consistent(struct pci_dev *hwdev, size_t size, ++ void *ptr, dma_addr_t dma_addr) ++{ ++ efrm_dma_free_coherent(&hwdev->dev, size, ptr, dma_addr); ++} ++ ++ ++#endif /* DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/kernel_proc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/kernel_proc.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,109 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains /proc/driver/sfc_resource/ implementation. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++ ++/** Top level directory for sfc specific stats **/ ++static struct proc_dir_entry *efrm_proc_root; /* = NULL */ ++ ++static int ++efrm_resource_read_proc(char *buf, char **start, off_t offset, int count, ++ int *eof, void *data); ++ ++int efrm_install_proc_entries(void) ++{ ++ /* create the top-level directory for etherfabric specific stuff */ ++ efrm_proc_root = proc_mkdir("driver/sfc_resource", NULL); ++ if (!efrm_proc_root) ++ return -ENOMEM; ++ ++ if (create_proc_read_entry("resources", 0, efrm_proc_root, ++ efrm_resource_read_proc, 0) == NULL) { ++ EFRM_WARN("%s: Unable to create /proc/drivers/sfc_resource/" ++ "resources", __func__); ++ } ++ return 0; ++} ++ ++void efrm_uninstall_proc_entries(void) ++{ ++ EFRM_ASSERT(efrm_proc_root); ++ remove_proc_entry("resources", efrm_proc_root); ++ remove_proc_entry(efrm_proc_root->name, efrm_proc_root->parent); ++ efrm_proc_root = NULL; ++} ++ ++/**************************************************************************** ++ * ++ * /proc/drivers/sfc/resources ++ * ++ ****************************************************************************/ ++ ++#define EFRM_PROC_PRINTF(buf, len, fmt, ...) \ ++ do { \ ++ if (count - len > 0) \ ++ len += snprintf(buf+len, count-len, (fmt), \ ++ __VA_ARGS__); \ ++ } while (0) ++ ++static int ++efrm_resource_read_proc(char *buf, char **start, off_t offset, int count, ++ int *eof, void *data) ++{ ++ irq_flags_t lock_flags; ++ int len = 0; ++ int type; ++ struct efrm_resource_manager *rm; ++ ++ for (type = 0; type < EFRM_RESOURCE_NUM; type++) { ++ rm = efrm_rm_table[type]; ++ if (rm == NULL) ++ continue; ++ ++ EFRM_PROC_PRINTF(buf, len, "*** %s ***\n", rm->rm_name); ++ ++ spin_lock_irqsave(&rm->rm_lock, lock_flags); ++ EFRM_PROC_PRINTF(buf, len, "current = %u\n", rm->rm_resources); ++ EFRM_PROC_PRINTF(buf, len, " max = %u\n\n", ++ rm->rm_resources_hiwat); ++ spin_unlock_irqrestore(&rm->rm_lock, lock_flags); ++ } ++ ++ return count ? strlen(buf) : 0; ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/kfifo.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/kfifo.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,208 @@ ++/* ++ * A simple kernel FIFO implementation. ++ * ++ * Copyright (C) 2004 Stelian Pop ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * This file is stolen from the Linux kernel sources ++ * (linux-2.6.22/kernel/kfifo.c) into sfc_resource driver. ++ * It should be used for old kernels without kfifo implementation. ++ * Most part of linux/kfifo.h is incorporated into ++ * ci/efrm/sysdep_linux.h. ++ */ ++#include ++#ifdef HAS_NO_KFIFO ++ ++#include ++#include ++#include ++#include ++/*#include */ ++ ++/** ++ * kfifo_init - allocates a new FIFO using a preallocated buffer ++ * @buffer: the preallocated buffer to be used. ++ * @size: the size of the internal buffer, this have to be a power of 2. ++ * @gfp_mask: get_free_pages mask, passed to kmalloc() ++ * @lock: the lock to be used to protect the fifo buffer ++ * ++ * Do NOT pass the kfifo to kfifo_free() after use! Simply free the ++ * &struct kfifo with kfree(). ++ */ ++struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size, ++ gfp_t gfp_mask, spinlock_t *lock) ++{ ++ struct kfifo *fifo; ++ ++ /* size must be a power of 2 */ ++ BUG_ON(size & (size - 1)); ++ ++ fifo = kmalloc(sizeof(struct kfifo), gfp_mask); ++ if (!fifo) ++ return ERR_PTR(-ENOMEM); ++ ++ fifo->buffer = buffer; ++ fifo->size = size; ++ fifo->in = fifo->out = 0; ++ fifo->lock = lock; ++ ++ return fifo; ++} ++EXPORT_SYMBOL(kfifo_init); ++ ++/** ++ * kfifo_alloc - allocates a new FIFO and its internal buffer ++ * @size: the size of the internal buffer to be allocated. ++ * @gfp_mask: get_free_pages mask, passed to kmalloc() ++ * @lock: the lock to be used to protect the fifo buffer ++ * ++ * The size will be rounded-up to a power of 2. ++ */ ++struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock) ++{ ++ unsigned char *buffer; ++ struct kfifo *ret; ++ ++ /* ++ * round up to the next power of 2, since our 'let the indices ++ * wrap' tachnique works only in this case. ++ */ ++ if (size & (size - 1)) { ++ BUG_ON(size > 0x80000000); ++ size = roundup_pow_of_two(size); ++ } ++ ++ buffer = kmalloc(size, gfp_mask); ++ if (!buffer) ++ return ERR_PTR(-ENOMEM); ++ ++ ret = kfifo_init(buffer, size, gfp_mask, lock); ++ ++ if (IS_ERR(ret)) ++ kfree(buffer); ++ ++ return ret; ++} ++EXPORT_SYMBOL(kfifo_alloc); ++ ++/** ++ * kfifo_free - frees the FIFO ++ * @fifo: the fifo to be freed. ++ */ ++void kfifo_free(struct kfifo *fifo) ++{ ++ kfree(fifo->buffer); ++ kfree(fifo); ++} ++EXPORT_SYMBOL(kfifo_free); ++ ++/** ++ * __kfifo_put - puts some data into the FIFO, no locking version ++ * @fifo: the fifo to be used. ++ * @buffer: the data to be added. ++ * @len: the length of the data to be added. ++ * ++ * This function copies at most @len bytes from the @buffer into ++ * the FIFO depending on the free space, and returns the number of ++ * bytes copied. ++ * ++ * Note that with only one concurrent reader and one concurrent ++ * writer, you don't need extra locking to use these functions. ++ */ ++unsigned int ++__kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len) ++{ ++ unsigned int l; ++ ++ len = min(len, fifo->size - fifo->in + fifo->out); ++ ++ /* ++ * Ensure that we sample the fifo->out index -before- we ++ * start putting bytes into the kfifo. ++ */ ++ ++ smp_mb(); ++ ++ /* first put the data starting from fifo->in to buffer end */ ++ l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); ++ memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); ++ ++ /* then put the rest (if any) at the beginning of the buffer */ ++ memcpy(fifo->buffer, buffer + l, len - l); ++ ++ /* ++ * Ensure that we add the bytes to the kfifo -before- ++ * we update the fifo->in index. ++ */ ++ ++ smp_wmb(); ++ ++ fifo->in += len; ++ ++ return len; ++} ++EXPORT_SYMBOL(__kfifo_put); ++ ++/** ++ * __kfifo_get - gets some data from the FIFO, no locking version ++ * @fifo: the fifo to be used. ++ * @buffer: where the data must be copied. ++ * @len: the size of the destination buffer. ++ * ++ * This function copies at most @len bytes from the FIFO into the ++ * @buffer and returns the number of copied bytes. ++ * ++ * Note that with only one concurrent reader and one concurrent ++ * writer, you don't need extra locking to use these functions. ++ */ ++unsigned int ++__kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len) ++{ ++ unsigned int l; ++ ++ len = min(len, fifo->in - fifo->out); ++ ++ /* ++ * Ensure that we sample the fifo->in index -before- we ++ * start removing bytes from the kfifo. ++ */ ++ ++ smp_rmb(); ++ ++ /* first get the data from fifo->out until the end of the buffer */ ++ l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); ++ memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); ++ ++ /* then get the rest (if any) from the beginning of the buffer */ ++ memcpy(buffer + l, fifo->buffer, len - l); ++ ++ /* ++ * Ensure that we remove the bytes from the kfifo -before- ++ * we update the fifo->out index. ++ */ ++ ++ smp_mb(); ++ ++ fifo->out += len; ++ ++ return len; ++} ++EXPORT_SYMBOL(__kfifo_get); ++ ++#endif +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/linux_resource_internal.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/linux_resource_internal.h 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,76 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains Linux-specific API internal for the resource driver. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#ifndef __LINUX_RESOURCE_INTERNAL__ ++#define __LINUX_RESOURCE_INTERNAL__ ++ ++#include ++#include ++#include ++#include ++ ++ ++/*! Linux specific EtherFabric initialisation */ ++extern int ++linux_efrm_nic_ctor(struct linux_efhw_nic *, struct pci_dev *, ++ spinlock_t *reg_lock, ++ unsigned nic_flags, unsigned nic_options); ++ ++/*! Linux specific EtherFabric initialisation */ ++extern void linux_efrm_nic_dtor(struct linux_efhw_nic *); ++ ++/*! Linux specific EtherFabric initialisation -- interrupt registration */ ++extern int linux_efrm_irq_ctor(struct linux_efhw_nic *); ++ ++/*! Linux specific EtherFabric initialisation -- interrupt deregistration */ ++extern void linux_efrm_irq_dtor(struct linux_efhw_nic *); ++ ++extern int efrm_driverlink_register(void); ++extern void efrm_driverlink_unregister(void); ++ ++extern int ++efrm_nic_add(struct pci_dev *dev, unsigned int opts, const uint8_t *mac_addr, ++ struct linux_efhw_nic **lnic_out, spinlock_t *reg_lock, ++ int bt_min, int bt_max, int non_irq_evq, ++ const struct vi_resource_dimensions *); ++extern void efrm_nic_del(struct linux_efhw_nic *); ++ ++ ++extern int efrm_install_proc_entries(void); ++extern void efrm_uninstall_proc_entries(void); ++ ++#endif /* __LINUX_RESOURCE_INTERNAL__ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/nic.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/nic.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,174 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains EtherFabric Generic NIC instance (init, interrupts, ++ * etc) ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++int efhw_device_type_init(struct efhw_device_type *dt, ++ int vendor_id, int device_id, ++ int class_revision) ++{ ++ if (vendor_id != 0x1924) ++ return 0; ++ ++ switch (device_id) { ++ case 0x0703: ++ case 0x6703: ++ dt->variant = 'A'; ++ switch (class_revision) { ++ case 0: ++ dt->revision = 0; ++ break; ++ case 1: ++ dt->revision = 1; ++ break; ++ default: ++ return 0; ++ } ++ break; ++ case 0x0710: ++ dt->variant = 'B'; ++ switch (class_revision) { ++ case 2: ++ dt->revision = 0; ++ break; ++ default: ++ return 0; ++ } ++ break; ++ default: ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++/*-------------------------------------------------------------------- ++ * ++ * NIC Initialisation ++ * ++ *--------------------------------------------------------------------*/ ++ ++/* make this separate from initialising data structure ++** to allow this to be called at a later time once we can access PCI ++** config space to find out what hardware we have ++*/ ++void efhw_nic_init(struct efhw_nic *nic, unsigned flags, unsigned options, ++ struct efhw_device_type dev_type) ++{ ++ nic->devtype = dev_type; ++ nic->flags = flags; ++ nic->options = options; ++ nic->bar_ioaddr = 0; ++ spin_lock_init(&nic->the_reg_lock); ++ nic->reg_lock = &nic->the_reg_lock; ++ nic->mtu = 1500 + ETH_HLEN; ++ ++ nic->irq_unit = EFHW_IRQ_UNIT_UNUSED; ++ ++ nic->evq_sizes = 512 | 1024 | 2048 | 4096 | 8192 | ++ 16384 | 32768; ++ nic->txq_sizes = 512 | 1024 | 2048 | 4096; ++ nic->rxq_sizes = 512 | 1024 | 2048 | 4096; ++ nic->efhw_func = &falcon_char_functional_units; ++ nic->ctr_ap_bytes = EFHW_64M; ++ switch (nic->devtype.variant) { ++ case 'A': ++ nic->ctr_ap_bar = FALCON_S_CTR_AP_BAR; ++ nic->num_evqs = 4096; ++ nic->num_dmaqs = 4096; ++ nic->num_timers = 4096; ++ break; ++ case 'B': ++ nic->flags |= NIC_FLAG_NO_INTERRUPT; ++ nic->ctr_ap_bar = FALCON_P_CTR_AP_BAR; ++ nic->num_evqs = 4096; ++ nic->num_dmaqs = 4096; ++ nic->num_timers = 4096; ++ break; ++ default: ++ EFHW_ASSERT(0); ++ break; ++ } ++} ++ ++ ++void efhw_nic_close_interrupts(struct efhw_nic *nic) ++{ ++ EFHW_ASSERT(nic); ++ if (!efhw_nic_have_hw(nic)) ++ return; ++ ++ EFHW_ASSERT(efhw_nic_have_hw(nic)); ++ ++ if (nic->irq_unit != EFHW_IRQ_UNIT_UNUSED) ++ efhw_nic_interrupt_disable(nic); ++} ++ ++void efhw_nic_dtor(struct efhw_nic *nic) ++{ ++ EFHW_ASSERT(nic); ++ ++ /* Check that we have functional units because the software only ++ * driver doesn't initialise anything hardware related any more */ ++ ++ /* close interrupts is called first because the act of deregistering ++ the driver could cause this driver to change from master to slave ++ and hence the implicit interrupt mappings would be wrong */ ++ ++ EFHW_TRACE("%s: functional units ... ", __func__); ++ ++ if (efhw_nic_have_functional_units(nic)) { ++ efhw_nic_close_interrupts(nic); ++ efhw_nic_close_hardware(nic); ++ } ++ EFHW_TRACE("%s: functional units ... done", __func__); ++ ++ /* destroy event queues */ ++ EFHW_TRACE("%s: event queues ... ", __func__); ++ ++ if (nic->interrupting_evq.evq_mask) ++ efhw_keventq_dtor(nic, &nic->interrupting_evq); ++ if (nic->non_interrupting_evq.evq_mask) ++ efhw_keventq_dtor(nic, &nic->non_interrupting_evq); ++ ++ EFHW_TRACE("%s: event queues ... done", __func__); ++ ++ spin_lock_destroy(&nic->the_reg_lock); ++ ++ EFHW_TRACE("%s: DONE", __func__); ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/resource_driver.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/resource_driver.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,600 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains main driver entry points. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include "linux_resource_internal.h" ++#include "kernel_compat.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Solarflare Communications"); ++MODULE_LICENSE("GPL"); ++ ++static struct efhw_ev_handler ev_handler = { ++ .wakeup_fn = efrm_handle_wakeup_event, ++ .timeout_fn = efrm_handle_timeout_event, ++ .dmaq_flushed_fn = efrm_handle_dmaq_flushed, ++}; ++ ++const int max_hardware_init_repeats = 10; ++ ++/*-------------------------------------------------------------------- ++ * ++ * Module load time variables ++ * ++ *--------------------------------------------------------------------*/ ++/* See docs/notes/pci_alloc_consistent */ ++static int do_irq = 1; /* enable interrupts */ ++ ++#if defined(CONFIG_X86_XEN) ++static int irq_moderation = 60; /* interrupt moderation (60 usec) */ ++#else ++static int irq_moderation = 20; /* interrupt moderation (20 usec) */ ++#endif ++static int nic_options = NIC_OPT_DEFAULT; ++int efx_vi_eventq_size = EFX_VI_EVENTQ_SIZE_DEFAULT; ++ ++module_param(do_irq, int, S_IRUGO); ++MODULE_PARM_DESC(do_irq, "Enable interrupts. " ++ "Do not turn it off unless you know what are you doing."); ++module_param(irq_moderation, int, S_IRUGO); ++MODULE_PARM_DESC(irq_moderation, "IRQ moderation in usec"); ++module_param(nic_options, int, S_IRUGO); ++MODULE_PARM_DESC(nic_options, "Nic options -- see efhw_types.h"); ++module_param(efx_vi_eventq_size, int, S_IRUGO); ++MODULE_PARM_DESC(efx_vi_eventq_size, ++ "Size of event queue allocated by efx_vi library"); ++ ++/*-------------------------------------------------------------------- ++ * ++ * Linux specific NIC initialisation ++ * ++ *--------------------------------------------------------------------*/ ++ ++static inline irqreturn_t ++linux_efrm_interrupt(int irr, void *dev_id) ++{ ++ return efhw_nic_interrupt((struct efhw_nic *)dev_id); ++} ++ ++int linux_efrm_irq_ctor(struct linux_efhw_nic *lnic) ++{ ++ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic; ++ ++ nic->flags &= ~NIC_FLAG_MSI; ++ if (nic->flags & NIC_FLAG_TRY_MSI) { ++ int rc = pci_enable_msi(lnic->pci_dev); ++ if (rc < 0) { ++ EFRM_WARN("%s: Could not enable MSI (%d)", ++ __func__, rc); ++ EFRM_WARN("%s: Continuing with legacy interrupt mode", ++ __func__); ++ } else { ++ EFRM_NOTICE("%s: MSI enabled", __func__); ++ nic->flags |= NIC_FLAG_MSI; ++ } ++ } ++ ++ if (request_irq(lnic->pci_dev->irq, linux_efrm_interrupt, ++ IRQF_SHARED, "sfc_resource", nic)) { ++ EFRM_ERR("Request for interrupt #%d failed", ++ lnic->pci_dev->irq); ++ nic->flags &= ~NIC_FLAG_OS_IRQ_EN; ++ return -EBUSY; ++ } ++ nic->flags |= NIC_FLAG_OS_IRQ_EN; ++ ++ return 0; ++} ++ ++void linux_efrm_irq_dtor(struct linux_efhw_nic *lnic) ++{ ++ EFRM_TRACE("%s: start", __func__); ++ ++ if (lnic->efrm_nic.efhw_nic.flags & NIC_FLAG_OS_IRQ_EN) { ++ free_irq(lnic->pci_dev->irq, &lnic->efrm_nic.efhw_nic); ++ lnic->efrm_nic.efhw_nic.flags &= ~NIC_FLAG_OS_IRQ_EN; ++ } ++ ++ if (lnic->efrm_nic.efhw_nic.flags & NIC_FLAG_MSI) { ++ pci_disable_msi(lnic->pci_dev); ++ lnic->efrm_nic.efhw_nic.flags &= ~NIC_FLAG_MSI; ++ } ++ ++ EFRM_TRACE("%s: done", __func__); ++} ++ ++/* Allocate buffer table entries for a particular NIC. ++ */ ++static int efrm_nic_buffer_table_alloc(struct efhw_nic *nic) ++{ ++ int capacity; ++ int page_order; ++ int rc; ++ ++ /* Choose queue size. */ ++ for (capacity = 8192; capacity <= nic->evq_sizes; capacity <<= 1) { ++ if (capacity > nic->evq_sizes) { ++ EFRM_ERR ++ ("%s: Unable to choose EVQ size (supported=%x)", ++ __func__, nic->evq_sizes); ++ return -E2BIG; ++ } else if (capacity & nic->evq_sizes) ++ break; ++ } ++ ++ nic->interrupting_evq.hw.capacity = capacity; ++ nic->interrupting_evq.hw.buf_tbl_alloc.base = (unsigned)-1; ++ ++ nic->non_interrupting_evq.hw.capacity = capacity; ++ nic->non_interrupting_evq.hw.buf_tbl_alloc.base = (unsigned)-1; ++ ++ /* allocate buffer table entries to map onto the iobuffer */ ++ page_order = get_order(capacity * sizeof(efhw_event_t)); ++ if (!(nic->flags & NIC_FLAG_NO_INTERRUPT)) { ++ rc = efrm_buffer_table_alloc(page_order, ++ &nic->interrupting_evq ++ .hw.buf_tbl_alloc); ++ if (rc < 0) { ++ EFRM_WARN ++ ("%s: failed (%d) to alloc %d buffer table entries", ++ __func__, rc, page_order); ++ return rc; ++ } ++ } ++ rc = efrm_buffer_table_alloc(page_order, ++ &nic->non_interrupting_evq.hw. ++ buf_tbl_alloc); ++ if (rc < 0) { ++ EFRM_WARN ++ ("%s: failed (%d) to alloc %d buffer table entries", ++ __func__, rc, page_order); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++/* Free buffer table entries allocated for a particular NIC. ++ */ ++static void efrm_nic_buffer_table_free(struct efhw_nic *nic) ++{ ++ if (nic->interrupting_evq.hw.buf_tbl_alloc.base != (unsigned)-1) ++ efrm_buffer_table_free(&nic->interrupting_evq.hw ++ .buf_tbl_alloc); ++ if (nic->non_interrupting_evq.hw.buf_tbl_alloc.base != (unsigned)-1) ++ efrm_buffer_table_free(&nic->non_interrupting_evq ++ .hw.buf_tbl_alloc); ++} ++ ++static int iomap_bar(struct linux_efhw_nic *lnic, size_t len) ++{ ++ volatile char __iomem *ioaddr; ++ ++ ioaddr = ioremap_nocache(lnic->ctr_ap_pci_addr, len); ++ if (ioaddr == 0) ++ return -ENOMEM; ++ ++ lnic->efrm_nic.efhw_nic.bar_ioaddr = ioaddr; ++ return 0; ++} ++ ++static int linux_efhw_nic_map_ctr_ap(struct linux_efhw_nic *lnic) ++{ ++ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic; ++ int rc; ++ ++ rc = iomap_bar(lnic, nic->ctr_ap_bytes); ++ ++ /* Bug 5195: workaround for now. */ ++ if (rc != 0 && nic->ctr_ap_bytes > 16 * 1024 * 1024) { ++ /* Try half the size for now. */ ++ nic->ctr_ap_bytes /= 2; ++ EFRM_WARN("Bug 5195 WORKAROUND: retrying iomap of %d bytes", ++ nic->ctr_ap_bytes); ++ rc = iomap_bar(lnic, nic->ctr_ap_bytes); ++ } ++ ++ if (rc < 0) { ++ EFRM_ERR("Failed (%d) to map bar (%d bytes)", ++ rc, nic->ctr_ap_bytes); ++ return rc; ++ } ++ ++ return rc; ++} ++ ++int ++linux_efrm_nic_ctor(struct linux_efhw_nic *lnic, struct pci_dev *dev, ++ spinlock_t *reg_lock, ++ unsigned nic_flags, unsigned nic_options) ++{ ++ struct efhw_device_type dev_type; ++ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic; ++ u8 class_revision; ++ int rc; ++ ++ rc = pci_read_config_byte(dev, PCI_CLASS_REVISION, &class_revision); ++ if (rc != 0) { ++ EFRM_ERR("%s: pci_read_config_byte failed (%d)", ++ __func__, rc); ++ return rc; ++ } ++ ++ if (!efhw_device_type_init(&dev_type, dev->vendor, dev->device, ++ class_revision)) { ++ EFRM_ERR("%s: efhw_device_type_init failed %04x:%04x(%d)", ++ __func__, (unsigned) dev->vendor, ++ (unsigned) dev->device, (int) class_revision); ++ return -ENODEV; ++ } ++ ++ EFRM_NOTICE("attaching device type %04x:%04x %d:%c%d", ++ (unsigned) dev->vendor, (unsigned) dev->device, ++ dev_type.arch, dev_type.variant, dev_type.revision); ++ ++ /* Initialise the adapter-structure. */ ++ efhw_nic_init(nic, nic_flags, nic_options, dev_type); ++ lnic->pci_dev = dev; ++ ++ rc = pci_enable_device(dev); ++ if (rc < 0) { ++ EFRM_ERR("%s: pci_enable_device failed (%d)", ++ __func__, rc); ++ return rc; ++ } ++ ++ lnic->ctr_ap_pci_addr = pci_resource_start(dev, nic->ctr_ap_bar); ++ ++ if (!pci_dma_supported(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) { ++ EFRM_ERR("%s: pci_dma_supported(%lx) failed", __func__, ++ (unsigned long)EFHW_DMA_ADDRMASK); ++ return -ENODEV; ++ } ++ ++ if (pci_set_dma_mask(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) { ++ EFRM_ERR("%s: pci_set_dma_mask(%lx) failed", __func__, ++ (unsigned long)EFHW_DMA_ADDRMASK); ++ return -ENODEV; ++ } ++ ++ if (pci_set_consistent_dma_mask(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) { ++ EFRM_ERR("%s: pci_set_consistent_dma_mask(%lx) failed", ++ __func__, (unsigned long)EFHW_DMA_ADDRMASK); ++ return -ENODEV; ++ } ++ ++ rc = linux_efhw_nic_map_ctr_ap(lnic); ++ if (rc < 0) ++ return rc; ++ ++ /* By default struct efhw_nic contains its own lock for protecting ++ * access to nic registers. We override it with a pointer to the ++ * lock in the net driver. This is needed when resource and net ++ * drivers share a single PCI function (falcon B series). ++ */ ++ nic->reg_lock = reg_lock; ++ return 0; ++} ++ ++void linux_efrm_nic_dtor(struct linux_efhw_nic *lnic) ++{ ++ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic; ++ volatile char __iomem *bar_ioaddr = nic->bar_ioaddr; ++ ++ efhw_nic_dtor(nic); ++ ++ /* Unmap the bar. */ ++ EFRM_ASSERT(bar_ioaddr); ++ iounmap(bar_ioaddr); ++ nic->bar_ioaddr = 0; ++} ++ ++/**************************************************************************** ++ * ++ * efrm_tasklet - used to poll the eventq which may result in further callbacks ++ * ++ ****************************************************************************/ ++ ++static void efrm_tasklet(unsigned long pdev) ++{ ++ struct efhw_nic *nic = (struct efhw_nic *)pdev; ++ ++ EFRM_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT)); ++ ++ efhw_keventq_poll(nic, &nic->interrupting_evq); ++ EFRM_TRACE("%s: complete", __func__); ++} ++ ++/**************************************************************************** ++ * ++ * char driver specific interrupt callbacks -- run at hard IRQL ++ * ++ ****************************************************************************/ ++static void efrm_handle_eventq_irq(struct efhw_nic *nic, int evq) ++{ ++ /* NB. The interrupt must have already been acked (for legacy mode). */ ++ ++ EFRM_TRACE("%s: starting tasklet", __func__); ++ EFRM_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT)); ++ ++ tasklet_schedule(&linux_efhw_nic(nic)->tasklet); ++} ++ ++/* A count of how many NICs this driver knows about. */ ++static int n_nics_probed; ++ ++/**************************************************************************** ++ * ++ * efrm_nic_add: add the NIC to the resource driver ++ * ++ * NOTE: the flow of control through this routine is quite subtle ++ * because of the number of operations that can fail. We therefore ++ * take the apporaching of keeping the return code (rc) variable ++ * accurate, and only do operations while it is non-negative. Tear down ++ * is done at the end if rc is negative, depending on what has been set up ++ * by that point. ++ * ++ * So basically just make sure that any code you add checks rc>=0 before ++ * doing any work and you'll be fine. ++ * ++ ****************************************************************************/ ++int ++efrm_nic_add(struct pci_dev *dev, unsigned flags, const uint8_t *mac_addr, ++ struct linux_efhw_nic **lnic_out, spinlock_t *reg_lock, ++ int bt_min, int bt_lim, int non_irq_evq, ++ const struct vi_resource_dimensions *res_dim) ++{ ++ struct linux_efhw_nic *lnic = NULL; ++ struct efhw_nic *nic = NULL; ++ int count = 0, rc = 0, resources_init = 0; ++ int constructed = 0; ++ int registered_nic = 0; ++ int buffers_allocated = 0; ++ static unsigned nic_index; /* = 0; */ ++ ++ EFRM_TRACE("%s: device detected (Slot '%s', IRQ %d)", __func__, ++ pci_name(dev) ? pci_name(dev) : "?", dev->irq); ++ ++ /* Ensure that we have room for the new adapter-structure. */ ++ if (efrm_nic_tablep->nic_count == EFHW_MAX_NR_DEVS) { ++ EFRM_WARN("%s: WARNING: too many devices", __func__); ++ rc = -ENOMEM; ++ goto failed; ++ } ++ ++ if (n_nics_probed == 0) { ++ rc = efrm_resources_init(res_dim, bt_min, bt_lim); ++ if (rc != 0) ++ goto failed; ++ resources_init = 1; ++ } ++ ++ /* Allocate memory for the new adapter-structure. */ ++ lnic = kmalloc(sizeof(*lnic), GFP_KERNEL); ++ if (lnic == NULL) { ++ EFRM_ERR("%s: ERROR: failed to allocate memory", __func__); ++ rc = -ENOMEM; ++ goto failed; ++ } ++ memset(lnic, 0, sizeof(*lnic)); ++ nic = &lnic->efrm_nic.efhw_nic; ++ ++ lnic->ev_handlers = &ev_handler; ++ ++ /* OS specific hardware mappings */ ++ rc = linux_efrm_nic_ctor(lnic, dev, reg_lock, flags, nic_options); ++ if (rc < 0) { ++ EFRM_ERR("%s: ERROR: initialisation failed", __func__); ++ goto failed; ++ } ++ ++ constructed = 1; ++ ++ /* Tell the driver about the NIC - this needs to be done before the ++ resources managers get created below. Note we haven't initialised ++ the hardware yet, and I don't like doing this before the perhaps ++ unreliable hardware initialisation. However, there's quite a lot ++ of code to review if we wanted to hardware init before bringing ++ up the resource managers. */ ++ rc = efrm_driver_register_nic(&lnic->efrm_nic, nic_index, ++ /* TODO: ifindex */ nic_index); ++ if (rc < 0) { ++ EFRM_ERR("%s: cannot register nic %d with nic error code %d", ++ __func__, efrm_nic_tablep->nic_count, rc); ++ goto failed; ++ } ++ ++nic_index; ++ registered_nic = 1; ++ ++ rc = efrm_nic_buffer_table_alloc(nic); ++ if (rc < 0) ++ goto failed; ++ buffers_allocated = 1; ++ ++ /****************************************************/ ++ /* hardware bringup */ ++ /****************************************************/ ++ /* Detecting hardware can be a slightly unreliable process; ++ we want to make sure that we maximise our chances, so we ++ loop a few times until all is good. */ ++ for (count = 0; count < max_hardware_init_repeats; count++) { ++ rc = efhw_nic_init_hardware(nic, &ev_handler, mac_addr, ++ non_irq_evq); ++ if (rc >= 0) ++ break; ++ ++ /* pain */ ++ EFRM_ERR ++ ("error - hardware initialisation failed code %d, " ++ "attempt %d of %d", rc, count + 1, ++ max_hardware_init_repeats); ++ } ++ if (rc < 0) ++ goto failed; ++ ++ tasklet_init(&lnic->tasklet, efrm_tasklet, (ulong)nic); ++ ++ /* set up interrupt handlers (hard-irq) */ ++ nic->irq_handler = &efrm_handle_eventq_irq; ++ ++ /* this device can now take management interrupts */ ++ if (do_irq && !(nic->flags & NIC_FLAG_NO_INTERRUPT)) { ++ rc = linux_efrm_irq_ctor(lnic); ++ if (rc < 0) { ++ EFRM_ERR("Interrupt initialisation failed (%d)", rc); ++ goto failed; ++ } ++ efhw_nic_set_interrupt_moderation(nic, -1, irq_moderation); ++ efhw_nic_interrupt_enable(nic); ++ } ++ EFRM_TRACE("interrupts are %sregistered", do_irq ? "" : "not "); ++ ++ *lnic_out = lnic; ++ EFRM_ASSERT(rc == 0); ++ ++n_nics_probed; ++ return 0; ++ ++failed: ++ if (buffers_allocated) ++ efrm_nic_buffer_table_free(nic); ++ if (registered_nic) ++ efrm_driver_unregister_nic(&lnic->efrm_nic); ++ if (constructed) ++ linux_efrm_nic_dtor(lnic); ++ kfree(lnic); /* safe in any case */ ++ if (resources_init) ++ efrm_resources_fini(); ++ return rc; ++} ++ ++/**************************************************************************** ++ * ++ * efrm_nic_del: Remove the nic from the resource driver structures ++ * ++ ****************************************************************************/ ++void efrm_nic_del(struct linux_efhw_nic *lnic) ++{ ++ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic; ++ ++ EFRM_TRACE("%s:", __func__); ++ EFRM_ASSERT(nic); ++ ++ efrm_nic_buffer_table_free(nic); ++ ++ efrm_driver_unregister_nic(&lnic->efrm_nic); ++ ++ /* ++ * Synchronise here with any running ISR. ++ * Remove the OS handler. There should be no IRQs being generated ++ * by our NIC at this point. ++ */ ++ if (efhw_nic_have_functional_units(nic)) { ++ efhw_nic_close_interrupts(nic); ++ linux_efrm_irq_dtor(lnic); ++ tasklet_kill(&lnic->tasklet); ++ } ++ ++ /* Close down hardware and free resources. */ ++ linux_efrm_nic_dtor(lnic); ++ kfree(lnic); ++ ++ if (--n_nics_probed == 0) ++ efrm_resources_fini(); ++ ++ EFRM_TRACE("%s: done", __func__); ++} ++ ++/**************************************************************************** ++ * ++ * init_module: register as a PCI driver. ++ * ++ ****************************************************************************/ ++static int init_sfc_resource(void) ++{ ++ int rc = 0; ++ ++ EFRM_TRACE("%s: RESOURCE driver starting", __func__); ++ ++ efrm_driver_ctor(); ++ ++ /* Register the driver so that our 'probe' function is called for ++ * each EtherFabric device in the system. ++ */ ++ rc = efrm_driverlink_register(); ++ if (rc == -ENODEV) ++ EFRM_ERR("%s: no devices found", __func__); ++ if (rc < 0) ++ goto failed_driverlink; ++ ++ if (efrm_install_proc_entries() != 0) { ++ /* Do not fail, but print a warning */ ++ EFRM_WARN("%s: WARNING: failed to install /proc entries", ++ __func__); ++ } ++ ++ return 0; ++ ++failed_driverlink: ++ efrm_driver_dtor(); ++ return rc; ++} ++ ++/**************************************************************************** ++ * ++ * cleanup_module: module-removal entry-point ++ * ++ ****************************************************************************/ ++static void cleanup_sfc_resource(void) ++{ ++ efrm_uninstall_proc_entries(); ++ ++ efrm_driverlink_unregister(); ++ ++ /* Clean up char-driver specific initialisation. ++ - driver dtor can use both work queue and buffer table entries */ ++ efrm_driver_dtor(); ++ ++ EFRM_TRACE("%s: unloaded", __func__); ++} ++ ++module_init(init_sfc_resource); ++module_exit(cleanup_sfc_resource); +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/resource_manager.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/resource_manager.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,145 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains generic code for resources and resource managers. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++/********************************************************************** ++ * struct efrm_resource_manager ++ */ ++ ++void efrm_resource_manager_dtor(struct efrm_resource_manager *rm) ++{ ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm); ++ ++ /* call destructor */ ++ EFRM_DO_DEBUG(if (rm->rm_resources) ++ EFRM_ERR("%s: %s leaked %d resources", ++ __func__, rm->rm_name, rm->rm_resources)); ++ EFRM_ASSERT(rm->rm_resources == 0); ++ EFRM_ASSERT(list_empty(&rm->rm_resources_list)); ++ ++ rm->rm_dtor(rm); ++ ++ /* clear out things built by efrm_resource_manager_ctor */ ++ spin_lock_destroy(&rm->rm_lock); ++ ++ /* and the free the memory */ ++ EFRM_DO_DEBUG(memset(rm, 0, sizeof(*rm))); ++ kfree(rm); ++} ++ ++/* Construct a resource manager. Resource managers are singletons. */ ++int ++efrm_resource_manager_ctor(struct efrm_resource_manager *rm, ++ void (*dtor)(struct efrm_resource_manager *), ++ const char *name, unsigned type) ++{ ++ EFRM_ASSERT(rm); ++ EFRM_ASSERT(dtor); ++ ++ rm->rm_name = name; ++ EFRM_DO_DEBUG(rm->rm_type = type); ++ rm->rm_dtor = dtor; ++ spin_lock_init(&rm->rm_lock); ++ rm->rm_resources = 0; ++ rm->rm_resources_hiwat = 0; ++ INIT_LIST_HEAD(&rm->rm_resources_list); ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm); ++ return 0; ++} ++ ++ ++void efrm_client_add_resource(struct efrm_client *client, ++ struct efrm_resource *rs) ++{ ++ struct efrm_resource_manager *rm; ++ irq_flags_t lock_flags; ++ ++ EFRM_ASSERT(client != NULL); ++ EFRM_ASSERT(rs != NULL); ++ ++ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags); ++ rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)]; ++ ++rm->rm_resources; ++ list_add(&rs->rs_manager_link, &rm->rm_resources_list); ++ if (rm->rm_resources > rm->rm_resources_hiwat) ++ rm->rm_resources_hiwat = rm->rm_resources; ++ rs->rs_client = client; ++ ++client->ref_count; ++ list_add(&rs->rs_client_link, &client->resources); ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags); ++} ++ ++ ++void efrm_resource_ref(struct efrm_resource *rs) ++{ ++ irq_flags_t lock_flags; ++ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags); ++ ++rs->rs_ref_count; ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags); ++} ++EXPORT_SYMBOL(efrm_resource_ref); ++ ++ ++int __efrm_resource_release(struct efrm_resource *rs) ++{ ++ struct efrm_resource_manager *rm; ++ irq_flags_t lock_flags; ++ int free_rs; ++ ++ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags); ++ free_rs = --rs->rs_ref_count == 0; ++ if (free_rs) { ++ rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)]; ++ EFRM_ASSERT(rm->rm_resources > 0); ++ --rm->rm_resources; ++ list_del(&rs->rs_manager_link); ++ list_del(&rs->rs_client_link); ++ } ++ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags); ++ return free_rs; ++} ++EXPORT_SYMBOL(__efrm_resource_release); ++ ++/* ++ * vi: sw=8:ai:aw ++ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/resources.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/resources.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,94 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains resource managers initialisation functions. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++ ++int ++efrm_resources_init(const struct vi_resource_dimensions *vi_res_dim, ++ int buffer_table_min, int buffer_table_lim) ++{ ++ int i, rc; ++ ++ rc = efrm_buffer_table_ctor(buffer_table_min, buffer_table_lim); ++ if (rc != 0) ++ return rc; ++ ++ /* Create resources in the correct order */ ++ for (i = 0; i < EFRM_RESOURCE_NUM; ++i) { ++ struct efrm_resource_manager **rmp = &efrm_rm_table[i]; ++ ++ EFRM_ASSERT(*rmp == NULL); ++ switch (i) { ++ case EFRM_RESOURCE_VI: ++ rc = efrm_create_vi_resource_manager(rmp, ++ vi_res_dim); ++ break; ++ case EFRM_RESOURCE_FILTER: ++ rc = efrm_create_filter_resource_manager(rmp); ++ break; ++ case EFRM_RESOURCE_IOBUFSET: ++ rc = efrm_create_iobufset_resource_manager(rmp); ++ break; ++ default: ++ rc = 0; ++ break; ++ } ++ ++ if (rc < 0) { ++ EFRM_ERR("%s: failed type=%d (%d)", ++ __func__, i, rc); ++ efrm_buffer_table_dtor(); ++ return rc; ++ } ++ } ++ ++ return 0; ++} ++ ++void efrm_resources_fini(void) ++{ ++ int i; ++ ++ for (i = EFRM_RESOURCE_NUM - 1; i >= 0; --i) ++ if (efrm_rm_table[i]) { ++ efrm_resource_manager_dtor(efrm_rm_table[i]); ++ efrm_rm_table[i] = NULL; ++ } ++ ++ efrm_buffer_table_dtor(); ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_alloc.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_alloc.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,820 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains allocation of VI resources. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++ ++/*** Data definitions ****************************************************/ ++ ++static const char *dmaq_names[] = { "TX", "RX" }; ++ ++struct vi_resource_manager *efrm_vi_manager; ++ ++/*** Forward references **************************************************/ ++ ++static int ++efrm_vi_resource_alloc_or_free(struct efrm_client *client, ++ int alloc, struct vi_resource *evq_virs, ++ uint16_t vi_flags, int32_t evq_capacity, ++ int32_t txq_capacity, int32_t rxq_capacity, ++ uint8_t tx_q_tag, uint8_t rx_q_tag, ++ struct vi_resource **virs_in_out); ++ ++/*** Reference count handling ********************************************/ ++ ++static inline void efrm_vi_rm_get_ref(struct vi_resource *virs) ++{ ++ atomic_inc(&virs->evq_refs); ++} ++ ++static inline void efrm_vi_rm_drop_ref(struct vi_resource *virs) ++{ ++ EFRM_ASSERT(atomic_read(&virs->evq_refs) != 0); ++ if (atomic_dec_and_test(&virs->evq_refs)) ++ efrm_vi_resource_alloc_or_free(virs->rs.rs_client, false, NULL, ++ 0, 0, 0, 0, 0, 0, &virs); ++} ++ ++/*** Instance numbers ****************************************************/ ++ ++static inline int efrm_vi_rm_alloc_id(uint16_t vi_flags, int32_t evq_capacity) ++{ ++ irq_flags_t lock_flags; ++ int instance; ++ int rc; ++ ++ if (efrm_nic_tablep->a_nic == NULL) /* ?? FIXME: surely not right */ ++ return -ENODEV; ++ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ /* Falcon A1 RX phys addr wierdness. */ ++ if (efrm_nic_tablep->a_nic->devtype.variant == 'A' && ++ (vi_flags & EFHW_VI_RX_PHYS_ADDR_EN)) { ++ if (vi_flags & EFHW_VI_JUMBO_EN) { ++ /* Falcon-A cannot do phys + scatter. */ ++ EFRM_WARN ++ ("%s: falcon-A does not support phys+scatter mode", ++ __func__); ++ instance = -1; ++ } else if (efrm_vi_manager->iscsi_dmaq_instance_is_free ++ && evq_capacity == 0) { ++ /* Falcon-A has a single RXQ that gives the correct ++ * semantics for physical addressing. However, it ++ * happens to have the same instance number as the ++ * 'char' event queue, so we cannot also hand out ++ * the event queue. */ ++ efrm_vi_manager->iscsi_dmaq_instance_is_free = false; ++ instance = FALCON_A1_ISCSI_DMAQ; ++ } else { ++ EFRM_WARN("%s: iSCSI receive queue not free", ++ __func__); ++ instance = -1; ++ } ++ goto unlock_out; ++ } ++ ++ if (vi_flags & EFHW_VI_RM_WITH_INTERRUPT) { ++ rc = __kfifo_get(efrm_vi_manager->instances_with_interrupt, ++ (unsigned char *)&instance, sizeof(instance)); ++ if (rc != sizeof(instance)) { ++ EFRM_ASSERT(rc == 0); ++ instance = -1; ++ } ++ goto unlock_out; ++ } ++ ++ /* Otherwise a normal run-of-the-mill VI. */ ++ rc = __kfifo_get(efrm_vi_manager->instances_with_timer, ++ (unsigned char *)&instance, sizeof(instance)); ++ if (rc != sizeof(instance)) { ++ EFRM_ASSERT(rc == 0); ++ instance = -1; ++ } ++ ++unlock_out: ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ return instance; ++} ++ ++static void efrm_vi_rm_free_id(int instance) ++{ ++ irq_flags_t lock_flags; ++ struct kfifo *instances; ++ ++ if (efrm_nic_tablep->a_nic == NULL) /* ?? FIXME: surely not right */ ++ return; ++ ++ if (efrm_nic_tablep->a_nic->devtype.variant == 'A' && ++ instance == FALCON_A1_ISCSI_DMAQ) { ++ EFRM_ASSERT(efrm_vi_manager->iscsi_dmaq_instance_is_free == ++ false); ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ efrm_vi_manager->iscsi_dmaq_instance_is_free = true; ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, ++ lock_flags); ++ } else { ++ if (instance >= efrm_vi_manager->with_timer_base && ++ instance < efrm_vi_manager->with_timer_limit) { ++ instances = efrm_vi_manager->instances_with_timer; ++ } else { ++ EFRM_ASSERT(instance >= ++ efrm_vi_manager->with_interrupt_base); ++ EFRM_ASSERT(instance < ++ efrm_vi_manager->with_interrupt_limit); ++ instances = efrm_vi_manager->instances_with_interrupt; ++ } ++ ++ EFRM_VERIFY_EQ(kfifo_put(instances, (unsigned char *)&instance, ++ sizeof(instance)), sizeof(instance)); ++ } ++} ++ ++/*** Queue sizes *********************************************************/ ++ ++/* NB. This should really take a nic as an argument, but that makes ++ * the buffer table allocation difficult. */ ++uint32_t efrm_vi_rm_evq_bytes(struct vi_resource *virs ++ /*,struct efhw_nic *nic */) ++{ ++ return virs->evq_capacity * sizeof(efhw_event_t); ++} ++EXPORT_SYMBOL(efrm_vi_rm_evq_bytes); ++ ++/* NB. This should really take a nic as an argument, but that makes ++ * the buffer table allocation difficult. */ ++uint32_t efrm_vi_rm_txq_bytes(struct vi_resource *virs ++ /*,struct efhw_nic *nic */) ++{ ++ return virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] * ++ FALCON_DMA_TX_DESC_BYTES; ++} ++EXPORT_SYMBOL(efrm_vi_rm_txq_bytes); ++ ++/* NB. This should really take a nic as an argument, but that makes ++ * the buffer table allocation difficult. */ ++uint32_t efrm_vi_rm_rxq_bytes(struct vi_resource *virs ++ /*,struct efhw_nic *nic */) ++{ ++ uint32_t bytes_per_desc = ((virs->flags & EFHW_VI_RX_PHYS_ADDR_EN) ++ ? FALCON_DMA_RX_PHYS_DESC_BYTES ++ : FALCON_DMA_RX_BUF_DESC_BYTES); ++ return virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] * bytes_per_desc; ++} ++EXPORT_SYMBOL(efrm_vi_rm_rxq_bytes); ++ ++static int choose_size(int size_rq, unsigned sizes) ++{ ++ int size; ++ ++ /* size_rq < 0 means default, but we interpret this as 'minimum'. */ ++ ++ for (size = 256;; size <<= 1) ++ if ((size & sizes) && size >= size_rq) ++ return size; ++ else if ((sizes & ~((size - 1) | size)) == 0) ++ return -1; ++} ++ ++static int ++efrm_vi_rm_adjust_alloc_request(struct vi_resource *virs, struct efhw_nic *nic) ++{ ++ int capacity; ++ ++ EFRM_ASSERT(nic->efhw_func); ++ ++ if (virs->evq_capacity) { ++ capacity = choose_size(virs->evq_capacity, nic->evq_sizes); ++ if (capacity < 0) { ++ EFRM_ERR("vi_resource: bad evq size %d (supported=%x)", ++ virs->evq_capacity, nic->evq_sizes); ++ return -E2BIG; ++ } ++ virs->evq_capacity = capacity; ++ } ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) { ++ capacity = ++ choose_size(virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX], ++ nic->txq_sizes); ++ if (capacity < 0) { ++ EFRM_ERR("vi_resource: bad txq size %d (supported=%x)", ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX], ++ nic->txq_sizes); ++ return -E2BIG; ++ } ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] = capacity; ++ } ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) { ++ capacity = ++ choose_size(virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX], ++ nic->rxq_sizes); ++ if (capacity < 0) { ++ EFRM_ERR("vi_resource: bad rxq size %d (supported=%x)", ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX], ++ nic->rxq_sizes); ++ return -E2BIG; ++ } ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] = capacity; ++ } ++ ++ return 0; ++} ++ ++/* remove the reference to the event queue in this VI resource and decrement ++ the event queue's use count */ ++static inline void efrm_vi_rm_detach_evq(struct vi_resource *virs) ++{ ++ struct vi_resource *evq_virs; ++ ++ EFRM_ASSERT(virs != NULL); ++ ++ evq_virs = virs->evq_virs; ++ ++ if (evq_virs != NULL) { ++ virs->evq_virs = NULL; ++ if (evq_virs == virs) { ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT ++ " had internal event queue ", __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle)); ++ } else { ++ efrm_vi_rm_drop_ref(evq_virs); ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " had event queue " ++ EFRM_RESOURCE_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle), ++ EFRM_RESOURCE_PRI_ARG(evq_virs->rs. ++ rs_handle)); ++ } ++ } else { ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT ++ " had no event queue (nothing to do)", ++ __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle)); ++ } ++} ++ ++/*** Buffer Table allocations ********************************************/ ++ ++static int ++efrm_vi_rm_alloc_or_free_buffer_table(struct vi_resource *virs, bool is_alloc) ++{ ++ uint32_t bytes; ++ int page_order; ++ int rc; ++ ++ if (!is_alloc) ++ goto destroy; ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) { ++ bytes = efrm_vi_rm_txq_bytes(virs); ++ page_order = get_order(bytes); ++ rc = efrm_buffer_table_alloc(page_order, ++ (virs->dmaq_buf_tbl_alloc + ++ EFRM_VI_RM_DMA_QUEUE_TX)); ++ if (rc != 0) { ++ EFRM_TRACE ++ ("%s: Error %d allocating TX buffer table entry", ++ __func__, rc); ++ goto fail_txq_alloc; ++ } ++ } ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) { ++ bytes = efrm_vi_rm_rxq_bytes(virs); ++ page_order = get_order(bytes); ++ rc = efrm_buffer_table_alloc(page_order, ++ (virs->dmaq_buf_tbl_alloc + ++ EFRM_VI_RM_DMA_QUEUE_RX)); ++ if (rc != 0) { ++ EFRM_TRACE ++ ("%s: Error %d allocating RX buffer table entry", ++ __func__, rc); ++ goto fail_rxq_alloc; ++ } ++ } ++ return 0; ++ ++destroy: ++ rc = 0; ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) { ++ efrm_buffer_table_free(&virs-> ++ dmaq_buf_tbl_alloc ++ [EFRM_VI_RM_DMA_QUEUE_RX]); ++ } ++fail_rxq_alloc: ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) { ++ efrm_buffer_table_free(&virs-> ++ dmaq_buf_tbl_alloc ++ [EFRM_VI_RM_DMA_QUEUE_TX]); ++ } ++fail_txq_alloc: ++ ++ return rc; ++} ++ ++/*** Per-NIC allocations *************************************************/ ++ ++static inline int ++efrm_vi_rm_init_evq(struct vi_resource *virs, struct efhw_nic *nic) ++{ ++ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ struct eventq_resource_hardware *evq_hw = ++ &virs->nic_info.evq_pages; ++ uint32_t buf_bytes = efrm_vi_rm_evq_bytes(virs); ++ int rc; ++ ++ if (virs->evq_capacity == 0) ++ return 0; ++ evq_hw->capacity = virs->evq_capacity; ++ ++ /* Allocate buffer table entries to map onto the iobuffer. This ++ * currently allocates its own buffer table entries on Falcon which is ++ * a bit wasteful on a multi-NIC system. */ ++ evq_hw->buf_tbl_alloc.base = (unsigned)-1; ++ rc = efrm_buffer_table_alloc(get_order(buf_bytes), ++ &evq_hw->buf_tbl_alloc); ++ if (rc < 0) { ++ EFHW_WARN("%s: failed (%d) to alloc %d buffer table entries", ++ __func__, rc, get_order(buf_bytes)); ++ return rc; ++ } ++ ++ /* Allocate the event queue memory. */ ++ rc = efhw_nic_event_queue_alloc_iobuffer(nic, evq_hw, instance, ++ buf_bytes); ++ if (rc != 0) { ++ EFRM_ERR("%s: Error allocating iobuffer: %d", __func__, rc); ++ efrm_buffer_table_free(&evq_hw->buf_tbl_alloc); ++ return rc; ++ } ++ ++ /* Initialise the event queue hardware */ ++ efhw_nic_event_queue_enable(nic, instance, virs->evq_capacity, ++ efhw_iopages_dma_addr(&evq_hw->iobuff) + ++ evq_hw->iobuff_off, ++ evq_hw->buf_tbl_alloc.base, ++ instance < 64); ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " capacity=%u", __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle), ++ virs->evq_capacity); ++ ++#if defined(__ia64__) ++ /* Page size may be large, so for now just increase the ++ * size of the requested evq up to a round number of ++ * pages ++ */ ++ buf_bytes = CI_ROUNDUP(buf_bytes, PAGE_SIZE); ++#endif ++ EFRM_ASSERT(buf_bytes % PAGE_SIZE == 0); ++ ++ virs->mem_mmap_bytes += buf_bytes; ++ ++ return 0; ++} ++ ++static inline void ++efrm_vi_rm_fini_evq(struct vi_resource *virs, struct efhw_nic *nic) ++{ ++ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ struct vi_resource_nic_info *nic_info = &virs->nic_info; ++ ++ if (virs->evq_capacity == 0) ++ return; ++ ++ /* Zero the timer-value for this queue. ++ And Tell NIC to stop using this event queue. */ ++ efhw_nic_event_queue_disable(nic, instance, 0); ++ ++ if (nic_info->evq_pages.buf_tbl_alloc.base != (unsigned)-1) ++ efrm_buffer_table_free(&nic_info->evq_pages.buf_tbl_alloc); ++ ++ efhw_iopages_free(nic, &nic_info->evq_pages.iobuff); ++} ++ ++/*! FIXME: we should make sure this number is never zero (=> unprotected) */ ++/*! FIXME: put this definition in a relevant header (e.g. as (evqid)+1) */ ++#define EFAB_EVQ_OWNER_ID(evqid) ((evqid)) ++ ++void ++efrm_vi_rm_init_dmaq(struct vi_resource *virs, int queue_type, ++ struct efhw_nic *nic) ++{ ++ int instance; ++ int evq_instance; ++ efhw_buffer_addr_t buf_addr; ++ ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ evq_instance = EFRM_RESOURCE_INSTANCE(virs->evq_virs->rs.rs_handle); ++ ++ buf_addr = virs->dmaq_buf_tbl_alloc[queue_type].base; ++ ++ if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX) { ++ efhw_nic_dmaq_tx_q_init(nic, ++ instance, /* dmaq */ ++ evq_instance, /* evq */ ++ EFAB_EVQ_OWNER_ID(evq_instance), /* owner */ ++ virs->dmaq_tag[queue_type], /* tag */ ++ virs->dmaq_capacity[queue_type], /* size of queue */ ++ buf_addr, /* buffer index */ ++ virs->flags); /* user specified Q attrs */ ++ } else { ++ efhw_nic_dmaq_rx_q_init(nic, ++ instance, /* dmaq */ ++ evq_instance, /* evq */ ++ EFAB_EVQ_OWNER_ID(evq_instance), /* owner */ ++ virs->dmaq_tag[queue_type], /* tag */ ++ virs->dmaq_capacity[queue_type], /* size of queue */ ++ buf_addr, /* buffer index */ ++ virs->flags); /* user specified Q attrs */ ++ } ++} ++ ++static int ++efrm_vi_rm_init_or_fini_dmaq(struct vi_resource *virs, ++ int queue_type, int init, ++ struct efhw_nic *nic) ++{ ++ int rc; ++ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ uint32_t buf_bytes; ++ struct vi_resource_nic_info *nic_info = &virs->nic_info; ++ int page_order; ++ uint32_t num_pages; ++ struct efhw_iopages *iobuff; ++ ++ if (!init) ++ goto destroy; ++ ++ /* Ignore disabled queues. */ ++ if (virs->dmaq_capacity[queue_type] == 0) { ++ if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX) ++ efhw_nic_dmaq_tx_q_disable(nic, instance); ++ else ++ efhw_nic_dmaq_rx_q_disable(nic, instance); ++ return 0; ++ } ++ ++ buf_bytes = (queue_type == EFRM_VI_RM_DMA_QUEUE_TX ++ ? efrm_vi_rm_txq_bytes(virs) ++ : efrm_vi_rm_rxq_bytes(virs)); ++ ++ page_order = get_order(buf_bytes); ++ ++ rc = efhw_iopages_alloc(nic, &nic_info->dmaq_pages[queue_type], ++ page_order); ++ if (rc != 0) { ++ EFRM_ERR("%s: Failed to allocate %s DMA buffer.", __func__, ++ dmaq_names[queue_type]); ++ goto fail_iopages; ++ } ++ ++ num_pages = 1 << page_order; ++ iobuff = &nic_info->dmaq_pages[queue_type]; ++ efhw_nic_buffer_table_set_n(nic, ++ virs->dmaq_buf_tbl_alloc[queue_type].base, ++ efhw_iopages_dma_addr(iobuff), ++ EFHW_NIC_PAGE_SIZE, 0, num_pages, 0); ++ ++ falcon_nic_buffer_table_confirm(nic); ++ ++ virs->mem_mmap_bytes += roundup(buf_bytes, PAGE_SIZE); ++ ++ /* Make sure there is an event queue. */ ++ if (virs->evq_virs->evq_capacity <= 0) { ++ EFRM_ERR("%s: Cannot use empty event queue for %s DMA", ++ __func__, dmaq_names[queue_type]); ++ rc = -EINVAL; ++ goto fail_evq; ++ } ++ ++ efrm_vi_rm_init_dmaq(virs, queue_type, nic); ++ ++ return 0; ++ ++destroy: ++ rc = 0; ++ ++ /* Ignore disabled queues. */ ++ if (virs->dmaq_capacity[queue_type] == 0) ++ return 0; ++ ++ /* Ensure TX pacing turned off -- queue flush doesn't reset this. */ ++ if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX) ++ falcon_nic_pace(nic, instance, 0); ++ ++ /* No need to disable the queue here. Nobody is using it anyway. */ ++ ++fail_evq: ++ efhw_iopages_free(nic, &nic_info->dmaq_pages[queue_type]); ++fail_iopages: ++ ++ return rc; ++} ++ ++static int ++efrm_vi_rm_init_or_fini_nic(struct vi_resource *virs, int init, ++ struct efhw_nic *nic) ++{ ++ int rc; ++#ifndef NDEBUG ++ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++#endif ++ ++ if (!init) ++ goto destroy; ++ ++ rc = efrm_vi_rm_init_evq(virs, nic); ++ if (rc != 0) ++ goto fail_evq; ++ ++ rc = efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX, ++ init, nic); ++ if (rc != 0) ++ goto fail_txq; ++ ++ rc = efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX, ++ init, nic); ++ if (rc != 0) ++ goto fail_rxq; ++ ++ /* Allocate space for the control page. */ ++ EFRM_ASSERT(falcon_tx_dma_page_offset(instance) < PAGE_SIZE); ++ EFRM_ASSERT(falcon_rx_dma_page_offset(instance) < PAGE_SIZE); ++ EFRM_ASSERT(falcon_timer_page_offset(instance) < PAGE_SIZE); ++ virs->bar_mmap_bytes += PAGE_SIZE; ++ ++ return 0; ++ ++destroy: ++ rc = 0; ++ ++ efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX, ++ false, nic); ++fail_rxq: ++ ++ efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX, ++ false, nic); ++fail_txq: ++ ++ efrm_vi_rm_fini_evq(virs, nic); ++fail_evq: ++ ++ EFRM_ASSERT(rc != 0 || !init); ++ return rc; ++} ++ ++static int ++efrm_vi_resource_alloc_or_free(struct efrm_client *client, ++ int alloc, struct vi_resource *evq_virs, ++ uint16_t vi_flags, int32_t evq_capacity, ++ int32_t txq_capacity, int32_t rxq_capacity, ++ uint8_t tx_q_tag, uint8_t rx_q_tag, ++ struct vi_resource **virs_in_out) ++{ ++ struct efhw_nic *nic = client->nic; ++ struct vi_resource *virs; ++ int rc; ++ int instance; ++ ++ EFRM_ASSERT(virs_in_out); ++ EFRM_ASSERT(efrm_vi_manager); ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_vi_manager->rm); ++ ++ if (!alloc) ++ goto destroy; ++ ++ rx_q_tag &= (1 << TX_DESCQ_LABEL_WIDTH) - 1; ++ tx_q_tag &= (1 << RX_DESCQ_LABEL_WIDTH) - 1; ++ ++ virs = kmalloc(sizeof(*virs), GFP_KERNEL); ++ if (virs == NULL) { ++ EFRM_ERR("%s: Error allocating VI resource object", ++ __func__); ++ rc = -ENOMEM; ++ goto fail_alloc; ++ } ++ memset(virs, 0, sizeof(*virs)); ++ ++ /* Some macros make the assumption that the struct efrm_resource is ++ * the first member of a struct vi_resource. */ ++ EFRM_ASSERT(&virs->rs == (struct efrm_resource *) (virs)); ++ ++ instance = efrm_vi_rm_alloc_id(vi_flags, evq_capacity); ++ if (instance < 0) { ++ /* Clear out the close list... */ ++ efrm_vi_rm_salvage_flushed_vis(); ++ instance = efrm_vi_rm_alloc_id(vi_flags, evq_capacity); ++ if (instance >= 0) ++ EFRM_TRACE("%s: Salvaged a closed VI.", __func__); ++ } ++ ++ if (instance < 0) { ++ /* Could flush resources and try again here. */ ++ EFRM_ERR("%s: Out of appropriate VI resources", __func__); ++ rc = -EBUSY; ++ goto fail_alloc_id; ++ } ++ ++ EFRM_TRACE("%s: new VI ID %d", __func__, instance); ++ efrm_resource_init(&virs->rs, EFRM_RESOURCE_VI, instance); ++ ++ /* Start with one reference. Any external VIs using the EVQ of this ++ * resource will increment this reference rather than the resource ++ * reference to avoid DMAQ flushes from waiting for other DMAQ ++ * flushes to complete. When the resource reference goes to zero, ++ * the DMAQ flush happens. When the flush completes, this reference ++ * is decremented. When this reference reaches zero, the instance ++ * is freed. */ ++ atomic_set(&virs->evq_refs, 1); ++ ++ virs->bar_mmap_bytes = 0; ++ virs->mem_mmap_bytes = 0; ++ virs->evq_capacity = evq_capacity; ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] = txq_capacity; ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] = rxq_capacity; ++ virs->dmaq_tag[EFRM_VI_RM_DMA_QUEUE_TX] = tx_q_tag; ++ virs->dmaq_tag[EFRM_VI_RM_DMA_QUEUE_RX] = rx_q_tag; ++ virs->flags = vi_flags; ++ INIT_LIST_HEAD(&virs->tx_flush_link); ++ INIT_LIST_HEAD(&virs->rx_flush_link); ++ virs->tx_flushing = 0; ++ virs->rx_flushing = 0; ++ ++ /* Adjust the queue sizes. */ ++ rc = efrm_vi_rm_adjust_alloc_request(virs, nic); ++ if (rc != 0) ++ goto fail_adjust_request; ++ ++ /* Attach the EVQ early so that we can ensure that the NIC sets ++ * match. */ ++ if (evq_virs == NULL) { ++ evq_virs = virs; ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT ++ " has no external event queue", __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle)); ++ } else { ++ /* Make sure the resource managers are the same. */ ++ if (EFRM_RESOURCE_TYPE(evq_virs->rs.rs_handle) != ++ EFRM_RESOURCE_VI) { ++ EFRM_ERR("%s: Mismatched owner for event queue VI " ++ EFRM_RESOURCE_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(evq_virs->rs.rs_handle)); ++ return -EINVAL; ++ } ++ EFRM_ASSERT(atomic_read(&evq_virs->evq_refs) != 0); ++ efrm_vi_rm_get_ref(evq_virs); ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " uses event queue " ++ EFRM_RESOURCE_FMT, ++ __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle), ++ EFRM_RESOURCE_PRI_ARG(evq_virs->rs.rs_handle)); ++ } ++ virs->evq_virs = evq_virs; ++ ++ rc = efrm_vi_rm_alloc_or_free_buffer_table(virs, true); ++ if (rc != 0) ++ goto fail_buffer_table; ++ ++ rc = efrm_vi_rm_init_or_fini_nic(virs, true, nic); ++ if (rc != 0) ++ goto fail_init_nic; ++ ++ efrm_client_add_resource(client, &virs->rs); ++ *virs_in_out = virs; ++ EFRM_TRACE("%s: Allocated " EFRM_RESOURCE_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle)); ++ return 0; ++ ++destroy: ++ virs = *virs_in_out; ++ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 1); ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ ++ EFRM_TRACE("%s: Freeing %d", __func__, ++ EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)); ++ ++ /* Destroying the VI. The reference count must be zero. */ ++ EFRM_ASSERT(atomic_read(&virs->evq_refs) == 0); ++ ++ /* The EVQ should have gone (and DMA disabled) so that this ++ * function can't be re-entered to destroy the EVQ VI. */ ++ EFRM_ASSERT(virs->evq_virs == NULL); ++ rc = 0; ++ ++fail_init_nic: ++ efrm_vi_rm_init_or_fini_nic(virs, false, nic); ++ ++ efrm_vi_rm_alloc_or_free_buffer_table(virs, false); ++fail_buffer_table: ++ ++ efrm_vi_rm_detach_evq(virs); ++ ++fail_adjust_request: ++ ++ EFRM_ASSERT(virs->evq_callback_fn == NULL); ++ EFRM_TRACE("%s: delete VI ID %d", __func__, instance); ++ efrm_vi_rm_free_id(instance); ++fail_alloc_id: ++ if (!alloc) ++ efrm_client_put(virs->rs.rs_client); ++ EFRM_DO_DEBUG(memset(virs, 0, sizeof(*virs))); ++ kfree(virs); ++fail_alloc: ++ *virs_in_out = NULL; ++ ++ return rc; ++} ++ ++/*** Resource object ****************************************************/ ++ ++int ++efrm_vi_resource_alloc(struct efrm_client *client, ++ struct vi_resource *evq_virs, ++ uint16_t vi_flags, int32_t evq_capacity, ++ int32_t txq_capacity, int32_t rxq_capacity, ++ uint8_t tx_q_tag, uint8_t rx_q_tag, ++ struct vi_resource **virs_out, ++ uint32_t *out_io_mmap_bytes, ++ uint32_t *out_mem_mmap_bytes, ++ uint32_t *out_txq_capacity, uint32_t *out_rxq_capacity) ++{ ++ int rc; ++ EFRM_ASSERT(client != NULL); ++ rc = efrm_vi_resource_alloc_or_free(client, true, evq_virs, vi_flags, ++ evq_capacity, txq_capacity, ++ rxq_capacity, tx_q_tag, rx_q_tag, ++ virs_out); ++ if (rc == 0) { ++ if (out_io_mmap_bytes != NULL) ++ *out_io_mmap_bytes = (*virs_out)->bar_mmap_bytes; ++ if (out_mem_mmap_bytes != NULL) ++ *out_mem_mmap_bytes = (*virs_out)->mem_mmap_bytes; ++ if (out_txq_capacity != NULL) ++ *out_txq_capacity = ++ (*virs_out)->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]; ++ if (out_rxq_capacity != NULL) ++ *out_rxq_capacity = ++ (*virs_out)->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]; ++ } ++ ++ return rc; ++} ++EXPORT_SYMBOL(efrm_vi_resource_alloc); ++ ++void efrm_vi_rm_free_flushed_resource(struct vi_resource *virs) ++{ ++ EFRM_ASSERT(virs != NULL); ++ EFRM_ASSERT(virs->rs.rs_ref_count == 0); ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle)); ++ /* release the associated event queue then drop our own reference ++ * count */ ++ efrm_vi_rm_detach_evq(virs); ++ efrm_vi_rm_drop_ref(virs); ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_event.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_event.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,250 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains event handling for VI resource. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++ ++static inline int ++efrm_eventq_bytes(struct vi_resource *virs) ++{ ++ return efrm_vi_rm_evq_bytes(virs); ++} ++ ++ ++static inline efhw_event_t * ++efrm_eventq_base(struct vi_resource *virs) ++{ ++ struct eventq_resource_hardware *hw; ++ hw = &(virs->nic_info.evq_pages); ++ return (efhw_event_t *) (efhw_iopages_ptr(&(hw->iobuff)) + ++ hw->iobuff_off); ++} ++ ++ ++void ++efrm_eventq_request_wakeup(struct vi_resource *virs, unsigned current_ptr) ++{ ++ struct efhw_nic *nic = virs->rs.rs_client->nic; ++ int next_i; ++ next_i = ((current_ptr / sizeof(efhw_event_t)) & ++ (virs->evq_capacity - 1)); ++ ++ efhw_nic_wakeup_request(nic, efrm_eventq_dma_addr(virs), next_i, ++ EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)); ++} ++EXPORT_SYMBOL(efrm_eventq_request_wakeup); ++ ++void efrm_eventq_reset(struct vi_resource *virs) ++{ ++ struct efhw_nic *nic = virs->rs.rs_client->nic; ++ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ ++ EFRM_ASSERT(virs->evq_capacity != 0); ++ ++ /* FIXME: Protect against concurrent resets. */ ++ ++ efhw_nic_event_queue_disable(nic, instance, 0); ++ ++ memset(efrm_eventq_base(virs), EFHW_CLEAR_EVENT_VALUE, ++ efrm_eventq_bytes(virs)); ++ efhw_nic_event_queue_enable(nic, instance, virs->evq_capacity, ++ efrm_eventq_dma_addr(virs), ++ virs->nic_info.evq_pages. ++ buf_tbl_alloc.base, ++ instance < 64); ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle)); ++} ++EXPORT_SYMBOL(efrm_eventq_reset); ++ ++int ++efrm_eventq_register_callback(struct vi_resource *virs, ++ void (*handler) (void *, int, ++ struct efhw_nic *nic), ++ void *arg) ++{ ++ struct efrm_nic_per_vi *cb_info; ++ int instance; ++ int bit; ++ ++ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0); ++ EFRM_ASSERT(virs->evq_capacity != 0); ++ EFRM_ASSERT(handler != NULL); ++ ++ /* ?? TODO: Get rid of this test when client is compulsory. */ ++ if (virs->rs.rs_client == NULL) { ++ EFRM_ERR("%s: no client", __func__); ++ return -EINVAL; ++ } ++ ++ virs->evq_callback_arg = arg; ++ virs->evq_callback_fn = handler; ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ cb_info = &efrm_nic(virs->rs.rs_client->nic)->vis[instance]; ++ ++ /* The handler can be set only once. */ ++ bit = test_and_set_bit(VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED, ++ &cb_info->state); ++ if (bit) ++ return -EBUSY; ++ cb_info->vi = virs; ++ ++ return 0; ++} ++EXPORT_SYMBOL(efrm_eventq_register_callback); ++ ++void efrm_eventq_kill_callback(struct vi_resource *virs) ++{ ++ struct efrm_nic_per_vi *cb_info; ++ int32_t evq_state; ++ int instance; ++ int bit; ++ ++ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0); ++ EFRM_ASSERT(virs->evq_capacity != 0); ++ EFRM_ASSERT(virs->rs.rs_client != NULL); ++ ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ cb_info = &efrm_nic(virs->rs.rs_client->nic)->vis[instance]; ++ cb_info->vi = NULL; ++ ++ /* Disable the timer. */ ++ efhw_nic_event_queue_disable(virs->rs.rs_client->nic, ++ instance, /*timer_only */ 1); ++ ++ /* Disable the callback. */ ++ bit = test_and_clear_bit(VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED, ++ &cb_info->state); ++ EFRM_ASSERT(bit); /* do not call me twice! */ ++ ++ /* Spin until the callback is complete. */ ++ do { ++ rmb(); ++ ++ udelay(1); ++ evq_state = cb_info->state; ++ } while ((evq_state & VI_RESOURCE_EVQ_STATE(BUSY))); ++ ++ virs->evq_callback_fn = NULL; ++} ++EXPORT_SYMBOL(efrm_eventq_kill_callback); ++ ++static void ++efrm_eventq_do_callback(struct efhw_nic *nic, unsigned instance, ++ bool is_timeout) ++{ ++ struct efrm_nic *rnic = efrm_nic(nic); ++ void (*handler) (void *, int is_timeout, struct efhw_nic *nic); ++ void *arg; ++ struct efrm_nic_per_vi *cb_info; ++ int32_t evq_state; ++ int32_t new_evq_state; ++ struct vi_resource *virs; ++ int bit; ++ ++ EFRM_ASSERT(efrm_vi_manager); ++ ++ cb_info = &rnic->vis[instance]; ++ ++ /* Set the BUSY bit and clear WAKEUP_PENDING. Do this ++ * before waking up the sleeper to avoid races. */ ++ while (1) { ++ evq_state = cb_info->state; ++ new_evq_state = evq_state; ++ ++ if ((evq_state & VI_RESOURCE_EVQ_STATE(BUSY)) != 0) { ++ EFRM_ERR("%s:%d: evq_state[%d] corrupted!", ++ __func__, __LINE__, instance); ++ return; ++ } ++ ++ if (!is_timeout) ++ new_evq_state &= ~VI_RESOURCE_EVQ_STATE(WAKEUP_PENDING); ++ ++ if (evq_state & VI_RESOURCE_EVQ_STATE(CALLBACK_REGISTERED)) { ++ new_evq_state |= VI_RESOURCE_EVQ_STATE(BUSY); ++ virs = cb_info->vi; ++ if (cmpxchg(&cb_info->state, evq_state, ++ new_evq_state) == evq_state) ++ break; ++ } else { ++ /* Just update the state if necessary. */ ++ if (new_evq_state == evq_state || ++ cmpxchg(&cb_info->state, evq_state, ++ new_evq_state) == evq_state) ++ return; ++ } ++ } ++ ++ if (virs) { ++ handler = virs->evq_callback_fn; ++ arg = virs->evq_callback_arg; ++ EFRM_ASSERT(handler != NULL); ++ handler(arg, is_timeout, nic); ++ } ++ ++ /* Clear the BUSY bit. */ ++ bit = ++ test_and_clear_bit(VI_RESOURCE_EVQ_STATE_BUSY, ++ &cb_info->state); ++ if (!bit) { ++ EFRM_ERR("%s:%d: evq_state corrupted!", ++ __func__, __LINE__); ++ } ++} ++ ++void efrm_handle_wakeup_event(struct efhw_nic *nic, unsigned instance) ++{ ++ efrm_eventq_do_callback(nic, instance, false); ++} ++ ++void efrm_handle_timeout_event(struct efhw_nic *nic, unsigned instance) ++{ ++ efrm_eventq_do_callback(nic, instance, true); ++} ++ ++void efrm_handle_sram_event(struct efhw_nic *nic) ++{ ++ if (nic->buf_commit_outstanding > 0) ++ nic->buf_commit_outstanding--; ++} +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_flush.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_flush.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,483 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains DMA queue flushing of VI resources. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++ ++/* can fail as workitem can already be scheuled -- ignore failure */ ++#define EFRM_VI_RM_DELAYED_FREE(manager) \ ++ queue_work(manager->workqueue, &manager->work_item) ++ ++static const int flush_fifo_hwm = 8 /* TODO should be a HW specific const */ ; ++ ++static void ++efrm_vi_resource_rx_flush_done(struct vi_resource *virs, bool *completed) ++{ ++ /* We should only get a flush event if there is a flush ++ * outstanding. */ ++ EFRM_ASSERT(virs->rx_flush_outstanding); ++ ++ virs->rx_flush_outstanding = 0; ++ virs->rx_flushing = 0; ++ ++ list_del(&virs->rx_flush_link); ++ efrm_vi_manager->rx_flush_outstanding_count--; ++ ++ if (virs->tx_flushing == 0) { ++ list_add_tail(&virs->rx_flush_link, ++ &efrm_vi_manager->close_pending); ++ *completed = 1; ++ } ++} ++ ++static void ++efrm_vi_resource_tx_flush_done(struct vi_resource *virs, bool *completed) ++{ ++ /* We should only get a flush event if there is a flush ++ * outstanding. */ ++ EFRM_ASSERT(virs->tx_flushing); ++ ++ virs->tx_flushing = 0; ++ ++ list_del(&virs->tx_flush_link); ++ ++ if (virs->rx_flushing == 0) { ++ list_add_tail(&virs->rx_flush_link, ++ &efrm_vi_manager->close_pending); ++ *completed = 1; ++ } ++} ++ ++static void ++efrm_vi_resource_issue_rx_flush(struct vi_resource *virs, bool *completed) ++{ ++ struct efhw_nic *nic = virs->rs.rs_client->nic; ++ int instance; ++ int rc; ++ ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ ++ list_add_tail(&virs->rx_flush_link, ++ &efrm_vi_manager->rx_flush_outstanding_list); ++ virs->rx_flush_outstanding = virs->rx_flushing; ++ efrm_vi_manager->rx_flush_outstanding_count++; ++ ++ EFRM_TRACE("%s: rx queue %d flush requested for nic %d", ++ __func__, instance, nic->index); ++ rc = efhw_nic_flush_rx_dma_channel(nic, instance); ++ if (rc == -EAGAIN) ++ efrm_vi_resource_rx_flush_done(virs, completed); ++} ++ ++static void ++efrm_vi_resource_issue_tx_flush(struct vi_resource *virs, bool *completed) ++{ ++ struct efhw_nic *nic = virs->rs.rs_client->nic; ++ int instance; ++ int rc; ++ ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ ++ list_add_tail(&virs->tx_flush_link, ++ &efrm_vi_manager->tx_flush_outstanding_list); ++ ++ EFRM_TRACE("%s: tx queue %d flush requested for nic %d", ++ __func__, instance, nic->index); ++ rc = efhw_nic_flush_tx_dma_channel(nic, instance); ++ if (rc == -EAGAIN) ++ efrm_vi_resource_tx_flush_done(virs, completed); ++} ++ ++static void efrm_vi_resource_process_waiting_flushes(bool *completed) ++{ ++ struct vi_resource *virs; ++ ++ while (efrm_vi_manager->rx_flush_outstanding_count < flush_fifo_hwm && ++ !list_empty(&efrm_vi_manager->rx_flush_waiting_list)) { ++ virs = ++ list_entry(list_pop ++ (&efrm_vi_manager->rx_flush_waiting_list), ++ struct vi_resource, rx_flush_link); ++ efrm_vi_resource_issue_rx_flush(virs, completed); ++ } ++} ++ ++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND ++static void ++efrm_vi_resource_flush_retry_vi(struct vi_resource *virs, ++ int64_t time_now, bool *completed) ++{ ++ struct efhw_nic *nic; ++ int instance; ++ ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ ++ virs->flush_count++; ++ virs->flush_time = time_now; ++ nic = virs->rs.rs_client->nic; ++ ++#if BUG7916_WORKAROUND ++ if (virs->rx_flush_outstanding) { ++ EFRM_TRACE("%s: Retrying RX flush on instance %d", ++ __func__, instance); ++ ++ list_del(&virs->rx_flush_link); ++ efrm_vi_manager->rx_flush_outstanding_count--; ++ efrm_vi_resource_issue_rx_flush(virs, completed); ++ efrm_vi_resource_process_waiting_flushes(completed); ++ } ++#endif ++ ++#if BUG5302_WORKAROUND ++ if (virs->tx_flushing) { ++ if (virs->flush_count > 5) { ++ EFRM_TRACE("%s: VI resource stuck flush pending " ++ "(instance=%d, count=%d)", ++ __func__, instance, virs->flush_count); ++ falcon_clobber_tx_dma_ptrs(nic, instance); ++ } else { ++ EFRM_TRACE("%s: Retrying TX flush on instance %d", ++ __func__, instance); ++ } ++ ++ list_del(&virs->tx_flush_link); ++ efrm_vi_resource_issue_tx_flush(virs, completed); ++ } ++#endif ++} ++#endif ++ ++int efrm_vi_resource_flush_retry(struct vi_resource *virs) ++{ ++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND ++ irq_flags_t lock_flags; ++ bool completed = false; ++ ++ if (virs->rx_flushing == 0 && virs->tx_flushing == 0) ++ return -EALREADY; ++ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ efrm_vi_resource_flush_retry_vi(virs, get_jiffies_64(), &completed); ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ if (completed) ++ EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager); ++#endif ++ ++ return 0; ++} ++EXPORT_SYMBOL(efrm_vi_resource_flush_retry); ++ ++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND ++/* resource manager lock should be taken before this call */ ++static void efrm_vi_handle_flush_loss(bool *completed) ++{ ++ struct list_head *pos, *temp; ++ struct vi_resource *virs; ++ int64_t time_now, time_pending; ++ ++ /* It's possible we miss flushes - the list is sorted in order we ++ * generate flushes, see if any are very old. It's also possible ++ * that we decide an endpoint is flushed even though we've not ++ * received all the flush events. We *should * mark as ++ * completed, reclaim and loop again. ?? ++ * THIS NEEDS BACKPORTING FROM THE FALCON branch ++ */ ++ time_now = get_jiffies_64(); ++ ++#if BUG7916_WORKAROUND ++ list_for_each_safe(pos, temp, ++ &efrm_vi_manager->rx_flush_outstanding_list) { ++ virs = container_of(pos, struct vi_resource, rx_flush_link); ++ ++ time_pending = time_now - virs->flush_time; ++ ++ /* List entries are held in reverse chronological order. Only ++ * process the old ones. */ ++ if (time_pending <= 0x100000000LL) ++ break; ++ ++ efrm_vi_resource_flush_retry_vi(virs, time_now, completed); ++ } ++#endif ++ ++#if BUG5302_WORKAROUND ++ list_for_each_safe(pos, temp, ++ &efrm_vi_manager->tx_flush_outstanding_list) { ++ virs = container_of(pos, struct vi_resource, tx_flush_link); ++ ++ time_pending = time_now - virs->flush_time; ++ ++ /* List entries are held in reverse chronological order. ++ * Only process the old ones. */ ++ if (time_pending <= 0x100000000LL) ++ break; ++ ++ efrm_vi_resource_flush_retry_vi(virs, time_now, completed); ++ } ++#endif ++} ++#endif ++ ++void ++efrm_vi_register_flush_callback(struct vi_resource *virs, ++ void (*handler)(void *), void *arg) ++{ ++ if (handler == NULL) { ++ virs->flush_callback_fn = handler; ++ wmb(); ++ virs->flush_callback_arg = arg; ++ } else { ++ virs->flush_callback_arg = arg; ++ wmb(); ++ virs->flush_callback_fn = handler; ++ } ++} ++EXPORT_SYMBOL(efrm_vi_register_flush_callback); ++ ++int efrm_pt_flush(struct vi_resource *virs) ++{ ++ int instance; ++ irq_flags_t lock_flags; ++ bool completed = false; ++ ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ ++ EFRM_ASSERT(virs->rx_flushing == 0); ++ EFRM_ASSERT(virs->rx_flush_outstanding == 0); ++ EFRM_ASSERT(virs->tx_flushing == 0); ++ ++ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " EVQ=%d TXQ=%d RXQ=%d", ++ __func__, EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle), ++ virs->evq_capacity, ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX], ++ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]); ++ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] != 0) ++ virs->rx_flushing = 1; ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] != 0) ++ virs->tx_flushing = 1; ++ ++ /* Clean up immediately if there are no flushes. */ ++ if (virs->rx_flushing == 0 && virs->tx_flushing == 0) { ++ list_add_tail(&virs->rx_flush_link, ++ &efrm_vi_manager->close_pending); ++ completed = true; ++ } ++ ++ /* Issue the RX flush if possible or queue it for later. */ ++ if (virs->rx_flushing) { ++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND ++ if (efrm_vi_manager->rx_flush_outstanding_count >= ++ flush_fifo_hwm) ++ efrm_vi_handle_flush_loss(&completed); ++#endif ++ if (efrm_vi_manager->rx_flush_outstanding_count >= ++ flush_fifo_hwm) { ++ list_add_tail(&virs->rx_flush_link, ++ &efrm_vi_manager->rx_flush_waiting_list); ++ } else { ++ efrm_vi_resource_issue_rx_flush(virs, &completed); ++ } ++ } ++ ++ /* Issue the TX flush. There's no limit to the number of ++ * outstanding TX flushes. */ ++ if (virs->tx_flushing) ++ efrm_vi_resource_issue_tx_flush(virs, &completed); ++ ++ virs->flush_time = get_jiffies_64(); ++ ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ if (completed) ++ EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager); ++ ++ return 0; ++} ++EXPORT_SYMBOL(efrm_pt_flush); ++ ++static void ++efrm_handle_rx_dmaq_flushed(struct efhw_nic *flush_nic, int instance, ++ bool *completed) ++{ ++ struct list_head *pos, *temp; ++ struct vi_resource *virs; ++ ++ list_for_each_safe(pos, temp, ++ &efrm_vi_manager->rx_flush_outstanding_list) { ++ virs = container_of(pos, struct vi_resource, rx_flush_link); ++ ++ if (instance == EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)) { ++ efrm_vi_resource_rx_flush_done(virs, completed); ++ efrm_vi_resource_process_waiting_flushes(completed); ++ return; ++ } ++ } ++ EFRM_TRACE("%s: Unhandled rx flush event, nic %d, instance %d", ++ __func__, flush_nic->index, instance); ++} ++ ++static void ++efrm_handle_tx_dmaq_flushed(struct efhw_nic *flush_nic, int instance, ++ bool *completed) ++{ ++ struct list_head *pos, *temp; ++ struct vi_resource *virs; ++ ++ list_for_each_safe(pos, temp, ++ &efrm_vi_manager->tx_flush_outstanding_list) { ++ virs = container_of(pos, struct vi_resource, tx_flush_link); ++ ++ if (instance == EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)) { ++ efrm_vi_resource_tx_flush_done(virs, completed); ++ return; ++ } ++ } ++ EFRM_TRACE("%s: Unhandled tx flush event, nic %d, instance %d", ++ __func__, flush_nic->index, instance); ++} ++ ++void ++efrm_handle_dmaq_flushed(struct efhw_nic *flush_nic, unsigned instance, ++ int rx_flush) ++{ ++ irq_flags_t lock_flags; ++ bool completed = false; ++ ++ EFRM_TRACE("%s: nic_i=%d instance=%d rx_flush=%d", __func__, ++ flush_nic->index, instance, rx_flush); ++ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ if (rx_flush) ++ efrm_handle_rx_dmaq_flushed(flush_nic, instance, &completed); ++ else ++ efrm_handle_tx_dmaq_flushed(flush_nic, instance, &completed); ++ ++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND ++ efrm_vi_handle_flush_loss(&completed); ++#endif ++ ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ if (completed) ++ EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager); ++} ++ ++static void ++efrm_vi_rm_reinit_dmaqs(struct vi_resource *virs) ++{ ++ struct efhw_nic *nic = virs->rs.rs_client->nic; ++ ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] != 0) ++ efrm_vi_rm_init_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX, nic); ++ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) ++ efrm_vi_rm_init_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX, nic); ++} ++ ++/* free any PT endpoints whose flush has now complete */ ++void efrm_vi_rm_delayed_free(struct work_struct *data) ++{ ++ irq_flags_t lock_flags; ++ struct list_head close_pending; ++ struct vi_resource *virs; ++ ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_vi_manager->rm); ++ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ list_replace_init(&efrm_vi_manager->close_pending, &close_pending); ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ EFRM_TRACE("%s: %p", __func__, efrm_vi_manager); ++ while (!list_empty(&close_pending)) { ++ virs = ++ list_entry(list_pop(&close_pending), struct vi_resource, ++ rx_flush_link); ++ EFRM_TRACE("%s: flushed VI instance=%d", __func__, ++ EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)); ++ ++ if (virs->flush_callback_fn != NULL) { ++ efrm_vi_rm_reinit_dmaqs(virs); ++ virs->flush_callback_fn(virs->flush_callback_arg); ++ } else ++ efrm_vi_rm_free_flushed_resource(virs); ++ } ++} ++ ++void efrm_vi_rm_salvage_flushed_vis(void) ++{ ++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND ++ irq_flags_t lock_flags; ++ bool completed; ++ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ efrm_vi_handle_flush_loss(&completed); ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++#endif ++ ++ efrm_vi_rm_delayed_free(&efrm_vi_manager->work_item); ++} ++ ++void efrm_vi_resource_free(struct vi_resource *virs) ++{ ++ efrm_vi_register_flush_callback(virs, NULL, NULL); ++ efrm_pt_flush(virs); ++} ++EXPORT_SYMBOL(efrm_vi_resource_free); ++ ++ ++void efrm_vi_resource_release(struct vi_resource *virs) ++{ ++ if (__efrm_resource_release(&virs->rs)) ++ efrm_vi_resource_free(virs); ++} ++EXPORT_SYMBOL(efrm_vi_resource_release); ++ ++/* ++ * vi: sw=8:ai:aw ++ */ +Index: head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_manager.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-07-15/drivers/net/sfc/sfc_resource/vi_resource_manager.c 2008-07-17 16:18:07.000000000 +0200 +@@ -0,0 +1,231 @@ ++/**************************************************************************** ++ * Driver for Solarflare network controllers - ++ * resource management for Xen backend, OpenOnload, etc ++ * (including support for SFE4001 10GBT NIC) ++ * ++ * This file contains the VI resource manager. ++ * ++ * Copyright 2005-2007: Solarflare Communications Inc, ++ * 9501 Jeronimo Road, Suite 250, ++ * Irvine, CA 92618, USA ++ * ++ * Developed and maintained by Solarflare Communications: ++ * ++ * ++ * ++ * Certain parts of the driver were implemented by ++ * Alexandra Kossovsky ++ * OKTET Labs Ltd, Russia, ++ * http://oktetlabs.ru, ++ * by request of Solarflare Communications ++ * ++ * ++ * 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, incorporated herein by reference. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ **************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "efrm_internal.h" ++ ++ ++int efrm_pt_pace(struct vi_resource *virs, unsigned int val) ++{ ++ struct efhw_nic *nic = virs->rs.rs_client->nic; ++ int instance; ++ ++ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0); ++ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle); ++ falcon_nic_pace(nic, instance, val); ++ EFRM_TRACE("%s[%d]=%d DONE", __func__, instance, val); ++ return 0; ++} ++EXPORT_SYMBOL(efrm_pt_pace); ++ ++/*** Resource manager creation/destruction *******************************/ ++ ++static void efrm_vi_rm_dtor(struct efrm_resource_manager *rm); ++ ++static int ++efrm_create_or_destroy_vi_resource_manager( ++ struct efrm_resource_manager **rm_in_out, ++ const struct vi_resource_dimensions *dims, ++ bool destroy) ++{ ++ struct vi_resource *virs; ++ struct list_head *pos, *temp; ++ struct list_head flush_pending; ++ irq_flags_t lock_flags; ++ int rc; ++ unsigned dmaq_min, dmaq_lim; ++ ++ EFRM_ASSERT(rm_in_out); ++ ++ if (destroy) ++ goto destroy; ++ ++ EFRM_ASSERT(dims); ++ EFRM_NOTICE("vi_resource_manager: evq_int=%u-%u evq_timer=%u-%u", ++ dims->evq_int_min, dims->evq_int_lim, ++ dims->evq_timer_min, dims->evq_timer_lim); ++ EFRM_NOTICE("vi_resource_manager: rxq=%u-%u txq=%u-%u", ++ dims->rxq_min, dims->rxq_lim, ++ dims->txq_min, dims->txq_lim); ++ ++ efrm_vi_manager = kmalloc(sizeof(*efrm_vi_manager), GFP_KERNEL); ++ if (efrm_vi_manager == NULL) { ++ rc = -ENOMEM; ++ goto fail_alloc; ++ } ++ ++ memset(efrm_vi_manager, 0, sizeof(*efrm_vi_manager)); ++ ++ efrm_vi_manager->iscsi_dmaq_instance_is_free = true; ++ ++ dmaq_min = max(dims->rxq_min, dims->txq_min); ++ dmaq_lim = min(dims->rxq_lim, dims->txq_lim); ++ ++ efrm_vi_manager->with_timer_base = ++ max(dmaq_min, dims->evq_timer_min); ++ efrm_vi_manager->with_timer_limit = ++ min(dmaq_lim, dims->evq_timer_lim); ++ rc = efrm_kfifo_id_ctor(&efrm_vi_manager->instances_with_timer, ++ efrm_vi_manager->with_timer_base, ++ efrm_vi_manager->with_timer_limit, ++ &efrm_vi_manager->rm.rm_lock); ++ if (rc < 0) ++ goto fail_with_timer_id_pool; ++ ++ efrm_vi_manager->with_interrupt_base = ++ max(dmaq_min, dims->evq_int_min); ++ efrm_vi_manager->with_interrupt_limit = ++ min(dmaq_lim, dims->evq_int_lim); ++ efrm_vi_manager->with_interrupt_limit = ++ max(efrm_vi_manager->with_interrupt_limit, ++ efrm_vi_manager->with_interrupt_base); ++ rc = efrm_kfifo_id_ctor(&efrm_vi_manager->instances_with_interrupt, ++ efrm_vi_manager->with_interrupt_base, ++ efrm_vi_manager->with_interrupt_limit, ++ &efrm_vi_manager->rm.rm_lock); ++ if (rc < 0) ++ goto fail_with_int_id_pool; ++ ++ INIT_LIST_HEAD(&efrm_vi_manager->rx_flush_waiting_list); ++ INIT_LIST_HEAD(&efrm_vi_manager->rx_flush_outstanding_list); ++ INIT_LIST_HEAD(&efrm_vi_manager->tx_flush_outstanding_list); ++ efrm_vi_manager->rx_flush_outstanding_count = 0; ++ ++ INIT_LIST_HEAD(&efrm_vi_manager->close_pending); ++ efrm_vi_manager->workqueue = create_workqueue("sfc_vi"); ++ if (efrm_vi_manager->workqueue == NULL) ++ goto fail_create_workqueue; ++ INIT_WORK(&efrm_vi_manager->work_item, efrm_vi_rm_delayed_free); ++ ++ /* NB. This must be the last step to avoid things getting tangled. ++ * efrm_resource_manager_dtor calls the vi_rm_dtor which ends up in ++ * this function. */ ++ rc = efrm_resource_manager_ctor(&efrm_vi_manager->rm, efrm_vi_rm_dtor, ++ "VI", EFRM_RESOURCE_VI); ++ if (rc < 0) ++ goto fail_rm_ctor; ++ ++ *rm_in_out = &efrm_vi_manager->rm; ++ return 0; ++ ++destroy: ++ rc = 0; ++ EFRM_RESOURCE_MANAGER_ASSERT_VALID(*rm_in_out); ++ ++ /* Abort outstanding flushes. Note, a VI resource can be on more ++ * than one of these lists. We handle this by starting with the TX ++ * list and then append VIs to this list if they aren't on the TX ++ * list already. A VI is on the TX flush list if tx_flushing ++ * is not empty. */ ++ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ list_replace_init(&efrm_vi_manager->tx_flush_outstanding_list, ++ &flush_pending); ++ ++ list_for_each_safe(pos, temp, ++ &efrm_vi_manager->rx_flush_waiting_list) { ++ virs = container_of(pos, struct vi_resource, rx_flush_link); ++ ++ list_del(&virs->rx_flush_link); ++ if (virs->tx_flushing == 0) ++ list_add_tail(&virs->tx_flush_link, &flush_pending); ++ } ++ ++ list_for_each_safe(pos, temp, ++ &efrm_vi_manager->rx_flush_outstanding_list) { ++ virs = container_of(pos, struct vi_resource, rx_flush_link); ++ ++ list_del(&virs->rx_flush_link); ++ if (virs->tx_flushing == 0) ++ list_add_tail(&virs->tx_flush_link, &flush_pending); ++ } ++ ++ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags); ++ ++ while (!list_empty(&flush_pending)) { ++ virs = ++ list_entry(list_pop(&flush_pending), struct vi_resource, ++ tx_flush_link); ++ EFRM_TRACE("%s: found PT endpoint " EFRM_RESOURCE_FMT ++ " with flush pending [Tx=0x%x, Rx=0x%x, RxO=0x%x]", ++ __func__, ++ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle), ++ virs->tx_flushing, ++ virs->rx_flushing, ++ virs->rx_flush_outstanding); ++ efrm_vi_rm_free_flushed_resource(virs); ++ } ++ ++fail_rm_ctor: ++ ++ /* Complete outstanding closes. */ ++ destroy_workqueue(efrm_vi_manager->workqueue); ++fail_create_workqueue: ++ EFRM_ASSERT(list_empty(&efrm_vi_manager->close_pending)); ++ kfifo_vfree(efrm_vi_manager->instances_with_interrupt); ++fail_with_int_id_pool: ++ ++ kfifo_vfree(efrm_vi_manager->instances_with_timer); ++fail_with_timer_id_pool: ++ ++ if (destroy) ++ return 0; ++ ++ EFRM_DO_DEBUG(memset(efrm_vi_manager, 0, sizeof(*efrm_vi_manager))); ++ kfree(efrm_vi_manager); ++fail_alloc: ++ ++ *rm_in_out = NULL; ++ EFRM_ERR("%s: failed rc=%d", __func__, rc); ++ return rc; ++} ++ ++int ++efrm_create_vi_resource_manager(struct efrm_resource_manager **rm_out, ++ const struct vi_resource_dimensions *dims) ++{ ++ return efrm_create_or_destroy_vi_resource_manager(rm_out, dims, false); ++} ++ ++static void efrm_vi_rm_dtor(struct efrm_resource_manager *rm) ++{ ++ efrm_create_or_destroy_vi_resource_manager(&rm, NULL, true); ++} diff --git a/src/patches/suse-2.6.27.31/patches.xen/sfc-sync-headers b/src/patches/suse-2.6.27.31/patches.xen/sfc-sync-headers new file mode 100644 index 000000000..01f6a194f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/sfc-sync-headers @@ -0,0 +1,1070 @@ +From: Kieran Mansley +Subject: sync Solarflare accelerator headers +References: bnc#489105 + +Sync the headers used by sfc_netback and sfc_netutil with those in the +sfc_resource driver to give a consistent view of cross-module APIs. + +Update sfc_netback to use efx_vi_alloc() as defined by the version of +sfc_resource module in SLES11. It now takes a net driver interface +index rather than a NIC index. + +efx_vi_hw_resource_get_phys() no longer returns a version. + +Set efhw_arch field of device type. + +Acked-by: jbeulich@novell.com + +--- sle11-2009-03-24.orig/drivers/net/sfc/sfc_resource/ci/efhw/common.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/net/sfc/sfc_resource/ci/efhw/common.h 2009-03-30 16:21:54.000000000 +0200 +@@ -41,6 +41,10 @@ + + #include + ++enum efhw_arch { ++ EFHW_ARCH_FALCON, ++}; ++ + typedef uint32_t efhw_buffer_addr_t; + #define EFHW_BUFFER_ADDR_FMT "[ba:%"PRIx32"]" + +--- sle11-2009-03-24.orig/drivers/net/sfc/sfc_resource/nic.c 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/net/sfc/sfc_resource/nic.c 2009-03-30 16:21:54.000000000 +0200 +@@ -47,6 +47,7 @@ int efhw_device_type_init(struct efhw_de + switch (device_id) { + case 0x0703: + case 0x6703: ++ dt->arch = EFHW_ARCH_FALCON; + dt->variant = 'A'; + switch (class_revision) { + case 0: +@@ -60,6 +61,7 @@ int efhw_device_type_init(struct efhw_de + } + break; + case 0x0710: ++ dt->arch = EFHW_ARCH_FALCON; + dt->variant = 'B'; + switch (class_revision) { + case 2: +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/accel.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/accel.h 2009-03-30 16:00:09.000000000 +0200 +@@ -123,8 +123,6 @@ struct netback_accel { + enum net_accel_hw_type hw_type; + /*! State of allocation */ + int hw_state; +- /*! Index into ci_driver.nics[] for this interface */ +- int nic_index; + /*! How to set up the acceleration for this hardware */ + int (*accel_setup)(struct netback_accel *); + /*! And how to stop it. */ +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/accel_solarflare.c 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/accel_solarflare.c 2009-03-30 16:10:59.000000000 +0200 +@@ -87,7 +87,6 @@ struct driverlink_port { + enum net_accel_hw_type type; + struct net_device *net_dev; + struct efx_dl_device *efx_dl_dev; +- int nic_index; + void *fwd_priv; + }; + +@@ -164,34 +163,6 @@ static struct netback_accel_hooks accel_ + }; + + +-/* +- * Handy helper which given an efx_dl_device works out which +- * efab_nic_t index into efrm_nic_table.nics[] it corresponds to +- */ +-static int efx_device_to_efab_nic_index(struct efx_dl_device *efx_dl_dev) +-{ +- int i; +- +- for (i = 0; i < EFHW_MAX_NR_DEVS; i++) { +- struct efhw_nic *nic = efrm_nic_table.nic[i]; +- +- /* +- * It's possible for the nic structure to have not +- * been initialised if the resource driver failed its +- * driverlink probe +- */ +- if (nic == NULL || nic->net_driver_dev == NULL) +- continue; +- +- /* Work out if these are talking about the same NIC */ +- if (nic->net_driver_dev->pci_dev == efx_dl_dev->pci_dev) +- return i; +- } +- +- return -1; +-} +- +- + /* Driver link probe - register our callbacks */ + static int bend_dl_probe(struct efx_dl_device *efx_dl_dev, + const struct net_device *net_dev, +@@ -225,17 +196,6 @@ static int bend_dl_probe(struct efx_dl_d + port->efx_dl_dev = efx_dl_dev; + efx_dl_dev->priv = port; + +- port->nic_index = efx_device_to_efab_nic_index(efx_dl_dev); +- if (port->nic_index < 0) { +- /* +- * This can happen in theory if the resource driver +- * failed to initialise properly +- */ +- EPRINTK("%s: nic structure not found\n", __FUNCTION__); +- rc = -EINVAL; +- goto fail2; +- } +- + port->fwd_priv = netback_accel_init_fwd_port(); + if (port->fwd_priv == NULL) { + EPRINTK("%s: failed to set up forwarding for port\n", +@@ -377,8 +337,6 @@ int netback_accel_sf_hwtype(struct netba + bend->accel_setup = netback_accel_setup_vnic_hw; + bend->accel_shutdown = netback_accel_shutdown_vnic_hw; + bend->fwd_priv = port->fwd_priv; +- /* This is just needed to pass to efx_vi_alloc */ +- bend->nic_index = port->nic_index; + bend->net_dev = port->net_dev; + mutex_unlock(&accel_mutex); + return 0; +@@ -505,7 +463,7 @@ static int ef_get_vnic(struct netback_ac + + accel_hw_priv = bend->accel_hw_priv; + +- rc = efx_vi_alloc(&accel_hw_priv->efx_vih, bend->nic_index); ++ rc = efx_vi_alloc(&accel_hw_priv->efx_vih, bend->net_dev->ifindex); + if (rc != 0) { + EPRINTK("%s: efx_vi_alloc failed %d\n", __FUNCTION__, rc); + free_page_state(bend); +@@ -600,9 +558,6 @@ static int ef_bend_hwinfo_falcon_common( + return rc; + } + +- if (res_mdata.version != 0) +- return -EPROTO; +- + hwinfo->nic_arch = res_mdata.nic_arch; + hwinfo->nic_variant = res_mdata.nic_variant; + hwinfo->nic_revision = res_mdata.nic_revision; +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h 2009-03-30 16:00:09.000000000 +0200 +@@ -49,11 +49,11 @@ struct efx_vi_state; + * Allocate an efx_vi, including event queue and pt_endpoint + * + * \param vih_out Pointer to a handle that is set on success +- * \param nic_index Index of NIC to apply this resource to ++ * \param ifindex Index of the network interface desired + * \return Zero on success (and vih_out set), non-zero on failure. + */ + extern int +-efx_vi_alloc(struct efx_vi_state **vih_out, int nic_index); ++efx_vi_alloc(struct efx_vi_state **vih_out, int ifindex); + + /*! + * Free a previously allocated efx_vi +@@ -190,8 +190,6 @@ efx_vi_filter_stop(struct efx_vi_state * + /*! Constants for the type field in efx_vi_hw_resource */ + #define EFX_VI_HW_RESOURCE_TXDMAQ 0x0 /* PFN of TX DMA Q */ + #define EFX_VI_HW_RESOURCE_RXDMAQ 0x1 /* PFN of RX DMA Q */ +-#define EFX_VI_HW_RESOURCE_TXBELL 0x2 /* PFN of TX Doorbell (EF1) */ +-#define EFX_VI_HW_RESOURCE_RXBELL 0x3 /* PFN of RX Doorbell (EF1) */ + #define EFX_VI_HW_RESOURCE_EVQTIMER 0x4 /* Address of event q timer */ + + /* Address of event q pointer (EF1) */ +@@ -229,7 +227,6 @@ struct efx_vi_hw_resource { + * Metadata concerning the list of hardware resource mappings + */ + struct efx_vi_hw_resource_metadata { +- int version; + int evq_order; + int evq_offs; + int evq_capacity; +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/common.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/common.h 2009-03-30 16:21:54.000000000 +0200 +@@ -43,7 +43,6 @@ + + enum efhw_arch { + EFHW_ARCH_FALCON, +- EFHW_ARCH_SIENA, + }; + + typedef uint32_t efhw_buffer_addr_t; +@@ -56,25 +55,21 @@ typedef union { + uint32_t a; + uint32_t b; + } opaque; +- struct { +- uint32_t code; +- uint32_t status; +- } ev1002; + } efhw_event_t; + + /* Flags for TX/RX queues */ +-#define EFHW_VI_JUMBO_EN 0x01 /*! scatter RX over multiple desc */ +-#define EFHW_VI_ISCSI_RX_HDIG_EN 0x02 /*! iscsi rx header digest */ +-#define EFHW_VI_ISCSI_TX_HDIG_EN 0x04 /*! iscsi tx header digest */ +-#define EFHW_VI_ISCSI_RX_DDIG_EN 0x08 /*! iscsi rx data digest */ +-#define EFHW_VI_ISCSI_TX_DDIG_EN 0x10 /*! iscsi tx data digest */ +-#define EFHW_VI_TX_PHYS_ADDR_EN 0x20 /*! TX physical address mode */ +-#define EFHW_VI_RX_PHYS_ADDR_EN 0x40 /*! RX physical address mode */ +-#define EFHW_VI_RM_WITH_INTERRUPT 0x80 /*! VI with an interrupt */ +-#define EFHW_VI_TX_IP_CSUM_DIS 0x100 /*! enable ip checksum generation */ +-#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum +- generation */ +-#define EFHW_VI_TX_TCPUDP_ONLY 0x400 /*! drop non-tcp/udp packets */ ++#define EFHW_VI_JUMBO_EN 0x01 /*! scatter RX over multiple desc */ ++#define EFHW_VI_ISCSI_RX_HDIG_EN 0x02 /*! iscsi rx header digest */ ++#define EFHW_VI_ISCSI_TX_HDIG_EN 0x04 /*! iscsi tx header digest */ ++#define EFHW_VI_ISCSI_RX_DDIG_EN 0x08 /*! iscsi rx data digest */ ++#define EFHW_VI_ISCSI_TX_DDIG_EN 0x10 /*! iscsi tx data digest */ ++#define EFHW_VI_TX_PHYS_ADDR_EN 0x20 /*! TX physical address mode */ ++#define EFHW_VI_RX_PHYS_ADDR_EN 0x40 /*! RX physical address mode */ ++#define EFHW_VI_RM_WITH_INTERRUPT 0x80 /*! VI with an interrupt */ ++#define EFHW_VI_TX_IP_CSUM_DIS 0x100 /*! enable ip checksum generation */ ++#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum ++ generation */ ++#define EFHW_VI_TX_TCPUDP_ONLY 0x400 /*! drop non-tcp/udp packets */ + + /* Types of hardware filter */ + /* Each of these values implicitly selects scatter filters on B0 - or in +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/common_sysdep.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/common_sysdep.h 2009-03-30 16:00:09.000000000 +0200 +@@ -41,7 +41,6 @@ + #define __CI_EFHW_COMMON_LINUX_H__ + + #include +-#include + + /* Dirty hack, but Linux kernel does not provide DMA_ADDR_T_FMT */ + #if BITS_PER_LONG == 64 || defined(CONFIG_HIGHMEM64G) +@@ -52,16 +51,11 @@ + + /* Linux kernel also does not provide PRIx32... Sigh. */ + #define PRIx32 "x" +-#define PRIx64 "llx" + +- +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +-enum { +- false = 0, +- true = 1 +-}; +- +-typedef _Bool bool; +-#endif /* LINUX_VERSION_CODE < 2.6.19 */ ++#ifdef __ia64__ ++# define PRIx64 "lx" ++#else ++# define PRIx64 "llx" ++#endif + + #endif /* __CI_EFHW_COMMON_LINUX_H__ */ +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/efhw_types.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/efhw_types.h 2009-03-30 16:00:09.000000000 +0200 +@@ -45,14 +45,6 @@ + + /*-------------------------------------------------------------------- + * +- * hardware limits used in the types +- * +- *--------------------------------------------------------------------*/ +- +-#define EFHW_KEVENTQ_MAX 8 +- +-/*-------------------------------------------------------------------- +- * + * forward type declarations + * + *--------------------------------------------------------------------*/ +@@ -72,7 +64,7 @@ struct efhw_buffer_table_allocation{ + + struct eventq_resource_hardware { + /*!iobuffer allocated for eventq - can be larger than eventq */ +- efhw_iopages_t iobuff; ++ struct efhw_iopages iobuff; + unsigned iobuff_off; + struct efhw_buffer_table_allocation buf_tbl_alloc; + int capacity; /*!< capacity of event queue */ +@@ -85,7 +77,7 @@ struct eventq_resource_hardware { + *--------------------------------------------------------------------*/ + + struct efhw_keventq { +- volatile int lock; ++ int lock; + caddr_t evq_base; + int32_t evq_ptr; + uint32_t evq_mask; +@@ -94,6 +86,37 @@ struct efhw_keventq { + struct efhw_ev_handler *ev_handlers; + }; + ++/*-------------------------------------------------------------------- ++ * ++ * filters ++ * ++ *--------------------------------------------------------------------*/ ++ ++struct efhw_filter_spec { ++ uint dmaq_id; ++ uint32_t saddr_le32; ++ uint32_t daddr_le32; ++ uint16_t sport_le16; ++ uint16_t dport_le16; ++ unsigned tcp : 1; ++ unsigned full : 1; ++ unsigned rss : 1; /* not supported on A1 */ ++ unsigned scatter : 1; /* not supported on A1 */ ++}; ++ ++struct efhw_filter_depth { ++ unsigned needed; ++ unsigned max; ++}; ++ ++struct efhw_filter_search_limits { ++ unsigned tcp_full; ++ unsigned tcp_wild; ++ unsigned udp_full; ++ unsigned udp_wild; ++}; ++ ++ + /********************************************************************** + * Portable HW interface. *************************************** + **********************************************************************/ +@@ -115,7 +138,7 @@ struct efhw_func_ops { + /*! initialise all hardware functional units */ + int (*init_hardware) (struct efhw_nic *nic, + struct efhw_ev_handler *, +- const uint8_t *mac_addr); ++ const uint8_t *mac_addr, int non_irq_evq); + + /*-------------- Interrupt support ------------ */ + +@@ -130,17 +153,17 @@ struct efhw_func_ops { + */ + int (*interrupt) (struct efhw_nic *nic); + +- /*! Enable given interrupt mask for the given IRQ unit */ +- void (*interrupt_enable) (struct efhw_nic *nic, uint idx); ++ /*! Enable the interrupt */ ++ void (*interrupt_enable) (struct efhw_nic *nic); + +- /*! Disable given interrupt mask for the given IRQ unit */ +- void (*interrupt_disable) (struct efhw_nic *nic, uint idx); ++ /*! Disable the interrupt */ ++ void (*interrupt_disable) (struct efhw_nic *nic); + + /*! Set interrupt moderation strategy for the given IRQ unit + ** val is in usec + */ +- void (*set_interrupt_moderation)(struct efhw_nic *nic, +- uint idx, uint val); ++ void (*set_interrupt_moderation)(struct efhw_nic *nic, int evq, ++ uint val); + + /*-------------- Event support ------------ */ + +@@ -152,7 +175,8 @@ struct efhw_func_ops { + void (*event_queue_enable) (struct efhw_nic *nic, + uint evq, /* evnt queue index */ + uint evq_size, /* units of #entries */ +- dma_addr_t q_base_addr, uint buf_base_id); ++ dma_addr_t q_base_addr, uint buf_base_id, ++ int interrupting); + + /*! Disable the given event queue (and any associated timer) */ + void (*event_queue_disable) (struct efhw_nic *nic, uint evq, +@@ -165,7 +189,7 @@ struct efhw_func_ops { + /*! Push a SW event on a given eventQ */ + void (*sw_event) (struct efhw_nic *nic, int data, int evq); + +- /*-------------- Filter support ------------ */ ++ /*-------------- IP Filter API ------------ */ + + /*! Setup a given filter - The software can request a filter_i, + * but some EtherFabric implementations will override with +@@ -176,13 +200,6 @@ struct efhw_func_ops { + unsigned saddr_be32, unsigned sport_be16, + unsigned daddr_be32, unsigned dport_be16); + +- /*! Attach a given filter to a DMAQ */ +- void (*ipfilter_attach) (struct efhw_nic *nic, int filter_idx, +- int dmaq_idx); +- +- /*! Detach a filter from its DMAQ */ +- void (*ipfilter_detach) (struct efhw_nic *nic, int filter_idx); +- + /*! Clear down a given filter */ + void (*ipfilter_clear) (struct efhw_nic *nic, int filter_idx); + +@@ -231,6 +248,14 @@ struct efhw_func_ops { + /*! Commit a buffer table update */ + void (*buffer_table_commit) (struct efhw_nic *nic); + ++ /*-------------- New filter API ------------ */ ++ ++ /*! Set a given filter */ ++ int (*filter_set) (struct efhw_nic *nic, struct efhw_filter_spec *spec, ++ int *filter_idx_out); ++ ++ /*! Clear a given filter */ ++ void (*filter_clear) (struct efhw_nic *nic, int filter_idx); + }; + + +@@ -255,12 +280,10 @@ struct efhw_device_type { + + /*! */ + struct efhw_nic { +- /*! zero base index in efrm_nic_table.nic array */ +- volatile int index; ++ /*! zero base index in efrm_nic_tablep->nic array */ ++ int index; + int ifindex; /*!< OS level nic index */ +-#ifdef HAS_NET_NAMESPACE + struct net *nd_net; +-#endif + + struct efhw_device_type devtype; + +@@ -276,14 +299,13 @@ struct efhw_nic { + # define NIC_FLAG_TRY_MSI 0x02 + # define NIC_FLAG_MSI 0x04 + # define NIC_FLAG_OS_IRQ_EN 0x08 +-# define NIC_FLAG_10G 0x10 + + unsigned mtu; /*!< MAC MTU (includes MAC hdr) */ + + /* hardware resources */ + + /*! I/O address of the start of the bar */ +- efhw_ioaddr_t bar_ioaddr; ++ volatile char __iomem *bar_ioaddr; + + /*! Bar number of control aperture. */ + unsigned ctr_ap_bar; +@@ -295,9 +317,6 @@ struct efhw_nic { + /*! EtherFabric Functional Units -- functions */ + const struct efhw_func_ops *efhw_func; + +- /* Value read from FPGA version register. Zero for asic. */ +- unsigned fpga_version; +- + /*! This lock protects a number of misc NIC resources. It should + * only be used for things that can be at the bottom of the lock + * order. ie. You mustn't attempt to grab any other lock while +@@ -312,14 +331,17 @@ struct efhw_nic { + void (*irq_handler) (struct efhw_nic *, int unit); + + /*! event queues per driver */ +- struct efhw_keventq evq[EFHW_KEVENTQ_MAX]; ++ struct efhw_keventq interrupting_evq; + + /* for marking when we are not using an IRQ unit + - 0 is a valid offset to an IRQ unit on EF1! */ + #define EFHW_IRQ_UNIT_UNUSED 0xffff +- /*! interrupt unit in use */ +- unsigned int irq_unit[EFHW_KEVENTQ_MAX]; +- efhw_iopage_t irq_iobuff; /*!< Falcon SYSERR interrupt */ ++ /*! interrupt unit in use for the interrupting event queue */ ++ unsigned int irq_unit; ++ ++ struct efhw_keventq non_interrupting_evq; ++ ++ struct efhw_iopage irq_iobuff; /*!< Falcon SYSERR interrupt */ + + /* The new driverlink infrastructure. */ + struct efx_dl_device *net_driver_dev; +@@ -331,8 +353,26 @@ struct efhw_nic { + unsigned rxq_sizes; + unsigned txq_sizes; + +- /* Size of filter table (including odd and even banks). */ +- unsigned filter_tbl_size; ++ /* Size of filter table. */ ++ unsigned ip_filter_tbl_size; ++ ++ /* Number of filters currently used */ ++ unsigned ip_filter_tbl_used; ++ ++ /* Dynamically allocated filter state. */ ++ uint8_t *filter_in_use; ++ struct efhw_filter_spec *filter_spec_cache; ++ ++ /* Currently required and maximum filter table search depths. */ ++ struct efhw_filter_depth tcp_full_srch; ++ struct efhw_filter_depth tcp_wild_srch; ++ struct efhw_filter_depth udp_full_srch; ++ struct efhw_filter_depth udp_wild_srch; ++ ++ /* Number of event queues, DMA queues and timers. */ ++ unsigned num_evqs; ++ unsigned num_dmaqs; ++ unsigned num_timers; + }; + + +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h 2009-03-30 16:00:09.000000000 +0200 +@@ -40,7 +40,7 @@ + #ifndef __CI_EFHW_HARDWARE_LINUX_H__ + #define __CI_EFHW_HARDWARE_LINUX_H__ + +-#include ++#include + + #ifdef __LITTLE_ENDIAN + #define EFHW_IS_LITTLE_ENDIAN +@@ -50,23 +50,8 @@ + #error Unknown endianness + #endif + +-#ifndef mmiowb +- #if defined(__i386__) || defined(__x86_64__) +- #define mmiowb() +- #elif defined(__ia64__) +- #ifndef ia64_mfa +- #define ia64_mfa() asm volatile ("mf.a" ::: "memory") +- #endif +- #define mmiowb ia64_mfa +- #else +- #error "Need definition for mmiowb()" +- #endif +-#endif +- +-typedef char *efhw_ioaddr_t; +- + #ifndef readq +-static inline uint64_t __readq(void __iomem *addr) ++static inline uint64_t __readq(volatile void __iomem *addr) + { + return *(volatile uint64_t *)addr; + } +@@ -74,7 +59,7 @@ static inline uint64_t __readq(void __io + #endif + + #ifndef writeq +-static inline void __writeq(uint64_t v, void __iomem *addr) ++static inline void __writeq(uint64_t v, volatile void __iomem *addr) + { + *(volatile uint64_t *)addr = v; + } +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/iopage_types.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/iopage_types.h 2009-03-30 16:00:09.000000000 +0200 +@@ -3,7 +3,8 @@ + * resource management for Xen backend, OpenOnload, etc + * (including support for SFE4001 10GBT NIC) + * +- * This file provides efhw_page_t and efhw_iopage_t for Linux kernel. ++ * This file provides struct efhw_page and struct efhw_iopage for Linux ++ * kernel. + * + * Copyright 2005-2007: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, +@@ -40,75 +41,76 @@ + + #include + #include ++#include + #include + + /*-------------------------------------------------------------------- + * +- * efhw_page_t: A single page of memory. Directly mapped in the driver, +- * and can be mapped to userlevel. ++ * struct efhw_page: A single page of memory. Directly mapped in the ++ * driver, and can be mapped to userlevel. + * + *--------------------------------------------------------------------*/ + +-typedef struct { ++struct efhw_page { + unsigned long kva; +-} efhw_page_t; ++}; + +-static inline int efhw_page_alloc(efhw_page_t *p) ++static inline int efhw_page_alloc(struct efhw_page *p) + { + p->kva = __get_free_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL); + return p->kva ? 0 : -ENOMEM; + } + +-static inline int efhw_page_alloc_zeroed(efhw_page_t *p) ++static inline int efhw_page_alloc_zeroed(struct efhw_page *p) + { + p->kva = get_zeroed_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL); + return p->kva ? 0 : -ENOMEM; + } + +-static inline void efhw_page_free(efhw_page_t *p) ++static inline void efhw_page_free(struct efhw_page *p) + { + free_page(p->kva); + EFHW_DO_DEBUG(memset(p, 0, sizeof(*p))); + } + +-static inline char *efhw_page_ptr(efhw_page_t *p) ++static inline char *efhw_page_ptr(struct efhw_page *p) + { + return (char *)p->kva; + } + +-static inline unsigned efhw_page_pfn(efhw_page_t *p) ++static inline unsigned efhw_page_pfn(struct efhw_page *p) + { + return (unsigned)(__pa(p->kva) >> PAGE_SHIFT); + } + +-static inline void efhw_page_mark_invalid(efhw_page_t *p) ++static inline void efhw_page_mark_invalid(struct efhw_page *p) + { + p->kva = 0; + } + +-static inline int efhw_page_is_valid(efhw_page_t *p) ++static inline int efhw_page_is_valid(struct efhw_page *p) + { + return p->kva != 0; + } + +-static inline void efhw_page_init_from_va(efhw_page_t *p, void *va) ++static inline void efhw_page_init_from_va(struct efhw_page *p, void *va) + { + p->kva = (unsigned long)va; + } + + /*-------------------------------------------------------------------- + * +- * efhw_iopage_t: A single page of memory. Directly mapped in the driver, ++ * struct efhw_iopage: A single page of memory. Directly mapped in the driver, + * and can be mapped to userlevel. Can also be accessed by the NIC. + * + *--------------------------------------------------------------------*/ + +-typedef struct { +- efhw_page_t p; ++struct efhw_iopage { ++ struct efhw_page p; + dma_addr_t dma_addr; +-} efhw_iopage_t; ++}; + +-static inline dma_addr_t efhw_iopage_dma_addr(efhw_iopage_t *p) ++static inline dma_addr_t efhw_iopage_dma_addr(struct efhw_iopage *p) + { + return p->dma_addr; + } +@@ -120,9 +122,9 @@ static inline dma_addr_t efhw_iopage_dma + + /*-------------------------------------------------------------------- + * +- * efhw_iopages_t: A set of pages that are contiguous in physical memory. +- * Directly mapped in the driver, and can be mapped to userlevel. Can also +- * be accessed by the NIC. ++ * struct efhw_iopages: A set of pages that are contiguous in physical ++ * memory. Directly mapped in the driver, and can be mapped to userlevel. ++ * Can also be accessed by the NIC. + * + * NB. The O/S may be unwilling to allocate many, or even any of these. So + * only use this type where the NIC really needs a physically contiguous +@@ -130,44 +132,44 @@ static inline dma_addr_t efhw_iopage_dma + * + *--------------------------------------------------------------------*/ + +-typedef struct { ++struct efhw_iopages { + caddr_t kva; + unsigned order; + dma_addr_t dma_addr; +-} efhw_iopages_t; ++}; + +-static inline caddr_t efhw_iopages_ptr(efhw_iopages_t *p) ++static inline caddr_t efhw_iopages_ptr(struct efhw_iopages *p) + { + return p->kva; + } + +-static inline unsigned efhw_iopages_pfn(efhw_iopages_t *p) ++static inline unsigned efhw_iopages_pfn(struct efhw_iopages *p) + { + return (unsigned)(__pa(p->kva) >> PAGE_SHIFT); + } + +-static inline dma_addr_t efhw_iopages_dma_addr(efhw_iopages_t *p) ++static inline dma_addr_t efhw_iopages_dma_addr(struct efhw_iopages *p) + { + return p->dma_addr; + } + +-static inline unsigned efhw_iopages_size(efhw_iopages_t *p) ++static inline unsigned efhw_iopages_size(struct efhw_iopages *p) + { + return 1u << (p->order + PAGE_SHIFT); + } + +-/* efhw_iopage_t <-> efhw_iopages_t conversions for handling physically +- * contiguous allocations in iobufsets for iSCSI. This allows the +- * essential information about contiguous allocations from +- * efhw_iopages_alloc() to be saved away in the efhw_iopage_t array in an +- * iobufset. (Changing the iobufset resource to use a union type would ++/* struct efhw_iopage <-> struct efhw_iopages conversions for handling ++ * physically contiguous allocations in iobufsets for iSCSI. This allows ++ * the essential information about contiguous allocations from ++ * efhw_iopages_alloc() to be saved away in the struct efhw_iopage array in ++ * an iobufset. (Changing the iobufset resource to use a union type would + * involve a lot of code changes, and make the iobufset's metadata larger + * which could be bad as it's supposed to fit into a single page on some + * platforms.) + */ + static inline void +-efhw_iopage_init_from_iopages(efhw_iopage_t *iopage, +- efhw_iopages_t *iopages, unsigned pageno) ++efhw_iopage_init_from_iopages(struct efhw_iopage *iopage, ++ struct efhw_iopages *iopages, unsigned pageno) + { + iopage->p.kva = ((unsigned long)efhw_iopages_ptr(iopages)) + + (pageno * PAGE_SIZE); +@@ -176,8 +178,8 @@ efhw_iopage_init_from_iopages(efhw_iopag + } + + static inline void +-efhw_iopages_init_from_iopage(efhw_iopages_t *iopages, +- efhw_iopage_t *iopage, unsigned order) ++efhw_iopages_init_from_iopage(struct efhw_iopages *iopages, ++ struct efhw_iopage *iopage, unsigned order) + { + iopages->kva = (caddr_t) efhw_iopage_ptr(iopage); + EFHW_ASSERT(iopages->kva); +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/public.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/public.h 2009-03-30 16:00:09.000000000 +0200 +@@ -70,11 +70,32 @@ int efhw_nic_event_queue_alloc_iobuffer( + extern void falcon_nic_set_rx_usr_buf_size(struct efhw_nic *, + int rx_usr_buf_size); + ++/*! Get RX filter search limits from RX_FILTER_CTL_REG. ++ * use_raw_values = 0 to get actual depth of search, or 1 to get raw values ++ * from register. ++ */ ++extern void ++falcon_nic_get_rx_filter_search_limits(struct efhw_nic *nic, ++ struct efhw_filter_search_limits *lim, ++ int use_raw_values); ++ ++/*! Set RX filter search limits in RX_FILTER_CTL_REG. ++ * use_raw_values = 0 if specifying actual depth of search, or 1 if specifying ++ * raw values to write to the register. ++ */ ++extern void ++falcon_nic_set_rx_filter_search_limits(struct efhw_nic *nic, ++ struct efhw_filter_search_limits *lim, ++ int use_raw_values); ++ ++ ++/*! Legacy RX IP filter search depth control interface */ + extern void + falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full, + uint32_t tcp_wild, + uint32_t udp_full, uint32_t udp_wild); + ++/*! Legacy RX IP filter search depth control interface */ + extern void + falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full, + uint32_t *tcp_wild, +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efhw/sysdep.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efhw/sysdep.h 2009-03-30 16:00:09.000000000 +0200 +@@ -39,34 +39,17 @@ + #ifndef __CI_EFHW_SYSDEP_LINUX_H__ + #define __CI_EFHW_SYSDEP_LINUX_H__ + +-#include + #include + #include + #include ++#include + #include + + #include /* necessary for etherdevice.h on some kernels */ + #include + +-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) +-static inline int is_local_ether_addr(const u8 *addr) +-{ +- return (0x02 & addr[0]); +-} +-#endif +- + typedef unsigned long irq_flags_t; + + #define spin_lock_destroy(l_) do {} while (0) + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +-#define HAS_NET_NAMESPACE +-#endif +- +-/* Funny, but linux has round_up for x86 only, defined in +- * x86-specific header */ +-#ifndef round_up +-#define round_up(x, y) (((x) + (y) - 1) & ~((y)-1)) +-#endif +- + #endif /* __CI_EFHW_SYSDEP_LINUX_H__ */ +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efrm/nic_table.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efrm/nic_table.h 2009-03-30 16:09:06.000000000 +0200 +@@ -62,21 +62,21 @@ struct efrm_nic_table { + }; + + /* Resource driver structures used by other drivers as well */ +-extern struct efrm_nic_table efrm_nic_table; ++extern struct efrm_nic_table *efrm_nic_tablep; + + static inline void efrm_nic_table_hold(void) + { +- atomic_inc(&efrm_nic_table.ref_count); ++ atomic_inc(&efrm_nic_tablep->ref_count); + } + + static inline void efrm_nic_table_rele(void) + { +- atomic_dec(&efrm_nic_table.ref_count); ++ atomic_dec(&efrm_nic_tablep->ref_count); + } + + static inline int efrm_nic_table_held(void) + { +- return (atomic_read(&efrm_nic_table.ref_count) != 0); ++ return atomic_read(&efrm_nic_tablep->ref_count) != 0; + } + + /* Run code block _x multiple times with variable nic set to each +@@ -86,13 +86,13 @@ static inline int efrm_nic_table_held(vo + for ((_nic_i) = (efrm_nic_table_hold(), 0); \ + (_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \ + (_nic_i)++) \ +- if (((_nic) = efrm_nic_table.nic[_nic_i])) ++ if (((_nic) = efrm_nic_tablep->nic[_nic_i])) + + #define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic) \ + for ((_i) = (efrm_nic_table_hold(), 0); \ + (_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \ + ++(_i)) \ +- if (((_nic) = efrm_nic_table.nic[_i]) && \ ++ if (((_nic) = efrm_nic_tablep->nic[_i]) && \ + efrm_nic_set_read((_set), (_i))) + + #endif /* __CI_EFRM_NIC_TABLE_H__ */ +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efrm/sysdep.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efrm/sysdep.h 2009-03-30 16:00:09.000000000 +0200 +@@ -41,14 +41,6 @@ + /* Spinlocks are defined in efhw/sysdep.h */ + #include + +-#if defined(__linux__) && defined(__KERNEL__) +- +-# include +- +-#else +- +-# include +- +-#endif ++#include + + #endif /* __CI_EFRM_SYSDEP_H__ */ +--- sle11-2009-03-24.orig/drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h 2009-03-30 16:16:28.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h 2009-03-30 16:00:09.000000000 +0200 +@@ -42,7 +42,6 @@ + #ifndef __CI_EFRM_SYSDEP_LINUX_H__ + #define __CI_EFRM_SYSDEP_LINUX_H__ + +-#include + #include + #include + #include +@@ -55,28 +54,15 @@ + #include + #include + #include +- +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) +-/* get roundup_pow_of_two(), which was in kernel.h in early kernel versions */ + #include +-#endif ++#include ++ + + /******************************************************************** + * + * List API + * + ********************************************************************/ +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +-static inline void +-list_replace_init(struct list_head *old, struct list_head *new) +-{ +- new->next = old->next; +- new->next->prev = new; +- new->prev = old->prev; +- new->prev->next = new; +- INIT_LIST_HEAD(old); +-} +-#endif + + static inline struct list_head *list_pop(struct list_head *list) + { +@@ -94,151 +80,10 @@ static inline struct list_head *list_pop + + /******************************************************************** + * +- * Workqueue API +- * +- ********************************************************************/ +- +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +-#define NEED_OLD_WORK_API +- +-/** +- * The old and new work function prototypes just change +- * the type of the pointer in the only argument, so it's +- * safe to cast one function type to the other +- */ +-typedef void (*efrm_old_work_func_t) (void *p); +- +-#undef INIT_WORK +-#define INIT_WORK(_work, _func) \ +- do { \ +- INIT_LIST_HEAD(&(_work)->entry); \ +- (_work)->pending = 0; \ +- PREPARE_WORK((_work), \ +- (efrm_old_work_func_t) (_func), \ +- (_work)); \ +- } while (0) +- +-#endif +- +-/******************************************************************** +- * + * Kfifo API + * + ********************************************************************/ + +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) +- +-#if !defined(RHEL_RELEASE_CODE) || (RHEL_RELEASE_CODE < 1029) +-typedef unsigned gfp_t; +-#endif +- +-#define HAS_NO_KFIFO +- +-struct kfifo { +- unsigned char *buffer; /* the buffer holding the data */ +- unsigned int size; /* the size of the allocated buffer */ +- unsigned int in; /* data is added at offset (in % size) */ +- unsigned int out; /* data is extracted from off. (out % size) */ +- spinlock_t *lock; /* protects concurrent modifications */ +-}; +- +-extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size, +- gfp_t gfp_mask, spinlock_t *lock); +-extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, +- spinlock_t *lock); +-extern void kfifo_free(struct kfifo *fifo); +-extern unsigned int __kfifo_put(struct kfifo *fifo, +- unsigned char *buffer, unsigned int len); +-extern unsigned int __kfifo_get(struct kfifo *fifo, +- unsigned char *buffer, unsigned int len); +- +-/** +- * kfifo_put - puts some data into the FIFO +- * @fifo: the fifo to be used. +- * @buffer: the data to be added. +- * @len: the length of the data to be added. +- * +- * This function copies at most @len bytes from the @buffer into +- * the FIFO depending on the free space, and returns the number of +- * bytes copied. +- */ +-static inline unsigned int +-kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len) +-{ +- unsigned long flags; +- unsigned int ret; +- +- spin_lock_irqsave(fifo->lock, flags); +- +- ret = __kfifo_put(fifo, buffer, len); +- +- spin_unlock_irqrestore(fifo->lock, flags); +- +- return ret; +-} +- +-/** +- * kfifo_get - gets some data from the FIFO +- * @fifo: the fifo to be used. +- * @buffer: where the data must be copied. +- * @len: the size of the destination buffer. +- * +- * This function copies at most @len bytes from the FIFO into the +- * @buffer and returns the number of copied bytes. +- */ +-static inline unsigned int +-kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len) +-{ +- unsigned long flags; +- unsigned int ret; +- +- spin_lock_irqsave(fifo->lock, flags); +- +- ret = __kfifo_get(fifo, buffer, len); +- +- /* +- * optimization: if the FIFO is empty, set the indices to 0 +- * so we don't wrap the next time +- */ +- if (fifo->in == fifo->out) +- fifo->in = fifo->out = 0; +- +- spin_unlock_irqrestore(fifo->lock, flags); +- +- return ret; +-} +- +-/** +- * __kfifo_len - returns the number of bytes available in the FIFO, no locking version +- * @fifo: the fifo to be used. +- */ +-static inline unsigned int __kfifo_len(struct kfifo *fifo) +-{ +- return fifo->in - fifo->out; +-} +- +-/** +- * kfifo_len - returns the number of bytes available in the FIFO +- * @fifo: the fifo to be used. +- */ +-static inline unsigned int kfifo_len(struct kfifo *fifo) +-{ +- unsigned long flags; +- unsigned int ret; +- +- spin_lock_irqsave(fifo->lock, flags); +- +- ret = __kfifo_len(fifo); +- +- spin_unlock_irqrestore(fifo->lock, flags); +- +- return ret; +-} +- +-#else +-#include +-#endif +- + static inline void kfifo_vfree(struct kfifo *fifo) + { + vfree(fifo->buffer); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-S3-MSI b/src/patches/suse-2.6.27.31/patches.xen/xen-S3-MSI new file mode 100644 index 000000000..c668d63a2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-S3-MSI @@ -0,0 +1,154 @@ +From: jbeulich@novell.com +Subject: fix Dom0 resume from S3 when MSI is in use +Patch-mainline: obsolete +References: bnc#435596 + +--- sle11-2009-04-20.orig/drivers/pci/msi-xen.c 2009-01-09 11:10:27.000000000 +0100 ++++ sle11-2009-04-20/drivers/pci/msi-xen.c 2009-04-24 13:37:37.000000000 +0200 +@@ -234,8 +234,8 @@ static int msi_unmap_pirq(struct pci_dev + int rc; + + unmap.domid = msi_get_dev_owner(dev); +- /* See comments in msi_map_pirq_to_vector, input parameter pirq +- * mean irq number only if the device belongs to dom0 itself. ++ /* See comments in msi_map_vector, input parameter pirq means ++ * irq number only if the device belongs to dom0 itself. + */ + unmap.pirq = (unmap.domid != DOMID_SELF) + ? pirq : evtchn_get_xen_pirq(pirq); +@@ -271,8 +271,7 @@ static u64 find_table_base(struct pci_de + /* + * Protected by msi_lock + */ +-static int msi_map_pirq_to_vector(struct pci_dev *dev, int pirq, +- int entry_nr, u64 table_base) ++static int msi_map_vector(struct pci_dev *dev, int entry_nr, u64 table_base) + { + struct physdev_map_pirq map_irq; + int rc; +@@ -283,7 +282,7 @@ static int msi_map_pirq_to_vector(struct + map_irq.domid = domid; + map_irq.type = MAP_PIRQ_TYPE_MSI; + map_irq.index = -1; +- map_irq.pirq = pirq < 0 ? -1 : evtchn_get_xen_pirq(pirq); ++ map_irq.pirq = -1; + map_irq.bus = dev->bus->number; + map_irq.devfn = dev->devfn; + map_irq.entry_nr = entry_nr; +@@ -294,7 +293,7 @@ static int msi_map_pirq_to_vector(struct + + if (rc < 0) + return rc; +- /* This happens when MSI support is not enabled in Xen. */ ++ /* This happens when MSI support is not enabled in older Xen. */ + if (rc == 0 && map_irq.pirq < 0) + return -ENOSYS; + +@@ -306,12 +305,7 @@ static int msi_map_pirq_to_vector(struct + * to another domain, and will be 'Linux irq' if it belongs to dom0. + */ + return ((domid != DOMID_SELF) ? +- map_irq.pirq : evtchn_map_pirq(pirq, map_irq.pirq)); +-} +- +-static int msi_map_vector(struct pci_dev *dev, int entry_nr, u64 table_base) +-{ +- return msi_map_pirq_to_vector(dev, -1, entry_nr, table_base); ++ map_irq.pirq : evtchn_map_pirq(-1, map_irq.pirq)); + } + + static void pci_intx_for_msi(struct pci_dev *dev, int enable) +@@ -320,62 +314,24 @@ static void pci_intx_for_msi(struct pci_ + pci_intx(dev, enable); + } + +-static void __pci_restore_msi_state(struct pci_dev *dev) +-{ +- int pirq; +- +- if (!dev->msi_enabled) +- return; +- +- pci_intx_for_msi(dev, 0); +- msi_set_enable(dev, 0); +- +- pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 0); +- if (pirq < 0) +- return; +-} +- +-static void __pci_restore_msix_state(struct pci_dev *dev) ++void pci_restore_msi_state(struct pci_dev *dev) + { +- int pos; +- unsigned long flags; +- u64 table_base; +- struct msi_dev_list *msi_dev_entry; +- struct msi_pirq_entry *pirq_entry, *tmp; ++ int rc; ++ struct physdev_restore_msi restore; + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); +- if (pos <= 0) +- return; +- +- if (!dev->msix_enabled) ++ if (!dev->msi_enabled && !dev->msix_enabled) + return; + + pci_intx_for_msi(dev, 0); +- msix_set_enable(dev, 0); +- +- msi_dev_entry = get_msi_dev_pirq_list(dev); +- table_base = find_table_base(dev, pos); +- if (!table_base) +- return; +- +- spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags); +- list_for_each_entry_safe(pirq_entry, tmp, +- &msi_dev_entry->pirq_list_head, list) { +- int rc = msi_map_pirq_to_vector(dev, pirq_entry->pirq, +- pirq_entry->entry_nr, table_base); +- if (rc < 0) +- printk(KERN_WARNING +- "%s: re-mapping irq #%d (pirq%d) failed: %d\n", +- pci_name(dev), pirq_entry->entry_nr, +- pirq_entry->pirq, rc); +- } +- spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags); +-} +- +-void pci_restore_msi_state(struct pci_dev *dev) +-{ +- __pci_restore_msi_state(dev); +- __pci_restore_msix_state(dev); ++ if (dev->msi_enabled) ++ msi_set_enable(dev, 0); ++ if (dev->msix_enabled) ++ msix_set_enable(dev, 0); ++ ++ restore.bus = dev->bus->number; ++ restore.devfn = dev->devfn; ++ rc = HYPERVISOR_physdev_op(PHYSDEVOP_restore_msi, &restore); ++ WARN(rc && rc != -ENOSYS, "restore_msi -> %d\n", rc); + } + EXPORT_SYMBOL_GPL(pci_restore_msi_state); + +--- sle11-2009-04-20.orig/include/xen/interface/physdev.h 2009-04-24 13:28:45.000000000 +0200 ++++ sle11-2009-04-20/include/xen/interface/physdev.h 2009-01-05 15:11:37.000000000 +0100 +@@ -183,6 +183,15 @@ struct physdev_manage_pci { + typedef struct physdev_manage_pci physdev_manage_pci_t; + DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_t); + ++#define PHYSDEVOP_restore_msi 19 ++struct physdev_restore_msi { ++ /* IN */ ++ uint8_t bus; ++ uint8_t devfn; ++}; ++typedef struct physdev_restore_msi physdev_restore_msi_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_restore_msi_t); ++ + /* + * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() + * hypercall since 0x00030202. diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-balloon-max-target b/src/patches/suse-2.6.27.31/patches.xen/xen-balloon-max-target new file mode 100644 index 000000000..d7b5a2809 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-balloon-max-target @@ -0,0 +1,78 @@ +From: ccoffing@novell.com +Subject: Expose min/max limits of domain ballooning +Patch-mainline: obsolete +References: 152667, 184727 + +jb: Also added this to the sysfs representation. + +--- sle11-2009-06-29.orig/drivers/xen/balloon/balloon.c 2009-06-29 15:30:29.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/balloon/balloon.c 2009-06-29 15:44:49.000000000 +0200 +@@ -194,7 +194,7 @@ static unsigned long current_target(void + return target; + } + +-static unsigned long minimum_target(void) ++unsigned long balloon_minimum_target(void) + { + #ifndef CONFIG_XEN + #define max_pfn num_physpages +@@ -406,7 +406,7 @@ static void balloon_process(struct work_ + void balloon_set_new_target(unsigned long target) + { + /* No need for lock. Not read-modify-write updates. */ +- bs.target_pages = max(target, minimum_target()); ++ bs.target_pages = max(target, balloon_minimum_target()); + schedule_work(&balloon_worker); + } + +@@ -481,10 +481,13 @@ static int balloon_read(char *page, char + page, + "Current allocation: %8lu kB\n" + "Requested target: %8lu kB\n" ++ "Minimum target: %8lu kB\n" ++ "Maximum target: %8lu kB\n" + "Low-mem balloon: %8lu kB\n" + "High-mem balloon: %8lu kB\n" + "Driver pages: %8lu kB\n", + PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages), ++ PAGES2KB(balloon_minimum_target()), PAGES2KB(num_physpages), + PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high), + PAGES2KB(bs.driver_pages)); + +--- sle11-2009-06-29.orig/drivers/xen/balloon/common.h 2009-06-29 15:24:00.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/balloon/common.h 2009-06-29 15:43:29.000000000 +0200 +@@ -52,5 +52,6 @@ int balloon_sysfs_init(void); + void balloon_sysfs_exit(void); + + void balloon_set_new_target(unsigned long target); ++unsigned long balloon_minimum_target(void); + + #endif /* __XEN_BALLOON_COMMON_H__ */ +--- sle11-2009-06-29.orig/drivers/xen/balloon/sysfs.c 2009-06-29 15:31:06.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/balloon/sysfs.c 2009-06-29 15:43:35.000000000 +0200 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -53,6 +54,8 @@ + static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL) + + BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages)); ++BALLOON_SHOW(min_kb, "%lu\n", PAGES2KB(balloon_minimum_target())); ++BALLOON_SHOW(max_kb, "%lu\n", PAGES2KB(num_physpages)); + BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low)); + BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high)); + BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages)); +@@ -94,6 +97,8 @@ static struct sysdev_attribute *balloon_ + + static struct attribute *balloon_info_attrs[] = { + &attr_current_kb.attr, ++ &attr_min_kb.attr, ++ &attr_max_kb.attr, + &attr_low_kb.attr, + &attr_high_kb.attr, + &attr_driver_kb.attr, diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-blkback-bimodal-suse b/src/patches/suse-2.6.27.31/patches.xen/xen-blkback-bimodal-suse new file mode 100644 index 000000000..3ca681fd9 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-blkback-bimodal-suse @@ -0,0 +1,43 @@ +Subject: backward compatibility +From: Gerd Hoffmann +Patch-mainline: obsolete + +--- + linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c | 6 ++++++ + linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c | 6 ++++++ + 2 files changed, 12 insertions(+) + +Index: head-2008-09-15/drivers/xen/blkback/xenbus.c +=================================================================== +--- head-2008-09-15.orig/drivers/xen/blkback/xenbus.c 2008-09-15 14:32:56.000000000 +0200 ++++ head-2008-09-15/drivers/xen/blkback/xenbus.c 2008-09-15 15:10:36.000000000 +0200 +@@ -496,6 +496,12 @@ static int connect_ring(struct backend_i + be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; + else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) + be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; ++#if 1 /* maintain compatibility with early sles10-sp1 and paravirt netware betas */ ++ else if (0 == strcmp(protocol, "1")) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; ++ else if (0 == strcmp(protocol, "2")) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; ++#endif + else { + xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); + return -1; +Index: head-2008-09-15/drivers/xen/blktap/xenbus.c +=================================================================== +--- head-2008-09-15.orig/drivers/xen/blktap/xenbus.c 2008-09-15 14:32:56.000000000 +0200 ++++ head-2008-09-15/drivers/xen/blktap/xenbus.c 2008-09-15 15:10:36.000000000 +0200 +@@ -434,6 +434,12 @@ static int connect_ring(struct backend_i + be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; + else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) + be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; ++#if 1 /* maintain compatibility with early sles10-sp1 and paravirt netware betas */ ++ else if (0 == strcmp(protocol, "1")) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; ++ else if (0 == strcmp(protocol, "2")) ++ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; ++#endif + else { + xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); + return -1; diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-blkback-cdrom b/src/patches/suse-2.6.27.31/patches.xen/xen-blkback-cdrom new file mode 100644 index 000000000..8a0dc2e7f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-blkback-cdrom @@ -0,0 +1,269 @@ +Subject: CDROM removable media-present attribute plus handling code +From: plc@novell.com +Patch-mainline: obsolete +References: 159907 + +Index: head-2008-05-08/drivers/xen/blkback/Makefile +=================================================================== +--- head-2008-05-08.orig/drivers/xen/blkback/Makefile 2008-05-08 15:34:23.000000000 +0200 ++++ head-2008-05-08/drivers/xen/blkback/Makefile 2008-05-08 15:05:13.000000000 +0200 +@@ -1,3 +1,3 @@ + obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkbk.o + +-blkbk-y := blkback.o xenbus.o interface.o vbd.o ++blkbk-y := blkback.o xenbus.o interface.o vbd.o cdrom.o +Index: head-2008-05-08/drivers/xen/blkback/cdrom.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-05-08/drivers/xen/blkback/cdrom.c 2008-05-13 15:34:40.000000000 +0200 +@@ -0,0 +1,162 @@ ++/****************************************************************************** ++ * blkback/cdrom.c ++ * ++ * Routines for managing cdrom watch and media-present attribute of a ++ * cdrom type virtual block device (VBD). ++ * ++ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand ++ * Copyright (c) 2007 Pat Campbell ++ * ++ * 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; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#include "common.h" ++ ++#undef DPRINTK ++#define DPRINTK(_f, _a...) \ ++ printk("(%s() file=%s, line=%d) " _f "\n", \ ++ __PRETTY_FUNCTION__, __FILE__ , __LINE__ , ##_a ) ++ ++ ++#define MEDIA_PRESENT "media-present" ++ ++static void cdrom_media_changed(struct xenbus_watch *, const char **, unsigned int); ++ ++/** ++ * Writes media-present=1 attribute for the given vbd device if not ++ * already there ++ */ ++static int cdrom_xenstore_write_media_present(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ struct xenbus_transaction xbt; ++ int err; ++ int media_present; ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, MEDIA_PRESENT, "%d", ++ &media_present); ++ if (0 < err) { ++ DPRINTK("already written err%d", err); ++ return(0); ++ } ++ media_present = 1; ++ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ return(-1); ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, MEDIA_PRESENT, "%d", media_present ); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "writing %s/%s", ++ dev->nodename, MEDIA_PRESENT); ++ goto abort; ++ } ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ if (err) ++ xenbus_dev_fatal(dev, err, "ending transaction"); ++ return 0; ++ abort: ++ xenbus_transaction_end(xbt, 1); ++ return -1; ++} ++ ++/** ++ * ++ */ ++static int cdrom_is_type(struct backend_info *be) ++{ ++ DPRINTK("type:%x", be->blkif->vbd.type ); ++ return (be->blkif->vbd.type & VDISK_CDROM) ++ && (be->blkif->vbd.type & GENHD_FL_REMOVABLE); ++} ++ ++/** ++ * ++ */ ++void cdrom_add_media_watch(struct backend_info *be) ++{ ++ struct xenbus_device *dev = be->dev; ++ int err; ++ ++ DPRINTK("nodename:%s", dev->nodename); ++ if (cdrom_is_type(be)) { ++ DPRINTK("is a cdrom"); ++ if ( cdrom_xenstore_write_media_present(be) == 0 ) { ++ DPRINTK( "xenstore wrote OK"); ++ err = xenbus_watch_path2(dev, dev->nodename, MEDIA_PRESENT, ++ &be->backend_cdrom_watch, ++ cdrom_media_changed); ++ if (err) ++ DPRINTK( "media_present watch add failed" ); ++ } ++ } ++} ++ ++/** ++ * Callback received when the "media_present" xenstore node is changed ++ */ ++static void cdrom_media_changed(struct xenbus_watch *watch, ++ const char **vec, unsigned int len) ++{ ++ int err; ++ unsigned media_present; ++ struct backend_info *be ++ = container_of(watch, struct backend_info, backend_cdrom_watch); ++ struct xenbus_device *dev = be->dev; ++ ++ if (!cdrom_is_type(be)) { ++ DPRINTK("callback not for a cdrom" ); ++ return; ++ } ++ ++ err = xenbus_scanf(XBT_NIL, dev->nodename, MEDIA_PRESENT, "%d", ++ &media_present); ++ if (err == 0 || err == -ENOENT) { ++ DPRINTK("xenbus_read of cdrom media_present node error:%d",err); ++ return; ++ } ++ ++ if (media_present == 0) ++ vbd_free(&be->blkif->vbd); ++ else { ++ char *p = strrchr(dev->otherend, '/') + 1; ++ long handle = simple_strtoul(p, NULL, 0); ++ ++ if (!be->blkif->vbd.bdev) { ++ err = vbd_create(be->blkif, handle, be->major, be->minor, ++ !strchr(be->mode, 'w'), 1); ++ if (err) { ++ be->major = be->minor = 0; ++ xenbus_dev_fatal(dev, err, "creating vbd structure"); ++ return; ++ } ++ } ++ } ++} +Index: head-2008-05-08/drivers/xen/blkback/common.h +=================================================================== +--- head-2008-05-08.orig/drivers/xen/blkback/common.h 2008-05-08 15:34:23.000000000 +0200 ++++ head-2008-05-08/drivers/xen/blkback/common.h 2008-05-13 15:35:13.000000000 +0200 +@@ -96,6 +96,17 @@ typedef struct blkif_st { + grant_ref_t shmem_ref; + } blkif_t; + ++struct backend_info ++{ ++ struct xenbus_device *dev; ++ blkif_t *blkif; ++ struct xenbus_watch backend_watch; ++ struct xenbus_watch backend_cdrom_watch; ++ unsigned major; ++ unsigned minor; ++ char *mode; ++}; ++ + blkif_t *blkif_alloc(domid_t domid); + void blkif_disconnect(blkif_t *blkif); + void blkif_free(blkif_t *blkif); +@@ -136,4 +147,7 @@ int blkif_schedule(void *arg); + int blkback_barrier(struct xenbus_transaction xbt, + struct backend_info *be, int state); + ++/* cdrom media change */ ++void cdrom_add_media_watch(struct backend_info *be); ++ + #endif /* __BLKIF__BACKEND__COMMON_H__ */ +Index: head-2008-05-08/drivers/xen/blkback/vbd.c +=================================================================== +--- head-2008-05-08.orig/drivers/xen/blkback/vbd.c 2008-05-08 15:34:23.000000000 +0200 ++++ head-2008-05-08/drivers/xen/blkback/vbd.c 2008-05-08 15:05:13.000000000 +0200 +@@ -106,6 +106,9 @@ int vbd_translate(struct phys_req *req, + if ((operation != READ) && vbd->readonly) + goto out; + ++ if (vbd->bdev == NULL) ++ goto out; ++ + if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd))) + goto out; + +Index: head-2008-05-08/drivers/xen/blkback/xenbus.c +=================================================================== +--- head-2008-05-08.orig/drivers/xen/blkback/xenbus.c 2008-05-08 15:34:23.000000000 +0200 ++++ head-2008-05-08/drivers/xen/blkback/xenbus.c 2008-05-08 15:05:13.000000000 +0200 +@@ -28,16 +28,6 @@ + pr_debug("blkback/xenbus (%s:%d) " fmt ".\n", \ + __FUNCTION__, __LINE__, ##args) + +-struct backend_info +-{ +- struct xenbus_device *dev; +- blkif_t *blkif; +- struct xenbus_watch backend_watch; +- unsigned major; +- unsigned minor; +- char *mode; +-}; +- + static void connect(struct backend_info *); + static int connect_ring(struct backend_info *); + static void backend_changed(struct xenbus_watch *, const char **, +@@ -183,6 +173,12 @@ static int blkback_remove(struct xenbus_ + be->backend_watch.node = NULL; + } + ++ if (be->backend_cdrom_watch.node) { ++ unregister_xenbus_watch(&be->backend_cdrom_watch); ++ kfree(be->backend_cdrom_watch.node); ++ be->backend_cdrom_watch.node = NULL; ++ } ++ + if (be->blkif) { + blkif_disconnect(be->blkif); + vbd_free(&be->blkif->vbd); +@@ -339,6 +335,9 @@ static void backend_changed(struct xenbu + + /* We're potentially connected now */ + update_blkif_status(be->blkif); ++ ++ /* Add watch for cdrom media status if necessay */ ++ cdrom_add_media_watch(be); + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-blkfront-cdrom b/src/patches/suse-2.6.27.31/patches.xen/xen-blkfront-cdrom new file mode 100644 index 000000000..1f8120e8c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-blkfront-cdrom @@ -0,0 +1,678 @@ +From: plc@novell.com +Subject: implement forwarding of CD-ROM specific commands +Patch-mainline: obsolete +References: fate#300964 + +--- sle11-2009-06-04.orig/drivers/cdrom/Makefile 2009-06-04 10:17:48.000000000 +0200 ++++ sle11-2009-06-04/drivers/cdrom/Makefile 2009-06-04 10:47:04.000000000 +0200 +@@ -9,6 +9,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) += + obj-$(CONFIG_BLK_DEV_SR) += cdrom.o + obj-$(CONFIG_PARIDE_PCD) += cdrom.o + obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o ++obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += cdrom.o + + obj-$(CONFIG_VIOCD) += viocd.o cdrom.o + obj-$(CONFIG_GDROM) += gdrom.o cdrom.o +--- sle11-2009-06-04.orig/drivers/xen/blkfront/Makefile 2009-06-04 10:17:48.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkfront/Makefile 2009-06-04 10:47:04.000000000 +0200 +@@ -1,5 +1,5 @@ + + obj-$(CONFIG_XEN_BLKDEV_FRONTEND) := xenblk.o + +-xenblk-objs := blkfront.o vbd.o ++xenblk-objs := blkfront.o vbd.o vcd.o + +--- sle11-2009-06-04.orig/drivers/xen/blkfront/blkfront.c 2009-06-04 10:46:54.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkfront/blkfront.c 2009-06-04 10:47:04.000000000 +0200 +@@ -377,6 +377,8 @@ static void connect(struct blkfront_info + add_disk(info->gd); + + info->is_ready = 1; ++ ++ register_vcd(info); + } + + /** +@@ -407,6 +409,8 @@ static void blkfront_closing(struct xenb + + xlvbd_sysfs_delif(info); + ++ unregister_vcd(info); ++ + xlvbd_del(info); + + out: +--- sle11-2009-06-04.orig/drivers/xen/blkfront/block.h 2009-06-04 10:21:09.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkfront/block.h 2009-06-04 10:47:04.000000000 +0200 +@@ -155,4 +155,8 @@ static inline void xlvbd_sysfs_delif(str + } + #endif + ++/* Virtual cdrom block-device */ ++extern void register_vcd(struct blkfront_info *info); ++extern void unregister_vcd(struct blkfront_info *info); ++ + #endif /* __XEN_DRIVERS_BLOCK_H__ */ +--- sle11-2009-06-04.orig/drivers/xen/blkfront/vbd.c 2009-06-04 10:21:09.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkfront/vbd.c 2009-06-04 10:47:04.000000000 +0200 +@@ -281,7 +281,8 @@ xlvbd_add(blkif_sector_t capacity, int v + goto out; + info->mi = mi; + +- if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0) ++ if (!(vdisk_info & VDISK_CDROM) && ++ (minor & ((1 << mi->type->partn_shift) - 1)) == 0) + nr_minors = 1 << mi->type->partn_shift; + + gd = alloc_disk(nr_minors); +@@ -290,7 +291,7 @@ xlvbd_add(blkif_sector_t capacity, int v + + offset = mi->index * mi->type->disks_per_major + + (minor >> mi->type->partn_shift); +- if (nr_minors > 1) { ++ if (nr_minors > 1 || (vdisk_info & VDISK_CDROM)) { + if (offset < 26) { + sprintf(gd->disk_name, "%s%c", + mi->type->diskname, 'a' + offset ); +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-04/drivers/xen/blkfront/vcd.c 2009-06-04 10:47:04.000000000 +0200 +@@ -0,0 +1,476 @@ ++/******************************************************************************* ++* vcd.c ++* ++* Implements CDROM cmd packet passing between frontend guest and backend driver. ++* ++* Copyright (c) 2008, Pat Campell plc@novell.com ++* ++* Permission is hereby granted, free of charge, to any person obtaining a copy ++* of this source file (the "Software"), to deal in the Software without ++* restriction, including without limitation the rights to use, copy, modify, ++* merge, publish, distribute, sublicense, and/or sell copies of the Software, ++* and to permit persons to whom the Software is furnished to do so, subject to ++* the following conditions: ++* ++* The above copyright notice and this permission notice shall be included in ++* all copies or substantial portions of the Software. ++* ++* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++* IN THE SOFTWARE. ++*/ ++ ++#define REVISION "$Revision: 1.0 $" ++ ++#include ++#include ++#include ++#include ++#include ++#include "block.h" ++ ++/* List of cdrom_device_info, can have as many as blkfront supports */ ++struct vcd_disk { ++ struct list_head vcd_entry; ++ struct cdrom_device_info vcd_cdrom_info; ++ spinlock_t vcd_cdrom_info_lock; ++}; ++static LIST_HEAD(vcd_disks); ++static DEFINE_SPINLOCK(vcd_disks_lock); ++ ++static struct vcd_disk * xencdrom_get_list_entry(struct gendisk *disk) ++{ ++ struct vcd_disk * ret_vcd = NULL; ++ struct vcd_disk * vcd; ++ ++ spin_lock(&vcd_disks_lock); ++ list_for_each_entry(vcd, &vcd_disks, vcd_entry) { ++ if (vcd->vcd_cdrom_info.disk == disk) { ++ spin_lock(&vcd->vcd_cdrom_info_lock); ++ ret_vcd = vcd; ++ break; ++ } ++ } ++ spin_unlock(&vcd_disks_lock); ++ return ret_vcd; ++} ++ ++static void submit_message(struct blkfront_info *info, void * sp) ++{ ++ struct request *req = NULL; ++ ++ req = blk_get_request(info->rq, READ, __GFP_WAIT); ++ if (blk_rq_map_kern(info->rq, req, sp, PAGE_SIZE, __GFP_WAIT)) ++ goto out; ++ ++ req->rq_disk = info->gd; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) ++ req->cmd_type = REQ_TYPE_BLOCK_PC; ++ req->cmd_flags |= REQ_NOMERGE; ++#else ++ req->flags |= REQ_BLOCK_PC; ++#endif ++ req->sector = 0; ++ req->nr_sectors = 1; ++ req->timeout = 60*HZ; ++ ++ blk_execute_rq(req->q, info->gd, req, 1); ++ ++out: ++ blk_put_request(req); ++} ++ ++static int submit_cdrom_cmd(struct blkfront_info *info, ++ struct packet_command * cgc) ++{ ++ int ret = 0; ++ struct page *page; ++ size_t size; ++ union xen_block_packet *sp; ++ struct xen_cdrom_packet *xcp; ++ struct vcd_generic_command * vgc; ++ ++ if (cgc->buffer && cgc->buflen > MAX_PACKET_DATA) { ++ printk(KERN_WARNING "%s() Packet buffer length is to large \n", __func__); ++ return -EIO; ++ } ++ ++ page = alloc_page(GFP_NOIO); ++ if (!page) { ++ printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); ++ return -ENOMEM; ++ } ++ ++ size = PAGE_SIZE; ++ memset(page_address(page), 0, PAGE_SIZE); ++ sp = page_address(page); ++ xcp = &(sp->xcp); ++ xcp->type = XEN_TYPE_CDROM_PACKET; ++ xcp->payload_offset = PACKET_PAYLOAD_OFFSET; ++ ++ vgc = (struct vcd_generic_command *)((char *)sp + xcp->payload_offset); ++ memcpy(vgc->cmd, cgc->cmd, CDROM_PACKET_SIZE); ++ vgc->stat = cgc->stat; ++ vgc->data_direction = cgc->data_direction; ++ vgc->quiet = cgc->quiet; ++ vgc->timeout = cgc->timeout; ++ if (cgc->sense) { ++ vgc->sense_offset = PACKET_SENSE_OFFSET; ++ memcpy((char *)sp + vgc->sense_offset, cgc->sense, sizeof(struct request_sense)); ++ } ++ if (cgc->buffer) { ++ vgc->buffer_offset = PACKET_BUFFER_OFFSET; ++ memcpy((char *)sp + vgc->buffer_offset, cgc->buffer, cgc->buflen); ++ vgc->buflen = cgc->buflen; ++ } ++ ++ submit_message(info,sp); ++ ++ if (xcp->ret) ++ ret = xcp->err; ++ ++ if (cgc->sense) { ++ memcpy(cgc->sense, (char *)sp + PACKET_SENSE_OFFSET, sizeof(struct request_sense)); ++ } ++ if (cgc->buffer && cgc->buflen) { ++ memcpy(cgc->buffer, (char *)sp + PACKET_BUFFER_OFFSET, cgc->buflen); ++ } ++ ++ __free_page(page); ++ return ret; ++} ++ ++ ++static int xencdrom_open(struct cdrom_device_info *cdi, int purpose) ++{ ++ int ret = 0; ++ struct page *page; ++ struct blkfront_info *info; ++ union xen_block_packet *sp; ++ struct xen_cdrom_open *xco; ++ ++ info = cdi->disk->private_data; ++ ++ if (strlen(info->xbdev->otherend) > MAX_PACKET_DATA) { ++ return -EIO; ++ } ++ ++ page = alloc_page(GFP_NOIO); ++ if (!page) { ++ printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); ++ return -ENOMEM; ++ } ++ ++ memset(page_address(page), 0, PAGE_SIZE); ++ sp = page_address(page); ++ xco = &(sp->xco); ++ xco->type = XEN_TYPE_CDROM_OPEN; ++ xco->payload_offset = sizeof(struct xen_cdrom_open); ++ strcpy((char *)sp + xco->payload_offset, info->xbdev->otherend); ++ ++ submit_message(info,sp); ++ ++ if (xco->ret) { ++ ret = xco->err; ++ goto out; ++ } ++ ++ if (xco->media_present) ++ set_capacity(cdi->disk, xco->sectors); ++ ++out: ++ __free_page(page); ++ return ret; ++} ++ ++static void xencdrom_release(struct cdrom_device_info *cdi) ++{ ++} ++ ++static int xencdrom_media_changed(struct cdrom_device_info *cdi, int disc_nr) ++{ ++ int ret; ++ struct page *page; ++ struct blkfront_info *info; ++ union xen_block_packet *sp; ++ struct xen_cdrom_media_changed *xcmc; ++ ++ info = cdi->disk->private_data; ++ ++ page = alloc_page(GFP_NOIO); ++ if (!page) { ++ printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); ++ return -ENOMEM; ++ } ++ ++ memset(page_address(page), 0, PAGE_SIZE); ++ sp = page_address(page); ++ xcmc = &(sp->xcmc); ++ xcmc->type = XEN_TYPE_CDROM_MEDIA_CHANGED; ++ submit_message(info,sp); ++ ret = xcmc->media_changed; ++ ++ __free_page(page); ++ ++ return ret; ++} ++ ++static int xencdrom_tray_move(struct cdrom_device_info *cdi, int position) ++{ ++ int ret; ++ struct packet_command cgc; ++ struct blkfront_info *info; ++ ++ info = cdi->disk->private_data; ++ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); ++ cgc.cmd[0] = GPCMD_START_STOP_UNIT; ++ if (position) ++ cgc.cmd[4] = 2; ++ else ++ cgc.cmd[4] = 3; ++ ret = submit_cdrom_cmd(info, &cgc); ++ return ret; ++} ++ ++static int xencdrom_lock_door(struct cdrom_device_info *cdi, int lock) ++{ ++ int ret = 0; ++ struct blkfront_info *info; ++ struct packet_command cgc; ++ ++ info = cdi->disk->private_data; ++ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); ++ cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; ++ cgc.cmd[4] = lock; ++ ret = submit_cdrom_cmd(info, &cgc); ++ return ret; ++} ++ ++static int xencdrom_packet(struct cdrom_device_info *cdi, ++ struct packet_command *cgc) ++{ ++ int ret = -EIO; ++ struct blkfront_info *info; ++ ++ info = cdi->disk->private_data; ++ ret = submit_cdrom_cmd(info, cgc); ++ cgc->stat = ret; ++ return ret; ++} ++ ++static int xencdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, ++ void *arg) ++{ ++ return -EINVAL; ++} ++ ++/* Query backend to see if CDROM packets are supported */ ++static int xencdrom_supported(struct blkfront_info *info) ++{ ++ struct page *page; ++ union xen_block_packet *sp; ++ struct xen_cdrom_support *xcs; ++ ++ page = alloc_page(GFP_NOIO); ++ if (!page) { ++ printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); ++ return -ENOMEM; ++ } ++ ++ memset(page_address(page), 0, PAGE_SIZE); ++ sp = page_address(page); ++ xcs = &(sp->xcs); ++ xcs->type = XEN_TYPE_CDROM_SUPPORT; ++ submit_message(info,sp); ++ return xcs->supported; ++} ++ ++static struct cdrom_device_ops xencdrom_dops = { ++ .open = xencdrom_open, ++ .release = xencdrom_release, ++ .media_changed = xencdrom_media_changed, ++ .tray_move = xencdrom_tray_move, ++ .lock_door = xencdrom_lock_door, ++ .generic_packet = xencdrom_packet, ++ .audio_ioctl = xencdrom_audio_ioctl, ++ .capability = (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | \ ++ CDC_MEDIA_CHANGED | CDC_GENERIC_PACKET | CDC_DVD | \ ++ CDC_CD_R), ++ .n_minors = 1, ++}; ++ ++static int xencdrom_block_open(struct inode *inode, struct file *file) ++{ ++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; ++ struct vcd_disk * vcd; ++ int ret = 0; ++ ++ if ((vcd = xencdrom_get_list_entry(info->gd))) { ++ ret = cdrom_open(&vcd->vcd_cdrom_info, inode, file); ++ info->users = vcd->vcd_cdrom_info.use_count; ++ spin_unlock(&vcd->vcd_cdrom_info_lock); ++ } ++ return ret; ++} ++ ++static int xencdrom_block_release(struct inode *inode, struct file *file) ++{ ++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; ++ struct vcd_disk * vcd; ++ int ret = 0; ++ ++ if ((vcd = xencdrom_get_list_entry(info->gd))) { ++ ret = cdrom_release(&vcd->vcd_cdrom_info, file); ++ spin_unlock(&vcd->vcd_cdrom_info_lock); ++ if (vcd->vcd_cdrom_info.use_count == 0) { ++ info->users = 1; ++ blkif_release(inode, file); ++ } ++ } ++ return ret; ++} ++ ++static int xencdrom_block_ioctl(struct inode *inode, struct file *file, ++ unsigned cmd, unsigned long arg) ++{ ++ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; ++ struct vcd_disk * vcd; ++ int ret = 0; ++ ++ if (!(vcd = xencdrom_get_list_entry(info->gd))) ++ goto out; ++ ++ switch (cmd) { ++ case 2285: /* SG_IO */ ++ ret = -ENOSYS; ++ break; ++ case CDROMEJECT: ++ ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 1); ++ break; ++ case CDROMCLOSETRAY: ++ ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 0); ++ break; ++ case CDROM_GET_CAPABILITY: ++ ret = vcd->vcd_cdrom_info.ops->capability & ~vcd->vcd_cdrom_info.mask; ++ break; ++ case CDROM_SET_OPTIONS: ++ ret = vcd->vcd_cdrom_info.options; ++ break; ++ case CDROM_SEND_PACKET: ++ { ++ struct packet_command * cgc = (struct packet_command *)arg; ++ ret = submit_cdrom_cmd(info, cgc); ++ } ++ break; ++ default: ++ /* Not supported, augment supported above if necessary */ ++ printk( "%s():%d Unsupported IOCTL:%x \n", __func__, __LINE__, cmd); ++ ret = -ENOTTY; ++ break; ++ } ++ spin_unlock(&vcd->vcd_cdrom_info_lock); ++out: ++ return ret; ++} ++ ++/* Called as result of cdrom_open, vcd_cdrom_info_lock already held */ ++static int xencdrom_block_media_changed(struct gendisk *disk) ++{ ++ struct vcd_disk * vcd; ++ struct vcd_disk * ret_vcd = NULL; ++ int ret = 0; ++ ++ spin_lock(&vcd_disks_lock); ++ list_for_each_entry(vcd, &vcd_disks, vcd_entry) { ++ if (vcd->vcd_cdrom_info.disk == disk) { ++ ret_vcd = vcd; ++ break; ++ } ++ } ++ spin_unlock(&vcd_disks_lock); ++ if (ret_vcd) { ++ ret = cdrom_media_changed(&ret_vcd->vcd_cdrom_info); ++ } ++ return ret; ++} ++ ++static struct block_device_operations xencdrom_bdops = ++{ ++ .owner = THIS_MODULE, ++ .open = xencdrom_block_open, ++ .release = xencdrom_block_release, ++ .ioctl = xencdrom_block_ioctl, ++ .media_changed = xencdrom_block_media_changed, ++}; ++ ++void register_vcd(struct blkfront_info *info) ++{ ++ struct gendisk * gd = info->gd; ++ struct vcd_disk * vcd; ++ ++ /* Make sure this is for a CD device */ ++ if (!(gd->flags & GENHD_FL_CD)) ++ goto out; ++ ++ /* Make sure we have backend support */ ++ if (!xencdrom_supported(info)) { ++ goto out; ++ } ++ ++ /* Create new vcd_disk and fill in cdrom_info */ ++ vcd = (struct vcd_disk *)kzalloc(sizeof(struct vcd_disk), GFP_KERNEL); ++ if (!vcd) { ++ printk(KERN_INFO "%s(): Unable to allocate vcd struct!\n", __func__); ++ goto out; ++ } ++ spin_lock_init(&vcd->vcd_cdrom_info_lock); ++ ++ vcd->vcd_cdrom_info.ops = &xencdrom_dops; ++ vcd->vcd_cdrom_info.speed = 4; ++ vcd->vcd_cdrom_info.capacity = 1; ++ vcd->vcd_cdrom_info.options = 0; ++ strcpy(vcd->vcd_cdrom_info.name, gd->disk_name); ++ vcd->vcd_cdrom_info.mask = ( CDC_CD_RW | CDC_DVD_R | CDC_DVD_RAM | ++ CDC_SELECT_DISC | CDC_SELECT_SPEED | ++ CDC_MRW | CDC_MRW_W | CDC_RAM); ++ ++ if (register_cdrom(&(vcd->vcd_cdrom_info)) != 0) { ++ printk(KERN_WARNING "%s() Cannot register blkdev as a cdrom %d!\n", __func__, ++ gd->major); ++ goto err_out; ++ } ++ xencdrom_bdops.owner = gd->fops->owner; ++ gd->fops = &xencdrom_bdops; ++ vcd->vcd_cdrom_info.disk = gd; ++ ++ spin_lock(&vcd_disks_lock); ++ list_add(&(vcd->vcd_entry), &vcd_disks); ++ spin_unlock(&vcd_disks_lock); ++out: ++ return; ++err_out: ++ kfree(vcd); ++} ++ ++void unregister_vcd(struct blkfront_info *info) { ++ struct gendisk * gd = info->gd; ++ struct vcd_disk * vcd; ++ ++ spin_lock(&vcd_disks_lock); ++ list_for_each_entry(vcd, &vcd_disks, vcd_entry) { ++ if (vcd->vcd_cdrom_info.disk == gd) { ++ spin_lock(&vcd->vcd_cdrom_info_lock); ++ unregister_cdrom(&vcd->vcd_cdrom_info); ++ list_del(&vcd->vcd_entry); ++ spin_unlock(&vcd->vcd_cdrom_info_lock); ++ kfree(vcd); ++ break; ++ } ++ } ++ spin_unlock(&vcd_disks_lock); ++} ++ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-04/include/xen/interface/io/cdromif.h 2009-06-04 10:47:04.000000000 +0200 +@@ -0,0 +1,120 @@ ++/****************************************************************************** ++ * cdromif.h ++ * ++ * Shared definitions between backend driver and Xen guest Virtual CDROM ++ * block device. ++ * ++ * Copyright (c) 2008, Pat Campell plc@novell.com ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __XEN_PUBLIC_IO_CDROMIF_H__ ++#define __XEN_PUBLIC_IO_CDROMIF_H__ ++ ++/* ++ * Queries backend for CDROM support ++ */ ++#define XEN_TYPE_CDROM_SUPPORT _IO('c', 1) ++ ++struct xen_cdrom_support ++{ ++ uint32_t type; ++ int8_t ret; /* returned, 0 succeded, -1 error */ ++ int8_t err; /* returned, backend errno */ ++ int8_t supported; /* returned, 1 supported */ ++}; ++ ++/* ++ * Opens backend device, returns drive geometry or ++ * any encountered errors ++ */ ++#define XEN_TYPE_CDROM_OPEN _IO('c', 2) ++ ++struct xen_cdrom_open ++{ ++ uint32_t type; ++ int8_t ret; ++ int8_t err; ++ int8_t pad; ++ int8_t media_present; /* returned */ ++ uint32_t sectors; /* returned */ ++ uint32_t sector_size; /* returned */ ++ int32_t payload_offset; /* offset to backend node name payload */ ++}; ++ ++/* ++ * Queries backend for media changed status ++ */ ++#define XEN_TYPE_CDROM_MEDIA_CHANGED _IO('c', 3) ++ ++struct xen_cdrom_media_changed ++{ ++ uint32_t type; ++ int8_t ret; ++ int8_t err; ++ int8_t media_changed; /* returned */ ++}; ++ ++/* ++ * Sends vcd generic CDROM packet to backend, followed ++ * immediately by the vcd_generic_command payload ++ */ ++#define XEN_TYPE_CDROM_PACKET _IO('c', 4) ++ ++struct xen_cdrom_packet ++{ ++ uint32_t type; ++ int8_t ret; ++ int8_t err; ++ int8_t pad[2]; ++ int32_t payload_offset; /* offset to vcd_generic_command payload */ ++}; ++ ++/* CDROM_PACKET_COMMAND, payload for XEN_TYPE_CDROM_PACKET */ ++struct vcd_generic_command ++{ ++ uint8_t cmd[CDROM_PACKET_SIZE]; ++ uint8_t pad[4]; ++ uint32_t buffer_offset; ++ uint32_t buflen; ++ int32_t stat; ++ uint32_t sense_offset; ++ uint8_t data_direction; ++ uint8_t pad1[3]; ++ int32_t quiet; ++ int32_t timeout; ++}; ++ ++union xen_block_packet ++{ ++ uint32_t type; ++ struct xen_cdrom_support xcs; ++ struct xen_cdrom_open xco; ++ struct xen_cdrom_media_changed xcmc; ++ struct xen_cdrom_packet xcp; ++}; ++ ++#define PACKET_PAYLOAD_OFFSET (sizeof(struct xen_cdrom_packet)) ++#define PACKET_SENSE_OFFSET (PACKET_PAYLOAD_OFFSET + sizeof(struct vcd_generic_command)) ++#define PACKET_BUFFER_OFFSET (PACKET_SENSE_OFFSET + sizeof(struct request_sense)) ++#define MAX_PACKET_DATA (PAGE_SIZE - sizeof(struct xen_cdrom_packet) - \ ++ sizeof(struct vcd_generic_command) - sizeof(struct request_sense)) ++ ++#endif diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-blkif-protocol-fallback-hack b/src/patches/suse-2.6.27.31/patches.xen/xen-blkif-protocol-fallback-hack new file mode 100644 index 000000000..9b32d13d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-blkif-protocol-fallback-hack @@ -0,0 +1,203 @@ +Subject: 32-on-64 blkif protocol negotiation fallback for old guests. +From: kraxel@suse.de +References: 244055 +Patch-mainline: never. + +See the comment below. Oh well. + +--- + drivers/xen/blkback/xenbus.c | 10 +-- + drivers/xen/blktap/xenbus.c | 10 +-- + drivers/xen/core/Makefile | 2 + drivers/xen/core/domctl.c | 133 +++++++++++++++++++++++++++++++++++++++++++ + drivers/xen/core/domctl.h | 2 + 5 files changed, 148 insertions(+), 9 deletions(-) + +Index: head-2008-09-15/drivers/xen/blkback/xenbus.c +=================================================================== +--- head-2008-09-15.orig/drivers/xen/blkback/xenbus.c 2008-09-15 15:10:36.000000000 +0200 ++++ head-2008-09-15/drivers/xen/blkback/xenbus.c 2008-09-15 15:10:39.000000000 +0200 +@@ -21,6 +21,7 @@ + #include + #include + #include "common.h" ++#include "../core/domctl.h" + + #undef DPRINTK + #define DPRINTK(fmt, args...) \ +@@ -488,8 +489,10 @@ static int connect_ring(struct backend_i + be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; + err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", + "%63s", protocol, NULL); +- if (err) +- strcpy(protocol, "unspecified, assuming native"); ++ if (err) { ++ strcpy(protocol, "unspecified"); ++ be->blkif->blk_protocol = xen_guest_blkif_protocol(be->blkif->domid); ++ } + else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) + be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; + else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) +Index: head-2008-09-15/drivers/xen/blktap/xenbus.c +=================================================================== +--- head-2008-09-15.orig/drivers/xen/blktap/xenbus.c 2008-09-15 15:10:36.000000000 +0200 ++++ head-2008-09-15/drivers/xen/blktap/xenbus.c 2008-09-15 15:10:39.000000000 +0200 +@@ -39,6 +39,7 @@ + #include + #include + #include "common.h" ++#include "../core/domctl.h" + + + struct backend_info +@@ -426,8 +427,10 @@ static int connect_ring(struct backend_i + be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; + err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", + "%63s", protocol, NULL); +- if (err) +- strcpy(protocol, "unspecified, assuming native"); ++ if (err) { ++ strcpy(protocol, "unspecified"); ++ be->blkif->blk_protocol = xen_guest_blkif_protocol(be->blkif->domid); ++ } + else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) + be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; + else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) +Index: head-2008-09-15/drivers/xen/core/Makefile +=================================================================== +--- head-2008-09-15.orig/drivers/xen/core/Makefile 2008-09-15 14:45:31.000000000 +0200 ++++ head-2008-09-15/drivers/xen/core/Makefile 2008-09-15 15:10:39.000000000 +0200 +@@ -2,7 +2,7 @@ + # Makefile for the linux kernel. + # + +-obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o firmware.o ++obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o firmware.o domctl.o + + obj-$(CONFIG_PCI) += pci.o + obj-$(CONFIG_PROC_FS) += xen_proc.o +Index: head-2008-09-15/drivers/xen/core/domctl.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-09-15/drivers/xen/core/domctl.c 2008-09-15 15:10:39.000000000 +0200 +@@ -0,0 +1,113 @@ ++/* ++ * !!! dirty hack alert !!! ++ * ++ * Problem: old guests kernels don't have a "protocol" node ++ * in the frontend xenstore directory, so mixing ++ * 32 and 64bit domains doesn't work. ++ * ++ * Upstream plans to solve this in the tools, by letting them ++ * create a protocol node. Which certainly makes sense. ++ * But it isn't trivial and isn't done yet. Too bad. ++ * ++ * So for the time being we use the get_address_size domctl ++ * hypercall for a pretty good guess. Not nice as the domctl ++ * hypercall isn't supposed to be used by the kernel. Because ++ * we don't want to have dependencies between dom0 kernel and ++ * xen kernel versions. Now we have one. Ouch. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "domctl.h" ++ ++/* stuff copied from xen/interface/domctl.h, which we can't ++ * include directly for the reasons outlined above .... */ ++ ++#define XEN_DOMCTL_get_address_size 36 ++typedef struct xen_domctl_address_size { ++ uint32_t size; ++} xen_domctl_address_size_t; ++ ++typedef __attribute__((aligned(8))) uint64_t uint64_aligned_t; ++ ++union xen_domctl { ++ /* v4: sles10 sp1: xen 3.0.4 + 32-on-64 patches */ ++ struct { ++ uint32_t cmd; ++ uint32_t interface_version; ++ domid_t domain; ++ union { ++ /* left out lots of other struct xen_domctl_foobar */ ++ struct xen_domctl_address_size address_size; ++ uint64_t dummy_align; ++ uint8_t dummy_pad[128]; ++ } u; ++ } v4; ++ ++ /* v5: upstream: xen 3.1 */ ++ struct { ++ uint32_t cmd; ++ uint32_t interface_version; ++ domid_t domain; ++ union { ++ struct xen_domctl_address_size address_size; ++ uint64_aligned_t dummy_align; ++ uint8_t dummy_pad[128]; ++ } u; ++ } v5; ++}; ++ ++/* The actual code comes here */ ++ ++static inline int hypervisor_domctl(void *domctl) ++{ ++ return _hypercall1(int, domctl, domctl); ++} ++ ++int xen_guest_address_size(int domid) ++{ ++ union xen_domctl domctl; ++ int low, ret; ++ ++#define guest_address_size(ver) do { \ ++ memset(&domctl, 0, sizeof(domctl)); \ ++ domctl.v##ver.cmd = XEN_DOMCTL_get_address_size; \ ++ domctl.v##ver.interface_version = low = ver; \ ++ domctl.v##ver.domain = domid; \ ++ ret = hypervisor_domctl(&domctl) ?: domctl.v##ver.u.address_size.size; \ ++ if (ret == 32 || ret == 64) { \ ++ printk("v" #ver " domctl worked ok: dom%d is %d-bit\n", \ ++ domid, ret); \ ++ return ret; \ ++ } \ ++} while (0) ++ ++ guest_address_size(5); ++#if CONFIG_XEN_COMPAT < 0x030100 ++ guest_address_size(4); ++#endif ++ ++ ret = BITS_PER_LONG; ++ printk("v%d...5 domctls failed, assuming dom%d is native: %d\n", ++ low, domid, ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(xen_guest_address_size); ++ ++int xen_guest_blkif_protocol(int domid) ++{ ++ int address_size = xen_guest_address_size(domid); ++ ++ if (address_size == BITS_PER_LONG) ++ return BLKIF_PROTOCOL_NATIVE; ++ if (address_size == 32) ++ return BLKIF_PROTOCOL_X86_32; ++ if (address_size == 64) ++ return BLKIF_PROTOCOL_X86_64; ++ return BLKIF_PROTOCOL_NATIVE; ++} ++EXPORT_SYMBOL_GPL(xen_guest_blkif_protocol); +Index: head-2008-09-15/drivers/xen/core/domctl.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-09-15/drivers/xen/core/domctl.h 2008-09-15 15:10:39.000000000 +0200 +@@ -0,0 +1,2 @@ ++int xen_guest_address_size(int domid); ++int xen_guest_blkif_protocol(int domid); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-blktap-vma-close-fix b/src/patches/suse-2.6.27.31/patches.xen/xen-blktap-vma-close-fix new file mode 100644 index 000000000..cfc9c2d72 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-blktap-vma-close-fix @@ -0,0 +1,130 @@ +From: jbeulich@novell.com +Subject: fix c/s 863 +Patch-mainline: obsolete (superceded by c/s 867) + +get_user_pages() expects vma->vm_private_data of VM_FOREIGN vma-s to +point to an array of struct page *, hence blktap must not alter the +meaning of that field. + +Found-by: Isaku Yamahata + +--- sle11-2009-04-20.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:41:53.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/blktap/blktap.c 2009-04-29 09:36:57.000000000 +0200 +@@ -320,7 +320,7 @@ static pte_t blktap_clear_pte(struct vm_ + int offset, seg, usr_idx, pending_idx, mmap_idx; + unsigned long uvstart = vma->vm_start + (RING_PAGES << PAGE_SHIFT); + unsigned long kvaddr; +- struct tap_vma_priv *priv; ++ struct page **map; + struct page *pg; + struct grant_handle_pair *khandle; + struct gnttab_unmap_grant_ref unmap[2]; +@@ -335,12 +335,12 @@ static pte_t blktap_clear_pte(struct vm_ + is_fullmm); + + info = vma->vm_file->private_data; +- priv = vma->vm_private_data; ++ map = vma->vm_private_data; + + /* TODO Should these be changed to if statements? */ + BUG_ON(!info); + BUG_ON(!info->idx_map); +- BUG_ON(!priv); ++ BUG_ON(!map); + + offset = (int) ((uvaddr - uvstart) >> PAGE_SHIFT); + usr_idx = OFFSET_TO_USR_IDX(offset); +@@ -352,7 +352,7 @@ static pte_t blktap_clear_pte(struct vm_ + kvaddr = idx_to_kaddr(mmap_idx, pending_idx, seg); + pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); + ClearPageReserved(pg); +- priv->map[offset + RING_PAGES] = NULL; ++ map[offset + RING_PAGES] = NULL; + + khandle = &pending_handle(mmap_idx, pending_idx, seg); + +@@ -395,9 +395,11 @@ static pte_t blktap_clear_pte(struct vm_ + + static void blktap_vma_close(struct vm_area_struct *vma) + { +- struct tap_vma_priv *priv = vma->vm_private_data; ++ if (vma->vm_private_data) { ++ struct tap_vma_priv *priv = container_of(vma->vm_private_data, ++ struct tap_vma_priv, ++ map); + +- if (priv) { + priv->info->vma = NULL; + kfree(priv); + } +@@ -708,7 +710,7 @@ static int blktap_mmap(struct file *filp + } + priv->info = info; + +- vma->vm_private_data = priv; ++ vma->vm_private_data = priv->map; + vma->vm_flags |= VM_FOREIGN; + vma->vm_flags |= VM_DONTCOPY; + +@@ -1189,7 +1191,7 @@ static int blktap_read_ufe_ring(tap_blki + for (j = 0; j < pending_req->nr_pages; j++) { + + unsigned long kvaddr, uvaddr; +- struct tap_vma_priv *priv = info->vma->vm_private_data; ++ struct page **map = info->vma->vm_private_data; + struct page *pg; + int offset; + +@@ -1200,7 +1202,7 @@ static int blktap_read_ufe_ring(tap_blki + ClearPageReserved(pg); + offset = (uvaddr - info->vma->vm_start) + >> PAGE_SHIFT; +- priv->map[offset] = NULL; ++ map[offset] = NULL; + } + fast_flush_area(pending_req, pending_idx, usr_idx, info->minor); + info->idx_map[usr_idx] = INVALID_REQ; +@@ -1366,7 +1368,7 @@ static void dispatch_rw_block_io(blkif_t + unsigned int nseg; + int ret, i, nr_sects = 0; + tap_blkif_t *info; +- struct tap_vma_priv *priv; ++ struct page **pgmap; + blkif_request_t *target; + int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx); + int usr_idx; +@@ -1432,7 +1434,6 @@ static void dispatch_rw_block_io(blkif_t + pending_req->status = BLKIF_RSP_OKAY; + pending_req->nr_pages = nseg; + op = 0; +- priv = info->vma->vm_private_data; + mm = info->vma->vm_mm; + if (!xen_feature(XENFEAT_auto_translated_physmap)) + down_write(&mm->mmap_sem); +@@ -1477,6 +1478,8 @@ static void dispatch_rw_block_io(blkif_t + ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op); + BUG_ON(ret); + ++ pgmap = info->vma->vm_private_data; ++ + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + up_write(&mm->mmap_sem); + +@@ -1516,7 +1519,7 @@ static void dispatch_rw_block_io(blkif_t + >> PAGE_SHIFT)); + offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; + pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); +- priv->map[offset] = pg; ++ pgmap[offset] = pg; + } + } else { + for (i = 0; i < nseg; i++) { +@@ -1543,7 +1546,7 @@ static void dispatch_rw_block_io(blkif_t + + offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT; + pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT); +- priv->map[offset] = pg; ++ pgmap[offset] = pg; + } + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-blktap-write-barriers b/src/patches/suse-2.6.27.31/patches.xen/xen-blktap-write-barriers new file mode 100644 index 000000000..ee72b5f0e --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-blktap-write-barriers @@ -0,0 +1,105 @@ +From: kwolf@suse.de +Subject: blktap: Write Barriers +Patch-mainline: obsolete + +--- sle11-2009-04-20.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:40:25.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/blktap/blktap.c 2009-04-20 11:41:45.000000000 +0200 +@@ -1321,6 +1321,9 @@ static int do_block_io_op(blkif_t *blkif + dispatch_rw_block_io(blkif, &req, pending_req); + break; + ++ case BLKIF_OP_WRITE_BARRIER: ++ /* TODO Some counter? */ ++ /* Fall through */ + case BLKIF_OP_WRITE: + blkif->st_wr_req++; + dispatch_rw_block_io(blkif, &req, pending_req); +@@ -1352,7 +1355,7 @@ static void dispatch_rw_block_io(blkif_t + pending_req_t *pending_req) + { + extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); +- int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ; ++ int op, operation; + struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2]; + unsigned int nseg; + int ret, i, nr_sects = 0; +@@ -1364,6 +1367,21 @@ static void dispatch_rw_block_io(blkif_t + uint16_t mmap_idx = pending_req->mem_idx; + struct mm_struct *mm; + ++ switch (req->operation) { ++ case BLKIF_OP_READ: ++ operation = READ; ++ break; ++ case BLKIF_OP_WRITE: ++ operation = WRITE; ++ break; ++ case BLKIF_OP_WRITE_BARRIER: ++ operation = WRITE_BARRIER; ++ break; ++ default: ++ operation = 0; /* make gcc happy */ ++ BUG(); ++ } ++ + if (blkif->dev_num < 0 || blkif->dev_num > MAX_TAP_DEV) + goto fail_response; + +@@ -1402,7 +1420,7 @@ static void dispatch_rw_block_io(blkif_t + + pending_req->blkif = blkif; + pending_req->id = req->id; +- pending_req->operation = operation; ++ pending_req->operation = req->operation; + pending_req->status = BLKIF_RSP_OKAY; + pending_req->nr_pages = nseg; + op = 0; +@@ -1420,7 +1438,7 @@ static void dispatch_rw_block_io(blkif_t + kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i); + + flags = GNTMAP_host_map; +- if (operation == WRITE) ++ if (operation != READ) + flags |= GNTMAP_readonly; + gnttab_set_map_op(&map[op], kvaddr, flags, + req->seg[i].gref, blkif->domid); +@@ -1437,7 +1455,7 @@ static void dispatch_rw_block_io(blkif_t + + flags = GNTMAP_host_map | GNTMAP_application_map + | GNTMAP_contains_pte; +- if (operation == WRITE) ++ if (operation != READ) + flags |= GNTMAP_readonly; + gnttab_set_map_op(&map[op], ptep, flags, + req->seg[i].gref, blkif->domid); +--- sle11-2009-04-20.orig/drivers/xen/blktap/xenbus.c 2008-09-15 15:10:39.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/blktap/xenbus.c 2008-11-10 12:14:32.000000000 +0100 +@@ -395,7 +395,28 @@ static void connect(struct backend_info + int err; + + struct xenbus_device *dev = be->dev; ++ struct xenbus_transaction xbt; + ++ /* Write feature-barrier to xenstore */ ++again: ++ err = xenbus_transaction_start(&xbt); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "starting transaction"); ++ return; ++ } ++ ++ err = xenbus_printf(xbt, dev->nodename, "feature-barrier", "1"); ++ if (err) { ++ xenbus_dev_fatal(dev, err, "writing feature-barrier"); ++ xenbus_transaction_end(xbt, 1); ++ return; ++ } ++ ++ err = xenbus_transaction_end(xbt, 0); ++ if (err == -EAGAIN) ++ goto again; ++ ++ /* Switch state */ + err = xenbus_switch_state(dev, XenbusStateConnected); + if (err) + xenbus_dev_fatal(dev, err, "switching to Connected state", diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-configurable-guest-devices b/src/patches/suse-2.6.27.31/patches.xen/xen-configurable-guest-devices new file mode 100644 index 000000000..c0256c9c7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-configurable-guest-devices @@ -0,0 +1,74 @@ +From: jbeulich@novell.com +Subject: allow number of guest devices to be configurable +Patch-mainline: obsolete + +... and derive NR_DYNIRQS from this (rather than having a hard-coded +value). +Similarly, allow the number of simultaneous transmits in netback to be +configurable. + +--- sle11-2009-03-04.orig/drivers/xen/Kconfig 2009-03-05 15:45:30.000000000 +0100 ++++ sle11-2009-03-04/drivers/xen/Kconfig 2008-12-05 16:57:43.000000000 +0100 +@@ -73,6 +73,15 @@ config XEN_NETDEV_BACKEND + network devices to other guests via a high-performance shared-memory + interface. + ++config XEN_NETDEV_TX_SHIFT ++ int "Maximum simultaneous transmit requests (as a power of 2)" ++ depends on XEN_NETDEV_BACKEND ++ range 5 16 ++ default 8 ++ help ++ The maximum number transmits the driver can hold pending, expressed ++ as the exponent of a power of 2. ++ + config XEN_NETDEV_PIPELINED_TRANSMITTER + bool "Pipelined transmitter (DANGEROUS)" + depends on XEN_NETDEV_BACKEND +@@ -255,6 +264,16 @@ config XEN_SYSFS + help + Xen hypervisor attributes will show up under /sys/hypervisor/. + ++config XEN_NR_GUEST_DEVICES ++ int "Number of guest devices" ++ range 0 4032 if 64BIT ++ range 0 960 ++ default 256 if XEN_BACKEND ++ default 16 ++ help ++ Specify the total number of virtual devices (i.e. both frontend ++ and backend) that you want the kernel to be able to service. ++ + choice + prompt "Xen version compatibility" + default XEN_COMPAT_030002_AND_LATER +--- sle11-2009-03-04.orig/drivers/xen/netback/netback.c 2009-03-05 15:45:30.000000000 +0100 ++++ sle11-2009-03-04/drivers/xen/netback/netback.c 2008-12-23 09:35:35.000000000 +0100 +@@ -71,7 +71,7 @@ static DECLARE_TASKLET(net_rx_tasklet, n + static struct timer_list net_timer; + static struct timer_list netbk_tx_pending_timer; + +-#define MAX_PENDING_REQS 256 ++#define MAX_PENDING_REQS (1U << CONFIG_XEN_NETDEV_TX_SHIFT) + + static struct sk_buff_head rx_queue; + +@@ -1212,6 +1212,7 @@ static void net_tx_action(unsigned long + net_tx_action_dealloc(); + + mop = tx_map_ops; ++ BUILD_BUG_ON(MAX_SKB_FRAGS >= MAX_PENDING_REQS); + while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) && + !list_empty(&net_schedule_list)) { + /* Get a netif from the list with work to do. */ +--- sle11-2009-03-04.orig/include/asm-x86/mach-xen/asm/irq_vectors.h 2009-03-05 15:45:30.000000000 +0100 ++++ sle11-2009-03-04/include/asm-x86/mach-xen/asm/irq_vectors.h 2009-03-05 15:45:49.000000000 +0100 +@@ -44,7 +44,7 @@ + #endif + + #define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS) +-#define NR_DYNIRQS 256 ++#define NR_DYNIRQS (64 + CONFIG_XEN_NR_GUEST_DEVICES) + + #define NR_IRQS (NR_PIRQS + NR_DYNIRQS) + #define NR_IRQ_VECTORS NR_IRQS diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-cpufreq-report b/src/patches/suse-2.6.27.31/patches.xen/xen-cpufreq-report new file mode 100644 index 000000000..184ee4a20 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-cpufreq-report @@ -0,0 +1,59 @@ +From: jbeulich@novell.com +Subject: make /proc/cpuinfo track CPU speed +Patch-mainline: obsolete + +--- sle11-2009-07-31.orig/arch/x86/kernel/acpi/processor_extcntl_xen.c 2009-07-31 14:52:14.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/kernel/acpi/processor_extcntl_xen.c 2009-07-31 15:14:03.000000000 +0200 +@@ -204,3 +204,14 @@ void arch_acpi_processor_init_extcntl(co + *ops = &xen_extcntl_ops; + } + EXPORT_SYMBOL(arch_acpi_processor_init_extcntl); ++ ++unsigned int cpufreq_quick_get(unsigned int cpu) ++{ ++ xen_platform_op_t op = { ++ .cmd = XENPF_get_cpu_freq, ++ .interface_version = XENPF_INTERFACE_VERSION, ++ .u.get_cpu_freq.vcpu = cpu ++ }; ++ ++ return HYPERVISOR_platform_op(&op) == 0 ? op.u.get_cpu_freq.freq : 0; ++} +--- sle11-2009-07-31.orig/include/linux/cpufreq.h 2009-07-31 14:49:20.000000000 +0200 ++++ sle11-2009-07-31/include/linux/cpufreq.h 2008-10-01 16:44:34.000000000 +0200 +@@ -282,7 +282,7 @@ int cpufreq_update_policy(unsigned int c + unsigned int cpufreq_get(unsigned int cpu); + + /* query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it */ +-#ifdef CONFIG_CPU_FREQ ++#if defined(CONFIG_CPU_FREQ) || defined(CONFIG_PROCESSOR_EXTERNAL_CONTROL) + unsigned int cpufreq_quick_get(unsigned int cpu); + #else + static inline unsigned int cpufreq_quick_get(unsigned int cpu) +--- sle11-2009-07-31.orig/include/xen/interface/platform.h 2009-07-31 14:49:20.000000000 +0200 ++++ sle11-2009-07-31/include/xen/interface/platform.h 2008-10-01 16:44:34.000000000 +0200 +@@ -312,6 +312,16 @@ struct xenpf_set_processor_pminfo { + typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t; + DEFINE_XEN_GUEST_HANDLE(xenpf_set_processor_pminfo_t); + ++#define XENPF_get_cpu_freq ('N' << 24) ++struct xenpf_get_cpu_freq { ++ /* IN variables */ ++ uint32_t vcpu; ++ /* OUT variables */ ++ uint32_t freq; /* in kHz */ ++}; ++typedef struct xenpf_get_cpu_freq xenpf_get_cpu_freq_t; ++DEFINE_XEN_GUEST_HANDLE(xenpf_get_cpu_freq_t); ++ + struct xen_platform_op { + uint32_t cmd; + uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ +@@ -327,6 +337,7 @@ struct xen_platform_op { + struct xenpf_change_freq change_freq; + struct xenpf_getidletime getidletime; + struct xenpf_set_processor_pminfo set_pminfo; ++ struct xenpf_get_cpu_freq get_cpu_freq; + uint8_t pad[128]; + } u; + }; diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-i386-panic-on-oops b/src/patches/suse-2.6.27.31/patches.xen/xen-i386-panic-on-oops new file mode 100644 index 000000000..a12ce4074 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-i386-panic-on-oops @@ -0,0 +1,25 @@ +From: jbeulich@novell.com +Subject: Parse oops=panic (match x86-64) +Patch-mainline: obsolete + +Index: head-2008-11-25/arch/x86/kernel/traps_32-xen.c +=================================================================== +--- head-2008-11-25.orig/arch/x86/kernel/traps_32-xen.c 2008-11-25 13:17:46.000000000 +0100 ++++ head-2008-11-25/arch/x86/kernel/traps_32-xen.c 2008-11-25 13:18:12.000000000 +0100 +@@ -1277,6 +1277,16 @@ void __cpuinit smp_trap_init(trap_info_t + } + } + ++static int __init oops_setup(char *s) ++{ ++ if (!s) ++ return -EINVAL; ++ if (!strcmp(s, "panic")) ++ panic_on_oops = 1; ++ return 0; ++} ++early_param("oops", oops_setup); ++ + static int __init kstack_setup(char *s) + { + kstack_depth_to_print = simple_strtoul(s, NULL, 0); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-ipi-per-cpu-irq b/src/patches/suse-2.6.27.31/patches.xen/xen-ipi-per-cpu-irq new file mode 100644 index 000000000..d950a1f0d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-ipi-per-cpu-irq @@ -0,0 +1,778 @@ +From: jbeulich@novell.com +Subject: fold IPIs onto a single IRQ each +Patch-mainline: obsolete + +--- sle11-2009-06-04.orig/arch/x86/kernel/genapic_xen_64.c 2009-06-04 10:46:34.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/genapic_xen_64.c 2009-06-04 10:47:21.000000000 +0200 +@@ -25,13 +25,13 @@ + #include + #include + +-DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); +- + static inline void __send_IPI_one(unsigned int cpu, int vector) + { +- int irq = per_cpu(ipi_to_irq, cpu)[vector]; +- BUG_ON(irq < 0); +- notify_remote_via_irq(irq); ++#ifdef CONFIG_SMP ++ notify_remote_via_ipi(vector, cpu); ++#else ++ BUG(); ++#endif + } + + static void xen_send_IPI_shortcut(unsigned int shortcut, +--- sle11-2009-06-04.orig/arch/x86/kernel/ipi-xen.c 2009-06-04 10:46:34.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/ipi-xen.c 2009-06-04 10:47:21.000000000 +0200 +@@ -48,15 +48,6 @@ static inline int __prepare_ICR2(unsigne + } + #else + #include +- +-DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); +- +-static inline void __send_IPI_one(unsigned int cpu, int vector) +-{ +- int irq = per_cpu(ipi_to_irq, cpu)[vector]; +- BUG_ON(irq < 0); +- notify_remote_via_irq(irq); +-} + #endif + + void __send_IPI_shortcut(unsigned int shortcut, int vector) +@@ -90,12 +81,12 @@ void __send_IPI_shortcut(unsigned int sh + + switch (shortcut) { + case APIC_DEST_SELF: +- __send_IPI_one(smp_processor_id(), vector); ++ notify_remote_via_ipi(vector, smp_processor_id()); + break; + case APIC_DEST_ALLBUT: + for_each_online_cpu(cpu) + if (cpu != smp_processor_id()) +- __send_IPI_one(cpu, vector); ++ notify_remote_via_ipi(vector, cpu); + break; + default: + printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut, +@@ -165,7 +156,7 @@ void send_IPI_mask_bitmask(const cpumask + WARN_ON(!cpus_subset(*cpumask, cpu_online_map)); + for_each_online_cpu(cpu) + if (cpu_isset(cpu, *cpumask)) +- __send_IPI_one(cpu, vector); ++ notify_remote_via_ipi(vector, cpu); + #endif + local_irq_restore(flags); + } +--- sle11-2009-06-04.orig/arch/x86/kernel/irq_32-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/irq_32-xen.c 2009-06-04 10:47:21.000000000 +0200 +@@ -404,6 +404,9 @@ void fixup_irqs(cpumask_t map) + if (irq == 2) + continue; + ++ if (irq_desc[irq].status & IRQ_PER_CPU) ++ continue; ++ + cpus_and(mask, irq_desc[irq].affinity, map); + if (any_online_cpu(mask) == NR_CPUS) { + /*printk("Breaking affinity for irq %i\n", irq);*/ +--- sle11-2009-06-04.orig/arch/x86/kernel/irq_64-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/irq_64-xen.c 2009-06-04 10:47:21.000000000 +0200 +@@ -245,6 +245,7 @@ void fixup_irqs(cpumask_t map) + spin_lock(&irq_desc[irq].lock); + + if (!irq_has_action(irq) || ++ (irq_desc[irq].status & IRQ_PER_CPU) || + cpus_equal(irq_desc[irq].affinity, map)) { + spin_unlock(&irq_desc[irq].lock); + continue; +--- sle11-2009-06-04.orig/drivers/xen/Kconfig 2009-06-04 10:47:17.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/Kconfig 2009-06-04 10:47:21.000000000 +0200 +@@ -4,6 +4,7 @@ + + config XEN + bool ++ select IRQ_PER_CPU if SMP + + if XEN + config XEN_INTERFACE_VERSION +@@ -292,6 +293,9 @@ config HAVE_IRQ_IGNORE_UNHANDLED + config GENERIC_HARDIRQS_NO__DO_IRQ + def_bool y + ++config IRQ_PER_CPU ++ bool ++ + config NO_IDLE_HZ + def_bool y + +--- sle11-2009-06-04.orig/drivers/xen/core/evtchn.c 2009-06-04 10:47:20.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/evtchn.c 2009-06-04 10:47:21.000000000 +0200 +@@ -58,6 +58,22 @@ static DEFINE_SPINLOCK(irq_mapping_updat + static int evtchn_to_irq[NR_EVENT_CHANNELS] = { + [0 ... NR_EVENT_CHANNELS-1] = -1 }; + ++/* IRQ <-> IPI mapping. */ ++#ifndef NR_IPIS ++#define NR_IPIS 1 ++#endif ++#if defined(CONFIG_SMP) && defined(CONFIG_X86) ++static int ipi_to_irq[NR_IPIS] __read_mostly = {[0 ... NR_IPIS-1] = -1}; ++static DEFINE_PER_CPU(int[NR_IPIS], ipi_to_evtchn); ++#else ++#define PER_CPU_IPI_IRQ ++#endif ++#if !defined(CONFIG_SMP) || !defined(PER_CPU_IPI_IRQ) ++#define BUG_IF_IPI(irq) BUG_ON(type_from_irq(irq) == IRQT_IPI) ++#else ++#define BUG_IF_IPI(irq) ((void)(irq)) ++#endif ++ + /* Packed IRQ information: binding type, sub-type index, and event channel. */ + static u32 irq_info[NR_IRQS]; + +@@ -98,10 +114,12 @@ static inline u32 mk_irq_info(u32 type, + * Accessors for packed IRQ information. + */ + ++#ifdef PER_CPU_IPI_IRQ + static inline unsigned int evtchn_from_irq(int irq) + { + return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1); + } ++#endif + + static inline unsigned int index_from_irq(int irq) + { +@@ -113,14 +131,28 @@ static inline unsigned int type_from_irq + return irq_info[irq] >> (32 - _IRQT_BITS); + } + ++#ifndef PER_CPU_IPI_IRQ ++static inline unsigned int evtchn_from_per_cpu_irq(unsigned int irq, unsigned int cpu) ++{ ++ BUG_ON(type_from_irq(irq) != IRQT_IPI); ++ return per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)]; ++} ++ ++static inline unsigned int evtchn_from_irq(unsigned int irq) ++{ ++ if (type_from_irq(irq) != IRQT_IPI) ++ return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1); ++ return evtchn_from_per_cpu_irq(irq, smp_processor_id()); ++} ++#endif ++ + /* IRQ <-> VIRQ mapping. */ + DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1}; + ++#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) + /* IRQ <-> IPI mapping. */ +-#ifndef NR_IPIS +-#define NR_IPIS 1 +-#endif + DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) = {[0 ... NR_IPIS-1] = -1}; ++#endif + + /* Reference counts for bindings to IRQs. */ + static int irq_bindcount[NR_IRQS]; +@@ -145,8 +177,14 @@ static void bind_evtchn_to_cpu(unsigned + + BUG_ON(!test_bit(chn, s->evtchn_mask)); + +- if (irq != -1) +- irq_desc[irq].affinity = cpumask_of_cpu(cpu); ++ if (irq != -1) { ++ struct irq_desc *desc = irq_desc + irq; ++ ++ if (!(desc->status & IRQ_PER_CPU)) ++ desc->affinity = cpumask_of_cpu(cpu); ++ else ++ cpu_set(cpu, desc->affinity); ++ } + + clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]); + set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]); +@@ -315,14 +353,29 @@ asmlinkage void evtchn_do_upcall(struct + irq_exit(); + } + +-static int find_unbound_irq(void) ++static struct irq_chip dynirq_chip; ++ ++static int find_unbound_irq(bool percpu) + { + static int warned; + int irq; + + for (irq = DYNIRQ_BASE; irq < (DYNIRQ_BASE + NR_DYNIRQS); irq++) +- if (irq_bindcount[irq] == 0) ++ if (irq_bindcount[irq] == 0) { ++ irq_flow_handler_t handle; ++ const char *name; ++ ++ if (!percpu) { ++ handle = handle_level_irq; ++ name = "level"; ++ } else { ++ handle = handle_percpu_irq; ++ name = "percpu"; ++ } ++ set_irq_chip_and_handler_name(irq, &dynirq_chip, ++ handle, name); + return irq; ++ } + + if (!warned) { + warned = 1; +@@ -340,7 +393,7 @@ static int bind_caller_port_to_irq(unsig + spin_lock(&irq_mapping_update_lock); + + if ((irq = evtchn_to_irq[caller_port]) == -1) { +- if ((irq = find_unbound_irq()) < 0) ++ if ((irq = find_unbound_irq(false)) < 0) + goto out; + + evtchn_to_irq[caller_port] = irq; +@@ -362,7 +415,7 @@ static int bind_local_port_to_irq(unsign + + BUG_ON(evtchn_to_irq[local_port] != -1); + +- if ((irq = find_unbound_irq()) < 0) { ++ if ((irq = find_unbound_irq(false)) < 0) { + struct evtchn_close close = { .port = local_port }; + if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) + BUG(); +@@ -415,7 +468,7 @@ static int bind_virq_to_irq(unsigned int + spin_lock(&irq_mapping_update_lock); + + if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { +- if ((irq = find_unbound_irq()) < 0) ++ if ((irq = find_unbound_irq(false)) < 0) + goto out; + + bind_virq.virq = virq; +@@ -440,6 +493,7 @@ static int bind_virq_to_irq(unsigned int + return irq; + } + ++#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) + static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) + { + struct evtchn_bind_ipi bind_ipi; +@@ -448,7 +502,7 @@ static int bind_ipi_to_irq(unsigned int + spin_lock(&irq_mapping_update_lock); + + if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { +- if ((irq = find_unbound_irq()) < 0) ++ if ((irq = find_unbound_irq(false)) < 0) + goto out; + + bind_ipi.vcpu = cpu; +@@ -471,6 +525,7 @@ static int bind_ipi_to_irq(unsigned int + spin_unlock(&irq_mapping_update_lock); + return irq; + } ++#endif + + static void unbind_from_irq(unsigned int irq) + { +@@ -478,6 +533,7 @@ static void unbind_from_irq(unsigned int + unsigned int cpu; + int evtchn = evtchn_from_irq(irq); + ++ BUG_IF_IPI(irq); + spin_lock(&irq_mapping_update_lock); + + if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { +@@ -491,10 +547,12 @@ static void unbind_from_irq(unsigned int + per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) + [index_from_irq(irq)] = -1; + break; ++#if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) + case IRQT_IPI: + per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn)) + [index_from_irq(irq)] = -1; + break; ++#endif + default: + break; + } +@@ -513,6 +571,46 @@ static void unbind_from_irq(unsigned int + spin_unlock(&irq_mapping_update_lock); + } + ++#if defined(CONFIG_SMP) && !defined(PER_CPU_IPI_IRQ) ++void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu) ++{ ++ struct evtchn_close close; ++ int evtchn = evtchn_from_per_cpu_irq(irq, cpu); ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ if (VALID_EVTCHN(evtchn)) { ++ struct irq_desc *desc = irq_desc + irq; ++ ++ mask_evtchn(evtchn); ++ ++ BUG_ON(irq_bindcount[irq] <= 1); ++ irq_bindcount[irq]--; ++ cpu_clear(cpu, desc->affinity); ++ ++ close.port = evtchn; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close)) ++ BUG(); ++ ++ switch (type_from_irq(irq)) { ++ case IRQT_IPI: ++ per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)] = 0; ++ break; ++ default: ++ BUG(); ++ break; ++ } ++ ++ /* Closed ports are implicitly re-bound to VCPU0. */ ++ bind_evtchn_to_cpu(evtchn, 0); ++ ++ evtchn_to_irq[evtchn] = -1; ++ } ++ ++ spin_unlock(&irq_mapping_update_lock); ++} ++#endif /* CONFIG_SMP && !PER_CPU_IPI_IRQ */ ++ + int bind_caller_port_to_irqhandler( + unsigned int caller_port, + irq_handler_t handler, +@@ -607,6 +705,8 @@ int bind_virq_to_irqhandler( + } + EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler); + ++#ifdef CONFIG_SMP ++#ifdef PER_CPU_IPI_IRQ + int bind_ipi_to_irqhandler( + unsigned int ipi, + unsigned int cpu, +@@ -629,7 +729,71 @@ int bind_ipi_to_irqhandler( + + return irq; + } +-EXPORT_SYMBOL_GPL(bind_ipi_to_irqhandler); ++#else ++int __cpuinit bind_ipi_to_irqaction( ++ unsigned int ipi, ++ unsigned int cpu, ++ struct irqaction *action) ++{ ++ struct evtchn_bind_ipi bind_ipi; ++ int evtchn, irq, retval = 0; ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ if (VALID_EVTCHN(per_cpu(ipi_to_evtchn, cpu)[ipi])) { ++ spin_unlock(&irq_mapping_update_lock); ++ return -EBUSY; ++ } ++ ++ if ((irq = ipi_to_irq[ipi]) == -1) { ++ if ((irq = find_unbound_irq(true)) < 0) { ++ spin_unlock(&irq_mapping_update_lock); ++ return irq; ++ } ++ ++ /* Extra reference so count will never drop to zero. */ ++ irq_bindcount[irq]++; ++ ++ ipi_to_irq[ipi] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, 0); ++ retval = 1; ++ } ++ ++ bind_ipi.vcpu = cpu; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, ++ &bind_ipi) != 0) ++ BUG(); ++ ++ evtchn = bind_ipi.port; ++ evtchn_to_irq[evtchn] = irq; ++ per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn; ++ ++ bind_evtchn_to_cpu(evtchn, cpu); ++ ++ irq_bindcount[irq]++; ++ ++ spin_unlock(&irq_mapping_update_lock); ++ ++ if (retval == 0) { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ unmask_evtchn(evtchn); ++ local_irq_restore(flags); ++ } else { ++ action->flags |= IRQF_PERCPU; ++ retval = setup_irq(irq, action); ++ if (retval) { ++ unbind_from_per_cpu_irq(irq, cpu); ++ BUG_ON(retval > 0); ++ irq = retval; ++ } ++ } ++ ++ return irq; ++} ++#endif /* PER_CPU_IPI_IRQ */ ++#endif /* CONFIG_SMP */ + + void unbind_from_irqhandler(unsigned int irq, void *dev_id) + { +@@ -655,6 +819,7 @@ static void rebind_irq_to_cpu(unsigned i + { + int evtchn = evtchn_from_irq(irq); + ++ BUG_IF_IPI(irq); + if (VALID_EVTCHN(evtchn)) + rebind_evtchn_to_cpu(evtchn, tcpu); + } +@@ -739,6 +904,7 @@ static struct irq_chip dynirq_chip = { + .unmask = unmask_dynirq, + .mask_ack = ack_dynirq, + .ack = ack_dynirq, ++ .eoi = end_dynirq, + .end = end_dynirq, + #ifdef CONFIG_SMP + .set_affinity = set_affinity_irq, +@@ -918,10 +1084,21 @@ int irq_ignore_unhandled(unsigned int ir + return !!(irq_status.flags & XENIRQSTAT_shared); + } + ++#if defined(CONFIG_SMP) && !defined(PER_CPU_IPI_IRQ) ++void notify_remote_via_ipi(unsigned int ipi, unsigned int cpu) ++{ ++ int evtchn = evtchn_from_per_cpu_irq(ipi_to_irq[ipi], cpu); ++ ++ if (VALID_EVTCHN(evtchn)) ++ notify_remote_via_evtchn(evtchn); ++} ++#endif ++ + void notify_remote_via_irq(int irq) + { + int evtchn = evtchn_from_irq(irq); + ++ BUG_IF_IPI(irq); + if (VALID_EVTCHN(evtchn)) + notify_remote_via_evtchn(evtchn); + } +@@ -929,6 +1106,7 @@ EXPORT_SYMBOL_GPL(notify_remote_via_irq) + + int irq_to_evtchn_port(int irq) + { ++ BUG_IF_IPI(irq); + return evtchn_from_irq(irq); + } + EXPORT_SYMBOL_GPL(irq_to_evtchn_port); +@@ -1044,11 +1222,17 @@ static void restore_cpu_virqs(unsigned i + + static void restore_cpu_ipis(unsigned int cpu) + { ++#ifdef CONFIG_SMP + struct evtchn_bind_ipi bind_ipi; + int ipi, irq, evtchn; + + for (ipi = 0; ipi < NR_IPIS; ipi++) { ++#ifdef PER_CPU_IPI_IRQ + if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) ++#else ++ if ((irq = ipi_to_irq[ipi]) == -1 ++ || !VALID_EVTCHN(per_cpu(ipi_to_evtchn, cpu)[ipi])) ++#endif + continue; + + BUG_ON(irq_info[irq] != mk_irq_info(IRQT_IPI, ipi, 0)); +@@ -1062,13 +1246,18 @@ static void restore_cpu_ipis(unsigned in + + /* Record the new mapping. */ + evtchn_to_irq[evtchn] = irq; ++#ifdef PER_CPU_IPI_IRQ + irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); ++#else ++ per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn; ++#endif + bind_evtchn_to_cpu(evtchn, cpu); + + /* Ready for use. */ + if (!(irq_desc[irq].status & IRQ_DISABLED)) + unmask_evtchn(evtchn); + } ++#endif + } + + static int evtchn_resume(struct sys_device *dev) +@@ -1239,8 +1428,6 @@ void __init xen_init_IRQ(void) + irq_bindcount[i] = 0; + + irq_desc[i].status |= IRQ_NOPROBE; +- set_irq_chip_and_handler_name(i, &dynirq_chip, +- handle_level_irq, "level"); + } + + /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */ +--- sle11-2009-06-04.orig/drivers/xen/core/smpboot.c 2009-06-04 10:47:07.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/smpboot.c 2009-06-04 10:47:21.000000000 +0200 +@@ -49,12 +49,9 @@ cpumask_t cpu_initialized_map; + DEFINE_PER_CPU(struct cpuinfo_x86, cpu_info); + EXPORT_PER_CPU_SYMBOL(cpu_info); + +-static DEFINE_PER_CPU(int, resched_irq); +-static DEFINE_PER_CPU(int, callfunc_irq); +-static DEFINE_PER_CPU(int, call1func_irq); +-static char resched_name[NR_CPUS][15]; +-static char callfunc_name[NR_CPUS][15]; +-static char call1func_name[NR_CPUS][15]; ++static int __read_mostly resched_irq = -1; ++static int __read_mostly callfunc_irq = -1; ++static int __read_mostly call1func_irq = -1; + + #ifdef CONFIG_X86_LOCAL_APIC + #define set_cpu_to_apicid(cpu, apicid) (per_cpu(x86_cpu_to_apicid, cpu) = (apicid)) +@@ -109,47 +106,54 @@ remove_siblinginfo(unsigned int cpu) + + static int __cpuinit xen_smp_intr_init(unsigned int cpu) + { ++ static struct irqaction resched_action = { ++ .handler = smp_reschedule_interrupt, ++ .flags = IRQF_DISABLED, ++ .name = "resched" ++ }, callfunc_action = { ++ .handler = smp_call_function_interrupt, ++ .flags = IRQF_DISABLED, ++ .name = "callfunc" ++ }, call1func_action = { ++ .handler = smp_call_function_single_interrupt, ++ .flags = IRQF_DISABLED, ++ .name = "call1func" ++ }; + int rc; + +- per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = +- per_cpu(call1func_irq, cpu) = -1; +- +- sprintf(resched_name[cpu], "resched%u", cpu); +- rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, +- cpu, +- smp_reschedule_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- resched_name[cpu], +- NULL); ++ rc = bind_ipi_to_irqaction(RESCHEDULE_VECTOR, ++ cpu, ++ &resched_action); + if (rc < 0) +- goto fail; +- per_cpu(resched_irq, cpu) = rc; +- +- sprintf(callfunc_name[cpu], "callfunc%u", cpu); +- rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR, +- cpu, +- smp_call_function_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- callfunc_name[cpu], +- NULL); ++ return rc; ++ if (resched_irq < 0) ++ resched_irq = rc; ++ else ++ BUG_ON(resched_irq != rc); ++ ++ rc = bind_ipi_to_irqaction(CALL_FUNCTION_VECTOR, ++ cpu, ++ &callfunc_action); + if (rc < 0) +- goto fail; +- per_cpu(callfunc_irq, cpu) = rc; +- +- sprintf(call1func_name[cpu], "call1func%u", cpu); +- rc = bind_ipi_to_irqhandler(CALL_FUNC_SINGLE_VECTOR, +- cpu, +- smp_call_function_single_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- call1func_name[cpu], +- NULL); ++ goto unbind_resched; ++ if (callfunc_irq < 0) ++ callfunc_irq = rc; ++ else ++ BUG_ON(callfunc_irq != rc); ++ ++ rc = bind_ipi_to_irqaction(CALL_FUNC_SINGLE_VECTOR, ++ cpu, ++ &call1func_action); + if (rc < 0) +- goto fail; +- per_cpu(call1func_irq, cpu) = rc; ++ goto unbind_call; ++ if (call1func_irq < 0) ++ call1func_irq = rc; ++ else ++ BUG_ON(call1func_irq != rc); + + rc = xen_spinlock_init(cpu); + if (rc < 0) +- goto fail; ++ goto unbind_call1; + + if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0)) + goto fail; +@@ -157,13 +161,13 @@ static int __cpuinit xen_smp_intr_init(u + return 0; + + fail: +- if (per_cpu(resched_irq, cpu) >= 0) +- unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); +- if (per_cpu(callfunc_irq, cpu) >= 0) +- unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); +- if (per_cpu(call1func_irq, cpu) >= 0) +- unbind_from_irqhandler(per_cpu(call1func_irq, cpu), NULL); + xen_spinlock_cleanup(cpu); ++ unbind_call1: ++ unbind_from_per_cpu_irq(call1func_irq, cpu); ++ unbind_call: ++ unbind_from_per_cpu_irq(callfunc_irq, cpu); ++ unbind_resched: ++ unbind_from_per_cpu_irq(resched_irq, cpu); + return rc; + } + +@@ -173,9 +177,9 @@ static void __cpuinit xen_smp_intr_exit( + if (cpu != 0) + local_teardown_timer(cpu); + +- unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); +- unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); +- unbind_from_irqhandler(per_cpu(call1func_irq, cpu), NULL); ++ unbind_from_per_cpu_irq(resched_irq, cpu); ++ unbind_from_per_cpu_irq(callfunc_irq, cpu); ++ unbind_from_per_cpu_irq(call1func_irq, cpu); + xen_spinlock_cleanup(cpu); + } + #endif +--- sle11-2009-06-04.orig/drivers/xen/core/spinlock.c 2009-06-04 10:36:24.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/spinlock.c 2009-06-04 10:47:21.000000000 +0200 +@@ -16,8 +16,7 @@ + + extern irqreturn_t smp_reschedule_interrupt(int, void *); + +-static DEFINE_PER_CPU(int, spinlock_irq) = -1; +-static char spinlock_name[NR_CPUS][15]; ++static int __read_mostly spinlock_irq = -1; + + struct spinning { + raw_spinlock_t *lock; +@@ -34,34 +33,36 @@ static DEFINE_PER_CPU(raw_rwlock_t, spin + + int __cpuinit xen_spinlock_init(unsigned int cpu) + { ++ static struct irqaction spinlock_action = { ++ .handler = smp_reschedule_interrupt, ++ .flags = IRQF_DISABLED, ++ .name = "spinlock" ++ }; + int rc; + +- sprintf(spinlock_name[cpu], "spinlock%u", cpu); +- rc = bind_ipi_to_irqhandler(SPIN_UNLOCK_VECTOR, +- cpu, +- smp_reschedule_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- spinlock_name[cpu], +- NULL); ++ rc = bind_ipi_to_irqaction(SPIN_UNLOCK_VECTOR, ++ cpu, ++ &spinlock_action); + if (rc < 0) + return rc; + +- disable_irq(rc); /* make sure it's never delivered */ +- per_cpu(spinlock_irq, cpu) = rc; ++ if (spinlock_irq < 0) { ++ disable_irq(rc); /* make sure it's never delivered */ ++ spinlock_irq = rc; ++ } else ++ BUG_ON(spinlock_irq != rc); + + return 0; + } + + void __cpuinit xen_spinlock_cleanup(unsigned int cpu) + { +- if (per_cpu(spinlock_irq, cpu) >= 0) +- unbind_from_irqhandler(per_cpu(spinlock_irq, cpu), NULL); +- per_cpu(spinlock_irq, cpu) = -1; ++ unbind_from_per_cpu_irq(spinlock_irq, cpu); + } + + int xen_spin_wait(raw_spinlock_t *lock, unsigned int token) + { +- int rc = 0, irq = __get_cpu_var(spinlock_irq); ++ int rc = 0, irq = spinlock_irq; + raw_rwlock_t *rm_lock; + unsigned long flags; + struct spinning spinning; +@@ -155,7 +156,7 @@ void xen_spin_kick(raw_spinlock_t *lock, + raw_local_irq_restore(flags); + + if (unlikely(spinning)) { +- notify_remote_via_irq(per_cpu(spinlock_irq, cpu)); ++ notify_remote_via_ipi(SPIN_UNLOCK_VECTOR, cpu); + return; + } + } +--- sle11-2009-06-04.orig/include/xen/evtchn.h 2009-06-04 10:47:20.000000000 +0200 ++++ sle11-2009-06-04/include/xen/evtchn.h 2009-06-04 10:47:21.000000000 +0200 +@@ -78,6 +78,8 @@ int bind_virq_to_irqhandler( + unsigned long irqflags, + const char *devname, + void *dev_id); ++#if defined(CONFIG_SMP) && !defined(MODULE) ++#ifndef CONFIG_X86 + int bind_ipi_to_irqhandler( + unsigned int ipi, + unsigned int cpu, +@@ -85,6 +87,13 @@ int bind_ipi_to_irqhandler( + unsigned long irqflags, + const char *devname, + void *dev_id); ++#else ++int bind_ipi_to_irqaction( ++ unsigned int ipi, ++ unsigned int cpu, ++ struct irqaction *action); ++#endif ++#endif + + /* + * Common unbind function for all event sources. Takes IRQ to unbind from. +@@ -93,6 +102,11 @@ int bind_ipi_to_irqhandler( + */ + void unbind_from_irqhandler(unsigned int irq, void *dev_id); + ++#if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86) ++/* Specialized unbind function for per-CPU IRQs. */ ++void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu); ++#endif ++ + #ifndef CONFIG_XEN + void irq_resume(void); + #endif +@@ -184,4 +198,8 @@ int clear_pirq_hw_action(int pirq); + #define PIRQ_END 5 + #define PIRQ_ACK 6 + ++#if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86) ++void notify_remote_via_ipi(unsigned int ipi, unsigned int cpu); ++#endif ++ + #endif /* __ASM_EVTCHN_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-kconfig-compat-3.2.0 b/src/patches/suse-2.6.27.31/patches.xen/xen-kconfig-compat-3.2.0 new file mode 100644 index 000000000..96b719566 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-kconfig-compat-3.2.0 @@ -0,0 +1,26 @@ +From: jbeulich@novell.com +Subject: add 3.2.0-compatibility configure option +Patch-mainline: obsolete + +Index: head-2008-10-24/drivers/xen/Kconfig +=================================================================== +--- head-2008-10-24.orig/drivers/xen/Kconfig 2008-10-24 10:46:02.000000000 +0200 ++++ head-2008-10-24/drivers/xen/Kconfig 2008-10-24 10:52:17.000000000 +0200 +@@ -267,6 +267,9 @@ choice + config XEN_COMPAT_030100_AND_LATER + bool "3.1.0 and later" + ++ config XEN_COMPAT_030200_AND_LATER ++ bool "3.2.0 and later" ++ + config XEN_COMPAT_LATEST_ONLY + bool "no compatibility code" + +@@ -275,6 +278,7 @@ endchoice + config XEN_COMPAT + hex + default 0xffffff if XEN_COMPAT_LATEST_ONLY ++ default 0x030200 if XEN_COMPAT_030200_AND_LATER + default 0x030100 if XEN_COMPAT_030100_AND_LATER + default 0x030004 if XEN_COMPAT_030004_AND_LATER + default 0x030002 if XEN_COMPAT_030002_AND_LATER diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-modular-blktap b/src/patches/suse-2.6.27.31/patches.xen/xen-modular-blktap new file mode 100644 index 000000000..c7f5f8734 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-modular-blktap @@ -0,0 +1,22 @@ +From: ccoffing@novell.com +Subject: Retain backwards-compatible module name with CONFIG_XEN_BLKDEV_TAP=m +Patch-mainline: obsolete + +Index: head-2008-08-18/drivers/xen/blktap/Makefile +=================================================================== +--- head-2008-08-18.orig/drivers/xen/blktap/Makefile 2008-08-21 09:43:30.000000000 +0200 ++++ head-2008-08-18/drivers/xen/blktap/Makefile 2007-04-27 15:30:48.000000000 +0200 +@@ -1,5 +1,5 @@ + LINUXINCLUDE += -I../xen/include/public/io + +-obj-$(CONFIG_XEN_BLKDEV_TAP) := xenblktap.o ++obj-$(CONFIG_XEN_BLKDEV_TAP) := blktap.o + +-xenblktap-y := xenbus.o interface.o blktap.o ++blktap-y := xenbus.o interface.o blocktap.o +Index: head-2008-08-18/drivers/xen/blktap/blocktap.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ head-2008-08-18/drivers/xen/blktap/blocktap.c 2007-04-27 15:30:48.000000000 +0200 +@@ -0,0 +1 @@ ++#include "blktap.c" diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-netback-notify-multi b/src/patches/suse-2.6.27.31/patches.xen/xen-netback-notify-multi new file mode 100644 index 000000000..b17370552 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-netback-notify-multi @@ -0,0 +1,85 @@ +From: jbeulich@novell.com +Subject: netback: use multicall for send multiple notifications +Patch-mainline: obsolete + +This also does a small fairness improvement since now notifications +get sent in the order requests came in rather than in the inverse one. + +--- sle11-2009-03-24.orig/drivers/xen/core/evtchn.c 2009-03-31 13:36:56.000000000 +0200 ++++ sle11-2009-03-24/drivers/xen/core/evtchn.c 2009-03-31 13:37:08.000000000 +0200 +@@ -1294,6 +1294,21 @@ void notify_remote_via_irq(int irq) + } + EXPORT_SYMBOL_GPL(notify_remote_via_irq); + ++int multi_notify_remote_via_irq(multicall_entry_t *mcl, int irq) ++{ ++ int evtchn = evtchn_from_irq(irq); ++ ++ BUG_ON(type_from_irq(irq) == IRQT_VIRQ); ++ BUG_IF_IPI(irq); ++ ++ if (!VALID_EVTCHN(evtchn)) ++ return -EINVAL; ++ ++ multi_notify_remote_via_evtchn(mcl, evtchn); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(multi_notify_remote_via_irq); ++ + int irq_to_evtchn_port(int irq) + { + BUG_IF_VIRQ_PER_CPU(irq); +--- sle11-2009-03-24.orig/drivers/xen/netback/netback.c 2008-12-23 09:35:42.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/netback/netback.c 2008-12-23 09:35:48.000000000 +0100 +@@ -748,10 +748,20 @@ static void net_rx_action(unsigned long + npo.meta_cons += nr_frags + 1; + } + +- while (notify_nr != 0) { +- irq = notify_list[--notify_nr]; ++ if (notify_nr == 1) { ++ irq = *notify_list; + __clear_bit(irq, rx_notify); + notify_remote_via_irq(irq + DYNIRQ_BASE); ++ } else { ++ for (count = ret = 0; ret < notify_nr; ++ret) { ++ irq = notify_list[ret]; ++ __clear_bit(irq, rx_notify); ++ if (!multi_notify_remote_via_irq(rx_mcl + count, ++ irq + DYNIRQ_BASE)) ++ ++count; ++ } ++ if (HYPERVISOR_multicall(rx_mcl, count)) ++ BUG(); + } + + /* More work to do? */ +--- sle11-2009-03-24.orig/include/xen/evtchn.h 2009-03-04 11:38:25.000000000 +0100 ++++ sle11-2009-03-24/include/xen/evtchn.h 2008-12-01 12:10:27.000000000 +0100 +@@ -179,6 +179,18 @@ static inline void notify_remote_via_evt + VOID(HYPERVISOR_event_channel_op(EVTCHNOP_send, &send)); + } + ++static inline void ++multi_notify_remote_via_evtchn(multicall_entry_t *mcl, int port) ++{ ++ struct evtchn_send *send = (void *)(mcl->args + 2); ++ ++ BUILD_BUG_ON(sizeof(*send) > sizeof(mcl->args) - 2 * sizeof(*mcl->args)); ++ send->port = port; ++ mcl->op = __HYPERVISOR_event_channel_op; ++ mcl->args[0] = EVTCHNOP_send; ++ mcl->args[1] = (unsigned long)send; ++} ++ + /* Clear an irq's pending state, in preparation for polling on it. */ + void xen_clear_irq_pending(int irq); + +@@ -197,6 +209,7 @@ void xen_poll_irq(int irq); + * by bind_*_to_irqhandler(). + */ + void notify_remote_via_irq(int irq); ++int multi_notify_remote_via_irq(multicall_entry_t *, int irq); + int irq_to_evtchn_port(int irq); + + #define PIRQ_SET_MAPPING 0x0 diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-netback-nr-irqs b/src/patches/suse-2.6.27.31/patches.xen/xen-netback-nr-irqs new file mode 100644 index 000000000..ee25bdbb5 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-netback-nr-irqs @@ -0,0 +1,61 @@ +From: jbeulich@novell.com +Subject: netback: reduce overhead of IRQ recording +Patch-mainline: obsolete + +Since both NR_PIRQS and NR_DYNIRQS are no longer hardcoded, the +(memory) overhead of tracking which ones to send notifications to can +be pretty unbounded. Also, store the dynirq rather than the raw irq +to push up the limit where the type of notify_list needs to become +'int' rather than 'u16'. + +--- head-2009-02-02.orig/drivers/xen/netback/interface.c 2009-02-02 09:40:43.000000000 +0100 ++++ head-2009-02-02/drivers/xen/netback/interface.c 2009-02-02 10:20:51.000000000 +0100 +@@ -280,6 +280,7 @@ int netif_map(netif_t *netif, unsigned l + netif->dev->name, netif); + if (err < 0) + goto err_hypervisor; ++ BUG_ON(err < DYNIRQ_BASE || err >= DYNIRQ_BASE + NR_DYNIRQS); + netif->irq = err; + disable_irq(netif->irq); + +--- head-2009-02-02.orig/drivers/xen/netback/netback.c 2008-12-23 09:35:35.000000000 +0100 ++++ head-2009-02-02/drivers/xen/netback/netback.c 2008-12-23 09:35:42.000000000 +0100 +@@ -580,8 +580,12 @@ static void net_rx_action(unsigned long + static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; + static gnttab_transfer_t grant_trans_op[NET_RX_RING_SIZE]; + static gnttab_copy_t grant_copy_op[NET_RX_RING_SIZE]; +- static unsigned char rx_notify[NR_IRQS]; ++ static DECLARE_BITMAP(rx_notify, NR_DYNIRQS); ++#if NR_DYNIRQS <= 0x10000 + static u16 notify_list[NET_RX_RING_SIZE]; ++#else ++ static int notify_list[NET_RX_RING_SIZE]; ++#endif + static struct netbk_rx_meta meta[NET_RX_RING_SIZE]; + + struct netrx_pending_operations npo = { +@@ -730,11 +734,9 @@ static void net_rx_action(unsigned long + nr_frags); + + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret); +- irq = netif->irq; +- if (ret && !rx_notify[irq]) { +- rx_notify[irq] = 1; ++ irq = netif->irq - DYNIRQ_BASE; ++ if (ret && !__test_and_set_bit(irq, rx_notify)) + notify_list[notify_nr++] = irq; +- } + + if (netif_queue_stopped(netif->dev) && + netif_schedulable(netif) && +@@ -748,8 +750,8 @@ static void net_rx_action(unsigned long + + while (notify_nr != 0) { + irq = notify_list[--notify_nr]; +- rx_notify[irq] = 0; +- notify_remote_via_irq(irq); ++ __clear_bit(irq, rx_notify); ++ notify_remote_via_irq(irq + DYNIRQ_BASE); + } + + /* More work to do? */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-op-packet b/src/patches/suse-2.6.27.31/patches.xen/xen-op-packet new file mode 100644 index 000000000..3e5fcb3d2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-op-packet @@ -0,0 +1,140 @@ +From: plc@novell.com +Subject: add support for new operation type BLKIF_OP_PACKET +Patch-mainline: obsolete +References: fate#300964 + +--- sle11-2009-06-04.orig/drivers/xen/blkback/blkback.c 2009-06-04 10:20:39.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkback/blkback.c 2009-06-04 10:46:54.000000000 +0200 +@@ -192,13 +192,15 @@ static void fast_flush_area(pending_req_ + + static void print_stats(blkif_t *blkif) + { +- printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d | br %4d\n", ++ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d | br %4d | pk %4d\n", + current->comm, blkif->st_oo_req, +- blkif->st_rd_req, blkif->st_wr_req, blkif->st_br_req); ++ blkif->st_rd_req, blkif->st_wr_req, blkif->st_br_req, ++ blkif->st_pk_req); + blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000); + blkif->st_rd_req = 0; + blkif->st_wr_req = 0; + blkif->st_oo_req = 0; ++ blkif->st_pk_req = 0; + } + + int blkif_schedule(void *arg) +@@ -358,6 +360,13 @@ static int do_block_io_op(blkif_t *blkif + blkif->st_wr_req++; + dispatch_rw_block_io(blkif, &req, pending_req); + break; ++ case BLKIF_OP_PACKET: ++ DPRINTK("error: block operation BLKIF_OP_PACKET not implemented\n"); ++ blkif->st_pk_req++; ++ make_response(blkif, req.id, req.operation, ++ BLKIF_RSP_ERROR); ++ free_req(pending_req); ++ break; + default: + /* A good sign something is wrong: sleep for a while to + * avoid excessive CPU consumption by a bad guest. */ +--- sle11-2009-06-04.orig/drivers/xen/blkback/common.h 2009-06-04 10:46:52.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkback/common.h 2009-06-04 10:46:54.000000000 +0200 +@@ -87,6 +87,7 @@ typedef struct blkif_st { + int st_wr_req; + int st_oo_req; + int st_br_req; ++ int st_pk_req; + int st_rd_sect; + int st_wr_sect; + +--- sle11-2009-06-04.orig/drivers/xen/blkfront/blkfront.c 2009-06-04 10:21:09.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blkfront/blkfront.c 2009-06-04 10:46:54.000000000 +0200 +@@ -626,6 +626,8 @@ static int blkif_queue_request(struct re + BLKIF_OP_WRITE : BLKIF_OP_READ; + if (blk_barrier_rq(req)) + ring_req->operation = BLKIF_OP_WRITE_BARRIER; ++ if (blk_pc_request(req)) ++ ring_req->operation = BLKIF_OP_PACKET; + + ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); + BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); +@@ -677,7 +679,7 @@ void do_blkif_request(struct request_que + + while ((req = elv_next_request(rq)) != NULL) { + info = req->rq_disk->private_data; +- if (!blk_fs_request(req)) { ++ if (!blk_fs_request(req) && !blk_pc_request(req)) { + end_request(req, 0); + continue; + } +@@ -754,6 +756,7 @@ static irqreturn_t blkif_int(int irq, vo + /* fall through */ + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: ++ case BLKIF_OP_PACKET: + if (unlikely(bret->status != BLKIF_RSP_OKAY)) + DPRINTK("Bad return from blkdev data " + "request: %x\n", bret->status); +--- sle11-2009-06-04.orig/drivers/xen/blktap/blktap.c 2009-06-04 10:46:52.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blktap/blktap.c 2009-06-04 10:46:54.000000000 +0200 +@@ -1087,13 +1087,14 @@ static void fast_flush_area(pending_req_ + + static void print_stats(blkif_t *blkif) + { +- printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d\n", ++ printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d | pk %4d\n", + current->comm, blkif->st_oo_req, +- blkif->st_rd_req, blkif->st_wr_req); ++ blkif->st_rd_req, blkif->st_wr_req, blkif->st_pk_req); + blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000); + blkif->st_rd_req = 0; + blkif->st_wr_req = 0; + blkif->st_oo_req = 0; ++ blkif->st_pk_req = 0; + } + + int tap_blkif_schedule(void *arg) +@@ -1329,6 +1330,11 @@ static int do_block_io_op(blkif_t *blkif + dispatch_rw_block_io(blkif, &req, pending_req); + break; + ++ case BLKIF_OP_PACKET: ++ blkif->st_pk_req++; ++ dispatch_rw_block_io(blkif, &req, pending_req); ++ break; ++ + default: + /* A good sign something is wrong: sleep for a while to + * avoid excessive CPU consumption by a bad guest. */ +@@ -1368,6 +1374,8 @@ static void dispatch_rw_block_io(blkif_t + struct mm_struct *mm; + + switch (req->operation) { ++ case BLKIF_OP_PACKET: ++ /* Fall through */ + case BLKIF_OP_READ: + operation = READ; + break; +--- sle11-2009-06-04.orig/drivers/xen/blktap/common.h 2009-06-04 10:20:18.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/blktap/common.h 2009-06-04 10:46:54.000000000 +0200 +@@ -75,6 +75,7 @@ typedef struct blkif_st { + int st_rd_req; + int st_wr_req; + int st_oo_req; ++ int st_pk_req; + int st_rd_sect; + int st_wr_sect; + +--- sle11-2009-06-04.orig/include/xen/interface/io/blkif.h 2009-06-04 10:18:38.000000000 +0200 ++++ sle11-2009-06-04/include/xen/interface/io/blkif.h 2009-06-04 10:46:54.000000000 +0200 +@@ -76,6 +76,10 @@ + * "feature-flush-cache" node! + */ + #define BLKIF_OP_FLUSH_DISKCACHE 3 ++/* ++ * Device specific command packet contained within the request ++ */ ++#define BLKIF_OP_PACKET 4 + + /* + * Maximum scatter/gather segments per request. diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-rt2860-build b/src/patches/suse-2.6.27.31/patches.xen/xen-rt2860-build new file mode 100644 index 000000000..414a91c34 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-rt2860-build @@ -0,0 +1,16 @@ +From: jbeulich@novell.com +Subject: fix issue with Windows-style types used in rt28x0 +Patch-mainline: obsolete + +--- sle11-2009-03-04.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-12 16:42:09.000000000 +0100 ++++ sle11-2009-03-04/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-12 16:43:54.000000000 +0100 +@@ -348,4 +348,9 @@ MULTI_grant_table_op(multicall_entry_t * + + #endif + ++#ifdef LINUX ++/* drivers/staging/rt28?0/ use Windows-style types, including VOID */ ++#undef VOID ++#endif ++ + #endif /* __HYPERVISOR_H__ */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-scsifront-block-timeout-update b/src/patches/suse-2.6.27.31/patches.xen/xen-scsifront-block-timeout-update new file mode 100644 index 000000000..577b8413c --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-scsifront-block-timeout-update @@ -0,0 +1,31 @@ +From: Hannes Reinecke +Subject: Update XEN scsifront driver to request timeouts +Patch-mainline: obsolete + +Update XEN scsifront driver to the block request handling +patches. + +Signed-off-by: Hannes Reinecke + +Index: head-2008-09-15/drivers/xen/scsifront/scsifront.c +=================================================================== +--- head-2008-09-15.orig/drivers/xen/scsifront/scsifront.c 2008-09-15 15:22:09.000000000 +0200 ++++ head-2008-09-15/drivers/xen/scsifront/scsifront.c 2008-09-15 15:22:12.000000000 +0200 +@@ -348,7 +348,7 @@ static int scsifront_queuecommand(struct + memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE); + + ring_req->sc_data_direction = (uint8_t)sc->sc_data_direction; +- ring_req->timeout_per_command = (sc->timeout_per_command / HZ); ++ ring_req->timeout_per_command = (sc->request->timeout / HZ); + + info->shadow[rqid].req_scsi_cmnd = (unsigned long)sc; + info->shadow[rqid].sc_data_direction = sc->sc_data_direction; +@@ -418,7 +418,7 @@ static int scsifront_dev_reset_handler(s + memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE); + + ring_req->sc_data_direction = (uint8_t)sc->sc_data_direction; +- ring_req->timeout_per_command = (sc->timeout_per_command / HZ); ++ ring_req->timeout_per_command = (sc->request->timeout / HZ); + ring_req->nr_segments = 0; + + scsifront_do_request(info); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-sections b/src/patches/suse-2.6.27.31/patches.xen/xen-sections new file mode 100644 index 000000000..3d90bb854 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-sections @@ -0,0 +1,160 @@ +From: jbeulich@novell.com +Subject: fix placement of some routines/data +Patch-mainline: obsolete + +--- sle11-2009-05-14.orig/arch/x86/kernel/e820-xen.c 2009-05-06 10:29:07.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/e820-xen.c 2009-02-17 14:01:20.000000000 +0100 +@@ -42,7 +42,7 @@ + * user can e.g. boot the original kernel with mem=1G while still booting the + * next kernel with full memory. + */ +-struct e820map e820; ++struct e820map __initdata e820; + #ifndef CONFIG_XEN + struct e820map e820_saved; + #else +--- sle11-2009-05-14.orig/arch/x86/kernel/process_32-xen.c 2008-10-01 16:20:58.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/process_32-xen.c 2008-12-01 12:07:15.000000000 +0100 +@@ -99,7 +99,7 @@ static void cpu_exit_clear(void) + } + #endif + +-static inline void play_dead(void) ++static void __ref play_dead(void) + { + idle_task_exit(); + local_irq_disable(); +--- sle11-2009-05-14.orig/arch/x86/kernel/process_64-xen.c 2008-10-01 16:20:58.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/process_64-xen.c 2008-12-01 12:07:15.000000000 +0100 +@@ -95,7 +95,7 @@ void exit_idle(void) + } + + #ifdef CONFIG_HOTPLUG_CPU +-static inline void play_dead(void) ++static void __ref play_dead(void) + { + idle_task_exit(); + #ifndef CONFIG_XEN +--- sle11-2009-05-14.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:13:50.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/time_32-xen.c 2009-03-24 10:22:14.000000000 +0100 +@@ -702,7 +702,7 @@ int xen_update_persistent_clock(void) + /* Dynamically-mapped IRQ. */ + DEFINE_PER_CPU(int, timer_irq); + +-static void setup_cpu0_timer_irq(void) ++static void __init setup_cpu0_timer_irq(void) + { + per_cpu(timer_irq, 0) = + bind_virq_to_irqhandler( +@@ -913,7 +913,7 @@ int __cpuinit local_setup_timer(unsigned + return 0; + } + +-void __cpuexit local_teardown_timer(unsigned int cpu) ++void __cpuinit local_teardown_timer(unsigned int cpu) + { + BUG_ON(cpu == 0); + unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL); +--- sle11-2009-05-14.orig/arch/x86/mm/ioremap-xen.c 2009-01-16 10:45:51.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/ioremap-xen.c 2009-01-07 10:55:24.000000000 +0100 +@@ -201,7 +201,8 @@ int touch_pte_range(struct mm_struct *mm + + EXPORT_SYMBOL(touch_pte_range); + +-int page_is_ram(unsigned long pagenr) ++#ifdef CONFIG_X86_32 ++int __init page_is_ram(unsigned long pagenr) + { + resource_size_t addr, end; + int i; +@@ -239,6 +240,7 @@ int page_is_ram(unsigned long pagenr) + } + return 0; + } ++#endif + + /* + * Fix up the linear direct mapping of the kernel to avoid cache attribute +--- sle11-2009-05-14.orig/drivers/xen/core/cpu_hotplug.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/core/cpu_hotplug.c 2008-12-01 12:07:15.000000000 +0100 +@@ -24,7 +24,7 @@ static int local_cpu_hotplug_request(voi + return (current->mm != NULL); + } + +-static void vcpu_hotplug(unsigned int cpu) ++static void __cpuinit vcpu_hotplug(unsigned int cpu) + { + int err; + char dir[32], state[32]; +@@ -51,7 +51,7 @@ static void vcpu_hotplug(unsigned int cp + } + } + +-static void handle_vcpu_hotplug_event( ++static void __cpuinit handle_vcpu_hotplug_event( + struct xenbus_watch *watch, const char **vec, unsigned int len) + { + unsigned int cpu; +@@ -80,12 +80,12 @@ static int smpboot_cpu_notify(struct not + return NOTIFY_OK; + } + +-static int setup_cpu_watcher(struct notifier_block *notifier, +- unsigned long event, void *data) ++static int __cpuinit setup_cpu_watcher(struct notifier_block *notifier, ++ unsigned long event, void *data) + { + unsigned int i; + +- static struct xenbus_watch cpu_watch = { ++ static struct xenbus_watch __cpuinitdata cpu_watch = { + .node = "cpu", + .callback = handle_vcpu_hotplug_event, + .flags = XBWF_new_thread }; +@@ -105,7 +105,7 @@ static int __init setup_vcpu_hotplug_eve + { + static struct notifier_block hotplug_cpu = { + .notifier_call = smpboot_cpu_notify }; +- static struct notifier_block xsn_cpu = { ++ static struct notifier_block __cpuinitdata xsn_cpu = { + .notifier_call = setup_cpu_watcher }; + + if (!is_running_on_xen()) +@@ -119,7 +119,7 @@ static int __init setup_vcpu_hotplug_eve + + arch_initcall(setup_vcpu_hotplug_event); + +-int smp_suspend(void) ++int __ref smp_suspend(void) + { + unsigned int cpu; + int err; +@@ -140,7 +140,7 @@ int smp_suspend(void) + return 0; + } + +-void smp_resume(void) ++void __ref smp_resume(void) + { + unsigned int cpu; + +--- sle11-2009-05-14.orig/drivers/xen/core/smpboot.c 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/core/smpboot.c 2008-12-01 12:07:15.000000000 +0100 +@@ -168,7 +168,7 @@ static int __cpuinit xen_smp_intr_init(u + } + + #ifdef CONFIG_HOTPLUG_CPU +-static void __cpuexit xen_smp_intr_exit(unsigned int cpu) ++static void __cpuinit xen_smp_intr_exit(unsigned int cpu) + { + if (cpu != 0) + local_teardown_timer(cpu); +@@ -387,7 +387,7 @@ int __cpuexit __cpu_disable(void) + return 0; + } + +-void __cpuexit __cpu_die(unsigned int cpu) ++void __cpuinit __cpu_die(unsigned int cpu) + { + while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) { + current->state = TASK_UNINTERRUPTIBLE; diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-swiotlb-heuristics b/src/patches/suse-2.6.27.31/patches.xen/xen-swiotlb-heuristics new file mode 100644 index 000000000..8f71d28a7 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-swiotlb-heuristics @@ -0,0 +1,32 @@ +From: jbeulich@novell.com +Subject: adjust Xen's swiotlb default size setting +Patch-mainline: obsolete + +--- sle11-2009-02-05.orig/lib/swiotlb-xen.c 2009-02-05 11:18:17.000000000 +0100 ++++ sle11-2009-02-05/lib/swiotlb-xen.c 2009-02-05 11:18:23.000000000 +0100 +@@ -224,8 +224,8 @@ swiotlb_init_with_default_size(size_t de + void __init + swiotlb_init(void) + { +- long ram_end; +- size_t defsz = 64 * (1 << 20); /* 64MB default size */ ++ unsigned long ram_end; ++ size_t defsz = 64 << 20; /* 64MB default size */ + + if (swiotlb_force == 1) { + swiotlb = 1; +@@ -234,8 +234,12 @@ swiotlb_init(void) + is_initial_xendomain()) { + /* Domain 0 always has a swiotlb. */ + ram_end = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); +- if (ram_end <= 0x7ffff) +- defsz = 2 * (1 << 20); /* 2MB on <2GB on systems. */ ++ if (ram_end <= 0x1ffff) ++ defsz = 2 << 20; /* 2MB on <512MB systems. */ ++ else if (ram_end <= 0x3ffff) ++ defsz = 4 << 20; /* 4MB on <1GB systems. */ ++ else if (ram_end <= 0x7ffff) ++ defsz = 8 << 20; /* 8MB on <2GB systems. */ + swiotlb = 1; + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-sysdev-suspend b/src/patches/suse-2.6.27.31/patches.xen/xen-sysdev-suspend new file mode 100644 index 000000000..00d5b74db --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-sysdev-suspend @@ -0,0 +1,374 @@ +From: jbeulich@novell.com +Subject: use base kernel suspend/resume infrastructure +Patch-mainline: obsolete + +... rather than calling just a few functions explicitly. + +--- sle11-2009-03-24.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:22:14.000000000 +0100 ++++ sle11-2009-03-24/arch/x86/kernel/time_32-xen.c 2009-03-24 10:22:24.000000000 +0100 +@@ -88,6 +88,10 @@ static DEFINE_PER_CPU(struct vcpu_runsta + /* Must be signed, as it's compared with s64 quantities which can be -ve. */ + #define NS_PER_TICK (1000000000LL/HZ) + ++static struct vcpu_set_periodic_timer xen_set_periodic_tick = { ++ .period_ns = NS_PER_TICK ++}; ++ + static void __clock_was_set(struct work_struct *unused) + { + clock_was_set(); +@@ -597,6 +601,25 @@ void mark_tsc_unstable(char *reason) + } + EXPORT_SYMBOL_GPL(mark_tsc_unstable); + ++static void init_missing_ticks_accounting(unsigned int cpu) ++{ ++ struct vcpu_register_runstate_memory_area area; ++ struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ int rc; ++ ++ memset(runstate, 0, sizeof(*runstate)); ++ ++ area.addr.v = runstate; ++ rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); ++ WARN_ON(rc && rc != -ENOSYS); ++ ++ per_cpu(processed_blocked_time, cpu) = ++ runstate->time[RUNSTATE_blocked]; ++ per_cpu(processed_stolen_time, cpu) = ++ runstate->time[RUNSTATE_runnable] + ++ runstate->time[RUNSTATE_offline]; ++} ++ + static cycle_t cs_last; + + static cycle_t xen_clocksource_read(void) +@@ -633,11 +656,32 @@ static cycle_t xen_clocksource_read(void + #endif + } + ++/* No locking required. Interrupts are disabled on all CPUs. */ + static void xen_clocksource_resume(void) + { +- extern void time_resume(void); ++ unsigned int cpu; ++ ++ init_cpu_khz(); ++ ++ for_each_online_cpu(cpu) { ++ switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, ++ &xen_set_periodic_tick)) { ++ case 0: ++#if CONFIG_XEN_COMPAT <= 0x030004 ++ case -ENOSYS: ++#endif ++ break; ++ default: ++ BUG(); ++ } ++ get_time_values_from_xen(cpu); ++ per_cpu(processed_system_time, cpu) = ++ per_cpu(shadow_time, 0).system_timestamp; ++ init_missing_ticks_accounting(cpu); ++ } ++ ++ processed_system_time = per_cpu(shadow_time, 0).system_timestamp; + +- time_resume(); + cs_last = local_clock(); + } + +@@ -652,25 +696,6 @@ static struct clocksource clocksource_xe + .resume = xen_clocksource_resume, + }; + +-static void init_missing_ticks_accounting(unsigned int cpu) +-{ +- struct vcpu_register_runstate_memory_area area; +- struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); +- int rc; +- +- memset(runstate, 0, sizeof(*runstate)); +- +- area.addr.v = runstate; +- rc = HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area, cpu, &area); +- WARN_ON(rc && rc != -ENOSYS); +- +- per_cpu(processed_blocked_time, cpu) = +- runstate->time[RUNSTATE_blocked]; +- per_cpu(processed_stolen_time, cpu) = +- runstate->time[RUNSTATE_runnable] + +- runstate->time[RUNSTATE_offline]; +-} +- + unsigned long xen_read_persistent_clock(void) + { + const shared_info_t *s = HYPERVISOR_shared_info; +@@ -715,10 +740,6 @@ static void __init setup_cpu0_timer_irq( + BUG_ON(per_cpu(timer_irq, 0) < 0); + } + +-static struct vcpu_set_periodic_timer xen_set_periodic_tick = { +- .period_ns = NS_PER_TICK +-}; +- + void __init time_init(void) + { + init_cpu_khz(); +@@ -842,35 +863,6 @@ void xen_halt(void) + } + EXPORT_SYMBOL(xen_halt); + +-/* No locking required. Interrupts are disabled on all CPUs. */ +-void time_resume(void) +-{ +- unsigned int cpu; +- +- init_cpu_khz(); +- +- for_each_online_cpu(cpu) { +- switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu, +- &xen_set_periodic_tick)) { +- case 0: +-#if CONFIG_XEN_COMPAT <= 0x030004 +- case -ENOSYS: +-#endif +- break; +- default: +- BUG(); +- } +- get_time_values_from_xen(cpu); +- per_cpu(processed_system_time, cpu) = +- per_cpu(shadow_time, 0).system_timestamp; +- init_missing_ticks_accounting(cpu); +- } +- +- processed_system_time = per_cpu(shadow_time, 0).system_timestamp; +- +- update_wallclock(); +-} +- + #ifdef CONFIG_SMP + static char timer_name[NR_CPUS][15]; + +--- sle11-2009-03-24.orig/drivers/xen/core/evtchn.c 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/core/evtchn.c 2009-01-14 14:57:55.000000000 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1070,9 +1071,20 @@ static void restore_cpu_ipis(unsigned in + } + } + +-void irq_resume(void) ++static int evtchn_resume(struct sys_device *dev) + { + unsigned int cpu, irq, evtchn; ++ struct evtchn_status status; ++ ++ /* Avoid doing anything in the 'suspend cancelled' case. */ ++ status.dom = DOMID_SELF; ++ status.port = evtchn_from_irq(__get_cpu_var(virq_to_irq)[VIRQ_TIMER]); ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_status, &status)) ++ BUG(); ++ if (status.status == EVTCHNSTAT_virq ++ && status.vcpu == smp_processor_id() ++ && status.u.virq == VIRQ_TIMER) ++ return 0; + + init_evtchn_cpu_bindings(); + +@@ -1103,7 +1115,32 @@ void irq_resume(void) + restore_cpu_ipis(cpu); + } + ++ return 0; ++} ++ ++static struct sysdev_class evtchn_sysclass = { ++ .name = "evtchn", ++ .resume = evtchn_resume, ++}; ++ ++static struct sys_device device_evtchn = { ++ .id = 0, ++ .cls = &evtchn_sysclass, ++}; ++ ++static int __init evtchn_register(void) ++{ ++ int err; ++ ++ if (is_initial_xendomain()) ++ return 0; ++ ++ err = sysdev_class_register(&evtchn_sysclass); ++ if (!err) ++ err = sysdev_register(&device_evtchn); ++ return err; + } ++core_initcall(evtchn_register); + #endif + + #if defined(CONFIG_X86_IO_APIC) +--- sle11-2009-03-24.orig/drivers/xen/core/gnttab.c 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/core/gnttab.c 2008-12-15 11:32:52.000000000 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -704,23 +705,37 @@ EXPORT_SYMBOL(gnttab_post_map_adjust); + + #endif /* __HAVE_ARCH_PTE_SPECIAL */ + +-int gnttab_resume(void) ++static int gnttab_resume(struct sys_device *dev) + { + if (max_nr_grant_frames() < nr_grant_frames) + return -ENOSYS; + return gnttab_map(0, nr_grant_frames - 1); + } ++#define gnttab_resume() gnttab_resume(NULL) + + #ifdef CONFIG_PM_SLEEP +-int gnttab_suspend(void) +-{ + #ifdef CONFIG_X86 ++static int gnttab_suspend(struct sys_device *dev, pm_message_t state) ++{ + apply_to_page_range(&init_mm, (unsigned long)shared, + PAGE_SIZE * nr_grant_frames, + unmap_pte_fn, NULL); +-#endif + return 0; + } ++#else ++#define gnttab_suspend NULL ++#endif ++ ++static struct sysdev_class gnttab_sysclass = { ++ .name = "gnttab", ++ .resume = gnttab_resume, ++ .suspend = gnttab_suspend, ++}; ++ ++static struct sys_device device_gnttab = { ++ .id = 0, ++ .cls = &gnttab_sysclass, ++}; + #endif + + #else /* !CONFIG_XEN */ +@@ -800,6 +815,17 @@ int __devinit gnttab_init(void) + if (!is_running_on_xen()) + return -ENODEV; + ++#if defined(CONFIG_XEN) && defined(CONFIG_PM_SLEEP) ++ if (!is_initial_xendomain()) { ++ int err = sysdev_class_register(&gnttab_sysclass); ++ ++ if (!err) ++ err = sysdev_register(&device_gnttab); ++ if (err) ++ return err; ++ } ++#endif ++ + nr_grant_frames = 1; + boot_max_nr_grant_frames = __max_nr_grant_frames(); + +--- sle11-2009-03-24.orig/drivers/xen/core/machine_reboot.c 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-03-24/drivers/xen/core/machine_reboot.c 2009-02-17 12:23:48.000000000 +0100 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include "../../base/base.h" + + #if defined(__i386__) || defined(__x86_64__) + +@@ -141,7 +142,6 @@ static int take_machine_down(void *_susp + { + struct suspend *suspend = _suspend; + int suspend_cancelled, err; +- extern void time_resume(void); + + if (suspend->fast_suspend) { + BUG_ON(!irqs_disabled()); +@@ -167,20 +167,23 @@ static int take_machine_down(void *_susp + } + + mm_pin_all(); +- gnttab_suspend(); +- pre_suspend(); +- +- /* +- * This hypercall returns 1 if suspend was cancelled or the domain was +- * merely checkpointed, and 0 if it is resuming in a new domain. +- */ +- suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); ++ suspend_cancelled = sysdev_suspend(PMSG_FREEZE); ++ if (!suspend_cancelled) { ++ pre_suspend(); + ++ /* ++ * This hypercall returns 1 if suspend was cancelled or the domain was ++ * merely checkpointed, and 0 if it is resuming in a new domain. ++ */ ++ suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); ++ } else ++ BUG_ON(suspend_cancelled > 0); + suspend->resume_notifier(suspend_cancelled); +- post_suspend(suspend_cancelled); +- gnttab_resume(); ++ if (suspend_cancelled >= 0) { ++ post_suspend(suspend_cancelled); ++ sysdev_resume(); ++ } + if (!suspend_cancelled) { +- irq_resume(); + #ifdef __x86_64__ + /* + * Older versions of Xen do not save/restore the user %cr3. +@@ -192,7 +195,6 @@ static int take_machine_down(void *_susp + current->active_mm->pgd))); + #endif + } +- time_resume(); + + if (!suspend->fast_suspend) + local_irq_enable(); +--- sle11-2009-03-24.orig/include/xen/evtchn.h 2009-03-16 16:33:40.000000000 +0100 ++++ sle11-2009-03-24/include/xen/evtchn.h 2008-12-15 11:32:52.000000000 +0100 +@@ -93,7 +93,9 @@ int bind_ipi_to_irqhandler( + */ + void unbind_from_irqhandler(unsigned int irq, void *dev_id); + ++#ifndef CONFIG_XEN + void irq_resume(void); ++#endif + + /* Entry point for notifications into Linux subsystems. */ + asmlinkage void evtchn_do_upcall(struct pt_regs *regs); +--- sle11-2009-03-24.orig/include/xen/gnttab.h 2009-03-24 10:00:14.000000000 +0100 ++++ sle11-2009-03-24/include/xen/gnttab.h 2008-12-15 11:32:52.000000000 +0100 +@@ -110,8 +110,9 @@ static inline void __gnttab_dma_unmap_pa + + void gnttab_reset_grant_page(struct page *page); + +-int gnttab_suspend(void); ++#ifndef CONFIG_XEN + int gnttab_resume(void); ++#endif + + void *arch_gnttab_alloc_shared(unsigned long *frames); + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-virq-per-cpu-irq b/src/patches/suse-2.6.27.31/patches.xen/xen-virq-per-cpu-irq new file mode 100644 index 000000000..93aec46ea --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-virq-per-cpu-irq @@ -0,0 +1,636 @@ +From: jbeulich@novell.com +Subject: fold per-CPU VIRQs onto a single IRQ each +Patch-mainline: obsolete + +--- sle11-2009-06-04.orig/arch/x86/kernel/time_32-xen.c 2009-06-04 10:47:20.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/time_32-xen.c 2009-06-04 10:47:28.000000000 +0200 +@@ -725,19 +725,17 @@ int xen_update_persistent_clock(void) + } + + /* Dynamically-mapped IRQ. */ +-DEFINE_PER_CPU(int, timer_irq); ++static int __read_mostly timer_irq = -1; ++static struct irqaction timer_action = { ++ .handler = timer_interrupt, ++ .flags = IRQF_DISABLED, ++ .name = "timer" ++}; + + static void __init setup_cpu0_timer_irq(void) + { +- per_cpu(timer_irq, 0) = +- bind_virq_to_irqhandler( +- VIRQ_TIMER, +- 0, +- timer_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- "timer0", +- NULL); +- BUG_ON(per_cpu(timer_irq, 0) < 0); ++ timer_irq = bind_virq_to_irqaction(VIRQ_TIMER, 0, &timer_action); ++ BUG_ON(timer_irq < 0); + } + + void __init time_init(void) +@@ -864,8 +862,6 @@ void xen_halt(void) + EXPORT_SYMBOL(xen_halt); + + #ifdef CONFIG_SMP +-static char timer_name[NR_CPUS][15]; +- + int __cpuinit local_setup_timer(unsigned int cpu) + { + int seq, irq; +@@ -891,16 +887,10 @@ int __cpuinit local_setup_timer(unsigned + init_missing_ticks_accounting(cpu); + } while (read_seqretry(&xtime_lock, seq)); + +- sprintf(timer_name[cpu], "timer%u", cpu); +- irq = bind_virq_to_irqhandler(VIRQ_TIMER, +- cpu, +- timer_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- timer_name[cpu], +- NULL); ++ irq = bind_virq_to_irqaction(VIRQ_TIMER, cpu, &timer_action); + if (irq < 0) + return irq; +- per_cpu(timer_irq, cpu) = irq; ++ BUG_ON(timer_irq != irq); + + return 0; + } +@@ -908,7 +898,7 @@ int __cpuinit local_setup_timer(unsigned + void __cpuinit local_teardown_timer(unsigned int cpu) + { + BUG_ON(cpu == 0); +- unbind_from_irqhandler(per_cpu(timer_irq, cpu), NULL); ++ unbind_from_per_cpu_irq(timer_irq, cpu, &timer_action); + } + #endif + +--- sle11-2009-06-04.orig/drivers/xen/core/evtchn.c 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/evtchn.c 2009-06-04 10:47:28.000000000 +0200 +@@ -58,6 +58,23 @@ static DEFINE_SPINLOCK(irq_mapping_updat + static int evtchn_to_irq[NR_EVENT_CHANNELS] = { + [0 ... NR_EVENT_CHANNELS-1] = -1 }; + ++#if defined(CONFIG_SMP) && defined(CONFIG_X86) ++static struct per_cpu_irqaction { ++ struct irqaction action; /* must be first */ ++ struct per_cpu_irqaction *next; ++ cpumask_t cpus; ++} *virq_actions[NR_VIRQS]; ++/* IRQ <-> VIRQ mapping. */ ++static DECLARE_BITMAP(virq_per_cpu, NR_VIRQS) __read_mostly; ++static DEFINE_PER_CPU(int[NR_VIRQS], virq_to_evtchn); ++#define BUG_IF_VIRQ_PER_CPU(irq) \ ++ BUG_ON(type_from_irq(irq) == IRQT_VIRQ \ ++ && test_bit(index_from_irq(irq), virq_per_cpu)) ++#else ++#define BUG_IF_VIRQ_PER_CPU(irq) ((void)(irq)) ++#define PER_CPU_VIRQ_IRQ ++#endif ++ + /* IRQ <-> IPI mapping. */ + #ifndef NR_IPIS + #define NR_IPIS 1 +@@ -114,13 +131,6 @@ static inline u32 mk_irq_info(u32 type, + * Accessors for packed IRQ information. + */ + +-#ifdef PER_CPU_IPI_IRQ +-static inline unsigned int evtchn_from_irq(int irq) +-{ +- return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1); +-} +-#endif +- + static inline unsigned int index_from_irq(int irq) + { + return (irq_info[irq] >> _EVTCHN_BITS) & ((1U << _INDEX_BITS) - 1); +@@ -131,20 +141,35 @@ static inline unsigned int type_from_irq + return irq_info[irq] >> (32 - _IRQT_BITS); + } + +-#ifndef PER_CPU_IPI_IRQ + static inline unsigned int evtchn_from_per_cpu_irq(unsigned int irq, unsigned int cpu) + { +- BUG_ON(type_from_irq(irq) != IRQT_IPI); +- return per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)]; ++ switch (type_from_irq(irq)) { ++#ifndef PER_CPU_VIRQ_IRQ ++ case IRQT_VIRQ: ++ return per_cpu(virq_to_evtchn, cpu)[index_from_irq(irq)]; ++#endif ++#ifndef PER_CPU_IPI_IRQ ++ case IRQT_IPI: ++ return per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)]; ++#endif ++ } ++ BUG(); ++ return 0; + } + + static inline unsigned int evtchn_from_irq(unsigned int irq) + { +- if (type_from_irq(irq) != IRQT_IPI) +- return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1); +- return evtchn_from_per_cpu_irq(irq, smp_processor_id()); +-} ++ switch (type_from_irq(irq)) { ++#ifndef PER_CPU_VIRQ_IRQ ++ case IRQT_VIRQ: ++#endif ++#ifndef PER_CPU_IPI_IRQ ++ case IRQT_IPI: + #endif ++ return evtchn_from_per_cpu_irq(irq, smp_processor_id()); ++ } ++ return irq_info[irq] & ((1U << _EVTCHN_BITS) - 1); ++} + + /* IRQ <-> VIRQ mapping. */ + DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1}; +@@ -479,6 +504,14 @@ static int bind_virq_to_irq(unsigned int + evtchn = bind_virq.port; + + evtchn_to_irq[evtchn] = irq; ++#ifndef PER_CPU_VIRQ_IRQ ++ { ++ unsigned int cpu; ++ ++ for_each_possible_cpu(cpu) ++ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn; ++ } ++#endif + irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); + + per_cpu(virq_to_irq, cpu)[virq] = irq; +@@ -533,7 +566,9 @@ static void unbind_from_irq(unsigned int + unsigned int cpu; + int evtchn = evtchn_from_irq(irq); + ++ BUG_IF_VIRQ_PER_CPU(irq); + BUG_IF_IPI(irq); ++ + spin_lock(&irq_mapping_update_lock); + + if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) { +@@ -546,6 +581,11 @@ static void unbind_from_irq(unsigned int + case IRQT_VIRQ: + per_cpu(virq_to_irq, cpu_from_evtchn(evtchn)) + [index_from_irq(irq)] = -1; ++#ifndef PER_CPU_VIRQ_IRQ ++ for_each_possible_cpu(cpu) ++ per_cpu(virq_to_evtchn, cpu) ++ [index_from_irq(irq)] = 0; ++#endif + break; + #if defined(CONFIG_SMP) && defined(PER_CPU_IPI_IRQ) + case IRQT_IPI: +@@ -571,11 +611,13 @@ static void unbind_from_irq(unsigned int + spin_unlock(&irq_mapping_update_lock); + } + +-#if defined(CONFIG_SMP) && !defined(PER_CPU_IPI_IRQ) +-void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu) ++#if defined(CONFIG_SMP) && (!defined(PER_CPU_IPI_IRQ) || !defined(PER_CPU_VIRQ_IRQ)) ++void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu, ++ struct irqaction *action) + { + struct evtchn_close close; + int evtchn = evtchn_from_per_cpu_irq(irq, cpu); ++ struct irqaction *free_action = NULL; + + spin_lock(&irq_mapping_update_lock); + +@@ -586,6 +628,32 @@ void unbind_from_per_cpu_irq(unsigned in + + BUG_ON(irq_bindcount[irq] <= 1); + irq_bindcount[irq]--; ++ ++#ifndef PER_CPU_VIRQ_IRQ ++ if (type_from_irq(irq) == IRQT_VIRQ) { ++ unsigned int virq = index_from_irq(irq); ++ struct per_cpu_irqaction *cur, *prev = NULL; ++ ++ cur = virq_actions[virq]; ++ while (cur) { ++ if (cur->action.dev_id == action) { ++ cpu_clear(cpu, cur->cpus); ++ if (cpus_empty(cur->cpus)) { ++ if (prev) ++ prev->next = cur->next; ++ else ++ virq_actions[virq] = cur->next; ++ free_action = action; ++ } ++ } else if (cpu_isset(cpu, cur->cpus)) ++ evtchn = 0; ++ cur = (prev = cur)->next; ++ } ++ if (!VALID_EVTCHN(evtchn)) ++ goto done; ++ } ++#endif ++ + cpu_clear(cpu, desc->affinity); + + close.port = evtchn; +@@ -593,9 +661,16 @@ void unbind_from_per_cpu_irq(unsigned in + BUG(); + + switch (type_from_irq(irq)) { ++#ifndef PER_CPU_VIRQ_IRQ ++ case IRQT_VIRQ: ++ per_cpu(virq_to_evtchn, cpu)[index_from_irq(irq)] = 0; ++ break; ++#endif ++#ifndef PER_CPU_IPI_IRQ + case IRQT_IPI: + per_cpu(ipi_to_evtchn, cpu)[index_from_irq(irq)] = 0; + break; ++#endif + default: + BUG(); + break; +@@ -607,9 +682,16 @@ void unbind_from_per_cpu_irq(unsigned in + evtchn_to_irq[evtchn] = -1; + } + ++#ifndef PER_CPU_VIRQ_IRQ ++done: ++#endif + spin_unlock(&irq_mapping_update_lock); ++ ++ if (free_action) ++ free_irq(irq, free_action); + } +-#endif /* CONFIG_SMP && !PER_CPU_IPI_IRQ */ ++EXPORT_SYMBOL_GPL(unbind_from_per_cpu_irq); ++#endif /* CONFIG_SMP && (!PER_CPU_IPI_IRQ || !PER_CPU_VIRQ_IRQ) */ + + int bind_caller_port_to_irqhandler( + unsigned int caller_port, +@@ -691,6 +773,8 @@ int bind_virq_to_irqhandler( + { + int irq, retval; + ++ BUG_IF_VIRQ_PER_CPU(virq); ++ + irq = bind_virq_to_irq(virq, cpu); + if (irq < 0) + return irq; +@@ -706,6 +790,108 @@ int bind_virq_to_irqhandler( + EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler); + + #ifdef CONFIG_SMP ++#ifndef PER_CPU_VIRQ_IRQ ++int bind_virq_to_irqaction( ++ unsigned int virq, ++ unsigned int cpu, ++ struct irqaction *action) ++{ ++ struct evtchn_bind_virq bind_virq; ++ int evtchn, irq, retval = 0; ++ struct per_cpu_irqaction *cur = NULL, *new; ++ ++ BUG_ON(!test_bit(virq, virq_per_cpu)); ++ ++ if (action->dev_id) ++ return -EINVAL; ++ ++ new = kzalloc(sizeof(*new), GFP_ATOMIC); ++ if (new) { ++ new->action = *action; ++ new->action.dev_id = action; ++ } ++ ++ spin_lock(&irq_mapping_update_lock); ++ ++ for (cur = virq_actions[virq]; cur; cur = cur->next) ++ if (cur->action.dev_id == action) ++ break; ++ if (!cur) { ++ if (!new) { ++ spin_unlock(&irq_mapping_update_lock); ++ return -ENOMEM; ++ } ++ new->next = virq_actions[virq]; ++ virq_actions[virq] = cur = new; ++ retval = 1; ++ } ++ cpu_set(cpu, cur->cpus); ++ action = &cur->action; ++ ++ if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { ++ unsigned int cpu; ++ ++ BUG_ON(!retval); ++ ++ if ((irq = find_unbound_irq(true)) < 0) { ++ if (cur) ++ virq_actions[virq] = cur->next; ++ spin_unlock(&irq_mapping_update_lock); ++ if (cur != new) ++ kfree(new); ++ return irq; ++ } ++ ++ /* Extra reference so count will never drop to zero. */ ++ irq_bindcount[irq]++; ++ ++ for_each_possible_cpu(cpu) ++ per_cpu(virq_to_irq, cpu)[virq] = irq; ++ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, 0); ++ } ++ ++ evtchn = per_cpu(virq_to_evtchn, cpu)[virq]; ++ if (!VALID_EVTCHN(evtchn)) { ++ bind_virq.virq = virq; ++ bind_virq.vcpu = cpu; ++ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, ++ &bind_virq) != 0) ++ BUG(); ++ evtchn = bind_virq.port; ++ evtchn_to_irq[evtchn] = irq; ++ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn; ++ ++ bind_evtchn_to_cpu(evtchn, cpu); ++ } ++ ++ irq_bindcount[irq]++; ++ ++ spin_unlock(&irq_mapping_update_lock); ++ ++ if (cur != new) ++ kfree(new); ++ ++ if (retval == 0) { ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ unmask_evtchn(evtchn); ++ local_irq_restore(flags); ++ } else { ++ action->flags |= IRQF_PERCPU; ++ retval = setup_irq(irq, action); ++ if (retval) { ++ unbind_from_per_cpu_irq(irq, cpu, cur->action.dev_id); ++ BUG_ON(retval > 0); ++ irq = retval; ++ } ++ } ++ ++ return irq; ++} ++EXPORT_SYMBOL_GPL(bind_virq_to_irqaction); ++#endif ++ + #ifdef PER_CPU_IPI_IRQ + int bind_ipi_to_irqhandler( + unsigned int ipi, +@@ -784,7 +970,7 @@ int __cpuinit bind_ipi_to_irqaction( + action->flags |= IRQF_PERCPU; + retval = setup_irq(irq, action); + if (retval) { +- unbind_from_per_cpu_irq(irq, cpu); ++ unbind_from_per_cpu_irq(irq, cpu, NULL); + BUG_ON(retval > 0); + irq = retval; + } +@@ -819,7 +1005,9 @@ static void rebind_irq_to_cpu(unsigned i + { + int evtchn = evtchn_from_irq(irq); + ++ BUG_IF_VIRQ_PER_CPU(irq); + BUG_IF_IPI(irq); ++ + if (VALID_EVTCHN(evtchn)) + rebind_evtchn_to_cpu(evtchn, tcpu); + } +@@ -1098,7 +1286,9 @@ void notify_remote_via_irq(int irq) + { + int evtchn = evtchn_from_irq(irq); + ++ BUG_ON(type_from_irq(irq) == IRQT_VIRQ); + BUG_IF_IPI(irq); ++ + if (VALID_EVTCHN(evtchn)) + notify_remote_via_evtchn(evtchn); + } +@@ -1106,6 +1296,7 @@ EXPORT_SYMBOL_GPL(notify_remote_via_irq) + + int irq_to_evtchn_port(int irq) + { ++ BUG_IF_VIRQ_PER_CPU(irq); + BUG_IF_IPI(irq); + return evtchn_from_irq(irq); + } +@@ -1200,6 +1391,12 @@ static void restore_cpu_virqs(unsigned i + if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) + continue; + ++#ifndef PER_CPU_VIRQ_IRQ ++ if (test_bit(virq, virq_per_cpu) ++ && !VALID_EVTCHN(per_cpu(virq_to_evtchn, cpu)[virq])) ++ continue; ++#endif ++ + BUG_ON(irq_info[irq] != mk_irq_info(IRQT_VIRQ, virq, 0)); + + /* Get a new binding from Xen. */ +@@ -1212,7 +1409,19 @@ static void restore_cpu_virqs(unsigned i + + /* Record the new mapping. */ + evtchn_to_irq[evtchn] = irq; ++#ifdef PER_CPU_VIRQ_IRQ + irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); ++#else ++ if (test_bit(virq, virq_per_cpu)) ++ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn; ++ else { ++ unsigned int cpu; ++ ++ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); ++ for_each_possible_cpu(cpu) ++ per_cpu(virq_to_evtchn, cpu)[virq] = evtchn; ++ } ++#endif + bind_evtchn_to_cpu(evtchn, cpu); + + /* Ready for use. */ +@@ -1267,7 +1476,11 @@ static int evtchn_resume(struct sys_devi + + /* Avoid doing anything in the 'suspend cancelled' case. */ + status.dom = DOMID_SELF; ++#ifdef PER_CPU_VIRQ_IRQ + status.port = evtchn_from_irq(__get_cpu_var(virq_to_irq)[VIRQ_TIMER]); ++#else ++ status.port = __get_cpu_var(virq_to_evtchn)[VIRQ_TIMER]; ++#endif + if (HYPERVISOR_event_channel_op(EVTCHNOP_status, &status)) + BUG(); + if (status.status == EVTCHNSTAT_virq +@@ -1407,6 +1620,15 @@ void __init xen_init_IRQ(void) + unsigned int i; + struct physdev_pirq_eoi_gmfn eoi_gmfn; + ++#ifndef PER_CPU_VIRQ_IRQ ++ __set_bit(VIRQ_TIMER, virq_per_cpu); ++ __set_bit(VIRQ_DEBUG, virq_per_cpu); ++ __set_bit(VIRQ_XENOPROF, virq_per_cpu); ++#ifdef CONFIG_IA64 ++ __set_bit(VIRQ_ITC, virq_per_cpu); ++#endif ++#endif ++ + init_evtchn_cpu_bindings(); + + pirq_needs_eoi = alloc_bootmem_pages(sizeof(unsigned long) +--- sle11-2009-06-04.orig/drivers/xen/core/smpboot.c 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/smpboot.c 2009-06-04 10:47:28.000000000 +0200 +@@ -163,11 +163,11 @@ static int __cpuinit xen_smp_intr_init(u + fail: + xen_spinlock_cleanup(cpu); + unbind_call1: +- unbind_from_per_cpu_irq(call1func_irq, cpu); ++ unbind_from_per_cpu_irq(call1func_irq, cpu, NULL); + unbind_call: +- unbind_from_per_cpu_irq(callfunc_irq, cpu); ++ unbind_from_per_cpu_irq(callfunc_irq, cpu, NULL); + unbind_resched: +- unbind_from_per_cpu_irq(resched_irq, cpu); ++ unbind_from_per_cpu_irq(resched_irq, cpu, NULL); + return rc; + } + +@@ -177,9 +177,9 @@ static void __cpuinit xen_smp_intr_exit( + if (cpu != 0) + local_teardown_timer(cpu); + +- unbind_from_per_cpu_irq(resched_irq, cpu); +- unbind_from_per_cpu_irq(callfunc_irq, cpu); +- unbind_from_per_cpu_irq(call1func_irq, cpu); ++ unbind_from_per_cpu_irq(resched_irq, cpu, NULL); ++ unbind_from_per_cpu_irq(callfunc_irq, cpu, NULL); ++ unbind_from_per_cpu_irq(call1func_irq, cpu, NULL); + xen_spinlock_cleanup(cpu); + } + #endif +--- sle11-2009-06-04.orig/drivers/xen/core/spinlock.c 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/spinlock.c 2009-06-04 10:47:28.000000000 +0200 +@@ -57,7 +57,7 @@ int __cpuinit xen_spinlock_init(unsigned + + void __cpuinit xen_spinlock_cleanup(unsigned int cpu) + { +- unbind_from_per_cpu_irq(spinlock_irq, cpu); ++ unbind_from_per_cpu_irq(spinlock_irq, cpu, NULL); + } + + int xen_spin_wait(raw_spinlock_t *lock, unsigned int token) +--- sle11-2009-06-04.orig/drivers/xen/netback/netback.c 2009-06-04 10:20:21.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/netback/netback.c 2009-06-04 10:47:28.000000000 +0200 +@@ -1561,6 +1561,12 @@ static irqreturn_t netif_be_dbg(int irq, + + return IRQ_HANDLED; + } ++ ++static struct irqaction netif_be_dbg_action = { ++ .handler = netif_be_dbg, ++ .flags = IRQF_SHARED, ++ .name = "net-be-dbg" ++}; + #endif + + static int __init netback_init(void) +@@ -1620,12 +1626,9 @@ static int __init netback_init(void) + netif_xenbus_init(); + + #ifdef NETBE_DEBUG_INTERRUPT +- (void)bind_virq_to_irqhandler(VIRQ_DEBUG, +- 0, +- netif_be_dbg, +- IRQF_SHARED, +- "net-be-dbg", +- &netif_be_dbg); ++ (void)bind_virq_to_irqaction(VIRQ_DEBUG, ++ 0, ++ &netif_be_dbg_action); + #endif + + return 0; +--- sle11-2009-06-04.orig/drivers/xen/xenoprof/xenoprofile.c 2009-06-04 10:20:39.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/xenoprof/xenoprofile.c 2009-06-04 10:47:28.000000000 +0200 +@@ -210,6 +210,11 @@ static irqreturn_t xenoprof_ovf_interrup + return IRQ_HANDLED; + } + ++static struct irqaction ovf_action = { ++ .handler = xenoprof_ovf_interrupt, ++ .flags = IRQF_DISABLED, ++ .name = "xenoprof" ++}; + + static void unbind_virq(void) + { +@@ -217,7 +222,7 @@ static void unbind_virq(void) + + for_each_online_cpu(i) { + if (ovf_irq[i] >= 0) { +- unbind_from_irqhandler(ovf_irq[i], NULL); ++ unbind_from_per_cpu_irq(ovf_irq[i], i, &ovf_action); + ovf_irq[i] = -1; + } + } +@@ -230,12 +235,7 @@ static int bind_virq(void) + int result; + + for_each_online_cpu(i) { +- result = bind_virq_to_irqhandler(VIRQ_XENOPROF, +- i, +- xenoprof_ovf_interrupt, +- IRQF_DISABLED|IRQF_NOBALANCING, +- "xenoprof", +- NULL); ++ result = bind_virq_to_irqaction(VIRQ_XENOPROF, i, &ovf_action); + + if (result < 0) { + unbind_virq(); +--- sle11-2009-06-04.orig/include/xen/evtchn.h 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/include/xen/evtchn.h 2009-06-04 10:47:28.000000000 +0200 +@@ -78,6 +78,17 @@ int bind_virq_to_irqhandler( + unsigned long irqflags, + const char *devname, + void *dev_id); ++#if defined(CONFIG_SMP) && defined(CONFIG_XEN) && defined(CONFIG_X86) ++int bind_virq_to_irqaction( ++ unsigned int virq, ++ unsigned int cpu, ++ struct irqaction *action); ++#else ++#define bind_virq_to_irqaction(virq, cpu, action) \ ++ bind_virq_to_irqhandler(virq, cpu, (action)->handler, \ ++ (action)->flags | IRQF_NOBALANCING, \ ++ (action)->name, action) ++#endif + #if defined(CONFIG_SMP) && !defined(MODULE) + #ifndef CONFIG_X86 + int bind_ipi_to_irqhandler( +@@ -102,9 +113,13 @@ int bind_ipi_to_irqaction( + */ + void unbind_from_irqhandler(unsigned int irq, void *dev_id); + +-#if defined(CONFIG_SMP) && !defined(MODULE) && defined(CONFIG_X86) ++#if defined(CONFIG_SMP) && defined(CONFIG_XEN) && defined(CONFIG_X86) + /* Specialized unbind function for per-CPU IRQs. */ +-void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu); ++void unbind_from_per_cpu_irq(unsigned int irq, unsigned int cpu, ++ struct irqaction *); ++#else ++#define unbind_from_per_cpu_irq(irq, cpu, action) \ ++ unbind_from_irqhandler(irq, action) + #endif + + #ifndef CONFIG_XEN diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-bigmem b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-bigmem new file mode 100644 index 000000000..d7fb80544 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-bigmem @@ -0,0 +1,161 @@ +From: jbeulich@novell.com +Subject: fix issues with the assignment of huge amounts of memory +Patch-mainline: obsolete + +At the same time remove the non-applicable and broken support for the +memmap= command line option. + +--- sle11-2009-07-31.orig/arch/x86/kernel/e820-xen.c 2009-02-17 14:01:20.000000000 +0100 ++++ sle11-2009-07-31/arch/x86/kernel/e820-xen.c 2009-03-13 16:14:19.000000000 +0100 +@@ -1308,6 +1308,26 @@ static int __init parse_memopt(char *p) + + i = e820.nr_map - 1; + current_end = e820.map[i].addr + e820.map[i].size; ++ ++ /* ++ * A little less than 2% of available memory are needed for page ++ * tables, p2m map, and mem_map. Hence the maximum amount of memory ++ * we can potentially balloon up to can in no case exceed about 50 ++ * times of what we've been given initially. Since even with that we ++ * won't be able to boot (due to various calculations done based on ++ * the total number of pages) we further restrict this to factor 32. ++ */ ++ if ((mem_size >> (PAGE_SHIFT + 5)) > xen_start_info->nr_pages) { ++ u64 size = (u64)xen_start_info->nr_pages << 5; ++ ++ printk(KERN_WARNING "mem=%Luk is invalid for an initial" ++ " allocation of %luk, using %Luk\n", ++ (unsigned long long)mem_size >> 10, ++ xen_start_info->nr_pages << (PAGE_SHIFT - 10), ++ (unsigned long long)size << (PAGE_SHIFT - 10)); ++ mem_size = size << PAGE_SHIFT; ++ } ++ + if (current_end < mem_size) { + /* + * The e820 map ends before our requested size so +@@ -1367,6 +1387,7 @@ static int __init parse_memmap_opt(char + return *p == '\0' ? 0 : -EINVAL; + } + early_param("memmap", parse_memmap_opt); ++#endif + + void __init finish_e820_parsing(void) + { +@@ -1381,7 +1402,6 @@ void __init finish_e820_parsing(void) + e820_print_map("user"); + } + } +-#endif + + static inline const char *e820_type_to_string(int e820_type) + { +@@ -1407,7 +1427,7 @@ void __init e820_reserve_resources(void) + struct resource *res; + u64 end; + +- res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map); ++ res = alloc_bootmem(sizeof(struct resource) * e820.nr_map); + for (i = 0; i < e820.nr_map; i++) { + end = e820.map[i].addr + e820.map[i].size - 1; + #ifndef CONFIG_RESOURCES_64BIT +--- sle11-2009-07-31.orig/arch/x86/kernel/setup-xen.c 2009-07-31 15:14:20.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/kernel/setup-xen.c 2009-07-31 15:14:31.000000000 +0200 +@@ -128,12 +128,7 @@ static struct notifier_block xen_panic_b + unsigned long *phys_to_machine_mapping; + EXPORT_SYMBOL(phys_to_machine_mapping); + +-unsigned long *pfn_to_mfn_frame_list_list, +-#ifdef CONFIG_X86_64 +- *pfn_to_mfn_frame_list[512]; +-#else +- *pfn_to_mfn_frame_list[128]; +-#endif ++unsigned long *pfn_to_mfn_frame_list_list, **pfn_to_mfn_frame_list; + + /* Raw start-of-day parameters from the hypervisor. */ + start_info_t *xen_start_info; +@@ -1036,17 +1031,17 @@ void __init setup_arch(char **cmdline_p) + p2m_pages = xen_start_info->nr_pages; + + if (!xen_feature(XENFEAT_auto_translated_physmap)) { +- unsigned long i, j; ++ unsigned long i, j, size; + unsigned int k, fpp; + + /* Make sure we have a large enough P->M table. */ + phys_to_machine_mapping = alloc_bootmem_pages( + max_pfn * sizeof(unsigned long)); +- memset(phys_to_machine_mapping, ~0, +- max_pfn * sizeof(unsigned long)); + memcpy(phys_to_machine_mapping, + (unsigned long *)xen_start_info->mfn_list, + p2m_pages * sizeof(unsigned long)); ++ memset(phys_to_machine_mapping + p2m_pages, ~0, ++ (max_pfn - p2m_pages) * sizeof(unsigned long)); + free_bootmem( + __pa(xen_start_info->mfn_list), + PFN_PHYS(PFN_UP(xen_start_info->nr_pages * +@@ -1056,15 +1051,26 @@ void __init setup_arch(char **cmdline_p) + * Initialise the list of the frames that specify the list of + * frames that make up the p2m table. Used by save/restore. + */ +- pfn_to_mfn_frame_list_list = alloc_bootmem_pages(PAGE_SIZE); +- + fpp = PAGE_SIZE/sizeof(unsigned long); ++ size = (max_pfn + fpp - 1) / fpp; ++ size = (size + fpp - 1) / fpp; ++ ++size; /* include a zero terminator for crash tools */ ++ size *= sizeof(unsigned long); ++ pfn_to_mfn_frame_list_list = alloc_bootmem_pages(size); ++ if (size > PAGE_SIZE ++ && xen_create_contiguous_region((unsigned long) ++ pfn_to_mfn_frame_list_list, ++ get_order(size), 0)) ++ BUG(); ++ size -= sizeof(unsigned long); ++ pfn_to_mfn_frame_list = alloc_bootmem(size); ++ + for (i = j = 0, k = -1; i < max_pfn; i += fpp, j++) { + if (j == fpp) + j = 0; + if (j == 0) { + k++; +- BUG_ON(k>=ARRAY_SIZE(pfn_to_mfn_frame_list)); ++ BUG_ON(k * sizeof(unsigned long) >= size); + pfn_to_mfn_frame_list[k] = + alloc_bootmem_pages(PAGE_SIZE); + pfn_to_mfn_frame_list_list[k] = +--- sle11-2009-07-31.orig/arch/x86/kernel/setup_percpu-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/kernel/setup_percpu-xen.c 2009-03-13 16:14:41.000000000 +0100 +@@ -211,7 +211,7 @@ static void __init setup_node_to_cpumask + } + + /* allocate the map */ +- map = alloc_bootmem_low(nr_node_ids * sizeof(cpumask_t)); ++ map = alloc_bootmem(nr_node_ids * sizeof(cpumask_t)); + + pr_debug(KERN_DEBUG "Node to cpumask map at %p for %d nodes\n", + map, nr_node_ids); +--- sle11-2009-07-31.orig/drivers/xen/core/machine_kexec.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-07-31/drivers/xen/core/machine_kexec.c 2009-03-13 16:13:15.000000000 +0100 +@@ -57,7 +57,7 @@ void __init xen_machine_kexec_setup_reso + + /* allocate xen_phys_cpus */ + +- xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource)); ++ xen_phys_cpus = alloc_bootmem(k * sizeof(struct resource)); + BUG_ON(xen_phys_cpus == NULL); + + /* fill in xen_phys_cpus with per-cpu crash note information */ +--- sle11-2009-07-31.orig/drivers/xen/core/machine_reboot.c 2009-02-17 12:23:48.000000000 +0100 ++++ sle11-2009-07-31/drivers/xen/core/machine_reboot.c 2009-02-17 12:25:29.000000000 +0100 +@@ -76,7 +76,7 @@ static void post_suspend(int suspend_can + unsigned long shinfo_mfn; + extern unsigned long max_pfn; + extern unsigned long *pfn_to_mfn_frame_list_list; +- extern unsigned long *pfn_to_mfn_frame_list[]; ++ extern unsigned long **pfn_to_mfn_frame_list; + + if (suspend_cancelled) { + xen_start_info->store_mfn = diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-consistent-nmi b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-consistent-nmi new file mode 100644 index 000000000..16ae28b6f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-consistent-nmi @@ -0,0 +1,248 @@ +From: jbeulich@novell.com +Subject: make i386 and x86 NMI code consistent, disable all APIC-related stuff +Patch-mainline: obsolete +References: 191115 + +--- head-2008-12-08.orig/arch/x86/kernel/Makefile 2008-12-08 13:37:43.000000000 +0100 ++++ head-2008-12-08/arch/x86/kernel/Makefile 2008-12-08 13:39:19.000000000 +0100 +@@ -120,7 +120,6 @@ ifeq ($(CONFIG_X86_64),y) + + obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o + +- obj-$(CONFIG_XEN) += nmi.o + time_64-$(CONFIG_XEN) += time_32.o + endif + +--- head-2008-12-08.orig/arch/x86/kernel/cpu/Makefile 2008-12-08 13:37:45.000000000 +0100 ++++ head-2008-12-08/arch/x86/kernel/cpu/Makefile 2008-12-08 13:39:19.000000000 +0100 +@@ -24,4 +24,4 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/ + + obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o + +-disabled-obj-$(CONFIG_XEN) := hypervisor.o vmware.o ++disabled-obj-$(CONFIG_XEN) := hypervisor.o perfctr-watchdog.o vmware.o +--- head-2008-12-08.orig/arch/x86/kernel/nmi.c 2008-12-08 13:25:43.000000000 +0100 ++++ head-2008-12-08/arch/x86/kernel/nmi.c 2008-12-08 13:39:19.000000000 +0100 +@@ -27,7 +27,7 @@ + #include + #include + +-#ifndef CONFIG_XEN ++#ifdef ARCH_HAS_NMI_WATCHDOG + #include + #endif + #include +@@ -41,6 +41,9 @@ + #include + + int unknown_nmi_panic; ++ ++#ifdef ARCH_HAS_NMI_WATCHDOG ++ + int nmi_watchdog_enabled; + + static cpumask_t backtrace_mask = CPU_MASK_NONE; +@@ -181,10 +184,8 @@ int __init check_nmi_watchdog(void) + kfree(prev_nmi_count); + return 0; + error: +-#ifndef CONFIG_XEN + if (nmi_watchdog == NMI_IO_APIC && !timer_through_8259) + disable_8259A_irq(0); +-#endif + #ifdef CONFIG_X86_32 + timer_ack = 0; + #endif +@@ -460,6 +461,8 @@ nmi_watchdog_tick(struct pt_regs *regs, + return rc; + } + ++#endif /* ARCH_HAS_NMI_WATCHDOG */ ++ + #ifdef CONFIG_SYSCTL + + static int __init setup_unknown_nmi_panic(char *str) +@@ -479,6 +482,7 @@ static int unknown_nmi_panic_callback(st + return 0; + } + ++#ifdef ARCH_HAS_NMI_WATCHDOG + /* + * proc handler for /proc/sys/kernel/nmi + */ +@@ -511,6 +515,7 @@ int proc_nmi_enabled(struct ctl_table *t + } + return 0; + } ++#endif + + #endif /* CONFIG_SYSCTL */ + +@@ -523,6 +528,7 @@ int do_nmi_callback(struct pt_regs *regs + return 0; + } + ++#ifdef ARCH_HAS_NMI_WATCHDOG + void __trigger_all_cpu_backtrace(void) + { + int i; +@@ -535,3 +541,4 @@ void __trigger_all_cpu_backtrace(void) + mdelay(1); + } + } ++#endif +--- head-2008-12-08.orig/arch/x86/kernel/traps_32-xen.c 2008-12-08 13:37:51.000000000 +0100 ++++ head-2008-12-08/arch/x86/kernel/traps_32-xen.c 2008-12-08 13:39:19.000000000 +0100 +@@ -823,12 +823,14 @@ static notrace __kprobes void default_do + == NOTIFY_STOP) + return; + #ifdef CONFIG_X86_LOCAL_APIC ++#ifdef ARCH_HAS_NMI_WATCHDOG + /* + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ + if (nmi_watchdog_tick(regs, reason)) + return; ++#endif + if (!do_nmi_callback(regs, cpu)) + unknown_nmi_error(reason, regs); + #else +--- head-2008-12-08.orig/arch/x86/kernel/traps_64-xen.c 2008-12-08 13:37:51.000000000 +0100 ++++ head-2008-12-08/arch/x86/kernel/traps_64-xen.c 2008-12-08 13:39:19.000000000 +0100 +@@ -636,7 +636,7 @@ void die(const char *str, struct pt_regs + oops_end(flags, regs, SIGSEGV); + } + +-#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_SYSCTL) ++#ifdef CONFIG_SYSCTL + notrace __kprobes void + die_nmi(char *str, struct pt_regs *regs, int do_panic) + { +@@ -882,6 +882,7 @@ asmlinkage notrace __kprobes void defaul + == NOTIFY_STOP) + return; + #ifdef CONFIG_X86_LOCAL_APIC ++#ifdef ARCH_HAS_NMI_WATCHDOG + /* + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. +@@ -891,6 +892,9 @@ asmlinkage notrace __kprobes void defaul + #endif + if (!do_nmi_callback(regs, cpu)) + unknown_nmi_error(reason, regs); ++#else ++ unknown_nmi_error(reason, regs); ++#endif + + return; + } +--- head-2008-12-08.orig/arch/x86/mach-xen/setup.c 2008-12-08 13:25:43.000000000 +0100 ++++ head-2008-12-08/arch/x86/mach-xen/setup.c 2008-12-08 13:39:19.000000000 +0100 +@@ -108,12 +108,10 @@ void __init machine_specific_arch_setup( + .address = CALLBACK_ADDR(system_call) + }; + #endif +-#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_X86_32) + static struct callback_register __initdata nmi_cb = { + .type = CALLBACKTYPE_nmi, + .address = CALLBACK_ADDR(nmi) + }; +-#endif + + ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event); + if (ret == 0) +@@ -137,7 +135,6 @@ void __init machine_specific_arch_setup( + #endif + BUG_ON(ret); + +-#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_X86_32) + ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb); + #if CONFIG_XEN_COMPAT <= 0x030002 + if (ret == -ENOSYS) { +@@ -148,7 +145,6 @@ void __init machine_specific_arch_setup( + HYPERVISOR_nmi_op(XENNMI_register_callback, &cb); + } + #endif +-#endif + + #ifdef CONFIG_X86_32 + /* Do an early initialization of the fixmap area */ +--- head-2008-12-08.orig/include/asm-x86/irq.h 2008-12-08 13:15:52.000000000 +0100 ++++ head-2008-12-08/include/asm-x86/irq.h 2008-12-08 13:39:19.000000000 +0100 +@@ -15,7 +15,7 @@ static inline int irq_canonicalize(int i + return ((irq == 2) ? 9 : irq); + } + +-#ifdef CONFIG_X86_LOCAL_APIC ++#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_XEN) + # define ARCH_HAS_NMI_WATCHDOG + #endif + +--- head-2008-12-08.orig/include/asm-x86/nmi.h 2008-12-08 13:15:52.000000000 +0100 ++++ head-2008-12-08/include/asm-x86/nmi.h 2008-12-08 13:39:19.000000000 +0100 +@@ -5,8 +5,6 @@ + #include + #include + +-#ifdef ARCH_HAS_NMI_WATCHDOG +- + /** + * do_nmi_callback + * +@@ -20,6 +18,11 @@ extern void default_do_nmi(struct pt_reg + #endif + + extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); ++ ++extern int unknown_nmi_panic; ++ ++#ifdef ARCH_HAS_NMI_WATCHDOG ++ + extern int check_nmi_watchdog(void); + extern int nmi_watchdog_enabled; + extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); +@@ -46,7 +49,6 @@ struct ctl_table; + struct file; + extern int proc_nmi_enabled(struct ctl_table *, int , struct file *, + void __user *, size_t *, loff_t *); +-extern int unknown_nmi_panic; + + void __trigger_all_cpu_backtrace(void); + #define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace() +@@ -69,7 +71,6 @@ static inline int nmi_watchdog_active(vo + */ + return nmi_watchdog & 0x3; + } +-#endif + + void lapic_watchdog_stop(void); + int lapic_watchdog_init(unsigned nmi_hz); +@@ -78,6 +79,9 @@ unsigned lapic_adjust_nmi_hz(unsigned hz + int lapic_watchdog_ok(void); + void disable_lapic_nmi_watchdog(void); + void enable_lapic_nmi_watchdog(void); ++ ++#endif ++ + void stop_nmi(void); + void restart_nmi(void); + +--- head-2008-12-08.orig/kernel/sysctl.c 2008-12-08 13:17:58.000000000 +0100 ++++ head-2008-12-08/kernel/sysctl.c 2008-12-08 13:39:19.000000000 +0100 +@@ -673,6 +673,7 @@ static struct ctl_table kern_table[] = { + .mode = 0644, + .proc_handler = &proc_dointvec, + }, ++#ifdef ARCH_HAS_NMI_WATCHDOG + { + .procname = "nmi_watchdog", + .data = &nmi_watchdog_enabled, +@@ -681,6 +682,7 @@ static struct ctl_table kern_table[] = { + .proc_handler = &proc_nmi_enabled, + }, + #endif ++#endif + #if defined(CONFIG_X86) + { + .ctl_name = KERN_PANIC_ON_NMI, diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-dcr-fallback b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-dcr-fallback new file mode 100644 index 000000000..830acd313 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-dcr-fallback @@ -0,0 +1,154 @@ +Subject: Add fallback when XENMEM_exchange fails to replace contiguous region +From: jbeulich@novell.com +Patch-mainline: obsolete +References: 181869 + +This avoids losing precious special memory in places where any memory can be +used. + +--- sle11-2009-06-29.orig/arch/x86/mm/hypervisor.c 2009-03-16 16:17:45.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/hypervisor.c 2009-03-30 12:18:24.000000000 +0200 +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -712,6 +713,83 @@ void xen_destroy_contiguous_region(unsig + BUG(); + + balloon_unlock(flags); ++ ++ if (unlikely(!success)) { ++ /* Try hard to get the special memory back to Xen. */ ++ exchange.in.extent_order = 0; ++ set_xen_guest_handle(exchange.in.extent_start, &in_frame); ++ ++ for (i = 0; i < (1U<> PAGE_SHIFT; ++ set_phys_to_machine(pfn, frame); ++ if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ mmu.ptr = ((uint64_t)frame << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; ++ mmu.val = pfn; ++ cr_mcl[j].op = __HYPERVISOR_mmu_update; ++ cr_mcl[j].args[0] = (unsigned long)&mmu; ++ cr_mcl[j].args[1] = 1; ++ cr_mcl[j].args[2] = 0; ++ cr_mcl[j].args[3] = DOMID_SELF; ++ ++j; ++ } ++ ++ cr_mcl[j].op = __HYPERVISOR_memory_op; ++ cr_mcl[j].args[0] = XENMEM_decrease_reservation; ++ cr_mcl[j].args[1] = (unsigned long)&exchange.in; ++ ++ if (HYPERVISOR_multicall(cr_mcl, j + 1)) ++ BUG(); ++ BUG_ON(cr_mcl[j].result != 1); ++ while (j--) ++ BUG_ON(cr_mcl[j].result != 0); ++ ++ balloon_unlock(flags); ++ ++ free_empty_pages(&page, 1); ++ ++ in_frame++; ++ vstart += PAGE_SIZE; ++ } ++ } + } + EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); + +--- sle11-2009-06-29.orig/drivers/xen/balloon/balloon.c 2009-06-29 15:44:49.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/balloon/balloon.c 2009-06-29 15:46:09.000000000 +0200 +@@ -665,7 +665,7 @@ struct page **alloc_empty_pages_and_page + goto out; + } + +-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) ++static void _free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages, int free_vec) + { + unsigned long flags; + int i; +@@ -678,13 +678,26 @@ void free_empty_pages_and_pagevec(struct + BUG_ON(page_count(pagevec[i]) != 1); + balloon_append(pagevec[i]); + } ++ if (!free_vec) ++ totalram_pages = bs.current_pages -= nr_pages; + balloon_unlock(flags); + +- kfree(pagevec); ++ if (free_vec) ++ kfree(pagevec); + + schedule_work(&balloon_worker); + } + ++void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages) ++{ ++ _free_empty_pages_and_pagevec(pagevec, nr_pages, 1); ++} ++ ++void free_empty_pages(struct page **pagevec, int nr_pages) ++{ ++ _free_empty_pages_and_pagevec(pagevec, nr_pages, 0); ++} ++ + void balloon_release_driver_page(struct page *page) + { + unsigned long flags; +--- sle11-2009-06-29.orig/include/xen/balloon.h 2009-03-16 16:38:05.000000000 +0100 ++++ sle11-2009-06-29/include/xen/balloon.h 2009-03-16 16:40:33.000000000 +0100 +@@ -47,6 +47,10 @@ void balloon_update_driver_allowance(lon + struct page **alloc_empty_pages_and_pagevec(int nr_pages); + void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages); + ++/* Free an empty page range (not allocated through ++ alloc_empty_pages_and_pagevec), adding to the balloon. */ ++void free_empty_pages(struct page **pagevec, int nr_pages); ++ + void balloon_release_driver_page(struct page *page); + + /* diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-exit-mmap b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-exit-mmap new file mode 100644 index 000000000..30f302bf8 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-exit-mmap @@ -0,0 +1,67 @@ +Subject: be more aggressive about de-activating mm-s under destruction +From: jbeulich@novell.com +Patch-mainline: obsolete + +... by not only handling the current task on the CPU arch_exit_mmap() +gets executed on, but also forcing remote CPUs to do so. + +Index: head-2008-12-01/arch/x86/mm/pgtable-xen.c +=================================================================== +--- head-2008-12-01.orig/arch/x86/mm/pgtable-xen.c 2008-12-01 12:13:06.000000000 +0100 ++++ head-2008-12-01/arch/x86/mm/pgtable-xen.c 2008-12-01 12:13:16.000000000 +0100 +@@ -418,27 +418,44 @@ void arch_dup_mmap(struct mm_struct *old + mm_pin(mm); + } + +-void arch_exit_mmap(struct mm_struct *mm) ++/* ++ * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() *much* ++ * faster this way, as no hypercalls are needed for the page table updates. ++ */ ++static void leave_active_mm(struct task_struct *tsk, struct mm_struct *mm) ++ __releases(tsk->alloc_lock) + { +- struct task_struct *tsk = current; +- +- task_lock(tsk); +- +- /* +- * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() +- * *much* faster this way, as no tlb flushes means bigger wrpt batches. +- */ + if (tsk->active_mm == mm) { + tsk->active_mm = &init_mm; + atomic_inc(&init_mm.mm_count); + + switch_mm(mm, &init_mm, tsk); + +- atomic_dec(&mm->mm_count); +- BUG_ON(atomic_read(&mm->mm_count) == 0); ++ if (atomic_dec_and_test(&mm->mm_count)) ++ BUG(); + } + + task_unlock(tsk); ++} ++ ++static void _leave_active_mm(void *mm) ++{ ++ struct task_struct *tsk = current; ++ ++ if (spin_trylock(&tsk->alloc_lock)) ++ leave_active_mm(tsk, mm); ++} ++ ++void arch_exit_mmap(struct mm_struct *mm) ++{ ++ struct task_struct *tsk = current; ++ ++ task_lock(tsk); ++ leave_active_mm(tsk, mm); ++ ++ preempt_disable(); ++ smp_call_function_mask(mm->cpu_vm_mask, _leave_active_mm, mm, 1); ++ preempt_enable(); + + if (PagePinned(virt_to_page(mm->pgd)) + && atomic_read(&mm->mm_count) == 1 diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-exports b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-exports new file mode 100644 index 000000000..06f82eb68 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-exports @@ -0,0 +1,23 @@ +Subject: export a few more symbols +From: jbeulich@novell.com +Patch-mainline: obsolete +References: bnc#458222 + +--- sle11-2009-03-16.orig/arch/x86/mm/hypervisor.c 2009-03-16 16:40:37.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/mm/hypervisor.c 2009-03-16 16:40:44.000000000 +0100 +@@ -486,6 +486,7 @@ void xen_tlb_flush_all(void) + op.cmd = MMUEXT_TLB_FLUSH_ALL; + BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); + } ++EXPORT_SYMBOL_GPL(xen_tlb_flush_all); + + void xen_tlb_flush_mask(cpumask_t *mask) + { +@@ -504,6 +505,7 @@ void xen_invlpg_all(unsigned long ptr) + op.arg1.linear_addr = ptr & PAGE_MASK; + BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); + } ++EXPORT_SYMBOL_GPL(xen_invlpg_all); + + void xen_invlpg_mask(cpumask_t *mask, unsigned long ptr) + { diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-machphys-prediction b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-machphys-prediction new file mode 100644 index 000000000..865cc756d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-machphys-prediction @@ -0,0 +1,210 @@ +From: jbeulich@novell.com +Subject: properly predict phys<->mach translations +Patch-mainline: obsolete + +Index: head-2008-11-04/include/asm-x86/mach-xen/asm/maddr_32.h +=================================================================== +--- head-2008-11-04.orig/include/asm-x86/mach-xen/asm/maddr_32.h 2008-11-04 11:54:55.000000000 +0100 ++++ head-2008-11-04/include/asm-x86/mach-xen/asm/maddr_32.h 2008-10-17 12:45:23.000000000 +0200 +@@ -30,17 +30,19 @@ extern unsigned int machine_to_phys_or + + static inline unsigned long pfn_to_mfn(unsigned long pfn) + { +- if (xen_feature(XENFEAT_auto_translated_physmap)) ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) + return pfn; +- BUG_ON(max_mapnr && pfn >= max_mapnr); ++ if (likely(max_mapnr)) ++ BUG_ON(pfn >= max_mapnr); + return phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT; + } + + static inline int phys_to_machine_mapping_valid(unsigned long pfn) + { +- if (xen_feature(XENFEAT_auto_translated_physmap)) ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) + return 1; +- BUG_ON(max_mapnr && pfn >= max_mapnr); ++ if (likely(max_mapnr)) ++ BUG_ON(pfn >= max_mapnr); + return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); + } + +@@ -48,7 +50,7 @@ static inline unsigned long mfn_to_pfn(u + { + unsigned long pfn; + +- if (xen_feature(XENFEAT_auto_translated_physmap)) ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) + return mfn; + + if (unlikely((mfn >> machine_to_phys_order) != 0)) +@@ -95,17 +97,18 @@ static inline unsigned long mfn_to_pfn(u + static inline unsigned long mfn_to_local_pfn(unsigned long mfn) + { + unsigned long pfn = mfn_to_pfn(mfn); +- if ((pfn < max_mapnr) +- && !xen_feature(XENFEAT_auto_translated_physmap) +- && (phys_to_machine_mapping[pfn] != mfn)) ++ if (likely(pfn < max_mapnr) ++ && likely(!xen_feature(XENFEAT_auto_translated_physmap)) ++ && unlikely(phys_to_machine_mapping[pfn] != mfn)) + return max_mapnr; /* force !pfn_valid() */ + return pfn; + } + + static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) + { +- BUG_ON(max_mapnr && pfn >= max_mapnr); +- if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ if (likely(max_mapnr)) ++ BUG_ON(pfn >= max_mapnr); ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { + BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); + return; + } +Index: head-2008-11-04/include/asm-x86/mach-xen/asm/maddr_64.h +=================================================================== +--- head-2008-11-04.orig/include/asm-x86/mach-xen/asm/maddr_64.h 2008-11-04 11:54:55.000000000 +0100 ++++ head-2008-11-04/include/asm-x86/mach-xen/asm/maddr_64.h 2008-10-17 12:46:35.000000000 +0200 +@@ -25,17 +25,19 @@ extern unsigned int machine_to_phys_or + + static inline unsigned long pfn_to_mfn(unsigned long pfn) + { +- if (xen_feature(XENFEAT_auto_translated_physmap)) ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) + return pfn; +- BUG_ON(max_mapnr && pfn >= max_mapnr); ++ if (likely(max_mapnr)) ++ BUG_ON(pfn >= max_mapnr); + return phys_to_machine_mapping[pfn] & ~FOREIGN_FRAME_BIT; + } + + static inline int phys_to_machine_mapping_valid(unsigned long pfn) + { +- if (xen_feature(XENFEAT_auto_translated_physmap)) ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) + return 1; +- BUG_ON(max_mapnr && pfn >= max_mapnr); ++ if (likely(max_mapnr)) ++ BUG_ON(pfn >= max_mapnr); + return (phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY); + } + +@@ -43,7 +45,7 @@ static inline unsigned long mfn_to_pfn(u + { + unsigned long pfn; + +- if (xen_feature(XENFEAT_auto_translated_physmap)) ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) + return mfn; + + if (unlikely((mfn >> machine_to_phys_order) != 0)) +@@ -90,17 +92,18 @@ static inline unsigned long mfn_to_pfn(u + static inline unsigned long mfn_to_local_pfn(unsigned long mfn) + { + unsigned long pfn = mfn_to_pfn(mfn); +- if ((pfn < max_mapnr) +- && !xen_feature(XENFEAT_auto_translated_physmap) +- && (phys_to_machine_mapping[pfn] != mfn)) ++ if (likely(pfn < max_mapnr) ++ && likely(!xen_feature(XENFEAT_auto_translated_physmap)) ++ && unlikely(phys_to_machine_mapping[pfn] != mfn)) + return max_mapnr; /* force !pfn_valid() */ + return pfn; + } + + static inline void set_phys_to_machine(unsigned long pfn, unsigned long mfn) + { +- BUG_ON(max_mapnr && pfn >= max_mapnr); +- if (xen_feature(XENFEAT_auto_translated_physmap)) { ++ if (likely(max_mapnr)) ++ BUG_ON(pfn >= max_mapnr); ++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) { + BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY); + return; + } +Index: head-2008-11-04/include/asm-x86/mach-xen/asm/page.h +=================================================================== +--- head-2008-11-04.orig/include/asm-x86/mach-xen/asm/page.h 2008-11-04 11:55:22.000000000 +0100 ++++ head-2008-11-04/include/asm-x86/mach-xen/asm/page.h 2008-10-17 12:53:40.000000000 +0200 +@@ -102,7 +102,7 @@ static inline void copy_user_page(void * + #define __pgd_ma(x) ((pgd_t) { (x) } ) + static inline pgd_t xen_make_pgd(pgdval_t val) + { +- if (val & _PAGE_PRESENT) ++ if (likely(val & _PAGE_PRESENT)) + val = pte_phys_to_machine(val); + return (pgd_t) { val }; + } +@@ -112,10 +112,10 @@ static inline pgdval_t xen_pgd_val(pgd_t + { + pgdval_t ret = __pgd_val(pgd); + #if PAGETABLE_LEVELS == 2 && CONFIG_XEN_COMPAT <= 0x030002 +- if (ret) ++ if (likely(ret)) + ret = machine_to_phys(ret) | _PAGE_PRESENT; + #else +- if (ret & _PAGE_PRESENT) ++ if (likely(ret & _PAGE_PRESENT)) + ret = pte_machine_to_phys(ret); + #endif + return ret; +@@ -128,7 +128,7 @@ typedef struct { pudval_t pud; } pud_t; + #define __pud_ma(x) ((pud_t) { (x) } ) + static inline pud_t xen_make_pud(pudval_t val) + { +- if (val & _PAGE_PRESENT) ++ if (likely(val & _PAGE_PRESENT)) + val = pte_phys_to_machine(val); + return (pud_t) { val }; + } +@@ -137,7 +137,7 @@ static inline pud_t xen_make_pud(pudval_ + static inline pudval_t xen_pud_val(pud_t pud) + { + pudval_t ret = __pud_val(pud); +- if (ret & _PAGE_PRESENT) ++ if (likely(ret & _PAGE_PRESENT)) + ret = pte_machine_to_phys(ret); + return ret; + } +@@ -156,7 +156,7 @@ typedef struct { pmdval_t pmd; } pmd_t; + #define __pmd_ma(x) ((pmd_t) { (x) } ) + static inline pmd_t xen_make_pmd(pmdval_t val) + { +- if (val & _PAGE_PRESENT) ++ if (likely(val & _PAGE_PRESENT)) + val = pte_phys_to_machine(val); + return (pmd_t) { val }; + } +@@ -166,10 +166,10 @@ static inline pmdval_t xen_pmd_val(pmd_t + { + pmdval_t ret = __pmd_val(pmd); + #if CONFIG_XEN_COMPAT <= 0x030002 +- if (ret) ++ if (likely(ret)) + ret = pte_machine_to_phys(ret) | _PAGE_PRESENT; + #else +- if (ret & _PAGE_PRESENT) ++ if (likely(ret & _PAGE_PRESENT)) + ret = pte_machine_to_phys(ret); + #endif + return ret; +@@ -188,7 +188,7 @@ static inline pmdval_t xen_pmd_val(pmd_t + #define __pte_ma(x) ((pte_t) { .pte = (x) } ) + static inline pte_t xen_make_pte(pteval_t val) + { +- if ((val & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT) ++ if (likely((val & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT)) + val = pte_phys_to_machine(val); + return (pte_t) { .pte = val }; + } +@@ -197,7 +197,7 @@ static inline pte_t xen_make_pte(pteval_ + static inline pteval_t xen_pte_val(pte_t pte) + { + pteval_t ret = __pte_val(pte); +- if ((pte.pte_low & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT) ++ if (likely((pte.pte_low & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT)) + ret = pte_machine_to_phys(ret); + return ret; + } diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-no-lapic b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-no-lapic new file mode 100644 index 000000000..cdf922636 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-no-lapic @@ -0,0 +1,1033 @@ +From: jbeulich@novell.com +Subject: Disallow all accesses to the local APIC page +Patch-mainline: obsolete +References: 191115 + +--- sle11-2009-06-04.orig/arch/x86/kernel/Makefile 2009-06-04 10:47:37.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/Makefile 2009-06-04 10:47:37.000000000 +0200 +@@ -120,9 +120,11 @@ ifeq ($(CONFIG_X86_64),y) + + obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o + ++ apic_64-$(CONFIG_XEN) += apic_32.o + time_64-$(CONFIG_XEN) += time_32.o + endif + +-disabled-obj-$(CONFIG_XEN) := %_uv.o crash.o early-quirks.o hpet.o i8253.o \ +- i8259.o irqinit_$(BITS).o pci-swiotlb_64.o reboot.o smpboot.o \ +- tlb_$(BITS).o tsc.o tsc_sync.o uv_%.o vsmp_64.o ++disabled-obj-$(CONFIG_XEN) := %_uv.o crash.o early-quirks.o genapic_flat_64.o \ ++ genx2apic_%.o hpet.o i8253.o i8259.o irqinit_$(BITS).o \ ++ pci-swiotlb_64.o reboot.o smpboot.o tlb_$(BITS).o tsc.o tsc_sync.o \ ++ uv_%.o vsmp_64.o +--- sle11-2009-06-04.orig/arch/x86/kernel/acpi/boot.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/acpi/boot.c 2009-06-04 10:47:37.000000000 +0200 +@@ -89,7 +89,7 @@ int acpi_sci_override_gsi __initdata; + int acpi_skip_timer_override __initdata; + int acpi_use_timer_override __initdata; + +-#ifdef CONFIG_X86_LOCAL_APIC ++#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_XEN) + static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; + #endif + +@@ -237,12 +237,14 @@ static int __init acpi_parse_madt(struct + return -ENODEV; + } + ++#ifndef CONFIG_XEN + if (madt->address) { + acpi_lapic_addr = (u64) madt->address; + + printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", + madt->address); + } ++#endif + + acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); + +@@ -317,6 +319,7 @@ static int __init + acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header, + const unsigned long end) + { ++#ifndef CONFIG_XEN + struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL; + + lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header; +@@ -325,6 +328,7 @@ acpi_parse_lapic_addr_ovr(struct acpi_su + return -EINVAL; + + acpi_lapic_addr = lapic_addr_ovr->address; ++#endif + + return 0; + } +@@ -904,10 +908,12 @@ static int mp_find_ioapic(int gsi) + static u8 __init uniq_ioapic_id(u8 id) + { + #ifdef CONFIG_X86_32 ++#ifndef CONFIG_XEN + if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && + !APIC_XAPIC(apic_version[boot_cpu_physical_apicid])) + return io_apic_get_unique_id(nr_ioapics, id); + else ++#endif + return id; + #else + int i; +@@ -1139,7 +1145,7 @@ int mp_register_gsi(u32 gsi, int trigger + + ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base; + +-#ifdef CONFIG_X86_32 ++#if defined(CONFIG_X86_32) && !defined(CONFIG_XEN) + if (ioapic_renumber_irq) + gsi = ioapic_renumber_irq(ioapic, gsi); + #endif +--- sle11-2009-06-04.orig/arch/x86/kernel/apic_32-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/apic_32-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -1,60 +1,11 @@ + /* +- * Local APIC handling, local APIC timers +- * +- * (c) 1999, 2000 Ingo Molnar +- * +- * Fixes +- * Maciej W. Rozycki : Bits for genuine 82489DX APICs; +- * thanks to Eric Gilmore +- * and Rolf G. Tews +- * for testing these extensively. +- * Maciej W. Rozycki : Various updates and fixes. +- * Mikael Pettersson : Power Management for UP-APIC. +- * Pavel Machek and +- * Mikael Pettersson : PM converted to driver model. ++ * Local APIC handling stubs + */ + + #include +- +-#include +-#include +-#include + #include +-#include +-#include +-#include +-#include +-#include +-#include +-#include + +-#include + #include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-#include "io_ports.h" +- +-#ifndef CONFIG_XEN +-/* +- * cpu_mask that denotes the CPUs that needs timer interrupt coming in as +- * IPIs in place of local APIC timers +- */ +-static cpumask_t timer_bcast_ipi; +-#endif +- +-/* +- * Knob to control our willingness to enable the local APIC. +- */ + + /* + * Debug level, exported for io_apic.c +@@ -64,33 +15,32 @@ unsigned int apic_verbosity; + /* Have we found an MP table */ + int smp_found_config; + +-#ifndef CONFIG_XEN +-static int modern_apic(void) ++static int __init apic_set_verbosity(char *str) + { +- /* AMD systems use old APIC versions, so check the CPU */ +- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && +- boot_cpu_data.x86 >= 0xf) +- return 1; +- return lapic_get_version() >= 0x14; ++ if (strcmp("debug", str) == 0) ++ apic_verbosity = APIC_DEBUG; ++ else if (strcmp("verbose", str) == 0) ++ apic_verbosity = APIC_VERBOSE; ++ return 1; + } +-#endif /* !CONFIG_XEN */ + +-int get_physical_broadcast(void) +-{ +- return 0xff; +-} ++__setup("apic=", apic_set_verbosity); + + int setup_profiling_timer(unsigned int multiplier) + { + return -EINVAL; + } + ++#ifndef CONFIG_SMP + /* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ + int __init APIC_init_uniprocessor(void) + { ++ if (!cpu_has_apic) ++ return -1; ++ + #ifdef CONFIG_X86_IO_APIC + if (smp_found_config) + if (!skip_ioapic_setup && nr_ioapics) +@@ -99,3 +49,4 @@ int __init APIC_init_uniprocessor(void) + + return 0; + } ++#endif +--- sle11-2009-06-04.orig/arch/x86/kernel/apic_64-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,188 +0,0 @@ +-/* +- * Local APIC handling, local APIC timers +- * +- * (c) 1999, 2000 Ingo Molnar +- * +- * Fixes +- * Maciej W. Rozycki : Bits for genuine 82489DX APICs; +- * thanks to Eric Gilmore +- * and Rolf G. Tews +- * for testing these extensively. +- * Maciej W. Rozycki : Various updates and fixes. +- * Mikael Pettersson : Power Management for UP-APIC. +- * Pavel Machek and +- * Mikael Pettersson : PM converted to driver model. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-int disable_apic; +- +-/* +- * Debug level, exported for io_apic.c +- */ +-unsigned int apic_verbosity; +- +-/* Have we found an MP table */ +-int smp_found_config; +- +-/* +- * The guts of the apic timer interrupt +- */ +-static void local_apic_timer_interrupt(void) +-{ +-#ifndef CONFIG_XEN +- int cpu = smp_processor_id(); +- struct clock_event_device *evt = &per_cpu(lapic_events, cpu); +- +- /* +- * Normally we should not be here till LAPIC has been initialized but +- * in some cases like kdump, its possible that there is a pending LAPIC +- * timer interrupt from previous kernel's context and is delivered in +- * new kernel the moment interrupts are enabled. +- * +- * Interrupts are enabled early and LAPIC is setup much later, hence +- * its possible that when we get here evt->event_handler is NULL. +- * Check for event_handler being NULL and discard the interrupt as +- * spurious. +- */ +- if (!evt->event_handler) { +- printk(KERN_WARNING +- "Spurious LAPIC timer interrupt on cpu %d\n", cpu); +- /* Switch it off */ +- lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); +- return; +- } +-#endif +- +- /* +- * the NMI deadlock-detector uses this. +- */ +- add_pda(apic_timer_irqs, 1); +- +-#ifndef CONFIG_XEN +- evt->event_handler(evt); +-#endif +-} +- +-/* +- * Local APIC timer interrupt. This is the most natural way for doing +- * local interrupts, but local timer interrupts can be emulated by +- * broadcast interrupts too. [in case the hw doesn't support APIC timers] +- * +- * [ if a single-CPU system runs an SMP kernel then we call the local +- * interrupt as well. Thus we cannot inline the local irq ... ] +- */ +-void smp_apic_timer_interrupt(struct pt_regs *regs) +-{ +- struct pt_regs *old_regs = set_irq_regs(regs); +- +- /* +- * NOTE! We'd better ACK the irq immediately, +- * because timer handling can be slow. +- */ +- ack_APIC_irq(); +- /* +- * update_process_times() expects us to have done irq_enter(). +- * Besides, if we don't timer interrupts ignore the global +- * interrupt lock, which is the WrongThing (tm) to do. +- */ +- exit_idle(); +- irq_enter(); +- local_apic_timer_interrupt(); +- irq_exit(); +- set_irq_regs(old_regs); +-} +- +-int setup_profiling_timer(unsigned int multiplier) +-{ +- return -EINVAL; +-} +- +-/* +- * This initializes the IO-APIC and APIC hardware if this is +- * a UP kernel. +- */ +-int __init APIC_init_uniprocessor(void) +-{ +-#ifdef CONFIG_X86_IO_APIC +- if (smp_found_config && !skip_ioapic_setup && nr_ioapics) +- setup_IO_APIC(); +-#endif +- +- return 1; +-} +- +-/* +- * Local APIC interrupts +- */ +- +-/* +- * This interrupt should _never_ happen with our APIC/SMP architecture +- */ +-asmlinkage void smp_spurious_interrupt(void) +-{ +- unsigned int v; +- exit_idle(); +- irq_enter(); +- /* +- * Check if this really is a spurious interrupt and ACK it +- * if it is a vectored one. Just in case... +- * Spurious interrupts should not be ACKed. +- */ +- v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1)); +- if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) +- ack_APIC_irq(); +- +- add_pda(irq_spurious_count, 1); +- irq_exit(); +-} +- +-/* +- * This interrupt should never happen with our APIC/SMP architecture +- */ +-asmlinkage void smp_error_interrupt(void) +-{ +- unsigned int v, v1; +- +- exit_idle(); +- irq_enter(); +- /* First tickle the hardware, only then report what went on. -- REW */ +- v = apic_read(APIC_ESR); +- apic_write(APIC_ESR, 0); +- v1 = apic_read(APIC_ESR); +- ack_APIC_irq(); +- atomic_inc(&irq_err_count); +- +- /* Here is what the APIC error bits mean: +- 0: Send CS error +- 1: Receive CS error +- 2: Send accept error +- 3: Receive accept error +- 4: Reserved +- 5: Send illegal vector +- 6: Received illegal vector +- 7: Illegal register address +- */ +- printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", +- smp_processor_id(), v , v1); +- irq_exit(); +-} +--- sle11-2009-06-04.orig/arch/x86/kernel/cpu/common-xen.c 2009-06-04 10:46:36.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/cpu/common-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -19,10 +19,6 @@ + #include + #include + #include +-#else +-#ifdef CONFIG_XEN +-#define phys_pkg_id(a,b) a +-#endif + #endif + #include + +--- sle11-2009-06-04.orig/arch/x86/kernel/genapic_64-xen.c 2009-06-04 10:46:28.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/genapic_64-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -18,7 +18,6 @@ + #include + + #include +-#include + #include + + #ifdef CONFIG_ACPI +--- sle11-2009-06-04.orig/arch/x86/kernel/genapic_xen_64.c 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/genapic_xen_64.c 2009-06-04 10:47:37.000000000 +0200 +@@ -18,7 +18,6 @@ + #include + #ifdef CONFIG_XEN_PRIVILEGED_GUEST + #include +-#include + #else + #include + #endif +@@ -78,20 +77,6 @@ static const cpumask_t *xen_target_cpus( + return &cpu_online_map; + } + +-static void xen_vector_allocation_domain(int cpu, cpumask_t *retmask) +-{ +- cpus_clear(*retmask); +- cpu_set(cpu, *retmask); +-} +- +-/* +- * Set up the logical destination ID. +- * Do nothing, not called now. +- */ +-static void xen_init_apic_ldr(void) +-{ +-} +- + static void xen_send_IPI_mask(const cpumask_t *cpumask, int vector) + { + xen_send_IPI_shortcut(APIC_DEST_ALLINC, cpumask, vector); +@@ -118,17 +103,9 @@ static void xen_send_IPI_self(int vector + xen_send_IPI_shortcut(APIC_DEST_SELF, NULL, vector); + } + +-#ifdef CONFIG_XEN_PRIVILEGED_GUEST +-static int xen_apic_id_registered(void) +-{ +- /* better be set */ +- return physid_isset(smp_processor_id(), phys_cpu_present_map); +-} +-#endif +- + static unsigned int xen_cpu_mask_to_apicid(const cpumask_t *cpumask) + { +- return cpus_addr(*cpumask)[0] & APIC_ALL_CPUS; ++ return cpus_addr(*cpumask)[0]; + } + + static unsigned int phys_pkg_id(int index_msb) +@@ -144,13 +121,8 @@ struct genapic apic_xen = { + #ifdef CONFIG_XEN_PRIVILEGED_GUEST + .int_delivery_mode = dest_LowestPrio, + #endif +- .int_dest_mode = (APIC_DEST_LOGICAL != 0), ++ .int_dest_mode = 1, + .target_cpus = xen_target_cpus, +- .vector_allocation_domain = xen_vector_allocation_domain, +-#ifdef CONFIG_XEN_PRIVILEGED_GUEST +- .apic_id_registered = xen_apic_id_registered, +-#endif +- .init_apic_ldr = xen_init_apic_ldr, + .send_IPI_all = xen_send_IPI_all, + .send_IPI_allbutself = xen_send_IPI_allbutself, + .send_IPI_mask = xen_send_IPI_mask, +--- sle11-2009-06-04.orig/arch/x86/kernel/io_apic_32-xen.c 2009-06-04 10:46:34.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/io_apic_32-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -48,7 +48,6 @@ + #include + + #include +-#include + + #ifdef CONFIG_XEN + #include +@@ -63,20 +62,20 @@ + unsigned long io_apic_irqs; + + #define clear_IO_APIC() ((void)0) +-#endif /* CONFIG_XEN */ +- ++#else + int (*ioapic_renumber_irq)(int ioapic, int irq); + atomic_t irq_mis_count; + +-#ifndef CONFIG_XEN + /* Where if anywhere is the i8259 connect in external int mode */ + static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; +-#endif ++#endif /* CONFIG_XEN */ + + static DEFINE_SPINLOCK(ioapic_lock); + static DEFINE_SPINLOCK(vector_lock); + ++#ifndef CONFIG_XEN + int timer_through_8259 __initdata; ++#endif + + /* + * Is the SiS APIC rmw bug present ? +@@ -105,7 +104,9 @@ int mp_bus_id_to_type[MAX_MP_BUSSES]; + + DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); + ++#ifndef CONFIG_XEN + static int disable_timer_pin_1 __initdata; ++#endif + + /* + * Rough estimation of how many shared IRQs there are, can +@@ -1177,11 +1178,13 @@ static int pin_2_irq(int idx, int apic, + irq += nr_ioapic_registers[i++]; + irq += pin; + ++#ifndef CONFIG_XEN + /* + * For MPS mode, so far only needed by ES7000 platform + */ + if (ioapic_renumber_irq) + irq = ioapic_renumber_irq(apic, irq); ++#endif + } + + /* +@@ -2933,6 +2936,7 @@ int acpi_get_override_irq(int bus_irq, i + + #endif /* CONFIG_ACPI */ + ++#ifndef CONFIG_XEN + static int __init parse_disable_timer_pin_1(char *arg) + { + disable_timer_pin_1 = 1; +@@ -2946,6 +2950,7 @@ static int __init parse_enable_timer_pin + return 0; + } + early_param("enable_timer_pin_1", parse_enable_timer_pin_1); ++#endif + + static int __init parse_noapic(char *arg) + { +--- sle11-2009-06-04.orig/arch/x86/kernel/io_apic_64-xen.c 2009-06-04 10:46:34.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/io_apic_64-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -78,10 +78,6 @@ char system_vectors[NR_VECTORS] = { [0 . + + int sis_apic_bug; /* not actually supported, dummy for compile */ + +-static int no_timer_check; +- +-static int disable_timer_pin_1 __initdata; +- + #ifdef CONFIG_XEN + #include + #include +@@ -96,6 +92,10 @@ unsigned long io_apic_irqs; + + #define clear_IO_APIC() ((void)0) + #else ++static int no_timer_check; ++ ++static int disable_timer_pin_1 __initdata; ++ + int timer_through_8259 __initdata; + + /* Where if anywhere is the i8259 connect in external int mode */ +@@ -487,6 +487,7 @@ static int __init parse_noapic(char *str + } + early_param("noapic", parse_noapic); + ++#ifndef CONFIG_XEN + /* Actually the next is obsolete, but keep it for paranoid reasons -AK */ + static int __init disable_timer_pin_setup(char *arg) + { +@@ -494,6 +495,7 @@ static int __init disable_timer_pin_setu + return 1; + } + __setup("disable_timer_pin_1", disable_timer_pin_setup); ++#endif + + + /* +@@ -1820,10 +1822,6 @@ static inline void __init check_timer(vo + out: + local_irq_restore(flags); + } +-#else +-#define check_timer() ((void)0) +-int timer_uses_ioapic_pin_0 = 0; +-#endif /* !CONFIG_XEN */ + + static int __init notimercheck(char *s) + { +@@ -1831,6 +1829,10 @@ static int __init notimercheck(char *s) + return 1; + } + __setup("no_timer_check", notimercheck); ++#else ++#define check_timer() ((void)0) ++int timer_uses_ioapic_pin_0 = 0; ++#endif /* !CONFIG_XEN */ + + /* + * +--- sle11-2009-06-04.orig/arch/x86/kernel/irq_32-xen.c 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/irq_32-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -252,7 +252,9 @@ unsigned int do_IRQ(struct pt_regs *regs + * Interrupt statistics: + */ + ++#ifndef CONFIG_XEN + atomic_t irq_err_count; ++#endif + + /* + * /proc/interrupts printing: +@@ -308,7 +310,7 @@ skip: + for_each_online_cpu(j) + seq_printf(p, "%10u ", nmi_count(j)); + seq_printf(p, " Non-maskable interrupts\n"); +-#ifdef CONFIG_X86_LOCAL_APIC ++#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_XEN) + seq_printf(p, "LOC: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", +@@ -341,6 +343,7 @@ skip: + per_cpu(irq_stat,j).irq_thermal_count); + seq_printf(p, " Thermal event interrupts\n"); + #endif ++#ifndef CONFIG_XEN + #ifdef CONFIG_X86_LOCAL_APIC + seq_printf(p, "SPU: "); + for_each_online_cpu(j) +@@ -352,6 +355,7 @@ skip: + #if defined(CONFIG_X86_IO_APIC) + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + #endif ++#endif + } + return 0; + } +@@ -384,12 +388,16 @@ u64 arch_irq_stat_cpu(unsigned int cpu) + + u64 arch_irq_stat(void) + { ++#ifndef CONFIG_XEN + u64 sum = atomic_read(&irq_err_count); + + #ifdef CONFIG_X86_IO_APIC + sum += atomic_read(&irq_mis_count); + #endif + return sum; ++#else ++ return 0; ++#endif + } + + #ifdef CONFIG_HOTPLUG_CPU +--- sle11-2009-06-04.orig/arch/x86/kernel/irq_64-xen.c 2009-06-04 10:47:21.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/irq_64-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -18,7 +18,9 @@ + #include + #include + ++#ifndef CONFIG_XEN + atomic_t irq_err_count; ++#endif + + /* + * 'what should we do if we get a hw irq event on an illegal vector'. +@@ -27,19 +29,6 @@ atomic_t irq_err_count; + void ack_bad_irq(unsigned int irq) + { + printk(KERN_WARNING "unexpected IRQ trap at irq %02x\n", irq); +-#ifdef CONFIG_X86_LOCAL_APIC +- /* +- * Currently unexpected vectors happen only on SMP and APIC. +- * We _must_ ack these because every local APIC has only N +- * irq slots per priority level, and a 'hanging, unacked' IRQ +- * holds up an irq slot - in excessive cases (when multiple +- * unexpected vectors occur) that might lock up the APIC +- * completely. +- * But don't ack when the APIC is disabled. -AK +- */ +- if (!disable_apic) +- ack_APIC_irq(); +-#endif + } + + #ifdef CONFIG_DEBUG_STACKOVERFLOW +@@ -119,7 +108,7 @@ skip: + for_each_online_cpu(j) + seq_printf(p, "%10u ", cpu_pda(j)->__nmi_count); + seq_printf(p, " Non-maskable interrupts\n"); +-#ifdef CONFIG_X86_LOCAL_APIC ++#ifndef CONFIG_XEN + seq_printf(p, "LOC: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs); +@@ -151,13 +140,13 @@ skip: + seq_printf(p, "%10u ", cpu_pda(j)->irq_threshold_count); + seq_printf(p, " Threshold APIC interrupts\n"); + #endif +-#ifdef CONFIG_X86_LOCAL_APIC ++#ifndef CONFIG_XEN + seq_printf(p, "SPU: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", cpu_pda(j)->irq_spurious_count); + seq_printf(p, " Spurious interrupts\n"); +-#endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); ++#endif + } + return 0; + } +@@ -187,7 +176,11 @@ u64 arch_irq_stat_cpu(unsigned int cpu) + + u64 arch_irq_stat(void) + { ++#ifndef CONFIG_XEN + return atomic_read(&irq_err_count); ++#else ++ return 0; ++#endif + } + + /* +--- sle11-2009-06-04.orig/arch/x86/kernel/mpparse-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/mpparse-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -31,7 +31,6 @@ + + #include + #ifdef CONFIG_X86_32 +-#include + #include + #endif + +@@ -287,7 +286,9 @@ static int __init smp_check_mpc(struct m + + printk(KERN_INFO "MPTABLE: Product ID: %s\n", str); + ++#ifndef CONFIG_XEN + printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic); ++#endif + + return 1; + } +@@ -315,9 +316,11 @@ static int __init smp_read_mpc(struct mp + } else + mps_oem_check(mpc, oem, str); + #endif ++#ifndef CONFIG_XEN + /* save the local APIC address, it might be non-default */ + if (!acpi_lapic) + mp_lapic_addr = mpc->mpc_lapic; ++#endif + + if (early) + return 1; +@@ -548,10 +551,12 @@ static inline void __init construct_defa + int linttypes[2] = { mp_ExtINT, mp_NMI }; + int i; + ++#ifndef CONFIG_XEN + /* + * local APIC has default address + */ + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; ++#endif + + /* + * 2 CPUs, numbered 0 & 1. +@@ -627,10 +632,12 @@ static void __init __get_smp_config(unsi + */ + if (mpf->mpf_feature1 != 0) { + if (early) { ++#ifndef CONFIG_XEN + /* + * local APIC has default address + */ + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; ++#endif + return; + } + +--- sle11-2009-06-04.orig/arch/x86/kernel/traps_64-xen.c 2009-06-04 10:47:37.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/traps_64-xen.c 2009-06-04 10:47:37.000000000 +0200 +@@ -1174,15 +1174,15 @@ asmlinkage void do_spurious_interrupt_bu + { + } + +-#if 0 ++#ifndef CONFIG_XEN + asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) + { + } +-#endif + + asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) + { + } ++#endif + + /* + * 'math_state_restore()' saves the current math information in the +--- sle11-2009-06-04.orig/drivers/xen/core/smpboot.c 2009-06-04 10:47:28.000000000 +0200 ++++ sle11-2009-06-04/drivers/xen/core/smpboot.c 2009-06-04 10:47:37.000000000 +0200 +@@ -346,7 +346,7 @@ void __init smp_prepare_cpus(unsigned in + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ +- if (!skip_ioapic_setup && nr_ioapics) ++ if (cpu_has_apic && !skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); + #endif + } +--- sle11-2009-06-04.orig/include/asm-x86/apic.h 2009-06-04 10:18:34.000000000 +0200 ++++ sle11-2009-06-04/include/asm-x86/apic.h 2009-06-04 10:47:37.000000000 +0200 +@@ -5,7 +5,9 @@ + #include + + #include ++#ifndef CONFIG_XEN + #include ++#endif + #include + #include + #include +@@ -40,6 +42,7 @@ extern void generic_apic_probe(void); + #ifdef CONFIG_X86_LOCAL_APIC + + extern unsigned int apic_verbosity; ++#ifndef CONFIG_XEN + extern int local_apic_timer_c2_ok; + + extern int ioapic_force; +@@ -149,6 +152,7 @@ static inline void ack_APIC_irq(void) + /* Docs say use 0 for future compatibility */ + apic_write(APIC_EOI, 0); + } ++#endif + + extern int lapic_get_maxlvt(void); + extern void clear_local_APIC(void); +--- sle11-2009-06-04.orig/include/asm-x86/apicdef.h 2009-06-04 10:17:48.000000000 +0200 ++++ sle11-2009-06-04/include/asm-x86/apicdef.h 2009-06-04 10:47:37.000000000 +0200 +@@ -1,6 +1,8 @@ + #ifndef _ASM_X86_APICDEF_H + #define _ASM_X86_APICDEF_H + ++#ifndef CONFIG_XEN ++ + /* + * Constants for various Intel APICs. (local APIC, IOAPIC, etc.) + * +@@ -132,6 +134,16 @@ + #define APIC_BASE_MSR 0x800 + #define X2APIC_ENABLE (1UL << 10) + ++#else /* CONFIG_XEN */ ++ ++enum { ++ APIC_DEST_ALLBUT = 0x1, ++ APIC_DEST_SELF, ++ APIC_DEST_ALLINC ++}; ++ ++#endif /* CONFIG_XEN */ ++ + #ifdef CONFIG_X86_32 + # define MAX_IO_APICS 64 + #else +@@ -139,6 +151,8 @@ + # define MAX_LOCAL_APIC 32768 + #endif + ++#ifndef CONFIG_XEN ++ + /* + * All x86-64 systems are xAPIC compatible. + * In the following, "apicid" is a physical APIC ID. +@@ -409,6 +423,8 @@ struct local_apic { + + #undef u32 + ++#endif /* CONFIG_XEN */ ++ + #ifdef CONFIG_X86_32 + #define BAD_APICID 0xFFu + #else +--- sle11-2009-06-04.orig/include/asm-x86/ipi.h 2009-06-04 10:17:48.000000000 +0200 ++++ sle11-2009-06-04/include/asm-x86/ipi.h 2009-06-04 10:47:37.000000000 +0200 +@@ -1,6 +1,8 @@ + #ifndef __ASM_IPI_H + #define __ASM_IPI_H + ++#ifndef CONFIG_XEN ++ + /* + * Copyright 2004 James Cleverdon, IBM. + * Subject to the GNU Public License, v.2 +@@ -151,4 +153,6 @@ static inline void send_IPI_mask_allbuts + local_irq_restore(flags); + } + ++#endif /* CONFIG_XEN */ ++ + #endif /* __ASM_IPI_H */ +--- sle11-2009-06-04.orig/include/asm-x86/mach-xen/asm/fixmap_32.h 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/include/asm-x86/mach-xen/asm/fixmap_32.h 2009-06-04 10:47:37.000000000 +0200 +@@ -55,10 +55,10 @@ enum fixed_addresses { + FIX_VDSO, + FIX_DBGP_BASE, + FIX_EARLYCON_MEM_BASE, ++#ifndef CONFIG_XEN + #ifdef CONFIG_X86_LOCAL_APIC + FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ + #endif +-#ifndef CONFIG_XEN + #ifdef CONFIG_X86_IO_APIC + FIX_IO_APIC_BASE_0, + FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1, +--- sle11-2009-06-04.orig/include/asm-x86/mach-xen/asm/fixmap_64.h 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-06-04/include/asm-x86/mach-xen/asm/fixmap_64.h 2009-06-04 10:47:37.000000000 +0200 +@@ -13,7 +13,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -41,10 +40,8 @@ enum fixed_addresses { + VSYSCALL_HPET, + FIX_DBGP_BASE, + FIX_EARLYCON_MEM_BASE, +-#ifdef CONFIG_X86_LOCAL_APIC +- FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ +-#endif + #ifndef CONFIG_XEN ++ FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ + FIX_IO_APIC_BASE_0, + FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1, + #endif +--- sle11-2009-06-04.orig/include/asm-x86/mach-xen/asm/smp.h 2009-06-04 10:46:32.000000000 +0200 ++++ sle11-2009-06-04/include/asm-x86/mach-xen/asm/smp.h 2009-06-04 10:47:37.000000000 +0200 +@@ -16,7 +16,7 @@ + # endif + #endif + #include +-#include ++#include + + #define cpu_callout_map cpu_possible_map + extern cpumask_t cpu_initialized; +@@ -178,7 +178,7 @@ DECLARE_PER_CPU(int, cpu_number); + #define stack_smp_processor_id() 0 + #endif + +-#ifdef CONFIG_X86_LOCAL_APIC ++#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_XEN) + + static inline int logical_smp_processor_id(void) + { +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-04/include/asm-x86/mach-xen/mach_apic.h 2009-06-04 10:47:37.000000000 +0200 +@@ -0,0 +1,54 @@ ++#ifndef __ASM_MACH_APIC_H ++#define __ASM_MACH_APIC_H ++ ++#include ++ ++#ifdef CONFIG_X86_64 ++ ++#include ++#define INT_DELIVERY_MODE (genapic->int_delivery_mode) ++#define INT_DEST_MODE (genapic->int_dest_mode) ++#define TARGET_CPUS (genapic->target_cpus()) ++#define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) ++#define phys_pkg_id (genapic->phys_pkg_id) ++#define send_IPI_self (genapic->send_IPI_self) ++extern void setup_apic_routing(void); ++ ++#else ++ ++#ifdef CONFIG_SMP ++#define TARGET_CPUS cpu_online_map ++#else ++#define TARGET_CPUS cpumask_of_cpu(0) ++#endif ++ ++#define INT_DELIVERY_MODE dest_LowestPrio ++#define INT_DEST_MODE 1 ++ ++static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) ++{ ++ return cpuid_apic; ++} ++ ++static inline void setup_apic_routing(void) ++{ ++} ++ ++static inline int multi_timer_check(int apic, int irq) ++{ ++ return 0; ++} ++ ++static inline int apicid_to_node(int logical_apicid) ++{ ++ return 0; ++} ++ ++static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ++{ ++ return cpus_addr(cpumask)[0]; ++} ++ ++#endif /* CONFIG_X86_64 */ ++ ++#endif /* __ASM_MACH_APIC_H */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-no-lazy-tlb b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-no-lazy-tlb new file mode 100644 index 000000000..03c655b81 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-no-lazy-tlb @@ -0,0 +1,57 @@ +From: jbeulich@novell.com +Subject: ensure inadvertent uses of lazy TLB data are caught during the build +Patch-mainline: obsolete + +Index: head-2008-11-17/arch/x86/kernel/cpu/common_64-xen.c +=================================================================== +--- head-2008-11-17.orig/arch/x86/kernel/cpu/common_64-xen.c 2008-11-17 14:06:21.000000000 +0100 ++++ head-2008-11-17/arch/x86/kernel/cpu/common_64-xen.c 2008-11-17 14:07:10.000000000 +0100 +@@ -557,8 +557,10 @@ void pda_init(int cpu) + pda->irqcount = -1; + pda->kernelstack = (unsigned long)stack_thread_info() - + PDA_STACKOFFSET + THREAD_SIZE; ++#ifndef CONFIG_XEN + pda->active_mm = &init_mm; + pda->mmu_state = 0; ++#endif + + if (cpu == 0) { + /* others are initialized in smpboot.c */ +Index: head-2008-11-17/include/asm-x86/mach-xen/asm/tlbflush.h +=================================================================== +--- head-2008-11-17.orig/include/asm-x86/mach-xen/asm/tlbflush.h 2008-11-17 13:41:59.000000000 +0100 ++++ head-2008-11-17/include/asm-x86/mach-xen/asm/tlbflush.h 2008-11-17 14:07:10.000000000 +0100 +@@ -82,6 +82,7 @@ static inline void flush_tlb_range(struc + flush_tlb_mm(vma->vm_mm); + } + ++#ifndef CONFIG_XEN + #define TLBSTATE_OK 1 + #define TLBSTATE_LAZY 2 + +@@ -93,6 +94,7 @@ struct tlb_state { + }; + DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate); + #endif ++#endif + + #endif /* SMP */ + +Index: head-2008-11-17/include/asm-x86/pda.h +=================================================================== +--- head-2008-11-17.orig/include/asm-x86/pda.h 2008-11-17 13:15:55.000000000 +0100 ++++ head-2008-11-17/include/asm-x86/pda.h 2008-11-17 14:07:10.000000000 +0100 +@@ -26,9 +26,13 @@ struct x8664_pda { + short in_bootmem; /* pda lives in bootmem */ + unsigned int __softirq_pending; + unsigned int __nmi_count; /* number of NMI on this CPUs */ ++#ifndef CONFIG_XEN + short mmu_state; + short isidle; + struct mm_struct *active_mm; ++#else ++ short isidle; ++#endif + unsigned apic_timer_irqs; + unsigned irq0_irqs; + unsigned irq_resched_count; diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-panic-no-reboot b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-panic-no-reboot new file mode 100644 index 000000000..2d44e96fd --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-panic-no-reboot @@ -0,0 +1,32 @@ +From: jbeulich@novell.com +Subject: Don't automatically reboot Dom0 on panic (match native) +Patch-mainline: obsolete + +$subject says it all. + +--- sle11-2009-07-31.orig/arch/x86/kernel/setup-xen.c 2009-07-31 15:13:24.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/kernel/setup-xen.c 2009-07-31 15:14:20.000000000 +0200 +@@ -699,15 +699,16 @@ void __init setup_arch(char **cmdline_p) + unsigned long p2m_pages; + struct physdev_set_iopl set_iopl; + ++ if (!is_initial_xendomain()) { + #ifdef CONFIG_X86_32 +- /* Force a quick death if the kernel panics (not domain 0). */ +- extern int panic_timeout; +- if (!panic_timeout && !is_initial_xendomain()) +- panic_timeout = 1; ++ /* Force a quick death if the kernel panics (not domain 0). */ ++ extern int panic_timeout; ++ if (!panic_timeout) ++ panic_timeout = 1; + #endif +- +- /* Register a call for panic conditions. */ +- atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); ++ /* Register a call for panic conditions. */ ++ atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); ++ } + + WARN_ON(HYPERVISOR_vm_assist(VMASST_CMD_enable, + VMASST_TYPE_writable_pagetables)); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86-pmd-handling b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-pmd-handling new file mode 100644 index 000000000..a35f1d58a --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86-pmd-handling @@ -0,0 +1,598 @@ +From: jbeulich@novell.com +Subject: consolidate pmd/pud/pgd entry handling +Patch-mainline: obsolete + +--- sle11-2009-04-09.orig/arch/x86/mm/hypervisor.c 2009-03-30 12:18:24.000000000 +0200 ++++ sle11-2009-04-09/arch/x86/mm/hypervisor.c 2009-03-16 16:40:37.000000000 +0100 +@@ -357,31 +357,91 @@ void xen_l1_entry_update(pte_t *ptr, pte + } + EXPORT_SYMBOL_GPL(xen_l1_entry_update); + ++static void do_lN_entry_update(mmu_update_t *mmu, unsigned int mmu_count, ++ struct page *page) ++{ ++ if (likely(page)) { ++ multicall_entry_t mcl[2]; ++ unsigned long pfn = page_to_pfn(page); ++ ++ MULTI_update_va_mapping(mcl, ++ (unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte(pfn, PAGE_KERNEL_RO), 0); ++ SetPagePinned(page); ++ MULTI_mmu_update(mcl + 1, mmu, mmu_count, NULL, DOMID_SELF); ++ if (unlikely(HYPERVISOR_multicall_check(mcl, 2, NULL))) ++ BUG(); ++ } else if (unlikely(HYPERVISOR_mmu_update(mmu, mmu_count, ++ NULL, DOMID_SELF) < 0)) ++ BUG(); ++} ++ + void xen_l2_entry_update(pmd_t *ptr, pmd_t val) + { + mmu_update_t u; ++ struct page *page = NULL; ++ ++ if (likely(pmd_present(val)) && likely(!pmd_large(val)) ++ && likely(mem_map) ++ && likely(PagePinned(virt_to_page(ptr)))) { ++ page = pmd_page(val); ++ if (unlikely(PagePinned(page))) ++ page = NULL; ++ else if (PageHighMem(page)) { ++#ifdef CONFIG_HIGHPTE ++ BUG(); ++#endif ++ kmap_flush_unused(); ++ page = NULL; ++ } ++ } + u.ptr = virt_to_machine(ptr); + u.val = __pmd_val(val); +- BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++ do_lN_entry_update(&u, 1, page); + } + + #if defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) + void xen_l3_entry_update(pud_t *ptr, pud_t val) + { + mmu_update_t u; ++ struct page *page = NULL; ++ ++ if (likely(pud_present(val)) ++#ifdef CONFIG_X86_64 ++ && likely(!pud_large(val)) ++#endif ++ && likely(mem_map) ++ && likely(PagePinned(virt_to_page(ptr)))) { ++ page = pud_page(val); ++ if (unlikely(PagePinned(page))) ++ page = NULL; ++ } + u.ptr = virt_to_machine(ptr); + u.val = __pud_val(val); +- BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++ do_lN_entry_update(&u, 1, page); + } + #endif + + #ifdef CONFIG_X86_64 +-void xen_l4_entry_update(pgd_t *ptr, pgd_t val) ++void xen_l4_entry_update(pgd_t *ptr, int user, pgd_t val) + { +- mmu_update_t u; +- u.ptr = virt_to_machine(ptr); +- u.val = __pgd_val(val); +- BUG_ON(HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF) < 0); ++ mmu_update_t u[2]; ++ struct page *page = NULL; ++ ++ if (likely(pgd_present(val)) && likely(mem_map) ++ && likely(PagePinned(virt_to_page(ptr)))) { ++ page = pgd_page(val); ++ if (unlikely(PagePinned(page))) ++ page = NULL; ++ } ++ u[0].ptr = virt_to_machine(ptr); ++ u[0].val = __pgd_val(val); ++ if (user) { ++ u[1].ptr = virt_to_machine(__user_pgd(ptr)); ++ u[1].val = __pgd_val(val); ++ do_lN_entry_update(u, 2, page); ++ } else ++ do_lN_entry_update(u, 1, page); + } + #endif /* CONFIG_X86_64 */ + +--- sle11-2009-04-09.orig/arch/x86/mm/init_32-xen.c 2009-02-17 18:06:20.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/mm/init_32-xen.c 2009-03-16 17:39:12.000000000 +0100 +@@ -728,6 +728,8 @@ static void __init zone_sizes_init(void) + #endif + + free_area_init_nodes(max_zone_pfns); ++ ++ xen_init_pgd_pin(); + } + + void __init setup_bootmem_allocator(void) +@@ -1089,8 +1091,6 @@ void __init mem_init(void) + cpa_init(); + save_pg_dir(); + zap_low_mappings(); +- +- SetPagePinned(virt_to_page(init_mm.pgd)); + } + + #ifdef CONFIG_MEMORY_HOTPLUG +--- sle11-2009-04-09.orig/arch/x86/mm/init_64-xen.c 2009-03-16 16:39:50.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:37.000000000 +0100 +@@ -195,7 +195,10 @@ set_pte_vaddr_pud(pud_t *pud_page, unsig + if (pud_none(*pud)) { + pmd = (pmd_t *) spp_getpage(); + make_page_readonly(pmd, XENFEAT_writable_page_tables); +- pud_populate(&init_mm, pud, pmd); ++ if (!after_bootmem) ++ xen_l3_entry_update(pud, __pud(__pa(pmd) | _PAGE_TABLE)); ++ else ++ pud_populate(&init_mm, pud, pmd); + if (pmd != pmd_offset(pud, 0)) { + printk(KERN_ERR "PAGETABLE BUG #01! %p <-> %p\n", + pmd, pmd_offset(pud, 0)); +@@ -478,7 +481,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned + XENFEAT_writable_page_tables); + *pmd = __pmd(pte_phys | _PAGE_TABLE); + } else { +- make_page_readonly(pte, XENFEAT_writable_page_tables); + spin_lock(&init_mm.page_table_lock); + pmd_populate_kernel(&init_mm, pmd, __va(pte_phys)); + spin_unlock(&init_mm.page_table_lock); +@@ -547,7 +549,6 @@ phys_pud_init(pud_t *pud_page, unsigned + else + *pud = __pud(pmd_phys | _PAGE_TABLE); + } else { +- make_page_readonly(pmd, XENFEAT_writable_page_tables); + spin_lock(&init_mm.page_table_lock); + pud_populate(&init_mm, pud, __va(pmd_phys)); + spin_unlock(&init_mm.page_table_lock); +@@ -775,7 +776,6 @@ static unsigned long __meminit kernel_ph + XENFEAT_writable_page_tables); + xen_l4_entry_update(pgd, __pgd(pud_phys | _PAGE_TABLE)); + } else { +- make_page_readonly(pud, XENFEAT_writable_page_tables); + spin_lock(&init_mm.page_table_lock); + pgd_populate(&init_mm, pgd, __va(pud_phys)); + spin_unlock(&init_mm.page_table_lock); +@@ -1004,7 +1004,7 @@ void __init paging_init(void) + sparse_init(); + free_area_init_nodes(max_zone_pfns); + +- SetPagePinned(virt_to_page(init_mm.pgd)); ++ xen_init_pgd_pin(); + } + #endif + +--- sle11-2009-04-09.orig/arch/x86/mm/pgtable-xen.c 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/mm/pgtable-xen.c 2009-04-09 14:54:03.000000000 +0200 +@@ -42,16 +42,16 @@ pgtable_t pte_alloc_one(struct mm_struct + void __pte_free(pgtable_t pte) + { + if (!PageHighMem(pte)) { +- unsigned long va = (unsigned long)page_address(pte); +- unsigned int level; +- pte_t *ptep = lookup_address(va, &level); +- +- BUG_ON(!ptep || level != PG_LEVEL_4K || !pte_present(*ptep)); +- if (!pte_write(*ptep) +- && HYPERVISOR_update_va_mapping(va, +- mk_pte(pte, PAGE_KERNEL), +- 0)) +- BUG(); ++ if (PagePinned(pte)) { ++ unsigned long pfn = page_to_pfn(pte); ++ ++ if (HYPERVISOR_update_va_mapping((unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte(pfn, ++ PAGE_KERNEL), ++ 0)) ++ BUG(); ++ ClearPagePinned(pte); ++ } + } else + #ifdef CONFIG_HIGHPTE + ClearPagePinned(pte); +@@ -93,14 +93,15 @@ pmd_t *pmd_alloc_one(struct mm_struct *m + + void __pmd_free(pgtable_t pmd) + { +- unsigned long va = (unsigned long)page_address(pmd); +- unsigned int level; +- pte_t *ptep = lookup_address(va, &level); +- +- BUG_ON(!ptep || level != PG_LEVEL_4K || !pte_present(*ptep)); +- if (!pte_write(*ptep) +- && HYPERVISOR_update_va_mapping(va, mk_pte(pmd, PAGE_KERNEL), 0)) +- BUG(); ++ if (PagePinned(pmd)) { ++ unsigned long pfn = page_to_pfn(pmd); ++ ++ if (HYPERVISOR_update_va_mapping((unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte(pfn, PAGE_KERNEL), ++ 0)) ++ BUG(); ++ ClearPagePinned(pmd); ++ } + + ClearPageForeign(pmd); + init_page_count(pmd); +@@ -192,21 +193,20 @@ static inline unsigned int pgd_walk_set_ + { + unsigned long pfn = page_to_pfn(page); + +- if (PageHighMem(page)) { +- if (pgprot_val(flags) & _PAGE_RW) +- ClearPagePinned(page); +- else +- SetPagePinned(page); +- } else { +- MULTI_update_va_mapping(per_cpu(pb_mcl, cpu) + seq, +- (unsigned long)__va(pfn << PAGE_SHIFT), +- pfn_pte(pfn, flags), 0); +- if (unlikely(++seq == PIN_BATCH)) { +- if (unlikely(HYPERVISOR_multicall_check(per_cpu(pb_mcl, cpu), +- PIN_BATCH, NULL))) +- BUG(); +- seq = 0; +- } ++ if (pgprot_val(flags) & _PAGE_RW) ++ ClearPagePinned(page); ++ else ++ SetPagePinned(page); ++ if (PageHighMem(page)) ++ return seq; ++ MULTI_update_va_mapping(per_cpu(pb_mcl, cpu) + seq, ++ (unsigned long)__va(pfn << PAGE_SHIFT), ++ pfn_pte(pfn, flags), 0); ++ if (unlikely(++seq == PIN_BATCH)) { ++ if (unlikely(HYPERVISOR_multicall_check(per_cpu(pb_mcl, cpu), ++ PIN_BATCH, NULL))) ++ BUG(); ++ seq = 0; + } + + return seq; +@@ -253,6 +253,16 @@ static void pgd_walk(pgd_t *pgd_base, pg + } + } + ++#ifdef CONFIG_X86_PAE ++ for (; g < PTRS_PER_PGD; g++, pgd++) { ++ BUG_ON(pgd_none(*pgd)); ++ pud = pud_offset(pgd, 0); ++ BUG_ON(pud_none(*pud)); ++ pmd = pmd_offset(pud, 0); ++ seq = pgd_walk_set_prot(virt_to_page(pmd),flags,cpu,seq); ++ } ++#endif ++ + mcl = per_cpu(pb_mcl, cpu); + #ifdef CONFIG_X86_64 + if (unlikely(seq > PIN_BATCH - 2)) { +@@ -288,6 +298,51 @@ static void pgd_walk(pgd_t *pgd_base, pg + put_cpu(); + } + ++void __init xen_init_pgd_pin(void) ++{ ++ pgd_t *pgd = init_mm.pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ unsigned int g, u, m; ++ ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ return; ++ ++ SetPagePinned(virt_to_page(pgd)); ++ for (g = 0; g < PTRS_PER_PGD; g++, pgd++) { ++#ifndef CONFIG_X86_PAE ++ if (g >= pgd_index(HYPERVISOR_VIRT_START) ++ && g <= pgd_index(HYPERVISOR_VIRT_END - 1)) ++ continue; ++#endif ++ if (!pgd_present(*pgd)) ++ continue; ++ pud = pud_offset(pgd, 0); ++ if (PTRS_PER_PUD > 1) /* not folded */ ++ SetPagePinned(virt_to_page(pud)); ++ for (u = 0; u < PTRS_PER_PUD; u++, pud++) { ++ if (!pud_present(*pud)) ++ continue; ++ pmd = pmd_offset(pud, 0); ++ if (PTRS_PER_PMD > 1) /* not folded */ ++ SetPagePinned(virt_to_page(pmd)); ++ for (m = 0; m < PTRS_PER_PMD; m++, pmd++) { ++#ifdef CONFIG_X86_PAE ++ if (g == pgd_index(HYPERVISOR_VIRT_START) ++ && m >= pmd_index(HYPERVISOR_VIRT_START)) ++ continue; ++#endif ++ if (!pmd_present(*pmd)) ++ continue; ++ SetPagePinned(pmd_page(*pmd)); ++ } ++ } ++ } ++#ifdef CONFIG_X86_64 ++ SetPagePinned(virt_to_page(level3_user_pgt)); ++#endif ++} ++ + static void __pgd_pin(pgd_t *pgd) + { + pgd_walk(pgd, PAGE_KERNEL_RO); +@@ -480,21 +535,18 @@ static void pgd_dtor(void *pgd) + + void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd) + { +- struct page *page = virt_to_page(pmd); +- unsigned long pfn = page_to_pfn(page); +- +- paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); +- + /* Note: almost everything apart from _PAGE_PRESENT is + reserved at the pmd (PDPT) level. */ +- if (PagePinned(virt_to_page(mm->pgd))) { +- BUG_ON(PageHighMem(page)); +- BUG_ON(HYPERVISOR_update_va_mapping( +- (unsigned long)__va(pfn << PAGE_SHIFT), +- pfn_pte(pfn, PAGE_KERNEL_RO), 0)); +- set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT)); +- } else +- *pudp = __pud(__pa(pmd) | _PAGE_PRESENT); ++ pud_t pud = __pud(__pa(pmd) | _PAGE_PRESENT); ++ ++ paravirt_alloc_pmd(mm, page_to_pfn(virt_to_page(pmd))); ++ ++ if (likely(!PagePinned(virt_to_page(pudp)))) { ++ *pudp = pud; ++ return; ++ } ++ ++ set_pud(pudp, pud); + + /* + * According to Intel App note "TLBs, Paging-Structure Caches, +@@ -589,13 +641,10 @@ static void pgd_prepopulate_pmd(struct m + i++, pud++, addr += PUD_SIZE) { + pmd_t *pmd = pmds[i]; + +- if (i >= KERNEL_PGD_BOUNDARY) { ++ if (i >= KERNEL_PGD_BOUNDARY) + memcpy(pmd, + (pmd_t *)pgd_page_vaddr(swapper_pg_dir[i]), + sizeof(pmd_t) * PTRS_PER_PMD); +- make_lowmem_page_readonly( +- pmd, XENFEAT_writable_page_tables); +- } + + /* It is safe to poke machine addresses of pmds under the pgd_lock. */ + pud_populate(mm, pud, pmd); +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-12 16:43:54.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:40:37.000000000 +0100 +@@ -94,10 +94,12 @@ void xen_invlpg(unsigned long ptr); + void xen_l1_entry_update(pte_t *ptr, pte_t val); + void xen_l2_entry_update(pmd_t *ptr, pmd_t val); + void xen_l3_entry_update(pud_t *ptr, pud_t val); /* x86_64/PAE */ +-void xen_l4_entry_update(pgd_t *ptr, pgd_t val); /* x86_64 only */ ++void xen_l4_entry_update(pgd_t *ptr, int user, pgd_t val); /* x86_64 only */ + void xen_pgd_pin(unsigned long ptr); + void xen_pgd_unpin(unsigned long ptr); + ++void xen_init_pgd_pin(void); ++ + void xen_set_ldt(const void *ptr, unsigned int ents); + + #ifdef CONFIG_SMP +@@ -331,6 +333,18 @@ MULTI_update_va_mapping( + } + + static inline void ++MULTI_mmu_update(multicall_entry_t *mcl, mmu_update_t *req, ++ unsigned int count, unsigned int *success_count, ++ domid_t domid) ++{ ++ mcl->op = __HYPERVISOR_mmu_update; ++ mcl->args[0] = (unsigned long)req; ++ mcl->args[1] = count; ++ mcl->args[2] = (unsigned long)success_count; ++ mcl->args[3] = domid; ++} ++ ++static inline void + MULTI_grant_table_op(multicall_entry_t *mcl, unsigned int cmd, + void *uop, unsigned int count) + { +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/pgalloc.h 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/pgalloc.h 2009-03-16 16:40:37.000000000 +0100 +@@ -64,20 +64,16 @@ static inline void pmd_populate(struct m + struct page *pte) + { + unsigned long pfn = page_to_pfn(pte); ++ pmd_t ent = __pmd(((pmdval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE); + + paravirt_alloc_pte(mm, pfn); +- if (PagePinned(virt_to_page(mm->pgd))) { +- if (!PageHighMem(pte)) +- BUG_ON(HYPERVISOR_update_va_mapping( +- (unsigned long)__va(pfn << PAGE_SHIFT), +- pfn_pte(pfn, PAGE_KERNEL_RO), 0)); +-#ifndef CONFIG_X86_64 +- else if (!TestSetPagePinned(pte)) +- kmap_flush_unused(); ++ if (PagePinned(virt_to_page(pmd))) { ++#ifndef CONFIG_HIGHPTE ++ BUG_ON(PageHighMem(pte)); + #endif +- set_pmd(pmd, __pmd(((pmdval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE)); ++ set_pmd(pmd, ent); + } else +- *pmd = __pmd(((pmdval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE); ++ *pmd = ent; + } + + #define pmd_pgtable(pmd) pmd_page(pmd) +@@ -99,39 +95,28 @@ extern void pud_populate(struct mm_struc + #else /* !CONFIG_X86_PAE */ + static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) + { ++ pud_t ent = __pud(_PAGE_TABLE | __pa(pmd)); ++ + paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); +- if (unlikely(PagePinned(virt_to_page((mm)->pgd)))) { +- BUG_ON(HYPERVISOR_update_va_mapping( +- (unsigned long)pmd, +- pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, +- PAGE_KERNEL_RO), 0)); +- set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))); +- } else +- *pud = __pud(_PAGE_TABLE | __pa(pmd)); ++ if (PagePinned(virt_to_page(pud))) ++ set_pud(pud, ent); ++ else ++ *pud = ent; + } + #endif /* CONFIG_X86_PAE */ + + #if PAGETABLE_LEVELS > 3 + #define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD) + +-/* +- * We need to use the batch mode here, but pgd_pupulate() won't be +- * be called frequently. +- */ + static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) + { ++ pgd_t ent = __pgd(_PAGE_TABLE | __pa(pud)); ++ + paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT); +- if (unlikely(PagePinned(virt_to_page((mm)->pgd)))) { +- BUG_ON(HYPERVISOR_update_va_mapping( +- (unsigned long)pud, +- pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, +- PAGE_KERNEL_RO), 0)); +- set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))); +- set_pgd(__user_pgd(pgd), __pgd(_PAGE_TABLE | __pa(pud))); +- } else { +- *(pgd) = __pgd(_PAGE_TABLE | __pa(pud)); +- *__user_pgd(pgd) = *(pgd); +- } ++ if (unlikely(PagePinned(virt_to_page(pgd)))) ++ xen_l4_entry_update(pgd, 1, ent); ++ else ++ *__user_pgd(pgd) = *pgd = ent; + } + + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/pgtable-3level.h 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/pgtable-3level.h 2009-03-16 16:40:37.000000000 +0100 +@@ -76,12 +76,15 @@ static inline void __xen_pte_clear(pte_t + ptep->pte_high = 0; + } + +-static inline void xen_pmd_clear(pmd_t *pmd) +-{ +- xen_l2_entry_update(pmd, __pmd(0)); +-} ++#define xen_pmd_clear(pmd) \ ++({ \ ++ pmd_t *__pmdp = (pmd); \ ++ PagePinned(virt_to_page(__pmdp)) \ ++ ? set_pmd(__pmdp, __pmd(0)) \ ++ : (void)(*__pmdp = __pmd(0)); \ ++}) + +-static inline void pud_clear(pud_t *pudp) ++static inline void __xen_pud_clear(pud_t *pudp) + { + pgdval_t pgd; + +@@ -102,13 +105,21 @@ static inline void pud_clear(pud_t *pudp + xen_tlb_flush(); + } + +-#define pud_page(pud) ((struct page *) __va(pud_val(pud) & PTE_PFN_MASK)) ++#define xen_pud_clear(pudp) \ ++({ \ ++ pud_t *__pudp = (pudp); \ ++ PagePinned(virt_to_page(__pudp)) \ ++ ? __xen_pud_clear(__pudp) \ ++ : (void)(*__pudp = __pud(0)); \ ++}) ++ ++#define pud_page(pud) pfn_to_page(pud_val(pud) >> PAGE_SHIFT) + + #define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PTE_PFN_MASK)) + + + /* Find an entry in the second-level page table.. */ +-#define pmd_offset(pud, address) ((pmd_t *)pud_page(*(pud)) + \ ++#define pmd_offset(pud, address) ((pmd_t *)pud_page_vaddr(*(pud)) + \ + pmd_index(address)) + + #ifdef CONFIG_SMP +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-16 16:40:37.000000000 +0100 +@@ -110,33 +110,41 @@ static inline void xen_set_pmd(pmd_t *pm + xen_l2_entry_update(pmdp, pmd); + } + +-static inline void xen_pmd_clear(pmd_t *pmd) +-{ +- xen_set_pmd(pmd, xen_make_pmd(0)); +-} ++#define xen_pmd_clear(pmd) \ ++({ \ ++ pmd_t *__pmdp = (pmd); \ ++ PagePinned(virt_to_page(__pmdp)) \ ++ ? set_pmd(__pmdp, xen_make_pmd(0)) \ ++ : (void)(*__pmdp = xen_make_pmd(0)); \ ++}) + + static inline void xen_set_pud(pud_t *pudp, pud_t pud) + { + xen_l3_entry_update(pudp, pud); + } + +-static inline void xen_pud_clear(pud_t *pud) +-{ +- xen_set_pud(pud, xen_make_pud(0)); +-} ++#define xen_pud_clear(pud) \ ++({ \ ++ pud_t *__pudp = (pud); \ ++ PagePinned(virt_to_page(__pudp)) \ ++ ? set_pud(__pudp, xen_make_pud(0)) \ ++ : (void)(*__pudp = xen_make_pud(0)); \ ++}) + + #define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD) + + static inline void xen_set_pgd(pgd_t *pgdp, pgd_t pgd) + { +- xen_l4_entry_update(pgdp, pgd); ++ xen_l4_entry_update(pgdp, 0, pgd); + } + +-static inline void xen_pgd_clear(pgd_t *pgd) +-{ +- xen_set_pgd(pgd, xen_make_pgd(0)); +- xen_set_pgd(__user_pgd(pgd), xen_make_pgd(0)); +-} ++#define xen_pgd_clear(pgd) \ ++({ \ ++ pgd_t *__pgdp = (pgd); \ ++ PagePinned(virt_to_page(__pgdp)) \ ++ ? xen_l4_entry_update(__pgdp, 1, xen_make_pgd(0)) \ ++ : (void)(*__user_pgd(__pgdp) = *__pgdp = xen_make_pgd(0)); \ ++}) + + #define pte_same(a, b) ((a).pte == (b).pte) + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-dump-user-pgt b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-dump-user-pgt new file mode 100644 index 000000000..5956139b2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-dump-user-pgt @@ -0,0 +1,48 @@ +From: jbeulich@novell.com +Subject: dump the correct page tables for user mode faults +Patch-mainline: obsolete + +Index: head-2008-11-10/arch/x86/mm/fault-xen.c +=================================================================== +--- head-2008-11-10.orig/arch/x86/mm/fault-xen.c 2008-11-17 11:33:51.000000000 +0100 ++++ head-2008-11-10/arch/x86/mm/fault-xen.c 2008-11-17 11:38:21.000000000 +0100 +@@ -189,9 +189,11 @@ static int bad_address(void *p) + unsigned long dummy; + return probe_kernel_address((unsigned long *)p, dummy); + } ++#else ++#define dump_pagetable(addr, krnl) dump_pagetable(addr) + #endif + +-static void dump_pagetable(unsigned long address) ++static void dump_pagetable(unsigned long address, bool kernel) + { + #ifdef CONFIG_X86_32 + __typeof__(pte_val(__pte(0))) page; +@@ -239,6 +241,8 @@ static void dump_pagetable(unsigned long + pgd = (pgd_t *)read_cr3(); + + pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); ++ if (!kernel) ++ pgd = __user_pgd(pgd); + pgd += pgd_index(address); + if (bad_address(pgd)) goto bad; + printk("PGD %lx ", pgd_val(*pgd)); +@@ -419,7 +423,7 @@ static void show_fault_oops(struct pt_re + printk(KERN_CONT " at %p\n", (void *) address); + printk(KERN_ALERT "IP:"); + printk_address(regs->ip, 1); +- dump_pagetable(address); ++ dump_pagetable(address, !(error_code & PF_USER)); + } + + #ifdef CONFIG_X86_64 +@@ -431,7 +435,7 @@ static noinline void pgtable_bad(unsigne + + printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", + current->comm, address); +- dump_pagetable(address); ++ dump_pagetable(address, !(error_code & PF_USER)); + tsk = current; + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-note-init-p2m b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-note-init-p2m new file mode 100644 index 000000000..a1bac3467 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-note-init-p2m @@ -0,0 +1,384 @@ +From: jbeulich@novell.com +Subject: eliminate scalability issues from initial mapping setup +Patch-mainline: obsolete +References: bnc#417417 + +Direct Xen to place the initial P->M table outside of the initial +mapping, as otherwise the 1G (implementation) / 2G (theoretical) +restriction on the size of the initial mapping limits the amount +of memory a domain can be handed initially. + +Note that the flags passed to HYPERVISOR_update_va_mapping() from +__make_page_writable() and make_lowmem_page_writable() are +intentionally not including UVMF_ALL. This is intended to be on optimal +choice between the overhead of a potential spurious page fault (as +remote CPUs may still have read-only translations in their TLBs) and +the overhead of cross processor flushes. Flushing on the local CPU +shouldn't be as expensive (and hence can be viewed as an optimization +avoiding the spurious page fault on the local CPU), but is required +when the functions are used before the page fault handler gets set up. + +--- sle11-2009-07-31.orig/arch/x86/kernel/head64-xen.c 2009-02-16 16:49:32.000000000 +0100 ++++ sle11-2009-07-31/arch/x86/kernel/head64-xen.c 2009-03-16 16:40:54.000000000 +0100 +@@ -171,6 +171,14 @@ void __init x86_64_start_reservations(ch + + (xen_start_info->nr_pt_frames << PAGE_SHIFT), + "Xen provided"); + ++ if (xen_feature(XENFEAT_auto_translated_physmap)) ++ xen_start_info->mfn_list = ~0UL; ++ else if (xen_start_info->mfn_list < __START_KERNEL_map) ++ reserve_early(xen_start_info->first_p2m_pfn << PAGE_SHIFT, ++ (xen_start_info->first_p2m_pfn ++ + xen_start_info->nr_p2m_frames) << PAGE_SHIFT, ++ "INITP2M"); ++ + /* + * At this point everything still needed from the boot loader + * or BIOS or kernel text should be early reserved or marked not +--- sle11-2009-07-31.orig/arch/x86/kernel/head_64-xen.S 2009-03-16 16:40:52.000000000 +0100 ++++ sle11-2009-07-31/arch/x86/kernel/head_64-xen.S 2009-03-16 16:40:54.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -135,6 +136,7 @@ ENTRY(empty_zero_page) + ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .quad startup_64) + ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .quad hypercall_page) + ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad _PAGE_PRESENT, _PAGE_PRESENT) ++ ELFNOTE(Xen, XEN_ELFNOTE_INIT_P2M, .quad VMEMMAP_START) + ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") + ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") + ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1) +--- sle11-2009-07-31.orig/arch/x86/kernel/setup-xen.c 2009-07-31 15:14:31.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/kernel/setup-xen.c 2009-07-31 15:14:44.000000000 +0200 +@@ -1021,7 +1021,7 @@ void __init setup_arch(char **cmdline_p) + difference = xen_start_info->nr_pages - max_pfn; + + set_xen_guest_handle(reservation.extent_start, +- ((unsigned long *)xen_start_info->mfn_list) + max_pfn); ++ phys_to_machine_mapping + max_pfn); + reservation.nr_extents = difference; + ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &reservation); +@@ -1038,14 +1038,86 @@ void __init setup_arch(char **cmdline_p) + phys_to_machine_mapping = alloc_bootmem_pages( + max_pfn * sizeof(unsigned long)); + memcpy(phys_to_machine_mapping, +- (unsigned long *)xen_start_info->mfn_list, ++ __va(__pa(xen_start_info->mfn_list)), + p2m_pages * sizeof(unsigned long)); + memset(phys_to_machine_mapping + p2m_pages, ~0, + (max_pfn - p2m_pages) * sizeof(unsigned long)); +- free_bootmem( +- __pa(xen_start_info->mfn_list), +- PFN_PHYS(PFN_UP(xen_start_info->nr_pages * +- sizeof(unsigned long)))); ++ ++#ifdef CONFIG_X86_64 ++ if (xen_start_info->mfn_list == VMEMMAP_START) { ++ /* ++ * Since it is well isolated we can (and since it is ++ * perhaps large we should) also free the page tables ++ * mapping the initial P->M table. ++ */ ++ unsigned long va = VMEMMAP_START, pa; ++ pgd_t *pgd = pgd_offset_k(va); ++ pud_t *pud_page = pud_offset(pgd, 0); ++ ++ BUILD_BUG_ON(VMEMMAP_START & ~PGDIR_MASK); ++ xen_l4_entry_update(pgd, __pgd(0)); ++ for(;;) { ++ pud_t *pud = pud_page + pud_index(va); ++ ++ if (pud_none(*pud)) ++ va += PUD_SIZE; ++ else if (pud_large(*pud)) { ++ pa = pud_val(*pud) & PHYSICAL_PAGE_MASK; ++ make_pages_writable(__va(pa), ++ PUD_SIZE >> PAGE_SHIFT, ++ XENFEAT_writable_page_tables); ++ free_bootmem(pa, PUD_SIZE); ++ va += PUD_SIZE; ++ } else { ++ pmd_t *pmd = pmd_offset(pud, va); ++ ++ if (pmd_large(*pmd)) { ++ pa = pmd_val(*pmd) & PHYSICAL_PAGE_MASK; ++ make_pages_writable(__va(pa), ++ PMD_SIZE >> PAGE_SHIFT, ++ XENFEAT_writable_page_tables); ++ free_bootmem(pa, PMD_SIZE); ++ } else if (!pmd_none(*pmd)) { ++ pte_t *pte = pte_offset_kernel(pmd, va); ++ ++ for (i = 0; i < PTRS_PER_PTE; ++i) { ++ if (pte_none(pte[i])) ++ break; ++ pa = pte_pfn(pte[i]) << PAGE_SHIFT; ++ make_page_writable(__va(pa), ++ XENFEAT_writable_page_tables); ++ free_bootmem(pa, PAGE_SIZE); ++ } ++ ClearPagePinned(virt_to_page(pte)); ++ make_page_writable(pte, ++ XENFEAT_writable_page_tables); ++ free_bootmem(__pa(pte), PAGE_SIZE); ++ } ++ va += PMD_SIZE; ++ if (pmd_index(va)) ++ continue; ++ ClearPagePinned(virt_to_page(pmd)); ++ make_page_writable(pmd, ++ XENFEAT_writable_page_tables); ++ free_bootmem(__pa((unsigned long)pmd ++ & PAGE_MASK), ++ PAGE_SIZE); ++ } ++ if (!pud_index(va)) ++ break; ++ } ++ ClearPagePinned(virt_to_page(pud_page)); ++ make_page_writable(pud_page, ++ XENFEAT_writable_page_tables); ++ free_bootmem(__pa((unsigned long)pud_page & PAGE_MASK), ++ PAGE_SIZE); ++ } else if (!WARN_ON(xen_start_info->mfn_list ++ < __START_KERNEL_map)) ++#endif ++ free_bootmem(__pa(xen_start_info->mfn_list), ++ PFN_PHYS(PFN_UP(xen_start_info->nr_pages * ++ sizeof(unsigned long)))); ++ + + /* + * Initialise the list of the frames that specify the list of +--- sle11-2009-07-31.orig/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:52.000000000 +0100 ++++ sle11-2009-07-31/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:54.000000000 +0100 +@@ -157,6 +157,17 @@ static unsigned long __meminitdata table + static unsigned long __meminitdata table_cur; + static unsigned long __meminitdata table_top; + ++static __init unsigned long get_table_cur(void) ++{ ++ BUG_ON(!table_cur); ++ if (xen_start_info->mfn_list < __START_KERNEL_map ++ && table_cur == xen_start_info->first_p2m_pfn) { ++ table_cur += xen_start_info->nr_p2m_frames; ++ table_top += xen_start_info->nr_p2m_frames; ++ } ++ return table_cur++; ++} ++ + /* + * NOTE: This function is marked __ref because it calls __init function + * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0. +@@ -168,8 +179,7 @@ static __ref void *spp_getpage(void) + if (after_bootmem) + ptr = (void *) get_zeroed_page(GFP_ATOMIC); + else if (table_cur < table_top) { +- ptr = __va(table_cur << PAGE_SHIFT); +- table_cur++; ++ ptr = __va(get_table_cur() << PAGE_SHIFT); + memset(ptr, 0, PAGE_SIZE); + } else + ptr = alloc_bootmem_pages(PAGE_SIZE); +@@ -334,8 +344,7 @@ static __ref void *alloc_low_page(unsign + return adr; + } + +- BUG_ON(!table_cur); +- pfn = table_cur++; ++ pfn = get_table_cur(); + if (pfn >= table_top) + panic("alloc_low_page: ran out of memory"); + +@@ -361,14 +370,29 @@ static inline int __meminit make_readonl + /* Make new page tables read-only on the first pass. */ + if (!xen_feature(XENFEAT_writable_page_tables) + && !max_pfn_mapped +- && (paddr >= (table_start << PAGE_SHIFT)) +- && (paddr < (table_top << PAGE_SHIFT))) +- readonly = 1; ++ && (paddr >= (table_start << PAGE_SHIFT))) { ++ unsigned long top = table_top; ++ ++ /* Account for the range get_table_cur() skips. */ ++ if (xen_start_info->mfn_list < __START_KERNEL_map ++ && table_cur <= xen_start_info->first_p2m_pfn ++ && top > xen_start_info->first_p2m_pfn) ++ top += xen_start_info->nr_p2m_frames; ++ if (paddr < (top << PAGE_SHIFT)) ++ readonly = 1; ++ } + /* Make old page tables read-only. */ + if (!xen_feature(XENFEAT_writable_page_tables) + && (paddr >= (xen_start_info->pt_base - __START_KERNEL_map)) + && (paddr < (table_cur << PAGE_SHIFT))) + readonly = 1; ++ /* Make P->M table (and its page tables) read-only. */ ++ if (!xen_feature(XENFEAT_writable_page_tables) ++ && xen_start_info->mfn_list < __START_KERNEL_map ++ && paddr >= (xen_start_info->first_p2m_pfn << PAGE_SHIFT) ++ && paddr < (xen_start_info->first_p2m_pfn ++ + xen_start_info->nr_p2m_frames) << PAGE_SHIFT) ++ readonly = 1; + + /* + * No need for writable mapping of kernel image. This also ensures that +@@ -616,6 +640,12 @@ void __init xen_init_pt(void) + __pud(__pa_symbol(level2_kernel_pgt) | _PAGE_TABLE); + memcpy(level2_kernel_pgt, page, PAGE_SIZE); + ++ /* Copy the initial P->M table mappings if necessary. */ ++ addr = pgd_index(xen_start_info->mfn_list); ++ if (addr < pgd_index(__START_KERNEL_map)) ++ init_level4_pgt[addr] = ++ ((pgd_t *)xen_start_info->pt_base)[addr]; ++ + /* Do an early initialization of the fixmap area. */ + addr = __fix_to_virt(FIX_EARLYCON_MEM_BASE); + level3_kernel_pgt[pud_index(addr)] = +@@ -676,22 +706,28 @@ static void __init find_early_table_spac + static void __init xen_finish_init_mapping(void) + { + unsigned long i, start, end; ++ struct mmuext_op mmuext; + + /* Re-vector virtual addresses pointing into the initial + mapping to the just-established permanent ones. */ + xen_start_info = __va(__pa(xen_start_info)); + xen_start_info->pt_base = (unsigned long) + __va(__pa(xen_start_info->pt_base)); +- if (!xen_feature(XENFEAT_auto_translated_physmap)) { ++ if (!xen_feature(XENFEAT_auto_translated_physmap) ++ && xen_start_info->mfn_list >= __START_KERNEL_map) + phys_to_machine_mapping = + __va(__pa(xen_start_info->mfn_list)); +- xen_start_info->mfn_list = (unsigned long) +- phys_to_machine_mapping; +- } + if (xen_start_info->mod_start) + xen_start_info->mod_start = (unsigned long) + __va(__pa(xen_start_info->mod_start)); + ++ /* Unpin the no longer used Xen provided page tables. */ ++ mmuext.cmd = MMUEXT_UNPIN_TABLE; ++ mmuext.arg1.mfn = pfn_to_mfn(__pa(xen_start_info->pt_base) ++ >> PAGE_SHIFT); ++ if (HYPERVISOR_mmuext_op(&mmuext, 1, NULL, DOMID_SELF)) ++ BUG(); ++ + /* Destroy the Xen-created mappings beyond the kernel image. */ + start = PAGE_ALIGN((unsigned long)_end); + end = __START_KERNEL_map + (table_start << PAGE_SHIFT); +@@ -948,9 +984,20 @@ unsigned long __init_refok init_memory_m + + __flush_tlb_all(); + +- if (!after_bootmem && table_top > table_start) ++ if (!after_bootmem && table_top > table_start) { ++ if (xen_start_info->mfn_list < __START_KERNEL_map ++ && table_start <= xen_start_info->first_p2m_pfn ++ && table_top > xen_start_info->first_p2m_pfn) { ++ reserve_early(table_start << PAGE_SHIFT, ++ xen_start_info->first_p2m_pfn ++ << PAGE_SHIFT, ++ "PGTABLE"); ++ table_start = xen_start_info->first_p2m_pfn ++ + xen_start_info->nr_p2m_frames; ++ } + reserve_early(table_start << PAGE_SHIFT, + table_top << PAGE_SHIFT, "PGTABLE"); ++ } + + printk(KERN_INFO "last_map_addr: %lx end: %lx\n", + last_map_addr, end); +--- sle11-2009-07-31.orig/arch/x86/mm/pageattr-xen.c 2009-06-29 15:42:17.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/mm/pageattr-xen.c 2009-06-29 15:46:57.000000000 +0200 +@@ -1262,7 +1262,7 @@ static void __make_page_writable(unsigne + + pte = lookup_address(va, &level); + BUG_ON(!pte || level != PG_LEVEL_4K); +- if (HYPERVISOR_update_va_mapping(va, pte_mkwrite(*pte), 0)) ++ if (HYPERVISOR_update_va_mapping(va, pte_mkwrite(*pte), UVMF_INVLPG)) + BUG(); + if (in_secondary_range(va)) { + unsigned long pfn = pte_pfn(*pte); +--- sle11-2009-07-31.orig/arch/x86/mm/pgtable-xen.c 2009-04-09 14:54:18.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/mm/pgtable-xen.c 2009-03-16 16:40:54.000000000 +0100 +@@ -323,7 +323,7 @@ void __init xen_init_pgd_pin(void) + if (PTRS_PER_PUD > 1) /* not folded */ + SetPagePinned(virt_to_page(pud)); + for (u = 0; u < PTRS_PER_PUD; u++, pud++) { +- if (!pud_present(*pud)) ++ if (!pud_present(*pud) || pud_large(*pud)) + continue; + pmd = pmd_offset(pud, 0); + if (PTRS_PER_PMD > 1) /* not folded */ +@@ -334,7 +334,7 @@ void __init xen_init_pgd_pin(void) + && m >= pmd_index(HYPERVISOR_VIRT_START)) + continue; + #endif +- if (!pmd_present(*pmd)) ++ if (!pmd_present(*pmd) || pmd_large(*pmd)) + continue; + SetPagePinned(pmd_page(*pmd)); + } +--- sle11-2009-07-31.orig/arch/x86/mm/pgtable_32-xen.c 2009-06-04 10:21:39.000000000 +0200 ++++ sle11-2009-07-31/arch/x86/mm/pgtable_32-xen.c 2009-03-16 16:40:54.000000000 +0100 +@@ -188,6 +188,6 @@ void make_lowmem_page_writable(void *va, + pte = lookup_address((unsigned long)va, &level); + BUG_ON(!pte || level != PG_LEVEL_4K || !pte_present(*pte)); + rc = HYPERVISOR_update_va_mapping( +- (unsigned long)va, pte_mkwrite(*pte), 0); ++ (unsigned long)va, pte_mkwrite(*pte), UVMF_INVLPG); + BUG_ON(rc); + } +--- sle11-2009-07-31.orig/include/xen/interface/elfnote.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-07-31/include/xen/interface/elfnote.h 2009-03-16 16:40:54.000000000 +0100 +@@ -162,9 +162,20 @@ + #define XEN_ELFNOTE_SUSPEND_CANCEL 14 + + /* ++ * The (non-default) location the initial phys-to-machine map should be ++ * placed at by the hypervisor (Dom0) or the tools (DomU). ++ * The kernel must be prepared for this mapping to be established using ++ * large pages, despite such otherwise not being available to guests. ++ * The kernel must also be prepared that the page table pages used for ++ * this mapping may not be accessible through the initial mapping. ++ * (Only x86-64 supports this at present.) ++ */ ++#define XEN_ELFNOTE_INIT_P2M 15 ++ ++/* + * The number of the highest elfnote defined. + */ +-#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUSPEND_CANCEL ++#define XEN_ELFNOTE_MAX XEN_ELFNOTE_INIT_P2M + + /* + * System information exported through crash notes. +--- sle11-2009-07-31.orig/include/xen/interface/xen.h 2009-05-14 11:17:48.000000000 +0200 ++++ sle11-2009-07-31/include/xen/interface/xen.h 2009-03-16 16:40:54.000000000 +0100 +@@ -536,6 +536,7 @@ typedef struct shared_info shared_info_t + * a. relocated kernel image + * b. initial ram disk [mod_start, mod_len] + * c. list of allocated page frames [mfn_list, nr_pages] ++ * (unless relocated due to XEN_ELFNOTE_INIT_P2M) + * d. start_info_t structure [register ESI (x86)] + * e. bootstrap page tables [pt_base, CR3 (x86)] + * f. bootstrap stack [register ESP (x86)] +@@ -577,6 +578,9 @@ struct start_info { + unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */ + unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ + int8_t cmd_line[MAX_GUEST_CMDLINE]; ++ /* The pfn range here covers both page table and p->m table frames. */ ++ unsigned long first_p2m_pfn;/* 1st pfn forming initial P->M table. */ ++ unsigned long nr_p2m_frames;/* # of pfns forming initial P->M table. */ + }; + typedef struct start_info start_info_t; + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-pgd-alloc-order b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-pgd-alloc-order new file mode 100644 index 000000000..5d4f4f7bf --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-pgd-alloc-order @@ -0,0 +1,350 @@ +From: jbeulich@novell.com +Subject: don't require order-1 allocations for pgd-s +Patch-mainline: obsolete + +At the same time remove the useless user mode pair of init_level4_pgt. + +--- sle11-2009-04-09.orig/arch/x86/kernel/cpu/common_64-xen.c 2008-11-17 14:07:10.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/kernel/cpu/common_64-xen.c 2009-03-16 16:40:52.000000000 +0100 +@@ -530,8 +530,7 @@ static void __init_refok switch_pt(int c + #ifdef CONFIG_XEN + if (cpu == 0) + xen_init_pt(); +- xen_pt_switch(__pa_symbol(init_level4_pgt)); +- xen_new_user_pt(__pa_symbol(__user_pgd(init_level4_pgt))); ++ xen_pt_switch(init_level4_pgt); + #endif + } + +--- sle11-2009-04-09.orig/arch/x86/kernel/head_64-xen.S 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/kernel/head_64-xen.S 2009-03-16 16:40:52.000000000 +0100 +@@ -44,14 +44,6 @@ ENTRY(name) + + NEXT_PAGE(init_level4_pgt) + .fill 512,8,0 +- /* +- * We update two pgd entries to make kernel and user pgd consistent +- * at pgd_populate(). It can be used for kernel modules. So we place +- * this page here for those cases to avoid memory corruption. +- * We also use this page to establish the initial mapping for the +- * vsyscall area. +- */ +- .fill 512,8,0 + + NEXT_PAGE(level3_kernel_pgt) + .fill 512,8,0 +--- sle11-2009-04-09.orig/arch/x86/mm/hypervisor.c 2009-03-16 16:40:50.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/mm/hypervisor.c 2009-03-30 12:19:20.000000000 +0200 +@@ -423,7 +423,7 @@ void xen_l3_entry_update(pud_t *ptr, pud + #endif + + #ifdef CONFIG_X86_64 +-void xen_l4_entry_update(pgd_t *ptr, int user, pgd_t val) ++void xen_l4_entry_update(pgd_t *ptr, pgd_t val) + { + mmu_update_t u[2]; + struct page *page = NULL; +@@ -436,8 +436,10 @@ void xen_l4_entry_update(pgd_t *ptr, int + } + u[0].ptr = virt_to_machine(ptr); + u[0].val = __pgd_val(val); +- if (user) { +- u[1].ptr = virt_to_machine(__user_pgd(ptr)); ++ if (((unsigned long)ptr & ~PAGE_MASK) ++ < pgd_index(__HYPERVISOR_VIRT_START) * sizeof(*ptr) ++ && (ptr = __user_pgd(ptr)) != NULL) { ++ u[1].ptr = virt_to_machine(ptr); + u[1].val = __pgd_val(val); + do_lN_entry_update(u, 2, page); + } else +@@ -445,21 +447,25 @@ void xen_l4_entry_update(pgd_t *ptr, int + } + #endif /* CONFIG_X86_64 */ + +-void xen_pt_switch(unsigned long ptr) ++#ifdef CONFIG_X86_64 ++void xen_pt_switch(pgd_t *pgd) + { + struct mmuext_op op; + op.cmd = MMUEXT_NEW_BASEPTR; +- op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); ++ op.arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); + BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); + } + +-void xen_new_user_pt(unsigned long ptr) ++void xen_new_user_pt(pgd_t *pgd) + { + struct mmuext_op op; ++ ++ pgd = __user_pgd(pgd); + op.cmd = MMUEXT_NEW_USER_BASEPTR; +- op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); ++ op.arg1.mfn = pgd ? pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT) : 0; + BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); + } ++#endif + + void xen_tlb_flush(void) + { +@@ -529,28 +535,38 @@ void xen_invlpg_mask(cpumask_t *mask, un + void xen_pgd_pin(pgd_t *pgd) + { + struct mmuext_op op[NR_PGD_PIN_OPS]; ++ unsigned int nr = NR_PGD_PIN_OPS; + + op[0].cmd = MMUEXT_PIN_L3_TABLE; + op[0].arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); + #ifdef CONFIG_X86_64 + op[1].cmd = op[0].cmd = MMUEXT_PIN_L4_TABLE; +- op[1].arg1.mfn = pfn_to_mfn(__pa(__user_pgd(pgd)) >> PAGE_SHIFT); ++ pgd = __user_pgd(pgd); ++ if (pgd) ++ op[1].arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); ++ else ++ nr = 1; + #endif +- if (HYPERVISOR_mmuext_op(op, NR_PGD_PIN_OPS, NULL, DOMID_SELF) < 0) ++ if (HYPERVISOR_mmuext_op(op, nr, NULL, DOMID_SELF) < 0) + BUG(); + } + + void xen_pgd_unpin(pgd_t *pgd) + { + struct mmuext_op op[NR_PGD_PIN_OPS]; ++ unsigned int nr = NR_PGD_PIN_OPS; + + op[0].cmd = MMUEXT_UNPIN_TABLE; + op[0].arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); + #ifdef CONFIG_X86_64 +- op[1].cmd = MMUEXT_UNPIN_TABLE; +- op[1].arg1.mfn = pfn_to_mfn(__pa(__user_pgd(pgd)) >> PAGE_SHIFT); ++ pgd = __user_pgd(pgd); ++ if (pgd) { ++ op[1].cmd = MMUEXT_UNPIN_TABLE; ++ op[1].arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); ++ } else ++ nr = 1; + #endif +- if (HYPERVISOR_mmuext_op(op, NR_PGD_PIN_OPS, NULL, DOMID_SELF) < 0) ++ if (HYPERVISOR_mmuext_op(op, nr, NULL, DOMID_SELF) < 0) + BUG(); + } + +--- sle11-2009-04-09.orig/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:50.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:52.000000000 +0100 +@@ -616,9 +616,6 @@ void __init xen_init_pt(void) + __pud(__pa_symbol(level2_kernel_pgt) | _PAGE_TABLE); + memcpy(level2_kernel_pgt, page, PAGE_SIZE); + +- __user_pgd(init_level4_pgt)[pgd_index(VSYSCALL_START)] = +- __pgd(__pa_symbol(level3_user_pgt) | _PAGE_TABLE); +- + /* Do an early initialization of the fixmap area. */ + addr = __fix_to_virt(FIX_EARLYCON_MEM_BASE); + level3_kernel_pgt[pud_index(addr)] = +@@ -628,8 +625,6 @@ void __init xen_init_pt(void) + + early_make_page_readonly(init_level4_pgt, + XENFEAT_writable_page_tables); +- early_make_page_readonly(__user_pgd(init_level4_pgt), +- XENFEAT_writable_page_tables); + early_make_page_readonly(level3_kernel_pgt, + XENFEAT_writable_page_tables); + early_make_page_readonly(level3_user_pgt, +--- sle11-2009-04-09.orig/arch/x86/mm/pgtable-xen.c 2009-03-16 16:40:50.000000000 +0100 ++++ sle11-2009-04-09/arch/x86/mm/pgtable-xen.c 2009-04-09 14:54:18.000000000 +0200 +@@ -270,9 +270,11 @@ static void pgd_walk(pgd_t *pgd_base, pg + BUG(); + seq = 0; + } ++ pgd = __user_pgd(pgd_base); ++ BUG_ON(!pgd); + MULTI_update_va_mapping(mcl + seq, +- (unsigned long)__user_pgd(pgd_base), +- pfn_pte(virt_to_phys(__user_pgd(pgd_base))>>PAGE_SHIFT, flags), ++ (unsigned long)pgd, ++ pfn_pte(virt_to_phys(pgd)>>PAGE_SHIFT, flags), + 0); + MULTI_update_va_mapping(mcl + seq + 1, + (unsigned long)pgd_base, +@@ -662,12 +664,29 @@ static void pgd_prepopulate_pmd(struct m + } + } + ++static inline pgd_t *user_pgd_alloc(pgd_t *pgd) ++{ + #ifdef CONFIG_X86_64 +-/* We allocate two contiguous pages for kernel and user. */ +-#define PGD_ORDER 1 +-#else +-#define PGD_ORDER 0 ++ if (pgd) { ++ pgd_t *upgd = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); ++ ++ if (upgd) ++ virt_to_page(pgd)->index = (long)upgd; ++ else { ++ free_page((unsigned long)pgd); ++ pgd = NULL; ++ } ++ } ++#endif ++ return pgd; ++} ++ ++static inline void user_pgd_free(pgd_t *pgd) ++{ ++#ifdef CONFIG_X86_64 ++ free_page(virt_to_page(pgd)->index); + #endif ++} + + pgd_t *pgd_alloc(struct mm_struct *mm) + { +@@ -675,7 +694,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + pmd_t *pmds[PREALLOCATED_PMDS]; + unsigned long flags; + +- pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER); ++ pgd = user_pgd_alloc((void *)__get_free_page(GFP_KERNEL|__GFP_ZERO)); + + if (pgd == NULL) + goto out; +@@ -714,7 +733,8 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + out_free_pmds: + free_pmds(pmds, mm, !xen_feature(XENFEAT_pae_pgdir_above_4gb)); + out_free_pgd: +- free_pages((unsigned long)pgd, PGD_ORDER); ++ user_pgd_free(pgd); ++ free_page((unsigned long)pgd); + out: + return NULL; + } +@@ -733,7 +753,8 @@ void pgd_free(struct mm_struct *mm, pgd_ + + pgd_mop_up_pmds(mm, pgd); + paravirt_pgd_free(mm, pgd); +- free_pages((unsigned long)pgd, PGD_ORDER); ++ user_pgd_free(pgd); ++ free_page((unsigned long)pgd); + } + + /* blktap and gntdev need this, as otherwise they would implicitly (and +--- sle11-2009-04-09.orig/drivers/xen/core/machine_reboot.c 2009-02-17 12:25:29.000000000 +0100 ++++ sle11-2009-04-09/drivers/xen/core/machine_reboot.c 2009-03-16 16:40:52.000000000 +0100 +@@ -191,8 +191,7 @@ static int take_machine_down(void *_susp + * in fast-suspend mode as that implies a new enough Xen. + */ + if (!suspend->fast_suspend) +- xen_new_user_pt(__pa(__user_pgd( +- current->active_mm->pgd))); ++ xen_new_user_pt(current->active_mm->pgd); + #endif + } + +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:40:50.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:40:52.000000000 +0100 +@@ -85,8 +85,8 @@ void do_hypervisor_callback(struct pt_re + * be MACHINE addresses. + */ + +-void xen_pt_switch(unsigned long ptr); +-void xen_new_user_pt(unsigned long ptr); /* x86_64 only */ ++void xen_pt_switch(pgd_t *); ++void xen_new_user_pt(pgd_t *); /* x86_64 only */ + void xen_load_gs(unsigned int selector); /* x86_64 only */ + void xen_tlb_flush(void); + void xen_invlpg(unsigned long ptr); +@@ -94,7 +94,7 @@ void xen_invlpg(unsigned long ptr); + void xen_l1_entry_update(pte_t *ptr, pte_t val); + void xen_l2_entry_update(pmd_t *ptr, pmd_t val); + void xen_l3_entry_update(pud_t *ptr, pud_t val); /* x86_64/PAE */ +-void xen_l4_entry_update(pgd_t *ptr, int user, pgd_t val); /* x86_64 only */ ++void xen_l4_entry_update(pgd_t *ptr, pgd_t val); /* x86_64 only */ + void xen_pgd_pin(pgd_t *); + void xen_pgd_unpin(pgd_t *); + +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/mmu_context_64.h 2009-03-16 16:38:16.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/mmu_context_64.h 2009-03-16 16:40:52.000000000 +0100 +@@ -46,6 +46,7 @@ static inline void switch_mm(struct mm_s + { + unsigned cpu = smp_processor_id(); + struct mmuext_op _op[3], *op = _op; ++ pgd_t *upgd; + + if (likely(prev != next)) { + BUG_ON(!xen_feature(XENFEAT_writable_page_tables) && +@@ -64,9 +65,11 @@ static inline void switch_mm(struct mm_s + op->arg1.mfn = pfn_to_mfn(__pa(next->pgd) >> PAGE_SHIFT); + op++; + +- /* xen_new_user_pt(__pa(__user_pgd(next->pgd))) */ ++ /* xen_new_user_pt(next->pgd) */ + op->cmd = MMUEXT_NEW_USER_BASEPTR; +- op->arg1.mfn = pfn_to_mfn(__pa(__user_pgd(next->pgd)) >> PAGE_SHIFT); ++ upgd = __user_pgd(next->pgd); ++ op->arg1.mfn = likely(upgd) ++ ? pfn_to_mfn(__pa(upgd) >> PAGE_SHIFT) : 0; + op++; + + if (unlikely(next->context.ldt != prev->context.ldt)) { +@@ -90,7 +93,7 @@ static inline void switch_mm(struct mm_s + * to make sure to use no freed page tables. + */ + load_cr3(next->pgd); +- xen_new_user_pt(__pa(__user_pgd(next->pgd))); ++ xen_new_user_pt(next->pgd); + load_LDT_nolock(&next->context); + } + } +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/pgalloc.h 2009-03-16 16:40:37.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/pgalloc.h 2009-03-16 16:40:52.000000000 +0100 +@@ -106,15 +106,13 @@ static inline void pud_populate(struct m + #endif /* CONFIG_X86_PAE */ + + #if PAGETABLE_LEVELS > 3 +-#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD) +- + static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) + { + pgd_t ent = __pgd(_PAGE_TABLE | __pa(pud)); + + paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT); + if (unlikely(PagePinned(virt_to_page(pgd)))) +- xen_l4_entry_update(pgd, 1, ent); ++ xen_l4_entry_update(pgd, ent); + else + *__user_pgd(pgd) = *pgd = ent; + } +--- sle11-2009-04-09.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-16 16:40:37.000000000 +0100 ++++ sle11-2009-04-09/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-16 16:40:52.000000000 +0100 +@@ -131,18 +131,25 @@ static inline void xen_set_pud(pud_t *pu + : (void)(*__pudp = xen_make_pud(0)); \ + }) + +-#define __user_pgd(pgd) ((pgd) + PTRS_PER_PGD) ++static inline pgd_t *__user_pgd(pgd_t *pgd) ++{ ++ if (unlikely(((unsigned long)pgd & PAGE_MASK) ++ == (unsigned long)init_level4_pgt)) ++ return NULL; ++ return (pgd_t *)(virt_to_page(pgd)->index ++ + ((unsigned long)pgd & ~PAGE_MASK)); ++} + + static inline void xen_set_pgd(pgd_t *pgdp, pgd_t pgd) + { +- xen_l4_entry_update(pgdp, 0, pgd); ++ xen_l4_entry_update(pgdp, pgd); + } + + #define xen_pgd_clear(pgd) \ + ({ \ + pgd_t *__pgdp = (pgd); \ + PagePinned(virt_to_page(__pgdp)) \ +- ? xen_l4_entry_update(__pgdp, 1, xen_make_pgd(0)) \ ++ ? xen_l4_entry_update(__pgdp, xen_make_pgd(0)) \ + : (void)(*__user_pgd(__pgdp) = *__pgdp = xen_make_pgd(0)); \ + }) + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-pgd-pin b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-pgd-pin new file mode 100644 index 000000000..04a6b4ff0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen-x86_64-pgd-pin @@ -0,0 +1,111 @@ +From: jbeulich@novell.com +Subject: make pinning of pgd pairs transparent to callers +Patch-mainline: obsolete + +--- sle11-2009-03-16.orig/arch/x86/mm/hypervisor.c 2009-03-16 16:40:44.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/mm/hypervisor.c 2009-03-16 16:40:50.000000000 +0100 +@@ -520,26 +520,38 @@ void xen_invlpg_mask(cpumask_t *mask, un + + #endif /* CONFIG_SMP */ + +-void xen_pgd_pin(unsigned long ptr) +-{ +- struct mmuext_op op; + #ifdef CONFIG_X86_64 +- op.cmd = MMUEXT_PIN_L4_TABLE; +-#elif defined(CONFIG_X86_PAE) +- op.cmd = MMUEXT_PIN_L3_TABLE; ++#define NR_PGD_PIN_OPS 2 + #else +- op.cmd = MMUEXT_PIN_L2_TABLE; ++#define NR_PGD_PIN_OPS 1 + #endif +- op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); +- BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++ ++void xen_pgd_pin(pgd_t *pgd) ++{ ++ struct mmuext_op op[NR_PGD_PIN_OPS]; ++ ++ op[0].cmd = MMUEXT_PIN_L3_TABLE; ++ op[0].arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); ++#ifdef CONFIG_X86_64 ++ op[1].cmd = op[0].cmd = MMUEXT_PIN_L4_TABLE; ++ op[1].arg1.mfn = pfn_to_mfn(__pa(__user_pgd(pgd)) >> PAGE_SHIFT); ++#endif ++ if (HYPERVISOR_mmuext_op(op, NR_PGD_PIN_OPS, NULL, DOMID_SELF) < 0) ++ BUG(); + } + +-void xen_pgd_unpin(unsigned long ptr) ++void xen_pgd_unpin(pgd_t *pgd) + { +- struct mmuext_op op; +- op.cmd = MMUEXT_UNPIN_TABLE; +- op.arg1.mfn = pfn_to_mfn(ptr >> PAGE_SHIFT); +- BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0); ++ struct mmuext_op op[NR_PGD_PIN_OPS]; ++ ++ op[0].cmd = MMUEXT_UNPIN_TABLE; ++ op[0].arg1.mfn = pfn_to_mfn(__pa(pgd) >> PAGE_SHIFT); ++#ifdef CONFIG_X86_64 ++ op[1].cmd = MMUEXT_UNPIN_TABLE; ++ op[1].arg1.mfn = pfn_to_mfn(__pa(__user_pgd(pgd)) >> PAGE_SHIFT); ++#endif ++ if (HYPERVISOR_mmuext_op(op, NR_PGD_PIN_OPS, NULL, DOMID_SELF) < 0) ++ BUG(); + } + + void xen_set_ldt(const void *ptr, unsigned int ents) +--- sle11-2009-03-16.orig/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:37.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/mm/init_64-xen.c 2009-03-16 16:40:50.000000000 +0100 +@@ -641,10 +641,8 @@ void __init xen_init_pt(void) + early_make_page_readonly(level1_fixmap_pgt, + XENFEAT_writable_page_tables); + +- if (!xen_feature(XENFEAT_writable_page_tables)) { +- xen_pgd_pin(__pa_symbol(init_level4_pgt)); +- xen_pgd_pin(__pa_symbol(__user_pgd(init_level4_pgt))); +- } ++ if (!xen_feature(XENFEAT_writable_page_tables)) ++ xen_pgd_pin(init_level4_pgt); + } + + static void __init find_early_table_space(unsigned long end, int use_pse, +--- sle11-2009-03-16.orig/arch/x86/mm/pgtable-xen.c 2009-03-16 16:40:44.000000000 +0100 ++++ sle11-2009-03-16/arch/x86/mm/pgtable-xen.c 2009-03-16 16:40:50.000000000 +0100 +@@ -347,19 +347,13 @@ static void __pgd_pin(pgd_t *pgd) + { + pgd_walk(pgd, PAGE_KERNEL_RO); + kmap_flush_unused(); +- xen_pgd_pin(__pa(pgd)); /* kernel */ +-#ifdef CONFIG_X86_64 +- xen_pgd_pin(__pa(__user_pgd(pgd))); /* user */ +-#endif ++ xen_pgd_pin(pgd); + SetPagePinned(virt_to_page(pgd)); + } + + static void __pgd_unpin(pgd_t *pgd) + { +- xen_pgd_unpin(__pa(pgd)); +-#ifdef CONFIG_X86_64 +- xen_pgd_unpin(__pa(__user_pgd(pgd))); +-#endif ++ xen_pgd_unpin(pgd); + pgd_walk(pgd, PAGE_KERNEL); + ClearPagePinned(virt_to_page(pgd)); + } +--- sle11-2009-03-16.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:40:37.000000000 +0100 ++++ sle11-2009-03-16/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-16 16:40:50.000000000 +0100 +@@ -95,8 +95,8 @@ void xen_l1_entry_update(pte_t *ptr, pte + void xen_l2_entry_update(pmd_t *ptr, pmd_t val); + void xen_l3_entry_update(pud_t *ptr, pud_t val); /* x86_64/PAE */ + void xen_l4_entry_update(pgd_t *ptr, int user, pgd_t val); /* x86_64 only */ +-void xen_pgd_pin(unsigned long ptr); +-void xen_pgd_unpin(unsigned long ptr); ++void xen_pgd_pin(pgd_t *); ++void xen_pgd_unpin(pgd_t *); + + void xen_init_pgd_pin(void); + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch b/src/patches/suse-2.6.27.31/patches.xen/xen3-acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch new file mode 100644 index 000000000..8cb69e22b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch @@ -0,0 +1,38 @@ +From 07ae95f988a34465bdcb384bfa73c03424fe2312 Mon Sep 17 00:00:00 2001 +From: Andrew Patterson +Date: Mon, 10 Nov 2008 15:31:05 -0700 +Subject: ACPI/PCI: PCI MSI _OSC support capabilities called when root bridge added +Patch-mainline: 2.6.29 +References: bnc#438941 + +The _OSC capability OSC_MSI_SUPPORT is set when the root bridge is added +with pci_acpi_osc_support(), so we no longer need to do it in the PCI +MSI driver. Also adds the function pci_msi_enabled, which returns true +if pci=nomsi is not on the kernel command-line. + +Signed-off-by: Andrew Patterson +Signed-off-by: Jesse Barnes +Signed-off-by: Greg Kroah-Hartman + +Automatically created from "patches.drivers/acpi-pci-pci-msi-_osc-support-capabilities-called-when-root-bridge-added.patch" by xen-port-patches.py + +--- sle11-2009-04-20.orig/drivers/pci/msi-xen.c 2009-04-24 13:36:45.000000000 +0200 ++++ sle11-2009-04-20/drivers/pci/msi-xen.c 2009-01-09 11:10:27.000000000 +0100 +@@ -804,6 +804,17 @@ void pci_no_msi(void) + pci_msi_enable = 0; + } + ++/** ++ * pci_msi_enabled - is MSI enabled? ++ * ++ * Returns true if MSI has not been disabled by the command-line option ++ * pci=nomsi. ++ **/ ++int pci_msi_enabled(void) ++{ ++ return pci_msi_enable; ++} ++ + void pci_msi_init_pci_dev(struct pci_dev *dev) + { + #ifndef CONFIG_XEN diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-arch-x86 b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-arch-x86 new file mode 100644 index 000000000..7a09fb1d4 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-arch-x86 @@ -0,0 +1,41 @@ +Subject: xen3 x86 build fixes. +From: jbeulich@novell.com +Patch-mainline: obsolete + +--- sle11-2009-06-04.orig/arch/x86/kdb/kdba_bt.c 2009-06-04 10:17:50.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kdb/kdba_bt.c 2009-06-04 10:19:52.000000000 +0200 +@@ -3196,6 +3196,9 @@ bb_usage_mov(const struct bb_operand *sr + bb_is_int_reg(dst->base_rc) && + full_register_dst) { + #ifdef CONFIG_X86_32 ++#ifndef TSS_sysenter_sp0 ++#define TSS_sysenter_sp0 SYSENTER_stack_sp0 ++#endif + /* mov from TSS_sysenter_sp0+offset to esp to fix up the + * sysenter stack, it leaves esp well defined. mov + * TSS_ysenter_sp0+offset(%esp),%esp is followed by up to 5 +--- sle11-2009-06-04.orig/arch/x86/power/Makefile 2009-06-04 10:17:50.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/power/Makefile 2009-06-04 10:19:52.000000000 +0200 +@@ -1,2 +1,4 @@ + obj-$(CONFIG_PM_SLEEP) += cpu_$(BITS).o + obj-$(CONFIG_HIBERNATION) += hibernate_$(BITS).o hibernate_asm_$(BITS).o ++ ++disabled-obj-$(CONFIG_XEN) := cpu_$(BITS).o +--- sle11-2009-06-04.orig/arch/x86/power/cpu_64.c 2009-06-04 10:18:37.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/power/cpu_64.c 2009-06-04 10:19:52.000000000 +0200 +@@ -135,7 +135,6 @@ void restore_processor_state(void) + + static void fix_processor_context(void) + { +-#ifndef CONFIG_X86_NO_TSS + int cpu = smp_processor_id(); + struct tss_struct *t = &per_cpu(init_tss, cpu); + +@@ -147,7 +146,6 @@ static void fix_processor_context(void) + set_tss_desc(cpu, t); + + get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9; +-#endif + + syscall_init(); /* This sets MSR_*STAR and related */ + load_TR_desc(); /* This does ltr */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-common b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-common new file mode 100644 index 000000000..2504696d3 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-common @@ -0,0 +1,360 @@ +Subject: Fix xen build. +From: jbeulich@novell.com +Patch-mainline: obsolete + +--- sle11-2009-06-29.orig/drivers/acpi/hardware/hwsleep.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/drivers/acpi/hardware/hwsleep.c 2009-02-16 16:01:39.000000000 +0100 +@@ -430,6 +430,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_stat + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ ++#ifndef CONFIG_XEN + acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) + { + u32 in_value; +@@ -479,6 +480,7 @@ acpi_status asmlinkage acpi_enter_sleep_ + } + + ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) ++#endif + + /******************************************************************************* + * +--- sle11-2009-06-29.orig/drivers/base/cpu.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/base/cpu.c 2009-02-17 11:26:03.000000000 +0100 +@@ -78,7 +78,7 @@ static inline void register_cpu_control( + } + #endif /* CONFIG_HOTPLUG_CPU */ + +-#ifdef CONFIG_KEXEC ++#if defined(CONFIG_KEXEC) && !defined(CONFIG_XEN) + #include + + static ssize_t show_crash_notes(struct sys_device *dev, struct sysdev_attribute *attr, +@@ -173,7 +173,7 @@ int __cpuinit register_cpu(struct cpu *c + if (!error) + register_cpu_under_node(num, cpu_to_node(num)); + +-#ifdef CONFIG_KEXEC ++#if defined(CONFIG_KEXEC) && !defined(CONFIG_XEN) + if (!error) + error = sysdev_create_file(&cpu->sysdev, &attr_crash_notes); + #endif +--- sle11-2009-06-29.orig/drivers/ide/ide-lib.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/drivers/ide/ide-lib.c 2009-02-16 16:01:39.000000000 +0100 +@@ -177,6 +177,16 @@ void ide_toggle_bounce(ide_drive_t *driv + { + u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ + ++#ifndef CONFIG_XEN ++ if (!PCI_DMA_BUS_IS_PHYS) { ++ addr = BLK_BOUNCE_ANY; ++ } else if (on && drive->media == ide_disk) { ++ struct device *dev = drive->hwif->dev; ++ ++ if (dev && dev->dma_mask) ++ addr = *dev->dma_mask; ++ } ++#else + if (on && drive->media == ide_disk) { + struct device *dev = drive->hwif->dev; + +@@ -185,6 +195,7 @@ void ide_toggle_bounce(ide_drive_t *driv + else if (dev && dev->dma_mask) + addr = *dev->dma_mask; + } ++#endif + + if (drive->queue) + blk_queue_bounce_limit(drive->queue, addr); +--- sle11-2009-06-29.orig/drivers/oprofile/buffer_sync.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/drivers/oprofile/buffer_sync.c 2009-02-16 16:01:39.000000000 +0100 +@@ -44,7 +44,9 @@ static cpumask_t marked_cpus = CPU_MASK_ + static DEFINE_SPINLOCK(task_mortuary); + static void process_task_mortuary(void); + ++#ifdef CONFIG_XEN + static int cpu_current_domain[NR_CPUS]; ++#endif + + /* Take ownership of the task struct and place it on the + * list for processing. Only after two full buffer syncs +@@ -153,11 +155,13 @@ static void end_sync(void) + int sync_start(void) + { + int err; ++#ifdef CONFIG_XEN + int i; + + for (i = 0; i < NR_CPUS; i++) { + cpu_current_domain[i] = COORDINATOR_DOMAIN; + } ++#endif + + start_cpu_work(); + +@@ -302,12 +306,14 @@ static void add_cpu_mode_switch(unsigned + } + } + ++#ifdef CONFIG_XEN + static void add_domain_switch(unsigned long domain_id) + { + add_event_entry(ESCAPE_CODE); + add_event_entry(DOMAIN_SWITCH_CODE); + add_event_entry(domain_id); + } ++#endif + + static void + add_user_ctx_switch(struct task_struct const * task, unsigned long cookie) +@@ -531,11 +537,14 @@ void sync_buffer(int cpu) + + add_cpu_switch(cpu); + ++#ifdef CONFIG_XEN + /* We need to assign the first samples in this CPU buffer to the + same domain that we were processing at the last sync_buffer */ + if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) { + add_domain_switch(cpu_current_domain[cpu]); + } ++#endif ++ + /* Remember, only we can modify tail_pos */ + + available = get_slots(cpu_buf); +@@ -553,8 +562,10 @@ void sync_buffer(int cpu) + } else if (s->event == CPU_TRACE_BEGIN) { + state = sb_bt_start; + add_trace_begin(); ++#ifdef CONFIG_XEN + } else if (s->event == CPU_DOMAIN_SWITCH) { +- domain_switch = 1; ++ domain_switch = 1; ++#endif + } else { + struct mm_struct * oldmm = mm; + +@@ -568,21 +579,21 @@ void sync_buffer(int cpu) + add_user_ctx_switch(new, cookie); + } + } else { ++#ifdef CONFIG_XEN + if (domain_switch) { + cpu_current_domain[cpu] = s->eip; + add_domain_switch(s->eip); + domain_switch = 0; +- } else { +- if (cpu_current_domain[cpu] != ++ } else if (cpu_current_domain[cpu] != + COORDINATOR_DOMAIN) { +- add_sample_entry(s->eip, s->event); +- } +- else if (state >= sb_bt_start && +- !add_sample(mm, s, cpu_mode)) { +- if (state == sb_bt_start) { +- state = sb_bt_ignore; +- atomic_inc(&oprofile_stats.bt_lost_no_mapping); +- } ++ add_sample_entry(s->eip, s->event); ++ } else ++#endif ++ if (state >= sb_bt_start && ++ !add_sample(mm, s, cpu_mode)) { ++ if (state == sb_bt_start) { ++ state = sb_bt_ignore; ++ atomic_inc(&oprofile_stats.bt_lost_no_mapping); + } + } + } +@@ -591,10 +602,12 @@ void sync_buffer(int cpu) + } + release_mm(mm); + ++#ifdef CONFIG_XEN + /* We reset domain to COORDINATOR at each CPU switch */ + if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) { + add_domain_switch(COORDINATOR_DOMAIN); + } ++#endif + + mark_done(cpu); + +--- sle11-2009-06-29.orig/drivers/oprofile/cpu_buffer.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/drivers/oprofile/cpu_buffer.c 2009-02-16 16:01:39.000000000 +0100 +@@ -38,7 +38,11 @@ static void wq_sync_buffer(struct work_s + #define DEFAULT_TIMER_EXPIRE (HZ / 10) + static int work_enabled; + ++#ifndef CONFIG_XEN ++#define current_domain COORDINATOR_DOMAIN ++#else + static int32_t current_domain = COORDINATOR_DOMAIN; ++#endif + + void free_cpu_buffers(void) + { +@@ -303,6 +307,7 @@ void oprofile_add_trace(unsigned long pc + add_sample(cpu_buf, pc, 0); + } + ++#ifdef CONFIG_XEN + int oprofile_add_domain_switch(int32_t domain_id) + { + struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; +@@ -321,6 +326,7 @@ int oprofile_add_domain_switch(int32_t d + + return 1; + } ++#endif + + /* + * This serves to avoid cpu buffer overflow, and makes sure +--- sle11-2009-06-29.orig/drivers/oprofile/oprof.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/drivers/oprofile/oprof.c 2009-02-16 16:01:39.000000000 +0100 +@@ -37,6 +37,7 @@ static DEFINE_MUTEX(start_mutex); + */ + static int timer = 0; + ++#ifdef CONFIG_XEN + int oprofile_set_active(int active_domains[], unsigned int adomains) + { + int err; +@@ -62,6 +63,7 @@ int oprofile_set_passive(int passive_dom + mutex_unlock(&start_mutex); + return err; + } ++#endif + + int oprofile_setup(void) + { +--- sle11-2009-06-29.orig/drivers/oprofile/oprofile_files.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/drivers/oprofile/oprofile_files.c 2009-02-16 16:01:39.000000000 +0100 +@@ -124,6 +124,8 @@ static const struct file_operations dump + .write = dump_write, + }; + ++#ifdef CONFIG_XEN ++ + #define TMPBUFSIZE 512 + + static unsigned int adomains = 0; +@@ -313,12 +315,16 @@ static struct file_operations passive_do + .write = pdomain_write, + }; + ++#endif /* CONFIG_XEN */ ++ + void oprofile_create_files(struct super_block * sb, struct dentry * root) + { + oprofilefs_create_file(sb, root, "enable", &enable_fops); + oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); ++#ifdef CONFIG_XEN + oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops); + oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops); ++#endif + oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); + oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); +--- sle11-2009-06-29.orig/include/linux/mm.h 2009-06-29 15:17:31.000000000 +0200 ++++ sle11-2009-06-29/include/linux/mm.h 2009-06-29 15:27:58.000000000 +0200 +@@ -202,10 +202,12 @@ struct vm_operations_struct { + int (*access)(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write); + ++#ifdef CONFIG_XEN + /* Area-specific function for clearing the PTE at @ptep. Returns the + * original value of @ptep. */ + pte_t (*zap_pte)(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, int is_fullmm); ++#endif + #ifdef CONFIG_NUMA + /* + * set_policy() op must add a reference to any non-NULL @new mempolicy +--- sle11-2009-06-29.orig/include/linux/oprofile.h 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/include/linux/oprofile.h 2009-06-29 15:28:01.000000000 +0200 +@@ -16,8 +16,9 @@ + #include + #include + #include +- ++#ifdef CONFIG_XEN + #include ++#endif + + /* Each escaped entry is prefixed by ESCAPE_CODE + * then one of the following codes, then the +@@ -53,11 +54,12 @@ struct oprofile_operations { + /* create any necessary configuration files in the oprofile fs. + * Optional. */ + int (*create_files)(struct super_block * sb, struct dentry * root); ++#ifdef CONFIG_XEN + /* setup active domains with Xen */ + int (*set_active)(int *active_domains, unsigned int adomains); + /* setup passive domains with Xen */ + int (*set_passive)(int *passive_domains, unsigned int pdomains); +- ++#endif + /* Do any necessary interrupt setup. Optional. */ + int (*setup)(void); + /* Do any necessary interrupt shutdown. Optional. */ +--- sle11-2009-06-29.orig/kernel/kexec.c 2008-11-25 13:31:12.000000000 +0100 ++++ sle11-2009-06-29/kernel/kexec.c 2009-02-17 11:27:16.000000000 +0100 +@@ -44,8 +44,10 @@ + #include + #endif + ++#ifndef CONFIG_XEN + /* Per cpu memory for storing cpu states in case of system crash. */ + note_buf_t* crash_notes; ++#endif + int dump_after_notifier; + + /* vmcoreinfo stuff */ +@@ -1167,6 +1169,7 @@ static void final_note(u32 *buf) + memcpy(buf, ¬e, sizeof(note)); + } + ++#ifndef CONFIG_XEN + void crash_save_cpu(struct pt_regs *regs, int cpu) + { + struct elf_prstatus prstatus; +@@ -1192,6 +1195,7 @@ void crash_save_cpu(struct pt_regs *regs + &prstatus, sizeof(prstatus)); + final_note(buf); + } ++#endif + + #ifdef CONFIG_SYSCTL + static ctl_table dump_after_notifier_table[] = { +@@ -1219,6 +1223,7 @@ static ctl_table kexec_sys_table[] = { + + static int __init crash_notes_memory_init(void) + { ++#ifndef CONFIG_XEN + /* Allocate memory for saving cpu registers. */ + crash_notes = alloc_percpu(note_buf_t); + if (!crash_notes) { +@@ -1226,6 +1231,7 @@ static int __init crash_notes_memory_ini + " states failed\n"); + return -ENOMEM; + } ++#endif + #ifdef CONFIG_SYSCTL + register_sysctl_table(kexec_sys_table); + #endif +--- sle11-2009-06-29.orig/mm/memory.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/mm/memory.c 2009-02-16 16:01:39.000000000 +0100 +@@ -758,10 +758,12 @@ static unsigned long zap_pte_range(struc + page->index > details->last_index)) + continue; + } ++#ifdef CONFIG_XEN + if (unlikely(vma->vm_ops && vma->vm_ops->zap_pte)) + ptent = vma->vm_ops->zap_pte(vma, addr, pte, + tlb->fullmm); + else ++#endif + ptent = ptep_get_and_clear_full(mm, addr, pte, + tlb->fullmm); + tlb_remove_tlb_entry(tlb, pte, addr); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-kconfig b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-kconfig new file mode 100644 index 000000000..c9c0aa60f --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-kconfig @@ -0,0 +1,82 @@ +Subject: Fix xen configuration. +From: jbeulich@novell.com +Patch-mainline: obsolete + +--- sle11-2009-02-05.orig/arch/x86/Kconfig 2009-02-05 10:18:30.000000000 +0100 ++++ sle11-2009-02-05/arch/x86/Kconfig 2009-02-05 10:20:53.000000000 +0100 +@@ -140,6 +140,7 @@ config HAVE_CPUMASK_OF_CPU_MAP + config ARCH_HIBERNATION_POSSIBLE + def_bool y + depends on !SMP || !X86_VOYAGER ++ depends on !XEN + + config ARCH_SUSPEND_POSSIBLE + def_bool y +@@ -198,7 +199,7 @@ config X86_HT + + config X86_BIOS_REBOOT + bool +- depends on !X86_VOYAGER ++ depends on !X86_VOYAGER && !XEN + default y + + config X86_TRAMPOLINE +@@ -993,7 +994,7 @@ config HIGHMEM + config X86_PAE + def_bool n + prompt "PAE (Physical Address Extension) Support" +- depends on X86_32 && !HIGHMEM4G ++ depends on X86_32 && (!HIGHMEM4G || X86_XEN) + select RESOURCES_64BIT + help + PAE is required for NX support, and furthermore enables +--- sle11-2009-02-05.orig/arch/x86/Kconfig.debug 2009-02-02 09:38:47.000000000 +0100 ++++ sle11-2009-02-05/arch/x86/Kconfig.debug 2009-02-02 09:40:56.000000000 +0100 +@@ -304,7 +304,7 @@ config OPTIMIZE_INLINING + + config KDB + bool "Built-in Kernel Debugger support" +- depends on DEBUG_KERNEL ++ depends on DEBUG_KERNEL && !XEN + select KALLSYMS + select KALLSYMS_ALL + help +--- sle11-2009-02-05.orig/drivers/xen/Kconfig 2008-11-10 11:49:15.000000000 +0100 ++++ sle11-2009-02-05/drivers/xen/Kconfig 2008-12-05 08:43:56.000000000 +0100 +@@ -16,12 +16,14 @@ menu "XEN" + + config XEN_PRIVILEGED_GUEST + bool "Privileged Guest (domain 0)" +- select PCI_REASSIGN if PCI + help + Support for privileged operation (domain 0) + + config XEN_UNPRIVILEGED_GUEST + def_bool !XEN_PRIVILEGED_GUEST ++ select PM ++ select PM_SLEEP ++ select PM_SLEEP_SMP if SMP + + config XEN_PRIVCMD + def_bool y +@@ -99,8 +101,9 @@ config XEN_NETDEV_LOOPBACK + + config XEN_PCIDEV_BACKEND + tristate "PCI-device backend driver" +- depends on PCI && XEN_BACKEND ++ depends on PCI && XEN_PRIVILEGED_GUEST && XEN_BACKEND + default XEN_BACKEND ++ select PCI_REASSIGN + help + The PCI device backend driver allows the kernel to export arbitrary + PCI devices to other guests. If you select this to be a module, you +@@ -110,8 +113,8 @@ config XEN_PCIDEV_BACKEND + choice + prompt "PCI Backend Mode" + depends on XEN_PCIDEV_BACKEND +- default XEN_PCIDEV_BACKEND_VPCI if !IA64 + default XEN_PCIDEV_BACKEND_CONTROLLER if IA64 ++ default XEN_PCIDEV_BACKEND_VPCI + + config XEN_PCIDEV_BACKEND_VPCI + bool "Virtual PCI" diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-xen b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-xen new file mode 100644 index 000000000..278177554 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-fixup-xen @@ -0,0 +1,5619 @@ +Subject: Fix Xen build wrt. Xen files coming from mainline. +From: http://xenbits.xensource.com/linux-2.6.18-xen.hg (tip 728:832aac894efd) +Patch-mainline: obsolete + +Acked-by: jbeulich@novell.com + +Index: head-2008-11-25/drivers/xen/Makefile +=================================================================== +--- head-2008-11-25.orig/drivers/xen/Makefile 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/Makefile 2008-11-25 12:35:56.000000000 +0100 +@@ -1,4 +1,25 @@ +-obj-y += grant-table.o features.o events.o manage.o ++obj-y += core/ ++obj-y += console/ ++obj-y += evtchn/ + obj-y += xenbus/ +-obj-$(CONFIG_XEN_XENCOMM) += xencomm.o +-obj-$(CONFIG_XEN_BALLOON) += balloon.o ++obj-y += char/ ++ ++obj-y += util.o ++obj-$(CONFIG_XEN_BALLOON) += balloon/ ++obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ ++obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ ++obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ ++obj-$(CONFIG_XEN_TPMDEV_BACKEND) += tpmback/ ++obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ ++obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ ++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ ++obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ ++obj-$(CONFIG_XEN_FRAMEBUFFER) += fbfront/ ++obj-$(CONFIG_XEN_KEYBOARD) += fbfront/ ++obj-$(CONFIG_XEN_SCSI_BACKEND) += scsiback/ ++obj-$(CONFIG_XEN_SCSI_FRONTEND) += scsifront/ ++obj-$(CONFIG_XEN_PRIVCMD) += privcmd/ ++obj-$(CONFIG_XEN_GRANT_DEV) += gntdev/ ++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL) += sfc_netutil/ ++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND) += sfc_netfront/ ++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND) += sfc_netback/ +Index: head-2008-11-25/drivers/xen/xenbus/Makefile +=================================================================== +--- head-2008-11-25.orig/drivers/xen/xenbus/Makefile 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/xenbus/Makefile 2008-11-25 12:35:56.000000000 +0100 +@@ -1,7 +1,9 @@ +-obj-y += xenbus.o ++obj-y += xenbus_client.o xenbus_comms.o xenbus_xs.o xenbus_probe.o ++obj-$(CONFIG_XEN_BACKEND) += xenbus_be.o + +-xenbus-objs = +-xenbus-objs += xenbus_client.o +-xenbus-objs += xenbus_comms.o +-xenbus-objs += xenbus_xs.o +-xenbus-objs += xenbus_probe.o ++xenbus_be-objs = ++xenbus_be-objs += xenbus_backend_client.o ++ ++xenbus-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o ++obj-y += $(xenbus-y) $(xenbus-m) ++obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o +Index: head-2008-11-25/drivers/xen/xenbus/xenbus_client.c +=================================================================== +--- head-2008-11-25.orig/drivers/xen/xenbus/xenbus_client.c 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/xenbus/xenbus_client.c 2008-11-25 12:35:56.000000000 +0100 +@@ -30,14 +30,18 @@ + * IN THE SOFTWARE. + */ + +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include ++#include ++#include + #include ++#include ++ ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include ++#endif ++ ++#define DPRINTK(fmt, args...) \ ++ pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) + + const char *xenbus_strstate(enum xenbus_state state) + { +@@ -54,20 +58,6 @@ const char *xenbus_strstate(enum xenbus_ + } + EXPORT_SYMBOL_GPL(xenbus_strstate); + +-/** +- * xenbus_watch_path - register a watch +- * @dev: xenbus device +- * @path: path to watch +- * @watch: watch to register +- * @callback: callback to register +- * +- * Register a @watch on the given path, using the given xenbus_watch structure +- * for storage, and the given @callback function as the callback. Return 0 on +- * success, or -errno on error. On success, the given @path will be saved as +- * @watch->node, and remains the caller's to free. On error, @watch->node will +- * be NULL, the device will switch to %XenbusStateClosing, and the error will +- * be saved in the store. +- */ + int xenbus_watch_path(struct xenbus_device *dev, const char *path, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, +@@ -91,58 +81,26 @@ int xenbus_watch_path(struct xenbus_devi + EXPORT_SYMBOL_GPL(xenbus_watch_path); + + +-/** +- * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path +- * @dev: xenbus device +- * @watch: watch to register +- * @callback: callback to register +- * @pathfmt: format of path to watch +- * +- * Register a watch on the given @path, using the given xenbus_watch +- * structure for storage, and the given @callback function as the callback. +- * Return 0 on success, or -errno on error. On success, the watched path +- * (@path/@path2) will be saved as @watch->node, and becomes the caller's to +- * kfree(). On error, watch->node will be NULL, so the caller has nothing to +- * free, the device will switch to %XenbusStateClosing, and the error will be +- * saved in the store. +- */ +-int xenbus_watch_pathfmt(struct xenbus_device *dev, +- struct xenbus_watch *watch, +- void (*callback)(struct xenbus_watch *, +- const char **, unsigned int), +- const char *pathfmt, ...) ++int xenbus_watch_path2(struct xenbus_device *dev, const char *path, ++ const char *path2, struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int)) + { + int err; +- va_list ap; +- char *path; +- +- va_start(ap, pathfmt); +- path = kvasprintf(GFP_NOIO | __GFP_HIGH, pathfmt, ap); +- va_end(ap); +- +- if (!path) { ++ char *state = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/%s", path, path2); ++ if (!state) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); + return -ENOMEM; + } +- err = xenbus_watch_path(dev, path, watch, callback); ++ err = xenbus_watch_path(dev, state, watch, callback); + + if (err) +- kfree(path); ++ kfree(state); + return err; + } +-EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt); ++EXPORT_SYMBOL_GPL(xenbus_watch_path2); + + +-/** +- * xenbus_switch_state +- * @dev: xenbus device +- * @xbt: transaction handle +- * @state: new state +- * +- * Advertise in the store a change of the given driver to the given new_state. +- * Return 0 on success, or -errno on error. On error, the device will switch +- * to XenbusStateClosing, and the error will be saved in the store. +- */ + int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state) + { + /* We check whether the state is currently set to the given value, and +@@ -201,13 +159,12 @@ static char *error_path(struct xenbus_de + } + + +-static void xenbus_va_dev_error(struct xenbus_device *dev, int err, +- const char *fmt, va_list ap) ++void _dev_error(struct xenbus_device *dev, int err, const char *fmt, ++ va_list ap) + { + int ret; + unsigned int len; +- char *printf_buffer = NULL; +- char *path_buffer = NULL; ++ char *printf_buffer = NULL, *path_buffer = NULL; + + #define PRINTF_BUFFER_SIZE 4096 + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); +@@ -224,74 +181,51 @@ static void xenbus_va_dev_error(struct x + path_buffer = error_path(dev); + + if (path_buffer == NULL) { +- dev_err(&dev->dev, "failed to write error node for %s (%s)\n", ++ printk("xenbus: failed to write error node for %s (%s)\n", + dev->nodename, printf_buffer); + goto fail; + } + + if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { +- dev_err(&dev->dev, "failed to write error node for %s (%s)\n", ++ printk("xenbus: failed to write error node for %s (%s)\n", + dev->nodename, printf_buffer); + goto fail; + } + + fail: +- kfree(printf_buffer); +- kfree(path_buffer); ++ if (printf_buffer) ++ kfree(printf_buffer); ++ if (path_buffer) ++ kfree(path_buffer); + } + + +-/** +- * xenbus_dev_error +- * @dev: xenbus device +- * @err: error to report +- * @fmt: error message format +- * +- * Report the given negative errno into the store, along with the given +- * formatted message. +- */ +-void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) ++void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ++ ...) + { + va_list ap; + + va_start(ap, fmt); +- xenbus_va_dev_error(dev, err, fmt, ap); ++ _dev_error(dev, err, fmt, ap); + va_end(ap); + } + EXPORT_SYMBOL_GPL(xenbus_dev_error); + +-/** +- * xenbus_dev_fatal +- * @dev: xenbus device +- * @err: error to report +- * @fmt: error message format +- * +- * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by +- * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly +- * closedown of this driver and its peer. +- */ + +-void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...) ++void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ++ ...) + { + va_list ap; + + va_start(ap, fmt); +- xenbus_va_dev_error(dev, err, fmt, ap); ++ _dev_error(dev, err, fmt, ap); + va_end(ap); + + xenbus_switch_state(dev, XenbusStateClosing); + } + EXPORT_SYMBOL_GPL(xenbus_dev_fatal); + +-/** +- * xenbus_grant_ring +- * @dev: xenbus device +- * @ring_mfn: mfn of ring to grant +- +- * Grant access to the given @ring_mfn to the peer of the given device. Return +- * 0 on success, or -errno on error. On error, the device will switch to +- * XenbusStateClosing, and the error will be saved in the store. +- */ ++ + int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) + { + int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); +@@ -302,18 +236,12 @@ int xenbus_grant_ring(struct xenbus_devi + EXPORT_SYMBOL_GPL(xenbus_grant_ring); + + +-/** +- * Allocate an event channel for the given xenbus_device, assigning the newly +- * created local port to *port. Return 0 on success, or -errno on error. On +- * error, the device will switch to XenbusStateClosing, and the error will be +- * saved in the store. +- */ + int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) + { + struct evtchn_alloc_unbound alloc_unbound; + int err; + +- alloc_unbound.dom = DOMID_SELF; ++ alloc_unbound.dom = DOMID_SELF; + alloc_unbound.remote_dom = dev->otherend_id; + + err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, +@@ -328,36 +256,6 @@ int xenbus_alloc_evtchn(struct xenbus_de + EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn); + + +-/** +- * Bind to an existing interdomain event channel in another domain. Returns 0 +- * on success and stores the local port in *port. On error, returns -errno, +- * switches the device to XenbusStateClosing, and saves the error in XenStore. +- */ +-int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port) +-{ +- struct evtchn_bind_interdomain bind_interdomain; +- int err; +- +- bind_interdomain.remote_dom = dev->otherend_id; +- bind_interdomain.remote_port = remote_port; +- +- err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, +- &bind_interdomain); +- if (err) +- xenbus_dev_fatal(dev, err, +- "binding to event channel %d from domain %d", +- remote_port, dev->otherend_id); +- else +- *port = bind_interdomain.local_port; +- +- return err; +-} +-EXPORT_SYMBOL_GPL(xenbus_bind_evtchn); +- +- +-/** +- * Free an existing event channel. Returns 0 on success or -errno on error. +- */ + int xenbus_free_evtchn(struct xenbus_device *dev, int port) + { + struct evtchn_close close; +@@ -374,189 +272,6 @@ int xenbus_free_evtchn(struct xenbus_dev + EXPORT_SYMBOL_GPL(xenbus_free_evtchn); + + +-/** +- * xenbus_map_ring_valloc +- * @dev: xenbus device +- * @gnt_ref: grant reference +- * @vaddr: pointer to address to be filled out by mapping +- * +- * Based on Rusty Russell's skeleton driver's map_page. +- * Map a page of memory into this domain from another domain's grant table. +- * xenbus_map_ring_valloc allocates a page of virtual address space, maps the +- * page to that address, and sets *vaddr to that address. +- * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) +- * or -ENOMEM on error. If an error is returned, device will switch to +- * XenbusStateClosing and the error message will be saved in XenStore. +- */ +-int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) +-{ +- struct gnttab_map_grant_ref op = { +- .flags = GNTMAP_host_map, +- .ref = gnt_ref, +- .dom = dev->otherend_id, +- }; +- struct vm_struct *area; +- +- *vaddr = NULL; +- +- area = xen_alloc_vm_area(PAGE_SIZE); +- if (!area) +- return -ENOMEM; +- +- op.host_addr = (unsigned long)area->addr; +- +- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) +- BUG(); +- +- if (op.status != GNTST_okay) { +- xen_free_vm_area(area); +- xenbus_dev_fatal(dev, op.status, +- "mapping in shared page %d from domain %d", +- gnt_ref, dev->otherend_id); +- return op.status; +- } +- +- /* Stuff the handle in an unused field */ +- area->phys_addr = (unsigned long)op.handle; +- +- *vaddr = area->addr; +- return 0; +-} +-EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); +- +- +-/** +- * xenbus_map_ring +- * @dev: xenbus device +- * @gnt_ref: grant reference +- * @handle: pointer to grant handle to be filled +- * @vaddr: address to be mapped to +- * +- * Map a page of memory into this domain from another domain's grant table. +- * xenbus_map_ring does not allocate the virtual address space (you must do +- * this yourself!). It only maps in the page to the specified address. +- * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) +- * or -ENOMEM on error. If an error is returned, device will switch to +- * XenbusStateClosing and the error message will be saved in XenStore. +- */ +-int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, +- grant_handle_t *handle, void *vaddr) +-{ +- struct gnttab_map_grant_ref op = { +- .host_addr = (unsigned long)vaddr, +- .flags = GNTMAP_host_map, +- .ref = gnt_ref, +- .dom = dev->otherend_id, +- }; +- +- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) +- BUG(); +- +- if (op.status != GNTST_okay) { +- xenbus_dev_fatal(dev, op.status, +- "mapping in shared page %d from domain %d", +- gnt_ref, dev->otherend_id); +- } else +- *handle = op.handle; +- +- return op.status; +-} +-EXPORT_SYMBOL_GPL(xenbus_map_ring); +- +- +-/** +- * xenbus_unmap_ring_vfree +- * @dev: xenbus device +- * @vaddr: addr to unmap +- * +- * Based on Rusty Russell's skeleton driver's unmap_page. +- * Unmap a page of memory in this domain that was imported from another domain. +- * Use xenbus_unmap_ring_vfree if you mapped in your memory with +- * xenbus_map_ring_valloc (it will free the virtual address space). +- * Returns 0 on success and returns GNTST_* on error +- * (see xen/include/interface/grant_table.h). +- */ +-int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) +-{ +- struct vm_struct *area; +- struct gnttab_unmap_grant_ref op = { +- .host_addr = (unsigned long)vaddr, +- }; +- +- /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) +- * method so that we don't have to muck with vmalloc internals here. +- * We could force the user to hang on to their struct vm_struct from +- * xenbus_map_ring_valloc, but these 6 lines considerably simplify +- * this API. +- */ +- read_lock(&vmlist_lock); +- for (area = vmlist; area != NULL; area = area->next) { +- if (area->addr == vaddr) +- break; +- } +- read_unlock(&vmlist_lock); +- +- if (!area) { +- xenbus_dev_error(dev, -ENOENT, +- "can't find mapped virtual address %p", vaddr); +- return GNTST_bad_virt_addr; +- } +- +- op.handle = (grant_handle_t)area->phys_addr; +- +- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) +- BUG(); +- +- if (op.status == GNTST_okay) +- xen_free_vm_area(area); +- else +- xenbus_dev_error(dev, op.status, +- "unmapping page at handle %d error %d", +- (int16_t)area->phys_addr, op.status); +- +- return op.status; +-} +-EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); +- +- +-/** +- * xenbus_unmap_ring +- * @dev: xenbus device +- * @handle: grant handle +- * @vaddr: addr to unmap +- * +- * Unmap a page of memory in this domain that was imported from another domain. +- * Returns 0 on success and returns GNTST_* on error +- * (see xen/include/interface/grant_table.h). +- */ +-int xenbus_unmap_ring(struct xenbus_device *dev, +- grant_handle_t handle, void *vaddr) +-{ +- struct gnttab_unmap_grant_ref op = { +- .host_addr = (unsigned long)vaddr, +- .handle = handle, +- }; +- +- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) +- BUG(); +- +- if (op.status != GNTST_okay) +- xenbus_dev_error(dev, op.status, +- "unmapping page at handle %d error %d", +- handle, op.status); +- +- return op.status; +-} +-EXPORT_SYMBOL_GPL(xenbus_unmap_ring); +- +- +-/** +- * xenbus_read_driver_state +- * @path: path for driver +- * +- * Return the state of the driver rooted at the given store path, or +- * XenbusStateUnknown if no state can be read. +- */ + enum xenbus_state xenbus_read_driver_state(const char *path) + { + enum xenbus_state result; +Index: head-2008-11-25/drivers/xen/xenbus/xenbus_comms.c +=================================================================== +--- head-2008-11-25.orig/drivers/xen/xenbus/xenbus_comms.c 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/xenbus/xenbus_comms.c 2008-11-25 12:35:56.000000000 +0100 +@@ -34,19 +34,28 @@ + #include + #include + #include ++#include ++#include ++#include + #include +-#include +-#include +-#include ++ ++#include ++ + #include "xenbus_comms.h" + ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include ++#endif ++ + static int xenbus_irq; + +-static DECLARE_WORK(probe_work, xenbus_probe); ++extern void xenbus_probe(void *); ++extern int xenstored_ready; ++static DECLARE_WORK(probe_work, xenbus_probe, NULL); + + static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); + +-static irqreturn_t wake_waiting(int irq, void *unused) ++static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs) + { + if (unlikely(xenstored_ready == 0)) { + xenstored_ready = 1; +@@ -82,13 +91,6 @@ static const void *get_input_chunk(XENST + return buf + MASK_XENSTORE_IDX(cons); + } + +-/** +- * xb_write - low level write +- * @data: buffer to send +- * @len: length of buffer +- * +- * Returns 0 on success, error otherwise. +- */ + int xb_write(const void *data, unsigned len) + { + struct xenstore_domain_interface *intf = xen_store_interface; +@@ -197,12 +199,11 @@ int xb_read(void *data, unsigned len) + return 0; + } + +-/** +- * xb_init_comms - Set up interrupt handler off store event channel. +- */ ++/* Set up interrupt handler off store event channel. */ + int xb_init_comms(void) + { + struct xenstore_domain_interface *intf = xen_store_interface; ++ int err; + + if (intf->req_prod != intf->req_cons) + printk(KERN_ERR "XENBUS request ring is not quiescent " +@@ -215,20 +216,18 @@ int xb_init_comms(void) + intf->rsp_cons = intf->rsp_prod; + } + +- if (xenbus_irq) { +- /* Already have an irq; assume we're resuming */ +- rebind_evtchn_irq(xen_store_evtchn, xenbus_irq); +- } else { +- int err; +- err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting, +- 0, "xenbus", &xb_waitq); +- if (err <= 0) { +- printk(KERN_ERR "XENBUS request irq failed %i\n", err); +- return err; +- } ++ if (xenbus_irq) ++ unbind_from_irqhandler(xenbus_irq, &xb_waitq); + +- xenbus_irq = err; ++ err = bind_caller_port_to_irqhandler( ++ xen_store_evtchn, wake_waiting, ++ 0, "xenbus", &xb_waitq); ++ if (err <= 0) { ++ printk(KERN_ERR "XENBUS request irq failed %i\n", err); ++ return err; + } + ++ xenbus_irq = err; ++ + return 0; + } +Index: head-2008-11-25/drivers/xen/xenbus/xenbus_probe.c +=================================================================== +--- head-2008-11-25.orig/drivers/xen/xenbus/xenbus_probe.c 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/xenbus/xenbus_probe.c 2008-11-25 12:35:56.000000000 +0100 +@@ -4,6 +4,7 @@ + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * Copyright (C) 2005, 2006 XenSource Ltd ++ * Copyright (C) 2007 Solarflare Communications, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 +@@ -32,7 +33,7 @@ + + #define DPRINTK(fmt, args...) \ + pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \ +- __func__, __LINE__, ##args) ++ __FUNCTION__, __LINE__, ##args) + + #include + #include +@@ -41,24 +42,35 @@ + #include + #include + #include +-#include + #include +-#include ++#include + ++#include + #include ++#include + #include +-#include ++#include + #include +-#include +-#include ++#include ++#include ++#include ++#ifdef MODULE ++#include ++#endif + + #include "xenbus_comms.h" + #include "xenbus_probe.h" + ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include ++#endif ++ + int xen_store_evtchn; + struct xenstore_domain_interface *xen_store_interface; + static unsigned long xen_store_mfn; + ++extern struct mutex xenwatch_mutex; ++ + static BLOCKING_NOTIFIER_HEAD(xenstore_chain); + + static void wait_for_devices(struct xenbus_driver *xendrv); +@@ -88,16 +100,6 @@ int xenbus_match(struct device *_dev, st + return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; + } + +-static int xenbus_uevent(struct device *_dev, struct kobj_uevent_env *env) +-{ +- struct xenbus_device *dev = to_xenbus_device(_dev); +- +- if (add_uevent_var(env, "MODALIAS=xen:%s", dev->devicetype)) +- return -ENOMEM; +- +- return 0; +-} +- + /* device// => - */ + static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) + { +@@ -166,6 +168,30 @@ static int read_backend_details(struct x + return read_otherend_details(xendev, "backend-id", "backend"); + } + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++static int xenbus_uevent_frontend(struct device *dev, char **envp, ++ int num_envp, char *buffer, int buffer_size) ++{ ++ struct xenbus_device *xdev; ++ int length = 0, i = 0; ++ ++ if (dev == NULL) ++ return -ENODEV; ++ xdev = to_xenbus_device(dev); ++ if (xdev == NULL) ++ return -ENODEV; ++ ++ /* stuff we want to pass to /sbin/hotplug */ ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "XENBUS_TYPE=%s", xdev->devicetype); ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "XENBUS_PATH=%s", xdev->nodename); ++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, ++ "MODALIAS=xen:%s", xdev->devicetype); ++ ++ return 0; ++} ++#endif + + /* Bus type for frontend drivers. */ + static struct xen_bus_type xenbus_frontend = { +@@ -173,13 +199,19 @@ static struct xen_bus_type xenbus_fronte + .levels = 2, /* device/type/ */ + .get_bus_id = frontend_bus_id, + .probe = xenbus_probe_frontend, ++ .error = -ENODEV, + .bus = { + .name = "xen", + .match = xenbus_match, +- .uevent = xenbus_uevent, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, ++ .uevent = xenbus_uevent_frontend, ++#endif ++ }, ++ .dev = { ++ .bus_id = "xen", + }, + }; + +@@ -196,17 +228,16 @@ static void otherend_changed(struct xenb + if (!dev->otherend || + strncmp(dev->otherend, vec[XS_WATCH_PATH], + strlen(dev->otherend))) { +- dev_dbg(&dev->dev, "Ignoring watch at %s\n", +- vec[XS_WATCH_PATH]); ++ DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); + return; + } + + state = xenbus_read_driver_state(dev->otherend); + +- dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n", +- state, xenbus_strstate(state), dev->otherend_watch.node, +- vec[XS_WATCH_PATH]); ++ DPRINTK("state is %d (%s), %s, %s", state, xenbus_strstate(state), ++ dev->otherend_watch.node, vec[XS_WATCH_PATH]); + ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) + /* + * Ignore xenbus transitions during shutdown. This prevents us doing + * work that can fail e.g., when the rootfs is gone. +@@ -220,6 +251,7 @@ static void otherend_changed(struct xenb + xenbus_frontend_closed(dev); + return; + } ++#endif + + if (drv->otherend_changed) + drv->otherend_changed(dev, state); +@@ -239,8 +271,8 @@ static int talk_to_otherend(struct xenbu + + static int watch_otherend(struct xenbus_device *dev) + { +- return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed, +- "%s/%s", dev->otherend, "state"); ++ return xenbus_watch_path2(dev, dev->otherend, "state", ++ &dev->otherend_watch, otherend_changed); + } + + +@@ -266,8 +298,9 @@ int xenbus_dev_probe(struct device *_dev + + err = talk_to_otherend(dev); + if (err) { +- dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n", +- dev->nodename); ++ printk(KERN_WARNING ++ "xenbus_probe: talk_to_otherend on %s failed.\n", ++ dev->nodename); + return err; + } + +@@ -277,7 +310,8 @@ int xenbus_dev_probe(struct device *_dev + + err = watch_otherend(dev); + if (err) { +- dev_warn(&dev->dev, "watch_otherend on %s failed.\n", ++ printk(KERN_WARNING ++ "xenbus_probe: watch_otherend on %s failed.\n", + dev->nodename); + return err; + } +@@ -313,43 +347,55 @@ static void xenbus_dev_shutdown(struct d + + DPRINTK("%s", dev->nodename); + ++ if (is_initial_xendomain()) ++ return; ++ + get_device(&dev->dev); + if (dev->state != XenbusStateConnected) { +- printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__, ++ printk("%s: %s: %s != Connected, skipping\n", __FUNCTION__, + dev->nodename, xenbus_strstate(dev->state)); + goto out; + } + xenbus_switch_state(dev, XenbusStateClosing); + timeout = wait_for_completion_timeout(&dev->down, timeout); + if (!timeout) +- printk(KERN_INFO "%s: %s timeout closing device\n", +- __func__, dev->nodename); ++ printk("%s: %s timeout closing device\n", __FUNCTION__, dev->nodename); + out: + put_device(&dev->dev); + } + + int xenbus_register_driver_common(struct xenbus_driver *drv, +- struct xen_bus_type *bus, +- struct module *owner, +- const char *mod_name) ++ struct xen_bus_type *bus) + { ++ int ret; ++ ++ if (bus->error) ++ return bus->error; ++ + drv->driver.name = drv->name; + drv->driver.bus = &bus->bus; +- drv->driver.owner = owner; +- drv->driver.mod_name = mod_name; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) ++ drv->driver.owner = drv->owner; ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++ drv->driver.probe = xenbus_dev_probe; ++ drv->driver.remove = xenbus_dev_remove; ++ drv->driver.shutdown = xenbus_dev_shutdown; ++#endif + +- return driver_register(&drv->driver); ++ mutex_lock(&xenwatch_mutex); ++ ret = driver_register(&drv->driver); ++ mutex_unlock(&xenwatch_mutex); ++ return ret; + } + +-int __xenbus_register_frontend(struct xenbus_driver *drv, +- struct module *owner, const char *mod_name) ++int xenbus_register_frontend(struct xenbus_driver *drv) + { + int ret; + + drv->read_otherend_details = read_backend_details; + +- ret = xenbus_register_driver_common(drv, &xenbus_frontend, +- owner, mod_name); ++ ret = xenbus_register_driver_common(drv, &xenbus_frontend); + if (ret) + return ret; + +@@ -358,7 +404,7 @@ int __xenbus_register_frontend(struct xe + + return 0; + } +-EXPORT_SYMBOL_GPL(__xenbus_register_frontend); ++EXPORT_SYMBOL_GPL(xenbus_register_frontend); + + void xenbus_unregister_driver(struct xenbus_driver *drv) + { +@@ -436,25 +482,25 @@ static void xenbus_dev_release(struct de + } + + static ssize_t xendev_show_nodename(struct device *dev, +- struct device_attribute *attr, char *buf) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) ++ struct device_attribute *attr, ++#endif ++ char *buf) + { + return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); + } + DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); + + static ssize_t xendev_show_devtype(struct device *dev, +- struct device_attribute *attr, char *buf) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) ++ struct device_attribute *attr, ++#endif ++ char *buf) + { + return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); + } + DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); + +-static ssize_t xendev_show_modalias(struct device *dev, +- struct device_attribute *attr, char *buf) +-{ +- return sprintf(buf, "xen:%s\n", to_xenbus_device(dev)->devicetype); +-} +-DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL); + + int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, +@@ -467,6 +513,9 @@ int xenbus_probe_node(struct xen_bus_typ + + enum xenbus_state state = xenbus_read_driver_state(nodename); + ++ if (bus->error) ++ return bus->error; ++ + if (state != XenbusStateInitialising) { + /* Device is not new, so ignore it. This can happen if a + device is going away after switching to Closed. */ +@@ -491,6 +540,7 @@ int xenbus_probe_node(struct xen_bus_typ + xendev->devicetype = tmpstring; + init_completion(&xendev->down); + ++ xendev->dev.parent = &bus->dev; + xendev->dev.bus = &bus->bus; + xendev->dev.release = xenbus_dev_release; + +@@ -505,22 +555,15 @@ int xenbus_probe_node(struct xen_bus_typ + + err = device_create_file(&xendev->dev, &dev_attr_nodename); + if (err) +- goto fail_unregister; +- ++ goto unregister; + err = device_create_file(&xendev->dev, &dev_attr_devtype); + if (err) +- goto fail_remove_nodename; +- +- err = device_create_file(&xendev->dev, &dev_attr_modalias); +- if (err) +- goto fail_remove_devtype; ++ goto unregister; + + return 0; +-fail_remove_devtype: +- device_remove_file(&xendev->dev, &dev_attr_devtype); +-fail_remove_nodename: ++unregister: + device_remove_file(&xendev->dev, &dev_attr_nodename); +-fail_unregister: ++ device_remove_file(&xendev->dev, &dev_attr_devtype); + device_unregister(&xendev->dev); + fail: + kfree(xendev); +@@ -533,8 +576,7 @@ static int xenbus_probe_frontend(const c + char *nodename; + int err; + +- nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", +- xenbus_frontend.root, type, name); ++ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_frontend.root, type, name); + if (!nodename) + return -ENOMEM; + +@@ -571,6 +613,9 @@ int xenbus_probe_devices(struct xen_bus_ + char **dir; + unsigned int i, dir_n; + ++ if (bus->error) ++ return bus->error; ++ + dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); + if (IS_ERR(dir)) + return PTR_ERR(dir); +@@ -607,15 +652,15 @@ static int strsep_len(const char *str, c + return (len == 0) ? i : -ERANGE; + } + +-void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) ++void dev_changed(const char *node, struct xen_bus_type *bus) + { + int exists, rootlen; + struct xenbus_device *dev; + char type[BUS_ID_SIZE]; + const char *p, *root; + +- if (char_count(node, '/') < 2) +- return; ++ if (bus->error || char_count(node, '/') < 2) ++ return; + + exists = xenbus_exists(XBT_NIL, node, ""); + if (!exists) { +@@ -649,7 +694,7 @@ static void frontend_changed(struct xenb + { + DPRINTK(""); + +- xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); ++ dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); + } + + /* We watch for devices appearing and vanishing. */ +@@ -748,7 +793,8 @@ void xenbus_suspend(void) + { + DPRINTK(""); + +- bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); ++ if (!xenbus_frontend.error) ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); + xenbus_backend_suspend(suspend_dev); + xs_suspend(); + } +@@ -758,7 +804,8 @@ void xenbus_resume(void) + { + xb_init_comms(); + xs_resume(); +- bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); ++ if (!xenbus_frontend.error) ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); + xenbus_backend_resume(resume_dev); + } + EXPORT_SYMBOL_GPL(xenbus_resume); +@@ -766,7 +813,8 @@ EXPORT_SYMBOL_GPL(xenbus_resume); + void xenbus_suspend_cancel(void) + { + xs_suspend_cancel(); +- bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev); ++ if (!xenbus_frontend.error) ++ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev); + xenbus_backend_resume(suspend_cancel_dev); + } + EXPORT_SYMBOL_GPL(xenbus_suspend_cancel); +@@ -794,7 +842,8 @@ void unregister_xenstore_notifier(struct + } + EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); + +-void xenbus_probe(struct work_struct *unused) ++ ++void xenbus_probe(void *unused) + { + BUG_ON((xenstored_ready <= 0)); + +@@ -807,63 +856,171 @@ void xenbus_probe(struct work_struct *un + blocking_notifier_call_chain(&xenstore_chain, 0, NULL); + } + +-static int __init xenbus_probe_init(void) ++ ++#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST) ++static struct file_operations xsd_kva_fops; ++static struct proc_dir_entry *xsd_kva_intf; ++static struct proc_dir_entry *xsd_port_intf; ++ ++static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ size_t size = vma->vm_end - vma->vm_start; ++ ++ if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0)) ++ return -EINVAL; ++ ++ if (remap_pfn_range(vma, vma->vm_start, mfn_to_pfn(xen_store_mfn), ++ size, vma->vm_page_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static int xsd_kva_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "0x%p", xen_store_interface); ++ *eof = 1; ++ return len; ++} ++ ++static int xsd_port_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d", xen_store_evtchn); ++ *eof = 1; ++ return len; ++} ++#endif ++ ++static int xenbus_probe_init(void) + { + int err = 0; ++ unsigned long page = 0; + + DPRINTK(""); + +- err = -ENODEV; + if (!is_running_on_xen()) +- goto out_error; ++ return -ENODEV; + + /* Register ourselves with the kernel bus subsystem */ +- err = bus_register(&xenbus_frontend.bus); +- if (err) +- goto out_error; +- +- err = xenbus_backend_bus_register(); +- if (err) +- goto out_unreg_front; ++ xenbus_frontend.error = bus_register(&xenbus_frontend.bus); ++ if (xenbus_frontend.error) ++ printk(KERN_WARNING ++ "XENBUS: Error registering frontend bus: %i\n", ++ xenbus_frontend.error); ++ xenbus_backend_bus_register(); + + /* + * Domain0 doesn't have a store_evtchn or store_mfn yet. + */ + if (is_initial_xendomain()) { +- /* dom0 not yet supported */ ++ struct evtchn_alloc_unbound alloc_unbound; ++ ++ /* Allocate page. */ ++ page = get_zeroed_page(GFP_KERNEL); ++ if (!page) ++ return -ENOMEM; ++ ++ xen_store_mfn = xen_start_info->store_mfn = ++ pfn_to_mfn(virt_to_phys((void *)page) >> ++ PAGE_SHIFT); ++ ++ /* Next allocate a local port which xenstored can bind to */ ++ alloc_unbound.dom = DOMID_SELF; ++ alloc_unbound.remote_dom = 0; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, ++ &alloc_unbound); ++ if (err == -ENOSYS) ++ goto err; ++ BUG_ON(err); ++ xen_store_evtchn = xen_start_info->store_evtchn = ++ alloc_unbound.port; ++ ++#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST) ++ /* And finally publish the above info in /proc/xen */ ++ xsd_kva_intf = create_xen_proc_entry("xsd_kva", 0600); ++ if (xsd_kva_intf) { ++ memcpy(&xsd_kva_fops, xsd_kva_intf->proc_fops, ++ sizeof(xsd_kva_fops)); ++ xsd_kva_fops.mmap = xsd_kva_mmap; ++ xsd_kva_intf->proc_fops = &xsd_kva_fops; ++ xsd_kva_intf->read_proc = xsd_kva_read; ++ } ++ xsd_port_intf = create_xen_proc_entry("xsd_port", 0400); ++ if (xsd_port_intf) ++ xsd_port_intf->read_proc = xsd_port_read; ++#endif ++ xen_store_interface = mfn_to_virt(xen_store_mfn); + } else { + xenstored_ready = 1; ++#ifdef CONFIG_XEN + xen_store_evtchn = xen_start_info->store_evtchn; + xen_store_mfn = xen_start_info->store_mfn; ++ xen_store_interface = mfn_to_virt(xen_store_mfn); ++#else ++ xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); ++ xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); ++ xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, ++ PAGE_SIZE); ++#endif + } +- xen_store_interface = mfn_to_virt(xen_store_mfn); ++ ++ ++ xenbus_dev_init(); + + /* Initialize the interface to xenstore. */ + err = xs_init(); + if (err) { + printk(KERN_WARNING + "XENBUS: Error initializing xenstore comms: %i\n", err); +- goto out_unreg_back; ++ goto err; + } + ++ /* Register ourselves with the kernel device subsystem */ ++ if (!xenbus_frontend.error) { ++ xenbus_frontend.error = device_register(&xenbus_frontend.dev); ++ if (xenbus_frontend.error) { ++ bus_unregister(&xenbus_frontend.bus); ++ printk(KERN_WARNING ++ "XENBUS: Error registering frontend device: %i\n", ++ xenbus_frontend.error); ++ } ++ } ++ xenbus_backend_device_register(); ++ + if (!is_initial_xendomain()) + xenbus_probe(NULL); + + return 0; + +- out_unreg_back: +- xenbus_backend_bus_unregister(); ++ err: ++ if (page) ++ free_page(page); + +- out_unreg_front: +- bus_unregister(&xenbus_frontend.bus); ++ /* ++ * Do not unregister the xenbus front/backend buses here. The buses ++ * must exist because front/backend drivers will use them when they are ++ * registered. ++ */ + +- out_error: + return err; + } + ++#ifdef CONFIG_XEN + postcore_initcall(xenbus_probe_init); +- +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("Dual BSD/GPL"); ++#else ++int xenbus_init(void) ++{ ++ return xenbus_probe_init(); ++} ++#endif + + static int is_disconnected_device(struct device *dev, void *data) + { +@@ -883,12 +1040,14 @@ static int is_disconnected_device(struct + return 0; + + xendrv = to_xenbus_driver(dev->driver); +- return (xendev->state != XenbusStateConnected || ++ return (xendev->state < XenbusStateConnected || + (xendrv->is_ready && !xendrv->is_ready(xendev))); + } + + static int exists_disconnected_device(struct device_driver *drv) + { ++ if (xenbus_frontend.error) ++ return xenbus_frontend.error; + return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, + is_disconnected_device); + } +@@ -897,6 +1056,7 @@ static int print_device_status(struct de + { + struct xenbus_device *xendev = to_xenbus_device(dev); + struct device_driver *drv = data; ++ struct xenbus_driver *xendrv; + + /* Is this operation limited to a particular driver? */ + if (drv && (dev->driver != drv)) +@@ -906,12 +1066,23 @@ static int print_device_status(struct de + /* Information only: is this too noisy? */ + printk(KERN_INFO "XENBUS: Device with no driver: %s\n", + xendev->nodename); +- } else if (xendev->state != XenbusStateConnected) { ++ return 0; ++ } ++ ++ if (xendev->state < XenbusStateConnected) { ++ enum xenbus_state rstate = XenbusStateUnknown; ++ if (xendev->otherend) ++ rstate = xenbus_read_driver_state(xendev->otherend); + printk(KERN_WARNING "XENBUS: Timeout connecting " +- "to device: %s (state %d)\n", +- xendev->nodename, xendev->state); ++ "to device: %s (local state %d, remote state %d)\n", ++ xendev->nodename, xendev->state, rstate); + } + ++ xendrv = to_xenbus_driver(dev->driver); ++ if (xendrv->is_ready && !xendrv->is_ready(xendev)) ++ printk(KERN_WARNING "XENBUS: Device not ready: %s\n", ++ xendev->nodename); ++ + return 0; + } + +@@ -919,7 +1090,7 @@ static int print_device_status(struct de + static int ready_to_wait_for_devices; + + /* +- * On a 10 second timeout, wait for all devices currently configured. We need ++ * On a 5-minute timeout, wait for all devices currently configured. We need + * to do this to guarantee that the filesystems and / or network devices + * needed for boot are available, before we can allow the boot to proceed. + * +@@ -934,18 +1105,30 @@ static int ready_to_wait_for_devices; + */ + static void wait_for_devices(struct xenbus_driver *xendrv) + { +- unsigned long timeout = jiffies + 10*HZ; ++ unsigned long start = jiffies; + struct device_driver *drv = xendrv ? &xendrv->driver : NULL; ++ unsigned int seconds_waited = 0; + + if (!ready_to_wait_for_devices || !is_running_on_xen()) + return; + + while (exists_disconnected_device(drv)) { +- if (time_after(jiffies, timeout)) +- break; ++ if (time_after(jiffies, start + (seconds_waited+5)*HZ)) { ++ if (!seconds_waited) ++ printk(KERN_WARNING "XENBUS: Waiting for " ++ "devices to initialise: "); ++ seconds_waited += 5; ++ printk("%us...", 300 - seconds_waited); ++ if (seconds_waited == 300) ++ break; ++ } ++ + schedule_timeout_interruptible(HZ/10); + } + ++ if (seconds_waited) ++ printk("\n"); ++ + bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, + print_device_status); + } +@@ -953,10 +1136,18 @@ static void wait_for_devices(struct xenb + #ifndef MODULE + static int __init boot_wait_for_devices(void) + { +- ready_to_wait_for_devices = 1; +- wait_for_devices(NULL); ++ if (!xenbus_frontend.error) { ++ ready_to_wait_for_devices = 1; ++ wait_for_devices(NULL); ++ } + return 0; + } + + late_initcall(boot_wait_for_devices); + #endif ++ ++int xenbus_for_each_frontend(void *arg, int (*fn)(struct device *, void *)) ++{ ++ return bus_for_each_dev(&xenbus_frontend.bus, NULL, arg, fn); ++} ++EXPORT_SYMBOL_GPL(xenbus_for_each_frontend); +Index: head-2008-11-25/drivers/xen/xenbus/xenbus_probe.h +=================================================================== +--- head-2008-11-25.orig/drivers/xen/xenbus/xenbus_probe.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/xenbus/xenbus_probe.h 2008-11-25 12:35:56.000000000 +0100 +@@ -34,41 +34,42 @@ + #ifndef _XENBUS_PROBE_H + #define _XENBUS_PROBE_H + +-#ifdef CONFIG_XEN_BACKEND ++#if defined(CONFIG_XEN_BACKEND) || defined(CONFIG_XEN_BACKEND_MODULE) + extern void xenbus_backend_suspend(int (*fn)(struct device *, void *)); + extern void xenbus_backend_resume(int (*fn)(struct device *, void *)); + extern void xenbus_backend_probe_and_watch(void); +-extern int xenbus_backend_bus_register(void); +-extern void xenbus_backend_bus_unregister(void); ++extern void xenbus_backend_bus_register(void); ++extern void xenbus_backend_device_register(void); + #else + static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {} + static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {} + static inline void xenbus_backend_probe_and_watch(void) {} +-static inline int xenbus_backend_bus_register(void) { return 0; } +-static inline void xenbus_backend_bus_unregister(void) {} ++static inline void xenbus_backend_bus_register(void) {} ++static inline void xenbus_backend_device_register(void) {} + #endif + + struct xen_bus_type + { + char *root; ++ int error; + unsigned int levels; + int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); + int (*probe)(const char *type, const char *dir); + struct bus_type bus; ++ struct device dev; + }; + + extern int xenbus_match(struct device *_dev, struct device_driver *_drv); + extern int xenbus_dev_probe(struct device *_dev); + extern int xenbus_dev_remove(struct device *_dev); + extern int xenbus_register_driver_common(struct xenbus_driver *drv, +- struct xen_bus_type *bus, +- struct module *owner, +- const char *mod_name); ++ struct xen_bus_type *bus); + extern int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, + const char *nodename); + extern int xenbus_probe_devices(struct xen_bus_type *bus); + +-extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); ++extern void dev_changed(const char *node, struct xen_bus_type *bus); + + #endif ++ +Index: head-2008-11-25/drivers/xen/xenbus/xenbus_xs.c +=================================================================== +--- head-2008-11-25.orig/drivers/xen/xenbus/xenbus_xs.c 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/drivers/xen/xenbus/xenbus_xs.c 2008-11-25 12:35:56.000000000 +0100 +@@ -47,6 +47,14 @@ + #include + #include "xenbus_comms.h" + ++#ifdef HAVE_XEN_PLATFORM_COMPAT_H ++#include ++#endif ++ ++#ifndef PF_NOFREEZE /* Old kernel (pre-2.6.6). */ ++#define PF_NOFREEZE 0 ++#endif ++ + struct xs_stored_msg { + struct list_head list; + +@@ -108,7 +116,7 @@ static DEFINE_SPINLOCK(watch_events_lock + * carrying out work. + */ + static pid_t xenwatch_pid; +-static DEFINE_MUTEX(xenwatch_mutex); ++/* static */ DEFINE_MUTEX(xenwatch_mutex); + static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); + + static int get_error(const char *errorstring) +@@ -177,7 +185,7 @@ void *xenbus_dev_request_and_reply(struc + + mutex_unlock(&xs_state.request_mutex); + +- if ((msg->type == XS_TRANSACTION_END) || ++ if ((req_msg.type == XS_TRANSACTION_END) || + ((req_msg.type == XS_TRANSACTION_START) && + (msg->type == XS_ERROR))) + up_read(&xs_state.transaction_mutex); +@@ -213,7 +221,7 @@ static void *xs_talkv(struct xenbus_tran + } + + for (i = 0; i < num_vecs; i++) { +- err = xb_write(iovec[i].iov_base, iovec[i].iov_len); ++ err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; + if (err) { + mutex_unlock(&xs_state.request_mutex); + return ERR_PTR(err); +@@ -294,7 +302,7 @@ static char **split(char *strings, unsig + char *p, **ret; + + /* Count the strings. */ +- *num = count_strings(strings, len); ++ *num = count_strings(strings, len) + 1; + + /* Transfer to one big alloc for easy freeing. */ + ret = kmalloc(*num * sizeof(char *) + len, GFP_NOIO | __GFP_HIGH); +@@ -308,6 +316,7 @@ static char **split(char *strings, unsig + strings = (char *)&ret[*num]; + for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) + ret[(*num)++] = p; ++ ret[*num] = strings + len; + + return ret; + } +@@ -498,7 +507,7 @@ int xenbus_printf(struct xenbus_transact + #define PRINTF_BUFFER_SIZE 4096 + char *printf_buffer; + +- printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); ++ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_NOIO | __GFP_HIGH); + if (printf_buffer == NULL) + return -ENOMEM; + +@@ -621,6 +630,8 @@ void unregister_xenbus_watch(struct xenb + char token[sizeof(watch) * 2 + 1]; + int err; + ++ BUG_ON(watch->flags & XBWF_new_thread); ++ + sprintf(token, "%lX", (long)watch); + + down_read(&xs_state.watch_mutex); +@@ -638,11 +649,6 @@ void unregister_xenbus_watch(struct xenb + + up_read(&xs_state.watch_mutex); + +- /* Make sure there are no callbacks running currently (unless +- its us) */ +- if (current->pid != xenwatch_pid) +- mutex_lock(&xenwatch_mutex); +- + /* Cancel pending watch events. */ + spin_lock(&watch_events_lock); + list_for_each_entry_safe(msg, tmp, &watch_events, list) { +@@ -654,8 +660,11 @@ void unregister_xenbus_watch(struct xenb + } + spin_unlock(&watch_events_lock); + +- if (current->pid != xenwatch_pid) ++ /* Flush any currently-executing callback, unless we are it. :-) */ ++ if (current->pid != xenwatch_pid) { ++ mutex_lock(&xenwatch_mutex); + mutex_unlock(&xenwatch_mutex); ++ } + } + EXPORT_SYMBOL_GPL(unregister_xenbus_watch); + +@@ -693,11 +702,30 @@ void xs_suspend_cancel(void) + up_write(&xs_state.transaction_mutex); + } + ++static int xenwatch_handle_callback(void *data) ++{ ++ struct xs_stored_msg *msg = data; ++ ++ msg->u.watch.handle->callback(msg->u.watch.handle, ++ (const char **)msg->u.watch.vec, ++ msg->u.watch.vec_size); ++ ++ kfree(msg->u.watch.vec); ++ kfree(msg); ++ ++ /* Kill this kthread if we were spawned just for this callback. */ ++ if (current->pid != xenwatch_pid) ++ do_exit(0); ++ ++ return 0; ++} ++ + static int xenwatch_thread(void *unused) + { + struct list_head *ent; + struct xs_stored_msg *msg; + ++ current->flags |= PF_NOFREEZE; + for (;;) { + wait_event_interruptible(watch_events_waitq, + !list_empty(&watch_events)); +@@ -713,17 +741,29 @@ static int xenwatch_thread(void *unused) + list_del(ent); + spin_unlock(&watch_events_lock); + +- if (ent != &watch_events) { +- msg = list_entry(ent, struct xs_stored_msg, list); +- msg->u.watch.handle->callback( +- msg->u.watch.handle, +- (const char **)msg->u.watch.vec, +- msg->u.watch.vec_size); +- kfree(msg->u.watch.vec); +- kfree(msg); ++ if (ent == &watch_events) { ++ mutex_unlock(&xenwatch_mutex); ++ continue; + } + +- mutex_unlock(&xenwatch_mutex); ++ msg = list_entry(ent, struct xs_stored_msg, list); ++ ++ /* ++ * Unlock the mutex before running an XBWF_new_thread ++ * handler. kthread_run can block which can deadlock ++ * against unregister_xenbus_watch() if we need to ++ * unregister other watches in order to make ++ * progress. This can occur on resume before the swap ++ * device is attached. ++ */ ++ if (msg->u.watch.handle->flags & XBWF_new_thread) { ++ mutex_unlock(&xenwatch_mutex); ++ kthread_run(xenwatch_handle_callback, ++ msg, "xenwatch_cb"); ++ } else { ++ xenwatch_handle_callback(msg); ++ mutex_unlock(&xenwatch_mutex); ++ } + } + + return 0; +@@ -817,6 +857,7 @@ static int xenbus_thread(void *unused) + { + int err; + ++ current->flags |= PF_NOFREEZE; + for (;;) { + err = process_msg(); + if (err) +Index: head-2008-11-25/include/xen/balloon.h +=================================================================== +--- head-2008-11-25.orig/include/xen/balloon.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/balloon.h 2008-11-25 12:35:56.000000000 +0100 +@@ -31,12 +31,9 @@ + * IN THE SOFTWARE. + */ + +-#ifndef __XEN_BALLOON_H__ +-#define __XEN_BALLOON_H__ ++#ifndef __ASM_BALLOON_H__ ++#define __ASM_BALLOON_H__ + +-#include +- +-#if 0 + /* + * Inform the balloon driver that it should allow some slop for device-driver + * memory activities. +@@ -56,6 +53,5 @@ void balloon_release_driver_page(struct + extern spinlock_t balloon_lock; + #define balloon_lock(__flags) spin_lock_irqsave(&balloon_lock, __flags) + #define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags) +-#endif + +-#endif /* __XEN_BALLOON_H__ */ ++#endif /* __ASM_BALLOON_H__ */ +Index: head-2008-11-25/include/xen/interface/callback.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/callback.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/callback.h 2008-11-25 12:35:56.000000000 +0100 +@@ -86,6 +86,8 @@ struct callback_register { + uint16_t flags; + xen_callback_t address; + }; ++typedef struct callback_register callback_register_t; ++DEFINE_XEN_GUEST_HANDLE(callback_register_t); + + /* + * Unregister a callback. +@@ -98,5 +100,22 @@ struct callback_unregister { + uint16_t type; + uint16_t _unused; + }; ++typedef struct callback_unregister callback_unregister_t; ++DEFINE_XEN_GUEST_HANDLE(callback_unregister_t); ++ ++#if __XEN_INTERFACE_VERSION__ < 0x00030207 ++#undef CALLBACKTYPE_sysenter ++#define CALLBACKTYPE_sysenter CALLBACKTYPE_sysenter_deprecated ++#endif + + #endif /* __XEN_PUBLIC_CALLBACK_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/elfnote.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/elfnote.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/elfnote.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Definitions used for the Xen ELF notes. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2006, Ian Campbell, XenSource Ltd. + */ + +@@ -10,7 +28,7 @@ + #define __XEN_PUBLIC_ELFNOTE_H__ + + /* +- * The notes should live in a SHT_NOTE segment and have "Xen" in the ++ * The notes should live in a PT_NOTE segment and have "Xen" in the + * name field. + * + * Numeric types are either 4 or 8 bytes depending on the content of +@@ -22,8 +40,6 @@ + + /* + * NAME=VALUE pair (string). +- * +- * LEGACY: FEATURES and PAE + */ + #define XEN_ELFNOTE_INFO 0 + +@@ -90,7 +106,12 @@ + #define XEN_ELFNOTE_LOADER 8 + + /* +- * The kernel supports PAE (x86/32 only, string = "yes" or "no"). ++ * The kernel supports PAE (x86/32 only, string = "yes", "no" or ++ * "bimodal"). ++ * ++ * For compatibility with Xen 3.0.3 and earlier the "bimodal" setting ++ * may be given as "yes,bimodal" which will cause older Xen to treat ++ * this kernel as PAE. + * + * LEGACY: PAE (n.b. The legacy interface included a provision to + * indicate 'extended-cr3' support allowing L3 page tables to be +@@ -140,6 +161,65 @@ + */ + #define XEN_ELFNOTE_SUSPEND_CANCEL 14 + ++/* ++ * The number of the highest elfnote defined. ++ */ ++#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUSPEND_CANCEL ++ ++/* ++ * System information exported through crash notes. ++ * ++ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO ++ * note in case of a system crash. This note will contain various ++ * information about the system, see xen/include/xen/elfcore.h. ++ */ ++#define XEN_ELFNOTE_CRASH_INFO 0x1000001 ++ ++/* ++ * System registers exported through crash notes. ++ * ++ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS ++ * note per cpu in case of a system crash. This note is architecture ++ * specific and will contain registers not saved in the "CORE" note. ++ * See xen/include/xen/elfcore.h for more information. ++ */ ++#define XEN_ELFNOTE_CRASH_REGS 0x1000002 ++ ++ ++/* ++ * xen dump-core none note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_NONE ++ * in its dump file to indicate that the file is xen dump-core ++ * file. This note doesn't have any other information. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_NONE 0x2000000 ++ ++/* ++ * xen dump-core header note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_HEADER ++ * in its dump file. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_HEADER 0x2000001 ++ ++/* ++ * xen dump-core xen version note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_XEN_VERSION ++ * in its dump file. It contains the xen version obtained via the ++ * XENVER hypercall. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_XEN_VERSION 0x2000002 ++ ++/* ++ * xen dump-core format version note. ++ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION ++ * in its dump file. It contains a format version identifier. ++ * See tools/libxc/xc_core.h for more information. ++ */ ++#define XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION 0x2000003 ++ + #endif /* __XEN_PUBLIC_ELFNOTE_H__ */ + + /* +Index: head-2008-11-25/include/xen/interface/event_channel.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/event_channel.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/event_channel.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,14 +3,39 @@ + * + * Event channels between domains. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2003-2004, K A Fraser. + */ + + #ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__ + #define __XEN_PUBLIC_EVENT_CHANNEL_H__ + ++/* ++ * Prototype for this hypercall is: ++ * int event_channel_op(int cmd, void *args) ++ * @cmd == EVTCHNOP_??? (event-channel operation). ++ * @args == Operation-specific extra arguments (NULL if none). ++ */ ++ + typedef uint32_t evtchn_port_t; +-DEFINE_GUEST_HANDLE(evtchn_port_t); ++DEFINE_XEN_GUEST_HANDLE(evtchn_port_t); + + /* + * EVTCHNOP_alloc_unbound: Allocate a port in domain and mark as +@@ -20,13 +45,14 @@ DEFINE_GUEST_HANDLE(evtchn_port_t); + * 1. If the caller is unprivileged then must be DOMID_SELF. + * 2. may be DOMID_SELF, allowing loopback connections. + */ +-#define EVTCHNOP_alloc_unbound 6 ++#define EVTCHNOP_alloc_unbound 6 + struct evtchn_alloc_unbound { +- /* IN parameters */ +- domid_t dom, remote_dom; +- /* OUT parameters */ +- evtchn_port_t port; ++ /* IN parameters */ ++ domid_t dom, remote_dom; ++ /* OUT parameters */ ++ evtchn_port_t port; + }; ++typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t; + + /* + * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between +@@ -39,29 +65,35 @@ struct evtchn_alloc_unbound { + */ + #define EVTCHNOP_bind_interdomain 0 + struct evtchn_bind_interdomain { +- /* IN parameters. */ +- domid_t remote_dom; +- evtchn_port_t remote_port; +- /* OUT parameters. */ +- evtchn_port_t local_port; ++ /* IN parameters. */ ++ domid_t remote_dom; ++ evtchn_port_t remote_port; ++ /* OUT parameters. */ ++ evtchn_port_t local_port; + }; ++typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t; + + /* + * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ on specified + * vcpu. + * NOTES: +- * 1. A virtual IRQ may be bound to at most one event channel per vcpu. +- * 2. The allocated event channel is bound to the specified vcpu. The binding +- * may not be changed. ++ * 1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list ++ * in xen.h for the classification of each VIRQ. ++ * 2. Global VIRQs must be allocated on VCPU0 but can subsequently be ++ * re-bound via EVTCHNOP_bind_vcpu. ++ * 3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu. ++ * The allocated event channel is bound to the specified vcpu and the ++ * binding cannot be changed. + */ +-#define EVTCHNOP_bind_virq 1 ++#define EVTCHNOP_bind_virq 1 + struct evtchn_bind_virq { +- /* IN parameters. */ +- uint32_t virq; +- uint32_t vcpu; +- /* OUT parameters. */ +- evtchn_port_t port; ++ /* IN parameters. */ ++ uint32_t virq; ++ uint32_t vcpu; ++ /* OUT parameters. */ ++ evtchn_port_t port; + }; ++typedef struct evtchn_bind_virq evtchn_bind_virq_t; + + /* + * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ . +@@ -69,15 +101,16 @@ struct evtchn_bind_virq { + * 1. A physical IRQ may be bound to at most one event channel per domain. + * 2. Only a sufficiently-privileged domain may bind to a physical IRQ. + */ +-#define EVTCHNOP_bind_pirq 2 ++#define EVTCHNOP_bind_pirq 2 + struct evtchn_bind_pirq { +- /* IN parameters. */ +- uint32_t pirq; ++ /* IN parameters. */ ++ uint32_t pirq; + #define BIND_PIRQ__WILL_SHARE 1 +- uint32_t flags; /* BIND_PIRQ__* */ +- /* OUT parameters. */ +- evtchn_port_t port; ++ uint32_t flags; /* BIND_PIRQ__* */ ++ /* OUT parameters. */ ++ evtchn_port_t port; + }; ++typedef struct evtchn_bind_pirq evtchn_bind_pirq_t; + + /* + * EVTCHNOP_bind_ipi: Bind a local event channel to receive events. +@@ -85,33 +118,36 @@ struct evtchn_bind_pirq { + * 1. The allocated event channel is bound to the specified vcpu. The binding + * may not be changed. + */ +-#define EVTCHNOP_bind_ipi 7 ++#define EVTCHNOP_bind_ipi 7 + struct evtchn_bind_ipi { +- uint32_t vcpu; +- /* OUT parameters. */ +- evtchn_port_t port; ++ uint32_t vcpu; ++ /* OUT parameters. */ ++ evtchn_port_t port; + }; ++typedef struct evtchn_bind_ipi evtchn_bind_ipi_t; + + /* + * EVTCHNOP_close: Close a local event channel . If the channel is + * interdomain then the remote end is placed in the unbound state + * (EVTCHNSTAT_unbound), awaiting a new connection. + */ +-#define EVTCHNOP_close 3 ++#define EVTCHNOP_close 3 + struct evtchn_close { +- /* IN parameters. */ +- evtchn_port_t port; ++ /* IN parameters. */ ++ evtchn_port_t port; + }; ++typedef struct evtchn_close evtchn_close_t; + + /* + * EVTCHNOP_send: Send an event to the remote end of the channel whose local + * endpoint is . + */ +-#define EVTCHNOP_send 4 ++#define EVTCHNOP_send 4 + struct evtchn_send { +- /* IN parameters. */ +- evtchn_port_t port; ++ /* IN parameters. */ ++ evtchn_port_t port; + }; ++typedef struct evtchn_send evtchn_send_t; + + /* + * EVTCHNOP_status: Get the current status of the communication channel which +@@ -121,75 +157,108 @@ struct evtchn_send { + * 2. Only a sufficiently-privileged domain may obtain the status of an event + * channel for which is not DOMID_SELF. + */ +-#define EVTCHNOP_status 5 ++#define EVTCHNOP_status 5 + struct evtchn_status { +- /* IN parameters */ +- domid_t dom; +- evtchn_port_t port; +- /* OUT parameters */ +-#define EVTCHNSTAT_closed 0 /* Channel is not in use. */ +-#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/ +-#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ +-#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ +-#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ +-#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */ +- uint32_t status; +- uint32_t vcpu; /* VCPU to which this channel is bound. */ +- union { +- struct { +- domid_t dom; +- } unbound; /* EVTCHNSTAT_unbound */ +- struct { +- domid_t dom; +- evtchn_port_t port; +- } interdomain; /* EVTCHNSTAT_interdomain */ +- uint32_t pirq; /* EVTCHNSTAT_pirq */ +- uint32_t virq; /* EVTCHNSTAT_virq */ +- } u; ++ /* IN parameters */ ++ domid_t dom; ++ evtchn_port_t port; ++ /* OUT parameters */ ++#define EVTCHNSTAT_closed 0 /* Channel is not in use. */ ++#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/ ++#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ ++#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ ++#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ ++#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */ ++ uint32_t status; ++ uint32_t vcpu; /* VCPU to which this channel is bound. */ ++ union { ++ struct { ++ domid_t dom; ++ } unbound; /* EVTCHNSTAT_unbound */ ++ struct { ++ domid_t dom; ++ evtchn_port_t port; ++ } interdomain; /* EVTCHNSTAT_interdomain */ ++ uint32_t pirq; /* EVTCHNSTAT_pirq */ ++ uint32_t virq; /* EVTCHNSTAT_virq */ ++ } u; + }; ++typedef struct evtchn_status evtchn_status_t; + + /* + * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an + * event is pending. + * NOTES: +- * 1. IPI- and VIRQ-bound channels always notify the vcpu that initialised +- * the binding. This binding cannot be changed. +- * 2. All other channels notify vcpu0 by default. This default is set when ++ * 1. IPI-bound channels always notify the vcpu specified at bind time. ++ * This binding cannot be changed. ++ * 2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time. ++ * This binding cannot be changed. ++ * 3. All other channels notify vcpu0 by default. This default is set when + * the channel is allocated (a port that is freed and subsequently reused + * has its binding reset to vcpu0). + */ +-#define EVTCHNOP_bind_vcpu 8 ++#define EVTCHNOP_bind_vcpu 8 + struct evtchn_bind_vcpu { +- /* IN parameters. */ +- evtchn_port_t port; +- uint32_t vcpu; ++ /* IN parameters. */ ++ evtchn_port_t port; ++ uint32_t vcpu; + }; ++typedef struct evtchn_bind_vcpu evtchn_bind_vcpu_t; + + /* + * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver + * a notification to the appropriate VCPU if an event is pending. + */ +-#define EVTCHNOP_unmask 9 ++#define EVTCHNOP_unmask 9 + struct evtchn_unmask { +- /* IN parameters. */ +- evtchn_port_t port; ++ /* IN parameters. */ ++ evtchn_port_t port; ++}; ++typedef struct evtchn_unmask evtchn_unmask_t; ++ ++/* ++ * EVTCHNOP_reset: Close all event channels associated with specified domain. ++ * NOTES: ++ * 1. may be specified as DOMID_SELF. ++ * 2. Only a sufficiently-privileged domain may specify other than DOMID_SELF. ++ */ ++#define EVTCHNOP_reset 10 ++struct evtchn_reset { ++ /* IN parameters. */ ++ domid_t dom; + }; ++typedef struct evtchn_reset evtchn_reset_t; + ++/* ++ * Argument to event_channel_op_compat() hypercall. Superceded by new ++ * event_channel_op() hypercall since 0x00030202. ++ */ + struct evtchn_op { +- uint32_t cmd; /* EVTCHNOP_* */ +- union { +- struct evtchn_alloc_unbound alloc_unbound; +- struct evtchn_bind_interdomain bind_interdomain; +- struct evtchn_bind_virq bind_virq; +- struct evtchn_bind_pirq bind_pirq; +- struct evtchn_bind_ipi bind_ipi; +- struct evtchn_close close; +- struct evtchn_send send; +- struct evtchn_status status; +- struct evtchn_bind_vcpu bind_vcpu; +- struct evtchn_unmask unmask; +- } u; ++ uint32_t cmd; /* EVTCHNOP_* */ ++ union { ++ struct evtchn_alloc_unbound alloc_unbound; ++ struct evtchn_bind_interdomain bind_interdomain; ++ struct evtchn_bind_virq bind_virq; ++ struct evtchn_bind_pirq bind_pirq; ++ struct evtchn_bind_ipi bind_ipi; ++ struct evtchn_close close; ++ struct evtchn_send send; ++ struct evtchn_status status; ++ struct evtchn_bind_vcpu bind_vcpu; ++ struct evtchn_unmask unmask; ++ } u; + }; +-DEFINE_GUEST_HANDLE_STRUCT(evtchn_op); ++typedef struct evtchn_op evtchn_op_t; ++DEFINE_XEN_GUEST_HANDLE(evtchn_op_t); + + #endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/features.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/features.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/features.h 2008-11-25 12:22:34.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Feature flags, reported by XENVER_get_features. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2006, Keir Fraser + */ + +@@ -41,6 +59,25 @@ + /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ + #define XENFEAT_mmu_pt_update_preserve_ad 5 + ++/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */ ++#define XENFEAT_highmem_assist 6 ++ ++/* ++ * If set, GNTTABOP_map_grant_ref honors flags to be placed into guest kernel ++ * available pte bits. ++ */ ++#define XENFEAT_gnttab_map_avail_bits 7 ++ + #define XENFEAT_NR_SUBMAPS 1 + + #endif /* __XEN_PUBLIC_FEATURES_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/grant_table.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/grant_table.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/grant_table.h 2008-11-25 12:22:34.000000000 +0100 +@@ -100,6 +100,7 @@ struct grant_entry { + */ + uint32_t frame; + }; ++typedef struct grant_entry grant_entry_t; + + /* + * Type of grant entry. +@@ -118,6 +119,7 @@ struct grant_entry { + * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST] + * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN] + * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN] ++ * GTF_PAT, GTF_PWT, GTF_PCD: (x86) cache attribute flags for the grant [GST] + */ + #define _GTF_readonly (2) + #define GTF_readonly (1U<<_GTF_readonly) +@@ -125,6 +127,12 @@ struct grant_entry { + #define GTF_reading (1U<<_GTF_reading) + #define _GTF_writing (4) + #define GTF_writing (1U<<_GTF_writing) ++#define _GTF_PWT (5) ++#define GTF_PWT (1U<<_GTF_PWT) ++#define _GTF_PCD (6) ++#define GTF_PCD (1U<<_GTF_PCD) ++#define _GTF_PAT (7) ++#define GTF_PAT (1U<<_GTF_PAT) + + /* + * Subflags for GTF_accept_transfer: +@@ -185,7 +193,8 @@ struct gnttab_map_grant_ref { + grant_handle_t handle; + uint64_t dev_bus_addr; + }; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_map_grant_ref); ++typedef struct gnttab_map_grant_ref gnttab_map_grant_ref_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_map_grant_ref_t); + + /* + * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings +@@ -207,7 +216,8 @@ struct gnttab_unmap_grant_ref { + /* OUT parameters. */ + int16_t status; /* GNTST_* */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_unmap_grant_ref); ++typedef struct gnttab_unmap_grant_ref gnttab_unmap_grant_ref_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t); + + /* + * GNTTABOP_setup_table: Set up a grant table for comprising at least +@@ -225,9 +235,10 @@ struct gnttab_setup_table { + uint32_t nr_frames; + /* OUT parameters. */ + int16_t status; /* GNTST_* */ +- GUEST_HANDLE(ulong) frame_list; ++ XEN_GUEST_HANDLE(ulong) frame_list; + }; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_setup_table); ++typedef struct gnttab_setup_table gnttab_setup_table_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_t); + + /* + * GNTTABOP_dump_table: Dump the contents of the grant table to the +@@ -240,7 +251,8 @@ struct gnttab_dump_table { + /* OUT parameters. */ + int16_t status; /* GNTST_* */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_dump_table); ++typedef struct gnttab_dump_table gnttab_dump_table_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_dump_table_t); + + /* + * GNTTABOP_transfer_grant_ref: Transfer to a foreign domain. The +@@ -253,13 +265,15 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_dump_t + #define GNTTABOP_transfer 4 + struct gnttab_transfer { + /* IN parameters. */ +- unsigned long mfn; ++ xen_pfn_t mfn; + domid_t domid; + grant_ref_t ref; + /* OUT parameters. */ + int16_t status; + }; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_transfer); ++typedef struct gnttab_transfer gnttab_transfer_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t); ++ + + /* + * GNTTABOP_copy: Hypervisor based copy +@@ -285,22 +299,22 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_transf + #define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref) + + #define GNTTABOP_copy 5 +-struct gnttab_copy { +- /* IN parameters. */ +- struct { +- union { +- grant_ref_t ref; +- unsigned long gmfn; +- } u; +- domid_t domid; +- uint16_t offset; +- } source, dest; +- uint16_t len; +- uint16_t flags; /* GNTCOPY_* */ +- /* OUT parameters. */ +- int16_t status; +-}; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_copy); ++typedef struct gnttab_copy { ++ /* IN parameters. */ ++ struct { ++ union { ++ grant_ref_t ref; ++ xen_pfn_t gmfn; ++ } u; ++ domid_t domid; ++ uint16_t offset; ++ } source, dest; ++ uint16_t len; ++ uint16_t flags; /* GNTCOPY_* */ ++ /* OUT parameters. */ ++ int16_t status; ++} gnttab_copy_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t); + + /* + * GNTTABOP_query_size: Query the current and maximum sizes of the shared +@@ -318,10 +332,35 @@ struct gnttab_query_size { + uint32_t max_nr_frames; + int16_t status; /* GNTST_* */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_size); ++typedef struct gnttab_query_size gnttab_query_size_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t); + + /* +- * Bitfield values for update_pin_status.flags. ++ * GNTTABOP_unmap_and_replace: Destroy one or more grant-reference mappings ++ * tracked by but atomically replace the page table entry with one ++ * pointing to the machine address under . will be ++ * redirected to the null entry. ++ * NOTES: ++ * 1. The call may fail in an undefined manner if either mapping is not ++ * tracked by . ++ * 2. After executing a batch of unmaps, it is guaranteed that no stale ++ * mappings will remain in the device or host TLBs. ++ */ ++#define GNTTABOP_unmap_and_replace 7 ++struct gnttab_unmap_and_replace { ++ /* IN parameters. */ ++ uint64_t host_addr; ++ uint64_t new_addr; ++ grant_handle_t handle; ++ /* OUT parameters. */ ++ int16_t status; /* GNTST_* */ ++}; ++typedef struct gnttab_unmap_and_replace gnttab_unmap_and_replace_t; ++DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t); ++ ++ ++/* ++ * Bitfield values for gnttab_map_grant_ref.flags. + */ + /* Map the grant entry for access by I/O devices. */ + #define _GNTMAP_device_map (0) +@@ -349,6 +388,13 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_ + #define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte) + + /* ++ * Bits to be placed in guest kernel available PTE bits (architecture ++ * dependent; only supported when XENFEAT_gnttab_map_avail_bits is set). ++ */ ++#define _GNTMAP_guest_avail0 (16) ++#define GNTMAP_guest_avail_mask ((uint32_t)~0 << _GNTMAP_guest_avail0) ++ ++/* + * Values for error status returns. All errors are -ve. + */ + #define GNTST_okay (0) /* Normal return. */ +@@ -361,7 +407,8 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_ + #define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */ + #define GNTST_permission_denied (-8) /* Not enough privilege for operation. */ + #define GNTST_bad_page (-9) /* Specified page was invalid for op. */ +-#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary */ ++#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary. */ ++#define GNTST_address_too_big (-11) /* transfer page address too large. */ + + #define GNTTABOP_error_msgs { \ + "okay", \ +@@ -374,7 +421,18 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_ + "no spare translation slot in the I/O MMU", \ + "permission denied", \ + "bad page", \ +- "copy arguments cross page boundary" \ ++ "copy arguments cross page boundary", \ ++ "page address size too large" \ + } + + #endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/blkif.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/blkif.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/blkif.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Unified block-device I/O interface for Xen guest OSes. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2003-2004, Keir Fraser + */ + +@@ -24,8 +42,10 @@ + * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()). + */ + +-typedef uint16_t blkif_vdev_t; +-typedef uint64_t blkif_sector_t; ++#ifndef blkif_vdev_t ++#define blkif_vdev_t uint16_t ++#endif ++#define blkif_sector_t uint64_t + + /* + * REQUEST CODES. +@@ -34,7 +54,7 @@ typedef uint64_t blkif_sector_t; + #define BLKIF_OP_WRITE 1 + /* + * Recognised only if "feature-barrier" is present in backend xenbus info. +- * The "feature_barrier" node contains a boolean indicating whether barrier ++ * The "feature-barrier" node contains a boolean indicating whether barrier + * requests are likely to succeed or fail. Either way, a barrier request + * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by + * the underlying block-device hardware. The boolean simply indicates whether +@@ -43,33 +63,50 @@ typedef uint64_t blkif_sector_t; + * create the "feature-barrier" node! + */ + #define BLKIF_OP_WRITE_BARRIER 2 ++/* ++ * Recognised if "feature-flush-cache" is present in backend xenbus ++ * info. A flush will ask the underlying storage hardware to flush its ++ * non-volatile caches as appropriate. The "feature-flush-cache" node ++ * contains a boolean indicating whether flush requests are likely to ++ * succeed or fail. Either way, a flush request may fail at any time ++ * with BLKIF_RSP_EOPNOTSUPP if it is unsupported by the underlying ++ * block-device hardware. The boolean simply indicates whether or not it ++ * is worthwhile for the frontend to attempt flushes. If a backend does ++ * not recognise BLKIF_OP_WRITE_FLUSH_CACHE, it should *not* create the ++ * "feature-flush-cache" node! ++ */ ++#define BLKIF_OP_FLUSH_DISKCACHE 3 + + /* + * Maximum scatter/gather segments per request. +- * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE. ++ * This is carefully chosen so that sizeof(blkif_ring_t) <= PAGE_SIZE. + * NB. This could be 12 if the ring indexes weren't stored in the same page. + */ + #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11 + ++struct blkif_request_segment { ++ grant_ref_t gref; /* reference to I/O buffer frame */ ++ /* @first_sect: first sector in frame to transfer (inclusive). */ ++ /* @last_sect: last sector in frame to transfer (inclusive). */ ++ uint8_t first_sect, last_sect; ++}; ++ + struct blkif_request { +- uint8_t operation; /* BLKIF_OP_??? */ +- uint8_t nr_segments; /* number of segments */ +- blkif_vdev_t handle; /* only for read/write requests */ +- uint64_t id; /* private guest value, echoed in resp */ +- blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ +- struct blkif_request_segment { +- grant_ref_t gref; /* reference to I/O buffer frame */ +- /* @first_sect: first sector in frame to transfer (inclusive). */ +- /* @last_sect: last sector in frame to transfer (inclusive). */ +- uint8_t first_sect, last_sect; +- } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; ++ uint8_t operation; /* BLKIF_OP_??? */ ++ uint8_t nr_segments; /* number of segments */ ++ blkif_vdev_t handle; /* only for read/write requests */ ++ uint64_t id; /* private guest value, echoed in resp */ ++ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ ++ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + }; ++typedef struct blkif_request blkif_request_t; + + struct blkif_response { +- uint64_t id; /* copied from request */ +- uint8_t operation; /* copied from request */ +- int16_t status; /* BLKIF_RSP_??? */ ++ uint64_t id; /* copied from request */ ++ uint8_t operation; /* copied from request */ ++ int16_t status; /* BLKIF_RSP_??? */ + }; ++typedef struct blkif_response blkif_response_t; + + /* + * STATUS RETURN CODES. +@@ -92,3 +129,13 @@ DEFINE_RING_TYPES(blkif, struct blkif_re + #define VDISK_READONLY 0x4 + + #endif /* __XEN_PUBLIC_IO_BLKIF_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/console.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/console.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/console.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Console I/O interface for Xen guest OSes. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2005, Keir Fraser + */ + +@@ -21,3 +39,13 @@ struct xencons_interface { + }; + + #endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/fbif.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/fbif.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/fbif.h 2008-11-25 12:35:56.000000000 +0100 +@@ -41,12 +41,13 @@ + */ + #define XENFB_TYPE_UPDATE 2 + +-struct xenfb_update { +- uint8_t type; /* XENFB_TYPE_UPDATE */ +- int32_t x; /* source x */ +- int32_t y; /* source y */ +- int32_t width; /* rect width */ +- int32_t height; /* rect height */ ++struct xenfb_update ++{ ++ uint8_t type; /* XENFB_TYPE_UPDATE */ ++ int32_t x; /* source x */ ++ int32_t y; /* source y */ ++ int32_t width; /* rect width */ ++ int32_t height; /* rect height */ + }; + + /* +@@ -55,36 +56,58 @@ struct xenfb_update { + */ + #define XENFB_TYPE_RESIZE 3 + +-struct xenfb_resize { +- uint8_t type; /* XENFB_TYPE_RESIZE */ +- int32_t width; /* width in pixels */ +- int32_t height; /* height in pixels */ +- int32_t stride; /* stride in bytes */ +- int32_t depth; /* depth in bits */ +- int32_t offset; /* start offset within framebuffer */ ++struct xenfb_resize ++{ ++ uint8_t type; /* XENFB_TYPE_RESIZE */ ++ int32_t width; /* width in pixels */ ++ int32_t height; /* height in pixels */ ++ int32_t stride; /* stride in bytes */ ++ int32_t depth; /* depth in bits */ ++ int32_t offset; /* offset of the framebuffer in bytes */ + }; + + #define XENFB_OUT_EVENT_SIZE 40 + +-union xenfb_out_event { +- uint8_t type; +- struct xenfb_update update; +- struct xenfb_resize resize; +- char pad[XENFB_OUT_EVENT_SIZE]; ++union xenfb_out_event ++{ ++ uint8_t type; ++ struct xenfb_update update; ++ struct xenfb_resize resize; ++ char pad[XENFB_OUT_EVENT_SIZE]; + }; + + /* In events (backend -> frontend) */ + + /* + * Frontends should ignore unknown in events. +- * No in events currently defined. + */ + ++/* ++ * Framebuffer refresh period advice ++ * Backend sends it to advise the frontend their preferred period of ++ * refresh. Frontends that keep the framebuffer constantly up-to-date ++ * just ignore it. Frontends that use the advice should immediately ++ * refresh the framebuffer (and send an update notification event if ++ * those have been requested), then use the update frequency to guide ++ * their periodical refreshs. ++ */ ++#define XENFB_TYPE_REFRESH_PERIOD 1 ++#define XENFB_NO_REFRESH 0 ++ ++struct xenfb_refresh_period ++{ ++ uint8_t type; /* XENFB_TYPE_UPDATE_PERIOD */ ++ uint32_t period; /* period of refresh, in ms, ++ * XENFB_NO_REFRESH if no refresh is needed */ ++}; ++ + #define XENFB_IN_EVENT_SIZE 40 + +-union xenfb_in_event { +- uint8_t type; +- char pad[XENFB_IN_EVENT_SIZE]; ++union xenfb_in_event ++{ ++ uint8_t type; ++ struct xenfb_refresh_period refresh_period; ++ char pad[XENFB_IN_EVENT_SIZE]; + }; + + /* shared page */ +@@ -93,41 +116,41 @@ union xenfb_in_event { + #define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) + #define XENFB_IN_RING_OFFS 1024 + #define XENFB_IN_RING(page) \ +- ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) ++ ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) + #define XENFB_IN_RING_REF(page, idx) \ +- (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) ++ (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) + + #define XENFB_OUT_RING_SIZE 2048 + #define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) + #define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) + #define XENFB_OUT_RING(page) \ +- ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) ++ ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) + #define XENFB_OUT_RING_REF(page, idx) \ +- (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) ++ (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) + +-struct xenfb_page { +- uint32_t in_cons, in_prod; +- uint32_t out_cons, out_prod; +- +- int32_t width; /* width of the framebuffer (in pixels) */ +- int32_t height; /* height of the framebuffer (in pixels) */ +- uint32_t line_length; /* length of a row of pixels (in bytes) */ +- uint32_t mem_length; /* length of the framebuffer (in bytes) */ +- uint8_t depth; /* depth of a pixel (in bits) */ +- +- /* +- * Framebuffer page directory +- * +- * Each directory page holds PAGE_SIZE / sizeof(*pd) +- * framebuffer pages, and can thus map up to PAGE_SIZE * +- * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and +- * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 +- * Megs 64 bit. 256 directories give enough room for a 512 +- * Meg framebuffer with a max resolution of 12,800x10,240. +- * Should be enough for a while with room leftover for +- * expansion. +- */ +- unsigned long pd[256]; ++struct xenfb_page ++{ ++ uint32_t in_cons, in_prod; ++ uint32_t out_cons, out_prod; ++ ++ int32_t width; /* the width of the framebuffer (in pixels) */ ++ int32_t height; /* the height of the framebuffer (in pixels) */ ++ uint32_t line_length; /* the length of a row of pixels (in bytes) */ ++ uint32_t mem_length; /* the length of the framebuffer (in bytes) */ ++ uint8_t depth; /* the depth of a pixel (in bits) */ ++ ++ /* ++ * Framebuffer page directory ++ * ++ * Each directory page holds PAGE_SIZE / sizeof(*pd) ++ * framebuffer pages, and can thus map up to PAGE_SIZE * ++ * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and ++ * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs ++ * 64 bit. 256 directories give enough room for a 512 Meg ++ * framebuffer with a max resolution of 12,800x10,240. Should ++ * be enough for a while with room leftover for expansion. ++ */ ++ unsigned long pd[256]; + }; + + /* +@@ -141,3 +164,13 @@ struct xenfb_page { + #endif + + #endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/kbdif.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/kbdif.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/kbdif.h 2008-11-25 12:35:56.000000000 +0100 +@@ -45,34 +45,38 @@ + */ + #define XENKBD_TYPE_POS 4 + +-struct xenkbd_motion { +- uint8_t type; /* XENKBD_TYPE_MOTION */ +- int32_t rel_x; /* relative X motion */ +- int32_t rel_y; /* relative Y motion */ +- int32_t rel_z; /* relative Z motion (wheel) */ +-}; +- +-struct xenkbd_key { +- uint8_t type; /* XENKBD_TYPE_KEY */ +- uint8_t pressed; /* 1 if pressed; 0 otherwise */ +- uint32_t keycode; /* KEY_* from linux/input.h */ +-}; +- +-struct xenkbd_position { +- uint8_t type; /* XENKBD_TYPE_POS */ +- int32_t abs_x; /* absolute X position (in FB pixels) */ +- int32_t abs_y; /* absolute Y position (in FB pixels) */ +- int32_t rel_z; /* relative Z motion (wheel) */ ++struct xenkbd_motion ++{ ++ uint8_t type; /* XENKBD_TYPE_MOTION */ ++ int32_t rel_x; /* relative X motion */ ++ int32_t rel_y; /* relative Y motion */ ++ int32_t rel_z; /* relative Z motion (wheel) */ ++}; ++ ++struct xenkbd_key ++{ ++ uint8_t type; /* XENKBD_TYPE_KEY */ ++ uint8_t pressed; /* 1 if pressed; 0 otherwise */ ++ uint32_t keycode; /* KEY_* from linux/input.h */ ++}; ++ ++struct xenkbd_position ++{ ++ uint8_t type; /* XENKBD_TYPE_POS */ ++ int32_t abs_x; /* absolute X position (in FB pixels) */ ++ int32_t abs_y; /* absolute Y position (in FB pixels) */ ++ int32_t rel_z; /* relative Z motion (wheel) */ + }; + + #define XENKBD_IN_EVENT_SIZE 40 + +-union xenkbd_in_event { +- uint8_t type; +- struct xenkbd_motion motion; +- struct xenkbd_key key; +- struct xenkbd_position pos; +- char pad[XENKBD_IN_EVENT_SIZE]; ++union xenkbd_in_event ++{ ++ uint8_t type; ++ struct xenkbd_motion motion; ++ struct xenkbd_key key; ++ struct xenkbd_position pos; ++ char pad[XENKBD_IN_EVENT_SIZE]; + }; + + /* Out events (frontend -> backend) */ +@@ -85,9 +89,10 @@ union xenkbd_in_event { + + #define XENKBD_OUT_EVENT_SIZE 40 + +-union xenkbd_out_event { +- uint8_t type; +- char pad[XENKBD_OUT_EVENT_SIZE]; ++union xenkbd_out_event ++{ ++ uint8_t type; ++ char pad[XENKBD_OUT_EVENT_SIZE]; + }; + + /* shared page */ +@@ -96,21 +101,32 @@ union xenkbd_out_event { + #define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) + #define XENKBD_IN_RING_OFFS 1024 + #define XENKBD_IN_RING(page) \ +- ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) ++ ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) + #define XENKBD_IN_RING_REF(page, idx) \ +- (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) ++ (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) + + #define XENKBD_OUT_RING_SIZE 1024 + #define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) + #define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) + #define XENKBD_OUT_RING(page) \ +- ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) ++ ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) + #define XENKBD_OUT_RING_REF(page, idx) \ +- (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) ++ (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) + +-struct xenkbd_page { +- uint32_t in_cons, in_prod; +- uint32_t out_cons, out_prod; ++struct xenkbd_page ++{ ++ uint32_t in_cons, in_prod; ++ uint32_t out_cons, out_prod; + }; + + #endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/netif.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/netif.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/netif.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Unified network-device I/O interface for Xen guest OSes. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2003-2004, Keir Fraser + */ + +@@ -47,18 +65,21 @@ + #define _NETTXF_extra_info (3) + #define NETTXF_extra_info (1U<<_NETTXF_extra_info) + +-struct xen_netif_tx_request { ++struct netif_tx_request { + grant_ref_t gref; /* Reference to buffer page */ + uint16_t offset; /* Offset within buffer page */ + uint16_t flags; /* NETTXF_* */ + uint16_t id; /* Echoed in response message. */ + uint16_t size; /* Packet size in bytes. */ + }; ++typedef struct netif_tx_request netif_tx_request_t; + + /* Types of netif_extra_info descriptors. */ +-#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */ +-#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */ +-#define XEN_NETIF_EXTRA_TYPE_MAX (2) ++#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */ ++#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */ ++#define XEN_NETIF_EXTRA_TYPE_MCAST_ADD (2) /* u.mcast */ ++#define XEN_NETIF_EXTRA_TYPE_MCAST_DEL (3) /* u.mcast */ ++#define XEN_NETIF_EXTRA_TYPE_MAX (4) + + /* netif_extra_info flags. */ + #define _XEN_NETIF_EXTRA_FLAG_MORE (0) +@@ -71,49 +92,68 @@ struct xen_netif_tx_request { + * This structure needs to fit within both netif_tx_request and + * netif_rx_response for compatibility. + */ +-struct xen_netif_extra_info { +- uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */ +- uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */ +- +- union { +- struct { +- /* +- * Maximum payload size of each segment. For +- * example, for TCP this is just the path MSS. +- */ +- uint16_t size; +- +- /* +- * GSO type. This determines the protocol of +- * the packet and any extra features required +- * to segment the packet properly. +- */ +- uint8_t type; /* XEN_NETIF_GSO_TYPE_* */ +- +- /* Future expansion. */ +- uint8_t pad; +- +- /* +- * GSO features. This specifies any extra GSO +- * features required to process this packet, +- * such as ECN support for TCPv4. +- */ +- uint16_t features; /* XEN_NETIF_GSO_FEAT_* */ +- } gso; ++struct netif_extra_info { ++ uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */ ++ uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */ ++ ++ union { ++ /* ++ * XEN_NETIF_EXTRA_TYPE_GSO: ++ */ ++ struct { ++ /* ++ * Maximum payload size of each segment. For example, for TCP this ++ * is just the path MSS. ++ */ ++ uint16_t size; ++ ++ /* ++ * GSO type. This determines the protocol of the packet and any ++ * extra features required to segment the packet properly. ++ */ ++ uint8_t type; /* XEN_NETIF_GSO_TYPE_* */ ++ ++ /* Future expansion. */ ++ uint8_t pad; ++ ++ /* ++ * GSO features. This specifies any extra GSO features required ++ * to process this packet, such as ECN support for TCPv4. ++ */ ++ uint16_t features; /* XEN_NETIF_GSO_FEAT_* */ ++ } gso; ++ ++ /* ++ * XEN_NETIF_EXTRA_TYPE_MCAST_{ADD,DEL}: ++ * Backend advertises availability via 'feature-multicast-control' ++ * xenbus node containing value '1'. ++ * Frontend requests this feature by advertising ++ * 'request-multicast-control' xenbus node containing value '1'. ++ * If multicast control is requested then multicast flooding is ++ * disabled and the frontend must explicitly register its interest ++ * in multicast groups using dummy transmit requests containing ++ * MCAST_{ADD,DEL} extra-info fragments. ++ */ ++ struct { ++ uint8_t addr[6]; /* Address to add/remove. */ ++ } mcast; + +- uint16_t pad[3]; +- } u; ++ uint16_t pad[3]; ++ } u; + }; ++typedef struct netif_extra_info netif_extra_info_t; + +-struct xen_netif_tx_response { +- uint16_t id; +- int16_t status; /* NETIF_RSP_* */ ++struct netif_tx_response { ++ uint16_t id; ++ int16_t status; /* NETIF_RSP_* */ + }; ++typedef struct netif_tx_response netif_tx_response_t; + +-struct xen_netif_rx_request { +- uint16_t id; /* Echoed in response message. */ +- grant_ref_t gref; /* Reference to incoming granted frame */ ++struct netif_rx_request { ++ uint16_t id; /* Echoed in response message. */ ++ grant_ref_t gref; /* Reference to incoming granted frame */ + }; ++typedef struct netif_rx_request netif_rx_request_t; + + /* Packet data has been validated against protocol checksum. */ + #define _NETRXF_data_validated (0) +@@ -131,23 +171,20 @@ struct xen_netif_rx_request { + #define _NETRXF_extra_info (3) + #define NETRXF_extra_info (1U<<_NETRXF_extra_info) + +-struct xen_netif_rx_response { ++struct netif_rx_response { + uint16_t id; + uint16_t offset; /* Offset in page of start of received packet */ + uint16_t flags; /* NETRXF_* */ + int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */ + }; ++typedef struct netif_rx_response netif_rx_response_t; + + /* + * Generate netif ring structures and types. + */ + +-DEFINE_RING_TYPES(xen_netif_tx, +- struct xen_netif_tx_request, +- struct xen_netif_tx_response); +-DEFINE_RING_TYPES(xen_netif_rx, +- struct xen_netif_rx_request, +- struct xen_netif_rx_response); ++DEFINE_RING_TYPES(netif_tx, struct netif_tx_request, struct netif_tx_response); ++DEFINE_RING_TYPES(netif_rx, struct netif_rx_request, struct netif_rx_response); + + #define NETIF_RSP_DROPPED -2 + #define NETIF_RSP_ERROR -1 +@@ -156,3 +193,13 @@ DEFINE_RING_TYPES(xen_netif_rx, + #define NETIF_RSP_NULL 1 + + #endif ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/protocols.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/protocols.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/protocols.h 2008-11-25 12:35:56.000000000 +0100 +@@ -1,10 +1,31 @@ ++/****************************************************************************** ++ * protocols.h ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++ + #ifndef __XEN_PROTOCOLS_H__ + #define __XEN_PROTOCOLS_H__ + + #define XEN_IO_PROTO_ABI_X86_32 "x86_32-abi" + #define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi" + #define XEN_IO_PROTO_ABI_IA64 "ia64-abi" +-#define XEN_IO_PROTO_ABI_POWERPC64 "powerpc64-abi" + + #if defined(__i386__) + # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32 +@@ -12,8 +33,6 @@ + # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64 + #elif defined(__ia64__) + # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64 +-#elif defined(__powerpc64__) +-# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64 + #else + # error arch fixup needed here + #endif +Index: head-2008-11-25/include/xen/interface/io/ring.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/ring.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/ring.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,16 +3,42 @@ + * + * Shared producer-consumer ring macros. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Tim Deegan and Andrew Warfield November 2004. + */ + + #ifndef __XEN_PUBLIC_IO_RING_H__ + #define __XEN_PUBLIC_IO_RING_H__ + ++#include "../xen-compat.h" ++ ++#if __XEN_INTERFACE_VERSION__ < 0x00030208 ++#define xen_mb() mb() ++#define xen_rmb() rmb() ++#define xen_wmb() wmb() ++#endif ++ + typedef unsigned int RING_IDX; + + /* Round a 32-bit unsigned constant down to the nearest power of two. */ +-#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) ++#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) + #define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x)) + #define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x)) + #define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x)) +@@ -25,73 +51,76 @@ typedef unsigned int RING_IDX; + * power of two (so we can mask with (size-1) to loop around). + */ + #define __RING_SIZE(_s, _sz) \ +- (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) ++ (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) + + /* + * Macros to make the correct C datatypes for a new kind of ring. + * + * To make a new ring datatype, you need to have two message structures, +- * let's say struct request, and struct response already defined. ++ * let's say request_t, and response_t already defined. + * + * In a header where you want the ring datatype declared, you then do: + * +- * DEFINE_RING_TYPES(mytag, struct request, struct response); ++ * DEFINE_RING_TYPES(mytag, request_t, response_t); + * + * These expand out to give you a set of types, as you can see below. + * The most important of these are: + * +- * struct mytag_sring - The shared ring. +- * struct mytag_front_ring - The 'front' half of the ring. +- * struct mytag_back_ring - The 'back' half of the ring. ++ * mytag_sring_t - The shared ring. ++ * mytag_front_ring_t - The 'front' half of the ring. ++ * mytag_back_ring_t - The 'back' half of the ring. + * + * To initialize a ring in your code you need to know the location and size + * of the shared memory area (PAGE_SIZE, for instance). To initialise + * the front half: + * +- * struct mytag_front_ring front_ring; +- * SHARED_RING_INIT((struct mytag_sring *)shared_page); +- * FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page, +- * PAGE_SIZE); ++ * mytag_front_ring_t front_ring; ++ * SHARED_RING_INIT((mytag_sring_t *)shared_page); ++ * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); + * + * Initializing the back follows similarly (note that only the front + * initializes the shared ring): + * +- * struct mytag_back_ring back_ring; +- * BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page, +- * PAGE_SIZE); ++ * mytag_back_ring_t back_ring; ++ * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); + */ + +-#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ +- \ +-/* Shared ring entry */ \ +-union __name##_sring_entry { \ +- __req_t req; \ +- __rsp_t rsp; \ +-}; \ +- \ +-/* Shared ring page */ \ +-struct __name##_sring { \ +- RING_IDX req_prod, req_event; \ +- RING_IDX rsp_prod, rsp_event; \ +- uint8_t pad[48]; \ +- union __name##_sring_entry ring[1]; /* variable-length */ \ +-}; \ +- \ +-/* "Front" end's private variables */ \ +-struct __name##_front_ring { \ +- RING_IDX req_prod_pvt; \ +- RING_IDX rsp_cons; \ +- unsigned int nr_ents; \ +- struct __name##_sring *sring; \ +-}; \ +- \ +-/* "Back" end's private variables */ \ +-struct __name##_back_ring { \ +- RING_IDX rsp_prod_pvt; \ +- RING_IDX req_cons; \ +- unsigned int nr_ents; \ +- struct __name##_sring *sring; \ +-}; ++#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ ++ \ ++/* Shared ring entry */ \ ++union __name##_sring_entry { \ ++ __req_t req; \ ++ __rsp_t rsp; \ ++}; \ ++ \ ++/* Shared ring page */ \ ++struct __name##_sring { \ ++ RING_IDX req_prod, req_event; \ ++ RING_IDX rsp_prod, rsp_event; \ ++ uint8_t pad[48]; \ ++ union __name##_sring_entry ring[1]; /* variable-length */ \ ++}; \ ++ \ ++/* "Front" end's private variables */ \ ++struct __name##_front_ring { \ ++ RING_IDX req_prod_pvt; \ ++ RING_IDX rsp_cons; \ ++ unsigned int nr_ents; \ ++ struct __name##_sring *sring; \ ++}; \ ++ \ ++/* "Back" end's private variables */ \ ++struct __name##_back_ring { \ ++ RING_IDX rsp_prod_pvt; \ ++ RING_IDX req_cons; \ ++ unsigned int nr_ents; \ ++ struct __name##_sring *sring; \ ++}; \ ++ \ ++/* Syntactic sugar */ \ ++typedef struct __name##_sring __name##_sring_t; \ ++typedef struct __name##_front_ring __name##_front_ring_t; \ ++typedef struct __name##_back_ring __name##_back_ring_t + + /* + * Macros for manipulating rings. +@@ -109,86 +138,94 @@ struct __name##_back_ring { \ + */ + + /* Initialising empty rings */ +-#define SHARED_RING_INIT(_s) do { \ +- (_s)->req_prod = (_s)->rsp_prod = 0; \ +- (_s)->req_event = (_s)->rsp_event = 1; \ +- memset((_s)->pad, 0, sizeof((_s)->pad)); \ ++#define SHARED_RING_INIT(_s) do { \ ++ (_s)->req_prod = (_s)->rsp_prod = 0; \ ++ (_s)->req_event = (_s)->rsp_event = 1; \ ++ (void)memset((_s)->pad, 0, sizeof((_s)->pad)); \ + } while(0) + +-#define FRONT_RING_INIT(_r, _s, __size) do { \ +- (_r)->req_prod_pvt = 0; \ +- (_r)->rsp_cons = 0; \ +- (_r)->nr_ents = __RING_SIZE(_s, __size); \ +- (_r)->sring = (_s); \ ++#define FRONT_RING_INIT(_r, _s, __size) do { \ ++ (_r)->req_prod_pvt = 0; \ ++ (_r)->rsp_cons = 0; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++ (_r)->sring = (_s); \ + } while (0) + +-#define BACK_RING_INIT(_r, _s, __size) do { \ +- (_r)->rsp_prod_pvt = 0; \ +- (_r)->req_cons = 0; \ +- (_r)->nr_ents = __RING_SIZE(_s, __size); \ +- (_r)->sring = (_s); \ ++#define BACK_RING_INIT(_r, _s, __size) do { \ ++ (_r)->rsp_prod_pvt = 0; \ ++ (_r)->req_cons = 0; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++ (_r)->sring = (_s); \ + } while (0) + + /* Initialize to existing shared indexes -- for recovery */ +-#define FRONT_RING_ATTACH(_r, _s, __size) do { \ +- (_r)->sring = (_s); \ +- (_r)->req_prod_pvt = (_s)->req_prod; \ +- (_r)->rsp_cons = (_s)->rsp_prod; \ +- (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++#define FRONT_RING_ATTACH(_r, _s, __size) do { \ ++ (_r)->sring = (_s); \ ++ (_r)->req_prod_pvt = (_s)->req_prod; \ ++ (_r)->rsp_cons = (_s)->rsp_prod; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ + } while (0) + +-#define BACK_RING_ATTACH(_r, _s, __size) do { \ +- (_r)->sring = (_s); \ +- (_r)->rsp_prod_pvt = (_s)->rsp_prod; \ +- (_r)->req_cons = (_s)->req_prod; \ +- (_r)->nr_ents = __RING_SIZE(_s, __size); \ ++#define BACK_RING_ATTACH(_r, _s, __size) do { \ ++ (_r)->sring = (_s); \ ++ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \ ++ (_r)->req_cons = (_s)->req_prod; \ ++ (_r)->nr_ents = __RING_SIZE(_s, __size); \ + } while (0) + + /* How big is this ring? */ +-#define RING_SIZE(_r) \ ++#define RING_SIZE(_r) \ + ((_r)->nr_ents) + + /* Number of free requests (for use on front side only). */ +-#define RING_FREE_REQUESTS(_r) \ ++#define RING_FREE_REQUESTS(_r) \ + (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons)) + + /* Test if there is an empty slot available on the front ring. + * (This is only meaningful from the front. ) + */ +-#define RING_FULL(_r) \ ++#define RING_FULL(_r) \ + (RING_FREE_REQUESTS(_r) == 0) + + /* Test if there are outstanding messages to be processed on a ring. */ +-#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ ++#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ + ((_r)->sring->rsp_prod - (_r)->rsp_cons) + +-#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ +- ({ \ +- unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ +- unsigned int rsp = RING_SIZE(_r) - \ +- ((_r)->req_cons - (_r)->rsp_prod_pvt); \ +- req < rsp ? req : rsp; \ +- }) ++#ifdef __GNUC__ ++#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ ++ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ ++ unsigned int rsp = RING_SIZE(_r) - \ ++ ((_r)->req_cons - (_r)->rsp_prod_pvt); \ ++ req < rsp ? req : rsp; \ ++}) ++#else ++/* Same as above, but without the nice GCC ({ ... }) syntax. */ ++#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ ++ ((((_r)->sring->req_prod - (_r)->req_cons) < \ ++ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \ ++ ((_r)->sring->req_prod - (_r)->req_cons) : \ ++ (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ++#endif + + /* Direct access to individual ring elements, by index. */ +-#define RING_GET_REQUEST(_r, _idx) \ ++#define RING_GET_REQUEST(_r, _idx) \ + (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) + +-#define RING_GET_RESPONSE(_r, _idx) \ ++#define RING_GET_RESPONSE(_r, _idx) \ + (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) + + /* Loop termination condition: Would the specified index overflow the ring? */ +-#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ ++#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ + (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) + +-#define RING_PUSH_REQUESTS(_r) do { \ +- wmb(); /* back sees requests /before/ updated producer index */ \ +- (_r)->sring->req_prod = (_r)->req_prod_pvt; \ ++#define RING_PUSH_REQUESTS(_r) do { \ ++ xen_wmb(); /* back sees requests /before/ updated producer index */ \ ++ (_r)->sring->req_prod = (_r)->req_prod_pvt; \ + } while (0) + +-#define RING_PUSH_RESPONSES(_r) do { \ +- wmb(); /* front sees responses /before/ updated producer index */ \ +- (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ ++#define RING_PUSH_RESPONSES(_r) do { \ ++ xen_wmb(); /* front sees resps /before/ updated producer index */ \ ++ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ + } while (0) + + /* +@@ -221,40 +258,50 @@ struct __name##_back_ring { \ + * field appropriately. + */ + +-#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ +- RING_IDX __old = (_r)->sring->req_prod; \ +- RING_IDX __new = (_r)->req_prod_pvt; \ +- wmb(); /* back sees requests /before/ updated producer index */ \ +- (_r)->sring->req_prod = __new; \ +- mb(); /* back sees new requests /before/ we check req_event */ \ +- (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ +- (RING_IDX)(__new - __old)); \ ++#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ ++ RING_IDX __old = (_r)->sring->req_prod; \ ++ RING_IDX __new = (_r)->req_prod_pvt; \ ++ xen_wmb(); /* back sees requests /before/ updated producer index */ \ ++ (_r)->sring->req_prod = __new; \ ++ xen_mb(); /* back sees new requests /before/ we check req_event */ \ ++ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ ++ (RING_IDX)(__new - __old)); \ + } while (0) + +-#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ +- RING_IDX __old = (_r)->sring->rsp_prod; \ +- RING_IDX __new = (_r)->rsp_prod_pvt; \ +- wmb(); /* front sees responses /before/ updated producer index */ \ +- (_r)->sring->rsp_prod = __new; \ +- mb(); /* front sees new responses /before/ we check rsp_event */ \ +- (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ +- (RING_IDX)(__new - __old)); \ ++#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ ++ RING_IDX __old = (_r)->sring->rsp_prod; \ ++ RING_IDX __new = (_r)->rsp_prod_pvt; \ ++ xen_wmb(); /* front sees resps /before/ updated producer index */ \ ++ (_r)->sring->rsp_prod = __new; \ ++ xen_mb(); /* front sees new resps /before/ we check rsp_event */ \ ++ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ ++ (RING_IDX)(__new - __old)); \ + } while (0) + +-#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ +- (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ +- if (_work_to_do) break; \ +- (_r)->sring->req_event = (_r)->req_cons + 1; \ +- mb(); \ +- (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ ++#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ ++ if (_work_to_do) break; \ ++ (_r)->sring->req_event = (_r)->req_cons + 1; \ ++ xen_mb(); \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ + } while (0) + +-#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ +- (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ +- if (_work_to_do) break; \ +- (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ +- mb(); \ +- (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ ++#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ ++ if (_work_to_do) break; \ ++ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ ++ xen_mb(); \ ++ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ + } while (0) + + #endif /* __XEN_PUBLIC_IO_RING_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/io/xenbus.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/xenbus.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/xenbus.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,42 +3,78 @@ + * + * Xenbus protocol details. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (C) 2005 XenSource Ltd. + */ + + #ifndef _XEN_PUBLIC_IO_XENBUS_H + #define _XEN_PUBLIC_IO_XENBUS_H + +-/* The state of either end of the Xenbus, i.e. the current communication +- status of initialisation across the bus. States here imply nothing about +- the state of the connection between the driver and the kernel's device +- layers. */ +-enum xenbus_state +-{ +- XenbusStateUnknown = 0, +- XenbusStateInitialising = 1, +- XenbusStateInitWait = 2, /* Finished early +- initialisation, but waiting +- for information from the peer +- or hotplug scripts. */ +- XenbusStateInitialised = 3, /* Initialised and waiting for a +- connection from the peer. */ +- XenbusStateConnected = 4, +- XenbusStateClosing = 5, /* The device is being closed +- due to an error or an unplug +- event. */ +- XenbusStateClosed = 6 ++/* ++ * The state of either end of the Xenbus, i.e. the current communication ++ * status of initialisation across the bus. States here imply nothing about ++ * the state of the connection between the driver and the kernel's device ++ * layers. ++ */ ++enum xenbus_state { ++ XenbusStateUnknown = 0, ++ ++ XenbusStateInitialising = 1, ++ ++ /* ++ * InitWait: Finished early initialisation but waiting for information ++ * from the peer or hotplug scripts. ++ */ ++ XenbusStateInitWait = 2, ++ ++ /* ++ * Initialised: Waiting for a connection from the peer. ++ */ ++ XenbusStateInitialised = 3, ++ ++ XenbusStateConnected = 4, ++ ++ /* ++ * Closing: The device is being closed due to an error or an unplug event. ++ */ ++ XenbusStateClosing = 5, ++ ++ XenbusStateClosed = 6, ++ ++ /* ++ * Reconfiguring: The device is being reconfigured. ++ */ ++ XenbusStateReconfiguring = 7, + ++ XenbusStateReconfigured = 8 + }; ++typedef enum xenbus_state XenbusState; + + #endif /* _XEN_PUBLIC_IO_XENBUS_H */ + + /* + * Local variables: +- * c-file-style: "linux" +- * indent-tabs-mode: t +- * c-indent-level: 8 +- * c-basic-offset: 8 +- * tab-width: 8 ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil + * End: + */ +Index: head-2008-11-25/include/xen/interface/io/xs_wire.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/io/xs_wire.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/io/xs_wire.h 2008-11-25 12:35:56.000000000 +0100 +@@ -1,6 +1,25 @@ + /* + * Details of the "wire" protocol between Xen Store Daemon and client + * library or guest kernel. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (C) 2005 Rusty Russell IBM Corporation + */ + +@@ -26,7 +45,9 @@ enum xsd_sockmsg_type + XS_SET_PERMS, + XS_WATCH_EVENT, + XS_ERROR, +- XS_IS_DOMAIN_INTRODUCED ++ XS_IS_DOMAIN_INTRODUCED, ++ XS_RESUME, ++ XS_SET_TARGET + }; + + #define XS_WRITE_NONE "NONE" +@@ -40,7 +61,12 @@ struct xsd_errors + const char *errstring; + }; + #define XSD_ERROR(x) { x, #x } +-static struct xsd_errors xsd_errors[] __attribute__((unused)) = { ++/* LINTED: static unused */ ++static struct xsd_errors xsd_errors[] ++#if defined(__GNUC__) ++__attribute__((unused)) ++#endif ++ = { + XSD_ERROR(EINVAL), + XSD_ERROR(EACCES), + XSD_ERROR(EEXIST), +@@ -84,4 +110,21 @@ struct xenstore_domain_interface { + XENSTORE_RING_IDX rsp_cons, rsp_prod; + }; + ++/* Violating this is very bad. See docs/misc/xenstore.txt. */ ++#define XENSTORE_PAYLOAD_MAX 4096 ++ ++/* Violating these just gets you an error back */ ++#define XENSTORE_ABS_PATH_MAX 3072 ++#define XENSTORE_REL_PATH_MAX 2048 ++ + #endif /* _XS_WIRE_H */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/memory.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/memory.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/memory.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Memory reservation and information. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2005, Keir Fraser + */ + +@@ -10,13 +28,28 @@ + #define __XEN_PUBLIC_MEMORY_H__ + + /* +- * Increase or decrease the specified domain's memory reservation. Returns a +- * -ve errcode on failure, or the # extents successfully allocated or freed. ++ * Increase or decrease the specified domain's memory reservation. Returns the ++ * number of extents successfully allocated or freed. + * arg == addr of struct xen_memory_reservation. + */ + #define XENMEM_increase_reservation 0 + #define XENMEM_decrease_reservation 1 + #define XENMEM_populate_physmap 6 ++ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030209 ++/* ++ * Maximum # bits addressable by the user of the allocated region (e.g., I/O ++ * devices often have a 32-bit limitation even in 64-bit systems). If zero ++ * then the user has no addressing restriction. This field is not used by ++ * XENMEM_decrease_reservation. ++ */ ++#define XENMEMF_address_bits(x) (x) ++#define XENMEMF_get_address_bits(x) ((x) & 0xffu) ++/* NUMA node to allocate from. */ ++#define XENMEMF_node(x) (((x) + 1) << 8) ++#define XENMEMF_get_node(x) ((((x) >> 8) - 1) & 0xffu) ++#endif ++ + struct xen_memory_reservation { + + /* +@@ -29,19 +62,18 @@ struct xen_memory_reservation { + * OUT: GMFN bases of extents that were allocated + * (NB. This command also updates the mach_to_phys translation table) + */ +- GUEST_HANDLE(ulong) extent_start; ++ XEN_GUEST_HANDLE(ulong) extent_start; + + /* Number of extents, and size/alignment of each (2^extent_order pages). */ +- unsigned long nr_extents; ++ xen_ulong_t nr_extents; + unsigned int extent_order; + +- /* +- * Maximum # bits addressable by the user of the allocated region (e.g., +- * I/O devices often have a 32-bit limitation even in 64-bit systems). If +- * zero then the user has no addressing restriction. +- * This field is not used by XENMEM_decrease_reservation. +- */ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030209 ++ /* XENMEMF flags. */ ++ unsigned int mem_flags; ++#else + unsigned int address_bits; ++#endif + + /* + * Domain whose reservation is being changed. +@@ -50,7 +82,51 @@ struct xen_memory_reservation { + domid_t domid; + + }; +-DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation); ++typedef struct xen_memory_reservation xen_memory_reservation_t; ++DEFINE_XEN_GUEST_HANDLE(xen_memory_reservation_t); ++ ++/* ++ * An atomic exchange of memory pages. If return code is zero then ++ * @out.extent_list provides GMFNs of the newly-allocated memory. ++ * Returns zero on complete success, otherwise a negative error code. ++ * On complete success then always @nr_exchanged == @in.nr_extents. ++ * On partial success @nr_exchanged indicates how much work was done. ++ */ ++#define XENMEM_exchange 11 ++struct xen_memory_exchange { ++ /* ++ * [IN] Details of memory extents to be exchanged (GMFN bases). ++ * Note that @in.address_bits is ignored and unused. ++ */ ++ struct xen_memory_reservation in; ++ ++ /* ++ * [IN/OUT] Details of new memory extents. ++ * We require that: ++ * 1. @in.domid == @out.domid ++ * 2. @in.nr_extents << @in.extent_order == ++ * @out.nr_extents << @out.extent_order ++ * 3. @in.extent_start and @out.extent_start lists must not overlap ++ * 4. @out.extent_start lists GPFN bases to be populated ++ * 5. @out.extent_start is overwritten with allocated GMFN bases ++ */ ++ struct xen_memory_reservation out; ++ ++ /* ++ * [OUT] Number of input extents that were successfully exchanged: ++ * 1. The first @nr_exchanged input extents were successfully ++ * deallocated. ++ * 2. The corresponding first entries in the output extent list correctly ++ * indicate the GMFNs that were successfully exchanged. ++ * 3. All other input and output extents are untouched. ++ * 4. If not all input exents are exchanged then the return code of this ++ * command will be non-zero. ++ * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER! ++ */ ++ xen_ulong_t nr_exchanged; ++}; ++typedef struct xen_memory_exchange xen_memory_exchange_t; ++DEFINE_XEN_GUEST_HANDLE(xen_memory_exchange_t); + + /* + * Returns the maximum machine frame number of mapped RAM in this system. +@@ -68,6 +144,11 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_memory_re + #define XENMEM_maximum_reservation 4 + + /* ++ * Returns the maximum GPFN in use by the guest, or -ve errcode on failure. ++ */ ++#define XENMEM_maximum_gpfn 14 ++ ++/* + * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys + * mapping table. Architectures which do not have a m2p table do not implement + * this command. +@@ -86,7 +167,7 @@ struct xen_machphys_mfn_list { + * any large discontiguities in the machine address space, 2MB gaps in + * the machphys table will be represented by an MFN base of zero. + */ +- GUEST_HANDLE(ulong) extent_start; ++ XEN_GUEST_HANDLE(xen_pfn_t) extent_start; + + /* + * Number of extents written to the above array. This will be smaller +@@ -94,7 +175,22 @@ struct xen_machphys_mfn_list { + */ + unsigned int nr_extents; + }; +-DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); ++typedef struct xen_machphys_mfn_list xen_machphys_mfn_list_t; ++DEFINE_XEN_GUEST_HANDLE(xen_machphys_mfn_list_t); ++ ++/* ++ * Returns the location in virtual address space of the machine_to_phys ++ * mapping table. Architectures which do not have a m2p table, or which do not ++ * map it by default into guest address space, do not implement this command. ++ * arg == addr of xen_machphys_mapping_t. ++ */ ++#define XENMEM_machphys_mapping 12 ++struct xen_machphys_mapping { ++ xen_ulong_t v_start, v_end; /* Start and end virtual addresses. */ ++ xen_ulong_t max_mfn; /* Maximum MFN that can be looked up. */ ++}; ++typedef struct xen_machphys_mapping xen_machphys_mapping_t; ++DEFINE_XEN_GUEST_HANDLE(xen_machphys_mapping_t); + + /* + * Sets the GPFN at which a particular page appears in the specified guest's +@@ -109,15 +205,33 @@ struct xen_add_to_physmap { + /* Source mapping space. */ + #define XENMAPSPACE_shared_info 0 /* shared info page */ + #define XENMAPSPACE_grant_table 1 /* grant table page */ ++#define XENMAPSPACE_mfn 2 /* usual MFN */ + unsigned int space; + + /* Index into source mapping space. */ +- unsigned long idx; ++ xen_ulong_t idx; + + /* GPFN where the source mapping page should appear. */ +- unsigned long gpfn; ++ xen_pfn_t gpfn; + }; +-DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap); ++typedef struct xen_add_to_physmap xen_add_to_physmap_t; ++DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t); ++ ++/* ++ * Unmaps the page appearing at a particular GPFN from the specified guest's ++ * pseudophysical address space. ++ * arg == addr of xen_remove_from_physmap_t. ++ */ ++#define XENMEM_remove_from_physmap 15 ++struct xen_remove_from_physmap { ++ /* Which domain to change the mapping for. */ ++ domid_t domid; ++ ++ /* GPFN of the current mapping of the page. */ ++ xen_pfn_t gpfn; ++}; ++typedef struct xen_remove_from_physmap xen_remove_from_physmap_t; ++DEFINE_XEN_GUEST_HANDLE(xen_remove_from_physmap_t); + + /* + * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error +@@ -129,17 +243,71 @@ struct xen_translate_gpfn_list { + domid_t domid; + + /* Length of list. */ +- unsigned long nr_gpfns; ++ xen_ulong_t nr_gpfns; + + /* List of GPFNs to translate. */ +- GUEST_HANDLE(ulong) gpfn_list; ++ XEN_GUEST_HANDLE(xen_pfn_t) gpfn_list; + + /* + * Output list to contain MFN translations. May be the same as the input + * list (in which case each input GPFN is overwritten with the output MFN). + */ +- GUEST_HANDLE(ulong) mfn_list; ++ XEN_GUEST_HANDLE(xen_pfn_t) mfn_list; ++}; ++typedef struct xen_translate_gpfn_list xen_translate_gpfn_list_t; ++DEFINE_XEN_GUEST_HANDLE(xen_translate_gpfn_list_t); ++ ++/* ++ * Returns the pseudo-physical memory map as it was when the domain ++ * was started (specified by XENMEM_set_memory_map). ++ * arg == addr of xen_memory_map_t. ++ */ ++#define XENMEM_memory_map 9 ++struct xen_memory_map { ++ /* ++ * On call the number of entries which can be stored in buffer. On ++ * return the number of entries which have been stored in ++ * buffer. ++ */ ++ unsigned int nr_entries; ++ ++ /* ++ * Entries in the buffer are in the same format as returned by the ++ * BIOS INT 0x15 EAX=0xE820 call. ++ */ ++ XEN_GUEST_HANDLE(void) buffer; ++}; ++typedef struct xen_memory_map xen_memory_map_t; ++DEFINE_XEN_GUEST_HANDLE(xen_memory_map_t); ++ ++/* ++ * Returns the real physical memory map. Passes the same structure as ++ * XENMEM_memory_map. ++ * arg == addr of xen_memory_map_t. ++ */ ++#define XENMEM_machine_memory_map 10 ++ ++/* ++ * Set the pseudo-physical memory map of a domain, as returned by ++ * XENMEM_memory_map. ++ * arg == addr of xen_foreign_memory_map_t. ++ */ ++#define XENMEM_set_memory_map 13 ++struct xen_foreign_memory_map { ++ domid_t domid; ++ struct xen_memory_map map; + }; +-DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list); ++typedef struct xen_foreign_memory_map xen_foreign_memory_map_t; ++DEFINE_XEN_GUEST_HANDLE(xen_foreign_memory_map_t); + + #endif /* __XEN_PUBLIC_MEMORY_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/physdev.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/physdev.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/physdev.h 2008-11-25 12:35:56.000000000 +0100 +@@ -24,7 +24,7 @@ + /* + * Prototype for this hypercall is: + * int physdev_op(int cmd, void *args) +- * @cmd == PHYSDEVOP_??? (physdev operation). ++ * @cmd == PHYSDEVOP_??? (physdev operation). + * @args == Operation-specific extra arguments (NULL if none). + */ + +@@ -32,114 +32,188 @@ + * Notify end-of-interrupt (EOI) for the specified IRQ. + * @arg == pointer to physdev_eoi structure. + */ +-#define PHYSDEVOP_eoi 12 ++#define PHYSDEVOP_eoi 12 + struct physdev_eoi { +- /* IN */ +- uint32_t irq; ++ /* IN */ ++ uint32_t irq; + }; ++typedef struct physdev_eoi physdev_eoi_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t); + + /* + * Query the status of an IRQ line. + * @arg == pointer to physdev_irq_status_query structure. + */ +-#define PHYSDEVOP_irq_status_query 5 ++#define PHYSDEVOP_irq_status_query 5 + struct physdev_irq_status_query { +- /* IN */ +- uint32_t irq; +- /* OUT */ +- uint32_t flags; /* XENIRQSTAT_* */ ++ /* IN */ ++ uint32_t irq; ++ /* OUT */ ++ uint32_t flags; /* XENIRQSTAT_* */ + }; ++typedef struct physdev_irq_status_query physdev_irq_status_query_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_irq_status_query_t); + + /* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */ +-#define _XENIRQSTAT_needs_eoi (0) +-#define XENIRQSTAT_needs_eoi (1U<<_XENIRQSTAT_needs_eoi) ++#define _XENIRQSTAT_needs_eoi (0) ++#define XENIRQSTAT_needs_eoi (1U<<_XENIRQSTAT_needs_eoi) + + /* IRQ shared by multiple guests? */ +-#define _XENIRQSTAT_shared (1) +-#define XENIRQSTAT_shared (1U<<_XENIRQSTAT_shared) ++#define _XENIRQSTAT_shared (1) ++#define XENIRQSTAT_shared (1U<<_XENIRQSTAT_shared) + + /* + * Set the current VCPU's I/O privilege level. + * @arg == pointer to physdev_set_iopl structure. + */ +-#define PHYSDEVOP_set_iopl 6 ++#define PHYSDEVOP_set_iopl 6 + struct physdev_set_iopl { +- /* IN */ +- uint32_t iopl; ++ /* IN */ ++ uint32_t iopl; + }; ++typedef struct physdev_set_iopl physdev_set_iopl_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_set_iopl_t); + + /* + * Set the current VCPU's I/O-port permissions bitmap. + * @arg == pointer to physdev_set_iobitmap structure. + */ +-#define PHYSDEVOP_set_iobitmap 7 ++#define PHYSDEVOP_set_iobitmap 7 + struct physdev_set_iobitmap { +- /* IN */ +- uint8_t * bitmap; +- uint32_t nr_ports; ++ /* IN */ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030205 ++ XEN_GUEST_HANDLE(uint8) bitmap; ++#else ++ uint8_t *bitmap; ++#endif ++ uint32_t nr_ports; + }; ++typedef struct physdev_set_iobitmap physdev_set_iobitmap_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_set_iobitmap_t); + + /* + * Read or write an IO-APIC register. + * @arg == pointer to physdev_apic structure. + */ +-#define PHYSDEVOP_apic_read 8 +-#define PHYSDEVOP_apic_write 9 ++#define PHYSDEVOP_apic_read 8 ++#define PHYSDEVOP_apic_write 9 + struct physdev_apic { +- /* IN */ +- unsigned long apic_physbase; +- uint32_t reg; +- /* IN or OUT */ +- uint32_t value; ++ /* IN */ ++ unsigned long apic_physbase; ++ uint32_t reg; ++ /* IN or OUT */ ++ uint32_t value; + }; ++typedef struct physdev_apic physdev_apic_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_apic_t); + + /* + * Allocate or free a physical upcall vector for the specified IRQ line. + * @arg == pointer to physdev_irq structure. + */ +-#define PHYSDEVOP_alloc_irq_vector 10 +-#define PHYSDEVOP_free_irq_vector 11 ++#define PHYSDEVOP_alloc_irq_vector 10 ++#define PHYSDEVOP_free_irq_vector 11 + struct physdev_irq { +- /* IN */ +- uint32_t irq; +- /* IN or OUT */ +- uint32_t vector; ++ /* IN */ ++ uint32_t irq; ++ /* IN or OUT */ ++ uint32_t vector; ++}; ++typedef struct physdev_irq physdev_irq_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_irq_t); ++ ++#define MAP_PIRQ_TYPE_MSI 0x0 ++#define MAP_PIRQ_TYPE_GSI 0x1 ++#define MAP_PIRQ_TYPE_UNKNOWN 0x2 ++ ++#define PHYSDEVOP_map_pirq 13 ++struct physdev_map_pirq { ++ domid_t domid; ++ /* IN */ ++ int type; ++ /* IN */ ++ int index; ++ /* IN or OUT */ ++ int pirq; ++ /* IN */ ++ int bus; ++ /* IN */ ++ int devfn; ++ /* IN */ ++ int entry_nr; ++ /* IN */ ++ uint64_t table_base; ++}; ++typedef struct physdev_map_pirq physdev_map_pirq_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t); ++ ++#define PHYSDEVOP_unmap_pirq 14 ++struct physdev_unmap_pirq { ++ domid_t domid; ++ /* IN */ ++ int pirq; ++}; ++ ++typedef struct physdev_unmap_pirq physdev_unmap_pirq_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t); ++ ++#define PHYSDEVOP_manage_pci_add 15 ++#define PHYSDEVOP_manage_pci_remove 16 ++struct physdev_manage_pci { ++ /* IN */ ++ uint8_t bus; ++ uint8_t devfn; + }; + ++typedef struct physdev_manage_pci physdev_manage_pci_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_t); ++ + /* + * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() + * hypercall since 0x00030202. + */ + struct physdev_op { +- uint32_t cmd; +- union { +- struct physdev_irq_status_query irq_status_query; +- struct physdev_set_iopl set_iopl; +- struct physdev_set_iobitmap set_iobitmap; +- struct physdev_apic apic_op; +- struct physdev_irq irq_op; +- } u; ++ uint32_t cmd; ++ union { ++ struct physdev_irq_status_query irq_status_query; ++ struct physdev_set_iopl set_iopl; ++ struct physdev_set_iobitmap set_iobitmap; ++ struct physdev_apic apic_op; ++ struct physdev_irq irq_op; ++ } u; + }; ++typedef struct physdev_op physdev_op_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_op_t); + + /* + * Notify that some PIRQ-bound event channels have been unmasked. + * ** This command is obsolete since interface version 0x00030202 and is ** +- * ** unsupported by newer versions of Xen. ** ++ * ** unsupported by newer versions of Xen. ** + */ +-#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4 ++#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4 + + /* + * These all-capitals physdev operation names are superceded by the new names + * (defined above) since interface version 0x00030202. + */ +-#define PHYSDEVOP_IRQ_STATUS_QUERY PHYSDEVOP_irq_status_query +-#define PHYSDEVOP_SET_IOPL PHYSDEVOP_set_iopl +-#define PHYSDEVOP_SET_IOBITMAP PHYSDEVOP_set_iobitmap +-#define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read +-#define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write +-#define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector +-#define PHYSDEVOP_FREE_VECTOR PHYSDEVOP_free_irq_vector ++#define PHYSDEVOP_IRQ_STATUS_QUERY PHYSDEVOP_irq_status_query ++#define PHYSDEVOP_SET_IOPL PHYSDEVOP_set_iopl ++#define PHYSDEVOP_SET_IOBITMAP PHYSDEVOP_set_iobitmap ++#define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read ++#define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write ++#define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector ++#define PHYSDEVOP_FREE_VECTOR PHYSDEVOP_free_irq_vector + #define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi +-#define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared ++#define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared + + #endif /* __XEN_PUBLIC_PHYSDEV_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/sched.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/sched.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/sched.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Scheduler state interactions + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2005, Keir Fraser + */ + +@@ -13,17 +31,17 @@ + + /* + * The prototype for this hypercall is: +- * long sched_op_new(int cmd, void *arg) ++ * long sched_op(int cmd, void *arg) + * @cmd == SCHEDOP_??? (scheduler operation). + * @arg == Operation-specific extra argument(s), as described below. + * +- * **NOTE**: +- * Versions of Xen prior to 3.0.2 provide only the following legacy version ++ * Versions of Xen prior to 3.0.2 provided only the following legacy version + * of this hypercall, supporting only the commands yield, block and shutdown: + * long sched_op(int cmd, unsigned long arg) + * @cmd == SCHEDOP_??? (scheduler operation). + * @arg == 0 (SCHEDOP_yield and SCHEDOP_block) + * == SHUTDOWN_* code (SCHEDOP_shutdown) ++ * This legacy version is available to new guests as sched_op_compat(). + */ + + /* +@@ -49,7 +67,8 @@ + struct sched_shutdown { + unsigned int reason; /* SHUTDOWN_* */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(sched_shutdown); ++typedef struct sched_shutdown sched_shutdown_t; ++DEFINE_XEN_GUEST_HANDLE(sched_shutdown_t); + + /* + * Poll a set of event-channel ports. Return when one or more are pending. An +@@ -58,11 +77,26 @@ DEFINE_GUEST_HANDLE_STRUCT(sched_shutdow + */ + #define SCHEDOP_poll 3 + struct sched_poll { +- GUEST_HANDLE(evtchn_port_t) ports; ++ XEN_GUEST_HANDLE(evtchn_port_t) ports; + unsigned int nr_ports; + uint64_t timeout; + }; +-DEFINE_GUEST_HANDLE_STRUCT(sched_poll); ++typedef struct sched_poll sched_poll_t; ++DEFINE_XEN_GUEST_HANDLE(sched_poll_t); ++ ++/* ++ * Declare a shutdown for another domain. The main use of this function is ++ * in interpreting shutdown requests and reasons for fully-virtualized ++ * domains. A para-virtualized domain may use SCHEDOP_shutdown directly. ++ * @arg == pointer to sched_remote_shutdown structure. ++ */ ++#define SCHEDOP_remote_shutdown 4 ++struct sched_remote_shutdown { ++ domid_t domain_id; /* Remote domain ID */ ++ unsigned int reason; /* SHUTDOWN_xxx reason */ ++}; ++typedef struct sched_remote_shutdown sched_remote_shutdown_t; ++DEFINE_XEN_GUEST_HANDLE(sched_remote_shutdown_t); + + /* + * Reason codes for SCHEDOP_shutdown. These may be interpreted by control +@@ -75,3 +109,13 @@ DEFINE_GUEST_HANDLE_STRUCT(sched_poll); + #define SHUTDOWN_crash 3 /* Tell controller we've crashed. */ + + #endif /* __XEN_PUBLIC_SCHED_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/vcpu.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/vcpu.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/vcpu.h 2008-11-25 12:35:56.000000000 +0100 +@@ -29,9 +29,9 @@ + + /* + * Prototype for this hypercall is: +- * int vcpu_op(int cmd, int vcpuid, void *extra_args) +- * @cmd == VCPUOP_??? (VCPU operation). +- * @vcpuid == VCPU to operate on. ++ * int vcpu_op(int cmd, int vcpuid, void *extra_args) ++ * @cmd == VCPUOP_??? (VCPU operation). ++ * @vcpuid == VCPU to operate on. + * @extra_args == Operation-specific extra arguments (NULL if none). + */ + +@@ -40,52 +40,53 @@ + * newly-initialised VCPU will not run until it is brought up by VCPUOP_up. + * + * @extra_arg == pointer to vcpu_guest_context structure containing initial +- * state for the VCPU. ++ * state for the VCPU. + */ +-#define VCPUOP_initialise 0 ++#define VCPUOP_initialise 0 + + /* + * Bring up a VCPU. This makes the VCPU runnable. This operation will fail + * if the VCPU has not been initialised (VCPUOP_initialise). + */ +-#define VCPUOP_up 1 ++#define VCPUOP_up 1 + + /* + * Bring down a VCPU (i.e., make it non-runnable). + * There are a few caveats that callers should observe: +- * 1. This operation may return, and VCPU_is_up may return false, before the +- * VCPU stops running (i.e., the command is asynchronous). It is a good +- * idea to ensure that the VCPU has entered a non-critical loop before +- * bringing it down. Alternatively, this operation is guaranteed +- * synchronous if invoked by the VCPU itself. +- * 2. After a VCPU is initialised, there is currently no way to drop all its +- * references to domain memory. Even a VCPU that is down still holds +- * memory references via its pagetable base pointer and GDT. It is good +- * practise to move a VCPU onto an 'idle' or default page table, LDT and +- * GDT before bringing it down. ++ * 1. This operation may return, and VCPU_is_up may return false, before the ++ * VCPU stops running (i.e., the command is asynchronous). It is a good ++ * idea to ensure that the VCPU has entered a non-critical loop before ++ * bringing it down. Alternatively, this operation is guaranteed ++ * synchronous if invoked by the VCPU itself. ++ * 2. After a VCPU is initialised, there is currently no way to drop all its ++ * references to domain memory. Even a VCPU that is down still holds ++ * memory references via its pagetable base pointer and GDT. It is good ++ * practise to move a VCPU onto an 'idle' or default page table, LDT and ++ * GDT before bringing it down. + */ +-#define VCPUOP_down 2 ++#define VCPUOP_down 2 + + /* Returns 1 if the given VCPU is up. */ +-#define VCPUOP_is_up 3 ++#define VCPUOP_is_up 3 + + /* + * Return information about the state and running time of a VCPU. + * @extra_arg == pointer to vcpu_runstate_info structure. + */ +-#define VCPUOP_get_runstate_info 4 ++#define VCPUOP_get_runstate_info 4 + struct vcpu_runstate_info { +- /* VCPU's current state (RUNSTATE_*). */ +- int state; +- /* When was current state entered (system time, ns)? */ +- uint64_t state_entry_time; +- /* +- * Time spent in each RUNSTATE_* (ns). The sum of these times is +- * guaranteed not to drift from system time. +- */ +- uint64_t time[4]; ++ /* VCPU's current state (RUNSTATE_*). */ ++ int state; ++ /* When was current state entered (system time, ns)? */ ++ uint64_t state_entry_time; ++ /* ++ * Time spent in each RUNSTATE_* (ns). The sum of these times is ++ * guaranteed not to drift from system time. ++ */ ++ uint64_t time[4]; + }; +-DEFINE_GUEST_HANDLE_STRUCT(vcpu_runstate_info); ++typedef struct vcpu_runstate_info vcpu_runstate_info_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_runstate_info_t); + + /* VCPU is currently running on a physical CPU. */ + #define RUNSTATE_running 0 +@@ -108,47 +109,52 @@ DEFINE_GUEST_HANDLE_STRUCT(vcpu_runstate + * Register a shared memory area from which the guest may obtain its own + * runstate information without needing to execute a hypercall. + * Notes: +- * 1. The registered address may be virtual or physical, depending on the +- * platform. The virtual address should be registered on x86 systems. +- * 2. Only one shared area may be registered per VCPU. The shared area is +- * updated by the hypervisor each time the VCPU is scheduled. Thus +- * runstate.state will always be RUNSTATE_running and +- * runstate.state_entry_time will indicate the system time at which the +- * VCPU was last scheduled to run. ++ * 1. The registered address may be virtual or physical or guest handle, ++ * depending on the platform. Virtual address or guest handle should be ++ * registered on x86 systems. ++ * 2. Only one shared area may be registered per VCPU. The shared area is ++ * updated by the hypervisor each time the VCPU is scheduled. Thus ++ * runstate.state will always be RUNSTATE_running and ++ * runstate.state_entry_time will indicate the system time at which the ++ * VCPU was last scheduled to run. + * @extra_arg == pointer to vcpu_register_runstate_memory_area structure. + */ + #define VCPUOP_register_runstate_memory_area 5 + struct vcpu_register_runstate_memory_area { +- union { +- GUEST_HANDLE(vcpu_runstate_info) h; +- struct vcpu_runstate_info *v; +- uint64_t p; +- } addr; ++ union { ++ XEN_GUEST_HANDLE(vcpu_runstate_info_t) h; ++ struct vcpu_runstate_info *v; ++ uint64_t p; ++ } addr; + }; ++typedef struct vcpu_register_runstate_memory_area vcpu_register_runstate_memory_area_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_register_runstate_memory_area_t); + + /* + * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer + * which can be set via these commands. Periods smaller than one millisecond + * may not be supported. + */ +-#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */ +-#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */ ++#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */ ++#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */ + struct vcpu_set_periodic_timer { +- uint64_t period_ns; ++ uint64_t period_ns; + }; +-DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_periodic_timer); ++typedef struct vcpu_set_periodic_timer vcpu_set_periodic_timer_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_set_periodic_timer_t); + + /* + * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot + * timer which can be set via these commands. + */ +-#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */ ++#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */ + #define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */ + struct vcpu_set_singleshot_timer { +- uint64_t timeout_abs_ns; +- uint32_t flags; /* VCPU_SSHOTTMR_??? */ ++ uint64_t timeout_abs_ns; /* Absolute system time value in nanoseconds. */ ++ uint32_t flags; /* VCPU_SSHOTTMR_??? */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_singleshot_timer); ++typedef struct vcpu_set_singleshot_timer vcpu_set_singleshot_timer_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_set_singleshot_timer_t); + + /* Flags to VCPUOP_set_singleshot_timer. */ + /* Require the timeout to be in the future (return -ETIME if it's passed). */ +@@ -161,13 +167,47 @@ DEFINE_GUEST_HANDLE_STRUCT(vcpu_set_sing + * structure in a convenient place, such as in a per-cpu data area. + * The pointer need not be page aligned, but the structure must not + * cross a page boundary. ++ * ++ * This may be called only once per vcpu. + */ +-#define VCPUOP_register_vcpu_info 10 /* arg == struct vcpu_info */ ++#define VCPUOP_register_vcpu_info 10 /* arg == vcpu_register_vcpu_info_t */ + struct vcpu_register_vcpu_info { + uint64_t mfn; /* mfn of page to place vcpu_info */ + uint32_t offset; /* offset within page */ + uint32_t rsvd; /* unused */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_vcpu_info); ++typedef struct vcpu_register_vcpu_info vcpu_register_vcpu_info_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_register_vcpu_info_t); ++ ++/* Send an NMI to the specified VCPU. @extra_arg == NULL. */ ++#define VCPUOP_send_nmi 11 ++ ++/* ++ * Get the physical ID information for a pinned vcpu's underlying physical ++ * processor. The physical ID informmation is architecture-specific. ++ * On x86: id[31:0]=apic_id, id[63:32]=acpi_id, and all values 0xff and ++ * greater are reserved. ++ * This command returns -EINVAL if it is not a valid operation for this VCPU. ++ */ ++#define VCPUOP_get_physid 12 /* arg == vcpu_get_physid_t */ ++struct vcpu_get_physid { ++ uint64_t phys_id; ++}; ++typedef struct vcpu_get_physid vcpu_get_physid_t; ++DEFINE_XEN_GUEST_HANDLE(vcpu_get_physid_t); ++#define xen_vcpu_physid_to_x86_apicid(physid) \ ++ ((((uint32_t)(physid)) >= 0xff) ? 0xff : ((uint8_t)(physid))) ++#define xen_vcpu_physid_to_x86_acpiid(physid) \ ++ ((((uint32_t)((physid)>>32)) >= 0xff) ? 0xff : ((uint8_t)((physid)>>32))) + + #endif /* __XEN_PUBLIC_VCPU_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/version.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/version.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/version.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,6 +3,24 @@ + * + * Xen version, type, and compile information. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2005, Nguyen Anh Quynh + * Copyright (c) 2005, Keir Fraser + */ +@@ -10,17 +28,15 @@ + #ifndef __XEN_PUBLIC_VERSION_H__ + #define __XEN_PUBLIC_VERSION_H__ + +-/* NB. All ops return zero on success, except XENVER_version. */ ++/* NB. All ops return zero on success, except XENVER_{version,pagesize} */ + + /* arg == NULL; returns major:minor (16:16). */ + #define XENVER_version 0 + + /* arg == xen_extraversion_t. */ + #define XENVER_extraversion 1 +-struct xen_extraversion { +- char extraversion[16]; +-}; +-#define XEN_EXTRAVERSION_LEN (sizeof(struct xen_extraversion)) ++typedef char xen_extraversion_t[16]; ++#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t)) + + /* arg == xen_compile_info_t. */ + #define XENVER_compile_info 2 +@@ -30,31 +46,46 @@ struct xen_compile_info { + char compile_domain[32]; + char compile_date[32]; + }; ++typedef struct xen_compile_info xen_compile_info_t; + + #define XENVER_capabilities 3 +-struct xen_capabilities_info { +- char info[1024]; +-}; +-#define XEN_CAPABILITIES_INFO_LEN (sizeof(struct xen_capabilities_info)) ++typedef char xen_capabilities_info_t[1024]; ++#define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t)) + + #define XENVER_changeset 4 +-struct xen_changeset_info { +- char info[64]; +-}; +-#define XEN_CHANGESET_INFO_LEN (sizeof(struct xen_changeset_info)) ++typedef char xen_changeset_info_t[64]; ++#define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t)) + + #define XENVER_platform_parameters 5 + struct xen_platform_parameters { + unsigned long virt_start; + }; ++typedef struct xen_platform_parameters xen_platform_parameters_t; + + #define XENVER_get_features 6 + struct xen_feature_info { + unsigned int submap_idx; /* IN: which 32-bit submap to return */ + uint32_t submap; /* OUT: 32-bit submap */ + }; ++typedef struct xen_feature_info xen_feature_info_t; + + /* Declares the features reported by XENVER_get_features. */ + #include "features.h" + ++/* arg == NULL; returns host memory page size. */ ++#define XENVER_pagesize 7 ++ ++/* arg == xen_domain_handle_t. */ ++#define XENVER_guest_handle 8 ++ + #endif /* __XEN_PUBLIC_VERSION_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/interface/xen.h +=================================================================== +--- head-2008-11-25.orig/include/xen/interface/xen.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/interface/xen.h 2008-11-25 12:35:56.000000000 +0100 +@@ -3,35 +3,68 @@ + * + * Guest OS interface to Xen. + * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to ++ * deal in the Software without restriction, including without limitation the ++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * + * Copyright (c) 2004, K A Fraser + */ + + #ifndef __XEN_PUBLIC_XEN_H__ + #define __XEN_PUBLIC_XEN_H__ + +-#include ++#include "xen-compat.h" ++#ifdef CONFIG_PARAVIRT_XEN + #include ++#endif + +-/* +- * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS). +- */ ++#if defined(__i386__) || defined(__x86_64__) ++#include "arch-x86/xen.h" ++#elif defined(__ia64__) ++#include "arch-ia64.h" ++#else ++#error "Unsupported architecture" ++#endif ++ ++#ifndef __ASSEMBLY__ ++/* Guest handles for primitive C types. */ ++DEFINE_XEN_GUEST_HANDLE(char); ++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char); ++DEFINE_XEN_GUEST_HANDLE(int); ++__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int); ++DEFINE_XEN_GUEST_HANDLE(long); ++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); ++DEFINE_XEN_GUEST_HANDLE(void); ++ ++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); ++#endif + + /* +- * x86_32: EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. +- * EAX = return value +- * (argument registers may be clobbered on return) +- * x86_64: RAX = vector; RDI, RSI, RDX, R10, R8, R9 = args 1, 2, 3, 4, 5, 6. +- * RAX = return value +- * (argument registers not clobbered on return; RCX, R11 are) ++ * HYPERCALLS + */ ++ + #define __HYPERVISOR_set_trap_table 0 + #define __HYPERVISOR_mmu_update 1 + #define __HYPERVISOR_set_gdt 2 + #define __HYPERVISOR_stack_switch 3 + #define __HYPERVISOR_set_callbacks 4 + #define __HYPERVISOR_fpu_taskswitch 5 +-#define __HYPERVISOR_sched_op 6 +-#define __HYPERVISOR_dom0_op 7 ++#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */ ++#define __HYPERVISOR_platform_op 7 + #define __HYPERVISOR_set_debugreg 8 + #define __HYPERVISOR_get_debugreg 9 + #define __HYPERVISOR_update_descriptor 10 +@@ -39,10 +72,10 @@ + #define __HYPERVISOR_multicall 13 + #define __HYPERVISOR_update_va_mapping 14 + #define __HYPERVISOR_set_timer_op 15 +-#define __HYPERVISOR_event_channel_op_compat 16 ++#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */ + #define __HYPERVISOR_xen_version 17 + #define __HYPERVISOR_console_io 18 +-#define __HYPERVISOR_physdev_op_compat 19 ++#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */ + #define __HYPERVISOR_grant_table_op 20 + #define __HYPERVISOR_vm_assist 21 + #define __HYPERVISOR_update_va_mapping_otherdomain 22 +@@ -50,7 +83,7 @@ + #define __HYPERVISOR_vcpu_op 24 + #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ + #define __HYPERVISOR_mmuext_op 26 +-#define __HYPERVISOR_acm_op 27 ++#define __HYPERVISOR_xsm_op 27 + #define __HYPERVISOR_nmi_op 28 + #define __HYPERVISOR_sched_op_new 29 + #define __HYPERVISOR_callback_op 30 +@@ -58,6 +91,9 @@ + #define __HYPERVISOR_event_channel_op 32 + #define __HYPERVISOR_physdev_op 33 + #define __HYPERVISOR_hvm_op 34 ++#define __HYPERVISOR_sysctl 35 ++#define __HYPERVISOR_domctl 36 ++#define __HYPERVISOR_kexec_op 37 + + /* Architecture-specific hypercall definitions. */ + #define __HYPERVISOR_arch_0 48 +@@ -70,15 +106,48 @@ + #define __HYPERVISOR_arch_7 55 + + /* ++ * HYPERCALL COMPATIBILITY. ++ */ ++ ++/* New sched_op hypercall introduced in 0x00030101. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030101 ++#undef __HYPERVISOR_sched_op ++#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat ++#else ++#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_new ++#endif ++ ++/* New event-channel and physdev hypercalls introduced in 0x00030202. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030202 ++#undef __HYPERVISOR_event_channel_op ++#define __HYPERVISOR_event_channel_op __HYPERVISOR_event_channel_op_compat ++#undef __HYPERVISOR_physdev_op ++#define __HYPERVISOR_physdev_op __HYPERVISOR_physdev_op_compat ++#endif ++ ++/* New platform_op hypercall introduced in 0x00030204. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030204 ++#define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op ++#endif ++ ++/* + * VIRTUAL INTERRUPTS + * + * Virtual interrupts that a guest OS may receive from Xen. +- */ +-#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */ +-#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */ +-#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ +-#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ +-#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ ++ * ++ * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a ++ * global VIRQ. The former can be bound once per VCPU and cannot be re-bound. ++ * The latter can be allocated only once per guest: they must initially be ++ * allocated to VCPU0 but can subsequently be re-bound. ++ */ ++#define VIRQ_TIMER 0 /* V. Timebase update, and/or requested timeout. */ ++#define VIRQ_DEBUG 1 /* V. Request guest to dump debug info. */ ++#define VIRQ_CONSOLE 2 /* G. (DOM0) Bytes received on emergency console. */ ++#define VIRQ_DOM_EXC 3 /* G. (DOM0) Exceptional event for some domain. */ ++#define VIRQ_TBUF 4 /* G. (DOM0) Trace buffer has records available. */ ++#define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */ ++#define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */ ++#define VIRQ_CON_RING 8 /* G. (DOM0) Bytes received on console */ + + /* Architecture-specific VIRQ definitions. */ + #define VIRQ_ARCH_0 16 +@@ -91,6 +158,7 @@ + #define VIRQ_ARCH_7 23 + + #define NR_VIRQS 24 ++ + /* + * MMU-UPDATE REQUESTS + * +@@ -166,6 +234,13 @@ + * cmd: MMUEXT_SET_LDT + * linear_addr: Linear address of LDT base (NB. must be page-aligned). + * nr_ents: Number of entries in LDT. ++ * ++ * cmd: MMUEXT_CLEAR_PAGE ++ * mfn: Machine frame number to be cleared. ++ * ++ * cmd: MMUEXT_COPY_PAGE ++ * mfn: Machine frame number of the destination page. ++ * src_mfn: Machine frame number of the source page. + */ + #define MMUEXT_PIN_L1_TABLE 0 + #define MMUEXT_PIN_L2_TABLE 1 +@@ -182,24 +257,34 @@ + #define MMUEXT_FLUSH_CACHE 12 + #define MMUEXT_SET_LDT 13 + #define MMUEXT_NEW_USER_BASEPTR 15 ++#define MMUEXT_CLEAR_PAGE 16 ++#define MMUEXT_COPY_PAGE 17 + + #ifndef __ASSEMBLY__ + struct mmuext_op { +- unsigned int cmd; +- union { +- /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */ +- unsigned long mfn; +- /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */ +- unsigned long linear_addr; +- } arg1; +- union { +- /* SET_LDT */ +- unsigned int nr_ents; +- /* TLB_FLUSH_MULTI, INVLPG_MULTI */ +- void *vcpumask; +- } arg2; ++ unsigned int cmd; ++ union { ++ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR ++ * CLEAR_PAGE, COPY_PAGE */ ++ xen_pfn_t mfn; ++ /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */ ++ unsigned long linear_addr; ++ } arg1; ++ union { ++ /* SET_LDT */ ++ unsigned int nr_ents; ++ /* TLB_FLUSH_MULTI, INVLPG_MULTI */ ++#if __XEN_INTERFACE_VERSION__ >= 0x00030205 ++ XEN_GUEST_HANDLE(void) vcpumask; ++#else ++ void *vcpumask; ++#endif ++ /* COPY_PAGE */ ++ xen_pfn_t src_mfn; ++ } arg2; + }; +-DEFINE_GUEST_HANDLE_STRUCT(mmuext_op); ++typedef struct mmuext_op mmuext_op_t; ++DEFINE_XEN_GUEST_HANDLE(mmuext_op_t); + #endif + + /* These are passed as 'flags' to update_va_mapping. They can be ORed. */ +@@ -224,11 +309,24 @@ DEFINE_GUEST_HANDLE_STRUCT(mmuext_op); + */ + #define VMASST_CMD_enable 0 + #define VMASST_CMD_disable 1 ++ ++/* x86/32 guests: simulate full 4GB segment limits. */ + #define VMASST_TYPE_4gb_segments 0 ++ ++/* x86/32 guests: trap (vector 15) whenever above vmassist is used. */ + #define VMASST_TYPE_4gb_segments_notify 1 ++ ++/* ++ * x86 guests: support writes to bottom-level PTEs. ++ * NB1. Page-directory entries cannot be written. ++ * NB2. Guest must continue to remove all writable mappings of PTEs. ++ */ + #define VMASST_TYPE_writable_pagetables 2 ++ ++/* x86/PAE guests: support PDPTs above 4GB. */ + #define VMASST_TYPE_pae_extended_cr3 3 +-#define MAX_VMASST_TYPE 3 ++ ++#define MAX_VMASST_TYPE 3 + + #ifndef __ASSEMBLY__ + +@@ -267,18 +365,19 @@ struct mmu_update { + uint64_t ptr; /* Machine address of PTE. */ + uint64_t val; /* New contents of PTE. */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(mmu_update); ++typedef struct mmu_update mmu_update_t; ++DEFINE_XEN_GUEST_HANDLE(mmu_update_t); + + /* + * Send an array of these to HYPERVISOR_multicall(). + * NB. The fields are natural register size for this architecture. + */ + struct multicall_entry { +- unsigned long op; +- long result; ++ unsigned long op, result; + unsigned long args[6]; + }; +-DEFINE_GUEST_HANDLE_STRUCT(multicall_entry); ++typedef struct multicall_entry multicall_entry_t; ++DEFINE_XEN_GUEST_HANDLE(multicall_entry_t); + + /* + * Event channel endpoints per domain: +@@ -287,173 +386,240 @@ DEFINE_GUEST_HANDLE_STRUCT(multicall_ent + #define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64) + + struct vcpu_time_info { +- /* +- * Updates to the following values are preceded and followed +- * by an increment of 'version'. The guest can therefore +- * detect updates by looking for changes to 'version'. If the +- * least-significant bit of the version number is set then an +- * update is in progress and the guest must wait to read a +- * consistent set of values. The correct way to interact with +- * the version number is similar to Linux's seqlock: see the +- * implementations of read_seqbegin/read_seqretry. +- */ +- uint32_t version; +- uint32_t pad0; +- uint64_t tsc_timestamp; /* TSC at last update of time vals. */ +- uint64_t system_time; /* Time, in nanosecs, since boot. */ +- /* +- * Current system time: +- * system_time + ((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul +- * CPU frequency (Hz): +- * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift +- */ +- uint32_t tsc_to_system_mul; +- int8_t tsc_shift; +- int8_t pad1[3]; ++ /* ++ * Updates to the following values are preceded and followed by an ++ * increment of 'version'. The guest can therefore detect updates by ++ * looking for changes to 'version'. If the least-significant bit of ++ * the version number is set then an update is in progress and the guest ++ * must wait to read a consistent set of values. ++ * The correct way to interact with the version number is similar to ++ * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry. ++ */ ++ uint32_t version; ++ uint32_t pad0; ++ uint64_t tsc_timestamp; /* TSC at last update of time vals. */ ++ uint64_t system_time; /* Time, in nanosecs, since boot. */ ++ /* ++ * Current system time: ++ * system_time + ++ * ((((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul) >> 32) ++ * CPU frequency (Hz): ++ * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift ++ */ ++ uint32_t tsc_to_system_mul; ++ int8_t tsc_shift; ++ int8_t pad1[3]; + }; /* 32 bytes */ ++typedef struct vcpu_time_info vcpu_time_info_t; + + struct vcpu_info { +- /* +- * 'evtchn_upcall_pending' is written non-zero by Xen to indicate +- * a pending notification for a particular VCPU. It is then cleared +- * by the guest OS /before/ checking for pending work, thus avoiding +- * a set-and-check race. Note that the mask is only accessed by Xen +- * on the CPU that is currently hosting the VCPU. This means that the +- * pending and mask flags can be updated by the guest without special +- * synchronisation (i.e., no need for the x86 LOCK prefix). +- * This may seem suboptimal because if the pending flag is set by +- * a different CPU then an IPI may be scheduled even when the mask +- * is set. However, note: +- * 1. The task of 'interrupt holdoff' is covered by the per-event- +- * channel mask bits. A 'noisy' event that is continually being +- * triggered can be masked at source at this very precise +- * granularity. +- * 2. The main purpose of the per-VCPU mask is therefore to restrict +- * reentrant execution: whether for concurrency control, or to +- * prevent unbounded stack usage. Whatever the purpose, we expect +- * that the mask will be asserted only for short periods at a time, +- * and so the likelihood of a 'spurious' IPI is suitably small. +- * The mask is read before making an event upcall to the guest: a +- * non-zero mask therefore guarantees that the VCPU will not receive +- * an upcall activation. The mask is cleared when the VCPU requests +- * to block: this avoids wakeup-waiting races. +- */ +- uint8_t evtchn_upcall_pending; +- uint8_t evtchn_upcall_mask; +- unsigned long evtchn_pending_sel; +- struct arch_vcpu_info arch; +- struct pvclock_vcpu_time_info time; ++ /* ++ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate ++ * a pending notification for a particular VCPU. It is then cleared ++ * by the guest OS /before/ checking for pending work, thus avoiding ++ * a set-and-check race. Note that the mask is only accessed by Xen ++ * on the CPU that is currently hosting the VCPU. This means that the ++ * pending and mask flags can be updated by the guest without special ++ * synchronisation (i.e., no need for the x86 LOCK prefix). ++ * This may seem suboptimal because if the pending flag is set by ++ * a different CPU then an IPI may be scheduled even when the mask ++ * is set. However, note: ++ * 1. The task of 'interrupt holdoff' is covered by the per-event- ++ * channel mask bits. A 'noisy' event that is continually being ++ * triggered can be masked at source at this very precise ++ * granularity. ++ * 2. The main purpose of the per-VCPU mask is therefore to restrict ++ * reentrant execution: whether for concurrency control, or to ++ * prevent unbounded stack usage. Whatever the purpose, we expect ++ * that the mask will be asserted only for short periods at a time, ++ * and so the likelihood of a 'spurious' IPI is suitably small. ++ * The mask is read before making an event upcall to the guest: a ++ * non-zero mask therefore guarantees that the VCPU will not receive ++ * an upcall activation. The mask is cleared when the VCPU requests ++ * to block: this avoids wakeup-waiting races. ++ */ ++ uint8_t evtchn_upcall_pending; ++ uint8_t evtchn_upcall_mask; ++ unsigned long evtchn_pending_sel; ++ struct arch_vcpu_info arch; ++#ifdef CONFIG_PARAVIRT_XEN ++ struct pvclock_vcpu_time_info time; ++#else ++ struct vcpu_time_info time; ++#endif + }; /* 64 bytes (x86) */ ++#ifndef __XEN__ ++typedef struct vcpu_info vcpu_info_t; ++#endif + + /* + * Xen/kernel shared data -- pointer provided in start_info. +- * NB. We expect that this struct is smaller than a page. ++ * ++ * This structure is defined to be both smaller than a page, and the ++ * only data on the shared page, but may vary in actual size even within ++ * compatible Xen versions; guests should not rely on the size ++ * of this structure remaining constant. + */ + struct shared_info { +- struct vcpu_info vcpu_info[MAX_VIRT_CPUS]; ++ struct vcpu_info vcpu_info[MAX_VIRT_CPUS]; + +- /* +- * A domain can create "event channels" on which it can send and receive +- * asynchronous event notifications. There are three classes of event that +- * are delivered by this mechanism: +- * 1. Bi-directional inter- and intra-domain connections. Domains must +- * arrange out-of-band to set up a connection (usually by allocating +- * an unbound 'listener' port and avertising that via a storage service +- * such as xenstore). +- * 2. Physical interrupts. A domain with suitable hardware-access +- * privileges can bind an event-channel port to a physical interrupt +- * source. +- * 3. Virtual interrupts ('events'). A domain can bind an event-channel +- * port to a virtual interrupt source, such as the virtual-timer +- * device or the emergency console. +- * +- * Event channels are addressed by a "port index". Each channel is +- * associated with two bits of information: +- * 1. PENDING -- notifies the domain that there is a pending notification +- * to be processed. This bit is cleared by the guest. +- * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING +- * will cause an asynchronous upcall to be scheduled. This bit is only +- * updated by the guest. It is read-only within Xen. If a channel +- * becomes pending while the channel is masked then the 'edge' is lost +- * (i.e., when the channel is unmasked, the guest must manually handle +- * pending notifications as no upcall will be scheduled by Xen). +- * +- * To expedite scanning of pending notifications, any 0->1 pending +- * transition on an unmasked channel causes a corresponding bit in a +- * per-vcpu selector word to be set. Each bit in the selector covers a +- * 'C long' in the PENDING bitfield array. +- */ +- unsigned long evtchn_pending[sizeof(unsigned long) * 8]; +- unsigned long evtchn_mask[sizeof(unsigned long) * 8]; +- +- /* +- * Wallclock time: updated only by control software. Guests should base +- * their gettimeofday() syscall on this wallclock-base value. +- */ +- struct pvclock_wall_clock wc; ++ /* ++ * A domain can create "event channels" on which it can send and receive ++ * asynchronous event notifications. There are three classes of event that ++ * are delivered by this mechanism: ++ * 1. Bi-directional inter- and intra-domain connections. Domains must ++ * arrange out-of-band to set up a connection (usually by allocating ++ * an unbound 'listener' port and avertising that via a storage service ++ * such as xenstore). ++ * 2. Physical interrupts. A domain with suitable hardware-access ++ * privileges can bind an event-channel port to a physical interrupt ++ * source. ++ * 3. Virtual interrupts ('events'). A domain can bind an event-channel ++ * port to a virtual interrupt source, such as the virtual-timer ++ * device or the emergency console. ++ * ++ * Event channels are addressed by a "port index". Each channel is ++ * associated with two bits of information: ++ * 1. PENDING -- notifies the domain that there is a pending notification ++ * to be processed. This bit is cleared by the guest. ++ * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING ++ * will cause an asynchronous upcall to be scheduled. This bit is only ++ * updated by the guest. It is read-only within Xen. If a channel ++ * becomes pending while the channel is masked then the 'edge' is lost ++ * (i.e., when the channel is unmasked, the guest must manually handle ++ * pending notifications as no upcall will be scheduled by Xen). ++ * ++ * To expedite scanning of pending notifications, any 0->1 pending ++ * transition on an unmasked channel causes a corresponding bit in a ++ * per-vcpu selector word to be set. Each bit in the selector covers a ++ * 'C long' in the PENDING bitfield array. ++ */ ++ unsigned long evtchn_pending[sizeof(unsigned long) * 8]; ++ unsigned long evtchn_mask[sizeof(unsigned long) * 8]; ++ ++ /* ++ * Wallclock time: updated only by control software. Guests should base ++ * their gettimeofday() syscall on this wallclock-base value. ++ */ ++#ifdef CONFIG_PARAVIRT_XEN ++ struct pvclock_wall_clock wc; ++#else ++ uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */ ++ uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */ ++ uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */ ++#endif + +- struct arch_shared_info arch; ++ struct arch_shared_info arch; + + }; ++#ifndef __XEN__ ++typedef struct shared_info shared_info_t; ++#endif + + /* +- * Start-of-day memory layout for the initial domain (DOM0): ++ * Start-of-day memory layout: + * 1. The domain is started within contiguous virtual-memory region. +- * 2. The contiguous region begins and ends on an aligned 4MB boundary. +- * 3. The region start corresponds to the load address of the OS image. +- * If the load address is not 4MB aligned then the address is rounded down. +- * 4. This the order of bootstrap elements in the initial virtual region: ++ * 2. The contiguous region ends on an aligned 4MB boundary. ++ * 3. This the order of bootstrap elements in the initial virtual region: + * a. relocated kernel image + * b. initial ram disk [mod_start, mod_len] + * c. list of allocated page frames [mfn_list, nr_pages] + * d. start_info_t structure [register ESI (x86)] + * e. bootstrap page tables [pt_base, CR3 (x86)] + * f. bootstrap stack [register ESP (x86)] +- * 5. Bootstrap elements are packed together, but each is 4kB-aligned. +- * 6. The initial ram disk may be omitted. +- * 7. The list of page frames forms a contiguous 'pseudo-physical' memory ++ * 4. Bootstrap elements are packed together, but each is 4kB-aligned. ++ * 5. The initial ram disk may be omitted. ++ * 6. The list of page frames forms a contiguous 'pseudo-physical' memory + * layout for the domain. In particular, the bootstrap virtual-memory + * region is a 1:1 mapping to the first section of the pseudo-physical map. +- * 8. All bootstrap elements are mapped read-writable for the guest OS. The ++ * 7. All bootstrap elements are mapped read-writable for the guest OS. The + * only exception is the bootstrap page table, which is mapped read-only. +- * 9. There is guaranteed to be at least 512kB padding after the final ++ * 8. There is guaranteed to be at least 512kB padding after the final + * bootstrap element. If necessary, the bootstrap virtual region is + * extended by an extra 4MB to ensure this. + */ + + #define MAX_GUEST_CMDLINE 1024 + struct start_info { +- /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */ +- char magic[32]; /* "xen--". */ +- unsigned long nr_pages; /* Total pages allocated to this domain. */ +- unsigned long shared_info; /* MACHINE address of shared info struct. */ +- uint32_t flags; /* SIF_xxx flags. */ +- unsigned long store_mfn; /* MACHINE page number of shared page. */ +- uint32_t store_evtchn; /* Event channel for store communication. */ +- union { +- struct { +- unsigned long mfn; /* MACHINE page number of console page. */ +- uint32_t evtchn; /* Event channel for console page. */ +- } domU; +- struct { +- uint32_t info_off; /* Offset of console_info struct. */ +- uint32_t info_size; /* Size of console_info struct from start.*/ +- } dom0; +- } console; +- /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */ +- unsigned long pt_base; /* VIRTUAL address of page directory. */ +- unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */ +- unsigned long mfn_list; /* VIRTUAL address of page-frame list. */ +- unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */ +- unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ +- int8_t cmd_line[MAX_GUEST_CMDLINE]; ++ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */ ++ char magic[32]; /* "xen--". */ ++ unsigned long nr_pages; /* Total pages allocated to this domain. */ ++ unsigned long shared_info; /* MACHINE address of shared info struct. */ ++ uint32_t flags; /* SIF_xxx flags. */ ++ xen_pfn_t store_mfn; /* MACHINE page number of shared page. */ ++ uint32_t store_evtchn; /* Event channel for store communication. */ ++ union { ++ struct { ++ xen_pfn_t mfn; /* MACHINE page number of console page. */ ++ uint32_t evtchn; /* Event channel for console page. */ ++ } domU; ++ struct { ++ uint32_t info_off; /* Offset of console_info struct. */ ++ uint32_t info_size; /* Size of console_info struct from start.*/ ++ } dom0; ++ } console; ++ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */ ++ unsigned long pt_base; /* VIRTUAL address of page directory. */ ++ unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */ ++ unsigned long mfn_list; /* VIRTUAL address of page-frame list. */ ++ unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */ ++ unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ ++ int8_t cmd_line[MAX_GUEST_CMDLINE]; + }; ++typedef struct start_info start_info_t; ++ ++/* New console union for dom0 introduced in 0x00030203. */ ++#if __XEN_INTERFACE_VERSION__ < 0x00030203 ++#define console_mfn console.domU.mfn ++#define console_evtchn console.domU.evtchn ++#endif + + /* These flags are passed in the 'flags' field of start_info_t. */ + #define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */ + #define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */ ++#define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */ + +-typedef uint64_t cpumap_t; ++typedef struct dom0_vga_console_info { ++ uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */ ++#define XEN_VGATYPE_TEXT_MODE_3 0x03 ++#define XEN_VGATYPE_VESA_LFB 0x23 ++ ++ union { ++ struct { ++ /* Font height, in pixels. */ ++ uint16_t font_height; ++ /* Cursor location (column, row). */ ++ uint16_t cursor_x, cursor_y; ++ /* Number of rows and columns (dimensions in characters). */ ++ uint16_t rows, columns; ++ } text_mode_3; ++ ++ struct { ++ /* Width and height, in pixels. */ ++ uint16_t width, height; ++ /* Bytes per scan line. */ ++ uint16_t bytes_per_line; ++ /* Bits per pixel. */ ++ uint16_t bits_per_pixel; ++ /* LFB physical address, and size (in units of 64kB). */ ++ uint32_t lfb_base; ++ uint32_t lfb_size; ++ /* RGB mask offsets and sizes, as defined by VBE 1.2+ */ ++ uint8_t red_pos, red_size; ++ uint8_t green_pos, green_size; ++ uint8_t blue_pos, blue_size; ++ uint8_t rsvd_pos, rsvd_size; ++#if __XEN_INTERFACE_VERSION__ >= 0x00030206 ++ /* VESA capabilities (offset 0xa, VESA command 0x4f00). */ ++ uint32_t gbl_caps; ++ /* Mode attributes (offset 0x0, VESA command 0x4f01). */ ++ uint16_t mode_attrs; ++#endif ++ } vesa_lfb; ++ } u; ++} dom0_vga_console_info_t; ++#define xen_vga_console_info dom0_vga_console_info ++#define xen_vga_console_info_t dom0_vga_console_info_t + + typedef uint8_t xen_domain_handle_t[16]; + +@@ -461,6 +627,11 @@ typedef uint8_t xen_domain_handle_t[16]; + #define __mk_unsigned_long(x) x ## UL + #define mk_unsigned_long(x) __mk_unsigned_long(x) + ++__DEFINE_XEN_GUEST_HANDLE(uint8, uint8_t); ++__DEFINE_XEN_GUEST_HANDLE(uint16, uint16_t); ++__DEFINE_XEN_GUEST_HANDLE(uint32, uint32_t); ++__DEFINE_XEN_GUEST_HANDLE(uint64, uint64_t); ++ + #else /* __ASSEMBLY__ */ + + /* In assembly code we cannot use C numeric constant suffixes. */ +@@ -468,4 +639,24 @@ typedef uint8_t xen_domain_handle_t[16]; + + #endif /* !__ASSEMBLY__ */ + ++/* Default definitions for macros used by domctl/sysctl. */ ++#if defined(__XEN__) || defined(__XEN_TOOLS__) ++#ifndef uint64_aligned_t ++#define uint64_aligned_t uint64_t ++#endif ++#ifndef XEN_GUEST_HANDLE_64 ++#define XEN_GUEST_HANDLE_64(name) XEN_GUEST_HANDLE(name) ++#endif ++#endif ++ + #endif /* __XEN_PUBLIC_XEN_H__ */ ++ ++/* ++ * Local variables: ++ * mode: C ++ * c-set-style: "BSD" ++ * c-basic-offset: 4 ++ * tab-width: 4 ++ * indent-tabs-mode: nil ++ * End: ++ */ +Index: head-2008-11-25/include/xen/xenbus.h +=================================================================== +--- head-2008-11-25.orig/include/xen/xenbus.h 2008-11-25 12:33:06.000000000 +0100 ++++ head-2008-11-25/include/xen/xenbus.h 2008-11-25 12:35:56.000000000 +0100 +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -55,8 +56,17 @@ struct xenbus_watch + /* Callback (executed in a process context with no locks held). */ + void (*callback)(struct xenbus_watch *, + const char **vec, unsigned int len); ++ ++ /* See XBWF_ definitions below. */ ++ unsigned long flags; + }; + ++/* ++ * Execute callback in its own kthread. Useful if the callback is long ++ * running or heavily serialised, to avoid taking out the main xenwatch thread ++ * for a long period of time (or even unwittingly causing a deadlock). ++ */ ++#define XBWF_new_thread 1 + + /* A xenbus device. */ + struct xenbus_device { +@@ -105,27 +115,8 @@ static inline struct xenbus_driver *to_x + return container_of(drv, struct xenbus_driver, driver); + } + +-int __must_check __xenbus_register_frontend(struct xenbus_driver *drv, +- struct module *owner, +- const char *mod_name); +- +-static inline int __must_check +-xenbus_register_frontend(struct xenbus_driver *drv) +-{ +- WARN_ON(drv->owner != THIS_MODULE); +- return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME); +-} +- +-int __must_check __xenbus_register_backend(struct xenbus_driver *drv, +- struct module *owner, +- const char *mod_name); +-static inline int __must_check +-xenbus_register_backend(struct xenbus_driver *drv) +-{ +- WARN_ON(drv->owner != THIS_MODULE); +- return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME); +-} +- ++int xenbus_register_frontend(struct xenbus_driver *drv); ++int xenbus_register_backend(struct xenbus_driver *drv); + void xenbus_unregister_driver(struct xenbus_driver *drv); + + struct xenbus_transaction +@@ -136,8 +127,6 @@ struct xenbus_transaction + /* Nil transaction ID. */ + #define XBT_NIL ((struct xenbus_transaction) { 0 }) + +-int __init xenbus_dev_init(void); +- + char **xenbus_directory(struct xenbus_transaction t, + const char *dir, const char *node, unsigned int *num); + void *xenbus_read(struct xenbus_transaction t, +@@ -167,7 +156,6 @@ int xenbus_printf(struct xenbus_transact + int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); + + /* notifer routines for when the xenstore comes up */ +-extern int xenstored_ready; + int register_xenstore_notifier(struct notifier_block *nb); + void unregister_xenstore_notifier(struct notifier_block *nb); + +@@ -180,12 +168,9 @@ void xs_suspend_cancel(void); + /* Used by xenbus_dev to borrow kernel's store connection. */ + void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); + +-struct work_struct; +- + /* Prepare for domain suspend: then resume or cancel the suspend. */ + void xenbus_suspend(void); + void xenbus_resume(void); +-void xenbus_probe(struct work_struct *); + void xenbus_suspend_cancel(void); + + #define XENBUS_IS_ERR_READ(str) ({ \ +@@ -198,38 +183,125 @@ void xenbus_suspend_cancel(void); + + #define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE) + ++ ++/** ++ * Register a watch on the given path, using the given xenbus_watch structure ++ * for storage, and the given callback function as the callback. Return 0 on ++ * success, or -errno on error. On success, the given path will be saved as ++ * watch->node, and remains the caller's to free. On error, watch->node will ++ * be NULL, the device will switch to XenbusStateClosing, and the error will ++ * be saved in the store. ++ */ + int xenbus_watch_path(struct xenbus_device *dev, const char *path, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)); +-int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, +- void (*callback)(struct xenbus_watch *, +- const char **, unsigned int), +- const char *pathfmt, ...) +- __attribute__ ((format (printf, 4, 5))); + ++ ++/** ++ * Register a watch on the given path/path2, using the given xenbus_watch ++ * structure for storage, and the given callback function as the callback. ++ * Return 0 on success, or -errno on error. On success, the watched path ++ * (path/path2) will be saved as watch->node, and becomes the caller's to ++ * kfree(). On error, watch->node will be NULL, so the caller has nothing to ++ * free, the device will switch to XenbusStateClosing, and the error will be ++ * saved in the store. ++ */ ++int xenbus_watch_path2(struct xenbus_device *dev, const char *path, ++ const char *path2, struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int)); ++ ++ ++/** ++ * Advertise in the store a change of the given driver to the given new_state. ++ * Return 0 on success, or -errno on error. On error, the device will switch ++ * to XenbusStateClosing, and the error will be saved in the store. ++ */ + int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); ++ ++ ++/** ++ * Grant access to the given ring_mfn to the peer of the given device. Return ++ * 0 on success, or -errno on error. On error, the device will switch to ++ * XenbusStateClosing, and the error will be saved in the store. ++ */ + int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn); +-int xenbus_map_ring_valloc(struct xenbus_device *dev, +- int gnt_ref, void **vaddr); ++ ++ ++/** ++ * Map a page of memory into this domain from another domain's grant table. ++ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the ++ * page to that address, and sets *vaddr to that address. ++ * xenbus_map_ring does not allocate the virtual address space (you must do ++ * this yourself!). It only maps in the page to the specified address. ++ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) ++ * or -ENOMEM on error. If an error is returned, device will switch to ++ * XenbusStateClosing and the error message will be saved in XenStore. ++ */ ++struct vm_struct *xenbus_map_ring_valloc(struct xenbus_device *dev, ++ int gnt_ref); + int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, + grant_handle_t *handle, void *vaddr); + +-int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr); ++ ++/** ++ * Unmap a page of memory in this domain that was imported from another domain. ++ * Use xenbus_unmap_ring_vfree if you mapped in your memory with ++ * xenbus_map_ring_valloc (it will free the virtual address space). ++ * Returns 0 on success and returns GNTST_* on error ++ * (see xen/include/interface/grant_table.h). ++ */ ++int xenbus_unmap_ring_vfree(struct xenbus_device *dev, struct vm_struct *); + int xenbus_unmap_ring(struct xenbus_device *dev, + grant_handle_t handle, void *vaddr); + ++ ++/** ++ * Allocate an event channel for the given xenbus_device, assigning the newly ++ * created local port to *port. Return 0 on success, or -errno on error. On ++ * error, the device will switch to XenbusStateClosing, and the error will be ++ * saved in the store. ++ */ + int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); +-int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port); ++ ++ ++/** ++ * Free an existing event channel. Returns 0 on success or -errno on error. ++ */ + int xenbus_free_evtchn(struct xenbus_device *dev, int port); + ++ ++/** ++ * Return the state of the driver rooted at the given store path, or ++ * XenbusStateUnknown if no state can be read. ++ */ + enum xenbus_state xenbus_read_driver_state(const char *path); + +-void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...); +-void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...); ++ ++/*** ++ * Report the given negative errno into the store, along with the given ++ * formatted message. ++ */ ++void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ++ ...); ++ ++ ++/*** ++ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by ++ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly ++ * closedown of this driver and its peer. ++ */ ++void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ++ ...); ++ ++int xenbus_dev_init(void); + + const char *xenbus_strstate(enum xenbus_state state); + int xenbus_dev_is_online(struct xenbus_device *dev); + int xenbus_frontend_closed(struct xenbus_device *dev); + ++int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *)); ++int xenbus_for_each_frontend(void *arg, int (*fn)(struct device *, void *)); ++ + #endif /* _XEN_XENBUS_H */ diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-intel-ibex-peak-device-ids.patch b/src/patches/suse-2.6.27.31/patches.xen/xen3-intel-ibex-peak-device-ids.patch new file mode 100644 index 000000000..3b5cdaf0b --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-intel-ibex-peak-device-ids.patch @@ -0,0 +1,50 @@ +From: Seth Heasley +Date: Thu, 28 Aug 2008 22:40:59 +0000 (-0700) +Subject: x86/PCI: irq and pci_ids patch for Intel Ibex Peak DeviceIDs +X-Git-Tag: v2.6.28-rc1~77^2~28 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=37a84ec668ba251ae02cf2c2c664baf6b247ae1f +References: bnc#415383 + +x86/PCI: irq and pci_ids patch for Intel Ibex Peak DeviceIDs + +This patch updates the Intel Ibex Peak (PCH) LPC and SMBus Controller +DeviceIDs. + +The LPC Controller ID is set by Firmware within the range of +0x3b00-3b1f. This range is included in pci_ids.h using min and max +values, and irq.c now has code to handle the range (in lieu of 32 +additions to a SWITCH statement). + +The SMBus Controller ID is a fixed-value and will not change. + +Signed-off-by: Seth Heasley +Acked-by: Jean Delvare +Signed-off-by: Jesse Barnes +Acked-by: John Jolly +Automatically created from "patches.drivers/intel-ibex-peak-device-ids.patch" by xen-port-patches.py + +--- sle11-2009-02-05.orig/arch/x86/pci/irq-xen.c 2009-02-05 10:29:06.000000000 +0100 ++++ sle11-2009-02-05/arch/x86/pci/irq-xen.c 2009-02-05 10:41:46.000000000 +0100 +@@ -597,13 +597,20 @@ static __init int intel_router_probe(str + case PCI_DEVICE_ID_INTEL_ICH10_1: + case PCI_DEVICE_ID_INTEL_ICH10_2: + case PCI_DEVICE_ID_INTEL_ICH10_3: +- case PCI_DEVICE_ID_INTEL_PCH_0: +- case PCI_DEVICE_ID_INTEL_PCH_1: + r->name = "PIIX/ICH"; + r->get = pirq_piix_get; + r->set = pirq_piix_set; + return 1; + } ++ ++ if ((device >= PCI_DEVICE_ID_INTEL_PCH_LPC_MIN) && ++ (device <= PCI_DEVICE_ID_INTEL_PCH_LPC_MAX)) { ++ r->name = "PIIX/ICH"; ++ r->get = pirq_piix_get; ++ r->set = pirq_piix_set; ++ return 1; ++ } ++ + return 0; + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-kdb-x86 b/src/patches/suse-2.6.27.31/patches.xen/xen3-kdb-x86 new file mode 100644 index 000000000..89e561194 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-kdb-x86 @@ -0,0 +1,61 @@ +From: SGI KDB Development +Subject: kdb-v4.4-2.6.27-rc8-x86-1 +References: FATE#303971 +X-URL: ftp://oss.sgi.com/www/projects/kdb/download/v4.4/ + +The KDB x86 code. + +Acked-by: Bernhard Walle + +Automatically created from "patches.suse/kdb-x86" by xen-port-patches.py + +--- sle11-2009-06-04.orig/arch/x86/kdb/kdba_bt.c 2009-06-04 10:19:52.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kdb/kdba_bt.c 2009-06-04 10:46:41.000000000 +0200 +@@ -683,7 +683,7 @@ static const char *bb_spurious[] = { + /* relocate_kernel */ + "relocate_new_kernel", + #endif /* CONFIG_KEXEC */ +-#ifdef CONFIG_XEN ++#ifdef CONFIG_PARAVIRT_XEN + /* arch/i386/xen/xen-asm.S */ + "xen_irq_enable_direct_end", + "xen_irq_disable_direct_end", +@@ -4757,7 +4757,7 @@ kdb_bb_all(int argc, const char **argv) + #ifdef CONFIG_MATH_EMULATION + " CONFIG_MATH_EMULATION" + #endif +-#ifdef CONFIG_XEN ++#ifdef CONFIG_PARAVIRT_XEN + " CONFIG_XEN" + #endif + #ifdef CONFIG_DEBUG_INFO +--- sle11-2009-06-04.orig/arch/x86/kdb/kdba_support.c 2009-06-04 10:17:48.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kdb/kdba_support.c 2009-06-04 10:46:41.000000000 +0200 +@@ -49,7 +49,7 @@ extern void halt_current_cpu(struct pt_r + + void kdba_kdump_shutdown_slave(struct pt_regs *regs) + { +-#ifndef CONFIG_XEN ++#ifndef CONFIG_PARAVIRT_XEN + halt_current_cpu(regs); + #endif /* CONFIG_XEN */ + } +--- sle11-2009-06-04.orig/arch/x86/kernel/crash.c 2009-06-04 10:17:48.000000000 +0200 ++++ sle11-2009-06-04/arch/x86/kernel/crash.c 2009-06-04 10:46:41.000000000 +0200 +@@ -224,14 +224,14 @@ void machine_crash_shutdown_begin(void) + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = safe_smp_processor_id(); +-#ifndef CONFIG_XEN ++#ifndef CONFIG_PARAVIRT_XEN + nmi_shootdown_cpus_init(); + #endif /* CONFIG_XEN */ + } + + void machine_crash_shutdown_end(struct pt_regs *regs) + { +-#ifndef CONFIG_XEN ++#ifndef CONFIG_PARAVIRT_XEN + wait_other_cpus(); + + local_irq_disable(); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.18 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.18 new file mode 100644 index 000000000..b3c3b22e6 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.18 @@ -0,0 +1,341 @@ +From: www.kernel.org +Subject: Linux 2.6.18 +Patch-mainline: 2.6.18 + +Automatically created from "patches.kernel.org/patch-2.6.18" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-05-14.orig/arch/x86/Kconfig 2009-02-05 10:20:53.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/Kconfig 2009-04-20 11:36:10.000000000 +0200 +@@ -44,7 +44,6 @@ config GENERIC_LOCKBREAK + + config GENERIC_TIME + def_bool y +- depends on !X86_XEN + + config GENERIC_CMOS_UPDATE + def_bool y +--- sle11-2009-05-14.orig/arch/x86/kernel/Makefile 2008-12-01 11:14:33.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/Makefile 2009-04-20 11:36:10.000000000 +0200 +@@ -124,5 +124,5 @@ ifeq ($(CONFIG_X86_64),y) + pci-dma_64-$(CONFIG_XEN) += pci-dma_32.o + endif + +-disabled-obj-$(CONFIG_XEN) := i8259_$(BITS).o reboot.o smpboot_$(BITS).o ++disabled-obj-$(CONFIG_XEN) := i8253.o i8259_$(BITS).o reboot.o smpboot_$(BITS).o tsc_$(BITS).o + %/head_$(BITS).o %/head_$(BITS).s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) := +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:01:13.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:01:46.000000000 +0200 +@@ -388,8 +388,10 @@ ENTRY(sysenter_entry_pv) + movl %ebp,12(%esp) + movl $__USER_CS,4(%esp) + addl $4,%esp ++ CFI_ADJUST_CFA_OFFSET -4 + /* +5*4 is SS:ESP,EFLAGS,CS:EIP. +8 is esp0 setting. */ + pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) ++ CFI_ADJUST_CFA_OFFSET 4 + /* + * Load the potential sixth argument from user stack. + * Careful about security. +--- sle11-2009-05-14.orig/arch/x86/kernel/setup64-xen.c 2009-05-14 11:01:13.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/setup64-xen.c 2009-04-20 11:36:10.000000000 +0200 +@@ -363,5 +363,7 @@ void __cpuinit cpu_init (void) + + fpu_init(); + +- raw_local_save_flags(kernel_eflags); ++ asm ("pushfq; popq %0" : "=rm" (kernel_eflags)); ++ if (raw_irqs_disabled()) ++ kernel_eflags &= ~X86_EFLAGS_IF; + } +--- sle11-2009-05-14.orig/arch/x86/kernel/time_32-xen.c 2009-03-18 12:51:05.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/time_32-xen.c 2009-04-20 11:36:10.000000000 +0200 +@@ -76,8 +76,13 @@ + + #if defined (__i386__) + #include ++#include ++DEFINE_SPINLOCK(i8253_lock); ++EXPORT_SYMBOL(i8253_lock); + #endif + ++#define XEN_SHIFT 22 ++ + int pit_latch_buggy; /* extern */ + + #if defined(__x86_64__) +@@ -97,10 +102,6 @@ extern unsigned long wall_jiffies; + DEFINE_SPINLOCK(rtc_lock); + EXPORT_SYMBOL(rtc_lock); + +-extern struct init_timer_opts timer_tsc_init; +-extern struct timer_opts timer_tsc; +-#define timer_none timer_tsc +- + /* These are peridically updated in shared_info, and then copied here. */ + struct shadow_time_info { + u64 tsc_timestamp; /* TSC at last update of time vals. */ +@@ -229,14 +230,6 @@ static inline u64 scale_delta(u64 delta, + return product; + } + +-#if 0 /* defined (__i386__) */ +-int read_current_timer(unsigned long *timer_val) +-{ +- rdtscl(*timer_val); +- return 0; +-} +-#endif +- + void init_cpu_khz(void) + { + u64 __cpu_khz = 1000000ULL << 32; +@@ -256,6 +249,7 @@ static u64 get_nsec_offset(struct shadow + return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift); + } + ++#ifdef CONFIG_X86_64 + static unsigned long get_usec_offset(struct shadow_time_info *shadow) + { + u64 now, delta; +@@ -263,6 +257,7 @@ static unsigned long get_usec_offset(str + delta = now - shadow->tsc_timestamp; + return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift); + } ++#endif + + static void __update_wallclock(time_t sec, long nsec) + { +@@ -377,6 +372,8 @@ void rtc_cmos_write(unsigned char val, u + } + EXPORT_SYMBOL(rtc_cmos_write); + ++#ifdef CONFIG_X86_64 ++ + /* + * This version of gettimeofday has microsecond resolution + * and better than microsecond precision on fast x86 machines with TSC. +@@ -512,6 +509,8 @@ int do_settimeofday(struct timespec *tv) + + EXPORT_SYMBOL(do_settimeofday); + ++#endif ++ + static void sync_xen_wallclock(unsigned long dummy); + static DEFINE_TIMER(sync_xen_wallclock_timer, sync_xen_wallclock, 0, 0); + static void sync_xen_wallclock(unsigned long dummy) +@@ -563,11 +562,15 @@ static int set_rtc_mmss(unsigned long no + return retval; + } + ++#ifdef CONFIG_X86_64 + /* monotonic_clock(): returns # of nanoseconds passed since time_init() + * Note: This function is required to return accurate + * time even in the absence of multiple timer ticks. + */ + unsigned long long monotonic_clock(void) ++#else ++unsigned long long sched_clock(void) ++#endif + { + unsigned int cpu = get_cpu(); + struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); +@@ -587,9 +590,9 @@ unsigned long long monotonic_clock(void) + + return time; + } ++#ifdef CONFIG_X86_64 + EXPORT_SYMBOL(monotonic_clock); + +-#ifdef __x86_64__ + unsigned long long sched_clock(void) + { + return monotonic_clock(); +@@ -759,6 +762,89 @@ irqreturn_t timer_interrupt(int irq, voi + return IRQ_HANDLED; + } + ++#ifndef CONFIG_X86_64 ++ ++void tsc_init(void) ++{ ++ init_cpu_khz(); ++ printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", ++ cpu_khz / 1000, cpu_khz % 1000); ++ ++ use_tsc_delay(); ++} ++ ++#include ++ ++void mark_tsc_unstable(void) ++{ ++#ifndef CONFIG_XEN /* XXX Should tell the hypervisor about this fact. */ ++ tsc_unstable = 1; ++#endif ++} ++EXPORT_SYMBOL_GPL(mark_tsc_unstable); ++ ++static cycle_t xen_clocksource_read(void) ++{ ++#ifdef CONFIG_SMP ++ static cycle_t last_ret; ++#ifndef CONFIG_64BIT ++ cycle_t last = cmpxchg64(&last_ret, 0, 0); ++#else ++ cycle_t last = last_ret; ++#define cmpxchg64 cmpxchg ++#endif ++ cycle_t ret = sched_clock(); ++ ++ if (unlikely((s64)(ret - last) < 0)) { ++ if (last - ret > permitted_clock_jitter ++ && printk_ratelimit()) { ++ unsigned int cpu = get_cpu(); ++ struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); ++ ++ printk(KERN_WARNING "clocksource/%u: " ++ "Time went backwards: " ++ "ret=%Lx delta=%Ld shadow=%Lx offset=%Lx\n", ++ cpu, ret, ret - last, shadow->system_timestamp, ++ get_nsec_offset(shadow)); ++ put_cpu(); ++ } ++ return last; ++ } ++ ++ for (;;) { ++ cycle_t cur = cmpxchg64(&last_ret, last, ret); ++ ++ if (cur == last || (s64)(ret - cur) < 0) ++ return ret; ++ last = cur; ++ } ++#else ++ return sched_clock(); ++#endif ++} ++ ++static struct clocksource clocksource_xen = { ++ .name = "xen", ++ .rating = 400, ++ .read = xen_clocksource_read, ++ .mask = CLOCKSOURCE_MASK(64), ++ .mult = 1 << XEN_SHIFT, /* time directly in nanoseconds */ ++ .shift = XEN_SHIFT, ++ .is_continuous = 1, ++}; ++ ++static int __init init_xen_clocksource(void) ++{ ++ clocksource_xen.mult = clocksource_khz2mult(cpu_khz, ++ clocksource_xen.shift); ++ ++ return clocksource_register(&clocksource_xen); ++} ++ ++module_init(init_xen_clocksource); ++ ++#endif ++ + static void init_missing_ticks_accounting(unsigned int cpu) + { + struct vcpu_register_runstate_memory_area area; +@@ -947,11 +1033,11 @@ void __init time_init(void) + + update_wallclock(); + ++#ifdef CONFIG_X86_64 + init_cpu_khz(); + printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", + cpu_khz / 1000, cpu_khz % 1000); + +-#if defined(__x86_64__) + vxtime.mode = VXTIME_TSC; + vxtime.quot = (1000000L << 32) / vxtime_hz; + vxtime.tsc_quot = (1000L << 32) / cpu_khz; +--- sle11-2009-05-14.orig/drivers/oprofile/oprofile_files.c 2009-02-16 16:01:39.000000000 +0100 ++++ sle11-2009-05-14/drivers/oprofile/oprofile_files.c 2009-04-20 11:36:10.000000000 +0200 +@@ -217,7 +217,7 @@ static ssize_t adomain_read(struct file + } + + +-static struct file_operations active_domain_ops = { ++static const struct file_operations active_domain_ops = { + .read = adomain_read, + .write = adomain_write, + }; +@@ -310,7 +310,7 @@ static ssize_t pdomain_read(struct file + return retval; + } + +-static struct file_operations passive_domain_ops = { ++static const struct file_operations passive_domain_ops = { + .read = pdomain_read, + .write = pdomain_write, + }; +--- sle11-2009-05-14.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:35:40.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blktap/blktap.c 2009-04-20 11:36:10.000000000 +0200 +@@ -931,7 +931,7 @@ static int req_increase(void) + + static void mmap_req_del(int mmap) + { +- BUG_ON(!spin_is_locked(&pending_free_lock)); ++ assert_spin_locked(&pending_free_lock); + + kfree(pending_reqs[mmap]); + pending_reqs[mmap] = NULL; +--- sle11-2009-05-14.orig/drivers/xen/core/smpboot.c 2009-05-14 11:01:13.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/core/smpboot.c 2009-04-28 16:02:07.000000000 +0200 +@@ -48,10 +48,6 @@ cpumask_t cpu_initialized_map; + struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; + EXPORT_SYMBOL(cpu_data); + +-#ifdef CONFIG_HOTPLUG_CPU +-DEFINE_PER_CPU(int, cpu_state) = { 0 }; +-#endif +- + static DEFINE_PER_CPU(int, resched_irq); + static DEFINE_PER_CPU(int, callfunc_irq); + static char resched_name[NR_CPUS][15]; +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:13:45.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-04-20 11:36:10.000000000 +0200 +@@ -394,7 +394,6 @@ static inline int pmd_large(pmd_t pte) { + + /* + * Level 4 access. +- * Never use these in the common code. + */ + #define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & PTE_MASK)) + #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/processor_32.h 2009-05-14 11:01:13.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/processor_32.h 2009-04-20 11:36:10.000000000 +0200 +@@ -23,7 +23,7 @@ + #include + + /* flag for disabling the tsc */ +-extern int tsc_disable; ++#define tsc_disable 0 + + struct desc_struct { + unsigned long a,b; +--- sle11-2009-05-14.orig/include/asm-x86/thread_info.h 2009-05-14 11:01:13.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/thread_info.h 2009-04-20 11:36:10.000000000 +0200 +@@ -142,12 +142,16 @@ struct thread_info { + (_TIF_SIGPENDING|_TIF_MCE_NOTIFY|_TIF_NOTIFY_RESUME|_TIF_PERFMON_WORK) + + /* flags to check in __switch_to() */ ++#ifndef CONFIG_XEN + #define _TIF_WORK_CTXSW \ + (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_BTS_TRACE_TS| \ + _TIF_NOTSC|_TIF_PERFMON_CTXSW) + + #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW + #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) ++#else ++#define _TIF_WORK_CTXSW _TIF_DEBUG ++#endif + + #define PREEMPT_ACTIVE 0x10000000 + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.19 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.19 new file mode 100644 index 000000000..4ba8c96f2 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.19 @@ -0,0 +1,12224 @@ +From: www.kernel.org +Subject: Linux 2.6.19 +Patch-mainline: 2.6.19 + +Automatically created from "patches.kernel.org/patch-2.6.19" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-05-14.orig/arch/x86/Kconfig 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/Kconfig 2009-03-04 11:28:34.000000000 +0100 +@@ -415,6 +415,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER + + menuconfig PARAVIRT_GUEST + bool "Paravirtualized guest support" ++ depends on !X86_XEN && !X86_64_XEN + help + Say Y here to get to see options related to running Linux under + various hypervisors. This option alone does not add any kernel code. +--- sle11-2009-05-14.orig/arch/x86/kernel/apic_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/apic_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -54,7 +54,6 @@ static cpumask_t timer_bcast_ipi; + /* + * Knob to control our willingness to enable the local APIC. + */ +-int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ + + /* + * Debug level +@@ -102,7 +101,7 @@ int get_physical_broadcast(void) + + #ifndef CONFIG_XEN + #ifndef CONFIG_SMP +-static void up_apic_timer_interrupt_call(struct pt_regs *regs) ++static void up_apic_timer_interrupt_call(void) + { + int cpu = smp_processor_id(); + +@@ -111,11 +110,11 @@ static void up_apic_timer_interrupt_call + */ + per_cpu(irq_stat, cpu).apic_timer_irqs++; + +- smp_local_timer_interrupt(regs); ++ smp_local_timer_interrupt(); + } + #endif + +-void smp_send_timer_broadcast_ipi(struct pt_regs *regs) ++void smp_send_timer_broadcast_ipi(void) + { + cpumask_t mask; + +@@ -128,7 +127,7 @@ void smp_send_timer_broadcast_ipi(struct + * We can directly call the apic timer interrupt handler + * in UP case. Minus all irq related functions + */ +- up_apic_timer_interrupt_call(regs); ++ up_apic_timer_interrupt_call(); + #endif + } + } +--- sle11-2009-05-14.orig/arch/x86/kernel/cpu/common-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/cpu/common-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -43,7 +43,7 @@ struct cpu_dev * cpu_devs[X86_VENDOR_NUM + + extern int disable_pse; + +-static void default_init(struct cpuinfo_x86 * c) ++static void __cpuinit default_init(struct cpuinfo_x86 * c) + { + /* Not much we can do here... */ + /* Check if at least it has cpuid */ +@@ -56,7 +56,7 @@ static void default_init(struct cpuinfo_ + } + } + +-static struct cpu_dev default_cpu = { ++static struct cpu_dev __cpuinitdata default_cpu = { + .c_init = default_init, + .c_vendor = "Unknown", + }; +@@ -191,7 +191,16 @@ static void __cpuinit get_cpu_vendor(str + + static int __init x86_fxsr_setup(char * s) + { ++ /* Tell all the other CPU's to not use it... */ + disable_x86_fxsr = 1; ++ ++ /* ++ * ... and clear the bits early in the boot_cpu_data ++ * so that the bootup process doesn't try to do this ++ * either. ++ */ ++ clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability); ++ clear_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability); + return 1; + } + __setup("nofxsr", x86_fxsr_setup); +@@ -272,7 +281,7 @@ static void __init early_cpu_detect(void + } + } + +-void __cpuinit generic_identify(struct cpuinfo_x86 * c) ++static void __cpuinit generic_identify(struct cpuinfo_x86 * c) + { + u32 tfms, xlvl; + int ebx; +@@ -698,8 +707,7 @@ old_gdt: + */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; +- if (current->mm) +- BUG(); ++ BUG_ON(current->mm); + enter_lazy_tlb(&init_mm, current); + + load_esp0(t, thread); +@@ -712,7 +720,7 @@ old_gdt: + #endif + + /* Clear %fs and %gs. */ +- asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); ++ asm volatile ("movl %0, %%fs; movl %0, %%gs" : : "r" (0)); + + /* Clear all 6 debug registers: */ + set_debugreg(0, 0); +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:01:46.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:07:47.000000000 +0200 +@@ -80,8 +80,12 @@ VM_MASK = 0x00020000 + NMI_MASK = 0x80000000 + + #ifndef CONFIG_XEN +-#define DISABLE_INTERRUPTS cli +-#define ENABLE_INTERRUPTS sti ++/* These are replaces for paravirtualization */ ++#define DISABLE_INTERRUPTS cli ++#define ENABLE_INTERRUPTS sti ++#define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit ++#define INTERRUPT_RETURN iret ++#define GET_CR0_INTO_EAX movl %cr0, %eax + #else + /* Offsets into shared_info_t. */ + #define evtchn_upcall_pending /* 0 */ +@@ -99,15 +103,29 @@ NMI_MASK = 0x80000000 + + #define __DISABLE_INTERRUPTS movb $1,evtchn_upcall_mask(%esi) + #define __ENABLE_INTERRUPTS movb $0,evtchn_upcall_mask(%esi) ++#define __TEST_PENDING testb $0xFF,evtchn_upcall_pending(%esi) + #define DISABLE_INTERRUPTS GET_VCPU_INFO ; \ + __DISABLE_INTERRUPTS + #define ENABLE_INTERRUPTS GET_VCPU_INFO ; \ + __ENABLE_INTERRUPTS +-#define __TEST_PENDING testb $0xFF,evtchn_upcall_pending(%esi) ++#define ENABLE_INTERRUPTS_SYSEXIT __ENABLE_INTERRUPTS ; \ ++sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/ ; \ ++ __TEST_PENDING ; \ ++ jnz 14f # process more events if necessary... ; \ ++ movl ESI(%esp), %esi ; \ ++ sysexit ; \ ++14: __DISABLE_INTERRUPTS ; \ ++ TRACE_IRQS_OFF ; \ ++sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/ ; \ ++ push %esp ; \ ++ call evtchn_do_upcall ; \ ++ add $4,%esp ; \ ++ jmp ret_from_intr ++#define INTERRUPT_RETURN iret + #endif + + #ifdef CONFIG_PREEMPT +-#define preempt_stop cli; TRACE_IRQS_OFF ++#define preempt_stop DISABLE_INTERRUPTS; TRACE_IRQS_OFF + #else + #define preempt_stop + #define resume_kernel restore_nocheck +@@ -206,18 +224,21 @@ NMI_MASK = 0x80000000 + + #define RING0_INT_FRAME \ + CFI_STARTPROC simple;\ ++ CFI_SIGNAL_FRAME;\ + CFI_DEF_CFA esp, 3*4;\ + /*CFI_OFFSET cs, -2*4;*/\ + CFI_OFFSET eip, -3*4 + + #define RING0_EC_FRAME \ + CFI_STARTPROC simple;\ ++ CFI_SIGNAL_FRAME;\ + CFI_DEF_CFA esp, 4*4;\ + /*CFI_OFFSET cs, -2*4;*/\ + CFI_OFFSET eip, -3*4 + + #define RING0_PTREGS_FRAME \ + CFI_STARTPROC simple;\ ++ CFI_SIGNAL_FRAME;\ + CFI_DEF_CFA esp, OLDESP-EBX;\ + /*CFI_OFFSET cs, CS-OLDESP;*/\ + CFI_OFFSET eip, EIP-OLDESP;\ +@@ -263,8 +284,9 @@ ret_from_intr: + check_userspace: + movl EFLAGS(%esp), %eax # mix EFLAGS and CS + movb CS(%esp), %al +- testl $(VM_MASK | 2), %eax +- jz resume_kernel ++ andl $(VM_MASK | SEGMENT_RPL_MASK), %eax ++ cmpl $USER_RPL, %eax ++ jb resume_kernel # not returning to v8086 or userspace + ENTRY(resume_userspace) + DISABLE_INTERRUPTS # make sure we don't miss an interrupt + # setting need_resched or sigpending +@@ -277,7 +299,7 @@ ENTRY(resume_userspace) + + #ifdef CONFIG_PREEMPT + ENTRY(resume_kernel) +- cli ++ DISABLE_INTERRUPTS + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jnz restore_nocheck + need_resched: +@@ -297,6 +319,7 @@ need_resched: + # sysenter call handler stub + ENTRY(sysenter_entry) + CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA esp, 0 + CFI_REGISTER esp, ebp + movl SYSENTER_stack_esp0(%esp),%esp +@@ -305,7 +328,7 @@ sysenter_past_esp: + * No need to follow this irqs on/off section: the syscall + * disabled irqs and here we enable it straight after entry: + */ +- sti ++ ENABLE_INTERRUPTS + pushl $(__USER_DS) + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET ss, 0*/ +@@ -359,26 +382,8 @@ sysenter_past_esp: + movl EIP(%esp), %edx + movl OLDESP(%esp), %ecx + xorl %ebp,%ebp +-#ifdef CONFIG_XEN + TRACE_IRQS_ON +- __ENABLE_INTERRUPTS +-sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/ +- __TEST_PENDING +- jnz 14f # process more events if necessary... +- movl ESI(%esp), %esi +- sysexit +-14: __DISABLE_INTERRUPTS +- TRACE_IRQS_OFF +-sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/ +- push %esp +- call evtchn_do_upcall +- add $4,%esp +- jmp ret_from_intr +-#else +- TRACE_IRQS_ON +- sti +- sysexit +-#endif /* !CONFIG_XEN */ ++ ENABLE_INTERRUPTS_SYSEXIT + CFI_ENDPROC + + # pv sysenter call handler stub +@@ -444,8 +449,8 @@ restore_all: + # See comments in process.c:copy_thread() for details. + movb OLDSS(%esp), %ah + movb CS(%esp), %al +- andl $(VM_MASK | (4 << 8) | 3), %eax +- cmpl $((4 << 8) | 3), %eax ++ andl $(VM_MASK | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax ++ cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax + CFI_REMEMBER_STATE + je ldt_ss # returning to user-space with LDT SS + restore_nocheck: +@@ -467,12 +472,11 @@ restore_nocheck_notrace: + RESTORE_REGS + addl $4, %esp + CFI_ADJUST_CFA_OFFSET -4 +-1: iret ++1: INTERRUPT_RETURN + .section .fixup,"ax" + iret_exc: + #ifndef CONFIG_XEN +- TRACE_IRQS_ON +- sti ++ ENABLE_INTERRUPTS + #endif + pushl $0 # no error code + pushl $do_iret_error +@@ -498,7 +502,7 @@ ldt_ss: + * dosemu and wine happy. */ + subl $8, %esp # reserve space for switch16 pointer + CFI_ADJUST_CFA_OFFSET 8 +- cli ++ DISABLE_INTERRUPTS + TRACE_IRQS_OFF + movl %esp, %eax + /* Set up the 16bit stack frame with switch32 pointer on top, +@@ -508,7 +512,7 @@ ldt_ss: + TRACE_IRQS_IRET + RESTORE_REGS + lss 20+4(%esp), %esp # switch to 16bit stack +-1: iret ++1: INTERRUPT_RETURN + .section __ex_table,"a" + .align 4 + .long 1b,iret_exc +@@ -524,7 +528,7 @@ scrit: /**** START OF CRITICAL REGION ** + RESTORE_REGS + addl $4, %esp + CFI_ADJUST_CFA_OFFSET -4 +-1: iret ++1: INTERRUPT_RETURN + .section __ex_table,"a" + .align 4 + .long 1b,iret_exc +@@ -713,11 +717,9 @@ ENTRY(name) \ + #define UNWIND_ESPFIX_STACK + #endif + +-ENTRY(divide_error) +- RING0_INT_FRAME +- pushl $0 # no error code +- CFI_ADJUST_CFA_OFFSET 4 +- pushl $do_divide_error ++KPROBE_ENTRY(page_fault) ++ RING0_EC_FRAME ++ pushl $do_page_fault + CFI_ADJUST_CFA_OFFSET 4 + ALIGN + error_code: +@@ -767,6 +769,7 @@ error_code: + call *%edi + jmp ret_from_exception + CFI_ENDPROC ++KPROBE_END(page_fault) + + #ifdef CONFIG_XEN + # A note on the "critical region" in our callback handler. +@@ -790,9 +793,11 @@ ENTRY(hypervisor_callback) + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL +- testb $2,CS(%esp) ++ movl CS(%esp),%ecx + movl EIP(%esp),%eax +- jnz .Ldo_upcall ++ andl $SEGMENT_RPL_MASK,%ecx ++ cmpl $USER_RPL,%ecx ++ jae .Ldo_upcall + cmpl $scrit,%eax + jb 0f + cmpl $ecrit,%eax +@@ -928,7 +933,7 @@ ENTRY(device_not_available) + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + #ifndef CONFIG_XEN +- movl %cr0, %eax ++ GET_CR0_INTO_EAX + testl $0x4, %eax # EM (math emulation bit) + je device_available_emulate + pushl $0 # temporary storage for ORIG_EIP +@@ -963,9 +968,15 @@ device_available_emulate: + jne ok; \ + label: \ + movl SYSENTER_stack_esp0+offset(%esp),%esp; \ ++ CFI_DEF_CFA esp, 0; \ ++ CFI_UNDEFINED eip; \ + pushfl; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ + pushl $__KERNEL_CS; \ +- pushl $sysenter_past_esp ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ pushl $sysenter_past_esp; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ ++ CFI_REL_OFFSET eip, 0 + #endif /* CONFIG_XEN */ + + KPROBE_ENTRY(debug) +@@ -984,7 +995,8 @@ debug_stack_correct: + call do_debug + jmp ret_from_exception + CFI_ENDPROC +- .previous .text ++KPROBE_END(debug) ++ + #ifndef CONFIG_XEN + /* + * NMI is doubly nasty. It can happen _while_ we're handling +@@ -994,7 +1006,7 @@ debug_stack_correct: + * check whether we got an NMI on the debug path where the debug + * fault happened on the sysenter path. + */ +-ENTRY(nmi) ++KPROBE_ENTRY(nmi) + RING0_INT_FRAME + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 +@@ -1019,6 +1031,7 @@ ENTRY(nmi) + cmpl $sysenter_entry,12(%esp) + je nmi_debug_stack_check + nmi_stack_correct: ++ /* We have a RING0_INT_FRAME here */ + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL +@@ -1029,9 +1042,12 @@ nmi_stack_correct: + CFI_ENDPROC + + nmi_stack_fixup: ++ RING0_INT_FRAME + FIX_STACK(12,nmi_stack_correct, 1) + jmp nmi_stack_correct ++ + nmi_debug_stack_check: ++ /* We have a RING0_INT_FRAME here */ + cmpw $__KERNEL_CS,16(%esp) + jne nmi_stack_correct + cmpl $debug,(%esp) +@@ -1042,8 +1058,10 @@ nmi_debug_stack_check: + jmp nmi_stack_correct + + nmi_16bit_stack: +- RING0_INT_FRAME +- /* create the pointer to lss back */ ++ /* We have a RING0_INT_FRAME here. ++ * ++ * create the pointer to lss back ++ */ + pushl %ss + CFI_ADJUST_CFA_OFFSET 4 + pushl %esp +@@ -1064,14 +1082,14 @@ nmi_16bit_stack: + call do_nmi + RESTORE_REGS + lss 12+4(%esp), %esp # back to 16bit stack +-1: iret ++1: INTERRUPT_RETURN + CFI_ENDPROC + .section __ex_table,"a" + .align 4 + .long 1b,iret_exc + .previous + #else +-ENTRY(nmi) ++KPROBE_ENTRY(nmi) + RING0_INT_FRAME + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 +@@ -1083,6 +1101,7 @@ ENTRY(nmi) + jmp restore_all + CFI_ENDPROC + #endif ++KPROBE_END(nmi) + + KPROBE_ENTRY(int3) + RING0_INT_FRAME +@@ -1094,7 +1113,7 @@ KPROBE_ENTRY(int3) + call do_int3 + jmp ret_from_exception + CFI_ENDPROC +- .previous .text ++KPROBE_END(int3) + + ENTRY(overflow) + RING0_INT_FRAME +@@ -1159,7 +1178,7 @@ KPROBE_ENTRY(general_protection) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC +- .previous .text ++KPROBE_END(general_protection) + + ENTRY(alignment_check) + RING0_EC_FRAME +@@ -1168,13 +1187,14 @@ ENTRY(alignment_check) + jmp error_code + CFI_ENDPROC + +-KPROBE_ENTRY(page_fault) +- RING0_EC_FRAME +- pushl $do_page_fault ++ENTRY(divide_error) ++ RING0_INT_FRAME ++ pushl $0 # no error code ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl $do_divide_error + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC +- .previous .text + + #ifdef CONFIG_X86_MCE + ENTRY(machine_check) +@@ -1236,6 +1256,19 @@ ENTRY(fixup_4gb_segment) + jmp error_code + CFI_ENDPROC + ++ENTRY(kernel_thread_helper) ++ pushl $0 # fake return address for unwinder ++ CFI_STARTPROC ++ movl %edx,%eax ++ push %edx ++ CFI_ADJUST_CFA_OFFSET 4 ++ call *%ebx ++ push %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ call do_exit ++ CFI_ENDPROC ++ENDPROC(kernel_thread_helper) ++ + .section .rodata,"a" + #include "syscall_table.S" + +--- sle11-2009-05-14.orig/arch/x86/kernel/head_32-xen.S 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/head_32-xen.S 2009-03-04 11:28:34.000000000 +0100 +@@ -62,7 +62,7 @@ ENTRY(startup_32) + movl %eax,%gs + cld # gcc2 wants the direction flag cleared at all times + +- pushl %eax # fake return address ++ pushl $0 # fake return address for unwinder + jmp start_kernel + + #define HYPERCALL_PAGE_OFFSET 0x1000 +--- sle11-2009-05-14.orig/arch/x86/kernel/io_apic_32-xen.c 2009-03-16 16:13:45.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/io_apic_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -31,6 +31,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include + #include +@@ -38,13 +41,15 @@ + #include + #include + #include ++#include ++#include + + #include ++#include + + #include "io_ports.h" + + #ifdef CONFIG_XEN +- + #include + #include + #include +@@ -56,32 +61,7 @@ + + unsigned long io_apic_irqs; + +-static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg) +-{ +- struct physdev_apic apic_op; +- int ret; +- +- apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; +- apic_op.reg = reg; +- ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op); +- if (ret) +- return ret; +- return apic_op.value; +-} +- +-static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) +-{ +- struct physdev_apic apic_op; +- +- apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; +- apic_op.reg = reg; +- apic_op.value = value; +- WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op)); +-} +- +-#define io_apic_read(a,r) xen_io_apic_read(a,r) +-#define io_apic_write(a,r,v) xen_io_apic_write(a,r,v) +- ++#define clear_IO_APIC() ((void)0) + #endif /* CONFIG_XEN */ + + int (*ioapic_renumber_irq)(int ioapic, int irq); +@@ -108,7 +88,7 @@ int sis_apic_bug = -1; + */ + int nr_ioapic_registers[MAX_IO_APICS]; + +-int disable_timer_pin_1 __initdata; ++static int disable_timer_pin_1 __initdata; + + /* + * Rough estimation of how many shared IRQs there are, can +@@ -128,12 +108,124 @@ static struct irq_pin_list { + int apic, pin, next; + } irq_2_pin[PIN_MAP_SIZE]; + +-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; +-#ifdef CONFIG_PCI_MSI +-#define vector_to_irq(vector) \ +- (platform_legacy_irq(vector) ? vector : vector_irq[vector]) ++#ifndef CONFIG_XEN ++struct io_apic { ++ unsigned int index; ++ unsigned int unused[3]; ++ unsigned int data; ++}; ++ ++static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) ++{ ++ return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) ++ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); ++} ++#endif ++ ++static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) ++{ ++#ifndef CONFIG_XEN ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ return readl(&io_apic->data); ++#else ++ struct physdev_apic apic_op; ++ int ret; ++ ++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; ++ apic_op.reg = reg; ++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op); ++ if (ret) ++ return ret; ++ return apic_op.value; ++#endif ++} ++ ++static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++#ifndef CONFIG_XEN ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ writel(value, &io_apic->data); ++#else ++ struct physdev_apic apic_op; ++ ++ apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; ++ apic_op.reg = reg; ++ apic_op.value = value; ++ WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op)); ++#endif ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * Re-write a value: to be used for read-modify-write ++ * cycles where the read already set up the index register. ++ * ++ * Older SiS APIC requires we rewrite the index register ++ */ ++static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) ++{ ++ volatile struct io_apic *io_apic = io_apic_base(apic); ++ if (sis_apic_bug) ++ writel(reg, &io_apic->index); ++ writel(value, &io_apic->data); ++} + #else +-#define vector_to_irq(vector) (vector) ++#define io_apic_modify io_apic_write ++#endif ++ ++union entry_union { ++ struct { u32 w1, w2; }; ++ struct IO_APIC_route_entry entry; ++}; ++ ++#ifndef CONFIG_XEN ++static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) ++{ ++ union entry_union eu; ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin); ++ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ return eu.entry; ++} ++#endif ++ ++/* ++ * When we write a new IO APIC routing entry, we need to write the high ++ * word first! If the mask bit in the low word is clear, we will enable ++ * the interrupt, and we need to make sure the entry is fully populated ++ * before that happens. ++ */ ++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ unsigned long flags; ++ union entry_union eu; ++ eu.entry = e; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * When we mask an IO APIC routing entry, we need to write the low ++ * word first, in order to set the mask bit before we change the ++ * high bits! ++ */ ++static void ioapic_mask_entry(int apic, int pin) ++{ ++ unsigned long flags; ++ union entry_union eu = { .entry.mask = 1 }; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} + #endif + + /* +@@ -159,9 +251,7 @@ static void add_pin_to_irq(unsigned int + entry->pin = pin; + } + +-#ifdef CONFIG_XEN +-#define clear_IO_APIC() ((void)0) +-#else ++#ifndef CONFIG_XEN + /* + * Reroute an IRQ to a different pin. + */ +@@ -246,25 +336,16 @@ static void unmask_IO_APIC_irq (unsigned + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) + { + struct IO_APIC_route_entry entry; +- unsigned long flags; + + /* Check delivery_mode to be sure we're not clearing an SMI pin */ +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); +- *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ entry = ioapic_read_entry(apic, pin); + if (entry.delivery_mode == dest_SMI) + return; + + /* + * Disable it in the IO-APIC irq-routing table: + */ +- memset(&entry, 0, sizeof(entry)); +- entry.mask = 1; +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); +- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_mask_entry(apic, pin); + } + + static void clear_IO_APIC (void) +@@ -304,7 +385,7 @@ static void set_ioapic_affinity_irq(unsi + break; + entry = irq_2_pin + entry->next; + } +- set_irq_info(irq, cpumask); ++ set_native_irq_info(irq, cpumask); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + +@@ -1212,43 +1293,43 @@ static inline int IO_APIC_irq_trigger(in + /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ + u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; /* = { FIRST_DEVICE_VECTOR , 0 }; */ + +-int assign_irq_vector(int irq) ++static int __assign_irq_vector(int irq) + { +- unsigned long flags; + int vector; + struct physdev_irq irq_op; + +- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); ++ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); + + if (irq < PIRQ_BASE || irq - PIRQ_BASE >= NR_PIRQS) + return -EINVAL; + +- spin_lock_irqsave(&vector_lock, flags); +- +- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { +- spin_unlock_irqrestore(&vector_lock, flags); +- return IO_APIC_VECTOR(irq); +- } ++ if (irq_vector[irq] > 0) ++ return irq_vector[irq]; + + irq_op.irq = irq; +- if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) { +- spin_unlock_irqrestore(&vector_lock, flags); ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) + return -ENOSPC; +- } + + vector = irq_op.vector; +- vector_irq[vector] = irq; +- if (irq != AUTO_ASSIGN) +- IO_APIC_VECTOR(irq) = vector; ++ irq_vector[irq] = vector; ++ ++ return vector; ++} ++ ++static int assign_irq_vector(int irq) ++{ ++ unsigned long flags; ++ int vector; + ++ spin_lock_irqsave(&vector_lock, flags); ++ vector = __assign_irq_vector(irq); + spin_unlock_irqrestore(&vector_lock, flags); + + return vector; + } + + #ifndef CONFIG_XEN +-static struct hw_interrupt_type ioapic_level_type; +-static struct hw_interrupt_type ioapic_edge_type; ++static struct irq_chip ioapic_chip; + + #define IOAPIC_AUTO -1 + #define IOAPIC_EDGE 0 +@@ -1256,16 +1337,16 @@ static struct hw_interrupt_type ioapic_e + + static void ioapic_register_intr(int irq, int vector, unsigned long trigger) + { +- unsigned idx; +- +- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; +- + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) +- irq_desc[idx].chip = &ioapic_level_type; +- else +- irq_desc[idx].chip = &ioapic_edge_type; +- set_intr_gate(vector, interrupt[idx]); ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_fasteoi_irq, "fasteoi"); ++ else { ++ irq_desc[irq].status |= IRQ_DELAYED_DISABLE; ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_edge_irq, "edge"); ++ } ++ set_intr_gate(vector, interrupt[irq]); + } + #else + #define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq) +@@ -1336,9 +1417,8 @@ static void __init setup_IO_APIC_irqs(vo + if (!apic && (irq < 16)) + disable_8259A_irq(irq); + } ++ ioapic_write_entry(apic, pin, entry); + spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); +- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + } +@@ -1355,7 +1435,6 @@ static void __init setup_IO_APIC_irqs(vo + static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) + { + struct IO_APIC_route_entry entry; +- unsigned long flags; + + memset(&entry,0,sizeof(entry)); + +@@ -1380,15 +1459,13 @@ static void __init setup_ExtINT_IRQ0_pin + * The timer IRQ doesn't have to know that behind the + * scene we have a 8259A-master in AEOI mode ... + */ +- irq_desc[0].chip = &ioapic_edge_type; ++ irq_desc[0].chip = &ioapic_chip; ++ set_irq_handler(0, handle_edge_irq); + + /* + * Add it to the IO-APIC irq-routing table: + */ +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); +- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_write_entry(apic, pin, entry); + + enable_8259A_irq(0); + } +@@ -1498,10 +1575,7 @@ void __init print_IO_APIC(void) + for (i = 0; i <= reg_01.bits.entries; i++) { + struct IO_APIC_route_entry entry; + +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); +- *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ entry = ioapic_read_entry(apic, i); + + printk(KERN_DEBUG " %02x %03X %02X ", + i, +@@ -1521,17 +1595,12 @@ void __init print_IO_APIC(void) + ); + } + } +- if (use_pci_vector()) +- printk(KERN_INFO "Using vector-based indexing\n"); + printk(KERN_DEBUG "IRQ to pin mappings:\n"); + for (i = 0; i < NR_IRQS; i++) { + struct irq_pin_list *entry = irq_2_pin + i; + if (entry->pin < 0) + continue; +- if (use_pci_vector() && !platform_legacy_irq(i)) +- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); +- else +- printk(KERN_DEBUG "IRQ%d ", i); ++ printk(KERN_DEBUG "IRQ%d ", i); + for (;;) { + printk("-> %d:%d", entry->apic, entry->pin); + if (!entry->next) +@@ -1720,10 +1789,7 @@ static void __init enable_IO_APIC(void) + /* See if any of the pins is in ExtINT mode */ + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { + struct IO_APIC_route_entry entry; +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); +- *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ entry = ioapic_read_entry(apic, pin); + + + /* If the interrupt line is enabled and in ExtInt mode +@@ -1782,7 +1848,6 @@ void disable_IO_APIC(void) + */ + if (ioapic_i8259.pin != -1) { + struct IO_APIC_route_entry entry; +- unsigned long flags; + + memset(&entry, 0, sizeof(entry)); + entry.mask = 0; /* Enabled */ +@@ -1799,12 +1864,7 @@ void disable_IO_APIC(void) + /* + * Add it to the IO-APIC irq-routing table: + */ +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin, +- *(((int *)&entry)+1)); +- io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin, +- *(((int *)&entry)+0)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); + } + disconnect_bsp_APIC(ioapic_i8259.pin != -1); + #endif +@@ -1971,6 +2031,8 @@ static int __init timer_irq_works(void) + */ + + /* ++ * Startup quirk: ++ * + * Starting up a edge-triggered IO-APIC interrupt is + * nasty - we need to make sure that we get the edge. + * If it is already asserted for some reason, we need +@@ -1978,8 +2040,10 @@ static int __init timer_irq_works(void) + * + * This is not complete - we should be able to fake + * an edge even if it isn't on the 8259A... ++ * ++ * (We do this for level-triggered IRQs too - it cannot hurt.) + */ +-static unsigned int startup_edge_ioapic_irq(unsigned int irq) ++static unsigned int startup_ioapic_irq(unsigned int irq) + { + int was_pending = 0; + unsigned long flags; +@@ -1996,47 +2060,18 @@ static unsigned int startup_edge_ioapic_ + return was_pending; + } + +-/* +- * Once we have recorded IRQ_PENDING already, we can mask the +- * interrupt for real. This prevents IRQ storms from unhandled +- * devices. +- */ +-static void ack_edge_ioapic_irq(unsigned int irq) +-{ +- move_irq(irq); +- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) +- == (IRQ_PENDING | IRQ_DISABLED)) +- mask_IO_APIC_irq(irq); +- ack_APIC_irq(); +-} +- +-/* +- * Level triggered interrupts can just be masked, +- * and shutting down and starting up the interrupt +- * is the same as enabling and disabling them -- except +- * with a startup need to return a "was pending" value. +- * +- * Level triggered interrupts are special because we +- * do not touch any IO-APIC register while handling +- * them. We ack the APIC in the end-IRQ handler, not +- * in the start-IRQ-handler. Protection against reentrance +- * from the same interrupt is still provided, both by the +- * generic IRQ layer and by the fact that an unacked local +- * APIC does not accept IRQs. +- */ +-static unsigned int startup_level_ioapic_irq (unsigned int irq) ++static void ack_ioapic_irq(unsigned int irq) + { +- unmask_IO_APIC_irq(irq); +- +- return 0; /* don't check for pending */ ++ move_native_irq(irq); ++ ack_APIC_irq(); + } + +-static void end_level_ioapic_irq (unsigned int irq) ++static void ack_ioapic_quirk_irq(unsigned int irq) + { + unsigned long v; + int i; + +- move_irq(irq); ++ move_native_irq(irq); + /* + * It appears there is an erratum which affects at least version 0x11 + * of I/O APIC (that's the 82093AA and cores integrated into various +@@ -2056,7 +2091,7 @@ static void end_level_ioapic_irq (unsign + * operation to prevent an edge-triggered interrupt escaping meanwhile. + * The idea is from Manfred Spraul. --macro + */ +- i = IO_APIC_VECTOR(irq); ++ i = irq_vector[irq]; + + v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); + +@@ -2071,104 +2106,24 @@ static void end_level_ioapic_irq (unsign + } + } + +-#ifdef CONFIG_PCI_MSI +-static unsigned int startup_edge_ioapic_vector(unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- return startup_edge_ioapic_irq(irq); +-} +- +-static void ack_edge_ioapic_vector(unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- move_native_irq(vector); +- ack_edge_ioapic_irq(irq); +-} +- +-static unsigned int startup_level_ioapic_vector (unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- return startup_level_ioapic_irq (irq); +-} +- +-static void end_level_ioapic_vector (unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- move_native_irq(vector); +- end_level_ioapic_irq(irq); +-} +- +-static void mask_IO_APIC_vector (unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- mask_IO_APIC_irq(irq); +-} +- +-static void unmask_IO_APIC_vector (unsigned int vector) ++static int ioapic_retrigger_irq(unsigned int irq) + { +- int irq = vector_to_irq(vector); +- +- unmask_IO_APIC_irq(irq); +-} +- +-#ifdef CONFIG_SMP +-static void set_ioapic_affinity_vector (unsigned int vector, +- cpumask_t cpu_mask) +-{ +- int irq = vector_to_irq(vector); +- +- set_native_irq_info(vector, cpu_mask); +- set_ioapic_affinity_irq(irq, cpu_mask); +-} +-#endif +-#endif +- +-static int ioapic_retrigger(unsigned int irq) +-{ +- send_IPI_self(IO_APIC_VECTOR(irq)); ++ send_IPI_self(irq_vector[irq]); + + return 1; + } + +-/* +- * Level and edge triggered IO-APIC interrupts need different handling, +- * so we use two separate IRQ descriptors. Edge triggered IRQs can be +- * handled with the level-triggered descriptor, but that one has slightly +- * more overhead. Level-triggered interrupts cannot be handled with the +- * edge-triggered handler, without risking IRQ storms and other ugly +- * races. +- */ +-static struct hw_interrupt_type ioapic_edge_type __read_mostly = { +- .typename = "IO-APIC-edge", +- .startup = startup_edge_ioapic, +- .shutdown = shutdown_edge_ioapic, +- .enable = enable_edge_ioapic, +- .disable = disable_edge_ioapic, +- .ack = ack_edge_ioapic, +- .end = end_edge_ioapic, +-#ifdef CONFIG_SMP +- .set_affinity = set_ioapic_affinity, +-#endif +- .retrigger = ioapic_retrigger, +-}; +- +-static struct hw_interrupt_type ioapic_level_type __read_mostly = { +- .typename = "IO-APIC-level", +- .startup = startup_level_ioapic, +- .shutdown = shutdown_level_ioapic, +- .enable = enable_level_ioapic, +- .disable = disable_level_ioapic, +- .ack = mask_and_ack_level_ioapic, +- .end = end_level_ioapic, ++static struct irq_chip ioapic_chip __read_mostly = { ++ .name = "IO-APIC", ++ .startup = startup_ioapic_irq, ++ .mask = mask_IO_APIC_irq, ++ .unmask = unmask_IO_APIC_irq, ++ .ack = ack_ioapic_irq, ++ .eoi = ack_ioapic_quirk_irq, + #ifdef CONFIG_SMP +- .set_affinity = set_ioapic_affinity, ++ .set_affinity = set_ioapic_affinity_irq, + #endif +- .retrigger = ioapic_retrigger, ++ .retrigger = ioapic_retrigger_irq, + }; + #endif /* !CONFIG_XEN */ + +@@ -2189,12 +2144,7 @@ static inline void init_IO_APIC_traps(vo + */ + for (irq = 0; irq < NR_IRQS ; irq++) { + int tmp = irq; +- if (use_pci_vector()) { +- if (!platform_legacy_irq(tmp)) +- if ((tmp = vector_to_irq(tmp)) == -1) +- continue; +- } +- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { ++ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { + /* + * Hmm.. We don't have an entry for this, + * so default to an old-fashioned 8259 +@@ -2205,22 +2155,23 @@ static inline void init_IO_APIC_traps(vo + #ifndef CONFIG_XEN + else + /* Strange. Oh, well.. */ +- irq_desc[irq].chip = &no_irq_type; ++ irq_desc[irq].chip = &no_irq_chip; + #endif + } + } + } + + #ifndef CONFIG_XEN +-static void enable_lapic_irq (unsigned int irq) +-{ +- unsigned long v; ++/* ++ * The local APIC irq-chip implementation: ++ */ + +- v = apic_read(APIC_LVT0); +- apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED); ++static void ack_apic(unsigned int irq) ++{ ++ ack_APIC_irq(); + } + +-static void disable_lapic_irq (unsigned int irq) ++static void mask_lapic_irq (unsigned int irq) + { + unsigned long v; + +@@ -2228,21 +2179,19 @@ static void disable_lapic_irq (unsigned + apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); + } + +-static void ack_lapic_irq (unsigned int irq) ++static void unmask_lapic_irq (unsigned int irq) + { +- ack_APIC_irq(); +-} ++ unsigned long v; + +-static void end_lapic_irq (unsigned int i) { /* nothing */ } ++ v = apic_read(APIC_LVT0); ++ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED); ++} + +-static struct hw_interrupt_type lapic_irq_type __read_mostly = { +- .typename = "local-APIC-edge", +- .startup = NULL, /* startup_irq() not used for IRQ0 */ +- .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ +- .enable = enable_lapic_irq, +- .disable = disable_lapic_irq, +- .ack = ack_lapic_irq, +- .end = end_lapic_irq ++static struct irq_chip lapic_chip __read_mostly = { ++ .name = "local-APIC-edge", ++ .mask = mask_lapic_irq, ++ .unmask = unmask_lapic_irq, ++ .eoi = ack_apic, + }; + + static void setup_nmi (void) +@@ -2275,17 +2224,13 @@ static inline void unlock_ExtINT_logic(v + int apic, pin, i; + struct IO_APIC_route_entry entry0, entry1; + unsigned char save_control, save_freq_select; +- unsigned long flags; + + pin = find_isa_irq_pin(8, mp_INT); + apic = find_isa_irq_apic(8, mp_INT); + if (pin == -1) + return; + +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin); +- *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ entry0 = ioapic_read_entry(apic, pin); + clear_IO_APIC_pin(apic, pin); + + memset(&entry1, 0, sizeof(entry1)); +@@ -2298,10 +2243,7 @@ static inline void unlock_ExtINT_logic(v + entry1.trigger = 0; + entry1.vector = 0; + +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1)); +- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_write_entry(apic, pin, entry1); + + save_control = CMOS_READ(RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); +@@ -2320,10 +2262,7 @@ static inline void unlock_ExtINT_logic(v + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + clear_IO_APIC_pin(apic, pin); + +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1)); +- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_write_entry(apic, pin, entry0); + } + + int timer_uses_ioapic_pin_0; +@@ -2423,7 +2362,8 @@ static inline void check_timer(void) + printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); + + disable_8259A_irq(0); +- irq_desc[0].chip = &lapic_irq_type; ++ set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq, ++ "fasteio"); + apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ + enable_8259A_irq(0); + +@@ -2537,17 +2477,12 @@ static int ioapic_suspend(struct sys_dev + { + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; +- unsigned long flags; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; +- spin_lock_irqsave(&ioapic_lock, flags); +- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { +- *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); +- *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); +- } +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) ++ entry[i] = ioapic_read_entry(dev->id, i); + + return 0; + } +@@ -2569,11 +2504,9 @@ static int ioapic_resume(struct sys_devi + reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; + io_apic_write(dev->id, 0, reg_00.raw); + } +- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { +- io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); +- io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); +- } + spin_unlock_irqrestore(&ioapic_lock, flags); ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++) ++ ioapic_write_entry(dev->id, i, entry[i]); + + return 0; + } +@@ -2619,8 +2552,240 @@ static int __init ioapic_init_sysfs(void + + device_initcall(ioapic_init_sysfs); + ++/* ++ * Dynamic irq allocate and deallocation ++ */ ++int create_irq(void) ++{ ++ /* Allocate an unused irq */ ++ int irq, new, vector; ++ unsigned long flags; ++ ++ irq = -ENOSPC; ++ spin_lock_irqsave(&vector_lock, flags); ++ for (new = (NR_IRQS - 1); new >= 0; new--) { ++ if (platform_legacy_irq(new)) ++ continue; ++ if (irq_vector[new] != 0) ++ continue; ++ vector = __assign_irq_vector(new); ++ if (likely(vector > 0)) ++ irq = new; ++ break; ++ } ++ spin_unlock_irqrestore(&vector_lock, flags); ++ ++ if (irq >= 0) { ++ set_intr_gate(vector, interrupt[irq]); ++ dynamic_irq_init(irq); ++ } ++ return irq; ++} ++ ++void destroy_irq(unsigned int irq) ++{ ++ unsigned long flags; ++ ++ dynamic_irq_cleanup(irq); ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ irq_vector[irq] = 0; ++ spin_unlock_irqrestore(&vector_lock, flags); ++} ++ + #endif /* CONFIG_XEN */ + ++/* ++ * MSI mesage composition ++ */ ++#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) ++static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) ++{ ++ int vector; ++ unsigned dest; ++ ++ vector = assign_irq_vector(irq); ++ if (vector >= 0) { ++ dest = cpu_mask_to_apicid(TARGET_CPUS); ++ ++ msg->address_hi = MSI_ADDR_BASE_HI; ++ msg->address_lo = ++ MSI_ADDR_BASE_LO | ++ ((INT_DEST_MODE == 0) ? ++ MSI_ADDR_DEST_MODE_PHYSICAL: ++ MSI_ADDR_DEST_MODE_LOGICAL) | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_ADDR_REDIRECTION_CPU: ++ MSI_ADDR_REDIRECTION_LOWPRI) | ++ MSI_ADDR_DEST_ID(dest); ++ ++ msg->data = ++ MSI_DATA_TRIGGER_EDGE | ++ MSI_DATA_LEVEL_ASSERT | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_DATA_DELIVERY_FIXED: ++ MSI_DATA_DELIVERY_LOWPRI) | ++ MSI_DATA_VECTOR(vector); ++ } ++ return vector; ++} ++ ++#ifdef CONFIG_SMP ++static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ struct msi_msg msg; ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ vector = assign_irq_vector(irq); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(mask); ++ ++ read_msi_msg(irq, &msg); ++ ++ msg.data &= ~MSI_DATA_VECTOR_MASK; ++ msg.data |= MSI_DATA_VECTOR(vector); ++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; ++ msg.address_lo |= MSI_ADDR_DEST_ID(dest); ++ ++ write_msi_msg(irq, &msg); ++ set_native_irq_info(irq, mask); ++} ++#endif /* CONFIG_SMP */ ++ ++/* ++ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, ++ * which implement the MSI or MSI-X Capability Structure. ++ */ ++static struct irq_chip msi_chip = { ++ .name = "PCI-MSI", ++ .unmask = unmask_msi_irq, ++ .mask = mask_msi_irq, ++ .ack = ack_ioapic_irq, ++#ifdef CONFIG_SMP ++ .set_affinity = set_msi_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ struct msi_msg msg; ++ int ret; ++ ret = msi_compose_msg(dev, irq, &msg); ++ if (ret < 0) ++ return ret; ++ ++ write_msi_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, ++ "edge"); ++ ++ return 0; ++} ++ ++void arch_teardown_msi_irq(unsigned int irq) ++{ ++ return; ++} ++ ++#endif /* CONFIG_PCI_MSI */ ++ ++/* ++ * Hypertransport interrupt support ++ */ ++#ifdef CONFIG_HT_IRQ ++ ++#ifdef CONFIG_SMP ++ ++static void target_ht_irq(unsigned int irq, unsigned int dest) ++{ ++ struct ht_irq_msg msg; ++ fetch_ht_irq_msg(irq, &msg); ++ ++ msg.address_lo &= ~(HT_IRQ_LOW_DEST_ID_MASK); ++ msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); ++ ++ msg.address_lo |= HT_IRQ_LOW_DEST_ID(dest); ++ msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); ++ ++ write_ht_irq_msg(irq, &msg); ++} ++ ++static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ unsigned int dest; ++ cpumask_t tmp; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ dest = cpu_mask_to_apicid(mask); ++ ++ target_ht_irq(irq, dest); ++ set_native_irq_info(irq, mask); ++} ++#endif ++ ++static struct irq_chip ht_irq_chip = { ++ .name = "PCI-HT", ++ .mask = mask_ht_irq, ++ .unmask = unmask_ht_irq, ++ .ack = ack_ioapic_irq, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ht_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ int vector; ++ ++ vector = assign_irq_vector(irq); ++ if (vector >= 0) { ++ struct ht_irq_msg msg; ++ unsigned dest; ++ cpumask_t tmp; ++ ++ cpus_clear(tmp); ++ cpu_set(vector >> 8, tmp); ++ dest = cpu_mask_to_apicid(tmp); ++ ++ msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); ++ ++ msg.address_lo = ++ HT_IRQ_LOW_BASE | ++ HT_IRQ_LOW_DEST_ID(dest) | ++ HT_IRQ_LOW_VECTOR(vector) | ++ ((INT_DEST_MODE == 0) ? ++ HT_IRQ_LOW_DM_PHYSICAL : ++ HT_IRQ_LOW_DM_LOGICAL) | ++ HT_IRQ_LOW_RQEOI_EDGE | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ HT_IRQ_LOW_MT_FIXED : ++ HT_IRQ_LOW_MT_ARBITRATED) | ++ HT_IRQ_LOW_IRQ_MASKED; ++ ++ write_ht_irq_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &ht_irq_chip, ++ handle_edge_irq, "edge"); ++ } ++ return vector; ++} ++#endif /* CONFIG_HT_IRQ */ ++ + /* -------------------------------------------------------------------------- + ACPI-based IOAPIC Configuration + -------------------------------------------------------------------------- */ +@@ -2774,13 +2939,34 @@ int io_apic_set_pci_routing (int ioapic, + if (!ioapic && (irq < 16)) + disable_8259A_irq(irq); + ++ ioapic_write_entry(ioapic, pin, entry); + spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); +- io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); +- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); ++ set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; + } + + #endif /* CONFIG_ACPI */ ++ ++static int __init parse_disable_timer_pin_1(char *arg) ++{ ++ disable_timer_pin_1 = 1; ++ return 0; ++} ++early_param("disable_timer_pin_1", parse_disable_timer_pin_1); ++ ++static int __init parse_enable_timer_pin_1(char *arg) ++{ ++ disable_timer_pin_1 = -1; ++ return 0; ++} ++early_param("enable_timer_pin_1", parse_enable_timer_pin_1); ++ ++static int __init parse_noapic(char *arg) ++{ ++ /* disable IO-APIC */ ++ disable_ioapic_setup(); ++ return 0; ++} ++early_param("noapic", parse_noapic); +--- sle11-2009-05-14.orig/arch/x86/kernel/irq_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/irq_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -53,8 +53,10 @@ static union irq_ctx *softirq_ctx[NR_CPU + */ + fastcall unsigned int do_IRQ(struct pt_regs *regs) + { ++ struct pt_regs *old_regs; + /* high bit used in ret_from_ code */ + int irq = ~regs->orig_eax; ++ struct irq_desc *desc = irq_desc + irq; + #ifdef CONFIG_4KSTACKS + union irq_ctx *curctx, *irqctx; + u32 *isp; +@@ -66,6 +68,7 @@ fastcall unsigned int do_IRQ(struct pt_r + BUG(); + } + ++ old_regs = set_irq_regs(regs); + /*irq_enter();*/ + #ifdef CONFIG_DEBUG_STACKOVERFLOW + /* Debugging check for stack overflow: is there less than 1KB free? */ +@@ -110,19 +113,20 @@ fastcall unsigned int do_IRQ(struct pt_r + (curctx->tinfo.preempt_count & SOFTIRQ_MASK); + + asm volatile( +- " xchgl %%ebx,%%esp \n" +- " call __do_IRQ \n" ++ " xchgl %%ebx,%%esp \n" ++ " call *%%edi \n" + " movl %%ebx,%%esp \n" + : "=a" (arg1), "=d" (arg2), "=b" (ebx) +- : "0" (irq), "1" (regs), "2" (isp) +- : "memory", "cc", "ecx" ++ : "0" (irq), "1" (desc), "2" (isp), ++ "D" (desc->handle_irq) ++ : "memory", "cc" + ); + } else + #endif +- __do_IRQ(irq, regs); ++ desc->handle_irq(irq, desc); + + /*irq_exit();*/ +- ++ set_irq_regs(old_regs); + return 1; + } + +@@ -253,7 +257,8 @@ int show_interrupts(struct seq_file *p, + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); + #endif +- seq_printf(p, " %14s", irq_desc[i].chip->typename); ++ seq_printf(p, " %8s", irq_desc[i].chip->name); ++ seq_printf(p, "-%-8s", irq_desc[i].name); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) +--- sle11-2009-05-14.orig/arch/x86/kernel/ldt_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/ldt_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * linux/kernel/ldt.c ++ * linux/arch/i386/kernel/ldt.c + * + * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds + * Copyright (C) 1999 Ingo Molnar +--- sle11-2009-05-14.orig/arch/x86/kernel/microcode-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/microcode-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -2,6 +2,7 @@ + * Intel CPU Microcode Update Driver for Linux + * + * Copyright (C) 2000-2004 Tigran Aivazian ++ * 2006 Shaohua Li + * + * This driver allows to upgrade microcode on Intel processors + * belonging to IA-32 family - PentiumPro, Pentium II, +@@ -33,7 +34,9 @@ + #include + #include + #include +-#include ++#include ++#include ++#include + + #include + #include +@@ -55,12 +58,7 @@ module_param(verbose, int, 0644); + /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ + static DEFINE_MUTEX(microcode_mutex); + +-static int microcode_open (struct inode *unused1, struct file *unused2) +-{ +- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; +-} +- +- ++#ifdef CONFIG_MICROCODE_OLD_INTERFACE + static int do_microcode_update (const void __user *ubuf, size_t len) + { + int err; +@@ -85,6 +83,11 @@ static int do_microcode_update (const vo + return err; + } + ++static int microcode_open (struct inode *unused1, struct file *unused2) ++{ ++ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; ++} ++ + static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos) + { + ssize_t ret; +@@ -117,7 +120,7 @@ static struct miscdevice microcode_dev = + .fops = µcode_fops, + }; + +-static int __init microcode_init (void) ++static int __init microcode_dev_init (void) + { + int error; + +@@ -129,6 +132,68 @@ static int __init microcode_init (void) + return error; + } + ++ return 0; ++} ++ ++static void __exit microcode_dev_exit (void) ++{ ++ misc_deregister(µcode_dev); ++} ++ ++MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); ++#else ++#define microcode_dev_init() 0 ++#define microcode_dev_exit() do { } while(0) ++#endif ++ ++/* fake device for request_firmware */ ++static struct platform_device *microcode_pdev; ++ ++static int request_microcode(void) ++{ ++ char name[30]; ++ const struct cpuinfo_x86 *c = &boot_cpu_data; ++ const struct firmware *firmware; ++ int error; ++ struct xen_platform_op op; ++ ++ sprintf(name,"intel-ucode/%02x-%02x-%02x", ++ c->x86, c->x86_model, c->x86_mask); ++ error = request_firmware(&firmware, name, µcode_pdev->dev); ++ if (error) { ++ pr_debug("ucode data file %s load failed\n", name); ++ return error; ++ } ++ ++ op.cmd = XENPF_microcode_update; ++ set_xen_guest_handle(op.u.microcode.data, (void *)firmware->data); ++ op.u.microcode.length = firmware->size; ++ error = HYPERVISOR_platform_op(&op); ++ ++ release_firmware(firmware); ++ ++ if (error) ++ pr_debug("ucode load failed\n"); ++ ++ return error; ++} ++ ++static int __init microcode_init (void) ++{ ++ int error; ++ ++ error = microcode_dev_init(); ++ if (error) ++ return error; ++ microcode_pdev = platform_device_register_simple("microcode", -1, ++ NULL, 0); ++ if (IS_ERR(microcode_pdev)) { ++ microcode_dev_exit(); ++ return PTR_ERR(microcode_pdev); ++ } ++ ++ request_microcode(); ++ + printk(KERN_INFO + "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " \n"); + return 0; +@@ -136,9 +201,9 @@ static int __init microcode_init (void) + + static void __exit microcode_exit (void) + { +- misc_deregister(µcode_dev); ++ microcode_dev_exit(); ++ platform_device_unregister(microcode_pdev); + } + + module_init(microcode_init) + module_exit(microcode_exit) +-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR); +--- sle11-2009-05-14.orig/arch/x86/kernel/mpparse_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/mpparse_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -30,6 +30,7 @@ + #include + + #include ++#include + #include + #include + +@@ -68,7 +69,7 @@ unsigned int def_to_bigsmp = 0; + /* Processor that is doing the boot up */ + unsigned int boot_cpu_physical_apicid = -1U; + /* Internal processor count */ +-static unsigned int __devinitdata num_processors; ++unsigned int __cpuinitdata num_processors; + + /* Bitmask of physically existing CPUs */ + physid_mask_t phys_cpu_present_map; +@@ -235,12 +236,14 @@ static void __init MP_bus_info (struct m + + mpc_oem_bus_info(m, str, translation_table[mpc_record]); + ++#if MAX_MP_BUSSES < 256 + if (m->mpc_busid >= MAX_MP_BUSSES) { + printk(KERN_WARNING "MP table busid value (%d) for bustype %s " + " is too large, max. supported is %d\n", + m->mpc_busid, str, MAX_MP_BUSSES - 1); + return; + } ++#endif + + if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; +@@ -300,19 +303,6 @@ static void __init MP_lintsrc_info (stru + m->mpc_irqtype, m->mpc_irqflag & 3, + (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid, + m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint); +- /* +- * Well it seems all SMP boards in existence +- * use ExtINT/LVT1 == LINT0 and +- * NMI/LVT2 == LINT1 - the following check +- * will show us if this assumptions is false. +- * Until then we do not have to add baggage. +- */ +- if ((m->mpc_irqtype == mp_ExtINT) && +- (m->mpc_destapiclint != 0)) +- BUG(); +- if ((m->mpc_irqtype == mp_NMI) && +- (m->mpc_destapiclint != 1)) +- BUG(); + } + + #ifdef CONFIG_X86_NUMAQ +@@ -838,8 +828,7 @@ int es7000_plat; + + #ifdef CONFIG_ACPI + +-void __init mp_register_lapic_address ( +- u64 address) ++void __init mp_register_lapic_address(u64 address) + { + #ifndef CONFIG_XEN + mp_lapic_addr = (unsigned long) address; +@@ -853,13 +842,10 @@ void __init mp_register_lapic_address ( + #endif + } + +- +-void __devinit mp_register_lapic ( +- u8 id, +- u8 enabled) ++void __devinit mp_register_lapic (u8 id, u8 enabled) + { + struct mpc_config_processor processor; +- int boot_cpu = 0; ++ int boot_cpu = 0; + + if (MAX_APICS - id <= 0) { + printk(KERN_WARNING "Processor #%d invalid (max %d)\n", +@@ -898,11 +884,9 @@ static struct mp_ioapic_routing { + u32 pin_programmed[4]; + } mp_ioapic_routing[MAX_IO_APICS]; + +- +-static int mp_find_ioapic ( +- int gsi) ++static int mp_find_ioapic (int gsi) + { +- int i = 0; ++ int i = 0; + + /* Find the IOAPIC that manages this GSI. */ + for (i = 0; i < nr_ioapics; i++) { +@@ -915,15 +899,11 @@ static int mp_find_ioapic ( + + return -1; + } +- + +-void __init mp_register_ioapic ( +- u8 id, +- u32 address, +- u32 gsi_base) ++void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base) + { +- int idx = 0; +- int tmpid; ++ int idx = 0; ++ int tmpid; + + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " +@@ -971,16 +951,10 @@ void __init mp_register_ioapic ( + mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, + mp_ioapic_routing[idx].gsi_base, + mp_ioapic_routing[idx].gsi_end); +- +- return; + } + +- +-void __init mp_override_legacy_irq ( +- u8 bus_irq, +- u8 polarity, +- u8 trigger, +- u32 gsi) ++void __init ++mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) + { + struct mpc_config_intsrc intsrc; + int ioapic = -1; +@@ -1018,15 +992,13 @@ void __init mp_override_legacy_irq ( + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); +- +- return; + } + + void __init mp_config_acpi_legacy_irqs (void) + { + struct mpc_config_intsrc intsrc; +- int i = 0; +- int ioapic = -1; ++ int i = 0; ++ int ioapic = -1; + + /* + * Fabricate the legacy ISA bus (bus #31). +@@ -1095,12 +1067,12 @@ void __init mp_config_acpi_legacy_irqs ( + + #define MAX_GSI_NUM 4096 + +-int mp_register_gsi (u32 gsi, int triggering, int polarity) ++int mp_register_gsi(u32 gsi, int triggering, int polarity) + { +- int ioapic = -1; +- int ioapic_pin = 0; +- int idx, bit = 0; +- static int pci_irq = 16; ++ int ioapic = -1; ++ int ioapic_pin = 0; ++ int idx, bit = 0; ++ static int pci_irq = 16; + /* + * Mapping between Global System Interrups, which + * represent all possible interrupts, and IRQs +--- sle11-2009-05-14.orig/arch/x86/kernel/pci-dma-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/pci-dma-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -110,8 +110,7 @@ dma_map_sg(struct device *hwdev, struct + { + int i, rc; + +- if (direction == DMA_NONE) +- BUG(); ++ BUG_ON(!valid_dma_direction(direction)); + WARN_ON(nents == 0 || sg[0].length == 0); + + if (swiotlb) { +@@ -142,7 +141,7 @@ dma_unmap_sg(struct device *hwdev, struc + { + int i; + +- BUG_ON(direction == DMA_NONE); ++ BUG_ON(!valid_dma_direction(direction)); + if (swiotlb) + swiotlb_unmap_sg(hwdev, sg, nents, direction); + else { +@@ -159,8 +158,7 @@ dma_map_page(struct device *dev, struct + { + dma_addr_t dma_addr; + +- BUG_ON(direction == DMA_NONE); +- ++ BUG_ON(!valid_dma_direction(direction)); + if (swiotlb) { + dma_addr = swiotlb_map_page( + dev, page, offset, size, direction); +@@ -177,7 +175,7 @@ void + dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) + { +- BUG_ON(direction == DMA_NONE); ++ BUG_ON(!valid_dma_direction(direction)); + if (swiotlb) + swiotlb_unmap_page(dev, dma_address, size, direction); + else +@@ -359,8 +357,7 @@ dma_map_single(struct device *dev, void + { + dma_addr_t dma; + +- if (direction == DMA_NONE) +- BUG(); ++ BUG_ON(!valid_dma_direction(direction)); + WARN_ON(size == 0); + + if (swiotlb) { +@@ -381,8 +378,7 @@ void + dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) + { +- if (direction == DMA_NONE) +- BUG(); ++ BUG_ON(!valid_dma_direction(direction)); + if (swiotlb) + swiotlb_unmap_single(dev, dma_addr, size, direction); + else +--- sle11-2009-05-14.orig/arch/x86/kernel/process_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/process_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -186,7 +187,7 @@ void cpu_idle(void) + void cpu_idle_wait(void) + { + unsigned int cpu, this_cpu = get_cpu(); +- cpumask_t map; ++ cpumask_t map, tmp = current->cpus_allowed; + + set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); + put_cpu(); +@@ -208,6 +209,8 @@ void cpu_idle_wait(void) + } + cpus_and(map, map, cpu_online_map); + } while (!cpus_empty(map)); ++ ++ set_cpus_allowed(current, tmp); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + +@@ -240,9 +243,9 @@ void show_regs(struct pt_regs * regs) + if (user_mode_vm(regs)) + printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); + printk(" EFLAGS: %08lx %s (%s %.*s)\n", +- regs->eflags, print_tainted(), system_utsname.release, +- (int)strcspn(system_utsname.version, " "), +- system_utsname.version); ++ regs->eflags, print_tainted(), init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax,regs->ebx,regs->ecx,regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx", +@@ -264,15 +267,6 @@ void show_regs(struct pt_regs * regs) + * the "args". + */ + extern void kernel_thread_helper(void); +-__asm__(".section .text\n" +- ".align 4\n" +- "kernel_thread_helper:\n\t" +- "movl %edx,%eax\n\t" +- "pushl %edx\n\t" +- "call *%ebx\n\t" +- "pushl %eax\n\t" +- "call do_exit\n" +- ".previous"); + + /* + * Create a kernel thread +@@ -290,7 +284,7 @@ int kernel_thread(int (*fn)(void *), voi + regs.xes = __USER_DS; + regs.orig_eax = -1; + regs.eip = (unsigned long) kernel_thread_helper; +- regs.xcs = GET_KERNEL_CS(); ++ regs.xcs = __KERNEL_CS | get_kernel_rpl(); + regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; + + /* Ok, create the new process.. */ +@@ -369,13 +363,12 @@ int copy_thread(int nr, unsigned long cl + + tsk = current; + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { +- p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); ++ p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, ++ IO_BITMAP_BYTES, GFP_KERNEL); + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; + return -ENOMEM; + } +- memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr, +- IO_BITMAP_BYTES); + set_tsk_thread_flag(p, TIF_IO_BITMAP); + } + +@@ -871,7 +864,7 @@ asmlinkage int sys_get_thread_area(struc + + unsigned long arch_align_stack(unsigned long sp) + { +- if (randomize_va_space) ++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; + } +--- sle11-2009-05-14.orig/arch/x86/kernel/setup_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/setup_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -83,9 +84,6 @@ static struct notifier_block xen_panic_b + xen_panic_event, NULL, 0 /* try to go last */ + }; + +-extern char hypercall_page[PAGE_SIZE]; +-EXPORT_SYMBOL(hypercall_page); +- + int disable_pse __devinitdata = 0; + + /* +@@ -105,18 +103,6 @@ EXPORT_SYMBOL(boot_cpu_data); + + unsigned long mmu_cr4_features; + +-#ifdef CONFIG_ACPI +- int acpi_disabled = 0; +-#else +- int acpi_disabled = 1; +-#endif +-EXPORT_SYMBOL(acpi_disabled); +- +-#ifdef CONFIG_ACPI +-int __initdata acpi_force = 0; +-extern acpi_interrupt_flags acpi_sci_flags; +-#endif +- + /* for MCA, but anyone else can use it if they want */ + unsigned int machine_id; + #ifdef CONFIG_MCA +@@ -170,7 +156,6 @@ struct e820map machine_e820; + #endif + + extern void early_cpu_init(void); +-extern void generic_apic_probe(char *); + extern int root_mountflags; + + unsigned long saved_videomode; +@@ -243,9 +228,6 @@ static struct resource adapter_rom_resou + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM + } }; + +-#define ADAPTER_ROM_RESOURCES \ +- (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0]) +- + static struct resource video_rom_resource = { + .name = "Video ROM", + .start = 0xc0000, +@@ -307,9 +289,6 @@ static struct resource standard_io_resou + .flags = IORESOURCE_BUSY | IORESOURCE_IO + } }; + +-#define STANDARD_IO_RESOURCES \ +- (sizeof standard_io_resources / sizeof standard_io_resources[0]) +- + #define romsignature(x) (*(unsigned short *)(x) == 0xaa55) + + static int __init romchecksum(unsigned char *rom, unsigned long length) +@@ -372,7 +351,7 @@ static void __init probe_roms(void) + } + + /* check for adapter roms on 2k boundaries */ +- for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) { ++ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { + rom = isa_bus_to_virt(start); + if (!romsignature(rom)) + continue; +@@ -779,246 +758,152 @@ static inline void copy_edd(void) + } + #endif + +-static void __init parse_cmdline_early (char ** cmdline_p) ++static int __initdata user_defined_memmap = 0; ++ ++/* ++ * "mem=nopentium" disables the 4MB page tables. ++ * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM ++ * to , overriding the bios size. ++ * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from ++ * to +, overriding the bios size. ++ * ++ * HPA tells me bootloaders need to parse mem=, so no new ++ * option should be mem= [also see Documentation/i386/boot.txt] ++ */ ++static int __init parse_mem(char *arg) + { +- char c = ' ', *to = command_line, *from = saved_command_line; +- int len = 0, max_cmdline; +- int userdef = 0; +- +- if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) +- max_cmdline = COMMAND_LINE_SIZE; +- memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline); +- /* Save unparsed command line copy for /proc/cmdline */ +- saved_command_line[max_cmdline-1] = '\0'; +- +- for (;;) { +- if (c != ' ') +- goto next_char; +- /* +- * "mem=nopentium" disables the 4MB page tables. +- * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM +- * to , overriding the bios size. +- * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from +- * to +, overriding the bios size. +- * +- * HPA tells me bootloaders need to parse mem=, so no new +- * option should be mem= [also see Documentation/i386/boot.txt] +- */ +- if (!memcmp(from, "mem=", 4)) { +- if (to != command_line) +- to--; +- if (!memcmp(from+4, "nopentium", 9)) { +- from += 9+4; +- clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); +- disable_pse = 1; +- } else { +- /* If the user specifies memory size, we +- * limit the BIOS-provided memory map to +- * that size. exactmap can be used to specify +- * the exact map. mem=number can be used to +- * trim the existing memory map. +- */ +- unsigned long long mem_size; +- +- mem_size = memparse(from+4, &from); +- limit_regions(mem_size); +- userdef=1; +- } +- } ++ if (!arg) ++ return -EINVAL; + +- else if (!memcmp(from, "memmap=", 7)) { +- if (to != command_line) +- to--; +- if (!memcmp(from+7, "exactmap", 8)) { +-#ifdef CONFIG_CRASH_DUMP +- /* If we are doing a crash dump, we +- * still need to know the real mem +- * size before original memory map is +- * reset. +- */ +- find_max_pfn(); +- saved_max_pfn = max_pfn; +-#endif +- from += 8+7; +- e820.nr_map = 0; +- userdef = 1; +- } else { +- /* If the user specifies memory size, we +- * limit the BIOS-provided memory map to +- * that size. exactmap can be used to specify +- * the exact map. mem=number can be used to +- * trim the existing memory map. +- */ +- unsigned long long start_at, mem_size; ++ if (strcmp(arg, "nopentium") == 0) { ++ clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); ++ disable_pse = 1; ++ } else { ++ /* If the user specifies memory size, we ++ * limit the BIOS-provided memory map to ++ * that size. exactmap can be used to specify ++ * the exact map. mem=number can be used to ++ * trim the existing memory map. ++ */ ++ unsigned long long mem_size; + +- mem_size = memparse(from+7, &from); +- if (*from == '@') { +- start_at = memparse(from+1, &from); +- add_memory_region(start_at, mem_size, E820_RAM); +- } else if (*from == '#') { +- start_at = memparse(from+1, &from); +- add_memory_region(start_at, mem_size, E820_ACPI); +- } else if (*from == '$') { +- start_at = memparse(from+1, &from); +- add_memory_region(start_at, mem_size, E820_RESERVED); +- } else { +- limit_regions(mem_size); +- userdef=1; +- } +- } +- } +- +- else if (!memcmp(from, "noexec=", 7)) +- noexec_setup(from + 7); ++ mem_size = memparse(arg, &arg); ++ limit_regions(mem_size); ++ user_defined_memmap = 1; ++ } ++ return 0; ++} ++early_param("mem", parse_mem); + ++static int __init parse_memmap(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; + +-#ifdef CONFIG_X86_MPPARSE +- /* +- * If the BIOS enumerates physical processors before logical, +- * maxcpus=N at enumeration-time can be used to disable HT. ++ if (strcmp(arg, "exactmap") == 0) { ++#ifdef CONFIG_CRASH_DUMP ++ /* If we are doing a crash dump, we ++ * still need to know the real mem ++ * size before original memory map is ++ * reset. + */ +- else if (!memcmp(from, "maxcpus=", 8)) { +- extern unsigned int maxcpus; +- +- maxcpus = simple_strtoul(from + 8, NULL, 0); +- } ++ find_max_pfn(); ++ saved_max_pfn = max_pfn; + #endif ++ e820.nr_map = 0; ++ user_defined_memmap = 1; ++ } else { ++ /* If the user specifies memory size, we ++ * limit the BIOS-provided memory map to ++ * that size. exactmap can be used to specify ++ * the exact map. mem=number can be used to ++ * trim the existing memory map. ++ */ ++ unsigned long long start_at, mem_size; + +-#ifdef CONFIG_ACPI +- /* "acpi=off" disables both ACPI table parsing and interpreter */ +- else if (!memcmp(from, "acpi=off", 8)) { +- disable_acpi(); +- } +- +- /* acpi=force to over-ride black-list */ +- else if (!memcmp(from, "acpi=force", 10)) { +- acpi_force = 1; +- acpi_ht = 1; +- acpi_disabled = 0; +- } +- +- /* acpi=strict disables out-of-spec workarounds */ +- else if (!memcmp(from, "acpi=strict", 11)) { +- acpi_strict = 1; +- } +- +- /* Limit ACPI just to boot-time to enable HT */ +- else if (!memcmp(from, "acpi=ht", 7)) { +- if (!acpi_force) +- disable_acpi(); +- acpi_ht = 1; +- } +- +- /* "pci=noacpi" disable ACPI IRQ routing and PCI scan */ +- else if (!memcmp(from, "pci=noacpi", 10)) { +- acpi_disable_pci(); +- } +- /* "acpi=noirq" disables ACPI interrupt routing */ +- else if (!memcmp(from, "acpi=noirq", 10)) { +- acpi_noirq_set(); ++ mem_size = memparse(arg, &arg); ++ if (*arg == '@') { ++ start_at = memparse(arg+1, &arg); ++ add_memory_region(start_at, mem_size, E820_RAM); ++ } else if (*arg == '#') { ++ start_at = memparse(arg+1, &arg); ++ add_memory_region(start_at, mem_size, E820_ACPI); ++ } else if (*arg == '$') { ++ start_at = memparse(arg+1, &arg); ++ add_memory_region(start_at, mem_size, E820_RESERVED); ++ } else { ++ limit_regions(mem_size); ++ user_defined_memmap = 1; + } ++ } ++ return 0; ++} ++early_param("memmap", parse_memmap); + +- else if (!memcmp(from, "acpi_sci=edge", 13)) +- acpi_sci_flags.trigger = 1; +- +- else if (!memcmp(from, "acpi_sci=level", 14)) +- acpi_sci_flags.trigger = 3; ++#ifdef CONFIG_PROC_VMCORE ++/* elfcorehdr= specifies the location of elf core header ++ * stored by the crashed kernel. ++ */ ++static int __init parse_elfcorehdr(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; + +- else if (!memcmp(from, "acpi_sci=high", 13)) +- acpi_sci_flags.polarity = 1; ++ elfcorehdr_addr = memparse(arg, &arg); ++ return 0; ++} ++early_param("elfcorehdr", parse_elfcorehdr); ++#endif /* CONFIG_PROC_VMCORE */ + +- else if (!memcmp(from, "acpi_sci=low", 12)) +- acpi_sci_flags.polarity = 3; ++/* ++ * highmem=size forces highmem to be exactly 'size' bytes. ++ * This works even on boxes that have no highmem otherwise. ++ * This also works to reduce highmem size on bigger boxes. ++ */ ++static int __init parse_highmem(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; + +-#ifdef CONFIG_X86_IO_APIC +- else if (!memcmp(from, "acpi_skip_timer_override", 24)) +- acpi_skip_timer_override = 1; ++ highmem_pages = memparse(arg, &arg) >> PAGE_SHIFT; ++ return 0; ++} ++early_param("highmem", parse_highmem); + +- if (!memcmp(from, "disable_timer_pin_1", 19)) +- disable_timer_pin_1 = 1; +- if (!memcmp(from, "enable_timer_pin_1", 18)) +- disable_timer_pin_1 = -1; +- +- /* disable IO-APIC */ +- else if (!memcmp(from, "noapic", 6)) +- disable_ioapic_setup(); +-#endif /* CONFIG_X86_IO_APIC */ +-#endif /* CONFIG_ACPI */ ++/* ++ * vmalloc=size forces the vmalloc area to be exactly 'size' ++ * bytes. This can be used to increase (or decrease) the ++ * vmalloc area - the default is 128m. ++ */ ++static int __init parse_vmalloc(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; + +-#ifdef CONFIG_X86_LOCAL_APIC +- /* enable local APIC */ +- else if (!memcmp(from, "lapic", 5)) +- lapic_enable(); +- +- /* disable local APIC */ +- else if (!memcmp(from, "nolapic", 6)) +- lapic_disable(); +-#endif /* CONFIG_X86_LOCAL_APIC */ ++ __VMALLOC_RESERVE = memparse(arg, &arg); ++ return 0; ++} ++early_param("vmalloc", parse_vmalloc); + +-#ifdef CONFIG_KEXEC +- /* crashkernel=size@addr specifies the location to reserve for +- * a crash kernel. By reserving this memory we guarantee +- * that linux never set's it up as a DMA target. +- * Useful for holding code to do something appropriate +- * after a kernel panic. +- */ +- else if (!memcmp(from, "crashkernel=", 12)) { + #ifndef CONFIG_XEN +- unsigned long size, base; +- size = memparse(from+12, &from); +- if (*from == '@') { +- base = memparse(from+1, &from); +- /* FIXME: Do I want a sanity check +- * to validate the memory range? +- */ +- crashk_res.start = base; +- crashk_res.end = base + size - 1; +- } +-#else +- printk("Ignoring crashkernel command line, " +- "parameter will be supplied by xen\n"); +-#endif +- } +-#endif +-#ifdef CONFIG_PROC_VMCORE +- /* elfcorehdr= specifies the location of elf core header +- * stored by the crashed kernel. +- */ +- else if (!memcmp(from, "elfcorehdr=", 11)) +- elfcorehdr_addr = memparse(from+11, &from); +-#endif ++/* ++ * reservetop=size reserves a hole at the top of the kernel address space which ++ * a hypervisor can load into later. Needed for dynamically loaded hypervisors, ++ * so relocating the fixmap can be done before paging initialization. ++ */ ++static int __init parse_reservetop(char *arg) ++{ ++ unsigned long address; + +- /* +- * highmem=size forces highmem to be exactly 'size' bytes. +- * This works even on boxes that have no highmem otherwise. +- * This also works to reduce highmem size on bigger boxes. +- */ +- else if (!memcmp(from, "highmem=", 8)) +- highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; +- +- /* +- * vmalloc=size forces the vmalloc area to be exactly 'size' +- * bytes. This can be used to increase (or decrease) the +- * vmalloc area - the default is 128m. +- */ +- else if (!memcmp(from, "vmalloc=", 8)) +- __VMALLOC_RESERVE = memparse(from+8, &from); ++ if (!arg) ++ return -EINVAL; + +- next_char: +- c = *(from++); +- if (!c) +- break; +- if (COMMAND_LINE_SIZE <= ++len) +- break; +- *(to++) = c; +- } +- *to = '\0'; +- *cmdline_p = command_line; +- if (userdef) { +- printk(KERN_INFO "user-defined physical RAM map:\n"); +- print_memory_map("user"); +- } ++ address = memparse(arg, &arg); ++ reserve_top_address(address); ++ return 0; + } ++early_param("reservetop", parse_reservetop); ++#endif + + /* + * Callback for efi_memory_walk. +@@ -1039,7 +924,7 @@ efi_find_max_pfn(unsigned long start, un + static int __init + efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg) + { +- memory_present(0, start, end); ++ memory_present(0, PFN_UP(start), PFN_DOWN(end)); + return 0; + } + +@@ -1306,6 +1191,14 @@ static unsigned long __init setup_memory + } + printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", + pages_to_mb(highend_pfn - highstart_pfn)); ++ num_physpages = highend_pfn; ++ high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; ++#else ++ num_physpages = max_low_pfn; ++ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; ++#endif ++#ifdef CONFIG_FLATMEM ++ max_mapnr = num_physpages; + #endif + printk(KERN_NOTICE "%ldMB LOWMEM available.\n", + pages_to_mb(max_low_pfn)); +@@ -1317,22 +1210,19 @@ static unsigned long __init setup_memory + + void __init zone_sizes_init(void) + { +- unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; +- unsigned int max_dma, low; +- +- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; +- low = max_low_pfn; +- +- if (low < max_dma) +- zones_size[ZONE_DMA] = low; +- else { +- zones_size[ZONE_DMA] = max_dma; +- zones_size[ZONE_NORMAL] = low - max_dma; ++ unsigned long max_zone_pfns[MAX_NR_ZONES]; ++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); ++ max_zone_pfns[ZONE_DMA] = ++ virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; ++ max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + #ifdef CONFIG_HIGHMEM +- zones_size[ZONE_HIGHMEM] = highend_pfn - low; ++ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; ++ add_active_range(0, 0, highend_pfn); ++#else ++ add_active_range(0, 0, max_low_pfn); + #endif +- } +- free_area_init(zones_size); ++ ++ free_area_init_nodes(max_zone_pfns); + } + #else + extern unsigned long __init setup_memory(void); +@@ -1389,6 +1279,7 @@ void __init setup_bootmem_allocator(void + */ + acpi_reserve_bootmem(); + #endif ++ numa_kva_reserve(); + #endif /* !CONFIG_XEN */ + + #ifdef CONFIG_BLK_DEV_INITRD +@@ -1574,7 +1465,7 @@ static int __init request_standard_resou + request_resource(&iomem_resource, &video_ram_resource); + + /* request I/O space for devices used on all i[345]86 PCs */ +- for (i = 0; i < STANDARD_IO_RESOURCES; i++) ++ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) + request_resource(&ioport_resource, &standard_io_resources[i]); + return 0; + } +@@ -1705,17 +1596,19 @@ void __init setup_arch(char **cmdline_p) + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; + +- parse_cmdline_early(cmdline_p); ++ if ((i = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) ++ i = COMMAND_LINE_SIZE; ++ memcpy(saved_command_line, xen_start_info->cmd_line, i); ++ saved_command_line[i - 1] = '\0'; ++ parse_early_param(); + +-#ifdef CONFIG_EARLY_PRINTK +- { +- char *s = strstr(*cmdline_p, "earlyprintk="); +- if (s) { +- setup_early_printk(strchr(s, '=') + 1); +- printk("early console enabled\n"); +- } ++ if (user_defined_memmap) { ++ printk(KERN_INFO "user-defined physical RAM map:\n"); ++ print_memory_map("user"); + } +-#endif ++ ++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); ++ *cmdline_p = command_line; + + max_low_pfn = setup_memory(); + +@@ -1822,7 +1715,7 @@ void __init setup_arch(char **cmdline_p) + dmi_scan_machine(); + + #ifdef CONFIG_X86_GENERICARCH +- generic_apic_probe(*cmdline_p); ++ generic_apic_probe(); + #endif + if (efi_enabled) + efi_map_memmap(); +@@ -1843,9 +1736,11 @@ void __init setup_arch(char **cmdline_p) + acpi_boot_table_init(); + #endif + ++#ifdef CONFIG_PCI + #ifdef CONFIG_X86_IO_APIC + check_acpi_pci(); /* Checks more than just ACPI actually */ + #endif ++#endif + + #ifdef CONFIG_ACPI + acpi_boot_init(); +--- sle11-2009-05-14.orig/arch/x86/kernel/smp_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/smp_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -279,8 +279,7 @@ static inline void leave_mm (unsigned lo + * 2) Leave the mm if we are in the lazy tlb mode. + */ + +-irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id, +- struct pt_regs *regs) ++irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id) + { + unsigned long cpu; + +@@ -567,16 +566,14 @@ void smp_send_stop(void) + * all the work is done automatically when + * we return from the interrupt. + */ +-irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id, +- struct pt_regs *regs) ++irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id) + { + + return IRQ_HANDLED; + } + + #include +-irqreturn_t smp_call_function_interrupt(int irq, void *dev_id, +- struct pt_regs *regs) ++irqreturn_t smp_call_function_interrupt(int irq, void *dev_id) + { + void (*func) (void *info) = call_data->func; + void *info = call_data->info; +@@ -603,3 +600,69 @@ irqreturn_t smp_call_function_interrupt( + return IRQ_HANDLED; + } + ++/* ++ * this function sends a 'generic call function' IPI to one other CPU ++ * in the system. ++ * ++ * cpu is a standard Linux logical CPU number. ++ */ ++static void ++__smp_call_function_single(int cpu, void (*func) (void *info), void *info, ++ int nonatomic, int wait) ++{ ++ struct call_data_struct data; ++ int cpus = 1; ++ ++ data.func = func; ++ data.info = info; ++ atomic_set(&data.started, 0); ++ data.wait = wait; ++ if (wait) ++ atomic_set(&data.finished, 0); ++ ++ call_data = &data; ++ wmb(); ++ /* Send a message to all other CPUs and wait for them to respond */ ++ send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR); ++ ++ /* Wait for response */ ++ while (atomic_read(&data.started) != cpus) ++ cpu_relax(); ++ ++ if (!wait) ++ return; ++ ++ while (atomic_read(&data.finished) != cpus) ++ cpu_relax(); ++} ++ ++/* ++ * smp_call_function_single - Run a function on another CPU ++ * @func: The function to run. This must be fast and non-blocking. ++ * @info: An arbitrary pointer to pass to the function. ++ * @nonatomic: Currently unused. ++ * @wait: If true, wait until function has completed on other CPUs. ++ * ++ * Retrurns 0 on success, else a negative status code. ++ * ++ * Does not return until the remote CPU is nearly ready to execute ++ * or is or has executed. ++ */ ++ ++int smp_call_function_single(int cpu, void (*func) (void *info), void *info, ++ int nonatomic, int wait) ++{ ++ /* prevent preemption and reschedule on another processor */ ++ int me = get_cpu(); ++ if (cpu == me) { ++ WARN_ON(1); ++ put_cpu(); ++ return -EBUSY; ++ } ++ spin_lock_bh(&call_lock); ++ __smp_call_function_single(cpu, func, info, nonatomic, wait); ++ spin_unlock_bh(&call_lock); ++ put_cpu(); ++ return 0; ++} ++EXPORT_SYMBOL(smp_call_function_single); +--- sle11-2009-05-14.orig/arch/x86/kernel/time_32-xen.c 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/time_32-xen.c 2009-03-24 10:08:00.000000000 +0100 +@@ -89,7 +89,6 @@ int pit_latch_buggy; /* ext + unsigned long vxtime_hz = PIT_TICK_RATE; + struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */ + volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; +-unsigned long __wall_jiffies __section_wall_jiffies = INITIAL_JIFFIES; + struct timespec __xtime __section_xtime; + struct timezone __sys_tz __section_sys_tz; + #endif +@@ -97,8 +96,6 @@ struct timezone __sys_tz __section_sys_t + unsigned int cpu_khz; /* Detected as we calibrate the TSC */ + EXPORT_SYMBOL(cpu_khz); + +-extern unsigned long wall_jiffies; +- + DEFINE_SPINLOCK(rtc_lock); + EXPORT_SYMBOL(rtc_lock); + +@@ -265,11 +262,10 @@ static void __update_wallclock(time_t se + time_t wtm_sec, xtime_sec; + u64 tmp, wc_nsec; + +- /* Adjust wall-clock time base based on wall_jiffies ticks. */ ++ /* Adjust wall-clock time base. */ + wc_nsec = processed_system_time; + wc_nsec += sec * (u64)NSEC_PER_SEC; + wc_nsec += nsec; +- wc_nsec -= (jiffies - wall_jiffies) * (u64)NS_PER_TICK; + + /* Split wallclock base into seconds and nanoseconds. */ + tmp = wc_nsec; +@@ -392,16 +388,10 @@ void do_gettimeofday(struct timeval *tv) + shadow = &per_cpu(shadow_time, cpu); + + do { +- unsigned long lost; +- + local_time_version = shadow->version; + seq = read_seqbegin(&xtime_lock); + + usec = get_usec_offset(shadow); +- lost = jiffies - wall_jiffies; +- +- if (unlikely(lost)) +- usec += lost * (USEC_PER_SEC / HZ); + + sec = xtime.tv_sec; + usec += (xtime.tv_nsec / NSEC_PER_USEC); +@@ -525,7 +515,7 @@ static void sync_xen_wallclock(unsigned + write_seqlock_irq(&xtime_lock); + + sec = xtime.tv_sec; +- nsec = xtime.tv_nsec + ((jiffies - wall_jiffies) * (u64)NS_PER_TICK); ++ nsec = xtime.tv_nsec; + __normalize_time(&sec, &nsec); + + op.cmd = XENPF_settime; +@@ -599,42 +589,49 @@ unsigned long long sched_clock(void) + } + #endif + +-#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) + unsigned long profile_pc(struct pt_regs *regs) + { + unsigned long pc = instruction_pointer(regs); + +-#ifdef __x86_64__ +- /* Assume the lock function has either no stack frame or only a single word. +- This checks if the address on the stack looks like a kernel text address. +- There is a small window for false hits, but in that case the tick +- is just accounted to the spinlock function. +- Better would be to write these functions in assembler again +- and check exactly. */ ++#if defined(CONFIG_SMP) || defined(__x86_64__) + if (!user_mode_vm(regs) && in_lock_functions(pc)) { +- char *v = *(char **)regs->rsp; +- if ((v >= _stext && v <= _etext) || +- (v >= _sinittext && v <= _einittext) || +- (v >= (char *)MODULES_VADDR && v <= (char *)MODULES_END)) +- return (unsigned long)v; +- return ((unsigned long *)regs->rsp)[1]; ++# ifdef CONFIG_FRAME_POINTER ++# ifdef __i386__ ++ return ((unsigned long *)regs->ebp)[1]; ++# else ++ return ((unsigned long *)regs->rbp)[1]; ++# endif ++# else ++# ifdef __i386__ ++ unsigned long *sp; ++ if ((regs->xcs & 2) == 0) ++ sp = (unsigned long *)®s->esp; ++ else ++ sp = (unsigned long *)regs->esp; ++# else ++ unsigned long *sp = (unsigned long *)regs->rsp; ++# endif ++ /* Return address is either directly at stack pointer ++ or above a saved eflags. Eflags has bits 22-31 zero, ++ kernel addresses don't. */ ++ if (sp[0] >> 22) ++ return sp[0]; ++ if (sp[1] >> 22) ++ return sp[1]; ++# endif + } +-#else +- if (!user_mode_vm(regs) && in_lock_functions(pc)) +- return *(unsigned long *)(regs->ebp + 4); + #endif + + return pc; + } + EXPORT_SYMBOL(profile_pc); +-#endif + + /* + * This is the same as the above, except we _also_ save the current + * Time Stamp Counter value at the time of the timer interrupt, so that + * we later on can estimate the time of day more exactly. + */ +-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t timer_interrupt(int irq, void *dev_id) + { + s64 delta, delta_cpu, stolen, blocked; + u64 sched_time; +@@ -692,10 +689,14 @@ irqreturn_t timer_interrupt(int irq, voi + } + + /* System-wide jiffy work. */ +- while (delta >= NS_PER_TICK) { +- delta -= NS_PER_TICK; +- processed_system_time += NS_PER_TICK; +- do_timer(regs); ++ if (delta >= NS_PER_TICK) { ++ do_div(delta, NS_PER_TICK); ++ processed_system_time += delta * NS_PER_TICK; ++ while (delta > HZ) { ++ do_timer(HZ); ++ delta -= HZ; ++ } ++ do_timer(delta); + } + + if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) { +@@ -740,7 +741,7 @@ irqreturn_t timer_interrupt(int irq, voi + if (delta_cpu > 0) { + do_div(delta_cpu, NS_PER_TICK); + per_cpu(processed_system_time, cpu) += delta_cpu * NS_PER_TICK; +- if (user_mode_vm(regs)) ++ if (user_mode_vm(get_irq_regs())) + account_user_time(current, (cputime_t)delta_cpu); + else + account_system_time(current, HARDIRQ_OFFSET, +@@ -754,10 +755,10 @@ irqreturn_t timer_interrupt(int irq, voi + /* Local timer processing (see update_process_times()). */ + run_local_timers(); + if (rcu_pending(cpu)) +- rcu_check_callbacks(cpu, user_mode_vm(regs)); ++ rcu_check_callbacks(cpu, user_mode_vm(get_irq_regs())); + scheduler_tick(); + run_posix_cpu_timers(current); +- profile_tick(CPU_PROFILING, regs); ++ profile_tick(CPU_PROFILING); + + return IRQ_HANDLED; + } +@@ -967,10 +968,11 @@ extern void (*late_time_init)(void); + /* Duplicate of time_init() below, with hpet_enable part added */ + static void __init hpet_time_init(void) + { +- xtime.tv_sec = get_cmos_time(); +- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); +- set_normalized_timespec(&wall_to_monotonic, +- -xtime.tv_sec, -xtime.tv_nsec); ++ struct timespec ts; ++ ts.tv_sec = get_cmos_time(); ++ ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); ++ ++ do_settimeofday(&ts); + + if ((hpet_enable() >= 0) && hpet_use_timer) { + printk("Using HPET for base-timer\n"); +--- sle11-2009-05-14.orig/arch/x86/kernel/traps_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/traps_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_EISA + #include +@@ -40,7 +41,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -51,11 +51,14 @@ + #include + #include + #include ++#include + + #include + + #include "mach_traps.h" + ++int panic_on_unrecovered_nmi; ++ + asmlinkage int system_call(void); + + struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, +@@ -124,62 +127,63 @@ static inline int valid_stack_ptr(struct + p < (void *)tinfo + THREAD_SIZE - 3; + } + +-/* +- * Print one address/symbol entries per line. +- */ +-static inline void print_addr_and_symbol(unsigned long addr, char *log_lvl) +-{ +- printk(" [<%08lx>] ", addr); +- +- print_symbol("%s\n", addr); +-} +- + static inline unsigned long print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long ebp, +- char *log_lvl) ++ struct stacktrace_ops *ops, void *data) + { + unsigned long addr; + + #ifdef CONFIG_FRAME_POINTER + while (valid_stack_ptr(tinfo, (void *)ebp)) { ++ unsigned long new_ebp; + addr = *(unsigned long *)(ebp + 4); +- print_addr_and_symbol(addr, log_lvl); ++ ops->address(data, addr); + /* + * break out of recursive entries (such as +- * end_of_stack_stop_unwind_function): ++ * end_of_stack_stop_unwind_function). Also, ++ * we can never allow a frame pointer to ++ * move downwards! + */ +- if (ebp == *(unsigned long *)ebp) ++ new_ebp = *(unsigned long *)ebp; ++ if (new_ebp <= ebp) + break; +- ebp = *(unsigned long *)ebp; ++ ebp = new_ebp; + } + #else + while (valid_stack_ptr(tinfo, stack)) { + addr = *stack++; + if (__kernel_text_address(addr)) +- print_addr_and_symbol(addr, log_lvl); ++ ops->address(data, addr); + } + #endif + return ebp; + } + ++struct ops_and_data { ++ struct stacktrace_ops *ops; ++ void *data; ++}; ++ + static asmlinkage int +-show_trace_unwind(struct unwind_frame_info *info, void *log_lvl) ++dump_trace_unwind(struct unwind_frame_info *info, void *data) + { ++ struct ops_and_data *oad = (struct ops_and_data *)data; + int n = 0; + + while (unwind(info) == 0 && UNW_PC(info)) { + n++; +- print_addr_and_symbol(UNW_PC(info), log_lvl); ++ oad->ops->address(oad->data, UNW_PC(info)); + if (arch_unw_user_mode(info)) + break; + } + return n; + } + +-static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, +- unsigned long *stack, char *log_lvl) ++void dump_trace(struct task_struct *task, struct pt_regs *regs, ++ unsigned long *stack, ++ struct stacktrace_ops *ops, void *data) + { +- unsigned long ebp; ++ unsigned long ebp = 0; + + if (!task) + task = current; +@@ -187,54 +191,116 @@ static void show_trace_log_lvl(struct ta + if (call_trace >= 0) { + int unw_ret = 0; + struct unwind_frame_info info; ++ struct ops_and_data oad = { .ops = ops, .data = data }; + + if (regs) { + if (unwind_init_frame_info(&info, task, regs) == 0) +- unw_ret = show_trace_unwind(&info, log_lvl); ++ unw_ret = dump_trace_unwind(&info, &oad); + } else if (task == current) +- unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl); ++ unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); + else { + if (unwind_init_blocked(&info, task) == 0) +- unw_ret = show_trace_unwind(&info, log_lvl); ++ unw_ret = dump_trace_unwind(&info, &oad); + } + if (unw_ret > 0) { + if (call_trace == 1 && !arch_unw_user_mode(&info)) { +- print_symbol("DWARF2 unwinder stuck at %s\n", ++ ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", + UNW_PC(&info)); + if (UNW_SP(&info) >= PAGE_OFFSET) { +- printk("Leftover inexact backtrace:\n"); ++ ops->warning(data, "Leftover inexact backtrace:\n"); + stack = (void *)UNW_SP(&info); ++ if (!stack) ++ return; ++ ebp = UNW_FP(&info); + } else +- printk("Full inexact backtrace again:\n"); ++ ops->warning(data, "Full inexact backtrace again:\n"); + } else if (call_trace >= 1) + return; + else +- printk("Full inexact backtrace again:\n"); ++ ops->warning(data, "Full inexact backtrace again:\n"); + } else +- printk("Inexact backtrace:\n"); ++ ops->warning(data, "Inexact backtrace:\n"); + } +- +- if (task == current) { +- /* Grab ebp right from our regs */ +- asm ("movl %%ebp, %0" : "=r" (ebp) : ); +- } else { +- /* ebp is the last reg pushed by switch_to */ +- ebp = *(unsigned long *) task->thread.esp; ++ if (!stack) { ++ unsigned long dummy; ++ stack = &dummy; ++ if (task && task != current) ++ stack = (unsigned long *)task->thread.esp; ++ } ++ ++#ifdef CONFIG_FRAME_POINTER ++ if (!ebp) { ++ if (task == current) { ++ /* Grab ebp right from our regs */ ++ asm ("movl %%ebp, %0" : "=r" (ebp) : ); ++ } else { ++ /* ebp is the last reg pushed by switch_to */ ++ ebp = *(unsigned long *) task->thread.esp; ++ } + } ++#endif + + while (1) { + struct thread_info *context; + context = (struct thread_info *) + ((unsigned long)stack & (~(THREAD_SIZE - 1))); +- ebp = print_context_stack(context, stack, ebp, log_lvl); ++ ebp = print_context_stack(context, stack, ebp, ops, data); ++ /* Should be after the line below, but somewhere ++ in early boot context comes out corrupted and we ++ can't reference it -AK */ ++ if (ops->stack(data, "IRQ") < 0) ++ break; + stack = (unsigned long*)context->previous_esp; + if (!stack) + break; +- printk("%s =======================\n", log_lvl); + } + } ++EXPORT_SYMBOL(dump_trace); ++ ++static void ++print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) ++{ ++ printk(data); ++ print_symbol(msg, symbol); ++ printk("\n"); ++} ++ ++static void print_trace_warning(void *data, char *msg) ++{ ++ printk("%s%s\n", (char *)data, msg); ++} + +-void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long * stack) ++static int print_trace_stack(void *data, char *name) ++{ ++ return 0; ++} ++ ++/* ++ * Print one address/symbol entries per line. ++ */ ++static void print_trace_address(void *data, unsigned long addr) ++{ ++ printk("%s [<%08lx>] ", (char *)data, addr); ++ print_symbol("%s\n", addr); ++} ++ ++static struct stacktrace_ops print_trace_ops = { ++ .warning = print_trace_warning, ++ .warning_symbol = print_trace_warning_symbol, ++ .stack = print_trace_stack, ++ .address = print_trace_address, ++}; ++ ++static void ++show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, ++ unsigned long * stack, char *log_lvl) ++{ ++ dump_trace(task, regs, stack, &print_trace_ops, log_lvl); ++ printk("%s =======================\n", log_lvl); ++} ++ ++void show_trace(struct task_struct *task, struct pt_regs *regs, ++ unsigned long * stack) + { + show_trace_log_lvl(task, regs, stack, ""); + } +@@ -297,12 +363,13 @@ void show_registers(struct pt_regs *regs + ss = regs->xss & 0xffff; + } + print_modules(); +- printk(KERN_EMERG "CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\n" +- "EFLAGS: %08lx (%s %.*s) \n", ++ printk(KERN_EMERG "CPU: %d\n" ++ KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" ++ KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, +- print_tainted(), regs->eflags, system_utsname.release, +- (int)strcspn(system_utsname.version, " "), +- system_utsname.version); ++ print_tainted(), regs->eflags, init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); + print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); + printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); +@@ -319,6 +386,8 @@ void show_registers(struct pt_regs *regs + */ + if (in_kernel) { + u8 __user *eip; ++ int code_bytes = 64; ++ unsigned char c; + + printk("\n" KERN_EMERG "Stack: "); + show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); +@@ -326,9 +395,12 @@ void show_registers(struct pt_regs *regs + printk(KERN_EMERG "Code: "); + + eip = (u8 __user *)regs->eip - 43; +- for (i = 0; i < 64; i++, eip++) { +- unsigned char c; +- ++ if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { ++ /* try starting at EIP */ ++ eip = (u8 __user *)regs->eip; ++ code_bytes = 32; ++ } ++ for (i = 0; i < code_bytes; i++, eip++) { + if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { + printk(" Bad EIP value."); + break; +@@ -349,7 +421,7 @@ static void handle_BUG(struct pt_regs *r + + if (eip < PAGE_OFFSET) + return; +- if (__get_user(ud2, (unsigned short __user *)eip)) ++ if (probe_kernel_address((unsigned short __user *)eip, ud2)) + return; + if (ud2 != 0x0b0f) + return; +@@ -362,7 +434,8 @@ static void handle_BUG(struct pt_regs *r + char *file; + char c; + +- if (__get_user(line, (unsigned short __user *)(eip + 2))) ++ if (probe_kernel_address((unsigned short __user *)(eip + 2), ++ line)) + break; + if (__get_user(file, (char * __user *)(eip + 4)) || + (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) +@@ -604,18 +677,24 @@ gp_in_kernel: + } + } + +-static void mem_parity_error(unsigned char reason, struct pt_regs * regs) ++static __kprobes void ++mem_parity_error(unsigned char reason, struct pt_regs * regs) + { +- printk(KERN_EMERG "Uhhuh. NMI received. Dazed and confused, but trying " +- "to continue\n"); ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " ++ "CPU %d.\n", reason, smp_processor_id()); + printk(KERN_EMERG "You probably have a hardware problem with your RAM " + "chips\n"); ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + + /* Clear and disable the memory parity error line. */ + clear_mem_error(reason); + } + +-static void io_check_error(unsigned char reason, struct pt_regs * regs) ++static __kprobes void ++io_check_error(unsigned char reason, struct pt_regs * regs) + { + printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); +@@ -624,7 +703,8 @@ static void io_check_error(unsigned char + clear_io_check_error(reason); + } + +-static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) ++static __kprobes void ++unknown_nmi_error(unsigned char reason, struct pt_regs * regs) + { + #ifdef CONFIG_MCA + /* Might actually be able to figure out what the guilty party +@@ -634,15 +714,18 @@ static void unknown_nmi_error(unsigned c + return; + } + #endif +- printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", +- reason, smp_processor_id()); +- printk("Dazed and confused, but trying to continue\n"); +- printk("Do you have a strange power saving mode enabled?\n"); ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " ++ "CPU %d.\n", reason, smp_processor_id()); ++ printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + } + + static DEFINE_SPINLOCK(nmi_print_lock); + +-void die_nmi (struct pt_regs *regs, const char *msg) ++void __kprobes die_nmi(struct pt_regs *regs, const char *msg) + { + if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == + NOTIFY_STOP) +@@ -674,7 +757,7 @@ void die_nmi (struct pt_regs *regs, cons + do_exit(SIGSEGV); + } + +-static void default_do_nmi(struct pt_regs * regs) ++static __kprobes void default_do_nmi(struct pt_regs * regs) + { + unsigned char reason = 0; + +@@ -691,12 +774,12 @@ static void default_do_nmi(struct pt_reg + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ +- if (nmi_watchdog) { +- nmi_watchdog_tick(regs); ++ if (nmi_watchdog_tick(regs, reason)) + return; +- } ++ if (!do_nmi_callback(regs, smp_processor_id())) + #endif +- unknown_nmi_error(reason, regs); ++ unknown_nmi_error(reason, regs); ++ + return; + } + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) +@@ -712,14 +795,7 @@ static void default_do_nmi(struct pt_reg + reassert_nmi(); + } + +-static int dummy_nmi_callback(struct pt_regs * regs, int cpu) +-{ +- return 0; +-} +- +-static nmi_callback_t nmi_callback = dummy_nmi_callback; +- +-fastcall void do_nmi(struct pt_regs * regs, long error_code) ++fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) + { + int cpu; + +@@ -729,25 +805,11 @@ fastcall void do_nmi(struct pt_regs * re + + ++nmi_count(cpu); + +- if (!rcu_dereference(nmi_callback)(regs, cpu)) +- default_do_nmi(regs); ++ default_do_nmi(regs); + + nmi_exit(); + } + +-void set_nmi_callback(nmi_callback_t callback) +-{ +- vmalloc_sync_all(); +- rcu_assign_pointer(nmi_callback, callback); +-} +-EXPORT_SYMBOL_GPL(set_nmi_callback); +- +-void unset_nmi_callback(void) +-{ +- nmi_callback = dummy_nmi_callback; +-} +-EXPORT_SYMBOL_GPL(unset_nmi_callback); +- + #ifdef CONFIG_KPROBES + fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) + { +--- sle11-2009-05-14.orig/arch/x86/mach-xen/setup.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mach-xen/setup.c 2009-03-04 11:28:34.000000000 +0100 +@@ -103,8 +103,10 @@ void __init pre_setup_arch_hook(void) + + setup_xen_features(); + +- if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0) +- set_fixaddr_top(pp.virt_start); ++ if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0) { ++ hypervisor_virt_start = pp.virt_start; ++ reserve_top_address(0UL - pp.virt_start); ++ } + + if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) { + machine_to_phys_mapping = (unsigned long *)mapping.v_start; +--- sle11-2009-05-14.orig/arch/x86/mm/fault_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mm/fault_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -27,21 +27,24 @@ + #include + #include + #include ++#include + + extern void die(const char *,struct pt_regs *,long); + +-#ifdef CONFIG_KPROBES +-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); ++static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); ++ + int register_page_fault_notifier(struct notifier_block *nb) + { + vmalloc_sync_all(); + return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); + } ++EXPORT_SYMBOL_GPL(register_page_fault_notifier); + + int unregister_page_fault_notifier(struct notifier_block *nb) + { + return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); + } ++EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); + + static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +@@ -55,14 +58,6 @@ static inline int notify_page_fault(enum + }; + return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); + } +-#else +-static inline int notify_page_fault(enum die_val val, const char *str, +- struct pt_regs *regs, long err, int trap, int sig) +-{ +- return NOTIFY_DONE; +-} +-#endif +- + + /* + * Unlock any spinlocks which will prevent us from getting the +@@ -119,10 +114,10 @@ static inline unsigned long get_segment_ + } + + /* The standard kernel/user address space limit. */ +- *eip_limit = (seg & 2) ? USER_DS.seg : KERNEL_DS.seg; ++ *eip_limit = user_mode(regs) ? USER_DS.seg : KERNEL_DS.seg; + + /* By far the most common cases. */ +- if (likely(seg == __USER_CS || seg == GET_KERNEL_CS())) ++ if (likely(SEGMENT_IS_FLAT_CODE(seg))) + return eip; + + /* Check the segment exists, is within the current LDT/GDT size, +@@ -559,11 +554,7 @@ good_area: + write = 0; + switch (error_code & 3) { + default: /* 3: write, present */ +-#ifdef TEST_VERIFY_AREA +- if (regs->cs == GET_KERNEL_CS()) +- printk("WP fault at %08lx\n", regs->eip); +-#endif +- /* fall through */ ++ /* fall through */ + case 2: /* write, not present */ + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; +@@ -572,7 +563,7 @@ good_area: + case 1: /* read, present */ + goto bad_area; + case 0: /* read, not present */ +- if (!(vma->vm_flags & (VM_READ | VM_EXEC))) ++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) + goto bad_area; + } + +@@ -704,7 +695,7 @@ no_context: + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (tsk->pid == 1) { ++ if (is_init(tsk)) { + yield(); + down_read(&mm->mmap_sem); + goto survive; +--- sle11-2009-05-14.orig/arch/x86/mm/highmem_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mm/highmem_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -38,11 +38,9 @@ static void *__kmap_atomic(struct page * + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +-#ifdef CONFIG_DEBUG_HIGHMEM + if (!pte_none(*(kmap_pte-idx))) + BUG(); +-#endif +- set_pte_at_sync(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); ++ set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); + + return (void*) vaddr; + } +@@ -62,36 +60,26 @@ void *kmap_atomic_pte(struct page *page, + + void kunmap_atomic(void *kvaddr, enum km_type type) + { +-#if defined(CONFIG_DEBUG_HIGHMEM) || defined(CONFIG_XEN) + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); + +- if (vaddr < FIXADDR_START) { // FIXME ++#ifdef CONFIG_DEBUG_HIGHMEM ++ if (vaddr >= PAGE_OFFSET && vaddr < (unsigned long)high_memory) { + dec_preempt_count(); + preempt_check_resched(); + return; + } +-#endif + +-#if defined(CONFIG_DEBUG_HIGHMEM) + if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)) + BUG(); +- +- /* +- * force other mappings to Oops if they'll try to access +- * this pte without first remap it +- */ +- pte_clear(&init_mm, vaddr, kmap_pte-idx); +- __flush_tlb_one(vaddr); +-#elif defined(CONFIG_XEN) ++#endif + /* +- * We must ensure there are no dangling pagetable references when +- * returning memory to Xen (decrease_reservation). +- * XXX TODO: We could make this faster by only zapping when +- * kmap_flush_unused is called but that is trickier and more invasive. ++ * Force other mappings to Oops if they'll try to access this pte ++ * without first remap it. Keeping stale mappings around is a bad idea ++ * also, in case the page changes cacheability attributes or becomes ++ * a protected page in a hypervisor. + */ +- pte_clear(&init_mm, vaddr, kmap_pte-idx); +-#endif ++ kpte_clear_flush(kmap_pte-idx, vaddr); + + dec_preempt_count(); + preempt_check_resched(); +@@ -110,7 +98,6 @@ void *kmap_atomic_pfn(unsigned long pfn, + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot)); +- __flush_tlb_one(vaddr); + + return (void*) vaddr; + } +--- sle11-2009-05-14.orig/arch/x86/mm/hypervisor.c 2008-12-15 11:13:45.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/hypervisor.c 2009-03-04 11:28:34.000000000 +0100 +@@ -31,6 +31,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -44,6 +45,302 @@ + #include + #include + ++EXPORT_SYMBOL(hypercall_page); ++ ++#define NR_MC BITS_PER_LONG ++#define NR_MMU BITS_PER_LONG ++#define NR_MMUEXT (BITS_PER_LONG / 4) ++ ++DEFINE_PER_CPU(bool, xen_lazy_mmu); ++EXPORT_PER_CPU_SYMBOL(xen_lazy_mmu); ++struct lazy_mmu { ++ unsigned int nr_mc, nr_mmu, nr_mmuext; ++ multicall_entry_t mc[NR_MC]; ++ mmu_update_t mmu[NR_MMU]; ++ struct mmuext_op mmuext[NR_MMUEXT]; ++}; ++static DEFINE_PER_CPU(struct lazy_mmu, lazy_mmu); ++ ++static inline bool use_lazy_mmu_mode(void) ++{ ++#ifdef CONFIG_PREEMPT ++ if (!preempt_count()) ++ return false; ++#endif ++ return !irq_count(); ++} ++ ++static void multicall_failed(const multicall_entry_t *mc, int rc) ++{ ++ printk(KERN_EMERG "hypercall#%lu(%lx, %lx, %lx, %lx)" ++ " failed: %d (caller %lx)\n", ++ mc->op, mc->args[0], mc->args[1], mc->args[2], mc->args[3], ++ rc, mc->args[5]); ++ BUG(); ++} ++ ++int xen_multicall_flush(bool ret_last) { ++ struct lazy_mmu *lazy = &__get_cpu_var(lazy_mmu); ++ multicall_entry_t *mc = lazy->mc; ++ unsigned int count = lazy->nr_mc; ++ ++ if (!count || !use_lazy_mmu_mode()) ++ return 0; ++ ++ lazy->nr_mc = 0; ++ lazy->nr_mmu = 0; ++ lazy->nr_mmuext = 0; ++ ++ if (count == 1) { ++ int rc = _hypercall(int, mc->op, mc->args[0], mc->args[1], ++ mc->args[2], mc->args[3], mc->args[4]); ++ ++ if (unlikely(rc)) { ++ if (ret_last) ++ return rc; ++ multicall_failed(mc, rc); ++ } ++ } else { ++ if (HYPERVISOR_multicall(mc, count)) ++ BUG(); ++ while (count-- > ret_last) ++ if (unlikely(mc++->result)) ++ multicall_failed(mc - 1, mc[-1].result); ++ if (ret_last) ++ return mc->result; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(xen_multicall_flush); ++ ++int xen_multi_update_va_mapping(unsigned long va, pte_t pte, ++ unsigned long uvmf) ++{ ++ struct lazy_mmu *lazy = &__get_cpu_var(lazy_mmu); ++ multicall_entry_t *mc; ++ ++ if (unlikely(!use_lazy_mmu_mode())) ++#ifdef CONFIG_X86_PAE ++ return _hypercall4(int, update_va_mapping, va, ++ pte.pte_low, pte.pte_high, uvmf); ++#else ++ return _hypercall3(int, update_va_mapping, va, ++ pte.pte, uvmf); ++#endif ++ ++ if (unlikely(lazy->nr_mc == NR_MC)) ++ xen_multicall_flush(false); ++ ++ mc = lazy->mc + lazy->nr_mc++; ++ mc->op = __HYPERVISOR_update_va_mapping; ++ mc->args[0] = va; ++#ifndef CONFIG_X86_PAE ++ mc->args[1] = pte.pte; ++#else ++ mc->args[1] = pte.pte_low; ++ mc->args[2] = pte.pte_high; ++#endif ++ mc->args[MULTI_UVMFLAGS_INDEX] = uvmf; ++ mc->args[5] = (long)__builtin_return_address(0); ++ ++ return 0; ++} ++ ++static inline bool mmu_may_merge(const multicall_entry_t *mc, ++ unsigned int op, domid_t domid) ++{ ++ return mc->op == op && !mc->args[2] && mc->args[3] == domid; ++} ++ ++int xen_multi_mmu_update(mmu_update_t *src, unsigned int count, ++ unsigned int *success_count, domid_t domid) ++{ ++ struct lazy_mmu *lazy = &__get_cpu_var(lazy_mmu); ++ multicall_entry_t *mc = lazy->mc + lazy->nr_mc; ++ mmu_update_t *dst; ++ bool commit, merge; ++ ++ if (unlikely(!use_lazy_mmu_mode())) ++ return _hypercall4(int, mmu_update, src, count, ++ success_count, domid); ++ ++ commit = (lazy->nr_mmu + count) > NR_MMU || success_count; ++ merge = lazy->nr_mc && !commit ++ && mmu_may_merge(mc - 1, __HYPERVISOR_mmu_update, domid); ++ if (unlikely(lazy->nr_mc == NR_MC) && !merge) { ++ xen_multicall_flush(false); ++ mc = lazy->mc; ++ commit = count > NR_MMU || success_count; ++ } ++ ++ if (!lazy->nr_mc && unlikely(commit)) ++ return _hypercall4(int, mmu_update, src, count, ++ success_count, domid); ++ ++ dst = lazy->mmu + lazy->nr_mmu; ++ lazy->nr_mmu += count; ++ if (merge) { ++ mc[-1].args[1] += count; ++ memcpy(dst, src, count * sizeof(*src)); ++ } else { ++ ++lazy->nr_mc; ++ mc->op = __HYPERVISOR_mmu_update; ++ if (!commit) { ++ mc->args[0] = (unsigned long)dst; ++ memcpy(dst, src, count * sizeof(*src)); ++ } else ++ mc->args[0] = (unsigned long)src; ++ mc->args[1] = count; ++ mc->args[2] = (unsigned long)success_count; ++ mc->args[3] = domid; ++ mc->args[5] = (long)__builtin_return_address(0); ++ } ++ ++ while (!commit && count--) ++ switch (src++->ptr & (sizeof(pteval_t) - 1)) { ++ case MMU_NORMAL_PT_UPDATE: ++ case MMU_PT_UPDATE_PRESERVE_AD: ++ break; ++ default: ++ commit = true; ++ break; ++ } ++ ++ return commit ? xen_multicall_flush(true) : 0; ++} ++ ++int xen_multi_mmuext_op(struct mmuext_op *src, unsigned int count, ++ unsigned int *success_count, domid_t domid) ++{ ++ struct lazy_mmu *lazy = &__get_cpu_var(lazy_mmu); ++ multicall_entry_t *mc; ++ struct mmuext_op *dst; ++ bool commit, merge; ++ ++ if (unlikely(!use_lazy_mmu_mode())) ++ return _hypercall4(int, mmuext_op, src, count, ++ success_count, domid); ++ ++ /* ++ * While it could be useful in theory, I've never seen the body of ++ * this conditional to be reached, hence it seems more reasonable ++ * to disable it for the time being. ++ */ ++ if (0 && likely(count) ++ && likely(!success_count) ++ && likely(domid == DOMID_SELF) ++ && likely(lazy->nr_mc) ++ && lazy->mc[lazy->nr_mc - 1].op == __HYPERVISOR_update_va_mapping) { ++ unsigned long oldf, newf = UVMF_NONE; ++ ++ switch (src->cmd) { ++ case MMUEXT_TLB_FLUSH_ALL: ++ newf = UVMF_TLB_FLUSH | UVMF_ALL; ++ break; ++ case MMUEXT_INVLPG_ALL: ++ newf = UVMF_INVLPG | UVMF_ALL; ++ break; ++ case MMUEXT_TLB_FLUSH_MULTI: ++ newf = UVMF_TLB_FLUSH | UVMF_MULTI ++ | (unsigned long)src->arg2.vcpumask.p; ++ break; ++ case MMUEXT_INVLPG_MULTI: ++ newf = UVMF_INVLPG | UVMF_MULTI ++ | (unsigned long)src->arg2.vcpumask.p; ++ break; ++ case MMUEXT_TLB_FLUSH_LOCAL: ++ newf = UVMF_TLB_FLUSH | UVMF_LOCAL; ++ break; ++ case MMUEXT_INVLPG_LOCAL: ++ newf = UVMF_INVLPG | UVMF_LOCAL; ++ break; ++ } ++ mc = lazy->mc + lazy->nr_mc - 1; ++ oldf = mc->args[MULTI_UVMFLAGS_INDEX]; ++ if (newf == UVMF_NONE || oldf == UVMF_NONE ++ || newf == (UVMF_TLB_FLUSH | UVMF_ALL)) ++ ; ++ else if (oldf == (UVMF_TLB_FLUSH | UVMF_ALL)) ++ newf = UVMF_TLB_FLUSH | UVMF_ALL; ++ else if ((newf & UVMF_FLUSHTYPE_MASK) == UVMF_INVLPG ++ && (oldf & UVMF_FLUSHTYPE_MASK) == UVMF_INVLPG ++ && ((src->arg1.linear_addr ^ mc->args[0]) ++ >> PAGE_SHIFT)) ++ newf = UVMF_NONE; ++ else if (((oldf | newf) & UVMF_ALL) ++ && !((oldf ^ newf) & UVMF_FLUSHTYPE_MASK)) ++ newf |= UVMF_ALL; ++ else if ((oldf ^ newf) & ~UVMF_FLUSHTYPE_MASK) ++ newf = UVMF_NONE; ++ else if ((oldf & UVMF_FLUSHTYPE_MASK) == UVMF_TLB_FLUSH) ++ newf = (newf & ~UVMF_FLUSHTYPE_MASK) | UVMF_TLB_FLUSH; ++ else if ((newf & UVMF_FLUSHTYPE_MASK) != UVMF_TLB_FLUSH ++ && ((newf ^ oldf) & UVMF_FLUSHTYPE_MASK)) ++ newf = UVMF_NONE; ++ if (newf != UVMF_NONE) { ++ mc->args[MULTI_UVMFLAGS_INDEX] = newf; ++ ++src; ++ if (!--count) ++ return 0; ++ } ++ } ++ ++ mc = lazy->mc + lazy->nr_mc; ++ commit = (lazy->nr_mmuext + count) > NR_MMUEXT || success_count; ++ merge = lazy->nr_mc && !commit ++ && mmu_may_merge(mc - 1, __HYPERVISOR_mmuext_op, domid); ++ if (unlikely(lazy->nr_mc == NR_MC) && !merge) { ++ xen_multicall_flush(false); ++ mc = lazy->mc; ++ commit = count > NR_MMUEXT || success_count; ++ } ++ ++ if (!lazy->nr_mc && unlikely(commit)) ++ return _hypercall4(int, mmuext_op, src, count, ++ success_count, domid); ++ ++ dst = lazy->mmuext + lazy->nr_mmuext; ++ lazy->nr_mmuext += count; ++ if (merge) { ++ mc[-1].args[1] += count; ++ memcpy(dst, src, count * sizeof(*src)); ++ } else { ++ ++lazy->nr_mc; ++ mc->op = __HYPERVISOR_mmuext_op; ++ if (!commit) { ++ mc->args[0] = (unsigned long)dst; ++ memcpy(dst, src, count * sizeof(*src)); ++ } else ++ mc->args[0] = (unsigned long)src; ++ mc->args[1] = count; ++ mc->args[2] = (unsigned long)success_count; ++ mc->args[3] = domid; ++ mc->args[5] = (long)__builtin_return_address(0); ++ } ++ ++ while (!commit && count--) ++ switch (src++->cmd) { ++ case MMUEXT_PIN_L1_TABLE: ++ case MMUEXT_PIN_L2_TABLE: ++ case MMUEXT_PIN_L3_TABLE: ++ case MMUEXT_PIN_L4_TABLE: ++ case MMUEXT_UNPIN_TABLE: ++ case MMUEXT_TLB_FLUSH_LOCAL: ++ case MMUEXT_INVLPG_LOCAL: ++ case MMUEXT_TLB_FLUSH_MULTI: ++ case MMUEXT_INVLPG_MULTI: ++ case MMUEXT_TLB_FLUSH_ALL: ++ case MMUEXT_INVLPG_ALL: ++ break; ++ default: ++ commit = true; ++ break; ++ } ++ ++ return commit ? xen_multicall_flush(true) : 0; ++} ++ + void xen_l1_entry_update(pte_t *ptr, pte_t val) + { + mmu_update_t u; +@@ -542,7 +839,8 @@ int write_ldt_entry(void *ldt, int entry + #define MAX_BATCHED_FULL_PTES 32 + + int xen_change_pte_range(struct mm_struct *mm, pmd_t *pmd, +- unsigned long addr, unsigned long end, pgprot_t newprot) ++ unsigned long addr, unsigned long end, pgprot_t newprot, ++ int dirty_accountable) + { + int rc = 0, i = 0; + mmu_update_t u[MAX_BATCHED_FULL_PTES]; +@@ -555,10 +853,14 @@ int xen_change_pte_range(struct mm_struc + pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + do { + if (pte_present(*pte)) { ++ pte_t ptent = pte_modify(*pte, newprot); ++ ++ if (dirty_accountable && pte_dirty(ptent)) ++ ptent = pte_mkwrite(ptent); + u[i].ptr = (__pmd_val(*pmd) & PHYSICAL_PAGE_MASK) + | ((unsigned long)pte & ~PAGE_MASK) + | MMU_PT_UPDATE_PRESERVE_AD; +- u[i].val = __pte_val(pte_modify(*pte, newprot)); ++ u[i].val = __pte_val(ptent); + if (++i == MAX_BATCHED_FULL_PTES) { + if ((rc = HYPERVISOR_mmu_update( + &u[0], i, NULL, DOMID_SELF)) != 0) +--- sle11-2009-05-14.orig/arch/x86/mm/init_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mm/init_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -462,16 +462,22 @@ EXPORT_SYMBOL(__supported_pte_mask); + * on Enable + * off Disable + */ +-void __init noexec_setup(const char *str) ++static int __init noexec_setup(char *str) + { +- if (!strncmp(str, "on",2) && cpu_has_nx) { +- __supported_pte_mask |= _PAGE_NX; +- disable_nx = 0; +- } else if (!strncmp(str,"off",3)) { ++ if (!str || !strcmp(str, "on")) { ++ if (cpu_has_nx) { ++ __supported_pte_mask |= _PAGE_NX; ++ disable_nx = 0; ++ } ++ } else if (!strcmp(str,"off")) { + disable_nx = 1; + __supported_pte_mask &= ~_PAGE_NX; +- } ++ } else ++ return -EINVAL; ++ ++ return 0; + } ++early_param("noexec", noexec_setup); + + int nx_enabled = 0; + #ifdef CONFIG_X86_PAE +@@ -514,6 +520,7 @@ int __init set_kernel_exec(unsigned long + pte->pte_high &= ~(1 << (_PAGE_BIT_NX - 32)); + else + pte->pte_high |= 1 << (_PAGE_BIT_NX - 32); ++ pte_update_defer(&init_mm, vaddr, pte); + __flush_tlb_all(); + out: + return ret; +@@ -596,18 +603,6 @@ static void __init test_wp_bit(void) + } + } + +-static void __init set_max_mapnr_init(void) +-{ +-#ifdef CONFIG_HIGHMEM +- num_physpages = highend_pfn; +-#else +- num_physpages = max_low_pfn; +-#endif +-#ifdef CONFIG_FLATMEM +- max_mapnr = num_physpages; +-#endif +-} +- + static struct kcore_list kcore_mem, kcore_vmalloc; + + void __init mem_init(void) +@@ -623,8 +618,7 @@ void __init mem_init(void) + #endif + + #ifdef CONFIG_FLATMEM +- if (!mem_map) +- BUG(); ++ BUG_ON(!mem_map); + #endif + + bad_ppro = ppro_with_ram_bug(); +@@ -639,17 +633,6 @@ void __init mem_init(void) + } + #endif + +- set_max_mapnr_init(); +- +-#ifdef CONFIG_HIGHMEM +- high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1; +-#else +- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1; +-#endif +- printk("vmalloc area: %lx-%lx, maxmem %lx\n", +- VMALLOC_START,VMALLOC_END,MAXMEM); +- BUG_ON(VMALLOC_START > VMALLOC_END); +- + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem(); + /* XEN: init and count low-mem pages outside initial allocation. */ +@@ -687,6 +670,48 @@ void __init mem_init(void) + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) + ); + ++#if 1 /* double-sanity-check paranoia */ ++ printk("virtual kernel memory layout:\n" ++ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#ifdef CONFIG_HIGHMEM ++ " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#endif ++ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" ++ " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" ++ " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", ++ FIXADDR_START, FIXADDR_TOP, ++ (FIXADDR_TOP - FIXADDR_START) >> 10, ++ ++#ifdef CONFIG_HIGHMEM ++ PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, ++ (LAST_PKMAP*PAGE_SIZE) >> 10, ++#endif ++ ++ VMALLOC_START, VMALLOC_END, ++ (VMALLOC_END - VMALLOC_START) >> 20, ++ ++ (unsigned long)__va(0), (unsigned long)high_memory, ++ ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20, ++ ++ (unsigned long)&__init_begin, (unsigned long)&__init_end, ++ ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10, ++ ++ (unsigned long)&_etext, (unsigned long)&_edata, ++ ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, ++ ++ (unsigned long)&_text, (unsigned long)&_etext, ++ ((unsigned long)&_etext - (unsigned long)&_text) >> 10); ++ ++#ifdef CONFIG_HIGHMEM ++ BUG_ON(PKMAP_BASE+LAST_PKMAP*PAGE_SIZE > FIXADDR_START); ++ BUG_ON(VMALLOC_END > PKMAP_BASE); ++#endif ++ BUG_ON(VMALLOC_START > VMALLOC_END); ++ BUG_ON((unsigned long)high_memory > VMALLOC_START); ++#endif /* double-sanity-check paranoia */ ++ + #ifdef CONFIG_X86_PAE + if (!cpu_has_pae) + panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); +@@ -717,7 +742,7 @@ void __init mem_init(void) + int arch_add_memory(int nid, u64 start, u64 size) + { + struct pglist_data *pgdata = &contig_page_data; +- struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1; ++ struct zone *zone = pgdata->node_zones + ZONE_HIGHMEM; + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + +--- sle11-2009-05-14.orig/arch/x86/mm/ioremap_32-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mm/ioremap_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -12,7 +12,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -118,7 +118,7 @@ int direct_remap_pfn_range(struct vm_are + if (domid == DOMID_SELF) + return -EINVAL; + +- vma->vm_flags |= VM_IO | VM_RESERVED; ++ vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; + + vma->vm_mm->context.has_foreign_mappings = 1; + +@@ -203,6 +203,7 @@ void __iomem * __ioremap(unsigned long p + void __iomem * addr; + struct vm_struct * area; + unsigned long offset, last_addr; ++ pgprot_t prot; + domid_t domid = DOMID_IO; + + /* Don't allow wraparound or zero size */ +@@ -234,6 +235,8 @@ void __iomem * __ioremap(unsigned long p + domid = DOMID_SELF; + } + ++ prot = __pgprot(_KERNPG_TABLE | flags); ++ + /* + * Mappings have to be page-aligned + */ +@@ -249,10 +252,9 @@ void __iomem * __ioremap(unsigned long p + return NULL; + area->phys_addr = phys_addr; + addr = (void __iomem *) area->addr; +- flags |= _KERNPG_TABLE; + if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr, + phys_addr>>PAGE_SHIFT, +- size, __pgprot(flags), domid)) { ++ size, prot, domid)) { + vunmap((void __force *) addr); + return NULL; + } +--- sle11-2009-05-14.orig/arch/x86/mm/pgtable_32-xen.c 2008-12-01 11:25:57.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/pgtable_32-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -68,7 +68,9 @@ void show_mem(void) + printk(KERN_INFO "%lu pages writeback\n", + global_page_state(NR_WRITEBACK)); + printk(KERN_INFO "%lu pages mapped\n", global_page_state(NR_FILE_MAPPED)); +- printk(KERN_INFO "%lu pages slab\n", global_page_state(NR_SLAB)); ++ printk(KERN_INFO "%lu pages slab\n", ++ global_page_state(NR_SLAB_RECLAIMABLE) + ++ global_page_state(NR_SLAB_UNRECLAIMABLE)); + printk(KERN_INFO "%lu pages pagetables\n", + global_page_state(NR_PAGETABLE)); + } +@@ -108,18 +110,11 @@ void set_pmd_pfn(unsigned long vaddr, un + __flush_tlb_one(vaddr); + } + +-static int nr_fixmaps = 0; ++static int fixmaps; + unsigned long hypervisor_virt_start = HYPERVISOR_VIRT_START; +-unsigned long __FIXADDR_TOP = (HYPERVISOR_VIRT_START - 2 * PAGE_SIZE); ++unsigned long __FIXADDR_TOP = (HYPERVISOR_VIRT_START - PAGE_SIZE); + EXPORT_SYMBOL(__FIXADDR_TOP); + +-void __init set_fixaddr_top(unsigned long top) +-{ +- BUG_ON(nr_fixmaps > 0); +- hypervisor_virt_start = top; +- __FIXADDR_TOP = hypervisor_virt_start - 2 * PAGE_SIZE; +-} +- + void __set_fixmap (enum fixed_addresses idx, maddr_t phys, pgprot_t flags) + { + unsigned long address = __fix_to_virt(idx); +@@ -141,7 +136,21 @@ void __set_fixmap (enum fixed_addresses + if (HYPERVISOR_update_va_mapping(address, pte, + UVMF_INVLPG|UVMF_ALL)) + BUG(); +- nr_fixmaps++; ++ fixmaps++; ++} ++ ++/** ++ * reserve_top_address - reserves a hole in the top of kernel address space ++ * @reserve - size of hole to reserve ++ * ++ * Can be used to relocate the fixmap area and poke a hole in the top ++ * of kernel address space to make room for a hypervisor. ++ */ ++void __init reserve_top_address(unsigned long reserve) ++{ ++ BUG_ON(fixmaps > 0); ++ __FIXADDR_TOP = -reserve - PAGE_SIZE; ++ __VMALLOC_RESERVE += reserve; + } + + pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +--- sle11-2009-05-14.orig/arch/x86/pci/irq-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/pci/irq-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -991,10 +991,6 @@ static void __init pcibios_fixup_irqs(vo + pci_name(bridge), 'A' + pin, irq); + } + if (irq >= 0) { +- if (use_pci_vector() && +- !platform_legacy_irq(irq)) +- irq = IO_APIC_VECTOR(irq); +- + printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", + pci_name(dev), 'A' + pin, irq); + dev->irq = irq; +@@ -1155,10 +1151,6 @@ static int pirq_enable_irq(struct pci_de + } + dev = temp_dev; + if (irq >= 0) { +-#ifdef CONFIG_PCI_MSI +- if (!platform_legacy_irq(irq)) +- irq = IO_APIC_VECTOR(irq); +-#endif + printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", + pci_name(dev), 'A' + pin, irq); + dev->irq = irq; +@@ -1179,33 +1171,3 @@ static int pirq_enable_irq(struct pci_de + } + return 0; + } +- +-int pci_vector_resources(int last, int nr_released) +-{ +- int count = nr_released; +- +- int next = last; +- int offset = (last % 8); +- +- while (next < FIRST_SYSTEM_VECTOR) { +- next += 8; +-#ifdef CONFIG_X86_64 +- if (next == IA32_SYSCALL_VECTOR) +- continue; +-#else +- if (next == SYSCALL_VECTOR) +- continue; +-#endif +- count++; +- if (next >= FIRST_SYSTEM_VECTOR) { +- if (offset%8) { +- next = FIRST_DEVICE_VECTOR + offset; +- offset++; +- continue; +- } +- count--; +- } +- } +- +- return count; +-} +--- sle11-2009-05-14.orig/arch/x86/ia32/ia32entry-xen.S 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/ia32/ia32entry-xen.S 2009-03-04 11:28:34.000000000 +0100 +@@ -83,6 +83,7 @@ + */ + ENTRY(ia32_sysenter_target) + CFI_STARTPROC32 simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-RIP+16 + /*CFI_REL_OFFSET ss,SS-RIP+16*/ + CFI_REL_OFFSET rsp,RSP-RIP+16 +@@ -164,6 +165,7 @@ ENDPROC(ia32_sysenter_target) + */ + ENTRY(ia32_cstar_target) + CFI_STARTPROC32 simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-RIP+16 + /*CFI_REL_OFFSET ss,SS-RIP+16*/ + CFI_REL_OFFSET rsp,RSP-RIP+16 +@@ -243,6 +245,7 @@ ia32_badarg: + + ENTRY(ia32_syscall) + CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-RIP+16 + /*CFI_REL_OFFSET ss,SS-RIP+16*/ + CFI_REL_OFFSET rsp,RSP-RIP+16 +@@ -320,6 +323,7 @@ ENTRY(ia32_ptregs_common) + popq %r11 + CFI_ENDPROC + CFI_STARTPROC32 simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-ARGOFFSET + CFI_REL_OFFSET rax,RAX-ARGOFFSET + CFI_REL_OFFSET rcx,RCX-ARGOFFSET +@@ -653,8 +657,8 @@ ia32_sys_call_table: + .quad sys_readlinkat /* 305 */ + .quad sys_fchmodat + .quad sys_faccessat +- .quad quiet_ni_syscall /* pselect6 for now */ +- .quad quiet_ni_syscall /* ppoll for now */ ++ .quad compat_sys_pselect6 ++ .quad compat_sys_ppoll + .quad sys_unshare /* 310 */ + .quad compat_sys_set_robust_list + .quad compat_sys_get_robust_list +@@ -663,4 +667,5 @@ ia32_sys_call_table: + .quad sys_tee + .quad compat_sys_vmsplice + .quad compat_sys_move_pages ++ .quad sys_getcpu + ia32_syscall_end: +--- sle11-2009-05-14.orig/arch/x86/kernel/Makefile 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/Makefile 2009-03-04 11:28:34.000000000 +0100 +@@ -104,9 +104,9 @@ obj-$(CONFIG_X86_XEN) += fixup.o + ### + # 64 bit specific files + ifeq ($(CONFIG_X86_64),y) +- obj-y += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o tlb_uv.o +- obj-$(CONFIG_X86_XEN_GENAPIC) += genapic_xen_64.o +- obj-y += uv_sysfs.o ++ obj-$(CONFIG_X86_LOCAL_APIC) += genapic_64.o genapic_flat_64.o genx2apic_uv_x.o ++ obj-$(CONFIG_X86_XEN_GENAPIC) += genapic_64.o genapic_xen_64.o ++ obj-y += tlb_uv.o uv_sysfs.o + obj-y += genx2apic_cluster.o + obj-y += genx2apic_phys.o + obj-y += bios_uv.o uv_irq.o +@@ -124,5 +124,7 @@ ifeq ($(CONFIG_X86_64),y) + pci-dma_64-$(CONFIG_XEN) += pci-dma_32.o + endif + +-disabled-obj-$(CONFIG_XEN) := i8253.o i8259_$(BITS).o reboot.o smpboot_$(BITS).o tsc_$(BITS).o ++disabled-obj-$(CONFIG_XEN) := early-quirks.o i8253.o i8259_$(BITS).o reboot.o \ ++ smpboot_$(BITS).o tsc_$(BITS).o ++disabled-obj-$(CONFIG_XEN_UNPRIVILEGED_GUEST) += mpparse_64.o + %/head_$(BITS).o %/head_$(BITS).s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) := +--- sle11-2009-05-14.orig/arch/x86/kernel/apic_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/apic_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -43,7 +43,7 @@ int apic_verbosity; + */ + void ack_bad_irq(unsigned int irq) + { +- printk("unexpected IRQ trap at vector %02x\n", irq); ++ printk("unexpected IRQ trap at irq %02x\n", irq); + /* + * Currently unexpected vectors happen only on SMP and APIC. + * We _must_ ack these because every local APIC has only N +@@ -62,19 +62,19 @@ int setup_profiling_timer(unsigned int m + return -EINVAL; + } + +-void smp_local_timer_interrupt(struct pt_regs *regs) ++void smp_local_timer_interrupt(void) + { +- profile_tick(CPU_PROFILING, regs); ++ profile_tick(CPU_PROFILING); + #ifndef CONFIG_XEN + #ifdef CONFIG_SMP +- update_process_times(user_mode(regs)); ++ update_process_times(user_mode(get_irq_regs())); + #endif + #endif + /* + * We take the 'long' return path, and there every subsystem + * grabs the appropriate locks (kernel lock/ irq lock). + * +- * we might want to decouple profiling from the 'long path', ++ * We might want to decouple profiling from the 'long path', + * and do the profiling totally in assembly. + * + * Currently this isn't too much of an issue (performance wise), +@@ -92,6 +92,8 @@ void smp_local_timer_interrupt(struct pt + */ + void smp_apic_timer_interrupt(struct pt_regs *regs) + { ++ struct pt_regs *old_regs = set_irq_regs(regs); ++ + /* + * the NMI deadlock-detector uses this. + */ +@@ -109,8 +111,9 @@ void smp_apic_timer_interrupt(struct pt_ + */ + exit_idle(); + irq_enter(); +- smp_local_timer_interrupt(regs); ++ smp_local_timer_interrupt(); + irq_exit(); ++ set_irq_regs(old_regs); + } + + /* +@@ -188,9 +191,8 @@ int disable_apic; + int __init APIC_init_uniprocessor (void) + { + #ifdef CONFIG_X86_IO_APIC +- if (smp_found_config) +- if (!skip_ioapic_setup && nr_ioapics) +- setup_IO_APIC(); ++ if (smp_found_config && !skip_ioapic_setup && nr_ioapics) ++ setup_IO_APIC(); + #endif + + return 1; +--- sle11-2009-05-14.orig/arch/x86/kernel/e820_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/e820_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -25,6 +26,11 @@ + #include + #include + ++struct e820map e820 __initdata; ++#ifdef CONFIG_XEN ++struct e820map machine_e820 __initdata; ++#endif ++ + /* + * PFN of last memory page. + */ +@@ -41,14 +47,10 @@ unsigned long end_pfn_map; + /* + * Last pfn which the user wants to use. + */ +-unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT; ++static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; + + extern struct resource code_resource, data_resource; + +-#ifdef CONFIG_XEN +-extern struct e820map machine_e820; +-#endif +- + /* Check for some hardcoded bad areas that early boot is not allowed to touch */ + static inline int bad_addr(unsigned long *addrp, unsigned long size) + { +@@ -57,13 +59,13 @@ static inline int bad_addr(unsigned long + #ifndef CONFIG_XEN + /* various gunk below that needed for SMP startup */ + if (addr < 0x8000) { +- *addrp = 0x8000; ++ *addrp = PAGE_ALIGN(0x8000); + return 1; + } + + /* direct mapping tables of the kernel */ + if (last >= table_start<= INITRD_START && + addr < INITRD_START+INITRD_SIZE) { +- *addrp = INITRD_START + INITRD_SIZE; ++ *addrp = PAGE_ALIGN(INITRD_START + INITRD_SIZE); + return 1; + } + #endif +- /* kernel code + 640k memory hole (later should not be needed, but +- be paranoid for now) */ +- if (last >= 640*1024 && addr < 1024*1024) { +- *addrp = 1024*1024; +- return 1; +- } +- if (last >= __pa_symbol(&_text) && last < __pa_symbol(&_end)) { +- *addrp = __pa_symbol(&_end); ++ /* kernel code */ ++ if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) { ++ *addrp = PAGE_ALIGN(__pa_symbol(&_end)); + return 1; + } + + if (last >= ebda_addr && addr < ebda_addr + ebda_size) { +- *addrp = ebda_addr + ebda_size; ++ *addrp = PAGE_ALIGN(ebda_addr + ebda_size); + return 1; + } + +@@ -184,7 +181,7 @@ unsigned long __init find_e820_area(unsi + continue; + while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size) + ; +- last = addr + size; ++ last = PAGE_ALIGN(addr) + size; + if (last > ei->addr + ei->size) + continue; + if (last > end) +@@ -194,59 +191,14 @@ unsigned long __init find_e820_area(unsi + return -1UL; + } + +-/* +- * Free bootmem based on the e820 table for a node. +- */ +-void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end) +-{ +- int i; +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +- unsigned long last, addr; +- +- if (ei->type != E820_RAM || +- ei->addr+ei->size <= start || +- ei->addr >= end) +- continue; +- +- addr = round_up(ei->addr, PAGE_SIZE); +- if (addr < start) +- addr = start; +- +- last = round_down(ei->addr + ei->size, PAGE_SIZE); +- if (last >= end) +- last = end; +- +- if (last > addr && last-addr >= PAGE_SIZE) +- free_bootmem_node(pgdat, addr, last-addr); +- } +-} +- + /* + * Find the highest page frame number we have available + */ + unsigned long __init e820_end_of_ram(void) + { +- int i; + unsigned long end_pfn = 0; ++ end_pfn = find_max_pfn_with_active_regions(); + +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +- unsigned long start, end; +- +- start = round_up(ei->addr, PAGE_SIZE); +- end = round_down(ei->addr + ei->size, PAGE_SIZE); +- if (start >= end) +- continue; +- if (ei->type == E820_RAM) { +- if (end > end_pfn<>PAGE_SHIFT; +- } else { +- if (end > end_pfn_map<>PAGE_SHIFT; +- } +- } +- + if (end_pfn > end_pfn_map) + end_pfn_map = end_pfn; + if (end_pfn_map > MAXMEM>>PAGE_SHIFT) +@@ -256,43 +208,10 @@ unsigned long __init e820_end_of_ram(voi + if (end_pfn > end_pfn_map) + end_pfn = end_pfn_map; + ++ printk("end_pfn_map = %lu\n", end_pfn_map); + return end_pfn; + } + +-/* +- * Compute how much memory is missing in a range. +- * Unlike the other functions in this file the arguments are in page numbers. +- */ +-unsigned long __init +-e820_hole_size(unsigned long start_pfn, unsigned long end_pfn) +-{ +- unsigned long ram = 0; +- unsigned long start = start_pfn << PAGE_SHIFT; +- unsigned long end = end_pfn << PAGE_SHIFT; +- int i; +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +- unsigned long last, addr; +- +- if (ei->type != E820_RAM || +- ei->addr+ei->size <= start || +- ei->addr >= end) +- continue; +- +- addr = round_up(ei->addr, PAGE_SIZE); +- if (addr < start) +- addr = start; +- +- last = round_down(ei->addr + ei->size, PAGE_SIZE); +- if (last >= end) +- last = end; +- +- if (last > addr) +- ram += last - addr; +- } +- return ((end - start) - ram) >> PAGE_SHIFT; +-} +- + /* + * Mark e820 reserved areas as busy for the resource manager. + */ +@@ -333,6 +252,98 @@ void __init e820_reserve_resources(struc + } + } + ++#ifndef CONFIG_XEN ++/* Mark pages corresponding to given address range as nosave */ ++static void __init ++e820_mark_nosave_range(unsigned long start, unsigned long end) ++{ ++ unsigned long pfn, max_pfn; ++ ++ if (start >= end) ++ return; ++ ++ printk("Nosave address range: %016lx - %016lx\n", start, end); ++ max_pfn = end >> PAGE_SHIFT; ++ for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++) ++ if (pfn_valid(pfn)) ++ SetPageNosave(pfn_to_page(pfn)); ++} ++ ++/* ++ * Find the ranges of physical addresses that do not correspond to ++ * e820 RAM areas and mark the corresponding pages as nosave for software ++ * suspend and suspend to RAM. ++ * ++ * This function requires the e820 map to be sorted and without any ++ * overlapping entries and assumes the first e820 area to be RAM. ++ */ ++void __init e820_mark_nosave_regions(void) ++{ ++ int i; ++ unsigned long paddr; ++ ++ paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE); ++ for (i = 1; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ ++ if (paddr < ei->addr) ++ e820_mark_nosave_range(paddr, ++ round_up(ei->addr, PAGE_SIZE)); ++ ++ paddr = round_down(ei->addr + ei->size, PAGE_SIZE); ++ if (ei->type != E820_RAM) ++ e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE), ++ paddr); ++ ++ if (paddr >= (end_pfn << PAGE_SHIFT)) ++ break; ++ } ++} ++#endif ++ ++/* Walk the e820 map and register active regions within a node */ ++void __init ++e820_register_active_regions(int nid, unsigned long start_pfn, ++ unsigned long end_pfn) ++{ ++ int i; ++ unsigned long ei_startpfn, ei_endpfn; ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT; ++ ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) ++ >> PAGE_SHIFT; ++ ++ /* Skip map entries smaller than a page */ ++ if (ei_startpfn >= ei_endpfn) ++ continue; ++ ++ /* Check if end_pfn_map should be updated */ ++ if (ei->type != E820_RAM && ei_endpfn > end_pfn_map) ++ end_pfn_map = ei_endpfn; ++ ++ /* Skip if map is outside the node */ ++ if (ei->type != E820_RAM || ++ ei_endpfn <= start_pfn || ++ ei_startpfn >= end_pfn) ++ continue; ++ ++ /* Check for overlaps */ ++ if (ei_startpfn < start_pfn) ++ ei_startpfn = start_pfn; ++ if (ei_endpfn > end_pfn) ++ ei_endpfn = end_pfn; ++ ++ /* Obey end_user_pfn to save on memmap */ ++ if (ei_startpfn >= end_user_pfn) ++ continue; ++ if (ei_endpfn > end_user_pfn) ++ ei_endpfn = end_user_pfn; ++ ++ add_active_range(nid, ei_startpfn, ei_endpfn); ++ } ++} ++ + /* + * Add a memory region to the kernel e820 map. + */ +@@ -553,13 +564,6 @@ static int __init sanitize_e820_map(stru + * If we're lucky and live on a modern system, the setup code + * will have given us a memory map that we can use to properly + * set up memory. If we aren't, we'll fake a memory map. +- * +- * We check to see that the memory map contains at least 2 elements +- * before we'll use it, because the detection code in setup.S may +- * not be perfect and most every PC known to man has two memory +- * regions: one from 0 to 640k, and one from 1mb up. (The IBM +- * thinkpad 560x, for example, does not cooperate with the memory +- * detection code.) + */ + static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) + { +@@ -581,27 +585,6 @@ static int __init copy_e820_map(struct e + if (start > end) + return -1; + +-#ifndef CONFIG_XEN +- /* +- * Some BIOSes claim RAM in the 640k - 1M region. +- * Not right. Fix it up. +- * +- * This should be removed on Hammer which is supposed to not +- * have non e820 covered ISA mappings there, but I had some strange +- * problems so it stays for now. -AK +- */ +- if (type == E820_RAM) { +- if (start < 0x100000ULL && end > 0xA0000ULL) { +- if (start < 0xA0000ULL) +- add_memory_region(start, 0xA0000ULL-start, type); +- if (end <= 0x100000ULL) +- continue; +- start = 0x100000ULL; +- size = end - start; +- } +- } +-#endif +- + add_memory_region(start, size, type); + } while (biosmap++,--nr_map); + +@@ -622,11 +605,15 @@ static int __init copy_e820_map(struct e + return 0; + } + ++void early_panic(char *msg) ++{ ++ early_printk(msg); ++ panic(msg); ++} ++ + #ifndef CONFIG_XEN + void __init setup_memory_region(void) + { +- char *who = "BIOS-e820"; +- + /* + * Try to copy the BIOS-supplied E820-map. + * +@@ -634,24 +621,10 @@ void __init setup_memory_region(void) + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); +- if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { +- unsigned long mem_size; +- +- /* compare results from other methods and take the greater */ +- if (ALT_MEM_K < EXT_MEM_K) { +- mem_size = EXT_MEM_K; +- who = "BIOS-88"; +- } else { +- mem_size = ALT_MEM_K; +- who = "BIOS-e801"; +- } +- +- e820.nr_map = 0; +- add_memory_region(0, LOWMEMSIZE(), E820_RAM); +- add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); +- } ++ if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) ++ early_panic("Cannot find a valid memory map"); + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); +- e820_print_map(who); ++ e820_print_map("BIOS-e820"); + } + + #else /* CONFIG_XEN */ +@@ -683,20 +656,23 @@ void __init setup_memory_region(void) + + sanitize_e820_map(map, (char *)&memmap.nr_entries); + +- BUG_ON(copy_e820_map(map, (char)memmap.nr_entries) < 0); ++ if (copy_e820_map(map, (char)memmap.nr_entries) < 0) ++ early_panic("Cannot find a valid memory map"); + + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); + e820_print_map("Xen"); + } + #endif + +-void __init parse_memopt(char *p, char **from) +-{ ++static int __init parse_memopt(char *p) ++{ + int i; + unsigned long current_end; + unsigned long end; + +- end_user_pfn = memparse(p, from); ++ if (!p) ++ return -EINVAL; ++ end_user_pfn = memparse(p, &p); + end_user_pfn >>= PAGE_SHIFT; + + end = end_user_pfn<> PAGE_SHIFT); + } +- p = *from; ++ return *p == '\0' ? 0 : -EINVAL; ++} ++early_param("memmap", parse_memmap_opt); ++ ++void finish_e820_parsing(void) ++{ ++ if (userdef) { ++ printk(KERN_INFO "user-defined physical RAM map:\n"); ++ e820_print_map("user"); ++ } + } + + unsigned long pci_mem_start = 0xaeedbabe; +--- sle11-2009-05-14.orig/arch/x86/kernel/early_printk-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/early_printk-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -244,20 +244,16 @@ void early_printk(const char *fmt, ...) + + static int __initdata keep_early; + +-int __init setup_early_printk(char *opt) ++static int __init setup_early_printk(char *buf) + { +- char *space; +- char buf[256]; ++ if (!buf) ++ return 0; + + if (early_console_initialized) +- return 1; +- +- strlcpy(buf,opt,sizeof(buf)); +- space = strchr(buf, ' '); +- if (space) +- *space = 0; ++ return 0; ++ early_console_initialized = 1; + +- if (strstr(buf,"keep")) ++ if (strstr(buf, "keep")) + keep_early = 1; + + if (!strncmp(buf, "serial", 6)) { +@@ -281,11 +277,12 @@ int __init setup_early_printk(char *opt) + early_console = &simnow_console; + keep_early = 1; + } +- early_console_initialized = 1; + register_console(early_console); + return 0; + } + ++early_param("earlyprintk", setup_early_printk); ++ + void __init disable_early_printk(void) + { + if (!early_console_initialized || !early_console) +@@ -299,4 +296,3 @@ void __init disable_early_printk(void) + } + } + +-__setup("earlyprintk=", setup_early_printk); +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_64-xen.S 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/entry_64-xen.S 2009-03-04 11:28:34.000000000 +0100 +@@ -4,9 +4,6 @@ + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2000, 2001, 2002 Andi Kleen SuSE Labs + * Copyright (C) 2000 Pavel Machek +- * +- * $Id$ +- * + * Jun Nakajima + * Asit Mallick + * Modified for Xen +@@ -26,15 +23,25 @@ + * at the top of the kernel process stack. + * - partial stack frame: partially saved registers upto R11. + * - full stack frame: Like partial stack frame, but all register saved. +- * +- * TODO: +- * - schedule it carefully for the final hardware. ++ * ++ * Some macro usage: ++ * - CFI macros are used to generate dwarf2 unwind information for better ++ * backtraces. They don't change any code. ++ * - SAVE_ALL/RESTORE_ALL - Save/restore all registers ++ * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify. ++ * There are unfortunately lots of special cases where some registers ++ * not touched. The macro is a big mess that should be cleaned up. ++ * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS. ++ * Gives a full stack frame. ++ * - ENTRY/END Define functions in the symbol table. ++ * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack ++ * frame that is otherwise undefined after a SYSCALL ++ * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging. ++ * - errorentry/paranoidentry/zeroentry - Define exception entry points. + */ + +-#define ASSEMBLY 1 + #include + #include +-#include + #include + #include + #include +@@ -117,6 +124,7 @@ NMI_MASK = 0x80000000 + .macro CFI_DEFAULT_STACK start=1,adj=0 + .if \start + CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8 - \adj*ARGOFFSET + .else + CFI_DEF_CFA_OFFSET SS+8 - \adj*ARGOFFSET +@@ -207,6 +215,7 @@ END(ret_from_fork) + */ + .macro _frame ref + CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-\ref + /*CFI_REL_OFFSET ss,SS-\ref*/ + CFI_REL_OFFSET rsp,RSP-\ref +@@ -334,6 +343,8 @@ tracesys: + LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST + cmpq $__NR_syscall_max,%rax ++ movq $-ENOSYS,%rcx ++ cmova %rcx,%rax + ja 1f + movq %r10,%rcx /* fixup for C */ + call *sys_call_table(,%rax,8) +@@ -349,6 +360,7 @@ END(system_call) + */ + ENTRY(int_ret_from_sys_call) + CFI_STARTPROC simple ++ CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-ARGOFFSET + /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/ + CFI_REL_OFFSET rsp,RSP-ARGOFFSET +@@ -583,8 +595,7 @@ retint_signal: + #ifdef CONFIG_PREEMPT + /* Returning to kernel space. Check if we need preemption */ + /* rcx: threadinfo. interrupts off. */ +- .p2align +-retint_kernel: ++ENTRY(retint_kernel) + cmpl $0,threadinfo_preempt_count(%rcx) + jnz retint_restore_args + bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx) +@@ -644,7 +655,6 @@ ENTRY(call_function_interrupt) + END(call_function_interrupt) + #endif + +-#ifdef CONFIG_X86_LOCAL_APIC + ENTRY(apic_timer_interrupt) + apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt + END(apic_timer_interrupt) +@@ -656,7 +666,6 @@ END(error_interrupt) + ENTRY(spurious_interrupt) + apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt + END(spurious_interrupt) +-#endif + #endif /* !CONFIG_XEN */ + + /* +@@ -755,7 +764,9 @@ paranoid_exit\trace: + testl $3,CS(%rsp) + jnz paranoid_userspace\trace + paranoid_swapgs\trace: ++ .if \trace + TRACE_IRQS_IRETQ 0 ++ .endif + swapgs + paranoid_restore\trace: + RESTORE_ALL 8 +@@ -802,7 +813,7 @@ paranoid_schedule\trace: + * Exception entry point. This expects an error code/orig_rax on the stack + * and the exception handler in %rax. + */ +-ENTRY(error_entry) ++KPROBE_ENTRY(error_entry) + _frame RDI + CFI_REL_OFFSET rax,0 + /* rdi slot contains rax, oldrax contains error code */ +@@ -896,7 +907,7 @@ error_kernelspace: + jmp error_sti + #endif + CFI_ENDPROC +-END(error_entry) ++KPROBE_END(error_entry) + + ENTRY(hypervisor_callback) + zeroentry do_hypervisor_callback +@@ -936,26 +947,6 @@ ENTRY(do_hypervisor_callback) # do_hyp + CFI_ENDPROC + END(do_hypervisor_callback) + +-#ifdef CONFIG_X86_LOCAL_APIC +-KPROBE_ENTRY(nmi) +- zeroentry do_nmi_callback +-ENTRY(do_nmi_callback) +- CFI_STARTPROC +- addq $8, %rsp +- CFI_ENDPROC +- CFI_DEFAULT_STACK +- call do_nmi +- orl $NMI_MASK,EFLAGS(%rsp) +- RESTORE_REST +- XEN_BLOCK_EVENTS(%rsi) +- TRACE_IRQS_OFF +- GET_THREAD_INFO(%rcx) +- jmp retint_restore_args +- CFI_ENDPROC +- .previous .text +-END(nmi) +-#endif +- + ALIGN + restore_all_enable_events: + CFI_DEFAULT_STACK adj=1 +@@ -1121,7 +1112,7 @@ ENDPROC(child_rip) + * do_sys_execve asm fallback arguments: + * rdi: name, rsi: argv, rdx: envp, fake frame on the stack + */ +-ENTRY(execve) ++ENTRY(kernel_execve) + CFI_STARTPROC + FAKE_STACK_FRAME $0 + SAVE_ALL +@@ -1135,12 +1126,11 @@ ENTRY(execve) + UNFAKE_STACK_FRAME + ret + CFI_ENDPROC +-ENDPROC(execve) ++ENDPROC(kernel_execve) + + KPROBE_ENTRY(page_fault) + errorentry do_page_fault +-END(page_fault) +- .previous .text ++KPROBE_END(page_fault) + + ENTRY(coprocessor_error) + zeroentry do_coprocessor_error +@@ -1162,25 +1152,25 @@ KPROBE_ENTRY(debug) + zeroentry do_debug + /* paranoidexit + CFI_ENDPROC */ +-END(debug) +- .previous .text ++KPROBE_END(debug) + +-#if 0 +- /* runs on exception stack */ + KPROBE_ENTRY(nmi) +- INTR_FRAME +- pushq $-1 +- CFI_ADJUST_CFA_OFFSET 8 +- paranoidentry do_nmi, 0, 0 +-#ifdef CONFIG_TRACE_IRQFLAGS +- paranoidexit 0 +-#else +- jmp paranoid_exit1 +- CFI_ENDPROC +-#endif +-END(nmi) +- .previous .text +-#endif ++ zeroentry do_nmi_callback ++KPROBE_END(nmi) ++do_nmi_callback: ++ CFI_STARTPROC ++ addq $8, %rsp ++ CFI_ENDPROC ++ CFI_DEFAULT_STACK ++ call do_nmi ++ orl $NMI_MASK,EFLAGS(%rsp) ++ RESTORE_REST ++ XEN_BLOCK_EVENTS(%rsi) ++ TRACE_IRQS_OFF ++ GET_THREAD_INFO(%rcx) ++ jmp retint_restore_args ++ CFI_ENDPROC ++END(do_nmi_callback) + + KPROBE_ENTRY(int3) + /* INTR_FRAME +@@ -1189,8 +1179,7 @@ KPROBE_ENTRY(int3) + zeroentry do_int3 + /* jmp paranoid_exit1 + CFI_ENDPROC */ +-END(int3) +- .previous .text ++KPROBE_END(int3) + + ENTRY(overflow) + zeroentry do_overflow +@@ -1241,8 +1230,7 @@ END(stack_segment) + + KPROBE_ENTRY(general_protection) + errorentry do_general_protection +-END(general_protection) +- .previous .text ++KPROBE_END(general_protection) + + ENTRY(alignment_check) + errorentry do_alignment_check +--- sle11-2009-05-14.orig/arch/x86/kernel/genapic_xen_64.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/genapic_xen_64.c 2009-03-04 11:28:34.000000000 +0100 +@@ -71,6 +71,13 @@ static cpumask_t xen_target_cpus(void) + return cpu_online_map; + } + ++static cpumask_t xen_vector_allocation_domain(int cpu) ++{ ++ cpumask_t domain = CPU_MASK_NONE; ++ cpu_set(cpu, domain); ++ return domain; ++} ++ + /* + * Set up the logical destination ID. + * Do nothing, not called now. +@@ -147,8 +154,8 @@ struct genapic apic_xen = { + .int_delivery_mode = dest_LowestPrio, + #endif + .int_dest_mode = (APIC_DEST_LOGICAL != 0), +- .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST, + .target_cpus = xen_target_cpus, ++ .vector_allocation_domain = xen_vector_allocation_domain, + #ifdef CONFIG_XEN_PRIVILEGED_GUEST + .apic_id_registered = xen_apic_id_registered, + #endif +--- sle11-2009-05-14.orig/arch/x86/kernel/head_64-xen.S 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/head_64-xen.S 2009-03-04 11:28:34.000000000 +0100 +@@ -5,9 +5,6 @@ + * Copyright (C) 2000 Pavel Machek + * Copyright (C) 2000 Karsten Keil + * Copyright (C) 2001,2002 Andi Kleen +- * +- * $Id: head.S,v 1.49 2002/03/19 17:39:25 ak Exp $ +- * + * Jun Nakajima + * Modified for Xen + */ +@@ -149,7 +146,7 @@ ENTRY(cpu_gdt_table) + .quad 0,0 /* TSS */ + .quad 0,0 /* LDT */ + .quad 0,0,0 /* three TLS descriptors */ +- .quad 0 /* unused */ ++ .quad 0x0000f40000000000 /* node/CPU stored in limit */ + gdt_end: + /* asm/segment.h:GDT_ENTRIES must match this */ + /* This should be a multiple of the cache line size */ +--- sle11-2009-05-14.orig/arch/x86/kernel/head64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/head64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -7,6 +7,9 @@ + * Modified for Xen. + */ + ++/* PDA is not ready to be used until the end of x86_64_start_kernel(). */ ++#define arch_use_lazy_mmu_mode() false ++ + #include + #include + #include +@@ -54,11 +57,9 @@ static void __init copy_bootdata(char *r + new_data = *(int *) (x86_boot_params + NEW_CL_POINTER); + if (!new_data) { + if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) { +- printk("so old bootloader that it does not support commandline?!\n"); + return; + } + new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET; +- printk("old bootloader convention, maybe loadlin?\n"); + } + command_line = (char *) ((u64)(new_data)); + memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); +@@ -70,25 +71,6 @@ static void __init copy_bootdata(char *r + memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline); + saved_command_line[max_cmdline-1] = '\0'; + #endif +- printk("Bootdata ok (command line is %s)\n", saved_command_line); +-} +- +-static void __init setup_boot_cpu_data(void) +-{ +- unsigned int dummy, eax; +- +- /* get vendor info */ +- cpuid(0, (unsigned int *)&boot_cpu_data.cpuid_level, +- (unsigned int *)&boot_cpu_data.x86_vendor_id[0], +- (unsigned int *)&boot_cpu_data.x86_vendor_id[8], +- (unsigned int *)&boot_cpu_data.x86_vendor_id[4]); +- +- /* get cpu type */ +- cpuid(1, &eax, &dummy, &dummy, +- (unsigned int *) &boot_cpu_data.x86_capability); +- boot_cpu_data.x86 = (eax >> 8) & 0xf; +- boot_cpu_data.x86_model = (eax >> 4) & 0xf; +- boot_cpu_data.x86_mask = eax & 0xf; + } + + #include +@@ -101,7 +83,6 @@ void __init x86_64_start_kernel(char * r + { + struct xen_machphys_mapping mapping; + unsigned long machine_to_phys_nr_ents; +- char *s; + int i; + + setup_xen_features(); +@@ -128,10 +109,7 @@ void __init x86_64_start_kernel(char * r + asm volatile("lidt %0" :: "m" (idt_descr)); + #endif + +- /* +- * This must be called really, really early: +- */ +- lockdep_init(); ++ early_printk("Kernel alive\n"); + + for (i = 0; i < NR_CPUS; i++) + cpu_pda(i) = &boot_cpu_pda[i]; +@@ -141,22 +119,5 @@ void __init x86_64_start_kernel(char * r + #ifdef CONFIG_SMP + cpu_set(0, cpu_online_map); + #endif +- s = strstr(saved_command_line, "earlyprintk="); +- if (s != NULL) +- setup_early_printk(strchr(s, '=') + 1); +-#ifdef CONFIG_NUMA +- s = strstr(saved_command_line, "numa="); +- if (s != NULL) +- numa_setup(s+5); +-#endif +-#ifdef CONFIG_X86_IO_APIC +- if (strstr(saved_command_line, "disableapic")) +- disable_apic = 1; +-#endif +- /* You need early console to see that */ +- if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE) +- panic("Kernel too big for kernel mapping\n"); +- +- setup_boot_cpu_data(); + start_kernel(); + } +--- sle11-2009-05-14.orig/arch/x86/kernel/io_apic_64-xen.c 2009-03-16 16:13:45.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/io_apic_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -26,9 +26,12 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include ++#include + #ifdef CONFIG_ACPI + #include + #endif +@@ -41,6 +44,10 @@ + #include + #include + #include ++#include ++#include ++ ++static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result); + + #define __apicdebuginit __init + +@@ -48,17 +55,30 @@ int sis_apic_bug; /* not actually suppor + + static int no_timer_check; + +-int disable_timer_pin_1 __initdata; ++static int disable_timer_pin_1 __initdata; + +-#ifndef CONFIG_XEN +-int timer_over_8254 __initdata = 0; ++#ifdef CONFIG_XEN ++#include ++#include ++#include ++ ++/* Fake i8259 */ ++#define make_8259A_irq(_irq) (io_apic_irqs &= ~(1UL<<(_irq))) ++#define disable_8259A_irq(_irq) ((void)0) ++#define i8259A_irq_pending(_irq) (0) ++ ++unsigned long io_apic_irqs; ++ ++#define clear_IO_APIC() ((void)0) ++#else ++int timer_over_8254 __initdata = 1; + + /* Where if anywhere is the i8259 connect in external int mode */ + static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; + #endif + + static DEFINE_SPINLOCK(ioapic_lock); +-static DEFINE_SPINLOCK(vector_lock); ++DEFINE_SPINLOCK(vector_lock); + + /* + * # of IRQ routing registers +@@ -83,29 +103,27 @@ static struct irq_pin_list { + short apic, pin, next; + } irq_2_pin[PIN_MAP_SIZE]; + +-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; +-#ifdef CONFIG_PCI_MSI +-#define vector_to_irq(vector) \ +- (platform_legacy_irq(vector) ? vector : vector_irq[vector]) +-#else +-#define vector_to_irq(vector) (vector) +-#endif +- +-#ifdef CONFIG_XEN +- +-#include +-#include +-#include +- +-/* Fake i8259 */ +-#define make_8259A_irq(_irq) (io_apic_irqs &= ~(1UL<<(_irq))) +-#define disable_8259A_irq(_irq) ((void)0) +-#define i8259A_irq_pending(_irq) (0) ++#ifndef CONFIG_XEN ++struct io_apic { ++ unsigned int index; ++ unsigned int unused[3]; ++ unsigned int data; ++}; + +-unsigned long io_apic_irqs; ++static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) ++{ ++ return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx) ++ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK); ++} ++#endif + +-static inline unsigned int xen_io_apic_read(unsigned int apic, unsigned int reg) ++static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg) + { ++#ifndef CONFIG_XEN ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ return readl(&io_apic->data); ++#else + struct physdev_apic apic_op; + int ret; + +@@ -115,31 +133,133 @@ static inline unsigned int xen_io_apic_r + if (ret) + return ret; + return apic_op.value; ++#endif + } + +-static inline void xen_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) ++static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value) + { ++#ifndef CONFIG_XEN ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(reg, &io_apic->index); ++ writel(value, &io_apic->data); ++#else + struct physdev_apic apic_op; + + apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr; + apic_op.reg = reg; + apic_op.value = value; + WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op)); ++#endif ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * Re-write a value: to be used for read-modify-write ++ * cycles where the read already set up the index register. ++ */ ++static inline void io_apic_modify(unsigned int apic, unsigned int value) ++{ ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ writel(value, &io_apic->data); + } ++#else ++#define io_apic_modify io_apic_write ++#endif + +-#define io_apic_read(a,r) xen_io_apic_read(a,r) +-#define io_apic_write(a,r,v) xen_io_apic_write(a,r,v) ++/* ++ * Synchronize the IO-APIC and the CPU by doing ++ * a dummy read from the IO-APIC ++ */ ++static inline void io_apic_sync(unsigned int apic) ++{ ++#ifndef CONFIG_XEN ++ struct io_apic __iomem *io_apic = io_apic_base(apic); ++ readl(&io_apic->data); ++#endif ++} + +-#define clear_IO_APIC() ((void)0) ++union entry_union { ++ struct { u32 w1, w2; }; ++ struct IO_APIC_route_entry entry; ++}; + +-#else ++#ifndef CONFIG_XEN ++static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) ++{ ++ union entry_union eu; ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ eu.w1 = io_apic_read(apic, 0x10 + 2 * pin); ++ eu.w2 = io_apic_read(apic, 0x11 + 2 * pin); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ return eu.entry; ++} ++#endif ++ ++/* ++ * When we write a new IO APIC routing entry, we need to write the high ++ * word first! If the mask bit in the low word is clear, we will enable ++ * the interrupt, and we need to make sure the entry is fully populated ++ * before that happens. ++ */ ++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ unsigned long flags; ++ union entry_union eu; ++ eu.entry = e; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} ++ ++#ifndef CONFIG_XEN ++/* ++ * When we mask an IO APIC routing entry, we need to write the low ++ * word first, in order to set the mask bit before we change the ++ * high bits! ++ */ ++static void ioapic_mask_entry(int apic, int pin) ++{ ++ unsigned long flags; ++ union entry_union eu = { .entry.mask = 1 }; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++ io_apic_write(apic, 0x11 + 2*pin, eu.w2); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++} + + #ifdef CONFIG_SMP ++static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) ++{ ++ int apic, pin; ++ struct irq_pin_list *entry = irq_2_pin + irq; ++ ++ BUG_ON(irq >= NR_IRQS); ++ for (;;) { ++ unsigned int reg; ++ apic = entry->apic; ++ pin = entry->pin; ++ if (pin == -1) ++ break; ++ io_apic_write(apic, 0x11 + pin*2, dest); ++ reg = io_apic_read(apic, 0x10 + pin*2); ++ reg &= ~0x000000ff; ++ reg |= vector; ++ io_apic_modify(apic, reg); ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++} ++ + static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) + { + unsigned long flags; + unsigned int dest; + cpumask_t tmp; ++ int vector; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) +@@ -147,7 +267,11 @@ static void set_ioapic_affinity_irq(unsi + + cpus_and(mask, tmp, CPU_MASK_ALL); + +- dest = cpu_mask_to_apicid(mask); ++ vector = assign_irq_vector(irq, mask, &tmp); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(tmp); + + /* + * Only the high 8 bits are valid. +@@ -155,13 +279,12 @@ static void set_ioapic_affinity_irq(unsi + dest = SET_APIC_LOGICAL_ID(dest); + + spin_lock_irqsave(&ioapic_lock, flags); +- __DO_ACTION(1, = dest, ) +- set_irq_info(irq, mask); ++ __target_IO_APIC_irq(irq, dest, vector); ++ set_native_irq_info(irq, mask); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + #endif +- +-#endif /* !CONFIG_XEN */ ++#endif + + /* + * The common case is 1:1 IRQ<->pin mappings. Sometimes there are +@@ -241,24 +364,15 @@ static void unmask_IO_APIC_irq (unsigned + static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) + { + struct IO_APIC_route_entry entry; +- unsigned long flags; + + /* Check delivery_mode to be sure we're not clearing an SMI pin */ +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); +- *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ entry = ioapic_read_entry(apic, pin); + if (entry.delivery_mode == dest_SMI) + return; + /* + * Disable it in the IO-APIC irq-routing table: + */ +- memset(&entry, 0, sizeof(entry)); +- entry.mask = 1; +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); +- io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_mask_entry(apic, pin); + } + + static void clear_IO_APIC (void) +@@ -272,16 +386,6 @@ static void clear_IO_APIC (void) + + #endif /* !CONFIG_XEN */ + +-static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF }; +- +-/* +- * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to +- * specific CPU-side IRQs. +- */ +- +-#define MAX_PIRQS 8 +-static int pirq_entries [MAX_PIRQS]; +-static int pirqs_enabled; + int skip_ioapic_setup; + int ioapic_force; + +@@ -290,18 +394,17 @@ int ioapic_force; + static int __init disable_ioapic_setup(char *str) + { + skip_ioapic_setup = 1; +- return 1; ++ return 0; + } ++early_param("noapic", disable_ioapic_setup); + +-static int __init enable_ioapic_setup(char *str) ++/* Actually the next is obsolete, but keep it for paranoid reasons -AK */ ++static int __init disable_timer_pin_setup(char *arg) + { +- ioapic_force = 1; +- skip_ioapic_setup = 0; ++ disable_timer_pin_1 = 1; + return 1; + } +- +-__setup("noapic", disable_ioapic_setup); +-__setup("apic", enable_ioapic_setup); ++__setup("disable_timer_pin_1", disable_timer_pin_setup); + + #ifndef CONFIG_XEN + static int __init setup_disable_8254_timer(char *s) +@@ -319,137 +422,6 @@ __setup("disable_8254_timer", setup_disa + __setup("enable_8254_timer", setup_enable_8254_timer); + #endif /* !CONFIG_XEN */ + +-#include +-#include +-#include +- +- +-#ifdef CONFIG_ACPI +- +-static int nvidia_hpet_detected __initdata; +- +-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) +-{ +- nvidia_hpet_detected = 1; +- return 0; +-} +-#endif +- +-/* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC +- off. Check for an Nvidia or VIA PCI bridge and turn it off. +- Use pci direct infrastructure because this runs before the PCI subsystem. +- +- Can be overwritten with "apic" +- +- And another hack to disable the IOMMU on VIA chipsets. +- +- ... and others. Really should move this somewhere else. +- +- Kludge-O-Rama. */ +-void __init check_ioapic(void) +-{ +- int num,slot,func; +- /* Poor man's PCI discovery */ +- for (num = 0; num < 32; num++) { +- for (slot = 0; slot < 32; slot++) { +- for (func = 0; func < 8; func++) { +- u32 class; +- u32 vendor; +- u8 type; +- class = read_pci_config(num,slot,func, +- PCI_CLASS_REVISION); +- if (class == 0xffffffff) +- break; +- +- if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) +- continue; +- +- vendor = read_pci_config(num, slot, func, +- PCI_VENDOR_ID); +- vendor &= 0xffff; +- switch (vendor) { +- case PCI_VENDOR_ID_VIA: +-#ifdef CONFIG_IOMMU +- if ((end_pfn > MAX_DMA32_PFN || +- force_iommu) && +- !iommu_aperture_allowed) { +- printk(KERN_INFO +- "Looks like a VIA chipset. Disabling IOMMU. Override with \"iommu=allowed\"\n"); +- iommu_aperture_disabled = 1; +- } +-#endif +- return; +- case PCI_VENDOR_ID_NVIDIA: +-#ifdef CONFIG_ACPI +- /* +- * All timer overrides on Nvidia are +- * wrong unless HPET is enabled. +- */ +- nvidia_hpet_detected = 0; +- acpi_table_parse(ACPI_HPET, +- nvidia_hpet_check); +- if (nvidia_hpet_detected == 0) { +- acpi_skip_timer_override = 1; +- printk(KERN_INFO "Nvidia board " +- "detected. Ignoring ACPI " +- "timer override.\n"); +- } +-#endif +- /* RED-PEN skip them on mptables too? */ +- return; +- case PCI_VENDOR_ID_ATI: +- +- /* This should be actually default, but +- for 2.6.16 let's do it for ATI only where +- it's really needed. */ +-#ifndef CONFIG_XEN +- if (timer_over_8254 == 1) { +- timer_over_8254 = 0; +- printk(KERN_INFO +- "ATI board detected. Disabling timer routing over 8254.\n"); +- } +-#endif +- return; +- } +- +- +- /* No multi-function device? */ +- type = read_pci_config_byte(num,slot,func, +- PCI_HEADER_TYPE); +- if (!(type & 0x80)) +- break; +- } +- } +- } +-} +- +-static int __init ioapic_pirq_setup(char *str) +-{ +- int i, max; +- int ints[MAX_PIRQS+1]; +- +- get_options(str, ARRAY_SIZE(ints), ints); +- +- for (i = 0; i < MAX_PIRQS; i++) +- pirq_entries[i] = -1; +- +- pirqs_enabled = 1; +- apic_printk(APIC_VERBOSE, "PIRQ redirection, working around broken MP-BIOS.\n"); +- max = MAX_PIRQS; +- if (ints[0] < MAX_PIRQS) +- max = ints[0]; +- +- for (i = 0; i < max; i++) { +- apic_printk(APIC_VERBOSE, "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); +- /* +- * PIRQs are mapped upside down, usually. +- */ +- pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; +- } +- return 1; +-} +- +-__setup("pirq=", ioapic_pirq_setup); + + /* + * Find the IRQ entry number of a certain pin. +@@ -479,9 +451,7 @@ static int __init find_isa_irq_pin(int i + for (i = 0; i < mp_irq_entries; i++) { + int lbus = mp_irqs[i].mpc_srcbus; + +- if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || +- mp_bus_id_to_type[lbus] == MP_BUS_EISA || +- mp_bus_id_to_type[lbus] == MP_BUS_MCA) && ++ if (test_bit(lbus, mp_bus_not_pci) && + (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_srcbusirq == irq)) + +@@ -497,9 +467,7 @@ static int __init find_isa_irq_apic(int + for (i = 0; i < mp_irq_entries; i++) { + int lbus = mp_irqs[i].mpc_srcbus; + +- if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || +- mp_bus_id_to_type[lbus] == MP_BUS_EISA || +- mp_bus_id_to_type[lbus] == MP_BUS_MCA) && ++ if (test_bit(lbus, mp_bus_not_pci) && + (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_srcbusirq == irq)) + break; +@@ -540,7 +508,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, + mp_irqs[i].mpc_dstapic == MP_APIC_ALL) + break; + +- if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && ++ if (!test_bit(lbus, mp_bus_not_pci) && + !mp_irqs[i].mpc_irqtype && + (bus == lbus) && + (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { +@@ -563,27 +531,6 @@ int IO_APIC_get_PCI_irq_vector(int bus, + return best_guess; + } + +-/* +- * EISA Edge/Level control register, ELCR +- */ +-static int EISA_ELCR(unsigned int irq) +-{ +- if (irq < 16) { +- unsigned int port = 0x4d0 + (irq >> 3); +- return (inb(port) >> (irq & 7)) & 1; +- } +- apic_printk(APIC_VERBOSE, "Broken MPtable reports ISA irq %d\n", irq); +- return 0; +-} +- +-/* EISA interrupts are always polarity zero and can be edge or level +- * trigger depending on the ELCR value. If an interrupt is listed as +- * EISA conforming in the MP table, that means its trigger type must +- * be read in from the ELCR */ +- +-#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq)) +-#define default_EISA_polarity(idx) (0) +- + /* ISA interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ + +@@ -596,12 +543,6 @@ static int EISA_ELCR(unsigned int irq) + #define default_PCI_trigger(idx) (1) + #define default_PCI_polarity(idx) (1) + +-/* MCA interrupts are always polarity zero level triggered, +- * when listed as conforming in the MP table. */ +- +-#define default_MCA_trigger(idx) (1) +-#define default_MCA_polarity(idx) (0) +- + static int __init MPBIOS_polarity(int idx) + { + int bus = mp_irqs[idx].mpc_srcbus; +@@ -613,38 +554,11 @@ static int __init MPBIOS_polarity(int id + switch (mp_irqs[idx].mpc_irqflag & 3) + { + case 0: /* conforms, ie. bus-type dependent polarity */ +- { +- switch (mp_bus_id_to_type[bus]) +- { +- case MP_BUS_ISA: /* ISA pin */ +- { +- polarity = default_ISA_polarity(idx); +- break; +- } +- case MP_BUS_EISA: /* EISA pin */ +- { +- polarity = default_EISA_polarity(idx); +- break; +- } +- case MP_BUS_PCI: /* PCI pin */ +- { +- polarity = default_PCI_polarity(idx); +- break; +- } +- case MP_BUS_MCA: /* MCA pin */ +- { +- polarity = default_MCA_polarity(idx); +- break; +- } +- default: +- { +- printk(KERN_WARNING "broken BIOS!!\n"); +- polarity = 1; +- break; +- } +- } ++ if (test_bit(bus, mp_bus_not_pci)) ++ polarity = default_ISA_polarity(idx); ++ else ++ polarity = default_PCI_polarity(idx); + break; +- } + case 1: /* high active */ + { + polarity = 0; +@@ -682,38 +596,11 @@ static int MPBIOS_trigger(int idx) + switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) + { + case 0: /* conforms, ie. bus-type dependent */ +- { +- switch (mp_bus_id_to_type[bus]) +- { +- case MP_BUS_ISA: /* ISA pin */ +- { +- trigger = default_ISA_trigger(idx); +- break; +- } +- case MP_BUS_EISA: /* EISA pin */ +- { +- trigger = default_EISA_trigger(idx); +- break; +- } +- case MP_BUS_PCI: /* PCI pin */ +- { +- trigger = default_PCI_trigger(idx); +- break; +- } +- case MP_BUS_MCA: /* MCA pin */ +- { +- trigger = default_MCA_trigger(idx); +- break; +- } +- default: +- { +- printk(KERN_WARNING "broken BIOS!!\n"); +- trigger = 1; +- break; +- } +- } ++ if (test_bit(bus, mp_bus_not_pci)) ++ trigger = default_ISA_trigger(idx); ++ else ++ trigger = default_PCI_trigger(idx); + break; +- } + case 1: /* edge */ + { + trigger = 0; +@@ -750,64 +637,6 @@ static inline int irq_trigger(int idx) + return MPBIOS_trigger(idx); + } + +-static int next_irq = 16; +- +-/* +- * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ +- * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number +- * from ACPI, which can reach 800 in large boxen. +- * +- * Compact the sparse GSI space into a sequential IRQ series and reuse +- * vectors if possible. +- */ +-int gsi_irq_sharing(int gsi) +-{ +- int i, tries, vector; +- +- BUG_ON(gsi >= NR_IRQ_VECTORS); +- +- if (platform_legacy_irq(gsi)) +- return gsi; +- +- if (gsi_2_irq[gsi] != 0xFF) +- return (int)gsi_2_irq[gsi]; +- +- tries = NR_IRQS; +- try_again: +- vector = assign_irq_vector(gsi); +- +- /* +- * Sharing vectors means sharing IRQs, so scan irq_vectors for previous +- * use of vector and if found, return that IRQ. However, we never want +- * to share legacy IRQs, which usually have a different trigger mode +- * than PCI. +- */ +- for (i = 0; i < NR_IRQS; i++) +- if (IO_APIC_VECTOR(i) == vector) +- break; +- if (platform_legacy_irq(i)) { +- if (--tries >= 0) { +- IO_APIC_VECTOR(i) = 0; +- goto try_again; +- } +- panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi); +- } +- if (i < NR_IRQS) { +- gsi_2_irq[gsi] = i; +- printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n", +- gsi, vector, i); +- return i; +- } +- +- i = next_irq++; +- BUG_ON(i >= NR_IRQS); +- gsi_2_irq[gsi] = i; +- IO_APIC_VECTOR(i) = vector; +- printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n", +- gsi, vector, i); +- return i; +-} +- + static int pin_2_irq(int idx, int apic, int pin) + { + int irq, i; +@@ -819,49 +648,16 @@ static int pin_2_irq(int idx, int apic, + if (mp_irqs[idx].mpc_dstirq != pin) + printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); + +- switch (mp_bus_id_to_type[bus]) +- { +- case MP_BUS_ISA: /* ISA pin */ +- case MP_BUS_EISA: +- case MP_BUS_MCA: +- { +- irq = mp_irqs[idx].mpc_srcbusirq; +- break; +- } +- case MP_BUS_PCI: /* PCI pin */ +- { +- /* +- * PCI IRQs are mapped in order +- */ +- i = irq = 0; +- while (i < apic) +- irq += nr_ioapic_registers[i++]; +- irq += pin; +- irq = gsi_irq_sharing(irq); +- break; +- } +- default: +- { +- printk(KERN_ERR "unknown bus type %d.\n",bus); +- irq = 0; +- break; +- } +- } +- BUG_ON(irq >= NR_IRQS); +- +- /* +- * PCI IRQ command line redirection. Yes, limits are hardcoded. +- */ +- if ((pin >= 16) && (pin <= 23)) { +- if (pirq_entries[pin-16] != -1) { +- if (!pirq_entries[pin-16]) { +- apic_printk(APIC_VERBOSE, "disabling PIRQ%d\n", pin-16); +- } else { +- irq = pirq_entries[pin-16]; +- apic_printk(APIC_VERBOSE, "using PIRQ%d -> IRQ %d\n", +- pin-16, irq); +- } +- } ++ if (test_bit(bus, mp_bus_not_pci)) { ++ irq = mp_irqs[idx].mpc_srcbusirq; ++ } else { ++ /* ++ * PCI IRQs are mapped in order ++ */ ++ i = irq = 0; ++ while (i < apic) ++ irq += nr_ioapic_registers[i++]; ++ irq += pin; + } + BUG_ON(irq >= NR_IRQS); + return irq; +@@ -885,46 +681,71 @@ static inline int IO_APIC_irq_trigger(in + } + + /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ +-u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; ++static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; + +-int assign_irq_vector(int irq) ++static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) + { +- unsigned long flags; + int vector; + struct physdev_irq irq_op; + +- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); ++ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); + + if (irq < PIRQ_BASE || irq - PIRQ_BASE >= NR_PIRQS) + return -EINVAL; + +- spin_lock_irqsave(&vector_lock, flags); ++ cpus_and(*result, mask, cpu_online_map); + +- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { +- spin_unlock_irqrestore(&vector_lock, flags); +- return IO_APIC_VECTOR(irq); +- } ++ if (irq_vector[irq] > 0) ++ return irq_vector[irq]; + + irq_op.irq = irq; +- if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) { +- spin_unlock_irqrestore(&vector_lock, flags); ++ if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) + return -ENOSPC; +- } + + vector = irq_op.vector; +- vector_irq[vector] = irq; +- if (irq != AUTO_ASSIGN) +- IO_APIC_VECTOR(irq) = vector; ++ irq_vector[irq] = vector; + +- spin_unlock_irqrestore(&vector_lock, flags); ++ return vector; ++} ++ ++static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) ++{ ++ int vector; ++ unsigned long flags; + ++ spin_lock_irqsave(&vector_lock, flags); ++ vector = __assign_irq_vector(irq, mask, result); ++ spin_unlock_irqrestore(&vector_lock, flags); + return vector; + } + +-extern void (*interrupt[NR_IRQS])(void); + #ifndef CONFIG_XEN +-static struct hw_interrupt_type ioapic_level_type; +-static struct hw_interrupt_type ioapic_edge_type; ++void __setup_vector_irq(int cpu) ++{ ++ /* Initialize vector_irq on a new cpu */ ++ /* This function must be called with vector_lock held */ ++ int irq, vector; ++ ++ /* Mark the inuse vectors */ ++ for (irq = 0; irq < NR_IRQ_VECTORS; ++irq) { ++ if (!cpu_isset(cpu, irq_domain[irq])) ++ continue; ++ vector = irq_vector[irq]; ++ per_cpu(vector_irq, cpu)[vector] = irq; ++ } ++ /* Mark the free vectors */ ++ for (vector = 0; vector < NR_VECTORS; ++vector) { ++ irq = per_cpu(vector_irq, cpu)[vector]; ++ if (irq < 0) ++ continue; ++ if (!cpu_isset(cpu, irq_domain[irq])) ++ per_cpu(vector_irq, cpu)[vector] = -1; ++ } ++} ++ ++extern void (*interrupt[NR_IRQS])(void); ++ ++static struct irq_chip ioapic_chip; + + #define IOAPIC_AUTO -1 + #define IOAPIC_EDGE 0 +@@ -932,16 +753,15 @@ static struct hw_interrupt_type ioapic_e + + static void ioapic_register_intr(int irq, int vector, unsigned long trigger) + { +- unsigned idx; +- +- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; +- + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) +- irq_desc[idx].chip = &ioapic_level_type; +- else +- irq_desc[idx].chip = &ioapic_edge_type; +- set_intr_gate(vector, interrupt[idx]); ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_fasteoi_irq, "fasteoi"); ++ else { ++ irq_desc[irq].status |= IRQ_DELAYED_DISABLE; ++ set_irq_chip_and_handler_name(irq, &ioapic_chip, ++ handle_edge_irq, "edge"); ++ } + } + #else + #define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq) +@@ -994,16 +814,21 @@ static void __init setup_IO_APIC_irqs(vo + continue; + + if (IO_APIC_IRQ(irq)) { +- vector = assign_irq_vector(irq); ++ cpumask_t mask; ++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask); ++ if (vector < 0) ++ continue; ++ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); + entry.vector = vector; + + ioapic_register_intr(irq, vector, IOAPIC_AUTO); + if (!apic && (irq < 16)) + disable_8259A_irq(irq); + } ++ ioapic_write_entry(apic, pin, entry); ++ + spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); +- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); + set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + } +@@ -1046,7 +871,7 @@ static void __init setup_ExtINT_IRQ0_pin + * The timer IRQ doesn't have to know that behind the + * scene we have a 8259A-master in AEOI mode ... + */ +- irq_desc[0].chip = &ioapic_edge_type; ++ set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge"); + + /* + * Add it to the IO-APIC irq-routing table: +@@ -1142,10 +967,7 @@ void __apicdebuginit print_IO_APIC(void) + for (i = 0; i <= reg_01.bits.entries; i++) { + struct IO_APIC_route_entry entry; + +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2); +- *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ entry = ioapic_read_entry(apic, i); + + printk(KERN_DEBUG " %02x %03X %02X ", + i, +@@ -1165,17 +987,12 @@ void __apicdebuginit print_IO_APIC(void) + ); + } + } +- if (use_pci_vector()) +- printk(KERN_INFO "Using vector-based indexing\n"); + printk(KERN_DEBUG "IRQ to pin mappings:\n"); + for (i = 0; i < NR_IRQS; i++) { + struct irq_pin_list *entry = irq_2_pin + i; + if (entry->pin < 0) + continue; +- if (use_pci_vector() && !platform_legacy_irq(i)) +- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); +- else +- printk(KERN_DEBUG "IRQ%d ", i); ++ printk(KERN_DEBUG "IRQ%d ", i); + for (;;) { + printk("-> %d:%d", entry->apic, entry->pin); + if (!entry->next) +@@ -1339,9 +1156,6 @@ static void __init enable_IO_APIC(void) + irq_2_pin[i].pin = -1; + irq_2_pin[i].next = 0; + } +- if (!pirqs_enabled) +- for (i = 0; i < MAX_PIRQS; i++) +- pirq_entries[i] = -1; + + /* + * The number of IO-APIC IRQ registers (== #pins): +@@ -1358,11 +1172,7 @@ static void __init enable_IO_APIC(void) + /* See if any of the pins is in ExtINT mode */ + for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { + struct IO_APIC_route_entry entry; +- spin_lock_irqsave(&ioapic_lock, flags); +- *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); +- *(((int *)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); +- spin_unlock_irqrestore(&ioapic_lock, flags); +- ++ entry = ioapic_read_entry(apic, pin); + + /* If the interrupt line is enabled and in ExtInt mode + * I have found the pin where the i8259 is connected. +@@ -1416,7 +1226,6 @@ void disable_IO_APIC(void) + */ + if (ioapic_i8259.pin != -1) { + struct IO_APIC_route_entry entry; +- unsigned long flags; + + memset(&entry, 0, sizeof(entry)); + entry.mask = 0; /* Enabled */ +@@ -1433,12 +1242,7 @@ void disable_IO_APIC(void) + /* + * Add it to the IO-APIC irq-routing table: + */ +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin, +- *(((int *)&entry)+1)); +- io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin, +- *(((int *)&entry)+0)); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); + } + + disconnect_bsp_APIC(ioapic_i8259.pin != -1); +@@ -1446,76 +1250,6 @@ void disable_IO_APIC(void) + } + + /* +- * function to set the IO-APIC physical IDs based on the +- * values stored in the MPC table. +- * +- * by Matt Domsch Tue Dec 21 12:25:05 CST 1999 +- */ +- +-#ifndef CONFIG_XEN +-static void __init setup_ioapic_ids_from_mpc (void) +-{ +- union IO_APIC_reg_00 reg_00; +- int apic; +- int i; +- unsigned char old_id; +- unsigned long flags; +- +- /* +- * Set the IOAPIC ID to the value stored in the MPC table. +- */ +- for (apic = 0; apic < nr_ioapics; apic++) { +- +- /* Read the register 0 value */ +- spin_lock_irqsave(&ioapic_lock, flags); +- reg_00.raw = io_apic_read(apic, 0); +- spin_unlock_irqrestore(&ioapic_lock, flags); +- +- old_id = mp_ioapics[apic].mpc_apicid; +- +- +- printk(KERN_INFO "Using IO-APIC %d\n", mp_ioapics[apic].mpc_apicid); +- +- +- /* +- * We need to adjust the IRQ routing table +- * if the ID changed. +- */ +- if (old_id != mp_ioapics[apic].mpc_apicid) +- for (i = 0; i < mp_irq_entries; i++) +- if (mp_irqs[i].mpc_dstapic == old_id) +- mp_irqs[i].mpc_dstapic +- = mp_ioapics[apic].mpc_apicid; +- +- /* +- * Read the right value from the MPC table and +- * write it into the ID register. +- */ +- apic_printk(APIC_VERBOSE,KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", +- mp_ioapics[apic].mpc_apicid); +- +- reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; +- spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(apic, 0, reg_00.raw); +- spin_unlock_irqrestore(&ioapic_lock, flags); +- +- /* +- * Sanity check +- */ +- spin_lock_irqsave(&ioapic_lock, flags); +- reg_00.raw = io_apic_read(apic, 0); +- spin_unlock_irqrestore(&ioapic_lock, flags); +- if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) +- printk("could not set ID!\n"); +- else +- apic_printk(APIC_VERBOSE," ok.\n"); +- } +-} +-#else +-static void __init setup_ioapic_ids_from_mpc(void) { } +-#endif +- +-/* + * There is a nasty bug in some older SMP boards, their mptable lies + * about the timer IRQ. We do the following to work around the situation: + * +@@ -1569,7 +1303,7 @@ static int __init timer_irq_works(void) + * an edge even if it isn't on the 8259A... + */ + +-static unsigned int startup_edge_ioapic_irq(unsigned int irq) ++static unsigned int startup_ioapic_irq(unsigned int irq) + { + int was_pending = 0; + unsigned long flags; +@@ -1586,107 +1320,19 @@ static unsigned int startup_edge_ioapic_ + return was_pending; + } + +-/* +- * Once we have recorded IRQ_PENDING already, we can mask the +- * interrupt for real. This prevents IRQ storms from unhandled +- * devices. +- */ +-static void ack_edge_ioapic_irq(unsigned int irq) +-{ +- move_irq(irq); +- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) +- == (IRQ_PENDING | IRQ_DISABLED)) +- mask_IO_APIC_irq(irq); +- ack_APIC_irq(); +-} +- +-/* +- * Level triggered interrupts can just be masked, +- * and shutting down and starting up the interrupt +- * is the same as enabling and disabling them -- except +- * with a startup need to return a "was pending" value. +- * +- * Level triggered interrupts are special because we +- * do not touch any IO-APIC register while handling +- * them. We ack the APIC in the end-IRQ handler, not +- * in the start-IRQ-handler. Protection against reentrance +- * from the same interrupt is still provided, both by the +- * generic IRQ layer and by the fact that an unacked local +- * APIC does not accept IRQs. +- */ +-static unsigned int startup_level_ioapic_irq (unsigned int irq) +-{ +- unmask_IO_APIC_irq(irq); +- +- return 0; /* don't check for pending */ +-} +- +-static void end_level_ioapic_irq (unsigned int irq) +-{ +- move_irq(irq); +- ack_APIC_irq(); +-} +- +-#ifdef CONFIG_PCI_MSI +-static unsigned int startup_edge_ioapic_vector(unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- return startup_edge_ioapic_irq(irq); +-} +- +-static void ack_edge_ioapic_vector(unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- move_native_irq(vector); +- ack_edge_ioapic_irq(irq); +-} +- +-static unsigned int startup_level_ioapic_vector (unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- return startup_level_ioapic_irq (irq); +-} +- +-static void end_level_ioapic_vector (unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- move_native_irq(vector); +- end_level_ioapic_irq(irq); +-} +- +-static void mask_IO_APIC_vector (unsigned int vector) +-{ +- int irq = vector_to_irq(vector); +- +- mask_IO_APIC_irq(irq); +-} +- +-static void unmask_IO_APIC_vector (unsigned int vector) ++static int ioapic_retrigger_irq(unsigned int irq) + { +- int irq = vector_to_irq(vector); +- +- unmask_IO_APIC_irq(irq); +-} +- +-#ifdef CONFIG_SMP +-static void set_ioapic_affinity_vector (unsigned int vector, +- cpumask_t cpu_mask) +-{ +- int irq = vector_to_irq(vector); ++ cpumask_t mask; ++ unsigned vector; ++ unsigned long flags; + +- set_native_irq_info(vector, cpu_mask); +- set_ioapic_affinity_irq(irq, cpu_mask); +-} +-#endif // CONFIG_SMP +-#endif // CONFIG_PCI_MSI ++ spin_lock_irqsave(&vector_lock, flags); ++ vector = irq_vector[irq]; ++ cpus_clear(mask); ++ cpu_set(first_cpu(irq_domain[irq]), mask); + +-static int ioapic_retrigger(unsigned int irq) +-{ +- send_IPI_self(IO_APIC_VECTOR(irq)); ++ send_IPI_mask(mask, vector); ++ spin_unlock_irqrestore(&vector_lock, flags); + + return 1; + } +@@ -1700,32 +1346,47 @@ static int ioapic_retrigger(unsigned int + * races. + */ + +-static struct hw_interrupt_type ioapic_edge_type __read_mostly = { +- .typename = "IO-APIC-edge", +- .startup = startup_edge_ioapic, +- .shutdown = shutdown_edge_ioapic, +- .enable = enable_edge_ioapic, +- .disable = disable_edge_ioapic, +- .ack = ack_edge_ioapic, +- .end = end_edge_ioapic, +-#ifdef CONFIG_SMP +- .set_affinity = set_ioapic_affinity, ++static void ack_apic_edge(unsigned int irq) ++{ ++ move_native_irq(irq); ++ ack_APIC_irq(); ++} ++ ++static void ack_apic_level(unsigned int irq) ++{ ++ int do_unmask_irq = 0; ++ ++#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) ++ /* If we are moving the irq we need to mask it */ ++ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { ++ do_unmask_irq = 1; ++ mask_IO_APIC_irq(irq); ++ } + #endif +- .retrigger = ioapic_retrigger, +-}; + +-static struct hw_interrupt_type ioapic_level_type __read_mostly = { +- .typename = "IO-APIC-level", +- .startup = startup_level_ioapic, +- .shutdown = shutdown_level_ioapic, +- .enable = enable_level_ioapic, +- .disable = disable_level_ioapic, +- .ack = mask_and_ack_level_ioapic, +- .end = end_level_ioapic, ++ /* ++ * We must acknowledge the irq before we move it or the acknowledge will ++ * not propogate properly. ++ */ ++ ack_APIC_irq(); ++ ++ /* Now we can move and renable the irq */ ++ move_masked_irq(irq); ++ if (unlikely(do_unmask_irq)) ++ unmask_IO_APIC_irq(irq); ++} ++ ++static struct irq_chip ioapic_chip __read_mostly = { ++ .name = "IO-APIC", ++ .startup = startup_ioapic_irq, ++ .mask = mask_IO_APIC_irq, ++ .unmask = unmask_IO_APIC_irq, ++ .ack = ack_apic_edge, ++ .eoi = ack_apic_level, + #ifdef CONFIG_SMP +- .set_affinity = set_ioapic_affinity, ++ .set_affinity = set_ioapic_affinity_irq, + #endif +- .retrigger = ioapic_retrigger, ++ .retrigger = ioapic_retrigger_irq, + }; + #endif /* !CONFIG_XEN */ + +@@ -1746,12 +1407,7 @@ static inline void init_IO_APIC_traps(vo + */ + for (irq = 0; irq < NR_IRQS ; irq++) { + int tmp = irq; +- if (use_pci_vector()) { +- if (!platform_legacy_irq(tmp)) +- if ((tmp = vector_to_irq(tmp)) == -1) +- continue; +- } +- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { ++ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { + /* + * Hmm.. We don't have an entry for this, + * so default to an old-fashioned 8259 +@@ -1762,7 +1418,7 @@ static inline void init_IO_APIC_traps(vo + #ifndef CONFIG_XEN + else + /* Strange. Oh, well.. */ +- irq_desc[irq].chip = &no_irq_type; ++ irq_desc[irq].chip = &no_irq_chip; + #endif + } + } +@@ -1883,8 +1539,6 @@ static inline void unlock_ExtINT_logic(v + spin_unlock_irqrestore(&ioapic_lock, flags); + } + +-int timer_uses_ioapic_pin_0; +- + /* + * This code may look a bit paranoid, but it's supposed to cooperate with + * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ +@@ -1897,13 +1551,13 @@ static inline void check_timer(void) + { + int apic1, pin1, apic2, pin2; + int vector; ++ cpumask_t mask; + + /* + * get/set the timer IRQ vector: + */ + disable_8259A_irq(0); +- vector = assign_irq_vector(0); +- set_intr_gate(vector, interrupt[0]); ++ vector = assign_irq_vector(0, TARGET_CPUS, &mask); + + /* + * Subtle, code in do_timer_interrupt() expects an AEOI +@@ -1922,9 +1576,6 @@ static inline void check_timer(void) + pin2 = ioapic_i8259.pin; + apic2 = ioapic_i8259.apic; + +- if (pin1 == 0) +- timer_uses_ioapic_pin_0 = 1; +- + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", + vector, apic1, pin1, apic2, pin2); + +@@ -2039,11 +1690,6 @@ void __init setup_IO_APIC(void) + + apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); + +- /* +- * Set up the IO-APIC IRQ routing table. +- */ +- if (!acpi_ioapic) +- setup_ioapic_ids_from_mpc(); + #ifndef CONFIG_XEN + sync_Arb_IDs(); + #endif /* !CONFIG_XEN */ +@@ -2066,17 +1712,12 @@ static int ioapic_suspend(struct sys_dev + { + struct IO_APIC_route_entry *entry; + struct sysfs_ioapic_data *data; +- unsigned long flags; + int i; + + data = container_of(dev, struct sysfs_ioapic_data, dev); + entry = data->entry; +- spin_lock_irqsave(&ioapic_lock, flags); +- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { +- *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i); +- *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i); +- } +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) ++ *entry = ioapic_read_entry(dev->id, i); + + return 0; + } +@@ -2098,11 +1739,9 @@ static int ioapic_resume(struct sys_devi + reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid; + io_apic_write(dev->id, 0, reg_00.raw); + } +- for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) { +- io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1)); +- io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0)); +- } + spin_unlock_irqrestore(&ioapic_lock, flags); ++ for (i = 0; i < nr_ioapic_registers[dev->id]; i++) ++ ioapic_write_entry(dev->id, i, entry[i]); + + return 0; + } +@@ -2148,28 +1787,254 @@ static int __init ioapic_init_sysfs(void + + device_initcall(ioapic_init_sysfs); + ++/* ++ * Dynamic irq allocate and deallocation ++ */ ++int create_irq(void) ++{ ++ /* Allocate an unused irq */ ++ int irq; ++ int new; ++ int vector = 0; ++ unsigned long flags; ++ cpumask_t mask; ++ ++ irq = -ENOSPC; ++ spin_lock_irqsave(&vector_lock, flags); ++ for (new = (NR_IRQS - 1); new >= 0; new--) { ++ if (platform_legacy_irq(new)) ++ continue; ++ if (irq_vector[new] != 0) ++ continue; ++ vector = __assign_irq_vector(new, TARGET_CPUS, &mask); ++ if (likely(vector > 0)) ++ irq = new; ++ break; ++ } ++ spin_unlock_irqrestore(&vector_lock, flags); ++ ++ if (irq >= 0) { ++ dynamic_irq_init(irq); ++ } ++ return irq; ++} ++ ++void destroy_irq(unsigned int irq) ++{ ++ unsigned long flags; ++ ++ dynamic_irq_cleanup(irq); ++ ++ spin_lock_irqsave(&vector_lock, flags); ++ irq_vector[irq] = 0; ++ spin_unlock_irqrestore(&vector_lock, flags); ++} ++ + #endif /* CONFIG_XEN */ + +-/* -------------------------------------------------------------------------- +- ACPI-based IOAPIC Configuration +- -------------------------------------------------------------------------- */ ++/* ++ * MSI mesage composition ++ */ ++#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) ++static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) ++{ ++ int vector; ++ unsigned dest; ++ cpumask_t tmp; + +-#ifdef CONFIG_ACPI ++ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); ++ if (vector >= 0) { ++ dest = cpu_mask_to_apicid(tmp); ++ ++ msg->address_hi = MSI_ADDR_BASE_HI; ++ msg->address_lo = ++ MSI_ADDR_BASE_LO | ++ ((INT_DEST_MODE == 0) ? ++ MSI_ADDR_DEST_MODE_PHYSICAL: ++ MSI_ADDR_DEST_MODE_LOGICAL) | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_ADDR_REDIRECTION_CPU: ++ MSI_ADDR_REDIRECTION_LOWPRI) | ++ MSI_ADDR_DEST_ID(dest); ++ ++ msg->data = ++ MSI_DATA_TRIGGER_EDGE | ++ MSI_DATA_LEVEL_ASSERT | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ MSI_DATA_DELIVERY_FIXED: ++ MSI_DATA_DELIVERY_LOWPRI) | ++ MSI_DATA_VECTOR(vector); ++ } ++ return vector; ++} + +-#define IO_APIC_MAX_ID 0xFE ++#ifdef CONFIG_SMP ++static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ struct msi_msg msg; ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ vector = assign_irq_vector(irq, mask, &tmp); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ read_msi_msg(irq, &msg); ++ ++ msg.data &= ~MSI_DATA_VECTOR_MASK; ++ msg.data |= MSI_DATA_VECTOR(vector); ++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; ++ msg.address_lo |= MSI_ADDR_DEST_ID(dest); + +-int __init io_apic_get_version (int ioapic) ++ write_msi_msg(irq, &msg); ++ set_native_irq_info(irq, mask); ++} ++#endif /* CONFIG_SMP */ ++ ++/* ++ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, ++ * which implement the MSI or MSI-X Capability Structure. ++ */ ++static struct irq_chip msi_chip = { ++ .name = "PCI-MSI", ++ .unmask = unmask_msi_irq, ++ .mask = mask_msi_irq, ++ .ack = ack_apic_edge, ++#ifdef CONFIG_SMP ++ .set_affinity = set_msi_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) + { +- union IO_APIC_reg_01 reg_01; +- unsigned long flags; ++ struct msi_msg msg; ++ int ret; ++ ret = msi_compose_msg(dev, irq, &msg); ++ if (ret < 0) ++ return ret; + +- spin_lock_irqsave(&ioapic_lock, flags); +- reg_01.raw = io_apic_read(ioapic, 1); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ write_msi_msg(irq, &msg); + +- return reg_01.bits.version; ++ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); ++ ++ return 0; ++} ++ ++void arch_teardown_msi_irq(unsigned int irq) ++{ ++ return; + } + ++#endif /* CONFIG_PCI_MSI */ ++ ++/* ++ * Hypertransport interrupt support ++ */ ++#ifdef CONFIG_HT_IRQ ++ ++#ifdef CONFIG_SMP ++ ++static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) ++{ ++ struct ht_irq_msg msg; ++ fetch_ht_irq_msg(irq, &msg); ++ ++ msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); ++ msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK); ++ ++ msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); ++ msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest); ++ ++ write_ht_irq_msg(irq, &msg); ++} ++ ++static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) ++{ ++ unsigned int dest; ++ cpumask_t tmp; ++ int vector; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ tmp = TARGET_CPUS; ++ ++ cpus_and(mask, tmp, CPU_MASK_ALL); ++ ++ vector = assign_irq_vector(irq, mask, &tmp); ++ if (vector < 0) ++ return; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ target_ht_irq(irq, dest, vector); ++ set_native_irq_info(irq, mask); ++} ++#endif ++ ++static struct irq_chip ht_irq_chip = { ++ .name = "PCI-HT", ++ .mask = mask_ht_irq, ++ .unmask = unmask_ht_irq, ++ .ack = ack_apic_edge, ++#ifdef CONFIG_SMP ++ .set_affinity = set_ht_irq_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ++{ ++ int vector; ++ cpumask_t tmp; ++ ++ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); ++ if (vector >= 0) { ++ struct ht_irq_msg msg; ++ unsigned dest; ++ ++ dest = cpu_mask_to_apicid(tmp); ++ ++ msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); ++ ++ msg.address_lo = ++ HT_IRQ_LOW_BASE | ++ HT_IRQ_LOW_DEST_ID(dest) | ++ HT_IRQ_LOW_VECTOR(vector) | ++ ((INT_DEST_MODE == 0) ? ++ HT_IRQ_LOW_DM_PHYSICAL : ++ HT_IRQ_LOW_DM_LOGICAL) | ++ HT_IRQ_LOW_RQEOI_EDGE | ++ ((INT_DELIVERY_MODE != dest_LowestPrio) ? ++ HT_IRQ_LOW_MT_FIXED : ++ HT_IRQ_LOW_MT_ARBITRATED) | ++ HT_IRQ_LOW_IRQ_MASKED; ++ ++ write_ht_irq_msg(irq, &msg); ++ ++ set_irq_chip_and_handler_name(irq, &ht_irq_chip, ++ handle_edge_irq, "edge"); ++ } ++ return vector; ++} ++#endif /* CONFIG_HT_IRQ */ ++ ++/* -------------------------------------------------------------------------- ++ ACPI-based IOAPIC Configuration ++ -------------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_ACPI ++ ++#define IO_APIC_MAX_ID 0xFE + + int __init io_apic_get_redir_entries (int ioapic) + { +@@ -2188,6 +2053,8 @@ int io_apic_set_pci_routing (int ioapic, + { + struct IO_APIC_route_entry entry; + unsigned long flags; ++ int vector; ++ cpumask_t mask; + + if (!IO_APIC_IRQ(irq)) { + apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", +@@ -2196,6 +2063,17 @@ int io_apic_set_pci_routing (int ioapic, + } + + /* ++ * IRQs < 16 are already in the irq_2_pin[] map ++ */ ++ if (irq >= 16) ++ add_pin_to_irq(irq, ioapic, pin); ++ ++ ++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask); ++ if (vector < 0) ++ return vector; ++ ++ /* + * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. + * Note that we mask (disable) IRQs now -- these get enabled when the + * corresponding device driver registers for this IRQ. +@@ -2205,19 +2083,11 @@ int io_apic_set_pci_routing (int ioapic, + + entry.delivery_mode = INT_DELIVERY_MODE; + entry.dest_mode = INT_DEST_MODE; +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); + entry.trigger = edge_level; + entry.polarity = active_high_low; + entry.mask = 1; /* Disabled (masked) */ +- +- irq = gsi_irq_sharing(irq); +- /* +- * IRQs < 16 are already in the irq_2_pin[] map +- */ +- if (irq >= 16) +- add_pin_to_irq(irq, ioapic, pin); +- +- entry.vector = assign_irq_vector(irq); ++ entry.vector = vector & 0xff; + + apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " + "IRQ %d Mode:%i Active:%i)\n", ioapic, +@@ -2229,10 +2099,10 @@ int io_apic_set_pci_routing (int ioapic, + if (!ioapic && (irq < 16)) + disable_8259A_irq(irq); + ++ ioapic_write_entry(ioapic, pin, entry); ++ + spin_lock_irqsave(&ioapic_lock, flags); +- io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); +- io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); +- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); ++ set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +--- sle11-2009-05-14.orig/arch/x86/kernel/ioport_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/ioport_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -58,6 +58,7 @@ asmlinkage long sys_ioperm(unsigned long + + memset(bitmap, 0xff, IO_BITMAP_BYTES); + t->io_bitmap_ptr = bitmap; ++ set_thread_flag(TIF_IO_BITMAP); + + set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); + set_iobitmap.nr_ports = IO_BITMAP_BITS; +--- sle11-2009-05-14.orig/arch/x86/kernel/irq_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/irq_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -20,11 +20,6 @@ + #include + + atomic_t irq_err_count; +-#ifdef CONFIG_X86_IO_APIC +-#ifdef APIC_MISMATCH_DEBUG +-atomic_t irq_mis_count; +-#endif +-#endif + + #ifdef CONFIG_DEBUG_STACKOVERFLOW + /* +@@ -79,7 +74,8 @@ int show_interrupts(struct seq_file *p, + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); + #endif +- seq_printf(p, " %14s", irq_desc[i].chip->typename); ++ seq_printf(p, " %8s", irq_desc[i].chip->name); ++ seq_printf(p, "-%-8s", irq_desc[i].name); + + seq_printf(p, " %s", action->name); + for (action=action->next; action; action = action->next) +@@ -99,11 +95,6 @@ skip: + seq_putc(p, '\n'); + #endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +-#ifdef CONFIG_X86_IO_APIC +-#ifdef APIC_MISMATCH_DEBUG +- seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); +-#endif +-#endif + } + return 0; + } +@@ -114,24 +105,28 @@ skip: + * handlers). + */ + asmlinkage unsigned int do_IRQ(struct pt_regs *regs) +-{ ++{ ++ struct pt_regs *old_regs = set_irq_regs(regs); ++ + /* high bit used in ret_from_ code */ + unsigned irq = ~regs->orig_rax; + +- if (unlikely(irq >= NR_IRQS)) { +- printk(KERN_EMERG "%s: cannot handle IRQ %d\n", +- __FUNCTION__, irq); +- BUG(); +- } +- + /*exit_idle();*/ + /*irq_enter();*/ ++ + #ifdef CONFIG_DEBUG_STACKOVERFLOW + stack_overflow_check(regs); + #endif +- __do_IRQ(irq, regs); ++ ++ if (likely(irq < NR_IRQS)) ++ generic_handle_irq(irq); ++ else ++ printk(KERN_EMERG "%s: %d.%d No irq handler for irq\n", ++ __func__, smp_processor_id(), irq); ++ + /*irq_exit();*/ + ++ set_irq_regs(old_regs); + return 1; + } + +@@ -192,6 +187,6 @@ EXPORT_SYMBOL(do_softirq); + */ + void ack_bad_irq(unsigned int irq) + { +- printk("unexpected IRQ trap at vector %02x\n", irq); ++ printk("unexpected IRQ trap at irq %02x\n", irq); + } + #endif +--- sle11-2009-05-14.orig/arch/x86/kernel/mpparse_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/mpparse_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -41,8 +41,7 @@ int acpi_found_madt; + * Various Linux-internal data structures created from the + * MP-table. + */ +-unsigned char apic_version [MAX_APICS]; +-unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; ++DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); + int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; + + static int mp_current_pci_id = 0; +@@ -56,7 +55,6 @@ struct mpc_config_intsrc mp_irqs[MAX_IRQ + int mp_irq_entries; + + int nr_ioapics; +-int pic_mode; + unsigned long mp_lapic_addr = 0; + + +@@ -71,19 +69,6 @@ unsigned disabled_cpus __initdata; + /* Bitmask of physically existing CPUs */ + physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE; + +-/* ACPI MADT entry parsing functions */ +-#ifdef CONFIG_ACPI +-extern struct acpi_boot_flags acpi_boot; +-#ifdef CONFIG_X86_LOCAL_APIC +-extern int acpi_parse_lapic (acpi_table_entry_header *header); +-extern int acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header); +-extern int acpi_parse_lapic_nmi (acpi_table_entry_header *header); +-#endif /*CONFIG_X86_LOCAL_APIC*/ +-#ifdef CONFIG_X86_IO_APIC +-extern int acpi_parse_ioapic (acpi_table_entry_header *header); +-#endif /*CONFIG_X86_IO_APIC*/ +-#endif /*CONFIG_ACPI*/ +- + u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; + + +@@ -109,24 +94,20 @@ static int __init mpf_checksum(unsigned + static void __cpuinit MP_processor_info (struct mpc_config_processor *m) + { + int cpu; +- unsigned char ver; + cpumask_t tmp_map; ++ char *bootup_cpu = ""; + + if (!(m->mpc_cpuflag & CPU_ENABLED)) { + disabled_cpus++; + return; + } +- +- printk(KERN_INFO "Processor #%d %d:%d APIC version %d\n", +- m->mpc_apicid, +- (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8, +- (m->mpc_cpufeature & CPU_MODEL_MASK)>>4, +- m->mpc_apicver); +- + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { +- Dprintk(" Bootup CPU\n"); ++ bootup_cpu = " (Bootup-CPU)"; + boot_cpu_id = m->mpc_apicid; + } ++ ++ printk(KERN_INFO "Processor #%d%s\n", m->mpc_apicid, bootup_cpu); ++ + if (num_processors >= NR_CPUS) { + printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + " Processor ignored.\n", NR_CPUS); +@@ -137,24 +118,7 @@ static void __cpuinit MP_processor_info + cpus_complement(tmp_map, cpu_present_map); + cpu = first_cpu(tmp_map); + +-#if MAX_APICS < 255 +- if ((int)m->mpc_apicid > MAX_APICS) { +- printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n", +- m->mpc_apicid, MAX_APICS); +- return; +- } +-#endif +- ver = m->mpc_apicver; +- + physid_set(m->mpc_apicid, phys_cpu_present_map); +- /* +- * Validate version +- */ +- if (ver == 0x0) { +- printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); +- ver = 0x10; +- } +- apic_version[m->mpc_apicid] = ver; + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { + /* + * bios_cpu_apicid is required to have processors listed +@@ -185,37 +149,42 @@ static void __init MP_bus_info (struct m + Dprintk("Bus #%d is %s\n", m->mpc_busid, str); + + if (strncmp(str, "ISA", 3) == 0) { +- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; +- } else if (strncmp(str, "EISA", 4) == 0) { +- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; ++ set_bit(m->mpc_busid, mp_bus_not_pci); + } else if (strncmp(str, "PCI", 3) == 0) { +- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; ++ clear_bit(m->mpc_busid, mp_bus_not_pci); + mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; + mp_current_pci_id++; +- } else if (strncmp(str, "MCA", 3) == 0) { +- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; + } else { + printk(KERN_ERR "Unknown bustype %s\n", str); + } + } + ++static int bad_ioapic(unsigned long address) ++{ ++ if (nr_ioapics >= MAX_IO_APICS) { ++ printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " ++ "(found %d)\n", MAX_IO_APICS, nr_ioapics); ++ panic("Recompile kernel with bigger MAX_IO_APICS!\n"); ++ } ++ if (!address) { ++ printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" ++ " found in table, skipping!\n"); ++ return 1; ++ } ++ return 0; ++} ++ + static void __init MP_ioapic_info (struct mpc_config_ioapic *m) + { + if (!(m->mpc_flags & MPC_APIC_USABLE)) + return; + +- printk("I/O APIC #%d Version %d at 0x%X.\n", +- m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); +- if (nr_ioapics >= MAX_IO_APICS) { +- printk(KERN_ERR "Max # of I/O APICs (%d) exceeded (found %d).\n", +- MAX_IO_APICS, nr_ioapics); +- panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); +- } +- if (!m->mpc_apicaddr) { +- printk(KERN_ERR "WARNING: bogus zero I/O APIC address" +- " found in MP table, skipping!\n"); ++ printk("I/O APIC #%d at 0x%X.\n", ++ m->mpc_apicid, m->mpc_apicaddr); ++ ++ if (bad_ioapic(m->mpc_apicaddr)) + return; +- } ++ + mp_ioapics[nr_ioapics] = *m; + nr_ioapics++; + } +@@ -239,19 +208,6 @@ static void __init MP_lintsrc_info (stru + m->mpc_irqtype, m->mpc_irqflag & 3, + (m->mpc_irqflag >> 2) &3, m->mpc_srcbusid, + m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint); +- /* +- * Well it seems all SMP boards in existence +- * use ExtINT/LVT1 == LINT0 and +- * NMI/LVT2 == LINT1 - the following check +- * will show us if this assumptions is false. +- * Until then we do not have to add baggage. +- */ +- if ((m->mpc_irqtype == mp_ExtINT) && +- (m->mpc_destapiclint != 0)) +- BUG(); +- if ((m->mpc_irqtype == mp_NMI) && +- (m->mpc_destapiclint != 1)) +- BUG(); + } + + /* +@@ -265,7 +221,7 @@ static int __init smp_read_mpc(struct mp + unsigned char *mpt=((unsigned char *)mpc)+count; + + if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { +- printk("SMP mptable: bad signature [%c%c%c%c]!\n", ++ printk("MPTABLE: bad signature [%c%c%c%c]!\n", + mpc->mpc_signature[0], + mpc->mpc_signature[1], + mpc->mpc_signature[2], +@@ -273,31 +229,31 @@ static int __init smp_read_mpc(struct mp + return 0; + } + if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) { +- printk("SMP mptable: checksum error!\n"); ++ printk("MPTABLE: checksum error!\n"); + return 0; + } + if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { +- printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n", ++ printk(KERN_ERR "MPTABLE: bad table version (%d)!!\n", + mpc->mpc_spec); + return 0; + } + if (!mpc->mpc_lapic) { +- printk(KERN_ERR "SMP mptable: null local APIC address!\n"); ++ printk(KERN_ERR "MPTABLE: null local APIC address!\n"); + return 0; + } + memcpy(str,mpc->mpc_oem,8); +- str[8]=0; +- printk(KERN_INFO "OEM ID: %s ",str); ++ str[8] = 0; ++ printk(KERN_INFO "MPTABLE: OEM ID: %s ",str); + + memcpy(str,mpc->mpc_productid,12); +- str[12]=0; +- printk("Product ID: %s ",str); ++ str[12] = 0; ++ printk("MPTABLE: Product ID: %s ",str); + +- printk("APIC at: 0x%X\n",mpc->mpc_lapic); ++ printk("MPTABLE: APIC at: 0x%X\n",mpc->mpc_lapic); + + /* save the local APIC address, it might be non-default */ + if (!acpi_lapic) +- mp_lapic_addr = mpc->mpc_lapic; ++ mp_lapic_addr = mpc->mpc_lapic; + + /* + * Now process the configuration blocks. +@@ -309,7 +265,7 @@ static int __init smp_read_mpc(struct mp + struct mpc_config_processor *m= + (struct mpc_config_processor *)mpt; + if (!acpi_lapic) +- MP_processor_info(m); ++ MP_processor_info(m); + mpt += sizeof(*m); + count += sizeof(*m); + break; +@@ -328,8 +284,8 @@ static int __init smp_read_mpc(struct mp + struct mpc_config_ioapic *m= + (struct mpc_config_ioapic *)mpt; + MP_ioapic_info(m); +- mpt+=sizeof(*m); +- count+=sizeof(*m); ++ mpt += sizeof(*m); ++ count += sizeof(*m); + break; + } + case MP_INTSRC: +@@ -338,8 +294,8 @@ static int __init smp_read_mpc(struct mp + (struct mpc_config_intsrc *)mpt; + + MP_intsrc_info(m); +- mpt+=sizeof(*m); +- count+=sizeof(*m); ++ mpt += sizeof(*m); ++ count += sizeof(*m); + break; + } + case MP_LINTSRC: +@@ -347,15 +303,15 @@ static int __init smp_read_mpc(struct mp + struct mpc_config_lintsrc *m= + (struct mpc_config_lintsrc *)mpt; + MP_lintsrc_info(m); +- mpt+=sizeof(*m); +- count+=sizeof(*m); ++ mpt += sizeof(*m); ++ count += sizeof(*m); + break; + } + } + } + clustered_apic_check(); + if (!num_processors) +- printk(KERN_ERR "SMP mptable: no processors registered!\n"); ++ printk(KERN_ERR "MPTABLE: no processors registered!\n"); + return num_processors; + } + +@@ -451,13 +407,10 @@ static inline void __init construct_defa + * 2 CPUs, numbered 0 & 1. + */ + processor.mpc_type = MP_PROCESSOR; +- /* Either an integrated APIC or a discrete 82489DX. */ +- processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; ++ processor.mpc_apicver = 0; + processor.mpc_cpuflag = CPU_ENABLED; +- processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | +- (boot_cpu_data.x86_model << 4) | +- boot_cpu_data.x86_mask; +- processor.mpc_featureflag = boot_cpu_data.x86_capability[0]; ++ processor.mpc_cpufeature = 0; ++ processor.mpc_featureflag = 0; + processor.mpc_reserved[0] = 0; + processor.mpc_reserved[1] = 0; + for (i = 0; i < 2; i++) { +@@ -476,14 +429,6 @@ static inline void __init construct_defa + case 5: + memcpy(bus.mpc_bustype, "ISA ", 6); + break; +- case 2: +- case 6: +- case 3: +- memcpy(bus.mpc_bustype, "EISA ", 6); +- break; +- case 4: +- case 7: +- memcpy(bus.mpc_bustype, "MCA ", 6); + } + MP_bus_info(&bus); + if (mpc_default_type > 4) { +@@ -494,7 +439,7 @@ static inline void __init construct_defa + + ioapic.mpc_type = MP_IOAPIC; + ioapic.mpc_apicid = 2; +- ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01; ++ ioapic.mpc_apicver = 0; + ioapic.mpc_flags = MPC_APIC_USABLE; + ioapic.mpc_apicaddr = 0xFEC00000; + MP_ioapic_info(&ioapic); +@@ -537,13 +482,6 @@ void __init get_smp_config (void) + printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n"); + + printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); +- if (mpf->mpf_feature2 & (1<<7)) { +- printk(KERN_INFO " IMCR and PIC compatibility mode.\n"); +- pic_mode = 1; +- } else { +- printk(KERN_INFO " Virtual Wire compatibility mode.\n"); +- pic_mode = 0; +- } + + /* + * Now see if we need to read further. +@@ -620,7 +558,7 @@ static int __init smp_scan_config (unsig + return 0; + } + +-void __init find_intel_smp (void) ++void __init find_smp_config(void) + { + unsigned int address; + +@@ -637,9 +575,7 @@ void __init find_intel_smp (void) + smp_scan_config(0xF0000,0x10000)) + return; + /* +- * If it is an SMP machine we should know now, unless the +- * configuration is in an EISA/MCA bus machine with an +- * extended bios data area. ++ * If it is an SMP machine we should know now. + * + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E, calculate and scan it here. +@@ -660,64 +596,38 @@ void __init find_intel_smp (void) + printk(KERN_INFO "No mptable found.\n"); + } + +-/* +- * - Intel MP Configuration Table +- */ +-void __init find_smp_config (void) +-{ +-#ifdef CONFIG_X86_LOCAL_APIC +- find_intel_smp(); +-#endif +-} +- +- + /* -------------------------------------------------------------------------- + ACPI-based MP Configuration + -------------------------------------------------------------------------- */ + + #ifdef CONFIG_ACPI + +-void __init mp_register_lapic_address ( +- u64 address) ++void __init mp_register_lapic_address(u64 address) + { + #ifndef CONFIG_XEN + mp_lapic_addr = (unsigned long) address; +- + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); +- + if (boot_cpu_id == -1U) + boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); +- +- Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid); + #endif + } + +- +-void __cpuinit mp_register_lapic ( +- u8 id, +- u8 enabled) ++void __cpuinit mp_register_lapic (u8 id, u8 enabled) + { + struct mpc_config_processor processor; + int boot_cpu = 0; + +- if (id >= MAX_APICS) { +- printk(KERN_WARNING "Processor #%d invalid (max %d)\n", +- id, MAX_APICS); +- return; +- } +- +- if (id == boot_cpu_physical_apicid) ++ if (id == boot_cpu_id) + boot_cpu = 1; + + #ifndef CONFIG_XEN + processor.mpc_type = MP_PROCESSOR; + processor.mpc_apicid = id; +- processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR)); ++ processor.mpc_apicver = 0; + processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0); + processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0); +- processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | +- (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask; +- processor.mpc_featureflag = boot_cpu_data.x86_capability[0]; ++ processor.mpc_cpufeature = 0; ++ processor.mpc_featureflag = 0; + processor.mpc_reserved[0] = 0; + processor.mpc_reserved[1] = 0; + #endif +@@ -725,8 +635,6 @@ void __cpuinit mp_register_lapic ( + MP_processor_info(&processor); + } + +-#ifdef CONFIG_X86_IO_APIC +- + #define MP_ISA_BUS 0 + #define MP_MAX_IOAPIC_PIN 127 + +@@ -737,11 +645,9 @@ static struct mp_ioapic_routing { + u32 pin_programmed[4]; + } mp_ioapic_routing[MAX_IO_APICS]; + +- +-static int mp_find_ioapic ( +- int gsi) ++static int mp_find_ioapic(int gsi) + { +- int i = 0; ++ int i = 0; + + /* Find the IOAPIC that manages this GSI. */ + for (i = 0; i < nr_ioapics; i++) { +@@ -751,28 +657,15 @@ static int mp_find_ioapic ( + } + + printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); +- + return -1; + } +- + +-void __init mp_register_ioapic ( +- u8 id, +- u32 address, +- u32 gsi_base) ++void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base) + { +- int idx = 0; ++ int idx = 0; + +- if (nr_ioapics >= MAX_IO_APICS) { +- printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " +- "(found %d)\n", MAX_IO_APICS, nr_ioapics); +- panic("Recompile kernel with bigger MAX_IO_APICS!\n"); +- } +- if (!address) { +- printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" +- " found in MADT table, skipping!\n"); ++ if (bad_ioapic(address)) + return; +- } + + idx = nr_ioapics++; + +@@ -784,7 +677,7 @@ void __init mp_register_ioapic ( + set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); + #endif + mp_ioapics[idx].mpc_apicid = id; +- mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx); ++ mp_ioapics[idx].mpc_apicver = 0; + + /* + * Build basic IRQ lookup table to facilitate gsi->io_apic lookups +@@ -795,21 +688,15 @@ void __init mp_register_ioapic ( + mp_ioapic_routing[idx].gsi_end = gsi_base + + io_apic_get_redir_entries(idx); + +- printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " ++ printk(KERN_INFO "IOAPIC[%d]: apic_id %d, address 0x%x, " + "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, +- mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, ++ mp_ioapics[idx].mpc_apicaddr, + mp_ioapic_routing[idx].gsi_start, + mp_ioapic_routing[idx].gsi_end); +- +- return; + } + +- +-void __init mp_override_legacy_irq ( +- u8 bus_irq, +- u8 polarity, +- u8 trigger, +- u32 gsi) ++void __init ++mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) + { + struct mpc_config_intsrc intsrc; + int ioapic = -1; +@@ -847,22 +734,18 @@ void __init mp_override_legacy_irq ( + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); +- +- return; + } + +- +-void __init mp_config_acpi_legacy_irqs (void) ++void __init mp_config_acpi_legacy_irqs(void) + { + struct mpc_config_intsrc intsrc; +- int i = 0; +- int ioapic = -1; ++ int i = 0; ++ int ioapic = -1; + + /* + * Fabricate the legacy ISA bus (bus #31). + */ +- mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; +- Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); ++ set_bit(MP_ISA_BUS, mp_bus_not_pci); + + /* + * Locate the IOAPIC that manages the ISA IRQs (0-15). +@@ -915,24 +798,13 @@ void __init mp_config_acpi_legacy_irqs ( + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); + } +- +- return; + } + +-#define MAX_GSI_NUM 4096 +- + int mp_register_gsi(u32 gsi, int triggering, int polarity) + { +- int ioapic = -1; +- int ioapic_pin = 0; +- int idx, bit = 0; +- static int pci_irq = 16; +- /* +- * Mapping between Global System Interrupts, which +- * represent all possible interrupts, to the IRQs +- * assigned to actual devices. +- */ +- static int gsi_to_irq[MAX_GSI_NUM]; ++ int ioapic = -1; ++ int ioapic_pin = 0; ++ int idx, bit = 0; + + if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) + return gsi; +@@ -965,47 +837,14 @@ int mp_register_gsi(u32 gsi, int trigger + if ((1< 15), but +- * avoid a problem where the 8254 timer (IRQ0) is setup +- * via an override (so it's not on pin 0 of the ioapic), +- * and at the same time, the pin 0 interrupt is a PCI +- * type. The gsi > 15 test could cause these two pins +- * to be shared as IRQ0, and they are not shareable. +- * So test for this condition, and if necessary, avoid +- * the pin collision. +- */ +- if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0)) +- gsi = pci_irq++; +- /* +- * Don't assign IRQ used by ACPI SCI +- */ +- if (gsi == acpi_fadt.sci_int) +- gsi = pci_irq++; +- gsi_to_irq[irq] = gsi; +- } else { +- printk(KERN_ERR "GSI %u is too high\n", gsi); +- return gsi; +- } +- } +- + io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, + triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, + polarity == ACPI_ACTIVE_HIGH ? 0 : 1); + return gsi; + } +- +-#endif /*CONFIG_X86_IO_APIC*/ + #endif /*CONFIG_ACPI*/ +--- sle11-2009-05-14.orig/arch/x86/kernel/process_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/process_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -89,25 +89,24 @@ void idle_notifier_unregister(struct not + } + EXPORT_SYMBOL(idle_notifier_unregister); + +-enum idle_state { CPU_IDLE, CPU_NOT_IDLE }; +-static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE; +- + void enter_idle(void) + { +- __get_cpu_var(idle_state) = CPU_IDLE; ++ write_pda(isidle, 1); + atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); + } + + static void __exit_idle(void) + { +- __get_cpu_var(idle_state) = CPU_NOT_IDLE; ++ if (test_and_clear_bit_pda(0, isidle) == 0) ++ return; + atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); + } + + /* Called from interrupts to signify idle end */ + void exit_idle(void) + { +- if (current->pid | read_pda(irqcount)) ++ /* idle loop has pid 0 */ ++ if (current->pid) + return; + __exit_idle(); + } +@@ -184,6 +183,9 @@ void cpu_idle (void) + play_dead(); + enter_idle(); + idle(); ++ /* In many cases the interrupt that ended idle ++ has already called exit_idle. But some idle ++ loops can be woken up without interrupt. */ + __exit_idle(); + } + +@@ -196,7 +198,7 @@ void cpu_idle (void) + void cpu_idle_wait(void) + { + unsigned int cpu, this_cpu = get_cpu(); +- cpumask_t map; ++ cpumask_t map, tmp = current->cpus_allowed; + + set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); + put_cpu(); +@@ -219,6 +221,8 @@ void cpu_idle_wait(void) + } + cpus_and(map, map, cpu_online_map); + } while (!cpus_empty(map)); ++ ++ set_cpus_allowed(current, tmp); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + +@@ -250,9 +254,9 @@ void __show_regs(struct pt_regs * regs) + print_modules(); + printk("Pid: %d, comm: %.20s %s %s %.*s\n", + current->pid, current->comm, print_tainted(), +- system_utsname.release, +- (int)strcspn(system_utsname.version, " "), +- system_utsname.version); ++ init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); + printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); + printk_address(regs->rip); + printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, +@@ -310,6 +314,7 @@ void exit_thread(void) + + kfree(t->io_bitmap_ptr); + t->io_bitmap_ptr = NULL; ++ clear_thread_flag(TIF_IO_BITMAP); + /* + * Careful, clear this in the TSS too: + */ +@@ -340,6 +345,7 @@ void flush_thread(void) + if (t->flags & _TIF_IA32) + current_thread_info()->status |= TS_COMPAT; + } ++ t->flags &= ~_TIF_DEBUG; + + tsk->thread.debugreg0 = 0; + tsk->thread.debugreg1 = 0; +@@ -432,7 +438,7 @@ int copy_thread(int nr, unsigned long cl + asm("mov %%es,%0" : "=m" (p->thread.es)); + asm("mov %%ds,%0" : "=m" (p->thread.ds)); + +- if (unlikely(me->thread.io_bitmap_ptr != NULL)) { ++ if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) { + p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); + if (!p->thread.io_bitmap_ptr) { + p->thread.io_bitmap_max = 0; +@@ -440,6 +446,7 @@ int copy_thread(int nr, unsigned long cl + } + memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, + IO_BITMAP_BYTES); ++ set_tsk_thread_flag(p, TIF_IO_BITMAP); + } + + /* +@@ -474,6 +481,30 @@ static inline void __save_init_fpu( stru + } + + /* ++ * This special macro can be used to load a debugging register ++ */ ++#define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) ++ ++static inline void __switch_to_xtra(struct task_struct *prev_p, ++ struct task_struct *next_p) ++{ ++ struct thread_struct *prev, *next; ++ ++ prev = &prev_p->thread, ++ next = &next_p->thread; ++ ++ if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { ++ loaddebug(next, 0); ++ loaddebug(next, 1); ++ loaddebug(next, 2); ++ loaddebug(next, 3); ++ /* no 4 and 5 */ ++ loaddebug(next, 6); ++ loaddebug(next, 7); ++ } ++} ++ ++/* + * switch_to(x,y) should switch tasks from x to y. + * + * This could still be optimized: +@@ -501,6 +532,10 @@ __switch_to(struct task_struct *prev_p, + #endif + multicall_entry_t _mcl[8], *mcl = _mcl; + ++ /* we're going to use this soon, after a few expensive things */ ++ if (next_p->fpu_counter>5) ++ prefetch(&next->i387.fxsave); ++ + /* + * This is basically '__unlazy_fpu', except that we queue a + * multicall to indicate FPU task switch, rather than +@@ -513,7 +548,8 @@ __switch_to(struct task_struct *prev_p, + mcl->op = __HYPERVISOR_fpu_taskswitch; + mcl->args[0] = 1; + mcl++; +- } ++ } else ++ prev_p->fpu_counter = 0; + + /* + * Reload esp0, LDT and the page table pointer: +@@ -608,21 +644,29 @@ __switch_to(struct task_struct *prev_p, + write_pda(oldrsp, next->userrsp); + write_pda(pcurrent, next_p); + write_pda(kernelstack, +- task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); ++ (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); ++#ifdef CONFIG_CC_STACKPROTECTOR ++ write_pda(stack_canary, next_p->stack_canary); ++ ++ /* ++ * Build time only check to make sure the stack_canary is at ++ * offset 40 in the pda; this is a gcc ABI requirement ++ */ ++ BUILD_BUG_ON(offsetof(struct x8664_pda, stack_canary) != 40); ++#endif + + /* + * Now maybe reload the debug registers + */ +- if (unlikely(next->debugreg7)) { +- set_debugreg(next->debugreg0, 0); +- set_debugreg(next->debugreg1, 1); +- set_debugreg(next->debugreg2, 2); +- set_debugreg(next->debugreg3, 3); +- /* no 4 and 5 */ +- set_debugreg(next->debugreg6, 6); +- set_debugreg(next->debugreg7, 7); +- } ++ if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) ++ __switch_to_xtra(prev_p, next_p); + ++ /* If the task has used fpu the last 5 timeslices, just do a full ++ * restore of the math state immediately to avoid the trap; the ++ * chances of needing FPU soon are obviously high now ++ */ ++ if (next_p->fpu_counter>5) ++ math_state_restore(); + return prev_p; + } + +@@ -842,7 +886,7 @@ int dump_task_regs(struct task_struct *t + + unsigned long arch_align_stack(unsigned long sp) + { +- if (randomize_va_space) ++ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; + } +--- sle11-2009-05-14.orig/arch/x86/kernel/setup_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/setup_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -88,9 +88,6 @@ extern struct edid_info edid_info; + shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page; + EXPORT_SYMBOL(HYPERVISOR_shared_info); + +-extern char hypercall_page[PAGE_SIZE]; +-EXPORT_SYMBOL(hypercall_page); +- + static int xen_panic_event(struct notifier_block *, unsigned long, void *); + static struct notifier_block xen_panic_block = { + xen_panic_event, NULL, 0 /* try to go last */ +@@ -118,16 +115,6 @@ EXPORT_SYMBOL(boot_cpu_data); + + unsigned long mmu_cr4_features; + +-int acpi_disabled; +-EXPORT_SYMBOL(acpi_disabled); +-#ifdef CONFIG_ACPI +-extern int __initdata acpi_ht; +-extern acpi_interrupt_flags acpi_sci_flags; +-int __initdata acpi_force = 0; +-#endif +- +-int acpi_numa __initdata; +- + /* Boot loader ID as an integer, for the benefit of proc_dointvec */ + int bootloader_type; + +@@ -151,10 +138,6 @@ struct sys_desc_table_struct { + + struct edid_info edid_info; + EXPORT_SYMBOL_GPL(edid_info); +-struct e820map e820; +-#ifdef CONFIG_XEN +-struct e820map machine_e820; +-#endif + + extern int root_mountflags; + +@@ -181,9 +164,6 @@ struct resource standard_io_resources[] + .flags = IORESOURCE_BUSY | IORESOURCE_IO } + }; + +-#define STANDARD_IO_RESOURCES \ +- (sizeof standard_io_resources / sizeof standard_io_resources[0]) +- + #define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM) + + struct resource data_resource = { +@@ -230,9 +210,6 @@ static struct resource adapter_rom_resou + .flags = IORESOURCE_ROM } + }; + +-#define ADAPTER_ROM_RESOURCES \ +- (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0]) +- + static struct resource video_rom_resource = { + .name = "Video ROM", + .start = 0xc0000, +@@ -309,7 +286,8 @@ static void __init probe_roms(void) + } + + /* check for adapter roms on 2k boundaries */ +- for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) { ++ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; ++ start += 2048) { + rom = isa_bus_to_virt(start); + if (!romsignature(rom)) + continue; +@@ -329,187 +307,22 @@ static void __init probe_roms(void) + } + } + +-/* Check for full argument with no trailing characters */ +-static int fullarg(char *p, char *arg) ++#ifdef CONFIG_PROC_VMCORE ++/* elfcorehdr= specifies the location of elf core header ++ * stored by the crashed kernel. This option will be passed ++ * by kexec loader to the capture kernel. ++ */ ++static int __init setup_elfcorehdr(char *arg) + { +- int l = strlen(arg); +- return !memcmp(p, arg, l) && (p[l] == 0 || isspace(p[l])); ++ char *end; ++ if (!arg) ++ return -EINVAL; ++ elfcorehdr_addr = memparse(arg, &end); ++ return end > arg ? 0 : -EINVAL; + } +- +-static __init void parse_cmdline_early (char ** cmdline_p) +-{ +- char c = ' ', *to = command_line, *from = COMMAND_LINE; +- int len = 0; +- int userdef = 0; +- +- for (;;) { +- if (c != ' ') +- goto next_char; +- +-#ifdef CONFIG_SMP +- /* +- * If the BIOS enumerates physical processors before logical, +- * maxcpus=N at enumeration-time can be used to disable HT. +- */ +- else if (!memcmp(from, "maxcpus=", 8)) { +- extern unsigned int maxcpus; +- +- maxcpus = simple_strtoul(from + 8, NULL, 0); +- } +-#endif +-#ifdef CONFIG_ACPI +- /* "acpi=off" disables both ACPI table parsing and interpreter init */ +- if (fullarg(from,"acpi=off")) +- disable_acpi(); +- +- if (fullarg(from, "acpi=force")) { +- /* add later when we do DMI horrors: */ +- acpi_force = 1; +- acpi_disabled = 0; +- } +- +- /* acpi=ht just means: do ACPI MADT parsing +- at bootup, but don't enable the full ACPI interpreter */ +- if (fullarg(from, "acpi=ht")) { +- if (!acpi_force) +- disable_acpi(); +- acpi_ht = 1; +- } +- else if (fullarg(from, "pci=noacpi")) +- acpi_disable_pci(); +- else if (fullarg(from, "acpi=noirq")) +- acpi_noirq_set(); +- +- else if (fullarg(from, "acpi_sci=edge")) +- acpi_sci_flags.trigger = 1; +- else if (fullarg(from, "acpi_sci=level")) +- acpi_sci_flags.trigger = 3; +- else if (fullarg(from, "acpi_sci=high")) +- acpi_sci_flags.polarity = 1; +- else if (fullarg(from, "acpi_sci=low")) +- acpi_sci_flags.polarity = 3; +- +- /* acpi=strict disables out-of-spec workarounds */ +- else if (fullarg(from, "acpi=strict")) { +- acpi_strict = 1; +- } +-#ifdef CONFIG_X86_IO_APIC +- else if (fullarg(from, "acpi_skip_timer_override")) +- acpi_skip_timer_override = 1; +-#endif +-#endif +- +-#ifndef CONFIG_XEN +- if (fullarg(from, "nolapic") || fullarg(from, "disableapic")) { +- clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); +- disable_apic = 1; +- } +- +- if (fullarg(from, "noapic")) +- skip_ioapic_setup = 1; +- +- if (fullarg(from,"apic")) { +- skip_ioapic_setup = 0; +- ioapic_force = 1; +- } +-#endif +- +- if (!memcmp(from, "mem=", 4)) +- parse_memopt(from+4, &from); +- +- if (!memcmp(from, "memmap=", 7)) { +- /* exactmap option is for used defined memory */ +- if (!memcmp(from+7, "exactmap", 8)) { +-#ifdef CONFIG_CRASH_DUMP +- /* If we are doing a crash dump, we +- * still need to know the real mem +- * size before original memory map is +- * reset. +- */ +- saved_max_pfn = e820_end_of_ram(); +-#endif +- from += 8+7; +- end_pfn_map = 0; +- e820.nr_map = 0; +- userdef = 1; +- } +- else { +- parse_memmapopt(from+7, &from); +- userdef = 1; +- } +- } +- +-#ifdef CONFIG_NUMA +- if (!memcmp(from, "numa=", 5)) +- numa_setup(from+5); ++early_param("elfcorehdr", setup_elfcorehdr); + #endif + +- if (!memcmp(from,"iommu=",6)) { +- iommu_setup(from+6); +- } +- +- if (fullarg(from,"oops=panic")) +- panic_on_oops = 1; +- +- if (!memcmp(from, "noexec=", 7)) +- nonx_setup(from + 7); +- +-#ifdef CONFIG_KEXEC +- /* crashkernel=size@addr specifies the location to reserve for +- * a crash kernel. By reserving this memory we guarantee +- * that linux never set's it up as a DMA target. +- * Useful for holding code to do something appropriate +- * after a kernel panic. +- */ +- else if (!memcmp(from, "crashkernel=", 12)) { +-#ifndef CONFIG_XEN +- unsigned long size, base; +- size = memparse(from+12, &from); +- if (*from == '@') { +- base = memparse(from+1, &from); +- /* FIXME: Do I want a sanity check +- * to validate the memory range? +- */ +- crashk_res.start = base; +- crashk_res.end = base + size - 1; +- } +-#else +- printk("Ignoring crashkernel command line, " +- "parameter will be supplied by xen\n"); +-#endif +- } +-#endif +- +-#ifdef CONFIG_PROC_VMCORE +- /* elfcorehdr= specifies the location of elf core header +- * stored by the crashed kernel. This option will be passed +- * by kexec loader to the capture kernel. +- */ +- else if(!memcmp(from, "elfcorehdr=", 11)) +- elfcorehdr_addr = memparse(from+11, &from); +-#endif +- +-#if defined(CONFIG_HOTPLUG_CPU) && !defined(CONFIG_XEN) +- else if (!memcmp(from, "additional_cpus=", 16)) +- setup_additional_cpus(from+16); +-#endif +- +- next_char: +- c = *(from++); +- if (!c) +- break; +- if (COMMAND_LINE_SIZE <= ++len) +- break; +- *(to++) = c; +- } +- if (userdef) { +- printk(KERN_INFO "user-defined physical RAM map:\n"); +- e820_print_map("user"); +- } +- *to = '\0'; +- *cmdline_p = command_line; +-} +- + #ifndef CONFIG_NUMA + static void __init + contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn) +@@ -521,10 +334,11 @@ contig_initmem_init(unsigned long start_ + if (bootmap == -1L) + panic("Cannot find bootmem map of size %ld\n",bootmap_size); + bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn); ++ e820_register_active_regions(0, start_pfn, end_pfn); + #ifdef CONFIG_XEN +- e820_bootmem_free(NODE_DATA(0), 0, xen_start_info->nr_pages<nr_pages); + #else +- e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT); ++ free_bootmem_with_active_regions(0, end_pfn); + #endif + reserve_bootmem(bootmap, bootmap_size); + } +@@ -587,6 +401,10 @@ static void discover_ebda(void) + void __init setup_arch(char **cmdline_p) + { + #ifdef CONFIG_XEN ++ extern struct e820map machine_e820; ++ ++ printk(KERN_INFO "Command line: %s\n", saved_command_line); ++ + /* Register a call for panic conditions. */ + atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); + +@@ -612,6 +430,8 @@ void __init setup_arch(char **cmdline_p) + + ARCH_SETUP + #else ++ printk(KERN_INFO "Command line: %s\n", saved_command_line); ++ + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); + screen_info = SCREEN_INFO; + edid_info = EDID_INFO; +@@ -639,16 +459,22 @@ void __init setup_arch(char **cmdline_p) + data_resource.start = virt_to_phys(&_etext); + data_resource.end = virt_to_phys(&_edata)-1; + +- parse_cmdline_early(cmdline_p); +- + early_identify_cpu(&boot_cpu_data); + ++ strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); ++ *cmdline_p = command_line; ++ ++ parse_early_param(); ++ ++ finish_e820_parsing(); ++ ++ e820_register_active_regions(0, 0, -1UL); + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + end_pfn = e820_end_of_ram(); +- num_physpages = end_pfn; /* for pfn_valid */ ++ num_physpages = end_pfn; + + check_efer(); + +@@ -659,6 +485,14 @@ void __init setup_arch(char **cmdline_p) + if (is_initial_xendomain()) + dmi_scan_machine(); + ++ /* How many end-of-memory variables you have, grandma! */ ++ max_low_pfn = end_pfn; ++ max_pfn = end_pfn; ++ high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1; ++ ++ /* Remove active ranges so rediscovery with NUMA-awareness happens */ ++ remove_all_active_ranges(); ++ + #ifdef CONFIG_ACPI_NUMA + /* + * Parse SRAT to discover nodes. +@@ -848,16 +682,16 @@ void __init setup_arch(char **cmdline_p) + BUG(); + } + ++#ifdef CONFIG_ACPI + if (!is_initial_xendomain()) { + acpi_disabled = 1; +-#ifdef CONFIG_ACPI + acpi_ht = 0; +-#endif + } + #endif ++#endif + +-#ifndef CONFIG_XEN +- check_ioapic(); ++#if defined(CONFIG_PCI) && !defined(CONFIG_XEN) ++ early_quirks(); + #endif + + zap_low_mappings(0); +@@ -907,6 +741,7 @@ void __init setup_arch(char **cmdline_p) + e820_reserve_resources(machine_e820.map, machine_e820.nr_map); + #else + e820_reserve_resources(e820.map, e820.nr_map); ++ e820_mark_nosave_regions(); + #endif + + request_resource(&iomem_resource, &video_ram_resource); +@@ -914,7 +749,7 @@ void __init setup_arch(char **cmdline_p) + { + unsigned i; + /* request I/O space for devices used on all i[345]86 PCs */ +- for (i = 0; i < STANDARD_IO_RESOURCES; i++) ++ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) + request_resource(&ioport_resource, &standard_io_resources[i]); + } + +@@ -1098,7 +933,7 @@ static void __init amd_detect_cmp(struct + #endif + } + +-static void __init init_amd(struct cpuinfo_x86 *c) ++static void __cpuinit init_amd(struct cpuinfo_x86 *c) + { + unsigned level; + +@@ -1154,6 +989,12 @@ static void __init init_amd(struct cpuin + + /* Fix cpuid4 emulation for more */ + num_cache_leaves = 3; ++ ++ /* When there is only one core no need to synchronize RDTSC */ ++ if (num_possible_cpus() == 1) ++ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ else ++ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); + } + + static void __cpuinit detect_ht(struct cpuinfo_x86 *c) +@@ -1235,8 +1076,7 @@ static void srat_detect_node(void) + node = first_node(node_online_map); + numa_set_node(cpu, node); + +- if (acpi_numa > 0) +- printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node); ++ printk(KERN_INFO "CPU %d/%x -> Node %d\n", cpu, apicid, node); + #endif + } + +@@ -1270,6 +1110,8 @@ static void __cpuinit init_intel(struct + if ((c->x86 == 0xf && c->x86_model >= 0x03) || + (c->x86 == 0x6 && c->x86_model >= 0x0e)) + set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); ++ if (c->x86 == 6) ++ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); + set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); + c->x86_max_cores = intel_num_cpu_cores(c); + +@@ -1488,8 +1330,8 @@ static int show_cpuinfo(struct seq_file + + /* Intel-defined (#2) */ + "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", +- "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL, +- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, ++ NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* VIA/Cyrix/Centaur-defined */ +--- sle11-2009-05-14.orig/arch/x86/kernel/setup64-xen.c 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/setup64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -31,7 +31,7 @@ + #include + #endif + +-char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,}; ++char x86_boot_params[BOOT_PARAM_SIZE] __initdata; + + cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; + +@@ -55,8 +55,10 @@ Control non executable mappings for 64bi + on Enable(default) + off Disable + */ +-int __init nonx_setup(char *str) ++static int __init nonx_setup(char *str) + { ++ if (!str) ++ return -EINVAL; + if (!strncmp(str, "on", 2)) { + __supported_pte_mask |= _PAGE_NX; + do_not_nx = 0; +@@ -64,9 +66,9 @@ int __init nonx_setup(char *str) + do_not_nx = 1; + __supported_pte_mask &= ~_PAGE_NX; + } +- return 1; ++ return 0; + } +-__setup("noexec=", nonx_setup); /* parsed early actually */ ++early_param("noexec", nonx_setup); + + int force_personality32 = 0; + +@@ -102,12 +104,9 @@ void __init setup_per_cpu_areas(void) + #endif + + /* Copy section for each CPU (we discard the original) */ +- size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); +-#ifdef CONFIG_MODULES +- if (size < PERCPU_ENOUGH_ROOM) +- size = PERCPU_ENOUGH_ROOM; +-#endif ++ size = PERCPU_ENOUGH_ROOM; + ++ printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", size); + for_each_cpu_mask (i, cpu_possible_map) { + char *ptr; + +@@ -169,7 +168,10 @@ void pda_init(int cpu) + /* Setup up data that may be needed in __get_free_pages early */ + asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); + #ifndef CONFIG_XEN ++ /* Memory clobbers used to order PDA accessed */ ++ mb(); + wrmsrl(MSR_GS_BASE, pda); ++ mb(); + #else + if (HYPERVISOR_set_segment_base(SEGBASE_GS_KERNEL, + (unsigned long)pda)) +@@ -302,28 +304,17 @@ void __cpuinit cpu_init (void) + * set up and load the per-CPU TSS + */ + for (v = 0; v < N_EXCEPTION_STACKS; v++) { ++ static const unsigned int order[N_EXCEPTION_STACKS] = { ++ [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, ++ [DEBUG_STACK - 1] = DEBUG_STACK_ORDER ++ }; + if (cpu) { +- static const unsigned int order[N_EXCEPTION_STACKS] = { +- [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER, +- [DEBUG_STACK - 1] = DEBUG_STACK_ORDER +- }; +- + estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]); + if (!estacks) + panic("Cannot allocate exception stack %ld %d\n", + v, cpu); + } +- switch (v + 1) { +-#if DEBUG_STKSZ > EXCEPTION_STKSZ +- case DEBUG_STACK: +- cpu_pda(cpu)->debugstack = (unsigned long)estacks; +- estacks += DEBUG_STKSZ; +- break; +-#endif +- default: +- estacks += EXCEPTION_STKSZ; +- break; +- } ++ estacks += PAGE_SIZE << order[v]; + orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks; + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/smp_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/smp_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -381,9 +381,8 @@ int smp_call_function_single (int cpu, v + /* prevent preemption and reschedule on another processor */ + int me = get_cpu(); + if (cpu == me) { +- WARN_ON(1); + put_cpu(); +- return -EBUSY; ++ return 0; + } + spin_lock_bh(&call_lock); + __smp_call_function_single(cpu, func, info, nonatomic, wait); +@@ -501,7 +500,7 @@ void smp_send_stop(void) + #ifndef CONFIG_XEN + asmlinkage void smp_reschedule_interrupt(void) + #else +-asmlinkage irqreturn_t smp_reschedule_interrupt(void) ++asmlinkage irqreturn_t smp_reschedule_interrupt(int irq, void *ctx) + #endif + { + #ifndef CONFIG_XEN +@@ -514,7 +513,7 @@ asmlinkage irqreturn_t smp_reschedule_in + #ifndef CONFIG_XEN + asmlinkage void smp_call_function_interrupt(void) + #else +-asmlinkage irqreturn_t smp_call_function_interrupt(void) ++asmlinkage irqreturn_t smp_call_function_interrupt(int irq, void *ctx) + #endif + { + void (*func) (void *info) = call_data->func; +@@ -545,31 +544,3 @@ asmlinkage irqreturn_t smp_call_function + return IRQ_HANDLED; + #endif + } +- +-int safe_smp_processor_id(void) +-{ +-#ifdef CONFIG_XEN +- return smp_processor_id(); +-#else +- unsigned apicid, i; +- +- if (disable_apic) +- return 0; +- +- apicid = hard_smp_processor_id(); +- if (apicid < NR_CPUS && x86_cpu_to_apicid[apicid] == apicid) +- return apicid; +- +- for (i = 0; i < NR_CPUS; ++i) { +- if (x86_cpu_to_apicid[i] == apicid) +- return i; +- } +- +- /* No entries in x86_cpu_to_apicid? Either no MPS|ACPI, +- * or called too early. Either way, we must be CPU 0. */ +- if (x86_cpu_to_apicid[0] == BAD_APICID) +- return 0; +- +- return 0; /* Should not happen */ +-#endif +-} +--- sle11-2009-05-14.orig/arch/x86/kernel/traps_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/traps_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -45,6 +46,7 @@ + #include + #include + #include ++#include + + asmlinkage void divide_error(void); + asmlinkage void debug(void); +@@ -114,7 +116,6 @@ static int call_trace = 1; + #endif + + #ifdef CONFIG_KALLSYMS +-# include + void printk_address(unsigned long address) + { + unsigned long offset = 0, symsize; +@@ -142,7 +143,7 @@ void printk_address(unsigned long addres + #endif + + static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, +- unsigned *usedp, const char **idp) ++ unsigned *usedp, char **idp) + { + #ifndef CONFIG_X86_NO_TSS + static char ids[][8] = { +@@ -162,26 +163,7 @@ static unsigned long *in_exception_stack + * 'stack' is in one of them: + */ + for (k = 0; k < N_EXCEPTION_STACKS; k++) { +- unsigned long end; +- +- /* +- * set 'end' to the end of the exception stack. +- */ +- switch (k + 1) { +- /* +- * TODO: this block is not needed i think, because +- * setup64.c:cpu_init() sets up t->ist[DEBUG_STACK] +- * properly too. +- */ +-#if DEBUG_STKSZ > EXCEPTION_STKSZ +- case DEBUG_STACK: +- end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ; +- break; +-#endif +- default: +- end = per_cpu(orig_ist, cpu).ist[k]; +- break; +- } ++ unsigned long end = per_cpu(orig_ist, cpu).ist[k]; + /* + * Is 'stack' above this exception frame's end? + * If yes then skip to the next frame. +@@ -236,13 +218,19 @@ static unsigned long *in_exception_stack + return NULL; + } + +-static int show_trace_unwind(struct unwind_frame_info *info, void *context) ++struct ops_and_data { ++ struct stacktrace_ops *ops; ++ void *data; ++}; ++ ++static int dump_trace_unwind(struct unwind_frame_info *info, void *context) + { ++ struct ops_and_data *oad = (struct ops_and_data *)context; + int n = 0; + + while (unwind(info) == 0 && UNW_PC(info)) { + n++; +- printk_address(UNW_PC(info)); ++ oad->ops->address(oad->data, UNW_PC(info)); + if (arch_unw_user_mode(info)) + break; + } +@@ -256,13 +244,19 @@ static int show_trace_unwind(struct unwi + * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack + */ + +-void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack) ++static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) + { +- const unsigned cpu = safe_smp_processor_id(); ++ void *t = (void *)tinfo; ++ return p > t && p < t + THREAD_SIZE - 3; ++} ++ ++void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, ++ struct stacktrace_ops *ops, void *data) ++{ ++ const unsigned cpu = smp_processor_id(); + unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; + unsigned used = 0; +- +- printk("\nCall Trace:\n"); ++ struct thread_info *tinfo; + + if (!tsk) + tsk = current; +@@ -270,32 +264,47 @@ void show_trace(struct task_struct *tsk, + if (call_trace >= 0) { + int unw_ret = 0; + struct unwind_frame_info info; ++ struct ops_and_data oad = { .ops = ops, .data = data }; + + if (regs) { + if (unwind_init_frame_info(&info, tsk, regs) == 0) +- unw_ret = show_trace_unwind(&info, NULL); ++ unw_ret = dump_trace_unwind(&info, &oad); + } else if (tsk == current) +- unw_ret = unwind_init_running(&info, show_trace_unwind, NULL); ++ unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); + else { + if (unwind_init_blocked(&info, tsk) == 0) +- unw_ret = show_trace_unwind(&info, NULL); ++ unw_ret = dump_trace_unwind(&info, &oad); + } + if (unw_ret > 0) { + if (call_trace == 1 && !arch_unw_user_mode(&info)) { +- print_symbol("DWARF2 unwinder stuck at %s\n", ++ ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", + UNW_PC(&info)); + if ((long)UNW_SP(&info) < 0) { +- printk("Leftover inexact backtrace:\n"); ++ ops->warning(data, "Leftover inexact backtrace:\n"); + stack = (unsigned long *)UNW_SP(&info); ++ if (!stack) ++ return; + } else +- printk("Full inexact backtrace again:\n"); ++ ops->warning(data, "Full inexact backtrace again:\n"); + } else if (call_trace >= 1) + return; + else +- printk("Full inexact backtrace again:\n"); ++ ops->warning(data, "Full inexact backtrace again:\n"); + } else +- printk("Inexact backtrace:\n"); ++ ops->warning(data, "Inexact backtrace:\n"); + } ++ if (!stack) { ++ unsigned long dummy; ++ stack = &dummy; ++ if (tsk && tsk != current) ++ stack = (unsigned long *)tsk->thread.rsp; ++ } ++ /* ++ * Align the stack pointer on word boundary, later loops ++ * rely on that (and corruption / debug info bugs can cause ++ * unaligned values here): ++ */ ++ stack = (unsigned long *)((unsigned long)stack & ~(sizeof(long)-1)); + + /* + * Print function call entries within a stack. 'cond' is the +@@ -305,7 +314,9 @@ void show_trace(struct task_struct *tsk, + #define HANDLE_STACK(cond) \ + do while (cond) { \ + unsigned long addr = *stack++; \ +- if (kernel_text_address(addr)) { \ ++ if (oops_in_progress ? \ ++ __kernel_text_address(addr) : \ ++ kernel_text_address(addr)) { \ + /* \ + * If the address is either in the text segment of the \ + * kernel, or in the region which contains vmalloc'ed \ +@@ -314,7 +325,7 @@ void show_trace(struct task_struct *tsk, + * down the cause of the crash will be able to figure \ + * out the call path that was taken. \ + */ \ +- printk_address(addr); \ ++ ops->address(data, addr); \ + } \ + } while (0) + +@@ -323,16 +334,17 @@ void show_trace(struct task_struct *tsk, + * current stack address. If the stacks consist of nested + * exceptions + */ +- for ( ; ; ) { +- const char *id; ++ for (;;) { ++ char *id; + unsigned long *estack_end; + estack_end = in_exception_stack(cpu, (unsigned long)stack, + &used, &id); + + if (estack_end) { +- printk(" <%s>", id); ++ if (ops->stack(data, id) < 0) ++ break; + HANDLE_STACK (stack < estack_end); +- printk(" "); ++ ops->stack(data, ""); + /* + * We link to the next stack via the + * second-to-last pointer (index -2 to end) in the +@@ -347,7 +359,8 @@ void show_trace(struct task_struct *tsk, + (IRQSTACKSIZE - 64) / sizeof(*irqstack); + + if (stack >= irqstack && stack < irqstack_end) { +- printk(" "); ++ if (ops->stack(data, "IRQ") < 0) ++ break; + HANDLE_STACK (stack < irqstack_end); + /* + * We link to the next stack (which would be +@@ -356,7 +369,7 @@ void show_trace(struct task_struct *tsk, + */ + stack = (unsigned long *) (irqstack_end[-1]); + irqstack_end = NULL; +- printk(" "); ++ ops->stack(data, "EOI"); + continue; + } + } +@@ -364,19 +377,58 @@ void show_trace(struct task_struct *tsk, + } + + /* +- * This prints the process stack: ++ * This handles the process stack: + */ +- HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); ++ tinfo = current_thread_info(); ++ HANDLE_STACK (valid_stack_ptr(tinfo, stack)); + #undef HANDLE_STACK ++} ++EXPORT_SYMBOL(dump_trace); + ++static void ++print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) ++{ ++ print_symbol(msg, symbol); + printk("\n"); + } + +-static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp) ++static void print_trace_warning(void *data, char *msg) ++{ ++ printk("%s\n", msg); ++} ++ ++static int print_trace_stack(void *data, char *name) ++{ ++ printk(" <%s> ", name); ++ return 0; ++} ++ ++static void print_trace_address(void *data, unsigned long addr) ++{ ++ printk_address(addr); ++} ++ ++static struct stacktrace_ops print_trace_ops = { ++ .warning = print_trace_warning, ++ .warning_symbol = print_trace_warning_symbol, ++ .stack = print_trace_stack, ++ .address = print_trace_address, ++}; ++ ++void ++show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack) ++{ ++ printk("\nCall Trace:\n"); ++ dump_trace(tsk, regs, stack, &print_trace_ops, NULL); ++ printk("\n"); ++} ++ ++static void ++_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *rsp) + { + unsigned long *stack; + int i; +- const int cpu = safe_smp_processor_id(); ++ const int cpu = smp_processor_id(); + unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr); + unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); + +@@ -430,7 +482,7 @@ void show_registers(struct pt_regs *regs + int i; + int in_kernel = !user_mode(regs); + unsigned long rsp; +- const int cpu = safe_smp_processor_id(); ++ const int cpu = smp_processor_id(); + struct task_struct *cur = cpu_pda(cpu)->pcurrent; + + rsp = regs->rsp; +@@ -505,9 +557,11 @@ static unsigned int die_nest_count; + + unsigned __kprobes long oops_begin(void) + { +- int cpu = safe_smp_processor_id(); ++ int cpu = smp_processor_id(); + unsigned long flags; + ++ oops_enter(); ++ + /* racy, but better than risking deadlock. */ + local_irq_save(flags); + if (!spin_trylock(&die_lock)) { +@@ -536,6 +590,7 @@ void __kprobes oops_end(unsigned long fl + spin_unlock_irqrestore(&die_lock, flags); + if (panic_on_oops) + panic("Fatal exception"); ++ oops_exit(); + } + + void __kprobes __die(const char * str, struct pt_regs * regs, long err) +@@ -572,8 +627,8 @@ void die(const char * str, struct pt_reg + do_exit(SIGSEGV); + } + +-#ifdef CONFIG_X86_LOCAL_APIC +-void __kprobes die_nmi(char *str, struct pt_regs *regs) ++#if defined(CONFIG_X86_LOCAL_APIC) || defined(CONFIG_SYSCTL) ++void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) + { + unsigned long flags = oops_begin(); + +@@ -581,13 +636,12 @@ void __kprobes die_nmi(char *str, struct + * We are in trouble anyway, lets at least try + * to get a message out. + */ +- printk(str, safe_smp_processor_id()); ++ printk(str, smp_processor_id()); + show_registers(regs); + if (kexec_should_crash(current)) + crash_kexec(regs); +- if (panic_on_timeout || panic_on_oops) +- panic("nmi watchdog"); +- printk("console shuts up ...\n"); ++ if (do_panic || panic_on_oops) ++ panic("Non maskable interrupt"); + oops_end(flags); + nmi_exit(); + local_irq_enable(); +@@ -734,8 +788,15 @@ asmlinkage void __kprobes do_general_pro + static __kprobes void + mem_parity_error(unsigned char reason, struct pt_regs * regs) + { +- printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); +- printk("You probably have a hardware problem with your RAM chips\n"); ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", ++ reason); ++ printk(KERN_EMERG "You probably have a hardware problem with your " ++ "RAM chips\n"); ++ ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + + #if 0 /* XEN */ + /* Clear and disable the memory parity error line. */ +@@ -762,9 +823,15 @@ io_check_error(unsigned char reason, str + + static __kprobes void + unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +-{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); +- printk("Dazed and confused, but trying to continue\n"); +- printk("Do you have a strange power saving mode enabled?\n"); ++{ ++ printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", ++ reason); ++ printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); ++ ++ if (panic_on_unrecovered_nmi) ++ panic("NMI: Not continuing"); ++ ++ printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + } + + /* Runs on IST stack. This code must keep interrupts off all the time. +@@ -789,12 +856,12 @@ asmlinkage __kprobes void default_do_nmi + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ +- if (nmi_watchdog > 0) { +- nmi_watchdog_tick(regs,reason); ++ if (nmi_watchdog_tick(regs,reason)) + return; +- } + #endif +- unknown_nmi_error(reason, regs); ++ if (!do_nmi_callback(regs,cpu)) ++ unknown_nmi_error(reason, regs); ++ + return; + } + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) +@@ -1081,6 +1148,7 @@ asmlinkage void math_state_restore(void) + init_fpu(me); + restore_fpu_checking(&me->thread.i387.fxsave); + task_thread_info(me)->status |= TS_USEDFPU; ++ me->fpu_counter++; + } + + +@@ -1141,24 +1209,30 @@ void __cpuinit smp_trap_init(trap_info_t + } + + +-/* Actual parsing is done early in setup.c. */ +-static int __init oops_dummy(char *s) ++static int __init oops_setup(char *s) + { +- panic_on_oops = 1; +- return 1; ++ if (!s) ++ return -EINVAL; ++ if (!strcmp(s, "panic")) ++ panic_on_oops = 1; ++ return 0; + } +-__setup("oops=", oops_dummy); ++early_param("oops", oops_setup); + + static int __init kstack_setup(char *s) + { ++ if (!s) ++ return -EINVAL; + kstack_depth_to_print = simple_strtoul(s,NULL,0); +- return 1; ++ return 0; + } +-__setup("kstack=", kstack_setup); ++early_param("kstack", kstack_setup); + + #ifdef CONFIG_STACK_UNWIND + static int __init call_trace_setup(char *s) + { ++ if (!s) ++ return -EINVAL; + if (strcmp(s, "old") == 0) + call_trace = -1; + else if (strcmp(s, "both") == 0) +@@ -1167,7 +1241,7 @@ static int __init call_trace_setup(char + call_trace = 1; + else if (strcmp(s, "new") == 0) + call_trace = 2; +- return 1; ++ return 0; + } +-__setup("call_trace=", call_trace_setup); ++early_param("call_trace", call_trace_setup); + #endif +--- sle11-2009-05-14.orig/arch/x86/kernel/vsyscall_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/vsyscall_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -26,6 +26,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + #include + #include +@@ -33,11 +37,15 @@ + #include + #include + #include ++#include ++#include ++#include + + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) + + int __sysctl_vsyscall __section_sysctl_vsyscall = 1; + seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; ++int __vgetcpu_mode __section_vgetcpu_mode; + + #include + +@@ -61,8 +69,7 @@ static __always_inline void do_vgettimeo + sequence = read_seqbegin(&__xtime_lock); + + sec = __xtime.tv_sec; +- usec = (__xtime.tv_nsec / 1000) + +- (__jiffies - __wall_jiffies) * (1000000 / HZ); ++ usec = __xtime.tv_nsec / 1000; + + if (__vxtime.mode != VXTIME_HPET) { + t = get_cycles_sync(); +@@ -72,7 +79,8 @@ static __always_inline void do_vgettimeo + __vxtime.tsc_quot) >> 32; + /* See comment in x86_64 do_gettimeofday. */ + } else { +- usec += ((readl((void *)fix_to_virt(VSYSCALL_HPET) + 0xf0) - ++ usec += ((readl((void __iomem *) ++ fix_to_virt(VSYSCALL_HPET) + 0xf0) - + __vxtime.last) * __vxtime.quot) >> 32; + } + } while (read_seqretry(&__xtime_lock, sequence)); +@@ -127,9 +135,46 @@ time_t __vsyscall(1) vtime(time_t *t) + return __xtime.tv_sec; + } + +-long __vsyscall(2) venosys_0(void) +-{ +- return -ENOSYS; ++/* Fast way to get current CPU and node. ++ This helps to do per node and per CPU caches in user space. ++ The result is not guaranteed without CPU affinity, but usually ++ works out because the scheduler tries to keep a thread on the same ++ CPU. ++ ++ tcache must point to a two element sized long array. ++ All arguments can be NULL. */ ++long __vsyscall(2) ++vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) ++{ ++ unsigned int dummy, p; ++ unsigned long j = 0; ++ ++ /* Fast cache - only recompute value once per jiffies and avoid ++ relatively costly rdtscp/cpuid otherwise. ++ This works because the scheduler usually keeps the process ++ on the same CPU and this syscall doesn't guarantee its ++ results anyways. ++ We do this here because otherwise user space would do it on ++ its own in a likely inferior way (no access to jiffies). ++ If you don't like it pass NULL. */ ++ if (tcache && tcache->blob[0] == (j = __jiffies)) { ++ p = tcache->blob[1]; ++ } else if (__vgetcpu_mode == VGETCPU_RDTSCP) { ++ /* Load per CPU data from RDTSCP */ ++ rdtscp(dummy, dummy, p); ++ } else { ++ /* Load per CPU data from GDT */ ++ asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG)); ++ } ++ if (tcache) { ++ tcache->blob[0] = j; ++ tcache->blob[1] = p; ++ } ++ if (cpu) ++ *cpu = p & 0xfff; ++ if (node) ++ *node = p >> 12; ++ return 0; + } + + long __vsyscall(3) venosys_1(void) +@@ -149,7 +194,8 @@ static int vsyscall_sysctl_change(ctl_ta + void __user *buffer, size_t *lenp, loff_t *ppos) + { + extern u16 vsysc1, vsysc2; +- u16 *map1, *map2; ++ u16 __iomem *map1; ++ u16 __iomem *map2; + int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); + if (!write) + return ret; +@@ -164,11 +210,11 @@ static int vsyscall_sysctl_change(ctl_ta + goto out; + } + if (!sysctl_vsyscall) { +- *map1 = SYSCALL; +- *map2 = SYSCALL; ++ writew(SYSCALL, map1); ++ writew(SYSCALL, map2); + } else { +- *map1 = NOP2; +- *map2 = NOP2; ++ writew(NOP2, map1); ++ writew(NOP2, map2); + } + iounmap(map2); + out: +@@ -200,6 +246,48 @@ static ctl_table kernel_root_table2[] = + + #endif + ++/* Assume __initcall executes before all user space. Hopefully kmod ++ doesn't violate that. We'll find out if it does. */ ++static void __cpuinit vsyscall_set_cpu(int cpu) ++{ ++ unsigned long d; ++ unsigned long node = 0; ++#ifdef CONFIG_NUMA ++ node = cpu_to_node[cpu]; ++#endif ++ if (cpu_has(&cpu_data[cpu], X86_FEATURE_RDTSCP)) ++ write_rdtscp_aux((node << 12) | cpu); ++ ++ /* Store cpu number in limit so that it can be loaded quickly ++ in user space in vgetcpu. ++ 12 bits for the CPU and 8 bits for the node. */ ++ d = 0x0f40000000000ULL; ++ d |= cpu; ++ d |= (node & 0xf) << 12; ++ d |= (node >> 4) << 48; ++ if (HYPERVISOR_update_descriptor(virt_to_machine(cpu_gdt(cpu) ++ + GDT_ENTRY_PER_CPU), ++ d)) ++ BUG(); ++} ++ ++static void __cpuinit cpu_vsyscall_init(void *arg) ++{ ++ /* preemption should be already off */ ++ vsyscall_set_cpu(raw_smp_processor_id()); ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static int __cpuinit ++cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) ++{ ++ long cpu = (long)arg; ++ if (action == CPU_ONLINE) ++ smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); ++ return NOTIFY_DONE; ++} ++#endif ++ + static void __init map_vsyscall(void) + { + extern char __vsyscall_0; +@@ -214,13 +302,20 @@ static int __init vsyscall_init(void) + VSYSCALL_ADDR(__NR_vgettimeofday))); + BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); + BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); ++ BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); + map_vsyscall(); + #ifdef CONFIG_XEN + sysctl_vsyscall = 0; /* disable vgettimeofay() */ ++ if (boot_cpu_has(X86_FEATURE_RDTSCP)) ++ vgetcpu_mode = VGETCPU_RDTSCP; ++ else ++ vgetcpu_mode = VGETCPU_LSL; + #endif + #ifdef CONFIG_SYSCTL + register_sysctl_table(kernel_root_table2, 0); + #endif ++ on_each_cpu(cpu_vsyscall_init, NULL, 0, 1); ++ hotcpu_notifier(cpu_vsyscall_notifier, 0); + return 0; + } + +--- sle11-2009-05-14.orig/arch/x86/mm/fault_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mm/fault_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -40,8 +40,7 @@ + #define PF_RSVD (1<<3) + #define PF_INSTR (1<<4) + +-#ifdef CONFIG_KPROBES +-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); ++static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); + + /* Hook to register for page fault notifications */ + int register_page_fault_notifier(struct notifier_block *nb) +@@ -49,11 +48,13 @@ int register_page_fault_notifier(struct + vmalloc_sync_all(); + return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); + } ++EXPORT_SYMBOL_GPL(register_page_fault_notifier); + + int unregister_page_fault_notifier(struct notifier_block *nb) + { + return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); + } ++EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); + + static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +@@ -67,13 +68,6 @@ static inline int notify_page_fault(enum + }; + return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); + } +-#else +-static inline int notify_page_fault(enum die_val val, const char *str, +- struct pt_regs *regs, long err, int trap, int sig) +-{ +- return NOTIFY_DONE; +-} +-#endif + + void bust_spinlocks(int yes) + { +@@ -102,7 +96,7 @@ void bust_spinlocks(int yes) + static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, + unsigned long error_code) + { +- unsigned char *instr; ++ unsigned char __user *instr; + int scan_more = 1; + int prefetch = 0; + unsigned char *max_instr; +@@ -111,7 +105,7 @@ static noinline int is_prefetch(struct p + if (error_code & PF_INSTR) + return 0; + +- instr = (unsigned char *)convert_rip_to_linear(current, regs); ++ instr = (unsigned char __user *)convert_rip_to_linear(current, regs); + max_instr = instr + 15; + + if (user_mode(regs) && instr >= (unsigned char *)TASK_SIZE) +@@ -122,7 +116,7 @@ static noinline int is_prefetch(struct p + unsigned char instr_hi; + unsigned char instr_lo; + +- if (__get_user(opcode, instr)) ++ if (__get_user(opcode, (char __user *)instr)) + break; + + instr_hi = opcode & 0xf0; +@@ -160,7 +154,7 @@ static noinline int is_prefetch(struct p + case 0x00: + /* Prefetch instruction is 0x0F0D or 0x0F18 */ + scan_more = 0; +- if (__get_user(opcode, instr)) ++ if (__get_user(opcode, (char __user *)instr)) + break; + prefetch = (instr_lo == 0xF) && + (opcode == 0x0D || opcode == 0x18); +@@ -176,7 +170,7 @@ static noinline int is_prefetch(struct p + static int bad_address(void *p) + { + unsigned long dummy; +- return __get_user(dummy, (unsigned long *)p); ++ return __get_user(dummy, (unsigned long __user *)p); + } + + void dump_pagetable(unsigned long address) +@@ -248,7 +242,7 @@ static int is_errata93(struct pt_regs *r + + int unhandled_signal(struct task_struct *tsk, int sig) + { +- if (tsk->pid == 1) ++ if (is_init(tsk)) + return 1; + if (tsk->ptrace & PT_PTRACED) + return 0; +@@ -300,7 +294,7 @@ static int vmalloc_fault(unsigned long a + if (pgd_none(*pgd)) + set_pgd(pgd, *pgd_ref); + else +- BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref)); ++ BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); + + /* Below here mismatches are bugs because these lower tables + are shared */ +@@ -309,7 +303,7 @@ static int vmalloc_fault(unsigned long a + pud_ref = pud_offset(pgd_ref, address); + if (pud_none(*pud_ref)) + return -1; +- if (pud_none(*pud) || pud_page(*pud) != pud_page(*pud_ref)) ++ if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref)) + BUG(); + pmd = pmd_offset(pud, address); + pmd_ref = pmd_offset(pud_ref, address); +@@ -531,7 +525,7 @@ good_area: + case PF_PROT: /* read, present */ + goto bad_area; + case 0: /* read, not present */ +- if (!(vma->vm_flags & (VM_READ | VM_EXEC))) ++ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) + goto bad_area; + } + +@@ -647,7 +641,7 @@ no_context: + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (current->pid == 1) { ++ if (is_init(current)) { + yield(); + goto again; + } +@@ -702,7 +696,7 @@ void vmalloc_sync_all(void) + if (pgd_none(*pgd)) + set_pgd(pgd, *pgd_ref); + else +- BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref)); ++ BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); + } + spin_unlock(&pgd_lock); + set_bit(pgd_index(address), insync); +--- sle11-2009-05-14.orig/arch/x86/mm/init_64-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/mm/init_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -61,8 +61,6 @@ EXPORT_SYMBOL(__kernel_page_user); + + int after_bootmem; + +-static unsigned long dma_reserve __initdata; +- + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + extern unsigned long start_pfn; + +@@ -420,7 +418,6 @@ __init void *early_ioremap(unsigned long + + /* actually usually some more */ + if (size >= LARGE_PAGE_SIZE) { +- printk("SMBIOS area too long %lu\n", size); + return NULL; + } + set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); +@@ -442,16 +439,24 @@ __init void early_iounmap(void *addr, un + #endif + + static void __meminit +-phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end) ++phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end) + { +- int i, k; ++ int i = pmd_index(address); + +- for (i = 0; i < PTRS_PER_PMD; pmd++, i++) { ++ for (; i < PTRS_PER_PMD; i++) { + unsigned long pte_phys; ++ pmd_t *pmd = pmd_page + i; + pte_t *pte, *pte_save; ++ int k; + + if (address >= end) + break; ++ ++ if (__pmd_val(*pmd)) { ++ address += PMD_SIZE; ++ continue; ++ } ++ + pte = alloc_static_page(&pte_phys); + pte_save = pte; + for (k = 0; k < PTRS_PER_PTE; pte++, k++, address += PTE_SIZE) { +@@ -478,40 +483,35 @@ phys_pmd_init(pmd_t *pmd, unsigned long + static void __meminit + phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end) + { +- pmd_t *pmd = pmd_offset(pud, (unsigned long)__va(address)); +- +- if (pmd_none(*pmd)) { +- spin_lock(&init_mm.page_table_lock); +- phys_pmd_init(pmd, address, end); +- spin_unlock(&init_mm.page_table_lock); +- __flush_tlb_all(); +- } ++ pmd_t *pmd = pmd_offset(pud,0); ++ spin_lock(&init_mm.page_table_lock); ++ phys_pmd_init(pmd, address, end); ++ spin_unlock(&init_mm.page_table_lock); ++ __flush_tlb_all(); + } + +-static void __meminit phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) ++static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end) + { +- long i = pud_index(address); +- +- pud = pud + i; +- +- if (after_bootmem && pud_val(*pud)) { +- phys_pmd_update(pud, address, end); +- return; +- } ++ int i = pud_index(addr); + +- for (; i < PTRS_PER_PUD; pud++, i++) { +- unsigned long paddr, pmd_phys; ++ for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE ) { ++ unsigned long pmd_phys; ++ pud_t *pud = pud_page + pud_index(addr); + pmd_t *pmd; + +- paddr = (address & PGDIR_MASK) + i*PUD_SIZE; +- if (paddr >= end) ++ if (addr >= end) + break; + ++ if (__pud_val(*pud)) { ++ phys_pmd_update(pud, addr, end); ++ continue; ++ } ++ + pmd = alloc_static_page(&pmd_phys); + + spin_lock(&init_mm.page_table_lock); + *pud = __pud(pmd_phys | _KERNPG_TABLE); +- phys_pmd_init(pmd, paddr, end); ++ phys_pmd_init(pmd, addr, end); + spin_unlock(&init_mm.page_table_lock); + + early_make_page_readonly(pmd, XENFEAT_writable_page_tables); +@@ -775,69 +775,18 @@ void __cpuinit zap_low_mappings(int cpu) + #endif + } + +-/* Compute zone sizes for the DMA and DMA32 zones in a node. */ +-__init void +-size_zones(unsigned long *z, unsigned long *h, +- unsigned long start_pfn, unsigned long end_pfn) +-{ +- int i; +- unsigned long w; +- +- for (i = 0; i < MAX_NR_ZONES; i++) +- z[i] = 0; +- +- if (start_pfn < MAX_DMA_PFN) +- z[ZONE_DMA] = MAX_DMA_PFN - start_pfn; +- if (start_pfn < MAX_DMA32_PFN) { +- unsigned long dma32_pfn = MAX_DMA32_PFN; +- if (dma32_pfn > end_pfn) +- dma32_pfn = end_pfn; +- z[ZONE_DMA32] = dma32_pfn - start_pfn; +- } +- z[ZONE_NORMAL] = end_pfn - start_pfn; +- +- /* Remove lower zones from higher ones. */ +- w = 0; +- for (i = 0; i < MAX_NR_ZONES; i++) { +- if (z[i]) +- z[i] -= w; +- w += z[i]; +- } +- +- /* Compute holes */ +- w = start_pfn; +- for (i = 0; i < MAX_NR_ZONES; i++) { +- unsigned long s = w; +- w += z[i]; +- h[i] = e820_hole_size(s, w); +- } +- +- /* Add the space pace needed for mem_map to the holes too. */ +- for (i = 0; i < MAX_NR_ZONES; i++) +- h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE; +- +- /* The 16MB DMA zone has the kernel and other misc mappings. +- Account them too */ +- if (h[ZONE_DMA]) { +- h[ZONE_DMA] += dma_reserve; +- if (h[ZONE_DMA] >= z[ZONE_DMA]) { +- printk(KERN_WARNING +- "Kernel too large and filling up ZONE_DMA?\n"); +- h[ZONE_DMA] = z[ZONE_DMA]; +- } +- } +-} +- + #ifndef CONFIG_NUMA + void __init paging_init(void) + { +- unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES]; ++ unsigned long max_zone_pfns[MAX_NR_ZONES]; ++ memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); ++ max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; ++ max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; ++ max_zone_pfns[ZONE_NORMAL] = end_pfn; + + memory_present(0, 0, end_pfn); + sparse_init(); +- size_zones(zones, holes, 0, end_pfn); +- free_area_init_node(0, NODE_DATA(0), zones, +- __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes); ++ free_area_init_nodes(max_zone_pfns); + + init_mm.context.pinned = 1; + } +@@ -891,36 +840,23 @@ void online_page(struct page *page) + + #ifdef CONFIG_MEMORY_HOTPLUG + /* +- * XXX: memory_add_physaddr_to_nid() is to find node id from physical address +- * via probe interface of sysfs. If acpi notifies hot-add event, then it +- * can tell node id by searching dsdt. But, probe interface doesn't have +- * node id. So, return 0 as node id at this time. +- */ +-#ifdef CONFIG_NUMA +-int memory_add_physaddr_to_nid(u64 start) +-{ +- return 0; +-} +-#endif +- +-/* + * Memory is added always to NORMAL zone. This means you will never get + * additional DMA/DMA32 memory. + */ + int arch_add_memory(int nid, u64 start, u64 size) + { + struct pglist_data *pgdat = NODE_DATA(nid); +- struct zone *zone = pgdat->node_zones + MAX_NR_ZONES-2; ++ struct zone *zone = pgdat->node_zones + ZONE_NORMAL; + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; + int ret; + ++ init_memory_mapping(start, (start + size -1)); ++ + ret = __add_pages(zone, start_pfn, nr_pages); + if (ret) + goto error; + +- init_memory_mapping(start, (start + size -1)); +- + return ret; + error: + printk("%s: Problem encountered in __add_pages!\n", __func__); +@@ -934,7 +870,17 @@ int remove_memory(u64 start, u64 size) + } + EXPORT_SYMBOL_GPL(remove_memory); + +-#else /* CONFIG_MEMORY_HOTPLUG */ ++#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA) ++int memory_add_physaddr_to_nid(u64 start) ++{ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); ++#endif ++ ++#endif /* CONFIG_MEMORY_HOTPLUG */ ++ ++#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE + /* + * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance, + * just online the pages. +@@ -960,7 +906,7 @@ int __add_pages(struct zone *z, unsigned + } + return err; + } +-#endif /* CONFIG_MEMORY_HOTPLUG */ ++#endif + + static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, + kcore_vsyscall; +@@ -972,12 +918,6 @@ void __init mem_init(void) + + pci_iommu_alloc(); + +- /* How many end-of-memory variables you have, grandma! */ +- max_low_pfn = end_pfn; +- max_pfn = end_pfn; +- num_physpages = end_pfn; +- high_memory = (void *) __va(end_pfn * PAGE_SIZE); +- + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); + +@@ -995,7 +935,8 @@ void __init mem_init(void) + init_page_count(pfn_to_page(pfn)); + totalram_pages++; + } +- reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn); ++ reservedpages = end_pfn - totalram_pages - ++ absent_pages_in_range(0, end_pfn); + + after_bootmem = 1; + +@@ -1102,15 +1043,32 @@ void free_initrd_mem(unsigned long start + + void __init reserve_bootmem_generic(unsigned long phys, unsigned len) + { +- /* Should check here against the e820 map to avoid double free */ + #ifdef CONFIG_NUMA + int nid = phys_to_nid(phys); ++#endif ++ unsigned long pfn = phys >> PAGE_SHIFT; ++ if (pfn >= end_pfn) { ++ /* This can happen with kdump kernels when accessing firmware ++ tables. */ ++ if (pfn < end_pfn_map) ++ return; ++ printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %u\n", ++ phys, len); ++ return; ++ } ++ ++ /* Should check here against the e820 map to avoid double free */ ++#ifdef CONFIG_NUMA + reserve_bootmem_node(NODE_DATA(nid), phys, len); + #else + reserve_bootmem(phys, len); + #endif +- if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) ++#ifndef CONFIG_XEN ++ if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) { + dma_reserve += len / PAGE_SIZE; ++ set_dma_reserve(dma_reserve); ++ } ++#endif + } + + int kern_addr_valid(unsigned long addr) +--- sle11-2009-05-14.orig/arch/x86/mm/pageattr_64-xen.c 2008-12-01 11:25:57.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/pageattr_64-xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -377,8 +377,8 @@ static void revert_page(unsigned long ad + BUG_ON(pud_none(*pud)); + pmd = pmd_offset(pud, address); + BUG_ON(__pmd_val(*pmd) & _PAGE_PSE); +- pgprot_val(ref_prot) |= _PAGE_PSE; + large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot); ++ large_pte = pte_mkhuge(large_pte); + set_pte((pte_t *)pmd, large_pte); + } + +@@ -388,32 +388,28 @@ __change_page_attr(unsigned long address + { + pte_t *kpte; + struct page *kpte_page; +- unsigned kpte_flags; + pgprot_t ref_prot2; + kpte = lookup_address(address); + if (!kpte) return 0; + kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK); +- kpte_flags = pte_val(*kpte); + if (pgprot_val(prot) != pgprot_val(ref_prot)) { +- if ((kpte_flags & _PAGE_PSE) == 0) { ++ if (!pte_huge(*kpte)) { + set_pte(kpte, pfn_pte(pfn, prot)); + } else { + /* + * split_large_page will take the reference for this + * change_page_attr on the split page. + */ +- + struct page *split; +- ref_prot2 = __pgprot(pgprot_val(pte_pgprot(*lookup_address(address))) & ~(1<<_PAGE_BIT_PSE)); +- ++ ref_prot2 = pte_pgprot(pte_clrhuge(*kpte)); + split = split_large_page(address, prot, ref_prot2); + if (!split) + return -ENOMEM; +- set_pte(kpte,mk_pte(split, ref_prot2)); ++ set_pte(kpte, mk_pte(split, ref_prot2)); + kpte_page = split; +- } ++ } + page_private(kpte_page)++; +- } else if ((kpte_flags & _PAGE_PSE) == 0) { ++ } else if (!pte_huge(*kpte)) { + set_pte(kpte, pfn_pte(pfn, ref_prot)); + BUG_ON(page_private(kpte_page) == 0); + page_private(kpte_page)--; +@@ -470,10 +466,12 @@ int change_page_attr_addr(unsigned long + * lowmem */ + if (__pa(address) < KERNEL_TEXT_SIZE) { + unsigned long addr2; +- pgprot_t prot2 = prot; ++ pgprot_t prot2; + addr2 = __START_KERNEL_map + __pa(address); +- pgprot_val(prot2) &= ~_PAGE_NX; +- err = __change_page_attr(addr2, pfn, prot2, PAGE_KERNEL_EXEC); ++ /* Make sure the kernel mappings stay executable */ ++ prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); ++ err = __change_page_attr(addr2, pfn, prot2, ++ PAGE_KERNEL_EXEC); + } + } + up_write(&init_mm.mmap_sem); +--- sle11-2009-05-14.orig/drivers/char/tpm/tpm_xen.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/drivers/char/tpm/tpm_xen.c 2009-03-04 11:28:34.000000000 +0100 +@@ -85,8 +85,7 @@ static struct tpm_private *my_priv; + + /* local function prototypes */ + static irqreturn_t tpmif_int(int irq, +- void *tpm_priv, +- struct pt_regs *ptregs); ++ void *tpm_priv); + static void tpmif_rx_action(unsigned long unused); + static int tpmif_connect(struct xenbus_device *dev, + struct tpm_private *tp, +@@ -559,7 +558,7 @@ static void tpmif_rx_action(unsigned lon + } + + +-static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs) ++static irqreturn_t tpmif_int(int irq, void *tpm_priv) + { + struct tpm_private *tp = tpm_priv; + unsigned long flags; +--- sle11-2009-05-14.orig/drivers/pci/Kconfig 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/pci/Kconfig 2009-03-04 11:28:34.000000000 +0100 +@@ -48,7 +48,7 @@ config PCI_DEBUG + config HT_IRQ + bool "Interrupts on hypertransport devices" + default y +- depends on PCI && X86_LOCAL_APIC && X86_IO_APIC ++ depends on PCI && X86_LOCAL_APIC && X86_IO_APIC && !XEN + help + This allows native hypertransport devices to use interrupts. + +--- sle11-2009-05-14.orig/drivers/pci/msi-xen.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/pci/msi-xen.c 2009-04-24 13:31:56.000000000 +0200 +@@ -6,6 +6,7 @@ + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + ++#include + #include + #include + #include +@@ -14,6 +15,7 @@ + #include + #include + #include ++#include + + #include + +@@ -26,14 +28,6 @@ + + static int pci_msi_enable = 1; + +-static struct msi_ops *msi_ops; +- +-int msi_register(struct msi_ops *ops) +-{ +- msi_ops = ops; +- return 0; +-} +- + static LIST_HEAD(msi_dev_head); + DEFINE_SPINLOCK(msi_dev_lock); + +@@ -406,9 +400,9 @@ void pci_restore_msix_state(struct pci_d + * @dev: pointer to the pci_dev data structure of MSI device function + * + * Setup the MSI capability structure of device function with a single +- * MSI vector, regardless of device function is capable of handling ++ * MSI irq, regardless of device function is capable of handling + * multiple messages. A return of zero indicates the successful setup +- * of an entry zero with the new MSI vector or non-zero for otherwise. ++ * of an entry zero with the new MSI irq or non-zero for otherwise. + **/ + static int msi_capability_init(struct pci_dev *dev) + { +@@ -422,11 +416,11 @@ static int msi_capability_init(struct pc + if (pirq < 0) + return -EBUSY; + +- dev->irq = pirq; + /* Set MSI enabled bits */ + enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + dev->msi_enabled = 1; + ++ dev->irq = pirq; + return 0; + } + +@@ -437,8 +431,8 @@ static int msi_capability_init(struct pc + * @nvec: number of @entries + * + * Setup the MSI-X capability structure of device function with a +- * single MSI-X vector. A return of zero indicates the successful setup of +- * requested MSI-X entries with allocated vectors or non-zero for otherwise. ++ * single MSI-X irq. A return of zero indicates the successful setup of ++ * requested MSI-X entries with allocated irqs or non-zero for otherwise. + **/ + static int msix_capability_init(struct pci_dev *dev, + struct msix_entry *entries, int nvec) +@@ -480,12 +474,18 @@ static int msix_capability_init(struct p + } + + if (i != nvec) { ++ int avail = i - 1; + for (j = --i; j >= 0; j--) { + msi_unmap_pirq(dev, entries[j].vector); + detach_pirq_entry(entries[j].entry, msi_dev_entry); + entries[j].vector = 0; + } +- return -EBUSY; ++ /* If we had some success report the number of irqs ++ * we succeeded in setting up. ++ */ ++ if (avail <= 0) ++ avail = -EBUSY; ++ return avail; + } + + enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); +@@ -495,11 +495,40 @@ static int msix_capability_init(struct p + } + + /** ++ * pci_msi_supported - check whether MSI may be enabled on device ++ * @dev: pointer to the pci_dev data structure of MSI device function ++ * ++ * Look at global flags, the device itself, and its parent busses ++ * to return 0 if MSI are supported for the device. ++ **/ ++static ++int pci_msi_supported(struct pci_dev * dev) ++{ ++ struct pci_bus *bus; ++ ++ /* MSI must be globally enabled and supported by the device */ ++ if (!pci_msi_enable || !dev || dev->no_msi) ++ return -EINVAL; ++ ++ /* Any bridge which does NOT route MSI transactions from it's ++ * secondary bus to it's primary bus must set NO_MSI flag on ++ * the secondary pci_bus. ++ * We expect only arch-specific PCI host bus controller driver ++ * or quirks for specific PCI bridges to be setting NO_MSI. ++ */ ++ for (bus = dev->bus; bus; bus = bus->parent) ++ if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++/** + * pci_enable_msi - configure device's MSI capability structure + * @dev: pointer to the pci_dev data structure of MSI device function + * + * Setup the MSI capability structure of device function with +- * a single MSI vector upon its software driver call to request for ++ * a single MSI irq upon its software driver call to request for + * MSI mode enabled on its hardware device function. A return of zero + * indicates the successful setup of an entry zero with the new MSI + * vector or non-zero for otherwise. +@@ -507,18 +536,10 @@ static int msix_capability_init(struct p + extern int pci_frontend_enable_msi(struct pci_dev *dev); + int pci_enable_msi(struct pci_dev* dev) + { +- struct pci_bus *bus; +- int pos, temp, status = -EINVAL; ++ int pos, temp, status; + +- if (!pci_msi_enable || !dev) +- return status; +- +- if (dev->no_msi) +- return status; +- +- for (bus = dev->bus; bus; bus = bus->parent) +- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) +- return -EINVAL; ++ if (pci_msi_supported(dev) < 0) ++ return -EINVAL; + + status = msi_init(); + if (status < 0) +@@ -547,10 +568,10 @@ int pci_enable_msi(struct pci_dev* dev) + if (!pos) + return -EINVAL; + +- /* Check whether driver already requested for MSI-X vectors */ ++ /* Check whether driver already requested for MSI-X irqs */ + if (dev->msix_enabled) { + printk(KERN_INFO "PCI: %s: Can't enable MSI. " +- "Device already has MSI-X vectors assigned\n", ++ "Device already has MSI-X irq assigned\n", + pci_name(dev)); + dev->irq = temp; + return -EINVAL; +@@ -602,36 +623,28 @@ void pci_disable_msi(struct pci_dev* dev + * pci_enable_msix - configure device's MSI-X capability structure + * @dev: pointer to the pci_dev data structure of MSI-X device function + * @entries: pointer to an array of MSI-X entries +- * @nvec: number of MSI-X vectors requested for allocation by device driver ++ * @nvec: number of MSI-X irqs requested for allocation by device driver + * + * Setup the MSI-X capability structure of device function with the number +- * of requested vectors upon its software driver call to request for ++ * of requested irqs upon its software driver call to request for + * MSI-X mode enabled on its hardware device function. A return of zero + * indicates the successful configuration of MSI-X capability structure +- * with new allocated MSI-X vectors. A return of < 0 indicates a failure. ++ * with new allocated MSI-X irqs. A return of < 0 indicates a failure. + * Or a return of > 0 indicates that driver request is exceeding the number +- * of vectors available. Driver should use the returned value to re-send ++ * of irqs available. Driver should use the returned value to re-send + * its request. + **/ + extern int pci_frontend_enable_msix(struct pci_dev *dev, + struct msix_entry *entries, int nvec); + int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) + { +- struct pci_bus *bus; + int status, pos, nr_entries; + int i, j, temp; + u16 control; + +- if (!pci_msi_enable || !dev || !entries) ++ if (!entries || pci_msi_supported(dev) < 0) + return -EINVAL; + +- if (dev->no_msi) +- return -EINVAL; +- +- for (bus = dev->bus; bus; bus = bus->parent) +- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) +- return -EINVAL; +- + #ifdef CONFIG_XEN_PCIDEV_FRONTEND + if (!is_initial_xendomain()) { + struct msi_dev_list *msi_dev_entry; +@@ -694,7 +707,7 @@ int pci_enable_msix(struct pci_dev* dev, + /* Check whether driver already requested for MSI vector */ + if (dev->msi_enabled) { + printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " +- "Device already has an MSI vector assigned\n", ++ "Device already has an MSI irq assigned\n", + pci_name(dev)); + dev->irq = temp; + return -EINVAL; +@@ -757,11 +770,11 @@ void pci_disable_msix(struct pci_dev* de + } + + /** +- * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state ++ * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state + * @dev: pointer to the pci_dev data structure of MSI(X) device function + * + * Being called during hotplug remove, from which the device function +- * is hot-removed. All previous assigned MSI/MSI-X vectors, if ++ * is hot-removed. All previous assigned MSI/MSI-X irqs, if + * allocated for this device function, are reclaimed to unused state, + * which may be used later on. + **/ +--- sle11-2009-05-14.orig/drivers/xen/Kconfig 2008-12-05 08:43:56.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/Kconfig 2009-03-04 11:28:34.000000000 +0100 +@@ -287,6 +287,9 @@ endmenu + config HAVE_IRQ_IGNORE_UNHANDLED + def_bool y + ++config GENERIC_HARDIRQS_NO__DO_IRQ ++ def_bool y ++ + config NO_IDLE_HZ + def_bool y + +--- sle11-2009-05-14.orig/drivers/xen/balloon/balloon.c 2008-11-25 13:31:07.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/balloon/balloon.c 2009-03-04 11:28:34.000000000 +0100 +@@ -84,7 +84,7 @@ static unsigned long frame_list[PAGE_SIZ + /* VM /proc information for memory */ + extern unsigned long totalram_pages; + +-#ifndef MODULE ++#if !defined(MODULE) && defined(CONFIG_HIGHMEM) + extern unsigned long totalhigh_pages; + #define inc_totalhigh_pages() (totalhigh_pages++) + #define dec_totalhigh_pages() (totalhigh_pages--) +--- sle11-2009-05-14.orig/drivers/xen/blkback/blkback.c 2008-12-01 11:21:10.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkback/blkback.c 2009-03-04 11:28:34.000000000 +0100 +@@ -288,7 +288,7 @@ static void blkif_notify_work(blkif_t *b + wake_up(&blkif->wq); + } + +-irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t blkif_be_int(int irq, void *dev_id) + { + blkif_notify_work(dev_id); + return IRQ_HANDLED; +--- sle11-2009-05-14.orig/drivers/xen/blkback/common.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blkback/common.h 2009-03-04 11:28:34.000000000 +0100 +@@ -130,7 +130,7 @@ void blkif_interface_init(void); + + void blkif_xenbus_init(void); + +-irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs); ++irqreturn_t blkif_be_int(int irq, void *dev_id); + int blkif_schedule(void *arg); + + int blkback_barrier(struct xenbus_transaction xbt, +--- sle11-2009-05-14.orig/drivers/xen/blkfront/blkfront.c 2009-03-05 15:42:00.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkfront/blkfront.c 2009-03-24 10:08:16.000000000 +0100 +@@ -70,7 +70,7 @@ static int setup_blkring(struct xenbus_d + + static void kick_pending_request_queues(struct blkfront_info *); + +-static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs); ++static irqreturn_t blkif_int(int irq, void *dev_id); + static void blkif_restart_queue(void *arg); + static void blkif_recover(struct blkfront_info *); + static void blkif_completion(struct blk_shadow *); +@@ -707,7 +707,7 @@ void do_blkif_request(request_queue_t *r + } + + +-static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) ++static irqreturn_t blkif_int(int irq, void *dev_id) + { + struct request *req; + blkif_response_t *bret; +--- sle11-2009-05-14.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blktap/blktap.c 2009-04-20 11:37:34.000000000 +0200 +@@ -1222,7 +1222,7 @@ static void blkif_notify_work(blkif_t *b + wake_up(&blkif->wq); + } + +-irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t tap_blkif_be_int(int irq, void *dev_id) + { + blkif_notify_work(dev_id); + return IRQ_HANDLED; +--- sle11-2009-05-14.orig/drivers/xen/blktap/common.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blktap/common.h 2009-03-04 11:28:34.000000000 +0100 +@@ -113,7 +113,7 @@ void tap_blkif_interface_init(void); + + void tap_blkif_xenbus_init(void); + +-irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs); ++irqreturn_t tap_blkif_be_int(int irq, void *dev_id); + int tap_blkif_schedule(void *arg); + + int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif); +--- sle11-2009-05-14.orig/drivers/xen/console/console.c 2008-12-15 11:13:47.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/console/console.c 2009-03-04 11:28:34.000000000 +0100 +@@ -361,7 +361,7 @@ static struct tty_struct *xencons_tty; + static int xencons_priv_irq; + static char x_char; + +-void xencons_rx(char *buf, unsigned len, struct pt_regs *regs) ++void xencons_rx(char *buf, unsigned len) + { + int i; + unsigned long flags; +@@ -386,8 +386,7 @@ void xencons_rx(char *buf, unsigned len, + if (time_before(jiffies, sysrq_timeout)) { + spin_unlock_irqrestore( + &xencons_lock, flags); +- handle_sysrq( +- buf[i], regs, xencons_tty); ++ handle_sysrq(buf[i], xencons_tty); + spin_lock_irqsave( + &xencons_lock, flags); + continue; +@@ -452,14 +451,13 @@ void xencons_tx(void) + } + + /* Privileged receive callback and transmit kicker. */ +-static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id, +- struct pt_regs *regs) ++static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id) + { + static char rbuf[16]; + int l; + + while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0) +- xencons_rx(rbuf, l, regs); ++ xencons_rx(rbuf, l); + + xencons_tx(); + +@@ -647,7 +645,7 @@ static void xencons_close(struct tty_str + spin_unlock_irqrestore(&xencons_lock, flags); + } + +-static struct tty_operations xencons_ops = { ++static const struct tty_operations xencons_ops = { + .open = xencons_open, + .close = xencons_close, + .write = xencons_write, +--- sle11-2009-05-14.orig/drivers/xen/console/xencons_ring.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/console/xencons_ring.c 2009-03-04 11:28:34.000000000 +0100 +@@ -83,7 +83,7 @@ int xencons_ring_send(const char *data, + return sent; + } + +-static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs) ++static irqreturn_t handle_input(int irq, void *unused) + { + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; +@@ -94,7 +94,7 @@ static irqreturn_t handle_input(int irq, + BUG_ON((prod - cons) > sizeof(intf->in)); + + while (cons != prod) { +- xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1, regs); ++ xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1); + cons++; + } + +--- sle11-2009-05-14.orig/drivers/xen/core/evtchn.c 2009-03-16 16:14:12.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/core/evtchn.c 2009-03-04 11:28:34.000000000 +0100 +@@ -516,7 +516,7 @@ static void unbind_from_irq(unsigned int + + int bind_caller_port_to_irqhandler( + unsigned int caller_port, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id) +@@ -539,7 +539,7 @@ EXPORT_SYMBOL_GPL(bind_caller_port_to_ir + + int bind_listening_port_to_irqhandler( + unsigned int remote_domain, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id) +@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(bind_listening_port_to + int bind_interdomain_evtchn_to_irqhandler( + unsigned int remote_domain, + unsigned int remote_port, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id) +@@ -587,7 +587,7 @@ EXPORT_SYMBOL_GPL(bind_interdomain_evtch + int bind_virq_to_irqhandler( + unsigned int virq, + unsigned int cpu, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id) +@@ -611,7 +611,7 @@ EXPORT_SYMBOL_GPL(bind_virq_to_irqhandle + int bind_ipi_to_irqhandler( + unsigned int ipi, + unsigned int cpu, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id) +@@ -696,15 +696,7 @@ static unsigned int startup_dynirq(unsig + return 0; + } + +-static void shutdown_dynirq(unsigned int irq) +-{ +- int evtchn = evtchn_from_irq(irq); +- +- if (VALID_EVTCHN(evtchn)) +- mask_evtchn(evtchn); +-} +- +-static void enable_dynirq(unsigned int irq) ++static void unmask_dynirq(unsigned int irq) + { + int evtchn = evtchn_from_irq(irq); + +@@ -712,7 +704,7 @@ static void enable_dynirq(unsigned int i + unmask_evtchn(evtchn); + } + +-static void disable_dynirq(unsigned int irq) ++static void mask_dynirq(unsigned int irq) + { + int evtchn = evtchn_from_irq(irq); + +@@ -740,12 +732,13 @@ static void end_dynirq(unsigned int irq) + unmask_evtchn(evtchn); + } + +-static struct hw_interrupt_type dynirq_type = { +- .typename = "Dynamic-irq", ++static struct irq_chip dynirq_chip = { ++ .name = "Dynamic", + .startup = startup_dynirq, +- .shutdown = shutdown_dynirq, +- .enable = enable_dynirq, +- .disable = disable_dynirq, ++ .shutdown = mask_dynirq, ++ .mask = mask_dynirq, ++ .unmask = unmask_dynirq, ++ .mask_ack = ack_dynirq, + .ack = ack_dynirq, + .end = end_dynirq, + #ifdef CONFIG_SMP +@@ -859,12 +852,12 @@ static void shutdown_pirq(unsigned int i + irq_info[irq] = mk_irq_info(IRQT_PIRQ, index_from_irq(irq), 0); + } + +-static void enable_pirq(unsigned int irq) ++static void unmask_pirq(unsigned int irq) + { + startup_pirq(irq); + } + +-static void disable_pirq(unsigned int irq) ++static void mask_pirq(unsigned int irq) + { + } + +@@ -891,12 +884,13 @@ static void end_pirq(unsigned int irq) + pirq_unmask_and_notify(evtchn, irq); + } + +-static struct hw_interrupt_type pirq_type = { +- .typename = "Phys-irq", ++static struct irq_chip pirq_chip = { ++ .name = "Phys", + .startup = startup_pirq, + .shutdown = shutdown_pirq, +- .enable = enable_pirq, +- .disable = disable_pirq, ++ .mask = mask_pirq, ++ .unmask = unmask_pirq, ++ .mask_ack = ack_pirq, + .ack = ack_pirq, + .end = end_pirq, + #ifdef CONFIG_SMP +@@ -1081,7 +1075,8 @@ void evtchn_register_pirq(int irq) + if (identity_mapped_irq(irq) || type_from_irq(irq) != IRQT_UNBOUND) + return; + irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, 0); +- irq_desc[irq].chip = &pirq_type; ++ set_irq_chip_and_handler_name(irq, &pirq_chip, handle_level_irq, ++ "level"); + } + + int evtchn_map_pirq(int irq, int xen_pirq) +@@ -1104,11 +1099,18 @@ int evtchn_map_pirq(int irq, int xen_pir + spin_unlock(&irq_alloc_lock); + if (irq < PIRQ_BASE) + return -ENOSPC; +- irq_desc[irq].chip = &pirq_type; ++ set_irq_chip_and_handler_name(irq, &pirq_chip, ++ handle_level_irq, "level"); + } else if (!xen_pirq) { + if (unlikely(type_from_irq(irq) != IRQT_PIRQ)) + return -EINVAL; +- irq_desc[irq].chip = &no_irq_type; ++ /* ++ * dynamic_irq_cleanup(irq) would seem to be the correct thing ++ * here, but cannot be used as we get here also during shutdown ++ * when a driver didn't free_irq() its MSI(-X) IRQ(s), which ++ * then causes a warning in dynamic_irq_cleanup(). ++ */ ++ set_irq_chip_and_handler(irq, NULL, NULL); + irq_info[irq] = IRQ_UNBOUND; + return 0; + } else if (type_from_irq(irq) != IRQT_PIRQ +@@ -1154,10 +1156,9 @@ void __init xen_init_IRQ(void) + for (i = DYNIRQ_BASE; i < (DYNIRQ_BASE + NR_DYNIRQS); i++) { + irq_bindcount[i] = 0; + +- irq_desc[i].status = IRQ_DISABLED|IRQ_NOPROBE; +- irq_desc[i].action = NULL; +- irq_desc[i].depth = 1; +- irq_desc[i].chip = &dynirq_type; ++ irq_desc[i].status |= IRQ_NOPROBE; ++ set_irq_chip_and_handler_name(i, &dynirq_chip, ++ handle_level_irq, "level"); + } + + /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */ +@@ -1173,9 +1174,7 @@ void __init xen_init_IRQ(void) + continue; + #endif + +- irq_desc[i].status = IRQ_DISABLED; +- irq_desc[i].action = NULL; +- irq_desc[i].depth = 1; +- irq_desc[i].chip = &pirq_type; ++ set_irq_chip_and_handler_name(i, &pirq_chip, ++ handle_level_irq, "level"); + } + } +--- sle11-2009-05-14.orig/drivers/xen/core/reboot.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/core/reboot.c 2009-03-04 11:28:34.000000000 +0100 +@@ -14,6 +14,7 @@ + + #ifdef HAVE_XEN_PLATFORM_COMPAT_H + #include ++#undef handle_sysrq + #endif + + MODULE_LICENSE("Dual BSD/GPL"); +@@ -231,7 +232,7 @@ static void sysrq_handler(struct xenbus_ + + #ifdef CONFIG_MAGIC_SYSRQ + if (sysrq_key != '\0') +- handle_sysrq(sysrq_key, NULL, NULL); ++ handle_sysrq(sysrq_key, NULL); + #endif + } + +@@ -245,7 +246,7 @@ static struct xenbus_watch sysrq_watch = + .callback = sysrq_handler + }; + +-static irqreturn_t suspend_int(int irq, void* dev_id, struct pt_regs *ptregs) ++static irqreturn_t suspend_int(int irq, void* dev_id) + { + switch_shutdown_state(SHUTDOWN_SUSPEND); + return IRQ_HANDLED; +--- sle11-2009-05-14.orig/drivers/xen/core/smpboot.c 2009-04-28 16:02:07.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/core/smpboot.c 2009-03-04 11:28:34.000000000 +0100 +@@ -25,8 +25,8 @@ + #include + #include + +-extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *); +-extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *); ++extern irqreturn_t smp_reschedule_interrupt(int, void *); ++extern irqreturn_t smp_call_function_interrupt(int, void *); + + extern int local_setup_timer(unsigned int cpu); + extern void local_teardown_timer(unsigned int cpu); +@@ -62,8 +62,6 @@ EXPORT_SYMBOL(cpu_core_map); + #if defined(__i386__) + u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff }; + EXPORT_SYMBOL(x86_cpu_to_apicid); +-#elif !defined(CONFIG_X86_IO_APIC) +-unsigned int maxcpus = NR_CPUS; + #endif + + void __init prefill_possible_map(void) +--- sle11-2009-05-14.orig/drivers/xen/fbfront/xenfb.c 2009-02-16 15:59:55.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/fbfront/xenfb.c 2009-03-04 11:28:34.000000000 +0100 +@@ -524,8 +524,7 @@ static struct fb_ops xenfb_fb_ops = { + .fb_set_par = xenfb_set_par, + }; + +-static irqreturn_t xenfb_event_handler(int rq, void *dev_id, +- struct pt_regs *regs) ++static irqreturn_t xenfb_event_handler(int rq, void *dev_id) + { + /* + * No in events recognized, simply ignore them all. +--- sle11-2009-05-14.orig/drivers/xen/fbfront/xenkbd.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/fbfront/xenkbd.c 2009-03-04 11:28:34.000000000 +0100 +@@ -46,7 +46,7 @@ static void xenkbd_disconnect_backend(st + * to do that. + */ + +-static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs) ++static irqreturn_t input_handler(int rq, void *dev_id) + { + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; +--- sle11-2009-05-14.orig/drivers/xen/gntdev/gntdev.c 2008-12-15 11:13:45.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/gntdev/gntdev.c 2009-03-04 11:28:34.000000000 +0100 +@@ -752,9 +752,6 @@ static pte_t gntdev_clear_pte(struct vm_ + BUG(); + } + +- /* Copy the existing value of the PTE for returning. */ +- copy = *ptep; +- + /* Calculate the grant relating to this PTE. */ + slot_index = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT); + +@@ -769,6 +766,10 @@ static pte_t gntdev_clear_pte(struct vm_ + GNTDEV_INVALID_HANDLE && + !xen_feature(XENFEAT_auto_translated_physmap)) { + /* NOT USING SHADOW PAGE TABLES. */ ++ ++ /* Copy the existing value of the PTE for returning. */ ++ copy = *ptep; ++ + gnttab_set_unmap_op(&op, ptep_to_machine(ptep), + GNTMAP_contains_pte, + private_data->grants[slot_index] +@@ -781,7 +782,7 @@ static pte_t gntdev_clear_pte(struct vm_ + op.status); + } else { + /* USING SHADOW PAGE TABLES. */ +- pte_clear_full(vma->vm_mm, addr, ptep, is_fullmm); ++ copy = ptep_get_and_clear_full(vma->vm_mm, addr, ptep, is_fullmm); + } + + /* Finally, we unmap the grant from kernel space. */ +@@ -809,7 +810,7 @@ static pte_t gntdev_clear_pte(struct vm_ + >> PAGE_SHIFT, INVALID_P2M_ENTRY); + + } else { +- pte_clear_full(vma->vm_mm, addr, ptep, is_fullmm); ++ copy = ptep_get_and_clear_full(vma->vm_mm, addr, ptep, is_fullmm); + } + + return copy; +--- sle11-2009-05-14.orig/drivers/xen/netback/accel.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/netback/accel.c 2009-03-04 11:28:34.000000000 +0100 +@@ -65,7 +65,7 @@ static int match_accelerator(struct xenb + + if (IS_ERR(eth_name)) { + /* Probably means not present */ +- DPRINTK("%s: no match due to xenbus_read accel error %d\n", ++ DPRINTK("%s: no match due to xenbus_read accel error %ld\n", + __FUNCTION__, PTR_ERR(eth_name)); + return 0; + } else { +--- sle11-2009-05-14.orig/drivers/xen/netback/common.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/netback/common.h 2009-03-04 11:28:34.000000000 +0100 +@@ -200,7 +200,7 @@ void netif_deschedule_work(netif_t *neti + + int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev); + struct net_device_stats *netif_be_get_stats(struct net_device *dev); +-irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs); ++irqreturn_t netif_be_int(int irq, void *dev_id); + + static inline int netbk_can_queue(struct net_device *dev) + { +--- sle11-2009-05-14.orig/drivers/xen/netback/loopback.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/netback/loopback.c 2009-03-04 11:28:34.000000000 +0100 +@@ -151,7 +151,7 @@ static int loopback_start_xmit(struct sk + np->stats.rx_bytes += skb->len; + np->stats.rx_packets++; + +- if (skb->ip_summed == CHECKSUM_HW) { ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Defer checksum calculation. */ + skb->proto_csum_blank = 1; + /* Must be a local packet: assert its integrity. */ +--- sle11-2009-05-14.orig/drivers/xen/netback/netback.c 2008-12-23 09:31:07.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/netback/netback.c 2009-03-04 11:28:34.000000000 +0100 +@@ -692,7 +692,7 @@ static void net_rx_action(unsigned long + id = meta[npo.meta_cons].id; + flags = nr_frags ? NETRXF_more_data : 0; + +- if (skb->ip_summed == CHECKSUM_HW) /* local packet? */ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ + flags |= NETRXF_csum_blank | NETRXF_data_validated; + else if (skb->proto_data_valid) /* remote but checksummed? */ + flags |= NETRXF_data_validated; +@@ -1459,7 +1459,7 @@ static void netif_page_release(struct pa + netif_idx_release(idx); + } + +-irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t netif_be_int(int irq, void *dev_id) + { + netif_t *netif = dev_id; + +@@ -1526,7 +1526,7 @@ static netif_rx_response_t *make_rx_resp + } + + #ifdef NETBE_DEBUG_INTERRUPT +-static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs) ++static irqreturn_t netif_be_dbg(int irq, void *dev_id) + { + struct list_head *ent; + netif_t *netif; +--- sle11-2009-05-14.orig/drivers/xen/netfront/netfront.c 2009-04-09 14:41:33.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/netfront/netfront.c 2009-03-30 16:34:59.000000000 +0200 +@@ -136,7 +136,7 @@ static inline int netif_needs_gso(struct + { + return skb_is_gso(skb) && + (!skb_gso_ok(skb, dev->features) || +- unlikely(skb->ip_summed != CHECKSUM_HW)); ++ unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); + } + #else + #define HAVE_GSO 0 +@@ -222,7 +222,7 @@ static void network_tx_buf_gc(struct net + static void network_alloc_rx_buffers(struct net_device *); + static void send_fake_arp(struct net_device *); + +-static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs); ++static irqreturn_t netif_int(int irq, void *dev_id); + + #ifdef CONFIG_SYSFS + static int xennet_sysfs_addif(struct net_device *netdev); +@@ -992,7 +992,7 @@ static int network_start_xmit(struct sk_ + tx->flags = 0; + extra = NULL; + +- if (skb->ip_summed == CHECKSUM_HW) /* local packet? */ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */ + tx->flags |= NETTXF_csum_blank | NETTXF_data_validated; + #ifdef CONFIG_XEN + if (skb->proto_data_valid) /* remote but checksummed? */ +@@ -1049,7 +1049,7 @@ static int network_start_xmit(struct sk_ + return 0; + } + +-static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs) ++static irqreturn_t netif_int(int irq, void *dev_id) + { + struct net_device *dev = dev_id; + struct netfront_info *np = netdev_priv(dev); +--- sle11-2009-05-14.orig/drivers/xen/pciback/pciback.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/pciback/pciback.h 2009-03-04 11:28:34.000000000 +0100 +@@ -87,7 +87,7 @@ int pciback_publish_pci_roots(struct pci + void pciback_release_devices(struct pciback_device *pdev); + + /* Handles events from front-end */ +-irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs); ++irqreturn_t pciback_handle_event(int irq, void *dev_id); + void pciback_do_op(void *data); + + int pciback_xenbus_register(void); +--- sle11-2009-05-14.orig/drivers/xen/pciback/pciback_ops.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/pciback/pciback_ops.c 2009-03-04 11:28:34.000000000 +0100 +@@ -107,7 +107,7 @@ void pciback_do_op(void *data) + test_and_schedule_op(pdev); + } + +-irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t pciback_handle_event(int irq, void *dev_id) + { + struct pciback_device *pdev = dev_id; + +--- sle11-2009-05-14.orig/drivers/xen/pcifront/pci_op.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/pcifront/pci_op.c 2009-03-04 11:28:34.000000000 +0100 +@@ -508,10 +508,16 @@ int __devinit pcifront_rescan_root(struc + + d = pci_scan_single_device(b, devfn); + if (d) { ++ int err; ++ + dev_info(&pdev->xdev->dev, "New device on " + "%04x:%02x:%02x.%02x found.\n", domain, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); +- pci_bus_add_device(d); ++ err = pci_bus_add_device(d); ++ if (err) ++ dev_err(&pdev->xdev->dev, ++ "error %d adding device, continuing.\n", ++ err); + } + } + +--- sle11-2009-05-14.orig/drivers/xen/privcmd/compat_privcmd.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/privcmd/compat_privcmd.c 2009-03-04 11:28:34.000000000 +0100 +@@ -18,7 +18,6 @@ + * Authors: Jimi Xenidis + */ + +-#include + #include + #include + #include +--- sle11-2009-05-14.orig/drivers/xen/privcmd/privcmd.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/privcmd/privcmd.c 2009-03-04 11:28:34.000000000 +0100 +@@ -40,7 +40,7 @@ static int privcmd_enforce_singleshot_ma + static long privcmd_ioctl(struct file *file, + unsigned int cmd, unsigned long data) + { +- int ret = -ENOSYS; ++ long ret = -ENOSYS; + void __user *udata = (void __user *) data; + + switch (cmd) { +@@ -50,42 +50,15 @@ static long privcmd_ioctl(struct file *f + if (copy_from_user(&hypercall, udata, sizeof(hypercall))) + return -EFAULT; + +-#if defined(__i386__) ++#ifdef CONFIG_X86 + if (hypercall.op >= (PAGE_SIZE >> 5)) + break; +- __asm__ __volatile__ ( +- "pushl %%ebx; pushl %%ecx; pushl %%edx; " +- "pushl %%esi; pushl %%edi; " +- "movl 8(%%eax),%%ebx ;" +- "movl 16(%%eax),%%ecx ;" +- "movl 24(%%eax),%%edx ;" +- "movl 32(%%eax),%%esi ;" +- "movl 40(%%eax),%%edi ;" +- "movl (%%eax),%%eax ;" +- "shll $5,%%eax ;" +- "addl $hypercall_page,%%eax ;" +- "call *%%eax ;" +- "popl %%edi; popl %%esi; popl %%edx; " +- "popl %%ecx; popl %%ebx" +- : "=a" (ret) : "0" (&hypercall) : "memory" ); +-#elif defined (__x86_64__) +- if (hypercall.op < (PAGE_SIZE >> 5)) { +- long ign1, ign2, ign3; +- __asm__ __volatile__ ( +- "movq %8,%%r10; movq %9,%%r8;" +- "shll $5,%%eax ;" +- "addq $hypercall_page,%%rax ;" +- "call *%%rax" +- : "=a" (ret), "=D" (ign1), +- "=S" (ign2), "=d" (ign3) +- : "0" ((unsigned int)hypercall.op), +- "1" (hypercall.arg[0]), +- "2" (hypercall.arg[1]), +- "3" (hypercall.arg[2]), +- "g" (hypercall.arg[3]), +- "g" (hypercall.arg[4]) +- : "r8", "r10", "memory" ); +- } ++ ret = _hypercall(long, (unsigned int)hypercall.op, ++ (unsigned long)hypercall.arg[0], ++ (unsigned long)hypercall.arg[1], ++ (unsigned long)hypercall.arg[2], ++ (unsigned long)hypercall.arg[3], ++ (unsigned long)hypercall.arg[4]); + #else + ret = privcmd_hypercall(&hypercall); + #endif +@@ -306,7 +279,7 @@ static int privcmd_mmap(struct file * fi + return -ENOSYS; + + /* DONTCOPY is essential for Xen as copy_page_range is broken. */ +- vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY; ++ vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTCOPY; + vma->vm_ops = &privcmd_vm_ops; + vma->vm_private_data = NULL; + +--- sle11-2009-05-14.orig/drivers/xen/scsiback/common.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/scsiback/common.h 2009-03-04 11:28:34.000000000 +0100 +@@ -142,7 +142,7 @@ typedef struct { + #define VSCSIIF_TIMEOUT (900*HZ) + + +-irqreturn_t scsiback_intr(int, void *, struct pt_regs *); ++irqreturn_t scsiback_intr(int, void *); + int scsiback_init_sring(struct vscsibk_info *info, + unsigned long ring_ref, unsigned int evtchn); + int scsiback_schedule(void *data); +--- sle11-2009-05-14.orig/drivers/xen/scsiback/scsiback.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/scsiback/scsiback.c 2009-03-04 11:28:34.000000000 +0100 +@@ -440,7 +440,7 @@ void scsiback_cmd_exec(pending_req_t *pe + write = (data_dir == DMA_TO_DEVICE); + rq = blk_get_request(pending_req->sdev->request_queue, write, GFP_KERNEL); + +- rq->flags |= REQ_BLOCK_PC; ++ rq->cmd_type = REQ_TYPE_BLOCK_PC; + rq->cmd_len = cmd_len; + memcpy(rq->cmd, pending_req->cmnd, cmd_len); + +@@ -484,7 +484,7 @@ static void scsiback_device_reset_exec(p + } + + +-irqreturn_t scsiback_intr(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t scsiback_intr(int irq, void *dev_id) + { + scsiback_notify_work((struct vscsibk_info *)dev_id); + return IRQ_HANDLED; +--- sle11-2009-05-14.orig/drivers/xen/scsifront/common.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/scsifront/common.h 2009-03-04 11:28:34.000000000 +0100 +@@ -122,7 +122,7 @@ struct vscsifrnt_info { + int scsifront_xenbus_init(void); + void scsifront_xenbus_unregister(void); + int scsifront_schedule(void *data); +-irqreturn_t scsifront_intr(int irq, void *dev_id, struct pt_regs *ptregs); ++irqreturn_t scsifront_intr(int irq, void *dev_id); + int scsifront_cmd_done(struct vscsifrnt_info *info); + + +--- sle11-2009-05-14.orig/drivers/xen/scsifront/scsifront.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/scsifront/scsifront.c 2009-03-04 11:28:34.000000000 +0100 +@@ -100,7 +100,7 @@ static void scsifront_do_request(struct + notify_remote_via_irq(irq); + } + +-irqreturn_t scsifront_intr(int irq, void *dev_id, struct pt_regs *ptregs) ++irqreturn_t scsifront_intr(int irq, void *dev_id) + { + scsifront_notify_work((struct vscsifrnt_info *)dev_id); + return IRQ_HANDLED; +--- sle11-2009-05-14.orig/drivers/xen/sfc_netback/accel_xenbus.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/sfc_netback/accel_xenbus.c 2009-03-04 11:28:34.000000000 +0100 +@@ -68,8 +68,7 @@ static void unlink_bend(struct netback_a + + + /* Demultiplex a message IRQ from the frontend driver. */ +-static irqreturn_t msgirq_from_frontend(int irq, void *context, +- struct pt_regs *unused) ++static irqreturn_t msgirq_from_frontend(int irq, void *context) + { + struct xenbus_device *dev = context; + struct netback_accel *bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev); +@@ -84,8 +83,7 @@ static irqreturn_t msgirq_from_frontend( + * functionally, but we need it to pass to the bind function, and may + * get called spuriously + */ +-static irqreturn_t netirq_from_frontend(int irq, void *context, +- struct pt_regs *unused) ++static irqreturn_t netirq_from_frontend(int irq, void *context) + { + VPRINTK("netirq %d from device %s\n", irq, + ((struct xenbus_device *)context)->nodename); +--- sle11-2009-05-14.orig/drivers/xen/sfc_netfront/accel.h 2009-04-09 14:41:38.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/sfc_netfront/accel.h 2009-03-30 16:34:56.000000000 +0200 +@@ -451,10 +451,8 @@ void netfront_accel_msg_tx_fastpath(netf + u32 ip, u16 port, u8 protocol); + + /* Process an IRQ received from back end driver */ +-irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context, +- struct pt_regs *unused); +-irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context, +- struct pt_regs *unused); ++irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context); ++irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + extern void netfront_accel_msg_from_bend(struct work_struct *context); +--- sle11-2009-05-14.orig/drivers/xen/sfc_netfront/accel_msg.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/sfc_netfront/accel_msg.c 2009-03-04 11:28:34.000000000 +0100 +@@ -490,8 +490,7 @@ void netfront_accel_msg_from_bend(void * + } + + +-irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context, +- struct pt_regs *unused) ++irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context) + { + netfront_accel_vnic *vnic = (netfront_accel_vnic *)context; + VPRINTK("irq %d from device %s\n", irq, vnic->dev->nodename); +@@ -502,8 +501,7 @@ irqreturn_t netfront_accel_msg_channel_i + } + + /* Process an interrupt received from the NIC via backend */ +-irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context, +- struct pt_regs *unused) ++irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context) + { + netfront_accel_vnic *vnic = (netfront_accel_vnic *)context; + struct net_device *net_dev = vnic->net_dev; +--- sle11-2009-05-14.orig/drivers/xen/sfc_netfront/accel_tso.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/sfc_netfront/accel_tso.c 2009-03-04 11:28:34.000000000 +0100 +@@ -363,7 +363,7 @@ int netfront_accel_enqueue_skb_tso(netfr + + tso_check_safe(skb); + +- if (skb->ip_summed != CHECKSUM_HW) ++ if (skb->ip_summed != CHECKSUM_PARTIAL) + EPRINTK("Trying to TSO send a packet without HW checksum\n"); + + tso_start(&state, skb); +--- sle11-2009-05-14.orig/drivers/xen/sfc_netfront/accel_vi.c 2009-04-09 14:41:38.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:35:11.000000000 +0200 +@@ -461,7 +461,7 @@ netfront_accel_enqueue_skb_multi(netfron + + frag_i = -1; + +- if (skb->ip_summed == CHECKSUM_HW) { ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Set to zero to encourage falcon to work it out for us */ + *(u16*)(skb->h.raw + skb->csum) = 0; + } +@@ -580,7 +580,7 @@ netfront_accel_enqueue_skb_single(netfro + + kva = buf->pkt_kva; + +- if (skb->ip_summed == CHECKSUM_HW) { ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Set to zero to encourage falcon to work it out for us */ + *(u16*)(skb->h.raw + skb->csum) = 0; + } +--- sle11-2009-05-14.orig/drivers/xen/tpmback/common.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/tpmback/common.h 2009-03-04 11:28:34.000000000 +0100 +@@ -61,7 +61,7 @@ void tpmif_deschedule_work(tpmif_t * tpm + void tpmif_xenbus_init(void); + void tpmif_xenbus_exit(void); + int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn); +-irqreturn_t tpmif_be_int(int irq, void *dev_id, struct pt_regs *regs); ++irqreturn_t tpmif_be_int(int irq, void *dev_id); + + long int tpmback_get_instance(struct backend_info *bi); + +--- sle11-2009-05-14.orig/drivers/xen/tpmback/tpmback.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/tpmback/tpmback.c 2009-03-04 11:28:34.000000000 +0100 +@@ -502,7 +502,7 @@ static ssize_t vtpm_op_read(struct file + list_del(&pak->next); + write_unlock_irqrestore(&dataex.pak_lock, flags); + +- DPRINTK("size given by app: %d, available: %d\n", size, left); ++ DPRINTK("size given by app: %zu, available: %u\n", size, left); + + ret_size = min_t(size_t, size, left); + +@@ -899,7 +899,7 @@ static void tpm_tx_action(unsigned long + } + } + +-irqreturn_t tpmif_be_int(int irq, void *dev_id, struct pt_regs *regs) ++irqreturn_t tpmif_be_int(int irq, void *dev_id) + { + tpmif_t *tpmif = (tpmif_t *) dev_id; + +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_comms.c 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_comms.c 2009-03-04 11:28:34.000000000 +0100 +@@ -55,7 +55,7 @@ static DECLARE_WORK(probe_work, xenbus_p + + static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); + +-static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs) ++static irqreturn_t wake_waiting(int irq, void *unused) + { + if (unlikely(xenstored_ready == 0)) { + xenstored_ready = 1; +--- sle11-2009-05-14.orig/drivers/xen/xenoprof/xenoprofile.c 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/xenoprof/xenoprofile.c 2009-03-04 11:28:34.000000000 +0100 +@@ -194,8 +194,7 @@ done: + oprofile_add_domain_switch(COORDINATOR_DOMAIN); + } + +-static irqreturn_t +-xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs) ++static irqreturn_t xenoprof_ovf_interrupt(int irq, void *dev_id) + { + struct xenoprof_buf * buf; + static unsigned long flag; +--- sle11-2009-05-14.orig/include/asm-generic/pgtable.h 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/include/asm-generic/pgtable.h 2009-03-04 11:28:34.000000000 +0100 +@@ -100,7 +100,7 @@ static inline void ptep_set_wrprotect(st + #endif + + #ifndef arch_change_pte_range +-#define arch_change_pte_range(mm, pmd, addr, end, newprot) 0 ++#define arch_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) 0 + #endif + + #ifndef __HAVE_ARCH_PTE_SAME +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/desc_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/desc_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -32,52 +32,110 @@ static inline struct desc_struct *get_cp + return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address; + } + ++/* ++ * This is the ldt that every process will get unless we need ++ * something other than this. ++ */ ++extern struct desc_struct default_ldt[]; ++extern struct desc_struct idt_table[]; ++extern void set_intr_gate(unsigned int irq, void * addr); ++ ++static inline void pack_descriptor(__u32 *a, __u32 *b, ++ unsigned long base, unsigned long limit, unsigned char type, unsigned char flags) ++{ ++ *a = ((base & 0xffff) << 16) | (limit & 0xffff); ++ *b = (base & 0xff000000) | ((base & 0xff0000) >> 16) | ++ (limit & 0x000f0000) | ((type & 0xff) << 8) | ((flags & 0xf) << 20); ++} ++ ++static inline void pack_gate(__u32 *a, __u32 *b, ++ unsigned long base, unsigned short seg, unsigned char type, unsigned char flags) ++{ ++ *a = (seg << 16) | (base & 0xffff); ++ *b = (base & 0xffff0000) | ((type & 0xff) << 8) | (flags & 0xff); ++} ++ ++#define DESCTYPE_LDT 0x82 /* present, system, DPL-0, LDT */ ++#define DESCTYPE_TSS 0x89 /* present, system, DPL-0, 32-bit TSS */ ++#define DESCTYPE_TASK 0x85 /* present, system, DPL-0, task gate */ ++#define DESCTYPE_INT 0x8e /* present, system, DPL-0, interrupt gate */ ++#define DESCTYPE_TRAP 0x8f /* present, system, DPL-0, trap gate */ ++#define DESCTYPE_DPL3 0x60 /* DPL-3 */ ++#define DESCTYPE_S 0x10 /* !system */ ++ + #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) + #define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)) + + #define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) + #define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) +-#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr)) +-#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt)) ++#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) ++#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) + + #define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr)) + #define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) +-#define store_tr(tr) __asm__ ("str %0":"=mr" (tr)) +-#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt)) ++#define store_tr(tr) __asm__ ("str %0":"=m" (tr)) ++#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) + +-/* +- * This is the ldt that every process will get unless we need +- * something other than this. +- */ +-extern struct desc_struct default_ldt[]; +-extern void set_intr_gate(unsigned int irq, void * addr); ++#if TLS_SIZE != 24 ++# error update this code. ++#endif ++ ++static inline void load_TLS(struct thread_struct *t, unsigned int cpu) ++{ ++#define C(i) if (HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), \ ++ *(u64 *)&t->tls_array[i]) \ ++ BUG() ++ C(0); C(1); C(2); ++#undef C ++} + +-#define _set_tssldt_desc(n,addr,limit,type) \ +-__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ +- "movw %w1,2(%2)\n\t" \ +- "rorl $16,%1\n\t" \ +- "movb %b1,4(%2)\n\t" \ +- "movb %4,5(%2)\n\t" \ +- "movb $0,6(%2)\n\t" \ +- "movb %h1,7(%2)\n\t" \ +- "rorl $16,%1" \ +- : "=m"(*(n)) : "q" (addr), "r"(n), "ir"(limit), "i"(type)) ++#ifndef CONFIG_XEN ++static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b) ++{ ++ __u32 *lp = (__u32 *)((char *)dt + entry*8); ++ *lp = entry_a; ++ *(lp+1) = entry_b; ++} + +-#ifndef CONFIG_X86_NO_TSS +-static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr) ++#define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++#define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++#else ++extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); ++extern int write_gdt_entry(void *gdt, int entry, __u32 entry_a, __u32 entry_b); ++#endif ++#ifndef CONFIG_X86_NO_IDT ++#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++ ++static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) + { +- _set_tssldt_desc(&get_cpu_gdt_table(cpu)[entry], (int)addr, +- offsetof(struct tss_struct, __cacheline_filler) - 1, 0x89); ++ __u32 a, b; ++ pack_gate(&a, &b, (unsigned long)addr, seg, type, 0); ++ write_idt_entry(idt_table, gate, a, b); + } ++#endif + +-#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) ++#ifndef CONFIG_X86_NO_TSS ++static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, const void *addr) ++{ ++ __u32 a, b; ++ pack_descriptor(&a, &b, (unsigned long)addr, ++ offsetof(struct tss_struct, __cacheline_filler) - 1, ++ DESCTYPE_TSS, 0); ++ write_gdt_entry(get_cpu_gdt_table(cpu), entry, a, b); ++} + #endif + +-static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size) ++static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int entries) + { +- _set_tssldt_desc(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82); ++ __u32 a, b; ++ pack_descriptor(&a, &b, (unsigned long)addr, ++ entries * sizeof(struct desc_struct) - 1, ++ DESCTYPE_LDT, 0); ++ write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, a, b); + } + ++#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) ++ + #define LDT_entry_a(info) \ + ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) + +@@ -103,21 +161,6 @@ static inline void set_ldt_desc(unsigned + (info)->seg_not_present == 1 && \ + (info)->useable == 0 ) + +-extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); +- +-#if TLS_SIZE != 24 +-# error update this code. +-#endif +- +-static inline void load_TLS(struct thread_struct *t, unsigned int cpu) +-{ +-#define C(i) if (HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), \ +- *(u64 *)&t->tls_array[i])) \ +- BUG(); +- C(0); C(1); C(2); +-#undef C +-} +- + static inline void clear_LDT(void) + { + int cpu = get_cpu(); +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/fixmap_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/fixmap_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -55,7 +55,7 @@ enum fixed_addresses { + #ifdef CONFIG_X86_LOCAL_APIC + FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ + #endif +-#ifdef CONFIG_X86_IO_APIC ++#if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_XEN) + FIX_IO_APIC_BASE_0, + FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1, + #endif +@@ -95,10 +95,9 @@ enum fixed_addresses { + __end_of_fixed_addresses + }; + +-extern void set_fixaddr_top(unsigned long top); +- + extern void __set_fixmap(enum fixed_addresses idx, + maddr_t phys, pgprot_t flags); ++extern void reserve_top_address(unsigned long reserve); + + #define set_fixmap(idx, phys) \ + __set_fixmap(idx, phys, PAGE_KERNEL) +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/hypercall_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/hypercall_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -128,6 +128,23 @@ + __res; \ + }) + ++#define _hypercall(type, op, a1, a2, a3, a4, a5) \ ++({ \ ++ type __res; \ ++ register typeof((a1)+0) __arg1 asm("ebx") = (a1); \ ++ register typeof((a2)+0) __arg2 asm("ecx") = (a2); \ ++ register typeof((a3)+0) __arg3 asm("edx") = (a3); \ ++ register typeof((a4)+0) __arg4 asm("esi") = (a4); \ ++ register typeof((a5)+0) __arg5 asm("edi") = (a5); \ ++ asm volatile ( \ ++ "call *%6" \ ++ : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ ++ "+r" (__arg3), "+r" (__arg4), "+r" (__arg5) \ ++ : "0" (hypercall_page + (op) * 32) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ + static inline int __must_check + HYPERVISOR_set_trap_table( + const trap_info_t *table) +@@ -140,6 +157,8 @@ HYPERVISOR_mmu_update( + mmu_update_t *req, unsigned int count, unsigned int *success_count, + domid_t domid) + { ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_mmu_update(req, count, success_count, domid); + return _hypercall4(int, mmu_update, req, count, success_count, domid); + } + +@@ -148,6 +167,8 @@ HYPERVISOR_mmuext_op( + struct mmuext_op *op, unsigned int count, unsigned int *success_count, + domid_t domid) + { ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_mmuext_op(op, count, success_count, domid); + return _hypercall4(int, mmuext_op, op, count, success_count, domid); + } + +@@ -238,6 +259,8 @@ static inline int __must_check + HYPERVISOR_memory_op( + unsigned int cmd, void *arg) + { ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); + return _hypercall2(int, memory_op, cmd, arg); + } + +@@ -253,6 +276,9 @@ HYPERVISOR_update_va_mapping( + unsigned long va, pte_t new_val, unsigned long flags) + { + unsigned long pte_hi = 0; ++ ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_update_va_mapping(va, new_val, flags); + #ifdef CONFIG_X86_PAE + pte_hi = new_val.pte_high; + #endif +@@ -316,6 +342,8 @@ static inline int __must_check + HYPERVISOR_grant_table_op( + unsigned int cmd, void *uop, unsigned int count) + { ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); + return _hypercall3(int, grant_table_op, cmd, uop, count); + } + +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/hypercall_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/hypercall_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -134,6 +134,23 @@ + __res; \ + }) + ++#define _hypercall(type, op, a1, a2, a3, a4, a5) \ ++({ \ ++ type __res; \ ++ register typeof((a1)+0) __arg1 asm("rdi") = (a1); \ ++ register typeof((a2)+0) __arg2 asm("rsi") = (a2); \ ++ register typeof((a3)+0) __arg3 asm("rdx") = (a3); \ ++ register typeof((a4)+0) __arg4 asm("r10") = (a4); \ ++ register typeof((a5)+0) __arg5 asm("r8") = (a5); \ ++ asm volatile ( \ ++ "call *%6" \ ++ : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ ++ "+r" (__arg3), "+r" (__arg4), "+r" (__arg5) \ ++ : "0" (hypercall_page + (op) * 32) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ + static inline int __must_check + HYPERVISOR_set_trap_table( + const trap_info_t *table) +@@ -146,6 +163,8 @@ HYPERVISOR_mmu_update( + mmu_update_t *req, unsigned int count, unsigned int *success_count, + domid_t domid) + { ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_mmu_update(req, count, success_count, domid); + return _hypercall4(int, mmu_update, req, count, success_count, domid); + } + +@@ -154,6 +173,8 @@ HYPERVISOR_mmuext_op( + struct mmuext_op *op, unsigned int count, unsigned int *success_count, + domid_t domid) + { ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_mmuext_op(op, count, success_count, domid); + return _hypercall4(int, mmuext_op, op, count, success_count, domid); + } + +@@ -241,6 +262,8 @@ static inline int __must_check + HYPERVISOR_memory_op( + unsigned int cmd, void *arg) + { ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); + return _hypercall2(int, memory_op, cmd, arg); + } + +@@ -255,6 +278,8 @@ static inline int __must_check + HYPERVISOR_update_va_mapping( + unsigned long va, pte_t new_val, unsigned long flags) + { ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_update_va_mapping(va, new_val, flags); + return _hypercall3(int, update_va_mapping, va, new_val.pte, flags); + } + +@@ -314,6 +339,8 @@ static inline int __must_check + HYPERVISOR_grant_table_op( + unsigned int cmd, void *uop, unsigned int count) + { ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); + return _hypercall3(int, grant_table_op, cmd, uop, count); + } + +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-04 11:28:34.000000000 +0100 +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + #include + #include + #if defined(__i386__) +@@ -135,7 +136,46 @@ void scrub_pages(void *, unsigned int); + #define scrub_pages(_p,_n) ((void)0) + #endif + +-#include ++#if defined(CONFIG_XEN) && !defined(MODULE) ++ ++DECLARE_PER_CPU(bool, xen_lazy_mmu); ++ ++int xen_multicall_flush(bool); ++ ++int __must_check xen_multi_update_va_mapping(unsigned long va, pte_t, ++ unsigned long flags); ++int __must_check xen_multi_mmu_update(mmu_update_t *, unsigned int count, ++ unsigned int *success_count, domid_t); ++int __must_check xen_multi_mmuext_op(struct mmuext_op *, unsigned int count, ++ unsigned int *success_count, domid_t); ++ ++#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE ++static inline void arch_enter_lazy_mmu_mode(void) ++{ ++ __get_cpu_var(xen_lazy_mmu) = true; ++} ++ ++static inline void arch_leave_lazy_mmu_mode(void) ++{ ++ __get_cpu_var(xen_lazy_mmu) = false; ++ xen_multicall_flush(false); ++} ++ ++#if defined(CONFIG_X86_32) ++#define arch_use_lazy_mmu_mode() unlikely(x86_read_percpu(xen_lazy_mmu)) ++#elif !defined(arch_use_lazy_mmu_mode) ++#define arch_use_lazy_mmu_mode() unlikely(__get_cpu_var(xen_lazy_mmu)) ++#endif ++ ++#else /* !CONFIG_XEN || MODULE */ ++ ++static inline void xen_multicall_flush(bool ignore) {} ++#define arch_use_lazy_mmu_mode() false ++#define xen_multi_update_va_mapping(...) ({ BUG(); -ENOSYS; }) ++#define xen_multi_mmu_update(...) ({ BUG(); -ENOSYS; }) ++#define xen_multi_mmuext_op(...) ({ BUG(); -ENOSYS; }) ++ ++#endif /* CONFIG_XEN && !MODULE */ + + #if defined(CONFIG_X86_64) + #define MULTI_UVMFLAGS_INDEX 2 +@@ -147,11 +187,15 @@ void scrub_pages(void *, unsigned int); + + #ifdef CONFIG_XEN + #define is_running_on_xen() 1 ++extern char hypercall_page[PAGE_SIZE]; + #else + extern char *hypercall_stubs; ++#define hypercall_page hypercall_stubs + #define is_running_on_xen() (!!hypercall_stubs) + #endif + ++#include ++ + static inline int + HYPERVISOR_yield( + void) +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable-3level.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable-3level.h 2009-03-04 11:28:34.000000000 +0100 +@@ -53,7 +53,6 @@ static inline int pte_exec_kernel(pte_t + * not possible, use pte_get_and_clear to obtain the old pte + * value and then use set_pte to update it. -ben + */ +-#define __HAVE_ARCH_SET_PTE_ATOMIC + + static inline void set_pte(pte_t *ptep, pte_t pte) + { +@@ -70,14 +69,6 @@ static inline void set_pte(pte_t *ptep, + set_pte((ptep), (pteval)); \ + } while (0) + +-#define set_pte_at_sync(_mm,addr,ptep,pteval) do { \ +- if (((_mm) != current->mm && (_mm) != &init_mm) || \ +- HYPERVISOR_update_va_mapping((addr), (pteval), UVMF_INVLPG)) { \ +- set_pte((ptep), (pteval)); \ +- xen_invlpg((addr)); \ +- } \ +-} while (0) +- + #define set_pmd(pmdptr,pmdval) \ + xen_l2_entry_update((pmdptr), (pmdval)) + #define set_pud(pudptr,pudval) \ +@@ -94,7 +85,7 @@ static inline void pud_clear (pud_t * pu + #define pud_page(pud) \ + ((struct page *) __va(pud_val(pud) & PAGE_MASK)) + +-#define pud_page_kernel(pud) \ ++#define pud_page_vaddr(pud) \ + ((unsigned long) __va(pud_val(pud) & PAGE_MASK)) + + +@@ -124,6 +115,7 @@ static inline void pte_clear(struct mm_s + + #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) + ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR + static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + pte_t pte = *ptep; +@@ -142,6 +134,7 @@ static inline pte_t ptep_get_and_clear(s + return pte; + } + ++#define __HAVE_ARCH_PTEP_CLEAR_FLUSH + #define ptep_clear_flush(vma, addr, ptep) \ + ({ \ + pte_t *__ptep = (ptep); \ +@@ -159,6 +152,7 @@ static inline pte_t ptep_get_and_clear(s + __res; \ + }) + ++#define __HAVE_ARCH_PTE_SAME + static inline int pte_same(pte_t a, pte_t b) + { + return a.pte_low == b.pte_low && a.pte_high == b.pte_high; +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:13:45.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -260,31 +260,89 @@ static inline pte_t pte_mkhuge(pte_t pte + # include + #endif + +-#define ptep_test_and_clear_dirty(vma, addr, ptep) \ ++/* ++ * Rules for using pte_update - it must be called after any PTE update which ++ * has not been done using the set_pte / clear_pte interfaces. It is used by ++ * shadow mode hypervisors to resynchronize the shadow page tables. Kernel PTE ++ * updates should either be sets, clears, or set_pte_atomic for P->P ++ * transitions, which means this hook should only be called for user PTEs. ++ * This hook implies a P->P protection or access change has taken place, which ++ * requires a subsequent TLB flush. The notification can optionally be delayed ++ * until the TLB flush event by using the pte_update_defer form of the ++ * interface, but care must be taken to assure that the flush happens while ++ * still holding the same page table lock so that the shadow and primary pages ++ * do not become out of sync on SMP. ++ */ ++#define pte_update(mm, addr, ptep) do { } while (0) ++#define pte_update_defer(mm, addr, ptep) do { } while (0) ++ ++ ++/* ++ * We only update the dirty/accessed state if we set ++ * the dirty bit by hand in the kernel, since the hardware ++ * will do the accessed bit for us, and we don't want to ++ * race with other CPU's that might be updating the dirty ++ * bit at the same time. ++ */ ++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ ++do { \ ++ if (dirty) \ ++ ptep_establish(vma, address, ptep, entry); \ ++} while (0) ++ ++/* ++ * We don't actually have these, but we want to advertise them so that ++ * we can encompass the flush here. ++ */ ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++ ++/* ++ * Rules for using ptep_establish: the pte MUST be a user pte, and ++ * must be a present->present transition. ++ */ ++#define __HAVE_ARCH_PTEP_ESTABLISH ++#define ptep_establish(vma, address, ptep, pteval) \ ++do { \ ++ if ( likely((vma)->vm_mm == current->mm) ) { \ ++ BUG_ON(HYPERVISOR_update_va_mapping(address, \ ++ pteval, \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI)); \ ++ } else { \ ++ xen_l1_entry_update(ptep, pteval); \ ++ flush_tlb_page(vma, address); \ ++ } \ ++} while (0) ++ ++#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH ++#define ptep_clear_flush_dirty(vma, address, ptep) \ + ({ \ + pte_t __pte = *(ptep); \ +- int __ret = pte_dirty(__pte); \ +- if (__ret) { \ +- __pte = pte_mkclean(__pte); \ +- if ((vma)->vm_mm != current->mm || \ +- HYPERVISOR_update_va_mapping(addr, __pte, 0)) \ +- (ptep)->pte_low = __pte.pte_low; \ +- } \ +- __ret; \ ++ int __dirty = pte_dirty(__pte); \ ++ __pte = pte_mkclean(__pte); \ ++ if (test_bit(PG_pinned, &virt_to_page((vma)->vm_mm->pgd)->flags)) \ ++ ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ ++ else if (__dirty) \ ++ (ptep)->pte_low = __pte.pte_low; \ ++ __dirty; \ + }) + +-#define ptep_test_and_clear_young(vma, addr, ptep) \ ++#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH ++#define ptep_clear_flush_young(vma, address, ptep) \ + ({ \ + pte_t __pte = *(ptep); \ +- int __ret = pte_young(__pte); \ +- if (__ret) \ +- __pte = pte_mkold(__pte); \ +- if ((vma)->vm_mm != current->mm || \ +- HYPERVISOR_update_va_mapping(addr, __pte, 0)) \ +- (ptep)->pte_low = __pte.pte_low; \ +- __ret; \ ++ int __young = pte_young(__pte); \ ++ __pte = pte_mkold(__pte); \ ++ if (test_bit(PG_pinned, &virt_to_page((vma)->vm_mm->pgd)->flags)) \ ++ ptep_set_access_flags(vma, address, ptep, __pte, __young); \ ++ else if (__young) \ ++ (ptep)->pte_low = __pte.pte_low; \ ++ __young; \ + }) + ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL + #define ptep_get_and_clear_full(mm, addr, ptep, full) \ + ((full) ? ({ \ + pte_t __res = *(ptep); \ +@@ -296,6 +354,7 @@ static inline pte_t pte_mkhuge(pte_t pte + }) : \ + ptep_get_and_clear(mm, addr, ptep)) + ++#define __HAVE_ARCH_PTEP_SET_WRPROTECT + static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + pte_t pte = *ptep; +@@ -391,11 +450,11 @@ static inline pte_t pte_modify(pte_t pte + #define pte_index(address) \ + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + #define pte_offset_kernel(dir, address) \ +- ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(address)) ++ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) + + #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) + +-#define pmd_page_kernel(pmd) \ ++#define pmd_page_vaddr(pmd) \ + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + + /* +@@ -418,8 +477,6 @@ extern pte_t *lookup_address(unsigned lo + static inline int set_kernel_exec(unsigned long vaddr, int enable) { return 0;} + #endif + +-extern void noexec_setup(const char *str); +- + #if defined(CONFIG_HIGHPTE) + #define pte_offset_map(dir, address) \ + ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + \ +@@ -437,37 +494,17 @@ extern void noexec_setup(const char *str + #define pte_unmap_nested(pte) do { } while (0) + #endif + +-#define __HAVE_ARCH_PTEP_ESTABLISH +-#define ptep_establish(vma, address, ptep, pteval) \ +- do { \ +- if ( likely((vma)->vm_mm == current->mm) ) { \ +- BUG_ON(HYPERVISOR_update_va_mapping(address, \ +- pteval, \ +- (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ +- UVMF_INVLPG|UVMF_MULTI)); \ +- } else { \ +- xen_l1_entry_update(ptep, pteval); \ +- flush_tlb_page(vma, address); \ +- } \ +- } while (0) ++/* Clear a kernel PTE and flush it from the TLB */ ++#define kpte_clear_flush(ptep, vaddr) do { \ ++ if (HYPERVISOR_update_va_mapping(vaddr, __pte(0), UVMF_INVLPG)) \ ++ BUG(); \ ++} while (0) + + /* + * The i386 doesn't have any external MMU info: the kernel page + * tables contain all the necessary information. +- * +- * Also, we only update the dirty/accessed state if we set +- * the dirty bit by hand in the kernel, since the hardware +- * will do the accessed bit for us, and we don't want to +- * race with other CPU's that might be updating the dirty +- * bit at the same time. + */ + #define update_mmu_cache(vma,address,pte) do { } while (0) +-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS +-#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ +- do { \ +- if (dirty) \ +- ptep_establish(vma, address, ptep, entry); \ +- } while (0) + + #include + void make_lowmem_page_readonly(void *va, unsigned int feature); +@@ -526,10 +563,11 @@ int touch_pte_range(struct mm_struct *mm + unsigned long size); + + int xen_change_pte_range(struct mm_struct *mm, pmd_t *pmd, +- unsigned long addr, unsigned long end, pgprot_t newprot); ++ unsigned long addr, unsigned long end, pgprot_t newprot, ++ int dirty_accountable); + +-#define arch_change_pte_range(mm, pmd, addr, end, newprot) \ +- xen_change_pte_range(mm, pmd, addr, end, newprot) ++#define arch_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) \ ++ xen_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) + + #define io_remap_pfn_range(vma,from,pfn,size,prot) \ + direct_remap_pfn_range(vma,from,pfn,size,prot,DOMID_IO) +@@ -538,13 +576,6 @@ direct_remap_pfn_range(vma,from,pfn,size + #define GET_IOSPACE(pfn) 0 + #define GET_PFN(pfn) (pfn) + +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY +-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL +-#define __HAVE_ARCH_PTEP_CLEAR_FLUSH +-#define __HAVE_ARCH_PTEP_SET_WRPROTECT +-#define __HAVE_ARCH_PTE_SAME + #include + + #endif /* _I386_PGTABLE_H */ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/processor_32.h 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/processor_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -146,6 +146,18 @@ static inline void detect_ht(struct cpui + #define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ + #define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ + ++static inline void __cpuid(unsigned int *eax, unsigned int *ebx, ++ unsigned int *ecx, unsigned int *edx) ++{ ++ /* ecx is often an input as well as an output. */ ++ __asm__(XEN_CPUID ++ : "=a" (*eax), ++ "=b" (*ebx), ++ "=c" (*ecx), ++ "=d" (*edx) ++ : "0" (*eax), "2" (*ecx)); ++} ++ + /* + * Generic CPUID function + * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx +@@ -153,24 +165,18 @@ static inline void detect_ht(struct cpui + */ + static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) + { +- __asm__(XEN_CPUID +- : "=a" (*eax), +- "=b" (*ebx), +- "=c" (*ecx), +- "=d" (*edx) +- : "0" (op), "c"(0)); ++ *eax = op; ++ *ecx = 0; ++ __cpuid(eax, ebx, ecx, edx); + } + + /* Some CPUID calls want 'count' to be placed in ecx */ + static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, +- int *edx) ++ int *edx) + { +- __asm__(XEN_CPUID +- : "=a" (*eax), +- "=b" (*ebx), +- "=c" (*ecx), +- "=d" (*edx) +- : "0" (op), "c" (count)); ++ *eax = op; ++ *ecx = count; ++ __cpuid(eax, ebx, ecx, edx); + } + + /* +@@ -178,42 +184,30 @@ static inline void cpuid_count(int op, i + */ + static inline unsigned int cpuid_eax(unsigned int op) + { +- unsigned int eax; ++ unsigned int eax, ebx, ecx, edx; + +- __asm__(XEN_CPUID +- : "=a" (eax) +- : "0" (op) +- : "bx", "cx", "dx"); ++ cpuid(op, &eax, &ebx, &ecx, &edx); + return eax; + } + static inline unsigned int cpuid_ebx(unsigned int op) + { +- unsigned int eax, ebx; ++ unsigned int eax, ebx, ecx, edx; + +- __asm__(XEN_CPUID +- : "=a" (eax), "=b" (ebx) +- : "0" (op) +- : "cx", "dx" ); ++ cpuid(op, &eax, &ebx, &ecx, &edx); + return ebx; + } + static inline unsigned int cpuid_ecx(unsigned int op) + { +- unsigned int eax, ecx; ++ unsigned int eax, ebx, ecx, edx; + +- __asm__(XEN_CPUID +- : "=a" (eax), "=c" (ecx) +- : "0" (op) +- : "bx", "dx" ); ++ cpuid(op, &eax, &ebx, &ecx, &edx); + return ecx; + } + static inline unsigned int cpuid_edx(unsigned int op) + { +- unsigned int eax, edx; ++ unsigned int eax, ebx, ecx, edx; + +- __asm__(XEN_CPUID +- : "=a" (eax), "=d" (edx) +- : "0" (op) +- : "bx", "cx"); ++ cpuid(op, &eax, &ebx, &ecx, &edx); + return edx; + } + +@@ -315,6 +309,8 @@ static inline void __mwait(unsigned long + : :"a" (eax), "c" (ecx)); + } + ++extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); ++ + /* from system description table in BIOS. Mostly for MCA use, but + others may find it useful. */ + extern unsigned int machine_id; +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/segment_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/segment_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -61,11 +61,9 @@ + + #define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE + 0) + #define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8) +-#define GET_KERNEL_CS() (__KERNEL_CS | (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) ) + + #define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE + 1) + #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8) +-#define GET_KERNEL_DS() (__KERNEL_DS | (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) ) + + #define GDT_ENTRY_TSS (GDT_ENTRY_KERNEL_BASE + 4) + #define GDT_ENTRY_LDT (GDT_ENTRY_KERNEL_BASE + 5) +@@ -85,6 +83,11 @@ + + #define GDT_SIZE (GDT_ENTRIES * 8) + ++/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ ++#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) ++/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ ++#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) ++ + /* Simple and small GDT entries for booting only */ + + #define GDT_ENTRY_BOOT_CS 2 +@@ -114,4 +117,16 @@ + */ + #define IDT_ENTRIES 256 + ++/* Bottom two bits of selector give the ring privilege level */ ++#define SEGMENT_RPL_MASK 0x3 ++/* Bit 2 is table indicator (LDT/GDT) */ ++#define SEGMENT_TI_MASK 0x4 ++ ++/* User mode is privilege level 3 */ ++#define USER_RPL 0x3 ++/* LDT segment has TI set, GDT has it cleared */ ++#define SEGMENT_LDT 0x4 ++#define SEGMENT_GDT 0x0 ++ ++#define get_kernel_rpl() (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) + #endif +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/smp_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/smp_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -79,25 +79,36 @@ static inline int hard_smp_processor_id( + return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)); + } + #endif +- +-static __inline int logical_smp_processor_id(void) +-{ +- /* we don't want to mark this access volatile - bad code generation */ +- return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR)); +-} +- + #endif + ++#define safe_smp_processor_id() smp_processor_id() + extern int __cpu_disable(void); + extern void __cpu_die(unsigned int cpu); + extern void prefill_possible_map(void); ++extern unsigned int num_processors; ++ + #endif /* !__ASSEMBLY__ */ + + #else /* CONFIG_SMP */ + ++#define safe_smp_processor_id() 0 + #define cpu_physical_id(cpu) boot_cpu_physical_apicid + + #define NO_PROC_ID 0xFF /* No processor magic marker */ + + #endif ++ ++#ifndef __ASSEMBLY__ ++ ++extern u8 apicid_2_node[]; ++ ++#ifdef CONFIG_X86_LOCAL_APIC ++static __inline int logical_smp_processor_id(void) ++{ ++ /* we don't want to mark this access volatile - bad code generation */ ++ return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR)); ++} ++#endif ++#endif ++ + #endif +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/system_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/system_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -267,6 +267,9 @@ static inline unsigned long __xchg(unsig + #define cmpxchg(ptr,o,n)\ + ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ + (unsigned long)(n),sizeof(*(ptr)))) ++#define sync_cmpxchg(ptr,o,n)\ ++ ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\ ++ (unsigned long)(n),sizeof(*(ptr)))) + #endif + + static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, +@@ -296,6 +299,39 @@ static inline unsigned long __cmpxchg(vo + return old; + } + ++/* ++ * Always use locked operations when touching memory shared with a ++ * hypervisor, since the system may be SMP even if the guest kernel ++ * isn't. ++ */ ++static inline unsigned long __sync_cmpxchg(volatile void *ptr, ++ unsigned long old, ++ unsigned long new, int size) ++{ ++ unsigned long prev; ++ switch (size) { ++ case 1: ++ __asm__ __volatile__("lock; cmpxchgb %b1,%2" ++ : "=a"(prev) ++ : "q"(new), "m"(*__xg(ptr)), "0"(old) ++ : "memory"); ++ return prev; ++ case 2: ++ __asm__ __volatile__("lock; cmpxchgw %w1,%2" ++ : "=a"(prev) ++ : "r"(new), "m"(*__xg(ptr)), "0"(old) ++ : "memory"); ++ return prev; ++ case 4: ++ __asm__ __volatile__("lock; cmpxchgl %1,%2" ++ : "=a"(prev) ++ : "r"(new), "m"(*__xg(ptr)), "0"(old) ++ : "memory"); ++ return prev; ++ } ++ return old; ++} ++ + #ifndef CONFIG_X86_CMPXCHG + /* + * Building a kernel capable running on 80386. It may be necessary to +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/tlbflush_32.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/tlbflush_32.h 2009-03-04 11:28:34.000000000 +0100 +@@ -8,8 +8,6 @@ + #define __flush_tlb_global() xen_tlb_flush() + #define __flush_tlb_all() xen_tlb_flush() + +-extern unsigned long pgkern_mask; +- + #define cpu_has_invlpg (boot_cpu_data.x86 > 3) + + #define __flush_tlb_single(addr) xen_invlpg(addr) +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -55,13 +55,6 @@ extern dma_addr_t bad_dma_address; + extern struct dma_mapping_ops* dma_ops; + extern int iommu_merge; + +-static inline int valid_dma_direction(int dma_direction) +-{ +- return ((dma_direction == DMA_BIDIRECTIONAL) || +- (dma_direction == DMA_TO_DEVICE) || +- (dma_direction == DMA_FROM_DEVICE)); +-} +- + #if 0 + static inline int dma_mapping_error(dma_addr_t dma_addr) + { +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/fixmap_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/fixmap_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -41,7 +41,7 @@ enum fixed_addresses { + #ifdef CONFIG_X86_LOCAL_APIC + FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ + #endif +-#ifdef CONFIG_X86_IO_APIC ++#ifndef CONFIG_XEN + FIX_IO_APIC_BASE_0, + FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1, + #endif +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -44,12 +44,9 @@ extern unsigned long __supported_pte_mas + + #define swapper_pg_dir init_level4_pgt + +-extern int nonx_setup(char *str); + extern void paging_init(void); + extern void clear_kernel_mapping(unsigned long addr, unsigned long size); + +-extern unsigned long pgkern_mask; +- + /* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. +@@ -119,9 +116,6 @@ static inline void pgd_clear (pgd_t * pg + set_pgd(__user_pgd(pgd), __pgd(0)); + } + +-#define pud_page(pud) \ +- ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK)) +- + #define pte_same(a, b) ((a).pte == (b).pte) + + #define pte_pgprot(a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK)) +@@ -333,7 +327,7 @@ static inline pte_t ptep_get_and_clear_f + #define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT) + static inline int pte_user(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } + static inline int pte_read(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } +-static inline int pte_exec(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } ++static inline int pte_exec(pte_t pte) { return !(__pte_val(pte) & _PAGE_NX); } + 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_write(pte_t pte) { return __pte_val(pte) & _PAGE_RW; } +@@ -346,29 +340,12 @@ static inline pte_t pte_mkclean(pte_t pt + static inline pte_t pte_mkold(pte_t pte) { __pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } + static inline pte_t pte_wrprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_RW; return pte; } + static inline pte_t pte_mkread(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; } +-static inline pte_t pte_mkexec(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; } ++static inline pte_t pte_mkexec(pte_t pte) { __pte_val(pte) &= ~_PAGE_NX; 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_mkhuge(pte_t pte) { __pte_val(pte) |= _PAGE_PSE; return pte; } +- +-#define ptep_test_and_clear_dirty(vma, addr, ptep) \ +-({ \ +- pte_t __pte = *(ptep); \ +- int __ret = pte_dirty(__pte); \ +- if (__ret) \ +- set_pte_at((vma)->vm_mm, addr, ptep, pte_mkclean(__pte)); \ +- __ret; \ +-}) +- +-#define ptep_test_and_clear_young(vma, addr, ptep) \ +-({ \ +- pte_t __pte = *(ptep); \ +- int __ret = pte_young(__pte); \ +- if (__ret) \ +- set_pte_at((vma)->vm_mm, addr, ptep, pte_mkold(__pte)); \ +- __ret; \ +-}) ++static inline pte_t pte_clrhuge(pte_t pte) { __pte_val(pte) &= ~_PAGE_PSE; return pte; } + + static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { +@@ -395,7 +372,8 @@ static inline int pmd_large(pmd_t pte) { + /* + * Level 4 access. + */ +-#define pgd_page(pgd) ((unsigned long) __va(pgd_val(pgd) & PTE_MASK)) ++#define pgd_page_vaddr(pgd) ((unsigned long) __va(pgd_val(pgd) & PTE_MASK)) ++#define pgd_page(pgd) (pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)) + #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) + #define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) + #define pgd_offset_k(address) (init_level4_pgt + pgd_index(address)) +@@ -404,16 +382,18 @@ static inline int pmd_large(pmd_t pte) { + + /* PUD - Level3 access */ + /* to find an entry in a page-table-directory. */ ++#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PHYSICAL_PAGE_MASK)) ++#define pud_page(pud) (pfn_to_page(pud_val(pud) >> PAGE_SHIFT)) + #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) +-#define pud_offset(pgd, address) ((pud_t *) pgd_page(*(pgd)) + pud_index(address)) ++#define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address)) + #define pud_present(pud) (__pud_val(pud) & _PAGE_PRESENT) + + /* PMD - Level 2 access */ +-#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK)) ++#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK)) + #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) + + #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) +-#define pmd_offset(dir, address) ((pmd_t *) pud_page(*(dir)) + \ ++#define pmd_offset(dir, address) ((pmd_t *) pud_page_vaddr(*(dir)) + \ + pmd_index(address)) + #define pmd_none(x) (!__pmd_val(x)) + #if CONFIG_XEN_COMPAT <= 0x030002 +@@ -444,6 +424,7 @@ static inline pte_t mk_pte_phys(unsigned + { + unsigned long pteval; + pteval = physpage | pgprot_val(pgprot); ++ pteval &= __supported_pte_mask; + return __pte(pteval); + } + +@@ -465,7 +446,7 @@ static inline pte_t pte_modify(pte_t pte + + #define pte_index(address) \ + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +-#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \ ++#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + \ + pte_index(address)) + + /* x86-64 always has all page tables mapped. */ +@@ -506,6 +487,40 @@ static inline pte_t pte_modify(pte_t pte + ptep_establish(vma, address, ptep, entry); \ + } while (0) + ++ ++/* ++ * i386 says: We don't actually have these, but we want to advertise ++ * them so that we can encompass the flush here. ++ */ ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++ ++#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH ++#define ptep_clear_flush_dirty(vma, address, ptep) \ ++({ \ ++ pte_t __pte = *(ptep); \ ++ int __dirty = pte_dirty(__pte); \ ++ __pte = pte_mkclean(__pte); \ ++ if ((vma)->vm_mm->context.pinned) \ ++ ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ ++ else if (__dirty) \ ++ set_pte(ptep, __pte); \ ++ __dirty; \ ++}) ++ ++#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH ++#define ptep_clear_flush_young(vma, address, ptep) \ ++({ \ ++ pte_t __pte = *(ptep); \ ++ int __young = pte_young(__pte); \ ++ __pte = pte_mkold(__pte); \ ++ if ((vma)->vm_mm->context.pinned) \ ++ ptep_set_access_flags(vma, address, ptep, __pte, __young); \ ++ else if (__young) \ ++ set_pte(ptep, __pte); \ ++ __young; \ ++}) ++ + /* Encode and de-code a swap entry */ + #define __swp_type(x) (((x).val >> 1) & 0x3f) + #define __swp_offset(x) ((x).val >> 8) +@@ -547,10 +562,11 @@ int touch_pte_range(struct mm_struct *mm + unsigned long size); + + int xen_change_pte_range(struct mm_struct *mm, pmd_t *pmd, +- unsigned long addr, unsigned long end, pgprot_t newprot); ++ unsigned long addr, unsigned long end, pgprot_t newprot, ++ int dirty_accountable); + +-#define arch_change_pte_range(mm, pmd, addr, end, newprot) \ +- xen_change_pte_range(mm, pmd, addr, end, newprot) ++#define arch_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) \ ++ xen_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) + + #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO) +@@ -572,8 +588,6 @@ int xen_change_pte_range(struct mm_struc + #define kc_offset_to_vaddr(o) \ + (((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o)) + +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL + #define __HAVE_ARCH_PTEP_CLEAR_FLUSH +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/processor_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/processor_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -484,6 +484,8 @@ static inline void __mwait(unsigned long + : :"a" (eax), "c" (ecx)); + } + ++extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); ++ + #define stack_current() \ + ({ \ + struct thread_info *ti; \ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/smp_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/smp_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -4,15 +4,12 @@ + /* + * We need the APIC definitions automatically as part of 'smp.h' + */ +-#ifndef __ASSEMBLY__ + #include + #include + #include + extern int disable_apic; +-#endif + + #ifdef CONFIG_X86_LOCAL_APIC +-#ifndef __ASSEMBLY__ + #include + #include + #ifdef CONFIG_X86_IO_APIC +@@ -21,10 +18,8 @@ extern int disable_apic; + #include + #include + #endif +-#endif + + #ifdef CONFIG_SMP +-#ifndef ASSEMBLY + + #include + +@@ -41,14 +36,11 @@ extern cpumask_t cpu_initialized; + + extern void smp_alloc_memory(void); + extern volatile unsigned long smp_invalidate_needed; +-extern int pic_mode; + extern void lock_ipi_call_lock(void); + extern void unlock_ipi_call_lock(void); + extern int smp_num_siblings; + extern void smp_send_reschedule(int cpu); + void smp_stop_cpu(void); +-extern int smp_call_function_single(int cpuid, void (*func) (void *info), +- void *info, int retry, int wait); + + extern cpumask_t cpu_sibling_map[NR_CPUS]; + extern cpumask_t cpu_core_map[NR_CPUS]; +@@ -77,20 +69,16 @@ static inline int hard_smp_processor_id( + } + #endif + +-extern int safe_smp_processor_id(void); + extern int __cpu_disable(void); + extern void __cpu_die(unsigned int cpu); + extern void prefill_possible_map(void); + extern unsigned num_processors; + extern unsigned disabled_cpus; + +-#endif /* !ASSEMBLY */ +- + #define NO_PROC_ID 0xFF /* No processor magic marker */ + + #endif + +-#ifndef ASSEMBLY + /* + * Some lowlevel functions might want to know about + * the real APIC ID <-> CPU # mapping. +@@ -114,11 +102,8 @@ static inline int cpu_present_to_apicid( + } + #endif + +-#endif /* !ASSEMBLY */ +- + #ifndef CONFIG_SMP + #define stack_smp_processor_id() 0 +-#define safe_smp_processor_id() 0 + #define cpu_logical_map(x) (x) + #else + #include +@@ -130,7 +115,6 @@ static inline int cpu_present_to_apicid( + }) + #endif + +-#ifndef __ASSEMBLY__ + #ifdef CONFIG_X86_LOCAL_APIC + static __inline int logical_smp_processor_id(void) + { +@@ -138,13 +122,18 @@ static __inline int logical_smp_processo + return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR)); + } + #endif +-#endif + + #ifdef CONFIG_SMP + #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] + #else + #define cpu_physical_id(cpu) boot_cpu_id +-#endif +- ++static inline int smp_call_function_single(int cpuid, void (*func) (void *info), ++ void *info, int retry, int wait) ++{ ++ /* Disable interrupts here? */ ++ func(info); ++ return 0; ++} ++#endif /* !CONFIG_SMP */ + #endif + +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/system_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/system_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -24,6 +24,7 @@ + #define __EXTRA_CLOBBER \ + ,"rcx","rbx","rdx","r8","r9","r10","r11","r12","r13","r14","r15" + ++/* Save restore flags to clear handle leaking NT */ + #define switch_to(prev,next,last) \ + asm volatile(SAVE_CONTEXT \ + "movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/tlbflush_64.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/tlbflush_64.h 2009-03-04 11:28:34.000000000 +0100 +@@ -12,9 +12,6 @@ + */ + #define __flush_tlb_global() xen_tlb_flush() + +- +-extern unsigned long pgkern_mask; +- + #define __flush_tlb_all() __flush_tlb_global() + + #define __flush_tlb_one(addr) xen_invlpg((unsigned long)addr) +--- sle11-2009-05-14.orig/include/linux/skbuff.h 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/include/linux/skbuff.h 2009-03-04 11:28:34.000000000 +0100 +@@ -1771,5 +1771,12 @@ static inline void skb_forward_csum(stru + } + + bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); ++ ++#ifdef CONFIG_XEN ++int skb_checksum_setup(struct sk_buff *skb); ++#else ++static inline int skb_checksum_setup(struct sk_buff *skb) { return 0; } ++#endif ++ + #endif /* __KERNEL__ */ + #endif /* _LINUX_SKBUFF_H */ +--- sle11-2009-05-14.orig/include/xen/evtchn.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/xen/evtchn.h 2009-03-04 11:28:34.000000000 +0100 +@@ -54,34 +54,34 @@ + */ + int bind_caller_port_to_irqhandler( + unsigned int caller_port, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id); + int bind_listening_port_to_irqhandler( + unsigned int remote_domain, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id); + int bind_interdomain_evtchn_to_irqhandler( + unsigned int remote_domain, + unsigned int remote_port, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id); + int bind_virq_to_irqhandler( + unsigned int virq, + unsigned int cpu, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id); + int bind_ipi_to_irqhandler( + unsigned int ipi, + unsigned int cpu, +- irqreturn_t (*handler)(int, void *, struct pt_regs *), ++ irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_id); +--- sle11-2009-05-14.orig/include/xen/xencons.h 2009-05-14 11:02:43.000000000 +0200 ++++ sle11-2009-05-14/include/xen/xencons.h 2009-03-04 11:28:34.000000000 +0100 +@@ -8,7 +8,7 @@ void xencons_force_flush(void); + void xencons_resume(void); + + /* Interrupt work hooks. Receive data, or kick data out. */ +-void xencons_rx(char *buf, unsigned len, struct pt_regs *regs); ++void xencons_rx(char *buf, unsigned len); + void xencons_tx(void); + + int xencons_ring_init(void); +--- sle11-2009-05-14.orig/mm/mprotect.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/mm/mprotect.c 2009-03-04 11:28:34.000000000 +0100 +@@ -92,7 +92,7 @@ static inline void change_pmd_range(stru + next = pmd_addr_end(addr, end); + if (pmd_none_or_clear_bad(pmd)) + continue; +- if (arch_change_pte_range(mm, pmd, addr, next, newprot)) ++ if (arch_change_pte_range(mm, pmd, addr, next, newprot, dirty_accountable)) + continue; + change_pte_range(mm, pmd, addr, next, newprot, dirty_accountable); + } while (pmd++, addr = next, addr != end); +--- sle11-2009-05-14.orig/net/core/dev.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/net/core/dev.c 2009-03-04 11:28:34.000000000 +0100 +@@ -1765,15 +1765,14 @@ inline int skb_checksum_setup(struct sk_ + } + if ((skb->h.raw + skb->csum + 2) > skb->tail) + goto out; +- skb->ip_summed = CHECKSUM_HW; ++ skb->ip_summed = CHECKSUM_PARTIAL; + skb->proto_csum_blank = 0; + } + return 0; + out: + return -EPROTO; + } +-#else +-inline int skb_checksum_setup(struct sk_buff *skb) { return 0; } ++EXPORT_SYMBOL(skb_checksum_setup); + #endif + + /** +@@ -2327,7 +2326,7 @@ int netif_receive_skb(struct sk_buff *sk + case CHECKSUM_UNNECESSARY: + skb->proto_data_valid = 1; + break; +- case CHECKSUM_HW: ++ case CHECKSUM_PARTIAL: + /* XXX Implement me. */ + default: + skb->proto_data_valid = 0; +@@ -4989,7 +4988,6 @@ EXPORT_SYMBOL(unregister_netdevice_notif + EXPORT_SYMBOL(net_enable_timestamp); + EXPORT_SYMBOL(net_disable_timestamp); + EXPORT_SYMBOL(dev_get_flags); +-EXPORT_SYMBOL(skb_checksum_setup); + + #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + EXPORT_SYMBOL(br_handle_frame_hook); diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.20 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.20 new file mode 100644 index 000000000..88c02c9f0 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.20 @@ -0,0 +1,7153 @@ +From: www.kernel.org +Subject: Linux 2.6.20 +Patch-mainline: 2.6.20 + +Automatically created from "patches.kernel.org/patch-2.6.20" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-06-29.orig/arch/x86/Kconfig 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/Kconfig 2009-02-05 10:22:19.000000000 +0100 +@@ -1431,7 +1431,7 @@ config PHYSICAL_START + + config RELOCATABLE + bool "Build a relocatable kernel (EXPERIMENTAL)" +- depends on EXPERIMENTAL ++ depends on EXPERIMENTAL && !X86_XEN + help + This builds a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. +--- sle11-2009-06-29.orig/arch/x86/kernel/asm-offsets_32.c 2008-11-25 12:35:53.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/asm-offsets_32.c 2008-12-15 11:26:44.000000000 +0100 +@@ -54,6 +54,7 @@ void foo(void) + OFFSET(TI_exec_domain, thread_info, exec_domain); + OFFSET(TI_flags, thread_info, flags); + OFFSET(TI_status, thread_info, status); ++ OFFSET(TI_cpu, thread_info, cpu); + OFFSET(TI_preempt_count, thread_info, preempt_count); + OFFSET(TI_addr_limit, thread_info, addr_limit); + OFFSET(TI_restart_block, thread_info, restart_block); +@@ -108,6 +109,11 @@ void foo(void) + + OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); + ++#ifdef CONFIG_XEN ++ BLANK(); ++ OFFSET(XEN_START_mfn_list, start_info, mfn_list); ++#endif ++ + #ifdef CONFIG_PARAVIRT + BLANK(); + OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled); +--- sle11-2009-06-29.orig/arch/x86/kernel/cpu/common-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/cpu/common-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -22,6 +22,7 @@ + #define phys_pkg_id(a,b) a + #endif + #endif ++#include + #include + + #include "cpu.h" +@@ -29,10 +30,8 @@ + DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); + EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); + +-#ifndef CONFIG_XEN +-DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); +-EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); +-#endif ++struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly; ++EXPORT_SYMBOL(_cpu_pda); + + static int cachesize_override __cpuinitdata = -1; + static int disable_x86_fxsr __cpuinitdata; +@@ -60,7 +59,7 @@ static struct cpu_dev __cpuinitdata defa + .c_init = default_init, + .c_vendor = "Unknown", + }; +-static struct cpu_dev * this_cpu = &default_cpu; ++static struct cpu_dev * this_cpu __cpuinitdata = &default_cpu; + + static int __init cachesize_setup(char *str) + { +@@ -242,29 +241,14 @@ static int __cpuinit have_cpuid_p(void) + return flag_is_changeable_p(X86_EFLAGS_ID); + } + +-/* Do minimum CPU detection early. +- Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. +- The others are not touched to avoid unwanted side effects. +- +- WARNING: this function is only called on the BP. Don't add code here +- that is supposed to run on all CPUs. */ +-static void __init early_cpu_detect(void) ++void __init cpu_detect(struct cpuinfo_x86 *c) + { +- struct cpuinfo_x86 *c = &boot_cpu_data; +- +- c->x86_cache_alignment = 32; +- +- if (!have_cpuid_p()) +- return; +- + /* Get vendor name */ + cpuid(0x00000000, &c->cpuid_level, + (int *)&c->x86_vendor_id[0], + (int *)&c->x86_vendor_id[8], + (int *)&c->x86_vendor_id[4]); + +- get_cpu_vendor(c, 1); +- + c->x86 = 4; + if (c->cpuid_level >= 0x00000001) { + u32 junk, tfms, cap0, misc; +@@ -281,6 +265,26 @@ static void __init early_cpu_detect(void + } + } + ++/* Do minimum CPU detection early. ++ Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. ++ The others are not touched to avoid unwanted side effects. ++ ++ WARNING: this function is only called on the BP. Don't add code here ++ that is supposed to run on all CPUs. */ ++static void __init early_cpu_detect(void) ++{ ++ struct cpuinfo_x86 *c = &boot_cpu_data; ++ ++ c->x86_cache_alignment = 32; ++ ++ if (!have_cpuid_p()) ++ return; ++ ++ cpu_detect(c); ++ ++ get_cpu_vendor(c, 1); ++} ++ + static void __cpuinit generic_identify(struct cpuinfo_x86 * c) + { + u32 tfms, xlvl; +@@ -315,6 +319,8 @@ static void __cpuinit generic_identify(s + #else + c->apicid = (ebx >> 24) & 0xFF; + #endif ++ if (c->x86_capability[0] & (1<<19)) ++ c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8; + } else { + /* Have CPUID level 0 only - unheard of */ + c->x86 = 4; +@@ -379,6 +385,7 @@ void __cpuinit identify_cpu(struct cpuin + c->x86_vendor_id[0] = '\0'; /* Unset */ + c->x86_model_id[0] = '\0'; /* Unset */ + c->x86_max_cores = 1; ++ c->x86_clflush_size = 32; + memset(&c->x86_capability, 0, sizeof c->x86_capability); + + if (!have_cpuid_p()) { +@@ -599,61 +606,23 @@ void __init early_cpu_init(void) + #endif + } + +-static void __cpuinit cpu_gdt_init(const struct Xgt_desc_struct *gdt_descr) ++/* Make sure %gs is initialized properly in idle threads */ ++struct pt_regs * __devinit idle_regs(struct pt_regs *regs) + { +- unsigned long frames[16]; +- unsigned long va; +- int f; +- +- for (va = gdt_descr->address, f = 0; +- va < gdt_descr->address + gdt_descr->size; +- va += PAGE_SIZE, f++) { +- frames[f] = virt_to_mfn(va); +- make_lowmem_page_readonly( +- (void *)va, XENFEAT_writable_descriptor_tables); +- } +- if (HYPERVISOR_set_gdt(frames, (gdt_descr->size + 1) / 8)) +- BUG(); ++ memset(regs, 0, sizeof(struct pt_regs)); ++ regs->xgs = __KERNEL_PDA; ++ return regs; + } + +-/* +- * cpu_init() initializes state that is per-CPU. Some data is already +- * initialized (naturally) in the bootstrap process, such as the GDT +- * and IDT. We reload them nevertheless, this function acts as a +- * 'CPU state barrier', nothing should get across. +- */ +-void __cpuinit cpu_init(void) ++static __cpuinit int alloc_gdt(int cpu) + { +- int cpu = smp_processor_id(); +-#ifndef CONFIG_X86_NO_TSS +- struct tss_struct * t = &per_cpu(init_tss, cpu); +-#endif +- struct thread_struct *thread = ¤t->thread; +- struct desc_struct *gdt; + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ struct desc_struct *gdt; ++ struct i386_pda *pda; + +- if (cpu_test_and_set(cpu, cpu_initialized)) { +- printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); +- for (;;) local_irq_enable(); +- } +- printk(KERN_INFO "Initializing CPU#%d\n", cpu); +- +- if (cpu_has_vme || cpu_has_de) +- clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); +- if (tsc_disable && cpu_has_tsc) { +- printk(KERN_NOTICE "Disabling TSC...\n"); +- /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ +- clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); +- set_in_cr4(X86_CR4_TSD); +- } ++ gdt = (struct desc_struct *)cpu_gdt_descr->address; ++ pda = cpu_pda(cpu); + +-#ifndef CONFIG_XEN +- /* The CPU hotplug case */ +- if (cpu_gdt_descr->address) { +- gdt = (struct desc_struct *)cpu_gdt_descr->address; +- memset(gdt, 0, PAGE_SIZE); +- goto old_gdt; +- } + /* + * This is a horrible hack to allocate the GDT. The problem + * is that cpu_init() is called really early for the boot CPU +@@ -661,54 +630,141 @@ void __cpuinit cpu_init(void) + * CPUs, when bootmem will have gone away + */ + if (NODE_DATA(0)->bdata->node_bootmem_map) { +- gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE); +- /* alloc_bootmem_pages panics on failure, so no check */ ++ BUG_ON(gdt != NULL || pda != NULL); ++ ++ gdt = alloc_bootmem_pages(PAGE_SIZE); ++ pda = alloc_bootmem(sizeof(*pda)); ++ /* alloc_bootmem(_pages) panics on failure, so no check */ ++ + memset(gdt, 0, PAGE_SIZE); ++ memset(pda, 0, sizeof(*pda)); + } else { +- gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); +- if (unlikely(!gdt)) { +- printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu); +- for (;;) +- local_irq_enable(); ++ /* GDT and PDA might already have been allocated if ++ this is a CPU hotplug re-insertion. */ ++ if (gdt == NULL) ++ gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); ++ ++ if (pda == NULL) ++ pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu)); ++ ++ if (unlikely(!gdt || !pda)) { ++ free_pages((unsigned long)gdt, 0); ++ kfree(pda); ++ return 0; + } + } +-old_gdt: ++ ++ cpu_gdt_descr->address = (unsigned long)gdt; ++ cpu_pda(cpu) = pda; ++ ++ return 1; ++} ++ ++/* Initial PDA used by boot CPU */ ++struct i386_pda boot_pda = { ++ ._pda = &boot_pda, ++ .cpu_number = 0, ++ .pcurrent = &init_task, ++}; ++ ++static inline void set_kernel_gs(void) ++{ ++ /* Set %gs for this CPU's PDA. Memory clobber is to create a ++ barrier with respect to any PDA operations, so the compiler ++ doesn't move any before here. */ ++ asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory"); ++} ++ ++/* Initialize the CPU's GDT and PDA. The boot CPU does this for ++ itself, but secondaries find this done for them. */ ++__cpuinit int init_gdt(int cpu, struct task_struct *idle) ++{ ++ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ struct desc_struct *gdt; ++ struct i386_pda *pda; ++ ++ /* For non-boot CPUs, the GDT and PDA should already have been ++ allocated. */ ++ if (!alloc_gdt(cpu)) { ++ printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu); ++ return 0; ++ } ++ ++ gdt = (struct desc_struct *)cpu_gdt_descr->address; ++ pda = cpu_pda(cpu); ++ ++ BUG_ON(gdt == NULL || pda == NULL); ++ + /* + * Initialize the per-CPU GDT with the boot GDT, + * and set up the GDT descriptor: + */ + memcpy(gdt, cpu_gdt_table, GDT_SIZE); ++ cpu_gdt_descr->size = GDT_SIZE - 1; + +- /* Set up GDT entry for 16bit stack */ +- *(__u64 *)(&gdt[GDT_ENTRY_ESPFIX_SS]) |= +- ((((__u64)stk16_off) << 16) & 0x000000ffffff0000ULL) | +- ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) | +- (CPU_16BIT_STACK_SIZE - 1); ++ pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, ++ (u32 *)&gdt[GDT_ENTRY_PDA].b, ++ (unsigned long)pda, sizeof(*pda) - 1, ++ 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ ++ ++ memset(pda, 0, sizeof(*pda)); ++ pda->_pda = pda; ++ pda->cpu_number = cpu; ++ pda->pcurrent = idle; + +- cpu_gdt_descr->size = GDT_SIZE - 1; +- cpu_gdt_descr->address = (unsigned long)gdt; +-#else +- if (cpu == 0 && cpu_gdt_descr->address == 0) { +- gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE); +- /* alloc_bootmem_pages panics on failure, so no check */ +- memset(gdt, 0, PAGE_SIZE); ++ return 1; ++} + +- memcpy(gdt, cpu_gdt_table, GDT_SIZE); +- +- cpu_gdt_descr->size = GDT_SIZE; +- cpu_gdt_descr->address = (unsigned long)gdt; ++void __cpuinit cpu_set_gdt(int cpu) ++{ ++ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ unsigned long va, frames[16]; ++ int f; ++ ++ for (va = cpu_gdt_descr->address, f = 0; ++ va < cpu_gdt_descr->address + cpu_gdt_descr->size; ++ va += PAGE_SIZE, f++) { ++ frames[f] = virt_to_mfn(va); ++ make_lowmem_page_readonly( ++ (void *)va, XENFEAT_writable_descriptor_tables); + } ++ BUG_ON(HYPERVISOR_set_gdt(frames, (cpu_gdt_descr->size + 1) / 8)); ++ ++ set_kernel_gs(); ++} ++ ++/* Common CPU init for both boot and secondary CPUs */ ++static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) ++{ ++#ifndef CONFIG_X86_NO_TSS ++ struct tss_struct * t = &per_cpu(init_tss, cpu); + #endif ++ struct thread_struct *thread = &curr->thread; ++ ++ if (cpu_test_and_set(cpu, cpu_initialized)) { ++ printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); ++ for (;;) local_irq_enable(); ++ } + +- cpu_gdt_init(cpu_gdt_descr); ++ printk(KERN_INFO "Initializing CPU#%d\n", cpu); ++ ++ if (cpu_has_vme || cpu_has_de) ++ clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); ++ if (tsc_disable && cpu_has_tsc) { ++ printk(KERN_NOTICE "Disabling TSC...\n"); ++ /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ ++ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); ++ set_in_cr4(X86_CR4_TSD); ++ } + + /* + * Set up and load the per-CPU TSS and LDT + */ + atomic_inc(&init_mm.mm_count); +- current->active_mm = &init_mm; +- BUG_ON(current->mm); +- enter_lazy_tlb(&init_mm, current); ++ curr->active_mm = &init_mm; ++ if (curr->mm) ++ BUG(); ++ enter_lazy_tlb(&init_mm, curr); + + load_esp0(t, thread); + +@@ -719,8 +775,8 @@ old_gdt: + __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); + #endif + +- /* Clear %fs and %gs. */ +- asm volatile ("movl %0, %%fs; movl %0, %%gs" : : "r" (0)); ++ /* Clear %fs. */ ++ asm volatile ("mov %0, %%fs" : : "r" (0)); + + /* Clear all 6 debug registers: */ + set_debugreg(0, 0); +@@ -738,6 +794,38 @@ old_gdt: + mxcsr_feature_mask_init(); + } + ++/* Entrypoint to initialize secondary CPU */ ++void __cpuinit secondary_cpu_init(void) ++{ ++ int cpu = smp_processor_id(); ++ struct task_struct *curr = current; ++ ++ _cpu_init(cpu, curr); ++} ++ ++/* ++ * cpu_init() initializes state that is per-CPU. Some data is already ++ * initialized (naturally) in the bootstrap process, such as the GDT ++ * and IDT. We reload them nevertheless, this function acts as a ++ * 'CPU state barrier', nothing should get across. ++ */ ++void __cpuinit cpu_init(void) ++{ ++ int cpu = smp_processor_id(); ++ struct task_struct *curr = current; ++ ++ /* Set up the real GDT and PDA, so we can transition from the ++ boot versions. */ ++ if (!init_gdt(cpu, curr)) { ++ /* failed to allocate something; not much we can do... */ ++ for (;;) ++ local_irq_enable(); ++ } ++ ++ cpu_set_gdt(cpu); ++ _cpu_init(cpu, curr); ++} ++ + #ifdef CONFIG_HOTPLUG_CPU + void __cpuinit cpu_uninit(void) + { +--- sle11-2009-06-29.orig/arch/x86/kernel/cpu/mtrr/main-xen.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/cpu/mtrr/main-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -12,7 +12,7 @@ + static DEFINE_MUTEX(mtrr_mutex); + + void generic_get_mtrr(unsigned int reg, unsigned long *base, +- unsigned int *size, mtrr_type * type) ++ unsigned long *size, mtrr_type * type) + { + struct xen_platform_op op; + +@@ -115,8 +115,7 @@ int mtrr_del_page(int reg, unsigned long + { + unsigned i; + mtrr_type ltype; +- unsigned long lbase; +- unsigned int lsize; ++ unsigned long lbase, lsize; + int error = -EINVAL; + struct xen_platform_op op; + +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/arch/x86/kernel/e820_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -0,0 +1,1015 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_EFI ++int efi_enabled = 0; ++EXPORT_SYMBOL(efi_enabled); ++#endif ++ ++struct e820map e820; ++struct change_member { ++ struct e820entry *pbios; /* pointer to original bios entry */ ++ unsigned long long addr; /* address for this change point */ ++}; ++static struct change_member change_point_list[2*E820MAX] __initdata; ++static struct change_member *change_point[2*E820MAX] __initdata; ++static struct e820entry *overlap_list[E820MAX] __initdata; ++static struct e820entry new_bios[E820MAX] __initdata; ++/* For PCI or other memory-mapped resources */ ++unsigned long pci_mem_start = 0x10000000; ++#ifdef CONFIG_PCI ++EXPORT_SYMBOL(pci_mem_start); ++#endif ++extern int user_defined_memmap; ++struct resource data_resource = { ++ .name = "Kernel data", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM ++}; ++ ++struct resource code_resource = { ++ .name = "Kernel code", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM ++}; ++ ++static struct resource system_rom_resource = { ++ .name = "System ROM", ++ .start = 0xf0000, ++ .end = 0xfffff, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}; ++ ++static struct resource extension_rom_resource = { ++ .name = "Extension ROM", ++ .start = 0xe0000, ++ .end = 0xeffff, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}; ++ ++static struct resource adapter_rom_resources[] = { { ++ .name = "Adapter ROM", ++ .start = 0xc8000, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}, { ++ .name = "Adapter ROM", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}, { ++ .name = "Adapter ROM", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}, { ++ .name = "Adapter ROM", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}, { ++ .name = "Adapter ROM", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}, { ++ .name = "Adapter ROM", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++} }; ++ ++static struct resource video_rom_resource = { ++ .name = "Video ROM", ++ .start = 0xc0000, ++ .end = 0xc7fff, ++ .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM ++}; ++ ++static struct resource video_ram_resource = { ++ .name = "Video RAM area", ++ .start = 0xa0000, ++ .end = 0xbffff, ++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM ++}; ++ ++static struct resource standard_io_resources[] = { { ++ .name = "dma1", ++ .start = 0x0000, ++ .end = 0x001f, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "pic1", ++ .start = 0x0020, ++ .end = 0x0021, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "timer0", ++ .start = 0x0040, ++ .end = 0x0043, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "timer1", ++ .start = 0x0050, ++ .end = 0x0053, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "keyboard", ++ .start = 0x0060, ++ .end = 0x006f, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "dma page reg", ++ .start = 0x0080, ++ .end = 0x008f, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "pic2", ++ .start = 0x00a0, ++ .end = 0x00a1, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "dma2", ++ .start = 0x00c0, ++ .end = 0x00df, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++}, { ++ .name = "fpu", ++ .start = 0x00f0, ++ .end = 0x00ff, ++ .flags = IORESOURCE_BUSY | IORESOURCE_IO ++} }; ++ ++static int romsignature(const unsigned char *x) ++{ ++ unsigned short sig; ++ int ret = 0; ++ if (probe_kernel_address((const unsigned short *)x, sig) == 0) ++ ret = (sig == 0xaa55); ++ return ret; ++} ++ ++static int __init romchecksum(unsigned char *rom, unsigned long length) ++{ ++ unsigned char *p, sum = 0; ++ ++ for (p = rom; p < rom + length; p++) ++ sum += *p; ++ return sum == 0; ++} ++ ++static void __init probe_roms(void) ++{ ++ unsigned long start, length, upper; ++ unsigned char *rom; ++ int i; ++ ++#ifdef CONFIG_XEN ++ /* Nothing to do if not running in dom0. */ ++ if (!is_initial_xendomain()) ++ return; ++#endif ++ ++ /* video rom */ ++ upper = adapter_rom_resources[0].start; ++ for (start = video_rom_resource.start; start < upper; start += 2048) { ++ rom = isa_bus_to_virt(start); ++ if (!romsignature(rom)) ++ continue; ++ ++ video_rom_resource.start = start; ++ ++ /* 0 < length <= 0x7f * 512, historically */ ++ length = rom[2] * 512; ++ ++ /* if checksum okay, trust length byte */ ++ if (length && romchecksum(rom, length)) ++ video_rom_resource.end = start + length - 1; ++ ++ request_resource(&iomem_resource, &video_rom_resource); ++ break; ++ } ++ ++ start = (video_rom_resource.end + 1 + 2047) & ~2047UL; ++ if (start < upper) ++ start = upper; ++ ++ /* system rom */ ++ request_resource(&iomem_resource, &system_rom_resource); ++ upper = system_rom_resource.start; ++ ++ /* check for extension rom (ignore length byte!) */ ++ rom = isa_bus_to_virt((unsigned long)extension_rom_resource.start); ++ if (romsignature(rom)) { ++ length = extension_rom_resource.end - extension_rom_resource.start + 1; ++ if (romchecksum(rom, length)) { ++ request_resource(&iomem_resource, &extension_rom_resource); ++ upper = extension_rom_resource.start; ++ } ++ } ++ ++ /* check for adapter roms on 2k boundaries */ ++ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { ++ rom = isa_bus_to_virt(start); ++ if (!romsignature(rom)) ++ continue; ++ ++ /* 0 < length <= 0x7f * 512, historically */ ++ length = rom[2] * 512; ++ ++ /* but accept any length that fits if checksum okay */ ++ if (!length || start + length > upper || !romchecksum(rom, length)) ++ continue; ++ ++ adapter_rom_resources[i].start = start; ++ adapter_rom_resources[i].end = start + length - 1; ++ request_resource(&iomem_resource, &adapter_rom_resources[i]); ++ ++ start = adapter_rom_resources[i++].end & ~2047UL; ++ } ++} ++ ++#ifdef CONFIG_XEN ++static struct e820map machine_e820 __initdata; ++#define e820 machine_e820 ++#endif ++ ++/* ++ * Request address space for all standard RAM and ROM resources ++ * and also for regions reported as reserved by the e820. ++ */ ++static void __init ++legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource) ++{ ++ int i; ++ ++ probe_roms(); ++ for (i = 0; i < e820.nr_map; i++) { ++ struct resource *res; ++#ifndef CONFIG_RESOURCES_64BIT ++ if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) ++ continue; ++#endif ++ res = kzalloc(sizeof(struct resource), GFP_ATOMIC); ++ switch (e820.map[i].type) { ++ case E820_RAM: res->name = "System RAM"; break; ++ case E820_ACPI: res->name = "ACPI Tables"; break; ++ case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; ++ default: res->name = "reserved"; ++ } ++ res->start = e820.map[i].addr; ++ res->end = res->start + e820.map[i].size - 1; ++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; ++ if (request_resource(&iomem_resource, res)) { ++ kfree(res); ++ continue; ++ } ++ if (e820.map[i].type == E820_RAM) { ++ /* ++ * We don't know which RAM region contains kernel data, ++ * so we try it repeatedly and let the resource manager ++ * test it. ++ */ ++#ifndef CONFIG_XEN ++ request_resource(res, code_resource); ++ request_resource(res, data_resource); ++#endif ++#ifdef CONFIG_KEXEC ++ request_resource(res, &crashk_res); ++#ifdef CONFIG_XEN ++ xen_machine_kexec_register_resources(res); ++#endif ++#endif ++ } ++ } ++} ++ ++#undef e820 ++ ++/* ++ * Request address space for all standard resources ++ * ++ * This is called just before pcibios_init(), which is also a ++ * subsys_initcall, but is linked in later (in arch/i386/pci/common.c). ++ */ ++static int __init request_standard_resources(void) ++{ ++ int i; ++ ++ /* Nothing to do if not running in dom0. */ ++ if (!is_initial_xendomain()) ++ return 0; ++ ++ printk("Setting up standard PCI resources\n"); ++ if (efi_enabled) ++ efi_initialize_iomem_resources(&code_resource, &data_resource); ++ else ++ legacy_init_iomem_resources(&code_resource, &data_resource); ++ ++ /* EFI systems may still have VGA */ ++ request_resource(&iomem_resource, &video_ram_resource); ++ ++ /* request I/O space for devices used on all i[345]86 PCs */ ++ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) ++ request_resource(&ioport_resource, &standard_io_resources[i]); ++ return 0; ++} ++ ++subsys_initcall(request_standard_resources); ++ ++void __init add_memory_region(unsigned long long start, ++ unsigned long long size, int type) ++{ ++ int x; ++ ++ if (!efi_enabled) { ++ x = e820.nr_map; ++ ++ if (x == E820MAX) { ++ printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); ++ return; ++ } ++ ++ e820.map[x].addr = start; ++ e820.map[x].size = size; ++ e820.map[x].type = type; ++ e820.nr_map++; ++ } ++} /* add_memory_region */ ++ ++/* ++ * Sanitize the BIOS e820 map. ++ * ++ * Some e820 responses include overlapping entries. The following ++ * replaces the original e820 map with a new one, removing overlaps. ++ * ++ */ ++int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) ++{ ++ struct change_member *change_tmp; ++ unsigned long current_type, last_type; ++ unsigned long long last_addr; ++ int chgidx, still_changing; ++ int overlap_entries; ++ int new_bios_entry; ++ int old_nr, new_nr, chg_nr; ++ int i; ++ ++ /* ++ Visually we're performing the following (1,2,3,4 = memory types)... ++ ++ Sample memory map (w/overlaps): ++ ____22__________________ ++ ______________________4_ ++ ____1111________________ ++ _44_____________________ ++ 11111111________________ ++ ____________________33__ ++ ___________44___________ ++ __________33333_________ ++ ______________22________ ++ ___________________2222_ ++ _________111111111______ ++ _____________________11_ ++ _________________4______ ++ ++ Sanitized equivalent (no overlap): ++ 1_______________________ ++ _44_____________________ ++ ___1____________________ ++ ____22__________________ ++ ______11________________ ++ _________1______________ ++ __________3_____________ ++ ___________44___________ ++ _____________33_________ ++ _______________2________ ++ ________________1_______ ++ _________________4______ ++ ___________________2____ ++ ____________________33__ ++ ______________________4_ ++ */ ++ printk("sanitize start\n"); ++ /* if there's only one memory region, don't bother */ ++ if (*pnr_map < 2) { ++ printk("sanitize bail 0\n"); ++ return -1; ++ } ++ ++ old_nr = *pnr_map; ++ ++ /* bail out if we find any unreasonable addresses in bios map */ ++ for (i=0; iaddr = biosmap[i].addr; ++ change_point[chgidx++]->pbios = &biosmap[i]; ++ change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; ++ change_point[chgidx++]->pbios = &biosmap[i]; ++ } ++ } ++ chg_nr = chgidx; /* true number of change-points */ ++ ++ /* sort change-point list by memory addresses (low -> high) */ ++ still_changing = 1; ++ while (still_changing) { ++ still_changing = 0; ++ for (i=1; i < chg_nr; i++) { ++ /* if > , swap */ ++ /* or, if current= & last=, swap */ ++ if ((change_point[i]->addr < change_point[i-1]->addr) || ++ ((change_point[i]->addr == change_point[i-1]->addr) && ++ (change_point[i]->addr == change_point[i]->pbios->addr) && ++ (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) ++ ) ++ { ++ change_tmp = change_point[i]; ++ change_point[i] = change_point[i-1]; ++ change_point[i-1] = change_tmp; ++ still_changing=1; ++ } ++ } ++ } ++ ++ /* create a new bios memory map, removing overlaps */ ++ overlap_entries=0; /* number of entries in the overlap table */ ++ new_bios_entry=0; /* index for creating new bios map entries */ ++ last_type = 0; /* start with undefined memory type */ ++ last_addr = 0; /* start with 0 as last starting address */ ++ /* loop through change-points, determining affect on the new bios map */ ++ for (chgidx=0; chgidx < chg_nr; chgidx++) ++ { ++ /* keep track of all overlapping bios entries */ ++ if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) ++ { ++ /* add map entry to overlap list (> 1 entry implies an overlap) */ ++ overlap_list[overlap_entries++]=change_point[chgidx]->pbios; ++ } ++ else ++ { ++ /* remove entry from list (order independent, so swap with last) */ ++ for (i=0; ipbios) ++ overlap_list[i] = overlap_list[overlap_entries-1]; ++ } ++ overlap_entries--; ++ } ++ /* if there are overlapping entries, decide which "type" to use */ ++ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ ++ current_type = 0; ++ for (i=0; itype > current_type) ++ current_type = overlap_list[i]->type; ++ /* continue building up new bios map based on this information */ ++ if (current_type != last_type) { ++ if (last_type != 0) { ++ new_bios[new_bios_entry].size = ++ change_point[chgidx]->addr - last_addr; ++ /* move forward only if the new size was non-zero */ ++ if (new_bios[new_bios_entry].size != 0) ++ if (++new_bios_entry >= E820MAX) ++ break; /* no more space left for new bios entries */ ++ } ++ if (current_type != 0) { ++ new_bios[new_bios_entry].addr = change_point[chgidx]->addr; ++ new_bios[new_bios_entry].type = current_type; ++ last_addr=change_point[chgidx]->addr; ++ } ++ last_type = current_type; ++ } ++ } ++ new_nr = new_bios_entry; /* retain count for new bios entries */ ++ ++ /* copy new bios mapping into original location */ ++ memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); ++ *pnr_map = new_nr; ++ ++ printk("sanitize end\n"); ++ return 0; ++} ++ ++/* ++ * Copy the BIOS e820 map into a safe place. ++ * ++ * Sanity-check it while we're at it.. ++ * ++ * If we're lucky and live on a modern system, the setup code ++ * will have given us a memory map that we can use to properly ++ * set up memory. If we aren't, we'll fake a memory map. ++ * ++ * We check to see that the memory map contains at least 2 elements ++ * before we'll use it, because the detection code in setup.S may ++ * not be perfect and most every PC known to man has two memory ++ * regions: one from 0 to 640k, and one from 1mb up. (The IBM ++ * thinkpad 560x, for example, does not cooperate with the memory ++ * detection code.) ++ */ ++int __init copy_e820_map(struct e820entry * biosmap, int nr_map) ++{ ++#ifndef CONFIG_XEN ++ /* Only one memory region (or negative)? Ignore it */ ++ if (nr_map < 2) ++ return -1; ++#else ++ BUG_ON(nr_map < 1); ++#endif ++ ++ do { ++ unsigned long long start = biosmap->addr; ++ unsigned long long size = biosmap->size; ++ unsigned long long end = start + size; ++ unsigned long type = biosmap->type; ++ printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type); ++ ++ /* Overflow in 64 bits? Ignore the memory map. */ ++ if (start > end) ++ return -1; ++ ++#ifndef CONFIG_XEN ++ /* ++ * Some BIOSes claim RAM in the 640k - 1M region. ++ * Not right. Fix it up. ++ */ ++ if (type == E820_RAM) { ++ printk("copy_e820_map() type is E820_RAM\n"); ++ if (start < 0x100000ULL && end > 0xA0000ULL) { ++ printk("copy_e820_map() lies in range...\n"); ++ if (start < 0xA0000ULL) { ++ printk("copy_e820_map() start < 0xA0000ULL\n"); ++ add_memory_region(start, 0xA0000ULL-start, type); ++ } ++ if (end <= 0x100000ULL) { ++ printk("copy_e820_map() end <= 0x100000ULL\n"); ++ continue; ++ } ++ start = 0x100000ULL; ++ size = end - start; ++ } ++ } ++#endif ++ add_memory_region(start, size, type); ++ } while (biosmap++,--nr_map); ++ ++#ifdef CONFIG_XEN ++ if (is_initial_xendomain()) { ++ struct xen_memory_map memmap; ++ ++ memmap.nr_entries = E820MAX; ++ set_xen_guest_handle(memmap.buffer, machine_e820.map); ++ ++ if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap)) ++ BUG(); ++ machine_e820.nr_map = memmap.nr_entries; ++ } else ++ machine_e820 = e820; ++#endif ++ ++ return 0; ++} ++ ++/* ++ * Callback for efi_memory_walk. ++ */ ++static int __init ++efi_find_max_pfn(unsigned long start, unsigned long end, void *arg) ++{ ++ unsigned long *max_pfn = arg, pfn; ++ ++ if (start < end) { ++ pfn = PFN_UP(end -1); ++ if (pfn > *max_pfn) ++ *max_pfn = pfn; ++ } ++ return 0; ++} ++ ++static int __init ++efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg) ++{ ++ memory_present(0, PFN_UP(start), PFN_DOWN(end)); ++ return 0; ++} ++ ++/* ++ * Find the highest page frame number we have available ++ */ ++void __init find_max_pfn(void) ++{ ++ int i; ++ ++ max_pfn = 0; ++ if (efi_enabled) { ++ efi_memmap_walk(efi_find_max_pfn, &max_pfn); ++ efi_memmap_walk(efi_memory_present_wrapper, NULL); ++ return; ++ } ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ unsigned long start, end; ++ /* RAM? */ ++ if (e820.map[i].type != E820_RAM) ++ continue; ++ start = PFN_UP(e820.map[i].addr); ++ end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); ++ if (start >= end) ++ continue; ++ if (end > max_pfn) ++ max_pfn = end; ++ memory_present(0, start, end); ++ } ++} ++ ++/* ++ * Free all available memory for boot time allocation. Used ++ * as a callback function by efi_memory_walk() ++ */ ++ ++static int __init ++free_available_memory(unsigned long start, unsigned long end, void *arg) ++{ ++ /* check max_low_pfn */ ++ if (start >= (max_low_pfn << PAGE_SHIFT)) ++ return 0; ++ if (end >= (max_low_pfn << PAGE_SHIFT)) ++ end = max_low_pfn << PAGE_SHIFT; ++ if (start < end) ++ free_bootmem(start, end - start); ++ ++ return 0; ++} ++/* ++ * Register fully available low RAM pages with the bootmem allocator. ++ */ ++void __init register_bootmem_low_pages(unsigned long max_low_pfn) ++{ ++ int i; ++ ++ if (efi_enabled) { ++ efi_memmap_walk(free_available_memory, NULL); ++ return; ++ } ++ for (i = 0; i < e820.nr_map; i++) { ++ unsigned long curr_pfn, last_pfn, size; ++ /* ++ * Reserve usable low memory ++ */ ++ if (e820.map[i].type != E820_RAM) ++ continue; ++ /* ++ * We are rounding up the start address of usable memory: ++ */ ++ curr_pfn = PFN_UP(e820.map[i].addr); ++ if (curr_pfn >= max_low_pfn) ++ continue; ++ /* ++ * ... and at the end of the usable range downwards: ++ */ ++ last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); ++ ++#ifdef CONFIG_XEN ++ /* ++ * Truncate to the number of actual pages currently ++ * present. ++ */ ++ if (last_pfn > xen_start_info->nr_pages) ++ last_pfn = xen_start_info->nr_pages; ++#endif ++ ++ if (last_pfn > max_low_pfn) ++ last_pfn = max_low_pfn; ++ ++ /* ++ * .. finally, did all the rounding and playing ++ * around just make the area go away? ++ */ ++ if (last_pfn <= curr_pfn) ++ continue; ++ ++ size = last_pfn - curr_pfn; ++ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); ++ } ++} ++ ++void __init e820_register_memory(void) ++{ ++ unsigned long gapstart, gapsize, round; ++ unsigned long long last; ++ int i; ++ ++#ifdef CONFIG_XEN ++ if (is_initial_xendomain()) { ++ struct xen_memory_map memmap; ++ ++ memmap.nr_entries = E820MAX; ++ set_xen_guest_handle(memmap.buffer, machine_e820.map); ++ ++ if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap)) ++ BUG(); ++ machine_e820.nr_map = memmap.nr_entries; ++ } ++ else ++ machine_e820 = e820; ++#define e820 machine_e820 ++#endif ++ ++ /* ++ * Search for the bigest gap in the low 32 bits of the e820 ++ * memory space. ++ */ ++ last = 0x100000000ull; ++ gapstart = 0x10000000; ++ gapsize = 0x400000; ++ i = e820.nr_map; ++ while (--i >= 0) { ++ unsigned long long start = e820.map[i].addr; ++ unsigned long long end = start + e820.map[i].size; ++ ++ /* ++ * Since "last" is at most 4GB, we know we'll ++ * fit in 32 bits if this condition is true ++ */ ++ if (last > end) { ++ unsigned long gap = last - end; ++ ++ if (gap > gapsize) { ++ gapsize = gap; ++ gapstart = end; ++ } ++ } ++ if (start < last) ++ last = start; ++ } ++#undef e820 ++ ++ /* ++ * See how much we want to round up: start off with ++ * rounding to the next 1MB area. ++ */ ++ round = 0x100000; ++ while ((gapsize >> 4) > round) ++ round += round; ++ /* Fun with two's complement */ ++ pci_mem_start = (gapstart + round) & -round; ++ ++ printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", ++ pci_mem_start, gapstart, gapsize); ++} ++ ++void __init print_memory_map(char *who) ++{ ++ int i; ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ printk(" %s: %016Lx - %016Lx ", who, ++ e820.map[i].addr, ++ e820.map[i].addr + e820.map[i].size); ++ switch (e820.map[i].type) { ++ case E820_RAM: printk("(usable)\n"); ++ break; ++ case E820_RESERVED: ++ printk("(reserved)\n"); ++ break; ++ case E820_ACPI: ++ printk("(ACPI data)\n"); ++ break; ++ case E820_NVS: ++ printk("(ACPI NVS)\n"); ++ break; ++ default: printk("type %lu\n", e820.map[i].type); ++ break; ++ } ++ } ++} ++ ++static __init __always_inline void efi_limit_regions(unsigned long long size) ++{ ++ unsigned long long current_addr = 0; ++ efi_memory_desc_t *md, *next_md; ++ void *p, *p1; ++ int i, j; ++ ++ j = 0; ++ p1 = memmap.map; ++ for (p = p1, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) { ++ md = p; ++ next_md = p1; ++ current_addr = md->phys_addr + ++ PFN_PHYS(md->num_pages); ++ if (is_available_memory(md)) { ++ if (md->phys_addr >= size) continue; ++ memcpy(next_md, md, memmap.desc_size); ++ if (current_addr >= size) { ++ next_md->num_pages -= ++ PFN_UP(current_addr-size); ++ } ++ p1 += memmap.desc_size; ++ next_md = p1; ++ j++; ++ } else if ((md->attribute & EFI_MEMORY_RUNTIME) == ++ EFI_MEMORY_RUNTIME) { ++ /* In order to make runtime services ++ * available we have to include runtime ++ * memory regions in memory map */ ++ memcpy(next_md, md, memmap.desc_size); ++ p1 += memmap.desc_size; ++ next_md = p1; ++ j++; ++ } ++ } ++ memmap.nr_map = j; ++ memmap.map_end = memmap.map + ++ (memmap.nr_map * memmap.desc_size); ++} ++ ++void __init limit_regions(unsigned long long size) ++{ ++ unsigned long long current_addr = 0; ++ int i; ++ ++ print_memory_map("limit_regions start"); ++ if (efi_enabled) { ++ efi_limit_regions(size); ++ return; ++ } ++ for (i = 0; i < e820.nr_map; i++) { ++ current_addr = e820.map[i].addr + e820.map[i].size; ++ if (current_addr < size) ++ continue; ++ ++ if (e820.map[i].type != E820_RAM) ++ continue; ++ ++ if (e820.map[i].addr >= size) { ++ /* ++ * This region starts past the end of the ++ * requested size, skip it completely. ++ */ ++ e820.nr_map = i; ++ } else { ++ e820.nr_map = i + 1; ++ e820.map[i].size -= current_addr - size; ++ } ++ print_memory_map("limit_regions endfor"); ++ return; ++ } ++#ifdef CONFIG_XEN ++ if (current_addr < size) { ++ /* ++ * The e820 map finished before our requested size so ++ * extend the final entry to the requested address. ++ */ ++ --i; ++ if (e820.map[i].type == E820_RAM) ++ e820.map[i].size -= current_addr - size; ++ else ++ add_memory_region(current_addr, size - current_addr, E820_RAM); ++ } ++#endif ++ print_memory_map("limit_regions endfunc"); ++} ++ ++/* ++ * This function checks if any part of the range is mapped ++ * with type. ++ */ ++int ++e820_any_mapped(u64 start, u64 end, unsigned type) ++{ ++ int i; ++ ++#ifndef CONFIG_XEN ++ for (i = 0; i < e820.nr_map; i++) { ++ const struct e820entry *ei = &e820.map[i]; ++#else ++ if (!is_initial_xendomain()) ++ return 0; ++ for (i = 0; i < machine_e820.nr_map; ++i) { ++ const struct e820entry *ei = &machine_e820.map[i]; ++#endif ++ ++ if (type && ei->type != type) ++ continue; ++ if (ei->addr >= end || ei->addr + ei->size <= start) ++ continue; ++ return 1; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(e820_any_mapped); ++ ++ /* ++ * This function checks if the entire range is mapped with type. ++ * ++ * Note: this function only works correct if the e820 table is sorted and ++ * not-overlapping, which is the case ++ */ ++int __init ++e820_all_mapped(unsigned long s, unsigned long e, unsigned type) ++{ ++ u64 start = s; ++ u64 end = e; ++ int i; ++ ++#ifndef CONFIG_XEN ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++#else ++ if (!is_initial_xendomain()) ++ return 0; ++ for (i = 0; i < machine_e820.nr_map; ++i) { ++ const struct e820entry *ei = &machine_e820.map[i]; ++#endif ++ ++ if (type && ei->type != type) ++ continue; ++ /* is the region (part) in overlap with the current region ?*/ ++ if (ei->addr >= end || ei->addr + ei->size <= start) ++ continue; ++ /* if the region is at the beginning of we move ++ * start to the end of the region since it's ok until there ++ */ ++ if (ei->addr <= start) ++ start = ei->addr + ei->size; ++ /* if start is now at or beyond end, we're done, full ++ * coverage */ ++ if (start >= end) ++ return 1; /* we're done */ ++ } ++ return 0; ++} ++ ++static int __init parse_memmap(char *arg) ++{ ++ if (!arg) ++ return -EINVAL; ++ ++ if (strcmp(arg, "exactmap") == 0) { ++#ifdef CONFIG_CRASH_DUMP ++ /* If we are doing a crash dump, we ++ * still need to know the real mem ++ * size before original memory map is ++ * reset. ++ */ ++ find_max_pfn(); ++ saved_max_pfn = max_pfn; ++#endif ++ e820.nr_map = 0; ++ user_defined_memmap = 1; ++ } else { ++ /* If the user specifies memory size, we ++ * limit the BIOS-provided memory map to ++ * that size. exactmap can be used to specify ++ * the exact map. mem=number can be used to ++ * trim the existing memory map. ++ */ ++ unsigned long long start_at, mem_size; ++ ++ mem_size = memparse(arg, &arg); ++ if (*arg == '@') { ++ start_at = memparse(arg+1, &arg); ++ add_memory_region(start_at, mem_size, E820_RAM); ++ } else if (*arg == '#') { ++ start_at = memparse(arg+1, &arg); ++ add_memory_region(start_at, mem_size, E820_ACPI); ++ } else if (*arg == '$') { ++ start_at = memparse(arg+1, &arg); ++ add_memory_region(start_at, mem_size, E820_RESERVED); ++ } else { ++ limit_regions(mem_size); ++ user_defined_memmap = 1; ++ } ++ } ++ return 0; ++} ++early_param("memmap", parse_memmap); +--- sle11-2009-06-29.orig/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:07:47.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:08:06.000000000 +0200 +@@ -30,12 +30,13 @@ + * 18(%esp) - %eax + * 1C(%esp) - %ds + * 20(%esp) - %es +- * 24(%esp) - orig_eax +- * 28(%esp) - %eip +- * 2C(%esp) - %cs +- * 30(%esp) - %eflags +- * 34(%esp) - %oldesp +- * 38(%esp) - %oldss ++ * 24(%esp) - %gs ++ * 28(%esp) - orig_eax ++ * 2C(%esp) - %eip ++ * 30(%esp) - %cs ++ * 34(%esp) - %eflags ++ * 38(%esp) - %oldesp ++ * 3C(%esp) - %oldss + * + * "current" is in register %ebx during any slow entries. + */ +@@ -48,27 +49,25 @@ + #include + #include + #include ++#include + #include + #include "irq_vectors.h" + #include + +-#define nr_syscalls ((syscall_table_size)/4) ++/* ++ * We use macros for low-level operations which need to be overridden ++ * for paravirtualization. The following will never clobber any registers: ++ * INTERRUPT_RETURN (aka. "iret") ++ * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax") ++ * ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit"). ++ * ++ * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must ++ * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY). ++ * Allowing a register to be clobbered can shrink the paravirt replacement ++ * enough to patch inline, increasing performance. ++ */ + +-EBX = 0x00 +-ECX = 0x04 +-EDX = 0x08 +-ESI = 0x0C +-EDI = 0x10 +-EBP = 0x14 +-EAX = 0x18 +-DS = 0x1C +-ES = 0x20 +-ORIG_EAX = 0x24 +-EIP = 0x28 +-CS = 0x2C +-EFLAGS = 0x30 +-OLDESP = 0x34 +-OLDSS = 0x38 ++#define nr_syscalls ((syscall_table_size)/4) + + CF_MASK = 0x00000001 + TF_MASK = 0x00000100 +@@ -79,61 +78,16 @@ VM_MASK = 0x00020000 + /* Pseudo-eflags. */ + NMI_MASK = 0x80000000 + +-#ifndef CONFIG_XEN +-/* These are replaces for paravirtualization */ +-#define DISABLE_INTERRUPTS cli +-#define ENABLE_INTERRUPTS sti +-#define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit +-#define INTERRUPT_RETURN iret +-#define GET_CR0_INTO_EAX movl %cr0, %eax +-#else +-/* Offsets into shared_info_t. */ +-#define evtchn_upcall_pending /* 0 */ +-#define evtchn_upcall_mask 1 +- +-#define sizeof_vcpu_shift 6 +- +-#ifdef CONFIG_SMP +-#define GET_VCPU_INFO movl TI_cpu(%ebp),%esi ; \ +- shl $sizeof_vcpu_shift,%esi ; \ +- addl HYPERVISOR_shared_info,%esi +-#else +-#define GET_VCPU_INFO movl HYPERVISOR_shared_info,%esi +-#endif +- +-#define __DISABLE_INTERRUPTS movb $1,evtchn_upcall_mask(%esi) +-#define __ENABLE_INTERRUPTS movb $0,evtchn_upcall_mask(%esi) +-#define __TEST_PENDING testb $0xFF,evtchn_upcall_pending(%esi) +-#define DISABLE_INTERRUPTS GET_VCPU_INFO ; \ +- __DISABLE_INTERRUPTS +-#define ENABLE_INTERRUPTS GET_VCPU_INFO ; \ +- __ENABLE_INTERRUPTS +-#define ENABLE_INTERRUPTS_SYSEXIT __ENABLE_INTERRUPTS ; \ +-sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/ ; \ +- __TEST_PENDING ; \ +- jnz 14f # process more events if necessary... ; \ +- movl ESI(%esp), %esi ; \ +- sysexit ; \ +-14: __DISABLE_INTERRUPTS ; \ +- TRACE_IRQS_OFF ; \ +-sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/ ; \ +- push %esp ; \ +- call evtchn_do_upcall ; \ +- add $4,%esp ; \ +- jmp ret_from_intr +-#define INTERRUPT_RETURN iret +-#endif +- + #ifdef CONFIG_PREEMPT +-#define preempt_stop DISABLE_INTERRUPTS; TRACE_IRQS_OFF ++#define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF + #else +-#define preempt_stop ++#define preempt_stop(clobbers) + #define resume_kernel restore_nocheck + #endif + + .macro TRACE_IRQS_IRET + #ifdef CONFIG_TRACE_IRQFLAGS +- testl $IF_MASK,EFLAGS(%esp) # interrupts off? ++ testl $IF_MASK,PT_EFLAGS(%esp) # interrupts off? + jz 1f + TRACE_IRQS_ON + 1: +@@ -148,6 +102,9 @@ sysexit_ecrit: /**** END OF SYSEXIT CRIT + + #define SAVE_ALL \ + cld; \ ++ pushl %gs; \ ++ CFI_ADJUST_CFA_OFFSET 4;\ ++ /*CFI_REL_OFFSET gs, 0;*/\ + pushl %es; \ + CFI_ADJUST_CFA_OFFSET 4;\ + /*CFI_REL_OFFSET es, 0;*/\ +@@ -177,7 +134,9 @@ sysexit_ecrit: /**** END OF SYSEXIT CRIT + CFI_REL_OFFSET ebx, 0;\ + movl $(__USER_DS), %edx; \ + movl %edx, %ds; \ +- movl %edx, %es; ++ movl %edx, %es; \ ++ movl $(__KERNEL_PDA), %edx; \ ++ movl %edx, %gs + + #define RESTORE_INT_REGS \ + popl %ebx; \ +@@ -210,17 +169,22 @@ sysexit_ecrit: /**** END OF SYSEXIT CRIT + 2: popl %es; \ + CFI_ADJUST_CFA_OFFSET -4;\ + /*CFI_RESTORE es;*/\ +-.section .fixup,"ax"; \ +-3: movl $0,(%esp); \ +- jmp 1b; \ ++3: popl %gs; \ ++ CFI_ADJUST_CFA_OFFSET -4;\ ++ /*CFI_RESTORE gs;*/\ ++.pushsection .fixup,"ax"; \ + 4: movl $0,(%esp); \ ++ jmp 1b; \ ++5: movl $0,(%esp); \ + jmp 2b; \ +-.previous; \ ++6: movl $0,(%esp); \ ++ jmp 3b; \ + .section __ex_table,"a";\ + .align 4; \ +- .long 1b,3b; \ +- .long 2b,4b; \ +-.previous ++ .long 1b,4b; \ ++ .long 2b,5b; \ ++ .long 3b,6b; \ ++.popsection + + #define RING0_INT_FRAME \ + CFI_STARTPROC simple;\ +@@ -239,18 +203,18 @@ sysexit_ecrit: /**** END OF SYSEXIT CRIT + #define RING0_PTREGS_FRAME \ + CFI_STARTPROC simple;\ + CFI_SIGNAL_FRAME;\ +- CFI_DEF_CFA esp, OLDESP-EBX;\ +- /*CFI_OFFSET cs, CS-OLDESP;*/\ +- CFI_OFFSET eip, EIP-OLDESP;\ +- /*CFI_OFFSET es, ES-OLDESP;*/\ +- /*CFI_OFFSET ds, DS-OLDESP;*/\ +- CFI_OFFSET eax, EAX-OLDESP;\ +- CFI_OFFSET ebp, EBP-OLDESP;\ +- CFI_OFFSET edi, EDI-OLDESP;\ +- CFI_OFFSET esi, ESI-OLDESP;\ +- CFI_OFFSET edx, EDX-OLDESP;\ +- CFI_OFFSET ecx, ECX-OLDESP;\ +- CFI_OFFSET ebx, EBX-OLDESP ++ CFI_DEF_CFA esp, PT_OLDESP-PT_EBX;\ ++ /*CFI_OFFSET cs, PT_CS-PT_OLDESP;*/\ ++ CFI_OFFSET eip, PT_EIP-PT_OLDESP;\ ++ /*CFI_OFFSET es, PT_ES-PT_OLDESP;*/\ ++ /*CFI_OFFSET ds, PT_DS-PT_OLDESP;*/\ ++ CFI_OFFSET eax, PT_EAX-PT_OLDESP;\ ++ CFI_OFFSET ebp, PT_EBP-PT_OLDESP;\ ++ CFI_OFFSET edi, PT_EDI-PT_OLDESP;\ ++ CFI_OFFSET esi, PT_ESI-PT_OLDESP;\ ++ CFI_OFFSET edx, PT_EDX-PT_OLDESP;\ ++ CFI_OFFSET ecx, PT_ECX-PT_OLDESP;\ ++ CFI_OFFSET ebx, PT_EBX-PT_OLDESP + + ENTRY(ret_from_fork) + CFI_STARTPROC +@@ -278,17 +242,18 @@ ENTRY(ret_from_fork) + ALIGN + RING0_PTREGS_FRAME + ret_from_exception: +- preempt_stop ++ preempt_stop(CLBR_ANY) + ret_from_intr: + GET_THREAD_INFO(%ebp) + check_userspace: +- movl EFLAGS(%esp), %eax # mix EFLAGS and CS +- movb CS(%esp), %al ++ movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS ++ movb PT_CS(%esp), %al + andl $(VM_MASK | SEGMENT_RPL_MASK), %eax + cmpl $USER_RPL, %eax + jb resume_kernel # not returning to v8086 or userspace ++ + ENTRY(resume_userspace) +- DISABLE_INTERRUPTS # make sure we don't miss an interrupt ++ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret + movl TI_flags(%ebp), %ecx +@@ -299,14 +264,14 @@ ENTRY(resume_userspace) + + #ifdef CONFIG_PREEMPT + ENTRY(resume_kernel) +- DISABLE_INTERRUPTS ++ DISABLE_INTERRUPTS(CLBR_ANY) + cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? + jnz restore_nocheck + need_resched: + movl TI_flags(%ebp), %ecx # need_resched set ? + testb $_TIF_NEED_RESCHED, %cl + jz restore_all +- testl $IF_MASK,EFLAGS(%esp) # interrupts off (exception path) ? ++ testl $IF_MASK,PT_EFLAGS(%esp) # interrupts off (exception path) ? + jz restore_all + call preempt_schedule_irq + jmp need_resched +@@ -328,7 +293,7 @@ sysenter_past_esp: + * No need to follow this irqs on/off section: the syscall + * disabled irqs and here we enable it straight after entry: + */ +- ENABLE_INTERRUPTS ++ ENABLE_INTERRUPTS(CLBR_NONE) + pushl $(__USER_DS) + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET ss, 0*/ +@@ -340,12 +305,16 @@ sysenter_past_esp: + pushl $(__USER_CS) + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET cs, 0*/ ++#ifndef CONFIG_COMPAT_VDSO + /* + * Push current_thread_info()->sysenter_return to the stack. + * A tiny bit of offset fixup is necessary - 4*4 means the 4 words + * pushed above; +8 corresponds to copy_thread's esp0 setting. + */ + pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) ++#else ++ pushl $SYSENTER_RETURN ++#endif + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET eip, 0 + +@@ -372,19 +341,27 @@ sysenter_past_esp: + cmpl $(nr_syscalls), %eax + jae syscall_badsys + call *sys_call_table(,%eax,4) +- movl %eax,EAX(%esp) +- DISABLE_INTERRUPTS ++ movl %eax,PT_EAX(%esp) ++ DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX) + TRACE_IRQS_OFF + movl TI_flags(%ebp), %ecx + testw $_TIF_ALLWORK_MASK, %cx + jne syscall_exit_work + /* if something modifies registers it must also disable sysexit */ +- movl EIP(%esp), %edx +- movl OLDESP(%esp), %ecx ++ movl PT_EIP(%esp), %edx ++ movl PT_OLDESP(%esp), %ecx + xorl %ebp,%ebp + TRACE_IRQS_ON ++1: mov PT_GS(%esp), %gs + ENABLE_INTERRUPTS_SYSEXIT + CFI_ENDPROC ++.pushsection .fixup,"ax" ++2: movl $0,PT_GS(%esp) ++ jmp 1b ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,2b ++.popsection + + # pv sysenter call handler stub + ENTRY(sysenter_entry_pv) +@@ -419,7 +396,7 @@ ENTRY(system_call) + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + GET_THREAD_INFO(%ebp) +- testl $TF_MASK,EFLAGS(%esp) ++ testl $TF_MASK,PT_EFLAGS(%esp) + jz no_singlestep + orl $_TIF_SINGLESTEP,TI_flags(%ebp) + no_singlestep: +@@ -431,9 +408,9 @@ no_singlestep: + jae syscall_badsys + syscall_call: + call *sys_call_table(,%eax,4) +- movl %eax,EAX(%esp) # store the return value ++ movl %eax,PT_EAX(%esp) # store the return value + syscall_exit: +- DISABLE_INTERRUPTS # make sure we don't miss an interrupt ++ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret + TRACE_IRQS_OFF +@@ -443,12 +420,12 @@ syscall_exit: + + restore_all: + #ifndef CONFIG_XEN +- movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS +- # Warning: OLDSS(%esp) contains the wrong/random values if we ++ movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS ++ # Warning: PT_OLDSS(%esp) contains the wrong/random values if we + # are returning to the kernel. + # See comments in process.c:copy_thread() for details. +- movb OLDSS(%esp), %ah +- movb CS(%esp), %al ++ movb PT_OLDSS(%esp), %ah ++ movb PT_CS(%esp), %al + andl $(VM_MASK | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax + cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax + CFI_REMEMBER_STATE +@@ -456,7 +433,7 @@ restore_all: + restore_nocheck: + #else + restore_nocheck: +- movl EFLAGS(%esp), %eax ++ movl PT_EFLAGS(%esp), %eax + testl $(VM_MASK|NMI_MASK), %eax + CFI_REMEMBER_STATE + jnz hypervisor_iret +@@ -470,13 +447,13 @@ restore_nocheck: + TRACE_IRQS_IRET + restore_nocheck_notrace: + RESTORE_REGS +- addl $4, %esp ++ addl $4, %esp # skip orig_eax/error_code + CFI_ADJUST_CFA_OFFSET -4 + 1: INTERRUPT_RETURN + .section .fixup,"ax" + iret_exc: + #ifndef CONFIG_XEN +- ENABLE_INTERRUPTS ++ ENABLE_INTERRUPTS(CLBR_NONE) + #endif + pushl $0 # no error code + pushl $do_iret_error +@@ -490,33 +467,42 @@ iret_exc: + CFI_RESTORE_STATE + #ifndef CONFIG_XEN + ldt_ss: +- larl OLDSS(%esp), %eax ++ larl PT_OLDSS(%esp), %eax + jnz restore_nocheck + testl $0x00400000, %eax # returning to 32bit stack? + jnz restore_nocheck # allright, normal return ++ ++#ifdef CONFIG_PARAVIRT ++ /* ++ * The kernel can't run on a non-flat stack if paravirt mode ++ * is active. Rather than try to fixup the high bits of ++ * ESP, bypass this code entirely. This may break DOSemu ++ * and/or Wine support in a paravirt VM, although the option ++ * is still available to implement the setting of the high ++ * 16-bits in the INTERRUPT_RETURN paravirt-op. ++ */ ++ cmpl $0, paravirt_ops+PARAVIRT_enabled ++ jne restore_nocheck ++#endif ++ + /* If returning to userspace with 16bit stack, + * try to fix the higher word of ESP, as the CPU + * won't restore it. + * This is an "official" bug of all the x86-compatible + * CPUs, which we can try to work around to make + * dosemu and wine happy. */ +- subl $8, %esp # reserve space for switch16 pointer +- CFI_ADJUST_CFA_OFFSET 8 +- DISABLE_INTERRUPTS ++ movl PT_OLDESP(%esp), %eax ++ movl %esp, %edx ++ call patch_espfix_desc ++ pushl $__ESPFIX_SS ++ CFI_ADJUST_CFA_OFFSET 4 ++ pushl %eax ++ CFI_ADJUST_CFA_OFFSET 4 ++ DISABLE_INTERRUPTS(CLBR_EAX) + TRACE_IRQS_OFF +- movl %esp, %eax +- /* Set up the 16bit stack frame with switch32 pointer on top, +- * and a switch16 pointer on top of the current frame. */ +- call setup_x86_bogus_stack +- CFI_ADJUST_CFA_OFFSET -8 # frame has moved +- TRACE_IRQS_IRET +- RESTORE_REGS +- lss 20+4(%esp), %esp # switch to 16bit stack +-1: INTERRUPT_RETURN +-.section __ex_table,"a" +- .align 4 +- .long 1b,iret_exc +-.previous ++ lss (%esp), %esp ++ CFI_ADJUST_CFA_OFFSET -8 ++ jmp restore_nocheck + #else + ALIGN + restore_all_enable_events: +@@ -540,7 +526,7 @@ ecrit: /**** END OF CRITICAL REGION *** + + CFI_RESTORE_STATE + hypervisor_iret: +- andl $~NMI_MASK, EFLAGS(%esp) ++ andl $~NMI_MASK, PT_EFLAGS(%esp) + RESTORE_REGS + addl $4, %esp + CFI_ADJUST_CFA_OFFSET -4 +@@ -556,7 +542,7 @@ work_pending: + jz work_notifysig + work_resched: + call schedule +- DISABLE_INTERRUPTS # make sure we don't miss an interrupt ++ DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret + TRACE_IRQS_OFF +@@ -569,7 +555,8 @@ work_resched: + + work_notifysig: # deal with pending signals and + # notify-resume requests +- testl $VM_MASK, EFLAGS(%esp) ++#ifdef CONFIG_VM86 ++ testl $VM_MASK, PT_EFLAGS(%esp) + movl %esp, %eax + jne work_notifysig_v86 # returning to kernel-space or + # vm86-space +@@ -579,29 +566,30 @@ work_notifysig: # deal with pending s + + ALIGN + work_notifysig_v86: +-#ifdef CONFIG_VM86 + pushl %ecx # save ti_flags for do_notify_resume + CFI_ADJUST_CFA_OFFSET 4 + call save_v86_state # %eax contains pt_regs pointer + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + movl %eax, %esp ++#else ++ movl %esp, %eax ++#endif + xorl %edx, %edx + call do_notify_resume + jmp resume_userspace_sig +-#endif + + # perform syscall exit tracing + ALIGN + syscall_trace_entry: +- movl $-ENOSYS,EAX(%esp) ++ movl $-ENOSYS,PT_EAX(%esp) + movl %esp, %eax + xorl %edx,%edx + call do_syscall_trace + cmpl $0, %eax + jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, + # so must skip actual syscall +- movl ORIG_EAX(%esp), %eax ++ movl PT_ORIG_EAX(%esp), %eax + cmpl $(nr_syscalls), %eax + jnae syscall_call + jmp syscall_exit +@@ -612,7 +600,7 @@ syscall_exit_work: + testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl + jz work_pending + TRACE_IRQS_ON +- ENABLE_INTERRUPTS # could let do_syscall_trace() call ++ ENABLE_INTERRUPTS(CLBR_ANY) # could let do_syscall_trace() call + # schedule() instead + movl %esp, %eax + movl $1, %edx +@@ -626,40 +614,39 @@ syscall_fault: + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + GET_THREAD_INFO(%ebp) +- movl $-EFAULT,EAX(%esp) ++ movl $-EFAULT,PT_EAX(%esp) + jmp resume_userspace + + syscall_badsys: +- movl $-ENOSYS,EAX(%esp) ++ movl $-ENOSYS,PT_EAX(%esp) + jmp resume_userspace + CFI_ENDPROC + + #ifndef CONFIG_XEN + #define FIXUP_ESPFIX_STACK \ +- movl %esp, %eax; \ +- /* switch to 32bit stack using the pointer on top of 16bit stack */ \ +- lss %ss:CPU_16BIT_STACK_SIZE-8, %esp; \ +- /* copy data from 16bit stack to 32bit stack */ \ +- call fixup_x86_bogus_stack; \ +- /* put ESP to the proper location */ \ +- movl %eax, %esp; +-#define UNWIND_ESPFIX_STACK \ ++ /* since we are on a wrong stack, we cant make it a C code :( */ \ ++ movl %gs:PDA_cpu, %ebx; \ ++ PER_CPU(cpu_gdt_descr, %ebx); \ ++ movl GDS_address(%ebx), %ebx; \ ++ GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ ++ addl %esp, %eax; \ ++ pushl $__KERNEL_DS; \ ++ CFI_ADJUST_CFA_OFFSET 4; \ + pushl %eax; \ + CFI_ADJUST_CFA_OFFSET 4; \ ++ lss (%esp), %esp; \ ++ CFI_ADJUST_CFA_OFFSET -8; ++#define UNWIND_ESPFIX_STACK \ + movl %ss, %eax; \ +- /* see if on 16bit stack */ \ ++ /* see if on espfix stack */ \ + cmpw $__ESPFIX_SS, %ax; \ +- je 28f; \ +-27: popl %eax; \ +- CFI_ADJUST_CFA_OFFSET -4; \ +-.section .fixup,"ax"; \ +-28: movl $__KERNEL_DS, %eax; \ ++ jne 27f; \ ++ movl $__KERNEL_DS, %eax; \ + movl %eax, %ds; \ + movl %eax, %es; \ +- /* switch to 32bit stack */ \ ++ /* switch to normal stack */ \ + FIXUP_ESPFIX_STACK; \ +- jmp 27b; \ +-.previous ++27:; + + /* + * Build the entry stubs and pointer table with +@@ -723,13 +710,16 @@ KPROBE_ENTRY(page_fault) + CFI_ADJUST_CFA_OFFSET 4 + ALIGN + error_code: ++ /* the function address is in %gs's slot on the stack */ ++ pushl %es ++ CFI_ADJUST_CFA_OFFSET 4 ++ /*CFI_REL_OFFSET es, 0*/ + pushl %ds + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET ds, 0*/ + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET eax, 0 +- xorl %eax, %eax + pushl %ebp + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebp, 0 +@@ -742,7 +732,6 @@ error_code: + pushl %edx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET edx, 0 +- decl %eax # eax = -1 + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx, 0 +@@ -750,18 +739,20 @@ error_code: + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebx, 0 + cld +- pushl %es ++ pushl %gs + CFI_ADJUST_CFA_OFFSET 4 +- /*CFI_REL_OFFSET es, 0*/ ++ /*CFI_REL_OFFSET gs, 0*/ ++ movl $(__KERNEL_PDA), %ecx ++ movl %ecx, %gs + UNWIND_ESPFIX_STACK + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + /*CFI_REGISTER es, ecx*/ +- movl ES(%esp), %edi # get the function address +- movl ORIG_EAX(%esp), %edx # get the error code +- movl %eax, ORIG_EAX(%esp) +- movl %ecx, ES(%esp) +- /*CFI_REL_OFFSET es, ES*/ ++ movl PT_GS(%esp), %edi # get the function address ++ movl PT_ORIG_EAX(%esp), %edx # get the error code ++ movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart ++ mov %ecx, PT_GS(%esp) ++ /*CFI_REL_OFFSET gs, ES*/ + movl $(__USER_DS), %ecx + movl %ecx, %ds + movl %ecx, %es +@@ -793,8 +784,8 @@ ENTRY(hypervisor_callback) + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL +- movl CS(%esp),%ecx +- movl EIP(%esp),%eax ++ movl PT_CS(%esp),%ecx ++ movl PT_EIP(%esp),%eax + andl $SEGMENT_RPL_MASK,%ecx + cmpl $USER_RPL,%ecx + jae .Ldo_upcall +@@ -808,7 +799,7 @@ ENTRY(hypervisor_callback) + jb .Ldo_upcall + cmpl $sysexit_ecrit,%eax + ja .Ldo_upcall +- addl $OLDESP,%esp # Remove eflags...ebx from stack frame. ++ addl $PT_OLDESP,%esp # Remove eflags...ebx from stack frame. + #endif + .Ldo_upcall: + push %esp +@@ -830,7 +821,7 @@ critical_region_fixup: + movsbl critical_fixup_table-scrit(%eax),%ecx # %ecx contains num slots popped + testl %ecx,%ecx + leal (%esp,%ecx,4),%esi # %esi points at end of src region +- leal OLDESP(%esp),%edi # %edi points at end of dst region ++ leal PT_OLDESP(%esp),%edi # %edi points at end of dst region + jle 17f # skip loop if nothing to copy + 16: subl $4,%esi # pre-decrementing copy loop + subl $4,%edi +@@ -853,8 +844,9 @@ critical_fixup_table: + .byte 6 # pop %eax + .byte 7 # pop %ds + .byte 8 # pop %es +- .byte 9,9,9 # add $4,%esp +- .byte 10 # iret ++ .byte 9,9 # pop %gs ++ .byte 10,10,10 # add $4,%esp ++ .byte 11 # iret + .byte -1,-1,-1,-1 # movb $1,1(%esi) = __DISABLE_INTERRUPTS + .previous + +@@ -944,7 +936,7 @@ ENTRY(device_not_available) + jmp ret_from_exception + device_available_emulate: + #endif +- preempt_stop ++ preempt_stop(CLBR_ANY) + call math_state_restore + jmp ret_from_exception + CFI_ENDPROC +@@ -1014,7 +1006,7 @@ KPROBE_ENTRY(nmi) + cmpw $__ESPFIX_SS, %ax + popl %eax + CFI_ADJUST_CFA_OFFSET -4 +- je nmi_16bit_stack ++ je nmi_espfix_stack + cmpl $sysenter_entry,(%esp) + je nmi_stack_fixup + pushl %eax +@@ -1057,7 +1049,7 @@ nmi_debug_stack_check: + FIX_STACK(24,nmi_stack_correct, 1) + jmp nmi_stack_correct + +-nmi_16bit_stack: ++nmi_espfix_stack: + /* We have a RING0_INT_FRAME here. + * + * create the pointer to lss back +@@ -1066,7 +1058,6 @@ nmi_16bit_stack: + CFI_ADJUST_CFA_OFFSET 4 + pushl %esp + CFI_ADJUST_CFA_OFFSET 4 +- movzwl %sp, %esp + addw $4, (%esp) + /* copy the iret frame of 12 bytes */ + .rept 3 +@@ -1077,11 +1068,11 @@ nmi_16bit_stack: + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + FIXUP_ESPFIX_STACK # %eax == %esp +- CFI_ADJUST_CFA_OFFSET -20 # the frame has now moved + xorl %edx,%edx # zero error code + call do_nmi + RESTORE_REGS +- lss 12+4(%esp), %esp # back to 16bit stack ++ lss 12+4(%esp), %esp # back to espfix stack ++ CFI_ADJUST_CFA_OFFSET -24 + 1: INTERRUPT_RETURN + CFI_ENDPROC + .section __ex_table,"a" +@@ -1097,12 +1088,25 @@ KPROBE_ENTRY(nmi) + xorl %edx,%edx # zero error code + movl %esp,%eax # pt_regs pointer + call do_nmi +- orl $NMI_MASK, EFLAGS(%esp) ++ orl $NMI_MASK, PT_EFLAGS(%esp) + jmp restore_all + CFI_ENDPROC + #endif + KPROBE_END(nmi) + ++#ifdef CONFIG_PARAVIRT ++ENTRY(native_iret) ++1: iret ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,iret_exc ++.previous ++ ++ENTRY(native_irq_enable_sysexit) ++ sti ++ sysexit ++#endif ++ + KPROBE_ENTRY(int3) + RING0_INT_FRAME + pushl $-1 # mark this as an int +@@ -1218,37 +1222,6 @@ ENTRY(spurious_interrupt_bug) + CFI_ENDPROC + #endif /* !CONFIG_XEN */ + +-#ifdef CONFIG_STACK_UNWIND +-ENTRY(arch_unwind_init_running) +- CFI_STARTPROC +- movl 4(%esp), %edx +- movl (%esp), %ecx +- leal 4(%esp), %eax +- movl %ebx, EBX(%edx) +- xorl %ebx, %ebx +- movl %ebx, ECX(%edx) +- movl %ebx, EDX(%edx) +- movl %esi, ESI(%edx) +- movl %edi, EDI(%edx) +- movl %ebp, EBP(%edx) +- movl %ebx, EAX(%edx) +- movl $__USER_DS, DS(%edx) +- movl $__USER_DS, ES(%edx) +- movl %ebx, ORIG_EAX(%edx) +- movl %ecx, EIP(%edx) +- movl 12(%esp), %ecx +- movl $__KERNEL_CS, CS(%edx) +- movl %ebx, EFLAGS(%edx) +- movl %eax, OLDESP(%edx) +- movl 8(%esp), %eax +- movl %ecx, 8(%esp) +- movl EBX(%edx), %ebx +- movl $__KERNEL_DS, OLDSS(%edx) +- jmpl *%eax +- CFI_ENDPROC +-ENDPROC(arch_unwind_init_running) +-#endif +- + ENTRY(fixup_4gb_segment) + RING0_EC_FRAME + pushl $do_fixup_4gb_segment +--- sle11-2009-06-29.orig/arch/x86/kernel/head_32-xen.S 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/head_32-xen.S 2008-12-15 11:26:44.000000000 +0100 +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -35,6 +36,8 @@ ENTRY(startup_32) + /* Set up the stack pointer */ + movl $(init_thread_union+THREAD_SIZE),%esp + ++ call setup_pda ++ + /* get vendor info */ + xorl %eax,%eax # call CPUID with 0 -> return vendor ID + XEN_CPUID +@@ -57,14 +60,58 @@ ENTRY(startup_32) + + movb $1,X86_HARD_MATH + +- xorl %eax,%eax # Clear FS/GS and LDT ++ xorl %eax,%eax # Clear FS + movl %eax,%fs +- movl %eax,%gs ++ ++ movl $(__KERNEL_PDA),%eax ++ mov %eax,%gs ++ + cld # gcc2 wants the direction flag cleared at all times + + pushl $0 # fake return address for unwinder + jmp start_kernel + ++/* ++ * Point the GDT at this CPU's PDA. This will be ++ * cpu_gdt_table and boot_pda. ++ */ ++setup_pda: ++ /* get the PDA pointer */ ++ movl $boot_pda, %eax ++ ++ /* slot the PDA address into the GDT */ ++ mov $cpu_gdt_table, %ecx ++ mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */ ++ shr $16, %eax ++ mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */ ++ mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */ ++ ++ # %esi still points to start_info, and no registers ++ # need to be preserved. ++ ++ movl XEN_START_mfn_list(%esi), %ebx ++ movl $(cpu_gdt_table - __PAGE_OFFSET), %eax ++ shrl $PAGE_SHIFT, %eax ++ movl (%ebx,%eax,4), %ecx ++ pushl %ecx # frame number for set_gdt below ++ ++ xorl %esi, %esi ++ xorl %edx, %edx ++ shldl $PAGE_SHIFT, %ecx, %edx ++ shll $PAGE_SHIFT, %ecx ++ orl $0x61, %ecx ++ movl $cpu_gdt_table, %ebx ++ movl $__HYPERVISOR_update_va_mapping, %eax ++ int $0x82 ++ ++ movl $(PAGE_SIZE_asm / 8), %ecx ++ movl %esp, %ebx ++ movl $__HYPERVISOR_set_gdt, %eax ++ int $0x82 ++ ++ popl %ecx ++ ret ++ + #define HYPERCALL_PAGE_OFFSET 0x1000 + .org HYPERCALL_PAGE_OFFSET + ENTRY(hypercall_page) +@@ -93,7 +140,8 @@ ENTRY(empty_zero_page) + /* + * The Global Descriptor Table contains 28 quadwords, per-CPU. + */ +- .align L1_CACHE_BYTES ++ .section .data.page_aligned, "aw" ++ .align PAGE_SIZE_asm + ENTRY(cpu_gdt_table) + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x0000000000000000 /* 0x0b reserved */ +@@ -135,12 +183,13 @@ ENTRY(cpu_gdt_table) + .quad 0x0000000000000000 /* 0xc0 APM CS 16 code (16 bit) */ + .quad 0x0000000000000000 /* 0xc8 APM DS data */ + +- .quad 0x0000000000000000 /* 0xd0 - ESPFIX 16-bit SS */ +- .quad 0x0000000000000000 /* 0xd8 - unused */ ++ .quad 0x0000000000000000 /* 0xd0 - ESPFIX SS */ ++ .quad 0x00cf92000000ffff /* 0xd8 - PDA */ + .quad 0x0000000000000000 /* 0xe0 - unused */ + .quad 0x0000000000000000 /* 0xe8 - unused */ + .quad 0x0000000000000000 /* 0xf0 - unused */ + .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ ++ .align PAGE_SIZE_asm + + #if CONFIG_XEN_COMPAT <= 0x030002 + /* +@@ -165,9 +214,9 @@ ENTRY(cpu_gdt_table) + .ascii ",ELF_PADDR_OFFSET=0x" + utoa __PAGE_OFFSET + .ascii ",VIRT_ENTRY=0x" +- utoa (__PAGE_OFFSET + __PHYSICAL_START + VIRT_ENTRY_OFFSET) ++ utoa (__PAGE_OFFSET + LOAD_PHYSICAL_ADDR + VIRT_ENTRY_OFFSET) + .ascii ",HYPERCALL_PAGE=0x" +- utoa ((__PHYSICAL_START+HYPERCALL_PAGE_OFFSET)>>PAGE_SHIFT) ++ utoa ((LOAD_PHYSICAL_ADDR+HYPERCALL_PAGE_OFFSET)>>PAGE_SHIFT) + .ascii ",FEATURES=writable_page_tables" + .ascii "|writable_descriptor_tables" + .ascii "|auto_translated_physmap" +--- sle11-2009-06-29.orig/arch/x86/kernel/io_apic_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/io_apic_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -199,14 +200,20 @@ static struct IO_APIC_route_entry ioapic + * the interrupt, and we need to make sure the entry is fully populated + * before that happens. + */ +-static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++static void ++__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) + { +- unsigned long flags; + union entry_union eu; + eu.entry = e; +- spin_lock_irqsave(&ioapic_lock, flags); + io_apic_write(apic, 0x11 + 2*pin, eu.w2); + io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++} ++ ++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(apic, pin, e); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + +@@ -889,8 +896,7 @@ static int __init find_isa_irq_pin(int i + + if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || + mp_bus_id_to_type[lbus] == MP_BUS_EISA || +- mp_bus_id_to_type[lbus] == MP_BUS_MCA || +- mp_bus_id_to_type[lbus] == MP_BUS_NEC98 ++ mp_bus_id_to_type[lbus] == MP_BUS_MCA + ) && + (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_srcbusirq == irq)) +@@ -909,8 +915,7 @@ static int __init find_isa_irq_apic(int + + if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || + mp_bus_id_to_type[lbus] == MP_BUS_EISA || +- mp_bus_id_to_type[lbus] == MP_BUS_MCA || +- mp_bus_id_to_type[lbus] == MP_BUS_NEC98 ++ mp_bus_id_to_type[lbus] == MP_BUS_MCA + ) && + (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_srcbusirq == irq)) +@@ -1043,12 +1048,6 @@ static int EISA_ELCR(unsigned int irq) + #define default_MCA_trigger(idx) (1) + #define default_MCA_polarity(idx) (0) + +-/* NEC98 interrupts are always polarity zero edge triggered, +- * when listed as conforming in the MP table. */ +- +-#define default_NEC98_trigger(idx) (0) +-#define default_NEC98_polarity(idx) (0) +- + static int __init MPBIOS_polarity(int idx) + { + int bus = mp_irqs[idx].mpc_srcbus; +@@ -1083,11 +1082,6 @@ static int __init MPBIOS_polarity(int id + polarity = default_MCA_polarity(idx); + break; + } +- case MP_BUS_NEC98: /* NEC 98 pin */ +- { +- polarity = default_NEC98_polarity(idx); +- break; +- } + default: + { + printk(KERN_WARNING "broken BIOS!!\n"); +@@ -1157,11 +1151,6 @@ static int MPBIOS_trigger(int idx) + trigger = default_MCA_trigger(idx); + break; + } +- case MP_BUS_NEC98: /* NEC 98 pin */ +- { +- trigger = default_NEC98_trigger(idx); +- break; +- } + default: + { + printk(KERN_WARNING "broken BIOS!!\n"); +@@ -1223,7 +1212,6 @@ static int pin_2_irq(int idx, int apic, + case MP_BUS_ISA: /* ISA pin */ + case MP_BUS_EISA: + case MP_BUS_MCA: +- case MP_BUS_NEC98: + { + irq = mp_irqs[idx].mpc_srcbusirq; + break; +@@ -1291,7 +1279,7 @@ static inline int IO_APIC_irq_trigger(in + } + + /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ +-u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; /* = { FIRST_DEVICE_VECTOR , 0 }; */ ++static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; /* = { FIRST_DEVICE_VECTOR , 0 }; */ + + static int __assign_irq_vector(int irq) + { +@@ -1417,8 +1405,8 @@ static void __init setup_IO_APIC_irqs(vo + if (!apic && (irq < 16)) + disable_8259A_irq(irq); + } +- ioapic_write_entry(apic, pin, entry); + spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(apic, pin, entry); + set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + } +@@ -1988,6 +1976,15 @@ static void __init setup_ioapic_ids_from + #endif + + #ifndef CONFIG_XEN ++static int no_timer_check __initdata; ++ ++static int __init notimercheck(char *s) ++{ ++ no_timer_check = 1; ++ return 1; ++} ++__setup("no_timer_check", notimercheck); ++ + /* + * There is a nasty bug in some older SMP boards, their mptable lies + * about the timer IRQ. We do the following to work around the situation: +@@ -1996,10 +1993,13 @@ static void __init setup_ioapic_ids_from + * - if this function detects that timer IRQs are defunct, then we fall + * back to ISA timer IRQs + */ +-static int __init timer_irq_works(void) ++int __init timer_irq_works(void) + { + unsigned long t1 = jiffies; + ++ if (no_timer_check) ++ return 1; ++ + local_irq_enable(); + /* Let ten ticks pass... */ + mdelay((10 * 1000) / HZ); +@@ -2226,9 +2226,15 @@ static inline void unlock_ExtINT_logic(v + unsigned char save_control, save_freq_select; + + pin = find_isa_irq_pin(8, mp_INT); ++ if (pin == -1) { ++ WARN_ON_ONCE(1); ++ return; ++ } + apic = find_isa_irq_apic(8, mp_INT); +- if (pin == -1) ++ if (apic == -1) { ++ WARN_ON_ONCE(1); + return; ++ } + + entry0 = ioapic_read_entry(apic, pin); + clear_IO_APIC_pin(apic, pin); +@@ -2273,7 +2279,7 @@ int timer_uses_ioapic_pin_0; + * is so screwy. Thanks to Brian Perkins for testing/hacking this beast + * fanatically on his truly buggy board. + */ +-static inline void check_timer(void) ++static inline void __init check_timer(void) + { + int apic1, pin1, apic2, pin2; + int vector; +@@ -2558,7 +2564,7 @@ device_initcall(ioapic_init_sysfs); + int create_irq(void) + { + /* Allocate an unused irq */ +- int irq, new, vector; ++ int irq, new, vector = 0; + unsigned long flags; + + irq = -ENOSPC; +@@ -2939,8 +2945,8 @@ int io_apic_set_pci_routing (int ioapic, + if (!ioapic && (irq < 16)) + disable_8259A_irq(irq); + +- ioapic_write_entry(ioapic, pin, entry); + spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(ioapic, pin, entry); + set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + +--- sle11-2009-06-29.orig/arch/x86/kernel/ldt_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/ldt_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -177,16 +177,14 @@ static int read_default_ldt(void __user + { + int err; + unsigned long size; +- void *address; + + err = 0; +- address = &default_ldt[0]; + size = 5*sizeof(struct desc_struct); + if (size > bytecount) + size = bytecount; + + err = size; +- if (copy_to_user(ptr, address, size)) ++ if (clear_user(ptr, size)) + err = -EFAULT; + + return err; +--- sle11-2009-06-29.orig/arch/x86/kernel/microcode-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/microcode-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * Intel CPU Microcode Update Driver for Linux + * +- * Copyright (C) 2000-2004 Tigran Aivazian ++ * Copyright (C) 2000-2006 Tigran Aivazian + * 2006 Shaohua Li + * + * This driver allows to upgrade microcode on Intel processors +@@ -43,7 +43,7 @@ + #include + + MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); +-MODULE_AUTHOR("Tigran Aivazian "); ++MODULE_AUTHOR("Tigran Aivazian "); + MODULE_LICENSE("GPL"); + + static int verbose; +@@ -195,7 +195,7 @@ static int __init microcode_init (void) + request_microcode(); + + printk(KERN_INFO +- "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " \n"); ++ "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " \n"); + return 0; + } + +--- sle11-2009-06-29.orig/arch/x86/kernel/mpparse_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/mpparse_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -36,7 +36,7 @@ + + /* Have we found an MP table */ + int smp_found_config; +-unsigned int __initdata maxcpus = NR_CPUS; ++unsigned int __cpuinitdata maxcpus = NR_CPUS; + + /* + * Various Linux-internal data structures created from the +@@ -102,10 +102,10 @@ static int __init mpf_checksum(unsigned + */ + + static int mpc_record; +-static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata; ++static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __cpuinitdata; + + #ifndef CONFIG_XEN +-static void __devinit MP_processor_info (struct mpc_config_processor *m) ++static void __cpuinit MP_processor_info (struct mpc_config_processor *m) + { + int ver, apicid; + physid_mask_t phys_cpu; +@@ -221,7 +221,7 @@ static void __devinit MP_processor_info + bios_cpu_apicid[num_processors - 1] = m->mpc_apicid; + } + #else +-void __init MP_processor_info (struct mpc_config_processor *m) ++static void __cpuinit MP_processor_info (struct mpc_config_processor *m) + { + num_processors++; + } +@@ -256,8 +256,6 @@ static void __init MP_bus_info (struct m + mp_current_pci_id++; + } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; +- } else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) { +- mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98; + } else { + printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str); + } +@@ -842,7 +840,7 @@ void __init mp_register_lapic_address(u6 + #endif + } + +-void __devinit mp_register_lapic (u8 id, u8 enabled) ++void __cpuinit mp_register_lapic (u8 id, u8 enabled) + { + struct mpc_config_processor processor; + int boot_cpu = 0; +--- sle11-2009-06-29.orig/arch/x86/kernel/pci-dma-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/pci-dma-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -276,7 +276,7 @@ EXPORT_SYMBOL(dma_free_coherent); + int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) + { +- void __iomem *mem_base; ++ void __iomem *mem_base = NULL; + int pages = size >> PAGE_SHIFT; + int bitmap_size = (pages + 31)/32; + +@@ -293,14 +293,12 @@ int dma_declare_coherent_memory(struct d + if (!mem_base) + goto out; + +- dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); ++ dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dev->dma_mem) + goto out; +- memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem)); +- dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL); ++ dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dev->dma_mem->bitmap) + goto free1_out; +- memset(dev->dma_mem->bitmap, 0, bitmap_size); + + dev->dma_mem->virt_base = mem_base; + dev->dma_mem->device_base = device_addr; +@@ -315,6 +313,8 @@ int dma_declare_coherent_memory(struct d + free1_out: + kfree(dev->dma_mem->bitmap); + out: ++ if (mem_base) ++ iounmap(mem_base); + return 0; + } + EXPORT_SYMBOL(dma_declare_coherent_memory); +--- sle11-2009-06-29.orig/arch/x86/kernel/process_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/process_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -60,6 +60,7 @@ + + #include + #include ++#include + + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +@@ -104,28 +105,24 @@ EXPORT_SYMBOL(enable_hlt); + */ + static void poll_idle (void) + { +- local_irq_enable(); +- +- asm volatile( +- "2:" +- "testl %0, %1;" +- "rep; nop;" +- "je 2b;" +- : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); ++ cpu_relax(); + } + + static void xen_idle(void) + { +- local_irq_disable(); ++ current_thread_info()->status &= ~TS_POLLING; ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); + +- if (need_resched()) ++ local_irq_disable(); ++ if (!need_resched()) ++ safe_halt(); /* enables interrupts racelessly */ ++ else + local_irq_enable(); +- else { +- current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); +- safe_halt(); +- current_thread_info()->status |= TS_POLLING; +- } ++ current_thread_info()->status |= TS_POLLING; + } + #ifdef CONFIG_APM_MODULE + EXPORT_SYMBOL(default_idle); +@@ -250,8 +247,8 @@ void show_regs(struct pt_regs * regs) + regs->eax,regs->ebx,regs->ecx,regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx", + regs->esi, regs->edi, regs->ebp); +- printk(" DS: %04x ES: %04x\n", +- 0xffff & regs->xds,0xffff & regs->xes); ++ printk(" DS: %04x ES: %04x GS: %04x\n", ++ 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs); + + cr0 = read_cr0(); + cr2 = read_cr2(); +@@ -282,6 +279,7 @@ int kernel_thread(int (*fn)(void *), voi + + regs.xds = __USER_DS; + regs.xes = __USER_DS; ++ regs.xgs = __KERNEL_PDA; + regs.orig_eax = -1; + regs.eip = (unsigned long) kernel_thread_helper; + regs.xcs = __KERNEL_CS | get_kernel_rpl(); +@@ -359,7 +357,6 @@ int copy_thread(int nr, unsigned long cl + p->thread.eip = (unsigned long) ret_from_fork; + + savesegment(fs,p->thread.fs); +- savesegment(gs,p->thread.gs); + + tsk = current; + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { +@@ -438,7 +435,7 @@ void dump_thread(struct pt_regs * regs, + dump->regs.ds = regs->xds; + dump->regs.es = regs->xes; + savesegment(fs,dump->regs.fs); +- savesegment(gs,dump->regs.gs); ++ dump->regs.gs = regs->xgs; + dump->regs.orig_eax = regs->orig_eax; + dump->regs.eip = regs->eip; + dump->regs.cs = regs->xcs; +@@ -635,17 +632,19 @@ struct task_struct fastcall * __switch_t + if (unlikely(HYPERVISOR_multicall_check(_mcl, mcl - _mcl, NULL))) + BUG(); + ++ /* we're going to use this soon, after a few expensive things */ ++ if (next_p->fpu_counter > 5) ++ prefetch(&next->i387.fxsave); ++ + /* +- * Restore %fs and %gs if needed. ++ * Restore %fs if needed. + * +- * Glibc normally makes %fs be zero, and %gs is one of +- * the TLS segments. ++ * Glibc normally makes %fs be zero. + */ + if (unlikely(next->fs)) + loadsegment(fs, next->fs); + +- if (next->gs) +- loadsegment(gs, next->gs); ++ write_pda(pcurrent, next_p); + + /* + * Now maybe handle debug registers +@@ -655,6 +654,13 @@ struct task_struct fastcall * __switch_t + + disable_tsc(prev_p, next_p); + ++ /* If the task has used fpu the last 5 timeslices, just do a full ++ * restore of the math state immediately to avoid the trap; the ++ * chances of needing FPU soon are obviously high now ++ */ ++ if (next_p->fpu_counter > 5) ++ math_state_restore(); ++ + return prev_p; + } + +--- sle11-2009-06-29.orig/arch/x86/kernel/quirks-xen.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/quirks-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -3,10 +3,12 @@ + */ + #include + #include ++#include ++#include ++#include + + #if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_XEN)) && defined(CONFIG_PCI) +- +-static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) ++static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev) + { + u8 config, rev; + u32 word; +@@ -14,14 +16,12 @@ static void __devinit quirk_intel_irqbal + /* BIOS may enable hardware IRQ balancing for + * E7520/E7320/E7525(revision ID 0x9 and below) + * based platforms. +- * Disable SW irqbalance/affinity on those platforms. ++ * For those platforms, make sure that the genapic is set to 'flat' + */ + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev > 0x9) + return; + +- printk(KERN_INFO "Intel E7520/7320/7525 detected."); +- + /* enable access to config space*/ + pci_read_config_byte(dev, 0xf4, &config); + pci_write_config_byte(dev, 0xf4, config|0x2); +@@ -30,6 +30,46 @@ static void __devinit quirk_intel_irqbal + raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); + + if (!(word & (1 << 13))) { ++#ifndef CONFIG_XEN ++#ifdef CONFIG_X86_64 ++ if (genapic != &apic_flat) ++ panic("APIC mode must be flat on this system\n"); ++#elif defined(CONFIG_X86_GENERICARCH) ++ if (genapic != &apic_default) ++ panic("APIC mode must be default(flat) on this system. Use apic=default\n"); ++#endif ++#endif ++ } ++ ++ /* put back the original value for config space*/ ++ if (!(config & 0x2)) ++ pci_write_config_byte(dev, 0xf4, config); ++} ++ ++void __init quirk_intel_irqbalance(void) ++{ ++ u8 config, rev; ++ u32 word; ++ ++ /* BIOS may enable hardware IRQ balancing for ++ * E7520/E7320/E7525(revision ID 0x9 and below) ++ * based platforms. ++ * Disable SW irqbalance/affinity on those platforms. ++ */ ++ rev = read_pci_config_byte(0, 0, 0, PCI_CLASS_REVISION); ++ if (rev > 0x9) ++ return; ++ ++ printk(KERN_INFO "Intel E7520/7320/7525 detected."); ++ ++ /* enable access to config space */ ++ config = read_pci_config_byte(0, 0, 0, 0xf4); ++ write_pci_config_byte(0, 0, 0, 0xf4, config|0x2); ++ ++ /* read xTPR register */ ++ word = read_pci_config_16(0, 0, 0x40, 0x4c); ++ ++ if (!(word & (1 << 13))) { + struct xen_platform_op op; + printk(KERN_INFO "Disabling irq balancing and affinity\n"); + op.cmd = XENPF_platform_quirk; +@@ -37,11 +77,12 @@ static void __devinit quirk_intel_irqbal + WARN_ON(HYPERVISOR_platform_op(&op)); + } + +- /* put back the original value for config space*/ ++ /* put back the original value for config space */ + if (!(config & 0x2)) +- pci_write_config_byte(dev, 0xf4, config); ++ write_pci_config_byte(0, 0, 0, 0xf4, config); + } +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, verify_quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, verify_quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, verify_quirk_intel_irqbalance); ++ + #endif +--- sle11-2009-06-29.orig/arch/x86/kernel/setup_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -76,9 +76,6 @@ + #include + #endif + +-/* Forward Declaration. */ +-void __init find_max_pfn(void); +- + static int xen_panic_event(struct notifier_block *, unsigned long, void *); + static struct notifier_block xen_panic_block = { + xen_panic_event, NULL, 0 /* try to go last */ +@@ -89,14 +86,11 @@ int disable_pse __devinitdata = 0; + /* + * Machine setup.. + */ +- +-#ifdef CONFIG_EFI +-int efi_enabled = 0; +-EXPORT_SYMBOL(efi_enabled); +-#endif ++extern struct resource code_resource; ++extern struct resource data_resource; + + /* cpu data as detected by the assembly code in head.S */ +-struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; ++struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; + /* common cpu data for all cpus */ + struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; + EXPORT_SYMBOL(boot_cpu_data); +@@ -112,12 +106,6 @@ unsigned int machine_submodel_id; + unsigned int BIOS_revision; + unsigned int mca_pentium_flag; + +-/* For PCI or other memory-mapped resources */ +-unsigned long pci_mem_start = 0x10000000; +-#ifdef CONFIG_PCI +-EXPORT_SYMBOL(pci_mem_start); +-#endif +- + /* Boot loader ID as an integer, for the benefit of proc_dointvec */ + int bootloader_type; + +@@ -150,10 +138,6 @@ struct ist_info ist_info; + defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) + EXPORT_SYMBOL(ist_info); + #endif +-struct e820map e820; +-#ifdef CONFIG_XEN +-struct e820map machine_e820; +-#endif + + extern void early_cpu_init(void); + extern int root_mountflags; +@@ -168,209 +152,6 @@ static char command_line[COMMAND_LINE_SI + + unsigned char __initdata boot_params[PARAM_SIZE]; + +-static struct resource data_resource = { +- .name = "Kernel data", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; +- +-static struct resource code_resource = { +- .name = "Kernel code", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; +- +-static struct resource system_rom_resource = { +- .name = "System ROM", +- .start = 0xf0000, +- .end = 0xfffff, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}; +- +-static struct resource extension_rom_resource = { +- .name = "Extension ROM", +- .start = 0xe0000, +- .end = 0xeffff, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}; +- +-static struct resource adapter_rom_resources[] = { { +- .name = "Adapter ROM", +- .start = 0xc8000, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}, { +- .name = "Adapter ROM", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}, { +- .name = "Adapter ROM", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}, { +- .name = "Adapter ROM", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}, { +- .name = "Adapter ROM", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}, { +- .name = "Adapter ROM", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-} }; +- +-static struct resource video_rom_resource = { +- .name = "Video ROM", +- .start = 0xc0000, +- .end = 0xc7fff, +- .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM +-}; +- +-static struct resource video_ram_resource = { +- .name = "Video RAM area", +- .start = 0xa0000, +- .end = 0xbffff, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; +- +-static struct resource standard_io_resources[] = { { +- .name = "dma1", +- .start = 0x0000, +- .end = 0x001f, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "pic1", +- .start = 0x0020, +- .end = 0x0021, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "timer0", +- .start = 0x0040, +- .end = 0x0043, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "timer1", +- .start = 0x0050, +- .end = 0x0053, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "keyboard", +- .start = 0x0060, +- .end = 0x006f, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "dma page reg", +- .start = 0x0080, +- .end = 0x008f, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "pic2", +- .start = 0x00a0, +- .end = 0x00a1, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "dma2", +- .start = 0x00c0, +- .end = 0x00df, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "fpu", +- .start = 0x00f0, +- .end = 0x00ff, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-} }; +- +-#define romsignature(x) (*(unsigned short *)(x) == 0xaa55) +- +-static int __init romchecksum(unsigned char *rom, unsigned long length) +-{ +- unsigned char *p, sum = 0; +- +- for (p = rom; p < rom + length; p++) +- sum += *p; +- return sum == 0; +-} +- +-static void __init probe_roms(void) +-{ +- unsigned long start, length, upper; +- unsigned char *rom; +- int i; +- +-#ifdef CONFIG_XEN +- /* Nothing to do if not running in dom0. */ +- if (!is_initial_xendomain()) +- return; +-#endif +- +- /* video rom */ +- upper = adapter_rom_resources[0].start; +- for (start = video_rom_resource.start; start < upper; start += 2048) { +- rom = isa_bus_to_virt(start); +- if (!romsignature(rom)) +- continue; +- +- video_rom_resource.start = start; +- +- /* 0 < length <= 0x7f * 512, historically */ +- length = rom[2] * 512; +- +- /* if checksum okay, trust length byte */ +- if (length && romchecksum(rom, length)) +- video_rom_resource.end = start + length - 1; +- +- request_resource(&iomem_resource, &video_rom_resource); +- break; +- } +- +- start = (video_rom_resource.end + 1 + 2047) & ~2047UL; +- if (start < upper) +- start = upper; +- +- /* system rom */ +- request_resource(&iomem_resource, &system_rom_resource); +- upper = system_rom_resource.start; +- +- /* check for extension rom (ignore length byte!) */ +- rom = isa_bus_to_virt(extension_rom_resource.start); +- if (romsignature(rom)) { +- length = extension_rom_resource.end - extension_rom_resource.start + 1; +- if (romchecksum(rom, length)) { +- request_resource(&iomem_resource, &extension_rom_resource); +- upper = extension_rom_resource.start; +- } +- } +- +- /* check for adapter roms on 2k boundaries */ +- for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { +- rom = isa_bus_to_virt(start); +- if (!romsignature(rom)) +- continue; +- +- /* 0 < length <= 0x7f * 512, historically */ +- length = rom[2] * 512; +- +- /* but accept any length that fits if checksum okay */ +- if (!length || start + length > upper || !romchecksum(rom, length)) +- continue; +- +- adapter_rom_resources[i].start = start; +- adapter_rom_resources[i].end = start + length - 1; +- request_resource(&iomem_resource, &adapter_rom_resources[i]); +- +- start = adapter_rom_resources[i++].end & ~2047UL; +- } +-} +- + /* + * Point at the empty zero page to start with. We map the real shared_info + * page as soon as fixmap is up and running. +@@ -386,353 +167,6 @@ EXPORT_SYMBOL(phys_to_machine_mapping); + start_info_t *xen_start_info; + EXPORT_SYMBOL(xen_start_info); + +-void __init add_memory_region(unsigned long long start, +- unsigned long long size, int type) +-{ +- int x; +- +- if (!efi_enabled) { +- x = e820.nr_map; +- +- if (x == E820MAX) { +- printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); +- return; +- } +- +- e820.map[x].addr = start; +- e820.map[x].size = size; +- e820.map[x].type = type; +- e820.nr_map++; +- } +-} /* add_memory_region */ +- +-static void __init limit_regions(unsigned long long size) +-{ +- unsigned long long current_addr = 0; +- int i; +- +- if (efi_enabled) { +- efi_memory_desc_t *md; +- void *p; +- +- for (p = memmap.map, i = 0; p < memmap.map_end; +- p += memmap.desc_size, i++) { +- md = p; +- current_addr = md->phys_addr + (md->num_pages << 12); +- if (md->type == EFI_CONVENTIONAL_MEMORY) { +- if (current_addr >= size) { +- md->num_pages -= +- (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT); +- memmap.nr_map = i + 1; +- return; +- } +- } +- } +- } +- for (i = 0; i < e820.nr_map; i++) { +- current_addr = e820.map[i].addr + e820.map[i].size; +- if (current_addr < size) +- continue; +- +- if (e820.map[i].type != E820_RAM) +- continue; +- +- if (e820.map[i].addr >= size) { +- /* +- * This region starts past the end of the +- * requested size, skip it completely. +- */ +- e820.nr_map = i; +- } else { +- e820.nr_map = i + 1; +- e820.map[i].size -= current_addr - size; +- } +- return; +- } +-#ifdef CONFIG_XEN +- if (i==e820.nr_map && current_addr < size) { +- /* +- * The e820 map finished before our requested size so +- * extend the final entry to the requested address. +- */ +- --i; +- if (e820.map[i].type == E820_RAM) +- e820.map[i].size -= current_addr - size; +- else +- add_memory_region(current_addr, size - current_addr, E820_RAM); +- } +-#endif +-} +- +-#define E820_DEBUG 1 +- +-static void __init print_memory_map(char *who) +-{ +- int i; +- +- for (i = 0; i < e820.nr_map; i++) { +- printk(" %s: %016Lx - %016Lx ", who, +- e820.map[i].addr, +- e820.map[i].addr + e820.map[i].size); +- switch (e820.map[i].type) { +- case E820_RAM: printk("(usable)\n"); +- break; +- case E820_RESERVED: +- printk("(reserved)\n"); +- break; +- case E820_ACPI: +- printk("(ACPI data)\n"); +- break; +- case E820_NVS: +- printk("(ACPI NVS)\n"); +- break; +- default: printk("type %lu\n", e820.map[i].type); +- break; +- } +- } +-} +- +-/* +- * Sanitize the BIOS e820 map. +- * +- * Some e820 responses include overlapping entries. The following +- * replaces the original e820 map with a new one, removing overlaps. +- * +- */ +-struct change_member { +- struct e820entry *pbios; /* pointer to original bios entry */ +- unsigned long long addr; /* address for this change point */ +-}; +-static struct change_member change_point_list[2*E820MAX] __initdata; +-static struct change_member *change_point[2*E820MAX] __initdata; +-static struct e820entry *overlap_list[E820MAX] __initdata; +-static struct e820entry new_bios[E820MAX] __initdata; +- +-int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) +-{ +- struct change_member *change_tmp; +- unsigned long current_type, last_type; +- unsigned long long last_addr; +- int chgidx, still_changing; +- int overlap_entries; +- int new_bios_entry; +- int old_nr, new_nr, chg_nr; +- int i; +- +- /* +- Visually we're performing the following (1,2,3,4 = memory types)... +- +- Sample memory map (w/overlaps): +- ____22__________________ +- ______________________4_ +- ____1111________________ +- _44_____________________ +- 11111111________________ +- ____________________33__ +- ___________44___________ +- __________33333_________ +- ______________22________ +- ___________________2222_ +- _________111111111______ +- _____________________11_ +- _________________4______ +- +- Sanitized equivalent (no overlap): +- 1_______________________ +- _44_____________________ +- ___1____________________ +- ____22__________________ +- ______11________________ +- _________1______________ +- __________3_____________ +- ___________44___________ +- _____________33_________ +- _______________2________ +- ________________1_______ +- _________________4______ +- ___________________2____ +- ____________________33__ +- ______________________4_ +- */ +- +- /* if there's only one memory region, don't bother */ +- if (*pnr_map < 2) +- return -1; +- +- old_nr = *pnr_map; +- +- /* bail out if we find any unreasonable addresses in bios map */ +- for (i=0; iaddr = biosmap[i].addr; +- change_point[chgidx++]->pbios = &biosmap[i]; +- change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; +- change_point[chgidx++]->pbios = &biosmap[i]; +- } +- } +- chg_nr = chgidx; /* true number of change-points */ +- +- /* sort change-point list by memory addresses (low -> high) */ +- still_changing = 1; +- while (still_changing) { +- still_changing = 0; +- for (i=1; i < chg_nr; i++) { +- /* if > , swap */ +- /* or, if current= & last=, swap */ +- if ((change_point[i]->addr < change_point[i-1]->addr) || +- ((change_point[i]->addr == change_point[i-1]->addr) && +- (change_point[i]->addr == change_point[i]->pbios->addr) && +- (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) +- ) +- { +- change_tmp = change_point[i]; +- change_point[i] = change_point[i-1]; +- change_point[i-1] = change_tmp; +- still_changing=1; +- } +- } +- } +- +- /* create a new bios memory map, removing overlaps */ +- overlap_entries=0; /* number of entries in the overlap table */ +- new_bios_entry=0; /* index for creating new bios map entries */ +- last_type = 0; /* start with undefined memory type */ +- last_addr = 0; /* start with 0 as last starting address */ +- /* loop through change-points, determining affect on the new bios map */ +- for (chgidx=0; chgidx < chg_nr; chgidx++) +- { +- /* keep track of all overlapping bios entries */ +- if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) +- { +- /* add map entry to overlap list (> 1 entry implies an overlap) */ +- overlap_list[overlap_entries++]=change_point[chgidx]->pbios; +- } +- else +- { +- /* remove entry from list (order independent, so swap with last) */ +- for (i=0; ipbios) +- overlap_list[i] = overlap_list[overlap_entries-1]; +- } +- overlap_entries--; +- } +- /* if there are overlapping entries, decide which "type" to use */ +- /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ +- current_type = 0; +- for (i=0; itype > current_type) +- current_type = overlap_list[i]->type; +- /* continue building up new bios map based on this information */ +- if (current_type != last_type) { +- if (last_type != 0) { +- new_bios[new_bios_entry].size = +- change_point[chgidx]->addr - last_addr; +- /* move forward only if the new size was non-zero */ +- if (new_bios[new_bios_entry].size != 0) +- if (++new_bios_entry >= E820MAX) +- break; /* no more space left for new bios entries */ +- } +- if (current_type != 0) { +- new_bios[new_bios_entry].addr = change_point[chgidx]->addr; +- new_bios[new_bios_entry].type = current_type; +- last_addr=change_point[chgidx]->addr; +- } +- last_type = current_type; +- } +- } +- new_nr = new_bios_entry; /* retain count for new bios entries */ +- +- /* copy new bios mapping into original location */ +- memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); +- *pnr_map = new_nr; +- +- return 0; +-} +- +-/* +- * Copy the BIOS e820 map into a safe place. +- * +- * Sanity-check it while we're at it.. +- * +- * If we're lucky and live on a modern system, the setup code +- * will have given us a memory map that we can use to properly +- * set up memory. If we aren't, we'll fake a memory map. +- * +- * We check to see that the memory map contains at least 2 elements +- * before we'll use it, because the detection code in setup.S may +- * not be perfect and most every PC known to man has two memory +- * regions: one from 0 to 640k, and one from 1mb up. (The IBM +- * thinkpad 560x, for example, does not cooperate with the memory +- * detection code.) +- */ +-int __init copy_e820_map(struct e820entry * biosmap, int nr_map) +-{ +-#ifndef CONFIG_XEN +- /* Only one memory region (or negative)? Ignore it */ +- if (nr_map < 2) +- return -1; +-#else +- BUG_ON(nr_map < 1); +-#endif +- +- do { +- unsigned long long start = biosmap->addr; +- unsigned long long size = biosmap->size; +- unsigned long long end = start + size; +- unsigned long type = biosmap->type; +- +- /* Overflow in 64 bits? Ignore the memory map. */ +- if (start > end) +- return -1; +- +-#ifndef CONFIG_XEN +- /* +- * Some BIOSes claim RAM in the 640k - 1M region. +- * Not right. Fix it up. +- */ +- if (type == E820_RAM) { +- if (start < 0x100000ULL && end > 0xA0000ULL) { +- if (start < 0xA0000ULL) +- add_memory_region(start, 0xA0000ULL-start, type); +- if (end <= 0x100000ULL) +- continue; +- start = 0x100000ULL; +- size = end - start; +- } +- } +-#endif +- add_memory_region(start, size, type); +- } while (biosmap++,--nr_map); +- +-#ifdef CONFIG_XEN +- if (is_initial_xendomain()) { +- struct xen_memory_map memmap; +- +- memmap.nr_entries = E820MAX; +- set_xen_guest_handle(memmap.buffer, machine_e820.map); +- +- if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap)) +- BUG(); +- machine_e820.nr_map = memmap.nr_entries; +- } else +- machine_e820 = e820; +-#endif +- +- return 0; +-} +- + #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) + struct edd edd; + #ifdef CONFIG_EDD_MODULE +@@ -758,7 +192,7 @@ static inline void copy_edd(void) + } + #endif + +-static int __initdata user_defined_memmap = 0; ++int __initdata user_defined_memmap = 0; + + /* + * "mem=nopentium" disables the 4MB page tables. +@@ -795,51 +229,6 @@ static int __init parse_mem(char *arg) + } + early_param("mem", parse_mem); + +-static int __init parse_memmap(char *arg) +-{ +- if (!arg) +- return -EINVAL; +- +- if (strcmp(arg, "exactmap") == 0) { +-#ifdef CONFIG_CRASH_DUMP +- /* If we are doing a crash dump, we +- * still need to know the real mem +- * size before original memory map is +- * reset. +- */ +- find_max_pfn(); +- saved_max_pfn = max_pfn; +-#endif +- e820.nr_map = 0; +- user_defined_memmap = 1; +- } else { +- /* If the user specifies memory size, we +- * limit the BIOS-provided memory map to +- * that size. exactmap can be used to specify +- * the exact map. mem=number can be used to +- * trim the existing memory map. +- */ +- unsigned long long start_at, mem_size; +- +- mem_size = memparse(arg, &arg); +- if (*arg == '@') { +- start_at = memparse(arg+1, &arg); +- add_memory_region(start_at, mem_size, E820_RAM); +- } else if (*arg == '#') { +- start_at = memparse(arg+1, &arg); +- add_memory_region(start_at, mem_size, E820_ACPI); +- } else if (*arg == '$') { +- start_at = memparse(arg+1, &arg); +- add_memory_region(start_at, mem_size, E820_RESERVED); +- } else { +- limit_regions(mem_size); +- user_defined_memmap = 1; +- } +- } +- return 0; +-} +-early_param("memmap", parse_memmap); +- + #ifdef CONFIG_PROC_VMCORE + /* elfcorehdr= specifies the location of elf core header + * stored by the crashed kernel. +@@ -906,127 +295,6 @@ early_param("reservetop", parse_reservet + #endif + + /* +- * Callback for efi_memory_walk. +- */ +-static int __init +-efi_find_max_pfn(unsigned long start, unsigned long end, void *arg) +-{ +- unsigned long *max_pfn = arg, pfn; +- +- if (start < end) { +- pfn = PFN_UP(end -1); +- if (pfn > *max_pfn) +- *max_pfn = pfn; +- } +- return 0; +-} +- +-static int __init +-efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg) +-{ +- memory_present(0, PFN_UP(start), PFN_DOWN(end)); +- return 0; +-} +- +-/* +- * This function checks if any part of the range is mapped +- * with type. +- */ +-int +-e820_any_mapped(u64 start, u64 end, unsigned type) +-{ +- int i; +- +-#ifndef CONFIG_XEN +- for (i = 0; i < e820.nr_map; i++) { +- const struct e820entry *ei = &e820.map[i]; +-#else +- if (!is_initial_xendomain()) +- return 0; +- for (i = 0; i < machine_e820.nr_map; ++i) { +- const struct e820entry *ei = &machine_e820.map[i]; +-#endif +- +- if (type && ei->type != type) +- continue; +- if (ei->addr >= end || ei->addr + ei->size <= start) +- continue; +- return 1; +- } +- return 0; +-} +-EXPORT_SYMBOL_GPL(e820_any_mapped); +- +- /* +- * This function checks if the entire range is mapped with type. +- * +- * Note: this function only works correct if the e820 table is sorted and +- * not-overlapping, which is the case +- */ +-int __init +-e820_all_mapped(unsigned long s, unsigned long e, unsigned type) +-{ +- u64 start = s; +- u64 end = e; +- int i; +- +-#ifndef CONFIG_XEN +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +-#else +- if (!is_initial_xendomain()) +- return 0; +- for (i = 0; i < machine_e820.nr_map; ++i) { +- const struct e820entry *ei = &machine_e820.map[i]; +-#endif +- if (type && ei->type != type) +- continue; +- /* is the region (part) in overlap with the current region ?*/ +- if (ei->addr >= end || ei->addr + ei->size <= start) +- continue; +- /* if the region is at the beginning of we move +- * start to the end of the region since it's ok until there +- */ +- if (ei->addr <= start) +- start = ei->addr + ei->size; +- /* if start is now at or beyond end, we're done, full +- * coverage */ +- if (start >= end) +- return 1; /* we're done */ +- } +- return 0; +-} +- +-/* +- * Find the highest page frame number we have available +- */ +-void __init find_max_pfn(void) +-{ +- int i; +- +- max_pfn = 0; +- if (efi_enabled) { +- efi_memmap_walk(efi_find_max_pfn, &max_pfn); +- efi_memmap_walk(efi_memory_present_wrapper, NULL); +- return; +- } +- +- for (i = 0; i < e820.nr_map; i++) { +- unsigned long start, end; +- /* RAM? */ +- if (e820.map[i].type != E820_RAM) +- continue; +- start = PFN_UP(e820.map[i].addr); +- end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); +- if (start >= end) +- continue; +- if (end > max_pfn) +- max_pfn = end; +- memory_present(0, start, end); +- } +-} +- +-/* + * Determine low and high memory ranges: + */ + unsigned long __init find_max_low_pfn(void) +@@ -1085,77 +353,6 @@ unsigned long __init find_max_low_pfn(vo + return max_low_pfn; + } + +-/* +- * Free all available memory for boot time allocation. Used +- * as a callback function by efi_memory_walk() +- */ +- +-static int __init +-free_available_memory(unsigned long start, unsigned long end, void *arg) +-{ +- /* check max_low_pfn */ +- if (start >= (max_low_pfn << PAGE_SHIFT)) +- return 0; +- if (end >= (max_low_pfn << PAGE_SHIFT)) +- end = max_low_pfn << PAGE_SHIFT; +- if (start < end) +- free_bootmem(start, end - start); +- +- return 0; +-} +-/* +- * Register fully available low RAM pages with the bootmem allocator. +- */ +-static void __init register_bootmem_low_pages(unsigned long max_low_pfn) +-{ +- int i; +- +- if (efi_enabled) { +- efi_memmap_walk(free_available_memory, NULL); +- return; +- } +- for (i = 0; i < e820.nr_map; i++) { +- unsigned long curr_pfn, last_pfn, size; +- /* +- * Reserve usable low memory +- */ +- if (e820.map[i].type != E820_RAM) +- continue; +- /* +- * We are rounding up the start address of usable memory: +- */ +- curr_pfn = PFN_UP(e820.map[i].addr); +- if (curr_pfn >= max_low_pfn) +- continue; +- /* +- * ... and at the end of the usable range downwards: +- */ +- last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); +- +-#ifdef CONFIG_XEN +- /* +- * Truncate to the number of actual pages currently +- * present. +- */ +- if (last_pfn > xen_start_info->nr_pages) +- last_pfn = xen_start_info->nr_pages; +-#endif +- +- if (last_pfn > max_low_pfn) +- last_pfn = max_low_pfn; +- +- /* +- * .. finally, did all the rounding and playing +- * around just make the area go away? +- */ +- if (last_pfn <= curr_pfn) +- continue; +- +- size = last_pfn - curr_pfn; +- free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); +- } +-} +- + #ifndef CONFIG_XEN + /* + * workaround for Dell systems that neglect to reserve EBDA +@@ -1245,8 +442,8 @@ void __init setup_bootmem_allocator(void + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + */ +- reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) + +- bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START)); ++ reserve_bootmem(__pa_symbol(_text), (PFN_PHYS(min_low_pfn) + ++ bootmap_size + PAGE_SIZE-1) - __pa_symbol(_text)); + + #ifndef CONFIG_XEN + /* +@@ -1328,160 +525,6 @@ void __init remapped_pgdat_init(void) + } + } + +-/* +- * Request address space for all standard RAM and ROM resources +- * and also for regions reported as reserved by the e820. +- */ +-static void __init +-legacy_init_iomem_resources(struct e820entry *e820, int nr_map, +- struct resource *code_resource, +- struct resource *data_resource) +-{ +- int i; +- +- probe_roms(); +- +- for (i = 0; i < nr_map; i++) { +- struct resource *res; +-#ifndef CONFIG_RESOURCES_64BIT +- if (e820[i].addr + e820[i].size > 0x100000000ULL) +- continue; +-#endif +- res = kzalloc(sizeof(struct resource), GFP_ATOMIC); +- switch (e820[i].type) { +- case E820_RAM: res->name = "System RAM"; break; +- case E820_ACPI: res->name = "ACPI Tables"; break; +- case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; +- default: res->name = "reserved"; +- } +- res->start = e820[i].addr; +- res->end = res->start + e820[i].size - 1; +- res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; +- if (request_resource(&iomem_resource, res)) { +- kfree(res); +- continue; +- } +- if (e820[i].type == E820_RAM) { +- /* +- * We don't know which RAM region contains kernel data, +- * so we try it repeatedly and let the resource manager +- * test it. +- */ +-#ifndef CONFIG_XEN +- request_resource(res, code_resource); +- request_resource(res, data_resource); +-#endif +-#ifdef CONFIG_KEXEC +- if (crashk_res.start != crashk_res.end) +- request_resource(res, &crashk_res); +-#ifdef CONFIG_XEN +- xen_machine_kexec_register_resources(res); +-#endif +-#endif +- } +- } +-} +- +-/* +- * Locate a unused range of the physical address space below 4G which +- * can be used for PCI mappings. +- */ +-static void __init +-e820_setup_gap(struct e820entry *e820, int nr_map) +-{ +- unsigned long gapstart, gapsize, round; +- unsigned long long last; +- int i; +- +- /* +- * Search for the bigest gap in the low 32 bits of the e820 +- * memory space. +- */ +- last = 0x100000000ull; +- gapstart = 0x10000000; +- gapsize = 0x400000; +- i = nr_map; +- while (--i >= 0) { +- unsigned long long start = e820[i].addr; +- unsigned long long end = start + e820[i].size; +- +- /* +- * Since "last" is at most 4GB, we know we'll +- * fit in 32 bits if this condition is true +- */ +- if (last > end) { +- unsigned long gap = last - end; +- +- if (gap > gapsize) { +- gapsize = gap; +- gapstart = end; +- } +- } +- if (start < last) +- last = start; +- } +- +- /* +- * See how much we want to round up: start off with +- * rounding to the next 1MB area. +- */ +- round = 0x100000; +- while ((gapsize >> 4) > round) +- round += round; +- /* Fun with two's complement */ +- pci_mem_start = (gapstart + round) & -round; +- +- printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", +- pci_mem_start, gapstart, gapsize); +-} +- +-/* +- * Request address space for all standard resources +- * +- * This is called just before pcibios_init(), which is also a +- * subsys_initcall, but is linked in later (in arch/i386/pci/common.c). +- */ +-static int __init request_standard_resources(void) +-{ +- int i; +- +- /* Nothing to do if not running in dom0. */ +- if (!is_initial_xendomain()) +- return 0; +- +- printk("Setting up standard PCI resources\n"); +-#ifdef CONFIG_XEN +- legacy_init_iomem_resources(machine_e820.map, machine_e820.nr_map, +- &code_resource, &data_resource); +-#else +- if (efi_enabled) +- efi_initialize_iomem_resources(&code_resource, &data_resource); +- else +- legacy_init_iomem_resources(e820.map, e820.nr_map, +- &code_resource, &data_resource); +-#endif +- +- /* EFI systems may still have VGA */ +- request_resource(&iomem_resource, &video_ram_resource); +- +- /* request I/O space for devices used on all i[345]86 PCs */ +- for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) +- request_resource(&ioport_resource, &standard_io_resources[i]); +- return 0; +-} +- +-subsys_initcall(request_standard_resources); +- +-static void __init register_memory(void) +-{ +-#ifdef CONFIG_XEN +- if (is_initial_xendomain()) +- e820_setup_gap(machine_e820.map, machine_e820.nr_map); +- else +-#endif +- e820_setup_gap(e820.map, e820.nr_map); +-} +- + #ifdef CONFIG_MCA + static void set_mca_bus(int x) + { +@@ -1491,6 +534,12 @@ static void set_mca_bus(int x) + static void set_mca_bus(int x) { } + #endif + ++/* Overridden in paravirt.c if CONFIG_PARAVIRT */ ++char * __init __attribute__((weak)) memory_setup(void) ++{ ++ return machine_specific_memory_setup(); ++} ++ + /* + * Determine if we were loaded by an EFI loader. If so, then we have also been + * passed the efi memmap, systab, etc., so we should use these data structures +@@ -1578,7 +627,7 @@ void __init setup_arch(char **cmdline_p) + efi_init(); + else { + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); +- print_memory_map(machine_specific_memory_setup()); ++ print_memory_map(memory_setup()); + } + + copy_edd(); +@@ -1757,7 +806,7 @@ void __init setup_arch(char **cmdline_p) + get_smp_config(); + #endif + +- register_memory(); ++ e820_register_memory(); + + if (is_initial_xendomain()) { + #ifdef CONFIG_VT +--- sle11-2009-06-29.orig/arch/x86/kernel/smp_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/smp_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -659,6 +659,10 @@ int smp_call_function_single(int cpu, vo + put_cpu(); + return -EBUSY; + } ++ ++ /* Can deadlock when called with interrupts disabled */ ++ WARN_ON(irqs_disabled()); ++ + spin_lock_bh(&call_lock); + __smp_call_function_single(cpu, func, info, nonatomic, wait); + spin_unlock_bh(&call_lock); +--- sle11-2009-06-29.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:08:00.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/time_32-xen.c 2009-03-24 10:08:30.000000000 +0100 +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + #include + + #include "mach_time.h" +@@ -129,11 +130,11 @@ static DEFINE_PER_CPU(struct vcpu_runsta + /* Must be signed, as it's compared with s64 quantities which can be -ve. */ + #define NS_PER_TICK (1000000000LL/HZ) + +-static void __clock_was_set(void *unused) ++static void __clock_was_set(struct work_struct *unused) + { + clock_was_set(); + } +-static DECLARE_WORK(clock_was_set_work, __clock_was_set, NULL); ++static DECLARE_WORK(clock_was_set_work, __clock_was_set); + + /* + * GCC 4.3 can turn loops over an induction variable into division. We do +@@ -543,10 +544,7 @@ static int set_rtc_mmss(unsigned long no + /* gets recalled with irq locally disabled */ + /* XXX - does irqsave resolve this? -johnstul */ + spin_lock_irqsave(&rtc_lock, flags); +- if (efi_enabled) +- retval = efi_set_rtc_mmss(nowtime); +- else +- retval = mach_set_rtc_mmss(nowtime); ++ retval = set_wallclock(nowtime); + spin_unlock_irqrestore(&rtc_lock, flags); + + return retval; +@@ -873,10 +871,7 @@ unsigned long get_cmos_time(void) + + spin_lock_irqsave(&rtc_lock, flags); + +- if (efi_enabled) +- retval = efi_get_time(); +- else +- retval = mach_get_cmos_time(); ++ retval = get_wallclock(); + + spin_unlock_irqrestore(&rtc_lock, flags); + +@@ -978,7 +973,7 @@ static void __init hpet_time_init(void) + printk("Using HPET for base-timer\n"); + } + +- time_init_hook(); ++ do_time_init(); + } + #endif + +--- sle11-2009-06-29.orig/arch/x86/kernel/traps_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/traps_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -29,6 +29,8 @@ + #include + #include + #include ++#include ++#include + + #ifdef CONFIG_EISA + #include +@@ -61,9 +63,6 @@ int panic_on_unrecovered_nmi; + + asmlinkage int system_call(void); + +-struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, +- { 0, 0 }, { 0, 0 } }; +- + /* Do we ignore FPU interrupts ? */ + char ignore_fpu_irq = 0; + +@@ -100,12 +99,7 @@ asmlinkage void fixup_4gb_segment(void); + #endif + asmlinkage void machine_check(void); + +-static int kstack_depth_to_print = 24; +-#ifdef CONFIG_STACK_UNWIND +-static int call_trace = 1; +-#else +-#define call_trace (-1) +-#endif ++int kstack_depth_to_print = 24; + ATOMIC_NOTIFIER_HEAD(i386die_chain); + + int register_die_notifier(struct notifier_block *nb) +@@ -159,25 +153,7 @@ static inline unsigned long print_contex + return ebp; + } + +-struct ops_and_data { +- struct stacktrace_ops *ops; +- void *data; +-}; +- +-static asmlinkage int +-dump_trace_unwind(struct unwind_frame_info *info, void *data) +-{ +- struct ops_and_data *oad = (struct ops_and_data *)data; +- int n = 0; +- +- while (unwind(info) == 0 && UNW_PC(info)) { +- n++; +- oad->ops->address(oad->data, UNW_PC(info)); +- if (arch_unw_user_mode(info)) +- break; +- } +- return n; +-} ++#define MSG(msg) ops->warning(data, msg) + + void dump_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, +@@ -188,39 +164,6 @@ void dump_trace(struct task_struct *task + if (!task) + task = current; + +- if (call_trace >= 0) { +- int unw_ret = 0; +- struct unwind_frame_info info; +- struct ops_and_data oad = { .ops = ops, .data = data }; +- +- if (regs) { +- if (unwind_init_frame_info(&info, task, regs) == 0) +- unw_ret = dump_trace_unwind(&info, &oad); +- } else if (task == current) +- unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); +- else { +- if (unwind_init_blocked(&info, task) == 0) +- unw_ret = dump_trace_unwind(&info, &oad); +- } +- if (unw_ret > 0) { +- if (call_trace == 1 && !arch_unw_user_mode(&info)) { +- ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", +- UNW_PC(&info)); +- if (UNW_SP(&info) >= PAGE_OFFSET) { +- ops->warning(data, "Leftover inexact backtrace:\n"); +- stack = (void *)UNW_SP(&info); +- if (!stack) +- return; +- ebp = UNW_FP(&info); +- } else +- ops->warning(data, "Full inexact backtrace again:\n"); +- } else if (call_trace >= 1) +- return; +- else +- ops->warning(data, "Full inexact backtrace again:\n"); +- } else +- ops->warning(data, "Inexact backtrace:\n"); +- } + if (!stack) { + unsigned long dummy; + stack = &dummy; +@@ -253,6 +196,7 @@ void dump_trace(struct task_struct *task + stack = (unsigned long*)context->previous_esp; + if (!stack) + break; ++ touch_nmi_watchdog(); + } + } + EXPORT_SYMBOL(dump_trace); +@@ -385,7 +329,7 @@ void show_registers(struct pt_regs *regs + * time of the fault.. + */ + if (in_kernel) { +- u8 __user *eip; ++ u8 *eip; + int code_bytes = 64; + unsigned char c; + +@@ -394,18 +338,20 @@ void show_registers(struct pt_regs *regs + + printk(KERN_EMERG "Code: "); + +- eip = (u8 __user *)regs->eip - 43; +- if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { ++ eip = (u8 *)regs->eip - 43; ++ if (eip < (u8 *)PAGE_OFFSET || ++ probe_kernel_address(eip, c)) { + /* try starting at EIP */ +- eip = (u8 __user *)regs->eip; ++ eip = (u8 *)regs->eip; + code_bytes = 32; + } + for (i = 0; i < code_bytes; i++, eip++) { +- if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { ++ if (eip < (u8 *)PAGE_OFFSET || ++ probe_kernel_address(eip, c)) { + printk(" Bad EIP value."); + break; + } +- if (eip == (u8 __user *)regs->eip) ++ if (eip == (u8 *)regs->eip) + printk("<%02x> ", c); + else + printk("%02x ", c); +@@ -414,43 +360,22 @@ void show_registers(struct pt_regs *regs + printk("\n"); + } + +-static void handle_BUG(struct pt_regs *regs) ++int is_valid_bugaddr(unsigned long eip) + { +- unsigned long eip = regs->eip; + unsigned short ud2; + + if (eip < PAGE_OFFSET) +- return; +- if (probe_kernel_address((unsigned short __user *)eip, ud2)) +- return; +- if (ud2 != 0x0b0f) +- return; ++ return 0; ++ if (probe_kernel_address((unsigned short *)eip, ud2)) ++ return 0; + +- printk(KERN_EMERG "------------[ cut here ]------------\n"); +- +-#ifdef CONFIG_DEBUG_BUGVERBOSE +- do { +- unsigned short line; +- char *file; +- char c; +- +- if (probe_kernel_address((unsigned short __user *)(eip + 2), +- line)) +- break; +- if (__get_user(file, (char * __user *)(eip + 4)) || +- (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) +- file = ""; +- +- printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); +- return; +- } while (0); +-#endif +- printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n"); ++ return ud2 == 0x0b0f; + } + +-/* This is gone through when something in the kernel +- * has done something bad and is about to be terminated. +-*/ ++/* ++ * This is gone through when something in the kernel has done something bad and ++ * is about to be terminated. ++ */ + void die(const char * str, struct pt_regs * regs, long err) + { + static struct { +@@ -458,7 +383,7 @@ void die(const char * str, struct pt_reg + u32 lock_owner; + int lock_owner_depth; + } die = { +- .lock = SPIN_LOCK_UNLOCKED, ++ .lock = __SPIN_LOCK_UNLOCKED(die.lock), + .lock_owner = -1, + .lock_owner_depth = 0 + }; +@@ -482,7 +407,8 @@ void die(const char * str, struct pt_reg + unsigned long esp; + unsigned short ss; + +- handle_BUG(regs); ++ report_bug(regs->eip); ++ + printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); + #ifdef CONFIG_PREEMPT + printk(KERN_EMERG "PREEMPT "); +@@ -682,8 +608,7 @@ mem_parity_error(unsigned char reason, s + { + printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " + "CPU %d.\n", reason, smp_processor_id()); +- printk(KERN_EMERG "You probably have a hardware problem with your RAM " +- "chips\n"); ++ printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); + if (panic_on_unrecovered_nmi) + panic("NMI: Not continuing"); + +@@ -741,7 +666,6 @@ void __kprobes die_nmi(struct pt_regs *r + printk(" on CPU%d, eip %08lx, registers:\n", + smp_processor_id(), regs->eip); + show_registers(regs); +- printk(KERN_EMERG "console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); +@@ -1057,49 +981,24 @@ fastcall void do_spurious_interrupt_bug( + #endif + } + +-fastcall void setup_x86_bogus_stack(unsigned char * stk) ++fastcall unsigned long patch_espfix_desc(unsigned long uesp, ++ unsigned long kesp) + { +- unsigned long *switch16_ptr, *switch32_ptr; +- struct pt_regs *regs; +- unsigned long stack_top, stack_bot; +- unsigned short iret_frame16_off; +- int cpu = smp_processor_id(); +- /* reserve the space on 32bit stack for the magic switch16 pointer */ +- memmove(stk, stk + 8, sizeof(struct pt_regs)); +- switch16_ptr = (unsigned long *)(stk + sizeof(struct pt_regs)); +- regs = (struct pt_regs *)stk; +- /* now the switch32 on 16bit stack */ +- stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu); +- stack_top = stack_bot + CPU_16BIT_STACK_SIZE; +- switch32_ptr = (unsigned long *)(stack_top - 8); +- iret_frame16_off = CPU_16BIT_STACK_SIZE - 8 - 20; +- /* copy iret frame on 16bit stack */ +- memcpy((void *)(stack_bot + iret_frame16_off), ®s->eip, 20); +- /* fill in the switch pointers */ +- switch16_ptr[0] = (regs->esp & 0xffff0000) | iret_frame16_off; +- switch16_ptr[1] = __ESPFIX_SS; +- switch32_ptr[0] = (unsigned long)stk + sizeof(struct pt_regs) + +- 8 - CPU_16BIT_STACK_SIZE; +- switch32_ptr[1] = __KERNEL_DS; +-} +- +-fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp) +-{ +- unsigned long *switch32_ptr; +- unsigned char *stack16, *stack32; +- unsigned long stack_top, stack_bot; +- int len; + int cpu = smp_processor_id(); +- stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu); +- stack_top = stack_bot + CPU_16BIT_STACK_SIZE; +- switch32_ptr = (unsigned long *)(stack_top - 8); +- /* copy the data from 16bit stack to 32bit stack */ +- len = CPU_16BIT_STACK_SIZE - 8 - sp; +- stack16 = (unsigned char *)(stack_bot + sp); +- stack32 = (unsigned char *) +- (switch32_ptr[0] + CPU_16BIT_STACK_SIZE - 8 - len); +- memcpy(stack32, stack16, len); +- return stack32; ++ struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address; ++ unsigned long base = (kesp - uesp) & -THREAD_SIZE; ++ unsigned long new_kesp = kesp - base; ++ unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; ++ __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; ++ /* Set up base for espfix segment */ ++ desc &= 0x00f0ff0000000000ULL; ++ desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | ++ ((((__u64)base) << 32) & 0xff00000000000000ULL) | ++ ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | ++ (lim_pages & 0xffff); ++ *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; ++ return new_kesp; + } + #endif + +@@ -1113,7 +1012,7 @@ fastcall unsigned char * fixup_x86_bogus + * Must be called with kernel preemption disabled (in this case, + * local interrupts are disabled at the call-site in entry.S). + */ +-asmlinkage void math_state_restore(struct pt_regs regs) ++asmlinkage void math_state_restore(void) + { + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = thread->task; +@@ -1123,6 +1022,7 @@ asmlinkage void math_state_restore(struc + init_fpu(tsk); + restore_fpu(tsk); + thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ ++ tsk->fpu_counter++; + } + + #ifndef CONFIG_MATH_EMULATION +@@ -1234,19 +1134,3 @@ static int __init kstack_setup(char *s) + return 1; + } + __setup("kstack=", kstack_setup); +- +-#ifdef CONFIG_STACK_UNWIND +-static int __init call_trace_setup(char *s) +-{ +- if (strcmp(s, "old") == 0) +- call_trace = -1; +- else if (strcmp(s, "both") == 0) +- call_trace = 0; +- else if (strcmp(s, "newfallback") == 0) +- call_trace = 1; +- else if (strcmp(s, "new") == 2) +- call_trace = 2; +- return 1; +-} +-__setup("call_trace=", call_trace_setup); +-#endif +--- sle11-2009-06-29.orig/arch/x86/kernel/vmlinux_32.lds.S 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/vmlinux_32.lds.S 2008-12-15 11:26:44.000000000 +0100 +@@ -29,6 +29,12 @@ PHDRS { + SECTIONS + { + . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; ++ ++#if defined(CONFIG_XEN) && CONFIG_XEN_COMPAT <= 0x030002 ++#undef LOAD_OFFSET ++#define LOAD_OFFSET 0 ++#endif ++ + phys_startup_32 = startup_32 - LOAD_OFFSET; + + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { +--- sle11-2009-06-29.orig/arch/x86/kvm/Kconfig 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kvm/Kconfig 2008-12-15 11:26:44.000000000 +0100 +@@ -7,6 +7,7 @@ config HAVE_KVM + menuconfig VIRTUALIZATION + bool "Virtualization" + depends on HAVE_KVM || X86 ++ depends on !XEN + default y + ---help--- + Say Y here to get to see options for using your Linux host to run other +--- sle11-2009-06-29.orig/arch/x86/mm/fault_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/fault_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -22,9 +22,9 @@ + #include + #include + #include ++#include + + #include +-#include + #include + #include + #include +@@ -167,7 +167,7 @@ static inline unsigned long get_segment_ + static int __is_prefetch(struct pt_regs *regs, unsigned long addr) + { + unsigned long limit; +- unsigned long instr = get_segment_eip (regs, &limit); ++ unsigned char *instr = (unsigned char *)get_segment_eip (regs, &limit); + int scan_more = 1; + int prefetch = 0; + int i; +@@ -177,9 +177,9 @@ static int __is_prefetch(struct pt_regs + unsigned char instr_hi; + unsigned char instr_lo; + +- if (instr > limit) ++ if (instr > (unsigned char *)limit) + break; +- if (__get_user(opcode, (unsigned char __user *) instr)) ++ if (probe_kernel_address(instr, opcode)) + break; + + instr_hi = opcode & 0xf0; +@@ -204,9 +204,9 @@ static int __is_prefetch(struct pt_regs + case 0x00: + /* Prefetch instruction is 0x0F0D or 0x0F18 */ + scan_more = 0; +- if (instr > limit) ++ if (instr > (unsigned char *)limit) + break; +- if (__get_user(opcode, (unsigned char __user *) instr)) ++ if (probe_kernel_address(instr, opcode)) + break; + prefetch = (instr_lo == 0xF) && + (opcode == 0x0D || opcode == 0x18); +--- sle11-2009-06-29.orig/arch/x86/mm/highmem_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/highmem_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -32,7 +32,7 @@ static void *__kmap_atomic(struct page * + unsigned long vaddr; + + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ +- inc_preempt_count(); ++ pagefault_disable(); + if (!PageHighMem(page)) + return page_address(page); + +@@ -63,26 +63,22 @@ void kunmap_atomic(void *kvaddr, enum km + unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; + enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); + +-#ifdef CONFIG_DEBUG_HIGHMEM +- if (vaddr >= PAGE_OFFSET && vaddr < (unsigned long)high_memory) { +- dec_preempt_count(); +- preempt_check_resched(); +- return; +- } +- +- if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx)) +- BUG(); +-#endif + /* + * Force other mappings to Oops if they'll try to access this pte + * without first remap it. Keeping stale mappings around is a bad idea + * also, in case the page changes cacheability attributes or becomes + * a protected page in a hypervisor. + */ +- kpte_clear_flush(kmap_pte-idx, vaddr); ++ if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) ++ kpte_clear_flush(kmap_pte-idx, vaddr); ++ else { ++#ifdef CONFIG_DEBUG_HIGHMEM ++ BUG_ON(vaddr < PAGE_OFFSET); ++ BUG_ON(vaddr >= (unsigned long)high_memory); ++#endif ++ } + +- dec_preempt_count(); +- preempt_check_resched(); ++ pagefault_enable(); + } + + /* This is the same as kmap_atomic() but can map memory that doesn't +@@ -93,7 +89,7 @@ void *kmap_atomic_pfn(unsigned long pfn, + enum fixed_addresses idx; + unsigned long vaddr; + +- inc_preempt_count(); ++ pagefault_disable(); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +--- sle11-2009-06-29.orig/arch/x86/mm/init_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/init_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -233,8 +233,6 @@ static inline int page_kills_ppro(unsign + + #endif + +-extern int is_available_memory(efi_memory_desc_t *); +- + int page_is_ram(unsigned long pagenr) + { + int i; +@@ -327,7 +325,7 @@ void __init add_one_highpage_init(struct + SetPageReserved(page); + } + +-static int add_one_highpage_hotplug(struct page *page, unsigned long pfn) ++static int __meminit add_one_highpage_hotplug(struct page *page, unsigned long pfn) + { + free_new_highpage(page, pfn); + totalram_pages++; +@@ -344,7 +342,7 @@ static int add_one_highpage_hotplug(stru + * has been added dynamically that would be + * onlined here is in HIGHMEM + */ +-void online_page(struct page *page) ++void __meminit online_page(struct page *page) + { + ClearPageReserved(page); + add_one_highpage_hotplug(page, page_to_pfn(page)); +@@ -732,16 +730,10 @@ void __init mem_init(void) + set_bit(PG_pinned, &virt_to_page(init_mm.pgd)->flags); + } + +-/* +- * this is for the non-NUMA, single node SMP system case. +- * Specifically, in the case of x86, we will always add +- * memory to the highmem for now. +- */ + #ifdef CONFIG_MEMORY_HOTPLUG +-#ifndef CONFIG_NEED_MULTIPLE_NODES + int arch_add_memory(int nid, u64 start, u64 size) + { +- struct pglist_data *pgdata = &contig_page_data; ++ struct pglist_data *pgdata = NODE_DATA(nid); + struct zone *zone = pgdata->node_zones + ZONE_HIGHMEM; + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long nr_pages = size >> PAGE_SHIFT; +@@ -753,11 +745,11 @@ int remove_memory(u64 start, u64 size) + { + return -EINVAL; + } +-#endif ++EXPORT_SYMBOL_GPL(remove_memory); + #endif + +-kmem_cache_t *pgd_cache; +-kmem_cache_t *pmd_cache; ++struct kmem_cache *pgd_cache; ++struct kmem_cache *pmd_cache; + + void __init pgtable_cache_init(void) + { +--- sle11-2009-06-29.orig/arch/x86/mm/pgtable_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/pgtable_32-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -203,7 +203,7 @@ void pte_free(struct page *pte) + __free_page(pte); + } + +-void pmd_ctor(void *pmd, kmem_cache_t *cache, unsigned long flags) ++void pmd_ctor(void *pmd, struct kmem_cache *cache, unsigned long flags) + { + memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); + } +@@ -243,7 +243,7 @@ static inline void pgd_list_del(pgd_t *p + set_page_private(next, (unsigned long)pprev); + } + +-void pgd_ctor(void *pgd, kmem_cache_t *cache, unsigned long unused) ++void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) + { + unsigned long flags; + +@@ -264,7 +264,7 @@ void pgd_ctor(void *pgd, kmem_cache_t *c + } + + /* never called when PTRS_PER_PMD > 1 */ +-void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) ++void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused) + { + unsigned long flags; /* can be called from interrupt context */ + +--- sle11-2009-06-29.orig/arch/x86/pci/irq-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/pci/irq-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -768,7 +768,7 @@ static void __init pirq_find_router(stru + DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for %04x:%04x\n", + rt->rtr_vendor, rt->rtr_device); + +- pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn); ++ pirq_router_dev = pci_get_bus_and_slot(rt->rtr_bus, rt->rtr_devfn); + if (!pirq_router_dev) { + DBG(KERN_DEBUG "PCI: Interrupt router not found at " + "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn); +@@ -788,6 +788,8 @@ static void __init pirq_find_router(stru + pirq_router_dev->vendor, + pirq_router_dev->device, + pci_name(pirq_router_dev)); ++ ++ /* The device remains referenced for the kernel lifetime */ + } + + static struct irq_info *pirq_get_info(struct pci_dev *dev) +--- sle11-2009-06-29.orig/arch/x86/kernel/entry_64-xen.S 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/entry_64-xen.S 2008-12-15 11:26:44.000000000 +0100 +@@ -261,7 +261,6 @@ ENTRY(system_call) + movq %rax,ORIG_RAX-ARGOFFSET(%rsp) + GET_THREAD_INFO(%rcx) + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx) +- CFI_REMEMBER_STATE + jnz tracesys + cmpq $__NR_syscall_max,%rax + ja badsys +@@ -272,7 +271,6 @@ ENTRY(system_call) + * Syscall return path ending with SYSRET (fast path) + * Has incomplete stack frame and undefined top of stack. + */ +- .globl ret_from_sys_call + ret_from_sys_call: + movl $_TIF_ALLWORK_MASK,%edi + /* edi: flagmask */ +@@ -282,8 +280,8 @@ sysret_check: + TRACE_IRQS_OFF + movl threadinfo_flags(%rcx),%edx + andl %edi,%edx +- CFI_REMEMBER_STATE + jnz sysret_careful ++ CFI_REMEMBER_STATE + /* + * sysretq will re-enable interrupts: + */ +@@ -292,10 +290,10 @@ sysret_check: + RESTORE_ARGS 0,8,0 + HYPERVISOR_IRET VGCF_IN_SYSCALL + ++ CFI_RESTORE_STATE + /* Handle reschedules */ + /* edx: work, edi: workmask */ + sysret_careful: +- CFI_RESTORE_STATE + bt $TIF_NEED_RESCHED,%edx + jnc sysret_signal + TRACE_IRQS_ON +@@ -334,7 +332,6 @@ badsys: + + /* Do syscall tracing */ + tracesys: +- CFI_RESTORE_STATE + SAVE_REST + movq $-ENOSYS,RAX(%rsp) + FIXUP_TOP_OF_STACK %rdi +@@ -350,32 +347,13 @@ tracesys: + call *sys_call_table(,%rax,8) + 1: movq %rax,RAX-ARGOFFSET(%rsp) + /* Use IRET because user could have changed frame */ +- jmp int_ret_from_sys_call +- CFI_ENDPROC +-END(system_call) + + /* + * Syscall return path ending with IRET. + * Has correct top of stack, but partial stack frame. +- */ +-ENTRY(int_ret_from_sys_call) +- CFI_STARTPROC simple +- CFI_SIGNAL_FRAME +- CFI_DEF_CFA rsp,SS+8-ARGOFFSET +- /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/ +- CFI_REL_OFFSET rsp,RSP-ARGOFFSET +- /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ +- /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/ +- CFI_REL_OFFSET rip,RIP-ARGOFFSET +- CFI_REL_OFFSET rdx,RDX-ARGOFFSET +- CFI_REL_OFFSET rcx,RCX-ARGOFFSET +- CFI_REL_OFFSET rax,RAX-ARGOFFSET +- CFI_REL_OFFSET rdi,RDI-ARGOFFSET +- CFI_REL_OFFSET rsi,RSI-ARGOFFSET +- CFI_REL_OFFSET r8,R8-ARGOFFSET +- CFI_REL_OFFSET r9,R9-ARGOFFSET +- CFI_REL_OFFSET r10,R10-ARGOFFSET +- CFI_REL_OFFSET r11,R11-ARGOFFSET ++ */ ++ .globl int_ret_from_sys_call ++int_ret_from_sys_call: + XEN_BLOCK_EVENTS(%rsi) + TRACE_IRQS_OFF + testb $3,CS-ARGOFFSET(%rsp) +@@ -428,8 +406,6 @@ int_very_careful: + popq %rdi + CFI_ADJUST_CFA_OFFSET -8 + andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi +- XEN_BLOCK_EVENTS(%rsi) +- TRACE_IRQS_OFF + jmp int_restore_rest + + int_signal: +@@ -445,7 +421,7 @@ int_restore_rest: + TRACE_IRQS_OFF + jmp int_with_check + CFI_ENDPROC +-END(int_ret_from_sys_call) ++END(system_call) + + /* + * Certain special system calls that need to save a complete full stack frame. +@@ -1275,36 +1251,3 @@ ENTRY(call_softirq) + ret + CFI_ENDPROC + ENDPROC(call_softirq) +- +-#ifdef CONFIG_STACK_UNWIND +-ENTRY(arch_unwind_init_running) +- CFI_STARTPROC +- movq %r15, R15(%rdi) +- movq %r14, R14(%rdi) +- xchgq %rsi, %rdx +- movq %r13, R13(%rdi) +- movq %r12, R12(%rdi) +- xorl %eax, %eax +- movq %rbp, RBP(%rdi) +- movq %rbx, RBX(%rdi) +- movq (%rsp), %rcx +- movq %rax, R11(%rdi) +- movq %rax, R10(%rdi) +- movq %rax, R9(%rdi) +- movq %rax, R8(%rdi) +- movq %rax, RAX(%rdi) +- movq %rax, RCX(%rdi) +- movq %rax, RDX(%rdi) +- movq %rax, RSI(%rdi) +- movq %rax, RDI(%rdi) +- movq %rax, ORIG_RAX(%rdi) +- movq %rcx, RIP(%rdi) +- leaq 8(%rsp), %rcx +- movq $__KERNEL_CS, CS(%rdi) +- movq %rax, EFLAGS(%rdi) +- movq %rcx, RSP(%rdi) +- movq $__KERNEL_DS, SS(%rdi) +- jmpq *%rdx +- CFI_ENDPROC +-ENDPROC(arch_unwind_init_running) +-#endif +--- sle11-2009-06-29.orig/arch/x86/kernel/genapic_64-xen.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/genapic_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -34,6 +34,7 @@ extern struct genapic apic_physflat; + + #ifndef CONFIG_XEN + struct genapic *genapic = &apic_flat; ++struct genapic *genapic_force; + #else + extern struct genapic apic_xen; + struct genapic *genapic = &apic_xen; +@@ -52,6 +53,13 @@ void __init clustered_apic_check(void) + u8 cluster_cnt[NUM_APIC_CLUSTERS]; + int max_apic = 0; + ++ /* genapic selection can be forced because of certain quirks. ++ */ ++ if (genapic_force) { ++ genapic = genapic_force; ++ goto print; ++ } ++ + #if defined(CONFIG_ACPI) + /* + * Some x86_64 machines use physical APIC mode regardless of how many +--- sle11-2009-06-29.orig/arch/x86/kernel/head64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/head64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -104,7 +104,10 @@ void __init x86_64_start_kernel(char * r + machine_to_phys_order++; + + #if 0 +- for (i = 0; i < 256; i++) ++ /* clear bss before set_intr_gate with early_idt_handler */ ++ clear_bss(); ++ ++ for (i = 0; i < IDT_ENTRIES; i++) + set_intr_gate(i, early_idt_handler); + asm volatile("lidt %0" :: "m" (idt_descr)); + #endif +--- sle11-2009-06-29.orig/arch/x86/kernel/io_apic_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/io_apic_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -202,14 +202,20 @@ static struct IO_APIC_route_entry ioapic + * the interrupt, and we need to make sure the entry is fully populated + * before that happens. + */ +-static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++static void ++__ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) + { +- unsigned long flags; + union entry_union eu; + eu.entry = e; +- spin_lock_irqsave(&ioapic_lock, flags); + io_apic_write(apic, 0x11 + 2*pin, eu.w2); + io_apic_write(apic, 0x10 + 2*pin, eu.w1); ++} ++ ++static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&ioapic_lock, flags); ++ __ioapic_write_entry(apic, pin, e); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + +@@ -720,6 +726,22 @@ static int assign_irq_vector(int irq, cp + } + + #ifndef CONFIG_XEN ++static void __clear_irq_vector(int irq) ++{ ++ cpumask_t mask; ++ int cpu, vector; ++ ++ BUG_ON(!irq_vector[irq]); ++ ++ vector = irq_vector[irq]; ++ cpus_and(mask, irq_domain[irq], cpu_online_map); ++ for_each_cpu_mask(cpu, mask) ++ per_cpu(vector_irq, cpu)[vector] = -1; ++ ++ irq_vector[irq] = 0; ++ irq_domain[irq] = CPU_MASK_NONE; ++} ++ + void __setup_vector_irq(int cpu) + { + /* Initialize vector_irq on a new cpu */ +@@ -767,26 +789,65 @@ static void ioapic_register_intr(int irq + #define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq) + #endif /* !CONFIG_XEN */ + +-static void __init setup_IO_APIC_irqs(void) ++static void __init setup_IO_APIC_irq(int apic, int pin, int idx, int irq) + { + struct IO_APIC_route_entry entry; +- int apic, pin, idx, irq, first_notcon = 1, vector; ++ int vector; + unsigned long flags; + +- apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); + +- for (apic = 0; apic < nr_ioapics; apic++) { +- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { ++ /* ++ * add it to the IO-APIC irq-routing table: ++ */ ++ memset(&entry,0,sizeof(entry)); + +- /* +- * add it to the IO-APIC irq-routing table: +- */ +- memset(&entry,0,sizeof(entry)); ++ entry.delivery_mode = INT_DELIVERY_MODE; ++ entry.dest_mode = INT_DEST_MODE; ++ entry.mask = 0; /* enable IRQ */ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); + +- entry.delivery_mode = INT_DELIVERY_MODE; +- entry.dest_mode = INT_DEST_MODE; +- entry.mask = 0; /* enable IRQ */ ++ entry.trigger = irq_trigger(idx); ++ entry.polarity = irq_polarity(idx); ++ ++ if (irq_trigger(idx)) { ++ entry.trigger = 1; ++ entry.mask = 1; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ } ++ ++ if (/* !apic && */ !IO_APIC_IRQ(irq)) ++ return; ++ ++ if (IO_APIC_IRQ(irq)) { ++ cpumask_t mask; ++ vector = assign_irq_vector(irq, TARGET_CPUS, &mask); ++ if (vector < 0) ++ return; ++ ++ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); ++ entry.vector = vector; ++ ++ ioapic_register_intr(irq, vector, IOAPIC_AUTO); ++ if (!apic && (irq < 16)) ++ disable_8259A_irq(irq); ++ } ++ ++ ioapic_write_entry(apic, pin, entry); ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ set_native_irq_info(irq, TARGET_CPUS); ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ ++} ++ ++static void __init setup_IO_APIC_irqs(void) ++{ ++ int apic, pin, idx, irq, first_notcon = 1; ++ ++ apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); ++ ++ for (apic = 0; apic < nr_ioapics; apic++) { ++ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { + + idx = find_irq_entry(apic,pin,mp_INT); + if (idx == -1) { +@@ -798,39 +859,11 @@ static void __init setup_IO_APIC_irqs(vo + continue; + } + +- entry.trigger = irq_trigger(idx); +- entry.polarity = irq_polarity(idx); +- +- if (irq_trigger(idx)) { +- entry.trigger = 1; +- entry.mask = 1; +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); +- } +- + irq = pin_2_irq(idx, apic, pin); + add_pin_to_irq(irq, apic, pin); + +- if (/* !apic && */ !IO_APIC_IRQ(irq)) +- continue; +- +- if (IO_APIC_IRQ(irq)) { +- cpumask_t mask; +- vector = assign_irq_vector(irq, TARGET_CPUS, &mask); +- if (vector < 0) +- continue; +- +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); +- entry.vector = vector; ++ setup_IO_APIC_irq(apic, pin, idx, irq); + +- ioapic_register_intr(irq, vector, IOAPIC_AUTO); +- if (!apic && (irq < 16)) +- disable_8259A_irq(irq); +- } +- ioapic_write_entry(apic, pin, entry); +- +- spin_lock_irqsave(&ioapic_lock, flags); +- set_native_irq_info(irq, TARGET_CPUS); +- spin_unlock_irqrestore(&ioapic_lock, flags); + } + } + +@@ -1826,7 +1859,7 @@ void destroy_irq(unsigned int irq) + dynamic_irq_cleanup(irq); + + spin_lock_irqsave(&vector_lock, flags); +- irq_vector[irq] = 0; ++ __clear_irq_vector(irq); + spin_unlock_irqrestore(&vector_lock, flags); + } + +@@ -2131,7 +2164,15 @@ void __init setup_ioapic_dest(void) + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); +- set_ioapic_affinity_irq(irq, TARGET_CPUS); ++ ++ /* setup_IO_APIC_irqs could fail to get vector for some device ++ * when you have too many devices, because at that time only boot ++ * cpu is online. ++ */ ++ if(!irq_vector[irq]) ++ setup_IO_APIC_irq(ioapic, pin, irq_entry, irq); ++ else ++ set_ioapic_affinity_irq(irq, TARGET_CPUS); + } + + } +--- sle11-2009-06-29.orig/arch/x86/kernel/irq_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/irq_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -120,7 +120,7 @@ asmlinkage unsigned int do_IRQ(struct pt + + if (likely(irq < NR_IRQS)) + generic_handle_irq(irq); +- else ++ else if (printk_ratelimit()) + printk(KERN_EMERG "%s: %d.%d No irq handler for irq\n", + __func__, smp_processor_id(), irq); + +--- sle11-2009-06-29.orig/arch/x86/kernel/mpparse_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/mpparse_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -35,8 +35,6 @@ + int smp_found_config; + unsigned int __initdata maxcpus = NR_CPUS; + +-int acpi_found_madt; +- + /* + * Various Linux-internal data structures created from the + * MP-table. +--- sle11-2009-06-29.orig/arch/x86/kernel/process_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/process_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -119,29 +119,23 @@ void exit_idle(void) + static void poll_idle (void) + { + local_irq_enable(); +- +- asm volatile( +- "2:" +- "testl %0,%1;" +- "rep; nop;" +- "je 2b;" +- : : +- "i" (_TIF_NEED_RESCHED), +- "m" (current_thread_info()->flags)); ++ cpu_relax(); + } + + static void xen_idle(void) + { ++ current_thread_info()->status &= ~TS_POLLING; ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); + local_irq_disable(); +- +- if (need_resched()) +- local_irq_enable(); +- else { +- current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); ++ if (!need_resched()) + safe_halt(); +- current_thread_info()->status |= TS_POLLING; +- } ++ else ++ local_irq_enable(); ++ current_thread_info()->status |= TS_POLLING; + } + + #ifdef CONFIG_HOTPLUG_CPU +@@ -181,6 +175,12 @@ void cpu_idle (void) + idle = xen_idle; /* no alternatives */ + if (cpu_is_offline(smp_processor_id())) + play_dead(); ++ /* ++ * Idle routines should keep interrupts disabled ++ * from here on, until they go to idle. ++ * Otherwise, idle callbacks can misfire. ++ */ ++ local_irq_disable(); + enter_idle(); + idle(); + /* In many cases the interrupt that ended idle +--- sle11-2009-06-29.orig/arch/x86/kernel/setup_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -573,8 +573,7 @@ void __init setup_arch(char **cmdline_p) + if (LOADER_TYPE && INITRD_START) { + if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { + reserve_bootmem_generic(INITRD_START, INITRD_SIZE); +- initrd_start = +- INITRD_START ? INITRD_START + PAGE_OFFSET : 0; ++ initrd_start = INITRD_START + PAGE_OFFSET; + initrd_end = initrd_start+INITRD_SIZE; + } + else { +@@ -990,11 +989,8 @@ static void __cpuinit init_amd(struct cp + /* Fix cpuid4 emulation for more */ + num_cache_leaves = 3; + +- /* When there is only one core no need to synchronize RDTSC */ +- if (num_possible_cpus() == 1) +- set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); +- else +- clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ /* RDTSC can be speculated around */ ++ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); + } + + static void __cpuinit detect_ht(struct cpuinfo_x86 *c) +@@ -1093,6 +1089,15 @@ static void __cpuinit init_intel(struct + set_bit(X86_FEATURE_ARCH_PERFMON, &c->x86_capability); + } + ++ if (cpu_has_ds) { ++ unsigned int l1, l2; ++ rdmsr(MSR_IA32_MISC_ENABLE, l1, l2); ++ if (!(l1 & (1<<11))) ++ set_bit(X86_FEATURE_BTS, c->x86_capability); ++ if (!(l1 & (1<<12))) ++ set_bit(X86_FEATURE_PEBS, c->x86_capability); ++ } ++ + n = c->extended_cpuid_level; + if (n >= 0x80000008) { + unsigned eax = cpuid_eax(0x80000008); +@@ -1112,7 +1117,10 @@ static void __cpuinit init_intel(struct + set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); + if (c->x86 == 6) + set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); +- set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ if (c->x86 == 15) ++ set_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ else ++ clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); + c->x86_max_cores = intel_num_cpu_cores(c); + + srat_detect_node(); +--- sle11-2009-06-29.orig/arch/x86/kernel/smp_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/smp_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -384,12 +384,17 @@ int smp_call_function_single (int cpu, v + put_cpu(); + return 0; + } ++ ++ /* Can deadlock when called with interrupts disabled */ ++ WARN_ON(irqs_disabled()); ++ + spin_lock_bh(&call_lock); + __smp_call_function_single(cpu, func, info, nonatomic, wait); + spin_unlock_bh(&call_lock); + put_cpu(); + return 0; + } ++EXPORT_SYMBOL(smp_call_function_single); + + /* + * this function sends a 'generic call function' IPI to all other CPUs +--- sle11-2009-06-29.orig/arch/x86/kernel/traps_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/traps_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -30,9 +30,10 @@ + #include + #include + #include ++#include ++#include + + #include +-#include + #include + #include + #include +@@ -108,12 +109,7 @@ static inline void preempt_conditional_c + preempt_enable_no_resched(); + } + +-static int kstack_depth_to_print = 12; +-#ifdef CONFIG_STACK_UNWIND +-static int call_trace = 1; +-#else +-#define call_trace (-1) +-#endif ++int kstack_depth_to_print = 12; + + #ifdef CONFIG_KALLSYMS + void printk_address(unsigned long address) +@@ -218,24 +214,7 @@ static unsigned long *in_exception_stack + return NULL; + } + +-struct ops_and_data { +- struct stacktrace_ops *ops; +- void *data; +-}; +- +-static int dump_trace_unwind(struct unwind_frame_info *info, void *context) +-{ +- struct ops_and_data *oad = (struct ops_and_data *)context; +- int n = 0; +- +- while (unwind(info) == 0 && UNW_PC(info)) { +- n++; +- oad->ops->address(oad->data, UNW_PC(info)); +- if (arch_unw_user_mode(info)) +- break; +- } +- return n; +-} ++#define MSG(txt) ops->warning(data, txt) + + /* + * x86-64 can have upto three kernel stacks: +@@ -250,61 +229,24 @@ static inline int valid_stack_ptr(struct + return p > t && p < t + THREAD_SIZE - 3; + } + +-void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, ++void dump_trace(struct task_struct *tsk, struct pt_regs *regs, ++ unsigned long *stack, + struct stacktrace_ops *ops, void *data) + { +- const unsigned cpu = smp_processor_id(); +- unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; ++ const unsigned cpu = get_cpu(); ++ unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr; + unsigned used = 0; + struct thread_info *tinfo; + + if (!tsk) + tsk = current; + +- if (call_trace >= 0) { +- int unw_ret = 0; +- struct unwind_frame_info info; +- struct ops_and_data oad = { .ops = ops, .data = data }; +- +- if (regs) { +- if (unwind_init_frame_info(&info, tsk, regs) == 0) +- unw_ret = dump_trace_unwind(&info, &oad); +- } else if (tsk == current) +- unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); +- else { +- if (unwind_init_blocked(&info, tsk) == 0) +- unw_ret = dump_trace_unwind(&info, &oad); +- } +- if (unw_ret > 0) { +- if (call_trace == 1 && !arch_unw_user_mode(&info)) { +- ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", +- UNW_PC(&info)); +- if ((long)UNW_SP(&info) < 0) { +- ops->warning(data, "Leftover inexact backtrace:\n"); +- stack = (unsigned long *)UNW_SP(&info); +- if (!stack) +- return; +- } else +- ops->warning(data, "Full inexact backtrace again:\n"); +- } else if (call_trace >= 1) +- return; +- else +- ops->warning(data, "Full inexact backtrace again:\n"); +- } else +- ops->warning(data, "Inexact backtrace:\n"); +- } + if (!stack) { + unsigned long dummy; + stack = &dummy; + if (tsk && tsk != current) + stack = (unsigned long *)tsk->thread.rsp; + } +- /* +- * Align the stack pointer on word boundary, later loops +- * rely on that (and corruption / debug info bugs can cause +- * unaligned values here): +- */ +- stack = (unsigned long *)((unsigned long)stack & ~(sizeof(long)-1)); + + /* + * Print function call entries within a stack. 'cond' is the +@@ -314,9 +256,9 @@ void dump_trace(struct task_struct *tsk, + #define HANDLE_STACK(cond) \ + do while (cond) { \ + unsigned long addr = *stack++; \ +- if (oops_in_progress ? \ +- __kernel_text_address(addr) : \ +- kernel_text_address(addr)) { \ ++ /* Use unlocked access here because except for NMIs \ ++ we should be already protected against module unloads */ \ ++ if (__kernel_text_address(addr)) { \ + /* \ + * If the address is either in the text segment of the \ + * kernel, or in the region which contains vmalloc'ed \ +@@ -379,9 +321,10 @@ void dump_trace(struct task_struct *tsk, + /* + * This handles the process stack: + */ +- tinfo = current_thread_info(); ++ tinfo = task_thread_info(tsk); + HANDLE_STACK (valid_stack_ptr(tinfo, stack)); + #undef HANDLE_STACK ++ put_cpu(); + } + EXPORT_SYMBOL(dump_trace); + +@@ -518,30 +461,15 @@ bad: + printk("\n"); + } + +-void handle_BUG(struct pt_regs *regs) +-{ +- struct bug_frame f; +- long len; +- const char *prefix = ""; ++int is_valid_bugaddr(unsigned long rip) ++{ ++ unsigned short ud2; + +- if (user_mode(regs)) +- return; +- if (__copy_from_user(&f, (const void __user *) regs->rip, +- sizeof(struct bug_frame))) +- return; +- if (f.filename >= 0 || +- f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) +- return; +- len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1; +- if (len < 0 || len >= PATH_MAX) +- f.filename = (int)(long)"unmapped filename"; +- else if (len > 50) { +- f.filename += len - 50; +- prefix = "..."; +- } +- printk("----------- [cut here ] --------- [please bite here ] ---------\n"); +- printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line); +-} ++ if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2))) ++ return 0; ++ ++ return ud2 == 0x0b0f; ++} + + #ifdef CONFIG_BUG + void out_of_line_bug(void) +@@ -621,7 +549,9 @@ void die(const char * str, struct pt_reg + { + unsigned long flags = oops_begin(); + +- handle_BUG(regs); ++ if (!user_mode(regs)) ++ report_bug(regs->rip); ++ + __die(str, regs, err); + oops_end(flags); + do_exit(SIGSEGV); +@@ -790,8 +720,7 @@ mem_parity_error(unsigned char reason, s + { + printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", + reason); +- printk(KERN_EMERG "You probably have a hardware problem with your " +- "RAM chips\n"); ++ printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); + + if (panic_on_unrecovered_nmi) + panic("NMI: Not continuing"); +@@ -1227,21 +1156,3 @@ static int __init kstack_setup(char *s) + return 0; + } + early_param("kstack", kstack_setup); +- +-#ifdef CONFIG_STACK_UNWIND +-static int __init call_trace_setup(char *s) +-{ +- if (!s) +- return -EINVAL; +- if (strcmp(s, "old") == 0) +- call_trace = -1; +- else if (strcmp(s, "both") == 0) +- call_trace = 0; +- else if (strcmp(s, "newfallback") == 0) +- call_trace = 1; +- else if (strcmp(s, "new") == 0) +- call_trace = 2; +- return 0; +-} +-early_param("call_trace", call_trace_setup); +-#endif +--- sle11-2009-06-29.orig/arch/x86/kernel/vsyscall_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/vsyscall_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -42,6 +42,7 @@ + #include + + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) ++#define __syscall_clobber "r11","rcx","memory" + + int __sysctl_vsyscall __section_sysctl_vsyscall = 1; + seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; +@@ -224,8 +225,7 @@ out: + + static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, +- void __user *newval, size_t newlen, +- void **context) ++ void __user *newval, size_t newlen) + { + return -ENOSYS; + } +@@ -277,7 +277,6 @@ static void __cpuinit cpu_vsyscall_init( + vsyscall_set_cpu(raw_smp_processor_id()); + } + +-#ifdef CONFIG_HOTPLUG_CPU + static int __cpuinit + cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) + { +@@ -286,13 +285,13 @@ cpu_vsyscall_notifier(struct notifier_bl + smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); + return NOTIFY_DONE; + } +-#endif + + static void __init map_vsyscall(void) + { + extern char __vsyscall_0; + unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0); + ++ /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */ + __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL); + } + +--- sle11-2009-06-29.orig/arch/x86/mm/fault_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/fault_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -23,9 +23,9 @@ + #include + #include + #include ++#include + + #include +-#include + #include + #include + #include +@@ -96,7 +96,7 @@ void bust_spinlocks(int yes) + static noinline int is_prefetch(struct pt_regs *regs, unsigned long addr, + unsigned long error_code) + { +- unsigned char __user *instr; ++ unsigned char *instr; + int scan_more = 1; + int prefetch = 0; + unsigned char *max_instr; +@@ -116,7 +116,7 @@ static noinline int is_prefetch(struct p + unsigned char instr_hi; + unsigned char instr_lo; + +- if (__get_user(opcode, (char __user *)instr)) ++ if (probe_kernel_address(instr, opcode)) + break; + + instr_hi = opcode & 0xf0; +@@ -154,7 +154,7 @@ static noinline int is_prefetch(struct p + case 0x00: + /* Prefetch instruction is 0x0F0D or 0x0F18 */ + scan_more = 0; +- if (__get_user(opcode, (char __user *)instr)) ++ if (probe_kernel_address(instr, opcode)) + break; + prefetch = (instr_lo == 0xF) && + (opcode == 0x0D || opcode == 0x18); +@@ -170,7 +170,7 @@ static noinline int is_prefetch(struct p + static int bad_address(void *p) + { + unsigned long dummy; +- return __get_user(dummy, (unsigned long __user *)p); ++ return probe_kernel_address((unsigned long *)p, dummy); + } + + void dump_pagetable(unsigned long address) +--- sle11-2009-06-29.orig/arch/x86/mm/init_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/init_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -1127,14 +1127,15 @@ static __init int x8664_sysctl_init(void + __initcall(x8664_sysctl_init); + #endif + +-/* A pseudo VMAs to allow ptrace access for the vsyscall page. This only ++/* A pseudo VMA to allow ptrace access for the vsyscall page. This only + covers the 64bit vsyscall page now. 32bit has a real VMA now and does + not need special handling anymore. */ + + static struct vm_area_struct gate_vma = { + .vm_start = VSYSCALL_START, +- .vm_end = VSYSCALL_END, +- .vm_page_prot = PAGE_READONLY ++ .vm_end = VSYSCALL_START + (VSYSCALL_MAPPED_PAGES << PAGE_SHIFT), ++ .vm_page_prot = PAGE_READONLY_EXEC, ++ .vm_flags = VM_READ | VM_EXEC + }; + + struct vm_area_struct *get_gate_vma(struct task_struct *tsk) +--- sle11-2009-06-29.orig/arch/x86/mm/pageattr_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/pageattr_64-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -330,34 +330,40 @@ static struct page *split_large_page(uns + return base; + } + +- +-static void flush_kernel_map(void *address) ++static void cache_flush_page(void *adr) + { +- if (0 && address && cpu_has_clflush) { +- /* is this worth it? */ +- int i; +- for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) +- asm volatile("clflush (%0)" :: "r" (address + i)); +- } else +- asm volatile("wbinvd":::"memory"); +- if (address) +- __flush_tlb_one(address); +- else +- __flush_tlb_all(); ++ int i; ++ for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) ++ asm volatile("clflush (%0)" :: "r" (adr + i)); + } + ++static void flush_kernel_map(void *arg) ++{ ++ struct list_head *l = (struct list_head *)arg; ++ struct page *pg; + +-static inline void flush_map(unsigned long address) ++ /* When clflush is available always use it because it is ++ much cheaper than WBINVD */ ++ if (!cpu_has_clflush) ++ asm volatile("wbinvd" ::: "memory"); ++ list_for_each_entry(pg, l, lru) { ++ void *adr = page_address(pg); ++ if (cpu_has_clflush) ++ cache_flush_page(adr); ++ __flush_tlb_one(adr); ++ } ++} ++ ++static inline void flush_map(struct list_head *l) + { +- on_each_cpu(flush_kernel_map, (void *)address, 1, 1); ++ on_each_cpu(flush_kernel_map, l, 1, 1); + } + +-static struct page *deferred_pages; /* protected by init_mm.mmap_sem */ ++static LIST_HEAD(deferred_pages); /* protected by init_mm.mmap_sem */ + + static inline void save_page(struct page *fpage) + { +- fpage->lru.next = (struct list_head *)deferred_pages; +- deferred_pages = fpage; ++ list_add(&fpage->lru, &deferred_pages); + } + + /* +@@ -487,18 +493,18 @@ int change_page_attr(struct page *page, + + void global_flush_tlb(void) + { +- struct page *dpage; ++ struct page *pg, *next; ++ struct list_head l; + + down_read(&init_mm.mmap_sem); +- dpage = xchg(&deferred_pages, NULL); ++ list_replace_init(&deferred_pages, &l); + up_read(&init_mm.mmap_sem); + +- flush_map((dpage && !dpage->lru.next) ? (unsigned long)page_address(dpage) : 0); +- while (dpage) { +- struct page *tmp = dpage; +- dpage = (struct page *)dpage->lru.next; +- ClearPagePrivate(tmp); +- __free_page(tmp); ++ flush_map(&l); ++ ++ list_for_each_entry_safe(pg, next, &l, lru) { ++ ClearPagePrivate(pg); ++ __free_page(pg); + } + } + +--- sle11-2009-06-29.orig/drivers/pci/msi-xen.c 2009-04-24 13:31:56.000000000 +0200 ++++ sle11-2009-06-29/drivers/pci/msi-xen.c 2008-12-15 11:26:44.000000000 +0100 +@@ -263,10 +263,8 @@ void disable_msi_mode(struct pci_dev *de + pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msix_enabled = 0; + } +- if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { +- /* PCI Express Endpoint device detected */ +- pci_intx(dev, 1); /* enable intx */ +- } ++ ++ pci_intx(dev, 1); /* enable intx */ + } + + static void enable_msi_mode(struct pci_dev *dev, int pos, int type) +@@ -284,10 +282,8 @@ static void enable_msi_mode(struct pci_d + pci_write_config_word(dev, msi_control_reg(pos), control); + dev->msix_enabled = 1; + } +- if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { +- /* PCI Express Endpoint device detected */ +- pci_intx(dev, 0); /* disable intx */ +- } ++ ++ pci_intx(dev, 0); /* disable intx */ + } + + #ifdef CONFIG_PM +--- sle11-2009-06-29.orig/drivers/xen/balloon/balloon.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/balloon/balloon.c 2009-06-29 15:28:36.000000000 +0200 +@@ -97,8 +97,8 @@ extern unsigned long totalhigh_pages; + static LIST_HEAD(ballooned_pages); + + /* Main work function, always executed in process context. */ +-static void balloon_process(void *unused); +-static DECLARE_WORK(balloon_worker, balloon_process, NULL); ++static void balloon_process(struct work_struct *unused); ++static DECLARE_WORK(balloon_worker, balloon_process); + static struct timer_list balloon_timer; + + /* When ballooning out (allocating memory to return to Xen) we don't really +@@ -375,7 +375,7 @@ static int decrease_reservation(unsigned + * by the balloon lock), or with changes to the Xen hard limit, but we will + * recover from these in time. + */ +-static void balloon_process(void *unused) ++static void balloon_process(struct work_struct *unused) + { + int need_sleep = 0; + long credit; +--- sle11-2009-06-29.orig/drivers/xen/blkback/blkback.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/blkback/blkback.c 2008-12-15 11:26:44.000000000 +0100 +@@ -37,6 +37,7 @@ + + #include + #include ++#include + #include + #include + #include +--- sle11-2009-06-29.orig/drivers/xen/blkback/interface.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/blkback/interface.c 2008-12-15 11:26:44.000000000 +0100 +@@ -34,7 +34,7 @@ + #include + #include + +-static kmem_cache_t *blkif_cachep; ++static struct kmem_cache *blkif_cachep; + + blkif_t *blkif_alloc(domid_t domid) + { +--- sle11-2009-06-29.orig/drivers/xen/blkfront/blkfront.c 2009-03-24 10:08:16.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/blkfront/blkfront.c 2009-03-24 10:08:27.000000000 +0100 +@@ -71,7 +71,7 @@ static int setup_blkring(struct xenbus_d + static void kick_pending_request_queues(struct blkfront_info *); + + static irqreturn_t blkif_int(int irq, void *dev_id); +-static void blkif_restart_queue(void *arg); ++static void blkif_restart_queue(struct work_struct *arg); + static void blkif_recover(struct blkfront_info *); + static void blkif_completion(struct blk_shadow *); + static void blkif_free(struct blkfront_info *, int); +@@ -111,7 +111,7 @@ static int blkfront_probe(struct xenbus_ + info->xbdev = dev; + info->vdevice = vdevice; + info->connected = BLKIF_STATE_DISCONNECTED; +- INIT_WORK(&info->work, blkif_restart_queue, (void *)info); ++ INIT_WORK(&info->work, blkif_restart_queue); + + for (i = 0; i < BLK_RING_SIZE; i++) + info->shadow[i].req.id = i+1; +@@ -462,9 +462,9 @@ static void kick_pending_request_queues( + } + } + +-static void blkif_restart_queue(void *arg) ++static void blkif_restart_queue(struct work_struct *arg) + { +- struct blkfront_info *info = (struct blkfront_info *)arg; ++ struct blkfront_info *info = container_of(arg, struct blkfront_info, work); + spin_lock_irq(&blkif_io_lock); + if (info->connected == BLKIF_STATE_CONNECTED) + kick_pending_request_queues(info); +--- sle11-2009-06-29.orig/drivers/xen/blktap/blktap.c 2009-04-20 11:37:34.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/blktap/blktap.c 2009-04-20 11:37:50.000000000 +0200 +@@ -40,6 +40,7 @@ + + #include + #include ++#include + #include + #include + #include "common.h" +--- sle11-2009-06-29.orig/drivers/xen/blktap/interface.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/blktap/interface.c 2008-12-15 11:26:44.000000000 +0100 +@@ -34,7 +34,7 @@ + #include "common.h" + #include + +-static kmem_cache_t *blkif_cachep; ++static struct kmem_cache *blkif_cachep; + + blkif_t *tap_alloc_blkif(domid_t domid) + { +--- sle11-2009-06-29.orig/drivers/xen/char/mem.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/char/mem.c 2008-12-15 11:26:44.000000000 +0100 +@@ -157,7 +157,7 @@ static loff_t memory_lseek(struct file * + { + loff_t ret; + +- mutex_lock(&file->f_dentry->d_inode->i_mutex); ++ mutex_lock(&file->f_path.dentry->d_inode->i_mutex); + switch (orig) { + case 0: + file->f_pos = offset; +@@ -172,7 +172,7 @@ static loff_t memory_lseek(struct file * + default: + ret = -EINVAL; + } +- mutex_unlock(&file->f_dentry->d_inode->i_mutex); ++ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); + return ret; + } + +--- sle11-2009-06-29.orig/drivers/xen/console/console.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/console/console.c 2008-12-15 11:26:44.000000000 +0100 +@@ -85,11 +85,6 @@ static int xc_num = -1; + #define XEN_HVC_MAJOR 229 + #define XEN_HVC_MINOR 0 + +-#ifdef CONFIG_MAGIC_SYSRQ +-static unsigned long sysrq_requested; +-extern int sysrq_enabled; +-#endif +- + static int __init xencons_setup(char *str) + { + char *q; +@@ -355,8 +350,8 @@ void __init dom0_init_screen_info(const + #define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) && \ + ((_tty)->index != (xc_num - 1))) + +-static struct termios *xencons_termios[MAX_NR_CONSOLES]; +-static struct termios *xencons_termios_locked[MAX_NR_CONSOLES]; ++static struct ktermios *xencons_termios[MAX_NR_CONSOLES]; ++static struct ktermios *xencons_termios_locked[MAX_NR_CONSOLES]; + static struct tty_struct *xencons_tty; + static int xencons_priv_irq; + static char x_char; +@@ -372,7 +367,9 @@ void xencons_rx(char *buf, unsigned len) + + for (i = 0; i < len; i++) { + #ifdef CONFIG_MAGIC_SYSRQ +- if (sysrq_enabled) { ++ if (sysrq_on()) { ++ static unsigned long sysrq_requested; ++ + if (buf[i] == '\x0f') { /* ^O */ + if (!sysrq_requested) { + sysrq_requested = jiffies; +--- sle11-2009-06-29.orig/drivers/xen/core/reboot.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/core/reboot.c 2008-12-15 11:26:44.000000000 +0100 +@@ -34,8 +34,8 @@ static int suspend_cancelled; + /* Can we leave APs online when we suspend? */ + static int fast_suspend; + +-static void __shutdown_handler(void *unused); +-static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL); ++static void __shutdown_handler(struct work_struct *unused); ++static DECLARE_DELAYED_WORK(shutdown_work, __shutdown_handler); + + static int setup_suspend_evtchn(void); + +@@ -105,7 +105,7 @@ static int xen_suspend(void *__unused) + case SHUTDOWN_RESUMING: + break; + default: +- schedule_work(&shutdown_work); ++ schedule_delayed_work(&shutdown_work, 0); + break; + } + +@@ -137,12 +137,12 @@ static void switch_shutdown_state(int ne + + /* Either we kick off the work, or we leave it to xen_suspend(). */ + if (old_state == SHUTDOWN_INVALID) +- schedule_work(&shutdown_work); ++ schedule_delayed_work(&shutdown_work, 0); + else + BUG_ON(old_state != SHUTDOWN_RESUMING); + } + +-static void __shutdown_handler(void *unused) ++static void __shutdown_handler(struct work_struct *unused) + { + int err; + +--- sle11-2009-06-29.orig/drivers/xen/core/smpboot.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/core/smpboot.c 2008-12-15 11:26:44.000000000 +0100 +@@ -161,7 +161,12 @@ static void xen_smp_intr_exit(unsigned i + + void __cpuinit cpu_bringup(void) + { ++#ifdef __i386__ ++ cpu_set_gdt(current_thread_info()->cpu); ++ secondary_cpu_init(); ++#else + cpu_init(); ++#endif + identify_cpu(cpu_data + smp_processor_id()); + touch_softlockup_watchdog(); + preempt_disable(); +@@ -300,11 +305,12 @@ void __init smp_prepare_cpus(unsigned in + if (cpu == 0) + continue; + ++ idle = fork_idle(cpu); ++ if (IS_ERR(idle)) ++ panic("failed fork for CPU %d", cpu); ++ + #ifdef __x86_64__ + gdt_descr = &cpu_gdt_descr[cpu]; +-#else +- gdt_descr = &per_cpu(cpu_gdt_descr, cpu); +-#endif + gdt_descr->address = get_zeroed_page(GFP_KERNEL); + if (unlikely(!gdt_descr->address)) { + printk(KERN_CRIT "CPU%d failed to allocate GDT\n", +@@ -313,6 +319,11 @@ void __init smp_prepare_cpus(unsigned in + } + gdt_descr->size = GDT_SIZE; + memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE); ++#else ++ if (unlikely(!init_gdt(cpu, idle))) ++ continue; ++ gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++#endif + make_page_readonly( + (void *)gdt_descr->address, + XENFEAT_writable_descriptor_tables); +@@ -332,10 +343,6 @@ void __init smp_prepare_cpus(unsigned in + cpu_2_logical_apicid[cpu] = apicid; + x86_cpu_to_apicid[cpu] = apicid; + +- idle = fork_idle(cpu); +- if (IS_ERR(idle)) +- panic("failed fork for CPU %d", cpu); +- + #ifdef __x86_64__ + cpu_pda(cpu)->pcurrent = idle; + cpu_pda(cpu)->cpunumber = cpu; +--- sle11-2009-06-29.orig/drivers/xen/fbfront/xenfb.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/fbfront/xenfb.c 2008-12-15 11:26:44.000000000 +0100 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +--- sle11-2009-06-29.orig/drivers/xen/netback/loopback.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/netback/loopback.c 2008-12-15 11:26:44.000000000 +0100 +@@ -54,6 +54,7 @@ + #include + #include /* secpath_reset() */ + #include /* is_initial_xendomain() */ ++#include <../net/core/kmap_skb.h> /* k{,un}map_skb_frag() */ + + static int nloopbacks = -1; + module_param(nloopbacks, int, 0); +--- sle11-2009-06-29.orig/drivers/xen/pciback/conf_space_header.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/pciback/conf_space_header.c 2008-12-15 11:26:44.000000000 +0100 +@@ -22,14 +22,14 @@ static int command_write(struct pci_dev + { + int err; + +- if (!dev->is_enabled && is_enable_cmd(value)) { ++ if (!atomic_read(&dev->enable_cnt) && is_enable_cmd(value)) { + if (unlikely(verbose_request)) + printk(KERN_DEBUG "pciback: %s: enable\n", + pci_name(dev)); + err = pci_enable_device(dev); + if (err) + return err; +- } else if (dev->is_enabled && !is_enable_cmd(value)) { ++ } else if (atomic_read(&dev->enable_cnt) && !is_enable_cmd(value)) { + if (unlikely(verbose_request)) + printk(KERN_DEBUG "pciback: %s: disable\n", + pci_name(dev)); +--- sle11-2009-06-29.orig/drivers/xen/pciback/pciback.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/pciback/pciback.h 2008-12-15 11:26:44.000000000 +0100 +@@ -88,7 +88,7 @@ void pciback_release_devices(struct pcib + + /* Handles events from front-end */ + irqreturn_t pciback_handle_event(int irq, void *dev_id); +-void pciback_do_op(void *data); ++void pciback_do_op(struct work_struct *work); + + int pciback_xenbus_register(void); + void pciback_xenbus_unregister(void); +--- sle11-2009-06-29.orig/drivers/xen/pciback/pciback_ops.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/pciback/pciback_ops.c 2008-12-15 11:26:44.000000000 +0100 +@@ -25,7 +25,7 @@ void pciback_reset_device(struct pci_dev + + pci_write_config_word(dev, PCI_COMMAND, 0); + +- dev->is_enabled = 0; ++ atomic_set(&dev->enable_cnt, 0); + dev->is_busmaster = 0; + } else { + pci_read_config_word(dev, PCI_COMMAND, &cmd); +@@ -51,9 +51,9 @@ static inline void test_and_schedule_op( + * context because some of the pci_* functions can sleep (mostly due to ACPI + * use of semaphores). This function is intended to be called from a work + * queue in process context taking a struct pciback_device as a parameter */ +-void pciback_do_op(void *data) ++void pciback_do_op(struct work_struct *work) + { +- struct pciback_device *pdev = data; ++ struct pciback_device *pdev = container_of(work, struct pciback_device, op_work); + struct pci_dev *dev; + struct xen_pci_op *op = &pdev->sh_info->op; + +--- sle11-2009-06-29.orig/drivers/xen/pciback/xenbus.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/pciback/xenbus.c 2008-12-15 11:26:44.000000000 +0100 +@@ -32,7 +32,7 @@ static struct pciback_device *alloc_pdev + pdev->evtchn_irq = INVALID_EVTCHN_IRQ; + pdev->be_watching = 0; + +- INIT_WORK(&pdev->op_work, pciback_do_op, pdev); ++ INIT_WORK(&pdev->op_work, pciback_do_op); + + if (pciback_init_devices(pdev)) { + kfree(pdev); +@@ -54,7 +54,6 @@ static void pciback_disconnect(struct pc + + /* If the driver domain started an op, make sure we complete it or + * delete it before releasing the shared memory */ +- cancel_delayed_work(&pdev->op_work); + flush_scheduled_work(); + + if (pdev->sh_info != NULL) { +--- sle11-2009-06-29.orig/drivers/xen/scsiback/interface.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/scsiback/interface.c 2008-12-15 11:26:44.000000000 +0100 +@@ -39,7 +39,7 @@ + #include + + +-static kmem_cache_t *scsiback_cachep; ++static struct kmem_cache *scsiback_cachep; + + struct vscsibk_info *vscsibk_info_alloc(domid_t domid) + { +--- sle11-2009-06-29.orig/drivers/xen/scsiback/scsiback.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/scsiback/scsiback.c 2008-12-15 11:26:44.000000000 +0100 +@@ -322,13 +322,11 @@ static int scsiback_merge_bio(struct req + + if (!rq->bio) + blk_rq_bio_prep(q, rq, bio); +- else if (!q->back_merge_fn(q, rq, bio)) ++ else if (!ll_back_merge_fn(q, rq, bio)) + return -EINVAL; + else { + rq->biotail->bi_next = bio; + rq->biotail = bio; +- rq->hard_nr_sectors += bio_sectors(bio); +- rq->nr_sectors = rq->hard_nr_sectors; + } + + return 0; +--- sle11-2009-06-29.orig/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:35:11.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:35:25.000000000 +0200 +@@ -463,7 +463,7 @@ netfront_accel_enqueue_skb_multi(netfron + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Set to zero to encourage falcon to work it out for us */ +- *(u16*)(skb->h.raw + skb->csum) = 0; ++ *(u16*)(skb->h.raw + skb->csum_offset) = 0; + } + + if (multi_post_start_new_buffer(vnic, &state)) { +@@ -582,7 +582,7 @@ netfront_accel_enqueue_skb_single(netfro + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Set to zero to encourage falcon to work it out for us */ +- *(u16*)(skb->h.raw + skb->csum) = 0; ++ *(u16*)(skb->h.raw + skb->csum_offset) = 0; + } + NETFRONT_ACCEL_PKTBUFF_FOR_EACH_FRAGMENT + (skb, idx, frag_data, frag_len, { +--- sle11-2009-06-29.orig/drivers/xen/tpmback/interface.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/tpmback/interface.c 2008-12-15 11:26:44.000000000 +0100 +@@ -15,7 +15,7 @@ + #include + #include + +-static kmem_cache_t *tpmif_cachep; ++static struct kmem_cache *tpmif_cachep; + int num_frontends = 0; + + LIST_HEAD(tpmif_list); +--- sle11-2009-06-29.orig/drivers/xen/xenbus/xenbus_comms.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/xenbus/xenbus_comms.c 2008-12-15 11:26:44.000000000 +0100 +@@ -49,9 +49,9 @@ + + static int xenbus_irq; + +-extern void xenbus_probe(void *); ++extern void xenbus_probe(struct work_struct *); + extern int xenstored_ready; +-static DECLARE_WORK(probe_work, xenbus_probe, NULL); ++static DECLARE_WORK(probe_work, xenbus_probe); + + static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); + +--- sle11-2009-06-29.orig/drivers/xen/xenbus/xenbus_probe.c 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/xenbus/xenbus_probe.c 2008-12-15 11:26:44.000000000 +0100 +@@ -843,7 +843,7 @@ void unregister_xenstore_notifier(struct + EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); + + +-void xenbus_probe(void *unused) ++void xenbus_probe(struct work_struct *unused) + { + BUG_ON((xenstored_ready <= 0)); + +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/desc_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/desc_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -4,8 +4,6 @@ + #include + #include + +-#define CPU_16BIT_STACK_SIZE 1024 +- + #ifndef __ASSEMBLY__ + + #include +@@ -15,8 +13,6 @@ + + extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; + +-DECLARE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); +- + struct Xgt_desc_struct { + unsigned short size; + unsigned long address __attribute__((packed)); +@@ -32,11 +28,6 @@ static inline struct desc_struct *get_cp + return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address; + } + +-/* +- * This is the ldt that every process will get unless we need +- * something other than this. +- */ +-extern struct desc_struct default_ldt[]; + extern struct desc_struct idt_table[]; + extern void set_intr_gate(unsigned int irq, void * addr); + +@@ -63,8 +54,8 @@ static inline void pack_gate(__u32 *a, _ + #define DESCTYPE_DPL3 0x60 /* DPL-3 */ + #define DESCTYPE_S 0x10 /* !system */ + ++#ifndef CONFIG_XEN + #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) +-#define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)) + + #define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) + #define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) +@@ -75,6 +66,7 @@ static inline void pack_gate(__u32 *a, _ + #define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) + #define store_tr(tr) __asm__ ("str %0":"=m" (tr)) + #define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) ++#endif + + #if TLS_SIZE != 24 + # error update this code. +@@ -90,22 +82,43 @@ static inline void load_TLS(struct threa + } + + #ifndef CONFIG_XEN ++#define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++#define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++ + static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b) + { + __u32 *lp = (__u32 *)((char *)dt + entry*8); + *lp = entry_a; + *(lp+1) = entry_b; + } +- +-#define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) +-#define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) ++#define set_ldt native_set_ldt + #else + extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); + extern int write_gdt_entry(void *gdt, int entry, __u32 entry_a, __u32 entry_b); ++#define set_ldt xen_set_ldt ++#endif ++ ++#ifndef CONFIG_XEN ++static inline fastcall void native_set_ldt(const void *addr, ++ unsigned int entries) ++{ ++ if (likely(entries == 0)) ++ __asm__ __volatile__("lldt %w0"::"q" (0)); ++ else { ++ unsigned cpu = smp_processor_id(); ++ __u32 a, b; ++ ++ pack_descriptor(&a, &b, (unsigned long)addr, ++ entries * sizeof(struct desc_struct) - 1, ++ DESCTYPE_LDT, 0); ++ write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, a, b); ++ __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); ++ } ++} + #endif +-#ifndef CONFIG_X86_NO_IDT +-#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) + ++#ifndef CONFIG_X86_NO_IDT + static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg) + { + __u32 a, b; +@@ -125,14 +138,6 @@ static inline void __set_tss_desc(unsign + } + #endif + +-static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int entries) +-{ +- __u32 a, b; +- pack_descriptor(&a, &b, (unsigned long)addr, +- entries * sizeof(struct desc_struct) - 1, +- DESCTYPE_LDT, 0); +- write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, a, b); +-} + + #define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr) + +@@ -163,36 +168,22 @@ static inline void set_ldt_desc(unsigned + + static inline void clear_LDT(void) + { +- int cpu = get_cpu(); +- +- /* +- * NB. We load the default_ldt for lcall7/27 handling on demand, as +- * it slows down context switching. Noone uses it anyway. +- */ +- cpu = cpu; /* XXX avoid compiler warning */ +- xen_set_ldt(NULL, 0); +- put_cpu(); ++ set_ldt(NULL, 0); + } + + /* + * load one particular LDT into the current CPU + */ +-static inline void load_LDT_nolock(mm_context_t *pc, int cpu) ++static inline void load_LDT_nolock(mm_context_t *pc) + { +- void *segments = pc->ldt; +- int count = pc->size; +- +- if (likely(!count)) +- segments = NULL; +- +- xen_set_ldt(segments, count); ++ set_ldt(pc->ldt, pc->size); + } + + static inline void load_LDT(mm_context_t *pc) + { +- int cpu = get_cpu(); +- load_LDT_nolock(pc, cpu); +- put_cpu(); ++ preempt_disable(); ++ load_LDT_nolock(pc); ++ preempt_enable(); + } + + static inline unsigned long get_desc_base(unsigned long *desc) +@@ -204,6 +195,29 @@ static inline unsigned long get_desc_bas + return base; + } + ++#else /* __ASSEMBLY__ */ ++ ++/* ++ * GET_DESC_BASE reads the descriptor base of the specified segment. ++ * ++ * Args: ++ * idx - descriptor index ++ * gdt - GDT pointer ++ * base - 32bit register to which the base will be written ++ * lo_w - lo word of the "base" register ++ * lo_b - lo byte of the "base" register ++ * hi_b - hi byte of the low word of the "base" register ++ * ++ * Example: ++ * GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah) ++ * Will read the base address of GDT_ENTRY_ESPFIX_SS and put it into %eax. ++ */ ++#define GET_DESC_BASE(idx, gdt, base, lo_w, lo_b, hi_b) \ ++ movb idx*8+4(gdt), lo_b; \ ++ movb idx*8+7(gdt), hi_b; \ ++ shll $16, base; \ ++ movw idx*8+2(gdt), lo_w; ++ + #endif /* !__ASSEMBLY__ */ + + #endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/dma-mapping_32.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/dma-mapping_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -127,10 +127,10 @@ dma_get_cache_alignment(void) + return (1 << INTERNODE_CACHE_SHIFT); + } + +-#define dma_is_consistent(d) (1) ++#define dma_is_consistent(d, h) (1) + + static inline void +-dma_cache_sync(void *vaddr, size_t size, ++dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) + { + flush_write_buffers(); +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/fixmap_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/fixmap_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -13,13 +13,16 @@ + #ifndef _ASM_FIXMAP_H + #define _ASM_FIXMAP_H + +- + /* used by vmalloc.c, vsyscall.lds.S. + * + * Leave one empty page between vmalloc'ed areas and + * the start of the fixmap. + */ + extern unsigned long __FIXADDR_TOP; ++#ifdef CONFIG_COMPAT_VDSO ++#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO) ++#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1) ++#endif + + #ifndef __ASSEMBLY__ + #include +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/highmem.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/highmem.h 2008-12-15 11:26:44.000000000 +0100 +@@ -85,7 +85,7 @@ static inline void clear_user_highpage(s + + void copy_highpage(struct page *to, struct page *from); + static inline void copy_user_highpage(struct page *to, struct page *from, +- unsigned long vaddr) ++ unsigned long vaddr, struct vm_area_struct *vma) + { + copy_highpage(to, from); + } +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/hypervisor.h 2008-12-15 11:26:44.000000000 +0100 +@@ -46,15 +46,6 @@ + #include + #include + #include +-#if defined(__i386__) +-# ifdef CONFIG_X86_PAE +-# include +-# else +-# include +-# endif +-#elif defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) +-# include +-#endif + + extern shared_info_t *HYPERVISOR_shared_info; + +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/irqflags_32.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/irqflags_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -22,9 +22,6 @@ + + #define __raw_local_save_flags() (current_vcpu_info()->evtchn_upcall_mask) + +-#define raw_local_save_flags(flags) \ +- do { (flags) = __raw_local_save_flags(); } while (0) +- + #define raw_local_irq_restore(x) \ + do { \ + vcpu_info_t *_vcpu; \ +@@ -66,18 +63,6 @@ void raw_safe_halt(void); + */ + void halt(void); + +-static inline int raw_irqs_disabled_flags(unsigned long flags) +-{ +- return (flags != 0); +-} +- +-#define raw_irqs_disabled() \ +-({ \ +- unsigned long flags = __raw_local_save_flags(); \ +- \ +- raw_irqs_disabled_flags(flags); \ +-}) +- + /* + * For spinlocks, etc: + */ +@@ -90,9 +75,62 @@ static inline int raw_irqs_disabled_flag + flags; \ + }) + ++#else ++/* Offsets into shared_info_t. */ ++#define evtchn_upcall_pending /* 0 */ ++#define evtchn_upcall_mask 1 ++ ++#define sizeof_vcpu_shift 6 ++ ++#ifdef CONFIG_SMP ++#define GET_VCPU_INFO movl TI_cpu(%ebp),%esi ; \ ++ shl $sizeof_vcpu_shift,%esi ; \ ++ addl HYPERVISOR_shared_info,%esi ++#else ++#define GET_VCPU_INFO movl HYPERVISOR_shared_info,%esi ++#endif ++ ++#define __DISABLE_INTERRUPTS movb $1,evtchn_upcall_mask(%esi) ++#define __ENABLE_INTERRUPTS movb $0,evtchn_upcall_mask(%esi) ++#define __TEST_PENDING testb $0xFF,evtchn_upcall_pending(%esi) ++#define DISABLE_INTERRUPTS(clb) GET_VCPU_INFO ; \ ++ __DISABLE_INTERRUPTS ++#define ENABLE_INTERRUPTS(clb) GET_VCPU_INFO ; \ ++ __ENABLE_INTERRUPTS ++#define ENABLE_INTERRUPTS_SYSEXIT __ENABLE_INTERRUPTS ; \ ++sysexit_scrit: /**** START OF SYSEXIT CRITICAL REGION ****/ ; \ ++ __TEST_PENDING ; \ ++ jnz 14f /* process more events if necessary... */ ; \ ++ movl PT_ESI(%esp), %esi ; \ ++ sysexit ; \ ++14: __DISABLE_INTERRUPTS ; \ ++ TRACE_IRQS_OFF ; \ ++sysexit_ecrit: /**** END OF SYSEXIT CRITICAL REGION ****/ ; \ ++ push %esp ; \ ++ call evtchn_do_upcall ; \ ++ add $4,%esp ; \ ++ jmp ret_from_intr ++#define INTERRUPT_RETURN iret ++#endif /* __ASSEMBLY__ */ ++ ++#ifndef __ASSEMBLY__ ++#define raw_local_save_flags(flags) \ ++ do { (flags) = __raw_local_save_flags(); } while (0) ++ + #define raw_local_irq_save(flags) \ + do { (flags) = __raw_local_irq_save(); } while (0) + ++static inline int raw_irqs_disabled_flags(unsigned long flags) ++{ ++ return (flags != 0); ++} ++ ++#define raw_irqs_disabled() \ ++({ \ ++ unsigned long flags = __raw_local_save_flags(); \ ++ \ ++ raw_irqs_disabled_flags(flags); \ ++}) + #endif /* __ASSEMBLY__ */ + + /* +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/mmu_context_32.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/mmu_context_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -27,14 +27,13 @@ static inline void enter_lazy_tlb(struct + static inline void __prepare_arch_switch(void) + { + /* +- * Save away %fs and %gs. No need to save %es and %ds, as those +- * are always kernel segments while inside the kernel. Must +- * happen before reload of cr3/ldt (i.e., not in __switch_to). ++ * Save away %fs. No need to save %gs, as it was saved on the ++ * stack on entry. No need to save %es and %ds, as those are ++ * always kernel segments while inside the kernel. + */ +- asm volatile ( "mov %%fs,%0 ; mov %%gs,%1" +- : "=m" (current->thread.fs), +- "=m" (current->thread.gs)); +- asm volatile ( "movl %0,%%fs ; movl %0,%%gs" ++ asm volatile ( "mov %%fs,%0" ++ : "=m" (current->thread.fs)); ++ asm volatile ( "movl %0,%%fs" + : : "r" (0) ); + } + +@@ -89,14 +88,14 @@ static inline void switch_mm(struct mm_s + * tlb flush IPI delivery. We must reload %cr3. + */ + load_cr3(next->pgd); +- load_LDT_nolock(&next->context, cpu); ++ load_LDT_nolock(&next->context); + } + } + #endif + } + +-#define deactivate_mm(tsk, mm) \ +- asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0)) ++#define deactivate_mm(tsk, mm) \ ++ asm("movl %0,%%fs": :"r" (0)); + + static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) + { +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pgtable-3level.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgtable-3level.h 2008-12-15 11:26:44.000000000 +0100 +@@ -1,8 +1,6 @@ + #ifndef _I386_PGTABLE_3LEVEL_H + #define _I386_PGTABLE_3LEVEL_H + +-#include +- + /* + * Intel Physical Address Extension (PAE) Mode - three-level page + * tables on PPro+ CPUs. +@@ -75,6 +73,23 @@ static inline void set_pte(pte_t *ptep, + xen_l3_entry_update((pudptr), (pudval)) + + /* ++ * For PTEs and PDEs, we must clear the P-bit first when clearing a page table ++ * entry, so clear the bottom half first and enforce ordering with a compiler ++ * barrier. ++ */ ++static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ if ((mm != current->mm && mm != &init_mm) ++ || HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { ++ ptep->pte_low = 0; ++ smp_wmb(); ++ ptep->pte_high = 0; ++ } ++} ++ ++#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) ++ ++/* + * Pentium-II erratum A13: in PAE mode we explicitly have to flush + * the TLB via cr3 if the top-level pgd is changed... + * We do not let the generic code free and clear pgd entries due to +@@ -93,45 +108,16 @@ static inline void pud_clear (pud_t * pu + #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \ + pmd_index(address)) + +-static inline int pte_none(pte_t pte) +-{ +- return !(pte.pte_low | pte.pte_high); +-} +- +-/* +- * For PTEs and PDEs, we must clear the P-bit first when clearing a page table +- * entry, so clear the bottom half first and enforce ordering with a compiler +- * barrier. +- */ +-static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++static inline pte_t raw_ptep_get_and_clear(pte_t *ptep, pte_t res) + { +- if ((mm != current->mm && mm != &init_mm) +- || HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { +- ptep->pte_low = 0; +- smp_wmb(); ++ uint64_t val = __pte_val(res); ++ if (__cmpxchg64(ptep, val, 0) != val) { ++ /* xchg acts as a barrier before the setting of the high bits */ ++ res.pte_low = xchg(&ptep->pte_low, 0); ++ res.pte_high = ptep->pte_high; + ptep->pte_high = 0; + } +-} +- +-#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) +- +-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +-static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) +-{ +- pte_t pte = *ptep; +- if (!pte_none(pte)) { +- if ((mm != &init_mm) || +- HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { +- uint64_t val = __pte_val(pte); +- if (__cmpxchg64(ptep, val, 0) != val) { +- /* xchg acts as a barrier before the setting of the high bits */ +- pte.pte_low = xchg(&ptep->pte_low, 0); +- pte.pte_high = ptep->pte_high; +- ptep->pte_high = 0; +- } +- } +- } +- return pte; ++ return res; + } + + #define __HAVE_ARCH_PTEP_CLEAR_FLUSH +@@ -160,6 +146,11 @@ static inline int pte_same(pte_t a, pte_ + + #define pte_page(x) pfn_to_page(pte_pfn(x)) + ++static inline int pte_none(pte_t pte) ++{ ++ return !(pte.pte_low | pte.pte_high); ++} ++ + #define __pte_mfn(_pte) (((_pte).pte_low >> PAGE_SHIFT) | \ + ((_pte).pte_high << (32-PAGE_SHIFT))) + #define pte_mfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -38,14 +38,14 @@ struct vm_area_struct; + #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + extern unsigned long empty_zero_page[1024]; + extern pgd_t *swapper_pg_dir; +-extern kmem_cache_t *pgd_cache; +-extern kmem_cache_t *pmd_cache; ++extern struct kmem_cache *pgd_cache; ++extern struct kmem_cache *pmd_cache; + extern spinlock_t pgd_lock; + extern struct page *pgd_list; + +-void pmd_ctor(void *, kmem_cache_t *, unsigned long); +-void pgd_ctor(void *, kmem_cache_t *, unsigned long); +-void pgd_dtor(void *, kmem_cache_t *, unsigned long); ++void pmd_ctor(void *, struct kmem_cache *, unsigned long); ++void pgd_ctor(void *, struct kmem_cache *, unsigned long); ++void pgd_dtor(void *, struct kmem_cache *, unsigned long); + void pgtable_cache_init(void); + void paging_init(void); + +@@ -276,7 +276,6 @@ static inline pte_t pte_mkhuge(pte_t pte + #define pte_update(mm, addr, ptep) do { } while (0) + #define pte_update_defer(mm, addr, ptep) do { } while (0) + +- + /* + * We only update the dirty/accessed state if we set + * the dirty bit by hand in the kernel, since the hardware +@@ -342,6 +341,19 @@ do { \ + __young; \ + }) + ++#define __HAVE_ARCH_PTEP_GET_AND_CLEAR ++static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++{ ++ pte_t pte = *ptep; ++ if (!pte_none(pte) ++ && (mm != &init_mm ++ || HYPERVISOR_update_va_mapping(addr, __pte(0), 0))) { ++ pte = raw_ptep_get_and_clear(ptep, pte); ++ pte_update(mm, addr, ptep); ++ } ++ return pte; ++} ++ + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL + #define ptep_get_and_clear_full(mm, addr, ptep, full) \ + ((full) ? ({ \ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/processor_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/processor_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + + /* flag for disabling the tsc */ +@@ -73,6 +74,7 @@ struct cpuinfo_x86 { + #endif + unsigned char x86_max_cores; /* cpuid returned max cores value */ + unsigned char apicid; ++ unsigned short x86_clflush_size; + #ifdef CONFIG_SMP + unsigned char booted_cores; /* number of cores as seen by OS */ + __u8 phys_proc_id; /* Physical processor id. */ +@@ -114,6 +116,8 @@ extern struct cpuinfo_x86 cpu_data[]; + extern int cpu_llc_id[NR_CPUS]; + extern char ignore_fpu_irq; + ++void __init cpu_detect(struct cpuinfo_x86 *c); ++ + extern void identify_cpu(struct cpuinfo_x86 *); + extern void print_cpu_info(struct cpuinfo_x86 *); + extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); +@@ -146,8 +150,8 @@ static inline void detect_ht(struct cpui + #define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ + #define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ + +-static inline void __cpuid(unsigned int *eax, unsigned int *ebx, +- unsigned int *ecx, unsigned int *edx) ++static inline fastcall void xen_cpuid(unsigned int *eax, unsigned int *ebx, ++ unsigned int *ecx, unsigned int *edx) + { + /* ecx is often an input as well as an output. */ + __asm__(XEN_CPUID +@@ -158,59 +162,6 @@ static inline void __cpuid(unsigned int + : "0" (*eax), "2" (*ecx)); + } + +-/* +- * Generic CPUID function +- * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx +- * resulting in stale register contents being returned. +- */ +-static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) +-{ +- *eax = op; +- *ecx = 0; +- __cpuid(eax, ebx, ecx, edx); +-} +- +-/* Some CPUID calls want 'count' to be placed in ecx */ +-static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, +- int *edx) +-{ +- *eax = op; +- *ecx = count; +- __cpuid(eax, ebx, ecx, edx); +-} +- +-/* +- * CPUID functions returning a single datum +- */ +-static inline unsigned int cpuid_eax(unsigned int op) +-{ +- unsigned int eax, ebx, ecx, edx; +- +- cpuid(op, &eax, &ebx, &ecx, &edx); +- return eax; +-} +-static inline unsigned int cpuid_ebx(unsigned int op) +-{ +- unsigned int eax, ebx, ecx, edx; +- +- cpuid(op, &eax, &ebx, &ecx, &edx); +- return ebx; +-} +-static inline unsigned int cpuid_ecx(unsigned int op) +-{ +- unsigned int eax, ebx, ecx, edx; +- +- cpuid(op, &eax, &ebx, &ecx, &edx); +- return ecx; +-} +-static inline unsigned int cpuid_edx(unsigned int op) +-{ +- unsigned int eax, ebx, ecx, edx; +- +- cpuid(op, &eax, &ebx, &ecx, &edx); +- return edx; +-} +- + #define load_cr3(pgdir) write_cr3(__pa(pgdir)) + + /* +@@ -480,9 +431,9 @@ struct thread_struct { + .vm86_info = NULL, \ + .sysenter_cs = __KERNEL_CS, \ + .io_bitmap_ptr = NULL, \ ++ .gs = __KERNEL_PDA, \ + } + +-#ifndef CONFIG_X86_NO_TSS + /* + * Note that the .io_bitmap member must be extra-big. This is because + * the CPU will access an additional byte beyond the end of the IO +@@ -497,26 +448,9 @@ struct thread_struct { + .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \ + } + +-static inline void __load_esp0(struct tss_struct *tss, struct thread_struct *thread) +-{ +- tss->esp0 = thread->esp0; +- /* This can only happen when SEP is enabled, no need to test "SEP"arately */ +- if (unlikely(tss->ss1 != thread->sysenter_cs)) { +- tss->ss1 = thread->sysenter_cs; +- wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); +- } +-} +-#define load_esp0(tss, thread) \ +- __load_esp0(tss, thread) +-#else +-#define load_esp0(tss, thread) do { \ +- if (HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0)) \ +- BUG(); \ +-} while (0) +-#endif +- + #define start_thread(regs, new_eip, new_esp) do { \ +- __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \ ++ __asm__("movl %0,%%fs": :"r" (0)); \ ++ regs->xgs = 0; \ + set_fs(USER_DS); \ + regs->xds = __USER_DS; \ + regs->xes = __USER_DS; \ +@@ -526,26 +460,6 @@ static inline void __load_esp0(struct ts + regs->esp = new_esp; \ + } while (0) + +-/* +- * These special macros can be used to get or set a debugging register +- */ +-#define get_debugreg(var, register) \ +- (var) = HYPERVISOR_get_debugreg((register)) +-#define set_debugreg(value, register) \ +- WARN_ON(HYPERVISOR_set_debugreg((register), (value))) +- +-/* +- * Set IOPL bits in EFLAGS from given mask +- */ +-static inline void set_iopl_mask(unsigned mask) +-{ +- struct physdev_set_iopl set_iopl; +- +- /* Force the change at ring 0. */ +- set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3; +- WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl)); +-} +- + /* Forward declaration, a strange C thing */ + struct task_struct; + struct mm_struct; +@@ -637,6 +551,105 @@ static inline void rep_nop(void) + + #define cpu_relax() rep_nop() + ++#define paravirt_enabled() 0 ++#define __cpuid xen_cpuid ++ ++#ifndef CONFIG_X86_NO_TSS ++static inline void __load_esp0(struct tss_struct *tss, struct thread_struct *thread) ++{ ++ tss->esp0 = thread->esp0; ++ /* This can only happen when SEP is enabled, no need to test "SEP"arately */ ++ if (unlikely(tss->ss1 != thread->sysenter_cs)) { ++ tss->ss1 = thread->sysenter_cs; ++ wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); ++ } ++} ++#define load_esp0(tss, thread) \ ++ __load_esp0(tss, thread) ++#else ++#define load_esp0(tss, thread) do { \ ++ if (HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0)) \ ++ BUG(); \ ++} while (0) ++#endif ++ ++ ++/* ++ * These special macros can be used to get or set a debugging register ++ */ ++#define get_debugreg(var, register) \ ++ (var) = HYPERVISOR_get_debugreg(register) ++#define set_debugreg(value, register) \ ++ WARN_ON(HYPERVISOR_set_debugreg(register, value)) ++ ++#define set_iopl_mask xen_set_iopl_mask ++ ++/* ++ * Set IOPL bits in EFLAGS from given mask ++ */ ++static inline void xen_set_iopl_mask(unsigned mask) ++{ ++ struct physdev_set_iopl set_iopl; ++ ++ /* Force the change at ring 0. */ ++ set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3; ++ WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl)); ++} ++ ++ ++/* ++ * Generic CPUID function ++ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx ++ * resulting in stale register contents being returned. ++ */ ++static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) ++{ ++ *eax = op; ++ *ecx = 0; ++ __cpuid(eax, ebx, ecx, edx); ++} ++ ++/* Some CPUID calls want 'count' to be placed in ecx */ ++static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, ++ int *edx) ++{ ++ *eax = op; ++ *ecx = count; ++ __cpuid(eax, ebx, ecx, edx); ++} ++ ++/* ++ * CPUID functions returning a single datum ++ */ ++static inline unsigned int cpuid_eax(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return eax; ++} ++static inline unsigned int cpuid_ebx(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return ebx; ++} ++static inline unsigned int cpuid_ecx(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return ecx; ++} ++static inline unsigned int cpuid_edx(unsigned int op) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ cpuid(op, &eax, &ebx, &ecx, &edx); ++ return edx; ++} ++ + /* generic versions from gas */ + #define GENERIC_NOP1 ".byte 0x90\n" + #define GENERIC_NOP2 ".byte 0x89,0xf6\n" +@@ -736,4 +749,8 @@ extern unsigned long boot_option_idle_ov + extern void enable_sep_cpu(void); + extern int sysenter_setup(void); + ++extern int init_gdt(int cpu, struct task_struct *idle); ++extern void cpu_set_gdt(int); ++extern void secondary_cpu_init(void); ++ + #endif /* __ASM_I386_PROCESSOR_H */ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/segment_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/segment_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -39,7 +39,7 @@ + * 25 - APM BIOS support + * + * 26 - ESPFIX small SS +- * 27 - unused ++ * 27 - PDA [ per-cpu private data area ] + * 28 - unused + * 29 - unused + * 30 - unused +@@ -74,6 +74,9 @@ + #define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14) + #define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8) + ++#define GDT_ENTRY_PDA (GDT_ENTRY_KERNEL_BASE + 15) ++#define __KERNEL_PDA (GDT_ENTRY_PDA * 8) ++ + #define GDT_ENTRY_DOUBLEFAULT_TSS 31 + + /* +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/smp_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/smp_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #endif + + #ifdef CONFIG_X86_LOCAL_APIC +@@ -56,7 +57,7 @@ extern void cpu_uninit(void); + * from the initial startup. We map APIC_BASE very early in page_setup(), + * so this is correct in the x86 case. + */ +-#define raw_smp_processor_id() (current_thread_info()->cpu) ++#define raw_smp_processor_id() (read_pda(cpu_number)) + + extern cpumask_t cpu_possible_map; + #define cpu_callin_map cpu_possible_map +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/system_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/system_32.h 2008-12-15 11:26:44.000000000 +0100 +@@ -139,17 +139,17 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" + #define write_cr4(x) \ + __asm__ __volatile__("movl %0,%%cr4": :"r" (x)) + +-/* +- * Clear and set 'TS' bit respectively +- */ ++#define wbinvd() \ ++ __asm__ __volatile__ ("wbinvd": : :"memory") ++ ++/* Clear the 'TS' bit */ + #define clts() (HYPERVISOR_fpu_taskswitch(0)) ++ ++/* Set the 'TS' bit */ + #define stts() (HYPERVISOR_fpu_taskswitch(1)) + + #endif /* __KERNEL__ */ + +-#define wbinvd() \ +- __asm__ __volatile__ ("wbinvd": : :"memory") +- + static inline unsigned long get_limit(unsigned long segment) + { + unsigned long __limit; +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/desc_64.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/desc_64.h 2008-12-15 11:26:44.000000000 +0100 +@@ -9,62 +9,11 @@ + + #include + #include ++#include + + #include + #include + +-// 8 byte segment descriptor +-struct desc_struct { +- u16 limit0; +- u16 base0; +- unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1; +- unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8; +-} __attribute__((packed)); +- +-struct n_desc_struct { +- unsigned int a,b; +-}; +- +-enum { +- GATE_INTERRUPT = 0xE, +- GATE_TRAP = 0xF, +- GATE_CALL = 0xC, +-}; +- +-// 16byte gate +-struct gate_struct { +- u16 offset_low; +- u16 segment; +- unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; +- u16 offset_middle; +- u32 offset_high; +- u32 zero1; +-} __attribute__((packed)); +- +-#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF) +-#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF) +-#define PTR_HIGH(x) ((unsigned long)(x) >> 32) +- +-enum { +- DESC_TSS = 0x9, +- DESC_LDT = 0x2, +-}; +- +-// LDT or TSS descriptor in the GDT. 16 bytes. +-struct ldttss_desc { +- u16 limit0; +- u16 base0; +- unsigned base1 : 8, type : 5, dpl : 2, p : 1; +- unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8; +- u32 base3; +- u32 zero1; +-} __attribute__((packed)); +- +-struct desc_ptr { +- unsigned short size; +- unsigned long address; +-} __attribute__((packed)) ; +- + extern struct desc_ptr idt_descr, cpu_gdt_descr[NR_CPUS]; + + extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2008-12-15 11:26:44.000000000 +0100 +@@ -64,6 +64,9 @@ static inline int dma_mapping_error(dma_ + return (dma_addr == bad_dma_address); + } + ++#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) ++#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) ++ + extern void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp); + extern void dma_free_coherent(struct device *dev, size_t size, void *vaddr, +@@ -181,12 +184,13 @@ static inline int dma_get_cache_alignmen + return boot_cpu_data.x86_clflush_size; + } + +-#define dma_is_consistent(h) 1 ++#define dma_is_consistent(d, h) 1 + + extern int dma_set_mask(struct device *dev, u64 mask); + + static inline void +-dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction dir) ++dma_cache_sync(struct device *dev, void *vaddr, size_t size, ++ enum dma_data_direction dir) + { + flush_write_buffers(); + } +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:26:44.000000000 +0100 +@@ -237,19 +237,18 @@ extern unsigned int __kernel_page_user; + + static inline unsigned long pgd_bad(pgd_t pgd) + { +- unsigned long val = __pgd_val(pgd); +- val &= ~PTE_MASK; +- val &= ~(_PAGE_USER | _PAGE_DIRTY); +- return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED); ++ return __pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); + } + +-static inline unsigned long pud_bad(pud_t pud) +-{ +- unsigned long val = __pud_val(pud); +- val &= ~PTE_MASK; +- val &= ~(_PAGE_USER | _PAGE_DIRTY); +- return val & ~(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED); +-} ++static inline unsigned long pud_bad(pud_t pud) ++{ ++ return __pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); ++} ++ ++static inline unsigned long pmd_bad(pmd_t pmd) ++{ ++ return __pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); ++} + + #define set_pte_at(_mm,addr,ptep,pteval) do { \ + if (((_mm) != current->mm && (_mm) != &init_mm) || \ +@@ -404,8 +403,6 @@ static inline int pmd_large(pmd_t pte) { + #define pmd_present(x) (__pmd_val(x) & _PAGE_PRESENT) + #endif + #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) +-#define pmd_bad(x) ((__pmd_val(x) & ~(PTE_MASK | _PAGE_USER | _PAGE_PRESENT)) \ +- != (_KERNPG_TABLE & ~(_PAGE_USER | _PAGE_PRESENT))) + #define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot))) + #define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT) + +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/processor_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/processor_64.h 2008-12-15 11:26:44.000000000 +0100 +@@ -484,6 +484,14 @@ static inline void __mwait(unsigned long + : :"a" (eax), "c" (ecx)); + } + ++static inline void __sti_mwait(unsigned long eax, unsigned long ecx) ++{ ++ /* "mwait %eax,%ecx;" */ ++ asm volatile( ++ "sti; .byte 0x0f,0x01,0xc9;" ++ : :"a" (eax), "c" (ecx)); ++} ++ + extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx); + + #define stack_current() \ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/smp_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/smp_64.h 2008-12-15 11:26:44.000000000 +0100 +@@ -88,11 +88,6 @@ extern u8 x86_cpu_to_log_apicid[NR_CPUS] + extern u8 bios_cpu_apicid[]; + + #ifdef CONFIG_X86_LOCAL_APIC +-static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) +-{ +- return cpus_addr(cpumask)[0]; +-} +- + static inline int cpu_present_to_apicid(int mps_cpu) + { + if (mps_cpu < NR_CPUS) +@@ -127,13 +122,6 @@ static __inline int logical_smp_processo + #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] + #else + #define cpu_physical_id(cpu) boot_cpu_id +-static inline int smp_call_function_single(int cpuid, void (*func) (void *info), +- void *info, int retry, int wait) +-{ +- /* Disable interrupts here? */ +- func(info); +- return 0; +-} + #endif /* !CONFIG_SMP */ + #endif + +--- sle11-2009-06-29.orig/kernel/kexec.c 2009-02-17 11:27:16.000000000 +0100 ++++ sle11-2009-06-29/kernel/kexec.c 2009-02-17 11:34:22.000000000 +0100 +@@ -374,7 +374,7 @@ static struct page *kimage_alloc_pages(g + if (limit == ~0UL) + address_bits = BITS_PER_LONG; + else +- address_bits = long_log2(limit); ++ address_bits = ilog2(limit); + + if (xen_limit_pages_to_max_mfn(pages, order, address_bits) < 0) { + __free_pages(pages, order); +--- sle11-2009-06-29.orig/net/core/dev.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/net/core/dev.c 2008-12-15 11:26:44.000000000 +0100 +@@ -1751,10 +1751,10 @@ inline int skb_checksum_setup(struct sk_ + goto out; + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: +- skb->csum = offsetof(struct tcphdr, check); ++ skb->csum_offset = offsetof(struct tcphdr, check); + break; + case IPPROTO_UDP: +- skb->csum = offsetof(struct udphdr, check); ++ skb->csum_offset = offsetof(struct udphdr, check); + break; + default: + if (net_ratelimit()) +@@ -1763,7 +1763,7 @@ inline int skb_checksum_setup(struct sk_ + " %d packet", skb->nh.iph->protocol); + goto out; + } +- if ((skb->h.raw + skb->csum + 2) > skb->tail) ++ if ((skb->h.raw + skb->csum_offset + 2) > skb->tail) + goto out; + skb->ip_summed = CHECKSUM_PARTIAL; + skb->proto_csum_blank = 0; diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.21 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.21 new file mode 100644 index 000000000..68a7d4faa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.21 @@ -0,0 +1,4874 @@ +From: www.kernel.org +Subject: Linux 2.6.21 +Patch-mainline: 2.6.21 + +Automatically created from "patches.kernel.org/patch-2.6.21" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-05-14.orig/arch/x86/Kconfig 2009-02-05 10:22:19.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/Kconfig 2009-03-04 11:25:55.000000000 +0100 +@@ -50,13 +50,15 @@ config GENERIC_CMOS_UPDATE + + config CLOCKSOURCE_WATCHDOG + def_bool y ++ depends on !X86_XEN + + config GENERIC_CLOCKEVENTS + def_bool y ++ depends on !X86_XEN + + config GENERIC_CLOCKEVENTS_BROADCAST + def_bool y +- depends on X86_64 || (X86_32 && X86_LOCAL_APIC) ++ depends on X86_64 || (X86_32 && X86_LOCAL_APIC && !X86_XEN) + + config LOCKDEP_SUPPORT + def_bool y +--- sle11-2009-05-14.orig/arch/x86/kernel/Makefile 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/Makefile 2009-03-04 11:25:55.000000000 +0100 +@@ -124,7 +124,7 @@ ifeq ($(CONFIG_X86_64),y) + pci-dma_64-$(CONFIG_XEN) += pci-dma_32.o + endif + +-disabled-obj-$(CONFIG_XEN) := early-quirks.o i8253.o i8259_$(BITS).o reboot.o \ +- smpboot_$(BITS).o tsc_$(BITS).o ++disabled-obj-$(CONFIG_XEN) := early-quirks.o hpet.o i8253.o i8259_$(BITS).o reboot.o \ ++ smpboot_$(BITS).o tsc_$(BITS).o tsc_sync.o + disabled-obj-$(CONFIG_XEN_UNPRIVILEGED_GUEST) += mpparse_64.o + %/head_$(BITS).o %/head_$(BITS).s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) := +--- sle11-2009-05-14.orig/arch/x86/kernel/apic_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/apic_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -25,6 +25,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -56,83 +58,26 @@ static cpumask_t timer_bcast_ipi; + */ + + /* +- * Debug level ++ * Debug level, exported for io_apic.c + */ + int apic_verbosity; + + #ifndef CONFIG_XEN + static int modern_apic(void) + { +- unsigned int lvr, version; + /* AMD systems use old APIC versions, so check the CPU */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && +- boot_cpu_data.x86 >= 0xf) ++ boot_cpu_data.x86 >= 0xf) + return 1; +- lvr = apic_read(APIC_LVR); +- version = GET_APIC_VERSION(lvr); +- return version >= 0x14; ++ return lapic_get_version() >= 0x14; + } + #endif /* !CONFIG_XEN */ + +-/* +- * 'what should we do if we get a hw irq event on an illegal vector'. +- * each architecture has to answer this themselves. +- */ +-void ack_bad_irq(unsigned int irq) +-{ +- printk("unexpected IRQ trap at vector %02x\n", irq); +- /* +- * Currently unexpected vectors happen only on SMP and APIC. +- * We _must_ ack these because every local APIC has only N +- * irq slots per priority level, and a 'hanging, unacked' IRQ +- * holds up an irq slot - in excessive cases (when multiple +- * unexpected vectors occur) that might lock up the APIC +- * completely. +- * But only ack when the APIC is enabled -AK +- */ +- if (cpu_has_apic) +- ack_APIC_irq(); +-} +- + int get_physical_broadcast(void) + { + return 0xff; + } + +-#ifndef CONFIG_XEN +-#ifndef CONFIG_SMP +-static void up_apic_timer_interrupt_call(void) +-{ +- int cpu = smp_processor_id(); +- +- /* +- * the NMI deadlock-detector uses this. +- */ +- per_cpu(irq_stat, cpu).apic_timer_irqs++; +- +- smp_local_timer_interrupt(); +-} +-#endif +- +-void smp_send_timer_broadcast_ipi(void) +-{ +- cpumask_t mask; +- +- cpus_and(mask, cpu_online_map, timer_bcast_ipi); +- if (!cpus_empty(mask)) { +-#ifdef CONFIG_SMP +- send_IPI_mask(mask, LOCAL_TIMER_VECTOR); +-#else +- /* +- * We can directly call the apic timer interrupt handler +- * in UP case. Minus all irq related functions +- */ +- up_apic_timer_interrupt_call(); +-#endif +- } +-} +-#endif +- + int setup_profiling_timer(unsigned int multiplier) + { + return -EINVAL; +--- sle11-2009-05-14.orig/arch/x86/kernel/cpu/common-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/cpu/common-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -610,7 +610,7 @@ void __init early_cpu_init(void) + struct pt_regs * __devinit idle_regs(struct pt_regs *regs) + { + memset(regs, 0, sizeof(struct pt_regs)); +- regs->xgs = __KERNEL_PDA; ++ regs->xfs = __KERNEL_PDA; + return regs; + } + +@@ -667,12 +667,12 @@ struct i386_pda boot_pda = { + .pcurrent = &init_task, + }; + +-static inline void set_kernel_gs(void) ++static inline void set_kernel_fs(void) + { +- /* Set %gs for this CPU's PDA. Memory clobber is to create a ++ /* Set %fs for this CPU's PDA. Memory clobber is to create a + barrier with respect to any PDA operations, so the compiler + doesn't move any before here. */ +- asm volatile ("mov %0, %%gs" : : "r" (__KERNEL_PDA) : "memory"); ++ asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory"); + } + + /* Initialize the CPU's GDT and PDA. The boot CPU does this for +@@ -730,7 +730,7 @@ void __cpuinit cpu_set_gdt(int cpu) + } + BUG_ON(HYPERVISOR_set_gdt(frames, (cpu_gdt_descr->size + 1) / 8)); + +- set_kernel_gs(); ++ set_kernel_fs(); + } + + /* Common CPU init for both boot and secondary CPUs */ +@@ -775,8 +775,8 @@ static void __cpuinit _cpu_init(int cpu, + __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); + #endif + +- /* Clear %fs. */ +- asm volatile ("mov %0, %%fs" : : "r" (0)); ++ /* Clear %gs. */ ++ asm volatile ("mov %0, %%gs" : : "r" (0)); + + /* Clear all 6 debug registers: */ + set_debugreg(0, 0); +--- sle11-2009-05-14.orig/arch/x86/kernel/e820_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/e820_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + + #ifdef CONFIG_EFI +@@ -157,21 +158,22 @@ static struct resource standard_io_resou + .flags = IORESOURCE_BUSY | IORESOURCE_IO + } }; + +-static int romsignature(const unsigned char *x) ++#define ROMSIGNATURE 0xaa55 ++ ++static int __init romsignature(const unsigned char *rom) + { + unsigned short sig; +- int ret = 0; +- if (probe_kernel_address((const unsigned short *)x, sig) == 0) +- ret = (sig == 0xaa55); +- return ret; ++ ++ return probe_kernel_address((const unsigned short *)rom, sig) == 0 && ++ sig == ROMSIGNATURE; + } + + static int __init romchecksum(unsigned char *rom, unsigned long length) + { +- unsigned char *p, sum = 0; ++ unsigned char sum; + +- for (p = rom; p < rom + length; p++) +- sum += *p; ++ for (sum = 0; length; length--) ++ sum += *rom++; + return sum == 0; + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:08:06.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:09:56.000000000 +0200 +@@ -30,7 +30,7 @@ + * 18(%esp) - %eax + * 1C(%esp) - %ds + * 20(%esp) - %es +- * 24(%esp) - %gs ++ * 24(%esp) - %fs + * 28(%esp) - orig_eax + * 2C(%esp) - %eip + * 30(%esp) - %cs +@@ -102,9 +102,9 @@ NMI_MASK = 0x80000000 + + #define SAVE_ALL \ + cld; \ +- pushl %gs; \ ++ pushl %fs; \ + CFI_ADJUST_CFA_OFFSET 4;\ +- /*CFI_REL_OFFSET gs, 0;*/\ ++ /*CFI_REL_OFFSET fs, 0;*/\ + pushl %es; \ + CFI_ADJUST_CFA_OFFSET 4;\ + /*CFI_REL_OFFSET es, 0;*/\ +@@ -136,7 +136,7 @@ NMI_MASK = 0x80000000 + movl %edx, %ds; \ + movl %edx, %es; \ + movl $(__KERNEL_PDA), %edx; \ +- movl %edx, %gs ++ movl %edx, %fs + + #define RESTORE_INT_REGS \ + popl %ebx; \ +@@ -169,9 +169,9 @@ NMI_MASK = 0x80000000 + 2: popl %es; \ + CFI_ADJUST_CFA_OFFSET -4;\ + /*CFI_RESTORE es;*/\ +-3: popl %gs; \ ++3: popl %fs; \ + CFI_ADJUST_CFA_OFFSET -4;\ +- /*CFI_RESTORE gs;*/\ ++ /*CFI_RESTORE fs;*/\ + .pushsection .fixup,"ax"; \ + 4: movl $0,(%esp); \ + jmp 1b; \ +@@ -230,6 +230,7 @@ ENTRY(ret_from_fork) + CFI_ADJUST_CFA_OFFSET -4 + jmp syscall_exit + CFI_ENDPROC ++END(ret_from_fork) + + /* + * Return to user mode is not as complex as all this looks, +@@ -261,6 +262,7 @@ ENTRY(resume_userspace) + # int/exception return? + jne work_pending + jmp restore_all ++END(ret_from_exception) + + #ifdef CONFIG_PREEMPT + ENTRY(resume_kernel) +@@ -275,6 +277,7 @@ need_resched: + jz restore_all + call preempt_schedule_irq + jmp need_resched ++END(resume_kernel) + #endif + CFI_ENDPROC + +@@ -352,16 +355,17 @@ sysenter_past_esp: + movl PT_OLDESP(%esp), %ecx + xorl %ebp,%ebp + TRACE_IRQS_ON +-1: mov PT_GS(%esp), %gs ++1: mov PT_FS(%esp), %fs + ENABLE_INTERRUPTS_SYSEXIT + CFI_ENDPROC + .pushsection .fixup,"ax" +-2: movl $0,PT_GS(%esp) ++2: movl $0,PT_FS(%esp) + jmp 1b + .section __ex_table,"a" + .align 4 + .long 1b,2b + .popsection ++ENDPROC(sysenter_entry) + + # pv sysenter call handler stub + ENTRY(sysenter_entry_pv) +@@ -533,6 +537,7 @@ hypervisor_iret: + jmp hypercall_page + (__HYPERVISOR_iret * 32) + #endif + CFI_ENDPROC ++ENDPROC(system_call) + + # perform work that needs to be done immediately before resumption + ALIGN +@@ -578,6 +583,7 @@ work_notifysig_v86: + xorl %edx, %edx + call do_notify_resume + jmp resume_userspace_sig ++END(work_pending) + + # perform syscall exit tracing + ALIGN +@@ -593,6 +599,7 @@ syscall_trace_entry: + cmpl $(nr_syscalls), %eax + jnae syscall_call + jmp syscall_exit ++END(syscall_trace_entry) + + # perform syscall exit tracing + ALIGN +@@ -606,6 +613,7 @@ syscall_exit_work: + movl $1, %edx + call do_syscall_trace + jmp resume_userspace ++END(syscall_exit_work) + CFI_ENDPROC + + RING0_INT_FRAME # can't unwind into user space anyway +@@ -616,16 +624,18 @@ syscall_fault: + GET_THREAD_INFO(%ebp) + movl $-EFAULT,PT_EAX(%esp) + jmp resume_userspace ++END(syscall_fault) + + syscall_badsys: + movl $-ENOSYS,PT_EAX(%esp) + jmp resume_userspace ++END(syscall_badsys) + CFI_ENDPROC + + #ifndef CONFIG_XEN + #define FIXUP_ESPFIX_STACK \ + /* since we are on a wrong stack, we cant make it a C code :( */ \ +- movl %gs:PDA_cpu, %ebx; \ ++ movl %fs:PDA_cpu, %ebx; \ + PER_CPU(cpu_gdt_descr, %ebx); \ + movl GDS_address(%ebx), %ebx; \ + GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ +@@ -656,9 +666,9 @@ syscall_badsys: + ENTRY(interrupt) + .text + +-vector=0 + ENTRY(irq_entries_start) + RING0_INT_FRAME ++vector=0 + .rept NR_IRQS + ALIGN + .if vector +@@ -667,11 +677,16 @@ ENTRY(irq_entries_start) + 1: pushl $~(vector) + CFI_ADJUST_CFA_OFFSET 4 + jmp common_interrupt +-.data ++ .previous + .long 1b +-.text ++ .text + vector=vector+1 + .endr ++END(irq_entries_start) ++ ++.previous ++END(interrupt) ++.previous + + /* + * the CPU automatically disables interrupts when executing an IRQ vector, +@@ -684,6 +699,7 @@ common_interrupt: + movl %esp,%eax + call do_IRQ + jmp ret_from_intr ++ENDPROC(common_interrupt) + CFI_ENDPROC + + #define BUILD_INTERRUPT(name, nr) \ +@@ -696,10 +712,16 @@ ENTRY(name) \ + movl %esp,%eax; \ + call smp_/**/name; \ + jmp ret_from_intr; \ +- CFI_ENDPROC ++ CFI_ENDPROC; \ ++ENDPROC(name) + + /* The include is where all of the SMP etc. interrupts come from */ + #include "entry_arch.h" ++ ++/* This alternate entry is needed because we hijack the apic LVTT */ ++#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC) ++BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR) ++#endif + #else + #define UNWIND_ESPFIX_STACK + #endif +@@ -710,7 +732,7 @@ KPROBE_ENTRY(page_fault) + CFI_ADJUST_CFA_OFFSET 4 + ALIGN + error_code: +- /* the function address is in %gs's slot on the stack */ ++ /* the function address is in %fs's slot on the stack */ + pushl %es + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET es, 0*/ +@@ -739,20 +761,20 @@ error_code: + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebx, 0 + cld +- pushl %gs ++ pushl %fs + CFI_ADJUST_CFA_OFFSET 4 +- /*CFI_REL_OFFSET gs, 0*/ ++ /*CFI_REL_OFFSET fs, 0*/ + movl $(__KERNEL_PDA), %ecx +- movl %ecx, %gs ++ movl %ecx, %fs + UNWIND_ESPFIX_STACK + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + /*CFI_REGISTER es, ecx*/ +- movl PT_GS(%esp), %edi # get the function address ++ movl PT_FS(%esp), %edi # get the function address + movl PT_ORIG_EAX(%esp), %edx # get the error code + movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart +- mov %ecx, PT_GS(%esp) +- /*CFI_REL_OFFSET gs, ES*/ ++ mov %ecx, PT_FS(%esp) ++ /*CFI_REL_OFFSET fs, ES*/ + movl $(__USER_DS), %ecx + movl %ecx, %ds + movl %ecx, %es +@@ -844,7 +866,7 @@ critical_fixup_table: + .byte 6 # pop %eax + .byte 7 # pop %ds + .byte 8 # pop %es +- .byte 9,9 # pop %gs ++ .byte 9,9 # pop %fs + .byte 10,10,10 # add $4,%esp + .byte 11 # iret + .byte -1,-1,-1,-1 # movb $1,1(%esi) = __DISABLE_INTERRUPTS +@@ -909,6 +931,7 @@ ENTRY(coprocessor_error) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(coprocessor_error) + + ENTRY(simd_coprocessor_error) + RING0_INT_FRAME +@@ -918,6 +941,7 @@ ENTRY(simd_coprocessor_error) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(simd_coprocessor_error) + + ENTRY(device_not_available) + RING0_INT_FRAME +@@ -940,6 +964,7 @@ device_available_emulate: + call math_state_restore + jmp ret_from_exception + CFI_ENDPROC ++END(device_not_available) + + #ifndef CONFIG_XEN + /* +@@ -1101,10 +1126,12 @@ ENTRY(native_iret) + .align 4 + .long 1b,iret_exc + .previous ++END(native_iret) + + ENTRY(native_irq_enable_sysexit) + sti + sysexit ++END(native_irq_enable_sysexit) + #endif + + KPROBE_ENTRY(int3) +@@ -1127,6 +1154,7 @@ ENTRY(overflow) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(overflow) + + ENTRY(bounds) + RING0_INT_FRAME +@@ -1136,6 +1164,7 @@ ENTRY(bounds) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(bounds) + + ENTRY(invalid_op) + RING0_INT_FRAME +@@ -1145,6 +1174,7 @@ ENTRY(invalid_op) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(invalid_op) + + ENTRY(coprocessor_segment_overrun) + RING0_INT_FRAME +@@ -1154,6 +1184,7 @@ ENTRY(coprocessor_segment_overrun) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(coprocessor_segment_overrun) + + ENTRY(invalid_TSS) + RING0_EC_FRAME +@@ -1161,6 +1192,7 @@ ENTRY(invalid_TSS) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(invalid_TSS) + + ENTRY(segment_not_present) + RING0_EC_FRAME +@@ -1168,6 +1200,7 @@ ENTRY(segment_not_present) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(segment_not_present) + + ENTRY(stack_segment) + RING0_EC_FRAME +@@ -1175,6 +1208,7 @@ ENTRY(stack_segment) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(stack_segment) + + KPROBE_ENTRY(general_protection) + RING0_EC_FRAME +@@ -1190,6 +1224,7 @@ ENTRY(alignment_check) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(alignment_check) + + ENTRY(divide_error) + RING0_INT_FRAME +@@ -1199,6 +1234,7 @@ ENTRY(divide_error) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(divide_error) + + #ifdef CONFIG_X86_MCE + ENTRY(machine_check) +@@ -1209,6 +1245,7 @@ ENTRY(machine_check) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(machine_check) + #endif + + #ifndef CONFIG_XEN +@@ -1228,6 +1265,7 @@ ENTRY(fixup_4gb_segment) + CFI_ADJUST_CFA_OFFSET 4 + jmp error_code + CFI_ENDPROC ++END(spurious_interrupt_bug) + + ENTRY(kernel_thread_helper) + pushl $0 # fake return address for unwinder +--- sle11-2009-05-14.orig/arch/x86/kernel/head_32-xen.S 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/head_32-xen.S 2009-03-04 11:25:55.000000000 +0100 +@@ -27,6 +27,7 @@ + #define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability + #define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id + ++.section .text.head,"ax",@progbits + #define VIRT_ENTRY_OFFSET 0x0 + .org VIRT_ENTRY_OFFSET + ENTRY(startup_32) +@@ -60,11 +61,11 @@ ENTRY(startup_32) + + movb $1,X86_HARD_MATH + +- xorl %eax,%eax # Clear FS +- movl %eax,%fs ++ xorl %eax,%eax # Clear GS ++ movl %eax,%gs + + movl $(__KERNEL_PDA),%eax +- mov %eax,%gs ++ mov %eax,%fs + + cld # gcc2 wants the direction flag cleared at all times + +@@ -75,7 +76,7 @@ ENTRY(startup_32) + * Point the GDT at this CPU's PDA. This will be + * cpu_gdt_table and boot_pda. + */ +-setup_pda: ++ENTRY(setup_pda) + /* get the PDA pointer */ + movl $boot_pda, %eax + +--- sle11-2009-05-14.orig/arch/x86/kernel/io_apic_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/io_apic_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -167,7 +167,7 @@ static inline void io_apic_write(unsigne + */ + static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) + { +- volatile struct io_apic *io_apic = io_apic_base(apic); ++ volatile struct io_apic __iomem *io_apic = io_apic_base(apic); + if (sis_apic_bug) + writel(reg, &io_apic->index); + writel(value, &io_apic->data); +@@ -392,7 +392,7 @@ static void set_ioapic_affinity_irq(unsi + break; + entry = irq_2_pin + entry->next; + } +- set_native_irq_info(irq, cpumask); ++ irq_desc[irq].affinity = cpumask; + spin_unlock_irqrestore(&ioapic_lock, flags); + } + +@@ -531,8 +531,8 @@ static void do_irq_balance(void) + package_index = CPU_TO_PACKAGEINDEX(i); + for (j = 0; j < NR_IRQS; j++) { + unsigned long value_now, delta; +- /* Is this an active IRQ? */ +- if (!irq_desc[j].action) ++ /* Is this an active IRQ or balancing disabled ? */ ++ if (!irq_desc[j].action || irq_balancing_disabled(j)) + continue; + if ( package_index == i ) + IRQ_DELTA(package_index,j) = 0; +@@ -785,7 +785,7 @@ failed: + return 0; + } + +-int __init irqbalance_disable(char *str) ++int __devinit irqbalance_disable(char *str) + { + irqbalance_disabled = 1; + return 1; +@@ -1329,11 +1329,9 @@ static void ioapic_register_intr(int irq + trigger == IOAPIC_LEVEL) + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_fasteoi_irq, "fasteoi"); +- else { +- irq_desc[irq].status |= IRQ_DELAYED_DISABLE; ++ else + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_edge_irq, "edge"); +- } + set_intr_gate(vector, interrupt[irq]); + } + #else +@@ -1407,7 +1405,6 @@ static void __init setup_IO_APIC_irqs(vo + } + spin_lock_irqsave(&ioapic_lock, flags); + __ioapic_write_entry(apic, pin, entry); +- set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + } + } +@@ -1638,7 +1635,7 @@ void /*__init*/ print_local_APIC(void * + v = apic_read(APIC_LVR); + printk(KERN_INFO "... APIC VERSION: %08x\n", v); + ver = GET_APIC_VERSION(v); +- maxlvt = get_maxlvt(); ++ maxlvt = lapic_get_maxlvt(); + + v = apic_read(APIC_TASKPRI); + printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); +@@ -1976,7 +1973,7 @@ static void __init setup_ioapic_ids_from + #endif + + #ifndef CONFIG_XEN +-static int no_timer_check __initdata; ++int no_timer_check __initdata; + + static int __init notimercheck(char *s) + { +@@ -2369,7 +2366,7 @@ static inline void __init check_timer(vo + + disable_8259A_irq(0); + set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq, +- "fasteio"); ++ "fasteoi"); + apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ + enable_8259A_irq(0); + +@@ -2662,7 +2659,7 @@ static void set_msi_irq_affinity(unsigne + msg.address_lo |= MSI_ADDR_DEST_ID(dest); + + write_msi_msg(irq, &msg); +- set_native_irq_info(irq, mask); ++ irq_desc[irq].affinity = mask; + } + #endif /* CONFIG_SMP */ + +@@ -2681,25 +2678,32 @@ static struct irq_chip msi_chip = { + .retrigger = ioapic_retrigger_irq, + }; + +-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) ++int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) + { + struct msi_msg msg; +- int ret; ++ int irq, ret; ++ irq = create_irq(); ++ if (irq < 0) ++ return irq; ++ ++ set_irq_msi(irq, desc); + ret = msi_compose_msg(dev, irq, &msg); +- if (ret < 0) ++ if (ret < 0) { ++ destroy_irq(irq); + return ret; ++ } + + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, + "edge"); + +- return 0; ++ return irq; + } + + void arch_teardown_msi_irq(unsigned int irq) + { +- return; ++ destroy_irq(irq); + } + + #endif /* CONFIG_PCI_MSI */ +@@ -2739,7 +2743,7 @@ static void set_ht_irq_affinity(unsigned + dest = cpu_mask_to_apicid(mask); + + target_ht_irq(irq, dest); +- set_native_irq_info(irq, mask); ++ irq_desc[irq].affinity = mask; + } + #endif + +@@ -2947,7 +2951,6 @@ int io_apic_set_pci_routing (int ioapic, + + spin_lock_irqsave(&ioapic_lock, flags); + __ioapic_write_entry(ioapic, pin, entry); +- set_native_irq_info(irq, TARGET_CPUS); + spin_unlock_irqrestore(&ioapic_lock, flags); + + return 0; +--- sle11-2009-05-14.orig/arch/x86/kernel/irq_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/irq_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -10,7 +10,6 @@ + * io_apic.c.) + */ + +-#include + #include + #include + #include +@@ -19,19 +18,34 @@ + #include + #include + ++#include ++#include ++ + DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; + EXPORT_PER_CPU_SYMBOL(irq_stat); + +-#ifndef CONFIG_X86_LOCAL_APIC + /* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves. + */ + void ack_bad_irq(unsigned int irq) + { +- printk("unexpected IRQ trap at vector %02x\n", irq); +-} ++ printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); ++ ++#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_XEN) ++ /* ++ * Currently unexpected vectors happen only on SMP and APIC. ++ * We _must_ ack these because every local APIC has only N ++ * irq slots per priority level, and a 'hanging, unacked' IRQ ++ * holds up an irq slot - in excessive cases (when multiple ++ * unexpected vectors occur) that might lock up the APIC ++ * completely. ++ * But only ack when the APIC is enabled -AK ++ */ ++ if (cpu_has_apic) ++ ack_APIC_irq(); + #endif ++} + + #ifdef CONFIG_4KSTACKS + /* +--- sle11-2009-05-14.orig/arch/x86/kernel/microcode-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/microcode-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -108,7 +108,7 @@ static ssize_t microcode_write (struct f + return ret; + } + +-static struct file_operations microcode_fops = { ++static const struct file_operations microcode_fops = { + .owner = THIS_MODULE, + .write = microcode_write, + .open = microcode_open, +--- sle11-2009-05-14.orig/arch/x86/kernel/mpparse_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/mpparse_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -1079,7 +1079,7 @@ int mp_register_gsi(u32 gsi, int trigger + static int gsi_to_irq[MAX_GSI_NUM]; + + /* Don't set up the ACPI SCI because it's already set up */ +- if (acpi_fadt.sci_int == gsi) ++ if (acpi_gbl_FADT.sci_interrupt == gsi) + return gsi; + + ioapic = mp_find_ioapic(gsi); +@@ -1136,7 +1136,7 @@ int mp_register_gsi(u32 gsi, int trigger + /* + * Don't assign IRQ used by ACPI SCI + */ +- if (gsi == acpi_fadt.sci_int) ++ if (gsi == acpi_gbl_FADT.sci_interrupt) + gsi = pci_irq++; + gsi_to_irq[irq] = gsi; + } else { +--- sle11-2009-05-14.orig/arch/x86/kernel/pci-dma-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/pci-dma-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -311,7 +311,7 @@ int dma_declare_coherent_memory(struct d + return DMA_MEMORY_IO; + + free1_out: +- kfree(dev->dma_mem->bitmap); ++ kfree(dev->dma_mem); + out: + if (mem_base) + iounmap(mem_base); +--- sle11-2009-05-14.orig/arch/x86/kernel/pcspeaker.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/pcspeaker.c 2009-03-04 11:25:55.000000000 +0100 +@@ -7,6 +7,11 @@ static __init int add_pcspkr(void) + struct platform_device *pd; + int ret; + ++#ifdef CONFIG_XEN ++ if (!is_initial_xendomain()) ++ return 0; ++#endif ++ + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; +--- sle11-2009-05-14.orig/arch/x86/kernel/process_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/process_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -160,6 +161,7 @@ void cpu_idle(void) + + /* endless idle loop with no priority at all */ + while (1) { ++ tick_nohz_stop_sched_tick(); + while (!need_resched()) { + void (*idle)(void); + +@@ -175,6 +177,7 @@ void cpu_idle(void) + __get_cpu_var(irq_stat).idle_timestamp = jiffies; + idle(); + } ++ tick_nohz_restart_sched_tick(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); +@@ -247,8 +250,8 @@ void show_regs(struct pt_regs * regs) + regs->eax,regs->ebx,regs->ecx,regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx", + regs->esi, regs->edi, regs->ebp); +- printk(" DS: %04x ES: %04x GS: %04x\n", +- 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xgs); ++ printk(" DS: %04x ES: %04x FS: %04x\n", ++ 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xfs); + + cr0 = read_cr0(); + cr2 = read_cr2(); +@@ -279,7 +282,7 @@ int kernel_thread(int (*fn)(void *), voi + + regs.xds = __USER_DS; + regs.xes = __USER_DS; +- regs.xgs = __KERNEL_PDA; ++ regs.xfs = __KERNEL_PDA; + regs.orig_eax = -1; + regs.eip = (unsigned long) kernel_thread_helper; + regs.xcs = __KERNEL_CS | get_kernel_rpl(); +@@ -356,7 +359,7 @@ int copy_thread(int nr, unsigned long cl + + p->thread.eip = (unsigned long) ret_from_fork; + +- savesegment(fs,p->thread.fs); ++ savesegment(gs,p->thread.gs); + + tsk = current; + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { +@@ -434,8 +437,8 @@ void dump_thread(struct pt_regs * regs, + dump->regs.eax = regs->eax; + dump->regs.ds = regs->xds; + dump->regs.es = regs->xes; +- savesegment(fs,dump->regs.fs); +- dump->regs.gs = regs->xgs; ++ dump->regs.fs = regs->xfs; ++ savesegment(gs,dump->regs.gs); + dump->regs.orig_eax = regs->orig_eax; + dump->regs.eip = regs->eip; + dump->regs.cs = regs->xcs; +@@ -637,16 +640,6 @@ struct task_struct fastcall * __switch_t + prefetch(&next->i387.fxsave); + + /* +- * Restore %fs if needed. +- * +- * Glibc normally makes %fs be zero. +- */ +- if (unlikely(next->fs)) +- loadsegment(fs, next->fs); +- +- write_pda(pcurrent, next_p); +- +- /* + * Now maybe handle debug registers + */ + if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) +@@ -654,6 +647,15 @@ struct task_struct fastcall * __switch_t + + disable_tsc(prev_p, next_p); + ++ /* ++ * Leave lazy mode, flushing any hypercalls made here. ++ * This must be done before restoring TLS segments so ++ * the GDT and LDT are properly updated, and must be ++ * done before math_state_restore, so the TS bit is up ++ * to date. ++ */ ++ arch_leave_lazy_cpu_mode(); ++ + /* If the task has used fpu the last 5 timeslices, just do a full + * restore of the math state immediately to avoid the trap; the + * chances of needing FPU soon are obviously high now +@@ -661,6 +663,14 @@ struct task_struct fastcall * __switch_t + if (next_p->fpu_counter > 5) + math_state_restore(); + ++ /* ++ * Restore %gs if needed (which is common) ++ */ ++ if (prev->gs | next->gs) ++ loadsegment(gs, next->gs); ++ ++ write_pda(pcurrent, next_p); ++ + return prev_p; + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/setup_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/setup_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -148,7 +147,7 @@ unsigned long saved_videomode; + #define RAMDISK_PROMPT_FLAG 0x8000 + #define RAMDISK_LOAD_FLAG 0x4000 + +-static char command_line[COMMAND_LINE_SIZE]; ++static char __initdata command_line[COMMAND_LINE_SIZE]; + + unsigned char __initdata boot_params[PARAM_SIZE]; + +@@ -647,8 +646,8 @@ void __init setup_arch(char **cmdline_p) + + if ((i = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) + i = COMMAND_LINE_SIZE; +- memcpy(saved_command_line, xen_start_info->cmd_line, i); +- saved_command_line[i - 1] = '\0'; ++ memcpy(boot_command_line, xen_start_info->cmd_line, i); ++ boot_command_line[i - 1] = '\0'; + parse_early_param(); + + if (user_defined_memmap) { +@@ -656,11 +655,19 @@ void __init setup_arch(char **cmdline_p) + print_memory_map("user"); + } + +- strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); ++ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); + *cmdline_p = command_line; + + max_low_pfn = setup_memory(); + ++#ifdef CONFIG_VMI ++ /* ++ * Must be after max_low_pfn is determined, and before kernel ++ * pagetables are setup. ++ */ ++ vmi_init(); ++#endif ++ + /* + * NOTE: before this point _nobody_ is allowed to allocate + * any memory using the bootmem allocator. Although the +@@ -823,7 +830,6 @@ void __init setup_arch(char **cmdline_p) + conswitchp = &dummy_con; + #endif + } +- tsc_init(); + } + + static int +@@ -833,31 +839,3 @@ xen_panic_event(struct notifier_block *t + /* we're never actually going to get here... */ + return NOTIFY_DONE; + } +- +-static __init int add_pcspkr(void) +-{ +- struct platform_device *pd; +- int ret; +- +- if (!is_initial_xendomain()) +- return 0; +- +- pd = platform_device_alloc("pcspkr", -1); +- if (!pd) +- return -ENOMEM; +- +- ret = platform_device_add(pd); +- if (ret) +- platform_device_put(pd); +- +- return ret; +-} +-device_initcall(add_pcspkr); +- +-/* +- * Local Variables: +- * mode:c +- * c-file-style:"k&r" +- * c-basic-offset:8 +- * End: +- */ +--- sle11-2009-05-14.orig/arch/x86/kernel/smp_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/smp_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -335,8 +335,7 @@ static void flush_tlb_others(cpumask_t c + /* + * i'm not happy about this global shared spinlock in the + * MM hot path, but we'll see how contended it is. +- * Temporarily this turns IRQs off, so that lockups are +- * detected by the NMI watchdog. ++ * AK: x86-64 has a faster method that could be ported. + */ + spin_lock(&tlbstate_lock); + +@@ -361,7 +360,7 @@ static void flush_tlb_others(cpumask_t c + + while (!cpus_empty(flush_cpumask)) + /* nothing. lockup detection does not belong here */ +- mb(); ++ cpu_relax(); + + flush_mm = NULL; + flush_va = 0; +--- sle11-2009-05-14.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:08:30.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/time_32-xen.c 2009-03-24 10:11:08.000000000 +0100 +@@ -51,6 +51,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -75,25 +76,17 @@ + #include + #include + +-#if defined (__i386__) +-#include ++#ifdef CONFIG_X86_32 + #include + DEFINE_SPINLOCK(i8253_lock); + EXPORT_SYMBOL(i8253_lock); +-#endif +- +-#define XEN_SHIFT 22 +- + int pit_latch_buggy; /* extern */ +- +-#if defined(__x86_64__) +-unsigned long vxtime_hz = PIT_TICK_RATE; +-struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */ ++#else + volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; +-struct timespec __xtime __section_xtime; +-struct timezone __sys_tz __section_sys_tz; + #endif + ++#define XEN_SHIFT 22 ++ + unsigned int cpu_khz; /* Detected as we calibrate the TSC */ + EXPORT_SYMBOL(cpu_khz); + +@@ -113,9 +106,6 @@ static DEFINE_PER_CPU(struct shadow_time + static struct timespec shadow_tv; + static u32 shadow_tv_version; + +-static struct timeval monotonic_tv; +-static spinlock_t monotonic_lock = SPIN_LOCK_UNLOCKED; +- + /* Keep track of last time we did processing/updating of jiffies and xtime. */ + static u64 processed_system_time; /* System time (ns) at last processing. */ + static DEFINE_PER_CPU(u64, processed_system_time); +@@ -228,7 +218,7 @@ static inline u64 scale_delta(u64 delta, + return product; + } + +-void init_cpu_khz(void) ++static void init_cpu_khz(void) + { + u64 __cpu_khz = 1000000ULL << 32; + struct vcpu_time_info *info = &vcpu_info(0)->time; +@@ -247,16 +237,6 @@ static u64 get_nsec_offset(struct shadow + return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift); + } + +-#ifdef CONFIG_X86_64 +-static unsigned long get_usec_offset(struct shadow_time_info *shadow) +-{ +- u64 now, delta; +- rdtscll(now); +- delta = now - shadow->tsc_timestamp; +- return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift); +-} +-#endif +- + static void __update_wallclock(time_t sec, long nsec) + { + long wtm_nsec, xtime_nsec; +@@ -369,139 +349,6 @@ void rtc_cmos_write(unsigned char val, u + } + EXPORT_SYMBOL(rtc_cmos_write); + +-#ifdef CONFIG_X86_64 +- +-/* +- * This version of gettimeofday has microsecond resolution +- * and better than microsecond precision on fast x86 machines with TSC. +- */ +-void do_gettimeofday(struct timeval *tv) +-{ +- unsigned long seq; +- unsigned long usec, sec; +- unsigned long flags; +- s64 nsec; +- unsigned int cpu; +- struct shadow_time_info *shadow; +- u32 local_time_version; +- +- cpu = get_cpu(); +- shadow = &per_cpu(shadow_time, cpu); +- +- do { +- local_time_version = shadow->version; +- seq = read_seqbegin(&xtime_lock); +- +- usec = get_usec_offset(shadow); +- +- sec = xtime.tv_sec; +- usec += (xtime.tv_nsec / NSEC_PER_USEC); +- +- nsec = shadow->system_timestamp - processed_system_time; +- __normalize_time(&sec, &nsec); +- usec += (long)nsec / NSEC_PER_USEC; +- +- if (unlikely(!time_values_up_to_date(cpu))) { +- /* +- * We may have blocked for a long time, +- * rendering our calculations invalid +- * (e.g. the time delta may have +- * overflowed). Detect that and recalculate +- * with fresh values. +- */ +- get_time_values_from_xen(cpu); +- continue; +- } +- } while (read_seqretry(&xtime_lock, seq) || +- (local_time_version != shadow->version)); +- +- put_cpu(); +- +- while (usec >= USEC_PER_SEC) { +- usec -= USEC_PER_SEC; +- sec++; +- } +- +- spin_lock_irqsave(&monotonic_lock, flags); +- if ((sec > monotonic_tv.tv_sec) || +- ((sec == monotonic_tv.tv_sec) && (usec > monotonic_tv.tv_usec))) +- { +- monotonic_tv.tv_sec = sec; +- monotonic_tv.tv_usec = usec; +- } else { +- sec = monotonic_tv.tv_sec; +- usec = monotonic_tv.tv_usec; +- } +- spin_unlock_irqrestore(&monotonic_lock, flags); +- +- tv->tv_sec = sec; +- tv->tv_usec = usec; +-} +- +-EXPORT_SYMBOL(do_gettimeofday); +- +-int do_settimeofday(struct timespec *tv) +-{ +- time_t sec; +- s64 nsec; +- unsigned int cpu; +- struct shadow_time_info *shadow; +- struct xen_platform_op op; +- +- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) +- return -EINVAL; +- +- cpu = get_cpu(); +- shadow = &per_cpu(shadow_time, cpu); +- +- write_seqlock_irq(&xtime_lock); +- +- /* +- * Ensure we don't get blocked for a long time so that our time delta +- * overflows. If that were to happen then our shadow time values would +- * be stale, so we can retry with fresh ones. +- */ +- for (;;) { +- nsec = tv->tv_nsec - get_nsec_offset(shadow); +- if (time_values_up_to_date(cpu)) +- break; +- get_time_values_from_xen(cpu); +- } +- sec = tv->tv_sec; +- __normalize_time(&sec, &nsec); +- +- if (is_initial_xendomain() && !independent_wallclock) { +- op.cmd = XENPF_settime; +- op.u.settime.secs = sec; +- op.u.settime.nsecs = nsec; +- op.u.settime.system_time = shadow->system_timestamp; +- WARN_ON(HYPERVISOR_platform_op(&op)); +- update_wallclock(); +- } else if (independent_wallclock) { +- nsec -= shadow->system_timestamp; +- __normalize_time(&sec, &nsec); +- __update_wallclock(sec, nsec); +- } +- ntp_clear(); +- +- /* Reset monotonic gettimeofday() timeval. */ +- spin_lock(&monotonic_lock); +- monotonic_tv.tv_sec = 0; +- monotonic_tv.tv_usec = 0; +- spin_unlock(&monotonic_lock); +- +- write_sequnlock_irq(&xtime_lock); +- +- put_cpu(); +- +- clock_was_set(); +- return 0; +-} +- +-EXPORT_SYMBOL(do_settimeofday); +- +-#endif +- + static void sync_xen_wallclock(unsigned long dummy); + static DEFINE_TIMER(sync_xen_wallclock_timer, sync_xen_wallclock, 0, 0); + static void sync_xen_wallclock(unsigned long dummy) +@@ -550,15 +397,7 @@ static int set_rtc_mmss(unsigned long no + return retval; + } + +-#ifdef CONFIG_X86_64 +-/* monotonic_clock(): returns # of nanoseconds passed since time_init() +- * Note: This function is required to return accurate +- * time even in the absence of multiple timer ticks. +- */ +-unsigned long long monotonic_clock(void) +-#else + unsigned long long sched_clock(void) +-#endif + { + unsigned int cpu = get_cpu(); + struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); +@@ -578,21 +417,18 @@ unsigned long long sched_clock(void) + + return time; + } +-#ifdef CONFIG_X86_64 +-EXPORT_SYMBOL(monotonic_clock); +- +-unsigned long long sched_clock(void) +-{ +- return monotonic_clock(); +-} +-#endif + + unsigned long profile_pc(struct pt_regs *regs) + { + unsigned long pc = instruction_pointer(regs); + + #if defined(CONFIG_SMP) || defined(__x86_64__) +- if (!user_mode_vm(regs) && in_lock_functions(pc)) { ++# ifdef __i386__ ++ if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->xcs) ++# else ++ if (!user_mode(regs) ++# endif ++ && in_lock_functions(pc)) { + # ifdef CONFIG_FRAME_POINTER + # ifdef __i386__ + return ((unsigned long *)regs->ebp)[1]; +@@ -601,14 +437,11 @@ unsigned long profile_pc(struct pt_regs + # endif + # else + # ifdef __i386__ +- unsigned long *sp; +- if ((regs->xcs & 2) == 0) +- sp = (unsigned long *)®s->esp; +- else +- sp = (unsigned long *)regs->esp; ++ unsigned long *sp = (unsigned long *)®s->esp; + # else + unsigned long *sp = (unsigned long *)regs->rsp; + # endif ++ + /* Return address is either directly at stack pointer + or above a saved eflags. Eflags has bits 22-31 zero, + kernel addresses don't. */ +@@ -761,19 +594,6 @@ irqreturn_t timer_interrupt(int irq, voi + return IRQ_HANDLED; + } + +-#ifndef CONFIG_X86_64 +- +-void tsc_init(void) +-{ +- init_cpu_khz(); +- printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", +- cpu_khz / 1000, cpu_khz % 1000); +- +- use_tsc_delay(); +-} +- +-#include +- + void mark_tsc_unstable(void) + { + #ifndef CONFIG_XEN /* XXX Should tell the hypervisor about this fact. */ +@@ -829,21 +649,9 @@ static struct clocksource clocksource_xe + .mask = CLOCKSOURCE_MASK(64), + .mult = 1 << XEN_SHIFT, /* time directly in nanoseconds */ + .shift = XEN_SHIFT, +- .is_continuous = 1, ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }; + +-static int __init init_xen_clocksource(void) +-{ +- clocksource_xen.mult = clocksource_khz2mult(cpu_khz, +- clocksource_xen.shift); +- +- return clocksource_register(&clocksource_xen); +-} +- +-module_init(init_xen_clocksource); +- +-#endif +- + static void init_missing_ticks_accounting(unsigned int cpu) + { + struct vcpu_register_runstate_memory_area area; +@@ -864,7 +672,7 @@ static void init_missing_ticks_accountin + } + + /* not static: needed by APM */ +-unsigned long get_cmos_time(void) ++unsigned long read_persistent_clock(void) + { + unsigned long retval; + unsigned long flags; +@@ -877,11 +685,11 @@ unsigned long get_cmos_time(void) + + return retval; + } +-EXPORT_SYMBOL(get_cmos_time); + + static void sync_cmos_clock(unsigned long dummy); + + static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); ++int no_sync_cmos_clock; + + static void sync_cmos_clock(unsigned long dummy) + { +@@ -925,7 +733,8 @@ static void sync_cmos_clock(unsigned lon + + void notify_arch_cmos_timer(void) + { +- mod_timer(&sync_cmos_timer, jiffies + 1); ++ if (!no_sync_cmos_clock) ++ mod_timer(&sync_cmos_timer, jiffies + 1); + mod_timer(&sync_xen_wallclock_timer, jiffies + 1); + } + +@@ -958,29 +767,11 @@ static int time_init_device(void) + + device_initcall(time_init_device); + +-#ifdef CONFIG_HPET_TIMER + extern void (*late_time_init)(void); +-/* Duplicate of time_init() below, with hpet_enable part added */ +-static void __init hpet_time_init(void) +-{ +- struct timespec ts; +- ts.tv_sec = get_cmos_time(); +- ts.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); +- +- do_settimeofday(&ts); +- +- if ((hpet_enable() >= 0) && hpet_use_timer) { +- printk("Using HPET for base-timer\n"); +- } +- +- do_time_init(); +-} +-#endif + + /* Dynamically-mapped IRQ. */ + DEFINE_PER_CPU(int, timer_irq); + +-extern void (*late_time_init)(void); + static void setup_cpu0_timer_irq(void) + { + per_cpu(timer_irq, 0) = +@@ -988,7 +779,7 @@ static void setup_cpu0_timer_irq(void) + VIRQ_TIMER, + 0, + timer_interrupt, +- SA_INTERRUPT, ++ IRQF_DISABLED|IRQF_NOBALANCING, + "timer0", + NULL); + BUG_ON(per_cpu(timer_irq, 0) < 0); +@@ -1000,16 +791,9 @@ static struct vcpu_set_periodic_timer xe + + void __init time_init(void) + { +-#ifdef CONFIG_HPET_TIMER +- if (is_hpet_capable()) { +- /* +- * HPET initialization needs to do memory-mapped io. So, let +- * us do a late initialization after mem_init(). +- */ +- late_time_init = hpet_time_init; +- return; +- } +-#endif ++ init_cpu_khz(); ++ printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", ++ cpu_khz / 1000, cpu_khz % 1000); + + switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0, + &xen_set_periodic_tick)) { +@@ -1028,18 +812,12 @@ void __init time_init(void) + per_cpu(processed_system_time, 0) = processed_system_time; + init_missing_ticks_accounting(0); + +- update_wallclock(); ++ clocksource_register(&clocksource_xen); + +-#ifdef CONFIG_X86_64 +- init_cpu_khz(); +- printk(KERN_INFO "Xen reported: %u.%03u MHz processor.\n", +- cpu_khz / 1000, cpu_khz % 1000); ++ update_wallclock(); + +- vxtime.mode = VXTIME_TSC; +- vxtime.quot = (1000000L << 32) / vxtime_hz; +- vxtime.tsc_quot = (1000L << 32) / cpu_khz; +- sync_core(); +- rdtscll(vxtime.last_tsc); ++#ifndef CONFIG_X86_64 ++ use_tsc_delay(); + #endif + + /* Cannot request_irq() until kmem is initialised. */ +@@ -1196,7 +974,7 @@ int __cpuinit local_setup_timer(unsigned + irq = bind_virq_to_irqhandler(VIRQ_TIMER, + cpu, + timer_interrupt, +- SA_INTERRUPT, ++ IRQF_DISABLED|IRQF_NOBALANCING, + timer_name[cpu], + NULL); + if (irq < 0) +@@ -1285,7 +1063,7 @@ static ctl_table xen_table[] = { + }; + static int __init xen_sysctl_init(void) + { +- (void)register_sysctl_table(xen_table, 0); ++ (void)register_sysctl_table(xen_table); + return 0; + } + __initcall(xen_sysctl_init); +--- sle11-2009-05-14.orig/arch/x86/kernel/traps_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/traps_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -100,6 +100,7 @@ asmlinkage void fixup_4gb_segment(void); + asmlinkage void machine_check(void); + + int kstack_depth_to_print = 24; ++static unsigned int code_bytes = 64; + ATOMIC_NOTIFIER_HEAD(i386die_chain); + + int register_die_notifier(struct notifier_block *nb) +@@ -297,10 +298,11 @@ void show_registers(struct pt_regs *regs + int i; + int in_kernel = 1; + unsigned long esp; +- unsigned short ss; ++ unsigned short ss, gs; + + esp = (unsigned long) (®s->esp); + savesegment(ss, ss); ++ savesegment(gs, gs); + if (user_mode_vm(regs)) { + in_kernel = 0; + esp = regs->esp; +@@ -319,8 +321,8 @@ void show_registers(struct pt_regs *regs + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); +- printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", +- regs->xds & 0xffff, regs->xes & 0xffff, ss); ++ printk(KERN_EMERG "ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", ++ regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss); + printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", + TASK_COMM_LEN, current->comm, current->pid, + current_thread_info(), current, current->thread_info); +@@ -330,7 +332,8 @@ void show_registers(struct pt_regs *regs + */ + if (in_kernel) { + u8 *eip; +- int code_bytes = 64; ++ unsigned int code_prologue = code_bytes * 43 / 64; ++ unsigned int code_len = code_bytes; + unsigned char c; + + printk("\n" KERN_EMERG "Stack: "); +@@ -338,14 +341,14 @@ void show_registers(struct pt_regs *regs + + printk(KERN_EMERG "Code: "); + +- eip = (u8 *)regs->eip - 43; ++ eip = (u8 *)regs->eip - code_prologue; + if (eip < (u8 *)PAGE_OFFSET || + probe_kernel_address(eip, c)) { + /* try starting at EIP */ + eip = (u8 *)regs->eip; +- code_bytes = 32; ++ code_len = code_len - code_prologue + 1; + } +- for (i = 0; i < code_bytes; i++, eip++) { ++ for (i = 0; i < code_len; i++, eip++) { + if (eip < (u8 *)PAGE_OFFSET || + probe_kernel_address(eip, c)) { + printk(" Bad EIP value."); +@@ -1134,3 +1137,13 @@ static int __init kstack_setup(char *s) + return 1; + } + __setup("kstack=", kstack_setup); ++ ++static int __init code_bytes_setup(char *s) ++{ ++ code_bytes = simple_strtoul(s, NULL, 0); ++ if (code_bytes > 8192) ++ code_bytes = 8192; ++ ++ return 1; ++} ++__setup("code_bytes=", code_bytes_setup); +--- sle11-2009-05-14.orig/arch/x86/mm/fault_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/fault_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -46,43 +46,17 @@ int unregister_page_fault_notifier(struc + } + EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); + +-static inline int notify_page_fault(enum die_val val, const char *str, +- struct pt_regs *regs, long err, int trap, int sig) ++static inline int notify_page_fault(struct pt_regs *regs, long err) + { + struct die_args args = { + .regs = regs, +- .str = str, ++ .str = "page fault", + .err = err, +- .trapnr = trap, +- .signr = sig ++ .trapnr = 14, ++ .signr = SIGSEGV + }; +- return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); +-} +- +-/* +- * Unlock any spinlocks which will prevent us from getting the +- * message out +- */ +-void bust_spinlocks(int yes) +-{ +- int loglevel_save = console_loglevel; +- +- if (yes) { +- oops_in_progress = 1; +- return; +- } +-#ifdef CONFIG_VT +- unblank_screen(); +-#endif +- oops_in_progress = 0; +- /* +- * OK, the message is on the console. Now we call printk() +- * without oops_in_progress set so that printk will give klogd +- * a poke. Hold onto your hats... +- */ +- console_loglevel = 15; /* NMI oopser may have shut the console up */ +- printk(" "); +- console_loglevel = loglevel_save; ++ return atomic_notifier_call_chain(¬ify_page_fault_chain, ++ DIE_PAGE_FAULT, &args); + } + + /* +@@ -476,8 +450,7 @@ fastcall void __kprobes do_page_fault(st + /* Can take a spurious fault if mapping changes R/O -> R/W. */ + if (spurious_fault(regs, address, error_code)) + return; +- if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, +- SIGSEGV) == NOTIFY_STOP) ++ if (notify_page_fault(regs, error_code) == NOTIFY_STOP) + return; + /* + * Don't take the mm semaphore here. If we fixup a prefetch +@@ -486,8 +459,7 @@ fastcall void __kprobes do_page_fault(st + goto bad_area_nosemaphore; + } + +- if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, +- SIGSEGV) == NOTIFY_STOP) ++ if (notify_page_fault(regs, error_code) == NOTIFY_STOP) + return; + + /* It's safe to allow irq's after cr2 has been saved and the vmalloc +--- sle11-2009-05-14.orig/arch/x86/mm/highmem_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/highmem_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -33,14 +33,16 @@ static void *__kmap_atomic(struct page * + + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + pagefault_disable(); ++ ++ idx = type + KM_TYPE_NR*smp_processor_id(); ++ BUG_ON(!pte_none(*(kmap_pte-idx))); ++ + if (!PageHighMem(page)) + return page_address(page); + +- idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); +- if (!pte_none(*(kmap_pte-idx))) +- BUG(); + set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); ++ /*arch_flush_lazy_mmu_mode();*/ + + return (void*) vaddr; + } +@@ -94,6 +96,7 @@ void *kmap_atomic_pfn(unsigned long pfn, + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot)); ++ /*arch_flush_lazy_mmu_mode();*/ + + return (void*) vaddr; + } +--- sle11-2009-05-14.orig/arch/x86/mm/init_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/init_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -66,6 +66,7 @@ static pmd_t * __init one_md_table_init( + + #ifdef CONFIG_X86_PAE + pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); + make_lowmem_page_readonly(pmd_table, XENFEAT_writable_page_tables); + set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); + pud = pud_offset(pgd, 0); +@@ -87,6 +88,7 @@ static pte_t * __init one_page_table_ini + { + if (pmd_none(*pmd)) { + pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); + make_lowmem_page_readonly(page_table, + XENFEAT_writable_page_tables); + set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); +--- sle11-2009-05-14.orig/arch/x86/mm/pgtable_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/pgtable_32-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -149,6 +149,8 @@ void __set_fixmap (enum fixed_addresses + void __init reserve_top_address(unsigned long reserve) + { + BUG_ON(fixmaps > 0); ++ printk(KERN_INFO "Reserving virtual address space above 0x%08x\n", ++ (int)-reserve); + __FIXADDR_TOP = -reserve - PAGE_SIZE; + __VMALLOC_RESERVE += reserve; + } +@@ -258,6 +260,12 @@ void pgd_ctor(void *pgd, struct kmem_cac + swapper_pg_dir + USER_PTRS_PER_PGD, + KERNEL_PGD_PTRS); + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); ++ ++ /* must happen under lock */ ++ paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT, ++ __pa(swapper_pg_dir) >> PAGE_SHIFT, ++ USER_PTRS_PER_PGD, PTRS_PER_PGD - USER_PTRS_PER_PGD); ++ + pgd_list_add(pgd); + spin_unlock_irqrestore(&pgd_lock, flags); + } +@@ -268,6 +276,7 @@ void pgd_dtor(void *pgd, struct kmem_cac + { + unsigned long flags; /* can be called from interrupt context */ + ++ paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT); + spin_lock_irqsave(&pgd_lock, flags); + pgd_list_del(pgd); + spin_unlock_irqrestore(&pgd_lock, flags); +@@ -292,6 +301,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + if (!pmd) + goto out_oom; ++ paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT); + set_pgd(&pgd[i], __pgd(1 + __pa(pmd))); + } + return pgd; +@@ -314,6 +324,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + pmd[i] = kmem_cache_alloc(pmd_cache, GFP_KERNEL); + if (!pmd[i]) + goto out_oom; ++ paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT); + } + + spin_lock_irqsave(&pgd_lock, flags); +@@ -354,12 +365,17 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + + out_oom: + if (HAVE_SHARED_KERNEL_PMD) { +- for (i--; i >= 0; i--) +- kmem_cache_free(pmd_cache, +- (void *)__va(pgd_val(pgd[i])-1)); ++ for (i--; i >= 0; i--) { ++ pgd_t pgdent = pgd[i]; ++ void* pmd = (void *)__va(pgd_val(pgdent)-1); ++ paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); ++ kmem_cache_free(pmd_cache, pmd); ++ } + } else { +- for (i--; i >= 0; i--) ++ for (i--; i >= 0; i--) { ++ paravirt_release_pd(__pa(pmd[i]) >> PAGE_SHIFT); + kmem_cache_free(pmd_cache, pmd[i]); ++ } + kfree(pmd); + } + kmem_cache_free(pgd_cache, pgd); +@@ -383,7 +399,9 @@ void pgd_free(pgd_t *pgd) + /* in the PAE case user pgd entries are overwritten before usage */ + if (PTRS_PER_PMD > 1) { + for (i = 0; i < USER_PTRS_PER_PGD; ++i) { +- pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1); ++ pgd_t pgdent = pgd[i]; ++ void* pmd = (void *)__va(pgd_val(pgdent)-1); ++ paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); + kmem_cache_free(pmd_cache, pmd); + } + +--- sle11-2009-05-14.orig/arch/x86/ia32/ia32entry-xen.S 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/ia32/ia32entry-xen.S 2009-03-04 11:25:55.000000000 +0100 +@@ -465,7 +465,7 @@ ia32_sys_call_table: + .quad sys32_vm86_warning /* vm86old */ + .quad compat_sys_wait4 + .quad sys_swapoff /* 115 */ +- .quad sys32_sysinfo ++ .quad compat_sys_sysinfo + .quad sys32_ipc + .quad sys_fsync + .quad stub32_sigreturn +@@ -510,7 +510,7 @@ ia32_sys_call_table: + .quad sys_sched_yield + .quad sys_sched_get_priority_max + .quad sys_sched_get_priority_min /* 160 */ +- .quad sys_sched_rr_get_interval ++ .quad sys32_sched_rr_get_interval + .quad compat_sys_nanosleep + .quad sys_mremap + .quad sys_setresuid16 +@@ -668,4 +668,5 @@ ia32_sys_call_table: + .quad compat_sys_vmsplice + .quad compat_sys_move_pages + .quad sys_getcpu ++ .quad sys_epoll_pwait + ia32_syscall_end: +--- sle11-2009-05-14.orig/arch/x86/kernel/acpi/sleep_64-xen.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/acpi/sleep_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -59,7 +59,7 @@ unsigned long acpi_wakeup_address = 0; + unsigned long acpi_video_flags; + extern char wakeup_start, wakeup_end; + +-extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); ++extern unsigned long acpi_copy_wakeup_routine(unsigned long); + + static pgd_t low_ptr; + +@@ -67,8 +67,10 @@ static void init_low_mapping(void) + { + pgd_t *slot0 = pgd_offset(current->mm, 0UL); + low_ptr = *slot0; ++ /* FIXME: We're playing with the current task's page tables here, which ++ * is potentially dangerous on SMP systems. ++ */ + set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET)); +- WARN_ON(num_online_cpus() != 1); + local_flush_tlb(); + } + #endif +--- sle11-2009-05-14.orig/arch/x86/kernel/e820_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/e820_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -88,6 +88,13 @@ static inline int bad_addr(unsigned long + return 1; + } + ++#ifdef CONFIG_NUMA ++ /* NUMA memory to node map */ ++ if (last >= nodemap_addr && addr < nodemap_addr + nodemap_size) { ++ *addrp = nodemap_addr + nodemap_size; ++ return 1; ++ } ++#endif + /* XXX ramdisk image here? */ + #else + if (last < (table_end<type != E820_RAM || ++ ei->addr+ei->size <= start || ++ ei->addr >= end) ++ continue; ++ ++ addr = round_up(ei->addr, PAGE_SIZE); ++ if (addr < start) ++ addr = start; ++ ++ last = round_down(ei->addr + ei->size, PAGE_SIZE); ++ if (last >= end) ++ last = end; ++ ++ if (last > addr) ++ ram += last - addr; ++ } ++ return ((end - start) - ram); ++} ++ ++/* + * Mark e820 reserved areas as busy for the resource manager. + */ + void __init e820_reserve_resources(struct e820entry *e820, int nr_map) +@@ -738,7 +776,7 @@ static int __init parse_memmap_opt(char + } + early_param("memmap", parse_memmap_opt); + +-void finish_e820_parsing(void) ++void __init finish_e820_parsing(void) + { + if (userdef) { + printk(KERN_INFO "user-defined physical RAM map:\n"); +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_64-xen.S 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/entry_64-xen.S 2009-03-04 11:25:55.000000000 +0100 +@@ -629,6 +629,9 @@ END(invalidate_interrupt\num) + ENTRY(call_function_interrupt) + apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt + END(call_function_interrupt) ++ENTRY(irq_move_cleanup_interrupt) ++ apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt ++END(irq_move_cleanup_interrupt) + #endif + + ENTRY(apic_timer_interrupt) +--- sle11-2009-05-14.orig/arch/x86/kernel/genapic_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/genapic_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -65,8 +65,8 @@ void __init clustered_apic_check(void) + * Some x86_64 machines use physical APIC mode regardless of how many + * procs/clusters are present (x86_64 ES7000 is an example). + */ +- if (acpi_fadt.revision > FADT2_REVISION_ID) +- if (acpi_fadt.force_apic_physical_destination_mode) { ++ if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID) ++ if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) { + genapic = &apic_cluster; + goto print; + } +--- sle11-2009-05-14.orig/arch/x86/kernel/head64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/head64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -45,8 +45,6 @@ static void __init clear_bss(void) + #define OLD_CL_BASE_ADDR 0x90000 + #define OLD_CL_OFFSET 0x90022 + +-extern char saved_command_line[]; +- + static void __init copy_bootdata(char *real_mode_data) + { + #ifndef CONFIG_XEN +@@ -62,14 +60,14 @@ static void __init copy_bootdata(char *r + new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET; + } + command_line = (char *) ((u64)(new_data)); +- memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); ++ memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + #else + int max_cmdline; + + if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) + max_cmdline = COMMAND_LINE_SIZE; +- memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline); +- saved_command_line[max_cmdline-1] = '\0'; ++ memcpy(boot_command_line, xen_start_info->cmd_line, max_cmdline); ++ boot_command_line[max_cmdline-1] = '\0'; + #endif + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/io_apic_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/io_apic_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -36,6 +36,7 @@ + #include + #endif + ++#include + #include + #include + #include +@@ -47,7 +48,20 @@ + #include + #include + +-static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result); ++struct irq_cfg { ++#ifndef CONFIG_XEN ++ cpumask_t domain; ++ cpumask_t old_domain; ++#endif ++ unsigned move_cleanup_count; ++ u8 vector; ++ u8 move_in_progress : 1; ++}; ++ ++/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ ++struct irq_cfg irq_cfg[NR_IRQS] __read_mostly; ++ ++static int assign_irq_vector(int irq, cpumask_t mask); + + #define __apicdebuginit __init + +@@ -89,7 +103,7 @@ int nr_ioapic_registers[MAX_IO_APICS]; + * Rough estimation of how many shared IRQs there are, can + * be changed anytime. + */ +-#define MAX_PLUS_SHARED_IRQS NR_IRQ_VECTORS ++#define MAX_PLUS_SHARED_IRQS NR_IRQS + #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) + + /* +@@ -262,21 +276,19 @@ static void __target_IO_APIC_irq(unsigne + + static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) + { ++ struct irq_cfg *cfg = irq_cfg + irq; + unsigned long flags; + unsigned int dest; + cpumask_t tmp; +- int vector; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) +- tmp = TARGET_CPUS; +- +- cpus_and(mask, tmp, CPU_MASK_ALL); ++ return; + +- vector = assign_irq_vector(irq, mask, &tmp); +- if (vector < 0) ++ if (assign_irq_vector(irq, mask)) + return; + ++ cpus_and(tmp, cfg->domain, mask); + dest = cpu_mask_to_apicid(tmp); + + /* +@@ -285,8 +297,8 @@ static void set_ioapic_affinity_irq(unsi + dest = SET_APIC_LOGICAL_ID(dest); + + spin_lock_irqsave(&ioapic_lock, flags); +- __target_IO_APIC_irq(irq, dest, vector); +- set_native_irq_info(irq, mask); ++ __target_IO_APIC_irq(irq, dest, cfg->vector); ++ irq_desc[irq].affinity = mask; + spin_unlock_irqrestore(&ioapic_lock, flags); + } + #endif +@@ -332,11 +344,11 @@ static void add_pin_to_irq(unsigned int + reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ + reg ACTION; \ + io_apic_modify(entry->apic, reg); \ ++ FINAL; \ + if (!entry->next) \ + break; \ + entry = irq_2_pin + entry->next; \ + } \ +- FINAL; \ + } + + #define DO_ACTION(name,R,ACTION, FINAL) \ +@@ -669,77 +681,62 @@ static int pin_2_irq(int idx, int apic, + return irq; + } + +-static inline int IO_APIC_irq_trigger(int irq) +-{ +- int apic, idx, pin; +- +- for (apic = 0; apic < nr_ioapics; apic++) { +- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { +- idx = find_irq_entry(apic,pin,mp_INT); +- if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) +- return irq_trigger(idx); +- } +- } +- /* +- * nonexistent IRQs are edge default +- */ +- return 0; +-} +- +-/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ +-static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly; +- +-static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) ++static int __assign_irq_vector(int irq, cpumask_t mask) + { +- int vector; + struct physdev_irq irq_op; ++ struct irq_cfg *cfg; + +- BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); ++ BUG_ON((unsigned)irq >= NR_IRQS); + + if (irq < PIRQ_BASE || irq - PIRQ_BASE >= NR_PIRQS) + return -EINVAL; + +- cpus_and(*result, mask, cpu_online_map); ++ cfg = &irq_cfg[irq]; ++ ++ if ((cfg->move_in_progress) || cfg->move_cleanup_count) ++ return -EBUSY; + +- if (irq_vector[irq] > 0) +- return irq_vector[irq]; ++ if (cfg->vector) ++ return 0; + + irq_op.irq = irq; + if (HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) + return -ENOSPC; + +- vector = irq_op.vector; +- irq_vector[irq] = vector; ++ cfg->vector = irq_op.vector; + +- return vector; ++ return 0; + } + +-static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result) ++static int assign_irq_vector(int irq, cpumask_t mask) + { +- int vector; ++ int err; + unsigned long flags; + + spin_lock_irqsave(&vector_lock, flags); +- vector = __assign_irq_vector(irq, mask, result); ++ err = __assign_irq_vector(irq, mask); + spin_unlock_irqrestore(&vector_lock, flags); +- return vector; ++ return err; + } + + #ifndef CONFIG_XEN + static void __clear_irq_vector(int irq) + { ++ struct irq_cfg *cfg; + cpumask_t mask; + int cpu, vector; + +- BUG_ON(!irq_vector[irq]); ++ BUG_ON((unsigned)irq >= NR_IRQS); ++ cfg = &irq_cfg[irq]; ++ BUG_ON(!cfg->vector); + +- vector = irq_vector[irq]; +- cpus_and(mask, irq_domain[irq], cpu_online_map); ++ vector = cfg->vector; ++ cpus_and(mask, cfg->domain, cpu_online_map); + for_each_cpu_mask(cpu, mask) + per_cpu(vector_irq, cpu)[vector] = -1; + +- irq_vector[irq] = 0; +- irq_domain[irq] = CPU_MASK_NONE; ++ cfg->vector = 0; ++ cfg->domain = CPU_MASK_NONE; + } + + void __setup_vector_irq(int cpu) +@@ -749,10 +746,10 @@ void __setup_vector_irq(int cpu) + int irq, vector; + + /* Mark the inuse vectors */ +- for (irq = 0; irq < NR_IRQ_VECTORS; ++irq) { +- if (!cpu_isset(cpu, irq_domain[irq])) ++ for (irq = 0; irq < NR_IRQS; ++irq) { ++ if (!cpu_isset(cpu, irq_cfg[irq].domain)) + continue; +- vector = irq_vector[irq]; ++ vector = irq_cfg[irq].vector; + per_cpu(vector_irq, cpu)[vector] = irq; + } + /* Mark the free vectors */ +@@ -760,41 +757,49 @@ void __setup_vector_irq(int cpu) + irq = per_cpu(vector_irq, cpu)[vector]; + if (irq < 0) + continue; +- if (!cpu_isset(cpu, irq_domain[irq])) ++ if (!cpu_isset(cpu, irq_cfg[irq].domain)) + per_cpu(vector_irq, cpu)[vector] = -1; + } + } + +-extern void (*interrupt[NR_IRQS])(void); +- + static struct irq_chip ioapic_chip; + +-#define IOAPIC_AUTO -1 +-#define IOAPIC_EDGE 0 +-#define IOAPIC_LEVEL 1 +- +-static void ioapic_register_intr(int irq, int vector, unsigned long trigger) ++static void ioapic_register_intr(int irq, unsigned long trigger) + { +- if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || +- trigger == IOAPIC_LEVEL) ++ if (trigger) + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_fasteoi_irq, "fasteoi"); +- else { +- irq_desc[irq].status |= IRQ_DELAYED_DISABLE; ++ else + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_edge_irq, "edge"); +- } + } + #else +-#define ioapic_register_intr(irq, vector, trigger) evtchn_register_pirq(irq) ++#define ioapic_register_intr(irq, trigger) evtchn_register_pirq(irq) + #endif /* !CONFIG_XEN */ + +-static void __init setup_IO_APIC_irq(int apic, int pin, int idx, int irq) ++static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, ++ int trigger, int polarity) + { ++ struct irq_cfg *cfg = irq_cfg + irq; + struct IO_APIC_route_entry entry; +- int vector; +- unsigned long flags; ++ cpumask_t mask; ++ ++ if (!IO_APIC_IRQ(irq)) ++ return; + ++ mask = TARGET_CPUS; ++ if (assign_irq_vector(irq, mask)) ++ return; ++ ++#ifndef CONFIG_XEN ++ cpus_and(mask, cfg->domain, mask); ++#endif ++ ++ apic_printk(APIC_VERBOSE,KERN_DEBUG ++ "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> " ++ "IRQ %d Mode:%i Active:%i)\n", ++ apic, mp_ioapics[apic].mpc_apicid, pin, cfg->vector, ++ irq, trigger, polarity); + + /* + * add it to the IO-APIC irq-routing table: +@@ -803,41 +808,23 @@ static void __init setup_IO_APIC_irq(int + + entry.delivery_mode = INT_DELIVERY_MODE; + entry.dest_mode = INT_DEST_MODE; ++ entry.dest = cpu_mask_to_apicid(mask); + entry.mask = 0; /* enable IRQ */ +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); +- +- entry.trigger = irq_trigger(idx); +- entry.polarity = irq_polarity(idx); ++ entry.trigger = trigger; ++ entry.polarity = polarity; ++ entry.vector = cfg->vector; + +- if (irq_trigger(idx)) { +- entry.trigger = 1; ++ /* Mask level triggered irqs. ++ * Use IRQ_DELAYED_DISABLE for edge triggered irqs. ++ */ ++ if (trigger) + entry.mask = 1; +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); +- } +- +- if (/* !apic && */ !IO_APIC_IRQ(irq)) +- return; + +- if (IO_APIC_IRQ(irq)) { +- cpumask_t mask; +- vector = assign_irq_vector(irq, TARGET_CPUS, &mask); +- if (vector < 0) +- return; +- +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); +- entry.vector = vector; +- +- ioapic_register_intr(irq, vector, IOAPIC_AUTO); +- if (!apic && (irq < 16)) +- disable_8259A_irq(irq); +- } ++ ioapic_register_intr(irq, trigger); ++ if (irq < 16) ++ disable_8259A_irq(irq); + + ioapic_write_entry(apic, pin, entry); +- +- spin_lock_irqsave(&ioapic_lock, flags); +- set_native_irq_info(irq, TARGET_CPUS); +- spin_unlock_irqrestore(&ioapic_lock, flags); +- + } + + static void __init setup_IO_APIC_irqs(void) +@@ -862,8 +849,8 @@ static void __init setup_IO_APIC_irqs(vo + irq = pin_2_irq(idx, apic, pin); + add_pin_to_irq(irq, apic, pin); + +- setup_IO_APIC_irq(apic, pin, idx, irq); +- ++ setup_IO_APIC_irq(apic, pin, irq, ++ irq_trigger(idx), irq_polarity(idx)); + } + } + +@@ -894,7 +881,7 @@ static void __init setup_ExtINT_IRQ0_pin + */ + entry.dest_mode = INT_DEST_MODE; + entry.mask = 0; /* unmask IRQ now */ +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); ++ entry.dest = cpu_mask_to_apicid(TARGET_CPUS); + entry.delivery_mode = INT_DELIVERY_MODE; + entry.polarity = 0; + entry.trigger = 0; +@@ -994,18 +981,17 @@ void __apicdebuginit print_IO_APIC(void) + + printk(KERN_DEBUG ".... IRQ redirection table:\n"); + +- printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" +- " Stat Dest Deli Vect: \n"); ++ printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol" ++ " Stat Dmod Deli Vect: \n"); + + for (i = 0; i <= reg_01.bits.entries; i++) { + struct IO_APIC_route_entry entry; + + entry = ioapic_read_entry(apic, i); + +- printk(KERN_DEBUG " %02x %03X %02X ", ++ printk(KERN_DEBUG " %02x %03X ", + i, +- entry.dest.logical.logical_dest, +- entry.dest.physical.physical_dest ++ entry.dest + ); + + printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", +@@ -1269,8 +1255,7 @@ void disable_IO_APIC(void) + entry.dest_mode = 0; /* Physical */ + entry.delivery_mode = dest_ExtINT; /* ExtInt */ + entry.vector = 0; +- entry.dest.physical.physical_dest = +- GET_APIC_ID(apic_read(APIC_ID)); ++ entry.dest = GET_APIC_ID(apic_read(APIC_ID)); + + /* + * Add it to the IO-APIC irq-routing table: +@@ -1355,16 +1340,15 @@ static unsigned int startup_ioapic_irq(u + + static int ioapic_retrigger_irq(unsigned int irq) + { ++ struct irq_cfg *cfg = &irq_cfg[irq]; + cpumask_t mask; +- unsigned vector; + unsigned long flags; + + spin_lock_irqsave(&vector_lock, flags); +- vector = irq_vector[irq]; + cpus_clear(mask); +- cpu_set(first_cpu(irq_domain[irq]), mask); ++ cpu_set(first_cpu(cfg->domain), mask); + +- send_IPI_mask(mask, vector); ++ send_IPI_mask(mask, cfg->vector); + spin_unlock_irqrestore(&vector_lock, flags); + + return 1; +@@ -1379,8 +1363,68 @@ static int ioapic_retrigger_irq(unsigned + * races. + */ + ++#ifdef CONFIG_SMP ++asmlinkage void smp_irq_move_cleanup_interrupt(void) ++{ ++ unsigned vector, me; ++ ack_APIC_irq(); ++ exit_idle(); ++ irq_enter(); ++ ++ me = smp_processor_id(); ++ for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { ++ unsigned int irq; ++ struct irq_desc *desc; ++ struct irq_cfg *cfg; ++ irq = __get_cpu_var(vector_irq)[vector]; ++ if (irq >= NR_IRQS) ++ continue; ++ ++ desc = irq_desc + irq; ++ cfg = irq_cfg + irq; ++ spin_lock(&desc->lock); ++ if (!cfg->move_cleanup_count) ++ goto unlock; ++ ++ if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) ++ goto unlock; ++ ++ __get_cpu_var(vector_irq)[vector] = -1; ++ cfg->move_cleanup_count--; ++unlock: ++ spin_unlock(&desc->lock); ++ } ++ ++ irq_exit(); ++} ++ ++static void irq_complete_move(unsigned int irq) ++{ ++ struct irq_cfg *cfg = irq_cfg + irq; ++ unsigned vector, me; ++ ++ if (likely(!cfg->move_in_progress)) ++ return; ++ ++ vector = ~get_irq_regs()->orig_rax; ++ me = smp_processor_id(); ++ if ((vector == cfg->vector) && ++ cpu_isset(smp_processor_id(), cfg->domain)) { ++ cpumask_t cleanup_mask; ++ ++ cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); ++ cfg->move_cleanup_count = cpus_weight(cleanup_mask); ++ send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); ++ cfg->move_in_progress = 0; ++ } ++} ++#else ++static inline void irq_complete_move(unsigned int irq) {} ++#endif ++ + static void ack_apic_edge(unsigned int irq) + { ++ irq_complete_move(irq); + move_native_irq(irq); + ack_APIC_irq(); + } +@@ -1389,6 +1433,7 @@ static void ack_apic_level(unsigned int + { + int do_unmask_irq = 0; + ++ irq_complete_move(irq); + #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) + /* If we are moving the irq we need to mask it */ + if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { +@@ -1440,7 +1485,7 @@ static inline void init_IO_APIC_traps(vo + */ + for (irq = 0; irq < NR_IRQS ; irq++) { + int tmp = irq; +- if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) { ++ if (IO_APIC_IRQ(tmp) && !irq_cfg[tmp].vector) { + /* + * Hmm.. We don't have an entry for this, + * so default to an old-fashioned 8259 +@@ -1538,7 +1583,7 @@ static inline void unlock_ExtINT_logic(v + + entry1.dest_mode = 0; /* physical delivery */ + entry1.mask = 0; /* unmask IRQ now */ +- entry1.dest.physical.physical_dest = hard_smp_processor_id(); ++ entry1.dest = hard_smp_processor_id(); + entry1.delivery_mode = dest_ExtINT; + entry1.polarity = entry0.polarity; + entry1.trigger = 0; +@@ -1582,15 +1627,14 @@ static inline void unlock_ExtINT_logic(v + */ + static inline void check_timer(void) + { ++ struct irq_cfg *cfg = irq_cfg + 0; + int apic1, pin1, apic2, pin2; +- int vector; +- cpumask_t mask; + + /* + * get/set the timer IRQ vector: + */ + disable_8259A_irq(0); +- vector = assign_irq_vector(0, TARGET_CPUS, &mask); ++ assign_irq_vector(0, TARGET_CPUS); + + /* + * Subtle, code in do_timer_interrupt() expects an AEOI +@@ -1610,7 +1654,7 @@ static inline void check_timer(void) + apic2 = ioapic_i8259.apic; + + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", +- vector, apic1, pin1, apic2, pin2); ++ cfg->vector, apic1, pin1, apic2, pin2); + + if (pin1 != -1) { + /* +@@ -1641,7 +1685,7 @@ static inline void check_timer(void) + /* + * legacy devices should be connected to IO APIC #0 + */ +- setup_ExtINT_IRQ0_pin(apic2, pin2, vector); ++ setup_ExtINT_IRQ0_pin(apic2, pin2, cfg->vector); + if (timer_irq_works()) { + apic_printk(APIC_VERBOSE," works.\n"); + nmi_watchdog_default(); +@@ -1666,14 +1710,14 @@ static inline void check_timer(void) + + disable_8259A_irq(0); + irq_desc[0].chip = &lapic_irq_type; +- apic_write(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ ++ apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ + enable_8259A_irq(0); + + if (timer_irq_works()) { + apic_printk(APIC_VERBOSE," works.\n"); + return; + } +- apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); ++ apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); + apic_printk(APIC_VERBOSE," failed.\n"); + + apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as ExtINT IRQ..."); +@@ -1828,19 +1872,16 @@ int create_irq(void) + /* Allocate an unused irq */ + int irq; + int new; +- int vector = 0; + unsigned long flags; +- cpumask_t mask; + + irq = -ENOSPC; + spin_lock_irqsave(&vector_lock, flags); + for (new = (NR_IRQS - 1); new >= 0; new--) { + if (platform_legacy_irq(new)) + continue; +- if (irq_vector[new] != 0) ++ if (irq_cfg[new].vector != 0) + continue; +- vector = __assign_irq_vector(new, TARGET_CPUS, &mask); +- if (likely(vector > 0)) ++ if (__assign_irq_vector(new, TARGET_CPUS) == 0) + irq = new; + break; + } +@@ -1871,12 +1912,15 @@ void destroy_irq(unsigned int irq) + #if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) + static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) + { +- int vector; ++ struct irq_cfg *cfg = irq_cfg + irq; ++ int err; + unsigned dest; + cpumask_t tmp; + +- vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); +- if (vector >= 0) { ++ tmp = TARGET_CPUS; ++ err = assign_irq_vector(irq, tmp); ++ if (!err) { ++ cpus_and(tmp, cfg->domain, tmp); + dest = cpu_mask_to_apicid(tmp); + + msg->address_hi = MSI_ADDR_BASE_HI; +@@ -1896,40 +1940,38 @@ static int msi_compose_msg(struct pci_de + ((INT_DELIVERY_MODE != dest_LowestPrio) ? + MSI_DATA_DELIVERY_FIXED: + MSI_DATA_DELIVERY_LOWPRI) | +- MSI_DATA_VECTOR(vector); ++ MSI_DATA_VECTOR(cfg->vector); + } +- return vector; ++ return err; + } + + #ifdef CONFIG_SMP + static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) + { ++ struct irq_cfg *cfg = irq_cfg + irq; + struct msi_msg msg; + unsigned int dest; + cpumask_t tmp; +- int vector; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) +- tmp = TARGET_CPUS; +- +- cpus_and(mask, tmp, CPU_MASK_ALL); ++ return; + +- vector = assign_irq_vector(irq, mask, &tmp); +- if (vector < 0) ++ if (assign_irq_vector(irq, mask)) + return; + ++ cpus_and(tmp, cfg->domain, mask); + dest = cpu_mask_to_apicid(tmp); + + read_msi_msg(irq, &msg); + + msg.data &= ~MSI_DATA_VECTOR_MASK; +- msg.data |= MSI_DATA_VECTOR(vector); ++ msg.data |= MSI_DATA_VECTOR(cfg->vector); + msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; + msg.address_lo |= MSI_ADDR_DEST_ID(dest); + + write_msi_msg(irq, &msg); +- set_native_irq_info(irq, mask); ++ irq_desc[irq].affinity = mask; + } + #endif /* CONFIG_SMP */ + +@@ -1948,24 +1990,31 @@ static struct irq_chip msi_chip = { + .retrigger = ioapic_retrigger_irq, + }; + +-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) ++int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) + { + struct msi_msg msg; +- int ret; ++ int irq, ret; ++ irq = create_irq(); ++ if (irq < 0) ++ return irq; ++ ++ set_irq_msi(irq, desc); + ret = msi_compose_msg(dev, irq, &msg); +- if (ret < 0) ++ if (ret < 0) { ++ destroy_irq(irq); + return ret; ++ } + + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); + +- return 0; ++ return irq; + } + + void arch_teardown_msi_irq(unsigned int irq) + { +- return; ++ destroy_irq(irq); + } + + #endif /* CONFIG_PCI_MSI */ +@@ -1993,24 +2042,22 @@ static void target_ht_irq(unsigned int i + + static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) + { ++ struct irq_cfg *cfg = irq_cfg + irq; + unsigned int dest; + cpumask_t tmp; +- int vector; + + cpus_and(tmp, mask, cpu_online_map); + if (cpus_empty(tmp)) +- tmp = TARGET_CPUS; +- +- cpus_and(mask, tmp, CPU_MASK_ALL); ++ return; + +- vector = assign_irq_vector(irq, mask, &tmp); +- if (vector < 0) ++ if (assign_irq_vector(irq, mask)) + return; + ++ cpus_and(tmp, cfg->domain, mask); + dest = cpu_mask_to_apicid(tmp); + +- target_ht_irq(irq, dest, vector); +- set_native_irq_info(irq, mask); ++ target_ht_irq(irq, dest, cfg->vector); ++ irq_desc[irq].affinity = mask; + } + #endif + +@@ -2027,14 +2074,17 @@ static struct irq_chip ht_irq_chip = { + + int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) + { +- int vector; ++ struct irq_cfg *cfg = irq_cfg + irq; ++ int err; + cpumask_t tmp; + +- vector = assign_irq_vector(irq, TARGET_CPUS, &tmp); +- if (vector >= 0) { ++ tmp = TARGET_CPUS; ++ err = assign_irq_vector(irq, tmp); ++ if (!err) { + struct ht_irq_msg msg; + unsigned dest; + ++ cpus_and(tmp, cfg->domain, tmp); + dest = cpu_mask_to_apicid(tmp); + + msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest); +@@ -2042,7 +2092,7 @@ int arch_setup_ht_irq(unsigned int irq, + msg.address_lo = + HT_IRQ_LOW_BASE | + HT_IRQ_LOW_DEST_ID(dest) | +- HT_IRQ_LOW_VECTOR(vector) | ++ HT_IRQ_LOW_VECTOR(cfg->vector) | + ((INT_DEST_MODE == 0) ? + HT_IRQ_LOW_DM_PHYSICAL : + HT_IRQ_LOW_DM_LOGICAL) | +@@ -2057,7 +2107,7 @@ int arch_setup_ht_irq(unsigned int irq, + set_irq_chip_and_handler_name(irq, &ht_irq_chip, + handle_edge_irq, "edge"); + } +- return vector; ++ return err; + } + #endif /* CONFIG_HT_IRQ */ + +@@ -2082,13 +2132,8 @@ int __init io_apic_get_redir_entries (in + } + + +-int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low) ++int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity) + { +- struct IO_APIC_route_entry entry; +- unsigned long flags; +- int vector; +- cpumask_t mask; +- + if (!IO_APIC_IRQ(irq)) { + apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", + ioapic); +@@ -2101,42 +2146,7 @@ int io_apic_set_pci_routing (int ioapic, + if (irq >= 16) + add_pin_to_irq(irq, ioapic, pin); + +- +- vector = assign_irq_vector(irq, TARGET_CPUS, &mask); +- if (vector < 0) +- return vector; +- +- /* +- * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. +- * Note that we mask (disable) IRQs now -- these get enabled when the +- * corresponding device driver registers for this IRQ. +- */ +- +- memset(&entry,0,sizeof(entry)); +- +- entry.delivery_mode = INT_DELIVERY_MODE; +- entry.dest_mode = INT_DEST_MODE; +- entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); +- entry.trigger = edge_level; +- entry.polarity = active_high_low; +- entry.mask = 1; /* Disabled (masked) */ +- entry.vector = vector & 0xff; +- +- apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " +- "IRQ %d Mode:%i Active:%i)\n", ioapic, +- mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, +- edge_level, active_high_low); +- +- ioapic_register_intr(irq, entry.vector, edge_level); +- +- if (!ioapic && (irq < 16)) +- disable_8259A_irq(irq); +- +- ioapic_write_entry(ioapic, pin, entry); +- +- spin_lock_irqsave(&ioapic_lock, flags); +- set_native_irq_info(irq, TARGET_CPUS); +- spin_unlock_irqrestore(&ioapic_lock, flags); ++ setup_IO_APIC_irq(ioapic, pin, irq, triggering, polarity); + + return 0; + } +@@ -2169,8 +2179,10 @@ void __init setup_ioapic_dest(void) + * when you have too many devices, because at that time only boot + * cpu is online. + */ +- if(!irq_vector[irq]) +- setup_IO_APIC_irq(ioapic, pin, irq_entry, irq); ++ if (!irq_cfg[irq].vector) ++ setup_IO_APIC_irq(ioapic, pin, irq, ++ irq_trigger(irq_entry), ++ irq_polarity(irq_entry)); + else + set_ioapic_affinity_irq(irq, TARGET_CPUS); + } +--- sle11-2009-05-14.orig/arch/x86/kernel/irq_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/irq_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + atomic_t irq_err_count; + +@@ -120,9 +121,15 @@ asmlinkage unsigned int do_IRQ(struct pt + + if (likely(irq < NR_IRQS)) + generic_handle_irq(irq); +- else if (printk_ratelimit()) +- printk(KERN_EMERG "%s: %d.%d No irq handler for irq\n", +- __func__, smp_processor_id(), irq); ++ else { ++#ifndef CONFIG_XEN ++ if (!disable_apic) ++ ack_APIC_irq(); ++#endif ++ if (printk_ratelimit()) ++ printk(KERN_EMERG "%s: %d.%d No irq handler for irq\n", ++ __func__, smp_processor_id(), irq); ++ } + + /*irq_exit();*/ + +--- sle11-2009-05-14.orig/arch/x86/kernel/mpparse_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/mpparse_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -60,9 +60,9 @@ unsigned long mp_lapic_addr = 0; + /* Processor that is doing the boot up */ + unsigned int boot_cpu_id = -1U; + /* Internal processor count */ +-unsigned int num_processors __initdata = 0; ++unsigned int num_processors __cpuinitdata = 0; + +-unsigned disabled_cpus __initdata; ++unsigned disabled_cpus __cpuinitdata; + + /* Bitmask of physically existing CPUs */ + physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE; +@@ -808,7 +808,7 @@ int mp_register_gsi(u32 gsi, int trigger + return gsi; + + /* Don't set up the ACPI SCI because it's already set up */ +- if (acpi_fadt.sci_int == gsi) ++ if (acpi_gbl_FADT.sci_interrupt == gsi) + return gsi; + + ioapic = mp_find_ioapic(gsi); +--- sle11-2009-05-14.orig/arch/x86/kernel/process_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/process_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -338,14 +338,17 @@ void load_gs_index(unsigned gs) + void flush_thread(void) + { + struct task_struct *tsk = current; +- struct thread_info *t = current_thread_info(); + +- if (t->flags & _TIF_ABI_PENDING) { +- t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32); +- if (t->flags & _TIF_IA32) ++ if (test_tsk_thread_flag(tsk, TIF_ABI_PENDING)) { ++ clear_tsk_thread_flag(tsk, TIF_ABI_PENDING); ++ if (test_tsk_thread_flag(tsk, TIF_IA32)) { ++ clear_tsk_thread_flag(tsk, TIF_IA32); ++ } else { ++ set_tsk_thread_flag(tsk, TIF_IA32); + current_thread_info()->status |= TS_COMPAT; ++ } + } +- t->flags &= ~_TIF_DEBUG; ++ clear_tsk_thread_flag(tsk, TIF_DEBUG); + + tsk->thread.debugreg0 = 0; + tsk->thread.debugreg1 = 0; +--- sle11-2009-05-14.orig/arch/x86/kernel/setup_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/setup_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -141,7 +141,7 @@ EXPORT_SYMBOL_GPL(edid_info); + + extern int root_mountflags; + +-char command_line[COMMAND_LINE_SIZE]; ++char __initdata command_line[COMMAND_LINE_SIZE]; + + struct resource standard_io_resources[] = { + { .name = "dma1", .start = 0x00, .end = 0x1f, +@@ -179,134 +179,6 @@ struct resource code_resource = { + .flags = IORESOURCE_RAM, + }; + +-#define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM) +- +-static struct resource system_rom_resource = { +- .name = "System ROM", +- .start = 0xf0000, +- .end = 0xfffff, +- .flags = IORESOURCE_ROM, +-}; +- +-static struct resource extension_rom_resource = { +- .name = "Extension ROM", +- .start = 0xe0000, +- .end = 0xeffff, +- .flags = IORESOURCE_ROM, +-}; +- +-static struct resource adapter_rom_resources[] = { +- { .name = "Adapter ROM", .start = 0xc8000, .end = 0, +- .flags = IORESOURCE_ROM }, +- { .name = "Adapter ROM", .start = 0, .end = 0, +- .flags = IORESOURCE_ROM }, +- { .name = "Adapter ROM", .start = 0, .end = 0, +- .flags = IORESOURCE_ROM }, +- { .name = "Adapter ROM", .start = 0, .end = 0, +- .flags = IORESOURCE_ROM }, +- { .name = "Adapter ROM", .start = 0, .end = 0, +- .flags = IORESOURCE_ROM }, +- { .name = "Adapter ROM", .start = 0, .end = 0, +- .flags = IORESOURCE_ROM } +-}; +- +-static struct resource video_rom_resource = { +- .name = "Video ROM", +- .start = 0xc0000, +- .end = 0xc7fff, +- .flags = IORESOURCE_ROM, +-}; +- +-static struct resource video_ram_resource = { +- .name = "Video RAM area", +- .start = 0xa0000, +- .end = 0xbffff, +- .flags = IORESOURCE_RAM, +-}; +- +-#define romsignature(x) (*(unsigned short *)(x) == 0xaa55) +- +-static int __init romchecksum(unsigned char *rom, unsigned long length) +-{ +- unsigned char *p, sum = 0; +- +- for (p = rom; p < rom + length; p++) +- sum += *p; +- return sum == 0; +-} +- +-static void __init probe_roms(void) +-{ +- unsigned long start, length, upper; +- unsigned char *rom; +- int i; +- +-#ifdef CONFIG_XEN +- /* Nothing to do if not running in dom0. */ +- if (!is_initial_xendomain()) +- return; +-#endif +- +- /* video rom */ +- upper = adapter_rom_resources[0].start; +- for (start = video_rom_resource.start; start < upper; start += 2048) { +- rom = isa_bus_to_virt(start); +- if (!romsignature(rom)) +- continue; +- +- video_rom_resource.start = start; +- +- /* 0 < length <= 0x7f * 512, historically */ +- length = rom[2] * 512; +- +- /* if checksum okay, trust length byte */ +- if (length && romchecksum(rom, length)) +- video_rom_resource.end = start + length - 1; +- +- request_resource(&iomem_resource, &video_rom_resource); +- break; +- } +- +- start = (video_rom_resource.end + 1 + 2047) & ~2047UL; +- if (start < upper) +- start = upper; +- +- /* system rom */ +- request_resource(&iomem_resource, &system_rom_resource); +- upper = system_rom_resource.start; +- +- /* check for extension rom (ignore length byte!) */ +- rom = isa_bus_to_virt(extension_rom_resource.start); +- if (romsignature(rom)) { +- length = extension_rom_resource.end - extension_rom_resource.start + 1; +- if (romchecksum(rom, length)) { +- request_resource(&iomem_resource, &extension_rom_resource); +- upper = extension_rom_resource.start; +- } +- } +- +- /* check for adapter roms on 2k boundaries */ +- for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; +- start += 2048) { +- rom = isa_bus_to_virt(start); +- if (!romsignature(rom)) +- continue; +- +- /* 0 < length <= 0x7f * 512, historically */ +- length = rom[2] * 512; +- +- /* but accept any length that fits if checksum okay */ +- if (!length || start + length > upper || !romchecksum(rom, length)) +- continue; +- +- adapter_rom_resources[i].start = start; +- adapter_rom_resources[i].end = start + length - 1; +- request_resource(&iomem_resource, &adapter_rom_resources[i]); +- +- start = adapter_rom_resources[i++].end & ~2047UL; +- } +-} +- + #ifdef CONFIG_PROC_VMCORE + /* elfcorehdr= specifies the location of elf core header + * stored by the crashed kernel. This option will be passed +@@ -403,7 +275,7 @@ void __init setup_arch(char **cmdline_p) + #ifdef CONFIG_XEN + extern struct e820map machine_e820; + +- printk(KERN_INFO "Command line: %s\n", saved_command_line); ++ printk(KERN_INFO "Command line: %s\n", boot_command_line); + + /* Register a call for panic conditions. */ + atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); +@@ -430,7 +302,7 @@ void __init setup_arch(char **cmdline_p) + + ARCH_SETUP + #else +- printk(KERN_INFO "Command line: %s\n", saved_command_line); ++ printk(KERN_INFO "Command line: %s\n", boot_command_line); + + ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); + screen_info = SCREEN_INFO; +@@ -461,7 +333,7 @@ void __init setup_arch(char **cmdline_p) + + early_identify_cpu(&boot_cpu_data); + +- strlcpy(command_line, saved_command_line, COMMAND_LINE_SIZE); ++ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); + *cmdline_p = command_line; + + parse_early_param(); +@@ -531,6 +403,11 @@ void __init setup_arch(char **cmdline_p) + /* reserve ebda region */ + if (ebda_addr) + reserve_bootmem_generic(ebda_addr, ebda_size); ++#ifdef CONFIG_NUMA ++ /* reserve nodemap region */ ++ if (nodemap_addr) ++ reserve_bootmem_generic(nodemap_addr, nodemap_size); ++#endif + + #ifdef CONFIG_SMP + /* +@@ -731,10 +608,8 @@ void __init setup_arch(char **cmdline_p) + #endif + + /* +- * Request address space for all standard RAM and ROM resources +- * and also for regions reported as reserved by the e820. ++ * We trust e820 completely. No explicit ROM probing in memory. + */ +- probe_roms(); + #ifdef CONFIG_XEN + if (is_initial_xendomain()) + e820_reserve_resources(machine_e820.map, machine_e820.nr_map); +@@ -743,8 +618,6 @@ void __init setup_arch(char **cmdline_p) + e820_mark_nosave_regions(); + #endif + +- request_resource(&iomem_resource, &video_ram_resource); +- + { + unsigned i; + /* request I/O space for devices used on all i[345]86 PCs */ +@@ -1321,7 +1194,8 @@ static int show_cpuinfo(struct seq_file + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL, +- NULL, "fxsr_opt", NULL, "rdtscp", NULL, "lm", "3dnowext", "3dnow", ++ NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", ++ "3dnowext", "3dnow", + + /* Transmeta-defined */ + "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL, +@@ -1339,7 +1213,7 @@ static int show_cpuinfo(struct seq_file + /* Intel-defined (#2) */ + "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", + "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, +- NULL, NULL, "dca", NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* VIA/Cyrix/Centaur-defined */ +@@ -1349,8 +1223,10 @@ static int show_cpuinfo(struct seq_file + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* AMD-defined (#2) */ +- "lahf_lm", "cmp_legacy", "svm", NULL, "cr8_legacy", NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy", ++ "altmovcr8", "abm", "sse4a", ++ "misalignsse", "3dnowprefetch", ++ "osvw", "ibs", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; +@@ -1361,6 +1237,9 @@ static int show_cpuinfo(struct seq_file + "ttp", /* thermal trip */ + "tm", + "stc", ++ "100mhzsteps", ++ "hwpstate", ++ NULL, /* tsc invariant mapped to constant_tsc */ + NULL, + /* nothing */ /* constant_tsc - moved to flags */ + }; +@@ -1477,26 +1356,3 @@ struct seq_operations cpuinfo_op = { + .stop = c_stop, + .show = show_cpuinfo, + }; +- +-#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE) +-#include +-static __init int add_pcspkr(void) +-{ +- struct platform_device *pd; +- int ret; +- +- if (!is_initial_xendomain()) +- return 0; +- +- pd = platform_device_alloc("pcspkr", -1); +- if (!pd) +- return -ENOMEM; +- +- ret = platform_device_add(pd); +- if (ret) +- platform_device_put(pd); +- +- return ret; +-} +-device_initcall(add_pcspkr); +-#endif +--- sle11-2009-05-14.orig/arch/x86/kernel/vsyscall_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/vsyscall_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -34,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -44,56 +46,41 @@ + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) + #define __syscall_clobber "r11","rcx","memory" + +-int __sysctl_vsyscall __section_sysctl_vsyscall = 1; +-seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; ++struct vsyscall_gtod_data_t { ++ seqlock_t lock; ++ int sysctl_enabled; ++ struct timeval wall_time_tv; ++ struct timezone sys_tz; ++ cycle_t offset_base; ++ struct clocksource clock; ++}; + int __vgetcpu_mode __section_vgetcpu_mode; + +-#include +- +-static __always_inline void timeval_normalize(struct timeval * tv) ++struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data = + { +- time_t __sec; +- +- __sec = tv->tv_usec / 1000000; +- if (__sec) { +- tv->tv_usec %= 1000000; +- tv->tv_sec += __sec; +- } +-} ++ .lock = SEQLOCK_UNLOCKED, ++ .sysctl_enabled = 1, ++}; + +-static __always_inline void do_vgettimeofday(struct timeval * tv) ++void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) + { +- long sequence, t; +- unsigned long sec, usec; ++ unsigned long flags; + +- do { +- sequence = read_seqbegin(&__xtime_lock); +- +- sec = __xtime.tv_sec; +- usec = __xtime.tv_nsec / 1000; +- +- if (__vxtime.mode != VXTIME_HPET) { +- t = get_cycles_sync(); +- if (t < __vxtime.last_tsc) +- t = __vxtime.last_tsc; +- usec += ((t - __vxtime.last_tsc) * +- __vxtime.tsc_quot) >> 32; +- /* See comment in x86_64 do_gettimeofday. */ +- } else { +- usec += ((readl((void __iomem *) +- fix_to_virt(VSYSCALL_HPET) + 0xf0) - +- __vxtime.last) * __vxtime.quot) >> 32; +- } +- } while (read_seqretry(&__xtime_lock, sequence)); +- +- tv->tv_sec = sec + usec / 1000000; +- tv->tv_usec = usec % 1000000; ++ write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); ++ /* copy vsyscall data */ ++ vsyscall_gtod_data.clock = *clock; ++ vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec; ++ vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000; ++ vsyscall_gtod_data.sys_tz = sys_tz; ++ write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); + } + +-/* RED-PEN may want to readd seq locking, but then the variable should be write-once. */ ++/* RED-PEN may want to readd seq locking, but then the variable should be ++ * write-once. ++ */ + static __always_inline void do_get_tz(struct timezone * tz) + { +- *tz = __sys_tz; ++ *tz = __vsyscall_gtod_data.sys_tz; + } + + static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz) +@@ -101,7 +88,8 @@ static __always_inline int gettimeofday( + int ret; + asm volatile("vsysc2: syscall" + : "=a" (ret) +- : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) : __syscall_clobber ); ++ : "0" (__NR_gettimeofday),"D" (tv),"S" (tz) ++ : __syscall_clobber ); + return ret; + } + +@@ -114,10 +102,44 @@ static __always_inline long time_syscall + return secs; + } + ++static __always_inline void do_vgettimeofday(struct timeval * tv) ++{ ++ cycle_t now, base, mask, cycle_delta; ++ unsigned long seq, mult, shift, nsec_delta; ++ cycle_t (*vread)(void); ++ do { ++ seq = read_seqbegin(&__vsyscall_gtod_data.lock); ++ ++ vread = __vsyscall_gtod_data.clock.vread; ++ if (unlikely(!__vsyscall_gtod_data.sysctl_enabled || !vread)) { ++ gettimeofday(tv,NULL); ++ return; ++ } ++ now = vread(); ++ base = __vsyscall_gtod_data.clock.cycle_last; ++ mask = __vsyscall_gtod_data.clock.mask; ++ mult = __vsyscall_gtod_data.clock.mult; ++ shift = __vsyscall_gtod_data.clock.shift; ++ ++ *tv = __vsyscall_gtod_data.wall_time_tv; ++ ++ } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); ++ ++ /* calculate interval: */ ++ cycle_delta = (now - base) & mask; ++ /* convert to nsecs: */ ++ nsec_delta = (cycle_delta * mult) >> shift; ++ ++ /* convert to usecs and add to timespec: */ ++ tv->tv_usec += nsec_delta / NSEC_PER_USEC; ++ while (tv->tv_usec > USEC_PER_SEC) { ++ tv->tv_sec += 1; ++ tv->tv_usec -= USEC_PER_SEC; ++ } ++} ++ + int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) + { +- if (!__sysctl_vsyscall) +- return gettimeofday(tv,tz); + if (tv) + do_vgettimeofday(tv); + if (tz) +@@ -129,11 +151,11 @@ int __vsyscall(0) vgettimeofday(struct t + * unlikely */ + time_t __vsyscall(1) vtime(time_t *t) + { +- if (!__sysctl_vsyscall) ++ if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) + return time_syscall(t); + else if (t) +- *t = __xtime.tv_sec; +- return __xtime.tv_sec; ++ *t = __vsyscall_gtod_data.wall_time_tv.tv_sec; ++ return __vsyscall_gtod_data.wall_time_tv.tv_sec; + } + + /* Fast way to get current CPU and node. +@@ -210,7 +232,7 @@ static int vsyscall_sysctl_change(ctl_ta + ret = -ENOMEM; + goto out; + } +- if (!sysctl_vsyscall) { ++ if (!vsyscall_gtod_data.sysctl_enabled) { + writew(SYSCALL, map1); + writew(SYSCALL, map2); + } else { +@@ -232,16 +254,17 @@ static int vsyscall_sysctl_nostrat(ctl_t + + static ctl_table kernel_table2[] = { + { .ctl_name = 99, .procname = "vsyscall64", +- .data = &sysctl_vsyscall, .maxlen = sizeof(int), .mode = 0644, ++ .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int), ++ .mode = 0644, + .strategy = vsyscall_sysctl_nostrat, + .proc_handler = vsyscall_sysctl_change }, +- { 0, } ++ {} + }; + + static ctl_table kernel_root_table2[] = { + { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555, + .child = kernel_table2 }, +- { 0 }, ++ {} + }; + + #endif +@@ -304,14 +327,14 @@ static int __init vsyscall_init(void) + BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); + map_vsyscall(); + #ifdef CONFIG_XEN +- sysctl_vsyscall = 0; /* disable vgettimeofay() */ ++ vsyscall_gtod_data.sysctl_enabled = 0; /* disable vgettimeofay() */ + if (boot_cpu_has(X86_FEATURE_RDTSCP)) + vgetcpu_mode = VGETCPU_RDTSCP; + else + vgetcpu_mode = VGETCPU_LSL; + #endif + #ifdef CONFIG_SYSCTL +- register_sysctl_table(kernel_root_table2, 0); ++ register_sysctl_table(kernel_root_table2); + #endif + on_each_cpu(cpu_vsyscall_init, NULL, 0, 1); + hotcpu_notifier(cpu_vsyscall_notifier, 0); +--- sle11-2009-05-14.orig/arch/x86/mm/fault_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/fault_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -56,38 +56,17 @@ int unregister_page_fault_notifier(struc + } + EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); + +-static inline int notify_page_fault(enum die_val val, const char *str, +- struct pt_regs *regs, long err, int trap, int sig) ++static inline int notify_page_fault(struct pt_regs *regs, long err) + { + struct die_args args = { + .regs = regs, +- .str = str, ++ .str = "page fault", + .err = err, +- .trapnr = trap, +- .signr = sig ++ .trapnr = 14, ++ .signr = SIGSEGV + }; +- return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); +-} +- +-void bust_spinlocks(int yes) +-{ +- int loglevel_save = console_loglevel; +- if (yes) { +- oops_in_progress = 1; +- } else { +-#ifdef CONFIG_VT +- unblank_screen(); +-#endif +- oops_in_progress = 0; +- /* +- * OK, the message is on the console. Now we call printk() +- * without oops_in_progress set so that printk will give klogd +- * a poke. Hold onto your hats... +- */ +- console_loglevel = 15; /* NMI oopser may have shut the console up */ +- printk(" "); +- console_loglevel = loglevel_save; +- } ++ return atomic_notifier_call_chain(¬ify_page_fault_chain, ++ DIE_PAGE_FAULT, &args); + } + + /* Sometimes the CPU reports invalid exceptions on prefetch. +@@ -437,8 +416,7 @@ asmlinkage void __kprobes do_page_fault( + /* Can take a spurious fault if mapping changes R/O -> R/W. */ + if (spurious_fault(regs, address, error_code)) + return; +- if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, +- SIGSEGV) == NOTIFY_STOP) ++ if (notify_page_fault(regs, error_code) == NOTIFY_STOP) + return; + /* + * Don't take the mm semaphore here. If we fixup a prefetch +@@ -447,8 +425,7 @@ asmlinkage void __kprobes do_page_fault( + goto bad_area_nosemaphore; + } + +- if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, +- SIGSEGV) == NOTIFY_STOP) ++ if (notify_page_fault(regs, error_code) == NOTIFY_STOP) + return; + + if (likely(regs->eflags & X86_EFLAGS_IF)) +--- sle11-2009-05-14.orig/arch/x86/mm/init_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/init_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -1108,20 +1108,30 @@ int kern_addr_valid(unsigned long addr) + extern int exception_trace, page_fault_trace; + + static ctl_table debug_table2[] = { +- { 99, "exception-trace", &exception_trace, sizeof(int), 0644, NULL, +- proc_dointvec }, +- { 0, } ++ { ++ .ctl_name = 99, ++ .procname = "exception-trace", ++ .data = &exception_trace, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec ++ }, ++ {} + }; + + static ctl_table debug_root_table2[] = { +- { .ctl_name = CTL_DEBUG, .procname = "debug", .mode = 0555, +- .child = debug_table2 }, +- { 0 }, ++ { ++ .ctl_name = CTL_DEBUG, ++ .procname = "debug", ++ .mode = 0555, ++ .child = debug_table2 ++ }, ++ {} + }; + + static __init int x8664_sysctl_init(void) + { +- register_sysctl_table(debug_root_table2, 1); ++ register_sysctl_table(debug_root_table2); + return 0; + } + __initcall(x8664_sysctl_init); +--- sle11-2009-05-14.orig/arch/x86/mm/pageattr_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/pageattr_64-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -350,8 +350,8 @@ static void flush_kernel_map(void *arg) + void *adr = page_address(pg); + if (cpu_has_clflush) + cache_flush_page(adr); +- __flush_tlb_one(adr); + } ++ __flush_tlb_all(); + } + + static inline void flush_map(struct list_head *l) +@@ -376,6 +376,7 @@ static void revert_page(unsigned long ad + pud_t *pud; + pmd_t *pmd; + pte_t large_pte; ++ unsigned long pfn; + + pgd = pgd_offset_k(address); + BUG_ON(pgd_none(*pgd)); +@@ -383,7 +384,8 @@ static void revert_page(unsigned long ad + BUG_ON(pud_none(*pud)); + pmd = pmd_offset(pud, address); + BUG_ON(__pmd_val(*pmd) & _PAGE_PSE); +- large_pte = mk_pte_phys(__pa(address) & LARGE_PAGE_MASK, ref_prot); ++ pfn = (__pa(address) & LARGE_PAGE_MASK) >> PAGE_SHIFT; ++ large_pte = pfn_pte(pfn, ref_prot); + large_pte = pte_mkhuge(large_pte); + set_pte((pte_t *)pmd, large_pte); + } +--- sle11-2009-05-14.orig/drivers/acpi/processor_extcntl.c 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/drivers/acpi/processor_extcntl.c 2009-03-04 11:25:55.000000000 +0100 +@@ -32,9 +32,8 @@ + + #define ACPI_PROCESSOR_COMPONENT 0x01000000 + #define ACPI_PROCESSOR_CLASS "processor" +-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" + #define _COMPONENT ACPI_PROCESSOR_COMPONENT +-ACPI_MODULE_NAME("acpi_processor") ++ACPI_MODULE_NAME("processor_extcntl") + + static int processor_extcntl_parse_csd(struct acpi_processor *pr); + static int processor_extcntl_get_performance(struct acpi_processor *pr); +@@ -56,24 +55,17 @@ static int processor_notify_smm(void) + return 0; + + /* Can't write pstate_cnt to smi_cmd if either value is zero */ +- if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) { ++ if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"No SMI port or pstate_cnt\n")); + return 0; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n", +- acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd)); ++ acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command)); + +- /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use +- * it anyway, so we need to support it... */ +- if (acpi_fadt_is_v1) { +- ACPI_DEBUG_PRINT((ACPI_DB_INFO, +- "Using v1.0 FADT reserved value for pstate_cnt\n")); +- } +- +- status = acpi_os_write_port(acpi_fadt.smi_cmd, +- (u32) acpi_fadt.pstate_cnt, 8); ++ status = acpi_os_write_port(acpi_gbl_FADT.smi_command, ++ acpi_gbl_FADT.pstate_control, 8); + if (ACPI_FAILURE(status)) + return status; + +--- sle11-2009-05-14.orig/drivers/char/tpm/tpm_xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/char/tpm/tpm_xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -481,7 +481,6 @@ static struct xenbus_device_id tpmfront_ + + static struct xenbus_driver tpmfront = { + .name = "vtpm", +- .owner = THIS_MODULE, + .ids = tpmfront_ids, + .probe = tpmfront_probe, + .remove = tpmfront_remove, +@@ -491,9 +490,9 @@ static struct xenbus_driver tpmfront = { + .suspend_cancel = tpmfront_suspend_cancel, + }; + +-static void __init init_tpm_xenbus(void) ++static int __init init_tpm_xenbus(void) + { +- xenbus_register_frontend(&tpmfront); ++ return xenbus_register_frontend(&tpmfront); + } + + static int tpmif_allocate_tx_buffers(struct tpm_private *tp) +--- sle11-2009-05-14.orig/drivers/pci/msi-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/pci/msi-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -44,6 +44,36 @@ struct msi_pirq_entry { + int entry_nr; + }; + ++static void msi_set_enable(struct pci_dev *dev, int enable) ++{ ++ int pos; ++ u16 control; ++ ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); ++ if (pos) { ++ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); ++ control &= ~PCI_MSI_FLAGS_ENABLE; ++ if (enable) ++ control |= PCI_MSI_FLAGS_ENABLE; ++ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); ++ } ++} ++ ++static void msix_set_enable(struct pci_dev *dev, int enable) ++{ ++ int pos; ++ u16 control; ++ ++ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); ++ if (pos) { ++ pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); ++ control &= ~PCI_MSIX_FLAGS_ENABLE; ++ if (enable) ++ control |= PCI_MSIX_FLAGS_ENABLE; ++ pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); ++ } ++} ++ + static struct msi_dev_list *get_msi_dev_pirq_list(struct pci_dev *dev) + { + struct msi_dev_list *msi_dev_list, *ret = NULL; +@@ -235,126 +265,26 @@ static int msi_map_vector(struct pci_dev + + static int msi_init(void) + { +- static int status = 0; +- +- if (pci_msi_quirk) { +- pci_msi_enable = 0; +- printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n"); +- status = -EINVAL; +- } +- +- return status; +-} +- +-void pci_scan_msi_device(struct pci_dev *dev) { } +- +-void disable_msi_mode(struct pci_dev *dev, int pos, int type) +-{ +- u16 control; +- +- pci_read_config_word(dev, msi_control_reg(pos), &control); +- if (type == PCI_CAP_ID_MSI) { +- /* Set enabled bits to single MSI & enable MSI_enable bit */ +- msi_disable(control); +- pci_write_config_word(dev, msi_control_reg(pos), control); +- dev->msi_enabled = 0; +- } else { +- msix_disable(control); +- pci_write_config_word(dev, msi_control_reg(pos), control); +- dev->msix_enabled = 0; +- } +- +- pci_intx(dev, 1); /* enable intx */ +-} +- +-static void enable_msi_mode(struct pci_dev *dev, int pos, int type) +-{ +- u16 control; +- +- pci_read_config_word(dev, msi_control_reg(pos), &control); +- if (type == PCI_CAP_ID_MSI) { +- /* Set enabled bits to single MSI & enable MSI_enable bit */ +- msi_enable(control, 1); +- pci_write_config_word(dev, msi_control_reg(pos), control); +- dev->msi_enabled = 1; +- } else { +- msix_enable(control); +- pci_write_config_word(dev, msi_control_reg(pos), control); +- dev->msix_enabled = 1; +- } +- +- pci_intx(dev, 0); /* disable intx */ ++ return 0; + } + + #ifdef CONFIG_PM +-int pci_save_msi_state(struct pci_dev *dev) ++static void __pci_restore_msi_state(struct pci_dev *dev) + { +- int pos; +- +- pos = pci_find_capability(dev, PCI_CAP_ID_MSI); +- if (pos <= 0 || dev->no_msi) +- return 0; ++ int pirq; + + if (!dev->msi_enabled) +- return 0; +- +- /* Restore dev->irq to its default pin-assertion vector */ +- msi_unmap_pirq(dev, dev->irq); +- /* Disable MSI mode */ +- disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); +- /* Set the flags for use of restore */ +- dev->msi_enabled = 1; +- return 0; +-} +- +-void pci_restore_msi_state(struct pci_dev *dev) +-{ +- int pos, pirq; +- +- pos = pci_find_capability(dev, PCI_CAP_ID_MSI); +- if (pos <= 0) + return; + +- if (!dev->msi_enabled) +- return; ++ pci_intx(dev, 0); /* disable intx */ ++ msi_set_enable(dev, 0); + + pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 0); + if (pirq < 0) + return; +- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + } + +-int pci_save_msix_state(struct pci_dev *dev) +-{ +- int pos; +- unsigned long flags; +- struct msi_dev_list *msi_dev_entry; +- struct msi_pirq_entry *pirq_entry, *tmp; +- +- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); +- if (pos <= 0 || dev->no_msi) +- return 0; +- +- /* save the capability */ +- if (!dev->msix_enabled) +- return 0; +- +- msi_dev_entry = get_msi_dev_pirq_list(dev); +- +- spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags); +- list_for_each_entry_safe(pirq_entry, tmp, +- &msi_dev_entry->pirq_list_head, list) +- msi_unmap_pirq(dev, pirq_entry->pirq); +- spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags); +- +- disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); +- /* Set the flags for use of restore */ +- dev->msix_enabled = 1; +- +- return 0; +-} +- +-void pci_restore_msix_state(struct pci_dev *dev) ++static void __pci_restore_msix_state(struct pci_dev *dev) + { + int pos; + unsigned long flags; +@@ -369,6 +299,9 @@ void pci_restore_msix_state(struct pci_d + if (!dev->msix_enabled) + return; + ++ pci_intx(dev, 0); /* disable intx */ ++ msix_set_enable(dev, 0); ++ + msi_dev_entry = get_msi_dev_pirq_list(dev); + table_base = find_table_base(dev, pos); + if (!table_base) +@@ -386,10 +319,14 @@ void pci_restore_msix_state(struct pci_d + pirq_entry->pirq, rc); + } + spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags); ++} + +- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); ++void pci_restore_msi_state(struct pci_dev *dev) ++{ ++ __pci_restore_msi_state(dev); ++ __pci_restore_msix_state(dev); + } +-#endif ++#endif /* CONFIG_PM */ + + /** + * msi_capability_init - configure device's MSI capability structure +@@ -405,6 +342,8 @@ static int msi_capability_init(struct pc + int pos, pirq; + u16 control; + ++ msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ ++ + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + pci_read_config_word(dev, msi_control_reg(pos), &control); + +@@ -413,7 +352,8 @@ static int msi_capability_init(struct pc + return -EBUSY; + + /* Set MSI enabled bits */ +- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); ++ pci_intx(dev, 0); /* disable intx */ ++ msi_set_enable(dev, 1); + dev->msi_enabled = 1; + + dev->irq = pirq; +@@ -441,6 +381,8 @@ static int msix_capability_init(struct p + if (!msi_dev_entry) + return -ENOMEM; + ++ msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ ++ + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + table_base = find_table_base(dev, pos); + if (!table_base) +@@ -484,7 +426,8 @@ static int msix_capability_init(struct p + return avail; + } + +- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); ++ pci_intx(dev, 0); /* disable intx */ ++ msix_set_enable(dev, 1); + dev->msix_enabled = 1; + + return 0; +@@ -567,17 +510,14 @@ int pci_enable_msi(struct pci_dev* dev) + /* Check whether driver already requested for MSI-X irqs */ + if (dev->msix_enabled) { + printk(KERN_INFO "PCI: %s: Can't enable MSI. " +- "Device already has MSI-X irq assigned\n", +- pci_name(dev)); +- dev->irq = temp; ++ "Device already has MSI-X enabled\n", ++ pci_name(dev)); + return -EINVAL; + } + + status = msi_capability_init(dev); + if ( !status ) + dev->irq_old = temp; +- else +- dev->irq = temp; + + return status; + } +@@ -585,7 +525,6 @@ int pci_enable_msi(struct pci_dev* dev) + extern void pci_frontend_disable_msi(struct pci_dev* dev); + void pci_disable_msi(struct pci_dev* dev) + { +- int pos; + int pirq; + + if (!pci_msi_enable) +@@ -602,8 +541,7 @@ void pci_disable_msi(struct pci_dev* dev + } + #endif + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSI); +- if (!pos) ++ if (!dev->msi_enabled) + return; + + pirq = dev->irq; +@@ -612,7 +550,9 @@ void pci_disable_msi(struct pci_dev* dev + msi_unmap_pirq(dev, pirq); + + /* Disable MSI mode */ +- disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); ++ msi_set_enable(dev, 0); ++ pci_intx(dev, 1); /* enable intx */ ++ dev->msi_enabled = 0; + } + + /** +@@ -705,7 +645,6 @@ int pci_enable_msix(struct pci_dev* dev, + printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " + "Device already has an MSI irq assigned\n", + pci_name(dev)); +- dev->irq = temp; + return -EINVAL; + } + +@@ -713,8 +652,6 @@ int pci_enable_msix(struct pci_dev* dev, + + if ( !status ) + dev->irq_old = temp; +- else +- dev->irq = temp; + + return status; + } +@@ -722,10 +659,6 @@ int pci_enable_msix(struct pci_dev* dev, + extern void pci_frontend_disable_msix(struct pci_dev* dev); + void pci_disable_msix(struct pci_dev* dev) + { +- int pos; +- u16 control; +- +- + if (!pci_msi_enable) + return; + if (!dev) +@@ -751,18 +684,15 @@ void pci_disable_msix(struct pci_dev* de + } + #endif + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); +- if (!pos) +- return; +- +- pci_read_config_word(dev, msi_control_reg(pos), &control); +- if (!(control & PCI_MSIX_FLAGS_ENABLE)) ++ if (!dev->msix_enabled) + return; + + msi_remove_pci_irq_vectors(dev); + + /* Disable MSI mode */ +- disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); ++ msix_set_enable(dev, 0); ++ pci_intx(dev, 1); /* enable intx */ ++ dev->msix_enabled = 0; + } + + /** +--- sle11-2009-05-14.orig/drivers/xen/balloon/sysfs.c 2008-11-25 13:31:07.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/balloon/sysfs.c 2009-03-04 11:25:55.000000000 +0100 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include "common.h" + + #ifdef HAVE_XEN_PLATFORM_COMPAT_H +--- sle11-2009-05-14.orig/drivers/xen/blkback/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blkback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -527,7 +527,6 @@ static const struct xenbus_device_id blk + + static struct xenbus_driver blkback = { + .name = "vbd", +- .owner = THIS_MODULE, + .ids = blkback_ids, + .probe = blkback_probe, + .remove = blkback_remove, +@@ -537,5 +536,6 @@ static struct xenbus_driver blkback = { + + void blkif_xenbus_init(void) + { +- xenbus_register_backend(&blkback); ++ if (xenbus_register_backend(&blkback)) ++ BUG(); + } +--- sle11-2009-05-14.orig/drivers/xen/blkfront/blkfront.c 2009-03-24 10:08:27.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkfront/blkfront.c 2009-03-24 10:08:49.000000000 +0100 +@@ -902,7 +902,6 @@ MODULE_ALIAS("xen:vbd"); + + static struct xenbus_driver blkfront = { + .name = "vbd", +- .owner = THIS_MODULE, + .ids = blkfront_ids, + .probe = blkfront_probe, + .remove = blkfront_remove, +--- sle11-2009-05-14.orig/drivers/xen/blktap/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blktap/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -465,7 +465,6 @@ static const struct xenbus_device_id blk + + static struct xenbus_driver blktap = { + .name = "tap", +- .owner = THIS_MODULE, + .ids = blktap_ids, + .probe = blktap_probe, + .remove = blktap_remove, +@@ -475,5 +474,6 @@ static struct xenbus_driver blktap = { + + void tap_blkif_xenbus_init(void) + { +- xenbus_register_backend(&blktap); ++ if (xenbus_register_backend(&blktap)) ++ BUG(); + } +--- sle11-2009-05-14.orig/drivers/xen/core/evtchn.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/core/evtchn.c 2009-03-04 11:25:55.000000000 +0100 +@@ -145,7 +145,7 @@ static void bind_evtchn_to_cpu(unsigned + BUG_ON(!test_bit(chn, s->evtchn_mask)); + + if (irq != -1) +- set_native_irq_info(irq, cpumask_of_cpu(cpu)); ++ irq_desc[irq].affinity = cpumask_of_cpu(cpu); + + clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]); + set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]); +@@ -158,7 +158,7 @@ static void init_evtchn_cpu_bindings(voi + + /* By default all event channels notify CPU#0. */ + for (i = 0; i < NR_IRQS; i++) +- set_native_irq_info(i, cpumask_of_cpu(0)); ++ irq_desc[i].affinity = cpumask_of_cpu(0); + + memset(cpu_evtchn, 0, sizeof(cpu_evtchn)); + memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0])); +@@ -736,6 +736,7 @@ static struct irq_chip dynirq_chip = { + .name = "Dynamic", + .startup = startup_dynirq, + .shutdown = mask_dynirq, ++ .disable = mask_dynirq, + .mask = mask_dynirq, + .unmask = unmask_dynirq, + .mask_ack = ack_dynirq, +--- sle11-2009-05-14.orig/drivers/xen/core/smpboot.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/core/smpboot.c 2009-03-04 11:25:55.000000000 +0100 +@@ -117,7 +117,7 @@ static int __cpuinit xen_smp_intr_init(u + rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, + cpu, + smp_reschedule_interrupt, +- SA_INTERRUPT, ++ IRQF_DISABLED|IRQF_NOBALANCING, + resched_name[cpu], + NULL); + if (rc < 0) +@@ -128,7 +128,7 @@ static int __cpuinit xen_smp_intr_init(u + rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR, + cpu, + smp_call_function_interrupt, +- SA_INTERRUPT, ++ IRQF_DISABLED|IRQF_NOBALANCING, + callfunc_name[cpu], + NULL); + if (rc < 0) +@@ -257,7 +257,7 @@ void __init smp_prepare_cpus(unsigned in + { + unsigned int cpu; + struct task_struct *idle; +- int apicid, acpiid; ++ int apicid; + struct vcpu_get_physid cpu_id; + #ifdef __x86_64__ + struct desc_ptr *gdt_descr; +@@ -266,14 +266,8 @@ void __init smp_prepare_cpus(unsigned in + #endif + + apicid = 0; +- if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, 0, &cpu_id) == 0) { ++ if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, 0, &cpu_id) == 0) + apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id); +- acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id); +-#ifdef CONFIG_ACPI +- if (acpiid != 0xff) +- x86_acpiid_to_apicid[acpiid] = apicid; +-#endif +- } + boot_cpu_data.apicid = apicid; + cpu_data[0] = boot_cpu_data; + +@@ -329,14 +323,8 @@ void __init smp_prepare_cpus(unsigned in + XENFEAT_writable_descriptor_tables); + + apicid = cpu; +- if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) { ++ if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) + apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id); +- acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id); +-#ifdef CONFIG_ACPI +- if (acpiid != 0xff) +- x86_acpiid_to_apicid[acpiid] = apicid; +-#endif +- } + cpu_data[cpu] = boot_cpu_data; + cpu_data[cpu].apicid = apicid; + +--- sle11-2009-05-14.orig/drivers/xen/fbfront/xenfb.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/fbfront/xenfb.c 2009-03-04 11:25:55.000000000 +0100 +@@ -857,7 +857,6 @@ MODULE_ALIAS("xen:vfb"); + + static struct xenbus_driver xenfb_driver = { + .name = "vfb", +- .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, +--- sle11-2009-05-14.orig/drivers/xen/fbfront/xenkbd.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/fbfront/xenkbd.c 2009-03-04 11:25:55.000000000 +0100 +@@ -323,7 +323,6 @@ MODULE_ALIAS("xen:vkbd"); + + static struct xenbus_driver xenkbd_driver = { + .name = "vkbd", +- .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, +--- sle11-2009-05-14.orig/drivers/xen/netback/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/netback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -439,7 +439,6 @@ static const struct xenbus_device_id net + + static struct xenbus_driver netback = { + .name = "vif", +- .owner = THIS_MODULE, + .ids = netback_ids, + .probe = netback_probe, + .remove = netback_remove, +@@ -450,5 +449,6 @@ static struct xenbus_driver netback = { + + void netif_xenbus_init(void) + { +- xenbus_register_backend(&netback); ++ if (xenbus_register_backend(&netback)) ++ BUG(); + } +--- sle11-2009-05-14.orig/drivers/xen/netfront/netfront.c 2009-03-30 16:34:59.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/netfront/netfront.c 2009-03-30 16:35:44.000000000 +0200 +@@ -1892,20 +1892,19 @@ static struct ethtool_ops network_ethtoo + }; + + #ifdef CONFIG_SYSFS +-static ssize_t show_rxbuf_min(struct class_device *cd, char *buf) ++static ssize_t show_rxbuf_min(struct device *dev, ++ struct device_attribute *attr, char *buf) + { +- struct net_device *netdev = container_of(cd, struct net_device, +- class_dev); +- struct netfront_info *info = netdev_priv(netdev); ++ struct netfront_info *info = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%u\n", info->rx_min_target); + } + +-static ssize_t store_rxbuf_min(struct class_device *cd, ++static ssize_t store_rxbuf_min(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t len) + { +- struct net_device *netdev = container_of(cd, struct net_device, +- class_dev); ++ struct net_device *netdev = to_net_dev(dev); + struct netfront_info *np = netdev_priv(netdev); + char *endp; + unsigned long target; +@@ -1935,20 +1934,19 @@ static ssize_t store_rxbuf_min(struct cl + return len; + } + +-static ssize_t show_rxbuf_max(struct class_device *cd, char *buf) ++static ssize_t show_rxbuf_max(struct device *dev, ++ struct device_attribute *attr, char *buf) + { +- struct net_device *netdev = container_of(cd, struct net_device, +- class_dev); +- struct netfront_info *info = netdev_priv(netdev); ++ struct netfront_info *info = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%u\n", info->rx_max_target); + } + +-static ssize_t store_rxbuf_max(struct class_device *cd, ++static ssize_t store_rxbuf_max(struct device *dev, ++ struct device_attribute *attr, + const char *buf, size_t len) + { +- struct net_device *netdev = container_of(cd, struct net_device, +- class_dev); ++ struct net_device *netdev = to_net_dev(dev); + struct netfront_info *np = netdev_priv(netdev); + char *endp; + unsigned long target; +@@ -1978,16 +1976,15 @@ static ssize_t store_rxbuf_max(struct cl + return len; + } + +-static ssize_t show_rxbuf_cur(struct class_device *cd, char *buf) ++static ssize_t show_rxbuf_cur(struct device *dev, ++ struct device_attribute *attr, char *buf) + { +- struct net_device *netdev = container_of(cd, struct net_device, +- class_dev); +- struct netfront_info *info = netdev_priv(netdev); ++ struct netfront_info *info = netdev_priv(to_net_dev(dev)); + + return sprintf(buf, "%u\n", info->rx_target); + } + +-static const struct class_device_attribute xennet_attrs[] = { ++static struct device_attribute xennet_attrs[] = { + __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min), + __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max), + __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL), +@@ -1999,8 +1996,8 @@ static int xennet_sysfs_addif(struct net + int error = 0; + + for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { +- error = class_device_create_file(&netdev->class_dev, +- &xennet_attrs[i]); ++ error = device_create_file(&netdev->dev, ++ &xennet_attrs[i]); + if (error) + goto fail; + } +@@ -2008,8 +2005,7 @@ static int xennet_sysfs_addif(struct net + + fail: + while (--i >= 0) +- class_device_remove_file(&netdev->class_dev, +- &xennet_attrs[i]); ++ device_remove_file(&netdev->dev, &xennet_attrs[i]); + return error; + } + +@@ -2017,10 +2013,8 @@ static void xennet_sysfs_delif(struct ne + { + int i; + +- for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) { +- class_device_remove_file(&netdev->class_dev, +- &xennet_attrs[i]); +- } ++ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) ++ device_remove_file(&netdev->dev, &xennet_attrs[i]); + } + + #endif /* CONFIG_SYSFS */ +@@ -2186,7 +2180,6 @@ MODULE_ALIAS("xen:vif"); + + static struct xenbus_driver netfront_driver = { + .name = "vif", +- .owner = THIS_MODULE, + .ids = netfront_ids, + .probe = netfront_probe, + .remove = __devexit_p(netfront_remove), +--- sle11-2009-05-14.orig/drivers/xen/pciback/xenbus.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/pciback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -682,7 +682,6 @@ static const struct xenbus_device_id xen + + static struct xenbus_driver xenbus_pciback_driver = { + .name = "pciback", +- .owner = THIS_MODULE, + .ids = xenpci_ids, + .probe = pciback_xenbus_probe, + .remove = pciback_xenbus_remove, +--- sle11-2009-05-14.orig/drivers/xen/pcifront/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/pcifront/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -436,7 +436,6 @@ MODULE_ALIAS("xen:pci"); + + static struct xenbus_driver xenbus_pcifront_driver = { + .name = "pcifront", +- .owner = THIS_MODULE, + .ids = xenpci_ids, + .probe = pcifront_xenbus_probe, + .remove = pcifront_xenbus_remove, +--- sle11-2009-05-14.orig/drivers/xen/scsiback/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/scsiback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -350,7 +350,6 @@ static struct xenbus_device_id scsiback_ + + static struct xenbus_driver scsiback = { + .name = "vscsi", +- .owner = THIS_MODULE, + .ids = scsiback_ids, + .probe = scsiback_probe, + .remove = scsiback_remove, +--- sle11-2009-05-14.orig/drivers/xen/scsifront/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/scsifront/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -401,7 +401,6 @@ static struct xenbus_device_id scsifront + + static struct xenbus_driver scsifront_driver = { + .name = "vscsi", +- .owner = THIS_MODULE, + .ids = scsifront_ids, + .probe = scsifront_probe, + .remove = scsifront_remove, +--- sle11-2009-05-14.orig/drivers/xen/tpmback/common.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/tpmback/common.h 2009-03-04 11:25:55.000000000 +0100 +@@ -54,11 +54,11 @@ typedef struct tpmif_st { + + void tpmif_disconnect_complete(tpmif_t * tpmif); + tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi); +-void tpmif_interface_init(void); ++int tpmif_interface_init(void); + void tpmif_interface_exit(void); + void tpmif_schedule_work(tpmif_t * tpmif); + void tpmif_deschedule_work(tpmif_t * tpmif); +-void tpmif_xenbus_init(void); ++int tpmif_xenbus_init(void); + void tpmif_xenbus_exit(void); + int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn); + irqreturn_t tpmif_be_int(int irq, void *dev_id); +--- sle11-2009-05-14.orig/drivers/xen/tpmback/interface.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/tpmback/interface.c 2009-03-04 11:25:55.000000000 +0100 +@@ -156,13 +156,14 @@ void tpmif_disconnect_complete(tpmif_t * + free_tpmif(tpmif); + } + +-void __init tpmif_interface_init(void) ++int __init tpmif_interface_init(void) + { + tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t), + 0, 0, NULL, NULL); ++ return tpmif_cachep ? 0 : -ENOMEM; + } + +-void __exit tpmif_interface_exit(void) ++void tpmif_interface_exit(void) + { + kmem_cache_destroy(tpmif_cachep); + } +--- sle11-2009-05-14.orig/drivers/xen/tpmback/tpmback.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/tpmback/tpmback.c 2009-03-04 11:25:55.000000000 +0100 +@@ -923,22 +923,30 @@ static int __init tpmback_init(void) + spin_lock_init(&tpm_schedule_list_lock); + INIT_LIST_HEAD(&tpm_schedule_list); + +- tpmif_interface_init(); +- tpmif_xenbus_init(); ++ rc = tpmif_interface_init(); ++ if (!rc) { ++ rc = tpmif_xenbus_init(); ++ if (rc) ++ tpmif_interface_exit(); ++ } ++ if (rc) { ++ misc_deregister(&vtpms_miscdevice); ++ return rc; ++ } + + printk(KERN_ALERT "Successfully initialized TPM backend driver.\n"); + + return 0; + } +- + module_init(tpmback_init); + +-void __exit tpmback_exit(void) ++static void __exit tpmback_exit(void) + { + vtpm_release_packets(NULL, 0); + tpmif_xenbus_exit(); + tpmif_interface_exit(); + misc_deregister(&vtpms_miscdevice); + } ++module_exit(tpmback_exit) + + MODULE_LICENSE("Dual BSD/GPL"); +--- sle11-2009-05-14.orig/drivers/xen/tpmback/xenbus.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/tpmback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 +@@ -270,7 +270,6 @@ static const struct xenbus_device_id tpm + + static struct xenbus_driver tpmback = { + .name = "vtpm", +- .owner = THIS_MODULE, + .ids = tpmback_ids, + .probe = tpmback_probe, + .remove = tpmback_remove, +@@ -278,9 +277,9 @@ static struct xenbus_driver tpmback = { + }; + + +-void tpmif_xenbus_init(void) ++int tpmif_xenbus_init(void) + { +- xenbus_register_backend(&tpmback); ++ return xenbus_register_backend(&tpmback); + } + + void tpmif_xenbus_exit(void) +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_probe.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_probe.c 2009-03-04 11:25:55.000000000 +0100 +@@ -365,7 +365,9 @@ static void xenbus_dev_shutdown(struct d + } + + int xenbus_register_driver_common(struct xenbus_driver *drv, +- struct xen_bus_type *bus) ++ struct xen_bus_type *bus, ++ struct module *owner, ++ const char *mod_name) + { + int ret; + +@@ -375,7 +377,10 @@ int xenbus_register_driver_common(struct + drv->driver.name = drv->name; + drv->driver.bus = &bus->bus; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) +- drv->driver.owner = drv->owner; ++ drv->driver.owner = owner; ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) ++ drv->driver.mod_name = mod_name; + #endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) + drv->driver.probe = xenbus_dev_probe; +@@ -389,13 +394,15 @@ int xenbus_register_driver_common(struct + return ret; + } + +-int xenbus_register_frontend(struct xenbus_driver *drv) ++int __xenbus_register_frontend(struct xenbus_driver *drv, ++ struct module *owner, const char *mod_name) + { + int ret; + + drv->read_otherend_details = read_backend_details; + +- ret = xenbus_register_driver_common(drv, &xenbus_frontend); ++ ret = xenbus_register_driver_common(drv, &xenbus_frontend, ++ owner, mod_name); + if (ret) + return ret; + +@@ -404,7 +411,7 @@ int xenbus_register_frontend(struct xenb + + return 0; + } +-EXPORT_SYMBOL_GPL(xenbus_register_frontend); ++EXPORT_SYMBOL_GPL(__xenbus_register_frontend); + + void xenbus_unregister_driver(struct xenbus_driver *drv) + { +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_probe.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_probe.h 2009-03-04 11:25:55.000000000 +0100 +@@ -63,7 +63,9 @@ extern int xenbus_match(struct device *_ + extern int xenbus_dev_probe(struct device *_dev); + extern int xenbus_dev_remove(struct device *_dev); + extern int xenbus_register_driver_common(struct xenbus_driver *drv, +- struct xen_bus_type *bus); ++ struct xen_bus_type *bus, ++ struct module *owner, ++ const char *mod_name); + extern int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, + const char *nodename); +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_probe_backend.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_probe_backend.c 2009-03-04 11:25:55.000000000 +0100 +@@ -172,13 +172,15 @@ static int xenbus_uevent_backend(struct + return 0; + } + +-int xenbus_register_backend(struct xenbus_driver *drv) ++int __xenbus_register_backend(struct xenbus_driver *drv, ++ struct module *owner, const char *mod_name) + { + drv->read_otherend_details = read_frontend_details; + +- return xenbus_register_driver_common(drv, &xenbus_backend); ++ return xenbus_register_driver_common(drv, &xenbus_backend, ++ owner, mod_name); + } +-EXPORT_SYMBOL_GPL(xenbus_register_backend); ++EXPORT_SYMBOL_GPL(__xenbus_register_backend); + + /* backend/// */ + static int xenbus_probe_backend_unit(const char *dir, +--- sle11-2009-05-14.orig/drivers/xen/xenoprof/xenoprofile.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenoprof/xenoprofile.c 2009-03-04 11:25:55.000000000 +0100 +@@ -235,7 +235,7 @@ static int bind_virq(void) + result = bind_virq_to_irqhandler(VIRQ_XENOPROF, + i, + xenoprof_ovf_interrupt, +- SA_INTERRUPT, ++ IRQF_DISABLED|IRQF_NOBALANCING, + "xenoprof", + NULL); + +--- sle11-2009-05-14.orig/include/asm-x86/i8253.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/i8253.h 2009-03-04 11:25:55.000000000 +0100 +@@ -8,10 +8,14 @@ + + extern spinlock_t i8253_lock; + ++#ifdef CONFIG_GENERIC_CLOCKEVENTS ++ + extern struct clock_event_device *global_clock_event; + + extern void setup_pit_timer(void); + ++#endif ++ + #define inb_pit inb_p + #define outb_pit outb_p + +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/desc_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/desc_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -21,7 +21,7 @@ struct Xgt_desc_struct { + + extern struct Xgt_desc_struct idt_descr; + DECLARE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); +- ++extern struct Xgt_desc_struct early_gdt_descr; + + static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) + { +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-04 11:28:11.000000000 +0100 +@@ -158,6 +158,19 @@ static inline void arch_leave_lazy_mmu_m + #define arch_use_lazy_mmu_mode() unlikely(__get_cpu_var(xen_lazy_mmu)) + #endif + ++#if 0 /* All uses are in places potentially called asynchronously, but ++ * asynchronous code should rather not make use of lazy mode at all. ++ * Therefore, all uses of this function get commented out, proper ++ * detection of asynchronous invocations is added whereever needed, ++ * and this function is disabled to catch any new (improper) uses. ++ */ ++static inline void arch_flush_lazy_mmu_mode(void) ++{ ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); ++} ++#endif ++ + #else /* !CONFIG_XEN || MODULE */ + + static inline void xen_multicall_flush(bool ignore) {} +@@ -215,7 +228,7 @@ HYPERVISOR_block( + return rc; + } + +-static inline void /*__noreturn*/ ++static inline void __noreturn + HYPERVISOR_shutdown( + unsigned int reason) + { +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/mmu_context_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/mmu_context_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -27,13 +27,13 @@ static inline void enter_lazy_tlb(struct + static inline void __prepare_arch_switch(void) + { + /* +- * Save away %fs. No need to save %gs, as it was saved on the ++ * Save away %gs. No need to save %fs, as it was saved on the + * stack on entry. No need to save %es and %ds, as those are + * always kernel segments while inside the kernel. + */ +- asm volatile ( "mov %%fs,%0" +- : "=m" (current->thread.fs)); +- asm volatile ( "movl %0,%%fs" ++ asm volatile ( "mov %%gs,%0" ++ : "=m" (current->thread.gs)); ++ asm volatile ( "movl %0,%%gs" + : : "r" (0) ); + } + +@@ -95,7 +95,7 @@ static inline void switch_mm(struct mm_s + } + + #define deactivate_mm(tsk, mm) \ +- asm("movl %0,%%fs": :"r" (0)); ++ asm("movl %0,%%gs": :"r" (0)); + + static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) + { +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgalloc_32.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgalloc_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -6,12 +6,23 @@ + #include /* for struct page */ + #include /* for phys_to_virt and page_to_pseudophys */ + +-#define pmd_populate_kernel(mm, pmd, pte) \ +- set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) ++#define paravirt_alloc_pt(pfn) do { } while (0) ++#define paravirt_alloc_pd(pfn) do { } while (0) ++#define paravirt_alloc_pd(pfn) do { } while (0) ++#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0) ++#define paravirt_release_pt(pfn) do { } while (0) ++#define paravirt_release_pd(pfn) do { } while (0) ++ ++#define pmd_populate_kernel(mm, pmd, pte) \ ++do { \ ++ paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT); \ ++ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \ ++} while (0) + + #define pmd_populate(mm, pmd, pte) \ + do { \ + unsigned long pfn = page_to_pfn(pte); \ ++ paravirt_alloc_pt(pfn); \ + if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) { \ + if (!PageHighMem(pte)) \ + BUG_ON(HYPERVISOR_update_va_mapping( \ +@@ -42,7 +53,11 @@ static inline void pte_free_kernel(pte_t + + extern void pte_free(struct page *pte); + +-#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) ++#define __pte_free_tlb(tlb,pte) \ ++do { \ ++ paravirt_release_pt(page_to_pfn(pte)); \ ++ tlb_remove_page((tlb),(pte)); \ ++} while (0) + + #ifdef CONFIG_X86_PAE + /* +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -275,6 +275,7 @@ static inline pte_t pte_mkhuge(pte_t pte + */ + #define pte_update(mm, addr, ptep) do { } while (0) + #define pte_update_defer(mm, addr, ptep) do { } while (0) ++#define paravirt_map_pt_hook(slot, va, pfn) do { } while (0) + + /* + * We only update the dirty/accessed state if we set +@@ -490,12 +491,24 @@ extern pte_t *lookup_address(unsigned lo + #endif + + #if defined(CONFIG_HIGHPTE) +-#define pte_offset_map(dir, address) \ +- ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + \ +- pte_index(address)) +-#define pte_offset_map_nested(dir, address) \ +- ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + \ +- pte_index(address)) ++#define pte_offset_map(dir, address) \ ++({ \ ++ pte_t *__ptep; \ ++ unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \ ++ __ptep = (pte_t *)kmap_atomic_pte(pfn_to_page(pfn),KM_PTE0); \ ++ paravirt_map_pt_hook(KM_PTE0,__ptep, pfn); \ ++ __ptep = __ptep + pte_index(address); \ ++ __ptep; \ ++}) ++#define pte_offset_map_nested(dir, address) \ ++({ \ ++ pte_t *__ptep; \ ++ unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \ ++ __ptep = (pte_t *)kmap_atomic_pte(pfn_to_page(pfn),KM_PTE1); \ ++ paravirt_map_pt_hook(KM_PTE1,__ptep, pfn); \ ++ __ptep = __ptep + pte_index(address); \ ++ __ptep; \ ++}) + #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) + #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) + #else +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/processor_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/processor_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -431,7 +431,7 @@ struct thread_struct { + .vm86_info = NULL, \ + .sysenter_cs = __KERNEL_CS, \ + .io_bitmap_ptr = NULL, \ +- .gs = __KERNEL_PDA, \ ++ .fs = __KERNEL_PDA, \ + } + + /* +@@ -449,8 +449,8 @@ struct thread_struct { + } + + #define start_thread(regs, new_eip, new_esp) do { \ +- __asm__("movl %0,%%fs": :"r" (0)); \ +- regs->xgs = 0; \ ++ __asm__("movl %0,%%gs": :"r" (0)); \ ++ regs->xfs = 0; \ + set_fs(USER_DS); \ + regs->xds = __USER_DS; \ + regs->xes = __USER_DS; \ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/segment_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/segment_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -83,14 +83,8 @@ + * The GDT has 32 entries + */ + #define GDT_ENTRIES 32 +- + #define GDT_SIZE (GDT_ENTRIES * 8) + +-/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ +-#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) +-/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ +-#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) +- + /* Simple and small GDT entries for booting only */ + + #define GDT_ENTRY_BOOT_CS 2 +@@ -132,4 +126,21 @@ + #define SEGMENT_GDT 0x0 + + #define get_kernel_rpl() (xen_feature(XENFEAT_supervisor_mode_kernel)?0:1) ++ ++/* ++ * Matching rules for certain types of segments. ++ */ ++ ++/* Matches only __KERNEL_CS, ignoring PnP / USER / APM segments */ ++#define SEGMENT_IS_KERNEL_CODE(x) (((x) & ~3) == GDT_ENTRY_KERNEL_CS * 8 \ ++ || ((x) & ~3) == (FLAT_KERNEL_CS & ~3)) ++ ++/* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ ++#define SEGMENT_IS_FLAT_CODE(x) (((x) & ~0x13) == GDT_ENTRY_KERNEL_CS * 8 \ ++ || ((x) & ~3) == (FLAT_KERNEL_CS & ~3) \ ++ || ((x) & ~3) == (FLAT_USER_CS & ~3)) ++ ++/* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ ++#define SEGMENT_IS_PNP_CODE(x) (((x) & ~0x0b) == GDT_ENTRY_PNPBIOS_BASE * 8) ++ + #endif +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/smp_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/smp_32.h 2009-03-04 11:25:55.000000000 +0100 +@@ -52,6 +52,11 @@ extern void cpu_exit_clear(void); + extern void cpu_uninit(void); + #endif + ++#ifndef CONFIG_PARAVIRT ++#define startup_ipi_hook(phys_apicid, start_eip, start_esp) \ ++do { } while (0) ++#endif ++ + /* + * This function is needed by all SMP systems. It must _always_ be valid + * from the initial startup. We map APIC_BASE very early in page_setup(), +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2009-03-04 11:25:55.000000000 +0100 +@@ -9,7 +9,6 @@ + + #include + #include +-#include + + struct dma_mapping_ops { + int (*mapping_error)(dma_addr_t dma_addr); +@@ -67,6 +66,9 @@ static inline int dma_mapping_error(dma_ + #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) + #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) + ++#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) ++#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) ++ + extern void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp); + extern void dma_free_coherent(struct device *dev, size_t size, void *vaddr, +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-04 11:25:55.000000000 +0100 +@@ -416,15 +416,6 @@ static inline int pmd_large(pmd_t pte) { + #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) + #define mk_pte_huge(entry) (__pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE) + +-/* physical address -> PTE */ +-static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) +-{ +- unsigned long pteval; +- pteval = physpage | pgprot_val(pgprot); +- pteval &= __supported_pte_mask; +- return __pte(pteval); +-} +- + /* Change flags of a PTE */ + static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) + { +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/smp_64.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/smp_64.h 2009-03-04 11:25:55.000000000 +0100 +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + extern int disable_apic; + + #ifdef CONFIG_X86_LOCAL_APIC +@@ -73,7 +74,7 @@ extern int __cpu_disable(void); + extern void __cpu_die(unsigned int cpu); + extern void prefill_possible_map(void); + extern unsigned num_processors; +-extern unsigned disabled_cpus; ++extern unsigned __cpuinitdata disabled_cpus; + + #define NO_PROC_ID 0xFF /* No processor magic marker */ + +--- sle11-2009-05-14.orig/include/xen/xenbus.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/xenbus.h 2009-03-04 11:25:55.000000000 +0100 +@@ -93,8 +93,7 @@ struct xenbus_device_id + + /* A xenbus driver. */ + struct xenbus_driver { +- char *name; +- struct module *owner; ++ const char *name; + const struct xenbus_device_id *ids; + int (*probe)(struct xenbus_device *dev, + const struct xenbus_device_id *id); +@@ -115,8 +114,25 @@ static inline struct xenbus_driver *to_x + return container_of(drv, struct xenbus_driver, driver); + } + +-int xenbus_register_frontend(struct xenbus_driver *drv); +-int xenbus_register_backend(struct xenbus_driver *drv); ++int __must_check __xenbus_register_frontend(struct xenbus_driver *drv, ++ struct module *owner, ++ const char *mod_name); ++ ++static inline int __must_check ++xenbus_register_frontend(struct xenbus_driver *drv) ++{ ++ return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME); ++} ++ ++int __must_check __xenbus_register_backend(struct xenbus_driver *drv, ++ struct module *owner, ++ const char *mod_name); ++static inline int __must_check ++xenbus_register_backend(struct xenbus_driver *drv) ++{ ++ return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME); ++} ++ + void xenbus_unregister_driver(struct xenbus_driver *drv); + + struct xenbus_transaction +--- sle11-2009-05-14.orig/lib/swiotlb-xen.c 2009-03-20 10:00:58.000000000 +0100 ++++ sle11-2009-05-14/lib/swiotlb-xen.c 2009-03-04 11:25:55.000000000 +0100 +@@ -135,8 +135,8 @@ __setup("swiotlb=", setup_io_tlb_npages) + * Statically reserve bounce buffer space and initialize bounce buffer data + * structures for the software IO TLB used to implement the PCI DMA API. + */ +-void +-swiotlb_init_with_default_size (size_t default_size) ++void __init ++swiotlb_init_with_default_size(size_t default_size) + { + unsigned long i, bytes; + int rc; +@@ -221,7 +221,7 @@ swiotlb_init_with_default_size (size_t d + dma_bits); + } + +-void ++void __init + swiotlb_init(void) + { + long ram_end; +@@ -457,8 +457,8 @@ swiotlb_full(struct device *dev, size_t + * When the mapping is small enough return a static buffer to limit + * the damage, or panic when the transfer is too big. + */ +- printk(KERN_ERR "PCI-DMA: Out of SW-IOMMU space for %lu bytes at " +- "device %s\n", (unsigned long)size, dev ? dev->bus_id : "?"); ++ printk(KERN_ERR "PCI-DMA: Out of SW-IOMMU space for %zu bytes at " ++ "device %s\n", size, dev ? dev->bus_id : "?"); + + if (size > io_tlb_overflow && do_panic) { + if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) +@@ -602,7 +602,7 @@ swiotlb_map_sg(struct device *hwdev, str + sg[0].dma_length = 0; + return 0; + } +- sg->dma_address = (dma_addr_t)virt_to_bus(map); ++ sg->dma_address = virt_to_bus(map); + } else + sg->dma_address = dev_addr; + sg->dma_length = sg->length; +@@ -624,8 +624,7 @@ swiotlb_unmap_sg(struct device *hwdev, s + + for (i = 0; i < nelems; i++, sg++) + if (in_swiotlb_aperture(sg->dma_address)) +- unmap_single(hwdev, +- (void *)bus_to_virt(sg->dma_address), ++ unmap_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); + else + gnttab_dma_unmap_page(sg->dma_address); +@@ -648,8 +647,7 @@ swiotlb_sync_sg_for_cpu(struct device *h + + for (i = 0; i < nelems; i++, sg++) + if (in_swiotlb_aperture(sg->dma_address)) +- sync_single(hwdev, +- (void *)bus_to_virt(sg->dma_address), ++ sync_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); + } + +@@ -663,8 +661,7 @@ swiotlb_sync_sg_for_device(struct device + + for (i = 0; i < nelems; i++, sg++) + if (in_swiotlb_aperture(sg->dma_address)) +- sync_single(hwdev, +- (void *)bus_to_virt(sg->dma_address), ++ sync_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); + } + diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.22 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.22 new file mode 100644 index 000000000..129c8005d --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.22 @@ -0,0 +1,7551 @@ +From: www.kernel.org +Subject: Update to 2.6.22 +Patch-mainline: 2.6.22 + +Automatically created from "patches.kernel.org/patch-2.6.22" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-04-20.orig/arch/x86/Kconfig 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/Kconfig 2009-02-05 10:22:38.000000000 +0100 +@@ -1433,7 +1433,7 @@ config PHYSICAL_START + + config RELOCATABLE + bool "Build a relocatable kernel (EXPERIMENTAL)" +- depends on EXPERIMENTAL && !X86_XEN ++ depends on EXPERIMENTAL && !X86_XEN && !X86_64_XEN + help + This builds a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. +@@ -1487,7 +1487,6 @@ config COMPAT_VDSO + def_bool y + prompt "Compat VDSO support" + depends on X86_32 || IA32_EMULATION +- depends on !X86_XEN + help + Map the 32-bit VDSO to the predictable old-style address too. + ---help--- +@@ -1666,6 +1665,7 @@ config PCI + bool "PCI support" + default y + select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC) ++ select ARCH_SUPPORTS_MSI if (XEN_UNPRIVILEGED_GUEST && XEN_PCIDEV_FRONTEND) + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside +--- sle11-2009-04-20.orig/arch/x86/kernel/Makefile 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/Makefile 2008-12-15 11:27:22.000000000 +0100 +@@ -127,4 +127,4 @@ endif + disabled-obj-$(CONFIG_XEN) := early-quirks.o hpet.o i8253.o i8259_$(BITS).o reboot.o \ + smpboot_$(BITS).o tsc_$(BITS).o tsc_sync.o + disabled-obj-$(CONFIG_XEN_UNPRIVILEGED_GUEST) += mpparse_64.o +-%/head_$(BITS).o %/head_$(BITS).s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) := ++%/head_64.o %/head_64.s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) := +--- sle11-2009-04-20.orig/arch/x86/kernel/apic_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/apic_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +--- sle11-2009-04-20.orig/arch/x86/kernel/asm-offsets_32.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/asm-offsets_32.c 2008-12-15 11:27:22.000000000 +0100 +@@ -109,11 +109,6 @@ void foo(void) + + OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); + +-#ifdef CONFIG_XEN +- BLANK(); +- OFFSET(XEN_START_mfn_list, start_info, mfn_list); +-#endif +- + #ifdef CONFIG_PARAVIRT + BLANK(); + OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled); +--- sle11-2009-04-20.orig/arch/x86/kernel/cpu/common-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/cpu/common-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -22,16 +22,40 @@ + #define phys_pkg_id(a,b) a + #endif + #endif +-#include + #include + + #include "cpu.h" + +-DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); +-EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); ++DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { ++ [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, ++ [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, ++ [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, ++ [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, ++#ifndef CONFIG_XEN ++ /* ++ * Segments used for calling PnP BIOS have byte granularity. ++ * They code segments and data segments have fixed 64k limits, ++ * the transfer segment sizes are set at run time. ++ */ ++ [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ ++ [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ ++ [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ ++ [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ ++ [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ ++ /* ++ * The APM segments have byte granularity and their bases ++ * are set at run time. All have 64k limits. ++ */ ++ [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ ++ /* 16-bit code */ ++ [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 }, ++ [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ + +-struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly; +-EXPORT_SYMBOL(_cpu_pda); ++ [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, ++#endif ++ [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 }, ++} }; ++EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); + + static int cachesize_override __cpuinitdata = -1; + static int disable_x86_fxsr __cpuinitdata; +@@ -373,7 +397,7 @@ __setup("serialnumber", x86_serial_nr_se + /* + * This does the hard work of actually picking apart the CPU stuff... + */ +-void __cpuinit identify_cpu(struct cpuinfo_x86 *c) ++static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) + { + int i; + +@@ -484,15 +508,22 @@ void __cpuinit identify_cpu(struct cpuin + + /* Init Machine Check Exception if available. */ + mcheck_init(c); ++} + +- if (c == &boot_cpu_data) +- sysenter_setup(); ++void __init identify_boot_cpu(void) ++{ ++ identify_cpu(&boot_cpu_data); ++ sysenter_setup(); + enable_sep_cpu(); ++ mtrr_bp_init(); ++} + +- if (c == &boot_cpu_data) +- mtrr_bp_init(); +- else +- mtrr_ap_init(); ++void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) ++{ ++ BUG_ON(c == &boot_cpu_data); ++ identify_cpu(c); ++ enable_sep_cpu(); ++ mtrr_ap_init(); + } + + #ifdef CONFIG_X86_HT +@@ -606,136 +637,47 @@ void __init early_cpu_init(void) + #endif + } + +-/* Make sure %gs is initialized properly in idle threads */ ++/* Make sure %fs is initialized properly in idle threads */ + struct pt_regs * __devinit idle_regs(struct pt_regs *regs) + { + memset(regs, 0, sizeof(struct pt_regs)); +- regs->xfs = __KERNEL_PDA; ++ regs->xfs = __KERNEL_PERCPU; + return regs; + } + +-static __cpuinit int alloc_gdt(int cpu) ++/* Current gdt points %fs at the "master" per-cpu area: after this, ++ * it's on the real one. */ ++void switch_to_new_gdt(void) + { +- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); +- struct desc_struct *gdt; +- struct i386_pda *pda; +- +- gdt = (struct desc_struct *)cpu_gdt_descr->address; +- pda = cpu_pda(cpu); +- +- /* +- * This is a horrible hack to allocate the GDT. The problem +- * is that cpu_init() is called really early for the boot CPU +- * (and hence needs bootmem) but much later for the secondary +- * CPUs, when bootmem will have gone away +- */ +- if (NODE_DATA(0)->bdata->node_bootmem_map) { +- BUG_ON(gdt != NULL || pda != NULL); +- +- gdt = alloc_bootmem_pages(PAGE_SIZE); +- pda = alloc_bootmem(sizeof(*pda)); +- /* alloc_bootmem(_pages) panics on failure, so no check */ +- +- memset(gdt, 0, PAGE_SIZE); +- memset(pda, 0, sizeof(*pda)); +- } else { +- /* GDT and PDA might already have been allocated if +- this is a CPU hotplug re-insertion. */ +- if (gdt == NULL) +- gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); +- +- if (pda == NULL) +- pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu)); +- +- if (unlikely(!gdt || !pda)) { +- free_pages((unsigned long)gdt, 0); +- kfree(pda); +- return 0; +- } +- } +- +- cpu_gdt_descr->address = (unsigned long)gdt; +- cpu_pda(cpu) = pda; +- +- return 1; +-} +- +-/* Initial PDA used by boot CPU */ +-struct i386_pda boot_pda = { +- ._pda = &boot_pda, +- .cpu_number = 0, +- .pcurrent = &init_task, +-}; +- +-static inline void set_kernel_fs(void) +-{ +- /* Set %fs for this CPU's PDA. Memory clobber is to create a +- barrier with respect to any PDA operations, so the compiler +- doesn't move any before here. */ +- asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory"); +-} +- +-/* Initialize the CPU's GDT and PDA. The boot CPU does this for +- itself, but secondaries find this done for them. */ +-__cpuinit int init_gdt(int cpu, struct task_struct *idle) +-{ +- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); +- struct desc_struct *gdt; +- struct i386_pda *pda; +- +- /* For non-boot CPUs, the GDT and PDA should already have been +- allocated. */ +- if (!alloc_gdt(cpu)) { +- printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu); +- return 0; +- } +- +- gdt = (struct desc_struct *)cpu_gdt_descr->address; +- pda = cpu_pda(cpu); +- +- BUG_ON(gdt == NULL || pda == NULL); +- +- /* +- * Initialize the per-CPU GDT with the boot GDT, +- * and set up the GDT descriptor: +- */ +- memcpy(gdt, cpu_gdt_table, GDT_SIZE); +- cpu_gdt_descr->size = GDT_SIZE - 1; +- +- pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a, +- (u32 *)&gdt[GDT_ENTRY_PDA].b, +- (unsigned long)pda, sizeof(*pda) - 1, +- 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */ +- +- memset(pda, 0, sizeof(*pda)); +- pda->_pda = pda; +- pda->cpu_number = cpu; +- pda->pcurrent = idle; +- +- return 1; +-} +- +-void __cpuinit cpu_set_gdt(int cpu) +-{ +- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ struct Xgt_desc_struct gdt_descr; + unsigned long va, frames[16]; + int f; + +- for (va = cpu_gdt_descr->address, f = 0; +- va < cpu_gdt_descr->address + cpu_gdt_descr->size; ++ gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); ++ gdt_descr.size = GDT_SIZE - 1; ++ ++ for (va = gdt_descr.address, f = 0; ++ va < gdt_descr.address + gdt_descr.size; + va += PAGE_SIZE, f++) { + frames[f] = virt_to_mfn(va); + make_lowmem_page_readonly( + (void *)va, XENFEAT_writable_descriptor_tables); + } +- BUG_ON(HYPERVISOR_set_gdt(frames, (cpu_gdt_descr->size + 1) / 8)); +- +- set_kernel_fs(); ++ if (HYPERVISOR_set_gdt(frames, (gdt_descr.size + 1) / 8)) ++ BUG(); ++ asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory"); + } + +-/* Common CPU init for both boot and secondary CPUs */ +-static void __cpuinit _cpu_init(int cpu, struct task_struct *curr) ++/* ++ * cpu_init() initializes state that is per-CPU. Some data is already ++ * initialized (naturally) in the bootstrap process, such as the GDT ++ * and IDT. We reload them nevertheless, this function acts as a ++ * 'CPU state barrier', nothing should get across. ++ */ ++void __cpuinit cpu_init(void) + { ++ int cpu = smp_processor_id(); ++ struct task_struct *curr = current; + #ifndef CONFIG_X86_NO_TSS + struct tss_struct * t = &per_cpu(init_tss, cpu); + #endif +@@ -757,6 +699,8 @@ static void __cpuinit _cpu_init(int cpu, + set_in_cr4(X86_CR4_TSD); + } + ++ switch_to_new_gdt(); ++ + /* + * Set up and load the per-CPU TSS and LDT + */ +@@ -794,38 +738,6 @@ static void __cpuinit _cpu_init(int cpu, + mxcsr_feature_mask_init(); + } + +-/* Entrypoint to initialize secondary CPU */ +-void __cpuinit secondary_cpu_init(void) +-{ +- int cpu = smp_processor_id(); +- struct task_struct *curr = current; +- +- _cpu_init(cpu, curr); +-} +- +-/* +- * cpu_init() initializes state that is per-CPU. Some data is already +- * initialized (naturally) in the bootstrap process, such as the GDT +- * and IDT. We reload them nevertheless, this function acts as a +- * 'CPU state barrier', nothing should get across. +- */ +-void __cpuinit cpu_init(void) +-{ +- int cpu = smp_processor_id(); +- struct task_struct *curr = current; +- +- /* Set up the real GDT and PDA, so we can transition from the +- boot versions. */ +- if (!init_gdt(cpu, curr)) { +- /* failed to allocate something; not much we can do... */ +- for (;;) +- local_irq_enable(); +- } +- +- cpu_set_gdt(cpu); +- _cpu_init(cpu, curr); +-} +- + #ifdef CONFIG_HOTPLUG_CPU + void __cpuinit cpu_uninit(void) + { +--- sle11-2009-04-20.orig/arch/x86/kernel/cpu/mtrr/main-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/cpu/mtrr/main-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -167,7 +167,7 @@ mtrr_del(int reg, unsigned long base, un + EXPORT_SYMBOL(mtrr_add); + EXPORT_SYMBOL(mtrr_del); + +-void __init mtrr_bp_init(void) ++__init void mtrr_bp_init(void) + { + } + +--- sle11-2009-04-20.orig/arch/x86/kernel/e820_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/e820_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -162,26 +162,27 @@ static struct resource standard_io_resou + + static int __init romsignature(const unsigned char *rom) + { ++ const unsigned short * const ptr = (const unsigned short *)rom; + unsigned short sig; + +- return probe_kernel_address((const unsigned short *)rom, sig) == 0 && +- sig == ROMSIGNATURE; ++ return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; + } + +-static int __init romchecksum(unsigned char *rom, unsigned long length) ++static int __init romchecksum(const unsigned char *rom, unsigned long length) + { +- unsigned char sum; ++ unsigned char sum, c; + +- for (sum = 0; length; length--) +- sum += *rom++; +- return sum == 0; ++ for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) ++ sum += c; ++ return !length && !sum; + } + + static void __init probe_roms(void) + { ++ const unsigned char *rom; + unsigned long start, length, upper; +- unsigned char *rom; +- int i; ++ unsigned char c; ++ int i; + + #ifdef CONFIG_XEN + /* Nothing to do if not running in dom0. */ +@@ -198,8 +199,11 @@ static void __init probe_roms(void) + + video_rom_resource.start = start; + ++ if (probe_kernel_address(rom + 2, c) != 0) ++ continue; ++ + /* 0 < length <= 0x7f * 512, historically */ +- length = rom[2] * 512; ++ length = c * 512; + + /* if checksum okay, trust length byte */ + if (length && romchecksum(rom, length)) +@@ -233,8 +237,11 @@ static void __init probe_roms(void) + if (!romsignature(rom)) + continue; + ++ if (probe_kernel_address(rom + 2, c) != 0) ++ continue; ++ + /* 0 < length <= 0x7f * 512, historically */ +- length = rom[2] * 512; ++ length = c * 512; + + /* but accept any length that fits if checksum okay */ + if (!length || start + length > upper || !romchecksum(rom, length)) +@@ -249,7 +256,7 @@ static void __init probe_roms(void) + } + + #ifdef CONFIG_XEN +-static struct e820map machine_e820 __initdata; ++static struct e820map machine_e820; + #define e820 machine_e820 + #endif + +@@ -409,10 +416,8 @@ int __init sanitize_e820_map(struct e820 + ____________________33__ + ______________________4_ + */ +- printk("sanitize start\n"); + /* if there's only one memory region, don't bother */ + if (*pnr_map < 2) { +- printk("sanitize bail 0\n"); + return -1; + } + +@@ -421,7 +426,6 @@ int __init sanitize_e820_map(struct e820 + /* bail out if we find any unreasonable addresses in bios map */ + for (i=0; isize; + unsigned long long end = start + size; + unsigned long type = biosmap->type; +- printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type); + + /* Overflow in 64 bits? Ignore the memory map. */ + if (start > end) +@@ -564,17 +566,11 @@ int __init copy_e820_map(struct e820entr + * Not right. Fix it up. + */ + if (type == E820_RAM) { +- printk("copy_e820_map() type is E820_RAM\n"); + if (start < 0x100000ULL && end > 0xA0000ULL) { +- printk("copy_e820_map() lies in range...\n"); +- if (start < 0xA0000ULL) { +- printk("copy_e820_map() start < 0xA0000ULL\n"); ++ if (start < 0xA0000ULL) + add_memory_region(start, 0xA0000ULL-start, type); +- } +- if (end <= 0x100000ULL) { +- printk("copy_e820_map() end <= 0x100000ULL\n"); ++ if (end <= 0x100000ULL) + continue; +- } + start = 0x100000ULL; + size = end - start; + } +--- sle11-2009-04-20.orig/arch/x86/kernel/entry_32-xen.S 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/entry_32-xen.S 2008-12-15 11:27:22.000000000 +0100 +@@ -15,7 +15,7 @@ + * I changed all the .align's to 4 (16 byte alignment), as that's faster + * on a 486. + * +- * Stack layout in 'ret_from_system_call': ++ * Stack layout in 'syscall_exit': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in fork.c:copy_process, signal.c:do_signal, +@@ -135,7 +135,7 @@ NMI_MASK = 0x80000000 + movl $(__USER_DS), %edx; \ + movl %edx, %ds; \ + movl %edx, %es; \ +- movl $(__KERNEL_PDA), %edx; \ ++ movl $(__KERNEL_PERCPU), %edx; \ + movl %edx, %fs + + #define RESTORE_INT_REGS \ +@@ -308,16 +308,12 @@ sysenter_past_esp: + pushl $(__USER_CS) + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET cs, 0*/ +-#ifndef CONFIG_COMPAT_VDSO + /* + * Push current_thread_info()->sysenter_return to the stack. + * A tiny bit of offset fixup is necessary - 4*4 means the 4 words + * pushed above; +8 corresponds to copy_thread's esp0 setting. + */ + pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) +-#else +- pushl $SYSENTER_RETURN +-#endif + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET eip, 0 + +@@ -345,7 +341,7 @@ sysenter_past_esp: + jae syscall_badsys + call *sys_call_table(,%eax,4) + movl %eax,PT_EAX(%esp) +- DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX) ++ DISABLE_INTERRUPTS(CLBR_ANY) + TRACE_IRQS_OFF + movl TI_flags(%ebp), %ecx + testw $_TIF_ALLWORK_MASK, %cx +@@ -400,10 +396,6 @@ ENTRY(system_call) + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + GET_THREAD_INFO(%ebp) +- testl $TF_MASK,PT_EFLAGS(%esp) +- jz no_singlestep +- orl $_TIF_SINGLESTEP,TI_flags(%ebp) +-no_singlestep: + # system call tracing in operation / emulation + /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ + testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) +@@ -418,6 +410,10 @@ syscall_exit: + # setting need_resched or sigpending + # between sampling and the iret + TRACE_IRQS_OFF ++ testl $TF_MASK,PT_EFLAGS(%esp) # If tracing set singlestep flag on exit ++ jz no_singlestep ++ orl $_TIF_SINGLESTEP,TI_flags(%ebp) ++no_singlestep: + movl TI_flags(%ebp), %ecx + testw $_TIF_ALLWORK_MASK, %cx # current->work + jne syscall_exit_work +@@ -635,9 +631,7 @@ END(syscall_badsys) + #ifndef CONFIG_XEN + #define FIXUP_ESPFIX_STACK \ + /* since we are on a wrong stack, we cant make it a C code :( */ \ +- movl %fs:PDA_cpu, %ebx; \ +- PER_CPU(cpu_gdt_descr, %ebx); \ +- movl GDS_address(%ebx), %ebx; \ ++ PER_CPU(gdt_page, %ebx); \ + GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ + addl %esp, %eax; \ + pushl $__KERNEL_DS; \ +@@ -710,7 +704,7 @@ ENTRY(name) \ + SAVE_ALL; \ + TRACE_IRQS_OFF \ + movl %esp,%eax; \ +- call smp_/**/name; \ ++ call smp_##name; \ + jmp ret_from_intr; \ + CFI_ENDPROC; \ + ENDPROC(name) +@@ -718,10 +712,6 @@ ENDPROC(name) + /* The include is where all of the SMP etc. interrupts come from */ + #include "entry_arch.h" + +-/* This alternate entry is needed because we hijack the apic LVTT */ +-#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC) +-BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR) +-#endif + #else + #define UNWIND_ESPFIX_STACK + #endif +@@ -764,7 +754,7 @@ error_code: + pushl %fs + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET fs, 0*/ +- movl $(__KERNEL_PDA), %ecx ++ movl $(__KERNEL_PERCPU), %ecx + movl %ecx, %fs + UNWIND_ESPFIX_STACK + popl %ecx +--- sle11-2009-04-20.orig/arch/x86/kernel/head_32-xen.S 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/head_32-xen.S 2008-12-15 11:27:22.000000000 +0100 +@@ -37,7 +37,8 @@ ENTRY(startup_32) + /* Set up the stack pointer */ + movl $(init_thread_union+THREAD_SIZE),%esp + +- call setup_pda ++ movl %ss,%eax ++ movl %eax,%fs # gets reset once there's real percpu + + /* get vendor info */ + xorl %eax,%eax # call CPUID with 0 -> return vendor ID +@@ -64,55 +65,11 @@ ENTRY(startup_32) + xorl %eax,%eax # Clear GS + movl %eax,%gs + +- movl $(__KERNEL_PDA),%eax +- mov %eax,%fs +- + cld # gcc2 wants the direction flag cleared at all times + + pushl $0 # fake return address for unwinder + jmp start_kernel + +-/* +- * Point the GDT at this CPU's PDA. This will be +- * cpu_gdt_table and boot_pda. +- */ +-ENTRY(setup_pda) +- /* get the PDA pointer */ +- movl $boot_pda, %eax +- +- /* slot the PDA address into the GDT */ +- mov $cpu_gdt_table, %ecx +- mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */ +- shr $16, %eax +- mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */ +- mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */ +- +- # %esi still points to start_info, and no registers +- # need to be preserved. +- +- movl XEN_START_mfn_list(%esi), %ebx +- movl $(cpu_gdt_table - __PAGE_OFFSET), %eax +- shrl $PAGE_SHIFT, %eax +- movl (%ebx,%eax,4), %ecx +- pushl %ecx # frame number for set_gdt below +- +- xorl %esi, %esi +- xorl %edx, %edx +- shldl $PAGE_SHIFT, %ecx, %edx +- shll $PAGE_SHIFT, %ecx +- orl $0x61, %ecx +- movl $cpu_gdt_table, %ebx +- movl $__HYPERVISOR_update_va_mapping, %eax +- int $0x82 +- +- movl $(PAGE_SIZE_asm / 8), %ecx +- movl %esp, %ebx +- movl $__HYPERVISOR_set_gdt, %eax +- int $0x82 +- +- popl %ecx +- ret +- + #define HYPERCALL_PAGE_OFFSET 0x1000 + .org HYPERCALL_PAGE_OFFSET + ENTRY(hypercall_page) +@@ -138,60 +95,6 @@ ENTRY(empty_zero_page) + */ + .data + +-/* +- * The Global Descriptor Table contains 28 quadwords, per-CPU. +- */ +- .section .data.page_aligned, "aw" +- .align PAGE_SIZE_asm +-ENTRY(cpu_gdt_table) +- .quad 0x0000000000000000 /* NULL descriptor */ +- .quad 0x0000000000000000 /* 0x0b reserved */ +- .quad 0x0000000000000000 /* 0x13 reserved */ +- .quad 0x0000000000000000 /* 0x1b reserved */ +- .quad 0x0000000000000000 /* 0x20 unused */ +- .quad 0x0000000000000000 /* 0x28 unused */ +- .quad 0x0000000000000000 /* 0x33 TLS entry 1 */ +- .quad 0x0000000000000000 /* 0x3b TLS entry 2 */ +- .quad 0x0000000000000000 /* 0x43 TLS entry 3 */ +- .quad 0x0000000000000000 /* 0x4b reserved */ +- .quad 0x0000000000000000 /* 0x53 reserved */ +- .quad 0x0000000000000000 /* 0x5b reserved */ +- +- .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */ +- .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */ +- .quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */ +- .quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */ +- +- .quad 0x0000000000000000 /* 0x80 TSS descriptor */ +- .quad 0x0000000000000000 /* 0x88 LDT descriptor */ +- +- /* +- * Segments used for calling PnP BIOS have byte granularity. +- * They code segments and data segments have fixed 64k limits, +- * the transfer segment sizes are set at run time. +- */ +- .quad 0x0000000000000000 /* 0x90 32-bit code */ +- .quad 0x0000000000000000 /* 0x98 16-bit code */ +- .quad 0x0000000000000000 /* 0xa0 16-bit data */ +- .quad 0x0000000000000000 /* 0xa8 16-bit data */ +- .quad 0x0000000000000000 /* 0xb0 16-bit data */ +- +- /* +- * The APM segments have byte granularity and their bases +- * are set at run time. All have 64k limits. +- */ +- .quad 0x0000000000000000 /* 0xb8 APM CS code */ +- .quad 0x0000000000000000 /* 0xc0 APM CS 16 code (16 bit) */ +- .quad 0x0000000000000000 /* 0xc8 APM DS data */ +- +- .quad 0x0000000000000000 /* 0xd0 - ESPFIX SS */ +- .quad 0x00cf92000000ffff /* 0xd8 - PDA */ +- .quad 0x0000000000000000 /* 0xe0 - unused */ +- .quad 0x0000000000000000 /* 0xe8 - unused */ +- .quad 0x0000000000000000 /* 0xf0 - unused */ +- .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ +- .align PAGE_SIZE_asm +- + #if CONFIG_XEN_COMPAT <= 0x030002 + /* + * __xen_guest information +--- sle11-2009-04-20.orig/arch/x86/kernel/io_apic_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/io_apic_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -35,6 +34,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -710,8 +710,6 @@ static int balanced_irq(void *unused) + unsigned long prev_balance_time = jiffies; + long time_remaining = balanced_irq_interval; + +- daemonize("kirqd"); +- + /* push everything to CPU 0 to give us a starting point. */ + for (i = 0 ; i < NR_IRQS ; i++) { + irq_desc[i].pending_mask = cpumask_of_cpu(0); +@@ -771,10 +769,9 @@ static int __init balanced_irq_init(void + } + + printk(KERN_INFO "Starting balanced_irq\n"); +- if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) ++ if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd"))) + return 0; +- else +- printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); ++ printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); + failed: + for_each_possible_cpu(i) { + kfree(irq_cpu_data[i].irq_delta); +@@ -1455,10 +1452,6 @@ static void __init setup_ExtINT_IRQ0_pin + enable_8259A_irq(0); + } + +-static inline void UNEXPECTED_IO_APIC(void) +-{ +-} +- + void __init print_IO_APIC(void) + { + int apic, i; +@@ -1498,34 +1491,12 @@ void __init print_IO_APIC(void) + printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); + printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); + printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); +- if (reg_00.bits.ID >= get_physical_broadcast()) +- UNEXPECTED_IO_APIC(); +- if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) +- UNEXPECTED_IO_APIC(); + + printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw); + printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); +- if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ +- (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ +- (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ +- (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ +- (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ +- (reg_01.bits.entries != 0x2E) && +- (reg_01.bits.entries != 0x3F) +- ) +- UNEXPECTED_IO_APIC(); + + printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); + printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); +- if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ +- (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ +- (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ +- (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ +- (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ +- ) +- UNEXPECTED_IO_APIC(); +- if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) +- UNEXPECTED_IO_APIC(); + + /* + * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02, +@@ -1535,8 +1506,6 @@ void __init print_IO_APIC(void) + if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) { + printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); + printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); +- if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) +- UNEXPECTED_IO_APIC(); + } + + /* +@@ -1548,8 +1517,6 @@ void __init print_IO_APIC(void) + reg_03.raw != reg_01.raw) { + printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw); + printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT); +- if (reg_03.bits.__reserved_1) +- UNEXPECTED_IO_APIC(); + } + + printk(KERN_DEBUG ".... IRQ redirection table:\n"); +@@ -2686,19 +2653,19 @@ int arch_setup_msi_irq(struct pci_dev *d + if (irq < 0) + return irq; + +- set_irq_msi(irq, desc); + ret = msi_compose_msg(dev, irq, &msg); + if (ret < 0) { + destroy_irq(irq); + return ret; + } + ++ set_irq_msi(irq, desc); + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, + "edge"); + +- return irq; ++ return 0; + } + + void arch_teardown_msi_irq(unsigned int irq) +--- sle11-2009-04-20.orig/arch/x86/kernel/ioport_32-xen.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/arch/x86/kernel/ioport_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -12,10 +12,10 @@ + #include + #include + #include +-#include + #include + #include + #include ++#include + #include + + /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +--- sle11-2009-04-20.orig/arch/x86/kernel/irq_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/irq_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -24,6 +24,9 @@ + DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; + EXPORT_PER_CPU_SYMBOL(irq_stat); + ++DEFINE_PER_CPU(struct pt_regs *, irq_regs); ++EXPORT_PER_CPU_SYMBOL(irq_regs); ++ + /* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves. +--- sle11-2009-04-20.orig/arch/x86/kernel/ldt_32-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/ldt_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + +--- sle11-2009-04-20.orig/arch/x86/kernel/microcode-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/microcode-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -135,7 +135,7 @@ static int __init microcode_dev_init (vo + return 0; + } + +-static void __exit microcode_dev_exit (void) ++static void microcode_dev_exit (void) + { + misc_deregister(µcode_dev); + } +--- sle11-2009-04-20.orig/arch/x86/kernel/mpparse_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/mpparse_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -484,7 +483,7 @@ static int __init smp_read_mpc(struct mp + } + ++mpc_record; + } +- clustered_apic_check(); ++ setup_apic_routing(); + if (!num_processors) + printk(KERN_ERR "SMP mptable: no processors registered!\n"); + return num_processors; +--- sle11-2009-04-20.orig/arch/x86/kernel/pci-dma-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/pci-dma-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -278,7 +279,7 @@ int dma_declare_coherent_memory(struct d + { + void __iomem *mem_base = NULL; + int pages = size >> PAGE_SHIFT; +- int bitmap_size = (pages + 31)/32; ++ int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); + + if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) + goto out; +@@ -351,6 +352,32 @@ void *dma_mark_declared_memory_occupied( + EXPORT_SYMBOL(dma_mark_declared_memory_occupied); + #endif /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */ + ++#if defined(CONFIG_PCI) && !defined(CONFIG_XEN) ++/* Many VIA bridges seem to corrupt data for DAC. Disable it here */ ++ ++int forbid_dac; ++EXPORT_SYMBOL(forbid_dac); ++ ++static __devinit void via_no_dac(struct pci_dev *dev) ++{ ++ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) { ++ printk(KERN_INFO "PCI: VIA PCI bridge detected. Disabling DAC.\n"); ++ forbid_dac = 1; ++ } ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_ANY_ID, via_no_dac); ++ ++static int check_iommu(char *s) ++{ ++ if (!strcmp(s, "usedac")) { ++ forbid_dac = -1; ++ return 1; ++ } ++ return 0; ++} ++__setup("iommu=", check_iommu); ++#endif ++ + dma_addr_t + dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction direction) +--- sle11-2009-04-20.orig/arch/x86/kernel/process_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/process_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -21,7 +21,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -39,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -61,7 +61,6 @@ + + #include + #include +-#include + + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +@@ -70,6 +69,12 @@ static int hlt_counter; + unsigned long boot_option_idle_override = 0; + EXPORT_SYMBOL(boot_option_idle_override); + ++DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; ++EXPORT_PER_CPU_SYMBOL(current_task); ++ ++DEFINE_PER_CPU(int, cpu_number); ++EXPORT_PER_CPU_SYMBOL(cpu_number); ++ + /* + * Return saved PC of a blocked thread. + */ +@@ -168,6 +173,7 @@ void cpu_idle(void) + if (__get_cpu_var(cpu_idle_state)) + __get_cpu_var(cpu_idle_state) = 0; + ++ check_pgt_cache(); + rmb(); + idle = xen_idle; /* no alternatives */ + +@@ -218,18 +224,19 @@ void __devinit select_idle_routine(const + { + } + +-static int __init idle_setup (char *str) ++static int __init idle_setup(char *str) + { +- if (!strncmp(str, "poll", 4)) { ++ if (!strcmp(str, "poll")) { + printk("using polling idle threads.\n"); + pm_idle = poll_idle; + } ++ else ++ return -1; + + boot_option_idle_override = 1; +- return 1; ++ return 0; + } +- +-__setup("idle=", idle_setup); ++early_param("idle", idle_setup); + + void show_regs(struct pt_regs * regs) + { +@@ -282,7 +289,7 @@ int kernel_thread(int (*fn)(void *), voi + + regs.xds = __USER_DS; + regs.xes = __USER_DS; +- regs.xfs = __KERNEL_PDA; ++ regs.xfs = __KERNEL_PERCPU; + regs.orig_eax = -1; + regs.eip = (unsigned long) kernel_thread_helper; + regs.xcs = __KERNEL_CS | get_kernel_rpl(); +@@ -562,7 +569,7 @@ struct task_struct fastcall * __switch_t + * multicall to indicate FPU task switch, rather than + * synchronously trapping to Xen. + */ +- if (prev_p->thread_info->status & TS_USEDFPU) { ++ if (task_thread_info(prev_p)->status & TS_USEDFPU) { + __save_init_fpu(prev_p); /* _not_ save_init_fpu() */ + mcl->op = __HYPERVISOR_fpu_taskswitch; + mcl->args[0] = 1; +@@ -669,7 +676,7 @@ struct task_struct fastcall * __switch_t + if (prev->gs | next->gs) + loadsegment(gs, next->gs); + +- write_pda(pcurrent, next_p); ++ x86_write_percpu(current_task, next_p); + + return prev_p; + } +--- sle11-2009-04-20.orig/arch/x86/kernel/quirks-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/quirks-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -3,12 +3,10 @@ + */ + #include + #include +-#include +-#include +-#include + + #if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_SMP) || defined(CONFIG_XEN)) && defined(CONFIG_PCI) +-static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev) ++ ++static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) + { + u8 config, rev; + u32 word; +@@ -16,7 +14,7 @@ static void __devinit verify_quirk_intel + /* BIOS may enable hardware IRQ balancing for + * E7520/E7320/E7525(revision ID 0x9 and below) + * based platforms. +- * For those platforms, make sure that the genapic is set to 'flat' ++ * Disable SW irqbalance/affinity on those platforms. + */ + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev > 0x9) +@@ -30,59 +28,20 @@ static void __devinit verify_quirk_intel + raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); + + if (!(word & (1 << 13))) { +-#ifndef CONFIG_XEN +-#ifdef CONFIG_X86_64 +- if (genapic != &apic_flat) +- panic("APIC mode must be flat on this system\n"); +-#elif defined(CONFIG_X86_GENERICARCH) +- if (genapic != &apic_default) +- panic("APIC mode must be default(flat) on this system. Use apic=default\n"); +-#endif +-#endif +- } +- +- /* put back the original value for config space*/ +- if (!(config & 0x2)) +- pci_write_config_byte(dev, 0xf4, config); +-} +- +-void __init quirk_intel_irqbalance(void) +-{ +- u8 config, rev; +- u32 word; +- +- /* BIOS may enable hardware IRQ balancing for +- * E7520/E7320/E7525(revision ID 0x9 and below) +- * based platforms. +- * Disable SW irqbalance/affinity on those platforms. +- */ +- rev = read_pci_config_byte(0, 0, 0, PCI_CLASS_REVISION); +- if (rev > 0x9) +- return; +- +- printk(KERN_INFO "Intel E7520/7320/7525 detected."); +- +- /* enable access to config space */ +- config = read_pci_config_byte(0, 0, 0, 0xf4); +- write_pci_config_byte(0, 0, 0, 0xf4, config|0x2); +- +- /* read xTPR register */ +- word = read_pci_config_16(0, 0, 0x40, 0x4c); +- +- if (!(word & (1 << 13))) { + struct xen_platform_op op; +- printk(KERN_INFO "Disabling irq balancing and affinity\n"); ++ ++ printk(KERN_INFO "Intel E7520/7320/7525 detected. " ++ "Disabling irq balancing and affinity\n"); + op.cmd = XENPF_platform_quirk; + op.u.platform_quirk.quirk_id = QUIRK_NOIRQBALANCING; + WARN_ON(HYPERVISOR_platform_op(&op)); + } + +- /* put back the original value for config space */ ++ /* put back the original value for config space*/ + if (!(config & 0x2)) +- write_pci_config_byte(0, 0, 0, 0xf4, config); ++ pci_write_config_byte(dev, 0xf4, config); + } +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, verify_quirk_intel_irqbalance); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, verify_quirk_intel_irqbalance); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, verify_quirk_intel_irqbalance); +- ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); + #endif +--- sle11-2009-04-20.orig/arch/x86/kernel/smp_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/smp_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -216,7 +215,6 @@ static cpumask_t flush_cpumask; + static struct mm_struct * flush_mm; + static unsigned long flush_va; + static DEFINE_SPINLOCK(tlbstate_lock); +-#define FLUSH_ALL 0xffffffff + + /* + * We cannot call mmdrop() because we are in interrupt context, +@@ -298,7 +296,7 @@ irqreturn_t smp_invalidate_interrupt(int + + if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { +- if (flush_va == FLUSH_ALL) ++ if (flush_va == TLB_FLUSH_ALL) + local_flush_tlb(); + else + __flush_tlb_one(flush_va); +@@ -314,9 +312,11 @@ out: + return IRQ_HANDLED; + } + +-static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, +- unsigned long va) ++void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, ++ unsigned long va) + { ++ cpumask_t cpumask = *cpumaskp; ++ + /* + * A couple of (to be removed) sanity checks: + * +@@ -327,10 +327,12 @@ static void flush_tlb_others(cpumask_t c + BUG_ON(cpu_isset(smp_processor_id(), cpumask)); + BUG_ON(!mm); + ++#ifdef CONFIG_HOTPLUG_CPU + /* If a CPU which we ran on has gone down, OK. */ + cpus_and(cpumask, cpumask, cpu_online_map); +- if (cpus_empty(cpumask)) ++ if (unlikely(cpus_empty(cpumask))) + return; ++#endif + + /* + * i'm not happy about this global shared spinlock in the +@@ -341,17 +343,7 @@ static void flush_tlb_others(cpumask_t c + + flush_mm = mm; + flush_va = va; +-#if NR_CPUS <= BITS_PER_LONG +- atomic_set_mask(cpumask, &flush_cpumask); +-#else +- { +- int k; +- unsigned long *flush_mask = (unsigned long *)&flush_cpumask; +- unsigned long *cpu_mask = (unsigned long *)&cpumask; +- for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k) +- atomic_set_mask(cpu_mask[k], &flush_mask[k]); +- } +-#endif ++ cpus_or(flush_cpumask, cpumask, flush_cpumask); + /* + * We have to send the IPI only to + * CPUs affected. +@@ -378,7 +370,7 @@ void flush_tlb_current_task(void) + + local_flush_tlb(); + if (!cpus_empty(cpu_mask)) +- flush_tlb_others(cpu_mask, mm, FLUSH_ALL); ++ flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); + preempt_enable(); + } + +@@ -397,7 +389,7 @@ void flush_tlb_mm (struct mm_struct * mm + leave_mm(smp_processor_id()); + } + if (!cpus_empty(cpu_mask)) +- flush_tlb_others(cpu_mask, mm, FLUSH_ALL); ++ flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); + + preempt_enable(); + } +@@ -446,7 +438,7 @@ void flush_tlb_all(void) + * it goes straight through and wastes no time serializing + * anything. Worst case is that we lose a reschedule ... + */ +-void smp_send_reschedule(int cpu) ++void xen_smp_send_reschedule(int cpu) + { + WARN_ON(cpu_is_offline(cpu)); + send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); +@@ -478,36 +470,79 @@ void unlock_ipi_call_lock(void) + + static struct call_data_struct *call_data; + ++static void __smp_call_function(void (*func) (void *info), void *info, ++ int nonatomic, int wait) ++{ ++ struct call_data_struct data; ++ int cpus = num_online_cpus() - 1; ++ ++ if (!cpus) ++ return; ++ ++ data.func = func; ++ data.info = info; ++ atomic_set(&data.started, 0); ++ data.wait = wait; ++ if (wait) ++ atomic_set(&data.finished, 0); ++ ++ call_data = &data; ++ mb(); ++ ++ /* Send a message to all other CPUs and wait for them to respond */ ++ send_IPI_allbutself(CALL_FUNCTION_VECTOR); ++ ++ /* Wait for response */ ++ while (atomic_read(&data.started) != cpus) ++ cpu_relax(); ++ ++ if (wait) ++ while (atomic_read(&data.finished) != cpus) ++ cpu_relax(); ++} ++ ++ + /** +- * smp_call_function(): Run a function on all other CPUs. ++ * smp_call_function_mask(): Run a function on a set of other CPUs. ++ * @mask: The set of cpus to run on. Must not include the current cpu. + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. +- * @nonatomic: currently unused. + * @wait: If true, wait (atomically) until function has completed on other CPUs. + * +- * Returns 0 on success, else a negative status code. Does not return until +- * remote CPUs are nearly ready to execute <> or are or have executed. ++ * Returns 0 on success, else a negative status code. ++ * ++ * If @wait is true, then returns once @func has returned; otherwise ++ * it returns just before the target cpu calls @func. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. + */ +-int smp_call_function (void (*func) (void *info), void *info, int nonatomic, +- int wait) ++int ++xen_smp_call_function_mask(cpumask_t mask, ++ void (*func)(void *), void *info, ++ int wait) + { + struct call_data_struct data; ++ cpumask_t allbutself; + int cpus; + ++ /* Can deadlock when called with interrupts disabled */ ++ WARN_ON(irqs_disabled()); ++ + /* Holding any lock stops cpus from going down. */ + spin_lock(&call_lock); +- cpus = num_online_cpus() - 1; ++ ++ allbutself = cpu_online_map; ++ cpu_clear(smp_processor_id(), allbutself); ++ ++ cpus_and(mask, mask, allbutself); ++ cpus = cpus_weight(mask); ++ + if (!cpus) { + spin_unlock(&call_lock); + return 0; + } + +- /* Can deadlock when called with interrupts disabled */ +- WARN_ON(irqs_disabled()); +- + data.func = func; + data.info = info; + atomic_set(&data.started, 0); +@@ -517,9 +552,12 @@ int smp_call_function (void (*func) (voi + + call_data = &data; + mb(); +- +- /* Send a message to all other CPUs and wait for them to respond */ +- send_IPI_allbutself(CALL_FUNCTION_VECTOR); ++ ++ /* Send a message to other CPUs */ ++ if (cpus_equal(mask, allbutself)) ++ send_IPI_allbutself(CALL_FUNCTION_VECTOR); ++ else ++ send_IPI_mask(mask, CALL_FUNCTION_VECTOR); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) +@@ -532,15 +570,14 @@ int smp_call_function (void (*func) (voi + + return 0; + } +-EXPORT_SYMBOL(smp_call_function); + + static void stop_this_cpu (void * dummy) + { ++ local_irq_disable(); + /* + * Remove this CPU: + */ + cpu_clear(smp_processor_id(), cpu_online_map); +- local_irq_disable(); + disable_all_local_evtchn(); + if (cpu_data[smp_processor_id()].hlt_works_ok) + for(;;) halt(); +@@ -551,13 +588,18 @@ static void stop_this_cpu (void * dummy) + * this function calls the 'stop' function on all other CPUs in the system. + */ + +-void smp_send_stop(void) ++void xen_smp_send_stop(void) + { +- smp_call_function(stop_this_cpu, NULL, 1, 0); ++ /* Don't deadlock on the call lock in panic */ ++ int nolock = !spin_trylock(&call_lock); ++ unsigned long flags; + +- local_irq_disable(); ++ local_irq_save(flags); ++ __smp_call_function(stop_this_cpu, NULL, 0, 0); ++ if (!nolock) ++ spin_unlock(&call_lock); + disable_all_local_evtchn(); +- local_irq_enable(); ++ local_irq_restore(flags); + } + + /* +@@ -598,74 +640,3 @@ irqreturn_t smp_call_function_interrupt( + + return IRQ_HANDLED; + } +- +-/* +- * this function sends a 'generic call function' IPI to one other CPU +- * in the system. +- * +- * cpu is a standard Linux logical CPU number. +- */ +-static void +-__smp_call_function_single(int cpu, void (*func) (void *info), void *info, +- int nonatomic, int wait) +-{ +- struct call_data_struct data; +- int cpus = 1; +- +- data.func = func; +- data.info = info; +- atomic_set(&data.started, 0); +- data.wait = wait; +- if (wait) +- atomic_set(&data.finished, 0); +- +- call_data = &data; +- wmb(); +- /* Send a message to all other CPUs and wait for them to respond */ +- send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR); +- +- /* Wait for response */ +- while (atomic_read(&data.started) != cpus) +- cpu_relax(); +- +- if (!wait) +- return; +- +- while (atomic_read(&data.finished) != cpus) +- cpu_relax(); +-} +- +-/* +- * smp_call_function_single - Run a function on another CPU +- * @func: The function to run. This must be fast and non-blocking. +- * @info: An arbitrary pointer to pass to the function. +- * @nonatomic: Currently unused. +- * @wait: If true, wait until function has completed on other CPUs. +- * +- * Retrurns 0 on success, else a negative status code. +- * +- * Does not return until the remote CPU is nearly ready to execute +- * or is or has executed. +- */ +- +-int smp_call_function_single(int cpu, void (*func) (void *info), void *info, +- int nonatomic, int wait) +-{ +- /* prevent preemption and reschedule on another processor */ +- int me = get_cpu(); +- if (cpu == me) { +- WARN_ON(1); +- put_cpu(); +- return -EBUSY; +- } +- +- /* Can deadlock when called with interrupts disabled */ +- WARN_ON(irqs_disabled()); +- +- spin_lock_bh(&call_lock); +- __smp_call_function_single(cpu, func, info, nonatomic, wait); +- spin_unlock_bh(&call_lock); +- put_cpu(); +- return 0; +-} +-EXPORT_SYMBOL(smp_call_function_single); +--- sle11-2009-04-20.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:11:08.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/time_32-xen.c 2009-03-24 10:11:31.000000000 +0100 +@@ -80,7 +80,6 @@ + #include + DEFINE_SPINLOCK(i8253_lock); + EXPORT_SYMBOL(i8253_lock); +-int pit_latch_buggy; /* extern */ + #else + volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; + #endif +@@ -218,6 +217,26 @@ static inline u64 scale_delta(u64 delta, + return product; + } + ++static inline u64 get64(volatile u64 *ptr) ++{ ++#ifndef CONFIG_64BIT ++ return cmpxchg64(ptr, 0, 0); ++#else ++ return *ptr; ++#define cmpxchg64 cmpxchg ++#endif ++} ++ ++static inline u64 get64_local(volatile u64 *ptr) ++{ ++#ifndef CONFIG_64BIT ++ return cmpxchg64_local(ptr, 0, 0); ++#else ++ return *ptr; ++#define cmpxchg64_local cmpxchg_local ++#endif ++} ++ + static void init_cpu_khz(void) + { + u64 __cpu_khz = 1000000ULL << 32; +@@ -397,7 +416,7 @@ static int set_rtc_mmss(unsigned long no + return retval; + } + +-unsigned long long sched_clock(void) ++static unsigned long long local_clock(void) + { + unsigned int cpu = get_cpu(); + struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); +@@ -418,6 +437,61 @@ unsigned long long sched_clock(void) + return time; + } + ++/* ++ * Runstate accounting ++ */ ++static void get_runstate_snapshot(struct vcpu_runstate_info *res) ++{ ++ u64 state_time; ++ struct vcpu_runstate_info *state; ++ ++ BUG_ON(preemptible()); ++ ++ state = &__get_cpu_var(runstate); ++ ++ do { ++ state_time = get64_local(&state->state_entry_time); ++ *res = *state; ++ } while (get64_local(&state->state_entry_time) != state_time); ++ ++ WARN_ON_ONCE(res->state != RUNSTATE_running); ++} ++ ++/* ++ * Xen sched_clock implementation. Returns the number of unstolen ++ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED ++ * states. ++ */ ++unsigned long long sched_clock(void) ++{ ++ struct vcpu_runstate_info runstate; ++ cycle_t now; ++ u64 ret; ++ s64 offset; ++ ++ /* ++ * Ideally sched_clock should be called on a per-cpu basis ++ * anyway, so preempt should already be disabled, but that's ++ * not current practice at the moment. ++ */ ++ preempt_disable(); ++ ++ now = local_clock(); ++ ++ get_runstate_snapshot(&runstate); ++ ++ offset = now - runstate.state_entry_time; ++ if (offset < 0) ++ offset = 0; ++ ++ ret = offset + runstate.time[RUNSTATE_running] ++ + runstate.time[RUNSTATE_blocked]; ++ ++ preempt_enable(); ++ ++ return ret; ++} ++ + unsigned long profile_pc(struct pt_regs *regs) + { + unsigned long pc = instruction_pointer(regs); +@@ -465,10 +539,9 @@ EXPORT_SYMBOL(profile_pc); + irqreturn_t timer_interrupt(int irq, void *dev_id) + { + s64 delta, delta_cpu, stolen, blocked; +- u64 sched_time; + unsigned int i, cpu = smp_processor_id(); + struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); +- struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu); ++ struct vcpu_runstate_info runstate; + + /* + * Here we are in the timer irq handler. We just have irqs locally +@@ -488,20 +561,7 @@ irqreturn_t timer_interrupt(int irq, voi + delta -= processed_system_time; + delta_cpu -= per_cpu(processed_system_time, cpu); + +- /* +- * Obtain a consistent snapshot of stolen/blocked cycles. We +- * can use state_entry_time to detect if we get preempted here. +- */ +- do { +- sched_time = runstate->state_entry_time; +- barrier(); +- stolen = runstate->time[RUNSTATE_runnable] + +- runstate->time[RUNSTATE_offline] - +- per_cpu(processed_stolen_time, cpu); +- blocked = runstate->time[RUNSTATE_blocked] - +- per_cpu(processed_blocked_time, cpu); +- barrier(); +- } while (sched_time != runstate->state_entry_time); ++ get_runstate_snapshot(&runstate); + } while (!time_values_up_to_date(cpu)); + + if ((unlikely(delta < -(s64)permitted_clock_jitter) || +@@ -543,6 +603,9 @@ irqreturn_t timer_interrupt(int irq, voi + * HACK: Passing NULL to account_steal_time() + * ensures that the ticks are accounted as stolen. + */ ++ stolen = runstate.time[RUNSTATE_runnable] ++ + runstate.time[RUNSTATE_offline] ++ - per_cpu(processed_stolen_time, cpu); + if ((stolen > 0) && (delta_cpu > 0)) { + delta_cpu -= stolen; + if (unlikely(delta_cpu < 0)) +@@ -558,6 +621,8 @@ irqreturn_t timer_interrupt(int irq, voi + * HACK: Passing idle_task to account_steal_time() + * ensures that the ticks are accounted as idle/wait. + */ ++ blocked = runstate.time[RUNSTATE_blocked] ++ - per_cpu(processed_blocked_time, cpu); + if ((blocked > 0) && (delta_cpu > 0)) { + delta_cpu -= blocked; + if (unlikely(delta_cpu < 0)) +@@ -594,7 +659,7 @@ irqreturn_t timer_interrupt(int irq, voi + return IRQ_HANDLED; + } + +-void mark_tsc_unstable(void) ++void mark_tsc_unstable(char *reason) + { + #ifndef CONFIG_XEN /* XXX Should tell the hypervisor about this fact. */ + tsc_unstable = 1; +@@ -602,17 +667,13 @@ void mark_tsc_unstable(void) + } + EXPORT_SYMBOL_GPL(mark_tsc_unstable); + ++static cycle_t cs_last; ++ + static cycle_t xen_clocksource_read(void) + { + #ifdef CONFIG_SMP +- static cycle_t last_ret; +-#ifndef CONFIG_64BIT +- cycle_t last = cmpxchg64(&last_ret, 0, 0); +-#else +- cycle_t last = last_ret; +-#define cmpxchg64 cmpxchg +-#endif +- cycle_t ret = sched_clock(); ++ cycle_t last = get64(&cs_last); ++ cycle_t ret = local_clock(); + + if (unlikely((s64)(ret - last) < 0)) { + if (last - ret > permitted_clock_jitter +@@ -631,17 +692,25 @@ static cycle_t xen_clocksource_read(void + } + + for (;;) { +- cycle_t cur = cmpxchg64(&last_ret, last, ret); ++ cycle_t cur = cmpxchg64(&cs_last, last, ret); + + if (cur == last || (s64)(ret - cur) < 0) + return ret; + last = cur; + } + #else +- return sched_clock(); ++ return local_clock(); + #endif + } + ++static void xen_clocksource_resume(void) ++{ ++ extern void time_resume(void); ++ ++ time_resume(); ++ cs_last = local_clock(); ++} ++ + static struct clocksource clocksource_xen = { + .name = "xen", + .rating = 400, +@@ -650,6 +719,7 @@ static struct clocksource clocksource_xe + .mult = 1 << XEN_SHIFT, /* time directly in nanoseconds */ + .shift = XEN_SHIFT, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++ .resume = xen_clocksource_resume, + }; + + static void init_missing_ticks_accounting(unsigned int cpu) +@@ -738,35 +808,6 @@ void notify_arch_cmos_timer(void) + mod_timer(&sync_xen_wallclock_timer, jiffies + 1); + } + +-static int timer_resume(struct sys_device *dev) +-{ +- extern void time_resume(void); +- time_resume(); +- return 0; +-} +- +-static struct sysdev_class timer_sysclass = { +- .resume = timer_resume, +- set_kset_name("timer"), +-}; +- +- +-/* XXX this driverfs stuff should probably go elsewhere later -john */ +-static struct sys_device device_timer = { +- .id = 0, +- .cls = &timer_sysclass, +-}; +- +-static int time_init_device(void) +-{ +- int error = sysdev_class_register(&timer_sysclass); +- if (!error) +- error = sysdev_register(&device_timer); +- return error; +-} +- +-device_initcall(time_init_device); +- + extern void (*late_time_init)(void); + + /* Dynamically-mapped IRQ. */ +@@ -897,21 +938,21 @@ static void start_hz_timer(void) + cpu_clear(smp_processor_id(), nohz_cpu_mask); + } + +-void raw_safe_halt(void) ++void xen_safe_halt(void) + { + stop_hz_timer(); + /* Blocking includes an implicit local_irq_enable(). */ + HYPERVISOR_block(); + start_hz_timer(); + } +-EXPORT_SYMBOL(raw_safe_halt); ++EXPORT_SYMBOL(xen_safe_halt); + +-void halt(void) ++void xen_halt(void) + { + if (irqs_disabled()) + VOID(HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL)); + } +-EXPORT_SYMBOL(halt); ++EXPORT_SYMBOL(xen_halt); + + /* No locking required. Interrupts are disabled on all CPUs. */ + void time_resume(void) +--- sle11-2009-04-20.orig/arch/x86/kernel/traps_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/traps_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -52,7 +52,7 @@ + #include + #include + #include +-#include ++#include + #include + + #include +@@ -101,20 +101,6 @@ asmlinkage void machine_check(void); + + int kstack_depth_to_print = 24; + static unsigned int code_bytes = 64; +-ATOMIC_NOTIFIER_HEAD(i386die_chain); +- +-int register_die_notifier(struct notifier_block *nb) +-{ +- vmalloc_sync_all(); +- return atomic_notifier_chain_register(&i386die_chain, nb); +-} +-EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ +- +-int unregister_die_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&i386die_chain, nb); +-} +-EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ + + static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) + { +@@ -325,7 +311,7 @@ void show_registers(struct pt_regs *regs + regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss); + printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", + TASK_COMM_LEN, current->comm, current->pid, +- current_thread_info(), current, current->thread_info); ++ current_thread_info(), current, task_thread_info(current)); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. +@@ -482,8 +468,6 @@ static void __kprobes do_trap(int trapnr + siginfo_t *info) + { + struct task_struct *tsk = current; +- tsk->thread.error_code = error_code; +- tsk->thread.trap_no = trapnr; + + if (regs->eflags & VM_MASK) { + if (vm86) +@@ -495,6 +479,18 @@ static void __kprobes do_trap(int trapnr + goto kernel_trap; + + trap_signal: { ++ /* ++ * We want error_code and trap_no set for userspace faults and ++ * kernelspace faults which result in die(), but not ++ * kernelspace faults which are fixed up. die() gives the ++ * process no chance to handle the signal and notice the ++ * kernel fault information, so that won't result in polluting ++ * the information about previously queued, but not yet ++ * delivered, faults. See also do_general_protection below. ++ */ ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; ++ + if (info) + force_sig_info(signr, info, tsk); + else +@@ -503,8 +499,11 @@ static void __kprobes do_trap(int trapnr + } + + kernel_trap: { +- if (!fixup_exception(regs)) ++ if (!fixup_exception(regs)) { ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; + die(str, regs, error_code); ++ } + return; + } + +@@ -578,9 +577,6 @@ DO_ERROR_INFO(32, SIGSEGV, "iret excepti + fastcall void __kprobes do_general_protection(struct pt_regs * regs, + long error_code) + { +- current->thread.error_code = error_code; +- current->thread.trap_no = 13; +- + if (regs->eflags & VM_MASK) + goto gp_in_vm86; + +@@ -599,6 +595,8 @@ gp_in_vm86: + + gp_in_kernel: + if (!fixup_exception(regs)) { ++ current->thread.error_code = error_code; ++ current->thread.trap_no = 13; + if (notify_die(DIE_GPF, "general protection fault", regs, + error_code, 13, SIGSEGV) == NOTIFY_STOP) + return; +@@ -987,9 +985,7 @@ fastcall void do_spurious_interrupt_bug( + fastcall unsigned long patch_espfix_desc(unsigned long uesp, + unsigned long kesp) + { +- int cpu = smp_processor_id(); +- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); +- struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address; ++ struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; + unsigned long base = (kesp - uesp) & -THREAD_SIZE; + unsigned long new_kesp = kesp - base; + unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; +--- sle11-2009-04-20.orig/arch/x86/mm/fault_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/fault_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -14,19 +14,20 @@ + #include + #include + #include +-#include + #include + #include + #include + #include /* For unblank_screen() */ + #include ++#include /* for max_low_pfn */ ++#include + #include + #include + #include ++#include + + #include + #include +-#include + #include + + extern void die(const char *,struct pt_regs *,long); +@@ -259,25 +260,20 @@ static void dump_fault_path(unsigned lon + unsigned long page; + + page = read_cr3(); +- page = ((unsigned long *) __va(page))[address >> 22]; +- if (oops_may_print()) +- printk(KERN_ALERT "*pde = ma %08lx pa %08lx\n", page, +- machine_to_phys(page)); ++ page = ((unsigned long *) __va(page))[address >> PGDIR_SHIFT]; ++ printk(KERN_ALERT "*pde = ma %08lx pa %08lx\n", page, ++ machine_to_phys(page)); + /* + * We must not directly access the pte in the highpte + * case if the page table is located in highmem. + * And lets rather not kmap-atomic the pte, just in case + * it's allocated already. + */ +-#ifdef CONFIG_HIGHPTE +- if ((page >> PAGE_SHIFT) >= highstart_pfn) +- return; +-#endif +- if ((page & 1) && oops_may_print()) { +- page &= PAGE_MASK; +- address &= 0x003ff000; +- page = machine_to_phys(page); +- page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; ++ if ((machine_to_phys(page) >> PAGE_SHIFT) < max_low_pfn ++ && (page & _PAGE_PRESENT)) { ++ page = machine_to_phys(page & PAGE_MASK); ++ page = ((unsigned long *) __va(page))[(address >> PAGE_SHIFT) ++ & (PTRS_PER_PTE - 1)]; + printk(KERN_ALERT "*pte = ma %08lx pa %08lx\n", page, + machine_to_phys(page)); + } +@@ -581,6 +577,11 @@ bad_area: + bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ + if (error_code & 4) { ++ /* ++ * It's possible to have interrupts off here. ++ */ ++ local_irq_enable(); ++ + /* + * Valid to do another page fault here because this one came + * from user space. +@@ -633,7 +634,7 @@ no_context: + bust_spinlocks(1); + + if (oops_may_print()) { +- #ifdef CONFIG_X86_PAE ++#ifdef CONFIG_X86_PAE + if (error_code & 16) { + pte_t *pte = lookup_address(address); + +@@ -642,7 +643,7 @@ no_context: + "NX-protected page - exploit attempt? " + "(uid: %d)\n", current->uid); + } +- #endif ++#endif + if (address < PAGE_SIZE) + printk(KERN_ALERT "BUG: unable to handle kernel NULL " + "pointer dereference"); +@@ -652,8 +653,8 @@ no_context: + printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT " printing eip:\n"); + printk("%08lx\n", regs->eip); ++ dump_fault_path(address); + } +- dump_fault_path(address); + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; + tsk->thread.error_code = error_code; +@@ -694,7 +695,6 @@ do_sigbus: + force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); + } + +-#if !HAVE_SHARED_KERNEL_PMD + void vmalloc_sync_all(void) + { + /* +@@ -710,6 +710,9 @@ void vmalloc_sync_all(void) + static unsigned long start = TASK_SIZE; + unsigned long address; + ++ if (SHARED_KERNEL_PMD) ++ return; ++ + BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK); + for (address = start; + address >= TASK_SIZE && address < hypervisor_virt_start; +@@ -739,4 +742,3 @@ void vmalloc_sync_all(void) + start = address + (1UL << PMD_SHIFT); + } + } +-#endif +--- sle11-2009-04-20.orig/arch/x86/mm/highmem_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/highmem_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -26,7 +26,7 @@ void kunmap(struct page *page) + * However when holding an atomic kmap is is not legal to sleep, so atomic + * kmaps are appropriate for short, tight code paths only. + */ +-static void *__kmap_atomic(struct page *page, enum km_type type, pgprot_t prot) ++void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) + { + enum fixed_addresses idx; + unsigned long vaddr; +@@ -49,15 +49,7 @@ static void *__kmap_atomic(struct page * + + void *kmap_atomic(struct page *page, enum km_type type) + { +- return __kmap_atomic(page, type, kmap_prot); +-} +- +-/* Same as kmap_atomic but with PAGE_KERNEL_RO page protection. */ +-void *kmap_atomic_pte(struct page *page, enum km_type type) +-{ +- return __kmap_atomic(page, type, +- test_bit(PG_pinned, &page->flags) +- ? PAGE_KERNEL_RO : kmap_prot); ++ return kmap_atomic_prot(page, type, kmap_prot); + } + + void kunmap_atomic(void *kvaddr, enum km_type type) +@@ -80,6 +72,7 @@ void kunmap_atomic(void *kvaddr, enum km + #endif + } + ++ /*arch_flush_lazy_mmu_mode();*/ + pagefault_enable(); + } + +@@ -162,7 +155,6 @@ void copy_highpage(struct page *to, stru + EXPORT_SYMBOL(kmap); + EXPORT_SYMBOL(kunmap); + EXPORT_SYMBOL(kmap_atomic); +-EXPORT_SYMBOL(kmap_atomic_pte); + EXPORT_SYMBOL(kunmap_atomic); + EXPORT_SYMBOL(kmap_atomic_to_page); + EXPORT_SYMBOL(clear_highpage); +--- sle11-2009-04-20.orig/arch/x86/mm/init_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/init_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -65,17 +66,19 @@ static pmd_t * __init one_md_table_init( + pmd_t *pmd_table; + + #ifdef CONFIG_X86_PAE +- pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); +- paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); +- make_lowmem_page_readonly(pmd_table, XENFEAT_writable_page_tables); +- set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); +- pud = pud_offset(pgd, 0); +- if (pmd_table != pmd_offset(pud, 0)) +- BUG(); +-#else ++ if (!(__pgd_val(*pgd) & _PAGE_PRESENT)) { ++ pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ ++ paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT); ++ make_lowmem_page_readonly(pmd_table, XENFEAT_writable_page_tables); ++ set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); ++ pud = pud_offset(pgd, 0); ++ if (pmd_table != pmd_offset(pud, 0)) ++ BUG(); ++ } ++#endif + pud = pud_offset(pgd, 0); + pmd_table = pmd_offset(pud, 0); +-#endif + + return pmd_table; + } +@@ -86,16 +89,18 @@ static pmd_t * __init one_md_table_init( + */ + static pte_t * __init one_page_table_init(pmd_t *pmd) + { ++#if CONFIG_XEN_COMPAT <= 0x030002 + if (pmd_none(*pmd)) { ++#else ++ if (!(__pmd_val(*pmd) & _PAGE_PRESENT)) { ++#endif + pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ + paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); + make_lowmem_page_readonly(page_table, + XENFEAT_writable_page_tables); + set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); +- if (page_table != pte_offset_kernel(pmd, 0)) +- BUG(); +- +- return page_table; ++ BUG_ON(page_table != pte_offset_kernel(pmd, 0)); + } + + return pte_offset_kernel(pmd, 0); +@@ -115,7 +120,6 @@ static pte_t * __init one_page_table_ini + static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base) + { + pgd_t *pgd; +- pud_t *pud; + pmd_t *pmd; + int pgd_idx, pmd_idx; + unsigned long vaddr; +@@ -126,12 +130,10 @@ static void __init page_table_range_init + pgd = pgd_base + pgd_idx; + + for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { +- if (pgd_none(*pgd)) +- one_md_table_init(pgd); +- pud = pud_offset(pgd, vaddr); +- pmd = pmd_offset(pud, vaddr); ++ pmd = one_md_table_init(pgd); ++ pmd = pmd + pmd_index(vaddr); + for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { +- if (vaddr < hypervisor_virt_start && pmd_none(*pmd)) ++ if (vaddr < hypervisor_virt_start) + one_page_table_init(pmd); + + vaddr += PMD_SIZE; +@@ -194,24 +196,25 @@ static void __init kernel_physical_mappi + /* Map with big pages if possible, otherwise create normal page tables. */ + if (cpu_has_pse) { + unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; +- + if (is_kernel_text(address) || is_kernel_text(address2)) + set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); + else + set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); ++ + pfn += PTRS_PER_PTE; + } else { + pte = one_page_table_init(pmd); + +- pte += pte_ofs; +- for (; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { +- /* XEN: Only map initial RAM allocation. */ +- if ((pfn >= max_ram_pfn) || pte_present(*pte)) +- continue; +- if (is_kernel_text(address)) +- set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); +- else +- set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); ++ for (pte += pte_ofs; ++ pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; ++ pte++, pfn++, pte_ofs++, address += PAGE_SIZE) { ++ /* XEN: Only map initial RAM allocation. */ ++ if ((pfn >= max_ram_pfn) || pte_present(*pte)) ++ continue; ++ if (is_kernel_text(address)) ++ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); ++ else ++ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); + } + pte_ofs = 0; + } +@@ -381,15 +384,44 @@ extern void __init remap_numa_kva(void); + + pgd_t *swapper_pg_dir; + ++static void __init xen_pagetable_setup_start(pgd_t *base) ++{ ++} ++ ++static void __init xen_pagetable_setup_done(pgd_t *base) ++{ ++} ++ ++/* ++ * Build a proper pagetable for the kernel mappings. Up until this ++ * point, we've been running on some set of pagetables constructed by ++ * the boot process. ++ * ++ * If we're booting on native hardware, this will be a pagetable ++ * constructed in arch/i386/kernel/head.S, and not running in PAE mode ++ * (even if we'll end up running in PAE). The root of the pagetable ++ * will be swapper_pg_dir. ++ * ++ * If we're booting paravirtualized under a hypervisor, then there are ++ * more options: we may already be running PAE, and the pagetable may ++ * or may not be based in swapper_pg_dir. In any case, ++ * paravirt_pagetable_setup_start() will set up swapper_pg_dir ++ * appropriately for the rest of the initialization to work. ++ * ++ * In general, pagetable_init() assumes that the pagetable may already ++ * be partially populated, and so it avoids stomping on any existing ++ * mappings. ++ */ + static void __init pagetable_init (void) + { +- unsigned long vaddr; ++ unsigned long vaddr, end; + pgd_t *pgd_base = (pgd_t *)xen_start_info->pt_base; + ++ xen_pagetable_setup_start(pgd_base); ++ + /* Enable PSE if available */ +- if (cpu_has_pse) { ++ if (cpu_has_pse) + set_in_cr4(X86_CR4_PSE); +- } + + /* Enable PGE if available */ + if (cpu_has_pge) { +@@ -406,9 +438,12 @@ static void __init pagetable_init (void) + * created - mappings will be set by set_fixmap(): + */ + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; +- page_table_range_init(vaddr, hypervisor_virt_start, pgd_base); ++ end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; ++ page_table_range_init(vaddr, end, pgd_base); + + permanent_kmaps_init(pgd_base); ++ ++ xen_pagetable_setup_done(pgd_base); + } + + #if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP) +@@ -750,34 +785,29 @@ int remove_memory(u64 start, u64 size) + EXPORT_SYMBOL_GPL(remove_memory); + #endif + +-struct kmem_cache *pgd_cache; + struct kmem_cache *pmd_cache; + + void __init pgtable_cache_init(void) + { ++ size_t pgd_size = PTRS_PER_PGD*sizeof(pgd_t); ++ + if (PTRS_PER_PMD > 1) { + pmd_cache = kmem_cache_create("pmd", + PTRS_PER_PMD*sizeof(pmd_t), + PTRS_PER_PMD*sizeof(pmd_t), +- 0, ++ SLAB_PANIC, + pmd_ctor, + NULL); +- if (!pmd_cache) +- panic("pgtable_cache_init(): cannot create pmd cache"); ++ if (!SHARED_KERNEL_PMD) { ++ /* If we're in PAE mode and have a non-shared ++ kernel pmd, then the pgd size must be a ++ page size. This is because the pgd_list ++ links through the page structure, so there ++ can only be one pgd per page for this to ++ work. */ ++ pgd_size = PAGE_SIZE; ++ } + } +- pgd_cache = kmem_cache_create("pgd", +-#ifndef CONFIG_XEN +- PTRS_PER_PGD*sizeof(pgd_t), +- PTRS_PER_PGD*sizeof(pgd_t), +-#else +- PAGE_SIZE, +- PAGE_SIZE, +-#endif +- 0, +- pgd_ctor, +- PTRS_PER_PMD == 1 ? pgd_dtor : NULL); +- if (!pgd_cache) +- panic("pgtable_cache_init(): Cannot create pgd cache"); + } + + /* +@@ -811,13 +841,26 @@ static int noinline do_test_wp_bit(void) + + void mark_rodata_ro(void) + { +- unsigned long addr = (unsigned long)__start_rodata; +- +- for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) +- change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO); ++ unsigned long start = PFN_ALIGN(_text); ++ unsigned long size = PFN_ALIGN(_etext) - start; + +- printk("Write protecting the kernel read-only data: %uk\n", +- (__end_rodata - __start_rodata) >> 10); ++#ifndef CONFIG_KPROBES ++#ifdef CONFIG_HOTPLUG_CPU ++ /* It must still be possible to apply SMP alternatives. */ ++ if (num_possible_cpus() <= 1) ++#endif ++ { ++ change_page_attr(virt_to_page(start), ++ size >> PAGE_SHIFT, PAGE_KERNEL_RX); ++ printk("Write protecting the kernel text: %luk\n", size >> 10); ++ } ++#endif ++ start += size; ++ size = (unsigned long)__end_rodata - start; ++ change_page_attr(virt_to_page(start), ++ size >> PAGE_SHIFT, PAGE_KERNEL_RO); ++ printk("Write protecting the kernel read-only data: %luk\n", ++ size >> 10); + + /* + * change_page_attr() requires a global_flush_tlb() call after it. +@@ -840,7 +883,7 @@ void free_init_pages(char *what, unsigne + free_page(addr); + totalram_pages++; + } +- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); ++ printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); + } + + void free_initmem(void) +--- sle11-2009-04-20.orig/arch/x86/mm/ioremap_32-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/ioremap_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +--- sle11-2009-04-20.orig/arch/x86/mm/pgtable_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/pgtable_32-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -218,8 +219,6 @@ void pmd_ctor(void *pmd, struct kmem_cac + * against pageattr.c; it is the unique case in which a valid change + * of kernel pagetables can't be lazily synchronized by vmalloc faults. + * vmalloc faults work because attached pagetables are never freed. +- * The locking scheme was chosen on the basis of manfred's +- * recommendations and having no core impact whatsoever. + * -- wli + */ + DEFINE_SPINLOCK(pgd_lock); +@@ -245,37 +244,54 @@ static inline void pgd_list_del(pgd_t *p + set_page_private(next, (unsigned long)pprev); + } + +-void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused) ++ ++ ++#if (PTRS_PER_PMD == 1) ++/* Non-PAE pgd constructor */ ++void pgd_ctor(void *pgd) + { + unsigned long flags; + +- if (PTRS_PER_PMD > 1) { +- if (HAVE_SHARED_KERNEL_PMD) +- clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, +- swapper_pg_dir + USER_PTRS_PER_PGD, +- KERNEL_PGD_PTRS); +- } else { +- spin_lock_irqsave(&pgd_lock, flags); ++ /* !PAE, no pagetable sharing */ ++ memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); ++ ++ spin_lock_irqsave(&pgd_lock, flags); ++ ++ /* must happen under lock */ ++ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, ++ swapper_pg_dir + USER_PTRS_PER_PGD, ++ KERNEL_PGD_PTRS); ++ ++ paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT, ++ __pa(swapper_pg_dir) >> PAGE_SHIFT, ++ USER_PTRS_PER_PGD, ++ KERNEL_PGD_PTRS); ++ pgd_list_add(pgd); ++ spin_unlock_irqrestore(&pgd_lock, flags); ++} ++#else /* PTRS_PER_PMD > 1 */ ++/* PAE pgd constructor */ ++void pgd_ctor(void *pgd) ++{ ++ /* PAE, kernel PMD may be shared */ ++ ++ if (SHARED_KERNEL_PMD) { + clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, + KERNEL_PGD_PTRS); ++ } else { + memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t)); +- +- /* must happen under lock */ +- paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT, +- __pa(swapper_pg_dir) >> PAGE_SHIFT, +- USER_PTRS_PER_PGD, PTRS_PER_PGD - USER_PTRS_PER_PGD); +- +- pgd_list_add(pgd); +- spin_unlock_irqrestore(&pgd_lock, flags); + } + } ++#endif /* PTRS_PER_PMD */ + +-/* never called when PTRS_PER_PMD > 1 */ +-void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused) ++void pgd_dtor(void *pgd) + { + unsigned long flags; /* can be called from interrupt context */ + ++ if (SHARED_KERNEL_PMD) ++ return; ++ + paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT); + spin_lock_irqsave(&pgd_lock, flags); + pgd_list_del(pgd); +@@ -284,11 +300,46 @@ void pgd_dtor(void *pgd, struct kmem_cac + pgd_test_and_unpin(pgd); + } + ++#define UNSHARED_PTRS_PER_PGD \ ++ (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD) ++ ++/* If we allocate a pmd for part of the kernel address space, then ++ make sure its initialized with the appropriate kernel mappings. ++ Otherwise use a cached zeroed pmd. */ ++static pmd_t *pmd_cache_alloc(int idx) ++{ ++ pmd_t *pmd; ++ ++ if (idx >= USER_PTRS_PER_PGD) { ++ pmd = (pmd_t *)__get_free_page(GFP_KERNEL); ++ ++#ifndef CONFIG_XEN ++ if (pmd) ++ memcpy(pmd, ++ (void *)pgd_page_vaddr(swapper_pg_dir[idx]), ++ sizeof(pmd_t) * PTRS_PER_PMD); ++#endif ++ } else ++ pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); ++ ++ return pmd; ++} ++ ++static void pmd_cache_free(pmd_t *pmd, int idx) ++{ ++ if (idx >= USER_PTRS_PER_PGD) { ++ make_lowmem_page_writable(pmd, XENFEAT_writable_page_tables); ++ memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); ++ free_page((unsigned long)pmd); ++ } else ++ kmem_cache_free(pmd_cache, pmd); ++} ++ + pgd_t *pgd_alloc(struct mm_struct *mm) + { + int i; +- pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL); +- pmd_t **pmd; ++ pgd_t *pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor); ++ pmd_t **pmds = NULL; + unsigned long flags; + + pgd_test_and_unpin(pgd); +@@ -296,37 +347,40 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + if (PTRS_PER_PMD == 1 || !pgd) + return pgd; + +- if (HAVE_SHARED_KERNEL_PMD) { +- for (i = 0; i < USER_PTRS_PER_PGD; ++i) { +- pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL); +- if (!pmd) +- goto out_oom; +- paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT); +- set_pgd(&pgd[i], __pgd(1 + __pa(pmd))); ++#ifdef CONFIG_XEN ++ if (!SHARED_KERNEL_PMD) { ++ /* ++ * We can race save/restore (if we sleep during a GFP_KERNEL memory ++ * allocation). We therefore store virtual addresses of pmds as they ++ * do not change across save/restore, and poke the machine addresses ++ * into the pgdir under the pgd_lock. ++ */ ++ pmds = kmalloc(PTRS_PER_PGD * sizeof(pmd_t *), GFP_KERNEL); ++ if (!pmds) { ++ quicklist_free(0, pgd_dtor, pgd); ++ return NULL; + } +- return pgd; +- } +- +- /* +- * We can race save/restore (if we sleep during a GFP_KERNEL memory +- * allocation). We therefore store virtual addresses of pmds as they +- * do not change across save/restore, and poke the machine addresses +- * into the pgdir under the pgd_lock. +- */ +- pmd = kmalloc(PTRS_PER_PGD * sizeof(pmd_t *), GFP_KERNEL); +- if (!pmd) { +- kmem_cache_free(pgd_cache, pgd); +- return NULL; + } ++#endif + + /* Allocate pmds, remember virtual addresses. */ +- for (i = 0; i < PTRS_PER_PGD; ++i) { +- pmd[i] = kmem_cache_alloc(pmd_cache, GFP_KERNEL); +- if (!pmd[i]) ++ for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) { ++ pmd_t *pmd = pmd_cache_alloc(i); ++ ++ if (!pmd) + goto out_oom; ++ + paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT); ++ if (pmds) ++ pmds[i] = pmd; ++ else ++ set_pgd(&pgd[i], __pgd(1 + __pa(pmd))); + } + ++#ifdef CONFIG_XEN ++ if (SHARED_KERNEL_PMD) ++ return pgd; ++ + spin_lock_irqsave(&pgd_lock, flags); + + /* Protect against save/restore: move below 4GB under pgd_lock. */ +@@ -341,44 +395,43 @@ pgd_t *pgd_alloc(struct mm_struct *mm) + + /* Copy kernel pmd contents and write-protect the new pmds. */ + for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) { +- unsigned long v = (unsigned long)i << PGDIR_SHIFT; +- pgd_t *kpgd = pgd_offset_k(v); +- pud_t *kpud = pud_offset(kpgd, v); +- pmd_t *kpmd = pmd_offset(kpud, v); +- memcpy(pmd[i], kpmd, PAGE_SIZE); ++ memcpy(pmds[i], ++ (void *)pgd_page_vaddr(swapper_pg_dir[i]), ++ sizeof(pmd_t) * PTRS_PER_PMD); + make_lowmem_page_readonly( +- pmd[i], XENFEAT_writable_page_tables); ++ pmds[i], XENFEAT_writable_page_tables); + } + + /* It is safe to poke machine addresses of pmds under the pmd_lock. */ + for (i = 0; i < PTRS_PER_PGD; i++) +- set_pgd(&pgd[i], __pgd(1 + __pa(pmd[i]))); ++ set_pgd(&pgd[i], __pgd(1 + __pa(pmds[i]))); + + /* Ensure this pgd gets picked up and pinned on save/restore. */ + pgd_list_add(pgd); + + spin_unlock_irqrestore(&pgd_lock, flags); + +- kfree(pmd); ++ kfree(pmds); ++#endif + + return pgd; + + out_oom: +- if (HAVE_SHARED_KERNEL_PMD) { ++ if (!pmds) { + for (i--; i >= 0; i--) { + pgd_t pgdent = pgd[i]; + void* pmd = (void *)__va(pgd_val(pgdent)-1); + paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); +- kmem_cache_free(pmd_cache, pmd); ++ pmd_cache_free(pmd, i); + } + } else { + for (i--; i >= 0; i--) { +- paravirt_release_pd(__pa(pmd[i]) >> PAGE_SHIFT); +- kmem_cache_free(pmd_cache, pmd[i]); ++ paravirt_release_pd(__pa(pmds[i]) >> PAGE_SHIFT); ++ pmd_cache_free(pmds[i], i); + } +- kfree(pmd); ++ kfree(pmds); + } +- kmem_cache_free(pgd_cache, pgd); ++ quicklist_free(0, pgd_dtor, pgd); + return NULL; + } + +@@ -398,35 +451,24 @@ void pgd_free(pgd_t *pgd) + + /* in the PAE case user pgd entries are overwritten before usage */ + if (PTRS_PER_PMD > 1) { +- for (i = 0; i < USER_PTRS_PER_PGD; ++i) { ++ for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) { + pgd_t pgdent = pgd[i]; + void* pmd = (void *)__va(pgd_val(pgdent)-1); + paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT); +- kmem_cache_free(pmd_cache, pmd); ++ pmd_cache_free(pmd, i); + } + +- if (!HAVE_SHARED_KERNEL_PMD) { +- unsigned long flags; +- spin_lock_irqsave(&pgd_lock, flags); +- pgd_list_del(pgd); +- spin_unlock_irqrestore(&pgd_lock, flags); +- +- for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) { +- pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1); +- make_lowmem_page_writable( +- pmd, XENFEAT_writable_page_tables); +- memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); +- kmem_cache_free(pmd_cache, pmd); +- } +- +- if (!xen_feature(XENFEAT_pae_pgdir_above_4gb)) +- xen_destroy_contiguous_region( +- (unsigned long)pgd, 0); +- } ++ if (!xen_feature(XENFEAT_pae_pgdir_above_4gb)) ++ xen_destroy_contiguous_region((unsigned long)pgd, 0); + } + + /* in the non-PAE case, free_pgtables() clears user pgd entries */ +- kmem_cache_free(pgd_cache, pgd); ++ quicklist_free(0, pgd_dtor, pgd); ++} ++ ++void check_pgt_cache(void) ++{ ++ quicklist_trim(0, pgd_dtor, 25, 16); + } + + void make_lowmem_page_readonly(void *va, unsigned int feature) +@@ -723,13 +765,13 @@ void mm_pin_all(void) + spin_unlock_irqrestore(&pgd_lock, flags); + } + +-void _arch_dup_mmap(struct mm_struct *mm) ++void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) + { + if (!test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags)) + mm_pin(mm); + } + +-void _arch_exit_mmap(struct mm_struct *mm) ++void arch_exit_mmap(struct mm_struct *mm) + { + struct task_struct *tsk = current; + +--- sle11-2009-04-20.orig/arch/x86/ia32/ia32entry-xen.S 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/ia32/ia32entry-xen.S 2008-12-15 11:27:22.000000000 +0100 +@@ -431,11 +431,7 @@ ia32_sys_call_table: + .quad sys_symlink + .quad sys_lstat + .quad sys_readlink /* 85 */ +-#ifdef CONFIG_IA32_AOUT + .quad sys_uselib +-#else +- .quad quiet_ni_syscall +-#endif + .quad sys_swapon + .quad sys_reboot + .quad compat_sys_old_readdir +@@ -574,7 +570,7 @@ ia32_sys_call_table: + .quad quiet_ni_syscall /* tux */ + .quad quiet_ni_syscall /* security */ + .quad sys_gettid +- .quad sys_readahead /* 225 */ ++ .quad sys32_readahead /* 225 */ + .quad sys_setxattr + .quad sys_lsetxattr + .quad sys_fsetxattr +@@ -599,7 +595,7 @@ ia32_sys_call_table: + .quad compat_sys_io_getevents + .quad compat_sys_io_submit + .quad sys_io_cancel +- .quad sys_fadvise64 /* 250 */ ++ .quad sys32_fadvise64 /* 250 */ + .quad quiet_ni_syscall /* free_huge_pages */ + .quad sys_exit_group + .quad sys32_lookup_dcookie +@@ -663,10 +659,14 @@ ia32_sys_call_table: + .quad compat_sys_set_robust_list + .quad compat_sys_get_robust_list + .quad sys_splice +- .quad sys_sync_file_range +- .quad sys_tee ++ .quad sys32_sync_file_range ++ .quad sys_tee /* 315 */ + .quad compat_sys_vmsplice + .quad compat_sys_move_pages + .quad sys_getcpu + .quad sys_epoll_pwait +-ia32_syscall_end: ++ .quad compat_sys_utimensat /* 320 */ ++ .quad compat_sys_signalfd ++ .quad compat_sys_timerfd ++ .quad sys_eventfd ++ia32_syscall_end: +--- sle11-2009-04-20.orig/arch/x86/kernel/acpi/sleep_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/acpi/sleep_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -60,19 +60,6 @@ unsigned long acpi_video_flags; + extern char wakeup_start, wakeup_end; + + extern unsigned long acpi_copy_wakeup_routine(unsigned long); +- +-static pgd_t low_ptr; +- +-static void init_low_mapping(void) +-{ +- pgd_t *slot0 = pgd_offset(current->mm, 0UL); +- low_ptr = *slot0; +- /* FIXME: We're playing with the current task's page tables here, which +- * is potentially dangerous on SMP systems. +- */ +- set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET)); +- local_flush_tlb(); +-} + #endif + + /** +@@ -84,8 +71,6 @@ static void init_low_mapping(void) + int acpi_save_state_mem(void) + { + #ifndef CONFIG_ACPI_PV_SLEEP +- init_low_mapping(); +- + memcpy((void *)acpi_wakeup_address, &wakeup_start, + &wakeup_end - &wakeup_start); + acpi_copy_wakeup_routine(acpi_wakeup_address); +@@ -98,10 +83,6 @@ int acpi_save_state_mem(void) + */ + void acpi_restore_state_mem(void) + { +-#ifndef CONFIG_ACPI_PV_SLEEP +- set_pgd(pgd_offset(current->mm, 0UL), low_ptr); +- local_flush_tlb(); +-#endif + } + + /** +@@ -115,10 +96,11 @@ void acpi_restore_state_mem(void) + void __init acpi_reserve_bootmem(void) + { + #ifndef CONFIG_ACPI_PV_SLEEP +- acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); +- if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) ++ acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); ++ if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2)) + printk(KERN_CRIT +- "ACPI: Wakeup code way too big, will crash on attempt to suspend\n"); ++ "ACPI: Wakeup code way too big, will crash on attempt" ++ " to suspend\n"); + #endif + } + +--- sle11-2009-04-20.orig/arch/x86/kernel/apic_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/apic_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +--- sle11-2009-04-20.orig/arch/x86/kernel/e820_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/e820_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -17,6 +17,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -28,7 +30,7 @@ + + struct e820map e820 __initdata; + #ifdef CONFIG_XEN +-struct e820map machine_e820 __initdata; ++struct e820map machine_e820; + #endif + + /* +@@ -291,22 +293,6 @@ void __init e820_reserve_resources(struc + } + + #ifndef CONFIG_XEN +-/* Mark pages corresponding to given address range as nosave */ +-static void __init +-e820_mark_nosave_range(unsigned long start, unsigned long end) +-{ +- unsigned long pfn, max_pfn; +- +- if (start >= end) +- return; +- +- printk("Nosave address range: %016lx - %016lx\n", start, end); +- max_pfn = end >> PAGE_SHIFT; +- for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++) +- if (pfn_valid(pfn)) +- SetPageNosave(pfn_to_page(pfn)); +-} +- + /* + * Find the ranges of physical addresses that do not correspond to + * e820 RAM areas and mark the corresponding pages as nosave for software +@@ -325,13 +311,13 @@ void __init e820_mark_nosave_regions(voi + struct e820entry *ei = &e820.map[i]; + + if (paddr < ei->addr) +- e820_mark_nosave_range(paddr, +- round_up(ei->addr, PAGE_SIZE)); ++ register_nosave_region(PFN_DOWN(paddr), ++ PFN_UP(ei->addr)); + + paddr = round_down(ei->addr + ei->size, PAGE_SIZE); + if (ei->type != E820_RAM) +- e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE), +- paddr); ++ register_nosave_region(PFN_UP(ei->addr), ++ PFN_DOWN(paddr)); + + if (paddr >= (end_pfn << PAGE_SHIFT)) + break; +--- sle11-2009-04-20.orig/arch/x86/kernel/early_printk-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/early_printk-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -11,11 +11,10 @@ + + #ifdef __i386__ + #include +-#define VGABASE (__ISA_IO_base + 0xb8000) + #else + #include +-#define VGABASE ((void __iomem *)0xffffffff800b8000UL) + #endif ++#define VGABASE (__ISA_IO_base + 0xb8000) + + #ifndef CONFIG_XEN + static int max_ypos = 25, max_xpos = 80; +@@ -93,9 +92,9 @@ static int early_serial_putc(unsigned ch + static void early_serial_write(struct console *con, const char *s, unsigned n) + { + while (*s && n-- > 0) { +- early_serial_putc(*s); + if (*s == '\n') + early_serial_putc('\r'); ++ early_serial_putc(*s); + s++; + } + } +@@ -205,7 +204,7 @@ static noinline long simnow(long cmd, lo + return ret; + } + +-void __init simnow_init(char *str) ++static void __init simnow_init(char *str) + { + char *fn = "klog"; + if (*str == '=') +@@ -277,22 +276,12 @@ static int __init setup_early_printk(cha + early_console = &simnow_console; + keep_early = 1; + } ++ ++ if (keep_early) ++ early_console->flags &= ~CON_BOOT; ++ else ++ early_console->flags |= CON_BOOT; + register_console(early_console); + return 0; + } +- + early_param("earlyprintk", setup_early_printk); +- +-void __init disable_early_printk(void) +-{ +- if (!early_console_initialized || !early_console) +- return; +- if (!keep_early) { +- printk("disabling early console\n"); +- unregister_console(early_console); +- early_console_initialized = 0; +- } else { +- printk("keeping early console\n"); +- } +-} +- +--- sle11-2009-04-20.orig/arch/x86/kernel/entry_64-xen.S 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/entry_64-xen.S 2008-12-15 11:27:22.000000000 +0100 +@@ -1254,3 +1254,10 @@ ENTRY(call_softirq) + ret + CFI_ENDPROC + ENDPROC(call_softirq) ++ ++KPROBE_ENTRY(ignore_sysret) ++ CFI_STARTPROC ++ mov $-ENOSYS,%eax ++ HYPERVISOR_IRET 0 ++ CFI_ENDPROC ++ENDPROC(ignore_sysret) +--- sle11-2009-04-20.orig/arch/x86/kernel/genapic_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/genapic_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -11,123 +11,57 @@ + #include + #include + #include ++#include + #include + #include + #include +-#include + + #include + #include ++#include + +-#if defined(CONFIG_ACPI) ++#ifdef CONFIG_ACPI + #include + #endif + + /* which logical CPU number maps to which CPU (physical APIC ID) */ +-u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; ++u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly ++ = { [0 ... NR_CPUS-1] = BAD_APICID }; + EXPORT_SYMBOL(x86_cpu_to_apicid); +-u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; + +-extern struct genapic apic_cluster; +-extern struct genapic apic_flat; +-extern struct genapic apic_physflat; ++u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; + + #ifndef CONFIG_XEN +-struct genapic *genapic = &apic_flat; +-struct genapic *genapic_force; ++struct genapic __read_mostly *genapic = &apic_flat; + #else + extern struct genapic apic_xen; +-struct genapic *genapic = &apic_xen; ++struct genapic __read_mostly *genapic = &apic_xen; + #endif + + + /* + * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode. + */ +-void __init clustered_apic_check(void) ++void __init setup_apic_routing(void) + { + #ifndef CONFIG_XEN +- long i; +- u8 clusters, max_cluster; +- u8 id; +- u8 cluster_cnt[NUM_APIC_CLUSTERS]; +- int max_apic = 0; +- +- /* genapic selection can be forced because of certain quirks. +- */ +- if (genapic_force) { +- genapic = genapic_force; +- goto print; +- } +- +-#if defined(CONFIG_ACPI) ++#ifdef CONFIG_ACPI + /* +- * Some x86_64 machines use physical APIC mode regardless of how many +- * procs/clusters are present (x86_64 ES7000 is an example). ++ * Quirk: some x86_64 machines can only use physical APIC mode ++ * regardless of how many processors are present (x86_64 ES7000 ++ * is an example). + */ +- if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID) +- if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) { +- genapic = &apic_cluster; +- goto print; +- } +-#endif +- +- memset(cluster_cnt, 0, sizeof(cluster_cnt)); +- for (i = 0; i < NR_CPUS; i++) { +- id = bios_cpu_apicid[i]; +- if (id == BAD_APICID) +- continue; +- if (id > max_apic) +- max_apic = id; +- cluster_cnt[APIC_CLUSTERID(id)]++; +- } +- +- /* Don't use clustered mode on AMD platforms. */ +- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { ++ if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID && ++ (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) + genapic = &apic_physflat; +-#ifndef CONFIG_HOTPLUG_CPU +- /* In the CPU hotplug case we cannot use broadcast mode +- because that opens a race when a CPU is removed. +- Stay at physflat mode in this case. +- It is bad to do this unconditionally though. Once +- we have ACPI platform support for CPU hotplug +- we should detect hotplug capablity from ACPI tables and +- only do this when really needed. -AK */ +- if (max_apic <= 8) +- genapic = &apic_flat; +-#endif +- goto print; +- } +- +- clusters = 0; +- max_cluster = 0; +- +- for (i = 0; i < NUM_APIC_CLUSTERS; i++) { +- if (cluster_cnt[i] > 0) { +- ++clusters; +- if (cluster_cnt[i] > max_cluster) +- max_cluster = cluster_cnt[i]; +- } +- } ++ else ++#endif + +- /* +- * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode, +- * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical +- * else physical mode. +- * (We don't use lowest priority delivery + HW APIC IRQ steering, so +- * can ignore the clustered logical case and go straight to physical.) +- */ +- if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) { +-#ifdef CONFIG_HOTPLUG_CPU +- /* Don't use APIC shortcuts in CPU hotplug to avoid races */ +- genapic = &apic_physflat; +-#else ++ if (cpus_weight(cpu_possible_map) <= 8) + genapic = &apic_flat; +-#endif +- } else +- genapic = &apic_cluster; ++ else ++ genapic = &apic_physflat; + +-print: + #else + /* hardcode to xen apic functions */ + genapic = &apic_xen; +@@ -135,7 +69,7 @@ print: + printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); + } + +-/* Same for both flat and clustered. */ ++/* Same for both flat and physical. */ + + #ifdef CONFIG_XEN + extern void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest); +--- sle11-2009-04-20.orig/arch/x86/kernel/genapic_xen_64.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/genapic_xen_64.c 2008-12-15 11:27:22.000000000 +0100 +@@ -21,9 +21,8 @@ + #include + #else + #include +-#include +-#include + #endif ++#include + #include + + DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]); +--- sle11-2009-04-20.orig/arch/x86/kernel/head_64-xen.S 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/head_64-xen.S 2008-12-15 11:27:22.000000000 +0100 +@@ -5,6 +5,7 @@ + * Copyright (C) 2000 Pavel Machek + * Copyright (C) 2000 Karsten Keil + * Copyright (C) 2001,2002 Andi Kleen ++ * Copyright (C) 2005 Eric Biederman + * Jun Nakajima + * Modified for Xen + */ +@@ -34,27 +35,15 @@ startup_64: + pushq $0 # fake return address + jmp x86_64_start_kernel + +-#ifdef CONFIG_ACPI_SLEEP +-.org 0xf00 +- .globl pGDT32 +-pGDT32: +- .word gdt_end-cpu_gdt_table-1 +- .long cpu_gdt_table-__START_KERNEL_map +-#endif +-ENTRY(stext) +-ENTRY(_stext) ++.balign PAGE_SIZE + +- $page = 0 + #define NEXT_PAGE(name) \ +- $page = $page + 1; \ +- .org $page * 0x1000; \ +- phys_##name = $page * 0x1000 + __PHYSICAL_START; \ ++ .balign PAGE_SIZE; \ ++ phys_##name = . - .bootstrap.text; \ + ENTRY(name) + + NEXT_PAGE(init_level4_pgt) +- /* This gets initialized in x86_64_start_kernel */ + .fill 512,8,0 +-NEXT_PAGE(init_level4_user_pgt) + /* + * We update two pgd entries to make kernel and user pgd consistent + * at pgd_populate(). It can be used for kernel modules. So we place +@@ -101,14 +90,6 @@ NEXT_PAGE(hypercall_page) + #undef NEXT_PAGE + + .data +-/* Just dummy symbol to allow compilation. Not used in sleep path */ +-#ifdef CONFIG_ACPI_SLEEP +- .align PAGE_SIZE +-ENTRY(wakeup_level4_pgt) +- .fill 512,8,0 +-#endif +- +- .data + + .align 16 + .globl cpu_gdt_descr +@@ -136,13 +117,13 @@ gdt: + + ENTRY(cpu_gdt_table) + .quad 0x0000000000000000 /* NULL descriptor */ ++ .quad 0x00cf9b000000ffff /* __KERNEL32_CS */ ++ .quad 0x00af9b000000ffff /* __KERNEL_CS */ ++ .quad 0x00cf93000000ffff /* __KERNEL_DS */ ++ .quad 0x00cffb000000ffff /* __USER32_CS */ ++ .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */ ++ .quad 0x00affb000000ffff /* __USER_CS */ + .quad 0x0 /* unused */ +- .quad 0x00af9a000000ffff /* __KERNEL_CS */ +- .quad 0x00cf92000000ffff /* __KERNEL_DS */ +- .quad 0x00cffa000000ffff /* __USER32_CS */ +- .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */ +- .quad 0x00affa000000ffff /* __USER_CS */ +- .quad 0x00cf9a000000ffff /* __KERNEL32_CS */ + .quad 0,0 /* TSS */ + .quad 0,0 /* LDT */ + .quad 0,0,0 /* three TLS descriptors */ +@@ -165,14 +146,11 @@ ENTRY(empty_zero_page) + * __xen_guest information + */ + .macro utoh value +- .if (\value) < 0 || (\value) >= 0x10 +- utoh (((\value)>>4)&0x0fffffffffffffff) +- .endif +- .if ((\value) & 0xf) < 10 +- .byte '0' + ((\value) & 0xf) +- .else +- .byte 'A' + ((\value) & 0xf) - 10 +- .endif ++ i = 64 ++ .rept 16 ++ i = i - 4 ++ .byte '0' + ((((\value) >> i) & 0xf) > 9) * ('0' - 'A' + 10) + (((\value) >> i) & 0xf) ++ .endr + .endm + + .section __xen_guest +--- sle11-2009-04-20.orig/arch/x86/kernel/head64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/head64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -25,13 +25,21 @@ + #include + #include + #include ++#include + #include + + unsigned long start_pfn; + ++#ifndef CONFIG_XEN ++static void __init zap_identity_mappings(void) ++{ ++ pgd_t *pgd = pgd_offset_k(0UL); ++ pgd_clear(pgd); ++ __flush_tlb(); ++} ++ + /* Don't add a printk in there. printk relies on the PDA which is not initialized + yet. */ +-#if 0 + static void __init clear_bss(void) + { + memset(__bss_start, 0, +@@ -40,26 +48,25 @@ static void __init clear_bss(void) + #endif + + #define NEW_CL_POINTER 0x228 /* Relative to real mode data */ +-#define OLD_CL_MAGIC_ADDR 0x90020 ++#define OLD_CL_MAGIC_ADDR 0x20 + #define OLD_CL_MAGIC 0xA33F +-#define OLD_CL_BASE_ADDR 0x90000 +-#define OLD_CL_OFFSET 0x90022 ++#define OLD_CL_OFFSET 0x22 + + static void __init copy_bootdata(char *real_mode_data) + { + #ifndef CONFIG_XEN +- int new_data; ++ unsigned long new_data; + char * command_line; + + memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE); +- new_data = *(int *) (x86_boot_params + NEW_CL_POINTER); ++ new_data = *(u32 *) (x86_boot_params + NEW_CL_POINTER); + if (!new_data) { +- if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) { ++ if (OLD_CL_MAGIC != *(u16 *)(real_mode_data + OLD_CL_MAGIC_ADDR)) { + return; + } +- new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET; ++ new_data = __pa(real_mode_data) + *(u16 *)(real_mode_data + OLD_CL_OFFSET); + } +- command_line = (char *) ((u64)(new_data)); ++ command_line = __va(new_data); + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + #else + int max_cmdline; +@@ -101,10 +108,13 @@ void __init x86_64_start_kernel(char * r + while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents ) + machine_to_phys_order++; + +-#if 0 ++#ifndef CONFIG_XEN + /* clear bss before set_intr_gate with early_idt_handler */ + clear_bss(); + ++ /* Make NULL pointers segfault */ ++ zap_identity_mappings(); ++ + for (i = 0; i < IDT_ENTRIES; i++) + set_intr_gate(i, early_idt_handler); + asm volatile("lidt %0" :: "m" (idt_descr)); +@@ -116,7 +126,7 @@ void __init x86_64_start_kernel(char * r + cpu_pda(i) = &boot_cpu_pda[i]; + + pda_init(0); +- copy_bootdata(real_mode_data); ++ copy_bootdata(__va(real_mode_data)); + #ifdef CONFIG_SMP + cpu_set(0, cpu_online_map); + #endif +--- sle11-2009-04-20.orig/arch/x86/kernel/io_apic_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/io_apic_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -904,10 +903,6 @@ static void __init setup_ExtINT_IRQ0_pin + enable_8259A_irq(0); + } + +-void __init UNEXPECTED_IO_APIC(void) +-{ +-} +- + void __apicdebuginit print_IO_APIC(void) + { + int apic, i; +@@ -943,40 +938,16 @@ void __apicdebuginit print_IO_APIC(void) + printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); + printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); + printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); +- if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) +- UNEXPECTED_IO_APIC(); + + printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); + printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); +- if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ +- (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ +- (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ +- (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ +- (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ +- (reg_01.bits.entries != 0x2E) && +- (reg_01.bits.entries != 0x3F) && +- (reg_01.bits.entries != 0x03) +- ) +- UNEXPECTED_IO_APIC(); + + printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); + printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); +- if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ +- (reg_01.bits.version != 0x02) && /* 82801BA IO-APICs (ICH2) */ +- (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ +- (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ +- (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ +- (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ +- ) +- UNEXPECTED_IO_APIC(); +- if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) +- UNEXPECTED_IO_APIC(); + + if (reg_01.bits.version >= 0x10) { + printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); + printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); +- if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) +- UNEXPECTED_IO_APIC(); + } + + printk(KERN_DEBUG ".... IRQ redirection table:\n"); +@@ -1408,8 +1379,7 @@ static void irq_complete_move(unsigned i + + vector = ~get_irq_regs()->orig_rax; + me = smp_processor_id(); +- if ((vector == cfg->vector) && +- cpu_isset(smp_processor_id(), cfg->domain)) { ++ if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) { + cpumask_t cleanup_mask; + + cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map); +@@ -1444,7 +1414,7 @@ static void ack_apic_level(unsigned int + + /* + * We must acknowledge the irq before we move it or the acknowledge will +- * not propogate properly. ++ * not propagate properly. + */ + ack_APIC_irq(); + +@@ -1527,6 +1497,7 @@ static void ack_lapic_irq (unsigned int + static void end_lapic_irq (unsigned int i) { /* nothing */ } + + static struct hw_interrupt_type lapic_irq_type __read_mostly = { ++ .name = "local-APIC", + .typename = "local-APIC-edge", + .startup = NULL, /* startup_irq() not used for IRQ0 */ + .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ +@@ -1998,18 +1969,18 @@ int arch_setup_msi_irq(struct pci_dev *d + if (irq < 0) + return irq; + +- set_irq_msi(irq, desc); + ret = msi_compose_msg(dev, irq, &msg); + if (ret < 0) { + destroy_irq(irq); + return ret; + } + ++ set_irq_msi(irq, desc); + write_msi_msg(irq, &msg); + + set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); + +- return irq; ++ return 0; + } + + void arch_teardown_msi_irq(unsigned int irq) +--- sle11-2009-04-20.orig/arch/x86/kernel/ioport_64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/ioport_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -13,10 +13,10 @@ + #include + #include + #include +-#include + #include + #include + #include ++#include + #include + + /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +--- sle11-2009-04-20.orig/arch/x86/kernel/irq_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/irq_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -32,7 +32,7 @@ atomic_t irq_err_count; + */ + static inline void stack_overflow_check(struct pt_regs *regs) + { +- u64 curbase = (u64) current->thread_info; ++ u64 curbase = (u64)task_stack_page(current); + static unsigned long warned = -60*HZ; + + if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE && +@@ -145,17 +145,43 @@ void fixup_irqs(cpumask_t map) + + for (irq = 0; irq < NR_IRQS; irq++) { + cpumask_t mask; ++ int break_affinity = 0; ++ int set_affinity = 1; ++ + if (irq == 2) + continue; + ++ /* interrupt's are disabled at this point */ ++ spin_lock(&irq_desc[irq].lock); ++ ++ if (!irq_has_action(irq) || ++ cpus_equal(irq_desc[irq].affinity, map)) { ++ spin_unlock(&irq_desc[irq].lock); ++ continue; ++ } ++ + cpus_and(mask, irq_desc[irq].affinity, map); +- if (any_online_cpu(mask) == NR_CPUS) { +- /*printk("Breaking affinity for irq %i\n", irq);*/ ++ if (cpus_empty(mask)) { ++ break_affinity = 1; + mask = map; + } ++ ++ if (irq_desc[irq].chip->mask) ++ irq_desc[irq].chip->mask(irq); ++ + if (irq_desc[irq].chip->set_affinity) + irq_desc[irq].chip->set_affinity(irq, mask); +- else if (irq_desc[irq].action && !(warned++)) ++ else if (!(warned++)) ++ set_affinity = 0; ++ ++ if (irq_desc[irq].chip->unmask) ++ irq_desc[irq].chip->unmask(irq); ++ ++ spin_unlock(&irq_desc[irq].lock); ++ ++ if (break_affinity && set_affinity) ++ /*printk("Broke affinity for irq %i\n", irq)*/; ++ else if (!set_affinity) + printk("Cannot set affinity for irq %i\n", irq); + } + +--- sle11-2009-04-20.orig/arch/x86/kernel/ldt_64-xen.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/arch/x86/kernel/ldt_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + #include + #include + +--- sle11-2009-04-20.orig/arch/x86/kernel/mpparse_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/mpparse_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -307,7 +306,7 @@ static int __init smp_read_mpc(struct mp + } + } + } +- clustered_apic_check(); ++ setup_apic_routing(); + if (!num_processors) + printk(KERN_ERR "MPTABLE: no processors registered!\n"); + return num_processors; +--- sle11-2009-04-20.orig/arch/x86/kernel/process_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/process_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -49,7 +50,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -232,16 +232,18 @@ void __cpuinit select_idle_routine(const + + static int __init idle_setup (char *str) + { +- if (!strncmp(str, "poll", 4)) { ++ if (!strcmp(str, "poll")) { + printk("using polling idle threads.\n"); + pm_idle = poll_idle; +- } ++ } else if (!strcmp(str, "mwait")) ++ force_mwait = 1; ++ else ++ return -1; + + boot_option_idle_override = 1; +- return 1; ++ return 0; + } +- +-__setup("idle=", idle_setup); ++early_param("idle", idle_setup); + + /* Prints also some state that isn't saved in the pt_regs */ + void __show_regs(struct pt_regs * regs) +@@ -546,7 +548,7 @@ __switch_to(struct task_struct *prev_p, + * The AMD workaround requires it to be after DS reload, or + * after DS has been cleared, which we do in __prepare_arch_switch. + */ +- if (prev_p->thread_info->status & TS_USEDFPU) { ++ if (task_thread_info(prev_p)->status & TS_USEDFPU) { + __save_init_fpu(prev_p); /* _not_ save_init_fpu() */ + mcl->op = __HYPERVISOR_fpu_taskswitch; + mcl->args[0] = 1; +--- sle11-2009-04-20.orig/arch/x86/kernel/setup_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/setup_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -120,6 +120,8 @@ int bootloader_type; + + unsigned long saved_video_mode; + ++int force_mwait __cpuinitdata; ++ + /* + * Early DMI memory + */ +@@ -253,10 +255,10 @@ static void discover_ebda(void) + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E + */ +- ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER; ++ ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER); + ebda_addr <<= 4; + +- ebda_size = *(unsigned short *)(unsigned long)ebda_addr; ++ ebda_size = *(unsigned short *)__va(ebda_addr); + + /* Round EBDA up to pages */ + if (ebda_size == 0) +@@ -410,15 +412,8 @@ void __init setup_arch(char **cmdline_p) + #endif + + #ifdef CONFIG_SMP +- /* +- * But first pinch a few for the stack/trampoline stuff +- * FIXME: Don't need the extra page at 4K, but need to fix +- * trampoline before removing it. (see the GDT stuff) +- */ +- reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE); +- + /* Reserve SMP trampoline */ +- reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, PAGE_SIZE); ++ reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE); + #endif + #endif + +@@ -570,8 +565,6 @@ void __init setup_arch(char **cmdline_p) + early_quirks(); + #endif + +- zap_low_mappings(0); +- + /* + * set this early, so we dont allocate cpu0 + * if MADT list doesnt list BSP first +@@ -864,6 +857,10 @@ static void __cpuinit init_amd(struct cp + + /* RDTSC can be speculated around */ + clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); ++ ++ /* Family 10 doesn't support C states in MWAIT so don't use it */ ++ if (c->x86 == 0x10 && !force_mwait) ++ clear_bit(X86_FEATURE_MWAIT, &c->x86_capability); + } + + static void __cpuinit detect_ht(struct cpuinfo_x86 *c) +@@ -1146,9 +1143,7 @@ void __cpuinit identify_cpu(struct cpuin + #ifdef CONFIG_X86_MCE + mcheck_init(c); + #endif +- if (c == &boot_cpu_data) +- mtrr_bp_init(); +- else ++ if (c != &boot_cpu_data) + mtrr_ap_init(); + #ifdef CONFIG_NUMA + numa_add_cpu(smp_processor_id()); +@@ -1239,9 +1234,8 @@ static int show_cpuinfo(struct seq_file + "stc", + "100mhzsteps", + "hwpstate", +- NULL, /* tsc invariant mapped to constant_tsc */ +- NULL, +- /* nothing */ /* constant_tsc - moved to flags */ ++ "", /* tsc invariant mapped to constant_tsc */ ++ /* nothing */ + }; + + +--- sle11-2009-04-20.orig/arch/x86/kernel/setup64-xen.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/setup64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -113,9 +113,9 @@ void __init setup_per_cpu_areas(void) + if (!NODE_DATA(cpu_to_node(i))) { + printk("cpu with no node %d, num_online_nodes %d\n", + i, num_online_nodes()); +- ptr = alloc_bootmem(size); ++ ptr = alloc_bootmem_pages(size); + } else { +- ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size); ++ ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size); + } + if (!ptr) + panic("Cannot allocate cpu data for CPU %d\n", i); +@@ -208,6 +208,8 @@ char boot_exception_stacks[(N_EXCEPTION_ + __attribute__((section(".bss.page_aligned"))); + #endif + ++extern asmlinkage void ignore_sysret(void); ++ + /* May not be marked __init: used by software suspend */ + void syscall_init(void) + { +@@ -219,12 +221,22 @@ void syscall_init(void) + */ + wrmsrl(MSR_STAR, ((u64)__USER32_CS)<<48 | ((u64)__KERNEL_CS)<<32); + wrmsrl(MSR_LSTAR, system_call); ++ wrmsrl(MSR_CSTAR, ignore_sysret); + + /* Flags to clear on syscall */ + wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); + #endif + #ifdef CONFIG_IA32_EMULATION + syscall32_cpu_init (); ++#else ++ { ++ static const struct callback_register cstar = { ++ .type = CALLBACKTYPE_syscall32, ++ .address = (unsigned long)ignore_sysret ++ }; ++ if (HYPERVISOR_callback_op(CALLBACKOP_register, &cstar)) ++ printk(KERN_WARNING "Unable to register CSTAR callback\n"); ++ } + #endif + } + +@@ -262,7 +274,6 @@ void __cpuinit cpu_init (void) + /* CPU 0 is initialised in head64.c */ + if (cpu != 0) { + pda_init(cpu); +- zap_low_mappings(cpu); + } + #ifndef CONFIG_X86_NO_TSS + else +--- sle11-2009-04-20.orig/arch/x86/kernel/smp_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/smp_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -457,44 +456,36 @@ int smp_call_function (void (*func) (voi + } + EXPORT_SYMBOL(smp_call_function); + +-void smp_stop_cpu(void) ++static void stop_this_cpu(void *dummy) + { +- unsigned long flags; ++ local_irq_disable(); + /* + * Remove this CPU: + */ + cpu_clear(smp_processor_id(), cpu_online_map); +- local_irq_save(flags); + disable_all_local_evtchn(); +- local_irq_restore(flags); +-} +- +-static void smp_really_stop_cpu(void *dummy) +-{ +- smp_stop_cpu(); + for (;;) + halt(); + } + + void smp_send_stop(void) + { +- int nolock = 0; ++ int nolock; ++ unsigned long flags; ++ + #ifndef CONFIG_XEN + if (reboot_force) + return; + #endif ++ + /* Don't deadlock on the call lock in panic */ +- if (!spin_trylock(&call_lock)) { +- /* ignore locking because we have panicked anyways */ +- nolock = 1; +- } +- __smp_call_function(smp_really_stop_cpu, NULL, 0, 0); ++ nolock = !spin_trylock(&call_lock); ++ local_irq_save(flags); ++ __smp_call_function(stop_this_cpu, NULL, 0, 0); + if (!nolock) + spin_unlock(&call_lock); +- +- local_irq_disable(); + disable_all_local_evtchn(); +- local_irq_enable(); ++ local_irq_restore(flags); + } + + /* +--- sle11-2009-04-20.orig/arch/x86/kernel/traps_64-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/traps_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -39,7 +40,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -71,22 +71,6 @@ asmlinkage void alignment_check(void); + asmlinkage void machine_check(void); + asmlinkage void spurious_interrupt_bug(void); + +-ATOMIC_NOTIFIER_HEAD(die_chain); +-EXPORT_SYMBOL(die_chain); +- +-int register_die_notifier(struct notifier_block *nb) +-{ +- vmalloc_sync_all(); +- return atomic_notifier_chain_register(&die_chain, nb); +-} +-EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ +- +-int unregister_die_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(&die_chain, nb); +-} +-EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ +- + static inline void conditional_sti(struct pt_regs *regs) + { + if (regs->eflags & X86_EFLAGS_IF) +@@ -428,8 +412,7 @@ void show_registers(struct pt_regs *regs + const int cpu = smp_processor_id(); + struct task_struct *cur = cpu_pda(cpu)->pcurrent; + +- rsp = regs->rsp; +- ++ rsp = regs->rsp; + printk("CPU %d ", cpu); + __show_regs(regs); + printk("Process %s (pid: %d, threadinfo %p, task %p)\n", +@@ -440,7 +423,6 @@ void show_registers(struct pt_regs *regs + * time of the fault.. + */ + if (in_kernel) { +- + printk("Stack: "); + _show_stack(NULL, regs, (unsigned long*)rsp); + +@@ -485,13 +467,14 @@ static unsigned int die_nest_count; + + unsigned __kprobes long oops_begin(void) + { +- int cpu = smp_processor_id(); ++ int cpu; + unsigned long flags; + + oops_enter(); + + /* racy, but better than risking deadlock. */ + local_irq_save(flags); ++ cpu = smp_processor_id(); + if (!spin_trylock(&die_lock)) { + if (cpu == die_owner) + /* nested oops. should stop eventually */; +@@ -585,10 +568,20 @@ static void __kprobes do_trap(int trapnr + { + struct task_struct *tsk = current; + +- tsk->thread.error_code = error_code; +- tsk->thread.trap_no = trapnr; +- + if (user_mode(regs)) { ++ /* ++ * We want error_code and trap_no set for userspace ++ * faults and kernelspace faults which result in ++ * die(), but not kernelspace faults which are fixed ++ * up. die() gives the process no chance to handle ++ * the signal and notice the kernel fault information, ++ * so that won't result in polluting the information ++ * about previously queued, but not yet delivered, ++ * faults. See also do_general_protection below. ++ */ ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; ++ + if (exception_trace && unhandled_signal(tsk, signr)) + printk(KERN_INFO + "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", +@@ -609,8 +602,11 @@ static void __kprobes do_trap(int trapnr + fixup = search_exception_tables(regs->rip); + if (fixup) + regs->rip = fixup->fixup; +- else ++ else { ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; + die(str, regs, error_code); ++ } + return; + } + } +@@ -686,10 +682,10 @@ asmlinkage void __kprobes do_general_pro + + conditional_sti(regs); + +- tsk->thread.error_code = error_code; +- tsk->thread.trap_no = 13; +- + if (user_mode(regs)) { ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 13; ++ + if (exception_trace && unhandled_signal(tsk, SIGSEGV)) + printk(KERN_INFO + "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", +@@ -708,6 +704,9 @@ asmlinkage void __kprobes do_general_pro + regs->rip = fixup->fixup; + return; + } ++ ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 13; + if (notify_die(DIE_GPF, "general protection fault", regs, + error_code, 13, SIGSEGV) == NOTIFY_STOP) + return; +--- sle11-2009-04-20.orig/arch/x86/kernel/vsyscall_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/kernel/vsyscall_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -45,14 +45,34 @@ + + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) + #define __syscall_clobber "r11","rcx","memory" ++#define __pa_vsymbol(x) \ ++ ({unsigned long v; \ ++ extern char __vsyscall_0; \ ++ asm("" : "=r" (v) : "0" (x)); \ ++ ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); }) + ++/* ++ * vsyscall_gtod_data contains data that is : ++ * - readonly from vsyscalls ++ * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64) ++ * Try to keep this structure as small as possible to avoid cache line ping pongs ++ */ + struct vsyscall_gtod_data_t { +- seqlock_t lock; +- int sysctl_enabled; +- struct timeval wall_time_tv; ++ seqlock_t lock; ++ ++ /* open coded 'struct timespec' */ ++ time_t wall_time_sec; ++ u32 wall_time_nsec; ++ ++ int sysctl_enabled; + struct timezone sys_tz; +- cycle_t offset_base; +- struct clocksource clock; ++ struct { /* extract of a clocksource struct */ ++ cycle_t (*vread)(void); ++ cycle_t cycle_last; ++ cycle_t mask; ++ u32 mult; ++ u32 shift; ++ } clock; + }; + int __vgetcpu_mode __section_vgetcpu_mode; + +@@ -68,9 +88,13 @@ void update_vsyscall(struct timespec *wa + + write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); + /* copy vsyscall data */ +- vsyscall_gtod_data.clock = *clock; +- vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec; +- vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000; ++ vsyscall_gtod_data.clock.vread = clock->vread; ++ vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; ++ vsyscall_gtod_data.clock.mask = clock->mask; ++ vsyscall_gtod_data.clock.mult = clock->mult; ++ vsyscall_gtod_data.clock.shift = clock->shift; ++ vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; ++ vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vsyscall_gtod_data.sys_tz = sys_tz; + write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); + } +@@ -105,7 +129,8 @@ static __always_inline long time_syscall + static __always_inline void do_vgettimeofday(struct timeval * tv) + { + cycle_t now, base, mask, cycle_delta; +- unsigned long seq, mult, shift, nsec_delta; ++ unsigned seq; ++ unsigned long mult, shift, nsec; + cycle_t (*vread)(void); + do { + seq = read_seqbegin(&__vsyscall_gtod_data.lock); +@@ -121,21 +146,20 @@ static __always_inline void do_vgettimeo + mult = __vsyscall_gtod_data.clock.mult; + shift = __vsyscall_gtod_data.clock.shift; + +- *tv = __vsyscall_gtod_data.wall_time_tv; +- ++ tv->tv_sec = __vsyscall_gtod_data.wall_time_sec; ++ nsec = __vsyscall_gtod_data.wall_time_nsec; + } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); + + /* calculate interval: */ + cycle_delta = (now - base) & mask; + /* convert to nsecs: */ +- nsec_delta = (cycle_delta * mult) >> shift; ++ nsec += (cycle_delta * mult) >> shift; + +- /* convert to usecs and add to timespec: */ +- tv->tv_usec += nsec_delta / NSEC_PER_USEC; +- while (tv->tv_usec > USEC_PER_SEC) { ++ while (nsec >= NSEC_PER_SEC) { + tv->tv_sec += 1; +- tv->tv_usec -= USEC_PER_SEC; ++ nsec -= NSEC_PER_SEC; + } ++ tv->tv_usec = nsec / NSEC_PER_USEC; + } + + int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) +@@ -151,11 +175,16 @@ int __vsyscall(0) vgettimeofday(struct t + * unlikely */ + time_t __vsyscall(1) vtime(time_t *t) + { ++ struct timeval tv; ++ time_t result; + if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) + return time_syscall(t); +- else if (t) +- *t = __vsyscall_gtod_data.wall_time_tv.tv_sec; +- return __vsyscall_gtod_data.wall_time_tv.tv_sec; ++ ++ vgettimeofday(&tv, 0); ++ result = tv.tv_sec; ++ if (t) ++ *t = result; ++ return result; + } + + /* Fast way to get current CPU and node. +@@ -224,10 +253,10 @@ static int vsyscall_sysctl_change(ctl_ta + return ret; + /* gcc has some trouble with __va(__pa()), so just do it this + way. */ +- map1 = ioremap(__pa_symbol(&vsysc1), 2); ++ map1 = ioremap(__pa_vsymbol(&vsysc1), 2); + if (!map1) + return -ENOMEM; +- map2 = ioremap(__pa_symbol(&vsysc2), 2); ++ map2 = ioremap(__pa_vsymbol(&vsysc2), 2); + if (!map2) { + ret = -ENOMEM; + goto out; +@@ -304,7 +333,7 @@ static int __cpuinit + cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) + { + long cpu = (long)arg; +- if (action == CPU_ONLINE) ++ if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) + smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); + return NOTIFY_DONE; + } +--- sle11-2009-04-20.orig/arch/x86/mm/fault_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/fault_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -15,22 +15,22 @@ + #include + #include + #include +-#include + #include + #include + #include + #include /* For unblank_screen() */ + #include ++#include + #include + #include + #include ++#include + + #include + #include + #include + #include + #include +-#include + #include + + /* Page fault error code bits */ +@@ -537,6 +537,12 @@ bad_area: + bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ + if (error_code & PF_USER) { ++ ++ /* ++ * It's possible to have interrupts off here. ++ */ ++ local_irq_enable(); ++ + if (is_prefetch(regs, address, error_code)) + return; + +@@ -646,7 +652,7 @@ do_sigbus: + } + + DEFINE_SPINLOCK(pgd_lock); +-struct page *pgd_list; ++LIST_HEAD(pgd_list); + + void vmalloc_sync_all(void) + { +@@ -666,8 +672,7 @@ void vmalloc_sync_all(void) + if (pgd_none(*pgd_ref)) + continue; + spin_lock(&pgd_lock); +- for (page = pgd_list; page; +- page = (struct page *)page->index) { ++ list_for_each_entry(page, &pgd_list, lru) { + pgd_t *pgd; + pgd = (pgd_t *)page_address(page) + pgd_index(address); + if (pgd_none(*pgd)) +--- sle11-2009-04-20.orig/arch/x86/mm/init_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/init_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -25,10 +25,12 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + + #include + #include +@@ -51,7 +53,7 @@ + #define Dprintk(x...) + #endif + +-struct dma_mapping_ops* dma_ops; ++const struct dma_mapping_ops* dma_ops; + EXPORT_SYMBOL(dma_ops); + + #if CONFIG_XEN_COMPAT <= 0x030002 +@@ -191,6 +193,13 @@ void show_mem(void) + + for_each_online_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; ++i) { ++ /* this loop can take a while with 256 GB and 4k pages ++ so update the NMI watchdog */ ++ if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) { ++ touch_nmi_watchdog(); ++ } ++ if (!pfn_valid(pgdat->node_start_pfn + i)) ++ continue; + page = pfn_to_page(pgdat->node_start_pfn + i); + total++; + if (PageReserved(page)) +@@ -359,7 +368,7 @@ __set_fixmap (enum fixed_addresses idx, + } + } + +-unsigned long __initdata table_start, table_end; ++unsigned long __meminitdata table_start, table_end; + + static __meminit void *alloc_static_page(unsigned long *phys) + { +@@ -376,7 +385,7 @@ static __meminit void *alloc_static_page + start_pfn++; + memset((void *)va, 0, PAGE_SIZE); + return (void *)va; +-} ++} + + #define PTE_SIZE PAGE_SIZE + +@@ -412,28 +421,46 @@ static inline int make_readonly(unsigned + + #ifndef CONFIG_XEN + /* Must run before zap_low_mappings */ +-__init void *early_ioremap(unsigned long addr, unsigned long size) ++__meminit void *early_ioremap(unsigned long addr, unsigned long size) + { +- unsigned long map = round_down(addr, LARGE_PAGE_SIZE); +- +- /* actually usually some more */ +- if (size >= LARGE_PAGE_SIZE) { +- return NULL; ++ unsigned long vaddr; ++ pmd_t *pmd, *last_pmd; ++ int i, pmds; ++ ++ pmds = ((addr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE; ++ vaddr = __START_KERNEL_map; ++ pmd = level2_kernel_pgt; ++ last_pmd = level2_kernel_pgt + PTRS_PER_PMD - 1; ++ for (; pmd <= last_pmd; pmd++, vaddr += PMD_SIZE) { ++ for (i = 0; i < pmds; i++) { ++ if (pmd_present(pmd[i])) ++ goto next; ++ } ++ vaddr += addr & ~PMD_MASK; ++ addr &= PMD_MASK; ++ for (i = 0; i < pmds; i++, addr += PMD_SIZE) ++ set_pmd(pmd + i,__pmd(addr | _KERNPG_TABLE | _PAGE_PSE)); ++ __flush_tlb(); ++ return (void *)vaddr; ++ next: ++ ; + } +- set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); +- map += LARGE_PAGE_SIZE; +- set_pmd(temp_mappings[1].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE)); +- __flush_tlb(); +- return temp_mappings[0].address + (addr & (LARGE_PAGE_SIZE-1)); ++ printk("early_ioremap(0x%lx, %lu) failed\n", addr, size); ++ return NULL; + } + + /* To avoid virtual aliases later */ +-__init void early_iounmap(void *addr, unsigned long size) ++__meminit void early_iounmap(void *addr, unsigned long size) + { +- if ((void *)round_down((unsigned long)addr, LARGE_PAGE_SIZE) != temp_mappings[0].address) +- printk("early_iounmap: bad address %p\n", addr); +- set_pmd(temp_mappings[0].pmd, __pmd(0)); +- set_pmd(temp_mappings[1].pmd, __pmd(0)); ++ unsigned long vaddr; ++ pmd_t *pmd; ++ int i, pmds; ++ ++ vaddr = (unsigned long)addr; ++ pmds = ((vaddr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE; ++ pmd = level2_kernel_pgt + pmd_index(vaddr); ++ for (i = 0; i < pmds; i++) ++ pmd_clear(pmd + i); + __flush_tlb(); + } + #endif +@@ -767,14 +794,6 @@ void __meminit init_memory_mapping(unsig + __flush_tlb_all(); + } + +-void __cpuinit zap_low_mappings(int cpu) +-{ +- /* this is not required for Xen */ +-#if 0 +- swap_low_mappings(); +-#endif +-} +- + #ifndef CONFIG_NUMA + void __init paging_init(void) + { +@@ -960,17 +979,6 @@ void __init mem_init(void) + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +- +-#ifndef CONFIG_XEN +-#ifdef CONFIG_SMP +- /* +- * Sync boot_level4_pgt mappings with the init_level4_pgt +- * except for the low identity mappings which are already zapped +- * in init_level4_pgt. This sync-up is essential for AP's bringup +- */ +- memcpy(boot_level4_pgt+1, init_level4_pgt+1, (PTRS_PER_PGD-1)*sizeof(pgd_t)); +-#endif +-#endif + } + + void free_init_pages(char *what, unsigned long begin, unsigned long end) +@@ -980,7 +988,7 @@ void free_init_pages(char *what, unsigne + if (begin >= end) + return; + +- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); ++ printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); + for (addr = begin; addr < end; addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); +@@ -989,24 +997,17 @@ void free_init_pages(char *what, unsigne + if (addr >= __START_KERNEL_map) { + /* make_readonly() reports all kernel addresses. */ + __make_page_writable(__va(__pa(addr))); +- if (HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { +- pgd_t *pgd = pgd_offset_k(addr); +- pud_t *pud = pud_offset(pgd, addr); +- pmd_t *pmd = pmd_offset(pud, addr); +- pte_t *pte = pte_offset_kernel(pmd, addr); +- +- xen_l1_entry_update(pte, __pte(0)); /* fallback */ +- } ++ change_page_attr_addr(addr, 1, __pgprot(0)); + } + free_page(addr); + totalram_pages++; + } ++ if (addr > __START_KERNEL_map) ++ global_flush_tlb(); + } + + void free_initmem(void) + { +- memset(__initdata_begin, POISON_FREE_INITDATA, +- __initdata_end - __initdata_begin); + free_init_pages("unused kernel memory", + (unsigned long)(&__init_begin), + (unsigned long)(&__init_end)); +@@ -1016,13 +1017,28 @@ void free_initmem(void) + + void mark_rodata_ro(void) + { +- unsigned long addr = (unsigned long)__start_rodata; ++ unsigned long start = (unsigned long)_stext, end; ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ /* It must still be possible to apply SMP alternatives. */ ++ if (num_possible_cpus() > 1) ++ start = (unsigned long)_etext; ++#endif ++ ++#ifdef CONFIG_KPROBES ++ start = (unsigned long)__start_rodata; ++#endif ++ ++ end = (unsigned long)__end_rodata; ++ start = (start + PAGE_SIZE - 1) & PAGE_MASK; ++ end &= PAGE_MASK; ++ if (end <= start) ++ return; + +- for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE) +- change_page_attr_addr(addr, 1, PAGE_KERNEL_RO); ++ change_page_attr_addr(start, (end - start) >> PAGE_SHIFT, PAGE_KERNEL_RO); + +- printk ("Write protecting the kernel read-only data: %luk\n", +- (__end_rodata - __start_rodata) >> 10); ++ printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", ++ (end - start) >> 10); + + /* + * change_page_attr_addr() requires a global_flush_tlb() call after it. +@@ -1173,3 +1189,11 @@ int in_gate_area_no_task(unsigned long a + { + return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); + } ++ ++#ifndef CONFIG_XEN ++void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size) ++{ ++ return __alloc_bootmem_core(pgdat->bdata, size, ++ SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0); ++} ++#endif +--- sle11-2009-04-20.orig/arch/x86/mm/pageattr_64-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/arch/x86/mm/pageattr_64-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -215,13 +215,13 @@ void mm_pin_all(void) + preempt_enable(); + } + +-void _arch_dup_mmap(struct mm_struct *mm) ++void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) + { + if (!mm->context.pinned) + mm_pin(mm); + } + +-void _arch_exit_mmap(struct mm_struct *mm) ++void arch_exit_mmap(struct mm_struct *mm) + { + struct task_struct *tsk = current; + +@@ -343,10 +343,11 @@ static void flush_kernel_map(void *arg) + struct page *pg; + + /* When clflush is available always use it because it is +- much cheaper than WBINVD */ +- if (!cpu_has_clflush) ++ much cheaper than WBINVD. Disable clflush for now because ++ the high level code is not ready yet */ ++ if (1 || !cpu_has_clflush) + asm volatile("wbinvd" ::: "memory"); +- list_for_each_entry(pg, l, lru) { ++ else list_for_each_entry(pg, l, lru) { + void *adr = page_address(pg); + if (cpu_has_clflush) + cache_flush_page(adr); +@@ -460,16 +461,24 @@ __change_page_attr(unsigned long address + */ + int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot) + { +- int err = 0; ++ int err = 0, kernel_map = 0; + int i; + ++ if (address >= __START_KERNEL_map ++ && address < __START_KERNEL_map + KERNEL_TEXT_SIZE) { ++ address = (unsigned long)__va(__pa(address)); ++ kernel_map = 1; ++ } ++ + down_write(&init_mm.mmap_sem); + for (i = 0; i < numpages; i++, address += PAGE_SIZE) { + unsigned long pfn = __pa(address) >> PAGE_SHIFT; + +- err = __change_page_attr(address, pfn, prot, PAGE_KERNEL); +- if (err) +- break; ++ if (!kernel_map || pte_present(pfn_pte(0, prot))) { ++ err = __change_page_attr(address, pfn, prot, PAGE_KERNEL); ++ if (err) ++ break; ++ } + /* Handle kernel mapping too which aliases part of the + * lowmem */ + if (__pa(address) < KERNEL_TEXT_SIZE) { +--- sle11-2009-04-20.orig/drivers/char/tpm/tpm_xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/drivers/char/tpm/tpm_xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -463,7 +463,7 @@ static int tpmif_connect(struct xenbus_d + tp->backend_id = domid; + + err = bind_listening_port_to_irqhandler( +- domid, tpmif_int, SA_SAMPLE_RANDOM, "tpmif", tp); ++ domid, tpmif_int, IRQF_SAMPLE_RANDOM, "tpmif", tp); + if (err <= 0) { + WPRINTK("bind_listening_port_to_irqhandler failed " + "(err=%d)\n", err); +--- sle11-2009-04-20.orig/drivers/pci/msi-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/drivers/pci/msi-xen.c 2008-12-15 11:27:22.000000000 +0100 +@@ -12,16 +12,15 @@ + #include + #include + #include +-#include + #include + #include + #include ++#include + + #include + + #include + #include +-#include + + #include "pci.h" + #include "msi.h" +@@ -154,6 +153,7 @@ int register_msi_get_owner(int (*func)(s + get_owner = func; + return 0; + } ++EXPORT_SYMBOL(register_msi_get_owner); + + int unregister_msi_get_owner(int (*func)(struct pci_dev *dev)) + { +@@ -162,6 +162,7 @@ int unregister_msi_get_owner(int (*func) + get_owner = NULL; + return 0; + } ++EXPORT_SYMBOL(unregister_msi_get_owner); + + static int msi_get_dev_owner(struct pci_dev *dev) + { +@@ -263,11 +264,6 @@ static int msi_map_vector(struct pci_dev + return msi_map_pirq_to_vector(dev, -1, entry_nr, table_base); + } + +-static int msi_init(void) +-{ +- return 0; +-} +- + #ifdef CONFIG_PM + static void __pci_restore_msi_state(struct pci_dev *dev) + { +@@ -434,21 +430,32 @@ static int msix_capability_init(struct p + } + + /** +- * pci_msi_supported - check whether MSI may be enabled on device ++ * pci_msi_check_device - check whether MSI may be enabled on a device + * @dev: pointer to the pci_dev data structure of MSI device function ++ * @nvec: how many MSIs have been requested ? ++ * @type: are we checking for MSI or MSI-X ? + * + * Look at global flags, the device itself, and its parent busses +- * to return 0 if MSI are supported for the device. ++ * to determine if MSI/-X are supported for the device. If MSI/-X is ++ * supported return 0, else return an error code. + **/ +-static +-int pci_msi_supported(struct pci_dev * dev) ++static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) + { + struct pci_bus *bus; ++ int ret; + + /* MSI must be globally enabled and supported by the device */ + if (!pci_msi_enable || !dev || dev->no_msi) + return -EINVAL; + ++ /* ++ * You can't ask to have 0 or less MSIs configured. ++ * a) it's stupid .. ++ * b) the list manipulation code assumes nvec >= 1. ++ */ ++ if (nvec < 1) ++ return -ERANGE; ++ + /* Any bridge which does NOT route MSI transactions from it's + * secondary bus to it's primary bus must set NO_MSI flag on + * the secondary pci_bus. +@@ -459,6 +466,13 @@ int pci_msi_supported(struct pci_dev * d + if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) + return -EINVAL; + ++ ret = arch_msi_check_device(dev, nvec, type); ++ if (ret) ++ return ret; ++ ++ if (!pci_find_capability(dev, type)) ++ return -EINVAL; ++ + return 0; + } + +@@ -475,14 +489,11 @@ int pci_msi_supported(struct pci_dev * d + extern int pci_frontend_enable_msi(struct pci_dev *dev); + int pci_enable_msi(struct pci_dev* dev) + { +- int pos, temp, status; ++ int temp, status; + +- if (pci_msi_supported(dev) < 0) +- return -EINVAL; +- +- status = msi_init(); +- if (status < 0) +- return status; ++ status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); ++ if (status) ++ return status; + + #ifdef CONFIG_XEN_PCIDEV_FRONTEND + if (!is_initial_xendomain()) +@@ -503,10 +514,6 @@ int pci_enable_msi(struct pci_dev* dev) + + temp = dev->irq; + +- pos = pci_find_capability(dev, PCI_CAP_ID_MSI); +- if (!pos) +- return -EINVAL; +- + /* Check whether driver already requested for MSI-X irqs */ + if (dev->msix_enabled) { + printk(KERN_INFO "PCI: %s: Can't enable MSI. " +@@ -521,15 +528,14 @@ int pci_enable_msi(struct pci_dev* dev) + + return status; + } ++EXPORT_SYMBOL(pci_enable_msi); + + extern void pci_frontend_disable_msi(struct pci_dev* dev); + void pci_disable_msi(struct pci_dev* dev) + { + int pirq; + +- if (!pci_msi_enable) +- return; +- if (!dev) ++ if (!pci_msi_enable || !dev) + return; + + #ifdef CONFIG_XEN_PCIDEV_FRONTEND +@@ -554,6 +560,7 @@ void pci_disable_msi(struct pci_dev* dev + pci_intx(dev, 1); /* enable intx */ + dev->msi_enabled = 0; + } ++EXPORT_SYMBOL(pci_disable_msi); + + /** + * pci_enable_msix - configure device's MSI-X capability structure +@@ -578,7 +585,7 @@ int pci_enable_msix(struct pci_dev* dev, + int i, j, temp; + u16 control; + +- if (!entries || pci_msi_supported(dev) < 0) ++ if (!entries) + return -EINVAL; + + #ifdef CONFIG_XEN_PCIDEV_FRONTEND +@@ -616,14 +623,11 @@ int pci_enable_msix(struct pci_dev* dev, + } + #endif + +- status = msi_init(); +- if (status < 0) ++ status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX); ++ if (status) + return status; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); +- if (!pos) +- return -EINVAL; +- + pci_read_config_word(dev, msi_control_reg(pos), &control); + nr_entries = multi_msix_capable(control); + if (nvec > nr_entries) +@@ -655,6 +659,7 @@ int pci_enable_msix(struct pci_dev* dev, + + return status; + } ++EXPORT_SYMBOL(pci_enable_msix); + + extern void pci_frontend_disable_msix(struct pci_dev* dev); + void pci_disable_msix(struct pci_dev* dev) +@@ -694,6 +699,7 @@ void pci_disable_msix(struct pci_dev* de + pci_intx(dev, 1); /* enable intx */ + dev->msix_enabled = 0; + } ++EXPORT_SYMBOL(pci_disable_msix); + + /** + * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state +@@ -737,12 +743,57 @@ void pci_no_msi(void) + pci_msi_enable = 0; + } + +-EXPORT_SYMBOL(pci_enable_msi); +-EXPORT_SYMBOL(pci_disable_msi); +-EXPORT_SYMBOL(pci_enable_msix); +-EXPORT_SYMBOL(pci_disable_msix); +-#ifdef CONFIG_XEN +-EXPORT_SYMBOL(register_msi_get_owner); +-EXPORT_SYMBOL(unregister_msi_get_owner); ++void pci_msi_init_pci_dev(struct pci_dev *dev) ++{ ++#ifndef CONFIG_XEN ++ INIT_LIST_HEAD(&dev->msi_list); + #endif ++} ++ ++ ++/* Arch hooks */ ++ ++int __attribute__ ((weak)) ++arch_msi_check_device(struct pci_dev* dev, int nvec, int type) ++{ ++ return 0; ++} ++ ++#ifndef CONFIG_XEN ++int __attribute__ ((weak)) ++arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) ++{ ++ return 0; ++} ++ ++int __attribute__ ((weak)) ++arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ++{ ++ struct msi_desc *entry; ++ int ret; + ++ list_for_each_entry(entry, &dev->msi_list, list) { ++ ret = arch_setup_msi_irq(dev, entry); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) ++{ ++ return; ++} ++ ++void __attribute__ ((weak)) ++arch_teardown_msi_irqs(struct pci_dev *dev) ++{ ++ struct msi_desc *entry; ++ ++ list_for_each_entry(entry, &dev->msi_list, list) { ++ if (entry->irq != 0) ++ arch_teardown_msi_irq(entry->irq); ++ } ++} ++#endif +--- sle11-2009-04-20.orig/drivers/xen/blkfront/blkfront.c 2009-03-24 10:08:49.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/blkfront/blkfront.c 2009-03-24 10:11:24.000000000 +0100 +@@ -244,7 +244,7 @@ static int setup_blkring(struct xenbus_d + info->ring_ref = err; + + err = bind_listening_port_to_irqhandler( +- dev->otherend_id, blkif_int, SA_SAMPLE_RANDOM, "blkif", info); ++ dev->otherend_id, blkif_int, IRQF_SAMPLE_RANDOM, "blkif", info); + if (err <= 0) { + xenbus_dev_fatal(dev, err, + "bind_listening_port_to_irqhandler"); +--- sle11-2009-04-20.orig/drivers/xen/char/mem.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/char/mem.c 2008-12-15 11:27:22.000000000 +0100 +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +--- sle11-2009-04-20.orig/drivers/xen/core/hypervisor_sysfs.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/core/hypervisor_sysfs.c 2008-12-15 11:27:22.000000000 +0100 +@@ -50,7 +50,7 @@ static int __init hypervisor_subsys_init + if (!is_running_on_xen()) + return -ENODEV; + +- hypervisor_subsys.kset.kobj.ktype = &hyp_sysfs_kobj_type; ++ hypervisor_subsys.kobj.ktype = &hyp_sysfs_kobj_type; + return 0; + } + +--- sle11-2009-04-20.orig/drivers/xen/core/smpboot.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/core/smpboot.c 2008-12-15 11:27:22.000000000 +0100 +@@ -161,13 +161,12 @@ static void xen_smp_intr_exit(unsigned i + + void __cpuinit cpu_bringup(void) + { ++ cpu_init(); + #ifdef __i386__ +- cpu_set_gdt(current_thread_info()->cpu); +- secondary_cpu_init(); ++ identify_secondary_cpu(cpu_data + smp_processor_id()); + #else +- cpu_init(); +-#endif + identify_cpu(cpu_data + smp_processor_id()); ++#endif + touch_softlockup_watchdog(); + preempt_disable(); + local_irq_enable(); +@@ -187,11 +186,6 @@ static void __cpuinit cpu_initialize_con + static DEFINE_SPINLOCK(ctxt_lock); + + struct task_struct *idle = idle_task(cpu); +-#ifdef __x86_64__ +- struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu]; +-#else +- struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu); +-#endif + + if (cpu_test_and_set(cpu, cpu_initialized_map)) + return; +@@ -214,11 +208,11 @@ static void __cpuinit cpu_initialize_con + smp_trap_init(ctxt.trap_ctxt); + + ctxt.ldt_ents = 0; +- +- ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address); +- ctxt.gdt_ents = gdt_descr->size / 8; ++ ctxt.gdt_ents = GDT_SIZE / 8; + + #ifdef __i386__ ++ ctxt.gdt_frames[0] = virt_to_mfn(get_cpu_gdt_table(cpu)); ++ + ctxt.user_regs.cs = __KERNEL_CS; + ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs); + +@@ -231,7 +225,11 @@ static void __cpuinit cpu_initialize_con + ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback; + + ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir)); ++ ++ ctxt.user_regs.fs = __KERNEL_PERCPU; + #else /* __x86_64__ */ ++ ctxt.gdt_frames[0] = virt_to_mfn(cpu_gdt_descr[cpu].address); ++ + ctxt.user_regs.cs = __KERNEL_CS; + ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs); + +@@ -261,9 +259,8 @@ void __init smp_prepare_cpus(unsigned in + struct vcpu_get_physid cpu_id; + #ifdef __x86_64__ + struct desc_ptr *gdt_descr; +-#else +- struct Xgt_desc_struct *gdt_descr; + #endif ++ void *gdt_addr; + + apicid = 0; + if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, 0, &cpu_id) == 0) +@@ -313,14 +310,12 @@ void __init smp_prepare_cpus(unsigned in + } + gdt_descr->size = GDT_SIZE; + memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE); ++ gdt_addr = (void *)gdt_descr->address; + #else +- if (unlikely(!init_gdt(cpu, idle))) +- continue; +- gdt_descr = &per_cpu(cpu_gdt_descr, cpu); ++ init_gdt(cpu); ++ gdt_addr = get_cpu_gdt_table(cpu); + #endif +- make_page_readonly( +- (void *)gdt_descr->address, +- XENFEAT_writable_descriptor_tables); ++ make_page_readonly(gdt_addr, XENFEAT_writable_descriptor_tables); + + apicid = cpu; + if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) +@@ -334,7 +329,9 @@ void __init smp_prepare_cpus(unsigned in + #ifdef __x86_64__ + cpu_pda(cpu)->pcurrent = idle; + cpu_pda(cpu)->cpunumber = cpu; +- clear_ti_thread_flag(idle->thread_info, TIF_FORK); ++ clear_ti_thread_flag(task_thread_info(idle), TIF_FORK); ++#else ++ per_cpu(current_task, cpu) = idle; + #endif + + irq_ctx_init(cpu); +@@ -359,8 +356,12 @@ void __init smp_prepare_cpus(unsigned in + #endif + } + +-void __devinit smp_prepare_boot_cpu(void) ++void __init smp_prepare_boot_cpu(void) + { ++#ifdef __i386__ ++ init_gdt(smp_processor_id()); ++ switch_to_new_gdt(); ++#endif + prefill_possible_map(); + } + +--- sle11-2009-04-20.orig/drivers/xen/core/xen_sysfs.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/core/xen_sysfs.c 2008-12-15 11:27:22.000000000 +0100 +@@ -29,12 +29,12 @@ HYPERVISOR_ATTR_RO(type); + + static int __init xen_sysfs_type_init(void) + { +- return sysfs_create_file(&hypervisor_subsys.kset.kobj, &type_attr.attr); ++ return sysfs_create_file(&hypervisor_subsys.kobj, &type_attr.attr); + } + + static void xen_sysfs_type_destroy(void) + { +- sysfs_remove_file(&hypervisor_subsys.kset.kobj, &type_attr.attr); ++ sysfs_remove_file(&hypervisor_subsys.kobj, &type_attr.attr); + } + + /* xen version attributes */ +@@ -90,13 +90,13 @@ static struct attribute_group version_gr + + static int __init xen_sysfs_version_init(void) + { +- return sysfs_create_group(&hypervisor_subsys.kset.kobj, ++ return sysfs_create_group(&hypervisor_subsys.kobj, + &version_group); + } + + static void xen_sysfs_version_destroy(void) + { +- sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group); ++ sysfs_remove_group(&hypervisor_subsys.kobj, &version_group); + } + + /* UUID */ +@@ -126,12 +126,12 @@ HYPERVISOR_ATTR_RO(uuid); + + static int __init xen_sysfs_uuid_init(void) + { +- return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr); ++ return sysfs_create_file(&hypervisor_subsys.kobj, &uuid_attr.attr); + } + + static void xen_sysfs_uuid_destroy(void) + { +- sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr); ++ sysfs_remove_file(&hypervisor_subsys.kobj, &uuid_attr.attr); + } + + /* xen compilation attributes */ +@@ -204,13 +204,13 @@ static struct attribute_group xen_compil + + int __init static xen_compilation_init(void) + { +- return sysfs_create_group(&hypervisor_subsys.kset.kobj, ++ return sysfs_create_group(&hypervisor_subsys.kobj, + &xen_compilation_group); + } + + static void xen_compilation_destroy(void) + { +- sysfs_remove_group(&hypervisor_subsys.kset.kobj, ++ sysfs_remove_group(&hypervisor_subsys.kobj, + &xen_compilation_group); + } + +@@ -325,13 +325,13 @@ static struct attribute_group xen_proper + + static int __init xen_properties_init(void) + { +- return sysfs_create_group(&hypervisor_subsys.kset.kobj, ++ return sysfs_create_group(&hypervisor_subsys.kobj, + &xen_properties_group); + } + + static void xen_properties_destroy(void) + { +- sysfs_remove_group(&hypervisor_subsys.kset.kobj, ++ sysfs_remove_group(&hypervisor_subsys.kobj, + &xen_properties_group); + } + +@@ -350,13 +350,13 @@ HYPERVISOR_ATTR_RO(vmcoreinfo); + + static int __init xen_sysfs_vmcoreinfo_init(void) + { +- return sysfs_create_file(&hypervisor_subsys.kset.kobj, ++ return sysfs_create_file(&hypervisor_subsys.kobj, + &vmcoreinfo_attr.attr); + } + + static void xen_sysfs_vmcoreinfo_destroy(void) + { +- sysfs_remove_file(&hypervisor_subsys.kset.kobj, &vmcoreinfo_attr.attr); ++ sysfs_remove_file(&hypervisor_subsys.kobj, &vmcoreinfo_attr.attr); + } + + #endif +--- sle11-2009-04-20.orig/drivers/xen/netback/netback.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/netback/netback.c 2008-12-23 09:33:22.000000000 +0100 +@@ -195,7 +195,7 @@ static struct sk_buff *netbk_copy_skb(st + goto err; + + skb_reserve(nskb, 16 + NET_IP_ALIGN); +- headlen = nskb->end - nskb->data; ++ headlen = skb_end_pointer(nskb) - nskb->data; + if (headlen > skb_headlen(skb)) + headlen = skb_headlen(skb); + ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen); +@@ -241,11 +241,15 @@ static struct sk_buff *netbk_copy_skb(st + len -= copy; + } + ++#ifdef NET_SKBUFF_DATA_USES_OFFSET ++ offset = 0; ++#else + offset = nskb->data - skb->data; ++#endif + +- nskb->h.raw = skb->h.raw + offset; +- nskb->nh.raw = skb->nh.raw + offset; +- nskb->mac.raw = skb->mac.raw + offset; ++ nskb->transport_header = skb->transport_header + offset; ++ nskb->network_header = skb->network_header + offset; ++ nskb->mac_header = skb->mac_header + offset; + + return nskb; + +@@ -1619,7 +1623,7 @@ static int __init netback_init(void) + (void)bind_virq_to_irqhandler(VIRQ_DEBUG, + 0, + netif_be_dbg, +- SA_SHIRQ, ++ IRQF_SHARED, + "net-be-dbg", + &netif_be_dbg); + #endif +--- sle11-2009-04-20.orig/drivers/xen/netfront/netfront.c 2009-03-30 16:35:44.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/netfront/netfront.c 2009-03-30 16:36:30.000000000 +0200 +@@ -513,7 +513,7 @@ static int setup_device(struct xenbus_de + memcpy(netdev->dev_addr, info->mac, ETH_ALEN); + + err = bind_listening_port_to_irqhandler( +- dev->otherend_id, netif_int, SA_SAMPLE_RANDOM, netdev->name, ++ dev->otherend_id, netif_int, IRQF_SAMPLE_RANDOM, netdev->name, + netdev); + if (err < 0) + goto fail; +--- sle11-2009-04-20.orig/drivers/xen/pciback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/pciback/xenbus.c 2008-12-15 11:27:22.000000000 +0100 +@@ -99,7 +99,7 @@ static int pciback_do_attach(struct pcib + + err = bind_interdomain_evtchn_to_irqhandler( + pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event, +- SA_SAMPLE_RANDOM, "pciback", pdev); ++ IRQF_SAMPLE_RANDOM, "pciback", pdev); + if (err < 0) { + xenbus_dev_fatal(pdev->xdev, err, + "Error binding event channel to IRQ"); +--- sle11-2009-04-20.orig/drivers/xen/pcifront/xenbus.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/pcifront/xenbus.c 2008-12-15 11:27:22.000000000 +0100 +@@ -10,10 +10,6 @@ + #include + #include "pcifront.h" + +-#ifndef __init_refok +-#define __init_refok +-#endif +- + #define INVALID_GRANT_REF (0) + #define INVALID_EVTCHN (-1) + +--- sle11-2009-04-20.orig/drivers/xen/scsifront/xenbus.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/scsifront/xenbus.c 2008-12-15 11:27:22.000000000 +0100 +@@ -96,7 +96,7 @@ static int scsifront_alloc_ring(struct v + + err = bind_listening_port_to_irqhandler( + dev->otherend_id, scsifront_intr, +- SA_SAMPLE_RANDOM, "scsifront", info); ++ IRQF_SAMPLE_RANDOM, "scsifront", info); + + if (err <= 0) { + xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler"); +--- sle11-2009-04-20.orig/drivers/xen/sfc_netback/accel_fwd.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/sfc_netback/accel_fwd.c 2008-12-15 11:27:22.000000000 +0100 +@@ -308,7 +308,7 @@ static struct netback_accel *for_a_vnic( + static inline int packet_is_arp_reply(struct sk_buff *skb) + { + return skb->protocol == ntohs(ETH_P_ARP) +- && skb->nh.arph->ar_op == ntohs(ARPOP_REPLY); ++ && arp_hdr(skb)->ar_op == ntohs(ARPOP_REPLY); + } + + +@@ -392,12 +392,13 @@ void netback_accel_tx_packet(struct sk_b + + BUG_ON(fwd_priv == NULL); + +- if (is_broadcast_ether_addr(skb->mac.raw) && packet_is_arp_reply(skb)) { ++ if (is_broadcast_ether_addr(skb_mac_header(skb)) ++ && packet_is_arp_reply(skb)) { + /* + * update our fast path forwarding to reflect this + * gratuitous ARP + */ +- mac = skb->mac.raw+ETH_ALEN; ++ mac = skb_mac_header(skb)+ETH_ALEN; + + DPRINTK("%s: found gratuitous ARP for " MAC_FMT "\n", + __FUNCTION__, MAC_ARG(mac)); +--- sle11-2009-04-20.orig/drivers/xen/sfc_netback/accel_solarflare.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/sfc_netback/accel_solarflare.c 2009-03-30 16:36:16.000000000 +0200 +@@ -113,7 +113,7 @@ bend_dl_tx_packet(struct efx_dl_device * + BUG_ON(port == NULL); + + NETBACK_ACCEL_STATS_OP(global_stats.dl_tx_packets++); +- if (skb->mac.raw != NULL) ++ if (skb_mac_header_was_set(skb)) + netback_accel_tx_packet(skb, port->fwd_priv); + else { + DPRINTK("Ignoring packet with missing mac address\n"); +--- sle11-2009-04-20.orig/drivers/xen/sfc_netfront/accel_tso.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/drivers/xen/sfc_netfront/accel_tso.c 2008-12-15 11:27:22.000000000 +0100 +@@ -33,10 +33,9 @@ + + #include "accel_tso.h" + +-#define PTR_DIFF(p1, p2) ((u8*)(p1) - (u8*)(p2)) +-#define ETH_HDR_LEN(skb) ((skb)->nh.raw - (skb)->data) +-#define SKB_TCP_OFF(skb) PTR_DIFF ((skb)->h.th, (skb)->data) +-#define SKB_IP_OFF(skb) PTR_DIFF ((skb)->nh.iph, (skb)->data) ++#define ETH_HDR_LEN(skb) skb_network_offset(skb) ++#define SKB_TCP_OFF(skb) skb_transport_offset(skb) ++#define SKB_IP_OFF(skb) skb_network_offset(skb) + + /* + * Set a maximum number of buffers in each output packet to make life +@@ -114,9 +113,8 @@ struct netfront_accel_tso_state { + static inline void tso_check_safe(struct sk_buff *skb) { + EPRINTK_ON(skb->protocol != htons (ETH_P_IP)); + EPRINTK_ON(((struct ethhdr*) skb->data)->h_proto != htons (ETH_P_IP)); +- EPRINTK_ON(skb->nh.iph->protocol != IPPROTO_TCP); +- EPRINTK_ON((SKB_TCP_OFF(skb) +- + (skb->h.th->doff << 2u)) > skb_headlen(skb)); ++ EPRINTK_ON(ip_hdr(skb)->protocol != IPPROTO_TCP); ++ EPRINTK_ON((SKB_TCP_OFF(skb) + tcp_hdrlen(skb)) > skb_headlen(skb)); + } + + +@@ -129,17 +127,17 @@ static inline void tso_start(struct netf + * All ethernet/IP/TCP headers combined size is TCP header size + * plus offset of TCP header relative to start of packet. + */ +- st->p.header_length = (skb->h.th->doff << 2u) + SKB_TCP_OFF(skb); ++ st->p.header_length = tcp_hdrlen(skb) + SKB_TCP_OFF(skb); + st->p.full_packet_size = (st->p.header_length + + skb_shinfo(skb)->gso_size); + st->p.gso_size = skb_shinfo(skb)->gso_size; + +- st->p.ip_id = htons(skb->nh.iph->id); +- st->seqnum = ntohl(skb->h.th->seq); ++ st->p.ip_id = htons(ip_hdr(skb)->id); ++ st->seqnum = ntohl(tcp_hdr(skb)->seq); + +- EPRINTK_ON(skb->h.th->urg); +- EPRINTK_ON(skb->h.th->syn); +- EPRINTK_ON(skb->h.th->rst); ++ EPRINTK_ON(tcp_hdr(skb)->urg); ++ EPRINTK_ON(tcp_hdr(skb)->syn); ++ EPRINTK_ON(tcp_hdr(skb)->rst); + + st->remaining_len = skb->len - st->p.header_length; + +@@ -258,8 +256,8 @@ int tso_start_new_packet(netfront_accel_ + /* This packet will be the last in the TSO burst. */ + ip_length = (st->p.header_length - ETH_HDR_LEN(skb) + + st->remaining_len); +- tsoh_th->fin = skb->h.th->fin; +- tsoh_th->psh = skb->h.th->psh; ++ tsoh_th->fin = tcp_hdr(skb)->fin; ++ tsoh_th->psh = tcp_hdr(skb)->psh; + } + + tsoh_iph->tot_len = htons(ip_length); +--- sle11-2009-04-20.orig/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:35:25.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:36:26.000000000 +0200 +@@ -463,7 +463,7 @@ netfront_accel_enqueue_skb_multi(netfron + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Set to zero to encourage falcon to work it out for us */ +- *(u16*)(skb->h.raw + skb->csum_offset) = 0; ++ *(u16*)(skb->head + skb->csum_start + skb->csum_offset) = 0; + } + + if (multi_post_start_new_buffer(vnic, &state)) { +@@ -582,7 +582,7 @@ netfront_accel_enqueue_skb_single(netfro + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* Set to zero to encourage falcon to work it out for us */ +- *(u16*)(skb->h.raw + skb->csum_offset) = 0; ++ *(u16*)(skb->head + skb->csum_start + skb->csum_offset) = 0; + } + NETFRONT_ACCEL_PKTBUFF_FOR_EACH_FRAGMENT + (skb, idx, frag_data, frag_len, { +--- sle11-2009-04-20.orig/drivers/xen/sfc_netfront/accel_xenbus.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/drivers/xen/sfc_netfront/accel_xenbus.c 2008-12-15 11:27:22.000000000 +0100 +@@ -356,7 +356,7 @@ static int vnic_setup_domU_shared_state( + /* Create xenbus msg event channel */ + err = bind_listening_port_to_irqhandler + (dev->otherend_id, netfront_accel_msg_channel_irq_from_bend, +- SA_SAMPLE_RANDOM, "vnicctrl", vnic); ++ IRQF_SAMPLE_RANDOM, "vnicctrl", vnic); + if (err < 0) { + EPRINTK("Couldn't bind msg event channel\n"); + goto fail_msg_irq; +@@ -367,7 +367,7 @@ static int vnic_setup_domU_shared_state( + /* Create xenbus net event channel */ + err = bind_listening_port_to_irqhandler + (dev->otherend_id, netfront_accel_net_channel_irq_from_bend, +- SA_SAMPLE_RANDOM, "vnicfront", vnic); ++ IRQF_SAMPLE_RANDOM, "vnicfront", vnic); + if (err < 0) { + EPRINTK("Couldn't bind net event channel\n"); + goto fail_net_irq; +--- sle11-2009-04-20.orig/fs/aio.c 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/fs/aio.c 2009-03-24 10:11:37.000000000 +0100 +@@ -38,7 +38,7 @@ + + #ifdef CONFIG_EPOLL + #include +-#include ++#include + #endif + + #if DEBUG > 1 +@@ -1325,7 +1325,7 @@ static const struct file_operations aioq + + /* make_aio_fd: + * Create a file descriptor that can be used to poll the event queue. +- * Based and piggybacked on the excellent epoll code. ++ * Based on the excellent epoll code. + */ + + static int make_aio_fd(struct kioctx *ioctx) +@@ -1334,7 +1334,8 @@ static int make_aio_fd(struct kioctx *io + struct inode *inode; + struct file *file; + +- error = ep_getfd(&fd, &inode, &file, NULL, &aioq_fops); ++ error = anon_inode_getfd(&fd, &inode, &file, "[aioq]", ++ &aioq_fops, ioctx); + if (error) + return error; + +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/desc_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/desc_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -11,23 +11,24 @@ + + #include + +-extern struct desc_struct cpu_gdt_table[GDT_ENTRIES]; +- + struct Xgt_desc_struct { + unsigned short size; + unsigned long address __attribute__((packed)); + unsigned short pad; + } __attribute__ ((packed)); + +-extern struct Xgt_desc_struct idt_descr; +-DECLARE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); +-extern struct Xgt_desc_struct early_gdt_descr; ++struct gdt_page ++{ ++ struct desc_struct gdt[GDT_ENTRIES]; ++} __attribute__((aligned(PAGE_SIZE))); ++DECLARE_PER_CPU(struct gdt_page, gdt_page); + + static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) + { +- return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address; ++ return per_cpu(gdt_page, cpu).gdt; + } + ++extern struct Xgt_desc_struct idt_descr; + extern struct desc_struct idt_table[]; + extern void set_intr_gate(unsigned int irq, void * addr); + +@@ -55,53 +56,32 @@ static inline void pack_gate(__u32 *a, _ + #define DESCTYPE_S 0x10 /* !system */ + + #ifndef CONFIG_XEN +-#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) +- +-#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) +-#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) ++#define load_TR_desc() native_load_tr_desc() ++#define load_gdt(dtr) native_load_gdt(dtr) ++#define load_idt(dtr) native_load_idt(dtr) + #define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr)) + #define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt)) + +-#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr)) +-#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) +-#define store_tr(tr) __asm__ ("str %0":"=m" (tr)) ++#define store_gdt(dtr) native_store_gdt(dtr) ++#define store_idt(dtr) native_store_idt(dtr) ++#define store_tr(tr) (tr = native_store_tr()) + #define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt)) +-#endif + +-#if TLS_SIZE != 24 +-# error update this code. +-#endif +- +-static inline void load_TLS(struct thread_struct *t, unsigned int cpu) +-{ +-#define C(i) if (HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), \ +- *(u64 *)&t->tls_array[i]) \ +- BUG() +- C(0); C(1); C(2); +-#undef C +-} ++#define load_TLS(t, cpu) native_load_tls(t, cpu) ++#define set_ldt native_set_ldt + +-#ifndef CONFIG_XEN + #define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) + #define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) + #define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b) + +-static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b) ++static inline void write_dt_entry(struct desc_struct *dt, ++ int entry, u32 entry_low, u32 entry_high) + { +- __u32 *lp = (__u32 *)((char *)dt + entry*8); +- *lp = entry_a; +- *(lp+1) = entry_b; ++ dt[entry].a = entry_low; ++ dt[entry].b = entry_high; + } +-#define set_ldt native_set_ldt +-#else +-extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); +-extern int write_gdt_entry(void *gdt, int entry, __u32 entry_a, __u32 entry_b); +-#define set_ldt xen_set_ldt +-#endif + +-#ifndef CONFIG_XEN +-static inline fastcall void native_set_ldt(const void *addr, +- unsigned int entries) ++static inline void native_set_ldt(const void *addr, unsigned int entries) + { + if (likely(entries == 0)) + __asm__ __volatile__("lldt %w0"::"q" (0)); +@@ -116,6 +96,65 @@ static inline fastcall void native_set_l + __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)); + } + } ++ ++ ++static inline void native_load_tr_desc(void) ++{ ++ asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); ++} ++ ++static inline void native_load_gdt(const struct Xgt_desc_struct *dtr) ++{ ++ asm volatile("lgdt %0"::"m" (*dtr)); ++} ++ ++static inline void native_load_idt(const struct Xgt_desc_struct *dtr) ++{ ++ asm volatile("lidt %0"::"m" (*dtr)); ++} ++ ++static inline void native_store_gdt(struct Xgt_desc_struct *dtr) ++{ ++ asm ("sgdt %0":"=m" (*dtr)); ++} ++ ++static inline void native_store_idt(struct Xgt_desc_struct *dtr) ++{ ++ asm ("sidt %0":"=m" (*dtr)); ++} ++ ++static inline unsigned long native_store_tr(void) ++{ ++ unsigned long tr; ++ asm ("str %0":"=r" (tr)); ++ return tr; ++} ++ ++static inline void native_load_tls(struct thread_struct *t, unsigned int cpu) ++{ ++ unsigned int i; ++ struct desc_struct *gdt = get_cpu_gdt_table(cpu); ++ ++ for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) ++ gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; ++} ++#else ++#define load_TLS(t, cpu) xen_load_tls(t, cpu) ++#define set_ldt xen_set_ldt ++ ++extern int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 entry_b); ++extern int write_gdt_entry(void *gdt, int entry, __u32 entry_a, __u32 entry_b); ++ ++static inline void xen_load_tls(struct thread_struct *t, unsigned int cpu) ++{ ++ unsigned int i; ++ struct desc_struct *gdt = get_cpu_gdt_table(cpu) + GDT_ENTRY_TLS_MIN; ++ ++ for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) ++ if (HYPERVISOR_update_descriptor(virt_to_machine(&gdt[i]), ++ *(u64 *)&t->tls_array[i])) ++ BUG(); ++} + #endif + + #ifndef CONFIG_X86_NO_IDT +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/fixmap_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/fixmap_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -19,10 +19,8 @@ + * the start of the fixmap. + */ + extern unsigned long __FIXADDR_TOP; +-#ifdef CONFIG_COMPAT_VDSO +-#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO) +-#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1) +-#endif ++#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO) ++#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1) + + #ifndef __ASSEMBLY__ + #include +@@ -85,6 +83,9 @@ enum fixed_addresses { + #ifdef CONFIG_PCI_MMCONFIG + FIX_PCIE_MCFG, + #endif ++#ifdef CONFIG_PARAVIRT ++ FIX_PARAVIRT_BOOTMAP, ++#endif + FIX_SHARED_INFO, + #define NR_FIX_ISAMAPS 256 + FIX_ISAMAP_END, +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/highmem.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/highmem.h 2008-12-15 11:27:22.000000000 +0100 +@@ -67,12 +67,18 @@ extern void FASTCALL(kunmap_high(struct + + void *kmap(struct page *page); + void kunmap(struct page *page); ++void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot); + void *kmap_atomic(struct page *page, enum km_type type); + void *kmap_atomic_pte(struct page *page, enum km_type type); + void kunmap_atomic(void *kvaddr, enum km_type type); + void *kmap_atomic_pfn(unsigned long pfn, enum km_type type); + struct page *kmap_atomic_to_page(void *ptr); + ++#define kmap_atomic_pte(page, type) \ ++ kmap_atomic_prot(page, type, \ ++ test_bit(PG_pinned, &(page)->flags) \ ++ ? PAGE_KERNEL_RO : kmap_prot) ++ + #define flush_cache_kmaps() do { } while (0) + + void clear_highpage(struct page *); +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/irqflags_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/irqflags_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -11,6 +11,40 @@ + #define _ASM_IRQFLAGS_H + + #ifndef __ASSEMBLY__ ++#define xen_save_fl(void) (current_vcpu_info()->evtchn_upcall_mask) ++ ++#define xen_restore_fl(f) \ ++do { \ ++ vcpu_info_t *_vcpu; \ ++ barrier(); \ ++ _vcpu = current_vcpu_info(); \ ++ if ((_vcpu->evtchn_upcall_mask = (f)) == 0) { \ ++ barrier(); /* unmask then check (avoid races) */\ ++ if (unlikely(_vcpu->evtchn_upcall_pending)) \ ++ force_evtchn_callback(); \ ++ } \ ++} while (0) ++ ++#define xen_irq_disable() \ ++do { \ ++ current_vcpu_info()->evtchn_upcall_mask = 1; \ ++ barrier(); \ ++} while (0) ++ ++#define xen_irq_enable() \ ++do { \ ++ vcpu_info_t *_vcpu; \ ++ barrier(); \ ++ _vcpu = current_vcpu_info(); \ ++ _vcpu->evtchn_upcall_mask = 0; \ ++ barrier(); /* unmask then check (avoid races) */ \ ++ if (unlikely(_vcpu->evtchn_upcall_pending)) \ ++ force_evtchn_callback(); \ ++} while (0) ++ ++void xen_safe_halt(void); ++ ++void xen_halt(void); + + /* + * The use of 'barrier' in the following reflects their use as local-lock +@@ -20,48 +54,31 @@ + * includes these barriers, for example. + */ + +-#define __raw_local_save_flags() (current_vcpu_info()->evtchn_upcall_mask) ++#define __raw_local_save_flags() xen_save_fl() + +-#define raw_local_irq_restore(x) \ +-do { \ +- vcpu_info_t *_vcpu; \ +- barrier(); \ +- _vcpu = current_vcpu_info(); \ +- if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \ +- barrier(); /* unmask then check (avoid races) */ \ +- if (unlikely(_vcpu->evtchn_upcall_pending)) \ +- force_evtchn_callback(); \ +- } \ +-} while (0) ++#define raw_local_irq_restore(flags) xen_restore_fl(flags) + +-#define raw_local_irq_disable() \ +-do { \ +- current_vcpu_info()->evtchn_upcall_mask = 1; \ +- barrier(); \ +-} while (0) ++#define raw_local_irq_disable() xen_irq_disable() + +-#define raw_local_irq_enable() \ +-do { \ +- vcpu_info_t *_vcpu; \ +- barrier(); \ +- _vcpu = current_vcpu_info(); \ +- _vcpu->evtchn_upcall_mask = 0; \ +- barrier(); /* unmask then check (avoid races) */ \ +- if (unlikely(_vcpu->evtchn_upcall_pending)) \ +- force_evtchn_callback(); \ +-} while (0) ++#define raw_local_irq_enable() xen_irq_enable() + + /* + * Used in the idle loop; sti takes one instruction cycle + * to complete: + */ +-void raw_safe_halt(void); ++static inline void raw_safe_halt(void) ++{ ++ xen_safe_halt(); ++} + + /* + * Used when interrupts are already enabled or to + * shutdown the processor: + */ +-void halt(void); ++static inline void halt(void) ++{ ++ xen_halt(); ++} + + /* + * For spinlocks, etc: +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/mmu_context_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/mmu_context_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -6,6 +6,20 @@ + #include + #include + ++void arch_exit_mmap(struct mm_struct *mm); ++void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm); ++ ++void mm_pin(struct mm_struct *mm); ++void mm_unpin(struct mm_struct *mm); ++void mm_pin_all(void); ++ ++static inline void xen_activate_mm(struct mm_struct *prev, ++ struct mm_struct *next) ++{ ++ if (!test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)) ++ mm_pin(next); ++} ++ + /* + * Used for LDT copy/destruction. + */ +@@ -37,10 +51,6 @@ static inline void __prepare_arch_switch + : : "r" (0) ); + } + +-extern void mm_pin(struct mm_struct *mm); +-extern void mm_unpin(struct mm_struct *mm); +-void mm_pin_all(void); +- + static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) +@@ -97,11 +107,10 @@ static inline void switch_mm(struct mm_s + #define deactivate_mm(tsk, mm) \ + asm("movl %0,%%gs": :"r" (0)); + +-static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) +-{ +- if (!test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)) +- mm_pin(next); +- switch_mm(prev, next, NULL); +-} ++#define activate_mm(prev, next) \ ++ do { \ ++ xen_activate_mm(prev, next); \ ++ switch_mm((prev),(next),NULL); \ ++ } while(0) + + #endif +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/pgalloc_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/pgalloc_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -1,7 +1,6 @@ + #ifndef _I386_PGALLOC_H + #define _I386_PGALLOC_H + +-#include + #include + #include /* for struct page */ + #include /* for phys_to_virt and page_to_pseudophys */ +@@ -69,6 +68,4 @@ do { \ + #define pud_populate(mm, pmd, pte) BUG() + #endif + +-#define check_pgt_cache() do { } while (0) +- + #endif /* _I386_PGALLOC_H */ +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/pgtable-3level.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/pgtable-3level.h 2008-12-15 11:27:22.000000000 +0100 +@@ -52,32 +52,40 @@ static inline int pte_exec_kernel(pte_t + * value and then use set_pte to update it. -ben + */ + +-static inline void set_pte(pte_t *ptep, pte_t pte) ++static inline void xen_set_pte(pte_t *ptep, pte_t pte) + { + ptep->pte_high = pte.pte_high; + smp_wmb(); + ptep->pte_low = pte.pte_low; + } +-#define set_pte_atomic(pteptr,pteval) \ +- set_64bit((unsigned long long *)(pteptr),__pte_val(pteval)) + +-#define set_pte_at(_mm,addr,ptep,pteval) do { \ +- if (((_mm) != current->mm && (_mm) != &init_mm) || \ +- HYPERVISOR_update_va_mapping((addr), (pteval), 0)) \ +- set_pte((ptep), (pteval)); \ +-} while (0) +- +-#define set_pmd(pmdptr,pmdval) \ +- xen_l2_entry_update((pmdptr), (pmdval)) +-#define set_pud(pudptr,pudval) \ +- xen_l3_entry_update((pudptr), (pudval)) ++static inline void xen_set_pte_at(struct mm_struct *mm, unsigned long addr, ++ pte_t *ptep , pte_t pte) ++{ ++ if ((mm != current->mm && mm != &init_mm) || ++ HYPERVISOR_update_va_mapping(addr, pte, 0)) ++ xen_set_pte(ptep, pte); ++} ++ ++static inline void xen_set_pte_atomic(pte_t *ptep, pte_t pte) ++{ ++ set_64bit((unsigned long long *)(ptep),__pte_val(pte)); ++} ++static inline void xen_set_pmd(pmd_t *pmdp, pmd_t pmd) ++{ ++ xen_l2_entry_update(pmdp, pmd); ++} ++static inline void xen_set_pud(pud_t *pudp, pud_t pud) ++{ ++ xen_l3_entry_update(pudp, pud); ++} + + /* + * For PTEs and PDEs, we must clear the P-bit first when clearing a page table + * entry, so clear the bottom half first and enforce ordering with a compiler + * barrier. + */ +-static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ++static inline void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + if ((mm != current->mm && mm != &init_mm) + || HYPERVISOR_update_va_mapping(addr, __pte(0), 0)) { +@@ -87,7 +95,18 @@ static inline void pte_clear(struct mm_s + } + } + +-#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) ++static inline void xen_pmd_clear(pmd_t *pmd) ++{ ++ xen_l2_entry_update(pmd, __pmd(0)); ++} ++ ++#define set_pte(ptep, pte) xen_set_pte(ptep, pte) ++#define set_pte_at(mm, addr, ptep, pte) xen_set_pte_at(mm, addr, ptep, pte) ++#define set_pte_atomic(ptep, pte) xen_set_pte_atomic(ptep, pte) ++#define set_pmd(pmdp, pmd) xen_set_pmd(pmdp, pmd) ++#define set_pud(pudp, pud) xen_set_pud(pudp, pud) ++#define pte_clear(mm, addr, ptep) xen_pte_clear(mm, addr, ptep) ++#define pmd_clear(pmd) xen_pmd_clear(pmd) + + /* + * Pentium-II erratum A13: in PAE mode we explicitly have to flush +@@ -108,7 +127,8 @@ static inline void pud_clear (pud_t * pu + #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \ + pmd_index(address)) + +-static inline pte_t raw_ptep_get_and_clear(pte_t *ptep, pte_t res) ++#ifdef CONFIG_SMP ++static inline pte_t xen_ptep_get_and_clear(pte_t *ptep, pte_t res) + { + uint64_t val = __pte_val(res); + if (__cmpxchg64(ptep, val, 0) != val) { +@@ -119,6 +139,9 @@ static inline pte_t raw_ptep_get_and_cle + } + return res; + } ++#else ++#define xen_ptep_get_and_clear(xp, pte) xen_local_ptep_get_and_clear(xp, pte) ++#endif + + #define __HAVE_ARCH_PTEP_CLEAR_FLUSH + #define ptep_clear_flush(vma, addr, ptep) \ +@@ -165,13 +188,13 @@ extern unsigned long long __supported_pt + static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) + { + return __pte((((unsigned long long)page_nr << PAGE_SHIFT) | +- pgprot_val(pgprot)) & __supported_pte_mask); ++ pgprot_val(pgprot)) & __supported_pte_mask); + } + + static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) + { + return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | +- pgprot_val(pgprot)) & __supported_pte_mask); ++ pgprot_val(pgprot)) & __supported_pte_mask); + } + + /* +@@ -191,6 +214,4 @@ static inline pmd_t pfn_pmd(unsigned lon + + #define __pmd_free_tlb(tlb, x) do { } while (0) + +-void vmalloc_sync_all(void); +- + #endif /* _I386_PGTABLE_3LEVEL_H */ +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/pgtable-3level-defs.h 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/pgtable-3level-defs.h 2008-12-15 11:27:22.000000000 +0100 +@@ -1,7 +1,7 @@ + #ifndef _I386_PGTABLE_3LEVEL_DEFS_H + #define _I386_PGTABLE_3LEVEL_DEFS_H + +-#define HAVE_SHARED_KERNEL_PMD 0 ++#define SHARED_KERNEL_PMD 0 + + /* + * PGDIR_SHIFT determines what a top-level page table entry can map +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -24,11 +24,11 @@ + #include + #include + #include ++#include + + /* Is this pagetable pinned? */ + #define PG_pinned PG_arch_1 + +-struct mm_struct; + struct vm_area_struct; + + /* +@@ -38,17 +38,16 @@ struct vm_area_struct; + #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + extern unsigned long empty_zero_page[1024]; + extern pgd_t *swapper_pg_dir; +-extern struct kmem_cache *pgd_cache; + extern struct kmem_cache *pmd_cache; + extern spinlock_t pgd_lock; + extern struct page *pgd_list; ++void check_pgt_cache(void); + + void pmd_ctor(void *, struct kmem_cache *, unsigned long); +-void pgd_ctor(void *, struct kmem_cache *, unsigned long); +-void pgd_dtor(void *, struct kmem_cache *, unsigned long); + void pgtable_cache_init(void); + void paging_init(void); + ++ + /* + * The Linux x86 paging architecture is 'compile-time dual-mode', it + * implements both the traditional 2-level x86 page tables and the +@@ -165,6 +164,7 @@ void paging_init(void); + + extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC; + #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) ++#define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) + #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD) + #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) + #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) +@@ -172,6 +172,7 @@ extern unsigned long long __PAGE_KERNEL, + #define PAGE_KERNEL __pgprot(__PAGE_KERNEL) + #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO) + #define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC) ++#define PAGE_KERNEL_RX __pgprot(__PAGE_KERNEL_RX) + #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE) + #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) + #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC) +@@ -275,7 +276,13 @@ static inline pte_t pte_mkhuge(pte_t pte + */ + #define pte_update(mm, addr, ptep) do { } while (0) + #define pte_update_defer(mm, addr, ptep) do { } while (0) +-#define paravirt_map_pt_hook(slot, va, pfn) do { } while (0) ++ ++/* local pte updates need not use xchg for locking */ ++static inline pte_t xen_local_ptep_get_and_clear(pte_t *ptep, pte_t res) ++{ ++ xen_set_pte(ptep, __pte(0)); ++ return res; ++} + + /* + * We only update the dirty/accessed state if we set +@@ -286,17 +293,34 @@ static inline pte_t pte_mkhuge(pte_t pte + */ + #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS + #define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ +-do { \ +- if (dirty) \ ++({ \ ++ int __changed = !pte_same(*(ptep), entry); \ ++ if (__changed && (dirty)) \ + ptep_establish(vma, address, ptep, entry); \ +-} while (0) ++ __changed; \ ++}) + +-/* +- * We don't actually have these, but we want to advertise them so that +- * we can encompass the flush here. +- */ + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY ++#define ptep_test_and_clear_dirty(vma, addr, ptep) ({ \ ++ int __ret = 0; \ ++ if (pte_dirty(*(ptep))) \ ++ __ret = test_and_clear_bit(_PAGE_BIT_DIRTY, \ ++ &(ptep)->pte_low); \ ++ if (__ret) \ ++ pte_update((vma)->vm_mm, addr, ptep); \ ++ __ret; \ ++}) ++ + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++#define ptep_test_and_clear_young(vma, addr, ptep) ({ \ ++ int __ret = 0; \ ++ if (pte_young(*(ptep))) \ ++ __ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, \ ++ &(ptep)->pte_low); \ ++ if (__ret) \ ++ pte_update((vma)->vm_mm, addr, ptep); \ ++ __ret; \ ++}) + + /* + * Rules for using ptep_establish: the pte MUST be a user pte, and +@@ -323,7 +347,7 @@ do { \ + int __dirty = pte_dirty(__pte); \ + __pte = pte_mkclean(__pte); \ + if (test_bit(PG_pinned, &virt_to_page((vma)->vm_mm->pgd)->flags)) \ +- ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ ++ (void)ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ + else if (__dirty) \ + (ptep)->pte_low = __pte.pte_low; \ + __dirty; \ +@@ -336,7 +360,7 @@ do { \ + int __young = pte_young(__pte); \ + __pte = pte_mkold(__pte); \ + if (test_bit(PG_pinned, &virt_to_page((vma)->vm_mm->pgd)->flags)) \ +- ptep_set_access_flags(vma, address, ptep, __pte, __young); \ ++ (void)ptep_set_access_flags(vma, address, ptep, __pte, __young); \ + else if (__young) \ + (ptep)->pte_low = __pte.pte_low; \ + __young; \ +@@ -349,7 +373,7 @@ static inline pte_t ptep_get_and_clear(s + if (!pte_none(pte) + && (mm != &init_mm + || HYPERVISOR_update_va_mapping(addr, __pte(0), 0))) { +- pte = raw_ptep_get_and_clear(ptep, pte); ++ pte = xen_ptep_get_and_clear(ptep, pte); + pte_update(mm, addr, ptep); + } + return pte; +@@ -491,24 +515,10 @@ extern pte_t *lookup_address(unsigned lo + #endif + + #if defined(CONFIG_HIGHPTE) +-#define pte_offset_map(dir, address) \ +-({ \ +- pte_t *__ptep; \ +- unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \ +- __ptep = (pte_t *)kmap_atomic_pte(pfn_to_page(pfn),KM_PTE0); \ +- paravirt_map_pt_hook(KM_PTE0,__ptep, pfn); \ +- __ptep = __ptep + pte_index(address); \ +- __ptep; \ +-}) +-#define pte_offset_map_nested(dir, address) \ +-({ \ +- pte_t *__ptep; \ +- unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \ +- __ptep = (pte_t *)kmap_atomic_pte(pfn_to_page(pfn),KM_PTE1); \ +- paravirt_map_pt_hook(KM_PTE1,__ptep, pfn); \ +- __ptep = __ptep + pte_index(address); \ +- __ptep; \ +-}) ++#define pte_offset_map(dir, address) \ ++ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address)) ++#define pte_offset_map_nested(dir, address) \ ++ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address)) + #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) + #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) + #else +@@ -597,10 +607,6 @@ int xen_change_pte_range(struct mm_struc + #define io_remap_pfn_range(vma,from,pfn,size,prot) \ + direct_remap_pfn_range(vma,from,pfn,size,prot,DOMID_IO) + +-#define MK_IOSPACE_PFN(space, pfn) (pfn) +-#define GET_IOSPACE(pfn) 0 +-#define GET_PFN(pfn) (pfn) +- + #include + + #endif /* _I386_PGTABLE_H */ +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/processor_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/processor_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + /* flag for disabling the tsc */ +@@ -118,7 +119,8 @@ extern char ignore_fpu_irq; + + void __init cpu_detect(struct cpuinfo_x86 *c); + +-extern void identify_cpu(struct cpuinfo_x86 *); ++extern void identify_boot_cpu(void); ++extern void identify_secondary_cpu(struct cpuinfo_x86 *); + extern void print_cpu_info(struct cpuinfo_x86 *); + extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); + extern unsigned short num_cache_leaves; +@@ -129,29 +131,8 @@ extern void detect_ht(struct cpuinfo_x86 + static inline void detect_ht(struct cpuinfo_x86 *c) {} + #endif + +-/* +- * EFLAGS bits +- */ +-#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ +-#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */ +-#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */ +-#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ +-#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */ +-#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */ +-#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */ +-#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */ +-#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */ +-#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */ +-#define X86_EFLAGS_NT 0x00004000 /* Nested Task */ +-#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */ +-#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */ +-#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */ +-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */ +-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ +-#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ +- +-static inline fastcall void xen_cpuid(unsigned int *eax, unsigned int *ebx, +- unsigned int *ecx, unsigned int *edx) ++static inline void xen_cpuid(unsigned int *eax, unsigned int *ebx, ++ unsigned int *ecx, unsigned int *edx) + { + /* ecx is often an input as well as an output. */ + __asm__(XEN_CPUID +@@ -165,21 +146,6 @@ static inline fastcall void xen_cpuid(un + #define load_cr3(pgdir) write_cr3(__pa(pgdir)) + + /* +- * Intel CPU features in CR4 +- */ +-#define X86_CR4_VME 0x0001 /* enable vm86 extensions */ +-#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */ +-#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */ +-#define X86_CR4_DE 0x0008 /* enable debugging extensions */ +-#define X86_CR4_PSE 0x0010 /* enable page size extensions */ +-#define X86_CR4_PAE 0x0020 /* enable physical address extensions */ +-#define X86_CR4_MCE 0x0040 /* Machine check enable */ +-#define X86_CR4_PGE 0x0080 /* enable global pages */ +-#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */ +-#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ +-#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ +- +-/* + * Save the cr4 feature set we're using (ie + * Pentium 4MB enable and PPro Global page + * enable), so that any CPU's that boot up +@@ -206,26 +172,6 @@ static inline void clear_in_cr4 (unsigne + } + + /* +- * NSC/Cyrix CPU configuration register indexes +- */ +- +-#define CX86_PCR0 0x20 +-#define CX86_GCR 0xb8 +-#define CX86_CCR0 0xc0 +-#define CX86_CCR1 0xc1 +-#define CX86_CCR2 0xc2 +-#define CX86_CCR3 0xc3 +-#define CX86_CCR4 0xe8 +-#define CX86_CCR5 0xe9 +-#define CX86_CCR6 0xea +-#define CX86_CCR7 0xeb +-#define CX86_PCR1 0xf0 +-#define CX86_DIR0 0xfe +-#define CX86_DIR1 0xff +-#define CX86_ARR_BASE 0xc4 +-#define CX86_RCR_BASE 0xdc +- +-/* + * NSC/Cyrix CPU indexed register access macros + */ + +@@ -351,7 +297,8 @@ typedef struct { + struct thread_struct; + + #ifndef CONFIG_X86_NO_TSS +-struct tss_struct { ++/* This is the TSS defined by the hardware. */ ++struct i386_hw_tss { + unsigned short back_link,__blh; + unsigned long esp0; + unsigned short ss0,__ss0h; +@@ -375,6 +322,11 @@ struct tss_struct { + unsigned short gs, __gsh; + unsigned short ldt, __ldth; + unsigned short trace, io_bitmap_base; ++} __attribute__((packed)); ++ ++struct tss_struct { ++ struct i386_hw_tss x86_tss; ++ + /* + * The extra 1 is there because the CPU will access an + * additional byte beyond the end of the IO permission +@@ -428,10 +380,11 @@ struct thread_struct { + }; + + #define INIT_THREAD { \ ++ .esp0 = sizeof(init_stack) + (long)&init_stack, \ + .vm86_info = NULL, \ + .sysenter_cs = __KERNEL_CS, \ + .io_bitmap_ptr = NULL, \ +- .fs = __KERNEL_PDA, \ ++ .fs = __KERNEL_PERCPU, \ + } + + /* +@@ -441,10 +394,12 @@ struct thread_struct { + * be within the limit. + */ + #define INIT_TSS { \ +- .esp0 = sizeof(init_stack) + (long)&init_stack, \ +- .ss0 = __KERNEL_DS, \ +- .ss1 = __KERNEL_CS, \ +- .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \ ++ .x86_tss = { \ ++ .esp0 = sizeof(init_stack) + (long)&init_stack, \ ++ .ss0 = __KERNEL_DS, \ ++ .ss1 = __KERNEL_CS, \ ++ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \ ++ }, \ + .io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \ + } + +@@ -551,38 +506,33 @@ static inline void rep_nop(void) + + #define cpu_relax() rep_nop() + +-#define paravirt_enabled() 0 +-#define __cpuid xen_cpuid +- + #ifndef CONFIG_X86_NO_TSS +-static inline void __load_esp0(struct tss_struct *tss, struct thread_struct *thread) ++static inline void native_load_esp0(struct tss_struct *tss, struct thread_struct *thread) + { +- tss->esp0 = thread->esp0; ++ tss->x86_tss.esp0 = thread->esp0; + /* This can only happen when SEP is enabled, no need to test "SEP"arately */ +- if (unlikely(tss->ss1 != thread->sysenter_cs)) { +- tss->ss1 = thread->sysenter_cs; ++ if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) { ++ tss->x86_tss.ss1 = thread->sysenter_cs; + wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0); + } + } +-#define load_esp0(tss, thread) \ +- __load_esp0(tss, thread) + #else +-#define load_esp0(tss, thread) do { \ ++#define xen_load_esp0(tss, thread) do { \ + if (HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0)) \ + BUG(); \ + } while (0) + #endif + + +-/* +- * These special macros can be used to get or set a debugging register +- */ +-#define get_debugreg(var, register) \ +- (var) = HYPERVISOR_get_debugreg(register) +-#define set_debugreg(value, register) \ +- WARN_ON(HYPERVISOR_set_debugreg(register, value)) ++static inline unsigned long xen_get_debugreg(int regno) ++{ ++ return HYPERVISOR_get_debugreg(regno); ++} + +-#define set_iopl_mask xen_set_iopl_mask ++static inline void xen_set_debugreg(int regno, unsigned long value) ++{ ++ WARN_ON(HYPERVISOR_set_debugreg(regno, value)); ++} + + /* + * Set IOPL bits in EFLAGS from given mask +@@ -597,6 +547,21 @@ static inline void xen_set_iopl_mask(uns + } + + ++#define paravirt_enabled() 0 ++#define __cpuid xen_cpuid ++ ++#define load_esp0 xen_load_esp0 ++ ++/* ++ * These special macros can be used to get or set a debugging register ++ */ ++#define get_debugreg(var, register) \ ++ (var) = xen_get_debugreg(register) ++#define set_debugreg(value, register) \ ++ xen_set_debugreg(register, value) ++ ++#define set_iopl_mask xen_set_iopl_mask ++ + /* + * Generic CPUID function + * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx +@@ -749,8 +714,14 @@ extern unsigned long boot_option_idle_ov + extern void enable_sep_cpu(void); + extern int sysenter_setup(void); + +-extern int init_gdt(int cpu, struct task_struct *idle); ++/* Defined in head.S */ ++extern struct Xgt_desc_struct early_gdt_descr; ++ + extern void cpu_set_gdt(int); +-extern void secondary_cpu_init(void); ++extern void switch_to_new_gdt(void); ++extern void cpu_init(void); ++extern void init_gdt(int cpu); ++ ++extern int force_mwait; + + #endif /* __ASM_I386_PROCESSOR_H */ +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/segment_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/segment_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -39,7 +39,7 @@ + * 25 - APM BIOS support + * + * 26 - ESPFIX small SS +- * 27 - PDA [ per-cpu private data area ] ++ * 27 - per-cpu [ offset to per-cpu data area ] + * 28 - unused + * 29 - unused + * 30 - unused +@@ -74,8 +74,12 @@ + #define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14) + #define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8) + +-#define GDT_ENTRY_PDA (GDT_ENTRY_KERNEL_BASE + 15) +-#define __KERNEL_PDA (GDT_ENTRY_PDA * 8) ++#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15) ++#ifdef CONFIG_SMP ++#define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8) ++#else ++#define __KERNEL_PERCPU 0 ++#endif + + #define GDT_ENTRY_DOUBLEFAULT_TSS 31 + +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/smp_32.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/smp_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -8,19 +8,15 @@ + #include + #include + #include +-#include + #endif + +-#ifdef CONFIG_X86_LOCAL_APIC +-#ifndef __ASSEMBLY__ +-#include ++#if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__) + #include + #include ++#include + #ifdef CONFIG_X86_IO_APIC + #include + #endif +-#include +-#endif + #endif + + #define BAD_APICID 0xFFu +@@ -52,9 +48,76 @@ extern void cpu_exit_clear(void); + extern void cpu_uninit(void); + #endif + +-#ifndef CONFIG_PARAVIRT ++#ifndef CONFIG_XEN ++struct smp_ops ++{ ++ void (*smp_prepare_boot_cpu)(void); ++ void (*smp_prepare_cpus)(unsigned max_cpus); ++ int (*cpu_up)(unsigned cpu); ++ void (*smp_cpus_done)(unsigned max_cpus); ++ ++ void (*smp_send_stop)(void); ++ void (*smp_send_reschedule)(int cpu); ++ int (*smp_call_function_mask)(cpumask_t mask, ++ void (*func)(void *info), void *info, ++ int wait); ++}; ++ ++extern struct smp_ops smp_ops; ++ ++static inline void smp_prepare_boot_cpu(void) ++{ ++ smp_ops.smp_prepare_boot_cpu(); ++} ++static inline void smp_prepare_cpus(unsigned int max_cpus) ++{ ++ smp_ops.smp_prepare_cpus(max_cpus); ++} ++static inline int __cpu_up(unsigned int cpu) ++{ ++ return smp_ops.cpu_up(cpu); ++} ++static inline void smp_cpus_done(unsigned int max_cpus) ++{ ++ smp_ops.smp_cpus_done(max_cpus); ++} ++ ++static inline void smp_send_stop(void) ++{ ++ smp_ops.smp_send_stop(); ++} ++static inline void smp_send_reschedule(int cpu) ++{ ++ smp_ops.smp_send_reschedule(cpu); ++} ++static inline int smp_call_function_mask(cpumask_t mask, ++ void (*func) (void *info), void *info, ++ int wait) ++{ ++ return smp_ops.smp_call_function_mask(mask, func, info, wait); ++} ++ ++void native_smp_prepare_boot_cpu(void); ++void native_smp_prepare_cpus(unsigned int max_cpus); ++int native_cpu_up(unsigned int cpunum); ++void native_smp_cpus_done(unsigned int max_cpus); ++ + #define startup_ipi_hook(phys_apicid, start_eip, start_esp) \ + do { } while (0) ++ ++#else ++ ++ ++void xen_smp_send_stop(void); ++void xen_smp_send_reschedule(int cpu); ++int xen_smp_call_function_mask(cpumask_t mask, ++ void (*func) (void *info), void *info, ++ int wait); ++ ++#define smp_send_stop xen_smp_send_stop ++#define smp_send_reschedule xen_smp_send_reschedule ++#define smp_call_function_mask xen_smp_call_function_mask ++ + #endif + + /* +@@ -62,7 +125,8 @@ do { } while (0) + * from the initial startup. We map APIC_BASE very early in page_setup(), + * so this is correct in the x86 case. + */ +-#define raw_smp_processor_id() (read_pda(cpu_number)) ++DECLARE_PER_CPU(int, cpu_number); ++#define raw_smp_processor_id() (x86_read_percpu(cpu_number)) + + extern cpumask_t cpu_possible_map; + #define cpu_callin_map cpu_possible_map +@@ -73,20 +137,6 @@ static inline int num_booting_cpus(void) + return cpus_weight(cpu_possible_map); + } + +-#ifdef CONFIG_X86_LOCAL_APIC +- +-#ifdef APIC_DEFINITION +-extern int hard_smp_processor_id(void); +-#else +-#include +-static inline int hard_smp_processor_id(void) +-{ +- /* we don't want to mark this access volatile - bad code generation */ +- return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)); +-} +-#endif +-#endif +- + #define safe_smp_processor_id() smp_processor_id() + extern int __cpu_disable(void); + extern void __cpu_die(unsigned int cpu); +@@ -102,10 +152,31 @@ extern unsigned int num_processors; + + #define NO_PROC_ID 0xFF /* No processor magic marker */ + +-#endif ++#endif /* CONFIG_SMP */ + + #ifndef __ASSEMBLY__ + ++#ifdef CONFIG_X86_LOCAL_APIC ++ ++#ifdef APIC_DEFINITION ++extern int hard_smp_processor_id(void); ++#else ++#include ++static inline int hard_smp_processor_id(void) ++{ ++ /* we don't want to mark this access volatile - bad code generation */ ++ return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)); ++} ++#endif /* APIC_DEFINITION */ ++ ++#else /* CONFIG_X86_LOCAL_APIC */ ++ ++#ifndef CONFIG_SMP ++#define hard_smp_processor_id() 0 ++#endif ++ ++#endif /* CONFIG_X86_LOCAL_APIC */ ++ + extern u8 apicid_2_node[]; + + #ifdef CONFIG_X86_LOCAL_APIC +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/system_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/system_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -4,7 +4,7 @@ + #include + #include + #include +-#include /* for LOCK_PREFIX */ ++#include + #include + #include + +@@ -90,308 +90,102 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" + #define savesegment(seg, value) \ + asm volatile("mov %%" #seg ",%0":"=rm" (value)) + +-#define read_cr0() ({ \ +- unsigned int __dummy; \ +- __asm__ __volatile__( \ +- "movl %%cr0,%0\n\t" \ +- :"=r" (__dummy)); \ +- __dummy; \ +-}) +-#define write_cr0(x) \ +- __asm__ __volatile__("movl %0,%%cr0": :"r" (x)) +- +-#define read_cr2() (current_vcpu_info()->arch.cr2) +-#define write_cr2(x) \ +- __asm__ __volatile__("movl %0,%%cr2": :"r" (x)) +- +-#define read_cr3() ({ \ +- unsigned int __dummy; \ +- __asm__ ( \ +- "movl %%cr3,%0\n\t" \ +- :"=r" (__dummy)); \ +- __dummy = xen_cr3_to_pfn(__dummy); \ +- mfn_to_pfn(__dummy) << PAGE_SHIFT; \ +-}) +-#define write_cr3(x) ({ \ +- unsigned int __dummy = pfn_to_mfn((x) >> PAGE_SHIFT); \ +- __dummy = xen_pfn_to_cr3(__dummy); \ +- __asm__ __volatile__("movl %0,%%cr3": :"r" (__dummy)); \ +-}) +-#define read_cr4() ({ \ +- unsigned int __dummy; \ +- __asm__( \ +- "movl %%cr4,%0\n\t" \ +- :"=r" (__dummy)); \ +- __dummy; \ +-}) +-#define read_cr4_safe() ({ \ +- unsigned int __dummy; \ +- /* This could fault if %cr4 does not exist */ \ +- __asm__("1: movl %%cr4, %0 \n" \ +- "2: \n" \ +- ".section __ex_table,\"a\" \n" \ +- ".long 1b,2b \n" \ +- ".previous \n" \ +- : "=r" (__dummy): "0" (0)); \ +- __dummy; \ +-}) +- +-#define write_cr4(x) \ +- __asm__ __volatile__("movl %0,%%cr4": :"r" (x)) +- +-#define wbinvd() \ +- __asm__ __volatile__ ("wbinvd": : :"memory") +- +-/* Clear the 'TS' bit */ +-#define clts() (HYPERVISOR_fpu_taskswitch(0)) +- +-/* Set the 'TS' bit */ +-#define stts() (HYPERVISOR_fpu_taskswitch(1)) +- +-#endif /* __KERNEL__ */ +- +-static inline unsigned long get_limit(unsigned long segment) ++static inline void xen_clts(void) + { +- unsigned long __limit; +- __asm__("lsll %1,%0" +- :"=r" (__limit):"r" (segment)); +- return __limit+1; ++ HYPERVISOR_fpu_taskswitch(0); + } + +-#define nop() __asm__ __volatile__ ("nop") +- +-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr)))) +- +-#define tas(ptr) (xchg((ptr),1)) +- +-struct __xchg_dummy { unsigned long a[100]; }; +-#define __xg(x) ((struct __xchg_dummy *)(x)) ++static inline unsigned long xen_read_cr0(void) ++{ ++ unsigned long val; ++ asm volatile("movl %%cr0,%0\n\t" :"=r" (val)); ++ return val; ++} + ++static inline void xen_write_cr0(unsigned long val) ++{ ++ asm volatile("movl %0,%%cr0": :"r" (val)); ++} + +-#ifdef CONFIG_X86_CMPXCHG64 ++#define xen_read_cr2() (current_vcpu_info()->arch.cr2) + +-/* +- * The semantics of XCHGCMP8B are a bit strange, this is why +- * there is a loop and the loading of %%eax and %%edx has to +- * be inside. This inlines well in most cases, the cached +- * cost is around ~38 cycles. (in the future we might want +- * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that +- * might have an implicit FPU-save as a cost, so it's not +- * clear which path to go.) +- * +- * cmpxchg8b must be used with the lock prefix here to allow +- * the instruction to be executed atomically, see page 3-102 +- * of the instruction set reference 24319102.pdf. We need +- * the reader side to see the coherent 64bit value. +- */ +-static inline void __set_64bit (unsigned long long * ptr, +- unsigned int low, unsigned int high) ++static inline void xen_write_cr2(unsigned long val) + { +- __asm__ __volatile__ ( +- "\n1:\t" +- "movl (%0), %%eax\n\t" +- "movl 4(%0), %%edx\n\t" +- "lock cmpxchg8b (%0)\n\t" +- "jnz 1b" +- : /* no outputs */ +- : "D"(ptr), +- "b"(low), +- "c"(high) +- : "ax","dx","memory"); ++ asm volatile("movl %0,%%cr2": :"r" (val)); + } + +-static inline void __set_64bit_constant (unsigned long long *ptr, +- unsigned long long value) ++static inline unsigned long xen_read_cr3(void) + { +- __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL)); ++ unsigned long val; ++ asm volatile("movl %%cr3,%0\n\t" :"=r" (val)); ++ return mfn_to_pfn(xen_cr3_to_pfn(val)) << PAGE_SHIFT; + } +-#define ll_low(x) *(((unsigned int*)&(x))+0) +-#define ll_high(x) *(((unsigned int*)&(x))+1) + +-static inline void __set_64bit_var (unsigned long long *ptr, +- unsigned long long value) ++static inline void xen_write_cr3(unsigned long val) + { +- __set_64bit(ptr,ll_low(value), ll_high(value)); ++ val = xen_pfn_to_cr3(pfn_to_mfn(val >> PAGE_SHIFT)); ++ asm volatile("movl %0,%%cr3": :"r" (val)); + } + +-#define set_64bit(ptr,value) \ +-(__builtin_constant_p(value) ? \ +- __set_64bit_constant(ptr, value) : \ +- __set_64bit_var(ptr, value) ) +- +-#define _set_64bit(ptr,value) \ +-(__builtin_constant_p(value) ? \ +- __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \ +- __set_64bit(ptr, ll_low(value), ll_high(value)) ) +- +-#endif +- +-/* +- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway +- * Note 2: xchg has side effect, so that attribute volatile is necessary, +- * but generally the primitive is invalid, *ptr is output argument. --ANK +- */ +-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) ++static inline unsigned long xen_read_cr4(void) + { +- switch (size) { +- case 1: +- __asm__ __volatile__("xchgb %b0,%1" +- :"=q" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- case 2: +- __asm__ __volatile__("xchgw %w0,%1" +- :"=r" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- case 4: +- __asm__ __volatile__("xchgl %0,%1" +- :"=r" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- } +- return x; ++ unsigned long val; ++ asm volatile("movl %%cr4,%0\n\t" :"=r" (val)); ++ return val; + } + +-/* +- * Atomic compare and exchange. Compare OLD with MEM, if identical, +- * store NEW in MEM. Return the initial value in MEM. Success is +- * indicated by comparing RETURN with OLD. +- */ +- +-#ifdef CONFIG_X86_CMPXCHG +-#define __HAVE_ARCH_CMPXCHG 1 +-#define cmpxchg(ptr,o,n)\ +- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ +- (unsigned long)(n),sizeof(*(ptr)))) +-#define sync_cmpxchg(ptr,o,n)\ +- ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\ +- (unsigned long)(n),sizeof(*(ptr)))) +-#endif ++static inline unsigned long xen_read_cr4_safe(void) ++{ ++ unsigned long val; ++ /* This could fault if %cr4 does not exist */ ++ asm("1: movl %%cr4, %0 \n" ++ "2: \n" ++ ".section __ex_table,\"a\" \n" ++ ".long 1b,2b \n" ++ ".previous \n" ++ : "=r" (val): "0" (0)); ++ return val; ++} + +-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, +- unsigned long new, int size) ++static inline void xen_write_cr4(unsigned long val) + { +- unsigned long prev; +- switch (size) { +- case 1: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" +- : "=a"(prev) +- : "q"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 2: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 4: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- } +- return old; ++ asm volatile("movl %0,%%cr4": :"r" (val)); + } + +-/* +- * Always use locked operations when touching memory shared with a +- * hypervisor, since the system may be SMP even if the guest kernel +- * isn't. +- */ +-static inline unsigned long __sync_cmpxchg(volatile void *ptr, +- unsigned long old, +- unsigned long new, int size) +-{ +- unsigned long prev; +- switch (size) { +- case 1: +- __asm__ __volatile__("lock; cmpxchgb %b1,%2" +- : "=a"(prev) +- : "q"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 2: +- __asm__ __volatile__("lock; cmpxchgw %w1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 4: +- __asm__ __volatile__("lock; cmpxchgl %1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- } +- return old; ++static inline void xen_wbinvd(void) ++{ ++ asm volatile("wbinvd": : :"memory"); + } + +-#ifndef CONFIG_X86_CMPXCHG +-/* +- * Building a kernel capable running on 80386. It may be necessary to +- * simulate the cmpxchg on the 80386 CPU. For that purpose we define +- * a function for each of the sizes we support. +- */ ++#define read_cr0() (xen_read_cr0()) ++#define write_cr0(x) (xen_write_cr0(x)) ++#define read_cr2() (xen_read_cr2()) ++#define write_cr2(x) (xen_write_cr2(x)) ++#define read_cr3() (xen_read_cr3()) ++#define write_cr3(x) (xen_write_cr3(x)) ++#define read_cr4() (xen_read_cr4()) ++#define read_cr4_safe() (xen_read_cr4_safe()) ++#define write_cr4(x) (xen_write_cr4(x)) ++#define wbinvd() (xen_wbinvd()) + +-extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8); +-extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16); +-extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32); +- +-static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old, +- unsigned long new, int size) +-{ +- switch (size) { +- case 1: +- return cmpxchg_386_u8(ptr, old, new); +- case 2: +- return cmpxchg_386_u16(ptr, old, new); +- case 4: +- return cmpxchg_386_u32(ptr, old, new); +- } +- return old; +-} +- +-#define cmpxchg(ptr,o,n) \ +-({ \ +- __typeof__(*(ptr)) __ret; \ +- if (likely(boot_cpu_data.x86 > 3)) \ +- __ret = __cmpxchg((ptr), (unsigned long)(o), \ +- (unsigned long)(n), sizeof(*(ptr))); \ +- else \ +- __ret = cmpxchg_386((ptr), (unsigned long)(o), \ +- (unsigned long)(n), sizeof(*(ptr))); \ +- __ret; \ +-}) +-#endif ++/* Clear the 'TS' bit */ ++#define clts() (xen_clts()) + +-#ifdef CONFIG_X86_CMPXCHG64 ++/* Set the 'TS' bit */ ++#define stts() (HYPERVISOR_fpu_taskswitch(1)) + +-static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old, +- unsigned long long new) ++#endif /* __KERNEL__ */ ++ ++static inline unsigned long get_limit(unsigned long segment) + { +- unsigned long long prev; +- __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3" +- : "=A"(prev) +- : "b"((unsigned long)new), +- "c"((unsigned long)(new >> 32)), +- "m"(*__xg(ptr)), +- "0"(old) +- : "memory"); +- return prev; +-} +- +-#define cmpxchg64(ptr,o,n)\ +- ((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\ +- (unsigned long long)(n))) ++ unsigned long __limit; ++ __asm__("lsll %1,%0" ++ :"=r" (__limit):"r" (segment)); ++ return __limit+1; ++} ++ ++#define nop() __asm__ __volatile__ ("nop") + +-#endif +- + /* + * Force strict CPU ordering. + * And yes, this is required on UP too when we're talking +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/tlbflush_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/tlbflush_32.h 2008-12-15 11:27:22.000000000 +0100 +@@ -29,8 +29,13 @@ + * and page-granular flushes are available only on i486 and up. + */ + ++#define TLB_FLUSH_ALL 0xffffffff ++ ++ + #ifndef CONFIG_SMP + ++#include ++ + #define flush_tlb() __flush_tlb() + #define flush_tlb_all() __flush_tlb_all() + #define local_flush_tlb() __flush_tlb() +@@ -55,7 +60,7 @@ static inline void flush_tlb_range(struc + __flush_tlb(); + } + +-#else ++#else /* SMP */ + + #include + +@@ -84,9 +89,7 @@ struct tlb_state + char __cacheline_padding[L1_CACHE_BYTES-8]; + }; + DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate); +- +- +-#endif ++#endif /* SMP */ + + #define flush_tlb_kernel_range(start, end) flush_tlb_all() + +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/desc_64.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/desc_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -127,16 +127,6 @@ static inline void set_ldt_desc(unsigned + DESC_LDT, size * 8 - 1); + } + +-static inline void set_seg_base(unsigned cpu, int entry, void *base) +-{ +- struct desc_struct *d = &cpu_gdt(cpu)[entry]; +- u32 addr = (u32)(u64)base; +- BUG_ON((u64)base >> 32); +- d->base0 = addr & 0xffff; +- d->base1 = (addr >> 16) & 0xff; +- d->base2 = (addr >> 24) & 0xff; +-} +- + #define LDT_entry_a(info) \ + ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) + /* Don't allow setting of the lm bit. It is useless anyways because +@@ -165,25 +155,15 @@ static inline void set_seg_base(unsigned + (info)->useable == 0 && \ + (info)->lm == 0) + +-#if TLS_SIZE != 24 +-# error update this code. +-#endif +- + static inline void load_TLS(struct thread_struct *t, unsigned int cpu) + { +-#if 0 ++ unsigned int i; + u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN); +- gdt[0] = t->tls_array[0]; +- gdt[1] = t->tls_array[1]; +- gdt[2] = t->tls_array[2]; +-#endif +-#define C(i) \ +- if (HYPERVISOR_update_descriptor(virt_to_machine(&cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]), \ +- t->tls_array[i])) \ +- BUG(); + +- C(0); C(1); C(2); +-#undef C ++ for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) ++ if (HYPERVISOR_update_descriptor(virt_to_machine(&gdt[i]), ++ t->tls_array[i])) ++ BUG(); + } + + /* +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -51,7 +51,7 @@ struct dma_mapping_ops { + }; + + extern dma_addr_t bad_dma_address; +-extern struct dma_mapping_ops* dma_ops; ++extern const struct dma_mapping_ops* dma_ops; + extern int iommu_merge; + + #if 0 +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/fixmap_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/fixmap_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + + /* +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/irqflags_64.h 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/irqflags_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -9,6 +9,7 @@ + */ + #ifndef _ASM_IRQFLAGS_H + #define _ASM_IRQFLAGS_H ++#include + + #ifndef __ASSEMBLY__ + /* +@@ -50,19 +51,19 @@ static inline void raw_local_irq_disable + { + unsigned long flags = __raw_local_save_flags(); + +- raw_local_irq_restore((flags & ~(1 << 9)) | (1 << 18)); ++ raw_local_irq_restore((flags & ~X86_EFLAGS_IF) | X86_EFLAGS_AC); + } + + static inline void raw_local_irq_enable(void) + { + unsigned long flags = __raw_local_save_flags(); + +- raw_local_irq_restore((flags | (1 << 9)) & ~(1 << 18)); ++ raw_local_irq_restore((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC)); + } + + static inline int raw_irqs_disabled_flags(unsigned long flags) + { +- return !(flags & (1<<9)) || (flags & (1 << 18)); ++ return !(flags & X86_EFLAGS_IF) || (flags & X86_EFLAGS_AC); + } + + #else /* CONFIG_X86_VSMP */ +@@ -118,13 +119,21 @@ static inline int raw_irqs_disabled_flag + * Used in the idle loop; sti takes one instruction cycle + * to complete: + */ +-void raw_safe_halt(void); ++void xen_safe_halt(void); ++static inline void raw_safe_halt(void) ++{ ++ xen_safe_halt(); ++} + + /* + * Used when interrupts are already enabled or to + * shutdown the processor: + */ +-void halt(void); ++void xen_halt(void); ++static inline void halt(void) ++{ ++ xen_halt(); ++} + + #else /* __ASSEMBLY__: */ + # ifdef CONFIG_TRACE_IRQFLAGS +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/mmu_context_64.h 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/mmu_context_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -9,6 +9,9 @@ + #include + #include + ++void arch_exit_mmap(struct mm_struct *mm); ++void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm); ++ + /* + * possibly do the LDT unload here? + */ +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/page_64.h 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/page_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -7,6 +7,7 @@ + #include + #include + #endif ++#include + #include + + /* +@@ -19,18 +20,14 @@ + + /* PAGE_SHIFT determines the page size */ + #define PAGE_SHIFT 12 +-#ifdef __ASSEMBLY__ +-#define PAGE_SIZE (0x1 << PAGE_SHIFT) +-#else +-#define PAGE_SIZE (1UL << PAGE_SHIFT) +-#endif ++#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) + #define PAGE_MASK (~(PAGE_SIZE-1)) + + /* See Documentation/x86_64/mm.txt for a description of the memory map. */ + #define __PHYSICAL_MASK_SHIFT 46 +-#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) ++#define __PHYSICAL_MASK ((_AC(1,UL) << __PHYSICAL_MASK_SHIFT) - 1) + #define __VIRTUAL_MASK_SHIFT 48 +-#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) ++#define __VIRTUAL_MASK ((_AC(1,UL) << __VIRTUAL_MASK_SHIFT) - 1) + + #define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK) + +@@ -55,10 +52,10 @@ + #define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ + + #define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) +-#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT) ++#define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT) + + #define HPAGE_SHIFT PMD_SHIFT +-#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) ++#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) + #define HPAGE_MASK (~(HPAGE_SIZE - 1)) + #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) + +@@ -152,17 +149,23 @@ static inline pgd_t __pgd(unsigned long + + #define __pgprot(x) ((pgprot_t) { (x) } ) + +-#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START) +-#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) +-#define __START_KERNEL_map 0xffffffff80000000UL +-#define __PAGE_OFFSET 0xffff880000000000UL ++#endif /* !__ASSEMBLY__ */ + +-#else + #define __PHYSICAL_START CONFIG_PHYSICAL_START ++#define __KERNEL_ALIGN 0x200000 ++ ++/* ++ * Make sure kernel is aligned to 2MB address. Catching it at compile ++ * time is better. Change your config file and compile the kernel ++ * for a 2MB aligned address (CONFIG_PHYSICAL_START) ++ */ ++#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0 ++#error "CONFIG_PHYSICAL_START must be a multiple of 2MB" ++#endif ++ + #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) +-#define __START_KERNEL_map 0xffffffff80000000 +-#define __PAGE_OFFSET 0xffff880000000000 +-#endif /* !__ASSEMBLY__ */ ++#define __START_KERNEL_map _AC(0xffffffff80000000, UL) ++#define __PAGE_OFFSET _AC(0xffff880000000000, UL) + + #if CONFIG_XEN_COMPAT <= 0x030002 + #undef LOAD_OFFSET +@@ -172,20 +175,20 @@ static inline pgd_t __pgd(unsigned long + /* to align the pointer to the (next) page boundary */ + #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +-#define KERNEL_TEXT_SIZE (40UL*1024*1024) +-#define KERNEL_TEXT_START 0xffffffff80000000UL ++#define KERNEL_TEXT_SIZE (40*1024*1024) ++#define KERNEL_TEXT_START _AC(0xffffffff80000000, UL) ++ ++#define PAGE_OFFSET __PAGE_OFFSET + +-#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) ++#ifndef __ASSEMBLY__ ++static inline unsigned long __phys_addr(unsigned long x) ++{ ++ return x - (x >= __START_KERNEL_map ? __START_KERNEL_map : PAGE_OFFSET); ++} ++#endif + +-/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol. +- Otherwise you risk miscompilation. */ +-#define __pa(x) (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET) +-/* __pa_symbol should be used for C visible symbols. +- This seems to be the official gcc blessed way to do such arithmetic. */ +-#define __pa_symbol(x) \ +- ({unsigned long v; \ +- asm("" : "=r" (v) : "0" (x)); \ +- __pa(v); }) ++#define __pa(x) __phys_addr((unsigned long)(x)) ++#define __pa_symbol(x) __phys_addr((unsigned long)(x)) + + #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) + #define __boot_va(x) __va(x) +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/pgalloc_64.h 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/pgalloc_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -1,7 +1,6 @@ + #ifndef _X86_64_PGALLOC_H + #define _X86_64_PGALLOC_H + +-#include + #include + #include + #include +@@ -100,24 +99,16 @@ static inline void pgd_list_add(pgd_t *p + struct page *page = virt_to_page(pgd); + + spin_lock(&pgd_lock); +- page->index = (pgoff_t)pgd_list; +- if (pgd_list) +- pgd_list->private = (unsigned long)&page->index; +- pgd_list = page; +- page->private = (unsigned long)&pgd_list; ++ list_add(&page->lru, &pgd_list); + spin_unlock(&pgd_lock); + } + + static inline void pgd_list_del(pgd_t *pgd) + { +- struct page *next, **pprev, *page = virt_to_page(pgd); ++ struct page *page = virt_to_page(pgd); + + spin_lock(&pgd_lock); +- next = (struct page *)page->index; +- pprev = (struct page **)page->private; +- *pprev = next; +- if (next) +- next->private = (unsigned long)pprev; ++ list_del(&page->lru); + spin_unlock(&pgd_lock); + } + +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -1,12 +1,14 @@ + #ifndef _X86_64_PGTABLE_H + #define _X86_64_PGTABLE_H + ++#include ++#ifndef __ASSEMBLY__ ++ + /* + * This file contains the functions and defines necessary to modify and use + * the x86-64 page table tree. + */ + #include +-#include + #include + #include + #include +@@ -35,11 +37,9 @@ extern pte_t *lookup_address(unsigned lo + #endif + + extern pud_t level3_kernel_pgt[512]; +-extern pud_t level3_physmem_pgt[512]; + extern pud_t level3_ident_pgt[512]; + extern pmd_t level2_kernel_pgt[512]; + extern pgd_t init_level4_pgt[]; +-extern pgd_t boot_level4_pgt[]; + extern unsigned long __supported_pte_mask; + + #define swapper_pg_dir init_level4_pgt +@@ -54,6 +54,8 @@ extern void clear_kernel_mapping(unsigne + extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; + #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + ++#endif /* !__ASSEMBLY__ */ ++ + /* + * PGDIR_SHIFT determines what a top-level page table entry can map + */ +@@ -78,6 +80,8 @@ extern unsigned long empty_zero_page[PAG + */ + #define PTRS_PER_PTE 512 + ++#ifndef __ASSEMBLY__ ++ + #define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%016lx pfn %010lx).\n", __FILE__, __LINE__, \ + &(e), __pte_val(e), pte_pfn(e)) +@@ -120,22 +124,23 @@ static inline void pgd_clear (pgd_t * pg + + #define pte_pgprot(a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK)) + +-#define PMD_SIZE (1UL << PMD_SHIFT) ++#endif /* !__ASSEMBLY__ */ ++ ++#define PMD_SIZE (_AC(1,UL) << PMD_SHIFT) + #define PMD_MASK (~(PMD_SIZE-1)) +-#define PUD_SIZE (1UL << PUD_SHIFT) ++#define PUD_SIZE (_AC(1,UL) << PUD_SHIFT) + #define PUD_MASK (~(PUD_SIZE-1)) +-#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT) + #define PGDIR_MASK (~(PGDIR_SIZE-1)) + + #define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1) + #define FIRST_USER_ADDRESS 0 + +-#ifndef __ASSEMBLY__ +-#define MAXMEM 0x3fffffffffffUL +-#define VMALLOC_START 0xffffc20000000000UL +-#define VMALLOC_END 0xffffe1ffffffffffUL +-#define MODULES_VADDR 0xffffffff88000000UL +-#define MODULES_END 0xfffffffffff00000UL ++#define MAXMEM _AC(0x3fffffffffff, UL) ++#define VMALLOC_START _AC(0xffffc20000000000, UL) ++#define VMALLOC_END _AC(0xffffe1ffffffffff, UL) ++#define MODULES_VADDR _AC(0xffffffff88000000, UL) ++#define MODULES_END _AC(0xfffffffffff00000, UL) + #define MODULES_LEN (MODULES_END - MODULES_VADDR) + + #define _PAGE_BIT_PRESENT 0 +@@ -161,16 +166,18 @@ static inline void pgd_clear (pgd_t * pg + #define _PAGE_GLOBAL 0x100 /* Global TLB entry */ + + #define _PAGE_PROTNONE 0x080 /* If not present */ +-#define _PAGE_NX (1UL<<_PAGE_BIT_NX) ++#define _PAGE_NX (_AC(1,UL)<<_PAGE_BIT_NX) + + /* Mapped page is I/O or foreign and has no associated page struct. */ + #define _PAGE_IO 0x200 + ++#ifndef __ASSEMBLY__ + #if CONFIG_XEN_COMPAT <= 0x030002 + extern unsigned int __kernel_page_user; + #else + #define __kernel_page_user 0 + #endif ++#endif + + #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) + #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | __kernel_page_user) +@@ -235,6 +242,8 @@ extern unsigned int __kernel_page_user; + #define __S110 PAGE_SHARED_EXEC + #define __S111 PAGE_SHARED_EXEC + ++#ifndef __ASSEMBLY__ ++ + static inline unsigned long pgd_bad(pgd_t pgd) + { + return __pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER); +@@ -346,6 +355,20 @@ static inline pte_t pte_mkwrite(pte_t pt + static inline pte_t pte_mkhuge(pte_t pte) { __pte_val(pte) |= _PAGE_PSE; return pte; } + static inline pte_t pte_clrhuge(pte_t pte) { __pte_val(pte) &= ~_PAGE_PSE; return pte; } + ++static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) ++{ ++ if (!pte_dirty(*ptep)) ++ return 0; ++ return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte); ++} ++ ++static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) ++{ ++ if (!pte_young(*ptep)) ++ return 0; ++ return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte); ++} ++ + static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) + { + pte_t pte = *ptep; +@@ -470,18 +493,12 @@ static inline pte_t pte_modify(pte_t pte + * bit at the same time. */ + #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS + #define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ +- do { \ +- if (dirty) \ +- ptep_establish(vma, address, ptep, entry); \ +- } while (0) +- +- +-/* +- * i386 says: We don't actually have these, but we want to advertise +- * them so that we can encompass the flush here. +- */ +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++({ \ ++ int __changed = !pte_same(*(ptep), entry); \ ++ if (__changed && (dirty)) \ ++ ptep_establish(vma, address, ptep, entry); \ ++ __changed; \ ++}) + + #define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH + #define ptep_clear_flush_dirty(vma, address, ptep) \ +@@ -490,7 +507,7 @@ static inline pte_t pte_modify(pte_t pte + int __dirty = pte_dirty(__pte); \ + __pte = pte_mkclean(__pte); \ + if ((vma)->vm_mm->context.pinned) \ +- ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ ++ (void)ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ + else if (__dirty) \ + set_pte(ptep, __pte); \ + __dirty; \ +@@ -503,7 +520,7 @@ static inline pte_t pte_modify(pte_t pte + int __young = pte_young(__pte); \ + __pte = pte_mkold(__pte); \ + if ((vma)->vm_mm->context.pinned) \ +- ptep_set_access_flags(vma, address, ptep, __pte, __young); \ ++ (void)ptep_set_access_flags(vma, address, ptep, __pte, __young); \ + else if (__young) \ + set_pte(ptep, __pte); \ + __young; \ +@@ -517,10 +534,7 @@ static inline pte_t pte_modify(pte_t pte + #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + + extern spinlock_t pgd_lock; +-extern struct page *pgd_list; +-void vmalloc_sync_all(void); +- +-#endif /* !__ASSEMBLY__ */ ++extern struct list_head pgd_list; + + extern int kern_addr_valid(unsigned long addr); + +@@ -559,10 +573,6 @@ int xen_change_pte_range(struct mm_struc + #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO) + +-#define MK_IOSPACE_PFN(space, pfn) (pfn) +-#define GET_IOSPACE(pfn) 0 +-#define GET_PFN(pfn) (pfn) +- + #define HAVE_ARCH_UNMAPPED_AREA + + #define pgtable_cache_init() do { } while (0) +@@ -576,11 +586,14 @@ int xen_change_pte_range(struct mm_struc + #define kc_offset_to_vaddr(o) \ + (((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o)) + ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG ++#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL + #define __HAVE_ARCH_PTEP_CLEAR_FLUSH + #define __HAVE_ARCH_PTEP_SET_WRPROTECT + #define __HAVE_ARCH_PTE_SAME + #include ++#endif /* !__ASSEMBLY__ */ + + #endif /* _X86_64_PGTABLE_H */ +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/processor_64.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/processor_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #define TF_MASK 0x00000100 + #define IF_MASK 0x00000200 +@@ -103,42 +104,6 @@ extern unsigned int init_intel_cacheinfo + extern unsigned short num_cache_leaves; + + /* +- * EFLAGS bits +- */ +-#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ +-#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */ +-#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */ +-#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ +-#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */ +-#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */ +-#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */ +-#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */ +-#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */ +-#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */ +-#define X86_EFLAGS_NT 0x00004000 /* Nested Task */ +-#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */ +-#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */ +-#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */ +-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */ +-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ +-#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ +- +-/* +- * Intel CPU features in CR4 +- */ +-#define X86_CR4_VME 0x0001 /* enable vm86 extensions */ +-#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */ +-#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */ +-#define X86_CR4_DE 0x0008 /* enable debugging extensions */ +-#define X86_CR4_PSE 0x0010 /* enable page size extensions */ +-#define X86_CR4_PAE 0x0020 /* enable physical address extensions */ +-#define X86_CR4_MCE 0x0040 /* Machine check enable */ +-#define X86_CR4_PGE 0x0080 /* enable global pages */ +-#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */ +-#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ +-#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ +- +-/* + * Save the cr4 feature set we're using (ie + * Pentium 4MB enable and PPro Global page + * enable), so that any CPU's that boot up +@@ -203,7 +168,7 @@ struct i387_fxsave_struct { + u32 mxcsr; + u32 mxcsr_mask; + u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ +- u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 128 bytes */ ++ u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ + u32 padding[24]; + } __attribute__ ((aligned (16))); + +@@ -436,22 +401,6 @@ static inline void prefetchw(void *x) + #define cpu_relax() rep_nop() + + /* +- * NSC/Cyrix CPU configuration register indexes +- */ +-#define CX86_CCR0 0xc0 +-#define CX86_CCR1 0xc1 +-#define CX86_CCR2 0xc2 +-#define CX86_CCR3 0xc3 +-#define CX86_CCR4 0xe8 +-#define CX86_CCR5 0xe9 +-#define CX86_CCR6 0xea +-#define CX86_CCR7 0xeb +-#define CX86_DIR0 0xfe +-#define CX86_DIR1 0xff +-#define CX86_ARR_BASE 0xc4 +-#define CX86_RCR_BASE 0xdc +- +-/* + * NSC/Cyrix CPU indexed register access macros + */ + +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/smp_64.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/smp_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -11,12 +11,11 @@ + extern int disable_apic; + + #ifdef CONFIG_X86_LOCAL_APIC +-#include + #include ++#include + #ifdef CONFIG_X86_IO_APIC + #include + #endif +-#include + #include + #endif + +@@ -41,7 +40,6 @@ extern void lock_ipi_call_lock(void); + extern void unlock_ipi_call_lock(void); + extern int smp_num_siblings; + extern void smp_send_reschedule(int cpu); +-void smp_stop_cpu(void); + + extern cpumask_t cpu_sibling_map[NR_CPUS]; + extern cpumask_t cpu_core_map[NR_CPUS]; +@@ -62,14 +60,6 @@ static inline int num_booting_cpus(void) + + #define raw_smp_processor_id() read_pda(cpunumber) + +-#ifdef CONFIG_X86_LOCAL_APIC +-static inline int hard_smp_processor_id(void) +-{ +- /* we don't want to mark this access volatile - bad code generation */ +- return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); +-} +-#endif +- + extern int __cpu_disable(void); + extern void __cpu_die(unsigned int cpu); + extern void prefill_possible_map(void); +@@ -78,6 +68,14 @@ extern unsigned __cpuinitdata disabled_c + + #define NO_PROC_ID 0xFF /* No processor magic marker */ + ++#endif /* CONFIG_SMP */ ++ ++#ifdef CONFIG_X86_LOCAL_APIC ++static inline int hard_smp_processor_id(void) ++{ ++ /* we don't want to mark this access volatile - bad code generation */ ++ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); ++} + #endif + + /* +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/system_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/system_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -3,7 +3,7 @@ + + #include + #include +-#include ++#include + + #include + #include +@@ -43,7 +43,7 @@ + [threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \ + [ti_flags] "i" (offsetof(struct thread_info, flags)),\ + [tif_fork] "i" (TIF_FORK), \ +- [thread_info] "i" (offsetof(struct task_struct, thread_info)), \ ++ [thread_info] "i" (offsetof(struct task_struct, stack)), \ + [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)) \ + : "memory", "cc" __EXTRA_CLOBBER) + +@@ -92,6 +92,12 @@ static inline void write_cr0(unsigned lo + machine_to_phys(__dummy); \ + }) + ++static inline void write_cr3(unsigned long val) ++{ ++ val = phys_to_machine(val); ++ asm volatile("movq %0,%%cr3" :: "r" (val) : "memory"); ++} ++ + static inline unsigned long read_cr4(void) + { + unsigned long cr4; +@@ -101,7 +107,7 @@ static inline unsigned long read_cr4(voi + + static inline void write_cr4(unsigned long val) + { +- asm volatile("movq %0,%%cr4" :: "r" (val)); ++ asm volatile("movq %0,%%cr4" :: "r" (val) : "memory"); + } + + #define stts() (HYPERVISOR_fpu_taskswitch(1)) +@@ -122,100 +128,6 @@ static inline void sched_cacheflush(void + + #define nop() __asm__ __volatile__ ("nop") + +-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr)))) +- +-#define tas(ptr) (xchg((ptr),1)) +- +-#define __xg(x) ((volatile long *)(x)) +- +-static inline void set_64bit(volatile unsigned long *ptr, unsigned long val) +-{ +- *ptr = val; +-} +- +-#define _set_64bit set_64bit +- +-/* +- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway +- * Note 2: xchg has side effect, so that attribute volatile is necessary, +- * but generally the primitive is invalid, *ptr is output argument. --ANK +- */ +-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +-{ +- switch (size) { +- case 1: +- __asm__ __volatile__("xchgb %b0,%1" +- :"=q" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- case 2: +- __asm__ __volatile__("xchgw %w0,%1" +- :"=r" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- case 4: +- __asm__ __volatile__("xchgl %k0,%1" +- :"=r" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- case 8: +- __asm__ __volatile__("xchgq %0,%1" +- :"=r" (x) +- :"m" (*__xg(ptr)), "0" (x) +- :"memory"); +- break; +- } +- return x; +-} +- +-/* +- * Atomic compare and exchange. Compare OLD with MEM, if identical, +- * store NEW in MEM. Return the initial value in MEM. Success is +- * indicated by comparing RETURN with OLD. +- */ +- +-#define __HAVE_ARCH_CMPXCHG 1 +- +-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, +- unsigned long new, int size) +-{ +- unsigned long prev; +- switch (size) { +- case 1: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" +- : "=a"(prev) +- : "q"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 2: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 4: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- case 8: +- __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2" +- : "=a"(prev) +- : "r"(new), "m"(*__xg(ptr)), "0"(old) +- : "memory"); +- return prev; +- } +- return old; +-} +- +-#define cmpxchg(ptr,o,n)\ +- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ +- (unsigned long)(n),sizeof(*(ptr)))) +- + #ifdef CONFIG_SMP + #define smp_mb() mb() + #define smp_rmb() rmb() +--- sle11-2009-04-20.orig/include/asm-x86/mach-xen/asm/tlbflush_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-04-20/include/asm-x86/mach-xen/asm/tlbflush_64.h 2008-12-15 11:27:22.000000000 +0100 +@@ -2,7 +2,9 @@ + #define _X8664_TLBFLUSH_H + + #include ++#include + #include ++#include + + #define __flush_tlb() xen_tlb_flush() + +--- sle11-2009-04-20.orig/include/linux/pci.h 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/include/linux/pci.h 2008-12-15 11:27:22.000000000 +0100 +@@ -239,7 +239,7 @@ struct pci_dev { + int rom_attr_enabled; /* has display of the rom attribute been enabled? */ + struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ + struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ +-#ifdef CONFIG_PCI_MSI ++#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) + struct list_head msi_list; + #endif + struct pci_vpd *vpd; +--- sle11-2009-04-20.orig/lib/swiotlb-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-04-20/lib/swiotlb-xen.c 2009-02-05 11:16:51.000000000 +0100 +@@ -723,7 +723,6 @@ swiotlb_dma_supported (struct device *hw + return (mask >= ((1UL << dma_bits) - 1)); + } + +-EXPORT_SYMBOL(swiotlb_init); + EXPORT_SYMBOL(swiotlb_map_single); + EXPORT_SYMBOL(swiotlb_unmap_single); + EXPORT_SYMBOL(swiotlb_map_sg); +--- sle11-2009-04-20.orig/net/core/dev.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-04-20/net/core/dev.c 2008-12-15 11:27:22.000000000 +0100 +@@ -1744,12 +1744,17 @@ static struct netdev_queue *dev_pick_tx( + inline int skb_checksum_setup(struct sk_buff *skb) + { + if (skb->proto_csum_blank) { ++ struct iphdr *iph; ++ unsigned char *th; ++ + if (skb->protocol != htons(ETH_P_IP)) + goto out; +- skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl; +- if (skb->h.raw >= skb->tail) ++ iph = ip_hdr(skb); ++ th = skb_network_header(skb) + 4 * iph->ihl; ++ if (th >= skb_tail_pointer(skb)) + goto out; +- switch (skb->nh.iph->protocol) { ++ skb->csum_start = th - skb->head; ++ switch (iph->protocol) { + case IPPROTO_TCP: + skb->csum_offset = offsetof(struct tcphdr, check); + break; +@@ -1760,10 +1765,10 @@ inline int skb_checksum_setup(struct sk_ + if (net_ratelimit()) + printk(KERN_ERR "Attempting to checksum a non-" + "TCP/UDP packet, dropping a protocol" +- " %d packet", skb->nh.iph->protocol); ++ " %d packet", iph->protocol); + goto out; + } +- if ((skb->h.raw + skb->csum_offset + 2) > skb->tail) ++ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb)) + goto out; + skb->ip_summed = CHECKSUM_PARTIAL; + skb->proto_csum_blank = 0; +--- sle11-2009-04-20.orig/scripts/Makefile.xen.awk 2009-04-29 08:44:31.000000000 +0200 ++++ sle11-2009-04-20/scripts/Makefile.xen.awk 2008-12-15 11:27:22.000000000 +0100 +@@ -13,7 +13,7 @@ BEGIN { + next + } + +-/:[[:space:]]*%\.[cS][[:space:]]/ { ++/:[[:space:]]*\$\(src\)\/%\.[cS][[:space:]]/ { + line = gensub(/%.([cS])/, "%-xen.\\1", "g", $0) + line = gensub(/(single-used-m)/, "xen-\\1", "g", line) + print line diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.23 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.23 new file mode 100644 index 000000000..ea2c556a1 --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.23 @@ -0,0 +1,5149 @@ +From: www.kernel.org +Subject: Update to 2.6.23 +Patch-mainline: 2.6.23 + +Automatically created from "patches.kernel.org/patch-2.6.23" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-05-14.orig/arch/x86/Makefile 2008-12-01 11:11:08.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/Makefile 2009-02-16 16:17:21.000000000 +0100 +@@ -148,7 +148,7 @@ libs-y += arch/x86/lib/ + core-y += $(fcore-y) + + # Xen paravirtualization support +-core-$(CONFIG_XEN) += arch/x86/xen/ ++core-$(CONFIG_PARAVIRT_XEN) += arch/x86/xen/ + + # lguest paravirtualization support + core-$(CONFIG_LGUEST_GUEST) += arch/x86/lguest/ +--- sle11-2009-05-14.orig/arch/x86/kernel/acpi/sleep_32-xen.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/acpi/sleep_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -15,7 +15,7 @@ + #ifndef CONFIG_ACPI_PV_SLEEP + /* address in low memory of the wakeup routine. */ + unsigned long acpi_wakeup_address = 0; +-unsigned long acpi_video_flags; ++unsigned long acpi_realmode_flags; + extern char wakeup_start, wakeup_end; + + extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); +@@ -74,9 +74,11 @@ static int __init acpi_sleep_setup(char + { + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "s3_bios", 7) == 0) +- acpi_video_flags = 1; ++ acpi_realmode_flags |= 1; + if (strncmp(str, "s3_mode", 7) == 0) +- acpi_video_flags |= 2; ++ acpi_realmode_flags |= 2; ++ if (strncmp(str, "s3_beep", 7) == 0) ++ acpi_realmode_flags |= 4; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); +@@ -86,9 +88,11 @@ static int __init acpi_sleep_setup(char + + __setup("acpi_sleep=", acpi_sleep_setup); + ++/* Ouch, we want to delete this. We already have better version in userspace, in ++ s2ram from suspend.sf.net project */ + static __init int reset_videomode_after_s3(struct dmi_system_id *d) + { +- acpi_video_flags |= 2; ++ acpi_realmode_flags |= 2; + return 0; + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/asm-offsets_32.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/asm-offsets_32.c 2009-02-16 16:17:21.000000000 +0100 +@@ -19,7 +19,9 @@ + #include + #include + ++#if defined(CONFIG_XEN) || defined(CONFIG_PARAVIRT_XEN) + #include ++#endif + + #include + #include "../../../drivers/lguest/lg.h" +@@ -121,7 +123,7 @@ void foo(void) + OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0); + #endif + +-#ifdef CONFIG_XEN ++#ifdef CONFIG_PARAVIRT_XEN + BLANK(); + OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask); + OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending); +--- sle11-2009-05-14.orig/arch/x86/kernel/cpu/common-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/cpu/common-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -360,6 +360,8 @@ static void __cpuinit generic_identify(s + if ( xlvl >= 0x80000004 ) + get_model_name(c); /* Default name */ + } ++ ++ init_scattered_cpuid_features(c); + } + + early_intel_workaround(c); +@@ -611,7 +613,6 @@ extern int nsc_init_cpu(void); + extern int amd_init_cpu(void); + extern int centaur_init_cpu(void); + extern int transmeta_init_cpu(void); +-extern int rise_init_cpu(void); + extern int nexgen_init_cpu(void); + extern int umc_init_cpu(void); + +@@ -623,7 +624,6 @@ void __init early_cpu_init(void) + amd_init_cpu(); + centaur_init_cpu(); + transmeta_init_cpu(); +- rise_init_cpu(); + nexgen_init_cpu(); + umc_init_cpu(); + early_cpu_detect(); +--- sle11-2009-05-14.orig/arch/x86/kernel/cpu/mtrr/main-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/cpu/mtrr/main-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -167,7 +167,7 @@ mtrr_del(int reg, unsigned long base, un + EXPORT_SYMBOL(mtrr_add); + EXPORT_SYMBOL(mtrr_del); + +-__init void mtrr_bp_init(void) ++void __init mtrr_bp_init(void) + { + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/e820_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/e820_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -343,6 +344,37 @@ static int __init request_standard_resou + + subsys_initcall(request_standard_resources); + ++#if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION) ++/** ++ * e820_mark_nosave_regions - Find the ranges of physical addresses that do not ++ * correspond to e820 RAM areas and mark the corresponding pages as nosave for ++ * hibernation. ++ * ++ * This function requires the e820 map to be sorted and without any ++ * overlapping entries and assumes the first e820 area to be RAM. ++ */ ++void __init e820_mark_nosave_regions(void) ++{ ++ int i; ++ unsigned long pfn; ++ ++ pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size); ++ for (i = 1; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ ++ if (pfn < PFN_UP(ei->addr)) ++ register_nosave_region(pfn, PFN_UP(ei->addr)); ++ ++ pfn = PFN_DOWN(ei->addr + ei->size); ++ if (ei->type != E820_RAM) ++ register_nosave_region(PFN_UP(ei->addr), pfn); ++ ++ if (pfn >= max_low_pfn) ++ break; ++ } ++} ++#endif ++ + void __init add_memory_region(unsigned long long start, + unsigned long long size, int type) + { +@@ -804,7 +836,7 @@ void __init print_memory_map(char *who) + case E820_NVS: + printk("(ACPI NVS)\n"); + break; +- default: printk("type %lu\n", e820.map[i].type); ++ default: printk("type %u\n", e820.map[i].type); + break; + } + } +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32.S 2008-11-25 12:35:53.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/entry_32.S 2009-02-16 16:17:21.000000000 +0100 +@@ -1112,7 +1112,7 @@ ENTRY(kernel_thread_helper) + CFI_ENDPROC + ENDPROC(kernel_thread_helper) + +-#ifdef CONFIG_XEN ++#ifdef CONFIG_PARAVIRT_XEN + /* Xen doesn't set %esp to be precisely what the normal sysenter + entrypoint expects, so fix it up before using the normal path. */ + ENTRY(xen_sysenter_target) +@@ -1205,7 +1205,7 @@ ENTRY(xen_failsafe_callback) + .previous + ENDPROC(xen_failsafe_callback) + +-#endif /* CONFIG_XEN */ ++#endif /* CONFIG_PARAVIRT_XEN */ + + #ifdef CONFIG_FTRACE + #ifdef CONFIG_DYNAMIC_FTRACE +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32-xen.S 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/entry_32-xen.S 2009-02-16 16:17:21.000000000 +0100 +@@ -452,9 +452,6 @@ restore_nocheck_notrace: + 1: INTERRUPT_RETURN + .section .fixup,"ax" + iret_exc: +-#ifndef CONFIG_XEN +- ENABLE_INTERRUPTS(CLBR_NONE) +-#endif + pushl $0 # no error code + pushl $do_iret_error + jmp error_code +--- sle11-2009-05-14.orig/arch/x86/kernel/head_32-xen.S 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/head_32-xen.S 2009-02-16 16:17:21.000000000 +0100 +@@ -86,7 +86,10 @@ ENTRY(_stext) + /* + * BSS section + */ +-.section ".bss.page_aligned","w" ++.section ".bss.page_aligned","wa" ++ .align PAGE_SIZE_asm ++ENTRY(swapper_pg_pmd) ++ .fill 1024,4,0 + ENTRY(empty_zero_page) + .fill 4096,1,0 + +@@ -136,25 +139,25 @@ ENTRY(empty_zero_page) + #endif /* CONFIG_XEN_COMPAT <= 0x030002 */ + + +- ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "linux") +- ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "2.6") +- ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0") +- ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long, __PAGE_OFFSET) ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6") ++ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0") ++ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long __PAGE_OFFSET) + #if CONFIG_XEN_COMPAT <= 0x030002 +- ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, __PAGE_OFFSET) ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long __PAGE_OFFSET) + #else +- ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long, 0) ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .long 0) + #endif +- ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long, startup_32) +- ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long, hypercall_page) +- ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long, HYPERVISOR_VIRT_START) +- ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") ++ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long startup_32) ++ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long hypercall_page) ++ ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, .long HYPERVISOR_VIRT_START) ++ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") + #ifdef CONFIG_X86_PAE +- ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "yes") +- ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad, _PAGE_PRESENT,_PAGE_PRESENT) ++ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes") ++ ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad _PAGE_PRESENT, _PAGE_PRESENT) + #else +- ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz, "no") +- ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .long, _PAGE_PRESENT,_PAGE_PRESENT) ++ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "no") ++ ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .long _PAGE_PRESENT, _PAGE_PRESENT) + #endif +- ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic") +- ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long, 1) ++ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") ++ ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1) +--- sle11-2009-05-14.orig/arch/x86/kernel/init_task-xen.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/kernel/init_task-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -46,6 +46,6 @@ EXPORT_SYMBOL(init_task); + * per-CPU TSS segments. Threads are completely 'soft' on Linux, + * no more per-task TSS's. + */ +-DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS; ++DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS; + #endif + +--- sle11-2009-05-14.orig/arch/x86/kernel/io_apic_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/io_apic_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -402,14 +402,6 @@ static void set_ioapic_affinity_irq(unsi + # include /* kmalloc() */ + # include /* time_after() */ + +-#ifdef CONFIG_BALANCED_IRQ_DEBUG +-# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) +-# define Dprintk(x...) do { TDprintk(x); } while (0) +-# else +-# define TDprintk(x...) +-# define Dprintk(x...) +-# endif +- + #define IRQBALANCE_CHECK_ARCH -999 + #define MAX_BALANCED_IRQ_INTERVAL (5*HZ) + #define MIN_BALANCED_IRQ_INTERVAL (HZ/2) +@@ -492,7 +484,7 @@ static inline void balance_irq(int cpu, + static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold) + { + int i, j; +- Dprintk("Rotating IRQs among CPUs.\n"); ++ + for_each_online_cpu(i) { + for (j = 0; j < NR_IRQS; j++) { + if (!irq_desc[j].action) +@@ -609,19 +601,11 @@ tryanothercpu: + max_loaded = tmp_loaded; /* processor */ + imbalance = (max_cpu_irq - min_cpu_irq) / 2; + +- Dprintk("max_loaded cpu = %d\n", max_loaded); +- Dprintk("min_loaded cpu = %d\n", min_loaded); +- Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq); +- Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq); +- Dprintk("load imbalance = %lu\n", imbalance); +- + /* if imbalance is less than approx 10% of max load, then + * observe diminishing returns action. - quit + */ +- if (imbalance < (max_cpu_irq >> 3)) { +- Dprintk("Imbalance too trivial\n"); ++ if (imbalance < (max_cpu_irq >> 3)) + goto not_worth_the_effort; +- } + + tryanotherirq: + /* if we select an IRQ to move that can't go where we want, then +@@ -678,9 +662,6 @@ tryanotherirq: + cpus_and(tmp, target_cpu_mask, allowed_mask); + + if (!cpus_empty(tmp)) { +- +- Dprintk("irq = %d moved to cpu = %d\n", +- selected_irq, min_loaded); + /* mark for change destination */ + set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded)); + +@@ -700,7 +681,6 @@ not_worth_the_effort: + */ + balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, + balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); +- Dprintk("IRQ worth rotating not found\n"); + return; + } + +@@ -716,6 +696,7 @@ static int balanced_irq(void *unused) + set_pending_irq(i, cpumask_of_cpu(0)); + } + ++ set_freezable(); + for ( ; ; ) { + time_remaining = schedule_timeout_interruptible(time_remaining); + try_to_freeze(); +@@ -825,14 +806,6 @@ static int pirq_entries [MAX_PIRQS]; + static int pirqs_enabled; + int skip_ioapic_setup; + +-static int __init ioapic_setup(char *str) +-{ +- skip_ioapic_setup = 1; +- return 1; +-} +- +-__setup("noapic", ioapic_setup); +- + static int __init ioapic_pirq_setup(char *str) + { + int i, max; +@@ -1323,12 +1296,15 @@ static struct irq_chip ioapic_chip; + static void ioapic_register_intr(int irq, int vector, unsigned long trigger) + { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || +- trigger == IOAPIC_LEVEL) ++ trigger == IOAPIC_LEVEL) { ++ irq_desc[irq].status |= IRQ_LEVEL; + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_fasteoi_irq, "fasteoi"); +- else ++ } else { ++ irq_desc[irq].status &= ~IRQ_LEVEL; + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_edge_irq, "edge"); ++ } + set_intr_gate(vector, interrupt[irq]); + } + #else +@@ -1957,7 +1933,7 @@ __setup("no_timer_check", notimercheck); + * - if this function detects that timer IRQs are defunct, then we fall + * back to ISA timer IRQs + */ +-int __init timer_irq_works(void) ++static int __init timer_irq_works(void) + { + unsigned long t1 = jiffies; + +--- sle11-2009-05-14.orig/arch/x86/kernel/irq_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/irq_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -21,7 +21,7 @@ + #include + #include + +-DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; ++DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); + EXPORT_PER_CPU_SYMBOL(irq_stat); + + DEFINE_PER_CPU(struct pt_regs *, irq_regs); +@@ -149,15 +149,11 @@ fastcall unsigned int do_IRQ(struct pt_r + + #ifdef CONFIG_4KSTACKS + +-/* +- * These should really be __section__(".bss.page_aligned") as well, but +- * gcc's 3.0 and earlier don't handle that correctly. +- */ + static char softirq_stack[NR_CPUS * THREAD_SIZE] +- __attribute__((__aligned__(THREAD_SIZE))); ++ __attribute__((__section__(".bss.page_aligned"))); + + static char hardirq_stack[NR_CPUS * THREAD_SIZE] +- __attribute__((__aligned__(THREAD_SIZE))); ++ __attribute__((__section__(".bss.page_aligned"))); + + /* + * allocate per-cpu stacks for hardirq and for softirq processing +--- sle11-2009-05-14.orig/arch/x86/kernel/microcode-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/microcode-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +--- sle11-2009-05-14.orig/arch/x86/kernel/pci-dma-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/pci-dma-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -24,7 +24,7 @@ + #include + + #ifdef __x86_64__ +-#include ++#include + + int iommu_merge __read_mostly = 0; + EXPORT_SYMBOL(iommu_merge); +--- sle11-2009-05-14.orig/arch/x86/kernel/process_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/process_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -241,6 +241,7 @@ early_param("idle", idle_setup); + void show_regs(struct pt_regs * regs) + { + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; ++ unsigned long d0, d1, d2, d3, d6, d7; + + printk("\n"); + printk("Pid: %d, comm: %20s\n", current->pid, current->comm); +@@ -265,6 +266,17 @@ void show_regs(struct pt_regs * regs) + cr3 = read_cr3(); + cr4 = read_cr4_safe(); + printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); ++ ++ get_debugreg(d0, 0); ++ get_debugreg(d1, 1); ++ get_debugreg(d2, 2); ++ get_debugreg(d3, 3); ++ printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", ++ d0, d1, d2, d3); ++ get_debugreg(d6, 6); ++ get_debugreg(d7, 7); ++ printk("DR6: %08lx DR7: %08lx\n", d6, d7); ++ + show_trace(NULL, regs, ®s->esp); + } + +@@ -473,7 +485,30 @@ int dump_task_regs(struct task_struct *t + return 1; + } + +-static noinline void __switch_to_xtra(struct task_struct *next_p) ++#ifdef CONFIG_SECCOMP ++void hard_disable_TSC(void) ++{ ++ write_cr4(read_cr4() | X86_CR4_TSD); ++} ++void disable_TSC(void) ++{ ++ preempt_disable(); ++ if (!test_and_set_thread_flag(TIF_NOTSC)) ++ /* ++ * Must flip the CPU state synchronously with ++ * TIF_NOTSC in the current running context. ++ */ ++ hard_disable_TSC(); ++ preempt_enable(); ++} ++void hard_enable_TSC(void) ++{ ++ write_cr4(read_cr4() & ~X86_CR4_TSD); ++} ++#endif /* CONFIG_SECCOMP */ ++ ++static noinline void ++__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p) + { + struct thread_struct *next; + +@@ -488,33 +523,17 @@ static noinline void __switch_to_xtra(st + set_debugreg(next->debugreg[6], 6); + set_debugreg(next->debugreg[7], 7); + } +-} + +-/* +- * This function selects if the context switch from prev to next +- * has to tweak the TSC disable bit in the cr4. +- */ +-static inline void disable_tsc(struct task_struct *prev_p, +- struct task_struct *next_p) +-{ +- struct thread_info *prev, *next; +- +- /* +- * gcc should eliminate the ->thread_info dereference if +- * has_secure_computing returns 0 at compile time (SECCOMP=n). +- */ +- prev = task_thread_info(prev_p); +- next = task_thread_info(next_p); +- +- if (has_secure_computing(prev) || has_secure_computing(next)) { +- /* slow path here */ +- if (has_secure_computing(prev) && +- !has_secure_computing(next)) { +- write_cr4(read_cr4() & ~X86_CR4_TSD); +- } else if (!has_secure_computing(prev) && +- has_secure_computing(next)) +- write_cr4(read_cr4() | X86_CR4_TSD); ++#ifdef CONFIG_SECCOMP ++ if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ ++ test_tsk_thread_flag(next_p, TIF_NOTSC)) { ++ /* prev and next are different */ ++ if (test_tsk_thread_flag(next_p, TIF_NOTSC)) ++ hard_disable_TSC(); ++ else ++ hard_enable_TSC(); + } ++#endif + } + + /* +@@ -649,10 +668,9 @@ struct task_struct fastcall * __switch_t + /* + * Now maybe handle debug registers + */ +- if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) +- __switch_to_xtra(next_p); +- +- disable_tsc(prev_p, next_p); ++ if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV || ++ task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT)) ++ __switch_to_xtra(prev_p, next_p); + + /* + * Leave lazy mode, flushing any hypercalls made here. +--- sle11-2009-05-14.orig/arch/x86/kernel/setup_32-xen.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/setup_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -114,19 +114,10 @@ static unsigned int highmem_pages = -1; + /* + * Setup options + */ +-struct drive_info_struct { char dummy[32]; } drive_info; +-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \ +- defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +-EXPORT_SYMBOL(drive_info); +-#endif + struct screen_info screen_info; + EXPORT_SYMBOL(screen_info); + struct apm_info apm_info; + EXPORT_SYMBOL(apm_info); +-struct sys_desc_table_struct { +- unsigned short length; +- unsigned char table[0]; +-}; + struct edid_info edid_info; + EXPORT_SYMBOL_GPL(edid_info); + #ifndef CONFIG_XEN +@@ -149,7 +140,7 @@ unsigned long saved_videomode; + + static char __initdata command_line[COMMAND_LINE_SIZE]; + +-unsigned char __initdata boot_params[PARAM_SIZE]; ++struct boot_params __initdata boot_params; + + /* + * Point at the empty zero page to start with. We map the real shared_info +@@ -316,18 +307,18 @@ unsigned long __init find_max_low_pfn(vo + printk(KERN_WARNING "Warning only %ldMB will be used.\n", + MAXMEM>>20); + if (max_pfn > MAX_NONPAE_PFN) +- printk(KERN_WARNING "Use a PAE enabled kernel.\n"); ++ printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n"); + else + printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); + max_pfn = MAXMEM_PFN; + #else /* !CONFIG_HIGHMEM */ +-#ifndef CONFIG_X86_PAE ++#ifndef CONFIG_HIGHMEM64G + if (max_pfn > MAX_NONPAE_PFN) { + max_pfn = MAX_NONPAE_PFN; + printk(KERN_WARNING "Warning only 4GB will be used.\n"); +- printk(KERN_WARNING "Use a PAE enabled kernel.\n"); ++ printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n"); + } +-#endif /* !CONFIG_X86_PAE */ ++#endif /* !CONFIG_HIGHMEM64G */ + #endif /* !CONFIG_HIGHMEM */ + } else { + if (highmem_pages == -1) +@@ -514,7 +505,7 @@ void __init setup_bootmem_allocator(void + * + * This should all compile down to nothing when NUMA is off. + */ +-void __init remapped_pgdat_init(void) ++static void __init remapped_pgdat_init(void) + { + int nid; + +@@ -589,7 +580,6 @@ void __init setup_arch(char **cmdline_p) + properly. Setting ROOT_DEV to default to /dev/ram0 breaks initrd. + */ + ROOT_DEV = MKDEV(UNNAMED_MAJOR,0); +- drive_info = DRIVE_INFO; + screen_info = SCREEN_INFO; + copy_edid(); + apm_info.bios = APM_BIOS_INFO; +@@ -767,6 +757,8 @@ void __init setup_arch(char **cmdline_p) + * NOTE: at this point the bootmem allocator is fully available. + */ + ++ paravirt_post_allocator_init(); ++ + if (is_initial_xendomain()) + dmi_scan_machine(); + +@@ -814,6 +806,7 @@ void __init setup_arch(char **cmdline_p) + #endif + + e820_register_memory(); ++ e820_mark_nosave_regions(); + + if (is_initial_xendomain()) { + #ifdef CONFIG_VT +--- sle11-2009-05-14.orig/arch/x86/kernel/smp_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/smp_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -22,6 +22,7 @@ + + #include + #include ++#include + #if 0 + #include + #endif +@@ -217,13 +218,13 @@ static unsigned long flush_va; + static DEFINE_SPINLOCK(tlbstate_lock); + + /* +- * We cannot call mmdrop() because we are in interrupt context, ++ * We cannot call mmdrop() because we are in interrupt context, + * instead update mm->cpu_vm_mask. + * + * We need to reload %cr3 since the page tables may be going + * away from under us.. + */ +-static inline void leave_mm (unsigned long cpu) ++void leave_mm(unsigned long cpu) + { + if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) + BUG(); +--- sle11-2009-05-14.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:11:31.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/time_32-xen.c 2009-03-24 10:12:09.000000000 +0100 +@@ -76,11 +76,12 @@ + #include + #include + +-#ifdef CONFIG_X86_32 + #include + DEFINE_SPINLOCK(i8253_lock); + EXPORT_SYMBOL(i8253_lock); +-#else ++ ++#ifdef CONFIG_X86_64 ++#include + volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES; + #endif + +@@ -756,56 +757,10 @@ unsigned long read_persistent_clock(void + return retval; + } + +-static void sync_cmos_clock(unsigned long dummy); +- +-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); +-int no_sync_cmos_clock; +- +-static void sync_cmos_clock(unsigned long dummy) +-{ +- struct timeval now, next; +- int fail = 1; +- +- /* +- * If we have an externally synchronized Linux clock, then update +- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be +- * called as close as possible to 500 ms before the new second starts. +- * This code is run on a timer. If the clock is set, that timer +- * may not expire at the correct time. Thus, we adjust... +- */ +- if (!ntp_synced()) +- /* +- * Not synced, exit, do not restart a timer (if one is +- * running, let it run out). +- */ +- return; +- +- do_gettimeofday(&now); +- if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 && +- now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) +- fail = set_rtc_mmss(now.tv_sec); +- +- next.tv_usec = USEC_AFTER - now.tv_usec; +- if (next.tv_usec <= 0) +- next.tv_usec += USEC_PER_SEC; +- +- if (!fail) +- next.tv_sec = 659; +- else +- next.tv_sec = 0; +- +- if (next.tv_usec >= USEC_PER_SEC) { +- next.tv_sec++; +- next.tv_usec -= USEC_PER_SEC; +- } +- mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next)); +-} +- +-void notify_arch_cmos_timer(void) ++int update_persistent_clock(struct timespec now) + { +- if (!no_sync_cmos_clock) +- mod_timer(&sync_cmos_timer, jiffies + 1); + mod_timer(&sync_xen_wallclock_timer, jiffies + 1); ++ return set_rtc_mmss(now.tv_sec); + } + + extern void (*late_time_init)(void); +--- sle11-2009-05-14.orig/arch/x86/kernel/traps_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/traps_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -41,6 +41,10 @@ + #include + #endif + ++#if defined(CONFIG_EDAC) ++#include ++#endif ++ + #include + #include + #include +@@ -102,36 +106,45 @@ asmlinkage void machine_check(void); + int kstack_depth_to_print = 24; + static unsigned int code_bytes = 64; + +-static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) ++static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size) + { + return p > (void *)tinfo && +- p < (void *)tinfo + THREAD_SIZE - 3; ++ p <= (void *)tinfo + THREAD_SIZE - size; + } + ++/* The form of the top of the frame on the stack */ ++struct stack_frame { ++ struct stack_frame *next_frame; ++ unsigned long return_address; ++}; ++ + static inline unsigned long print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long ebp, + struct stacktrace_ops *ops, void *data) + { +- unsigned long addr; +- + #ifdef CONFIG_FRAME_POINTER +- while (valid_stack_ptr(tinfo, (void *)ebp)) { +- unsigned long new_ebp; +- addr = *(unsigned long *)(ebp + 4); ++ struct stack_frame *frame = (struct stack_frame *)ebp; ++ while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) { ++ struct stack_frame *next; ++ unsigned long addr; ++ ++ addr = frame->return_address; + ops->address(data, addr); + /* + * break out of recursive entries (such as + * end_of_stack_stop_unwind_function). Also, + * we can never allow a frame pointer to + * move downwards! +- */ +- new_ebp = *(unsigned long *)ebp; +- if (new_ebp <= ebp) ++ */ ++ next = frame->next_frame; ++ if (next <= frame) + break; +- ebp = new_ebp; ++ frame = next; + } + #else +- while (valid_stack_ptr(tinfo, stack)) { ++ while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { ++ unsigned long addr; ++ + addr = *stack++; + if (__kernel_text_address(addr)) + ops->address(data, addr); +@@ -154,7 +167,7 @@ void dump_trace(struct task_struct *task + if (!stack) { + unsigned long dummy; + stack = &dummy; +- if (task && task != current) ++ if (task != current) + stack = (unsigned long *)task->thread.esp; + } + +@@ -213,6 +226,7 @@ static void print_trace_address(void *da + { + printk("%s [<%08lx>] ", (char *)data, addr); + print_symbol("%s\n", addr); ++ touch_nmi_watchdog(); + } + + static struct stacktrace_ops print_trace_ops = { +@@ -396,7 +410,7 @@ void die(const char * str, struct pt_reg + unsigned long esp; + unsigned short ss; + +- report_bug(regs->eip); ++ report_bug(regs->eip, regs); + + printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); + #ifdef CONFIG_PREEMPT +@@ -439,6 +453,7 @@ void die(const char * str, struct pt_reg + + bust_spinlocks(0); + die.lock_owner = -1; ++ add_taint(TAINT_DIE); + spin_unlock_irqrestore(&die.lock, flags); + + if (!regs) +@@ -523,10 +538,12 @@ fastcall void do_##name(struct pt_regs * + do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ + } + +-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ ++#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ + fastcall void do_##name(struct pt_regs * regs, long error_code) \ + { \ + siginfo_t info; \ ++ if (irq) \ ++ local_irq_enable(); \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ +@@ -566,13 +583,13 @@ DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) + #endif + DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) + DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) +-DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip) ++DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0) + DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) + DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) + DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) + DO_ERROR(12, SIGBUS, "stack segment", stack_segment) +-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) +-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) ++DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) ++DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1) + + fastcall void __kprobes do_general_protection(struct pt_regs * regs, + long error_code) +@@ -585,6 +602,13 @@ fastcall void __kprobes do_general_prote + + current->thread.error_code = error_code; + current->thread.trap_no = 13; ++ if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) && ++ printk_ratelimit()) ++ printk(KERN_INFO ++ "%s[%d] general protection eip:%lx esp:%lx error:%lx\n", ++ current->comm, current->pid, ++ regs->eip, regs->esp, error_code); ++ + force_sig(SIGSEGV, current); + return; + +@@ -610,6 +634,14 @@ mem_parity_error(unsigned char reason, s + printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " + "CPU %d.\n", reason, smp_processor_id()); + printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); ++ ++#if defined(CONFIG_EDAC) ++ if(edac_handler_set()) { ++ edac_atomic_assert_error(); ++ return; ++ } ++#endif ++ + if (panic_on_unrecovered_nmi) + panic("NMI: Not continuing"); + +@@ -720,6 +752,8 @@ static __kprobes void default_do_nmi(str + reassert_nmi(); + } + ++static int ignore_nmis; ++ + fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) + { + int cpu; +@@ -730,11 +764,24 @@ fastcall __kprobes void do_nmi(struct pt + + ++nmi_count(cpu); + +- default_do_nmi(regs); ++ if (!ignore_nmis) ++ default_do_nmi(regs); + + nmi_exit(); + } + ++void stop_nmi(void) ++{ ++ acpi_nmi_disable(); ++ ignore_nmis++; ++} ++ ++void restart_nmi(void) ++{ ++ ignore_nmis--; ++ acpi_nmi_enable(); ++} ++ + #ifdef CONFIG_KPROBES + fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) + { +@@ -1023,6 +1070,7 @@ asmlinkage void math_state_restore(void) + thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ + tsk->fpu_counter++; + } ++EXPORT_SYMBOL_GPL(math_state_restore); + + #ifndef CONFIG_MATH_EMULATION + +--- sle11-2009-05-14.orig/arch/x86/mach-xen/setup.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mach-xen/setup.c 2009-02-16 16:17:21.000000000 +0100 +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -101,7 +102,7 @@ void __init pre_setup_arch_hook(void) + + init_mm.pgd = swapper_pg_dir = (pgd_t *)xen_start_info->pt_base; + +- setup_xen_features(); ++ xen_setup_features(); + + if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0) { + hypervisor_virt_start = pp.virt_start; +@@ -157,4 +158,18 @@ void __init machine_specific_arch_setup( + HYPERVISOR_nmi_op(XENNMI_register_callback, &cb); + } + #endif ++ ++ /* Do an early initialization of the fixmap area */ ++ { ++ extern pte_t swapper_pg_pmd[PTRS_PER_PTE]; ++ unsigned long addr = __fix_to_virt(FIX_EARLYCON_MEM_BASE); ++ pgd_t *pgd = (pgd_t *)xen_start_info->pt_base; ++ pud_t *pud = pud_offset(pgd + pgd_index(addr), addr); ++ pmd_t *pmd = pmd_offset(pud, addr); ++ ++ swapper_pg_dir = pgd; ++ init_mm.pgd = pgd; ++ make_lowmem_page_readonly(swapper_pg_pmd, XENFEAT_writable_page_tables); ++ set_pmd(pmd, __pmd(__pa_symbol(swapper_pg_pmd) | _PAGE_TABLE)); ++ } + } +--- sle11-2009-05-14.orig/arch/x86/mm/fault_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/fault_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -346,7 +346,10 @@ static inline pmd_t *vmalloc_sync_one(pg + pmd_k = pmd_offset(pud_k, address); + if (!pmd_present(*pmd_k)) + return NULL; +- if (!pmd_present(*pmd)) ++ if (!pmd_present(*pmd)) { ++ bool lazy = x86_read_percpu(xen_lazy_mmu); ++ ++ x86_write_percpu(xen_lazy_mmu, false); + #if CONFIG_XEN_COMPAT > 0x030002 + set_pmd(pmd, *pmd_k); + #else +@@ -356,7 +359,8 @@ static inline pmd_t *vmalloc_sync_one(pg + */ + set_pmd(pmd, __pmd(pmd_val(*pmd_k))); + #endif +- else ++ x86_write_percpu(xen_lazy_mmu, lazy); ++ } else + BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); + return pmd_k; + } +@@ -388,6 +392,8 @@ static inline int vmalloc_fault(unsigned + return 0; + } + ++int show_unhandled_signals = 1; ++ + /* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate +@@ -408,6 +414,7 @@ fastcall void __kprobes do_page_fault(st + struct vm_area_struct * vma; + unsigned long address; + int write, si_code; ++ int fault; + + /* get the address */ + address = read_cr2(); +@@ -541,20 +548,18 @@ good_area: + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ +- switch (handle_mm_fault(mm, vma, address, write)) { +- case VM_FAULT_MINOR: +- tsk->min_flt++; +- break; +- case VM_FAULT_MAJOR: +- tsk->maj_flt++; +- break; +- case VM_FAULT_SIGBUS: +- goto do_sigbus; +- case VM_FAULT_OOM: ++ fault = handle_mm_fault(mm, vma, address, write); ++ if (unlikely(fault & VM_FAULT_ERROR)) { ++ if (fault & VM_FAULT_OOM) + goto out_of_memory; +- default: +- BUG(); ++ else if (fault & VM_FAULT_SIGBUS) ++ goto do_sigbus; ++ BUG(); + } ++ if (fault & VM_FAULT_MAJOR) ++ tsk->maj_flt++; ++ else ++ tsk->min_flt++; + + /* + * Did it hit the DOS screen memory VA from vm86 mode? +@@ -589,6 +594,14 @@ bad_area_nosemaphore: + if (is_prefetch(regs, address, error_code)) + return; + ++ if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && ++ printk_ratelimit()) { ++ printk("%s%s[%d]: segfault at %08lx eip %08lx " ++ "esp %08lx error %lx\n", ++ tsk->pid > 1 ? KERN_INFO : KERN_EMERG, ++ tsk->comm, tsk->pid, address, regs->eip, ++ regs->esp, error_code); ++ } + tsk->thread.cr2 = address; + /* Kernel addresses are always protection faults */ + tsk->thread.error_code = error_code | (address >= TASK_SIZE); +--- sle11-2009-05-14.orig/arch/x86/mm/highmem_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/highmem_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -34,17 +34,16 @@ void *kmap_atomic_prot(struct page *page + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ + pagefault_disable(); + +- idx = type + KM_TYPE_NR*smp_processor_id(); +- BUG_ON(!pte_none(*(kmap_pte-idx))); +- + if (!PageHighMem(page)) + return page_address(page); + ++ idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); ++ BUG_ON(!pte_none(*(kmap_pte-idx))); + set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); + /*arch_flush_lazy_mmu_mode();*/ + +- return (void*) vaddr; ++ return (void *)vaddr; + } + + void *kmap_atomic(struct page *page, enum km_type type) +--- sle11-2009-05-14.orig/arch/x86/mm/init_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/init_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -96,7 +96,7 @@ static pte_t * __init one_page_table_ini + #endif + pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + +- paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT); ++ paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT); + make_lowmem_page_readonly(page_table, + XENFEAT_writable_page_tables); + set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); +@@ -446,7 +446,7 @@ static void __init pagetable_init (void) + xen_pagetable_setup_done(pgd_base); + } + +-#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP) ++#if defined(CONFIG_HIBERNATION) || defined(CONFIG_ACPI) + /* + * Swap suspend & friends need this for resume because things like the intel-agp + * driver might have split up a kernel 4MB mapping. +@@ -485,9 +485,13 @@ void zap_low_mappings (void) + flush_tlb_all(); + } + ++int nx_enabled = 0; ++ ++#ifdef CONFIG_X86_PAE ++ + static int disable_nx __initdata = 0; + u64 __supported_pte_mask __read_mostly = ~_PAGE_NX; +-EXPORT_SYMBOL(__supported_pte_mask); ++EXPORT_SYMBOL_GPL(__supported_pte_mask); + + /* + * noexec = on|off +@@ -514,9 +518,6 @@ static int __init noexec_setup(char *str + } + early_param("noexec", noexec_setup); + +-int nx_enabled = 0; +-#ifdef CONFIG_X86_PAE +- + static void __init set_nx(void) + { + unsigned int v[4], l, h; +@@ -764,7 +765,7 @@ void __init mem_init(void) + zap_low_mappings(); + #endif + +- set_bit(PG_pinned, &virt_to_page(init_mm.pgd)->flags); ++ SetPagePinned(virt_to_page(init_mm.pgd)); + } + + #ifdef CONFIG_MEMORY_HOTPLUG +@@ -796,8 +797,7 @@ void __init pgtable_cache_init(void) + PTRS_PER_PMD*sizeof(pmd_t), + PTRS_PER_PMD*sizeof(pmd_t), + SLAB_PANIC, +- pmd_ctor, +- NULL); ++ pmd_ctor); + if (!SHARED_KERNEL_PMD) { + /* If we're in PAE mode and have a non-shared + kernel pmd, then the pgd size must be a +--- sle11-2009-05-14.orig/arch/x86/mm/ioremap_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/ioremap_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -363,9 +363,8 @@ void iounmap(volatile void __iomem *addr + + /* Reset the direct mapping. Can block */ + if ((p->flags >> 20) && is_local_lowmem(p->phys_addr)) { +- /* p->size includes the guard page, but cpa doesn't like that */ + change_page_attr(virt_to_page(bus_to_virt(p->phys_addr)), +- (p->size - PAGE_SIZE) >> PAGE_SHIFT, ++ get_vm_area_size(p) >> PAGE_SHIFT, + PAGE_KERNEL); + global_flush_tlb(); + } +--- sle11-2009-05-14.orig/arch/x86/mm/pgtable_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/pgtable_32-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -198,7 +198,7 @@ void pte_free(struct page *pte) + va, pfn_pte(pfn, PAGE_KERNEL), 0)) + BUG(); + } else +- clear_bit(PG_pinned, &pte->flags); ++ ClearPagePinned(pte); + + ClearPageForeign(pte); + init_page_count(pte); +@@ -248,7 +248,7 @@ static inline void pgd_list_del(pgd_t *p + + #if (PTRS_PER_PMD == 1) + /* Non-PAE pgd constructor */ +-void pgd_ctor(void *pgd) ++static void pgd_ctor(void *pgd) + { + unsigned long flags; + +@@ -271,7 +271,7 @@ void pgd_ctor(void *pgd) + } + #else /* PTRS_PER_PMD > 1 */ + /* PAE pgd constructor */ +-void pgd_ctor(void *pgd) ++static void pgd_ctor(void *pgd) + { + /* PAE, kernel PMD may be shared */ + +@@ -285,7 +285,7 @@ void pgd_ctor(void *pgd) + } + #endif /* PTRS_PER_PMD */ + +-void pgd_dtor(void *pgd) ++static void pgd_dtor(void *pgd) + { + unsigned long flags; /* can be called from interrupt context */ + +@@ -637,9 +637,9 @@ static inline unsigned int pgd_walk_set_ + + if (PageHighMem(page)) { + if (pgprot_val(flags) & _PAGE_RW) +- clear_bit(PG_pinned, &page->flags); ++ ClearPagePinned(page); + else +- set_bit(PG_pinned, &page->flags); ++ SetPagePinned(page); + } else { + MULTI_update_va_mapping(per_cpu(pb_mcl, cpu) + seq, + (unsigned long)__va(pfn << PAGE_SHIFT), +@@ -709,19 +709,19 @@ static void __pgd_pin(pgd_t *pgd) + pgd_walk(pgd, PAGE_KERNEL_RO); + kmap_flush_unused(); + xen_pgd_pin(__pa(pgd)); +- set_bit(PG_pinned, &virt_to_page(pgd)->flags); ++ SetPagePinned(virt_to_page(pgd)); + } + + static void __pgd_unpin(pgd_t *pgd) + { + xen_pgd_unpin(__pa(pgd)); + pgd_walk(pgd, PAGE_KERNEL); +- clear_bit(PG_pinned, &virt_to_page(pgd)->flags); ++ ClearPagePinned(virt_to_page(pgd)); + } + + static void pgd_test_and_unpin(pgd_t *pgd) + { +- if (test_bit(PG_pinned, &virt_to_page(pgd)->flags)) ++ if (PagePinned(virt_to_page(pgd))) + __pgd_unpin(pgd); + } + +@@ -759,7 +759,7 @@ void mm_pin_all(void) + */ + spin_lock_irqsave(&pgd_lock, flags); + for (page = pgd_list; page; page = (struct page *)page->index) { +- if (!test_bit(PG_pinned, &page->flags)) ++ if (!PagePinned(page)) + __pgd_pin((pgd_t *)page_address(page)); + } + spin_unlock_irqrestore(&pgd_lock, flags); +@@ -767,7 +767,7 @@ void mm_pin_all(void) + + void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) + { +- if (!test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags)) ++ if (!PagePinned(virt_to_page(mm->pgd))) + mm_pin(mm); + } + +@@ -793,7 +793,7 @@ void arch_exit_mmap(struct mm_struct *mm + + task_unlock(tsk); + +- if (test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags) && ++ if (PagePinned(virt_to_page(mm->pgd)) && + (atomic_read(&mm->mm_count) == 1) && + !mm->context.has_foreign_mappings) + mm_unpin(mm); +--- sle11-2009-05-14.orig/arch/x86/pci/irq-xen.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/pci/irq-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -142,8 +142,9 @@ static void __init pirq_peer_trick(void) + for(i = 1; i < 256; i++) { + if (!busmap[i] || pci_find_bus(0, i)) + continue; +- if (pci_scan_bus(i, &pci_root_ops, NULL)) +- printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); ++ if (pci_scan_bus_with_sysdata(i)) ++ printk(KERN_INFO "PCI: Discovered primary peer " ++ "bus %02x [IRQ]\n", i); + } + pcibios_last_bus = -1; + } +@@ -553,6 +554,7 @@ static __init int intel_router_probe(str + case PCI_DEVICE_ID_INTEL_ICH9_3: + case PCI_DEVICE_ID_INTEL_ICH9_4: + case PCI_DEVICE_ID_INTEL_ICH9_5: ++ case PCI_DEVICE_ID_INTEL_TOLAPAI_0: + r->name = "PIIX/ICH"; + r->get = pirq_piix_get; + r->set = pirq_piix_set; +--- sle11-2009-05-14.orig/arch/x86/xen/Kconfig 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/xen/Kconfig 2009-02-16 16:17:21.000000000 +0100 +@@ -2,7 +2,7 @@ + # This Kconfig describes xen options + # + +-config XEN ++config PARAVIRT_XEN + bool "Xen guest support" + select PARAVIRT + select PARAVIRT_CLOCK +--- sle11-2009-05-14.orig/arch/x86/xen/xen-head.S 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/xen/xen-head.S 2009-02-16 16:17:21.000000000 +0100 +@@ -1,7 +1,7 @@ + /* Xen-specific pieces of head.S, intended to be included in the right + place in head.S */ + +-#ifdef CONFIG_XEN ++#ifdef CONFIG_PARAVIRT_XEN + + #include + #include +@@ -52,4 +52,4 @@ ENTRY(hypercall_page) + ELFNOTE(Xen, XEN_ELFNOTE_HV_START_LOW, _ASM_PTR __HYPERVISOR_VIRT_START) + ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, _ASM_PTR 0) + +-#endif /*CONFIG_XEN */ ++#endif /* CONFIG_PARAVIRT_XEN */ +--- sle11-2009-05-14.orig/arch/x86/ia32/ia32entry-xen.S 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/ia32/ia32entry-xen.S 2009-02-16 16:17:21.000000000 +0100 +@@ -105,7 +105,7 @@ ENTRY(ia32_sysenter_target) + movl $VSYSCALL32_SYSEXIT,8(%rsp) + movq %rax,(%rsp) + cld +- SAVE_ARGS 0,0,0 ++ SAVE_ARGS 0,0,1 + /* no need to do an access_ok check here because rbp has been + 32bit zero extended */ + 1: movl (%rbp),%r9d +@@ -244,7 +244,7 @@ ia32_badarg: + */ + + ENTRY(ia32_syscall) +- CFI_STARTPROC simple ++ CFI_STARTPROC32 simple + CFI_SIGNAL_FRAME + CFI_DEF_CFA rsp,SS+8-RIP+16 + /*CFI_REL_OFFSET ss,SS-RIP+16*/ +@@ -280,6 +280,7 @@ ia32_sysret: + + ia32_tracesys: + SAVE_REST ++ CLEAR_RREGS + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace_enter +@@ -476,7 +477,7 @@ ia32_sys_call_table: + .quad sys_init_module + .quad sys_delete_module + .quad quiet_ni_syscall /* 130 get_kernel_syms */ +- .quad sys_quotactl ++ .quad sys32_quotactl + .quad sys_getpgid + .quad sys_fchdir + .quad quiet_ni_syscall /* bdflush */ +@@ -669,4 +670,5 @@ ia32_sys_call_table: + .quad compat_sys_signalfd + .quad compat_sys_timerfd + .quad sys_eventfd ++ .quad sys32_fallocate + ia32_syscall_end: +--- sle11-2009-05-14.orig/arch/x86/kernel/acpi/sleep_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/acpi/sleep_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -51,12 +51,10 @@ + Low-Level Sleep Support + -------------------------------------------------------------------------- */ + +-#ifdef CONFIG_ACPI_SLEEP +- + #ifndef CONFIG_ACPI_PV_SLEEP + /* address in low memory of the wakeup routine. */ + unsigned long acpi_wakeup_address = 0; +-unsigned long acpi_video_flags; ++unsigned long acpi_realmode_flags; + extern char wakeup_start, wakeup_end; + + extern unsigned long acpi_copy_wakeup_routine(unsigned long); +@@ -109,9 +107,11 @@ static int __init acpi_sleep_setup(char + { + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "s3_bios", 7) == 0) +- acpi_video_flags = 1; ++ acpi_realmode_flags |= 1; + if (strncmp(str, "s3_mode", 7) == 0) +- acpi_video_flags |= 2; ++ acpi_realmode_flags |= 2; ++ if (strncmp(str, "s3_beep", 7) == 0) ++ acpi_realmode_flags |= 4; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); +@@ -123,8 +123,6 @@ static int __init acpi_sleep_setup(char + __setup("acpi_sleep=", acpi_sleep_setup); + #endif /* CONFIG_ACPI_PV_SLEEP */ + +-#endif /*CONFIG_ACPI_SLEEP */ +- + void acpi_pci_link_exit(void) + { + } +--- sle11-2009-05-14.orig/arch/x86/kernel/apic_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/apic_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -50,7 +50,7 @@ void ack_bad_irq(unsigned int irq) + * holds up an irq slot - in excessive cases (when multiple + * unexpected vectors occur) that might lock up the APIC + * completely. +- * But don't ack when the APIC is disabled. -AK ++ * But don't ack when the APIC is disabled. -AK + */ + if (!disable_apic) + ack_APIC_irq(); +@@ -132,20 +132,6 @@ asmlinkage void smp_spurious_interrupt(v + if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) + ack_APIC_irq(); + +-#if 0 +- static unsigned long last_warning; +- static unsigned long skipped; +- +- /* see sw-dev-man vol 3, chapter 7.4.13.5 */ +- if (time_before(last_warning+30*HZ,jiffies)) { +- printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n", +- smp_processor_id(), skipped); +- last_warning = jiffies; +- skipped = 0; +- } else { +- skipped++; +- } +-#endif + irq_exit(); + } + +@@ -177,7 +163,7 @@ asmlinkage void smp_error_interrupt(void + 7: Illegal register address + */ + printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n", +- smp_processor_id(), v , v1); ++ smp_processor_id(), v , v1); + irq_exit(); + } + +--- sle11-2009-05-14.orig/arch/x86/kernel/e820_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/e820_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -222,37 +222,6 @@ unsigned long __init e820_end_of_ram(voi + } + + /* +- * Find the hole size in the range. +- */ +-unsigned long __init e820_hole_size(unsigned long start, unsigned long end) +-{ +- unsigned long ram = 0; +- int i; +- +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +- unsigned long last, addr; +- +- if (ei->type != E820_RAM || +- ei->addr+ei->size <= start || +- ei->addr >= end) +- continue; +- +- addr = round_up(ei->addr, PAGE_SIZE); +- if (addr < start) +- addr = start; +- +- last = round_down(ei->addr + ei->size, PAGE_SIZE); +- if (last >= end) +- last = end; +- +- if (last > addr) +- ram += last - addr; +- } +- return ((end - start) - ram); +-} +- +-/* + * Mark e820 reserved areas as busy for the resource manager. + */ + void __init e820_reserve_resources(struct e820entry *e820, int nr_map) +@@ -325,47 +294,61 @@ void __init e820_mark_nosave_regions(voi + } + #endif + ++/* ++ * Finds an active region in the address range from start_pfn to end_pfn and ++ * returns its range in ei_startpfn and ei_endpfn for the e820 entry. ++ */ ++static int __init e820_find_active_region(const struct e820entry *ei, ++ unsigned long start_pfn, ++ unsigned long end_pfn, ++ unsigned long *ei_startpfn, ++ unsigned long *ei_endpfn) ++{ ++ *ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT; ++ *ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) >> PAGE_SHIFT; ++ ++ /* Skip map entries smaller than a page */ ++ if (*ei_startpfn >= *ei_endpfn) ++ return 0; ++ ++ /* Check if end_pfn_map should be updated */ ++ if (ei->type != E820_RAM && *ei_endpfn > end_pfn_map) ++ end_pfn_map = *ei_endpfn; ++ ++ /* Skip if map is outside the node */ ++ if (ei->type != E820_RAM || *ei_endpfn <= start_pfn || ++ *ei_startpfn >= end_pfn) ++ return 0; ++ ++ /* Check for overlaps */ ++ if (*ei_startpfn < start_pfn) ++ *ei_startpfn = start_pfn; ++ if (*ei_endpfn > end_pfn) ++ *ei_endpfn = end_pfn; ++ ++ /* Obey end_user_pfn to save on memmap */ ++ if (*ei_startpfn >= end_user_pfn) ++ return 0; ++ if (*ei_endpfn > end_user_pfn) ++ *ei_endpfn = end_user_pfn; ++ ++ return 1; ++} ++ + /* Walk the e820 map and register active regions within a node */ + void __init + e820_register_active_regions(int nid, unsigned long start_pfn, + unsigned long end_pfn) + { ++ unsigned long ei_startpfn; ++ unsigned long ei_endpfn; + int i; +- unsigned long ei_startpfn, ei_endpfn; +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +- ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT; +- ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) +- >> PAGE_SHIFT; +- +- /* Skip map entries smaller than a page */ +- if (ei_startpfn >= ei_endpfn) +- continue; +- +- /* Check if end_pfn_map should be updated */ +- if (ei->type != E820_RAM && ei_endpfn > end_pfn_map) +- end_pfn_map = ei_endpfn; +- +- /* Skip if map is outside the node */ +- if (ei->type != E820_RAM || +- ei_endpfn <= start_pfn || +- ei_startpfn >= end_pfn) +- continue; +- +- /* Check for overlaps */ +- if (ei_startpfn < start_pfn) +- ei_startpfn = start_pfn; +- if (ei_endpfn > end_pfn) +- ei_endpfn = end_pfn; +- +- /* Obey end_user_pfn to save on memmap */ +- if (ei_startpfn >= end_user_pfn) +- continue; +- if (ei_endpfn > end_user_pfn) +- ei_endpfn = end_user_pfn; + +- add_active_range(nid, ei_startpfn, ei_endpfn); +- } ++ for (i = 0; i < e820.nr_map; i++) ++ if (e820_find_active_region(&e820.map[i], ++ start_pfn, end_pfn, ++ &ei_startpfn, &ei_endpfn)) ++ add_active_range(nid, ei_startpfn, ei_endpfn); + } + + /* +@@ -386,12 +369,35 @@ void __init add_memory_region(unsigned l + e820.nr_map++; + } + ++/* ++ * Find the hole size (in bytes) in the memory range. ++ * @start: starting address of the memory range to scan ++ * @end: ending address of the memory range to scan ++ */ ++unsigned long __init e820_hole_size(unsigned long start, unsigned long end) ++{ ++ unsigned long start_pfn = start >> PAGE_SHIFT; ++ unsigned long end_pfn = end >> PAGE_SHIFT; ++ unsigned long ei_startpfn; ++ unsigned long ei_endpfn; ++ unsigned long ram = 0; ++ int i; ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ if (e820_find_active_region(&e820.map[i], ++ start_pfn, end_pfn, ++ &ei_startpfn, &ei_endpfn)) ++ ram += ei_endpfn - ei_startpfn; ++ } ++ return end - start - (ram << PAGE_SHIFT); ++} ++ + void __init e820_print_map(char *who) + { + int i; + + for (i = 0; i < e820.nr_map; i++) { +- printk(" %s: %016Lx - %016Lx ", who, ++ printk(KERN_INFO " %s: %016Lx - %016Lx ", who, + (unsigned long long) e820.map[i].addr, + (unsigned long long) (e820.map[i].addr + e820.map[i].size)); + switch (e820.map[i].type) { +--- sle11-2009-05-14.orig/arch/x86/kernel/early_printk-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/early_printk-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -174,6 +174,7 @@ static __init void early_serial_init(cha + * mappings. Someone should fix this for domain 0. For now, use fake serial. + */ + #define early_vga_console early_serial_console ++#define xenboot_console early_serial_console + + #endif + +@@ -261,20 +262,22 @@ static int __init setup_early_printk(cha + } else if (!strncmp(buf, "ttyS", 4)) { + early_serial_init(buf); + early_console = &early_serial_console; +- } else if (!strncmp(buf, "vga", 3) ++ } else if (!strncmp(buf, "vga", 3)) { + #ifndef CONFIG_XEN + && SCREEN_INFO.orig_video_isVGA == 1) { + max_xpos = SCREEN_INFO.orig_video_cols; + max_ypos = SCREEN_INFO.orig_video_lines; + current_ypos = SCREEN_INFO.orig_y; +-#else +- || !strncmp(buf, "xen", 3)) { + #endif + early_console = &early_vga_console; + } else if (!strncmp(buf, "simnow", 6)) { + simnow_init(buf + 6); + early_console = &simnow_console; + keep_early = 1; ++#ifdef CONFIG_XEN ++ } else if (!strncmp(buf, "xen", 3)) { ++ early_console = &xenboot_console; ++#endif + } + + if (keep_early) +--- sle11-2009-05-14.orig/arch/x86/kernel/entry_64-xen.S 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/entry_64-xen.S 2009-02-16 16:17:21.000000000 +0100 +@@ -310,7 +310,7 @@ sysret_signal: + TRACE_IRQS_ON + /* sti */ + XEN_UNBLOCK_EVENTS(%rsi) +- testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx ++ testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx + jz 1f + + /* Really a signal */ +@@ -409,7 +409,7 @@ int_very_careful: + jmp int_restore_rest + + int_signal: +- testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx ++ testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx + jz 1f + movq %rsp,%rdi # &ptregs -> arg1 + xorl %esi,%esi # oldset -> arg2 +@@ -552,7 +552,7 @@ retint_careful: + jmp retint_check + + retint_signal: +- testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx ++ testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx + jz retint_restore_args + TRACE_IRQS_ON + XEN_UNBLOCK_EVENTS(%rsi) +--- sle11-2009-05-14.orig/arch/x86/kernel/head_64-xen.S 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/head_64-xen.S 2009-02-16 16:17:21.000000000 +0100 +@@ -23,7 +23,7 @@ + #include + #include + +- .section .bootstrap.text, "ax", @progbits ++ .section .text.head, "ax", @progbits + .code64 + .globl startup_64 + startup_64: +@@ -39,7 +39,7 @@ startup_64: + + #define NEXT_PAGE(name) \ + .balign PAGE_SIZE; \ +- phys_##name = . - .bootstrap.text; \ ++ phys_##name = . - .text.head; \ + ENTRY(name) + + NEXT_PAGE(init_level4_pgt) +@@ -66,6 +66,12 @@ NEXT_PAGE(level3_user_pgt) + NEXT_PAGE(level2_kernel_pgt) + .fill 512,8,0 + ++NEXT_PAGE(level2_fixmap_pgt) ++ .fill 512,8,0 ++ ++NEXT_PAGE(level1_fixmap_pgt) ++ .fill 512,8,0 ++ + NEXT_PAGE(hypercall_page) + CFI_STARTPROC + .rept 0x1000 / 0x20 +@@ -172,18 +178,18 @@ ENTRY(empty_zero_page) + .byte 0 + #endif /* CONFIG_XEN_COMPAT <= 0x030002 */ + +- ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "linux") +- ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "2.6") +- ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0") +- ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .quad, __START_KERNEL_map) ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") ++ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6") ++ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0") ++ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .quad __START_KERNEL_map) + #if CONFIG_XEN_COMPAT <= 0x030002 +- ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, __START_KERNEL_map) ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad __START_KERNEL_map) + #else +- ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, 0) ++ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad 0) + #endif +- ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .quad, startup_64) +- ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .quad, hypercall_page) +- ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad, _PAGE_PRESENT,_PAGE_PRESENT) +- ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") +- ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic") +- ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long, 1) ++ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .quad startup_64) ++ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .quad hypercall_page) ++ ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, .quad _PAGE_PRESENT, _PAGE_PRESENT) ++ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel") ++ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") ++ ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1) +--- sle11-2009-05-14.orig/arch/x86/kernel/head64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/head64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -90,7 +90,7 @@ void __init x86_64_start_kernel(char * r + unsigned long machine_to_phys_nr_ents; + int i; + +- setup_xen_features(); ++ xen_setup_features(); + + xen_start_info = (struct start_info *)real_mode_data; + if (!xen_feature(XENFEAT_auto_translated_physmap)) +--- sle11-2009-05-14.orig/arch/x86/kernel/io_apic_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/io_apic_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -165,7 +165,9 @@ static inline void io_apic_write(unsigne + #endif + } + +-#ifndef CONFIG_XEN ++#ifdef CONFIG_XEN ++#define io_apic_modify io_apic_write ++#else + /* + * Re-write a value: to be used for read-modify-write + * cycles where the read already set up the index register. +@@ -175,8 +177,32 @@ static inline void io_apic_modify(unsign + struct io_apic __iomem *io_apic = io_apic_base(apic); + writel(value, &io_apic->data); + } +-#else +-#define io_apic_modify io_apic_write ++ ++static int io_apic_level_ack_pending(unsigned int irq) ++{ ++ struct irq_pin_list *entry; ++ unsigned long flags; ++ int pending = 0; ++ ++ spin_lock_irqsave(&ioapic_lock, flags); ++ entry = irq_2_pin + irq; ++ for (;;) { ++ unsigned int reg; ++ int pin; ++ ++ pin = entry->pin; ++ if (pin == -1) ++ break; ++ reg = io_apic_read(entry->apic, 0x10 + pin*2); ++ /* Is the remote IRR bit set? */ ++ pending |= (reg >> 14) & 1; ++ if (!entry->next) ++ break; ++ entry = irq_2_pin + entry->next; ++ } ++ spin_unlock_irqrestore(&ioapic_lock, flags); ++ return pending; ++} + #endif + + /* +@@ -406,14 +432,12 @@ static void clear_IO_APIC (void) + int skip_ioapic_setup; + int ioapic_force; + +-/* dummy parsing: see setup.c */ +- +-static int __init disable_ioapic_setup(char *str) ++static int __init parse_noapic(char *str) + { +- skip_ioapic_setup = 1; ++ disable_ioapic_setup(); + return 0; + } +-early_param("noapic", disable_ioapic_setup); ++early_param("noapic", parse_noapic); + + /* Actually the next is obsolete, but keep it for paranoid reasons -AK */ + static int __init disable_timer_pin_setup(char *arg) +@@ -765,12 +789,15 @@ static struct irq_chip ioapic_chip; + + static void ioapic_register_intr(int irq, unsigned long trigger) + { +- if (trigger) ++ if (trigger) { ++ irq_desc[irq].status |= IRQ_LEVEL; + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_fasteoi_irq, "fasteoi"); +- else ++ } else { ++ irq_desc[irq].status &= ~IRQ_LEVEL; + set_irq_chip_and_handler_name(irq, &ioapic_chip, + handle_edge_irq, "edge"); ++ } + } + #else + #define ioapic_register_intr(irq, trigger) evtchn_register_pirq(irq) +@@ -1419,9 +1446,37 @@ static void ack_apic_level(unsigned int + ack_APIC_irq(); + + /* Now we can move and renable the irq */ +- move_masked_irq(irq); +- if (unlikely(do_unmask_irq)) ++ if (unlikely(do_unmask_irq)) { ++ /* Only migrate the irq if the ack has been received. ++ * ++ * On rare occasions the broadcast level triggered ack gets ++ * delayed going to ioapics, and if we reprogram the ++ * vector while Remote IRR is still set the irq will never ++ * fire again. ++ * ++ * To prevent this scenario we read the Remote IRR bit ++ * of the ioapic. This has two effects. ++ * - On any sane system the read of the ioapic will ++ * flush writes (and acks) going to the ioapic from ++ * this cpu. ++ * - We get to see if the ACK has actually been delivered. ++ * ++ * Based on failed experiments of reprogramming the ++ * ioapic entry from outside of irq context starting ++ * with masking the ioapic entry and then polling until ++ * Remote IRR was clear before reprogramming the ++ * ioapic I don't trust the Remote IRR bit to be ++ * completey accurate. ++ * ++ * However there appears to be no other way to plug ++ * this race, so if the Remote IRR bit is not ++ * accurate and is causing problems then it is a hardware bug ++ * and you can go talk to the chipset vendor about it. ++ */ ++ if (!io_apic_level_ack_pending(irq)) ++ move_masked_irq(irq); + unmask_IO_APIC_irq(irq); ++ } + } + + static struct irq_chip ioapic_chip __read_mostly = { +--- sle11-2009-05-14.orig/arch/x86/kernel/ldt_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/ldt_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -114,6 +114,8 @@ int init_new_context(struct task_struct + memset(&mm->context, 0, sizeof(mm->context)); + init_MUTEX(&mm->context.sem); + old_mm = current->mm; ++ if (old_mm) ++ mm->context.vdso = old_mm->context.vdso; + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); + retval = copy_ldt(&mm->context, &old_mm->context); +@@ -146,7 +148,7 @@ void destroy_context(struct mm_struct *m + kfree(mm->context.ldt); + mm->context.size = 0; + } +- if (!mm->context.pinned) { ++ if (!PagePinned(virt_to_page(mm->pgd))) { + spin_lock(&mm_unpinned_lock); + list_del(&mm->context.unpinned); + spin_unlock(&mm_unpinned_lock); +--- sle11-2009-05-14.orig/arch/x86/kernel/mpparse_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/mpparse_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -32,7 +32,6 @@ + + /* Have we found an MP table */ + int smp_found_config; +-unsigned int __initdata maxcpus = NR_CPUS; + + /* + * Various Linux-internal data structures created from the +@@ -657,6 +656,20 @@ static int mp_find_ioapic(int gsi) + return -1; + } + ++static u8 uniq_ioapic_id(u8 id) ++{ ++ int i; ++ DECLARE_BITMAP(used, 256); ++ bitmap_zero(used, 256); ++ for (i = 0; i < nr_ioapics; i++) { ++ struct mpc_config_ioapic *ia = &mp_ioapics[i]; ++ __set_bit(ia->mpc_apicid, used); ++ } ++ if (!test_bit(id, used)) ++ return id; ++ return find_first_zero_bit(used, 256); ++} ++ + void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base) + { + int idx = 0; +@@ -664,7 +677,7 @@ void __init mp_register_ioapic(u8 id, u3 + if (bad_ioapic(address)) + return; + +- idx = nr_ioapics++; ++ idx = nr_ioapics; + + mp_ioapics[idx].mpc_type = MP_IOAPIC; + mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE; +@@ -673,7 +686,7 @@ void __init mp_register_ioapic(u8 id, u3 + #ifndef CONFIG_XEN + set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); + #endif +- mp_ioapics[idx].mpc_apicid = id; ++ mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id); + mp_ioapics[idx].mpc_apicver = 0; + + /* +@@ -690,6 +703,8 @@ void __init mp_register_ioapic(u8 id, u3 + mp_ioapics[idx].mpc_apicaddr, + mp_ioapic_routing[idx].gsi_start, + mp_ioapic_routing[idx].gsi_end); ++ ++ nr_ioapics++; + } + + void __init +--- sle11-2009-05-14.orig/arch/x86/kernel/process_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/process_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -249,6 +250,7 @@ early_param("idle", idle_setup); + void __show_regs(struct pt_regs * regs) + { + unsigned long fs, gs, shadowgs; ++ unsigned long d0, d1, d2, d3, d6, d7; + unsigned int fsindex,gsindex; + unsigned int ds,cs,es; + +@@ -288,6 +290,14 @@ void __show_regs(struct pt_regs * regs) + fs,fsindex,gs,gsindex,shadowgs); + printk("CS: %04x DS: %04x ES: %04x\n", cs, ds, es); + ++ get_debugreg(d0, 0); ++ get_debugreg(d1, 1); ++ get_debugreg(d2, 2); ++ printk("DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2); ++ get_debugreg(d3, 3); ++ get_debugreg(d6, 6); ++ get_debugreg(d7, 7); ++ printk("DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7); + } + + void show_regs(struct pt_regs *regs) +--- sle11-2009-05-14.orig/arch/x86/kernel/setup_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/setup_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -827,6 +827,8 @@ static void __cpuinit init_amd(struct cp + level = cpuid_eax(1); + if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)) + set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); ++ if (c->x86 == 0x10) ++ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); + + /* Enable workaround for FXSAVE leak */ + if (c->x86 >= 6) +@@ -852,8 +854,14 @@ static void __cpuinit init_amd(struct cp + if (c->extended_cpuid_level >= 0x80000008) + amd_detect_cmp(c); + +- /* Fix cpuid4 emulation for more */ +- num_cache_leaves = 3; ++ if (c->extended_cpuid_level >= 0x80000006 && ++ (cpuid_edx(0x80000006) & 0xf000)) ++ num_cache_leaves = 4; ++ else ++ num_cache_leaves = 3; ++ ++ if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11) ++ set_bit(X86_FEATURE_K8, &c->x86_capability); + + /* RDTSC can be speculated around */ + clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability); +@@ -1098,6 +1106,8 @@ void __cpuinit identify_cpu(struct cpuin + c->x86_capability[2] = cpuid_edx(0x80860001); + } + ++ init_scattered_cpuid_features(c); ++ + c->apicid = phys_pkg_id(0); + + /* +@@ -1183,7 +1193,7 @@ static int show_cpuinfo(struct seq_file + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", +- "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL, ++ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe", + + /* AMD-defined */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +@@ -1199,10 +1209,11 @@ static int show_cpuinfo(struct seq_file + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Other (Linux-defined) */ +- "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL, +- "constant_tsc", NULL, NULL, +- "up", NULL, NULL, NULL, NULL, NULL, NULL, NULL, +- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", ++ NULL, NULL, NULL, NULL, ++ "constant_tsc", "up", NULL, "arch_perfmon", ++ "pebs", "bts", NULL, "sync_rdtsc", ++ "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Intel-defined (#2) */ +@@ -1213,7 +1224,7 @@ static int show_cpuinfo(struct seq_file + + /* VIA/Cyrix/Centaur-defined */ + NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en", +- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +@@ -1224,6 +1235,12 @@ static int show_cpuinfo(struct seq_file + "osvw", "ibs", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ ++ /* Auxiliary (Linux-defined) */ ++ "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; + static char *x86_power_flags[] = { + "ts", /* temperature sensor */ +--- sle11-2009-05-14.orig/arch/x86/kernel/setup64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/setup64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -125,11 +125,14 @@ void __init setup_per_cpu_areas(void) + } + + #ifdef CONFIG_XEN +-static void switch_pt(void) ++static void __init_refok switch_pt(int cpu) + { ++ if (cpu == 0) ++ xen_init_pt(); + xen_pt_switch(__pa_symbol(init_level4_pgt)); + xen_new_user_pt(__pa_symbol(__user_pgd(init_level4_pgt))); + } ++#define switch_pt() switch_pt(cpu) + + static void __cpuinit cpu_gdt_init(const struct desc_ptr *gdt_descr) + { +@@ -185,9 +188,6 @@ void pda_init(int cpu) + pda->mmu_state = 0; + + if (cpu == 0) { +-#ifdef CONFIG_XEN +- xen_init_pt(); +-#endif + /* others are initialized in smpboot.c */ + pda->pcurrent = &init_task; + pda->irqstackptr = boot_cpu_stack; +--- sle11-2009-05-14.orig/arch/x86/kernel/smp_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/smp_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -362,7 +362,7 @@ __smp_call_function_single(int cpu, void + } + + /* +- * smp_call_function_single - Run a function on another CPU ++ * smp_call_function_single - Run a function on a specific CPU + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @nonatomic: Currently unused. +@@ -379,17 +379,21 @@ int smp_call_function_single (int cpu, v + { + /* prevent preemption and reschedule on another processor */ + int me = get_cpu(); ++ ++ /* Can deadlock when called with interrupts disabled */ ++ WARN_ON(irqs_disabled()); ++ + if (cpu == me) { ++ local_irq_disable(); ++ func(info); ++ local_irq_enable(); + put_cpu(); + return 0; + } + +- /* Can deadlock when called with interrupts disabled */ +- WARN_ON(irqs_disabled()); +- +- spin_lock_bh(&call_lock); ++ spin_lock(&call_lock); + __smp_call_function_single(cpu, func, info, nonatomic, wait); +- spin_unlock_bh(&call_lock); ++ spin_unlock(&call_lock); + put_cpu(); + return 0; + } +--- sle11-2009-05-14.orig/arch/x86/kernel/traps_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/traps_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -34,6 +34,10 @@ + #include + #include + ++#if defined(CONFIG_EDAC) ++#include ++#endif ++ + #include + #include + #include +@@ -332,6 +336,7 @@ static int print_trace_stack(void *data, + + static void print_trace_address(void *data, unsigned long addr) + { ++ touch_nmi_watchdog(); + printk_address(addr); + } + +@@ -520,6 +525,7 @@ void __kprobes __die(const char * str, s + printk("\n"); + notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); + show_registers(regs); ++ add_taint(TAINT_DIE); + /* Executive summary in case the oops scrolled away */ + printk(KERN_ALERT "RIP "); + printk_address(regs->rip); +@@ -533,7 +539,7 @@ void die(const char * str, struct pt_reg + unsigned long flags = oops_begin(); + + if (!user_mode(regs)) +- report_bug(regs->rip); ++ report_bug(regs->rip, regs); + + __die(str, regs, err); + oops_end(flags); +@@ -582,7 +588,8 @@ static void __kprobes do_trap(int trapnr + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + +- if (exception_trace && unhandled_signal(tsk, signr)) ++ if (show_unhandled_signals && unhandled_signal(tsk, signr) && ++ printk_ratelimit()) + printk(KERN_INFO + "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", + tsk->comm, tsk->pid, str, +@@ -686,7 +693,8 @@ asmlinkage void __kprobes do_general_pro + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 13; + +- if (exception_trace && unhandled_signal(tsk, SIGSEGV)) ++ if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && ++ printk_ratelimit()) + printk(KERN_INFO + "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", + tsk->comm, tsk->pid, +@@ -721,6 +729,13 @@ mem_parity_error(unsigned char reason, s + reason); + printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); + ++#if defined(CONFIG_EDAC) ++ if(edac_handler_set()) { ++ edac_atomic_assert_error(); ++ return; ++ } ++#endif ++ + if (panic_on_unrecovered_nmi) + panic("NMI: Not continuing"); + +--- sle11-2009-05-14.orig/arch/x86/kernel/vsyscall_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/kernel/vsyscall_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) + #define __syscall_clobber "r11","rcx","memory" +@@ -57,26 +58,9 @@ + * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64) + * Try to keep this structure as small as possible to avoid cache line ping pongs + */ +-struct vsyscall_gtod_data_t { +- seqlock_t lock; +- +- /* open coded 'struct timespec' */ +- time_t wall_time_sec; +- u32 wall_time_nsec; +- +- int sysctl_enabled; +- struct timezone sys_tz; +- struct { /* extract of a clocksource struct */ +- cycle_t (*vread)(void); +- cycle_t cycle_last; +- cycle_t mask; +- u32 mult; +- u32 shift; +- } clock; +-}; + int __vgetcpu_mode __section_vgetcpu_mode; + +-struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data = ++struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data = + { + .lock = SEQLOCK_UNLOCKED, + .sysctl_enabled = 1, +@@ -96,6 +80,8 @@ void update_vsyscall(struct timespec *wa + vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; + vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vsyscall_gtod_data.sys_tz = sys_tz; ++ vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; ++ vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; + write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); + } + +--- sle11-2009-05-14.orig/arch/x86/mm/fault_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/fault_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -159,7 +159,9 @@ void dump_pagetable(unsigned long addres + pmd_t *pmd; + pte_t *pte; + +- pgd = __va(read_cr3() & PHYSICAL_PAGE_MASK); ++ pgd = (pgd_t *)read_cr3(); ++ ++ pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK); + pgd += pgd_index(address); + if (bad_address(pgd)) goto bad; + printk("PGD %lx ", pgd_val(*pgd)); +@@ -219,16 +221,6 @@ static int is_errata93(struct pt_regs *r + return 0; + } + +-int unhandled_signal(struct task_struct *tsk, int sig) +-{ +- if (is_init(tsk)) +- return 1; +- if (tsk->ptrace & PT_PTRACED) +- return 0; +- return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || +- (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); +-} +- + static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, + unsigned long error_code) + { +@@ -302,8 +294,8 @@ static int vmalloc_fault(unsigned long a + return 0; + } + +-int page_fault_trace = 0; +-int exception_trace = 1; ++static int page_fault_trace; ++int show_unhandled_signals = 1; + + + #define MEM_VERBOSE 1 +@@ -372,7 +364,7 @@ asmlinkage void __kprobes do_page_fault( + struct vm_area_struct * vma; + unsigned long address; + const struct exception_table_entry *fixup; +- int write; ++ int write, fault; + unsigned long flags; + siginfo_t info; + +@@ -384,7 +376,7 @@ asmlinkage void __kprobes do_page_fault( + prefetchw(&mm->mmap_sem); + + /* get the address */ +- address = current_vcpu_info()->arch.cr2; ++ address = read_cr2(); + + info.si_code = SEGV_MAPERR; + +@@ -445,6 +437,13 @@ asmlinkage void __kprobes do_page_fault( + 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 +@@ -511,19 +510,18 @@ good_area: + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ +- switch (handle_mm_fault(mm, vma, address, write)) { +- case VM_FAULT_MINOR: +- tsk->min_flt++; +- break; +- case VM_FAULT_MAJOR: +- tsk->maj_flt++; +- break; +- case VM_FAULT_SIGBUS: +- goto do_sigbus; +- default: +- goto out_of_memory; ++ fault = handle_mm_fault(mm, vma, address, write); ++ if (unlikely(fault & VM_FAULT_ERROR)) { ++ if (fault & VM_FAULT_OOM) ++ goto out_of_memory; ++ else if (fault & VM_FAULT_SIGBUS) ++ goto do_sigbus; ++ BUG(); + } +- ++ if (fault & VM_FAULT_MAJOR) ++ tsk->maj_flt++; ++ else ++ tsk->min_flt++; + up_read(&mm->mmap_sem); + return; + +@@ -556,7 +554,8 @@ bad_area_nosemaphore: + (address >> 32)) + return; + +- if (exception_trace && unhandled_signal(tsk, SIGSEGV)) { ++ if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && ++ printk_ratelimit()) { + printk( + "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n", + tsk->pid > 1 ? KERN_INFO : KERN_EMERG, +@@ -630,7 +629,7 @@ out_of_memory: + } + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) +- do_exit(SIGKILL); ++ do_group_exit(SIGKILL); + goto no_context; + + do_sigbus: +--- sle11-2009-05-14.orig/arch/x86/mm/init_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/init_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -66,6 +66,9 @@ int after_bootmem; + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + extern unsigned long start_pfn; + ++extern pmd_t level2_fixmap_pgt[PTRS_PER_PMD]; ++extern pte_t level1_fixmap_pgt[PTRS_PER_PTE]; ++ + /* + * Use this until direct mapping is established, i.e. before __va() is + * available in init_memory_mapping(). +@@ -362,6 +365,10 @@ __set_fixmap (enum fixed_addresses idx, + set_pte_phys(address, phys, prot, 0); + set_pte_phys(address, phys, prot, 1); + break; ++ case FIX_EARLYCON_MEM_BASE: ++ xen_l1_entry_update(level1_fixmap_pgt + pte_index(address), ++ pfn_pte_ma(phys >> PAGE_SHIFT, prot)); ++ break; + default: + set_pte_phys_ma(address, phys, prot); + break; +@@ -594,6 +601,13 @@ void __init xen_init_pt(void) + __user_pgd(init_level4_pgt)[pgd_index(VSYSCALL_START)] = + __pgd(__pa_symbol(level3_user_pgt) | _PAGE_TABLE); + ++ /* Do an early initialization of the fixmap area. */ ++ addr = __fix_to_virt(FIX_EARLYCON_MEM_BASE); ++ level3_kernel_pgt[pud_index(addr)] = ++ __pud(__pa_symbol(level2_fixmap_pgt) | _PAGE_TABLE); ++ level2_fixmap_pgt[pmd_index(addr)] = ++ __pmd(__pa_symbol(level1_fixmap_pgt) | _PAGE_TABLE); ++ + early_make_page_readonly(init_level4_pgt, + XENFEAT_writable_page_tables); + early_make_page_readonly(__user_pgd(init_level4_pgt), +@@ -604,6 +618,10 @@ void __init xen_init_pt(void) + XENFEAT_writable_page_tables); + early_make_page_readonly(level2_kernel_pgt, + XENFEAT_writable_page_tables); ++ early_make_page_readonly(level2_fixmap_pgt, ++ XENFEAT_writable_page_tables); ++ early_make_page_readonly(level1_fixmap_pgt, ++ XENFEAT_writable_page_tables); + + if (!xen_feature(XENFEAT_writable_page_tables)) { + xen_pgd_pin(__pa_symbol(init_level4_pgt)); +@@ -807,7 +825,7 @@ void __init paging_init(void) + sparse_init(); + free_area_init_nodes(max_zone_pfns); + +- init_mm.context.pinned = 1; ++ SetPagePinned(virt_to_page(init_mm.pgd)); + } + #endif + +@@ -1118,41 +1136,6 @@ int kern_addr_valid(unsigned long addr) + return pfn_valid(pte_pfn(*pte)); + } + +-#ifdef CONFIG_SYSCTL +-#include +- +-extern int exception_trace, page_fault_trace; +- +-static ctl_table debug_table2[] = { +- { +- .ctl_name = 99, +- .procname = "exception-trace", +- .data = &exception_trace, +- .maxlen = sizeof(int), +- .mode = 0644, +- .proc_handler = proc_dointvec +- }, +- {} +-}; +- +-static ctl_table debug_root_table2[] = { +- { +- .ctl_name = CTL_DEBUG, +- .procname = "debug", +- .mode = 0555, +- .child = debug_table2 +- }, +- {} +-}; +- +-static __init int x8664_sysctl_init(void) +-{ +- register_sysctl_table(debug_root_table2); +- return 0; +-} +-__initcall(x8664_sysctl_init); +-#endif +- + /* A pseudo VMA to allow ptrace access for the vsyscall page. This only + covers the 64bit vsyscall page now. 32bit has a real VMA now and does + not need special handling anymore. */ +@@ -1191,9 +1174,18 @@ int in_gate_area_no_task(unsigned long a + } + + #ifndef CONFIG_XEN +-void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size) ++void * __init alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size) + { + return __alloc_bootmem_core(pgdat->bdata, size, + SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0); + } + #endif ++ ++const char *arch_vma_name(struct vm_area_struct *vma) ++{ ++ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) ++ return "[vdso]"; ++ if (vma == &gate_vma) ++ return "[vsyscall]"; ++ return NULL; ++} +--- sle11-2009-05-14.orig/arch/x86/mm/pageattr_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/arch/x86/mm/pageattr_64-xen.c 2009-02-16 16:17:21.000000000 +0100 +@@ -171,7 +171,7 @@ void mm_pin(struct mm_struct *mm) + mm_walk(mm, PAGE_KERNEL_RO); + xen_pgd_pin(__pa(mm->pgd)); /* kernel */ + xen_pgd_pin(__pa(__user_pgd(mm->pgd))); /* user */ +- mm->context.pinned = 1; ++ SetPagePinned(virt_to_page(mm->pgd)); + spin_lock(&mm_unpinned_lock); + list_del(&mm->context.unpinned); + spin_unlock(&mm_unpinned_lock); +@@ -189,7 +189,7 @@ void mm_unpin(struct mm_struct *mm) + xen_pgd_unpin(__pa(mm->pgd)); + xen_pgd_unpin(__pa(__user_pgd(mm->pgd))); + mm_walk(mm, PAGE_KERNEL); +- mm->context.pinned = 0; ++ ClearPagePinned(virt_to_page(mm->pgd)); + spin_lock(&mm_unpinned_lock); + list_add(&mm->context.unpinned, &mm_unpinned); + spin_unlock(&mm_unpinned_lock); +@@ -217,7 +217,7 @@ void mm_pin_all(void) + + void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) + { +- if (!mm->context.pinned) ++ if (!PagePinned(virt_to_page(mm->pgd))) + mm_pin(mm); + } + +@@ -243,8 +243,9 @@ void arch_exit_mmap(struct mm_struct *mm + + task_unlock(tsk); + +- if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) && +- !mm->context.has_foreign_mappings ) ++ if (PagePinned(virt_to_page(mm->pgd)) ++ && (atomic_read(&mm->mm_count) == 1) ++ && !mm->context.has_foreign_mappings) + mm_unpin(mm); + } + +@@ -343,14 +344,13 @@ static void flush_kernel_map(void *arg) + struct page *pg; + + /* When clflush is available always use it because it is +- much cheaper than WBINVD. Disable clflush for now because +- the high level code is not ready yet */ ++ much cheaper than WBINVD. */ ++ /* clflush is still broken. Disable for now. */ + if (1 || !cpu_has_clflush) + asm volatile("wbinvd" ::: "memory"); + else list_for_each_entry(pg, l, lru) { + void *adr = page_address(pg); +- if (cpu_has_clflush) +- cache_flush_page(adr); ++ cache_flush_page(adr); + } + __flush_tlb_all(); + } +@@ -364,7 +364,8 @@ static LIST_HEAD(deferred_pages); /* pro + + static inline void save_page(struct page *fpage) + { +- list_add(&fpage->lru, &deferred_pages); ++ if (!test_and_set_bit(PG_arch_1, &fpage->flags)) ++ list_add(&fpage->lru, &deferred_pages); + } + + /* +@@ -398,9 +399,12 @@ __change_page_attr(unsigned long address + pte_t *kpte; + struct page *kpte_page; + pgprot_t ref_prot2; ++ + kpte = lookup_address(address); + if (!kpte) return 0; + kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK); ++ BUG_ON(PageLRU(kpte_page)); ++ BUG_ON(PageCompound(kpte_page)); + if (pgprot_val(prot) != pgprot_val(ref_prot)) { + if (!pte_huge(*kpte)) { + set_pte(kpte, pfn_pte(pfn, prot)); +@@ -439,10 +443,9 @@ __change_page_attr(unsigned long address + return 0; + #endif + +- if (page_private(kpte_page) == 0) { +- save_page(kpte_page); ++ save_page(kpte_page); ++ if (page_private(kpte_page) == 0) + revert_page(address, ref_prot); +- } + return 0; + } + +@@ -514,6 +517,10 @@ void global_flush_tlb(void) + flush_map(&l); + + list_for_each_entry_safe(pg, next, &l, lru) { ++ list_del(&pg->lru); ++ clear_bit(PG_arch_1, &pg->flags); ++ if (page_private(pg) != 0) ++ continue; + ClearPagePrivate(pg); + __free_page(pg); + } +--- sle11-2009-05-14.orig/arch/x86/vdso/vdso32/note.S 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/arch/x86/vdso/vdso32/note.S 2009-02-16 16:17:21.000000000 +0100 +@@ -13,7 +13,7 @@ ELFNOTE_START(Linux, 0, "a") + .long LINUX_VERSION_CODE + ELFNOTE_END + +-#ifdef CONFIG_XEN ++#if defined(CONFIG_X86_XEN) || defined(CONFIG_PARAVIRT_XEN) + /* + * Add a special note telling glibc's dynamic linker a fake hardware + * flavor that it will use to choose the search path for libraries in the +@@ -37,8 +37,12 @@ ELFNOTE_END + + ELFNOTE_START(GNU, 2, "a") + .long 1 /* ncaps */ ++#ifdef CONFIG_PARAVIRT_XEN + VDSO32_NOTE_MASK: /* Symbol used by arch/x86/xen/setup.c */ + .long 0 /* mask */ ++#else ++ .long 1 << VDSO_NOTE_NONEGSEG_BIT /* mask */ ++#endif + .byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg" /* bit, name */ + ELFNOTE_END + #endif +--- sle11-2009-05-14.orig/drivers/Makefile 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-05-14/drivers/Makefile 2009-02-16 16:17:21.000000000 +0100 +@@ -16,7 +16,7 @@ obj-$(CONFIG_ACPI) += acpi/ + obj-$(CONFIG_PNP) += pnp/ + obj-$(CONFIG_ARM_AMBA) += amba/ + +-obj-$(CONFIG_XEN) += xen/ ++obj-$(CONFIG_PARAVIRT_XEN) += xen/ + + # char/ comes before serial/ etc so that the VT console is the boot-time + # default. +--- sle11-2009-05-14.orig/drivers/block/Kconfig 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/block/Kconfig 2009-02-16 16:17:21.000000000 +0100 +@@ -423,9 +423,9 @@ config XILINX_SYSACE + help + Include support for the Xilinx SystemACE CompactFlash interface + +-config XEN_BLKDEV_FRONTEND ++config XEN_BLKFRONT + tristate "Xen virtual block device support" +- depends on XEN ++ depends on PARAVIRT_XEN + default y + help + This driver implements the front-end of the Xen virtual +--- sle11-2009-05-14.orig/drivers/block/Makefile 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/block/Makefile 2009-02-16 16:17:21.000000000 +0100 +@@ -31,5 +31,5 @@ obj-$(CONFIG_BLK_DEV_SX8) += sx8.o + obj-$(CONFIG_BLK_DEV_UB) += ub.o + obj-$(CONFIG_BLK_DEV_HD) += hd.o + +-obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o ++obj-$(CONFIG_XEN_BLKFRONT) += xen-blkfront.o + obj-$(CONFIG_CIPHER_TWOFISH) += loop_fish2.o +--- sle11-2009-05-14.orig/drivers/block/xen-blkfront.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/block/xen-blkfront.c 2009-02-16 16:17:21.000000000 +0100 +@@ -1021,7 +1021,6 @@ static struct xenbus_device_id blkfront_ + + static struct xenbus_driver blkfront = { + .name = "vbd", +- .owner = THIS_MODULE, + .ids = blkfront_ids, + .probe = blkfront_probe, + .remove = blkfront_remove, +--- sle11-2009-05-14.orig/drivers/char/Kconfig 2009-02-16 15:58:02.000000000 +0100 ++++ sle11-2009-05-14/drivers/char/Kconfig 2009-02-16 16:17:21.000000000 +0100 +@@ -624,7 +624,7 @@ config HVC_BEAT + + config HVC_XEN + bool "Xen Hypervisor Console support" +- depends on XEN ++ depends on PARAVIRT_XEN + select HVC_DRIVER + select HVC_IRQ + default y +--- sle11-2009-05-14.orig/drivers/net/Kconfig 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/net/Kconfig 2009-02-16 16:17:21.000000000 +0100 +@@ -2545,9 +2545,9 @@ source "drivers/atm/Kconfig" + + source "drivers/s390/net/Kconfig" + +-config XEN_NETDEV_FRONTEND ++config XEN_NETFRONT + tristate "Xen network device frontend driver" +- depends on XEN ++ depends on PARAVIRT_XEN + default y + help + The network device frontend driver allows the kernel to +--- sle11-2009-05-14.orig/drivers/net/Makefile 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/net/Makefile 2009-02-16 16:17:21.000000000 +0100 +@@ -142,7 +142,7 @@ obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2 + obj-$(CONFIG_SLIP) += slip.o + obj-$(CONFIG_SLHC) += slhc.o + +-obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o ++obj-$(CONFIG_XEN_NETFRONT) += xen-netfront.o + + obj-$(CONFIG_DUMMY) += dummy.o + obj-$(CONFIG_IFB) += ifb.o +--- sle11-2009-05-14.orig/drivers/net/xen-netfront.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/net/xen-netfront.c 2009-02-16 16:17:21.000000000 +0100 +@@ -36,8 +36,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -765,45 +763,6 @@ static RING_IDX xennet_fill_frags(struct + return cons; + } + +-static int skb_checksum_setup(struct sk_buff *skb) +-{ +- struct iphdr *iph; +- unsigned char *th; +- int err = -EPROTO; +- +- if (skb->protocol != htons(ETH_P_IP)) +- goto out; +- +- iph = (void *)skb->data; +- th = skb->data + 4 * iph->ihl; +- if (th >= skb_tail_pointer(skb)) +- goto out; +- +- skb->csum_start = th - skb->head; +- switch (iph->protocol) { +- case IPPROTO_TCP: +- skb->csum_offset = offsetof(struct tcphdr, check); +- break; +- case IPPROTO_UDP: +- skb->csum_offset = offsetof(struct udphdr, check); +- break; +- default: +- if (net_ratelimit()) +- printk(KERN_ERR "Attempting to checksum a non-" +- "TCP/UDP packet, dropping a protocol" +- " %d packet", iph->protocol); +- goto out; +- } +- +- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb)) +- goto out; +- +- err = 0; +- +-out: +- return err; +-} +- + static int handle_incoming_queue(struct net_device *dev, + struct sk_buff_head *rxq) + { +@@ -1784,7 +1743,6 @@ static int __devexit xennet_remove(struc + + static struct xenbus_driver netfront = { + .name = "vif", +- .owner = THIS_MODULE, + .ids = netfront_ids, + .probe = netfront_probe, + .remove = __devexit_p(xennet_remove), +--- sle11-2009-05-14.orig/drivers/xen/Makefile 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/Makefile 2009-02-16 16:17:21.000000000 +0100 +@@ -1,10 +1,12 @@ +-obj-y += core/ +-obj-y += console/ +-obj-y += evtchn/ +-obj-y += xenbus/ +-obj-y += char/ ++obj-$(CONFIG_PARAVIRT_XEN) += grant-table.o + +-obj-y += util.o ++obj-$(CONFIG_XEN) += core/ ++obj-$(CONFIG_XEN) += console/ ++obj-$(CONFIG_XEN) += evtchn/ ++obj-y += xenbus/ ++obj-$(CONFIG_XEN) += char/ ++ ++obj-$(CONFIG_XEN) += util.o + obj-$(CONFIG_XEN_BALLOON) += balloon/ + obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ + obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ +--- sle11-2009-05-14.orig/drivers/xen/blkback/blkback.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkback/blkback.c 2009-02-16 16:17:21.000000000 +0100 +@@ -154,7 +154,7 @@ static void unplug_queue(blkif_t *blkif) + + static void plug_queue(blkif_t *blkif, struct block_device *bdev) + { +- request_queue_t *q = bdev_get_queue(bdev); ++ struct request_queue *q = bdev_get_queue(bdev); + + if (q == blkif->plug) + return; +--- sle11-2009-05-14.orig/drivers/xen/blkback/common.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkback/common.h 2009-02-16 16:17:21.000000000 +0100 +@@ -79,7 +79,7 @@ typedef struct blkif_st { + wait_queue_head_t wq; + struct task_struct *xenblkd; + unsigned int waiting_reqs; +- request_queue_t *plug; ++ struct request_queue *plug; + + /* statistics */ + unsigned long st_print; +--- sle11-2009-05-14.orig/drivers/xen/blkback/interface.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkback/interface.c 2009-02-16 16:17:21.000000000 +0100 +@@ -177,5 +177,5 @@ void blkif_free(blkif_t *blkif) + void __init blkif_interface_init(void) + { + blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t), +- 0, 0, NULL, NULL); ++ 0, 0, NULL); + } +--- sle11-2009-05-14.orig/drivers/xen/blkfront/blkfront.c 2009-03-24 10:11:24.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkfront/blkfront.c 2009-03-24 10:12:03.000000000 +0100 +@@ -662,7 +662,7 @@ static int blkif_queue_request(struct re + * do_blkif_request + * read a block; request is in a request queue + */ +-void do_blkif_request(request_queue_t *rq) ++void do_blkif_request(struct request_queue *rq) + { + struct blkfront_info *info = NULL; + struct request *req; +--- sle11-2009-05-14.orig/drivers/xen/blkfront/block.h 2009-03-05 15:42:00.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blkfront/block.h 2009-03-24 10:11:58.000000000 +0100 +@@ -106,7 +106,7 @@ struct blkfront_info + struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + unsigned int irq; + struct xlbd_major_info *mi; +- request_queue_t *rq; ++ struct request_queue *rq; + struct work_struct work; + struct gnttab_free_callback callback; + struct blk_shadow shadow[BLK_RING_SIZE]; +@@ -130,7 +130,7 @@ extern int blkif_ioctl(struct inode *ino + extern int blkif_getgeo(struct block_device *, struct hd_geometry *); + extern int blkif_check(dev_t dev); + extern int blkif_revalidate(dev_t dev); +-extern void do_blkif_request (request_queue_t *rq); ++extern void do_blkif_request (struct request_queue *rq); + + /* Virtual block-device subsystem. */ + /* Note that xlvbd_add doesn't call add_disk for you: you're expected +--- sle11-2009-05-14.orig/drivers/xen/blkfront/vbd.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/blkfront/vbd.c 2009-02-16 16:17:21.000000000 +0100 +@@ -211,7 +211,7 @@ xlbd_put_major_info(struct xlbd_major_in + static int + xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) + { +- request_queue_t *rq; ++ struct request_queue *rq; + + rq = blk_init_queue(do_blkif_request, &blkif_io_lock); + if (rq == NULL) +--- sle11-2009-05-14.orig/drivers/xen/blktap/common.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blktap/common.h 2009-02-16 16:17:21.000000000 +0100 +@@ -68,7 +68,7 @@ typedef struct blkif_st { + wait_queue_head_t wq; + struct task_struct *xenblkd; + unsigned int waiting_reqs; +- request_queue_t *plug; ++ struct request_queue *plug; + + /* statistics */ + unsigned long st_print; +--- sle11-2009-05-14.orig/drivers/xen/blktap/interface.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/blktap/interface.c 2009-02-16 16:17:21.000000000 +0100 +@@ -177,5 +177,5 @@ void tap_blkif_kmem_cache_free(blkif_t * + void __init tap_blkif_interface_init(void) + { + blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t), +- 0, 0, NULL, NULL); ++ 0, 0, NULL); + } +--- sle11-2009-05-14.orig/drivers/xen/core/features.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/core/features.c 2009-02-16 16:17:21.000000000 +0100 +@@ -19,7 +19,7 @@ u8 xen_features[XENFEAT_NR_SUBMAPS * 32] + /* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */ + EXPORT_SYMBOL(xen_features); + +-void setup_xen_features(void) ++void xen_setup_features(void) + { + xen_feature_info_t fi; + int i, j; +--- sle11-2009-05-14.orig/drivers/xen/core/reboot.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/core/reboot.c 2009-02-16 16:17:21.000000000 +0100 +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + #include + #include + #include +--- sle11-2009-05-14.orig/drivers/xen/scsiback/interface.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/scsiback/interface.c 2009-02-16 16:17:21.000000000 +0100 +@@ -167,7 +167,7 @@ void scsiback_free(struct vscsibk_info * + int __init scsiback_interface_init(void) + { + scsiback_cachep = kmem_cache_create("vscsiif_cache", +- sizeof(struct vscsibk_info), 0, 0, NULL, NULL); ++ sizeof(struct vscsibk_info), 0, 0, NULL); + if (!scsiback_cachep) { + printk(KERN_ERR "scsiback: can't init scsi cache\n"); + return -ENOMEM; +--- sle11-2009-05-14.orig/drivers/xen/scsifront/scsifront.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/scsifront/scsifront.c 2009-02-16 16:17:21.000000000 +0100 +@@ -147,7 +147,7 @@ static void scsifront_cdb_cmd_done(struc + add_id_to_freelist(info, id); + + sc->result = ring_res->rslt; +- sc->resid = ring_res->residual_len; ++ scsi_set_resid(sc, ring_res->residual_len); + + if (ring_res->sense_len > VSCSIIF_SENSE_BUFFERSIZE) + sense_len = VSCSIIF_SENSE_BUFFERSIZE; +--- sle11-2009-05-14.orig/drivers/xen/tpmback/interface.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/tpmback/interface.c 2009-02-16 16:17:21.000000000 +0100 +@@ -12,6 +12,7 @@ + */ + + #include "common.h" ++#include + #include + #include + +@@ -159,7 +160,7 @@ void tpmif_disconnect_complete(tpmif_t * + int __init tpmif_interface_init(void) + { + tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t), +- 0, 0, NULL, NULL); ++ 0, 0, NULL); + return tpmif_cachep ? 0 : -ENOMEM; + } + +--- sle11-2009-05-14.orig/drivers/xen/util.c 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/drivers/xen/util.c 2009-02-16 16:17:21.000000000 +0100 +@@ -1,8 +1,5 @@ +-#include ++#include + #include +-#include +-#include +-#include + #include + + struct class *get_xen_class(void) +@@ -21,45 +18,3 @@ struct class *get_xen_class(void) + return xen_class; + } + EXPORT_SYMBOL_GPL(get_xen_class); +- +-#ifdef CONFIG_X86 +-static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data) +-{ +- /* apply_to_page_range() does all the hard work. */ +- return 0; +-} +- +-struct vm_struct *alloc_vm_area(unsigned long size) +-{ +- struct vm_struct *area; +- +- area = get_vm_area(size, VM_IOREMAP); +- if (area == NULL) +- return NULL; +- +- /* +- * This ensures that page tables are constructed for this region +- * of kernel virtual address space and mapped into init_mm. +- */ +- if (apply_to_page_range(&init_mm, (unsigned long)area->addr, +- area->size, f, NULL)) { +- free_vm_area(area); +- return NULL; +- } +- +- /* Map page directories into every address space. */ +- vmalloc_sync_all(); +- +- return area; +-} +-EXPORT_SYMBOL_GPL(alloc_vm_area); +- +-void free_vm_area(struct vm_struct *area) +-{ +- struct vm_struct *ret; +- ret = remove_vm_area(area->addr); +- BUG_ON(ret != area); +- kfree(area); +-} +-EXPORT_SYMBOL_GPL(free_vm_area); +-#endif /* CONFIG_X86 */ +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_client.c 2009-03-17 15:27:31.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_client.c 2009-03-24 10:12:22.000000000 +0100 +@@ -30,19 +30,26 @@ + * IN THE SOFTWARE. + */ + ++#if defined(CONFIG_XEN) || defined(MODULE) + #include + #include + #include +-#include + #include ++#else ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++#include + + #ifdef HAVE_XEN_PLATFORM_COMPAT_H + #include + #endif + +-#define DPRINTK(fmt, args...) \ +- pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) +- + const char *xenbus_strstate(enum xenbus_state state) + { + static const char *const name[] = { +@@ -60,6 +67,20 @@ const char *xenbus_strstate(enum xenbus_ + } + EXPORT_SYMBOL_GPL(xenbus_strstate); + ++/** ++ * xenbus_watch_path - register a watch ++ * @dev: xenbus device ++ * @path: path to watch ++ * @watch: watch to register ++ * @callback: callback to register ++ * ++ * Register a @watch on the given path, using the given xenbus_watch structure ++ * for storage, and the given @callback function as the callback. Return 0 on ++ * success, or -errno on error. On success, the given @path will be saved as ++ * @watch->node, and remains the caller's to free. On error, @watch->node will ++ * be NULL, the device will switch to %XenbusStateClosing, and the error will ++ * be saved in the store. ++ */ + int xenbus_watch_path(struct xenbus_device *dev, const char *path, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, +@@ -83,6 +104,7 @@ int xenbus_watch_path(struct xenbus_devi + EXPORT_SYMBOL_GPL(xenbus_watch_path); + + ++#if defined(CONFIG_XEN) || defined(MODULE) + int xenbus_watch_path2(struct xenbus_device *dev, const char *path, + const char *path2, struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, +@@ -101,8 +123,60 @@ int xenbus_watch_path2(struct xenbus_dev + return err; + } + EXPORT_SYMBOL_GPL(xenbus_watch_path2); ++#else ++/** ++ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path ++ * @dev: xenbus device ++ * @watch: watch to register ++ * @callback: callback to register ++ * @pathfmt: format of path to watch ++ * ++ * Register a watch on the given @path, using the given xenbus_watch ++ * structure for storage, and the given @callback function as the callback. ++ * Return 0 on success, or -errno on error. On success, the watched path ++ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to ++ * kfree(). On error, watch->node will be NULL, so the caller has nothing to ++ * free, the device will switch to %XenbusStateClosing, and the error will be ++ * saved in the store. ++ */ ++int xenbus_watch_pathfmt(struct xenbus_device *dev, ++ struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int), ++ const char *pathfmt, ...) ++{ ++ int err; ++ va_list ap; ++ char *path; + ++ va_start(ap, pathfmt); ++ path = kvasprintf(GFP_KERNEL, pathfmt, ap); ++ va_end(ap); + ++ if (!path) { ++ xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); ++ return -ENOMEM; ++ } ++ err = xenbus_watch_path(dev, path, watch, callback); ++ ++ if (err) ++ kfree(path); ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt); ++#endif ++ ++ ++/** ++ * xenbus_switch_state ++ * @dev: xenbus device ++ * @xbt: transaction handle ++ * @state: new state ++ * ++ * Advertise in the store a change of the given driver to the given new_state. ++ * Return 0 on success, or -errno on error. On error, the device will switch ++ * to XenbusStateClosing, and the error will be saved in the store. ++ */ + int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state) + { + /* We check whether the state is currently set to the given value, and +@@ -161,8 +235,8 @@ static char *error_path(struct xenbus_de + } + + +-void _dev_error(struct xenbus_device *dev, int err, const char *fmt, +- va_list ap) ++static void _dev_error(struct xenbus_device *dev, int err, ++ const char *fmt, va_list ap) + { + int ret; + unsigned int len; +@@ -183,14 +257,16 @@ void _dev_error(struct xenbus_device *de + path_buffer = error_path(dev); + + if (path_buffer == NULL) { +- printk("xenbus: failed to write error node for %s (%s)\n", +- dev->nodename, printf_buffer); ++ dev_err(&dev->dev, ++ "xenbus: failed to write error node for %s (%s)\n", ++ dev->nodename, printf_buffer); + goto fail; + } + + if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { +- printk("xenbus: failed to write error node for %s (%s)\n", +- dev->nodename, printf_buffer); ++ dev_err(&dev->dev, ++ "xenbus: failed to write error node for %s (%s)\n", ++ dev->nodename, printf_buffer); + goto fail; + } + +@@ -202,6 +278,15 @@ fail: + } + + ++/** ++ * xenbus_dev_error ++ * @dev: xenbus device ++ * @err: error to report ++ * @fmt: error message format ++ * ++ * Report the given negative errno into the store, along with the given ++ * formatted message. ++ */ + void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, + ...) + { +@@ -214,6 +299,16 @@ void xenbus_dev_error(struct xenbus_devi + EXPORT_SYMBOL_GPL(xenbus_dev_error); + + ++/** ++ * xenbus_dev_fatal ++ * @dev: xenbus device ++ * @err: error to report ++ * @fmt: error message format ++ * ++ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by ++ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly ++ * closedown of this driver and its peer. ++ */ + void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, + ...) + { +@@ -228,6 +323,15 @@ void xenbus_dev_fatal(struct xenbus_devi + EXPORT_SYMBOL_GPL(xenbus_dev_fatal); + + ++/** ++ * xenbus_grant_ring ++ * @dev: xenbus device ++ * @ring_mfn: mfn of ring to grant ++ * ++ * Grant access to the given @ring_mfn to the peer of the given device. Return ++ * 0 on success, or -errno on error. On error, the device will switch to ++ * XenbusStateClosing, and the error will be saved in the store. ++ */ + int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) + { + int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); +@@ -238,6 +342,12 @@ int xenbus_grant_ring(struct xenbus_devi + EXPORT_SYMBOL_GPL(xenbus_grant_ring); + + ++/** ++ * Allocate an event channel for the given xenbus_device, assigning the newly ++ * created local port to *port. Return 0 on success, or -errno on error. On ++ * error, the device will switch to XenbusStateClosing, and the error will be ++ * saved in the store. ++ */ + int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) + { + struct evtchn_alloc_unbound alloc_unbound; +@@ -258,6 +368,38 @@ int xenbus_alloc_evtchn(struct xenbus_de + EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn); + + ++#if 0 /* !defined(CONFIG_XEN) && !defined(MODULE) */ ++/** ++ * Bind to an existing interdomain event channel in another domain. Returns 0 ++ * on success and stores the local port in *port. On error, returns -errno, ++ * switches the device to XenbusStateClosing, and saves the error in XenStore. ++ */ ++int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port) ++{ ++ struct evtchn_bind_interdomain bind_interdomain; ++ int err; ++ ++ bind_interdomain.remote_dom = dev->otherend_id; ++ bind_interdomain.remote_port = remote_port; ++ ++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, ++ &bind_interdomain); ++ if (err) ++ xenbus_dev_fatal(dev, err, ++ "binding to event channel %d from domain %d", ++ remote_port, dev->otherend_id); ++ else ++ *port = bind_interdomain.local_port; ++ ++ return err; ++} ++EXPORT_SYMBOL_GPL(xenbus_bind_evtchn); ++#endif ++ ++ ++/** ++ * Free an existing event channel. Returns 0 on success or -errno on error. ++ */ + int xenbus_free_evtchn(struct xenbus_device *dev, int port) + { + struct evtchn_close close; +@@ -274,6 +416,191 @@ int xenbus_free_evtchn(struct xenbus_dev + EXPORT_SYMBOL_GPL(xenbus_free_evtchn); + + ++#if 0 /* !defined(CONFIG_XEN) && !defined(MODULE) */ ++/** ++ * xenbus_map_ring_valloc ++ * @dev: xenbus device ++ * @gnt_ref: grant reference ++ * @vaddr: pointer to address to be filled out by mapping ++ * ++ * Based on Rusty Russell's skeleton driver's map_page. ++ * Map a page of memory into this domain from another domain's grant table. ++ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the ++ * page to that address, and sets *vaddr to that address. ++ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) ++ * or -ENOMEM on error. If an error is returned, device will switch to ++ * XenbusStateClosing and the error message will be saved in XenStore. ++ */ ++int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) ++{ ++ struct gnttab_map_grant_ref op = { ++ .flags = GNTMAP_host_map, ++ .ref = gnt_ref, ++ .dom = dev->otherend_id, ++ }; ++ struct vm_struct *area; ++ ++ *vaddr = NULL; ++ ++ area = alloc_vm_area(PAGE_SIZE); ++ if (!area) ++ return -ENOMEM; ++ ++ op.host_addr = (unsigned long)area->addr; ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status != GNTST_okay) { ++ free_vm_area(area); ++ xenbus_dev_fatal(dev, op.status, ++ "mapping in shared page %d from domain %d", ++ gnt_ref, dev->otherend_id); ++ return op.status; ++ } ++ ++ /* Stuff the handle in an unused field */ ++ area->phys_addr = (unsigned long)op.handle; ++ ++ *vaddr = area->addr; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); ++ ++ ++/** ++ * xenbus_map_ring ++ * @dev: xenbus device ++ * @gnt_ref: grant reference ++ * @handle: pointer to grant handle to be filled ++ * @vaddr: address to be mapped to ++ * ++ * Map a page of memory into this domain from another domain's grant table. ++ * xenbus_map_ring does not allocate the virtual address space (you must do ++ * this yourself!). It only maps in the page to the specified address. ++ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) ++ * or -ENOMEM on error. If an error is returned, device will switch to ++ * XenbusStateClosing and the error message will be saved in XenStore. ++ */ ++int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, ++ grant_handle_t *handle, void *vaddr) ++{ ++ struct gnttab_map_grant_ref op = { ++ .host_addr = (unsigned long)vaddr, ++ .flags = GNTMAP_host_map, ++ .ref = gnt_ref, ++ .dom = dev->otherend_id, ++ }; ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status != GNTST_okay) { ++ xenbus_dev_fatal(dev, op.status, ++ "mapping in shared page %d from domain %d", ++ gnt_ref, dev->otherend_id); ++ } else ++ *handle = op.handle; ++ ++ return op.status; ++} ++EXPORT_SYMBOL_GPL(xenbus_map_ring); ++ ++ ++/** ++ * xenbus_unmap_ring_vfree ++ * @dev: xenbus device ++ * @vaddr: addr to unmap ++ * ++ * Based on Rusty Russell's skeleton driver's unmap_page. ++ * Unmap a page of memory in this domain that was imported from another domain. ++ * Use xenbus_unmap_ring_vfree if you mapped in your memory with ++ * xenbus_map_ring_valloc (it will free the virtual address space). ++ * Returns 0 on success and returns GNTST_* on error ++ * (see xen/include/interface/grant_table.h). ++ */ ++int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) ++{ ++ struct vm_struct *area; ++ struct gnttab_unmap_grant_ref op = { ++ .host_addr = (unsigned long)vaddr, ++ }; ++ ++ /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) ++ * method so that we don't have to muck with vmalloc internals here. ++ * We could force the user to hang on to their struct vm_struct from ++ * xenbus_map_ring_valloc, but these 6 lines considerably simplify ++ * this API. ++ */ ++ read_lock(&vmlist_lock); ++ for (area = vmlist; area != NULL; area = area->next) { ++ if (area->addr == vaddr) ++ break; ++ } ++ read_unlock(&vmlist_lock); ++ ++ if (!area) { ++ xenbus_dev_error(dev, -ENOENT, ++ "can't find mapped virtual address %p", vaddr); ++ return GNTST_bad_virt_addr; ++ } ++ ++ op.handle = (grant_handle_t)area->phys_addr; ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status == GNTST_okay) ++ free_vm_area(area); ++ else ++ xenbus_dev_error(dev, op.status, ++ "unmapping page at handle %d error %d", ++ (int16_t)area->phys_addr, op.status); ++ ++ return op.status; ++} ++EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); ++ ++ ++/** ++ * xenbus_unmap_ring ++ * @dev: xenbus device ++ * @handle: grant handle ++ * @vaddr: addr to unmap ++ * ++ * Unmap a page of memory in this domain that was imported from another domain. ++ * Returns 0 on success and returns GNTST_* on error ++ * (see xen/include/interface/grant_table.h). ++ */ ++int xenbus_unmap_ring(struct xenbus_device *dev, ++ grant_handle_t handle, void *vaddr) ++{ ++ struct gnttab_unmap_grant_ref op = { ++ .host_addr = (unsigned long)vaddr, ++ .handle = handle, ++ }; ++ ++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) ++ BUG(); ++ ++ if (op.status != GNTST_okay) ++ xenbus_dev_error(dev, op.status, ++ "unmapping page at handle %d error %d", ++ handle, op.status); ++ ++ return op.status; ++} ++EXPORT_SYMBOL_GPL(xenbus_unmap_ring); ++#endif ++ ++ ++/** ++ * xenbus_read_driver_state ++ * @path: path for driver ++ * ++ * Return the state of the driver rooted at the given store path, or ++ * XenbusStateUnknown if no state can be read. ++ */ + enum xenbus_state xenbus_read_driver_state(const char *path) + { + enum xenbus_state result; +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_comms.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_comms.c 2009-02-16 16:17:21.000000000 +0100 +@@ -34,12 +34,15 @@ + #include + #include + #include +-#include +-#include +-#include + #include +- ++#if defined(CONFIG_XEN) || defined(MODULE) ++#include + #include ++#else ++#include ++#include ++#include ++#endif + + #include "xenbus_comms.h" + +@@ -91,6 +94,13 @@ static const void *get_input_chunk(XENST + return buf + MASK_XENSTORE_IDX(cons); + } + ++/** ++ * xb_write - low level write ++ * @data: buffer to send ++ * @len: length of buffer ++ * ++ * Returns 0 on success, error otherwise. ++ */ + int xb_write(const void *data, unsigned len) + { + struct xenstore_domain_interface *intf = xen_store_interface; +@@ -199,7 +209,9 @@ int xb_read(void *data, unsigned len) + return 0; + } + +-/* Set up interrupt handler off store event channel. */ ++/** ++ * xb_init_comms - Set up interrupt handler off store event channel. ++ */ + int xb_init_comms(void) + { + struct xenstore_domain_interface *intf = xen_store_interface; +@@ -219,7 +231,11 @@ int xb_init_comms(void) + if (xenbus_irq) + unbind_from_irqhandler(xenbus_irq, &xb_waitq); + ++#if defined(CONFIG_XEN) || defined(MODULE) + err = bind_caller_port_to_irqhandler( ++#else ++ err = bind_evtchn_to_irqhandler( ++#endif + xen_store_evtchn, wake_waiting, + 0, "xenbus", &xb_waitq); + if (err <= 0) { +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_probe.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_probe.c 2009-02-16 16:17:21.000000000 +0100 +@@ -43,12 +43,11 @@ + #include + #include + #include +-#include ++#include + +-#include + #include +-#include + #include ++#if defined(CONFIG_XEN) || defined(MODULE) + #include + #include + #include +@@ -57,6 +56,12 @@ + #ifdef MODULE + #include + #endif ++#else ++#include ++#include ++#include ++#include ++#endif + + #include "xenbus_comms.h" + #include "xenbus_probe.h" +@@ -168,7 +173,7 @@ static int read_backend_details(struct x + return read_otherend_details(xendev, "backend-id", "backend"); + } + +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) && (defined(CONFIG_XEN) || defined(MODULE)) + static int xenbus_uevent_frontend(struct device *dev, char **envp, + int num_envp, char *buffer, int buffer_size) + { +@@ -207,12 +212,16 @@ static struct xen_bus_type xenbus_fronte + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, ++#if defined(CONFIG_XEN) || defined(MODULE) + .uevent = xenbus_uevent_frontend, + #endif ++#endif + }, ++#if defined(CONFIG_XEN) || defined(MODULE) + .dev = { + .bus_id = "xen", + }, ++#endif + }; + + static void otherend_changed(struct xenbus_watch *watch, +@@ -228,14 +237,15 @@ static void otherend_changed(struct xenb + if (!dev->otherend || + strncmp(dev->otherend, vec[XS_WATCH_PATH], + strlen(dev->otherend))) { +- DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); ++ dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]); + return; + } + + state = xenbus_read_driver_state(dev->otherend); + +- DPRINTK("state is %d (%s), %s, %s", state, xenbus_strstate(state), +- dev->otherend_watch.node, vec[XS_WATCH_PATH]); ++ dev_dbg(&dev->dev, "state is %d (%s), %s, %s", ++ state, xenbus_strstate(state), dev->otherend_watch.node, ++ vec[XS_WATCH_PATH]); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) + /* +@@ -271,8 +281,13 @@ static int talk_to_otherend(struct xenbu + + static int watch_otherend(struct xenbus_device *dev) + { ++#if defined(CONFIG_XEN) || defined(MODULE) + return xenbus_watch_path2(dev, dev->otherend, "state", + &dev->otherend_watch, otherend_changed); ++#else ++ return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed, ++ "%s/%s", dev->otherend, "state"); ++#endif + } + + +@@ -298,9 +313,9 @@ int xenbus_dev_probe(struct device *_dev + + err = talk_to_otherend(dev); + if (err) { +- printk(KERN_WARNING +- "xenbus_probe: talk_to_otherend on %s failed.\n", +- dev->nodename); ++ dev_warn(&dev->dev, ++ "xenbus_probe: talk_to_otherend on %s failed.\n", ++ dev->nodename); + return err; + } + +@@ -310,9 +325,9 @@ int xenbus_dev_probe(struct device *_dev + + err = watch_otherend(dev); + if (err) { +- printk(KERN_WARNING +- "xenbus_probe: watch_otherend on %s failed.\n", +- dev->nodename); ++ dev_warn(&dev->dev, ++ "xenbus_probe: watch_otherend on %s failed.\n", ++ dev->nodename); + return err; + } + +@@ -352,14 +367,15 @@ static void xenbus_dev_shutdown(struct d + + get_device(&dev->dev); + if (dev->state != XenbusStateConnected) { +- printk("%s: %s: %s != Connected, skipping\n", __FUNCTION__, +- dev->nodename, xenbus_strstate(dev->state)); ++ dev_info(&dev->dev, "%s: %s: %s != Connected, skipping\n", __FUNCTION__, ++ dev->nodename, xenbus_strstate(dev->state)); + goto out; + } + xenbus_switch_state(dev, XenbusStateClosing); + timeout = wait_for_completion_timeout(&dev->down, timeout); + if (!timeout) +- printk("%s: %s timeout closing device\n", __FUNCTION__, dev->nodename); ++ dev_info(&dev->dev, "%s: %s timeout closing device\n", ++ __FUNCTION__, dev->nodename); + out: + put_device(&dev->dev); + } +@@ -547,7 +563,9 @@ int xenbus_probe_node(struct xen_bus_typ + xendev->devicetype = tmpstring; + init_completion(&xendev->down); + ++#if defined(CONFIG_XEN) || defined(MODULE) + xendev->dev.parent = &bus->dev; ++#endif + xendev->dev.bus = &bus->bus; + xendev->dev.release = xenbus_dev_release; + +@@ -562,15 +580,16 @@ int xenbus_probe_node(struct xen_bus_typ + + err = device_create_file(&xendev->dev, &dev_attr_nodename); + if (err) +- goto unregister; ++ goto fail_unregister; ++ + err = device_create_file(&xendev->dev, &dev_attr_devtype); + if (err) +- goto unregister; ++ goto fail_remove_file; + + return 0; +-unregister: ++fail_remove_file: + device_remove_file(&xendev->dev, &dev_attr_nodename); +- device_remove_file(&xendev->dev, &dev_attr_devtype); ++fail_unregister: + device_unregister(&xendev->dev); + fail: + kfree(xendev); +@@ -583,7 +602,8 @@ static int xenbus_probe_frontend(const c + char *nodename; + int err; + +- nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_frontend.root, type, name); ++ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", ++ xenbus_frontend.root, type, name); + if (!nodename) + return -ENOMEM; + +@@ -659,7 +679,7 @@ static int strsep_len(const char *str, c + return (len == 0) ? i : -ERANGE; + } + +-void dev_changed(const char *node, struct xen_bus_type *bus) ++void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) + { + int exists, rootlen; + struct xenbus_device *dev; +@@ -667,7 +687,7 @@ void dev_changed(const char *node, struc + const char *p, *root; + + if (bus->error || char_count(node, '/') < 2) +- return; ++ return; + + exists = xenbus_exists(XBT_NIL, node, ""); + if (!exists) { +@@ -701,7 +721,7 @@ static void frontend_changed(struct xenb + { + DPRINTK(""); + +- dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); ++ xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); + } + + /* We watch for devices appearing and vanishing. */ +@@ -904,10 +924,16 @@ static int xsd_port_read(char *page, cha + } + #endif + +-static int xenbus_probe_init(void) ++#ifndef MODULE ++static int __init xenbus_probe_init(void) ++#else ++static int __devinit xenbus_probe_init(void) ++#endif + { + int err = 0; ++#if defined(CONFIG_XEN) || defined(MODULE) + unsigned long page = 0; ++#endif + + DPRINTK(""); + +@@ -926,6 +952,7 @@ static int xenbus_probe_init(void) + * Domain0 doesn't have a store_evtchn or store_mfn yet. + */ + if (is_initial_xendomain()) { ++#if defined(CONFIG_XEN) || defined(MODULE) + struct evtchn_alloc_unbound alloc_unbound; + + /* Allocate page. */ +@@ -963,10 +990,13 @@ static int xenbus_probe_init(void) + if (xsd_port_intf) + xsd_port_intf->read_proc = xsd_port_read; + #endif ++#else ++ /* dom0 not yet supported */ ++#endif + xen_store_interface = mfn_to_virt(xen_store_mfn); + } else { + xenstored_ready = 1; +-#ifdef CONFIG_XEN ++#ifndef MODULE + xen_store_evtchn = xen_start_info->store_evtchn; + xen_store_mfn = xen_start_info->store_mfn; + xen_store_interface = mfn_to_virt(xen_store_mfn); +@@ -979,7 +1009,9 @@ static int xenbus_probe_init(void) + } + + ++#if defined(CONFIG_XEN) || defined(MODULE) + xenbus_dev_init(); ++#endif + + /* Initialize the interface to xenstore. */ + err = xs_init(); +@@ -989,6 +1021,7 @@ static int xenbus_probe_init(void) + goto err; + } + ++#if defined(CONFIG_XEN) || defined(MODULE) + /* Register ourselves with the kernel device subsystem */ + if (!xenbus_frontend.error) { + xenbus_frontend.error = device_register(&xenbus_frontend.dev); +@@ -999,6 +1032,7 @@ static int xenbus_probe_init(void) + xenbus_frontend.error); + } + } ++#endif + xenbus_backend_device_register(); + + if (!is_initial_xendomain()) +@@ -1007,8 +1041,10 @@ static int xenbus_probe_init(void) + return 0; + + err: ++#if defined(CONFIG_XEN) || defined(MODULE) + if (page) + free_page(page); ++#endif + + /* + * Do not unregister the xenbus front/backend buses here. The buses +@@ -1019,11 +1055,15 @@ static int xenbus_probe_init(void) + return err; + } + +-#ifdef CONFIG_XEN ++#ifndef MODULE + postcore_initcall(xenbus_probe_init); ++#ifdef CONFIG_XEN + MODULE_LICENSE("Dual BSD/GPL"); + #else +-int xenbus_init(void) ++MODULE_LICENSE("GPL"); ++#endif ++#else ++int __devinit xenbus_init(void) + { + return xenbus_probe_init(); + } +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_probe.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_probe.h 2009-02-16 16:17:21.000000000 +0100 +@@ -56,7 +56,9 @@ struct xen_bus_type + int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); + int (*probe)(const char *type, const char *dir); + struct bus_type bus; ++#if defined(CONFIG_XEN) || defined(MODULE) + struct device dev; ++#endif + }; + + extern int xenbus_match(struct device *_dev, struct device_driver *_drv); +@@ -71,7 +73,7 @@ extern int xenbus_probe_node(struct xen_ + const char *nodename); + extern int xenbus_probe_devices(struct xen_bus_type *bus); + +-extern void dev_changed(const char *node, struct xen_bus_type *bus); ++extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); + + #endif + +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_probe_backend.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_probe_backend.c 2009-02-16 16:17:21.000000000 +0100 +@@ -236,7 +236,7 @@ static void backend_changed(struct xenbu + { + DPRINTK(""); + +- dev_changed(vec[XS_WATCH_PATH], &xenbus_backend); ++ xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend); + } + + static struct xenbus_watch be_watch = { +--- sle11-2009-05-14.orig/drivers/xen/xenbus/xenbus_xs.c 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/drivers/xen/xenbus/xenbus_xs.c 2009-02-16 16:17:21.000000000 +0100 +@@ -221,7 +221,7 @@ static void *xs_talkv(struct xenbus_tran + } + + for (i = 0; i < num_vecs; i++) { +- err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; ++ err = xb_write(iovec[i].iov_base, iovec[i].iov_len); + if (err) { + mutex_unlock(&xs_state.request_mutex); + return ERR_PTR(err); +@@ -630,7 +630,9 @@ void unregister_xenbus_watch(struct xenb + char token[sizeof(watch) * 2 + 1]; + int err; + ++#if defined(CONFIG_XEN) || defined(MODULE) + BUG_ON(watch->flags & XBWF_new_thread); ++#endif + + sprintf(token, "%lX", (long)watch); + +@@ -649,6 +651,11 @@ void unregister_xenbus_watch(struct xenb + + up_read(&xs_state.watch_mutex); + ++ /* Make sure there are no callbacks running currently (unless ++ its us) */ ++ if (current->pid != xenwatch_pid) ++ mutex_lock(&xenwatch_mutex); ++ + /* Cancel pending watch events. */ + spin_lock(&watch_events_lock); + list_for_each_entry_safe(msg, tmp, &watch_events, list) { +@@ -660,11 +667,8 @@ void unregister_xenbus_watch(struct xenb + } + spin_unlock(&watch_events_lock); + +- /* Flush any currently-executing callback, unless we are it. :-) */ +- if (current->pid != xenwatch_pid) { +- mutex_lock(&xenwatch_mutex); ++ if (current->pid != xenwatch_pid) + mutex_unlock(&xenwatch_mutex); +- } + } + EXPORT_SYMBOL_GPL(unregister_xenbus_watch); + +@@ -702,6 +706,7 @@ void xs_suspend_cancel(void) + up_write(&xs_state.transaction_mutex); + } + ++#if defined(CONFIG_XEN) || defined(MODULE) + static int xenwatch_handle_callback(void *data) + { + struct xs_stored_msg *msg = data; +@@ -719,6 +724,7 @@ static int xenwatch_handle_callback(void + + return 0; + } ++#endif + + static int xenwatch_thread(void *unused) + { +@@ -748,6 +754,7 @@ static int xenwatch_thread(void *unused) + + msg = list_entry(ent, struct xs_stored_msg, list); + ++#if defined(CONFIG_XEN) || defined(MODULE) + /* + * Unlock the mutex before running an XBWF_new_thread + * handler. kthread_run can block which can deadlock +@@ -764,6 +771,15 @@ static int xenwatch_thread(void *unused) + xenwatch_handle_callback(msg); + mutex_unlock(&xenwatch_mutex); + } ++#else ++ msg->u.watch.handle->callback( ++ msg->u.watch.handle, ++ (const char **)msg->u.watch.vec, ++ msg->u.watch.vec_size); ++ mutex_unlock(&xenwatch_mutex); ++ kfree(msg->u.watch.vec); ++ kfree(msg); ++#endif + } + + return 0; +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/fixmap_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/fixmap_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -53,6 +53,8 @@ extern unsigned long __FIXADDR_TOP; + enum fixed_addresses { + FIX_HOLE, + FIX_VDSO, ++ FIX_DBGP_BASE, ++ FIX_EARLYCON_MEM_BASE, + #ifdef CONFIG_X86_LOCAL_APIC + FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ + #endif +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/highmem.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/highmem.h 2009-02-16 16:17:21.000000000 +0100 +@@ -76,8 +76,7 @@ struct page *kmap_atomic_to_page(void *p + + #define kmap_atomic_pte(page, type) \ + kmap_atomic_prot(page, type, \ +- test_bit(PG_pinned, &(page)->flags) \ +- ? PAGE_KERNEL_RO : kmap_prot) ++ PagePinned(page) ? PAGE_KERNEL_RO : kmap_prot) + + #define flush_cache_kmaps() do { } while (0) + +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/maddr_32.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/maddr_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -155,6 +155,7 @@ static inline paddr_t pte_machine_to_phy + + #ifdef CONFIG_X86_PAE + #define __pte_ma(x) ((pte_t) { (x), (maddr_t)(x) >> 32 } ) ++extern unsigned long long __supported_pte_mask; + static inline pte_t pfn_pte_ma(unsigned long page_nr, pgprot_t pgprot) + { + pte_t pte; +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/mmu_context_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/mmu_context_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -16,7 +16,7 @@ void mm_pin_all(void); + static inline void xen_activate_mm(struct mm_struct *prev, + struct mm_struct *next) + { +- if (!test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)) ++ if (!PagePinned(virt_to_page(next->pgd))) + mm_pin(next); + } + +@@ -51,6 +51,8 @@ static inline void __prepare_arch_switch + : : "r" (0) ); + } + ++void leave_mm(unsigned long cpu); ++ + static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) +@@ -60,7 +62,7 @@ static inline void switch_mm(struct mm_s + + if (likely(prev != next)) { + BUG_ON(!xen_feature(XENFEAT_writable_page_tables) && +- !test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)); ++ !PagePinned(virt_to_page(next->pgd))); + + /* stop flush ipis for the previous mm */ + cpu_clear(cpu, prev->cpu_vm_mask); +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pci_32.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pci_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -3,6 +3,14 @@ + + + #ifdef __KERNEL__ ++ ++struct pci_sysdata { ++ int node; /* NUMA node */ ++}; ++ ++/* scan a bus after allocating a pci_sysdata for it */ ++extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); ++ + #include /* for struct page */ + + /* Can be used to override the logic in pci_scan_bus for skipping +@@ -81,48 +89,11 @@ struct pci_dev; + + #endif + +-/* This is always fine. */ +-#define pci_dac_dma_supported(pci_dev, mask) (1) +- +-static inline dma64_addr_t +-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) +-{ +- return ((dma64_addr_t) page_to_phys(page) + +- (dma64_addr_t) offset); +-} +- +-static inline struct page * +-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) +-{ +- return pfn_to_page(dma_addr >> PAGE_SHIFT); +-} +- +-static inline unsigned long +-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) +-{ +- return (dma_addr & ~PAGE_MASK); +-} +- +-static inline void +-pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +-{ +-} +- +-static inline void +-pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +-{ +- flush_write_buffers(); +-} +- + #define HAVE_PCI_MMAP + extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); + + +-static inline void pcibios_add_platform_entries(struct pci_dev *dev) +-{ +-} +- + #ifdef CONFIG_PCI + static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgalloc_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgalloc_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -5,7 +5,7 @@ + #include /* for struct page */ + #include /* for phys_to_virt and page_to_pseudophys */ + +-#define paravirt_alloc_pt(pfn) do { } while (0) ++#define paravirt_alloc_pt(mm, pfn) do { } while (0) + #define paravirt_alloc_pd(pfn) do { } while (0) + #define paravirt_alloc_pd(pfn) do { } while (0) + #define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0) +@@ -14,15 +14,15 @@ + + #define pmd_populate_kernel(mm, pmd, pte) \ + do { \ +- paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT); \ ++ paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT); \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \ + } while (0) + + #define pmd_populate(mm, pmd, pte) \ + do { \ + unsigned long pfn = page_to_pfn(pte); \ +- paravirt_alloc_pt(pfn); \ +- if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) { \ ++ paravirt_alloc_pt(mm, pfn); \ ++ if (PagePinned(virt_to_page((mm)->pgd))) { \ + if (!PageHighMem(pte)) \ + BUG_ON(HYPERVISOR_update_va_mapping( \ + (unsigned long)__va(pfn << PAGE_SHIFT), \ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -26,9 +26,6 @@ + #include + #include + +-/* Is this pagetable pinned? */ +-#define PG_pinned PG_arch_1 +- + struct vm_area_struct; + + /* +@@ -82,7 +79,7 @@ void paging_init(void); + * area for the same reason. ;) + */ + #define VMALLOC_OFFSET (8*1024*1024) +-#define VMALLOC_START (((unsigned long) high_memory + vmalloc_earlyreserve + \ ++#define VMALLOC_START (((unsigned long) high_memory + \ + 2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1)) + #ifdef CONFIG_HIGHMEM + # define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) +@@ -231,8 +228,6 @@ extern unsigned long pg0[]; + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +-static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; } +-static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; } + static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; } + static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; } + static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; } +@@ -243,13 +238,9 @@ static inline int pte_huge(pte_t pte) { + */ + static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; } + +-static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; } +-static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; } + static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; } + static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; } + static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; } +-static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; } +-static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; } + static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; } + static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; } + static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; } +@@ -295,22 +286,20 @@ static inline pte_t xen_local_ptep_get_a + #define ptep_set_access_flags(vma, address, ptep, entry, dirty) \ + ({ \ + int __changed = !pte_same(*(ptep), entry); \ +- if (__changed && (dirty)) \ +- ptep_establish(vma, address, ptep, entry); \ ++ if (__changed && (dirty)) { \ ++ if ( likely((vma)->vm_mm == current->mm) ) { \ ++ BUG_ON(HYPERVISOR_update_va_mapping(address, \ ++ entry, \ ++ (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ ++ UVMF_INVLPG|UVMF_MULTI)); \ ++ } else { \ ++ xen_l1_entry_update(ptep, entry); \ ++ flush_tlb_page(vma, address); \ ++ } \ ++ } \ + __changed; \ + }) + +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY +-#define ptep_test_and_clear_dirty(vma, addr, ptep) ({ \ +- int __ret = 0; \ +- if (pte_dirty(*(ptep))) \ +- __ret = test_and_clear_bit(_PAGE_BIT_DIRTY, \ +- &(ptep)->pte_low); \ +- if (__ret) \ +- pte_update((vma)->vm_mm, addr, ptep); \ +- __ret; \ +-}) +- + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG + #define ptep_test_and_clear_young(vma, addr, ptep) ({ \ + int __ret = 0; \ +@@ -322,44 +311,13 @@ static inline pte_t xen_local_ptep_get_a + __ret; \ + }) + +-/* +- * Rules for using ptep_establish: the pte MUST be a user pte, and +- * must be a present->present transition. +- */ +-#define __HAVE_ARCH_PTEP_ESTABLISH +-#define ptep_establish(vma, address, ptep, pteval) \ +-do { \ +- if ( likely((vma)->vm_mm == current->mm) ) { \ +- BUG_ON(HYPERVISOR_update_va_mapping(address, \ +- pteval, \ +- (unsigned long)(vma)->vm_mm->cpu_vm_mask.bits| \ +- UVMF_INVLPG|UVMF_MULTI)); \ +- } else { \ +- xen_l1_entry_update(ptep, pteval); \ +- flush_tlb_page(vma, address); \ +- } \ +-} while (0) +- +-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH +-#define ptep_clear_flush_dirty(vma, address, ptep) \ +-({ \ +- pte_t __pte = *(ptep); \ +- int __dirty = pte_dirty(__pte); \ +- __pte = pte_mkclean(__pte); \ +- if (test_bit(PG_pinned, &virt_to_page((vma)->vm_mm->pgd)->flags)) \ +- (void)ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ +- else if (__dirty) \ +- (ptep)->pte_low = __pte.pte_low; \ +- __dirty; \ +-}) +- + #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH + #define ptep_clear_flush_young(vma, address, ptep) \ + ({ \ + pte_t __pte = *(ptep); \ + int __young = pte_young(__pte); \ + __pte = pte_mkold(__pte); \ +- if (test_bit(PG_pinned, &virt_to_page((vma)->vm_mm->pgd)->flags)) \ ++ if (PagePinned(virt_to_page((vma)->vm_mm->pgd))) \ + (void)ptep_set_access_flags(vma, address, ptep, __pte, __young); \ + else if (__young) \ + (ptep)->pte_low = __pte.pte_low; \ +@@ -383,7 +341,7 @@ static inline pte_t ptep_get_and_clear(s + #define ptep_get_and_clear_full(mm, addr, ptep, full) \ + ((full) ? ({ \ + pte_t __res = *(ptep); \ +- if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) \ ++ if (PagePinned(virt_to_page((mm)->pgd))) \ + xen_l1_entry_update(ptep, __pte(0)); \ + else \ + *(ptep) = __pte(0); \ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable-3level.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable-3level.h 2009-02-16 16:17:21.000000000 +0100 +@@ -23,26 +23,11 @@ + #define pud_present(pud) 1 + + /* +- * Is the pte executable? +- */ +-static inline int pte_x(pte_t pte) +-{ +- return !(__pte_val(pte) & _PAGE_NX); +-} +- +-/* +- * All present user-pages with !NX bit are user-executable: +- */ +-static inline int pte_exec(pte_t pte) +-{ +- return pte_user(pte) && pte_x(pte); +-} +-/* + * All present pages with !NX bit are kernel-executable: + */ + static inline int pte_exec_kernel(pte_t pte) + { +- return pte_x(pte); ++ return !(__pte_val(pte) & _PAGE_NX); + } + + /* Rules for using set_pte: the pte being assigned *must* be +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/processor_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/processor_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -89,7 +89,6 @@ struct cpuinfo_x86 { + #define X86_VENDOR_UMC 3 + #define X86_VENDOR_NEXGEN 4 + #define X86_VENDOR_CENTAUR 5 +-#define X86_VENDOR_RISE 6 + #define X86_VENDOR_TRANSMETA 7 + #define X86_VENDOR_NSC 8 + #define X86_VENDOR_NUM 9 +@@ -122,6 +121,7 @@ void __init cpu_detect(struct cpuinfo_x8 + extern void identify_boot_cpu(void); + extern void identify_secondary_cpu(struct cpuinfo_x86 *); + extern void print_cpu_info(struct cpuinfo_x86 *); ++extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c); + extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); + extern unsigned short num_cache_leaves; + +@@ -171,17 +171,6 @@ static inline void clear_in_cr4 (unsigne + write_cr4(cr4); + } + +-/* +- * NSC/Cyrix CPU indexed register access macros +- */ +- +-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) +- +-#define setCx86(reg, data) do { \ +- outb((reg), 0x22); \ +- outb((data), 0x23); \ +-} while (0) +- + /* Stop speculative execution */ + static inline void sync_core(void) + { +@@ -230,6 +219,10 @@ extern int bootloader_type; + + #define HAVE_ARCH_PICK_MMAP_LAYOUT + ++extern void hard_disable_TSC(void); ++extern void disable_TSC(void); ++extern void hard_enable_TSC(void); ++ + /* + * Size of io_bitmap. + */ +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/system_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/system_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -205,11 +205,6 @@ static inline unsigned long get_limit(un + */ + + +-/* +- * Actually only lfence would be needed for mb() because all stores done +- * by the kernel should be already ordered. But keep a full barrier for now. +- */ +- + #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) + #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) + +@@ -301,15 +296,6 @@ void enable_hlt(void); + extern int es7000_plat; + void cpu_idle_wait(void); + +-/* +- * On SMP systems, when the scheduler does migration-cost autodetection, +- * it needs a way to flush as much of the CPU's caches as possible: +- */ +-static inline void sched_cacheflush(void) +-{ +- wbinvd(); +-} +- + extern unsigned long arch_align_stack(unsigned long sp); + extern void free_init_pages(char *what, unsigned long begin, unsigned long end); + +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/tlbflush_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/tlbflush_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -91,7 +91,11 @@ struct tlb_state + DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate); + #endif /* SMP */ + +-#define flush_tlb_kernel_range(start, end) flush_tlb_all() ++static inline void flush_tlb_kernel_range(unsigned long start, ++ unsigned long end) ++{ ++ flush_tlb_all(); ++} + + static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/fixmap_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/fixmap_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -23,9 +23,9 @@ + * compile time, but to set the physical address only + * in the boot process. + * +- * these 'compile-time allocated' memory buffers are +- * fixed-size 4k pages. (or larger if used with an increment +- * highger than 1) use fixmap_set(idx,phys) to associate ++ * These 'compile-time allocated' memory buffers are ++ * fixed-size 4k pages (or larger if used with an increment ++ * higher than 1). Use set_fixmap(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across +@@ -36,6 +36,8 @@ enum fixed_addresses { + VSYSCALL_LAST_PAGE, + VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1, + VSYSCALL_HPET, ++ FIX_DBGP_BASE, ++ FIX_EARLYCON_MEM_BASE, + FIX_HPET_BASE, + #ifdef CONFIG_X86_LOCAL_APIC + FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ +@@ -105,7 +107,7 @@ static __always_inline unsigned long fix + if (idx >= __end_of_fixed_addresses) + __this_fixmap_does_not_exist(); + +- return __fix_to_virt(idx); ++ return __fix_to_virt(idx); + } + + #endif +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/mmu_context_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/mmu_context_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -76,7 +76,7 @@ static inline void switch_mm(struct mm_s + + if (likely(prev != next)) { + BUG_ON(!xen_feature(XENFEAT_writable_page_tables) && +- !next->context.pinned); ++ !PagePinned(virt_to_page(next->pgd))); + + /* stop flush ipis for the previous mm */ + cpu_clear(cpu, prev->cpu_vm_mask); +@@ -131,7 +131,7 @@ static inline void switch_mm(struct mm_s + + static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) + { +- if (!next->context.pinned) ++ if (!PagePinned(virt_to_page(next->pgd))) + mm_pin(next); + switch_mm(prev, next, NULL); + } +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/page_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/page_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -72,7 +72,8 @@ void copy_page(void *, void *); + #define clear_user_page(page, vaddr, pg) clear_page(page) + #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr) ++#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \ ++ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr) + #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE + + /* +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgalloc_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgalloc_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -21,7 +21,7 @@ static inline void pmd_populate_kernel(s + + static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte) + { +- if (unlikely((mm)->context.pinned)) { ++ if (unlikely(PagePinned(virt_to_page((mm)->pgd)))) { + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)__va(page_to_pfn(pte) << PAGE_SHIFT), + pfn_pte(page_to_pfn(pte), PAGE_KERNEL_RO), 0)); +@@ -33,7 +33,7 @@ static inline void pmd_populate(struct m + + static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) + { +- if (unlikely((mm)->context.pinned)) { ++ if (unlikely(PagePinned(virt_to_page((mm)->pgd)))) { + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)pmd, + pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, +@@ -50,7 +50,7 @@ static inline void pud_populate(struct m + */ + static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) + { +- if (unlikely((mm)->context.pinned)) { ++ if (unlikely(PagePinned(virt_to_page((mm)->pgd)))) { + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)pud, + pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -304,7 +304,7 @@ static inline pte_t ptep_get_and_clear_f + { + if (full) { + pte_t pte = *ptep; +- if (mm->context.pinned) ++ if (PagePinned(virt_to_page(mm->pgd))) + xen_l1_entry_update(ptep, __pte(0)); + else + *ptep = __pte(0); +@@ -333,21 +333,15 @@ static inline pte_t ptep_get_and_clear_f + * Undefined behaviour if not.. + */ + #define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT) +-static inline int pte_user(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } +-static inline int pte_read(pte_t pte) { return __pte_val(pte) & _PAGE_USER; } +-static inline int pte_exec(pte_t pte) { return !(__pte_val(pte) & _PAGE_NX); } + 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_write(pte_t pte) { return __pte_val(pte) & _PAGE_RW; } + static inline int pte_file(pte_t pte) { return __pte_val(pte) & _PAGE_FILE; } + static inline int pte_huge(pte_t pte) { return __pte_val(pte) & _PAGE_PSE; } + +-static inline pte_t pte_rdprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; return pte; } +-static inline pte_t pte_exprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_USER; 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_wrprotect(pte_t pte) { __pte_val(pte) &= ~_PAGE_RW; return pte; } +-static inline pte_t pte_mkread(pte_t pte) { __pte_val(pte) |= _PAGE_USER; return pte; } + static inline pte_t pte_mkexec(pte_t pte) { __pte_val(pte) &= ~_PAGE_NX; 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; } +@@ -355,13 +349,6 @@ static inline pte_t pte_mkwrite(pte_t pt + static inline pte_t pte_mkhuge(pte_t pte) { __pte_val(pte) |= _PAGE_PSE; return pte; } + static inline pte_t pte_clrhuge(pte_t pte) { __pte_val(pte) &= ~_PAGE_PSE; return pte; } + +-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) +-{ +- if (!pte_dirty(*ptep)) +- return 0; +- return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte); +-} +- + static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) + { + if (!pte_young(*ptep)) +@@ -500,26 +487,13 @@ static inline pte_t pte_modify(pte_t pte + __changed; \ + }) + +-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH +-#define ptep_clear_flush_dirty(vma, address, ptep) \ +-({ \ +- pte_t __pte = *(ptep); \ +- int __dirty = pte_dirty(__pte); \ +- __pte = pte_mkclean(__pte); \ +- if ((vma)->vm_mm->context.pinned) \ +- (void)ptep_set_access_flags(vma, address, ptep, __pte, __dirty); \ +- else if (__dirty) \ +- set_pte(ptep, __pte); \ +- __dirty; \ +-}) +- + #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH + #define ptep_clear_flush_young(vma, address, ptep) \ + ({ \ + pte_t __pte = *(ptep); \ + int __young = pte_young(__pte); \ + __pte = pte_mkold(__pte); \ +- if ((vma)->vm_mm->context.pinned) \ ++ if (PagePinned(virt_to_page((vma)->vm_mm->pgd))) \ + (void)ptep_set_access_flags(vma, address, ptep, __pte, __young); \ + else if (__young) \ + set_pte(ptep, __pte); \ +@@ -570,6 +544,8 @@ int xen_change_pte_range(struct mm_struc + #define arch_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) \ + xen_change_pte_range(mm, pmd, addr, end, newprot, dirty_accountable) + ++pte_t *lookup_address(unsigned long addr); ++ + #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ + direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO) + +@@ -587,7 +563,6 @@ int xen_change_pte_range(struct mm_struc + (((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o)) + + #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR + #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL + #define __HAVE_ARCH_PTEP_CLEAR_FLUSH +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/processor_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/processor_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -83,7 +83,6 @@ struct cpuinfo_x86 { + #define X86_VENDOR_UMC 3 + #define X86_VENDOR_NEXGEN 4 + #define X86_VENDOR_CENTAUR 5 +-#define X86_VENDOR_RISE 6 + #define X86_VENDOR_TRANSMETA 7 + #define X86_VENDOR_NUM 8 + #define X86_VENDOR_UNKNOWN 0xff +@@ -100,6 +99,7 @@ extern char ignore_irq13; + + extern void identify_cpu(struct cpuinfo_x86 *); + extern void print_cpu_info(struct cpuinfo_x86 *); ++extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c); + extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); + extern unsigned short num_cache_leaves; + +@@ -377,12 +377,10 @@ static inline void sync_core(void) + asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory"); + } + +-#define cpu_has_fpu 1 +- + #define ARCH_HAS_PREFETCH + static inline void prefetch(void *x) + { +- asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); ++ asm volatile("prefetcht0 (%0)" :: "r" (x)); + } + + #define ARCH_HAS_PREFETCHW 1 +@@ -400,17 +398,6 @@ static inline void prefetchw(void *x) + + #define cpu_relax() rep_nop() + +-/* +- * NSC/Cyrix CPU indexed register access macros +- */ +- +-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) +- +-#define setCx86(reg, data) do { \ +- outb((reg), 0x22); \ +- outb((data), 0x23); \ +-} while (0) +- + static inline void serialize_cpu(void) + { + __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/system_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/system_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -79,12 +79,16 @@ static inline unsigned long read_cr0(voi + unsigned long cr0; + asm volatile("movq %%cr0,%0" : "=r" (cr0)); + return cr0; +-} ++} + + static inline void write_cr0(unsigned long val) + { + asm volatile("movq %0,%%cr0" :: "r" (val)); +-} ++} ++ ++#define read_cr2() current_vcpu_info()->arch.cr2 ++ ++#define write_cr2(val) ((void)(current_vcpu_info()->arch.cr2 = (val))) + + #define read_cr3() ({ \ + unsigned long __dummy; \ +@@ -103,27 +107,28 @@ static inline unsigned long read_cr4(voi + unsigned long cr4; + asm("movq %%cr4,%0" : "=r" (cr4)); + return cr4; +-} ++} + + static inline void write_cr4(unsigned long val) + { + asm volatile("movq %0,%%cr4" :: "r" (val) : "memory"); +-} +- +-#define stts() (HYPERVISOR_fpu_taskswitch(1)) ++} + +-#define wbinvd() \ +- __asm__ __volatile__ ("wbinvd": : :"memory"); ++static inline unsigned long read_cr8(void) ++{ ++ return 0; ++} + +-/* +- * On SMP systems, when the scheduler does migration-cost autodetection, +- * it needs a way to flush as much of the CPU's caches as possible. +- */ +-static inline void sched_cacheflush(void) ++static inline void write_cr8(unsigned long val) + { +- wbinvd(); ++ BUG_ON(val); + } + ++#define stts() (HYPERVISOR_fpu_taskswitch(1)) ++ ++#define wbinvd() \ ++ __asm__ __volatile__ ("wbinvd": : :"memory") ++ + #endif /* __KERNEL__ */ + + #define nop() __asm__ __volatile__ ("nop") +--- sle11-2009-05-14.orig/include/asm-x86/mach-xen/asm/tlbflush_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/include/asm-x86/mach-xen/asm/tlbflush_64.h 2009-02-16 16:17:21.000000000 +0100 +@@ -89,7 +89,11 @@ static inline void flush_tlb_range(struc + + #endif + +-#define flush_tlb_kernel_range(start, end) flush_tlb_all() ++static inline void flush_tlb_kernel_range(unsigned long start, ++ unsigned long end) ++{ ++ flush_tlb_all(); ++} + + static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +--- sle11-2009-05-14.orig/include/asm-x86/thread_info.h 2009-04-20 11:36:10.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/thread_info.h 2009-02-16 16:17:21.000000000 +0100 +@@ -150,7 +150,8 @@ struct thread_info { + #define _TIF_WORK_CTXSW_PREV _TIF_WORK_CTXSW + #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) + #else +-#define _TIF_WORK_CTXSW _TIF_DEBUG ++#define _TIF_WORK_CTXSW_NEXT (_TIF_NOTSC | _TIF_DEBUG) ++#define _TIF_WORK_CTXSW_PREV (_TIF_NOTSC) + #endif + + #define PREEMPT_ACTIVE 0x10000000 +--- sle11-2009-05-14.orig/include/asm-x86/xen/interface.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/xen/interface.h 2009-02-16 16:17:21.000000000 +0100 +@@ -10,17 +10,17 @@ + #define __ASM_X86_XEN_INTERFACE_H + + #ifdef __XEN__ +-#define __DEFINE_GUEST_HANDLE(name, type) \ ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef struct { type *p; } __guest_handle_ ## name + #else +-#define __DEFINE_GUEST_HANDLE(name, type) \ ++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef type * __guest_handle_ ## name + #endif + +-#define DEFINE_GUEST_HANDLE_STRUCT(name) \ +- __DEFINE_GUEST_HANDLE(name, struct name) +-#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name) +-#define GUEST_HANDLE(name) __guest_handle_ ## name ++#define DEFINE_XEN_GUEST_HANDLE_STRUCT(name) \ ++ __DEFINE_XEN_GUEST_HANDLE(name, struct name) ++#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) ++#define XEN_GUEST_HANDLE(name) __guest_handle_ ## name + + #ifdef __XEN__ + #if defined(__i386__) +@@ -47,14 +47,8 @@ + #endif + + #ifndef __ASSEMBLY__ +-/* Guest handles for primitive C types. */ +-__DEFINE_GUEST_HANDLE(uchar, unsigned char); +-__DEFINE_GUEST_HANDLE(uint, unsigned int); +-__DEFINE_GUEST_HANDLE(ulong, unsigned long); +-DEFINE_GUEST_HANDLE(char); +-DEFINE_GUEST_HANDLE(int); +-DEFINE_GUEST_HANDLE(long); +-DEFINE_GUEST_HANDLE(void); ++typedef unsigned long xen_pfn_t; ++typedef unsigned long xen_ulong_t; + #endif + + #ifndef HYPERVISOR_VIRT_START +@@ -103,7 +97,7 @@ struct trap_info { + uint16_t cs; /* code selector */ + unsigned long address; /* code offset */ + }; +-DEFINE_GUEST_HANDLE_STRUCT(trap_info); ++DEFINE_XEN_GUEST_HANDLE_STRUCT(trap_info); + + struct arch_shared_info { + unsigned long max_pfn; /* max pfn that appears in table */ +@@ -157,7 +151,7 @@ struct vcpu_guest_context { + uint64_t gs_base_user; + #endif + }; +-DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context); ++DEFINE_XEN_GUEST_HANDLE_STRUCT(vcpu_guest_context); + #endif /* !__ASSEMBLY__ */ + + /* +--- sle11-2009-05-14.orig/include/asm-x86/xen/interface_32.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/asm-x86/xen/interface_32.h 2009-02-16 16:17:21.000000000 +0100 +@@ -62,7 +62,7 @@ struct cpu_user_regs { + uint16_t fs, _pad4; + uint16_t gs, _pad5; + }; +-DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs); ++DEFINE_XEN_GUEST_HANDLE_STRUCT(cpu_user_regs); + + typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ + +--- sle11-2009-05-14.orig/include/linux/elfnote.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/linux/elfnote.h 2009-02-16 16:17:21.000000000 +0100 +@@ -52,7 +52,7 @@ + 4484:.balign 4 ; \ + .popsection ; + +-#define ELFNOTE(name, type, desc) \ ++#define ELFNOTE(name, type, desc...) \ + ELFNOTE_START(name, type, "") \ + desc ; \ + ELFNOTE_END +--- sle11-2009-05-14.orig/include/linux/page-flags.h 2009-01-16 10:20:18.000000000 +0100 ++++ sle11-2009-05-14/include/linux/page-flags.h 2009-02-16 16:17:21.000000000 +0100 +@@ -100,6 +100,10 @@ enum pageflags { + #endif + #ifdef CONFIG_XEN + PG_foreign, /* Page is owned by foreign allocator. */ ++ PG_pinned, /* Cannot alias with PG_owner_priv_1 since ++ * bad_page() checks include this bit. ++ * Also cannot use PG_arch_1 since that now ++ * has a different purpose on x86. */ + #endif + __NR_PAGEFLAGS, + +--- sle11-2009-05-14.orig/include/linux/skbuff.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-05-14/include/linux/skbuff.h 2009-02-16 16:17:21.000000000 +0100 +@@ -1772,7 +1772,7 @@ static inline void skb_forward_csum(stru + + bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); + +-#ifdef CONFIG_XEN ++#if defined(CONFIG_XEN) || defined(CONFIG_PARAVIRT_XEN) + int skb_checksum_setup(struct sk_buff *skb); + #else + static inline int skb_checksum_setup(struct sk_buff *skb) { return 0; } +--- sle11-2009-05-14.orig/include/xen/driver_util.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/xen/driver_util.h 2009-02-16 16:17:21.000000000 +0100 +@@ -5,10 +5,6 @@ + #include + #include + +-/* Allocate/destroy a 'vmalloc' VM area. */ +-extern struct vm_struct *alloc_vm_area(unsigned long size); +-extern void free_vm_area(struct vm_struct *area); +- + extern struct class *get_xen_class(void); + + #endif /* __ASM_XEN_DRIVER_UTIL_H__ */ +--- sle11-2009-05-14.orig/include/xen/features.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/xen/features.h 2009-02-16 16:17:21.000000000 +0100 +@@ -10,6 +10,7 @@ + #define __XEN_FEATURES_H__ + + #include ++#include + + void xen_setup_features(void); + +@@ -20,4 +21,4 @@ static inline int xen_feature(int flag) + return xen_features[flag]; + } + +-#endif /* __ASM_XEN_FEATURES_H__ */ ++#endif /* __XEN_FEATURES_H__ */ +--- sle11-2009-05-14.orig/include/xen/interface/arch-x86/xen.h 2009-05-14 10:56:29.000000000 +0200 ++++ sle11-2009-05-14/include/xen/interface/arch-x86/xen.h 2009-02-16 16:17:21.000000000 +0100 +@@ -49,6 +49,9 @@ + #define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) + #endif + ++/* Allow co-existing Linux 2.6.23+ Xen interface definitions. */ ++#define DEFINE_XEN_GUEST_HANDLE_STRUCT(name) struct name ++ + #if defined(__i386__) + #include "xen-x86_32.h" + #elif defined(__x86_64__) +--- sle11-2009-05-14.orig/include/xen/interface/event_channel.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/event_channel.h 2009-02-16 16:17:21.000000000 +0100 +@@ -248,6 +248,7 @@ struct evtchn_op { + struct evtchn_unmask unmask; + } u; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(evtchn_op); + typedef struct evtchn_op evtchn_op_t; + DEFINE_XEN_GUEST_HANDLE(evtchn_op_t); + +--- sle11-2009-05-14.orig/include/xen/interface/io/netif.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/io/netif.h 2009-02-16 16:17:21.000000000 +0100 +@@ -183,8 +183,22 @@ typedef struct netif_rx_response netif_r + * Generate netif ring structures and types. + */ + ++#if defined(CONFIG_XEN) || defined(HAVE_XEN_PLATFORM_COMPAT_H) + DEFINE_RING_TYPES(netif_tx, struct netif_tx_request, struct netif_tx_response); + DEFINE_RING_TYPES(netif_rx, struct netif_rx_request, struct netif_rx_response); ++#else ++#define xen_netif_tx_request netif_tx_request ++#define xen_netif_rx_request netif_rx_request ++#define xen_netif_tx_response netif_tx_response ++#define xen_netif_rx_response netif_rx_response ++DEFINE_RING_TYPES(xen_netif_tx, ++ struct xen_netif_tx_request, ++ struct xen_netif_tx_response); ++DEFINE_RING_TYPES(xen_netif_rx, ++ struct xen_netif_rx_request, ++ struct xen_netif_rx_response); ++#define xen_netif_extra_info netif_extra_info ++#endif + + #define NETIF_RSP_DROPPED -2 + #define NETIF_RSP_ERROR -1 +--- sle11-2009-05-14.orig/include/xen/interface/memory.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/memory.h 2009-02-16 16:17:21.000000000 +0100 +@@ -82,6 +82,7 @@ struct xen_memory_reservation { + domid_t domid; + + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(xen_memory_reservation); + typedef struct xen_memory_reservation xen_memory_reservation_t; + DEFINE_XEN_GUEST_HANDLE(xen_memory_reservation_t); + +@@ -175,6 +176,7 @@ struct xen_machphys_mfn_list { + */ + unsigned int nr_extents; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); + typedef struct xen_machphys_mfn_list xen_machphys_mfn_list_t; + DEFINE_XEN_GUEST_HANDLE(xen_machphys_mfn_list_t); + +@@ -214,6 +216,7 @@ struct xen_add_to_physmap { + /* GPFN where the source mapping page should appear. */ + xen_pfn_t gpfn; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(xen_add_to_physmap); + typedef struct xen_add_to_physmap xen_add_to_physmap_t; + DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t); + +@@ -254,6 +257,7 @@ struct xen_translate_gpfn_list { + */ + XEN_GUEST_HANDLE(xen_pfn_t) mfn_list; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list); + typedef struct xen_translate_gpfn_list xen_translate_gpfn_list_t; + DEFINE_XEN_GUEST_HANDLE(xen_translate_gpfn_list_t); + +--- sle11-2009-05-14.orig/include/xen/interface/sched.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/sched.h 2009-02-16 16:17:21.000000000 +0100 +@@ -67,6 +67,7 @@ + struct sched_shutdown { + unsigned int reason; /* SHUTDOWN_* */ + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(sched_shutdown); + typedef struct sched_shutdown sched_shutdown_t; + DEFINE_XEN_GUEST_HANDLE(sched_shutdown_t); + +@@ -81,6 +82,7 @@ struct sched_poll { + unsigned int nr_ports; + uint64_t timeout; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(sched_poll); + typedef struct sched_poll sched_poll_t; + DEFINE_XEN_GUEST_HANDLE(sched_poll_t); + +--- sle11-2009-05-14.orig/include/xen/interface/version.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/version.h 2009-02-16 16:17:21.000000000 +0100 +@@ -36,6 +36,9 @@ + /* arg == xen_extraversion_t. */ + #define XENVER_extraversion 1 + typedef char xen_extraversion_t[16]; ++struct xen_extraversion { ++ xen_extraversion_t extraversion; ++}; + #define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t)) + + /* arg == xen_compile_info_t. */ +@@ -50,10 +53,16 @@ typedef struct xen_compile_info xen_comp + + #define XENVER_capabilities 3 + typedef char xen_capabilities_info_t[1024]; ++struct xen_capabilities_info { ++ xen_capabilities_info_t info; ++}; + #define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t)) + + #define XENVER_changeset 4 + typedef char xen_changeset_info_t[64]; ++struct xen_changeset_info { ++ xen_changeset_info_t info; ++}; + #define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t)) + + #define XENVER_platform_parameters 5 +--- sle11-2009-05-14.orig/include/xen/interface/xen.h 2008-11-25 12:35:56.000000000 +0100 ++++ sle11-2009-05-14/include/xen/interface/xen.h 2009-05-14 11:17:48.000000000 +0200 +@@ -32,7 +32,9 @@ + #include + #endif + +-#if defined(__i386__) || defined(__x86_64__) ++#if defined(CONFIG_PARAVIRT_XEN) && !defined(HAVE_XEN_PLATFORM_COMPAT_H) ++#include ++#elif defined(__i386__) || defined(__x86_64__) + #include "arch-x86/xen.h" + #elif defined(__ia64__) + #include "arch-ia64.h" +@@ -110,7 +112,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); + */ + + /* New sched_op hypercall introduced in 0x00030101. */ +-#if __XEN_INTERFACE_VERSION__ < 0x00030101 ++#if __XEN_INTERFACE_VERSION__ < 0x00030101 || (defined(CONFIG_PARAVIRT_XEN) && !defined(HAVE_XEN_PLATFORM_COMPAT_H)) + #undef __HYPERVISOR_sched_op + #define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat + #else +@@ -126,7 +128,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); + #endif + + /* New platform_op hypercall introduced in 0x00030204. */ +-#if __XEN_INTERFACE_VERSION__ < 0x00030204 ++#if __XEN_INTERFACE_VERSION__ < 0x00030204 || (defined(CONFIG_PARAVIRT_XEN) && !defined(HAVE_XEN_PLATFORM_COMPAT_H)) + #define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op + #endif + +@@ -285,6 +287,7 @@ struct mmuext_op { + xen_pfn_t src_mfn; + } arg2; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(mmuext_op); + typedef struct mmuext_op mmuext_op_t; + DEFINE_XEN_GUEST_HANDLE(mmuext_op_t); + #endif +@@ -367,6 +370,7 @@ struct mmu_update { + uint64_t ptr; /* Machine address of PTE. */ + uint64_t val; /* New contents of PTE. */ + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(mmu_update); + typedef struct mmu_update mmu_update_t; + DEFINE_XEN_GUEST_HANDLE(mmu_update_t); + +@@ -375,9 +379,15 @@ DEFINE_XEN_GUEST_HANDLE(mmu_update_t); + * NB. The fields are natural register size for this architecture. + */ + struct multicall_entry { +- unsigned long op, result; ++ unsigned long op; ++#if !defined(CONFIG_PARAVIRT_XEN) || defined(HAVE_XEN_PLATFORM_COMPAT_H) ++ unsigned long result; ++#else ++ long result; ++#endif + unsigned long args[6]; + }; ++DEFINE_XEN_GUEST_HANDLE_STRUCT(multicall_entry); + typedef struct multicall_entry multicall_entry_t; + DEFINE_XEN_GUEST_HANDLE(multicall_entry_t); + +--- sle11-2009-05-14.orig/include/xen/xenbus.h 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-05-14/include/xen/xenbus.h 2009-02-16 16:17:21.000000000 +0100 +@@ -57,16 +57,20 @@ struct xenbus_watch + void (*callback)(struct xenbus_watch *, + const char **vec, unsigned int len); + ++#if defined(CONFIG_XEN) || defined(HAVE_XEN_PLATFORM_COMPAT_H) + /* See XBWF_ definitions below. */ + unsigned long flags; ++#endif + }; + ++#if defined(CONFIG_XEN) || defined(HAVE_XEN_PLATFORM_COMPAT_H) + /* + * Execute callback in its own kthread. Useful if the callback is long + * running or heavily serialised, to avoid taking out the main xenwatch thread + * for a long period of time (or even unwittingly causing a deadlock). + */ + #define XBWF_new_thread 1 ++#endif + + /* A xenbus device. */ + struct xenbus_device { +@@ -214,6 +218,7 @@ int xenbus_watch_path(struct xenbus_devi + const char **, unsigned int)); + + ++#if defined(CONFIG_XEN) || defined(HAVE_XEN_PLATFORM_COMPAT_H) + /** + * Register a watch on the given path/path2, using the given xenbus_watch + * structure for storage, and the given callback function as the callback. +@@ -227,7 +232,13 @@ int xenbus_watch_path2(struct xenbus_dev + const char *path2, struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)); +- ++#else ++int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, ++ void (*callback)(struct xenbus_watch *, ++ const char **, unsigned int), ++ const char *pathfmt, ...) ++ __attribute__ ((format (printf, 4, 5))); ++#endif + + /** + * Advertise in the store a change of the given driver to the given new_state. +--- sle11-2009-05-14.orig/net/core/dev.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-05-14/net/core/dev.c 2009-02-16 16:17:21.000000000 +0100 +@@ -131,7 +131,7 @@ + + #include "net-sysfs.h" + +-#ifdef CONFIG_XEN ++#if defined(CONFIG_XEN) || defined(CONFIG_PARAVIRT_XEN) + #include + #include + #include +@@ -1740,42 +1740,54 @@ static struct netdev_queue *dev_pick_tx( + return netdev_get_tx_queue(dev, queue_index); + } + +-#ifdef CONFIG_XEN ++#if defined(CONFIG_XEN) || defined(CONFIG_PARAVIRT_XEN) + inline int skb_checksum_setup(struct sk_buff *skb) + { +- if (skb->proto_csum_blank) { +- struct iphdr *iph; +- unsigned char *th; ++ struct iphdr *iph; ++ unsigned char *th; ++ int err = -EPROTO; + +- if (skb->protocol != htons(ETH_P_IP)) +- goto out; +- iph = ip_hdr(skb); +- th = skb_network_header(skb) + 4 * iph->ihl; +- if (th >= skb_tail_pointer(skb)) +- goto out; +- skb->csum_start = th - skb->head; +- switch (iph->protocol) { +- case IPPROTO_TCP: +- skb->csum_offset = offsetof(struct tcphdr, check); +- break; +- case IPPROTO_UDP: +- skb->csum_offset = offsetof(struct udphdr, check); +- break; +- default: +- if (net_ratelimit()) +- printk(KERN_ERR "Attempting to checksum a non-" +- "TCP/UDP packet, dropping a protocol" +- " %d packet", iph->protocol); +- goto out; +- } +- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb)) +- goto out; +- skb->ip_summed = CHECKSUM_PARTIAL; +- skb->proto_csum_blank = 0; ++#ifdef CONFIG_XEN ++ if (!skb->proto_csum_blank) ++ return 0; ++#endif ++ ++ if (skb->protocol != htons(ETH_P_IP)) ++ goto out; ++ ++ iph = ip_hdr(skb); ++ th = skb_network_header(skb) + 4 * iph->ihl; ++ if (th >= skb_tail_pointer(skb)) ++ goto out; ++ ++ skb->csum_start = th - skb->head; ++ switch (iph->protocol) { ++ case IPPROTO_TCP: ++ skb->csum_offset = offsetof(struct tcphdr, check); ++ break; ++ case IPPROTO_UDP: ++ skb->csum_offset = offsetof(struct udphdr, check); ++ break; ++ default: ++ if (net_ratelimit()) ++ printk(KERN_ERR "Attempting to checksum a non-" ++ "TCP/UDP packet, dropping a protocol" ++ " %d packet", iph->protocol); ++ goto out; + } +- return 0; ++ ++ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb)) ++ goto out; ++ ++#ifdef CONFIG_XEN ++ skb->ip_summed = CHECKSUM_PARTIAL; ++ skb->proto_csum_blank = 0; ++#endif ++ ++ err = 0; ++ + out: +- return -EPROTO; ++ return err; + } + EXPORT_SYMBOL(skb_checksum_setup); + #endif diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.24 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.24 new file mode 100644 index 000000000..daff2bafa --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.24 @@ -0,0 +1,8673 @@ +From: www.kernel.org +Subject: Update to 2.6.24 +Patch-mainline: 2.6.24 + +Automatically created from "patches.kernel.org/patch-2.6.24" by xen-port-patches.py + +Acked-by: jbeulich@novell.com + +--- sle11-2009-06-29.orig/arch/x86/Kconfig 2009-02-05 10:22:38.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/Kconfig 2009-02-16 16:18:36.000000000 +0100 +@@ -50,15 +50,16 @@ config GENERIC_CMOS_UPDATE + + config CLOCKSOURCE_WATCHDOG + def_bool y +- depends on !X86_XEN ++ depends on !XEN + + config GENERIC_CLOCKEVENTS + def_bool y +- depends on !X86_XEN ++ depends on !XEN + + config GENERIC_CLOCKEVENTS_BROADCAST + def_bool y +- depends on X86_64 || (X86_32 && X86_LOCAL_APIC && !X86_XEN) ++ depends on X86_64 || (X86_32 && X86_LOCAL_APIC) ++ depends on !XEN + + config LOCKDEP_SUPPORT + def_bool y +@@ -211,12 +212,12 @@ config X86_TRAMPOLINE + + config X86_NO_TSS + bool +- depends on X86_XEN || X86_64_XEN ++ depends on XEN + default y + + config X86_NO_IDT + bool +- depends on X86_XEN || X86_64_XEN ++ depends on XEN + default y + + config KTIME_SCALAR +@@ -287,6 +288,7 @@ config X86_PC + + config X86_XEN + bool "Xen-compatible" ++ depends on X86_32 + select XEN + select X86_PAE + select X86_UP_APIC if !SMP && XEN_PRIVILEGED_GUEST +@@ -365,6 +367,7 @@ endif + + config X86_64_XEN + bool "Enable Xen compatible kernel" ++ depends on X86_64 + select XEN + select SWIOTLB + help +@@ -417,7 +420,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER + + menuconfig PARAVIRT_GUEST + bool "Paravirtualized guest support" +- depends on !X86_XEN && !X86_64_XEN ++ depends on !XEN + help + Say Y here to get to see options related to running Linux under + various hypervisors. This option alone does not add any kernel code. +@@ -511,7 +514,7 @@ source "arch/x86/Kconfig.cpu" + config HPET_TIMER + def_bool X86_64 + prompt "HPET Timer Support" if X86_32 +- depends on !X86_XEN && !X86_64_XEN ++ depends on !XEN + help + Use the IA-PC HPET (High Precision Event Timer) to manage + time in preference to the PIT and RTC, if a HPET is +@@ -831,7 +834,7 @@ config I8K + config X86_REBOOTFIXUPS + def_bool n + prompt "Enable X86 board specific fixups for reboot" +- depends on X86_32 && !X86_XEN ++ depends on X86_32 && !XEN + ---help--- + This enables chipset and/or board specific fixups to be done + in order to get reboot to work correctly. This is only needed on +@@ -1164,7 +1167,7 @@ config X86_RESERVE_LOW_64K + config MATH_EMULATION + bool + prompt "Math emulation" if X86_32 +- depends on !X86_XEN ++ depends on !XEN + ---help--- + Linux can emulate a math coprocessor (used for floating point + operations) if you don't have one. 486DX and Pentium processors have +@@ -1272,7 +1275,7 @@ config X86_PAT + config EFI + def_bool n + prompt "EFI runtime service support" +- depends on ACPI && !X86_XEN && !X86_64_XEN ++ depends on ACPI && !XEN + ---help--- + This enables the kernel to use EFI runtime services that are + available (such as the EFI variable services). +@@ -1287,7 +1290,7 @@ config EFI + config IRQBALANCE + def_bool y + prompt "Enable kernel irq balancing" +- depends on X86_32 && SMP && X86_IO_APIC && !X86_XEN ++ depends on X86_32 && SMP && X86_IO_APIC && !XEN + help + The default yes will allow the kernel to do irq load balancing. + Saying no will keep the kernel from doing irq load balancing. +@@ -1433,7 +1436,7 @@ config PHYSICAL_START + + config RELOCATABLE + bool "Build a relocatable kernel (EXPERIMENTAL)" +- depends on EXPERIMENTAL && !X86_XEN && !X86_64_XEN ++ depends on EXPERIMENTAL && !XEN + help + This builds a kernel image that retains relocation information + so it can be loaded someplace besides the default 1MB. +@@ -1503,6 +1506,7 @@ endmenu + config ARCH_ENABLE_MEMORY_HOTPLUG + def_bool y + depends on X86_64 || (X86_32 && HIGHMEM) ++ depends on !XEN + + config HAVE_ARCH_EARLY_PFN_TO_NID + def_bool X86_64 +@@ -1693,7 +1697,7 @@ choice + + config PCI_GOBIOS + bool "BIOS" +- depends on !X86_XEN ++ depends on !XEN + + config PCI_GOMMCONFIG + bool "MMConfig" +@@ -1744,7 +1748,7 @@ config PCI_MMCONFIG + + config XEN_PCIDEV_FRONTEND + bool "Xen PCI Frontend" if X86_64 +- depends on PCI && ((X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)) || X86_64_XEN) ++ depends on PCI && XEN && (PCI_GOXEN_FE || PCI_GOANY || X86_64) + select HOTPLUG + default y + help +@@ -1761,6 +1765,7 @@ config XEN_PCIDEV_FE_DEBUG + config DMAR + bool "Support for DMA Remapping Devices (EXPERIMENTAL)" + depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL ++ depends on !XEN + help + DMA remapping (DMAR) devices support enables independent address + translations for Direct Memory Access (DMA) from devices. +--- sle11-2009-06-29.orig/arch/x86/Makefile 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/Makefile 2009-02-16 16:18:36.000000000 +0100 +@@ -191,8 +191,8 @@ PHONY += zImage bzImage vmlinuz compress + zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install + + ifdef CONFIG_XEN +-CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \ +- -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS) ++KBUILD_CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \ ++ -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(KBUILD_CPPFLAGS) + + ifdef CONFIG_X86_64 + LDFLAGS_vmlinux := -e startup_64 +@@ -206,6 +206,8 @@ KBUILD_IMAGE := $(boot)/vmlinuz + + vmlinuz: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) ++ $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot ++ $(Q)ln -fsn ../../x86/boot/$@ $(objtree)/arch/$(UTS_MACHINE)/boot/$@ + else + # Default kernel to build + all: bzImage +--- sle11-2009-06-29.orig/arch/x86/ia32/ia32entry-xen.S 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/ia32/ia32entry-xen.S 2009-02-16 16:18:36.000000000 +0100 +@@ -125,20 +125,16 @@ sysenter_do_call: + jmp int_ret_from_sys_call + + sysenter_tracesys: ++ xchgl %r9d,%ebp + SAVE_REST + CLEAR_RREGS ++ movq %r9,R9(%rsp) + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace_enter + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST +- movl %ebp, %ebp +- /* no need to do an access_ok check here because rbp has been +- 32bit zero extended */ +-1: movl (%rbp),%r9d +- .section __ex_table,"a" +- .quad 1b,ia32_badarg +- .previous ++ xchgl %ebp,%r9d + jmp sysenter_do_call + CFI_ENDPROC + ENDPROC(ia32_sysenter_target) +@@ -200,20 +196,17 @@ cstar_do_call: + jmp int_ret_from_sys_call + + cstar_tracesys: ++ xchgl %r9d,%ebp + SAVE_REST + CLEAR_RREGS ++ movq %r9,R9(%rsp) + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace_enter + LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST ++ xchgl %ebp,%r9d + movl RSP-ARGOFFSET(%rsp), %r8d +- /* no need to do an access_ok check here because r8 has been +- 32bit zero extended */ +-1: movl (%r8),%r9d +- .section __ex_table,"a" +- .quad 1b,ia32_badarg +- .previous + jmp cstar_do_call + END(ia32_cstar_target) + +--- sle11-2009-06-29.orig/arch/x86/kernel/Makefile 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/Makefile 2009-02-16 16:18:36.000000000 +0100 +@@ -127,4 +127,4 @@ endif + disabled-obj-$(CONFIG_XEN) := early-quirks.o hpet.o i8253.o i8259_$(BITS).o reboot.o \ + smpboot_$(BITS).o tsc_$(BITS).o tsc_sync.o + disabled-obj-$(CONFIG_XEN_UNPRIVILEGED_GUEST) += mpparse_64.o +-%/head_64.o %/head_64.s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) := ++%/head_64.o %/head_64.s: asflags-$(CONFIG_XEN) := +--- sle11-2009-06-29.orig/arch/x86/kernel/acpi/sleep_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/acpi/sleep_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -90,7 +90,7 @@ __setup("acpi_sleep=", acpi_sleep_setup) + + /* Ouch, we want to delete this. We already have better version in userspace, in + s2ram from suspend.sf.net project */ +-static __init int reset_videomode_after_s3(struct dmi_system_id *d) ++static __init int reset_videomode_after_s3(const struct dmi_system_id *d) + { + acpi_realmode_flags |= 2; + return 0; +--- sle11-2009-06-29.orig/arch/x86/kernel/acpi/sleep_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/acpi/sleep_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -123,6 +123,3 @@ static int __init acpi_sleep_setup(char + __setup("acpi_sleep=", acpi_sleep_setup); + #endif /* CONFIG_ACPI_PV_SLEEP */ + +-void acpi_pci_link_exit(void) +-{ +-} +--- sle11-2009-06-29.orig/arch/x86/kernel/apic_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/apic_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -63,22 +63,38 @@ int setup_profiling_timer(unsigned int m + + void smp_local_timer_interrupt(void) + { +- profile_tick(CPU_PROFILING); + #ifndef CONFIG_XEN +-#ifdef CONFIG_SMP +- update_process_times(user_mode(get_irq_regs())); +-#endif +-#endif ++ int cpu = smp_processor_id(); ++ struct clock_event_device *evt = &per_cpu(lapic_events, cpu); ++ + /* +- * We take the 'long' return path, and there every subsystem +- * grabs the appropriate locks (kernel lock/ irq lock). ++ * Normally we should not be here till LAPIC has been initialized but ++ * in some cases like kdump, its possible that there is a pending LAPIC ++ * timer interrupt from previous kernel's context and is delivered in ++ * new kernel the moment interrupts are enabled. + * +- * We might want to decouple profiling from the 'long path', +- * and do the profiling totally in assembly. +- * +- * Currently this isn't too much of an issue (performance wise), +- * we can take more than 100K local irqs per second on a 100 MHz P5. ++ * Interrupts are enabled early and LAPIC is setup much later, hence ++ * its possible that when we get here evt->event_handler is NULL. ++ * Check for event_handler being NULL and discard the interrupt as ++ * spurious. ++ */ ++ if (!evt->event_handler) { ++ printk(KERN_WARNING ++ "Spurious LAPIC timer interrupt on cpu %d\n", cpu); ++ /* Switch it off */ ++ lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); ++ return; ++ } ++#endif ++ ++ /* ++ * the NMI deadlock-detector uses this. + */ ++ add_pda(apic_timer_irqs, 1); ++ ++#ifndef CONFIG_XEN ++ evt->event_handler(evt); ++#endif + } + + /* +@@ -94,11 +110,6 @@ void smp_apic_timer_interrupt(struct pt_ + struct pt_regs *old_regs = set_irq_regs(regs); + + /* +- * the NMI deadlock-detector uses this. +- */ +- add_pda(apic_timer_irqs, 1); +- +- /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ +@@ -132,6 +143,7 @@ asmlinkage void smp_spurious_interrupt(v + if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f))) + ack_APIC_irq(); + ++ add_pda(irq_spurious_count, 1); + irq_exit(); + } + +--- sle11-2009-06-29.orig/arch/x86/kernel/cpu/common-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/cpu/common-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -214,7 +214,7 @@ static void __cpuinit get_cpu_vendor(str + + static int __init x86_fxsr_setup(char * s) + { +- /* Tell all the other CPU's to not use it... */ ++ /* Tell all the other CPUs to not use it... */ + disable_x86_fxsr = 1; + + /* +--- sle11-2009-06-29.orig/arch/x86/kernel/e820_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/e820_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -52,6 +52,13 @@ struct resource code_resource = { + .flags = IORESOURCE_BUSY | IORESOURCE_MEM + }; + ++struct resource bss_resource = { ++ .name = "Kernel bss", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM ++}; ++ + static struct resource system_rom_resource = { + .name = "System ROM", + .start = 0xf0000, +@@ -266,7 +273,9 @@ static struct e820map machine_e820; + * and also for regions reported as reserved by the e820. + */ + static void __init +-legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource) ++legacy_init_iomem_resources(struct resource *code_resource, ++ struct resource *data_resource, ++ struct resource *bss_resource) + { + int i; + +@@ -300,9 +309,11 @@ legacy_init_iomem_resources(struct resou + #ifndef CONFIG_XEN + request_resource(res, code_resource); + request_resource(res, data_resource); ++ request_resource(res, bss_resource); + #endif + #ifdef CONFIG_KEXEC +- request_resource(res, &crashk_res); ++ if (crashk_res.start != crashk_res.end) ++ request_resource(res, &crashk_res); + #ifdef CONFIG_XEN + xen_machine_kexec_register_resources(res); + #endif +@@ -329,9 +340,11 @@ static int __init request_standard_resou + + printk("Setting up standard PCI resources\n"); + if (efi_enabled) +- efi_initialize_iomem_resources(&code_resource, &data_resource); ++ efi_initialize_iomem_resources(&code_resource, ++ &data_resource, &bss_resource); + else +- legacy_init_iomem_resources(&code_resource, &data_resource); ++ legacy_init_iomem_resources(&code_resource, ++ &data_resource, &bss_resource); + + /* EFI systems may still have VGA */ + request_resource(&iomem_resource, &video_ram_resource); +@@ -774,7 +787,7 @@ void __init e820_register_memory(void) + #endif + + /* +- * Search for the bigest gap in the low 32 bits of the e820 ++ * Search for the biggest gap in the low 32 bits of the e820 + * memory space. + */ + last = 0x100000000ull; +--- sle11-2009-06-29.orig/arch/x86/kernel/e820_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/e820_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -24,7 +24,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +@@ -51,7 +51,7 @@ unsigned long end_pfn_map; + */ + static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; + +-extern struct resource code_resource, data_resource; ++extern struct resource code_resource, data_resource, bss_resource; + + /* Check for some hardcoded bad areas that early boot is not allowed to touch */ + static inline int bad_addr(unsigned long *addrp, unsigned long size) +@@ -73,10 +73,15 @@ static inline int bad_addr(unsigned long + + /* initrd */ + #ifdef CONFIG_BLK_DEV_INITRD +- if (LOADER_TYPE && INITRD_START && last >= INITRD_START && +- addr < INITRD_START+INITRD_SIZE) { +- *addrp = PAGE_ALIGN(INITRD_START + INITRD_SIZE); +- return 1; ++ if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { ++ unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; ++ unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; ++ unsigned long ramdisk_end = ramdisk_image+ramdisk_size; ++ ++ if (last >= ramdisk_image && addr < ramdisk_end) { ++ *addrp = PAGE_ALIGN(ramdisk_end); ++ return 1; ++ } + } + #endif + /* kernel code */ +@@ -249,6 +254,7 @@ void __init e820_reserve_resources(struc + #ifndef CONFIG_XEN + request_resource(res, &code_resource); + request_resource(res, &data_resource); ++ request_resource(res, &bss_resource); + #endif + #ifdef CONFIG_KEXEC + if (crashk_res.start != crashk_res.end) +@@ -650,8 +656,8 @@ void __init setup_memory_region(void) + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ +- sanitize_e820_map(E820_MAP, &E820_MAP_NR); +- if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) ++ sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries); ++ if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0) + early_panic("Cannot find a valid memory map"); + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); + e820_print_map("BIOS-e820"); +@@ -836,3 +842,22 @@ __init void e820_setup_gap(struct e820en + printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", + pci_mem_start, gapstart, gapsize); + } ++ ++int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) ++{ ++ int i; ++ ++ if (slot < 0 || slot >= e820.nr_map) ++ return -1; ++ for (i = slot; i < e820.nr_map; i++) { ++ if (e820.map[i].type != E820_RAM) ++ continue; ++ break; ++ } ++ if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT)) ++ return -1; ++ *addr = e820.map[i].addr; ++ *size = min_t(u64, e820.map[i].size + e820.map[i].addr, ++ max_pfn << PAGE_SHIFT) - *addr; ++ return i + 1; ++} +--- sle11-2009-06-29.orig/arch/x86/kernel/early_printk-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/early_printk-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -6,14 +6,9 @@ + #include + #include + #include ++#include + + /* Simple VGA output */ +- +-#ifdef __i386__ +-#include +-#else +-#include +-#endif + #define VGABASE (__ISA_IO_base + 0xb8000) + + #ifndef CONFIG_XEN +@@ -264,10 +259,10 @@ static int __init setup_early_printk(cha + early_console = &early_serial_console; + } else if (!strncmp(buf, "vga", 3)) { + #ifndef CONFIG_XEN +- && SCREEN_INFO.orig_video_isVGA == 1) { +- max_xpos = SCREEN_INFO.orig_video_cols; +- max_ypos = SCREEN_INFO.orig_video_lines; +- current_ypos = SCREEN_INFO.orig_y; ++ && boot_params.screen_info.orig_video_isVGA == 1) { ++ max_xpos = boot_params.screen_info.orig_video_cols; ++ max_ypos = boot_params.screen_info.orig_video_lines; ++ current_ypos = boot_params.screen_info.orig_y; + #endif + early_console = &early_vga_console; + } else if (!strncmp(buf, "simnow", 6)) { +--- sle11-2009-06-29.orig/arch/x86/kernel/entry_32-xen.S 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:18:18.000000000 +0200 +@@ -254,6 +254,7 @@ check_userspace: + jb resume_kernel # not returning to v8086 or userspace + + ENTRY(resume_userspace) ++ LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret +@@ -341,6 +342,7 @@ sysenter_past_esp: + jae syscall_badsys + call *sys_call_table(,%eax,4) + movl %eax,PT_EAX(%esp) ++ LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) + TRACE_IRQS_OFF + movl TI_flags(%ebp), %ecx +@@ -406,6 +408,7 @@ syscall_call: + call *sys_call_table(,%eax,4) + movl %eax,PT_EAX(%esp) # store the return value + syscall_exit: ++ LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret +@@ -478,7 +481,7 @@ ldt_ss: + * is still available to implement the setting of the high + * 16-bits in the INTERRUPT_RETURN paravirt-op. + */ +- cmpl $0, paravirt_ops+PARAVIRT_enabled ++ cmpl $0, pv_info+PARAVIRT_enabled + jne restore_nocheck + #endif + +@@ -540,6 +543,7 @@ work_pending: + jz work_notifysig + work_resched: + call schedule ++ LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret +@@ -1268,6 +1272,6 @@ ENTRY(kernel_thread_helper) + ENDPROC(kernel_thread_helper) + + .section .rodata,"a" +-#include "syscall_table.S" ++#include "syscall_table_32.S" + + syscall_table_size=(.-sys_call_table) +--- sle11-2009-06-29.orig/arch/x86/kernel/entry_64-xen.S 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/entry_64-xen.S 2009-02-16 16:18:36.000000000 +0100 +@@ -57,7 +57,7 @@ + #include + #include + +-#include "xen_entry.S" ++#include "xen_entry_64.S" + + .code64 + +@@ -275,6 +275,7 @@ ret_from_sys_call: + movl $_TIF_ALLWORK_MASK,%edi + /* edi: flagmask */ + sysret_check: ++ LOCKDEP_SYS_EXIT + GET_THREAD_INFO(%rcx) + XEN_BLOCK_EVENTS(%rsi) + TRACE_IRQS_OFF +@@ -365,6 +366,7 @@ int_ret_from_sys_call: + movl $_TIF_ALLWORK_MASK,%edi + /* edi: mask to check */ + int_with_check: ++ LOCKDEP_SYS_EXIT_IRQ + GET_THREAD_INFO(%rcx) + movl threadinfo_flags(%rcx),%edx + andl %edi,%edx +@@ -516,11 +518,12 @@ END(stub_rt_sigreturn) + + retint_check: + CFI_DEFAULT_STACK adj=1 ++ LOCKDEP_SYS_EXIT_IRQ + movl threadinfo_flags(%rcx),%edx + andl %edi,%edx + CFI_REMEMBER_STATE + jnz retint_careful +-retint_restore_args: ++retint_restore_args: /* return to kernel space */ + movl EFLAGS-REST_SKIP(%rsp), %eax + shr $9, %eax # EAX[0] == IRET_EFLAGS.IF + XEN_GET_VCPU_INFO(%rsi) +@@ -841,7 +844,7 @@ error_call_handler: + movq ORIG_RAX(%rsp),%rsi # get error code + movq $-1,ORIG_RAX(%rsp) + call *%rax +-error_exit: ++error_exit: + RESTORE_REST + /* cli */ + XEN_BLOCK_EVENTS(%rsi) +@@ -849,14 +852,11 @@ error_exit: + GET_THREAD_INFO(%rcx) + testb $3,CS-ARGOFFSET(%rsp) + jz retint_kernel ++ LOCKDEP_SYS_EXIT_IRQ + movl threadinfo_flags(%rcx),%edx + movl $_TIF_WORK_MASK,%edi + andl %edi,%edx + jnz retint_careful +- /* +- * The iret might restore flags: +- */ +- TRACE_IRQS_IRETQ + jmp retint_restore_args + + #if 0 +@@ -1071,7 +1071,7 @@ child_rip: + movq %rsi, %rdi + call *%rax + # exit +- xorl %edi, %edi ++ mov %eax, %edi + call do_exit + CFI_ENDPROC + ENDPROC(child_rip) +--- sle11-2009-06-29.orig/arch/x86/kernel/genapic_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/genapic_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -24,12 +24,21 @@ + #include + #endif + +-/* which logical CPU number maps to which CPU (physical APIC ID) */ +-u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly ++/* ++ * which logical CPU number maps to which CPU (physical APIC ID) ++ * ++ * The following static array is used during kernel startup ++ * and the x86_cpu_to_apicid_ptr contains the address of the ++ * array during this time. Is it zeroed when the per_cpu ++ * data area is removed. ++ */ ++#ifndef CONFIG_XEN ++u8 x86_cpu_to_apicid_init[NR_CPUS] __initdata + = { [0 ... NR_CPUS-1] = BAD_APICID }; +-EXPORT_SYMBOL(x86_cpu_to_apicid); +- +-u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; ++void *x86_cpu_to_apicid_ptr; ++#endif ++DEFINE_PER_CPU(u8, x86_cpu_to_apicid) = BAD_APICID; ++EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid); + + #ifndef CONFIG_XEN + struct genapic __read_mostly *genapic = &apic_flat; +--- sle11-2009-06-29.orig/arch/x86/kernel/head64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/head64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * linux/arch/x86_64/kernel/head64.c -- prepare to run common code ++ * prepare to run common code + * + * Copyright (C) 2000 Andrea Arcangeli SuSE + * +@@ -21,7 +21,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -47,27 +46,16 @@ static void __init clear_bss(void) + } + #endif + +-#define NEW_CL_POINTER 0x228 /* Relative to real mode data */ +-#define OLD_CL_MAGIC_ADDR 0x20 +-#define OLD_CL_MAGIC 0xA33F +-#define OLD_CL_OFFSET 0x22 +- + static void __init copy_bootdata(char *real_mode_data) + { + #ifndef CONFIG_XEN +- unsigned long new_data; + char * command_line; + +- memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE); +- new_data = *(u32 *) (x86_boot_params + NEW_CL_POINTER); +- if (!new_data) { +- if (OLD_CL_MAGIC != *(u16 *)(real_mode_data + OLD_CL_MAGIC_ADDR)) { +- return; +- } +- new_data = __pa(real_mode_data) + *(u16 *)(real_mode_data + OLD_CL_OFFSET); ++ memcpy(&boot_params, real_mode_data, sizeof boot_params); ++ if (boot_params.hdr.cmd_line_ptr) { ++ command_line = __va(boot_params.hdr.cmd_line_ptr); ++ memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + } +- command_line = __va(new_data); +- memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + #else + int max_cmdline; + +@@ -117,7 +105,7 @@ void __init x86_64_start_kernel(char * r + + for (i = 0; i < IDT_ENTRIES; i++) + set_intr_gate(i, early_idt_handler); +- asm volatile("lidt %0" :: "m" (idt_descr)); ++ load_idt((const struct desc_ptr *)&idt_descr); + #endif + + early_printk("Kernel alive\n"); +--- sle11-2009-06-29.orig/arch/x86/kernel/init_task-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/init_task-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -14,11 +14,11 @@ static struct fs_struct init_fs = INIT_F + 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); +- ++#ifdef CONFIG_X86_XEN + #define swapper_pg_dir ((pgd_t *)NULL) ++#endif + struct mm_struct init_mm = INIT_MM(init_mm); + #undef swapper_pg_dir +- + EXPORT_SYMBOL(init_mm); + + /* +@@ -28,7 +28,7 @@ EXPORT_SYMBOL(init_mm); + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +-union thread_union init_thread_union ++union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +@@ -38,14 +38,15 @@ union thread_union init_thread_union + * All other task structs will be allocated on slabs in fork.c + */ + struct task_struct init_task = INIT_TASK(init_task); +- + EXPORT_SYMBOL(init_task); + + #ifndef CONFIG_X86_NO_TSS + /* +- * per-CPU TSS segments. Threads are completely 'soft' on Linux, +- * no more per-task TSS's. +- */ ++ * no more per-task TSS's. The TSS size is kept cacheline-aligned ++ * so they are allowed to end up in the .data.cacheline_aligned ++ * section. Since TSS's are completely CPU-local, we want them ++ * on exact cacheline boundaries, to eliminate cacheline ping-pong. ++ */ + DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS; + #endif + +--- sle11-2009-06-29.orig/arch/x86/kernel/io_apic_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/io_apic_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -427,7 +427,7 @@ static struct irq_cpu_info { + + #define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) + +-#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) ++#define CPU_TO_PACKAGEINDEX(i) (first_cpu(per_cpu(cpu_sibling_map, i))) + + static cpumask_t balance_irq_affinity[NR_IRQS] = { + [0 ... NR_IRQS-1] = CPU_MASK_ALL +@@ -633,7 +633,7 @@ tryanotherirq: + + imbalance = move_this_load; + +- /* For physical_balance case, we accumlated both load ++ /* For physical_balance case, we accumulated both load + * values in the one of the siblings cpu_irq[], + * to use the same code for physical and logical processors + * as much as possible. +@@ -647,7 +647,7 @@ tryanotherirq: + * (A+B)/2 vs B + */ + load = CPU_IRQ(min_loaded) >> 1; +- for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { ++ for_each_cpu_mask(j, per_cpu(cpu_sibling_map, min_loaded)) { + if (load > CPU_IRQ(j)) { + /* This won't change cpu_sibling_map[min_loaded] */ + load = CPU_IRQ(j); +@@ -1018,7 +1018,7 @@ static int EISA_ELCR(unsigned int irq) + #define default_MCA_trigger(idx) (1) + #define default_MCA_polarity(idx) (0) + +-static int __init MPBIOS_polarity(int idx) ++static int MPBIOS_polarity(int idx) + { + int bus = mp_irqs[idx].mpc_srcbus; + int polarity; +@@ -1347,6 +1347,11 @@ static void __init setup_IO_APIC_irqs(vo + continue; + } + ++ if (!first_notcon) { ++ apic_printk(APIC_VERBOSE, " not connected.\n"); ++ first_notcon = 1; ++ } ++ + entry.trigger = irq_trigger(idx); + entry.polarity = irq_polarity(idx); + +@@ -1936,13 +1941,16 @@ __setup("no_timer_check", notimercheck); + static int __init timer_irq_works(void) + { + unsigned long t1 = jiffies; ++ unsigned long flags; + + if (no_timer_check) + return 1; + ++ local_save_flags(flags); + local_irq_enable(); + /* Let ten ticks pass... */ + mdelay((10 * 1000) / HZ); ++ local_irq_restore(flags); + + /* + * Expect a few ticks at least, to be sure some possible +@@ -2223,6 +2231,9 @@ static inline void __init check_timer(vo + { + int apic1, pin1, apic2, pin2; + int vector; ++ unsigned long flags; ++ ++ local_irq_save(flags); + + /* + * get/set the timer IRQ vector: +@@ -2268,7 +2279,7 @@ static inline void __init check_timer(vo + } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); +- return; ++ goto out; + } + clear_IO_APIC_pin(apic1, pin1); + printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to " +@@ -2291,7 +2302,7 @@ static inline void __init check_timer(vo + if (nmi_watchdog == NMI_IO_APIC) { + setup_nmi(); + } +- return; ++ goto out; + } + /* + * Cleanup, just in case ... +@@ -2315,7 +2326,7 @@ static inline void __init check_timer(vo + + if (timer_irq_works()) { + printk(" works.\n"); +- return; ++ goto out; + } + apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); + printk(" failed.\n"); +@@ -2331,11 +2342,13 @@ static inline void __init check_timer(vo + + if (timer_irq_works()) { + printk(" works.\n"); +- return; ++ goto out; + } + printk(" failed :(.\n"); + panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " + "report. Then try booting with the 'noapic' option"); ++out: ++ local_irq_restore(flags); + } + #else + int timer_uses_ioapic_pin_0 = 0; +@@ -2353,6 +2366,14 @@ int timer_uses_ioapic_pin_0 = 0; + + void __init setup_IO_APIC(void) + { ++#ifndef CONFIG_XEN ++ int i; ++ ++ /* Reserve all the system vectors. */ ++ for (i = FIRST_SYSTEM_VECTOR; i < NR_VECTORS; i++) ++ set_bit(i, used_vectors); ++#endif ++ + enable_IO_APIC(); + + if (acpi_ioapic) +@@ -2542,7 +2563,7 @@ void destroy_irq(unsigned int irq) + #endif /* CONFIG_XEN */ + + /* +- * MSI mesage composition ++ * MSI message composition + */ + #if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) + static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) +@@ -2899,6 +2920,25 @@ int io_apic_set_pci_routing (int ioapic, + return 0; + } + ++int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) ++{ ++ int i; ++ ++ if (skip_ioapic_setup) ++ return -1; ++ ++ for (i = 0; i < mp_irq_entries; i++) ++ if (mp_irqs[i].mpc_irqtype == mp_INT && ++ mp_irqs[i].mpc_srcbusirq == bus_irq) ++ break; ++ if (i >= mp_irq_entries) ++ return -1; ++ ++ *trigger = irq_trigger(i); ++ *polarity = irq_polarity(i); ++ return 0; ++} ++ + #endif /* CONFIG_ACPI */ + + static int __init parse_disable_timer_pin_1(char *arg) +--- sle11-2009-06-29.orig/arch/x86/kernel/io_apic_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/io_apic_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #ifdef CONFIG_ACPI + #include + #endif +@@ -584,7 +585,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, + #define default_PCI_trigger(idx) (1) + #define default_PCI_polarity(idx) (1) + +-static int __init MPBIOS_polarity(int idx) ++static int MPBIOS_polarity(int idx) + { + int bus = mp_irqs[idx].mpc_srcbus; + int polarity; +@@ -871,6 +872,10 @@ static void __init setup_IO_APIC_irqs(vo + apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mpc_apicid, pin); + continue; + } ++ if (!first_notcon) { ++ apic_printk(APIC_VERBOSE, " not connected.\n"); ++ first_notcon = 1; ++ } + + irq = pin_2_irq(idx, apic, pin); + add_pin_to_irq(irq, apic, pin); +@@ -881,7 +886,7 @@ static void __init setup_IO_APIC_irqs(vo + } + + if (!first_notcon) +- apic_printk(APIC_VERBOSE," not connected.\n"); ++ apic_printk(APIC_VERBOSE, " not connected.\n"); + } + + #ifndef CONFIG_XEN +@@ -1277,10 +1282,13 @@ void disable_IO_APIC(void) + static int __init timer_irq_works(void) + { + unsigned long t1 = jiffies; ++ unsigned long flags; + ++ local_save_flags(flags); + local_irq_enable(); + /* Let ten ticks pass... */ + mdelay((10 * 1000) / HZ); ++ local_irq_restore(flags); + + /* + * Expect a few ticks at least, to be sure some possible +@@ -1655,6 +1663,9 @@ static inline void check_timer(void) + { + struct irq_cfg *cfg = irq_cfg + 0; + int apic1, pin1, apic2, pin2; ++ unsigned long flags; ++ ++ local_irq_save(flags); + + /* + * get/set the timer IRQ vector: +@@ -1696,7 +1707,7 @@ static inline void check_timer(void) + } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); +- return; ++ goto out; + } + clear_IO_APIC_pin(apic1, pin1); + apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " +@@ -1718,7 +1729,7 @@ static inline void check_timer(void) + if (nmi_watchdog == NMI_IO_APIC) { + setup_nmi(); + } +- return; ++ goto out; + } + /* + * Cleanup, just in case ... +@@ -1741,7 +1752,7 @@ static inline void check_timer(void) + + if (timer_irq_works()) { + apic_printk(APIC_VERBOSE," works.\n"); +- return; ++ goto out; + } + apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); + apic_printk(APIC_VERBOSE," failed.\n"); +@@ -1756,10 +1767,12 @@ static inline void check_timer(void) + + if (timer_irq_works()) { + apic_printk(APIC_VERBOSE," works.\n"); +- return; ++ goto out; + } + apic_printk(APIC_VERBOSE," failed :(.\n"); + panic("IO-APIC + timer doesn't work! Try using the 'noapic' kernel parameter\n"); ++out: ++ local_irq_restore(flags); + } + #else + #define check_timer() ((void)0) +@@ -1775,7 +1788,7 @@ __setup("no_timer_check", notimercheck); + + /* + * +- * IRQ's that are handled by the PIC in the MPS IOAPIC case. ++ * IRQs that are handled by the PIC in the MPS IOAPIC case. + * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. + * Linux doesn't really care, as it's not actually used + * for any interrupt handling anyway. +@@ -1858,7 +1871,7 @@ static struct sysdev_class ioapic_sysdev + static int __init ioapic_init_sysfs(void) + { + struct sys_device * dev; +- int i, size, error = 0; ++ int i, size, error; + + error = sysdev_class_register(&ioapic_sysdev_class); + if (error) +@@ -1867,12 +1880,11 @@ static int __init ioapic_init_sysfs(void + for (i = 0; i < nr_ioapics; i++ ) { + size = sizeof(struct sys_device) + nr_ioapic_registers[i] + * sizeof(struct IO_APIC_route_entry); +- mp_ioapic_data[i] = kmalloc(size, GFP_KERNEL); ++ mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL); + if (!mp_ioapic_data[i]) { + printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); + continue; + } +- memset(mp_ioapic_data[i], 0, size); + dev = &mp_ioapic_data[i]->dev; + dev->id = i; + dev->cls = &ioapic_sysdev_class; +@@ -1933,7 +1945,7 @@ void destroy_irq(unsigned int irq) + #endif /* CONFIG_XEN */ + + /* +- * MSI mesage composition ++ * MSI message composition + */ + #if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN) + static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) +@@ -2043,8 +2055,64 @@ void arch_teardown_msi_irq(unsigned int + destroy_irq(irq); + } + +-#endif /* CONFIG_PCI_MSI */ ++#ifdef CONFIG_DMAR ++#ifdef CONFIG_SMP ++static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask) ++{ ++ struct irq_cfg *cfg = irq_cfg + irq; ++ struct msi_msg msg; ++ unsigned int dest; ++ cpumask_t tmp; ++ ++ cpus_and(tmp, mask, cpu_online_map); ++ if (cpus_empty(tmp)) ++ return; ++ ++ if (assign_irq_vector(irq, mask)) ++ return; ++ ++ cpus_and(tmp, cfg->domain, mask); ++ dest = cpu_mask_to_apicid(tmp); ++ ++ dmar_msi_read(irq, &msg); ++ ++ msg.data &= ~MSI_DATA_VECTOR_MASK; ++ msg.data |= MSI_DATA_VECTOR(cfg->vector); ++ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; ++ msg.address_lo |= MSI_ADDR_DEST_ID(dest); ++ ++ dmar_msi_write(irq, &msg); ++ irq_desc[irq].affinity = mask; ++} ++#endif /* CONFIG_SMP */ ++ ++struct irq_chip dmar_msi_type = { ++ .name = "DMAR_MSI", ++ .unmask = dmar_msi_unmask, ++ .mask = dmar_msi_mask, ++ .ack = ack_apic_edge, ++#ifdef CONFIG_SMP ++ .set_affinity = dmar_msi_set_affinity, ++#endif ++ .retrigger = ioapic_retrigger_irq, ++}; ++ ++int arch_setup_dmar_msi(unsigned int irq) ++{ ++ int ret; ++ struct msi_msg msg; ++ ++ ret = msi_compose_msg(NULL, irq, &msg); ++ if (ret < 0) ++ return ret; ++ dmar_msi_write(irq, &msg); ++ set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq, ++ "edge"); ++ return 0; ++} ++#endif + ++#endif /* CONFIG_PCI_MSI */ + /* + * Hypertransport interrupt support + */ +@@ -2177,8 +2245,27 @@ int io_apic_set_pci_routing (int ioapic, + return 0; + } + +-#endif /* CONFIG_ACPI */ + ++int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) ++{ ++ int i; ++ ++ if (skip_ioapic_setup) ++ return -1; ++ ++ for (i = 0; i < mp_irq_entries; i++) ++ if (mp_irqs[i].mpc_irqtype == mp_INT && ++ mp_irqs[i].mpc_srcbusirq == bus_irq) ++ break; ++ if (i >= mp_irq_entries) ++ return -1; ++ ++ *trigger = irq_trigger(i); ++ *polarity = irq_polarity(i); ++ return 0; ++} ++ ++#endif /* CONFIG_ACPI */ + + #ifndef CONFIG_XEN + /* +@@ -2217,3 +2304,4 @@ void __init setup_ioapic_dest(void) + } + #endif + #endif /* !CONFIG_XEN */ ++ +--- sle11-2009-06-29.orig/arch/x86/kernel/ioport_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/ioport_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/kernel/ioport.c +- * + * This contains the io-permission bitmap code - written by obz, with changes + * by Linus. + */ +--- sle11-2009-06-29.orig/arch/x86/kernel/ioport_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/ioport_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/x86_64/kernel/ioport.c +- * + * This contains the io-permission bitmap code - written by obz, with changes + * by Linus. + */ +--- sle11-2009-06-29.orig/arch/x86/kernel/irq_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/irq_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/kernel/irq.c +- * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This file contains the lowest level x86-specific interrupt +@@ -231,8 +229,6 @@ asmlinkage void do_softirq(void) + + local_irq_restore(flags); + } +- +-EXPORT_SYMBOL(do_softirq); + #endif + + /* +@@ -259,9 +255,17 @@ int show_interrupts(struct seq_file *p, + } + + if (i < NR_IRQS) { ++ unsigned any_count = 0; ++ + spin_lock_irqsave(&irq_desc[i].lock, flags); ++#ifndef CONFIG_SMP ++ any_count = kstat_irqs(i); ++#else ++ for_each_online_cpu(j) ++ any_count |= kstat_cpu(j).irqs[i]; ++#endif + action = irq_desc[i].action; +- if (!action) ++ if (!action && !any_count) + goto skip; + seq_printf(p, "%3d: ",i); + #ifndef CONFIG_SMP +@@ -272,10 +276,12 @@ int show_interrupts(struct seq_file *p, + #endif + seq_printf(p, " %8s", irq_desc[i].chip->name); + seq_printf(p, "-%-8s", irq_desc[i].name); +- seq_printf(p, " %s", action->name); + +- for (action=action->next; action; action = action->next) +- seq_printf(p, ", %s", action->name); ++ if (action) { ++ seq_printf(p, " %s", action->name); ++ while ((action = action->next) != NULL) ++ seq_printf(p, ", %s", action->name); ++ } + + seq_putc(p, '\n'); + skip: +@@ -284,13 +290,46 @@ skip: + seq_printf(p, "NMI: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", nmi_count(j)); +- seq_putc(p, '\n'); ++ seq_printf(p, " Non-maskable interrupts\n"); + #ifdef CONFIG_X86_LOCAL_APIC + seq_printf(p, "LOC: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", + per_cpu(irq_stat,j).apic_timer_irqs); +- seq_putc(p, '\n'); ++ seq_printf(p, " Local timer interrupts\n"); ++#endif ++#ifdef CONFIG_SMP ++ seq_printf(p, "RES: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", ++ per_cpu(irq_stat,j).irq_resched_count); ++ seq_printf(p, " Rescheduling interrupts\n"); ++ seq_printf(p, "CAL: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", ++ per_cpu(irq_stat,j).irq_call_count); ++ seq_printf(p, " function call interrupts\n"); ++#ifndef CONFIG_XEN ++ seq_printf(p, "TLB: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", ++ per_cpu(irq_stat,j).irq_tlb_count); ++ seq_printf(p, " TLB shootdowns\n"); ++#endif ++#endif ++#ifdef CONFIG_X86_MCE ++ seq_printf(p, "TRM: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", ++ per_cpu(irq_stat,j).irq_thermal_count); ++ seq_printf(p, " Thermal event interrupts\n"); ++#endif ++#ifdef CONFIG_X86_LOCAL_APIC ++ seq_printf(p, "SPU: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", ++ per_cpu(irq_stat,j).irq_spurious_count); ++ seq_printf(p, " Spurious interrupts\n"); + #endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); + #if defined(CONFIG_X86_IO_APIC) +--- sle11-2009-06-29.orig/arch/x86/kernel/irq_64-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/irq_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/x86_64/kernel/irq.c +- * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This file contains the lowest level x86_64-specific interrupt +@@ -64,9 +62,17 @@ int show_interrupts(struct seq_file *p, + } + + if (i < NR_IRQS) { ++ unsigned any_count = 0; ++ + spin_lock_irqsave(&irq_desc[i].lock, flags); ++#ifndef CONFIG_SMP ++ any_count = kstat_irqs(i); ++#else ++ for_each_online_cpu(j) ++ any_count |= kstat_cpu(j).irqs[i]; ++#endif + action = irq_desc[i].action; +- if (!action) ++ if (!action && !any_count) + goto skip; + seq_printf(p, "%3d: ",i); + #ifndef CONFIG_SMP +@@ -78,9 +84,11 @@ int show_interrupts(struct seq_file *p, + seq_printf(p, " %8s", irq_desc[i].chip->name); + seq_printf(p, "-%-8s", irq_desc[i].name); + +- seq_printf(p, " %s", action->name); +- for (action=action->next; action; action = action->next) +- seq_printf(p, ", %s", action->name); ++ if (action) { ++ seq_printf(p, " %s", action->name); ++ while ((action = action->next) != NULL) ++ seq_printf(p, ", %s", action->name); ++ } + seq_putc(p, '\n'); + skip: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); +@@ -88,12 +96,44 @@ skip: + seq_printf(p, "NMI: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", cpu_pda(j)->__nmi_count); +- seq_putc(p, '\n'); ++ seq_printf(p, " Non-maskable interrupts\n"); + #ifdef CONFIG_X86_LOCAL_APIC + seq_printf(p, "LOC: "); + for_each_online_cpu(j) + seq_printf(p, "%10u ", cpu_pda(j)->apic_timer_irqs); +- seq_putc(p, '\n'); ++ seq_printf(p, " Local timer interrupts\n"); ++#endif ++#ifdef CONFIG_SMP ++ seq_printf(p, "RES: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", cpu_pda(j)->irq_resched_count); ++ seq_printf(p, " Rescheduling interrupts\n"); ++ seq_printf(p, "CAL: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", cpu_pda(j)->irq_call_count); ++ seq_printf(p, " function call interrupts\n"); ++#ifndef CONFIG_XEN ++ seq_printf(p, "TLB: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", cpu_pda(j)->irq_tlb_count); ++ seq_printf(p, " TLB shootdowns\n"); ++#endif ++#endif ++#ifdef CONFIG_X86_MCE ++ seq_printf(p, "TRM: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", cpu_pda(j)->irq_thermal_count); ++ seq_printf(p, " Thermal event interrupts\n"); ++ seq_printf(p, "THR: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", cpu_pda(j)->irq_threshold_count); ++ seq_printf(p, " Threshold APIC interrupts\n"); ++#endif ++#ifdef CONFIG_X86_LOCAL_APIC ++ seq_printf(p, "SPU: "); ++ for_each_online_cpu(j) ++ seq_printf(p, "%10u ", cpu_pda(j)->irq_spurious_count); ++ seq_printf(p, " Spurious interrupts\n"); + #endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); + } +@@ -211,7 +251,6 @@ asmlinkage void do_softirq(void) + } + local_irq_restore(flags); + } +-EXPORT_SYMBOL(do_softirq); + + #ifndef CONFIG_X86_LOCAL_APIC + /* +--- sle11-2009-06-29.orig/arch/x86/kernel/ldt_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/ldt_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/kernel/ldt.c +- * + * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds + * Copyright (C) 1999 Ingo Molnar + */ +@@ -106,14 +104,14 @@ int init_new_context(struct task_struct + struct mm_struct * old_mm; + int retval = 0; + +- init_MUTEX(&mm->context.sem); ++ mutex_init(&mm->context.lock); + mm->context.size = 0; + mm->context.has_foreign_mappings = 0; + old_mm = current->mm; + if (old_mm && old_mm->context.size > 0) { +- down(&old_mm->context.sem); ++ mutex_lock(&old_mm->context.lock); + retval = copy_ldt(&mm->context, &old_mm->context); +- up(&old_mm->context.sem); ++ mutex_unlock(&old_mm->context.lock); + } + return retval; + } +@@ -149,7 +147,7 @@ static int read_ldt(void __user * ptr, u + if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) + bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; + +- down(&mm->context.sem); ++ mutex_lock(&mm->context.lock); + size = mm->context.size*LDT_ENTRY_SIZE; + if (size > bytecount) + size = bytecount; +@@ -157,7 +155,7 @@ static int read_ldt(void __user * ptr, u + err = 0; + if (copy_to_user(ptr, mm->context.ldt, size)) + err = -EFAULT; +- up(&mm->context.sem); ++ mutex_unlock(&mm->context.lock); + if (err < 0) + goto error_return; + if (size != bytecount) { +@@ -213,7 +211,7 @@ static int write_ldt(void __user * ptr, + goto out; + } + +- down(&mm->context.sem); ++ mutex_lock(&mm->context.lock); + if (ldt_info.entry_number >= mm->context.size) { + error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); + if (error < 0) +@@ -240,7 +238,7 @@ install: + entry_1, entry_2); + + out_unlock: +- up(&mm->context.sem); ++ mutex_unlock(&mm->context.lock); + out: + return error; + } +--- sle11-2009-06-29.orig/arch/x86/kernel/ldt_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/ldt_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/x86_64/kernel/ldt.c +- * + * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds + * Copyright (C) 1999 Ingo Molnar + * Copyright (C) 2002 Andi Kleen +@@ -112,19 +110,14 @@ int init_new_context(struct task_struct + int retval = 0; + + memset(&mm->context, 0, sizeof(mm->context)); +- init_MUTEX(&mm->context.sem); ++ mutex_init(&mm->context.lock); + old_mm = current->mm; + if (old_mm) + mm->context.vdso = old_mm->context.vdso; + if (old_mm && old_mm->context.size > 0) { +- down(&old_mm->context.sem); ++ mutex_lock(&old_mm->context.lock); + retval = copy_ldt(&mm->context, &old_mm->context); +- up(&old_mm->context.sem); +- } +- if (retval == 0) { +- spin_lock(&mm_unpinned_lock); +- list_add(&mm->context.unpinned, &mm_unpinned); +- spin_unlock(&mm_unpinned_lock); ++ mutex_unlock(&old_mm->context.lock); + } + return retval; + } +@@ -148,11 +141,6 @@ void destroy_context(struct mm_struct *m + kfree(mm->context.ldt); + mm->context.size = 0; + } +- if (!PagePinned(virt_to_page(mm->pgd))) { +- spin_lock(&mm_unpinned_lock); +- list_del(&mm->context.unpinned); +- spin_unlock(&mm_unpinned_lock); +- } + } + + static int read_ldt(void __user * ptr, unsigned long bytecount) +@@ -166,7 +154,7 @@ static int read_ldt(void __user * ptr, u + if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) + bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; + +- down(&mm->context.sem); ++ mutex_lock(&mm->context.lock); + size = mm->context.size*LDT_ENTRY_SIZE; + if (size > bytecount) + size = bytecount; +@@ -174,7 +162,7 @@ static int read_ldt(void __user * ptr, u + err = 0; + if (copy_to_user(ptr, mm->context.ldt, size)) + err = -EFAULT; +- up(&mm->context.sem); ++ mutex_unlock(&mm->context.lock); + if (err < 0) + goto error_return; + if (size != bytecount) { +@@ -227,7 +215,7 @@ static int write_ldt(void __user * ptr, + goto out; + } + +- down(&mm->context.sem); ++ mutex_lock(&mm->context.lock); + if (ldt_info.entry_number >= (unsigned)mm->context.size) { + error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); + if (error < 0) +@@ -256,7 +244,7 @@ install: + error = HYPERVISOR_update_descriptor(mach_lp, (unsigned long)((entry_1 | (unsigned long) entry_2 << 32))); + + out_unlock: +- up(&mm->context.sem); ++ mutex_unlock(&mm->context.lock); + out: + return error; + } +--- sle11-2009-06-29.orig/arch/x86/kernel/mpparse_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/mpparse_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1023,7 +1023,7 @@ void __init mp_config_acpi_legacy_irqs ( + + /* + * Use the default configuration for the IRQs 0-15. Unless +- * overriden by (MADT) interrupt source override entries. ++ * overridden by (MADT) interrupt source override entries. + */ + for (i = 0; i < 16; i++) { + int idx; +--- sle11-2009-06-29.orig/arch/x86/kernel/mpparse_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/mpparse_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -57,6 +57,8 @@ unsigned long mp_lapic_addr = 0; + + /* Processor that is doing the boot up */ + unsigned int boot_cpu_id = -1U; ++EXPORT_SYMBOL(boot_cpu_id); ++ + /* Internal processor count */ + unsigned int num_processors __cpuinitdata = 0; + +@@ -87,7 +89,7 @@ static int __init mpf_checksum(unsigned + } + + #ifndef CONFIG_XEN +-static void __cpuinit MP_processor_info (struct mpc_config_processor *m) ++static void __cpuinit MP_processor_info(struct mpc_config_processor *m) + { + int cpu; + cpumask_t tmp_map; +@@ -124,13 +126,24 @@ static void __cpuinit MP_processor_info + cpu = 0; + } + bios_cpu_apicid[cpu] = m->mpc_apicid; +- x86_cpu_to_apicid[cpu] = m->mpc_apicid; ++ /* ++ * We get called early in the the start_kernel initialization ++ * process when the per_cpu data area is not yet setup, so we ++ * use a static array that is removed after the per_cpu data ++ * area is created. ++ */ ++ if (x86_cpu_to_apicid_ptr) { ++ u8 *x86_cpu_to_apicid = (u8 *)x86_cpu_to_apicid_ptr; ++ x86_cpu_to_apicid[cpu] = m->mpc_apicid; ++ } else { ++ per_cpu(x86_cpu_to_apicid, cpu) = m->mpc_apicid; ++ } + + cpu_set(cpu, cpu_possible_map); + cpu_set(cpu, cpu_present_map); + } + #else +-static void __cpuinit MP_processor_info (struct mpc_config_processor *m) ++static void __cpuinit MP_processor_info(struct mpc_config_processor *m) + { + num_processors++; + } +--- sle11-2009-06-29.orig/arch/x86/kernel/pci-dma-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/pci-dma-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -13,14 +13,13 @@ + #include + #include + #include +-#include + #include + #include + #include + #include + #include +-#include +-#include ++#include ++#include + #include + + #ifdef __x86_64__ +@@ -106,27 +105,29 @@ int range_straddles_page_boundary(paddr_ + } + + int +-dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, ++dma_map_sg(struct device *hwdev, struct scatterlist *sgl, int nents, + enum dma_data_direction direction) + { + int i, rc; + + BUG_ON(!valid_dma_direction(direction)); +- WARN_ON(nents == 0 || sg[0].length == 0); ++ WARN_ON(nents == 0 || sgl->length == 0); + + if (swiotlb) { +- rc = swiotlb_map_sg(hwdev, sg, nents, direction); ++ rc = swiotlb_map_sg(hwdev, sgl, nents, direction); + } else { +- for (i = 0; i < nents; i++ ) { +- BUG_ON(!sg[i].page); +- sg[i].dma_address = +- gnttab_dma_map_page(sg[i].page) + sg[i].offset; +- sg[i].dma_length = sg[i].length; ++ struct scatterlist *sg; ++ ++ for_each_sg(sgl, sg, nents, i) { ++ BUG_ON(!sg_page(sg)); ++ sg->dma_address = ++ gnttab_dma_map_page(sg_page(sg)) + sg->offset; ++ sg->dma_length = sg->length; + IOMMU_BUG_ON(address_needs_mapping( +- hwdev, sg[i].dma_address)); ++ hwdev, sg->dma_address)); + IOMMU_BUG_ON(range_straddles_page_boundary( +- page_to_pseudophys(sg[i].page) + sg[i].offset, +- sg[i].length)); ++ page_to_pseudophys(sg_page(sg)) + sg->offset, ++ sg->length)); + } + rc = nents; + } +@@ -137,17 +138,19 @@ dma_map_sg(struct device *hwdev, struct + EXPORT_SYMBOL(dma_map_sg); + + void +-dma_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents, ++dma_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nents, + enum dma_data_direction direction) + { + int i; + + BUG_ON(!valid_dma_direction(direction)); + if (swiotlb) +- swiotlb_unmap_sg(hwdev, sg, nents, direction); ++ swiotlb_unmap_sg(hwdev, sgl, nents, direction); + else { +- for (i = 0; i < nents; i++ ) +- gnttab_dma_unmap_page(sg[i].dma_address); ++ struct scatterlist *sg; ++ ++ for_each_sg(sgl, sg, nents, i) ++ gnttab_dma_unmap_page(sg->dma_address); + } + } + EXPORT_SYMBOL(dma_unmap_sg); +@@ -261,7 +264,8 @@ void dma_free_coherent(struct device *de + { + struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; + int order = get_order(size); +- ++ ++ WARN_ON(irqs_disabled()); /* for portability */ + if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { + int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + +--- sle11-2009-06-29.orig/arch/x86/kernel/process_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/process_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/kernel/process.c +- * + * Copyright (C) 1995 Linus Torvalds + * + * Pentium III FXSR, SSE support +@@ -190,6 +188,10 @@ void cpu_idle(void) + } + } + ++static void do_nothing(void *unused) ++{ ++} ++ + void cpu_idle_wait(void) + { + unsigned int cpu, this_cpu = get_cpu(); +@@ -214,13 +216,20 @@ void cpu_idle_wait(void) + cpu_clear(cpu, map); + } + cpus_and(map, map, cpu_online_map); ++ /* ++ * We waited 1 sec, if a CPU still did not call idle ++ * it may be because it is in idle and not waking up ++ * because it has nothing to do. ++ * Give all the remaining CPUS a kick. ++ */ ++ smp_call_function_mask(map, do_nothing, 0, 0); + } while (!cpus_empty(map)); + + set_cpus_allowed(current, tmp); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + +-void __devinit select_idle_routine(const struct cpuinfo_x86 *c) ++void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) + { + } + +@@ -238,34 +247,52 @@ static int __init idle_setup(char *str) + } + early_param("idle", idle_setup); + +-void show_regs(struct pt_regs * regs) ++void __show_registers(struct pt_regs *regs, int all) + { + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + unsigned long d0, d1, d2, d3, d6, d7; ++ unsigned long esp; ++ unsigned short ss, gs; ++ ++ if (user_mode_vm(regs)) { ++ esp = regs->esp; ++ ss = regs->xss & 0xffff; ++ savesegment(gs, gs); ++ } else { ++ esp = (unsigned long) (®s->esp); ++ savesegment(ss, ss); ++ savesegment(gs, gs); ++ } + + printk("\n"); +- printk("Pid: %d, comm: %20s\n", current->pid, current->comm); +- printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id()); ++ printk("Pid: %d, comm: %s %s (%s %.*s)\n", ++ task_pid_nr(current), current->comm, ++ print_tainted(), init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); ++ ++ printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", ++ 0xffff & regs->xcs, regs->eip, regs->eflags, ++ smp_processor_id()); + print_symbol("EIP is at %s\n", regs->eip); + +- if (user_mode_vm(regs)) +- printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); +- printk(" EFLAGS: %08lx %s (%s %.*s)\n", +- regs->eflags, print_tainted(), init_utsname()->release, +- (int)strcspn(init_utsname()->version, " "), +- init_utsname()->version); + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", +- regs->eax,regs->ebx,regs->ecx,regs->edx); +- printk("ESI: %08lx EDI: %08lx EBP: %08lx", +- regs->esi, regs->edi, regs->ebp); +- printk(" DS: %04x ES: %04x FS: %04x\n", +- 0xffff & regs->xds,0xffff & regs->xes, 0xffff & regs->xfs); ++ regs->eax, regs->ebx, regs->ecx, regs->edx); ++ printk("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", ++ regs->esi, regs->edi, regs->ebp, esp); ++ printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", ++ regs->xds & 0xffff, regs->xes & 0xffff, ++ regs->xfs & 0xffff, gs, ss); ++ ++ if (!all) ++ return; + + cr0 = read_cr0(); + cr2 = read_cr2(); + cr3 = read_cr3(); + cr4 = read_cr4_safe(); +- printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); ++ printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", ++ cr0, cr2, cr3, cr4); + + get_debugreg(d0, 0); + get_debugreg(d1, 1); +@@ -273,10 +300,16 @@ void show_regs(struct pt_regs * regs) + get_debugreg(d3, 3); + printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", + d0, d1, d2, d3); ++ + get_debugreg(d6, 6); + get_debugreg(d7, 7); +- printk("DR6: %08lx DR7: %08lx\n", d6, d7); ++ printk("DR6: %08lx DR7: %08lx\n", ++ d6, d7); ++} + ++void show_regs(struct pt_regs *regs) ++{ ++ __show_registers(regs, 1); + show_trace(NULL, regs, ®s->esp); + } + +--- sle11-2009-06-29.orig/arch/x86/kernel/process_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/process_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/x86-64/kernel/process.c +- * + * Copyright (C) 1995 Linus Torvalds + * + * Pentium III FXSR, SSE support +@@ -41,6 +39,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -172,6 +171,9 @@ void cpu_idle (void) + + if (__get_cpu_var(cpu_idle_state)) + __get_cpu_var(cpu_idle_state) = 0; ++ ++ tick_nohz_stop_sched_tick(); ++ + rmb(); + idle = xen_idle; /* no alternatives */ + if (cpu_is_offline(smp_processor_id())) +@@ -190,12 +192,17 @@ void cpu_idle (void) + __exit_idle(); + } + ++ tick_nohz_restart_sched_tick(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } + } + ++static void do_nothing(void *unused) ++{ ++} ++ + void cpu_idle_wait(void) + { + unsigned int cpu, this_cpu = get_cpu(); +@@ -221,6 +228,13 @@ void cpu_idle_wait(void) + cpu_clear(cpu, map); + } + cpus_and(map, map, cpu_online_map); ++ /* ++ * We waited 1 sec, if a CPU still did not call idle ++ * it may be because it is in idle and not waking up ++ * because it has nothing to do. ++ * Give all the remaining CPUS a kick. ++ */ ++ smp_call_function_mask(map, do_nothing, 0, 0); + } while (!cpus_empty(map)); + + set_cpus_allowed(current, tmp); +@@ -528,7 +542,7 @@ static inline void __switch_to_xtra(stru + * + * Kprobes not supported here. Set the probe on schedule instead. + */ +-__kprobes struct task_struct * ++struct task_struct * + __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + { + struct thread_struct *prev = &prev_p->thread, +--- sle11-2009-06-29.orig/arch/x86/kernel/quirks-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/quirks-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -41,7 +41,353 @@ static void __devinit quirk_intel_irqbal + if (!(config & 0x2)) + pci_write_config_byte(dev, 0xf4, config); + } +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); +-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, ++ quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, ++ quirk_intel_irqbalance); ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, ++ quirk_intel_irqbalance); ++#endif ++ ++#if defined(CONFIG_HPET_TIMER) ++#include ++ ++unsigned long force_hpet_address; ++ ++static enum { ++ NONE_FORCE_HPET_RESUME, ++ OLD_ICH_FORCE_HPET_RESUME, ++ ICH_FORCE_HPET_RESUME, ++ VT8237_FORCE_HPET_RESUME, ++ NVIDIA_FORCE_HPET_RESUME, ++} force_hpet_resume_type; ++ ++static void __iomem *rcba_base; ++ ++static void ich_force_hpet_resume(void) ++{ ++ u32 val; ++ ++ if (!force_hpet_address) ++ return; ++ ++ if (rcba_base == NULL) ++ BUG(); ++ ++ /* read the Function Disable register, dword mode only */ ++ val = readl(rcba_base + 0x3404); ++ if (!(val & 0x80)) { ++ /* HPET disabled in HPTC. Trying to enable */ ++ writel(val | 0x80, rcba_base + 0x3404); ++ } ++ ++ val = readl(rcba_base + 0x3404); ++ if (!(val & 0x80)) ++ BUG(); ++ else ++ printk(KERN_DEBUG "Force enabled HPET at resume\n"); ++ ++ return; ++} ++ ++static void ich_force_enable_hpet(struct pci_dev *dev) ++{ ++ u32 val; ++ u32 uninitialized_var(rcba); ++ int err = 0; ++ ++ if (hpet_address || force_hpet_address) ++ return; ++ ++ pci_read_config_dword(dev, 0xF0, &rcba); ++ rcba &= 0xFFFFC000; ++ if (rcba == 0) { ++ printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n"); ++ return; ++ } ++ ++ /* use bits 31:14, 16 kB aligned */ ++ rcba_base = ioremap_nocache(rcba, 0x4000); ++ if (rcba_base == NULL) { ++ printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n"); ++ return; ++ } ++ ++ /* read the Function Disable register, dword mode only */ ++ val = readl(rcba_base + 0x3404); ++ ++ if (val & 0x80) { ++ /* HPET is enabled in HPTC. Just not reported by BIOS */ ++ val = val & 0x3; ++ force_hpet_address = 0xFED00000 | (val << 12); ++ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", ++ force_hpet_address); ++ iounmap(rcba_base); ++ return; ++ } ++ ++ /* HPET disabled in HPTC. Trying to enable */ ++ writel(val | 0x80, rcba_base + 0x3404); ++ ++ val = readl(rcba_base + 0x3404); ++ if (!(val & 0x80)) { ++ err = 1; ++ } else { ++ val = val & 0x3; ++ force_hpet_address = 0xFED00000 | (val << 12); ++ } ++ ++ if (err) { ++ force_hpet_address = 0; ++ iounmap(rcba_base); ++ printk(KERN_DEBUG "Failed to force enable HPET\n"); ++ } else { ++ force_hpet_resume_type = ICH_FORCE_HPET_RESUME; ++ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", ++ force_hpet_address); ++ } ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, ++ ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, ++ ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, ++ ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, ++ ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, ++ ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, ++ ich_force_enable_hpet); ++ ++ ++static struct pci_dev *cached_dev; ++ ++static void old_ich_force_hpet_resume(void) ++{ ++ u32 val; ++ u32 uninitialized_var(gen_cntl); ++ ++ if (!force_hpet_address || !cached_dev) ++ return; ++ ++ pci_read_config_dword(cached_dev, 0xD0, &gen_cntl); ++ gen_cntl &= (~(0x7 << 15)); ++ gen_cntl |= (0x4 << 15); ++ ++ pci_write_config_dword(cached_dev, 0xD0, gen_cntl); ++ pci_read_config_dword(cached_dev, 0xD0, &gen_cntl); ++ val = gen_cntl >> 15; ++ val &= 0x7; ++ if (val == 0x4) ++ printk(KERN_DEBUG "Force enabled HPET at resume\n"); ++ else ++ BUG(); ++} ++ ++static void old_ich_force_enable_hpet(struct pci_dev *dev) ++{ ++ u32 val; ++ u32 uninitialized_var(gen_cntl); ++ ++ if (hpet_address || force_hpet_address) ++ return; ++ ++ pci_read_config_dword(dev, 0xD0, &gen_cntl); ++ /* ++ * Bit 17 is HPET enable bit. ++ * Bit 16:15 control the HPET base address. ++ */ ++ val = gen_cntl >> 15; ++ val &= 0x7; ++ if (val & 0x4) { ++ val &= 0x3; ++ force_hpet_address = 0xFED00000 | (val << 12); ++ printk(KERN_DEBUG "HPET at base address 0x%lx\n", ++ force_hpet_address); ++ return; ++ } ++ ++ /* ++ * HPET is disabled. Trying enabling at FED00000 and check ++ * whether it sticks ++ */ ++ gen_cntl &= (~(0x7 << 15)); ++ gen_cntl |= (0x4 << 15); ++ pci_write_config_dword(dev, 0xD0, gen_cntl); ++ ++ pci_read_config_dword(dev, 0xD0, &gen_cntl); ++ ++ val = gen_cntl >> 15; ++ val &= 0x7; ++ if (val & 0x4) { ++ /* HPET is enabled in HPTC. Just not reported by BIOS */ ++ val &= 0x3; ++ force_hpet_address = 0xFED00000 | (val << 12); ++ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", ++ force_hpet_address); ++ cached_dev = dev; ++ force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME; ++ return; ++ } ++ ++ printk(KERN_DEBUG "Failed to force enable HPET\n"); ++} ++ ++/* ++ * Undocumented chipset features. Make sure that the user enforced ++ * this. ++ */ ++static void old_ich_force_enable_hpet_user(struct pci_dev *dev) ++{ ++ if (hpet_force_user) ++ old_ich_force_enable_hpet(dev); ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, ++ old_ich_force_enable_hpet_user); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, ++ old_ich_force_enable_hpet_user); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, ++ old_ich_force_enable_hpet_user); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, ++ old_ich_force_enable_hpet_user); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, ++ old_ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12, ++ old_ich_force_enable_hpet); ++ ++ ++static void vt8237_force_hpet_resume(void) ++{ ++ u32 val; ++ ++ if (!force_hpet_address || !cached_dev) ++ return; ++ ++ val = 0xfed00000 | 0x80; ++ pci_write_config_dword(cached_dev, 0x68, val); ++ ++ pci_read_config_dword(cached_dev, 0x68, &val); ++ if (val & 0x80) ++ printk(KERN_DEBUG "Force enabled HPET at resume\n"); ++ else ++ BUG(); ++} ++ ++static void vt8237_force_enable_hpet(struct pci_dev *dev) ++{ ++ u32 uninitialized_var(val); ++ ++ if (!hpet_force_user || hpet_address || force_hpet_address) ++ return; ++ ++ pci_read_config_dword(dev, 0x68, &val); ++ /* ++ * Bit 7 is HPET enable bit. ++ * Bit 31:10 is HPET base address (contrary to what datasheet claims) ++ */ ++ if (val & 0x80) { ++ force_hpet_address = (val & ~0x3ff); ++ printk(KERN_DEBUG "HPET at base address 0x%lx\n", ++ force_hpet_address); ++ return; ++ } ++ ++ /* ++ * HPET is disabled. Trying enabling at FED00000 and check ++ * whether it sticks ++ */ ++ val = 0xfed00000 | 0x80; ++ pci_write_config_dword(dev, 0x68, val); ++ ++ pci_read_config_dword(dev, 0x68, &val); ++ if (val & 0x80) { ++ force_hpet_address = (val & ~0x3ff); ++ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", ++ force_hpet_address); ++ cached_dev = dev; ++ force_hpet_resume_type = VT8237_FORCE_HPET_RESUME; ++ return; ++ } ++ ++ printk(KERN_DEBUG "Failed to force enable HPET\n"); ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, ++ vt8237_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, ++ vt8237_force_enable_hpet); ++ ++/* ++ * Undocumented chipset feature taken from LinuxBIOS. ++ */ ++static void nvidia_force_hpet_resume(void) ++{ ++ pci_write_config_dword(cached_dev, 0x44, 0xfed00001); ++ printk(KERN_DEBUG "Force enabled HPET at resume\n"); ++} ++ ++static void nvidia_force_enable_hpet(struct pci_dev *dev) ++{ ++ u32 uninitialized_var(val); ++ ++ if (!hpet_force_user || hpet_address || force_hpet_address) ++ return; ++ ++ pci_write_config_dword(dev, 0x44, 0xfed00001); ++ pci_read_config_dword(dev, 0x44, &val); ++ force_hpet_address = val & 0xfffffffe; ++ force_hpet_resume_type = NVIDIA_FORCE_HPET_RESUME; ++ printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", ++ force_hpet_address); ++ cached_dev = dev; ++ return; ++} ++ ++/* ISA Bridges */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0050, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0051, ++ nvidia_force_enable_hpet); ++ ++/* LPC bridges */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0360, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0361, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0362, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0363, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0364, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0365, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0366, ++ nvidia_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0367, ++ nvidia_force_enable_hpet); ++ ++void force_hpet_resume(void) ++{ ++ switch (force_hpet_resume_type) { ++ case ICH_FORCE_HPET_RESUME: ++ return ich_force_hpet_resume(); ++ ++ case OLD_ICH_FORCE_HPET_RESUME: ++ return old_ich_force_hpet_resume(); ++ ++ case VT8237_FORCE_HPET_RESUME: ++ return vt8237_force_hpet_resume(); ++ ++ case NVIDIA_FORCE_HPET_RESUME: ++ return nvidia_force_hpet_resume(); ++ ++ default: ++ break; ++ } ++} ++ + #endif +--- sle11-2009-06-29.orig/arch/x86/kernel/setup64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -27,11 +26,12 @@ + #include + #include + #include ++#include + #ifdef CONFIG_XEN + #include + #endif + +-char x86_boot_params[BOOT_PARAM_SIZE] __initdata; ++struct boot_params __initdata boot_params; + + cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; + +@@ -159,8 +159,8 @@ static void switch_pt(void) + + static void __cpuinit cpu_gdt_init(const struct desc_ptr *gdt_descr) + { +- asm volatile("lgdt %0" :: "m" (*gdt_descr)); +- asm volatile("lidt %0" :: "m" (idt_descr)); ++ load_gdt(gdt_descr); ++ load_idt(idt_descr); + } + #endif + +@@ -252,6 +252,14 @@ void __cpuinit check_efer(void) + + unsigned long kernel_eflags; + ++#ifndef CONFIG_X86_NO_TSS ++/* ++ * Copies of the original ist values from the tss are only accessed during ++ * debugging, no special alignment required. ++ */ ++DEFINE_PER_CPU(struct orig_ist, orig_ist); ++#endif ++ + /* + * cpu_init() initializes state that is per-CPU. Some data is already + * initialized (naturally) in the bootstrap process, such as the GDT +--- sle11-2009-06-29.orig/arch/x86/kernel/setup_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/kernel/setup.c +- * + * Copyright (C) 1995 Linus Torvalds + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 +@@ -70,6 +68,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_XEN + #include +@@ -80,13 +79,14 @@ static struct notifier_block xen_panic_b + xen_panic_event, NULL, 0 /* try to go last */ + }; + +-int disable_pse __devinitdata = 0; ++int disable_pse __cpuinitdata = 0; + + /* + * Machine setup.. + */ + extern struct resource code_resource; + extern struct resource data_resource; ++extern struct resource bss_resource; + + /* cpu data as detected by the assembly code in head.S */ + struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; +@@ -98,9 +98,6 @@ unsigned long mmu_cr4_features; + + /* for MCA, but anyone else can use it if they want */ + unsigned int machine_id; +-#ifdef CONFIG_MCA +-EXPORT_SYMBOL(machine_id); +-#endif + unsigned int machine_submodel_id; + unsigned int BIOS_revision; + unsigned int mca_pentium_flag; +@@ -121,7 +118,7 @@ EXPORT_SYMBOL(apm_info); + struct edid_info edid_info; + EXPORT_SYMBOL_GPL(edid_info); + #ifndef CONFIG_XEN +-#define copy_edid() (edid_info = EDID_INFO) ++#define copy_edid() (edid_info = boot_params.edid_info) + #endif + struct ist_info ist_info; + #if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ +@@ -170,10 +167,11 @@ EXPORT_SYMBOL(edd); + */ + static inline void copy_edd(void) + { +- memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); +- memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); +- edd.mbr_signature_nr = EDD_MBR_SIG_NR; +- edd.edd_info_nr = EDD_NR; ++ memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer, ++ sizeof(edd.mbr_signature)); ++ memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info)); ++ edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries; ++ edd.edd_info_nr = boot_params.eddbuf_entries; + } + #endif + #else +@@ -416,6 +414,53 @@ extern unsigned long __init setup_memory + extern void zone_sizes_init(void); + #endif /* !CONFIG_NEED_MULTIPLE_NODES */ + ++static inline unsigned long long get_total_mem(void) ++{ ++ unsigned long long total; ++ ++ total = max_low_pfn - min_low_pfn; ++#ifdef CONFIG_HIGHMEM ++ total += highend_pfn - highstart_pfn; ++#endif ++ ++ return total << PAGE_SHIFT; ++} ++ ++#ifdef CONFIG_KEXEC ++#ifndef CONFIG_XEN ++static void __init reserve_crashkernel(void) ++{ ++ unsigned long long total_mem; ++ unsigned long long crash_size, crash_base; ++ int ret; ++ ++ total_mem = get_total_mem(); ++ ++ ret = parse_crashkernel(boot_command_line, total_mem, ++ &crash_size, &crash_base); ++ if (ret == 0 && crash_size > 0) { ++ if (crash_base > 0) { ++ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " ++ "for crashkernel (System RAM: %ldMB)\n", ++ (unsigned long)(crash_size >> 20), ++ (unsigned long)(crash_base >> 20), ++ (unsigned long)(total_mem >> 20)); ++ crashk_res.start = crash_base; ++ crashk_res.end = crash_base + crash_size - 1; ++ reserve_bootmem(crash_base, crash_size); ++ } else ++ printk(KERN_INFO "crashkernel reservation failed - " ++ "you have to specify a base address\n"); ++ } ++} ++#else ++#define reserve_crashkernel xen_machine_kexec_setup_resources ++#endif ++#else ++static inline void __init reserve_crashkernel(void) ++{} ++#endif ++ + void __init setup_bootmem_allocator(void) + { + unsigned long bootmap_size; +@@ -471,30 +516,25 @@ void __init setup_bootmem_allocator(void + + #ifdef CONFIG_BLK_DEV_INITRD + if (xen_start_info->mod_start) { +- if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { +- /*reserve_bootmem(INITRD_START, INITRD_SIZE);*/ +- initrd_start = INITRD_START + PAGE_OFFSET; +- initrd_end = initrd_start+INITRD_SIZE; ++ unsigned long ramdisk_image = __pa(xen_start_info->mod_start); ++ unsigned long ramdisk_size = xen_start_info->mod_len; ++ unsigned long ramdisk_end = ramdisk_image + ramdisk_size; ++ unsigned long end_of_lowmem = max_low_pfn << PAGE_SHIFT; ++ ++ if (ramdisk_end <= end_of_lowmem) { ++ /*reserve_bootmem(ramdisk_image, ramdisk_size);*/ ++ initrd_start = ramdisk_image + PAGE_OFFSET; ++ initrd_end = initrd_start+ramdisk_size; + initrd_below_start_ok = 1; +- } +- else { ++ } else { + printk(KERN_ERR "initrd extends beyond end of memory " +- "(0x%08lx > 0x%08lx)\ndisabling initrd\n", +- INITRD_START + INITRD_SIZE, +- max_low_pfn << PAGE_SHIFT); ++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n", ++ ramdisk_end, end_of_lowmem); + initrd_start = 0; + } + } + #endif +-#ifdef CONFIG_KEXEC +-#ifdef CONFIG_XEN +- xen_machine_kexec_setup_resources(); +-#else +- if (crashk_res.start != crashk_res.end) +- reserve_bootmem(crashk_res.start, +- crashk_res.end - crashk_res.start + 1); +-#endif +-#endif ++ reserve_crashkernel(); + } + + /* +@@ -572,7 +612,8 @@ void __init setup_arch(char **cmdline_p) + * the system table is valid. If not, then initialize normally. + */ + #ifdef CONFIG_EFI +- if ((LOADER_TYPE == 0x50) && EFI_SYSTAB) ++ if ((boot_params.hdr.type_of_loader == 0x50) && ++ boot_params.efi_info.efi_systab) + efi_enabled = 1; + #endif + +@@ -580,18 +621,18 @@ void __init setup_arch(char **cmdline_p) + properly. Setting ROOT_DEV to default to /dev/ram0 breaks initrd. + */ + ROOT_DEV = MKDEV(UNNAMED_MAJOR,0); +- screen_info = SCREEN_INFO; ++ screen_info = boot_params.screen_info; + copy_edid(); +- apm_info.bios = APM_BIOS_INFO; +- ist_info = IST_INFO; +- saved_videomode = VIDEO_MODE; +- if( SYS_DESC_TABLE.length != 0 ) { +- set_mca_bus(SYS_DESC_TABLE.table[3] & 0x2); +- machine_id = SYS_DESC_TABLE.table[0]; +- machine_submodel_id = SYS_DESC_TABLE.table[1]; +- BIOS_revision = SYS_DESC_TABLE.table[2]; ++ apm_info.bios = boot_params.apm_bios_info; ++ ist_info = boot_params.ist_info; ++ saved_videomode = boot_params.hdr.vid_mode; ++ if( boot_params.sys_desc_table.length != 0 ) { ++ set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2); ++ machine_id = boot_params.sys_desc_table.table[0]; ++ machine_submodel_id = boot_params.sys_desc_table.table[1]; ++ BIOS_revision = boot_params.sys_desc_table.table[2]; + } +- bootloader_type = LOADER_TYPE; ++ bootloader_type = boot_params.hdr.type_of_loader; + + if (is_initial_xendomain()) { + const struct dom0_vga_console_info *info = +@@ -606,9 +647,9 @@ void __init setup_arch(char **cmdline_p) + screen_info.orig_video_isVGA = 0; + + #ifdef CONFIG_BLK_DEV_RAM +- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; +- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); +- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); ++ rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK; ++ rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0); ++ rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0); + #endif + + ARCH_SETUP +@@ -621,7 +662,7 @@ void __init setup_arch(char **cmdline_p) + + copy_edd(); + +- if (!MOUNT_ROOT_RDONLY) ++ if (!boot_params.hdr.root_flags) + root_mountflags &= ~MS_RDONLY; + init_mm.start_code = (unsigned long) _text; + init_mm.end_code = (unsigned long) _etext; +@@ -633,6 +674,8 @@ void __init setup_arch(char **cmdline_p) + code_resource.end = virt_to_phys(_etext)-1; + data_resource.start = virt_to_phys(_etext); + data_resource.end = virt_to_phys(_edata)-1; ++ bss_resource.start = virt_to_phys(&__bss_start); ++ bss_resource.end = virt_to_phys(&__bss_stop)-1; + + if ((i = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE) + i = COMMAND_LINE_SIZE; +@@ -661,7 +704,7 @@ void __init setup_arch(char **cmdline_p) + /* + * NOTE: before this point _nobody_ is allowed to allocate + * any memory using the bootmem allocator. Although the +- * alloctor is now initialised only the first 8Mb of the kernel ++ * allocator is now initialised only the first 8Mb of the kernel + * virtual address space has been mapped. All allocations before + * paging_init() has completed must use the alloc_bootmem_low_pages() + * variant (which allocates DMA'able memory) and care must be taken +@@ -784,10 +827,8 @@ void __init setup_arch(char **cmdline_p) + acpi_boot_table_init(); + #endif + +-#ifdef CONFIG_PCI +-#ifdef CONFIG_X86_IO_APIC +- check_acpi_pci(); /* Checks more than just ACPI actually */ +-#endif ++#if defined(CONFIG_PCI) && !defined(CONFIG_XEN) ++ early_quirks(); + #endif + + #ifdef CONFIG_ACPI +--- sle11-2009-06-29.orig/arch/x86/kernel/setup_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,10 +1,5 @@ + /* +- * linux/arch/x86-64/kernel/setup.c +- * + * Copyright (C) 1995 Linus Torvalds +- * +- * Nov 2001 Dave Jones +- * Forked from i386 setup code. + */ + + /* +@@ -57,13 +52,13 @@ + #include + #include + #include +-#include + #include + #include + #include + #include + #include + #include ++#include + #ifdef CONFIG_XEN + #include + #include +@@ -180,6 +175,12 @@ struct resource code_resource = { + .end = 0, + .flags = IORESOURCE_RAM, + }; ++struct resource bss_resource = { ++ .name = "Kernel bss", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_RAM, ++}; + + #ifdef CONFIG_PROC_VMCORE + /* elfcorehdr= specifies the location of elf core header +@@ -231,10 +232,11 @@ EXPORT_SYMBOL(edd); + */ + static inline void copy_edd(void) + { +- memcpy(edd.mbr_signature, EDD_MBR_SIGNATURE, sizeof(edd.mbr_signature)); +- memcpy(edd.edd_info, EDD_BUF, sizeof(edd.edd_info)); +- edd.mbr_signature_nr = EDD_MBR_SIG_NR; +- edd.edd_info_nr = EDD_NR; ++ memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer, ++ sizeof(edd.mbr_signature)); ++ memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info)); ++ edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries; ++ edd.edd_info_nr = boot_params.eddbuf_entries; + } + #endif + #else +@@ -243,6 +245,41 @@ static inline void copy_edd(void) + } + #endif + ++#ifdef CONFIG_KEXEC ++#ifndef CONFIG_XEN ++static void __init reserve_crashkernel(void) ++{ ++ unsigned long long free_mem; ++ unsigned long long crash_size, crash_base; ++ int ret; ++ ++ free_mem = ((unsigned long long)max_low_pfn - min_low_pfn) << PAGE_SHIFT; ++ ++ ret = parse_crashkernel(boot_command_line, free_mem, ++ &crash_size, &crash_base); ++ if (ret == 0 && crash_size) { ++ if (crash_base > 0) { ++ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " ++ "for crashkernel (System RAM: %ldMB)\n", ++ (unsigned long)(crash_size >> 20), ++ (unsigned long)(crash_base >> 20), ++ (unsigned long)(free_mem >> 20)); ++ crashk_res.start = crash_base; ++ crashk_res.end = crash_base + crash_size - 1; ++ reserve_bootmem(crash_base, crash_size); ++ } else ++ printk(KERN_INFO "crashkernel reservation failed - " ++ "you have to specify a base address\n"); ++ } ++} ++#else ++#define reserve_crashkernel xen_machine_kexec_setup_resources ++#endif ++#else ++static inline void __init reserve_crashkernel(void) ++{} ++#endif ++ + #ifndef CONFIG_XEN + #define EBDA_ADDR_POINTER 0x40E + +@@ -283,7 +320,7 @@ void __init setup_arch(char **cmdline_p) + atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); +- screen_info = SCREEN_INFO; ++ screen_info = boot_params.screen_info; + + if (is_initial_xendomain()) { + const struct dom0_vga_console_info *info = +@@ -306,22 +343,22 @@ void __init setup_arch(char **cmdline_p) + #else + printk(KERN_INFO "Command line: %s\n", boot_command_line); + +- ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); +- screen_info = SCREEN_INFO; +- edid_info = EDID_INFO; ++ ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev); ++ screen_info = boot_params.screen_info; ++ edid_info = boot_params.edid_info; + #endif /* !CONFIG_XEN */ +- saved_video_mode = SAVED_VIDEO_MODE; +- bootloader_type = LOADER_TYPE; ++ saved_video_mode = boot_params.hdr.vid_mode; ++ bootloader_type = boot_params.hdr.type_of_loader; + + #ifdef CONFIG_BLK_DEV_RAM +- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; +- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); +- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); ++ rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK; ++ rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0); ++ rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0); + #endif + setup_memory_region(); + copy_edd(); + +- if (!MOUNT_ROOT_RDONLY) ++ if (!boot_params.hdr.root_flags) + root_mountflags &= ~MS_RDONLY; + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; +@@ -332,6 +369,8 @@ void __init setup_arch(char **cmdline_p) + code_resource.end = virt_to_phys(&_etext)-1; + data_resource.start = virt_to_phys(&_etext); + data_resource.end = virt_to_phys(&_edata)-1; ++ bss_resource.start = virt_to_phys(&__bss_start); ++ bss_resource.end = virt_to_phys(&__bss_stop)-1; + + early_identify_cpu(&boot_cpu_data); + +@@ -359,6 +398,11 @@ void __init setup_arch(char **cmdline_p) + if (is_initial_xendomain()) + dmi_scan_machine(); + ++#if defined(CONFIG_SMP) && !defined(CONFIG_XEN) ++ /* setup to use the static apicid table during kernel startup */ ++ x86_cpu_to_apicid_ptr = (void *)&x86_cpu_to_apicid_init; ++#endif ++ + /* How many end-of-memory variables you have, grandma! */ + max_low_pfn = end_pfn; + max_pfn = end_pfn; +@@ -423,52 +467,37 @@ void __init setup_arch(char **cmdline_p) + */ + acpi_reserve_bootmem(); + #endif +-#ifdef CONFIG_XEN + #ifdef CONFIG_BLK_DEV_INITRD ++#ifdef CONFIG_XEN + if (xen_start_info->mod_start) { +- if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { +- /*reserve_bootmem_generic(INITRD_START, INITRD_SIZE);*/ +- initrd_start = INITRD_START + PAGE_OFFSET; +- initrd_end = initrd_start+INITRD_SIZE; ++ unsigned long ramdisk_image = __pa(xen_start_info->mod_start); ++ unsigned long ramdisk_size = xen_start_info->mod_len; ++#else ++ if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { ++ unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; ++ unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; ++#endif ++ unsigned long ramdisk_end = ramdisk_image + ramdisk_size; ++ unsigned long end_of_mem = end_pfn << PAGE_SHIFT; ++ ++ if (ramdisk_end <= end_of_mem) { ++#ifndef CONFIG_XEN ++ reserve_bootmem_generic(ramdisk_image, ramdisk_size); ++#endif ++ initrd_start = ramdisk_image + PAGE_OFFSET; ++ initrd_end = initrd_start+ramdisk_size; ++#ifdef CONFIG_XEN + initrd_below_start_ok = 1; +- } else { +- printk(KERN_ERR "initrd extends beyond end of memory " +- "(0x%08lx > 0x%08lx)\ndisabling initrd\n", +- (unsigned long)(INITRD_START + INITRD_SIZE), +- (unsigned long)(end_pfn << PAGE_SHIFT)); +- initrd_start = 0; +- } +- } + #endif +-#else /* CONFIG_XEN */ +-#ifdef CONFIG_BLK_DEV_INITRD +- if (LOADER_TYPE && INITRD_START) { +- if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { +- reserve_bootmem_generic(INITRD_START, INITRD_SIZE); +- initrd_start = INITRD_START + PAGE_OFFSET; +- initrd_end = initrd_start+INITRD_SIZE; +- } +- else { ++ } else { + printk(KERN_ERR "initrd extends beyond end of memory " +- "(0x%08lx > 0x%08lx)\ndisabling initrd\n", +- (unsigned long)(INITRD_START + INITRD_SIZE), +- (unsigned long)(end_pfn << PAGE_SHIFT)); ++ "(0x%08lx > 0x%08lx)\ndisabling initrd\n", ++ ramdisk_end, end_of_mem); + initrd_start = 0; + } + } + #endif +-#endif /* !CONFIG_XEN */ +-#ifdef CONFIG_KEXEC +-#ifdef CONFIG_XEN +- xen_machine_kexec_setup_resources(); +-#else +- if (crashk_res.start != crashk_res.end) { +- reserve_bootmem_generic(crashk_res.start, +- crashk_res.end - crashk_res.start + 1); +- } +-#endif +-#endif +- ++ reserve_crashkernel(); + paging_init(); + #ifdef CONFIG_X86_LOCAL_APIC + /* +@@ -783,7 +812,7 @@ static void __init amd_detect_cmp(struct + but in the same order as the HT nodeids. + If that doesn't result in a usable node fall back to the + path for the previous case. */ +- int ht_nodeid = apicid - (cpu_data[0].phys_proc_id << bits); ++ int ht_nodeid = apicid - (cpu_data(0).phys_proc_id << bits); + if (ht_nodeid >= 0 && + apicid_to_node[ht_nodeid] != NUMA_NO_NODE) + node = apicid_to_node[ht_nodeid]; +@@ -798,6 +827,39 @@ static void __init amd_detect_cmp(struct + #endif + } + ++#define ENABLE_C1E_MASK 0x18000000 ++#define CPUID_PROCESSOR_SIGNATURE 1 ++#define CPUID_XFAM 0x0ff00000 ++#define CPUID_XFAM_K8 0x00000000 ++#define CPUID_XFAM_10H 0x00100000 ++#define CPUID_XFAM_11H 0x00200000 ++#define CPUID_XMOD 0x000f0000 ++#define CPUID_XMOD_REV_F 0x00040000 ++ ++#ifndef CONFIG_XEN ++/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */ ++static __cpuinit int amd_apic_timer_broken(void) ++{ ++ u32 lo, hi; ++ u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); ++ switch (eax & CPUID_XFAM) { ++ case CPUID_XFAM_K8: ++ if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F) ++ break; ++ case CPUID_XFAM_10H: ++ case CPUID_XFAM_11H: ++ rdmsr(MSR_K8_ENABLE_C1E, lo, hi); ++ if (lo & ENABLE_C1E_MASK) ++ return 1; ++ break; ++ default: ++ /* err on the side of caution */ ++ return 1; ++ } ++ return 0; ++} ++#endif ++ + static void __cpuinit init_amd(struct cpuinfo_x86 *c) + { + unsigned level; +@@ -827,7 +889,7 @@ static void __cpuinit init_amd(struct cp + level = cpuid_eax(1); + if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58)) + set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); +- if (c->x86 == 0x10) ++ if (c->x86 == 0x10 || c->x86 == 0x11) + set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability); + + /* Enable workaround for FXSAVE leak */ +@@ -869,6 +931,11 @@ static void __cpuinit init_amd(struct cp + /* Family 10 doesn't support C states in MWAIT so don't use it */ + if (c->x86 == 0x10 && !force_mwait) + clear_bit(X86_FEATURE_MWAIT, &c->x86_capability); ++ ++#ifndef CONFIG_XEN ++ if (amd_apic_timer_broken()) ++ disable_apic_timer = 1; ++#endif + } + + static void __cpuinit detect_ht(struct cpuinfo_x86 *c) +@@ -1179,6 +1246,7 @@ void __cpuinit print_cpu_info(struct cpu + static int show_cpuinfo(struct seq_file *m, void *v) + { + struct cpuinfo_x86 *c = v; ++ int cpu = 0; + + /* + * These flag bits must match the definitions in . +@@ -1188,7 +1256,7 @@ static int show_cpuinfo(struct seq_file + * applications want to get the raw CPUID data, they should access + * /dev/cpu//cpuid instead. + */ +- static char *x86_cap_flags[] = { ++ static const char *const x86_cap_flags[] = { + /* Intel-defined */ + "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", +@@ -1219,7 +1287,7 @@ static int show_cpuinfo(struct seq_file + /* Intel-defined (#2) */ + "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est", + "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, +- NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", ++ NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* VIA/Cyrix/Centaur-defined */ +@@ -1229,10 +1297,10 @@ static int show_cpuinfo(struct seq_file + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* AMD-defined (#2) */ +- "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy", +- "altmovcr8", "abm", "sse4a", +- "misalignsse", "3dnowprefetch", +- "osvw", "ibs", NULL, NULL, NULL, NULL, ++ "lahf_lm", "cmp_legacy", "svm", "extapic", ++ "cr8_legacy", "abm", "sse4a", "misalignsse", ++ "3dnowprefetch", "osvw", "ibs", "sse5", ++ "skinit", "wdt", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +@@ -1242,7 +1310,7 @@ static int show_cpuinfo(struct seq_file + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + }; +- static char *x86_power_flags[] = { ++ static const char *const x86_power_flags[] = { + "ts", /* temperature sensor */ + "fid", /* frequency id control */ + "vid", /* voltage id control */ +@@ -1257,8 +1325,7 @@ static int show_cpuinfo(struct seq_file + + + #ifdef CONFIG_SMP +- if (!cpu_online(c-cpu_data)) +- return 0; ++ cpu = c->cpu_index; + #endif + + seq_printf(m,"processor\t: %u\n" +@@ -1266,7 +1333,7 @@ static int show_cpuinfo(struct seq_file + "cpu family\t: %d\n" + "model\t\t: %d\n" + "model name\t: %s\n", +- (unsigned)(c-cpu_data), ++ (unsigned)cpu, + c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown", + c->x86, + (int)c->x86_model, +@@ -1278,7 +1345,7 @@ static int show_cpuinfo(struct seq_file + seq_printf(m, "stepping\t: unknown\n"); + + if (cpu_has(c,X86_FEATURE_TSC)) { +- unsigned int freq = cpufreq_quick_get((unsigned)(c-cpu_data)); ++ unsigned int freq = cpufreq_quick_get((unsigned)cpu); + if (!freq) + freq = cpu_khz; + seq_printf(m, "cpu MHz\t\t: %u.%03u\n", +@@ -1291,9 +1358,9 @@ static int show_cpuinfo(struct seq_file + + #ifdef CONFIG_SMP + if (smp_num_siblings * c->x86_max_cores > 1) { +- int cpu = c - cpu_data; + seq_printf(m, "physical id\t: %d\n", c->phys_proc_id); +- seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu])); ++ seq_printf(m, "siblings\t: %d\n", ++ cpus_weight(per_cpu(cpu_core_map, cpu))); + seq_printf(m, "core id\t\t: %d\n", c->cpu_core_id); + seq_printf(m, "cpu cores\t: %d\n", c->booted_cores); + } +@@ -1348,12 +1415,16 @@ static int show_cpuinfo(struct seq_file + + static void *c_start(struct seq_file *m, loff_t *pos) + { +- return *pos < NR_CPUS ? cpu_data + *pos : NULL; ++ if (*pos == 0) /* just in case, cpu 0 is not the first */ ++ *pos = first_cpu(cpu_online_map); ++ if ((*pos) < NR_CPUS && cpu_online(*pos)) ++ return &cpu_data(*pos); ++ return NULL; + } + + static void *c_next(struct seq_file *m, void *v, loff_t *pos) + { +- ++*pos; ++ *pos = next_cpu(*pos, cpu_online_map); + return c_start(m, pos); + } + +--- sle11-2009-06-29.orig/arch/x86/kernel/smp_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/smp_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -72,7 +72,7 @@ + * + * B stepping CPUs may hang. There are hardware work arounds + * for this. We warn about it in case your board doesn't have the work +- * arounds. Basically thats so I can tell anyone with a B stepping ++ * arounds. Basically that's so I can tell anyone with a B stepping + * CPU and SMP problems "tough". + * + * Specific items [From Pentium Processor Specification Update] +@@ -241,7 +241,7 @@ void leave_mm(unsigned long cpu) + * 1a1) cpu_clear(cpu, old_mm->cpu_vm_mask); + * Stop ipi delivery for the old mm. This is not synchronized with + * the other cpus, but smp_invalidate_interrupt ignore flush ipis +- * for the wrong mm, and in the worst case we perform a superflous ++ * for the wrong mm, and in the worst case we perform a superfluous + * tlb flush. + * 1a2) set cpu_tlbstate to TLBSTATE_OK + * Now the smp_invalidate_interrupt won't call leave_mm if cpu0 +@@ -309,6 +309,7 @@ irqreturn_t smp_invalidate_interrupt(int + smp_mb__after_clear_bit(); + out: + put_cpu_no_resched(); ++ __get_cpu_var(irq_stat).irq_tlb_count++; + + return IRQ_HANDLED; + } +@@ -580,7 +581,7 @@ static void stop_this_cpu (void * dummy) + */ + cpu_clear(smp_processor_id(), cpu_online_map); + disable_all_local_evtchn(); +- if (cpu_data[smp_processor_id()].hlt_works_ok) ++ if (cpu_data(smp_processor_id()).hlt_works_ok) + for(;;) halt(); + for (;;); + } +@@ -610,6 +611,7 @@ void xen_smp_send_stop(void) + */ + irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id) + { ++ __get_cpu_var(irq_stat).irq_resched_count++; + + return IRQ_HANDLED; + } +@@ -632,6 +634,7 @@ irqreturn_t smp_call_function_interrupt( + */ + irq_enter(); + (*func)(info); ++ __get_cpu_var(irq_stat).irq_call_count++; + irq_exit(); + + if (wait) { +--- sle11-2009-06-29.orig/arch/x86/kernel/smp_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/smp_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -167,6 +167,7 @@ asmlinkage void smp_invalidate_interrupt + out: + ack_APIC_irq(); + cpu_clear(cpu, f->flush_cpumask); ++ add_pda(irq_tlb_count, 1); + } + + static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, +@@ -326,17 +327,27 @@ void unlock_ipi_call_lock(void) + } + + /* +- * this function sends a 'generic call function' IPI to one other CPU +- * in the system. +- * +- * cpu is a standard Linux logical CPU number. ++ * this function sends a 'generic call function' IPI to all other CPU ++ * of the system defined in the mask. + */ +-static void +-__smp_call_function_single(int cpu, void (*func) (void *info), void *info, +- int nonatomic, int wait) ++ ++static int ++__smp_call_function_mask(cpumask_t mask, ++ void (*func)(void *), void *info, ++ int wait) + { + struct call_data_struct data; +- int cpus = 1; ++ cpumask_t allbutself; ++ int cpus; ++ ++ allbutself = cpu_online_map; ++ cpu_clear(smp_processor_id(), allbutself); ++ ++ cpus_and(mask, mask, allbutself); ++ cpus = cpus_weight(mask); ++ ++ if (!cpus) ++ return 0; + + data.func = func; + data.info = info; +@@ -347,19 +358,55 @@ __smp_call_function_single(int cpu, void + + call_data = &data; + wmb(); +- /* Send a message to all other CPUs and wait for them to respond */ +- send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR); ++ ++ /* Send a message to other CPUs */ ++ if (cpus_equal(mask, allbutself)) ++ send_IPI_allbutself(CALL_FUNCTION_VECTOR); ++ else ++ send_IPI_mask(mask, CALL_FUNCTION_VECTOR); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + cpu_relax(); + + if (!wait) +- return; ++ return 0; + + while (atomic_read(&data.finished) != cpus) + cpu_relax(); ++ ++ return 0; ++} ++/** ++ * smp_call_function_mask(): Run a function on a set of other CPUs. ++ * @mask: The set of cpus to run on. Must not include the current cpu. ++ * @func: The function to run. This must be fast and non-blocking. ++ * @info: An arbitrary pointer to pass to the function. ++ * @wait: If true, wait (atomically) until function has completed on other CPUs. ++ * ++ * Returns 0 on success, else a negative status code. ++ * ++ * If @wait is true, then returns once @func has returned; otherwise ++ * it returns just before the target cpu calls @func. ++ * ++ * You must not call this function with disabled interrupts or from a ++ * hardware interrupt handler or from a bottom half handler. ++ */ ++int smp_call_function_mask(cpumask_t mask, ++ void (*func)(void *), void *info, ++ int wait) ++{ ++ int ret; ++ ++ /* Can deadlock when called with interrupts disabled */ ++ WARN_ON(irqs_disabled()); ++ ++ spin_lock(&call_lock); ++ ret = __smp_call_function_mask(mask, func, info, wait); ++ spin_unlock(&call_lock); ++ return ret; + } ++EXPORT_SYMBOL(smp_call_function_mask); + + /* + * smp_call_function_single - Run a function on a specific CPU +@@ -378,6 +425,7 @@ int smp_call_function_single (int cpu, v + int nonatomic, int wait) + { + /* prevent preemption and reschedule on another processor */ ++ int ret; + int me = get_cpu(); + + /* Can deadlock when called with interrupts disabled */ +@@ -391,51 +439,14 @@ int smp_call_function_single (int cpu, v + return 0; + } + +- spin_lock(&call_lock); +- __smp_call_function_single(cpu, func, info, nonatomic, wait); +- spin_unlock(&call_lock); ++ ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait); ++ + put_cpu(); +- return 0; ++ return ret; + } + EXPORT_SYMBOL(smp_call_function_single); + + /* +- * this function sends a 'generic call function' IPI to all other CPUs +- * in the system. +- */ +-static void __smp_call_function (void (*func) (void *info), void *info, +- int nonatomic, int wait) +-{ +- struct call_data_struct data; +- int cpus = num_online_cpus()-1; +- +- if (!cpus) +- return; +- +- data.func = func; +- data.info = info; +- atomic_set(&data.started, 0); +- data.wait = wait; +- if (wait) +- atomic_set(&data.finished, 0); +- +- call_data = &data; +- wmb(); +- /* Send a message to all other CPUs and wait for them to respond */ +- send_IPI_allbutself(CALL_FUNCTION_VECTOR); +- +- /* Wait for response */ +- while (atomic_read(&data.started) != cpus) +- cpu_relax(); +- +- if (!wait) +- return; +- +- while (atomic_read(&data.finished) != cpus) +- cpu_relax(); +-} +- +-/* + * smp_call_function - run a function on all other CPUs. + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. +@@ -453,10 +464,7 @@ static void __smp_call_function (void (* + int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) + { +- spin_lock(&call_lock); +- __smp_call_function(func,info,nonatomic,wait); +- spin_unlock(&call_lock); +- return 0; ++ return smp_call_function_mask(cpu_online_map, func, info, wait); + } + EXPORT_SYMBOL(smp_call_function); + +@@ -485,7 +493,7 @@ void smp_send_stop(void) + /* Don't deadlock on the call lock in panic */ + nolock = !spin_trylock(&call_lock); + local_irq_save(flags); +- __smp_call_function(stop_this_cpu, NULL, 0, 0); ++ __smp_call_function_mask(cpu_online_map, stop_this_cpu, NULL, 0); + if (!nolock) + spin_unlock(&call_lock); + disable_all_local_evtchn(); +@@ -505,7 +513,9 @@ asmlinkage irqreturn_t smp_reschedule_in + { + #ifndef CONFIG_XEN + ack_APIC_irq(); +-#else ++#endif ++ add_pda(irq_resched_count, 1); ++#ifdef CONFIG_XEN + return IRQ_HANDLED; + #endif + } +@@ -535,6 +545,7 @@ asmlinkage irqreturn_t smp_call_function + exit_idle(); + irq_enter(); + (*func)(info); ++ add_pda(irq_call_count, 1); + irq_exit(); + if (wait) { + mb(); +--- sle11-2009-06-29.orig/arch/x86/kernel/time_32-xen.c 2009-03-24 10:12:09.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/time_32-xen.c 2009-03-24 10:12:35.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/kernel/time.c +- * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the PC-specific time handling details: +@@ -74,6 +72,7 @@ + #include + + #include ++#include + #include + + #include +@@ -544,6 +543,13 @@ irqreturn_t timer_interrupt(int irq, voi + struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu); + struct vcpu_runstate_info runstate; + ++ /* Keep nmi watchdog up to date */ ++#ifdef __i386__ ++ per_cpu(irq_stat, smp_processor_id()).irq0_irqs++; ++#else ++ add_pda(irq0_irqs, 1); ++#endif ++ + /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other +@@ -994,7 +1000,7 @@ static int time_cpufreq_notifier(struct + struct cpufreq_freqs *freq = data; + struct xen_platform_op op; + +- if (cpu_has(&cpu_data[freq->cpu], X86_FEATURE_CONSTANT_TSC)) ++ if (cpu_has(&cpu_data(freq->cpu), X86_FEATURE_CONSTANT_TSC)) + return 0; + + if (val == CPUFREQ_PRECHANGE) +@@ -1032,30 +1038,33 @@ core_initcall(cpufreq_time_setup); + */ + static ctl_table xen_subtable[] = { + { +- .ctl_name = 1, ++ .ctl_name = CTL_XEN_INDEPENDENT_WALLCLOCK, + .procname = "independent_wallclock", + .data = &independent_wallclock, + .maxlen = sizeof(independent_wallclock), + .mode = 0644, ++ .strategy = sysctl_data, + .proc_handler = proc_dointvec + }, + { +- .ctl_name = 2, ++ .ctl_name = CTL_XEN_PERMITTED_CLOCK_JITTER, + .procname = "permitted_clock_jitter", + .data = &permitted_clock_jitter, + .maxlen = sizeof(permitted_clock_jitter), + .mode = 0644, ++ .strategy = sysctl_data, + .proc_handler = proc_doulongvec_minmax + }, +- { 0 } ++ { } + }; + static ctl_table xen_table[] = { + { +- .ctl_name = 123, ++ .ctl_name = CTL_XEN, + .procname = "xen", + .mode = 0555, +- .child = xen_subtable}, +- { 0 } ++ .child = xen_subtable ++ }, ++ { } + }; + static int __init xen_sysctl_init(void) + { +--- sle11-2009-06-29.orig/arch/x86/kernel/traps_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/traps_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/i386/traps.c +- * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Pentium III FXSR, SSE support +@@ -65,6 +63,11 @@ + + int panic_on_unrecovered_nmi; + ++#ifndef CONFIG_XEN ++DECLARE_BITMAP(used_vectors, NR_VECTORS); ++EXPORT_SYMBOL_GPL(used_vectors); ++#endif ++ + asmlinkage int system_call(void); + + /* Do we ignore FPU interrupts ? */ +@@ -120,7 +123,7 @@ struct stack_frame { + + static inline unsigned long print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long ebp, +- struct stacktrace_ops *ops, void *data) ++ const struct stacktrace_ops *ops, void *data) + { + #ifdef CONFIG_FRAME_POINTER + struct stack_frame *frame = (struct stack_frame *)ebp; +@@ -157,7 +160,7 @@ static inline unsigned long print_contex + + void dump_trace(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack, +- struct stacktrace_ops *ops, void *data) ++ const struct stacktrace_ops *ops, void *data) + { + unsigned long ebp = 0; + +@@ -229,7 +232,7 @@ static void print_trace_address(void *da + touch_nmi_watchdog(); + } + +-static struct stacktrace_ops print_trace_ops = { ++static const struct stacktrace_ops print_trace_ops = { + .warning = print_trace_warning, + .warning_symbol = print_trace_warning_symbol, + .stack = print_trace_stack, +@@ -288,6 +291,11 @@ void dump_stack(void) + { + unsigned long stack; + ++ printk("Pid: %d, comm: %.20s %s %s %.*s\n", ++ current->pid, current->comm, print_tainted(), ++ init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); + show_trace(current, NULL, &stack); + } + +@@ -296,48 +304,24 @@ EXPORT_SYMBOL(dump_stack); + void show_registers(struct pt_regs *regs) + { + int i; +- int in_kernel = 1; +- unsigned long esp; +- unsigned short ss, gs; +- +- esp = (unsigned long) (®s->esp); +- savesegment(ss, ss); +- savesegment(gs, gs); +- if (user_mode_vm(regs)) { +- in_kernel = 0; +- esp = regs->esp; +- ss = regs->xss & 0xffff; +- } ++ + print_modules(); +- printk(KERN_EMERG "CPU: %d\n" +- KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" +- KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", +- smp_processor_id(), 0xffff & regs->xcs, regs->eip, +- print_tainted(), regs->eflags, init_utsname()->release, +- (int)strcspn(init_utsname()->version, " "), +- init_utsname()->version); +- print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); +- printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", +- regs->eax, regs->ebx, regs->ecx, regs->edx); +- printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", +- regs->esi, regs->edi, regs->ebp, esp); +- printk(KERN_EMERG "ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", +- regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss); ++ __show_registers(regs, 0); + printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", +- TASK_COMM_LEN, current->comm, current->pid, ++ TASK_COMM_LEN, current->comm, task_pid_nr(current), + current_thread_info(), current, task_thread_info(current)); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ +- if (in_kernel) { ++ if (!user_mode_vm(regs)) { + u8 *eip; + unsigned int code_prologue = code_bytes * 43 / 64; + unsigned int code_len = code_bytes; + unsigned char c; + + printk("\n" KERN_EMERG "Stack: "); +- show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); ++ show_stack_log_lvl(NULL, regs, ®s->esp, KERN_EMERG); + + printk(KERN_EMERG "Code: "); + +@@ -382,11 +366,11 @@ int is_valid_bugaddr(unsigned long eip) + void die(const char * str, struct pt_regs * regs, long err) + { + static struct { +- spinlock_t lock; ++ raw_spinlock_t lock; + u32 lock_owner; + int lock_owner_depth; + } die = { +- .lock = __SPIN_LOCK_UNLOCKED(die.lock), ++ .lock = __RAW_SPIN_LOCK_UNLOCKED, + .lock_owner = -1, + .lock_owner_depth = 0 + }; +@@ -397,40 +381,33 @@ void die(const char * str, struct pt_reg + + if (die.lock_owner != raw_smp_processor_id()) { + console_verbose(); +- spin_lock_irqsave(&die.lock, flags); ++ raw_local_irq_save(flags); ++ __raw_spin_lock(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); +- } +- else +- local_save_flags(flags); ++ } else ++ raw_local_irq_save(flags); + + if (++die.lock_owner_depth < 3) { +- int nl = 0; + unsigned long esp; + unsigned short ss; + + report_bug(regs->eip, regs); + +- printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); ++ printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++ ++die_counter); + #ifdef CONFIG_PREEMPT +- printk(KERN_EMERG "PREEMPT "); +- nl = 1; ++ printk("PREEMPT "); + #endif + #ifdef CONFIG_SMP +- if (!nl) +- printk(KERN_EMERG); + printk("SMP "); +- nl = 1; + #endif + #ifdef CONFIG_DEBUG_PAGEALLOC +- if (!nl) +- printk(KERN_EMERG); + printk("DEBUG_PAGEALLOC"); +- nl = 1; + #endif +- if (nl) +- printk("\n"); ++ printk("\n"); ++ + if (notify_die(DIE_OOPS, str, regs, err, + current->thread.trap_no, SIGSEGV) != + NOTIFY_STOP) { +@@ -454,7 +431,8 @@ void die(const char * str, struct pt_reg + bust_spinlocks(0); + die.lock_owner = -1; + add_taint(TAINT_DIE); +- spin_unlock_irqrestore(&die.lock, flags); ++ __raw_spin_unlock(&die.lock); ++ raw_local_irq_restore(flags); + + if (!regs) + return; +@@ -571,6 +549,7 @@ fastcall void do_##name(struct pt_regs * + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ ++ trace_hardirqs_fixup(); \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ +@@ -606,7 +585,7 @@ fastcall void __kprobes do_general_prote + printk_ratelimit()) + printk(KERN_INFO + "%s[%d] general protection eip:%lx esp:%lx error:%lx\n", +- current->comm, current->pid, ++ current->comm, task_pid_nr(current), + regs->eip, regs->esp, error_code); + + force_sig(SIGSEGV, current); +@@ -785,6 +764,8 @@ void restart_nmi(void) + #ifdef CONFIG_KPROBES + fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) + { ++ trace_hardirqs_fixup(); ++ + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return; +@@ -822,6 +803,8 @@ fastcall void __kprobes do_debug(struct + unsigned int condition; + struct task_struct *tsk = current; + ++ trace_hardirqs_fixup(); ++ + get_debugreg(condition, 6); + + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, +@@ -1084,20 +1067,6 @@ asmlinkage void math_emulate(long arg) + + #endif /* CONFIG_MATH_EMULATION */ + +-#ifdef CONFIG_X86_F00F_BUG +-void __init trap_init_f00f_bug(void) +-{ +- __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); +- +- /* +- * Update the IDT descriptor and reload the IDT so that +- * it uses the read-only mapped virtual address. +- */ +- idt_descr.address = fix_to_virt(FIX_F00F_IDT); +- load_idt(&idt_descr); +-} +-#endif +- + + /* + * NB. All these are "trap gates" (i.e. events_mask isn't set) except +--- sle11-2009-06-29.orig/arch/x86/kernel/traps_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/traps_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/x86-64/traps.c +- * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs + * +@@ -33,6 +31,7 @@ + #include + #include + #include ++#include + + #if defined(CONFIG_EDAC) + #include +@@ -205,7 +204,7 @@ static unsigned long *in_exception_stack + #define MSG(txt) ops->warning(data, txt) + + /* +- * x86-64 can have upto three kernel stacks: ++ * x86-64 can have up to three kernel stacks: + * process stack + * interrupt stack + * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack +@@ -219,7 +218,7 @@ static inline int valid_stack_ptr(struct + + void dump_trace(struct task_struct *tsk, struct pt_regs *regs, + unsigned long *stack, +- struct stacktrace_ops *ops, void *data) ++ const struct stacktrace_ops *ops, void *data) + { + const unsigned cpu = get_cpu(); + unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr; +@@ -340,7 +339,7 @@ static void print_trace_address(void *da + printk_address(addr); + } + +-static struct stacktrace_ops print_trace_ops = { ++static const struct stacktrace_ops print_trace_ops = { + .warning = print_trace_warning, + .warning_symbol = print_trace_warning_symbol, + .stack = print_trace_stack, +@@ -404,6 +403,12 @@ void show_stack(struct task_struct *tsk, + void dump_stack(void) + { + unsigned long dummy; ++ ++ printk("Pid: %d, comm: %.20s %s %s %.*s\n", ++ current->pid, current->comm, print_tainted(), ++ init_utsname()->release, ++ (int)strcspn(init_utsname()->version, " "), ++ init_utsname()->version); + show_trace(NULL, NULL, &dummy); + } + +@@ -466,7 +471,7 @@ void out_of_line_bug(void) + EXPORT_SYMBOL(out_of_line_bug); + #endif + +-static DEFINE_SPINLOCK(die_lock); ++static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; + static int die_owner = -1; + static unsigned int die_nest_count; + +@@ -478,13 +483,13 @@ unsigned __kprobes long oops_begin(void) + oops_enter(); + + /* racy, but better than risking deadlock. */ +- local_irq_save(flags); ++ raw_local_irq_save(flags); + cpu = smp_processor_id(); +- if (!spin_trylock(&die_lock)) { ++ if (!__raw_spin_trylock(&die_lock)) { + if (cpu == die_owner) + /* nested oops. should stop eventually */; + else +- spin_lock(&die_lock); ++ __raw_spin_lock(&die_lock); + } + die_nest_count++; + die_owner = cpu; +@@ -498,12 +503,10 @@ void __kprobes oops_end(unsigned long fl + die_owner = -1; + bust_spinlocks(0); + die_nest_count--; +- if (die_nest_count) +- /* We still own the lock */ +- local_irq_restore(flags); +- else ++ if (!die_nest_count) + /* Nest count reaches zero, release the lock. */ +- spin_unlock_irqrestore(&die_lock, flags); ++ __raw_spin_unlock(&die_lock); ++ raw_local_irq_restore(flags); + if (panic_on_oops) + panic("Fatal exception"); + oops_exit(); +@@ -636,6 +639,7 @@ asmlinkage void do_##name(struct pt_regs + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ ++ trace_hardirqs_fixup(); \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ +@@ -741,11 +745,8 @@ mem_parity_error(unsigned char reason, s + + printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); + +-#if 0 /* XEN */ + /* Clear and disable the memory parity error line. */ +- reason = (reason & 0xf) | 4; +- outb(reason, 0x61); +-#endif /* XEN */ ++ clear_mem_error(reason); + } + + static __kprobes void +@@ -754,14 +755,8 @@ io_check_error(unsigned char reason, str + printk("NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + +-#if 0 /* XEN */ + /* Re-enable the IOCK line, wait for a few seconds */ +- reason = (reason & 0xf) | 8; +- outb(reason, 0x61); +- mdelay(2000); +- reason &= ~8; +- outb(reason, 0x61); +-#endif /* XEN */ ++ clear_io_check_error(reason); + } + + static __kprobes void +@@ -821,6 +816,8 @@ asmlinkage __kprobes void default_do_nmi + /* runs on IST stack. */ + asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code) + { ++ trace_hardirqs_fixup(); ++ + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { + return; + } +@@ -858,6 +855,8 @@ asmlinkage void __kprobes do_debug(struc + struct task_struct *tsk = current; + siginfo_t info; + ++ trace_hardirqs_fixup(); ++ + get_debugreg(condition, 6); + + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, +--- sle11-2009-06-29.orig/arch/x86/kernel/vsyscall_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/vsyscall_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,4 @@ + /* +- * linux/arch/x86_64/kernel/vsyscall.c +- * + * Copyright (C) 2001 Andrea Arcangeli SuSE + * Copyright 2003 Andi Kleen, SuSE Labs. + * +@@ -50,12 +48,12 @@ + ({unsigned long v; \ + extern char __vsyscall_0; \ + asm("" : "=r" (v) : "0" (x)); \ +- ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); }) ++ ((v - VSYSCALL_START) + __pa_symbol(&__vsyscall_0)); }) + + /* + * vsyscall_gtod_data contains data that is : + * - readonly from vsyscalls +- * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64) ++ * - written by timer interrupt or systcl (/proc/sys/kernel/vsyscall64) + * Try to keep this structure as small as possible to avoid cache line ping pongs + */ + int __vgetcpu_mode __section_vgetcpu_mode; +@@ -66,6 +64,16 @@ struct vsyscall_gtod_data __vsyscall_gto + .sysctl_enabled = 1, + }; + ++void update_vsyscall_tz(void) ++{ ++ unsigned long flags; ++ ++ write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); ++ /* sys_tz has changed */ ++ vsyscall_gtod_data.sys_tz = sys_tz; ++ write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); ++} ++ + void update_vsyscall(struct timespec *wall_time, struct clocksource *clock) + { + unsigned long flags; +@@ -79,8 +87,6 @@ void update_vsyscall(struct timespec *wa + vsyscall_gtod_data.clock.shift = clock->shift; + vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; + vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; +- vsyscall_gtod_data.sys_tz = sys_tz; +- vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic; + write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); + } +@@ -166,7 +172,7 @@ time_t __vsyscall(1) vtime(time_t *t) + if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) + return time_syscall(t); + +- vgettimeofday(&tv, 0); ++ vgettimeofday(&tv, NULL); + result = tv.tv_sec; + if (t) + *t = result; +@@ -260,18 +266,10 @@ out: + return ret; + } + +-static int vsyscall_sysctl_nostrat(ctl_table *t, int __user *name, int nlen, +- void __user *oldval, size_t __user *oldlenp, +- void __user *newval, size_t newlen) +-{ +- return -ENOSYS; +-} +- + static ctl_table kernel_table2[] = { +- { .ctl_name = 99, .procname = "vsyscall64", ++ { .procname = "vsyscall64", + .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int), + .mode = 0644, +- .strategy = vsyscall_sysctl_nostrat, + .proc_handler = vsyscall_sysctl_change }, + {} + }; +@@ -291,9 +289,9 @@ static void __cpuinit vsyscall_set_cpu(i + unsigned long d; + unsigned long node = 0; + #ifdef CONFIG_NUMA +- node = cpu_to_node[cpu]; ++ node = cpu_to_node(cpu); + #endif +- if (cpu_has(&cpu_data[cpu], X86_FEATURE_RDTSCP)) ++ if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP)) + write_rdtscp_aux((node << 12) | cpu); + + /* Store cpu number in limit so that it can be loaded quickly +--- sle11-2009-06-29.orig/arch/x86/mm/fault_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/fault_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -32,33 +33,27 @@ + + extern void die(const char *,struct pt_regs *,long); + +-static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); +- +-int register_page_fault_notifier(struct notifier_block *nb) ++#ifdef CONFIG_KPROBES ++static inline int notify_page_fault(struct pt_regs *regs) + { +- vmalloc_sync_all(); +- return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); +-} +-EXPORT_SYMBOL_GPL(register_page_fault_notifier); ++ int ret = 0; + +-int unregister_page_fault_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); +-} +-EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); ++ /* kprobe_running() needs smp_processor_id() */ ++ if (!user_mode_vm(regs)) { ++ preempt_disable(); ++ if (kprobe_running() && kprobe_fault_handler(regs, 14)) ++ ret = 1; ++ preempt_enable(); ++ } + +-static inline int notify_page_fault(struct pt_regs *regs, long err) ++ return ret; ++} ++#else ++static inline int notify_page_fault(struct pt_regs *regs) + { +- struct die_args args = { +- .regs = regs, +- .str = "page fault", +- .err = err, +- .trapnr = 14, +- .signr = SIGSEGV +- }; +- return atomic_notifier_call_chain(¬ify_page_fault_chain, +- DIE_PAGE_FAULT, &args); ++ return 0; + } ++#endif + + /* + * Return EIP plus the CS segment base. The segment limit is also +@@ -110,7 +105,7 @@ static inline unsigned long get_segment_ + LDT and other horrors are only used in user space. */ + if (seg & (1<<2)) { + /* Must lock the LDT while reading it. */ +- down(¤t->mm->context.sem); ++ mutex_lock(¤t->mm->context.lock); + desc = current->mm->context.ldt; + desc = (void *)desc + (seg & ~7); + } else { +@@ -123,7 +118,7 @@ static inline unsigned long get_segment_ + base = get_desc_base((unsigned long *)desc); + + if (seg & (1<<2)) { +- up(¤t->mm->context.sem); ++ mutex_unlock(¤t->mm->context.lock); + } else + put_cpu(); + +@@ -244,7 +239,7 @@ static void dump_fault_path(unsigned lon + if (mfn_to_pfn(mfn) >= highstart_pfn) + return; + #endif +- if (p[0] & _PAGE_PRESENT) { ++ if ((p[0] & _PAGE_PRESENT) && !(p[0] & _PAGE_PSE)) { + page = mfn_to_pfn(mfn) << PAGE_SHIFT; + p = (unsigned long *) __va(page); + address &= 0x001fffff; +@@ -270,7 +265,8 @@ static void dump_fault_path(unsigned lon + * it's allocated already. + */ + if ((machine_to_phys(page) >> PAGE_SHIFT) < max_low_pfn +- && (page & _PAGE_PRESENT)) { ++ && (page & _PAGE_PRESENT) ++ && !(page & _PAGE_PSE)) { + page = machine_to_phys(page & PAGE_MASK); + page = ((unsigned long *) __va(page))[(address >> PAGE_SHIFT) + & (PTRS_PER_PTE - 1)]; +@@ -416,6 +412,11 @@ fastcall void __kprobes do_page_fault(st + int write, si_code; + int fault; + ++ /* ++ * We can fault from pretty much anywhere, with unknown IRQ state. ++ */ ++ trace_hardirqs_fixup(); ++ + /* get the address */ + address = read_cr2(); + +@@ -453,7 +454,7 @@ fastcall void __kprobes do_page_fault(st + /* Can take a spurious fault if mapping changes R/O -> R/W. */ + if (spurious_fault(regs, address, error_code)) + return; +- if (notify_page_fault(regs, error_code) == NOTIFY_STOP) ++ if (notify_page_fault(regs)) + return; + /* + * Don't take the mm semaphore here. If we fixup a prefetch +@@ -462,7 +463,7 @@ fastcall void __kprobes do_page_fault(st + goto bad_area_nosemaphore; + } + +- if (notify_page_fault(regs, error_code) == NOTIFY_STOP) ++ if (notify_page_fault(regs)) + return; + + /* It's safe to allow irq's after cr2 has been saved and the vmalloc +@@ -481,7 +482,7 @@ fastcall void __kprobes do_page_fault(st + + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the +- * kernel and should generate an OOPS. Unfortunatly, in the case of an ++ * kernel and should generate an OOPS. Unfortunately, in the case of an + * erroneous fault occurring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user +@@ -489,7 +490,7 @@ fastcall void __kprobes do_page_fault(st + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform +- * the source reference check when there is a possibilty of a deadlock. ++ * the source reference check when there is a possibility of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. +@@ -598,8 +599,8 @@ bad_area_nosemaphore: + printk_ratelimit()) { + printk("%s%s[%d]: segfault at %08lx eip %08lx " + "esp %08lx error %lx\n", +- tsk->pid > 1 ? KERN_INFO : KERN_EMERG, +- tsk->comm, tsk->pid, address, regs->eip, ++ task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, ++ tsk->comm, task_pid_nr(tsk), address, regs->eip, + regs->esp, error_code); + } + tsk->thread.cr2 = address; +@@ -664,8 +665,7 @@ no_context: + printk(KERN_ALERT "BUG: unable to handle kernel paging" + " request"); + printk(" at virtual address %08lx\n",address); +- printk(KERN_ALERT " printing eip:\n"); +- printk("%08lx\n", regs->eip); ++ printk(KERN_ALERT "printing eip: %08lx\n", regs->eip); + dump_fault_path(address); + } + tsk->thread.cr2 = address; +@@ -681,14 +681,14 @@ no_context: + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_init(tsk)) { ++ if (is_global_init(tsk)) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) +- do_exit(SIGKILL); ++ do_group_exit(SIGKILL); + goto no_context; + + do_sigbus: +--- sle11-2009-06-29.orig/arch/x86/mm/fault_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/fault_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -40,34 +41,27 @@ + #define PF_RSVD (1<<3) + #define PF_INSTR (1<<4) + +-static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); +- +-/* Hook to register for page fault notifications */ +-int register_page_fault_notifier(struct notifier_block *nb) ++#ifdef CONFIG_KPROBES ++static inline int notify_page_fault(struct pt_regs *regs) + { +- vmalloc_sync_all(); +- return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); +-} +-EXPORT_SYMBOL_GPL(register_page_fault_notifier); ++ int ret = 0; + +-int unregister_page_fault_notifier(struct notifier_block *nb) +-{ +- return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); +-} +-EXPORT_SYMBOL_GPL(unregister_page_fault_notifier); ++ /* kprobe_running() needs smp_processor_id() */ ++ if (!user_mode(regs)) { ++ preempt_disable(); ++ if (kprobe_running() && kprobe_fault_handler(regs, 14)) ++ ret = 1; ++ preempt_enable(); ++ } + +-static inline int notify_page_fault(struct pt_regs *regs, long err) ++ return ret; ++} ++#else ++static inline int notify_page_fault(struct pt_regs *regs) + { +- struct die_args args = { +- .regs = regs, +- .str = "page fault", +- .err = err, +- .trapnr = 14, +- .signr = SIGSEGV +- }; +- return atomic_notifier_call_chain(¬ify_page_fault_chain, +- DIE_PAGE_FAULT, &args); ++ return 0; + } ++#endif + + /* Sometimes the CPU reports invalid exceptions on prefetch. + Check that here and ignore. +@@ -175,7 +169,7 @@ void dump_pagetable(unsigned long addres + pmd = pmd_offset(pud, address); + if (bad_address(pmd)) goto bad; + printk("PMD %lx ", pmd_val(*pmd)); +- if (!pmd_present(*pmd)) goto ret; ++ if (!pmd_present(*pmd) || pmd_large(*pmd)) goto ret; + + pte = pte_offset_kernel(pmd, address); + if (bad_address(pte)) goto bad; +@@ -294,7 +288,6 @@ static int vmalloc_fault(unsigned long a + return 0; + } + +-static int page_fault_trace; + int show_unhandled_signals = 1; + + +@@ -371,6 +364,11 @@ asmlinkage void __kprobes do_page_fault( + if (!user_mode(regs)) + error_code &= ~PF_USER; /* means kernel */ + ++ /* ++ * We can fault from pretty much anywhere, with unknown IRQ state. ++ */ ++ trace_hardirqs_fixup(); ++ + tsk = current; + mm = tsk->mm; + prefetchw(&mm->mmap_sem); +@@ -408,7 +406,7 @@ asmlinkage void __kprobes do_page_fault( + /* Can take a spurious fault if mapping changes R/O -> R/W. */ + if (spurious_fault(regs, address, error_code)) + return; +- if (notify_page_fault(regs, error_code) == NOTIFY_STOP) ++ if (notify_page_fault(regs)) + return; + /* + * Don't take the mm semaphore here. If we fixup a prefetch +@@ -417,16 +415,12 @@ asmlinkage void __kprobes do_page_fault( + goto bad_area_nosemaphore; + } + +- if (notify_page_fault(regs, error_code) == NOTIFY_STOP) ++ if (notify_page_fault(regs)) + return; + + if (likely(regs->eflags & X86_EFLAGS_IF)) + local_irq_enable(); + +- if (unlikely(page_fault_trace)) +- printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n", +- regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code); +- + if (unlikely(error_code & PF_RSVD)) + pgtable_bad(address, regs, error_code); + +@@ -447,7 +441,7 @@ asmlinkage void __kprobes do_page_fault( + again: + /* When running in the kernel we expect faults to occur only to + * addresses in user space. All other faults represent errors in the +- * kernel and should generate an OOPS. Unfortunatly, in the case of an ++ * kernel and should generate an OOPS. Unfortunately, in the case of an + * erroneous fault occurring in a code path which already holds mmap_sem + * we will deadlock attempting to validate the fault against the + * address space. Luckily the kernel only validly references user +@@ -455,7 +449,7 @@ asmlinkage void __kprobes do_page_fault( + * exceptions table. + * + * As the vast majority of faults will be valid we will only perform +- * the source reference check when there is a possibilty of a deadlock. ++ * the source reference check when there is a possibility of a deadlock. + * Attempt to lock the address space, if we cannot we then validate the + * source. If this is invalid we can skip the address space check, + * thus avoiding the deadlock. +@@ -557,7 +551,7 @@ bad_area_nosemaphore: + if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && + printk_ratelimit()) { + printk( +- "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n", ++ "%s%s[%d]: segfault at %lx rip %lx rsp %lx error %lx\n", + tsk->pid > 1 ? KERN_INFO : KERN_EMERG, + tsk->comm, tsk->pid, address, regs->rip, + regs->rsp, error_code); +@@ -623,7 +617,7 @@ no_context: + */ + out_of_memory: + up_read(&mm->mmap_sem); +- if (is_init(current)) { ++ if (is_global_init(current)) { + yield(); + goto again; + } +@@ -690,10 +684,3 @@ void vmalloc_sync_all(void) + BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) == + (__START_KERNEL & PGDIR_MASK))); + } +- +-static int __init enable_pagefaulttrace(char *str) +-{ +- page_fault_trace = 1; +- return 1; +-} +-__setup("pagefaulttrace", enable_pagefaulttrace); +--- sle11-2009-06-29.orig/arch/x86/mm/hypervisor.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/hypervisor.c 2009-05-06 10:23:43.000000000 +0200 +@@ -496,6 +496,9 @@ int xen_create_contiguous_region( + unsigned long frame, flags; + unsigned int i; + int rc, success; ++#ifdef CONFIG_64BIT ++ pte_t *ptep = NULL; ++#endif + struct xen_memory_exchange exchange = { + .in = { + .nr_extents = 1UL << order, +@@ -521,6 +524,27 @@ int xen_create_contiguous_region( + if (unlikely(order > MAX_CONTIG_ORDER)) + return -ENOMEM; + ++#ifdef CONFIG_64BIT ++ if (unlikely(vstart > PAGE_OFFSET + MAXMEM)) { ++ unsigned int level; ++ ++ if (vstart < __START_KERNEL_map ++ || vstart + (PAGE_SIZE << order) > (unsigned long)_end) ++ return -EINVAL; ++ ptep = lookup_address((unsigned long)__va(__pa(vstart)), ++ &level); ++ if (ptep && pte_none(*ptep)) ++ ptep = NULL; ++ if (vstart < __START_KERNEL && ptep) ++ return -EINVAL; ++ if (order > MAX_CONTIG_ORDER - 1) ++ return -ENOMEM; ++ } ++#else ++ if (unlikely(vstart + (PAGE_SIZE << order) > (unsigned long)high_memory)) ++ return -EINVAL; ++#endif ++ + set_xen_guest_handle(exchange.in.extent_start, in_frames); + set_xen_guest_handle(exchange.out.extent_start, &out_frame); + +@@ -533,9 +557,19 @@ int xen_create_contiguous_region( + in_frames[i] = pfn_to_mfn((__pa(vstart) >> PAGE_SHIFT) + i); + MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE), + __pte_ma(0), 0); ++#ifdef CONFIG_64BIT ++ if (ptep) ++ MULTI_update_va_mapping(cr_mcl + i + (1U << order), ++ (unsigned long)__va(__pa(vstart)) + (i*PAGE_SIZE), ++ __pte_ma(0), 0); ++#endif + set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, + INVALID_P2M_ENTRY); + } ++#ifdef CONFIG_64BIT ++ if (ptep) ++ i += i; ++#endif + if (HYPERVISOR_multicall_check(cr_mcl, i, NULL)) + BUG(); + +@@ -569,9 +603,18 @@ int xen_create_contiguous_region( + frame = success ? (out_frame + i) : in_frames[i]; + MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE), + pfn_pte_ma(frame, PAGE_KERNEL), 0); ++#ifdef CONFIG_64BIT ++ if (ptep) ++ MULTI_update_va_mapping(cr_mcl + i + (1U << order), ++ (unsigned long)__va(__pa(vstart)) + (i*PAGE_SIZE), ++ pfn_pte_ma(frame, PAGE_KERNEL_RO), 0); ++#endif + set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i, frame); + } +- ++#ifdef CONFIG_64BIT ++ if (ptep) ++ i += i; ++#endif + cr_mcl[i - 1].args[MULTI_UVMFLAGS_INDEX] = order + ? UVMF_TLB_FLUSH|UVMF_ALL + : UVMF_INVLPG|UVMF_ALL; +--- sle11-2009-06-29.orig/arch/x86/mm/init_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/init_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -94,7 +94,14 @@ static pte_t * __init one_page_table_ini + #else + if (!(__pmd_val(*pmd) & _PAGE_PRESENT)) { + #endif +- pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ pte_t *page_table = NULL; ++ ++#ifdef CONFIG_DEBUG_PAGEALLOC ++ page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); ++#endif ++ if (!page_table) ++ page_table = ++ (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); + + paravirt_alloc_pt(&init_mm, __pa(page_table) >> PAGE_SHIFT); + make_lowmem_page_readonly(page_table, +@@ -102,7 +109,7 @@ static pte_t * __init one_page_table_ini + set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); + BUG_ON(page_table != pte_offset_kernel(pmd, 0)); + } +- ++ + return pte_offset_kernel(pmd, 0); + } + +@@ -360,8 +367,13 @@ extern void set_highmem_pages_init(int); + static void __init set_highmem_pages_init(int bad_ppro) + { + int pfn; +- for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) +- add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro); ++ for (pfn = highstart_pfn; pfn < highend_pfn; pfn++) { ++ /* ++ * Holes under sparsemem might not have no mem_map[]: ++ */ ++ if (pfn_valid(pfn)) ++ add_one_highpage_init(pfn_to_page(pfn), pfn, bad_ppro); ++ } + totalram_pages += totalhigh_pages; + } + #endif /* CONFIG_FLATMEM */ +@@ -779,35 +791,18 @@ int arch_add_memory(int nid, u64 start, + return __add_pages(zone, start_pfn, nr_pages); + } + +-int remove_memory(u64 start, u64 size) +-{ +- return -EINVAL; +-} +-EXPORT_SYMBOL_GPL(remove_memory); + #endif + + struct kmem_cache *pmd_cache; + + void __init pgtable_cache_init(void) + { +- size_t pgd_size = PTRS_PER_PGD*sizeof(pgd_t); +- +- if (PTRS_PER_PMD > 1) { ++ if (PTRS_PER_PMD > 1) + pmd_cache = kmem_cache_create("pmd", +- PTRS_PER_PMD*sizeof(pmd_t), +- PTRS_PER_PMD*sizeof(pmd_t), +- SLAB_PANIC, +- pmd_ctor); +- if (!SHARED_KERNEL_PMD) { +- /* If we're in PAE mode and have a non-shared +- kernel pmd, then the pgd size must be a +- page size. This is because the pgd_list +- links through the page structure, so there +- can only be one pgd per page for this to +- work. */ +- pgd_size = PAGE_SIZE; +- } +- } ++ PTRS_PER_PMD*sizeof(pmd_t), ++ PTRS_PER_PMD*sizeof(pmd_t), ++ SLAB_PANIC, ++ pmd_ctor); + } + + /* +--- sle11-2009-06-29.orig/arch/x86/mm/init_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/init_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -767,7 +767,7 @@ static void xen_finish_init_mapping(void + /* Setup the direct mapping of the physical memory at PAGE_OFFSET. + This runs before bootmem is initialized and gets pages directly from the + physical memory. To access them they are temporarily mapped. */ +-void __meminit init_memory_mapping(unsigned long start, unsigned long end) ++void __init_refok init_memory_mapping(unsigned long start, unsigned long end) + { + unsigned long next; + +@@ -901,12 +901,6 @@ error: + } + EXPORT_SYMBOL_GPL(arch_add_memory); + +-int remove_memory(u64 start, u64 size) +-{ +- return -EINVAL; +-} +-EXPORT_SYMBOL_GPL(remove_memory); +- + #if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA) + int memory_add_physaddr_to_nid(u64 start) + { +@@ -1173,14 +1167,6 @@ int in_gate_area_no_task(unsigned long a + return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); + } + +-#ifndef CONFIG_XEN +-void * __init alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size) +-{ +- return __alloc_bootmem_core(pgdat->bdata, size, +- SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0); +-} +-#endif +- + const char *arch_vma_name(struct vm_area_struct *vma) + { + if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) +@@ -1189,3 +1175,48 @@ const char *arch_vma_name(struct vm_area + return "[vsyscall]"; + return NULL; + } ++ ++#ifdef CONFIG_SPARSEMEM_VMEMMAP ++/* ++ * Initialise the sparsemem vmemmap using huge-pages at the PMD level. ++ */ ++int __meminit vmemmap_populate(struct page *start_page, ++ unsigned long size, int node) ++{ ++ unsigned long addr = (unsigned long)start_page; ++ unsigned long end = (unsigned long)(start_page + size); ++ unsigned long next; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ ++ for (; addr < end; addr = next) { ++ next = pmd_addr_end(addr, end); ++ ++ pgd = vmemmap_pgd_populate(addr, node); ++ if (!pgd) ++ return -ENOMEM; ++ pud = vmemmap_pud_populate(pgd, addr, node); ++ if (!pud) ++ return -ENOMEM; ++ ++ pmd = pmd_offset(pud, addr); ++ if (pmd_none(*pmd)) { ++ pte_t entry; ++ void *p = vmemmap_alloc_block(PMD_SIZE, node); ++ if (!p) ++ return -ENOMEM; ++ ++ entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL); ++ mk_pte_huge(entry); ++ set_pmd(pmd, __pmd(pte_val(entry))); ++ ++ printk(KERN_DEBUG " [%lx-%lx] PMD ->%p on node %d\n", ++ addr, addr + PMD_SIZE - 1, p, node); ++ } else ++ vmemmap_verify((pte_t *)pmd, node, addr, next); ++ } ++ ++ return 0; ++} ++#endif +--- sle11-2009-06-29.orig/arch/x86/mm/pageattr_64-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/pageattr_64-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -17,9 +17,6 @@ + #include + #include + +-LIST_HEAD(mm_unpinned); +-DEFINE_SPINLOCK(mm_unpinned_lock); +- + static void _pin_lock(struct mm_struct *mm, int lock) { + if (lock) + spin_lock(&mm->page_table_lock); +@@ -81,8 +78,8 @@ static void _pin_lock(struct mm_struct * + #define PIN_BATCH 8 + static DEFINE_PER_CPU(multicall_entry_t[PIN_BATCH], pb_mcl); + +-static inline unsigned int mm_walk_set_prot(void *pt, pgprot_t flags, +- unsigned int cpu, unsigned int seq) ++static inline unsigned int pgd_walk_set_prot(void *pt, pgprot_t flags, ++ unsigned int cpu, unsigned int seq) + { + struct page *page = virt_to_page(pt); + unsigned long pfn = page_to_pfn(page); +@@ -100,9 +97,9 @@ static inline unsigned int mm_walk_set_p + return seq; + } + +-static void mm_walk(struct mm_struct *mm, pgprot_t flags) ++static void pgd_walk(pgd_t *pgd_base, pgprot_t flags) + { +- pgd_t *pgd; ++ pgd_t *pgd = pgd_base; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; +@@ -110,7 +107,6 @@ static void mm_walk(struct mm_struct *mm + unsigned int cpu, seq; + multicall_entry_t *mcl; + +- pgd = mm->pgd; + cpu = get_cpu(); + + /* +@@ -125,18 +121,18 @@ static void mm_walk(struct mm_struct *mm + continue; + pud = pud_offset(pgd, 0); + if (PTRS_PER_PUD > 1) /* not folded */ +- seq = mm_walk_set_prot(pud,flags,cpu,seq); ++ seq = pgd_walk_set_prot(pud,flags,cpu,seq); + for (u = 0; u < PTRS_PER_PUD; u++, pud++) { + if (pud_none(*pud)) + continue; + pmd = pmd_offset(pud, 0); + if (PTRS_PER_PMD > 1) /* not folded */ +- seq = mm_walk_set_prot(pmd,flags,cpu,seq); ++ seq = pgd_walk_set_prot(pmd,flags,cpu,seq); + for (m = 0; m < PTRS_PER_PMD; m++, pmd++) { + if (pmd_none(*pmd)) + continue; + pte = pte_offset_kernel(pmd,0); +- seq = mm_walk_set_prot(pte,flags,cpu,seq); ++ seq = pgd_walk_set_prot(pte,flags,cpu,seq); + } + } + } +@@ -148,12 +144,12 @@ static void mm_walk(struct mm_struct *mm + seq = 0; + } + MULTI_update_va_mapping(mcl + seq, +- (unsigned long)__user_pgd(mm->pgd), +- pfn_pte(virt_to_phys(__user_pgd(mm->pgd))>>PAGE_SHIFT, flags), ++ (unsigned long)__user_pgd(pgd_base), ++ pfn_pte(virt_to_phys(__user_pgd(pgd_base))>>PAGE_SHIFT, flags), + 0); + MULTI_update_va_mapping(mcl + seq + 1, +- (unsigned long)mm->pgd, +- pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, flags), ++ (unsigned long)pgd_base, ++ pfn_pte(virt_to_phys(pgd_base)>>PAGE_SHIFT, flags), + UVMF_TLB_FLUSH); + if (unlikely(HYPERVISOR_multicall_check(mcl, seq + 2, NULL))) + BUG(); +@@ -161,21 +157,35 @@ static void mm_walk(struct mm_struct *mm + put_cpu(); + } + ++static void __pgd_pin(pgd_t *pgd) ++{ ++ pgd_walk(pgd, PAGE_KERNEL_RO); ++ xen_pgd_pin(__pa(pgd)); /* kernel */ ++ xen_pgd_pin(__pa(__user_pgd(pgd))); /* user */ ++ SetPagePinned(virt_to_page(pgd)); ++} ++ ++static void __pgd_unpin(pgd_t *pgd) ++{ ++ xen_pgd_unpin(__pa(pgd)); ++ xen_pgd_unpin(__pa(__user_pgd(pgd))); ++ pgd_walk(pgd, PAGE_KERNEL); ++ ClearPagePinned(virt_to_page(pgd)); ++} ++ ++void pgd_test_and_unpin(pgd_t *pgd) ++{ ++ if (PagePinned(virt_to_page(pgd))) ++ __pgd_unpin(pgd); ++} ++ + void mm_pin(struct mm_struct *mm) + { + if (xen_feature(XENFEAT_writable_page_tables)) + return; + + pin_lock(mm); +- +- mm_walk(mm, PAGE_KERNEL_RO); +- xen_pgd_pin(__pa(mm->pgd)); /* kernel */ +- xen_pgd_pin(__pa(__user_pgd(mm->pgd))); /* user */ +- SetPagePinned(virt_to_page(mm->pgd)); +- spin_lock(&mm_unpinned_lock); +- list_del(&mm->context.unpinned); +- spin_unlock(&mm_unpinned_lock); +- ++ __pgd_pin(mm->pgd); + pin_unlock(mm); + } + +@@ -185,34 +195,30 @@ void mm_unpin(struct mm_struct *mm) + return; + + pin_lock(mm); +- +- xen_pgd_unpin(__pa(mm->pgd)); +- xen_pgd_unpin(__pa(__user_pgd(mm->pgd))); +- mm_walk(mm, PAGE_KERNEL); +- ClearPagePinned(virt_to_page(mm->pgd)); +- spin_lock(&mm_unpinned_lock); +- list_add(&mm->context.unpinned, &mm_unpinned); +- spin_unlock(&mm_unpinned_lock); +- ++ __pgd_unpin(mm->pgd); + pin_unlock(mm); + } + + void mm_pin_all(void) + { ++ struct page *page; ++ unsigned long flags; ++ + if (xen_feature(XENFEAT_writable_page_tables)) + return; + + /* +- * Allow uninterrupted access to the mm_unpinned list. We don't +- * actually take the mm_unpinned_lock as it is taken inside mm_pin(). ++ * Allow uninterrupted access to the pgd_list. Also protects ++ * __pgd_pin() by disabling preemption. + * All other CPUs must be at a safe point (e.g., in stop_machine + * or offlined entirely). + */ +- preempt_disable(); +- while (!list_empty(&mm_unpinned)) +- mm_pin(list_entry(mm_unpinned.next, struct mm_struct, +- context.unpinned)); +- preempt_enable(); ++ spin_lock_irqsave(&pgd_lock, flags); ++ list_for_each_entry(page, &pgd_list, lru) { ++ if (!PagePinned(page)) ++ __pgd_pin((pgd_t *)page_address(page)); ++ } ++ spin_unlock_irqrestore(&pgd_lock, flags); + } + + void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +@@ -331,11 +337,11 @@ static struct page *split_large_page(uns + return base; + } + +-static void cache_flush_page(void *adr) ++void clflush_cache_range(void *adr, int size) + { + int i; +- for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) +- asm volatile("clflush (%0)" :: "r" (adr + i)); ++ for (i = 0; i < size; i += boot_cpu_data.x86_clflush_size) ++ clflush(adr+i); + } + + static void flush_kernel_map(void *arg) +@@ -350,7 +356,7 @@ static void flush_kernel_map(void *arg) + asm volatile("wbinvd" ::: "memory"); + else list_for_each_entry(pg, l, lru) { + void *adr = page_address(pg); +- cache_flush_page(adr); ++ clflush_cache_range(adr, PAGE_SIZE); + } + __flush_tlb_all(); + } +@@ -418,6 +424,7 @@ __change_page_attr(unsigned long address + split = split_large_page(address, prot, ref_prot2); + if (!split) + return -ENOMEM; ++ pgprot_val(ref_prot2) &= ~_PAGE_NX; + set_pte(kpte, mk_pte(split, ref_prot2)); + kpte_page = split; + } +@@ -510,9 +517,14 @@ void global_flush_tlb(void) + struct page *pg, *next; + struct list_head l; + +- down_read(&init_mm.mmap_sem); ++ /* ++ * Write-protect the semaphore, to exclude two contexts ++ * doing a list_replace_init() call in parallel and to ++ * exclude new additions to the deferred_pages list: ++ */ ++ down_write(&init_mm.mmap_sem); + list_replace_init(&deferred_pages, &l); +- up_read(&init_mm.mmap_sem); ++ up_write(&init_mm.mmap_sem); + + flush_map(&l); + +--- sle11-2009-06-29.orig/arch/x86/mm/pgtable_32-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/mm/pgtable_32-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -46,6 +47,8 @@ void show_mem(void) + for_each_online_pgdat(pgdat) { + pgdat_resize_lock(pgdat, &flags); + for (i = 0; i < pgdat->node_spanned_pages; ++i) { ++ if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) ++ touch_nmi_watchdog(); + page = pgdat_page_nr(pgdat, i); + total++; + if (PageHighMem(page)) +@@ -206,7 +209,7 @@ void pte_free(struct page *pte) + __free_page(pte); + } + +-void pmd_ctor(void *pmd, struct kmem_cache *cache, unsigned long flags) ++void pmd_ctor(struct kmem_cache *cache, void *pmd) + { + memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t)); + } +--- sle11-2009-06-29.orig/arch/x86/pci/irq-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/pci/irq-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -173,7 +173,7 @@ void eisa_set_level_irq(unsigned int irq + } + + /* +- * Common IRQ routing practice: nybbles in config space, ++ * Common IRQ routing practice: nibbles in config space, + * offset by some magic constant. + */ + static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr) +@@ -496,6 +496,26 @@ static int pirq_amd756_set(struct pci_de + return 1; + } + ++/* ++ * PicoPower PT86C523 ++ */ ++static int pirq_pico_get(struct pci_dev *router, struct pci_dev *dev, int pirq) ++{ ++ outb(0x10 + ((pirq - 1) >> 1), 0x24); ++ return ((pirq - 1) & 1) ? (inb(0x26) >> 4) : (inb(0x26) & 0xf); ++} ++ ++static int pirq_pico_set(struct pci_dev *router, struct pci_dev *dev, int pirq, ++ int irq) ++{ ++ unsigned int x; ++ outb(0x10 + ((pirq - 1) >> 1), 0x24); ++ x = inb(0x26); ++ x = ((pirq - 1) & 1) ? ((x & 0x0f) | (irq << 4)) : ((x & 0xf0) | (irq)); ++ outb(x, 0x26); ++ return 1; ++} ++ + #ifdef CONFIG_PCI_BIOS + + static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +@@ -569,7 +589,7 @@ static __init int via_router_probe(struc + /* FIXME: We should move some of the quirk fixup stuff here */ + + /* +- * work arounds for some buggy BIOSes ++ * workarounds for some buggy BIOSes + */ + if (device == PCI_DEVICE_ID_VIA_82C586_0) { + switch(router->device) { +@@ -725,6 +745,24 @@ static __init int amd_router_probe(struc + return 1; + } + ++static __init int pico_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) ++{ ++ switch (device) { ++ case PCI_DEVICE_ID_PICOPOWER_PT86C523: ++ r->name = "PicoPower PT86C523"; ++ r->get = pirq_pico_get; ++ r->set = pirq_pico_set; ++ return 1; ++ ++ case PCI_DEVICE_ID_PICOPOWER_PT86C523BBP: ++ r->name = "PicoPower PT86C523 rev. BB+"; ++ r->get = pirq_pico_get; ++ r->set = pirq_pico_set; ++ return 1; ++ } ++ return 0; ++} ++ + static __initdata struct irq_router_handler pirq_routers[] = { + { PCI_VENDOR_ID_INTEL, intel_router_probe }, + { PCI_VENDOR_ID_AL, ali_router_probe }, +@@ -736,6 +774,7 @@ static __initdata struct irq_router_hand + { PCI_VENDOR_ID_VLSI, vlsi_router_probe }, + { PCI_VENDOR_ID_SERVERWORKS, serverworks_router_probe }, + { PCI_VENDOR_ID_AMD, amd_router_probe }, ++ { PCI_VENDOR_ID_PICOPOWER, pico_router_probe }, + /* Someone with docs needs to add the ATI Radeon IGP */ + { 0, NULL } + }; +@@ -1014,7 +1053,7 @@ static void __init pcibios_fixup_irqs(vo + * Work around broken HP Pavilion Notebooks which assign USB to + * IRQ 9 even though it is actually wired to IRQ 11 + */ +-static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d) ++static int __init fix_broken_hp_bios_irq9(const struct dmi_system_id *d) + { + if (!broken_hp_bios_irq9) { + broken_hp_bios_irq9 = 1; +@@ -1027,7 +1066,7 @@ static int __init fix_broken_hp_bios_irq + * Work around broken Acer TravelMate 360 Notebooks which assign + * Cardbus to IRQ 11 even though it is actually wired to IRQ 10 + */ +-static int __init fix_acer_tm360_irqrouting(struct dmi_system_id *d) ++static int __init fix_acer_tm360_irqrouting(const struct dmi_system_id *d) + { + if (!acer_tm360_irqrouting) { + acer_tm360_irqrouting = 1; +--- sle11-2009-06-29.orig/drivers/acpi/processor_idle.c 2009-06-29 15:17:44.000000000 +0200 ++++ sle11-2009-06-29/drivers/acpi/processor_idle.c 2009-06-29 15:29:06.000000000 +0200 +@@ -1749,6 +1749,13 @@ int acpi_processor_cst_has_changed(struc + if (!pr->flags.power_setup_done) + return -ENODEV; + ++ if (processor_pm_external()) { ++ acpi_processor_get_power_info(pr); ++ processor_notify_external(pr, ++ PROCESSOR_PM_CHANGE, PM_TYPE_IDLE); ++ return ret; ++ } ++ + cpuidle_pause_and_lock(); + cpuidle_disable_device(&pr->power.dev); + acpi_processor_get_power_info(pr); +--- sle11-2009-06-29.orig/drivers/cpuidle/Kconfig 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/cpuidle/Kconfig 2009-02-16 16:18:36.000000000 +0100 +@@ -1,6 +1,7 @@ + + config CPU_IDLE + bool "CPU idle PM support" ++ depends on !PROCESSOR_EXTERNAL_CONTROL + default ACPI + help + CPU idle is a generic framework for supporting software-controlled +--- sle11-2009-06-29.orig/drivers/oprofile/cpu_buffer.c 2009-02-16 16:01:39.000000000 +0100 ++++ sle11-2009-06-29/drivers/oprofile/cpu_buffer.c 2009-03-12 16:15:32.000000000 +0100 +@@ -308,6 +308,37 @@ void oprofile_add_trace(unsigned long pc + } + + #ifdef CONFIG_XEN ++/* ++ * This is basically log_sample(b, ESCAPE_CODE, cpu_mode, CPU_TRACE_BEGIN), ++ * as was previously accessible through oprofile_add_pc(). ++ */ ++void oprofile_add_mode(int cpu_mode) ++{ ++ struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); ++ struct task_struct *task; ++ ++ if (nr_available_slots(cpu_buf) < 3) { ++ cpu_buf->sample_lost_overflow++; ++ return; ++ } ++ ++ task = current; ++ ++ /* notice a switch from user->kernel or vice versa */ ++ if (cpu_buf->last_cpu_mode != cpu_mode) { ++ cpu_buf->last_cpu_mode = cpu_mode; ++ add_code(cpu_buf, cpu_mode); ++ } ++ ++ /* notice a task switch */ ++ if (cpu_buf->last_task != task) { ++ cpu_buf->last_task = task; ++ add_code(cpu_buf, (unsigned long)task); ++ } ++ ++ add_code(cpu_buf, CPU_TRACE_BEGIN); ++} ++ + int oprofile_add_domain_switch(int32_t domain_id) + { + struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()]; +--- sle11-2009-06-29.orig/drivers/pci/msi-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/drivers/pci/msi-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -264,6 +264,12 @@ static int msi_map_vector(struct pci_dev + return msi_map_pirq_to_vector(dev, -1, entry_nr, table_base); + } + ++static void pci_intx_for_msi(struct pci_dev *dev, int enable) ++{ ++ if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG)) ++ pci_intx(dev, enable); ++} ++ + #ifdef CONFIG_PM + static void __pci_restore_msi_state(struct pci_dev *dev) + { +@@ -272,7 +278,7 @@ static void __pci_restore_msi_state(stru + if (!dev->msi_enabled) + return; + +- pci_intx(dev, 0); /* disable intx */ ++ pci_intx_for_msi(dev, 0); + msi_set_enable(dev, 0); + + pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 0); +@@ -295,7 +301,7 @@ static void __pci_restore_msix_state(str + if (!dev->msix_enabled) + return; + +- pci_intx(dev, 0); /* disable intx */ ++ pci_intx_for_msi(dev, 0); + msix_set_enable(dev, 0); + + msi_dev_entry = get_msi_dev_pirq_list(dev); +@@ -348,7 +354,7 @@ static int msi_capability_init(struct pc + return -EBUSY; + + /* Set MSI enabled bits */ +- pci_intx(dev, 0); /* disable intx */ ++ pci_intx_for_msi(dev, 0); + msi_set_enable(dev, 1); + dev->msi_enabled = 1; + +@@ -422,7 +428,7 @@ static int msix_capability_init(struct p + return avail; + } + +- pci_intx(dev, 0); /* disable intx */ ++ pci_intx_for_msi(dev, 0); + msix_set_enable(dev, 1); + dev->msix_enabled = 1; + +@@ -557,7 +563,7 @@ void pci_disable_msi(struct pci_dev* dev + + /* Disable MSI mode */ + msi_set_enable(dev, 0); +- pci_intx(dev, 1); /* enable intx */ ++ pci_intx_for_msi(dev, 1); + dev->msi_enabled = 0; + } + EXPORT_SYMBOL(pci_disable_msi); +@@ -696,7 +702,7 @@ void pci_disable_msix(struct pci_dev* de + + /* Disable MSI mode */ + msix_set_enable(dev, 0); +- pci_intx(dev, 1); /* enable intx */ ++ pci_intx_for_msi(dev, 1); + dev->msix_enabled = 0; + } + EXPORT_SYMBOL(pci_disable_msix); +--- sle11-2009-06-29.orig/drivers/xen/blkback/blkback.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/blkback/blkback.c 2009-02-16 16:18:36.000000000 +0100 +@@ -269,13 +269,10 @@ static void __end_block_io_op(pending_re + } + } + +-static int end_block_io_op(struct bio *bio, unsigned int done, int error) ++static void end_block_io_op(struct bio *bio, int error) + { +- if (bio->bi_size != 0) +- return 1; + __end_block_io_op(bio->bi_private, error); + bio_put(bio); +- return error; + } + + +--- sle11-2009-06-29.orig/drivers/xen/blkfront/blkfront.c 2009-03-24 10:12:03.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/blkfront/blkfront.c 2009-02-16 16:18:36.000000000 +0100 +@@ -233,7 +233,7 @@ static int setup_blkring(struct xenbus_d + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); + +- memset(info->sg, 0, sizeof(info->sg)); ++ sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); + + err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); + if (err < 0) { +@@ -625,9 +625,8 @@ static int blkif_queue_request(struct re + + ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); + BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); +- for (i = 0; i < ring_req->nr_segments; ++i) { +- sg = info->sg + i; +- buffer_mfn = page_to_phys(sg->page) >> PAGE_SHIFT; ++ for_each_sg(info->sg, sg, ring_req->nr_segments, i) { ++ buffer_mfn = page_to_phys(sg_page(sg)) >> PAGE_SHIFT; + fsect = sg->offset >> 9; + lsect = fsect + (sg->length >> 9) - 1; + /* install a grant reference. */ +--- sle11-2009-06-29.orig/drivers/xen/core/firmware.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/core/firmware.c 2009-03-25 18:10:23.000000000 +0100 +@@ -1,4 +1,5 @@ + #include ++#include + #include + #include + #include +--- sle11-2009-06-29.orig/drivers/xen/core/machine_kexec.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/core/machine_kexec.c 2009-02-17 11:46:41.000000000 +0100 +@@ -29,6 +29,10 @@ void __init xen_machine_kexec_setup_reso + int k = 0; + int rc; + ++ if (strstr(boot_command_line, "crashkernel=")) ++ printk(KERN_WARNING "Ignoring crashkernel command line, " ++ "parameter will be supplied by xen\n"); ++ + if (!is_initial_xendomain()) + return; + +@@ -130,6 +134,13 @@ void __init xen_machine_kexec_setup_reso + xen_max_nr_phys_cpus)) + goto err; + ++#ifdef CONFIG_X86 ++ if (xen_create_contiguous_region((unsigned long)&vmcoreinfo_note, ++ get_order(sizeof(vmcoreinfo_note)), ++ BITS_PER_LONG)) ++ goto err; ++#endif ++ + return; + + err: +@@ -205,6 +216,13 @@ NORET_TYPE void machine_kexec(struct kim + panic("KEXEC_CMD_kexec hypercall should not return\n"); + } + ++#ifdef CONFIG_X86 ++unsigned long paddr_vmcoreinfo_note(void) ++{ ++ return virt_to_machine(&vmcoreinfo_note); ++} ++#endif ++ + void machine_shutdown(void) + { + /* do nothing */ +--- sle11-2009-06-29.orig/drivers/xen/core/smpboot.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/core/smpboot.c 2009-02-16 16:18:36.000000000 +0100 +@@ -45,8 +45,8 @@ cpumask_t cpu_possible_map; + EXPORT_SYMBOL(cpu_possible_map); + cpumask_t cpu_initialized_map; + +-struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; +-EXPORT_SYMBOL(cpu_data); ++DEFINE_PER_CPU(struct cpuinfo_x86, cpu_info); ++EXPORT_PER_CPU_SYMBOL(cpu_info); + + static DEFINE_PER_CPU(int, resched_irq); + static DEFINE_PER_CPU(int, callfunc_irq); +@@ -55,13 +55,13 @@ static char callfunc_name[NR_CPUS][15]; + + u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; + +-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; +-cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; +-EXPORT_SYMBOL(cpu_core_map); ++DEFINE_PER_CPU(cpumask_t, cpu_sibling_map); ++DEFINE_PER_CPU(cpumask_t, cpu_core_map); ++EXPORT_PER_CPU_SYMBOL(cpu_core_map); + + #if defined(__i386__) +-u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff }; +-EXPORT_SYMBOL(x86_cpu_to_apicid); ++DEFINE_PER_CPU(u8, x86_cpu_to_apicid) = BAD_APICID; ++EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid); + #endif + + void __init prefill_possible_map(void) +@@ -86,25 +86,25 @@ void __init smp_alloc_memory(void) + static inline void + set_cpu_sibling_map(unsigned int cpu) + { +- cpu_data[cpu].phys_proc_id = cpu; +- cpu_data[cpu].cpu_core_id = 0; ++ cpu_data(cpu).phys_proc_id = cpu; ++ cpu_data(cpu).cpu_core_id = 0; + +- cpu_sibling_map[cpu] = cpumask_of_cpu(cpu); +- cpu_core_map[cpu] = cpumask_of_cpu(cpu); ++ per_cpu(cpu_sibling_map, cpu) = cpumask_of_cpu(cpu); ++ per_cpu(cpu_core_map, cpu) = cpumask_of_cpu(cpu); + +- cpu_data[cpu].booted_cores = 1; ++ cpu_data(cpu).booted_cores = 1; + } + + static void + remove_siblinginfo(unsigned int cpu) + { +- cpu_data[cpu].phys_proc_id = BAD_APICID; +- cpu_data[cpu].cpu_core_id = BAD_APICID; ++ cpu_data(cpu).phys_proc_id = BAD_APICID; ++ cpu_data(cpu).cpu_core_id = BAD_APICID; + +- cpus_clear(cpu_sibling_map[cpu]); +- cpus_clear(cpu_core_map[cpu]); ++ cpus_clear(per_cpu(cpu_sibling_map, cpu)); ++ cpus_clear(per_cpu(cpu_core_map, cpu)); + +- cpu_data[cpu].booted_cores = 0; ++ cpu_data(cpu).booted_cores = 0; + } + + static int __cpuinit xen_smp_intr_init(unsigned int cpu) +@@ -163,9 +163,9 @@ void __cpuinit cpu_bringup(void) + { + cpu_init(); + #ifdef __i386__ +- identify_secondary_cpu(cpu_data + smp_processor_id()); ++ identify_secondary_cpu(¤t_cpu_data); + #else +- identify_cpu(cpu_data + smp_processor_id()); ++ identify_cpu(¤t_cpu_data); + #endif + touch_softlockup_watchdog(); + preempt_disable(); +@@ -266,16 +266,16 @@ void __init smp_prepare_cpus(unsigned in + if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, 0, &cpu_id) == 0) + apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id); + boot_cpu_data.apicid = apicid; +- cpu_data[0] = boot_cpu_data; ++ cpu_data(0) = boot_cpu_data; + + cpu_2_logical_apicid[0] = apicid; +- x86_cpu_to_apicid[0] = apicid; ++ per_cpu(x86_cpu_to_apicid, 0) = apicid; + + current_thread_info()->cpu = 0; + + for (cpu = 0; cpu < NR_CPUS; cpu++) { +- cpus_clear(cpu_sibling_map[cpu]); +- cpus_clear(cpu_core_map[cpu]); ++ cpus_clear(per_cpu(cpu_sibling_map, cpu)); ++ cpus_clear(per_cpu(cpu_core_map, cpu)); + } + + set_cpu_sibling_map(0); +@@ -320,11 +320,12 @@ void __init smp_prepare_cpus(unsigned in + apicid = cpu; + if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) + apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id); +- cpu_data[cpu] = boot_cpu_data; +- cpu_data[cpu].apicid = apicid; ++ cpu_data(cpu) = boot_cpu_data; ++ cpu_data(cpu).cpu_index = cpu; ++ cpu_data(cpu).apicid = apicid; + + cpu_2_logical_apicid[cpu] = apicid; +- x86_cpu_to_apicid[cpu] = apicid; ++ per_cpu(x86_cpu_to_apicid, cpu) = apicid; + + #ifdef __x86_64__ + cpu_pda(cpu)->pcurrent = idle; +--- sle11-2009-06-29.orig/drivers/xen/netback/loopback.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/netback/loopback.c 2009-02-16 16:18:36.000000000 +0100 +@@ -285,9 +285,9 @@ static void __exit clean_loopback(int i) + char dev_name[IFNAMSIZ]; + + sprintf(dev_name, "vif0.%d", i); +- dev1 = dev_get_by_name(dev_name); ++ dev1 = dev_get_by_name(&init_net, dev_name); + sprintf(dev_name, "veth%d", i); +- dev2 = dev_get_by_name(dev_name); ++ dev2 = dev_get_by_name(&init_net, dev_name); + if (dev1 && dev2) { + unregister_netdev(dev2); + unregister_netdev(dev1); +--- sle11-2009-06-29.orig/drivers/xen/netback/netback.c 2008-12-23 09:33:22.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/netback/netback.c 2009-02-16 16:18:36.000000000 +0100 +@@ -350,8 +350,8 @@ static void xen_network_done_notify(void + { + static struct net_device *eth0_dev = NULL; + if (unlikely(eth0_dev == NULL)) +- eth0_dev = __dev_get_by_name("eth0"); +- netif_rx_schedule(eth0_dev); ++ eth0_dev = __dev_get_by_name(&init_net, "eth0"); ++ netif_rx_schedule(eth0_dev, ???); + } + /* + * Add following to poll() function in NAPI driver (Tigon3 is example): +--- sle11-2009-06-29.orig/drivers/xen/netback/xenbus.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/netback/xenbus.c 2009-02-16 16:18:36.000000000 +0100 +@@ -149,12 +149,10 @@ fail: + * and vif variables to the environment, for the benefit of the vif-* hotplug + * scripts. + */ +-static int netback_uevent(struct xenbus_device *xdev, char **envp, +- int num_envp, char *buffer, int buffer_size) ++static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env) + { + struct backend_info *be = xdev->dev.driver_data; + netif_t *netif = be->netif; +- int i = 0, length = 0; + char *val; + + DPRINTK("netback_uevent"); +@@ -166,15 +164,11 @@ static int netback_uevent(struct xenbus_ + return err; + } + else { +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, +- &length, "script=%s", val); ++ add_uevent_var(env, "script=%s", val); + kfree(val); + } + +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "vif=%s", netif->dev->name); +- +- envp[i] = NULL; ++ add_uevent_var(env, "vif=%s", netif->dev->name); + + return 0; + } +--- sle11-2009-06-29.orig/drivers/xen/netfront/accel.c 2009-04-09 14:43:45.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/netfront/accel.c 2009-03-30 16:39:19.000000000 +0200 +@@ -313,7 +313,7 @@ accelerator_set_vif_state_hooks(struct n + DPRINTK("%p\n",vif_state); + + /* Make sure there are no data path operations going on */ +- netif_poll_disable(vif_state->np->netdev); ++ napi_disable(&vif_state->np->napi); + netif_tx_lock_bh(vif_state->np->netdev); + + accelerator = vif_state->np->accelerator; +@@ -322,7 +322,7 @@ accelerator_set_vif_state_hooks(struct n + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + + netif_tx_unlock_bh(vif_state->np->netdev); +- netif_poll_enable(vif_state->np->netdev); ++ napi_enable(&vif_state->np->napi); + } + + +@@ -496,7 +496,7 @@ accelerator_remove_single_hook(struct ne + unsigned long flags; + + /* Make sure there are no data path operations going on */ +- netif_poll_disable(vif_state->np->netdev); ++ napi_disable(&vif_state->np->napi); + netif_tx_lock_bh(vif_state->np->netdev); + + spin_lock_irqsave(&accelerator->vif_states_lock, flags); +@@ -512,7 +512,7 @@ accelerator_remove_single_hook(struct ne + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + + netif_tx_unlock_bh(vif_state->np->netdev); +- netif_poll_enable(vif_state->np->netdev); ++ napi_enable(&vif_state->np->napi); + } + + +--- sle11-2009-06-29.orig/drivers/xen/netfront/netfront.c 2009-03-30 16:36:30.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/netfront/netfront.c 2009-03-30 16:39:44.000000000 +0200 +@@ -626,6 +626,7 @@ static int network_open(struct net_devic + struct netfront_info *np = netdev_priv(dev); + + memset(&np->stats, 0, sizeof(np->stats)); ++ napi_enable(&np->napi); + + spin_lock_bh(&np->rx_lock); + if (netfront_carrier_ok(np)) { +@@ -634,7 +635,7 @@ static int network_open(struct net_devic + if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)){ + netfront_accelerator_call_stop_napi_irq(np, dev); + +- netif_rx_schedule(dev); ++ netif_rx_schedule(dev, &np->napi); + } + } + spin_unlock_bh(&np->rx_lock); +@@ -706,7 +707,7 @@ static void rx_refill_timeout(unsigned l + + netfront_accelerator_call_stop_napi_irq(np, dev); + +- netif_rx_schedule(dev); ++ netif_rx_schedule(dev, &np->napi); + } + + static void network_alloc_rx_buffers(struct net_device *dev) +@@ -1063,7 +1064,7 @@ static irqreturn_t netif_int(int irq, vo + if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) { + netfront_accelerator_call_stop_napi_irq(np, dev); + +- netif_rx_schedule(dev); ++ netif_rx_schedule(dev, &np->napi); + dev->last_rx = jiffies; + } + } +@@ -1316,16 +1317,17 @@ static int xennet_set_skb_gso(struct sk_ + #endif + } + +-static int netif_poll(struct net_device *dev, int *pbudget) ++static int netif_poll(struct napi_struct *napi, int budget) + { +- struct netfront_info *np = netdev_priv(dev); ++ struct netfront_info *np = container_of(napi, struct netfront_info, napi); ++ struct net_device *dev = np->netdev; + struct sk_buff *skb; + struct netfront_rx_info rinfo; + struct netif_rx_response *rx = &rinfo.rx; + struct netif_extra_info *extras = rinfo.extras; + RING_IDX i, rp; + struct multicall_entry *mcl; +- int work_done, budget, more_to_do = 1, accel_more_to_do = 1; ++ int work_done, more_to_do = 1, accel_more_to_do = 1; + struct sk_buff_head rxq; + struct sk_buff_head errq; + struct sk_buff_head tmpq; +@@ -1345,8 +1347,6 @@ static int netif_poll(struct net_device + skb_queue_head_init(&errq); + skb_queue_head_init(&tmpq); + +- if ((budget = *pbudget) > dev->quota) +- budget = dev->quota; + rp = np->rx.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + +@@ -1508,9 +1508,6 @@ err: + accel_more_to_do = 0; + } + +- *pbudget -= work_done; +- dev->quota -= work_done; +- + if (work_done < budget) { + local_irq_save(flags); + +@@ -1527,14 +1524,14 @@ err: + } + + if (!more_to_do && !accel_more_to_do) +- __netif_rx_complete(dev); ++ __netif_rx_complete(dev, napi); + + local_irq_restore(flags); + } + + spin_unlock(&np->rx_lock); + +- return more_to_do | accel_more_to_do; ++ return work_done; + } + + static void netif_release_tx_bufs(struct netfront_info *np) +@@ -1681,6 +1678,7 @@ static int network_close(struct net_devi + { + struct netfront_info *np = netdev_priv(dev); + netif_stop_queue(np->netdev); ++ napi_disable(&np->napi); + return 0; + } + +@@ -2088,16 +2086,14 @@ static struct net_device * __devinit cre + netdev->hard_start_xmit = network_start_xmit; + netdev->stop = network_close; + netdev->get_stats = network_get_stats; +- netdev->poll = netif_poll; ++ netif_napi_add(netdev, &np->napi, netif_poll, 64); + netdev->set_multicast_list = network_set_multicast_list; + netdev->uninit = netif_uninit; + netdev->set_mac_address = xennet_set_mac_address; + netdev->change_mtu = xennet_change_mtu; +- netdev->weight = 64; + netdev->features = NETIF_F_IP_CSUM; + + SET_ETHTOOL_OPS(netdev, &network_ethtool_ops); +- SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &dev->dev); + + np->netdev = netdev; +--- sle11-2009-06-29.orig/drivers/xen/netfront/netfront.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/netfront/netfront.h 2009-02-16 16:18:36.000000000 +0100 +@@ -157,6 +157,8 @@ struct netfront_info { + spinlock_t tx_lock; + spinlock_t rx_lock; + ++ struct napi_struct napi; ++ + unsigned int irq; + unsigned int copying_receiver; + unsigned int carrier; +--- sle11-2009-06-29.orig/drivers/xen/pciback/Makefile 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/pciback/Makefile 2009-02-16 16:18:36.000000000 +0100 +@@ -12,6 +12,4 @@ pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT + pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o + pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o + +-ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y) +-EXTRA_CFLAGS += -DDEBUG +-endif ++ccflags-$(CONFIG_XEN_PCIDEV_BE_DEBUG) += -DDEBUG +--- sle11-2009-06-29.orig/drivers/xen/pcifront/Makefile 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/pcifront/Makefile 2009-02-16 16:18:36.000000000 +0100 +@@ -2,6 +2,4 @@ obj-y += pcifront.o + + pcifront-y := pci_op.o xenbus.o pci.o + +-ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y) +-EXTRA_CFLAGS += -DDEBUG +-endif ++ccflags-$(CONFIG_XEN_PCIDEV_FE_DEBUG) += -DDEBUG +--- sle11-2009-06-29.orig/drivers/xen/scsiback/emulate.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/scsiback/emulate.c 2009-02-16 16:18:36.000000000 +0100 +@@ -104,9 +104,10 @@ static void resp_not_supported_cmd(pendi + } + + +-static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg, ++static int __copy_to_sg(struct scatterlist *sgl, unsigned int nr_sg, + void *buf, unsigned int buflen) + { ++ struct scatterlist *sg; + void *from = buf; + void *to; + unsigned int from_rest = buflen; +@@ -115,8 +116,8 @@ static int __copy_to_sg(struct scatterli + unsigned int i; + unsigned long pfn; + +- for (i = 0; i < nr_sg; i++) { +- if (sg->page == NULL) { ++ for_each_sg (sgl, sg, nr_sg, i) { ++ if (sg_page(sg) == NULL) { + printk(KERN_WARNING "%s: inconsistent length field in " + "scatterlist\n", __FUNCTION__); + return -ENOMEM; +@@ -125,7 +126,7 @@ static int __copy_to_sg(struct scatterli + to_capa = sg->length; + copy_size = min_t(unsigned int, to_capa, from_rest); + +- pfn = page_to_pfn(sg->page); ++ pfn = page_to_pfn(sg_page(sg)); + to = pfn_to_kaddr(pfn) + (sg->offset); + memcpy(to, from, copy_size); + +@@ -134,7 +135,6 @@ static int __copy_to_sg(struct scatterli + return 0; + } + +- sg++; + from += copy_size; + } + +@@ -143,9 +143,10 @@ static int __copy_to_sg(struct scatterli + return -ENOMEM; + } + +-static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg, ++static int __copy_from_sg(struct scatterlist *sgl, unsigned int nr_sg, + void *buf, unsigned int buflen) + { ++ struct scatterlist *sg; + void *from; + void *to = buf; + unsigned int from_rest; +@@ -154,8 +155,8 @@ static int __copy_from_sg(struct scatter + unsigned int i; + unsigned long pfn; + +- for (i = 0; i < nr_sg; i++) { +- if (sg->page == NULL) { ++ for_each_sg (sgl, sg, nr_sg, i) { ++ if (sg_page(sg) == NULL) { + printk(KERN_WARNING "%s: inconsistent length field in " + "scatterlist\n", __FUNCTION__); + return -ENOMEM; +@@ -170,13 +171,11 @@ static int __copy_from_sg(struct scatter + } + copy_size = from_rest; + +- pfn = page_to_pfn(sg->page); ++ pfn = page_to_pfn(sg_page(sg)); + from = pfn_to_kaddr(pfn) + (sg->offset); + memcpy(to, from, copy_size); + + to_capa -= copy_size; +- +- sg++; + to += copy_size; + } + +--- sle11-2009-06-29.orig/drivers/xen/scsiback/scsiback.c 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/scsiback/scsiback.c 2009-02-16 16:18:36.000000000 +0100 +@@ -247,6 +247,8 @@ static int scsiback_gnttab_data_map(vscs + write = (data_dir == DMA_TO_DEVICE); + + if (nr_segments) { ++ struct scatterlist *sg; ++ + /* free of (sgl) in fast_flush_area()*/ + pending_req->sgl = kmalloc(sizeof(struct scatterlist) * nr_segments, + GFP_KERNEL); +@@ -255,6 +257,8 @@ static int scsiback_gnttab_data_map(vscs + return -ENOMEM; + } + ++ sg_init_table(pending_req->sgl, nr_segments); ++ + for (i = 0; i < nr_segments; i++) { + flags = GNTMAP_host_map; + if (write) +@@ -267,7 +271,7 @@ static int scsiback_gnttab_data_map(vscs + err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nr_segments); + BUG_ON(err); + +- for (i = 0; i < nr_segments; i++) { ++ for_each_sg (pending_req->sgl, sg, nr_segments, i) { + if (unlikely(map[i].status != 0)) { + printk(KERN_ERR "scsiback: invalid buffer -- could not remap it\n"); + map[i].handle = SCSIBACK_INVALID_HANDLE; +@@ -283,15 +287,15 @@ static int scsiback_gnttab_data_map(vscs + pending_req, i)) >> PAGE_SHIFT, + FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT)); + +- pending_req->sgl[i].page = virt_to_page(vaddr(pending_req, i)); +- pending_req->sgl[i].offset = ring_req->seg[i].offset; +- pending_req->sgl[i].length = ring_req->seg[i].length; +- data_len += pending_req->sgl[i].length; ++ sg_set_page(sg, virt_to_page(vaddr(pending_req, i)), ++ ring_req->seg[i].length, ++ ring_req->seg[i].offset); ++ data_len += sg->length; + + barrier(); +- if (pending_req->sgl[i].offset >= PAGE_SIZE || +- pending_req->sgl[i].length > PAGE_SIZE || +- pending_req->sgl[i].offset + pending_req->sgl[i].length > PAGE_SIZE) ++ if (sg->offset >= PAGE_SIZE || ++ sg->length > PAGE_SIZE || ++ sg->offset + sg->length > PAGE_SIZE) + err |= 1; + + } +@@ -320,27 +324,14 @@ static int scsiback_merge_bio(struct req + + blk_queue_bounce(q, &bio); + +- if (!rq->bio) +- blk_rq_bio_prep(q, rq, bio); +- else if (!ll_back_merge_fn(q, rq, bio)) +- return -EINVAL; +- else { +- rq->biotail->bi_next = bio; +- rq->biotail = bio; +- } +- +- return 0; ++ return blk_rq_append_bio(q, rq, bio); + } + + + /* quoted scsi_lib.c/scsi_bi_endio */ +-static int scsiback_bi_endio(struct bio *bio, unsigned int bytes_done, int error) ++static void scsiback_bi_endio(struct bio *bio, int error) + { +- if (bio->bi_size) +- return 1; +- + bio_put(bio); +- return 0; + } + + +@@ -351,16 +342,16 @@ static int request_map_sg(struct request + struct request_queue *q = rq->q; + int nr_pages; + unsigned int nsegs = count; +- + unsigned int data_len = 0, len, bytes, off; ++ struct scatterlist *sg; + struct page *page; + struct bio *bio = NULL; + int i, err, nr_vecs = 0; + +- for (i = 0; i < nsegs; i++) { +- page = pending_req->sgl[i].page; +- off = (unsigned int)pending_req->sgl[i].offset; +- len = (unsigned int)pending_req->sgl[i].length; ++ for_each_sg (pending_req->sgl, sg, nsegs, i) { ++ page = sg_page(sg); ++ off = sg->offset; ++ len = sg->length; + data_len += len; + + nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT; +@@ -388,7 +379,7 @@ static int request_map_sg(struct request + if (bio->bi_vcnt >= nr_vecs) { + err = scsiback_merge_bio(rq, bio); + if (err) { +- bio_endio(bio, bio->bi_size, 0); ++ bio_endio(bio, 0); + goto free_bios; + } + bio = NULL; +@@ -411,7 +402,7 @@ free_bios: + /* + * call endio instead of bio_put incase it was bounced + */ +- bio_endio(bio, bio->bi_size, 0); ++ bio_endio(bio, 0); + } + + return err; +--- sle11-2009-06-29.orig/drivers/xen/scsifront/scsifront.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/scsifront/scsifront.c 2009-02-16 16:18:36.000000000 +0100 +@@ -246,11 +246,10 @@ static int map_data_for_request(struct v + { + grant_ref_t gref_head; + struct page *page; +- int err, i, ref, ref_cnt = 0; ++ int err, ref, ref_cnt = 0; + int write = (sc->sc_data_direction == DMA_TO_DEVICE); +- int nr_pages, off, len, bytes; ++ unsigned int i, nr_pages, off, len, bytes; + unsigned long buffer_pfn; +- unsigned int data_len = 0; + + if (sc->sc_data_direction == DMA_NONE) + return 0; +@@ -263,25 +262,31 @@ static int map_data_for_request(struct v + + if (sc->use_sg) { + /* quoted scsi_lib.c/scsi_req_map_sg . */ +- struct scatterlist *sg = (struct scatterlist *)sc->request_buffer; +- nr_pages = (sc->request_bufflen + sg[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; ++ struct scatterlist *sg, *sgl = (struct scatterlist *)sc->request_buffer; ++ unsigned int data_len = sc->request_bufflen; + ++ nr_pages = (sc->request_bufflen + sgl->offset + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (nr_pages > VSCSIIF_SG_TABLESIZE) { + printk(KERN_ERR "scsifront: Unable to map request_buffer for command!\n"); + ref_cnt = (-E2BIG); + goto big_to_sg; + } + +- for (i = 0; i < sc->use_sg; i++) { +- page = sg[i].page; +- off = sg[i].offset; +- len = sg[i].length; +- data_len += len; ++ for_each_sg (sgl, sg, sc->use_sg, i) { ++ page = sg_page(sg); ++ off = sg->offset; ++ len = sg->length; + + buffer_pfn = page_to_phys(page) >> PAGE_SHIFT; + +- while (len > 0) { ++ while (len > 0 && data_len > 0) { ++ /* ++ * sg sends a scatterlist that is larger than ++ * the data_len it wants transferred for certain ++ * IO sizes ++ */ + bytes = min_t(unsigned int, len, PAGE_SIZE - off); ++ bytes = min(bytes, data_len); + + ref = gnttab_claim_grant_reference(&gref_head); + BUG_ON(ref == -ENOSPC); +@@ -296,6 +301,7 @@ static int map_data_for_request(struct v + + buffer_pfn++; + len -= bytes; ++ data_len -= bytes; + off = 0; + ref_cnt++; + } +--- sle11-2009-06-29.orig/drivers/xen/sfc_netback/accel_fwd.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/sfc_netback/accel_fwd.c 2009-02-16 16:18:36.000000000 +0100 +@@ -181,10 +181,11 @@ int netback_accel_fwd_add(const __u8 *ma + unsigned long flags; + cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac); + struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv; ++ DECLARE_MAC_BUF(buf); + + BUG_ON(fwd_priv == NULL); + +- DPRINTK("Adding mac " MAC_FMT "\n", MAC_ARG(mac)); ++ DPRINTK("Adding mac %s\n", print_mac(buf, mac)); + + spin_lock_irqsave(&fwd_set->fwd_lock, flags); + +@@ -199,8 +200,8 @@ int netback_accel_fwd_add(const __u8 *ma + if (cuckoo_hash_lookup(&fwd_set->fwd_hash_table, + (cuckoo_hash_key *)(&key), &rc) != 0) { + spin_unlock_irqrestore(&fwd_set->fwd_lock, flags); +- EPRINTK("MAC address " MAC_FMT " already accelerated.\n", +- MAC_ARG(mac)); ++ EPRINTK("MAC address %s already accelerated.\n", ++ print_mac(buf, mac)); + return -EEXIST; + } + +@@ -235,8 +236,9 @@ void netback_accel_fwd_remove(const __u8 + unsigned long flags; + cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac); + struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv; ++ DECLARE_MAC_BUF(buf); + +- DPRINTK("Removing mac " MAC_FMT "\n", MAC_ARG(mac)); ++ DPRINTK("Removing mac %s\n", print_mac(buf, mac)); + + BUG_ON(fwd_priv == NULL); + +@@ -394,14 +396,16 @@ void netback_accel_tx_packet(struct sk_b + + if (is_broadcast_ether_addr(skb_mac_header(skb)) + && packet_is_arp_reply(skb)) { ++ DECLARE_MAC_BUF(buf); ++ + /* + * update our fast path forwarding to reflect this + * gratuitous ARP + */ + mac = skb_mac_header(skb)+ETH_ALEN; + +- DPRINTK("%s: found gratuitous ARP for " MAC_FMT "\n", +- __FUNCTION__, MAC_ARG(mac)); ++ DPRINTK("%s: found gratuitous ARP for %s\n", ++ __FUNCTION__, print_mac(buf, mac)); + + spin_lock_irqsave(&fwd_set->fwd_lock, flags); + /* +--- sle11-2009-06-29.orig/drivers/xen/sfc_netback/accel_msg.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/sfc_netback/accel_msg.c 2009-02-16 16:18:36.000000000 +0100 +@@ -57,11 +57,11 @@ static void netback_accel_msg_tx_localma + { + unsigned long lock_state; + struct net_accel_msg *msg; ++ DECLARE_MAC_BUF(buf); + + BUG_ON(bend == NULL || mac == NULL); + +- VPRINTK("Sending local mac message: " MAC_FMT "\n", +- MAC_ARG((const char *)mac)); ++ VPRINTK("Sending local mac message: %s\n", print_mac(buf, mac)); + + msg = net_accel_msg_start_send(bend->shared_page, &bend->to_domU, + &lock_state); +--- sle11-2009-06-29.orig/drivers/xen/sfc_netfront/accel_msg.c 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/sfc_netfront/accel_msg.c 2009-02-16 16:18:36.000000000 +0100 +@@ -41,11 +41,13 @@ static void vnic_start_interrupts(netfro + /* Prime our interrupt */ + spin_lock_irqsave(&vnic->irq_enabled_lock, flags); + if (!netfront_accel_vi_enable_interrupts(vnic)) { ++ struct netfront_info *np = netdev_priv(vnic->net_dev); ++ + /* Cripes, that was quick, better pass it up */ + netfront_accel_disable_net_interrupts(vnic); + vnic->irq_enabled = 0; + NETFRONT_ACCEL_STATS_OP(vnic->stats.poll_schedule_count++); +- netif_rx_schedule(vnic->net_dev); ++ netif_rx_schedule(vnic->net_dev, &np->napi); + } else { + /* + * Nothing yet, make sure we get interrupts through +@@ -72,6 +74,7 @@ static void vnic_stop_interrupts(netfron + static void vnic_start_fastpath(netfront_accel_vnic *vnic) + { + struct net_device *net_dev = vnic->net_dev; ++ struct netfront_info *np = netdev_priv(net_dev); + unsigned long flags; + + DPRINTK("%s\n", __FUNCTION__); +@@ -80,9 +83,9 @@ static void vnic_start_fastpath(netfront + vnic->tx_enabled = 1; + spin_unlock_irqrestore(&vnic->tx_lock, flags); + +- netif_poll_disable(net_dev); ++ napi_disable(&np->napi); + vnic->poll_enabled = 1; +- netif_poll_enable(net_dev); ++ napi_enable(&np->napi); + + vnic_start_interrupts(vnic); + } +@@ -114,11 +117,11 @@ void vnic_stop_fastpath(netfront_accel_v + spin_unlock_irqrestore(&vnic->tx_lock, flags1); + + /* Must prevent polls and hold lock to modify poll_enabled */ +- netif_poll_disable(net_dev); ++ napi_disable(&np->napi); + spin_lock_irqsave(&vnic->irq_enabled_lock, flags1); + vnic->poll_enabled = 0; + spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags1); +- netif_poll_enable(net_dev); ++ napi_enable(&np->napi); + } + + +@@ -326,8 +329,10 @@ static int vnic_process_localmac_msg(net + cuckoo_hash_mac_key key; + + if (msg->u.localmac.flags & NET_ACCEL_MSG_ADD) { +- DPRINTK("MAC has moved, could be local: " MAC_FMT "\n", +- MAC_ARG(msg->u.localmac.mac)); ++ DECLARE_MAC_BUF(buf); ++ ++ DPRINTK("MAC has moved, could be local: %s\n", ++ print_mac(buf, msg->u.localmac.mac)); + key = cuckoo_mac_to_key(msg->u.localmac.mac); + spin_lock_irqsave(&vnic->table_lock, flags); + /* Try to remove it, not a big deal if not there */ +@@ -515,6 +520,8 @@ irqreturn_t netfront_accel_net_channel_i + + spin_lock_irqsave(&vnic->irq_enabled_lock, flags); + if (vnic->irq_enabled) { ++ struct netfront_info *np = netdev_priv(net_dev); ++ + netfront_accel_disable_net_interrupts(vnic); + vnic->irq_enabled = 0; + spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags); +@@ -527,7 +534,7 @@ irqreturn_t netfront_accel_net_channel_i + vnic->stats.event_count_since_irq; + vnic->stats.event_count_since_irq = 0; + #endif +- netif_rx_schedule(net_dev); ++ netif_rx_schedule(net_dev, &np->napi); + } + else { + spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags); +--- sle11-2009-06-29.orig/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:36:26.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/sfc_netfront/accel_vi.c 2009-03-30 16:39:38.000000000 +0200 +@@ -641,8 +641,10 @@ netfront_accel_vi_tx_post(netfront_accel + (cuckoo_hash_key *)(&key), &value); + + if (!try_fastpath) { +- VPRINTK("try fast path false for mac: " MAC_FMT "\n", +- MAC_ARG(skb->data)); ++ DECLARE_MAC_BUF(buf); ++ ++ VPRINTK("try fast path false for mac: %s\n", ++ print_mac(buf, skb->data)); + + return NETFRONT_ACCEL_STATUS_CANT; + } +@@ -768,9 +770,10 @@ static void netfront_accel_vi_rx_comple + if (compare_ether_addr(skb->data, vnic->mac)) { + struct iphdr *ip = (struct iphdr *)(skb->data + ETH_HLEN); + u16 port; ++ DECLARE_MAC_BUF(buf); + +- DPRINTK("%s: saw wrong MAC address " MAC_FMT "\n", +- __FUNCTION__, MAC_ARG(skb->data)); ++ DPRINTK("%s: saw wrong MAC address %s\n", ++ __FUNCTION__, print_mac(buf, skb->data)); + + if (ip->protocol == IPPROTO_TCP) { + struct tcphdr *tcp = (struct tcphdr *) +--- sle11-2009-06-29.orig/drivers/xen/sfc_netutil/accel_util.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/drivers/xen/sfc_netutil/accel_util.h 2009-02-16 16:18:36.000000000 +0100 +@@ -63,9 +63,6 @@ + DPRINTK("%s at %s:%d\n", #exp, __FILE__, __LINE__); \ + } while(0) + +-#define MAC_FMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" +-#define MAC_ARG(_mac) (_mac)[0], (_mac)[1], (_mac)[2], (_mac)[3], (_mac)[4], (_mac)[5] +- + #include + + /*! Map a set of pages from another domain +--- sle11-2009-06-29.orig/drivers/xen/xenbus/xenbus_probe.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/xenbus/xenbus_probe.c 2009-02-16 16:18:36.000000000 +0100 +@@ -174,11 +174,9 @@ static int read_backend_details(struct x + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) && (defined(CONFIG_XEN) || defined(MODULE)) +-static int xenbus_uevent_frontend(struct device *dev, char **envp, +- int num_envp, char *buffer, int buffer_size) ++static int xenbus_uevent_frontend(struct device *dev, struct kobj_uevent_env *env) + { + struct xenbus_device *xdev; +- int length = 0, i = 0; + + if (dev == NULL) + return -ENODEV; +@@ -187,12 +185,9 @@ static int xenbus_uevent_frontend(struct + return -ENODEV; + + /* stuff we want to pass to /sbin/hotplug */ +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "XENBUS_TYPE=%s", xdev->devicetype); +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "XENBUS_PATH=%s", xdev->nodename); +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "MODALIAS=xen:%s", xdev->devicetype); ++ add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype); ++ add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename); ++ add_uevent_var(env, "MODALIAS=xen:%s", xdev->devicetype); + + return 0; + } +--- sle11-2009-06-29.orig/drivers/xen/xenbus/xenbus_probe_backend.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/xenbus/xenbus_probe_backend.c 2009-02-16 16:18:36.000000000 +0100 +@@ -60,8 +60,7 @@ + #include + #endif + +-static int xenbus_uevent_backend(struct device *dev, char **envp, +- int num_envp, char *buffer, int buffer_size); ++static int xenbus_uevent_backend(struct device *dev, struct kobj_uevent_env *env); + static int xenbus_probe_backend(const char *type, const char *domid); + + extern int read_otherend_details(struct xenbus_device *xendev, +@@ -128,13 +127,10 @@ static struct xen_bus_type xenbus_backen + }, + }; + +-static int xenbus_uevent_backend(struct device *dev, char **envp, +- int num_envp, char *buffer, int buffer_size) ++static int xenbus_uevent_backend(struct device *dev, struct kobj_uevent_env *env) + { + struct xenbus_device *xdev; + struct xenbus_driver *drv; +- int i = 0; +- int length = 0; + + DPRINTK(""); + +@@ -146,27 +142,16 @@ static int xenbus_uevent_backend(struct + return -ENODEV; + + /* stuff we want to pass to /sbin/hotplug */ +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "XENBUS_TYPE=%s", xdev->devicetype); ++ add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype); + +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "XENBUS_PATH=%s", xdev->nodename); ++ add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename); + +- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, +- "XENBUS_BASE_PATH=%s", xenbus_backend.root); +- +- /* terminate, set to next free slot, shrink available space */ +- envp[i] = NULL; +- envp = &envp[i]; +- num_envp -= i; +- buffer = &buffer[length]; +- buffer_size -= length; ++ add_uevent_var(env, "XENBUS_BASE_PATH=%s", xenbus_backend.root); + + if (dev->driver) { + drv = to_xenbus_driver(dev->driver); + if (drv && drv->uevent) +- return drv->uevent(xdev, envp, num_envp, buffer, +- buffer_size); ++ return drv->uevent(xdev, env); + } + + return 0; +--- sle11-2009-06-29.orig/drivers/xen/xenoprof/xenoprofile.c 2009-03-04 11:25:55.000000000 +0100 ++++ sle11-2009-06-29/drivers/xen/xenoprof/xenoprofile.c 2009-03-11 15:39:38.000000000 +0100 +@@ -29,7 +29,6 @@ + #include + #include + #include +-#include "../../../drivers/oprofile/cpu_buffer.h" + #include "../../../drivers/oprofile/event_buffer.h" + + #define MAX_XENOPROF_SAMPLES 16 +@@ -142,8 +141,7 @@ static void xenoprof_add_pc(xenoprof_buf + if (xenoprof_is_escape(buf, tail) && + xenoprof_get_event(buf, tail) == XENOPROF_TRACE_BEGIN) { + tracing=1; +- oprofile_add_pc(ESCAPE_CODE, buf->event_log[tail].mode, +- CPU_TRACE_BEGIN); ++ oprofile_add_mode(buf->event_log[tail].mode); + if (!is_passive) + oprofile_samples++; + else +--- sle11-2009-06-29.orig/fs/xfs/linux-2.6/xfs_buf.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/fs/xfs/linux-2.6/xfs_buf.c 2009-02-16 16:18:36.000000000 +0100 +@@ -187,7 +187,7 @@ free_address( + { + a_list_t *aentry; + +-#ifdef CONFIG_XEN ++#if defined(CONFIG_XEN) || defined(CONFIG_PARAVIRT_XEN) + /* + * Xen needs to be able to make sure it can get an exclusive + * RO mapping of pages it wants to turn into a pagetable. If +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/agp.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/agp.h 2009-02-16 16:18:36.000000000 +0100 +@@ -1,20 +1,22 @@ +-#ifndef AGP_H +-#define AGP_H 1 ++#ifndef _ASM_X86_AGP_H ++#define _ASM_X86_AGP_H + + #include + #include + #include + +-/* +- * Functions to keep the agpgart mappings coherent with the MMU. +- * The GART gives the CPU a physical alias of pages in memory. The alias region is +- * mapped uncacheable. Make sure there are no conflicting mappings +- * with different cachability attributes for the same page. This avoids +- * data corruption on some CPUs. ++/* ++ * Functions to keep the agpgart mappings coherent with the MMU. The ++ * GART gives the CPU a physical alias of pages in memory. The alias ++ * region is mapped uncacheable. Make sure there are no conflicting ++ * mappings with different cachability attributes for the same ++ * page. This avoids data corruption on some CPUs. + */ + +-/* Caller's responsibility to call global_flush_tlb() for +- * performance reasons */ ++/* ++ * Caller's responsibility to call global_flush_tlb() for performance ++ * reasons ++ */ + #define map_page_into_agp(page) ( \ + xen_create_contiguous_region((unsigned long)page_address(page), 0, 32) \ + ?: change_page_attr(page, 1, PAGE_KERNEL_NOCACHE)) +@@ -24,9 +26,11 @@ + change_page_attr(page, 1, PAGE_KERNEL)) + #define flush_agp_mappings() global_flush_tlb() + +-/* Could use CLFLUSH here if the cpu supports it. But then it would +- need to be called for each cacheline of the whole page so it may not be +- worth it. Would need a page for it. */ ++/* ++ * Could use CLFLUSH here if the cpu supports it. But then it would ++ * need to be called for each cacheline of the whole page so it may ++ * not be worth it. Would need a page for it. ++ */ + #define flush_agp_cache() wbinvd() + + /* Convert a physical address to an address suitable for the GART. */ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/desc.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "desc_32.h" ++#else ++# include "desc_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/desc_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/desc_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -34,6 +34,18 @@ static inline void clear_LDT(void) + put_cpu(); + } + ++#ifndef CONFIG_X86_NO_TSS ++static inline unsigned long __store_tr(void) ++{ ++ unsigned long tr; ++ ++ asm volatile ("str %w0":"=r" (tr)); ++ return tr; ++} ++ ++#define store_tr(tr) (tr) = __store_tr() ++#endif ++ + /* + * This is the ldt that every process will get unless we need + * something other than this. +@@ -47,6 +59,18 @@ extern struct desc_ptr cpu_gdt_descr[]; + /* the cpu gdt accessor */ + #define cpu_gdt(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address) + ++#ifndef CONFIG_XEN ++static inline void load_gdt(const struct desc_ptr *ptr) ++{ ++ asm volatile("lgdt %w0"::"m" (*ptr)); ++} ++ ++static inline void store_gdt(struct desc_ptr *ptr) ++{ ++ asm("sgdt %w0":"=m" (*ptr)); ++} ++#endif ++ + static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist) + { + struct gate_struct s; +@@ -87,6 +111,16 @@ static inline void set_system_gate_ist(i + { + _set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, ist); + } ++ ++static inline void load_idt(const struct desc_ptr *ptr) ++{ ++ asm volatile("lidt %w0"::"m" (*ptr)); ++} ++ ++static inline void store_idt(struct desc_ptr *dtr) ++{ ++ asm("sidt %w0":"=m" (*dtr)); ++} + #endif + + static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned type, +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/dma-mapping.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "dma-mapping_32.h" ++#else ++# include "dma-mapping_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/dma-mapping_32.h 2008-12-15 11:26:44.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/dma-mapping_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -7,9 +7,9 @@ + */ + + #include ++#include + #include + #include +-#include + #include + + static inline int +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/dma-mapping_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -6,8 +6,7 @@ + * documentation. + */ + +- +-#include ++#include + #include + + struct dma_mapping_ops { +@@ -203,4 +202,4 @@ extern int panic_on_overflow; + + #endif /* _X8664_DMA_MAPPING_H */ + +-#include ++#include "dma-mapping_32.h" +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/fixmap.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "fixmap_32.h" ++#else ++# include "fixmap_64.h" ++#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/hypercall.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,404 @@ ++/****************************************************************************** ++ * hypercall.h ++ * ++ * Linux-specific hypervisor handling. ++ * ++ * Copyright (c) 2002-2004, K A Fraser ++ * ++ * 64-bit updates: ++ * Benjamin Liu ++ * Jun Nakajima ++ * ++ * 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; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef __HYPERCALL_H__ ++#define __HYPERCALL_H__ ++ ++#ifndef __HYPERVISOR_H__ ++# error "please don't include this file directly" ++#endif ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++# include /* memcpy() */ ++#endif ++ ++#ifdef CONFIG_XEN ++#define HYPERCALL_ASM_OPERAND "%c" ++#define HYPERCALL_LOCATION(op) (hypercall_page + (op) * 32) ++#define HYPERCALL_C_OPERAND(name) "i" (HYPERCALL_LOCATION(__HYPERVISOR_##name)) ++#else ++#define HYPERCALL_ASM_OPERAND "*%" ++#define HYPERCALL_LOCATION(op) (hypercall_stubs + (op) * 32) ++#define HYPERCALL_C_OPERAND(name) "g" (HYPERCALL_LOCATION(__HYPERVISOR_##name)) ++#endif ++ ++#define HYPERCALL_ARG(arg, n) \ ++ register typeof((arg)+0) __arg##n asm(HYPERCALL_arg##n) = (arg) ++ ++#define _hypercall0(type, name) \ ++({ \ ++ type __res; \ ++ asm volatile ( \ ++ "call " HYPERCALL_ASM_OPERAND "1" \ ++ : "=a" (__res) \ ++ : HYPERCALL_C_OPERAND(name) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#define _hypercall1(type, name, arg) \ ++({ \ ++ type __res; \ ++ HYPERCALL_ARG(arg, 1); \ ++ asm volatile ( \ ++ "call " HYPERCALL_ASM_OPERAND "2" \ ++ : "=a" (__res), "+r" (__arg1) \ ++ : HYPERCALL_C_OPERAND(name) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#define _hypercall2(type, name, a1, a2) \ ++({ \ ++ type __res; \ ++ HYPERCALL_ARG(a1, 1); \ ++ HYPERCALL_ARG(a2, 2); \ ++ asm volatile ( \ ++ "call " HYPERCALL_ASM_OPERAND "3" \ ++ : "=a" (__res), "+r" (__arg1), "+r" (__arg2) \ ++ : HYPERCALL_C_OPERAND(name) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#define _hypercall3(type, name, a1, a2, a3) \ ++({ \ ++ type __res; \ ++ HYPERCALL_ARG(a1, 1); \ ++ HYPERCALL_ARG(a2, 2); \ ++ HYPERCALL_ARG(a3, 3); \ ++ asm volatile ( \ ++ "call " HYPERCALL_ASM_OPERAND "4" \ ++ : "=a" (__res), "+r" (__arg1), \ ++ "+r" (__arg2), "+r" (__arg3) \ ++ : HYPERCALL_C_OPERAND(name) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#define _hypercall4(type, name, a1, a2, a3, a4) \ ++({ \ ++ type __res; \ ++ HYPERCALL_ARG(a1, 1); \ ++ HYPERCALL_ARG(a2, 2); \ ++ HYPERCALL_ARG(a3, 3); \ ++ HYPERCALL_ARG(a4, 4); \ ++ asm volatile ( \ ++ "call " HYPERCALL_ASM_OPERAND "5" \ ++ : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ ++ "+r" (__arg3), "+r" (__arg4) \ ++ : HYPERCALL_C_OPERAND(name) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ ++({ \ ++ type __res; \ ++ HYPERCALL_ARG(a1, 1); \ ++ HYPERCALL_ARG(a2, 2); \ ++ HYPERCALL_ARG(a3, 3); \ ++ HYPERCALL_ARG(a4, 4); \ ++ HYPERCALL_ARG(a5, 5); \ ++ asm volatile ( \ ++ "call " HYPERCALL_ASM_OPERAND "6" \ ++ : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ ++ "+r" (__arg3), "+r" (__arg4), "+r" (__arg5) \ ++ : HYPERCALL_C_OPERAND(name) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#define _hypercall(type, op, a1, a2, a3, a4, a5) \ ++({ \ ++ type __res; \ ++ HYPERCALL_ARG(a1, 1); \ ++ HYPERCALL_ARG(a2, 2); \ ++ HYPERCALL_ARG(a3, 3); \ ++ HYPERCALL_ARG(a4, 4); \ ++ HYPERCALL_ARG(a5, 5); \ ++ asm volatile ( \ ++ "call *%6" \ ++ : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ ++ "+r" (__arg3), "+r" (__arg4), "+r" (__arg5) \ ++ : "g" (HYPERCALL_LOCATION(op)) \ ++ : "memory" ); \ ++ __res; \ ++}) ++ ++#ifdef CONFIG_X86_32 ++# include "hypercall_32.h" ++#else ++# include "hypercall_64.h" ++#endif ++ ++static inline int __must_check ++HYPERVISOR_set_trap_table( ++ const trap_info_t *table) ++{ ++ return _hypercall1(int, set_trap_table, table); ++} ++ ++static inline int __must_check ++HYPERVISOR_mmu_update( ++ mmu_update_t *req, unsigned int count, unsigned int *success_count, ++ domid_t domid) ++{ ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_mmu_update(req, count, success_count, domid); ++ return _hypercall4(int, mmu_update, req, count, success_count, domid); ++} ++ ++static inline int __must_check ++HYPERVISOR_mmuext_op( ++ struct mmuext_op *op, unsigned int count, unsigned int *success_count, ++ domid_t domid) ++{ ++ if (arch_use_lazy_mmu_mode()) ++ return xen_multi_mmuext_op(op, count, success_count, domid); ++ return _hypercall4(int, mmuext_op, op, count, success_count, domid); ++} ++ ++static inline int __must_check ++HYPERVISOR_set_gdt( ++ unsigned long *frame_list, unsigned int entries) ++{ ++ return _hypercall2(int, set_gdt, frame_list, entries); ++} ++ ++static inline int __must_check ++HYPERVISOR_stack_switch( ++ unsigned long ss, unsigned long esp) ++{ ++ return _hypercall2(int, stack_switch, ss, esp); ++} ++ ++static inline int ++HYPERVISOR_fpu_taskswitch( ++ int set) ++{ ++ return _hypercall1(int, fpu_taskswitch, set); ++} ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++static inline int __must_check ++HYPERVISOR_sched_op_compat( ++ int cmd, unsigned long arg) ++{ ++ return _hypercall2(int, sched_op_compat, cmd, arg); ++} ++#endif ++ ++static inline int __must_check ++HYPERVISOR_sched_op( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, sched_op, cmd, arg); ++} ++ ++static inline int __must_check ++HYPERVISOR_platform_op( ++ struct xen_platform_op *platform_op) ++{ ++ platform_op->interface_version = XENPF_INTERFACE_VERSION; ++ return _hypercall1(int, platform_op, platform_op); ++} ++ ++static inline int __must_check ++HYPERVISOR_set_debugreg( ++ unsigned int reg, unsigned long value) ++{ ++ return _hypercall2(int, set_debugreg, reg, value); ++} ++ ++static inline unsigned long __must_check ++HYPERVISOR_get_debugreg( ++ unsigned int reg) ++{ ++ return _hypercall1(unsigned long, get_debugreg, reg); ++} ++ ++static inline int __must_check ++HYPERVISOR_memory_op( ++ unsigned int cmd, void *arg) ++{ ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); ++ return _hypercall2(int, memory_op, cmd, arg); ++} ++ ++static inline int __must_check ++HYPERVISOR_multicall( ++ multicall_entry_t *call_list, unsigned int nr_calls) ++{ ++ return _hypercall2(int, multicall, call_list, nr_calls); ++} ++ ++static inline int __must_check ++HYPERVISOR_event_channel_op( ++ int cmd, void *arg) ++{ ++ int rc = _hypercall2(int, event_channel_op, cmd, arg); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ struct evtchn_op op; ++ op.cmd = cmd; ++ memcpy(&op.u, arg, sizeof(op.u)); ++ rc = _hypercall1(int, event_channel_op_compat, &op); ++ memcpy(arg, &op.u, sizeof(op.u)); ++ } ++#endif ++ ++ return rc; ++} ++ ++static inline int __must_check ++HYPERVISOR_xen_version( ++ int cmd, void *arg) ++{ ++ return _hypercall2(int, xen_version, cmd, arg); ++} ++ ++static inline int __must_check ++HYPERVISOR_console_io( ++ int cmd, unsigned int count, char *str) ++{ ++ return _hypercall3(int, console_io, cmd, count, str); ++} ++ ++static inline int __must_check ++HYPERVISOR_physdev_op( ++ int cmd, void *arg) ++{ ++ int rc = _hypercall2(int, physdev_op, cmd, arg); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (unlikely(rc == -ENOSYS)) { ++ struct physdev_op op; ++ op.cmd = cmd; ++ memcpy(&op.u, arg, sizeof(op.u)); ++ rc = _hypercall1(int, physdev_op_compat, &op); ++ memcpy(arg, &op.u, sizeof(op.u)); ++ } ++#endif ++ ++ return rc; ++} ++ ++static inline int __must_check ++HYPERVISOR_grant_table_op( ++ unsigned int cmd, void *uop, unsigned int count) ++{ ++ if (arch_use_lazy_mmu_mode()) ++ xen_multicall_flush(false); ++ return _hypercall3(int, grant_table_op, cmd, uop, count); ++} ++ ++static inline int __must_check ++HYPERVISOR_vm_assist( ++ unsigned int cmd, unsigned int type) ++{ ++ return _hypercall2(int, vm_assist, cmd, type); ++} ++ ++static inline int __must_check ++HYPERVISOR_vcpu_op( ++ int cmd, unsigned int vcpuid, void *extra_args) ++{ ++ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); ++} ++ ++static inline int __must_check ++HYPERVISOR_suspend( ++ unsigned long srec) ++{ ++ struct sched_shutdown sched_shutdown = { ++ .reason = SHUTDOWN_suspend ++ }; ++ ++ int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown, ++ &sched_shutdown, srec); ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++ if (rc == -ENOSYS) ++ rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown, ++ SHUTDOWN_suspend, srec); ++#endif ++ ++ return rc; ++} ++ ++#if CONFIG_XEN_COMPAT <= 0x030002 ++static inline int ++HYPERVISOR_nmi_op( ++ unsigned long op, void *arg) ++{ ++ return _hypercall2(int, nmi_op, op, arg); ++} ++#endif ++ ++#ifndef CONFIG_XEN ++static inline unsigned long __must_check ++HYPERVISOR_hvm_op( ++ int op, void *arg) ++{ ++ return _hypercall2(unsigned long, hvm_op, op, arg); ++} ++#endif ++ ++static inline int __must_check ++HYPERVISOR_callback_op( ++ int cmd, const void *arg) ++{ ++ return _hypercall2(int, callback_op, cmd, arg); ++} ++ ++static inline int __must_check ++HYPERVISOR_xenoprof_op( ++ int op, void *arg) ++{ ++ return _hypercall2(int, xenoprof_op, op, arg); ++} ++ ++static inline int __must_check ++HYPERVISOR_kexec_op( ++ unsigned long op, void *args) ++{ ++ return _hypercall2(int, kexec_op, op, args); ++} ++ ++#endif /* __HYPERCALL_H__ */ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/hypercall_32.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/hypercall_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -1,191 +1,10 @@ +-/****************************************************************************** +- * hypercall.h +- * +- * Linux-specific hypervisor handling. +- * +- * Copyright (c) 2002-2004, K A Fraser +- * +- * 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; or, when distributed +- * separately from the Linux kernel or incorporated into other +- * software packages, subject to the following license: +- * +- * Permission is hereby granted, free of charge, to any person obtaining a copy +- * of this source file (the "Software"), to deal in the Software without +- * restriction, including without limitation the rights to use, copy, modify, +- * merge, publish, distribute, sublicense, and/or sell copies of the Software, +- * and to permit persons to whom the Software is furnished to do so, subject to +- * the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +- * IN THE SOFTWARE. +- */ +- +-#ifndef __HYPERCALL_H__ +-#define __HYPERCALL_H__ +- +-#include /* memcpy() */ +-#include +- +-#ifndef __HYPERVISOR_H__ +-# error "please don't include this file directly" +-#endif +- +-#ifdef CONFIG_XEN +-#define HYPERCALL_STR(name) \ +- "call hypercall_page + ("__stringify(__HYPERVISOR_##name)" * 32)" +-#else +-#define HYPERCALL_STR(name) \ +- "mov hypercall_stubs,%%eax; " \ +- "add $("__stringify(__HYPERVISOR_##name)" * 32),%%eax; "\ +- "call *%%eax" +-#endif +- +-#define _hypercall0(type, name) \ +-({ \ +- type __res; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res) \ +- : \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall1(type, name, a1) \ +-({ \ +- type __res; \ +- long __ign1; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=b" (__ign1) \ +- : "1" ((long)(a1)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall2(type, name, a1, a2) \ +-({ \ +- type __res; \ +- long __ign1, __ign2; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ +- : "1" ((long)(a1)), "2" ((long)(a2)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall3(type, name, a1, a2, a3) \ +-({ \ +- type __res; \ +- long __ign1, __ign2, __ign3; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ +- "=d" (__ign3) \ +- : "1" ((long)(a1)), "2" ((long)(a2)), \ +- "3" ((long)(a3)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall4(type, name, a1, a2, a3, a4) \ +-({ \ +- type __res; \ +- long __ign1, __ign2, __ign3, __ign4; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ +- "=d" (__ign3), "=S" (__ign4) \ +- : "1" ((long)(a1)), "2" ((long)(a2)), \ +- "3" ((long)(a3)), "4" ((long)(a4)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +-({ \ +- type __res; \ +- long __ign1, __ign2, __ign3, __ign4, __ign5; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ +- "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ +- : "1" ((long)(a1)), "2" ((long)(a2)), \ +- "3" ((long)(a3)), "4" ((long)(a4)), \ +- "5" ((long)(a5)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall(type, op, a1, a2, a3, a4, a5) \ +-({ \ +- type __res; \ +- register typeof((a1)+0) __arg1 asm("ebx") = (a1); \ +- register typeof((a2)+0) __arg2 asm("ecx") = (a2); \ +- register typeof((a3)+0) __arg3 asm("edx") = (a3); \ +- register typeof((a4)+0) __arg4 asm("esi") = (a4); \ +- register typeof((a5)+0) __arg5 asm("edi") = (a5); \ +- asm volatile ( \ +- "call *%6" \ +- : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ +- "+r" (__arg3), "+r" (__arg4), "+r" (__arg5) \ +- : "0" (hypercall_page + (op) * 32) \ +- : "memory" ); \ +- __res; \ +-}) +- +-static inline int __must_check +-HYPERVISOR_set_trap_table( +- const trap_info_t *table) +-{ +- return _hypercall1(int, set_trap_table, table); +-} +- +-static inline int __must_check +-HYPERVISOR_mmu_update( +- mmu_update_t *req, unsigned int count, unsigned int *success_count, +- domid_t domid) +-{ +- if (arch_use_lazy_mmu_mode()) +- return xen_multi_mmu_update(req, count, success_count, domid); +- return _hypercall4(int, mmu_update, req, count, success_count, domid); +-} +- +-static inline int __must_check +-HYPERVISOR_mmuext_op( +- struct mmuext_op *op, unsigned int count, unsigned int *success_count, +- domid_t domid) +-{ +- if (arch_use_lazy_mmu_mode()) +- return xen_multi_mmuext_op(op, count, success_count, domid); +- return _hypercall4(int, mmuext_op, op, count, success_count, domid); +-} +- +-static inline int __must_check +-HYPERVISOR_set_gdt( +- unsigned long *frame_list, unsigned int entries) +-{ +- return _hypercall2(int, set_gdt, frame_list, entries); +-} +- +-static inline int __must_check +-HYPERVISOR_stack_switch( +- unsigned long ss, unsigned long esp) +-{ +- return _hypercall2(int, stack_switch, ss, esp); +-} ++#define HYPERCALL_arg1 "ebx" ++#define HYPERCALL_arg2 "ecx" ++#define HYPERCALL_arg3 "edx" ++#define HYPERCALL_arg4 "esi" ++#define HYPERCALL_arg5 "edi" + ++#if CONFIG_XEN_COMPAT <= 0x030002 + static inline int __must_check + HYPERVISOR_set_callbacks( + unsigned long event_selector, unsigned long event_address, +@@ -195,80 +14,24 @@ HYPERVISOR_set_callbacks( + event_selector, event_address, + failsafe_selector, failsafe_address); + } +- +-static inline int +-HYPERVISOR_fpu_taskswitch( +- int set) +-{ +- return _hypercall1(int, fpu_taskswitch, set); +-} +- +-static inline int __must_check +-HYPERVISOR_sched_op_compat( +- int cmd, unsigned long arg) +-{ +- return _hypercall2(int, sched_op_compat, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_sched_op( +- int cmd, void *arg) +-{ +- return _hypercall2(int, sched_op, cmd, arg); +-} ++#endif + + static inline long __must_check + HYPERVISOR_set_timer_op( + u64 timeout) + { +- unsigned long timeout_hi = (unsigned long)(timeout>>32); +- unsigned long timeout_lo = (unsigned long)timeout; +- return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); +-} +- +-static inline int __must_check +-HYPERVISOR_platform_op( +- struct xen_platform_op *platform_op) +-{ +- platform_op->interface_version = XENPF_INTERFACE_VERSION; +- return _hypercall1(int, platform_op, platform_op); +-} +- +-static inline int __must_check +-HYPERVISOR_set_debugreg( +- unsigned int reg, unsigned long value) +-{ +- return _hypercall2(int, set_debugreg, reg, value); +-} +- +-static inline unsigned long __must_check +-HYPERVISOR_get_debugreg( +- unsigned int reg) +-{ +- return _hypercall1(unsigned long, get_debugreg, reg); ++ return _hypercall2(long, set_timer_op, ++ (unsigned long)timeout, ++ (unsigned long)(timeout>>32)); + } + + static inline int __must_check + HYPERVISOR_update_descriptor( + u64 ma, u64 desc) + { +- return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32); +-} +- +-static inline int __must_check +-HYPERVISOR_memory_op( +- unsigned int cmd, void *arg) +-{ +- if (arch_use_lazy_mmu_mode()) +- xen_multicall_flush(false); +- return _hypercall2(int, memory_op, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_multicall( +- multicall_entry_t *call_list, unsigned int nr_calls) +-{ +- return _hypercall2(int, multicall, call_list, nr_calls); ++ return _hypercall4(int, update_descriptor, ++ (unsigned long)ma, (unsigned long)(ma>>32), ++ (unsigned long)desc, (unsigned long)(desc>>32)); + } + + static inline int __must_check +@@ -287,67 +50,6 @@ HYPERVISOR_update_va_mapping( + } + + static inline int __must_check +-HYPERVISOR_event_channel_op( +- int cmd, void *arg) +-{ +- int rc = _hypercall2(int, event_channel_op, cmd, arg); +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +- if (unlikely(rc == -ENOSYS)) { +- struct evtchn_op op; +- op.cmd = cmd; +- memcpy(&op.u, arg, sizeof(op.u)); +- rc = _hypercall1(int, event_channel_op_compat, &op); +- memcpy(arg, &op.u, sizeof(op.u)); +- } +-#endif +- +- return rc; +-} +- +-static inline int __must_check +-HYPERVISOR_xen_version( +- int cmd, void *arg) +-{ +- return _hypercall2(int, xen_version, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_console_io( +- int cmd, unsigned int count, char *str) +-{ +- return _hypercall3(int, console_io, cmd, count, str); +-} +- +-static inline int __must_check +-HYPERVISOR_physdev_op( +- int cmd, void *arg) +-{ +- int rc = _hypercall2(int, physdev_op, cmd, arg); +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +- if (unlikely(rc == -ENOSYS)) { +- struct physdev_op op; +- op.cmd = cmd; +- memcpy(&op.u, arg, sizeof(op.u)); +- rc = _hypercall1(int, physdev_op_compat, &op); +- memcpy(arg, &op.u, sizeof(op.u)); +- } +-#endif +- +- return rc; +-} +- +-static inline int __must_check +-HYPERVISOR_grant_table_op( +- unsigned int cmd, void *uop, unsigned int count) +-{ +- if (arch_use_lazy_mmu_mode()) +- xen_multicall_flush(false); +- return _hypercall3(int, grant_table_op, cmd, uop, count); +-} +- +-static inline int __must_check + HYPERVISOR_update_va_mapping_otherdomain( + unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) + { +@@ -358,80 +60,3 @@ HYPERVISOR_update_va_mapping_otherdomain + return _hypercall5(int, update_va_mapping_otherdomain, va, + new_val.pte_low, pte_hi, flags, domid); + } +- +-static inline int __must_check +-HYPERVISOR_vm_assist( +- unsigned int cmd, unsigned int type) +-{ +- return _hypercall2(int, vm_assist, cmd, type); +-} +- +-static inline int __must_check +-HYPERVISOR_vcpu_op( +- int cmd, unsigned int vcpuid, void *extra_args) +-{ +- return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); +-} +- +-static inline int __must_check +-HYPERVISOR_suspend( +- unsigned long srec) +-{ +- struct sched_shutdown sched_shutdown = { +- .reason = SHUTDOWN_suspend +- }; +- +- int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown, +- &sched_shutdown, srec); +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +- if (rc == -ENOSYS) +- rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown, +- SHUTDOWN_suspend, srec); +-#endif +- +- return rc; +-} +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +-static inline int +-HYPERVISOR_nmi_op( +- unsigned long op, void *arg) +-{ +- return _hypercall2(int, nmi_op, op, arg); +-} +-#endif +- +-#ifndef CONFIG_XEN +-static inline unsigned long __must_check +-HYPERVISOR_hvm_op( +- int op, void *arg) +-{ +- return _hypercall2(unsigned long, hvm_op, op, arg); +-} +-#endif +- +-static inline int __must_check +-HYPERVISOR_callback_op( +- int cmd, const void *arg) +-{ +- return _hypercall2(int, callback_op, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_xenoprof_op( +- int op, void *arg) +-{ +- return _hypercall2(int, xenoprof_op, op, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_kexec_op( +- unsigned long op, void *args) +-{ +- return _hypercall2(int, kexec_op, op, args); +-} +- +- +- +-#endif /* __HYPERCALL_H__ */ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/hypercall_64.h 2009-03-04 11:28:34.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/hypercall_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -1,197 +1,10 @@ +-/****************************************************************************** +- * hypercall.h +- * +- * Linux-specific hypervisor handling. +- * +- * Copyright (c) 2002-2004, K A Fraser +- * +- * 64-bit updates: +- * Benjamin Liu +- * Jun Nakajima +- * +- * 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; or, when distributed +- * separately from the Linux kernel or incorporated into other +- * software packages, subject to the following license: +- * +- * Permission is hereby granted, free of charge, to any person obtaining a copy +- * of this source file (the "Software"), to deal in the Software without +- * restriction, including without limitation the rights to use, copy, modify, +- * merge, publish, distribute, sublicense, and/or sell copies of the Software, +- * and to permit persons to whom the Software is furnished to do so, subject to +- * the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +- * IN THE SOFTWARE. +- */ +- +-#ifndef __HYPERCALL_H__ +-#define __HYPERCALL_H__ +- +-#include /* memcpy() */ +-#include +- +-#ifndef __HYPERVISOR_H__ +-# error "please don't include this file directly" +-#endif +- +-#ifdef CONFIG_XEN +-#define HYPERCALL_STR(name) \ +- "call hypercall_page + ("__stringify(__HYPERVISOR_##name)" * 32)" +-#else +-#define HYPERCALL_STR(name) \ +- "mov $("__stringify(__HYPERVISOR_##name)" * 32),%%eax; "\ +- "add hypercall_stubs(%%rip),%%rax; " \ +- "call *%%rax" +-#endif +- +-#define _hypercall0(type, name) \ +-({ \ +- type __res; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res) \ +- : \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall1(type, name, a1) \ +-({ \ +- type __res; \ +- long __ign1; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=D" (__ign1) \ +- : "1" ((long)(a1)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall2(type, name, a1, a2) \ +-({ \ +- type __res; \ +- long __ign1, __ign2; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=D" (__ign1), "=S" (__ign2) \ +- : "1" ((long)(a1)), "2" ((long)(a2)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall3(type, name, a1, a2, a3) \ +-({ \ +- type __res; \ +- long __ign1, __ign2, __ign3; \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ +- "=d" (__ign3) \ +- : "1" ((long)(a1)), "2" ((long)(a2)), \ +- "3" ((long)(a3)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall4(type, name, a1, a2, a3, a4) \ +-({ \ +- type __res; \ +- long __ign1, __ign2, __ign3; \ +- register long __arg4 asm("r10") = (long)(a4); \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ +- "=d" (__ign3), "+r" (__arg4) \ +- : "1" ((long)(a1)), "2" ((long)(a2)), \ +- "3" ((long)(a3)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +-({ \ +- type __res; \ +- long __ign1, __ign2, __ign3; \ +- register long __arg4 asm("r10") = (long)(a4); \ +- register long __arg5 asm("r8") = (long)(a5); \ +- asm volatile ( \ +- HYPERCALL_STR(name) \ +- : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ +- "=d" (__ign3), "+r" (__arg4), "+r" (__arg5) \ +- : "1" ((long)(a1)), "2" ((long)(a2)), \ +- "3" ((long)(a3)) \ +- : "memory" ); \ +- __res; \ +-}) +- +-#define _hypercall(type, op, a1, a2, a3, a4, a5) \ +-({ \ +- type __res; \ +- register typeof((a1)+0) __arg1 asm("rdi") = (a1); \ +- register typeof((a2)+0) __arg2 asm("rsi") = (a2); \ +- register typeof((a3)+0) __arg3 asm("rdx") = (a3); \ +- register typeof((a4)+0) __arg4 asm("r10") = (a4); \ +- register typeof((a5)+0) __arg5 asm("r8") = (a5); \ +- asm volatile ( \ +- "call *%6" \ +- : "=a" (__res), "+r" (__arg1), "+r" (__arg2), \ +- "+r" (__arg3), "+r" (__arg4), "+r" (__arg5) \ +- : "0" (hypercall_page + (op) * 32) \ +- : "memory" ); \ +- __res; \ +-}) +- +-static inline int __must_check +-HYPERVISOR_set_trap_table( +- const trap_info_t *table) +-{ +- return _hypercall1(int, set_trap_table, table); +-} +- +-static inline int __must_check +-HYPERVISOR_mmu_update( +- mmu_update_t *req, unsigned int count, unsigned int *success_count, +- domid_t domid) +-{ +- if (arch_use_lazy_mmu_mode()) +- return xen_multi_mmu_update(req, count, success_count, domid); +- return _hypercall4(int, mmu_update, req, count, success_count, domid); +-} +- +-static inline int __must_check +-HYPERVISOR_mmuext_op( +- struct mmuext_op *op, unsigned int count, unsigned int *success_count, +- domid_t domid) +-{ +- if (arch_use_lazy_mmu_mode()) +- return xen_multi_mmuext_op(op, count, success_count, domid); +- return _hypercall4(int, mmuext_op, op, count, success_count, domid); +-} +- +-static inline int __must_check +-HYPERVISOR_set_gdt( +- unsigned long *frame_list, unsigned int entries) +-{ +- return _hypercall2(int, set_gdt, frame_list, entries); +-} +- +-static inline int __must_check +-HYPERVISOR_stack_switch( +- unsigned long ss, unsigned long esp) +-{ +- return _hypercall2(int, stack_switch, ss, esp); +-} ++#define HYPERCALL_arg1 "rdi" ++#define HYPERCALL_arg2 "rsi" ++#define HYPERCALL_arg3 "rdx" ++#define HYPERCALL_arg4 "r10" ++#define HYPERCALL_arg5 "r8" + ++#if CONFIG_XEN_COMPAT <= 0x030002 + static inline int __must_check + HYPERVISOR_set_callbacks( + unsigned long event_address, unsigned long failsafe_address, +@@ -200,27 +13,7 @@ HYPERVISOR_set_callbacks( + return _hypercall3(int, set_callbacks, + event_address, failsafe_address, syscall_address); + } +- +-static inline int +-HYPERVISOR_fpu_taskswitch( +- int set) +-{ +- return _hypercall1(int, fpu_taskswitch, set); +-} +- +-static inline int __must_check +-HYPERVISOR_sched_op_compat( +- int cmd, unsigned long arg) +-{ +- return _hypercall2(int, sched_op_compat, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_sched_op( +- int cmd, void *arg) +-{ +- return _hypercall2(int, sched_op, cmd, arg); +-} ++#endif + + static inline long __must_check + HYPERVISOR_set_timer_op( +@@ -230,28 +23,6 @@ HYPERVISOR_set_timer_op( + } + + static inline int __must_check +-HYPERVISOR_platform_op( +- struct xen_platform_op *platform_op) +-{ +- platform_op->interface_version = XENPF_INTERFACE_VERSION; +- return _hypercall1(int, platform_op, platform_op); +-} +- +-static inline int __must_check +-HYPERVISOR_set_debugreg( +- unsigned int reg, unsigned long value) +-{ +- return _hypercall2(int, set_debugreg, reg, value); +-} +- +-static inline unsigned long __must_check +-HYPERVISOR_get_debugreg( +- unsigned int reg) +-{ +- return _hypercall1(unsigned long, get_debugreg, reg); +-} +- +-static inline int __must_check + HYPERVISOR_update_descriptor( + unsigned long ma, unsigned long word) + { +@@ -259,22 +30,6 @@ HYPERVISOR_update_descriptor( + } + + static inline int __must_check +-HYPERVISOR_memory_op( +- unsigned int cmd, void *arg) +-{ +- if (arch_use_lazy_mmu_mode()) +- xen_multicall_flush(false); +- return _hypercall2(int, memory_op, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_multicall( +- multicall_entry_t *call_list, unsigned int nr_calls) +-{ +- return _hypercall2(int, multicall, call_list, nr_calls); +-} +- +-static inline int __must_check + HYPERVISOR_update_va_mapping( + unsigned long va, pte_t new_val, unsigned long flags) + { +@@ -284,67 +39,6 @@ HYPERVISOR_update_va_mapping( + } + + static inline int __must_check +-HYPERVISOR_event_channel_op( +- int cmd, void *arg) +-{ +- int rc = _hypercall2(int, event_channel_op, cmd, arg); +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +- if (unlikely(rc == -ENOSYS)) { +- struct evtchn_op op; +- op.cmd = cmd; +- memcpy(&op.u, arg, sizeof(op.u)); +- rc = _hypercall1(int, event_channel_op_compat, &op); +- memcpy(arg, &op.u, sizeof(op.u)); +- } +-#endif +- +- return rc; +-} +- +-static inline int __must_check +-HYPERVISOR_xen_version( +- int cmd, void *arg) +-{ +- return _hypercall2(int, xen_version, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_console_io( +- int cmd, unsigned int count, char *str) +-{ +- return _hypercall3(int, console_io, cmd, count, str); +-} +- +-static inline int __must_check +-HYPERVISOR_physdev_op( +- int cmd, void *arg) +-{ +- int rc = _hypercall2(int, physdev_op, cmd, arg); +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +- if (unlikely(rc == -ENOSYS)) { +- struct physdev_op op; +- op.cmd = cmd; +- memcpy(&op.u, arg, sizeof(op.u)); +- rc = _hypercall1(int, physdev_op_compat, &op); +- memcpy(arg, &op.u, sizeof(op.u)); +- } +-#endif +- +- return rc; +-} +- +-static inline int __must_check +-HYPERVISOR_grant_table_op( +- unsigned int cmd, void *uop, unsigned int count) +-{ +- if (arch_use_lazy_mmu_mode()) +- xen_multicall_flush(false); +- return _hypercall3(int, grant_table_op, cmd, uop, count); +-} +- +-static inline int __must_check + HYPERVISOR_update_va_mapping_otherdomain( + unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) + { +@@ -353,83 +47,8 @@ HYPERVISOR_update_va_mapping_otherdomain + } + + static inline int __must_check +-HYPERVISOR_vm_assist( +- unsigned int cmd, unsigned int type) +-{ +- return _hypercall2(int, vm_assist, cmd, type); +-} +- +-static inline int __must_check +-HYPERVISOR_vcpu_op( +- int cmd, unsigned int vcpuid, void *extra_args) +-{ +- return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); +-} +- +-static inline int __must_check + HYPERVISOR_set_segment_base( + int reg, unsigned long value) + { + return _hypercall2(int, set_segment_base, reg, value); + } +- +-static inline int __must_check +-HYPERVISOR_suspend( +- unsigned long srec) +-{ +- struct sched_shutdown sched_shutdown = { +- .reason = SHUTDOWN_suspend +- }; +- +- int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown, +- &sched_shutdown, srec); +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +- if (rc == -ENOSYS) +- rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown, +- SHUTDOWN_suspend, srec); +-#endif +- +- return rc; +-} +- +-#if CONFIG_XEN_COMPAT <= 0x030002 +-static inline int +-HYPERVISOR_nmi_op( +- unsigned long op, void *arg) +-{ +- return _hypercall2(int, nmi_op, op, arg); +-} +-#endif +- +-#ifndef CONFIG_XEN +-static inline unsigned long __must_check +-HYPERVISOR_hvm_op( +- int op, void *arg) +-{ +- return _hypercall2(unsigned long, hvm_op, op, arg); +-} +-#endif +- +-static inline int __must_check +-HYPERVISOR_callback_op( +- int cmd, const void *arg) +-{ +- return _hypercall2(int, callback_op, cmd, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_xenoprof_op( +- int op, void *arg) +-{ +- return _hypercall2(int, xenoprof_op, op, arg); +-} +- +-static inline int __must_check +-HYPERVISOR_kexec_op( +- unsigned long op, void *args) +-{ +- return _hypercall2(int, kexec_op, op, args); +-} +- +-#endif /* __HYPERCALL_H__ */ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/hypervisor.h 2009-03-04 11:28:11.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/hypervisor.h 2009-02-16 16:18:36.000000000 +0100 +@@ -194,7 +194,6 @@ static inline void xen_multicall_flush(b + extern char hypercall_page[PAGE_SIZE]; + #else + extern char *hypercall_stubs; +-#define hypercall_page hypercall_stubs + #define is_running_on_xen() (!!hypercall_stubs) + #endif + +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/io.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "io_32.h" ++#else ++# include "io_64.h" ++#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/irqflags.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "irqflags_32.h" ++#else ++# include "irqflags_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/irqflags_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/irqflags_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -148,6 +148,23 @@ static inline int raw_irqs_disabled_flag + \ + raw_irqs_disabled_flags(flags); \ + }) ++ ++/* ++ * makes the traced hardirq state match with the machine state ++ * ++ * should be a rarely used function, only in places where its ++ * otherwise impossible to know the irq state, like in traps. ++ */ ++static inline void trace_hardirqs_fixup_flags(unsigned long flags) ++{ ++ if (raw_irqs_disabled_flags(flags)) ++ trace_hardirqs_off(); ++ else ++ trace_hardirqs_on(); ++} ++ ++#define trace_hardirqs_fixup() \ ++ trace_hardirqs_fixup_flags(__raw_local_save_flags()) + #endif /* __ASSEMBLY__ */ + + /* +@@ -179,4 +196,17 @@ static inline int raw_irqs_disabled_flag + # define TRACE_IRQS_OFF + #endif + ++#ifdef CONFIG_DEBUG_LOCK_ALLOC ++# define LOCKDEP_SYS_EXIT \ ++ pushl %eax; \ ++ pushl %ecx; \ ++ pushl %edx; \ ++ call lockdep_sys_exit; \ ++ popl %edx; \ ++ popl %ecx; \ ++ popl %eax; ++#else ++# define LOCKDEP_SYS_EXIT ++#endif ++ + #endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/irqflags_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/irqflags_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -116,6 +116,22 @@ static inline int raw_irqs_disabled_flag + }) + + /* ++ * makes the traced hardirq state match with the machine state ++ * ++ * should be a rarely used function, only in places where its ++ * otherwise impossible to know the irq state, like in traps. ++ */ ++static inline void trace_hardirqs_fixup_flags(unsigned long flags) ++{ ++ if (raw_irqs_disabled_flags(flags)) ++ trace_hardirqs_off(); ++ else ++ trace_hardirqs_on(); ++} ++ ++#define trace_hardirqs_fixup() \ ++ trace_hardirqs_fixup_flags(__raw_local_save_flags()) ++/* + * Used in the idle loop; sti takes one instruction cycle + * to complete: + */ +@@ -143,6 +159,20 @@ static inline void halt(void) + # define TRACE_IRQS_ON + # define TRACE_IRQS_OFF + # endif ++# ifdef CONFIG_DEBUG_LOCK_ALLOC ++# define LOCKDEP_SYS_EXIT call lockdep_sys_exit_thunk ++# define LOCKDEP_SYS_EXIT_IRQ \ ++ TRACE_IRQS_ON; \ ++ sti; \ ++ SAVE_REST; \ ++ LOCKDEP_SYS_EXIT; \ ++ RESTORE_REST; \ ++ cli; \ ++ TRACE_IRQS_OFF; ++# else ++# define LOCKDEP_SYS_EXIT ++# define LOCKDEP_SYS_EXIT_IRQ ++# endif + #endif + + #endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/maddr.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "maddr_32.h" ++#else ++# include "maddr_64.h" ++#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/mmu_context.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "mmu_context_32.h" ++#else ++# include "mmu_context_64.h" ++#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/page.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,13 @@ ++#ifdef __KERNEL__ ++# ifdef CONFIG_X86_32 ++# include "page_32.h" ++# else ++# include "page_64.h" ++# endif ++#else ++# ifdef __i386__ ++# include "page_32.h" ++# else ++# include "page_64.h" ++# endif ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/page_64.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/page_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -207,6 +207,7 @@ static inline unsigned long __phys_addr( + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + + #define __HAVE_ARCH_GATE_AREA 1 ++#define vmemmap ((struct page *)VMEMMAP_START) + + #include + #include +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pci.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,100 @@ ++#ifndef __x86_PCI_H ++#define __x86_PCI_H ++ ++#include /* for struct page */ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifdef __KERNEL__ ++ ++struct pci_sysdata { ++ int domain; /* PCI domain */ ++ int node; /* NUMA node */ ++#ifdef CONFIG_X86_64 ++ void* iommu; /* IOMMU private data */ ++#endif ++#ifdef CONFIG_XEN_PCIDEV_FRONTEND ++ struct pcifront_device *pdev; ++#endif ++}; ++ ++/* scan a bus after allocating a pci_sysdata for it */ ++extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); ++ ++static inline int pci_domain_nr(struct pci_bus *bus) ++{ ++ struct pci_sysdata *sd = bus->sysdata; ++ return sd->domain; ++} ++ ++static inline int pci_proc_domain(struct pci_bus *bus) ++{ ++ return pci_domain_nr(bus); ++} ++ ++ ++/* Can be used to override the logic in pci_scan_bus for skipping ++ already-configured bus numbers - to be used for buggy BIOSes ++ or architectures with incomplete PCI setup by the loader */ ++ ++#ifdef CONFIG_PCI ++extern unsigned int pcibios_assign_all_busses(void); ++#else ++#define pcibios_assign_all_busses() 0 ++#endif ++ ++#include ++#define pcibios_scan_all_fns(a, b) (!is_initial_xendomain()) ++ ++extern unsigned long pci_mem_start; ++#define PCIBIOS_MIN_IO 0x1000 ++#define PCIBIOS_MIN_MEM (pci_mem_start) ++ ++#define PCIBIOS_MIN_CARDBUS_IO 0x4000 ++ ++void pcibios_config_init(void); ++struct pci_bus * pcibios_scan_root(int bus); ++ ++void pcibios_set_master(struct pci_dev *dev); ++void pcibios_penalize_isa_irq(int irq, int active); ++struct irq_routing_table *pcibios_get_irq_routing_table(void); ++int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); ++ ++ ++#define HAVE_PCI_MMAP ++extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, ++ enum pci_mmap_state mmap_state, int write_combine); ++ ++ ++#ifdef CONFIG_PCI ++static inline void pci_dma_burst_advice(struct pci_dev *pdev, ++ enum pci_dma_burst_strategy *strat, ++ unsigned long *strategy_parameter) ++{ ++ *strat = PCI_DMA_BURST_INFINITY; ++ *strategy_parameter = ~0UL; ++} ++#endif ++ ++ ++#endif /* __KERNEL__ */ ++ ++#ifdef CONFIG_X86_32 ++# include "pci_32.h" ++#else ++# include "pci_64.h" ++#endif ++ ++/* implement the pci_ DMA API in terms of the generic device dma_ one */ ++#include ++ ++/* generic pci stuff */ ++#include ++ ++ ++ ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pci_32.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pci_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -4,52 +4,10 @@ + + #ifdef __KERNEL__ + +-struct pci_sysdata { +- int node; /* NUMA node */ +-}; +- +-/* scan a bus after allocating a pci_sysdata for it */ +-extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); +- +-#include /* for struct page */ +- +-/* Can be used to override the logic in pci_scan_bus for skipping +- already-configured bus numbers - to be used for buggy BIOSes +- or architectures with incomplete PCI setup by the loader */ +- +-#ifdef CONFIG_PCI +-extern unsigned int pcibios_assign_all_busses(void); +-#else +-#define pcibios_assign_all_busses() 0 +-#endif +- +-#include +-#define pcibios_scan_all_fns(a, b) (!is_initial_xendomain()) +- +-extern unsigned long pci_mem_start; +-#define PCIBIOS_MIN_IO 0x1000 +-#define PCIBIOS_MIN_MEM (pci_mem_start) +- +-#define PCIBIOS_MIN_CARDBUS_IO 0x4000 +- +-void pcibios_config_init(void); +-struct pci_bus * pcibios_scan_root(int bus); +- +-void pcibios_set_master(struct pci_dev *dev); +-void pcibios_penalize_isa_irq(int irq, int active); +-struct irq_routing_table *pcibios_get_irq_routing_table(void); +-int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); +- + /* Dynamic DMA mapping stuff. + * i386 has everything mapped statically. + */ + +-#include +-#include +-#include +-#include +-#include +- + struct pci_dev; + + #ifdef CONFIG_SWIOTLB +@@ -89,31 +47,8 @@ struct pci_dev; + + #endif + +-#define HAVE_PCI_MMAP +-extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, +- enum pci_mmap_state mmap_state, int write_combine); +- +- +-#ifdef CONFIG_PCI +-static inline void pci_dma_burst_advice(struct pci_dev *pdev, +- enum pci_dma_burst_strategy *strat, +- unsigned long *strategy_parameter) +-{ +- *strat = PCI_DMA_BURST_INFINITY; +- *strategy_parameter = ~0UL; +-} +-#endif + + #endif /* __KERNEL__ */ + +-#ifdef CONFIG_XEN_PCIDEV_FRONTEND +-#include +-#endif /* CONFIG_XEN_PCIDEV_FRONTEND */ +- +-/* implement the pci_ DMA API in terms of the generic device dma_ one */ +-#include +- +-/* generic pci stuff */ +-#include + + #endif /* __i386_PCI_H */ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgalloc.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "pgalloc_32.h" ++#else ++# include "pgalloc_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pgalloc_64.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgalloc_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -112,6 +112,8 @@ static inline void pgd_list_del(pgd_t *p + spin_unlock(&pgd_lock); + } + ++extern void pgd_test_and_unpin(pgd_t *); ++ + static inline pgd_t *pgd_alloc(struct mm_struct *mm) + { + /* +@@ -122,6 +124,7 @@ static inline pgd_t *pgd_alloc(struct mm + if (!pgd) + return NULL; + pgd_list_add(pgd); ++ pgd_test_and_unpin(pgd); + /* + * Copy kernel pointers in from init. + * Could keep a freelist or slab cache of those because the kernel +@@ -144,27 +147,7 @@ static inline pgd_t *pgd_alloc(struct mm + + static inline void pgd_free(pgd_t *pgd) + { +- pte_t *ptep = virt_to_ptep(pgd); +- +- if (!pte_write(*ptep)) { +- xen_pgd_unpin(__pa(pgd)); +- BUG_ON(HYPERVISOR_update_va_mapping( +- (unsigned long)pgd, +- pfn_pte(virt_to_phys(pgd)>>PAGE_SHIFT, PAGE_KERNEL), +- 0)); +- } +- +- ptep = virt_to_ptep(__user_pgd(pgd)); +- +- if (!pte_write(*ptep)) { +- xen_pgd_unpin(__pa(__user_pgd(pgd))); +- BUG_ON(HYPERVISOR_update_va_mapping( +- (unsigned long)__user_pgd(pgd), +- pfn_pte(virt_to_phys(__user_pgd(pgd))>>PAGE_SHIFT, +- PAGE_KERNEL), +- 0)); +- } +- ++ pgd_test_and_unpin(pgd); + pgd_list_del(pgd); + free_pages((unsigned long)pgd, 1); + } +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgtable.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "pgtable_32.h" ++#else ++# include "pgtable_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgtable_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -17,10 +17,7 @@ + #include + #include + +-#ifndef _I386_BITOPS_H +-#include +-#endif +- ++#include + #include + #include + #include +@@ -40,7 +37,7 @@ extern spinlock_t pgd_lock; + extern struct page *pgd_list; + void check_pgt_cache(void); + +-void pmd_ctor(void *, struct kmem_cache *, unsigned long); ++void pmd_ctor(struct kmem_cache *, void *); + void pgtable_cache_init(void); + void paging_init(void); + +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/pgtable_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -9,7 +9,7 @@ + * the x86-64 page table tree. + */ + #include +-#include ++#include + #include + #include + #include +@@ -139,6 +139,7 @@ static inline void pgd_clear (pgd_t * pg + #define MAXMEM _AC(0x3fffffffffff, UL) + #define VMALLOC_START _AC(0xffffc20000000000, UL) + #define VMALLOC_END _AC(0xffffe1ffffffffff, UL) ++#define VMEMMAP_START _AC(0xffffe20000000000, UL) + #define MODULES_VADDR _AC(0xffffffff88000000, UL) + #define MODULES_END _AC(0xfffffffffff00000, UL) + #define MODULES_LEN (MODULES_END - MODULES_VADDR) +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/processor.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "processor_32.h" ++#else ++# include "processor_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/processor_32.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/processor_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -80,6 +80,7 @@ struct cpuinfo_x86 { + unsigned char booted_cores; /* number of cores as seen by OS */ + __u8 phys_proc_id; /* Physical processor id. */ + __u8 cpu_core_id; /* Core id */ ++ __u8 cpu_index; /* index into per_cpu list */ + #endif + } __attribute__((__aligned__(SMP_CACHE_BYTES))); + +@@ -106,14 +107,19 @@ DECLARE_PER_CPU(struct tss_struct, init_ + #endif + + #ifdef CONFIG_SMP +-extern struct cpuinfo_x86 cpu_data[]; +-#define current_cpu_data cpu_data[smp_processor_id()] ++DECLARE_PER_CPU(struct cpuinfo_x86, cpu_info); ++#define cpu_data(cpu) per_cpu(cpu_info, cpu) ++#define current_cpu_data cpu_data(smp_processor_id()) + #else +-#define cpu_data (&boot_cpu_data) +-#define current_cpu_data boot_cpu_data ++#define cpu_data(cpu) boot_cpu_data ++#define current_cpu_data boot_cpu_data + #endif + +-extern int cpu_llc_id[NR_CPUS]; ++/* ++ * the following now lives in the per cpu area: ++ * extern int cpu_llc_id[NR_CPUS]; ++ */ ++DECLARE_PER_CPU(u8, cpu_llc_id); + extern char ignore_fpu_irq; + + void __init cpu_detect(struct cpuinfo_x86 *c); +@@ -560,7 +566,9 @@ static inline void xen_set_iopl_mask(uns + * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx + * resulting in stale register contents being returned. + */ +-static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) ++static inline void cpuid(unsigned int op, ++ unsigned int *eax, unsigned int *ebx, ++ unsigned int *ecx, unsigned int *edx) + { + *eax = op; + *ecx = 0; +@@ -568,8 +576,9 @@ static inline void cpuid(unsigned int op + } + + /* Some CPUID calls want 'count' to be placed in ecx */ +-static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, +- int *edx) ++static inline void cpuid_count(unsigned int op, int count, ++ unsigned int *eax, unsigned int *ebx, ++ unsigned int *ecx, unsigned int *edx) + { + *eax = op; + *ecx = count; +@@ -639,6 +648,17 @@ static inline unsigned int cpuid_edx(uns + #define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n" + #define K7_NOP8 K7_NOP7 ASM_NOP1 + ++/* P6 nops */ ++/* uses eax dependencies (Intel-recommended choice) */ ++#define P6_NOP1 GENERIC_NOP1 ++#define P6_NOP2 ".byte 0x66,0x90\n" ++#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" ++#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" ++#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" ++#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" ++#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" ++#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" ++ + #ifdef CONFIG_MK8 + #define ASM_NOP1 K8_NOP1 + #define ASM_NOP2 K8_NOP2 +@@ -657,6 +677,17 @@ static inline unsigned int cpuid_edx(uns + #define ASM_NOP6 K7_NOP6 + #define ASM_NOP7 K7_NOP7 + #define ASM_NOP8 K7_NOP8 ++#elif defined(CONFIG_M686) || defined(CONFIG_MPENTIUMII) || \ ++ defined(CONFIG_MPENTIUMIII) || defined(CONFIG_MPENTIUMM) || \ ++ defined(CONFIG_MCORE2) || defined(CONFIG_PENTIUM4) ++#define ASM_NOP1 P6_NOP1 ++#define ASM_NOP2 P6_NOP2 ++#define ASM_NOP3 P6_NOP3 ++#define ASM_NOP4 P6_NOP4 ++#define ASM_NOP5 P6_NOP5 ++#define ASM_NOP6 P6_NOP6 ++#define ASM_NOP7 P6_NOP7 ++#define ASM_NOP8 P6_NOP8 + #else + #define ASM_NOP1 GENERIC_NOP1 + #define ASM_NOP2 GENERIC_NOP2 +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/processor_64.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/processor_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -74,6 +74,7 @@ struct cpuinfo_x86 { + __u8 booted_cores; /* number of cores as seen by OS */ + __u8 phys_proc_id; /* Physical Processor id. */ + __u8 cpu_core_id; /* Core id. */ ++ __u8 cpu_index; /* index into per_cpu list */ + #endif + } ____cacheline_aligned; + +@@ -88,11 +89,12 @@ struct cpuinfo_x86 { + #define X86_VENDOR_UNKNOWN 0xff + + #ifdef CONFIG_SMP +-extern struct cpuinfo_x86 cpu_data[]; +-#define current_cpu_data cpu_data[smp_processor_id()] ++DECLARE_PER_CPU(struct cpuinfo_x86, cpu_info); ++#define cpu_data(cpu) per_cpu(cpu_info, cpu) ++#define current_cpu_data cpu_data(smp_processor_id()) + #else +-#define cpu_data (&boot_cpu_data) +-#define current_cpu_data boot_cpu_data ++#define cpu_data(cpu) boot_cpu_data ++#define current_cpu_data boot_cpu_data + #endif + + extern char ignore_irq13; +@@ -343,6 +345,16 @@ struct extended_sigtable { + }; + + ++#if defined(CONFIG_MPSC) || defined(CONFIG_MCORE2) ++#define ASM_NOP1 P6_NOP1 ++#define ASM_NOP2 P6_NOP2 ++#define ASM_NOP3 P6_NOP3 ++#define ASM_NOP4 P6_NOP4 ++#define ASM_NOP5 P6_NOP5 ++#define ASM_NOP6 P6_NOP6 ++#define ASM_NOP7 P6_NOP7 ++#define ASM_NOP8 P6_NOP8 ++#else + #define ASM_NOP1 K8_NOP1 + #define ASM_NOP2 K8_NOP2 + #define ASM_NOP3 K8_NOP3 +@@ -351,6 +363,7 @@ struct extended_sigtable { + #define ASM_NOP6 K8_NOP6 + #define ASM_NOP7 K8_NOP7 + #define ASM_NOP8 K8_NOP8 ++#endif + + /* Opteron nops */ + #define K8_NOP1 ".byte 0x90\n" +@@ -362,6 +375,17 @@ struct extended_sigtable { + #define K8_NOP7 K8_NOP4 K8_NOP3 + #define K8_NOP8 K8_NOP4 K8_NOP4 + ++/* P6 nops */ ++/* uses eax dependencies (Intel-recommended choice) */ ++#define P6_NOP1 ".byte 0x90\n" ++#define P6_NOP2 ".byte 0x66,0x90\n" ++#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n" ++#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n" ++#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n" ++#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n" ++#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n" ++#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n" ++ + #define ASM_NOP_MAX 8 + + /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ +@@ -377,12 +401,6 @@ static inline void sync_core(void) + asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory"); + } + +-#define ARCH_HAS_PREFETCH +-static inline void prefetch(void *x) +-{ +- asm volatile("prefetcht0 (%0)" :: "r" (x)); +-} +- + #define ARCH_HAS_PREFETCHW 1 + static inline void prefetchw(void *x) + { +@@ -398,11 +416,6 @@ static inline void prefetchw(void *x) + + #define cpu_relax() rep_nop() + +-static inline void serialize_cpu(void) +-{ +- __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx"); +-} +- + static inline void __monitor(const void *eax, unsigned long ecx, + unsigned long edx) + { +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/segment.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "segment_32.h" ++#else ++# include "../../segment_64.h" ++#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/smp.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "smp_32.h" ++#else ++# include "smp_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/smp_32.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/smp_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -11,7 +11,7 @@ + #endif + + #if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__) +-#include ++#include + #include + #include + #ifdef CONFIG_X86_IO_APIC +@@ -30,8 +30,8 @@ + extern void smp_alloc_memory(void); + extern int pic_mode; + extern int smp_num_siblings; +-extern cpumask_t cpu_sibling_map[]; +-extern cpumask_t cpu_core_map[]; ++DECLARE_PER_CPU(cpumask_t, cpu_sibling_map); ++DECLARE_PER_CPU(cpumask_t, cpu_core_map); + + extern void (*mtrr_hook) (void); + extern void zap_low_mappings (void); +@@ -39,9 +39,11 @@ extern void lock_ipi_call_lock(void); + extern void unlock_ipi_call_lock(void); + + #define MAX_APICID 256 +-extern u8 x86_cpu_to_apicid[]; ++extern u8 __initdata x86_cpu_to_apicid_init[]; ++extern void *x86_cpu_to_apicid_ptr; ++DECLARE_PER_CPU(u8, x86_cpu_to_apicid); + +-#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] ++#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu) + + #ifdef CONFIG_HOTPLUG_CPU + extern void cpu_exit_clear(void); +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/smp_64.h 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/smp_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -40,10 +40,19 @@ extern void lock_ipi_call_lock(void); + extern void unlock_ipi_call_lock(void); + extern int smp_num_siblings; + extern void smp_send_reschedule(int cpu); ++extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), ++ void *info, int wait); + +-extern cpumask_t cpu_sibling_map[NR_CPUS]; +-extern cpumask_t cpu_core_map[NR_CPUS]; +-extern u8 cpu_llc_id[NR_CPUS]; ++/* ++ * cpu_sibling_map and cpu_core_map now live ++ * in the per cpu area ++ * ++ * extern cpumask_t cpu_sibling_map[NR_CPUS]; ++ * extern cpumask_t cpu_core_map[NR_CPUS]; ++ */ ++DECLARE_PER_CPU(cpumask_t, cpu_sibling_map); ++DECLARE_PER_CPU(cpumask_t, cpu_core_map); ++DECLARE_PER_CPU(u8, cpu_llc_id); + + #define SMP_TRAMPOLINE_BASE 0x6000 + +@@ -70,6 +79,8 @@ extern unsigned __cpuinitdata disabled_c + + #endif /* CONFIG_SMP */ + ++#define safe_smp_processor_id() smp_processor_id() ++ + #ifdef CONFIG_X86_LOCAL_APIC + static inline int hard_smp_processor_id(void) + { +@@ -82,8 +93,9 @@ static inline int hard_smp_processor_id( + * Some lowlevel functions might want to know about + * the real APIC ID <-> CPU # mapping. + */ +-extern u8 x86_cpu_to_apicid[NR_CPUS]; /* physical ID */ +-extern u8 x86_cpu_to_log_apicid[NR_CPUS]; ++extern u8 __initdata x86_cpu_to_apicid_init[]; ++extern void *x86_cpu_to_apicid_ptr; ++DECLARE_PER_CPU(u8, x86_cpu_to_apicid); /* physical ID */ + extern u8 bios_cpu_apicid[]; + + #ifdef CONFIG_X86_LOCAL_APIC +@@ -118,8 +130,9 @@ static __inline int logical_smp_processo + #endif + + #ifdef CONFIG_SMP +-#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] ++#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu) + #else ++extern unsigned int boot_cpu_id; + #define cpu_physical_id(cpu) boot_cpu_id + #endif /* !CONFIG_SMP */ + #endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/swiotlb.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "swiotlb_32.h" ++#else ++# include "../../swiotlb.h" ++#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/system.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "system_32.h" ++#else ++# include "system_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/system_32.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/system_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -9,6 +9,7 @@ + #include + + #ifdef __KERNEL__ ++#define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */ + + struct task_struct; /* one of the stranger aspects of C forward declarations.. */ + extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); +@@ -138,7 +139,7 @@ static inline unsigned long xen_read_cr4 + { + unsigned long val; + /* This could fault if %cr4 does not exist */ +- asm("1: movl %%cr4, %0 \n" ++ asm volatile("1: movl %%cr4, %0 \n" + "2: \n" + ".section __ex_table,\"a\" \n" + ".long 1b,2b \n" +@@ -157,6 +158,11 @@ static inline void xen_wbinvd(void) + asm volatile("wbinvd": : :"memory"); + } + ++static inline void clflush(volatile void *__p) ++{ ++ asm volatile("clflush %0" : "+m" (*(char __force *)__p)); ++} ++ + #define read_cr0() (xen_read_cr0()) + #define write_cr0(x) (xen_write_cr0(x)) + #define read_cr2() (xen_read_cr2()) +@@ -207,6 +213,7 @@ static inline unsigned long get_limit(un + + #define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) + #define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) ++#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) + + /** + * read_barrier_depends - Flush all pending reads that subsequents reads +@@ -262,18 +269,18 @@ static inline unsigned long get_limit(un + + #define read_barrier_depends() do { } while(0) + ++#ifdef CONFIG_SMP ++#define smp_mb() mb() ++#ifdef CONFIG_X86_PPRO_FENCE ++# define smp_rmb() rmb() ++#else ++# define smp_rmb() barrier() ++#endif + #ifdef CONFIG_X86_OOSTORE +-/* Actually there are no OOO store capable CPUs for now that do SSE, +- but make it already an possibility. */ +-#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) ++# define smp_wmb() wmb() + #else +-#define wmb() __asm__ __volatile__ ("": : :"memory") ++# define smp_wmb() barrier() + #endif +- +-#ifdef CONFIG_SMP +-#define smp_mb() mb() +-#define smp_rmb() rmb() +-#define smp_wmb() wmb() + #define smp_read_barrier_depends() read_barrier_depends() + #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) + #else +@@ -300,5 +307,6 @@ extern unsigned long arch_align_stack(un + extern void free_init_pages(char *what, unsigned long begin, unsigned long end); + + void default_idle(void); ++void __show_registers(struct pt_regs *, int all); + + #endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/system_64.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/system_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -11,8 +11,12 @@ + + #ifdef __KERNEL__ + +-#define __STR(x) #x +-#define STR(x) __STR(x) ++/* entries in ARCH_DLINFO: */ ++#ifdef CONFIG_IA32_EMULATION ++# define AT_VECTOR_SIZE_ARCH 2 ++#else ++# define AT_VECTOR_SIZE_ARCH 1 ++#endif + + #define __SAVE(reg,offset) "movq %%" #reg ",(14-" #offset ")*8(%%rsp)\n\t" + #define __RESTORE(reg,offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t" +@@ -92,7 +96,7 @@ static inline void write_cr0(unsigned lo + + #define read_cr3() ({ \ + unsigned long __dummy; \ +- asm("movq %%cr3,%0" : "=r" (__dummy)); \ ++ asm volatile("movq %%cr3,%0" : "=r" (__dummy)); \ + machine_to_phys(__dummy); \ + }) + +@@ -105,7 +109,7 @@ static inline void write_cr3(unsigned lo + static inline unsigned long read_cr4(void) + { + unsigned long cr4; +- asm("movq %%cr4,%0" : "=r" (cr4)); ++ asm volatile("movq %%cr4,%0" : "=r" (cr4)); + return cr4; + } + +@@ -131,12 +135,17 @@ static inline void write_cr8(unsigned lo + + #endif /* __KERNEL__ */ + ++static inline void clflush(volatile void *__p) ++{ ++ asm volatile("clflush %0" : "+m" (*(char __force *)__p)); ++} ++ + #define nop() __asm__ __volatile__ ("nop") + + #ifdef CONFIG_SMP + #define smp_mb() mb() +-#define smp_rmb() rmb() +-#define smp_wmb() wmb() ++#define smp_rmb() barrier() ++#define smp_wmb() barrier() + #define smp_read_barrier_depends() do {} while(0) + #else + #define smp_mb() barrier() +@@ -153,12 +162,8 @@ static inline void write_cr8(unsigned lo + */ + #define mb() asm volatile("mfence":::"memory") + #define rmb() asm volatile("lfence":::"memory") +- +-#ifdef CONFIG_UNORDERED_IO + #define wmb() asm volatile("sfence" ::: "memory") +-#else +-#define wmb() asm volatile("" ::: "memory") +-#endif ++ + #define read_barrier_depends() do {} while(0) + #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) + +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/tlbflush.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "tlbflush_32.h" ++#else ++# include "tlbflush_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/tlbflush_32.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/tlbflush_32.h 2009-02-16 16:18:36.000000000 +0100 +@@ -23,7 +23,6 @@ + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages +- * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables + * + * ..but the i386 has somewhat limited tlb flushing capabilities, + * and page-granular flushes are available only on i486 and up. +@@ -97,10 +96,4 @@ static inline void flush_tlb_kernel_rang + flush_tlb_all(); + } + +-static inline void flush_tlb_pgtables(struct mm_struct *mm, +- unsigned long start, unsigned long end) +-{ +- /* i386 does not keep any page table caches in TLB */ +-} +- + #endif /* _I386_TLBFLUSH_H */ +--- sle11-2009-06-29.orig/include/asm-x86/mach-xen/asm/tlbflush_64.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/tlbflush_64.h 2009-02-16 16:18:36.000000000 +0100 +@@ -28,7 +28,6 @@ + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages +- * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables + * + * x86-64 can only flush individual pages or full VMs. For a range flush + * we always do the full VM. Might be worth trying if for a small +@@ -95,12 +94,4 @@ static inline void flush_tlb_kernel_rang + flush_tlb_all(); + } + +-static inline void flush_tlb_pgtables(struct mm_struct *mm, +- unsigned long start, unsigned long end) +-{ +- /* x86_64 does not keep any page table caches in a software TLB. +- The CPUs do in their hardware TLBs, but they are handled +- by the normal TLB flushing algorithms. */ +-} +- + #endif /* _X8664_TLBFLUSH_H */ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/asm-x86/mach-xen/asm/xor.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,5 @@ ++#ifdef CONFIG_X86_32 ++# include "../../xor_32.h" ++#else ++# include "xor_64.h" ++#endif +--- sle11-2009-06-29.orig/include/asm-x86/mmu.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/asm-x86/mmu.h 2009-02-16 16:18:36.000000000 +0100 +@@ -16,6 +16,9 @@ typedef struct { + rwlock_t ldtlock; + #endif + int size; ++#ifdef CONFIG_XEN ++ unsigned has_foreign_mappings:1; ++#endif + struct mutex lock; + void *vdso; + } mm_context_t; +--- sle11-2009-06-29.orig/include/linux/kexec.h 2009-02-16 15:58:14.000000000 +0100 ++++ sle11-2009-06-29/include/linux/kexec.h 2009-02-17 12:43:57.000000000 +0100 +@@ -202,8 +202,15 @@ extern int dump_after_notifier; + #define VMCOREINFO_BYTES (4096) + #define VMCOREINFO_NOTE_NAME "VMCOREINFO" + #define VMCOREINFO_NOTE_NAME_BYTES ALIGN(sizeof(VMCOREINFO_NOTE_NAME), 4) ++#if !defined(CONFIG_XEN) || !defined(CONFIG_X86) + #define VMCOREINFO_NOTE_SIZE (KEXEC_NOTE_HEAD_BYTES*2 + VMCOREINFO_BYTES \ + + VMCOREINFO_NOTE_NAME_BYTES) ++#else ++#define VMCOREINFO_NOTE_SIZE ALIGN(KEXEC_NOTE_HEAD_BYTES*2 \ ++ + VMCOREINFO_BYTES \ ++ + VMCOREINFO_NOTE_NAME_BYTES, \ ++ PAGE_SIZE) ++#endif + + /* Location of a reserved region to hold the crash kernel. + */ +--- sle11-2009-06-29.orig/include/linux/oprofile.h 2009-06-29 15:28:01.000000000 +0200 ++++ sle11-2009-06-29/include/linux/oprofile.h 2009-06-29 15:28:57.000000000 +0200 +@@ -119,6 +119,8 @@ void oprofile_add_pc(unsigned long pc, i + /* add a backtrace entry, to be called from the ->backtrace callback */ + void oprofile_add_trace(unsigned long eip); + ++void oprofile_add_mode(int cpu_mode); ++ + /* add a domain switch entry */ + int oprofile_add_domain_switch(int32_t domain_id); + +--- sle11-2009-06-29.orig/include/linux/sysctl.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/linux/sysctl.h 2009-02-16 16:18:36.000000000 +0100 +@@ -69,6 +69,7 @@ enum + CTL_BUS=8, /* Busses */ + CTL_ABI=9, /* Binary emulation */ + CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ ++ CTL_XEN=123, /* Xen info and control */ + CTL_ARLAN=254, /* arlan wireless driver */ + CTL_S390DBF=5677, /* s390 debug */ + CTL_SUNRPC=7249, /* sunrpc debug */ +--- sle11-2009-06-29.orig/include/xen/pcifront.h 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/include/xen/pcifront.h 2009-02-16 16:18:36.000000000 +0100 +@@ -12,13 +12,11 @@ + + #ifndef __ia64__ + ++#include ++ + struct pcifront_device; + struct pci_bus; +- +-struct pcifront_sd { +- int domain; +- struct pcifront_device *pdev; +-}; ++#define pcifront_sd pci_sysdata + + static inline struct pcifront_device * + pcifront_get_pdev(struct pcifront_sd *sd) +@@ -34,18 +32,6 @@ static inline void pcifront_init_sd(stru + sd->pdev = pdev; + } + +-#if defined(CONFIG_PCI_DOMAINS) +-static inline int pci_domain_nr(struct pci_bus *bus) +-{ +- struct pcifront_sd *sd = bus->sysdata; +- return sd->domain; +-} +-static inline int pci_proc_domain(struct pci_bus *bus) +-{ +- return pci_domain_nr(bus); +-} +-#endif /* CONFIG_PCI_DOMAINS */ +- + static inline void pcifront_setup_root_resources(struct pci_bus *bus, + struct pcifront_sd *sd) + { +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/include/xen/sysctl.h 2009-02-16 16:18:36.000000000 +0100 +@@ -0,0 +1,11 @@ ++#ifndef _XEN_SYSCTL_H ++#define _XEN_SYSCTL_H ++ ++/* CTL_XEN names: */ ++enum ++{ ++ CTL_XEN_INDEPENDENT_WALLCLOCK=1, ++ CTL_XEN_PERMITTED_CLOCK_JITTER=2, ++}; ++ ++#endif /* _XEN_SYSCTL_H */ +--- sle11-2009-06-29.orig/include/xen/xenbus.h 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/include/xen/xenbus.h 2009-02-16 16:18:36.000000000 +0100 +@@ -107,7 +107,7 @@ struct xenbus_driver { + int (*suspend)(struct xenbus_device *dev); + int (*suspend_cancel)(struct xenbus_device *dev); + int (*resume)(struct xenbus_device *dev); +- int (*uevent)(struct xenbus_device *, char **, int, char *, int); ++ int (*uevent)(struct xenbus_device *, struct kobj_uevent_env *); + struct device_driver driver; + int (*read_otherend_details)(struct xenbus_device *dev); + int (*is_ready)(struct xenbus_device *dev); +--- sle11-2009-06-29.orig/kernel/kexec.c 2009-02-17 11:34:22.000000000 +0100 ++++ sle11-2009-06-29/kernel/kexec.c 2009-02-17 12:38:20.000000000 +0100 +@@ -52,7 +52,11 @@ int dump_after_notifier; + + /* vmcoreinfo stuff */ + unsigned char vmcoreinfo_data[VMCOREINFO_BYTES]; +-u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; ++u32 ++#if defined(CONFIG_XEN) && defined(CONFIG_X86) ++__attribute__((__section__(".bss.page_aligned"), __aligned__(PAGE_SIZE))) ++#endif ++vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; + size_t vmcoreinfo_size; + size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data); + +@@ -1240,6 +1244,7 @@ static int __init crash_notes_memory_ini + module_init(crash_notes_memory_init) + + ++#ifndef CONFIG_XEN + /* + * parsing the "crashkernel" commandline + * +@@ -1402,7 +1407,7 @@ int __init parse_crashkernel(char *cm + + return 0; + } +- ++#endif + + + void crash_save_vmcoreinfo(void) +@@ -1459,7 +1464,18 @@ static int __init crash_save_vmcoreinfo_ + + VMCOREINFO_SYMBOL(init_uts_ns); + VMCOREINFO_SYMBOL(node_online_map); ++#ifndef CONFIG_X86_XEN + VMCOREINFO_SYMBOL(swapper_pg_dir); ++#else ++/* ++ * Since for x86-32 Xen swapper_pg_dir is a pointer rather than an array, ++ * make the value stored consistent with native (i.e. the base address of ++ * the page directory). ++ */ ++# define swapper_pg_dir *swapper_pg_dir ++ VMCOREINFO_SYMBOL(swapper_pg_dir); ++# undef swapper_pg_dir ++#endif + VMCOREINFO_SYMBOL(_stext); + + #ifndef CONFIG_NEED_MULTIPLE_NODES +--- sle11-2009-06-29.orig/kernel/sysctl_check.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/kernel/sysctl_check.c 2009-02-16 16:18:36.000000000 +0100 +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + struct trans_ctl_table { + int ctl_name; +@@ -897,6 +898,14 @@ static const struct trans_ctl_table tran + {} + }; + ++#ifdef CONFIG_XEN ++static struct trans_ctl_table trans_xen_table[] = { ++ { CTL_XEN_INDEPENDENT_WALLCLOCK, "independent_wallclock" }, ++ { CTL_XEN_PERMITTED_CLOCK_JITTER, "permitted_clock_jitter" }, ++ {} ++}; ++#endif ++ + static const struct trans_ctl_table trans_arlan_conf_table0[] = { + { 1, "spreadingCode" }, + { 2, "channelNumber" }, +@@ -1232,6 +1241,9 @@ static const struct trans_ctl_table tran + { CTL_BUS, "bus", trans_bus_table }, + { CTL_ABI, "abi" }, + /* CTL_CPU not used */ ++#ifdef CONFIG_XEN ++ { CTL_XEN, "xen", trans_xen_table }, ++#endif + { CTL_ARLAN, "arlan", trans_arlan_table }, + { CTL_S390DBF, "s390dbf", trans_s390dbf_table }, + { CTL_SUNRPC, "sunrpc", trans_sunrpc_table }, +--- sle11-2009-06-29.orig/lib/swiotlb-xen.c 2009-02-05 11:16:51.000000000 +0100 ++++ sle11-2009-06-29/lib/swiotlb-xen.c 2009-02-16 16:18:36.000000000 +0100 +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + + int swiotlb; + EXPORT_SYMBOL(swiotlb); +@@ -574,9 +574,10 @@ swiotlb_sync_single_for_device(struct de + * same here. + */ + int +-swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems, ++swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems, + int dir) + { ++ struct scatterlist *sg; + struct phys_addr buffer; + dma_addr_t dev_addr; + char *map; +@@ -584,22 +585,22 @@ swiotlb_map_sg(struct device *hwdev, str + + BUG_ON(dir == DMA_NONE); + +- for (i = 0; i < nelems; i++, sg++) { +- dev_addr = gnttab_dma_map_page(sg->page) + sg->offset; ++ for_each_sg(sgl, sg, nelems, i) { ++ dev_addr = gnttab_dma_map_page(sg_page(sg)) + sg->offset; + +- if (range_straddles_page_boundary(page_to_pseudophys(sg->page) ++ if (range_straddles_page_boundary(page_to_pseudophys(sg_page(sg)) + + sg->offset, sg->length) + || address_needs_mapping(hwdev, dev_addr)) { + gnttab_dma_unmap_page(dev_addr); +- buffer.page = sg->page; ++ buffer.page = sg_page(sg); + buffer.offset = sg->offset; + map = map_single(hwdev, buffer, sg->length, dir); + if (!map) { + /* Don't panic here, we expect map_sg users + to do proper error handling. */ + swiotlb_full(hwdev, sg->length, dir, 0); +- swiotlb_unmap_sg(hwdev, sg - i, i, dir); +- sg[0].dma_length = 0; ++ swiotlb_unmap_sg(hwdev, sgl, i, dir); ++ sgl[0].dma_length = 0; + return 0; + } + sg->dma_address = virt_to_bus(map); +@@ -615,19 +616,21 @@ swiotlb_map_sg(struct device *hwdev, str + * concerning calls here are the same as for swiotlb_unmap_single() above. + */ + void +-swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems, ++swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems, + int dir) + { ++ struct scatterlist *sg; + int i; + + BUG_ON(dir == DMA_NONE); + +- for (i = 0; i < nelems; i++, sg++) ++ for_each_sg(sgl, sg, nelems, i) { + if (in_swiotlb_aperture(sg->dma_address)) + unmap_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); + else + gnttab_dma_unmap_page(sg->dma_address); ++ } + } + + /* +@@ -638,31 +641,35 @@ swiotlb_unmap_sg(struct device *hwdev, s + * and usage. + */ + void +-swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg, ++swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sgl, + int nelems, int dir) + { ++ struct scatterlist *sg; + int i; + + BUG_ON(dir == DMA_NONE); + +- for (i = 0; i < nelems; i++, sg++) ++ for_each_sg(sgl, sg, nelems, i) { + if (in_swiotlb_aperture(sg->dma_address)) + sync_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); ++ } + } + + void +-swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg, ++swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sgl, + int nelems, int dir) + { ++ struct scatterlist *sg; + int i; + + BUG_ON(dir == DMA_NONE); + +- for (i = 0; i < nelems; i++, sg++) ++ for_each_sg(sgl, sg, nelems, i) { + if (in_swiotlb_aperture(sg->dma_address)) + sync_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); ++ } + } + + #ifdef CONFIG_HIGHMEM diff --git a/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.25 b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.25 new file mode 100644 index 000000000..a1535d8be --- /dev/null +++ b/src/patches/suse-2.6.27.31/patches.xen/xen3-patch-2.6.25 @@ -0,0 +1,29291 @@ +From: kernel.org +Subject: 2.6.25 +Patch-mainline: 2.6.25 + +Signed-off-by: Greg Kroah-Hartman + +Automatically created from "patches.kernel.org/patch-2.6.25" by xen-port-patches.py + +--- sle11-2009-06-29.orig/arch/x86/Kconfig 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/Kconfig 2009-03-16 16:33:40.000000000 +0100 +@@ -27,7 +27,7 @@ config X86 + select HAVE_KRETPROBES + select HAVE_DYNAMIC_FTRACE + select HAVE_FTRACE +- select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) ++ select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) && !XEN + select HAVE_ARCH_KGDB if !X86_VOYAGER + select HAVE_ARCH_TRACEHOOK + select HAVE_GENERIC_DMA_COHERENT if X86_32 +@@ -211,14 +211,12 @@ config X86_TRAMPOLINE + default y + + config X86_NO_TSS +- bool ++ def_bool y + depends on XEN +- default y + + config X86_NO_IDT +- bool ++ def_bool y + depends on XEN +- default y + + config KTIME_SCALAR + def_bool X86_32 +@@ -728,9 +726,8 @@ config X86_VISWS_APIC + depends on X86_32 && X86_VISWS + + config X86_XEN_GENAPIC +- bool ++ def_bool y + depends on X86_64_XEN +- default y + + config X86_MCE + bool "Machine Check Exception" +@@ -1117,7 +1114,7 @@ config ARCH_DISCONTIGMEM_DEFAULT + + config ARCH_SPARSEMEM_DEFAULT + def_bool y +- depends on X86_64 ++ depends on X86_64 && !X86_64_XEN + + config ARCH_SPARSEMEM_ENABLE + def_bool y +@@ -1747,10 +1744,10 @@ config PCI_MMCONFIG + depends on X86_64 && PCI && ACPI + + config XEN_PCIDEV_FRONTEND +- bool "Xen PCI Frontend" if X86_64 ++ def_bool y ++ prompt "Xen PCI Frontend" if X86_64 + depends on PCI && XEN && (PCI_GOXEN_FE || PCI_GOANY || X86_64) + select HOTPLUG +- default y + help + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. +@@ -1758,7 +1755,6 @@ config XEN_PCIDEV_FRONTEND + config XEN_PCIDEV_FE_DEBUG + bool "Xen PCI Frontend Debugging" + depends on XEN_PCIDEV_FRONTEND +- default n + help + Enables some debug statements within the PCI Frontend. + +--- sle11-2009-06-29.orig/arch/x86/Kconfig.debug 2009-02-02 09:40:56.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/Kconfig.debug 2009-03-16 16:33:40.000000000 +0100 +@@ -279,6 +279,7 @@ config DEBUG_BOOT_PARAMS + bool "Debug boot parameters" + depends on DEBUG_KERNEL + depends on DEBUG_FS ++ depends on !XEN + help + This option will cause struct boot_params to be exported via debugfs. + +--- sle11-2009-06-29.orig/arch/x86/ia32/ia32entry-xen.S 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/ia32/ia32entry-xen.S 2009-03-16 16:33:40.000000000 +0100 +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -99,10 +98,11 @@ ENTRY(ia32_sysenter_target) + CFI_RESTORE rcx + movl %ebp,%ebp /* zero extension */ + movl %eax,%eax ++ movl 48-THREAD_SIZE+threadinfo_sysenter_return(%rsp),%r10d + movl $__USER32_DS,40(%rsp) + movq %rbp,32(%rsp) + movl $__USER32_CS,16(%rsp) +- movl $VSYSCALL32_SYSEXIT,8(%rsp) ++ movq %r10,8(%rsp) + movq %rax,(%rsp) + cld + SAVE_ARGS 0,0,1 +@@ -582,8 +582,8 @@ ia32_sys_call_table: + .quad compat_sys_futex /* 240 */ + .quad compat_sys_sched_setaffinity + .quad compat_sys_sched_getaffinity +- .quad sys32_set_thread_area +- .quad sys32_get_thread_area ++ .quad sys_set_thread_area ++ .quad sys_get_thread_area + .quad compat_sys_io_setup /* 245 */ + .quad sys_io_destroy + .quad compat_sys_io_getevents +@@ -661,7 +661,9 @@ ia32_sys_call_table: + .quad sys_epoll_pwait + .quad compat_sys_utimensat /* 320 */ + .quad compat_sys_signalfd +- .quad compat_sys_timerfd ++ .quad sys_timerfd_create + .quad sys_eventfd + .quad sys32_fallocate ++ .quad compat_sys_timerfd_settime /* 325 */ ++ .quad compat_sys_timerfd_gettime + ia32_syscall_end: +--- sle11-2009-06-29.orig/arch/x86/kernel/Makefile 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/Makefile 2009-03-16 16:33:40.000000000 +0100 +@@ -120,11 +120,10 @@ ifeq ($(CONFIG_X86_64),y) + + obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o + ++ obj-$(CONFIG_XEN) += nmi_64.o + time_64-$(CONFIG_XEN) += time_32.o + pci-dma_64-$(CONFIG_XEN) += pci-dma_32.o + endif + + disabled-obj-$(CONFIG_XEN) := early-quirks.o hpet.o i8253.o i8259_$(BITS).o reboot.o \ + smpboot_$(BITS).o tsc_$(BITS).o tsc_sync.o +-disabled-obj-$(CONFIG_XEN_UNPRIVILEGED_GUEST) += mpparse_64.o +-%/head_64.o %/head_64.s: asflags-$(CONFIG_XEN) := +--- sle11-2009-06-29.orig/arch/x86/kernel/acpi/boot.c 2008-12-01 11:11:08.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/acpi/boot.c 2009-03-16 16:33:40.000000000 +0100 +@@ -133,6 +133,9 @@ char *__init __acpi_map_table(unsigned l + #ifndef CONFIG_XEN + if (phys+size <= (max_low_pfn_mapped << PAGE_SHIFT)) + return __va(phys); ++#else ++ if (phys + size <= (NR_FIX_ISAMAPS << PAGE_SHIFT)) ++ return isa_bus_to_virt(phys); + #endif + + offset = phys & (PAGE_SIZE - 1); +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/arch/x86/kernel/acpi/sleep-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -0,0 +1,95 @@ ++/* ++ * sleep.c - x86-specific ACPI sleep support. ++ * ++ * Copyright (C) 2001-2003 Patrick Mochel ++ * Copyright (C) 2001-2003 Pavel Machek ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef CONFIG_ACPI_PV_SLEEP ++/* address in low memory of the wakeup routine. */ ++unsigned long acpi_wakeup_address = 0; ++unsigned long acpi_realmode_flags; ++extern char wakeup_start, wakeup_end; ++ ++extern unsigned long acpi_copy_wakeup_routine(unsigned long); ++#endif ++ ++/** ++ * acpi_save_state_mem - save kernel state ++ * ++ * Create an identity mapped page table and copy the wakeup routine to ++ * low memory. ++ */ ++int acpi_save_state_mem(void) ++{ ++#ifndef CONFIG_ACPI_PV_SLEEP ++ if (!acpi_wakeup_address) { ++ printk(KERN_ERR "Could not allocate memory during boot, S3 disabled\n"); ++ return -ENOMEM; ++ } ++ memcpy((void *)acpi_wakeup_address, &wakeup_start, ++ &wakeup_end - &wakeup_start); ++ acpi_copy_wakeup_routine(acpi_wakeup_address); ++#endif ++ ++ return 0; ++} ++ ++/* ++ * acpi_restore_state - undo effects of acpi_save_state_mem ++ */ ++void acpi_restore_state_mem(void) ++{ ++} ++ ++ ++/** ++ * acpi_reserve_bootmem - do _very_ early ACPI initialisation ++ * ++ * We allocate a page from the first 1MB of memory for the wakeup ++ * routine for when we come back from a sleep state. The ++ * runtime allocator allows specification of <16MB pages, but not ++ * <1MB pages. ++ */ ++void __init acpi_reserve_bootmem(void) ++{ ++#ifndef CONFIG_ACPI_PV_SLEEP ++ if ((&wakeup_end - &wakeup_start) > PAGE_SIZE*2) { ++ printk(KERN_ERR ++ "ACPI: Wakeup code way too big, S3 disabled.\n"); ++ return; ++ } ++ ++ acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); ++ if (!acpi_wakeup_address) ++ printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); ++#endif ++} ++ ++ ++#ifndef CONFIG_ACPI_PV_SLEEP ++static int __init acpi_sleep_setup(char *str) ++{ ++ while ((str != NULL) && (*str != '\0')) { ++ if (strncmp(str, "s3_bios", 7) == 0) ++ acpi_realmode_flags |= 1; ++ if (strncmp(str, "s3_mode", 7) == 0) ++ acpi_realmode_flags |= 2; ++ if (strncmp(str, "s3_beep", 7) == 0) ++ acpi_realmode_flags |= 4; ++ str = strchr(str, ','); ++ if (str != NULL) ++ str += strspn(str, ", \t"); ++ } ++ return 1; ++} ++ ++__setup("acpi_sleep=", acpi_sleep_setup); ++#endif /* CONFIG_ACPI_PV_SLEEP */ +--- sle11-2009-06-29.orig/arch/x86/kernel/acpi/sleep_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,117 +0,0 @@ +-/* +- * sleep.c - x86-specific ACPI sleep support. +- * +- * Copyright (C) 2001-2003 Patrick Mochel +- * Copyright (C) 2001-2003 Pavel Machek +- */ +- +-#include +-#include +-#include +-#include +- +-#include +- +-#ifndef CONFIG_ACPI_PV_SLEEP +-/* address in low memory of the wakeup routine. */ +-unsigned long acpi_wakeup_address = 0; +-unsigned long acpi_realmode_flags; +-extern char wakeup_start, wakeup_end; +- +-extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); +-#endif +- +-/** +- * acpi_save_state_mem - save kernel state +- * +- * Create an identity mapped page table and copy the wakeup routine to +- * low memory. +- */ +-int acpi_save_state_mem(void) +-{ +-#ifndef CONFIG_ACPI_PV_SLEEP +- if (!acpi_wakeup_address) +- return 1; +- memcpy((void *)acpi_wakeup_address, &wakeup_start, +- &wakeup_end - &wakeup_start); +- acpi_copy_wakeup_routine(acpi_wakeup_address); +-#endif +- return 0; +-} +- +-/* +- * acpi_restore_state - undo effects of acpi_save_state_mem +- */ +-void acpi_restore_state_mem(void) +-{ +-} +- +-/** +- * acpi_reserve_bootmem - do _very_ early ACPI initialisation +- * +- * We allocate a page from the first 1MB of memory for the wakeup +- * routine for when we come back from a sleep state. The +- * runtime allocator allows specification of <16MB pages, but not +- * <1MB pages. +- */ +-void __init acpi_reserve_bootmem(void) +-{ +-#ifndef CONFIG_ACPI_PV_SLEEP +- if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) { +- printk(KERN_ERR +- "ACPI: Wakeup code way too big, S3 disabled.\n"); +- return; +- } +- +- acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); +- if (!acpi_wakeup_address) +- printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); +-#endif +-} +- +-#ifndef CONFIG_ACPI_PV_SLEEP +-static int __init acpi_sleep_setup(char *str) +-{ +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "s3_bios", 7) == 0) +- acpi_realmode_flags |= 1; +- if (strncmp(str, "s3_mode", 7) == 0) +- acpi_realmode_flags |= 2; +- if (strncmp(str, "s3_beep", 7) == 0) +- acpi_realmode_flags |= 4; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- return 1; +-} +- +-__setup("acpi_sleep=", acpi_sleep_setup); +- +-/* Ouch, we want to delete this. We already have better version in userspace, in +- s2ram from suspend.sf.net project */ +-static __init int reset_videomode_after_s3(const struct dmi_system_id *d) +-{ +- acpi_realmode_flags |= 2; +- return 0; +-} +- +-static __initdata struct dmi_system_id acpisleep_dmi_table[] = { +- { /* Reset video mode after returning from ACPI S3 sleep */ +- .callback = reset_videomode_after_s3, +- .ident = "Toshiba Satellite 4030cdt", +- .matches = { +- DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), +- }, +- }, +- {} +-}; +- +-static int __init acpisleep_dmi_init(void) +-{ +- dmi_check_system(acpisleep_dmi_table); +- return 0; +-} +- +-core_initcall(acpisleep_dmi_init); +-#endif /* CONFIG_ACPI_PV_SLEEP */ +--- sle11-2009-06-29.orig/arch/x86/kernel/acpi/sleep_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,125 +0,0 @@ +-/* +- * acpi.c - Architecture-Specific Low-Level ACPI Support +- * +- * Copyright (C) 2001, 2002 Paul Diefenbaugh +- * Copyright (C) 2001 Jun Nakajima +- * Copyright (C) 2001 Patrick Mochel +- * Copyright (C) 2002 Andi Kleen, SuSE Labs (x86-64 port) +- * Copyright (C) 2003 Pavel Machek, SuSE Labs +- * +- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +- * +- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* -------------------------------------------------------------------------- +- Low-Level Sleep Support +- -------------------------------------------------------------------------- */ +- +-#ifndef CONFIG_ACPI_PV_SLEEP +-/* address in low memory of the wakeup routine. */ +-unsigned long acpi_wakeup_address = 0; +-unsigned long acpi_realmode_flags; +-extern char wakeup_start, wakeup_end; +- +-extern unsigned long acpi_copy_wakeup_routine(unsigned long); +-#endif +- +-/** +- * acpi_save_state_mem - save kernel state +- * +- * Create an identity mapped page table and copy the wakeup routine to +- * low memory. +- */ +-int acpi_save_state_mem(void) +-{ +-#ifndef CONFIG_ACPI_PV_SLEEP +- memcpy((void *)acpi_wakeup_address, &wakeup_start, +- &wakeup_end - &wakeup_start); +- acpi_copy_wakeup_routine(acpi_wakeup_address); +-#endif +- return 0; +-} +- +-/* +- * acpi_restore_state +- */ +-void acpi_restore_state_mem(void) +-{ +-} +- +-/** +- * acpi_reserve_bootmem - do _very_ early ACPI initialisation +- * +- * We allocate a page in low memory for the wakeup +- * routine for when we come back from a sleep state. The +- * runtime allocator allows specification of <16M pages, but not +- * <1M pages. +- */ +-void __init acpi_reserve_bootmem(void) +-{ +-#ifndef CONFIG_ACPI_PV_SLEEP +- acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2); +- if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2)) +- printk(KERN_CRIT +- "ACPI: Wakeup code way too big, will crash on attempt" +- " to suspend\n"); +-#endif +-} +- +-#ifndef CONFIG_ACPI_PV_SLEEP +-static int __init acpi_sleep_setup(char *str) +-{ +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "s3_bios", 7) == 0) +- acpi_realmode_flags |= 1; +- if (strncmp(str, "s3_mode", 7) == 0) +- acpi_realmode_flags |= 2; +- if (strncmp(str, "s3_beep", 7) == 0) +- acpi_realmode_flags |= 4; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- +- return 1; +-} +- +-__setup("acpi_sleep=", acpi_sleep_setup); +-#endif /* CONFIG_ACPI_PV_SLEEP */ +- +--- sle11-2009-06-29.orig/arch/x86/kernel/apic_32-xen.c 2008-12-15 11:27:22.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/apic_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -86,7 +86,7 @@ int setup_profiling_timer(unsigned int m + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +-int __init APIC_init_uniprocessor (void) ++int __init APIC_init_uniprocessor(void) + { + #ifdef CONFIG_X86_IO_APIC + if (smp_found_config) +--- sle11-2009-06-29.orig/arch/x86/kernel/apic_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/apic_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -34,34 +34,17 @@ + #include + #include + +-int apic_verbosity; ++int disable_apic; + + /* +- * 'what should we do if we get a hw irq event on an illegal vector'. +- * each architecture has to answer this themselves. ++ * Debug level, exported for io_apic.c + */ +-void ack_bad_irq(unsigned int irq) +-{ +- printk("unexpected IRQ trap at irq %02x\n", irq); +- /* +- * Currently unexpected vectors happen only on SMP and APIC. +- * We _must_ ack these because every local APIC has only N +- * irq slots per priority level, and a 'hanging, unacked' IRQ +- * holds up an irq slot - in excessive cases (when multiple +- * unexpected vectors occur) that might lock up the APIC +- * completely. +- * But don't ack when the APIC is disabled. -AK +- */ +- if (!disable_apic) +- ack_APIC_irq(); +-} +- +-int setup_profiling_timer(unsigned int multiplier) +-{ +- return -EINVAL; +-} ++int apic_verbosity; + +-void smp_local_timer_interrupt(void) ++/* ++ * The guts of the apic timer interrupt ++ */ ++static void local_apic_timer_interrupt(void) + { + #ifndef CONFIG_XEN + int cpu = smp_processor_id(); +@@ -121,11 +104,34 @@ void smp_apic_timer_interrupt(struct pt_ + */ + exit_idle(); + irq_enter(); +- smp_local_timer_interrupt(); ++ local_apic_timer_interrupt(); + irq_exit(); + set_irq_regs(old_regs); + } + ++int setup_profiling_timer(unsigned int multiplier) ++{ ++ return -EINVAL; ++} ++ ++/* ++ * This initializes the IO-APIC and APIC hardware if this is ++ * a UP kernel. ++ */ ++int __init APIC_init_uniprocessor(void) ++{ ++#ifdef CONFIG_X86_IO_APIC ++ if (smp_found_config && !skip_ioapic_setup && nr_ioapics) ++ setup_IO_APIC(); ++#endif ++ ++ return 1; ++} ++ ++/* ++ * Local APIC interrupts ++ */ ++ + /* + * This interrupt should _never_ happen with our APIC/SMP architecture + */ +@@ -150,7 +156,6 @@ asmlinkage void smp_spurious_interrupt(v + /* + * This interrupt should never happen with our APIC/SMP architecture + */ +- + asmlinkage void smp_error_interrupt(void) + { + unsigned int v, v1; +@@ -178,19 +183,3 @@ asmlinkage void smp_error_interrupt(void + smp_processor_id(), v , v1); + irq_exit(); + } +- +-int disable_apic; +- +-/* +- * This initializes the IO-APIC and APIC hardware if this is +- * a UP kernel. +- */ +-int __init APIC_init_uniprocessor (void) +-{ +-#ifdef CONFIG_X86_IO_APIC +- if (smp_found_config && !skip_ioapic_setup && nr_ioapics) +- setup_IO_APIC(); +-#endif +- +- return 1; +-} +--- sle11-2009-06-29.orig/arch/x86/kernel/asm-offsets_32.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/asm-offsets_32.c 2009-03-16 16:33:40.000000000 +0100 +@@ -23,8 +23,10 @@ + #include + #endif + ++#ifdef CONFIG_LGUEST_GUEST + #include + #include "../../../drivers/lguest/lg.h" ++#endif + + /* workaround for a warning with -Wmissing-prototypes */ + void foo(void); +--- sle11-2009-06-29.orig/arch/x86/kernel/cpu/common-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/cpu/common-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -27,45 +27,50 @@ + #include "cpu.h" + + DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { +- [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, +- [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, +- [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, +- [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, ++ [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } }, ++ [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } }, ++ [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } }, ++ [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff200 } } }, + #ifndef CONFIG_XEN + /* + * Segments used for calling PnP BIOS have byte granularity. + * They code segments and data segments have fixed 64k limits, + * the transfer segment sizes are set at run time. + */ +- [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ +- [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ +- [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ +- [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ +- [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ ++ /* 32-bit code */ ++ [GDT_ENTRY_PNPBIOS_CS32] = { { { 0x0000ffff, 0x00409a00 } } }, ++ /* 16-bit code */ ++ [GDT_ENTRY_PNPBIOS_CS16] = { { { 0x0000ffff, 0x00009a00 } } }, ++ /* 16-bit data */ ++ [GDT_ENTRY_PNPBIOS_DS] = { { { 0x0000ffff, 0x00009200 } } }, ++ /* 16-bit data */ ++ [GDT_ENTRY_PNPBIOS_TS1] = { { { 0x00000000, 0x00009200 } } }, ++ /* 16-bit data */ ++ [GDT_ENTRY_PNPBIOS_TS2] = { { { 0x00000000, 0x00009200 } } }, + /* + * The APM segments have byte granularity and their bases + * are set at run time. All have 64k limits. + */ +- [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ ++ /* 32-bit code */ ++ [GDT_ENTRY_APMBIOS_BASE] = { { { 0x0000ffff, 0x00409a00 } } }, + /* 16-bit code */ +- [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 }, +- [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */ ++ [GDT_ENTRY_APMBIOS_BASE+1] = { { { 0x0000ffff, 0x00009a00 } } }, ++ /* data */ ++ [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } }, + +- [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 }, ++ [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, + #endif +- [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 }, ++ [GDT_ENTRY_PERCPU] = { { { 0x00000000, 0x00000000 } } }, + } }; + EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); + ++__u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; ++ + static int cachesize_override __cpuinitdata = -1; +-static int disable_x86_fxsr __cpuinitdata; + static int disable_x86_serial_nr __cpuinitdata = 1; +-static int disable_x86_sep __cpuinitdata; + + struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; + +-extern int disable_pse; +- + static void __cpuinit default_init(struct cpuinfo_x86 * c) + { + /* Not much we can do here... */ +@@ -214,16 +219,8 @@ static void __cpuinit get_cpu_vendor(str + + static int __init x86_fxsr_setup(char * s) + { +- /* Tell all the other CPUs to not use it... */ +- disable_x86_fxsr = 1; +- +- /* +- * ... and clear the bits early in the boot_cpu_data +- * so that the bootup process doesn't try to do this +- * either. +- */ +- clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability); +- clear_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability); ++ setup_clear_cpu_cap(X86_FEATURE_FXSR); ++ setup_clear_cpu_cap(X86_FEATURE_XMM); + return 1; + } + __setup("nofxsr", x86_fxsr_setup); +@@ -231,7 +228,7 @@ __setup("nofxsr", x86_fxsr_setup); + + static int __init x86_sep_setup(char * s) + { +- disable_x86_sep = 1; ++ setup_clear_cpu_cap(X86_FEATURE_SEP); + return 1; + } + __setup("nosep", x86_sep_setup); +@@ -268,10 +265,10 @@ static int __cpuinit have_cpuid_p(void) + void __init cpu_detect(struct cpuinfo_x86 *c) + { + /* Get vendor name */ +- cpuid(0x00000000, &c->cpuid_level, +- (int *)&c->x86_vendor_id[0], +- (int *)&c->x86_vendor_id[8], +- (int *)&c->x86_vendor_id[4]); ++ cpuid(0x00000000, (unsigned int *)&c->cpuid_level, ++ (unsigned int *)&c->x86_vendor_id[0], ++ (unsigned int *)&c->x86_vendor_id[8], ++ (unsigned int *)&c->x86_vendor_id[4]); + + c->x86 = 4; + if (c->cpuid_level >= 0x00000001) { +@@ -284,9 +281,38 @@ void __init cpu_detect(struct cpuinfo_x8 + if (c->x86 >= 0x6) + c->x86_model += ((tfms >> 16) & 0xF) << 4; + c->x86_mask = tfms & 15; +- if (cap0 & (1<<19)) ++ if (cap0 & (1<<19)) { + c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8; ++ c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; ++ } ++ } ++} ++static void __cpuinit early_get_cap(struct cpuinfo_x86 *c) ++{ ++ u32 tfms, xlvl; ++ unsigned int ebx; ++ ++ memset(&c->x86_capability, 0, sizeof c->x86_capability); ++ if (have_cpuid_p()) { ++ /* Intel-defined flags: level 0x00000001 */ ++ if (c->cpuid_level >= 0x00000001) { ++ u32 capability, excap; ++ cpuid(0x00000001, &tfms, &ebx, &excap, &capability); ++ c->x86_capability[0] = capability; ++ c->x86_capability[4] = excap; ++ } ++ ++ /* AMD-defined flags: level 0x80000001 */ ++ xlvl = cpuid_eax(0x80000000); ++ if ((xlvl & 0xffff0000) == 0x80000000) { ++ if (xlvl >= 0x80000001) { ++ c->x86_capability[1] = cpuid_edx(0x80000001); ++ c->x86_capability[6] = cpuid_ecx(0x80000001); ++ } ++ } ++ + } ++ + } + + /* Do minimum CPU detection early. +@@ -300,6 +326,7 @@ static void __init early_cpu_detect(void + struct cpuinfo_x86 *c = &boot_cpu_data; + + c->x86_cache_alignment = 32; ++ c->x86_clflush_size = 32; + + if (!have_cpuid_p()) + return; +@@ -307,19 +334,30 @@ static void __init early_cpu_detect(void + cpu_detect(c); + + get_cpu_vendor(c, 1); ++ ++ switch (c->x86_vendor) { ++ case X86_VENDOR_AMD: ++ early_init_amd(c); ++ break; ++ case X86_VENDOR_INTEL: ++ early_init_intel(c); ++ break; ++ } ++ ++ early_get_cap(c); + } + + static void __cpuinit generic_identify(struct cpuinfo_x86 * c) + { + u32 tfms, xlvl; +- int ebx; ++ unsigned int ebx; + + if (have_cpuid_p()) { + /* Get vendor name */ +- cpuid(0x00000000, &c->cpuid_level, +- (int *)&c->x86_vendor_id[0], +- (int *)&c->x86_vendor_id[8], +- (int *)&c->x86_vendor_id[4]); ++ cpuid(0x00000000, (unsigned int *)&c->cpuid_level, ++ (unsigned int *)&c->x86_vendor_id[0], ++ (unsigned int *)&c->x86_vendor_id[8], ++ (unsigned int *)&c->x86_vendor_id[4]); + + get_cpu_vendor(c, 0); + /* Initialize the standard set of capabilities */ +@@ -364,8 +402,6 @@ static void __cpuinit generic_identify(s + init_scattered_cpuid_features(c); + } + +- early_intel_workaround(c); +- + #ifdef CONFIG_X86_HT + c->phys_proc_id = (cpuid_ebx(1) >> 24) & 0xff; + #endif +@@ -399,7 +435,7 @@ __setup("serialnumber", x86_serial_nr_se + /* + * This does the hard work of actually picking apart the CPU stuff... + */ +-static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) ++void __cpuinit identify_cpu(struct cpuinfo_x86 *c) + { + int i; + +@@ -425,20 +461,9 @@ static void __cpuinit identify_cpu(struc + + generic_identify(c); + +- printk(KERN_DEBUG "CPU: After generic identify, caps:"); +- for (i = 0; i < NCAPINTS; i++) +- printk(" %08lx", c->x86_capability[i]); +- printk("\n"); +- +- if (this_cpu->c_identify) { ++ if (this_cpu->c_identify) + this_cpu->c_identify(c); + +- printk(KERN_DEBUG "CPU: After vendor identify, caps:"); +- for (i = 0; i < NCAPINTS; i++) +- printk(" %08lx", c->x86_capability[i]); +- printk("\n"); +- } +- + /* + * Vendor-specific initialization. In this section we + * canonicalize the feature flags, meaning if there are +@@ -460,23 +485,6 @@ static void __cpuinit identify_cpu(struc + * we do "generic changes." + */ + +- /* TSC disabled? */ +- if ( tsc_disable ) +- clear_bit(X86_FEATURE_TSC, c->x86_capability); +- +- /* FXSR disabled? */ +- if (disable_x86_fxsr) { +- clear_bit(X86_FEATURE_FXSR, c->x86_capability); +- clear_bit(X86_FEATURE_XMM, c->x86_capability); +- } +- +- /* SEP disabled? */ +- if (disable_x86_sep) +- clear_bit(X86_FEATURE_SEP, c->x86_capability); +- +- if (disable_pse) +- clear_bit(X86_FEATURE_PSE, c->x86_capability); +- + /* If the model name is still unset, do table lookup. */ + if ( !c->x86_model_id[0] ) { + char *p; +@@ -489,13 +497,6 @@ static void __cpuinit identify_cpu(struc + c->x86, c->x86_model); + } + +- /* Now the feature flags better reflect actual CPU features! */ +- +- printk(KERN_DEBUG "CPU: After all inits, caps:"); +- for (i = 0; i < NCAPINTS; i++) +- printk(" %08lx", c->x86_capability[i]); +- printk("\n"); +- + /* + * On SMP, boot_cpu_data holds the common feature set between + * all CPUs; so make sure that we indicate which features are +@@ -508,8 +509,14 @@ static void __cpuinit identify_cpu(struc + boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; + } + ++ /* Clear all flags overriden by options */ ++ for (i = 0; i < NCAPINTS; i++) ++ c->x86_capability[i] &= ~cleared_cpu_caps[i]; ++ + /* Init Machine Check Exception if available. */ + mcheck_init(c); ++ ++ select_idle_routine(c); + } + + void __init identify_boot_cpu(void) +@@ -517,7 +524,6 @@ void __init identify_boot_cpu(void) + identify_cpu(&boot_cpu_data); + sysenter_setup(); + enable_sep_cpu(); +- mtrr_bp_init(); + } + + void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) +@@ -574,6 +580,13 @@ void __cpuinit detect_ht(struct cpuinfo_ + } + #endif + ++static __init int setup_noclflush(char *arg) ++{ ++ setup_clear_cpu_cap(X86_FEATURE_CLFLSH); ++ return 1; ++} ++__setup("noclflush", setup_noclflush); ++ + void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) + { + char *vendor = NULL; +@@ -597,6 +610,17 @@ void __cpuinit print_cpu_info(struct cpu + printk("\n"); + } + ++static __init int setup_disablecpuid(char *arg) ++{ ++ int bit; ++ if (get_option(&arg, &bit) && bit < NCAPINTS*32) ++ setup_clear_cpu_cap(bit); ++ else ++ return 0; ++ return 1; ++} ++__setup("clearcpuid=", setup_disablecpuid); ++ + cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; + + /* This is hacky. :) +@@ -606,16 +630,6 @@ cpumask_t cpu_initialized __cpuinitdata + * They will insert themselves into the cpu_devs structure. + * Then, when cpu_init() is called, we can just iterate over that array. + */ +- +-extern int intel_cpu_init(void); +-extern int cyrix_init_cpu(void); +-extern int nsc_init_cpu(void); +-extern int amd_init_cpu(void); +-extern int centaur_init_cpu(void); +-extern int transmeta_init_cpu(void); +-extern int nexgen_init_cpu(void); +-extern int umc_init_cpu(void); +- + void __init early_cpu_init(void) + { + intel_cpu_init(); +@@ -627,21 +641,13 @@ void __init early_cpu_init(void) + nexgen_init_cpu(); + umc_init_cpu(); + early_cpu_detect(); +- +-#ifdef CONFIG_DEBUG_PAGEALLOC +- /* pse is not compatible with on-the-fly unmapping, +- * disable it even if the cpus claim to support it. +- */ +- clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); +- disable_pse = 1; +-#endif + } + + /* Make sure %fs is initialized properly in idle threads */ +-struct pt_regs * __devinit idle_regs(struct pt_regs *regs) ++struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) + { + memset(regs, 0, sizeof(struct pt_regs)); +- regs->xfs = __KERNEL_PERCPU; ++ regs->fs = __KERNEL_PERCPU; + return regs; + } + +@@ -649,7 +655,7 @@ struct pt_regs * __devinit idle_regs(str + * it's on the real one. */ + void switch_to_new_gdt(void) + { +- struct Xgt_desc_struct gdt_descr; ++ struct desc_ptr gdt_descr; + unsigned long va, frames[16]; + int f; + +@@ -692,12 +698,6 @@ void __cpuinit cpu_init(void) + + if (cpu_has_vme || cpu_has_de) + clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); +- if (tsc_disable && cpu_has_tsc) { +- printk(KERN_NOTICE "Disabling TSC...\n"); +- /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ +- clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); +- set_in_cr4(X86_CR4_TSD); +- } + + switch_to_new_gdt(); + +@@ -710,7 +710,7 @@ void __cpuinit cpu_init(void) + BUG(); + enter_lazy_tlb(&init_mm, curr); + +- load_esp0(t, thread); ++ load_sp0(t, thread); + + load_LDT(&init_mm.context); + +--- sle11-2009-06-29.orig/arch/x86/kernel/cpu/mtrr/main-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/cpu/mtrr/main-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -33,7 +33,7 @@ struct mtrr_ops generic_mtrr_ops = { + + struct mtrr_ops *mtrr_if = &generic_mtrr_ops; + unsigned int num_var_ranges; +-unsigned int *usage_table; ++unsigned int mtrr_usage_table[MAX_VAR_RANGES]; + + static void __init set_num_var_ranges(void) + { +@@ -52,17 +52,12 @@ static void __init init_table(void) + int i, max; + + max = num_var_ranges; +- if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL)) +- == NULL) { +- printk(KERN_ERR "mtrr: could not allocate\n"); +- return; +- } + for (i = 0; i < max; i++) +- usage_table[i] = 0; ++ mtrr_usage_table[i] = 0; + } + + int mtrr_add_page(unsigned long base, unsigned long size, +- unsigned int type, char increment) ++ unsigned int type, bool increment) + { + int error; + struct xen_platform_op op; +@@ -81,7 +76,7 @@ int mtrr_add_page(unsigned long base, un + } + + if (increment) +- ++usage_table[op.u.add_memtype.reg]; ++ ++mtrr_usage_table[op.u.add_memtype.reg]; + + mutex_unlock(&mtrr_mutex); + +@@ -103,7 +98,7 @@ static int mtrr_check(unsigned long base + + int + mtrr_add(unsigned long base, unsigned long size, unsigned int type, +- char increment) ++ bool increment) + { + if (mtrr_check(base, size)) + return -EINVAL; +@@ -136,11 +131,11 @@ int mtrr_del_page(int reg, unsigned long + goto out; + } + } +- if (usage_table[reg] < 1) { ++ if (mtrr_usage_table[reg] < 1) { + printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); + goto out; + } +- if (--usage_table[reg] < 1) { ++ if (--mtrr_usage_table[reg] < 1) { + op.cmd = XENPF_del_memtype; + op.u.del_memtype.handle = 0; + op.u.del_memtype.reg = reg; +--- sle11-2009-06-29.orig/arch/x86/kernel/e820_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/e820_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -18,11 +17,6 @@ + #include + #include + +-#ifdef CONFIG_EFI +-int efi_enabled = 0; +-EXPORT_SYMBOL(efi_enabled); +-#endif +- + struct e820map e820; + struct change_member { + struct e820entry *pbios; /* pointer to original bios entry */ +@@ -38,26 +32,6 @@ unsigned long pci_mem_start = 0x10000000 + EXPORT_SYMBOL(pci_mem_start); + #endif + extern int user_defined_memmap; +-struct resource data_resource = { +- .name = "Kernel data", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; +- +-struct resource code_resource = { +- .name = "Kernel code", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; +- +-struct resource bss_resource = { +- .name = "Kernel bss", +- .start = 0, +- .end = 0, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; + + static struct resource system_rom_resource = { + .name = "System ROM", +@@ -112,60 +86,6 @@ static struct resource video_rom_resourc + .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM + }; + +-static struct resource video_ram_resource = { +- .name = "Video RAM area", +- .start = 0xa0000, +- .end = 0xbffff, +- .flags = IORESOURCE_BUSY | IORESOURCE_MEM +-}; +- +-static struct resource standard_io_resources[] = { { +- .name = "dma1", +- .start = 0x0000, +- .end = 0x001f, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "pic1", +- .start = 0x0020, +- .end = 0x0021, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "timer0", +- .start = 0x0040, +- .end = 0x0043, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "timer1", +- .start = 0x0050, +- .end = 0x0053, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "keyboard", +- .start = 0x0060, +- .end = 0x006f, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "dma page reg", +- .start = 0x0080, +- .end = 0x008f, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "pic2", +- .start = 0x00a0, +- .end = 0x00a1, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "dma2", +- .start = 0x00c0, +- .end = 0x00df, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-}, { +- .name = "fpu", +- .start = 0x00f0, +- .end = 0x00ff, +- .flags = IORESOURCE_BUSY | IORESOURCE_IO +-} }; +- + #define ROMSIGNATURE 0xaa55 + + static int __init romsignature(const unsigned char *rom) +@@ -272,10 +192,9 @@ static struct e820map machine_e820; + * Request address space for all standard RAM and ROM resources + * and also for regions reported as reserved by the e820. + */ +-static void __init +-legacy_init_iomem_resources(struct resource *code_resource, +- struct resource *data_resource, +- struct resource *bss_resource) ++void __init init_iomem_resources(struct resource *code_resource, ++ struct resource *data_resource, ++ struct resource *bss_resource) + { + int i; + +@@ -324,39 +243,6 @@ legacy_init_iomem_resources(struct resou + + #undef e820 + +-/* +- * Request address space for all standard resources +- * +- * This is called just before pcibios_init(), which is also a +- * subsys_initcall, but is linked in later (in arch/i386/pci/common.c). +- */ +-static int __init request_standard_resources(void) +-{ +- int i; +- +- /* Nothing to do if not running in dom0. */ +- if (!is_initial_xendomain()) +- return 0; +- +- printk("Setting up standard PCI resources\n"); +- if (efi_enabled) +- efi_initialize_iomem_resources(&code_resource, +- &data_resource, &bss_resource); +- else +- legacy_init_iomem_resources(&code_resource, +- &data_resource, &bss_resource); +- +- /* EFI systems may still have VGA */ +- request_resource(&iomem_resource, &video_ram_resource); +- +- /* request I/O space for devices used on all i[345]86 PCs */ +- for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) +- request_resource(&ioport_resource, &standard_io_resources[i]); +- return 0; +-} +- +-subsys_initcall(request_standard_resources); +- + #if defined(CONFIG_PM) && defined(CONFIG_HIBERNATION) + /** + * e820_mark_nosave_regions - Find the ranges of physical addresses that do not +@@ -393,19 +279,17 @@ void __init add_memory_region(unsigned l + { + int x; + +- if (!efi_enabled) { +- x = e820.nr_map; +- +- if (x == E820MAX) { +- printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); +- return; +- } ++ x = e820.nr_map; + +- e820.map[x].addr = start; +- e820.map[x].size = size; +- e820.map[x].type = type; +- e820.nr_map++; ++ if (x == E820MAX) { ++ printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); ++ return; + } ++ ++ e820.map[x].addr = start; ++ e820.map[x].size = size; ++ e820.map[x].type = type; ++ e820.nr_map++; + } /* add_memory_region */ + + /* +@@ -642,29 +526,6 @@ int __init copy_e820_map(struct e820entr + } + + /* +- * Callback for efi_memory_walk. +- */ +-static int __init +-efi_find_max_pfn(unsigned long start, unsigned long end, void *arg) +-{ +- unsigned long *max_pfn = arg, pfn; +- +- if (start < end) { +- pfn = PFN_UP(end -1); +- if (pfn > *max_pfn) +- *max_pfn = pfn; +- } +- return 0; +-} +- +-static int __init +-efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg) +-{ +- memory_present(0, PFN_UP(start), PFN_DOWN(end)); +- return 0; +-} +- +-/* + * Find the highest page frame number we have available + */ + void __init find_max_pfn(void) +@@ -672,11 +533,6 @@ void __init find_max_pfn(void) + int i; + + max_pfn = 0; +- if (efi_enabled) { +- efi_memmap_walk(efi_find_max_pfn, &max_pfn); +- efi_memmap_walk(efi_memory_present_wrapper, NULL); +- return; +- } + + for (i = 0; i < e820.nr_map; i++) { + unsigned long start, end; +@@ -694,34 +550,12 @@ void __init find_max_pfn(void) + } + + /* +- * Free all available memory for boot time allocation. Used +- * as a callback function by efi_memory_walk() +- */ +- +-static int __init +-free_available_memory(unsigned long start, unsigned long end, void *arg) +-{ +- /* check max_low_pfn */ +- if (start >= (max_low_pfn << PAGE_SHIFT)) +- return 0; +- if (end >= (max_low_pfn << PAGE_SHIFT)) +- end = max_low_pfn << PAGE_SHIFT; +- if (start < end) +- free_bootmem(start, end - start); +- +- return 0; +-} +-/* + * Register fully available low RAM pages with the bootmem allocator. + */ + void __init register_bootmem_low_pages(unsigned long max_low_pfn) + { + int i; + +- if (efi_enabled) { +- efi_memmap_walk(free_available_memory, NULL); +- return; +- } + for (i = 0; i < e820.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + /* +@@ -855,56 +689,12 @@ void __init print_memory_map(char *who) + } + } + +-static __init __always_inline void efi_limit_regions(unsigned long long size) +-{ +- unsigned long long current_addr = 0; +- efi_memory_desc_t *md, *next_md; +- void *p, *p1; +- int i, j; +- +- j = 0; +- p1 = memmap.map; +- for (p = p1, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) { +- md = p; +- next_md = p1; +- current_addr = md->phys_addr + +- PFN_PHYS(md->num_pages); +- if (is_available_memory(md)) { +- if (md->phys_addr >= size) continue; +- memcpy(next_md, md, memmap.desc_size); +- if (current_addr >= size) { +- next_md->num_pages -= +- PFN_UP(current_addr-size); +- } +- p1 += memmap.desc_size; +- next_md = p1; +- j++; +- } else if ((md->attribute & EFI_MEMORY_RUNTIME) == +- EFI_MEMORY_RUNTIME) { +- /* In order to make runtime services +- * available we have to include runtime +- * memory regions in memory map */ +- memcpy(next_md, md, memmap.desc_size); +- p1 += memmap.desc_size; +- next_md = p1; +- j++; +- } +- } +- memmap.nr_map = j; +- memmap.map_end = memmap.map + +- (memmap.nr_map * memmap.desc_size); +-} +- + void __init limit_regions(unsigned long long size) + { + unsigned long long current_addr = 0; + int i; + + print_memory_map("limit_regions start"); +- if (efi_enabled) { +- efi_limit_regions(size); +- return; +- } + for (i = 0; i < e820.nr_map; i++) { + current_addr = e820.map[i].addr + e820.map[i].size; + if (current_addr < size) +@@ -1056,3 +846,44 @@ static int __init parse_memmap(char *arg + return 0; + } + early_param("memmap", parse_memmap); ++ ++#ifndef CONFIG_XEN ++void __init update_memory_range(u64 start, u64 size, unsigned old_type, ++ unsigned new_type) ++{ ++ int i; ++ ++ BUG_ON(old_type == new_type); ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ u64 final_start, final_end; ++ if (ei->type != old_type) ++ continue; ++ /* totally covered? */ ++ if (ei->addr >= start && ei->size <= size) { ++ ei->type = new_type; ++ continue; ++ } ++ /* partially covered */ ++ final_start = max(start, ei->addr); ++ final_end = min(start + size, ei->addr + ei->size); ++ if (final_start >= final_end) ++ continue; ++ add_memory_region(final_start, final_end - final_start, ++ new_type); ++ } ++} ++ ++void __init update_e820(void) ++{ ++ u8 nr_map; ++ ++ nr_map = e820.nr_map; ++ if (sanitize_e820_map(e820.map, &nr_map)) ++ return; ++ e820.nr_map = nr_map; ++ printk(KERN_INFO "modified physical RAM map:\n"); ++ print_memory_map("modified"); ++} ++#endif +--- sle11-2009-06-29.orig/arch/x86/kernel/e820_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/e820_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -1,4 +1,4 @@ +-/* ++/* + * Handle the memory map. + * The functions here do the job until bootmem takes over. + * +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + + struct e820map e820 __initdata; +@@ -33,96 +34,103 @@ struct e820map e820 __initdata; + struct e820map machine_e820; + #endif + +-/* ++/* + * PFN of last memory page. + */ +-unsigned long end_pfn; +-EXPORT_SYMBOL(end_pfn); ++unsigned long end_pfn; + +-/* ++/* + * end_pfn only includes RAM, while end_pfn_map includes all e820 entries. + * The direct mapping extends to end_pfn_map, so that we can directly access + * apertures, ACPI and other tables without having to play with fixmaps. +- */ +-unsigned long end_pfn_map; ++ */ ++unsigned long end_pfn_map; + +-/* ++/* + * Last pfn which the user wants to use. + */ + static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; + +-extern struct resource code_resource, data_resource, bss_resource; +- +-/* Check for some hardcoded bad areas that early boot is not allowed to touch */ +-static inline int bad_addr(unsigned long *addrp, unsigned long size) +-{ +- unsigned long addr = *addrp, last = addr + size; ++/* ++ * Early reserved memory areas. ++ */ ++#define MAX_EARLY_RES 20 + ++struct early_res { ++ unsigned long start, end; ++ char name[16]; ++}; ++static struct early_res early_res[MAX_EARLY_RES] __initdata = { + #ifndef CONFIG_XEN +- /* various gunk below that needed for SMP startup */ +- if (addr < 0x8000) { +- *addrp = PAGE_ALIGN(0x8000); +- return 1; +- } +- +- /* direct mapping tables of the kernel */ +- if (last >= table_start<= ramdisk_image && addr < ramdisk_end) { +- *addrp = PAGE_ALIGN(ramdisk_end); +- return 1; +- } +- } ++ { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ ++#ifdef CONFIG_SMP ++ { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE, "SMP_TRAMPOLINE" }, + #endif +- /* kernel code */ +- if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) { +- *addrp = PAGE_ALIGN(__pa_symbol(&_end)); +- return 1; +- } ++#endif ++ {} ++}; + +- if (last >= ebda_addr && addr < ebda_addr + ebda_size) { +- *addrp = PAGE_ALIGN(ebda_addr + ebda_size); +- return 1; ++void __init reserve_early(unsigned long start, unsigned long end, char *name) ++{ ++ int i; ++ struct early_res *r; ++ for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { ++ r = &early_res[i]; ++ if (end > r->start && start < r->end) ++ panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n", ++ start, end - 1, name?name:"", r->start, r->end - 1, r->name); + } ++ if (i >= MAX_EARLY_RES) ++ panic("Too many early reservations"); ++ r = &early_res[i]; ++ r->start = start; ++ r->end = end; ++ if (name) ++ strncpy(r->name, name, sizeof(r->name) - 1); ++} + +-#ifdef CONFIG_NUMA +- /* NUMA memory to node map */ +- if (last >= nodemap_addr && addr < nodemap_addr + nodemap_size) { +- *addrp = nodemap_addr + nodemap_size; +- return 1; ++void __init early_res_to_bootmem(void) ++{ ++ int i; ++ for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) { ++ struct early_res *r = &early_res[i]; ++ printk(KERN_INFO "early res: %d [%lx-%lx] %s\n", i, ++ r->start, r->end - 1, r->name); ++ reserve_bootmem_generic(r->start, r->end - r->start); + } +-#endif +- /* XXX ramdisk image here? */ +-#else +- if (last < (table_end<= r->start && addr < r->end) { ++ *addrp = addr = r->end; ++ changed = 1; ++ goto again; ++ } + } +-#endif +- return 0; +-} ++ return changed; ++} + + /* + * This function checks if any part of the range is mapped + * with type. + */ +-int e820_any_mapped(unsigned long start, unsigned long end, unsigned type) +-{ ++int ++e820_any_mapped(unsigned long start, unsigned long end, unsigned type) ++{ + int i; + + #ifndef CONFIG_XEN +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; + #else + if (!is_initial_xendomain()) + return 0; +@@ -130,12 +138,12 @@ int e820_any_mapped(unsigned long start, + const struct e820entry *ei = &machine_e820.map[i]; + #endif + +- if (type && ei->type != type) ++ if (type && ei->type != type) + continue; + if (ei->addr >= end || ei->addr + ei->size <= start) +- continue; +- return 1; +- } ++ continue; ++ return 1; ++ } + return 0; + } + EXPORT_SYMBOL_GPL(e820_any_mapped); +@@ -146,7 +154,8 @@ EXPORT_SYMBOL_GPL(e820_any_mapped); + * Note: this function only works correct if the e820 table is sorted and + * not-overlapping, which is the case + */ +-int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type) ++int __init e820_all_mapped(unsigned long start, unsigned long end, ++ unsigned type) + { + int i; + +@@ -171,65 +180,77 @@ int __init e820_all_mapped(unsigned long + */ + if (ei->addr <= start) + start = ei->addr + ei->size; +- /* if start is now at or beyond end, we're done, full coverage */ ++ /* ++ * if start is now at or beyond end, we're done, full ++ * coverage ++ */ + if (start >= end) +- return 1; /* we're done */ ++ return 1; + } + return 0; + } + +-/* +- * Find a free area in a specific range. +- */ +-unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) +-{ +- int i; +- for (i = 0; i < e820.nr_map; i++) { +- struct e820entry *ei = &e820.map[i]; +- unsigned long addr = ei->addr, last; +- if (ei->type != E820_RAM) +- continue; +- if (addr < start) ++/* ++ * Find a free area with specified alignment in a specific range. ++ */ ++unsigned long __init find_e820_area(unsigned long start, unsigned long end, ++ unsigned size, unsigned long align) ++{ ++ int i; ++ unsigned long mask = ~(align - 1); ++ ++ for (i = 0; i < e820.nr_map; i++) { ++ struct e820entry *ei = &e820.map[i]; ++ unsigned long addr = ei->addr, last; ++ ++ if (ei->type != E820_RAM) ++ continue; ++ if (addr < start) + addr = start; +- if (addr > ei->addr + ei->size) +- continue; ++ if (addr > ei->addr + ei->size) ++ continue; + while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size) + ; +- last = PAGE_ALIGN(addr) + size; ++ addr = (addr + align - 1) & mask; ++ last = addr + size; + if (last > ei->addr + ei->size) + continue; +- if (last > end) ++ if (last > end) + continue; +- return addr; +- } +- return -1UL; +-} ++ return addr; ++ } ++ return -1UL; ++} + + /* + * Find the highest page frame number we have available + */ + unsigned long __init e820_end_of_ram(void) + { +- unsigned long end_pfn = 0; ++ unsigned long end_pfn; ++ + end_pfn = find_max_pfn_with_active_regions(); +- +- if (end_pfn > end_pfn_map) ++ ++ if (end_pfn > end_pfn_map) + end_pfn_map = end_pfn; + if (end_pfn_map > MAXMEM>>PAGE_SHIFT) + end_pfn_map = MAXMEM>>PAGE_SHIFT; + if (end_pfn > end_user_pfn) + end_pfn = end_user_pfn; +- if (end_pfn > end_pfn_map) +- end_pfn = end_pfn_map; ++ if (end_pfn > end_pfn_map) ++ end_pfn = end_pfn_map; + +- printk("end_pfn_map = %lu\n", end_pfn_map); +- return end_pfn; ++ printk(KERN_INFO "end_pfn_map = %lu\n", end_pfn_map); ++ return end_pfn; + } + + /* + * Mark e820 reserved areas as busy for the resource manager. + */ +-void __init e820_reserve_resources(struct e820entry *e820, int nr_map) ++void __init e820_reserve_resources(struct e820entry *e820, int nr_map, ++ struct resource *code_resource, ++ struct resource *data_resource, ++ struct resource *bss_resource) + { + int i; + for (i = 0; i < nr_map; i++) { +@@ -247,14 +268,14 @@ void __init e820_reserve_resources(struc + request_resource(&iomem_resource, res); + if (e820[i].type == E820_RAM) { + /* +- * We don't know which RAM region contains kernel data, +- * so we try it repeatedly and let the resource manager +- * test it. ++ * We don't know which RAM region contains kernel data, ++ * so we try it repeatedly and let the resource manager ++ * test it. + */ + #ifndef CONFIG_XEN +- request_resource(res, &code_resource); +- request_resource(res, &data_resource); +- request_resource(res, &bss_resource); ++ request_resource(res, code_resource); ++ request_resource(res, data_resource); ++ request_resource(res, bss_resource); + #endif + #ifdef CONFIG_KEXEC + if (crashk_res.start != crashk_res.end) +@@ -357,9 +378,9 @@ e820_register_active_regions(int nid, un + add_active_range(nid, ei_startpfn, ei_endpfn); + } + +-/* ++/* + * Add a memory region to the kernel e820 map. +- */ ++ */ + void __init add_memory_region(unsigned long start, unsigned long size, int type) + { + int x = e820.nr_map; +@@ -384,9 +405,7 @@ unsigned long __init e820_hole_size(unsi + { + unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long end_pfn = end >> PAGE_SHIFT; +- unsigned long ei_startpfn; +- unsigned long ei_endpfn; +- unsigned long ram = 0; ++ unsigned long ei_startpfn, ei_endpfn, ram = 0; + int i; + + for (i = 0; i < e820.nr_map; i++) { +@@ -398,28 +417,31 @@ unsigned long __init e820_hole_size(unsi + return end - start - (ram << PAGE_SHIFT); + } + +-void __init e820_print_map(char *who) ++static void __init e820_print_map(char *who) + { + int i; + + for (i = 0; i < e820.nr_map; i++) { + printk(KERN_INFO " %s: %016Lx - %016Lx ", who, +- (unsigned long long) e820.map[i].addr, +- (unsigned long long) (e820.map[i].addr + e820.map[i].size)); ++ (unsigned long long) e820.map[i].addr, ++ (unsigned long long) ++ (e820.map[i].addr + e820.map[i].size)); + switch (e820.map[i].type) { +- case E820_RAM: printk("(usable)\n"); +- break; ++ case E820_RAM: ++ printk(KERN_CONT "(usable)\n"); ++ break; + case E820_RESERVED: +- printk("(reserved)\n"); +- break; ++ printk(KERN_CONT "(reserved)\n"); ++ break; + case E820_ACPI: +- printk("(ACPI data)\n"); +- break; ++ printk(KERN_CONT "(ACPI data)\n"); ++ break; + case E820_NVS: +- printk("(ACPI NVS)\n"); +- break; +- default: printk("type %u\n", e820.map[i].type); +- break; ++ printk(KERN_CONT "(ACPI NVS)\n"); ++ break; ++ default: ++ printk(KERN_CONT "type %u\n", e820.map[i].type); ++ break; + } + } + } +@@ -427,11 +449,11 @@ void __init e820_print_map(char *who) + /* + * Sanitize the BIOS e820 map. + * +- * Some e820 responses include overlapping entries. The following ++ * Some e820 responses include overlapping entries. The following + * replaces the original e820 map with a new one, removing overlaps. + * + */ +-static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) ++static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map) + { + struct change_member { + struct e820entry *pbios; /* pointer to original bios entry */ +@@ -451,7 +473,8 @@ static int __init sanitize_e820_map(stru + int i; + + /* +- Visually we're performing the following (1,2,3,4 = memory types)... ++ Visually we're performing the following ++ (1,2,3,4 = memory types)... + + Sample memory map (w/overlaps): + ____22__________________ +@@ -493,22 +516,23 @@ static int __init sanitize_e820_map(stru + old_nr = *pnr_map; + + /* bail out if we find any unreasonable addresses in bios map */ +- for (i=0; iaddr = biosmap[i].addr; + change_point[chgidx++]->pbios = &biosmap[i]; +- change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; ++ change_point[chgidx]->addr = biosmap[i].addr + ++ biosmap[i].size; + change_point[chgidx++]->pbios = &biosmap[i]; + } + } +@@ -518,75 +542,106 @@ static int __init sanitize_e820_map(stru + still_changing = 1; + while (still_changing) { + still_changing = 0; +- for (i=1; i < chg_nr; i++) { +- /* if > , swap */ +- /* or, if current= & last=, swap */ +- if ((change_point[i]->addr < change_point[i-1]->addr) || +- ((change_point[i]->addr == change_point[i-1]->addr) && +- (change_point[i]->addr == change_point[i]->pbios->addr) && +- (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) +- ) +- { ++ for (i = 1; i < chg_nr; i++) { ++ unsigned long long curaddr, lastaddr; ++ unsigned long long curpbaddr, lastpbaddr; ++ ++ curaddr = change_point[i]->addr; ++ lastaddr = change_point[i - 1]->addr; ++ curpbaddr = change_point[i]->pbios->addr; ++ lastpbaddr = change_point[i - 1]->pbios->addr; ++ ++ /* ++ * swap entries, when: ++ * ++ * curaddr > lastaddr or ++ * curaddr == lastaddr and curaddr == curpbaddr and ++ * lastaddr != lastpbaddr ++ */ ++ if (curaddr < lastaddr || ++ (curaddr == lastaddr && curaddr == curpbaddr && ++ lastaddr != lastpbaddr)) { + change_tmp = change_point[i]; + change_point[i] = change_point[i-1]; + change_point[i-1] = change_tmp; +- still_changing=1; ++ still_changing = 1; + } + } + } + + /* create a new bios memory map, removing overlaps */ +- overlap_entries=0; /* number of entries in the overlap table */ +- new_bios_entry=0; /* index for creating new bios map entries */ ++ overlap_entries = 0; /* number of entries in the overlap table */ ++ new_bios_entry = 0; /* index for creating new bios map entries */ + last_type = 0; /* start with undefined memory type */ + last_addr = 0; /* start with 0 as last starting address */ ++ + /* loop through change-points, determining affect on the new bios map */ +- for (chgidx=0; chgidx < chg_nr; chgidx++) +- { ++ for (chgidx = 0; chgidx < chg_nr; chgidx++) { + /* keep track of all overlapping bios entries */ +- if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) +- { +- /* add map entry to overlap list (> 1 entry implies an overlap) */ +- overlap_list[overlap_entries++]=change_point[chgidx]->pbios; +- } +- else +- { +- /* remove entry from list (order independent, so swap with last) */ +- for (i=0; ipbios) +- overlap_list[i] = overlap_list[overlap_entries-1]; ++ if (change_point[chgidx]->addr == ++ change_point[chgidx]->pbios->addr) { ++ /* ++ * add map entry to overlap list (> 1 entry ++ * implies an overlap) ++ */ ++ overlap_list[overlap_entries++] = ++ change_point[chgidx]->pbios; ++ } else { ++ /* ++ * remove entry from list (order independent, ++ * so swap with last) ++ */ ++ for (i = 0; i < overlap_entries; i++) { ++ if (overlap_list[i] == ++ change_point[chgidx]->pbios) ++ overlap_list[i] = ++ overlap_list[overlap_entries-1]; + } + overlap_entries--; + } +- /* if there are overlapping entries, decide which "type" to use */ +- /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ ++ /* ++ * if there are overlapping entries, decide which ++ * "type" to use (larger value takes precedence -- ++ * 1=usable, 2,3,4,4+=unusable) ++ */ + current_type = 0; +- for (i=0; itype > current_type) + current_type = overlap_list[i]->type; +- /* continue building up new bios map based on this information */ ++ /* ++ * continue building up new bios map based on this ++ * information ++ */ + if (current_type != last_type) { + if (last_type != 0) { + new_bios[new_bios_entry].size = + change_point[chgidx]->addr - last_addr; +- /* move forward only if the new size was non-zero */ ++ /* ++ * move forward only if the new size ++ * was non-zero ++ */ + if (new_bios[new_bios_entry].size != 0) ++ /* ++ * no more space left for new ++ * bios entries ? ++ */ + if (++new_bios_entry >= E820MAX) +- break; /* no more space left for new bios entries */ ++ break; + } + if (current_type != 0) { +- new_bios[new_bios_entry].addr = change_point[chgidx]->addr; ++ new_bios[new_bios_entry].addr = ++ change_point[chgidx]->addr; + new_bios[new_bios_entry].type = current_type; +- last_addr=change_point[chgidx]->addr; ++ last_addr = change_point[chgidx]->addr; + } + last_type = current_type; + } + } +- new_nr = new_bios_entry; /* retain count for new bios entries */ ++ /* retain count for new bios entries */ ++ new_nr = new_bios_entry; + + /* copy new bios mapping into original location */ +- memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); ++ memcpy(biosmap, new_bios, new_nr * sizeof(struct e820entry)); + *pnr_map = new_nr; + + return 0; +@@ -601,7 +656,7 @@ static int __init sanitize_e820_map(stru + * will have given us a memory map that we can use to properly + * set up memory. If we aren't, we'll fake a memory map. + */ +-static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) ++static int __init copy_e820_map(struct e820entry *biosmap, int nr_map) + { + #ifndef CONFIG_XEN + /* Only one memory region (or negative)? Ignore it */ +@@ -622,7 +677,7 @@ static int __init copy_e820_map(struct e + return -1; + + add_memory_region(start, size, type); +- } while (biosmap++,--nr_map); ++ } while (biosmap++, --nr_map); + + #ifdef CONFIG_XEN + if (is_initial_xendomain()) { +@@ -641,15 +696,17 @@ static int __init copy_e820_map(struct e + return 0; + } + +-void early_panic(char *msg) ++static void early_panic(char *msg) + { + early_printk(msg); + panic(msg); + } + +-#ifndef CONFIG_XEN +-void __init setup_memory_region(void) ++/* We're not void only for x86 32-bit compat */ ++char * __init machine_specific_memory_setup(void) + { ++#ifndef CONFIG_XEN ++ char *who = "BIOS-e820"; + /* + * Try to copy the BIOS-supplied E820-map. + * +@@ -659,14 +716,8 @@ void __init setup_memory_region(void) + sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries); + if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0) + early_panic("Cannot find a valid memory map"); +- printk(KERN_INFO "BIOS-provided physical RAM map:\n"); +- e820_print_map("BIOS-e820"); +-} +- + #else /* CONFIG_XEN */ +- +-void __init setup_memory_region(void) +-{ ++ char *who = "Xen"; + int rc; + struct xen_memory_map memmap; + /* +@@ -694,11 +745,13 @@ void __init setup_memory_region(void) + + if (copy_e820_map(map, (char)memmap.nr_entries) < 0) + early_panic("Cannot find a valid memory map"); +- ++#endif + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); +- e820_print_map("Xen"); ++ e820_print_map(who); ++ ++ /* In case someone cares... */ ++ return who; + } +-#endif + + static int __init parse_memopt(char *p) + { +@@ -709,7 +762,7 @@ static int __init parse_memopt(char *p) + if (!p) + return -EINVAL; + end_user_pfn = memparse(p, &p); +- end_user_pfn >>= PAGE_SHIFT; ++ end_user_pfn >>= PAGE_SHIFT; + + end = end_user_pfn<type != old_type) ++ continue; ++ /* totally covered? */ ++ if (ei->addr >= start && ei->size <= size) { ++ ei->type = new_type; ++ continue; ++ } ++ /* partially covered */ ++ final_start = max(start, ei->addr); ++ final_end = min(start + size, ei->addr + ei->size); ++ if (final_start >= final_end) ++ continue; ++ add_memory_region(final_start, final_end - final_start, ++ new_type); ++ } ++} ++ ++void __init update_e820(void) ++{ ++ u8 nr_map; ++ ++ nr_map = e820.nr_map; ++ if (sanitize_e820_map(e820.map, &nr_map)) ++ return; ++ e820.nr_map = nr_map; ++ printk(KERN_INFO "modified physical RAM map:\n"); ++ e820_print_map("modified"); ++} ++#endif ++ + unsigned long pci_mem_start = 0xaeedbabe; + EXPORT_SYMBOL(pci_mem_start); + +@@ -825,8 +927,10 @@ __init void e820_setup_gap(struct e820en + + if (!found) { + gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024; +- printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n" +- KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n"); ++ printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit " ++ "address range\n" ++ KERN_ERR "PCI: Unassigned devices with 32bit resource " ++ "registers may break!\n"); + } + + /* +@@ -839,8 +943,9 @@ __init void e820_setup_gap(struct e820en + /* Fun with two's complement */ + pci_mem_start = (gapstart + round) & -round; + +- printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", +- pci_mem_start, gapstart, gapsize); ++ printk(KERN_INFO ++ "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", ++ pci_mem_start, gapstart, gapsize); + } + + int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) +--- sle11-2009-06-29.orig/arch/x86/kernel/early_printk-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/early_printk-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -222,7 +222,7 @@ static struct console simnow_console = { + }; + + /* Direct interface for emergencies */ +-struct console *early_console = &early_vga_console; ++static struct console *early_console = &early_vga_console; + static int early_console_initialized = 0; + + void early_printk(const char *fmt, ...) +--- sle11-2009-06-29.orig/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:18:18.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:18:32.000000000 +0200 +@@ -59,7 +59,7 @@ + * for paravirtualization. The following will never clobber any registers: + * INTERRUPT_RETURN (aka. "iret") + * GET_CR0_INTO_EAX (aka. "movl %cr0, %eax") +- * ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit"). ++ * ENABLE_INTERRUPTS_SYSCALL_RET (aka "sti; sysexit"). + * + * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must + * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY). +@@ -282,16 +282,21 @@ END(resume_kernel) + #endif + CFI_ENDPROC + ++ .macro test_tif ti_reg # system call tracing in operation / emulation ++ /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ ++ testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(\ti_reg) ++ .endm ++ + /* SYSENTER_RETURN points to after the "sysenter" instruction in + the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */ + + # sysenter call handler stub +-ENTRY(sysenter_entry) ++ENTRY(ia32_sysenter_target) + CFI_STARTPROC simple + CFI_SIGNAL_FRAME + CFI_DEF_CFA esp, 0 + CFI_REGISTER esp, ebp +- movl SYSENTER_stack_esp0(%esp),%esp ++ movl SYSENTER_stack_sp0(%esp),%esp + sysenter_past_esp: + /* + * No need to follow this irqs on/off section: the syscall +@@ -334,9 +339,7 @@ sysenter_past_esp: + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + GET_THREAD_INFO(%ebp) +- +- /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ +- testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) ++ test_tif %ebp + jnz syscall_trace_entry + cmpl $(nr_syscalls), %eax + jae syscall_badsys +@@ -354,7 +357,7 @@ sysenter_past_esp: + xorl %ebp,%ebp + TRACE_IRQS_ON + 1: mov PT_FS(%esp), %fs +- ENABLE_INTERRUPTS_SYSEXIT ++ ENABLE_INTERRUPTS_SYSCALL_RET + CFI_ENDPROC + .pushsection .fixup,"ax" + 2: movl $0,PT_FS(%esp) +@@ -363,10 +366,10 @@ sysenter_past_esp: + .align 4 + .long 1b,2b + .popsection +-ENDPROC(sysenter_entry) ++ENDPROC(ia32_sysenter_target) + + # pv sysenter call handler stub +-ENTRY(sysenter_entry_pv) ++ENTRY(ia32pv_sysenter_target) + RING0_INT_FRAME + movl $__USER_DS,16(%esp) + movl %ebp,12(%esp) +@@ -389,7 +392,7 @@ ENTRY(sysenter_entry_pv) + .previous + /* fall through */ + CFI_ENDPROC +-ENDPROC(sysenter_entry_pv) ++ENDPROC(ia32pv_sysenter_target) + + # system call handler stub + ENTRY(system_call) +@@ -398,9 +401,7 @@ ENTRY(system_call) + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + GET_THREAD_INFO(%ebp) +- # system call tracing in operation / emulation +- /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ +- testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) ++ test_tif %ebp + jnz syscall_trace_entry + cmpl $(nr_syscalls), %eax + jae syscall_badsys +@@ -452,7 +453,8 @@ restore_nocheck_notrace: + RESTORE_REGS + addl $4, %esp # skip orig_eax/error_code + CFI_ADJUST_CFA_OFFSET -4 +-1: INTERRUPT_RETURN ++irq_return: ++ INTERRUPT_RETURN + .section .fixup,"ax" + iret_exc: + pushl $0 # no error code +@@ -461,7 +463,7 @@ iret_exc: + .previous + .section __ex_table,"a" + .align 4 +- .long 1b,iret_exc ++ .long irq_return,iret_exc + .previous + + CFI_RESTORE_STATE +@@ -657,7 +659,7 @@ END(syscall_badsys) + * Build the entry stubs and pointer table with + * some assembler magic. + */ +-.data ++.section .rodata,"a" + ENTRY(interrupt) + .text + +@@ -963,7 +965,7 @@ END(device_not_available) + * that sets up the real kernel stack. Check here, since we can't + * allow the wrong stack to be used. + * +- * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have ++ * "SYSENTER_stack_sp0+12" is because the NMI/debug handler will have + * already pushed 3 words if it hits on the sysenter instruction: + * eflags, cs and eip. + * +@@ -975,7 +977,7 @@ END(device_not_available) + cmpw $__KERNEL_CS,4(%esp); \ + jne ok; \ + label: \ +- movl SYSENTER_stack_esp0+offset(%esp),%esp; \ ++ movl SYSENTER_stack_sp0+offset(%esp),%esp; \ + CFI_DEF_CFA esp, 0; \ + CFI_UNDEFINED eip; \ + pushfl; \ +@@ -990,7 +992,7 @@ label: \ + KPROBE_ENTRY(debug) + RING0_INT_FRAME + #ifndef CONFIG_XEN +- cmpl $sysenter_entry,(%esp) ++ cmpl $ia32_sysenter_target,(%esp) + jne debug_stack_correct + FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn) + debug_stack_correct: +@@ -1023,7 +1025,7 @@ KPROBE_ENTRY(nmi) + popl %eax + CFI_ADJUST_CFA_OFFSET -4 + je nmi_espfix_stack +- cmpl $sysenter_entry,(%esp) ++ cmpl $ia32_sysenter_target,(%esp) + je nmi_stack_fixup + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 +@@ -1036,7 +1038,7 @@ KPROBE_ENTRY(nmi) + popl %eax + CFI_ADJUST_CFA_OFFSET -4 + jae nmi_stack_correct +- cmpl $sysenter_entry,12(%esp) ++ cmpl $ia32_sysenter_target,12(%esp) + je nmi_debug_stack_check + nmi_stack_correct: + /* We have a RING0_INT_FRAME here */ +@@ -1089,12 +1091,8 @@ nmi_espfix_stack: + RESTORE_REGS + lss 12+4(%esp), %esp # back to espfix stack + CFI_ADJUST_CFA_OFFSET -24 +-1: INTERRUPT_RETURN ++ jmp irq_return + CFI_ENDPROC +-.section __ex_table,"a" +- .align 4 +- .long 1b,iret_exc +-.previous + #else + KPROBE_ENTRY(nmi) + RING0_INT_FRAME +@@ -1112,17 +1110,17 @@ KPROBE_END(nmi) + + #ifdef CONFIG_PARAVIRT + ENTRY(native_iret) +-1: iret ++ iret + .section __ex_table,"a" + .align 4 +- .long 1b,iret_exc ++ .long native_iret, iret_exc + .previous + END(native_iret) + +-ENTRY(native_irq_enable_sysexit) ++ENTRY(native_irq_enable_syscall_ret) + sti + sysexit +-END(native_irq_enable_sysexit) ++END(native_irq_enable_syscall_ret) + #endif + + KPROBE_ENTRY(int3) +@@ -1271,7 +1269,144 @@ ENTRY(kernel_thread_helper) + CFI_ENDPROC + ENDPROC(kernel_thread_helper) + ++#include ++ ++ # pv syscall call handler stub ++ENTRY(ia32pv_cstar_target) ++ RING0_INT_FRAME ++ movl $__USER_DS,16(%esp) ++ movl %ebp,%ecx ++ movl $__USER_CS,4(%esp) ++ movl 12(%esp),%ebp ++ pushl %eax # save orig_eax ++ CFI_ADJUST_CFA_OFFSET 4 ++/* ++ * Load the potential sixth argument from user stack. ++ * Careful about security. ++ */ ++ cmpl $__PAGE_OFFSET-4,%ebp ++ CFI_REMEMBER_STATE ++ ja cstar_fault ++1: movl (%ebp),%ebp ++.section __ex_table,"a" ++ .align 4 ++ .long 1b,cstar_fault ++.previous ++ SAVE_ALL ++ GET_THREAD_INFO(%ebp) ++ test_tif %ebp ++ jnz cstar_trace_entry ++ cmpl $nr_syscalls,%eax ++ jae cstar_badsys ++.Lcstar_call: ++ btl %eax,cstar_special ++ jc .Lcstar_special ++ call *cstar_call_table(,%eax,4) ++ movl %eax,PT_EAX(%esp) # store the return value ++.Lcstar_exit: ++ movl PT_ECX(%esp),%ecx ++ movl %ecx,PT_EBP(%esp) # put user EBP back in place ++ jmp syscall_exit ++.Lcstar_special: ++ movl PT_ECX(%esp),%ecx ++ movl %ecx,PT_EBP(%esp) # put user EBP back in place ++ jmp syscall_call ++cstar_set_tif: ++ movl $cstar_clear_tif,(%esp) # replace return address ++ LOCK_PREFIX ++ orl $_TIF_CSTAR,TI_flags(%ebp) ++ jmp *sys_call_table(,%eax,4) ++cstar_clear_tif: ++ movl %eax,PT_EAX(%esp) # store the return value ++ LOCK_PREFIX ++ andl $~_TIF_CSTAR,TI_flags(%ebp) ++ jmp .Lcstar_exit ++cstar_trace_entry: ++ movl $-ENOSYS,PT_EAX(%esp) ++ cmpl $nr_syscalls,%eax ++ jae 1f ++ btl %eax,cstar_special ++ jc .Lcstar_trace_special ++1: movl %esp,%eax ++ xorl %edx,%edx ++ LOCK_PREFIX ++ orl $_TIF_CSTAR,TI_flags(%ebp) ++ call do_syscall_trace ++ LOCK_PREFIX ++ andl $~_TIF_CSTAR,TI_flags(%ebp) ++ testl %eax,%eax ++ jne .Lcstar_resume # ret != 0 -> running under PTRACE_SYSEMU, ++ # so must skip actual syscall ++ movl PT_ORIG_EAX(%esp),%eax ++ cmpl $nr_syscalls,%eax ++ jb .Lcstar_call ++ jmp .Lcstar_exit ++.Lcstar_trace_special: ++ movl PT_ECX(%esp),%ecx ++ movl %esp,%eax ++ xorl %edx,%edx ++ movl %ecx,PT_EBP(%esp) # put user EBP back in place ++ call do_syscall_trace ++ testl %eax,%eax ++ jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, ++ # so must skip actual syscall ++ movl PT_ORIG_EAX(%esp),%eax ++ cmpl $nr_syscalls,%eax ++ jb syscall_call ++ jmp syscall_exit ++cstar_badsys: ++ movl $-ENOSYS,PT_EAX(%esp) ++.Lcstar_resume: ++ movl PT_ECX(%esp),%ecx ++ movl %ecx,PT_EBP(%esp) # put user EBP back in place ++ jmp resume_userspace ++ CFI_RESTORE_STATE ++cstar_fault: ++ movl $-EFAULT,%eax ++ SAVE_ALL ++ GET_THREAD_INFO(%ebp) ++ jmp .Lcstar_resume ++ CFI_ENDPROC ++ENDPROC(ia32pv_cstar_target) ++ ++ENTRY(cstar_ret_from_fork) ++ CFI_STARTPROC ++ movl PT_ECX(%esp),%ecx ++ GET_THREAD_INFO(%ebp) ++ movl %ecx,PT_EBP(%esp) # put user EBP back in place ++ LOCK_PREFIX ++ andl $~_TIF_CSTAR,TI_flags(%ebp) ++ jmp ret_from_fork ++ CFI_ENDPROC ++END(ret_from_fork) ++ + .section .rodata,"a" + #include "syscall_table_32.S" + + syscall_table_size=(.-sys_call_table) ++ ++#include ++cstar_special: ++nr=0 ++mask=0 ++.rept nr_syscalls+31 ++ .irp n, __NR_sigreturn, __NR_rt_sigreturn ++ .if nr == \n ++ mask = mask | (1 << (\n & 31)) ++ .endif ++ .endr ++ nr = nr + 1 ++ .if (nr & 31) == 0 ++ .long mask ++ mask = 0 ++ .endif ++.endr ++#define sys_call_table cstar_call_table ++#define sys_fork cstar_set_tif ++#define sys_clone cstar_set_tif ++#define sys_vfork cstar_set_tif ++#include "syscall_table_32.S" ++#undef sys_call_table ++#undef sys_fork ++#undef sys_clone ++#undef sys_vfork +--- sle11-2009-06-29.orig/arch/x86/kernel/entry_64-xen.S 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/entry_64-xen.S 2009-03-16 16:33:40.000000000 +0100 +@@ -54,17 +54,22 @@ + #include + #include + #include +-#include ++#include + #include + +-#include "xen_entry_64.S" +- + .code64 + + #ifndef CONFIG_PREEMPT + #define retint_kernel retint_restore_args + #endif + ++#ifdef CONFIG_PARAVIRT ++ENTRY(native_irq_enable_syscall_ret) ++ movq %gs:pda_oldrsp,%rsp ++ swapgs ++ sysretq ++#endif /* CONFIG_PARAVIRT */ ++ + + .macro TRACE_IRQS_IRETQ offset=ARGOFFSET + #ifdef CONFIG_TRACE_IRQFLAGS +@@ -277,7 +282,7 @@ ret_from_sys_call: + sysret_check: + LOCKDEP_SYS_EXIT + GET_THREAD_INFO(%rcx) +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + movl threadinfo_flags(%rcx),%edx + andl %edi,%edx +@@ -287,7 +292,7 @@ sysret_check: + * sysretq will re-enable interrupts: + */ + TRACE_IRQS_ON +- XEN_UNBLOCK_EVENTS(%rsi) ++ ENABLE_INTERRUPTS(CLBR_NONE) + RESTORE_ARGS 0,8,0 + HYPERVISOR_IRET VGCF_IN_SYSCALL + +@@ -298,7 +303,7 @@ sysret_careful: + bt $TIF_NEED_RESCHED,%edx + jnc sysret_signal + TRACE_IRQS_ON +- XEN_UNBLOCK_EVENTS(%rsi) ++ ENABLE_INTERRUPTS(CLBR_NONE) + pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 + call schedule +@@ -309,9 +314,8 @@ sysret_careful: + /* Handle a signal */ + sysret_signal: + TRACE_IRQS_ON +-/* sti */ +- XEN_UNBLOCK_EVENTS(%rsi) +- testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx ++ ENABLE_INTERRUPTS(CLBR_NONE) ++ testl $_TIF_DO_NOTIFY_MASK,%edx + jz 1f + + /* Really a signal */ +@@ -323,7 +327,7 @@ sysret_signal: + 1: movl $_TIF_NEED_RESCHED,%edi + /* Use IRET because user could have changed frame. This + works because ptregscall_common has called FIXUP_TOP_OF_STACK. */ +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + jmp int_with_check + +@@ -355,7 +359,7 @@ tracesys: + */ + .globl int_ret_from_sys_call + int_ret_from_sys_call: +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + testb $3,CS-ARGOFFSET(%rsp) + jnz 1f +@@ -381,22 +385,20 @@ int_careful: + bt $TIF_NEED_RESCHED,%edx + jnc int_very_careful + TRACE_IRQS_ON +-/* sti */ +- XEN_UNBLOCK_EVENTS(%rsi) ++ ENABLE_INTERRUPTS(CLBR_NONE) + pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 + call schedule + popq %rdi + CFI_ADJUST_CFA_OFFSET -8 +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + jmp int_with_check + + /* handle signals and tracing -- both require a full stack frame */ + int_very_careful: + TRACE_IRQS_ON +-/* sti */ +- XEN_UNBLOCK_EVENTS(%rsi) ++ ENABLE_INTERRUPTS(CLBR_NONE) + SAVE_REST + /* Check for syscall exit trace */ + testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx +@@ -411,7 +413,7 @@ int_very_careful: + jmp int_restore_rest + + int_signal: +- testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx ++ testl $_TIF_DO_NOTIFY_MASK,%edx + jz 1f + movq %rsp,%rdi # &ptregs -> arg1 + xorl %esi,%esi # oldset -> arg2 +@@ -419,7 +421,7 @@ int_signal: + 1: movl $_TIF_NEED_RESCHED,%edi + int_restore_rest: + RESTORE_REST +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + jmp int_with_check + CFI_ENDPROC +@@ -474,6 +476,7 @@ ENTRY(stub_execve) + CFI_REGISTER rip, r11 + SAVE_REST + FIXUP_TOP_OF_STACK %r11 ++ movq %rsp, %rcx + call sys_execve + RESTORE_TOP_OF_STACK %r11 + movq %rax,RAX(%rsp) +@@ -526,11 +529,10 @@ retint_check: + retint_restore_args: /* return to kernel space */ + movl EFLAGS-REST_SKIP(%rsp), %eax + shr $9, %eax # EAX[0] == IRET_EFLAGS.IF +- XEN_GET_VCPU_INFO(%rsi) ++ GET_VCPU_INFO + andb evtchn_upcall_mask(%rsi),%al + andb $1,%al # EAX[0] == IRET_EFLAGS.IF & event_mask + jnz restore_all_enable_events # != 0 => enable event delivery +- XEN_PUT_VCPU_INFO(%rsi) + + RESTORE_ARGS 0,8,0 + HYPERVISOR_IRET 0 +@@ -541,31 +543,29 @@ retint_careful: + bt $TIF_NEED_RESCHED,%edx + jnc retint_signal + TRACE_IRQS_ON +- XEN_UNBLOCK_EVENTS(%rsi) +-/* sti */ ++ ENABLE_INTERRUPTS(CLBR_NONE) + pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 + call schedule + popq %rdi + CFI_ADJUST_CFA_OFFSET -8 + GET_THREAD_INFO(%rcx) +- XEN_BLOCK_EVENTS(%rsi) +-/* cli */ ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + jmp retint_check + + retint_signal: +- testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx ++ testl $_TIF_DO_NOTIFY_MASK,%edx + jz retint_restore_args + TRACE_IRQS_ON +- XEN_UNBLOCK_EVENTS(%rsi) ++ ENABLE_INTERRUPTS(CLBR_NONE) + SAVE_REST + movq $-1,ORIG_RAX(%rsp) + xorl %esi,%esi # oldset + movq %rsp,%rdi # &pt_regs + call do_notify_resume + RESTORE_REST +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + movl $_TIF_NEED_RESCHED,%edi + GET_THREAD_INFO(%rcx) +@@ -702,7 +702,7 @@ END(spurious_interrupt) + rdmsr + testl %edx,%edx + js 1f +- swapgs ++ SWAPGS + xorl %ebx,%ebx + 1: + #endif +@@ -719,8 +719,7 @@ END(spurious_interrupt) + .if \ist + addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) + .endif +-/* cli */ +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + .if \irqtrace + TRACE_IRQS_OFF + .endif +@@ -749,10 +748,10 @@ paranoid_swapgs\trace: + .if \trace + TRACE_IRQS_IRETQ 0 + .endif +- swapgs ++ SWAPGS_UNSAFE_STACK + paranoid_restore\trace: + RESTORE_ALL 8 +- iretq ++ jmp irq_return + paranoid_userspace\trace: + GET_THREAD_INFO(%rcx) + movl threadinfo_flags(%rcx),%ebx +@@ -767,11 +766,11 @@ paranoid_userspace\trace: + .if \trace + TRACE_IRQS_ON + .endif +- sti ++ ENABLE_INTERRUPTS(CLBR_NONE) + xorl %esi,%esi /* arg2: oldset */ + movq %rsp,%rdi /* arg1: &pt_regs */ + call do_notify_resume +- cli ++ DISABLE_INTERRUPTS(CLBR_NONE) + .if \trace + TRACE_IRQS_OFF + .endif +@@ -780,9 +779,9 @@ paranoid_schedule\trace: + .if \trace + TRACE_IRQS_ON + .endif +- sti ++ ENABLE_INTERRUPTS(CLBR_ANY) + call schedule +- cli ++ DISABLE_INTERRUPTS(CLBR_ANY) + .if \trace + TRACE_IRQS_OFF + .endif +@@ -846,8 +845,7 @@ error_call_handler: + call *%rax + error_exit: + RESTORE_REST +-/* cli */ +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + GET_THREAD_INFO(%rcx) + testb $3,CS-ARGOFFSET(%rsp) +@@ -875,7 +873,7 @@ error_kernelspace: + iret run with kernel gs again, so don't set the user space flag. + B stepping K8s sometimes report an truncated RIP for IRET + exceptions returning to compat mode. Check for these here too. */ +- leaq iret_label(%rip),%rbp ++ leaq irq_return(%rip),%rbp + cmpq %rbp,RIP(%rsp) + je error_swapgs + movl %ebp,%ebp /* zero extend */ +@@ -930,19 +928,17 @@ END(do_hypervisor_callback) + restore_all_enable_events: + CFI_DEFAULT_STACK adj=1 + TRACE_IRQS_ON +- XEN_UNBLOCK_EVENTS(%rsi) # %rsi is already set up... ++ __ENABLE_INTERRUPTS + + scrit: /**** START OF CRITICAL REGION ****/ +- XEN_TEST_PENDING(%rsi) ++ __TEST_PENDING + CFI_REMEMBER_STATE + jnz 14f # process more events if necessary... +- XEN_PUT_VCPU_INFO(%rsi) + RESTORE_ARGS 0,8,0 + HYPERVISOR_IRET 0 + + CFI_RESTORE_STATE +-14: XEN_LOCKED_BLOCK_EVENTS(%rsi) +- XEN_PUT_VCPU_INFO(%rsi) ++14: __DISABLE_INTERRUPTS + SAVE_REST + movq %rsp,%rdi # set the argument again + jmp 11b +@@ -1086,15 +1082,16 @@ ENDPROC(child_rip) + * rdi: name, rsi: argv, rdx: envp + * + * We want to fallback into: +- * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs) ++ * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs) + * + * do_sys_execve asm fallback arguments: +- * rdi: name, rsi: argv, rdx: envp, fake frame on the stack ++ * rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack + */ + ENTRY(kernel_execve) + CFI_STARTPROC + FAKE_STACK_FRAME $0 + SAVE_ALL ++ movq %rsp,%rcx + call sys_execve + movq %rax, RAX(%rsp) + RESTORE_REST +@@ -1144,7 +1141,7 @@ do_nmi_callback: + call do_nmi + orl $NMI_MASK,EFLAGS(%rsp) + RESTORE_REST +- XEN_BLOCK_EVENTS(%rsi) ++ DISABLE_INTERRUPTS(CLBR_NONE) + TRACE_IRQS_OFF + GET_THREAD_INFO(%rcx) + jmp retint_restore_args +--- sle11-2009-06-29.orig/arch/x86/kernel/fixup.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/fixup.c 2009-03-16 16:33:40.000000000 +0100 +@@ -36,7 +36,7 @@ + + #define DP(_f, _args...) printk(KERN_ALERT " " _f "\n" , ## _args ) + +-fastcall void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) ++void do_fixup_4gb_segment(struct pt_regs *regs, long error_code) + { + static unsigned long printed = 0; + char info[100]; +--- sle11-2009-06-29.orig/arch/x86/kernel/genapic_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/genapic_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -24,20 +24,13 @@ + #include + #endif + +-/* +- * which logical CPU number maps to which CPU (physical APIC ID) +- * +- * The following static array is used during kernel startup +- * and the x86_cpu_to_apicid_ptr contains the address of the +- * array during this time. Is it zeroed when the per_cpu +- * data area is removed. +- */ ++/* which logical CPU number maps to which CPU (physical APIC ID) */ + #ifndef CONFIG_XEN +-u8 x86_cpu_to_apicid_init[NR_CPUS] __initdata ++u16 x86_cpu_to_apicid_init[NR_CPUS] __initdata + = { [0 ... NR_CPUS-1] = BAD_APICID }; +-void *x86_cpu_to_apicid_ptr; ++void *x86_cpu_to_apicid_early_ptr; + #endif +-DEFINE_PER_CPU(u8, x86_cpu_to_apicid) = BAD_APICID; ++DEFINE_PER_CPU(u16, x86_cpu_to_apicid) = BAD_APICID; + EXPORT_PER_CPU_SYMBOL(x86_cpu_to_apicid); + + #ifndef CONFIG_XEN +--- sle11-2009-06-29.orig/arch/x86/kernel/head64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/head64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -26,6 +27,8 @@ + #include + #include + #include ++#include ++#include + + unsigned long start_pfn; + +@@ -34,7 +37,7 @@ static void __init zap_identity_mappings + { + pgd_t *pgd = pgd_offset_k(0UL); + pgd_clear(pgd); +- __flush_tlb(); ++ __flush_tlb_all(); + } + + /* Don't add a printk in there. printk relies on the PDA which is not initialized +@@ -72,6 +75,37 @@ EXPORT_SYMBOL(machine_to_phys_mapping); + unsigned int machine_to_phys_order; + EXPORT_SYMBOL(machine_to_phys_order); + ++#define EBDA_ADDR_POINTER 0x40E ++ ++static __init void reserve_ebda(void) ++{ ++#ifndef CONFIG_XEN ++ unsigned ebda_addr, ebda_size; ++ ++ /* ++ * there is a real-mode segmented pointer pointing to the ++ * 4K EBDA area at 0x40E ++ */ ++ ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER); ++ ebda_addr <<= 4; ++ ++ if (!ebda_addr) ++ return; ++ ++ ebda_size = *(unsigned short *)__va(ebda_addr); ++ ++ /* Round EBDA up to pages */ ++ if (ebda_size == 0) ++ ebda_size = 1; ++ ebda_size <<= 10; ++ ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE); ++ if (ebda_size > 64*1024) ++ ebda_size = 64*1024; ++ ++ reserve_early(ebda_addr, ebda_addr + ebda_size, "EBDA"); ++#endif ++} ++ + void __init x86_64_start_kernel(char * real_mode_data) + { + struct xen_machphys_mapping mapping; +@@ -103,8 +137,16 @@ void __init x86_64_start_kernel(char * r + /* Make NULL pointers segfault */ + zap_identity_mappings(); + +- for (i = 0; i < IDT_ENTRIES; i++) ++ /* Cleanup the over mapped high alias */ ++ cleanup_highmap(); ++ ++ for (i = 0; i < IDT_ENTRIES; i++) { ++#ifdef CONFIG_EARLY_PRINTK ++ set_intr_gate(i, &early_idt_handlers[i]); ++#else + set_intr_gate(i, early_idt_handler); ++#endif ++ } + load_idt((const struct desc_ptr *)&idt_descr); + #endif + +@@ -115,8 +157,19 @@ void __init x86_64_start_kernel(char * r + + pda_init(0); + copy_bootdata(__va(real_mode_data)); +-#ifdef CONFIG_SMP +- cpu_set(0, cpu_online_map); +-#endif ++ ++ reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS"); ++ ++ reserve_early(round_up(__pa_symbol(&_end), PAGE_SIZE), ++ start_pfn << PAGE_SHIFT, "Xen provided"); ++ ++ reserve_ebda(); ++ ++ /* ++ * At this point everything still needed from the boot loader ++ * or BIOS or kernel text should be early reserved or marked not ++ * RAM in e820. All other memory is free game. ++ */ ++ + start_kernel(); + } +--- sle11-2009-06-29.orig/arch/x86/kernel/head_32-xen.S 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/head_32-xen.S 2009-03-16 16:33:40.000000000 +0100 +@@ -3,6 +3,7 @@ + .text + #include + #include ++#include + #include + #include + #include +@@ -88,7 +89,7 @@ ENTRY(_stext) + */ + .section ".bss.page_aligned","wa" + .align PAGE_SIZE_asm +-ENTRY(swapper_pg_pmd) ++ENTRY(swapper_pg_fixmap) + .fill 1024,4,0 + ENTRY(empty_zero_page) + .fill 4096,1,0 +--- sle11-2009-06-29.orig/arch/x86/kernel/init_task-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/init_task-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -19,7 +19,7 @@ static struct sighand_struct init_sighan + #endif + struct mm_struct init_mm = INIT_MM(init_mm); + #undef swapper_pg_dir +-EXPORT_SYMBOL(init_mm); ++EXPORT_UNUSED_SYMBOL(init_mm); /* will be removed in 2.6.26 */ + + /* + * Initial thread structure. +--- sle11-2009-06-29.orig/arch/x86/kernel/io_apic_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/io_apic_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include /* time_after() */ + + #include + #include +@@ -48,8 +49,6 @@ + #include + #include + +-#include "io_ports.h" +- + #ifdef CONFIG_XEN + #include + #include +@@ -400,7 +399,7 @@ static void set_ioapic_affinity_irq(unsi + # include /* kernel_thread() */ + # include /* kstat */ + # include /* kmalloc() */ +-# include /* time_after() */ ++# include + + #define IRQBALANCE_CHECK_ARCH -999 + #define MAX_BALANCED_IRQ_INTERVAL (5*HZ) +@@ -777,7 +776,7 @@ late_initcall(balanced_irq_init); + #endif + + #ifndef CONFIG_SMP +-void fastcall send_IPI_self(int vector) ++void send_IPI_self(int vector) + { + #ifndef CONFIG_XEN + unsigned int cfg; +@@ -1959,7 +1958,7 @@ static int __init timer_irq_works(void) + * might have cached one ExtINT interrupt. Finally, at + * least one tick may be lost due to delays. + */ +- if (jiffies - t1 > 4) ++ if (time_after(jiffies, t1 + 4)) + return 1; + + return 0; +@@ -2142,7 +2141,7 @@ static struct irq_chip lapic_chip __read + .eoi = ack_apic, + }; + +-static void setup_nmi (void) ++static void __init setup_nmi(void) + { + /* + * Dirty trick to enable the NMI watchdog ... +@@ -2155,7 +2154,7 @@ static void setup_nmi (void) + */ + apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); + +- on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); ++ enable_NMI_through_LVT0(); + + apic_printk(APIC_VERBOSE, " done.\n"); + } +@@ -2479,7 +2478,7 @@ static int ioapic_resume(struct sys_devi + } + + static struct sysdev_class ioapic_sysdev_class = { +- set_kset_name("ioapic"), ++ .name = "ioapic", + .suspend = ioapic_suspend, + .resume = ioapic_resume, + }; +--- sle11-2009-06-29.orig/arch/x86/kernel/io_apic_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/io_apic_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -32,9 +32,11 @@ + #include + #include + #include ++#include + #ifdef CONFIG_ACPI + #include + #endif ++#include + + #include + #include +@@ -1064,7 +1066,7 @@ void __apicdebuginit print_local_APIC(vo + v = apic_read(APIC_LVR); + printk(KERN_INFO "... APIC VERSION: %08x\n", v); + ver = GET_APIC_VERSION(v); +- maxlvt = get_maxlvt(); ++ maxlvt = lapic_get_maxlvt(); + + v = apic_read(APIC_TASKPRI); + printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); +@@ -1165,7 +1167,7 @@ void __apicdebuginit print_PIC(void) + } + #endif /* !CONFIG_XEN */ + +-static void __init enable_IO_APIC(void) ++void __init enable_IO_APIC(void) + { + union IO_APIC_reg_01 reg_01; + #ifndef CONFIG_XEN +@@ -1299,7 +1301,7 @@ static int __init timer_irq_works(void) + */ + + /* jiffies wrap? */ +- if (jiffies - t1 > 4) ++ if (time_after(jiffies, t1 + 4)) + return 1; + return 0; + } +@@ -1412,7 +1414,7 @@ static void irq_complete_move(unsigned i + if (likely(!cfg->move_in_progress)) + return; + +- vector = ~get_irq_regs()->orig_rax; ++ vector = ~get_irq_regs()->orig_ax; + me = smp_processor_id(); + if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) { + cpumask_t cleanup_mask; +@@ -1439,7 +1441,7 @@ static void ack_apic_level(unsigned int + int do_unmask_irq = 0; + + irq_complete_move(irq); +-#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) ++#ifdef CONFIG_GENERIC_PENDING_IRQ + /* If we are moving the irq we need to mask it */ + if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { + do_unmask_irq = 1; +@@ -1570,7 +1572,7 @@ static struct hw_interrupt_type lapic_ir + .end = end_lapic_irq, + }; + +-static void setup_nmi (void) ++static void __init setup_nmi(void) + { + /* + * Dirty trick to enable the NMI watchdog ... +@@ -1583,7 +1585,7 @@ static void setup_nmi (void) + */ + printk(KERN_INFO "activating NMI Watchdog ..."); + +- enable_NMI_through_LVT0(NULL); ++ enable_NMI_through_LVT0(); + + printk(" done.\n"); + } +@@ -1659,7 +1661,7 @@ static inline void unlock_ExtINT_logic(v + * + * FIXME: really need to revamp this for modern platforms only. + */ +-static inline void check_timer(void) ++static inline void __init check_timer(void) + { + struct irq_cfg *cfg = irq_cfg + 0; + int apic1, pin1, apic2, pin2; +@@ -1863,7 +1865,7 @@ static int ioapic_resume(struct sys_devi + } + + static struct sysdev_class ioapic_sysdev_class = { +- set_kset_name("ioapic"), ++ .name = "ioapic", + .suspend = ioapic_suspend, + .resume = ioapic_resume, + }; +@@ -2303,5 +2305,93 @@ void __init setup_ioapic_dest(void) + } + } + #endif +-#endif /* !CONFIG_XEN */ + ++#define IOAPIC_RESOURCE_NAME_SIZE 11 ++ ++static struct resource *ioapic_resources; ++ ++static struct resource * __init ioapic_setup_resources(void) ++{ ++ unsigned long n; ++ struct resource *res; ++ char *mem; ++ int i; ++ ++ if (nr_ioapics <= 0) ++ return NULL; ++ ++ n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource); ++ n *= nr_ioapics; ++ ++ mem = alloc_bootmem(n); ++ res = (void *)mem; ++ ++ if (mem != NULL) { ++ memset(mem, 0, n); ++ mem += sizeof(struct resource) * nr_ioapics; ++ ++ for (i = 0; i < nr_ioapics; i++) { ++ res[i].name = mem; ++ res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY; ++ sprintf(mem, "IOAPIC %u", i); ++ mem += IOAPIC_RESOURCE_NAME_SIZE; ++ } ++ } ++ ++ ioapic_resources = res; ++ ++ return res; ++} ++ ++void __init ioapic_init_mappings(void) ++{ ++ unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; ++ struct resource *ioapic_res; ++ int i; ++ ++ ioapic_res = ioapic_setup_resources(); ++ for (i = 0; i < nr_ioapics; i++) { ++ if (smp_found_config) { ++ ioapic_phys = mp_ioapics[i].mpc_apicaddr; ++ } else { ++ ioapic_phys = (unsigned long) ++ alloc_bootmem_pages(PAGE_SIZE); ++ ioapic_phys = __pa(ioapic_phys); ++ } ++ set_fixmap_nocache(idx, ioapic_phys); ++ apic_printk(APIC_VERBOSE, ++ "mapped IOAPIC to %016lx (%016lx)\n", ++ __fix_to_virt(idx), ioapic_phys); ++ idx++; ++ ++ if (ioapic_res != NULL) { ++ ioapic_res->start = ioapic_phys; ++ ioapic_res->end = ioapic_phys + (4 * 1024) - 1; ++ ioapic_res++; ++ } ++ } ++} ++ ++static int __init ioapic_insert_resources(void) ++{ ++ int i; ++ struct resource *r = ioapic_resources; ++ ++ if (!r) { ++ printk(KERN_ERR ++ "IO APIC resources could be not be allocated.\n"); ++ return -1; ++ } ++ ++ for (i = 0; i < nr_ioapics; i++) { ++ insert_resource(&iomem_resource, r); ++ r++; ++ } ++ ++ return 0; ++} ++ ++/* Insert the IO APIC resources after PCI initialization has occured to handle ++ * IO APICS that are mapped in on a BAR in PCI space. */ ++late_initcall(ioapic_insert_resources); ++#endif /* !CONFIG_XEN */ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/arch/x86/kernel/ioport-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -0,0 +1,112 @@ ++/* ++ * This contains the io-permission bitmap code - written by obz, with changes ++ * by Linus. 32/64 bits code unification by Miguel Botón. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ ++static void set_bitmap(unsigned long *bitmap, unsigned int base, ++ unsigned int extent, int new_value) ++{ ++ unsigned int i; ++ ++ for (i = base; i < base + extent; i++) { ++ if (new_value) ++ __set_bit(i, bitmap); ++ else ++ __clear_bit(i, bitmap); ++ } ++} ++ ++/* ++ * this changes the io permissions bitmap in the current task. ++ */ ++asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ++{ ++ struct thread_struct * t = ¤t->thread; ++ struct physdev_set_iobitmap set_iobitmap; ++ ++ if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) ++ return -EINVAL; ++ if (turn_on && !capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ ++ /* ++ * If it's the first ioperm() call in this thread's lifetime, set the ++ * IO bitmap up. ioperm() is much less timing critical than clone(), ++ * this is why we delay this operation until now: ++ */ ++ if (!t->io_bitmap_ptr) { ++ unsigned long *bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); ++ ++ if (!bitmap) ++ return -ENOMEM; ++ ++ memset(bitmap, 0xff, IO_BITMAP_BYTES); ++ t->io_bitmap_ptr = bitmap; ++ set_thread_flag(TIF_IO_BITMAP); ++ ++ set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); ++ set_iobitmap.nr_ports = IO_BITMAP_BITS; ++ WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, ++ &set_iobitmap)); ++ } ++ ++ set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); ++ ++ return 0; ++} ++ ++/* ++ * sys_iopl has to be used when you want to access the IO ports ++ * beyond the 0x3ff range: to get the full 65536 ports bitmapped ++ * you'd need 8kB of bitmaps/process, which is a bit excessive. ++ */ ++static int do_iopl(unsigned int level, struct thread_struct *t) ++{ ++ unsigned int old = t->iopl >> 12; ++ ++ if (level > 3) ++ return -EINVAL; ++ /* Trying to gain more privileges? */ ++ if (level > old) { ++ if (!capable(CAP_SYS_RAWIO)) ++ return -EPERM; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_X86_32 ++asmlinkage long sys_iopl(unsigned long regsp) ++{ ++ struct pt_regs *regs = (struct pt_regs *)®sp; ++ unsigned int level = regs->bx; ++#else ++asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs) ++{ ++#endif ++ struct thread_struct *t = ¤t->thread; ++ int rc; ++ ++ rc = do_iopl(level, t); ++ if (rc < 0) ++ goto out; ++ ++ t->iopl = level << 12; ++ set_iopl_mask(t->iopl); ++out: ++ return rc; ++} +--- sle11-2009-06-29.orig/arch/x86/kernel/ioport_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,121 +0,0 @@ +-/* +- * This contains the io-permission bitmap code - written by obz, with changes +- * by Linus. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +-static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) +-{ +- unsigned long mask; +- unsigned long *bitmap_base = bitmap + (base / BITS_PER_LONG); +- unsigned int low_index = base & (BITS_PER_LONG-1); +- int length = low_index + extent; +- +- if (low_index != 0) { +- mask = (~0UL << low_index); +- if (length < BITS_PER_LONG) +- mask &= ~(~0UL << length); +- if (new_value) +- *bitmap_base++ |= mask; +- else +- *bitmap_base++ &= ~mask; +- length -= BITS_PER_LONG; +- } +- +- mask = (new_value ? ~0UL : 0UL); +- while (length >= BITS_PER_LONG) { +- *bitmap_base++ = mask; +- length -= BITS_PER_LONG; +- } +- +- if (length > 0) { +- mask = ~(~0UL << length); +- if (new_value) +- *bitmap_base++ |= mask; +- else +- *bitmap_base++ &= ~mask; +- } +-} +- +- +-/* +- * this changes the io permissions bitmap in the current task. +- */ +-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) +-{ +- struct thread_struct * t = ¤t->thread; +- unsigned long *bitmap; +- struct physdev_set_iobitmap set_iobitmap; +- +- if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) +- return -EINVAL; +- if (turn_on && !capable(CAP_SYS_RAWIO)) +- return -EPERM; +- +- /* +- * If it's the first ioperm() call in this thread's lifetime, set the +- * IO bitmap up. ioperm() is much less timing critical than clone(), +- * this is why we delay this operation until now: +- */ +- if (!t->io_bitmap_ptr) { +- bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); +- if (!bitmap) +- return -ENOMEM; +- +- memset(bitmap, 0xff, IO_BITMAP_BYTES); +- t->io_bitmap_ptr = bitmap; +- set_thread_flag(TIF_IO_BITMAP); +- +- set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); +- set_iobitmap.nr_ports = IO_BITMAP_BITS; +- WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, +- &set_iobitmap)); +- } +- +- set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); +- +- return 0; +-} +- +-/* +- * sys_iopl has to be used when you want to access the IO ports +- * beyond the 0x3ff range: to get the full 65536 ports bitmapped +- * you'd need 8kB of bitmaps/process, which is a bit excessive. +- * +- * Here we just change the eflags value on the stack: we allow +- * only the super-user to do it. This depends on the stack-layout +- * on system-call entry - see also fork() and the signal handling +- * code. +- */ +- +-asmlinkage long sys_iopl(unsigned long unused) +-{ +- volatile struct pt_regs * regs = (struct pt_regs *) &unused; +- unsigned int level = regs->ebx; +- struct thread_struct *t = ¤t->thread; +- unsigned int old = (t->iopl >> 12) & 3; +- +- if (level > 3) +- return -EINVAL; +- /* Trying to gain more privileges? */ +- if (level > old) { +- if (!capable(CAP_SYS_RAWIO)) +- return -EPERM; +- } +- t->iopl = level << 12; +- set_iopl_mask(t->iopl); +- return 0; +-} +--- sle11-2009-06-29.orig/arch/x86/kernel/ioport_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,99 +0,0 @@ +-/* +- * This contains the io-permission bitmap code - written by obz, with changes +- * by Linus. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +-static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) +-{ +- int i; +- +- if (new_value) +- for (i = base; i < base + extent; i++) +- __set_bit(i, bitmap); +- else +- for (i = base; i < base + extent; i++) +- clear_bit(i, bitmap); +-} +- +-/* +- * this changes the io permissions bitmap in the current task. +- */ +-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) +-{ +- struct thread_struct * t = ¤t->thread; +- unsigned long *bitmap; +- struct physdev_set_iobitmap set_iobitmap; +- +- if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) +- return -EINVAL; +- if (turn_on && !capable(CAP_SYS_RAWIO)) +- return -EPERM; +- +- /* +- * If it's the first ioperm() call in this thread's lifetime, set the +- * IO bitmap up. ioperm() is much less timing critical than clone(), +- * this is why we delay this operation until now: +- */ +- if (!t->io_bitmap_ptr) { +- bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); +- if (!bitmap) +- return -ENOMEM; +- +- memset(bitmap, 0xff, IO_BITMAP_BYTES); +- t->io_bitmap_ptr = bitmap; +- set_thread_flag(TIF_IO_BITMAP); +- +- set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap); +- set_iobitmap.nr_ports = IO_BITMAP_BITS; +- WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, +- &set_iobitmap)); +- } +- +- set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); +- +- return 0; +-} +- +-/* +- * sys_iopl has to be used when you want to access the IO ports +- * beyond the 0x3ff range: to get the full 65536 ports bitmapped +- * you'd need 8kB of bitmaps/process, which is a bit excessive. +- * +- */ +- +-asmlinkage long sys_iopl(unsigned int new_iopl, struct pt_regs *regs) +-{ +- unsigned int old_iopl = current->thread.iopl; +- struct physdev_set_iopl set_iopl; +- +- if (new_iopl > 3) +- return -EINVAL; +- +- /* Need "raw I/O" privileges for direct port access. */ +- if ((new_iopl > old_iopl) && !capable(CAP_SYS_RAWIO)) +- return -EPERM; +- +- /* Change our version of the privilege levels. */ +- current->thread.iopl = new_iopl; +- +- /* Force the change at ring 0. */ +- set_iopl.iopl = (new_iopl == 0) ? 1 : new_iopl; +- WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl)); +- +- return 0; +-} +--- sle11-2009-06-29.orig/arch/x86/kernel/irq_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/irq_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -66,11 +66,11 @@ static union irq_ctx *softirq_ctx[NR_CPU + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +-fastcall unsigned int do_IRQ(struct pt_regs *regs) ++unsigned int do_IRQ(struct pt_regs *regs) + { + struct pt_regs *old_regs; + /* high bit used in ret_from_ code */ +- int irq = ~regs->orig_eax; ++ int irq = ~regs->orig_ax; + struct irq_desc *desc = irq_desc + irq; + #ifdef CONFIG_4KSTACKS + union irq_ctx *curctx, *irqctx; +@@ -88,13 +88,13 @@ fastcall unsigned int do_IRQ(struct pt_r + #ifdef CONFIG_DEBUG_STACKOVERFLOW + /* Debugging check for stack overflow: is there less than 1KB free? */ + { +- long esp; ++ long sp; + + __asm__ __volatile__("andl %%esp,%0" : +- "=r" (esp) : "0" (THREAD_SIZE - 1)); +- if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) { ++ "=r" (sp) : "0" (THREAD_SIZE - 1)); ++ if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { + printk("do_IRQ: stack overflow: %ld\n", +- esp - sizeof(struct thread_info)); ++ sp - sizeof(struct thread_info)); + dump_stack(); + } + } +@@ -112,7 +112,7 @@ fastcall unsigned int do_IRQ(struct pt_r + * current stack (which is the irq stack already after all) + */ + if (curctx != irqctx) { +- int arg1, arg2, ebx; ++ int arg1, arg2, bx; + + /* build the stack frame on the IRQ stack */ + isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); +@@ -128,10 +128,10 @@ fastcall unsigned int do_IRQ(struct pt_r + (curctx->tinfo.preempt_count & SOFTIRQ_MASK); + + asm volatile( +- " xchgl %%ebx,%%esp \n" +- " call *%%edi \n" +- " movl %%ebx,%%esp \n" +- : "=a" (arg1), "=d" (arg2), "=b" (ebx) ++ " xchgl %%ebx,%%esp \n" ++ " call *%%edi \n" ++ " movl %%ebx,%%esp \n" ++ : "=a" (arg1), "=d" (arg2), "=b" (bx) + : "0" (irq), "1" (desc), "2" (isp), + "D" (desc->handle_irq) + : "memory", "cc" +--- sle11-2009-06-29.orig/arch/x86/kernel/irq_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/irq_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -20,6 +20,28 @@ + + atomic_t irq_err_count; + ++/* ++ * 'what should we do if we get a hw irq event on an illegal vector'. ++ * each architecture has to answer this themselves. ++ */ ++void ack_bad_irq(unsigned int irq) ++{ ++ printk(KERN_WARNING "unexpected IRQ trap at irq %02x\n", irq); ++#ifdef CONFIG_X86_LOCAL_APIC ++ /* ++ * Currently unexpected vectors happen only on SMP and APIC. ++ * We _must_ ack these because every local APIC has only N ++ * irq slots per priority level, and a 'hanging, unacked' IRQ ++ * holds up an irq slot - in excessive cases (when multiple ++ * unexpected vectors occur) that might lock up the APIC ++ * completely. ++ * But don't ack when the APIC is disabled. -AK ++ */ ++ if (!disable_apic) ++ ack_APIC_irq(); ++#endif ++} ++ + #ifdef CONFIG_DEBUG_STACKOVERFLOW + /* + * Probabilistic stack overflow check: +@@ -33,11 +55,11 @@ static inline void stack_overflow_check( + u64 curbase = (u64)task_stack_page(current); + static unsigned long warned = -60*HZ; + +- if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE && +- regs->rsp < curbase + sizeof(struct thread_info) + 128 && ++ if (regs->sp >= curbase && regs->sp <= curbase + THREAD_SIZE && ++ regs->sp < curbase + sizeof(struct thread_info) + 128 && + time_after(jiffies, warned + 60*HZ)) { +- printk("do_IRQ: %s near stack overflow (cur:%Lx,rsp:%lx)\n", +- current->comm, curbase, regs->rsp); ++ printk("do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n", ++ current->comm, curbase, regs->sp); + show_stack(NULL,NULL); + warned = jiffies; + } +@@ -150,7 +172,7 @@ asmlinkage unsigned int do_IRQ(struct pt + struct pt_regs *old_regs = set_irq_regs(regs); + + /* high bit used in ret_from_ code */ +- unsigned irq = ~regs->orig_rax; ++ unsigned irq = ~regs->orig_ax; + + /*exit_idle();*/ + /*irq_enter();*/ +@@ -251,14 +273,3 @@ asmlinkage void do_softirq(void) + } + local_irq_restore(flags); + } +- +-#ifndef CONFIG_X86_LOCAL_APIC +-/* +- * 'what should we do if we get a hw irq event on an illegal vector'. +- * each architecture has to answer this themselves. +- */ +-void ack_bad_irq(unsigned int irq) +-{ +- printk("unexpected IRQ trap at irq %02x\n", irq); +-} +-#endif +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ sle11-2009-06-29/arch/x86/kernel/ldt-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -0,0 +1,272 @@ ++/* ++ * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds ++ * Copyright (C) 1999 Ingo Molnar ++ * Copyright (C) 2002 Andi Kleen ++ * ++ * This handles calls from both 32bit and 64bit mode. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_SMP ++static void flush_ldt(void *null) ++{ ++ if (current->active_mm) ++ load_LDT(¤t->active_mm->context); ++} ++#endif ++ ++static int alloc_ldt(mm_context_t *pc, int mincount, int reload) ++{ ++ void *oldldt, *newldt; ++ int oldsize; ++ ++ if (mincount <= pc->size) ++ return 0; ++ oldsize = pc->size; ++ mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) & ++ (~(PAGE_SIZE / LDT_ENTRY_SIZE - 1)); ++ if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE) ++ newldt = vmalloc(mincount * LDT_ENTRY_SIZE); ++ else ++ newldt = (void *)__get_free_page(GFP_KERNEL); ++ ++ if (!newldt) ++ return -ENOMEM; ++ ++ if (oldsize) ++ memcpy(newldt, pc->ldt, oldsize * LDT_ENTRY_SIZE); ++ oldldt = pc->ldt; ++ memset(newldt + oldsize * LDT_ENTRY_SIZE, 0, ++ (mincount - oldsize) * LDT_ENTRY_SIZE); ++ ++#ifdef CONFIG_X86_64 ++ /* CHECKME: Do we really need this ? */ ++ wmb(); ++#endif ++ pc->ldt = newldt; ++ wmb(); ++ pc->size = mincount; ++ wmb(); ++ ++ if (reload) { ++#ifdef CONFIG_SMP ++ cpumask_t mask; ++ ++ preempt_disable(); ++#endif ++ make_pages_readonly(newldt, ++ (mincount * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ load_LDT(pc); ++#ifdef CONFIG_SMP ++ mask = cpumask_of_cpu(smp_processor_id()); ++ if (!cpus_equal(current->mm->cpu_vm_mask, mask)) ++ smp_call_function(flush_ldt, NULL, 1, 1); ++ preempt_enable(); ++#endif ++ } ++ if (oldsize) { ++ make_pages_writable(oldldt, ++ (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(oldldt); ++ else ++ put_page(virt_to_page(oldldt)); ++ } ++ return 0; ++} ++ ++static inline int copy_ldt(mm_context_t *new, mm_context_t *old) ++{ ++ int err = alloc_ldt(new, old->size, 0); ++ ++ if (err < 0) ++ return err; ++ memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE); ++ make_pages_readonly(new->ldt, ++ (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ return 0; ++} ++ ++/* ++ * we do not have to muck with descriptors here, that is ++ * done in switch_mm() as needed. ++ */ ++int init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ struct mm_struct *old_mm; ++ int retval = 0; ++ ++ memset(&mm->context, 0, sizeof(mm->context)); ++ mutex_init(&mm->context.lock); ++ old_mm = current->mm; ++ if (old_mm) ++ mm->context.vdso = old_mm->context.vdso; ++ if (old_mm && old_mm->context.size > 0) { ++ mutex_lock(&old_mm->context.lock); ++ retval = copy_ldt(&mm->context, &old_mm->context); ++ mutex_unlock(&old_mm->context.lock); ++ } ++ return retval; ++} ++ ++/* ++ * No need to lock the MM as we are the last user ++ * ++ * 64bit: Don't touch the LDT register - we're already in the next thread. ++ */ ++void destroy_context(struct mm_struct *mm) ++{ ++ if (mm->context.size) { ++ /* CHECKME: Can this ever happen ? */ ++ if (mm == current->active_mm) ++ clear_LDT(); ++ make_pages_writable(mm->context.ldt, ++ (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE, ++ XENFEAT_writable_descriptor_tables); ++ if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE) ++ vfree(mm->context.ldt); ++ else ++ put_page(virt_to_page(mm->context.ldt)); ++ mm->context.size = 0; ++ } ++} ++ ++static int read_ldt(void __user *ptr, unsigned long bytecount) ++{ ++ int err; ++ unsigned long size; ++ struct mm_struct *mm = current->mm; ++ ++ if (!mm->context.size) ++ return 0; ++ if (bytecount > LDT_ENTRY_SIZE * LDT_ENTRIES) ++ bytecount = LDT_ENTRY_SIZE * LDT_ENTRIES; ++ ++ mutex_lock(&mm->context.lock); ++ size = mm->context.size * LDT_ENTRY_SIZE; ++ if (size > bytecount) ++ size = bytecount; ++ ++ err = 0; ++ if (copy_to_user(ptr, mm->context.ldt, size)) ++ err = -EFAULT; ++ mutex_unlock(&mm->context.lock); ++ if (err < 0) ++ goto error_return; ++ if (size != bytecount) { ++ /* zero-fill the rest */ ++ if (clear_user(ptr + size, bytecount - size) != 0) { ++ err = -EFAULT; ++ goto error_return; ++ } ++ } ++ return bytecount; ++error_return: ++ return err; ++} ++ ++static int read_default_ldt(void __user *ptr, unsigned long bytecount) ++{ ++ /* CHECKME: Can we use _one_ random number ? */ ++#ifdef CONFIG_X86_32 ++ unsigned long size = 5 * sizeof(struct desc_struct); ++#else ++ unsigned long size = 128; ++#endif ++ if (bytecount > size) ++ bytecount = size; ++ if (clear_user(ptr, bytecount)) ++ return -EFAULT; ++ return bytecount; ++} ++ ++static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode) ++{ ++ struct mm_struct *mm = current->mm; ++ struct desc_struct ldt; ++ int error; ++ struct user_desc ldt_info; ++ ++ error = -EINVAL; ++ if (bytecount != sizeof(ldt_info)) ++ goto out; ++ error = -EFAULT; ++ if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) ++ goto out; ++ ++ error = -EINVAL; ++ if (ldt_info.entry_number >= LDT_ENTRIES) ++ goto out; ++ if (ldt_info.contents == 3) { ++ if (oldmode) ++ goto out; ++ if (ldt_info.seg_not_present == 0) ++ goto out; ++ } ++ ++ mutex_lock(&mm->context.lock); ++ if (ldt_info.entry_number >= mm->context.size) { ++ error = alloc_ldt(¤t->mm->context, ++ ldt_info.entry_number + 1, 1); ++ if (error < 0) ++ goto out_unlock; ++ } ++ ++ /* Allow LDTs to be cleared by the user. */ ++ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { ++ if (oldmode || LDT_empty(&ldt_info)) { ++ memset(&ldt, 0, sizeof(ldt)); ++ goto install; ++ } ++ } ++ ++ fill_ldt(&ldt, &ldt_info); ++ if (oldmode) ++ ldt.avl = 0; ++ ++ /* Install the new entry ... */ ++install: ++ error = write_ldt_entry(mm->context.ldt, ldt_info.entry_number, &ldt); ++ ++out_unlock: ++ mutex_unlock(&mm->context.lock); ++out: ++ return error; ++} ++ ++asmlinkage int sys_modify_ldt(int func, void __user *ptr, ++ unsigned long bytecount) ++{ ++ int ret = -ENOSYS; ++ ++ switch (func) { ++ case 0: ++ ret = read_ldt(ptr, bytecount); ++ break; ++ case 1: ++ ret = write_ldt(ptr, bytecount, 1); ++ break; ++ case 2: ++ ret = read_default_ldt(ptr, bytecount); ++ break; ++ case 0x11: ++ ret = write_ldt(ptr, bytecount, 0); ++ break; ++ } ++ return ret; ++} +--- sle11-2009-06-29.orig/arch/x86/kernel/ldt_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,265 +0,0 @@ +-/* +- * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds +- * Copyright (C) 1999 Ingo Molnar +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +- +-#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ +-static void flush_ldt(void *null) +-{ +- if (current->active_mm) +- load_LDT(¤t->active_mm->context); +-} +-#endif +- +-static int alloc_ldt(mm_context_t *pc, int mincount, int reload) +-{ +- void *oldldt; +- void *newldt; +- int oldsize; +- +- if (mincount <= pc->size) +- return 0; +- oldsize = pc->size; +- mincount = (mincount+511)&(~511); +- if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) +- newldt = vmalloc(mincount*LDT_ENTRY_SIZE); +- else +- newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); +- +- if (!newldt) +- return -ENOMEM; +- +- if (oldsize) +- memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); +- oldldt = pc->ldt; +- memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); +- pc->ldt = newldt; +- wmb(); +- pc->size = mincount; +- wmb(); +- +- if (reload) { +-#ifdef CONFIG_SMP +- cpumask_t mask; +- preempt_disable(); +-#endif +- make_pages_readonly( +- pc->ldt, +- (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- load_LDT(pc); +-#ifdef CONFIG_SMP +- mask = cpumask_of_cpu(smp_processor_id()); +- if (!cpus_equal(current->mm->cpu_vm_mask, mask)) +- smp_call_function(flush_ldt, NULL, 1, 1); +- preempt_enable(); +-#endif +- } +- if (oldsize) { +- make_pages_writable( +- oldldt, +- (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) +- vfree(oldldt); +- else +- kfree(oldldt); +- } +- return 0; +-} +- +-static inline int copy_ldt(mm_context_t *new, mm_context_t *old) +-{ +- int err = alloc_ldt(new, old->size, 0); +- if (err < 0) +- return err; +- memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); +- make_pages_readonly( +- new->ldt, +- (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- return 0; +-} +- +-/* +- * we do not have to muck with descriptors here, that is +- * done in switch_mm() as needed. +- */ +-int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +-{ +- struct mm_struct * old_mm; +- int retval = 0; +- +- mutex_init(&mm->context.lock); +- mm->context.size = 0; +- mm->context.has_foreign_mappings = 0; +- old_mm = current->mm; +- if (old_mm && old_mm->context.size > 0) { +- mutex_lock(&old_mm->context.lock); +- retval = copy_ldt(&mm->context, &old_mm->context); +- mutex_unlock(&old_mm->context.lock); +- } +- return retval; +-} +- +-/* +- * No need to lock the MM as we are the last user +- */ +-void destroy_context(struct mm_struct *mm) +-{ +- if (mm->context.size) { +- if (mm == current->active_mm) +- clear_LDT(); +- make_pages_writable( +- mm->context.ldt, +- (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) +- vfree(mm->context.ldt); +- else +- kfree(mm->context.ldt); +- mm->context.size = 0; +- } +-} +- +-static int read_ldt(void __user * ptr, unsigned long bytecount) +-{ +- int err; +- unsigned long size; +- struct mm_struct * mm = current->mm; +- +- if (!mm->context.size) +- return 0; +- if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) +- bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; +- +- mutex_lock(&mm->context.lock); +- size = mm->context.size*LDT_ENTRY_SIZE; +- if (size > bytecount) +- size = bytecount; +- +- err = 0; +- if (copy_to_user(ptr, mm->context.ldt, size)) +- err = -EFAULT; +- mutex_unlock(&mm->context.lock); +- if (err < 0) +- goto error_return; +- if (size != bytecount) { +- /* zero-fill the rest */ +- if (clear_user(ptr+size, bytecount-size) != 0) { +- err = -EFAULT; +- goto error_return; +- } +- } +- return bytecount; +-error_return: +- return err; +-} +- +-static int read_default_ldt(void __user * ptr, unsigned long bytecount) +-{ +- int err; +- unsigned long size; +- +- err = 0; +- size = 5*sizeof(struct desc_struct); +- if (size > bytecount) +- size = bytecount; +- +- err = size; +- if (clear_user(ptr, size)) +- err = -EFAULT; +- +- return err; +-} +- +-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) +-{ +- struct mm_struct * mm = current->mm; +- __u32 entry_1, entry_2; +- int error; +- struct user_desc ldt_info; +- +- error = -EINVAL; +- if (bytecount != sizeof(ldt_info)) +- goto out; +- error = -EFAULT; +- if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) +- goto out; +- +- error = -EINVAL; +- if (ldt_info.entry_number >= LDT_ENTRIES) +- goto out; +- if (ldt_info.contents == 3) { +- if (oldmode) +- goto out; +- if (ldt_info.seg_not_present == 0) +- goto out; +- } +- +- mutex_lock(&mm->context.lock); +- if (ldt_info.entry_number >= mm->context.size) { +- error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); +- if (error < 0) +- goto out_unlock; +- } +- +- /* Allow LDTs to be cleared by the user. */ +- if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { +- if (oldmode || LDT_empty(&ldt_info)) { +- entry_1 = 0; +- entry_2 = 0; +- goto install; +- } +- } +- +- entry_1 = LDT_entry_a(&ldt_info); +- entry_2 = LDT_entry_b(&ldt_info); +- if (oldmode) +- entry_2 &= ~(1 << 20); +- +- /* Install the new entry ... */ +-install: +- error = write_ldt_entry(mm->context.ldt, ldt_info.entry_number, +- entry_1, entry_2); +- +-out_unlock: +- mutex_unlock(&mm->context.lock); +-out: +- return error; +-} +- +-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +-{ +- int ret = -ENOSYS; +- +- switch (func) { +- case 0: +- ret = read_ldt(ptr, bytecount); +- break; +- case 1: +- ret = write_ldt(ptr, bytecount, 1); +- break; +- case 2: +- ret = read_default_ldt(ptr, bytecount); +- break; +- case 0x11: +- ret = write_ldt(ptr, bytecount, 0); +- break; +- } +- return ret; +-} +--- sle11-2009-06-29.orig/arch/x86/kernel/ldt_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ /dev/null 1970-01-01 00:00:00.000000000 +0000 +@@ -1,271 +0,0 @@ +-/* +- * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds +- * Copyright (C) 1999 Ingo Molnar +- * Copyright (C) 2002 Andi Kleen +- * +- * This handles calls from both 32bit and 64bit mode. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ +-static void flush_ldt(void *null) +-{ +- if (current->active_mm) +- load_LDT(¤t->active_mm->context); +-} +-#endif +- +-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload) +-{ +- void *oldldt; +- void *newldt; +- unsigned oldsize; +- +- if (mincount <= (unsigned)pc->size) +- return 0; +- oldsize = pc->size; +- mincount = (mincount+511)&(~511); +- if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) +- newldt = vmalloc(mincount*LDT_ENTRY_SIZE); +- else +- newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); +- +- if (!newldt) +- return -ENOMEM; +- +- if (oldsize) +- memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); +- oldldt = pc->ldt; +- memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); +- wmb(); +- pc->ldt = newldt; +- wmb(); +- pc->size = mincount; +- wmb(); +- if (reload) { +-#ifdef CONFIG_SMP +- cpumask_t mask; +- +- preempt_disable(); +-#endif +- make_pages_readonly( +- pc->ldt, +- (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- load_LDT(pc); +-#ifdef CONFIG_SMP +- mask = cpumask_of_cpu(smp_processor_id()); +- if (!cpus_equal(current->mm->cpu_vm_mask, mask)) +- smp_call_function(flush_ldt, NULL, 1, 1); +- preempt_enable(); +-#endif +- } +- if (oldsize) { +- make_pages_writable( +- oldldt, +- (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE) +- vfree(oldldt); +- else +- kfree(oldldt); +- } +- return 0; +-} +- +-static inline int copy_ldt(mm_context_t *new, mm_context_t *old) +-{ +- int err = alloc_ldt(new, old->size, 0); +- if (err < 0) +- return err; +- memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); +- make_pages_readonly( +- new->ldt, +- (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- return 0; +-} +- +-/* +- * we do not have to muck with descriptors here, that is +- * done in switch_mm() as needed. +- */ +-int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +-{ +- struct mm_struct * old_mm; +- int retval = 0; +- +- memset(&mm->context, 0, sizeof(mm->context)); +- mutex_init(&mm->context.lock); +- old_mm = current->mm; +- if (old_mm) +- mm->context.vdso = old_mm->context.vdso; +- if (old_mm && old_mm->context.size > 0) { +- mutex_lock(&old_mm->context.lock); +- retval = copy_ldt(&mm->context, &old_mm->context); +- mutex_unlock(&old_mm->context.lock); +- } +- return retval; +-} +- +-/* +- * +- * Don't touch the LDT register - we're already in the next thread. +- */ +-void destroy_context(struct mm_struct *mm) +-{ +- if (mm->context.size) { +- if (mm == current->active_mm) +- clear_LDT(); +- make_pages_writable( +- mm->context.ldt, +- (mm->context.size * LDT_ENTRY_SIZE) / PAGE_SIZE, +- XENFEAT_writable_descriptor_tables); +- if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) +- vfree(mm->context.ldt); +- else +- kfree(mm->context.ldt); +- mm->context.size = 0; +- } +-} +- +-static int read_ldt(void __user * ptr, unsigned long bytecount) +-{ +- int err; +- unsigned long size; +- struct mm_struct * mm = current->mm; +- +- if (!mm->context.size) +- return 0; +- if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) +- bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; +- +- mutex_lock(&mm->context.lock); +- size = mm->context.size*LDT_ENTRY_SIZE; +- if (size > bytecount) +- size = bytecount; +- +- err = 0; +- if (copy_to_user(ptr, mm->context.ldt, size)) +- err = -EFAULT; +- mutex_unlock(&mm->context.lock); +- if (err < 0) +- goto error_return; +- if (size != bytecount) { +- /* zero-fill the rest */ +- if (clear_user(ptr+size, bytecount-size) != 0) { +- err = -EFAULT; +- goto error_return; +- } +- } +- return bytecount; +-error_return: +- return err; +-} +- +-static int read_default_ldt(void __user * ptr, unsigned long bytecount) +-{ +- /* Arbitrary number */ +- /* x86-64 default LDT is all zeros */ +- if (bytecount > 128) +- bytecount = 128; +- if (clear_user(ptr, bytecount)) +- return -EFAULT; +- return bytecount; +-} +- +-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) +-{ +- struct task_struct *me = current; +- struct mm_struct * mm = me->mm; +- __u32 entry_1, entry_2, *lp; +- unsigned long mach_lp; +- int error; +- struct user_desc ldt_info; +- +- error = -EINVAL; +- +- if (bytecount != sizeof(ldt_info)) +- goto out; +- error = -EFAULT; +- if (copy_from_user(&ldt_info, ptr, bytecount)) +- goto out; +- +- error = -EINVAL; +- if (ldt_info.entry_number >= LDT_ENTRIES) +- goto out; +- if (ldt_info.contents == 3) { +- if (oldmode) +- goto out; +- if (ldt_info.seg_not_present == 0) +- goto out; +- } +- +- mutex_lock(&mm->context.lock); +- if (ldt_info.entry_number >= (unsigned)mm->context.size) { +- error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); +- if (error < 0) +- goto out_unlock; +- } +- +- lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); +- mach_lp = arbitrary_virt_to_machine(lp); +- +- /* Allow LDTs to be cleared by the user. */ +- if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { +- if (oldmode || LDT_empty(&ldt_info)) { +- entry_1 = 0; +- entry_2 = 0; +- goto install; +- } +- } +- +- entry_1 = LDT_entry_a(&ldt_info); +- entry_2 = LDT_entry_b(&ldt_info); +- if (oldmode) +- entry_2 &= ~(1 << 20); +- +- /* Install the new entry ... */ +-install: +- error = HYPERVISOR_update_descriptor(mach_lp, (unsigned long)((entry_1 | (unsigned long) entry_2 << 32))); +- +-out_unlock: +- mutex_unlock(&mm->context.lock); +-out: +- return error; +-} +- +-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +-{ +- int ret = -ENOSYS; +- +- switch (func) { +- case 0: +- ret = read_ldt(ptr, bytecount); +- break; +- case 1: +- ret = write_ldt(ptr, bytecount, 1); +- break; +- case 2: +- ret = read_default_ldt(ptr, bytecount); +- break; +- case 0x11: +- ret = write_ldt(ptr, bytecount, 0); +- break; +- } +- return ret; +-} +--- sle11-2009-06-29.orig/arch/x86/kernel/machine_kexec_64.c 2008-11-25 12:35:54.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/machine_kexec_64.c 2009-03-16 16:33:40.000000000 +0100 +@@ -300,7 +300,9 @@ void machine_kexec(struct kimage *image) + + void arch_crash_save_vmcoreinfo(void) + { ++#ifndef CONFIG_XEN /* could really be CONFIG_RELOCATABLE */ + VMCOREINFO_SYMBOL(phys_base); ++#endif + VMCOREINFO_SYMBOL(init_level4_pgt); + + #ifdef CONFIG_NUMA +--- sle11-2009-06-29.orig/arch/x86/kernel/microcode-xen.c 2009-02-16 16:17:21.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/microcode-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -167,7 +167,7 @@ static int request_microcode(void) + } + + op.cmd = XENPF_microcode_update; +- set_xen_guest_handle(op.u.microcode.data, (void *)firmware->data); ++ set_xen_guest_handle(op.u.microcode.data, firmware->data); + op.u.microcode.length = firmware->size; + error = HYPERVISOR_platform_op(&op); + +--- sle11-2009-06-29.orig/arch/x86/kernel/mpparse_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/mpparse_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -68,7 +68,7 @@ unsigned int def_to_bigsmp = 0; + /* Processor that is doing the boot up */ + unsigned int boot_cpu_physical_apicid = -1U; + /* Internal processor count */ +-unsigned int __cpuinitdata num_processors; ++unsigned int num_processors; + + /* Bitmask of physically existing CPUs */ + physid_mask_t phys_cpu_present_map; +@@ -265,7 +265,7 @@ static void __init MP_ioapic_info (struc + if (!(m->mpc_flags & MPC_APIC_USABLE)) + return; + +- printk(KERN_INFO "I/O APIC #%d Version %d at 0x%lX.\n", ++ printk(KERN_INFO "I/O APIC #%d Version %d at 0x%X.\n", + m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_CRIT "Max # of I/O APICs (%d) exceeded (found %d).\n", +@@ -412,9 +412,9 @@ static int __init smp_read_mpc(struct mp + + mps_oem_check(mpc, oem, str); + +- printk("APIC at: 0x%lX\n",mpc->mpc_lapic); ++ printk("APIC at: 0x%X\n", mpc->mpc_lapic); + +- /* ++ /* + * Save the local APIC address (it might be non-default) -- but only + * if we're not using ACPI. + */ +@@ -728,7 +728,7 @@ static int __init smp_scan_config (unsig + unsigned long *bp = isa_bus_to_virt(base); + struct intel_mp_floating *mpf; + +- Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); ++ printk(KERN_INFO "Scan SMP from %p for %ld bytes.\n", bp,length); + if (sizeof(*mpf) != 16) + printk("Error: MPF size\n"); + +@@ -742,9 +742,10 @@ static int __init smp_scan_config (unsig + + smp_found_config = 1; + #ifndef CONFIG_XEN +- printk(KERN_INFO "found SMP MP-table at %08lx\n", +- virt_to_phys(mpf)); +- reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); ++ printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n", ++ mpf, virt_to_phys(mpf)); ++ reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE, ++ BOOTMEM_DEFAULT); + if (mpf->mpf_physptr) { + /* + * We cannot access to MPC table to compute +@@ -759,11 +760,12 @@ static int __init smp_scan_config (unsig + unsigned long end = max_low_pfn * PAGE_SIZE; + if (mpf->mpf_physptr + size > end) + size = end - mpf->mpf_physptr; +- reserve_bootmem(mpf->mpf_physptr, size); ++ reserve_bootmem(mpf->mpf_physptr, size, ++ BOOTMEM_DEFAULT); + } + #else +- printk(KERN_INFO "found SMP MP-table at %08lx\n", +- ((unsigned long)bp - (unsigned long)isa_bus_to_virt(base)) + base); ++ printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n", ++ mpf, ((void *)bp - isa_bus_to_virt(base)) + base); + #endif + + mpf_found = mpf; +@@ -940,14 +942,14 @@ void __init mp_register_ioapic(u8 id, u3 + */ + mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid; + mp_ioapic_routing[idx].gsi_base = gsi_base; +- mp_ioapic_routing[idx].gsi_end = gsi_base + ++ mp_ioapic_routing[idx].gsi_end = gsi_base + + io_apic_get_redir_entries(idx); + +- printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, " +- "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, +- mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, +- mp_ioapic_routing[idx].gsi_base, +- mp_ioapic_routing[idx].gsi_end); ++ printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " ++ "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, ++ mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, ++ mp_ioapic_routing[idx].gsi_base, ++ mp_ioapic_routing[idx].gsi_end); + } + + void __init +@@ -1063,15 +1065,16 @@ void __init mp_config_acpi_legacy_irqs ( + } + + #define MAX_GSI_NUM 4096 ++#define IRQ_COMPRESSION_START 64 + + int mp_register_gsi(u32 gsi, int triggering, int polarity) + { + int ioapic = -1; + int ioapic_pin = 0; + int idx, bit = 0; +- static int pci_irq = 16; ++ static int pci_irq = IRQ_COMPRESSION_START; + /* +- * Mapping between Global System Interrups, which ++ * Mapping between Global System Interrupts, which + * represent all possible interrupts, and IRQs + * assigned to actual devices. + */ +@@ -1108,12 +1111,16 @@ int mp_register_gsi(u32 gsi, int trigger + if ((1<= 64, use IRQ compression ++ */ ++ if ((gsi >= IRQ_COMPRESSION_START) ++ && (triggering == ACPI_LEVEL_SENSITIVE)) { + /* + * For PCI devices assign IRQs in order, avoiding gaps + * due to unused I/O APIC pins. +--- sle11-2009-06-29.orig/arch/x86/kernel/mpparse_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/mpparse_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -60,14 +60,20 @@ unsigned int boot_cpu_id = -1U; + EXPORT_SYMBOL(boot_cpu_id); + + /* Internal processor count */ +-unsigned int num_processors __cpuinitdata = 0; ++unsigned int num_processors; + + unsigned disabled_cpus __cpuinitdata; + + /* Bitmask of physically existing CPUs */ + physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE; + +-u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; ++#ifndef CONFIG_XEN ++u16 x86_bios_cpu_apicid_init[NR_CPUS] __initdata ++ = { [0 ... NR_CPUS-1] = BAD_APICID }; ++void *x86_bios_cpu_apicid_early_ptr; ++#endif ++DEFINE_PER_CPU(u16, x86_bios_cpu_apicid) = BAD_APICID; ++EXPORT_PER_CPU_SYMBOL(x86_bios_cpu_apicid); + + + /* +@@ -119,24 +125,22 @@ static void __cpuinit MP_processor_info( + physid_set(m->mpc_apicid, phys_cpu_present_map); + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { + /* +- * bios_cpu_apicid is required to have processors listed ++ * x86_bios_cpu_apicid is required to have processors listed + * in same order as logical cpu numbers. Hence the first + * entry is BSP, and so on. + */ + cpu = 0; + } +- bios_cpu_apicid[cpu] = m->mpc_apicid; +- /* +- * We get called early in the the start_kernel initialization +- * process when the per_cpu data area is not yet setup, so we +- * use a static array that is removed after the per_cpu data +- * area is created. +- */ +- if (x86_cpu_to_apicid_ptr) { +- u8 *x86_cpu_to_apicid = (u8 *)x86_cpu_to_apicid_ptr; +- x86_cpu_to_apicid[cpu] = m->mpc_apicid; ++ /* are we being called early in kernel startup? */ ++ if (x86_cpu_to_apicid_early_ptr) { ++ u16 *cpu_to_apicid = x86_cpu_to_apicid_early_ptr; ++ u16 *bios_cpu_apicid = x86_bios_cpu_apicid_early_ptr; ++ ++ cpu_to_apicid[cpu] = m->mpc_apicid; ++ bios_cpu_apicid[cpu] = m->mpc_apicid; + } else { + per_cpu(x86_cpu_to_apicid, cpu) = m->mpc_apicid; ++ per_cpu(x86_bios_cpu_apicid, cpu) = m->mpc_apicid; + } + + cpu_set(cpu, cpu_possible_map); +--- sle11-2009-06-29.orig/arch/x86/kernel/pci-dma-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/pci-dma-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -434,3 +434,23 @@ dma_sync_single_for_device(struct device + swiotlb_sync_single_for_device(dev, dma_handle, size, direction); + } + EXPORT_SYMBOL(dma_sync_single_for_device); ++ ++void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_sg_for_cpu(dev,sg,nelems,direction); ++ flush_write_buffers(); ++} ++EXPORT_SYMBOL(dma_sync_sg_for_cpu); ++ ++void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, ++ enum dma_data_direction direction) ++{ ++ if (swiotlb) ++ swiotlb_sync_sg_for_device(dev,sg,nelems,direction); ++ flush_write_buffers(); ++} ++EXPORT_SYMBOL(dma_sync_sg_for_device); +--- sle11-2009-06-29.orig/arch/x86/kernel/process_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/process_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -23,7 +23,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -59,8 +58,10 @@ + + #include + #include ++#include + + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); ++asmlinkage void cstar_ret_from_fork(void) __asm__("cstar_ret_from_fork"); + + static int hlt_counter; + +@@ -78,7 +79,7 @@ EXPORT_PER_CPU_SYMBOL(cpu_number); + */ + unsigned long thread_saved_pc(struct task_struct *tsk) + { +- return ((unsigned long *)tsk->thread.esp)[3]; ++ return ((unsigned long *)tsk->thread.sp)[3]; + } + + /* +@@ -86,7 +87,6 @@ unsigned long thread_saved_pc(struct tas + */ + void (*pm_idle)(void); + EXPORT_SYMBOL(pm_idle); +-static DEFINE_PER_CPU(unsigned int, cpu_idle_state); + + void disable_hlt(void) + { +@@ -107,7 +107,7 @@ EXPORT_SYMBOL(enable_hlt); + * to poll the ->work.need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +-static void poll_idle (void) ++static void poll_idle(void) + { + cpu_relax(); + } +@@ -122,10 +122,19 @@ static void xen_idle(void) + smp_mb(); + + local_irq_disable(); +- if (!need_resched()) ++ if (!need_resched()) { ++ ktime_t t0, t1; ++ u64 t0n, t1n; ++ ++ t0 = ktime_get(); ++ t0n = ktime_to_ns(t0); + safe_halt(); /* enables interrupts racelessly */ +- else +- local_irq_enable(); ++ local_irq_disable(); ++ t1 = ktime_get(); ++ t1n = ktime_to_ns(t1); ++ sched_clock_idle_wakeup_event(t1n - t0n); ++ } ++ local_irq_enable(); + current_thread_info()->status |= TS_POLLING; + } + #ifdef CONFIG_APM_MODULE +@@ -168,13 +177,13 @@ void cpu_idle(void) + while (!need_resched()) { + void (*idle)(void); + +- if (__get_cpu_var(cpu_idle_state)) +- __get_cpu_var(cpu_idle_state) = 0; +- + check_pgt_cache(); + rmb(); + idle = xen_idle; /* no alternatives */ + ++ if (rcu_pending(cpu)) ++ rcu_check_callbacks(cpu, 0); ++ + if (cpu_is_offline(cpu)) + play_dead(); + +@@ -192,40 +201,19 @@ static void do_nothing(void *unused) + { + } + ++/* ++ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of ++ * pm_idle and update to new pm_idle value. Required while changing pm_idle ++ * handler on SMP systems. ++ * ++ * Caller must have changed pm_idle to the new value before the call. Old ++ * pm_idle value will not be used by any CPU after the return of this function. ++ */ + void cpu_idle_wait(void) + { +- unsigned int cpu, this_cpu = get_cpu(); +- cpumask_t map, tmp = current->cpus_allowed; +- +- set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); +- put_cpu(); +- +- cpus_clear(map); +- for_each_online_cpu(cpu) { +- per_cpu(cpu_idle_state, cpu) = 1; +- cpu_set(cpu, map); +- } +- +- __get_cpu_var(cpu_idle_state) = 0; +- +- wmb(); +- do { +- ssleep(1); +- for_each_online_cpu(cpu) { +- if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu)) +- cpu_clear(cpu, map); +- } +- cpus_and(map, map, cpu_online_map); +- /* +- * We waited 1 sec, if a CPU still did not call idle +- * it may be because it is in idle and not waking up +- * because it has nothing to do. +- * Give all the remaining CPUS a kick. +- */ +- smp_call_function_mask(map, do_nothing, 0, 0); +- } while (!cpus_empty(map)); +- +- set_cpus_allowed(current, tmp); ++ smp_mb(); ++ /* kick all the CPUs so that they exit out of pm_idle */ ++ smp_call_function(do_nothing, NULL, 0, 1); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + +@@ -251,15 +239,15 @@ void __show_registers(struct pt_regs *re + { + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + unsigned long d0, d1, d2, d3, d6, d7; +- unsigned long esp; ++ unsigned long sp; + unsigned short ss, gs; + + if (user_mode_vm(regs)) { +- esp = regs->esp; +- ss = regs->xss & 0xffff; ++ sp = regs->sp; ++ ss = regs->ss & 0xffff; + savesegment(gs, gs); + } else { +- esp = (unsigned long) (®s->esp); ++ sp = (unsigned long) (®s->sp); + savesegment(ss, ss); + savesegment(gs, gs); + } +@@ -272,17 +260,17 @@ void __show_registers(struct pt_regs *re + init_utsname()->version); + + printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", +- 0xffff & regs->xcs, regs->eip, regs->eflags, ++ 0xffff & regs->cs, regs->ip, regs->flags, + smp_processor_id()); +- print_symbol("EIP is at %s\n", regs->eip); ++ print_symbol("EIP is at %s\n", regs->ip); + + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", +- regs->eax, regs->ebx, regs->ecx, regs->edx); ++ regs->ax, regs->bx, regs->cx, regs->dx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", +- regs->esi, regs->edi, regs->ebp, esp); ++ regs->si, regs->di, regs->bp, sp); + printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", +- regs->xds & 0xffff, regs->xes & 0xffff, +- regs->xfs & 0xffff, gs, ss); ++ regs->ds & 0xffff, regs->es & 0xffff, ++ regs->fs & 0xffff, gs, ss); + + if (!all) + return; +@@ -310,12 +298,12 @@ void __show_registers(struct pt_regs *re + void show_regs(struct pt_regs *regs) + { + __show_registers(regs, 1); +- show_trace(NULL, regs, ®s->esp); ++ show_trace(NULL, regs, ®s->sp, regs->bp); + } + + /* +- * This gets run with %ebx containing the +- * function to call, and %edx containing ++ * This gets run with %bx containing the ++ * function to call, and %dx containing + * the "args". + */ + extern void kernel_thread_helper(void); +@@ -329,16 +317,16 @@ int kernel_thread(int (*fn)(void *), voi + + memset(®s, 0, sizeof(regs)); + +- regs.ebx = (unsigned long) fn; +- regs.edx = (unsigned long) arg; ++ regs.bx = (unsigned long) fn; ++ regs.dx = (unsigned long) arg; + +- regs.xds = __USER_DS; +- regs.xes = __USER_DS; +- regs.xfs = __KERNEL_PERCPU; +- regs.orig_eax = -1; +- regs.eip = (unsigned long) kernel_thread_helper; +- regs.xcs = __KERNEL_CS | get_kernel_rpl(); +- regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; ++ regs.ds = __USER_DS; ++ regs.es = __USER_DS; ++ regs.fs = __KERNEL_PERCPU; ++ regs.orig_ax = -1; ++ regs.ip = (unsigned long) kernel_thread_helper; ++ regs.cs = __KERNEL_CS | get_kernel_rpl(); ++ regs.flags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; + + /* Ok, create the new process.. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); +@@ -368,7 +356,12 @@ void flush_thread(void) + { + struct task_struct *tsk = current; + +- memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); ++ tsk->thread.debugreg0 = 0; ++ tsk->thread.debugreg1 = 0; ++ tsk->thread.debugreg2 = 0; ++ tsk->thread.debugreg3 = 0; ++ tsk->thread.debugreg6 = 0; ++ tsk->thread.debugreg7 = 0; + memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); + clear_tsk_thread_flag(tsk, TIF_DEBUG); + /* +@@ -393,7 +386,7 @@ void prepare_to_copy(struct task_struct + unlazy_fpu(tsk); + } + +-int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, ++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) + { +@@ -403,17 +396,19 @@ int copy_thread(int nr, unsigned long cl + + childregs = task_pt_regs(p); + *childregs = *regs; +- childregs->eax = 0; +- childregs->esp = esp; ++ childregs->ax = 0; ++ childregs->sp = sp; + +- p->thread.esp = (unsigned long) childregs; +- p->thread.esp0 = (unsigned long) (childregs+1); ++ p->thread.sp = (unsigned long) childregs; ++ p->thread.sp0 = (unsigned long) (childregs+1); + +- p->thread.eip = (unsigned long) ret_from_fork; ++ p->thread.ip = (unsigned long) ret_from_fork; + +- savesegment(gs,p->thread.gs); ++ savesegment(gs, p->thread.gs); + + tsk = current; ++ if (test_tsk_thread_flag(tsk, TIF_CSTAR)) ++ p->thread.ip = (unsigned long) cstar_ret_from_fork; + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { + p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr, + IO_BITMAP_BYTES, GFP_KERNEL); +@@ -424,34 +419,17 @@ int copy_thread(int nr, unsigned long cl + set_tsk_thread_flag(p, TIF_IO_BITMAP); + } + ++ err = 0; ++ + /* + * Set a new TLS for the child thread? + */ +- if (clone_flags & CLONE_SETTLS) { +- struct desc_struct *desc; +- struct user_desc info; +- int idx; +- +- err = -EFAULT; +- if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info))) +- goto out; +- err = -EINVAL; +- if (LDT_empty(&info)) +- goto out; +- +- idx = info.entry_number; +- if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) +- goto out; +- +- desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; +- desc->a = LDT_entry_a(&info); +- desc->b = LDT_entry_b(&info); +- } ++ if (clone_flags & CLONE_SETTLS) ++ err = do_set_thread_area(p, -1, ++ (struct user_desc __user *)childregs->si, 0); + + p->thread.iopl = current->thread.iopl; + +- err = 0; +- out: + if (err && p->thread.io_bitmap_ptr) { + kfree(p->thread.io_bitmap_ptr); + p->thread.io_bitmap_max = 0; +@@ -459,67 +437,8 @@ int copy_thread(int nr, unsigned long cl + return err; + } + +-/* +- * fill in the user structure for a core dump.. +- */ +-void dump_thread(struct pt_regs * regs, struct user * dump) +-{ +- int i; +- +-/* changed the size calculations - should hopefully work better. lbt */ +- dump->magic = CMAGIC; +- dump->start_code = 0; +- dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); +- dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; +- dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; +- dump->u_dsize -= dump->u_tsize; +- dump->u_ssize = 0; +- for (i = 0; i < 8; i++) +- dump->u_debugreg[i] = current->thread.debugreg[i]; +- +- if (dump->start_stack < TASK_SIZE) +- dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; +- +- dump->regs.ebx = regs->ebx; +- dump->regs.ecx = regs->ecx; +- dump->regs.edx = regs->edx; +- dump->regs.esi = regs->esi; +- dump->regs.edi = regs->edi; +- dump->regs.ebp = regs->ebp; +- dump->regs.eax = regs->eax; +- dump->regs.ds = regs->xds; +- dump->regs.es = regs->xes; +- dump->regs.fs = regs->xfs; +- savesegment(gs,dump->regs.gs); +- dump->regs.orig_eax = regs->orig_eax; +- dump->regs.eip = regs->eip; +- dump->regs.cs = regs->xcs; +- dump->regs.eflags = regs->eflags; +- dump->regs.esp = regs->esp; +- dump->regs.ss = regs->xss; +- +- dump->u_fpvalid = dump_fpu (regs, &dump->i387); +-} +-EXPORT_SYMBOL(dump_thread); +- +-/* +- * Capture the user space registers if the task is not running (in user space) +- */ +-int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +-{ +- struct pt_regs ptregs = *task_pt_regs(tsk); +- ptregs.xcs &= 0xffff; +- ptregs.xds &= 0xffff; +- ptregs.xes &= 0xffff; +- ptregs.xss &= 0xffff; +- +- elf_core_copy_regs(regs, &ptregs); +- +- return 1; +-} +- + #ifdef CONFIG_SECCOMP +-void hard_disable_TSC(void) ++static void hard_disable_TSC(void) + { + write_cr4(read_cr4() | X86_CR4_TSD); + } +@@ -534,7 +453,7 @@ void disable_TSC(void) + hard_disable_TSC(); + preempt_enable(); + } +-void hard_enable_TSC(void) ++static void hard_enable_TSC(void) + { + write_cr4(read_cr4() & ~X86_CR4_TSD); + } +@@ -543,18 +462,32 @@ void hard_enable_TSC(void) + static noinline void + __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p) + { +- struct thread_struct *next; ++ struct thread_struct *prev, *next; ++ unsigned long debugctl; + ++ prev = &prev_p->thread; + next = &next_p->thread; + ++ debugctl = prev->debugctlmsr; ++ if (next->ds_area_msr != prev->ds_area_msr) { ++ /* we clear debugctl to make sure DS ++ * is not in use when we change it */ ++ debugctl = 0; ++ wrmsrl(MSR_IA32_DEBUGCTLMSR, 0); ++ wrmsr(MSR_IA32_DS_AREA, next->ds_area_msr, 0); ++ } ++ ++ if (next->debugctlmsr != debugctl) ++ wrmsr(MSR_IA32_DEBUGCTLMSR, next->debugctlmsr, 0); ++ + if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { +- set_debugreg(next->debugreg[0], 0); +- set_debugreg(next->debugreg[1], 1); +- set_debugreg(next->debugreg[2], 2); +- set_debugreg(next->debugreg[3], 3); ++ set_debugreg(next->debugreg0, 0); ++ set_debugreg(next->debugreg1, 1); ++ set_debugreg(next->debugreg2, 2); ++ set_debugreg(next->debugreg3, 3); + /* no 4 and 5 */ +- set_debugreg(next->debugreg[6], 6); +- set_debugreg(next->debugreg[7], 7); ++ set_debugreg(next->debugreg6, 6); ++ set_debugreg(next->debugreg7, 7); + } + + #ifdef CONFIG_SECCOMP +@@ -567,6 +500,14 @@ __switch_to_xtra(struct task_struct *pre + hard_enable_TSC(); + } + #endif ++ ++#ifdef X86_BTS ++ if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS)) ++ ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS); ++ ++ if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS)) ++ ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES); ++#endif + } + + /* +@@ -592,11 +533,11 @@ __switch_to_xtra(struct task_struct *pre + * More important, however, is the fact that this allows us much + * more flexibility. + * +- * The return value (in %eax) will be the "prev" task after ++ * The return value (in %ax) will be the "prev" task after + * the task-switch, and shows up in ret_from_fork in entry.S, + * for example. + */ +-struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) ++struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) + { + struct thread_struct *prev = &prev_p->thread, + *next = &next_p->thread; +@@ -632,12 +573,12 @@ struct task_struct fastcall * __switch_t + #endif + + /* +- * Reload esp0. +- * This is load_esp0(tss, next) with a multicall. ++ * Reload sp0. ++ * This is load_sp0(tss, next) with a multicall. + */ + mcl->op = __HYPERVISOR_stack_switch; + mcl->args[0] = __KERNEL_DS; +- mcl->args[1] = next->esp0; ++ mcl->args[1] = next->sp0; + mcl++; + + /* +@@ -734,7 +675,7 @@ struct task_struct fastcall * __switch_t + + asmlinkage int sys_fork(struct pt_regs regs) + { +- return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL); ++ return do_fork(SIGCHLD, regs.sp, ®s, 0, NULL, NULL); + } + + asmlinkage int sys_clone(struct pt_regs regs) +@@ -743,12 +684,12 @@ asmlinkage int sys_clone(struct pt_regs + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + +- clone_flags = regs.ebx; +- newsp = regs.ecx; +- parent_tidptr = (int __user *)regs.edx; +- child_tidptr = (int __user *)regs.edi; ++ clone_flags = regs.bx; ++ newsp = regs.cx; ++ parent_tidptr = (int __user *)regs.dx; ++ child_tidptr = (int __user *)regs.di; + if (!newsp) +- newsp = regs.esp; ++ newsp = regs.sp; + return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); + } + +@@ -764,7 +705,7 @@ asmlinkage int sys_clone(struct pt_regs + */ + asmlinkage int sys_vfork(struct pt_regs regs) + { +- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0, NULL, NULL); ++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, ®s, 0, NULL, NULL); + } + + /* +@@ -775,18 +716,15 @@ asmlinkage int sys_execve(struct pt_regs + int error; + char * filename; + +- filename = getname((char __user *) regs.ebx); ++ filename = getname((char __user *) regs.bx); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, +- (char __user * __user *) regs.ecx, +- (char __user * __user *) regs.edx, ++ (char __user * __user *) regs.cx, ++ (char __user * __user *) regs.dx, + ®s); + if (error == 0) { +- task_lock(current); +- current->ptrace &= ~PT_DTRACE; +- task_unlock(current); + /* Make sure we don't return using sysenter.. */ + set_thread_flag(TIF_IRET); + } +@@ -800,145 +738,37 @@ out: + + unsigned long get_wchan(struct task_struct *p) + { +- unsigned long ebp, esp, eip; ++ unsigned long bp, sp, ip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)task_stack_page(p); +- esp = p->thread.esp; +- if (!stack_page || esp < stack_page || esp > top_esp+stack_page) ++ sp = p->thread.sp; ++ if (!stack_page || sp < stack_page || sp > top_esp+stack_page) + return 0; +- /* include/asm-i386/system.h:switch_to() pushes ebp last. */ +- ebp = *(unsigned long *) esp; ++ /* include/asm-i386/system.h:switch_to() pushes bp last. */ ++ bp = *(unsigned long *) sp; + do { +- if (ebp < stack_page || ebp > top_ebp+stack_page) ++ if (bp < stack_page || bp > top_ebp+stack_page) + return 0; +- eip = *(unsigned long *) (ebp+4); +- if (!in_sched_functions(eip)) +- return eip; +- ebp = *(unsigned long *) ebp; ++ ip = *(unsigned long *) (bp+4); ++ if (!in_sched_functions(ip)) ++ return ip; ++ bp = *(unsigned long *) bp; + } while (count++ < 16); + return 0; + } + +-/* +- * sys_alloc_thread_area: get a yet unused TLS descriptor index. +- */ +-static int get_free_idx(void) +-{ +- struct thread_struct *t = ¤t->thread; +- int idx; +- +- for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) +- if (desc_empty(t->tls_array + idx)) +- return idx + GDT_ENTRY_TLS_MIN; +- return -ESRCH; +-} +- +-/* +- * Set a given TLS descriptor: +- */ +-asmlinkage int sys_set_thread_area(struct user_desc __user *u_info) +-{ +- struct thread_struct *t = ¤t->thread; +- struct user_desc info; +- struct desc_struct *desc; +- int cpu, idx; +- +- if (copy_from_user(&info, u_info, sizeof(info))) +- return -EFAULT; +- idx = info.entry_number; +- +- /* +- * index -1 means the kernel should try to find and +- * allocate an empty descriptor: +- */ +- if (idx == -1) { +- idx = get_free_idx(); +- if (idx < 0) +- return idx; +- if (put_user(idx, &u_info->entry_number)) +- return -EFAULT; +- } +- +- if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) +- return -EINVAL; +- +- desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; +- +- /* +- * We must not get preempted while modifying the TLS. +- */ +- cpu = get_cpu(); +- +- if (LDT_empty(&info)) { +- desc->a = 0; +- desc->b = 0; +- } else { +- desc->a = LDT_entry_a(&info); +- desc->b = LDT_entry_b(&info); +- } +- load_TLS(t, cpu); +- +- put_cpu(); +- +- return 0; +-} +- +-/* +- * Get the current Thread-Local Storage area: +- */ +- +-#define GET_BASE(desc) ( \ +- (((desc)->a >> 16) & 0x0000ffff) | \ +- (((desc)->b << 16) & 0x00ff0000) | \ +- ( (desc)->b & 0xff000000) ) +- +-#define GET_LIMIT(desc) ( \ +- ((desc)->a & 0x0ffff) | \ +- ((desc)->b & 0xf0000) ) +- +-#define GET_32BIT(desc) (((desc)->b >> 22) & 1) +-#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) +-#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) +-#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) +-#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) +-#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) +- +-asmlinkage int sys_get_thread_area(struct user_desc __user *u_info) +-{ +- struct user_desc info; +- struct desc_struct *desc; +- int idx; +- +- if (get_user(idx, &u_info->entry_number)) +- return -EFAULT; +- if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) +- return -EINVAL; +- +- memset(&info, 0, sizeof(info)); +- +- desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; +- +- info.entry_number = idx; +- info.base_addr = GET_BASE(desc); +- info.limit = GET_LIMIT(desc); +- info.seg_32bit = GET_32BIT(desc); +- info.contents = GET_CONTENTS(desc); +- info.read_exec_only = !GET_WRITABLE(desc); +- info.limit_in_pages = GET_LIMIT_PAGES(desc); +- info.seg_not_present = !GET_PRESENT(desc); +- info.useable = GET_USEABLE(desc); +- +- if (copy_to_user(u_info, &info, sizeof(info))) +- return -EFAULT; +- return 0; +-} +- + unsigned long arch_align_stack(unsigned long sp) + { + if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) + sp -= get_random_int() % 8192; + return sp & ~0xf; + } ++ ++unsigned long arch_randomize_brk(struct mm_struct *mm) ++{ ++ unsigned long range_end = mm->brk + 0x02000000; ++ return randomize_range(mm->brk, range_end, 0) ? : mm->brk; ++} +--- sle11-2009-06-29.orig/arch/x86/kernel/process_64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/process_64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -3,7 +3,7 @@ + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 +- * ++ * + * X86-64 port + * Andi Kleen. + * +@@ -22,19 +22,18 @@ + #include + #include + #include ++#include + #include + #include +-#include + #include + #include + #include + #include +-#include +-#include + #include ++#include + #include ++#include + #include +-#include + #include + #include + #include +@@ -73,7 +72,6 @@ EXPORT_SYMBOL(boot_option_idle_override) + */ + void (*pm_idle)(void); + EXPORT_SYMBOL(pm_idle); +-static DEFINE_PER_CPU(unsigned int, cpu_idle_state); + + static ATOMIC_NOTIFIER_HEAD(idle_notifier); + +@@ -81,13 +79,6 @@ void idle_notifier_register(struct notif + { + atomic_notifier_chain_register(&idle_notifier, n); + } +-EXPORT_SYMBOL_GPL(idle_notifier_register); +- +-void idle_notifier_unregister(struct notifier_block *n) +-{ +- atomic_notifier_chain_unregister(&idle_notifier, n); +-} +-EXPORT_SYMBOL(idle_notifier_unregister); + + void enter_idle(void) + { +@@ -116,7 +107,7 @@ void exit_idle(void) + * to poll the ->need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +-static void poll_idle (void) ++static void poll_idle(void) + { + local_irq_enable(); + cpu_relax(); +@@ -131,10 +122,19 @@ static void xen_idle(void) + */ + smp_mb(); + local_irq_disable(); +- if (!need_resched()) +- safe_halt(); +- else +- local_irq_enable(); ++ if (!need_resched()) { ++ ktime_t t0, t1; ++ u64 t0n, t1n; ++ ++ t0 = ktime_get(); ++ t0n = ktime_to_ns(t0); ++ safe_halt(); /* enables interrupts racelessly */ ++ local_irq_disable(); ++ t1 = ktime_get(); ++ t1n = ktime_to_ns(t1); ++ sched_clock_idle_wakeup_event(t1n - t0n); ++ } ++ local_irq_enable(); + current_thread_info()->status |= TS_POLLING; + } + +@@ -161,19 +161,15 @@ static inline void play_dead(void) + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +-void cpu_idle (void) ++void cpu_idle(void) + { + current_thread_info()->status |= TS_POLLING; + /* endless idle loop with no priority at all */ + while (1) { ++ tick_nohz_stop_sched_tick(); + while (!need_resched()) { + void (*idle)(void); + +- if (__get_cpu_var(cpu_idle_state)) +- __get_cpu_var(cpu_idle_state) = 0; +- +- tick_nohz_stop_sched_tick(); +- + rmb(); + idle = xen_idle; /* no alternatives */ + if (cpu_is_offline(smp_processor_id())) +@@ -203,49 +199,27 @@ static void do_nothing(void *unused) + { + } + ++/* ++ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of ++ * pm_idle and update to new pm_idle value. Required while changing pm_idle ++ * handler on SMP systems. ++ * ++ * Caller must have changed pm_idle to the new value before the call. Old ++ * pm_idle value will not be used by any CPU after the return of this function. ++ */ + void cpu_idle_wait(void) + { +- unsigned int cpu, this_cpu = get_cpu(); +- cpumask_t map, tmp = current->cpus_allowed; +- +- set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); +- put_cpu(); +- +- cpus_clear(map); +- for_each_online_cpu(cpu) { +- per_cpu(cpu_idle_state, cpu) = 1; +- cpu_set(cpu, map); +- } +- +- __get_cpu_var(cpu_idle_state) = 0; +- +- wmb(); +- do { +- ssleep(1); +- for_each_online_cpu(cpu) { +- if (cpu_isset(cpu, map) && +- !per_cpu(cpu_idle_state, cpu)) +- cpu_clear(cpu, map); +- } +- cpus_and(map, map, cpu_online_map); +- /* +- * We waited 1 sec, if a CPU still did not call idle +- * it may be because it is in idle and not waking up +- * because it has nothing to do. +- * Give all the remaining CPUS a kick. +- */ +- smp_call_function_mask(map, do_nothing, 0, 0); +- } while (!cpus_empty(map)); +- +- set_cpus_allowed(current, tmp); ++ smp_mb(); ++ /* kick all the CPUs so that they exit out of pm_idle */ ++ smp_call_function(do_nothing, NULL, 0, 1); + } + EXPORT_SYMBOL_GPL(cpu_idle_wait); + +-void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) ++void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) + { + } + +-static int __init idle_setup (char *str) ++static int __init idle_setup(char *str) + { + if (!strcmp(str, "poll")) { + printk("using polling idle threads.\n"); +@@ -260,13 +234,13 @@ static int __init idle_setup (char *str) + } + early_param("idle", idle_setup); + +-/* Prints also some state that isn't saved in the pt_regs */ ++/* Prints also some state that isn't saved in the pt_regs */ + void __show_regs(struct pt_regs * regs) + { + unsigned long fs, gs, shadowgs; + unsigned long d0, d1, d2, d3, d6, d7; +- unsigned int fsindex,gsindex; +- unsigned int ds,cs,es; ++ unsigned int fsindex, gsindex; ++ unsigned int ds, cs, es; + + printk("\n"); + print_modules(); +@@ -275,16 +249,16 @@ void __show_regs(struct pt_regs * regs) + init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); +- printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); +- printk_address(regs->rip); +- printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, +- regs->eflags); ++ printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip); ++ printk_address(regs->ip, 1); ++ printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->sp, ++ regs->flags); + printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", +- regs->rax, regs->rbx, regs->rcx); ++ regs->ax, regs->bx, regs->cx); + printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", +- regs->rdx, regs->rsi, regs->rdi); ++ regs->dx, regs->si, regs->di); + printk("RBP: %016lx R08: %016lx R09: %016lx\n", +- regs->rbp, regs->r8, regs->r9); ++ regs->bp, regs->r8, regs->r9); + printk("R10: %016lx R11: %016lx R12: %016lx\n", + regs->r10, regs->r11, regs->r12); + printk("R13: %016lx R14: %016lx R15: %016lx\n", +@@ -318,7 +292,7 @@ void show_regs(struct pt_regs *regs) + { + printk("CPU %d:", smp_processor_id()); + __show_regs(regs); +- show_trace(NULL, regs, (void *)(regs + 1)); ++ show_trace(NULL, regs, (void *)(regs + 1), regs->bp); + } + + /* +@@ -329,7 +303,7 @@ void exit_thread(void) + struct task_struct *me = current; + struct thread_struct *t = &me->thread; + +- if (me->thread.io_bitmap_ptr) { ++ if (me->thread.io_bitmap_ptr) { + #ifndef CONFIG_X86_NO_TSS + struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); + #endif +@@ -382,7 +356,7 @@ void flush_thread(void) + tsk->thread.debugreg3 = 0; + tsk->thread.debugreg6 = 0; + tsk->thread.debugreg7 = 0; +- memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); ++ memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); + /* + * Forget coprocessor state.. + */ +@@ -405,26 +379,21 @@ void release_thread(struct task_struct * + + static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr) + { +- struct user_desc ud = { ++ struct user_desc ud = { + .base_addr = addr, + .limit = 0xfffff, + .seg_32bit = 1, + .limit_in_pages = 1, + .useable = 1, + }; +- struct n_desc_struct *desc = (void *)t->thread.tls_array; ++ struct desc_struct *desc = t->thread.tls_array; + desc += tls; +- desc->a = LDT_entry_a(&ud); +- desc->b = LDT_entry_b(&ud); ++ fill_ldt(desc, &ud); + } + + static inline u32 read_32bit_tls(struct task_struct *t, int tls) + { +- struct desc_struct *desc = (void *)t->thread.tls_array; +- desc += tls; +- return desc->base0 | +- (((u32)desc->base1) << 16) | +- (((u32)desc->base2) << 24); ++ return get_desc_base(&t->thread.tls_array[tls]); + } + + /* +@@ -436,7 +405,7 @@ void prepare_to_copy(struct task_struct + unlazy_fpu(tsk); + } + +-int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, ++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) + { +@@ -448,14 +417,14 @@ int copy_thread(int nr, unsigned long cl + (THREAD_SIZE + task_stack_page(p))) - 1; + *childregs = *regs; + +- childregs->rax = 0; +- childregs->rsp = rsp; +- if (rsp == ~0UL) +- childregs->rsp = (unsigned long)childregs; +- +- p->thread.rsp = (unsigned long) childregs; +- p->thread.rsp0 = (unsigned long) (childregs+1); +- p->thread.userrsp = me->thread.userrsp; ++ childregs->ax = 0; ++ childregs->sp = sp; ++ if (sp == ~0UL) ++ childregs->sp = (unsigned long)childregs; ++ ++ p->thread.sp = (unsigned long) childregs; ++ p->thread.sp0 = (unsigned long) (childregs+1); ++ p->thread.usersp = me->thread.usersp; + + set_tsk_thread_flag(p, TIF_FORK); + +@@ -476,7 +445,7 @@ int copy_thread(int nr, unsigned long cl + memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, + IO_BITMAP_BYTES); + set_tsk_thread_flag(p, TIF_IO_BITMAP); +- } ++ } + + /* + * Set a new TLS for the child thread? +@@ -484,7 +453,8 @@ int copy_thread(int nr, unsigned long cl + if (clone_flags & CLONE_SETTLS) { + #ifdef CONFIG_IA32_EMULATION + if (test_thread_flag(TIF_IA32)) +- err = ia32_child_tls(p, childregs); ++ err = do_set_thread_area(p, -1, ++ (struct user_desc __user *)childregs->si, 0); + else + #endif + err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8); +@@ -502,26 +472,32 @@ out: + return err; + } + +-static inline void __save_init_fpu( struct task_struct *tsk ) +-{ +- asm volatile( "rex64 ; fxsave %0 ; fnclex" +- : "=m" (tsk->thread.i387.fxsave)); +- tsk->thread_info->status &= ~TS_USEDFPU; +-} +- + /* + * This special macro can be used to load a debugging register + */ +-#define loaddebug(thread,r) set_debugreg(thread->debugreg ## r, r) ++#define loaddebug(thread, r) set_debugreg(thread->debugreg ## r, r) + + static inline void __switch_to_xtra(struct task_struct *prev_p, +- struct task_struct *next_p) ++ struct task_struct *next_p) + { + struct thread_struct *prev, *next; ++ unsigned long debugctl; + + prev = &prev_p->thread, + next = &next_p->thread; + ++ debugctl = prev->debugctlmsr; ++ if (next->ds_area_msr != prev->ds_area_msr) { ++ /* we clear debugctl to make sure DS ++ * is not in use when we change it */ ++ debugctl = 0; ++ wrmsrl(MSR_IA32_DEBUGCTLMSR, 0); ++ wrmsrl(MSR_IA32_DS_AREA, next->ds_area_msr); ++ } ++ ++ if (next->debugctlmsr != debugctl) ++ wrmsrl(MSR_IA32_DEBUGCTLMSR, next->debugctlmsr); ++ + if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { + loaddebug(next, 0); + loaddebug(next, 1); +@@ -531,12 +507,20 @@ static inline void __switch_to_xtra(stru + loaddebug(next, 6); + loaddebug(next, 7); + } ++ ++#ifdef X86_BTS ++ if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS)) ++ ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS); ++ ++ if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS)) ++ ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES); ++#endif + } + + /* + * switch_to(x,y) should switch tasks from x to y. + * +- * This could still be optimized: ++ * This could still be optimized: + * - fold all the options into a flag word and test it with a single test. + * - could test fs/gs bitsliced + * +@@ -547,7 +531,7 @@ __switch_to(struct task_struct *prev_p, + { + struct thread_struct *prev = &prev_p->thread, + *next = &next_p->thread; +- int cpu = smp_processor_id(); ++ int cpu = smp_processor_id(); + #ifndef CONFIG_X86_NO_TSS + struct tss_struct *tss = &per_cpu(init_tss, cpu); + #endif +@@ -581,11 +565,12 @@ __switch_to(struct task_struct *prev_p, + prev_p->fpu_counter = 0; + + /* +- * Reload esp0, LDT and the page table pointer: ++ * Reload sp0. ++ * This is load_sp0(tss, next) with a multicall. + */ + mcl->op = __HYPERVISOR_stack_switch; + mcl->args[0] = __KERNEL_DS; +- mcl->args[1] = next->rsp0; ++ mcl->args[1] = next->sp0; + mcl++; + + /* +@@ -593,11 +578,12 @@ __switch_to(struct task_struct *prev_p, + * This is load_TLS(next, cpu) with multicalls. + */ + #define C(i) do { \ +- if (unlikely(next->tls_array[i] != prev->tls_array[i])) { \ ++ if (unlikely(next->tls_array[i].a != prev->tls_array[i].a || \ ++ next->tls_array[i].b != prev->tls_array[i].b)) { \ + mcl->op = __HYPERVISOR_update_descriptor; \ + mcl->args[0] = virt_to_machine( \ +- &cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]); \ +- mcl->args[1] = next->tls_array[i]; \ ++ &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]);\ ++ mcl->args[1] = *(u64 *)&next->tls_array[i]; \ + mcl++; \ + } \ + } while (0) +@@ -605,7 +591,7 @@ __switch_to(struct task_struct *prev_p, + #undef C + + if (unlikely(prev->iopl != next->iopl)) { +- iopl_op.iopl = (next->iopl == 0) ? 1 : next->iopl; ++ iopl_op.iopl = (next->iopl == 0) ? 1 : (next->iopl >> 12) & 3; + #if CONFIG_XEN_COMPAT > 0x030002 + mcl->op = __HYPERVISOR_physdev_op; + mcl->args[0] = PHYSDEVOP_set_iopl; +@@ -669,8 +655,8 @@ __switch_to(struct task_struct *prev_p, + /* + * Switch the PDA context. + */ +- prev->userrsp = read_pda(oldrsp); +- write_pda(oldrsp, next->userrsp); ++ prev->usersp = read_pda(oldrsp); ++ write_pda(oldrsp, next->usersp); + write_pda(pcurrent, next_p); + write_pda(kernelstack, + (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); +@@ -687,7 +673,8 @@ __switch_to(struct task_struct *prev_p, + /* + * Now maybe reload the debug registers + */ +- if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) ++ if (unlikely(task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT || ++ task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV)) + __switch_to_xtra(prev_p, next_p); + + /* If the task has used fpu the last 5 timeslices, just do a full +@@ -702,23 +689,18 @@ __switch_to(struct task_struct *prev_p, + /* + * sys_execve() executes a new program. + */ +-asmlinkage ++asmlinkage + long sys_execve(char __user *name, char __user * __user *argv, +- char __user * __user *envp, struct pt_regs regs) ++ char __user * __user *envp, struct pt_regs *regs) + { + long error; + char * filename; + + filename = getname(name); + error = PTR_ERR(filename); +- if (IS_ERR(filename)) ++ if (IS_ERR(filename)) + return error; +- error = do_execve(filename, argv, envp, ®s); +- if (error == 0) { +- task_lock(current); +- current->ptrace &= ~PT_DTRACE; +- task_unlock(current); +- } ++ error = do_execve(filename, argv, envp, regs); + putname(filename); + return error; + } +@@ -728,18 +710,18 @@ void set_personality_64bit(void) + /* inherit personality from parent */ + + /* Make sure to be in 64bit mode */ +- clear_thread_flag(TIF_IA32); ++ clear_thread_flag(TIF_IA32); + + /* TBD: overwrites user setup. Should have two bits. + But 64bit processes have always behaved this way, + so it's not too bad. The main problem is just that +- 32bit childs are affected again. */ ++ 32bit childs are affected again. */ + current->personality &= ~READ_IMPLIES_EXEC; + } + + asmlinkage long sys_fork(struct pt_regs *regs) + { +- return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL); ++ return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); + } + + asmlinkage long +@@ -747,7 +729,7 @@ sys_clone(unsigned long clone_flags, uns + void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) + { + if (!newsp) +- newsp = regs->rsp; ++ newsp = regs->sp; + return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); + } + +@@ -763,29 +745,29 @@ sys_clone(unsigned long clone_flags, uns + */ + asmlinkage long sys_vfork(struct pt_regs *regs) + { +- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->rsp, regs, 0, ++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, + NULL, NULL); + } + + unsigned long get_wchan(struct task_struct *p) + { + unsigned long stack; +- u64 fp,rip; ++ u64 fp,ip; + int count = 0; + + if (!p || p == current || p->state==TASK_RUNNING) + return 0; + stack = (unsigned long)task_stack_page(p); +- if (p->thread.rsp < stack || p->thread.rsp > stack+THREAD_SIZE) ++ if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE) + return 0; +- fp = *(u64 *)(p->thread.rsp); ++ fp = *(u64 *)(p->thread.sp); + do { + if (fp < (unsigned long)stack || + fp > (unsigned long)stack+THREAD_SIZE) + return 0; +- rip = *(u64 *)(fp+8); +- if (!in_sched_functions(rip)) +- return rip; ++ ip = *(u64 *)(fp+8); ++ if (!in_sched_functions(ip)) ++ return ip; + fp = *(u64 *)fp; + } while (count++ < 16); + return 0; +@@ -827,19 +809,19 @@ long do_arch_prctl(struct task_struct *t + /* Not strictly needed for fs, but do it for symmetry + with gs */ + if (addr >= TASK_SIZE_OF(task)) +- return -EPERM; ++ return -EPERM; + cpu = get_cpu(); +- /* handle small bases via the GDT because that's faster to ++ /* handle small bases via the GDT because that's faster to + switch. */ +- if (addr <= 0xffffffff) { ++ if (addr <= 0xffffffff) { + set_32bit_tls(task, FS_TLS, addr); +- if (doit) { +- load_TLS(&task->thread, cpu); ++ if (doit) { ++ load_TLS(&task->thread, cpu); + asm volatile("movl %0,%%fs" :: "r"(FS_TLS_SEL)); + } + task->thread.fsindex = FS_TLS_SEL; + task->thread.fs = 0; +- } else { ++ } else { + task->thread.fsindex = 0; + task->thread.fs = addr; + if (doit) { +@@ -852,24 +834,24 @@ long do_arch_prctl(struct task_struct *t + } + put_cpu(); + break; +- case ARCH_GET_FS: { +- unsigned long base; ++ case ARCH_GET_FS: { ++ unsigned long base; + if (task->thread.fsindex == FS_TLS_SEL) + base = read_32bit_tls(task, FS_TLS); + else if (doit) + rdmsrl(MSR_FS_BASE, base); + else + base = task->thread.fs; +- ret = put_user(base, (unsigned long __user *)addr); +- break; ++ ret = put_user(base, (unsigned long __user *)addr); ++ break; + } +- case ARCH_GET_GS: { ++ case ARCH_GET_GS: { + unsigned long base; + unsigned gsindex; + if (task->thread.gsindex == GS_TLS_SEL) + base = read_32bit_tls(task, GS_TLS); + else if (doit) { +- asm("movl %%gs,%0" : "=r" (gsindex)); ++ asm("movl %%gs,%0" : "=r" (gsindex)); + if (gsindex) + rdmsrl(MSR_KERNEL_GS_BASE, base); + else +@@ -877,40 +859,21 @@ long do_arch_prctl(struct task_struct *t + } + else + base = task->thread.gs; +- ret = put_user(base, (unsigned long __user *)addr); ++ ret = put_user(base, (unsigned long __user *)addr); + break; + } + + default: + ret = -EINVAL; + break; +- } ++ } + +- return ret; +-} ++ return ret; ++} + + long sys_arch_prctl(int code, unsigned long addr) + { + return do_arch_prctl(current, code, addr); +-} +- +-/* +- * Capture the user space registers if the task is not running (in user space) +- */ +-int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +-{ +- struct pt_regs *pp, ptregs; +- +- pp = task_pt_regs(tsk); +- +- ptregs = *pp; +- ptregs.cs &= 0xffff; +- ptregs.ss &= 0xffff; +- +- elf_core_copy_regs(regs, &ptregs); +- +- boot_option_idle_override = 1; +- return 1; + } + + unsigned long arch_align_stack(unsigned long sp) +@@ -919,3 +882,9 @@ unsigned long arch_align_stack(unsigned + sp -= get_random_int() % 8192; + return sp & ~0xf; + } ++ ++unsigned long arch_randomize_brk(struct mm_struct *mm) ++{ ++ unsigned long range_end = mm->brk + 0x02000000; ++ return randomize_range(mm->brk, range_end, 0) ? : mm->brk; ++} +--- sle11-2009-06-29.orig/arch/x86/kernel/quirks-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/quirks-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -9,7 +9,7 @@ + static void __devinit quirk_intel_irqbalance(struct pci_dev *dev) + { + u8 config, rev; +- u32 word; ++ u16 word; + + /* BIOS may enable hardware IRQ balancing for + * E7520/E7320/E7525(revision ID 0x9 and below) +@@ -24,14 +24,17 @@ static void __devinit quirk_intel_irqbal + pci_read_config_byte(dev, 0xf4, &config); + pci_write_config_byte(dev, 0xf4, config|0x2); + +- /* read xTPR register */ +- raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); ++ /* ++ * read xTPR register. We may not have a pci_dev for device 8 ++ * because it might be hidden until the above write. ++ */ ++ pci_bus_read_config_word(dev->bus, PCI_DEVFN(8, 0), 0x4c, &word); + + if (!(word & (1 << 13))) { + struct xen_platform_op op; + +- printk(KERN_INFO "Intel E7520/7320/7525 detected. " +- "Disabling irq balancing and affinity\n"); ++ dev_info(&dev->dev, "Intel E7520/7320/7525 detected; " ++ "disabling irq balancing and affinity\n"); + op.cmd = XENPF_platform_quirk; + op.u.platform_quirk.quirk_id = QUIRK_NOIRQBALANCING; + WARN_ON(HYPERVISOR_platform_op(&op)); +@@ -102,14 +105,16 @@ static void ich_force_enable_hpet(struct + pci_read_config_dword(dev, 0xF0, &rcba); + rcba &= 0xFFFFC000; + if (rcba == 0) { +- printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n"); ++ dev_printk(KERN_DEBUG, &dev->dev, "RCBA disabled; " ++ "cannot force enable HPET\n"); + return; + } + + /* use bits 31:14, 16 kB aligned */ + rcba_base = ioremap_nocache(rcba, 0x4000); + if (rcba_base == NULL) { +- printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n"); ++ dev_printk(KERN_DEBUG, &dev->dev, "ioremap failed; " ++ "cannot force enable HPET\n"); + return; + } + +@@ -120,8 +125,8 @@ static void ich_force_enable_hpet(struct + /* HPET is enabled in HPTC. Just not reported by BIOS */ + val = val & 0x3; + force_hpet_address = 0xFED00000 | (val << 12); +- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", +- force_hpet_address); ++ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " ++ "0x%lx\n", force_hpet_address); + iounmap(rcba_base); + return; + } +@@ -140,11 +145,12 @@ static void ich_force_enable_hpet(struct + if (err) { + force_hpet_address = 0; + iounmap(rcba_base); +- printk(KERN_DEBUG "Failed to force enable HPET\n"); ++ dev_printk(KERN_DEBUG, &dev->dev, ++ "Failed to force enable HPET\n"); + } else { + force_hpet_resume_type = ICH_FORCE_HPET_RESUME; +- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", +- force_hpet_address); ++ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " ++ "0x%lx\n", force_hpet_address); + } + } + +@@ -160,6 +166,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + ich_force_enable_hpet); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, + ich_force_enable_hpet); ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, ++ ich_force_enable_hpet); + + + static struct pci_dev *cached_dev; +@@ -204,8 +212,8 @@ static void old_ich_force_enable_hpet(st + if (val & 0x4) { + val &= 0x3; + force_hpet_address = 0xFED00000 | (val << 12); +- printk(KERN_DEBUG "HPET at base address 0x%lx\n", +- force_hpet_address); ++ dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n", ++ force_hpet_address); + return; + } + +@@ -225,14 +233,14 @@ static void old_ich_force_enable_hpet(st + /* HPET is enabled in HPTC. Just not reported by BIOS */ + val &= 0x3; + force_hpet_address = 0xFED00000 | (val << 12); +- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", +- force_hpet_address); ++ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " ++ "0x%lx\n", force_hpet_address); + cached_dev = dev; + force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME; + return; + } + +- printk(KERN_DEBUG "Failed to force enable HPET\n"); ++ dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n"); + } + + /* +@@ -290,8 +298,8 @@ static void vt8237_force_enable_hpet(str + */ + if (val & 0x80) { + force_hpet_address = (val & ~0x3ff); +- printk(KERN_DEBUG "HPET at base address 0x%lx\n", +- force_hpet_address); ++ dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n", ++ force_hpet_address); + return; + } + +@@ -305,14 +313,14 @@ static void vt8237_force_enable_hpet(str + pci_read_config_dword(dev, 0x68, &val); + if (val & 0x80) { + force_hpet_address = (val & ~0x3ff); +- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", +- force_hpet_address); ++ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at " ++ "0x%lx\n", force_hpet_address); + cached_dev = dev; + force_hpet_resume_type = VT8237_FORCE_HPET_RESUME; + return; + } + +- printk(KERN_DEBUG "Failed to force enable HPET\n"); ++ dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n"); + } + + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, +@@ -340,7 +348,7 @@ static void nvidia_force_enable_hpet(str + pci_read_config_dword(dev, 0x44, &val); + force_hpet_address = val & 0xfffffffe; + force_hpet_resume_type = NVIDIA_FORCE_HPET_RESUME; +- printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n", ++ dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n", + force_hpet_address); + cached_dev = dev; + return; +@@ -353,6 +361,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_N + nvidia_force_enable_hpet); + + /* LPC bridges */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0260, ++ nvidia_force_enable_hpet); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0360, + nvidia_force_enable_hpet); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, 0x0361, +@@ -373,19 +383,19 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_N + void force_hpet_resume(void) + { + switch (force_hpet_resume_type) { +- case ICH_FORCE_HPET_RESUME: +- return ich_force_hpet_resume(); +- +- case OLD_ICH_FORCE_HPET_RESUME: +- return old_ich_force_hpet_resume(); +- +- case VT8237_FORCE_HPET_RESUME: +- return vt8237_force_hpet_resume(); +- +- case NVIDIA_FORCE_HPET_RESUME: +- return nvidia_force_hpet_resume(); +- +- default: ++ case ICH_FORCE_HPET_RESUME: ++ ich_force_hpet_resume(); ++ return; ++ case OLD_ICH_FORCE_HPET_RESUME: ++ old_ich_force_hpet_resume(); ++ return; ++ case VT8237_FORCE_HPET_RESUME: ++ vt8237_force_hpet_resume(); ++ return; ++ case NVIDIA_FORCE_HPET_RESUME: ++ nvidia_force_hpet_resume(); ++ return; ++ default: + break; + } + } +--- sle11-2009-06-29.orig/arch/x86/kernel/rtc.c 2009-06-29 15:14:52.000000000 +0200 ++++ sle11-2009-06-29/arch/x86/kernel/rtc.c 2009-03-16 16:33:40.000000000 +0100 +@@ -181,6 +181,10 @@ unsigned long read_persistent_clock(void + { + unsigned long retval, flags; + ++#ifdef CONFIG_XEN ++ if (!is_initial_xendomain()) ++ return xen_read_persistent_clock(); ++#endif + spin_lock_irqsave(&rtc_lock, flags); + retval = get_wallclock(); + spin_unlock_irqrestore(&rtc_lock, flags); +@@ -190,6 +194,10 @@ unsigned long read_persistent_clock(void + + int update_persistent_clock(struct timespec now) + { ++#ifdef CONFIG_XEN ++ if (xen_update_persistent_clock() < 0 || xen_independent_wallclock()) ++ return 0; ++#endif + return set_rtc_mmss(now.tv_sec); + } + +--- sle11-2009-06-29.orig/arch/x86/kernel/setup64-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup64-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -31,7 +31,11 @@ + #include + #endif + ++#ifndef CONFIG_DEBUG_BOOT_PARAMS + struct boot_params __initdata boot_params; ++#else ++struct boot_params boot_params; ++#endif + + cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; + +@@ -47,6 +51,7 @@ char boot_cpu_stack[IRQSTACKSIZE] __attr + + unsigned long __supported_pte_mask __read_mostly = ~0UL; + EXPORT_SYMBOL(__supported_pte_mask); ++ + static int do_not_nx __cpuinitdata = 0; + + /* noexec=on|off +@@ -90,6 +95,45 @@ static int __init nonx32_setup(char *str + __setup("noexec32=", nonx32_setup); + + /* ++ * Copy data used in early init routines from the initial arrays to the ++ * per cpu data areas. These arrays then become expendable and the ++ * *_early_ptr's are zeroed indicating that the static arrays are gone. ++ */ ++static void __init setup_per_cpu_maps(void) ++{ ++#ifndef CONFIG_XEN ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++#ifdef CONFIG_SMP ++ if (per_cpu_offset(cpu)) { ++#endif ++ per_cpu(x86_cpu_to_apicid, cpu) = ++ x86_cpu_to_apicid_init[cpu]; ++ per_cpu(x86_bios_cpu_apicid, cpu) = ++ x86_bios_cpu_apicid_init[cpu]; ++#ifdef CONFIG_NUMA ++ per_cpu(x86_cpu_to_node_map, cpu) = ++ x86_cpu_to_node_map_init[cpu]; ++#endif ++#ifdef CONFIG_SMP ++ } ++ else ++ printk(KERN_NOTICE "per_cpu_offset zero for cpu %d\n", ++ cpu); ++#endif ++ } ++ ++ /* indicate the early static arrays will soon be gone */ ++ x86_cpu_to_apicid_early_ptr = NULL; ++ x86_bios_cpu_apicid_early_ptr = NULL; ++#ifdef CONFIG_NUMA ++ x86_cpu_to_node_map_early_ptr = NULL; ++#endif ++#endif ++} ++ ++/* + * Great future plan: + * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data. + * Always point %gs to its beginning +@@ -109,19 +153,24 @@ void __init setup_per_cpu_areas(void) + printk(KERN_INFO "PERCPU: Allocating %lu bytes of per cpu data\n", size); + for_each_cpu_mask (i, cpu_possible_map) { + char *ptr; ++#ifndef CONFIG_NEED_MULTIPLE_NODES ++ ptr = alloc_bootmem_pages(size); ++#else ++ int node = early_cpu_to_node(i); + +- if (!NODE_DATA(cpu_to_node(i))) { +- printk("cpu with no node %d, num_online_nodes %d\n", +- i, num_online_nodes()); ++ if (!node_online(node) || !NODE_DATA(node)) + ptr = alloc_bootmem_pages(size); +- } else { +- ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size); +- } ++ else ++ ptr = alloc_bootmem_pages_node(NODE_DATA(node), size); ++#endif + if (!ptr) + panic("Cannot allocate cpu data for CPU %d\n", i); + cpu_pda(i)->data_offset = ptr - __per_cpu_start; + memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); + } ++ ++ /* setup percpu data maps early */ ++ setup_per_cpu_maps(); + } + + #ifdef CONFIG_XEN +@@ -224,7 +273,8 @@ void syscall_init(void) + wrmsrl(MSR_CSTAR, ignore_sysret); + + /* Flags to clear on syscall */ +- wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); ++ wrmsrl(MSR_SYSCALL_MASK, ++ X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_IOPL); + #endif + #ifdef CONFIG_IA32_EMULATION + syscall32_cpu_init (); +@@ -303,7 +353,7 @@ void __cpuinit cpu_init (void) + */ + #ifndef CONFIG_XEN + if (cpu) +- memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE); ++ memcpy(get_cpu_gdt_table(cpu), cpu_gdt_table, GDT_SIZE); + #endif + + cpu_gdt_descr[cpu].size = GDT_SIZE; +@@ -334,10 +384,10 @@ void __cpuinit cpu_init (void) + v, cpu); + } + estacks += PAGE_SIZE << order[v]; +- orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks; ++ orig_ist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks; + } + +- t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap); ++ t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); + /* + * <= is required because the CPU will access up to + * 8 bits beyond the end of the IO permission bitmap. +--- sle11-2009-06-29.orig/arch/x86/kernel/setup_32-xen.c 2009-02-16 16:18:36.000000000 +0100 ++++ sle11-2009-06-29/arch/x86/kernel/setup_32-xen.c 2009-03-16 16:33:40.000000000 +0100 +@@ -47,9 +47,12 @@ + #include + #include + #include ++#include ++#include + + #include